[
  {
    "path": ".gitattributes",
    "content": "*.js linguist-language=Python \n*.css linguist-language=Python "
  },
  {
    "path": ".gitignore",
    "content": "*/__pycache__/\n*/migrations/\n.idea/\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Hyhyhyhyhyhyh\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# demo\nhttp://data.sghen.cn\n登录用户名密码：admin/admin\n\n# 项目结构\n```\n项目\n│  gconfig.py           gunicorn配置文件\n│  manage.py            Django管理文件\n│  README.md            readme\n|  nginx.conf           nginx.conf\n│\n├─api                   ajax接口\n│\n├─authorize             身份认证模块\n|\n├─check                 自动检核模块\n|\n├─data                  仪表盘、检核明细模块\n|\n├─demand                更新源系统改造需求\n|\n├─docs                  文档目录\n│\n├─files                 上传下载文件模块\n│\n├─logs                  日志目录\n|\n├─mysite                Django配置目录\n│\n├─standard              查看、更新数据标准模块\n|\n├─utils                 一些复用的函数\n│\n└─static                css、js、附件等静态文件目录\n```\n\n\n# 更新记录\n## 2020-09-05\n- 修复若干本地部署会发生的错误\n- **重要**：修正部署文档`docs/部署文档.md`中的许多错误\n\n## 2020-06-13\n- 更新血缘分析模块\n\n## 2020-05\n- 数据源跟检核规则库中的数据库进行关联\n\n## 2020-04-23\n1. 前端侧边栏修改，显示更加紧凑\n2. 新增数据源的查看/修改/新增功能\n\n\n## 2020-03-29\n1. 后端\n    - 检核结果由按季度存放改在按日存放，记录检核版本方便查看历史变化趋势\n    - 根据check_execute_log检核日志表为前端提供日期选择接口；api代码更新为正式代码（代替随机数据）\n    - 添加日期维度表\n2. 前端：在仪表盘添加各公司质量总览及全期趋势图；添加日期选择控件等\n3. 进一步前后分离，减少后端渲染模板\n\n## 2019-12-29\n实际部署demo\n\n## 2019-09-09\ndemo\n\n\n# 启停项目\n```\n# 切换虚拟环境\nworkon django-2.1\n\n# 启动项目\ngunicorn mysite.wsgi -c /data/pyweb/data-quality/gconfig.py &\n```\n\n# todo\n- [ ] 数据标准编辑功能完善\n\n# 说明\n登录页面背景图来自https://pixabay.com"
  },
  {
    "path": "api/__init__.py",
    "content": ""
  },
  {
    "path": "api/admin.py",
    "content": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "api/api_backend.py",
    "content": "from django.http.response import JsonResponse\nfrom django.http.response import HttpResponseBadRequest\nfrom django.views.decorators.http import require_http_methods\nimport pandas as pd\nfrom crontab import CronTab\n\nfrom mysite import db_config\n\n\ndef encrypy_password(connection_string):\n    \"\"\"将连接串中的密码替换为*号\n    \"\"\"\n    str1 = connection_string.split('@')[0].split(':')[0]\n    str2 = connection_string.split('@')[0].split(':')[1]\n    str3 = connection_string.split('@')[1]\n    return f'{str1}:{str2}:******@{str3}'\n\n\n@require_http_methods(['GET'])\ndef db_query(request):\n    try:\n        conn = db_config.sqlalchemy_conn()\n        db = pd.read_sql(\"select name,db_type,alias,connection_string,db,ip,note,id from source_db_info order by name,db_type\", con=conn)\n        \n        db['connection_string'] = db['connection_string'].apply(encrypy_password)\n        \n        data = {\n            'company': db['name'].values.tolist(),\n            'db_type': db['db_type'].values.tolist(),\n            'alias': db['alias'].values.tolist(),\n            'connection_string': db['connection_string'].values.tolist(),\n            'db': db['db'].values.tolist(),\n            'ip': db['ip'].values.tolist(),\n            'note': db['note'].values.tolist(),\n            'rowid': db['id'].values.tolist()\n        }\n        return JsonResponse({'data': data, 'code': 1000})\n    except Exception as e:\n        return HttpResponseBadRequest(content=e)\n    finally:\n        conn.dispose()\n\n\n@require_http_methods(['POST'])\ndef db_update(request):\n    id = request.POST.get('id')\n    ip = request.POST.get('ip')\n    alias = request.POST.get('alias')\n    user = request.POST.get('user')\n    password = request.POST.get('password')\n    db = request.POST.get('db')\n    port = request.POST.get('port')\n    db_type = request.POST.get('db_type')\n    charset = request.POST.get('charset')\n    note = request.POST.get('note')\n    \n    if db_type == 'mysql':\n        connection_string = f'mysql+mysqldb://{user}:{password}@{ip}:{port}/{db}?charset={charset}'\n    elif db_type == 'oracle':\n        connection_string = f'oracle://{user}:{password}@{ip}:{port}/?service_name={db}'\n    elif db_type == 'sqlserver':\n        connection_string = f'mssql+pymssql://{user}:{password}@{ip}:{port}/{db}?charset={charset}'\n    elif db_type == 'postgresql':\n        connection_string = f'postgresql://{user}:{password}@{ip}:{port}/{db}'\n    \n    try:\n        # conn = db_config.mysql_connect()\n        # with conn.cursor() as curs:\n        #     sql = f\"\"\"update source_db_info\n        #                 set alias='{alias}',\n        #                 connection_string='{connection_string}',\n        #                 ip='{ip}',\n        #                 passwd='{password}',\n        #                 db='{db}',\n        #                 port={port},\n        #                 db_type='{db_type}',\n        #                 note='{note}'\n        #                 where id={id}\"\"\"\n        #     curs.execute(sql)\n        # conn.commit()\n        return JsonResponse({'data': '修改成功', 'code': 1000})\n    except Exception as e:\n        conn.rollback()\n        return HttpResponseBadRequest(content=e)\n    finally:\n        conn.close()\n\n \n@require_http_methods(['POST'])\ndef db_insert(request):\n    company = request.POST.get('company')\n    name = request.POST.get('name')\n    alias = request.POST.get('alias')\n    ip = request.POST.get('ip')\n    user = request.POST.get('user')\n    password = request.POST.get('password')\n    db = request.POST.get('db')\n    port = request.POST.get('port')\n    db_type = request.POST.get('db_type')\n    charset = request.POST.get('charset')\n    note = request.POST.get('note')\n    \n    if db_type == 'mysql':\n        connection_string = f'mysql+mysqldb://{user}:{password}@{ip}:{port}/{db}?charset={charset}'\n    elif db_type == 'oracle':\n        connection_string = f'oracle://{user}:{password}@{ip}:{port}/?service_name={db}'\n    elif db_type == 'sqlserver':\n        connection_string = f'mssql+pymssql://{user}:{password}@{ip}:{port}/{db}?charset={charset}'\n    elif db_type == 'postgresql':\n        connection_string = f'postgresql://{user}:{password}@{ip}:{port}/{db}'\n        \n    try:\n        conn = db_config.mysql_connect()\n        # with conn.cursor() as curs:\n        #     sql = f\"\"\"insert into source_db_info(company,name,alias,connection_string,ip,user,passwd,db,port,db_type,note)\n        #                 values('{company}','{name}','{alias}','{connection_string}','{ip}','{user}','{password}','{db}',{port},'{db_type}','{note}')\"\"\"\n        #     curs.execute(sql)\n        # conn.commit()\n        return JsonResponse({'data': '新增成功', 'code': 1000})\n    except Exception as e:\n        conn.rollback()\n        return HttpResponseBadRequest(content=e)\n    finally:\n        conn.close()\n\n\n@require_http_methods(['POST'])\ndef crontab_enable(request):\n    \"\"\"\n    启用/禁用自动检核的crontab任务\n    :param request:\n    :return:\n    \"\"\"\n    enable = request.POST.get('enable')\n    job_name = request.POST.get('job_name')\n\n    cron = CronTab(user=True)\n    job = list(cron.find_comment(job_name))[0]\n\n    if enable == 'false':\n        # job.enable(False)\n        # cron.write()\n        return JsonResponse({\"msg\": \"success\"})\n    elif enable == 'true':\n        # job.enable()\n        # cron.write()\n        return JsonResponse({\"msg\": \"success\"})\n    else:\n        return JsonResponse({\"msg\": \"failed\"})\n    \n\n@require_http_methods(['POST'])\ndef crontab_run(request):\n    job_name = request.POST.get('job_name')\n    \n    try:\n        cron =  CronTab(user=True)\n        job = list(cron.find_comment(job_name))[0]\n        job.run()\n        return JsonResponse({\"msg\": \"success\"})\n    except Exception as e:\n        return HttpResponseBadRequest(content=e)"
  },
  {
    "path": "api/api_blood.py",
    "content": "import re\nimport os\nimport sys\nimport pandas as pd\nfrom sqlalchemy import create_engine\nfrom django.http.response import JsonResponse, HttpResponseBadRequest\nfrom django.views.decorators.http import require_http_methods\n\nsys.path.insert(0, '..')\nfrom mysite import db_config\n\n\n'''\ndef extract_table_name_from_sql(sql_str):\n    \"\"\"\n    提取sql语句中的表名\n    \"\"\"\n    # 过滤去除/* */注释\n    q = re.sub(r\"/\\*[^*]*\\*+(?:[^*/][^*]*\\*+)*/\", \"\", sql_str)\n\n    # 去除以 -- 或 # 开头的注释行\n    lines = [line for line in q.splitlines() if not re.match(\"^\\s*(--|#)\", line)]\n\n    # 去除行尾的以 -- 或 # 开头的注释\n    q = \" \".join([re.split(\"--|#\", line)[0] for line in lines])\n\n    # 根据空格、();分割单词\n    tokens = re.split(r\"[\\s)(;]+\", q)\n\n    # 如果发现 from 或 join ，则把get_next设为True，然后获取表名\n    result = set()\n    get_next = False\n    for token in tokens:\n        if get_next:\n            if token.lower() not in [\"\", \"select\"]:\n                # result.append(token)\n                result.add(token)\n            get_next = False\n        get_next = token.lower() in [\"from\", \"join\"]\n\n    return result\n'''\n    \n@require_http_methods(['GET'])\ndef query_mapping(request):\n    table_name = request.GET.get('table_name')\n    \n    sql = f\"\"\"select distinct subject_area,\n                mapping_name,\n                source,\n\t\t\t\ttarget,\n                case when locate('_ts_', mapping_name)>0 then 1\n                     when locate('_ti_', mapping_name)>0 then 2\n                     when locate('_ods_', mapping_name)>0 then 3\n                     else 99\n                end level\n                from datacenter_mapping\n                where (\n                    lower(source) like '%{table_name.lower()}%'\n                    or lower(target) like '%{table_name.lower()}%'\n                    or lower(mapping_name) like '%{table_name.lower()}%'\n                    )\n                and source<>target\n                order by level asc,1,2,3\n            \"\"\"\n    \n    try:\n        conn = db_config.mysql_connect()\n        with conn.cursor() as curs:\n            curs.execute(sql)\n            r = curs.fetchall()\n        return JsonResponse({\n            'subject_area': [i[0] for i in r],\n            'mapping_name': [i[1] for i in r],\n            'source': [i[2] for i in r],\n            'target': [i[3] for i in r],\n            'level': [i[4] for i in r]\n        })\n    except Exception as e:\n        return HttpResponseBadRequest(e)\n    finally:\n        conn.close()\n\n"
  },
  {
    "path": "api/api_check.py",
    "content": "from django.http.response import JsonResponse, HttpResponse, HttpResponseBadRequest\nfrom django.views.decorators.http import require_http_methods\nfrom crontab import CronTab\nimport pandas as pd\n\nimport sys, MySQLdb\n\nsys.path.insert(0, '..')\nfrom mysite import db_config\nfrom check.autocheck import Check, MyThread\n\n\n@require_http_methods(['GET'])\ndef rule(request):\n    \"\"\"\n    根据公司名查询所有检核规则详情\n    \"\"\"\n    company = request.GET.get('name')\n    filter = request.GET.get('risk_market_filter')\n\n    conn = db_config.mysql_connect()\n    curs = conn.cursor()\n    curs.execute('set autocommit=0')\n    try:\n        sql = f\"\"\"select id,check_item,target_table,risk_market_item,problem_type,db,check_sql,note,status,source_system\n                    from check_result_template\n                    where source_system in ('{company}')\n                    and risk_market_item like '%{filter}%'\n                    order by id\"\"\"\n        curs.execute(sql)\n        result = curs.fetchall()\n        # 构造json\n        result_list = []\n        for i in result:\n            result_dict = {\"id\": i[0], \"check_item\": i[1], \"target_table\": i[2], \"risk_market_item\": i[3],\n                           \"problem_type\": i[4], \"db\": i[5], \"check_sql\": i[6], \"note\": i[7], \"status\": i[8],\n                           \"source_system\": i[9]}\n            result_list.append(result_dict)\n        json_data = {'data': result_list}\n        return JsonResponse(json_data)\n    except:\n        return HttpResponse('error', status=500)\n    finally:\n        curs.close()\n        conn.close()\n        \n        \n@require_http_methods(['GET'])\ndef rule_detail(request):\n    \"\"\"\n    根据公司名、id查询单条规则详情\n    \"\"\"\n    company = request.GET.get('company')\n    id =  request.GET.get('id')\n    \n    data = {\n        \"id\": None,\n        \"source_system\": None,\n        \"check_item\": None,\n        \"target_table\": None,\n        \"risk_market_item\": None,\n        \"problem_type\": None,\n        \"db\": None,\n        \"check_sql\": None,\n        \"note\": None,\n        \"status\": None,\n    }\n    if id == 'null':\n        return JsonResponse(data)\n    \n    sql = f\"\"\"select id,check_item,target_table,risk_market_item,problem_type,db,check_sql,note,status\n    from check_result_template\n    where source_system in ('{company}') and id={id}\"\"\"\n    conn = db_config.sqlalchemy_conn()\n    try:\n        result = pd.read_sql(sql, con=conn)\n        data = {\n            \"check_item\": result['check_item'].values.tolist()[0],\n            \"target_table\": result['target_table'].values.tolist()[0],\n            \"risk_market_item\": result['risk_market_item'].values.tolist()[0],\n            \"problem_type\": result['problem_type'].values.tolist()[0],\n            \"db\": result['db'].values.tolist()[0],\n            \"check_sql\": result['check_sql'].values.tolist()[0],\n            \"note\": result['note'].values.tolist()[0],\n            \"status\": result['status'].values.tolist()[0],\n        }\n        return JsonResponse(data)\n    except Exception as e:\n        return HttpResponseBadRequest(e)\n    finally:\n        conn.dispose()\n\n\n@require_http_methods(['POST'])\ndef rule_update(request):\n    \"\"\"\n    执行修改检核规则\n    \"\"\"\n    id = request.POST.get('id')\n    source_system = request.POST.get('source_system')\n    check_item = request.POST.get('check_item')\n    target_table = request.POST.get('target_table')\n    risk_market = request.POST.get('risk_market')\n    problem_type = request.POST.get('problem_type')\n    db = request.POST.get('db')\n    check_sql = request.POST.get('check_sql')\n    note = request.POST.get('note')\n    status = request.POST.get('status')\n\n    # 把\"转义为'，再把'转义为''\n    check_sql = MySQLdb.escape_string(check_sql).decode('utf-8')\n    # print(check_sql)\n    try:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        curs.execute('set autocommit=0')\n        sql = f\"\"\"update check_result_template set check_item='{check_item}',\n                                                target_table='{target_table}',\n                                                risk_market_item='{risk_market}',\n                                                problem_type='{problem_type}',\n                                                db='{db}',\n                                                check_sql='{check_sql}',\n                                                note='{note}',\n                                                status='{status}'\n                                                where id={id} and source_system='{source_system}'\"\"\"\n        # print(sql)\n        curs.execute(sql)\n        conn.commit()\n        return JsonResponse({'msg': '修改成功', 'code': 1000})\n    except Exception as e:\n        return HttpResponse(e, status=500)\n    finally:\n        curs.close()\n        conn.close()\n\n\n@require_http_methods(['POST'])\ndef rule_add(request):\n    \"\"\"\n    新增检核规则\n    \"\"\"\n    source_system = request.POST.get('source_system')\n    check_item = request.POST.get('check_item')\n    target_table = request.POST.get('target_table')\n    risk_market = request.POST.get('risk_market')\n    problem_type = request.POST.get('problem_type')\n    db = request.POST.get('db')\n    check_sql = request.POST.get('check_sql')\n    note = request.POST.get('note')\n    status = request.POST.get('status')\n\n    # 处理检核SQL中含有''的情况\n    check_sql = MySQLdb.escape_string(check_sql).decode('utf-8')\n    # print(check_sql)\n    try:\n        # 连接数据库\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        curs.execute('set autocommit=0')\n        sql = \"select max(id)+1 from check_result_template where source_system in ('\" + source_system + \"')\"\n        curs.execute(sql)\n        result = curs.fetchone()\n        new_id = str(result[0])  # 获取新增的id\n        sql = f\"\"\"insert into check_result_template(id,\n                                                    source_system,\n                                                    check_item,\n                                                    target_table,\n                                                    risk_market_item,\n                                                    problem_type,\n                                                    db,\n                                                    check_sql,\n                                                    note,\n                                                    status)\n                values({new_id},\n                        '{source_system}',\n                        '{check_item}',\n                        '{target_table}',\n                        '{risk_market}',\n                        '{problem_type}',\n                        '{db}',\n                        '{check_sql}',\n                        '{note}',\n                        '{status}')\"\"\"\n        # print(sql)\n        curs.execute(sql)\n        conn.commit()\n        return JsonResponse({'msg': '修改成功', 'code': 1000})\n    except Exception as e:\n        return HttpResponse(e, status=500)\n    finally:\n        curs.close()\n        conn.close()\n\n\n@require_http_methods(['POST'])\ndef rule_status_modify(request):\n    \"\"\"修改检核规则状态，禁用/启用 规则的状态\n    \"\"\"\n    id = request.POST.get('id')\n    post_status = request.POST.get('status')\n    company = request.POST.get('company')\n\n    conn = db_config.mysql_connect()\n    curs = conn.cursor()\n    curs.execute('set autocommit=0')\n    # 修改状态\n    try:\n        if post_status == '已启用':\n            sql = f\"update check_result_template set status='已停用' where id={id} and source_system='{company}'\"\n            rr = curs.execute(sql)\n            conn.commit()\n            return JsonResponse({'msg': '修改成功', 'code': 1000})\n        else:\n            sql = f\"update check_result_template set status='已启用' where id={id} and source_system='{company}'\"\n            rr = curs.execute(sql)\n            conn.commit()\n            return JsonResponse({'msg': '修改成功', 'code': 1000})\n    except:\n        return HttpResponse('error', status=500)\n    finally:\n        curs.close()\n        conn.close()\n\n\n@require_http_methods(['POST'])\ndef rule_execute(request):\n    \"\"\"执行检核\n    \"\"\"\n    company = request.POST.get('company')\n    username = request.POST.get('username')\n    quarter = request.POST.get('quarter')\n    source_system = company\n\n    if company == 'xt':\n        check = Check()\n        if check.init_table(company, source_system, quarter):\n            # 初始化3个线程\n            thread1 = MyThread(func=check.run_check,\n                               args=(company, source_system, quarter, 'oracle'))\n            thread2 = MyThread(func=check.run_check,\n                               args=(company, source_system, quarter, 'sqlserver'))\n            thread3 = MyThread(func=check.xt_spec, args=(quarter,))\n            thread4 = MyThread(func=check.run_check,\n                               args=(company, source_system, quarter, 'mysql'))\n            # 开启3个线程\n            thread1.start()\n            thread2.start()\n            thread3.start()\n            thread4.start()\n            # 等待运行结束\n            thread1.join()\n            thread2.join()\n            thread3.join()\n            thread4.join()\n\n            if thread1.get_result() is True:\n                if thread2.get_result() is True:\n                    if thread3.get_result() is True:\n                        if thread4.get_result() is True:\n                            run = True\n                        else:\n                            return JsonResponse({\n                                \"status\":\n                                    \"检核过程发生错误：\" + str(thread4.get_result())\n                            })\n                    else:\n                        return JsonResponse({\n                            \"status\":\n                                \"检核过程发生错误：\" + str(thread3.get_result())\n                        })\n                else:\n                    return JsonResponse(\n                        {\"status\": \"检核过程发生错误：\" + str(thread2.get_result())})\n            else:\n                return JsonResponse(\n                    {\"status\": \"检核过程发生错误：\" + str(thread1.get_result())})\n        else:\n            return JsonResponse({\"status\": \"初始化检核表发生错误\"})\n\n    elif company == 'zc':\n        source_system = '资产'\n        check = Check()\n        if check.init_table(company, source_system, quarter):\n            run = check.run_check(company, source_system, quarter, None)\n            if run is not True:\n                return JsonResponse({\"status\": \"检核过程发生错误：\" + str(run)})\n        else:\n            return JsonResponse({\"status\": \"初始化检核表发生错误\"})\n\n    elif company == 'db':\n        source_system = '担保'\n        check = Check()\n        if check.init_table(company, source_system, quarter):\n            run = check.run_check(company, source_system, quarter, None)\n            if run is not True:\n                return JsonResponse({\"status\": \"检核过程发生错误：\" + str(run)})\n        else:\n            return JsonResponse({\"status\": \"初始化检核表发生错误\"})\n\n    elif company == 'jk':\n        source_system = '金科'\n        check = Check()\n        if check.init_table(company, source_system, quarter):\n            run = check.run_check(company, source_system, quarter, None)\n            if run is not True:\n                return JsonResponse({\"status\": \"检核过程发生错误：\" + str(run)})\n        else:\n            return JsonResponse({\"status\": \"初始化检核表发生错误\"})\n\n    elif company == 'jj1':\n        source_system = '基金1'\n        check = Check()\n        if check.init_table(company, source_system, quarter):\n            run = check.run_check(company, source_system, quarter, None)\n            if run is not True:\n                return JsonResponse({\"status\": \"检核过程发生错误：\" + str(run)})\n        else:\n            return JsonResponse({\"status\": \"初始化检核表发生错误\"})\n\n    elif company == 'jj2':\n        source_system = '基金2'\n        check = Check()\n        if check.init_table(company, source_system, quarter):\n            run = check.run_check(company, source_system, quarter, None)\n            if run is not True:\n                return JsonResponse({\"status\": \"检核过程发生错误：\" + str(run)})\n        else:\n            return JsonResponse({\"status\": \"初始化检核表发生错误\"})\n\n    elif company == 'jz':\n        source_system = '金租'\n        check = Check()\n        if check.init_table(company, source_system, quarter):\n            run = check.run_check(company, source_system, quarter, None)\n            if run is not True:\n                return JsonResponse({\"status\": \"检核过程发生错误：\" + str(run)})\n        else:\n            return JsonResponse({\"status\": \"初始化检核表发生错误\"})\n\n    if run is True:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        curs.execute('set autocommit=0')\n        sql = \"insert into check_execute_log values(null,'{0}','{1}',now(),'{2}')\".format(\n            quarter, company, username)\n        print(sql)\n        curs.execute(sql)\n        conn.commit()\n        curs.close()\n        conn.close()\n        return JsonResponse({\n            \"status\": \"success\",\n            \"msg\": source_system + \"公司检核成功！\"\n        })\n\n\ndef update_crontab(request):\n    \"\"\"更新crontab命令\n    \"\"\"\n    job_time = request.POST.get('job_time')\n\n    try:\n        # cron  = CronTab(user=True)\n        # job = list(cron.find_comment('自动进行数据质量检核'))[0]\n        # job.setall(job_time)\n        return JsonResponse({\"msg\": \"操作成功\"})\n    except Exception as e:\n        return JsonResponse({\"msg\": \"操作失败\", \"reason\": e})\n    \n    \n@require_http_methods(['GET'])\ndef query_check_progress(request):\n    \"\"\"\n    查询正在运行的检核任务执行进度\n    :param request:\n    :return:\n    \"\"\"\n    company = request.GET.get('company')\n    db = request.GET.get('db')\n    \n    data = {}\n    try:\n        conn = db_config.mysql_connect()\n        for company in ('xt', 'zc', 'db', 'jk', 'jj1', 'jj2', 'jz'):\n            data[company] = {}\n            \n            with conn.cursor() as curs:\n                # 已检核指标总数\n                sql  = f\"\"\"select a.db,count(*)\n                            from check_result_{company} a,\n                            (\n                                select max(check_version) check_version,db from check_result_{company}\n                                where db in (select distinct alias from source_db_info where company='{company}')\n                                group by db\n                            ) b\n                            where a.check_sql is not null\n                            and a.check_sql != ''\n                            and a.check_version=b.check_version\n                            and a.db=b.db\n                            and a.update_flag='Y'\n                            group by a.db\"\"\"\n                curs.execute(sql)\n                result = curs.fetchall()\n                for i in result:\n                    data[company][i[0]] = i[1]\n                    \n                # 待检核指标总数\n                sql  = f\"\"\"select a.db,count(*)\n                            from check_result_{company} a,\n                            (\n                                select max(check_version) check_version,db from check_result_{company}\n                                where db in (select distinct alias from source_db_info where company='{company}')\n                                group by db\n                            ) b\n                            where a.check_sql is not null\n                            and a.check_sql != ''\n                            and a.check_version=b.check_version\n                            and a.db=b.db\n                            group by a.db\"\"\"\n                curs.execute(sql)\n                result = curs.fetchall()\n                for i in result:\n                    if i[1] == 0:\n                        data[company][i[0]] = 0\n                    else:\n                        data[company][i[0]] = round(data[company][i[0]]/i[1]*100, 2)\n                    \n        return JsonResponse(data)\n    except Exception as e:\n        return HttpResponseBadRequest(e)\n    finally:\n        conn.close()"
  },
  {
    "path": "api/api_dashboard.py",
    "content": "import numpy as np\nfrom django.http.response import JsonResponse\nfrom django.views.decorators.http import require_http_methods\n\nimport sys, MySQLdb\n\nsys.path.insert(0, '..')\nfrom mysite import db_config\nfrom utils import functions as f\n\n# np.set_printoptions(precision=2, suppress=True)\n\n\n@require_http_methods(['GET'])\ndef avg_problem_percentage(request):\n    \"\"\"\n    各公司平均问题占比\n    :param request:\n    :return:\n    \"\"\"\n    # 接口返回值列表\n    data = []\n    data_quarter = ['quarter']\n    data_company = []\n    \n    # 获取所有年所有季度\n    year = f.query_data_year()\n    quarter = []\n    for y in year:\n        q = f.query_data_quarter(y)\n        quarter.extend([(y, i) for i in q])\n        [data_quarter.append(str(y)+'Q'+str(i)) for i in q]\n    data.append(data_quarter)\n\n    # 查询各公司每季度数据\n    try:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        for company in ('xt', 'zc', 'db', 'jk', 'jj1', 'jj2', 'jz'):\n            data_company = [company]\n            sql = f\"\"\"select round(sum(a.problem_count)/sum(a.item_count)*100,2)\n                    from check_result_{company} a,dim_date b\n                    where a.RISK_MARKET_ITEM='是'\n                    and DATE_FORMAT(a.check_date,'%Y%m%d') = b.day_id\n                    and (b.year,b.quarter) in {tuple(quarter)}\n                    group by b.year,b.quarter\"\"\"\n            curs.execute(sql)\n            result = curs.fetchall()\n            [data_company.append(str(r[0])) for r in result]\n            data.append(data_company)\n        return JsonResponse(data, safe=False)\n    except Exception as e:\n        print(e)\n        return JsonResponse({'msg': str(e)})\n    finally:\n        curs.close()\n        conn.close()\n\n\n@require_http_methods(['GET'])\ndef same_problem_top5(request):\n    \"\"\"\n    各公司同类问题Top 5统计\n    :param request:\n    :return:\n    \"\"\"\n    year = request.GET.get('year')\n    quarter = request.GET.get('quarter')\n    month = request.GET.get('month')\n    day = request.GET.get('day')\n\n    try:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        # 查询风险集市相关的相同的检核项的问题占比总和\n        sql = f\"\"\"select check_item,count(*) cnt,sum(problem_per) from (\n                select check_item,problem_per,check_date from check_result_xt where risk_market_item='是' and problem_per is not null\n                union\n                select check_item,problem_per,check_date from check_result_zc where risk_market_item='是' and problem_per is not null\n                union\n                select check_item,problem_per,check_date from check_result_db where risk_market_item='是' and problem_per is not null\n                union\n                select check_item,problem_per,check_date from check_result_jk where risk_market_item='是' and problem_per is not null\n                union\n                select check_item,problem_per,check_date from check_result_jj1 where risk_market_item='是' and problem_per is not null\n                union\n                select check_item,problem_per,check_date from check_result_jj2 where risk_market_item='是' and problem_per is not null\n                union\n                select check_item,problem_per,check_date from check_result_jz where risk_market_item='是' and problem_per is not null\n                ) a, dim_date b\n            where DATE_FORMAT(a.check_date,'%Y%m%d') = b.day_id\n            and b.year={year}\n            and b.quarter={quarter}\n            and b.month={month}\n            and b.day={day}\n            group by check_item\n            having count(*)>1\n            order by 3 desc,2 desc\"\"\"\n        curs.execute(sql)\n        result = curs.fetchall()\n        \n        check_item = []\n        total_problem = []\n        [check_item.append(r[0]) for r in result]\n        [total_problem.append(float(str(r[2]))) for r in result]\n        \n        # 取top4问题项及占比\n        top4_item = check_item[0:4]\n        top4_problem = total_problem[0:4]\n        other_problem = sum(total_problem[4:])\n        # 合并 其他项\n        top4_item.append('其他')\n        top4_problem.append(other_problem)\n        data = {\n            'name': top4_item,\n            'value': top4_problem\n        }\n        return JsonResponse(data)\n    except Exception as e:\n        print(e)\n        return JsonResponse({'msg': str(e)})\n    finally:\n        curs.close()\n        conn.close()\n\n\n\n@require_http_methods(['GET'])\ndef subcompany_data_percentage(request):\n    \"\"\"\n    各公司数据量占比\n    :param request:\n    :return:\n    \"\"\"\n    year = request.GET.get('year')\n    quarter = request.GET.get('quarter')\n    month = request.GET.get('month')\n    day = request.GET.get('day')\n\n    data = []\n    try:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        for company in ('xt', 'zc', 'db', 'jk', 'jj1', 'jj2', 'jz'):\n            sql = f\"\"\"select sum(distinct item_count) from check_result_{company} a,\n                        (\n                            select max(a.check_version) check_version\n                            from check_result_{company} a,dim_date b where DATE_FORMAT(a.check_date,'%Y%m%d') = b.day_id\n                            and b.year={year}\n                            and b.quarter={quarter}\n                            and b.month={month}\n                            and b.day={day}\n                        ) b\n                        where a.check_version=b.check_version\n                        and a.risk_market_item='是'\"\"\"\n            curs.execute(sql)\n            result = curs.fetchone()\n            if result[0] is None:\n                data.append({'name': company, 'value': 0})\n            else:\n                data.append({'name': company, 'value': float(str(result[0]))})\n        return JsonResponse(data, safe=False)\n    except Exception as e:\n        print(e)\n        return JsonResponse({'msg': str(e)})\n    finally:\n        curs.close()\n        conn.close()\n\n\ndef count_db_rows(request):\n    \"\"\"统计各类数据库数据量\n    \"\"\"\n    quarter = request.GET.get('quarter')\n    \n    data = [{\n                \"name\": \"MySQL\",\n                \"value\": np.random.randint(1000,99999),\n            },\n            {\n                \"name\": \"Oracle\",\n                \"value\": np.random.randint(1000,99999)\n            },\n            {\n                \"name\": \"SQL server\",\n                \"value\": np.random.randint(1000,99999)\n            },\n            {\n                \"name\": \"HBase\",\n                \"value\": np.random.randint(1000,99999)\n            },\n            ]\n    return JsonResponse(data, safe=False)\n\n\n@require_http_methods(['GET'])\ndef data_overview_total(request):\n    \"\"\"\n    统计风险集市相关 总数据量、总问题数据量、总问题占比\n    :param request:\n    :return:\n    \"\"\"\n    year = request.GET.get('year')\n    quarter = request.GET.get('quarter')\n    month = request.GET.get('month')\n    day = request.GET.get('day')\n\n    all_cnt = 0\n    problem_cnt = 0\n\n    try:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        for company in ('xt', 'zc', 'db', 'jk', 'jj1', 'jj2', 'jz'):\n            sql = f\"\"\"select sum(a.item_count),sum(a.problem_count) from check_result_{company} a,\n                        (\n                            select max(a.check_version) check_version\n                            from check_result_{company} a,dim_date b where DATE_FORMAT(a.check_date,'%Y%m%d') = b.day_id\n                            and b.year={year}\n                            and b.quarter={quarter}\n                            and b.month={month}\n                            and b.day={day}\n                        ) b\n                        where a.check_version=b.check_version\n                        and a.risk_market_item='是'\"\"\"\n            curs.execute(sql)\n            result = curs.fetchone()\n            if result[0] is None:\n                continue\n            else:\n                all_cnt = all_cnt + result[0]\n                problem_cnt = problem_cnt + result[1]\n\n        response = {\n            'all_cnt': all_cnt,\n            'problem_cnt': problem_cnt,\n            'problem_per': round(problem_cnt / all_cnt * 100, 2)\n        }\n        return JsonResponse(response)\n    except Exception as e:\n        print(e)\n        return JsonResponse({'msg': str(e)})\n    finally:\n        curs.close()\n        conn.close()\n    \n    \n@require_http_methods(['GET'])\ndef data_overview_company(request):\n    \"\"\"\n    统计风险集市相关 各公司 检核数据量、问题数据量、问题数据占比\n    :param request:\n    :return:\n    \"\"\"\n    year = request.GET.get('year')\n    quarter = request.GET.get('quarter')\n    month = request.GET.get('month')\n    day = request.GET.get('day')\n    \n\n    data = []\n    try:    \n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        for company in ('xt', 'zc', 'db', 'jk', 'jj1', 'jj2', 'jz'):\n            sql = f\"\"\"select sum(a.item_count),sum(a.problem_count),round(sum(a.problem_count)/sum(a.item_count)*100,2)\n                        from check_result_{company} a,\n                        (\n                            select max(a.check_version) check_version\n                            from check_result_{company} a,dim_date b where DATE_FORMAT(a.check_date,'%Y%m%d') = b.day_id\n                            and b.year={year}\n                            and b.quarter={quarter}\n                            and b.month={month}\n                            and b.day={day}\n                        ) b\n                        where a.check_version=b.check_version\n                        and a.risk_market_item='是'\"\"\"\n            curs.execute (sql)\n            result = curs.fetchone()\n            data.append([company, result[0], result[1], result[2]])\n        return JsonResponse(data, safe=False)\n    except Exception as e:\n        print(e)\n        return JsonResponse({'msg': str(e)})\n    finally:\n        curs.close()\n        conn.close()\n        \n        \n@require_http_methods(['GET'])\ndef data_overview_company_trend(request):\n    \"\"\"\n    统计风险集市相关 各公司 检核数据量、问题数据量、问题数据占比\n    :param request:\n    :return:\n    \"\"\"\n    year = request.GET.get('year')\n    month = request.GET.get('month')\n    day = request.GET.get('day')\n    company = request.GET.get('company')\n    \n    try:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        sql = f\"\"\"select round(sum(problem_count)/sum(item_count)*100,2),check_version\n                    from check_result_{company}\n                    where risk_market_item='是'\n                    and check_date < date_add('{year}-{month}-{day}',interval 1 day)\n                    group by check_version\n                    order by check_version asc\"\"\"\n        curs.execute(sql)\n        result = curs.fetchall()\n        result = [r[0] for r in result]\n        return JsonResponse(result, safe=False)\n    except Exception as e:\n        print(e)\n        return JsonResponse({'msg': str(e)})\n    finally:\n        curs.close()\n        conn.close() \n\n\n@require_http_methods(['GET'])\ndef total_trend(request):\n    \"\"\"\n    显示集团总问题占比走势\n    :param request:\n    :return:\n    \"\"\"\n    value = []\n    try:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        sql = f\"\"\"select DATE_FORMAT(a.check_date,'%Y-%m-%d'),\n                        round(sum(a.problem_count)/sum(a.item_count)*100,2),\n                        count(distinct company) from\n                (\n                select 'xt' company,item_count,problem_count,check_date from check_result_xt where risk_market_item='是'\n                union\n                select 'zc' company,item_count,problem_count,check_date from check_result_zc where risk_market_item='是'\n                union\n                select 'db' company,item_count,problem_count,check_date from check_result_db where risk_market_item='是'\n                union\n                select 'jk' company,item_count,problem_count,check_date from check_result_jk where risk_market_item='是'\n                union\n                select 'jj1' company,item_count,problem_count,check_date from check_result_jj1 where risk_market_item='是'\n                union\n                select 'jj2' company,item_count,problem_count,check_date from check_result_jj2 where risk_market_item='是'\n                union\n                select 'jz' company,item_count,problem_count,check_date from check_result_jz where risk_market_item='是'\n                ) a\n                group by DATE_FORMAT(a.check_date,'%Y-%m-%d')\n                having count(distinct company)=7\n                order by 1 asc\"\"\"\n        curs.execute(sql)\n        result = curs.fetchall()\n        return JsonResponse({'datatime': [r[0] for r in result], 'value': [r[1] for r in result]}, safe=False)\n    except Exception as e:\n        print(e)\n        return JsonResponse({'msg': str(e)})\n    finally:\n        curs.close()\n        conn.close() \n        \n\n@require_http_methods(['GET'])\ndef subcompany_problem_count(request):\n    \"\"\"\n    子公司仪表盘-问题数据项统计\n    :param request:\n    :return:\n    \"\"\"\n    year = request.GET.get('year')\n    quarter = request.GET.get('quarter')\n    month = request.GET.get('month')\n    day = request.GET.get('day')\n    company = request.GET.get('company')\n\n    try:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        # 问题占比 | 问题数据总量 | 问题数据项\n        sql = f\"\"\"select sum(a.item_count),sum(a.problem_count),a.check_item from (\n                    select a.check_item,a.item_count,a.problem_count\n                                        from check_result_{company} a,\n                                        (\n                                            select max(a.check_version) check_version\n                                            from check_result_{company} a,dim_date b where DATE_FORMAT(a.check_date,'%Y%m%d') = b.day_id\n                                            and b.year={year}\n                                            and b.quarter={quarter}\n                                            and b.month={month}\n                                            and b.day={day}\n                                        ) b\n                                        where a.problem_count is not null\n                                        and a.problem_count !=0\n                                        and a.risk_market_item='是'\n                                        and a.check_version=b.check_version\n                    ) a\n                    group by a.check_item\n                    order by 2 desc\"\"\"\n        curs.execute(sql)\n        result = curs.fetchall()\n        result_list = [['问题占比', '问题数据总量', '问题数据项'], ]\n        for i in result:\n            problem_per = (int(i[1]) / int(i[0]))\n            problem_per = round(problem_per * 100, 2)\n            problem_total = int(i[1])\n            item = i[2]\n            result_list.append([problem_per, problem_total, item])\n        return JsonResponse(result_list, safe=False)\n    except Exception as e:\n        print(e)\n        return JsonResponse({'msg': str(e)})\n    finally:\n        curs.close()\n        conn.close()\n\n"
  },
  {
    "path": "api/api_datastandard.py",
    "content": "from django.http.response import JsonResponse\nfrom django.views.decorators.http import require_http_methods\n\nimport sys, MySQLdb\n\nsys.path.insert(0, '..')\nfrom mysite import db_config\n\n\ndef db_query(std_name, std_type):\n    conn = db_config.mysql_connect()\n    curs = conn.cursor()\n    if std_type == 'detail':\n        '''\n        请求类型：GET\n\n        请求参数：std_name数据标准名\n\n        返回参数：\n            id                      主键id\n            std_id                  标准编号\n            name                    标准名称\n            en_name                 标准英文名称\n            business_definition     业务定义\n            business_rule           业务规则\n            std_source              标准来源\n            data_type               数据类型\n            data_format             数据格式\n            code_rule               编码规则\n            code_range              编码范围\n            code_meaning            编码含义\n            business_range          业务范围\n            dept                    数据责任部门\n            system                  数据使用系统\n        '''\n        sql = f\"\"\"select id,std_id,name,en_name,business_definition,business_rule,std_source,data_type,data_format,\ncode_rule,code_range,code_meaning,business_range,dept,`system`\nfrom data_standard_detail\nwhere name='{std_name}'\"\"\"\n        print(sql)\n        curs.execute(sql)\n        result = curs.fetchone()\n        return {\n            'std_id': result[1],\n            'name': result[2],\n            'en_name': result[3],\n            'business_definition': result[4],\n            'business_rule': result[5],\n            'std_source': result[6],\n            'data_type': result[7],\n            'data_format': result[8],\n            'code_rule': result[9],\n            'code_range': result[10],\n            'code_meaning': result[11],\n            'business_range': result[12],\n            'dept': result[13],\n            'system': result[14],\n        }\n    elif std_type == 'desc':\n        '''\n        请求类型：GET\n\n        请求参数：std_name数据标准名\n\n        返回参数：\n            id          主键id\n            name        标准名称\n            content     标准内容    \n        '''\n        sql = f\"select id,name,content from data_standard_desc where name='{std_name}'\"\n        curs.execute(sql)\n        result = curs.fetchone()\n        return {\n            'name': result[1],\n            'content': result[2],\n        }\n    curs.close()\n    conn.close()\n\n\n# 查询数据标准\n@require_http_methods([\"GET\"])\ndef query_detail(request):\n    std_name = request.GET.get('std_name')\n    std_type = request.GET.get('std_type')\n\n    if not all([std_name, std_type]):\n        return JsonResponse({'msg': '请求参数缺失', 'code': 3000})\n\n    data = db_query(std_name, std_type)\n    return JsonResponse(data)\n\n\n# 查询数据标准编辑记录\n@require_http_methods([\"GET\"])\ndef query_update_history(request):\n    std_name = request.GET.get('std_name')\n\n    if std_name is None:\n        return JsonResponse({'msg': '请求参数缺失', 'code': 3000})\n\n    conn = db_config.mysql_connect()\n    curs = conn.cursor()\n    sql = f\"select username,update_time from data_standard_update_log where std_name='{std_name}' order by update_time desc limit 1\"\n    if curs.execute(sql) == 1:\n        result = curs.fetchone()\n        return JsonResponse({'username': result[0], 'last_update_time': str(result[1])})\n    else:\n        return JsonResponse({'username': None, 'last_update_time': None})\n\n\n# 更新数据标准\n@require_http_methods([\"POST\"])\ndef update(request):\n    username = request.POST.get('username')\n    std_type = request.POST.get('std_type')\n    std_name = request.POST.get('std_name')\n    en_name = request.POST.get('en_name')\n    business_definition = request.POST.get('business_definition')\n    business_rule = request.POST.get('business_rule')\n    std_source = request.POST.get('std_source')\n    data_type = request.POST.get('data_type')\n    data_format = request.POST.get('data_format')\n    code_rule = request.POST.get('code_rule')\n    code_range = request.POST.get('code_range')\n    code_meaning = request.POST.get('code_meaning')\n    business_range = request.POST.get('business_range')\n    dept = request.POST.get('dept')\n    system = request.POST.get('system')\n    content = request.POST.get('content')\n\n    conn = db_config.mysql_connect()\n    curs = conn.cursor()\n    curs.execute('set autocommit=0')\n\n    if not all([std_name, std_type]):\n        return JsonResponse({'msg': '请求参数缺失', 'code': 3000})\n\n    # post内容与数据库内容对比，如果内容一致则无需update\n    orgin_data = db_query(std_name, std_type)\n\n    if std_type == 'desc':\n        post_data = {'name': std_name, 'content': content}\n\n        if post_data == orgin_data:\n            return JsonResponse({'msg': '内容一致，无需修改', 'code': 1001})\n        else:\n            try:\n                # 把上一版本的数据标准内容存入到日志表\n                update_log = str(orgin_data.items() - post_data.items())  # 将被update替换的内容\n                sql = f\"insert into data_standard_update_log(std_name, username, previous_version) values('{std_name}', '{username}', \\\"{update_log}\\\")\"\n                curs.execute(sql)\n                conn.commit()\n\n                # 更新数据标准\n                sql = f\"update data_standard_desc set name='{std_name}', content='{content}' where name='{std_name}'\"\n                curs.execute(sql)\n                conn.commit()\n                curs.close()\n                conn.close()\n                return JsonResponse({'msg': '修改成功', 'code': 1000})\n            except Exception as e:\n                return JsonResponse({'msg': e, 'code': 2000})\n    elif std_type == 'detail':\n        post_data = {\n            'name': std_name,\n            'en_name': en_name,\n            'business_definition': business_definition,\n            'business_rule': business_rule,\n            'std_source': std_source,\n            'data_type': data_type,\n            'data_format': data_format,\n            'code_rule': code_rule,\n            'code_range': code_range,\n            'code_meaning': code_meaning,\n            'business_range': business_range,\n            'dept': dept,\n            'system': system,\n        }\n\n        if post_data == db_query(std_name, std_type):\n            return JsonResponse({'msg': '内容一致，无需修改', 'code': 1001})\n        else:\n            try:\n                # 把上一版本的数据标准内容存入到日志表\n                update_log = str(orgin_data.items() - post_data.items())  # 将被update替换的内容\n                sql = f\"insert into data_standard_update_log(std_name, username, previous_version) values('{std_name}', '{username}', \\\"{update_log}\\\")\"\n                curs.execute(sql)\n                conn.commit()\n\n                sql = f\"\"\"update data_standard_detail set name = '{std_name}', \n                                                    en_name = '{en_name}',\n                                                    business_definition = '{business_definition}', \n                                                    business_rule = '{business_rule}',\n                                                    std_source = '{std_source}',\n                                                    data_type = '{data_type}',\n                                                    data_format = '{data_format}',\n                                                    code_rule = '{code_rule}',\n                                                    code_range = '{code_range}',\n                                                    code_meaning = '{code_meaning}',\n                                                    business_range = '{business_range}',\n                                                    dept = '{dept}',\n                                                    `system` = '{system}'\n                    where name='{std_name}'\"\"\"\n                curs.execute(sql)\n                conn.commit()\n                curs.close()\n                conn.close()\n                return JsonResponse({'msg': '修改成功', 'code': 1000})\n            except Exception as e:\n                return JsonResponse({'msg': str(e), 'code': 2000})\n\n\n# 获取数据标准目录\n@require_http_methods([\"GET\"])\ndef query_index(request):\n    conn = db_config.mysql_connect()\n    curs = conn.cursor()\n\n    sql = \"select idx_id, idx_pid,idx_name,is_open from data_standard_index\"\n    curs.execute(sql)\n    result = curs.fetchall()\n\n    data = []\n    for i in result:\n        data.append({\n            'id': i[0],\n            'pId': i[1],\n            'name': i[2],\n            't': i[2],\n            'open': i[3]\n        })\n\n    curs.close()\n    conn.close()\n    return JsonResponse(data, safe=False)\n"
  },
  {
    "path": "api/api_date.py",
    "content": "from django.http.response import HttpResponse, JsonResponse\nfrom django.views.decorators.http import require_http_methods\n\nimport datetime\nimport math\n\nimport sys\nsys.path.insert(0, '..')\nfrom mysite import db_config\nfrom utils import functions as f\n\n@require_http_methods(['GET'])\ndef year_list(request):\n    '''查询已有检核结果的年份\n    '''\n    year = f.query_data_year()\n    \n    if year:\n        return JsonResponse({'data': year})\n    else:\n        return HttpResponse({'获取年份错误'}, status=500)\n\n\n@require_http_methods(['GET'])\ndef quarter_list(request):\n    '''查询已有检核结果的季度\n    '''\n    year = request.GET.get('year')\n    if not year:\n        year = datetime.datetime.now().year\n\n    quarter = f.query_data_quarter(year)\n    if quarter:\n        return JsonResponse({'data': quarter})\n    else:\n        return HttpResponse({'获取季度错误'}, status=500)\n    \n\n@require_http_methods(['GET'])\ndef month_list(request):\n    '''查询已有检核结果的月份\n    '''\n    year = request.GET.get('year')\n    quarter = request.GET.get('quarter')\n    if not all((year, quarter)):\n        year = year or datetime.datetime.now().year\n        quarter = quarter or math.ceil(datetime.datetime.now().month/3.)\n\n    month = f.query_data_month(year, quarter)\n    if month:\n        return JsonResponse({'data': month})\n    else:\n        return HttpResponse({'获取月份错误'}, status=500)\n\n\n@require_http_methods(['GET'])\ndef day_list(request):\n    '''查询已有检核结果的天\n    '''\n    year = request.GET.get('year')\n    quarter = request.GET.get('quarter')\n    month = request.GET.get('month')\n    if not all((year, quarter, month)):\n        year = year or datetime.datetime.now().year\n        quarter = quarter or math.ceil(datetime.datetime.now().month/3.)\n        month = month or datetime.datetime.now().month\n\n    day = f.query_data_day(year, quarter, month)\n    if day:\n        return JsonResponse({'data': day})\n    else:\n        return HttpResponse({'获取天错误'}, status=500)"
  },
  {
    "path": "api/api_files.py",
    "content": "import os\n\nfrom django.http import Http404, FileResponse\nfrom django.utils.encoding import escape_uri_path\n\n\ndef download(request):\n    filename = request.GET.get('filename')\n    file_path = '/data/pyweb/data-quality/static/files/' + filename\n    ext = os.path.basename(file_path).split('.')[-1].lower()\n    # 禁止请求含有py、db、sqlite3关键字的文件名\n    if ext not in ['py', 'db', 'sqlite3']:\n        response = FileResponse(open(file_path, 'rb'))\n        response['content_type'] = \"application/octet-stream\"\n        response[\n            'Content-Disposition'] = \"attachment; filename*=utf-8''{}\".format(\n                escape_uri_path(filename))\n        print(response['Content-Disposition'])\n        return response\n    else:\n        raise Http404"
  },
  {
    "path": "api/api_quality.py",
    "content": "from django.http.response import JsonResponse\nfrom django.views.decorators.http import require_http_methods\n\nimport sys\n\nsys.path.insert(0, '..')\nfrom mysite import db_config\n\n\n@require_http_methods(['GET'])\ndef quality_detail(request):\n    \"\"\"\n    查询给定日期的检核明细结果，返回最新版本数据\n    \"\"\"\n    company = request.GET.get('company')\n    year = request.GET.get('year')\n    quarter = request.GET.get('quarter')\n    month = request.GET.get('month')\n    day = request.GET.get('day')\n    \n    try:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        sql  = f\"\"\"select id,\n\t\t\t\tsource_system,\n\t\t\t\tcheck_item,\n\t\t\t\ttarget_table,\n\t\t\t\trisk_market_item,\n\t\t\t\tproblem_type,\n\t\t\t\tcheck_sql,\n\t\t\t\titem_count,\n\t\t\t\tproblem_count,\n\t\t\t\tconcat(problem_per,'%'),\n\t\t\t\tnote,\n\t\t\t\tcheck_date\n\t\t\t\tfrom check_result_{company} a,\n\t\t\t\t(\n\t\t\t\t\tselect max(a.check_version) check_version\n\t\t\t\t\tfrom check_result_{company} a,dim_date b where DATE_FORMAT(a.check_date,'%Y%m%d') = b.day_id\n\t\t\t\t\tand b.year={year}\n\t\t\t\t\tand b.quarter={quarter}\n\t\t\t\t\tand b.month={month}\n\t\t\t\t\tand b.day={day}\n\t\t\t\t) b\n\t\t\t\twhere a.risk_market_item='是'\n\t\t\t\tand a.check_version=b.check_version\n\t\t\t\torder by id asc\"\"\"\n        curs.execute(sql)\n        result = curs.fetchall()\n        \n        result_list = []\n        for i in result:\n            result_dict = {\"id\": i[0], \"source_system\": i[1], \"check_item\": i[2], \"target_table\": i[3], \"risk_market_item\": i[4],\n                           \"problem_type\": i[5], \"check_sql\": i[6], \"item_count\": i[7], \"problem_count\": i[8], \"problem_per\": i[9],\n                           \"note\": i[10], \"check_date\": i[10]}\n            result_list.append(result_dict)\n        return JsonResponse({'data': result_list})\n    except Exception as e:\n        print(e)\n        return JsonResponse({'msg': str(e)})\n    finally:\n        curs.close()\n        conn.close()\n        \n        \n@require_http_methods(['GET'])\ndef report_detail(request):\n    \"\"\"\n    查询给定日期，各公司的检核明细结果，返回最新版本数据\n    \"\"\"\n    company = request.GET.get('company')\n    year = request.GET.get('year')\n    quarter = request.GET.get('quarter')\n    month = request.GET.get('month')\n    day = request.GET.get('day')\n    \n    try:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        sql  = f\"\"\"select a.check_item,a.problem_type,a.problem_count,a.item_count,concat(a.problem_per,'%') problem_per \n                    from check_result_{company} a,\n                    (\n                        select max(a.check_version) check_version\n                        from check_result_{company} a,dim_date b where DATE_FORMAT(a.check_date,'%Y%m%d') = b.day_id\n                        and b.year={year}\n                        and b.quarter={quarter}\n                        and b.month={month}\n                        and b.day={day}\n                    ) b\n                    where a.risk_market_item='是'\n                    and a.check_version=b.check_version\n                    and (a.problem_count<>0 or a.problem_count is null)\n                    order by a.problem_type,a.problem_count desc\"\"\"\n        curs.execute(sql)\n        result = curs.fetchall()\n        \n        result_list = []\n        for i in result:\n            result_dict = {\"check_item\": i[0],\n                           \"problem_type\": i[1],\n                           \"problem_count\": i[2],\n                           \"item_count\": i[3],\n                           \"problem_per\": i[4],\n                           }\n            result_list.append(result_dict)\n        return JsonResponse({'data': result_list})\n    except Exception as e:\n        print(e)\n        return JsonResponse({'msg': str(e)})\n    finally:\n        curs.close()\n        conn.close()"
  },
  {
    "path": "api/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass ApiConfig(AppConfig):\n    name = 'api'\n"
  },
  {
    "path": "api/models.py",
    "content": "from django.db import models\n\n# Create your models here.\n"
  },
  {
    "path": "api/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "api/views.py",
    "content": "from django.shortcuts import render\n\n# Create your views here.\n"
  },
  {
    "path": "authorize/__init__.py",
    "content": ""
  },
  {
    "path": "authorize/admin.py",
    "content": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "authorize/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass AuthorizeConfig(AppConfig):\n    name = 'authorize'\n"
  },
  {
    "path": "authorize/models.py",
    "content": "from django.db import models\n\n# Create your models here.\n"
  },
  {
    "path": "authorize/templates/authorize/login.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-cmn-Hans\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta content=\"IE=edge\" http-equiv=\"X-UA-Compatible\">\n    <meta content=\"initial-scale=1.0, maximum-scale=1.0, user-scalable=no, width=device-width\" name=\"viewport\">\n    <!-- <meta name=\"theme-color\" content=\"#3f51b5\"> -->\n    <title>数据质量管理平台</title>\n\n    <link href=\"https://cdn.bootcss.com/twitter-bootstrap/3.3.5/css/bootstrap.min.css\" rel=\"stylesheet\">\n    <link href=\"/static/css/material-dash.css\" rel=\"stylesheet\">\n    <link href=\"https://fonts.googleapis.com/icon?family=Material+Icons\" rel=\"stylesheet\">\n    <link href=\"https://cdn.bootcss.com/materialize/1.0.0/css/materialize.min.css\" rel=\"stylesheet\">\n\n    <link rel=\"shortcut icon\" href=\"/static/img/favicon.ico\" type=\"image/x-icon\" />\n    <link href=\"/static/css/login.css\" rel=\"stylesheet\">\n\n    <style>\n        .nav>li>a {\n            padding-top: unset !important;\n            padding-bottom: unset !important;\n        }\n        nav i, nav [class^=\"mdi-\"], nav [class*=\"mdi-\"], nav i.material-icons {\n            display: unset;\n        }\n        input[type=\"checkbox\"]:not(:checked), [type=\"checkbox\"]:checked {\n            position: unset;\n            opacity: unset;\n            pointer-events: unset;\n        }\n    </style>\n</head>\n\n<body class=\"off-canvas-sidebar\" onload=\"Onload();\">\n    <!-- Begin 背景动画 -->\n    <div id=\"bg\">\n    </div>\n    <!-- End 背景动画 -->\n\n    <nav class=\"navbar navbar-primary navbar-transparent navbar-absolute\">\n        <div class=\"container\">\n            <div class=\"navbar-header\">\n                <button type=\"button\" class=\"navbar-toggle\" data-toggle=\"collapse\" data-target=\"#navigation-example-2\">\n                    <span class=\"sr-only\">Toggle navigation</span>\n                    <span class=\"icon-bar\"></span>\n                    <span class=\"icon-bar\"></span>\n                    <span class=\"icon-bar\"></span>\n                </button>\n                <a class=\"navbar-brand\" href=\"/\">数据质量管理平台</a>\n            </div>\n            <div class=\"collapse navbar-collapse\">\n                <ul class=\"nav navbar-nav navbar-right\">\n                    <li id=\"home\">\n                        <a href=\"/\">\n                            <i class=\"material-icons\">dashboard</i> 首页\n                        </a>\n                    </li>\n                    <li id=\"bind-mobile\">\n                        <a href=\"#\">\n                            <i class=\"material-icons\">person_add</i> 绑定手机号\n                        </a>\n                    </li>\n                    <li id=\"login-page\" class=\"active\">\n                        <a href=\"#\" onclick=\"SwitchTab('InputForm');\">\n                            <i class=\"material-icons\">fingerprint</i> 登录\n                        </a>\n                    </li>\n                    <li id=\"reset-pwd\" class=\"\">\n                        <a href=\"#\" onclick=\"SwitchTab('ResetForm');\">\n                            <i class=\"material-icons\">verified_user</i> 重置密码\n                        </a>\n                    </li>\n                </ul>\n            </div>\n        </div>\n    </nav>\n    <div class=\"wrapper wrapper-full-page\">\n        <div class=\"full-page login-page\">\n            <div class=\"content\">\n                <div class=\"container\">\n                    <div class=\"row\">\n                        <div class=\"col-md-4 col-sm-6 col-md-offset-4 col-sm-offset-3\">\n                            <div class=\"card card-login\">\n                                <div class=\"card-header text-center\" data-background-color=\"rose\">\n                                    <div class=\"card-title\">\n                                        <span>\n                                            <!-- <img src=\"/static/img/logo.png\" /> -->\n                                            数据质量管理平台\n                                        </span>\n                                    </div>\n\n                                    <div class=\"social-line\">\n                                        <a href=\"#账号登录\" class=\"btn btn-just-icon btn-simple\" onclick=\"SwitchTab('InputForm');\">\n                                            <span style=\"font-size: 14px;\">账号登录</span>\n                                        </a>\n                                    </div>\n                                </div>\n                                \n                                <!-- Begin 账号登录 -->\n                                <div class=\"card-content\" id=\"InputForm\">\n                                    <div class=\"input-group\" onkeydown=\"NextElement('username');\">\n                                        <span class=\"input-group-addon\"><i class=\"material-icons\">face</i></span>\n                                        <div class=\"form-group label-floating\">\n                                            <label class=\"control-label\">账号名</label>\n                                            <input class=\"form-control\" style=\"cursor: auto;\" type=\"text\" id=\"username\" value=\"admin\">\n                                            <span class=\"material-input\"></span>\n                                        </div>\n                                    </div>\n\n                                    <div class=\"input-group\" onkeydown=\"NextElement('password');\">\n                                        <span class=\"input-group-addon\"><i class=\"material-icons\">lock_outline</i></span>\n                                        <div class=\"form-group label-floating\">\n                                            <label class=\"control-label\">密码</label>\n                                            <input class=\"form-control\" style=\"cursor: auto;\" type=\"password\" id=\"password\" value=\"admin\">\n                                            <span class=\"material-input\"></span>\n                                        </div>\n                                    </div>\n\n                            \n                                    <a id=\"forget-password\" href=\"javascript:void(0)\" onclick=\"SwitchTab('ResetForm');\">忘记密码？</a>\n                                </div>\n                                <!-- End 账号登录 -->\n\n                                <!-- Begin 重置密码 -->\n                                <div class=\"card-content\" id=\"ResetForm\" style=\"display: none;\">\n                                    <div class=\"input-group\">\n                                        <span class=\"input-group-addon\"><i class=\"material-icons\">phone_iphone</i></span>\n                                        <div class=\"form-group label-floating\">\n                                            <label class=\"control-label\">手机号</label>\n                                            <input class=\"form-control\" style=\"cursor: auto;\" type=\"text\" id=\"mobile\">\n                                            <span class=\"material-input\"></span>\n                                        </div>\n                                    </div>\n\n                                    <div class=\"input-group\" onkeydown=\"NextElement('send-sms');\">\n                                        <span class=\"input-group-addon\">\n                                            <button id=\"send-sms\" type=\"button\" onclick=\"SendSMSCode();\" class=\"btn  btn-md\">获取验证码</button>\n                                        </span>\n                                        <div class=\"form-group label-floating\">\n                                            <label class=\"control-label\">短信验证码</label>\n                                            <input class=\"form-control\" style=\"cursor: auto;\" type=\"text\" id=\"sms-code\">\n                                            <span class=\"material-input\"></span>\n                                        </div>\n                                    </div>\n\n                                    <div class=\"input-group\" onkeydown=\"NextElement('new-password');\">\n                                        <span class=\"input-group-addon\"><i class=\"material-icons\">lock_outline</i></span>\n                                        <div class=\"form-group label-floating\">\n                                            <label class=\"control-label\">新密码</label>\n                                            <input class=\"form-control\" style=\"cursor: auto;\" type=\"password\" id=\"new-password\">\n                                            <span class=\"material-input\"></span>\n                                        </div>\n                                    </div>\n\n                                    <a id=\"forget-password\" href=\"javascript:void(0)\" onclick=\"SwitchTab('InputForm');\">返回账号登录</a>\n                                </div>\n                                <!-- End 重置密码 -->\n\n                                <!-- 登录按钮 -->\n                                <div class=\"text-center\">\n                                    <button type=\"button\" id=\"login\" onclick=\"Login();\" class=\"btn btn-rose btn-simple btn-wd btn-lg\">登录</button>\n                                    <button type=\"button\" id=\"reset\" onclick=\"ModifyPassword();\" class=\"btn btn-rose btn-simple btn-wd\" style=\"display: none;\">重置密码并登陆</button>\n                                </div>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n        \n    </div>\n    <footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;color:gray;text-align: right;\">\n        <div class=\"footer\">\n                © 2019-2020 Hyhyhyhyhyhyh\n        </div>\n    </footer>\n\n    <script type=\"text/javascript\" src=\"https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js\"></script>\n    <script type=\"text/javascript\" src=\"/static/js/login.js\"></script>\n    <script type=\"text/javascript\" src=\"/static/js/sweetalert.min.js\"></script>\n</body>\n\n</html>"
  },
  {
    "path": "authorize/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "authorize/urls.py",
    "content": "from django.urls import path\n\nfrom . import views\n\napp_name = 'authorize'\nurlpatterns = [\n    path('login', views.login, name='login'),\n    path('logout', views.logout, name='logout'),\n    path('login_auth', views.login_auth, name='login_auth'),\n    path('register', views.register, name='register'),\n    path('register_auth', views.register_auth, name='register_auth'),\n]"
  },
  {
    "path": "authorize/views.py",
    "content": "from django.shortcuts import render, redirect\nfrom django.views.decorators.http import require_http_methods\nfrom django.http.response import JsonResponse\n\n\n# from ldap3 import Server, Connection, ALL, SUBTREE, ServerPool,ALL_ATTRIBUTES\n\n# 登录页面\ndef login(request):\n    return render(request, \"authorize/login.html\")\n\n\n# 登录验证\n@require_http_methods([\"POST\"])\ndef login_auth(request):\n    username = request.POST.get('username')\n    password = request.POST.get('password')\n\n    # 普通验证\n    if username == 'admin' and password == 'admin':\n        request.session['username'] = username\n        request.session['is_login'] = True\n        if request.POST.get('autologin') == 'on':\n                request.session.set_expiry(7*24*60*60)  #session过期时间为7天\n        return JsonResponse({'status': 'success'})\n    else:\n        # user_conn.unbind()\n        # conn.unbind()\n        return JsonResponse({'status': 'failed'})\n\n    \"\"\"\n    使用openLDAP进行用户身份验证\n\n    server = Server(host='', port=636, use_ssl=True, get_info='ALL')\n    # 使用admin登录openldap验证输入的用户名\n    ldap_admin_dn = \"\"\n    ldap_admin_password = \"\"\n    conn = Connection(server, user=ldap_admin_dn, password=ldap_admin_password, auto_bind=True,version=3)\n    res = conn.search(search_base='',search_filter='(uid={})'.format(username)) #验证表单输入的账号名\n    if res:\n        entry = conn.response[0]  # 验证账号名及获取用户组织架构\n        user_dn = entry['dn']\n        user_status = entry['attributes']  #后续增加账号状态验证\n        # 验证密码\n        user_conn = Connection(server, user=user_dn, password=password, auto_bind=False,version=3)\n        if user_conn.bind() is True:\n            #验证通过\n            user_conn.unbind()\n            conn.unbind()\n            \n            if request.POST.get('autologin')==\"1\":\n                request.session.set_expiry(7*24*60*60)  #session过期时间为7天\n            request.session['username']=username\n            request.session['is_login']=True\n            return redirect('../../data/index')\n        else:\n            user_conn.unbind()\n            conn.unbind()\n            alert = \"<script>alert ('密码输入不正确');window.location.href='login';</script>\"\n            return render(request, 'authorize/login.html',{'alert':alert})\n    else:\n        conn.unbind()\n        alert = \"<script>alert ('账号名输入不正确');window.location.href='login';</script>\"\n        return render(request, 'authorize/login.html',{'alert':alert})\n    \"\"\"\n\n\ndef logout(request):\n    request.session.clear()\n    return render(request, \"authorize/login.html\")\n"
  },
  {
    "path": "backend/__init__.py",
    "content": ""
  },
  {
    "path": "backend/admin.py",
    "content": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "backend/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass BackendConfig(AppConfig):\n    name = 'backend'\n"
  },
  {
    "path": "backend/models.py",
    "content": "from django.db import models\n\n# Create your models here.\n"
  },
  {
    "path": "backend/templates/backend/crontab.html",
    "content": "{% include \"data/template-ui.html\" %}\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/icons.css\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/fonts.css\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/sweetalert.css\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/switchery.min.css\" />\n\n<style>\n    .container-fluid {\n        padding: 0 10 0;\n    }\n\n    .page-wrapper {\n        padding-bottom: 20px;\n    }\n\n    .page-wrapper {\n        min-height: 600px !important;\n    }\n\n    .table {\n        font-size: 13px;\n    }\n    .table > tbody > tr > td, .table > tbody > tr > th, .table > tfoot > tr > td, .table > tfoot > tr > th, .table > thead > tr > td, .table > thead > tr > th {\n        line-height: unset;\n    }\n    tbody tr td {\n        text-align: left;\n    }\n    \n    h6 {\n        color: rgb(0,128,82);\n    }\n\n    .btn {\n        margin-top: -3px;\n        margin-left: 1px;\n        background-color: #4680ff;\n        color: aliceblue;\n    }\n    .btn:hover, .btn:focus {\n        color:aliceblue;\n    }\n</style>\n\n<div class=\"page-wrapper\">\n    <div class=\"container-fluid animated fadeInUp\">\n        <div class=\"row\">\n            <div class=\"card col-12\">\n                <div class=\"card-title\">\n                    <h4 class=\"text-primary\">后台任务 - 调度信息</h4>\n                </div>\n\n                <div class=\"card-content\">\n                    <table class=\"table table-hover\">\n                        <thead>\n                            <td>任务名</td>\n                            <td>任务内容</td>\n                            <td>启用状态</td>\n                            <td>调度周期</td>\n                            <td># 操作</td>\n                        </thead>\n                        <tbody>\n                        {% for i in jobs %}\n                            <tr>\n                                <!-- 任务名 -->\n                                <td>{{ i.0 }}</td>\n\n                                <!-- 任务内容 -->\n                                <td>{{ i.1 }}</td>\n\n                                <!-- 启用状态 -->\n                                <td>\n                                    {% if i.2 == True %}\n                                    <input job_name=\"{{ i.0 }}\" type=\"checkbox\" class=\"js-switch\" checked/>\n                                    {% elif i.2 == False %}\n                                    <input job_name=\"{{ i.0 }}\" type=\"checkbox\" class=\"js-switch\"/>\n                                    {% endif %}\n                                </td>\n                                \n                                <!-- 调度周期 -->\n                                <td>{{ i.3 }}</td>\n\n                                <!-- 操作 -->\n                                <td>\n                                    <button job_name=\"{{ i.0 }}\" onclick=\"ExecJob(this);\" class=\"btn btn-xs btn-check\" type=\"button\">\n                                        <i class=\"im-rocket\"></i>&nbsp;&nbsp;立即执行>>\n                                    </button>\n                                </td>\n                            </tr>\n                        {% endfor%}\n                        </tbody>\n                    </table>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n\n<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n    <div class=\"footer\">\n        © 2019-2020 Hyhyhyhyhyhyh\n    </div>\n</footer>\n\n\n<!-- 设置头像 / 设置日期 -->\n<script src=\"/static/js/init.js\"></script>\n\n<script src=\"/static/js/sweetalert.min.js\"></script>\n<script src=\"/static/js/switchery.min.js\"></script>\n\n<script>\n    var elems = Array.prototype.slice.call(document.querySelectorAll('.js-switch'));\n\n    elems.forEach(function(html) {\n        var switchery = new Switchery(html, { size: 'small' });\n\n        html.onchange = function(e) {\n            var obj = $(this);\n            var job_name = obj.attr('job_name');\n            var enable;\n\n            if (obj.is(':checked')) {\n                enable = true;\n            } else {\n                enable = false;\n            }\n\n            // 修改定时任务启用状态\n            $.ajax({\n                url: '../../api/backend/crontab/enable',\n                type: 'POST',\n                data:{\n                    \"enable\": enable,\n                    \"job_name\": job_name,\n                },\n                success: function (data) {\n                    if (data.msg == 'success') {\n                        return true\n                    }\n                    else {\n                        swal({\n\t\t\t\t\t\t\ttitle: \"发生错误\",\n                            icon: \"error\",\n                            buttons: false,\n\t\t\t\t\t\t\ttimer: 1000\n\t\t\t\t\t\t});\n                    }\n                },\n                error: function (e) {\n                    swal({\n                        title: \"发生错误\",\n                        icon: \"error\",\n                        buttons: false,\n                        timer: 1000\n                    });\n                }\n            })\n          }\n    });\n\n    function ExecJob(obj){\n        var job_name = obj.attributes.job_name.value;\n        obj.disabled = true;\n        \n        // 手工触发定时任务\n        $.ajax({\n            url: '../../api/backend/crontab/run',\n            type: 'POST',\n            data:{\n                \"job_name\": job_name,\n            },\n            success: function (data) {\n                if (data.msg == 'success') {\n                    obj.disabled = false;\n                    swal({\n                        title: job_name + \"  执行完成\",\n                        icon: \"success\",\n                        timer: 1000\n                    });\n                }\n                else {\n                    swal({\n                        title: \"发生错误\",\n                        icon: \"error\",\n                        buttons: false,\n                        timer: 1000\n                    });\n                }\n            },\n            error: function (e) {\n                swal({\n                    title: \"发生错误\",\n                    icon: \"error\",\n                    buttons: false,\n                    timer: 1000\n                });\n            }\n        })\n    }\n</script>\n\n</body>\n\n</html>"
  },
  {
    "path": "backend/templates/backend/database.html",
    "content": "{% include \"data/template-ui.html\" %}\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/icons.css\" />\n<style>\n    table {\n        border-collapse: collapse;\n        width: 100%;\n        font-size: 13px;\n    }\n    .table > tbody > tr > td, .table > tbody > tr > th, .table > tfoot > tr > td, .table > tfoot > tr > th, .table > thead > tr > td, .table > thead > tr > th {\n        line-height: unset;\n        vertical-align: middle;\n    }\n</style>\n\n<div class=\"page-wrapper\">\n    <!-- 标题 -->\n    <div class=\"row page-titles\">\n        <div class=\"col-md-1 align-self-center\">\n            <h3 class=\"text-primary\" style=\"font-family: 'Open Sans', sans-serif;\">数据源</h3>\n        </div>\n\n        <div class=\"col-md-7\">\n            <a href=\"../backend/database/add\" target=\"_blank\" class=\"btn btn-primary\"><i class=\"im-plus-circle\"></i> 添加数据源</a>\n        </div>\n\n        <div class=\"col-md-4 align-self-center\">\n            <ol class=\"breadcrumb\">\n                <li class=\"breadcrumb-item\"><a href=\"../../data/dashboard/\">主页</a></li>\n                <li class=\"breadcrumb-item active\">数据源</li>\n            </ol>\n        </div>\n    </div>\n\n    <div class=\"container-fluid\">\n        <div class=\"row\">\n            <div class=\"col-md-12\">\n                <div class=\"card\" id=\"page-content\">\n                    <div class=\"table-responsive\">\n                        <table class=\"table table-hover overview_table\">\n                            <thead>\n                                <tr>\n                                    <th>所属公司</th>\n                                    <th>#</th>\n                                    <th>类型</th>\n                                    <th>源系统名</th>\n                                    <th>连接串</th>\n                                    <th>说明</th>\n                                    <th>详情</th>\n                                </tr>\n                            </thead>\n                            <tbody id=\"database\">\n                            </tbody>\n                        </table>\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n\n<!-- footer -->\n<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n    <div class=\"footer\">\n        © 2019-2020 Hyhyhyhyhyhyh\n    </div>\n</footer>\n</div>\n\n\n<!-- 设置头像 / 设置日期 -->\n<script src=\"/static/js/init.js\"></script>\n\n<script>\n    $.ajax({\n        type : \"GET\",\n        async : true,\n        url : \"../../api/backend/database/query\",    \n        data: {},\n        dataType : \"json\",\n        success : function(result) {\n            let tab = document.getElementById(\"database\");\n            let html = \"\";\n            for(let i in result.data.company){\n                html += \"<tr>\";\n                html += \"<td>\" + result.data.company[i] + \"</td>\";\n                html += '<td><img src=\"../../static/icons/db-icons/'+ result.data.db_type[i] +'.svg\" style=\"height:25px;width:40px;\"></img></td>';\n                html += \"<td>\" + result.data.db_type[i] + \"</td>\";\n                html += \"<td>\" + result.data.alias[i] + \"</td>\";\n                html += \"<td>\" + result.data.connection_string[i] + \"</td>\";\n                if(result.data.note[i] == null){\n                    html += \"<td></td>\";\n                }\n                else{\n                    html += \"<td>\" + result.data.note[i] + \"</td>\";\n                }\n                html += '<td><a href=\"../backend/database/detail?id='+ result.data.rowid[i] +'\" target=\"_blank\" style=\"color:#1779ba;\">详情</a></td>';\n                html += \"</tr>\";\n            }\n            tab.innerHTML = html;\n        },\n    })\n</script>\n\n</body>\n\n</html>"
  },
  {
    "path": "backend/templates/backend/database_add.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-cmn-Hans\">\n\n<head>\n\t<meta charset=\"utf-8\">\n\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n\t<!-- Tell the browser to be responsive to screen width -->\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t<meta name=\"description\" content=\"\">\n\t<meta name=\"author\" content=\"\">\n\t<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/static/img/favicon.ico\" />\n\t<title>数据质量检核平台</title>\n\n\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/check/css/admin/bootstrap.min.css\" />\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/check/css/admin/style.css\" />\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/icons.css\" />\n\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/sweetalert.css\" />\n\n\t<style>\n        .table {\n            color:black;\n        }\n        .table > thead > tr > th, .table > tbody > tr > th, .table > tfoot > tr > th, .table > thead > tr > td, .table > tbody > tr > td, .table > tfoot > tr > td {\n            vertical-align: middle;\n            text-align: center;\n        }\n        .ibox-tools{\n            float: unset;\n        }\n        .ibox-title h5{\n            margin: unset;\n            padding-top: 8px;\n            margin-right: 30px;\n        }\n        .table-hover>tbody>tr:hover {\n            background-color: aliceblue;\n        }\n\t</style>\n</head>\n\n<body>\n\t<div class=\"tnav row wrapper border-bottom white-bg page-heading\">\n\t\t<div class=\"col-sm-4\">\n\t\t\t<h2 class=\"fl\" style=\"color: #007bff;font-size: 21px;font-weight:500\">新增数据源</h2>\n\t\t\t<ol class=\"breadcrumb fl\">\n\t\t\t\t<li><a href=\"../../data/dashboard/\">主页</a></li>\n\t\t\t\t<li><strong>新增数据源</strong></li>\n\t\t\t</ol>\n\t\t</div>\n\t</div>\n\n\t<div class=\"row col-lg-8\">\n\t\t<div class=\"wrapper wrapper-content\">\n\t\t\t<div class=\"ibox\">\n\t\t\t\t<div class=\"ibox-content\">\n                    <table class=\"table table-hover overview_table\">\n                        <tbody>\n                            <tr>\n                                <td style=\"width: 130px;\">公司简称</td>\n                                <td><input id=\"company\" type=\"text\" class=\"form-control\" required></input></td>\n                            </tr>\n                            <tr>\n                                <td>所属公司</td>\n                                <td><input id=\"name\" type=\"text\" class=\"form-control\" required></input></td>\n                            </tr>\n                            <tr>\n                                <td>源系统名称</td>\n                                <td><input id=\"alias\" type=\"text\" class=\"form-control\" required></input></td>\n                            </tr>\n                            <tr>\n                                <td>数据库类型</td>\n                                <td style=\"text-align: left;\">\n                                    <select id=\"db_type\">\n                                        <option value=\"\"></option>\n                                        <option value=\"mysql\">mysql</option>\n                                        <option value=\"oracle\">oracle</option>\n                                        <option value=\"sqlserver\">sqlserver</option>\n                                        <option value=\"postgresql\">postgresql</option>\n                                    </select>\n                                </td>\n                            </tr>\n                            <tr>\n                                <td>IP</td>\n                                <td><input id=\"ip\" type=\"text\" class=\"form-control\"></td>\n                            </tr>\n                            <tr>\n                                <td>端口号</td>\n                                <td><input id=\"port\" type=\"text\" class=\"form-control\"></td>\n                            </tr>\n                            <tr>\n                                <td>数据库名/实例名</td>\n                                <td><input id=\"db\" type=\"text\" class=\"form-control\"></td>\n                            </tr>\n                            <tr>\n                                <td>数据库用户</td>\n                                <td><input id=\"user\" type=\"text\" class=\"form-control\"></td>\n                            </tr>\n                            <tr>\n                                <td>密码</td>\n                                <td><input id=\"password\" type=\"password\" class=\"form-control\" value=\"\"></td>\n                            </tr>\n                            <tr>\n                                <td>字符集</td>\n                                <td><input id=\"charset\" type=\"text\" class=\"form-control\"></td>\n                            </tr>\n                            <tr>\n                                <td>备注说明</td>\n                                <td><input id=\"note\" type=\"text\" class=\"form-control\"></td>\n                            </tr>\n\n                            <tr>\n                                <td colspan=\"2\">\n                                    <button onclick=\"Commit();\" class=\"btn btn-primary\"><i class=\"im-checkmark\"></i> 提交修改</button>\n                                </td>\n                            </tr>\n                        </tbody>\n                    </table>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\n    <footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n\t\t<div class=\"footer\">\n\t\t\t© 2019-2020 Hyhyhyhyhyhyh\n\t\t</div>\n\t</footer>\n\n\t<script type=\"text/javascript\" src=\"/static/js/jquery/jquery.min.js\"></script>\n\t<script type=\"text/javascript\" src=\"/static/js/bootstrap/js/bootstrap.min.js\"></script>\n\t<script type=\"text/javascript\" src=\"/static/js/sweetalert.min.js\"></script>\n\n\t<script>\n        function Commit(){\n            var company = document.getElementById(\"company\");\n            var name = document.getElementById(\"name\");\n            var alias = document.getElementById(\"alias\");\n            var ip = document.getElementById(\"ip\");\n            var user = document.getElementById(\"user\");\n            var password = document.getElementById(\"password\");\n            var db = document.getElementById(\"db\");\n            var port = document.getElementById(\"port\");\n            var db_type = document.getElementById(\"db_type\");\n            var note = document.getElementById(\"note\");\n\n            var db_type_value = db_type[db_type.selectedIndex].value;\n\n            // 判断数据源信息是否存在空值，存在空值则出现提示\n            var obj_id = [\"company\", \"name\", \"alias\", \"ip\", \"user\", \"password\", \"db\", \"port\"];\n            var objs = [company, name, alias, ip, user, password, db, port];\n            var null_cnt = 0;\n            for(let i in objs){\n                if (objs[i].value == null || objs[i].value.length == 0){\n                    document.getElementById(obj_id[i]).style.borderBottomColor = \"#ff0000\";\n                    null_cnt += 1;\n                }\n                else{\n                    objs[i].value = objs[i].value.trim();\n                }\n            }\n            if(db_type_value.length == 0){\n                db_type.style.borderBottomColor = \"#ff0000\";\n            }\n            if(null_cnt > 0){\n                swal({\n                    text: \"存在空值！\",\n                    icon: \"error\",\n                    buttons: false,\n                    timer: 1000\n                });\n                return;\n            }\n            \n            //更新数据库\n            $.ajax({\n                type: \"POST\",\n                url: \"../../api/backend/database/insert\",\n                data: {\n                    company: company.value,\n                    name: name.value,\n                    alias: alias.value,\n                    ip: ip.value,\n                    user: user.value,\n                    password: password.value,\n                    db: db.value,\n                    port: port.value,\n                    db_type: db_type_value,\n                    note: note.value\n                },\n                success: function (data) {\n                    console.log(data);\n                    swal({\n                            text: \"数据源新增成功...\",\n                            icon: \"success\",\n                            buttons: false,\n                            timer: 1000\n                        }).then(function(){\n                            window.history.back(-1) || window.close();\n                        });\n                },\n                error: function (e) {\n                    swal({\n                        title: \"发生错误\",\n                        text: e,\n                        icon: \"error\",\n                    })\n                }\n            })\n        };\n    </script>\n\n</body>\n\n</html>"
  },
  {
    "path": "backend/templates/backend/database_detail.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-cmn-Hans\">\n\n<head>\n\t<meta charset=\"utf-8\">\n\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n\t<!-- Tell the browser to be responsive to screen width -->\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t<meta name=\"description\" content=\"\">\n\t<meta name=\"author\" content=\"\">\n\t<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/static/img/favicon.ico\" />\n\t<title>数据质量检核平台</title>\n\n\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/check/css/admin/bootstrap.min.css\" />\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/check/css/admin/style.css\" />\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/fonts.css\" />\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/icons.css\" />\n\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/sweetalert.css\" />\n\n\t<style>\n        .table {\n            color:black;\n        }\n        .table > thead > tr > th, .table > tbody > tr > th, .table > tfoot > tr > th, .table > thead > tr > td, .table > tbody > tr > td, .table > tfoot > tr > td {\n            vertical-align: middle;\n        }\n        .ibox-tools{\n            float: unset;\n        }\n        .ibox-title h5{\n            margin: unset;\n            padding-top: 8px;\n            margin-right: 30px;\n        }\n\t</style>\n</head>\n\n<body>\n\t<!-- head star -->\n\t<div class=\"tnav row wrapper border-bottom white-bg page-heading\">\n\t\t<div class=\"col-sm-4\">\n\t\t\t<h2 class=\"fl\" style=\"color: #007bff;font-size: 21px;font-weight:500\">数据源：{{ db }} 详情</h2>\n\t\t\t<ol class=\"breadcrumb fl\">\n\t\t\t\t<li><a href=\"../../data/dashboard/\">主页</a></li>\n\t\t\t\t<li><strong>数据源详情</strong></li>\n\t\t\t</ol>\n\t\t</div>\n\t</div>\n\t<!-- head end -->\n\n\t<!-- table star -->\n\t<div class=\"row col-lg-8\">\n\t\t<div class=\"wrapper wrapper-content\">\n\t\t\t<div class=\"ibox\">\n\t\t\t\t<div class=\"ibox-title\">\n\t\t\t\t\t<h5>{{ name }}公司 - {{ db }}数据库 - 详情</h5>\n\t\t\t\t\t<div class=\"ibox-tools rboor\">\n                        <button class=\"btn btn-primary\" onclick=\"Commit();\"><i class=\"im-checkmark\"></i> 提交修改</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"ibox-content\">\n                    <table class=\"table table-hover overview_table\">\n                        <tbody>\n                            <tr>\n                                <td style=\"width: 130px;\">公司简称</td>\n                                <td>{{ company }}</td>\n                            </tr>\n                            <tr>\n                                <td>所属公司</td>\n                                <td>{{ name }}</td>\n                            </tr>\n                            <tr>\n                                <td>源系统名称</td>\n                                <td>{{ alias }}</td>\n                            </tr>\n                            <tr>\n                            <tr>\n                                <td>数据库类型</td>\n                                <td>\n                                    <select id=\"db_type\" class=\"selectpicker\">\n                                        <option>-- 请选择 --</option>\n                                        <option value=\"mysql\">mysql</option>\n                                        <option value=\"oracle\">oracle</option>\n                                        <option value=\"sqlserver\">sqlserver</option>\n                                        <option value=\"postgresql\">postgresql</option>\n                                    </select>\n                                </td>\n                            </tr>\n                            <tr>\n                                <td>IP</td>\n                                <td><input id=\"ip\" type=\"text\" class=\"form-control\" value='{{ ip|default_if_none:\"\" }}' required=\"required\"></td>\n                            </tr>\n                            <tr>\n                                <td>端口号</td>\n                                <td><input id=\"port\" type=\"text\" class=\"form-control\" value='{{ port|default_if_none:\"\" }}' required=\"required\"></td>\n                            </tr>\n                            <tr>\n                                <td>数据库名/实例名</td>\n                                <td><input id=\"db\" type=\"text\" class=\"form-control\" value='{{ db|default_if_none:\"\" }}' required=\"required\"></td>\n                            </tr>\n                            <tr>\n                                <td>数据库用户</td>\n                                <td><input id=\"user\" type=\"text\" class=\"form-control\" value='{{ user|default_if_none:\"\" }}' required=\"required\"></td>\n                            </tr>\n                            <tr>\n                                <td>密码</td>\n                                <td><input id=\"password\" type=\"password\" class=\"form-control\" value=\"\" required=\"required\"></td>\n                            </tr>\n                            <tr>\n                                <td>字符集</td>\n                                <td><input id=\"charset\" type=\"text\" class=\"form-control\" value='{{ charset|default_if_none:\"\" }}' required=\"required\"></td>\n                            </tr>\n                            <tr>\n                                <td>备注说明</td>\n                                <td><input id=\"note\" type=\"text\" class=\"form-control\" value='{{ note|default_if_none:\"\" }}' required=\"required\"></td>\n                            </tr>\n                        </tbody>\n                    </table>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t<!-- table end -->\n\t<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n\t\t<div class=\"footer\">\n\t\t\t© 2019-2020 Hyhyhyhyhyhyh\n\t\t</div>\n\t</footer>\n\n\t<script type=\"text/javascript\" src=\"/static/js/jquery/jquery.min.js\"></script>\n\t<script type=\"text/javascript\" src=\"/static/js/bootstrap/js/bootstrap.min.js\"></script>\n\t<script type=\"text/javascript\" src=\"/static/js/sweetalert.min.js\"></script>\n\n\t<script>\n        function Commit(){\n            var ip = document.getElementById(\"ip\");\n            var user = document.getElementById(\"user\");\n            var password = document.getElementById(\"password\");\n            var db = document.getElementById(\"db\");\n            var port = document.getElementById(\"port\");\n            var db_type = document.getElementById(\"db_type\");\n            var note = document.getElementById(\"note\");\n\n            // 判断数据源信息是否存在空值，存在空值则出现提示\n            var obj_id = [\"ip\", \"user\", \"password\", \"db\", \"port\", \"db_type\"];\n            var objs = [ip, user, password, db, port, db_type];\n            var null_cnt = 0;\n            for(let i in objs){\n                console.log(obj_id[i], objs[i].value);\n                if (objs[i].value == null || objs[i].value.length == 0){\n                    document.getElementById(obj_id[i]).style.borderBottomColor = \"#ff0000\";\n                    null_cnt += 1;\n                }\n            }\n            if(null_cnt > 0){\n                swal({\n                    text: \"存在空值！\",\n                    icon: \"error\",\n                    buttons: false,\n                    timer: 1000\n                });\n                return;\n            }\n\n            swal({\n                text: \"是否确定更新数据源信息？修改操作可能会导致检核任务失败\",\n                icon: \"warning\",\n                buttons: [\"取消\", \"确定\"],\n                dangerMode: true,\n              })\n              .then((value) => {\n                  //更新数据库\n                    $.ajax({\n                        type: \"POST\",\n                        url: \"../../api/backend/database/update\",\n                        data: {\n                            id: \"{{ id }}\",\n                            ip: ip.value,\n                            user: user.value,\n                            password: password.value,\n                            db: db.value,\n                            port: port.value,\n                            db_type: db_type.value,\n                            note: note.value\n                        },\n                        success: function (data) {\n                            console.log(data);\n                            swal({\n                                    text: \"数据源更新成功...\",\n                                    icon: \"success\",\n                                    buttons: false,\n                                    timer: 1000\n                                }).then(function(){\n                                    window.history.back(-1) || window.close();\n                                });\n                        },\n                        error: function (e) {\n                            swal({\n                                title: \"发生错误\",\n                                text: e,\n                                icon: \"error\",\n                            })\n                        }\n                    })\n              });\n        };\n\t</script>\n\n</body>\n\n</html>"
  },
  {
    "path": "backend/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "backend/views.py",
    "content": "import re\nimport pandas as pd\nfrom django.shortcuts import render\nfrom django.http.response import HttpResponseBadRequest\nfrom crontab import CronTab\n\nfrom mysite import db_config\nfrom utils.functions import is_login\n\n\n@is_login\ndef database(request):\n    \"\"\"列出数据源\n    \"\"\"\n    return render(request, \"backend/database.html\")\n\n\n@is_login\ndef database_detail(request):\n    \"\"\"查看数据源详情\n    \"\"\"\n    id = request.GET.get('id')\n    \n    try:\n        conn = db_config.sqlalchemy_conn()\n        db = pd.read_sql(f\"select company,name,alias,ip,user,db,port,db_type,charset,note from source_db_info where id={id}\", con=conn)\n        return render(request, \"backend/database_detail.html\", {\n                                                            'company': db['company'].values.tolist()[0],\n                                                            'name': db['name'].values.tolist()[0],\n                                                            'alias': db['alias'].values.tolist()[0],\n                                                            'ip': db['ip'].values.tolist()[0],\n                                                            'user': db['user'].values.tolist()[0],\n                                                            'db': db['db'].values.tolist()[0],\n                                                            'port': db['port'].values.tolist()[0],\n                                                            'db_type': db['db_type'].values.tolist()[0],\n                                                            'charset': db['charset'].values.tolist()[0],\n                                                            'note': db['note'].values.tolist()[0],\n                                                            'id': id\n                                                        })\n    except Exception as e:\n        return HttpResponseBadRequest(content=e)\n    finally:\n        conn.dispose()\n\n\n@is_login\ndef database_add(request):\n    \"\"\"新增数据源\n    \"\"\"\n    return render(request, \"backend/database_add.html\")\n\n\n@is_login\ndef crontab(request):\n    \"\"\"列出后台管理的定时任务\n    \"\"\"\n    data = []\n    cron = CronTab(user=True)\n    job = list(cron.find_comment(re.compile(r'backend')))\n    if job:\n        for i in job:\n            enable = i.is_enabled()\n            job_time = i.description(use_24hour_time_format=True, locale_code='zh_CN') # 获取crontab的度周期\n            comment = i.comment\n            command = i.command\n            data.append([comment, command, enable, job_time])\n            return render(request, \"backend/crontab.html\", {\"jobs\": data})\n    else:\n        return render(request, \"backend/crontab.html\", {\"jobs\": None})\n    "
  },
  {
    "path": "blood/__init__.py",
    "content": ""
  },
  {
    "path": "blood/admin.py",
    "content": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "blood/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass BloodConfig(AppConfig):\n    name = 'blood'\n"
  },
  {
    "path": "blood/models.py",
    "content": "from django.db import models\n\n# Create your models here.\n"
  },
  {
    "path": "blood/templates/blood/analyze.html",
    "content": "{% include \"data/template-ui.html\" %}\n<style>\n    a.active, button.active, a:focus, button:focus, a:hover, button:hover {\n        color: white;\n    }\n    table {\n        border-collapse: collapse;\n        width: 100%;\n        font-size: 13px;\n    }\n    .table > tbody > tr > td, .table > tbody > tr > th, .table > tfoot > tr > td, .table > tfoot > tr > th, .table > thead > tr > td, .table > thead > tr > th {\n        line-height: unset;\n        vertical-align: middle;\n    }\n</style>\n\n<!-- 正文主体 -->\n<div class=\"page-wrapper\">\n    <!-- 标题 -->\n    <div class=\"row page-titles\">\n        <div class=\"col-md-8 align-self-center\">\n            <h3 class=\"text-primary\" id=\"page_title\">血缘分析</h3>\n        </div>\n\n        <div class=\"col-md-4 align-self-center\">\n            <ol class=\"breadcrumb\">\n                <li class=\"breadcrumb-item\"><a href=\"../../data/dashboard/\">主页</a></li>\n                <li class=\"breadcrumb-item active\">血缘分析</li>\n            </ol>\n        </div>\n    </div>\n    \n    <div class=\"container-fluid\">\n        <div class=\"row\">\n            <div class=\"col-lg-12\">\n                <div class=\"card\">\n                    <div class=\"row\">\n                        <div class=\"col-md-4\">\n                            <input id=\"table_name\" placeholder=\"输入关键词：表名、mapping名\" class=\"form-control\" />\n                        </div>\n                        <div class=\"col-md-4\">\n                            <button class=\"btn btn-info\" onclick=\"QueryMapping();\"><i class=\"fa fa-search\"></i> 查询</button>\n                        </div>\n                    </div>\n    \n                    <div class=\"row\" style=\"padding-top:30px;\">\n                        <div class=\"col-md-12\">\n                            <div class=\"table-responsive\">\n                                <table class=\"table table-hover\">\n                                    <thead>\n                                        <tr>\n                                            <th>文件夹</th>\n                                            <th>映射名称</th>\n                                            <th>源表</th>\n                                            <th>目标表</th>\n                                        </tr>\n                                    </thead>\n                                    <tbody id=\"mapping_info\">\n                                    </tbody>\n                                </table>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"row\">\n            <div class=\"col-md-12\">\n                <div id=\"chart1\" class=\"card\" style=\"height: 300px;\"></div>\n            </div>\n        </div>\n    </div>\n</div>\n\n<!-- footer -->\n<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n    <div class=\"footer\">\n        © 2019-2020 Hyhyhyhyhyhyh\n    </div>\n</footer>\n\n</div>\n\n\n<!-- 设置头像 -->\n<script src=\"/static/js/init.js\"></script>\n<script type=\"text/javascript\" src=\"/static/js/sweetalert.min.js\"></script>\n\n<script>\n    function QueryMapping(){\n        var table_name = $(\"#table_name\").val();\n\n        if(table_name==undefined || table_name==\"\"){\n            table_name = localStorage.getItem(\"blood_query\");\n            $(\"#table_name\").attr(\"placeholder\", table_name);\n        }\n        else{\n            localStorage.setItem(\"blood_query\", table_name);\n        }\n\n        if(table_name == null || table_name == ''){\n            swal({\n                text: \"不能查询空关键字\",\n                icon: \"warning\",\n                buttons: false,\n                timer: 1000\n            });\n            return\n        }\n\n        $.ajax({\n            type : \"GET\",\n            async : false,\n            url : \"../../api/blood/mapping\",    \n            data: {\n                table_name: table_name\n            },\n            dataType : \"json\",\n            success : function(result) {\n                let tab = document.getElementById(\"mapping_info\");\n                let html = \"\";\n                for(let i in result.subject_area){\n                    html += \"<tr>\";\n                    html += \"<td>\" + result.subject_area[i] + \"</td>\";\n                    html += \"<td>\" + result.mapping_name[i] + \"</td>\";\n                    html += \"<td>\" + result.source[i] + \"</td>\";\n                    html += \"<td>\" + result.target[i] + \"</td>\";\n                    html += \"</tr>\";\n                }\n                tab.innerHTML = html;\n\n                InitChart(result);\n            }\n        })\n    }\n\n    // 血缘流向 桑基图\n    function InitChart(result){\n        var data = {\n            nodes: [],\n            links: []\n        }\n\n        var nodes = [];\n        var links = [];\n        const colors = [null, '#fbb4ae', '#b3cde3', '#ccebc5', '#decbe4'];\n        for(let i in result.subject_area){\n            nodes.push({\n                name: result.source[i],\n                itemStyle: {\n                    normal: {\n                        color: colors[result.level[i]]\n                    }\n                }\n            });\n            nodes.push({\n                name: result.target[i],\n                itemStyle: {\n                    normal: {\n                        color: colors[result.level[i]+1]\n                    }\n                }\n            });\n            links.push({\n                source: result.source[i],\n                target: result.target[i],\n                value: result.mapping_name[i].length,\n                mapping: result.mapping_name[i]\n            })\n        }\n\n        // nodes数组去重\n        var l = nodes.length;\n        var nodes_uniq = [];\n        for(let i=0;i<l;i++){\n            for(let j=i+1;j<l;j++){\n                if (nodes[i].name === nodes[j].name){\n                    i++;\n                    j = i;\n                }\n            }\n            nodes_uniq.push(nodes[i]);\n        }\n\n        data = {\n            nodes: nodes_uniq,\n            links: links\n        }\n        console.log(data);\n\n        // 设置桑基图\n        var chart1 = echarts.init(document.getElementById('chart1'));\n        chart1.clear();\n        chart1.setOption(option = {\n            title: {\n                text: '血缘流向'\n            },\n            tooltip: {\n                trigger: 'item',\n                triggerOn: 'mousemove',\n                formatter: function(x){\n                    return x.data.mapping;\n                }\n            },\n            animation: false,\n            series: [\n                {\n                    type: 'sankey',\n                    focusNodeAdjacency: 'allEdges',\n                    nodeAlign: 'left',\n                    data: data.nodes,\n                    links: data.links,\n                    lineStyle: {\n                        color: 'source',\n                        curveness: 0.5\n                    }\n                }\n            ]\n        });\n    }\n\n    // 初始化搜索结果，如果未有过血缘分析查询操作，则查询test_table用作展示样例\n    function initQuery(){\n        var blood_query = localStorage.getItem(\"blood_query\");\n        if(blood_query==undefined || blood_query==\"\"){\n            $(\"#table_name\").val(\"test_table\");\n            $(\"#table_name\").attr(\"placeholder\",\"test_table\");\n            localStorage.setItem(\"blood_query\", \"test_table\");\n        }\n        QueryMapping();\n    }\n    initQuery();\n</script>\n\n</body>\n\n</html>"
  },
  {
    "path": "blood/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "blood/views.py",
    "content": "from django.shortcuts import render\nfrom utils.functions import is_login\n\n\n@is_login\ndef analyze(request):\n    \"\"\"血缘分析\"\"\"\n    return render(request, \"blood/analyze.html\") "
  },
  {
    "path": "check/__init__.py",
    "content": ""
  },
  {
    "path": "check/admin.py",
    "content": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "check/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass CheckConfig(AppConfig):\n    name = 'check'\n"
  },
  {
    "path": "check/autocheck.py",
    "content": "import logging\nimport sys\nimport threading\nimport os\n\nsys.path.insert(0, '..')\nfrom mysite import db_config\nfrom utils import functions as f\nfrom sqlalchemy import create_engine\n\n\nos.environ['NLS_LANG']    = 'AMERICAN_AMERICA.UTF8'\nos.environ['ORACLE_HOME'] = '/data/oracle/app/11.2.4'\n\n\nclass Check(object):\n    def __init__(self, company):\n        self.company = company\n        \n    def init_table(self):\n        \"\"\"\n        类实例化所需参数\n        :param company:         公司名\n        :param source_system:   源系统名称\n        :return:\n        初始化检核表\n            如果check_result_{0}表存在，则从check_result_template表中插入对应公司检核项和逻辑\n            如果check_result_{0}表不存在，则使用check_result_template表作为模板新建\n        \"\"\"\n        company = self.company\n        \n        logging.info('*' * 50)\n        logging.info(f'开始初始化检核结果表...check_result_{company}')\n        \n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        curs.execute('set autocommit=0')\n        \n        sql = f\"select table_name from information_schema.tables where table_schema='data_quality' and table_name='check_result_{company}'\"\n        table_count = curs.execute(sql)\n        try:\n            if table_count == 0:    # 表不存在则新建\n                sql = f\"\"\"create table check_result_{company} as select * from check_result_template\n                                                                where company='{company}' order by id,source_system\"\"\"\n                curs.execute(sql)\n            else:                   # 表存在则插入\n                # 获取检核版本号\n                curs.execute(f\"select count(*) from check_execute_log where company='{company}'\")\n                version = curs.fetchone()[0] + 1\n                # 可能存在了初始化完检核表，但是检核失败导致事务回滚，检核表check_version={version}数据项为空的情况，因此需要处理这种情况\n                for sql in (\n                    f\"delete from check_result_{company} where check_version={version}\",\n                    f\"insert into check_result_{company} select * from check_result_template where company='{company}' order by id,source_system\",\n                    f\"update check_result_{company} set check_version={version} where check_version is null\",\n                ):\n                    curs.execute(sql)\n                \n            conn.commit()\n            logging.info('*' * 50, f\"初始化 check_result_{company}表 ...完成\", '*' * 50)\n            return True\n        except Exception as e:\n            conn.rollback()\n            logging.error('!' * 50, f'初始化 check_result_{company}表 ...失败,错误信息：{str(e)}', '!' * 50)\n            return False\n        finally:\n            curs.close()\n            conn.close()\n    \n    def run_check(self, db):\n        \"\"\"\n        执行检核\n        类实例化所需参数\n        :param company: 公司简称\n        :param db:      检核的数据库\n        :return:\n        \"\"\"\n        company = self.company\n        \n        logging.info('-' * 50)\n        logging.info(\"正在检核\" + company + \"数据...\")\n\n        try:\n            conn = db_config.mysql_connect()\n            curs = conn.cursor()\n            curs.execute('set autocommit=0')\n\n            # 从规则库表中取出检核项和检核sql，只运行“已启用”状态的SQL\n            sql = f\"\"\"select id,check_sql from check_result_template\n                    where company='{company}'\n                    and check_sql is not null\n                    and check_sql != ''\n                    and db='{db}'\n                    and status='已启用'\n                    order by id\"\"\"\n            curs.execute(sql)\n            check_list = curs.fetchall()\n            \n            \n            # 连接源系统数据库\n            curs.execute(f\"select connection_string from source_db_info where company='{company}' and alias='{db}'\")\n            connection_string = curs.fetchone()[0]\n            engine = create_engine(\n                connection_string,\n                echo=False,                     # 打印sql语句\n                max_overflow=0,                 # 超过连接池大小外最多创建的连接\n                pool_size=5,                    # 连接池大小\n                pool_timeout=30,                # 池中没有线程最多等待的时间，否则报错\n                pool_recycle=-1,                # 多久之后对线程池中的线程进行一次连接的回收（重置）\n            )\n            conn_source = engine.raw_connection()\n            \n            # 获取检核版本号\n            curs.execute(f\"select count(*) from check_execute_log where company='{company}'\")\n            version = curs.fetchone()[0] + 1\n\n            with conn_source.cursor() as curs_source:\n                # 执行检核\n                for i in check_list:\n                    id = i[0]\n                    check_sql = i[1]\n                    logging.info(f'{company}, db={db}, id={i[0]} >>>开始检核')\n                    curs_source.execute(check_sql)\n                    check_result = curs_source.fetchall()  # 检核结果\n                    for t in check_result:\n                        item_count = t[0]\n                        problem_count = t[1]\n                        archive_sql = f\"\"\"update check_result_{company}\n                                            set item_count={item_count},\n                                            problem_count={problem_count},\n                                            update_flag='Y',\n                                            check_date=current_timestamp\n                                            where id={id}\n                                            and check_version={version}\"\"\"\n                        curs.execute(archive_sql)\n                        conn.commit()\n                    logging.info(f'{company}, db={db}, id={i[0]} <<<完成')\n            conn_source.close()\n\n            # 根据检核结果明细计算问题占比\n            self.calc_result(version)\n            \n            logging.info(\"-\" * 25, f'{company}, db={db} 检核完成', \"-\" * 25)\n            return True\n        except Exception as e:\n            conn.rollback()\n            logging.error(\"!\" * 25, f'{company}, db={db}, id={id} 检核出错,错误信息：{str(e)}', \"!\" * 25)\n            return False\n        finally:\n            curs.close()\n            conn.close()\n            \n    def calc_result(self, version):\n        \"\"\"根据检核结果明细计算问题占比\n        1. 填充空值的问题占比\n        2. 计算正常的问题占比\n        \n        :param version:     要进行计算的版本号\n        :return:            检核成功返回True，失败返回False\n        \"\"\"\n        company = self.company\n        try:\n            conn = db_config.mysql_connect()\n            curs = conn.cursor()\n            curs.execute('set autocommit=0')\n            # 计算问题占比\n            # 处理item_count和problem_count都是null或=0的行\n            sql = f\"\"\"update check_result_{company}\n                        set problem_per=100\n                        where (item_count is null or item_count=0)\n                        and check_version={version}\"\"\"\n            curs.execute(sql)\n\n            # 计算正常的问题占比\n            sql = f\"\"\"update check_result_{company} set problem_per=problem_count/item_count*100\\\n                        where problem_per is null\n                        and check_version={version}\"\"\"\n            curs.execute(sql)\n            conn.commit()\n            return True\n        except Exception as e:\n            conn.rollback()\n            return False\n        finally:\n            curs.close()\n            conn.close()\n    \n\nclass MyThread(threading.Thread):\n    \"\"\"重新定义带返回值的线程类\"\"\"\n    def __init__(self,func,args=()):\n        super(MyThread,self).__init__()\n        self.func = func\n        self.args = args\n    def run(self):\n        self.result = self.func(*self.args)\n    def get_result(self):\n        try:\n            return self.result\n        except Exception:\n            return None"
  },
  {
    "path": "check/crontab_autocheck.py",
    "content": "import requests, datetime, math, threading\n\nquarter = str(datetime.datetime.now().year)+\"Q\"+str(math.ceil(datetime.datetime.now().month/3.))\nurl = \"http://dataquality.utrustfintech.com/check/rule_execute\"\n\ndef post_rule_execute(company, quarter):\n    data = {'company': company, 'username': 'crontab', 'quarter': quarter}\n    r = requests.post(url, data)\n\nt1 = threading.Thread(target=post_rule_execute, args=('ycxt', quarter))\nt2 = threading.Thread(target=post_rule_execute, args=('yczc', quarter))\nt3 = threading.Thread(target=post_rule_execute, args=('gdzdb', quarter))\nt4 = threading.Thread(target=post_rule_execute, args=('ycjk', quarter))\nt5 = threading.Thread(target=post_rule_execute, args=('fdct', quarter))\nt6 = threading.Thread(target=post_rule_execute, args=('zyyc', quarter))\nt7 = threading.Thread(target=post_rule_execute, args=('jz', quarter))\n\nt1.start();t2.start();t3.start();t4.start();t5.start();t6.start();t7.start()\n\n# 等待运行结束\nt1.join();t2.join();t3.join();t4.join();t5.join();t6.join();t7.join()\n\n"
  },
  {
    "path": "check/models.py",
    "content": "from django.db import models\n\n# Create your models here.\n"
  },
  {
    "path": "check/templates/check/blood_analyze.html",
    "content": "{% include \"data/template-ui.html\" %}\n<!-- 正文主体 -->\n<div class=\"page-wrapper\">\n    <!-- 标题 -->\n    <div class=\"row page-titles\">\n        <div class=\"col-md-4 align-self-center\">\n            <h3 class=\"text-primary\" id=\"page_title\">血缘分析（信托公司）</h3>\n        </div>\n\n        <div class=\"col-md-5 align-self-center\">\n            <div class=\"row\">\n                选择公司：\n                <select id=\"company_list\">\n                    <option>信托</option>\n                    <option>资产</option>\n                    <option>担保</option>\n                    <option>金科</option>\n                    <option>基金1</option>\n                    <option>基金2</option>\n                    <option>金租</option>\n                </select>\n                <button type=\"button\" class=\"btn btn-primary btn-xs p310\" onclick=\"ChangeCompany();\"><i class=\"fa fa-search\"></i></button>\n            </div>\n        </div>\n\n        <div class=\"col-md-3 align-self-center\">\n            <ol class=\"breadcrumb\">\n                <li class=\"breadcrumb-item\"><a href=\"../../data/index\">主页</a></li>\n                <li class=\"breadcrumb-item active\">血缘分析</li>\n            </ol>\n        </div>\n    </div>\n    \n    <div class=\"container-fluid animated fadeInUp\">\n        <div class=\"row\">\n            <div class=\"card\" style=\"height: 600px;width: 100%;\">\n                <div id=\"myDiagramDiv\" style=\"width:100%; height:600px\"></div>\n            </div>\n        </div>\n    </div>\n</div>\n\n<!-- footer -->\n<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n    <div class=\"footer\">\n        © 2019 Hyhyhyhyhyhyh\n    </div>\n</footer>\n\n</div>\n\n\n<!-- 设置头像 / 设置gojs-->\n<script src=\"/static/js/init.js\"></script>\n<!-- gojs库 -->\n<script src=\"/static/js/gojs/go.js\"></script>\n<script src=\"/static/js/gojs/Buttons.js\"></script>\n\n<script>\n    function ChangeCompany(){\n        var obj = document.getElementById(\"company_list\");\n        var value = obj.options[obj.selectedIndex].value; // 选中值\n        localStorage.setItem('selected_company', value);\n\n        var title = document.getElementById(\"page_title\");\n        title.innerHTML = \"血缘分析（\" + value + \"公司）\";\n    }\n</script>\n\n</body>\n\n</html>"
  },
  {
    "path": "check/templates/check/crontab.html",
    "content": "{% include \"data/template-ui.html\" %}\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/icons.css\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/fonts.css\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/sweetalert.css\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/switchery.min.css\" />\n\n<style>\n    .container-fluid {\n        padding: 0 10 0;\n    }\n\n    .page-wrapper {\n        padding-bottom: 20px;\n    }\n\n    .page-wrapper {\n        min-height: 600px !important;\n    }\n\n    .table {\n        font-size: 13px;\n    }\n    .table > tbody > tr > td, .table > tbody > tr > th, .table > tfoot > tr > td, .table > tfoot > tr > th, .table > thead > tr > td, .table > thead > tr > th {\n        line-height: unset;\n    }\n    tbody tr td {\n        text-align: left;\n    }\n    \n    h6 {\n        color: rgb(0,128,82);\n    }\n\n    .btn {\n        margin-top: -3px;\n        margin-left: 1px;\n        background-color: #4680ff;\n        color: aliceblue;\n    }\n    .btn:hover, .btn:focus {\n        color:aliceblue;\n    }\n</style>\n\n<div class=\"page-wrapper\">\n    <div class=\"container-fluid animated fadeInUp\">\n        <div class=\"row\">\n            <div class=\"card col-12\">\n                <div class=\"card-title\">\n                    <h4 class=\"text-primary\">检核任务 - 调度信息</h4>\n                </div>\n\n                <div class=\"card-content\">\n                    <table class=\"table table-hover\">\n                        <thead>\n                            <td>公司</td>\n                            <td>数据库</td>\n                            <td>启用状态</td>\n                            <td>完成进度</td>\n                            <td>调度周期</td>\n                            <td>上次运行时间</td>\n                            <td>上次运行情况</td>\n                            <td>#  操作</td>\n                        </thead>\n                        <tbody>\n                        {% for i in jobs %}\n                            <tr>\n                                <!-- 公司名 -->\n                                <td>{{ i.0 }}</td>\n\n                                <!-- 数据库名 -->\n                                <td>{{ i.2 }}</td>\n\n                                <!-- 启用状态 -->\n                                <td>\n                                    {% if i.5 == True %}\n                                    <input company=\"{{ i.1 }}\" db=\"{{ i.2 }}\" type=\"checkbox\" class=\"js-switch\" checked/>\n                                    {% elif i.5 == False %}\n                                    <input company=\"{{ i.1 }}\" db=\"{{ i.2 }}\" type=\"checkbox\" class=\"js-switch\"/>\n                                    {% elif i.5 is None %}\n                                    <i class=\"fa fa-warning\" style=\"color: #FFC107;\"></i>&nbsp;&nbsp;未部署\n                                    {% endif %}\n                                </td>\n                                \n                                <!-- 完成进度 -->\n                                <td class=\"project_progress\">\n                                    <div class=\"progress\">\n                                        <div class=\"progress-bar wow animated progress-animated\"\n                                            style=\"width: 0%; height:6px;\"\n                                            role=\"progressbar\" id=\"progressbar_{{ i.1 }}_{{ i.2 }}\"> </div>\n                                    </div>\n                                    <small id=\"progressvalue_{{ i.1 }}_{{ i.2 }}\">0% 已完成</small>\n                                </td>\n\n                                <!-- 调度周期 -->\n                                <td>{{ i.6 }}</td>\n\n                                <!-- 上次运行时间 -->\n                                <td>{{ i.3 }}</td>\n\n                                <!-- 上次运行状态 -->\n                                {% if i.4 == 'success' %}\n                                <td style=\"color: #4CAF50;\"><i class=\"fa fa-check\"></i>&nbsp;&nbsp;成功</td>\n                                {% else %}\n                                <td style=\"color: #F44336;\"><i class=\"fa fa-close\"></i>&nbsp;&nbsp;失败</td>\n                                {% endif %}\n\n                                <!-- 操作 -->\n                                <td>\n                                    <button class=\"btn btn-xs btn-check\" type=\"button\" onclick=\"CheckNow(this)\" c=\"{{ i.0 }}\" company=\"{{ i.1 }}\" db=\"{{ i.2 }}\">\n                                        <i class=\"im-paperplane\"></i>&nbsp;&nbsp;立即检核>>\n                                    </button>\n                                    <span id=\"i_{{i.1}}_{{i.2}}\" style=\"display: none;\">\n                                        <i class=\"fa fa-spinner fa-pulse\"></i>&nbsp;&nbsp;正在检核...\n                                    </span>\n                                    <!-- <button style=\"display: none;\" name=\"btn_progress\" onclick=\"UpadteProgress(this);\" company=\"{{ i.1 }}\" db=\"{{ i.2 }}\">\n                                    </button> -->\n                                </td>\n                            </tr>\n                        {% endfor%}\n                        </tbody>\n                    </table>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n\n<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n    <div class=\"footer\">\n        © 2019 Hyhyhyhyhyhyh\n    </div>\n</footer>\n\n\n<!-- 设置头像 / 设置日期 -->\n<script src=\"/static/js/init.js\"></script>\n\n<script src=\"/static/js/sweetalert.min.js\"></script>\n<script src=\"/static/js/switchery.min.js\"></script>\n\n<script>\n    var elems = Array.prototype.slice.call(document.querySelectorAll('.js-switch'));\n\n    elems.forEach(function(html) {\n        var switchery = new Switchery(html, { size: 'small' });\n\n        html.onchange = function(e) {\n            var obj = $(this);\n            var company = obj.attr('company');\n            var db = obj.attr('db');\n            var enable;\n\n            if (obj.is(':checked')) {\n                enable = true;\n            } else {\n                enable = false;\n            }\n\n            // 修改定时任务启用状态\n            $.ajax({\n                url: '../../api/check/crontab/status_modify',\n                type: 'POST',\n                data:{\n                    \"enable\": enable,\n                    \"company\": company,\n                    \"db\": db\n                },\n                success: function (data) {\n                    if (data.msg == 'success') {\n                        return true\n                    }\n                    else {\n                        swal({\n\t\t\t\t\t\t\ttitle: \"发生错误\",\n                            icon: \"error\",\n                            buttons: false,\n\t\t\t\t\t\t\ttimer: 1000\n\t\t\t\t\t\t});\n                    }\n                },\n                error: function (e) {\n                    swal({\n                        title: \"发生错误\",\n                        icon: \"error\",\n                        buttons: false,\n                        timer: 1000\n                    });\n                }\n            })\n          }\n    });\n\n\n    // 点击按钮手工调度检核任务\n    function CheckNow(obj){\n        var c = obj.attributes.c.value;\n        var company = obj.attributes.company.value;\n        var db = obj.attributes.db.value;\n        swal({\n            title: c + \"-\" + db +\"-开始执行检核\",\n            icon: \"success\",\n            timer: 2000\n        });\n        obj.style.display = \"none\";\n        document.getElementById(\"i_\"+company+\"_\"+db).style.display = \"block\";\n\n        $.ajax({\n            type: \"POST\",\n            url: \"../../api/check/rule/execute\",\n            data: {\n                company: company,\n                db: db,\n                username: localStorage.getItem(\"username\"),\n            },\n            success: function (data) {\n                //console.log(data);\n                if (data.status == 'success') {\n                    obj.style.display = \"block\";\n                    document.getElementById(\"i_\"+company+\"_\"+db).style.display = \"none\";\n                    swal({\n                        title: c + \"-\" + db +\"-检核成功\",\n                        icon: \"success\",\n                    });\n                }\n                else {\n                    swal('发生错误!', data.status, 'error');\n                    obj.style.display = \"block\";\n                    document.getElementById(\"i_\"+company+\"_\"+db).style.display = \"none\";\n                }\n            },\n            error: function (e) {\n                swal('发生错误!', data.status, 'error');\n                obj.style.display = \"block\";\n                document.getElementById(\"i_\"+company+\"_\"+db).style.display = \"none\";\n            }\n        })\n    }\n\n\n    // 查询并填充任务进度条\n    function UpadteProgress(){\n        var bar = document.getElementsByClassName(\"progress-bar\");\n        for(let i=0;i<bar.length;i++){\n            bar[i].style.width = '0%';\n        }\n\n        $.ajax({\n            type : \"GET\",\n            async : true,\n            url : \"../../api/check/progress\",\n            data: {},\n            dataType : \"json\",\n            success : function(result) {\n                for(var i in result){    // 按公司循环遍历\n                    var db =  result[i];\n                    if(Object.keys(db).length == 1){\n                        let value = Object.values(db)[0];\n                        let b = document.getElementById(\"progressbar_\" + i + \"_\" + Object.keys(db)[0]);\n                        let v = document.getElementById(\"progressvalue_\" + i + \"_\" + Object.keys(db)[0]);\n\n                        b.style.width = value + \"%\";\n                        v.innerHTML = value + \"% 已完成\";\n\n                        if(value <= 33){\n                            b.style.backgroundColor = '#F44336';  //红色\n                            v.style.color = '#F44336';\n                        }\n                        else if(value <= 66){\n                            b.style.backgroundColor = '#FFC107';  //黄色\n                            v.style.color = '#FFC107';\n                        }\n                        else{\n                            b.style.backgroundColor = '#4CAF50';  //绿色\n                            v.style.color = '#4CAF50';\n                        }\n                    }\n                    for(var j in db){\n                        //console.log(db[j]);\n                        let value = db[j];\n                        let b = document.getElementById(\"progressbar_\" + i + \"_\" + j);\n                        let v = document.getElementById(\"progressvalue_\" + i + \"_\" + j);\n                        b.style.width = value + \"%\";\n                        v.innerHTML = value + \"% 已完成\";\n\n                        if(value <= 33){\n                            b.style.backgroundColor = '#F44336';  //红色\n                            v.style.color = '#F44336';\n                        }\n                        else if(value <= 66){\n                            b.style.backgroundColor = '#FFC107';  //黄色\n                            v.style.color = '#FFC107';\n                        }\n                        else{\n                            b.style.backgroundColor = '#4CAF50';  //绿色\n                            v.style.color = '#4CAF50';\n                        }\n                    }\n                }\n            }\n        })\n    };\n\n\n    // 初始化进度条\n    UpadteProgress();\n    var intervalID = setInterval(UpadteProgress, 1000*60);     // 每分钟刷新一次进度条\n</script>\n\n</body>\n\n</html>"
  },
  {
    "path": "check/templates/check/rule_edit.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-cmn-Hans\">\n\n<head>\n\t<meta charset=\"utf-8\">\n\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t<meta name=\"description\" content=\"\">\n\t<meta name=\"author\" content=\"\">\n\t<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/static/img/favicon.ico\" />\n\t<title>数据质量检核平台</title>\n\n\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/check/css/admin/bootstrap.min.css\"/>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/check/css/admin/style.css\"/>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/CodeMirror/lib/codemirror.css\"/>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/CodeMirror/theme/eclipse.css\"/>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/sweetalert.css\"/>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/icons.css\"/>\n\t<link href=\"https://cdn.bootcss.com/bootstrap-select/2.0.0-beta1/css/bootstrap-select.min.css\" rel=\"stylesheet\">\n\n\n\t<style>\n\t\t.modal.fade.in{\n\t\t\ttop: 180px;\n\t\t}\n\t\t.table > thead > tr > th, .table > tbody > tr > th, .table > tfoot > tr > th, .table > thead > tr > td, .table > tbody > tr > td, .table > tfoot > tr > td {\n\t\t\tvertical-align: middle;\n\t\t}\n\t\t.btn-default:hover, .btn-default:focus, .btn-default:active, .btn-default.active, .open .dropdown-toggle.btn-default {\n\t\t\tbackground-color: unset;\n\t\t\tborder-color: unset;\n\t\t\tcolor: unset;\n\t\t}\n\t\t.btn-default.active, .btn-default.focus, .btn-default:active, .btn-default:focus, .btn-default:hover, .open>.dropdown-toggle.btn-default {\n\t\t\tbackground-color: unset;\n\t\t\tborder-color: unset;\n\t\t\tcolor: unset;\n\t\t}\n\t\t.popover{\n\t\t\tmax-width: 100%;\n\t\t}\n\t</style>\n</head>\n\n<body onload=\"OnLoad();\">\n\t<!-- head star -->\n\t<div class=\"tnav row wrapper border-bottom white-bg page-heading\">\n\t\t<div class=\"col-sm-4\">\n\t\t\t<h2 class=\"fl\" style=\"color: #007bff;font-size: 21px;font-weight:500\">数据质量检核规则库</h2>\n\t\t\t<ol class=\"breadcrumb fl\">\n\t\t\t\t<li><a href=\"../../data/index\">主页</a></li>\n\t\t\t\t<li><strong>检核规则库</strong></li>\n\t\t\t</ol>\n\t\t</div>\n\t</div>\n\t<!-- head end -->\n\n\t<!-- table star -->\n\t<div class=\"row col-lg-10\">\n\t\t<div class=\"wrapper wrapper-content animated fadeInUp\">\n\t\t\t<div class=\"ibox\">\n\t\t\t\t<div class=\"ibox-title\">\n\t\t\t\t\t<h5 id=\"page-title\"></h5>\n\t\t\t\t\t<div class=\"ibox-tools rboor\" style=\"bottom: 5px;\">\n\t\t\t\t\t\t<button onclick=\"Commit();\" class=\"btn btn-primary btn-sm\">\n\t\t\t\t\t\t\t<i class=\"fa fa-check-square-o\"></i> 提交\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"ibox-content\">\n\t\t\t\t\t<table class=\"table table-hover\">\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td style=\"width: 150px;\">\n\t\t\t\t\t\t\t\t<label class=\"form-label\">数据标准</label>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<input id=\"check_item\" type=\"text\" class=\"form-control\" style=\"width: 400px;\">\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>\n\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<label class=\"form-label\">目标表</label>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<input id=\"target_table\" type=\"text\" class=\"form-control\" style=\"width: 400px;\">\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>\n\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<label class=\"form-label\">是否风险集市</label>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<select id=\"risk_market\" class=\"selectpicker form-control\" style=\"width: 400px;\">\n\t\t\t\t\t\t\t\t\t<option value=\"是\">是</option>\n\t\t\t\t\t\t\t\t\t<option value=\"否\">否</option>\n\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>\n\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<label class=\"form-label\">问题分类</label>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<select id=\"problem_type\" type=\"text\" class=\"selectpicker form-control\">\n\t\t\t\t\t\t\t\t\t<option>-- 请选择 --</option>\n\t\t\t\t\t\t\t\t\t<option value=\"完整性检验\">完整性检验</option>\n\t\t\t\t\t\t\t\t\t<option value=\"准确性检验\">准确性检验</option>\n\t\t\t\t\t\t\t\t\t<option value=\"合理性检验\">合理性检验</option>\n\t\t\t\t\t\t\t\t\t<option value=\"一致性检验\">一致性检验</option>\n\t\t\t\t\t\t\t\t\t<option value=\"及时性检验\">及时性检验</option>\n\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<i class=\"fa fa-question-circle\" style=\"color: #ffab00;font-size:15px;\" data-toggle=\"popover\"></i>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>\n\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<label class=\"form-label\">源系统数据库</label>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td style=\"width: 150px;\">\n\t\t\t\t\t\t\t\t<select id=\"db\" class=\"selectpicker form-control\" disabled></select>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<button class=\"btn btn-primary btn-sm\" onclick=\"QueryDB();\">查询</button>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>\n\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<label class=\"form-label\">检核逻辑</label>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td colspan=\"2\">\n\t\t\t\t\t\t\t\t<textarea id=\"check_sql\" name=\"code\" type=\"text\" class=\"form-control\"></textarea>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>\n\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<label class=\"form-label\">备注</label>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td colspan=\"2\">\n\t\t\t\t\t\t\t\t<textarea id=\"note\" type=\"text\" class=\"form-control\" style=\"width: 800px;\"></textarea>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>\n\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<label class=\"form-label\">状态</label>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<select id=\"status\" class=\"selectpicker\" >\n\t\t\t\t\t\t\t\t\t<option value=\"已启用\">已启用</option>\n\t\t\t\t\t\t\t\t\t<option value=\"已停用\">已停用</option>\n\t\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</table>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t<!-- table end -->\n\t<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n\t\t<div class=\"footer\">\n\t\t\t© 2019 Hyhyhyhyhyhyh\n\t\t</div>\n\t</footer>\n\n\t<script src=\"/static/js/jquery/jquery.min.js\"></script>\n\t<script src=\"https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js\"></script>\n\t<script src=\"/static/CodeMirror/lib/codemirror.js\"></script>\n\t<script src=\"/static/CodeMirror/mode/sql.js\"></script>\n\t<script src=\"/static/js/sweetalert.min.js\"></script>\n\t<script src=\"https://cdn.bootcss.com/bootstrap-select/2.0.0-beta1/js/bootstrap-select.min.js\"></script>\n\n\n\t<script>\n\t\tvar company = \"{{ source_system }}\";\n\t\tvar id = \"{{ id }}\";\n\t\t\n\t\t// 初始化CodeMirror编辑框\n\t\tvar textarea = document.getElementById('check_sql');\n\t\tvar editor = CodeMirror.fromTextArea(textarea, {\n\t\t\tlineNumbers: true,\n\t\t\tautofocus: true,\n\t\t\tmode: 'text/x-plsql',\n\t\t\ttheme: 'eclipse',\n\t\t\tmatchBrackets: true,\n\t\t\tautoCloseBrackets: true,\n\t\t\textraKeys: {\n\t\t\t\t\"Ctrl\": \"autocomplete\"\n\t\t\t},\n\t\t});\n\t\teditor.setSize('1000px', 'auto');\n\n\t\t// 填充现有检核规则信息\n\t\tfunction OnLoad(){\n\t\t\t$(\".selectpicker\").selectpicker({\n\t\t\t\tnoneSelectedText: '-- 请选择 --' //默认显示内容  \n\t\t\t });\n\n\t\t\tif(id == \"null\"){\n\t\t\t\t$(\"#page-title\").html(company + \"公司-新增检核规则\");\n\t\t\t}\n\t\t\telse{\n\t\t\t\t$(\"#page-title\").html(company + \"公司-修改检核规则\");\n\t\t\t\tQueryDetail();\n\t\t\t}\n\t\t}\n\n\t\tfunction QueryDetail(){\n\t\t\t$.ajax({\n\t\t\t\ttype: \"GET\",\n\t\t\t\turl: \"../../api/check/rule/detail\",\n\t\t\t\tdata: {\n\t\t\t\t\tcompany: company,\n\t\t\t\t\tid: id,\n\t\t\t\t},\n\t\t\t\tsuccess: function (result) {\n\t\t\t\t\t$(\"#check_item\").val(result.check_item);\n\t\t\t\t\t$(\"#target_table\").val(result.target_table);\n\t\t\t\t\t$(\"#risk_market_item\").val(result.risk_market_item);\n\t\t\t\t\t$(\"#problem_type\").val(result.problem_type);\n\t\t\t\t\t$(\"#db\").selectpicker({noneSelectedText: result.db});\n\t\t\t\t\t$(\"#check_sql\").val(result.check_sql);\n\t\t\t\t\teditor.replaceSelection(result.check_sql);\n\t\t\t\t\t$(\"#note\").val(result.note);\n\t\t\t\t\t$(\"#status\").val(result.status);\n\n\t\t\t\t\t$(\"#problem_type\").selectpicker(\"refresh\");\n\t\t\t\t\t$(\"#db\").selectpicker(\"refresh\");\n\t\t\t\t\t$(\"#status\").selectpicker(\"refresh\");\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\t// popover气泡提示窗\n\t\t$(function() {\n\t\t\t$(\"[data-toggle='popover']\").popover({\n\t\t\t\thtml : true,\n\t\t\t\tplacement: \"right\",\n\t\t\t\ttrigger: \"hover focus\",\n\t\t\t\tcontainer: \"body\",\n\t\t\t\ttitle: \"说明\",\n\t\t\t\tdelay:{show:100, hide:200},\n\t\t\t\tcontent: \"<ul>\\\n\t\t\t\t<li>完整性：主要包括实体缺失、属性缺失、记录缺失和字段值缺失四个方面；</li>\\\n\t\t\t\t<li>准确性：一个数据值与设定为准确的值之间的一致程度，或与可接受程度之间的差异；</li>\\\n\t\t\t\t<li>合理性：主要包括格式、类型、值域和业务规则的合理有效；</li>\\\n\t\t\t\t<li>一致性：系统之间的数据差异和相互矛盾的一致性，业务指标统一定义，数据逻辑加工结果一致性；</li>\\\n\t\t\t\t<li>及时性：数据仓库ETL、应用展现的及时和快速性，Jobs运行耗时、运行质量、依赖运行及时性。</li>\\\n\t\t\t\t</ul>\"\n\t\t\t});\n\t\t});\n\n\t\tfunction QueryDB(){\n\t\t\t$.ajax({\n\t\t\t\ttype: \"GET\",\n\t\t\t\t\turl: \"../../api/backend/database/query\",\n\t\t\t\t\tdata: {},\n\t\t\t\t\tsuccess: function (result) {\n\t\t\t\t\t\t// 根据公司名从接口数据获取对应的数据库名\n\t\t\t\t\t\tlet db = [];\n\t\t\t\t\t\tfor(let i in result.data.company){\n\t\t\t\t\t\t\tif(result.data.company[i] == company){\n\t\t\t\t\t\t\t\tdb.push(result.data.alias[i]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// 清除原有option\n\t\t\t\t\t\t$(\"#db\").empty();\n\t\t\t\t\t\t// 设置显示内容\n\t\t\t\t\t\tfor(i in db){\n\t\t\t\t\t\t\t$(\"#db\").append($(\"<option value='\"+db[i]+\"'>\"+db[i]+\"</option>\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// 取消下拉框的禁用状态\n\t\t\t\t\t\t$('#db').prop('disabled', false);\n\t\t\t\t\t\t// 刷新下拉框状态\n\t\t\t\t\t\t$(\"#db\").selectpicker(\"refresh\");\n\t\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\tfunction Commit(){\n\t\t\t// 获取检核逻辑代码框中修改后的value\n\t\t\teditor.save();\n\t\t\tvar check_sql = editor.getValue();\n\n\t\t\tif(id == 'null'){\n\t\t\t\t// 新增检核规则\n\t\t\t\t$.ajax({\n\t\t\t\t\ttype: \"POST\",\n\t\t\t\t\turl: \"../../api/check/rule/add\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tsource_system:\tcompany,\n\t\t\t\t\t\tcheck_item: \t$(\"#check_item\").val(),\n\t\t\t\t\t\ttarget_table: \t$(\"#target_table\").val(),\n\t\t\t\t\t\trisk_market:\t$(\"#risk_market\").val(),\n\t\t\t\t\t\tproblem_type:\t$(\"#problem_type\").val(),\n\t\t\t\t\t\tdb: \t\t\t$(\"#db\").val(),\n\t\t\t\t\t\tcheck_sql: \t\tcheck_sql,\n\t\t\t\t\t\tnote: \t\t\t$(\"#note\").val(),\n\t\t\t\t\t\tstatus: \t\t$(\"#status\").val(),\n\t\t\t\t\t},\n\t\t\t\t\tsuccess: function (data) {\n\t\t\t\t\t\tswal({\n\t\t\t\t\t\t\ttext: \"检核规则新增成功，正在返回上一页...\",\n\t\t\t\t\t\t\ticon: \"success\",\n\t\t\t\t\t\t\tbuttons: false,\n\t\t\t\t\t\t\ttimer: 1000\n\t\t\t\t\t\t}).then(function(){\n\t\t\t\t\t\t\twindow.history.back(-1) || window.close();\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\terror: function (e) {\n\t\t\t\t\t\tswal({\n\t\t\t\t\t\t\ttitle: \"发生错误\",\n\t\t\t\t\t\t\ttext: e,\n\t\t\t\t\t\t\ticon: \"error\",\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t\telse{\n\t\t\t\t// 更新检核规则\n\t\t\t\t$.ajax({\n\t\t\t\t\ttype: \"POST\",\n\t\t\t\t\turl: \"../../api/check/rule/update\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tid:\t\t\t\tid,\n\t\t\t\t\t\tsource_system:\tcompany,\n\t\t\t\t\t\tcheck_item: \t$(\"#check_item\").val(),\n\t\t\t\t\t\ttarget_table: \t$(\"#target_table\").val(),\n\t\t\t\t\t\trisk_market:\t$(\"#risk_market\").val(),\n\t\t\t\t\t\tproblem_type:\t$(\"#problem_type\").val(),\n\t\t\t\t\t\tdb: \t\t\t$(\"#db\").val(),\n\t\t\t\t\t\tcheck_sql: \t\tcheck_sql,\n\t\t\t\t\t\tnote: \t\t\t$(\"#note\").val(),\n\t\t\t\t\t\tstatus: \t\t$(\"#status\").val(),\n\t\t\t\t\t},\n\t\t\t\t\tsuccess: function (data) {\n\t\t\t\t\t\tswal({\n\t\t\t\t\t\t\ttext: \"检核规则修改成功，正在返回上一页...\",\n\t\t\t\t\t\t\ticon: \"success\",\n\t\t\t\t\t\t\tbuttons: false,\n\t\t\t\t\t\t\ttimer: 1000\n\t\t\t\t\t\t}).then(function(){\n\t\t\t\t\t\t\twindow.history.back(-1) || window.close();\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\terror: function (e) {\n\t\t\t\t\t\tswal({\n\t\t\t\t\t\t\ttitle: \"发生错误\",\n\t\t\t\t\t\t\ttext: e,\n\t\t\t\t\t\t\ticon: \"error\",\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t</script>\n\n</body>\n\n</html>"
  },
  {
    "path": "check/templates/check/rule_list.html",
    "content": "{% include \"data/template-ui.html\" %}\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/datatables/foundation.min.css\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/datatables/dataTables.bootstrap4.min.css\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/icons.css\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/fonts.css\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/rule_list.css\" />\n\n<style>\n\ttd.details-control {\n\t\tbackground: url(\"/static/img/details_open.png\") no-repeat center center;\n\t\tcursor: pointer;\n\t}\n\n\ttr.shown td.details-control {\n\t\tbackground: url(\"/static/img/details_close.png\") no-repeat center center;\n\t}\n</style>\n\n<div class=\"page-wrapper\">\n\t<!-- 正文 -->\n\t<div class=\"container-fluid animated fadeInUp\">\n\t\t<div class=\"col-12\">\n\t\t\t<div class=\"card\">\n\t\t\t\t<div class=\"card-title\">\n\t\t\t\t\t<div class=\"row\" style=\"padding:0px !important;\">\n\t\t\t\t\t\t<div class=\"col-md-10\">\n\t\t\t\t\t\t\t<h4 class=\"text-primary\">{{ source_system }}公司-检核规则库</h4>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"col-md-2 pull-right\">\n\t\t\t\t\t\t\t<a href=\"../check/rule/edit?company={{ source_system }}&id=null\"\n\t\t\t\t\t\t\t\tclass=\"btn btn-primary btn-xs p310\"><i class=\"im-plus\"></i> 添加规则</a>\n\t\t\t\t\t\t\t<button id=\"tb-refresh\" href=\"#\" class=\"btn btn-primary btn-xs p1010\"><i\n\t\t\t\t\t\t\t\t\tclass=\"im-spinner2 fa-spin\"></i> 刷新</button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"card-content\">\n\t\t\t\t\t<div class=\"col-lg-3 \">\n\t\t\t\t\t\t<select style=\"height:2.2rem; font-size:13px; bottom:10px;margin:unset;\"\n\t\t\t\t\t\t\tonchange=\"fun_option(this.value);\">\n\t\t\t\t\t\t\t<option>是否风险集市</option>\n\t\t\t\t\t\t\t<option value=\"是\">是</option>\n\t\t\t\t\t\t\t<option value=\"否\">否</option>\n\t\t\t\t\t\t\t<option value=\"\">显示全部</option>\n\t\t\t\t\t\t</select>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<table id=\"example\" class=\"table table-bordered\" cellspacing=\"0\" width=\"100%\">\n\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<th>ID</th>\n\t\t\t\t\t\t\t\t<th>数据标准</th>\n\t\t\t\t\t\t\t\t<th>目标表</th>\n\t\t\t\t\t\t\t\t<th>是否风险集市</th>\n\t\t\t\t\t\t\t\t<th>问题分类</th>\n\t\t\t\t\t\t\t\t<th>源系统数据库</th>\n\t\t\t\t\t\t\t\t<th>检核逻辑</th>\n\t\t\t\t\t\t\t\t<th>状态</th>\n\t\t\t\t\t\t\t\t<th>操作</th>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t</thead>\n\t\t\t\t\t</table>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\n\t<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n\t\t<div class=\"footer\">\n\t\t\t© 2019 Hyhyhyhyhyhyh\n\t\t</div>\n\t</footer>\n\n\t<!-- 设置头像 / 设置日期 -->\n\t<script src=\"/static/js/init.js\"></script>\n\n\t<script type=\"text/javascript\" src=\"/static/js/DataTables/DataTables-1.10.18/js/jquery.dataTables.js\">\n\t</script>\n\t<script type=\"text/javascript\" src=\"/static/js/DataTables/DataTables-1.10.18/js/dataTables.bootstrap.js\">\n\t</script>\n\t<script type=\"text/javascript\">\n\t\tfunction fun_option(val) { //下拉框触发事件\n\t\t\tdocument.location.href = \"../check/rule?company={{ source_system }}&risk_market=\" + val;\n\t\t}\n\n\t\tfunction fun_status(id, status) { //下拉框触发事件\n\t\t\t$.ajax({\n\t\t\t\ttype: \"POST\",\n\t\t\t\turl: \"../../api/check/rule/status_modify\",\n\t\t\t\tdata: {\n\t\t\t\t\tid: id,\n\t\t\t\t\tstatus: status,\n\t\t\t\t\tcompany: \"{{ source_system }}\",\n\t\t\t\t},\n\t\t\t\tsuccess: function (data) {\n\t\t\t\t\tconsole.log(data);\n\t\t\t\t\tlocation.reload(true);\n\t\t\t\t},\n\t\t\t\terror: function (e) {\n\t\t\t\t\tconsole.log(e);\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\tfunction format(d) {\n\t\t\t// `d` is the original data object for the row\n\t\t\treturn '<table cellpadding=\"5\" cellspacing=\"0\" border=\"0\" style=\"padding-left:50px;\">' +\n\t\t\t\t'<tr>' +\n\t\t\t\t'<td>检核逻辑:</td>' +\n\t\t\t\t'<td>' + d.check_sql + '</td>' +\n\t\t\t\t'</tr>' +\n\t\t\t\t'<tr>' +\n\t\t\t\t'<td>备注:</td>' +\n\t\t\t\t'<td>' + d.note + '</td>' +\n\t\t\t\t'</tr>' +\n\t\t\t\t'</table>';\n\t\t}\n\n\t\t$(document).ready(function () {\n\t\t\tvar table = $('#example').DataTable({\n\t\t\t\t\"ajax\": {\n\t\t\t\t\t\"url\": \"../../api/check/rule\",\n\t\t\t\t\t\"type\": \"GET\",\n\t\t\t\t\t\"data\": function (d) {\n\t\t\t\t\t\treturn $.extend({}, d, {\n\t\t\t\t\t\t\tname: \"{{ source_system }}\",\n\t\t\t\t\t\t\trisk_market_filter: \"{{ risk_market_filter }}\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t//\"ajax\": \"/static/resource/objects2.txt\",\n\t\t\t\t\"columns\": [{\n\t\t\t\t\t\t\"data\": \"id\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"data\": \"check_item\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"data\": \"target_table\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"data\": \"risk_market_item\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"data\": \"problem_type\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"data\": \"db\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"className\": 'details-control',\n\t\t\t\t\t\t\"orderable\": false,\n\t\t\t\t\t\t\"data\": null,\n\t\t\t\t\t\t\"defaultContent\": ''\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"data\": \"status\"\n\t\t\t\t\t},\n\t\t\t\t],\n\n\t\t\t\t\"columnDefs\": [{\n\t\t\t\t\t\t// 定义操作列,######以下是重点########\n\t\t\t\t\t\t\"targets\": 8,\n\t\t\t\t\t\t//操作按钮目标列\n\t\t\t\t\t\t\"data\": null,\n\t\t\t\t\t\t\"render\": function (data, type, row) {\n\t\t\t\t\t\t\tvar id = '\"' + row.id + '\"';\n\t\t\t\t\t\t\tvar html = \"<a href='../check/rule/edit?id=\" + row.id + \"&company=\" + row\n\t\t\t\t\t\t\t\t.source_system + \"&username=\" + \"{{ username }}\" +\n\t\t\t\t\t\t\t\t\"' style='margin-right:5px;border-bottom: 1px dotted;'>编辑</a>\"\n\t\t\t\t\t\t\treturn html;\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\n\t\t\t\t\t{\n\t\t\t\t\t\t\"targets\": 7,\n\t\t\t\t\t\t\"data\": \"status\",\n\t\t\t\t\t\t\"render\": function (data, type, row) {\n\t\t\t\t\t\t\tvar id = '\"' + row.id + '\"';\n\t\t\t\t\t\t\tif (data == '已启用') {\n\t\t\t\t\t\t\t\tvar html = \"<a href='javascript:void(0);' onclick='fun_status(\" + row\n\t\t\t\t\t\t\t\t\t.id + \",\\\"\" + row.status +\n\t\t\t\t\t\t\t\t\t\"\\\")' style='color:#429e47;border-bottom: 1px dotted;'>\" + data +\n\t\t\t\t\t\t\t\t\t\"</a>\"\n\t\t\t\t\t\t\t\treturn html;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tvar html = \"<a href='javascript:void(0);' onclick='fun_status(\" + row\n\t\t\t\t\t\t\t\t\t.id + \",\\\"\" + row.status +\n\t\t\t\t\t\t\t\t\t\"\\\")' style='color:#e33734;border-bottom: 1px dotted;'>\" + data +\n\t\t\t\t\t\t\t\t\t\"</a>\"\n\t\t\t\t\t\t\t\treturn html;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t],\n\n\t\t\t\t\"pagingType\": \"full_numbers\",\n\t\t\t\t\"sLoadingRecords\": \"正在加载数据...\",\n\t\t\t\t\"sZeroRecords\": \"暂无数据\",\n\t\t\t\tstateSave: true,\n\t\t\t\t\"searching\": true,\n\t\t\t\t\"ordering\": true,\n\t\t\t\t//\"dom\":'frtilp',\n\t\t\t\t\"dom\": 'frt<\"row\"<\"col-md-3\"l><\"col-md-3\"i><\"col-md-6 pull-right\"p>>',\n\n\t\t\t\t//汉化\n\t\t\t\t\"language\": {\n\t\t\t\t\t\"processing\": \"玩命加载中...\",\n\t\t\t\t\t\"lengthMenu\": \"显示 _MENU_ 项结果\",\n\t\t\t\t\t\"zeroRecords\": \"没有匹配结果\",\n\t\t\t\t\t\"info\": \"显示第 _START_ 至 _END_ 项结果，共 _TOTAL_ 项\",\n\t\t\t\t\t\"infoEmpty\": \"显示第 0 至 0 项结果，共 0 项\",\n\t\t\t\t\t\"infoFiltered\": \"(由 _MAX_ 项结果过滤)\",\n\t\t\t\t\t\"infoPostFix\": \"\",\n\t\t\t\t\t\"url\": \"\",\n\t\t\t\t\t\"paginate\": {\n\t\t\t\t\t\t\"first\": \"首页\",\n\t\t\t\t\t\t\"previous\": \"上一页\",\n\t\t\t\t\t\t\"next\": \"下一页\",\n\t\t\t\t\t\t\"last\": \"末页\"\n\t\t\t\t\t},\n\t\t\t\t\t\"sSearch\": \"搜索:\",\n\t\t\t\t},\n\t\t\t});\n\n\t\t\t$('#example tbody').on('click', 'td.details-control', function () {\n\t\t\t\tvar tr = $(this).closest('tr');\n\t\t\t\tvar row = table.row(tr);\n\n\t\t\t\tif (row.child.isShown()) {\n\t\t\t\t\t// This row is already open - close it\n\t\t\t\t\trow.child.hide();\n\t\t\t\t\ttr.removeClass('shown');\n\t\t\t\t} else {\n\t\t\t\t\t// Open this row\n\t\t\t\t\trow.child(format(row.data())).show();\n\t\t\t\t\ttr.addClass('shown');\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t//刷新页面按钮\n\t\t\t$(\"#tb-refresh\").on(\"click\", function () {\n\t\t\t\tlocation.reload();\n\t\t\t});\n\n\t\t});\n\t</script>\n\n\t</body>\n\n\t</html>"
  },
  {
    "path": "check/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "check/views.py",
    "content": "import datetime\nimport math\nimport sys\n\nfrom crontab import CronTab\nfrom django.shortcuts import render\n\nsys.path.insert(0, '..')\nfrom mysite import db_config\nfrom utils import functions as f\nfrom utils.functions import is_login\n\n\n@is_login\ndef rule_list(request):\n    \"\"\"\n    检核规则列表\n    :param request:\n    :return:\n    \"\"\"\n    return render(request, \"check/rule_list.html\", {\"source_system\": request.GET.get('company'),\n                                                    \"risk_market_filter\": request.GET.get('risk_market'),\n                                                    \"username\": request.session['username']\n                                                    }\n                  )\n\n\n@is_login\ndef rule_edit(request):\n    \"\"\"\n    单条检核规则页面\n    :param request:\n    :return:\n    \"\"\"\n    return render(request, \"check/rule_edit.html\", {\"username\": request.session['username'],\n                                                   \"source_system\": request.GET.get('company'),\n                                                   \"id\": request.GET.get('id')\n                                                   })\n\n\n@is_login\ndef rule_execute_manual(request):\n    \"\"\"\n    查询检核进度\n    :param request:\n    :return:\n    \"\"\"\n    date = str(datetime.datetime.now().year) + \"-\" + str(datetime.datetime.now().month) + '-' + str(datetime.datetime.now().day)\n    return render(request, \"check/rule_exec.html\", {\"date\": date})\n\n\n@is_login\ndef show_crontab(request):\n    \"\"\"\n    自动检核配置页面\n    :param request:\n    :return:\n    \"\"\"\n    conn = db_config.mysql_connect()\n    with conn.cursor() as curs:\n        # 查询各个公司检核规则配置的数据库、上次检核任务的运行情况\n        sql = \"\"\"select distinct b.name,\n                                a.company,\n                                a.db,\n                                CAST(c.execute_date as char),\n                                c.status\n                from check_result_template a,\n                source_db_info b,\n                (select db,company,execute_date,status from check_execute_log  where id in \n                    (\n                        select id from (select max(id) id,company,db from check_execute_log where db is not null group by company,db) a\n                    )\n                ) c\n                where a.db=b.alias\n                and a.db=c.db\n                and a.company=c.company\n                order by 1,2,3\"\"\"\n        curs.execute(sql)\n        jobs = curs.fetchall()\n        \n    # 根据数据源中的公司和数据库信息匹配crontab定时任务\n    cron = CronTab(user=True)\n    data = []\n    for i in jobs:\n        job = list(cron.find_comment(f'autocheck-{i[1]}-{i[2]}'))\n        t = list(i)\n        if len(job) > 0:\n            enable = job[0].is_enabled()                                # 获取crontab启用状态\n            job_time = job[0].description(use_24hour_time_format=True, locale_code='zh_CN') # 获取crontab的调度周期 \n            t.extend([enable, job_time])\n        else:\n            t.append(None)\n        data.append(t)\n    \n    return render(request, \"check/crontab.html\", {\"jobs\": data})\n\n\n@is_login\ndef blood_analyze(request):\n    \"\"\"血缘分析\"\"\"\n    return render(request, \"check/blood_analyze.html\") "
  },
  {
    "path": "data/__init__.py",
    "content": ""
  },
  {
    "path": "data/admin.py",
    "content": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "data/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass DataConfig(AppConfig):\n    name = 'data'\n"
  },
  {
    "path": "data/models.py",
    "content": "from django.db import models\n\n# Create your models here.\n"
  },
  {
    "path": "data/templates/data/dashboard.html",
    "content": "{% include \"data/template-ui.html\" %}\n<style>\n    table {\n        border-collapse: collapse;\n        width: 100%;\n    }\n    thead th {\n        border-bottom: 2px solid #dee2e6;\n    }\n    tbody tr td {\n        padding: 9px;\n        vertical-align: top;\n        border-top: 1px solid #dee2e6;\n    }\n    #demand_table {\n        line-height: 19px;\n    }\n    .alert {\n        margin-bottom: 0px;\n        margin-left: 1%\n    }\n    select{\n        border: 0 none;\n        border-bottom: 1px solid;\n        appearance: none;\n        -moz-appearance:none; /* Firefox */\n        -webkit-appearance:none; /* Safari 和 Chrome */\n        -ms-appearance: none;\n        padding-left: 2%;\n        padding-right: 1%;\n    }\n    select::-ms-expand { display: none; }\n    .overview_table tr td{\n        font-size: 14px;\n        line-height: 31px;\n        padding: 0.3rem;\n        vertical-align: middle;\n    }\n</style>\n\n<!-- 正文主体 -->\n<div class=\"page-wrapper\">\n    <!-- 标题 -->\n    <div class=\"row page-titles\">\n        <div class=\"col-md-4 align-self-center\">\n            <h3 class=\"text-primary\">风险集市数据质量仪表盘</h3>\n        </div>\n\n        <div class=\"col-md-5 align-self-center\">\n            <div class=\"row\">\n                数据日期：\n                <select id=\"data_year\" onchange=\"GetQuarter();\" style=\"width: 60px;\"></select><span style=\"padding-right: 5px;\">年</span>\n                <span>· 第</span><select id=\"data_quarter\" onchange=\"GetMonth();\" style=\"width: 30px;\"></select><span style=\"padding-right: 5px;\">季度 ·</span>\n                <select id=\"data_month\" onchange=\"GetDay();\" style=\"width: 40px;\"></select><span style=\"padding-right: 5px;\">月</span>\n                <select id=\"data_day\" style=\"width: 40px;\"></select><span style=\"padding-right: 15px;\">日</span>\n                <button type=\"button\" class=\"btn btn-primary btn-xs p310\" onclick=\"ChangeDataDate();\"><i class=\"fa fa-search\"></i></button>\n            </div>\n        </div>\n\n        <div class=\"col-md-3 align-self-center\">\n            <ol class=\"breadcrumb\">\n                <li class=\"breadcrumb-item\"><a href=\"../../data/dashboard\">主页</a></li>\n                <li class=\"breadcrumb-item active\">仪表盘</li>\n            </ol>\n        </div>\n    </div>\n\n    <div class=\"container-fluid animated fadeInUp\">\n        <!--数据概览-->\n        <div class=\"row\">\n            <div class=\"col-lg-12\">\n                <div class=\"card\">\n                    <div class=\"card-body\">\n                        <h4 class=\"card-title\" style=\"margin-bottom: -10px;\">数据质量总览</h4>\n                        <div class=\"card-content\">\n                            <div class=\"row\">\n                                <div class=\"col-md-4\">\n                                    <div class=\"card bg-pink p-20\">\n                                        <div class=\"media widget-ten\">\n                                            <div class=\"media-left meida media-middle\">\n                                                <span><i class=\"ti-vector f-s-40\"></i></span>\n                                            </div>\n                                            <div class=\"media-body media-text-right\">\n                                                <h2 class=\"color-white\" id=\"all_cnt\"></h2>\n                                                <p class=\"m-b-0\">检核数据总量</p>\n                                            </div>\n                                        </div>\n                                    </div>\n                                </div>\n                                <div class=\"col-md-4\">\n                                    <div class=\"card bg-danger p-20\">\n                                        <div class=\"media widget-ten\">\n                                            <div class=\"media-left meida media-middle\">\n                                                <span><i class=\"ti-location-pin f-s-40\"></i></span>\n                                            </div>\n                                            <div class=\"media-body media-text-right\">\n                                                <h2 class=\"color-white\" id=\"problem_cnt\"></h2>\n                                                <p class=\"m-b-0\">问题数据总量</p>\n                                            </div>\n                                        </div>\n                                    </div>\n                                </div>\n                                <div class=\"col-md-4\">\n                                    <div class=\"card bg-primary p-20\">\n                                        <div class=\"media widget-ten\">\n                                            <div class=\"media-left meida media-middle\">\n                                                <span><i class=\"ti-bag f-s-40\"></i></span>\n                                            </div>\n                                            <div class=\"media-body media-text-right\">\n                                                <h2 class=\"color-white\" id=\"problem_per\"></h2>\n                                                <p class=\"m-b-0\">问题占比</p>\n                                            </div>\n                                        </div>\n                                    </div>\n                                </div>\n                            </div>\n\n                            <div class=\"row\">\n                                <div class=\"alert alert-secondary alert-dismissible fade show\">\n                                    <button type=\"button\" class=\"close\" data-dismiss=\"alert\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\n                                    <strong>注：</strong> 本季度的检核逻辑主要针对数据的规范性，尚未检核数据的准确性\n                                </div>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n\n        <!--问题占比-->\n        <div class=\"row\">\n            <div class=\"col-lg-4\">\n                <div class=\"card\">\n                    <!-- <h4 class=\"card-title\">各公司数据质量概况</h4> -->\n                    <div class=\"card-body\">\n                        <div class=\"table-responsive\">\n                            <table class=\"table table-hover overview_table\">\n                                <thead>\n                                    <tr>\n                                        <th colspan=\"2\">信托</th>\n                                        <th>问题占比趋势</th>\n                                    </tr>\n                                </thead>\n                                <tbody id=\"overview_xt\">\n                                </tbody>\n                            </table>\n                        </div>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"col-lg-4\">\n                <div class=\"card\">\n                    <div class=\"table-responsive\">\n                        <table class=\"table table-hover overview_table\">\n                            <thead>\n                                <tr>\n                                    <th colspan=\"2\">资产</th>\n                                    <th>问题占比趋势</th>\n                                </tr>\n                            </thead>\n                            <tbody id=\"overview_zc\">\n                            </tbody>\n                        </table>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"col-lg-4\">\n                <div class=\"card\">\n                    <div class=\"table-responsive\">\n                        <table class=\"table table-hover overview_table\">\n                            <thead>\n                                <tr>\n                                    <th colspan=\"2\">担保</th>\n                                    <th>问题占比趋势</th>\n                                </tr>\n                            </thead>\n                            <tbody id=\"overview_db\">\n                            </tbody>\n                        </table>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"col-lg-4\">\n                <div class=\"card\">\n                    <div class=\"table-responsive\">\n                        <table class=\"table table-hover overview_table\">\n                            <thead>\n                                <tr>\n                                    <th colspan=\"2\">金科</th>\n                                    <th>问题占比趋势</th>\n                                </tr>\n                            </thead>\n                            <tbody id=\"overview_jk\">\n                            </tbody>\n                        </table>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"col-lg-4\">\n                <div class=\"card\">\n                    <div class=\"table-responsive\">\n                        <table class=\"table table-hover overview_table\">\n                            <thead>\n                                <tr>\n                                    <th colspan=\"2\">基金1</th>\n                                    <th>问题占比趋势</th>\n                                </tr>\n                            </thead>\n                            <tbody id=\"overview_jj1\">\n                            </tbody>\n                        </table>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"col-lg-4\">\n                <div class=\"card\">\n                    <div class=\"table-responsive\">\n                        <table class=\"table table-hover overview_table\">\n                            <thead>\n                                <tr>\n                                    <th colspan=\"2\">基金2</th>\n                                    <th>问题占比趋势</th>\n                                </tr>\n                            </thead>\n                            <tbody id=\"overview_jj2\">\n                            </tbody>\n                        </table>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"col-lg-4\">\n                <div class=\"card\">\n                    <div class=\"table-responsive\">\n                        <table class=\"table table-hover overview_table\">\n                            <thead>\n                                <tr>\n                                    <th colspan=\"2\">金租</th>\n                                    <th>问题占比趋势</th>\n                                </tr>\n                            </thead>\n                            <tbody id=\"overview_jz\">\n                            </tbody>\n                        </table>\n                    </div>\n                </div>\n            </div>\n        </div>\n        \n        <div class=\"row\">\n            <!-- 各公司平均问题占比 -->\n            <div class=\"col-lg-7\">\n                <div class=\"card\" id=\"echarts1\" style=\"width:100%;height:400px;\"></div>\n            </div>\n\n            <!-- 集团总问题占比趋势 -->\n            <div class=\"col-lg-5\">\n                <div class=\"card\" id=\"echarts5\" style=\"width:100%;height:400px;\"></div>\n            </div>\n        </div>\n\n        <!-- 各公司需求改造进度 -->\n        <div class=\"row\">\n            <div class=\"col-lg-7\">\n                <div class=\"card\" id=\"echarts4\" style=\"width:100%;height:400px;\"></div>\n            </div>\n\n            <div class=\"col-lg-5\">\n                <div class=\"card\" style=\"width:100%;height:400px;\">\n                    <h5 class=\"card-title\">各公司需求改造进度</h5>\n                    <h4 class=\"card-subtitle\">风险集市相关</h4>\n                    <table id=\"demand_table\"></table>\n                </div>\n            </div>\n        </div>\n\n        <div class=\"row\">\n            <!-- 各公司数据量占比 -->\n            <div class=\"col-lg-7\">\n                <div class=\"card\" id=\"echarts3\" style=\"width:100%;height:500px;\"></div>\n            </div>\n\n            <!-- 各公司同类问题Top 10统计 -->\n            <div class=\"col-lg-5\">\n                <div class=\"card\" id=\"echarts2\" style=\"width:100%;height:500px;\"></div>\n            </div>\n        </div>\n\n    </div>\n</div>\n\n<!-- footer -->\n<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n    <div class=\"footer\">\n        © 2019 Hyhyhyhyhyhyh\n    </div>\n</footer>\n</div>\n\n<script>\n    //将用户名存入localStorage\n    localStorage.setItem('username', \"{{ username }}\");\n</script>\n\n<!-- 设置头像 / 设置日期 -->\n<script src=\"/static/js/init.js\"></script>\n<!-- 加载echarts数据 -->\n<script src=\"/static/js/dashboard_echarts.js\"></script>\n\n\n</body>\n\n</html>"
  },
  {
    "path": "data/templates/data/dashboard_subcompany.html",
    "content": "{% include \"data/template-ui.html\" %}\n<style>\n    table {\n        border-collapse: collapse;\n        width: 100%;\n    }\n    thead th {\n        border-bottom: 2px solid #dee2e6;\n    }\n    tbody tr td {\n        padding: 7px;\n        vertical-align: top;\n        border-top: 1px solid #dee2e6;\n    }\n    .excel-btn {\n        position: absolute;\n        right: 60%;\n        top: 85%;\n        background-color: #fff;\n        border-radius: 50%;\n        white-space: nowrap;\n        height: 56px;\n        width: 56px;\n        text-decoration: none;\n        box-shadow: 0 3px 5px -1px rgba(0, 0, 0, .2), 0 6px 10px 0 rgba(0, 0, 0, .14), 0 1px 18px 0 rgba(0, 0, 0, .12);\n        border-radius: 50%;\n        font-weight: 500;\n        letter-spacing: .0892857143em;\n    }\n\n    .excel-tips {\n        position: absolute;\n        display: none;\n        background: rgba(97, 97, 97, .9);\n        color: #fff;\n        border-radius: 4px;\n        font-size: 14px;\n        line-height: 22px;\n        padding: 5px 8px;\n        text-transform: none;\n        width: auto;\n        pointer-events: none;\n    }\n\n    .excel-icon {\n        border-radius: 50%;\n        height: 56px;\n        width: 56px;\n    }\n\n    .excel-btn:hover .excel-tips {\n        display: inline-block;\n        top: 25%;\n        left: 120%;\n        animation: fade-in;/*动画名称*/  \n        animation-duration: 0.3s;/*动画持续时间*/  \n        -webkit-animation:fade-in 0.3s;/*针对webkit内核*/\n    }\n\n    @keyframes fade-in {  \n        0% {opacity: 0;}/*初始状态 透明度为0*/  \n        50% {opacity: 0.5;}/*过渡状态 透明度为0*/  \n        100% {opacity: 1;}/*结束状态 透明度为1*/  \n    }  \n    @-webkit-keyframes fade-in {/*针对webkit内核*/  \n        0% {opacity: 0;}  \n        50% {opacity: 0.5;}  \n        100% {opacity: 1;}  \n    }  \n    select{\n        border: 0 none;\n        border-bottom: 1px solid;\n        appearance: none;\n        -moz-appearance:none; /* Firefox */\n        -webkit-appearance:none; /* Safari 和 Chrome */\n        -ms-appearance: none;\n        padding-left: 2%;\n        padding-right: 1%;\n    }\n    select::-ms-expand { display: none; }\n</style>\n\n<!-- 正文主体 -->\n<div class=\"page-wrapper\">\n    <!-- 标题 -->\n    <div class=\"row page-titles\">\n        <div class=\"col-md-4 align-self-center\">\n            <h3 class=\"text-primary\">{{ company }}公司-数据质量仪表盘</h3>\n        </div>\n\n        <div class=\"col-md-5 align-self-center\">\n            <div class=\"row\">\n                数据日期：\n                <select id=\"data_year\" onchange=\"GetQuarter();\" style=\"width: 60px;\"></select><span style=\"padding-right: 5px;\">年</span>\n                <span>· 第</span><select id=\"data_quarter\" onchange=\"GetMonth();\" style=\"width: 30px;\"></select><span style=\"padding-right: 5px;\">季度 ·</span>\n                <select id=\"data_month\" onchange=\"GetDay();\" style=\"width: 40px;\"></select><span style=\"padding-right: 5px;\">月</span>\n                <select id=\"data_day\" style=\"width: 40px;\"></select><span style=\"padding-right: 15px;\">日</span>\n                <button type=\"button\" class=\"btn btn-primary btn-xs p310\" onclick=\"ChangeDataDate();\"><i class=\"fa fa-search\"></i></button>\n            </div>\n        </div>\n\n        <div class=\"col-md-3 align-self-center\">\n            <ol class=\"breadcrumb\">\n                <li class=\"breadcrumb-item\"><a href=\"../../data/index\">主页</a></li>\n                <li class=\"breadcrumb-item active\">仪表盘</li>\n            </ol>\n        </div>\n    </div>\n\n    <!-- Begin 正文-->\n    <div class=\"container-fluid\">\n        <div class=\"alert alert-secondary alert-dismissible fade show\" style=\"margin-top:10px;margin-bottom:-7px;\">\n            <button type=\"button\" class=\"close\" data-dismiss=\"alert\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\n            <strong>注：</strong> 本季度的检核逻辑主要针对数据的规范性，尚未检核数据的准确性\n        </div>\n        \n        <div class=\"row\">\n            <div class=\"col-lg-12\">\n                <div class=\"card\" id=\"chart1\" style=\"width:100%;height:500px;\"></div>\n            </div>\n        </div>\n\n        <div class=\"row\">\n            <div class=\"col-lg-4\">\n                <div class=\"card\">\n                        <h4 class=\"card-title\">问题数据统计（风险集市相关）</h4>\n                        <table id=\"chart1_table\"></table>\n                </div>\n            </div>\n\n            <div class=\"col-lg-8\">\n                    <div class=\"card\">\n                        <h4 class=\"card-title\">源系统改造情况（风险集市相关）</h4>\n                        <table id=\"demand_table\"></table>\n                    </div>\n                </div>\n        </div>\n\n        <!-- 各公司风险指标图 -->\n        <div class=\"row\">\n            <div class=\"col-lg-12\">\n                <div class=\"card\" style=\"position:relative;\">\n                    <img src=\"../../static/resource/{{ company_zh }}公司风险指标.png\" style=\"object-fit:contain;width:100%;height:43vw;\">\n                    <a href=\"../../api/files/download?filename={{ company_zh }}公司风险指标.xlsx\" class=\"excel-btn\">\n                        <i><img src=\"../../static/img/excel-icon.jpg\" class=\"excel-icon\" /></i>\n                        <div class=\"excel-tips\">\n                            <span>下载详细定义</span>\n                        </div>\n                    </a>\n                </div>\n            </div>\n        </div>\n    </div>\n    <!-- End 正文 -->\n</div>\n\n<!-- footer -->\n<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n    <div class=\"footer\">\n            © 2019 Hyhyhyhyhyhyh\n    </div>\n</footer>\n</div>\n\n\n<!-- 设置头像 / 设置日期 -->\n<script src=\"/static/js/init.js\"></script>\n\n<script type=\"text/javascript\">\n    var year = localStorage.getItem(\"selected_year\");\n    var quarter = localStorage.getItem(\"selected_quarter\");\n    var month = localStorage.getItem(\"selected_month\");\n    var day = localStorage.getItem(\"selected_day\");\n    \n    var myChart1 = echarts.init(document.getElementById('chart1'));\n    \n    $('.chart').resize(function(){\n        myChart1.resize();\n    });\n    \n    var option = {\n        title : {\n            text: '问题数据项统计',\n            subtext: year+'-'+month+'-'+day +' 风险集市相关',\n            x:'center'\n        },\n        dataset: {\n            source: []\n        },\n        tooltip : {\n            trigger: 'axis',\n            formatter: ('{c}'.split(\",\"))[1]\n        },\n        grid: {\n            containLabel: true,\n            //width: 500,\n        },\n        xAxis: {\n            name: '问题数据总量',\n        },\n        yAxis: {\n            name: '问题数据项',\n            type: 'category',\n        },\n        visualMap: {\n            orient: 'horizontal',\n            left: 'center',\n            min: 10,\n            max: 100,\n            text: ['高占比', '低占比'],\n            // Map the score column to color\n            dimension: 0,\n            inRange: {\n                color: ['#D7DA8B', '#E15457']\n            }\n        },\n        series: [\n            {\n                type: 'bar',\n                encode: {\n                    x: '问题数据总量',\n                    y: '问题数据项'\n                }\n            }\n        ]\n    };    \n    \n    myChart1.setOption(option);\n    myChart1.showLoading();\n\n    // 请求接口数据-填充[问题数据统计]\n    $.ajax({\n        type : \"get\",\n        async : true,\n        url : \"../../api/dashboard/subcompany_problem_count\",\n        data: {\n            \"company\": \"{{ company }}\",\n            \"year\": year,\n            \"quarter\": quarter,\n            \"month\": month,\n            \"day\": day,\n        },\n        dataType : \"json\",\n        success : function(result) {\n            if (result) {                           //请求成功时执行该函数内容，result即为服务器返回的json对象\n                myChart1.hideLoading();              //隐藏加载动画\n                myChart1.setOption({                 //加载数据图表\n                //渲染echarts\n                    dataset: {\n                        source: result\n                    }\n                });\n\n                //渲染table\n                var html = \"<thead><th>问题数据项</th><th>问题数据总量</th><th>问题占比</th></thead><tbody>\";\n                for(var i=1;i<result.length;i++){\n                    html += \"<tr>\";\n                    html += \"<td>\" + result[i][2] + \"</td>\";\n                    html += \"<td>\" + result[i][1] + \"</td>\";\n                    html += \"<td>\" + result[i][0] + \"%</td>\";\n                    html += \"</tr>\";\n                }\n                html += \"</tbody>\";\n                document.getElementById(\"chart1_table\").innerHTML = html;\n            }\n        },\n        error : function(errorMsg) {\n            console.log(errorMsg);\n        }\n    })\n\n\n    // 请求接口数据-填充[源系统改造需求情况]\n    $.ajax({\n        type : \"get\",\n        async : true,           //异步请求（同步请求将会锁住浏览器，用户其他操作必须等待请求完成才可以执行）\n        url : \"../../static/resource/demand.json\",\n        data: {},\n        dataType : \"json\",        //返回数据形式为json\n        success : function(result) {\n            if (result) {\n                //渲染table\n                var html = \"<thead><th>#</th><th>源系统数据项</th><th>改造需求</th><th>需求提出时间</th>\";\n                for(var i=5;i<result[0].length;i++){\n                    html += \"<th>\";\n                    html += result[0][i].substr(0,6) + \"进度\";\n                    html += \"</th>\"\n                }\n                html += \"</thead><tbody>\";\n\n                for(var i=1;i<result.length;i++){\n                    html += \"<tr>\";\n                    if (result[i][1] != '{{ company_zh }}'){\n                       continue;\n                    }\n                    for(var t=0;t<result[i].length;t++){\n                        if(t==1){\n                           continue; \n                        }\n                        html += \"<td>\" + result[i][t] + \"</td>\";\n                    }\n                    html += \"</tr>\";\n                }\n                html += \"</tbody>\";\n                document.getElementById(\"demand_table\").innerHTML = html;\n            }\n        },\n        error : function(errorMsg) {\n            console.log(errorMsg);\n        }\n    })\n</script>\n</body>\n\n</html>"
  },
  {
    "path": "data/templates/data/report.html",
    "content": "{% include \"data/template-ui.html\" %}\n<!-- 设置word文档格式 -->\n<style type=\"text/css\">\n    tbody tr td {\n        font-family: \"SimSun\", sans-serif;\n        font-size: 21.3px;\n        color: #000;\n        text-align: center;\n    }\n\n    .table>thead>tr>th {\n        line-height: 25px;\n        vertical-align: top;\n    }\n\n    .table>thead>tr>th {\n        font-weight: 100;\n    }\n\n    thead tr th {\n        color: #000;\n        text-align: center;\n    }\n\n    thead tr th:last-child {\n        text-align: center;\n    }\n\n    tbody tr td:last-child {\n        text-align: center;\n    }\n\n    h3 {\n        size: 21.3px;\n        font-family: \"SimSun\", sans-serif;\n        color: #000;\n    }\n\n    select{\n        border: 0 none;\n        border-bottom: 1px solid;\n        appearance:none;\n        -moz-appearance:none; /* Firefox */\n        -webkit-appearance:none; /* Safari 和 Chrome */\n        padding: unset;\n        height: unset;\n        padding-left: 2%;\n        padding-right: 1%;\n        /*padding-top: 0.8rem;*/\n        margin: unset;\n    }\n    select::-ms-expand { display: none; }\n    select:focus{\n        border: 0 none;\n        border-bottom: 1px solid;\n        box-shadow: unset;\n    }\n</style>\n<!-- 设置word文档格式 END -->\n\n<div class=\"page-wrapper\">\n    <!-- 标题 -->\n    <div class=\"row page-titles\">\n        <div class=\"col-md-4 align-self-center\">\n            <h3 class=\"text-primary\" style=\"font-family: 'Open Sans', sans-serif;\">数据质量报告</h3>\n        </div>\n\n        <div class=\"col-md-5 align-self-center\">\n            <div class=\"row\">\n                数据日期：\n                <select id=\"data_year\" onchange=\"GetQuarter();\" style=\"width: 60px;\"></select><span style=\"padding-right: 5px;\">年</span>\n                <span>· 第</span><select id=\"data_quarter\" onchange=\"GetMonth();\" style=\"width: 30px;\"></select><span style=\"padding-right: 5px;\">季度 ·</span>\n                <select id=\"data_month\" onchange=\"GetDay();\" style=\"width: 40px;\"></select><span style=\"padding-right: 5px;\">月</span>\n                <select id=\"data_day\" style=\"width: 40px;\"></select><span style=\"padding-right: 15px;\">日</span>\n                <button type=\"button\" class=\"btn btn-primary btn-xs p310\" onclick=\"ChangeDataDate();\" style=\"border-radius: .25rem;\"><i class=\"fa fa-search\"></i></button>\n            </div>\n        </div>\n\n        <div class=\"col-md-3 align-self-center\">\n            <ol class=\"breadcrumb\">\n                <li class=\"breadcrumb-item\"><a href=\"../../data/index\">主页</a></li>\n                <li class=\"breadcrumb-item active\">数据质量检核报告-WORD</li>\n            </ol>\n        </div>\n    </div>\n\n    <div class=\"container-fluid animated fadeInUp\">\n        <div class=\"row\">\n            <div class=\"col-md-10\">\n                <div class=\"card\" id=\"page-content\">\n                    <h2 style=\"size:29.3px;text-align:center;font-family:SimSun;font-weight:bold;color:#000;\" />\n                    集团{{ quarter }}数据质量报告\n                    <h3 style=\"font-weight:bold;\" />1 总结\n                    <h3>&nbsp;&nbsp;本季度对对信托、资产、担保、金科、基金1、基金2、金租七个公司风险集市相关共{{ sum_item_cnt }}条数据进行检查，合计问题数{{ sum_problem_cnt }}，问题占比{{ total_problem_per }}。\n                        <font\n                            style=\"font-style:italic;size:21.3px;font-family:SimSun;color:rgb(91, 155, 213);text-decoration:underline;\">\n                            补充环比统计和需求完成情况统计</font>\n                    </h3>\n                    <h3 style=\"font-style:italic;color:rgb(91, 155, 213);\" />\n                    &nbsp;&nbsp;注：每个基础数据项为一条数据。例如一个项目的项目名称、项目类别、项目资金用途将会统计为3条数据。问题数据量、系统改造需求数量均按此粒度统计。\n                    </br>\n\n                    <h3 />风险集市相关数据质量概况如下（详见附件一）：\n                    <table class=\"table table-bordered\">\n                        <thead>\n                            <tr>\n                                <th />季度\n                                <th />公司\n                                <th />监测数据量\n                                <th />问题数据量\n                                <th />问题数据占比\n                            </tr>\n                        </thead>\n                        <tbody>\n                            {% for i in overview_result_1 %}\n                            <tr>\n                                <td>{{ i.0 }}</td>\n                                <td>{{ i.1 }}</td>\n                                <td>{{ i.2 }}</td>\n                                <td>{{ i.3 }}</td>\n                                <td>{{ i.4 }}</td>\n                            </tr>\n                            {% endfor %}\n                        </tbody>\n                    </table>\n                    <h3 style=\"font-style:italic;color:rgb(91, 155, 213);text-decoration:underline;\" />注：填写备注\n                    <h3 />&nbsp;&nbsp;源系统改造需求完成情况如下（详见附件一的“系统改造需求”标签页）：\n                    <table class=\"table table-bordered\">\n                        <thead>\n                            <tr>\n                                <th />序号\n                                <th />公司\n                                <th />已完成需求数\n                                <th />待完成需求数\n                                <th />完成率\n                            </tr>\n                        </thead>\n                        <tbody>\n                            <tr>\n                                <td />1\n                                <td />信托\n                                <td />\n                                <td />\n                                <td />\n                            </tr>\n                            <tr>\n                                <td />2\n                                <td />资产\n                                <td />\n                                <td />\n                                <td />\n                            </tr>\n                            <tr>\n                                <td />3\n                                <td />担保\n                                <td />\n                                <td />\n                                <td />\n                            </tr>\n                            <tr>\n                                <td />4\n                                <td />金科\n                                <td />\n                                <td />\n                                <td />\n                            </tr>\n                            <tr>\n                                <td />5\n                                <td />基金1\n                                <td />\n                                <td />\n                                <td />\n                            </tr>\n                            <tr>\n                                <td />6\n                                <td />基金2\n                                <td />\n                                <td />\n                                <td />\n                            </tr>\n                            <tr>\n                                <td />7\n                                <td />金租\n                                <td />\n                                <td />\n                                <td />\n                            </tr>\n                            <tr>\n                                <td />\n                                <td />合计\n                                <td />\n                                <td />\n                                <td />\n                            </tr>\n                        </tbody>\n                    </table>\n                    </br>\n\n                    <h3 style=\"font-weight:bold;\" />2 检查方案\n                    <h3 />依据标准：《集团数据质量标准V1.0》。\n                    <h3 />检查数据范围：\n                    <h3 style=\"color:#FF0000;\" />风险集市需要且截止2018年1月1日未结项的数据。\n                    <h3 />检查方法：具体参考附件一，主要对数据项进行空值检核、值域检核、类型检核、未创建项检核、合法性检核等。检核规则会逐步完善。\n                    </br>\n\n                    <h3 style=\"font-weight:bold;\" />3 数据质量检查结果\n                    <h3 />3.1 信托公司\n                    <h3 style=\"font-style:italic;color:rgb(91, 155, 213);text-decoration:underline;\">问题分析</h3>\n                    <table class=\"table table-bordered\">\n                        <thead>\n                            <tr>\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />数据项\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />检核规则\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;color:#FF0000;\" />问题数据量\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />检核数据量\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />占比\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />建议改进方案\n                            </tr>\n                        </thead>\n                        <tbody>\n                            {% for i in ycxt_detail %}\n                            <tr>\n                                <td>{{ i.0|default_if_none:\"\" }}</td>\n                                <td>{{ i.1|default_if_none:\"\" }}</td>\n                                <td>{{ i.2|default_if_none:\"\" }}</td>\n                                <td>{{ i.3|default_if_none:\"\" }}</td>\n                                <td>{{ i.4|default_if_none:\"\" }}</td>\n                                <td>{{ i.5|default_if_none:\"\" }}</td>\n                            </tr>\n                            {% endfor %}\n                        </tbody>\n                    </table>\n                    </br>\n\n                    <h3 />3.2 资产公司\n                    <h3 style=\"font-style:italic;color:rgb(91, 155, 213);text-decoration:underline;\">问题分析</h3>\n                    <table class=\"table table-bordered\">\n                        <thead>\n                            <tr>\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />数据项\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />检核规则\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;color:#FF0000;\" />问题数据量\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />检核数据量\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />占比\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />建议改进方案\n                            </tr>\n                        </thead>\n                        <tbody>\n                            {% for i in yczc_detail %}\n                            <tr>\n                                <td>{{ i.0|default_if_none:\"\" }}</td>\n                                <td>{{ i.1|default_if_none:\"\" }}</td>\n                                <td>{{ i.2|default_if_none:\"\" }}</td>\n                                <td>{{ i.3|default_if_none:\"\" }}</td>\n                                <td>{{ i.4|default_if_none:\"\" }}</td>\n                                <td>{{ i.5|default_if_none:\"\" }}</td>\n                            </tr>\n                            {% endfor %}\n                        </tbody>\n                    </table>\n                    </br>\n\n                    <h3 />3.3 担保公司\n                    <h3 style=\"font-style:italic;color:rgb(91, 155, 213);text-decoration:underline;\">问题分析</h3>\n                    <table class=\"table table-bordered\">\n                        <thead>\n                            <tr>\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />数据项\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />检核规则\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;color:#FF0000;\" />问题数据量\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />检核数据量\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />占比\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />建议改进方案\n                            </tr>\n                        </thead>\n                        <tbody>\n                            {% for i in gdzdb_detail %}\n                            <tr>\n                                <td>{{ i.0|default_if_none:\"\" }}</td>\n                                <td>{{ i.1|default_if_none:\"\" }}</td>\n                                <td>{{ i.2|default_if_none:\"\" }}</td>\n                                <td>{{ i.3|default_if_none:\"\" }}</td>\n                                <td>{{ i.4|default_if_none:\"\" }}</td>\n                                <td>{{ i.5|default_if_none:\"\" }}</td>\n                            </tr>\n                            {% endfor %}\n                        </tbody>\n                    </table>\n                    </br>\n\n                    <h3 />3.4 金科公司\n                    <h3 style=\"font-style:italic;color:rgb(91, 155, 213);text-decoration:underline;\">问题分析</h3>\n                    <table class=\"table table-bordered\">\n                        <thead>\n                            <tr>\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />数据项\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />检核规则\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;color:#FF0000;\" />问题数据量\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />检核数据量\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />占比\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />建议改进方案\n                            </tr>\n                        </thead>\n                        <tbody>\n                            {% for i in ycjk_detail %}\n                            <tr>\n                                <td>{{ i.0|default_if_none:\"\" }}</td>\n                                <td>{{ i.1|default_if_none:\"\" }}</td>\n                                <td>{{ i.2|default_if_none:\"\" }}</td>\n                                <td>{{ i.3|default_if_none:\"\" }}</td>\n                                <td>{{ i.4|default_if_none:\"\" }}</td>\n                                <td>{{ i.5|default_if_none:\"\" }}</td>\n                            </tr>\n                            {% endfor %}\n                        </tbody>\n                    </table>\n                    </br>\n\n                    <h3 />3.5 基金1\n                    <h3 style=\"font-style:italic;color:rgb(91, 155, 213);text-decoration:underline;\">问题分析</h3>\n                    <table class=\"table table-bordered\">\n                        <thead>\n                            <tr>\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />数据项\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />检核规则\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;color:#FF0000;\" />问题数据量\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />检核数据量\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />占比\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />建议改进方案\n                            </tr>\n                        </thead>\n                        <tbody>\n                            {% for i in fdct_detail %}\n                            <tr>\n                                <td>{{ i.0|default_if_none:\"\" }}</td>\n                                <td>{{ i.1|default_if_none:\"\" }}</td>\n                                <td>{{ i.2|default_if_none:\"\" }}</td>\n                                <td>{{ i.3|default_if_none:\"\" }}</td>\n                                <td>{{ i.4|default_if_none:\"\" }}</td>\n                                <td>{{ i.5|default_if_none:\"\" }}</td>\n                            </tr>\n                            {% endfor %}\n                        </tbody>\n                    </table>\n                    </br>\n\n                    <h3 />3.6 基金2\n                    <h3 style=\"font-style:italic;color:rgb(91, 155, 213);text-decoration:underline;\">问题分析</h3>\n                    <table class=\"table table-bordered\">\n                        <thead>\n                            <tr>\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />数据项\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />检核规则\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;color:#FF0000;\" />问题数据量\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />检核数据量\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />占比\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />建议改进方案\n                            </tr>\n                        </thead>\n                        <tbody>\n                            {% for i in zyyc_detail %}\n                            <tr>\n                                <td>{{ i.0|default_if_none:\"\" }}</td>\n                                <td>{{ i.1|default_if_none:\"\" }}</td>\n                                <td>{{ i.2|default_if_none:\"\" }}</td>\n                                <td>{{ i.3|default_if_none:\"\" }}</td>\n                                <td>{{ i.4|default_if_none:\"\" }}</td>\n                                <td>{{ i.5|default_if_none:\"\" }}</td>\n                            </tr>\n                            {% endfor %}\n                        </tbody>\n                    </table>\n                    </br>\n\n                    <h3 />3.7 金租公司\n                    <h3 style=\"font-style:italic;color:rgb(91, 155, 213);text-decoration:underline;\">问题分析</h3>\n                    <table class=\"table table-bordered\">\n                        <thead>\n                            <tr>\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />数据项\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />检核规则\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;color:#FF0000;\" />问题数据量\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />检核数据量\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />占比\n                                <th style=\"background-color:rgb(221,235,247);font-weight:bold;\" />建议改进方案\n                            </tr>\n                        </thead>\n                        <tbody>\n                            {% for i in jz_detail %}\n                            <tr>\n                                <td>{{ i.0|default_if_none:\"\" }}</td>\n                                <td>{{ i.1|default_if_none:\"\" }}</td>\n                                <td>{{ i.2|default_if_none:\"\" }}</td>\n                                <td>{{ i.3|default_if_none:\"\" }}</td>\n                                <td>{{ i.4|default_if_none:\"\" }}</td>\n                                <td>{{ i.5|default_if_none:\"\" }}</td>\n                            </tr>\n                            {% endfor %}\n                        </tbody>\n                    </table>\n                    </br>\n\n                    <h3 style=\"font-weight:bold;font-family:SimSun;color:#000;\">4 附件</h3>\n                    <h3 style=\"font-family:SimSun;color:#000;\">附件一、数据质量检核结果明细</h3>\n                    <h3\n                        style=\"font-style:italic;size:21.3px;font-family:SimSun;color:rgb(91, 155, 213);text-decoration:underline;\" />\n                    &nbsp;&nbsp;插入附件\n                    <h3 style=\"font-family:SimSun;color:#000;\">附件二、集团风险数据集市数据标准</h3>\n                    <h3\n                        style=\"font-style:italic;size:21.3px;font-family:SimSun;color:rgb(91, 155, 213);text-decoration:underline;\" />\n                    &nbsp;&nbsp;插入附件\n                </div>\n            </div>\n\n            <div class=\"col-md-2\">\n                <div class=\"card\">\n                    <a class=\"btn jquery-word-export\" href=\"javascript:void(0)\" style=\"color:#000;\">\n                        <span class=\"word-icon\" style=\"font-family:'Helvetica', sans-serif;\n                        font-size: 24px;\n                        font-weight: bold;\n                        background-color: #0054a6;\n                        color: white;\n                        padding: 2px 5px;\n                        vertical-align: middle;\">W</span>\n                        导出为.doc\n                    </a>\n                </div>\n            </div>\n            <!-- /.blog-sidebar -->\n        </div>\n    </div>\n</div>\n\n<!-- footer -->\n<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n    <div class=\"footer\">\n        © 2019 Hyhyhyhyhyhyh\n    </div>\n</footer>\n</div>\n\n\n<!-- 设置头像 / 设置日期 -->\n<script src=\"/static/js/init.js\"></script>\n</body>\n\n</html>"
  },
  {
    "path": "data/templates/data/result_detail.html",
    "content": "{% include \"data/template-ui.html\" %}\n<!-- DataTables CSS -->\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/datatables/foundation.min.css\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/datatables/dataTables.bootstrap4.min.css\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/datatables/fixedHeader.foundation.min.css\" />\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/datatables/buttons.foundation.min.css\" />\n\n<style>\n    .button-group .button {\n        font-size: 12px;\n        padding: 4px 10px;\n    }\n\n    .table-bordered thead td,\n    .table-bordered thead th {\n        border-bottom-width: 1px !important;\n    }\n\n    .container-fluid {\n        padding: 0 10 0;\n    }\n\n    table {\n        font-size: 14px;\n    }\n\n    select{\n        border: 0 none;\n        border-bottom: 1px solid;\n        appearance:none;\n        -moz-appearance:none; /* Firefox */\n        -webkit-appearance:none; /* Safari 和 Chrome */\n        padding: unset;\n        height: unset;\n        padding-left: 2%;\n        padding-right: 1%;\n        /*padding-top: 0.8rem;*/\n        margin: unset;\n    }\n    select::-ms-expand { display: none; }\n    select:focus{\n        border: 0 none;\n        border-bottom: 1px solid;\n        box-shadow: unset;\n    }\n\n    .grid-x {\n        padding-left: 30px;\n    }\n    .dataTables_wrapper {\n        padding-top: unset;\n    }\n\n    /* 超长文字单元格省略号显示 */\n    .gridtitle{\n        text-overflow: ellipsis;    /*超长部分以...代替*/\n        white-space: nowrap;/*文本不换行*/\n        max-width: 150px;/*最大宽度*/\n        overflow: hidden;/*超长部分隐藏掉*/\n　　}\n</style>\n\n<div class=\"page-wrapper\">\n    <!-- 标题 -->\n    <div class=\"row page-titles\">\n        <div class=\"col-md-4 align-self-center\">\n            <h3 class=\"text-primary\">数据质量检核报告</h3>\n        </div>\n\n        <div class=\"col-md-5 align-self-center\">\n            <div class=\"row\">\n                数据日期：\n                <select id=\"data_year\" onchange=\"GetQuarter();\" style=\"width: 60px;\"></select><span style=\"padding-right: 5px;\">年</span>\n                <span>· 第</span><select id=\"data_quarter\" onchange=\"GetMonth();\" style=\"width: 30px;\"></select><span style=\"padding-right: 5px;\">季度 ·</span>\n                <select id=\"data_month\" onchange=\"GetDay();\" style=\"width: 40px;\"></select><span style=\"padding-right: 5px;\">月</span>\n                <select id=\"data_day\" style=\"width: 40px;\"></select><span style=\"padding-right: 15px;\">日</span>\n                <button type=\"button\" class=\"btn btn-primary btn-xs p310\" onclick=\"ChangeDataDate();\" style=\"border-radius: .25rem;\"><i class=\"fa fa-search\"></i></button>\n            </div>\n        </div>\n\n        <div class=\"col-md-3 align-self-center\">\n            <ol class=\"breadcrumb\">\n                <li class=\"breadcrumb-item\"><a href=\"../../data/index\">主页</a></li>\n                <li class=\"breadcrumb-item active\">检核报告</li>\n            </ol>\n        </div>\n    </div>\n\n        <div class=\"container-fluid animated fadeInUp\">\n        <div class=\"row\">\n            <div class=\"col-lg-12\">\n                <div class=\"card\">\n                    <!-- 正文 -->\n                    <div class=\"card-content\">\n                        <table id=\"example\" class=\"table-bordered\" style=\"width:100%\">\n                            <thead>\n                                <tr>\n                                    <th>行号</th>\n                                    <th>系统</th>\n                                    <th>数据标准</th>\n                                    <th>目标表</th>\n                                    <th>是否风险集市</th>\n                                    <th>问题分类</th>\n                                    <th>报送SQL</th>\n                                    <th>报送数据量</th>\n                                    <th>问题数据量</th>\n                                    <th>问题占比</th>\n                                    <th>备注</th>\n                                </tr>\n                            </thead>\n                        </table>\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n\n<!-- footer -->\n<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n    <div class=\"footer\">\n        © 2019 Hyhyhyhyhyhyh\n    </div>\n</footer>\n</div>\n\n<!-- DataTables JS -->                    \n<script type=\"text/javascript\" src=\"https://cdn.datatables.net/1.10.20/js/jquery.dataTables.min.js\"></script>\n<script type=\"text/javascript\" src=\"https://cdn.bootcss.com/datatables/1.10.20/js/dataTables.foundation.min.js\"></script>\n<script type=\"text/javascript\" src=\"/static/js/DataTables/ColReorder-1.5.0/js/dataTables.colReorder.min.js\"></script>\n<script type=\"text/javascript\" src=\"/static/js/DataTables/Buttons-1.5.6/js/dataTables.buttons.min.js\"></script>\n<script type=\"text/javascript\" src=\"/static/js/DataTables/Buttons-1.5.6/js/buttons.foundation.min.js\"></script>\n<script type=\"text/javascript\" src=\"/static/js/DataTables/Buttons-1.5.6/js/buttons.html5.min.js\"></script>\n<script type=\"text/javascript\" src=\"/static/js/DataTables/Buttons-1.5.6/js/buttons.print.min.js\"></script>\n<script type=\"text/javascript\" src=\"/static/js/DataTables/Buttons-1.5.6/js/buttons.colVis.min.js\"></script>\n<script type=\"text/javascript\" src=\"/static/js/DataTables/JSZip-2.5.0/jszip.min.js\"></script>\n<script type=\"text/javascript\" src=\"/static/js/DataTables/pdfmake-0.1.36/pdfmake.min.js\"></script>\n<script type=\"text/javascript\" src=\"/static/js/DataTables/pdfmake-0.1.36/vfs_fonts.js\"></script>\n<script type=\"text/javascript\" src=\"/static/js/DataTables/FixedHeader-3.1.4/js/dataTables.fixedHeader.min.js\"></script>\n\n<!-- 设置头像 / 设置日期 -->\n<script src=\"/static/js/init.js\"></script>\n\n<script type=\"text/javascript\" class=\"init\">\n    $(document).ready(function () {\n        var table = $('#example').DataTable({\n            //使用ajax请求检核结果明细，填充datatables\n            \"ajax\": {\n                \"url\": \"../../api/quality/detail\",\n                \"type\": \"GET\",\n                \"async\": false,     //默认为true即异步加载接口数据，会导致buttons不显示\n                \"data\": function (d) {\n                    return $.extend({}, d, {\n                        \"company\": \"{{ company }}\",\n                        \"year\": localStorage.getItem(\"selected_year\"),\n                        \"quarter\": localStorage.getItem(\"selected_quarter\"),\n                        \"month\": localStorage.getItem(\"selected_month\"),\n                        \"day\": localStorage.getItem(\"selected_day\"),\n                    });\n                }\n            },\n\n            \"columns\": [\n                {\"data\": \"id\"},\n                {\"data\": \"source_system\"},\n                {\"data\": \"check_item\"},\n                {\"data\": \"target_table\"},\n                {\"data\": \"risk_market_item\"},\n                {\"data\": \"problem_type\"},\n                {\"data\": \"check_sql\", \"className\":\"gridtitle\",\n                    \"createdCell\": function (td, cellData, rowData, row, col) {\n                        $(td).attr('title', cellData);//设置单元格title，鼠标移上去时悬浮框展示全部内容\n                    }\n                },\n                {\"data\": \"item_count\"},\n                {\"data\": \"problem_count\"},\n                {\"data\": \"problem_per\"},\n                {\"data\": \"note\", \"className\":\"gridtitle\",\n                    \"createdCell\": function (td, cellData, rowData, row, col) {\n                        $(td).attr('title', cellData);//设置单元格title，鼠标移上去时悬浮框展示全部内容\n                    }\n                },\n            ],\n\n            \"createdRow\": function (row, data, dataIndex) {\n                //设置数据标准项浮窗\n                $('td:eq(2)', row).attr(\"data-toggle\", \"popover\");\n                $('td:eq(2)', row).attr(\"id\", data[\"check_item\"]);\n\n                //若问题占比大于0，则把表格问题占比列'td:eq(-2)'标红\n                if (data['problem_per'] != null){\n                    if (data['problem_per'].replace(/\\%/g, '') > 0) {\n                        $('td:eq(-2)', row).css('color', 'red');\n                    }\n                }\n            },\n\n            \"paging\": false,\n            \"fixedHeader\": true, // 固定表头\n            \"colReorder\": true, // 可拖动列\n            \"stateSave\": true,\n            \"buttons\": [\n                {\n                    'extend': 'excel',\n                    'text': '导出Excel',\n                    'className': 'btn btn-primary',\n                },\n                {\n                    'extend': 'colvis',\n                    'text': '隐藏列',\n                    'className': 'btn btn-primary',\n                },\n            ],\n            \"language\": {\n                \"info\": \"显示第 _START_ 至 _END_ 项结果，共 _TOTAL_ 项\",\n                \"sSearch\": \"搜索:\",\n            },\n        });\n        \n        table.buttons().container().appendTo('#example_wrapper .small-6.columns:eq(0)');\n    });\n\n    $(function() {\n        $(\"[data-toggle='popover']\").popover({\n            html : true,\n            placement: \"right\",\n            trigger: \"hover focus\",\n            container: \"body\",\n            title: \"业务定义与业务规则\",\n            delay:{show:100, hide:200},\n            content: function() {\n                var value = $(this).attr(\"id\");\n                return content(value);\n            }\n        });\n    });\n\n    //动态查询数据标准项的定义\n    function content(value) {\n        var hover_data;\n        $.ajax({\n            type : \"GET\",\n            async : false,\n            url : \"../../api/datastandard/query/detail\",\n            data: {\n                std_name: value,    //标准名\n                std_type: \"detail\"\n            },\n            dataType : \"json\",\n            success : function(result) {\n                hover_data = $(\"<form><ul>\" + \n                               \"<li><font style=\\\"font-weight:600;\\\">业务定义：</font>\"+ result.business_definition +\"</li>\" +\n                               \"<li style=\\\"padding-top:10px;\\\"><font style=\\\"font-weight:600;\\\">业务规则：</font>\" + result.business_rule + \"</form>\");\n            },\n        })\n        return hover_data;\n    }\n</script>\n\n</body>\n\n</html>"
  },
  {
    "path": "data/templates/data/template-ui.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-cmn-Hans\">\n{% load staticfiles %}\n\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,Chrome=1\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <meta name=\"description\" content=\"\">\n    <meta name=\"author\" content=\"\">\n\n    <title>数据质量管理平台</title>\n\n    <link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/static/img/favicon.ico\" />\n    <!-- Bootstraore CSS -->\n    <link rel=\"stylesheet\" href=\"/static/css/lib/bootstrap/bootstrap.min.css\" />\n    <!-- Custom CSS-->\n    <link rel=\"stylesheet\" href=\"/static/css/helper.css\" />\n    <link rel=\"stylesheet\" href=\"/static/css/style.css\" />\n\n    <!-- Jquery -->\n    <script src=\"/static/js/jquery/jquery.min.js\"></script>\n    <!-- slimscrollbar scrollbar JavaScript -->\n    <script src=\"/static/js/jquery/jquery.slimscroll.js\"></script>\n\n    <!-- Bootstrap tether Core JavaScript -->\n    <script src=\"/static/js/bootstrap/js/popper.min.js\"></script>\n    <script src=\"/static/js/bootstrap/js/bootstrap.min.js\"></script>\n    <!--Menu sidebar -->\n    <script src=\"/static/js/sidebarmenu.js\"></script>\n    <!--stickey kit -->\n    <script src=\"/static/js/sticky-kit-master/dist/sticky-kit.min.js\"></script>\n    <script src=\"/static/js/custom.min.js\"></script>\n\n    <!-- Echarts js如果放在二级模板延迟加载,会出现始化空白 -->\n    <script src=\"/static/js/Echarts/echarts.js\"></script>\n</head>\n\n<style>\n    .nav-label {\n        clear: both;\n        display: block;\n        font-family: open sans;\n        font-size: 14px;\n        font-weight: 600;\n        line-height: 20px;\n        width: 100%;\n        padding-left: 15px;\n        color: #fff;\n    }\n    .nav-label-home {\n        color: #fff;\n        clear: both;\n        display: block;\n        font-family: open sans;\n        font-size: 14px;\n        font-weight: 600;\n        line-height: 20px;\n        width: 100%;\n        padding-left: 15px;\n        padding-top: 10px;\n    }\n    hr {\n        border-color: hsla(0,0%,100%,.12);\n    }\n    .message-center {\n        height: auto !important;\n    }\n    .btn-circle {\n        padding: unset;\n        padding-top: 7px;\n    }\n    #avatar {\n        width: 40px;\n        color: #fff;\n        border-radius: 50%;\n        text-align: center;\n        font-size: 16px;\n    }\n</style>\n\n<body class=\"fix-header fix-sidebar\" onload=\"init();\">\n    <!-- 加载图 spinners.css -->\n    <div class=\"preloader\">\n        <svg class=\"circular\" viewBox=\"25 25 50 50\">\n            <circle class=\"path\" cx=\"50\" cy=\"50\" r=\"20\" fill=\"none\" stroke-width=\"2\" stroke-miterlimit=\"10\" /> </svg>\n    </div>\n\n    <div id=\"main-wrapper\">\n        <div class=\"header\">\n            <nav class=\"navbar top-navbar navbar-expand-md navbar-light\">\n                <!-- 左上角Logo -->\n                <div class=\"navbar-header\">\n                    <a class=\"navbar-brand\" href=\"../../data/dashboard/\">\n                        <span style=\"margin-left:-30px;color:#fff;\">数据质量管理平台</span>\n                    </a>\n                </div>\n\n                <!-- 顶栏 -->\n                <div class=\"navbar-collapse\" style=\"height:60px;\">\n                    <ul class=\"navbar-nav mr-auto mt-md-0\">\n                        <!-- 点击展开/隐藏侧边栏  -->\n                        <li class=\"nav-item\"> <a class=\"nav-link nav-toggler hidden-md-up text-muted  \"\n                                href=\"javascript:void(0)\"><i class=\"mdi mdi-menu\"></i></a> </li>\n                        <li class=\"nav-item m-l-10\"> <a class=\"nav-link sidebartoggler hidden-sm-down text-muted  \"\n                                href=\"javascript:void(0)\"><i class=\"ti-menu\"></i></a> </li>\n                    </ul>\n\n                    <ul class=\"navbar-nav my-lg-0\">\n                        <!-- Begin 提示 -->\n                        <li class=\"nav-item dropdown\">\n                            <a class=\"nav-link dropdown-toggle text-muted text-muted\" href=\"#\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\"> <i class=\"fa fa-bell\"></i>\n\t\t\t\t\t\t\t\t<div class=\"notify\"> <span class=\"heartbit\"></span> <span class=\"point\"></span> </div>\n\t\t\t\t\t\t\t</a>\n                            <div class=\"dropdown-menu dropdown-menu-right mailbox animated zoomIn\">\n                                <ul>\n                                    <li>\n                                        <div class=\"drop-title\">系统通知</div>\n                                    </li>\n                                    <li>\n                                        <div class=\"message-center\">\n                                            <!-- Message -->\n                                            <a href=\"#\">\n                                                <div class=\"btn btn-danger btn-circle m-r-10\"><i class=\"fa fa-commenting\"></i></div>\n                                                <div class=\"mail-contnet\">\n                                                    <span class=\"mail-desc\">截止至2019Q4，检核内容主要针对数据的规范性，尚不对数据准确性进行检核</span> <span class=\"time\">2019Q4</span>\n                                                </div>\n                                            </a>\n                                        </div>\n                                    </li>\n                                </ul>\n                            </div>\n                        </li>\n                        <!-- End 提示 -->\n\n                        <!-- Begin 用户 -->\n                        <li class=\"nav-item dropdown\">\n                            <a class=\"nav-link dropdown-toggle text-muted  \" href=\"#\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">\n                                <div id=\"avatar\"></div>\n                            <div id=\"avatar\"></div></a>\n                            <div class=\"dropdown-menu dropdown-menu-right animated zoomIn\">\n                                <ul class=\"dropdown-user\">\n                                    <li><a href=\"../../authorize/logout\"><i class=\"fa fa-power-off\"></i> 退出登录</a></li>\n                                </ul>\n                            </div>\n                        </li>\n                        <!-- End 用户 -->\n                    </ul>\n                </div>\n            </nav>\n        </div>\n\n        <!-- 侧边栏 -->\n        <div class=\"left-sidebar\">\n            <div class=\"scroll-sidebar\">\n                <nav class=\"sidebar-nav\">\n                    <ul id=\"sidebarnav\">\n                        <li class=\"nav-label\">质量管理</li>\n                        <li>\n                            <a class=\"has-arrow\" href=\"#\" aria-expanded=\"false\">\n                                <i class=\"fa fa-bar-chart-o\"></i>\n                                <span class=\"hide-menu\">仪表盘<span class=\"label label-rouded label-info pull-right\">8</span>\n                            </a>\n                            <ul aria-expanded=\"false\" class=\"collapse\">\n                                <li><a href=\"../../data/dashboard\">集团 </a></li>\n                                <li><a href=\"../../data/dashboard/subcompany?company=xt&company_zh=信托\">信托 </a></li>\n                                <li><a href=\"../../data/dashboard/subcompany?company=zc&company_zh=资产\">资产 </a></li>\n                                <li><a href=\"../../data/dashboard/subcompany?company=db&company_zh=担保\">担保 </a></li>\n                                <li><a href=\"../../data/dashboard/subcompany?company=jk&company_zh=金科\">金科 </a></li>\n                                <li><a href=\"../../data/dashboard/subcompany?company=jj1&company_zh=基金1\">基金1 </a></li>\n                                <li><a href=\"../../data/dashboard/subcompany?company=jj2&company_zh=基金2\">基金2 </a></li>\n                                <li><a href=\"../../data/dashboard/subcompany?company=jz&company_zh=金租\">金租 </a></li>\n                            </ul>\n                        </li>\n                        \n                        <li>\n                            <a class=\"has-arrow\" href=\"#\" aria-expanded=\"false\">\n                            <i class=\"fa fa-table\"></i>\n                            <span class=\"hide-menu\">检核结果明细<span class=\"label label-rouded label-danger pull-right\">7</span>\n                            </a>\n                            <ul aria-expanded=\"false\" class=\"collapse\">\n                                <li><a href=\"../../data/result_detail?company=xt\">信托 </a></li>\n                                <li><a href=\"../../data/result_detail?company=zc\">资产 </a></li>\n                                <li><a href=\"../../data/result_detail?company=db\">担保 </a></li>\n                                <li><a href=\"../../data/result_detail?company=jk\">金科 </a></li>\n                                <li><a href=\"../../data/result_detail?company=jj1\">基金2 </a></li>\n                                <li><a href=\"../../data/result_detail?company=jj2\">基金1 </a></li>\n                                <li><a href=\"../../data/result_detail?company=jz\">金租 </a></li>\n                            </ul>\n                        </li>\n                        <hr></hr>\n\n                        <!-- 标准管理 -->\n                        <li class=\"nav-label\">标准管理</li>\n                        <li>\n                            <a class=\"has-arrow\" href=\"../../datastandard/show\" aria-expanded=\"false\">\n                                <i class=\"fa fa-check-square-o\"></i>\n                                <span class=\"hide-menu\">数据标准</span>\n                            </a>\n                        </li>\n\n                        <li>\n                            <a class=\"has-arrow\" href=\"#\" aria-expanded=\"false\">\n                                <i class=\"fa\">\n                                    <img src=\"/static/icons/db-icons/sql.svg\" style=\"width: 27px;margin-left: -5px;\" />\n                                </i>\n                                <span class=\"hide-menu\">检核规则库<span class=\"label label-rouded label-warning pull-right\">7</span>\n                            </a>\n                            <ul aria-expanded=\"false\" class=\"collapse\">\n                                <li><a href=\"../../check/rule?company=xt&risk_market=\"> 信托 </a></li>\n                                <li><a href=\"../../check/rule?company=zc&risk_market=\"> 资产 </a></li>\n                                <li><a href=\"../../check/rule?company=db&risk_market=\">担保 </a></li>\n                                <li><a href=\"../../check/rule?company=jk&risk_market=\"> 金科 </a></li>\n                                <li><a href=\"../../check/rule?company=jj12&risk_market=\"> 基金2 </a></li>\n                                <li><a href=\"../../check/rule?company=jj21&risk_market=\"> 基金1 </a></li>\n                                <li><a href=\"../../check/rule?company=jz&risk_market=\"> 金租 </a></li>\n                            </ul>\n                        </li>\n\n                        <li> <a class=\"has-arrow\" href=\"../../blood/analyze\" aria-expanded=\"false\"><i class=\"fa fa-sitemap\"></i>\n                            <span class=\"hide-menu\">血缘分析</span>\n                            </a>\n                        </li>\n                        <hr></hr>\n                        \n                        <!-- 知识管理 -->\n                        <li class=\"nav-label\">知识管理</li>\n                        <li>\n                            <a class=\"has-arrow\" href=\"../../files/list\" aria-expanded=\"false\"><i class=\"fa fa-book\"></i>\n                            <span class=\"hide-menu\">数据治理知识库</span>\n                            </a>\n                        </li>\n                        <hr></hr>\n\n                        <!-- 后台管理 -->\n                        <li class=\"nav-label\">后台管理</li>\n                        <li>\n                            <a class=\"has-arrow\" href=\"../../backend/database\" aria-expanded=\"false\">\n                                <i class=\"fa fa-database\" style=\"width: 27px;\"></i>\n                                <span class=\"hide-menu\">数据源</span>\n                            </a>\n                        </li>\n\n                        <li>\n                            <a class=\"has-arrow\" href=\"#\" aria-expanded=\"false\">\n                                <i class=\"fa fa-tv\"></i>\n                                <span class=\"hide-menu\">任务调度<span class=\"label label-purple label-rouded pull-right\">2</span>\n                            </a>\n                            <ul aria-expanded=\"false\" class=\"collapse\">\n                                <li><a href=\"../../check/crontab\"> 检核任务 </a></li>\n                                <li><a href=\"../../backend/crontab\"> 后台任务 </a></li>\n                            </ul>\n                        </li>\n\n                        <li>\n                            <a class=\"has-arrow\" href=\"../../data/report\" aria-expanded=\"false\">\n                                <i class=\"fa fa-file-text\" style=\"width: 27px;\"></i>\n                                <span class=\"hide-menu\">生成Word报告模板</span>\n                            </a>\n                        </li>\n                        \n                        <li>\n                            <a class=\"has-arrow\" href=\"../../demand/import_sheet\" target=\"_blank\" aria-expanded=\"false\">\n                                <i class=\"fa fa-tags\" style=\"width: 27px;\"></i>\n                                <span class=\"hide-menu\">更新源系统改造需求进度表</span>\n                            </a>\n                        </li>\n                    </ul>\n                </nav>\n            </div>\n        </div>"
  },
  {
    "path": "data/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "data/urls.py",
    "content": "from django.urls import path\n\nfrom . import views\nfrom . import dashboard_charts\n\napp_name = 'data'\nurlpatterns = [\n    path('', views.index, name='index'),\n    path('index', views.index, name='index'),\n    path('dashboard', views.dashboard, name='dashboard'),\n    path('report', views.report, name='report'),\n    path('result_detail', views.result_detail, name='result_detail'),\n]\n"
  },
  {
    "path": "data/views.py",
    "content": "from django.shortcuts import render\n\nfrom utils.functions import is_login\nfrom utils import functions as f\n\n\n@is_login\ndef dashboard(request):\n    \"\"\"集团仪表盘\n    说明：本模块分3部分在前端展示\n    1. 第一行为3个数据概览统计\n    2. 第二行统计各个公司数据质量问题概况\n    3. 第三行使用pyecharts做的数据统计图\n    \"\"\"\n    return render(request, \"data/dashboard.html\", {\"username\": request.session['username']})\n\n\n@is_login\ndef dashboard_subcompany(request):\n    \"\"\"子公司仪表盘\n    说明：本模块分3部分在前端展示\n    1. 子公司问题数据项的分布\n    2. 子公司问题数据项的排序报表\n    3. 改造进度\n    \"\"\"\n    company = request.GET.get('company')\n    company_zh = request.GET.get('company')\n    return render(request, \"data/dashboard_subcompany.html\", {\"company\": company,\n                                                              \"company_zh\": company_zh,\n                                                              })\n\n\n@is_login\ndef result_detail(request):\n    \"\"\"\n    检核结果Excel明细\n    :param request:\n    :return:\n    \"\"\"\n    return render(request, \"data/result_detail.html\", {\"company\": request.GET.get('company')})\n\n\n@is_login\ndef report(request):\n    \"\"\"\n    检核报告Word\n    :param request:\n    :return:\n    \"\"\"\n    return render(request, \"data/report.html\")"
  },
  {
    "path": "demand/__init__.py",
    "content": ""
  },
  {
    "path": "demand/admin.py",
    "content": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "demand/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass DemandConfig(AppConfig):\n    name = 'demand'\n"
  },
  {
    "path": "demand/insert_excel.sql",
    "content": "insert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(1,'信托','风险等级','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(2,'信托','净资本类别','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(3,'信托','风险资本类别','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(4,'信托','参与人角色','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(5,'信托','所有制类型','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(6,'信托','参与人规模','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(7,'信托','参与人角色标识','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(8,'信托','产品收益率','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(9,'信托','参与人上市标识','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(10,'信托','项目投向行业','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(11,'信托','项目名称','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(12,'信托','项目来源','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(13,'信托','存续标识','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(1,'资产','逾期天数','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(2,'资产','续封续冻资产所在市','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(3,'资产','担保方式','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(4,'资产','收购方式','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(5,'资产','续封续冻资产所在县','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(6,'资产','项目五级分类','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(7,'资产','续封续冻资产所在省','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(8,'资产','资产金额','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(9,'资产','参与人行业','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(10,'资产','交易本金金额','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(11,'资产','到期日期','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(12,'资产','账面金额','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(13,'资产','资产处置合同金额','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(14,'资产','项目余额','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(15,'资产','项目金额','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(16,'资产','参与人市','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(17,'资产','收益率','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(18,'资产','项目收益','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(19,'资产','项目类别','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(20,'资产','开始日期','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(1,'再担保','五级分类','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(2,'再担保','参与人五级分类','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(3,'再担保','参与人县','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(4,'再担保','参与人行业','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(5,'再担保','收益率','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(6,'再担保','所有制类型','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(7,'再担保','机构证件号码','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(8,'再担保','机构证件类别','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(9,'再担保','项目收益','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(10,'再担保','参与人抵质押物估值','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(11,'再担保','参与人市','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(12,'再担保','参与人省份','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(13,'再担保','担保责任比例','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(14,'再担保','到期日期','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(15,'再担保','开始日期','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(16,'再担保','参与人规模','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(17,'再担保','项目名称','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(18,'再担保','项目余额','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(19,'再担保','项目金额','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(20,'再担保','项目编号','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(1,'中银粤财','参与人省份','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(2,'中银粤财','参与人市','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(3,'中银粤财','项目余额','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(4,'中银粤财','收益率','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(5,'中银粤财','项目资金用途','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(6,'中银粤财','项目金额','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(7,'中银粤财','项目名称','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(8,'中银粤财','管理费率','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(9,'中银粤财','交易本金金额','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(10,'中银粤财','项目类别','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(11,'中银粤财','约定退出方式','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(12,'中银粤财','项目投向行业（展业指引）','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(13,'中银粤财','到期日期','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(14,'中银粤财','约定退出日期','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(15,'中银粤财','项目管理方式','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(16,'中银粤财','我方管理角色','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(17,'中银粤财','基金资金来源','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(18,'中银粤财','投资轮次','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(19,'中银粤财','参与人角色标识','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(1,'基金创投','项目金额','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(2,'基金创投','约定退出日期','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(3,'基金创投','约定退出方式','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(4,'基金创投','管理费率','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(5,'基金创投','参与人市','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(6,'基金创投','参与人省份','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(7,'基金创投','交易分红金额','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(8,'基金创投','交易本金金额','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(9,'基金创投','项目类别','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(10,'基金创投','我方管理角色','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(11,'基金创投','项目余额','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(12,'基金创投','到期日期','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(13,'基金创投','项目管理方式','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(14,'基金创投','风险等级','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(15,'基金创投','项目投向行业（展业指引）','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(16,'基金创投','风险项目简述','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(17,'基金创投','项目资金用途','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(18,'基金创投','基金创投业务类型','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(19,'基金创投','收益率','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(20,'基金创投','投资轮次','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(21,'基金创投','参与人角色标识','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(22,'基金创投','交易类型','补创建数据项','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(1,'金租','项目五级分类','设为必填','201905','2019Q1','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(2,'金租','收益率','设为必填','201905','2019Q1','进行中');\n\n\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(1,'信托','风险等级','补创建数据项','201905','2019Q2','未开展');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(2,'信托','净资本类别','补创建数据项','201905','2019Q2','未开展');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(3,'信托','风险资本类别','补创建数据项','201905','2019Q2','未开展');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(4,'信托','参与人角色','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(5,'信托','所有制类型','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(6,'信托','参与人规模','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(7,'信托','参与人角色标识','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(8,'信托','产品收益率','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(9,'信托','参与人上市标识','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(10,'信托','项目投向行业','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(11,'信托','项目名称','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(12,'信托','项目来源','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(13,'信托','存续标识','设为必填','201905','2019Q2','业务系统自动填写，不是业务人员填写');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(1,'资产','逾期天数','补创建数据项','201905','2019Q2','进行中');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(2,'资产','续封续冻资产所在市','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(3,'资产','担保方式','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(4,'资产','收购方式','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(5,'资产','续封续冻资产所在县','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(6,'资产','项目五级分类','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(7,'资产','续封续冻资产所在省','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(8,'资产','资产金额','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(9,'资产','参与人行业','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(10,'资产','交易本金金额','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(11,'资产','到期日期','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(12,'资产','账面金额','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(13,'资产','资产处置合同金额','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(14,'资产','项目余额','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(15,'资产','项目金额','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(16,'资产','参与人市','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(17,'资产','收益率','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(18,'资产','项目收益','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(19,'资产','项目类别','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(20,'资产','开始日期','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(1,'再担保','五级分类','设为必填','201905','2019Q2','业务上季后审查回填，不是实时必填项');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(2,'再担保','参与人五级分类','设为必填','201905','2019Q2','业务上季后审查回填，不是实时必填项');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(3,'再担保','参与人县','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(4,'再担保','参与人行业','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(5,'再担保','收益率','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(6,'再担保','所有制类型','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(7,'再担保','机构证件号码','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(8,'再担保','机构证件类别','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(9,'再担保','项目收益','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(10,'再担保','参与人抵质押物估值','设为必填','201905','2019Q2','在有抵押物的业务场景中才要求必填');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(11,'再担保','参与人市','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(12,'再担保','参与人省份','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(13,'再担保','担保责任比例','设为必填','201905','2019Q2','在有合作渠道的业务场景中才要求必填');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(14,'再担保','到期日期','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(15,'再担保','开始日期','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(16,'再担保','参与人规模','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(17,'再担保','项目名称','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(18,'再担保','项目余额','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(19,'再担保','项目金额','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(20,'再担保','项目编号','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(1,'中银粤财','参与人省份','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(2,'中银粤财','参与人市','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(3,'中银粤财','项目余额','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(4,'中银粤财','收益率','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(5,'中银粤财','项目资金用途','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(6,'中银粤财','项目金额','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(7,'中银粤财','项目名称','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(8,'中银粤财','管理费率','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(9,'中银粤财','交易本金金额','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(10,'中银粤财','项目类别','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(11,'中银粤财','约定退出方式','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(12,'中银粤财','项目投向行业（展业指引）','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(13,'中银粤财','到期日期','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(14,'中银粤财','约定退出日期','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(15,'中银粤财','项目管理方式','补创建数据项','201905','2019Q2','未完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(16,'中银粤财','我方管理角色','补创建数据项','201905','2019Q2','未完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(17,'中银粤财','基金资金来源','补创建数据项','201905','2019Q2','未完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(18,'中银粤财','投资轮次','补创建数据项','201905','2019Q2','未完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(19,'中银粤财','参与人角色标识','补创建数据项','201905','2019Q2','未完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(1,'基金创投','项目金额','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(2,'基金创投','约定退出日期','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(3,'基金创投','约定退出方式','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(4,'基金创投','管理费率','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(5,'基金创投','参与人市','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(6,'基金创投','参与人省份','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(7,'基金创投','交易分红金额','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(8,'基金创投','交易本金金额','设为必填','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(9,'基金创投','项目类别','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(10,'基金创投','我方管理角色','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(11,'基金创投','项目余额','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(12,'基金创投','到期日期','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(13,'基金创投','项目管理方式','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(14,'基金创投','风险等级','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(15,'基金创投','项目投向行业（展业指引）','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(16,'基金创投','风险项目简述','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(17,'基金创投','项目资金用途','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(18,'基金创投','基金创投业务类型','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(19,'基金创投','收益率','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(20,'基金创投','投资轮次','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(21,'基金创投','参与人角色标识','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(22,'基金创投','交易类型','补创建数据项','201905','2019Q2','完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(1,'金租','项目五级分类','设为必填','201905','2019Q2','未完成');\ninsert into source_system_demand(id,company,item_name,demand_name,demand_created,quarter,status) values(2,'金租','收益率','设为必填','201905','2019Q2','未完成');"
  },
  {
    "path": "demand/models.py",
    "content": "from django.db import models\n\n# Create your models here.\n"
  },
  {
    "path": "demand/templates/demand/upload_form.html",
    "content": "<html>\n<head>\n    <title>数据质量检核平台</title>\n</head>\n<body>\n    <h5>上传源系统改造进度Excel表</h5>\n\n    {% if form.errors %}\n        <p style=\"color: red;\">\n            上传过程发生错误：{{ form.errors|pluralize }}\n        </p>\n    {% endif %}\n\n    <form action=\"\" enctype=\"multipart/form-data\"  method=\"post\">\n        <table>\n            {{ form.as_table }}\n        </table>\n        {% csrf_token %}\n        <input type=\"submit\" value=\"Submit\">\n    </form>\n</body>\n</html>\n"
  },
  {
    "path": "demand/tests.py",
    "content": "from django.test import TestCase\nimport requests\n\nurl = \"http://localhost:8000/api/demand_list\"\nresponse = requests.get(url=url,params={'company':'信托'})\n\n\nurl = \"http://localhost:8000/api/demand_list\"\nresponse = requests.get(url=url,params={'company':'信托'})"
  },
  {
    "path": "demand/views.py",
    "content": "import json\nimport sys\n\nfrom django import forms\nfrom django.http import HttpResponse, HttpResponseBadRequest\nfrom django.http.response import JsonResponse\nfrom django.shortcuts import render\n\n# import django_excel as excel\nsys.path.insert(0, '..')\nfrom mysite import db_config\n\n\ndef list_subcompany(request):\n    company = request.GET.get('company')\n    conn = db_config.mysql_connect()\n    curs = conn.cursor()\n\n    try:\n        sql = f\"\"\"select rownum,\n                        company,\n                        item_name,\n                        demand_name,\n                        demand_created,\n                        group_concat(quarter,status order by quarter asc separator'|')\n                    from source_system_demand\n                    where id in ( select max(id) from source_system_demand where company='{company}' group by company,item_name,quarter )\n                    group by rownum,company\"\"\"\n        curs.execute(sql)\n        result = curs.fetchall()\n\n        result_list = []\n        for i in result:\n            result_list_tmp = [i[0], i[1], i[2], i[3], i[4]]\n            for t in i[5].split('|'):\n                result_list_tmp.append(t)\n            result_list.append(result_list_tmp)\n        return JsonResponse(result_list, safe=False)\n    except:\n        return HttpResponse('error', status=500)\n    finally:\n        curs.close()\n        conn.close()\n\n\nclass UploadFileForm(forms.Form):\n    file = forms.FileField()\n\n\ndef import_sheet(request):\n    if request.method == \"POST\":\n        form = UploadFileForm(request.POST, request.FILES)\n        if form.is_valid():\n            excel_data = request.FILES['file'].get_array()\n            excel_data = json.dumps(excel_data)\n            with open('static/resource/demand.json', 'w') as file:\n                file.write(excel_data)\n            return HttpResponse(\"Excel处理成功，请返回首页查看数据\")\n        else:\n            return HttpResponseBadRequest()\n    else:\n        form = UploadFileForm()\n        return render(request, 'demand/upload_form.html', {'form': form})\n"
  },
  {
    "path": "docs/api_views.md",
    "content": "# 后端API接口说明\n> 部分echarts获取展示的数据是通过请求后端的api接口获取，而不是由Django模板渲染而来，方便代码复用\n\n---\n\n## download\n- URL：http://100.100.0.177/api/files/download\n- 功能：下载服务器上的文件\n- 请求类型：GET\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nfilename | 必须 | 附件文件名\n\n- 请求示例：http://100.100.0.177/api/files/download?filename=基金创投公司风险指标.xlsx\n- 返回值：无\n\n## avg_problem_percentage\n- URL：http://100.100.0.177/api/dashboard/avg_problem_percentage\n- 功能：获取所有季度的各公司平均问题占比\n- 请求类型：GET\n- 请求参数：无\n- 返回值：\n```\n[\n\t[\"quarter\", \"2019Q1\", \"2019Q2\", \"2019Q3\", \"2019Q4\"],\n\t[\"粤财信托\", \"4.55\", \"1.35\", \"0.00\", \"0.00\"],\n\t[\"粤财资产\", \"4.38\", \"4.34\", \"0.00\", \"0.00\"],\n\t[\"广东再担保\", \"14.40\", \"14.02\", \"0.00\", \"0.00\"],\n\t[\"粤财金科\", \"0.00\", \"0.00\", \"0.00\", \"0.00\"],\n\t[\"基金创投\", \"86.14\", \"77.15\", \"0.00\", \"0.00\"],\n\t[\"中银粤财\", \"73.70\", \"32.37\", \"0.00\", \"0.00\"],\n\t[\"金租\", \"5.98\", \"13.76\", \"13.72\", \"13.72\"]\n]\n```\n\n---\n\n## same_problem_top5\n- URL：http://100.100.0.177/api/dashboard/same_problem_top5\n- 功能：获取指定季度的各公司同类问题Top 5统计\n- 请求类型：GET\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nquarter | 必须 | 指定季度获取数据\n\n- 返回值：\n```\n{\n\t\"name\": [\"交易本金金额\", \"机构证件号码\", \"机构证件类别\", \"项目名称\", \"其他\"],\n\t\"value\": [\"6.84\", \"49.28\", \"48.84\", \"4.34\", 224.8]\n}\n```\n\n---\n\n## subcompany_data_percentage\n- URL：http://100.100.0.177/api/dashboard/subcompany_data_percentage\n- 功能：获取指定季度的各公司数据量占比\n- 请求类型：GET\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nquarter | 必须 | 指定季度获取数据\n\n- 返回值：\n```\n[{\n\t\"name\": \"粤财信托\",\n\t\"value\": \"6195905\"\n}, {\n\t\"name\": \"粤财资产\",\n\t\"value\": \"72575\"\n}, {\n\t\"name\": \"广东再担保\",\n\t\"value\": \"11892\"\n}, {\n\t\"name\": \"粤财金科\",\n\t\"value\": \"33792215\"\n}, {\n\t\"name\": \"基金创投\",\n\t\"value\": \"397\"\n}, {\n\t\"name\": \"中银粤财\",\n\t\"value\": \"945\"\n}, {\n\t\"name\": \"金租\",\n\t\"value\": \"67\"\n}]\n```\n---\n## count_db_rows\n- URL：http://100.100.0.177/api/dashboard/count_db_rows\n- 功能：获取指定季度的统计各类数据库数据量\n- 请求类型：GET\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nquarter | 必须 | 指定季度获取数据\n\n- 返回值：\n```\n[{\n\t\"name\": \"MySQL\",\n\t\"value\": \"33804107\",\n\t\"selected\": \"true\"\n}, {\n\t\"name\": \"Oracle\",\n\t\"value\": \"72642\"\n}, {\n\t\"name\": \"SQL server\",\n\t\"value\": \"1333\"\n}]\n```\n---\n\n## data_overiew\n- URL：http://100.100.0.177/api/dashboard/data_overiew\n- 功能：获取指定季度的统计风险集市相关 总数据量、总问题数据量、总问题占比\n- 请求类型：GET\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nquarter | 必须 | 指定季度获取数据\n\n- 返回值：\n```\n{\n\t\"all_cnt\": \"205952332\",\n\t\"problem_cnt\": \"1423787\",\n\t\"problem_per\": \"0.69\"\n}\n```\n\n---\n\n## total_trend\n- URL：http://100.100.0.177/api/dashboard/total_trend\n- 功能：获取所有季度的显示集团总问题占比走势\n- 请求类型：GET\n- 请求参数：无\n- 返回值：\n```\n{\n\t\"quarter\": [\"2019Q1\", \"2019Q2\", \"2019Q3\", \"2019Q4\"],\n\t\"value\": [\"0.69\", \"0.88\", \"0.00\", \"0.00\"]\n}\n```"
  },
  {
    "path": "docs/authorize_views.md",
    "content": "# 身份验证接口\n\n## login\n- URL：http://100.100.0.177/authorize/login\n\n- 功能：登录表单，用户输入账号名密码\n- 请求类型：GET\n- 请求参数：无\n- 返回值：无\n\n---\n\n## login_auth\n- URL：http://100.100.0.177/authorize/login_auth\n\n- 功能：连接LDAP，验证login页面表单post传递的用户名密码\n- 请求类型：POST / GET\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nusername | 必须 | OA账号名\npassword | 必须 | OA账号密码\n\n- 返回值：验证成功自动重定向到主页，并在服务端记录session；否则返回报错信息（用户名/密码输入错误）\n\n---\n\n## logout\n- URL：http://100.100.0.177/authorize/logout\n\n- 功能：清除用户对应的session，重定向到登录login页\n- 请求类型：GET\n- 请求参数：无\n- 返回值：无"
  },
  {
    "path": "docs/check_views.md",
    "content": "# 自动检核说明\n\n## rule_list\n- URL：http://100.100.0.177/check/login\n- 功能：检核规则库，`规则列表的内容由ajax调用check/rule_detail获取`\n- 请求类型：GET\n- 请求参数：无\n- 返回值：无\n\n---\n\n## rule_status_modify\n- URL：http://100.100.0.177/check/rule_status_modify\n- 功能：启用或禁用单条检核规则\n- 请求类型：POST\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nid          | 必须 | 前端显示的行号\npost_status | 必须 | 传入值为`已启用`时，禁用该条规则；传入值为`已禁用`时，启用该条规则\ncompany     | 必须 | 检核规则所属的公司中文简写\n\n\n- 返回值：无\n\n---\n\n## rule_config\n- URL：http://100.100.0.177/check/rule_config\n- 功能：查看检核规则详情\n- 请求类型：GET\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nid          | 必须 | 前端显示的行号\npost_status | 必须 | 传入值为`已启用`时，禁用该条规则；传入值为`已禁用`时，启用该条规则\ncompany     | 必须 | 检核规则所属的公司中文简写\nusername    | 必须 | 验证修改者身份，OASSO账号无提交按钮\n\n- 返回值：无\n\n---\n\n## rule_exec\n- URL：http://100.100.0.177/check/rule_exec\n- 功能：查看当前的手工触发的检核进度\n- 请求类型：GET\n- 请求参数：无\n- 返回值：无\n\n---\n\n## rule_detail\n- URL：http://100.100.0.177/check/rule_detail\n- 功能：获取检核规则内容\n- 请求类型：GET\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nname               | 必须 | 子公司简写，与Excel中的系统名一致\nrisk_market_filter | 必须 | 接受传入的值为`是`或`否`或空\n- 示例：http://100.100.0.177/check/rule_detail?name=信托&risk_market_filter=\n\n- 返回值：\n```\n{\n\t\"data\": [{\n\t\t\"id\": 1,\n\t\t\"check_item\": \"项目编号\",\n\t\t\"target_table\": \"项目基本信息\",\n\t\t\"risk_market_item\": \"是\",\n\t\t\"problem_type\": \"空值检核\",\n\t\t\"db\": \"sqlserver\",\n\t\t\"check_sql\": \"select count(distinct vc_stock_code),\\n       count(CASE\\n               WHEN vc_stock_code IS NULL or vc_stock_code = '' THEN\\n                1\\n             END)\\n  from (select t.vc_stock_code,\\n               t.vc_contract_no,\\n               t.en_contract_balance,\\n               t.vc_invest_use,\\n               t.l_begin_date,\\n               t.l_end_date\\n               \\n          from hswinrun2.dbo.stockcodesex t\\n         where t.l_end_date >= '20180101'and t.l_end_date < '20990101'\\n        union all\\n        select t.vc_stock_code,\\n               t.vc_contract_no,\\n               t.en_contract_balance,\\n               t.vc_invest_use,\\n               t.l_begin_date,\\n               t.l_end_date\\n          from hswinrun2_xedk.dbo.stockcodesex t\\n         where t.l_end_date >= '20180101'and t.l_end_date < '20990101') a\",\n\t\t\"note\": \"\",\n\t\t\"status\": \"已启用\",\n\t\t\"source_system\": \"信托\"\n\t}]\n}\n```\n\n---\n\n## rule_update\n- URL：http://100.100.0.177/check/rule_update\n- 功能：提交对检核规则的修改\n- 请求类型：POST\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nid            | 必须 | 规则对应的行号\nsource_system | 必须 | 规则所属的子公司中文简写\ncheck_item    | 必须 | 要修改为的`数据标准`名\ntarget_table  | 必须 | 要修改为的`目标表`名\nrisk_market   | 必须 | `是否风险集市所需指标`，接受的参数为`是`/`否`\nproblem_type  | 必须 | 要修改为的`问题分类`\ndb            | 必须 | 要修改为的`源系统数据库`类型\ncheck_sql     | 必须 | 要修改为的`检核逻辑`\nnote          | 必须 | 要修改为的`备注`\nstatus        | 必须 | 要修改为的`规则启用状态`，接受的参数为`已启用`/`已停用`；传入`已启用`会把规则状态置为启用，传入`已停用`会把规则状态置为禁用\n\n- 返回值：\n```\n修改成功返回'success'，http状态码200；发生异常则状态码为500\n```\n\n---\n\n## rule_add\n- URL：http://100.100.0.177/check/rule_add\n- 功能：提交对检核规则的新增\n- 请求类型：POST\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nsource_system | 必须 | 规则所属的子公司中文简写\ncheck_item    | 必须 | 要新增的`数据标准`名\ntarget_table  | 必须 | 要新增的`目标表`名\nrisk_market   | 必须 | `是否风险集市所需指标`，接受的参数为`是`/`否`\nproblem_type  | 必须 | 要新增的`问题分类`\ndb            | 必须 | 要新增的`源系统数据库`类型\ncheck_sql     | 必须 | 要新增的`检核逻辑`\nnote          | 必须 | 要新增的`备注`\nstatus        | 必须 | 要新增的`规则启用状态`，接受的参数为`已启用`/`已停用`；传入`已启用`会把规则状态置为启用，传入`已停用`会把规则状态置为禁用\n\n- 返回值：\n```\n新增成功返回'success'，http状态码200；发生异常则状态码为500\n```\n\n---\n\n## rule_execute\n- URL：http://100.100.0.177/check/rule_execute\n- 功能：提交对检核规则的新增\n- 请求类型：POST\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\ncompany  | 必须 | 执行检核的公司，接受的参数为`ycxt`/`yczc`/`gdzdb`/`ycjk`/`fdct`/`zyyc`/`jz`\nusername | 必须 | 执行检核的用户名，用于记录日志\nquarter  | 必须 | 检核结果将会落在该季度的表中\n\n- 返回值：\n```\n{\n\t\"status\": \"success\",\n\t\"msg\": \"XX公司检核成功！\"\n}\n```"
  },
  {
    "path": "docs/data_views.md",
    "content": "# 数据质量仪表盘接口\n\n## index\n- URL：http://100.100.0.177/data/index\n\n- 功能：重定向到http://100.100.0.177/data/dashboard\n- 请求类型：GET\n- 请求参数：无\n- 返回值：无\n\n---\n\n## dashboard\n- URL：http://100.100.0.177/data/dashboard\n\n页面内容：\n1. 集团数据质量总览：检核数据总量、问题数据总量总问题占比\n    - `ajax请求api/data_overiew`\n2. 选定季度的数据质量问题概况，7家子公司明细\n    - `ajax请求api/avg_problem_percentage`\n3. 所有季度的各公司平均问题占比，柱状图\n4. 所有季度的集团总问题占比，折线图\n    - `ajax请求api/total_trend`\n5. 选定季度的需求改造进度统计，柱状图\n    - `ajax请求api/demand/list_subcompany`\n6. 选定季度的需求改造进度统计，表格\n    - `ajax请求api/demand/list_subcompany`\n7. 选定季度的各公司数据量占比，环状图\n    - `ajax请求api/subcompany_data_percentage获取各公司数据量`\n    - `ajax请求api/count_db_rows获取各类型数据库数据量`\n8. 各公司同类问题Top 5统计，饼图\n    - `ajax请求api/same_problem_top5`\n9. 风险集市指标统计，图片\n    - `手工置换/data/data-quality/static/resource/风险集市指标统计.png`\n\n- 请求类型：GET\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nquarter | 非必须 | 选择显示的季度，不传入则显示上一季度的数据\n\n- 返回值：无\n\n--- \n\n## dashboard_subcompany\n- URL：http://100.100.0.177/data/dashboard_subcompany\n\n页面内容：\n1. 选定季度的子公司问题数据项统计，柱状图及列表\n    - `ajax调用data/subcompany_problem_count`\\\n2. 子公司源系统改造情况\n    - `ajax请求api/demand/list_subcompany`\n3. 子公司风险指标，图片及下载excel\n    - `图片手工置换服务器/data/data-quality/static/resource/XX公司风险指标.png`\n    - `ajax请求api/files/download下载对应公司的指标Excel表`\n\n- 请求类型：GET\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nname    | 必须   | 子公司简写\ncompany | 必须   | 子公司中文简写\nquarter | 非必须 | 选择显示的季度，不传入则显示上一季度的数据\n\n- 返回值：无\n\n--- \n\n## result_detail\n- URL：http://100.100.0.177/data/result_detail\n- 页面内容：选定季度的数据质量检核报告Excel结果\n- 请求类型：GET\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nname    | 必须   | 子公司简写\nquarter | 非必须 | 选择显示的季度，不传入则显示上一季度的数据\n- 返回值：无\n\n--- \n\n## report\n- URL：http://100.100.0.177/data/report\n- 页面内容：选定季度的数据质量检核报告Word结果，结果还需要人工加工\n- 请求类型：GET\n- 请求参数：\n\n参数 | 是否必须 | 说明\n-|-|-\nquarter | 非必须 | 选择显示的季度，不传入则显示上一季度的数据\n- 返回值：无\n"
  },
  {
    "path": "docs/ddl.sql",
    "content": "-- DDL\nCREATE DATABASE `data_quality` /*!40100 DEFAULT CHARACTER SET utf8 */ ;\n\n\n-- 程序账号\ncreate user system@'127.0.0.1' identified by 'H5cT7yHB8_';\ngrant all PRIVILEGES on data_quality.* to 'system'@'127.0.0.1';\nflush privileges;\n\nuse data_quality;\n\n-- 检核规则库，作为每个新次检核的模板表\nCREATE TABLE `check_result_template` (\n  `id` int(11) NOT NULL COMMENT '排序用id',\n  `company` varchar(100) DEFAULT NULL COMMENT '二级公司名或系统名(拼音)',\n  `source_system` varchar(10) NOT NULL COMMENT '二级公司名或系统名(中文)',\n  `check_item` varchar(100) DEFAULT NULL COMMENT '数据标准',\n  `target_table` varchar(100) DEFAULT NULL COMMENT '目标表',\n  `risk_market_item` varchar(2) DEFAULT NULL COMMENT '是否风险集市需要的指标',\n  `problem_type` varchar(100) DEFAULT NULL COMMENT '问题分类',\n  `check_sql` varchar(4000) DEFAULT NULL COMMENT '报送SQL',\n  `problem_id` varchar(4000) DEFAULT NULL COMMENT '问题数据对应主键编号',\n  `item_count` int(11) DEFAULT NULL COMMENT '报送数据量',\n  `problem_count` int(11) DEFAULT NULL COMMENT '问题数据量',\n  `problem_per` decimal(10,2) DEFAULT NULL,\n  `db` varchar(30) DEFAULT NULL,\n  `note` varchar(4000) DEFAULT NULL,\n  `status` varchar(10) DEFAULT NULL,\n  `update_flag` varchar(2) DEFAULT 'N',\n  `check_date` timestamp NULL DEFAULT NULL,\n  `check_version` int(11) DEFAULT NULL,\n  PRIMARY KEY (`id`,`source_system`)\n);\n\n\n-- 记录检核操作的日志表\nCREATE TABLE `check_execute_log` (\n  `id` int(11) NOT NULL AUTO_INCREMENT,\n  `company` varchar(30) NOT NULL,\n  `execute_date` timestamp NOT NULL,\n  `execute_user` varchar(30) NOT NULL,\n  `db` varchar(100) DEFAULT NULL,\n  `status` varchar(400) NOT NULL,\n  PRIMARY KEY (`id`)\n) ;\n\n\n-- 源系统改造需求管理表\nCREATE TABLE `source_system_demand` (\n  `id` int(11) DEFAULT NULL,\n  `company` varchar(10) DEFAULT NULL,\n  `item_name` varchar(100) DEFAULT NULL,\n  `demand_name` varchar(100) DEFAULT NULL,\n  `demand_created` varchar(20) DEFAULT NULL,\n  `quarter` varchar(10) DEFAULT NULL,\n  `status` varchar(100) DEFAULT NULL,\n  `row_created` timestamp NULL DEFAULT CURRENT_TIMESTAMP\n);\n-- Excel数据导入的sql详见 demand\\insert_excel.sql\n\n\n-- 数据标准记录明细表\nCREATE TABLE `data_standard_detail` (\n  `id` int(11) NOT NULL AUTO_INCREMENT,\n  `std_id` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  `name` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  `en_name` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  `business_definition` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  `business_rule` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  `std_source` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  `data_type` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  `data_format` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  `code_rule` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  `code_range` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  `code_meaning` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  `business_range` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  `dept` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  `system` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  PRIMARY KEY (`id`) USING BTREE\n) ;\n\n\n-- 数据标准记录概述表\nCREATE TABLE `data_standard_desc` (\n  `id` int(11) NOT NULL AUTO_INCREMENT,\n  `name` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  `content` text CHARACTER SET utf8 COLLATE utf8_general_ci,\n  PRIMARY KEY (`id`) USING BTREE\n);\n\n\n-- 数据标准目录表\nCREATE TABLE `data_standard_index` (\n  `pk_id` int(11) NOT NULL AUTO_INCREMENT,\n  `idx_id` int(11) DEFAULT NULL COMMENT '树节点id',\n  `idx_pid` int(11) DEFAULT NULL COMMENT '树父节点id',\n  `idx_name` text CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT '树节点名',\n  `is_open` text CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT '树节点是否默认展开',\n  PRIMARY KEY (`pk_id`) USING BTREE\n) ;\n\n-- 数据标准更新记录表\nCREATE TABLE `data_standard_update_log` (\n  `id` int(11) NOT NULL AUTO_INCREMENT,\n  `std_name` text CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT '数据标准名',\n  `username` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '操作者',\n  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,\n  `previous_version` text CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT '上一版本的内容',\n  PRIMARY KEY (`id`) USING BTREE\n);\n\n\n-- 日期维度表\n-- 时期生成，执行utils/generate_dim_date.py\nCREATE TABLE `dim_date` (\n  `date` datetime DEFAULT NULL,\n  `day_id` int(11) NOT NULL,\n  `year` int(11) DEFAULT NULL,\n  `month` int(11) DEFAULT NULL,\n  `day` int(11) DEFAULT NULL,\n  `quarter` int(11) DEFAULT NULL,\n  `day_name` text,\n  `weekofyear` bigint(20) DEFAULT NULL,\n  `dayofyear` int(11) DEFAULT NULL,\n  `daysinmonth` int(11) DEFAULT NULL,\n  `dayofweek` int(11) DEFAULT NULL,\n  `is_leap_year` tinyint(1) DEFAULT NULL,\n  `is_month_end` tinyint(1) DEFAULT NULL,\n  `is_month_start` tinyint(1) DEFAULT NULL,\n  `is_quarter_end` tinyint(1) DEFAULT NULL,\n  `is_quarter_start` tinyint(1) DEFAULT NULL,\n  `is_year_end` tinyint(1) DEFAULT NULL,\n  `is_year_start` tinyint(1) DEFAULT NULL,\n  PRIMARY KEY (`day_id`)\n);\n\n\n-- 数据源记录表\nCREATE TABLE `source_db_info` (\n  `id` int(11) NOT NULL AUTO_INCREMENT,\n  `company` varchar(10) DEFAULT NULL,\n  `name` varchar(40) DEFAULT NULL,\n  `alias` varchar(50) DEFAULT NULL,\n  `connection_string` varchar(100) DEFAULT NULL,\n  `ip` varchar(16) DEFAULT NULL,\n  `user` varchar(32) DEFAULT NULL,\n  `passwd` varchar(200) DEFAULT NULL,\n  `db` varchar(32) DEFAULT NULL,\n  `port` int(11) DEFAULT NULL,\n  `db_type` varchar(32) DEFAULT NULL,\n  `charset` varchar(10) DEFAULT NULL,\n  `note` varchar(200) DEFAULT NULL,\n  PRIMARY KEY (`id`)\n);\n\n\n-- ETL源-目标表，用于血缘分析\nCREATE TABLE `datacenter_mapping` (\n  `subject_area` varchar(255) DEFAULT NULL,\n  `mapping_name` varchar(255) DEFAULT NULL,\n  `source` varchar(255) DEFAULT NULL,\n  `target` varchar(255) DEFAULT NULL\n);"
  },
  {
    "path": "docs/demand_views.md",
    "content": "# 身份验证接口\n\n## import_sheet\n- URL：http://100.100.0.177/demand/import_sheet\n- 功能：上传源系统改造情况Excel表，处理成json格式的文本文件，存放在服务器`/data/data-quality/static/resource/demand.json`，供集团仪表盘和子公司仪表盘调用\n- 请求类型：GET请求打开页面，POST请求提交Excel表\n- 请求参数：无\n- 返回值：\n```\n上传成功为\"Excel处理成功，请返回首页查看数据\"\n失败为500\n```\n\n---\n\n## list_subcompany\n- URL：http://100.100.0.177/api/demand/list_subcompany\n- 功能：子公司源系统改造进度明细\n- 请求类型：GET\n- 请求参数：\n\n\n参数 | 是否必须 | 说明\n-|-|-\ncompany | 必须 | 公司简写，接受的参数为`ycxt`/`yczc`/`gdzdb`/`ycjk`/`fdct`/`zyyc`/`jz`\n\n- 请求示例：http://100.100.0.177/api/demand/list_subcompany?company=ycxt\n- 返回值：\n```\n[\n\t[1, \"信托\", \"风险等级\", \"补创建数据项\", \"201905\", \"2019Q1进行中\", \"2019Q2未开展\"],\n\t[2, \"信托\", \"净资本类别\", \"补创建数据项\", \"201905\", \"2019Q1进行中\", \"2019Q2未开展\"],\n\t[3, \"信托\", \"风险资本类别\", \"补创建数据项\", \"201905\", \"2019Q1进行中\", \"2019Q2未开展\"],\n\t[4, \"信托\", \"参与人角色\", \"设为必填\", \"201905\", \"2019Q1进行中\", \"2019Q2完成\"],\n\t[5, \"信托\", \"所有制类型\", \"设为必填\", \"201905\", \"2019Q1进行中\", \"2019Q2完成\"],\n\t[6, \"信托\", \"参与人规模\", \"设为必填\", \"201905\", \"2019Q1进行中\", \"2019Q2完成\"],\n\t[7, \"信托\", \"参与人角色标识\", \"设为必填\", \"201905\", \"2019Q1进行中\", \"2019Q2完成\"],\n\t[8, \"信托\", \"产品收益率\", \"设为必填\", \"201905\", \"2019Q1进行中\", \"2019Q2完成\"],\n\t[9, \"信托\", \"参与人上市标识\", \"设为必填\", \"201905\", \"2019Q1进行中\", \"2019Q2完成\"],\n\t[10, \"信托\", \"项目投向行业\", \"设为必填\", \"201905\", \"2019Q1进行中\", \"2019Q2完成\"],\n\t[11, \"信托\", \"项目名称\", \"设为必填\", \"201905\", \"2019Q1进行中\", \"2019Q2完成\"],\n\t[12, \"信托\", \"项目来源\", \"设为必填\", \"201905\", \"2019Q1进行中\", \"2019Q2完成\"],\n\t[13, \"信托\", \"存续标识\", \"设为必填\", \"201905\", \"2019Q1进行中\", \"2019Q2业务系统自动填写，不是业务人员填写\"]\n]\n```"
  },
  {
    "path": "docs/demo数据.sql",
    "content": "use data_quality;\n\n-- check_result_template demo数据\nINSERT INTO `check_result_template` VALUES (1,'db','db','项目编号',NULL,'是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,3011,1,0.03,'dbdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(1,'jj1','jj1','项目编号','项目基本信息','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,219,0,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(1,'jj2','jj2','项目编号','项目基本信息','是',NULL,'select now(),\\'+其他字段形成检核SQL\\' from table',NULL,350,0,0.00,'jjdb2',NULL,'已启用','Y','2019-03-30 16:00:00',1),(1,'jk','jk','项目编号','项目表','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,12372410,0,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(1,'jz','jz','项目编号','项目基本信息','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,39,0,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(1,'xt','xt','项目编号','项目基本信息','是','准确性检验','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,451027,0,0.00,'','备注测试1','已启用','Y','2019-03-30 16:00:00',1),(1,'zc','zc','项目编号','项目基本信息表','是','完整性检验','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,109,0,0.00,'','','已启用','Y','2019-03-30 16:00:00',1),(2,'db','db','项目名称',NULL,'是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,3011,19,0.63,'dbdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(2,'jj1','jj1','项目名称','项目基本信息','否','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,219,0,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(2,'jj2','jj2','项目名称','项目基本信息','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,350,13,3.71,'jjdb2',NULL,'已启用','Y','2019-03-30 16:00:00',1),(2,'jk','jk','项目名称','项目表','否','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,NULL,0,NULL,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(2,'jz','jz','项目名称','项目基本信息','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,39,0,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(2,'xt','xt','项目编号','资金基本信息','是','一致性检验','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,1103,0,0.00,'','11111','已停用','Y','2019-03-30 16:00:00',1),(2,'zc','zc','项目名称','项目基本信息表','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,109,0,0.00,'zcdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(3,'db','db','项目类别',NULL,'是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,3011,0,0.00,'dbdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(3,'jj1','jj1','项目类别','项目基本信息','是','未创建项','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,219,219,100.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(3,'jj2','jj2','项目类别','项目基本信息','是','未创建项','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,350,350,100.00,'jjdb2',NULL,'已启用','Y','2019-03-30 16:00:00',1),(3,'jk','jk','项目类别','项目表','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,12372410,NULL,NULL,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(3,'jz','jz','项目类别代码','项目基本信息','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,39,0,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(3,'xt','xt','项目名称','项目基本信息','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,451027,7,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(3,'zc','zc','项目类别','项目基本信息表','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,109,7,6.42,'zcdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(4,'db','db','开始日期',NULL,'是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,3011,206,6.84,'dbdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(4,'jj1','jj1','项目投向行业（展业指引）','项目基本信息','是','未创建项','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,219,219,100.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(4,'jj2','jj2','项目投向行业（展业指引）','项目其他信息','是','未创建项','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,350,350,100.00,'jjdb2',NULL,'已启用','Y','2019-03-30 16:00:00',1),(4,'jk','jk','开始日期','项目表','否','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,NULL,NULL,NULL,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(4,'jz','jz','开始日期','项目基本信息','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,39,0,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(4,'xt','xt','项目名称','资金基本信息','是','完整性检验','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,1103,0,0.00,'','','已启用','Y','2019-03-30 16:00:00',1),(4,'zc','zc','项目资金用途','项目基本信息表','是','值域检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,109,0,0.00,'zcdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(5,'db','db','到期日期',NULL,'是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,3011,215,7.14,'dbdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(5,'jj1','jj1','项目资金用途','项目基本信息','是','未创建项','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,219,219,100.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(5,'jj2','jj2','项目资金用途','项目基本信息','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,81,38,46.91,'jjdb2',NULL,'已启用','Y','2019-03-30 16:00:00',1),(5,'jk','jk','到期日期','项目表','是','合法性检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,12372410,0,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(5,'jz','jz','到期日期','项目基本信息','是','合法性检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,39,0,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(5,'xt','xt','项目类别','项目基本信息','是','准确性检验','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,451027,0,0.00,'','','已启用','Y','2019-03-30 16:00:00',1),(5,'zc','zc','项目交易对手（投向）','不良资产处置','是','值域检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,109,0,0.00,'zcdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(6,'db','db','我方管理角色','','是','一致性检验','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,3011,3011,100.00,'dbdb1','','已启用','Y','2019-03-30 16:00:00',1),(6,'jj2','jj2','开始日期','项目基本信息','否','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,70,70,100.00,'jjdb2',NULL,'已启用','Y','2019-03-30 16:00:00',1),(6,'jk','jk','项目金额','项目表','否','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,NULL,253,NULL,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(6,'jz','jz','项目金额','项目基本信息','是','值域检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,39,39,100.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(6,'xt','xt','项目类别','资金基本信息','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,1103,0,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(6,'zc','zc','开始日期',NULL,'是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,109,1,0.92,'zcdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(7,'db','db','项目金额',NULL,'是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,3011,9,0.30,'dbdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(7,'jj1','jj1','到期日期','项目基本信息','是','未创建项','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,219,219,100.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(7,'jj2','jj2','到期日期','项目基本信息','是','未创建项','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,350,350,100.00,'jjdb2',NULL,'已启用','Y','2019-03-30 16:00:00',1),(7,'jk','jk','项目余额','项目表','是','-- 请选择 --','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,12372410,0,0.00,'','','已启用','Y','2019-03-30 16:00:00',1),(7,'jz','jz','项目五级分类','项目基本信息','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,39,1,2.56,NULL,'90天后才有五级分类，但目前仅有2017年数据故全部空白','已启用','Y','2019-03-30 16:00:00',1),(7,'xt','xt','项目投向行业','项目其它信息','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,451027,15,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(7,'zc','zc','到期日期',NULL,'是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,109,73,66.97,'zcdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(8,'db','db','项目余额',NULL,'是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,3011,14,0.46,'dbdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(8,'jj2','jj2','约定退出日期','项目基本信息','是','未创建项','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,350,350,100.00,'jjdb2',NULL,'已启用','Y','2019-03-30 16:00:00',1),(8,'jk','jk','审批结论','项目表','否','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,NULL,239,NULL,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(8,'jz','jz','收益率','项目基本信息','是','值域检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,39,0,0.00,NULL,'数据不全造成部分数据没有同步到','已启用','Y','2019-03-30 16:00:00',1),(8,'xt','xt','项目投向（按功能）','项目其它信息','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,451027,0,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(8,'zc','zc','到期日期',NULL,'是','合法性检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,109,0,0.00,'zcdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(9,'db','db','项目收益',NULL,'是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,3011,698,23.18,'dbdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(9,'jj1','jj1','约定退出日期','项目基本信息','是','合法性检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,17,17,100.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(9,'jj2','jj2','约定退出方式','项目基本信息','是','未创建项','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,350,350,100.00,'jjdb2',NULL,'已启用','Y','2019-03-30 16:00:00',1),(9,'jk','jk','审批金额','项目表','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,12372410,0,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(9,'jz','jz','不含税收益率','项目基本信息','是','值域检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,NULL,NULL,NULL,NULL,'底层数据基础计算出结果','已启用','Y','2019-03-30 16:00:00',1),(9,'xt','xt','项目资金用途','项目基本信息','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,451027,0,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(9,'zc','zc','项目金额','项目基本信息表','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,109,25,22.94,'zcdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(10,'db','db','收益率',NULL,'是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,3011,875,29.06,'dbdb1',NULL,'已启用','Y','2019-03-30 16:00:00',1),(10,'jj2','jj2','项目管理方式','项目其他信息','是','未创建项','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,350,350,100.00,'jjdb2',NULL,'已启用','Y','2019-03-30 16:00:00',1),(10,'jk','jk','撤销原因','项目表','否','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,NULL,239,NULL,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(10,'jz','jz','项目收益','项目基本信息','否','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,NULL,NULL,NULL,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(10,'xt','xt','项目交易对手（投向）','项目其它信息','是','空值检核','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,451027,0,0.00,NULL,NULL,'已启用','Y','2019-03-30 16:00:00',1),(10,'zc','zc','项目余额','项目余额信息历史','是','-- 请选择 --','select now(),\\'+其他字段形成检核SQL\\' from table',NULL,109,27,24.77,'','','已启用','Y','2019-03-30 16:00:00',1),(11,'xt','xt','飒飒','阿萨','否','完整性检验','阿萨',NULL,NULL,NULL,NULL,'xtdb1','阿萨','已启用','N',NULL,NULL),(12,'xt','xt','','','是','-- 请选择 --','',NULL,NULL,NULL,NULL,'','','已启用','N',NULL,NULL),(99,'xt','xt','项目编号2',NULL,'是','空值检核','select now()',NULL,NULL,NULL,NULL,'xtdb3',NULL,'已启用','N',NULL,NULL);\n\n\n\n\n\n-- 数据标准demo数据\nINSERT INTO `data_standard_desc` VALUES (1,'概述','概述'),(2,'参考文献','国家标准：\\r\\n1)\t《GB/T 3304-1991 中国各民族名称的罗马字母拼写法和代码》\\r\\n2)\t《GB/T 2261.1-2003 个人基本信息分类与代码_第1部分_人的性别代码》\\r\\n3)\t《GB/T 2261.2-2003 个人基本信息分类与代码_第2部分_婚姻状况代码》\\r\\n4)\t《GB/T 2261.3-2003 个人基本信息分类与代码_第3部分_健康状况》\\r\\n5)\t《GB/T 2261.4-2003 个人基本信息分类与代码_第4部分_从业状况》\\r\\n6)\t《GB/T 11643-1999公民身份证号码》\\r\\n7)\t《GB/T 2659-2000 世界各国和地区名称代码》\\r\\n8)\t《GB/T 4754-2017 国民经济行业分类》\\r\\n9)\t《GB/T 12402-2000 经济类型分类与代码》\\r\\n10)\t《GB/T 2260-2017 2017中华人民共和国行政区划代码》\\r\\n\\r\\n外部管理规定：\\r\\n11)\t《关于印发中小企业划型标准规定的通知》(工信部联企业[2011]300号)\\r\\n12)\t《融资类担保机构信用评级管理办法》\\r\\n13)\t《中华人民共和国公司登记管理条例》\\r\\n14)\t《中华人民共和国企业法人登记管理条例实施细则》\\r\\n15)\t《合伙企业法》\\r\\n16)\t《统计上大中小微型企业划分办法（2017）》'),(3,'术语和定义','术语与定义'),(4,'项目（协议）','        项目（协议）指信托项目、资产管理项目、贷款协议、增信项目、担保协议、再担保协议、基金、子基金、股权直投项目、融资租赁合同。\\r\\n        基础信息：指项目的基本属性信息。项目编号、项目名称、项目类别、开始日期、到期日期、约定退出日期、约定退出方式；\\r\\n        事件信息：指项目参与人对于项目的投入与项目的运行方式。包括项目金额、项目余额、账面金额、资产金额、收购方式、资产包类型、资产包来源、审批结论、审批金额、撤销原因、拒绝原因；\\r\\n        管理信息：指项目的管理方式以及项目参与者在其中扮演的角色。项目管理方式，我方管理角色；\\r\\n        收益信息：指项目给投资者带来的回报情况与评价指标，包括收益率，项目收益；\\r\\n        风险信息：指对项目风险的主要风险评价指标与评价方式。包括项目投向行业、项目投向（按功能）、项目资金用途、项目交易对手（投向）、项目预计还款来源、风险等级、项目五级分类、担保责任比例、风险项目描述、担保方式。'),(5,'交易','        交易指项目（协议）中价值交换的具体信息，包括交易详情与交易状态。\\r\\n        交易详情：指与交易相关的基础信息与数据，包括交易编号，交易类型，交易日期，交易本金金额，交易利息金额；\\r\\n        交易状态：指交易为投资者带来的收益情况以及交易本身风险属性，包括交易分红金额，逾期天数；'),(6,'参与人（对公）','        对公参与人又称公司客户，是指与企业进行业务关系的法人客户，通常分为大型公司客户，中型公司客户，小型公司客户，微型公司客户等等，对公参与人主题中包含了这些客户的基本信息、关联信息、风险信息和风险缓释信息。\\r\\n        基本信息：指与对公参与人相关的基础信息。包括参与人类别，参与人编号，参与人名称，参与人角色标识，参与人行业，参与人地区，参与人规模，参与人所有制类型，参与人上市标识，参与人政府信用类标识，参与人担保类型，首次业务签约日期；\\r\\n        关联信息：指为监控企业关联方之间的交易,关联交易是公司运作中经常出现的而又易于发生不公平结果的交易。包括参与人实际控制人类别，参与人实际控制人名称，上级股东类别，上级股东名称，被投资企业名称；\\r\\n        风险信息：指参与人相关的风险信息，能协助相关问题和决策的相关因素。包括参与人信用等级，参与人历史违约标识，历史违约事件类型，违约日期，参与人五级分类；\\r\\n        风险缓释信息：指通过风险控制措施来降低风险的损失频率或影响程度。包括参与人抵质押物估值。'),(7,'参与人（个人）','        个人参与人指与企业发生业务往来的个人和企业内部员工，信息包含基础信息和员工信息两类。 \\r\\n        基础信息：指个人参与人的基础信息，包括参与人编号，参与人名称，参与人角色，参与人地区，参与人年龄，参与人性别；\\r\\n        员工信息：指个人参与人的职位与工作信息，包括参与人岗位，参与人所属单位，参与人所属部门，参与人职务，参与人职级。'),(8,'机构','        机构指集团内部依法设立的机关、事业、企业、社团及其他依法成立的单位。\\r\\n        基础信息：指机构相关的基础信息，包括机构编号，机构名称，机构简称，机构类型，投资类型；\\r\\n        层级关系：指能表明该机构与其他机构关系的层级信息，包括上级机构名称。'),(9,'产品','        指集团内各二级公司开展业务时，所使用的产品分类信息。\\r\\n        基础信息：指产品相关的识别信息，包括产品编号，产品名称；\\r\\n        层级关系：指能表明该产品与其他产品关系层级的信息，包括上级产品单元，产品级次。'),(10,'财务','        财务信息：期初借方余额，期初贷方余额，本期借方发生额，本期贷方发生额，期末借方余额，期末贷方余额，总账会计科目编号，总账会计科目名称，总账会计科目级次，会计日期，');\n\n\n\nINSERT INTO `data_standard_detail` VALUES (1,'PC000001\\r\\n','项目编号','Project Number',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(2,'PC000002\\r\\n','项目名称','Project Name',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(3,'PC000003\\r\\n','项目类别','Project Category\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(4,'PC000004\\r\\n','项目投向行业','Industry to be Invested\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(5,'PC000005\\r\\n','项目投向行业（展业指引）','Industry to be Invested（Guidance）\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(6,'PC000005\\r\\n','项目投向（按功能）','Trust Business\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(9,'PC000006\\r\\n','项目资金用途','Fund Usage',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(10,'PC000007\\r\\n','项目交易对手（投向）','Counterparty（The Scope of Investment）\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(11,'PC000008\\r\\n','项目来源','Project Source\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(12,'PC000009\\r\\n','项目所在省','Project Province\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(13,'PC000011\\r\\n','项目所在市','Project City\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(14,'PC000012\\r\\n','项目所在县','Project County\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(15,'PC000011\\r\\n','开始日期','Start Date\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(16,'PC000012\\r\\n','到期日期','Finish Date\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(17,'PC000013\\r\\n','约定退出日期','Planned Exit Date\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(18,'PC000014\\r\\n','约定退出方式','Planned Exit Route\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(19,'PC000015\\r\\n','项目管理方式','Investment Style\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(20,'PC000016\\r\\n','项目管理方式（监管）','Investment Style\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(21,'PC000017\\r\\n','我方管理角色','Partnership\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(22,'PC000018\\r\\n','项目金额','Amount\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(23,'PC000019\\r\\n','项目余额','Current Balance\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(24,'PC000020\\r\\n','账面金额','Book Amount\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(25,'PC000021\\r\\n','账面余额','Book Amount\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(26,'PC000022\\r\\n','资产金额','Asset Value\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(27,'PC000023\\r\\n','资产余额','Asset Value\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(28,'PC000024\\r\\n','收益率','Return Rate\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(29,'PC000025\\r\\n','项目收益','Project Return\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(30,'PC000026\\r\\n','审批结论','Result of Review\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(31,'PC000027\\r\\n','审批金额','Approved Amount\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(32,'PC000028\\r\\n','撤销原因','Cause of Revocation\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(33,'PC000029\\r\\n','拒绝原因','Cause of Rejection\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(34,'PC000030\\r\\n','风险等级','Risk Rating\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(35,'PC000031\\r\\n','项目五级分类','Five Level Classification of Projects\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(36,'PC000032\\r\\n','担保责任比例','Proportion of Guarantee Liability\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(37,'PC000033\\r\\n','风险项目简述','Descriptions of Risk Projects\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(38,'PC000034\\r\\n','担保方式','Guarantee Type\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(39,'PC000035\\r\\n','收购方式','Acquisition Mode\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(40,'PC000036\\r\\n','资产包类别','Type of Asset Package\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(41,'PC000037\\r\\n','资产编号','Asset Number\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(42,'PC000038\\r\\n','资产名称','Asset Name\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(43,'PC000039\\r\\n','资产类别','Type of Asset\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(44,'PC000042\\r\\n','续封续冻资产类型','Type of Continued Sealing Asset\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(45,'PC000042\\r\\n','是否续封续冻预警','Indicator of Continued Seal Early Warning\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(46,'PC000043\\r\\n','资产处置合同金额','Amount of Contract for Disposing of Assets\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(47,'PC000044\\r\\n','资金或资产来源','Sources of Funding\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(48,'PC000045\\r\\n','基金创投业务类型','Fund and Items Business Type\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(49,'PC000046\\r\\n','净资本类别\\r\\n','Net Capital Type\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(50,'PC000048\\r\\n','风险资本类别','Venture Capital Type',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(51,'PC000048\\r\\n','保证金','Cash Deposit\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(52,'PC000049\\r\\n','线上/线下','Online or Offline\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(53,'JY000001\\r\\n','交易编号','Transaction Number',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(54,'JY000002\\r\\n','交易类型','Transaction Type',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(55,'JY000003\\r\\n','交易日期','Transaction Date',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(56,'JY000004\\r\\n','交易本金金额','Transaction Principal Amount\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(57,'JY000005\\r\\n','交易利息金额','Interest Rate of Transaction',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(58,'JY000006\\r\\n','交易分红金额','Transaction Bonus\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(59,'JY000007\\r\\n','逾期天数','Overdue Days\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(60,'JY000008\\r\\n','基金资金来源','Source of Funding\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(61,'JY000009\\r\\n','预计还款金额','Estimated Amount of Repayment\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(62,'CY000001\\r\\n','参与人类别','Participants Type\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(63,'CY000002\\r\\n','参与人编号','Participants Number\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(64,'CY000003\\r\\n','参与人名称','Participants Name\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(65,'CY000004\\r\\n','机构证件类别','ID Type of Institutions\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(66,'CY000005\\r\\n','机构证件号码','ID Number of Institutions\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(67,'CY000006\\r\\n','机构证件有效期','Institutions Certificates Expiration Date\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(68,'CY000007\\r\\n','参与人角色标识','Participants Role\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(69,'CY000008\\r\\n','参与人行业','Industrial Classification of Participants\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(70,'CY000009\\r\\n','参与人省份','Participants Province\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(71,'CY000010\\r\\n','参与人市','Participants City\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(72,'CY000011\\r\\n','参与人县','Participants County\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(73,'CY000012\\r\\n','参与人规模','Participants Scale\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(74,'CY000013\\r\\n','从业人数','The Number of Employees\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(75,'CY000014\\r\\n','营业收入','Business Income\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(76,'CY000015\\r\\n','营业状态','Operating Status\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(77,'CY000016\\r\\n','所有制类型','Type of Enterprise\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(78,'CY000017\\r\\n','国企标识','Indicator of State-owned Enterprise\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(79,'CY000018\\r\\n','参与人上市标识','Public Enterprise Indicator\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(80,'CY000019\\r\\n','股票代码','Stock Code\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(81,'CY000020\\r\\n','股票类型','Stock Type\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(82,'CY000021\\r\\n','股票名称','Stock Name\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(83,'CY000023\\r\\n','参与人担保类型','Guarantor Type\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(84,'CY000024\\r\\n','参与人抵质押物估值','Participants Collateral Valuation\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(85,'CY000025\\r\\n','参与人实际控制人类别','Controlling Owner Type of Participants \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(86,'CY000026\\r\\n','参与人实际控制人名称','Controlling Owner Name of Participants \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(87,'CY000027\\r\\n','上级股东类别','Type of Superior Shareholders\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(88,'CY000028\\r\\n','上级股东名称','Name of Superior Shareholders\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(89,'CY000029\\r\\n','参与人内部信用等级','Participants Internal Rating Result\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(90,'CY000030\\r\\n','参与人外部信用等级','Participants External Rating Result\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(91,'CY000031\\r\\n','参与人历史违约标识','Participants Historical Default Indicator\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(92,'CY000032\\r\\n','历史违约事件类型','Historical Default Style\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(93,'CY000033\\r\\n','违约日期','Default Date\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(94,'CY000034\\r\\n','参与人五级分类','Participants Five-category Classification\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(95,'CY000035\\r\\n','首次业务签约日期','First Business Signing Date\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(96,'CY000036\\r\\n','法人代表姓名','Name of The Representative of A Legal Person\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(97,'CY000037\\r\\n','法人代表证件类型','ID Type of The Representative of A Legal Person\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(98,'CY000038\\r\\n','法人代表证件号码','ID Number of The Representative of A Legal Person\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(99,'CY000039\\r\\n','集团客户标志','Group Customer Indicator\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(100,'CY000040\\r\\n','企业成长阶段','Enterprise Growth Stage\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(101,'CY000041\\r\\n','投资轮次','Investment Rotation\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(102,'CY000042\\r\\n','注册日期','Date of Registration\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(103,'PI000001\\r\\n','参与人编号','Participant Number \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(104,'PI000002\\r\\n','参与人名称','Participant Legal Name\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(105,'PI000003\\r\\n','个人证件类别','Participant Certificate Type\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(106,'PI000004\\r\\n','个人证件号码','Participant Certificate Number\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(107,'PI000005\\r\\n','个人证件有效期','Participant Certificate Expiration Date\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(108,'PI000006\\r\\n','参与人角色','Participant Role \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(109,'PI000008\\r\\n','参与人年龄','Participant Age\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(110,'PI000009\\r\\n','参与人性别','Participant Gender\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(111,'PI000010\\r\\n','参与人岗位','Participant Role\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(112,'PI000011\\r\\n','参与人所属单位','Participant Company Name\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(113,'PI000012\\r\\n','参与人所属部门','Participant Department \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(114,'PI000013\\r\\n','参与人职务','Participant Position\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(115,'PI000014\\r\\n','参与人职级','Participant Ranking\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(116,'PI000015\\r\\n','从业状况','Employment Status\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(117,'PI000016\\r\\n','婚姻状况','Marriage Status\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(118,'PI000017\\r\\n','健康状况','Health Status\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(119,'PI000018\\r\\n','年收入','Annual Income\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(120,'PI000019\\r\\n','国籍','Nationality \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(121,'PI000020\\r\\n','家庭地址','Home Address\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(122,'PI000021\\r\\n','通讯地址','Current Address\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(123,'PI000022\\r\\n','联系电话','Contact Phone Number \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(124,'PI000023\\r\\n','民族','Nationalities of China \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(125,'PI000024\\r\\n','户口性质','Registered Permanent Residence Type \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(126,'PI000025\\r\\n','内部员工标志','Internal Employee Symbol\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(127,'II000001\\r\\n','机构编号','Institutional Number ',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(128,'II000002\\r\\n','机构名称','Institutional Legal Name\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(129,'II000003\\r\\n','机构简称','Institutional Shortened Name\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(130,'II000004\\r\\n','上级机构名称','Next Higher Institutional Name\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(131,'II000005\\r\\n','机构类型','Institution Type \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(132,'II000006\\r\\n','投资类型','Investment Type \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(133,'PP000001\\r\\n','产品编号','Product Number \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(134,'PP000002\\r\\n','产品名称','Product Name \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(135,'PP000003\\r\\n','上级产品单元','Next Superior Unit  \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(136,'PP000004\\r\\n','产品级次','Product Ranking \\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(137,'PP000005\\r\\n','产品开始日期','Product Start Date\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(138,'PP000006\\r\\n','产品结束日期','Product End Date',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(139,'PP000007\\r\\n','产品收益率','Product Return Rate\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(140,'PP000008\\r\\n','产品收益','Product Return\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(141,'PP000009\\r\\n','管理费率','Management Rate\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),(142,'PP000010\\r\\n','存续标识','Indicator of Existent Project\\r\\n',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);\n\n\n\nINSERT INTO `data_standard_index` VALUES (1,2,0,'参考文献','true'),(2,3,0,'术语和定义','true'),(3,4,0,'主题域分类','true'),(4,41,4,'项目（协议）',NULL),(5,42,4,'交易',NULL),(6,43,4,'参与人（对公）',NULL),(7,44,4,'参与人（个人）',NULL),(8,45,4,'机构',NULL),(9,46,4,'产品',NULL),(10,47,4,'财务',NULL),(11,5,0,'数据项标准','true'),(12,51,5,'项目（协议）',NULL),(13,5101,51,'项目编号',NULL),(14,5102,51,'项目名称',NULL),(15,5103,51,'项目类别',NULL),(16,5104,51,'项目投向行业',NULL),(17,5105,51,'项目投向行业（展业指引）',NULL),(18,5106,51,'项目投向（按功能）',NULL),(19,5107,51,'项目资金用途',NULL),(20,5108,51,'项目交易对手（投向）',NULL),(21,5109,51,'项目来源',NULL),(22,5110,51,'项目所在省',NULL),(23,5111,51,'项目所在市',NULL),(24,5112,51,'项目所在县',NULL),(25,5113,51,'开始日期',NULL),(26,5114,51,'到期日期',NULL),(27,5115,51,'约定退出日期',NULL),(28,5116,51,'约定退出方式',NULL),(29,5117,51,'项目管理方式',NULL),(30,5118,51,'项目管理方式（监管）',NULL),(31,5119,51,'我方管理角色',NULL),(32,5120,51,'项目金额',NULL),(33,5121,51,'项目余额',NULL),(34,5122,51,'账面金额',NULL),(35,5123,51,'账面余额',NULL),(36,5124,51,'资产金额',NULL),(37,5125,51,'资产余额',NULL),(38,5126,51,'收益率',NULL),(39,5127,51,'项目收益',NULL),(40,5128,51,'审批结论',NULL),(41,5129,51,'审批金额',NULL),(42,5130,51,'撤销原因',NULL),(43,5131,51,'拒绝原因',NULL),(44,5132,51,'风险等级',NULL),(45,5133,51,'项目五级分类',NULL),(46,5134,51,'担保责任比例',NULL),(47,5135,51,'风险项目简述',NULL),(48,5136,51,'担保方式',NULL),(49,5137,51,'收购方式',NULL),(50,5138,51,'资产包类别',NULL),(51,5139,51,'资产编号',NULL),(52,5140,51,'资产名称',NULL),(53,5141,51,'资产类别',NULL),(54,5142,51,'续封续冻资产类型',NULL),(55,5143,51,'是否续封续冻预警',NULL),(56,5144,51,'资产处置合同金额',NULL),(57,5145,51,'资金或资产来源',NULL),(58,5146,51,'基金创投业务类型',NULL),(59,5147,51,'净资本类别',NULL),(60,5148,51,'风险资本类别',NULL),(61,5149,51,'保证金',NULL),(62,5150,51,'线上/线下',NULL),(63,52,5,'交易',NULL),(64,5201,52,'交易编号',NULL),(65,5202,52,'交易类型',NULL),(66,5203,52,'交易日期',NULL),(67,5204,52,'交易本金金额',NULL),(68,5205,52,'交易利息金额',NULL),(69,5206,52,'交易分红金额',NULL),(70,5207,52,'逾期天数',NULL),(71,5208,52,'基金资金来源',NULL),(72,5209,52,'预计还款金额',NULL),(73,53,5,'参与人（对公）',NULL),(74,5301,53,'参与人类别',NULL),(75,5302,53,'参与人编号',NULL),(76,5303,53,'参与人名称',NULL),(77,5304,53,'机构证件类别',NULL),(78,5305,53,'机构证件号码',NULL),(79,5306,53,'机构证件有效期',NULL),(80,5307,53,'参与人角色标识',NULL),(81,5308,53,'参与人行业',NULL),(82,5309,53,'参与人省份',NULL),(83,5310,53,'参与人市',NULL),(84,5311,53,'参与人县',NULL),(85,5312,53,'参与人规模',NULL),(86,5313,53,'从业人数',NULL),(87,5314,53,'营业收入',NULL),(88,5315,53,'营业状态',NULL),(89,5316,53,'所有制类型',NULL),(90,5317,53,'国企标识',NULL),(91,5318,53,'参与人上市标识',NULL),(92,5319,53,'股票代码',NULL),(93,5320,53,'股票类型',NULL),(94,5321,53,'股票名称',NULL),(95,5322,53,'参与人担保类型',NULL),(96,5323,53,'参与人抵质押物估值',NULL),(97,5324,53,'地方政府融资平台标识',NULL),(98,5325,53,'参与人实际控制人类别',NULL),(99,5326,53,'参与人实际控制人名称',NULL),(100,5327,53,'上级股东类别',NULL),(101,5328,53,'上级股东名称',NULL),(102,5329,53,'参与人内部信用等级',NULL),(103,5330,53,'参与人外部信用等级',NULL),(104,5331,53,'参与人历史违约标识',NULL),(105,5332,53,'历史违约事件类型',NULL),(106,5333,53,'违约日期',NULL),(107,5334,53,'参与人五级分类',NULL),(108,5335,53,'首次业务签约日期',NULL),(109,5336,53,'法人代表姓名',NULL),(110,5337,53,'法人代表证件类型',NULL),(111,5338,53,'法人代表证件号码',NULL),(112,5339,53,'集团客户标志',NULL),(113,5340,53,'企业成长阶段',NULL),(114,5341,53,'投资轮次',NULL),(115,5342,53,'注册日期',NULL),(116,54,5,'参与人（个人）',NULL),(117,5401,54,'参与人编号',NULL),(118,5402,54,'参与人名称',NULL),(119,5403,54,'个人证件类别',NULL),(120,5404,54,'个人证件号码',NULL),(121,5405,54,'个人证件有效期',NULL),(122,5406,54,'参与人角色',NULL),(123,5407,54,'参与人年龄',NULL),(124,5408,54,'参与人性别',NULL),(125,5409,54,'参与人岗位',NULL),(126,5410,54,'参与人所属单位',NULL),(127,5411,54,'参与人所属部门',NULL),(128,5412,54,'参与人职务',NULL),(129,5413,54,'参与人职级',NULL),(130,5414,54,'从业状况',NULL),(131,5415,54,'婚姻状况',NULL),(132,5416,54,'健康状况',NULL),(133,5417,54,'年收入',NULL),(134,5418,54,'国籍',NULL),(135,5419,54,'家庭地址',NULL),(136,5420,54,'通讯地址',NULL),(137,5421,54,'联系电话',NULL),(138,5422,54,'民族',NULL),(139,5423,54,'户口性质',NULL),(140,5424,54,'内部员工标志',NULL),(141,55,5,'机构',NULL),(142,5501,55,'机构编号',NULL),(143,5502,55,'机构名称',NULL),(144,5503,55,'机构简称',NULL),(145,5504,55,'上级机构名称',NULL),(146,5505,55,'机构类型',NULL),(147,5506,55,'投资类型',NULL),(148,56,5,'产品',NULL),(149,5601,56,'产品编号',NULL),(150,5602,56,'产品名称',NULL),(151,5603,56,'上级产品单元',NULL),(152,5604,56,'产品级次',NULL),(153,5605,56,'产品开始日期',NULL),(154,5606,56,'产品结束日期',NULL),(155,5607,56,'产品收益率',NULL),(156,5608,56,'产品收益',NULL),(157,5609,56,'管理费率',NULL),(158,5610,56,'存续标识',NULL),(159,57,5,'财务',NULL),(160,5701,57,'期初借方余额',NULL),(161,5702,57,'期初贷方余额',NULL),(162,5703,57,'本期借方发生额',NULL),(163,5704,57,'本期贷方发生额',NULL),(164,5705,57,'期末借方余额',NULL),(165,5706,57,'期末贷方余额',NULL),(166,5707,57,'总账会计科目编号',NULL),(167,5708,57,'总账会计科目名称',NULL),(168,5709,57,'总账会计科目级次',NULL),(169,5710,57,'会计日期',NULL),(170,6,0,'附录','true');\n\n\n-- 数据源配置demo数据\nINSERT INTO `source_db_info` VALUES (1,'xt','xt','xtdb1','mysql+mysqldb://ceshi:1@1.2.3.4:1234/ceshi?charset=utf8mb4','1.2.3.4','ceshi','1','ceshi',1234,'mysql','utf8mb4','测试信息1'),(2,'zc','资产','zcdb1','oracle://cs:1@2.3.4.5:2345/?service_name=cs2','2.3.4.5','cs','1','cs2',2345,'oracle',NULL,''),(3,'db','担保','dbdb1','mssql+pymssql://cssscsc:1@3.4.5.6:3456/dbdbdbdb?charste=utf8','3.4.5.6','cssscsc','1','dbdbdbdb',3456,'sqlserver','utf8',''),(4,'xt','xt','xtdb2','oracle://ceshi2:1@4.5.6.7:4567/?service_name=ceshi2','4.5.6.7','ceshi2','1','ceshi2',4567,'oracle',NULL,NULL),(5,'xt','xt','xtdb3','mssql+pymssql://ceshi3:1@4.5.6.8:4568/ceshi3?charste=utf8','4.5.6.8','ceshi3','1','ceshi3',4568,'sqlserver',NULL,NULL),(8,'jj2','基金2','jjdb2','postgresql://bbb:1@2.2.2.2:2222/bbb','2.2.2.2','bbb','1','bbb',2222,'postgresql',NULL,NULL);\n\n\n-- 检核任务日志表demo数据\nINSERT INTO `check_execute_log` VALUES (256,'jz','2020-03-21 18:00:05','crontab',NULL,'success'),(257,'jj1','2020-03-21 18:00:06','crontab',NULL,'success'),(258,'jj2','2020-03-21 18:00:06','crontab','jjdb2','success'),(259,'zc','2020-03-21 18:00:10','crontab','zcdb1','success'),(260,'db','2020-03-21 18:00:30','crontab','dbdb1','success'),(261,'jk','2020-03-21 18:01:47','crontab',NULL,'success'),(262,'xt','2020-03-21 18:25:49','crontab','xtdb3','success'),(263,'jz','2019-12-30 16:00:00','crontab',NULL,'success'),(264,'jj1','2019-12-30 16:00:00','crontab',NULL,'success'),(265,'jj2','2019-12-30 16:00:00','crontab','jjdb2','success'),(266,'zc','2019-12-30 16:00:00','crontab','zcdb1','success'),(267,'db','2019-12-30 16:00:00','crontab','dbdb1','success'),(268,'jk','2019-12-30 16:00:00','crontab',NULL,'success'),(269,'xt','2019-12-30 16:00:00','crontab','xtdb3','success'),(270,'jz','2019-09-29 16:00:00','crontab',NULL,'success'),(271,'jj1','2019-09-29 16:00:00','crontab',NULL,'success'),(272,'jj2','2019-09-29 16:00:00','crontab','jjdb2','success'),(273,'zc','2019-09-29 16:00:00','crontab','zcdb1','success'),(274,'db','2019-09-29 16:00:00','crontab','dbdb1','success'),(275,'jk','2019-09-29 16:00:00','crontab',NULL,'success'),(276,'xt','2019-09-29 16:00:00','crontab','xtdb3','success'),(277,'jz','2019-06-29 16:00:00','crontab',NULL,'success'),(278,'jj1','2019-06-29 16:00:00','crontab',NULL,'success'),(279,'jj2','2019-06-29 16:00:00','crontab','jjdb2','success'),(280,'zc','2019-06-29 16:00:00','crontab','zcdb1','success'),(281,'db','2019-06-29 16:00:00','crontab','dbdb1','success'),(282,'jk','2019-06-29 16:00:00','crontab',NULL,'success'),(283,'xt','2019-06-29 16:00:00','crontab','xtdb3','success'),(284,'jz','2019-03-30 16:00:00','crontab',NULL,'success'),(285,'jj1','2019-03-30 16:00:00','crontab',NULL,'success'),(286,'jj2','2019-03-30 16:00:00','crontab','jjdb2','success'),(287,'zc','2019-03-30 16:00:00','crontab','zcdb1','success'),(288,'db','2019-03-30 16:00:00','crontab','dbdb1','success'),(289,'jk','2019-03-30 16:00:00','crontab',NULL,'success'),(290,'xt','2019-03-30 16:00:00','crontab','xtdb3','success'),(291,'db','2020-03-23 01:54:01','userA','dbdb1','success'),(292,'db','2020-03-23 01:57:08','userA','dbdb1','success'),(293,'zc','2020-03-23 01:58:10','userB','zcdb1','success'),(294,'db','2020-03-23 01:58:40','userB','dbdb1','success'),(295,'jj1','2020-03-23 01:58:49','userB',NULL,'success'),(296,'jj2','2020-03-23 01:58:52','userB','jjdb2','success'),(297,'jz','2020-03-23 01:58:55','userB',NULL,'success'),(298,'jk','2020-03-23 02:00:37','userB',NULL,'success'),(299,'xt','2020-03-23 02:30:20','userB','xtdb3','failed'),(300,'db','2020-03-23 02:43:38','userA','dbdb1','success'),(301,'db','2020-03-23 02:44:32','userA','dbdb1','success'),(302,'xt','2020-05-18 08:59:57','crontab','xtdb1','success'),(303,'xt','2020-05-18 08:59:57','crontab','xtdb2','success');\n\n\n\n-- ETL源-目标表demo数据\ninsert into datacenter_mapping values('DataCenter','m_ts_test_table_inc','src_test_table','ts_test_table');\ninsert into datacenter_mapping values('DataCenter','m_ts_test_table_inc','ts_test_table','th_test_table');\ninsert into datacenter_mapping values('DataCenter','m_ts_test_table_inc','ts_test_table','ti_test_table');\ninsert into datacenter_mapping values('DataCenter','m_ods_test_table_inc','ti_test_table','t_test_table');\n"
  },
  {
    "path": "docs/files_views.md",
    "content": "# 文件接口\n\n## list\n- URL：http://100.100.0.177/file/list\n- 功能：列出服务器`/data/data-quality/static/files`下的所有文件，文件下载调用`api/file/download`接口\n- 请求类型：GET\n- 请求参数：无\n- 返回值：无\n"
  },
  {
    "path": "docs/requirements.txt",
    "content": "astroid==2.3.3\nbackports.csv==1.0.7\ncertifi==2019.9.11\nchardet==3.0.4\ncron-descriptor==1.2.24\ncx-Oracle==7.2.2\nDateTime==4.3\ndefusedxml==0.6.0\nDjango==2.2.10\ndjango-bootstrap3==11.1.0\ndjango-bootstrap4==0.0.8\ndjango-debug-toolbar==2.0\ndjango-filter==2.2.0\ndjango-tables2==2.1.0\net-xmlfile==1.0.1\ngevent==1.4.0\ngreenlet==0.4.15\ngunicorn==19.9.0\nidna==2.8\nisort==4.3.21\njdcal==1.4.1\nJinja2==2.10.1\nlazy-object-proxy==1.4.3\nldap3==2.6\nlml==0.0.9\nMarkupSafe==1.1.1\nmccabe==0.6.1\nmeld3==1.0.2\nmysqlclient==1.4.4\nnumpy==1.17.0\nodfpy==1.4.0\nopenpyxl==2.5.14\npandas==1.0.3\nprettytable==0.7.2\npsycopg2==2.8.5\npyasn1==0.4.6\npyecharts==1.4.0\npyexcel==0.5.15\npyexcel-io==0.5.20\npyexcel-webio==0.1.4\npyexcel-xlsx==0.5.7\npylint==2.4.4\npymssql==2.1.4\npython-crontab==2.4.0\npython-dateutil==2.8.0\npytz==2019.2\nPyYAML==5.1.2\nredis==3.3.8\nrequests==2.22.0\nsimplejson==3.16.0\nsix==1.12.0\nSQLAlchemy==1.3.16\nsqlparse==0.3.0\nsupervisor==4.0.4\ntablib==0.13.0\ntexttable==1.6.2\ntyped-ast==1.4.1\nurllib3==1.25.5\nwrapt==1.11.2\nxlrd==1.2.0\nxlwt==1.3.0\nyapf==0.29.0\nzope.interface==4.6.0"
  },
  {
    "path": "docs/部署文档.md",
    "content": "# 运行环境\n环境|版本\n-|-\n操作系统|CentOS 7.6\n数据库|MySQL 5.7.24\nOracle客户端|11.2.0.4\n\n# 环境部署\n## 安装依赖包\n```\nyum install -y libaio*\nyum install postgresql-devel*\n```\n\n## MySQL安装\n略\n\n---\n\n## Django项目部署\n### 安装python3环境\n```\nyum install -y python3\nyum install -y python3-devel\nyum install -y mysql-devel\nyum install -y gcc\n```\n\n### 创建程序账号\n```\n# 创建程序账号\ngroupadd pyweb\nuseradd -g pyweb -m pyweb\npasswd pyweb\n\ngroupadd oinstall\nuseradd -g oinstall -m oracle\npasswd oracle\n```\n\n### 安装python虚拟环境\n```\n# 使用pyweb安装虚拟环境\nsu - pyweb\n\npip3 install --user virtualenv -i https://pypi.douban.com/simple/\npip3 install --user virtualenvwrapper -i https://pypi.douban.com/simple/\n\n# 配置pyweb用户的环境变量\nvim ~/.bash_profile\n## 加入以下内容\nexport WORKON_HOME=~/.virtualenvs\nexport VIRTUALENVWRAPPER_VIRTUALENV_ARGS='--no-site-packages'\nexport VIRTUALENVWRAPPER_PYTHON=/bin/python3\nsource /home/pyweb/.local/bin/virtualenvwrapper.sh\n```\n\n### 配置虚拟环境\n```\nmkvirtualenv django-2.1\n\npip3 install -r requirements.txt -i https://pypi.douban.com/simple/\n```\n\n### 代码部署\n```\nsu - root\nmkdir -p /data/pyweb\nchonw -R pyweb:pyweb /data/pyweb/\n\nsu - pyweb\ncd /data/pyweb/\ngit clone https://github.com/Hyhyhyhyhyhyh/Django-Data-quality-system.git\nmv Django-Data-quality-system data-quality\nmkdir -p /data/pyweb/data-quality/logs\n```\n\n### 初始化django数据库\n```\nworkon django-2.1\ncd /data/pyweb/data-quality\npython manage.py migrate\n```\n\n### 配置数据库连接\n- 创建数据库账号\n\n```\n# 创建django数据库及账号\nCREATE USER 'django'@'localhost' IDENTIFIED by 'Django^123';\ncreate database `django` default charset utf8mb4;\nGRANT ALL PRIVILEGES ON django.* TO 'django'@'localhost';\nflush privileges;\n\n# 创建数据质量管理平台数据库、表\nsource /data/pyweb/data-quality/docs/ddl.sql\n# 导入样例数据\nsource /data/pyweb/data-quality/docs/demo数据.sql\n# 导入日期维度表\nworkon django-2.1\npython /data/pyweb/data-quality/utils/generate_dim_date.py\n```\n\n- 配置数据库连接\n\n```\nvi /home/pyweb/.my.cnf\n[client]\ndatabase = django\nuser = django\npassword = Django^123\ndefault-character-set = utf8\nport = 3306\nsocket=/var/lib/mysql/mysql.sock\n```\n\n### 运行项目\n```\nworkon django-2.1\nnohup gunicorn mysite.wsgi -c /data/pyweb/data-quality/gconfig.py &\n```\n---\n\n## Nginx部署\n安装步骤略\n\n### 配置Nginx\n配置内容详见`nginx.conf`\n\n# 防火墙设置\n```\nservice iptables stop\n\n# 查看Firewalld状态\nfirewall-cmd --state\n\n# 启动firewalld服务\nsystemctl start firewalld\n\n# 把服务加入开机自启\nsystemctl enable firewalld.service\n\n# 放行端口号\nfirewall-cmd --zone=public --add-port=80/tcp --permanent\nfirewall-cmd --zone=public --add-port=3306/tcp --permanent\n\n# 重载防火墙配置\nfirewall-cmd --reload\n\n# 查看已放行端口\nfirewall-cmd --zone=public --list-ports\n\n# 禁用SELinux\nvim /etc/selinux/config\nSELINUX=permissive\n```\n"
  },
  {
    "path": "files/__init__.py",
    "content": ""
  },
  {
    "path": "files/admin.py",
    "content": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "files/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass FilesConfig(AppConfig):\n    name = 'files'\n"
  },
  {
    "path": "files/models.py",
    "content": "from django.db import models\n\n# Create your models here.\n"
  },
  {
    "path": "files/templates/files/file_list.html",
    "content": "{% include \"data/template-ui.html\" %}\n\n<div class=\"page-wrapper\">\n\t<!-- 正文 -->\n\t<div class=\"container-fluid animated fadeInUp\">\n\t\t<div class=\"col-12\">\n\t\t\t<div class=\"card\">\n\t\t\t\t<div class=\"card-title\">\n\t\t\t\t\t<div class=\"col-md-10\">\n                        <h4 class=\"text-primary\">{{ title }}</h4>\n                    </div>\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"card-content\">\n\t\t\t\t\t<table class=\"table table-hover\">\n                        <thead>\n                            <tr>\n                                <th>文档类型</th>\n                                <th>文件名</th>\n                                <th>操作</th>\n                            </tr>\n                        </thead>\n\n                        <tbody>\n                            {% for files in all_files %}\n                            <tr>\n                                <td><iframe src=\"../../static/icons/file-type-icons/file_type_{{ files.0 }}.svg\" width=\"26\" height=\"26\" frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\" allowtransparency=\"yes\"></iframe></td>\n                                <td>{{ files.1 }}</td>\n                                <td><a href=\"../../api/files/download?filename={{ files.1 }}\">下载</td>\n                            </tr>\n                            {% endfor %}\n                        </tbody>\n                    </table>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n    </div>\n</div>\n\n<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n    <div class=\"footer\">\n        © 2019 Hyhyhyhyhyhyh\n    </div>\n</footer>\n\n<!-- 设置头像 / 设置日期 -->\n<script src=\"/static/js/init.js\"></script>\n</body>\n\n</html>"
  },
  {
    "path": "files/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "files/views.py",
    "content": "import os\n\nfrom django.shortcuts import render\n\nfrom utils.functions import is_login\n\n\n@is_login\ndef list(request):\n    username = request.session['username']\n    request_type = request.GET.get('request_type')\n    file_name = os.listdir('/data/pyweb/data-quality/static/files')\n    title = '数据治理知识库'\n\n    if request_type == 'word_report':\n        file_name = [f for f in file_name if f.find('工作通报') != -1]\n        title = '数据治理工作通报'\n\n    all_files = []\n    for i in file_name:\n        file_type = i.split('.')\n        file_type = file_type[len(file_type) - 1]  # 获取文件扩展名\n        if file_type in ['xls', 'xlsx', 'xlsm', 'csv', 'xml']:\n            file_type = 'excel'\n        elif file_type in ['txt']:\n            file_type = 'text'\n        elif file_type in ['docx', 'doc']:\n            file_type = 'word'\n        elif file_type in ['htm', 'html']:\n            file_type = 'html'\n        elif file_type in ['ppt', 'pptx']:\n            file_type = 'powerpoint'\n        elif file_type in ['jpg', 'png', 'jpeg', 'gif', 'bmp']:\n            file_type = 'image'\n        all_files.append([file_type, i])\n    return render(request, 'files/file_list.html', {\n        'all_files': all_files,\n        'username': username,\n        'title': title\n    })\n"
  },
  {
    "path": "gconfig.py",
    "content": "# from gevent import monkey\n# monkey.patch_all()\n\nimport multiprocessing, logging\n\ndebug        = True\ntimeout      = 2000                     # 超时时间\nbind         = '0.0.0.0:9000'         # 提供web服务的端口，如果要跟容器通信，ip不能设置为localhost或127.0.0.1\nbacklog      = 2048                     # 监听队列\nchdir        = '/data/pyweb/data-quality'\nthreads      = multiprocessing.cpu_count() * 2   # 指定每个进程开启的线程数，实际并发数为workers * threads\nworkers      = multiprocessing.cpu_count() * 2 + 1\nworker_class = \"sync\"                 # 默认为阻塞sync模式（不设置threads为单线程），使用协程选择gevent模式\n\n# 日志设置\nloglevel          = 'debug'\npidfile           = '/data/pyweb/data-quality/logs/gunicorn.pid'\naccess_log_format = '%(t)s %(p)s %(h)s \"%(r)s\" %(s)s %(L)s %(b)s %(f)s\" \"%(a)s\"' \nerrorlog          = \"/data/pyweb/data-quality/logs/gunicorn_error.log\"        # 错误日志文件\ncapture_output    = True\naccesslog         = '-'"
  },
  {
    "path": "manage.py",
    "content": "#!/usr/bin/env python\n\"\"\"Django's command-line utility for administrative tasks.\"\"\"\nimport os\nimport sys\n\n\ndef main():\n    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')\n    try:\n        from django.core.management import execute_from_command_line\n    except ImportError as exc:\n        raise ImportError(\n            \"Couldn't import Django. Are you sure it's installed and \"\n            \"available on your PYTHONPATH environment variable? Did you \"\n            \"forget to activate a virtual environment?\"\n        ) from exc\n    execute_from_command_line(sys.argv)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "mysite/__init__.py",
    "content": ""
  },
  {
    "path": "mysite/db_config.py",
    "content": "import MySQLdb\nfrom sqlalchemy import create_engine\n\n\nmysql_host    = '127.0.0.1'\nmysql_port    = 3306\nconn_user     = 'system'\nconn_password = 'H5cT7yHB8_'\ndatabase      = 'data_quality'\nconn_charset  = 'utf8mb4'\nsocket        = '/var/lib/mysql/mysql.sock'\n    \n    \ndef mysql_connect():\n    conn = MySQLdb.connect(host=mysql_host,\n                           port=mysql_port,\n                           user=conn_user,\n                           passwd=conn_password,\n                           db=database,\n                           charset=conn_charset,\n                           unix_socket=socket,\n                           use_unicode=True)\n    return conn\n\n\ndef sqlalchemy_conn():\n    engine = create_engine(\n        f'mysql+mysqldb://{conn_user}:{conn_password}@{mysql_host}/{database}?charset={conn_charset}&unix_socket={socket}',\n        echo=False,                     # 打印sql语句\n        max_overflow=0,                 # 超过连接池大小外最多创建的连接\n        pool_size=5,                    # 连接池大小\n        pool_timeout=30,                # 池中没有线程最多等待的时间，否则报错\n        pool_recycle=-1,                # 多久之后对线程池中的线程进行一次连接的回收（重置）\n    )\n    return engine"
  },
  {
    "path": "mysite/settings.py",
    "content": "\"\"\"\nDjango settings for mysite project.\n\nGenerated by 'django-admin startproject' using Django 2.2.4.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/2.2/topics/settings/\n\nFor the full list of settings and their values, see\nhttps://docs.djangoproject.com/en/2.2/ref/settings/\n\"\"\"\n\nimport os\n\n# Build paths inside the project like this: os.path.join(BASE_DIR, ...)\nBASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n\n\n# Quick-start development settings - unsuitable for production\n# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/\n\n# SECURITY WARNING: keep the secret key used in production secret!\nSECRET_KEY = 'j@700h3_pkm@#6ql4xxol7z8=$t#y*uux8!8nkh5vzhc$_g#x!'\n\n# SECURITY WARNING: don't run with debug turned on in production!\nDEBUG = True\n\nALLOWED_HOSTS = ['*']\n\n\n# Application definition\n\nINSTALLED_APPS = [\n    'django.contrib.admin',\n    'django.contrib.auth',\n    'django.contrib.contenttypes',\n    'django.contrib.sessions',\n    'django.contrib.messages',\n    'django.contrib.staticfiles',\n    \n    'data',\n    'check',\n    'authorize',\n    'demand',\n    'files',\n    'api',\n    'standard',\n    'blood',\n    'backend',\n]\n\nMIDDLEWARE = [\n    'django.middleware.security.SecurityMiddleware',\n    'django.contrib.sessions.middleware.SessionMiddleware',\n    'django.middleware.common.CommonMiddleware',\n    # 'django.middleware.csrf.CsrfViewMiddleware',\n    'django.contrib.auth.middleware.AuthenticationMiddleware',\n    'django.contrib.messages.middleware.MessageMiddleware',\n    'django.middleware.clickjacking.XFrameOptionsMiddleware',\n]\n\nROOT_URLCONF = 'mysite.urls'\n\nTEMPLATES = [\n    {\n        'BACKEND': 'django.template.backends.django.DjangoTemplates',\n        'DIRS': [os.path.join(BASE_DIR, 'templates'),],\n        'APP_DIRS': True,\n        'OPTIONS': {\n            'context_processors': [\n                'django.template.context_processors.debug',\n                'django.template.context_processors.request',\n                'django.contrib.auth.context_processors.auth',\n                'django.contrib.messages.context_processors.messages',\n            ],\n        },\n    },\n]\n\nWSGI_APPLICATION = 'mysite.wsgi.application'\n\n\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.mysql',\n        'OPTIONS': {\n            'read_default_file': '/home/pyweb/.my.cnf',\n        },\n    }\n}\n\n\n# Password validation\n# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators\n\nAUTH_PASSWORD_VALIDATORS = [\n    {\n        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',\n    },\n]\n\n\n# Internationalization\n# https://docs.djangoproject.com/en/2.2/topics/i18n/\n\nLANGUAGE_CODE = 'en-us'\n\nTIME_ZONE = 'Asia/Shanghai'\n\nUSE_I18N = True\n\nUSE_L10N = True\n\nUSE_TZ = True\n\n\n# Static files (CSS, JavaScript, Images)\n# https://docs.djangoproject.com/en/2.2/howto/static-files/\n\nSTATIC_URL = '/static/'\n\nSTATICFILES_DIRS = (\n    os.path.join(BASE_DIR, 'static'),     # BASE_DIR是项目的绝对路径，在连上static,就是static目录的路径了\n)\n"
  },
  {
    "path": "mysite/source_db_config.py",
    "content": "import MySQLdb\nimport pymssql\nimport cx_Oracle\nimport os\n\n# SQL server数据库\ndef sqlserver_db():\n    conn = pymssql.connect(host='',\n                           user='',\n                           password='',\n                           database='',\n                           charset='utf8'\n                           )\n    return conn\n\n# Oracle数据库\ndef oracle_db():\n    os.environ['NLS_LANG']    = 'AMERICAN_AMERICA.UTF8'\n    os.environ['ORACLE_HOME'] = ''\n    conn = cx_Oracle.connect('')\n    return conn\n\n# MySQL数据库\ndef mysql_db():\n    conn = MySQLdb.connect(host='',\n                           port='',\n                           user='',\n                           passwd='',\n                           db='',\n                           charset='utf8',\n                           use_unicode=True\n                           )\n    return conn\n"
  },
  {
    "path": "mysite/urls.py",
    "content": "\"\"\"mysite URL Configuration\n\nThe `urlpatterns` list routes URLs to views. For more information please see:\n    https://docs.djangoproject.com/en/2.2/topics/http/urls/\nExamples:\nFunction views\n    1. Add an import:  from my_app import views\n    2. Add a URL to urlpatterns:  path('', views.home, name='home')\nClass-based views\n    1. Add an import:  from other_app.views import Home\n    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')\nIncluding another URLconf\n    1. Import the include() function: from django.urls import include, path\n    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))\n\"\"\"\nfrom django.contrib import admin\nfrom django.urls import include,path\nfrom django.views.generic import RedirectView\nfrom django.views.static import serve\nfrom django.conf.urls import url\n\nfrom data import views as dataView\nfrom authorize import views as authView\nfrom check import views as checkView\nfrom demand import views as demandView\nfrom files import views as filesView\nfrom standard import views as stdView\nfrom backend import views as beView\nfrom blood import views as bloodView\nfrom api import api_files as api_filesView\nfrom api import api_dashboard as api_dashView\nfrom api import api_datastandard as api_stdView\nfrom api import api_check as api_checkView\nfrom api import api_date as api_dateView\nfrom api import api_quality as api_qualityView\nfrom api import api_backend as api_beView\nfrom api import api_blood as api_bloodView\n\nurlpatterns = [\n    url(r'^static/(?P<path>.*)$', serve, {'document_root': '/data/pyweb/data-quality/static'}, name='static'),\n\n    # 仪表盘\n    path('data/dashboard/',             dataView.dashboard,                   name='dashboard'),\n    path('data/dashboard/subcompany',   dataView.dashboard_subcompany,        name='dashboard_subcompany'),\n    path('data/report',                dataView.report,                      name='report'),\n    path('data/result_detail',         dataView.result_detail,               name='result_detail'),\n    path('',                            RedirectView.as_view(url='data/dashboard/')),\n    path('data',                        RedirectView.as_view(url='data/dashboard/')),\n    path('data/index',                  RedirectView.as_view(url='../data/dashboard/')),\n\n    # 登录身份验证\n    path('authorize/login/',     authView.login,      name='login'),\n    path('authorize/logout/',    authView.logout,     name='logout'),\n    path('authorize/login_auth', authView.login_auth, name='login_auth'),\n\n    # 检核\n    path('check/rule',          checkView.rule_list,            name='rule'),\n    path('check/rule/edit',     checkView.rule_edit,            name='rule_edit'),\n    path('check/rule/exec',     checkView.rule_execute_manual,  name='rule_execute_manual'),\n    # 检核定时任务\n    path('check/crontab',       checkView.show_crontab,        name='show_crontab'),\n    # 血缘分析\n    path('blood/analyze',       bloodView.analyze,      name='blood_analyze'),\n\n    # 源系统改造需求\n    path('demand/import_sheet', demandView.import_sheet, name='import_sheet'),\n\n    # 附件管理\n    path('files/list', filesView.list, name='files_list'),\n\n    # 数据标准\n    path('datastandard/show',   stdView.show,   name='std_show'),\n    path('datastandard/update', stdView.update, name='update'),\n    \n    # 后台管理\n    path('backend/database',   beView.database,    name='database'),\n    path('backend/database/detail',   beView.database_detail,    name='database_detail'),\n    path('backend/database/add',   beView.database_add,    name='database_add'),\n    path('backend/crontab',   beView.crontab,    name='crontab'),\n\n    # API\n    path('api/date/year',       api_dateView.year_list,     name='year_list'),\n    path('api/date/quarter',    api_dateView.quarter_list,  name='quarter_list'),\n    path('api/date/month',      api_dateView.month_list,    name='month_list'),\n    path('api/date/day',        api_dateView.day_list,      name='day_list'),\n    \n    path('api/demand/list_subcompany',               demandView.list_subcompany,              name='demand_list_subcompany'),\n    path('api/files/download',                       api_filesView.download,                  name='files_download'),\n\n    path('api/dashboard/avg_problem_percentage',     api_dashView.avg_problem_percentage,     name='avg_problem_percentage'),\n    path('api/dashboard/same_problem_top5',          api_dashView.same_problem_top5,          name='same_problem_top5'),\n    path('api/dashboard/count_db_rows',              api_dashView.count_db_rows,              name='count_db_rows'),\n    path('api/dashboard/data_overview_total',        api_dashView.data_overview_total,        name='data_overview_total'),\n    path('api/dashboard/data_overview_company',      api_dashView.data_overview_company,      name='data_overview_company'),\n    path('api/dashboard/total_trend',                api_dashView.total_trend,                name='total_trend'),\n    path('api/dashboard/subcompany_problem_count',   api_dashView.subcompany_problem_count,   name='subcompany_problem_count'),\n    path('api/dashboard/subcompany_data_percentage', api_dashView.subcompany_data_percentage, name='subcompany_data_percentage'),\n    path('api/dashboard/data_overview_company_trend', api_dashView.data_overview_company_trend, name='data_overview_company_trend'),\n\n    path('api/datastandard/query/detail',            api_stdView.query_detail,                name='query_detail'),\n    path('api/datastandard/update',                  api_stdView.update,                      name='update'),\n    path('api/datastandard/query/index',             api_stdView.query_index,                 name='query_index'),\n    path('api/datastandard/query/history',           api_stdView.query_update_history,        name='query_update_history'),\n    \n    path('api/check/rule',                           api_checkView.rule,                      name='api_rule'),\n    path('api/check/rule/detail',                    api_checkView.rule_detail,               name='rule_detail'),\n    path('api/check/rule/update',                    api_checkView.rule_update,               name='rule_update'),\n    path('api/check/rule/add',                       api_checkView.rule_add,                  name='rule_add'),\n    path('api/check/rule/status_modify',             api_checkView.rule_status_modify,        name='rule_status_modify'),\n    path('api/check/rule/execute',                   api_checkView.rule_execute,              name='rule_execute'),\n    path('api/check/progress',                       api_checkView.query_check_progress,      name='query_check_progress'),\n    \n    # 检核结果明细\n    path('api/quality/detail',                       api_qualityView.quality_detail,          name='quality_detail'),\n    path('api/quality/report',                       api_qualityView.report_detail,           name='report_detail'),\n    \n    path('api/backend/database/query',           api_beView.db_query,        name='db_query'),\n    path('api/backend/database/update',           api_beView.db_update,        name='db_update'),\n    path('api/backend/database/insert',           api_beView.db_insert,        name='db_insert'),\n    path('api/backend/crontab/enable',          api_beView.crontab_enable,            name='crontab_enable'),\n    path('api/backend/crontab/run',          api_beView.crontab_run,            name='crontab_run'),\n    \n    path('api/blood/mapping',                  api_bloodView.query_mapping,             name='api_blood_query_mapping'),\n]\n"
  },
  {
    "path": "mysite/wsgi.py",
    "content": "\"\"\"\nWSGI config for mysite project.\n\nIt exposes the WSGI callable as a module-level variable named ``application``.\n\nFor more information on this file, see\nhttps://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/\n\"\"\"\n\nimport os\n\nfrom django.core.wsgi import get_wsgi_application\n\nos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')\n\napplication = get_wsgi_application()\n"
  },
  {
    "path": "nginx.conf",
    "content": "# 如果使用容器，则使用以下命令启动nginx\n# docker run -d \\\n#     -p 80:80 \\\n#     --volume /data/nginx/nginx.conf:/etc/nginx/nginx.conf \\\n#     --volume /data/pyweb/data-quality/static:/data/pyweb/data-quality/static \\\n#     --name nginx \\\n#     nginx\n\n\n# nginx.conf\nuser  nginx;\nworker_processes  1;\n\nerror_log  /var/log/nginx/error.log warn;\npid        /var/run/nginx.pid;\n\nevents {\n    worker_connections  1024;\n}\n\nhttp {\n    include       /etc/nginx/mime.types;\n    default_type  application/octet-stream;\n\n    log_format  main  '$remote_addr - $remote_user [$time_local] \"$request\" '\n                      '$status $body_bytes_sent \"$http_referer\" '\n                      '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n\n    access_log  /var/log/nginx/access.log  main;\n\n    sendfile        on;\n    #tcp_nopush     on;\n    client_max_body_size 50M;\n    keepalive_timeout  65;\n\n    # gzip  on;\n\n    include /etc/nginx/conf.d/*.conf;\n\n    upstream dataquality{\n        # 容器部署nginx方式启用以下配置\n        # server 172.18.0.1:9000;\n        server 0.0.0.0:9000;\n    }\n\n    server {\n        listen 80;\n        server_name dataquality;\n\n        location /static {\n                alias /data/pyweb/data-quality/static;\n        }\n\n        location / {\n            proxy_set_header Host $host;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_pass http://dataquality;\n        }\n    }\n}"
  },
  {
    "path": "standard/__init__.py",
    "content": ""
  },
  {
    "path": "standard/admin.py",
    "content": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "standard/apps.py",
    "content": "from django.apps import AppConfig\n\n\nclass StandardConfig(AppConfig):\n    name = 'standard'\n"
  },
  {
    "path": "standard/models.py",
    "content": "from django.db import models\n\n# Create your models here.\n"
  },
  {
    "path": "standard/templates/standard/show.html",
    "content": "{% include \"data/template-ui.html\" %}\n<link rel=\"stylesheet\" href='/static/zTree/css/zTreeStyle.css'>\n<style>\n    #std td {\n        font-size: 15px;\n        color: black !important;\n        text-align: left !important;\n        vertical-align: top;\n        width: 15px;\n        padding-top: 10px;\n    }\n\n    #desc {\n        white-space: pre-wrap;\n        color: black !important;\n        line-height: 30px;\n    }\n\n    #key {\n        width: 150px;\n        margin-left: 30px;\n        margin-top: -5px;\n        height: 30px;\n        font-size: 14px;\n    }\n</style>\n\n<!-- 正文主体 -->\n<div class=\"page-wrapper\">\n    <div class=\"row page-titles\">\n        <div class=\"col-md-6 align-self-center\">\n            <h3 class=\"text-primary\">数据标准</h3>\n        </div>\n\n        <div class=\"col-md-6 align-self-center\">\n            <ol class=\"breadcrumb\">\n                <li class=\"breadcrumb-item\"><a href=\"../../data/dashboard/\">主页</a></li>\n                <li class=\"breadcrumb-item active\">数据标准</li>\n            </ol>\n        </div>\n    </div>\n\n\n    <div class=\"container-fluid\">\n        <div class=\"row\">\n            <div class=\"col-md-3\">\n                <div class=\"card\">\n                    <div class=\"row\">\n                        <h5 style=\"color:black;font-weight:600;\">目录</h5>\n                        <input type=\"text\" id=\"key\" value=\"\" class=\"empty form-control\" placeholder=\"搜索关键字\"/>\n                    </div>\n\n                    <ul id=\"treeDemo\" class=\"ztree\"></ul>\n                </div>\n            </div>\n\n            <div class=\"col-md-8\">\n                <div class=\"card\" onload=\"FristLoad();\">\n                    <!-- 标准标题 -->\n                    <div class=\"row\">\n                        <div class=\"col-md-10\">\n                            <h3 style=\"color:black;font-weight:600;\" id=\"std_title\"></h3>\n                        </div>\n\n                        <div class=\"col-md-2 pull-right\">\n\t\t\t\t\t\t\t<a id=\"edit\" href=\"\" style=\"margin-right:5px;border-bottom: 1px dotted;color: #1779ba;\">编辑标准</a>\n                        </div>\n                    </div>\n\n                    <!-- 标准概述 -->\n                    <span id=\"desc\"></span>\n\n                    <!-- 标准明细 -->\n                    <table class=\"table-hover\" id=\"std\" style=\"display: none;table-layout: fixed;width: 100%;\">\n                        <tr>\n                            <td style=\"width: 20%;\">标准编号</h5></td>\n                            <td style=\"width: 80%;\" id=\"std_id\"></td>\n                        </tr>\n\n                        <tr>\n                            <td>标准中文名称</td>\n                            <td id=\"name\"></td>\n                        </tr>\n\n                        <tr>\n                            <td>标准英文名称</td>\n                            <td id=\"en_name\"></td>\n                        </tr>\n\n                        <tr>\n                            <td>业务定义</h5></td>\n                            <td id=\"business_definition\"></td>\n                        </tr>\n\n                        <tr>\n                            <td>业务规则</td>\n                            <td id=\"business_rule\"></td>\n                        </tr>\n\n                        <tr>\n                            <td>标准来源</td>\n                            <td id=\"std_source\"></td>\n                        </tr>\n\n                        <tr>\n                            <td>数据类别</td>\n                            <td id=\"data_type\"></td>\n                        </tr>\n\n                        <tr>\n                            <td>数据格式</td>\n                            <td id=\"data_format\"></td>\n                        </tr>\n\n                        <tr>\n                            <td>代码编码规则</td>\n                            <td id=\"code_rule\"></td>\n                        </tr>\n\n                        <tr>\n                            <td>取值范围</td>\n                            <td id=\"code_range\"></td>\n                        </tr>\n\n                        <tr>\n                            <td>代码取值含义</h5></td>\n                            <td id=\"code_meaning\"></td>\n                        </tr>\n\n                        <tr>\n                            <td>数据业务范围</td>\n                            <td id=\"business_range\"></td>\n                        </tr>\n\n                        <tr>\n                            <td>数据责任部门</h5></td>\n                            <td id=\"dept\"></td>\n                        </tr>\n\n                        <tr>\n                            <td>数据使用系统</td>\n                            <td id=\"system\"></td>\n                        </tr>\n                    </table>\n\n                    <div class=\"row\" style=\"margin-top: 30px;\">\n                        <div class=\"col-md-8 text-right\">\n                            <h5 class=\"update_info\">最后编辑：<span id=\"update_user\"></span></h5>\n                        </div>\n                        <div class=\"col-lg-4 text-left\">\n                            <h5 class=\"update_info\">编辑时间：<span id=\"update_time\"></span></h5>\n                        </div>\n                    </div>\n\n                </div>\n            </div>\n\n        </div>\n    </div>\n</div>\n\n<!-- footer -->\n<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n    <div class=\"footer\">\n        © 2019 Hyhyhyhyhyhyh\n    </div>\n</footer>\n</div>\n\n<!-- 设置头像 / 设置日期 -->\n<script src=\"/static/js/init.js\"></script>\n\n<script src='/static/zTree/js/jquery.ztree.core.min.js'></script>\n<script src='/static/zTree/js/fuzzysearch.js'></script>\n<script src='/static/zTree/js/jquery.ztree.exhide.min.js'></script>\n\n<SCRIPT type=\"text/javascript\">\n    var setting = {\n        data: {\n            key: {\n                title:\"t\"\n            },\n            simpleData: {\n                enable: true\n            }\n        },\n        callback: {\n            beforeClick: beforeClick,\n            onClick: onClick\n        },\n        async: {\n            enable: true,\n            url:\"../../api/datastandard/query/index\",\n            autoParam:[\"id\", \"pId\", \"name\", \"t\", \"open\"],\n            type: \"get\",\n            //otherParam:{\"otherParam\":\"zTreeAsyncTest\"},\n            //dataFilter: filter\n        },\n\n    };\n\n    var log, className = \"dark\";\n    function beforeClick(treeId, treeNode, clickFlag) {\n        className = (className === \"dark\" ? \"\":\"dark\");\n        showLog(\"[ \"+getTime()+\" beforeClick ]&nbsp;&nbsp;\" + treeNode.name );\n        return (treeNode.click != false);\n    }\n    function onClick(event, treeId, treeNode, clickFlag) {\n        //console.log(treeNode);\n        if (treeNode.level < 2){\n            $.ajax({\n                type : \"GET\",\n                async : false,\n                url : \"../../api/datastandard/query/detail\",\n                data: {\n                    std_name: treeNode.t,\n                    std_type: \"desc\"        //标准概述\n                },\n                dataType : \"json\",\n                success : function(result) {\n                    document.getElementById(\"std_title\").innerText = treeNode.t;\n                    document.getElementById(\"std\").style.display=\"none\";\n                    document.getElementById(\"desc\").style.display=\"\";\n                    document.getElementById(\"desc\").innerText = result.content;\n\n                    document.getElementById(\"edit\").href = \"../../datastandard/update?std_name=\" + treeNode.t + \"&std_type=desc\";\n                },\n            })\n        }\n        else {\n            $.ajax({\n                type : \"GET\",\n                async : false,\n                url : \"../../api/datastandard/query/detail\",\n                data: {\n                    std_name: treeNode.t,\n                    std_type: \"detail\"      //标准名\n                },\n                dataType : \"json\",\n                success : function(result) {\n                    document.getElementById(\"std_title\").innerText = treeNode.t;\n                    document.getElementById(\"std\").style.display=\"\";\n                    document.getElementById(\"desc\").style.display=\"none\";\n                    document.getElementById(\"std_id\").innerText = result.std_id;\n                    document.getElementById(\"name\").innerText = result.name;\n                    document.getElementById(\"en_name\").innerText = result.en_name;\n                    document.getElementById(\"business_definition\").innerText = result.business_definition;\n                    document.getElementById(\"business_rule\").innerText = result.business_rule;\n                    document.getElementById(\"std_source\").innerText = result.std_source;\n                    document.getElementById(\"data_type\").innerText = result.data_type;\n                    document.getElementById(\"data_format\").innerText = result.data_format;\n                    document.getElementById(\"code_rule\").innerText = result.code_rule;\n                    document.getElementById(\"code_range\").innerText = result.code_range;\n                    document.getElementById(\"code_meaning\").innerText = result.code_meaning;\n                    document.getElementById(\"business_range\").innerText = result.business_range;\n                    document.getElementById(\"dept\").innerText = result.dept;\n                    document.getElementById(\"system\").innerText = result.system;\n\n                    document.getElementById(\"edit\").href = \"../../datastandard/update?std_name=\" + treeNode.t + \"&std_type=detail\";\n                },\n            })\n        }\n    }\n    function showLog(str) {\n        if (!log) log = $(\"#log\");\n        log.append(\"<li class='\"+className+\"'>\"+str+\"</li>\");\n        if(log.children(\"li\").length > 8) {\n            log.get(0).removeChild(log.children(\"li\")[0]);\n        }\n    }\n    function getTime() {\n        var now= new Date(),\n        h=now.getHours(),\n        m=now.getMinutes(),\n        s=now.getSeconds();\n        return (h+\":\"+m+\":\"+s);\n    }\n\n    $(document).ready(function(){\n        //$.fn.zTree.init($(\"#treeDemo\"), setting, zNodes);   //初始化zTree\n        $.fn.zTree.init($(\"#treeDemo\"), setting);\n        fuzzySearch('treeDemo','#key',null,null);           //初始化模糊搜索方法\n        \n        if (typeof(document.referrer.split('?')[1]) == \"undefined\"){\n            var init_name = '概述';\n            var std_type  = 'desc';\n        }\n        else {\n            var url_param = document.referrer.split('?')[1].split('=')[0];\n            if (url_param != 'std_name'){\n                var init_name = '概述';\n                var std_type  = 'desc';\n            }\n            else {\n                var init_name = decodeURI(document.referrer.split('?')[1].split('=')[1].split('&')[0]);\n                var std_type  = decodeURI(document.referrer.split('?')[1].split('&')[1].split('=')[1]);\n            }\n        }\n\n        document.getElementById(\"edit\").href = \"../../datastandard/update?std_name=\" + init_name + \"&std_type=\" + std_type;\n\n        //初始化数据标准内容\n        $.ajax({\n            type : \"GET\",\n            async : false,\n            url : \"../../api/datastandard/query/detail\",\n            data: {\n                std_name: init_name,\n                std_type: std_type,\n            },\n            dataType : \"json\",\n            success : function(result) {\n                if (std_type == 'desc'){\n                    document.getElementById(\"std_title\").innerText = init_name;\n                    document.getElementById(\"std\").style.display=\"none\";\n                    document.getElementById(\"desc\").style.display=\"\";\n                    document.getElementById(\"desc\").innerText = result.content;\n                    document.getElementById(\"edit\").href = \"../../datastandard/update?std_name=\" + init_name + \"&std_type=desc\";\n                }\n                else {\n                    document.getElementById(\"std_title\").innerText = init_name;\n                    document.getElementById(\"std\").style.display=\"\";\n                    document.getElementById(\"desc\").style.display=\"none\";\n                    document.getElementById(\"std_id\").innerText = result.std_id;\n                    document.getElementById(\"name\").innerText = result.name;\n                    document.getElementById(\"en_name\").innerText = result.en_name;\n                    document.getElementById(\"business_definition\").innerText = result.business_definition;\n                    document.getElementById(\"business_rule\").innerText = result.business_rule;\n                    document.getElementById(\"std_source\").innerText = result.std_source;\n                    document.getElementById(\"data_type\").innerText = result.data_type;\n                    document.getElementById(\"data_format\").innerText = result.data_format;\n                    document.getElementById(\"code_rule\").innerText = result.code_rule;\n                    document.getElementById(\"code_range\").innerText = result.code_range;\n                    document.getElementById(\"code_meaning\").innerText = result.code_meaning;\n                    document.getElementById(\"business_range\").innerText = result.business_range;\n                    document.getElementById(\"dept\").innerText = result.dept;\n                    document.getElementById(\"system\").innerText = result.system;\n                    document.getElementById(\"edit\").href = \"../../datastandard/update?std_name=\" + init_name + \"&std_type=detail\";\n                }\n            },\n        })\n\n        $.ajax({\n            type : \"GET\",\n            async : false,\n            url : \"../../api/datastandard/query/history\",\n            data: {\n                std_name: init_name,\n            },\n            dataType : \"json\",\n            success : function(result) {\n                document.getElementById(\"update_user\").innerText = result.username;\n                document.getElementById(\"update_time\").innerText = result.last_update_time;\n            }\n        })\n    });\n</SCRIPT>\n</body>\n\n</html>"
  },
  {
    "path": "standard/templates/standard/update.html",
    "content": "{% load staticfiles %}\n<!DOCTYPE html>\n<html lang=\"zh-cmn-Hans\">\n\n<head>\n\t<meta charset=\"utf-8\">\n\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n\t<!-- Tell the browser to be responsive to screen width -->\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\t<meta name=\"description\" content=\"\">\n\t<meta name=\"author\" content=\"\">\n\t<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"{% static 'img/favicon.ico' %}\" />\n\t<title>数据质量检核平台</title>\n\n\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"{% static 'check/css/admin/bootstrap.min.css' %}\" />\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"{% static 'check/css/admin/style.css' %}\" />\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"{% static 'css/animate.css' %}\" />\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"{% static 'css/fonts.css' %}\" />\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"{% static 'css/icons.css' %}\" />\n\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{% static 'css/sweetalert.css' %}\" />\n    \n    <style>\n        textarea {\n            white-space:pre-wrap;\n        }\n    </style>\n</head>\n\n<body>\n\t<!-- head star -->\n\t<div class=\"tnav row wrapper border-bottom white-bg page-heading\">\n\t\t<div class=\"col-sm-4\">\n\t\t\t<h2 class=\"fl\" style=\"color: #007bff;font-size: 21px;font-weight:500\">数据质量检核规则库</h2>\n\t\t\t<ol class=\"breadcrumb fl\">\n\t\t\t\t<li><a href=\"../../data/index\">主页</a></li>\n\t\t\t\t<li><strong>数据标准</strong></li>\n\t\t\t</ol>\n\t\t</div>\n\t</div>\n\t<!-- head end -->\n\n\t<!-- table star -->\n\t<div class=\"row col-lg-12\">\n\t\t<div class=\"wrapper wrapper-content animated fadeInUp\">\n\t\t\t<div class=\"ibox\">\n\t\t\t\t<div class=\"ibox-title\">\n\t\t\t\t\t<h5>编辑数据标准-{{ std_name }}</h5>\n\t\t\t\t\t<div class=\"ibox-tools rboor\">\n\t\t\t\t\t\t<a href=\"javascript:void(0)\" id=\"commit\" class=\"btn btn-primary btn-xs p310\"><i class=\"im-reply\"></i> 提交</a>\n\t\t\t\t\t</div>\n                </div>\n                \n                <!-- 修改标准概述 -->\n                <div id=\"desc\" class=\"ibox-content\" style=\"display: none;\">\n                    <div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">标题</label>\n\t\t\t\t\t\t\t<input id=\"desc_name\" type=\"text\" class=\"form-control\" style=\"width: 400px;\" value=\"\">\n\t\t\t\t\t\t</div>\n                    </div>\n                    \n                    <div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">内容</label>\n\t\t\t\t\t\t\t<textarea id=\"content\" type=\"text\" class=\"form-control\" style=\"width: 800px;height:400px;\" value=\"\"></textarea>\n\t\t\t\t\t\t</div>\n                    </div>\n                </div>\n\n                <!-- 修改标准明细 -->\n\t\t\t\t<div id=\"std\" class=\"ibox-content\" style=\"display: none;\">\n\t\t\t\t\t<div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">标准编号</label>\n\t\t\t\t\t\t\t<input id=\"std_id\" type=\"text\" class=\"form-control\" style=\"width: 400px;\" value=\"\">\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">标准中文名称</label>\n\t\t\t\t\t\t\t<input id=\"std_name\" type=\"text\" class=\"form-control\" style=\"width: 400px;\" value=\"\">\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">标准英文名称</label>\n\t\t\t\t\t\t\t<input id=\"en_name\" type=\"text\" class=\"form-control\" style=\"width: 400px;\" value=\"\">\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">业务定义</label>\n\t\t\t\t\t\t\t<textarea id=\"business_definition\" type=\"text\" class=\"form-control\" style=\"width: 800px;\" value=\"\"></textarea>\n\t\t\t\t\t\t</div>\n                    </div>\n                    \n                    <div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">业务规则</label>\n\t\t\t\t\t\t\t<textarea id=\"business_rule\" type=\"text\" class=\"form-control\" style=\"width: 800px;\" value=\"\"></textarea>\n\t\t\t\t\t\t</div>\n                    </div>\n                    \n                    <div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">标准来源</label>\n\t\t\t\t\t\t\t<textarea id=\"std_source\" type=\"text\" class=\"form-control\" style=\"width: 800px;\" value=\"\"></textarea>\n\t\t\t\t\t\t</div>\n                    </div>\n                    \n                    <div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">数据类别</label>\n\t\t\t\t\t\t\t<input id=\"data_type\" type=\"text\" class=\"form-control\" style=\"width: 800px;\" value=\"\">\n\t\t\t\t\t\t</div>\n                    </div>\n                    \n                    <div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">业务定义</label>\n\t\t\t\t\t\t\t<textarea id=\"business_definition\" type=\"text\" class=\"form-control\" style=\"width: 800px;\" value=\"\"></textarea>\n\t\t\t\t\t\t</div>\n                    </div>\n                    \n                    <div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">数据格式</label>\n\t\t\t\t\t\t\t<input id=\"data_format\" type=\"text\" class=\"form-control\" style=\"width: 800px;\" value=\"\">\n\t\t\t\t\t\t</div>\n                    </div>\n                    \n                    <div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">代码编码规则\t</label>\n\t\t\t\t\t\t\t<textarea id=\"code_rule\" type=\"text\" class=\"form-control\" style=\"width: 1200px;\" value=\"\"></textarea>\n\t\t\t\t\t\t</div>\n                    </div>\n                    \n                    <div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">取值范围</label>\n\t\t\t\t\t\t\t<textarea id=\"code_range\" type=\"text\" class=\"form-control\" style=\"width: 1200px;\" value=\"\"></textarea>\n\t\t\t\t\t\t</div>\n                    </div>\n                    \n                    <div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">代码取值含义</label>\n\t\t\t\t\t\t\t<textarea id=\"code_meaning\" type=\"text\" class=\"form-control\" style=\"width: 1200px;\" value=\"\"></textarea>\n\t\t\t\t\t\t</div>\n                    </div>\n                    \n                    <div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">数据业务范围</label>\n\t\t\t\t\t\t\t<textarea id=\"business_range\" type=\"text\" class=\"form-control\" style=\"width: 1200px;\" value=\"\"></textarea>\n\t\t\t\t\t\t</div>\n                    </div>\n                    \n                    <div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">数据责任部门</label>\n\t\t\t\t\t\t\t<input id=\"dept\" type=\"text\" class=\"form-control\" style=\"width: 400px;\" value=\"\">\n\t\t\t\t\t\t</div>\n                    </div>\n                    \n                    <div class=\"row\">\n\t\t\t\t\t\t<div class=\"form-group col-sm-8 col-md-10\">\n\t\t\t\t\t\t\t<label class=\"form-label\">数据使用系统</label>\n\t\t\t\t\t\t\t<input id=\"system\" type=\"text\" class=\"form-control\" style=\"width: 300px;\" value=\"\">\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t<!-- table end -->\n\t<footer class=\"navbar-fixed-bottom\" style=\"line-height: 10px;font-size:13px;\">\n\t\t<div class=\"footer\">\n\t\t\t© 2019 Hyhyhyhyhyhyh\n\t\t</div>\n\t</footer>\n\n\t<script type=\"text/javascript\" src=\"{% static 'js/lib/jquery/jquery.min.js' %}\"></script>\n\t<script type=\"text/javascript\" src=\"{% static 'js/lib/bootstrap/js/bootstrap.min.js' %}\"></script>\n\n\t<script type=\"text/javascript\" src=\"{% static 'js/sweetalert.min.js' %}\"></script>\n\n\t<script>\n\t\t$(document).ready(function(){\n            //初始化页面\n            if (\"{{std_type}}\" == 'desc'){\n                $.ajax({\n                    type : \"GET\",\n                    async : false,\n                    url : \"../../api/datastandard/query/detail\",\n                    data: {\n                        std_name: \"{{ std_name }}\",\n                        std_type: \"desc\"\n                    },\n                    dataType : \"json\",\n                    success : function(result) {\n                        document.getElementById(\"std\").style.display=\"none\";\n                        document.getElementById(\"desc\").style.display=\"\";\n                        document.getElementById(\"desc_name\").value = result.name;\n                        document.getElementById(\"content\").value = result.content;\n\n                        //textarea高度自适应\n                        $.each($(\"textarea\"), function(i, n){\n                            $(n).css(\"height\", n.scrollHeight + \"px\");\n                        })\n                    },\n                })\n            }\n            else {\n                $.ajax({\n                    type : \"GET\",\n                    async : false,\n                    url : \"../../api/datastandard/query/detail\",    \n                    data: {\n                        std_name: \"{{ std_name }}\",\n                        std_type: \"detail\"\n                    },\n                    dataType : \"json\",\n                    success : function(result) {\n                        console.log(result);\n                        document.getElementById(\"std\").style.display=\"\";\n                        document.getElementById(\"desc\").style.display=\"none\";\n                        document.getElementById(\"std_id\").value = result.std_id;\n                        document.getElementById(\"std_name\").value = result.name;\n                        document.getElementById(\"en_name\").value = result.en_name;\n                        document.getElementById(\"business_definition\").value = result.business_definition;\n                        document.getElementById(\"business_rule\").value = result.business_rule;\n                        document.getElementById(\"std_source\").value = result.std_source;\n                        document.getElementById(\"data_type\").value = result.data_type;\n                        document.getElementById(\"data_format\").value = result.data_format;\n                        document.getElementById(\"code_rule\").value = result.code_rule;\n                        document.getElementById(\"code_range\").value = result.code_range;\n                        document.getElementById(\"code_meaning\").value = result.code_meaning;\n                        document.getElementById(\"business_range\").value = result.business_range;\n                        document.getElementById(\"dept\").value = result.dept;\n                        document.getElementById(\"system\").value = result.system;\n\n                        //textarea高度自适应\n                        $.each($(\"textarea\"), function(i, n){\n                            $(n).css(\"height\", n.scrollHeight + \"px\");\n                        })\n                    },\n                })\n            }\n        });\n\n        $(\"#commit\").on(\"click\", function () {\n            //获取每个标签中的value,更新至数据库中\n            if (\"{{std_type}}\" == 'desc'){\n                var std_name = document.getElementById(\"desc_name\").value;\n                var content  = document.getElementById(\"content\").value;\n                $.ajax({\n\t\t\t\t\ttype: \"POST\",\n\t\t\t\t\turl: \"../../api/datastandard/update\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tusername : \"{{ username }}\",\n                        std_type : 'desc',\n\t\t\t\t\t\tstd_name : std_name,\n\t\t\t\t\t\tcontent  : content\n\t\t\t\t\t},\n\t\t\t\t\tsuccess: function (data) {\n\t\t\t\t\t\tconsole.log(data);\n\t\t\t\t\t\tswal({\n                                text: \"数据标准修改成功，正在返回上一页...\",\n                                icon: \"success\",\n\t\t\t\t\t\t\t\tbuttons: false,\n\t\t\t\t\t\t\t\ttimer: 1000\n                            }).then(function(){\n\t\t\t\t\t\t\t\twindow.location.replace('../../datastandard/show');\n\t\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\terror: function (e) {\n\t\t\t\t\t\tswal({\n\t\t\t\t\t\t\ttitle: \"发生错误\",\n\t\t\t\t\t\t\ttext: e,\n\t\t\t\t\t\t\ticon: \"error\",\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t})\n            }\n            else {\n                var std_name            = document.getElementById(\"std_name\").value;\n                var en_name             = document.getElementById(\"en_name\").value;\n                var business_definition = document.getElementById(\"business_definition\").value;\n                var business_rule       = document.getElementById(\"business_rule\").value;\n                var std_source          = document.getElementById(\"std_source\").value;\n                var data_type           = document.getElementById(\"data_type\").value;\n                var data_format         = document.getElementById(\"data_format\").value;\n                var code_rule           = document.getElementById(\"code_rule\").value;\n                var code_range          = document.getElementById(\"code_range\").value;\n                var code_meaning        = document.getElementById(\"code_meaning\").value;\n                var business_range      = document.getElementById(\"business_range\").value;\n                var dept                = document.getElementById(\"dept\").value;\n                var system              = document.getElementById(\"system\").value;\n                $.ajax({\n\t\t\t\t\ttype: \"POST\",\n\t\t\t\t\turl: \"../../api/datastandard/update\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tusername\t\t   : \"{{ username }}\"    ,\n                        std_type           : 'detail',\n\t\t\t\t\t\tstd_name           : std_name            ,\n\t\t\t\t\t\ten_name            : en_name             ,\n\t\t\t\t\t\tbusiness_definition: business_definition ,\n\t\t\t\t\t\tbusiness_rule      : business_rule       ,\n\t\t\t\t\t\tstd_source         : std_source          ,\n\t\t\t\t\t\tdata_type          : data_type           ,\n\t\t\t\t\t\tdata_format        : data_format         ,\n\t\t\t\t\t\tcode_rule          : code_rule           ,\n\t\t\t\t\t\tcode_range         : code_range          ,\n\t\t\t\t\t\tcode_meaning       : code_meaning        ,\n\t\t\t\t\t\tbusiness_range     : business_range      ,\n\t\t\t\t\t\tdept               : dept                ,\n                        system             : system              ,\n\t\t\t\t\t},\n\t\t\t\t\tsuccess: function (data) {\n\t\t\t\t\t\tconsole.log(data);\n\t\t\t\t\t\tswal({\n                                text: \"数据标准修改成功，正在返回上一页...\",\n                                icon: \"success\",\n\t\t\t\t\t\t\t\tbuttons: false,\n\t\t\t\t\t\t\t\ttimer: 1000\n                            }).then(function(){\n\t\t\t\t\t\t\t\twindow.location.replace('../../datastandard/show');\n\t\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\terror: function (e) {\n\t\t\t\t\t\tswal({\n\t\t\t\t\t\t\ttitle: \"发生错误\",\n\t\t\t\t\t\t\ttext: e,\n\t\t\t\t\t\t\ticon: \"error\",\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t})\n            }\n        });\n\t</script>\n\n</body>\n\n</html>"
  },
  {
    "path": "standard/tests.py",
    "content": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "standard/views.py",
    "content": "from django.shortcuts import render\n\nfrom utils.functions import is_login\n\n\n@is_login\ndef show(request):\n    return render(request, \"standard/show.html\",\n                  {\"username\": request.session.get('username')})\n\n\n@is_login\ndef update(request):\n    return render(\n        request, \"standard/update.html\", {\n            \"username\": request.session.get('username'),\n            \"std_name\": request.GET.get('std_name'),\n            \"std_type\": request.GET.get('std_type'),\n        })\n"
  },
  {
    "path": "static/CodeMirror/lib/codemirror.css",
    "content": "/* BASICS */\n\n.CodeMirror {\n  /* Set height, width, borders, and global font properties here */\n  font-family: monospace;\n  height: 300px;\n  color: black;\n}\n\n/* PADDING */\n\n.CodeMirror-lines {\n  padding: 4px 0; /* Vertical padding around content */\n}\n.CodeMirror pre {\n  padding: 0 4px; /* Horizontal padding of content */\n}\n\n.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {\n  background-color: white; /* The little square between H and V scrollbars */\n}\n\n/* GUTTER */\n\n.CodeMirror-gutters {\n  border-right: 1px solid #ddd;\n  background-color: #f7f7f7;\n  white-space: nowrap;\n}\n.CodeMirror-linenumbers {}\n.CodeMirror-linenumber {\n  padding: 0 3px 0 5px;\n  min-width: 20px;\n  text-align: right;\n  color: #999;\n  white-space: nowrap;\n}\n\n.CodeMirror-guttermarker { color: black; }\n.CodeMirror-guttermarker-subtle { color: #999; }\n\n/* CURSOR */\n\n.CodeMirror-cursor {\n  border-left: 1px solid black;\n  border-right: none;\n  width: 0;\n}\n/* Shown when moving in bi-directional text */\n.CodeMirror div.CodeMirror-secondarycursor {\n  border-left: 1px solid silver;\n}\n.cm-fat-cursor .CodeMirror-cursor {\n  width: auto;\n  border: 0 !important;\n  background: #7e7;\n}\n.cm-fat-cursor div.CodeMirror-cursors {\n  z-index: 1;\n}\n\n.cm-animate-fat-cursor {\n  width: auto;\n  border: 0;\n  -webkit-animation: blink 1.06s steps(1) infinite;\n  -moz-animation: blink 1.06s steps(1) infinite;\n  animation: blink 1.06s steps(1) infinite;\n  background-color: #7e7;\n}\n@-moz-keyframes blink {\n  0% {}\n  50% { background-color: transparent; }\n  100% {}\n}\n@-webkit-keyframes blink {\n  0% {}\n  50% { background-color: transparent; }\n  100% {}\n}\n@keyframes blink {\n  0% {}\n  50% { background-color: transparent; }\n  100% {}\n}\n\n/* Can style cursor different in overwrite (non-insert) mode */\n.CodeMirror-overwrite .CodeMirror-cursor {}\n\n.cm-tab { display: inline-block; text-decoration: inherit; }\n\n.CodeMirror-rulers {\n  position: absolute;\n  left: 0; right: 0; top: -50px; bottom: -20px;\n  overflow: hidden;\n}\n.CodeMirror-ruler {\n  border-left: 1px solid #ccc;\n  top: 0; bottom: 0;\n  position: absolute;\n}\n\n/* DEFAULT THEME */\n\n.cm-s-default .cm-header {color: blue;}\n.cm-s-default .cm-quote {color: #090;}\n.cm-negative {color: #d44;}\n.cm-positive {color: #292;}\n.cm-header, .cm-strong {font-weight: bold;}\n.cm-em {font-style: italic;}\n.cm-link {text-decoration: underline;}\n.cm-strikethrough {text-decoration: line-through;}\n\n.cm-s-default .cm-keyword {color: #708;}\n.cm-s-default .cm-atom {color: #219;}\n.cm-s-default .cm-number {color: #164;}\n.cm-s-default .cm-def {color: #00f;}\n.cm-s-default .cm-variable,\n.cm-s-default .cm-punctuation,\n.cm-s-default .cm-property,\n.cm-s-default .cm-operator {}\n.cm-s-default .cm-variable-2 {color: #05a;}\n.cm-s-default .cm-variable-3 {color: #085;}\n.cm-s-default .cm-comment {color: #a50;}\n.cm-s-default .cm-string {color: #a11;}\n.cm-s-default .cm-string-2 {color: #f50;}\n.cm-s-default .cm-meta {color: #555;}\n.cm-s-default .cm-qualifier {color: #555;}\n.cm-s-default .cm-builtin {color: #30a;}\n.cm-s-default .cm-bracket {color: #997;}\n.cm-s-default .cm-tag {color: #170;}\n.cm-s-default .cm-attribute {color: #00c;}\n.cm-s-default .cm-hr {color: #999;}\n.cm-s-default .cm-link {color: #00c;}\n\n.cm-s-default .cm-error {color: #f00;}\n.cm-invalidchar {color: #f00;}\n\n.CodeMirror-composing { border-bottom: 2px solid; }\n\n/* Default styles for common addons */\n\ndiv.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}\ndiv.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}\n.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }\n.CodeMirror-activeline-background {background: #e8f2ff;}\n\n/* STOP */\n\n/* The rest of this file contains styles related to the mechanics of\n   the editor. You probably shouldn't touch them. */\n\n.CodeMirror {\n  position: relative;\n  overflow: hidden;\n  background: white;\n}\n\n.CodeMirror-scroll {\n  overflow: scroll !important; /* Things will break if this is overridden */\n  /* 30px is the magic margin used to hide the element's real scrollbars */\n  /* See overflow: hidden in .CodeMirror */\n  margin-bottom: -30px; margin-right: -30px;\n  padding-bottom: 30px;\n  height: 100%;\n  outline: none; /* Prevent dragging from highlighting the element */\n  position: relative;\n}\n.CodeMirror-sizer {\n  position: relative;\n  border-right: 30px solid transparent;\n}\n\n/* The fake, visible scrollbars. Used to force redraw during scrolling\n   before actual scrolling happens, thus preventing shaking and\n   flickering artifacts. */\n.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {\n  position: absolute;\n  z-index: 6;\n  display: none;\n}\n.CodeMirror-vscrollbar {\n  right: 0; top: 0;\n  overflow-x: hidden;\n  overflow-y: scroll;\n}\n.CodeMirror-hscrollbar {\n  bottom: 0; left: 0;\n  overflow-y: hidden;\n  overflow-x: scroll;\n}\n.CodeMirror-scrollbar-filler {\n  right: 0; bottom: 0;\n}\n.CodeMirror-gutter-filler {\n  left: 0; bottom: 0;\n}\n\n.CodeMirror-gutters {\n  position: absolute; left: 0; top: 0;\n  min-height: 100%;\n  z-index: 3;\n}\n.CodeMirror-gutter {\n  white-space: normal;\n  height: 100%;\n  display: inline-block;\n  vertical-align: top;\n  margin-bottom: -30px;\n  /* Hack to make IE7 behave */\n  *zoom:1;\n  *display:inline;\n}\n.CodeMirror-gutter-wrapper {\n  position: absolute;\n  z-index: 4;\n  background: none !important;\n  border: none !important;\n}\n.CodeMirror-gutter-background {\n  position: absolute;\n  top: 0; bottom: 0;\n  z-index: 4;\n}\n.CodeMirror-gutter-elt {\n  position: absolute;\n  cursor: default;\n  z-index: 4;\n}\n.CodeMirror-gutter-wrapper {\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  user-select: none;\n}\n\n.CodeMirror-lines {\n  cursor: text;\n  min-height: 1px; /* prevents collapsing before first draw */\n}\n.CodeMirror pre {\n  /* Reset some styles that the rest of the page might have set */\n  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;\n  border-width: 0;\n  background: transparent;\n  font-family: inherit;\n  font-size: inherit;\n  margin: 0;\n  white-space: pre;\n  word-wrap: normal;\n  line-height: inherit;\n  color: inherit;\n  z-index: 2;\n  position: relative;\n  overflow: visible;\n  -webkit-tap-highlight-color: transparent;\n  -webkit-font-variant-ligatures: none;\n  font-variant-ligatures: none;\n}\n.CodeMirror-wrap pre {\n  word-wrap: break-word;\n  white-space: pre-wrap;\n  word-break: normal;\n}\n\n.CodeMirror-linebackground {\n  position: absolute;\n  left: 0; right: 0; top: 0; bottom: 0;\n  z-index: 0;\n}\n\n.CodeMirror-linewidget {\n  position: relative;\n  z-index: 2;\n  overflow: auto;\n}\n\n.CodeMirror-widget {}\n\n.CodeMirror-code {\n  outline: none;\n}\n\n/* Force content-box sizing for the elements where we expect it */\n.CodeMirror-scroll,\n.CodeMirror-sizer,\n.CodeMirror-gutter,\n.CodeMirror-gutters,\n.CodeMirror-linenumber {\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n.CodeMirror-measure {\n  position: absolute;\n  width: 100%;\n  height: 0;\n  overflow: hidden;\n  visibility: hidden;\n}\n\n.CodeMirror-cursor {\n  position: absolute;\n  pointer-events: none;\n}\n.CodeMirror-measure pre { position: static; }\n\ndiv.CodeMirror-cursors {\n  visibility: hidden;\n  position: relative;\n  z-index: 3;\n}\ndiv.CodeMirror-dragcursors {\n  visibility: visible;\n}\n\n.CodeMirror-focused div.CodeMirror-cursors {\n  visibility: visible;\n}\n\n.CodeMirror-selected { background: #d9d9d9; }\n.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }\n.CodeMirror-crosshair { cursor: crosshair; }\n.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }\n.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }\n\n.cm-searching {\n  background: #ffa;\n  background: rgba(255, 255, 0, .4);\n}\n\n/* IE7 hack to prevent it from returning funny offsetTops on the spans */\n.CodeMirror span { *vertical-align: text-bottom; }\n\n/* Used to force a border model for a node */\n.cm-force-border { padding-right: .1px; }\n\n@media print {\n  /* Hide the cursor when printing */\n  .CodeMirror div.CodeMirror-cursors {\n    visibility: hidden;\n  }\n}\n\n/* See issue #2901 */\n.cm-tab-wrap-hack:after { content: ''; }\n\n/* Help users use markselection to safely style text background */\nspan.CodeMirror-selectedtext { background: none; }\n"
  },
  {
    "path": "static/CodeMirror/lib/codemirror.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n// This is CodeMirror (http://codemirror.net), a code editor\n// implemented in JavaScript on top of the browser's DOM.\n//\n// You can find some technical background for some of the code below\n// at http://marijnhaverbeke.nl/blog/#cm-internals .\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    module.exports = mod();\n  else if (typeof define == \"function\" && define.amd) // AMD\n    return define([], mod);\n  else // Plain browser env\n    (this || window).CodeMirror = mod();\n})(function() {\n  \"use strict\";\n\n  // BROWSER SNIFFING\n\n  // Kludges for bugs and behavior differences that can't be feature\n  // detected are enabled based on userAgent etc sniffing.\n  var userAgent = navigator.userAgent;\n  var platform = navigator.platform;\n\n  var gecko = /gecko\\/\\d/i.test(userAgent);\n  var ie_upto10 = /MSIE \\d/.test(userAgent);\n  var ie_11up = /Trident\\/(?:[7-9]|\\d{2,})\\..*rv:(\\d+)/.exec(userAgent);\n  var ie = ie_upto10 || ie_11up;\n  var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);\n  var webkit = /WebKit\\//.test(userAgent);\n  var qtwebkit = webkit && /Qt\\/\\d+\\.\\d+/.test(userAgent);\n  var chrome = /Chrome\\//.test(userAgent);\n  var presto = /Opera\\//.test(userAgent);\n  var safari = /Apple Computer/.test(navigator.vendor);\n  var mac_geMountainLion = /Mac OS X 1\\d\\D([8-9]|\\d\\d)\\D/.test(userAgent);\n  var phantom = /PhantomJS/.test(userAgent);\n\n  var ios = /AppleWebKit/.test(userAgent) && /Mobile\\/\\w+/.test(userAgent);\n  // This is woefully incomplete. Suggestions for alternative methods welcome.\n  var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);\n  var mac = ios || /Mac/.test(platform);\n  var chromeOS = /\\bCrOS\\b/.test(userAgent);\n  var windows = /win/i.test(platform);\n\n  var presto_version = presto && userAgent.match(/Version\\/(\\d*\\.\\d*)/);\n  if (presto_version) presto_version = Number(presto_version[1]);\n  if (presto_version && presto_version >= 15) { presto = false; webkit = true; }\n  // Some browsers use the wrong event properties to signal cmd/ctrl on OS X\n  var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));\n  var captureRightClick = gecko || (ie && ie_version >= 9);\n\n  // Optimize some code when these features are not used.\n  var sawReadOnlySpans = false, sawCollapsedSpans = false;\n\n  // EDITOR CONSTRUCTOR\n\n  // A CodeMirror instance represents an editor. This is the object\n  // that user code is usually dealing with.\n\n  function CodeMirror(place, options) {\n    if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);\n\n    this.options = options = options ? copyObj(options) : {};\n    // Determine effective options based on given values and defaults.\n    copyObj(defaults, options, false);\n    setGuttersForLineNumbers(options);\n\n    var doc = options.value;\n    if (typeof doc == \"string\") doc = new Doc(doc, options.mode, null, options.lineSeparator);\n    this.doc = doc;\n\n    var input = new CodeMirror.inputStyles[options.inputStyle](this);\n    var display = this.display = new Display(place, doc, input);\n    display.wrapper.CodeMirror = this;\n    updateGutters(this);\n    themeChanged(this);\n    if (options.lineWrapping)\n      this.display.wrapper.className += \" CodeMirror-wrap\";\n    if (options.autofocus && !mobile) display.input.focus();\n    initScrollbars(this);\n\n    this.state = {\n      keyMaps: [],  // stores maps added by addKeyMap\n      overlays: [], // highlighting overlays, as added by addOverlay\n      modeGen: 0,   // bumped when mode/overlay changes, used to invalidate highlighting info\n      overwrite: false,\n      delayingBlurEvent: false,\n      focused: false,\n      suppressEdits: false, // used to disable editing during key handlers when in readOnly mode\n      pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll\n      selectingText: false,\n      draggingText: false,\n      highlight: new Delayed(), // stores highlight worker timeout\n      keySeq: null,  // Unfinished key sequence\n      specialChars: null\n    };\n\n    var cm = this;\n\n    // Override magic textarea content restore that IE sometimes does\n    // on our hidden textarea on reload\n    if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20);\n\n    registerEventHandlers(this);\n    ensureGlobalHandlers();\n\n    startOperation(this);\n    this.curOp.forceUpdate = true;\n    attachDoc(this, doc);\n\n    if ((options.autofocus && !mobile) || cm.hasFocus())\n      setTimeout(bind(onFocus, this), 20);\n    else\n      onBlur(this);\n\n    for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))\n      optionHandlers[opt](this, options[opt], Init);\n    maybeUpdateLineNumberWidth(this);\n    if (options.finishInit) options.finishInit(this);\n    for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);\n    endOperation(this);\n    // Suppress optimizelegibility in Webkit, since it breaks text\n    // measuring on line wrapping boundaries.\n    if (webkit && options.lineWrapping &&\n        getComputedStyle(display.lineDiv).textRendering == \"optimizelegibility\")\n      display.lineDiv.style.textRendering = \"auto\";\n  }\n\n  // DISPLAY CONSTRUCTOR\n\n  // The display handles the DOM integration, both for input reading\n  // and content drawing. It holds references to DOM nodes and\n  // display-related state.\n\n  function Display(place, doc, input) {\n    var d = this;\n    this.input = input;\n\n    // Covers bottom-right square when both scrollbars are present.\n    d.scrollbarFiller = elt(\"div\", null, \"CodeMirror-scrollbar-filler\");\n    d.scrollbarFiller.setAttribute(\"cm-not-content\", \"true\");\n    // Covers bottom of gutter when coverGutterNextToScrollbar is on\n    // and h scrollbar is present.\n    d.gutterFiller = elt(\"div\", null, \"CodeMirror-gutter-filler\");\n    d.gutterFiller.setAttribute(\"cm-not-content\", \"true\");\n    // Will contain the actual code, positioned to cover the viewport.\n    d.lineDiv = elt(\"div\", null, \"CodeMirror-code\");\n    // Elements are added to these to represent selection and cursors.\n    d.selectionDiv = elt(\"div\", null, null, \"position: relative; z-index: 1\");\n    d.cursorDiv = elt(\"div\", null, \"CodeMirror-cursors\");\n    // A visibility: hidden element used to find the size of things.\n    d.measure = elt(\"div\", null, \"CodeMirror-measure\");\n    // When lines outside of the viewport are measured, they are drawn in this.\n    d.lineMeasure = elt(\"div\", null, \"CodeMirror-measure\");\n    // Wraps everything that needs to exist inside the vertically-padded coordinate system\n    d.lineSpace = elt(\"div\", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],\n                      null, \"position: relative; outline: none\");\n    // Moved around its parent to cover visible view.\n    d.mover = elt(\"div\", [elt(\"div\", [d.lineSpace], \"CodeMirror-lines\")], null, \"position: relative\");\n    // Set to the height of the document, allowing scrolling.\n    d.sizer = elt(\"div\", [d.mover], \"CodeMirror-sizer\");\n    d.sizerWidth = null;\n    // Behavior of elts with overflow: auto and padding is\n    // inconsistent across browsers. This is used to ensure the\n    // scrollable area is big enough.\n    d.heightForcer = elt(\"div\", null, null, \"position: absolute; height: \" + scrollerGap + \"px; width: 1px;\");\n    // Will contain the gutters, if any.\n    d.gutters = elt(\"div\", null, \"CodeMirror-gutters\");\n    d.lineGutter = null;\n    // Actual scrollable element.\n    d.scroller = elt(\"div\", [d.sizer, d.heightForcer, d.gutters], \"CodeMirror-scroll\");\n    d.scroller.setAttribute(\"tabIndex\", \"-1\");\n    // The element in which the editor lives.\n    d.wrapper = elt(\"div\", [d.scrollbarFiller, d.gutterFiller, d.scroller], \"CodeMirror\");\n\n    // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)\n    if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }\n    if (!webkit && !(gecko && mobile)) d.scroller.draggable = true;\n\n    if (place) {\n      if (place.appendChild) place.appendChild(d.wrapper);\n      else place(d.wrapper);\n    }\n\n    // Current rendered range (may be bigger than the view window).\n    d.viewFrom = d.viewTo = doc.first;\n    d.reportedViewFrom = d.reportedViewTo = doc.first;\n    // Information about the rendered lines.\n    d.view = [];\n    d.renderedView = null;\n    // Holds info about a single rendered line when it was rendered\n    // for measurement, while not in view.\n    d.externalMeasured = null;\n    // Empty space (in pixels) above the view\n    d.viewOffset = 0;\n    d.lastWrapHeight = d.lastWrapWidth = 0;\n    d.updateLineNumbers = null;\n\n    d.nativeBarWidth = d.barHeight = d.barWidth = 0;\n    d.scrollbarsClipped = false;\n\n    // Used to only resize the line number gutter when necessary (when\n    // the amount of lines crosses a boundary that makes its width change)\n    d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;\n    // Set to true when a non-horizontal-scrolling line widget is\n    // added. As an optimization, line widget aligning is skipped when\n    // this is false.\n    d.alignWidgets = false;\n\n    d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;\n\n    // Tracks the maximum line length so that the horizontal scrollbar\n    // can be kept static when scrolling.\n    d.maxLine = null;\n    d.maxLineLength = 0;\n    d.maxLineChanged = false;\n\n    // Used for measuring wheel scrolling granularity\n    d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;\n\n    // True when shift is held down.\n    d.shift = false;\n\n    // Used to track whether anything happened since the context menu\n    // was opened.\n    d.selForContextMenu = null;\n\n    d.activeTouch = null;\n\n    input.init(d);\n  }\n\n  // STATE UPDATES\n\n  // Used to get the editor into a consistent state again when options change.\n\n  function loadMode(cm) {\n    cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);\n    resetModeState(cm);\n  }\n\n  function resetModeState(cm) {\n    cm.doc.iter(function(line) {\n      if (line.stateAfter) line.stateAfter = null;\n      if (line.styles) line.styles = null;\n    });\n    cm.doc.frontier = cm.doc.first;\n    startWorker(cm, 100);\n    cm.state.modeGen++;\n    if (cm.curOp) regChange(cm);\n  }\n\n  function wrappingChanged(cm) {\n    if (cm.options.lineWrapping) {\n      addClass(cm.display.wrapper, \"CodeMirror-wrap\");\n      cm.display.sizer.style.minWidth = \"\";\n      cm.display.sizerWidth = null;\n    } else {\n      rmClass(cm.display.wrapper, \"CodeMirror-wrap\");\n      findMaxLine(cm);\n    }\n    estimateLineHeights(cm);\n    regChange(cm);\n    clearCaches(cm);\n    setTimeout(function(){updateScrollbars(cm);}, 100);\n  }\n\n  // Returns a function that estimates the height of a line, to use as\n  // first approximation until the line becomes visible (and is thus\n  // properly measurable).\n  function estimateHeight(cm) {\n    var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;\n    var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);\n    return function(line) {\n      if (lineIsHidden(cm.doc, line)) return 0;\n\n      var widgetsHeight = 0;\n      if (line.widgets) for (var i = 0; i < line.widgets.length; i++) {\n        if (line.widgets[i].height) widgetsHeight += line.widgets[i].height;\n      }\n\n      if (wrapping)\n        return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th;\n      else\n        return widgetsHeight + th;\n    };\n  }\n\n  function estimateLineHeights(cm) {\n    var doc = cm.doc, est = estimateHeight(cm);\n    doc.iter(function(line) {\n      var estHeight = est(line);\n      if (estHeight != line.height) updateLineHeight(line, estHeight);\n    });\n  }\n\n  function themeChanged(cm) {\n    cm.display.wrapper.className = cm.display.wrapper.className.replace(/\\s*cm-s-\\S+/g, \"\") +\n      cm.options.theme.replace(/(^|\\s)\\s*/g, \" cm-s-\");\n    clearCaches(cm);\n  }\n\n  function guttersChanged(cm) {\n    updateGutters(cm);\n    regChange(cm);\n    setTimeout(function(){alignHorizontally(cm);}, 20);\n  }\n\n  // Rebuild the gutter elements, ensure the margin to the left of the\n  // code matches their width.\n  function updateGutters(cm) {\n    var gutters = cm.display.gutters, specs = cm.options.gutters;\n    removeChildren(gutters);\n    for (var i = 0; i < specs.length; ++i) {\n      var gutterClass = specs[i];\n      var gElt = gutters.appendChild(elt(\"div\", null, \"CodeMirror-gutter \" + gutterClass));\n      if (gutterClass == \"CodeMirror-linenumbers\") {\n        cm.display.lineGutter = gElt;\n        gElt.style.width = (cm.display.lineNumWidth || 1) + \"px\";\n      }\n    }\n    gutters.style.display = i ? \"\" : \"none\";\n    updateGutterSpace(cm);\n  }\n\n  function updateGutterSpace(cm) {\n    var width = cm.display.gutters.offsetWidth;\n    cm.display.sizer.style.marginLeft = width + \"px\";\n  }\n\n  // Compute the character length of a line, taking into account\n  // collapsed ranges (see markText) that might hide parts, and join\n  // other lines onto it.\n  function lineLength(line) {\n    if (line.height == 0) return 0;\n    var len = line.text.length, merged, cur = line;\n    while (merged = collapsedSpanAtStart(cur)) {\n      var found = merged.find(0, true);\n      cur = found.from.line;\n      len += found.from.ch - found.to.ch;\n    }\n    cur = line;\n    while (merged = collapsedSpanAtEnd(cur)) {\n      var found = merged.find(0, true);\n      len -= cur.text.length - found.from.ch;\n      cur = found.to.line;\n      len += cur.text.length - found.to.ch;\n    }\n    return len;\n  }\n\n  // Find the longest line in the document.\n  function findMaxLine(cm) {\n    var d = cm.display, doc = cm.doc;\n    d.maxLine = getLine(doc, doc.first);\n    d.maxLineLength = lineLength(d.maxLine);\n    d.maxLineChanged = true;\n    doc.iter(function(line) {\n      var len = lineLength(line);\n      if (len > d.maxLineLength) {\n        d.maxLineLength = len;\n        d.maxLine = line;\n      }\n    });\n  }\n\n  // Make sure the gutters options contains the element\n  // \"CodeMirror-linenumbers\" when the lineNumbers option is true.\n  function setGuttersForLineNumbers(options) {\n    var found = indexOf(options.gutters, \"CodeMirror-linenumbers\");\n    if (found == -1 && options.lineNumbers) {\n      options.gutters = options.gutters.concat([\"CodeMirror-linenumbers\"]);\n    } else if (found > -1 && !options.lineNumbers) {\n      options.gutters = options.gutters.slice(0);\n      options.gutters.splice(found, 1);\n    }\n  }\n\n  // SCROLLBARS\n\n  // Prepare DOM reads needed to update the scrollbars. Done in one\n  // shot to minimize update/measure roundtrips.\n  function measureForScrollbars(cm) {\n    var d = cm.display, gutterW = d.gutters.offsetWidth;\n    var docH = Math.round(cm.doc.height + paddingVert(cm.display));\n    return {\n      clientHeight: d.scroller.clientHeight,\n      viewHeight: d.wrapper.clientHeight,\n      scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,\n      viewWidth: d.wrapper.clientWidth,\n      barLeft: cm.options.fixedGutter ? gutterW : 0,\n      docHeight: docH,\n      scrollHeight: docH + scrollGap(cm) + d.barHeight,\n      nativeBarWidth: d.nativeBarWidth,\n      gutterWidth: gutterW\n    };\n  }\n\n  function NativeScrollbars(place, scroll, cm) {\n    this.cm = cm;\n    var vert = this.vert = elt(\"div\", [elt(\"div\", null, null, \"min-width: 1px\")], \"CodeMirror-vscrollbar\");\n    var horiz = this.horiz = elt(\"div\", [elt(\"div\", null, null, \"height: 100%; min-height: 1px\")], \"CodeMirror-hscrollbar\");\n    place(vert); place(horiz);\n\n    on(vert, \"scroll\", function() {\n      if (vert.clientHeight) scroll(vert.scrollTop, \"vertical\");\n    });\n    on(horiz, \"scroll\", function() {\n      if (horiz.clientWidth) scroll(horiz.scrollLeft, \"horizontal\");\n    });\n\n    this.checkedZeroWidth = false;\n    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).\n    if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = \"18px\";\n  }\n\n  NativeScrollbars.prototype = copyObj({\n    update: function(measure) {\n      var needsH = measure.scrollWidth > measure.clientWidth + 1;\n      var needsV = measure.scrollHeight > measure.clientHeight + 1;\n      var sWidth = measure.nativeBarWidth;\n\n      if (needsV) {\n        this.vert.style.display = \"block\";\n        this.vert.style.bottom = needsH ? sWidth + \"px\" : \"0\";\n        var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);\n        // A bug in IE8 can cause this value to be negative, so guard it.\n        this.vert.firstChild.style.height =\n          Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + \"px\";\n      } else {\n        this.vert.style.display = \"\";\n        this.vert.firstChild.style.height = \"0\";\n      }\n\n      if (needsH) {\n        this.horiz.style.display = \"block\";\n        this.horiz.style.right = needsV ? sWidth + \"px\" : \"0\";\n        this.horiz.style.left = measure.barLeft + \"px\";\n        var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);\n        this.horiz.firstChild.style.width =\n          (measure.scrollWidth - measure.clientWidth + totalWidth) + \"px\";\n      } else {\n        this.horiz.style.display = \"\";\n        this.horiz.firstChild.style.width = \"0\";\n      }\n\n      if (!this.checkedZeroWidth && measure.clientHeight > 0) {\n        if (sWidth == 0) this.zeroWidthHack();\n        this.checkedZeroWidth = true;\n      }\n\n      return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};\n    },\n    setScrollLeft: function(pos) {\n      if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;\n      if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz);\n    },\n    setScrollTop: function(pos) {\n      if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;\n      if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert);\n    },\n    zeroWidthHack: function() {\n      var w = mac && !mac_geMountainLion ? \"12px\" : \"18px\";\n      this.horiz.style.height = this.vert.style.width = w;\n      this.horiz.style.pointerEvents = this.vert.style.pointerEvents = \"none\";\n      this.disableHoriz = new Delayed;\n      this.disableVert = new Delayed;\n    },\n    enableZeroWidthBar: function(bar, delay) {\n      bar.style.pointerEvents = \"auto\";\n      function maybeDisable() {\n        // To find out whether the scrollbar is still visible, we\n        // check whether the element under the pixel in the bottom\n        // left corner of the scrollbar box is the scrollbar box\n        // itself (when the bar is still visible) or its filler child\n        // (when the bar is hidden). If it is still visible, we keep\n        // it enabled, if it's hidden, we disable pointer events.\n        var box = bar.getBoundingClientRect();\n        var elt = document.elementFromPoint(box.left + 1, box.bottom - 1);\n        if (elt != bar) bar.style.pointerEvents = \"none\";\n        else delay.set(1000, maybeDisable);\n      }\n      delay.set(1000, maybeDisable);\n    },\n    clear: function() {\n      var parent = this.horiz.parentNode;\n      parent.removeChild(this.horiz);\n      parent.removeChild(this.vert);\n    }\n  }, NativeScrollbars.prototype);\n\n  function NullScrollbars() {}\n\n  NullScrollbars.prototype = copyObj({\n    update: function() { return {bottom: 0, right: 0}; },\n    setScrollLeft: function() {},\n    setScrollTop: function() {},\n    clear: function() {}\n  }, NullScrollbars.prototype);\n\n  CodeMirror.scrollbarModel = {\"native\": NativeScrollbars, \"null\": NullScrollbars};\n\n  function initScrollbars(cm) {\n    if (cm.display.scrollbars) {\n      cm.display.scrollbars.clear();\n      if (cm.display.scrollbars.addClass)\n        rmClass(cm.display.wrapper, cm.display.scrollbars.addClass);\n    }\n\n    cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) {\n      cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);\n      // Prevent clicks in the scrollbars from killing focus\n      on(node, \"mousedown\", function() {\n        if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0);\n      });\n      node.setAttribute(\"cm-not-content\", \"true\");\n    }, function(pos, axis) {\n      if (axis == \"horizontal\") setScrollLeft(cm, pos);\n      else setScrollTop(cm, pos);\n    }, cm);\n    if (cm.display.scrollbars.addClass)\n      addClass(cm.display.wrapper, cm.display.scrollbars.addClass);\n  }\n\n  function updateScrollbars(cm, measure) {\n    if (!measure) measure = measureForScrollbars(cm);\n    var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;\n    updateScrollbarsInner(cm, measure);\n    for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {\n      if (startWidth != cm.display.barWidth && cm.options.lineWrapping)\n        updateHeightsInViewport(cm);\n      updateScrollbarsInner(cm, measureForScrollbars(cm));\n      startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;\n    }\n  }\n\n  // Re-synchronize the fake scrollbars with the actual size of the\n  // content.\n  function updateScrollbarsInner(cm, measure) {\n    var d = cm.display;\n    var sizes = d.scrollbars.update(measure);\n\n    d.sizer.style.paddingRight = (d.barWidth = sizes.right) + \"px\";\n    d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + \"px\";\n    d.heightForcer.style.borderBottom = sizes.bottom + \"px solid transparent\"\n\n    if (sizes.right && sizes.bottom) {\n      d.scrollbarFiller.style.display = \"block\";\n      d.scrollbarFiller.style.height = sizes.bottom + \"px\";\n      d.scrollbarFiller.style.width = sizes.right + \"px\";\n    } else d.scrollbarFiller.style.display = \"\";\n    if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {\n      d.gutterFiller.style.display = \"block\";\n      d.gutterFiller.style.height = sizes.bottom + \"px\";\n      d.gutterFiller.style.width = measure.gutterWidth + \"px\";\n    } else d.gutterFiller.style.display = \"\";\n  }\n\n  // Compute the lines that are visible in a given viewport (defaults\n  // the the current scroll position). viewport may contain top,\n  // height, and ensure (see op.scrollToPos) properties.\n  function visibleLines(display, doc, viewport) {\n    var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;\n    top = Math.floor(top - paddingTop(display));\n    var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;\n\n    var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);\n    // Ensure is a {from: {line, ch}, to: {line, ch}} object, and\n    // forces those lines into the viewport (if possible).\n    if (viewport && viewport.ensure) {\n      var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;\n      if (ensureFrom < from) {\n        from = ensureFrom;\n        to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);\n      } else if (Math.min(ensureTo, doc.lastLine()) >= to) {\n        from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);\n        to = ensureTo;\n      }\n    }\n    return {from: from, to: Math.max(to, from + 1)};\n  }\n\n  // LINE NUMBERS\n\n  // Re-align line numbers and gutter marks to compensate for\n  // horizontal scrolling.\n  function alignHorizontally(cm) {\n    var display = cm.display, view = display.view;\n    if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;\n    var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;\n    var gutterW = display.gutters.offsetWidth, left = comp + \"px\";\n    for (var i = 0; i < view.length; i++) if (!view[i].hidden) {\n      if (cm.options.fixedGutter) {\n        if (view[i].gutter)\n          view[i].gutter.style.left = left;\n        if (view[i].gutterBackground)\n          view[i].gutterBackground.style.left = left;\n      }\n      var align = view[i].alignable;\n      if (align) for (var j = 0; j < align.length; j++)\n        align[j].style.left = left;\n    }\n    if (cm.options.fixedGutter)\n      display.gutters.style.left = (comp + gutterW) + \"px\";\n  }\n\n  // Used to ensure that the line number gutter is still the right\n  // size for the current document size. Returns true when an update\n  // is needed.\n  function maybeUpdateLineNumberWidth(cm) {\n    if (!cm.options.lineNumbers) return false;\n    var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;\n    if (last.length != display.lineNumChars) {\n      var test = display.measure.appendChild(elt(\"div\", [elt(\"div\", last)],\n                                                 \"CodeMirror-linenumber CodeMirror-gutter-elt\"));\n      var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;\n      display.lineGutter.style.width = \"\";\n      display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;\n      display.lineNumWidth = display.lineNumInnerWidth + padding;\n      display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;\n      display.lineGutter.style.width = display.lineNumWidth + \"px\";\n      updateGutterSpace(cm);\n      return true;\n    }\n    return false;\n  }\n\n  function lineNumberFor(options, i) {\n    return String(options.lineNumberFormatter(i + options.firstLineNumber));\n  }\n\n  // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,\n  // but using getBoundingClientRect to get a sub-pixel-accurate\n  // result.\n  function compensateForHScroll(display) {\n    return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;\n  }\n\n  // DISPLAY DRAWING\n\n  function DisplayUpdate(cm, viewport, force) {\n    var display = cm.display;\n\n    this.viewport = viewport;\n    // Store some values that we'll need later (but don't want to force a relayout for)\n    this.visible = visibleLines(display, cm.doc, viewport);\n    this.editorIsHidden = !display.wrapper.offsetWidth;\n    this.wrapperHeight = display.wrapper.clientHeight;\n    this.wrapperWidth = display.wrapper.clientWidth;\n    this.oldDisplayWidth = displayWidth(cm);\n    this.force = force;\n    this.dims = getDimensions(cm);\n    this.events = [];\n  }\n\n  DisplayUpdate.prototype.signal = function(emitter, type) {\n    if (hasHandler(emitter, type))\n      this.events.push(arguments);\n  };\n  DisplayUpdate.prototype.finish = function() {\n    for (var i = 0; i < this.events.length; i++)\n      signal.apply(null, this.events[i]);\n  };\n\n  function maybeClipScrollbars(cm) {\n    var display = cm.display;\n    if (!display.scrollbarsClipped && display.scroller.offsetWidth) {\n      display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;\n      display.heightForcer.style.height = scrollGap(cm) + \"px\";\n      display.sizer.style.marginBottom = -display.nativeBarWidth + \"px\";\n      display.sizer.style.borderRightWidth = scrollGap(cm) + \"px\";\n      display.scrollbarsClipped = true;\n    }\n  }\n\n  // Does the actual updating of the line display. Bails out\n  // (returning false) when there is nothing to be done and forced is\n  // false.\n  function updateDisplayIfNeeded(cm, update) {\n    var display = cm.display, doc = cm.doc;\n\n    if (update.editorIsHidden) {\n      resetView(cm);\n      return false;\n    }\n\n    // Bail out if the visible area is already rendered and nothing changed.\n    if (!update.force &&\n        update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&\n        (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&\n        display.renderedView == display.view && countDirtyView(cm) == 0)\n      return false;\n\n    if (maybeUpdateLineNumberWidth(cm)) {\n      resetView(cm);\n      update.dims = getDimensions(cm);\n    }\n\n    // Compute a suitable new viewport (from & to)\n    var end = doc.first + doc.size;\n    var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);\n    var to = Math.min(end, update.visible.to + cm.options.viewportMargin);\n    if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);\n    if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo);\n    if (sawCollapsedSpans) {\n      from = visualLineNo(cm.doc, from);\n      to = visualLineEndNo(cm.doc, to);\n    }\n\n    var different = from != display.viewFrom || to != display.viewTo ||\n      display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;\n    adjustView(cm, from, to);\n\n    display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));\n    // Position the mover div to align with the current scroll position\n    cm.display.mover.style.top = display.viewOffset + \"px\";\n\n    var toUpdate = countDirtyView(cm);\n    if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&\n        (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))\n      return false;\n\n    // For big changes, we hide the enclosing element during the\n    // update, since that speeds up the operations on most browsers.\n    var focused = activeElt();\n    if (toUpdate > 4) display.lineDiv.style.display = \"none\";\n    patchDisplay(cm, display.updateLineNumbers, update.dims);\n    if (toUpdate > 4) display.lineDiv.style.display = \"\";\n    display.renderedView = display.view;\n    // There might have been a widget with a focused element that got\n    // hidden or updated, if so re-focus it.\n    if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();\n\n    // Prevent selection and cursors from interfering with the scroll\n    // width and height.\n    removeChildren(display.cursorDiv);\n    removeChildren(display.selectionDiv);\n    display.gutters.style.height = display.sizer.style.minHeight = 0;\n\n    if (different) {\n      display.lastWrapHeight = update.wrapperHeight;\n      display.lastWrapWidth = update.wrapperWidth;\n      startWorker(cm, 400);\n    }\n\n    display.updateLineNumbers = null;\n\n    return true;\n  }\n\n  function postUpdateDisplay(cm, update) {\n    var viewport = update.viewport;\n\n    for (var first = true;; first = false) {\n      if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {\n        // Clip forced viewport to actual scrollable area.\n        if (viewport && viewport.top != null)\n          viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)};\n        // Updated line heights might result in the drawn area not\n        // actually covering the viewport. Keep looping until it does.\n        update.visible = visibleLines(cm.display, cm.doc, viewport);\n        if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)\n          break;\n      }\n      if (!updateDisplayIfNeeded(cm, update)) break;\n      updateHeightsInViewport(cm);\n      var barMeasure = measureForScrollbars(cm);\n      updateSelection(cm);\n      updateScrollbars(cm, barMeasure);\n      setDocumentHeight(cm, barMeasure);\n    }\n\n    update.signal(cm, \"update\", cm);\n    if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {\n      update.signal(cm, \"viewportChange\", cm, cm.display.viewFrom, cm.display.viewTo);\n      cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;\n    }\n  }\n\n  function updateDisplaySimple(cm, viewport) {\n    var update = new DisplayUpdate(cm, viewport);\n    if (updateDisplayIfNeeded(cm, update)) {\n      updateHeightsInViewport(cm);\n      postUpdateDisplay(cm, update);\n      var barMeasure = measureForScrollbars(cm);\n      updateSelection(cm);\n      updateScrollbars(cm, barMeasure);\n      setDocumentHeight(cm, barMeasure);\n      update.finish();\n    }\n  }\n\n  function setDocumentHeight(cm, measure) {\n    cm.display.sizer.style.minHeight = measure.docHeight + \"px\";\n    cm.display.heightForcer.style.top = measure.docHeight + \"px\";\n    cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + \"px\";\n  }\n\n  // Read the actual heights of the rendered lines, and update their\n  // stored heights to match.\n  function updateHeightsInViewport(cm) {\n    var display = cm.display;\n    var prevBottom = display.lineDiv.offsetTop;\n    for (var i = 0; i < display.view.length; i++) {\n      var cur = display.view[i], height;\n      if (cur.hidden) continue;\n      if (ie && ie_version < 8) {\n        var bot = cur.node.offsetTop + cur.node.offsetHeight;\n        height = bot - prevBottom;\n        prevBottom = bot;\n      } else {\n        var box = cur.node.getBoundingClientRect();\n        height = box.bottom - box.top;\n      }\n      var diff = cur.line.height - height;\n      if (height < 2) height = textHeight(display);\n      if (diff > .001 || diff < -.001) {\n        updateLineHeight(cur.line, height);\n        updateWidgetHeight(cur.line);\n        if (cur.rest) for (var j = 0; j < cur.rest.length; j++)\n          updateWidgetHeight(cur.rest[j]);\n      }\n    }\n  }\n\n  // Read and store the height of line widgets associated with the\n  // given line.\n  function updateWidgetHeight(line) {\n    if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)\n      line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight;\n  }\n\n  // Do a bulk-read of the DOM positions and sizes needed to draw the\n  // view, so that we don't interleave reading and writing to the DOM.\n  function getDimensions(cm) {\n    var d = cm.display, left = {}, width = {};\n    var gutterLeft = d.gutters.clientLeft;\n    for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {\n      left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;\n      width[cm.options.gutters[i]] = n.clientWidth;\n    }\n    return {fixedPos: compensateForHScroll(d),\n            gutterTotalWidth: d.gutters.offsetWidth,\n            gutterLeft: left,\n            gutterWidth: width,\n            wrapperWidth: d.wrapper.clientWidth};\n  }\n\n  // Sync the actual display DOM structure with display.view, removing\n  // nodes for lines that are no longer in view, and creating the ones\n  // that are not there yet, and updating the ones that are out of\n  // date.\n  function patchDisplay(cm, updateNumbersFrom, dims) {\n    var display = cm.display, lineNumbers = cm.options.lineNumbers;\n    var container = display.lineDiv, cur = container.firstChild;\n\n    function rm(node) {\n      var next = node.nextSibling;\n      // Works around a throw-scroll bug in OS X Webkit\n      if (webkit && mac && cm.display.currentWheelTarget == node)\n        node.style.display = \"none\";\n      else\n        node.parentNode.removeChild(node);\n      return next;\n    }\n\n    var view = display.view, lineN = display.viewFrom;\n    // Loop over the elements in the view, syncing cur (the DOM nodes\n    // in display.lineDiv) with the view as we go.\n    for (var i = 0; i < view.length; i++) {\n      var lineView = view[i];\n      if (lineView.hidden) {\n      } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet\n        var node = buildLineElement(cm, lineView, lineN, dims);\n        container.insertBefore(node, cur);\n      } else { // Already drawn\n        while (cur != lineView.node) cur = rm(cur);\n        var updateNumber = lineNumbers && updateNumbersFrom != null &&\n          updateNumbersFrom <= lineN && lineView.lineNumber;\n        if (lineView.changes) {\n          if (indexOf(lineView.changes, \"gutter\") > -1) updateNumber = false;\n          updateLineForChanges(cm, lineView, lineN, dims);\n        }\n        if (updateNumber) {\n          removeChildren(lineView.lineNumber);\n          lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));\n        }\n        cur = lineView.node.nextSibling;\n      }\n      lineN += lineView.size;\n    }\n    while (cur) cur = rm(cur);\n  }\n\n  // When an aspect of a line changes, a string is added to\n  // lineView.changes. This updates the relevant part of the line's\n  // DOM structure.\n  function updateLineForChanges(cm, lineView, lineN, dims) {\n    for (var j = 0; j < lineView.changes.length; j++) {\n      var type = lineView.changes[j];\n      if (type == \"text\") updateLineText(cm, lineView);\n      else if (type == \"gutter\") updateLineGutter(cm, lineView, lineN, dims);\n      else if (type == \"class\") updateLineClasses(lineView);\n      else if (type == \"widget\") updateLineWidgets(cm, lineView, dims);\n    }\n    lineView.changes = null;\n  }\n\n  // Lines with gutter elements, widgets or a background class need to\n  // be wrapped, and have the extra elements added to the wrapper div\n  function ensureLineWrapped(lineView) {\n    if (lineView.node == lineView.text) {\n      lineView.node = elt(\"div\", null, null, \"position: relative\");\n      if (lineView.text.parentNode)\n        lineView.text.parentNode.replaceChild(lineView.node, lineView.text);\n      lineView.node.appendChild(lineView.text);\n      if (ie && ie_version < 8) lineView.node.style.zIndex = 2;\n    }\n    return lineView.node;\n  }\n\n  function updateLineBackground(lineView) {\n    var cls = lineView.bgClass ? lineView.bgClass + \" \" + (lineView.line.bgClass || \"\") : lineView.line.bgClass;\n    if (cls) cls += \" CodeMirror-linebackground\";\n    if (lineView.background) {\n      if (cls) lineView.background.className = cls;\n      else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }\n    } else if (cls) {\n      var wrap = ensureLineWrapped(lineView);\n      lineView.background = wrap.insertBefore(elt(\"div\", null, cls), wrap.firstChild);\n    }\n  }\n\n  // Wrapper around buildLineContent which will reuse the structure\n  // in display.externalMeasured when possible.\n  function getLineContent(cm, lineView) {\n    var ext = cm.display.externalMeasured;\n    if (ext && ext.line == lineView.line) {\n      cm.display.externalMeasured = null;\n      lineView.measure = ext.measure;\n      return ext.built;\n    }\n    return buildLineContent(cm, lineView);\n  }\n\n  // Redraw the line's text. Interacts with the background and text\n  // classes because the mode may output tokens that influence these\n  // classes.\n  function updateLineText(cm, lineView) {\n    var cls = lineView.text.className;\n    var built = getLineContent(cm, lineView);\n    if (lineView.text == lineView.node) lineView.node = built.pre;\n    lineView.text.parentNode.replaceChild(built.pre, lineView.text);\n    lineView.text = built.pre;\n    if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {\n      lineView.bgClass = built.bgClass;\n      lineView.textClass = built.textClass;\n      updateLineClasses(lineView);\n    } else if (cls) {\n      lineView.text.className = cls;\n    }\n  }\n\n  function updateLineClasses(lineView) {\n    updateLineBackground(lineView);\n    if (lineView.line.wrapClass)\n      ensureLineWrapped(lineView).className = lineView.line.wrapClass;\n    else if (lineView.node != lineView.text)\n      lineView.node.className = \"\";\n    var textClass = lineView.textClass ? lineView.textClass + \" \" + (lineView.line.textClass || \"\") : lineView.line.textClass;\n    lineView.text.className = textClass || \"\";\n  }\n\n  function updateLineGutter(cm, lineView, lineN, dims) {\n    if (lineView.gutter) {\n      lineView.node.removeChild(lineView.gutter);\n      lineView.gutter = null;\n    }\n    if (lineView.gutterBackground) {\n      lineView.node.removeChild(lineView.gutterBackground);\n      lineView.gutterBackground = null;\n    }\n    if (lineView.line.gutterClass) {\n      var wrap = ensureLineWrapped(lineView);\n      lineView.gutterBackground = elt(\"div\", null, \"CodeMirror-gutter-background \" + lineView.line.gutterClass,\n                                      \"left: \" + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) +\n                                      \"px; width: \" + dims.gutterTotalWidth + \"px\");\n      wrap.insertBefore(lineView.gutterBackground, lineView.text);\n    }\n    var markers = lineView.line.gutterMarkers;\n    if (cm.options.lineNumbers || markers) {\n      var wrap = ensureLineWrapped(lineView);\n      var gutterWrap = lineView.gutter = elt(\"div\", null, \"CodeMirror-gutter-wrapper\", \"left: \" +\n                                             (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + \"px\");\n      cm.display.input.setUneditable(gutterWrap);\n      wrap.insertBefore(gutterWrap, lineView.text);\n      if (lineView.line.gutterClass)\n        gutterWrap.className += \" \" + lineView.line.gutterClass;\n      if (cm.options.lineNumbers && (!markers || !markers[\"CodeMirror-linenumbers\"]))\n        lineView.lineNumber = gutterWrap.appendChild(\n          elt(\"div\", lineNumberFor(cm.options, lineN),\n              \"CodeMirror-linenumber CodeMirror-gutter-elt\",\n              \"left: \" + dims.gutterLeft[\"CodeMirror-linenumbers\"] + \"px; width: \"\n              + cm.display.lineNumInnerWidth + \"px\"));\n      if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) {\n        var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];\n        if (found)\n          gutterWrap.appendChild(elt(\"div\", [found], \"CodeMirror-gutter-elt\", \"left: \" +\n                                     dims.gutterLeft[id] + \"px; width: \" + dims.gutterWidth[id] + \"px\"));\n      }\n    }\n  }\n\n  function updateLineWidgets(cm, lineView, dims) {\n    if (lineView.alignable) lineView.alignable = null;\n    for (var node = lineView.node.firstChild, next; node; node = next) {\n      var next = node.nextSibling;\n      if (node.className == \"CodeMirror-linewidget\")\n        lineView.node.removeChild(node);\n    }\n    insertLineWidgets(cm, lineView, dims);\n  }\n\n  // Build a line's DOM representation from scratch\n  function buildLineElement(cm, lineView, lineN, dims) {\n    var built = getLineContent(cm, lineView);\n    lineView.text = lineView.node = built.pre;\n    if (built.bgClass) lineView.bgClass = built.bgClass;\n    if (built.textClass) lineView.textClass = built.textClass;\n\n    updateLineClasses(lineView);\n    updateLineGutter(cm, lineView, lineN, dims);\n    insertLineWidgets(cm, lineView, dims);\n    return lineView.node;\n  }\n\n  // A lineView may contain multiple logical lines (when merged by\n  // collapsed spans). The widgets for all of them need to be drawn.\n  function insertLineWidgets(cm, lineView, dims) {\n    insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);\n    if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)\n      insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false);\n  }\n\n  function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {\n    if (!line.widgets) return;\n    var wrap = ensureLineWrapped(lineView);\n    for (var i = 0, ws = line.widgets; i < ws.length; ++i) {\n      var widget = ws[i], node = elt(\"div\", [widget.node], \"CodeMirror-linewidget\");\n      if (!widget.handleMouseEvents) node.setAttribute(\"cm-ignore-events\", \"true\");\n      positionLineWidget(widget, node, lineView, dims);\n      cm.display.input.setUneditable(node);\n      if (allowAbove && widget.above)\n        wrap.insertBefore(node, lineView.gutter || lineView.text);\n      else\n        wrap.appendChild(node);\n      signalLater(widget, \"redraw\");\n    }\n  }\n\n  function positionLineWidget(widget, node, lineView, dims) {\n    if (widget.noHScroll) {\n      (lineView.alignable || (lineView.alignable = [])).push(node);\n      var width = dims.wrapperWidth;\n      node.style.left = dims.fixedPos + \"px\";\n      if (!widget.coverGutter) {\n        width -= dims.gutterTotalWidth;\n        node.style.paddingLeft = dims.gutterTotalWidth + \"px\";\n      }\n      node.style.width = width + \"px\";\n    }\n    if (widget.coverGutter) {\n      node.style.zIndex = 5;\n      node.style.position = \"relative\";\n      if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + \"px\";\n    }\n  }\n\n  // POSITION OBJECT\n\n  // A Pos instance represents a position within the text.\n  var Pos = CodeMirror.Pos = function(line, ch) {\n    if (!(this instanceof Pos)) return new Pos(line, ch);\n    this.line = line; this.ch = ch;\n  };\n\n  // Compare two positions, return 0 if they are the same, a negative\n  // number when a is less, and a positive number otherwise.\n  var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; };\n\n  function copyPos(x) {return Pos(x.line, x.ch);}\n  function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; }\n  function minPos(a, b) { return cmp(a, b) < 0 ? a : b; }\n\n  // INPUT HANDLING\n\n  function ensureFocus(cm) {\n    if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }\n  }\n\n  // This will be set to a {lineWise: bool, text: [string]} object, so\n  // that, when pasting, we know what kind of selections the copied\n  // text was made out of.\n  var lastCopied = null;\n\n  function applyTextInput(cm, inserted, deleted, sel, origin) {\n    var doc = cm.doc;\n    cm.display.shift = false;\n    if (!sel) sel = doc.sel;\n\n    var paste = cm.state.pasteIncoming || origin == \"paste\";\n    var textLines = doc.splitLines(inserted), multiPaste = null\n    // When pasing N lines into N selections, insert one line per selection\n    if (paste && sel.ranges.length > 1) {\n      if (lastCopied && lastCopied.text.join(\"\\n\") == inserted) {\n        if (sel.ranges.length % lastCopied.text.length == 0) {\n          multiPaste = [];\n          for (var i = 0; i < lastCopied.text.length; i++)\n            multiPaste.push(doc.splitLines(lastCopied.text[i]));\n        }\n      } else if (textLines.length == sel.ranges.length) {\n        multiPaste = map(textLines, function(l) { return [l]; });\n      }\n    }\n\n    // Normal behavior is to insert the new text into every selection\n    for (var i = sel.ranges.length - 1; i >= 0; i--) {\n      var range = sel.ranges[i];\n      var from = range.from(), to = range.to();\n      if (range.empty()) {\n        if (deleted && deleted > 0) // Handle deletion\n          from = Pos(from.line, from.ch - deleted);\n        else if (cm.state.overwrite && !paste) // Handle overwrite\n          to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));\n        else if (lastCopied && lastCopied.lineWise && lastCopied.text.join(\"\\n\") == inserted)\n          from = to = Pos(from.line, 0)\n      }\n      var updateInput = cm.curOp.updateInput;\n      var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines,\n                         origin: origin || (paste ? \"paste\" : cm.state.cutIncoming ? \"cut\" : \"+input\")};\n      makeChange(cm.doc, changeEvent);\n      signalLater(cm, \"inputRead\", cm, changeEvent);\n    }\n    if (inserted && !paste)\n      triggerElectric(cm, inserted);\n\n    ensureCursorVisible(cm);\n    cm.curOp.updateInput = updateInput;\n    cm.curOp.typing = true;\n    cm.state.pasteIncoming = cm.state.cutIncoming = false;\n  }\n\n  function handlePaste(e, cm) {\n    var pasted = e.clipboardData && e.clipboardData.getData(\"Text\");\n    if (pasted) {\n      e.preventDefault();\n      if (!cm.isReadOnly() && !cm.options.disableInput)\n        runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, \"paste\"); });\n      return true;\n    }\n  }\n\n  function triggerElectric(cm, inserted) {\n    // When an 'electric' character is inserted, immediately trigger a reindent\n    if (!cm.options.electricChars || !cm.options.smartIndent) return;\n    var sel = cm.doc.sel;\n\n    for (var i = sel.ranges.length - 1; i >= 0; i--) {\n      var range = sel.ranges[i];\n      if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue;\n      var mode = cm.getModeAt(range.head);\n      var indented = false;\n      if (mode.electricChars) {\n        for (var j = 0; j < mode.electricChars.length; j++)\n          if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {\n            indented = indentLine(cm, range.head.line, \"smart\");\n            break;\n          }\n      } else if (mode.electricInput) {\n        if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch)))\n          indented = indentLine(cm, range.head.line, \"smart\");\n      }\n      if (indented) signalLater(cm, \"electricInput\", cm, range.head.line);\n    }\n  }\n\n  function copyableRanges(cm) {\n    var text = [], ranges = [];\n    for (var i = 0; i < cm.doc.sel.ranges.length; i++) {\n      var line = cm.doc.sel.ranges[i].head.line;\n      var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};\n      ranges.push(lineRange);\n      text.push(cm.getRange(lineRange.anchor, lineRange.head));\n    }\n    return {text: text, ranges: ranges};\n  }\n\n  function disableBrowserMagic(field, spellcheck) {\n    field.setAttribute(\"autocorrect\", \"off\");\n    field.setAttribute(\"autocapitalize\", \"off\");\n    field.setAttribute(\"spellcheck\", !!spellcheck);\n  }\n\n  // TEXTAREA INPUT STYLE\n\n  function TextareaInput(cm) {\n    this.cm = cm;\n    // See input.poll and input.reset\n    this.prevInput = \"\";\n\n    // Flag that indicates whether we expect input to appear real soon\n    // now (after some event like 'keypress' or 'input') and are\n    // polling intensively.\n    this.pollingFast = false;\n    // Self-resetting timeout for the poller\n    this.polling = new Delayed();\n    // Tracks when input.reset has punted to just putting a short\n    // string into the textarea instead of the full selection.\n    this.inaccurateSelection = false;\n    // Used to work around IE issue with selection being forgotten when focus moves away from textarea\n    this.hasSelection = false;\n    this.composing = null;\n  };\n\n  function hiddenTextarea() {\n    var te = elt(\"textarea\", null, null, \"position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none\");\n    var div = elt(\"div\", [te], null, \"overflow: hidden; position: relative; width: 3px; height: 0px;\");\n    // The textarea is kept positioned near the cursor to prevent the\n    // fact that it'll be scrolled into view on input from scrolling\n    // our fake cursor out of view. On webkit, when wrap=off, paste is\n    // very slow. So make the area wide instead.\n    if (webkit) te.style.width = \"1000px\";\n    else te.setAttribute(\"wrap\", \"off\");\n    // If border: 0; -- iOS fails to open keyboard (issue #1287)\n    if (ios) te.style.border = \"1px solid black\";\n    disableBrowserMagic(te);\n    return div;\n  }\n\n  TextareaInput.prototype = copyObj({\n    init: function(display) {\n      var input = this, cm = this.cm;\n\n      // Wraps and hides input textarea\n      var div = this.wrapper = hiddenTextarea();\n      // The semihidden textarea that is focused when the editor is\n      // focused, and receives input.\n      var te = this.textarea = div.firstChild;\n      display.wrapper.insertBefore(div, display.wrapper.firstChild);\n\n      // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)\n      if (ios) te.style.width = \"0px\";\n\n      on(te, \"input\", function() {\n        if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null;\n        input.poll();\n      });\n\n      on(te, \"paste\", function(e) {\n        if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return\n\n        cm.state.pasteIncoming = true;\n        input.fastPoll();\n      });\n\n      function prepareCopyCut(e) {\n        if (signalDOMEvent(cm, e)) return\n        if (cm.somethingSelected()) {\n          lastCopied = {lineWise: false, text: cm.getSelections()};\n          if (input.inaccurateSelection) {\n            input.prevInput = \"\";\n            input.inaccurateSelection = false;\n            te.value = lastCopied.text.join(\"\\n\");\n            selectInput(te);\n          }\n        } else if (!cm.options.lineWiseCopyCut) {\n          return;\n        } else {\n          var ranges = copyableRanges(cm);\n          lastCopied = {lineWise: true, text: ranges.text};\n          if (e.type == \"cut\") {\n            cm.setSelections(ranges.ranges, null, sel_dontScroll);\n          } else {\n            input.prevInput = \"\";\n            te.value = ranges.text.join(\"\\n\");\n            selectInput(te);\n          }\n        }\n        if (e.type == \"cut\") cm.state.cutIncoming = true;\n      }\n      on(te, \"cut\", prepareCopyCut);\n      on(te, \"copy\", prepareCopyCut);\n\n      on(display.scroller, \"paste\", function(e) {\n        if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return;\n        cm.state.pasteIncoming = true;\n        input.focus();\n      });\n\n      // Prevent normal selection in the editor (we handle our own)\n      on(display.lineSpace, \"selectstart\", function(e) {\n        if (!eventInWidget(display, e)) e_preventDefault(e);\n      });\n\n      on(te, \"compositionstart\", function() {\n        var start = cm.getCursor(\"from\");\n        if (input.composing) input.composing.range.clear()\n        input.composing = {\n          start: start,\n          range: cm.markText(start, cm.getCursor(\"to\"), {className: \"CodeMirror-composing\"})\n        };\n      });\n      on(te, \"compositionend\", function() {\n        if (input.composing) {\n          input.poll();\n          input.composing.range.clear();\n          input.composing = null;\n        }\n      });\n    },\n\n    prepareSelection: function() {\n      // Redraw the selection and/or cursor\n      var cm = this.cm, display = cm.display, doc = cm.doc;\n      var result = prepareSelection(cm);\n\n      // Move the hidden textarea near the cursor to prevent scrolling artifacts\n      if (cm.options.moveInputWithCursor) {\n        var headPos = cursorCoords(cm, doc.sel.primary().head, \"div\");\n        var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();\n        result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,\n                                            headPos.top + lineOff.top - wrapOff.top));\n        result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,\n                                             headPos.left + lineOff.left - wrapOff.left));\n      }\n\n      return result;\n    },\n\n    showSelection: function(drawn) {\n      var cm = this.cm, display = cm.display;\n      removeChildrenAndAdd(display.cursorDiv, drawn.cursors);\n      removeChildrenAndAdd(display.selectionDiv, drawn.selection);\n      if (drawn.teTop != null) {\n        this.wrapper.style.top = drawn.teTop + \"px\";\n        this.wrapper.style.left = drawn.teLeft + \"px\";\n      }\n    },\n\n    // Reset the input to correspond to the selection (or to be empty,\n    // when not typing and nothing is selected)\n    reset: function(typing) {\n      if (this.contextMenuPending) return;\n      var minimal, selected, cm = this.cm, doc = cm.doc;\n      if (cm.somethingSelected()) {\n        this.prevInput = \"\";\n        var range = doc.sel.primary();\n        minimal = hasCopyEvent &&\n          (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000);\n        var content = minimal ? \"-\" : selected || cm.getSelection();\n        this.textarea.value = content;\n        if (cm.state.focused) selectInput(this.textarea);\n        if (ie && ie_version >= 9) this.hasSelection = content;\n      } else if (!typing) {\n        this.prevInput = this.textarea.value = \"\";\n        if (ie && ie_version >= 9) this.hasSelection = null;\n      }\n      this.inaccurateSelection = minimal;\n    },\n\n    getField: function() { return this.textarea; },\n\n    supportsTouch: function() { return false; },\n\n    focus: function() {\n      if (this.cm.options.readOnly != \"nocursor\" && (!mobile || activeElt() != this.textarea)) {\n        try { this.textarea.focus(); }\n        catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM\n      }\n    },\n\n    blur: function() { this.textarea.blur(); },\n\n    resetPosition: function() {\n      this.wrapper.style.top = this.wrapper.style.left = 0;\n    },\n\n    receivedFocus: function() { this.slowPoll(); },\n\n    // Poll for input changes, using the normal rate of polling. This\n    // runs as long as the editor is focused.\n    slowPoll: function() {\n      var input = this;\n      if (input.pollingFast) return;\n      input.polling.set(this.cm.options.pollInterval, function() {\n        input.poll();\n        if (input.cm.state.focused) input.slowPoll();\n      });\n    },\n\n    // When an event has just come in that is likely to add or change\n    // something in the input textarea, we poll faster, to ensure that\n    // the change appears on the screen quickly.\n    fastPoll: function() {\n      var missed = false, input = this;\n      input.pollingFast = true;\n      function p() {\n        var changed = input.poll();\n        if (!changed && !missed) {missed = true; input.polling.set(60, p);}\n        else {input.pollingFast = false; input.slowPoll();}\n      }\n      input.polling.set(20, p);\n    },\n\n    // Read input from the textarea, and update the document to match.\n    // When something is selected, it is present in the textarea, and\n    // selected (unless it is huge, in which case a placeholder is\n    // used). When nothing is selected, the cursor sits after previously\n    // seen text (can be empty), which is stored in prevInput (we must\n    // not reset the textarea when typing, because that breaks IME).\n    poll: function() {\n      var cm = this.cm, input = this.textarea, prevInput = this.prevInput;\n      // Since this is called a *lot*, try to bail out as cheaply as\n      // possible when it is clear that nothing happened. hasSelection\n      // will be the case when there is a lot of text in the textarea,\n      // in which case reading its value would be expensive.\n      if (this.contextMenuPending || !cm.state.focused ||\n          (hasSelection(input) && !prevInput && !this.composing) ||\n          cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)\n        return false;\n\n      var text = input.value;\n      // If nothing changed, bail.\n      if (text == prevInput && !cm.somethingSelected()) return false;\n      // Work around nonsensical selection resetting in IE9/10, and\n      // inexplicable appearance of private area unicode characters on\n      // some key combos in Mac (#2689).\n      if (ie && ie_version >= 9 && this.hasSelection === text ||\n          mac && /[\\uf700-\\uf7ff]/.test(text)) {\n        cm.display.input.reset();\n        return false;\n      }\n\n      if (cm.doc.sel == cm.display.selForContextMenu) {\n        var first = text.charCodeAt(0);\n        if (first == 0x200b && !prevInput) prevInput = \"\\u200b\";\n        if (first == 0x21da) { this.reset(); return this.cm.execCommand(\"undo\"); }\n      }\n      // Find the part of the input that is actually new\n      var same = 0, l = Math.min(prevInput.length, text.length);\n      while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;\n\n      var self = this;\n      runInOp(cm, function() {\n        applyTextInput(cm, text.slice(same), prevInput.length - same,\n                       null, self.composing ? \"*compose\" : null);\n\n        // Don't leave long text in the textarea, since it makes further polling slow\n        if (text.length > 1000 || text.indexOf(\"\\n\") > -1) input.value = self.prevInput = \"\";\n        else self.prevInput = text;\n\n        if (self.composing) {\n          self.composing.range.clear();\n          self.composing.range = cm.markText(self.composing.start, cm.getCursor(\"to\"),\n                                             {className: \"CodeMirror-composing\"});\n        }\n      });\n      return true;\n    },\n\n    ensurePolled: function() {\n      if (this.pollingFast && this.poll()) this.pollingFast = false;\n    },\n\n    onKeyPress: function() {\n      if (ie && ie_version >= 9) this.hasSelection = null;\n      this.fastPoll();\n    },\n\n    onContextMenu: function(e) {\n      var input = this, cm = input.cm, display = cm.display, te = input.textarea;\n      var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;\n      if (!pos || presto) return; // Opera is difficult.\n\n      // Reset the current text selection only if the click is done outside of the selection\n      // and 'resetSelectionOnContextMenu' option is true.\n      var reset = cm.options.resetSelectionOnContextMenu;\n      if (reset && cm.doc.sel.contains(pos) == -1)\n        operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);\n\n      var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;\n      input.wrapper.style.cssText = \"position: absolute\"\n      var wrapperBox = input.wrapper.getBoundingClientRect()\n      te.style.cssText = \"position: absolute; width: 30px; height: 30px; top: \" + (e.clientY - wrapperBox.top - 5) +\n        \"px; left: \" + (e.clientX - wrapperBox.left - 5) + \"px; z-index: 1000; background: \" +\n        (ie ? \"rgba(255, 255, 255, .05)\" : \"transparent\") +\n        \"; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);\";\n      if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)\n      display.input.focus();\n      if (webkit) window.scrollTo(null, oldScrollY);\n      display.input.reset();\n      // Adds \"Select all\" to context menu in FF\n      if (!cm.somethingSelected()) te.value = input.prevInput = \" \";\n      input.contextMenuPending = true;\n      display.selForContextMenu = cm.doc.sel;\n      clearTimeout(display.detectingSelectAll);\n\n      // Select-all will be greyed out if there's nothing to select, so\n      // this adds a zero-width space so that we can later check whether\n      // it got selected.\n      function prepareSelectAllHack() {\n        if (te.selectionStart != null) {\n          var selected = cm.somethingSelected();\n          var extval = \"\\u200b\" + (selected ? te.value : \"\");\n          te.value = \"\\u21da\"; // Used to catch context-menu undo\n          te.value = extval;\n          input.prevInput = selected ? \"\" : \"\\u200b\";\n          te.selectionStart = 1; te.selectionEnd = extval.length;\n          // Re-set this, in case some other handler touched the\n          // selection in the meantime.\n          display.selForContextMenu = cm.doc.sel;\n        }\n      }\n      function rehide() {\n        input.contextMenuPending = false;\n        input.wrapper.style.cssText = oldWrapperCSS\n        te.style.cssText = oldCSS;\n        if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);\n\n        // Try to detect the user choosing select-all\n        if (te.selectionStart != null) {\n          if (!ie || (ie && ie_version < 9)) prepareSelectAllHack();\n          var i = 0, poll = function() {\n            if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&\n                te.selectionEnd > 0 && input.prevInput == \"\\u200b\")\n              operation(cm, commands.selectAll)(cm);\n            else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500);\n            else display.input.reset();\n          };\n          display.detectingSelectAll = setTimeout(poll, 200);\n        }\n      }\n\n      if (ie && ie_version >= 9) prepareSelectAllHack();\n      if (captureRightClick) {\n        e_stop(e);\n        var mouseup = function() {\n          off(window, \"mouseup\", mouseup);\n          setTimeout(rehide, 20);\n        };\n        on(window, \"mouseup\", mouseup);\n      } else {\n        setTimeout(rehide, 50);\n      }\n    },\n\n    readOnlyChanged: function(val) {\n      if (!val) this.reset();\n    },\n\n    setUneditable: nothing,\n\n    needsContentAttribute: false\n  }, TextareaInput.prototype);\n\n  // CONTENTEDITABLE INPUT STYLE\n\n  function ContentEditableInput(cm) {\n    this.cm = cm;\n    this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;\n    this.polling = new Delayed();\n    this.gracePeriod = false;\n  }\n\n  ContentEditableInput.prototype = copyObj({\n    init: function(display) {\n      var input = this, cm = input.cm;\n      var div = input.div = display.lineDiv;\n      disableBrowserMagic(div, cm.options.spellcheck);\n\n      on(div, \"paste\", function(e) {\n        if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return\n        // IE doesn't fire input events, so we schedule a read for the pasted content in this way\n        if (ie_version <= 11) setTimeout(operation(cm, function() {\n          if (!input.pollContent()) regChange(cm);\n        }), 20)\n      })\n\n      on(div, \"compositionstart\", function(e) {\n        var data = e.data;\n        input.composing = {sel: cm.doc.sel, data: data, startData: data};\n        if (!data) return;\n        var prim = cm.doc.sel.primary();\n        var line = cm.getLine(prim.head.line);\n        var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length));\n        if (found > -1 && found <= prim.head.ch)\n          input.composing.sel = simpleSelection(Pos(prim.head.line, found),\n                                                Pos(prim.head.line, found + data.length));\n      });\n      on(div, \"compositionupdate\", function(e) {\n        input.composing.data = e.data;\n      });\n      on(div, \"compositionend\", function(e) {\n        var ours = input.composing;\n        if (!ours) return;\n        if (e.data != ours.startData && !/\\u200b/.test(e.data))\n          ours.data = e.data;\n        // Need a small delay to prevent other code (input event,\n        // selection polling) from doing damage when fired right after\n        // compositionend.\n        setTimeout(function() {\n          if (!ours.handled)\n            input.applyComposition(ours);\n          if (input.composing == ours)\n            input.composing = null;\n        }, 50);\n      });\n\n      on(div, \"touchstart\", function() {\n        input.forceCompositionEnd();\n      });\n\n      on(div, \"input\", function() {\n        if (input.composing) return;\n        if (cm.isReadOnly() || !input.pollContent())\n          runInOp(input.cm, function() {regChange(cm);});\n      });\n\n      function onCopyCut(e) {\n        if (signalDOMEvent(cm, e)) return\n        if (cm.somethingSelected()) {\n          lastCopied = {lineWise: false, text: cm.getSelections()};\n          if (e.type == \"cut\") cm.replaceSelection(\"\", null, \"cut\");\n        } else if (!cm.options.lineWiseCopyCut) {\n          return;\n        } else {\n          var ranges = copyableRanges(cm);\n          lastCopied = {lineWise: true, text: ranges.text};\n          if (e.type == \"cut\") {\n            cm.operation(function() {\n              cm.setSelections(ranges.ranges, 0, sel_dontScroll);\n              cm.replaceSelection(\"\", null, \"cut\");\n            });\n          }\n        }\n        if (e.clipboardData) {\n          e.clipboardData.clearData();\n          var content = lastCopied.text.join(\"\\n\")\n          // iOS exposes the clipboard API, but seems to discard content inserted into it\n          e.clipboardData.setData(\"Text\", content);\n          if (e.clipboardData.getData(\"Text\") == content) {\n            e.preventDefault();\n            return\n          }\n        }\n        // Old-fashioned briefly-focus-a-textarea hack\n        var kludge = hiddenTextarea(), te = kludge.firstChild;\n        cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);\n        te.value = lastCopied.text.join(\"\\n\");\n        var hadFocus = document.activeElement;\n        selectInput(te);\n        setTimeout(function() {\n          cm.display.lineSpace.removeChild(kludge);\n          hadFocus.focus();\n          if (hadFocus == div) input.showPrimarySelection()\n        }, 50);\n      }\n      on(div, \"copy\", onCopyCut);\n      on(div, \"cut\", onCopyCut);\n    },\n\n    prepareSelection: function() {\n      var result = prepareSelection(this.cm, false);\n      result.focus = this.cm.state.focused;\n      return result;\n    },\n\n    showSelection: function(info, takeFocus) {\n      if (!info || !this.cm.display.view.length) return;\n      if (info.focus || takeFocus) this.showPrimarySelection();\n      this.showMultipleSelections(info);\n    },\n\n    showPrimarySelection: function() {\n      var sel = window.getSelection(), prim = this.cm.doc.sel.primary();\n      var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset);\n      var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset);\n      if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&\n          cmp(minPos(curAnchor, curFocus), prim.from()) == 0 &&\n          cmp(maxPos(curAnchor, curFocus), prim.to()) == 0)\n        return;\n\n      var start = posToDOM(this.cm, prim.from());\n      var end = posToDOM(this.cm, prim.to());\n      if (!start && !end) return;\n\n      var view = this.cm.display.view;\n      var old = sel.rangeCount && sel.getRangeAt(0);\n      if (!start) {\n        start = {node: view[0].measure.map[2], offset: 0};\n      } else if (!end) { // FIXME dangerously hacky\n        var measure = view[view.length - 1].measure;\n        var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;\n        end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]};\n      }\n\n      try { var rng = range(start.node, start.offset, end.offset, end.node); }\n      catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible\n      if (rng) {\n        if (!gecko && this.cm.state.focused) {\n          sel.collapse(start.node, start.offset);\n          if (!rng.collapsed) sel.addRange(rng);\n        } else {\n          sel.removeAllRanges();\n          sel.addRange(rng);\n        }\n        if (old && sel.anchorNode == null) sel.addRange(old);\n        else if (gecko) this.startGracePeriod();\n      }\n      this.rememberSelection();\n    },\n\n    startGracePeriod: function() {\n      var input = this;\n      clearTimeout(this.gracePeriod);\n      this.gracePeriod = setTimeout(function() {\n        input.gracePeriod = false;\n        if (input.selectionChanged())\n          input.cm.operation(function() { input.cm.curOp.selectionChanged = true; });\n      }, 20);\n    },\n\n    showMultipleSelections: function(info) {\n      removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);\n      removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);\n    },\n\n    rememberSelection: function() {\n      var sel = window.getSelection();\n      this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;\n      this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;\n    },\n\n    selectionInEditor: function() {\n      var sel = window.getSelection();\n      if (!sel.rangeCount) return false;\n      var node = sel.getRangeAt(0).commonAncestorContainer;\n      return contains(this.div, node);\n    },\n\n    focus: function() {\n      if (this.cm.options.readOnly != \"nocursor\") this.div.focus();\n    },\n    blur: function() { this.div.blur(); },\n    getField: function() { return this.div; },\n\n    supportsTouch: function() { return true; },\n\n    receivedFocus: function() {\n      var input = this;\n      if (this.selectionInEditor())\n        this.pollSelection();\n      else\n        runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; });\n\n      function poll() {\n        if (input.cm.state.focused) {\n          input.pollSelection();\n          input.polling.set(input.cm.options.pollInterval, poll);\n        }\n      }\n      this.polling.set(this.cm.options.pollInterval, poll);\n    },\n\n    selectionChanged: function() {\n      var sel = window.getSelection();\n      return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||\n        sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset;\n    },\n\n    pollSelection: function() {\n      if (!this.composing && !this.gracePeriod && this.selectionChanged()) {\n        var sel = window.getSelection(), cm = this.cm;\n        this.rememberSelection();\n        var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);\n        var head = domToPos(cm, sel.focusNode, sel.focusOffset);\n        if (anchor && head) runInOp(cm, function() {\n          setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);\n          if (anchor.bad || head.bad) cm.curOp.selectionChanged = true;\n        });\n      }\n    },\n\n    pollContent: function() {\n      var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();\n      var from = sel.from(), to = sel.to();\n      if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false;\n\n      var fromIndex;\n      if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {\n        var fromLine = lineNo(display.view[0].line);\n        var fromNode = display.view[0].node;\n      } else {\n        var fromLine = lineNo(display.view[fromIndex].line);\n        var fromNode = display.view[fromIndex - 1].node.nextSibling;\n      }\n      var toIndex = findViewIndex(cm, to.line);\n      if (toIndex == display.view.length - 1) {\n        var toLine = display.viewTo - 1;\n        var toNode = display.lineDiv.lastChild;\n      } else {\n        var toLine = lineNo(display.view[toIndex + 1].line) - 1;\n        var toNode = display.view[toIndex + 1].node.previousSibling;\n      }\n\n      var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));\n      var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));\n      while (newText.length > 1 && oldText.length > 1) {\n        if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }\n        else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }\n        else break;\n      }\n\n      var cutFront = 0, cutEnd = 0;\n      var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);\n      while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))\n        ++cutFront;\n      var newBot = lst(newText), oldBot = lst(oldText);\n      var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),\n                               oldBot.length - (oldText.length == 1 ? cutFront : 0));\n      while (cutEnd < maxCutEnd &&\n             newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))\n        ++cutEnd;\n\n      newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd);\n      newText[0] = newText[0].slice(cutFront);\n\n      var chFrom = Pos(fromLine, cutFront);\n      var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);\n      if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {\n        replaceRange(cm.doc, newText, chFrom, chTo, \"+input\");\n        return true;\n      }\n    },\n\n    ensurePolled: function() {\n      this.forceCompositionEnd();\n    },\n    reset: function() {\n      this.forceCompositionEnd();\n    },\n    forceCompositionEnd: function() {\n      if (!this.composing || this.composing.handled) return;\n      this.applyComposition(this.composing);\n      this.composing.handled = true;\n      this.div.blur();\n      this.div.focus();\n    },\n    applyComposition: function(composing) {\n      if (this.cm.isReadOnly())\n        operation(this.cm, regChange)(this.cm)\n      else if (composing.data && composing.data != composing.startData)\n        operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);\n    },\n\n    setUneditable: function(node) {\n      node.contentEditable = \"false\"\n    },\n\n    onKeyPress: function(e) {\n      e.preventDefault();\n      if (!this.cm.isReadOnly())\n        operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);\n    },\n\n    readOnlyChanged: function(val) {\n      this.div.contentEditable = String(val != \"nocursor\")\n    },\n\n    onContextMenu: nothing,\n    resetPosition: nothing,\n\n    needsContentAttribute: true\n  }, ContentEditableInput.prototype);\n\n  function posToDOM(cm, pos) {\n    var view = findViewForLine(cm, pos.line);\n    if (!view || view.hidden) return null;\n    var line = getLine(cm.doc, pos.line);\n    var info = mapFromLineView(view, line, pos.line);\n\n    var order = getOrder(line), side = \"left\";\n    if (order) {\n      var partPos = getBidiPartAt(order, pos.ch);\n      side = partPos % 2 ? \"right\" : \"left\";\n    }\n    var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);\n    result.offset = result.collapse == \"right\" ? result.end : result.start;\n    return result;\n  }\n\n  function badPos(pos, bad) { if (bad) pos.bad = true; return pos; }\n\n  function domToPos(cm, node, offset) {\n    var lineNode;\n    if (node == cm.display.lineDiv) {\n      lineNode = cm.display.lineDiv.childNodes[offset];\n      if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true);\n      node = null; offset = 0;\n    } else {\n      for (lineNode = node;; lineNode = lineNode.parentNode) {\n        if (!lineNode || lineNode == cm.display.lineDiv) return null;\n        if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break;\n      }\n    }\n    for (var i = 0; i < cm.display.view.length; i++) {\n      var lineView = cm.display.view[i];\n      if (lineView.node == lineNode)\n        return locateNodeInLineView(lineView, node, offset);\n    }\n  }\n\n  function locateNodeInLineView(lineView, node, offset) {\n    var wrapper = lineView.text.firstChild, bad = false;\n    if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true);\n    if (node == wrapper) {\n      bad = true;\n      node = wrapper.childNodes[offset];\n      offset = 0;\n      if (!node) {\n        var line = lineView.rest ? lst(lineView.rest) : lineView.line;\n        return badPos(Pos(lineNo(line), line.text.length), bad);\n      }\n    }\n\n    var textNode = node.nodeType == 3 ? node : null, topNode = node;\n    if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {\n      textNode = node.firstChild;\n      if (offset) offset = textNode.nodeValue.length;\n    }\n    while (topNode.parentNode != wrapper) topNode = topNode.parentNode;\n    var measure = lineView.measure, maps = measure.maps;\n\n    function find(textNode, topNode, offset) {\n      for (var i = -1; i < (maps ? maps.length : 0); i++) {\n        var map = i < 0 ? measure.map : maps[i];\n        for (var j = 0; j < map.length; j += 3) {\n          var curNode = map[j + 2];\n          if (curNode == textNode || curNode == topNode) {\n            var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);\n            var ch = map[j] + offset;\n            if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)];\n            return Pos(line, ch);\n          }\n        }\n      }\n    }\n    var found = find(textNode, topNode, offset);\n    if (found) return badPos(found, bad);\n\n    // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems\n    for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {\n      found = find(after, after.firstChild, 0);\n      if (found)\n        return badPos(Pos(found.line, found.ch - dist), bad);\n      else\n        dist += after.textContent.length;\n    }\n    for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) {\n      found = find(before, before.firstChild, -1);\n      if (found)\n        return badPos(Pos(found.line, found.ch + dist), bad);\n      else\n        dist += before.textContent.length;\n    }\n  }\n\n  function domTextBetween(cm, from, to, fromLine, toLine) {\n    var text = \"\", closing = false, lineSep = cm.doc.lineSeparator();\n    function recognizeMarker(id) { return function(marker) { return marker.id == id; }; }\n    function walk(node) {\n      if (node.nodeType == 1) {\n        var cmText = node.getAttribute(\"cm-text\");\n        if (cmText != null) {\n          if (cmText == \"\") cmText = node.textContent.replace(/\\u200b/g, \"\");\n          text += cmText;\n          return;\n        }\n        var markerID = node.getAttribute(\"cm-marker\"), range;\n        if (markerID) {\n          var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));\n          if (found.length && (range = found[0].find()))\n            text += getBetween(cm.doc, range.from, range.to).join(lineSep);\n          return;\n        }\n        if (node.getAttribute(\"contenteditable\") == \"false\") return;\n        for (var i = 0; i < node.childNodes.length; i++)\n          walk(node.childNodes[i]);\n        if (/^(pre|div|p)$/i.test(node.nodeName))\n          closing = true;\n      } else if (node.nodeType == 3) {\n        var val = node.nodeValue;\n        if (!val) return;\n        if (closing) {\n          text += lineSep;\n          closing = false;\n        }\n        text += val;\n      }\n    }\n    for (;;) {\n      walk(from);\n      if (from == to) break;\n      from = from.nextSibling;\n    }\n    return text;\n  }\n\n  CodeMirror.inputStyles = {\"textarea\": TextareaInput, \"contenteditable\": ContentEditableInput};\n\n  // SELECTION / CURSOR\n\n  // Selection objects are immutable. A new one is created every time\n  // the selection changes. A selection is one or more non-overlapping\n  // (and non-touching) ranges, sorted, and an integer that indicates\n  // which one is the primary selection (the one that's scrolled into\n  // view, that getCursor returns, etc).\n  function Selection(ranges, primIndex) {\n    this.ranges = ranges;\n    this.primIndex = primIndex;\n  }\n\n  Selection.prototype = {\n    primary: function() { return this.ranges[this.primIndex]; },\n    equals: function(other) {\n      if (other == this) return true;\n      if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false;\n      for (var i = 0; i < this.ranges.length; i++) {\n        var here = this.ranges[i], there = other.ranges[i];\n        if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false;\n      }\n      return true;\n    },\n    deepCopy: function() {\n      for (var out = [], i = 0; i < this.ranges.length; i++)\n        out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head));\n      return new Selection(out, this.primIndex);\n    },\n    somethingSelected: function() {\n      for (var i = 0; i < this.ranges.length; i++)\n        if (!this.ranges[i].empty()) return true;\n      return false;\n    },\n    contains: function(pos, end) {\n      if (!end) end = pos;\n      for (var i = 0; i < this.ranges.length; i++) {\n        var range = this.ranges[i];\n        if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)\n          return i;\n      }\n      return -1;\n    }\n  };\n\n  function Range(anchor, head) {\n    this.anchor = anchor; this.head = head;\n  }\n\n  Range.prototype = {\n    from: function() { return minPos(this.anchor, this.head); },\n    to: function() { return maxPos(this.anchor, this.head); },\n    empty: function() {\n      return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch;\n    }\n  };\n\n  // Take an unsorted, potentially overlapping set of ranges, and\n  // build a selection out of it. 'Consumes' ranges array (modifying\n  // it).\n  function normalizeSelection(ranges, primIndex) {\n    var prim = ranges[primIndex];\n    ranges.sort(function(a, b) { return cmp(a.from(), b.from()); });\n    primIndex = indexOf(ranges, prim);\n    for (var i = 1; i < ranges.length; i++) {\n      var cur = ranges[i], prev = ranges[i - 1];\n      if (cmp(prev.to(), cur.from()) >= 0) {\n        var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());\n        var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;\n        if (i <= primIndex) --primIndex;\n        ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));\n      }\n    }\n    return new Selection(ranges, primIndex);\n  }\n\n  function simpleSelection(anchor, head) {\n    return new Selection([new Range(anchor, head || anchor)], 0);\n  }\n\n  // Most of the external API clips given positions to make sure they\n  // actually exist within the document.\n  function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));}\n  function clipPos(doc, pos) {\n    if (pos.line < doc.first) return Pos(doc.first, 0);\n    var last = doc.first + doc.size - 1;\n    if (pos.line > last) return Pos(last, getLine(doc, last).text.length);\n    return clipToLen(pos, getLine(doc, pos.line).text.length);\n  }\n  function clipToLen(pos, linelen) {\n    var ch = pos.ch;\n    if (ch == null || ch > linelen) return Pos(pos.line, linelen);\n    else if (ch < 0) return Pos(pos.line, 0);\n    else return pos;\n  }\n  function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;}\n  function clipPosArray(doc, array) {\n    for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]);\n    return out;\n  }\n\n  // SELECTION UPDATES\n\n  // The 'scroll' parameter given to many of these indicated whether\n  // the new cursor position should be scrolled into view after\n  // modifying the selection.\n\n  // If shift is held or the extend flag is set, extends a range to\n  // include a given position (and optionally a second position).\n  // Otherwise, simply returns the range between the given positions.\n  // Used for cursor motion and such.\n  function extendRange(doc, range, head, other) {\n    if (doc.cm && doc.cm.display.shift || doc.extend) {\n      var anchor = range.anchor;\n      if (other) {\n        var posBefore = cmp(head, anchor) < 0;\n        if (posBefore != (cmp(other, anchor) < 0)) {\n          anchor = head;\n          head = other;\n        } else if (posBefore != (cmp(head, other) < 0)) {\n          head = other;\n        }\n      }\n      return new Range(anchor, head);\n    } else {\n      return new Range(other || head, head);\n    }\n  }\n\n  // Extend the primary selection range, discard the rest.\n  function extendSelection(doc, head, other, options) {\n    setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options);\n  }\n\n  // Extend all selections (pos is an array of selections with length\n  // equal the number of selections)\n  function extendSelections(doc, heads, options) {\n    for (var out = [], i = 0; i < doc.sel.ranges.length; i++)\n      out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null);\n    var newSel = normalizeSelection(out, doc.sel.primIndex);\n    setSelection(doc, newSel, options);\n  }\n\n  // Updates a single range in the selection.\n  function replaceOneSelection(doc, i, range, options) {\n    var ranges = doc.sel.ranges.slice(0);\n    ranges[i] = range;\n    setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);\n  }\n\n  // Reset the selection to a single range.\n  function setSimpleSelection(doc, anchor, head, options) {\n    setSelection(doc, simpleSelection(anchor, head), options);\n  }\n\n  // Give beforeSelectionChange handlers a change to influence a\n  // selection update.\n  function filterSelectionChange(doc, sel, options) {\n    var obj = {\n      ranges: sel.ranges,\n      update: function(ranges) {\n        this.ranges = [];\n        for (var i = 0; i < ranges.length; i++)\n          this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),\n                                     clipPos(doc, ranges[i].head));\n      },\n      origin: options && options.origin\n    };\n    signal(doc, \"beforeSelectionChange\", doc, obj);\n    if (doc.cm) signal(doc.cm, \"beforeSelectionChange\", doc.cm, obj);\n    if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1);\n    else return sel;\n  }\n\n  function setSelectionReplaceHistory(doc, sel, options) {\n    var done = doc.history.done, last = lst(done);\n    if (last && last.ranges) {\n      done[done.length - 1] = sel;\n      setSelectionNoUndo(doc, sel, options);\n    } else {\n      setSelection(doc, sel, options);\n    }\n  }\n\n  // Set a new selection.\n  function setSelection(doc, sel, options) {\n    setSelectionNoUndo(doc, sel, options);\n    addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);\n  }\n\n  function setSelectionNoUndo(doc, sel, options) {\n    if (hasHandler(doc, \"beforeSelectionChange\") || doc.cm && hasHandler(doc.cm, \"beforeSelectionChange\"))\n      sel = filterSelectionChange(doc, sel, options);\n\n    var bias = options && options.bias ||\n      (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);\n    setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));\n\n    if (!(options && options.scroll === false) && doc.cm)\n      ensureCursorVisible(doc.cm);\n  }\n\n  function setSelectionInner(doc, sel) {\n    if (sel.equals(doc.sel)) return;\n\n    doc.sel = sel;\n\n    if (doc.cm) {\n      doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;\n      signalCursorActivity(doc.cm);\n    }\n    signalLater(doc, \"cursorActivity\", doc);\n  }\n\n  // Verify that the selection does not partially select any atomic\n  // marked ranges.\n  function reCheckSelection(doc) {\n    setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll);\n  }\n\n  // Return a selection that does not partially select any atomic\n  // ranges.\n  function skipAtomicInSelection(doc, sel, bias, mayClear) {\n    var out;\n    for (var i = 0; i < sel.ranges.length; i++) {\n      var range = sel.ranges[i];\n      var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];\n      var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);\n      var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);\n      if (out || newAnchor != range.anchor || newHead != range.head) {\n        if (!out) out = sel.ranges.slice(0, i);\n        out[i] = new Range(newAnchor, newHead);\n      }\n    }\n    return out ? normalizeSelection(out, sel.primIndex) : sel;\n  }\n\n  function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {\n    var line = getLine(doc, pos.line);\n    if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {\n      var sp = line.markedSpans[i], m = sp.marker;\n      if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&\n          (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {\n        if (mayClear) {\n          signal(m, \"beforeCursorEnter\");\n          if (m.explicitlyCleared) {\n            if (!line.markedSpans) break;\n            else {--i; continue;}\n          }\n        }\n        if (!m.atomic) continue;\n\n        if (oldPos) {\n          var near = m.find(dir < 0 ? 1 : -1), diff;\n          if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)\n            near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null);\n          if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))\n            return skipAtomicInner(doc, near, pos, dir, mayClear);\n        }\n\n        var far = m.find(dir < 0 ? -1 : 1);\n        if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)\n          far = movePos(doc, far, dir, far.line == pos.line ? line : null);\n        return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null;\n      }\n    }\n    return pos;\n  }\n\n  // Ensure a given position is not inside an atomic range.\n  function skipAtomic(doc, pos, oldPos, bias, mayClear) {\n    var dir = bias || 1;\n    var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||\n        (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||\n        skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||\n        (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));\n    if (!found) {\n      doc.cantEdit = true;\n      return Pos(doc.first, 0);\n    }\n    return found;\n  }\n\n  function movePos(doc, pos, dir, line) {\n    if (dir < 0 && pos.ch == 0) {\n      if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1));\n      else return null;\n    } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {\n      if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0);\n      else return null;\n    } else {\n      return new Pos(pos.line, pos.ch + dir);\n    }\n  }\n\n  // SELECTION DRAWING\n\n  function updateSelection(cm) {\n    cm.display.input.showSelection(cm.display.input.prepareSelection());\n  }\n\n  function prepareSelection(cm, primary) {\n    var doc = cm.doc, result = {};\n    var curFragment = result.cursors = document.createDocumentFragment();\n    var selFragment = result.selection = document.createDocumentFragment();\n\n    for (var i = 0; i < doc.sel.ranges.length; i++) {\n      if (primary === false && i == doc.sel.primIndex) continue;\n      var range = doc.sel.ranges[i];\n      if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue;\n      var collapsed = range.empty();\n      if (collapsed || cm.options.showCursorWhenSelecting)\n        drawSelectionCursor(cm, range.head, curFragment);\n      if (!collapsed)\n        drawSelectionRange(cm, range, selFragment);\n    }\n    return result;\n  }\n\n  // Draws a cursor for the given range\n  function drawSelectionCursor(cm, head, output) {\n    var pos = cursorCoords(cm, head, \"div\", null, null, !cm.options.singleCursorHeightPerLine);\n\n    var cursor = output.appendChild(elt(\"div\", \"\\u00a0\", \"CodeMirror-cursor\"));\n    cursor.style.left = pos.left + \"px\";\n    cursor.style.top = pos.top + \"px\";\n    cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + \"px\";\n\n    if (pos.other) {\n      // Secondary cursor, shown when on a 'jump' in bi-directional text\n      var otherCursor = output.appendChild(elt(\"div\", \"\\u00a0\", \"CodeMirror-cursor CodeMirror-secondarycursor\"));\n      otherCursor.style.display = \"\";\n      otherCursor.style.left = pos.other.left + \"px\";\n      otherCursor.style.top = pos.other.top + \"px\";\n      otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + \"px\";\n    }\n  }\n\n  // Draws the given range as a highlighted selection\n  function drawSelectionRange(cm, range, output) {\n    var display = cm.display, doc = cm.doc;\n    var fragment = document.createDocumentFragment();\n    var padding = paddingH(cm.display), leftSide = padding.left;\n    var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;\n\n    function add(left, top, width, bottom) {\n      if (top < 0) top = 0;\n      top = Math.round(top);\n      bottom = Math.round(bottom);\n      fragment.appendChild(elt(\"div\", null, \"CodeMirror-selected\", \"position: absolute; left: \" + left +\n                               \"px; top: \" + top + \"px; width: \" + (width == null ? rightSide - left : width) +\n                               \"px; height: \" + (bottom - top) + \"px\"));\n    }\n\n    function drawForLine(line, fromArg, toArg) {\n      var lineObj = getLine(doc, line);\n      var lineLen = lineObj.text.length;\n      var start, end;\n      function coords(ch, bias) {\n        return charCoords(cm, Pos(line, ch), \"div\", lineObj, bias);\n      }\n\n      iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {\n        var leftPos = coords(from, \"left\"), rightPos, left, right;\n        if (from == to) {\n          rightPos = leftPos;\n          left = right = leftPos.left;\n        } else {\n          rightPos = coords(to - 1, \"right\");\n          if (dir == \"rtl\") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }\n          left = leftPos.left;\n          right = rightPos.right;\n        }\n        if (fromArg == null && from == 0) left = leftSide;\n        if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part\n          add(left, leftPos.top, null, leftPos.bottom);\n          left = leftSide;\n          if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);\n        }\n        if (toArg == null && to == lineLen) right = rightSide;\n        if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)\n          start = leftPos;\n        if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)\n          end = rightPos;\n        if (left < leftSide + 1) left = leftSide;\n        add(left, rightPos.top, right - left, rightPos.bottom);\n      });\n      return {start: start, end: end};\n    }\n\n    var sFrom = range.from(), sTo = range.to();\n    if (sFrom.line == sTo.line) {\n      drawForLine(sFrom.line, sFrom.ch, sTo.ch);\n    } else {\n      var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);\n      var singleVLine = visualLine(fromLine) == visualLine(toLine);\n      var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;\n      var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;\n      if (singleVLine) {\n        if (leftEnd.top < rightStart.top - 2) {\n          add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);\n          add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);\n        } else {\n          add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);\n        }\n      }\n      if (leftEnd.bottom < rightStart.top)\n        add(leftSide, leftEnd.bottom, null, rightStart.top);\n    }\n\n    output.appendChild(fragment);\n  }\n\n  // Cursor-blinking\n  function restartBlink(cm) {\n    if (!cm.state.focused) return;\n    var display = cm.display;\n    clearInterval(display.blinker);\n    var on = true;\n    display.cursorDiv.style.visibility = \"\";\n    if (cm.options.cursorBlinkRate > 0)\n      display.blinker = setInterval(function() {\n        display.cursorDiv.style.visibility = (on = !on) ? \"\" : \"hidden\";\n      }, cm.options.cursorBlinkRate);\n    else if (cm.options.cursorBlinkRate < 0)\n      display.cursorDiv.style.visibility = \"hidden\";\n  }\n\n  // HIGHLIGHT WORKER\n\n  function startWorker(cm, time) {\n    if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)\n      cm.state.highlight.set(time, bind(highlightWorker, cm));\n  }\n\n  function highlightWorker(cm) {\n    var doc = cm.doc;\n    if (doc.frontier < doc.first) doc.frontier = doc.first;\n    if (doc.frontier >= cm.display.viewTo) return;\n    var end = +new Date + cm.options.workTime;\n    var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));\n    var changedLines = [];\n\n    doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {\n      if (doc.frontier >= cm.display.viewFrom) { // Visible\n        var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength;\n        var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true);\n        line.styles = highlighted.styles;\n        var oldCls = line.styleClasses, newCls = highlighted.classes;\n        if (newCls) line.styleClasses = newCls;\n        else if (oldCls) line.styleClasses = null;\n        var ischange = !oldStyles || oldStyles.length != line.styles.length ||\n          oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);\n        for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];\n        if (ischange) changedLines.push(doc.frontier);\n        line.stateAfter = tooLong ? state : copyState(doc.mode, state);\n      } else {\n        if (line.text.length <= cm.options.maxHighlightLength)\n          processLine(cm, line.text, state);\n        line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;\n      }\n      ++doc.frontier;\n      if (+new Date > end) {\n        startWorker(cm, cm.options.workDelay);\n        return true;\n      }\n    });\n    if (changedLines.length) runInOp(cm, function() {\n      for (var i = 0; i < changedLines.length; i++)\n        regLineChange(cm, changedLines[i], \"text\");\n    });\n  }\n\n  // Finds the line to start with when starting a parse. Tries to\n  // find a line with a stateAfter, so that it can start with a\n  // valid state. If that fails, it returns the line with the\n  // smallest indentation, which tends to need the least context to\n  // parse correctly.\n  function findStartLine(cm, n, precise) {\n    var minindent, minline, doc = cm.doc;\n    var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);\n    for (var search = n; search > lim; --search) {\n      if (search <= doc.first) return doc.first;\n      var line = getLine(doc, search - 1);\n      if (line.stateAfter && (!precise || search <= doc.frontier)) return search;\n      var indented = countColumn(line.text, null, cm.options.tabSize);\n      if (minline == null || minindent > indented) {\n        minline = search - 1;\n        minindent = indented;\n      }\n    }\n    return minline;\n  }\n\n  function getStateBefore(cm, n, precise) {\n    var doc = cm.doc, display = cm.display;\n    if (!doc.mode.startState) return true;\n    var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter;\n    if (!state) state = startState(doc.mode);\n    else state = copyState(doc.mode, state);\n    doc.iter(pos, n, function(line) {\n      processLine(cm, line.text, state);\n      var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo;\n      line.stateAfter = save ? copyState(doc.mode, state) : null;\n      ++pos;\n    });\n    if (precise) doc.frontier = pos;\n    return state;\n  }\n\n  // POSITION MEASUREMENT\n\n  function paddingTop(display) {return display.lineSpace.offsetTop;}\n  function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;}\n  function paddingH(display) {\n    if (display.cachedPaddingH) return display.cachedPaddingH;\n    var e = removeChildrenAndAdd(display.measure, elt(\"pre\", \"x\"));\n    var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;\n    var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};\n    if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data;\n    return data;\n  }\n\n  function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; }\n  function displayWidth(cm) {\n    return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth;\n  }\n  function displayHeight(cm) {\n    return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight;\n  }\n\n  // Ensure the lineView.wrapping.heights array is populated. This is\n  // an array of bottom offsets for the lines that make up a drawn\n  // line. When lineWrapping is on, there might be more than one\n  // height.\n  function ensureLineHeights(cm, lineView, rect) {\n    var wrapping = cm.options.lineWrapping;\n    var curWidth = wrapping && displayWidth(cm);\n    if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {\n      var heights = lineView.measure.heights = [];\n      if (wrapping) {\n        lineView.measure.width = curWidth;\n        var rects = lineView.text.firstChild.getClientRects();\n        for (var i = 0; i < rects.length - 1; i++) {\n          var cur = rects[i], next = rects[i + 1];\n          if (Math.abs(cur.bottom - next.bottom) > 2)\n            heights.push((cur.bottom + next.top) / 2 - rect.top);\n        }\n      }\n      heights.push(rect.bottom - rect.top);\n    }\n  }\n\n  // Find a line map (mapping character offsets to text nodes) and a\n  // measurement cache for the given line number. (A line view might\n  // contain multiple lines when collapsed ranges are present.)\n  function mapFromLineView(lineView, line, lineN) {\n    if (lineView.line == line)\n      return {map: lineView.measure.map, cache: lineView.measure.cache};\n    for (var i = 0; i < lineView.rest.length; i++)\n      if (lineView.rest[i] == line)\n        return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]};\n    for (var i = 0; i < lineView.rest.length; i++)\n      if (lineNo(lineView.rest[i]) > lineN)\n        return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true};\n  }\n\n  // Render a line into the hidden node display.externalMeasured. Used\n  // when measurement is needed for a line that's not in the viewport.\n  function updateExternalMeasurement(cm, line) {\n    line = visualLine(line);\n    var lineN = lineNo(line);\n    var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);\n    view.lineN = lineN;\n    var built = view.built = buildLineContent(cm, view);\n    view.text = built.pre;\n    removeChildrenAndAdd(cm.display.lineMeasure, built.pre);\n    return view;\n  }\n\n  // Get a {top, bottom, left, right} box (in line-local coordinates)\n  // for a given character.\n  function measureChar(cm, line, ch, bias) {\n    return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias);\n  }\n\n  // Find a line view that corresponds to the given line number.\n  function findViewForLine(cm, lineN) {\n    if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)\n      return cm.display.view[findViewIndex(cm, lineN)];\n    var ext = cm.display.externalMeasured;\n    if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)\n      return ext;\n  }\n\n  // Measurement can be split in two steps, the set-up work that\n  // applies to the whole line, and the measurement of the actual\n  // character. Functions like coordsChar, that need to do a lot of\n  // measurements in a row, can thus ensure that the set-up work is\n  // only done once.\n  function prepareMeasureForLine(cm, line) {\n    var lineN = lineNo(line);\n    var view = findViewForLine(cm, lineN);\n    if (view && !view.text) {\n      view = null;\n    } else if (view && view.changes) {\n      updateLineForChanges(cm, view, lineN, getDimensions(cm));\n      cm.curOp.forceUpdate = true;\n    }\n    if (!view)\n      view = updateExternalMeasurement(cm, line);\n\n    var info = mapFromLineView(view, line, lineN);\n    return {\n      line: line, view: view, rect: null,\n      map: info.map, cache: info.cache, before: info.before,\n      hasHeights: false\n    };\n  }\n\n  // Given a prepared measurement object, measures the position of an\n  // actual character (or fetches it from the cache).\n  function measureCharPrepared(cm, prepared, ch, bias, varHeight) {\n    if (prepared.before) ch = -1;\n    var key = ch + (bias || \"\"), found;\n    if (prepared.cache.hasOwnProperty(key)) {\n      found = prepared.cache[key];\n    } else {\n      if (!prepared.rect)\n        prepared.rect = prepared.view.text.getBoundingClientRect();\n      if (!prepared.hasHeights) {\n        ensureLineHeights(cm, prepared.view, prepared.rect);\n        prepared.hasHeights = true;\n      }\n      found = measureCharInner(cm, prepared, ch, bias);\n      if (!found.bogus) prepared.cache[key] = found;\n    }\n    return {left: found.left, right: found.right,\n            top: varHeight ? found.rtop : found.top,\n            bottom: varHeight ? found.rbottom : found.bottom};\n  }\n\n  var nullRect = {left: 0, right: 0, top: 0, bottom: 0};\n\n  function nodeAndOffsetInLineMap(map, ch, bias) {\n    var node, start, end, collapse;\n    // First, search the line map for the text node corresponding to,\n    // or closest to, the target character.\n    for (var i = 0; i < map.length; i += 3) {\n      var mStart = map[i], mEnd = map[i + 1];\n      if (ch < mStart) {\n        start = 0; end = 1;\n        collapse = \"left\";\n      } else if (ch < mEnd) {\n        start = ch - mStart;\n        end = start + 1;\n      } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {\n        end = mEnd - mStart;\n        start = end - 1;\n        if (ch >= mEnd) collapse = \"right\";\n      }\n      if (start != null) {\n        node = map[i + 2];\n        if (mStart == mEnd && bias == (node.insertLeft ? \"left\" : \"right\"))\n          collapse = bias;\n        if (bias == \"left\" && start == 0)\n          while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {\n            node = map[(i -= 3) + 2];\n            collapse = \"left\";\n          }\n        if (bias == \"right\" && start == mEnd - mStart)\n          while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {\n            node = map[(i += 3) + 2];\n            collapse = \"right\";\n          }\n        break;\n      }\n    }\n    return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd};\n  }\n\n  function getUsefulRect(rects, bias) {\n    var rect = nullRect\n    if (bias == \"left\") for (var i = 0; i < rects.length; i++) {\n      if ((rect = rects[i]).left != rect.right) break\n    } else for (var i = rects.length - 1; i >= 0; i--) {\n      if ((rect = rects[i]).left != rect.right) break\n    }\n    return rect\n  }\n\n  function measureCharInner(cm, prepared, ch, bias) {\n    var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);\n    var node = place.node, start = place.start, end = place.end, collapse = place.collapse;\n\n    var rect;\n    if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.\n      for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned\n        while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start;\n        while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end;\n        if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)\n          rect = node.parentNode.getBoundingClientRect();\n        else\n          rect = getUsefulRect(range(node, start, end).getClientRects(), bias)\n        if (rect.left || rect.right || start == 0) break;\n        end = start;\n        start = start - 1;\n        collapse = \"right\";\n      }\n      if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect);\n    } else { // If it is a widget, simply get the box for the whole widget.\n      if (start > 0) collapse = bias = \"right\";\n      var rects;\n      if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)\n        rect = rects[bias == \"right\" ? rects.length - 1 : 0];\n      else\n        rect = node.getBoundingClientRect();\n    }\n    if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {\n      var rSpan = node.parentNode.getClientRects()[0];\n      if (rSpan)\n        rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom};\n      else\n        rect = nullRect;\n    }\n\n    var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;\n    var mid = (rtop + rbot) / 2;\n    var heights = prepared.view.measure.heights;\n    for (var i = 0; i < heights.length - 1; i++)\n      if (mid < heights[i]) break;\n    var top = i ? heights[i - 1] : 0, bot = heights[i];\n    var result = {left: (collapse == \"right\" ? rect.right : rect.left) - prepared.rect.left,\n                  right: (collapse == \"left\" ? rect.left : rect.right) - prepared.rect.left,\n                  top: top, bottom: bot};\n    if (!rect.left && !rect.right) result.bogus = true;\n    if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }\n\n    return result;\n  }\n\n  // Work around problem with bounding client rects on ranges being\n  // returned incorrectly when zoomed on IE10 and below.\n  function maybeUpdateRectForZooming(measure, rect) {\n    if (!window.screen || screen.logicalXDPI == null ||\n        screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))\n      return rect;\n    var scaleX = screen.logicalXDPI / screen.deviceXDPI;\n    var scaleY = screen.logicalYDPI / screen.deviceYDPI;\n    return {left: rect.left * scaleX, right: rect.right * scaleX,\n            top: rect.top * scaleY, bottom: rect.bottom * scaleY};\n  }\n\n  function clearLineMeasurementCacheFor(lineView) {\n    if (lineView.measure) {\n      lineView.measure.cache = {};\n      lineView.measure.heights = null;\n      if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)\n        lineView.measure.caches[i] = {};\n    }\n  }\n\n  function clearLineMeasurementCache(cm) {\n    cm.display.externalMeasure = null;\n    removeChildren(cm.display.lineMeasure);\n    for (var i = 0; i < cm.display.view.length; i++)\n      clearLineMeasurementCacheFor(cm.display.view[i]);\n  }\n\n  function clearCaches(cm) {\n    clearLineMeasurementCache(cm);\n    cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;\n    if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;\n    cm.display.lineNumChars = null;\n  }\n\n  function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }\n  function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }\n\n  // Converts a {top, bottom, left, right} box from line-local\n  // coordinates into another coordinate system. Context may be one of\n  // \"line\", \"div\" (display.lineDiv), \"local\"/null (editor), \"window\",\n  // or \"page\".\n  function intoCoordSystem(cm, lineObj, rect, context) {\n    if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {\n      var size = widgetHeight(lineObj.widgets[i]);\n      rect.top += size; rect.bottom += size;\n    }\n    if (context == \"line\") return rect;\n    if (!context) context = \"local\";\n    var yOff = heightAtLine(lineObj);\n    if (context == \"local\") yOff += paddingTop(cm.display);\n    else yOff -= cm.display.viewOffset;\n    if (context == \"page\" || context == \"window\") {\n      var lOff = cm.display.lineSpace.getBoundingClientRect();\n      yOff += lOff.top + (context == \"window\" ? 0 : pageScrollY());\n      var xOff = lOff.left + (context == \"window\" ? 0 : pageScrollX());\n      rect.left += xOff; rect.right += xOff;\n    }\n    rect.top += yOff; rect.bottom += yOff;\n    return rect;\n  }\n\n  // Coverts a box from \"div\" coords to another coordinate system.\n  // Context may be \"window\", \"page\", \"div\", or \"local\"/null.\n  function fromCoordSystem(cm, coords, context) {\n    if (context == \"div\") return coords;\n    var left = coords.left, top = coords.top;\n    // First move into \"page\" coordinate system\n    if (context == \"page\") {\n      left -= pageScrollX();\n      top -= pageScrollY();\n    } else if (context == \"local\" || !context) {\n      var localBox = cm.display.sizer.getBoundingClientRect();\n      left += localBox.left;\n      top += localBox.top;\n    }\n\n    var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();\n    return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top};\n  }\n\n  function charCoords(cm, pos, context, lineObj, bias) {\n    if (!lineObj) lineObj = getLine(cm.doc, pos.line);\n    return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context);\n  }\n\n  // Returns a box for a given cursor position, which may have an\n  // 'other' property containing the position of the secondary cursor\n  // on a bidi boundary.\n  function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {\n    lineObj = lineObj || getLine(cm.doc, pos.line);\n    if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);\n    function get(ch, right) {\n      var m = measureCharPrepared(cm, preparedMeasure, ch, right ? \"right\" : \"left\", varHeight);\n      if (right) m.left = m.right; else m.right = m.left;\n      return intoCoordSystem(cm, lineObj, m, context);\n    }\n    function getBidi(ch, partPos) {\n      var part = order[partPos], right = part.level % 2;\n      if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {\n        part = order[--partPos];\n        ch = bidiRight(part) - (part.level % 2 ? 0 : 1);\n        right = true;\n      } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {\n        part = order[++partPos];\n        ch = bidiLeft(part) - part.level % 2;\n        right = false;\n      }\n      if (right && ch == part.to && ch > part.from) return get(ch - 1);\n      return get(ch, right);\n    }\n    var order = getOrder(lineObj), ch = pos.ch;\n    if (!order) return get(ch);\n    var partPos = getBidiPartAt(order, ch);\n    var val = getBidi(ch, partPos);\n    if (bidiOther != null) val.other = getBidi(ch, bidiOther);\n    return val;\n  }\n\n  // Used to cheaply estimate the coordinates for a position. Used for\n  // intermediate scroll updates.\n  function estimateCoords(cm, pos) {\n    var left = 0, pos = clipPos(cm.doc, pos);\n    if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch;\n    var lineObj = getLine(cm.doc, pos.line);\n    var top = heightAtLine(lineObj) + paddingTop(cm.display);\n    return {left: left, right: left, top: top, bottom: top + lineObj.height};\n  }\n\n  // Positions returned by coordsChar contain some extra information.\n  // xRel is the relative x position of the input coordinates compared\n  // to the found position (so xRel > 0 means the coordinates are to\n  // the right of the character position, for example). When outside\n  // is true, that means the coordinates lie outside the line's\n  // vertical range.\n  function PosWithInfo(line, ch, outside, xRel) {\n    var pos = Pos(line, ch);\n    pos.xRel = xRel;\n    if (outside) pos.outside = true;\n    return pos;\n  }\n\n  // Compute the character position closest to the given coordinates.\n  // Input must be lineSpace-local (\"div\" coordinate system).\n  function coordsChar(cm, x, y) {\n    var doc = cm.doc;\n    y += cm.display.viewOffset;\n    if (y < 0) return PosWithInfo(doc.first, 0, true, -1);\n    var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;\n    if (lineN > last)\n      return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);\n    if (x < 0) x = 0;\n\n    var lineObj = getLine(doc, lineN);\n    for (;;) {\n      var found = coordsCharInner(cm, lineObj, lineN, x, y);\n      var merged = collapsedSpanAtEnd(lineObj);\n      var mergedPos = merged && merged.find(0, true);\n      if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))\n        lineN = lineNo(lineObj = mergedPos.to.line);\n      else\n        return found;\n    }\n  }\n\n  function coordsCharInner(cm, lineObj, lineNo, x, y) {\n    var innerOff = y - heightAtLine(lineObj);\n    var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;\n    var preparedMeasure = prepareMeasureForLine(cm, lineObj);\n\n    function getX(ch) {\n      var sp = cursorCoords(cm, Pos(lineNo, ch), \"line\", lineObj, preparedMeasure);\n      wrongLine = true;\n      if (innerOff > sp.bottom) return sp.left - adjust;\n      else if (innerOff < sp.top) return sp.left + adjust;\n      else wrongLine = false;\n      return sp.left;\n    }\n\n    var bidi = getOrder(lineObj), dist = lineObj.text.length;\n    var from = lineLeft(lineObj), to = lineRight(lineObj);\n    var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;\n\n    if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);\n    // Do a binary search between these bounds.\n    for (;;) {\n      if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {\n        var ch = x < fromX || x - fromX <= toX - x ? from : to;\n        var outside = ch == from ? fromOutside : toOutside\n        var xDiff = x - (ch == from ? fromX : toX);\n        // This is a kludge to handle the case where the coordinates\n        // are after a line-wrapped line. We should replace it with a\n        // more general handling of cursor positions around line\n        // breaks. (Issue #4078)\n        if (toOutside && !bidi && !/\\s/.test(lineObj.text.charAt(ch)) && xDiff > 0 &&\n            ch < lineObj.text.length && preparedMeasure.view.measure.heights.length > 1) {\n          var charSize = measureCharPrepared(cm, preparedMeasure, ch, \"right\");\n          if (innerOff <= charSize.bottom && innerOff >= charSize.top && Math.abs(x - charSize.right) < xDiff) {\n            outside = false\n            ch++\n            xDiff = x - charSize.right\n          }\n        }\n        while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;\n        var pos = PosWithInfo(lineNo, ch, outside, xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0);\n        return pos;\n      }\n      var step = Math.ceil(dist / 2), middle = from + step;\n      if (bidi) {\n        middle = from;\n        for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);\n      }\n      var middleX = getX(middle);\n      if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;}\n      else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;}\n    }\n  }\n\n  var measureText;\n  // Compute the default text height.\n  function textHeight(display) {\n    if (display.cachedTextHeight != null) return display.cachedTextHeight;\n    if (measureText == null) {\n      measureText = elt(\"pre\");\n      // Measure a bunch of lines, for browsers that compute\n      // fractional heights.\n      for (var i = 0; i < 49; ++i) {\n        measureText.appendChild(document.createTextNode(\"x\"));\n        measureText.appendChild(elt(\"br\"));\n      }\n      measureText.appendChild(document.createTextNode(\"x\"));\n    }\n    removeChildrenAndAdd(display.measure, measureText);\n    var height = measureText.offsetHeight / 50;\n    if (height > 3) display.cachedTextHeight = height;\n    removeChildren(display.measure);\n    return height || 1;\n  }\n\n  // Compute the default character width.\n  function charWidth(display) {\n    if (display.cachedCharWidth != null) return display.cachedCharWidth;\n    var anchor = elt(\"span\", \"xxxxxxxxxx\");\n    var pre = elt(\"pre\", [anchor]);\n    removeChildrenAndAdd(display.measure, pre);\n    var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;\n    if (width > 2) display.cachedCharWidth = width;\n    return width || 10;\n  }\n\n  // OPERATIONS\n\n  // Operations are used to wrap a series of changes to the editor\n  // state in such a way that each change won't have to update the\n  // cursor and display (which would be awkward, slow, and\n  // error-prone). Instead, display updates are batched and then all\n  // combined and executed at once.\n\n  var operationGroup = null;\n\n  var nextOpId = 0;\n  // Start a new operation.\n  function startOperation(cm) {\n    cm.curOp = {\n      cm: cm,\n      viewChanged: false,      // Flag that indicates that lines might need to be redrawn\n      startHeight: cm.doc.height, // Used to detect need to update scrollbar\n      forceUpdate: false,      // Used to force a redraw\n      updateInput: null,       // Whether to reset the input textarea\n      typing: false,           // Whether this reset should be careful to leave existing text (for compositing)\n      changeObjs: null,        // Accumulated changes, for firing change events\n      cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on\n      cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already\n      selectionChanged: false, // Whether the selection needs to be redrawn\n      updateMaxLine: false,    // Set when the widest line needs to be determined anew\n      scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet\n      scrollToPos: null,       // Used to scroll to a specific position\n      focus: false,\n      id: ++nextOpId           // Unique ID\n    };\n    if (operationGroup) {\n      operationGroup.ops.push(cm.curOp);\n    } else {\n      cm.curOp.ownsGroup = operationGroup = {\n        ops: [cm.curOp],\n        delayedCallbacks: []\n      };\n    }\n  }\n\n  function fireCallbacksForOps(group) {\n    // Calls delayed callbacks and cursorActivity handlers until no\n    // new ones appear\n    var callbacks = group.delayedCallbacks, i = 0;\n    do {\n      for (; i < callbacks.length; i++)\n        callbacks[i].call(null);\n      for (var j = 0; j < group.ops.length; j++) {\n        var op = group.ops[j];\n        if (op.cursorActivityHandlers)\n          while (op.cursorActivityCalled < op.cursorActivityHandlers.length)\n            op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm);\n      }\n    } while (i < callbacks.length);\n  }\n\n  // Finish an operation, updating the display and signalling delayed events\n  function endOperation(cm) {\n    var op = cm.curOp, group = op.ownsGroup;\n    if (!group) return;\n\n    try { fireCallbacksForOps(group); }\n    finally {\n      operationGroup = null;\n      for (var i = 0; i < group.ops.length; i++)\n        group.ops[i].cm.curOp = null;\n      endOperations(group);\n    }\n  }\n\n  // The DOM updates done when an operation finishes are batched so\n  // that the minimum number of relayouts are required.\n  function endOperations(group) {\n    var ops = group.ops;\n    for (var i = 0; i < ops.length; i++) // Read DOM\n      endOperation_R1(ops[i]);\n    for (var i = 0; i < ops.length; i++) // Write DOM (maybe)\n      endOperation_W1(ops[i]);\n    for (var i = 0; i < ops.length; i++) // Read DOM\n      endOperation_R2(ops[i]);\n    for (var i = 0; i < ops.length; i++) // Write DOM (maybe)\n      endOperation_W2(ops[i]);\n    for (var i = 0; i < ops.length; i++) // Read DOM\n      endOperation_finish(ops[i]);\n  }\n\n  function endOperation_R1(op) {\n    var cm = op.cm, display = cm.display;\n    maybeClipScrollbars(cm);\n    if (op.updateMaxLine) findMaxLine(cm);\n\n    op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||\n      op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||\n                         op.scrollToPos.to.line >= display.viewTo) ||\n      display.maxLineChanged && cm.options.lineWrapping;\n    op.update = op.mustUpdate &&\n      new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);\n  }\n\n  function endOperation_W1(op) {\n    op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);\n  }\n\n  function endOperation_R2(op) {\n    var cm = op.cm, display = cm.display;\n    if (op.updatedDisplay) updateHeightsInViewport(cm);\n\n    op.barMeasure = measureForScrollbars(cm);\n\n    // If the max line changed since it was last measured, measure it,\n    // and ensure the document's width matches it.\n    // updateDisplay_W2 will use these properties to do the actual resizing\n    if (display.maxLineChanged && !cm.options.lineWrapping) {\n      op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;\n      cm.display.sizerWidth = op.adjustWidthTo;\n      op.barMeasure.scrollWidth =\n        Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);\n      op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));\n    }\n\n    if (op.updatedDisplay || op.selectionChanged)\n      op.preparedSelection = display.input.prepareSelection(op.focus);\n  }\n\n  function endOperation_W2(op) {\n    var cm = op.cm;\n\n    if (op.adjustWidthTo != null) {\n      cm.display.sizer.style.minWidth = op.adjustWidthTo + \"px\";\n      if (op.maxScrollLeft < cm.doc.scrollLeft)\n        setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true);\n      cm.display.maxLineChanged = false;\n    }\n\n    var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus())\n    if (op.preparedSelection)\n      cm.display.input.showSelection(op.preparedSelection, takeFocus);\n    if (op.updatedDisplay || op.startHeight != cm.doc.height)\n      updateScrollbars(cm, op.barMeasure);\n    if (op.updatedDisplay)\n      setDocumentHeight(cm, op.barMeasure);\n\n    if (op.selectionChanged) restartBlink(cm);\n\n    if (cm.state.focused && op.updateInput)\n      cm.display.input.reset(op.typing);\n    if (takeFocus) ensureFocus(op.cm);\n  }\n\n  function endOperation_finish(op) {\n    var cm = op.cm, display = cm.display, doc = cm.doc;\n\n    if (op.updatedDisplay) postUpdateDisplay(cm, op.update);\n\n    // Abort mouse wheel delta measurement, when scrolling explicitly\n    if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))\n      display.wheelStartX = display.wheelStartY = null;\n\n    // Propagate the scroll position to the actual DOM scroller\n    if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {\n      doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));\n      display.scrollbars.setScrollTop(doc.scrollTop);\n      display.scroller.scrollTop = doc.scrollTop;\n    }\n    if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {\n      doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft));\n      display.scrollbars.setScrollLeft(doc.scrollLeft);\n      display.scroller.scrollLeft = doc.scrollLeft;\n      alignHorizontally(cm);\n    }\n    // If we need to scroll a specific position into view, do so.\n    if (op.scrollToPos) {\n      var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),\n                                     clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);\n      if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords);\n    }\n\n    // Fire events for markers that are hidden/unidden by editing or\n    // undoing\n    var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;\n    if (hidden) for (var i = 0; i < hidden.length; ++i)\n      if (!hidden[i].lines.length) signal(hidden[i], \"hide\");\n    if (unhidden) for (var i = 0; i < unhidden.length; ++i)\n      if (unhidden[i].lines.length) signal(unhidden[i], \"unhide\");\n\n    if (display.wrapper.offsetHeight)\n      doc.scrollTop = cm.display.scroller.scrollTop;\n\n    // Fire change events, and delayed event handlers\n    if (op.changeObjs)\n      signal(cm, \"changes\", cm, op.changeObjs);\n    if (op.update)\n      op.update.finish();\n  }\n\n  // Run the given function in an operation\n  function runInOp(cm, f) {\n    if (cm.curOp) return f();\n    startOperation(cm);\n    try { return f(); }\n    finally { endOperation(cm); }\n  }\n  // Wraps a function in an operation. Returns the wrapped function.\n  function operation(cm, f) {\n    return function() {\n      if (cm.curOp) return f.apply(cm, arguments);\n      startOperation(cm);\n      try { return f.apply(cm, arguments); }\n      finally { endOperation(cm); }\n    };\n  }\n  // Used to add methods to editor and doc instances, wrapping them in\n  // operations.\n  function methodOp(f) {\n    return function() {\n      if (this.curOp) return f.apply(this, arguments);\n      startOperation(this);\n      try { return f.apply(this, arguments); }\n      finally { endOperation(this); }\n    };\n  }\n  function docMethodOp(f) {\n    return function() {\n      var cm = this.cm;\n      if (!cm || cm.curOp) return f.apply(this, arguments);\n      startOperation(cm);\n      try { return f.apply(this, arguments); }\n      finally { endOperation(cm); }\n    };\n  }\n\n  // VIEW TRACKING\n\n  // These objects are used to represent the visible (currently drawn)\n  // part of the document. A LineView may correspond to multiple\n  // logical lines, if those are connected by collapsed ranges.\n  function LineView(doc, line, lineN) {\n    // The starting line\n    this.line = line;\n    // Continuing lines, if any\n    this.rest = visualLineContinued(line);\n    // Number of logical lines in this visual line\n    this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;\n    this.node = this.text = null;\n    this.hidden = lineIsHidden(doc, line);\n  }\n\n  // Create a range of LineView objects for the given lines.\n  function buildViewArray(cm, from, to) {\n    var array = [], nextPos;\n    for (var pos = from; pos < to; pos = nextPos) {\n      var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);\n      nextPos = pos + view.size;\n      array.push(view);\n    }\n    return array;\n  }\n\n  // Updates the display.view data structure for a given change to the\n  // document. From and to are in pre-change coordinates. Lendiff is\n  // the amount of lines added or subtracted by the change. This is\n  // used for changes that span multiple lines, or change the way\n  // lines are divided into visual lines. regLineChange (below)\n  // registers single-line changes.\n  function regChange(cm, from, to, lendiff) {\n    if (from == null) from = cm.doc.first;\n    if (to == null) to = cm.doc.first + cm.doc.size;\n    if (!lendiff) lendiff = 0;\n\n    var display = cm.display;\n    if (lendiff && to < display.viewTo &&\n        (display.updateLineNumbers == null || display.updateLineNumbers > from))\n      display.updateLineNumbers = from;\n\n    cm.curOp.viewChanged = true;\n\n    if (from >= display.viewTo) { // Change after\n      if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)\n        resetView(cm);\n    } else if (to <= display.viewFrom) { // Change before\n      if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {\n        resetView(cm);\n      } else {\n        display.viewFrom += lendiff;\n        display.viewTo += lendiff;\n      }\n    } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap\n      resetView(cm);\n    } else if (from <= display.viewFrom) { // Top overlap\n      var cut = viewCuttingPoint(cm, to, to + lendiff, 1);\n      if (cut) {\n        display.view = display.view.slice(cut.index);\n        display.viewFrom = cut.lineN;\n        display.viewTo += lendiff;\n      } else {\n        resetView(cm);\n      }\n    } else if (to >= display.viewTo) { // Bottom overlap\n      var cut = viewCuttingPoint(cm, from, from, -1);\n      if (cut) {\n        display.view = display.view.slice(0, cut.index);\n        display.viewTo = cut.lineN;\n      } else {\n        resetView(cm);\n      }\n    } else { // Gap in the middle\n      var cutTop = viewCuttingPoint(cm, from, from, -1);\n      var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);\n      if (cutTop && cutBot) {\n        display.view = display.view.slice(0, cutTop.index)\n          .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))\n          .concat(display.view.slice(cutBot.index));\n        display.viewTo += lendiff;\n      } else {\n        resetView(cm);\n      }\n    }\n\n    var ext = display.externalMeasured;\n    if (ext) {\n      if (to < ext.lineN)\n        ext.lineN += lendiff;\n      else if (from < ext.lineN + ext.size)\n        display.externalMeasured = null;\n    }\n  }\n\n  // Register a change to a single line. Type must be one of \"text\",\n  // \"gutter\", \"class\", \"widget\"\n  function regLineChange(cm, line, type) {\n    cm.curOp.viewChanged = true;\n    var display = cm.display, ext = cm.display.externalMeasured;\n    if (ext && line >= ext.lineN && line < ext.lineN + ext.size)\n      display.externalMeasured = null;\n\n    if (line < display.viewFrom || line >= display.viewTo) return;\n    var lineView = display.view[findViewIndex(cm, line)];\n    if (lineView.node == null) return;\n    var arr = lineView.changes || (lineView.changes = []);\n    if (indexOf(arr, type) == -1) arr.push(type);\n  }\n\n  // Clear the view.\n  function resetView(cm) {\n    cm.display.viewFrom = cm.display.viewTo = cm.doc.first;\n    cm.display.view = [];\n    cm.display.viewOffset = 0;\n  }\n\n  // Find the view element corresponding to a given line. Return null\n  // when the line isn't visible.\n  function findViewIndex(cm, n) {\n    if (n >= cm.display.viewTo) return null;\n    n -= cm.display.viewFrom;\n    if (n < 0) return null;\n    var view = cm.display.view;\n    for (var i = 0; i < view.length; i++) {\n      n -= view[i].size;\n      if (n < 0) return i;\n    }\n  }\n\n  function viewCuttingPoint(cm, oldN, newN, dir) {\n    var index = findViewIndex(cm, oldN), diff, view = cm.display.view;\n    if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)\n      return {index: index, lineN: newN};\n    for (var i = 0, n = cm.display.viewFrom; i < index; i++)\n      n += view[i].size;\n    if (n != oldN) {\n      if (dir > 0) {\n        if (index == view.length - 1) return null;\n        diff = (n + view[index].size) - oldN;\n        index++;\n      } else {\n        diff = n - oldN;\n      }\n      oldN += diff; newN += diff;\n    }\n    while (visualLineNo(cm.doc, newN) != newN) {\n      if (index == (dir < 0 ? 0 : view.length - 1)) return null;\n      newN += dir * view[index - (dir < 0 ? 1 : 0)].size;\n      index += dir;\n    }\n    return {index: index, lineN: newN};\n  }\n\n  // Force the view to cover a given range, adding empty view element\n  // or clipping off existing ones as needed.\n  function adjustView(cm, from, to) {\n    var display = cm.display, view = display.view;\n    if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {\n      display.view = buildViewArray(cm, from, to);\n      display.viewFrom = from;\n    } else {\n      if (display.viewFrom > from)\n        display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view);\n      else if (display.viewFrom < from)\n        display.view = display.view.slice(findViewIndex(cm, from));\n      display.viewFrom = from;\n      if (display.viewTo < to)\n        display.view = display.view.concat(buildViewArray(cm, display.viewTo, to));\n      else if (display.viewTo > to)\n        display.view = display.view.slice(0, findViewIndex(cm, to));\n    }\n    display.viewTo = to;\n  }\n\n  // Count the number of lines in the view whose DOM representation is\n  // out of date (or nonexistent).\n  function countDirtyView(cm) {\n    var view = cm.display.view, dirty = 0;\n    for (var i = 0; i < view.length; i++) {\n      var lineView = view[i];\n      if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty;\n    }\n    return dirty;\n  }\n\n  // EVENT HANDLERS\n\n  // Attach the necessary event handlers when initializing the editor\n  function registerEventHandlers(cm) {\n    var d = cm.display;\n    on(d.scroller, \"mousedown\", operation(cm, onMouseDown));\n    // Older IE's will not fire a second mousedown for a double click\n    if (ie && ie_version < 11)\n      on(d.scroller, \"dblclick\", operation(cm, function(e) {\n        if (signalDOMEvent(cm, e)) return;\n        var pos = posFromMouse(cm, e);\n        if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;\n        e_preventDefault(e);\n        var word = cm.findWordAt(pos);\n        extendSelection(cm.doc, word.anchor, word.head);\n      }));\n    else\n      on(d.scroller, \"dblclick\", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });\n    // Some browsers fire contextmenu *after* opening the menu, at\n    // which point we can't mess with it anymore. Context menu is\n    // handled in onMouseDown for these browsers.\n    if (!captureRightClick) on(d.scroller, \"contextmenu\", function(e) {onContextMenu(cm, e);});\n\n    // Used to suppress mouse event handling when a touch happens\n    var touchFinished, prevTouch = {end: 0};\n    function finishTouch() {\n      if (d.activeTouch) {\n        touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000);\n        prevTouch = d.activeTouch;\n        prevTouch.end = +new Date;\n      }\n    };\n    function isMouseLikeTouchEvent(e) {\n      if (e.touches.length != 1) return false;\n      var touch = e.touches[0];\n      return touch.radiusX <= 1 && touch.radiusY <= 1;\n    }\n    function farAway(touch, other) {\n      if (other.left == null) return true;\n      var dx = other.left - touch.left, dy = other.top - touch.top;\n      return dx * dx + dy * dy > 20 * 20;\n    }\n    on(d.scroller, \"touchstart\", function(e) {\n      if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) {\n        clearTimeout(touchFinished);\n        var now = +new Date;\n        d.activeTouch = {start: now, moved: false,\n                         prev: now - prevTouch.end <= 300 ? prevTouch : null};\n        if (e.touches.length == 1) {\n          d.activeTouch.left = e.touches[0].pageX;\n          d.activeTouch.top = e.touches[0].pageY;\n        }\n      }\n    });\n    on(d.scroller, \"touchmove\", function() {\n      if (d.activeTouch) d.activeTouch.moved = true;\n    });\n    on(d.scroller, \"touchend\", function(e) {\n      var touch = d.activeTouch;\n      if (touch && !eventInWidget(d, e) && touch.left != null &&\n          !touch.moved && new Date - touch.start < 300) {\n        var pos = cm.coordsChar(d.activeTouch, \"page\"), range;\n        if (!touch.prev || farAway(touch, touch.prev)) // Single tap\n          range = new Range(pos, pos);\n        else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap\n          range = cm.findWordAt(pos);\n        else // Triple tap\n          range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0)));\n        cm.setSelection(range.anchor, range.head);\n        cm.focus();\n        e_preventDefault(e);\n      }\n      finishTouch();\n    });\n    on(d.scroller, \"touchcancel\", finishTouch);\n\n    // Sync scrolling between fake scrollbars and real scrollable\n    // area, ensure viewport is updated when scrolling.\n    on(d.scroller, \"scroll\", function() {\n      if (d.scroller.clientHeight) {\n        setScrollTop(cm, d.scroller.scrollTop);\n        setScrollLeft(cm, d.scroller.scrollLeft, true);\n        signal(cm, \"scroll\", cm);\n      }\n    });\n\n    // Listen to wheel events in order to try and update the viewport on time.\n    on(d.scroller, \"mousewheel\", function(e){onScrollWheel(cm, e);});\n    on(d.scroller, \"DOMMouseScroll\", function(e){onScrollWheel(cm, e);});\n\n    // Prevent wrapper from ever scrolling\n    on(d.wrapper, \"scroll\", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });\n\n    d.dragFunctions = {\n      enter: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);},\n      over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},\n      start: function(e){onDragStart(cm, e);},\n      drop: operation(cm, onDrop),\n      leave: function(e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}\n    };\n\n    var inp = d.input.getField();\n    on(inp, \"keyup\", function(e) { onKeyUp.call(cm, e); });\n    on(inp, \"keydown\", operation(cm, onKeyDown));\n    on(inp, \"keypress\", operation(cm, onKeyPress));\n    on(inp, \"focus\", function (e) { onFocus(cm, e); });\n    on(inp, \"blur\", function (e) { onBlur(cm, e); });\n  }\n\n  function dragDropChanged(cm, value, old) {\n    var wasOn = old && old != CodeMirror.Init;\n    if (!value != !wasOn) {\n      var funcs = cm.display.dragFunctions;\n      var toggle = value ? on : off;\n      toggle(cm.display.scroller, \"dragstart\", funcs.start);\n      toggle(cm.display.scroller, \"dragenter\", funcs.enter);\n      toggle(cm.display.scroller, \"dragover\", funcs.over);\n      toggle(cm.display.scroller, \"dragleave\", funcs.leave);\n      toggle(cm.display.scroller, \"drop\", funcs.drop);\n    }\n  }\n\n  // Called when the window resizes\n  function onResize(cm) {\n    var d = cm.display;\n    if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)\n      return;\n    // Might be a text scaling operation, clear size caches.\n    d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;\n    d.scrollbarsClipped = false;\n    cm.setSize();\n  }\n\n  // MOUSE EVENTS\n\n  // Return true when the given mouse event happened in a widget\n  function eventInWidget(display, e) {\n    for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {\n      if (!n || (n.nodeType == 1 && n.getAttribute(\"cm-ignore-events\") == \"true\") ||\n          (n.parentNode == display.sizer && n != display.mover))\n        return true;\n    }\n  }\n\n  // Given a mouse event, find the corresponding position. If liberal\n  // is false, it checks whether a gutter or scrollbar was clicked,\n  // and returns null if it was. forRect is used by rectangular\n  // selections, and tries to estimate a character position even for\n  // coordinates beyond the right of the text.\n  function posFromMouse(cm, e, liberal, forRect) {\n    var display = cm.display;\n    if (!liberal && e_target(e).getAttribute(\"cm-not-content\") == \"true\") return null;\n\n    var x, y, space = display.lineSpace.getBoundingClientRect();\n    // Fails unpredictably on IE[67] when mouse is dragged around quickly.\n    try { x = e.clientX - space.left; y = e.clientY - space.top; }\n    catch (e) { return null; }\n    var coords = coordsChar(cm, x, y), line;\n    if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {\n      var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;\n      coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));\n    }\n    return coords;\n  }\n\n  // A mouse down can be a single click, double click, triple click,\n  // start of selection drag, start of text drag, new cursor\n  // (ctrl-click), rectangle drag (alt-drag), or xwin\n  // middle-click-paste. Or it might be a click on something we should\n  // not interfere with, such as a scrollbar or widget.\n  function onMouseDown(e) {\n    var cm = this, display = cm.display;\n    if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) return;\n    display.shift = e.shiftKey;\n\n    if (eventInWidget(display, e)) {\n      if (!webkit) {\n        // Briefly turn off draggability, to allow widgets to do\n        // normal dragging things.\n        display.scroller.draggable = false;\n        setTimeout(function(){display.scroller.draggable = true;}, 100);\n      }\n      return;\n    }\n    if (clickInGutter(cm, e)) return;\n    var start = posFromMouse(cm, e);\n    window.focus();\n\n    switch (e_button(e)) {\n    case 1:\n      // #3261: make sure, that we're not starting a second selection\n      if (cm.state.selectingText)\n        cm.state.selectingText(e);\n      else if (start)\n        leftButtonDown(cm, e, start);\n      else if (e_target(e) == display.scroller)\n        e_preventDefault(e);\n      break;\n    case 2:\n      if (webkit) cm.state.lastMiddleDown = +new Date;\n      if (start) extendSelection(cm.doc, start);\n      setTimeout(function() {display.input.focus();}, 20);\n      e_preventDefault(e);\n      break;\n    case 3:\n      if (captureRightClick) onContextMenu(cm, e);\n      else delayBlurEvent(cm);\n      break;\n    }\n  }\n\n  var lastClick, lastDoubleClick;\n  function leftButtonDown(cm, e, start) {\n    if (ie) setTimeout(bind(ensureFocus, cm), 0);\n    else cm.curOp.focus = activeElt();\n\n    var now = +new Date, type;\n    if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) {\n      type = \"triple\";\n    } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) {\n      type = \"double\";\n      lastDoubleClick = {time: now, pos: start};\n    } else {\n      type = \"single\";\n      lastClick = {time: now, pos: start};\n    }\n\n    var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;\n    if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&\n        type == \"single\" && (contained = sel.contains(start)) > -1 &&\n        (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) &&\n        (cmp(contained.to(), start) > 0 || start.xRel < 0))\n      leftButtonStartDrag(cm, e, start, modifier);\n    else\n      leftButtonSelect(cm, e, start, type, modifier);\n  }\n\n  // Start a text drag. When it ends, see if any dragging actually\n  // happen, and treat as a click if it didn't.\n  function leftButtonStartDrag(cm, e, start, modifier) {\n    var display = cm.display, startTime = +new Date;\n    var dragEnd = operation(cm, function(e2) {\n      if (webkit) display.scroller.draggable = false;\n      cm.state.draggingText = false;\n      off(document, \"mouseup\", dragEnd);\n      off(display.scroller, \"drop\", dragEnd);\n      if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {\n        e_preventDefault(e2);\n        if (!modifier && +new Date - 200 < startTime)\n          extendSelection(cm.doc, start);\n        // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)\n        if (webkit || ie && ie_version == 9)\n          setTimeout(function() {document.body.focus(); display.input.focus();}, 20);\n        else\n          display.input.focus();\n      }\n    });\n    // Let the drag handler handle this.\n    if (webkit) display.scroller.draggable = true;\n    cm.state.draggingText = dragEnd;\n    dragEnd.copy = mac ? e.altKey : e.ctrlKey\n    // IE's approach to draggable\n    if (display.scroller.dragDrop) display.scroller.dragDrop();\n    on(document, \"mouseup\", dragEnd);\n    on(display.scroller, \"drop\", dragEnd);\n  }\n\n  // Normal selection, as opposed to text dragging.\n  function leftButtonSelect(cm, e, start, type, addNew) {\n    var display = cm.display, doc = cm.doc;\n    e_preventDefault(e);\n\n    var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;\n    if (addNew && !e.shiftKey) {\n      ourIndex = doc.sel.contains(start);\n      if (ourIndex > -1)\n        ourRange = ranges[ourIndex];\n      else\n        ourRange = new Range(start, start);\n    } else {\n      ourRange = doc.sel.primary();\n      ourIndex = doc.sel.primIndex;\n    }\n\n    if (chromeOS ? e.shiftKey && e.metaKey : e.altKey) {\n      type = \"rect\";\n      if (!addNew) ourRange = new Range(start, start);\n      start = posFromMouse(cm, e, true, true);\n      ourIndex = -1;\n    } else if (type == \"double\") {\n      var word = cm.findWordAt(start);\n      if (cm.display.shift || doc.extend)\n        ourRange = extendRange(doc, ourRange, word.anchor, word.head);\n      else\n        ourRange = word;\n    } else if (type == \"triple\") {\n      var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0)));\n      if (cm.display.shift || doc.extend)\n        ourRange = extendRange(doc, ourRange, line.anchor, line.head);\n      else\n        ourRange = line;\n    } else {\n      ourRange = extendRange(doc, ourRange, start);\n    }\n\n    if (!addNew) {\n      ourIndex = 0;\n      setSelection(doc, new Selection([ourRange], 0), sel_mouse);\n      startSel = doc.sel;\n    } else if (ourIndex == -1) {\n      ourIndex = ranges.length;\n      setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),\n                   {scroll: false, origin: \"*mouse\"});\n    } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == \"single\" && !e.shiftKey) {\n      setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),\n                   {scroll: false, origin: \"*mouse\"});\n      startSel = doc.sel;\n    } else {\n      replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);\n    }\n\n    var lastPos = start;\n    function extendTo(pos) {\n      if (cmp(lastPos, pos) == 0) return;\n      lastPos = pos;\n\n      if (type == \"rect\") {\n        var ranges = [], tabSize = cm.options.tabSize;\n        var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);\n        var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);\n        var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);\n        for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));\n             line <= end; line++) {\n          var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);\n          if (left == right)\n            ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos)));\n          else if (text.length > leftPos)\n            ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize))));\n        }\n        if (!ranges.length) ranges.push(new Range(start, start));\n        setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),\n                     {origin: \"*mouse\", scroll: false});\n        cm.scrollIntoView(pos);\n      } else {\n        var oldRange = ourRange;\n        var anchor = oldRange.anchor, head = pos;\n        if (type != \"single\") {\n          if (type == \"double\")\n            var range = cm.findWordAt(pos);\n          else\n            var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0)));\n          if (cmp(range.anchor, anchor) > 0) {\n            head = range.head;\n            anchor = minPos(oldRange.from(), range.anchor);\n          } else {\n            head = range.anchor;\n            anchor = maxPos(oldRange.to(), range.head);\n          }\n        }\n        var ranges = startSel.ranges.slice(0);\n        ranges[ourIndex] = new Range(clipPos(doc, anchor), head);\n        setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse);\n      }\n    }\n\n    var editorSize = display.wrapper.getBoundingClientRect();\n    // Used to ensure timeout re-tries don't fire when another extend\n    // happened in the meantime (clearTimeout isn't reliable -- at\n    // least on Chrome, the timeouts still happen even when cleared,\n    // if the clear happens after their scheduled firing time).\n    var counter = 0;\n\n    function extend(e) {\n      var curCount = ++counter;\n      var cur = posFromMouse(cm, e, true, type == \"rect\");\n      if (!cur) return;\n      if (cmp(cur, lastPos) != 0) {\n        cm.curOp.focus = activeElt();\n        extendTo(cur);\n        var visible = visibleLines(display, doc);\n        if (cur.line >= visible.to || cur.line < visible.from)\n          setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);\n      } else {\n        var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;\n        if (outside) setTimeout(operation(cm, function() {\n          if (counter != curCount) return;\n          display.scroller.scrollTop += outside;\n          extend(e);\n        }), 50);\n      }\n    }\n\n    function done(e) {\n      cm.state.selectingText = false;\n      counter = Infinity;\n      e_preventDefault(e);\n      display.input.focus();\n      off(document, \"mousemove\", move);\n      off(document, \"mouseup\", up);\n      doc.history.lastSelOrigin = null;\n    }\n\n    var move = operation(cm, function(e) {\n      if (!e_button(e)) done(e);\n      else extend(e);\n    });\n    var up = operation(cm, done);\n    cm.state.selectingText = up;\n    on(document, \"mousemove\", move);\n    on(document, \"mouseup\", up);\n  }\n\n  // Determines whether an event happened in the gutter, and fires the\n  // handlers for the corresponding event.\n  function gutterEvent(cm, e, type, prevent) {\n    try { var mX = e.clientX, mY = e.clientY; }\n    catch(e) { return false; }\n    if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;\n    if (prevent) e_preventDefault(e);\n\n    var display = cm.display;\n    var lineBox = display.lineDiv.getBoundingClientRect();\n\n    if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);\n    mY -= lineBox.top - display.viewOffset;\n\n    for (var i = 0; i < cm.options.gutters.length; ++i) {\n      var g = display.gutters.childNodes[i];\n      if (g && g.getBoundingClientRect().right >= mX) {\n        var line = lineAtHeight(cm.doc, mY);\n        var gutter = cm.options.gutters[i];\n        signal(cm, type, cm, line, gutter, e);\n        return e_defaultPrevented(e);\n      }\n    }\n  }\n\n  function clickInGutter(cm, e) {\n    return gutterEvent(cm, e, \"gutterClick\", true);\n  }\n\n  // Kludge to work around strange IE behavior where it'll sometimes\n  // re-fire a series of drag-related events right after the drop (#1551)\n  var lastDrop = 0;\n\n  function onDrop(e) {\n    var cm = this;\n    clearDragCursor(cm);\n    if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))\n      return;\n    e_preventDefault(e);\n    if (ie) lastDrop = +new Date;\n    var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;\n    if (!pos || cm.isReadOnly()) return;\n    // Might be a file drop, in which case we simply extract the text\n    // and insert it.\n    if (files && files.length && window.FileReader && window.File) {\n      var n = files.length, text = Array(n), read = 0;\n      var loadFile = function(file, i) {\n        if (cm.options.allowDropFileTypes &&\n            indexOf(cm.options.allowDropFileTypes, file.type) == -1)\n          return;\n\n        var reader = new FileReader;\n        reader.onload = operation(cm, function() {\n          var content = reader.result;\n          if (/[\\x00-\\x08\\x0e-\\x1f]{2}/.test(content)) content = \"\";\n          text[i] = content;\n          if (++read == n) {\n            pos = clipPos(cm.doc, pos);\n            var change = {from: pos, to: pos,\n                          text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),\n                          origin: \"paste\"};\n            makeChange(cm.doc, change);\n            setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));\n          }\n        });\n        reader.readAsText(file);\n      };\n      for (var i = 0; i < n; ++i) loadFile(files[i], i);\n    } else { // Normal drop\n      // Don't do a replace if the drop happened inside of the selected text.\n      if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {\n        cm.state.draggingText(e);\n        // Ensure the editor is re-focused\n        setTimeout(function() {cm.display.input.focus();}, 20);\n        return;\n      }\n      try {\n        var text = e.dataTransfer.getData(\"Text\");\n        if (text) {\n          if (cm.state.draggingText && !cm.state.draggingText.copy)\n            var selected = cm.listSelections();\n          setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));\n          if (selected) for (var i = 0; i < selected.length; ++i)\n            replaceRange(cm.doc, \"\", selected[i].anchor, selected[i].head, \"drag\");\n          cm.replaceSelection(text, \"around\", \"paste\");\n          cm.display.input.focus();\n        }\n      }\n      catch(e){}\n    }\n  }\n\n  function onDragStart(cm, e) {\n    if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }\n    if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;\n\n    e.dataTransfer.setData(\"Text\", cm.getSelection());\n    e.dataTransfer.effectAllowed = \"copyMove\"\n\n    // Use dummy image instead of default browsers image.\n    // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.\n    if (e.dataTransfer.setDragImage && !safari) {\n      var img = elt(\"img\", null, null, \"position: fixed; left: 0; top: 0;\");\n      img.src = \"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\";\n      if (presto) {\n        img.width = img.height = 1;\n        cm.display.wrapper.appendChild(img);\n        // Force a relayout, or Opera won't use our image for some obscure reason\n        img._top = img.offsetTop;\n      }\n      e.dataTransfer.setDragImage(img, 0, 0);\n      if (presto) img.parentNode.removeChild(img);\n    }\n  }\n\n  function onDragOver(cm, e) {\n    var pos = posFromMouse(cm, e);\n    if (!pos) return;\n    var frag = document.createDocumentFragment();\n    drawSelectionCursor(cm, pos, frag);\n    if (!cm.display.dragCursor) {\n      cm.display.dragCursor = elt(\"div\", null, \"CodeMirror-cursors CodeMirror-dragcursors\");\n      cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);\n    }\n    removeChildrenAndAdd(cm.display.dragCursor, frag);\n  }\n\n  function clearDragCursor(cm) {\n    if (cm.display.dragCursor) {\n      cm.display.lineSpace.removeChild(cm.display.dragCursor);\n      cm.display.dragCursor = null;\n    }\n  }\n\n  // SCROLL EVENTS\n\n  // Sync the scrollable area and scrollbars, ensure the viewport\n  // covers the visible area.\n  function setScrollTop(cm, val) {\n    if (Math.abs(cm.doc.scrollTop - val) < 2) return;\n    cm.doc.scrollTop = val;\n    if (!gecko) updateDisplaySimple(cm, {top: val});\n    if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;\n    cm.display.scrollbars.setScrollTop(val);\n    if (gecko) updateDisplaySimple(cm);\n    startWorker(cm, 100);\n  }\n  // Sync scroller and scrollbar, ensure the gutter elements are\n  // aligned.\n  function setScrollLeft(cm, val, isScroller) {\n    if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;\n    val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);\n    cm.doc.scrollLeft = val;\n    alignHorizontally(cm);\n    if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;\n    cm.display.scrollbars.setScrollLeft(val);\n  }\n\n  // Since the delta values reported on mouse wheel events are\n  // unstandardized between browsers and even browser versions, and\n  // generally horribly unpredictable, this code starts by measuring\n  // the scroll effect that the first few mouse wheel events have,\n  // and, from that, detects the way it can convert deltas to pixel\n  // offsets afterwards.\n  //\n  // The reason we want to know the amount a wheel event will scroll\n  // is that it gives us a chance to update the display before the\n  // actual scrolling happens, reducing flickering.\n\n  var wheelSamples = 0, wheelPixelsPerUnit = null;\n  // Fill in a browser-detected starting value on browsers where we\n  // know one. These don't have to be accurate -- the result of them\n  // being wrong would just be a slight flicker on the first wheel\n  // scroll (if it is large enough).\n  if (ie) wheelPixelsPerUnit = -.53;\n  else if (gecko) wheelPixelsPerUnit = 15;\n  else if (chrome) wheelPixelsPerUnit = -.7;\n  else if (safari) wheelPixelsPerUnit = -1/3;\n\n  var wheelEventDelta = function(e) {\n    var dx = e.wheelDeltaX, dy = e.wheelDeltaY;\n    if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;\n    if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;\n    else if (dy == null) dy = e.wheelDelta;\n    return {x: dx, y: dy};\n  };\n  CodeMirror.wheelEventPixels = function(e) {\n    var delta = wheelEventDelta(e);\n    delta.x *= wheelPixelsPerUnit;\n    delta.y *= wheelPixelsPerUnit;\n    return delta;\n  };\n\n  function onScrollWheel(cm, e) {\n    var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;\n\n    var display = cm.display, scroll = display.scroller;\n    // Quit if there's nothing to scroll here\n    var canScrollX = scroll.scrollWidth > scroll.clientWidth;\n    var canScrollY = scroll.scrollHeight > scroll.clientHeight;\n    if (!(dx && canScrollX || dy && canScrollY)) return;\n\n    // Webkit browsers on OS X abort momentum scrolls when the target\n    // of the scroll event is removed from the scrollable element.\n    // This hack (see related code in patchDisplay) makes sure the\n    // element is kept around.\n    if (dy && mac && webkit) {\n      outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {\n        for (var i = 0; i < view.length; i++) {\n          if (view[i].node == cur) {\n            cm.display.currentWheelTarget = cur;\n            break outer;\n          }\n        }\n      }\n    }\n\n    // On some browsers, horizontal scrolling will cause redraws to\n    // happen before the gutter has been realigned, causing it to\n    // wriggle around in a most unseemly way. When we have an\n    // estimated pixels/delta value, we just handle horizontal\n    // scrolling entirely here. It'll be slightly off from native, but\n    // better than glitching out.\n    if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {\n      if (dy && canScrollY)\n        setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));\n      setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));\n      // Only prevent default scrolling if vertical scrolling is\n      // actually possible. Otherwise, it causes vertical scroll\n      // jitter on OSX trackpads when deltaX is small and deltaY\n      // is large (issue #3579)\n      if (!dy || (dy && canScrollY))\n        e_preventDefault(e);\n      display.wheelStartX = null; // Abort measurement, if in progress\n      return;\n    }\n\n    // 'Project' the visible viewport to cover the area that is being\n    // scrolled into view (if we know enough to estimate it).\n    if (dy && wheelPixelsPerUnit != null) {\n      var pixels = dy * wheelPixelsPerUnit;\n      var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;\n      if (pixels < 0) top = Math.max(0, top + pixels - 50);\n      else bot = Math.min(cm.doc.height, bot + pixels + 50);\n      updateDisplaySimple(cm, {top: top, bottom: bot});\n    }\n\n    if (wheelSamples < 20) {\n      if (display.wheelStartX == null) {\n        display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;\n        display.wheelDX = dx; display.wheelDY = dy;\n        setTimeout(function() {\n          if (display.wheelStartX == null) return;\n          var movedX = scroll.scrollLeft - display.wheelStartX;\n          var movedY = scroll.scrollTop - display.wheelStartY;\n          var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||\n            (movedX && display.wheelDX && movedX / display.wheelDX);\n          display.wheelStartX = display.wheelStartY = null;\n          if (!sample) return;\n          wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);\n          ++wheelSamples;\n        }, 200);\n      } else {\n        display.wheelDX += dx; display.wheelDY += dy;\n      }\n    }\n  }\n\n  // KEY EVENTS\n\n  // Run a handler that was bound to a key.\n  function doHandleBinding(cm, bound, dropShift) {\n    if (typeof bound == \"string\") {\n      bound = commands[bound];\n      if (!bound) return false;\n    }\n    // Ensure previous input has been read, so that the handler sees a\n    // consistent view of the document\n    cm.display.input.ensurePolled();\n    var prevShift = cm.display.shift, done = false;\n    try {\n      if (cm.isReadOnly()) cm.state.suppressEdits = true;\n      if (dropShift) cm.display.shift = false;\n      done = bound(cm) != Pass;\n    } finally {\n      cm.display.shift = prevShift;\n      cm.state.suppressEdits = false;\n    }\n    return done;\n  }\n\n  function lookupKeyForEditor(cm, name, handle) {\n    for (var i = 0; i < cm.state.keyMaps.length; i++) {\n      var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);\n      if (result) return result;\n    }\n    return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))\n      || lookupKey(name, cm.options.keyMap, handle, cm);\n  }\n\n  var stopSeq = new Delayed;\n  function dispatchKey(cm, name, e, handle) {\n    var seq = cm.state.keySeq;\n    if (seq) {\n      if (isModifierKey(name)) return \"handled\";\n      stopSeq.set(50, function() {\n        if (cm.state.keySeq == seq) {\n          cm.state.keySeq = null;\n          cm.display.input.reset();\n        }\n      });\n      name = seq + \" \" + name;\n    }\n    var result = lookupKeyForEditor(cm, name, handle);\n\n    if (result == \"multi\")\n      cm.state.keySeq = name;\n    if (result == \"handled\")\n      signalLater(cm, \"keyHandled\", cm, name, e);\n\n    if (result == \"handled\" || result == \"multi\") {\n      e_preventDefault(e);\n      restartBlink(cm);\n    }\n\n    if (seq && !result && /\\'$/.test(name)) {\n      e_preventDefault(e);\n      return true;\n    }\n    return !!result;\n  }\n\n  // Handle a key from the keydown event.\n  function handleKeyBinding(cm, e) {\n    var name = keyName(e, true);\n    if (!name) return false;\n\n    if (e.shiftKey && !cm.state.keySeq) {\n      // First try to resolve full name (including 'Shift-'). Failing\n      // that, see if there is a cursor-motion command (starting with\n      // 'go') bound to the keyname without 'Shift-'.\n      return dispatchKey(cm, \"Shift-\" + name, e, function(b) {return doHandleBinding(cm, b, true);})\n          || dispatchKey(cm, name, e, function(b) {\n               if (typeof b == \"string\" ? /^go[A-Z]/.test(b) : b.motion)\n                 return doHandleBinding(cm, b);\n             });\n    } else {\n      return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); });\n    }\n  }\n\n  // Handle a key from the keypress event\n  function handleCharBinding(cm, e, ch) {\n    return dispatchKey(cm, \"'\" + ch + \"'\", e,\n                       function(b) { return doHandleBinding(cm, b, true); });\n  }\n\n  var lastStoppedKey = null;\n  function onKeyDown(e) {\n    var cm = this;\n    cm.curOp.focus = activeElt();\n    if (signalDOMEvent(cm, e)) return;\n    // IE does strange things with escape.\n    if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false;\n    var code = e.keyCode;\n    cm.display.shift = code == 16 || e.shiftKey;\n    var handled = handleKeyBinding(cm, e);\n    if (presto) {\n      lastStoppedKey = handled ? code : null;\n      // Opera has no cut event... we try to at least catch the key combo\n      if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))\n        cm.replaceSelection(\"\", null, \"cut\");\n    }\n\n    // Turn mouse into crosshair when Alt is held on Mac.\n    if (code == 18 && !/\\bCodeMirror-crosshair\\b/.test(cm.display.lineDiv.className))\n      showCrossHair(cm);\n  }\n\n  function showCrossHair(cm) {\n    var lineDiv = cm.display.lineDiv;\n    addClass(lineDiv, \"CodeMirror-crosshair\");\n\n    function up(e) {\n      if (e.keyCode == 18 || !e.altKey) {\n        rmClass(lineDiv, \"CodeMirror-crosshair\");\n        off(document, \"keyup\", up);\n        off(document, \"mouseover\", up);\n      }\n    }\n    on(document, \"keyup\", up);\n    on(document, \"mouseover\", up);\n  }\n\n  function onKeyUp(e) {\n    if (e.keyCode == 16) this.doc.sel.shift = false;\n    signalDOMEvent(this, e);\n  }\n\n  function onKeyPress(e) {\n    var cm = this;\n    if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return;\n    var keyCode = e.keyCode, charCode = e.charCode;\n    if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}\n    if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return;\n    var ch = String.fromCharCode(charCode == null ? keyCode : charCode);\n    if (handleCharBinding(cm, e, ch)) return;\n    cm.display.input.onKeyPress(e);\n  }\n\n  // FOCUS/BLUR EVENTS\n\n  function delayBlurEvent(cm) {\n    cm.state.delayingBlurEvent = true;\n    setTimeout(function() {\n      if (cm.state.delayingBlurEvent) {\n        cm.state.delayingBlurEvent = false;\n        onBlur(cm);\n      }\n    }, 100);\n  }\n\n  function onFocus(cm, e) {\n    if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false;\n\n    if (cm.options.readOnly == \"nocursor\") return;\n    if (!cm.state.focused) {\n      signal(cm, \"focus\", cm, e);\n      cm.state.focused = true;\n      addClass(cm.display.wrapper, \"CodeMirror-focused\");\n      // This test prevents this from firing when a context\n      // menu is closed (since the input reset would kill the\n      // select-all detection hack)\n      if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {\n        cm.display.input.reset();\n        if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730\n      }\n      cm.display.input.receivedFocus();\n    }\n    restartBlink(cm);\n  }\n  function onBlur(cm, e) {\n    if (cm.state.delayingBlurEvent) return;\n\n    if (cm.state.focused) {\n      signal(cm, \"blur\", cm, e);\n      cm.state.focused = false;\n      rmClass(cm.display.wrapper, \"CodeMirror-focused\");\n    }\n    clearInterval(cm.display.blinker);\n    setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150);\n  }\n\n  // CONTEXT MENU HANDLING\n\n  // To make the context menu work, we need to briefly unhide the\n  // textarea (making it as unobtrusive as possible) to let the\n  // right-click take effect on it.\n  function onContextMenu(cm, e) {\n    if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;\n    if (signalDOMEvent(cm, e, \"contextmenu\")) return;\n    cm.display.input.onContextMenu(e);\n  }\n\n  function contextMenuInGutter(cm, e) {\n    if (!hasHandler(cm, \"gutterContextMenu\")) return false;\n    return gutterEvent(cm, e, \"gutterContextMenu\", false);\n  }\n\n  // UPDATING\n\n  // Compute the position of the end of a change (its 'to' property\n  // refers to the pre-change end).\n  var changeEnd = CodeMirror.changeEnd = function(change) {\n    if (!change.text) return change.to;\n    return Pos(change.from.line + change.text.length - 1,\n               lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));\n  };\n\n  // Adjust a position to refer to the post-change position of the\n  // same text, or the end of the change if the change covers it.\n  function adjustForChange(pos, change) {\n    if (cmp(pos, change.from) < 0) return pos;\n    if (cmp(pos, change.to) <= 0) return changeEnd(change);\n\n    var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;\n    if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch;\n    return Pos(line, ch);\n  }\n\n  function computeSelAfterChange(doc, change) {\n    var out = [];\n    for (var i = 0; i < doc.sel.ranges.length; i++) {\n      var range = doc.sel.ranges[i];\n      out.push(new Range(adjustForChange(range.anchor, change),\n                         adjustForChange(range.head, change)));\n    }\n    return normalizeSelection(out, doc.sel.primIndex);\n  }\n\n  function offsetPos(pos, old, nw) {\n    if (pos.line == old.line)\n      return Pos(nw.line, pos.ch - old.ch + nw.ch);\n    else\n      return Pos(nw.line + (pos.line - old.line), pos.ch);\n  }\n\n  // Used by replaceSelections to allow moving the selection to the\n  // start or around the replaced test. Hint may be \"start\" or \"around\".\n  function computeReplacedSel(doc, changes, hint) {\n    var out = [];\n    var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;\n    for (var i = 0; i < changes.length; i++) {\n      var change = changes[i];\n      var from = offsetPos(change.from, oldPrev, newPrev);\n      var to = offsetPos(changeEnd(change), oldPrev, newPrev);\n      oldPrev = change.to;\n      newPrev = to;\n      if (hint == \"around\") {\n        var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;\n        out[i] = new Range(inv ? to : from, inv ? from : to);\n      } else {\n        out[i] = new Range(from, from);\n      }\n    }\n    return new Selection(out, doc.sel.primIndex);\n  }\n\n  // Allow \"beforeChange\" event handlers to influence a change\n  function filterChange(doc, change, update) {\n    var obj = {\n      canceled: false,\n      from: change.from,\n      to: change.to,\n      text: change.text,\n      origin: change.origin,\n      cancel: function() { this.canceled = true; }\n    };\n    if (update) obj.update = function(from, to, text, origin) {\n      if (from) this.from = clipPos(doc, from);\n      if (to) this.to = clipPos(doc, to);\n      if (text) this.text = text;\n      if (origin !== undefined) this.origin = origin;\n    };\n    signal(doc, \"beforeChange\", doc, obj);\n    if (doc.cm) signal(doc.cm, \"beforeChange\", doc.cm, obj);\n\n    if (obj.canceled) return null;\n    return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin};\n  }\n\n  // Apply a change to a document, and add it to the document's\n  // history, and propagating it to all linked documents.\n  function makeChange(doc, change, ignoreReadOnly) {\n    if (doc.cm) {\n      if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly);\n      if (doc.cm.state.suppressEdits) return;\n    }\n\n    if (hasHandler(doc, \"beforeChange\") || doc.cm && hasHandler(doc.cm, \"beforeChange\")) {\n      change = filterChange(doc, change, true);\n      if (!change) return;\n    }\n\n    // Possibly split or suppress the update based on the presence\n    // of read-only spans in its range.\n    var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);\n    if (split) {\n      for (var i = split.length - 1; i >= 0; --i)\n        makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [\"\"] : change.text});\n    } else {\n      makeChangeInner(doc, change);\n    }\n  }\n\n  function makeChangeInner(doc, change) {\n    if (change.text.length == 1 && change.text[0] == \"\" && cmp(change.from, change.to) == 0) return;\n    var selAfter = computeSelAfterChange(doc, change);\n    addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);\n\n    makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));\n    var rebased = [];\n\n    linkedDocs(doc, function(doc, sharedHist) {\n      if (!sharedHist && indexOf(rebased, doc.history) == -1) {\n        rebaseHist(doc.history, change);\n        rebased.push(doc.history);\n      }\n      makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));\n    });\n  }\n\n  // Revert a change stored in a document's history.\n  function makeChangeFromHistory(doc, type, allowSelectionOnly) {\n    if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) return;\n\n    var hist = doc.history, event, selAfter = doc.sel;\n    var source = type == \"undo\" ? hist.done : hist.undone, dest = type == \"undo\" ? hist.undone : hist.done;\n\n    // Verify that there is a useable event (so that ctrl-z won't\n    // needlessly clear selection events)\n    for (var i = 0; i < source.length; i++) {\n      event = source[i];\n      if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)\n        break;\n    }\n    if (i == source.length) return;\n    hist.lastOrigin = hist.lastSelOrigin = null;\n\n    for (;;) {\n      event = source.pop();\n      if (event.ranges) {\n        pushSelectionToHistory(event, dest);\n        if (allowSelectionOnly && !event.equals(doc.sel)) {\n          setSelection(doc, event, {clearRedo: false});\n          return;\n        }\n        selAfter = event;\n      }\n      else break;\n    }\n\n    // Build up a reverse change object to add to the opposite history\n    // stack (redo when undoing, and vice versa).\n    var antiChanges = [];\n    pushSelectionToHistory(selAfter, dest);\n    dest.push({changes: antiChanges, generation: hist.generation});\n    hist.generation = event.generation || ++hist.maxGeneration;\n\n    var filter = hasHandler(doc, \"beforeChange\") || doc.cm && hasHandler(doc.cm, \"beforeChange\");\n\n    for (var i = event.changes.length - 1; i >= 0; --i) {\n      var change = event.changes[i];\n      change.origin = type;\n      if (filter && !filterChange(doc, change, false)) {\n        source.length = 0;\n        return;\n      }\n\n      antiChanges.push(historyChangeFromChange(doc, change));\n\n      var after = i ? computeSelAfterChange(doc, change) : lst(source);\n      makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));\n      if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)});\n      var rebased = [];\n\n      // Propagate to the linked documents\n      linkedDocs(doc, function(doc, sharedHist) {\n        if (!sharedHist && indexOf(rebased, doc.history) == -1) {\n          rebaseHist(doc.history, change);\n          rebased.push(doc.history);\n        }\n        makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));\n      });\n    }\n  }\n\n  // Sub-views need their line numbers shifted when text is added\n  // above or below them in the parent document.\n  function shiftDoc(doc, distance) {\n    if (distance == 0) return;\n    doc.first += distance;\n    doc.sel = new Selection(map(doc.sel.ranges, function(range) {\n      return new Range(Pos(range.anchor.line + distance, range.anchor.ch),\n                       Pos(range.head.line + distance, range.head.ch));\n    }), doc.sel.primIndex);\n    if (doc.cm) {\n      regChange(doc.cm, doc.first, doc.first - distance, distance);\n      for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)\n        regLineChange(doc.cm, l, \"gutter\");\n    }\n  }\n\n  // More lower-level change function, handling only a single document\n  // (not linked ones).\n  function makeChangeSingleDoc(doc, change, selAfter, spans) {\n    if (doc.cm && !doc.cm.curOp)\n      return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans);\n\n    if (change.to.line < doc.first) {\n      shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));\n      return;\n    }\n    if (change.from.line > doc.lastLine()) return;\n\n    // Clip the change to the size of this doc\n    if (change.from.line < doc.first) {\n      var shift = change.text.length - 1 - (doc.first - change.from.line);\n      shiftDoc(doc, shift);\n      change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),\n                text: [lst(change.text)], origin: change.origin};\n    }\n    var last = doc.lastLine();\n    if (change.to.line > last) {\n      change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),\n                text: [change.text[0]], origin: change.origin};\n    }\n\n    change.removed = getBetween(doc, change.from, change.to);\n\n    if (!selAfter) selAfter = computeSelAfterChange(doc, change);\n    if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans);\n    else updateDoc(doc, change, spans);\n    setSelectionNoUndo(doc, selAfter, sel_dontScroll);\n  }\n\n  // Handle the interaction of a change to a document with the editor\n  // that this document is part of.\n  function makeChangeSingleDocInEditor(cm, change, spans) {\n    var doc = cm.doc, display = cm.display, from = change.from, to = change.to;\n\n    var recomputeMaxLength = false, checkWidthStart = from.line;\n    if (!cm.options.lineWrapping) {\n      checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));\n      doc.iter(checkWidthStart, to.line + 1, function(line) {\n        if (line == display.maxLine) {\n          recomputeMaxLength = true;\n          return true;\n        }\n      });\n    }\n\n    if (doc.sel.contains(change.from, change.to) > -1)\n      signalCursorActivity(cm);\n\n    updateDoc(doc, change, spans, estimateHeight(cm));\n\n    if (!cm.options.lineWrapping) {\n      doc.iter(checkWidthStart, from.line + change.text.length, function(line) {\n        var len = lineLength(line);\n        if (len > display.maxLineLength) {\n          display.maxLine = line;\n          display.maxLineLength = len;\n          display.maxLineChanged = true;\n          recomputeMaxLength = false;\n        }\n      });\n      if (recomputeMaxLength) cm.curOp.updateMaxLine = true;\n    }\n\n    // Adjust frontier, schedule worker\n    doc.frontier = Math.min(doc.frontier, from.line);\n    startWorker(cm, 400);\n\n    var lendiff = change.text.length - (to.line - from.line) - 1;\n    // Remember that these lines changed, for updating the display\n    if (change.full)\n      regChange(cm);\n    else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))\n      regLineChange(cm, from.line, \"text\");\n    else\n      regChange(cm, from.line, to.line + 1, lendiff);\n\n    var changesHandler = hasHandler(cm, \"changes\"), changeHandler = hasHandler(cm, \"change\");\n    if (changeHandler || changesHandler) {\n      var obj = {\n        from: from, to: to,\n        text: change.text,\n        removed: change.removed,\n        origin: change.origin\n      };\n      if (changeHandler) signalLater(cm, \"change\", cm, obj);\n      if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj);\n    }\n    cm.display.selForContextMenu = null;\n  }\n\n  function replaceRange(doc, code, from, to, origin) {\n    if (!to) to = from;\n    if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }\n    if (typeof code == \"string\") code = doc.splitLines(code);\n    makeChange(doc, {from: from, to: to, text: code, origin: origin});\n  }\n\n  // SCROLLING THINGS INTO VIEW\n\n  // If an editor sits on the top or bottom of the window, partially\n  // scrolled out of view, this ensures that the cursor is visible.\n  function maybeScrollWindow(cm, coords) {\n    if (signalDOMEvent(cm, \"scrollCursorIntoView\")) return;\n\n    var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;\n    if (coords.top + box.top < 0) doScroll = true;\n    else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;\n    if (doScroll != null && !phantom) {\n      var scrollNode = elt(\"div\", \"\\u200b\", null, \"position: absolute; top: \" +\n                           (coords.top - display.viewOffset - paddingTop(cm.display)) + \"px; height: \" +\n                           (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + \"px; left: \" +\n                           coords.left + \"px; width: 2px;\");\n      cm.display.lineSpace.appendChild(scrollNode);\n      scrollNode.scrollIntoView(doScroll);\n      cm.display.lineSpace.removeChild(scrollNode);\n    }\n  }\n\n  // Scroll a given position into view (immediately), verifying that\n  // it actually became visible (as line heights are accurately\n  // measured, the position of something may 'drift' during drawing).\n  function scrollPosIntoView(cm, pos, end, margin) {\n    if (margin == null) margin = 0;\n    for (var limit = 0; limit < 5; limit++) {\n      var changed = false, coords = cursorCoords(cm, pos);\n      var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);\n      var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),\n                                         Math.min(coords.top, endCoords.top) - margin,\n                                         Math.max(coords.left, endCoords.left),\n                                         Math.max(coords.bottom, endCoords.bottom) + margin);\n      var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;\n      if (scrollPos.scrollTop != null) {\n        setScrollTop(cm, scrollPos.scrollTop);\n        if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true;\n      }\n      if (scrollPos.scrollLeft != null) {\n        setScrollLeft(cm, scrollPos.scrollLeft);\n        if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;\n      }\n      if (!changed) break;\n    }\n    return coords;\n  }\n\n  // Scroll a given set of coordinates into view (immediately).\n  function scrollIntoView(cm, x1, y1, x2, y2) {\n    var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);\n    if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);\n    if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);\n  }\n\n  // Calculate a new scroll position needed to scroll the given\n  // rectangle into view. Returns an object with scrollTop and\n  // scrollLeft properties. When these are undefined, the\n  // vertical/horizontal position does not need to be adjusted.\n  function calculateScrollPos(cm, x1, y1, x2, y2) {\n    var display = cm.display, snapMargin = textHeight(cm.display);\n    if (y1 < 0) y1 = 0;\n    var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;\n    var screen = displayHeight(cm), result = {};\n    if (y2 - y1 > screen) y2 = y1 + screen;\n    var docBottom = cm.doc.height + paddingVert(display);\n    var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;\n    if (y1 < screentop) {\n      result.scrollTop = atTop ? 0 : y1;\n    } else if (y2 > screentop + screen) {\n      var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);\n      if (newTop != screentop) result.scrollTop = newTop;\n    }\n\n    var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;\n    var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);\n    var tooWide = x2 - x1 > screenw;\n    if (tooWide) x2 = x1 + screenw;\n    if (x1 < 10)\n      result.scrollLeft = 0;\n    else if (x1 < screenleft)\n      result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));\n    else if (x2 > screenw + screenleft - 3)\n      result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;\n    return result;\n  }\n\n  // Store a relative adjustment to the scroll position in the current\n  // operation (to be applied when the operation finishes).\n  function addToScrollPos(cm, left, top) {\n    if (left != null || top != null) resolveScrollToPos(cm);\n    if (left != null)\n      cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left;\n    if (top != null)\n      cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;\n  }\n\n  // Make sure that at the end of the operation the current cursor is\n  // shown.\n  function ensureCursorVisible(cm) {\n    resolveScrollToPos(cm);\n    var cur = cm.getCursor(), from = cur, to = cur;\n    if (!cm.options.lineWrapping) {\n      from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur;\n      to = Pos(cur.line, cur.ch + 1);\n    }\n    cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true};\n  }\n\n  // When an operation has its scrollToPos property set, and another\n  // scroll action is applied before the end of the operation, this\n  // 'simulates' scrolling that position into view in a cheap way, so\n  // that the effect of intermediate scroll commands is not ignored.\n  function resolveScrollToPos(cm) {\n    var range = cm.curOp.scrollToPos;\n    if (range) {\n      cm.curOp.scrollToPos = null;\n      var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);\n      var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),\n                                    Math.min(from.top, to.top) - range.margin,\n                                    Math.max(from.right, to.right),\n                                    Math.max(from.bottom, to.bottom) + range.margin);\n      cm.scrollTo(sPos.scrollLeft, sPos.scrollTop);\n    }\n  }\n\n  // API UTILITIES\n\n  // Indent the given line. The how parameter can be \"smart\",\n  // \"add\"/null, \"subtract\", or \"prev\". When aggressive is false\n  // (typically set to true for forced single-line indents), empty\n  // lines are not indented, and places where the mode returns Pass\n  // are left alone.\n  function indentLine(cm, n, how, aggressive) {\n    var doc = cm.doc, state;\n    if (how == null) how = \"add\";\n    if (how == \"smart\") {\n      // Fall back to \"prev\" when the mode doesn't have an indentation\n      // method.\n      if (!doc.mode.indent) how = \"prev\";\n      else state = getStateBefore(cm, n);\n    }\n\n    var tabSize = cm.options.tabSize;\n    var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);\n    if (line.stateAfter) line.stateAfter = null;\n    var curSpaceString = line.text.match(/^\\s*/)[0], indentation;\n    if (!aggressive && !/\\S/.test(line.text)) {\n      indentation = 0;\n      how = \"not\";\n    } else if (how == \"smart\") {\n      indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);\n      if (indentation == Pass || indentation > 150) {\n        if (!aggressive) return;\n        how = \"prev\";\n      }\n    }\n    if (how == \"prev\") {\n      if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);\n      else indentation = 0;\n    } else if (how == \"add\") {\n      indentation = curSpace + cm.options.indentUnit;\n    } else if (how == \"subtract\") {\n      indentation = curSpace - cm.options.indentUnit;\n    } else if (typeof how == \"number\") {\n      indentation = curSpace + how;\n    }\n    indentation = Math.max(0, indentation);\n\n    var indentString = \"\", pos = 0;\n    if (cm.options.indentWithTabs)\n      for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += \"\\t\";}\n    if (pos < indentation) indentString += spaceStr(indentation - pos);\n\n    if (indentString != curSpaceString) {\n      replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), \"+input\");\n      line.stateAfter = null;\n      return true;\n    } else {\n      // Ensure that, if the cursor was in the whitespace at the start\n      // of the line, it is moved to the end of that space.\n      for (var i = 0; i < doc.sel.ranges.length; i++) {\n        var range = doc.sel.ranges[i];\n        if (range.head.line == n && range.head.ch < curSpaceString.length) {\n          var pos = Pos(n, curSpaceString.length);\n          replaceOneSelection(doc, i, new Range(pos, pos));\n          break;\n        }\n      }\n    }\n  }\n\n  // Utility for applying a change to a line by handle or number,\n  // returning the number and optionally registering the line as\n  // changed.\n  function changeLine(doc, handle, changeType, op) {\n    var no = handle, line = handle;\n    if (typeof handle == \"number\") line = getLine(doc, clipLine(doc, handle));\n    else no = lineNo(handle);\n    if (no == null) return null;\n    if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType);\n    return line;\n  }\n\n  // Helper for deleting text near the selection(s), used to implement\n  // backspace, delete, and similar functionality.\n  function deleteNearSelection(cm, compute) {\n    var ranges = cm.doc.sel.ranges, kill = [];\n    // Build up a set of ranges to kill first, merging overlapping\n    // ranges.\n    for (var i = 0; i < ranges.length; i++) {\n      var toKill = compute(ranges[i]);\n      while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {\n        var replaced = kill.pop();\n        if (cmp(replaced.from, toKill.from) < 0) {\n          toKill.from = replaced.from;\n          break;\n        }\n      }\n      kill.push(toKill);\n    }\n    // Next, remove those actual ranges.\n    runInOp(cm, function() {\n      for (var i = kill.length - 1; i >= 0; i--)\n        replaceRange(cm.doc, \"\", kill[i].from, kill[i].to, \"+delete\");\n      ensureCursorVisible(cm);\n    });\n  }\n\n  // Used for horizontal relative motion. Dir is -1 or 1 (left or\n  // right), unit can be \"char\", \"column\" (like char, but doesn't\n  // cross line boundaries), \"word\" (across next word), or \"group\" (to\n  // the start of next group of word or non-word-non-whitespace\n  // chars). The visually param controls whether, in right-to-left\n  // text, direction 1 means to move towards the next index in the\n  // string, or towards the character to the right of the current\n  // position. The resulting position will have a hitSide=true\n  // property if it reached the end of the document.\n  function findPosH(doc, pos, dir, unit, visually) {\n    var line = pos.line, ch = pos.ch, origDir = dir;\n    var lineObj = getLine(doc, line);\n    function findNextLine() {\n      var l = line + dir;\n      if (l < doc.first || l >= doc.first + doc.size) return false\n      line = l;\n      return lineObj = getLine(doc, l);\n    }\n    function moveOnce(boundToLine) {\n      var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);\n      if (next == null) {\n        if (!boundToLine && findNextLine()) {\n          if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);\n          else ch = dir < 0 ? lineObj.text.length : 0;\n        } else return false\n      } else ch = next;\n      return true;\n    }\n\n    if (unit == \"char\") {\n      moveOnce()\n    } else if (unit == \"column\") {\n      moveOnce(true)\n    } else if (unit == \"word\" || unit == \"group\") {\n      var sawType = null, group = unit == \"group\";\n      var helper = doc.cm && doc.cm.getHelper(pos, \"wordChars\");\n      for (var first = true;; first = false) {\n        if (dir < 0 && !moveOnce(!first)) break;\n        var cur = lineObj.text.charAt(ch) || \"\\n\";\n        var type = isWordChar(cur, helper) ? \"w\"\n          : group && cur == \"\\n\" ? \"n\"\n          : !group || /\\s/.test(cur) ? null\n          : \"p\";\n        if (group && !first && !type) type = \"s\";\n        if (sawType && sawType != type) {\n          if (dir < 0) {dir = 1; moveOnce();}\n          break;\n        }\n\n        if (type) sawType = type;\n        if (dir > 0 && !moveOnce(!first)) break;\n      }\n    }\n    var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true);\n    if (!cmp(pos, result)) result.hitSide = true;\n    return result;\n  }\n\n  // For relative vertical movement. Dir may be -1 or 1. Unit can be\n  // \"page\" or \"line\". The resulting position will have a hitSide=true\n  // property if it reached the end of the document.\n  function findPosV(cm, pos, dir, unit) {\n    var doc = cm.doc, x = pos.left, y;\n    if (unit == \"page\") {\n      var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);\n      var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3);\n      y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount;\n    } else if (unit == \"line\") {\n      y = dir > 0 ? pos.bottom + 3 : pos.top - 3;\n    }\n    for (;;) {\n      var target = coordsChar(cm, x, y);\n      if (!target.outside) break;\n      if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }\n      y += dir * 5;\n    }\n    return target;\n  }\n\n  // EDITOR METHODS\n\n  // The publicly visible API. Note that methodOp(f) means\n  // 'wrap f in an operation, performed on its `this` parameter'.\n\n  // This is not the complete set of editor methods. Most of the\n  // methods defined on the Doc type are also injected into\n  // CodeMirror.prototype, for backwards compatibility and\n  // convenience.\n\n  CodeMirror.prototype = {\n    constructor: CodeMirror,\n    focus: function(){window.focus(); this.display.input.focus();},\n\n    setOption: function(option, value) {\n      var options = this.options, old = options[option];\n      if (options[option] == value && option != \"mode\") return;\n      options[option] = value;\n      if (optionHandlers.hasOwnProperty(option))\n        operation(this, optionHandlers[option])(this, value, old);\n    },\n\n    getOption: function(option) {return this.options[option];},\n    getDoc: function() {return this.doc;},\n\n    addKeyMap: function(map, bottom) {\n      this.state.keyMaps[bottom ? \"push\" : \"unshift\"](getKeyMap(map));\n    },\n    removeKeyMap: function(map) {\n      var maps = this.state.keyMaps;\n      for (var i = 0; i < maps.length; ++i)\n        if (maps[i] == map || maps[i].name == map) {\n          maps.splice(i, 1);\n          return true;\n        }\n    },\n\n    addOverlay: methodOp(function(spec, options) {\n      var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);\n      if (mode.startState) throw new Error(\"Overlays may not be stateful.\");\n      insertSorted(this.state.overlays,\n                   {mode: mode, modeSpec: spec, opaque: options && options.opaque,\n                    priority: (options && options.priority) || 0},\n                   function(overlay) { return overlay.priority })\n      this.state.modeGen++;\n      regChange(this);\n    }),\n    removeOverlay: methodOp(function(spec) {\n      var overlays = this.state.overlays;\n      for (var i = 0; i < overlays.length; ++i) {\n        var cur = overlays[i].modeSpec;\n        if (cur == spec || typeof spec == \"string\" && cur.name == spec) {\n          overlays.splice(i, 1);\n          this.state.modeGen++;\n          regChange(this);\n          return;\n        }\n      }\n    }),\n\n    indentLine: methodOp(function(n, dir, aggressive) {\n      if (typeof dir != \"string\" && typeof dir != \"number\") {\n        if (dir == null) dir = this.options.smartIndent ? \"smart\" : \"prev\";\n        else dir = dir ? \"add\" : \"subtract\";\n      }\n      if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);\n    }),\n    indentSelection: methodOp(function(how) {\n      var ranges = this.doc.sel.ranges, end = -1;\n      for (var i = 0; i < ranges.length; i++) {\n        var range = ranges[i];\n        if (!range.empty()) {\n          var from = range.from(), to = range.to();\n          var start = Math.max(end, from.line);\n          end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;\n          for (var j = start; j < end; ++j)\n            indentLine(this, j, how);\n          var newRanges = this.doc.sel.ranges;\n          if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)\n            replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll);\n        } else if (range.head.line > end) {\n          indentLine(this, range.head.line, how, true);\n          end = range.head.line;\n          if (i == this.doc.sel.primIndex) ensureCursorVisible(this);\n        }\n      }\n    }),\n\n    // Fetch the parser token for a given character. Useful for hacks\n    // that want to inspect the mode state (say, for completion).\n    getTokenAt: function(pos, precise) {\n      return takeToken(this, pos, precise);\n    },\n\n    getLineTokens: function(line, precise) {\n      return takeToken(this, Pos(line), precise, true);\n    },\n\n    getTokenTypeAt: function(pos) {\n      pos = clipPos(this.doc, pos);\n      var styles = getLineStyles(this, getLine(this.doc, pos.line));\n      var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;\n      var type;\n      if (ch == 0) type = styles[2];\n      else for (;;) {\n        var mid = (before + after) >> 1;\n        if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;\n        else if (styles[mid * 2 + 1] < ch) before = mid + 1;\n        else { type = styles[mid * 2 + 2]; break; }\n      }\n      var cut = type ? type.indexOf(\"cm-overlay \") : -1;\n      return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1);\n    },\n\n    getModeAt: function(pos) {\n      var mode = this.doc.mode;\n      if (!mode.innerMode) return mode;\n      return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;\n    },\n\n    getHelper: function(pos, type) {\n      return this.getHelpers(pos, type)[0];\n    },\n\n    getHelpers: function(pos, type) {\n      var found = [];\n      if (!helpers.hasOwnProperty(type)) return found;\n      var help = helpers[type], mode = this.getModeAt(pos);\n      if (typeof mode[type] == \"string\") {\n        if (help[mode[type]]) found.push(help[mode[type]]);\n      } else if (mode[type]) {\n        for (var i = 0; i < mode[type].length; i++) {\n          var val = help[mode[type][i]];\n          if (val) found.push(val);\n        }\n      } else if (mode.helperType && help[mode.helperType]) {\n        found.push(help[mode.helperType]);\n      } else if (help[mode.name]) {\n        found.push(help[mode.name]);\n      }\n      for (var i = 0; i < help._global.length; i++) {\n        var cur = help._global[i];\n        if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)\n          found.push(cur.val);\n      }\n      return found;\n    },\n\n    getStateAfter: function(line, precise) {\n      var doc = this.doc;\n      line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);\n      return getStateBefore(this, line + 1, precise);\n    },\n\n    cursorCoords: function(start, mode) {\n      var pos, range = this.doc.sel.primary();\n      if (start == null) pos = range.head;\n      else if (typeof start == \"object\") pos = clipPos(this.doc, start);\n      else pos = start ? range.from() : range.to();\n      return cursorCoords(this, pos, mode || \"page\");\n    },\n\n    charCoords: function(pos, mode) {\n      return charCoords(this, clipPos(this.doc, pos), mode || \"page\");\n    },\n\n    coordsChar: function(coords, mode) {\n      coords = fromCoordSystem(this, coords, mode || \"page\");\n      return coordsChar(this, coords.left, coords.top);\n    },\n\n    lineAtHeight: function(height, mode) {\n      height = fromCoordSystem(this, {top: height, left: 0}, mode || \"page\").top;\n      return lineAtHeight(this.doc, height + this.display.viewOffset);\n    },\n    heightAtLine: function(line, mode) {\n      var end = false, lineObj;\n      if (typeof line == \"number\") {\n        var last = this.doc.first + this.doc.size - 1;\n        if (line < this.doc.first) line = this.doc.first;\n        else if (line > last) { line = last; end = true; }\n        lineObj = getLine(this.doc, line);\n      } else {\n        lineObj = line;\n      }\n      return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || \"page\").top +\n        (end ? this.doc.height - heightAtLine(lineObj) : 0);\n    },\n\n    defaultTextHeight: function() { return textHeight(this.display); },\n    defaultCharWidth: function() { return charWidth(this.display); },\n\n    setGutterMarker: methodOp(function(line, gutterID, value) {\n      return changeLine(this.doc, line, \"gutter\", function(line) {\n        var markers = line.gutterMarkers || (line.gutterMarkers = {});\n        markers[gutterID] = value;\n        if (!value && isEmpty(markers)) line.gutterMarkers = null;\n        return true;\n      });\n    }),\n\n    clearGutter: methodOp(function(gutterID) {\n      var cm = this, doc = cm.doc, i = doc.first;\n      doc.iter(function(line) {\n        if (line.gutterMarkers && line.gutterMarkers[gutterID]) {\n          line.gutterMarkers[gutterID] = null;\n          regLineChange(cm, i, \"gutter\");\n          if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;\n        }\n        ++i;\n      });\n    }),\n\n    lineInfo: function(line) {\n      if (typeof line == \"number\") {\n        if (!isLine(this.doc, line)) return null;\n        var n = line;\n        line = getLine(this.doc, line);\n        if (!line) return null;\n      } else {\n        var n = lineNo(line);\n        if (n == null) return null;\n      }\n      return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,\n              textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,\n              widgets: line.widgets};\n    },\n\n    getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};},\n\n    addWidget: function(pos, node, scroll, vert, horiz) {\n      var display = this.display;\n      pos = cursorCoords(this, clipPos(this.doc, pos));\n      var top = pos.bottom, left = pos.left;\n      node.style.position = \"absolute\";\n      node.setAttribute(\"cm-ignore-events\", \"true\");\n      this.display.input.setUneditable(node);\n      display.sizer.appendChild(node);\n      if (vert == \"over\") {\n        top = pos.top;\n      } else if (vert == \"above\" || vert == \"near\") {\n        var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),\n        hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);\n        // Default to positioning above (if specified and possible); otherwise default to positioning below\n        if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)\n          top = pos.top - node.offsetHeight;\n        else if (pos.bottom + node.offsetHeight <= vspace)\n          top = pos.bottom;\n        if (left + node.offsetWidth > hspace)\n          left = hspace - node.offsetWidth;\n      }\n      node.style.top = top + \"px\";\n      node.style.left = node.style.right = \"\";\n      if (horiz == \"right\") {\n        left = display.sizer.clientWidth - node.offsetWidth;\n        node.style.right = \"0px\";\n      } else {\n        if (horiz == \"left\") left = 0;\n        else if (horiz == \"middle\") left = (display.sizer.clientWidth - node.offsetWidth) / 2;\n        node.style.left = left + \"px\";\n      }\n      if (scroll)\n        scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);\n    },\n\n    triggerOnKeyDown: methodOp(onKeyDown),\n    triggerOnKeyPress: methodOp(onKeyPress),\n    triggerOnKeyUp: onKeyUp,\n\n    execCommand: function(cmd) {\n      if (commands.hasOwnProperty(cmd))\n        return commands[cmd].call(null, this);\n    },\n\n    triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),\n\n    findPosH: function(from, amount, unit, visually) {\n      var dir = 1;\n      if (amount < 0) { dir = -1; amount = -amount; }\n      for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {\n        cur = findPosH(this.doc, cur, dir, unit, visually);\n        if (cur.hitSide) break;\n      }\n      return cur;\n    },\n\n    moveH: methodOp(function(dir, unit) {\n      var cm = this;\n      cm.extendSelectionsBy(function(range) {\n        if (cm.display.shift || cm.doc.extend || range.empty())\n          return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually);\n        else\n          return dir < 0 ? range.from() : range.to();\n      }, sel_move);\n    }),\n\n    deleteH: methodOp(function(dir, unit) {\n      var sel = this.doc.sel, doc = this.doc;\n      if (sel.somethingSelected())\n        doc.replaceSelection(\"\", null, \"+delete\");\n      else\n        deleteNearSelection(this, function(range) {\n          var other = findPosH(doc, range.head, dir, unit, false);\n          return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other};\n        });\n    }),\n\n    findPosV: function(from, amount, unit, goalColumn) {\n      var dir = 1, x = goalColumn;\n      if (amount < 0) { dir = -1; amount = -amount; }\n      for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {\n        var coords = cursorCoords(this, cur, \"div\");\n        if (x == null) x = coords.left;\n        else coords.left = x;\n        cur = findPosV(this, coords, dir, unit);\n        if (cur.hitSide) break;\n      }\n      return cur;\n    },\n\n    moveV: methodOp(function(dir, unit) {\n      var cm = this, doc = this.doc, goals = [];\n      var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected();\n      doc.extendSelectionsBy(function(range) {\n        if (collapse)\n          return dir < 0 ? range.from() : range.to();\n        var headPos = cursorCoords(cm, range.head, \"div\");\n        if (range.goalColumn != null) headPos.left = range.goalColumn;\n        goals.push(headPos.left);\n        var pos = findPosV(cm, headPos, dir, unit);\n        if (unit == \"page\" && range == doc.sel.primary())\n          addToScrollPos(cm, null, charCoords(cm, pos, \"div\").top - headPos.top);\n        return pos;\n      }, sel_move);\n      if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++)\n        doc.sel.ranges[i].goalColumn = goals[i];\n    }),\n\n    // Find the word at the given position (as returned by coordsChar).\n    findWordAt: function(pos) {\n      var doc = this.doc, line = getLine(doc, pos.line).text;\n      var start = pos.ch, end = pos.ch;\n      if (line) {\n        var helper = this.getHelper(pos, \"wordChars\");\n        if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end;\n        var startChar = line.charAt(start);\n        var check = isWordChar(startChar, helper)\n          ? function(ch) { return isWordChar(ch, helper); }\n          : /\\s/.test(startChar) ? function(ch) {return /\\s/.test(ch);}\n          : function(ch) {return !/\\s/.test(ch) && !isWordChar(ch);};\n        while (start > 0 && check(line.charAt(start - 1))) --start;\n        while (end < line.length && check(line.charAt(end))) ++end;\n      }\n      return new Range(Pos(pos.line, start), Pos(pos.line, end));\n    },\n\n    toggleOverwrite: function(value) {\n      if (value != null && value == this.state.overwrite) return;\n      if (this.state.overwrite = !this.state.overwrite)\n        addClass(this.display.cursorDiv, \"CodeMirror-overwrite\");\n      else\n        rmClass(this.display.cursorDiv, \"CodeMirror-overwrite\");\n\n      signal(this, \"overwriteToggle\", this, this.state.overwrite);\n    },\n    hasFocus: function() { return this.display.input.getField() == activeElt(); },\n    isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit); },\n\n    scrollTo: methodOp(function(x, y) {\n      if (x != null || y != null) resolveScrollToPos(this);\n      if (x != null) this.curOp.scrollLeft = x;\n      if (y != null) this.curOp.scrollTop = y;\n    }),\n    getScrollInfo: function() {\n      var scroller = this.display.scroller;\n      return {left: scroller.scrollLeft, top: scroller.scrollTop,\n              height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,\n              width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,\n              clientHeight: displayHeight(this), clientWidth: displayWidth(this)};\n    },\n\n    scrollIntoView: methodOp(function(range, margin) {\n      if (range == null) {\n        range = {from: this.doc.sel.primary().head, to: null};\n        if (margin == null) margin = this.options.cursorScrollMargin;\n      } else if (typeof range == \"number\") {\n        range = {from: Pos(range, 0), to: null};\n      } else if (range.from == null) {\n        range = {from: range, to: null};\n      }\n      if (!range.to) range.to = range.from;\n      range.margin = margin || 0;\n\n      if (range.from.line != null) {\n        resolveScrollToPos(this);\n        this.curOp.scrollToPos = range;\n      } else {\n        var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left),\n                                      Math.min(range.from.top, range.to.top) - range.margin,\n                                      Math.max(range.from.right, range.to.right),\n                                      Math.max(range.from.bottom, range.to.bottom) + range.margin);\n        this.scrollTo(sPos.scrollLeft, sPos.scrollTop);\n      }\n    }),\n\n    setSize: methodOp(function(width, height) {\n      var cm = this;\n      function interpret(val) {\n        return typeof val == \"number\" || /^\\d+$/.test(String(val)) ? val + \"px\" : val;\n      }\n      if (width != null) cm.display.wrapper.style.width = interpret(width);\n      if (height != null) cm.display.wrapper.style.height = interpret(height);\n      if (cm.options.lineWrapping) clearLineMeasurementCache(this);\n      var lineNo = cm.display.viewFrom;\n      cm.doc.iter(lineNo, cm.display.viewTo, function(line) {\n        if (line.widgets) for (var i = 0; i < line.widgets.length; i++)\n          if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, \"widget\"); break; }\n        ++lineNo;\n      });\n      cm.curOp.forceUpdate = true;\n      signal(cm, \"refresh\", this);\n    }),\n\n    operation: function(f){return runInOp(this, f);},\n\n    refresh: methodOp(function() {\n      var oldHeight = this.display.cachedTextHeight;\n      regChange(this);\n      this.curOp.forceUpdate = true;\n      clearCaches(this);\n      this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);\n      updateGutterSpace(this);\n      if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)\n        estimateLineHeights(this);\n      signal(this, \"refresh\", this);\n    }),\n\n    swapDoc: methodOp(function(doc) {\n      var old = this.doc;\n      old.cm = null;\n      attachDoc(this, doc);\n      clearCaches(this);\n      this.display.input.reset();\n      this.scrollTo(doc.scrollLeft, doc.scrollTop);\n      this.curOp.forceScroll = true;\n      signalLater(this, \"swapDoc\", this, old);\n      return old;\n    }),\n\n    getInputField: function(){return this.display.input.getField();},\n    getWrapperElement: function(){return this.display.wrapper;},\n    getScrollerElement: function(){return this.display.scroller;},\n    getGutterElement: function(){return this.display.gutters;}\n  };\n  eventMixin(CodeMirror);\n\n  // OPTION DEFAULTS\n\n  // The default configuration options.\n  var defaults = CodeMirror.defaults = {};\n  // Functions to run when options are changed.\n  var optionHandlers = CodeMirror.optionHandlers = {};\n\n  function option(name, deflt, handle, notOnInit) {\n    CodeMirror.defaults[name] = deflt;\n    if (handle) optionHandlers[name] =\n      notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;\n  }\n\n  // Passed to option handlers when there is no old value.\n  var Init = CodeMirror.Init = {toString: function(){return \"CodeMirror.Init\";}};\n\n  // These two are, on init, called from the constructor because they\n  // have to be initialized before the editor can start at all.\n  option(\"value\", \"\", function(cm, val) {\n    cm.setValue(val);\n  }, true);\n  option(\"mode\", null, function(cm, val) {\n    cm.doc.modeOption = val;\n    loadMode(cm);\n  }, true);\n\n  option(\"indentUnit\", 2, loadMode, true);\n  option(\"indentWithTabs\", false);\n  option(\"smartIndent\", true);\n  option(\"tabSize\", 4, function(cm) {\n    resetModeState(cm);\n    clearCaches(cm);\n    regChange(cm);\n  }, true);\n  option(\"lineSeparator\", null, function(cm, val) {\n    cm.doc.lineSep = val;\n    if (!val) return;\n    var newBreaks = [], lineNo = cm.doc.first;\n    cm.doc.iter(function(line) {\n      for (var pos = 0;;) {\n        var found = line.text.indexOf(val, pos);\n        if (found == -1) break;\n        pos = found + val.length;\n        newBreaks.push(Pos(lineNo, found));\n      }\n      lineNo++;\n    });\n    for (var i = newBreaks.length - 1; i >= 0; i--)\n      replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length))\n  });\n  option(\"specialChars\", /[\\u0000-\\u001f\\u007f\\u00ad\\u200b-\\u200f\\u2028\\u2029\\ufeff]/g, function(cm, val, old) {\n    cm.state.specialChars = new RegExp(val.source + (val.test(\"\\t\") ? \"\" : \"|\\t\"), \"g\");\n    if (old != CodeMirror.Init) cm.refresh();\n  });\n  option(\"specialCharPlaceholder\", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);\n  option(\"electricChars\", true);\n  option(\"inputStyle\", mobile ? \"contenteditable\" : \"textarea\", function() {\n    throw new Error(\"inputStyle can not (yet) be changed in a running editor\"); // FIXME\n  }, true);\n  option(\"spellcheck\", false, function(cm, val) {\n    cm.getInputField().spellcheck = val\n  }, true);\n  option(\"rtlMoveVisually\", !windows);\n  option(\"wholeLineUpdateBefore\", true);\n\n  option(\"theme\", \"default\", function(cm) {\n    themeChanged(cm);\n    guttersChanged(cm);\n  }, true);\n  option(\"keyMap\", \"default\", function(cm, val, old) {\n    var next = getKeyMap(val);\n    var prev = old != CodeMirror.Init && getKeyMap(old);\n    if (prev && prev.detach) prev.detach(cm, next);\n    if (next.attach) next.attach(cm, prev || null);\n  });\n  option(\"extraKeys\", null);\n\n  option(\"lineWrapping\", false, wrappingChanged, true);\n  option(\"gutters\", [], function(cm) {\n    setGuttersForLineNumbers(cm.options);\n    guttersChanged(cm);\n  }, true);\n  option(\"fixedGutter\", true, function(cm, val) {\n    cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + \"px\" : \"0\";\n    cm.refresh();\n  }, true);\n  option(\"coverGutterNextToScrollbar\", false, function(cm) {updateScrollbars(cm);}, true);\n  option(\"scrollbarStyle\", \"native\", function(cm) {\n    initScrollbars(cm);\n    updateScrollbars(cm);\n    cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);\n    cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);\n  }, true);\n  option(\"lineNumbers\", false, function(cm) {\n    setGuttersForLineNumbers(cm.options);\n    guttersChanged(cm);\n  }, true);\n  option(\"firstLineNumber\", 1, guttersChanged, true);\n  option(\"lineNumberFormatter\", function(integer) {return integer;}, guttersChanged, true);\n  option(\"showCursorWhenSelecting\", false, updateSelection, true);\n\n  option(\"resetSelectionOnContextMenu\", true);\n  option(\"lineWiseCopyCut\", true);\n\n  option(\"readOnly\", false, function(cm, val) {\n    if (val == \"nocursor\") {\n      onBlur(cm);\n      cm.display.input.blur();\n      cm.display.disabled = true;\n    } else {\n      cm.display.disabled = false;\n    }\n    cm.display.input.readOnlyChanged(val)\n  });\n  option(\"disableInput\", false, function(cm, val) {if (!val) cm.display.input.reset();}, true);\n  option(\"dragDrop\", true, dragDropChanged);\n  option(\"allowDropFileTypes\", null);\n\n  option(\"cursorBlinkRate\", 530);\n  option(\"cursorScrollMargin\", 0);\n  option(\"cursorHeight\", 1, updateSelection, true);\n  option(\"singleCursorHeightPerLine\", true, updateSelection, true);\n  option(\"workTime\", 100);\n  option(\"workDelay\", 100);\n  option(\"flattenSpans\", true, resetModeState, true);\n  option(\"addModeClass\", false, resetModeState, true);\n  option(\"pollInterval\", 100);\n  option(\"undoDepth\", 200, function(cm, val){cm.doc.history.undoDepth = val;});\n  option(\"historyEventDelay\", 1250);\n  option(\"viewportMargin\", 10, function(cm){cm.refresh();}, true);\n  option(\"maxHighlightLength\", 10000, resetModeState, true);\n  option(\"moveInputWithCursor\", true, function(cm, val) {\n    if (!val) cm.display.input.resetPosition();\n  });\n\n  option(\"tabindex\", null, function(cm, val) {\n    cm.display.input.getField().tabIndex = val || \"\";\n  });\n  option(\"autofocus\", null);\n\n  // MODE DEFINITION AND QUERYING\n\n  // Known modes, by name and by MIME\n  var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};\n\n  // Extra arguments are stored as the mode's dependencies, which is\n  // used by (legacy) mechanisms like loadmode.js to automatically\n  // load a mode. (Preferred mechanism is the require/define calls.)\n  CodeMirror.defineMode = function(name, mode) {\n    if (!CodeMirror.defaults.mode && name != \"null\") CodeMirror.defaults.mode = name;\n    if (arguments.length > 2)\n      mode.dependencies = Array.prototype.slice.call(arguments, 2);\n    modes[name] = mode;\n  };\n\n  CodeMirror.defineMIME = function(mime, spec) {\n    mimeModes[mime] = spec;\n  };\n\n  // Given a MIME type, a {name, ...options} config object, or a name\n  // string, return a mode config object.\n  CodeMirror.resolveMode = function(spec) {\n    if (typeof spec == \"string\" && mimeModes.hasOwnProperty(spec)) {\n      spec = mimeModes[spec];\n    } else if (spec && typeof spec.name == \"string\" && mimeModes.hasOwnProperty(spec.name)) {\n      var found = mimeModes[spec.name];\n      if (typeof found == \"string\") found = {name: found};\n      spec = createObj(found, spec);\n      spec.name = found.name;\n    } else if (typeof spec == \"string\" && /^[\\w\\-]+\\/[\\w\\-]+\\+xml$/.test(spec)) {\n      return CodeMirror.resolveMode(\"application/xml\");\n    } else if (typeof spec == \"string\" && /^[\\w\\-]+\\/[\\w\\-]+\\+json$/.test(spec)) {\n      return CodeMirror.resolveMode(\"application/json\");\n    }\n    if (typeof spec == \"string\") return {name: spec};\n    else return spec || {name: \"null\"};\n  };\n\n  // Given a mode spec (anything that resolveMode accepts), find and\n  // initialize an actual mode object.\n  CodeMirror.getMode = function(options, spec) {\n    var spec = CodeMirror.resolveMode(spec);\n    var mfactory = modes[spec.name];\n    if (!mfactory) return CodeMirror.getMode(options, \"text/plain\");\n    var modeObj = mfactory(options, spec);\n    if (modeExtensions.hasOwnProperty(spec.name)) {\n      var exts = modeExtensions[spec.name];\n      for (var prop in exts) {\n        if (!exts.hasOwnProperty(prop)) continue;\n        if (modeObj.hasOwnProperty(prop)) modeObj[\"_\" + prop] = modeObj[prop];\n        modeObj[prop] = exts[prop];\n      }\n    }\n    modeObj.name = spec.name;\n    if (spec.helperType) modeObj.helperType = spec.helperType;\n    if (spec.modeProps) for (var prop in spec.modeProps)\n      modeObj[prop] = spec.modeProps[prop];\n\n    return modeObj;\n  };\n\n  // Minimal default mode.\n  CodeMirror.defineMode(\"null\", function() {\n    return {token: function(stream) {stream.skipToEnd();}};\n  });\n  CodeMirror.defineMIME(\"text/plain\", \"null\");\n\n  // This can be used to attach properties to mode objects from\n  // outside the actual mode definition.\n  var modeExtensions = CodeMirror.modeExtensions = {};\n  CodeMirror.extendMode = function(mode, properties) {\n    var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});\n    copyObj(properties, exts);\n  };\n\n  // EXTENSIONS\n\n  CodeMirror.defineExtension = function(name, func) {\n    CodeMirror.prototype[name] = func;\n  };\n  CodeMirror.defineDocExtension = function(name, func) {\n    Doc.prototype[name] = func;\n  };\n  CodeMirror.defineOption = option;\n\n  var initHooks = [];\n  CodeMirror.defineInitHook = function(f) {initHooks.push(f);};\n\n  var helpers = CodeMirror.helpers = {};\n  CodeMirror.registerHelper = function(type, name, value) {\n    if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};\n    helpers[type][name] = value;\n  };\n  CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {\n    CodeMirror.registerHelper(type, name, value);\n    helpers[type]._global.push({pred: predicate, val: value});\n  };\n\n  // MODE STATE HANDLING\n\n  // Utility functions for working with state. Exported because nested\n  // modes need to do this for their inner modes.\n\n  var copyState = CodeMirror.copyState = function(mode, state) {\n    if (state === true) return state;\n    if (mode.copyState) return mode.copyState(state);\n    var nstate = {};\n    for (var n in state) {\n      var val = state[n];\n      if (val instanceof Array) val = val.concat([]);\n      nstate[n] = val;\n    }\n    return nstate;\n  };\n\n  var startState = CodeMirror.startState = function(mode, a1, a2) {\n    return mode.startState ? mode.startState(a1, a2) : true;\n  };\n\n  // Given a mode and a state (for that mode), find the inner mode and\n  // state at the position that the state refers to.\n  CodeMirror.innerMode = function(mode, state) {\n    while (mode.innerMode) {\n      var info = mode.innerMode(state);\n      if (!info || info.mode == mode) break;\n      state = info.state;\n      mode = info.mode;\n    }\n    return info || {mode: mode, state: state};\n  };\n\n  // STANDARD COMMANDS\n\n  // Commands are parameter-less actions that can be performed on an\n  // editor, mostly used for keybindings.\n  var commands = CodeMirror.commands = {\n    selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);},\n    singleSelection: function(cm) {\n      cm.setSelection(cm.getCursor(\"anchor\"), cm.getCursor(\"head\"), sel_dontScroll);\n    },\n    killLine: function(cm) {\n      deleteNearSelection(cm, function(range) {\n        if (range.empty()) {\n          var len = getLine(cm.doc, range.head.line).text.length;\n          if (range.head.ch == len && range.head.line < cm.lastLine())\n            return {from: range.head, to: Pos(range.head.line + 1, 0)};\n          else\n            return {from: range.head, to: Pos(range.head.line, len)};\n        } else {\n          return {from: range.from(), to: range.to()};\n        }\n      });\n    },\n    deleteLine: function(cm) {\n      deleteNearSelection(cm, function(range) {\n        return {from: Pos(range.from().line, 0),\n                to: clipPos(cm.doc, Pos(range.to().line + 1, 0))};\n      });\n    },\n    delLineLeft: function(cm) {\n      deleteNearSelection(cm, function(range) {\n        return {from: Pos(range.from().line, 0), to: range.from()};\n      });\n    },\n    delWrappedLineLeft: function(cm) {\n      deleteNearSelection(cm, function(range) {\n        var top = cm.charCoords(range.head, \"div\").top + 5;\n        var leftPos = cm.coordsChar({left: 0, top: top}, \"div\");\n        return {from: leftPos, to: range.from()};\n      });\n    },\n    delWrappedLineRight: function(cm) {\n      deleteNearSelection(cm, function(range) {\n        var top = cm.charCoords(range.head, \"div\").top + 5;\n        var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, \"div\");\n        return {from: range.from(), to: rightPos };\n      });\n    },\n    undo: function(cm) {cm.undo();},\n    redo: function(cm) {cm.redo();},\n    undoSelection: function(cm) {cm.undoSelection();},\n    redoSelection: function(cm) {cm.redoSelection();},\n    goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},\n    goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},\n    goLineStart: function(cm) {\n      cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); },\n                            {origin: \"+move\", bias: 1});\n    },\n    goLineStartSmart: function(cm) {\n      cm.extendSelectionsBy(function(range) {\n        return lineStartSmart(cm, range.head);\n      }, {origin: \"+move\", bias: 1});\n    },\n    goLineEnd: function(cm) {\n      cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); },\n                            {origin: \"+move\", bias: -1});\n    },\n    goLineRight: function(cm) {\n      cm.extendSelectionsBy(function(range) {\n        var top = cm.charCoords(range.head, \"div\").top + 5;\n        return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, \"div\");\n      }, sel_move);\n    },\n    goLineLeft: function(cm) {\n      cm.extendSelectionsBy(function(range) {\n        var top = cm.charCoords(range.head, \"div\").top + 5;\n        return cm.coordsChar({left: 0, top: top}, \"div\");\n      }, sel_move);\n    },\n    goLineLeftSmart: function(cm) {\n      cm.extendSelectionsBy(function(range) {\n        var top = cm.charCoords(range.head, \"div\").top + 5;\n        var pos = cm.coordsChar({left: 0, top: top}, \"div\");\n        if (pos.ch < cm.getLine(pos.line).search(/\\S/)) return lineStartSmart(cm, range.head);\n        return pos;\n      }, sel_move);\n    },\n    goLineUp: function(cm) {cm.moveV(-1, \"line\");},\n    goLineDown: function(cm) {cm.moveV(1, \"line\");},\n    goPageUp: function(cm) {cm.moveV(-1, \"page\");},\n    goPageDown: function(cm) {cm.moveV(1, \"page\");},\n    goCharLeft: function(cm) {cm.moveH(-1, \"char\");},\n    goCharRight: function(cm) {cm.moveH(1, \"char\");},\n    goColumnLeft: function(cm) {cm.moveH(-1, \"column\");},\n    goColumnRight: function(cm) {cm.moveH(1, \"column\");},\n    goWordLeft: function(cm) {cm.moveH(-1, \"word\");},\n    goGroupRight: function(cm) {cm.moveH(1, \"group\");},\n    goGroupLeft: function(cm) {cm.moveH(-1, \"group\");},\n    goWordRight: function(cm) {cm.moveH(1, \"word\");},\n    delCharBefore: function(cm) {cm.deleteH(-1, \"char\");},\n    delCharAfter: function(cm) {cm.deleteH(1, \"char\");},\n    delWordBefore: function(cm) {cm.deleteH(-1, \"word\");},\n    delWordAfter: function(cm) {cm.deleteH(1, \"word\");},\n    delGroupBefore: function(cm) {cm.deleteH(-1, \"group\");},\n    delGroupAfter: function(cm) {cm.deleteH(1, \"group\");},\n    indentAuto: function(cm) {cm.indentSelection(\"smart\");},\n    indentMore: function(cm) {cm.indentSelection(\"add\");},\n    indentLess: function(cm) {cm.indentSelection(\"subtract\");},\n    insertTab: function(cm) {cm.replaceSelection(\"\\t\");},\n    insertSoftTab: function(cm) {\n      var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;\n      for (var i = 0; i < ranges.length; i++) {\n        var pos = ranges[i].from();\n        var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);\n        spaces.push(spaceStr(tabSize - col % tabSize));\n      }\n      cm.replaceSelections(spaces);\n    },\n    defaultTab: function(cm) {\n      if (cm.somethingSelected()) cm.indentSelection(\"add\");\n      else cm.execCommand(\"insertTab\");\n    },\n    transposeChars: function(cm) {\n      runInOp(cm, function() {\n        var ranges = cm.listSelections(), newSel = [];\n        for (var i = 0; i < ranges.length; i++) {\n          var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;\n          if (line) {\n            if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1);\n            if (cur.ch > 0) {\n              cur = new Pos(cur.line, cur.ch + 1);\n              cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),\n                              Pos(cur.line, cur.ch - 2), cur, \"+transpose\");\n            } else if (cur.line > cm.doc.first) {\n              var prev = getLine(cm.doc, cur.line - 1).text;\n              if (prev)\n                cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +\n                                prev.charAt(prev.length - 1),\n                                Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), \"+transpose\");\n            }\n          }\n          newSel.push(new Range(cur, cur));\n        }\n        cm.setSelections(newSel);\n      });\n    },\n    newlineAndIndent: function(cm) {\n      runInOp(cm, function() {\n        var len = cm.listSelections().length;\n        for (var i = 0; i < len; i++) {\n          var range = cm.listSelections()[i];\n          cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, \"+input\");\n          cm.indentLine(range.from().line + 1, null, true);\n        }\n        ensureCursorVisible(cm);\n      });\n    },\n    openLine: function(cm) {cm.replaceSelection(\"\\n\", \"start\")},\n    toggleOverwrite: function(cm) {cm.toggleOverwrite();}\n  };\n\n\n  // STANDARD KEYMAPS\n\n  var keyMap = CodeMirror.keyMap = {};\n\n  keyMap.basic = {\n    \"Left\": \"goCharLeft\", \"Right\": \"goCharRight\", \"Up\": \"goLineUp\", \"Down\": \"goLineDown\",\n    \"End\": \"goLineEnd\", \"Home\": \"goLineStartSmart\", \"PageUp\": \"goPageUp\", \"PageDown\": \"goPageDown\",\n    \"Delete\": \"delCharAfter\", \"Backspace\": \"delCharBefore\", \"Shift-Backspace\": \"delCharBefore\",\n    \"Tab\": \"defaultTab\", \"Shift-Tab\": \"indentAuto\",\n    \"Enter\": \"newlineAndIndent\", \"Insert\": \"toggleOverwrite\",\n    \"Esc\": \"singleSelection\"\n  };\n  // Note that the save and find-related commands aren't defined by\n  // default. User code or addons can define them. Unknown commands\n  // are simply ignored.\n  keyMap.pcDefault = {\n    \"Ctrl-A\": \"selectAll\", \"Ctrl-D\": \"deleteLine\", \"Ctrl-Z\": \"undo\", \"Shift-Ctrl-Z\": \"redo\", \"Ctrl-Y\": \"redo\",\n    \"Ctrl-Home\": \"goDocStart\", \"Ctrl-End\": \"goDocEnd\", \"Ctrl-Up\": \"goLineUp\", \"Ctrl-Down\": \"goLineDown\",\n    \"Ctrl-Left\": \"goGroupLeft\", \"Ctrl-Right\": \"goGroupRight\", \"Alt-Left\": \"goLineStart\", \"Alt-Right\": \"goLineEnd\",\n    \"Ctrl-Backspace\": \"delGroupBefore\", \"Ctrl-Delete\": \"delGroupAfter\", \"Ctrl-S\": \"save\", \"Ctrl-F\": \"find\",\n    \"Ctrl-G\": \"findNext\", \"Shift-Ctrl-G\": \"findPrev\", \"Shift-Ctrl-F\": \"replace\", \"Shift-Ctrl-R\": \"replaceAll\",\n    \"Ctrl-[\": \"indentLess\", \"Ctrl-]\": \"indentMore\",\n    \"Ctrl-U\": \"undoSelection\", \"Shift-Ctrl-U\": \"redoSelection\", \"Alt-U\": \"redoSelection\",\n    fallthrough: \"basic\"\n  };\n  // Very basic readline/emacs-style bindings, which are standard on Mac.\n  keyMap.emacsy = {\n    \"Ctrl-F\": \"goCharRight\", \"Ctrl-B\": \"goCharLeft\", \"Ctrl-P\": \"goLineUp\", \"Ctrl-N\": \"goLineDown\",\n    \"Alt-F\": \"goWordRight\", \"Alt-B\": \"goWordLeft\", \"Ctrl-A\": \"goLineStart\", \"Ctrl-E\": \"goLineEnd\",\n    \"Ctrl-V\": \"goPageDown\", \"Shift-Ctrl-V\": \"goPageUp\", \"Ctrl-D\": \"delCharAfter\", \"Ctrl-H\": \"delCharBefore\",\n    \"Alt-D\": \"delWordAfter\", \"Alt-Backspace\": \"delWordBefore\", \"Ctrl-K\": \"killLine\", \"Ctrl-T\": \"transposeChars\",\n    \"Ctrl-O\": \"openLine\"\n  };\n  keyMap.macDefault = {\n    \"Cmd-A\": \"selectAll\", \"Cmd-D\": \"deleteLine\", \"Cmd-Z\": \"undo\", \"Shift-Cmd-Z\": \"redo\", \"Cmd-Y\": \"redo\",\n    \"Cmd-Home\": \"goDocStart\", \"Cmd-Up\": \"goDocStart\", \"Cmd-End\": \"goDocEnd\", \"Cmd-Down\": \"goDocEnd\", \"Alt-Left\": \"goGroupLeft\",\n    \"Alt-Right\": \"goGroupRight\", \"Cmd-Left\": \"goLineLeft\", \"Cmd-Right\": \"goLineRight\", \"Alt-Backspace\": \"delGroupBefore\",\n    \"Ctrl-Alt-Backspace\": \"delGroupAfter\", \"Alt-Delete\": \"delGroupAfter\", \"Cmd-S\": \"save\", \"Cmd-F\": \"find\",\n    \"Cmd-G\": \"findNext\", \"Shift-Cmd-G\": \"findPrev\", \"Cmd-Alt-F\": \"replace\", \"Shift-Cmd-Alt-F\": \"replaceAll\",\n    \"Cmd-[\": \"indentLess\", \"Cmd-]\": \"indentMore\", \"Cmd-Backspace\": \"delWrappedLineLeft\", \"Cmd-Delete\": \"delWrappedLineRight\",\n    \"Cmd-U\": \"undoSelection\", \"Shift-Cmd-U\": \"redoSelection\", \"Ctrl-Up\": \"goDocStart\", \"Ctrl-Down\": \"goDocEnd\",\n    fallthrough: [\"basic\", \"emacsy\"]\n  };\n  keyMap[\"default\"] = mac ? keyMap.macDefault : keyMap.pcDefault;\n\n  // KEYMAP DISPATCH\n\n  function normalizeKeyName(name) {\n    var parts = name.split(/-(?!$)/), name = parts[parts.length - 1];\n    var alt, ctrl, shift, cmd;\n    for (var i = 0; i < parts.length - 1; i++) {\n      var mod = parts[i];\n      if (/^(cmd|meta|m)$/i.test(mod)) cmd = true;\n      else if (/^a(lt)?$/i.test(mod)) alt = true;\n      else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true;\n      else if (/^s(hift)$/i.test(mod)) shift = true;\n      else throw new Error(\"Unrecognized modifier name: \" + mod);\n    }\n    if (alt) name = \"Alt-\" + name;\n    if (ctrl) name = \"Ctrl-\" + name;\n    if (cmd) name = \"Cmd-\" + name;\n    if (shift) name = \"Shift-\" + name;\n    return name;\n  }\n\n  // This is a kludge to keep keymaps mostly working as raw objects\n  // (backwards compatibility) while at the same time support features\n  // like normalization and multi-stroke key bindings. It compiles a\n  // new normalized keymap, and then updates the old object to reflect\n  // this.\n  CodeMirror.normalizeKeyMap = function(keymap) {\n    var copy = {};\n    for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) {\n      var value = keymap[keyname];\n      if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue;\n      if (value == \"...\") { delete keymap[keyname]; continue; }\n\n      var keys = map(keyname.split(\" \"), normalizeKeyName);\n      for (var i = 0; i < keys.length; i++) {\n        var val, name;\n        if (i == keys.length - 1) {\n          name = keys.join(\" \");\n          val = value;\n        } else {\n          name = keys.slice(0, i + 1).join(\" \");\n          val = \"...\";\n        }\n        var prev = copy[name];\n        if (!prev) copy[name] = val;\n        else if (prev != val) throw new Error(\"Inconsistent bindings for \" + name);\n      }\n      delete keymap[keyname];\n    }\n    for (var prop in copy) keymap[prop] = copy[prop];\n    return keymap;\n  };\n\n  var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) {\n    map = getKeyMap(map);\n    var found = map.call ? map.call(key, context) : map[key];\n    if (found === false) return \"nothing\";\n    if (found === \"...\") return \"multi\";\n    if (found != null && handle(found)) return \"handled\";\n\n    if (map.fallthrough) {\n      if (Object.prototype.toString.call(map.fallthrough) != \"[object Array]\")\n        return lookupKey(key, map.fallthrough, handle, context);\n      for (var i = 0; i < map.fallthrough.length; i++) {\n        var result = lookupKey(key, map.fallthrough[i], handle, context);\n        if (result) return result;\n      }\n    }\n  };\n\n  // Modifier key presses don't count as 'real' key presses for the\n  // purpose of keymap fallthrough.\n  var isModifierKey = CodeMirror.isModifierKey = function(value) {\n    var name = typeof value == \"string\" ? value : keyNames[value.keyCode];\n    return name == \"Ctrl\" || name == \"Alt\" || name == \"Shift\" || name == \"Mod\";\n  };\n\n  // Look up the name of a key as indicated by an event object.\n  var keyName = CodeMirror.keyName = function(event, noShift) {\n    if (presto && event.keyCode == 34 && event[\"char\"]) return false;\n    var base = keyNames[event.keyCode], name = base;\n    if (name == null || event.altGraphKey) return false;\n    if (event.altKey && base != \"Alt\") name = \"Alt-\" + name;\n    if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != \"Ctrl\") name = \"Ctrl-\" + name;\n    if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != \"Cmd\") name = \"Cmd-\" + name;\n    if (!noShift && event.shiftKey && base != \"Shift\") name = \"Shift-\" + name;\n    return name;\n  };\n\n  function getKeyMap(val) {\n    return typeof val == \"string\" ? keyMap[val] : val;\n  }\n\n  // FROMTEXTAREA\n\n  CodeMirror.fromTextArea = function(textarea, options) {\n    options = options ? copyObj(options) : {};\n    options.value = textarea.value;\n    if (!options.tabindex && textarea.tabIndex)\n      options.tabindex = textarea.tabIndex;\n    if (!options.placeholder && textarea.placeholder)\n      options.placeholder = textarea.placeholder;\n    // Set autofocus to true if this textarea is focused, or if it has\n    // autofocus and no other element is focused.\n    if (options.autofocus == null) {\n      var hasFocus = activeElt();\n      options.autofocus = hasFocus == textarea ||\n        textarea.getAttribute(\"autofocus\") != null && hasFocus == document.body;\n    }\n\n    function save() {textarea.value = cm.getValue();}\n    if (textarea.form) {\n      on(textarea.form, \"submit\", save);\n      // Deplorable hack to make the submit method do the right thing.\n      if (!options.leaveSubmitMethodAlone) {\n        var form = textarea.form, realSubmit = form.submit;\n        try {\n          var wrappedSubmit = form.submit = function() {\n            save();\n            form.submit = realSubmit;\n            form.submit();\n            form.submit = wrappedSubmit;\n          };\n        } catch(e) {}\n      }\n    }\n\n    options.finishInit = function(cm) {\n      cm.save = save;\n      cm.getTextArea = function() { return textarea; };\n      cm.toTextArea = function() {\n        cm.toTextArea = isNaN; // Prevent this from being ran twice\n        save();\n        textarea.parentNode.removeChild(cm.getWrapperElement());\n        textarea.style.display = \"\";\n        if (textarea.form) {\n          off(textarea.form, \"submit\", save);\n          if (typeof textarea.form.submit == \"function\")\n            textarea.form.submit = realSubmit;\n        }\n      };\n    };\n\n    textarea.style.display = \"none\";\n    var cm = CodeMirror(function(node) {\n      textarea.parentNode.insertBefore(node, textarea.nextSibling);\n    }, options);\n    return cm;\n  };\n\n  // STRING STREAM\n\n  // Fed to the mode parsers, provides helper functions to make\n  // parsers more succinct.\n\n  var StringStream = CodeMirror.StringStream = function(string, tabSize) {\n    this.pos = this.start = 0;\n    this.string = string;\n    this.tabSize = tabSize || 8;\n    this.lastColumnPos = this.lastColumnValue = 0;\n    this.lineStart = 0;\n  };\n\n  StringStream.prototype = {\n    eol: function() {return this.pos >= this.string.length;},\n    sol: function() {return this.pos == this.lineStart;},\n    peek: function() {return this.string.charAt(this.pos) || undefined;},\n    next: function() {\n      if (this.pos < this.string.length)\n        return this.string.charAt(this.pos++);\n    },\n    eat: function(match) {\n      var ch = this.string.charAt(this.pos);\n      if (typeof match == \"string\") var ok = ch == match;\n      else var ok = ch && (match.test ? match.test(ch) : match(ch));\n      if (ok) {++this.pos; return ch;}\n    },\n    eatWhile: function(match) {\n      var start = this.pos;\n      while (this.eat(match)){}\n      return this.pos > start;\n    },\n    eatSpace: function() {\n      var start = this.pos;\n      while (/[\\s\\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;\n      return this.pos > start;\n    },\n    skipToEnd: function() {this.pos = this.string.length;},\n    skipTo: function(ch) {\n      var found = this.string.indexOf(ch, this.pos);\n      if (found > -1) {this.pos = found; return true;}\n    },\n    backUp: function(n) {this.pos -= n;},\n    column: function() {\n      if (this.lastColumnPos < this.start) {\n        this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);\n        this.lastColumnPos = this.start;\n      }\n      return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);\n    },\n    indentation: function() {\n      return countColumn(this.string, null, this.tabSize) -\n        (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);\n    },\n    match: function(pattern, consume, caseInsensitive) {\n      if (typeof pattern == \"string\") {\n        var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};\n        var substr = this.string.substr(this.pos, pattern.length);\n        if (cased(substr) == cased(pattern)) {\n          if (consume !== false) this.pos += pattern.length;\n          return true;\n        }\n      } else {\n        var match = this.string.slice(this.pos).match(pattern);\n        if (match && match.index > 0) return null;\n        if (match && consume !== false) this.pos += match[0].length;\n        return match;\n      }\n    },\n    current: function(){return this.string.slice(this.start, this.pos);},\n    hideFirstChars: function(n, inner) {\n      this.lineStart += n;\n      try { return inner(); }\n      finally { this.lineStart -= n; }\n    }\n  };\n\n  // TEXTMARKERS\n\n  // Created with markText and setBookmark methods. A TextMarker is a\n  // handle that can be used to clear or find a marked position in the\n  // document. Line objects hold arrays (markedSpans) containing\n  // {from, to, marker} object pointing to such marker objects, and\n  // indicating that such a marker is present on that line. Multiple\n  // lines may point to the same marker when it spans across lines.\n  // The spans will have null for their from/to properties when the\n  // marker continues beyond the start/end of the line. Markers have\n  // links back to the lines they currently touch.\n\n  var nextMarkerId = 0;\n\n  var TextMarker = CodeMirror.TextMarker = function(doc, type) {\n    this.lines = [];\n    this.type = type;\n    this.doc = doc;\n    this.id = ++nextMarkerId;\n  };\n  eventMixin(TextMarker);\n\n  // Clear the marker.\n  TextMarker.prototype.clear = function() {\n    if (this.explicitlyCleared) return;\n    var cm = this.doc.cm, withOp = cm && !cm.curOp;\n    if (withOp) startOperation(cm);\n    if (hasHandler(this, \"clear\")) {\n      var found = this.find();\n      if (found) signalLater(this, \"clear\", found.from, found.to);\n    }\n    var min = null, max = null;\n    for (var i = 0; i < this.lines.length; ++i) {\n      var line = this.lines[i];\n      var span = getMarkedSpanFor(line.markedSpans, this);\n      if (cm && !this.collapsed) regLineChange(cm, lineNo(line), \"text\");\n      else if (cm) {\n        if (span.to != null) max = lineNo(line);\n        if (span.from != null) min = lineNo(line);\n      }\n      line.markedSpans = removeMarkedSpan(line.markedSpans, span);\n      if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)\n        updateLineHeight(line, textHeight(cm.display));\n    }\n    if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {\n      var visual = visualLine(this.lines[i]), len = lineLength(visual);\n      if (len > cm.display.maxLineLength) {\n        cm.display.maxLine = visual;\n        cm.display.maxLineLength = len;\n        cm.display.maxLineChanged = true;\n      }\n    }\n\n    if (min != null && cm && this.collapsed) regChange(cm, min, max + 1);\n    this.lines.length = 0;\n    this.explicitlyCleared = true;\n    if (this.atomic && this.doc.cantEdit) {\n      this.doc.cantEdit = false;\n      if (cm) reCheckSelection(cm.doc);\n    }\n    if (cm) signalLater(cm, \"markerCleared\", cm, this);\n    if (withOp) endOperation(cm);\n    if (this.parent) this.parent.clear();\n  };\n\n  // Find the position of the marker in the document. Returns a {from,\n  // to} object by default. Side can be passed to get a specific side\n  // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the\n  // Pos objects returned contain a line object, rather than a line\n  // number (used to prevent looking up the same line twice).\n  TextMarker.prototype.find = function(side, lineObj) {\n    if (side == null && this.type == \"bookmark\") side = 1;\n    var from, to;\n    for (var i = 0; i < this.lines.length; ++i) {\n      var line = this.lines[i];\n      var span = getMarkedSpanFor(line.markedSpans, this);\n      if (span.from != null) {\n        from = Pos(lineObj ? line : lineNo(line), span.from);\n        if (side == -1) return from;\n      }\n      if (span.to != null) {\n        to = Pos(lineObj ? line : lineNo(line), span.to);\n        if (side == 1) return to;\n      }\n    }\n    return from && {from: from, to: to};\n  };\n\n  // Signals that the marker's widget changed, and surrounding layout\n  // should be recomputed.\n  TextMarker.prototype.changed = function() {\n    var pos = this.find(-1, true), widget = this, cm = this.doc.cm;\n    if (!pos || !cm) return;\n    runInOp(cm, function() {\n      var line = pos.line, lineN = lineNo(pos.line);\n      var view = findViewForLine(cm, lineN);\n      if (view) {\n        clearLineMeasurementCacheFor(view);\n        cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;\n      }\n      cm.curOp.updateMaxLine = true;\n      if (!lineIsHidden(widget.doc, line) && widget.height != null) {\n        var oldHeight = widget.height;\n        widget.height = null;\n        var dHeight = widgetHeight(widget) - oldHeight;\n        if (dHeight)\n          updateLineHeight(line, line.height + dHeight);\n      }\n    });\n  };\n\n  TextMarker.prototype.attachLine = function(line) {\n    if (!this.lines.length && this.doc.cm) {\n      var op = this.doc.cm.curOp;\n      if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)\n        (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);\n    }\n    this.lines.push(line);\n  };\n  TextMarker.prototype.detachLine = function(line) {\n    this.lines.splice(indexOf(this.lines, line), 1);\n    if (!this.lines.length && this.doc.cm) {\n      var op = this.doc.cm.curOp;\n      (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);\n    }\n  };\n\n  // Collapsed markers have unique ids, in order to be able to order\n  // them, which is needed for uniquely determining an outer marker\n  // when they overlap (they may nest, but not partially overlap).\n  var nextMarkerId = 0;\n\n  // Create a marker, wire it up to the right lines, and\n  function markText(doc, from, to, options, type) {\n    // Shared markers (across linked documents) are handled separately\n    // (markTextShared will call out to this again, once per\n    // document).\n    if (options && options.shared) return markTextShared(doc, from, to, options, type);\n    // Ensure we are in an operation.\n    if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);\n\n    var marker = new TextMarker(doc, type), diff = cmp(from, to);\n    if (options) copyObj(options, marker, false);\n    // Don't connect empty markers unless clearWhenEmpty is false\n    if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)\n      return marker;\n    if (marker.replacedWith) {\n      // Showing up as a widget implies collapsed (widget replaces text)\n      marker.collapsed = true;\n      marker.widgetNode = elt(\"span\", [marker.replacedWith], \"CodeMirror-widget\");\n      if (!options.handleMouseEvents) marker.widgetNode.setAttribute(\"cm-ignore-events\", \"true\");\n      if (options.insertLeft) marker.widgetNode.insertLeft = true;\n    }\n    if (marker.collapsed) {\n      if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||\n          from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))\n        throw new Error(\"Inserting collapsed marker partially overlapping an existing one\");\n      sawCollapsedSpans = true;\n    }\n\n    if (marker.addToHistory)\n      addChangeToHistory(doc, {from: from, to: to, origin: \"markText\"}, doc.sel, NaN);\n\n    var curLine = from.line, cm = doc.cm, updateMaxLine;\n    doc.iter(curLine, to.line + 1, function(line) {\n      if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)\n        updateMaxLine = true;\n      if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);\n      addMarkedSpan(line, new MarkedSpan(marker,\n                                         curLine == from.line ? from.ch : null,\n                                         curLine == to.line ? to.ch : null));\n      ++curLine;\n    });\n    // lineIsHidden depends on the presence of the spans, so needs a second pass\n    if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {\n      if (lineIsHidden(doc, line)) updateLineHeight(line, 0);\n    });\n\n    if (marker.clearOnEnter) on(marker, \"beforeCursorEnter\", function() { marker.clear(); });\n\n    if (marker.readOnly) {\n      sawReadOnlySpans = true;\n      if (doc.history.done.length || doc.history.undone.length)\n        doc.clearHistory();\n    }\n    if (marker.collapsed) {\n      marker.id = ++nextMarkerId;\n      marker.atomic = true;\n    }\n    if (cm) {\n      // Sync editor state\n      if (updateMaxLine) cm.curOp.updateMaxLine = true;\n      if (marker.collapsed)\n        regChange(cm, from.line, to.line + 1);\n      else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)\n        for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, \"text\");\n      if (marker.atomic) reCheckSelection(cm.doc);\n      signalLater(cm, \"markerAdded\", cm, marker);\n    }\n    return marker;\n  }\n\n  // SHARED TEXTMARKERS\n\n  // A shared marker spans multiple linked documents. It is\n  // implemented as a meta-marker-object controlling multiple normal\n  // markers.\n  var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) {\n    this.markers = markers;\n    this.primary = primary;\n    for (var i = 0; i < markers.length; ++i)\n      markers[i].parent = this;\n  };\n  eventMixin(SharedTextMarker);\n\n  SharedTextMarker.prototype.clear = function() {\n    if (this.explicitlyCleared) return;\n    this.explicitlyCleared = true;\n    for (var i = 0; i < this.markers.length; ++i)\n      this.markers[i].clear();\n    signalLater(this, \"clear\");\n  };\n  SharedTextMarker.prototype.find = function(side, lineObj) {\n    return this.primary.find(side, lineObj);\n  };\n\n  function markTextShared(doc, from, to, options, type) {\n    options = copyObj(options);\n    options.shared = false;\n    var markers = [markText(doc, from, to, options, type)], primary = markers[0];\n    var widget = options.widgetNode;\n    linkedDocs(doc, function(doc) {\n      if (widget) options.widgetNode = widget.cloneNode(true);\n      markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));\n      for (var i = 0; i < doc.linked.length; ++i)\n        if (doc.linked[i].isParent) return;\n      primary = lst(markers);\n    });\n    return new SharedTextMarker(markers, primary);\n  }\n\n  function findSharedMarkers(doc) {\n    return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())),\n                         function(m) { return m.parent; });\n  }\n\n  function copySharedMarkers(doc, markers) {\n    for (var i = 0; i < markers.length; i++) {\n      var marker = markers[i], pos = marker.find();\n      var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);\n      if (cmp(mFrom, mTo)) {\n        var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);\n        marker.markers.push(subMark);\n        subMark.parent = marker;\n      }\n    }\n  }\n\n  function detachSharedMarkers(markers) {\n    for (var i = 0; i < markers.length; i++) {\n      var marker = markers[i], linked = [marker.primary.doc];;\n      linkedDocs(marker.primary.doc, function(d) { linked.push(d); });\n      for (var j = 0; j < marker.markers.length; j++) {\n        var subMarker = marker.markers[j];\n        if (indexOf(linked, subMarker.doc) == -1) {\n          subMarker.parent = null;\n          marker.markers.splice(j--, 1);\n        }\n      }\n    }\n  }\n\n  // TEXTMARKER SPANS\n\n  function MarkedSpan(marker, from, to) {\n    this.marker = marker;\n    this.from = from; this.to = to;\n  }\n\n  // Search an array of spans for a span matching the given marker.\n  function getMarkedSpanFor(spans, marker) {\n    if (spans) for (var i = 0; i < spans.length; ++i) {\n      var span = spans[i];\n      if (span.marker == marker) return span;\n    }\n  }\n  // Remove a span from an array, returning undefined if no spans are\n  // left (we don't store arrays for lines without spans).\n  function removeMarkedSpan(spans, span) {\n    for (var r, i = 0; i < spans.length; ++i)\n      if (spans[i] != span) (r || (r = [])).push(spans[i]);\n    return r;\n  }\n  // Add a span to a line.\n  function addMarkedSpan(line, span) {\n    line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];\n    span.marker.attachLine(line);\n  }\n\n  // Used for the algorithm that adjusts markers for a change in the\n  // document. These functions cut an array of spans at a given\n  // character position, returning an array of remaining chunks (or\n  // undefined if nothing remains).\n  function markedSpansBefore(old, startCh, isInsert) {\n    if (old) for (var i = 0, nw; i < old.length; ++i) {\n      var span = old[i], marker = span.marker;\n      var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);\n      if (startsBefore || span.from == startCh && marker.type == \"bookmark\" && (!isInsert || !span.marker.insertLeft)) {\n        var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);\n        (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));\n      }\n    }\n    return nw;\n  }\n  function markedSpansAfter(old, endCh, isInsert) {\n    if (old) for (var i = 0, nw; i < old.length; ++i) {\n      var span = old[i], marker = span.marker;\n      var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);\n      if (endsAfter || span.from == endCh && marker.type == \"bookmark\" && (!isInsert || span.marker.insertLeft)) {\n        var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);\n        (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,\n                                              span.to == null ? null : span.to - endCh));\n      }\n    }\n    return nw;\n  }\n\n  // Given a change object, compute the new set of marker spans that\n  // cover the line in which the change took place. Removes spans\n  // entirely within the change, reconnects spans belonging to the\n  // same marker that appear on both sides of the change, and cuts off\n  // spans partially within the change. Returns an array of span\n  // arrays with one element for each line in (after) the change.\n  function stretchSpansOverChange(doc, change) {\n    if (change.full) return null;\n    var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;\n    var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;\n    if (!oldFirst && !oldLast) return null;\n\n    var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;\n    // Get the spans that 'stick out' on both sides\n    var first = markedSpansBefore(oldFirst, startCh, isInsert);\n    var last = markedSpansAfter(oldLast, endCh, isInsert);\n\n    // Next, merge those two ends\n    var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);\n    if (first) {\n      // Fix up .to properties of first\n      for (var i = 0; i < first.length; ++i) {\n        var span = first[i];\n        if (span.to == null) {\n          var found = getMarkedSpanFor(last, span.marker);\n          if (!found) span.to = startCh;\n          else if (sameLine) span.to = found.to == null ? null : found.to + offset;\n        }\n      }\n    }\n    if (last) {\n      // Fix up .from in last (or move them into first in case of sameLine)\n      for (var i = 0; i < last.length; ++i) {\n        var span = last[i];\n        if (span.to != null) span.to += offset;\n        if (span.from == null) {\n          var found = getMarkedSpanFor(first, span.marker);\n          if (!found) {\n            span.from = offset;\n            if (sameLine) (first || (first = [])).push(span);\n          }\n        } else {\n          span.from += offset;\n          if (sameLine) (first || (first = [])).push(span);\n        }\n      }\n    }\n    // Make sure we didn't create any zero-length spans\n    if (first) first = clearEmptySpans(first);\n    if (last && last != first) last = clearEmptySpans(last);\n\n    var newMarkers = [first];\n    if (!sameLine) {\n      // Fill gap with whole-line-spans\n      var gap = change.text.length - 2, gapMarkers;\n      if (gap > 0 && first)\n        for (var i = 0; i < first.length; ++i)\n          if (first[i].to == null)\n            (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null));\n      for (var i = 0; i < gap; ++i)\n        newMarkers.push(gapMarkers);\n      newMarkers.push(last);\n    }\n    return newMarkers;\n  }\n\n  // Remove spans that are empty and don't have a clearWhenEmpty\n  // option of false.\n  function clearEmptySpans(spans) {\n    for (var i = 0; i < spans.length; ++i) {\n      var span = spans[i];\n      if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)\n        spans.splice(i--, 1);\n    }\n    if (!spans.length) return null;\n    return spans;\n  }\n\n  // Used for un/re-doing changes from the history. Combines the\n  // result of computing the existing spans with the set of spans that\n  // existed in the history (so that deleting around a span and then\n  // undoing brings back the span).\n  function mergeOldSpans(doc, change) {\n    var old = getOldSpans(doc, change);\n    var stretched = stretchSpansOverChange(doc, change);\n    if (!old) return stretched;\n    if (!stretched) return old;\n\n    for (var i = 0; i < old.length; ++i) {\n      var oldCur = old[i], stretchCur = stretched[i];\n      if (oldCur && stretchCur) {\n        spans: for (var j = 0; j < stretchCur.length; ++j) {\n          var span = stretchCur[j];\n          for (var k = 0; k < oldCur.length; ++k)\n            if (oldCur[k].marker == span.marker) continue spans;\n          oldCur.push(span);\n        }\n      } else if (stretchCur) {\n        old[i] = stretchCur;\n      }\n    }\n    return old;\n  }\n\n  // Used to 'clip' out readOnly ranges when making a change.\n  function removeReadOnlyRanges(doc, from, to) {\n    var markers = null;\n    doc.iter(from.line, to.line + 1, function(line) {\n      if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {\n        var mark = line.markedSpans[i].marker;\n        if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))\n          (markers || (markers = [])).push(mark);\n      }\n    });\n    if (!markers) return null;\n    var parts = [{from: from, to: to}];\n    for (var i = 0; i < markers.length; ++i) {\n      var mk = markers[i], m = mk.find(0);\n      for (var j = 0; j < parts.length; ++j) {\n        var p = parts[j];\n        if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue;\n        var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);\n        if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)\n          newParts.push({from: p.from, to: m.from});\n        if (dto > 0 || !mk.inclusiveRight && !dto)\n          newParts.push({from: m.to, to: p.to});\n        parts.splice.apply(parts, newParts);\n        j += newParts.length - 1;\n      }\n    }\n    return parts;\n  }\n\n  // Connect or disconnect spans from a line.\n  function detachMarkedSpans(line) {\n    var spans = line.markedSpans;\n    if (!spans) return;\n    for (var i = 0; i < spans.length; ++i)\n      spans[i].marker.detachLine(line);\n    line.markedSpans = null;\n  }\n  function attachMarkedSpans(line, spans) {\n    if (!spans) return;\n    for (var i = 0; i < spans.length; ++i)\n      spans[i].marker.attachLine(line);\n    line.markedSpans = spans;\n  }\n\n  // Helpers used when computing which overlapping collapsed span\n  // counts as the larger one.\n  function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }\n  function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }\n\n  // Returns a number indicating which of two overlapping collapsed\n  // spans is larger (and thus includes the other). Falls back to\n  // comparing ids when the spans cover exactly the same range.\n  function compareCollapsedMarkers(a, b) {\n    var lenDiff = a.lines.length - b.lines.length;\n    if (lenDiff != 0) return lenDiff;\n    var aPos = a.find(), bPos = b.find();\n    var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);\n    if (fromCmp) return -fromCmp;\n    var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);\n    if (toCmp) return toCmp;\n    return b.id - a.id;\n  }\n\n  // Find out whether a line ends or starts in a collapsed span. If\n  // so, return the marker for that span.\n  function collapsedSpanAtSide(line, start) {\n    var sps = sawCollapsedSpans && line.markedSpans, found;\n    if (sps) for (var sp, i = 0; i < sps.length; ++i) {\n      sp = sps[i];\n      if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&\n          (!found || compareCollapsedMarkers(found, sp.marker) < 0))\n        found = sp.marker;\n    }\n    return found;\n  }\n  function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }\n  function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }\n\n  // Test whether there exists a collapsed span that partially\n  // overlaps (covers the start or end, but not both) of a new span.\n  // Such overlap is not allowed.\n  function conflictingCollapsedRange(doc, lineNo, from, to, marker) {\n    var line = getLine(doc, lineNo);\n    var sps = sawCollapsedSpans && line.markedSpans;\n    if (sps) for (var i = 0; i < sps.length; ++i) {\n      var sp = sps[i];\n      if (!sp.marker.collapsed) continue;\n      var found = sp.marker.find(0);\n      var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);\n      var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);\n      if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;\n      if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||\n          fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))\n        return true;\n    }\n  }\n\n  // A visual line is a line as drawn on the screen. Folding, for\n  // example, can cause multiple logical lines to appear on the same\n  // visual line. This finds the start of the visual line that the\n  // given line is part of (usually that is the line itself).\n  function visualLine(line) {\n    var merged;\n    while (merged = collapsedSpanAtStart(line))\n      line = merged.find(-1, true).line;\n    return line;\n  }\n\n  // Returns an array of logical lines that continue the visual line\n  // started by the argument, or undefined if there are no such lines.\n  function visualLineContinued(line) {\n    var merged, lines;\n    while (merged = collapsedSpanAtEnd(line)) {\n      line = merged.find(1, true).line;\n      (lines || (lines = [])).push(line);\n    }\n    return lines;\n  }\n\n  // Get the line number of the start of the visual line that the\n  // given line number is part of.\n  function visualLineNo(doc, lineN) {\n    var line = getLine(doc, lineN), vis = visualLine(line);\n    if (line == vis) return lineN;\n    return lineNo(vis);\n  }\n  // Get the line number of the start of the next visual line after\n  // the given line.\n  function visualLineEndNo(doc, lineN) {\n    if (lineN > doc.lastLine()) return lineN;\n    var line = getLine(doc, lineN), merged;\n    if (!lineIsHidden(doc, line)) return lineN;\n    while (merged = collapsedSpanAtEnd(line))\n      line = merged.find(1, true).line;\n    return lineNo(line) + 1;\n  }\n\n  // Compute whether a line is hidden. Lines count as hidden when they\n  // are part of a visual line that starts with another line, or when\n  // they are entirely covered by collapsed, non-widget span.\n  function lineIsHidden(doc, line) {\n    var sps = sawCollapsedSpans && line.markedSpans;\n    if (sps) for (var sp, i = 0; i < sps.length; ++i) {\n      sp = sps[i];\n      if (!sp.marker.collapsed) continue;\n      if (sp.from == null) return true;\n      if (sp.marker.widgetNode) continue;\n      if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))\n        return true;\n    }\n  }\n  function lineIsHiddenInner(doc, line, span) {\n    if (span.to == null) {\n      var end = span.marker.find(1, true);\n      return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker));\n    }\n    if (span.marker.inclusiveRight && span.to == line.text.length)\n      return true;\n    for (var sp, i = 0; i < line.markedSpans.length; ++i) {\n      sp = line.markedSpans[i];\n      if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&\n          (sp.to == null || sp.to != span.from) &&\n          (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&\n          lineIsHiddenInner(doc, line, sp)) return true;\n    }\n  }\n\n  // LINE WIDGETS\n\n  // Line widgets are block elements displayed above or below a line.\n\n  var LineWidget = CodeMirror.LineWidget = function(doc, node, options) {\n    if (options) for (var opt in options) if (options.hasOwnProperty(opt))\n      this[opt] = options[opt];\n    this.doc = doc;\n    this.node = node;\n  };\n  eventMixin(LineWidget);\n\n  function adjustScrollWhenAboveVisible(cm, line, diff) {\n    if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))\n      addToScrollPos(cm, null, diff);\n  }\n\n  LineWidget.prototype.clear = function() {\n    var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);\n    if (no == null || !ws) return;\n    for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);\n    if (!ws.length) line.widgets = null;\n    var height = widgetHeight(this);\n    updateLineHeight(line, Math.max(0, line.height - height));\n    if (cm) runInOp(cm, function() {\n      adjustScrollWhenAboveVisible(cm, line, -height);\n      regLineChange(cm, no, \"widget\");\n    });\n  };\n  LineWidget.prototype.changed = function() {\n    var oldH = this.height, cm = this.doc.cm, line = this.line;\n    this.height = null;\n    var diff = widgetHeight(this) - oldH;\n    if (!diff) return;\n    updateLineHeight(line, line.height + diff);\n    if (cm) runInOp(cm, function() {\n      cm.curOp.forceUpdate = true;\n      adjustScrollWhenAboveVisible(cm, line, diff);\n    });\n  };\n\n  function widgetHeight(widget) {\n    if (widget.height != null) return widget.height;\n    var cm = widget.doc.cm;\n    if (!cm) return 0;\n    if (!contains(document.body, widget.node)) {\n      var parentStyle = \"position: relative;\";\n      if (widget.coverGutter)\n        parentStyle += \"margin-left: -\" + cm.display.gutters.offsetWidth + \"px;\";\n      if (widget.noHScroll)\n        parentStyle += \"width: \" + cm.display.wrapper.clientWidth + \"px;\";\n      removeChildrenAndAdd(cm.display.measure, elt(\"div\", [widget.node], null, parentStyle));\n    }\n    return widget.height = widget.node.parentNode.offsetHeight;\n  }\n\n  function addLineWidget(doc, handle, node, options) {\n    var widget = new LineWidget(doc, node, options);\n    var cm = doc.cm;\n    if (cm && widget.noHScroll) cm.display.alignWidgets = true;\n    changeLine(doc, handle, \"widget\", function(line) {\n      var widgets = line.widgets || (line.widgets = []);\n      if (widget.insertAt == null) widgets.push(widget);\n      else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);\n      widget.line = line;\n      if (cm && !lineIsHidden(doc, line)) {\n        var aboveVisible = heightAtLine(line) < doc.scrollTop;\n        updateLineHeight(line, line.height + widgetHeight(widget));\n        if (aboveVisible) addToScrollPos(cm, null, widget.height);\n        cm.curOp.forceUpdate = true;\n      }\n      return true;\n    });\n    return widget;\n  }\n\n  // LINE DATA STRUCTURE\n\n  // Line objects. These hold state related to a line, including\n  // highlighting info (the styles array).\n  var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) {\n    this.text = text;\n    attachMarkedSpans(this, markedSpans);\n    this.height = estimateHeight ? estimateHeight(this) : 1;\n  };\n  eventMixin(Line);\n  Line.prototype.lineNo = function() { return lineNo(this); };\n\n  // Change the content (text, markers) of a line. Automatically\n  // invalidates cached information and tries to re-estimate the\n  // line's height.\n  function updateLine(line, text, markedSpans, estimateHeight) {\n    line.text = text;\n    if (line.stateAfter) line.stateAfter = null;\n    if (line.styles) line.styles = null;\n    if (line.order != null) line.order = null;\n    detachMarkedSpans(line);\n    attachMarkedSpans(line, markedSpans);\n    var estHeight = estimateHeight ? estimateHeight(line) : 1;\n    if (estHeight != line.height) updateLineHeight(line, estHeight);\n  }\n\n  // Detach a line from the document tree and its markers.\n  function cleanUpLine(line) {\n    line.parent = null;\n    detachMarkedSpans(line);\n  }\n\n  function extractLineClasses(type, output) {\n    if (type) for (;;) {\n      var lineClass = type.match(/(?:^|\\s+)line-(background-)?(\\S+)/);\n      if (!lineClass) break;\n      type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);\n      var prop = lineClass[1] ? \"bgClass\" : \"textClass\";\n      if (output[prop] == null)\n        output[prop] = lineClass[2];\n      else if (!(new RegExp(\"(?:^|\\s)\" + lineClass[2] + \"(?:$|\\s)\")).test(output[prop]))\n        output[prop] += \" \" + lineClass[2];\n    }\n    return type;\n  }\n\n  function callBlankLine(mode, state) {\n    if (mode.blankLine) return mode.blankLine(state);\n    if (!mode.innerMode) return;\n    var inner = CodeMirror.innerMode(mode, state);\n    if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);\n  }\n\n  function readToken(mode, stream, state, inner) {\n    for (var i = 0; i < 10; i++) {\n      if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode;\n      var style = mode.token(stream, state);\n      if (stream.pos > stream.start) return style;\n    }\n    throw new Error(\"Mode \" + mode.name + \" failed to advance stream.\");\n  }\n\n  // Utility for getTokenAt and getLineTokens\n  function takeToken(cm, pos, precise, asArray) {\n    function getObj(copy) {\n      return {start: stream.start, end: stream.pos,\n              string: stream.current(),\n              type: style || null,\n              state: copy ? copyState(doc.mode, state) : state};\n    }\n\n    var doc = cm.doc, mode = doc.mode, style;\n    pos = clipPos(doc, pos);\n    var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise);\n    var stream = new StringStream(line.text, cm.options.tabSize), tokens;\n    if (asArray) tokens = [];\n    while ((asArray || stream.pos < pos.ch) && !stream.eol()) {\n      stream.start = stream.pos;\n      style = readToken(mode, stream, state);\n      if (asArray) tokens.push(getObj(true));\n    }\n    return asArray ? tokens : getObj();\n  }\n\n  // Run the given mode's parser over a line, calling f for each token.\n  function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {\n    var flattenSpans = mode.flattenSpans;\n    if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;\n    var curStart = 0, curStyle = null;\n    var stream = new StringStream(text, cm.options.tabSize), style;\n    var inner = cm.options.addModeClass && [null];\n    if (text == \"\") extractLineClasses(callBlankLine(mode, state), lineClasses);\n    while (!stream.eol()) {\n      if (stream.pos > cm.options.maxHighlightLength) {\n        flattenSpans = false;\n        if (forceToEnd) processLine(cm, text, state, stream.pos);\n        stream.pos = text.length;\n        style = null;\n      } else {\n        style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses);\n      }\n      if (inner) {\n        var mName = inner[0].name;\n        if (mName) style = \"m-\" + (style ? mName + \" \" + style : mName);\n      }\n      if (!flattenSpans || curStyle != style) {\n        while (curStart < stream.start) {\n          curStart = Math.min(stream.start, curStart + 5000);\n          f(curStart, curStyle);\n        }\n        curStyle = style;\n      }\n      stream.start = stream.pos;\n    }\n    while (curStart < stream.pos) {\n      // Webkit seems to refuse to render text nodes longer than 57444\n      // characters, and returns inaccurate measurements in nodes\n      // starting around 5000 chars.\n      var pos = Math.min(stream.pos, curStart + 5000);\n      f(pos, curStyle);\n      curStart = pos;\n    }\n  }\n\n  // Compute a style array (an array starting with a mode generation\n  // -- for invalidation -- followed by pairs of end positions and\n  // style strings), which is used to highlight the tokens on the\n  // line.\n  function highlightLine(cm, line, state, forceToEnd) {\n    // A styles array always starts with a number identifying the\n    // mode/overlays that it is based on (for easy invalidation).\n    var st = [cm.state.modeGen], lineClasses = {};\n    // Compute the base array of styles\n    runMode(cm, line.text, cm.doc.mode, state, function(end, style) {\n      st.push(end, style);\n    }, lineClasses, forceToEnd);\n\n    // Run overlays, adjust style array.\n    for (var o = 0; o < cm.state.overlays.length; ++o) {\n      var overlay = cm.state.overlays[o], i = 1, at = 0;\n      runMode(cm, line.text, overlay.mode, true, function(end, style) {\n        var start = i;\n        // Ensure there's a token end at the current position, and that i points at it\n        while (at < end) {\n          var i_end = st[i];\n          if (i_end > end)\n            st.splice(i, 1, end, st[i+1], i_end);\n          i += 2;\n          at = Math.min(end, i_end);\n        }\n        if (!style) return;\n        if (overlay.opaque) {\n          st.splice(start, i - start, end, \"cm-overlay \" + style);\n          i = start + 2;\n        } else {\n          for (; start < i; start += 2) {\n            var cur = st[start+1];\n            st[start+1] = (cur ? cur + \" \" : \"\") + \"cm-overlay \" + style;\n          }\n        }\n      }, lineClasses);\n    }\n\n    return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};\n  }\n\n  function getLineStyles(cm, line, updateFrontier) {\n    if (!line.styles || line.styles[0] != cm.state.modeGen) {\n      var state = getStateBefore(cm, lineNo(line));\n      var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state);\n      line.stateAfter = state;\n      line.styles = result.styles;\n      if (result.classes) line.styleClasses = result.classes;\n      else if (line.styleClasses) line.styleClasses = null;\n      if (updateFrontier === cm.doc.frontier) cm.doc.frontier++;\n    }\n    return line.styles;\n  }\n\n  // Lightweight form of highlight -- proceed over this line and\n  // update state, but don't save a style array. Used for lines that\n  // aren't currently visible.\n  function processLine(cm, text, state, startAt) {\n    var mode = cm.doc.mode;\n    var stream = new StringStream(text, cm.options.tabSize);\n    stream.start = stream.pos = startAt || 0;\n    if (text == \"\") callBlankLine(mode, state);\n    while (!stream.eol()) {\n      readToken(mode, stream, state);\n      stream.start = stream.pos;\n    }\n  }\n\n  // Convert a style as returned by a mode (either null, or a string\n  // containing one or more styles) to a CSS style. This is cached,\n  // and also looks for line-wide styles.\n  var styleToClassCache = {}, styleToClassCacheWithMode = {};\n  function interpretTokenStyle(style, options) {\n    if (!style || /^\\s*$/.test(style)) return null;\n    var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;\n    return cache[style] ||\n      (cache[style] = style.replace(/\\S+/g, \"cm-$&\"));\n  }\n\n  // Render the DOM representation of the text of a line. Also builds\n  // up a 'line map', which points at the DOM nodes that represent\n  // specific stretches of text, and is used by the measuring code.\n  // The returned object contains the DOM node, this map, and\n  // information about line-wide styles that were set by the mode.\n  function buildLineContent(cm, lineView) {\n    // The padding-right forces the element to have a 'border', which\n    // is needed on Webkit to be able to get line-level bounding\n    // rectangles for it (in measureChar).\n    var content = elt(\"span\", null, null, webkit ? \"padding-right: .1px\" : null);\n    var builder = {pre: elt(\"pre\", [content], \"CodeMirror-line\"), content: content,\n                   col: 0, pos: 0, cm: cm,\n                   trailingSpace: false,\n                   splitSpaces: (ie || webkit) && cm.getOption(\"lineWrapping\")};\n    lineView.measure = {};\n\n    // Iterate over the logical lines that make up this visual line.\n    for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {\n      var line = i ? lineView.rest[i - 1] : lineView.line, order;\n      builder.pos = 0;\n      builder.addToken = buildToken;\n      // Optionally wire in some hacks into the token-rendering\n      // algorithm, to deal with browser quirks.\n      if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))\n        builder.addToken = buildTokenBadBidi(builder.addToken, order);\n      builder.map = [];\n      var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);\n      insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));\n      if (line.styleClasses) {\n        if (line.styleClasses.bgClass)\n          builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || \"\");\n        if (line.styleClasses.textClass)\n          builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || \"\");\n      }\n\n      // Ensure at least a single node is present, for measuring.\n      if (builder.map.length == 0)\n        builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure)));\n\n      // Store the map and a cache object for the current logical line\n      if (i == 0) {\n        lineView.measure.map = builder.map;\n        lineView.measure.cache = {};\n      } else {\n        (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map);\n        (lineView.measure.caches || (lineView.measure.caches = [])).push({});\n      }\n    }\n\n    // See issue #2901\n    if (webkit) {\n      var last = builder.content.lastChild\n      if (/\\bcm-tab\\b/.test(last.className) || (last.querySelector && last.querySelector(\".cm-tab\")))\n        builder.content.className = \"cm-tab-wrap-hack\";\n    }\n\n    signal(cm, \"renderLine\", cm, lineView.line, builder.pre);\n    if (builder.pre.className)\n      builder.textClass = joinClasses(builder.pre.className, builder.textClass || \"\");\n\n    return builder;\n  }\n\n  function defaultSpecialCharPlaceholder(ch) {\n    var token = elt(\"span\", \"\\u2022\", \"cm-invalidchar\");\n    token.title = \"\\\\u\" + ch.charCodeAt(0).toString(16);\n    token.setAttribute(\"aria-label\", token.title);\n    return token;\n  }\n\n  // Build up the DOM representation for a single token, and add it to\n  // the line map. Takes care to render special characters separately.\n  function buildToken(builder, text, style, startStyle, endStyle, title, css) {\n    if (!text) return;\n    var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text\n    var special = builder.cm.state.specialChars, mustWrap = false;\n    if (!special.test(text)) {\n      builder.col += text.length;\n      var content = document.createTextNode(displayText);\n      builder.map.push(builder.pos, builder.pos + text.length, content);\n      if (ie && ie_version < 9) mustWrap = true;\n      builder.pos += text.length;\n    } else {\n      var content = document.createDocumentFragment(), pos = 0;\n      while (true) {\n        special.lastIndex = pos;\n        var m = special.exec(text);\n        var skipped = m ? m.index - pos : text.length - pos;\n        if (skipped) {\n          var txt = document.createTextNode(displayText.slice(pos, pos + skipped));\n          if (ie && ie_version < 9) content.appendChild(elt(\"span\", [txt]));\n          else content.appendChild(txt);\n          builder.map.push(builder.pos, builder.pos + skipped, txt);\n          builder.col += skipped;\n          builder.pos += skipped;\n        }\n        if (!m) break;\n        pos += skipped + 1;\n        if (m[0] == \"\\t\") {\n          var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;\n          var txt = content.appendChild(elt(\"span\", spaceStr(tabWidth), \"cm-tab\"));\n          txt.setAttribute(\"role\", \"presentation\");\n          txt.setAttribute(\"cm-text\", \"\\t\");\n          builder.col += tabWidth;\n        } else if (m[0] == \"\\r\" || m[0] == \"\\n\") {\n          var txt = content.appendChild(elt(\"span\", m[0] == \"\\r\" ? \"\\u240d\" : \"\\u2424\", \"cm-invalidchar\"));\n          txt.setAttribute(\"cm-text\", m[0]);\n          builder.col += 1;\n        } else {\n          var txt = builder.cm.options.specialCharPlaceholder(m[0]);\n          txt.setAttribute(\"cm-text\", m[0]);\n          if (ie && ie_version < 9) content.appendChild(elt(\"span\", [txt]));\n          else content.appendChild(txt);\n          builder.col += 1;\n        }\n        builder.map.push(builder.pos, builder.pos + 1, txt);\n        builder.pos++;\n      }\n    }\n    builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32\n    if (style || startStyle || endStyle || mustWrap || css) {\n      var fullStyle = style || \"\";\n      if (startStyle) fullStyle += startStyle;\n      if (endStyle) fullStyle += endStyle;\n      var token = elt(\"span\", [content], fullStyle, css);\n      if (title) token.title = title;\n      return builder.content.appendChild(token);\n    }\n    builder.content.appendChild(content);\n  }\n\n  function splitSpaces(text, trailingBefore) {\n    if (text.length > 1 && !/  /.test(text)) return text\n    var spaceBefore = trailingBefore, result = \"\"\n    for (var i = 0; i < text.length; i++) {\n      var ch = text.charAt(i)\n      if (ch == \" \" && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))\n        ch = \"\\u00a0\"\n      result += ch\n      spaceBefore = ch == \" \"\n    }\n    return result\n  }\n\n  // Work around nonsense dimensions being reported for stretches of\n  // right-to-left text.\n  function buildTokenBadBidi(inner, order) {\n    return function(builder, text, style, startStyle, endStyle, title, css) {\n      style = style ? style + \" cm-force-border\" : \"cm-force-border\";\n      var start = builder.pos, end = start + text.length;\n      for (;;) {\n        // Find the part that overlaps with the start of this text\n        for (var i = 0; i < order.length; i++) {\n          var part = order[i];\n          if (part.to > start && part.from <= start) break;\n        }\n        if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css);\n        inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);\n        startStyle = null;\n        text = text.slice(part.to - start);\n        start = part.to;\n      }\n    };\n  }\n\n  function buildCollapsedSpan(builder, size, marker, ignoreWidget) {\n    var widget = !ignoreWidget && marker.widgetNode;\n    if (widget) builder.map.push(builder.pos, builder.pos + size, widget);\n    if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {\n      if (!widget)\n        widget = builder.content.appendChild(document.createElement(\"span\"));\n      widget.setAttribute(\"cm-marker\", marker.id);\n    }\n    if (widget) {\n      builder.cm.display.input.setUneditable(widget);\n      builder.content.appendChild(widget);\n    }\n    builder.pos += size;\n    builder.trailingSpace = false\n  }\n\n  // Outputs a number of spans to make up a line, taking highlighting\n  // and marked text into account.\n  function insertLineContent(line, builder, styles) {\n    var spans = line.markedSpans, allText = line.text, at = 0;\n    if (!spans) {\n      for (var i = 1; i < styles.length; i+=2)\n        builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options));\n      return;\n    }\n\n    var len = allText.length, pos = 0, i = 1, text = \"\", style, css;\n    var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;\n    for (;;) {\n      if (nextChange == pos) { // Update current marker set\n        spanStyle = spanEndStyle = spanStartStyle = title = css = \"\";\n        collapsed = null; nextChange = Infinity;\n        var foundBookmarks = [], endStyles\n        for (var j = 0; j < spans.length; ++j) {\n          var sp = spans[j], m = sp.marker;\n          if (m.type == \"bookmark\" && sp.from == pos && m.widgetNode) {\n            foundBookmarks.push(m);\n          } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {\n            if (sp.to != null && sp.to != pos && nextChange > sp.to) {\n              nextChange = sp.to;\n              spanEndStyle = \"\";\n            }\n            if (m.className) spanStyle += \" \" + m.className;\n            if (m.css) css = (css ? css + \";\" : \"\") + m.css;\n            if (m.startStyle && sp.from == pos) spanStartStyle += \" \" + m.startStyle;\n            if (m.endStyle && sp.to == nextChange) (endStyles || (endStyles = [])).push(m.endStyle, sp.to)\n            if (m.title && !title) title = m.title;\n            if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))\n              collapsed = sp;\n          } else if (sp.from > pos && nextChange > sp.from) {\n            nextChange = sp.from;\n          }\n        }\n        if (endStyles) for (var j = 0; j < endStyles.length; j += 2)\n          if (endStyles[j + 1] == nextChange) spanEndStyle += \" \" + endStyles[j]\n\n        if (!collapsed || collapsed.from == pos) for (var j = 0; j < foundBookmarks.length; ++j)\n          buildCollapsedSpan(builder, 0, foundBookmarks[j]);\n        if (collapsed && (collapsed.from || 0) == pos) {\n          buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,\n                             collapsed.marker, collapsed.from == null);\n          if (collapsed.to == null) return;\n          if (collapsed.to == pos) collapsed = false;\n        }\n      }\n      if (pos >= len) break;\n\n      var upto = Math.min(len, nextChange);\n      while (true) {\n        if (text) {\n          var end = pos + text.length;\n          if (!collapsed) {\n            var tokenText = end > upto ? text.slice(0, upto - pos) : text;\n            builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,\n                             spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : \"\", title, css);\n          }\n          if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}\n          pos = end;\n          spanStartStyle = \"\";\n        }\n        text = allText.slice(at, at = styles[i++]);\n        style = interpretTokenStyle(styles[i++], builder.cm.options);\n      }\n    }\n  }\n\n  // DOCUMENT DATA STRUCTURE\n\n  // By default, updates that start and end at the beginning of a line\n  // are treated specially, in order to make the association of line\n  // widgets and marker elements with the text behave more intuitive.\n  function isWholeLineUpdate(doc, change) {\n    return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == \"\" &&\n      (!doc.cm || doc.cm.options.wholeLineUpdateBefore);\n  }\n\n  // Perform a change on the document data structure.\n  function updateDoc(doc, change, markedSpans, estimateHeight) {\n    function spansFor(n) {return markedSpans ? markedSpans[n] : null;}\n    function update(line, text, spans) {\n      updateLine(line, text, spans, estimateHeight);\n      signalLater(line, \"change\", line, change);\n    }\n    function linesFor(start, end) {\n      for (var i = start, result = []; i < end; ++i)\n        result.push(new Line(text[i], spansFor(i), estimateHeight));\n      return result;\n    }\n\n    var from = change.from, to = change.to, text = change.text;\n    var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);\n    var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;\n\n    // Adjust the line structure\n    if (change.full) {\n      doc.insert(0, linesFor(0, text.length));\n      doc.remove(text.length, doc.size - text.length);\n    } else if (isWholeLineUpdate(doc, change)) {\n      // This is a whole-line replace. Treated specially to make\n      // sure line objects move the way they are supposed to.\n      var added = linesFor(0, text.length - 1);\n      update(lastLine, lastLine.text, lastSpans);\n      if (nlines) doc.remove(from.line, nlines);\n      if (added.length) doc.insert(from.line, added);\n    } else if (firstLine == lastLine) {\n      if (text.length == 1) {\n        update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);\n      } else {\n        var added = linesFor(1, text.length - 1);\n        added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));\n        update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));\n        doc.insert(from.line + 1, added);\n      }\n    } else if (text.length == 1) {\n      update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));\n      doc.remove(from.line + 1, nlines);\n    } else {\n      update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));\n      update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);\n      var added = linesFor(1, text.length - 1);\n      if (nlines > 1) doc.remove(from.line + 1, nlines - 1);\n      doc.insert(from.line + 1, added);\n    }\n\n    signalLater(doc, \"change\", doc, change);\n  }\n\n  // The document is represented as a BTree consisting of leaves, with\n  // chunk of lines in them, and branches, with up to ten leaves or\n  // other branch nodes below them. The top node is always a branch\n  // node, and is the document object itself (meaning it has\n  // additional methods and properties).\n  //\n  // All nodes have parent links. The tree is used both to go from\n  // line numbers to line objects, and to go from objects to numbers.\n  // It also indexes by height, and is used to convert between height\n  // and line object, and to find the total height of the document.\n  //\n  // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html\n\n  function LeafChunk(lines) {\n    this.lines = lines;\n    this.parent = null;\n    for (var i = 0, height = 0; i < lines.length; ++i) {\n      lines[i].parent = this;\n      height += lines[i].height;\n    }\n    this.height = height;\n  }\n\n  LeafChunk.prototype = {\n    chunkSize: function() { return this.lines.length; },\n    // Remove the n lines at offset 'at'.\n    removeInner: function(at, n) {\n      for (var i = at, e = at + n; i < e; ++i) {\n        var line = this.lines[i];\n        this.height -= line.height;\n        cleanUpLine(line);\n        signalLater(line, \"delete\");\n      }\n      this.lines.splice(at, n);\n    },\n    // Helper used to collapse a small branch into a single leaf.\n    collapse: function(lines) {\n      lines.push.apply(lines, this.lines);\n    },\n    // Insert the given array of lines at offset 'at', count them as\n    // having the given height.\n    insertInner: function(at, lines, height) {\n      this.height += height;\n      this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));\n      for (var i = 0; i < lines.length; ++i) lines[i].parent = this;\n    },\n    // Used to iterate over a part of the tree.\n    iterN: function(at, n, op) {\n      for (var e = at + n; at < e; ++at)\n        if (op(this.lines[at])) return true;\n    }\n  };\n\n  function BranchChunk(children) {\n    this.children = children;\n    var size = 0, height = 0;\n    for (var i = 0; i < children.length; ++i) {\n      var ch = children[i];\n      size += ch.chunkSize(); height += ch.height;\n      ch.parent = this;\n    }\n    this.size = size;\n    this.height = height;\n    this.parent = null;\n  }\n\n  BranchChunk.prototype = {\n    chunkSize: function() { return this.size; },\n    removeInner: function(at, n) {\n      this.size -= n;\n      for (var i = 0; i < this.children.length; ++i) {\n        var child = this.children[i], sz = child.chunkSize();\n        if (at < sz) {\n          var rm = Math.min(n, sz - at), oldHeight = child.height;\n          child.removeInner(at, rm);\n          this.height -= oldHeight - child.height;\n          if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }\n          if ((n -= rm) == 0) break;\n          at = 0;\n        } else at -= sz;\n      }\n      // If the result is smaller than 25 lines, ensure that it is a\n      // single leaf node.\n      if (this.size - n < 25 &&\n          (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {\n        var lines = [];\n        this.collapse(lines);\n        this.children = [new LeafChunk(lines)];\n        this.children[0].parent = this;\n      }\n    },\n    collapse: function(lines) {\n      for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines);\n    },\n    insertInner: function(at, lines, height) {\n      this.size += lines.length;\n      this.height += height;\n      for (var i = 0; i < this.children.length; ++i) {\n        var child = this.children[i], sz = child.chunkSize();\n        if (at <= sz) {\n          child.insertInner(at, lines, height);\n          if (child.lines && child.lines.length > 50) {\n            // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.\n            // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.\n            var remaining = child.lines.length % 25 + 25\n            for (var pos = remaining; pos < child.lines.length;) {\n              var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));\n              child.height -= leaf.height;\n              this.children.splice(++i, 0, leaf);\n              leaf.parent = this;\n            }\n            child.lines = child.lines.slice(0, remaining);\n            this.maybeSpill();\n          }\n          break;\n        }\n        at -= sz;\n      }\n    },\n    // When a node has grown, check whether it should be split.\n    maybeSpill: function() {\n      if (this.children.length <= 10) return;\n      var me = this;\n      do {\n        var spilled = me.children.splice(me.children.length - 5, 5);\n        var sibling = new BranchChunk(spilled);\n        if (!me.parent) { // Become the parent node\n          var copy = new BranchChunk(me.children);\n          copy.parent = me;\n          me.children = [copy, sibling];\n          me = copy;\n       } else {\n          me.size -= sibling.size;\n          me.height -= sibling.height;\n          var myIndex = indexOf(me.parent.children, me);\n          me.parent.children.splice(myIndex + 1, 0, sibling);\n        }\n        sibling.parent = me.parent;\n      } while (me.children.length > 10);\n      me.parent.maybeSpill();\n    },\n    iterN: function(at, n, op) {\n      for (var i = 0; i < this.children.length; ++i) {\n        var child = this.children[i], sz = child.chunkSize();\n        if (at < sz) {\n          var used = Math.min(n, sz - at);\n          if (child.iterN(at, used, op)) return true;\n          if ((n -= used) == 0) break;\n          at = 0;\n        } else at -= sz;\n      }\n    }\n  };\n\n  var nextDocId = 0;\n  var Doc = CodeMirror.Doc = function(text, mode, firstLine, lineSep) {\n    if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep);\n    if (firstLine == null) firstLine = 0;\n\n    BranchChunk.call(this, [new LeafChunk([new Line(\"\", null)])]);\n    this.first = firstLine;\n    this.scrollTop = this.scrollLeft = 0;\n    this.cantEdit = false;\n    this.cleanGeneration = 1;\n    this.frontier = firstLine;\n    var start = Pos(firstLine, 0);\n    this.sel = simpleSelection(start);\n    this.history = new History(null);\n    this.id = ++nextDocId;\n    this.modeOption = mode;\n    this.lineSep = lineSep;\n    this.extend = false;\n\n    if (typeof text == \"string\") text = this.splitLines(text);\n    updateDoc(this, {from: start, to: start, text: text});\n    setSelection(this, simpleSelection(start), sel_dontScroll);\n  };\n\n  Doc.prototype = createObj(BranchChunk.prototype, {\n    constructor: Doc,\n    // Iterate over the document. Supports two forms -- with only one\n    // argument, it calls that for each line in the document. With\n    // three, it iterates over the range given by the first two (with\n    // the second being non-inclusive).\n    iter: function(from, to, op) {\n      if (op) this.iterN(from - this.first, to - from, op);\n      else this.iterN(this.first, this.first + this.size, from);\n    },\n\n    // Non-public interface for adding and removing lines.\n    insert: function(at, lines) {\n      var height = 0;\n      for (var i = 0; i < lines.length; ++i) height += lines[i].height;\n      this.insertInner(at - this.first, lines, height);\n    },\n    remove: function(at, n) { this.removeInner(at - this.first, n); },\n\n    // From here, the methods are part of the public interface. Most\n    // are also available from CodeMirror (editor) instances.\n\n    getValue: function(lineSep) {\n      var lines = getLines(this, this.first, this.first + this.size);\n      if (lineSep === false) return lines;\n      return lines.join(lineSep || this.lineSeparator());\n    },\n    setValue: docMethodOp(function(code) {\n      var top = Pos(this.first, 0), last = this.first + this.size - 1;\n      makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),\n                        text: this.splitLines(code), origin: \"setValue\", full: true}, true);\n      setSelection(this, simpleSelection(top));\n    }),\n    replaceRange: function(code, from, to, origin) {\n      from = clipPos(this, from);\n      to = to ? clipPos(this, to) : from;\n      replaceRange(this, code, from, to, origin);\n    },\n    getRange: function(from, to, lineSep) {\n      var lines = getBetween(this, clipPos(this, from), clipPos(this, to));\n      if (lineSep === false) return lines;\n      return lines.join(lineSep || this.lineSeparator());\n    },\n\n    getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},\n\n    getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);},\n    getLineNumber: function(line) {return lineNo(line);},\n\n    getLineHandleVisualStart: function(line) {\n      if (typeof line == \"number\") line = getLine(this, line);\n      return visualLine(line);\n    },\n\n    lineCount: function() {return this.size;},\n    firstLine: function() {return this.first;},\n    lastLine: function() {return this.first + this.size - 1;},\n\n    clipPos: function(pos) {return clipPos(this, pos);},\n\n    getCursor: function(start) {\n      var range = this.sel.primary(), pos;\n      if (start == null || start == \"head\") pos = range.head;\n      else if (start == \"anchor\") pos = range.anchor;\n      else if (start == \"end\" || start == \"to\" || start === false) pos = range.to();\n      else pos = range.from();\n      return pos;\n    },\n    listSelections: function() { return this.sel.ranges; },\n    somethingSelected: function() {return this.sel.somethingSelected();},\n\n    setCursor: docMethodOp(function(line, ch, options) {\n      setSimpleSelection(this, clipPos(this, typeof line == \"number\" ? Pos(line, ch || 0) : line), null, options);\n    }),\n    setSelection: docMethodOp(function(anchor, head, options) {\n      setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);\n    }),\n    extendSelection: docMethodOp(function(head, other, options) {\n      extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);\n    }),\n    extendSelections: docMethodOp(function(heads, options) {\n      extendSelections(this, clipPosArray(this, heads), options);\n    }),\n    extendSelectionsBy: docMethodOp(function(f, options) {\n      var heads = map(this.sel.ranges, f);\n      extendSelections(this, clipPosArray(this, heads), options);\n    }),\n    setSelections: docMethodOp(function(ranges, primary, options) {\n      if (!ranges.length) return;\n      for (var i = 0, out = []; i < ranges.length; i++)\n        out[i] = new Range(clipPos(this, ranges[i].anchor),\n                           clipPos(this, ranges[i].head));\n      if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex);\n      setSelection(this, normalizeSelection(out, primary), options);\n    }),\n    addSelection: docMethodOp(function(anchor, head, options) {\n      var ranges = this.sel.ranges.slice(0);\n      ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));\n      setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);\n    }),\n\n    getSelection: function(lineSep) {\n      var ranges = this.sel.ranges, lines;\n      for (var i = 0; i < ranges.length; i++) {\n        var sel = getBetween(this, ranges[i].from(), ranges[i].to());\n        lines = lines ? lines.concat(sel) : sel;\n      }\n      if (lineSep === false) return lines;\n      else return lines.join(lineSep || this.lineSeparator());\n    },\n    getSelections: function(lineSep) {\n      var parts = [], ranges = this.sel.ranges;\n      for (var i = 0; i < ranges.length; i++) {\n        var sel = getBetween(this, ranges[i].from(), ranges[i].to());\n        if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator());\n        parts[i] = sel;\n      }\n      return parts;\n    },\n    replaceSelection: function(code, collapse, origin) {\n      var dup = [];\n      for (var i = 0; i < this.sel.ranges.length; i++)\n        dup[i] = code;\n      this.replaceSelections(dup, collapse, origin || \"+input\");\n    },\n    replaceSelections: docMethodOp(function(code, collapse, origin) {\n      var changes = [], sel = this.sel;\n      for (var i = 0; i < sel.ranges.length; i++) {\n        var range = sel.ranges[i];\n        changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin};\n      }\n      var newSel = collapse && collapse != \"end\" && computeReplacedSel(this, changes, collapse);\n      for (var i = changes.length - 1; i >= 0; i--)\n        makeChange(this, changes[i]);\n      if (newSel) setSelectionReplaceHistory(this, newSel);\n      else if (this.cm) ensureCursorVisible(this.cm);\n    }),\n    undo: docMethodOp(function() {makeChangeFromHistory(this, \"undo\");}),\n    redo: docMethodOp(function() {makeChangeFromHistory(this, \"redo\");}),\n    undoSelection: docMethodOp(function() {makeChangeFromHistory(this, \"undo\", true);}),\n    redoSelection: docMethodOp(function() {makeChangeFromHistory(this, \"redo\", true);}),\n\n    setExtending: function(val) {this.extend = val;},\n    getExtending: function() {return this.extend;},\n\n    historySize: function() {\n      var hist = this.history, done = 0, undone = 0;\n      for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done;\n      for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone;\n      return {undo: done, redo: undone};\n    },\n    clearHistory: function() {this.history = new History(this.history.maxGeneration);},\n\n    markClean: function() {\n      this.cleanGeneration = this.changeGeneration(true);\n    },\n    changeGeneration: function(forceSplit) {\n      if (forceSplit)\n        this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null;\n      return this.history.generation;\n    },\n    isClean: function (gen) {\n      return this.history.generation == (gen || this.cleanGeneration);\n    },\n\n    getHistory: function() {\n      return {done: copyHistoryArray(this.history.done),\n              undone: copyHistoryArray(this.history.undone)};\n    },\n    setHistory: function(histData) {\n      var hist = this.history = new History(this.history.maxGeneration);\n      hist.done = copyHistoryArray(histData.done.slice(0), null, true);\n      hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);\n    },\n\n    addLineClass: docMethodOp(function(handle, where, cls) {\n      return changeLine(this, handle, where == \"gutter\" ? \"gutter\" : \"class\", function(line) {\n        var prop = where == \"text\" ? \"textClass\"\n                 : where == \"background\" ? \"bgClass\"\n                 : where == \"gutter\" ? \"gutterClass\" : \"wrapClass\";\n        if (!line[prop]) line[prop] = cls;\n        else if (classTest(cls).test(line[prop])) return false;\n        else line[prop] += \" \" + cls;\n        return true;\n      });\n    }),\n    removeLineClass: docMethodOp(function(handle, where, cls) {\n      return changeLine(this, handle, where == \"gutter\" ? \"gutter\" : \"class\", function(line) {\n        var prop = where == \"text\" ? \"textClass\"\n                 : where == \"background\" ? \"bgClass\"\n                 : where == \"gutter\" ? \"gutterClass\" : \"wrapClass\";\n        var cur = line[prop];\n        if (!cur) return false;\n        else if (cls == null) line[prop] = null;\n        else {\n          var found = cur.match(classTest(cls));\n          if (!found) return false;\n          var end = found.index + found[0].length;\n          line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? \"\" : \" \") + cur.slice(end) || null;\n        }\n        return true;\n      });\n    }),\n\n    addLineWidget: docMethodOp(function(handle, node, options) {\n      return addLineWidget(this, handle, node, options);\n    }),\n    removeLineWidget: function(widget) { widget.clear(); },\n\n    markText: function(from, to, options) {\n      return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || \"range\");\n    },\n    setBookmark: function(pos, options) {\n      var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),\n                      insertLeft: options && options.insertLeft,\n                      clearWhenEmpty: false, shared: options && options.shared,\n                      handleMouseEvents: options && options.handleMouseEvents};\n      pos = clipPos(this, pos);\n      return markText(this, pos, pos, realOpts, \"bookmark\");\n    },\n    findMarksAt: function(pos) {\n      pos = clipPos(this, pos);\n      var markers = [], spans = getLine(this, pos.line).markedSpans;\n      if (spans) for (var i = 0; i < spans.length; ++i) {\n        var span = spans[i];\n        if ((span.from == null || span.from <= pos.ch) &&\n            (span.to == null || span.to >= pos.ch))\n          markers.push(span.marker.parent || span.marker);\n      }\n      return markers;\n    },\n    findMarks: function(from, to, filter) {\n      from = clipPos(this, from); to = clipPos(this, to);\n      var found = [], lineNo = from.line;\n      this.iter(from.line, to.line + 1, function(line) {\n        var spans = line.markedSpans;\n        if (spans) for (var i = 0; i < spans.length; i++) {\n          var span = spans[i];\n          if (!(span.to != null && lineNo == from.line && from.ch >= span.to ||\n                span.from == null && lineNo != from.line ||\n                span.from != null && lineNo == to.line && span.from >= to.ch) &&\n              (!filter || filter(span.marker)))\n            found.push(span.marker.parent || span.marker);\n        }\n        ++lineNo;\n      });\n      return found;\n    },\n    getAllMarks: function() {\n      var markers = [];\n      this.iter(function(line) {\n        var sps = line.markedSpans;\n        if (sps) for (var i = 0; i < sps.length; ++i)\n          if (sps[i].from != null) markers.push(sps[i].marker);\n      });\n      return markers;\n    },\n\n    posFromIndex: function(off) {\n      var ch, lineNo = this.first, sepSize = this.lineSeparator().length;\n      this.iter(function(line) {\n        var sz = line.text.length + sepSize;\n        if (sz > off) { ch = off; return true; }\n        off -= sz;\n        ++lineNo;\n      });\n      return clipPos(this, Pos(lineNo, ch));\n    },\n    indexFromPos: function (coords) {\n      coords = clipPos(this, coords);\n      var index = coords.ch;\n      if (coords.line < this.first || coords.ch < 0) return 0;\n      var sepSize = this.lineSeparator().length;\n      this.iter(this.first, coords.line, function (line) {\n        index += line.text.length + sepSize;\n      });\n      return index;\n    },\n\n    copy: function(copyHistory) {\n      var doc = new Doc(getLines(this, this.first, this.first + this.size),\n                        this.modeOption, this.first, this.lineSep);\n      doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;\n      doc.sel = this.sel;\n      doc.extend = false;\n      if (copyHistory) {\n        doc.history.undoDepth = this.history.undoDepth;\n        doc.setHistory(this.getHistory());\n      }\n      return doc;\n    },\n\n    linkedDoc: function(options) {\n      if (!options) options = {};\n      var from = this.first, to = this.first + this.size;\n      if (options.from != null && options.from > from) from = options.from;\n      if (options.to != null && options.to < to) to = options.to;\n      var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep);\n      if (options.sharedHist) copy.history = this.history;\n      (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});\n      copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];\n      copySharedMarkers(copy, findSharedMarkers(this));\n      return copy;\n    },\n    unlinkDoc: function(other) {\n      if (other instanceof CodeMirror) other = other.doc;\n      if (this.linked) for (var i = 0; i < this.linked.length; ++i) {\n        var link = this.linked[i];\n        if (link.doc != other) continue;\n        this.linked.splice(i, 1);\n        other.unlinkDoc(this);\n        detachSharedMarkers(findSharedMarkers(this));\n        break;\n      }\n      // If the histories were shared, split them again\n      if (other.history == this.history) {\n        var splitIds = [other.id];\n        linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true);\n        other.history = new History(null);\n        other.history.done = copyHistoryArray(this.history.done, splitIds);\n        other.history.undone = copyHistoryArray(this.history.undone, splitIds);\n      }\n    },\n    iterLinkedDocs: function(f) {linkedDocs(this, f);},\n\n    getMode: function() {return this.mode;},\n    getEditor: function() {return this.cm;},\n\n    splitLines: function(str) {\n      if (this.lineSep) return str.split(this.lineSep);\n      return splitLinesAuto(str);\n    },\n    lineSeparator: function() { return this.lineSep || \"\\n\"; }\n  });\n\n  // Public alias.\n  Doc.prototype.eachLine = Doc.prototype.iter;\n\n  // Set up methods on CodeMirror's prototype to redirect to the editor's document.\n  var dontDelegate = \"iter insert remove copy getEditor constructor\".split(\" \");\n  for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)\n    CodeMirror.prototype[prop] = (function(method) {\n      return function() {return method.apply(this.doc, arguments);};\n    })(Doc.prototype[prop]);\n\n  eventMixin(Doc);\n\n  // Call f for all linked documents.\n  function linkedDocs(doc, f, sharedHistOnly) {\n    function propagate(doc, skip, sharedHist) {\n      if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {\n        var rel = doc.linked[i];\n        if (rel.doc == skip) continue;\n        var shared = sharedHist && rel.sharedHist;\n        if (sharedHistOnly && !shared) continue;\n        f(rel.doc, shared);\n        propagate(rel.doc, doc, shared);\n      }\n    }\n    propagate(doc, null, true);\n  }\n\n  // Attach a document to an editor.\n  function attachDoc(cm, doc) {\n    if (doc.cm) throw new Error(\"This document is already in use.\");\n    cm.doc = doc;\n    doc.cm = cm;\n    estimateLineHeights(cm);\n    loadMode(cm);\n    if (!cm.options.lineWrapping) findMaxLine(cm);\n    cm.options.mode = doc.modeOption;\n    regChange(cm);\n  }\n\n  // LINE UTILITIES\n\n  // Find the line object corresponding to the given line number.\n  function getLine(doc, n) {\n    n -= doc.first;\n    if (n < 0 || n >= doc.size) throw new Error(\"There is no line \" + (n + doc.first) + \" in the document.\");\n    for (var chunk = doc; !chunk.lines;) {\n      for (var i = 0;; ++i) {\n        var child = chunk.children[i], sz = child.chunkSize();\n        if (n < sz) { chunk = child; break; }\n        n -= sz;\n      }\n    }\n    return chunk.lines[n];\n  }\n\n  // Get the part of a document between two positions, as an array of\n  // strings.\n  function getBetween(doc, start, end) {\n    var out = [], n = start.line;\n    doc.iter(start.line, end.line + 1, function(line) {\n      var text = line.text;\n      if (n == end.line) text = text.slice(0, end.ch);\n      if (n == start.line) text = text.slice(start.ch);\n      out.push(text);\n      ++n;\n    });\n    return out;\n  }\n  // Get the lines between from and to, as array of strings.\n  function getLines(doc, from, to) {\n    var out = [];\n    doc.iter(from, to, function(line) { out.push(line.text); });\n    return out;\n  }\n\n  // Update the height of a line, propagating the height change\n  // upwards to parent nodes.\n  function updateLineHeight(line, height) {\n    var diff = height - line.height;\n    if (diff) for (var n = line; n; n = n.parent) n.height += diff;\n  }\n\n  // Given a line object, find its line number by walking up through\n  // its parent links.\n  function lineNo(line) {\n    if (line.parent == null) return null;\n    var cur = line.parent, no = indexOf(cur.lines, line);\n    for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {\n      for (var i = 0;; ++i) {\n        if (chunk.children[i] == cur) break;\n        no += chunk.children[i].chunkSize();\n      }\n    }\n    return no + cur.first;\n  }\n\n  // Find the line at the given vertical position, using the height\n  // information in the document tree.\n  function lineAtHeight(chunk, h) {\n    var n = chunk.first;\n    outer: do {\n      for (var i = 0; i < chunk.children.length; ++i) {\n        var child = chunk.children[i], ch = child.height;\n        if (h < ch) { chunk = child; continue outer; }\n        h -= ch;\n        n += child.chunkSize();\n      }\n      return n;\n    } while (!chunk.lines);\n    for (var i = 0; i < chunk.lines.length; ++i) {\n      var line = chunk.lines[i], lh = line.height;\n      if (h < lh) break;\n      h -= lh;\n    }\n    return n + i;\n  }\n\n\n  // Find the height above the given line.\n  function heightAtLine(lineObj) {\n    lineObj = visualLine(lineObj);\n\n    var h = 0, chunk = lineObj.parent;\n    for (var i = 0; i < chunk.lines.length; ++i) {\n      var line = chunk.lines[i];\n      if (line == lineObj) break;\n      else h += line.height;\n    }\n    for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {\n      for (var i = 0; i < p.children.length; ++i) {\n        var cur = p.children[i];\n        if (cur == chunk) break;\n        else h += cur.height;\n      }\n    }\n    return h;\n  }\n\n  // Get the bidi ordering for the given line (and cache it). Returns\n  // false for lines that are fully left-to-right, and an array of\n  // BidiSpan objects otherwise.\n  function getOrder(line) {\n    var order = line.order;\n    if (order == null) order = line.order = bidiOrdering(line.text);\n    return order;\n  }\n\n  // HISTORY\n\n  function History(startGen) {\n    // Arrays of change events and selections. Doing something adds an\n    // event to done and clears undo. Undoing moves events from done\n    // to undone, redoing moves them in the other direction.\n    this.done = []; this.undone = [];\n    this.undoDepth = Infinity;\n    // Used to track when changes can be merged into a single undo\n    // event\n    this.lastModTime = this.lastSelTime = 0;\n    this.lastOp = this.lastSelOp = null;\n    this.lastOrigin = this.lastSelOrigin = null;\n    // Used by the isClean() method\n    this.generation = this.maxGeneration = startGen || 1;\n  }\n\n  // Create a history change event from an updateDoc-style change\n  // object.\n  function historyChangeFromChange(doc, change) {\n    var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};\n    attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);\n    linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true);\n    return histChange;\n  }\n\n  // Pop all selection events off the end of a history array. Stop at\n  // a change event.\n  function clearSelectionEvents(array) {\n    while (array.length) {\n      var last = lst(array);\n      if (last.ranges) array.pop();\n      else break;\n    }\n  }\n\n  // Find the top change event in the history. Pop off selection\n  // events that are in the way.\n  function lastChangeEvent(hist, force) {\n    if (force) {\n      clearSelectionEvents(hist.done);\n      return lst(hist.done);\n    } else if (hist.done.length && !lst(hist.done).ranges) {\n      return lst(hist.done);\n    } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {\n      hist.done.pop();\n      return lst(hist.done);\n    }\n  }\n\n  // Register a change in the history. Merges changes that are within\n  // a single operation, or are close together with an origin that\n  // allows merging (starting with \"+\") into a single event.\n  function addChangeToHistory(doc, change, selAfter, opId) {\n    var hist = doc.history;\n    hist.undone.length = 0;\n    var time = +new Date, cur;\n\n    if ((hist.lastOp == opId ||\n         hist.lastOrigin == change.origin && change.origin &&\n         ((change.origin.charAt(0) == \"+\" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||\n          change.origin.charAt(0) == \"*\")) &&\n        (cur = lastChangeEvent(hist, hist.lastOp == opId))) {\n      // Merge this change into the last event\n      var last = lst(cur.changes);\n      if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {\n        // Optimized case for simple insertion -- don't want to add\n        // new changesets for every character typed\n        last.to = changeEnd(change);\n      } else {\n        // Add new sub-event\n        cur.changes.push(historyChangeFromChange(doc, change));\n      }\n    } else {\n      // Can not be merged, start a new event.\n      var before = lst(hist.done);\n      if (!before || !before.ranges)\n        pushSelectionToHistory(doc.sel, hist.done);\n      cur = {changes: [historyChangeFromChange(doc, change)],\n             generation: hist.generation};\n      hist.done.push(cur);\n      while (hist.done.length > hist.undoDepth) {\n        hist.done.shift();\n        if (!hist.done[0].ranges) hist.done.shift();\n      }\n    }\n    hist.done.push(selAfter);\n    hist.generation = ++hist.maxGeneration;\n    hist.lastModTime = hist.lastSelTime = time;\n    hist.lastOp = hist.lastSelOp = opId;\n    hist.lastOrigin = hist.lastSelOrigin = change.origin;\n\n    if (!last) signal(doc, \"historyAdded\");\n  }\n\n  function selectionEventCanBeMerged(doc, origin, prev, sel) {\n    var ch = origin.charAt(0);\n    return ch == \"*\" ||\n      ch == \"+\" &&\n      prev.ranges.length == sel.ranges.length &&\n      prev.somethingSelected() == sel.somethingSelected() &&\n      new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500);\n  }\n\n  // Called whenever the selection changes, sets the new selection as\n  // the pending selection in the history, and pushes the old pending\n  // selection into the 'done' array when it was significantly\n  // different (in number of selected ranges, emptiness, or time).\n  function addSelectionToHistory(doc, sel, opId, options) {\n    var hist = doc.history, origin = options && options.origin;\n\n    // A new event is started when the previous origin does not match\n    // the current, or the origins don't allow matching. Origins\n    // starting with * are always merged, those starting with + are\n    // merged when similar and close together in time.\n    if (opId == hist.lastSelOp ||\n        (origin && hist.lastSelOrigin == origin &&\n         (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||\n          selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))\n      hist.done[hist.done.length - 1] = sel;\n    else\n      pushSelectionToHistory(sel, hist.done);\n\n    hist.lastSelTime = +new Date;\n    hist.lastSelOrigin = origin;\n    hist.lastSelOp = opId;\n    if (options && options.clearRedo !== false)\n      clearSelectionEvents(hist.undone);\n  }\n\n  function pushSelectionToHistory(sel, dest) {\n    var top = lst(dest);\n    if (!(top && top.ranges && top.equals(sel)))\n      dest.push(sel);\n  }\n\n  // Used to store marked span information in the history.\n  function attachLocalSpans(doc, change, from, to) {\n    var existing = change[\"spans_\" + doc.id], n = 0;\n    doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {\n      if (line.markedSpans)\n        (existing || (existing = change[\"spans_\" + doc.id] = {}))[n] = line.markedSpans;\n      ++n;\n    });\n  }\n\n  // When un/re-doing restores text containing marked spans, those\n  // that have been explicitly cleared should not be restored.\n  function removeClearedSpans(spans) {\n    if (!spans) return null;\n    for (var i = 0, out; i < spans.length; ++i) {\n      if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }\n      else if (out) out.push(spans[i]);\n    }\n    return !out ? spans : out.length ? out : null;\n  }\n\n  // Retrieve and filter the old marked spans stored in a change event.\n  function getOldSpans(doc, change) {\n    var found = change[\"spans_\" + doc.id];\n    if (!found) return null;\n    for (var i = 0, nw = []; i < change.text.length; ++i)\n      nw.push(removeClearedSpans(found[i]));\n    return nw;\n  }\n\n  // Used both to provide a JSON-safe object in .getHistory, and, when\n  // detaching a document, to split the history in two\n  function copyHistoryArray(events, newGroup, instantiateSel) {\n    for (var i = 0, copy = []; i < events.length; ++i) {\n      var event = events[i];\n      if (event.ranges) {\n        copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);\n        continue;\n      }\n      var changes = event.changes, newChanges = [];\n      copy.push({changes: newChanges});\n      for (var j = 0; j < changes.length; ++j) {\n        var change = changes[j], m;\n        newChanges.push({from: change.from, to: change.to, text: change.text});\n        if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\\d+)$/)) {\n          if (indexOf(newGroup, Number(m[1])) > -1) {\n            lst(newChanges)[prop] = change[prop];\n            delete change[prop];\n          }\n        }\n      }\n    }\n    return copy;\n  }\n\n  // Rebasing/resetting history to deal with externally-sourced changes\n\n  function rebaseHistSelSingle(pos, from, to, diff) {\n    if (to < pos.line) {\n      pos.line += diff;\n    } else if (from < pos.line) {\n      pos.line = from;\n      pos.ch = 0;\n    }\n  }\n\n  // Tries to rebase an array of history events given a change in the\n  // document. If the change touches the same lines as the event, the\n  // event, and everything 'behind' it, is discarded. If the change is\n  // before the event, the event's positions are updated. Uses a\n  // copy-on-write scheme for the positions, to avoid having to\n  // reallocate them all on every rebase, but also avoid problems with\n  // shared position objects being unsafely updated.\n  function rebaseHistArray(array, from, to, diff) {\n    for (var i = 0; i < array.length; ++i) {\n      var sub = array[i], ok = true;\n      if (sub.ranges) {\n        if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }\n        for (var j = 0; j < sub.ranges.length; j++) {\n          rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);\n          rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);\n        }\n        continue;\n      }\n      for (var j = 0; j < sub.changes.length; ++j) {\n        var cur = sub.changes[j];\n        if (to < cur.from.line) {\n          cur.from = Pos(cur.from.line + diff, cur.from.ch);\n          cur.to = Pos(cur.to.line + diff, cur.to.ch);\n        } else if (from <= cur.to.line) {\n          ok = false;\n          break;\n        }\n      }\n      if (!ok) {\n        array.splice(0, i + 1);\n        i = 0;\n      }\n    }\n  }\n\n  function rebaseHist(hist, change) {\n    var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;\n    rebaseHistArray(hist.done, from, to, diff);\n    rebaseHistArray(hist.undone, from, to, diff);\n  }\n\n  // EVENT UTILITIES\n\n  // Due to the fact that we still support jurassic IE versions, some\n  // compatibility wrappers are needed.\n\n  var e_preventDefault = CodeMirror.e_preventDefault = function(e) {\n    if (e.preventDefault) e.preventDefault();\n    else e.returnValue = false;\n  };\n  var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) {\n    if (e.stopPropagation) e.stopPropagation();\n    else e.cancelBubble = true;\n  };\n  function e_defaultPrevented(e) {\n    return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;\n  }\n  var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);};\n\n  function e_target(e) {return e.target || e.srcElement;}\n  function e_button(e) {\n    var b = e.which;\n    if (b == null) {\n      if (e.button & 1) b = 1;\n      else if (e.button & 2) b = 3;\n      else if (e.button & 4) b = 2;\n    }\n    if (mac && e.ctrlKey && b == 1) b = 3;\n    return b;\n  }\n\n  // EVENT HANDLING\n\n  // Lightweight event framework. on/off also work on DOM nodes,\n  // registering native DOM handlers.\n\n  var on = CodeMirror.on = function(emitter, type, f) {\n    if (emitter.addEventListener)\n      emitter.addEventListener(type, f, false);\n    else if (emitter.attachEvent)\n      emitter.attachEvent(\"on\" + type, f);\n    else {\n      var map = emitter._handlers || (emitter._handlers = {});\n      var arr = map[type] || (map[type] = []);\n      arr.push(f);\n    }\n  };\n\n  var noHandlers = []\n  function getHandlers(emitter, type, copy) {\n    var arr = emitter._handlers && emitter._handlers[type]\n    if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers\n    else return arr || noHandlers\n  }\n\n  var off = CodeMirror.off = function(emitter, type, f) {\n    if (emitter.removeEventListener)\n      emitter.removeEventListener(type, f, false);\n    else if (emitter.detachEvent)\n      emitter.detachEvent(\"on\" + type, f);\n    else {\n      var handlers = getHandlers(emitter, type, false)\n      for (var i = 0; i < handlers.length; ++i)\n        if (handlers[i] == f) { handlers.splice(i, 1); break; }\n    }\n  };\n\n  var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {\n    var handlers = getHandlers(emitter, type, true)\n    if (!handlers.length) return;\n    var args = Array.prototype.slice.call(arguments, 2);\n    for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args);\n  };\n\n  var orphanDelayedCallbacks = null;\n\n  // Often, we want to signal events at a point where we are in the\n  // middle of some work, but don't want the handler to start calling\n  // other methods on the editor, which might be in an inconsistent\n  // state or simply not expect any other events to happen.\n  // signalLater looks whether there are any handlers, and schedules\n  // them to be executed when the last operation ends, or, if no\n  // operation is active, when a timeout fires.\n  function signalLater(emitter, type /*, values...*/) {\n    var arr = getHandlers(emitter, type, false)\n    if (!arr.length) return;\n    var args = Array.prototype.slice.call(arguments, 2), list;\n    if (operationGroup) {\n      list = operationGroup.delayedCallbacks;\n    } else if (orphanDelayedCallbacks) {\n      list = orphanDelayedCallbacks;\n    } else {\n      list = orphanDelayedCallbacks = [];\n      setTimeout(fireOrphanDelayed, 0);\n    }\n    function bnd(f) {return function(){f.apply(null, args);};};\n    for (var i = 0; i < arr.length; ++i)\n      list.push(bnd(arr[i]));\n  }\n\n  function fireOrphanDelayed() {\n    var delayed = orphanDelayedCallbacks;\n    orphanDelayedCallbacks = null;\n    for (var i = 0; i < delayed.length; ++i) delayed[i]();\n  }\n\n  // The DOM events that CodeMirror handles can be overridden by\n  // registering a (non-DOM) handler on the editor for the event name,\n  // and preventDefault-ing the event in that handler.\n  function signalDOMEvent(cm, e, override) {\n    if (typeof e == \"string\")\n      e = {type: e, preventDefault: function() { this.defaultPrevented = true; }};\n    signal(cm, override || e.type, cm, e);\n    return e_defaultPrevented(e) || e.codemirrorIgnore;\n  }\n\n  function signalCursorActivity(cm) {\n    var arr = cm._handlers && cm._handlers.cursorActivity;\n    if (!arr) return;\n    var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);\n    for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)\n      set.push(arr[i]);\n  }\n\n  function hasHandler(emitter, type) {\n    return getHandlers(emitter, type).length > 0\n  }\n\n  // Add on and off methods to a constructor's prototype, to make\n  // registering events on such objects more convenient.\n  function eventMixin(ctor) {\n    ctor.prototype.on = function(type, f) {on(this, type, f);};\n    ctor.prototype.off = function(type, f) {off(this, type, f);};\n  }\n\n  // MISC UTILITIES\n\n  // Number of pixels added to scroller and sizer to hide scrollbar\n  var scrollerGap = 30;\n\n  // Returned or thrown by various protocols to signal 'I'm not\n  // handling this'.\n  var Pass = CodeMirror.Pass = {toString: function(){return \"CodeMirror.Pass\";}};\n\n  // Reused option objects for setSelection & friends\n  var sel_dontScroll = {scroll: false}, sel_mouse = {origin: \"*mouse\"}, sel_move = {origin: \"+move\"};\n\n  function Delayed() {this.id = null;}\n  Delayed.prototype.set = function(ms, f) {\n    clearTimeout(this.id);\n    this.id = setTimeout(f, ms);\n  };\n\n  // Counts the column offset in a string, taking tabs into account.\n  // Used mostly to find indentation.\n  var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) {\n    if (end == null) {\n      end = string.search(/[^\\s\\u00a0]/);\n      if (end == -1) end = string.length;\n    }\n    for (var i = startIndex || 0, n = startValue || 0;;) {\n      var nextTab = string.indexOf(\"\\t\", i);\n      if (nextTab < 0 || nextTab >= end)\n        return n + (end - i);\n      n += nextTab - i;\n      n += tabSize - (n % tabSize);\n      i = nextTab + 1;\n    }\n  };\n\n  // The inverse of countColumn -- find the offset that corresponds to\n  // a particular column.\n  var findColumn = CodeMirror.findColumn = function(string, goal, tabSize) {\n    for (var pos = 0, col = 0;;) {\n      var nextTab = string.indexOf(\"\\t\", pos);\n      if (nextTab == -1) nextTab = string.length;\n      var skipped = nextTab - pos;\n      if (nextTab == string.length || col + skipped >= goal)\n        return pos + Math.min(skipped, goal - col);\n      col += nextTab - pos;\n      col += tabSize - (col % tabSize);\n      pos = nextTab + 1;\n      if (col >= goal) return pos;\n    }\n  }\n\n  var spaceStrs = [\"\"];\n  function spaceStr(n) {\n    while (spaceStrs.length <= n)\n      spaceStrs.push(lst(spaceStrs) + \" \");\n    return spaceStrs[n];\n  }\n\n  function lst(arr) { return arr[arr.length-1]; }\n\n  var selectInput = function(node) { node.select(); };\n  if (ios) // Mobile Safari apparently has a bug where select() is broken.\n    selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; };\n  else if (ie) // Suppress mysterious IE10 errors\n    selectInput = function(node) { try { node.select(); } catch(_e) {} };\n\n  function indexOf(array, elt) {\n    for (var i = 0; i < array.length; ++i)\n      if (array[i] == elt) return i;\n    return -1;\n  }\n  function map(array, f) {\n    var out = [];\n    for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);\n    return out;\n  }\n\n  function insertSorted(array, value, score) {\n    var pos = 0, priority = score(value)\n    while (pos < array.length && score(array[pos]) <= priority) pos++\n    array.splice(pos, 0, value)\n  }\n\n  function nothing() {}\n\n  function createObj(base, props) {\n    var inst;\n    if (Object.create) {\n      inst = Object.create(base);\n    } else {\n      nothing.prototype = base;\n      inst = new nothing();\n    }\n    if (props) copyObj(props, inst);\n    return inst;\n  };\n\n  function copyObj(obj, target, overwrite) {\n    if (!target) target = {};\n    for (var prop in obj)\n      if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))\n        target[prop] = obj[prop];\n    return target;\n  }\n\n  function bind(f) {\n    var args = Array.prototype.slice.call(arguments, 1);\n    return function(){return f.apply(null, args);};\n  }\n\n  var nonASCIISingleCaseWordChar = /[\\u00df\\u0587\\u0590-\\u05f4\\u0600-\\u06ff\\u3040-\\u309f\\u30a0-\\u30ff\\u3400-\\u4db5\\u4e00-\\u9fcc\\uac00-\\ud7af]/;\n  var isWordCharBasic = CodeMirror.isWordChar = function(ch) {\n    return /\\w/.test(ch) || ch > \"\\x80\" &&\n      (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));\n  };\n  function isWordChar(ch, helper) {\n    if (!helper) return isWordCharBasic(ch);\n    if (helper.source.indexOf(\"\\\\w\") > -1 && isWordCharBasic(ch)) return true;\n    return helper.test(ch);\n  }\n\n  function isEmpty(obj) {\n    for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;\n    return true;\n  }\n\n  // Extending unicode characters. A series of a non-extending char +\n  // any number of extending chars is treated as a single unit as far\n  // as editing and measuring is concerned. This is not fully correct,\n  // since some scripts/fonts/browsers also treat other configurations\n  // of code points as a group.\n  var extendingChars = /[\\u0300-\\u036f\\u0483-\\u0489\\u0591-\\u05bd\\u05bf\\u05c1\\u05c2\\u05c4\\u05c5\\u05c7\\u0610-\\u061a\\u064b-\\u065e\\u0670\\u06d6-\\u06dc\\u06de-\\u06e4\\u06e7\\u06e8\\u06ea-\\u06ed\\u0711\\u0730-\\u074a\\u07a6-\\u07b0\\u07eb-\\u07f3\\u0816-\\u0819\\u081b-\\u0823\\u0825-\\u0827\\u0829-\\u082d\\u0900-\\u0902\\u093c\\u0941-\\u0948\\u094d\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09bc\\u09be\\u09c1-\\u09c4\\u09cd\\u09d7\\u09e2\\u09e3\\u0a01\\u0a02\\u0a3c\\u0a41\\u0a42\\u0a47\\u0a48\\u0a4b-\\u0a4d\\u0a51\\u0a70\\u0a71\\u0a75\\u0a81\\u0a82\\u0abc\\u0ac1-\\u0ac5\\u0ac7\\u0ac8\\u0acd\\u0ae2\\u0ae3\\u0b01\\u0b3c\\u0b3e\\u0b3f\\u0b41-\\u0b44\\u0b4d\\u0b56\\u0b57\\u0b62\\u0b63\\u0b82\\u0bbe\\u0bc0\\u0bcd\\u0bd7\\u0c3e-\\u0c40\\u0c46-\\u0c48\\u0c4a-\\u0c4d\\u0c55\\u0c56\\u0c62\\u0c63\\u0cbc\\u0cbf\\u0cc2\\u0cc6\\u0ccc\\u0ccd\\u0cd5\\u0cd6\\u0ce2\\u0ce3\\u0d3e\\u0d41-\\u0d44\\u0d4d\\u0d57\\u0d62\\u0d63\\u0dca\\u0dcf\\u0dd2-\\u0dd4\\u0dd6\\u0ddf\\u0e31\\u0e34-\\u0e3a\\u0e47-\\u0e4e\\u0eb1\\u0eb4-\\u0eb9\\u0ebb\\u0ebc\\u0ec8-\\u0ecd\\u0f18\\u0f19\\u0f35\\u0f37\\u0f39\\u0f71-\\u0f7e\\u0f80-\\u0f84\\u0f86\\u0f87\\u0f90-\\u0f97\\u0f99-\\u0fbc\\u0fc6\\u102d-\\u1030\\u1032-\\u1037\\u1039\\u103a\\u103d\\u103e\\u1058\\u1059\\u105e-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108d\\u109d\\u135f\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17b7-\\u17bd\\u17c6\\u17c9-\\u17d3\\u17dd\\u180b-\\u180d\\u18a9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193b\\u1a17\\u1a18\\u1a56\\u1a58-\\u1a5e\\u1a60\\u1a62\\u1a65-\\u1a6c\\u1a73-\\u1a7c\\u1a7f\\u1b00-\\u1b03\\u1b34\\u1b36-\\u1b3a\\u1b3c\\u1b42\\u1b6b-\\u1b73\\u1b80\\u1b81\\u1ba2-\\u1ba5\\u1ba8\\u1ba9\\u1c2c-\\u1c33\\u1c36\\u1c37\\u1cd0-\\u1cd2\\u1cd4-\\u1ce0\\u1ce2-\\u1ce8\\u1ced\\u1dc0-\\u1de6\\u1dfd-\\u1dff\\u200c\\u200d\\u20d0-\\u20f0\\u2cef-\\u2cf1\\u2de0-\\u2dff\\u302a-\\u302f\\u3099\\u309a\\ua66f-\\ua672\\ua67c\\ua67d\\ua6f0\\ua6f1\\ua802\\ua806\\ua80b\\ua825\\ua826\\ua8c4\\ua8e0-\\ua8f1\\ua926-\\ua92d\\ua947-\\ua951\\ua980-\\ua982\\ua9b3\\ua9b6-\\ua9b9\\ua9bc\\uaa29-\\uaa2e\\uaa31\\uaa32\\uaa35\\uaa36\\uaa43\\uaa4c\\uaab0\\uaab2-\\uaab4\\uaab7\\uaab8\\uaabe\\uaabf\\uaac1\\uabe5\\uabe8\\uabed\\udc00-\\udfff\\ufb1e\\ufe00-\\ufe0f\\ufe20-\\ufe26\\uff9e\\uff9f]/;\n  function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }\n\n  // DOM UTILITIES\n\n  function elt(tag, content, className, style) {\n    var e = document.createElement(tag);\n    if (className) e.className = className;\n    if (style) e.style.cssText = style;\n    if (typeof content == \"string\") e.appendChild(document.createTextNode(content));\n    else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);\n    return e;\n  }\n\n  var range;\n  if (document.createRange) range = function(node, start, end, endNode) {\n    var r = document.createRange();\n    r.setEnd(endNode || node, end);\n    r.setStart(node, start);\n    return r;\n  };\n  else range = function(node, start, end) {\n    var r = document.body.createTextRange();\n    try { r.moveToElementText(node.parentNode); }\n    catch(e) { return r; }\n    r.collapse(true);\n    r.moveEnd(\"character\", end);\n    r.moveStart(\"character\", start);\n    return r;\n  };\n\n  function removeChildren(e) {\n    for (var count = e.childNodes.length; count > 0; --count)\n      e.removeChild(e.firstChild);\n    return e;\n  }\n\n  function removeChildrenAndAdd(parent, e) {\n    return removeChildren(parent).appendChild(e);\n  }\n\n  var contains = CodeMirror.contains = function(parent, child) {\n    if (child.nodeType == 3) // Android browser always returns false when child is a textnode\n      child = child.parentNode;\n    if (parent.contains)\n      return parent.contains(child);\n    do {\n      if (child.nodeType == 11) child = child.host;\n      if (child == parent) return true;\n    } while (child = child.parentNode);\n  };\n\n  function activeElt() {\n    var activeElement = document.activeElement;\n    while (activeElement && activeElement.root && activeElement.root.activeElement)\n      activeElement = activeElement.root.activeElement;\n    return activeElement;\n  }\n  // Older versions of IE throws unspecified error when touching\n  // document.activeElement in some cases (during loading, in iframe)\n  if (ie && ie_version < 11) activeElt = function() {\n    try { return document.activeElement; }\n    catch(e) { return document.body; }\n  };\n\n  function classTest(cls) { return new RegExp(\"(^|\\\\s)\" + cls + \"(?:$|\\\\s)\\\\s*\"); }\n  var rmClass = CodeMirror.rmClass = function(node, cls) {\n    var current = node.className;\n    var match = classTest(cls).exec(current);\n    if (match) {\n      var after = current.slice(match.index + match[0].length);\n      node.className = current.slice(0, match.index) + (after ? match[1] + after : \"\");\n    }\n  };\n  var addClass = CodeMirror.addClass = function(node, cls) {\n    var current = node.className;\n    if (!classTest(cls).test(current)) node.className += (current ? \" \" : \"\") + cls;\n  };\n  function joinClasses(a, b) {\n    var as = a.split(\" \");\n    for (var i = 0; i < as.length; i++)\n      if (as[i] && !classTest(as[i]).test(b)) b += \" \" + as[i];\n    return b;\n  }\n\n  // WINDOW-WIDE EVENTS\n\n  // These must be handled carefully, because naively registering a\n  // handler for each editor will cause the editors to never be\n  // garbage collected.\n\n  function forEachCodeMirror(f) {\n    if (!document.body.getElementsByClassName) return;\n    var byClass = document.body.getElementsByClassName(\"CodeMirror\");\n    for (var i = 0; i < byClass.length; i++) {\n      var cm = byClass[i].CodeMirror;\n      if (cm) f(cm);\n    }\n  }\n\n  var globalsRegistered = false;\n  function ensureGlobalHandlers() {\n    if (globalsRegistered) return;\n    registerGlobalHandlers();\n    globalsRegistered = true;\n  }\n  function registerGlobalHandlers() {\n    // When the window resizes, we need to refresh active editors.\n    var resizeTimer;\n    on(window, \"resize\", function() {\n      if (resizeTimer == null) resizeTimer = setTimeout(function() {\n        resizeTimer = null;\n        forEachCodeMirror(onResize);\n      }, 100);\n    });\n    // When the window loses focus, we want to show the editor as blurred\n    on(window, \"blur\", function() {\n      forEachCodeMirror(onBlur);\n    });\n  }\n\n  // FEATURE DETECTION\n\n  // Detect drag-and-drop\n  var dragAndDrop = function() {\n    // There is *some* kind of drag-and-drop support in IE6-8, but I\n    // couldn't get it to work yet.\n    if (ie && ie_version < 9) return false;\n    var div = elt('div');\n    return \"draggable\" in div || \"dragDrop\" in div;\n  }();\n\n  var zwspSupported;\n  function zeroWidthElement(measure) {\n    if (zwspSupported == null) {\n      var test = elt(\"span\", \"\\u200b\");\n      removeChildrenAndAdd(measure, elt(\"span\", [test, document.createTextNode(\"x\")]));\n      if (measure.firstChild.offsetHeight != 0)\n        zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8);\n    }\n    var node = zwspSupported ? elt(\"span\", \"\\u200b\") :\n      elt(\"span\", \"\\u00a0\", null, \"display: inline-block; width: 1px; margin-right: -1px\");\n    node.setAttribute(\"cm-text\", \"\");\n    return node;\n  }\n\n  // Feature-detect IE's crummy client rect reporting for bidi text\n  var badBidiRects;\n  function hasBadBidiRects(measure) {\n    if (badBidiRects != null) return badBidiRects;\n    var txt = removeChildrenAndAdd(measure, document.createTextNode(\"A\\u062eA\"));\n    var r0 = range(txt, 0, 1).getBoundingClientRect();\n    var r1 = range(txt, 1, 2).getBoundingClientRect();\n    removeChildren(measure);\n    if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780)\n    return badBidiRects = (r1.right - r0.right < 3);\n  }\n\n  // See if \"\".split is the broken IE version, if so, provide an\n  // alternative way to split lines.\n  var splitLinesAuto = CodeMirror.splitLines = \"\\n\\nb\".split(/\\n/).length != 3 ? function(string) {\n    var pos = 0, result = [], l = string.length;\n    while (pos <= l) {\n      var nl = string.indexOf(\"\\n\", pos);\n      if (nl == -1) nl = string.length;\n      var line = string.slice(pos, string.charAt(nl - 1) == \"\\r\" ? nl - 1 : nl);\n      var rt = line.indexOf(\"\\r\");\n      if (rt != -1) {\n        result.push(line.slice(0, rt));\n        pos += rt + 1;\n      } else {\n        result.push(line);\n        pos = nl + 1;\n      }\n    }\n    return result;\n  } : function(string){return string.split(/\\r\\n?|\\n/);};\n\n  var hasSelection = window.getSelection ? function(te) {\n    try { return te.selectionStart != te.selectionEnd; }\n    catch(e) { return false; }\n  } : function(te) {\n    try {var range = te.ownerDocument.selection.createRange();}\n    catch(e) {}\n    if (!range || range.parentElement() != te) return false;\n    return range.compareEndPoints(\"StartToEnd\", range) != 0;\n  };\n\n  var hasCopyEvent = (function() {\n    var e = elt(\"div\");\n    if (\"oncopy\" in e) return true;\n    e.setAttribute(\"oncopy\", \"return;\");\n    return typeof e.oncopy == \"function\";\n  })();\n\n  var badZoomedRects = null;\n  function hasBadZoomedRects(measure) {\n    if (badZoomedRects != null) return badZoomedRects;\n    var node = removeChildrenAndAdd(measure, elt(\"span\", \"x\"));\n    var normal = node.getBoundingClientRect();\n    var fromRange = range(node, 0, 1).getBoundingClientRect();\n    return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1;\n  }\n\n  // KEY NAMES\n\n  var keyNames = CodeMirror.keyNames = {\n    3: \"Enter\", 8: \"Backspace\", 9: \"Tab\", 13: \"Enter\", 16: \"Shift\", 17: \"Ctrl\", 18: \"Alt\",\n    19: \"Pause\", 20: \"CapsLock\", 27: \"Esc\", 32: \"Space\", 33: \"PageUp\", 34: \"PageDown\", 35: \"End\",\n    36: \"Home\", 37: \"Left\", 38: \"Up\", 39: \"Right\", 40: \"Down\", 44: \"PrintScrn\", 45: \"Insert\",\n    46: \"Delete\", 59: \";\", 61: \"=\", 91: \"Mod\", 92: \"Mod\", 93: \"Mod\",\n    106: \"*\", 107: \"=\", 109: \"-\", 110: \".\", 111: \"/\", 127: \"Delete\",\n    173: \"-\", 186: \";\", 187: \"=\", 188: \",\", 189: \"-\", 190: \".\", 191: \"/\", 192: \"`\", 219: \"[\", 220: \"\\\\\",\n    221: \"]\", 222: \"'\", 63232: \"Up\", 63233: \"Down\", 63234: \"Left\", 63235: \"Right\", 63272: \"Delete\",\n    63273: \"Home\", 63275: \"End\", 63276: \"PageUp\", 63277: \"PageDown\", 63302: \"Insert\"\n  };\n  (function() {\n    // Number keys\n    for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);\n    // Alphabetic keys\n    for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);\n    // Function keys\n    for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = \"F\" + i;\n  })();\n\n  // BIDI HELPERS\n\n  function iterateBidiSections(order, from, to, f) {\n    if (!order) return f(from, to, \"ltr\");\n    var found = false;\n    for (var i = 0; i < order.length; ++i) {\n      var part = order[i];\n      if (part.from < to && part.to > from || from == to && part.to == from) {\n        f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? \"rtl\" : \"ltr\");\n        found = true;\n      }\n    }\n    if (!found) f(from, to, \"ltr\");\n  }\n\n  function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }\n  function bidiRight(part) { return part.level % 2 ? part.from : part.to; }\n\n  function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }\n  function lineRight(line) {\n    var order = getOrder(line);\n    if (!order) return line.text.length;\n    return bidiRight(lst(order));\n  }\n\n  function lineStart(cm, lineN) {\n    var line = getLine(cm.doc, lineN);\n    var visual = visualLine(line);\n    if (visual != line) lineN = lineNo(visual);\n    var order = getOrder(visual);\n    var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);\n    return Pos(lineN, ch);\n  }\n  function lineEnd(cm, lineN) {\n    var merged, line = getLine(cm.doc, lineN);\n    while (merged = collapsedSpanAtEnd(line)) {\n      line = merged.find(1, true).line;\n      lineN = null;\n    }\n    var order = getOrder(line);\n    var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);\n    return Pos(lineN == null ? lineNo(line) : lineN, ch);\n  }\n  function lineStartSmart(cm, pos) {\n    var start = lineStart(cm, pos.line);\n    var line = getLine(cm.doc, start.line);\n    var order = getOrder(line);\n    if (!order || order[0].level == 0) {\n      var firstNonWS = Math.max(0, line.text.search(/\\S/));\n      var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;\n      return Pos(start.line, inWS ? 0 : firstNonWS);\n    }\n    return start;\n  }\n\n  function compareBidiLevel(order, a, b) {\n    var linedir = order[0].level;\n    if (a == linedir) return true;\n    if (b == linedir) return false;\n    return a < b;\n  }\n  var bidiOther;\n  function getBidiPartAt(order, pos) {\n    bidiOther = null;\n    for (var i = 0, found; i < order.length; ++i) {\n      var cur = order[i];\n      if (cur.from < pos && cur.to > pos) return i;\n      if ((cur.from == pos || cur.to == pos)) {\n        if (found == null) {\n          found = i;\n        } else if (compareBidiLevel(order, cur.level, order[found].level)) {\n          if (cur.from != cur.to) bidiOther = found;\n          return i;\n        } else {\n          if (cur.from != cur.to) bidiOther = i;\n          return found;\n        }\n      }\n    }\n    return found;\n  }\n\n  function moveInLine(line, pos, dir, byUnit) {\n    if (!byUnit) return pos + dir;\n    do pos += dir;\n    while (pos > 0 && isExtendingChar(line.text.charAt(pos)));\n    return pos;\n  }\n\n  // This is needed in order to move 'visually' through bi-directional\n  // text -- i.e., pressing left should make the cursor go left, even\n  // when in RTL text. The tricky part is the 'jumps', where RTL and\n  // LTR text touch each other. This often requires the cursor offset\n  // to move more than one unit, in order to visually move one unit.\n  function moveVisually(line, start, dir, byUnit) {\n    var bidi = getOrder(line);\n    if (!bidi) return moveLogically(line, start, dir, byUnit);\n    var pos = getBidiPartAt(bidi, start), part = bidi[pos];\n    var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);\n\n    for (;;) {\n      if (target > part.from && target < part.to) return target;\n      if (target == part.from || target == part.to) {\n        if (getBidiPartAt(bidi, target) == pos) return target;\n        part = bidi[pos += dir];\n        return (dir > 0) == part.level % 2 ? part.to : part.from;\n      } else {\n        part = bidi[pos += dir];\n        if (!part) return null;\n        if ((dir > 0) == part.level % 2)\n          target = moveInLine(line, part.to, -1, byUnit);\n        else\n          target = moveInLine(line, part.from, 1, byUnit);\n      }\n    }\n  }\n\n  function moveLogically(line, start, dir, byUnit) {\n    var target = start + dir;\n    if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;\n    return target < 0 || target > line.text.length ? null : target;\n  }\n\n  // Bidirectional ordering algorithm\n  // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm\n  // that this (partially) implements.\n\n  // One-char codes used for character types:\n  // L (L):   Left-to-Right\n  // R (R):   Right-to-Left\n  // r (AL):  Right-to-Left Arabic\n  // 1 (EN):  European Number\n  // + (ES):  European Number Separator\n  // % (ET):  European Number Terminator\n  // n (AN):  Arabic Number\n  // , (CS):  Common Number Separator\n  // m (NSM): Non-Spacing Mark\n  // b (BN):  Boundary Neutral\n  // s (B):   Paragraph Separator\n  // t (S):   Segment Separator\n  // w (WS):  Whitespace\n  // N (ON):  Other Neutrals\n\n  // Returns null if characters are ordered as they appear\n  // (left-to-right), or an array of sections ({from, to, level}\n  // objects) in the order in which they occur visually.\n  var bidiOrdering = (function() {\n    // Character types for codepoints 0 to 0xff\n    var lowTypes = \"bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN\";\n    // Character types for codepoints 0x600 to 0x6ff\n    var arabicTypes = \"rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm\";\n    function charType(code) {\n      if (code <= 0xf7) return lowTypes.charAt(code);\n      else if (0x590 <= code && code <= 0x5f4) return \"R\";\n      else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600);\n      else if (0x6ee <= code && code <= 0x8ac) return \"r\";\n      else if (0x2000 <= code && code <= 0x200b) return \"w\";\n      else if (code == 0x200c) return \"b\";\n      else return \"L\";\n    }\n\n    var bidiRE = /[\\u0590-\\u05f4\\u0600-\\u06ff\\u0700-\\u08ac]/;\n    var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;\n    // Browsers seem to always treat the boundaries of block elements as being L.\n    var outerType = \"L\";\n\n    function BidiSpan(level, from, to) {\n      this.level = level;\n      this.from = from; this.to = to;\n    }\n\n    return function(str) {\n      if (!bidiRE.test(str)) return false;\n      var len = str.length, types = [];\n      for (var i = 0, type; i < len; ++i)\n        types.push(type = charType(str.charCodeAt(i)));\n\n      // W1. Examine each non-spacing mark (NSM) in the level run, and\n      // change the type of the NSM to the type of the previous\n      // character. If the NSM is at the start of the level run, it will\n      // get the type of sor.\n      for (var i = 0, prev = outerType; i < len; ++i) {\n        var type = types[i];\n        if (type == \"m\") types[i] = prev;\n        else prev = type;\n      }\n\n      // W2. Search backwards from each instance of a European number\n      // until the first strong type (R, L, AL, or sor) is found. If an\n      // AL is found, change the type of the European number to Arabic\n      // number.\n      // W3. Change all ALs to R.\n      for (var i = 0, cur = outerType; i < len; ++i) {\n        var type = types[i];\n        if (type == \"1\" && cur == \"r\") types[i] = \"n\";\n        else if (isStrong.test(type)) { cur = type; if (type == \"r\") types[i] = \"R\"; }\n      }\n\n      // W4. A single European separator between two European numbers\n      // changes to a European number. A single common separator between\n      // two numbers of the same type changes to that type.\n      for (var i = 1, prev = types[0]; i < len - 1; ++i) {\n        var type = types[i];\n        if (type == \"+\" && prev == \"1\" && types[i+1] == \"1\") types[i] = \"1\";\n        else if (type == \",\" && prev == types[i+1] &&\n                 (prev == \"1\" || prev == \"n\")) types[i] = prev;\n        prev = type;\n      }\n\n      // W5. A sequence of European terminators adjacent to European\n      // numbers changes to all European numbers.\n      // W6. Otherwise, separators and terminators change to Other\n      // Neutral.\n      for (var i = 0; i < len; ++i) {\n        var type = types[i];\n        if (type == \",\") types[i] = \"N\";\n        else if (type == \"%\") {\n          for (var end = i + 1; end < len && types[end] == \"%\"; ++end) {}\n          var replace = (i && types[i-1] == \"!\") || (end < len && types[end] == \"1\") ? \"1\" : \"N\";\n          for (var j = i; j < end; ++j) types[j] = replace;\n          i = end - 1;\n        }\n      }\n\n      // W7. Search backwards from each instance of a European number\n      // until the first strong type (R, L, or sor) is found. If an L is\n      // found, then change the type of the European number to L.\n      for (var i = 0, cur = outerType; i < len; ++i) {\n        var type = types[i];\n        if (cur == \"L\" && type == \"1\") types[i] = \"L\";\n        else if (isStrong.test(type)) cur = type;\n      }\n\n      // N1. A sequence of neutrals takes the direction of the\n      // surrounding strong text if the text on both sides has the same\n      // direction. European and Arabic numbers act as if they were R in\n      // terms of their influence on neutrals. Start-of-level-run (sor)\n      // and end-of-level-run (eor) are used at level run boundaries.\n      // N2. Any remaining neutrals take the embedding direction.\n      for (var i = 0; i < len; ++i) {\n        if (isNeutral.test(types[i])) {\n          for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}\n          var before = (i ? types[i-1] : outerType) == \"L\";\n          var after = (end < len ? types[end] : outerType) == \"L\";\n          var replace = before || after ? \"L\" : \"R\";\n          for (var j = i; j < end; ++j) types[j] = replace;\n          i = end - 1;\n        }\n      }\n\n      // Here we depart from the documented algorithm, in order to avoid\n      // building up an actual levels array. Since there are only three\n      // levels (0, 1, 2) in an implementation that doesn't take\n      // explicit embedding into account, we can build up the order on\n      // the fly, without following the level-based algorithm.\n      var order = [], m;\n      for (var i = 0; i < len;) {\n        if (countsAsLeft.test(types[i])) {\n          var start = i;\n          for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}\n          order.push(new BidiSpan(0, start, i));\n        } else {\n          var pos = i, at = order.length;\n          for (++i; i < len && types[i] != \"L\"; ++i) {}\n          for (var j = pos; j < i;) {\n            if (countsAsNum.test(types[j])) {\n              if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j));\n              var nstart = j;\n              for (++j; j < i && countsAsNum.test(types[j]); ++j) {}\n              order.splice(at, 0, new BidiSpan(2, nstart, j));\n              pos = j;\n            } else ++j;\n          }\n          if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i));\n        }\n      }\n      if (order[0].level == 1 && (m = str.match(/^\\s+/))) {\n        order[0].from = m[0].length;\n        order.unshift(new BidiSpan(0, 0, m[0].length));\n      }\n      if (lst(order).level == 1 && (m = str.match(/\\s+$/))) {\n        lst(order).to -= m[0].length;\n        order.push(new BidiSpan(0, len - m[0].length, len));\n      }\n      if (order[0].level == 2)\n        order.unshift(new BidiSpan(1, order[0].to, order[0].to));\n      if (order[0].level != lst(order).level)\n        order.push(new BidiSpan(order[0].level, len, len));\n\n      return order;\n    };\n  })();\n\n  // THE END\n\n  CodeMirror.version = \"5.19.0\";\n\n  return CodeMirror;\n});\n"
  },
  {
    "path": "static/CodeMirror/mode/sql.js",
    "content": "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http://codemirror.net/LICENSE\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../../lib/codemirror\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../../lib/codemirror\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n\"use strict\";\n\nCodeMirror.defineMode(\"sql\", function(config, parserConfig) {\n  \"use strict\";\n\n  var client         = parserConfig.client || {},\n      atoms          = parserConfig.atoms || {\"false\": true, \"true\": true, \"null\": true},\n      builtin        = parserConfig.builtin || {},\n      keywords       = parserConfig.keywords || {},\n      operatorChars  = parserConfig.operatorChars || /^[*+\\-%<>!=&|~^]/,\n      support        = parserConfig.support || {},\n      hooks          = parserConfig.hooks || {},\n      dateSQL        = parserConfig.dateSQL || {\"date\" : true, \"time\" : true, \"timestamp\" : true};\n\n  function tokenBase(stream, state) {\n    var ch = stream.next();\n\n    // call hooks from the mime type\n    if (hooks[ch]) {\n      var result = hooks[ch](stream, state);\n      if (result !== false) return result;\n    }\n\n    if (support.hexNumber == true &&\n      ((ch == \"0\" && stream.match(/^[xX][0-9a-fA-F]+/))\n      || (ch == \"x\" || ch == \"X\") && stream.match(/^'[0-9a-fA-F]+'/))) {\n      // hex\n      // ref: http://dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html\n      return \"number\";\n    } else if (support.binaryNumber == true &&\n      (((ch == \"b\" || ch == \"B\") && stream.match(/^'[01]+'/))\n      || (ch == \"0\" && stream.match(/^b[01]+/)))) {\n      // bitstring\n      // ref: http://dev.mysql.com/doc/refman/5.5/en/bit-field-literals.html\n      return \"number\";\n    } else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) {\n      // numbers\n      // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html\n          stream.match(/^[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?/);\n      support.decimallessFloat == true && stream.eat('.');\n      return \"number\";\n    } else if (ch == \"?\" && (stream.eatSpace() || stream.eol() || stream.eat(\";\"))) {\n      // placeholders\n      return \"variable-3\";\n    } else if (ch == \"'\" || (ch == '\"' && support.doubleQuote)) {\n      // strings\n      // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html\n      state.tokenize = tokenLiteral(ch);\n      return state.tokenize(stream, state);\n    } else if ((((support.nCharCast == true && (ch == \"n\" || ch == \"N\"))\n        || (support.charsetCast == true && ch == \"_\" && stream.match(/[a-z][a-z0-9]*/i)))\n        && (stream.peek() == \"'\" || stream.peek() == '\"'))) {\n      // charset casting: _utf8'str', N'str', n'str'\n      // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html\n      return \"keyword\";\n    } else if (/^[\\(\\),\\;\\[\\]]/.test(ch)) {\n      // no highlighting\n      return null;\n    } else if (support.commentSlashSlash && ch == \"/\" && stream.eat(\"/\")) {\n      // 1-line comment\n      stream.skipToEnd();\n      return \"comment\";\n    } else if ((support.commentHash && ch == \"#\")\n        || (ch == \"-\" && stream.eat(\"-\") && (!support.commentSpaceRequired || stream.eat(\" \")))) {\n      // 1-line comments\n      // ref: https://kb.askmonty.org/en/comment-syntax/\n      stream.skipToEnd();\n      return \"comment\";\n    } else if (ch == \"/\" && stream.eat(\"*\")) {\n      // multi-line comments\n      // ref: https://kb.askmonty.org/en/comment-syntax/\n      state.tokenize = tokenComment;\n      return state.tokenize(stream, state);\n    } else if (ch == \".\") {\n      // .1 for 0.1\n      if (support.zerolessFloat == true && stream.match(/^(?:\\d+(?:e[+-]?\\d+)?)/i)) {\n        return \"number\";\n      }\n      // .table_name (ODBC)\n      // // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html\n      if (support.ODBCdotTable == true && stream.match(/^[a-zA-Z_]+/)) {\n        return \"variable-2\";\n      }\n    } else if (operatorChars.test(ch)) {\n      // operators\n      stream.eatWhile(operatorChars);\n      return null;\n    } else if (ch == '{' &&\n        (stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*\"[^\"]*\"( )*}/))) {\n      // dates (weird ODBC syntax)\n      // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html\n      return \"number\";\n    } else {\n      stream.eatWhile(/^[_\\w\\d]/);\n      var word = stream.current().toLowerCase();\n      // dates (standard SQL syntax)\n      // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html\n      if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+\"[^\"]*\"/)))\n        return \"number\";\n      if (atoms.hasOwnProperty(word)) return \"atom\";\n      if (builtin.hasOwnProperty(word)) return \"builtin\";\n      if (keywords.hasOwnProperty(word)) return \"keyword\";\n      if (client.hasOwnProperty(word)) return \"string-2\";\n      return null;\n    }\n  }\n\n  // 'string', with char specified in quote escaped by '\\'\n  function tokenLiteral(quote) {\n    return function(stream, state) {\n      var escaped = false, ch;\n      while ((ch = stream.next()) != null) {\n        if (ch == quote && !escaped) {\n          state.tokenize = tokenBase;\n          break;\n        }\n        escaped = !escaped && ch == \"\\\\\";\n      }\n      return \"string\";\n    };\n  }\n  function tokenComment(stream, state) {\n    while (true) {\n      if (stream.skipTo(\"*\")) {\n        stream.next();\n        if (stream.eat(\"/\")) {\n          state.tokenize = tokenBase;\n          break;\n        }\n      } else {\n        stream.skipToEnd();\n        break;\n      }\n    }\n    return \"comment\";\n  }\n\n  function pushContext(stream, state, type) {\n    state.context = {\n      prev: state.context,\n      indent: stream.indentation(),\n      col: stream.column(),\n      type: type\n    };\n  }\n\n  function popContext(state) {\n    state.indent = state.context.indent;\n    state.context = state.context.prev;\n  }\n\n  return {\n    startState: function() {\n      return {tokenize: tokenBase, context: null};\n    },\n\n    token: function(stream, state) {\n      if (stream.sol()) {\n        if (state.context && state.context.align == null)\n          state.context.align = false;\n      }\n      if (stream.eatSpace()) return null;\n\n      var style = state.tokenize(stream, state);\n      if (style == \"comment\") return style;\n\n      if (state.context && state.context.align == null)\n        state.context.align = true;\n\n      var tok = stream.current();\n      if (tok == \"(\")\n        pushContext(stream, state, \")\");\n      else if (tok == \"[\")\n        pushContext(stream, state, \"]\");\n      else if (state.context && state.context.type == tok)\n        popContext(state);\n      return style;\n    },\n\n    indent: function(state, textAfter) {\n      var cx = state.context;\n      if (!cx) return CodeMirror.Pass;\n      var closing = textAfter.charAt(0) == cx.type;\n      if (cx.align) return cx.col + (closing ? 0 : 1);\n      else return cx.indent + (closing ? 0 : config.indentUnit);\n    },\n\n    blockCommentStart: \"/*\",\n    blockCommentEnd: \"*/\",\n    lineComment: support.commentSlashSlash ? \"//\" : support.commentHash ? \"#\" : null\n  };\n});\n\n(function() {\n  \"use strict\";\n\n  // `identifier`\n  function hookIdentifier(stream) {\n    // MySQL/MariaDB identifiers\n    // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html\n    var ch;\n    while ((ch = stream.next()) != null) {\n      if (ch == \"`\" && !stream.eat(\"`\")) return \"variable-2\";\n    }\n    stream.backUp(stream.current().length - 1);\n    return stream.eatWhile(/\\w/) ? \"variable-2\" : null;\n  }\n\n  // variable token\n  function hookVar(stream) {\n    // variables\n    // @@prefix.varName @varName\n    // varName can be quoted with ` or ' or \"\n    // ref: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html\n    if (stream.eat(\"@\")) {\n      stream.match(/^session\\./);\n      stream.match(/^local\\./);\n      stream.match(/^global\\./);\n    }\n\n    if (stream.eat(\"'\")) {\n      stream.match(/^.*'/);\n      return \"variable-2\";\n    } else if (stream.eat('\"')) {\n      stream.match(/^.*\"/);\n      return \"variable-2\";\n    } else if (stream.eat(\"`\")) {\n      stream.match(/^.*`/);\n      return \"variable-2\";\n    } else if (stream.match(/^[0-9a-zA-Z$\\.\\_]+/)) {\n      return \"variable-2\";\n    }\n    return null;\n  };\n\n  // short client keyword token\n  function hookClient(stream) {\n    // \\N means NULL\n    // ref: http://dev.mysql.com/doc/refman/5.5/en/null-values.html\n    if (stream.eat(\"N\")) {\n        return \"atom\";\n    }\n    // \\g, etc\n    // ref: http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html\n    return stream.match(/^[a-zA-Z.#!?]/) ? \"variable-2\" : null;\n  }\n\n  // these keywords are used by all SQL dialects (however, a mode can still overwrite it)\n  var sqlKeywords = \"alter and as asc between by count create delete desc distinct drop from group having in insert into is join like not on or order select set table union update values where limit \";\n\n  // turn a space-separated list into an array\n  function set(str) {\n    var obj = {}, words = str.split(\" \");\n    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;\n    return obj;\n  }\n\n  // A generic SQL Mode. It's not a standard, it just try to support what is generally supported\n  CodeMirror.defineMIME(\"text/x-sql\", {\n    name: \"sql\",\n    keywords: set(sqlKeywords + \"begin\"),\n    builtin: set(\"bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision real date datetime year unsigned signed decimal numeric\"),\n    atoms: set(\"false true null unknown\"),\n    operatorChars: /^[*+\\-%<>!=]/,\n    dateSQL: set(\"date time timestamp\"),\n    support: set(\"ODBCdotTable doubleQuote binaryNumber hexNumber\")\n  });\n\n  CodeMirror.defineMIME(\"text/x-mssql\", {\n    name: \"sql\",\n    client: set(\"charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee\"),\n    keywords: set(sqlKeywords + \"begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered declare\"),\n    builtin: set(\"bigint numeric bit smallint decimal smallmoney int tinyint money float real char varchar text nchar nvarchar ntext binary varbinary image cursor timestamp hierarchyid uniqueidentifier sql_variant xml table \"),\n    atoms: set(\"false true null unknown\"),\n    operatorChars: /^[*+\\-%<>!=]/,\n    dateSQL: set(\"date datetimeoffset datetime2 smalldatetime datetime time\"),\n    hooks: {\n      \"@\":   hookVar\n    }\n  });\n\n  CodeMirror.defineMIME(\"text/x-mysql\", {\n    name: \"sql\",\n    client: set(\"charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee\"),\n    keywords: set(sqlKeywords + \"accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general get global grant grants group group_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat\"),\n    builtin: set(\"bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric\"),\n    atoms: set(\"false true null unknown\"),\n    operatorChars: /^[*+\\-%<>!=&|^]/,\n    dateSQL: set(\"date time timestamp\"),\n    support: set(\"ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired\"),\n    hooks: {\n      \"@\":   hookVar,\n      \"`\":   hookIdentifier,\n      \"\\\\\":  hookClient\n    }\n  });\n\n  CodeMirror.defineMIME(\"text/x-mariadb\", {\n    name: \"sql\",\n    client: set(\"charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee\"),\n    keywords: set(sqlKeywords + \"accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated get global grant grants group groupby_concat handler hard hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show shutdown signal slave slow smallint snapshot soft soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat\"),\n    builtin: set(\"bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric\"),\n    atoms: set(\"false true null unknown\"),\n    operatorChars: /^[*+\\-%<>!=&|^]/,\n    dateSQL: set(\"date time timestamp\"),\n    support: set(\"ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired\"),\n    hooks: {\n      \"@\":   hookVar,\n      \"`\":   hookIdentifier,\n      \"\\\\\":  hookClient\n    }\n  });\n\n  // the query language used by Apache Cassandra is called CQL, but this mime type\n  // is called Cassandra to avoid confusion with Contextual Query Language\n  CodeMirror.defineMIME(\"text/x-cassandra\", {\n    name: \"sql\",\n    client: { },\n    keywords: set(\"add all allow alter and any apply as asc authorize batch begin by clustering columnfamily compact consistency count create custom delete desc distinct drop each_quorum exists filtering from grant if in index insert into key keyspace keyspaces level limit local_one local_quorum modify nan norecursive nosuperuser not of on one order password permission permissions primary quorum rename revoke schema select set storage superuser table three to token truncate ttl two type unlogged update use user users using values where with writetime\"),\n    builtin: set(\"ascii bigint blob boolean counter decimal double float frozen inet int list map static text timestamp timeuuid tuple uuid varchar varint\"),\n    atoms: set(\"false true infinity NaN\"),\n    operatorChars: /^[<>=]/,\n    dateSQL: { },\n    support: set(\"commentSlashSlash decimallessFloat\"),\n    hooks: { }\n  });\n\n  // this is based on Peter Raganitsch's 'plsql' mode\n  CodeMirror.defineMIME(\"text/x-plsql\", {\n    name:       \"sql\",\n    client:     set(\"appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap\"),\n    keywords:   set(\"abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elseif elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning returns reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work\"),\n    builtin:    set(\"abs acos add_months ascii asin atan atan2 average bfile bfilename bigserial bit blob ceil character chartorowid chr clob concat convert cos cosh count dec decode deref dual dump dup_val_on_index empty error exp false float floor found glb greatest hextoraw initcap instr instrb int integer isopen last_day least length lengthb ln lower lpad ltrim lub make_ref max min mlslabel mod months_between natural naturaln nchar nclob new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null number numeric nvarchar2 nvl others power rawtohex real reftohex round rowcount rowidtochar rowtype rpad rtrim serial sign signtype sin sinh smallint soundex sqlcode sqlerrm sqrt stddev string substr substrb sum sysdate tan tanh to_char text to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid unlogged upper user userenv varchar varchar2 variance varying vsize xml\"),\n    operatorChars: /^[*+\\-%<>!=~]/,\n    dateSQL:    set(\"date time timestamp\"),\n    support:    set(\"doubleQuote nCharCast zerolessFloat binaryNumber hexNumber\")\n  });\n\n  // Created to support specific hive keywords\n  CodeMirror.defineMIME(\"text/x-hive\", {\n    name: \"sql\",\n    keywords: set(\"select alter $elem$ $key$ $value$ add after all analyze and archive as asc before between binary both bucket buckets by cascade case cast change cluster clustered clusterstatus collection column columns comment compute concatenate continue create cross cursor data database databases dbproperties deferred delete delimited desc describe directory disable distinct distribute drop else enable end escaped exclusive exists explain export extended external false fetch fields fileformat first format formatted from full function functions grant group having hold_ddltime idxproperties if import in index indexes inpath inputdriver inputformat insert intersect into is items join keys lateral left like limit lines load local location lock locks mapjoin materialized minus msck no_drop nocompress not of offline on option or order out outer outputdriver outputformat overwrite partition partitioned partitions percent plus preserve procedure purge range rcfile read readonly reads rebuild recordreader recordwriter recover reduce regexp rename repair replace restrict revoke right rlike row schema schemas semi sequencefile serde serdeproperties set shared show show_database sort sorted ssl statistics stored streamtable table tables tablesample tblproperties temporary terminated textfile then tmp to touch transform trigger true unarchive undo union uniquejoin unlock update use using utc utc_tmestamp view when where while with\"),\n    builtin: set(\"bool boolean long timestamp tinyint smallint bigint int float double date datetime unsigned string array struct map uniontype\"),\n    atoms: set(\"false true null unknown\"),\n    operatorChars: /^[*+\\-%<>!=]/,\n    dateSQL: set(\"date timestamp\"),\n    support: set(\"ODBCdotTable doubleQuote binaryNumber hexNumber\")\n  });\n\n  CodeMirror.defineMIME(\"text/x-pgsql\", {\n    name: \"sql\",\n    client: set(\"source\"),\n    // http://www.postgresql.org/docs/9.5/static/sql-keywords-appendix.html\n    keywords: set(sqlKeywords + \"a abort abs absent absolute access according action ada add admin after aggregate all allocate also always analyse analyze any are array array_agg array_max_cardinality asensitive assertion assignment asymmetric at atomic attribute attributes authorization avg backward base64 before begin begin_frame begin_partition bernoulli binary bit_length blob blocked bom both breadth c cache call called cardinality cascade cascaded case cast catalog catalog_name ceil ceiling chain characteristics characters character_length character_set_catalog character_set_name character_set_schema char_length check checkpoint class class_origin clob close cluster coalesce cobol collate collation collation_catalog collation_name collation_schema collect column columns column_name command_function command_function_code comment comments commit committed concurrently condition condition_number configuration conflict connect connection connection_name constraint constraints constraint_catalog constraint_name constraint_schema constructor contains content continue control conversion convert copy corr corresponding cost covar_pop covar_samp cross csv cube cume_dist current current_catalog current_date current_default_transform_group current_path current_role current_row current_schema current_time current_timestamp current_transform_group_for_type current_user cursor cursor_name cycle data database datalink datetime_interval_code datetime_interval_precision day db deallocate dec declare default defaults deferrable deferred defined definer degree delimiter delimiters dense_rank depth deref derived describe descriptor deterministic diagnostics dictionary disable discard disconnect dispatch dlnewcopy dlpreviouscopy dlurlcomplete dlurlcompleteonly dlurlcompletewrite dlurlpath dlurlpathonly dlurlpathwrite dlurlscheme dlurlserver dlvalue do document domain dynamic dynamic_function dynamic_function_code each element else empty enable encoding encrypted end end-exec end_frame end_partition enforced enum equals escape event every except exception exclude excluding exclusive exec execute exists exp explain expression extension external extract false family fetch file filter final first first_value flag float floor following for force foreign fortran forward found frame_row free freeze fs full function functions fusion g general generated get global go goto grant granted greatest grouping groups handler header hex hierarchy hold hour id identity if ignore ilike immediate immediately immutable implementation implicit import including increment indent index indexes indicator inherit inherits initially inline inner inout input insensitive instance instantiable instead integrity intersect intersection invoker isnull isolation k key key_member key_type label lag language large last last_value lateral lead leading leakproof least left length level library like_regex link listen ln load local localtime localtimestamp location locator lock locked logged lower m map mapping match matched materialized max maxvalue max_cardinality member merge message_length message_octet_length message_text method min minute minvalue mod mode modifies module month more move multiset mumps name names namespace national natural nchar nclob nesting new next nfc nfd nfkc nfkd nil no none normalize normalized nothing notify notnull nowait nth_value ntile null nullable nullif nulls number object occurrences_regex octets octet_length of off offset oids old only open operator option options ordering ordinality others out outer output over overlaps overlay overriding owned owner p pad parameter parameter_mode parameter_name parameter_ordinal_position parameter_specific_catalog parameter_specific_name parameter_specific_schema parser partial partition pascal passing passthrough password percent percentile_cont percentile_disc percent_rank period permission placing plans pli policy portion position position_regex power precedes preceding prepare prepared preserve primary prior privileges procedural procedure program public quote range rank read reads reassign recheck recovery recursive ref references referencing refresh regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy regr_syy reindex relative release rename repeatable replace replica requiring reset respect restart restore restrict result return returned_cardinality returned_length returned_octet_length returned_sqlstate returning returns revoke right role rollback rollup routine routine_catalog routine_name routine_schema row rows row_count row_number rule savepoint scale schema schema_name scope scope_catalog scope_name scope_schema scroll search second section security selective self sensitive sequence sequences serializable server server_name session session_user setof sets share show similar simple size skip snapshot some source space specific specifictype specific_name sql sqlcode sqlerror sqlexception sqlstate sqlwarning sqrt stable standalone start state statement static statistics stddev_pop stddev_samp stdin stdout storage strict strip structure style subclass_origin submultiset substring substring_regex succeeds sum symmetric sysid system system_time system_user t tables tablesample tablespace table_name temp template temporary then ties timezone_hour timezone_minute to token top_level_count trailing transaction transactions_committed transactions_rolled_back transaction_active transform transforms translate translate_regex translation treat trigger trigger_catalog trigger_name trigger_schema trim trim_array true truncate trusted type types uescape unbounded uncommitted under unencrypted unique unknown unlink unlisten unlogged unnamed unnest until untyped upper uri usage user user_defined_type_catalog user_defined_type_code user_defined_type_name user_defined_type_schema using vacuum valid validate validator value value_of varbinary variadic var_pop var_samp verbose version versioning view views volatile when whenever whitespace width_bucket window within work wrapper write xmlagg xmlattributes xmlbinary xmlcast xmlcomment xmlconcat xmldeclaration xmldocument xmlelement xmlexists xmlforest xmliterate xmlnamespaces xmlparse xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltext xmlvalidate year yes loop repeat\"),\n    // http://www.postgresql.org/docs/9.5/static/datatype.html\n    builtin: set(\"bigint int8 bigserial serial8 bit varying varbit boolean bool box bytea character char varchar cidr circle date double precision float8 inet integer int int4 interval json jsonb line lseg macaddr money numeric decimal path pg_lsn point polygon real float4 smallint int2 smallserial serial2 serial serial4 text time without zone with timetz timestamp timestamptz tsquery tsvector txid_snapshot uuid xml\"),\n    atoms: set(\"false true null unknown\"),\n    operatorChars: /^[*+\\-%<>!=&|^\\/#@?~]/,\n    dateSQL: set(\"date time timestamp\"),\n    support: set(\"ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber nCharCast charsetCast\")\n  });\n\n  // Google's SQL-like query language, GQL\n  CodeMirror.defineMIME(\"text/x-gql\", {\n    name: \"sql\",\n    keywords: set(\"ancestor and asc by contains desc descendant distinct from group has in is limit offset on order select superset where\"),\n    atoms: set(\"false true\"),\n    builtin: set(\"blob datetime first key __key__ string integer double boolean null\"),\n    operatorChars: /^[*+\\-%<>!=]/\n  });\n}());\n\n});\n\n/*\n  How Properties of Mime Types are used by SQL Mode\n  =================================================\n\n  keywords:\n    A list of keywords you want to be highlighted.\n  builtin:\n    A list of builtin types you want to be highlighted (if you want types to be of class \"builtin\" instead of \"keyword\").\n  operatorChars:\n    All characters that must be handled as operators.\n  client:\n    Commands parsed and executed by the client (not the server).\n  support:\n    A list of supported syntaxes which are not common, but are supported by more than 1 DBMS.\n    * ODBCdotTable: .tableName\n    * zerolessFloat: .1\n    * doubleQuote\n    * nCharCast: N'string'\n    * charsetCast: _utf8'string'\n    * commentHash: use # char for comments\n    * commentSlashSlash: use // for comments\n    * commentSpaceRequired: require a space after -- for comments\n  atoms:\n    Keywords that must be highlighted as atoms,. Some DBMS's support more atoms than others:\n    UNKNOWN, INFINITY, UNDERFLOW, NaN...\n  dateSQL:\n    Used for date/time SQL standard syntax, because not all DBMS's support same temporal types.\n*/\n"
  },
  {
    "path": "static/CodeMirror/theme/eclipse.css",
    "content": ".cm-s-eclipse span.cm-meta { color: #FF1717; }\n.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; }\n.cm-s-eclipse span.cm-atom { color: #219; }\n.cm-s-eclipse span.cm-number { color: #164; }\n.cm-s-eclipse span.cm-def { color: #00f; }\n.cm-s-eclipse span.cm-variable { color: black; }\n.cm-s-eclipse span.cm-variable-2 { color: #0000C0; }\n.cm-s-eclipse span.cm-variable-3 { color: #0000C0; }\n.cm-s-eclipse span.cm-property { color: black; }\n.cm-s-eclipse span.cm-operator { color: black; }\n.cm-s-eclipse span.cm-comment { color: #3F7F5F; }\n.cm-s-eclipse span.cm-string { color: #2A00FF; }\n.cm-s-eclipse span.cm-string-2 { color: #f50; }\n.cm-s-eclipse span.cm-qualifier { color: #555; }\n.cm-s-eclipse span.cm-builtin { color: #30a; }\n.cm-s-eclipse span.cm-bracket { color: #cc7; }\n.cm-s-eclipse span.cm-tag { color: #170; }\n.cm-s-eclipse span.cm-attribute { color: #00c; }\n.cm-s-eclipse span.cm-link { color: #219; }\n.cm-s-eclipse span.cm-error { color: #f00; }\n\n.cm-s-eclipse .CodeMirror-activeline-background { background: #e8f2ff; }\n.cm-s-eclipse .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; }\n"
  },
  {
    "path": "static/check/css/admin/jquery.dataTables.css",
    "content": "/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: collapse;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n  outline: none;\n}\ntable.dataTable thead th,\ntable.dataTable thead td {\n  padding: 10px 18px !important;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 10px 18px 6px 18px;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc {\n  cursor: pointer;\n  *cursor: hand;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"../../images/tab/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"../../images/tab/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"../../images/tab/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"../../images/tab/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"../../images/tab/sort_desc_disabled.png\");\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 18px !important;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #abb9d3;\n}\ntable.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n  background-color: whitesmoke;\n}\ntable.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n  background-color: #a9b7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #f9f9f9;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad4;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b3cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a7b5ce;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b6d0;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #f9f9f9;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fbfbfb;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fdfdfd;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad4;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #adbbd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n  background-color: #ebebeb;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n  background-color: #eeeeee;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n  background-color: #a1aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n  background-color: #a2afc8;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n  background-color: #a4b2cb;\n}\ntable.dataTable.no-footer {\n  border-bottom: 1px solid #111;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 4px 17px 4px 4px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 4px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  -webkit-box-sizing: content-box;\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left; margin-left: 15px;\n  margin-top: 5px;\n}\n.dataTables_length {\n\tpadding-top: 0.755em;\n}\n.dataTables_info{margin-top:10px;}\n.dataTables_length label{font-weight: normal;}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n\n/*源自dataTables.bootstrap.min.css*/\n.dataTables_wrapper .dataTables_filter label {\n\tfont-weight: normal;\n\twhite-space: nowrap;\n\ttext-align: left\n}\n\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n  display: inline-block;\n  width: auto\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.755em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n  padding-top: 0.25em;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  box-sizing: border-box;\n  min-width: 1.5em;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n  outline: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  color: #333 !important;\n  border: 1px solid #cacaca;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n  cursor: default;\n  color: #666 !important;\n  border: 1px solid transparent;\n  background: transparent;\n  box-shadow: none;\n  outline: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  outline: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  outline: none;\n  \n}\n.pagination>li:active,\n.pagination>li>a:active{\n\toutline: none !important;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {\n  height: 0;\n  overflow: hidden;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: 1px solid #111;\n}\n.dataTables_wrapper.no-footer div.dataTables_scrollHead table,\n.dataTables_wrapper.no-footer div.dataTables_scrollBody table {\n  border-bottom: none;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em;\n  }\n}\n.p310{padding:2px 10px;}\n.pl0{padding-left: 0px;}\n.rboor{margin-top:-5px;}\n"
  },
  {
    "path": "static/check/css/admin/style.css",
    "content": "/* @import url(\"http://fonts.useso.com/css?family=Open+Sans:300,400,600,700&amp;lang=en\");\n@import url(\"http://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700&lang=en\"); */\n/*\n *\n *   H+ - Admin Theme\n *   version 2.2.0\n *\n*/\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n  font-weight: 100;\n}\nh1 {\n  font-size: 30px;\n}\nh2 {\n  font-size: 24px;\n}\nh3 {\n  font-size: 16px;\n}\nh4 {\n  font-size: 14px;\n}\nh5 {\n  font-size: 12px;\n}\nh6 {\n  font-size: 10px;\n}\nh3,\nh4,\nh5 {\n  margin-top: 5px;\n  font-weight: 600;\n}\n\n.nav > li > a {\n  color: #a7b1c2;\n  font-weight: 600;\n  padding: 14px 20px 14px 25px;\n}\n.nav.navbar-right > li > a {\n  color: #999c9e;\n}\n.nav > li.active > a {\n  color: #ffffff;\n}\n.navbar-default .nav > li > a:hover,\n.navbar-default .nav > li > a:focus {\n  background-color: #293846;\n  color: white;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n  background: #fff;\n}\n.nav.navbar-top-links > li > a:hover,\n.nav.navbar-top-links > li > a:focus {\n  background-color: transparent;\n}\n.nav > li > a i {\n  margin-right: 6px;\n}\n.navbar {\n  border: 0;\n}\n.navbar-default {\n  background-color: transparent;\n  border-color: #2f4050;\n}\n.navbar-top-links li {\n  display: inline-block;\n}\n.navbar-top-links li:last-child {\n  margin-right: 40px;\n}\n\nbody.body-small .navbar-top-links li:last-child {\n    margin-right: 10px;\n}\n.navbar-top-links li a {\n  padding: 20px 10px;\n  min-height: 50px;\n}\n.dropdown-menu {\n  border: medium none;\n  border-radius: 3px;\n  box-shadow: 0 0 3px rgba(86, 96, 117, 0.7);\n  display: none;\n  float: left;\n  font-size: 12px;\n  left: 0;\n  list-style: none outside none;\n  padding: 0;\n  position: absolute;\n  text-shadow: none;\n  top: 100%;\n  z-index: 1000;\n}\n.dropdown-menu > li > a {\n  border-radius: 3px;\n  color: inherit;\n  line-height: 25px;\n  margin: 4px;\n  text-align: left;\n  font-weight: normal;\n}\n.dropdown-menu > li > a.font-bold {\n  font-weight: 600;\n}\n.navbar-top-links .dropdown-menu li {\n  display: block;\n}\n.navbar-top-links .dropdown-menu li:last-child {\n  margin-right: 0;\n}\n.navbar-top-links .dropdown-menu li a {\n  padding: 3px 20px;\n  min-height: 0;\n}\n.navbar-top-links .dropdown-menu li a div {\n  white-space: normal;\n}\n.navbar-top-links .dropdown-messages,\n.navbar-top-links .dropdown-tasks,\n.navbar-top-links .dropdown-alerts {\n  width: 310px;\n  min-width: 0;\n}\n.navbar-top-links .dropdown-messages {\n  margin-left: 5px;\n}\n.navbar-top-links .dropdown-tasks {\n  margin-left: -59px;\n}\n.navbar-top-links .dropdown-alerts {\n  margin-left: -123px;\n}\n.navbar-top-links .dropdown-user {\n  right: 0;\n  left: auto;\n}\n.dropdown-messages,\n.dropdown-alerts {\n  padding: 10px 10px 10px 10px;\n}\n.dropdown-messages li a,\n.dropdown-alerts li a {\n  font-size: 12px;\n}\n.dropdown-messages li em,\n.dropdown-alerts li em {\n  font-size: 10px;\n}\n.nav.navbar-top-links .dropdown-alerts a {\n  font-size: 12px;\n}\n.nav-header {\n  padding: 33px 25px;\n  background: url(\"patterns/header-profile.png\") no-repeat;\n}\n.pace-done .nav-header {\n  transition: all 0.5s;\n}\n.nav > li.active {\n  border-left: 4px solid #19aa8d;\n  background: #293846;\n}\n.nav.nav-second-level > li.active {\n  border: none;\n}\n.nav.nav-second-level.collapse[style] {\n  height: auto !important;\n}\n.nav-header a {\n  color: #DFE4ED;\n}\n.nav-header .text-muted {\n  color: #8095a8;\n}\n.minimalize-styl-2 {\n  padding: 4px 12px;\n  margin: 14px 5px 5px 20px;\n  font-size: 14px;\n  float: left;\n}\n.navbar-form-custom {\n  float: left;\n  height: 50px;\n  padding: 0;\n  width: 200px;\n  display: inline-table;\n}\n.navbar-form-custom .form-group {\n  margin-bottom: 0;\n}\n.nav.navbar-top-links a {\n  font-size: 14px;\n}\n.navbar-form-custom .form-control {\n  background: none repeat scroll 0 0 rgba(0, 0, 0, 0);\n  border: medium none;\n  font-size: 14px;\n  height: 60px;\n  margin: 0;\n  z-index: 2000;\n}\n.count-info .label {\n  line-height: 12px;\n  padding: 2px 5px;\n  position: absolute;\n  right: 6px;\n  top: 12px;\n}\n.arrow {\n  float: right;\n}\n.fa.arrow:before {\n  content: \"\\f104\";\n}\n.active > a > .fa.arrow:before {\n  content: \"\\f107\";\n}\n.nav-second-level li,\n.nav-third-level li {\n  border-bottom: none !important;\n}\n.nav-second-level li a {\n  padding: 7px 10px 7px 10px;\n  padding-left: 52px;\n}\n.nav-third-level li a {\n  padding-left: 62px;\n}\n.nav-second-level li:last-child {\n  margin-bottom: 10px;\n}\nbody:not(.fixed-sidebar):not(.canvas-menu).mini-navbar .nav li:hover > .nav-second-level,\n.mini-navbar .nav li:focus > .nav-second-level {\n  display: block;\n  border-radius: 0 2px 2px 0;\n  min-width: 140px;\n  height: auto;\n}\nbody.mini-navbar .navbar-default .nav > li > .nav-second-level li a {\n  font-size: 12px;\n  border-radius: 3px;\n}\n.fixed-nav .slimScrollDiv #side-menu {\n  padding-bottom: 60px;\n}\n.mini-navbar .nav-second-level li a {\n  padding: 10px 10px 10px 15px;\n}\n.mini-navbar .nav-second-level {\n  position: absolute;\n  left: 70px;\n  top: 0px;\n  background-color: #2f4050;\n  padding: 10px 10px 10px 10px;\n  font-size: 12px;\n}\n.canvas-menu.mini-navbar .nav-second-level {\n  background: #293846;\n}\n.mini-navbar li.active .nav-second-level {\n  left: 65px;\n}\n.navbar-default .special_link a {\n  background: #007bff;\n  color: white;\n}\n.navbar-default .special_link a:hover {\n  background: #17987e !important;\n  color: white;\n}\n.navbar-default .special_link a span.label {\n  background: #fff;\n  color: #007bff;\n}\n.navbar-default .landing_link a {\n  background: #1cc09f;\n  color: white;\n}\n.navbar-default .landing_link a:hover {\n  background: #007bff !important;\n  color: white;\n}\n.navbar-default .landing_link a span.label {\n  background: #fff;\n  color: #1cc09f;\n}\n.logo-element {\n  text-align: center;\n  font-size: 18px;\n  font-weight: 600;\n  color: white;\n  display: none;\n  padding: 18px 0;\n}\n.pace-done .navbar-static-side,\n.pace-done .nav-header,\n.pace-done li.active,\n.pace-done #page-wrapper,\n.pace-done .footer {\n  -webkit-transition: all 0.5s;\n  -moz-transition: all 0.5s;\n  -o-transition: all 0.5s;\n  transition: all 0.5s;\n}\n.navbar-fixed-top {\n  background: #fff;\n  transition-duration: 0.5s;\n  border-bottom: 1px solid #e7eaec !important;\n  z-index: 2030;\n}\n.navbar-fixed-top,\n.navbar-static-top {\n  background: #f3f3f4;\n}\n.fixed-nav #wrapper {\n  margin-top: 60px;\n}\n.fixed-nav .minimalize-styl-2 {\n  margin: 14px 5px 5px 15px;\n}\n.body-small .navbar-fixed-top {\n  margin-left: 0px;\n}\nbody.mini-navbar .navbar-static-side {\n  width: 70px;\n}\nbody.mini-navbar .profile-element,\nbody.mini-navbar .nav-label,\nbody.mini-navbar .navbar-default .nav li a span {\n  display: none;\n}\nbody.canvas-menu .profile-element {\n  display: block;\n}\nbody:not(.fixed-sidebar):not(.canvas-menu).mini-navbar .nav-second-level {\n  display: none;\n}\nbody.mini-navbar .navbar-default .nav > li > a {\n  font-size: 16px;\n}\nbody.mini-navbar .logo-element {\n  display: block;\n}\nbody.canvas-menu .logo-element {\n  display: none;\n}\nbody.mini-navbar .nav-header {\n  padding: 0;\n  background-color: #007bff;\n}\nbody.canvas-menu .nav-header {\n  padding: 33px 25px;\n}\nbody.mini-navbar #page-wrapper {\n  margin: 0 0 0 70px;\n}\nbody.fixed-sidebar.mini-navbar .footer,\nbody.canvas-menu.mini-navbar .footer {\n  margin: 0 0 0 0 !important;\n}\nbody.canvas-menu.mini-navbar #page-wrapper,\nbody.canvas-menu.mini-navbar .footer {\n  margin: 0 0 0 0;\n}\nbody.fixed-sidebar .navbar-static-side,\nbody.canvas-menu .navbar-static-side {\n  position: fixed;\n  width: 220px;\n  z-index: 2001;\n  height: 100%;\n}\nbody.fixed-sidebar.mini-navbar .navbar-static-side {\n  width: 0px;\n}\nbody.fixed-sidebar.mini-navbar #page-wrapper {\n  margin: 0 0 0 0px;\n}\nbody.body-small.fixed-sidebar.mini-navbar #page-wrapper {\n  margin: 0 0 0 220px;\n}\nbody.body-small.fixed-sidebar.mini-navbar .navbar-static-side {\n  width: 220px;\n}\n.fixed-sidebar.mini-navbar .nav li:focus > .nav-second-level,\n.canvas-menu.mini-navbar .nav li:focus > .nav-second-level {\n  display: block;\n  height: auto;\n}\nbody.fixed-sidebar.mini-navbar .navbar-default .nav > li > .nav-second-level li a {\n  font-size: 12px;\n  border-radius: 3px;\n}\nbody.canvas-menu.mini-navbar .navbar-default .nav > li > .nav-second-level li a {\n  font-size: 13px;\n  border-radius: 3px;\n}\n.fixed-sidebar.mini-navbar .nav-second-level li a,\n.canvas-menu.mini-navbar .nav-second-level li a {\n  padding: 10px 10px 10px 15px;\n}\n.fixed-sidebar.mini-navbar .nav-second-level,\n.canvas-menu.mini-navbar .nav-second-level {\n  position: relative;\n  padding: 0;\n  font-size: 13px;\n}\n.fixed-sidebar.mini-navbar li.active .nav-second-level,\n.canvas-menu.mini-navbar li.active .nav-second-level {\n  left: 0px;\n}\nbody.fixed-sidebar.mini-navbar .navbar-default .nav > li > a,\nbody.canvas-menu.mini-navbar .navbar-default .nav > li > a {\n  font-size: 13px;\n}\nbody.fixed-sidebar.mini-navbar .nav-label,\nbody.fixed-sidebar.mini-navbar .navbar-default .nav li a span,\nbody.canvas-menu.mini-navbar .nav-label,\nbody.canvas-menu.mini-navbar .navbar-default .nav li a span {\n  display: inline;\n}\nbody.canvas-menu.mini-navbar .navbar-default .nav li .profile-element a span {\n  display: block;\n}\n.canvas-menu.mini-navbar .nav-second-level li a,\n.fixed-sidebar.mini-navbar .nav-second-level li a {\n  padding: 7px 10px 7px 52px;\n}\n.fixed-sidebar.mini-navbar .nav-second-level,\n.canvas-menu.mini-navbar .nav-second-level {\n  left: 0px;\n}\nbody.canvas-menu nav.navbar-static-side {\n  z-index: 2001;\n  background: #2f4050;\n  height: 100%;\n  position: fixed;\n  display: none;\n}\nbody.canvas-menu.mini-navbar nav.navbar-static-side {\n  display: block;\n  width: 220px;\n}\n.top-navigation #page-wrapper {\n  margin-left: 0;\n}\n.top-navigation .navbar-nav .dropdown-menu > .active > a {\n  background: white;\n  color: #007bff;\n  font-weight: bold;\n}\n.white-bg .navbar-fixed-top,\n.white-bg .navbar-static-top {\n  background: #fff;\n}\n.top-navigation .navbar {\n  margin-bottom: 0;\n}\n.top-navigation .nav > li > a {\n  padding: 15px 20px;\n  color: #676a6c;\n}\n.top-navigation .nav > li a:hover,\n.top-navigation .nav > li a:focus {\n  background: #fff;\n  color: #007bff;\n}\n.top-navigation .nav > li.active {\n  background: #fff;\n  border: none;\n}\n.top-navigation .nav > li.active > a {\n  color: #007bff;\n}\n.top-navigation .navbar-right {\n  margin-right: 10px;\n}\n.top-navigation .navbar-nav .dropdown-menu {\n  box-shadow: none;\n  border: 1px solid #e7eaec;\n}\n.top-navigation .dropdown-menu > li > a {\n  margin: 0;\n  padding: 7px 20px;\n}\n.navbar .dropdown-menu {\n  margin-top: 0px;\n}\n.top-navigation .navbar-brand {\n  background: #007bff;\n  color: #fff;\n  padding: 15px 25px;\n}\n.top-navigation .navbar-top-links li:last-child {\n  margin-right: 0;\n}\n.top-navigation.mini-navbar #page-wrapper,\n.top-navigation.body-small.fixed-sidebar.mini-navbar #page-wrapper,\n.mini-navbar .top-navigation #page-wrapper,\n.body-small.fixed-sidebar.mini-navbar .top-navigation #page-wrapper,\n.canvas-menu #page-wrapper {\n  margin: 0;\n}\n.top-navigation.fixed-nav #wrapper,\n.fixed-nav #wrapper.top-navigation {\n  margin-top: 50px;\n}\n.top-navigation .footer.fixed {\n  margin-left: 0 !important;\n}\n.top-navigation .wrapper.wrapper-content {\n  padding: 40px;\n}\n.top-navigation.body-small .wrapper.wrapper-content,\n.body-small .top-navigation .wrapper.wrapper-content {\n  padding: 40px 0px 40px 0px;\n}\n.navbar-toggle {\n  background-color: #007bff;\n  color: #fff;\n  padding: 6px 12px;\n  font-size: 14px;\n}\n.top-navigation .navbar-nav .open .dropdown-menu > li > a,\n.top-navigation .navbar-nav .open .dropdown-menu .dropdown-header {\n  padding: 10px 15px 10px 20px;\n}\n@media (max-width: 768px) {\n  .top-navigation .navbar-header {\n    display: block;\n    float: none;\n  }\n}\n.menu-visible-lg,\n.menu-visible-md {\n  display: none !important;\n}\n@media (min-width: 1200px) {\n  .menu-visible-lg {\n    display: block !important;\n  }\n}\n@media (min-width: 992px) {\n  .menu-visible-md {\n    display: block !important;\n  }\n}\n@media (max-width: 767px) {\n  .menu-visible-md {\n    display: block !important;\n  }\n  .menu-visible-lg {\n    display: block !important;\n  }\n}\n.btn {\n  border-radius: 3px;\n}\n.float-e-margins .btn {\n  margin-bottom: 5px;\n}\n.btn-w-m {\n  min-width: 120px;\n}\n.btn-primary.btn-outline {\n  color: #007bff;\n}\n.btn-success.btn-outline {\n  color: #007bff;\n}\n.btn-info.btn-outline {\n  color: #007bff;\n}\n.btn-warning.btn-outline {\n  color: #f8ac59;\n}\n.btn-danger.btn-outline {\n  color: #ed5565;\n}\n.btn-primary.btn-outline:hover,\n.btn-success.btn-outline:hover,\n.btn-info.btn-outline:hover,\n.btn-warning.btn-outline:hover,\n.btn-danger.btn-outline:hover {\n  color: #fff;\n}\n.btn-primary {\n  background-color: #007bff;\n  border-color: #007bff;\n  color: #FFFFFF;\n}\n.btn-primary:hover,\n.btn-primary:focus,\n.btn-primary:active,\n.btn-primary.active,\n.open .dropdown-toggle.btn-primary {\n  background-color: #007bff;\n  border-color: #007bff;\n  color: #FFFFFF;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open .dropdown-toggle.btn-primary {\n  background-image: none;\n}\n.btn-primary.disabled,\n.btn-primary.disabled:hover,\n.btn-primary.disabled:focus,\n.btn-primary.disabled:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled],\n.btn-primary[disabled]:hover,\n.btn-primary[disabled]:focus,\n.btn-primary[disabled]:active,\n.btn-primary.active[disabled],\nfieldset[disabled] .btn-primary,\nfieldset[disabled] .btn-primary:hover,\nfieldset[disabled] .btn-primary:focus,\nfieldset[disabled] .btn-primary:active,\nfieldset[disabled] .btn-primary.active {\n  background-color: #007bff;\n  border-color: #007bff;\n}\n.btn-success {\n  background-color: #007bff;\n  border-color: #007bff;\n  color: #FFFFFF;\n}\n.btn-success:hover,\n.btn-success:focus,\n.btn-success:active,\n.btn-success.active,\n.open .dropdown-toggle.btn-success {\n  background-color: #007bff;\n  border-color: #007bff;\n  color: #FFFFFF;\n}\n.btn-success:active,\n.btn-success.active,\n.open .dropdown-toggle.btn-success {\n  background-image: none;\n}\n.btn-success.disabled,\n.btn-success.disabled:hover,\n.btn-success.disabled:focus,\n.btn-success.disabled:active,\n.btn-success.disabled.active,\n.btn-success[disabled],\n.btn-success[disabled]:hover,\n.btn-success[disabled]:focus,\n.btn-success[disabled]:active,\n.btn-success.active[disabled],\nfieldset[disabled] .btn-success,\nfieldset[disabled] .btn-success:hover,\nfieldset[disabled] .btn-success:focus,\nfieldset[disabled] .btn-success:active,\nfieldset[disabled] .btn-success.active {\n  background-color: #007bff;\n  border-color: #007bff;\n}\n.btn-info {\n  background-color: #007bff;\n  border-color: #007bff;\n  color: #FFFFFF;\n}\n.btn-info:hover,\n.btn-info:focus,\n.btn-info:active,\n.btn-info.active,\n.open .dropdown-toggle.btn-info {\n  background-color: #007bff;\n  border-color: #007bff;\n  color: #FFFFFF;\n}\n.btn-info:active,\n.btn-info.active,\n.open .dropdown-toggle.btn-info {\n  background-image: none;\n}\n.btn-info.disabled,\n.btn-info.disabled:hover,\n.btn-info.disabled:focus,\n.btn-info.disabled:active,\n.btn-info.disabled.active,\n.btn-info[disabled],\n.btn-info[disabled]:hover,\n.btn-info[disabled]:focus,\n.btn-info[disabled]:active,\n.btn-info.active[disabled],\nfieldset[disabled] .btn-info,\nfieldset[disabled] .btn-info:hover,\nfieldset[disabled] .btn-info:focus,\nfieldset[disabled] .btn-info:active,\nfieldset[disabled] .btn-info.active {\n  background-color: #007bff;\n  border-color: #007bff;\n}\n.btn-default {\n  background-color: #c2c2c2;\n  border-color: #c2c2c2;\n  color: #FFFFFF;\n}\n.btn-default:hover,\n.btn-default:focus,\n.btn-default:active,\n.btn-default.active,\n.open .dropdown-toggle.btn-default {\n  background-color: #bababa;\n  border-color: #bababa;\n  color: #FFFFFF;\n}\n.btn-default:active,\n.btn-default.active,\n.open .dropdown-toggle.btn-default {\n  background-image: none;\n}\n.btn-default.disabled,\n.btn-default.disabled:hover,\n.btn-default.disabled:focus,\n.btn-default.disabled:active,\n.btn-default.disabled.active,\n.btn-default[disabled],\n.btn-default[disabled]:hover,\n.btn-default[disabled]:focus,\n.btn-default[disabled]:active,\n.btn-default.active[disabled],\nfieldset[disabled] .btn-default,\nfieldset[disabled] .btn-default:hover,\nfieldset[disabled] .btn-default:focus,\nfieldset[disabled] .btn-default:active,\nfieldset[disabled] .btn-default.active {\n  background-color: #cccccc;\n  border-color: #cccccc;\n}\n.btn-warning {\n  background-color: #f8ac59;\n  border-color: #f8ac59;\n  color: #FFFFFF;\n}\n.btn-warning:hover,\n.btn-warning:focus,\n.btn-warning:active,\n.btn-warning.active,\n.open .dropdown-toggle.btn-warning {\n  background-color: #f7a54a;\n  border-color: #f7a54a;\n  color: #FFFFFF;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open .dropdown-toggle.btn-warning {\n  background-image: none;\n}\n.btn-warning.disabled,\n.btn-warning.disabled:hover,\n.btn-warning.disabled:focus,\n.btn-warning.disabled:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled],\n.btn-warning[disabled]:hover,\n.btn-warning[disabled]:focus,\n.btn-warning[disabled]:active,\n.btn-warning.active[disabled],\nfieldset[disabled] .btn-warning,\nfieldset[disabled] .btn-warning:hover,\nfieldset[disabled] .btn-warning:focus,\nfieldset[disabled] .btn-warning:active,\nfieldset[disabled] .btn-warning.active {\n  background-color: #f9b66d;\n  border-color: #f9b66d;\n}\n.btn-danger {\n  background-color: #ed5565;\n  border-color: #ed5565;\n  color: #FFFFFF;\n}\n.btn-danger:hover,\n.btn-danger:focus,\n.btn-danger:active,\n.btn-danger.active,\n.open .dropdown-toggle.btn-danger {\n  background-color: #ec4758;\n  border-color: #ec4758;\n  color: #FFFFFF;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open .dropdown-toggle.btn-danger {\n  background-image: none;\n}\n.btn-danger.disabled,\n.btn-danger.disabled:hover,\n.btn-danger.disabled:focus,\n.btn-danger.disabled:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled],\n.btn-danger[disabled]:hover,\n.btn-danger[disabled]:focus,\n.btn-danger[disabled]:active,\n.btn-danger.active[disabled],\nfieldset[disabled] .btn-danger,\nfieldset[disabled] .btn-danger:hover,\nfieldset[disabled] .btn-danger:focus,\nfieldset[disabled] .btn-danger:active,\nfieldset[disabled] .btn-danger.active {\n  background-color: #ef6776;\n  border-color: #ef6776;\n}\n.btn-link {\n  color: inherit;\n}\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active,\n.btn-link.active,\n.open .dropdown-toggle.btn-link {\n  color: #007bff;\n  text-decoration: none;\n}\n.btn-link:active,\n.btn-link.active,\n.open .dropdown-toggle.btn-link {\n  background-image: none;\n}\n.btn-link.disabled,\n.btn-link.disabled:hover,\n.btn-link.disabled:focus,\n.btn-link.disabled:active,\n.btn-link.disabled.active,\n.btn-link[disabled],\n.btn-link[disabled]:hover,\n.btn-link[disabled]:focus,\n.btn-link[disabled]:active,\n.btn-link.active[disabled],\nfieldset[disabled] .btn-link,\nfieldset[disabled] .btn-link:hover,\nfieldset[disabled] .btn-link:focus,\nfieldset[disabled] .btn-link:active,\nfieldset[disabled] .btn-link.active {\n  color: #cacaca;\n}\n.btn-white {\n  color: inherit;\n  background: white;\n  border: 1px solid #e7eaec;\n}\n.btn-white:hover,\n.btn-white:focus,\n.btn-white:active,\n.btn-white.active,\n.open .dropdown-toggle.btn-white {\n  color: inherit;\n  border: 1px solid #d2d2d2;\n}\n.btn-white:active,\n.btn-white.active {\n  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15) inset;\n}\n.btn-white:active,\n.btn-white.active,\n.open .dropdown-toggle.btn-white {\n  background-image: none;\n}\n.btn-white.disabled,\n.btn-white.disabled:hover,\n.btn-white.disabled:focus,\n.btn-white.disabled:active,\n.btn-white.disabled.active,\n.btn-white[disabled],\n.btn-white[disabled]:hover,\n.btn-white[disabled]:focus,\n.btn-white[disabled]:active,\n.btn-white.active[disabled],\nfieldset[disabled] .btn-white,\nfieldset[disabled] .btn-white:hover,\nfieldset[disabled] .btn-white:focus,\nfieldset[disabled] .btn-white:active,\nfieldset[disabled] .btn-white.active {\n  color: #cacaca;\n}\n.form-control,\n.form-control:focus,\n.has-error .form-control:focus,\n.has-success .form-control:focus,\n.has-warning .form-control:focus,\n.navbar-collapse,\n.navbar-form,\n.navbar-form-custom .form-control:focus,\n.navbar-form-custom .form-control:hover,\n.open .btn.dropdown-toggle,\n.panel,\n.popover,\n.progress,\n.progress-bar {\n  box-shadow: none;\n}\n.btn-outline {\n  color: inherit;\n  background-color: transparent;\n  transition: all .5s;\n}\n.btn-rounded {\n  border-radius: 50px;\n}\n.btn-large-dim {\n  width: 90px;\n  height: 90px;\n  font-size: 42px;\n}\nbutton.dim {\n  display: inline-block;\n  color: #fff;\n  text-decoration: none;\n  text-transform: uppercase;\n  text-align: center;\n  padding-top: 6px;\n  margin-right: 10px;\n  position: relative;\n  cursor: pointer;\n  border-radius: 5px;\n  font-weight: 600;\n  margin-bottom: 20px !important;\n}\nbutton.dim:active {\n  top: 3px;\n}\nbutton.btn-primary.dim {\n  box-shadow: inset 0px 0px 0px #16987e, 0px 5px 0px 0px #16987e, 0px 10px 5px #999999;\n}\nbutton.btn-primary.dim:active {\n  box-shadow: inset 0px 0px 0px #16987e, 0px 2px 0px 0px #16987e, 0px 5px 3px #999999;\n}\nbutton.btn-default.dim {\n  box-shadow: inset 0px 0px 0px #b3b3b3, 0px 5px 0px 0px #b3b3b3, 0px 10px 5px #999999;\n}\nbutton.btn-default.dim:active {\n  box-shadow: inset 0px 0px 0px #b3b3b3, 0px 2px 0px 0px #b3b3b3, 0px 5px 3px #999999;\n}\nbutton.btn-warning.dim {\n  box-shadow: inset 0px 0px 0px #f79d3c, 0px 5px 0px 0px #f79d3c, 0px 10px 5px #999999;\n}\nbutton.btn-warning.dim:active {\n  box-shadow: inset 0px 0px 0px #f79d3c, 0px 2px 0px 0px #f79d3c, 0px 5px 3px #999999;\n}\nbutton.btn-info.dim {\n  box-shadow: inset 0px 0px 0px #1eacae, 0px 5px 0px 0px #1eacae, 0px 10px 5px #999999;\n}\nbutton.btn-info.dim:active {\n  box-shadow: inset 0px 0px 0px #1eacae, 0px 2px 0px 0px #1eacae, 0px 5px 3px #999999;\n}\nbutton.btn-success.dim {\n  box-shadow: inset 0px 0px 0px #1872ab, 0px 5px 0px 0px #1872ab, 0px 10px 5px #999999;\n}\nbutton.btn-success.dim:active {\n  box-shadow: inset 0px 0px 0px #1872ab, 0px 2px 0px 0px #1872ab, 0px 5px 3px #999999;\n}\nbutton.btn-danger.dim {\n  box-shadow: inset 0px 0px 0px #ea394c, 0px 5px 0px 0px #ea394c, 0px 10px 5px #999999;\n}\nbutton.btn-danger.dim:active {\n  box-shadow: inset 0px 0px 0px #ea394c, 0px 2px 0px 0px #ea394c, 0px 5px 3px #999999;\n}\nbutton.dim:before {\n  font-size: 50px;\n  line-height: 1em;\n  font-weight: normal;\n  color: #fff;\n  display: block;\n  padding-top: 10px;\n}\nbutton.dim:active:before {\n  top: 7px;\n  font-size: 50px;\n}\n.label {\n  background-color: #d1dade;\n  color: #5e5e5e;\n  font-family: 'Open Sans';\n  font-size: 10px;\n  font-weight: 600;\n  padding: 3px 8px;\n  text-shadow: none;\n}\n.badge {\n  background-color: #d1dade;\n  color: #5e5e5e;\n  font-family: 'Open Sans';\n  font-size: 11px;\n  font-weight: 600;\n  padding-bottom: 4px;\n  padding-left: 6px;\n  padding-right: 6px;\n  text-shadow: none;\n}\n.label-primary,\n.badge-primary {\n  background-color: #007bff;\n  color: #FFFFFF;\n}\n.label-success,\n.badge-success {\n  background-color: #007bff;\n  color: #FFFFFF;\n}\n.label-warning,\n.badge-warning {\n  background-color: #f8ac59;\n  color: #FFFFFF;\n}\n.label-warning-light,\n.badge-warning-light {\n  background-color: #f8ac59;\n  color: #ffffff;\n}\n.label-danger,\n.badge-danger {\n  background-color: #ed5565;\n  color: #FFFFFF;\n}\n.label-info,\n.badge-info {\n  background-color: #007bff;\n  color: #FFFFFF;\n}\n.label-inverse,\n.badge-inverse {\n  background-color: #262626;\n  color: #FFFFFF;\n}\n.label-white,\n.badge-white {\n  background-color: #FFFFFF;\n  color: #5E5E5E;\n}\n.label-white,\n.badge-disable {\n  background-color: #2A2E36;\n  color: #8B91A0;\n}\n/* TOOGLE SWICH */\n.onoffswitch {\n  position: relative;\n  width: 64px;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n}\n.onoffswitch-checkbox {\n  display: none;\n}\n.onoffswitch-label {\n  display: block;\n  overflow: hidden;\n  cursor: pointer;\n  border: 2px solid #007bff;\n  border-radius: 2px;\n}\n.onoffswitch-inner {\n  width: 200%;\n  margin-left: -100%;\n  -moz-transition: margin 0.3s ease-in 0s;\n  -webkit-transition: margin 0.3s ease-in 0s;\n  -o-transition: margin 0.3s ease-in 0s;\n  transition: margin 0.3s ease-in 0s;\n}\n.onoffswitch-inner:before,\n.onoffswitch-inner:after {\n  float: left;\n  width: 50%;\n  height: 20px;\n  padding: 0;\n  line-height: 20px;\n  font-size: 12px;\n  color: white;\n  font-family: Trebuchet, Arial, sans-serif;\n  font-weight: bold;\n  -moz-box-sizing: border-box;\n  -webkit-box-sizing: border-box;\n  box-sizing: border-box;\n}\n.onoffswitch-inner:before {\n  content: \"ON\";\n  padding-left: 10px;\n  background-color: #007bff;\n  color: #FFFFFF;\n}\n.onoffswitch-inner:after {\n  content: \"OFF\";\n  padding-right: 10px;\n  background-color: #FFFFFF;\n  color: #999999;\n  text-align: right;\n}\n.onoffswitch-switch {\n  width: 20px;\n  margin: 0px;\n  background: #FFFFFF;\n  border: 2px solid #007bff;\n  border-radius: 2px;\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  right: 44px;\n  -moz-transition: all 0.3s ease-in 0s;\n  -webkit-transition: all 0.3s ease-in 0s;\n  -o-transition: all 0.3s ease-in 0s;\n  transition: all 0.3s ease-in 0s;\n}\n.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {\n  margin-left: 0;\n}\n.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {\n  right: 0px;\n}\n/* CHOSEN PLUGIN */\n.chosen-container-single .chosen-single {\n  background: #ffffff;\n  box-shadow: none;\n  -moz-box-sizing: border-box;\n  background-color: #FFFFFF;\n  border: 1px solid #CBD5DD;\n  border-radius: 2px;\n  cursor: text;\n  height: auto !important;\n  margin: 0;\n  min-height: 30px;\n  overflow: hidden;\n  padding: 4px 12px;\n  position: relative;\n  width: 100%;\n}\n.chosen-container-multi .chosen-choices li.search-choice {\n  background: #f1f1f1;\n  border: 1px solid #ededed;\n  border-radius: 2px;\n  box-shadow: none;\n  color: #333333;\n  cursor: default;\n  line-height: 13px;\n  margin: 3px 0 3px 5px;\n  padding: 3px 20px 3px 5px;\n  position: relative;\n}\n/* PAGINATIN */\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n  background-color: #f4f4f4;\n  border-color: #DDDDDD;\n  color: inherit;\n  cursor: default;\n  z-index: 2;\n  outline: none;\n}\n.pagination > li > a,\n.pagination > li > span {\n  background-color: #FFFFFF;\n  border: 1px solid #DDDDDD;\n  color: inherit;\n  float: left;\n  line-height: 1.42857;\n  margin-left: -1px;\n  padding: 4px 10px;\n  position: relative;\n  text-decoration: none;\n}\n/* TOOLTIPS */\n.tooltip-inner {\n  background-color: #2F4050;\n}\n.tooltip.top .tooltip-arrow {\n  border-top-color: #2F4050;\n}\n.tooltip.right .tooltip-arrow {\n  border-right-color: #2F4050;\n}\n.tooltip.bottom .tooltip-arrow {\n  border-bottom-color: #2F4050;\n}\n.tooltip.left .tooltip-arrow {\n  border-left-color: #2F4050;\n}\n/* EASY PIE CHART*/\n.easypiechart {\n  position: relative;\n  text-align: center;\n}\n.easypiechart .h2 {\n  margin-left: 10px;\n  margin-top: 10px;\n  display: inline-block;\n}\n.easypiechart canvas {\n  top: 0;\n  left: 0;\n}\n.easypiechart .easypie-text {\n  line-height: 1;\n  position: absolute;\n  top: 33px;\n  width: 100%;\n  z-index: 1;\n}\n.easypiechart img {\n  margin-top: -4px;\n}\n.jqstooltip {\n  -webkit-box-sizing: content-box;\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n}\n/* FULLCALENDAR */\n.fc-state-default {\n  background-color: #ffffff;\n  background-image: none;\n  background-repeat: repeat-x;\n  box-shadow: none;\n  color: #333333;\n  text-shadow: none;\n}\n.fc-state-default {\n  border: 1px solid;\n}\n.fc-button {\n  color: inherit;\n  border: 1px solid #e7eaec;\n  cursor: pointer;\n  display: inline-block;\n  height: 1.9em;\n  line-height: 1.9em;\n  overflow: hidden;\n  padding: 0 0.6em;\n  position: relative;\n  white-space: nowrap;\n}\n.fc-state-active {\n  background-color: #007bff;\n  border-color: #007bff;\n  color: #ffffff;\n}\n.fc-header-title h2 {\n  font-size: 16px;\n  font-weight: 600;\n  color: inherit;\n}\n.fc-content .fc-widget-header,\n.fc-content .fc-widget-content {\n  border-color: #e7eaec;\n  font-weight: normal;\n}\n.fc-border-separate tbody {\n  background-color: #F8F8F8;\n}\n.fc-state-highlight {\n  background: none repeat scroll 0 0 #FCF8E3;\n}\n.external-event {\n  padding: 5px 10px;\n  border-radius: 2px;\n  cursor: pointer;\n  margin-bottom: 5px;\n}\n.fc-ltr .fc-event-hori.fc-event-end,\n.fc-rtl .fc-event-hori.fc-event-start {\n  border-radius: 2px;\n}\n.fc-event,\n.fc-agenda .fc-event-time,\n.fc-event a {\n  padding: 4px 6px;\n  background-color: #007bff;\n  /* background color */\n  border-color: #007bff;\n  /* border color */\n}\n.fc-event-time,\n.fc-event-title {\n  color: #717171;\n  padding: 0 1px;\n}\n.ui-calendar .fc-event-time,\n.ui-calendar .fc-event-title {\n  color: #fff;\n}\n/* Chat */\n.chat-activity-list .chat-element {\n  border-bottom: 1px solid #e7eaec;\n}\n.chat-element:first-child {\n  margin-top: 0;\n}\n.chat-element {\n  padding-bottom: 15px;\n}\n.chat-element,\n.chat-element .media {\n  margin-top: 15px;\n}\n.chat-element,\n.media-body {\n  overflow: hidden;\n}\n.media-body {\n  display: block;\n  width: auto;\n}\n.chat-element > .pull-left {\n  margin-right: 10px;\n}\n.chat-element img.img-circle,\n.dropdown-messages-box img.img-circle {\n  width: 38px;\n  height: 38px;\n}\n.chat-element .well {\n  border: 1px solid #e7eaec;\n  box-shadow: none;\n  margin-top: 10px;\n  margin-bottom: 5px;\n  padding: 10px 20px;\n  font-size: 11px;\n  line-height: 16px;\n}\n.chat-element .actions {\n  margin-top: 10px;\n}\n.chat-element .photos {\n  margin: 10px 0;\n}\n.right.chat-element > .pull-right {\n  margin-left: 10px;\n}\n.chat-photo {\n  max-height: 180px;\n  border-radius: 4px;\n  overflow: hidden;\n  margin-right: 10px;\n  margin-bottom: 10px;\n}\n.chat {\n  margin: 0;\n  padding: 0;\n  list-style: none;\n}\n.chat li {\n  margin-bottom: 10px;\n  padding-bottom: 5px;\n  border-bottom: 1px dotted #B3A9A9;\n}\n.chat li.left .chat-body {\n  margin-left: 60px;\n}\n.chat li.right .chat-body {\n  margin-right: 60px;\n}\n.chat li .chat-body p {\n  margin: 0;\n  color: #777777;\n}\n.panel .slidedown .glyphicon,\n.chat .glyphicon {\n  margin-right: 5px;\n}\n.chat-panel .panel-body {\n  height: 350px;\n  overflow-y: scroll;\n}\n/* LIST GROUP */\na.list-group-item.active,\na.list-group-item.active:hover,\na.list-group-item.active:focus {\n  background-color: #007bff;\n  border-color: #007bff;\n  color: #FFFFFF;\n  z-index: 2;\n}\n.list-group-item-heading {\n  margin-top: 10px;\n}\n.list-group-item-text {\n  margin: 0 0 10px;\n  color: inherit;\n  font-size: 12px;\n  line-height: inherit;\n}\n.no-padding .list-group-item {\n  border-left: none;\n  border-right: none;\n  border-bottom: none;\n}\n.no-padding .list-group-item:first-child {\n  border-left: none;\n  border-right: none;\n  border-bottom: none;\n  border-top: none;\n}\n.no-padding .list-group {\n  margin-bottom: 0;\n}\n.list-group-item {\n  background-color: inherit;\n  border: 1px solid #e7eaec;\n  display: block;\n  margin-bottom: -1px;\n  padding: 10px 15px;\n  position: relative;\n}\n.elements-list .list-group-item {\n  border-left: none;\n  border-right: none;\n  /*border-top: none;*/\n  padding: 15px 25px;\n}\n.elements-list .list-group-item:first-child {\n  border-left: none;\n  border-right: none;\n  border-top: none !important;\n}\n.elements-list .list-group {\n  margin-bottom: 0;\n}\n.elements-list a {\n  color: inherit;\n}\n.elements-list .list-group-item.active,\n.elements-list .list-group-item:hover {\n  background: #f3f3f4;\n  color: inherit;\n  border-color: #e7eaec;\n  /*border-bottom: 1px solid #e7eaec;*/\n  /*border-top: 1px solid #e7eaec;*/\n  border-radius: 0;\n}\n.elements-list li.active {\n  transition: none;\n}\n.element-detail-box {\n  padding: 25px;\n}\n/* FLOT CHART  */\n.flot-chart {\n  display: block;\n  height: 200px;\n}\n.widget .flot-chart.dashboard-chart {\n  display: block;\n  height: 120px;\n  margin-top: 40px;\n}\n.flot-chart.dashboard-chart {\n  display: block;\n  height: 180px;\n  margin-top: 40px;\n}\n.flot-chart-content {\n  width: 100%;\n  height: 100%;\n}\n.flot-chart-pie-content {\n  width: 200px;\n  height: 200px;\n  margin: auto;\n}\n.jqstooltip {\n  position: absolute;\n  display: block;\n  left: 0px;\n  top: 0px;\n  visibility: hidden;\n  background: #2b303a;\n  background-color: rgba(43, 48, 58, 0.8);\n  color: white;\n  text-align: left;\n  white-space: nowrap;\n  z-index: 10000;\n  padding: 5px 5px 5px 5px;\n  min-height: 22px;\n  border-radius: 3px;\n}\n.jqsfield {\n  color: white;\n  text-align: left;\n}\n.h-200 {\n  min-height: 200px;\n}\n.legendLabel {\n  padding-left: 5px;\n}\n.stat-list li:first-child {\n  margin-top: 0;\n}\n.stat-list {\n  list-style: none;\n  padding: 0;\n  margin: 0;\n}\n.stat-percent {\n  float: right;\n}\n.stat-list li {\n  margin-top: 15px;\n  position: relative;\n}\n/* DATATABLES */\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc:after,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  background: transparent;\n}\ntable.dataTable thead .sorting_asc:after {\n  float: right;\n  font-family: fontawesome;\n}\n/*table.dataTable thead .sorting_desc:after {\n  content: \"\\f0dd\";\n  float: right;\n  font-family: fontawesome;\n}*/\n/*table.dataTable thead .sorting:after {\n  content: \"\\f0dc\";\n  float: right;\n  font-family: fontawesome;\n  color: rgba(50, 50, 50, 0.5);\n}*/\n.dataTables_wrapper {\n  padding-bottom: 30px;\n}\n/* CIRCLE */\n.img-circle {\n  border-radius: 50%;\n}\n.btn-circle {\n  width: 30px;\n  height: 30px;\n  padding: 6px 0;\n  border-radius: 15px;\n  text-align: center;\n  font-size: 12px;\n  line-height: 1.428571429;\n}\n.btn-circle.btn-lg {\n  width: 50px;\n  height: 50px;\n  padding: 10px 16px;\n  border-radius: 25px;\n  font-size: 18px;\n  line-height: 1.33;\n}\n.btn-circle.btn-xl {\n  width: 70px;\n  height: 70px;\n  padding: 10px 16px;\n  border-radius: 35px;\n  font-size: 24px;\n  line-height: 1.33;\n}\n.show-grid [class^=\"col-\"] {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  border: 1px solid #ddd;\n  background-color: #eee !important;\n}\n.show-grid {\n  margin: 15px 0;\n}\n/* ANIMATION */\n.css-animation-box h1 {\n  font-size: 44px;\n}\n.animation-efect-links a {\n  padding: 4px 6px;\n  font-size: 12px;\n}\n#animation_box {\n  background-color: #f9f8f8;\n  border-radius: 16px;\n  width: 80%;\n  margin: 0 auto;\n  padding-top: 80px;\n}\n.animation-text-box {\n  position: absolute;\n  margin-top: 40px;\n  left: 50%;\n  margin-left: -100px;\n  width: 200px;\n}\n.animation-text-info {\n  position: absolute;\n  margin-top: -60px;\n  left: 50%;\n  margin-left: -100px;\n  width: 200px;\n  font-size: 10px;\n}\n.animation-text-box h2 {\n  font-size: 54px;\n  font-weight: 600;\n  margin-bottom: 5px;\n}\n.animation-text-box p {\n  font-size: 12px;\n  text-transform: uppercase;\n}\n/* PEACE */\n.pace {\n  -webkit-pointer-events: none;\n  pointer-events: none;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  user-select: none;\n}\n.pace-inactive {\n  display: none;\n}\n.pace .pace-progress {\n  background: #007bff;\n  position: fixed;\n  z-index: 2000;\n  top: 0;\n  right: 100%;\n  width: 100%;\n  height: 2px;\n}\n.pace-inactive {\n  display: none;\n}\n/* WIDGETS */\n.widget {\n  border-radius: 5px;\n  padding: 15px 20px;\n  margin-bottom: 10px;\n  margin-top: 10px;\n}\n.widget.style1 h2 {\n  font-size: 30px;\n}\n.widget h2,\n.widget h3 {\n  margin-top: 5px;\n  margin-bottom: 0;\n}\n.widget-text-box {\n  padding: 20px;\n  border: 1px solid #e7eaec;\n  background: #ffffff;\n}\n.widget-head-color-box {\n  border-radius: 5px 5px 0px 0px;\n  margin-top: 10px;\n}\n.widget .flot-chart {\n  height: 100px;\n}\n.vertical-align div {\n  display: inline-block;\n  vertical-align: middle;\n}\n.vertical-align h2,\n.vertical-align h3 {\n  margin: 0;\n}\n.todo-list {\n  list-style: none outside none;\n  margin: 0;\n  padding: 0;\n  font-size: 14px;\n}\n.todo-list.small-list {\n  font-size: 12px;\n}\n.todo-list.small-list > li {\n  background: #f3f3f4;\n  border-left: none;\n  border-right: none;\n  border-radius: 4px;\n  color: inherit;\n  margin-bottom: 2px;\n  padding: 6px 6px 6px 12px;\n}\n.todo-list.small-list .btn-xs,\n.todo-list.small-list .btn-group-xs > .btn {\n  border-radius: 5px;\n  font-size: 10px;\n  line-height: 1.5;\n  padding: 1px 2px 1px 5px;\n}\n.todo-list > li {\n  background: #f3f3f4;\n  border-left: 6px solid #e7eaec;\n  border-right: 6px solid #e7eaec;\n  border-radius: 4px;\n  color: inherit;\n  margin-bottom: 2px;\n  padding: 10px;\n}\n.todo-list .handle {\n  cursor: move;\n  display: inline-block;\n  font-size: 16px;\n  margin: 0 5px;\n}\n.todo-list > li .label {\n  font-size: 9px;\n  margin-left: 10px;\n}\n.check-link {\n  font-size: 16px;\n}\n.todo-completed {\n  text-decoration: line-through;\n}\n.geo-statistic h1 {\n  font-size: 36px;\n  margin-bottom: 0;\n}\n.glyphicon.fa {\n  font-family: \"FontAwesome\";\n}\n/* INPUTS */\n.inline {\n  display: inline-block !important;\n}\n.input-s-sm {\n  width: 120px;\n}\n.input-s {\n  width: 200px;\n}\n.input-s-lg {\n  width: 250px;\n}\n.i-checks {\n  padding-left: 0;\n}\n.form-control,\n.single-line {\n  background-color: #FFFFFF;\n  background-image: none;\n  border: 1px solid #e5e6e7;\n  border-radius: 1px;\n  color: inherit;\n  display: block;\n  padding: 0px 12px;\n  transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s ease-in-out 0s;\n  width: 100%;\n  font-size: 14px;\n}\n.form-control:focus,\n.single-line:focus {\n  border-color: #007bff !important;\n}\n.has-success .form-control {\n  border-color: #007bff;\n}\n.has-warning .form-control {\n  border-color: #f8ac59;\n}\n.has-error .form-control {\n  border-color: #ed5565;\n}\n.has-success .control-label {\n  color: #007bff;\n}\n.has-warning .control-label {\n  color: #f8ac59;\n}\n.has-error .control-label {\n  color: #ed5565;\n}\n.input-group-addon {\n  background-color: #fff;\n  border: 1px solid #E5E6E7;\n  border-radius: 1px;\n  color: inherit;\n  font-size: 14px;\n  font-weight: 400;\n  line-height: 1;\n  padding: 6px 12px;\n  text-align: center;\n}\n.spinner-buttons.input-group-btn .btn-xs {\n  line-height: 1.13;\n}\n.spinner-buttons.input-group-btn {\n  width: 20%;\n}\n.noUi-connect {\n  background: none repeat scroll 0 0 #007bff;\n  box-shadow: none;\n}\n.slider_red .noUi-connect {\n  background: none repeat scroll 0 0 #ed5565;\n  box-shadow: none;\n}\n/* UI Sortable */\n.ui-sortable .ibox-title {\n  cursor: move;\n}\n.ui-sortable-placeholder {\n  border: 1px dashed #cecece !important;\n  visibility: visible !important;\n  background: #e7eaec;\n}\n.ibox.ui-sortable-placeholder {\n  margin: 0px 0px 23px !important;\n}\n/* SWITCHES */\n.onoffswitch {\n  position: relative;\n  width: 54px;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n}\n.onoffswitch-checkbox {\n  display: none;\n}\n.onoffswitch-label {\n  display: block;\n  overflow: hidden;\n  cursor: pointer;\n  border: 2px solid #007bff;\n  border-radius: 3px;\n}\n.onoffswitch-inner {\n  display: block;\n  width: 200%;\n  margin-left: -100%;\n  -moz-transition: margin 0.3s ease-in 0s;\n  -webkit-transition: margin 0.3s ease-in 0s;\n  -o-transition: margin 0.3s ease-in 0s;\n  transition: margin 0.3s ease-in 0s;\n}\n.onoffswitch-inner:before,\n.onoffswitch-inner:after {\n  display: block;\n  float: left;\n  width: 50%;\n  height: 16px;\n  padding: 0;\n  line-height: 16px;\n  font-size: 10px;\n  color: white;\n  font-family: Trebuchet, Arial, sans-serif;\n  font-weight: bold;\n  -moz-box-sizing: border-box;\n  -webkit-box-sizing: border-box;\n  box-sizing: border-box;\n}\n.onoffswitch-inner:before {\n  content: \"ON\";\n  padding-left: 7px;\n  background-color: #007bff;\n  color: #FFFFFF;\n}\n.onoffswitch-inner:after {\n  content: \"OFF\";\n  padding-right: 7px;\n  background-color: #FFFFFF;\n  color: #919191;\n  text-align: right;\n}\n.onoffswitch-switch {\n  display: block;\n  width: 18px;\n  margin: 0px;\n  background: #FFFFFF;\n  border: 2px solid #007bff;\n  border-radius: 3px;\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  right: 36px;\n  -moz-transition: all 0.3s ease-in 0s;\n  -webkit-transition: all 0.3s ease-in 0s;\n  -o-transition: all 0.3s ease-in 0s;\n  transition: all 0.3s ease-in 0s;\n}\n.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {\n  margin-left: 0;\n}\n.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {\n  right: 0px;\n}\n/* jqGrid */\n.ui-jqgrid {\n  -moz-box-sizing: content-box;\n}\n.ui-jqgrid-btable {\n  border-collapse: separate;\n}\n.ui-jqgrid-htable {\n  border-collapse: separate;\n}\n.ui-jqgrid-titlebar {\n  height: 40px;\n  line-height: 15px;\n  color: #676a6c;\n  background-color: #F9F9F9;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n}\n.ui-jqgrid .ui-jqgrid-title {\n  float: left;\n  margin: 1.1em 1em 0.2em;\n}\n.ui-jqgrid .ui-jqgrid-titlebar {\n  position: relative;\n  border-left: 0px solid;\n  border-right: 0px solid;\n  border-top: 0px solid;\n}\n.ui-widget-header {\n  background: none;\n  background-image: none;\n  background-color: #f5f5f6;\n  text-transform: uppercase;\n  border-top-left-radius: 0px;\n  border-top-right-radius: 0px;\n}\n.ui-jqgrid tr.ui-row-ltr td {\n  border-right-color: inherit;\n  border-right-style: solid;\n  border-right-width: 1px;\n  text-align: left;\n  border-color: #DDDDDD;\n  background-color: inherit;\n}\n.ui-search-toolbar input[type=\"text\"] {\n  font-size: 12px;\n  height: 15px;\n  border: 1px solid #CCCCCC;\n  border-radius: 0px;\n}\n.ui-state-default,\n.ui-widget-content .ui-state-default,\n.ui-widget-header .ui-state-default {\n  background: #F9F9F9;\n  border: 1px solid #DDDDDD;\n  line-height: 15px;\n  font-weight: bold;\n  color: #676a6c;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n}\n.ui-widget-content {\n  box-sizing: content-box;\n}\n.ui-icon-triangle-1-n {\n  background-position: 1px -16px;\n}\n.ui-jqgrid tr.ui-search-toolbar th {\n  border-top-width: 0px !important;\n  border-top-color: inherit !important;\n  border-top-style: ridge !important;\n}\n.ui-state-hover,\n.ui-widget-content .ui-state-hover,\n.ui-state-focus,\n.ui-widget-content .ui-state-focus,\n.ui-widget-header .ui-state-focus {\n  background: #f5f5f5;\n  border-collapse: separate;\n}\n.ui-state-highlight,\n.ui-widget-content .ui-state-highlight,\n.ui-widget-header .ui-state-highlight {\n  background: #f2fbff;\n}\n.ui-state-active,\n.ui-widget-content .ui-state-active,\n.ui-widget-header .ui-state-active {\n  border: 1px solid #dddddd;\n  background: #ffffff;\n  font-weight: normal;\n  color: #212121;\n}\n.ui-jqgrid .ui-pg-input {\n  font-size: inherit;\n  width: 50px;\n  border: 1px solid #CCCCCC;\n  height: 15px;\n}\n.ui-jqgrid .ui-pg-selbox {\n  display: block;\n  font-size: 1em;\n  height: 25px;\n  line-height: 18px;\n  margin: 0;\n  width: auto;\n}\n.ui-jqgrid .ui-pager-control {\n  position: relative;\n}\n.ui-jqgrid .ui-jqgrid-pager {\n  height: 32px;\n  position: relative;\n}\n.ui-pg-table .navtable .ui-corner-all {\n  border-radius: 0px;\n}\n.ui-jqgrid .ui-pg-button:hover {\n  padding: 1px;\n  border: 0px;\n}\n.ui-jqgrid .loading {\n  position: absolute;\n  top: 45%;\n  left: 45%;\n  width: auto;\n  height: auto;\n  z-index: 101;\n  padding: 6px;\n  margin: 5px;\n  text-align: center;\n  font-weight: bold;\n  display: none;\n  border-width: 2px !important;\n  font-size: 11px;\n}\n.ui-jqgrid .form-control {\n  height: 10px;\n  width: auto;\n  display: inline;\n  padding: 10px 12px;\n}\n.ui-jqgrid-pager {\n  height: 32px;\n}\n.ui-corner-all,\n.ui-corner-top,\n.ui-corner-left,\n.ui-corner-tl {\n  border-top-left-radius: 0;\n}\n.ui-corner-all,\n.ui-corner-top,\n.ui-corner-right,\n.ui-corner-tr {\n  border-top-right-radius: 0;\n}\n.ui-corner-all,\n.ui-corner-bottom,\n.ui-corner-left,\n.ui-corner-bl {\n  border-bottom-left-radius: 0;\n}\n.ui-corner-all,\n.ui-corner-bottom,\n.ui-corner-right,\n.ui-corner-br {\n  border-bottom-right-radius: 0;\n}\n.ui-widget-content {\n  border: 1px solid #ddd;\n}\n.ui-jqgrid .ui-jqgrid-titlebar {\n  padding: 0;\n}\n.ui-jqgrid .ui-jqgrid-titlebar {\n  border-bottom: 1px solid #ddd;\n}\n.ui-jqgrid tr.jqgrow td {\n  padding: 6px;\n}\n.ui-jqdialog .ui-jqdialog-titlebar {\n  padding: 10px 10px;\n}\n.ui-jqdialog .ui-jqdialog-title {\n  float: none !important;\n}\n.ui-jqdialog > .ui-resizable-se {\n  position: absolute;\n}\n/* Nestable list */\n.dd {\n  position: relative;\n  display: block;\n  margin: 0;\n  padding: 0;\n  list-style: none;\n  font-size: 13px;\n  line-height: 20px;\n}\n.dd-list {\n  display: block;\n  position: relative;\n  margin: 0;\n  padding: 0;\n  list-style: none;\n}\n.dd-list .dd-list {\n  padding-left: 30px;\n}\n.dd-collapsed .dd-list {\n  display: none;\n}\n.dd-item,\n.dd-empty,\n.dd-placeholder {\n  display: block;\n  position: relative;\n  margin: 0;\n  padding: 0;\n  min-height: 20px;\n  font-size: 13px;\n  line-height: 20px;\n}\n.dd-handle {\n  display: block;\n  margin: 5px 0;\n  padding: 5px 10px;\n  color: #333;\n  text-decoration: none;\n  border: 1px solid #e7eaec;\n  background: #f5f5f5;\n  -webkit-border-radius: 3px;\n  border-radius: 3px;\n  box-sizing: border-box;\n  -moz-box-sizing: border-box;\n}\n.dd-handle span {\n  font-weight: bold;\n}\n.dd-handle:hover {\n  background: #f0f0f0;\n  cursor: pointer;\n  font-weight: bold;\n}\n.dd-item > button {\n  display: block;\n  position: relative;\n  cursor: pointer;\n  float: left;\n  width: 25px;\n  height: 20px;\n  margin: 5px 0;\n  padding: 0;\n  text-indent: 100%;\n  white-space: nowrap;\n  overflow: hidden;\n  border: 0;\n  background: transparent;\n  font-size: 12px;\n  line-height: 1;\n  text-align: center;\n  font-weight: bold;\n}\n.dd-item > button:before {\n  content: '+';\n  display: block;\n  position: absolute;\n  width: 100%;\n  text-align: center;\n  text-indent: 0;\n}\n.dd-item > button[data-action=\"collapse\"]:before {\n  content: '-';\n}\n#nestable2 .dd-item > button {\n  font-family: FontAwesome;\n  height: 34px;\n  width: 33px;\n  color: #c1c1c1;\n}\n#nestable2 .dd-item > button:before {\n  content: \"\\f067\";\n}\n#nestable2 .dd-item > button[data-action=\"collapse\"]:before {\n  content: \"\\f068\";\n}\n.dd-placeholder,\n.dd-empty {\n  margin: 5px 0;\n  padding: 0;\n  min-height: 30px;\n  background: #f2fbff;\n  border: 1px dashed #b6bcbf;\n  box-sizing: border-box;\n  -moz-box-sizing: border-box;\n}\n.dd-empty {\n  border: 1px dashed #bbb;\n  min-height: 100px;\n  background-color: #e5e5e5;\n  background-image: -webkit-linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%, #ffffff 75%, #ffffff), -webkit-linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%, #ffffff 75%, #ffffff);\n  background-image: -moz-linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%, #ffffff 75%, #ffffff), -moz-linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%, #ffffff 75%, #ffffff);\n  background-image: linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%, #ffffff 75%, #ffffff), linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%, #ffffff 75%, #ffffff);\n  background-size: 60px 60px;\n  background-position: 0 0, 30px 30px;\n}\n.dd-dragel {\n  position: absolute;\n  z-index: 9999;\n  pointer-events: none;\n}\n.dd-dragel > .dd-item .dd-handle {\n  margin-top: 0;\n}\n.dd-dragel .dd-handle {\n  -webkit-box-shadow: 2px 4px 6px 0 rgba(0, 0, 0, 0.1);\n  box-shadow: 2px 4px 6px 0 rgba(0, 0, 0, 0.1);\n}\n/**\n* Nestable Extras\n*/\n.nestable-lists {\n  display: block;\n  clear: both;\n  padding: 30px 0;\n  width: 100%;\n  border: 0;\n  border-top: 2px solid #ddd;\n  border-bottom: 2px solid #ddd;\n}\n#nestable-menu {\n  padding: 0;\n  margin: 10px 0 20px 0;\n}\n#nestable-output,\n#nestable2-output {\n  width: 100%;\n  font-size: 0.75em;\n  line-height: 1.333333em;\n  font-family: open sans, lucida grande, lucida sans unicode, helvetica, arial, sans-serif;\n  padding: 5px;\n  box-sizing: border-box;\n  -moz-box-sizing: border-box;\n}\n#nestable2 .dd-handle {\n  color: inherit;\n  border: 1px dashed #e7eaec;\n  background: #f3f3f4;\n  padding: 10px;\n}\n#nestable2 .dd-handle:hover {\n  /*background: #bbb;*/\n}\n#nestable2 span.label {\n  margin-right: 10px;\n}\n#nestable-output,\n#nestable2-output {\n  font-size: 12px;\n  padding: 25px;\n  box-sizing: border-box;\n  -moz-box-sizing: border-box;\n}\n/* CodeMirror */\n.CodeMirror {\n  border: 1px solid #eee;\n  height: auto;\n}\n.CodeMirror-scroll {\n  overflow-y: hidden;\n  overflow-x: auto;\n}\n/* Google Maps */\n.google-map {\n  height: 300px;\n}\n/* Validation */\nlabel.error {\n  color: #cc5965;\n  display: inline-block;\n  margin-left: 5px;\n}\n.form-control.error {\n  border: 1px dotted #cc5965;\n}\n/* ngGrid */\n.gridStyle {\n  border: 1px solid #d4d4d4;\n  width: 100%;\n  height: 400px;\n}\n.gridStyle2 {\n  border: 1px solid #d4d4d4;\n  width: 500px;\n  height: 300px;\n}\n.ngH eaderCell {\n  border-right: none;\n  border-bottom: 1px solid #e7eaec;\n}\n.ngCell {\n  border-right: none;\n}\n.ngTopPanel {\n  background: #F5F5F6;\n}\n.ngRow.even {\n  background: #f9f9f9;\n}\n.ngRow.selected {\n  background: #EBF2F1;\n}\n.ngRow {\n  border-bottom: 1px solid #e7eaec;\n}\n.ngCell {\n  background-color: transparent;\n}\n.ngHeaderCell {\n  border-right: none;\n}\n/* Toastr custom style */\n#toast-container > .toast {\n  background-image: none !important;\n}\n#toast-container > .toast:before {\n  position: fixed;\n  font-family: FontAwesome;\n  font-size: 24px;\n  line-height: 24px;\n  float: left;\n  color: #FFF;\n  padding-right: 0.5em;\n  margin: auto 0.5em auto -1.5em;\n}\n#toast-container > .toast-warning:before {\n  content: \"\\f0e7\";\n}\n#toast-container > .toast-error:before {\n  content: \"\\f071\";\n}\n#toast-container > .toast-info:before {\n  content: \"\\f005\";\n}\n#toast-container > .toast-success:before {\n  content: \"\\f00C\";\n}\n#toast-container > div {\n  -moz-box-shadow: 0 0 3px #999;\n  -webkit-box-shadow: 0 0 3px #999;\n  box-shadow: 0 0 3px #999;\n  opacity: .9;\n  -ms-filter: alpha(opacity=90);\n  filter: alpha(opacity=90);\n}\n#toast-container > :hover {\n  -moz-box-shadow: 0 0 4px #999;\n  -webkit-box-shadow: 0 0 4px #999;\n  box-shadow: 0 0 4px #999;\n  opacity: 1;\n  -ms-filter: alpha(opacity=100);\n  filter: alpha(opacity=100);\n  cursor: pointer;\n}\n.toast {\n  background-color: #007bff;\n}\n.toast-success {\n  background-color: #007bff;\n}\n.toast-error {\n  background-color: #ed5565;\n}\n.toast-info {\n  background-color: #007bff;\n}\n.toast-warning {\n  background-color: #f8ac59;\n}\n.toast-top-full-width {\n  margin-top: 20px;\n}\n.toast-bottom-full-width {\n  margin-bottom: 20px;\n}\n/* Image cropper style */\n.img-container,\n.img-preview {\n  overflow: hidden;\n  text-align: center;\n  width: 100%;\n}\n.img-preview-sm {\n  height: 130px;\n  width: 200px;\n}\n/* Forum styles  */\n.forum-post-container .media {\n  margin: 10px 10px 10px 10px;\n  padding: 20px 10px 20px 10px;\n  border-bottom: 1px solid #f1f1f1;\n}\n.forum-avatar {\n  float: left;\n  margin-right: 20px;\n  text-align: center;\n  width: 110px;\n}\n.forum-avatar .img-circle {\n  height: 48px;\n  width: 48px;\n}\n.author-info {\n  color: #676a6c;\n  font-size: 11px;\n  margin-top: 5px;\n  text-align: center;\n}\n.forum-post-info {\n  padding: 9px 12px 6px 12px;\n  background: #f9f9f9;\n  border: 1px solid #f1f1f1;\n}\n.media-body > .media {\n  background: #f9f9f9;\n  border-radius: 3px;\n  border: 1px solid #f1f1f1;\n}\n.forum-post-container .media-body .photos {\n  margin: 10px 0;\n}\n.forum-photo {\n  max-width: 140px;\n  border-radius: 3px;\n}\n.media-body > .media .forum-avatar {\n  width: 70px;\n  margin-right: 10px;\n}\n.media-body > .media .forum-avatar .img-circle {\n  height: 38px;\n  width: 38px;\n}\n.mid-icon {\n  font-size: 66px;\n}\n.forum-item {\n  margin: 10px 0;\n  padding: 10px 0 20px;\n  border-bottom: 1px solid #f1f1f1;\n}\n.views-number {\n  font-size: 24px;\n  line-height: 18px;\n  font-weight: 400;\n}\n.forum-container,\n.forum-post-container {\n  padding: 30px !important;\n}\n.forum-item small {\n  color: #999;\n}\n.forum-item .forum-sub-title {\n  color: #999;\n  margin-left: 50px;\n}\n.forum-title {\n  margin: 15px 0 15px 0;\n}\n.forum-info {\n  text-align: center;\n}\n.forum-desc {\n  color: #999;\n}\n.forum-icon {\n  float: left;\n  width: 30px;\n  margin-right: 20px;\n  text-align: center;\n}\na.forum-item-title {\n  color: inherit;\n  display: block;\n  font-size: 18px;\n  font-weight: 600;\n}\na.forum-item-title:hover {\n  color: inherit;\n}\n.forum-icon .fa {\n  font-size: 30px;\n  margin-top: 8px;\n  color: #9b9b9b;\n}\n.forum-item.active .fa {\n  color: #007bff;\n}\n.forum-item.active a.forum-item-title {\n  color: #007bff;\n}\n@media (max-width: 992px) {\n  .forum-info {\n    margin: 15px 0 10px 0px;\n    /* Comment this is you want to show forum info in small devices */\n    display: none;\n  }\n  .forum-desc {\n    float: none !important;\n  }\n}\n/* New Timeline style */\n.vertical-container {\n  /* this class is used to give a max-width to the element it is applied to, and center it horizontally when it reaches that max-width */\n  width: 90%;\n  max-width: 1170px;\n  margin: 0 auto;\n}\n.vertical-container::after {\n  /* clearfix */\n  content: '';\n  display: table;\n  clear: both;\n}\n#vertical-timeline {\n  position: relative;\n  padding: 0;\n  margin-top: 2em;\n  margin-bottom: 2em;\n}\n#vertical-timeline::before {\n  content: '';\n  position: absolute;\n  top: 0;\n  left: 18px;\n  height: 100%;\n  width: 4px;\n  background: #f1f1f1;\n}\n.vertical-timeline-content .btn {\n  float: right;\n}\n#vertical-timeline.light-timeline:before {\n  background: #e7eaec;\n}\n.dark-timeline .vertical-timeline-content:before {\n  border-color: transparent #f5f5f5 transparent transparent ;\n}\n.dark-timeline.center-orientation .vertical-timeline-content:before {\n  border-color: transparent  transparent transparent #f5f5f5;\n}\n.dark-timeline .vertical-timeline-block:nth-child(2n) .vertical-timeline-content:before,\n.dark-timeline.center-orientation .vertical-timeline-block:nth-child(2n) .vertical-timeline-content:before {\n  border-color: transparent #f5f5f5 transparent transparent;\n}\n.dark-timeline .vertical-timeline-content,\n.dark-timeline.center-orientation .vertical-timeline-content {\n  background: #f5f5f5;\n}\n@media only screen and (min-width: 1170px) {\n  #vertical-timeline.center-orientation {\n    margin-top: 3em;\n    margin-bottom: 3em;\n  }\n  #vertical-timeline.center-orientation:before {\n    left: 50%;\n    margin-left: -2px;\n  }\n}\n@media only screen and (max-width: 1170px) {\n  .center-orientation.dark-timeline .vertical-timeline-content:before {\n    border-color: transparent #f5f5f5 transparent transparent;\n  }\n}\n.vertical-timeline-block {\n  position: relative;\n  margin: 2em 0;\n}\n.vertical-timeline-block:after {\n  content: \"\";\n  display: table;\n  clear: both;\n}\n.vertical-timeline-block:first-child {\n  margin-top: 0;\n}\n.vertical-timeline-block:last-child {\n  margin-bottom: 0;\n}\n@media only screen and (min-width: 1170px) {\n  .center-orientation .vertical-timeline-block {\n    margin: 4em 0;\n  }\n  .center-orientation .vertical-timeline-block:first-child {\n    margin-top: 0;\n  }\n  .center-orientation .vertical-timeline-block:last-child {\n    margin-bottom: 0;\n  }\n}\n.vertical-timeline-icon {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 40px;\n  height: 40px;\n  border-radius: 50%;\n  font-size: 16px;\n  border: 3px solid #f1f1f1;\n  text-align: center;\n}\n.vertical-timeline-icon i {\n  display: block;\n  width: 24px;\n  height: 24px;\n  position: relative;\n  left: 50%;\n  top: 50%;\n  margin-left: -12px;\n  margin-top: -9px;\n}\n@media only screen and (min-width: 1170px) {\n  .center-orientation .vertical-timeline-icon {\n    width: 50px;\n    height: 50px;\n    left: 50%;\n    margin-left: -25px;\n    -webkit-transform: translateZ(0);\n    -webkit-backface-visibility: hidden;\n    font-size: 19px;\n  }\n  .center-orientation .vertical-timeline-icon i {\n    margin-left: -12px;\n    margin-top: -10px;\n  }\n  .center-orientation .cssanimations .vertical-timeline-icon.is-hidden {\n    visibility: hidden;\n  }\n}\n.vertical-timeline-content {\n  position: relative;\n  margin-left: 60px;\n  background: white;\n  border-radius: 0.25em;\n  padding: 1em;\n}\n.vertical-timeline-content:after {\n  content: \"\";\n  display: table;\n  clear: both;\n}\n.vertical-timeline-content h2 {\n  font-weight: 400;\n  margin-top: 4px;\n}\n.vertical-timeline-content p {\n  margin: 1em 0;\n  line-height: 1.6;\n}\n.vertical-timeline-content .vertical-date {\n  float: left;\n  font-weight: 500;\n}\n.vertical-date small {\n  color: #007bff;\n  font-weight: 400;\n}\n.vertical-timeline-content::before {\n  content: '';\n  position: absolute;\n  top: 16px;\n  right: 100%;\n  height: 0;\n  width: 0;\n  border: 7px solid transparent;\n  border-right: 7px solid white;\n}\n@media only screen and (min-width: 768px) {\n  .vertical-timeline-content h2 {\n    font-size: 18px;\n  }\n  .vertical-timeline-content p {\n    font-size: 13px;\n  }\n}\n@media only screen and (min-width: 1170px) {\n  .center-orientation .vertical-timeline-content {\n    margin-left: 0;\n    padding: 1.6em;\n    width: 45%;\n  }\n  .center-orientation .vertical-timeline-content::before {\n    top: 24px;\n    left: 100%;\n    border-color: transparent;\n    border-left-color: white;\n  }\n  .center-orientation .vertical-timeline-content .btn {\n    float: left;\n  }\n  .center-orientation .vertical-timeline-content .vertical-date {\n    position: absolute;\n    width: 100%;\n    left: 122%;\n    top: 2px;\n    font-size: 14px;\n  }\n  .center-orientation .vertical-timeline-block:nth-child(even) .vertical-timeline-content {\n    float: right;\n  }\n  .center-orientation .vertical-timeline-block:nth-child(even) .vertical-timeline-content::before {\n    top: 24px;\n    left: auto;\n    right: 100%;\n    border-color: transparent;\n    border-right-color: white;\n  }\n  .center-orientation .vertical-timeline-block:nth-child(even) .vertical-timeline-content .btn {\n    float: right;\n  }\n  .center-orientation .vertical-timeline-block:nth-child(even) .vertical-timeline-content .vertical-date {\n    left: auto;\n    right: 122%;\n    text-align: right;\n  }\n  .center-orientation .cssanimations .vertical-timeline-content.is-hidden {\n    visibility: hidden;\n  }\n}\n.sidebard-panel {\n  width: 220px;\n  background: #ebebed;\n  padding: 10px 20px;\n  position: absolute;\n  right: 0;\n}\n.sidebard-panel .feed-element img.img-circle {\n  width: 32px;\n  height: 32px;\n}\n.sidebard-panel .feed-element,\n.media-body,\n.sidebard-panel p {\n  font-size: 12px;\n}\n.sidebard-panel .feed-element {\n  margin-top: 20px;\n  padding-bottom: 0;\n}\n.sidebard-panel .list-group {\n  margin-bottom: 10px;\n}\n.sidebard-panel .list-group .list-group-item {\n  padding: 5px 0;\n  font-size: 12px;\n  border: 0;\n}\n.sidebar-content .wrapper,\n.wrapper.sidebar-content {\n  padding-right: 230px !important;\n}\n.body-small .sidebar-content .wrapper,\n.body-small .wrapper.sidebar-content {\n  padding-right: 20px !important;\n}\n#right-sidebar {\n  background-color: #fff;\n  border-left: 1px solid #e7eaec;\n  border-top: 1px solid #e7eaec;\n  overflow: hidden;\n  position: fixed;\n  top: 60px;\n  width: 260px !important;\n  z-index: 1009;\n  bottom: 0;\n  right: -260px;\n}\n#right-sidebar.sidebar-open {\n  right: 0;\n}\n#right-sidebar.sidebar-open.sidebar-top {\n  top: 0;\n  border-top: none;\n}\n.sidebar-container ul.nav-tabs {\n  border: none;\n}\n.sidebar-container ul.nav-tabs.navs-4 li {\n  width: 25%;\n}\n.sidebar-container ul.nav-tabs.navs-3 li {\n  width: 33.3333%;\n}\n.sidebar-container ul.nav-tabs.navs-2 li {\n  width: 50%;\n}\n.sidebar-container ul.nav-tabs li {\n  border: none;\n}\n.sidebar-container ul.nav-tabs li a {\n  border: none;\n  padding: 12px 10px;\n  margin: 0;\n  border-radius: 0;\n  background: #2f4050;\n  color: #fff;\n  text-align: center;\n  border-right: 1px solid #334556;\n}\n.sidebar-container ul.nav-tabs li.active a {\n  border: none;\n  background: #f9f9f9;\n  color: #676a6c;\n  font-weight: bold;\n}\n.sidebar-container .nav-tabs > li.active > a:hover,\n.sidebar-container .nav-tabs > li.active > a:focus {\n  border: none;\n}\n.sidebar-container ul.sidebar-list {\n  margin: 0;\n  padding: 0;\n}\n.sidebar-container ul.sidebar-list li {\n  border-bottom: 1px solid #e7eaec;\n  padding: 15px 20px;\n  list-style: none;\n  font-size: 12px;\n}\n.sidebar-container .sidebar-message:nth-child(2n+2) {\n  background: #f9f9f9;\n}\n.sidebar-container ul.sidebar-list li a {\n  text-decoration: none;\n  color: inherit;\n}\n.sidebar-container .sidebar-content {\n  padding: 15px 20px ;\n  font-size: 12px;\n}\n.sidebar-container .sidebar-title {\n  background: #f9f9f9;\n  padding: 20px;\n  border-bottom: 1px solid #e7eaec;\n}\n.sidebar-container .sidebar-title h3 {\n  margin-bottom: 3px;\n  padding-left: 2px;\n}\n.sidebar-container .tab-content h4 {\n  margin-bottom: 5px;\n}\n.sidebar-container .sidebar-message > a > .pull-left {\n  margin-right: 10px;\n}\n.sidebar-container .sidebar-message > a {\n  text-decoration: none;\n  color: inherit;\n}\n.sidebar-container .sidebar-message {\n  padding: 15px 20px;\n}\n.sidebar-container .sidebar-message .message-avatar {\n  height: 38px;\n  width: 38px;\n  border-radius: 50%;\n}\n.sidebar-container .setings-item {\n  padding: 15px 20px;\n  border-bottom: 1px solid #e7eaec;\n}\nbody {\n  background-color: #2f4050;\n  font-size: 13px;\n  color: #676a6c;\n  overflow-x: hidden;\n  background-color: #f3f3f4;\n}\nhtml,\nbody {\n  height: 100%;\n}\nbody.full-height-layout #wrapper,\nbody.full-height-layout #page-wrapper {\n  height: 100%;\n}\n#page-wrapper {\n  min-height: auto;\n}\nbody.boxed-layout {\n  background: url('patterns/shattered.png');\n}\nbody.boxed-layout #wrapper {\n  background-color: #2f4050;\n  max-width: 1200px;\n  margin: 0 auto;\n  -webkit-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.75);\n  -moz-box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.75);\n  box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.75);\n}\n.top-navigation.boxed-layout #wrapper,\n.boxed-layout #wrapper.top-navigation {\n  max-width: 1300px !important;\n}\n.block {\n  display: block;\n}\n.clear {\n  display: block;\n  overflow: hidden;\n}\na {\n  cursor: pointer;\n}\na:hover,\na:focus {\n  text-decoration: none;\n}\n.border-bottom {\n  border-bottom: 1px solid #e7eaec !important;\n}\n.font-bold {\n  font-weight: 600;\n}\n.font-noraml {\n  font-weight: 400;\n}\n.text-uppercase {\n  text-transform: uppercase;\n}\n.b-r {\n  border-right: 1px solid #e7eaec;\n}\n.hr-line-dashed {\n  border-top: 1px dashed #e7eaec;\n  color: #ffffff;\n  background-color: #ffffff;\n  height: 1px;\n  margin: 20px 0;\n}\n.hr-line-solid {\n  border-bottom: 1px solid #e7eaec;\n  background-color: rgba(0, 0, 0, 0);\n  border-style: solid !important;\n  margin-top: 15px;\n  margin-bottom: 15px;\n}\nvideo {\n  width: 100%    !important;\n  height: auto   !important;\n}\n/* GALLERY */\n.gallery > .row > div {\n  margin-bottom: 15px;\n}\n.fancybox img {\n  margin-bottom: 5px;\n  /* Only for demo */\n  width: 24%;\n}\n/* Summernote text editor  */\n.note-editor {\n  height: auto;\n  min-height: 300px;\n}\n/* MODAL */\n.modal-content {\n  background-clip: padding-box;\n  background-color: #FFFFFF;\n  border: 1px solid rgba(0, 0, 0, 0);\n  border-radius: 4px;\n  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n  outline: 0 none;\n  position: relative;\n}\n.modal-dialog {\n  z-index: 1200;\n}\n.modal-body {\n  padding: 20px 30px 30px 30px;\n}\n.inmodal .modal-body {\n  background: #f8fafb;\n}\n.inmodal .modal-header {\n  padding: 30px 15px;\n  text-align: center;\n}\n.animated.modal.fade .modal-dialog {\n  -webkit-transform: none;\n  -ms-transform: none;\n  -o-transform: none;\n  transform: none;\n}\n.inmodal .modal-title {\n  font-size: 26px;\n}\n.inmodal .modal-icon {\n  font-size: 84px;\n  color: #e2e3e3;\n}\n.modal-footer {\n  margin-top: 0;\n}\n/* WRAPPERS */\n#wrapper {\n  width: 100%;\n  overflow-x: hidden;\n}\n.wrapper {\n  padding: 0 20px;\n}\n.wrapper-content {\n  padding: 11px 10px 0px;\n}\n#page-wrapper {\n  padding: 0 15px;\n  min-height: 568px;\n  position: relative !important;\n}\n@media (min-width: 768px) {\n  #page-wrapper {\n    position: inherit;\n    margin: 0 0 0 240px;\n    min-height: 1000px;\n  }\n}\n.title-action {\n  text-align: right;\n  padding-top: 30px;\n}\n.ibox-content h1,\n.ibox-content h2,\n.ibox-content h3,\n.ibox-content h4,\n.ibox-content h5,\n.ibox-title h1,\n.ibox-title h2,\n.ibox-title h3,\n.ibox-title h4,\n.ibox-title h5 {\n  margin-top: 5px;\n}\nul.unstyled,\nol.unstyled {\n  list-style: none outside none;\n  margin-left: 0;\n}\n.big-icon {\n  font-size: 160px;\n  color: #e5e6e7;\n}\n/* FOOTER */\n.footer {\n  background: none repeat scroll 0 0 white;\n  border-top: 1px solid #e7eaec;\n  bottom: 0;\n  left: 0;\n  padding: 10px 20px;\n  position: absolute;\n  right: 0;\n}\n.footer.fixed_full {\n  position: fixed;\n  bottom: 0;\n  left: 0;\n  right: 0;\n  z-index: 1000;\n  padding: 10px 20px;\n  background: white;\n  border-top: 1px solid #e7eaec;\n}\n.footer.fixed {\n  position: fixed;\n  bottom: 0;\n  left: 0;\n  right: 0;\n  z-index: 1000;\n  padding: 10px 20px;\n  background: white;\n  border-top: 1px solid #e7eaec;\n  margin-left: 220px;\n}\nbody.mini-navbar .footer.fixed,\nbody.body-small.mini-navbar .footer.fixed {\n  margin: 0 0 0 70px;\n}\nbody.mini-navbar.canvas-menu .footer.fixed,\nbody.canvas-menu .footer.fixed {\n  margin: 0 !important;\n}\nbody.fixed-sidebar.body-small.mini-navbar .footer.fixed {\n  margin: 0 0 0 220px;\n}\nbody.body-small .footer.fixed {\n  margin-left: 0px;\n}\n/* PANELS */\n.page-heading {\n  border-top: 0;\n  padding: 0px 10px 20px 10px;\n}\n.panel-heading h1,\n.panel-heading h2 {\n  margin-bottom: 5px;\n}\n/* TABLES */\n.table-bordered {\n  border: 1px solid #EBEBEB;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n  background-color: #ffffff;\n  border-bottom-width: 1px;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n  border: 1px solid #e7e7e7;\n}\n.table > thead > tr > th {\n  border-bottom: 1px solid #DDDDDD;\n  vertical-align: bottom;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n  border-top: 1px solid #e7eaec;\n  line-height: 1.42857;\n  padding: 8px;\n  vertical-align: top;\n}\n/* PANELS */\n.panel.blank-panel {\n  background: none;\n  margin: 0;\n}\n.blank-panel .panel-heading {\n  padding-bottom: 0;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n  -moz-border-bottom-colors: none;\n  -moz-border-left-colors: none;\n  -moz-border-right-colors: none;\n  -moz-border-top-colors: none;\n  background: none;\n  border-color: #dddddd #dddddd rgba(0, 0, 0, 0);\n  border-bottom: #f3f3f4;\n  border-image: none;\n  border-style: solid;\n  border-width: 1px;\n  color: #555555;\n  cursor: default;\n}\n.nav.nav-tabs li {\n  background: none;\n  border: none;\n}\n.nav-tabs > li > a {\n  color: #A7B1C2;\n  font-weight: 600;\n  padding: 10px 20px 10px 25px;\n}\n.nav-tabs > li > a:hover,\n.nav-tabs > li > a:focus {\n  background-color: #e6e6e6;\n  color: #676a6c;\n}\n.ui-tab .tab-content {\n  padding: 20px 0px;\n}\n/* GLOBAL  */\n.no-padding {\n  padding: 0 !important;\n}\n.no-borders {\n  border: none !important;\n}\n.no-margins {\n  margin: 0 !important;\n}\n.no-top-border {\n  border-top: 0 !important;\n}\n.ibox-content.text-box {\n  padding-bottom: 0px;\n  padding-top: 15px;\n}\n.border-left-right {\n  border-left: 1px solid #e7eaec;\n  border-right: 1px solid #e7eaec;\n  border-top: none;\n  border-bottom: none;\n}\n.border-left {\n  border-left: 1px solid #e7eaec;\n  border-right: none;\n  border-top: none;\n  border-bottom: none;\n}\n.border-right {\n  border-left: none;\n  border-right: 1px solid #e7eaec;\n  border-top: none;\n  border-bottom: none;\n}\n.full-width {\n  width: 100% !important;\n}\n.link-block {\n  font-size: 12px;\n  padding: 10px;\n}\n.nav.navbar-top-links .link-block a {\n  font-size: 12px;\n}\n.link-block a {\n  font-size: 10px;\n  color: inherit;\n}\nbody.mini-navbar .branding {\n  display: none;\n}\nimg.circle-border {\n  border: 6px solid #FFFFFF;\n  border-radius: 50%;\n}\n.branding {\n  float: left;\n  color: #FFFFFF;\n  font-size: 18px;\n  font-weight: 600;\n  padding: 17px 20px;\n  text-align: center;\n  background-color: #007bff;\n}\n.login-panel {\n  margin-top: 25%;\n}\n.icons-box h3 {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.icons-box .infont a i {\n  font-size: 25px;\n  display: block;\n  color: #676a6c;\n}\n.icons-box .infont a {\n  color: #a6a8a9;\n}\n.icons-box .infont a {\n  padding: 10px;\n  margin: 1px;\n  display: block;\n}\n.ui-draggable .ibox-title {\n  cursor: move;\n}\n.breadcrumb {\n  background-color: #ffffff;\n  padding: 0;\n  margin-bottom: 0;\n}\n.breadcrumb > li a {\n  color: inherit;\n}\n.breadcrumb > .active {\n  color: inherit;\n}\ncode {\n  background-color: #F9F2F4;\n  border-radius: 4px;\n  color: #ca4440;\n  font-size: 90%;\n  padding: 2px 4px;\n  white-space: nowrap;\n}\n.ibox {\n  clear: both;\n  margin-bottom: 5px;\n  margin-top: 0;\n  padding: 0;\n}\n.ibox.collapsed .ibox-content {\n  display: none;\n}\n.ibox.collapsed .fa.fa-chevron-up:before {\n  content: \"\\f078\";\n}\n.ibox.collapsed .fa.fa-chevron-down:before {\n  content: \"\\f077\";\n}\n.ibox:after,\n.ibox:before {\n  display: table;\n}\n.ibox-title {\n  -moz-border-bottom-colors: none;\n  -moz-border-left-colors: none;\n  -moz-border-right-colors: none;\n  -moz-border-top-colors: none;\n  background-color: #ffffff;\n  border-color: #e7eaec;\n  border-image: none;\n  border-style: solid solid none;\n  border-width: 4px 0px 0;\n  color: inherit;\n  margin-bottom: 0;\n  padding: 14px 15px 7px;\n  min-height: 48px;\n}\n.ibox-content {\n  background-color: #ffffff;\n  color: inherit;\n  padding: 15px 20px 20px 20px;\n  border-color: #e7eaec;\n  border-image: none;\n  border-style: solid solid none;\n  border-width: 1px 0px;\n}\ntable.table-mail tr td {\n  padding: 12px;\n}\n.table-mail .check-mail {\n  padding-left: 20px;\n}\n.table-mail .mail-date {\n  padding-right: 20px;\n}\n.star-mail,\n.check-mail {\n  width: 40px;\n}\n.unread td a,\n.unread td {\n  font-weight: 600;\n  color: inherit;\n}\n.read td a,\n.read td {\n  font-weight: normal;\n  color: inherit;\n}\n.unread td {\n  background-color: #f9f8f8;\n}\n.ibox-content {\n  clear: both;\n}\n.ibox-heading {\n  background-color: #f3f6fb;\n  border-bottom: none;\n}\n.ibox-heading h3 {\n  font-weight: 200;\n  font-size: 24px;\n}\n.ibox-title h5 {\n  display: inline-block;\n  font-size: 14px;\n  margin: 0 0 7px;\n  padding: 0;\n  text-overflow: ellipsis;\n  float: left;\n}\n.ibox-title h5 i{ margin-right: 5px;}\n.ibox-title .label {\n  float: left;\n  margin-left: 4px;\n}\n.ibox-tools {\n  display: inline-block;\n  float: right;\n  margin-top: 0;\n  position: relative;\n  padding: 0;\n}\n.ibox-tools a {\n  cursor: pointer;\n  margin-left: 5px;\n  color: #c4c4c4;\n}\n.ibox-tools a.btn-primary {\n  color: #fff;\n}\n.ibox-tools .dropdown-menu > li > a {\n  padding: 4px 10px;\n  font-size: 12px;\n}\n.ibox .open > .dropdown-menu {\n  left: auto;\n  right: 0;\n}\n/* BACKGROUNDS */\n.gray-bg {\n  background-color: #f3f3f4;\n}\n.white-bg {\n  background-color: #ffffff;\n}\n.navy-bg {\n  background-color: #007bff;\n  color: #ffffff;\n}\n.blue-bg {\n  background-color: #007bff;\n  color: #ffffff;\n}\n.lazur-bg {\n  background-color: #007bff;\n  color: #ffffff;\n}\n.yellow-bg {\n  background-color: #f8ac59;\n  color: #ffffff;\n}\n.red-bg {\n  background-color: #ed5565;\n  color: #ffffff;\n}\n.black-bg {\n  background-color: #262626;\n}\n.panel-primary {\n  border-color: #007bff;\n}\n.panel-primary > .panel-heading {\n  background-color: #007bff;\n  border-color: #007bff;\n}\n.panel-success {\n  border-color: #007bff;\n}\n.panel-success > .panel-heading {\n  background-color: #007bff;\n  border-color: #007bff;\n  color: #ffffff;\n}\n.panel-info {\n  border-color: #007bff;\n}\n.panel-info > .panel-heading {\n  background-color: #007bff;\n  border-color: #007bff;\n  color: #ffffff;\n}\n.panel-warning {\n  border-color: #f8ac59;\n}\n.panel-warning > .panel-heading {\n  background-color: #f8ac59;\n  border-color: #f8ac59;\n  color: #ffffff;\n}\n.panel-danger {\n  border-color: #ed5565;\n}\n.panel-danger > .panel-heading {\n  background-color: #ed5565;\n  border-color: #ed5565;\n  color: #ffffff;\n}\n.progress-bar {\n  background-color: #007bff;\n}\n.progress-small,\n.progress-small .progress-bar {\n  height: 10px;\n}\n.progress-small,\n.progress-mini {\n  margin-top: 5px;\n}\n.progress-mini,\n.progress-mini .progress-bar {\n  height: 5px;\n  margin-bottom: 0px;\n}\n.progress-bar-navy-light {\n  background-color: #3dc7ab;\n}\n.progress-bar-success {\n  background-color: #007bff;\n}\n.progress-bar-info {\n  background-color: #007bff;\n}\n.progress-bar-warning {\n  background-color: #f8ac59;\n}\n.progress-bar-danger {\n  background-color: #ed5565;\n}\n.panel-title {\n  font-size: inherit;\n}\n.jumbotron {\n  border-radius: 6px;\n  padding: 40px;\n}\n.jumbotron h1 {\n  margin-top: 0;\n}\n/* COLORS */\n.text-navy {\n  color: #007bff;\n}\n.text-primary {\n  color: inherit;\n}\n.text-success {\n  color: #007bff;\n}\n.text-info {\n  color: #007bff;\n}\n.text-warning {\n  color: #f8ac59;\n}\n.text-danger {\n  color: #ed5565;\n}\n.text-muted {\n  color: #888888;\n}\n.simple_tag {\n  background-color: #f3f3f4;\n  border: 1px solid #e7eaec;\n  border-radius: 2px;\n  color: inherit;\n  font-size: 10px;\n  margin-right: 5px;\n  margin-top: 5px;\n  padding: 5px 12px;\n  display: inline-block;\n}\n.img-shadow {\n  -webkit-box-shadow: 0px 0px 3px 0px #919191;\n  -moz-box-shadow: 0px 0px 3px 0px #919191;\n  box-shadow: 0px 0px 3px 0px #919191;\n}\n/* For handle diferent bg color in AngularJS version */\n.dashboards\\.dashboard_2 nav.navbar,\n.dashboards\\.dashboard_3 nav.navbar,\n.mailbox\\.inbox nav.navbar,\n.mailbox\\.email_view nav.navbar,\n.mailbox\\.email_compose nav.navbar,\n.dashboards\\.dashboard_4_1 nav.navbar {\n  background: #fff;\n}\n/* For handle diferent bg color in MVC version */\n.Dashboard_2 .navbar.navbar-static-top,\n.Dashboard_3 .navbar.navbar-static-top,\n.Dashboard_4_1 .navbar.navbar-static-top,\n.ComposeEmail .navbar.navbar-static-top,\n.EmailView .navbar.navbar-static-top,\n.Inbox .navbar.navbar-static-top {\n  background: #fff;\n}\na.close-canvas-menu {\n  position: absolute;\n  top: 10px;\n  right: 15px;\n  z-index: 1011;\n  color: #a7b1c2;\n}\na.close-canvas-menu:hover {\n  color: #fff;\n}\n/* FULL HEIGHT */\n.full-height {\n  height: 100%;\n}\n.fh-breadcrumb {\n  height: calc(100% - 196px);\n  margin: 0 -15px;\n  position: relative;\n}\n.fh-no-breadcrumb {\n  height: calc(100% - 99px);\n  margin: 0 -15px;\n  position: relative;\n}\n.fh-column {\n  background: #fff;\n  height: 100%;\n  width: 240px;\n  float: left;\n}\n.modal-backdrop {\n  z-index: 2040 !important;\n}\n.modal {\n  z-index: 2050 !important;\n}\n.spiner-example {\n  height: 200px;\n  padding-top: 70px;\n}\n/* MARGINS & PADDINGS */\n.p-xxs {\n  padding: 5px;\n}\n.p-xs {\n  padding: 10px;\n}\n.p-sm {\n  padding: 15px;\n}\n.p-m {\n  padding: 20px;\n}\n.p-md {\n  padding: 25px;\n}\n.p-lg {\n  padding: 30px;\n}\n.p-xl {\n  padding: 40px;\n}\n.m-xxs {\n  margin: 2px 4px;\n}\n.m-xs {\n  margin: 5px;\n}\n.m-sm {\n  margin: 10px;\n}\n.m {\n  margin: 15px;\n}\n.m-md {\n  margin: 20px;\n}\n.m-lg {\n  margin: 30px;\n}\n.m-xl {\n  margin: 50px;\n}\n.m-n {\n  margin: 0 !important;\n}\n.m-l-none {\n  margin-left: 0;\n}\n.m-l-xs {\n  margin-left: 5px;\n}\n.m-l-sm {\n  margin-left: 10px;\n}\n.m-l {\n  margin-left: 15px;\n}\n.m-l-md {\n  margin-left: 20px;\n}\n.m-l-lg {\n  margin-left: 30px;\n}\n.m-l-xl {\n  margin-left: 40px;\n}\n.m-l-n-xxs {\n  margin-left: -1px;\n}\n.m-l-n-xs {\n  margin-left: -5px;\n}\n.m-l-n-sm {\n  margin-left: -10px;\n}\n.m-l-n {\n  margin-left: -15px;\n}\n.m-l-n-md {\n  margin-left: -20px;\n}\n.m-l-n-lg {\n  margin-left: -30px;\n}\n.m-l-n-xl {\n  margin-left: -40px;\n}\n.m-t-none {\n  margin-top: 0;\n}\n.m-t-xxs {\n  margin-top: 1px;\n}\n.m-t-xs {\n  margin-top: 5px;\n}\n.m-t-sm {\n  margin-top: 10px;\n}\n.m-t {\n  margin-top: 15px;\n}\n.m-t-md {\n  margin-top: 20px;\n}\n.m-t-lg {\n  margin-top: 30px;\n}\n.m-t-xl {\n  margin-top: 40px;\n}\n.m-t-n-xxs {\n  margin-top: -1px;\n}\n.m-t-n-xs {\n  margin-top: -5px;\n}\n.m-t-n-sm {\n  margin-top: -10px;\n}\n.m-t-n {\n  margin-top: -15px;\n}\n.m-t-n-md {\n  margin-top: -20px;\n}\n.m-t-n-lg {\n  margin-top: -30px;\n}\n.m-t-n-xl {\n  margin-top: -40px;\n}\n.m-r-none {\n  margin-right: 0;\n}\n.m-r-xxs {\n  margin-right: 1px;\n}\n.m-r-xs {\n  margin-right: 5px;\n}\n.m-r-sm {\n  margin-right: 10px;\n}\n.m-r {\n  margin-right: 15px;\n}\n.m-r-md {\n  margin-right: 20px;\n}\n.m-r-lg {\n  margin-right: 30px;\n}\n.m-r-xl {\n  margin-right: 40px;\n}\n.m-r-n-xxs {\n  margin-right: -1px;\n}\n.m-r-n-xs {\n  margin-right: -5px;\n}\n.m-r-n-sm {\n  margin-right: -10px;\n}\n.m-r-n {\n  margin-right: -15px;\n}\n.m-r-n-md {\n  margin-right: -20px;\n}\n.m-r-n-lg {\n  margin-right: -30px;\n}\n.m-r-n-xl {\n  margin-right: -40px;\n}\n.m-b-none {\n  margin-bottom: 0;\n}\n.m-b-xxs {\n  margin-bottom: 1px;\n}\n.m-b-xs {\n  margin-bottom: 5px;\n}\n.m-b-sm {\n  margin-bottom: 10px;\n}\n.m-b {\n  margin-bottom: 15px;\n}\n.m-b-md {\n  margin-bottom: 20px;\n}\n.m-b-lg {\n  margin-bottom: 30px;\n}\n.m-b-xl {\n  margin-bottom: 40px;\n}\n.m-b-n-xxs {\n  margin-bottom: -1px;\n}\n.m-b-n-xs {\n  margin-bottom: -5px;\n}\n.m-b-n-sm {\n  margin-bottom: -10px;\n}\n.m-b-n {\n  margin-bottom: -15px;\n}\n.m-b-n-md {\n  margin-bottom: -20px;\n}\n.m-b-n-lg {\n  margin-bottom: -30px;\n}\n.m-b-n-xl {\n  margin-bottom: -40px;\n}\n.space-15 {\n  margin: 15px 0;\n}\n.space-20 {\n  margin: 20px 0;\n}\n.space-25 {\n  margin: 25px 0;\n}\n.space-30 {\n  margin: 30px 0;\n}\nbody.modal-open {\n  padding-right: inherit !important;\n}\n/* SEARCH PAGE */\n.search-form {\n  margin-top: 10px;\n}\n.search-result h3 {\n  margin-bottom: 0;\n  color: #1E0FBE;\n}\n.search-result .search-link {\n  color: #006621;\n}\n.search-result p {\n  font-size: 12px;\n  margin-top: 5px;\n}\n/* CONTACTS */\n.contact-box {\n  background-color: #ffffff;\n  border: 1px solid #e7eaec;\n  padding: 20px;\n  margin-bottom: 20px;\n}\n.contact-box a {\n  color: inherit;\n}\n/* INVOICE */\n.invoice-table tbody > tr > td:last-child,\n.invoice-table tbody > tr > td:nth-child(4),\n.invoice-table tbody > tr > td:nth-child(3),\n.invoice-table tbody > tr > td:nth-child(2) {\n  text-align: right;\n}\n.invoice-table thead > tr > th:last-child,\n.invoice-table thead > tr > th:nth-child(4),\n.invoice-table thead > tr > th:nth-child(3),\n.invoice-table thead > tr > th:nth-child(2) {\n  text-align: right;\n}\n.invoice-total > tbody > tr > td:first-child {\n  text-align: right;\n}\n.invoice-total > tbody > tr > td {\n  border: 0 none;\n}\n.invoice-total > tbody > tr > td:last-child {\n  border-bottom: 1px solid #DDDDDD;\n  text-align: right;\n  width: 15%;\n}\n/* ERROR & LOGIN & LOCKSCREEN*/\n.middle-box {\n  max-width: 400px;\n  z-index: 100;\n  margin: 0 auto;\n  padding-top: 40px;\n}\n.lockscreen.middle-box {\n  width: 200px;\n  padding-top: 110px;\n}\n.loginscreen.middle-box {\n  width: 300px;\n}\n.loginColumns {\n  max-width: 800px;\n  margin: 0 auto;\n  padding: 100px 20px 20px 20px;\n}\n.passwordBox {\n  max-width: 460px;\n  margin: 0 auto;\n  padding: 100px 20px 20px 20px;\n}\n.logo-name {\n  color: #e6e6e6;\n  font-size: 180px;\n  font-weight: 800;\n  letter-spacing: -10px;\n  margin-bottom: 0px;\n}\n.middle-box h1 {\n  font-size: 170px;\n}\n.wrapper .middle-box {\n  margin-top: 140px;\n}\n.lock-word {\n  z-index: 10;\n  position: absolute;\n  top: 110px;\n  left: 50%;\n  margin-left: -470px;\n}\n.lock-word span {\n  font-size: 100px;\n  font-weight: 600;\n  color: #e9e9e9;\n  display: inline-block;\n}\n.lock-word .first-word {\n  margin-right: 160px;\n}\n/* DASBOARD */\n.dashboard-header {\n  border-top: 0;\n  padding: 20px 20px 20px 20px;\n}\n.dashboard-header h2 {\n  margin-top: 10px;\n  font-size: 26px;\n}\n.fist-item {\n  border-top: none !important;\n}\n.statistic-box {\n  margin-top: 40px;\n}\n.dashboard-header .list-group-item span.label {\n  margin-right: 10px;\n}\n.list-group.clear-list .list-group-item {\n  border-top: 1px solid #e7eaec;\n  border-bottom: 0;\n  border-right: 0;\n  border-left: 0;\n  padding: 10px 0;\n}\nul.clear-list:first-child {\n  border-top: none !important;\n}\n/* Intimeline */\n.timeline-item .date i {\n  position: absolute;\n  top: 0;\n  right: 0;\n  padding: 5px;\n  width: 30px;\n  text-align: center;\n  border-top: 1px solid #e7eaec;\n  border-bottom: 1px solid #e7eaec;\n  border-left: 1px solid #e7eaec;\n  background: #f8f8f8;\n}\n.timeline-item .date {\n  text-align: right;\n  width: 110px;\n  position: relative;\n  padding-top: 30px;\n}\n.timeline-item .content {\n  border-left: 1px solid #e7eaec;\n  border-top: 1px solid #e7eaec;\n  padding-top: 10px;\n  min-height: 100px;\n}\n.timeline-item .content:hover {\n  background: #f6f6f6;\n}\n/* PIN BOARD */\nul.notes li,\nul.tag-list li {\n  list-style: none;\n}\nul.notes li h4 {\n  margin-top: 20px;\n  font-size: 16px;\n}\nul.notes li div {\n  text-decoration: none;\n  color: #000;\n  background: #ffc;\n  display: block;\n  height: 140px;\n  width: 140px;\n  padding: 1em;\n  position: relative;\n}\nul.notes li div small {\n  position: absolute;\n  top: 5px;\n  right: 5px;\n  font-size: 10px;\n}\nul.notes li div a {\n  position: absolute;\n  right: 10px;\n  bottom: 10px;\n  color: inherit;\n}\nul.notes li {\n  margin: 10px 40px 50px 0px;\n  float: left;\n}\nul.notes li div p {\n  font-size: 12px;\n}\nul.notes li div {\n  text-decoration: none;\n  color: #000;\n  background: #ffc;\n  display: block;\n  height: 140px;\n  width: 140px;\n  padding: 1em;\n  /* Firefox */\n  -moz-box-shadow: 5px 5px 2px #212121;\n  /* Safari+Chrome */\n  -webkit-box-shadow: 5px 5px 2px rgba(33, 33, 33, 0.7);\n  /* Opera */\n  box-shadow: 5px 5px 2px rgba(33, 33, 33, 0.7);\n}\nul.notes li div {\n  -webkit-transform: rotate(-6deg);\n  -o-transform: rotate(-6deg);\n  -moz-transform: rotate(-6deg);\n}\nul.notes li:nth-child(even) div {\n  -o-transform: rotate(4deg);\n  -webkit-transform: rotate(4deg);\n  -moz-transform: rotate(4deg);\n  position: relative;\n  top: 5px;\n}\nul.notes li:nth-child(3n) div {\n  -o-transform: rotate(-3deg);\n  -webkit-transform: rotate(-3deg);\n  -moz-transform: rotate(-3deg);\n  position: relative;\n  top: -5px;\n}\nul.notes li:nth-child(5n) div {\n  -o-transform: rotate(5deg);\n  -webkit-transform: rotate(5deg);\n  -moz-transform: rotate(5deg);\n  position: relative;\n  top: -10px;\n}\nul.notes li div:hover,\nul.notes li div:focus {\n  -webkit-transform: scale(1.1);\n  -moz-transform: scale(1.1);\n  -o-transform: scale(1.1);\n  position: relative;\n  z-index: 5;\n}\nul.notes li div {\n  text-decoration: none;\n  color: #000;\n  background: #ffc;\n  display: block;\n  height: 210px;\n  width: 210px;\n  padding: 1em;\n  -moz-box-shadow: 5px 5px 7px #212121;\n  -webkit-box-shadow: 5px 5px 7px rgba(33, 33, 33, 0.7);\n  box-shadow: 5px 5px 7px rgba(33, 33, 33, 0.7);\n  -moz-transition: -moz-transform 0.15s linear;\n  -o-transition: -o-transform 0.15s linear;\n  -webkit-transition: -webkit-transform 0.15s linear;\n}\n/* FILE MANAGER */\n.file-box {\n  float: left;\n  width: 220px;\n}\n.file-manager h5 {\n  text-transform: uppercase;\n}\n.file-manager {\n  list-style: none outside none;\n  margin: 0;\n  padding: 0;\n}\n.folder-list li a {\n  color: #666666;\n  display: block;\n  padding: 5px 0;\n}\n.folder-list li {\n  border-bottom: 1px solid #e7eaec;\n  display: block;\n}\n.folder-list li i {\n  margin-right: 8px;\n  color: #3d4d5d;\n}\n.category-list li a {\n  color: #666666;\n  display: block;\n  padding: 5px 0;\n}\n.category-list li {\n  display: block;\n}\n.category-list li i {\n  margin-right: 8px;\n  color: #3d4d5d;\n}\n.category-list li a .text-navy {\n  color: #007bff;\n}\n.category-list li a .text-primary {\n  color: #007bff;\n}\n.category-list li a .text-info {\n  color: #007bff;\n}\n.category-list li a .text-danger {\n  color: #EF5352;\n}\n.category-list li a .text-warning {\n  color: #F8AC59;\n}\n.file-manager h5.tag-title {\n  margin-top: 20px;\n}\n.tag-list li {\n  float: left;\n}\n.tag-list li a {\n  font-size: 10px;\n  background-color: #f3f3f4;\n  padding: 5px 12px;\n  color: inherit;\n  border-radius: 2px;\n  border: 1px solid #e7eaec;\n  margin-right: 5px;\n  margin-top: 5px;\n  display: block;\n}\n.file {\n  border: 1px solid #e7eaec;\n  padding: 0;\n  background-color: #ffffff;\n  position: relative;\n  margin-bottom: 20px;\n  margin-right: 20px;\n}\n.file-manager .hr-line-dashed {\n  margin: 15px 0;\n}\n.file .icon,\n.file .image {\n  height: 100px;\n  overflow: hidden;\n}\n.file .icon {\n  padding: 15px 10px;\n  text-align: center;\n}\n.file-control {\n  color: inherit;\n  font-size: 11px;\n  margin-right: 10px;\n}\n.file-control.active {\n  text-decoration: underline;\n}\n.file .icon i {\n  font-size: 70px;\n  color: #dadada;\n}\n.file .file-name {\n  padding: 10px;\n  background-color: #f8f8f8;\n  border-top: 1px solid #e7eaec;\n}\n.file-name small {\n  color: #676a6c;\n}\n.corner {\n  position: absolute;\n  display: inline-block;\n  width: 0;\n  height: 0;\n  line-height: 0;\n  border: 0.6em solid transparent;\n  border-right: 0.6em solid #f1f1f1;\n  border-bottom: 0.6em solid #f1f1f1;\n  right: 0em;\n  bottom: 0em;\n}\na.compose-mail {\n  padding: 8px 10px;\n}\n.mail-search {\n  max-width: 300px;\n}\n/* PROFILE */\n.profile-content {\n  border-top: none !important;\n}\n.feed-activity-list .feed-element {\n  border-bottom: 1px solid #e7eaec;\n}\n.feed-element:first-child {\n  margin-top: 0;\n}\n.feed-element {\n  padding-bottom: 15px;\n}\n.feed-element,\n.feed-element .media {\n  margin-top: 15px;\n}\n.feed-element,\n.media-body {\n  overflow: hidden;\n}\n.feed-element > .pull-left {\n  margin-right: 10px;\n}\n.feed-element img.img-circle,\n.dropdown-messages-box img.img-circle {\n  width: 38px;\n  height: 38px;\n}\n.feed-element .well {\n  border: 1px solid #e7eaec;\n  box-shadow: none;\n  margin-top: 10px;\n  margin-bottom: 5px;\n  padding: 10px 20px;\n  font-size: 11px;\n  line-height: 16px;\n}\n.feed-element .actions {\n  margin-top: 10px;\n}\n.feed-element .photos {\n  margin: 10px 0;\n}\n.feed-photo {\n  max-height: 180px;\n  border-radius: 4px;\n  overflow: hidden;\n  margin-right: 10px;\n  margin-bottom: 10px;\n}\n/* MAILBOX */\n.mail-box {\n  background-color: #ffffff;\n  border: 1px solid #e7eaec;\n  border-top: 0;\n  padding: 0px;\n  margin-bottom: 20px;\n}\n.mail-box-header {\n  background-color: #ffffff;\n  border: 1px solid #e7eaec;\n  border-bottom: 0;\n  padding: 30px 20px 20px 20px;\n}\n.mail-box-header h2 {\n  margin-top: 0px;\n}\n.mailbox-content .tag-list li a {\n  background: #ffffff;\n}\n.mail-body {\n  border-top: 1px solid #e7eaec;\n  padding: 20px;\n}\n.mail-text {\n  border-top: 1px solid #e7eaec;\n}\n.mail-text .note-toolbar {\n  padding: 10px 15px;\n}\n.mail-body .form-group {\n  margin-bottom: 5px;\n}\n.mail-text .note-editor .note-toolbar {\n  background-color: #F9F8F8;\n}\n.mail-attachment {\n  border-top: 1px solid #e7eaec;\n  padding: 20px;\n  font-size: 12px;\n}\n.mailbox-content {\n  background: none;\n  border: none;\n  padding: 10px;\n}\n.mail-ontact {\n  width: 23%;\n}\n/* PROJECTS */\n.project-people,\n.project-actions {\n  text-align: right;\n  vertical-align: middle;\n}\ndd.project-people {\n  text-align: left;\n  margin-top: 5px;\n}\n.project-people img {\n  width: 32px;\n  height: 32px;\n}\n.project-title a {\n  font-size: 14px;\n  color: #676a6c;\n  font-weight: 600;\n}\n.project-list table tr td {\n  border-top: none;\n  border-bottom: 1px solid #e7eaec;\n  padding: 15px 10px;\n  vertical-align: middle;\n}\n.project-manager .tag-list li a {\n  font-size: 10px;\n  background-color: white;\n  padding: 5px 12px;\n  color: inherit;\n  border-radius: 2px;\n  border: 1px solid #e7eaec;\n  margin-right: 5px;\n  margin-top: 5px;\n  display: block;\n}\n.project-files li a {\n  font-size: 11px;\n  color: #676a6c;\n  margin-left: 10px;\n  line-height: 22px;\n}\n/* FAQ */\n.faq-item {\n  padding: 20px;\n  margin-bottom: 2px;\n  background: #fff;\n}\n.faq-question {\n  font-size: 18px;\n  font-weight: 600;\n  color: #007bff;\n  display: block;\n}\n.faq-question:hover {\n  color: #179d82;\n}\n.faq-answer {\n  margin-top: 10px;\n  background: #f3f3f4;\n  border: 1px solid #e7eaec;\n  border-radius: 3px;\n  padding: 15px;\n}\n.faq-item .tag-item {\n  background: #f3f3f4;\n  padding: 2px 6px;\n  font-size: 10px;\n  text-transform: uppercase;\n}\n/* Chat view */\n.message-input {\n  height: 90px !important;\n}\n.chat-avatar {\n  white: 36px;\n  height: 36px;\n  float: left;\n  margin-right: 10px;\n}\n.chat-user-name {\n  padding: 10px;\n}\n.chat-user {\n  padding: 8px 10px;\n  border-bottom: 1px solid #e7eaec;\n}\n.chat-user a {\n  color: inherit;\n}\n.chat-view {\n  z-index: 20012;\n}\n.chat-users,\n.chat-statistic {\n  margin-left: -30px;\n}\n@media (max-width: 992px) {\n  .chat-users,\n  .chat-statistic {\n    margin-left: 0px;\n  }\n}\n.chat-view .ibox-content {\n  padding: 0;\n}\n.chat-message {\n  padding: 10px 20px;\n}\n.message-avatar {\n  height: 48px;\n  width: 48px;\n  border: 1px solid #e7eaec;\n  border-radius: 4px;\n  margin-top: 1px;\n}\n.chat-discussion .chat-message:nth-child(2n+1) .message-avatar {\n  float: left;\n  margin-right: 10px;\n}\n.chat-discussion .chat-message:nth-child(2n) .message-avatar {\n  float: right;\n  margin-left: 10px;\n}\n.message {\n  background-color: #fff;\n  border: 1px solid #e7eaec;\n  text-align: left;\n  display: block;\n  padding: 10px 20px;\n  position: relative;\n  border-radius: 4px;\n}\n.chat-discussion .chat-message:nth-child(2n+1) .message-date {\n  float: right;\n}\n.chat-discussion .chat-message:nth-child(2n) .message-date {\n  float: left;\n}\n.chat-discussion .chat-message:nth-child(2n+1) .message {\n  text-align: left;\n  margin-left: 55px;\n}\n.chat-discussion .chat-message:nth-child(2n) .message {\n  text-align: right;\n  margin-right: 55px;\n}\n.message-date {\n  font-size: 10px;\n  color: #888888;\n}\n.message-content {\n  display: block;\n}\n.chat-discussion {\n  background: #eee;\n  padding: 15px;\n  height: 400px;\n  overflow-y: auto;\n}\n.chat-users {\n  overflow-y: auto;\n  height: 400px;\n}\n.chat-message-form .form-group {\n  margin-bottom: 0;\n}\n/* jsTree */\n.jstree-open > .jstree-anchor > .fa-folder:before {\n  content: \"\\f07c\";\n}\n.jstree-default .jstree-icon.none {\n  width: 0;\n}\n/* CLIENTS */\n.clients-list {\n  margin-top: 20px;\n}\n.clients-list .tab-pane {\n  position: relative;\n  height: 600px;\n}\n.client-detail {\n  position: relative;\n  height: 620px;\n}\n.clients-list table tr td {\n  height: 46px;\n  vertical-align: middle;\n  border: none ;\n}\n.client-link {\n  font-weight: 600;\n  color: inherit;\n}\n.client-link:hover {\n  color: inherit;\n}\n.client-avatar {\n  width: 42px;\n}\n.client-avatar img {\n  width: 28px;\n  height: 28px;\n  border-radius: 50%;\n}\n.contact-type {\n  width: 20px;\n  color: #c1c3c4;\n}\n.client-status {\n  text-align: left;\n}\n.client-detail .vertical-timeline-content p {\n  margin: 0;\n}\n.client-detail .vertical-timeline-icon.gray-bg {\n  color: #a7aaab;\n}\n.clients-list .nav-tabs > li.active > a,\n.clients-list .nav-tabs > li.active > a:hover,\n.clients-list .nav-tabs > li.active > a:focus {\n  border-bottom: 1px solid #fff;\n}\n/* BLOG ARTICLE */\n.blog h2 {\n  font-weight: 700;\n}\n.blog h5 {\n  margin: 0 0 5px 0;\n}\n.blog .btn {\n  margin: 0 0 5px 0;\n}\n.article h1 {\n  font-size: 48px;\n  font-weight: 700;\n  color: #2F4050;\n}\n.article p {\n  font-size: 15px;\n  line-height: 26px;\n}\n.article-title {\n  text-align: center;\n  margin: 40px 0 100px 0;\n}\n.article .ibox-content {\n  padding: 40px;\n}\n/* ISSUE TRACKER */\n.issue-tracker .btn-link {\n  color: #007bff;\n}\ntable.issue-tracker tbody tr td {\n  vertical-align: middle;\n  height: 50px;\n}\n.issue-info {\n  width: 50%;\n}\n.issue-info a {\n  font-weight: 600;\n  color: #676a6c;\n}\n.issue-info small {\n  display: block;\n}\n/* TEAMS */\n.team-members {\n  margin: 10px 0;\n}\n.team-members img.img-circle {\n  width: 42px;\n  height: 42px;\n  margin-bottom: 5px;\n}\n/* AGILE BOARD */\n.sortable-list {\n  padding: 10px 0;\n}\n.agile-list {\n  list-style: none;\n  margin: 0;\n}\n.agile-list li {\n  background: #FAFAFB;\n  border: 1px solid #e7eaec;\n  margin: 0px 0 10px 0;\n  padding: 10px;\n  border-radius: 2px;\n}\n.agile-list li:hover {\n  cursor: pointer;\n  background: #fff;\n}\n.agile-list li.warning-element {\n  border-left: 3px solid #f8ac59;\n}\n.agile-list li.danger-element {\n  border-left: 3px solid #ed5565;\n}\n.agile-list li.info-element {\n  border-left: 3px solid #007bff;\n}\n.agile-list li.success-element {\n  border-left: 3px solid #007bff;\n}\n.agile-detail {\n  margin-top: 5px;\n  font-size: 12px;\n}\n/* DIFF */\nins {\n  background-color: #c6ffc6;\n  text-decoration: none;\n}\ndel {\n  background-color: #ffc6c6;\n}\n#small-chat {\n  position: fixed;\n  bottom: 20px;\n  right: 20px;\n  z-index: 100;\n}\n#small-chat .badge {\n  position: absolute;\n  top: -3px;\n  right: -4px;\n}\n.open-small-chat {\n  height: 38px;\n  width: 38px;\n  display: block;\n  background: #007bff;\n  padding: 9px 8px;\n  text-align: center;\n  color: #fff;\n  border-radius: 50%;\n}\n.open-small-chat:hover {\n  color: white;\n  background: #007bff;\n}\n.small-chat-box {\n  display: none;\n  position: fixed;\n  bottom: 20px;\n  right: 75px;\n  background: #fff;\n  border: 1px solid #e7eaec;\n  width: 230px;\n  height: 320px;\n  border-radius: 4px;\n}\n.small-chat-box.ng-small-chat {\n  display: block;\n}\n.body-small .small-chat-box {\n  bottom: 70px;\n  right: 20px;\n}\n.small-chat-box.active {\n  display: block;\n}\n.small-chat-box .heading {\n  background: #2f4050;\n  padding: 8px 15px;\n  font-weight: bold;\n  color: #fff;\n}\n.small-chat-box .chat-date {\n  opacity: 0.6;\n  font-size: 10px;\n  font-weight: normal;\n}\n.small-chat-box .content {\n  padding: 15px 15px;\n}\n.small-chat-box .content .author-name {\n  font-weight: bold;\n  margin-bottom: 3px;\n  font-size: 11px;\n}\n.small-chat-box .content > div {\n  padding-bottom: 20px;\n}\n.small-chat-box .content .chat-message {\n  padding: 5px 10px;\n  border-radius: 6px;\n  font-size: 11px;\n  line-height: 14px;\n  max-width: 80%;\n  background: #f3f3f4;\n  margin-bottom: 10px;\n}\n.small-chat-box .content .chat-message.active {\n  background: #007bff;\n  color: #fff;\n}\n.small-chat-box .content .left {\n  text-align: left;\n  clear: both;\n}\n.small-chat-box .content .left .chat-message {\n  float: left;\n}\n.small-chat-box .content .right {\n  text-align: right;\n  clear: both;\n}\n.small-chat-box .content .right .chat-message {\n  float: right;\n}\n.small-chat-box .form-chat {\n  padding: 10px 10px;\n}\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-rotating-plane\"></div>\n *\n */\n.sk-spinner-rotating-plane.sk-spinner {\n  width: 30px;\n  height: 30px;\n  background-color: #007bff;\n  margin: 0 auto;\n  -webkit-animation: sk-rotatePlane 1.2s infinite ease-in-out;\n  animation: sk-rotatePlane 1.2s infinite ease-in-out;\n}\n@-webkit-keyframes sk-rotatePlane {\n  0% {\n    -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg);\n    transform: perspective(120px) rotateX(0deg) rotateY(0deg);\n  }\n  50% {\n    -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);\n    transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);\n  }\n  100% {\n    -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);\n    transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);\n  }\n}\n@keyframes sk-rotatePlane {\n  0% {\n    -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg);\n    transform: perspective(120px) rotateX(0deg) rotateY(0deg);\n  }\n  50% {\n    -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);\n    transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);\n  }\n  100% {\n    -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);\n    transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);\n  }\n}\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-double-bounce\">\n *      <div class=\"sk-double-bounce1\"></div>\n *      <div class=\"sk-double-bounce2\"></div>\n *    </div>\n *\n */\n.sk-spinner-double-bounce.sk-spinner {\n  width: 40px;\n  height: 40px;\n  position: relative;\n  margin: 0 auto;\n}\n.sk-spinner-double-bounce .sk-double-bounce1,\n.sk-spinner-double-bounce .sk-double-bounce2 {\n  width: 100%;\n  height: 100%;\n  border-radius: 50%;\n  background-color: #007bff;\n  opacity: 0.6;\n  position: absolute;\n  top: 0;\n  left: 0;\n  -webkit-animation: sk-doubleBounce 2s infinite ease-in-out;\n  animation: sk-doubleBounce 2s infinite ease-in-out;\n}\n.sk-spinner-double-bounce .sk-double-bounce2 {\n  -webkit-animation-delay: -1s;\n  animation-delay: -1s;\n}\n@-webkit-keyframes sk-doubleBounce {\n  0%,\n  100% {\n    -webkit-transform: scale(0);\n    transform: scale(0);\n  }\n  50% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n@keyframes sk-doubleBounce {\n  0%,\n  100% {\n    -webkit-transform: scale(0);\n    transform: scale(0);\n  }\n  50% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-wave\">\n *      <div class=\"sk-rect1\"></div>\n *      <div class=\"sk-rect2\"></div>\n *      <div class=\"sk-rect3\"></div>\n *      <div class=\"sk-rect4\"></div>\n *      <div class=\"sk-rect5\"></div>\n *    </div>\n *\n */\n.sk-spinner-wave.sk-spinner {\n  margin: 0 auto;\n  width: 50px;\n  height: 30px;\n  text-align: center;\n  font-size: 10px;\n}\n.sk-spinner-wave div {\n  background-color: #007bff;\n  height: 100%;\n  width: 6px;\n  display: inline-block;\n  -webkit-animation: sk-waveStretchDelay 1.2s infinite ease-in-out;\n  animation: sk-waveStretchDelay 1.2s infinite ease-in-out;\n}\n.sk-spinner-wave .sk-rect2 {\n  -webkit-animation-delay: -1.1s;\n  animation-delay: -1.1s;\n}\n.sk-spinner-wave .sk-rect3 {\n  -webkit-animation-delay: -1s;\n  animation-delay: -1s;\n}\n.sk-spinner-wave .sk-rect4 {\n  -webkit-animation-delay: -0.9s;\n  animation-delay: -0.9s;\n}\n.sk-spinner-wave .sk-rect5 {\n  -webkit-animation-delay: -0.8s;\n  animation-delay: -0.8s;\n}\n@-webkit-keyframes sk-waveStretchDelay {\n  0%,\n  40%,\n  100% {\n    -webkit-transform: scaleY(0.4);\n    transform: scaleY(0.4);\n  }\n  20% {\n    -webkit-transform: scaleY(1);\n    transform: scaleY(1);\n  }\n}\n@keyframes sk-waveStretchDelay {\n  0%,\n  40%,\n  100% {\n    -webkit-transform: scaleY(0.4);\n    transform: scaleY(0.4);\n  }\n  20% {\n    -webkit-transform: scaleY(1);\n    transform: scaleY(1);\n  }\n}\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-wandering-cubes\">\n *      <div class=\"sk-cube1\"></div>\n *      <div class=\"sk-cube2\"></div>\n *    </div>\n *\n */\n.sk-spinner-wandering-cubes.sk-spinner {\n  margin: 0 auto;\n  width: 32px;\n  height: 32px;\n  position: relative;\n}\n.sk-spinner-wandering-cubes .sk-cube1,\n.sk-spinner-wandering-cubes .sk-cube2 {\n  background-color: #007bff;\n  width: 10px;\n  height: 10px;\n  position: absolute;\n  top: 0;\n  left: 0;\n  -webkit-animation: sk-wanderingCubeMove 1.8s infinite ease-in-out;\n  animation: sk-wanderingCubeMove 1.8s infinite ease-in-out;\n}\n.sk-spinner-wandering-cubes .sk-cube2 {\n  -webkit-animation-delay: -0.9s;\n  animation-delay: -0.9s;\n}\n@-webkit-keyframes sk-wanderingCubeMove {\n  25% {\n    -webkit-transform: translateX(42px) rotate(-90deg) scale(0.5);\n    transform: translateX(42px) rotate(-90deg) scale(0.5);\n  }\n  50% {\n    /* Hack to make FF rotate in the right direction */\n    -webkit-transform: translateX(42px) translateY(42px) rotate(-179deg);\n    transform: translateX(42px) translateY(42px) rotate(-179deg);\n  }\n  50.1% {\n    -webkit-transform: translateX(42px) translateY(42px) rotate(-180deg);\n    transform: translateX(42px) translateY(42px) rotate(-180deg);\n  }\n  75% {\n    -webkit-transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5);\n    transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5);\n  }\n  100% {\n    -webkit-transform: rotate(-360deg);\n    transform: rotate(-360deg);\n  }\n}\n@keyframes sk-wanderingCubeMove {\n  25% {\n    -webkit-transform: translateX(42px) rotate(-90deg) scale(0.5);\n    transform: translateX(42px) rotate(-90deg) scale(0.5);\n  }\n  50% {\n    /* Hack to make FF rotate in the right direction */\n    -webkit-transform: translateX(42px) translateY(42px) rotate(-179deg);\n    transform: translateX(42px) translateY(42px) rotate(-179deg);\n  }\n  50.1% {\n    -webkit-transform: translateX(42px) translateY(42px) rotate(-180deg);\n    transform: translateX(42px) translateY(42px) rotate(-180deg);\n  }\n  75% {\n    -webkit-transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5);\n    transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5);\n  }\n  100% {\n    -webkit-transform: rotate(-360deg);\n    transform: rotate(-360deg);\n  }\n}\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-pulse\"></div>\n *\n */\n.sk-spinner-pulse.sk-spinner {\n  width: 40px;\n  height: 40px;\n  margin: 0 auto;\n  background-color: #007bff;\n  border-radius: 100%;\n  -webkit-animation: sk-pulseScaleOut 1s infinite ease-in-out;\n  animation: sk-pulseScaleOut 1s infinite ease-in-out;\n}\n@-webkit-keyframes sk-pulseScaleOut {\n  0% {\n    -webkit-transform: scale(0);\n    transform: scale(0);\n  }\n  100% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n    opacity: 0;\n  }\n}\n@keyframes sk-pulseScaleOut {\n  0% {\n    -webkit-transform: scale(0);\n    transform: scale(0);\n  }\n  100% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n    opacity: 0;\n  }\n}\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-chasing-dots\">\n *      <div class=\"sk-dot1\"></div>\n *      <div class=\"sk-dot2\"></div>\n *    </div>\n *\n */\n.sk-spinner-chasing-dots.sk-spinner {\n  margin: 0 auto;\n  width: 40px;\n  height: 40px;\n  position: relative;\n  text-align: center;\n  -webkit-animation: sk-chasingDotsRotate 2s infinite linear;\n  animation: sk-chasingDotsRotate 2s infinite linear;\n}\n.sk-spinner-chasing-dots .sk-dot1,\n.sk-spinner-chasing-dots .sk-dot2 {\n  width: 60%;\n  height: 60%;\n  display: inline-block;\n  position: absolute;\n  top: 0;\n  background-color: #007bff;\n  border-radius: 100%;\n  -webkit-animation: sk-chasingDotsBounce 2s infinite ease-in-out;\n  animation: sk-chasingDotsBounce 2s infinite ease-in-out;\n}\n.sk-spinner-chasing-dots .sk-dot2 {\n  top: auto;\n  bottom: 0px;\n  -webkit-animation-delay: -1s;\n  animation-delay: -1s;\n}\n@-webkit-keyframes sk-chasingDotsRotate {\n  100% {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@keyframes sk-chasingDotsRotate {\n  100% {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-webkit-keyframes sk-chasingDotsBounce {\n  0%,\n  100% {\n    -webkit-transform: scale(0);\n    transform: scale(0);\n  }\n  50% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n@keyframes sk-chasingDotsBounce {\n  0%,\n  100% {\n    -webkit-transform: scale(0);\n    transform: scale(0);\n  }\n  50% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-three-bounce\">\n *      <div class=\"sk-bounce1\"></div>\n *      <div class=\"sk-bounce2\"></div>\n *      <div class=\"sk-bounce3\"></div>\n *    </div>\n *\n */\n.sk-spinner-three-bounce.sk-spinner {\n  margin: 0 auto;\n  width: 70px;\n  text-align: center;\n}\n.sk-spinner-three-bounce div {\n  width: 18px;\n  height: 18px;\n  background-color: #007bff;\n  border-radius: 100%;\n  display: inline-block;\n  -webkit-animation: sk-threeBounceDelay 1.4s infinite ease-in-out;\n  animation: sk-threeBounceDelay 1.4s infinite ease-in-out;\n  /* Prevent first frame from flickering when animation starts */\n  -webkit-animation-fill-mode: both;\n  animation-fill-mode: both;\n}\n.sk-spinner-three-bounce .sk-bounce1 {\n  -webkit-animation-delay: -0.32s;\n  animation-delay: -0.32s;\n}\n.sk-spinner-three-bounce .sk-bounce2 {\n  -webkit-animation-delay: -0.16s;\n  animation-delay: -0.16s;\n}\n@-webkit-keyframes sk-threeBounceDelay {\n  0%,\n  80%,\n  100% {\n    -webkit-transform: scale(0);\n    transform: scale(0);\n  }\n  40% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n@keyframes sk-threeBounceDelay {\n  0%,\n  80%,\n  100% {\n    -webkit-transform: scale(0);\n    transform: scale(0);\n  }\n  40% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-circle\">\n *      <div class=\"sk-circle1 sk-circle\"></div>\n *      <div class=\"sk-circle2 sk-circle\"></div>\n *      <div class=\"sk-circle3 sk-circle\"></div>\n *      <div class=\"sk-circle4 sk-circle\"></div>\n *      <div class=\"sk-circle5 sk-circle\"></div>\n *      <div class=\"sk-circle6 sk-circle\"></div>\n *      <div class=\"sk-circle7 sk-circle\"></div>\n *      <div class=\"sk-circle8 sk-circle\"></div>\n *      <div class=\"sk-circle9 sk-circle\"></div>\n *      <div class=\"sk-circle10 sk-circle\"></div>\n *      <div class=\"sk-circle11 sk-circle\"></div>\n *      <div class=\"sk-circle12 sk-circle\"></div>\n *    </div>\n *\n */\n.sk-spinner-circle.sk-spinner {\n  margin: 0 auto;\n  width: 22px;\n  height: 22px;\n  position: relative;\n}\n.sk-spinner-circle .sk-circle {\n  width: 100%;\n  height: 100%;\n  position: absolute;\n  left: 0;\n  top: 0;\n}\n.sk-spinner-circle .sk-circle:before {\n  content: '';\n  display: block;\n  margin: 0 auto;\n  width: 20%;\n  height: 20%;\n  background-color: #007bff;\n  border-radius: 100%;\n  -webkit-animation: sk-circleBounceDelay 1.2s infinite ease-in-out;\n  animation: sk-circleBounceDelay 1.2s infinite ease-in-out;\n  /* Prevent first frame from flickering when animation starts */\n  -webkit-animation-fill-mode: both;\n  animation-fill-mode: both;\n}\n.sk-spinner-circle .sk-circle2 {\n  -webkit-transform: rotate(30deg);\n  -ms-transform: rotate(30deg);\n  transform: rotate(30deg);\n}\n.sk-spinner-circle .sk-circle3 {\n  -webkit-transform: rotate(60deg);\n  -ms-transform: rotate(60deg);\n  transform: rotate(60deg);\n}\n.sk-spinner-circle .sk-circle4 {\n  -webkit-transform: rotate(90deg);\n  -ms-transform: rotate(90deg);\n  transform: rotate(90deg);\n}\n.sk-spinner-circle .sk-circle5 {\n  -webkit-transform: rotate(120deg);\n  -ms-transform: rotate(120deg);\n  transform: rotate(120deg);\n}\n.sk-spinner-circle .sk-circle6 {\n  -webkit-transform: rotate(150deg);\n  -ms-transform: rotate(150deg);\n  transform: rotate(150deg);\n}\n.sk-spinner-circle .sk-circle7 {\n  -webkit-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  transform: rotate(180deg);\n}\n.sk-spinner-circle .sk-circle8 {\n  -webkit-transform: rotate(210deg);\n  -ms-transform: rotate(210deg);\n  transform: rotate(210deg);\n}\n.sk-spinner-circle .sk-circle9 {\n  -webkit-transform: rotate(240deg);\n  -ms-transform: rotate(240deg);\n  transform: rotate(240deg);\n}\n.sk-spinner-circle .sk-circle10 {\n  -webkit-transform: rotate(270deg);\n  -ms-transform: rotate(270deg);\n  transform: rotate(270deg);\n}\n.sk-spinner-circle .sk-circle11 {\n  -webkit-transform: rotate(300deg);\n  -ms-transform: rotate(300deg);\n  transform: rotate(300deg);\n}\n.sk-spinner-circle .sk-circle12 {\n  -webkit-transform: rotate(330deg);\n  -ms-transform: rotate(330deg);\n  transform: rotate(330deg);\n}\n.sk-spinner-circle .sk-circle2:before {\n  -webkit-animation-delay: -1.1s;\n  animation-delay: -1.1s;\n}\n.sk-spinner-circle .sk-circle3:before {\n  -webkit-animation-delay: -1s;\n  animation-delay: -1s;\n}\n.sk-spinner-circle .sk-circle4:before {\n  -webkit-animation-delay: -0.9s;\n  animation-delay: -0.9s;\n}\n.sk-spinner-circle .sk-circle5:before {\n  -webkit-animation-delay: -0.8s;\n  animation-delay: -0.8s;\n}\n.sk-spinner-circle .sk-circle6:before {\n  -webkit-animation-delay: -0.7s;\n  animation-delay: -0.7s;\n}\n.sk-spinner-circle .sk-circle7:before {\n  -webkit-animation-delay: -0.6s;\n  animation-delay: -0.6s;\n}\n.sk-spinner-circle .sk-circle8:before {\n  -webkit-animation-delay: -0.5s;\n  animation-delay: -0.5s;\n}\n.sk-spinner-circle .sk-circle9:before {\n  -webkit-animation-delay: -0.4s;\n  animation-delay: -0.4s;\n}\n.sk-spinner-circle .sk-circle10:before {\n  -webkit-animation-delay: -0.3s;\n  animation-delay: -0.3s;\n}\n.sk-spinner-circle .sk-circle11:before {\n  -webkit-animation-delay: -0.2s;\n  animation-delay: -0.2s;\n}\n.sk-spinner-circle .sk-circle12:before {\n  -webkit-animation-delay: -0.1s;\n  animation-delay: -0.1s;\n}\n@-webkit-keyframes sk-circleBounceDelay {\n  0%,\n  80%,\n  100% {\n    -webkit-transform: scale(0);\n    transform: scale(0);\n  }\n  40% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n@keyframes sk-circleBounceDelay {\n  0%,\n  80%,\n  100% {\n    -webkit-transform: scale(0);\n    transform: scale(0);\n  }\n  40% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-cube-grid\">\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *    </div>\n *\n */\n.sk-spinner-cube-grid {\n  /*\n   * Spinner positions\n   * 1 2 3\n   * 4 5 6\n   * 7 8 9\n   */\n}\n.sk-spinner-cube-grid.sk-spinner {\n  width: 30px;\n  height: 30px;\n  margin: 0 auto;\n}\n.sk-spinner-cube-grid .sk-cube {\n  width: 33%;\n  height: 33%;\n  background-color: #007bff;\n  float: left;\n  -webkit-animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;\n  animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;\n}\n.sk-spinner-cube-grid .sk-cube:nth-child(1) {\n  -webkit-animation-delay: 0.2s;\n  animation-delay: 0.2s;\n}\n.sk-spinner-cube-grid .sk-cube:nth-child(2) {\n  -webkit-animation-delay: 0.3s;\n  animation-delay: 0.3s;\n}\n.sk-spinner-cube-grid .sk-cube:nth-child(3) {\n  -webkit-animation-delay: 0.4s;\n  animation-delay: 0.4s;\n}\n.sk-spinner-cube-grid .sk-cube:nth-child(4) {\n  -webkit-animation-delay: 0.1s;\n  animation-delay: 0.1s;\n}\n.sk-spinner-cube-grid .sk-cube:nth-child(5) {\n  -webkit-animation-delay: 0.2s;\n  animation-delay: 0.2s;\n}\n.sk-spinner-cube-grid .sk-cube:nth-child(6) {\n  -webkit-animation-delay: 0.3s;\n  animation-delay: 0.3s;\n}\n.sk-spinner-cube-grid .sk-cube:nth-child(7) {\n  -webkit-animation-delay: 0s;\n  animation-delay: 0s;\n}\n.sk-spinner-cube-grid .sk-cube:nth-child(8) {\n  -webkit-animation-delay: 0.1s;\n  animation-delay: 0.1s;\n}\n.sk-spinner-cube-grid .sk-cube:nth-child(9) {\n  -webkit-animation-delay: 0.2s;\n  animation-delay: 0.2s;\n}\n@-webkit-keyframes sk-cubeGridScaleDelay {\n  0%,\n  70%,\n  100% {\n    -webkit-transform: scale3D(1, 1, 1);\n    transform: scale3D(1, 1, 1);\n  }\n  35% {\n    -webkit-transform: scale3D(0, 0, 1);\n    transform: scale3D(0, 0, 1);\n  }\n}\n@keyframes sk-cubeGridScaleDelay {\n  0%,\n  70%,\n  100% {\n    -webkit-transform: scale3D(1, 1, 1);\n    transform: scale3D(1, 1, 1);\n  }\n  35% {\n    -webkit-transform: scale3D(0, 0, 1);\n    transform: scale3D(0, 0, 1);\n  }\n}\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-wordpress\">\n *      <span class=\"sk-inner-circle\"></span>\n *    </div>\n *\n */\n.sk-spinner-wordpress.sk-spinner {\n  background-color: #007bff;\n  width: 30px;\n  height: 30px;\n  border-radius: 30px;\n  position: relative;\n  margin: 0 auto;\n  -webkit-animation: sk-innerCircle 1s linear infinite;\n  animation: sk-innerCircle 1s linear infinite;\n}\n.sk-spinner-wordpress .sk-inner-circle {\n  display: block;\n  background-color: #fff;\n  width: 8px;\n  height: 8px;\n  position: absolute;\n  border-radius: 8px;\n  top: 5px;\n  left: 5px;\n}\n@-webkit-keyframes sk-innerCircle {\n  0% {\n    -webkit-transform: rotate(0);\n    transform: rotate(0);\n  }\n  100% {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@keyframes sk-innerCircle {\n  0% {\n    -webkit-transform: rotate(0);\n    transform: rotate(0);\n  }\n  100% {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-fading-circle\">\n *      <div class=\"sk-circle1 sk-circle\"></div>\n *      <div class=\"sk-circle2 sk-circle\"></div>\n *      <div class=\"sk-circle3 sk-circle\"></div>\n *      <div class=\"sk-circle4 sk-circle\"></div>\n *      <div class=\"sk-circle5 sk-circle\"></div>\n *      <div class=\"sk-circle6 sk-circle\"></div>\n *      <div class=\"sk-circle7 sk-circle\"></div>\n *      <div class=\"sk-circle8 sk-circle\"></div>\n *      <div class=\"sk-circle9 sk-circle\"></div>\n *      <div class=\"sk-circle10 sk-circle\"></div>\n *      <div class=\"sk-circle11 sk-circle\"></div>\n *      <div class=\"sk-circle12 sk-circle\"></div>\n *    </div>\n *\n */\n.sk-spinner-fading-circle.sk-spinner {\n  margin: 0 auto;\n  width: 22px;\n  height: 22px;\n  position: relative;\n}\n.sk-spinner-fading-circle .sk-circle {\n  width: 100%;\n  height: 100%;\n  position: absolute;\n  left: 0;\n  top: 0;\n}\n.sk-spinner-fading-circle .sk-circle:before {\n  content: '';\n  display: block;\n  margin: 0 auto;\n  width: 18%;\n  height: 18%;\n  background-color: #007bff;\n  border-radius: 100%;\n  -webkit-animation: sk-circleFadeDelay 1.2s infinite ease-in-out;\n  animation: sk-circleFadeDelay 1.2s infinite ease-in-out;\n  /* Prevent first frame from flickering when animation starts */\n  -webkit-animation-fill-mode: both;\n  animation-fill-mode: both;\n}\n.sk-spinner-fading-circle .sk-circle2 {\n  -webkit-transform: rotate(30deg);\n  -ms-transform: rotate(30deg);\n  transform: rotate(30deg);\n}\n.sk-spinner-fading-circle .sk-circle3 {\n  -webkit-transform: rotate(60deg);\n  -ms-transform: rotate(60deg);\n  transform: rotate(60deg);\n}\n.sk-spinner-fading-circle .sk-circle4 {\n  -webkit-transform: rotate(90deg);\n  -ms-transform: rotate(90deg);\n  transform: rotate(90deg);\n}\n.sk-spinner-fading-circle .sk-circle5 {\n  -webkit-transform: rotate(120deg);\n  -ms-transform: rotate(120deg);\n  transform: rotate(120deg);\n}\n.sk-spinner-fading-circle .sk-circle6 {\n  -webkit-transform: rotate(150deg);\n  -ms-transform: rotate(150deg);\n  transform: rotate(150deg);\n}\n.sk-spinner-fading-circle .sk-circle7 {\n  -webkit-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  transform: rotate(180deg);\n}\n.sk-spinner-fading-circle .sk-circle8 {\n  -webkit-transform: rotate(210deg);\n  -ms-transform: rotate(210deg);\n  transform: rotate(210deg);\n}\n.sk-spinner-fading-circle .sk-circle9 {\n  -webkit-transform: rotate(240deg);\n  -ms-transform: rotate(240deg);\n  transform: rotate(240deg);\n}\n.sk-spinner-fading-circle .sk-circle10 {\n  -webkit-transform: rotate(270deg);\n  -ms-transform: rotate(270deg);\n  transform: rotate(270deg);\n}\n.sk-spinner-fading-circle .sk-circle11 {\n  -webkit-transform: rotate(300deg);\n  -ms-transform: rotate(300deg);\n  transform: rotate(300deg);\n}\n.sk-spinner-fading-circle .sk-circle12 {\n  -webkit-transform: rotate(330deg);\n  -ms-transform: rotate(330deg);\n  transform: rotate(330deg);\n}\n.sk-spinner-fading-circle .sk-circle2:before {\n  -webkit-animation-delay: -1.1s;\n  animation-delay: -1.1s;\n}\n.sk-spinner-fading-circle .sk-circle3:before {\n  -webkit-animation-delay: -1s;\n  animation-delay: -1s;\n}\n.sk-spinner-fading-circle .sk-circle4:before {\n  -webkit-animation-delay: -0.9s;\n  animation-delay: -0.9s;\n}\n.sk-spinner-fading-circle .sk-circle5:before {\n  -webkit-animation-delay: -0.8s;\n  animation-delay: -0.8s;\n}\n.sk-spinner-fading-circle .sk-circle6:before {\n  -webkit-animation-delay: -0.7s;\n  animation-delay: -0.7s;\n}\n.sk-spinner-fading-circle .sk-circle7:before {\n  -webkit-animation-delay: -0.6s;\n  animation-delay: -0.6s;\n}\n.sk-spinner-fading-circle .sk-circle8:before {\n  -webkit-animation-delay: -0.5s;\n  animation-delay: -0.5s;\n}\n.sk-spinner-fading-circle .sk-circle9:before {\n  -webkit-animation-delay: -0.4s;\n  animation-delay: -0.4s;\n}\n.sk-spinner-fading-circle .sk-circle10:before {\n  -webkit-animation-delay: -0.3s;\n  animation-delay: -0.3s;\n}\n.sk-spinner-fading-circle .sk-circle11:before {\n  -webkit-animation-delay: -0.2s;\n  animation-delay: -0.2s;\n}\n.sk-spinner-fading-circle .sk-circle12:before {\n  -webkit-animation-delay: -0.1s;\n  animation-delay: -0.1s;\n}\n@-webkit-keyframes sk-circleFadeDelay {\n  0%,\n  39%,\n  100% {\n    opacity: 0;\n  }\n  40% {\n    opacity: 1;\n  }\n}\n@keyframes sk-circleFadeDelay {\n  0%,\n  39%,\n  100% {\n    opacity: 0;\n  }\n  40% {\n    opacity: 1;\n  }\n}\nbody.rtls {\n  /* Theme config */\n}\nbody.rtls #page-wrapper {\n  margin: 0 220px 0 0;\n}\nbody.rtls .nav-second-level li a {\n  padding: 7px 35px 7px 10px;\n}\nbody.rtls .ibox-title h5 {\n  float: right;\n}\nbody.rtls .pull-right {\n  float: left !important;\n}\nbody.rtls .pull-left {\n  float: right !important;\n}\nbody.rtls .ibox-tools {\n  float: left;\n}\nbody.rtls .stat-percent {\n  float: left;\n}\nbody.rtls .navbar-right {\n  float: left !important;\n}\nbody.rtls .navbar-top-links li:last-child {\n  margin-left: 40px;\n  margin-right: 0;\n}\nbody.rtls .minimalize-styl-2 {\n  float: right;\n  margin: 14px 20px 5px 5px;\n}\nbody.rtls .feed-element > .pull-left {\n  margin-left: 10px;\n  margin-right: 0;\n}\nbody.rtls .timeline-item .date {\n  text-align: left;\n}\nbody.rtls .timeline-item .date i {\n  left: 0;\n  right: auto;\n}\nbody.rtls .timeline-item .content {\n  border-right: 1px solid #e7eaec;\n  border-left: none;\n}\nbody.rtls .theme-config {\n  left: 0;\n  right: auto;\n}\nbody.rtls .spin-icon {\n  border-radius: 0 20px 20px 0;\n}\nbody.rtls .toast-close-button {\n  float: left;\n}\nbody.rtls #toast-container > .toast:before {\n  margin: auto -1.5em auto 0.5em;\n}\nbody.rtls #toast-container > div {\n  padding: 15px 50px 15px 15px;\n}\nbody.rtls .center-orientation .vertical-timeline-icon i {\n  margin-left: 0;\n  margin-right: -12px;\n}\nbody.rtls .vertical-timeline-icon i {\n  right: 50%;\n  left: auto;\n  margin-left: auto;\n  margin-right: -12px;\n}\nbody.rtls .file-box {\n  float: right;\n}\nbody.rtls ul.notes li {\n  float: right;\n}\nbody.rtls .chat-users,\nbody.rtls .chat-statistic {\n  margin-right: -30px;\n  margin-left: auto;\n}\nbody.rtls .dropdown-menu > li > a {\n  text-align: right;\n}\nbody.rtls .b-r {\n  border-left: 1px solid #e7eaec;\n  border-right: none;\n}\nbody.rtls .dd-list .dd-list {\n  padding-right: 30px;\n  padding-left: 0;\n}\nbody.rtls .dd-item > button {\n  float: right;\n}\nbody.rtls .theme-config-box {\n  margin-left: -220px;\n  margin-right: 0;\n}\nbody.rtls .theme-config-box.show {\n  margin-left: 0;\n  margin-right: 0;\n}\nbody.rtls .spin-icon {\n  right: 0;\n  left: auto;\n}\nbody.rtls .skin-setttings {\n  margin-right: 40px;\n  margin-left: 0;\n}\nbody.rtls .skin-setttings {\n  direction: ltr;\n}\nbody.rtls .footer.fixed {\n  margin-right: 220px;\n  margin-left: 0;\n}\n@media (max-width: 992px) {\n  body.rtls .chat-users,\n  body.rtls .chat-statistic {\n    margin-right: 0px;\n  }\n}\nbody.rtls.mini-navbar .footer.fixed,\nbody.body-small.mini-navbar .footer.fixed {\n  margin: 0 70px 0 0;\n}\nbody.rtls.mini-navbar.fixed-sidebar .footer.fixed,\nbody.body-small.mini-navbar .footer.fixed {\n  margin: 0 0 0 0;\n}\nbody.rtls.top-navigation .navbar-toggle {\n  float: right;\n  margin-left: 15px;\n  margin-right: 15px;\n}\n.body-small.rtls.top-navigation .navbar-header {\n  float: none;\n}\nbody.rtls.top-navigation #page-wrapper {\n  margin: 0;\n}\nbody.rtls.mini-navbar #page-wrapper {\n  margin: 0 70px 0 0;\n}\nbody.rtls.mini-navbar.fixed-sidebar #page-wrapper {\n  margin: 0 0 0 0;\n}\nbody.rtls.body-small.fixed-sidebar.mini-navbar #page-wrapper {\n  margin: 0 220px 0 0;\n}\nbody.rtls.body-small.fixed-sidebar.mini-navbar .navbar-static-side {\n  width: 220px;\n}\n.body-small.rtls .navbar-fixed-top {\n  margin-right: 0px;\n}\n.body-small.rtls .navbar-header {\n  float: right;\n}\nbody.rtls .navbar-top-links li:last-child {\n  margin-left: 20px;\n}\nbody.rtls .top-navigation #page-wrapper,\nbody.rtls.mini-navbar .top-navigation #page-wrapper,\nbody.rtls.mini-navbar.top-navigation #page-wrapper {\n  margin: 0;\n}\nbody.rtls .top-navigation .footer.fixed,\nbody.rtls.top-navigation .footer.fixed {\n  margin: 0;\n}\n@media (max-width: 768px) {\n  body.rtls .navbar-top-links li:last-child {\n    margin-left: 20px;\n  }\n  .body-small.rtls #page-wrapper {\n    position: inherit;\n    margin: 0 0 0 0px;\n    min-height: 1000px;\n  }\n  .body-small.rtls .navbar-static-side {\n    display: none;\n    z-index: 2001;\n    position: absolute;\n    width: 70px;\n  }\n  .body-small.rtls.mini-navbar .navbar-static-side {\n    display: block;\n  }\n  .rtls.fixed-sidebar.body-small .navbar-static-side {\n    display: none;\n    z-index: 2001;\n    position: fixed;\n    width: 220px;\n  }\n  .rtls.fixed-sidebar.body-small.mini-navbar .navbar-static-side {\n    display: block;\n  }\n}\n.rtls .ltr-support {\n  direction: ltr;\n}\n/*\n *\n *   This is style for skin config\n *   Use only in demo theme\n *\n*/\n.theme-config {\n  position: absolute;\n  top: 90px;\n  right: 0px;\n  overflow: hidden;\n}\n.theme-config-box {\n  margin-right: -220px;\n  position: relative;\n  z-index: 2000;\n  transition-duration: 0.8s;\n}\n.theme-config-box.show {\n  margin-right: 0px;\n}\n.spin-icon {\n  background: #007bff;\n  position: absolute;\n  padding: 7px 10px 7px 13px;\n  border-radius: 20px 0px 0px 20px;\n  font-size: 16px;\n  top: 0;\n  left: 0px;\n  width: 40px;\n  color: #fff;\n  cursor: pointer;\n}\n.skin-setttings {\n  width: 220px;\n  margin-left: 40px;\n  background: #f3f3f4;\n}\n.skin-setttings .title {\n  background: #efefef;\n  text-align: center;\n  text-transform: uppercase;\n  font-weight: 600;\n  display: block;\n  padding: 10px 15px;\n  font-size: 12px;\n}\n.setings-item {\n  padding: 10px 30px;\n}\n.setings-item.skin {\n  text-align: center;\n}\n.setings-item .switch {\n  float: right;\n}\n.skin-name a {\n  text-transform: uppercase;\n}\n.setings-item a {\n  color: #fff;\n}\n.default-skin,\n.blue-skin,\n.ultra-skin,\n.yellow-skin {\n  text-align: center;\n}\n.default-skin {\n  font-weight: 600;\n  background: #007bff;\n}\n.default-skin:hover {\n  background: #199d82;\n}\n.blue-skin {\n  font-weight: 600;\n  background: url(\"patterns/header-profile-skin-1.png\") repeat scroll 0 0;\n}\n.blue-skin:hover {\n  background: #0d8ddb;\n}\n.yellow-skin {\n  font-weight: 600;\n  background: url(\"patterns/header-profile-skin-3.png\") repeat scroll 0 100%;\n}\n.yellow-skin:hover {\n  background: #ce8735;\n}\n.ultra-skin {\n  font-weight: 600;\n  background: url(\"patterns/header-profile-skin-2.png\") repeat scroll 0 0;\n}\n.ultra-skin:hover {\n  background: #1a2d40;\n}\n/*\n *\n *   SKIN 1 - H+ - Admin Theme\n *   NAME - Blue light\n *\n*/\n.skin-1 .minimalize-styl-2 {\n  margin: 14px 5px 5px 30px;\n}\n.skin-1 .navbar-top-links li:last-child {\n  margin-right: 30px;\n}\n.skin-1.fixed-nav .minimalize-styl-2 {\n  margin: 14px 5px 5px 15px;\n}\n.skin-1 .spin-icon {\n  background: #0e9aef !important;\n}\n.skin-1 .nav-header {\n  background: #0e9aef;\n  background: url('patterns/header-profile-skin-1.png');\n}\n.skin-1.mini-navbar .nav-second-level {\n  background: #3e495f;\n}\n.skin-1 .breadcrumb {\n  background: transparent;\n}\n.skin-1 .page-heading {\n  border: none;\n}\n.skin-1 .nav > li.active {\n  background: #3a4459;\n}\n.skin-1 .nav > li > a {\n  color: #9ea6b9;\n}\n.skin-1 .nav > li.active > a {\n  color: #fff;\n}\n.skin-1 .navbar-minimalize {\n  background: #0e9aef;\n  border-color: #0e9aef;\n}\nbody.skin-1 {\n  background: #3e495f;\n}\n.skin-1 .navbar-static-top {\n  background: #ffffff;\n}\n.skin-1 .dashboard-header {\n  background: transparent;\n  border-bottom: none !important;\n  border-top: none;\n  padding: 20px 30px 10px 30px;\n}\n.fixed-nav.skin-1 .navbar-fixed-top {\n  background: #fff;\n}\n.skin-1 .wrapper-content {\n  padding: 30px 15px;\n}\n.skin-1 #page-wrapper {\n  background: #f4f6fa;\n}\n.skin-1 .ibox-title,\n.skin-1 .ibox-content {\n  border-width: 1px;\n}\n.skin-1 .ibox-content:last-child {\n  border-style: solid solid solid solid;\n}\n.skin-1 .nav > li.active {\n  border: none;\n}\n.skin-1 .nav-header {\n  padding: 35px 25px 25px 25px;\n}\n.skin-1 .nav-header a.dropdown-toggle {\n  color: #fff;\n  margin-top: 10px;\n}\n.skin-1 .nav-header a.dropdown-toggle .text-muted {\n  color: #fff;\n  opacity: 0.8;\n}\n.skin-1 .profile-element {\n  text-align: center;\n}\n.skin-1 .img-circle {\n  border-radius: 5px;\n}\n.skin-1 .navbar-default .nav > li > a:hover,\n.skin-1 .navbar-default .nav > li > a:focus {\n  background: #3a4459;\n  color: #fff;\n}\n.skin-1 .nav.nav-tabs > li.active > a {\n  color: #555;\n}\n.skin-1 .nav.nav-tabs > li.active {\n  background: transparent;\n}\n/*\n *\n *   SKIN 2 - H+ - Admin Theme\n *   NAME - Ultra\n *\n*/\nbody.skin-2 {\n  color: #565758 !important;\n}\n.skin-2 .minimalize-styl-2 {\n  margin: 14px 5px 5px 25px;\n}\n.skin-2 .navbar-top-links li:last-child {\n  margin-right: 25px;\n}\n.skin-2 .spin-icon {\n  background: #007bff !important;\n}\n.skin-2 .nav-header {\n  background: #007bff;\n  background: url('patterns/header-profile-skin-2.png');\n}\n.skin-2.mini-navbar .nav-second-level {\n  background: #ededed;\n}\n.skin-2 .breadcrumb {\n  background: transparent;\n}\n.skin-2.fixed-nav .minimalize-styl-2 {\n  margin: 14px 5px 5px 15px;\n}\n.skin-2 .page-heading {\n  border: none;\n  background: rgba(255, 255, 255, 0.7);\n}\n.skin-2 .nav > li.active {\n  background: #e0e0e0;\n}\n.skin-2 .logo-element {\n  padding: 17px 0;\n}\n.skin-2 .nav > li > a,\n.skin-2 .welcome-message {\n  color: #edf6ff;\n}\n.skin-2 #top-search::-moz-placeholder {\n  color: #edf6ff;\n  opacity: 0.5;\n}\n.skin-2 #side-menu > li > a,\n.skin-2 .nav.nav-second-level > li > a {\n  color: #586b7d;\n}\n.skin-2 .nav > li.active > a {\n  color: #213a53;\n}\n.skin-2.mini-navbar .nav-header {\n  background: #213a53;\n}\n.skin-2 .navbar-minimalize {\n  background: #007bff;\n  border-color: #007bff;\n}\n.skin-2 .border-bottom {\n  border-bottom: none !important;\n}\n.skin-2 #top-search {\n  color: #fff;\n}\nbody.skin-2 #wrapper {\n  background-color: #ededed;\n}\n.skin-2 .navbar-static-top {\n  background: #213a53;\n}\n.fixed-nav.skin-2 .navbar-fixed-top {\n  background: #213a53;\n  border-bottom: none !important;\n}\n.skin-2 .nav-header {\n  padding: 30px 25px 30px 25px;\n}\n.skin-2 .dashboard-header {\n  background: rgba(255, 255, 255, 0.4);\n  border-bottom: none !important;\n  border-top: none;\n  padding: 20px 30px 20px 30px;\n}\n.skin-2 .wrapper-content {\n  padding: 30px 15px;\n}\n.skin-2 .dashoard-1 .wrapper-content {\n  padding: 0px 30px 25px 30px;\n}\n.skin-2 .ibox-title {\n  background: rgba(255, 255, 255, 0.7);\n  border: none;\n  margin-bottom: 1px;\n}\n.skin-2 .ibox-content {\n  background: rgba(255, 255, 255, 0.4);\n  border: none !important;\n}\n.skin-2 #page-wrapper {\n  background: #f6f6f6;\n  background: -webkit-radial-gradient(center, ellipse cover, #f6f6f6 20%, #d5d5d5 100%);\n  background: -o-radial-gradient(center, ellipse cover, #f6f6f6 20%, #d5d5d5 100%);\n  background: -ms-radial-gradient(center, ellipse cover, #f6f6f6 20%, #d5d5d5 100%);\n  background: radial-gradient(ellipse at center, #f6f6f6 20%, #d5d5d5 100%);\n  -ms-filter: \"progid:DXImageTransform.Microsoft.gradient(startColorstr=#f6f6f6, endColorstr=#d5d5d5)\";\n}\n.skin-2 .ibox-title,\n.skin-2 .ibox-content {\n  border-width: 1px;\n}\n.skin-2 .ibox-content:last-child {\n  border-style: solid solid solid solid;\n}\n.skin-2 .nav > li.active {\n  border: none;\n}\n.skin-2 .nav-header a.dropdown-toggle {\n  color: #edf6ff;\n  margin-top: 10px;\n}\n.skin-2 .nav-header a.dropdown-toggle .text-muted {\n  color: #edf6ff;\n  opacity: 0.8;\n}\n.skin-2 .img-circle {\n  border-radius: 10px;\n}\n.skin-2 .nav.navbar-top-links > li > a:hover,\n.skin-2 .nav.navbar-top-links > li > a:focus {\n  background: #1a2d41;\n}\n.skin-2 .navbar-default .nav > li > a:hover,\n.skin-2 .navbar-default .nav > li > a:focus {\n  background: #e0e0e0;\n  color: #213a53;\n}\n.skin-2 .nav.nav-tabs > li.active > a {\n  color: #555;\n}\n.skin-2 .nav.nav-tabs > li.active {\n  background: transparent;\n}\n/*\n *\n *   SKIN 3 - H+ - Admin Theme\n *   NAME - Yellow/purple\n *\n*/\n.skin-3 .minimalize-styl-2 {\n  margin: 14px 5px 5px 30px;\n}\n.skin-3 .navbar-top-links li:last-child {\n  margin-right: 30px;\n}\n.skin-3.fixed-nav .minimalize-styl-2 {\n  margin: 14px 5px 5px 15px;\n}\n.skin-3 .spin-icon {\n  background: #ecba52 !important;\n}\nbody.boxed-layout.skin-3 #wrapper {\n  background: #3e2c42;\n}\n.skin-3 .nav-header {\n  background: #ecba52;\n  background: url('patterns/header-profile-skin-3.png');\n}\n.skin-3.mini-navbar .nav-second-level {\n  background: #3e2c42;\n}\n.skin-3 .breadcrumb {\n  background: transparent;\n}\n.skin-3 .page-heading {\n  border: none;\n}\n.skin-3 .nav > li.active {\n  background: #38283c;\n}\n.fixed-nav.skin-3 .navbar-fixed-top {\n  background: #fff;\n}\n.skin-3 .nav > li > a {\n  color: #948b96;\n}\n.skin-3 .nav > li.active > a {\n  color: #fff;\n}\n.skin-3 .navbar-minimalize {\n  background: #ecba52;\n  border-color: #ecba52;\n}\nbody.skin-3 {\n  background: #3e2c42;\n}\n.skin-3 .navbar-static-top {\n  background: #ffffff;\n}\n.skin-3 .dashboard-header {\n  background: transparent;\n  border-bottom: none !important;\n  border-top: none;\n  padding: 20px 30px 10px 30px;\n}\n.skin-3 .wrapper-content {\n  padding: 30px 15px;\n}\n.skin-3 #page-wrapper {\n  background: #f4f6fa;\n}\n.skin-3 .ibox-title,\n.skin-3 .ibox-content {\n  border-width: 1px;\n}\n.skin-3 .ibox-content:last-child {\n  border-style: solid solid solid solid;\n}\n.skin-3 .nav > li.active {\n  border: none;\n}\n.skin-3 .nav-header {\n  padding: 35px 25px 25px 25px;\n}\n.skin-3 .nav-header a.dropdown-toggle {\n  color: #fff;\n  margin-top: 10px;\n}\n.skin-3 .nav-header a.dropdown-toggle .text-muted {\n  color: #fff;\n  opacity: 0.8;\n}\n.skin-3 .profile-element {\n  text-align: center;\n}\n.skin-3 .img-circle {\n  border-radius: 5px;\n}\n.skin-3 .navbar-default .nav > li > a:hover,\n.skin-3 .navbar-default .nav > li > a:focus {\n  background: #38283c;\n  color: #fff;\n}\n.skin-3 .nav.nav-tabs > li.active > a {\n  color: #555;\n}\n.skin-3 .nav.nav-tabs > li.active {\n  background: transparent;\n}\n@media (min-width: 768px) {\n  #page-wrapper {\n    position: inherit;\n    margin: 0 0 0 220px;\n    min-height: 1200px;\n  }\n  .navbar-static-side {\n    z-index: 2001;\n    position: absolute;\n    width: 220px;\n  }\n  .navbar-top-links .dropdown-messages,\n  .navbar-top-links .dropdown-tasks,\n  .navbar-top-links .dropdown-alerts {\n    margin-left: auto;\n  }\n}\n@media (max-width: 768px) {\n  #page-wrapper {\n    position: inherit;\n    margin: 0 0 0 0px;\n    min-height: 1000px;\n  }\n  .body-small .navbar-static-side {\n    display: none;\n    z-index: 2001;\n    position: absolute;\n    width: 70px;\n  }\n  .body-small.mini-navbar .navbar-static-side {\n    display: block;\n  }\n  .lock-word {\n    display: none;\n  }\n  .navbar-form-custom {\n    display: none;\n  }\n  .navbar-header {\n    display: inline;\n    float: left;\n  }\n  .sidebard-panel {\n    z-index: 2;\n    position: relative;\n    width: auto;\n    min-height: 100% !important;\n  }\n  .sidebar-content .wrapper {\n    padding-right: 0px;\n    z-index: 1;\n  }\n  .fixed-sidebar.body-small .navbar-static-side {\n    display: none;\n    z-index: 2001;\n    position: fixed;\n    width: 220px;\n  }\n  .fixed-sidebar.body-small.mini-navbar .navbar-static-side {\n    display: block;\n  }\n  .ibox-tools {\n    float: none;\n    text-align: right;\n    display: block;\n  }\n}\n@media (max-width: 350px) {\n  .timeline-item .date {\n    text-align: left;\n    width: 110px;\n    position: relative;\n    padding-top: 30px;\n  }\n  .timeline-item .date i {\n    position: absolute;\n    top: 0;\n    left: 15px;\n    padding: 5px;\n    width: 30px;\n    text-align: center;\n    border: 1px solid #e7eaec;\n    background: #f8f8f8;\n  }\n  .timeline-item .content {\n    border-left: none;\n    border-top: 1px solid #e7eaec;\n    padding-top: 10px;\n    min-height: 100px;\n  }\n  .nav.navbar-top-links li.dropdown {\n    display: none;\n  }\n  .ibox-tools {\n    float: none;\n    text-align: left;\n    display: inline-block;\n  }\n}\n/* Only demo */\n@media (max-width: 1000px) {\n  .welcome-message {\n    display: none;\n  }\n}\n\n\n/* ECHARTS  */\n.echarts {\n    height: 240px;\n}\n/* radio */\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] \n{\n\tvertical-align:middle;\n  margin:0 5px 0 15px;\n  -webkit-appearance: none;\n  appearance: none;\n  width: 16px;\n  height: 16px;\n  background: white;\n  border: 1px solid #ccc;\n  -webkit-border-radius: 1px;\n  -moz-border-radius: 1px;\n  border-radius: 1px;\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n  position: relative;\n  box-sizing: content-box \\9;\n  width: 16px \\9;\n  height: 16px \\9;\n  border-width: 0 \\9;\n  \n}\ninput[type=\"radio\"] {\n  -webkit-border-radius: 1em;\n  -moz-border-radius: 1em;\n  border-radius: 1em;\n  width: 15px;\n  height: 15px;\n  outline: none;\n}\ninput[type=\"checkbox\"]:hover {\n  border-color: #c6c6c6;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);\n  -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);\n  box-shadow: none \\9;\n}\ninput[type=\"checkbox\"]:active,\ninput[type=\"radio\"]:active {\n  border-color: #c6c6c6;\n  background-color: #ebebeb;\n  outline: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffffffff', GradientType=0);\n}\ninput[type=\"checkbox\"]:checked,\ninput[type=\"radio\"]:checked {\n  background: #fff;\n}\ninput[type=\"checkbox\"]:checked::after {\n  content: url(../../images/admin/i_16_checked.png);\n  display: block;\n  position: absolute;\n  top: -1px;\n  left: -1px;\n}\ninput[type=\"radio\"]:checked::after {\n  content: '';\n  display: block;\n  position: relative;\n  top: 3px;\n  left: 3px;\n  width: 7px;\n  height: 7px;\n  background: #666;\n  -webkit-border-radius: 1em;\n  -moz-border-radius: 1em;\n  border-radius: 1em;\n}\ninput[type=\"checkbox\"]:focus,\ninput[type=\"radio\"]:focus {\n  outline: none;\n  border-color: #4d90fe;\n}\n/* radio */\n.btn:active{outline: none;}\n.fl{float: left;}\n.fr{float: right;}\n.row{margin: 0 !important; padding: 0 !important;}\n.tnav h2{ margin:15px 0}\n.tnav .breadcrumb{margin:20px 0 0 10px}\n.tn{ text-align: center;}\n\n\n\n\n"
  },
  {
    "path": "static/check/css/login.css",
    "content": "@charset \"utf-8\";\n/* login */\nhtml,body{ overflow:hidden;}\nbody{  background: #65cea7 url(\"/images/login/login-bg.jpg\") no-repeat fixed;\n  background-size: cover;\n  width: 100%;\n  height: 100%;}\n.log_header {\n  width: 100%;\n  height: 55px;\n  line-height: 55px;\n  position: absolute;\n  left: 0;\n  top: 0px;\n}\n.H_login {\n  height: 55px;\n  float: left;\n}\n.H_Pelse {\n  text-align: right;\n  padding-right: 30px;\n  font-size: 15px;\n  color: #fff;\n}\n.H_Pelse a {\n  font-size: 13px;\n  color: #fff;\n  display: inline-block;\n  margin: 0 10px;\n}\n.log_foot {\n  width: 100%;\n  height: 50px;\n  line-height: 50px;\n  position: absolute;\n  left: 0;\n  bottom: 0px;\n}\n.log_foot p {\n  text-align: center;\n  font-size: 14px;\n  color: #fff;\n}\n.log_foot p a{ color: #fff;}\n\n.form-signin {\n  max-width: 330px;\n  margin: 100px auto;\n  background: #fff;\n  border-radius: 5px;\n  -webkit-border-radius: 5px;\n}\n.form-signin .form-signin-heading {\n  margin: 0;\n  padding: 25px 15px;\n  text-align: center;\n  color: #fff;\n  position: relative;\n}\n.sign-title {\n  font-size: 24px;\n  color: #fff;\n  position: absolute;\n  top: -60px;\n  left: 0;\n  text-align: center;\n  width: 100%;\n  text-transform: uppercase;\n}\n.login-wrap {\n  padding: 20px;\n  position: relative;\n}\n.form-signin input[type=\"text\"], .form-signin input[type=\"password\"] {\n    margin-bottom: 5px;\n    border-radius: 5px;\n    -webkit-border-radius: 5px;\n    border: 1px solid #6bc5a4;\n    background: #fff;\n    box-shadow: none;\n    font-size: 12px;\n    text-indent: 2em;\n}\n\n.form-signin .btn-login {\n    background: #6bc5a4;\n    color: #fff;\n    text-transform: uppercase;\n    font-weight: normal;\n    font-family: 'Open Sans', sans-serif;\n    margin: 20px 0 5px;\n    padding: 5px;\n    -webkit-transition: all 0.3s;\n    -moz-transition: all 0.3s;\n    transition: all 0.3s;\n    font-size: 30px;\n    outline: none;\n}\n\n.form-signin .btn-login:hover {\n    background: #688ac2;\n    -webkit-transition: all 0.3s;\n    -moz-transition: all 0.3s;\n    transition: all 0.3s;\n}\n\n.form-signin p {\n    text-align: left;\n    color: #b6b6b6;\n    font-size: 16px;\n    font-weight: normal;\n}\n\n.form-signin a, .form-signin a:hover {\n    color: #6bc5a4;\n}\n\n.form-signin a:hover {\n    text-decoration: underline;\n}\n.form-signin #imgVerify {\n  position: absolute;\n  right: 15px;\n  top: 6px;\n}\n.form-signin .left-input-icon {\n  position: absolute;\n  left: 15px;\n  top: 12px;\n  color: #999;\n  -webkit-transition: color;\n  transition: color;\n  -webkit-transition-duration: 0.4s;\n  transition-duration: 0.4s;\n}\n.Validform_checktip {overflow:hidden;color:#999;font-size:12px;margin: 0;display: block;}\n.Validform_right {display: none;}\n.Validform_wrong {color:#ef4836;white-space:nowrap;font-weight: normal;}\n.Validform_loading {padding-left:20px;}\n.Validform_error {border:1px solid #ef4836 !important;}\n#eMsg{ display: none;}\n/* Progress bar Custom styles\n---------------------------------------------------------------------------------------------- */\n.p0{padding:0;}.s16{font-size:15px; vertical-align: middle;}\n.mb10{margin-bottom: 10px;}\n.progress \n{\n  height: 8px;\n  margin-bottom: 20px;\n  overflow: hidden;\n  background-color: #e6e7e8;\n  border-radius: 5px;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n\n.progress-bar {\n  float: left;\n  width: 0;\n  height: 100%;\n  font-size: 12px;\n  line-height: 20px;\n  color: #ffffff;\n  text-align: center;\n  background-color: @primary;\n  border-radius: 3px;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-transition: width 0.6s ease;\n  transition: width 0.6s ease;\n}\n\n.progress-bar-success {\n  background-color: @success;\n}\n\n.progress-bar-info {\n  background-color: @info;\n}\n\n.progress-bar-warning {\n  background-color: @warning;\n}\n\n.progress-bar-danger {\n  background-color: @danger;\n}\n@media (max-width: 767px){.log_foot{display: none;}\n@media (min-width:768px){.log_foot{display: none;}}\n@media (min-width:992px){.log_foot{display: none;}}\n@media (min-width:1200px){.log_foot{display: block;}}\n\n\n@media (max-width:500px)\n{\n  \n  body\n  {\n      background: #23bab5 ;\n  }\n}"
  },
  {
    "path": "static/css/animate.css",
    "content": "@charset \"UTF-8\";.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both;}.animated.hinge{-webkit-animation-duration:2s;animation-duration:2s;}@-webkit-keyframes bounce {\n  0%, 20%, 50%, 80%, 100% {\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  } 40% {\n    -webkit-transform: translateY(-30px);\n    transform: translateY(-30px);\n  }\n\n  60% {\n    -webkit-transform: translateY(-15px);\n    transform: translateY(-15px);\n  }\n}\n\n@keyframes bounce {\n  0%, 20%, 50%, 80%, 100% {\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  40% {\n    -webkit-transform: translateY(-30px);\n    -ms-transform: translateY(-30px);\n    transform: translateY(-30px);\n  }\n\n  60% {\n    -webkit-transform: translateY(-15px);\n    -ms-transform: translateY(-15px);\n    transform: translateY(-15px);\n  }\n}\n\n.bounce {\n  -webkit-animation-name: bounce;\n  animation-name: bounce;\n}\n\n@-webkit-keyframes flash {\n  0%, 50%, 100% {\n    opacity: 1;\n  }\n\n  25%, 75% {\n    opacity: 0;\n  }\n}\n\n@keyframes flash {\n  0%, 50%, 100% {\n    opacity: 1;\n  }\n\n  25%, 75% {\n    opacity: 0;\n  }\n}\n\n.flash {\n  -webkit-animation-name: flash;\n  animation-name: flash;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@-webkit-keyframes pulse {\n  0% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n\n  50% {\n    -webkit-transform: scale(1.1);\n    transform: scale(1.1);\n  }\n\n  100% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n\n@keyframes pulse {\n  0% {\n    -webkit-transform: scale(1);\n    -ms-transform: scale(1);\n    transform: scale(1);\n  }\n\n  50% {\n    -webkit-transform: scale(1.1);\n    -ms-transform: scale(1.1);\n    transform: scale(1.1);\n  }\n\n  100% {\n    -webkit-transform: scale(1);\n    -ms-transform: scale(1);\n    transform: scale(1);\n  }\n}\n\n.pulse {\n  -webkit-animation-name: pulse;\n  animation-name: pulse;\n}\n\n@-webkit-keyframes shake {\n  0%, 100% {\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  10%, 30%, 50%, 70%, 90% {\n    -webkit-transform: translateX(-10px);\n    transform: translateX(-10px);\n  }\n\n  20%, 40%, 60%, 80% {\n    -webkit-transform: translateX(10px);\n    transform: translateX(10px);\n  }\n}\n\n@keyframes shake {\n  0%, 100% {\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  10%, 30%, 50%, 70%, 90% {\n    -webkit-transform: translateX(-10px);\n    -ms-transform: translateX(-10px);\n    transform: translateX(-10px);\n  }\n\n  20%, 40%, 60%, 80% {\n    -webkit-transform: translateX(10px);\n    -ms-transform: translateX(10px);\n    transform: translateX(10px);\n  }\n}\n\n.shake {\n  -webkit-animation-name: shake;\n  animation-name: shake;\n}\n\n@-webkit-keyframes swing {\n  20% {\n    -webkit-transform: rotate(15deg);\n    transform: rotate(15deg);\n  }\n\n  40% {\n    -webkit-transform: rotate(-10deg);\n    transform: rotate(-10deg);\n  }\n\n  60% {\n    -webkit-transform: rotate(5deg);\n    transform: rotate(5deg);\n  }\n\n  80% {\n    -webkit-transform: rotate(-5deg);\n    transform: rotate(-5deg);\n  }\n\n  100% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n}\n\n@keyframes swing {\n  20% {\n    -webkit-transform: rotate(15deg);\n    -ms-transform: rotate(15deg);\n    transform: rotate(15deg);\n  }\n\n  40% {\n    -webkit-transform: rotate(-10deg);\n    -ms-transform: rotate(-10deg);\n    transform: rotate(-10deg);\n  }\n\n  60% {\n    -webkit-transform: rotate(5deg);\n    -ms-transform: rotate(5deg);\n    transform: rotate(5deg);\n  }\n\n  80% {\n    -webkit-transform: rotate(-5deg);\n    -ms-transform: rotate(-5deg);\n    transform: rotate(-5deg);\n  }\n\n  100% {\n    -webkit-transform: rotate(0deg);\n    -ms-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n}\n\n.swing {\n  -webkit-transform-origin: top center;\n  -ms-transform-origin: top center;\n  transform-origin: top center;\n  -webkit-animation-name: swing;\n  animation-name: swing;\n}\n\n@-webkit-keyframes tada {\n  0% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n\n  10%, 20% {\n    -webkit-transform: scale(0.9) rotate(-3deg);\n    transform: scale(0.9) rotate(-3deg);\n  }\n\n  30%, 50%, 70%, 90% {\n    -webkit-transform: scale(1.1) rotate(3deg);\n    transform: scale(1.1) rotate(3deg);\n  }\n\n  40%, 60%, 80% {\n    -webkit-transform: scale(1.1) rotate(-3deg);\n    transform: scale(1.1) rotate(-3deg);\n  }\n\n  100% {\n    -webkit-transform: scale(1) rotate(0);\n    transform: scale(1) rotate(0);\n  }\n}\n\n@keyframes tada {\n  0% {\n    -webkit-transform: scale(1);\n    -ms-transform: scale(1);\n    transform: scale(1);\n  }\n\n  10%, 20% {\n    -webkit-transform: scale(0.9) rotate(-3deg);\n    -ms-transform: scale(0.9) rotate(-3deg);\n    transform: scale(0.9) rotate(-3deg);\n  }\n\n  30%, 50%, 70%, 90% {\n    -webkit-transform: scale(1.1) rotate(3deg);\n    -ms-transform: scale(1.1) rotate(3deg);\n    transform: scale(1.1) rotate(3deg);\n  }\n\n  40%, 60%, 80% {\n    -webkit-transform: scale(1.1) rotate(-3deg);\n    -ms-transform: scale(1.1) rotate(-3deg);\n    transform: scale(1.1) rotate(-3deg);\n  }\n\n  100% {\n    -webkit-transform: scale(1) rotate(0);\n    -ms-transform: scale(1) rotate(0);\n    transform: scale(1) rotate(0);\n  }\n}\n\n.tada {\n  -webkit-animation-name: tada;\n  animation-name: tada;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@-webkit-keyframes wobble {\n  0% {\n    -webkit-transform: translateX(0%);\n    transform: translateX(0%);\n  }\n\n  15% {\n    -webkit-transform: translateX(-25%) rotate(-5deg);\n    transform: translateX(-25%) rotate(-5deg);\n  }\n\n  30% {\n    -webkit-transform: translateX(20%) rotate(3deg);\n    transform: translateX(20%) rotate(3deg);\n  }\n\n  45% {\n    -webkit-transform: translateX(-15%) rotate(-3deg);\n    transform: translateX(-15%) rotate(-3deg);\n  }\n\n  60% {\n    -webkit-transform: translateX(10%) rotate(2deg);\n    transform: translateX(10%) rotate(2deg);\n  }\n\n  75% {\n    -webkit-transform: translateX(-5%) rotate(-1deg);\n    transform: translateX(-5%) rotate(-1deg);\n  }\n\n  100% {\n    -webkit-transform: translateX(0%);\n    transform: translateX(0%);\n  }\n}\n\n@keyframes wobble {\n  0% {\n    -webkit-transform: translateX(0%);\n    -ms-transform: translateX(0%);\n    transform: translateX(0%);\n  }\n\n  15% {\n    -webkit-transform: translateX(-25%) rotate(-5deg);\n    -ms-transform: translateX(-25%) rotate(-5deg);\n    transform: translateX(-25%) rotate(-5deg);\n  }\n\n  30% {\n    -webkit-transform: translateX(20%) rotate(3deg);\n    -ms-transform: translateX(20%) rotate(3deg);\n    transform: translateX(20%) rotate(3deg);\n  }\n\n  45% {\n    -webkit-transform: translateX(-15%) rotate(-3deg);\n    -ms-transform: translateX(-15%) rotate(-3deg);\n    transform: translateX(-15%) rotate(-3deg);\n  }\n\n  60% {\n    -webkit-transform: translateX(10%) rotate(2deg);\n    -ms-transform: translateX(10%) rotate(2deg);\n    transform: translateX(10%) rotate(2deg);\n  }\n\n  75% {\n    -webkit-transform: translateX(-5%) rotate(-1deg);\n    -ms-transform: translateX(-5%) rotate(-1deg);\n    transform: translateX(-5%) rotate(-1deg);\n  }\n\n  100% {\n    -webkit-transform: translateX(0%);\n    -ms-transform: translateX(0%);\n    transform: translateX(0%);\n  }\n}\n\n.wobble {\n  -webkit-animation-name: wobble;\n  animation-name: wobble;\n}\n\n@-webkit-keyframes bounceIn {\n  0% {\n    opacity: 0;\n    -webkit-transform: scale(.3);\n    transform: scale(.3);\n  }\n\n  50% {\n    opacity: 1;\n    -webkit-transform: scale(1.05);\n    transform: scale(1.05);\n  }\n\n  70% {\n    -webkit-transform: scale(.9);\n    transform: scale(.9);\n  }\n\n  100% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n\n@keyframes bounceIn {\n  0% {\n    opacity: 0;\n    -webkit-transform: scale(.3);\n    -ms-transform: scale(.3);\n    transform: scale(.3);\n  }\n\n  50% {\n    opacity: 1;\n    -webkit-transform: scale(1.05);\n    -ms-transform: scale(1.05);\n    transform: scale(1.05);\n  }\n\n  70% {\n    -webkit-transform: scale(.9);\n    -ms-transform: scale(.9);\n    transform: scale(.9);\n  }\n\n  100% {\n    -webkit-transform: scale(1);\n    -ms-transform: scale(1);\n    transform: scale(1);\n  }\n}\n\n.bounceIn {\n  -webkit-animation-name: bounceIn;\n  animation-name: bounceIn;\n}\n\n@-webkit-keyframes bounceInDown {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(-2000px);\n    transform: translateY(-2000px);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translateY(30px);\n    transform: translateY(30px);\n  }\n\n  80% {\n    -webkit-transform: translateY(-10px);\n    transform: translateY(-10px);\n  }\n\n  100% {\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  }\n}\n\n@keyframes bounceInDown {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(-2000px);\n    -ms-transform: translateY(-2000px);\n    transform: translateY(-2000px);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translateY(30px);\n    -ms-transform: translateY(30px);\n    transform: translateY(30px);\n  }\n\n  80% {\n    -webkit-transform: translateY(-10px);\n    -ms-transform: translateY(-10px);\n    transform: translateY(-10px);\n  }\n\n  100% {\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n}\n\n.bounceInDown {\n  -webkit-animation-name: bounceInDown;\n  animation-name: bounceInDown;\n}\n\n@-webkit-keyframes bounceInLeft {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(-2000px);\n    transform: translateX(-2000px);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translateX(30px);\n    transform: translateX(30px);\n  }\n\n  80% {\n    -webkit-transform: translateX(-10px);\n    transform: translateX(-10px);\n  }\n\n  100% {\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n@keyframes bounceInLeft {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(-2000px);\n    -ms-transform: translateX(-2000px);\n    transform: translateX(-2000px);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translateX(30px);\n    -ms-transform: translateX(30px);\n    transform: translateX(30px);\n  }\n\n  80% {\n    -webkit-transform: translateX(-10px);\n    -ms-transform: translateX(-10px);\n    transform: translateX(-10px);\n  }\n\n  100% {\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n.bounceInLeft {\n  -webkit-animation-name: bounceInLeft;\n  animation-name: bounceInLeft;\n}\n\n@-webkit-keyframes bounceInRight {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(2000px);\n    transform: translateX(2000px);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translateX(-30px);\n    transform: translateX(-30px);\n  }\n\n  80% {\n    -webkit-transform: translateX(10px);\n    transform: translateX(10px);\n  }\n\n  100% {\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n@keyframes bounceInRight {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(2000px);\n    -ms-transform: translateX(2000px);\n    transform: translateX(2000px);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translateX(-30px);\n    -ms-transform: translateX(-30px);\n    transform: translateX(-30px);\n  }\n\n  80% {\n    -webkit-transform: translateX(10px);\n    -ms-transform: translateX(10px);\n    transform: translateX(10px);\n  }\n\n  100% {\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n.bounceInRight {\n  -webkit-animation-name: bounceInRight;\n  animation-name: bounceInRight;\n}\n\n@-webkit-keyframes bounceInUp {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(2000px);\n    transform: translateY(2000px);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translateY(-30px);\n    transform: translateY(-30px);\n  }\n\n  80% {\n    -webkit-transform: translateY(10px);\n    transform: translateY(10px);\n  }\n\n  100% {\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  }\n}\n\n@keyframes bounceInUp {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(2000px);\n    -ms-transform: translateY(2000px);\n    transform: translateY(2000px);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translateY(-30px);\n    -ms-transform: translateY(-30px);\n    transform: translateY(-30px);\n  }\n\n  80% {\n    -webkit-transform: translateY(10px);\n    -ms-transform: translateY(10px);\n    transform: translateY(10px);\n  }\n\n  100% {\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n}\n\n.bounceInUp {\n  -webkit-animation-name: bounceInUp;\n  animation-name: bounceInUp;\n}\n\n@-webkit-keyframes bounceOut {\n  0% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n\n  25% {\n    -webkit-transform: scale(.95);\n    transform: scale(.95);\n  }\n\n  50% {\n    opacity: 1;\n    -webkit-transform: scale(1.1);\n    transform: scale(1.1);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: scale(.3);\n    transform: scale(.3);\n  }\n}\n\n@keyframes bounceOut {\n  0% {\n    -webkit-transform: scale(1);\n    -ms-transform: scale(1);\n    transform: scale(1);\n  }\n\n  25% {\n    -webkit-transform: scale(.95);\n    -ms-transform: scale(.95);\n    transform: scale(.95);\n  }\n\n  50% {\n    opacity: 1;\n    -webkit-transform: scale(1.1);\n    -ms-transform: scale(1.1);\n    transform: scale(1.1);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: scale(.3);\n    -ms-transform: scale(.3);\n    transform: scale(.3);\n  }\n}\n\n.bounceOut {\n  -webkit-animation-name: bounceOut;\n  animation-name: bounceOut;\n}\n\n@-webkit-keyframes bounceOutDown {\n  0% {\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  20% {\n    opacity: 1;\n    -webkit-transform: translateY(-20px);\n    transform: translateY(-20px);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(2000px);\n    transform: translateY(2000px);\n  }\n}\n\n@keyframes bounceOutDown {\n  0% {\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  20% {\n    opacity: 1;\n    -webkit-transform: translateY(-20px);\n    -ms-transform: translateY(-20px);\n    transform: translateY(-20px);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(2000px);\n    -ms-transform: translateY(2000px);\n    transform: translateY(2000px);\n  }\n}\n\n.bounceOutDown {\n  -webkit-animation-name: bounceOutDown;\n  animation-name: bounceOutDown;\n}\n\n@-webkit-keyframes bounceOutLeft {\n  0% {\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  20% {\n    opacity: 1;\n    -webkit-transform: translateX(20px);\n    transform: translateX(20px);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(-2000px);\n    transform: translateX(-2000px);\n  }\n}\n\n@keyframes bounceOutLeft {\n  0% {\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  20% {\n    opacity: 1;\n    -webkit-transform: translateX(20px);\n    -ms-transform: translateX(20px);\n    transform: translateX(20px);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(-2000px);\n    -ms-transform: translateX(-2000px);\n    transform: translateX(-2000px);\n  }\n}\n\n.bounceOutLeft {\n  -webkit-animation-name: bounceOutLeft;\n  animation-name: bounceOutLeft;\n}\n\n@-webkit-keyframes bounceOutRight {\n  0% {\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  20% {\n    opacity: 1;\n    -webkit-transform: translateX(-20px);\n    transform: translateX(-20px);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(2000px);\n    transform: translateX(2000px);\n  }\n}\n\n@keyframes bounceOutRight {\n  0% {\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  20% {\n    opacity: 1;\n    -webkit-transform: translateX(-20px);\n    -ms-transform: translateX(-20px);\n    transform: translateX(-20px);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(2000px);\n    -ms-transform: translateX(2000px);\n    transform: translateX(2000px);\n  }\n}\n\n.bounceOutRight {\n  -webkit-animation-name: bounceOutRight;\n  animation-name: bounceOutRight;\n}\n\n@-webkit-keyframes bounceOutUp {\n  0% {\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  20% {\n    opacity: 1;\n    -webkit-transform: translateY(20px);\n    transform: translateY(20px);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(-2000px);\n    transform: translateY(-2000px);\n  }\n}\n\n@keyframes bounceOutUp {\n  0% {\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  20% {\n    opacity: 1;\n    -webkit-transform: translateY(20px);\n    -ms-transform: translateY(20px);\n    transform: translateY(20px);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(-2000px);\n    -ms-transform: translateY(-2000px);\n    transform: translateY(-2000px);\n  }\n}\n\n.bounceOutUp {\n  -webkit-animation-name: bounceOutUp;\n  animation-name: bounceOutUp;\n}\n\n@-webkit-keyframes fadeIn {\n  0% {\n    opacity: 0;\n  }\n\n  100% {\n    opacity: 1;\n  }\n}\n\n@keyframes fadeIn {\n  0% {\n    opacity: 0;\n  }\n\n  100% {\n    opacity: 1;\n  }\n}\n\n.fadeIn {\n  -webkit-animation-name: fadeIn;\n  animation-name: fadeIn;\n}\n\n@-webkit-keyframes fadeInDown {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(-20px);\n    transform: translateY(-20px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  }\n}\n\n@keyframes fadeInDown {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(-20px);\n    -ms-transform: translateY(-20px);\n    transform: translateY(-20px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n}\n\n.fadeInDown {\n  -webkit-animation-name: fadeInDown;\n  animation-name: fadeInDown;\n}\n\n@-webkit-keyframes fadeInDownBig {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(-2000px);\n    transform: translateY(-2000px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  }\n}\n\n@keyframes fadeInDownBig {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(-2000px);\n    -ms-transform: translateY(-2000px);\n    transform: translateY(-2000px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n}\n\n.fadeInDownBig {\n  -webkit-animation-name: fadeInDownBig;\n  animation-name: fadeInDownBig;\n}\n\n@-webkit-keyframes fadeInLeft {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(-20px);\n    transform: translateX(-20px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n@keyframes fadeInLeft {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(-20px);\n    -ms-transform: translateX(-20px);\n    transform: translateX(-20px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n.fadeInLeft {\n  -webkit-animation-name: fadeInLeft;\n  animation-name: fadeInLeft;\n}\n\n@-webkit-keyframes fadeInLeftBig {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(-2000px);\n    transform: translateX(-2000px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n@keyframes fadeInLeftBig {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(-2000px);\n    -ms-transform: translateX(-2000px);\n    transform: translateX(-2000px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n.fadeInLeftBig {\n  -webkit-animation-name: fadeInLeftBig;\n  animation-name: fadeInLeftBig;\n}\n\n@-webkit-keyframes fadeInRight {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(20px);\n    transform: translateX(20px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n@keyframes fadeInRight {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(20px);\n    -ms-transform: translateX(20px);\n    transform: translateX(20px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n.fadeInRight {\n  -webkit-animation-name: fadeInRight;\n  animation-name: fadeInRight;\n}\n\n@-webkit-keyframes fadeInRightBig {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(2000px);\n    transform: translateX(2000px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n@keyframes fadeInRightBig {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(2000px);\n    -ms-transform: translateX(2000px);\n    transform: translateX(2000px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n.fadeInRightBig {\n  -webkit-animation-name: fadeInRightBig;\n  animation-name: fadeInRightBig;\n}\n\n@-webkit-keyframes fadeInUp {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(20px);\n    transform: translateY(20px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  }\n}\n\n@keyframes fadeInUp {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(20px);\n    -ms-transform: translateY(20px);\n    transform: translateY(20px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n}\n\n.fadeInUp {\n  -webkit-animation-name: fadeInUp;\n  animation-name: fadeInUp;\n}\n\n@-webkit-keyframes fadeInUpBig {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(2000px);\n    transform: translateY(2000px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  }\n}\n\n@keyframes fadeInUpBig {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(2000px);\n    -ms-transform: translateY(2000px);\n    transform: translateY(2000px);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n}\n\n.fadeInUpBig {\n  -webkit-animation-name: fadeInUpBig;\n  animation-name: fadeInUpBig;\n}\n\n@-webkit-keyframes fadeOut {\n  0% {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n  }\n}\n\n@keyframes fadeOut {\n  0% {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n  }\n}\n\n.fadeOut {\n  -webkit-animation-name: fadeOut;\n  animation-name: fadeOut;\n}\n\n@-webkit-keyframes fadeOutDown {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(20px);\n    transform: translateY(20px);\n  }\n}\n\n@keyframes fadeOutDown {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(20px);\n    -ms-transform: translateY(20px);\n    transform: translateY(20px);\n  }\n}\n\n.fadeOutDown {\n  -webkit-animation-name: fadeOutDown;\n  animation-name: fadeOutDown;\n}\n\n@-webkit-keyframes fadeOutDownBig {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(2000px);\n    transform: translateY(2000px);\n  }\n}\n\n@keyframes fadeOutDownBig {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(2000px);\n    -ms-transform: translateY(2000px);\n    transform: translateY(2000px);\n  }\n}\n\n.fadeOutDownBig {\n  -webkit-animation-name: fadeOutDownBig;\n  animation-name: fadeOutDownBig;\n}\n\n@-webkit-keyframes fadeOutLeft {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(-20px);\n    transform: translateX(-20px);\n  }\n}\n\n@keyframes fadeOutLeft {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(-20px);\n    -ms-transform: translateX(-20px);\n    transform: translateX(-20px);\n  }\n}\n\n.fadeOutLeft {\n  -webkit-animation-name: fadeOutLeft;\n  animation-name: fadeOutLeft;\n}\n\n@-webkit-keyframes fadeOutLeftBig {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(-2000px);\n    transform: translateX(-2000px);\n  }\n}\n\n@keyframes fadeOutLeftBig {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(-2000px);\n    -ms-transform: translateX(-2000px);\n    transform: translateX(-2000px);\n  }\n}\n\n.fadeOutLeftBig {\n  -webkit-animation-name: fadeOutLeftBig;\n  animation-name: fadeOutLeftBig;\n}\n\n@-webkit-keyframes fadeOutRight {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(20px);\n    transform: translateX(20px);\n  }\n}\n\n@keyframes fadeOutRight {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(20px);\n    -ms-transform: translateX(20px);\n    transform: translateX(20px);\n  }\n}\n\n.fadeOutRight {\n  -webkit-animation-name: fadeOutRight;\n  animation-name: fadeOutRight;\n}\n\n@-webkit-keyframes fadeOutRightBig {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(2000px);\n    transform: translateX(2000px);\n  }\n}\n\n@keyframes fadeOutRightBig {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(2000px);\n    -ms-transform: translateX(2000px);\n    transform: translateX(2000px);\n  }\n}\n\n.fadeOutRightBig {\n  -webkit-animation-name: fadeOutRightBig;\n  animation-name: fadeOutRightBig;\n}\n\n@-webkit-keyframes fadeOutUp {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(-20px);\n    transform: translateY(-20px);\n  }\n}\n\n@keyframes fadeOutUp {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(-20px);\n    -ms-transform: translateY(-20px);\n    transform: translateY(-20px);\n  }\n}\n\n.fadeOutUp {\n  -webkit-animation-name: fadeOutUp;\n  animation-name: fadeOutUp;\n}\n\n@-webkit-keyframes fadeOutUpBig {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(-2000px);\n    transform: translateY(-2000px);\n  }\n}\n\n@keyframes fadeOutUpBig {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(-2000px);\n    -ms-transform: translateY(-2000px);\n    transform: translateY(-2000px);\n  }\n}\n\n.fadeOutUpBig {\n  -webkit-animation-name: fadeOutUpBig;\n  animation-name: fadeOutUpBig;\n}\n\n@-webkit-keyframes flip {\n  0% {\n    -webkit-transform: perspective(400px) translateZ(0) rotateY(0) scale(1);\n    transform: perspective(400px) translateZ(0) rotateY(0) scale(1);\n    -webkit-animation-timing-function: ease-out;\n    animation-timing-function: ease-out;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1);\n    transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1);\n    -webkit-animation-timing-function: ease-out;\n    animation-timing-function: ease-out;\n  }\n\n  50% {\n    -webkit-transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);\n    transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  80% {\n    -webkit-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95);\n    transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  100% {\n    -webkit-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1);\n    transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n}\n\n@keyframes flip {\n  0% {\n    -webkit-transform: perspective(400px) translateZ(0) rotateY(0) scale(1);\n    -ms-transform: perspective(400px) translateZ(0) rotateY(0) scale(1);\n    transform: perspective(400px) translateZ(0) rotateY(0) scale(1);\n    -webkit-animation-timing-function: ease-out;\n    animation-timing-function: ease-out;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1);\n    -ms-transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1);\n    transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1);\n    -webkit-animation-timing-function: ease-out;\n    animation-timing-function: ease-out;\n  }\n\n  50% {\n    -webkit-transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);\n    -ms-transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);\n    transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  80% {\n    -webkit-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95);\n    -ms-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95);\n    transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  100% {\n    -webkit-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1);\n    -ms-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1);\n    transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n}\n\n.animated.flip {\n  -webkit-backface-visibility: visible;\n  -ms-backface-visibility: visible;\n  backface-visibility: visible;\n  -webkit-animation-name: flip;\n  animation-name: flip;\n}\n\n@-webkit-keyframes flipInX {\n  0% {\n    -webkit-transform: perspective(400px) rotateX(90deg);\n    transform: perspective(400px) rotateX(90deg);\n    opacity: 0;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) rotateX(-10deg);\n    transform: perspective(400px) rotateX(-10deg);\n  }\n\n  70% {\n    -webkit-transform: perspective(400px) rotateX(10deg);\n    transform: perspective(400px) rotateX(10deg);\n  }\n\n  100% {\n    -webkit-transform: perspective(400px) rotateX(0deg);\n    transform: perspective(400px) rotateX(0deg);\n    opacity: 1;\n  }\n}\n\n@keyframes flipInX {\n  0% {\n    -webkit-transform: perspective(400px) rotateX(90deg);\n    -ms-transform: perspective(400px) rotateX(90deg);\n    transform: perspective(400px) rotateX(90deg);\n    opacity: 0;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) rotateX(-10deg);\n    -ms-transform: perspective(400px) rotateX(-10deg);\n    transform: perspective(400px) rotateX(-10deg);\n  }\n\n  70% {\n    -webkit-transform: perspective(400px) rotateX(10deg);\n    -ms-transform: perspective(400px) rotateX(10deg);\n    transform: perspective(400px) rotateX(10deg);\n  }\n\n  100% {\n    -webkit-transform: perspective(400px) rotateX(0deg);\n    -ms-transform: perspective(400px) rotateX(0deg);\n    transform: perspective(400px) rotateX(0deg);\n    opacity: 1;\n  }\n}\n\n.flipInX {\n  -webkit-backface-visibility: visible !important;\n  -ms-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n  -webkit-animation-name: flipInX;\n  animation-name: flipInX;\n}\n\n@-webkit-keyframes flipInY {\n  0% {\n    -webkit-transform: perspective(400px) rotateY(90deg);\n    transform: perspective(400px) rotateY(90deg);\n    opacity: 0;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) rotateY(-10deg);\n    transform: perspective(400px) rotateY(-10deg);\n  }\n\n  70% {\n    -webkit-transform: perspective(400px) rotateY(10deg);\n    transform: perspective(400px) rotateY(10deg);\n  }\n\n  100% {\n    -webkit-transform: perspective(400px) rotateY(0deg);\n    transform: perspective(400px) rotateY(0deg);\n    opacity: 1;\n  }\n}\n\n@keyframes flipInY {\n  0% {\n    -webkit-transform: perspective(400px) rotateY(90deg);\n    -ms-transform: perspective(400px) rotateY(90deg);\n    transform: perspective(400px) rotateY(90deg);\n    opacity: 0;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) rotateY(-10deg);\n    -ms-transform: perspective(400px) rotateY(-10deg);\n    transform: perspective(400px) rotateY(-10deg);\n  }\n\n  70% {\n    -webkit-transform: perspective(400px) rotateY(10deg);\n    -ms-transform: perspective(400px) rotateY(10deg);\n    transform: perspective(400px) rotateY(10deg);\n  }\n\n  100% {\n    -webkit-transform: perspective(400px) rotateY(0deg);\n    -ms-transform: perspective(400px) rotateY(0deg);\n    transform: perspective(400px) rotateY(0deg);\n    opacity: 1;\n  }\n}\n\n.flipInY {\n  -webkit-backface-visibility: visible !important;\n  -ms-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n  -webkit-animation-name: flipInY;\n  animation-name: flipInY;\n}\n\n@-webkit-keyframes flipOutX {\n  0% {\n    -webkit-transform: perspective(400px) rotateX(0deg);\n    transform: perspective(400px) rotateX(0deg);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: perspective(400px) rotateX(90deg);\n    transform: perspective(400px) rotateX(90deg);\n    opacity: 0;\n  }\n}\n\n@keyframes flipOutX {\n  0% {\n    -webkit-transform: perspective(400px) rotateX(0deg);\n    -ms-transform: perspective(400px) rotateX(0deg);\n    transform: perspective(400px) rotateX(0deg);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: perspective(400px) rotateX(90deg);\n    -ms-transform: perspective(400px) rotateX(90deg);\n    transform: perspective(400px) rotateX(90deg);\n    opacity: 0;\n  }\n}\n\n.flipOutX {\n  -webkit-animation-name: flipOutX;\n  animation-name: flipOutX;\n  -webkit-backface-visibility: visible !important;\n  -ms-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n}\n\n@-webkit-keyframes flipOutY {\n  0% {\n    -webkit-transform: perspective(400px) rotateY(0deg);\n    transform: perspective(400px) rotateY(0deg);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: perspective(400px) rotateY(90deg);\n    transform: perspective(400px) rotateY(90deg);\n    opacity: 0;\n  }\n}\n\n@keyframes flipOutY {\n  0% {\n    -webkit-transform: perspective(400px) rotateY(0deg);\n    -ms-transform: perspective(400px) rotateY(0deg);\n    transform: perspective(400px) rotateY(0deg);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: perspective(400px) rotateY(90deg);\n    -ms-transform: perspective(400px) rotateY(90deg);\n    transform: perspective(400px) rotateY(90deg);\n    opacity: 0;\n  }\n}\n\n.flipOutY {\n  -webkit-backface-visibility: visible !important;\n  -ms-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n  -webkit-animation-name: flipOutY;\n  animation-name: flipOutY;\n}\n\n@-webkit-keyframes lightSpeedIn {\n  0% {\n    -webkit-transform: translateX(100%) skewX(-30deg);\n    transform: translateX(100%) skewX(-30deg);\n    opacity: 0;\n  }\n\n  60% {\n    -webkit-transform: translateX(-20%) skewX(30deg);\n    transform: translateX(-20%) skewX(30deg);\n    opacity: 1;\n  }\n\n  80% {\n    -webkit-transform: translateX(0%) skewX(-15deg);\n    transform: translateX(0%) skewX(-15deg);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: translateX(0%) skewX(0deg);\n    transform: translateX(0%) skewX(0deg);\n    opacity: 1;\n  }\n}\n\n@keyframes lightSpeedIn {\n  0% {\n    -webkit-transform: translateX(100%) skewX(-30deg);\n    -ms-transform: translateX(100%) skewX(-30deg);\n    transform: translateX(100%) skewX(-30deg);\n    opacity: 0;\n  }\n\n  60% {\n    -webkit-transform: translateX(-20%) skewX(30deg);\n    -ms-transform: translateX(-20%) skewX(30deg);\n    transform: translateX(-20%) skewX(30deg);\n    opacity: 1;\n  }\n\n  80% {\n    -webkit-transform: translateX(0%) skewX(-15deg);\n    -ms-transform: translateX(0%) skewX(-15deg);\n    transform: translateX(0%) skewX(-15deg);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: translateX(0%) skewX(0deg);\n    -ms-transform: translateX(0%) skewX(0deg);\n    transform: translateX(0%) skewX(0deg);\n    opacity: 1;\n  }\n}\n\n.lightSpeedIn {\n  -webkit-animation-name: lightSpeedIn;\n  animation-name: lightSpeedIn;\n  -webkit-animation-timing-function: ease-out;\n  animation-timing-function: ease-out;\n}\n\n@-webkit-keyframes lightSpeedOut {\n  0% {\n    -webkit-transform: translateX(0%) skewX(0deg);\n    transform: translateX(0%) skewX(0deg);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: translateX(100%) skewX(-30deg);\n    transform: translateX(100%) skewX(-30deg);\n    opacity: 0;\n  }\n}\n\n@keyframes lightSpeedOut {\n  0% {\n    -webkit-transform: translateX(0%) skewX(0deg);\n    -ms-transform: translateX(0%) skewX(0deg);\n    transform: translateX(0%) skewX(0deg);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: translateX(100%) skewX(-30deg);\n    -ms-transform: translateX(100%) skewX(-30deg);\n    transform: translateX(100%) skewX(-30deg);\n    opacity: 0;\n  }\n}\n\n.lightSpeedOut {\n  -webkit-animation-name: lightSpeedOut;\n  animation-name: lightSpeedOut;\n  -webkit-animation-timing-function: ease-in;\n  animation-timing-function: ease-in;\n}\n\n@-webkit-keyframes rotateIn {\n  0% {\n    -webkit-transform-origin: center center;\n    transform-origin: center center;\n    -webkit-transform: rotate(-200deg);\n    transform: rotate(-200deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: center center;\n    transform-origin: center center;\n    -webkit-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n}\n\n@keyframes rotateIn {\n  0% {\n    -webkit-transform-origin: center center;\n    -ms-transform-origin: center center;\n    transform-origin: center center;\n    -webkit-transform: rotate(-200deg);\n    -ms-transform: rotate(-200deg);\n    transform: rotate(-200deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: center center;\n    -ms-transform-origin: center center;\n    transform-origin: center center;\n    -webkit-transform: rotate(0);\n    -ms-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n}\n\n.rotateIn {\n  -webkit-animation-name: rotateIn;\n  animation-name: rotateIn;\n}\n\n@-webkit-keyframes rotateInDownLeft {\n  0% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(-90deg);\n    transform: rotate(-90deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n}\n\n@keyframes rotateInDownLeft {\n  0% {\n    -webkit-transform-origin: left bottom;\n    -ms-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(-90deg);\n    -ms-transform: rotate(-90deg);\n    transform: rotate(-90deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    -ms-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(0);\n    -ms-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n}\n\n.rotateInDownLeft {\n  -webkit-animation-name: rotateInDownLeft;\n  animation-name: rotateInDownLeft;\n}\n\n@-webkit-keyframes rotateInDownRight {\n  0% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(90deg);\n    transform: rotate(90deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n}\n\n@keyframes rotateInDownRight {\n  0% {\n    -webkit-transform-origin: right bottom;\n    -ms-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(90deg);\n    -ms-transform: rotate(90deg);\n    transform: rotate(90deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    -ms-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(0);\n    -ms-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n}\n\n.rotateInDownRight {\n  -webkit-animation-name: rotateInDownRight;\n  animation-name: rotateInDownRight;\n}\n\n@-webkit-keyframes rotateInUpLeft {\n  0% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(90deg);\n    transform: rotate(90deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n}\n\n@keyframes rotateInUpLeft {\n  0% {\n    -webkit-transform-origin: left bottom;\n    -ms-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(90deg);\n    -ms-transform: rotate(90deg);\n    transform: rotate(90deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    -ms-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(0);\n    -ms-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n}\n\n.rotateInUpLeft {\n  -webkit-animation-name: rotateInUpLeft;\n  animation-name: rotateInUpLeft;\n}\n\n@-webkit-keyframes rotateInUpRight {\n  0% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(-90deg);\n    transform: rotate(-90deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n}\n\n@keyframes rotateInUpRight {\n  0% {\n    -webkit-transform-origin: right bottom;\n    -ms-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(-90deg);\n    -ms-transform: rotate(-90deg);\n    transform: rotate(-90deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    -ms-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(0);\n    -ms-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n}\n\n.rotateInUpRight {\n  -webkit-animation-name: rotateInUpRight;\n  animation-name: rotateInUpRight;\n}\n\n@-webkit-keyframes rotateOut {\n  0% {\n    -webkit-transform-origin: center center;\n    transform-origin: center center;\n    -webkit-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: center center;\n    transform-origin: center center;\n    -webkit-transform: rotate(200deg);\n    transform: rotate(200deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOut {\n  0% {\n    -webkit-transform-origin: center center;\n    -ms-transform-origin: center center;\n    transform-origin: center center;\n    -webkit-transform: rotate(0);\n    -ms-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: center center;\n    -ms-transform-origin: center center;\n    transform-origin: center center;\n    -webkit-transform: rotate(200deg);\n    -ms-transform: rotate(200deg);\n    transform: rotate(200deg);\n    opacity: 0;\n  }\n}\n\n.rotateOut {\n  -webkit-animation-name: rotateOut;\n  animation-name: rotateOut;\n}\n\n@-webkit-keyframes rotateOutDownLeft {\n  0% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(90deg);\n    transform: rotate(90deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOutDownLeft {\n  0% {\n    -webkit-transform-origin: left bottom;\n    -ms-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(0);\n    -ms-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    -ms-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(90deg);\n    -ms-transform: rotate(90deg);\n    transform: rotate(90deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutDownLeft {\n  -webkit-animation-name: rotateOutDownLeft;\n  animation-name: rotateOutDownLeft;\n}\n\n@-webkit-keyframes rotateOutDownRight {\n  0% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(-90deg);\n    transform: rotate(-90deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOutDownRight {\n  0% {\n    -webkit-transform-origin: right bottom;\n    -ms-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(0);\n    -ms-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    -ms-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(-90deg);\n    -ms-transform: rotate(-90deg);\n    transform: rotate(-90deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutDownRight {\n  -webkit-animation-name: rotateOutDownRight;\n  animation-name: rotateOutDownRight;\n}\n\n@-webkit-keyframes rotateOutUpLeft {\n  0% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(-90deg);\n    transform: rotate(-90deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOutUpLeft {\n  0% {\n    -webkit-transform-origin: left bottom;\n    -ms-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(0);\n    -ms-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    -ms-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate(-90deg);\n    -ms-transform: rotate(-90deg);\n    transform: rotate(-90deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutUpLeft {\n  -webkit-animation-name: rotateOutUpLeft;\n  animation-name: rotateOutUpLeft;\n}\n\n@-webkit-keyframes rotateOutUpRight {\n  0% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(90deg);\n    transform: rotate(90deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOutUpRight {\n  0% {\n    -webkit-transform-origin: right bottom;\n    -ms-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(0);\n    -ms-transform: rotate(0);\n    transform: rotate(0);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    -ms-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate(90deg);\n    -ms-transform: rotate(90deg);\n    transform: rotate(90deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutUpRight {\n  -webkit-animation-name: rotateOutUpRight;\n  animation-name: rotateOutUpRight;\n}\n\n@-webkit-keyframes slideInDown {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(-2000px);\n    transform: translateY(-2000px);\n  }\n\n  100% {\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  }\n}\n\n@keyframes slideInDown {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(-2000px);\n    -ms-transform: translateY(-2000px);\n    transform: translateY(-2000px);\n  }\n\n  100% {\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n}\n\n.slideInDown {\n  -webkit-animation-name: slideInDown;\n  animation-name: slideInDown;\n}\n\n@-webkit-keyframes slideInLeft {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(-2000px);\n    transform: translateX(-2000px);\n  }\n\n  100% {\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n@keyframes slideInLeft {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(-2000px);\n    -ms-transform: translateX(-2000px);\n    transform: translateX(-2000px);\n  }\n\n  100% {\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n.slideInLeft {\n  -webkit-animation-name: slideInLeft;\n  animation-name: slideInLeft;\n}\n\n@-webkit-keyframes slideInRight {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(2000px);\n    transform: translateX(2000px);\n  }\n\n  100% {\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n@keyframes slideInRight {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(2000px);\n    -ms-transform: translateX(2000px);\n    transform: translateX(2000px);\n  }\n\n  100% {\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n}\n\n.slideInRight {\n  -webkit-animation-name: slideInRight;\n  animation-name: slideInRight;\n}\n\n@-webkit-keyframes slideOutLeft {\n  0% {\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(-2000px);\n    transform: translateX(-2000px);\n  }\n}\n\n@keyframes slideOutLeft {\n  0% {\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(-2000px);\n    -ms-transform: translateX(-2000px);\n    transform: translateX(-2000px);\n  }\n}\n\n.slideOutLeft {\n  -webkit-animation-name: slideOutLeft;\n  animation-name: slideOutLeft;\n}\n\n@-webkit-keyframes slideOutRight {\n  0% {\n    -webkit-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(2000px);\n    transform: translateX(2000px);\n  }\n}\n\n@keyframes slideOutRight {\n  0% {\n    -webkit-transform: translateX(0);\n    -ms-transform: translateX(0);\n    transform: translateX(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(2000px);\n    -ms-transform: translateX(2000px);\n    transform: translateX(2000px);\n  }\n}\n\n.slideOutRight {\n  -webkit-animation-name: slideOutRight;\n  animation-name: slideOutRight;\n}\n\n@-webkit-keyframes slideOutUp {\n  0% {\n    -webkit-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(-2000px);\n    transform: translateY(-2000px);\n  }\n}\n\n@keyframes slideOutUp {\n  0% {\n    -webkit-transform: translateY(0);\n    -ms-transform: translateY(0);\n    transform: translateY(0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(-2000px);\n    -ms-transform: translateY(-2000px);\n    transform: translateY(-2000px);\n  }\n}\n\n.slideOutUp {\n  -webkit-animation-name: slideOutUp;\n  animation-name: slideOutUp;\n}\n\n@-webkit-keyframes hinge {\n  0% {\n    -webkit-transform: rotate(0);\n    transform: rotate(0);\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  20%, 60% {\n    -webkit-transform: rotate(80deg);\n    transform: rotate(80deg);\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  40% {\n    -webkit-transform: rotate(60deg);\n    transform: rotate(60deg);\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  80% {\n    -webkit-transform: rotate(60deg) translateY(0);\n    transform: rotate(60deg) translateY(0);\n    opacity: 1;\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  100% {\n    -webkit-transform: translateY(700px);\n    transform: translateY(700px);\n    opacity: 0;\n  }\n}\n\n@keyframes hinge {\n  0% {\n    -webkit-transform: rotate(0);\n    -ms-transform: rotate(0);\n    transform: rotate(0);\n    -webkit-transform-origin: top left;\n    -ms-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  20%, 60% {\n    -webkit-transform: rotate(80deg);\n    -ms-transform: rotate(80deg);\n    transform: rotate(80deg);\n    -webkit-transform-origin: top left;\n    -ms-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  40% {\n    -webkit-transform: rotate(60deg);\n    -ms-transform: rotate(60deg);\n    transform: rotate(60deg);\n    -webkit-transform-origin: top left;\n    -ms-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  80% {\n    -webkit-transform: rotate(60deg) translateY(0);\n    -ms-transform: rotate(60deg) translateY(0);\n    transform: rotate(60deg) translateY(0);\n    opacity: 1;\n    -webkit-transform-origin: top left;\n    -ms-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  100% {\n    -webkit-transform: translateY(700px);\n    -ms-transform: translateY(700px);\n    transform: translateY(700px);\n    opacity: 0;\n  }\n}\n\n.hinge {\n  -webkit-animation-name: hinge;\n  animation-name: hinge;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@-webkit-keyframes rollIn {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(-100%) rotate(-120deg);\n    transform: translateX(-100%) rotate(-120deg);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateX(0px) rotate(0deg);\n    transform: translateX(0px) rotate(0deg);\n  }\n}\n\n@keyframes rollIn {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateX(-100%) rotate(-120deg);\n    -ms-transform: translateX(-100%) rotate(-120deg);\n    transform: translateX(-100%) rotate(-120deg);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: translateX(0px) rotate(0deg);\n    -ms-transform: translateX(0px) rotate(0deg);\n    transform: translateX(0px) rotate(0deg);\n  }\n}\n\n.rollIn {\n  -webkit-animation-name: rollIn;\n  animation-name: rollIn;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@-webkit-keyframes rollOut {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateX(0px) rotate(0deg);\n    transform: translateX(0px) rotate(0deg);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(100%) rotate(120deg);\n    transform: translateX(100%) rotate(120deg);\n  }\n}\n\n@keyframes rollOut {\n  0% {\n    opacity: 1;\n    -webkit-transform: translateX(0px) rotate(0deg);\n    -ms-transform: translateX(0px) rotate(0deg);\n    transform: translateX(0px) rotate(0deg);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translateX(100%) rotate(120deg);\n    -ms-transform: translateX(100%) rotate(120deg);\n    transform: translateX(100%) rotate(120deg);\n  }\n}\n\n.rollOut {\n  -webkit-animation-name: rollOut;\n  animation-name: rollOut;\n}"
  },
  {
    "path": "static/css/bak/animate.css",
    "content": "@charset \"UTF-8\";/*!\n * animate.css -http://daneden.me/animate\n * Version - 3.5.1\n * Licensed under the MIT license - http://opensource.org/licenses/MIT\n *\n * Copyright (c) 2016 Daniel Eden\n */.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.hinge{-webkit-animation-duration:2s;animation-duration:2s}.animated.flipOutX,.animated.flipOutY,.animated.bounceIn,.animated.bounceOut{-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes bounce{from,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}40%,43%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}@keyframes bounce{from,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}40%,43%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06);-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}.bounce{-webkit-animation-name:bounce;animation-name:bounce;-webkit-transform-origin:center bottom;transform-origin:center bottom}@-webkit-keyframes flash{from,50%,to{opacity:1}25%,75%{opacity:0}}@keyframes flash{from,50%,to{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes pulse{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes pulse{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.pulse{-webkit-animation-name:pulse;animation-name:pulse}@-webkit-keyframes rubberBand{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes rubberBand{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.rubberBand{-webkit-animation-name:rubberBand;animation-name:rubberBand}@-webkit-keyframes shake{from,to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}@keyframes shake{from,to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}.shake{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}.headShake{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-name:headShake;animation-name:headShake}@-webkit-keyframes swing{20%{-webkit-transform:rotate3d(0,0,1,15deg);transform:rotate3d(0,0,1,15deg)}40%{-webkit-transform:rotate3d(0,0,1,-10deg);transform:rotate3d(0,0,1,-10deg)}60%{-webkit-transform:rotate3d(0,0,1,5deg);transform:rotate3d(0,0,1,5deg)}80%{-webkit-transform:rotate3d(0,0,1,-5deg);transform:rotate3d(0,0,1,-5deg)}to{-webkit-transform:rotate3d(0,0,1,0deg);transform:rotate3d(0,0,1,0deg)}}@keyframes swing{20%{-webkit-transform:rotate3d(0,0,1,15deg);transform:rotate3d(0,0,1,15deg)}40%{-webkit-transform:rotate3d(0,0,1,-10deg);transform:rotate3d(0,0,1,-10deg)}60%{-webkit-transform:rotate3d(0,0,1,5deg);transform:rotate3d(0,0,1,5deg)}80%{-webkit-transform:rotate3d(0,0,1,-5deg);transform:rotate3d(0,0,1,-5deg)}to{-webkit-transform:rotate3d(0,0,1,0deg);transform:rotate3d(0,0,1,0deg)}}.swing{-webkit-transform-origin:top center;transform-origin:top center;-webkit-animation-name:swing;animation-name:swing}@-webkit-keyframes tada{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)}to{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes tada{from{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)}to{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.tada{-webkit-animation-name:tada;animation-name:tada}@-webkit-keyframes wobble{from{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg);transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg);transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg);transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg);transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg);transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}to{-webkit-transform:none;transform:none}}@keyframes wobble{from{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg);transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg);transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg);transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg);transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg);transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}to{-webkit-transform:none;transform:none}}.wobble{-webkit-animation-name:wobble;animation-name:wobble}@-webkit-keyframes jello{from,11.1%,to{-webkit-transform:none;transform:none}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}@keyframes jello{from,11.1%,to{-webkit-transform:none;transform:none}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}.jello{-webkit-animation-name:jello;animation-name:jello;-webkit-transform-origin:center;transform-origin:center}@-webkit-keyframes bounceIn{from,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes bounceIn{from,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.bounceIn{-webkit-animation-name:bounceIn;animation-name:bounceIn}@-webkit-keyframes bounceInDown{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInDown{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:none;transform:none}}.bounceInDown{-webkit-animation-name:bounceInDown;animation-name:bounceInDown}@-webkit-keyframes bounceInLeft{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInLeft{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:none;transform:none}}.bounceInLeft{-webkit-animation-name:bounceInLeft;animation-name:bounceInLeft}@-webkit-keyframes bounceInRight{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}from{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInRight{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}from{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:none;transform:none}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceInUp{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}from{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes bounceInUp{from,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1.000);animation-timing-function:cubic-bezier(.215,.61,.355,1.000)}from{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.bounceInUp{-webkit-animation-name:bounceInUp;animation-name:bounceInUp}@-webkit-keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}to{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}@keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}to{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}.bounceOut{-webkit-animation-name:bounceOut;animation-name:bounceOut}@-webkit-keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.bounceOutDown{-webkit-animation-name:bounceOutDown;animation-name:bounceOutDown}@-webkit-keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.bounceOutLeft{-webkit-animation-name:bounceOutLeft;animation-name:bounceOutLeft}@-webkit-keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.bounceOutUp{-webkit-animation-name:bounceOutUp;animation-name:bounceOutUp}@-webkit-keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes fadeIn{from{opacity:0}to{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{from{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDown{from{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInDownBig{from{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDownBig{from{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInDownBig{-webkit-animation-name:fadeInDownBig;animation-name:fadeInDownBig}@-webkit-keyframes fadeInLeft{from{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeft{from{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeft{-webkit-animation-name:fadeInLeft;animation-name:fadeInLeft}@-webkit-keyframes fadeInLeftBig{from{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeftBig{from{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeftBig{-webkit-animation-name:fadeInLeftBig;animation-name:fadeInLeftBig}@-webkit-keyframes fadeInRight{from{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRight{from{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInRight{-webkit-animation-name:fadeInRight;animation-name:fadeInRight}@-webkit-keyframes fadeInRightBig{from{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRightBig{from{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInRightBig{-webkit-animation-name:fadeInRightBig;animation-name:fadeInRightBig}@-webkit-keyframes fadeInUp{from{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUp{from{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeInUpBig{from{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUpBig{from{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInUpBig{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes fadeOut{from{opacity:1}to{opacity:0}}@keyframes fadeOut{from{opacity:1}to{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes fadeOutDown{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutDownBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes fadeOutDownBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.fadeOutDownBig{-webkit-animation-name:fadeOutDownBig;animation-name:fadeOutDownBig}@-webkit-keyframes fadeOutLeft{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes fadeOutLeft{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.fadeOutLeft{-webkit-animation-name:fadeOutLeft;animation-name:fadeOutLeft}@-webkit-keyframes fadeOutLeftBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes fadeOutLeftBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.fadeOutLeftBig{-webkit-animation-name:fadeOutLeftBig;animation-name:fadeOutLeftBig}@-webkit-keyframes fadeOutRight{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes fadeOutRight{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.fadeOutRight{-webkit-animation-name:fadeOutRight;animation-name:fadeOutRight}@-webkit-keyframes fadeOutRightBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes fadeOutRightBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.fadeOutRightBig{-webkit-animation-name:fadeOutRightBig;animation-name:fadeOutRightBig}@-webkit-keyframes fadeOutUp{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes fadeOutUp{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes fadeOutUpBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes fadeOutUpBig{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.fadeOutUpBig{-webkit-animation-name:fadeOutUpBig;animation-name:fadeOutUpBig}@-webkit-keyframes flip{from{-webkit-transform:perspective(400px) rotate3d(0,1,0,-360deg);transform:perspective(400px) rotate3d(0,1,0,-360deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}to{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}@keyframes flip{from{-webkit-transform:perspective(400px) rotate3d(0,1,0,-360deg);transform:perspective(400px) rotate3d(0,1,0,-360deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}to{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}.animated.flip{-webkit-backface-visibility:visible;backface-visibility:visible;-webkit-animation-name:flip;animation-name:flip}@-webkit-keyframes flipInX{from{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1,0,0,10deg);transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-5deg);transform:perspective(400px) rotate3d(1,0,0,-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInX{from{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1,0,0,10deg);transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-5deg);transform:perspective(400px) rotate3d(1,0,0,-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInX{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInX;animation-name:flipInX}@-webkit-keyframes flipInY{from{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-20deg);transform:perspective(400px) rotate3d(0,1,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(0,1,0,10deg);transform:perspective(400px) rotate3d(0,1,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-5deg);transform:perspective(400px) rotate3d(0,1,0,-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInY{from{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-20deg);transform:perspective(400px) rotate3d(0,1,0,-20deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(0,1,0,10deg);transform:perspective(400px) rotate3d(0,1,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-5deg);transform:perspective(400px) rotate3d(0,1,0,-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInY;animation-name:flipInY}@-webkit-keyframes flipOutX{from{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);opacity:1}to{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);opacity:0}}@keyframes flipOutX{from{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);opacity:1}to{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);opacity:0}}.flipOutX{-webkit-animation-name:flipOutX;animation-name:flipOutX;-webkit-backface-visibility:visible!important;backface-visibility:visible!important}@-webkit-keyframes flipOutY{from{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-15deg);transform:perspective(400px) rotate3d(0,1,0,-15deg);opacity:1}to{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);opacity:0}}@keyframes flipOutY{from{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-15deg);transform:perspective(400px) rotate3d(0,1,0,-15deg);opacity:1}to{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);opacity:0}}.flipOutY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipOutY;animation-name:flipOutY}@-webkit-keyframes lightSpeedIn{from{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg);opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg);opacity:1}to{-webkit-transform:none;transform:none;opacity:1}}@keyframes lightSpeedIn{from{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg);opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg);opacity:1}to{-webkit-transform:none;transform:none;opacity:1}}.lightSpeedIn{-webkit-animation-name:lightSpeedIn;animation-name:lightSpeedIn;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}@-webkit-keyframes lightSpeedOut{from{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}@keyframes lightSpeedOut{from{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}.lightSpeedOut{-webkit-animation-name:lightSpeedOut;animation-name:lightSpeedOut;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}@-webkit-keyframes rotateIn{from{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,-200deg);transform:rotate3d(0,0,1,-200deg);opacity:0}to{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateIn{from{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,-200deg);transform:rotate3d(0,0,1,-200deg);opacity:0}to{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}.rotateIn{-webkit-animation-name:rotateIn;animation-name:rotateIn}@-webkit-keyframes rotateInDownLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownLeft{-webkit-animation-name:rotateInDownLeft;animation-name:rotateInDownLeft}@-webkit-keyframes rotateInDownRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownRight{-webkit-animation-name:rotateInDownRight;animation-name:rotateInDownRight}@-webkit-keyframes rotateInUpLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpLeft{-webkit-animation-name:rotateInUpLeft;animation-name:rotateInUpLeft}@-webkit-keyframes rotateInUpRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-90deg);transform:rotate3d(0,0,1,-90deg);opacity:0}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-90deg);transform:rotate3d(0,0,1,-90deg);opacity:0}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpRight{-webkit-animation-name:rotateInUpRight;animation-name:rotateInUpRight}@-webkit-keyframes rotateOut{from{-webkit-transform-origin:center;transform-origin:center;opacity:1}to{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,200deg);transform:rotate3d(0,0,1,200deg);opacity:0}}@keyframes rotateOut{from{-webkit-transform-origin:center;transform-origin:center;opacity:1}to{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,200deg);transform:rotate3d(0,0,1,200deg);opacity:0}}.rotateOut{-webkit-animation-name:rotateOut;animation-name:rotateOut}@-webkit-keyframes rotateOutDownLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}}@keyframes rotateOutDownLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}}.rotateOutDownLeft{-webkit-animation-name:rotateOutDownLeft;animation-name:rotateOutDownLeft}@-webkit-keyframes rotateOutDownRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}@keyframes rotateOutDownRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}.rotateOutDownRight{-webkit-animation-name:rotateOutDownRight;animation-name:rotateOutDownRight}@-webkit-keyframes rotateOutUpLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}@keyframes rotateOutUpLeft{from{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}to{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}.rotateOutUpLeft{-webkit-animation-name:rotateOutUpLeft;animation-name:rotateOutUpLeft}@-webkit-keyframes rotateOutUpRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,90deg);transform:rotate3d(0,0,1,90deg);opacity:0}}@keyframes rotateOutUpRight{from{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}to{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,90deg);transform:rotate3d(0,0,1,90deg);opacity:0}}.rotateOutUpRight{-webkit-animation-name:rotateOutUpRight;animation-name:rotateOutUpRight}@-webkit-keyframes hinge{0%{-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate3d(0,0,1,80deg);transform:rotate3d(0,0,1,80deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}40%,80%{-webkit-transform:rotate3d(0,0,1,60deg);transform:rotate3d(0,0,1,60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}to{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}@keyframes hinge{0%{-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate3d(0,0,1,80deg);transform:rotate3d(0,0,1,80deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}40%,80%{-webkit-transform:rotate3d(0,0,1,60deg);transform:rotate3d(0,0,1,60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}to{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}.hinge{-webkit-animation-name:hinge;animation-name:hinge}@-webkit-keyframes rollIn{from{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg);transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes rollIn{from{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg);transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg)}to{opacity:1;-webkit-transform:none;transform:none}}.rollIn{-webkit-animation-name:rollIn;animation-name:rollIn}@-webkit-keyframes rollOut{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg);transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg)}}@keyframes rollOut{from{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg);transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg)}}.rollOut{-webkit-animation-name:rollOut;animation-name:rollOut}@-webkit-keyframes zoomIn{from{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{from{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}.zoomIn{-webkit-animation-name:zoomIn;animation-name:zoomIn}@-webkit-keyframes zoomInDown{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInDown{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInDown{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes zoomInLeft{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInLeft{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInLeft{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes zoomInRight{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInRight{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInRight{-webkit-animation-name:zoomInRight;animation-name:zoomInRight}@-webkit-keyframes zoomInUp{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInUp{from{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInUp{-webkit-animation-name:zoomInUp;animation-name:zoomInUp}@-webkit-keyframes zoomOut{from{opacity:1}50%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}to{opacity:0}}@keyframes zoomOut{from{opacity:1}50%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}to{opacity:0}}.zoomOut{-webkit-animation-name:zoomOut;animation-name:zoomOut}@-webkit-keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomOutDown{-webkit-animation-name:zoomOutDown;animation-name:zoomOutDown}@-webkit-keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}@keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}.zoomOutLeft{-webkit-animation-name:zoomOutLeft;animation-name:zoomOutLeft}@-webkit-keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}@keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}.zoomOutRight{-webkit-animation-name:zoomOutRight;animation-name:zoomOutRight}@-webkit-keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomOutUp{-webkit-animation-name:zoomOutUp;animation-name:zoomOutUp}@-webkit-keyframes slideInDown{from{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes slideInDown{from{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.slideInDown{-webkit-animation-name:slideInDown;animation-name:slideInDown}@-webkit-keyframes slideInLeft{from{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes slideInLeft{from{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.slideInLeft{-webkit-animation-name:slideInLeft;animation-name:slideInLeft}@-webkit-keyframes slideInRight{from{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes slideInRight{from{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.slideInRight{-webkit-animation-name:slideInRight;animation-name:slideInRight}@-webkit-keyframes slideInUp{from{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes slideInUp{from{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.slideInUp{-webkit-animation-name:slideInUp;animation-name:slideInUp}@-webkit-keyframes slideOutDown{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes slideOutDown{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.slideOutDown{-webkit-animation-name:slideOutDown;animation-name:slideOutDown}@-webkit-keyframes slideOutLeft{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes slideOutLeft{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.slideOutLeft{-webkit-animation-name:slideOutLeft;animation-name:slideOutLeft}@-webkit-keyframes slideOutRight{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes slideOutRight{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.slideOutRight{-webkit-animation-name:slideOutRight;animation-name:slideOutRight}@-webkit-keyframes slideOutUp{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes slideOutUp{from{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}to{visibility:hidden;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.slideOutUp{-webkit-animation-name:slideOutUp;animation-name:slideOutUp}"
  },
  {
    "path": "static/css/datatables/datatables-site.css",
    "content": "/*\nThis CSS file uses code with the following licenses:\n\n------\nGridism\nA simple, responsive, and handy CSS grid by @cobyism\nhttps://github.com/cobyism/gridism\n\n\n------\nYUI 3.14.0 (build a01e97d)\nCopyright 2013 Yahoo! Inc. All rights reserved.\nLicensed under the BSD License.\nhttp://yuilibrary.com/license/\n\n*/\nhtml {\n\tcolor: #000;\n\tbackground: #FFF\n}\n\nbody,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td {\n\tmargin: 0;\n\tpadding: 0\n}\n\ntable {\n\tborder-collapse: collapse;\n\tborder-spacing: 0\n}\n\nfieldset,img {\n\tborder: 0\n}\n\naddress,caption,cite,code,dfn,em,strong,th,var {\n\tfont-style: normal;\n\tfont-weight: normal\n}\n\nol,ul {\n\tlist-style: none\n}\n\ncaption,th {\n\ttext-align: left\n}\n\nh1,h2,h3,h4,h5,h6 {\n\tfont-size: 100%;\n\tfont-weight: normal\n}\n\nq:before,q:after {\n\tcontent: ''\n}\n\nabbr,acronym {\n\tborder: 0;\n\tfont-variant: normal\n}\n\nsup {\n\tvertical-align: text-top\n}\n\nsub {\n\tvertical-align: text-bottom\n}\n\ninput,textarea,select {\n\tfont-family: inherit;\n\tfont-size: inherit;\n\tfont-weight: inherit;\n\t*font-size: 100%\n}\n\nlegend {\n\tcolor: #000\n}\n\n#yui3-css-stamp.cssreset {\n\tdisplay: none\n}\n\n.grid,.unit {\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box\n}\n\n.grid {\n\tdisplay: block;\n\tclear: both;\n\tmargin-left: -10px;\n\tmargin-right: -10px\n}\n\n.grid.margin {\n\tmargin-left: 0;\n\tmargin-right: 0\n}\n\n.grid .unit {\n\tfloat: left;\n\twidth: 100%;\n\tpadding: 0 10px\n}\n\n.unit .unit:first-child {\n\tpadding-left: 0\n}\n\n.unit .unit:last-child {\n\tpadding-right: 0\n}\n\n.unit .grid:first-child>.unit {\n\tpadding-top: 0\n}\n\n.unit .grid:last-child>.unit {\n\tpadding-bottom: 0\n}\n\n.no-gutters .unit,.unit.no-gutters {\n\tpadding: 0 !important\n}\n\n.wrap .grid,.grid.wrap {\n\tmax-width: 978px;\n\tmargin: 0 auto\n}\n\n.grid .whole,.grid .w-1-1 {\n\twidth: 100%\n}\n\n.grid .half,.grid .w-1-2 {\n\twidth: 50%\n}\n\n.grid .one-third,.grid .w-1-3 {\n\twidth: 33.3332%\n}\n\n.grid .two-thirds,.grid .w-2-3 {\n\twidth: 66.6665%\n}\n\n.grid .one-quarter,.grid .w-1-4 {\n\twidth: 25%\n}\n\n.grid .three-quarters,.grid .w-3-4 {\n\twidth: 75%\n}\n\n.grid .one-fifth,.grid .w-1-5 {\n\twidth: 20%\n}\n\n.grid .two-fifths,.grid .w-2-5 {\n\twidth: 40%\n}\n\n.grid .three-fifths,.grid .w-3-5 {\n\twidth: 60%\n}\n\n.grid .four-fifths,.grid .w-4-5 {\n\twidth: 80%\n}\n\n.grid .one-sixth,.grid .w-1-6 {\n\twidth: 16.6665%\n}\n\n.grid .golden-small,.grid .w-g-s {\n\twidth: 38.2716%\n}\n\n.grid .golden-large,.grid .w-g-l {\n\twidth: 61.7283%\n}\n\n.grid {\n\t*zoom: 1\n}\n\n.grid:before,.grid:after {\n\tdisplay: table;\n\tcontent: \"\";\n\tline-height: 0\n}\n\n.grid:after {\n\tclear: both\n}\n\n.align-center {\n\ttext-align: center\n}\n\n.align-left {\n\ttext-align: left\n}\n\n.align-right {\n\ttext-align: right\n}\n\n.pull-left {\n\tfloat: left\n}\n\n.pull-right {\n\tfloat: right\n}\n\n@media screen and (max-width: 568px) {\n\t.grid .unit {\n\t\twidth: 100% !important;\n\t\tpadding-left: 20px;\n\t\tpadding-right: 20px\n\t}\n\n\t.unit .grid .unit {\n\t\tpadding-left: 0px;\n\t\tpadding-right: 0px\n\t}\n\n\t.center-on-mobiles {\n\t\ttext-align: center !important\n\t}\n\n\t.hide-on-mobiles {\n\t\tdisplay: none !important\n\t}\n}\n\n@media screen and (min-width: 1180px) {\n\t.wider .grid {\n\t\tmax-width: 1180px;\n\t\tmargin: 0 auto\n\t}\n}\n\n.syntaxhighlighter a,.syntaxhighlighter div,.syntaxhighlighter code,.syntaxhighlighter table,.syntaxhighlighter table td,.syntaxhighlighter table tr,.syntaxhighlighter table tbody,.syntaxhighlighter table thead,.syntaxhighlighter table caption,.syntaxhighlighter textarea {\n\t-moz-border-radius: 0 0 0 0 !important;\n\t-webkit-border-radius: 0 0 0 0 !important;\n\tbackground: none !important;\n\tborder: 0 !important;\n\tbottom: auto !important;\n\tfloat: none !important;\n\theight: auto !important;\n\tleft: auto !important;\n\tline-height: 1.1em !important;\n\tmargin: 0 !important;\n\toutline: 0 !important;\n\toverflow: visible !important;\n\tpadding: 0 !important;\n\tposition: static !important;\n\tright: auto !important;\n\ttext-align: left !important;\n\ttop: auto !important;\n\tvertical-align: baseline !important;\n\twidth: auto !important;\n\tbox-sizing: content-box !important;\n\tfont-family: \"Source Code Pro\",\"Consolas\",\"Monaco\",\"Bitstream Vera Sans Mono\",\"Courier New\",Courier,monospace !important;\n\tfont-weight: normal !important;\n\tfont-style: normal !important;\n\tfont-size: 1em !important;\n\tmin-height: inherit !important;\n\tmin-height: auto !important;\n\twhite-space: nowrap\n}\n\n.syntaxhighlighter {\n\twidth: 100% !important;\n\tmargin: 1em 0 1em 0 !important;\n\tposition: relative !important;\n\toverflow: auto !important;\n\tfont-size: 1em !important;\n\tclear: both;\n\tbox-shadow: inset 0 0 3px #555;\n\tpadding: 5px 3px;\n\tbackground: #f8f8f8 !important;\n\tbox-sizing: border-box\n}\n\n.syntaxhighlighter.source {\n\toverflow: hidden !important\n}\n\n.syntaxhighlighter .bold {\n\tfont-weight: bold !important\n}\n\n.syntaxhighlighter .italic {\n\tfont-style: italic !important\n}\n\n.syntaxhighlighter .line {\n\twhite-space: nowrap !important\n}\n\n.syntaxhighlighter table {\n\twidth: 100% !important\n}\n\n.syntaxhighlighter table caption {\n\ttext-align: left !important;\n\tpadding: .5em 0 0.5em 1em !important\n}\n\n.syntaxhighlighter table td.code {\n\twidth: 100% !important\n}\n\n.syntaxhighlighter table td.code .container {\n\tposition: relative !important\n}\n\n.syntaxhighlighter table td.code .container textarea {\n\tbox-sizing: border-box !important;\n\tposition: absolute !important;\n\tleft: 0 !important;\n\ttop: 0 !important;\n\twidth: 100% !important;\n\theight: 100% !important;\n\tborder: none !important;\n\tbackground: white !important;\n\tpadding-left: 1em !important;\n\toverflow: hidden !important;\n\twhite-space: pre !important\n}\n\n.syntaxhighlighter table td.gutter .line {\n\ttext-align: right !important;\n\tpadding: 2px 0.5em 2px 1em !important\n}\n\n.syntaxhighlighter table td.code .line {\n\tpadding: 2px 1em !important\n}\n\n.syntaxhighlighter.nogutter td.code .container textarea,.syntaxhighlighter.nogutter td.code .line {\n\tpadding-left: 0em !important\n}\n\n.syntaxhighlighter.show {\n\tdisplay: block !important\n}\n\n.syntaxhighlighter.collapsed table {\n\tdisplay: none !important\n}\n\n.syntaxhighlighter.collapsed .toolbar {\n\tpadding: 0.1em 0.8em 0em 0.8em !important;\n\tfont-size: 1em !important;\n\tposition: static !important;\n\twidth: auto !important;\n\theight: auto !important\n}\n\n.syntaxhighlighter.collapsed .toolbar span {\n\tdisplay: inline !important;\n\tmargin-right: 1em !important\n}\n\n.syntaxhighlighter.collapsed .toolbar span a {\n\tpadding: 0 !important;\n\tdisplay: none !important\n}\n\n.syntaxhighlighter.collapsed .toolbar span a.expandSource {\n\tdisplay: inline !important\n}\n\n.syntaxhighlighter .toolbar {\n\tposition: absolute !important;\n\tright: 10px !important;\n\ttop: 0 !important;\n\tfont-size: 10px !important;\n\tz-index: 7 !important\n}\n\n.syntaxhighlighter .toolbar span.title {\n\tdisplay: inline !important\n}\n\n.syntaxhighlighter .toolbar a {\n\tdisplay: block !important;\n\ttext-align: center !important;\n\ttext-decoration: none !important;\n\tpadding-top: 1px !important\n}\n\n.syntaxhighlighter .toolbar a.expandSource {\n\tdisplay: none !important\n}\n\n.syntaxhighlighter.ie {\n\tfont-size: .9em !important;\n\tpadding: 1px 0 1px 0 !important\n}\n\n.syntaxhighlighter.ie .toolbar {\n\tline-height: 8px !important\n}\n\n.syntaxhighlighter.ie .toolbar a {\n\tpadding-top: 0px !important\n}\n\n.syntaxhighlighter.printing .line.alt1 .content,.syntaxhighlighter.printing .line.alt2 .content,.syntaxhighlighter.printing .line.highlighted .number,.syntaxhighlighter.printing .line.highlighted.alt1 .content,.syntaxhighlighter.printing .line.highlighted.alt2 .content {\n\tbackground: none !important\n}\n\n.syntaxhighlighter.printing .line .number {\n\tcolor: #bbbbbb !important\n}\n\n.syntaxhighlighter.printing .line .content {\n\tcolor: black !important\n}\n\n.syntaxhighlighter.printing .toolbar {\n\tdisplay: none !important\n}\n\n.syntaxhighlighter.printing a {\n\ttext-decoration: none !important\n}\n\n.syntaxhighlighter.printing .plain,.syntaxhighlighter.printing .plain a {\n\tcolor: black !important\n}\n\n.syntaxhighlighter.printing .comments,.syntaxhighlighter.printing .comments a {\n\tcolor: #008200 !important\n}\n\n.syntaxhighlighter.printing .string,.syntaxhighlighter.printing .string a {\n\tcolor: blue !important\n}\n\n.syntaxhighlighter.printing .keyword {\n\tcolor: #006699 !important;\n\tfont-weight: bold !important\n}\n\n.syntaxhighlighter.printing .preprocessor {\n\tcolor: gray !important\n}\n\n.syntaxhighlighter.printing .variable {\n\tcolor: #aa7700 !important\n}\n\n.syntaxhighlighter.printing .value {\n\tcolor: #009900 !important\n}\n\n.syntaxhighlighter.printing .functions {\n\tcolor: #ff1493 !important\n}\n\n.syntaxhighlighter.printing .constants {\n\tcolor: #0066cc !important\n}\n\n.syntaxhighlighter.printing .script {\n\tfont-weight: bold !important\n}\n\n.syntaxhighlighter.printing .color1,.syntaxhighlighter.printing .color1 a {\n\tcolor: gray !important\n}\n\n.syntaxhighlighter.printing .color2,.syntaxhighlighter.printing .color2 a {\n\tcolor: #ff1493 !important\n}\n\n.syntaxhighlighter.printing .color3,.syntaxhighlighter.printing .color3 a {\n\tcolor: red !important\n}\n\n.syntaxhighlighter.printing .break,.syntaxhighlighter.printing .break a {\n\tcolor: black !important\n}\n\n.syntaxhighlighter {\n\tfont-size: 13px !important;\n\toverflow: visible !important\n}\n\n.syntaxhighlighter .line.alt1 {\n\tbackground-color: white !important\n}\n\n.syntaxhighlighter .line.alt2 {\n\tbackground-color: #F8F8F8 !important\n}\n\n.syntaxhighlighter .line.highlighted.alt1,.syntaxhighlighter .line.highlighted.alt2 {\n\tbackground-color: #e0e0e0 !important\n}\n\n.syntaxhighlighter .line.highlighted.number {\n\tcolor: black !important\n}\n\n.syntaxhighlighter table caption {\n\tcolor: black !important\n}\n\n.syntaxhighlighter .gutter div {\n\tcolor: #5C5C5C !important\n}\n\n.syntaxhighlighter .gutter .line.alt1,.syntaxhighlighter .gutter .line.alt2 {\n\tbackground-color: transparent !important\n}\n\n.odd .syntaxhighlighter .gutter .line.alt1,.odd .syntaxhighlighter .gutter .line.alt2 {\n\tbackground-color: #F2F2F2 !important\n}\n\n.syntaxhighlighter .gutter .line {\n\tborder-right: 3px solid #4E6CA3 !important\n}\n\n.syntaxhighlighter .gutter .line.highlighted {\n\tbackground-color: #4E6CA3 !important;\n\tcolor: white !important\n}\n\n.syntaxhighlighter.printing .line .content {\n\tborder: none !important\n}\n\n.syntaxhighlighter.collapsed {\n\toverflow: visible !important\n}\n\n.syntaxhighlighter.collapsed .toolbar {\n\tcolor: blue !important;\n\tbackground: white !important;\n\tborder: 1px solid #4E6CA3 !important\n}\n\n.syntaxhighlighter.collapsed .toolbar a {\n\tcolor: blue !important\n}\n\n.syntaxhighlighter.collapsed .toolbar a:hover {\n\tcolor: red !important\n}\n\n.syntaxhighlighter .toolbar {\n\tcolor: white !important;\n\tborder: none !important\n}\n\n.syntaxhighlighter .toolbar a {\n\tfont: 100%/1.45em \"Lucida Grande\", Verdana, Arial, Helvetica, sans-serif !important;\n\tcolor: white !important;\n\tbackground: #4E6CA3 !important;\n\tfloat: right !important;\n\tpadding: 2px 5px !important;\n\tclear: both\n}\n\n.syntaxhighlighter .toolbar a:hover {\n\tcolor: #b7c5df !important;\n\tbackground: #39568b !important\n}\n\n.syntaxhighlighter .plain,.syntaxhighlighter .plain a {\n\tcolor: black !important\n}\n\n.syntaxhighlighter .comments,.syntaxhighlighter .comments a {\n\tcolor: #008200 !important\n}\n\n.syntaxhighlighter .string,.syntaxhighlighter .string a {\n\tcolor: blue !important\n}\n\n.syntaxhighlighter .keyword {\n\tcolor: #006699 !important\n}\n\n.syntaxhighlighter .preprocessor {\n\tcolor: gray !important\n}\n\n.syntaxhighlighter .variable {\n\tcolor: #aa7700 !important\n}\n\n.syntaxhighlighter .value {\n\tcolor: #009900 !important\n}\n\n.syntaxhighlighter .functions {\n\tcolor: #ff1493 !important\n}\n\n.syntaxhighlighter .constants {\n\tcolor: #0066cc !important\n}\n\n.syntaxhighlighter .script {\n\tfont-weight: bold !important;\n\tcolor: #006699 !important;\n\tbackground-color: none !important\n}\n\n.syntaxhighlighter .color1,.syntaxhighlighter .color1 a {\n\tcolor: gray !important\n}\n\n.syntaxhighlighter .color2,.syntaxhighlighter .color2 a {\n\tcolor: #ff1493 !important\n}\n\n.syntaxhighlighter .color3,.syntaxhighlighter .color3 a {\n\tcolor: red !important\n}\n\n.syntaxhighlighter .keyword {\n\tfont-weight: bold !important\n}\n\n.datatables_ref:hover {\n\ttext-decoration: underline;\n\tcursor: pointer;\n\t*cursor: hand\n}\n\n.syntaxhighlighter .dtapi {\n\tcolor: #069\n}\n\n.syntaxhighlighter .dtapi:hover {\n\ttext-decoration: underline;\n\tcursor: pointer;\n\t*cursor: hand\n}\n\n.syntaxhighlighter table {\n\ttable-layout: fixed !important\n}\n\n.syntaxhighlighter table td.gutter {\n\twidth: 46px !important\n}\n\n.syntaxhighlighter table td.code {\n\twidth: auto !important;\n\toverflow: auto !important\n}\n\n#lbOverlay {\n\tposition: fixed;\n\tz-index: 9999;\n\tleft: 0;\n\ttop: 0;\n\twidth: 100%;\n\theight: 100%;\n\tbackground-color: #000;\n\tcursor: pointer\n}\n\n#lbCenter,#lbBottomContainer {\n\tposition: absolute;\n\tz-index: 9999;\n\toverflow: hidden;\n\tbackground-color: #fff\n}\n\n.lbLoading {\n\tbackground: #fff url(../images/slimbox/loading.gif) no-repeat center\n}\n\n#lbImage {\n\tposition: absolute;\n\tleft: 0;\n\ttop: 0;\n\tborder: 10px solid #fff;\n\tbackground-repeat: no-repeat\n}\n\n#lbPrevLink,#lbNextLink {\n\tdisplay: block;\n\tposition: absolute;\n\ttop: 0;\n\twidth: 50%;\n\toutline: none\n}\n\n#lbPrevLink {\n\tleft: 0\n}\n\n#lbPrevLink:hover {\n\tbackground: transparent url(../images/slimbox/prevlabel.gif) no-repeat 0 15%\n}\n\n#lbNextLink {\n\tright: 0\n}\n\n#lbNextLink:hover {\n\tbackground: transparent url(../images/slimbox/nextlabel.gif) no-repeat 100% 15%\n}\n\n#lbBottom {\n\tfont-family: Verdana, Arial, Geneva, Helvetica, sans-serif;\n\tfont-size: 10px;\n\tcolor: #666;\n\tline-height: 1.4em;\n\ttext-align: left;\n\tborder: 10px solid #fff;\n\tborder-top-style: none\n}\n\n#lbCloseLink {\n\tdisplay: block;\n\tfloat: right;\n\twidth: 66px;\n\theight: 22px;\n\tbackground: transparent url(../images/slimbox/closelabel.gif) no-repeat center;\n\tmargin: 5px 0;\n\toutline: none\n}\n\n#lbCaption,#lbNumber {\n\tmargin-right: 71px\n}\n\n#lbCaption {\n\tfont-weight: bold\n}\n\n@font-face {\n\tfont-family:'ralewaythin';src:url(\"../font/raleway_thin-webfont.eot\");src:url(\"../font/raleway_thin-webfont.eot?#iefix\") format(\"embedded-opentype\"),url(\"../font/raleway_thin-webfont.woff\") format(\"woff\"),url(\"../font/raleway_thin-webfont.ttf\") format(\"truetype\");font-weight:normal;font-style:normal\n}\n\nhtml {\n\theight: 100%;\n\tfont-size: inherit !important\n}\n\nbody {\n\tfont: 90%/1.45em \"Helvetica Neue\", HelveticaNeue, Helvetica, Arial, sans-serif !important;\n\tmargin: 0;\n\tpadding: 0;\n\tcolor: #333;\n\tbackground-color: #fff;\n\tposition: relative;\n\t/* padding-bottom: 220px !important; */\n    padding-bottom: 20px !important;\n\theight: auto !important;\n\tmin-height: 100%;\n\tbox-sizing: border-box;\n\t-webkit-font-smoothing: inherit\n}\n\np {\n\tmargin: 1em 0\n}\n\np:first-child {\n\tmargin-top: 0\n}\n\np:last-child {\n\tmargin-bottom: 0\n}\n\na {\n\tcursor: pointer;\n\tcolor: #3174c7;\n\ttext-decoration: none\n}\n\np a[href^=\"http\"]:not([href*=\"datatables.net\"]) {\n\tbackground: url(../images/external-site.gif) no-repeat right center;\n\tpadding-right: 1em\n}\n\na:hover {\n\ttext-decoration: underline\n}\n\nimg.lightbox {\n\toutline: 2px solid #3174C7;\n\toutline-offset: 1px;\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box\n}\n\nh2 {\n\tfont-size: 2em;\n\tmargin: 1.5em 0 0.5em 0\n}\n\nh3 {\n\tfont-size: 1.4em;\n\tline-height: 1.4em;\n\tmargin: 1em 0 0.5em 0\n}\n\nh3 span {\n\tfont-size: 0.8em\n}\n\nh4 {\n\tfont-size: 1.4em;\n\tmargin: 0.5em 0\n}\n\nh5 {\n\tfont-size: 1.2em;\n\tmargin: 0.5em 0\n}\n\nh6 {\n\tfont-size: 1.1em;\n\tmargin: 1.5em 0 0.5em 0\n}\n\nem {\n\tfont-style: italic\n}\n\nstrong {\n\tfont-weight: bold\n}\n\nspan.small,p.small {\n\tfont-size: 0.8em\n}\n\nimg.markdown {\n\tdisplay: block;\n\tmargin: 0 auto;\n\tmax-width: 100%\n}\n\nol.markdown,ol.formatting,ul.markdown,ul.formatting {\n\tmargin: 1.5em 2em 1.5em 1em\n}\n\nol.markdown li,ol.formatting li,ul.markdown li,ul.formatting li {\n\tborder-bottom: 1px solid #e6e6e6;\n\tpadding: 0.5em 0.5em\n}\n\nol.markdown li:before,ol.formatting li:before,ul.markdown li:before,ul.formatting li:before {\n\tcontent: \"- \";\n\tcolor: #ccc\n}\n\nol.markdown li:first-child,ol.formatting li:first-child,ul.markdown li:first-child,ul.formatting li:first-child {\n\tborder-top: 1px solid #efefef\n}\n\nol.markdown li:last-child,ol.formatting li:last-child,ul.markdown li:last-child,ul.formatting li:last-child {\n\tborder-bottom: 1px solid #efefef\n}\n\nol.markdown li:hover,ol.formatting li:hover,ul.markdown li:hover,ul.formatting li:hover {\n\tbackground-color: #f6f6f6\n}\n\nol.markdown ul,ol.formatting ul,ul.markdown ul,ul.formatting ul {\n\tmargin: 0.5em 0 0 1em\n}\n\nol.markdown ul li,ol.formatting ul li,ul.markdown ul li,ul.formatting ul li {\n\tfont-size: 0.9em;\n\tpadding: 0.25em 0.5em\n}\n\nol.markdown ul li:first-child,ol.formatting ul li:first-child,ul.markdown ul li:first-child,ul.formatting ul li:first-child {\n\tborder-top: none\n}\n\nol.markdown ul li:last-child,ol.formatting ul li:last-child,ul.markdown ul li:last-child,ul.formatting ul li:last-child {\n\tborder-bottom: none\n}\n\nol {\n\tlist-style-type: decimal\n}\n\nol>li {\n\ttext-indent: 0 !important\n}\n\n/* ol>li:before {\n\tcontent: \"\" !important\n} */\n\nul.blog_link_list span {\n\tfloat: right\n}\n\ndiv.dataTables_wrapper li {\n\ttext-indent: 0\n}\n\ndiv.dataTables_wrapper li:before {\n\tcontent: \"\"\n}\n\ncode {\n\tfont-family: \"Source Code Pro\", Consolas, Menlo, Monaco, \"Courier New\", monospace;\n\tpadding: 1px 4px;\n\tfont-size: 0.8em;\n\tcolor: #444;\n\tbackground-color: #fcfcfc;\n\tborder: 1px solid #e0e0e0;\n\t-webkit-border-radius: 3px;\n\t-moz-border-radius: 3px;\n\tborder-radius: 3px\n}\n\ncode:after {\n\tdisplay: inline-block;\n\tborder-left: 1px solid rgba(0,0,0,0.2);\n\tmargin-left: 4px;\n\tpadding-left: 4px;\n\topacity: 0.5\n}\n\na code {\n\ttext-decoration: underline\n}\n\ncode.option {\n\tcolor: #D14;\n\tbackground-color: #fcf6f8;\n\tborder: 1px solid #f7d6df;\n\twhite-space: nowrap\n}\n\ncode.option:after {\n\tcontent: 'Option'\n}\n\ncode.path {\n\tcolor: #095c05;\n\tbackground-color: #eef7ed;\n\tborder: 1px solid #8ccb89;\n\twhite-space: nowrap\n}\n\ncode.path:after {\n\tcontent: 'Path'\n}\n\ncode.tag {\n\tcolor: #c29f00;\n\tbackground-color: #fff9d7;\n\tborder: 1px solid #ffe700;\n\twhite-space: nowrap\n}\n\ncode.tag:after {\n\tcontent: 'Tag'\n}\n\ncode.api {\n\tcolor: #0c199c;\n\tbackground-color: #f4f5fc;\n\tborder: 1px solid #c6cbe9;\n\twhite-space: nowrap\n}\n\ncode.api:after {\n\tcontent: 'API'\n}\n\ncode.type {\n\tcolor: #d119cf;\n\tbackground-color: #faebfa;\n\tborder: 1px solid #f3aef2;\n\twhite-space: nowrap\n}\n\ncode.type:after {\n\tcontent: 'Type'\n}\n\ncode.event {\n\tcolor: #2a839e;\n\tbackground-color: #f5fafb;\n\tborder: 1px solid #a8ddec;\n\twhite-space: nowrap\n}\n\ncode.event:after {\n\tcontent: 'Event'\n}\n\ncode.string {\n\tcolor: #c05f1d;\n\tbackground-color: #f5eee9;\n\tborder: 1px solid #dfc4b2;\n\twhite-space: nowrap\n}\n\ncode.string:after {\n\tcontent: 'String'\n}\n\ncode.field {\n\tcolor: #ad1ee8;\n\tbackground-color: #f9f1fc;\n\tborder: 1px solid #ebc9f7;\n\twhite-space: nowrap\n}\n\ncode.field:after {\n\tcontent: 'Field'\n}\n\ncode.button {\n\tcolor: #464e50;\n\tbackground-color: #f2f7f9;\n\tborder: 1px solid #b8c3c5;\n\twhite-space: nowrap\n}\n\ncode.button:after {\n\tcontent: 'Button'\n}\n\ncode.multiline {\n\tdisplay: inline-block;\n\twidth: 95%\n}\n\ndiv.syntaxhighlighter code:after {\n\tdisplay: none\n}\n\nblockquote {\n\tmargin: 1em;\n\tborder: 1px solid #CCC;\n\tbackground-color: #F9F9F9;\n\tpadding: 1em;\n\tborder-radius: 0.25em\n}\n\naside {\n\twidth: 33%;\n\tfloat: right;\n\tfont-size: 0.9em;\n\tline-height: 1.45em;\n\tmargin: 0 1em 1em 1em;\n\tbox-shadow: 2px 2px 6px rgba(0,0,0,0.2);\n\tborder: 1px solid #CCC;\n\tbackground-color: #F9F9F9;\n\tpadding: 1em;\n\tborder-radius: 0.25em\n}\n\naside h1 {\n\tmargin: -1em;\n\tpadding: 1.5em 1em 0.5em 1em;\n\tfont-weight: bold\n}\n\naside h1:first-child {\n\tpadding-top: 0.5em\n}\n\naside h2 {\n\tmargin: -1em;\n\tpadding: 1em;\n\tfont-size: 1.3em\n}\n\naside ul {\n\tmargin: 1em 0em !important\n}\n\naside ul li {\n\ttext-indent: 0;\n\tpadding: 0.25em 0 !important\n}\n\naside ul li::before {\n\tcontent: \"\"\n}\n\naside ul:last-child {\n\tmargin-bottom: 0.5em\n}\n\ndiv.fw-nav ul,div.fw-page-nav ul {\n\tposition: relative;\n\tmargin: 0\n}\n\ndiv.fw-nav ul li:before,div.fw-page-nav ul li:before {\n\tcontent: none\n}\n\ndiv.fw-nav ul li,div.fw-page-nav ul li {\n\tposition: relative;\n\twidth: 100%;\n\tleft: 0;\n\tright: 0;\n\tborder: none;\n\tpadding: 0;\n\ttext-indent: 1em;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis\n}\n\ndiv.fw-nav ul li li,div.fw-page-nav ul li li {\n\ttext-indent: 2em;\n\tfont-size: 0.9em\n}\n\ndiv.fw-nav ul li li li,div.fw-page-nav ul li li li {\n\ttext-indent: 4em;\n\tfont-size: 0.9em\n}\n\ndiv.fw-nav ul span.ellipsis,div.fw-page-nav ul span.ellipsis {\n\tbackground-color: #eee;\n\tborder-radius: 4px;\n\tdisplay: inline-block;\n\ttext-align: center;\n\tpadding: 0 0.5em;\n\ttext-indent: 0\n}\n\ndiv.fw-nav ul ul li.sub>a:after,div.fw-page-nav ul ul li.sub>a:after {\n\tbackground: url(../images/nav-section.gif) no-repeat center center;\n\tdisplay: inline-block;\n\tcontent: \".\";\n\tcolor: transparent;\n\twidth: 18px\n}\n\ndiv.fw-nav a,div.fw-page-nav a {\n\tdisplay: block;\n\tpadding: 0.33em 0\n}\n\ndiv.fw-nav li li a,div.fw-page-nav li li a {\n\tpadding: 0.2em 0\n}\n\ndiv.fw-nav li.active,div.fw-nav li.sub-active,div.fw-page-nav li.active,div.fw-page-nav li.sub-active {\n\tbackground-color: rgba(200,200,200,0.1)\n}\n\ndiv.fw-nav li.active a,div.fw-nav li.sub-active a,div.fw-page-nav li.active a,div.fw-page-nav li.sub-active a {\n\tborder-right: 4px solid #ddd\n}\n\ndiv.fw-nav li ul li.active a,div.fw-nav li ul li.sub-active a,div.fw-page-nav li ul li.active a,div.fw-page-nav li ul li.sub-active a {\n\tborder-right: 4px solid #ccc\n}\n\ndiv.fw-nav li.active>a,div.fw-page-nav li.active>a {\n\tborder-right: 4px solid #458ae0 !important;\n\tbackground-color: rgba(200,200,200,0.4);\n\tcolor: black\n}\n\ndiv.fw-nav a:hover,div.fw-page-nav a:hover {\n\ttext-decoration: none;\n\tbackground-color: rgba(100,100,100,0.15) !important\n}\n\ndiv.fw-page-nav li a {\n\tborder-left: 4px solid transparent\n}\n\ndiv.fw-page-nav li.active>a {\n\tborder-left: 4px solid #458ae0 !important;\n\tborder-right: none !important;\n\tbackground-color: #f1f1f1 !important;\n\tcolor: black\n}\n\ndiv.fw-page-nav li.active a,div.fw-page-nav li.sub-active a {\n\tborder-left: 4px solid #ddd;\n\tborder-right: none;\n\tbackground-color: #f9f9f9\n}\n\ndiv.fw-page-nav div.page-nav-title {\n\tdisplay: none\n}\n\ndiv.fw-page-nav>div.page-nav {\n\tpadding: 0\n}\n\ndiv.fw-background {\n\tposition: absolute;\n\ttop: -677px;\n\tleft: 0;\n\twidth: 100%;\n\theight: 800px;\n\tbackground: #3a7fd5;\n\tbackground: linear-gradient(to right, #3a7fd5, #6ebce2);\n\ttransform: skew(0, -1.5deg);\n\ttransform-origin: bottom left;\n\tbox-shadow: inset 0 -3px 10px rgba(0,0,0,0.1)\n}\n\ndiv.fw-background.grey {\n\ttop: 0;\n\tbackground: #edf0f4;\n\tbackground: linear-gradient(to right, #edf0f4, #ebeef2)\n}\n\ndiv.fw-container-full {\n\tposition: relative;\n\tmargin: 0;\n\tmax-width: 100%;\n\tclear: both\n}\n\ndiv.fw-container-full div.fw-background {\n\theight: auto;\n\ttop: 0;\n\tbottom: 0;\n\ttransform-origin: top right\n}\n\ndiv.fw-container-full div.content {\n\tmargin-top: 9em\n}\n\ndiv.fw-hero {\n\tdisplay: none\n}\n\ndiv.fw-hero h1 {\n\tcolor: white;\n\tfont-size: 3em;\n\tfont-weight: bold;\n\tmargin-top: 2em;\n\tmargin-bottom: 1em;\n\tline-height: 1.25em\n}\n\ndiv.fw-hero div.hero-callout {\n\tbackground-color: white;\n\tpadding: 1.5em;\n\tbox-shadow: 3px 3px 20px rgba(0,0,0,0.3);\n\tborder-radius: 3px\n}\n\ndiv.fw-hero div.hero-item {\n\tcolor: white;\n\tfont-size: 1.2em;\n\tpadding: 0.5em 0 0 0;\n\tmargin: 2em 0 1em 0\n}\n\ndiv.fw-hero div.hero-item:first-child {\n\tpadding: 0;\n\tmargin-top: 0\n}\n\ndiv.fw-hero div.hero-item span.number {\n\tfont-weight: bold;\n\tfont-size: 1.5em;\n\tvertical-align: text-bottom\n}\n\ndiv.fw-hero div.hero-item span.number:after {\n\tdisplay: inline;\n\tcolor: #103665;\n\tcontent: '-';\n\tpadding: 0 4px 0 9px;\n\tfont-weight: 100\n}\n\ndiv.fw-hero div.cdn,div.fw-hero div.syntaxhighlighter {\n\tbackground: rgba(0,0,0,0.5) !important;\n\tborder-radius: 3px;\n\tbox-shadow: none !important\n}\n\ndiv.fw-hero div.cdn *,div.fw-hero div.syntaxhighlighter * {\n\tbackground: transparent !important;\n\tborder: none !important\n}\n\ndiv.fw-hero div.cdn {\n\tpadding: 5px\n}\n\ndiv.fw-hero div.cdn span {\n\tcolor: white;\n\tfont-weight: bold\n}\n\ndiv.fw-hero div.cdn input,div.fw-hero div.cdn a {\n\tcolor: #d6d6d6\n}\n\ndiv.fw-hero div.syntaxhighlighter div {\n\tline-height: 1.4em !important\n}\n\ndiv.fw-hero div.syntaxhighlighter .toolbar {\n\tdisplay: none\n}\n\ndiv.fw-hero div.syntaxhighlighter .line.alt2,div.fw-hero div.syntaxhighlighter .line.alt1 {\n\tbackground: transparent !important\n}\n\ndiv.fw-hero div.syntaxhighlighter .gutter .line {\n\tborder: none !important;\n\tcolor: #888 !important\n}\n\ndiv.fw-hero div.syntaxhighlighter .plain {\n\tcolor: #d6d6d6 !important\n}\n\ndiv.fw-hero div.syntaxhighlighter .string {\n\tcolor: white !important\n}\n\ndiv.fw-hero div.syntaxhighlighter .keyword {\n\tcolor: #6ebce2 !important\n}\n\ndiv.fw-hero .site-btn {\n\tborder-radius: 2em;\n\tbackground: #7bcbe5;\n\tbackground: linear-gradient(to bottom, #7bcbe5, #53badc);\n\tfont-weight: bold;\n\tletter-spacing: 1px;\n\tpadding: 1em 0;\n\tmargin-top: 2.5em\n}\n\ndiv.fw-hero .site-btn:hover {\n\tbox-shadow: 3px 3px 10px rgba(0,0,0,0.5)\n}\n\ndiv.fw-hero span.icon {\n\tposition: relative;\n\ttop: 10px;\n\tdisplay: inline-block;\n\theight: 17px;\n\twidth: 17px;\n\tbackground-position: center center;\n\tbackground-repeat: no-repeat\n}\n\ndiv.fw-hero span.i-arrow-down {\n\tbackground-image: url(data:image/png;\n\tbase64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAPCAYAAADd/14OAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJVJREFUeNpiFDBLTWBgYFBgwAQbPpyafQHGYYHS9QzYAVwhE1DXAiBtCMSOUFyITQfYRGQrgE7BajQTA5FgWClkRAoWWBA1APF6IG6ExpgBEDuwoGnUhyoEgQIg5gfii+hWO0AF9aF8mCIHYIR8YEQ2Dmi9AJA6AFUMVwSSY0ZW+OPpuR8c0sYrgExOIE6AKQIBgAADAMr4KAni8YsuAAAAAElFTkSuQmCC)\n}\n\ndiv.fw-hero span.i-arrow-right {\n\ttop: 5px;\n\tleft: 4px;\n\tbackground-image: url(data:image/png;\n\tbase64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAMCAYAAACEJVa/AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIJJREFUeNpiYCASCJilCoAwNjlGYg0AUgegXIcPp2Z/QJZnItYhQKwAxPogw9BdRJQhQJsfgFwAxB+xGUSsS0AGXYAa9BDdIEYgA+RXewbywEWQwUwMlAEFomMHSyzpQ8MHFFMXGCk1gNR0AtIgj24ASbEDiiBsBjCQGh64kj1AgAEAuXIv95gaUfgAAAAASUVORK5CYII=)\n}\n\nbody.hero div.fw-background {\n\ttop: 0\n}\n\nbody.hero div.fw-hero {\n\tdisplay: block\n}\n\nbody.hero div.nav-main {\n\tmargin-top: 0.5em !important\n}\n\ndiv.fw-container {\n\tposition: relative;\n\tmax-width: 1140px;\n\tmargin: 0 auto;\n\tclear: both;\n\tpadding: 0 1em;\n\tbox-sizing: border-box\n}\n\ndiv.fw-container:after {\n\tdisplay: block;\n\tcontent: '';\n\tclear: both\n}\n\ndiv.fw-container div.fw-header {\n\tposition: relative;\n\theight: 70px;\n\tmax-width: 1140px;\n\twidth: 100%;\n\toverflow: hidden;\n\tmargin: 0 auto;\n\twhite-space: nowrap\n}\n\ndiv.fw-container div.fw-header a {\n\tcolor: white\n}\n\ndiv.fw-container div.fw-header div.nav-master {\n\tposition: absolute;\n\ttop: 1em;\n\tleft: 0;\n\twidth: 30%;\n\tmin-width: 350px;\n\tz-index: 2;\n\tpadding: 0;\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box\n}\n\ndiv.fw-container div.fw-header div.nav-master div.nav-item {\n\twidth: 50%;\n\tdisplay: inline-block;\n\tfont-size: 1.6em;\n\tfont-weight: 100;\n\tletter-spacing: 1px;\n\tpadding-top: 15px\n}\n\ndiv.fw-container div.fw-header div.nav-master div.nav-item a {\n\tdisplay: inline-block;\n\tbackground-repeat: no-repeat;\n\tbackground-position: center left;\n\tpadding-left: 50px;\n\tline-height: 40px\n}\n\ndiv.fw-container div.fw-header div.nav-master div.nav-item a:hover {\n\tcolor: white\n}\n\ndiv.fw-container div.fw-header div.nav-master div.nav-item:nth-child(1) a {\n\tbackground-image: url(data:image/png;\n\tbase64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTM4IDc5LjE1OTgyNCwgMjAxNi8wOS8xNC0wMTowOTowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowYzM2OTczNC1lOWYxLTQ3ZmQtYTJmMS0xMTRiNDU5YzliZjgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUMwMTE4MDQwNEQ4MTFFOEEyQTFCRUVFOUI3NDk2NTYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUMwMTE4MDMwNEQ4MTFFOEEyQTFCRUVFOUI3NDk2NTYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoxMzZlMDIyMC1hZmVjLTRkNGMtYTc1ZS02NjUwNTlkNjAxMDIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MGMzNjk3MzQtZTlmMS00N2ZkLWEyZjEtMTE0YjQ1OWM5YmY4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)\n}\n\ndiv.fw-container div.fw-header div.nav-master div.nav-item:nth-child(2) {\n\tmargin-left: 1em\n}\n\ndiv.fw-container div.fw-header div.nav-master div.nav-item:nth-child(2) a {\n\tbackground-image: url(data:image/png;\n\tbase64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTM4IDc5LjE1OTgyNCwgMjAxNi8wOS8xNC0wMTowOTowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowYzM2OTczNC1lOWYxLTQ3ZmQtYTJmMS0xMTRiNDU5YzliZjgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RjIyRTkyNzcwNEQ4MTFFOEEyQTFCRUVFOUI3NDk2NTYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RjIyRTkyNzYwNEQ4MTFFOEEyQTFCRUVFOUI3NDk2NTYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoxMzZlMDIyMC1hZmVjLTRkNGMtYTc1ZS02NjUwNTlkNjAxMDIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MGMzNjk3MzQtZTlmMS00N2ZkLWEyZjEtMTE0YjQ1OWM5YmY4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+B0vo5gAAA4FJREFUeNrMmctLVVEUxr0Xr5DlII826dIgwhc4sBQVbaCjZj2gfNEgUMMaN+gPCJs0kURtEtRAoyh6UCZaVNiDbCRUBjrwUWA6ycwXevpWfBs2h6PtfTqn64If95579l7ru3vfs/fa68Zc100LYHFQBmpAKcgDe8FO3l8EM+ALGAHPwXuwYR1JBFqQBO1g0rW3SfZN2sQ0beiATrCiBRwHXaAJHGSbDOLwsya2mdD6rdCXE5bAU+A7na+DPlBpOfIxUA166cOlz7p/EZjOb69sCBRZCvOjiL6UdTGWlcBM8JAOlsD5EIR5OUffLmNlmgqUb3OfHedAeQTiFOWM4TJmuonAbnaYBQURilMUMJbL2FsKrGPDXxGPnN9ILjJ2w2YCHe1pbf2P4hStjD0Pcv0Eqid2IAXiFEPeqVY39oFVsAYKUyiwkBpWqenPnirWBhKgD3yy3C2LQQcYA8uye4Jv4DY4YOlLYt+ilja1F8fBFIe2yuLbyrp1DWyw7w/wDrwEM/zsdIBRPMy+oimuniCX+2XMQtxr9vsMToCEp82egNMc0/bucpniWg7vAKfHxK6CSvAEHAJ3wZqnzWxaMHOpRawmzgBirwwdSP53hr+5k8z9wjalpVQE5vPio2HnZr5ejEicriVf5nsObxyQA+YNOk+AXJDtM61hmegRXfMygln8cMGwc5KpvFdcBbgHBkMQqLRkxUNwJsL6wRtwLPSx1NIdx3AZkCVggRlyv5Z4vgVHtuh3CbwwjJGt0j25GOVFiWHnHs9h6G/ChN3MkKYMY5TQ92icy4VYkeGg3+DrEjiuTfFW1g52gB7DGErLmAj8wItqw87D4DoDtmpn4c3sAjgLxsEVwxhKy4gMZ0VEW50cOx9o2XlhkK0u6mRBbBjst/Bb5U0W0njiF7sZYHMvBh1gDCzTz1dwBxzlANj466WPdj1hTfLEvx0S1nVqSXpT/k4qf5pCgYPaYd730KQW7ZYUiGvRzuLOZsfOejZaTOGxs3E7H9x7TCoLGZ7SR1mE4so8pY8Mm+LRY6141ByBuGbuz2KPbIpHioQ23S6fsKKQlpJBzW+3zy5kVcCs9xQwewMWMKt8CpgNYZWAc7g2+ZWAG5keORyJBN+X8J5fCbiLPkOrUes7zmUwHaCIPs2+VkX02D/+DVHLY2sezyq7eP8nmObZRdK5Z0H/hvgtwADFObsUkY835QAAAABJRU5ErkJggg==)\n}\n\ndiv.fw-container div.fw-header div.nav-search {\n\tposition: absolute;\n\ttop: 18px;\n\tright: 0;\n\tcolor: white;\n\tfont-weight: 100\n}\n\ndiv.fw-container div.fw-header div.nav-search div.nav-item {\n\tmargin: 1em;\n\tdisplay: inline-block;\n\tbackground-repeat: no-repeat;\n\tbackground-position: center left;\n\tpadding-left: 22px;\n\tcolor: white\n}\n\ndiv.fw-container div.fw-header div.nav-search div.nav-item.search {\n\tborder-radius: 20px;\n\tbackground-color: rgba(255,255,255,0.5);\n\tpadding: 0 2em 0 1em;\n\tmargin-right: 0;\n\theight: 30px\n}\n\ndiv.fw-container div.fw-header div.nav-search div.nav-item:nth-child(1) {\n\tbackground-image: url(data:image/png;\n\tbase64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAPCAYAAAAyPTUwAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALFJREFUeNqEUgERgzAMTHYVUAerBCSAEyTMwSxUAhKQUAnMwSTgoPtw7a4XQvm7P0r4Psm3nHMORDTTNSIz77JgiFc8PZiUSAye4Accjw0QJ3DUdqUewa3QP6gP+X01WnvOS1a4dEaPMxfgdZKaa5xkyJexb6kL1xR9058pvhuwmpycdyNrwRcctFhO8m2I08kZQ0vwk5HKP1qnP/Sar3dDsHV04bgfEA8l33Bz7PEnwABb115LkRPJ9wAAAABJRU5ErkJggg==)\n}\n\ndiv.fw-container div.fw-header div.nav-search div.nav-item:nth-child(2) {\n\tbackground-image: url(data:image/png;\n\tbase64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAM1JREFUeNqsUwERwyAMJL0JQEIlVAJSkLA5wMGQgAQkVAISJqEO2HMLuxxLu+22v/tLm+bDp03JKKi1nhGsSGUiKmPdpAgXhKtIzWA0nwBiB9bhftVqJ/MD/iduFhEWpc6y/WVv1gTe2nxyxiboufqA08QRLKDdae6PxJbFLw2E0GufptsqXPRsIISbqMvgTDxfZ0dfisQLcwHL8DwZ7uSUEVY+zQuHVrzAcNJeDvZ4Q3DDymYwyHyznfm6fLEfzU0k7hqGv+gd2kHhLsAAWAbiLHZ2WKcAAAAASUVORK5CYII=)\n}\n\ndiv.fw-container div.fw-header div.nav-search div.nav-item:nth-child(3) {\n\tbackground-image: url(data:image/png;\n\tbase64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANtJREFUeNqcUgsNwyAQLUsFIKESKqESkICESpiESqiESmAOkFAJOGDvksfSsivpRvK4cNzv3Z3JOXf/nl4uY8xJiYADxEQkIAhgl452jzoaHEeICHhgp3oRZ/zZ2viUEUiAr2wsEIHQcp6BTePHAJmU1LIn8vs65Puijc4ZxzYa3OTshdtF2WNddlfPGe8dWBVHaeRTzUyDyOhFBkW3fkYmzoBj5Ll8cGxCw1Wj3FidLc4Sbbm7lqzCl25LE7Yf1lrGOfSHx3K1IMq4ZAOdYcNE4VjBrcxYmvAWYAB1DOITHc2nAAAAAABJRU5ErkJggg==)\n}\n\ndiv.fw-container div.fw-header div.nav-search div.nav-item:nth-child(4) {\n\tbackground-position: 10px center;\n\tbackground-image: url(data:image/png;\n\tbase64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAL1JREFUeNqsUgsNxCAMHVOAhJOABCQgYRJOwkk4CUhAwkmYhEnAASuX16RhkJJsTV5K+nn0Z5ZGSimOlCdYQiYkY8yxaEKJlvArfal2qyXvCK76Q/DQ0m615Dj4IHIlPecGZ1JaTIgL0r4S2PBVxsQfuJb5P7iJIb96bawyQOFg/4Vgx9srBOw/LoeD0jKOqFe+gz+PVrkJktD4AuzDNbckTNRe5RSJx76zOOGIDbgpEmWVj5O875DUVu0pwACNqkylG1oepQAAAABJRU5ErkJggg==)\n}\n\ndiv.fw-container div.fw-header div.nav-search div.nav-item div.search-clear {\n\tfloat: right;\n\tpadding-top: 4px\n}\n\ndiv.fw-container div.fw-header div.nav-search a {\n\tfont-weight: 100;\n\tletter-spacing: 1px\n}\n\ndiv.fw-container div.fw-header div.nav-search input {\n\tbackground: transparent;\n\tborder: none;\n\tcolor: white;\n\tmargin: 0 0 0 1em;\n\twidth: 200px;\n\tline-height: 1em;\n\tfont: 1em \"Helvetica Neue\", HelveticaNeue, Helvetica, Arial, sans-serif !important;\n\tbox-shadow: none\n}\n\ndiv.fw-container div.fw-header div.nav-search input:focus {\n\toutline: none\n}\n\ndiv.fw-container div.fw-header div.nav-search input::-webkit-input-placeholder {\n\tcolor: white;\n\tfont-weight: 100;\n\tletter-spacing: 1px\n}\n\ndiv.fw-container div.fw-header div.nav-search input::-moz-placeholder {\n\tcolor: white;\n\tfont-weight: 100;\n\tletter-spacing: 1px\n}\n\ndiv.fw-container div.fw-header div.nav-search input:-moz-placeholder {\n\tcolor: white;\n\tfont-weight: 100;\n\tletter-spacing: 1px\n}\n\ndiv.fw-container div.fw-header div.nav-search input:-ms-input-placeholder {\n\tcolor: white;\n\tfont-weight: 100;\n\tletter-spacing: 1px\n}\n\ndiv.fw-container div.fw-sidebar,div.fw-container div.fw-nav {\n\tfloat: left;\n\twidth: 20%;\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box\n}\n\ndiv.fw-container div.fw-sidebar div.nav-main,div.fw-container div.fw-nav div.nav-main {\n\tposition: relative;\n\tmargin-top: 7em\n}\n\ndiv.fw-container div.fw-sidebar div.nav-main>ul>li:nth-child(1):before,div.fw-container div.fw-sidebar div.nav-main>ul>li:nth-child(6):before,div.fw-container div.fw-sidebar div.nav-main>ul>li:nth-child(10):before,div.fw-container div.fw-nav div.nav-main>ul>li:nth-child(1):before,div.fw-container div.fw-nav div.nav-main>ul>li:nth-child(6):before,div.fw-container div.fw-nav div.nav-main>ul>li:nth-child(10):before {\n\tdisplay: block;\n\tfont-weight: 100;\n\tfont-style: italic;\n\tmargin-top: 1em;\n\tletter-spacing: 1px\n}\n\ndiv.fw-container div.fw-sidebar div.nav-main>ul>li:nth-child(1):before,div.fw-container div.fw-nav div.nav-main>ul>li:nth-child(1):before {\n\tcontent: 'Using DataTables';\n\tmargin-top: 0\n}\n\ndiv.fw-container div.fw-sidebar div.nav-main>ul>li:nth-child(6):before,div.fw-container div.fw-nav div.nav-main>ul>li:nth-child(6):before {\n\tcontent: 'More Help'\n}\n\ndiv.fw-container div.fw-sidebar div.nav-main>ul>li:nth-child(10):before,div.fw-container div.fw-nav div.nav-main>ul>li:nth-child(10):before {\n\tcontent: 'Get DataTables'\n}\n\ndiv.fw-container div.fw-sidebar div.nav-main>ul>li>a,div.fw-container div.fw-nav div.nav-main>ul>li>a {\n\tfont-weight: bold\n}\n\ndiv.fw-container div.fw-sidebar div.sidebar,div.fw-container div.fw-nav div.sidebar {\n\tposition: relative;\n\tmargin-top: 7em\n}\n\ndiv.fw-container div.fw-body {\n\tfloat: left;\n\twidth: 60%;\n\tpadding: 0 1em;\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box;\n\tposition: relative\n}\n\ndiv.fw-container div.fw-body div.content {\n\tposition: relative;\n\tmargin-top: 7em\n}\n\ndiv.fw-container div.fw-body div.content>h1 {\n\tposition: absolute;\n\ttop: -1.15em;\n\tleft: 0;\n\twidth: 100%;\n\tmargin: 0;\n\tfont-family: 'HelveticaNeue-UltraLight', 'Helvetica Neue UltraLight', 'ralewaythin', 'Helvetica Neue', \"Calibri Light\", \"Calibri\", Helvetica, Arial, sans-serif;\n\tfont-weight: 100;\n\tletter-spacing: 1px;\n\tfont-size: 3em;\n\tline-height: 1.2em;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis\n}\n\ndiv.fw-container div.fw-body div.content>h1 span {\n\tfont-size: 0.6em;\n\tline-height: 1em\n}\n\ndiv.fw-container div.fw-body div.content h2>a[name]:before,div.fw-container div.fw-body div.content h3>a[name]:before {\n\tdisplay: block;\n\tcontent: \"\";\n\theight: 60px;\n\tmargin-top: -60px\n}\n\ndiv.fw-container div.fw-page-nav {\n\tfloat: left;\n\twidth: 20%;\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box;\n\tmargin-top: 7em\n}\n\ndiv.fw-container div.fw-page-nav.static {\n\tmargin-top: 0\n}\n\ndiv.fw-container div.fw-page-nav.static div.page-nav {\n\tposition: fixed;\n\ttop: 0\n}\n\ndiv.fw-footer {\n\tposition: absolute;\n\tbottom: 0;\n\tleft: 0;\n\twidth: 100%;\n\tclear: both;\n\tcolor: #ccc;\n\ttext-align: right;\n\tpadding: 2em 0;\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box\n}\n\ndiv.fw-footer h4 {\n\tfloat: right;\n\tbackground-repeat: no-repeat;\n\tbackground-position: center left;\n\tbackground-image: url(data:image/png;\n\tbase64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTM4IDc5LjE1OTgyNCwgMjAxNi8wOS8xNC0wMTowOTowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowYzM2OTczNC1lOWYxLTQ3ZmQtYTJmMS0xMTRiNDU5YzliZjgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUMwMTE4MDQwNEQ4MTFFOEEyQTFCRUVFOUI3NDk2NTYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUMwMTE4MDMwNEQ4MTFFOEEyQTFCRUVFOUI3NDk2NTYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoxMzZlMDIyMC1hZmVjLTRkNGMtYTc1ZS02NjUwNTlkNjAxMDIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MGMzNjk3MzQtZTlmMS00N2ZkLWEyZjEtMTE0YjQ1OWM5YmY4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);padding-left: 50px;\n\tline-height: 40px\n}\n\ndiv.fw-footer p {\n\tclear: both\n}\n\ndiv.fw-footer a {\n\tcolor: #ccc;\n\ttext-decoration: underline\n}\n\ndiv.fw-footer div.copyright {\n\tposition: relative;\n\ttext-align: right;\n\tpadding: 1em 0;\n\tmax-width: 1140px;\n\tmargin: 0 auto;\n\tline-height: 1.8em;\n\tz-index: 1\n}\n\ndiv.fw-footer div.skew {\n\tbackground: #363d46;\n\theight: 70px;\n\ttransform: skew(0, -1.5deg);\n\ttransform-origin: top right;\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\tbox-shadow: inset 0 3px 10px rgba(0,0,0,0.1)\n}\n\ndiv.fw-footer div.skew-bg {\n\tposition: absolute;\n\ttop: 70px;\n\tbottom: 0;\n\tleft: 0;\n\tright: 0;\n\tbackground: #363d46\n}\n\nbody.wide div.fw-body {\n\twidth: 80%;\n\tfloat: right\n}\n\nbody.wide div.fw-page-nav {\n\tdisplay: none\n}\n\ndiv.mobile-show {\n\tdisplay: none\n}\n\n@media only screen and (max-width: 1070px) {\n\tdiv.fw-container div.fw-header div.nav-search input {\n\t\twidth: 150px\n\t}\n\n\tdiv.fw-footer div.copyright {\n\t\tpadding-right: 1em\n\t}\n}\n\n@media only screen and (max-width: 959px) {\n\tdiv.fw-container div.fw-body {\n\t\twidth: 80%\n\t}\n\n\tdiv.fw-container div.fw-page-nav {\n\t\tdisplay: none\n\t}\n\n\tdiv.fw-container div.fw-header div.nav-item.i-manual,div.fw-container div.fw-header div.nav-item.i-download {\n\t\tdisplay: none !important\n\t}\n}\n\n@media only screen and (max-width: 860px) {\n\tdiv.fw-hero h1 br {\n\t\tcontent: ' '\n\t}\n\n\tdiv.fw-hero h1 br:after {\n\t\tdisplay: inline-block;\n\t\tcontent: ' ';\n\t\twhite-space: pre\n\t}\n\n\tdiv.fw-hero div.grid .w-1-3 {\n\t\tdisplay: none\n\t}\n\n\tdiv.fw-hero div.grid .w-2-3 {\n\t\twidth: 100%\n\t}\n\n\tdiv.index-features div.feature {\n\t\twidth: 50% !important\n\t}\n\n\tdiv.news {\n\t\tmax-height: 1100px !important\n\t}\n\n\tdiv.news>div {\n\t\twidth: 49% !important\n\t}\n}\n\n@media only screen and (max-width: 760px) {\n\tbody.wide div.fw-container div.fw-body {\n\t\twidth: 100%\n\t}\n\n\tdiv.fw-container div.fw-hero h1 {\n\t\tmargin-top: 0\n\t}\n\n\tdiv.fw-container div.fw-header {\n\t\theight: 150px\n\t}\n\n\tdiv.fw-container div.fw-header div.nav-master {\n\t\tposition: relative;\n\t\ttop: 0;\n\t\twidth: 100%;\n\t\t-webkit-box-sizing: border-box;\n\t\t-moz-box-sizing: border-box;\n\t\tbox-sizing: border-box;\n\t\tleft: 0;\n\t\ttext-align: center\n\t}\n\n\tdiv.fw-container div.fw-header div.nav-master div.nav-item {\n\t\tmargin: 0 !important\n\t}\n\n\tdiv.fw-container div.fw-header div.nav-search {\n\t\tposition: static;\n\t\ttext-align: center\n\t}\n\n\tdiv.fw-container div.fw-nav {\n\t\tposition: relative;\n\t\tz-index: 5;\n\t\tfloat: none;\n\t\twidth: 100%;\n\t\theight: 9.5em;\n\t\toverflow: hidden;\n\t\tmargin-bottom: 1em\n\t}\n\n\tdiv.fw-container div.fw-nav div.nav-main {\n\t\tmargin-top: 0\n\t}\n\n\tdiv.fw-container div.fw-nav div.mobile-show {\n\t\tdisplay: block;\n\t\tposition: absolute;\n\t\tbottom: 0;\n\t\twidth: 100%;\n\t\theight: 55px;\n\t\tbackground-color: rgba(255,255,255,0.3);\n\t\tbackground: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(255,255,255,0.3)), color-stop(100%, #fff));\n\t\tbackground: -webkit-linear-gradient(top, rgba(255,255,255,0.3) 0%, #fff 100%);\n\t\tbackground: -moz-linear-gradient(top, rgba(255,255,255,0.3) 0%, #fff 100%);\n\t\tbackground: -ms-linear-gradient(top, rgba(255,255,255,0.3) 0%, #fff 100%);\n\t\tbackground: -o-linear-gradient(top, rgba(255,255,255,0.3) 0%, #fff 100%);\n\t\tbackground: linear-gradient(to bottom, rgba(255,255,255,0.3) 0%, #fff 100%)\n\t}\n\n\tdiv.fw-container div.fw-nav div.mobile-show a {\n\t\tposition: absolute;\n\t\tbottom: 0\n\t}\n\n\tdiv.fw-container div.fw-header {\n\t\tposition: relative\n\t}\n\n\tdiv.fw-container div.fw-header div.toolbar {\n\t\tposition: relative;\n\t\ttop: 0;\n\t\tright: 0;\n\t\twidth: auto;\n\t\tpadding: 1em 0\n\t}\n\n\tdiv.fw-container div.fw-header div.toolbar input[type='text'] {\n\t\twidth: 75%\n\t}\n\n\tdiv.fw-container div.fw-header div.toolbar input[type='submit'] {\n\t\twidth: 20%\n\t}\n\n\tdiv.fw-container div.fw-body {\n\t\twidth: 100%\n\t}\n\n\tdiv.fw-container div.fw-body aside {\n\t\tdisplay: none\n\t}\n\n\tdiv.fw-container div.fw-body div.content {\n\t\tmargin-top: 0\n\t}\n\n\tdiv.fw-container div.fw-body div.content h1 {\n\t\tposition: relative;\n\t\ttop: 0\n\t}\n}\n\n@media only screen and (max-width: 510px) {\n\tdiv.index-features div.feature {\n\t\twidth: 100% !important\n\t}\n\n\tdiv.news {\n\t\tmax-height: 1700px !important\n\t}\n\n\tdiv.fw-container div.fw-header div.nav-search input {\n\t\twidth: 75px\n\t}\n}\n\nh2.index-callout {\n\tfont-size: 3em;\n\ttext-align: center;\n\tfont-style: italic;\n\tmargin-top: 0;\n\tline-height: 1.05em\n}\n\nh2.index-callout:first-child {\n\tmargin-top: 2.5em\n}\n\np.callout {\n\tfont-size: 1.3em;\n\tline-height: 1.5em;\n\tmargin: 0 auto;\n\twidth: 70%;\n\ttext-align: center\n}\n\ndiv.index-features {\n\tmargin-top: 5em\n}\n\ndiv.index-features div.feature {\n\tfloat: left;\n\twidth: 33%;\n\tmin-height: 190px;\n\ttext-align: center\n}\n\ndiv.index-features div.feature div.feature-icon {\n\tmargin: 0 auto;\n\twidth: 220px;\n\theight: 65px;\n\tbackground-repeat: no-repeat;\n\tbackground-image: url(/media/images/index-features.png)\n}\n\ndiv.index-features div.feature div.title {\n\tfont-weight: bold;\n\tpadding-top: 1em;\n\tfont-size: 1.1em\n}\n\ndiv.index-features div.feature div.subtext {\n\tcolor: #72767c;\n\tpadding: 0.3em 1em\n}\n\ndiv.index-features div.feature a {\n\ttext-decoration: underline;\n\tcolor: inherit\n}\n\ndiv.index-features div.feature div.paging {\n\tbackground-position: 0 0\n}\n\ndiv.index-features div.feature div.search {\n\tbackground-position: -220px 0\n}\n\ndiv.index-features div.feature div.order {\n\tbackground-position: -440px 0\n}\n\ndiv.index-features div.feature div.data {\n\tbackground-position: 0 -65px\n}\n\ndiv.index-features div.feature div.theme {\n\tbackground-position: -220px -65px\n}\n\ndiv.index-features div.feature div.extn {\n\tbackground-position: -440px -65px\n}\n\ndiv.index-features div.feature div.mobile {\n\tbackground-position: 0 -130px\n}\n\ndiv.index-features div.feature div.i18n {\n\tbackground-position: -220px -130px\n}\n\ndiv.index-features div.feature div.oss {\n\tbackground-position: -440px -130px\n}\n\ndiv.editor-box {\n\tborder-top: 5px solid #c83030;\n\tbackground-color: white;\n\tpadding: 1.5em;\n\tbox-shadow: 3px 3px 20px rgba(0,0,0,0.3);\n\tborder-radius: 3px;\n\tmargin: 3em 0\n}\n\ndiv.editor-box h2 {\n\tmargin-top: 0;\n\tline-height: 1.45em;\n\tfont-style: italic\n}\n\ndiv.editor-box p {\n\tcolor: #999\n}\n\ndiv.editor-box a {\n\tmax-width: 50%;\n\tborder-radius: 2em;\n\tbackground-color: #b23335\n}\n\n.self-clear:after {\n\tcontent: \" \";\n\tdisplay: block;\n\tclear: both;\n\theight: 0;\n\twidth: 0\n}\n\ntable.reference tr.group td {\n\tbackground-color: #ccc;\n\tborder: 1px solid #888;\n\tborder-top: 1px solid #888 !important;\n\tfont-weight: bold\n}\n\ndiv.reference_related {\n\twidth: 33%;\n\tfloat: left\n}\n\ndiv.reference_related ul {\n\tmargin: 1em 0\n}\n\ndiv.ref_type {\n\tposition: relative;\n\tpadding: 3.5em 1em 1em 1em;\n\tborder: 1px solid #ccc;\n\tborder-radius: 5px;\n\tbox-shadow: 0 0 3px #bbb;\n\tmargin-bottom: 1em\n}\n\ndiv.ref_type:last-child {\n\tmargin-bottom: 0\n}\n\ndiv.ref_type h3 {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\theight: 1em;\n\tpadding: 0.5em;\n\tmargin-top: 0;\n\tbackground-color: #f6f6f6;\n\tborder-bottom: 1px solid #ddd;\n\tborder-top-left-radius: 5px;\n\tborder-top-right-radius: 5px;\n\twhite-space: nowrap\n}\n\ndiv.ref_type span.type {\n\tfont-size: 0.8em;\n\tcolor: #777;\n\tfont-style: italic\n}\n\ndiv.ref_type dl dt {\n\tfont-size: 1.1em\n}\n\ndiv.ref_type dl dd {\n\tmargin-left: 3em;\n\tmargin-bottom: 1em\n}\n\ndiv.ref_type dl:last-child {\n\tmargin-bottom: 0\n}\n\ndiv.deprecated {\n\tpadding: 1em;\n\tborder: 1px solid #ccc;\n\tborder-radius: 5px;\n\tbox-shadow: 0 0 3px #bbb;\n\tmargin-bottom: 1em;\n\tbackground-color: #f6f6f6\n}\n\ndiv.deprecated h2 {\n\tmargin-top: 0\n}\n\ndl.list dt {\n\twidth: 33%;\n\tfloat: left;\n\tclear: both\n}\n\ndl.list dd {\n\twidth: 66%;\n\tfloat: left\n}\n\ndl.list:after {\n\tcontent: \"\";\n\tdisplay: table;\n\tclear: both\n}\n\ndl.list.formatted dt,dl.list.formatted dd {\n\tpadding: 4px 10px;\n\tbox-sizing: border-box\n}\n\ndiv.since {\n\tcolor: #ac5900;\n\tfloat: right\n}\n\nspan.since {\n\tcolor: #ac5900\n}\n\ndiv.clear {\n\tclear: both;\n\theight: 0;\n\twidth: 100%;\n\tfloat: none !important\n}\n\ndiv.reference_example {\n\tborder-bottom: 1px solid #F3F3F3;\n\tpadding: 1em 0\n}\n\ndiv.reference_example:last-child {\n\tborder-bottom: none;\n\tpadding-bottom: 0\n}\n\ndiv.ref_search {\n\tdisplay: table;\n\tborder-spacing: 0.75em;\n\twidth: 100%;\n\tpadding: 0.5em 0;\n\tborder: 1px solid #ccc;\n\tborder-radius: 5px;\n\tbox-shadow: 2px 2px 2px #bbb;\n\ttext-align: center;\n\tmargin: 1em 0;\n\tbackground: #ffffff;\n\tbackground: -webkit-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);\n\tbackground: -moz-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);\n\tbackground: -ms-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);\n\tbackground: -o-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);\n\tbackground: linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);\n\tfilter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#f9f9f9',GradientType=0 )\n}\n\ndiv.ref_search div.ref_field {\n\tdisplay: table-row\n}\n\ndiv.ref_search div.ref_field div.ref_label {\n\tdisplay: table-cell;\n\ttext-align: right;\n\twidth: 12%\n}\n\ndiv.ref_search div.ref_field div.ref_input {\n\tdisplay: table-cell;\n\ttext-align: left\n}\n\ndiv.ref_search div.ref_field div.ref_input a.site-btn {\n\tmargin-bottom: 0;\n\tmargin-top: 0.5em\n}\n\ndiv.ref_search div.ref_field div.ref_input input {\n\tpadding: 0.5em;\n\tborder-radius: 0.5em;\n\twidth: 75%\n}\n\nbody.example h2.comments_title {\n\tdisplay: none\n}\n\nbody.example div.comment_add {\n\tmargin-bottom: 1.5em\n}\n\nbody.example div.dataTables_wrapper ul li,body.example div.dataTables_wrapper ol li {\n\tpadding: 0;\n\tborder: none !important\n}\n\nbody.example div.toc ul {\n\tcolor: #4E6CA3;\n\tlist-style-type: none;\n\tpadding-left: 0\n}\n\nbody.example div.toc li {\n\tpadding: 0.2em 1em;\n\tborder-left: 4px solid transparent;\n\tborder-bottom: 1px solid #e6e6e6\n}\n\nbody.example div.toc li.active {\n\tborder-left: 4px solid #458ae0\n}\n\nbody.example div.toc li:first-child {\n\tborder-top: 1px solid #efefef\n}\n\nbody.example div.toc li:last-child {\n\tborder-bottom: 1px solid #efefef\n}\n\nbody.example div.info {\n\tmargin-bottom: 2em;\n\t-webkit-column-count: 2;\n\t-moz-column-count: 2;\n\t-ms-column-count: 2;\n\t-o-column-count: 2;\n\tcolumn-count: 2;\n\t-webkit-column-rule: 1px solid #F3F3F3;\n\t-moz-column-rule: 1px solid #F3F3F3;\n\t-ms-column-rule: 1px solid #F3F3F3;\n\t-o-column-rule: 1px solid #F3F3F3;\n\tcolumn-rule: 1px solid #F3F3F3\n}\n\nbody.example div.info>* {\n\t-webkit-column-break-inside: avoid;\n\tbreak-inside: avoid\n}\n\nbody.example div.info li {\n\tmargin-top: 0.75em\n}\n\nbody.example div.info p:first-child {\n\tmargin-top: 0\n}\n\nbody.example div.toc {\n\t-webkit-column-count: 2;\n\t-moz-column-count: 2;\n\t-ms-column-count: 2;\n\t-o-column-count: 2;\n\tcolumn-count: 2\n}\n\nbody.example div.toc-group {\n\tdisplay: inline-block;\n\twidth: 100%\n}\n\nbody.example div.column_half {\n\tfloat: left;\n\twidth: 49%;\n\tpadding-right: 1%\n}\n\nbody.example div.dataTables_wrapper.dt-bootstrap .dataTables_paginate .paginate_button {\n\tpadding: 0;\n\tmargin-left: 0\n}\n\nbody.example div.dataTables_wrapper.dt-bootstrap div.a.site-btn,body.example div.dataTables_wrapper.dt-bootstrap button.site-btn,body.example div.dataTables_wrapper.dt-bootstrap input.site-btn {\n\tmargin-right: 0;\n\tpadding-top: 0.5em;\n\tpadding-bottom: 0.5em\n}\n\nbody.example div.dataTables_wrapper.dt-bootstrap th {\n\tbackground: none !important\n}\n\n@media only screen and (max-width: 979px) {\n\tdiv.container,div.footer {\n\t\tpadding: 0 1em\n\t}\n}\n\n@media screen and (max-width: 767px), screen and (max-width: 768px) and (orientation: portrait) {\n\tbody.example div.info {\n\t\t-webkit-column-count: 1;\n\t\t-moz-column-count: 1;\n\t\t-ms-column-count: 1;\n\t\t-o-column-count: 1;\n\t\tcolumn-count: 1\n\t}\n\n\tbody.example div.toc {\n\t\t-webkit-column-count: 1;\n\t\t-moz-column-count: 1;\n\t\t-ms-column-count: 1;\n\t\t-o-column-count: 1;\n\t\tcolumn-count: 1\n\t}\n\n\tbody.example h1 span {\n\t\tdisplay: block\n\t}\n}\n\ndiv.cdn {\n\tposition: relative;\n\tmargin-bottom: 1em;\n\tbox-shadow: 0 0 3px #555\n}\n\ndiv.cdn>span {\n\tdisplay: inline-block;\n\twidth: 15%;\n\theight: 30px;\n\ttext-align: center;\n\tpadding-top: 6px;\n\tfloat: left;\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box;\n\tbackground: #eee;\n\tborder-right: 1px solid #bbb;\n\tcursor: pointer;\n\tfont-size: 0.9em\n}\n\ndiv.cdn>span span {\n\tfont-size: 0.8em\n}\n\ndiv.cdn>input {\n\tdisplay: inline-block;\n\twidth: 84%;\n\theight: 30px;\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box;\n\tpadding: 10px 5px;\n\tvertical-align: middle;\n\tbackground-color: #f9f9f9;\n\tborder: none;\n\tfont-family: \"Source Code Pro\",\"Consolas\",\"Monaco\",\"Bitstream Vera Sans Mono\",\"Courier New\",Courier,monospace;\n\tfont-size: 0.8em\n}\n\ndiv.cdn>a.cdn-link {\n\tposition: absolute;\n\ttop: 6px;\n\tright: 11px;\n\theight: 9px;\n\twidth: 9px;\n\tbackground: url(../images/external-site.gif) no-repeat center center;\n\tbackground-color: #f9f9f9;\n\tpadding: 3px;\n\tborder: 1px solid #4d90fe;\n\tborder-radius: 3px\n}\n\ndiv.cdn>a.cdn-link:hover {\n\tborder: 1px solid #0E4EB5\n}\n\ntable.parameters {\n\twidth: 100%;\n\tmargin-bottom: 1em\n}\n\ntable.parameters td.parameter {\n\twidth: 200px\n}\n\ntable.parameters td.label {\n\twidth: 180px;\n\tpadding-left: 20px\n}\n\ntable.parameters .css_link {\n\ttext-decoration: none;\n\tcolor: #3174c7;\n\tcursor: pointer\n}\n\ntable.parameters .css_link:hover {\n\ttext-decoration: underline\n}\n\ntable.parameters tr.continuation td {\n\tborder-top: none\n}\n\ntable.parameters.buttons td[colspan]>p {\n\tpadding-left: 3em\n}\n\nform.layout div.field {\n\tclear: both;\n\tmargin-top: 1.2em\n}\n\nform.layout div.field label {\n\tfloat: left;\n\twidth: 30%;\n\tpadding-top: 8px\n}\n\nform.layout div.field>div {\n\tfloat: right;\n\twidth: 70%\n}\n\nform.layout div.field>div>span {\n\tdisplay: inline-block;\n\tfont-size: 0.9em;\n\tline-height: 1.3em;\n\tpadding-top: 4px\n}\n\nform.layout div.field>div.text {\n\tpadding-top: 8px\n}\n\nform.layout select {\n\tmargin: 0 1em\n}\n\nform input {\n\tpadding: 0.5em;\n\tborder-radius: 4px;\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box\n}\n\nform input.width-picker {\n\twidth: 3em;\n\tmargin-right: 0.25em\n}\n\nform input.colour-picker {\n\theight: auto !important\n}\n\nform input.std {\n\twidth: 66%\n}\n\nform textarea {\n\tpadding: 0.5em;\n\tborder-radius: 4px;\n\twidth: 100%;\n\theight: 6em;\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box\n}\n\nform input:focus,form textarea:focus {\n\tbackground-color: #FFE\n}\n\n.minicolors-theme-default .minicolors-swatch {\n\ttop: 10px !important;\n\tleft: 10px !important\n}\n\n.minicolors-theme-default .minicolors-input {\n\tpadding-left: 35px !important\n}\n\nul.tabs {\n\tposition: relative;\n\ttop: 1px;\n\theight: 40px;\n\tmargin: 20px 20px 0 0;\n\tborder: none\n}\n\nul.tabs li {\n\tdisplay: block;\n\tfloat: left;\n\tpadding: 0 15px;\n\theight: 40px;\n\tfont-size: 1.2em;\n\tmargin: 0 5px;\n\tcursor: pointer;\n\tline-height: 40px;\n\tcolor: #121e32;\n\tborder: 1px solid white;\n\tborder-bottom: none;\n\tmargin-top: -1px;\n\ttext-indent: 0\n}\n\nul.tabs li.active {\n\tborder: 1px solid #ccc;\n\tborder-bottom: 1px solid white;\n\tmargin-top: 0;\n\tborder-top-left-radius: 5px;\n\tborder-top-right-radius: 5px\n}\n\nul.tabs li.active:hover {\n\tbackground-color: white\n}\n\nul.tabs li:hover {\n\tbackground-color: #fafafa\n}\n\nul.tabs li:before {\n\tcontent: \"\"\n}\n\ndiv.tabs {\n\tclear: both\n}\n\ndiv.tabs>div {\n\tpadding: 1px 20px 20px 20px;\n\tborder: 1px solid #ccc;\n\tmargin-top: 1px;\n\tdisplay: none;\n\tborder-radius: 5px;\n\tbox-shadow: 2px 2px 2px #bbb\n}\n\na.site-btn,button.site-btn,input.site-btn {\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box;\n\tmin-width: 1.5em;\n\tdisplay: inline-block;\n\tbackground-color: #3b4146;\n\tcolor: white;\n\tdisplay: block;\n\tmargin-top: 1.5em;\n\tmargin-right: 0.5em;\n\ttext-align: center;\n\tpadding: 0.7em;\n\tborder: none;\n\tborder-radius: 4px;\n\tbox-shadow: 2px 2px 4px rgba(0,0,0,0.4);\n\ttext-decoration: none !important;\n\tcursor: pointer;\n\tfont-size: 1em\n}\n\na.site-btn:hover,button.site-btn:hover,input.site-btn:hover {\n\tbackground-color: #3174c7;\n\ttext-decoration: none;\n\tbox-shadow: 1px 1px 3px rgba(0,0,0,0.6)\n}\n\na.site-btn.small,button.site-btn.small,input.site-btn.small {\n\tpadding: 0.5em 1em\n}\n\na.site-btn.btn-inline,button.site-btn.btn-inline,input.site-btn.btn-inline {\n\tdisplay: inline-block\n}\n\na.site-btn.active,button.site-btn.active,input.site-btn.active {\n\tbackground-color: #3174c7\n}\n\ndiv.content h2.comments_title {\n\tmargin-top: 2.5em\n}\n\ndiv.content div.comments dl dt.odd,div.content div.comments dl dd.odd {\n\tbackground-color: #f7f7f7\n}\n\ndiv.content div.comments dl dt {\n\tpadding: 1em 1em 0 1em\n}\n\ndiv.content div.comments dl dt span {\n\tfloat: right\n}\n\ndiv.content div.comments dl dt span.version {\n\tcolor: #ad4900;\n\tdisplay: inline-block;\n\tpadding-left: 1em\n}\n\ndiv.content div.comments dl dd {\n\tpadding: 0.5em 1em 1em 1em;\n\tpadding-bottom: 1em;\n\tborder-bottom: 1px solid #ccc\n}\n\ndiv.content div.comments dl dd:last-child {\n\tborder-bottom: none\n}\n\ndiv.content div.comments dl dt.child,div.content div.comments dl dd.child {\n\tmargin-left: 3em\n}\n\ndiv.content div.comments div.comment_add {\n\tpadding: 1em;\n\tmargin-top: 1em;\n\tborder: 1px solid #ccc;\n\tborder-radius: 5px;\n\tbackground-color: #f9f9f9\n}\n\ndiv.content div.comments div.comment_add h3 {\n\tmargin-top: 0\n}\n\ndiv.content div.comments textarea {\n\twidth: 100%;\n\theight: 10em;\n\tpadding: 1em;\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box\n}\n\ndiv.content div.comments textarea:focus {\n\tbackground-color: #FFE\n}\n\ndl.legal dt {\n\tfloat: left;\n\twidth: 4%;\n\tclear: both;\n\tpadding-top: 1em\n}\n\ndl.legal dd {\n\tpadding-top: 1em;\n\tfloat: right;\n\twidth: 95%\n}\n\ndiv.tooltip {\n\tposition: absolute;\n\tdisplay: none;\n\twidth: 300px;\n\theight: auto;\n\tbackground-color: rgba(0,0,0,0.9);\n\tcolor: white;\n\tbox-shadow: 3px 3px 10px 0px #222;\n\tpadding: 1em;\n\tborder: 3px solid black;\n\tborder-radius: 5px;\n\tfont-size: 0.9em\n}\n\nspan.tooltip {\n\tcolor: #cf5930;\n\tborder-bottom: 1px dashed #cf5930\n}\n\ndiv.fw-body div.info li {\n\tmargin-top: 0\n}\n\n.curr {\n\tcolor: #c73300\n}\n\ndiv.purchase_options {\n\tdisplay: table;\n\twidth: 100%;\n\tborder-spacing: 10px;\n\tborder-collapse: separate;\n\tmargin: 0 -10px\n}\n\ndiv.purchase_options div.purchase_option {\n\tdisplay: table-cell;\n\twidth: 20%;\n\tpadding: 0;\n\theight: 100%;\n\tbackground: #f7f7f7;\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box\n}\n\ndiv.purchase_options div.purchase_option div.liner {\n\tposition: relative;\n\tpadding-bottom: 80px;\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box\n}\n\ndiv.purchase_options.options_4 div.purchase_option {\n\twidth: 25%\n}\n\ndiv.purchase_options.options_3 div.purchase_option {\n\twidth: 33%\n}\n\ndiv.purchase_options.options_2 {\n\tpadding-left: 17%\n}\n\ndiv.purchase_options.options_2 div.purchase_option {\n\twidth: 33%\n}\n\ndiv.purchase_options.options_1 {\n\tpadding-left: 25%\n}\n\ndiv.purchase_options.options_1 div.purchase_option {\n\twidth: 50%\n}\n\ndiv.purchase_options h3,div.purchase_options h4 {\n\ttext-align: center;\n\tborder-bottom: none;\n\tpadding-top: 12px;\n\tmargin: 8px 0;\n\tfont-size: 20px;\n\tline-height: 1.4em\n}\n\ndiv.purchase_options ul {\n\tpadding: 0;\n\tlist-style: none;\n\tfont-size: 90%;\n\tline-height: 1.45em\n}\n\ndiv.purchase_options ul li {\n\tpadding: 5px;\n\ttext-align: center;\n\tbackground: #f1f1f1;\n\tmargin: 5px\n}\n\ndiv.purchase_options ul li:last-child {\n\tborder-bottom: none\n}\n\ndiv.purchase_options button,div.purchase_options a.site-btn {\n\tposition: absolute;\n\tbottom: 16px;\n\tleft: 6%;\n\twidth: 88%;\n\tmargin: 0\n}\n\ndiv.purchase_options p {\n\tfont-size: 90%;\n\tline-height: 1.45em;\n\ttext-align: center\n}\n\n@media only screen and (max-width: 1000px) {\n\tdiv.purchase_options.options_5 {\n\t\tdisplay: block\n\t}\n\n\tdiv.purchase_options.options_5 div.purchase_option {\n\t\tdisplay: block;\n\t\twidth: 100% !important;\n\t\tmargin-bottom: 1em\n\t}\n\n\tdiv.purchase_options.options_5 div.purchase_option div.liner {\n\t\theight: auto !important\n\t}\n}\n\n@media only screen and (max-width: 700px) {\n\tdiv.purchase_options {\n\t\tdisplay: block\n\t}\n\n\tdiv.purchase_options div.purchase_option {\n\t\tdisplay: block;\n\t\twidth: 100% !important;\n\t\tmargin-bottom: 1em\n\t}\n\n\tdiv.purchase_options div.purchase_option div.liner {\n\t\theight: auto !important\n\t}\n\n\tdiv.purchase_options.options_2 {\n\t\tpadding-left: 0\n\t}\n}\n\ndiv.license_info {\n\tclear: both;\n\ttext-align: center;\n\tfont-size: 0.8em;\n\tpadding-top: 1em;\n\tbottom-top: 1em\n}\n\ndiv.license_info img {\n\tpadding-top: 0.5em\n}\n\ndiv.currency-selector {\n\tposition: absolute;\n\tright: 2em;\n\ttop: -2em;\n\tfont-size: 0.9em\n}\n\ndiv.currency-selector.usd a.usd,div.currency-selector.eur a.eur,div.currency-selector.gbp a.gbp {\n\tcolor: black\n}\n\ndiv.currency-selector.inline {\n\tposition: static;\n\ttext-align: right;\n\tpadding-right: 2.5em\n}\n\ndiv.DTE_Body div.DTE_Body_Content div.DTE_Field.DTE_Field_Type_title:hover {\n\tbackground-color: white;\n\tborder: 1px solid transparent\n}\n\ndiv.DTE_Field.DTE_Field_Type_title label {\n\twidth: 100% !important;\n\tfont-size: 1.2em;\n\tfont-weight: bold;\n\tmargin-left: -2em\n}\n\n@media only screen and (max-width: 580px) {\n\tdiv.DTE_Field.DTE_Field_Type_title label {\n\t\tmargin-left: 0\n\t}\n}\n\ndiv.DTE_Field.DTE_Field_Type_title div {\n\tdisplay: none\n}\n\ndiv.DTE_Field_Input a.register-forgot,div.DTE_Field_Input a.register-remember {\n\tdisplay: inline-block;\n\tfont-size: 1.2em;\n\tpadding-top: 0.5em\n}\n\ndiv.DTE_Form_Info {\n\ttext-align: center\n}\n\nform.purchase ul {\n\tlist-style-image: none !important;\n\tfont-size: 100% !important\n}\n\nform.purchase li.field {\n\tclear: both;\n\tpadding-top: 0.5em\n}\n\nform.purchase li.field>label {\n\tdisplay: block;\n\twidth: 33%;\n\tfloat: left;\n\tpadding-top: 3px\n}\n\nform.purchase li.field>div {\n\tfloat: right;\n\twidth: 66%\n}\n\nform.purchase li.field>div input[type='text'],form.purchase li.field>div input[type='password'] {\n\tpadding: 5px;\n\twidth: 90%\n}\n\nform.purchase li.field.title>div {\n\tpadding-top: 0.5em;\n\tpadding-bottom: 0.25em;\n\tfont-size: 1.3em\n}\n\nform.purchase li>div span.required {\n\tcolor: red\n}\n\nform.purchase li.field>div span.error {\n\tcolor: red;\n\tfont-size: 0.8em;\n\tdisplay: block\n}\n\nform.purchase li.field>div span.info {\n\tfont-size: 0.75em;\n\tline-height: 1.3em;\n\tdisplay: block\n}\n\ntd.total {\n\tfont-size: 1.1em\n}\n\ntable.checkout {\n\twidth: 100%\n}\n\ntable.checkout td {\n\tpadding: 10px\n}\n\ntable.checkout tr.product {\n\tborder-top: 1px solid #ccc;\n\tborder-bottom: 1px solid #ccc\n}\n\ntable.checkout td.right {\n\ttext-align: right\n}\n\nimg.progression {\n\tmargin-bottom: 0.5em\n}\n\nbutton.paymentButton {\n\tfloat: right;\n\tmargin-right: 0;\n\twidth: 180px;\n\theight: 45px;\n\twhite-space: nowrap\n}\n\nbutton.paymentButton img {\n\tvertical-align: middle\n}\n\ndiv.news {\n\tdisplay: flex;\n\tflex-direction: column;\n\t-ms-flex-direction: row;\n\tflex-wrap: wrap;\n\tmax-height: 735px;\n\tmargin-top: 1em\n}\n\ndiv.news>div {\n\tbackground: white;\n\twidth: 32.5%;\n\tmargin: 3px;\n\tbox-sizing: border-box;\n\tpadding: 1em\n}\n\ndiv.news>div.external a {\n\tbackground: url(../images/external-site.gif) no-repeat right top\n}\n\ndiv.news>div a {\n\tdisplay: block;\n\tcolor: inherit\n}\n\ndiv.news>div a:hover {\n\ttext-decoration: none\n}\n\ndiv.news>div p {\n\tcolor: grey;\n\tline-height: 1.5em;\n\tmargin-top: 0.5em\n}\n\ndiv.news>div h4 {\n\tfont-size: 1em;\n\tfont-weight: bold;\n\tmargin: 0\n}\n\ndiv.news>div h5 {\n\tfont-size: 0.9em;\n\tmargin: 0;\n\tcolor: grey\n}\n\ndiv.site-news {\n\tposition: absolute;\n\tz-index: 20;\n\ttop: 1em;\n\tleft: 17em;\n\twidth: 72%;\n\tpadding: 0.5em;\n\tborder: 1px solid #ccc;\n\tbackground: rgba(150,150,150,0.1);\n\tborder-radius: 0.25em;\n\t-webkit-box-sizing: border-box;\n\t-moz-box-sizing: border-box;\n\tbox-sizing: border-box\n}\n\ndiv.site-news div {\n\tfont-size: 0.8em;\n\tline-height: 1.45em\n}\n\n@media only screen and (max-width: 959px) {\n\tdiv.site-news {\n\t\tdisplay: none\n\t}\n}\n\ndiv.notice {\n\tfont-size: 0.9em;\n\tline-height: 1.45em;\n\tmargin: 1em;\n\tbox-shadow: 2px 2px 6px rgba(0,0,0,0.2);\n\tborder: 1px solid #CCC;\n\tbackground-color: #F9F9F9;\n\tpadding: 1em;\n\tborder-radius: 0.25em\n}\n\n@media only screen and (max-width: 700px) {\n\t#searchResults {\n\t\tdisplay: none\n\t}\n}\n\n#searchResults {\n\tposition: absolute;\n\ttop: 100px;\n\tleft: 0;\n\tright: 0;\n\tz-index: 9;\n\tmargin: 0 auto;\n\tmax-width: 1100px;\n\tbox-shadow: 3px 3px 15px rgba(0,0,0,0.5);\n\ttransition: opacity 0.25s linear;\n\toverflow: auto;\n\tdisplay: none;\n\topacity: 0;\n\tbackground: white;\n\tborder-radius: 3px\n}\n\n#searchResults div.info {\n\tpadding: 1em 2em;\n\tbackground: #458ae0;\n\tcolor: white;\n\tbottom: 0;\n\tbox-sizing: border-box;\n\tmargin-bottom: 0\n}\n\n#searchResults div.info h2 {\n\tfont-size: 16px;\n\tmargin: 0\n}\n\n#searchResults div.info div {\n\tfloat: right\n}\n\n#searchResults div.info a {\n\tcolor: white;\n\ttext-decoration: underline\n}\n\n#searchResults div.resultsWrapper {\n\tmax-height: 500px;\n\toverflow: auto\n}\n\n#searchBg {\n\tposition: fixed;\n\ttop: 70px;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tbackground: linear-gradient(to bottom, transparent 0%, rgba(0,0,0,0.3) 30%);\n\tcontent: \"\";\n\topacity: 0;\n\tdisplay: none;\n\ttransition: opacity 0.25s linear;\n\tz-index: 7\n}\n\n#searchResults div.results,#searchResultsStatic div.results {\n\tdisplay: flex\n}\n\n#searchResults div.search-column,#searchResultsStatic div.search-column {\n\tflex: auto;\n\twidth: 50%;\n\tpadding-bottom: 1em;\n\tbox-sizing: border-box\n}\n\n#searchResults div.search-column:first-child,#searchResultsStatic div.search-column:first-child {\n\tborder-right: 1px solid rgba(0,0,0,0.1)\n}\n\n#searchResults div.forum-order,#searchResultsStatic div.forum-order {\n\tfloat: right;\n\tpadding: 1.8em 2.2em 0 0;\n\tfont-size: 12px\n}\n\n#searchResults div.forum-order button,#searchResultsStatic div.forum-order button {\n\tborder: none;\n\tbackground-color: transparent;\n\tmargin: 0 0.25em;\n\tborder-bottom: 2px solid #f9f9f9\n}\n\n#searchResults div.forum-order button:focus,#searchResultsStatic div.forum-order button:focus {\n\toutline: none\n}\n\n#searchResults div.forum-order button.selected,#searchResultsStatic div.forum-order button.selected {\n\tborder-bottom: 2px solid #458ae0\n}\n\n#searchResults h3,#searchResultsStatic h3 {\n\tfont-size: 1.3em;\n\tpadding: 1em 1.45em 0.5em;\n\tmargin: 0;\n\tcolor: #458ae0;\n\tborder-top: 1px solid rgba(0,0,0,0.1)\n}\n\n#searchResults li,#searchResultsStatic li {\n\tdisplay: block;\n\tborder-top: 2px solid transparent;\n\tborder-bottom: 2px solid transparent;\n\tpadding: 0.7em 2em\n}\n\n#searchResults li.active,#searchResultsStatic li.active {\n\tborder-top: 2px solid #458ae0;\n\tborder-bottom: 2px solid #458ae0;\n\tbackground-color: #ecf0f5\n}\n\n#searchResults li a,#searchResultsStatic li a {\n\tcolor: inherit\n}\n\n#searchResults li a:hover,#searchResultsStatic li a:hover {\n\ttext-decoration: none\n}\n\n#searchResults li a div.title,#searchResults li a div.content,#searchResultsStatic li a div.title,#searchResultsStatic li a div.content {\n\twhite-space: nowrap;\n\ttext-overflow: ellipsis;\n\toverflow: hidden\n}\n\n#searchResults li a div.content,#searchResultsStatic li a div.content {\n\tcolor: #666;\n\tfont-size: 0.8em;\n\tmargin: 0\n}\n\n#searchResults li a span.date,#searchResultsStatic li a span.date {\n\tfloat: right;\n\tfont-size: 0.8em\n}\n\n#searchResults li em,#searchResultsStatic li em {\n\tfont-style: normal;\n\tborder-bottom: 2px solid #458ae0\n}\n\n#searchResultsStatic li:hover {\n\tborder-top: 2px solid #458ae0;\n\tborder-bottom: 2px solid #458ae0;\n\tbackground-color: #ecf0f5\n}\n\n#searchResultsStatic div.results {\n\tdisplay: block\n}\n\n#searchResultsStatic div.searchPaging {\n\tmargin: 1em auto 0 auto;\n\twhite-space: nowrap;\n\ttext-align: center\n}\n\n#searchResultsStatic div.searchPaging ul li {\n\tborder: none;\n\tdisplay: inline-block;\n\tpadding: 0\n}\n\n#searchResultsStatic div.searchPaging ul li.active {\n\tbackground: #f0f0f0\n}\n\n#searchResultsStatic div.searchPaging ul li.active a {\n\tcolor: black;\n\tbackground: #f0f0f0\n}\n\n#searchResultsStatic div.searchPaging ul li.disabled a {\n\tcolor: #aaa\n}\n\n#searchResultsStatic div.searchPaging ul li a {\n\tpadding: 0.5em 1em;\n\tborder: 1px solid #ccc;\n\tborder-radius: 4px\n}"
  },
  {
    "path": "static/css/datatables/jquery.dataTables.css",
    "content": "/*\n * Table styles\n */\n table.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: collapse;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n  outline: none;\n}\ntable.dataTable thead th,\ntable.dataTable thead td {\n  padding: 10px 18px !important;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 10px 18px 6px 18px;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc {\n  cursor: pointer;\n  *cursor: hand;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"../../images/tab/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"../../images/tab/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"../../images/tab/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"../../images/tab/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"../../images/tab/sort_desc_disabled.png\");\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 18px !important;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #abb9d3;\n}\ntable.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n  background-color: whitesmoke;\n}\ntable.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n  background-color: #a9b7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #f9f9f9;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad4;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b3cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a7b5ce;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b6d0;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #f9f9f9;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fbfbfb;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fdfdfd;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad4;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #adbbd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n  background-color: #ebebeb;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n  background-color: #eeeeee;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n  background-color: #a1aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n  background-color: #a2afc8;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n  background-color: #a4b2cb;\n}\ntable.dataTable.no-footer {\n  border-bottom: 1px solid #111;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 4px 17px 4px 4px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 4px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  -webkit-box-sizing: content-box;\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left; margin-left: 15px;\n  margin-top: 5px;\n}\n.dataTables_length {\n\tpadding-top: 0.755em;\n}\n.dataTables_info{margin-top:10px;}\n.dataTables_length label{font-weight: normal;}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n\n/*源自dataTables.bootstrap.min.css*/\n.dataTables_wrapper .dataTables_filter label {\n\tfont-weight: normal;\n\twhite-space: nowrap;\n\ttext-align: left\n}\n\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n  display: inline-block;\n  width: auto\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.755em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n  padding-top: 0.25em;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  box-sizing: border-box;\n  min-width: 1.5em;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n  outline: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  color: #333 !important;\n  border: 1px solid #cacaca;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n  cursor: default;\n  color: #666 !important;\n  border: 1px solid transparent;\n  background: transparent;\n  box-shadow: none;\n  outline: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  outline: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  outline: none;\n  \n}\n.pagination>li:active,\n.pagination>li>a:active{\n\toutline: none !important;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {\n  height: 0;\n  overflow: hidden;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: 1px solid #111;\n}\n.dataTables_wrapper.no-footer div.dataTables_scrollHead table,\n.dataTables_wrapper.no-footer div.dataTables_scrollBody table {\n  border-bottom: none;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em;\n  }\n}\n.p310{padding:2px 10px;}\n.pl0{padding-left: 0px;}\n.rboor{margin-top:-5px;}\n"
  },
  {
    "path": "static/css/datatables/jquery.dataTables.css.origin",
    "content": "/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th,\ntable.dataTable thead td {\n  padding: 10px 18px;\n  border-bottom: 1px solid #111;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 10px 18px 6px 18px;\n  border-top: 1px solid #111;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  cursor: pointer;\n  *cursor: hand;\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"../images/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"../images/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"../images/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"../images/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"../images/sort_desc_disabled.png\");\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #acbad4;\n}\ntable.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n  background-color: #f6f6f6;\n}\ntable.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n  background-color: #aab7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #fafafa;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a8b5cf;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b7d1;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #fafafa;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fcfcfc;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fefefe;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #aebcd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n  background-color: #ececec;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n  background-color: #efefef;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n  background-color: #a2aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n  background-color: #a3b0c9;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n  background-color: #a5b2cb;\n}\ntable.dataTable.no-footer {\n  border-bottom: 1px solid #111;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 4px 17px 4px 4px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 4px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.755em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n  padding-top: 0.25em;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em 1em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n  border-radius: 2px;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  color: #333 !important;\n  border: 1px solid #979797;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n  cursor: default;\n  color: #666 !important;\n  border: 1px solid transparent;\n  background: transparent;\n  box-shadow: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  color: white !important;\n  border: 1px solid #111;\n  background-color: #585858;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #585858 0%, #111 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #585858 0%, #111 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #585858 0%, #111 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #585858 0%, #111 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #585858 0%, #111 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  outline: none;\n  background-color: #2b2b2b;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);\n  /* W3C */\n  box-shadow: inset 0 0 3px #111;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td {\n  vertical-align: middle;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td > div.dataTables_sizing, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td > div.dataTables_sizing {\n  height: 0;\n  overflow: hidden;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: 1px solid #111;\n}\n.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,\n.dataTables_wrapper.no-footer div.dataTables_scrollBody > table {\n  border-bottom: none;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em;\n  }\n}"
  },
  {
    "path": "static/css/datatables.css",
    "content": "/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */ }\n  table.dataTable thead th,\n  table.dataTable tfoot th {\n    font-weight: bold; }\n  table.dataTable thead th,\n  table.dataTable thead td {\n    padding: 10px 18px;\n    border-bottom: 1px solid #111111; }\n    table.dataTable thead th:active,\n    table.dataTable thead td:active {\n      outline: none; }\n  table.dataTable tfoot th,\n  table.dataTable tfoot td {\n    padding: 10px 18px 6px 18px;\n    border-top: 1px solid #111111; }\n  table.dataTable thead .sorting,\n  table.dataTable thead .sorting_asc,\n  table.dataTable thead .sorting_desc,\n  table.dataTable thead .sorting_asc_disabled,\n  table.dataTable thead .sorting_desc_disabled {\n    cursor: pointer;\n    *cursor: hand;\n    background-repeat: no-repeat;\n    background-position: center right; }\n  table.dataTable thead .sorting {\n    background-image: url(\"../images/sort_both.png\"); }\n  table.dataTable thead .sorting_asc {\n    background-image: url(\"../images/sort_asc.png\"); }\n  table.dataTable thead .sorting_desc {\n    background-image: url(\"../images/sort_desc.png\"); }\n  table.dataTable thead .sorting_asc_disabled {\n    background-image: url(\"../images/sort_asc_disabled.png\"); }\n  table.dataTable thead .sorting_desc_disabled {\n    background-image: url(\"../images/sort_desc_disabled.png\"); }\n  table.dataTable tbody tr {\n    background-color: white; }\n    table.dataTable tbody tr.selected {\n      background-color: #b0bed9; }\n  table.dataTable tbody th,\n  table.dataTable tbody td {\n    padding: 8px 10px; }\n  table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n    border-top: 1px solid #dddddd; }\n  table.dataTable.row-border tbody tr:first-child th,\n  table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\n  table.dataTable.display tbody tr:first-child td {\n    border-top: none; }\n  table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n    border-top: 1px solid #dddddd;\n    border-right: 1px solid #dddddd; }\n  table.dataTable.cell-border tbody tr th:first-child,\n  table.dataTable.cell-border tbody tr td:first-child {\n    border-left: 1px solid #dddddd; }\n  table.dataTable.cell-border tbody tr:first-child th,\n  table.dataTable.cell-border tbody tr:first-child td {\n    border-top: none; }\n  table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n    background-color: #f9f9f9; }\n    table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n      background-color: #abb9d3; }\n  table.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n    background-color: whitesmoke; }\n    table.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n      background-color: #a9b7d1; }\n  table.dataTable.order-column tbody tr > .sorting_1,\n  table.dataTable.order-column tbody tr > .sorting_2,\n  table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\n  table.dataTable.display tbody tr > .sorting_2,\n  table.dataTable.display tbody tr > .sorting_3 {\n    background-color: #f9f9f9; }\n  table.dataTable.order-column tbody tr.selected > .sorting_1,\n  table.dataTable.order-column tbody tr.selected > .sorting_2,\n  table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\n  table.dataTable.display tbody tr.selected > .sorting_2,\n  table.dataTable.display tbody tr.selected > .sorting_3 {\n    background-color: #acbad4; }\n  table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n    background-color: #f1f1f1; }\n  table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n    background-color: #f3f3f3; }\n  table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n    background-color: whitesmoke; }\n  table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n    background-color: #a6b3cd; }\n  table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n    background-color: #a7b5ce; }\n  table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n    background-color: #a9b6d0; }\n  table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n    background-color: #f9f9f9; }\n  table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n    background-color: #fbfbfb; }\n  table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n    background-color: #fdfdfd; }\n  table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n    background-color: #acbad4; }\n  table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n    background-color: #adbbd6; }\n  table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n    background-color: #afbdd8; }\n  table.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n    background-color: #eaeaea; }\n  table.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n    background-color: #ebebeb; }\n  table.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n    background-color: #eeeeee; }\n  table.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n    background-color: #a1aec7; }\n  table.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n    background-color: #a2afc8; }\n  table.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n    background-color: #a4b2cb; }\n  table.dataTable.no-footer {\n    border-bottom: 1px solid #111111; }\n  table.dataTable.nowrap th, table.dataTable.nowrap td {\n    white-space: nowrap; }\n  table.dataTable.compact thead th,\n  table.dataTable.compact thead td {\n    padding: 4px 17px 4px 4px; }\n  table.dataTable.compact tfoot th,\n  table.dataTable.compact tfoot td {\n    padding: 4px; }\n  table.dataTable.compact tbody th,\n  table.dataTable.compact tbody td {\n    padding: 4px; }\n  table.dataTable th.dt-left,\n  table.dataTable td.dt-left {\n    text-align: left; }\n  table.dataTable th.dt-center,\n  table.dataTable td.dt-center,\n  table.dataTable td.dataTables_empty {\n    text-align: center; }\n  table.dataTable th.dt-right,\n  table.dataTable td.dt-right {\n    text-align: right; }\n  table.dataTable th.dt-justify,\n  table.dataTable td.dt-justify {\n    text-align: justify; }\n  table.dataTable th.dt-nowrap,\n  table.dataTable td.dt-nowrap {\n    white-space: nowrap; }\n  table.dataTable thead th.dt-head-left,\n  table.dataTable thead td.dt-head-left,\n  table.dataTable tfoot th.dt-head-left,\n  table.dataTable tfoot td.dt-head-left {\n    text-align: left; }\n  table.dataTable thead th.dt-head-center,\n  table.dataTable thead td.dt-head-center,\n  table.dataTable tfoot th.dt-head-center,\n  table.dataTable tfoot td.dt-head-center {\n    text-align: center; }\n  table.dataTable thead th.dt-head-right,\n  table.dataTable thead td.dt-head-right,\n  table.dataTable tfoot th.dt-head-right,\n  table.dataTable tfoot td.dt-head-right {\n    text-align: right; }\n  table.dataTable thead th.dt-head-justify,\n  table.dataTable thead td.dt-head-justify,\n  table.dataTable tfoot th.dt-head-justify,\n  table.dataTable tfoot td.dt-head-justify {\n    text-align: justify; }\n  table.dataTable thead th.dt-head-nowrap,\n  table.dataTable thead td.dt-head-nowrap,\n  table.dataTable tfoot th.dt-head-nowrap,\n  table.dataTable tfoot td.dt-head-nowrap {\n    white-space: nowrap; }\n  table.dataTable tbody th.dt-body-left,\n  table.dataTable tbody td.dt-body-left {\n    text-align: left; }\n  table.dataTable tbody th.dt-body-center,\n  table.dataTable tbody td.dt-body-center {\n    text-align: center; }\n  table.dataTable tbody th.dt-body-right,\n  table.dataTable tbody td.dt-body-right {\n    text-align: right; }\n  table.dataTable tbody th.dt-body-justify,\n  table.dataTable tbody td.dt-body-justify {\n    text-align: justify; }\n  table.dataTable tbody th.dt-body-nowrap,\n  table.dataTable tbody td.dt-body-nowrap {\n    white-space: nowrap; }\n \ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  box-sizing: content-box; }\n \n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1; }\n  .dataTables_wrapper .dataTables_length {\n    float: left; }\n  .dataTables_wrapper .dataTables_filter {\n    float: right;\n    text-align: right; }\n    .dataTables_wrapper .dataTables_filter input {\n      margin-left: 0.5em; }\n  .dataTables_wrapper .dataTables_info {\n    clear: both;\n    float: left;\n    padding-top: 0.755em; }\n  .dataTables_wrapper .dataTables_paginate {\n    float: right;\n    text-align: right;\n    padding-top: 0.25em; }\n    .dataTables_wrapper .dataTables_paginate .paginate_button {\n      box-sizing: border-box;\n      display: inline-block;\n      min-width: 1.5em;\n      padding: 0.5em 1em;\n      margin-left: 2px;\n      text-align: center;\n      text-decoration: none !important;\n      cursor: pointer;\n      *cursor: hand;\n      color: #333333 !important;\n      border: 1px solid transparent;\n      border-radius: 2px; }\n      .dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n        color: #333333 !important;\n        border: 1px solid #979797;\n        background-color: white;\n        background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, gainsboro));\n        /* Chrome,Safari4+ */\n        background: -webkit-linear-gradient(top, white 0%, gainsboro 100%);\n        /* Chrome10+,Safari5.1+ */\n        background: -moz-linear-gradient(top, white 0%, gainsboro 100%);\n        /* FF3.6+ */\n        background: -ms-linear-gradient(top, white 0%, gainsboro 100%);\n        /* IE10+ */\n        background: -o-linear-gradient(top, white 0%, gainsboro 100%);\n        /* Opera 11.10+ */\n        background: linear-gradient(to bottom, white 0%, gainsboro 100%);\n        /* W3C */ }\n      .dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n        cursor: default;\n        color: #666 !important;\n        border: 1px solid transparent;\n        background: transparent;\n        box-shadow: none; }\n      .dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n        color: white !important;\n        border: 1px solid #111111;\n        background-color: #585858;\n        background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111111));\n        /* Chrome,Safari4+ */\n        background: -webkit-linear-gradient(top, #585858 0%, #111111 100%);\n        /* Chrome10+,Safari5.1+ */\n        background: -moz-linear-gradient(top, #585858 0%, #111111 100%);\n        /* FF3.6+ */\n        background: -ms-linear-gradient(top, #585858 0%, #111111 100%);\n        /* IE10+ */\n        background: -o-linear-gradient(top, #585858 0%, #111111 100%);\n        /* Opera 11.10+ */\n        background: linear-gradient(to bottom, #585858 0%, #111111 100%);\n        /* W3C */ }\n      .dataTables_wrapper .dataTables_paginate .paginate_button:active {\n        outline: none;\n        background-color: #2b2b2b;\n        background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));\n        /* Chrome,Safari4+ */\n        background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n        /* Chrome10+,Safari5.1+ */\n        background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n        /* FF3.6+ */\n        background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n        /* IE10+ */\n        background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n        /* Opera 11.10+ */\n        background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);\n        /* W3C */\n        box-shadow: inset 0 0 3px #111; }\n    .dataTables_wrapper .dataTables_paginate .ellipsis {\n      padding: 0 1em; }\n  .dataTables_wrapper .dataTables_processing {\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    width: 100%;\n    height: 40px;\n    margin-left: -50%;\n    margin-top: -25px;\n    padding-top: 20px;\n    text-align: center;\n    font-size: 1.2em;\n    background-color: white;\n    background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n    background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n    background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n    background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n    background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n    background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%); }\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter,\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_processing,\n  .dataTables_wrapper .dataTables_paginate {\n    color: #333333; }\n  .dataTables_wrapper .dataTables_scroll {\n    clear: both; }\n    .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n      *margin-top: -1px;\n      -webkit-overflow-scrolling: touch; }\n      .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td {\n        vertical-align: middle; }\n      .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th > div.dataTables_sizing,\n      .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td > div.dataTables_sizing, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th > div.dataTables_sizing,\n      .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td > div.dataTables_sizing {\n        height: 0;\n        overflow: hidden;\n        margin: 0 !important;\n        padding: 0 !important; }\n  .dataTables_wrapper.no-footer .dataTables_scrollBody {\n    border-bottom: 1px solid #111111; }\n  .dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,\n  .dataTables_wrapper.no-footer div.dataTables_scrollBody > table {\n    border-bottom: none; }\n  .dataTables_wrapper:after {\n    visibility: hidden;\n    display: block;\n    content: \"\";\n    clear: both;\n    height: 0; }\n \n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center; }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em; } }\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center; }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em; } }"
  },
  {
    "path": "static/css/fonts.css",
    "content": "/* cyrillic-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 300;\n  src: local('Roboto Light'), local('Roboto-Light'), url(http://fontstatic.useso.com/s/roboto/v15/0eC6fl06luXEYWpBSJvXCBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');\n  unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;\n}\n/* cyrillic */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 300;\n  src: local('Roboto Light'), local('Roboto-Light'), url(http://fontstatic.useso.com/s/roboto/v15/Fl4y0QdOxyyTHEGMXX8kcRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');\n  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 300;\n  src: local('Roboto Light'), local('Roboto-Light'), url(http://fontstatic.useso.com/s/roboto/v15/-L14Jk06m6pUHB-5mXQQnRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');\n  unicode-range: U+1F00-1FFF;\n}\n/* greek */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 300;\n  src: local('Roboto Light'), local('Roboto-Light'), url(http://fontstatic.useso.com/s/roboto/v15/I3S1wsgSg9YCurV6PUkTORJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');\n  unicode-range: U+0370-03FF;\n}\n/* vietnamese */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 300;\n  src: local('Roboto Light'), local('Roboto-Light'), url(http://fontstatic.useso.com/s/roboto/v15/NYDWBdD4gIq26G5XYbHsFBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');\n  unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;\n}\n/* latin-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 300;\n  src: local('Roboto Light'), local('Roboto-Light'), url(http://fontstatic.useso.com/s/roboto/v15/Pru33qjShpZSmG3z6VYwnRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');\n  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 300;\n  src: local('Roboto Light'), local('Roboto-Light'), url(http://fontstatic.useso.com/s/roboto/v15/Hgo13k-tfSpn0qi1SFdUfVtXRa8TVwTICgirnJhmVJw.woff2) format('woff2');\n  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;\n}\n/* cyrillic-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Roboto'), local('Roboto-Regular'), url(http://fontstatic.useso.com/s/roboto/v15/ek4gzZ-GeXAPcSbHtCeQI_esZW2xOQ-xsNqO47m55DA.woff2) format('woff2');\n  unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;\n}\n/* cyrillic */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Roboto'), local('Roboto-Regular'), url(http://fontstatic.useso.com/s/roboto/v15/mErvLBYg_cXG3rLvUsKT_fesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');\n  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Roboto'), local('Roboto-Regular'), url(http://fontstatic.useso.com/s/roboto/v15/-2n2p-_Y08sg57CNWQfKNvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');\n  unicode-range: U+1F00-1FFF;\n}\n/* greek */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Roboto'), local('Roboto-Regular'), url(http://fontstatic.useso.com/s/roboto/v15/u0TOpm082MNkS5K0Q4rhqvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');\n  unicode-range: U+0370-03FF;\n}\n/* vietnamese */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Roboto'), local('Roboto-Regular'), url(http://fontstatic.useso.com/s/roboto/v15/NdF9MtnOpLzo-noMoG0miPesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');\n  unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;\n}\n/* latin-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Roboto'), local('Roboto-Regular'), url(http://fontstatic.useso.com/s/roboto/v15/Fcx7Wwv8OzT71A3E1XOAjvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');\n  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Roboto'), local('Roboto-Regular'), url(http://fontstatic.useso.com/s/roboto/v15/CWB0XYA8bzo0kSThX0UTuA.woff2) format('woff2');\n  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;\n}\n/* cyrillic-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 700;\n  src: local('Roboto Bold'), local('Roboto-Bold'), url(http://fontstatic.useso.com/s/roboto/v15/77FXFjRbGzN4aCrSFhlh3hJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');\n  unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;\n}\n/* cyrillic */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 700;\n  src: local('Roboto Bold'), local('Roboto-Bold'), url(http://fontstatic.useso.com/s/roboto/v15/isZ-wbCXNKAbnjo6_TwHThJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');\n  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 700;\n  src: local('Roboto Bold'), local('Roboto-Bold'), url(http://fontstatic.useso.com/s/roboto/v15/UX6i4JxQDm3fVTc1CPuwqhJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');\n  unicode-range: U+1F00-1FFF;\n}\n/* greek */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 700;\n  src: local('Roboto Bold'), local('Roboto-Bold'), url(http://fontstatic.useso.com/s/roboto/v15/jSN2CGVDbcVyCnfJfjSdfBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');\n  unicode-range: U+0370-03FF;\n}\n/* vietnamese */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 700;\n  src: local('Roboto Bold'), local('Roboto-Bold'), url(http://fontstatic.useso.com/s/roboto/v15/PwZc-YbIL414wB9rB1IAPRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');\n  unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;\n}\n/* latin-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 700;\n  src: local('Roboto Bold'), local('Roboto-Bold'), url(http://fontstatic.useso.com/s/roboto/v15/97uahxiqZRoncBaCEI3aWxJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');\n  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 700;\n  src: local('Roboto Bold'), local('Roboto-Bold'), url(http://fontstatic.useso.com/s/roboto/v15/d-6IYplOFocCacKzxwXSOFtXRa8TVwTICgirnJhmVJw.woff2) format('woff2');\n  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;\n}\n/* cyrillic-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: italic;\n  font-weight: 300;\n  src: local('Roboto Light Italic'), local('Roboto-LightItalic'), url(http://fontstatic.useso.com/s/roboto/v15/7m8l7TlFO-S3VkhHuR0atzTOQ_MqJVwkKsUn0wKzc2I.woff2) format('woff2');\n  unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;\n}\n/* cyrillic */\n@font-face {\n  font-family: 'Roboto';\n  font-style: italic;\n  font-weight: 300;\n  src: local('Roboto Light Italic'), local('Roboto-LightItalic'), url(http://fontstatic.useso.com/s/roboto/v15/7m8l7TlFO-S3VkhHuR0atzUj_cnvWIuuBMVgbX098Mw.woff2) format('woff2');\n  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: italic;\n  font-weight: 300;\n  src: local('Roboto Light Italic'), local('Roboto-LightItalic'), url(http://fontstatic.useso.com/s/roboto/v15/7m8l7TlFO-S3VkhHuR0at0bcKLIaa1LC45dFaAfauRA.woff2) format('woff2');\n  unicode-range: U+1F00-1FFF;\n}\n/* greek */\n@font-face {\n  font-family: 'Roboto';\n  font-style: italic;\n  font-weight: 300;\n  src: local('Roboto Light Italic'), local('Roboto-LightItalic'), url(http://fontstatic.useso.com/s/roboto/v15/7m8l7TlFO-S3VkhHuR0at2o_sUJ8uO4YLWRInS22T3Y.woff2) format('woff2');\n  unicode-range: U+0370-03FF;\n}\n/* vietnamese */\n@font-face {\n  font-family: 'Roboto';\n  font-style: italic;\n  font-weight: 300;\n  src: local('Roboto Light Italic'), local('Roboto-LightItalic'), url(http://fontstatic.useso.com/s/roboto/v15/7m8l7TlFO-S3VkhHuR0at76up8jxqWt8HVA3mDhkV_0.woff2) format('woff2');\n  unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;\n}\n/* latin-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: italic;\n  font-weight: 300;\n  src: local('Roboto Light Italic'), local('Roboto-LightItalic'), url(http://fontstatic.useso.com/s/roboto/v15/7m8l7TlFO-S3VkhHuR0atyYE0-AqJ3nfInTTiDXDjU4.woff2) format('woff2');\n  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n  font-family: 'Roboto';\n  font-style: italic;\n  font-weight: 300;\n  src: local('Roboto Light Italic'), local('Roboto-LightItalic'), url(http://fontstatic.useso.com/s/roboto/v15/7m8l7TlFO-S3VkhHuR0at44P5ICox8Kq3LLUNMylGO4.woff2) format('woff2');\n  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;\n}\n/* cyrillic-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: italic;\n  font-weight: 400;\n  src: local('Roboto Italic'), local('Roboto-Italic'), url(http://fontstatic.useso.com/s/roboto/v15/WxrXJa0C3KdtC7lMafG4dRTbgVql8nDJpwnrE27mub0.woff2) format('woff2');\n  unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;\n}\n/* cyrillic */\n@font-face {\n  font-family: 'Roboto';\n  font-style: italic;\n  font-weight: 400;\n  src: local('Roboto Italic'), local('Roboto-Italic'), url(http://fontstatic.useso.com/s/roboto/v15/OpXUqTo0UgQQhGj_SFdLWBTbgVql8nDJpwnrE27mub0.woff2) format('woff2');\n  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: italic;\n  font-weight: 400;\n  src: local('Roboto Italic'), local('Roboto-Italic'), url(http://fontstatic.useso.com/s/roboto/v15/1hZf02POANh32k2VkgEoUBTbgVql8nDJpwnrE27mub0.woff2) format('woff2');\n  unicode-range: U+1F00-1FFF;\n}\n/* greek */\n@font-face {\n  font-family: 'Roboto';\n  font-style: italic;\n  font-weight: 400;\n  src: local('Roboto Italic'), local('Roboto-Italic'), url(http://fontstatic.useso.com/s/roboto/v15/cDKhRaXnQTOVbaoxwdOr9xTbgVql8nDJpwnrE27mub0.woff2) format('woff2');\n  unicode-range: U+0370-03FF;\n}\n/* vietnamese */\n@font-face {\n  font-family: 'Roboto';\n  font-style: italic;\n  font-weight: 400;\n  src: local('Roboto Italic'), local('Roboto-Italic'), url(http://fontstatic.useso.com/s/roboto/v15/K23cxWVTrIFD6DJsEVi07RTbgVql8nDJpwnrE27mub0.woff2) format('woff2');\n  unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;\n}\n/* latin-ext */\n@font-face {\n  font-family: 'Roboto';\n  font-style: italic;\n  font-weight: 400;\n  src: local('Roboto Italic'), local('Roboto-Italic'), url(http://fontstatic.useso.com/s/roboto/v15/vSzulfKSK0LLjjfeaxcREhTbgVql8nDJpwnrE27mub0.woff2) format('woff2');\n  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n  font-family: 'Roboto';\n  font-style: italic;\n  font-weight: 400;\n  src: local('Roboto Italic'), local('Roboto-Italic'), url(http://fontstatic.useso.com/s/roboto/v15/vPcynSL0qHq_6dX7lKVByfesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');\n  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;\n}"
  },
  {
    "path": "static/css/helper.css",
    "content": "/*  font  */\n\n/*  font size */\n\n.f-s-1 {font-size: 1px!important;}\n.f-s-2 {font-size: 2px!important;}\n.f-s-3 {font-size: 3px!important;}\n.f-s-4 {font-size: 4px!important;}\n.f-s-5 {font-size: 5px!important;}\n.f-s-6 {font-size: 6px!important;}\n.f-s-7 {font-size: 7px!important;}\n.f-s-8 {font-size: 8px!important;}\n.f-s-9 {font-size: 9px!important;}\n.f-s-10 {font-size: 10px!important;}\n.f-s-11 {font-size: 11px!important;}\n.f-s-12 {font-size: 12px!important;}\n.f-s-13 {font-size: 13px!important;}\n.f-s-14 {font-size: 14px!important;}\n.f-s-15 {font-size: 15px!important;}\n.f-s-16 {font-size: 16px!important;}\n.f-s-17 {font-size: 17px!important;}\n.f-s-18 {font-size: 18px!important;}\n.f-s-19 {font-size: 19px!important;}\n.f-s-20 {font-size: 20px!important;}\n.f-s-21 {font-size: 21px!important;}\n.f-s-22 {font-size: 22px!important;}\n.f-s-23 {font-size: 23px!important;}\n.f-s-24 {font-size: 24px!important;}\n.f-s-25 {font-size: 25px!important;}\n.f-s-26 {font-size: 26px!important;}\n.f-s-27 {font-size: 27px!important;}\n.f-s-28 {font-size: 28px!important;}\n.f-s-29 {font-size: 29px!important;}\n.f-s-30 {font-size: 30px!important;}\n.f-s-31 {font-size: 31px!important;}\n.f-s-32 {font-size: 32px!important;}\n.f-s-33 {font-size: 33px!important;}\n.f-s-34 {font-size: 34px!important;}\n.f-s-35 {font-size: 35px!important;}\n.f-s-36 {font-size: 36px!important;}\n.f-s-37 {font-size: 37px!important;}\n.f-s-38 {font-size: 38px!important;}\n.f-s-39 {font-size: 39px!important;}\n.f-s-40 {font-size: 40px!important;}\n.f-s-41 {font-size: 41px!important;}\n.f-s-42 {font-size: 42px!important;}\n.f-s-43 {font-size: 43px!important;}\n.f-s-44 {font-size: 44px!important;}\n.f-s-45 {font-size: 45px!important;}\n.f-s-46 {font-size: 46px!important;}\n.f-s-47 {font-size: 47px!important;}\n.f-s-48 {font-size: 48px!important;}\n.f-s-49 {font-size: 49px!important;}\n.f-s-50 {font-size: 50px!important;}\n.f-s-51 {font-size: 51px!important;}\n.f-s-52 {font-size: 52px!important;}\n.f-s-53 {font-size: 53px!important;}\n.f-s-54 {font-size: 54px!important;}\n.f-s-55 {font-size: 55px!important;}\n.f-s-56 {font-size: 56px!important;}\n.f-s-57 {font-size: 57px!important;}\n.f-s-58 {font-size: 58px!important;}\n.f-s-59 {font-size: 59px!important;}\n.f-s-60 {font-size: 60px!important;}\n.f-s-61 {font-size: 61px!important;}\n.f-s-62 {font-size: 62px!important;}\n.f-s-63 {font-size: 63px!important;}\n.f-s-64 {font-size: 64px!important;}\n.f-s-65 {font-size: 65px!important;}\n.f-s-66 {font-size: 66px!important;}\n.f-s-67 {font-size: 67px!important;}\n.f-s-68 {font-size: 68px!important;}\n.f-s-69 {font-size: 69px!important;}\n.f-s-70 {font-size: 70px!important;}\n.f-s-71 {font-size: 71px!important;}\n.f-s-72 {font-size: 72px!important;}\n.f-s-73 {font-size: 73px!important;}\n.f-s-74 {font-size: 74px!important;}\n.f-s-75 {font-size: 75px!important;}\n.f-s-76 {font-size: 76px!important;}\n.f-s-77 {font-size: 77px!important;}\n.f-s-78 {font-size: 78px!important;}\n.f-s-79 {font-size: 79px!important;}\n.f-s-80 {font-size: 80px!important;}\n.f-s-81 {font-size: 81px!important;}\n.f-s-82 {font-size: 82px!important;}\n.f-s-83 {font-size: 83px!important;}\n.f-s-84 {font-size: 84px!important;}\n.f-s-85 {font-size: 85px!important;}\n.f-s-86 {font-size: 86px!important;}\n.f-s-87 {font-size: 87px!important;}\n.f-s-88 {font-size: 88px!important;}\n.f-s-89 {font-size: 89px!important;}\n.f-s-90 {font-size: 90px!important;}\n.f-s-91 {font-size: 91px!important;}\n.f-s-92 {font-size: 92px!important;}\n.f-s-93 {font-size: 93px!important;}\n.f-s-94 {font-size: 94px!important;}\n.f-s-95 {font-size: 95px!important;}\n.f-s-96 {font-size: 96px!important;}\n.f-s-97 {font-size: 97px!important;}\n.f-s-98 {font-size: 98px!important;}\n.f-s-99 {font-size: 99px!important;}\n.f-s-100 {font-size: 100px!important;}\n\n/*   font weight */\n\n.f-w-100 {font-weight: 100}\n.f-w-200 {font-weight: 200}\n.f-w-300 {font-weight: 300}\n.f-w-400 {font-weight: 400}\n.f-w-500 {font-weight: 500}\n.f-w-600 {font-weight: 600}\n.f-w-700 {font-weight: 700}\n.f-w-800 {font-weight: 800}\n.f-w-900 {font-weight: 900}\n\n\n/*   margin  */\n\n.m-0 {margin: 0px!important;}\n\n/*   margin top  */\n\n.m-t-0 {margin-top: 0px!important;}\n.m-t-1 {margin-top: 1px!important;}\n.m-t-2 {margin-top: 2px!important;}\n.m-t-3 {margin-top: 3px!important;}\n.m-t-4 {margin-top: 4px!important;}\n.m-t-5 {margin-top: 5px!important;}\n.m-t-6 {margin-top: 6px!important;}\n.m-t-7 {margin-top: 7px!important;}\n.m-t-8 {margin-top: 8px!important;}\n.m-t-9 {margin-top: 9px!important;}\n.m-t-10 {margin-top: 10px!important;}\n.m-t-11 {margin-top: 11px!important;}\n.m-t-12 {margin-top: 12px!important;}\n.m-t-13 {margin-top: 13px!important;}\n.m-t-14 {margin-top: 14px!important;}\n.m-t-15 {margin-top: 15px!important;}\n.m-t-16 {margin-top: 16px!important;}\n.m-t-17 {margin-top: 17px!important;}\n.m-t-18 {margin-top: 18px!important;}\n.m-t-19 {margin-top: 19px!important;}\n.m-t-20 {margin-top: 20px!important;}\n.m-t-21 {margin-top: 21px!important;}\n.m-t-22 {margin-top: 22px!important;}\n.m-t-23 {margin-top: 23px!important;}\n.m-t-24 {margin-top: 24px!important;}\n.m-t-25 {margin-top: 25px!important;}\n.m-t-26 {margin-top: 26px!important;}\n.m-t-27 {margin-top: 27px!important;}\n.m-t-28 {margin-top: 28px!important;}\n.m-t-29 {margin-top: 29px!important;}\n.m-t-30 {margin-top: 30px!important;}\n.m-t-31 {margin-top: 31px!important;}\n.m-t-32 {margin-top: 32px!important;}\n.m-t-33 {margin-top: 33px!important;}\n.m-t-34 {margin-top: 34px!important;}\n.m-t-35 {margin-top: 35px!important;}\n.m-t-36 {margin-top: 36px!important;}\n.m-t-37 {margin-top: 37px!important;}\n.m-t-38 {margin-top: 38px!important;}\n.m-t-39 {margin-top: 39px!important;}\n.m-t-40 {margin-top: 40px!important;}\n.m-t-41 {margin-top: 41px!important;}\n.m-t-42 {margin-top: 42px!important;}\n.m-t-43 {margin-top: 43px!important;}\n.m-t-44 {margin-top: 44px!important;}\n.m-t-45 {margin-top: 45px!important;}\n.m-t-46 {margin-top: 46px!important;}\n.m-t-47 {margin-top: 47px!important;}\n.m-t-48 {margin-top: 48px!important;}\n.m-t-49 {margin-top: 49px!important;}\n.m-t-50 {margin-top: 50px!important;}\n.m-t-51 {margin-top: 51px!important;}\n.m-t-52 {margin-top: 52px!important;}\n.m-t-53 {margin-top: 53px!important;}\n.m-t-54 {margin-top: 54px!important;}\n.m-t-55 {margin-top: 55px!important;}\n.m-t-56 {margin-top: 56px!important;}\n.m-t-57 {margin-top: 57px!important;}\n.m-t-58 {margin-top: 58px!important;}\n.m-t-59 {margin-top: 59px!important;}\n.m-t-60 {margin-top: 60px!important;}\n.m-t-61 {margin-top: 61px!important;}\n.m-t-62 {margin-top: 62px!important;}\n.m-t-63 {margin-top: 63px!important;}\n.m-t-64 {margin-top: 64px!important;}\n.m-t-65 {margin-top: 65px!important;}\n.m-t-66 {margin-top: 66px!important;}\n.m-t-67 {margin-top: 67px!important;}\n.m-t-68 {margin-top: 68px!important;}\n.m-t-69 {margin-top: 69px!important;}\n.m-t-70 {margin-top: 70px!important;}\n.m-t-71 {margin-top: 71px!important;}\n.m-t-72 {margin-top: 72px!important;}\n.m-t-73 {margin-top: 73px!important;}\n.m-t-74 {margin-top: 74px!important;}\n.m-t-75 {margin-top: 75px!important;}\n.m-t-76 {margin-top: 76px!important;}\n.m-t-77 {margin-top: 77px!important;}\n.m-t-78 {margin-top: 78px!important;}\n.m-t-79 {margin-top: 79px!important;}\n.m-t-80 {margin-top: 80px!important;}\n.m-t-81 {margin-top: 81px!important;}\n.m-t-82 {margin-top: 82px!important;}\n.m-t-83 {margin-top: 83px!important;}\n.m-t-84 {margin-top: 84px!important;}\n.m-t-85 {margin-top: 85px!important;}\n.m-t-86 {margin-top: 86px!important;}\n.m-t-87 {margin-top: 87px!important;}\n.m-t-88 {margin-top: 88px!important;}\n.m-t-89 {margin-top: 89px!important;}\n.m-t-90 {margin-top: 90px!important;}\n.m-t-91 {margin-top: 91px!important;}\n.m-t-92 {margin-top: 92px!important;}\n.m-t-93 {margin-top: 93px!important;}\n.m-t-94 {margin-top: 94px!important;}\n.m-t-95 {margin-top: 95px!important;}\n.m-t-96 {margin-top: 96px!important;}\n.m-t-97 {margin-top: 97px!important;}\n.m-t-98 {margin-top: 98px!important;}\n.m-t-99 {margin-top: 99px!important;}\n.m-t-100 {margin-top: 100px!important;}\n.m-t-101 {margin-top: 101px!important;}\n.m-t-102 {margin-top: 102px!important;}\n.m-t-103 {margin-top: 103px!important;}\n.m-t-104 {margin-top: 104px!important;}\n.m-t-105 {margin-top: 105px!important;}\n.m-t-106 {margin-top: 106px!important;}\n.m-t-107 {margin-top: 107px!important;}\n.m-t-108 {margin-top: 108px!important;}\n.m-t-109 {margin-top: 109px!important;}\n.m-t-110 {margin-top: 110px!important;}\n.m-t-111 {margin-top: 111px!important;}\n.m-t-112 {margin-top: 112px!important;}\n.m-t-113 {margin-top: 113px!important;}\n.m-t-114 {margin-top: 114px!important;}\n.m-t-115 {margin-top: 115px!important;}\n.m-t-116 {margin-top: 116px!important;}\n.m-t-117 {margin-top: 117px!important;}\n.m-t-118 {margin-top: 118px!important;}\n.m-t-119 {margin-top: 119px!important;}\n.m-t-120 {margin-top: 120px!important;}\n.m-t-121 {margin-top: 121px!important;}\n.m-t-122 {margin-top: 122px!important;}\n.m-t-123 {margin-top: 123px!important;}\n.m-t-124 {margin-top: 124px!important;}\n.m-t-125 {margin-top: 125px!important;}\n.m-t-126 {margin-top: 126px!important;}\n.m-t-127 {margin-top: 127px!important;}\n.m-t-128 {margin-top: 128px!important;}\n.m-t-129 {margin-top: 129px!important;}\n.m-t-130 {margin-top: 130px!important;}\n.m-t-131 {margin-top: 131px!important;}\n.m-t-132 {margin-top: 132px!important;}\n.m-t-133 {margin-top: 133px!important;}\n.m-t-134 {margin-top: 134px!important;}\n.m-t-135 {margin-top: 135px!important;}\n.m-t-136 {margin-top: 136px!important;}\n.m-t-137 {margin-top: 137px!important;}\n.m-t-138 {margin-top: 138px!important;}\n.m-t-139 {margin-top: 139px!important;}\n.m-t-140 {margin-top: 140px!important;}\n.m-t-141 {margin-top: 141px!important;}\n.m-t-142 {margin-top: 142px!important;}\n.m-t-143 {margin-top: 143px!important;}\n.m-t-144 {margin-top: 144px!important;}\n.m-t-145 {margin-top: 145px!important;}\n.m-t-146 {margin-top: 146px!important;}\n.m-t-147 {margin-top: 147px!important;}\n.m-t-148 {margin-top: 148px!important;}\n.m-t-149 {margin-top: 149px!important;}\n.m-t-150 {margin-top: 150px!important;}\n\n\n/*   margin right  */\n\n.m-r-0 {margin-right: 0px!important;}\n.m-r-1 {margin-right: 1px!important;}\n.m-r-2 {margin-right: 2px!important;}\n.m-r-3 {margin-right: 3px!important;}\n.m-r-4 {margin-right: 4px!important;}\n.m-r-5 {margin-right: 5px!important;}\n.m-r-6 {margin-right: 6px!important;}\n.m-r-7 {margin-right: 7px!important;}\n.m-r-8 {margin-right: 8px!important;}\n.m-r-9 {margin-right: 9px!important;}\n.m-r-10 {margin-right: 10px!important;}\n.m-r-11 {margin-right: 11px!important;}\n.m-r-12 {margin-right: 12px!important;}\n.m-r-13 {margin-right: 13px!important;}\n.m-r-14 {margin-right: 14px!important;}\n.m-r-15 {margin-right: 15px!important;}\n.m-r-16 {margin-right: 16px!important;}\n.m-r-17 {margin-right: 17px!important;}\n.m-r-18 {margin-right: 18px!important;}\n.m-r-19 {margin-right: 19px!important;}\n.m-r-20 {margin-right: 20px!important;}\n.m-r-21 {margin-right: 21px!important;}\n.m-r-22 {margin-right: 22px!important;}\n.m-r-23 {margin-right: 23px!important;}\n.m-r-24 {margin-right: 24px!important;}\n.m-r-25 {margin-right: 25px!important;}\n.m-r-26 {margin-right: 26px!important;}\n.m-r-27 {margin-right: 27px!important;}\n.m-r-28 {margin-right: 28px!important;}\n.m-r-29 {margin-right: 29px!important;}\n.m-r-30 {margin-right: 30px!important;}\n.m-r-31 {margin-right: 31px!important;}\n.m-r-32 {margin-right: 32px!important;}\n.m-r-33 {margin-right: 33px!important;}\n.m-r-34 {margin-right: 34px!important;}\n.m-r-35 {margin-right: 35px!important;}\n.m-r-36 {margin-right: 36px!important;}\n.m-r-37 {margin-right: 37px!important;}\n.m-r-38 {margin-right: 38px!important;}\n.m-r-39 {margin-right: 39px!important;}\n.m-r-40 {margin-right: 40px!important;}\n.m-r-41 {margin-right: 4px!important;}\n.m-r-42 {margin-right: 42px!important;}\n.m-r-43 {margin-right: 43px!important;}\n.m-r-44 {margin-right: 44px!important;}\n.m-r-45 {margin-right: 45px!important;}\n.m-r-46 {margin-right: 46px!important;}\n.m-r-47 {margin-right: 47px!important;}\n.m-r-48 {margin-right: 48px!important;}\n.m-r-49 {margin-right: 49px!important;}\n.m-r-50 {margin-right: 50px!important;}\n.m-r-51 {margin-right: 51px!important;}\n.m-r-52 {margin-right: 52px!important;}\n.m-r-53 {margin-right: 53px!important;}\n.m-r-54 {margin-right: 54px!important;}\n.m-r-55 {margin-right: 55px!important;}\n.m-r-56 {margin-right: 56px!important;}\n.m-r-57 {margin-right: 57px!important;}\n.m-r-58 {margin-right: 58px!important;}\n.m-r-59 {margin-right: 59px!important;}\n.m-r-60 {margin-right: 60px!important;}\n.m-r-61 {margin-right: 61px!important;}\n.m-r-62 {margin-right: 62px!important;}\n.m-r-63 {margin-right: 63px!important;}\n.m-r-64 {margin-right: 64px!important;}\n.m-r-65 {margin-right: 65px!important;}\n.m-r-66 {margin-right: 66px!important;}\n.m-r-67 {margin-right: 67px!important;}\n.m-r-68 {margin-right: 68px!important;}\n.m-r-69 {margin-right: 69px!important;}\n.m-r-70 {margin-right: 70px!important;}\n.m-r-71 {margin-right: 71px!important;}\n.m-r-72 {margin-right: 72px!important;}\n.m-r-73 {margin-right: 73px!important;}\n.m-r-74 {margin-right: 74px!important;}\n.m-r-75 {margin-right: 75px!important;}\n.m-r-76 {margin-right: 76px!important;}\n.m-r-77 {margin-right: 77px!important;}\n.m-r-78 {margin-right: 78px!important;}\n.m-r-79 {margin-right: 79px!important;}\n.m-r-80 {margin-right: 80px!important;}\n.m-r-81 {margin-right: 81px!important;}\n.m-r-82 {margin-right: 82px!important;}\n.m-r-83 {margin-right: 83px!important;}\n.m-r-84 {margin-right: 84px!important;}\n.m-r-85 {margin-right: 85px!important;}\n.m-r-86 {margin-right: 86px!important;}\n.m-r-87 {margin-right: 87px!important;}\n.m-r-88 {margin-right: 88px!important;}\n.m-r-89 {margin-right: 89px!important;}\n.m-r-90 {margin-right: 90px!important;}\n.m-r-91 {margin-right: 91px!important;}\n.m-r-92 {margin-right: 92px!important;}\n.m-r-93 {margin-right: 93px!important;}\n.m-r-94 {margin-right: 94px!important;}\n.m-r-95 {margin-right: 95px!important;}\n.m-r-96 {margin-right: 96px!important;}\n.m-r-97 {margin-right: 97px!important;}\n.m-r-98 {margin-right: 98px!important;}\n.m-r-99 {margin-right: 99px!important;}\n.m-r-100 {margin-right: 100px!important;}\n.m-r-101 {margin-right: 101px!important;}\n.m-r-102 {margin-right: 102px!important;}\n.m-r-103 {margin-right: 103px!important;}\n.m-r-104 {margin-right: 104px!important;}\n.m-r-105 {margin-right: 105px!important;}\n.m-r-106 {margin-right: 106px!important;}\n.m-r-107 {margin-right: 107px!important;}\n.m-r-108 {margin-right: 108px!important;}\n.m-r-109 {margin-right: 109px!important;}\n.m-r-110 {margin-right: 110px!important;}\n.m-r-111 {margin-right: 111px!important;}\n.m-r-112 {margin-right: 112px!important;}\n.m-r-113 {margin-right: 113px!important;}\n.m-r-114 {margin-right: 114px!important;}\n.m-r-115 {margin-right: 115px!important;}\n.m-r-116 {margin-right: 116px!important;}\n.m-r-117 {margin-right: 117px!important;}\n.m-r-118 {margin-right: 118px!important;}\n.m-r-119 {margin-right: 119px!important;}\n.m-r-120 {margin-right: 120px!important;}\n.m-r-121 {margin-right: 121px!important;}\n.m-r-122 {margin-right: 122px!important;}\n.m-r-123 {margin-right: 123px!important;}\n.m-r-124 {margin-right: 124px!important;}\n.m-r-125 {margin-right: 125px!important;}\n.m-r-126 {margin-right: 126px!important;}\n.m-r-127 {margin-right: 127px!important;}\n.m-r-128 {margin-right: 128px!important;}\n.m-r-129 {margin-right: 129px!important;}\n.m-r-130 {margin-right: 130px!important;}\n.m-r-131 {margin-right: 131px!important;}\n.m-r-132 {margin-right: 132px!important;}\n.m-r-133 {margin-right: 133px!important;}\n.m-r-134 {margin-right: 134px!important;}\n.m-r-135 {margin-right: 135px!important;}\n.m-r-136 {margin-right: 136px!important;}\n.m-r-137 {margin-right: 137px!important;}\n.m-r-138 {margin-right: 138px!important;}\n.m-r-139 {margin-right: 139px!important;}\n.m-r-140 {margin-right: 140px!important;}\n.m-r-141 {margin-right: 141px!important;}\n.m-r-142 {margin-right: 142px!important;}\n.m-r-143 {margin-right: 143px!important;}\n.m-r-144 {margin-right: 144px!important;}\n.m-r-145 {margin-right: 145px!important;}\n.m-r-146 {margin-right: 146px!important;}\n.m-r-147 {margin-right: 147px!important;}\n.m-r-148 {margin-right: 148px!important;}\n.m-r-149 {margin-right: 149px!important;}\n.m-r-150 {margin-right: 150px!important;}\n\n\n/*   margin bottom  */\n\n.m-b-0 {margin-bottom: 0px!important;}\n.m-b-1 {margin-bottom: 1px!important;}\n.m-b-2 {margin-bottom: 2px!important;}\n.m-b-3 {margin-bottom: 3px!important;}\n.m-b-4 {margin-bottom: 4px!important;}\n.m-b-5 {margin-bottom: 5px!important;}\n.m-b-6 {margin-bottom: 6px!important;}\n.m-b-7 {margin-bottom: 7px!important;}\n.m-b-8 {margin-bottom: 8px!important;}\n.m-b-9 {margin-bottom: 9px!important;}\n.m-b-10 {margin-bottom: 10px!important;}\n.m-b-11 {margin-bottom: 11px!important;}\n.m-b-12 {margin-bottom: 12px!important;}\n.m-b-13 {margin-bottom: 13px!important;}\n.m-b-14 {margin-bottom: 14px!important;}\n.m-b-15 {margin-bottom: 15px!important;}\n.m-b-16 {margin-bottom: 16px!important;}\n.m-b-17 {margin-bottom: 17px!important;}\n.m-b-18 {margin-bottom: 18px!important;}\n.m-b-19 {margin-bottom: 19px!important;}\n.m-b-20 {margin-bottom: 20px!important;}\n.m-b-21 {margin-bottom: 21px!important;}\n.m-b-22 {margin-bottom: 22px!important;}\n.m-b-23 {margin-bottom: 23px!important;}\n.m-b-24 {margin-bottom: 24px!important;}\n.m-b-25 {margin-bottom: 25px!important;}\n.m-b-26 {margin-bottom: 26px!important;}\n.m-b-27 {margin-bottom: 27px!important;}\n.m-b-28 {margin-bottom: 28px!important;}\n.m-b-29 {margin-bottom: 29px!important;}\n.m-b-30 {margin-bottom: 30px!important;}\n.m-b-31 {margin-bottom: 31px!important;}\n.m-b-32 {margin-bottom: 32px!important;}\n.m-b-33 {margin-bottom: 33px!important;}\n.m-b-34 {margin-bottom: 34px!important;}\n.m-b-35 {margin-bottom: 35px!important;}\n.m-b-36 {margin-bottom: 36px!important;}\n.m-b-37 {margin-bottom: 37px!important;}\n.m-b-38 {margin-bottom: 38px!important;}\n.m-b-39 {margin-bottom: 39px!important;}\n.m-b-40 {margin-bottom: 40px!important;}\n.m-b-41 {margin-bottom: 4px!important;}\n.m-b-42 {margin-bottom: 42px!important;}\n.m-b-43 {margin-bottom: 43px!important;}\n.m-b-44 {margin-bottom: 44px!important;}\n.m-b-45 {margin-bottom: 45px!important;}\n.m-b-46 {margin-bottom: 46px!important;}\n.m-b-47 {margin-bottom: 47px!important;}\n.m-b-48 {margin-bottom: 48px!important;}\n.m-b-49 {margin-bottom: 49px!important;}\n.m-b-50 {margin-bottom: 50px!important;}\n.m-b-51 {margin-bottom: 51px!important;}\n.m-b-52 {margin-bottom: 52px!important;}\n.m-b-53 {margin-bottom: 53px!important;}\n.m-b-54 {margin-bottom: 54px!important;}\n.m-b-55 {margin-bottom: 55px!important;}\n.m-b-56 {margin-bottom: 56px!important;}\n.m-b-57 {margin-bottom: 57px!important;}\n.m-b-58 {margin-bottom: 58px!important;}\n.m-b-59 {margin-bottom: 59px!important;}\n.m-b-60 {margin-bottom: 60px!important;}\n.m-b-61 {margin-bottom: 61px!important;}\n.m-b-62 {margin-bottom: 62px!important;}\n.m-b-63 {margin-bottom: 63px!important;}\n.m-b-64 {margin-bottom: 64px!important;}\n.m-b-65 {margin-bottom: 65px!important;}\n.m-b-66 {margin-bottom: 66px!important;}\n.m-b-67 {margin-bottom: 67px!important;}\n.m-b-68 {margin-bottom: 68px!important;}\n.m-b-69 {margin-bottom: 69px!important;}\n.m-b-70 {margin-bottom: 70px!important;}\n.m-b-71 {margin-bottom: 71px!important;}\n.m-b-72 {margin-bottom: 72px!important;}\n.m-b-73 {margin-bottom: 73px!important;}\n.m-b-74 {margin-bottom: 74px!important;}\n.m-b-75 {margin-bottom: 75px!important;}\n.m-b-76 {margin-bottom: 76px!important;}\n.m-b-77 {margin-bottom: 77px!important;}\n.m-b-78 {margin-bottom: 78px!important;}\n.m-b-79 {margin-bottom: 79px!important;}\n.m-b-80 {margin-bottom: 80px!important;}\n.m-b-81 {margin-bottom: 81px!important;}\n.m-b-82 {margin-bottom: 82px!important;}\n.m-b-83 {margin-bottom: 83px!important;}\n.m-b-84 {margin-bottom: 84px!important;}\n.m-b-85 {margin-bottom: 85px!important;}\n.m-b-86 {margin-bottom: 86px!important;}\n.m-b-87 {margin-bottom: 87px!important;}\n.m-b-88 {margin-bottom: 88px!important;}\n.m-b-89 {margin-bottom: 89px!important;}\n.m-b-90 {margin-bottom: 90px!important;}\n.m-b-91 {margin-bottom: 91px!important;}\n.m-b-92 {margin-bottom: 92px!important;}\n.m-b-93 {margin-bottom: 93px!important;}\n.m-b-94 {margin-bottom: 94px!important;}\n.m-b-95 {margin-bottom: 95px!important;}\n.m-b-96 {margin-bottom: 96px!important;}\n.m-b-97 {margin-bottom: 97px!important;}\n.m-b-98 {margin-bottom: 98px!important;}\n.m-b-99 {margin-bottom: 99px!important;}\n.m-b-100 {margin-bottom: 100px!important;}\n.m-b-101 {margin-bottom: 101px!important;}\n.m-b-102 {margin-bottom: 102px!important;}\n.m-b-103 {margin-bottom: 103px!important;}\n.m-b-104 {margin-bottom: 104px!important;}\n.m-b-105 {margin-bottom: 105px!important;}\n.m-b-106 {margin-bottom: 106px!important;}\n.m-b-107 {margin-bottom: 107px!important;}\n.m-b-108 {margin-bottom: 108px!important;}\n.m-b-109 {margin-bottom: 109px!important;}\n.m-b-110 {margin-bottom: 110px!important;}\n.m-b-111 {margin-bottom: 111px!important;}\n.m-b-112 {margin-bottom: 112px!important;}\n.m-b-113 {margin-bottom: 113px!important;}\n.m-b-114 {margin-bottom: 114px!important;}\n.m-b-115 {margin-bottom: 115px!important;}\n.m-b-116 {margin-bottom: 116px!important;}\n.m-b-117 {margin-bottom: 117px!important;}\n.m-b-118 {margin-bottom: 118px!important;}\n.m-b-119 {margin-bottom: 119px!important;}\n.m-b-120 {margin-bottom: 120px!important;}\n.m-b-121 {margin-bottom: 121px!important;}\n.m-b-122 {margin-bottom: 122px!important;}\n.m-b-123 {margin-bottom: 123px!important;}\n.m-b-124 {margin-bottom: 124px!important;}\n.m-b-125 {margin-bottom: 125px!important;}\n.m-b-126 {margin-bottom: 126px!important;}\n.m-b-127 {margin-bottom: 127px!important;}\n.m-b-128 {margin-bottom: 128px!important;}\n.m-b-129 {margin-bottom: 129px!important;}\n.m-b-130 {margin-bottom: 130px!important;}\n.m-b-131 {margin-bottom: 131px!important;}\n.m-b-132 {margin-bottom: 132px!important;}\n.m-b-133 {margin-bottom: 133px!important;}\n.m-b-134 {margin-bottom: 134px!important;}\n.m-b-135 {margin-bottom: 135px!important;}\n.m-b-136 {margin-bottom: 136px!important;}\n.m-b-137 {margin-bottom: 137px!important;}\n.m-b-138 {margin-bottom: 138px!important;}\n.m-b-139 {margin-bottom: 139px!important;}\n.m-b-140 {margin-bottom: 140px!important;}\n.m-b-141 {margin-bottom: 141px!important;}\n.m-b-142 {margin-bottom: 142px!important;}\n.m-b-143 {margin-bottom: 143px!important;}\n.m-b-144 {margin-bottom: 144px!important;}\n.m-b-145 {margin-bottom: 145px!important;}\n.m-b-146 {margin-bottom: 146px!important;}\n.m-b-147 {margin-bottom: 147px!important;}\n.m-b-148 {margin-bottom: 148px!important;}\n.m-b-149 {margin-bottom: 149px!important;}\n.m-b-150 {margin-bottom: 150px!important;}\n\n\n/*   margin left  */\n\n.m-l-0 {margin-left: 0px!important;}\n.m-l-1 {margin-left: 1px!important;}\n.m-l-2 {margin-left: 2px!important;}\n.m-l-3 {margin-left: 3px!important;}\n.m-l-4 {margin-left: 4px!important;}\n.m-l-5 {margin-left: 5px!important;}\n.m-l-6 {margin-left: 6px!important;}\n.m-l-7 {margin-left: 7px!important;}\n.m-l-8 {margin-left: 8px!important;}\n.m-l-9 {margin-left: 9px!important;}\n.m-l-10 {margin-left: 10px!important;}\n.m-l-11 {margin-left: 11px!important;}\n.m-l-12 {margin-left: 12px!important;}\n.m-l-13 {margin-left: 13px!important;}\n.m-l-14 {margin-left: 14px!important;}\n.m-l-15 {margin-left: 15px!important;}\n.m-l-16 {margin-left: 16px!important;}\n.m-l-17 {margin-left: 17px!important;}\n.m-l-18 {margin-left: 18px!important;}\n.m-l-19 {margin-left: 19px!important;}\n.m-l-20 {margin-left: 20px!important;}\n.m-l-21 {margin-left: 21px!important;}\n.m-l-22 {margin-left: 22px!important;}\n.m-l-23 {margin-left: 23px!important;}\n.m-l-24 {margin-left: 24px!important;}\n.m-l-25 {margin-left: 25px!important;}\n.m-l-26 {margin-left: 26px!important;}\n.m-l-27 {margin-left: 27px!important;}\n.m-l-28 {margin-left: 28px!important;}\n.m-l-29 {margin-left: 29px!important;}\n.m-l-30 {margin-left: 30px!important;}\n.m-l-31 {margin-left: 31px!important;}\n.m-l-32 {margin-left: 32px!important;}\n.m-l-33 {margin-left: 33px!important;}\n.m-l-34 {margin-left: 34px!important;}\n.m-l-35 {margin-left: 35px!important;}\n.m-l-36 {margin-left: 36px!important;}\n.m-l-37 {margin-left: 37px!important;}\n.m-l-38 {margin-left: 38px!important;}\n.m-l-39 {margin-left: 39px!important;}\n.m-l-40 {margin-left: 40px!important;}\n.m-l-41 {margin-left: 4px!important;}\n.m-l-42 {margin-left: 42px!important;}\n.m-l-43 {margin-left: 43px!important;}\n.m-l-44 {margin-left: 44px!important;}\n.m-l-45 {margin-left: 45px!important;}\n.m-l-46 {margin-left: 46px!important;}\n.m-l-47 {margin-left: 47px!important;}\n.m-l-48 {margin-left: 48px!important;}\n.m-l-49 {margin-left: 49px!important;}\n.m-l-50 {margin-left: 50px!important;}\n.m-l-51 {margin-left: 51px!important;}\n.m-l-52 {margin-left: 52px!important;}\n.m-l-53 {margin-left: 53px!important;}\n.m-l-54 {margin-left: 54px!important;}\n.m-l-55 {margin-left: 55px!important;}\n.m-l-56 {margin-left: 56px!important;}\n.m-l-57 {margin-left: 57px!important;}\n.m-l-58 {margin-left: 58px!important;}\n.m-l-59 {margin-left: 59px!important;}\n.m-l-60 {margin-left: 60px!important;}\n.m-l-61 {margin-left: 61px!important;}\n.m-l-62 {margin-left: 62px!important;}\n.m-l-63 {margin-left: 63px!important;}\n.m-l-64 {margin-left: 64px!important;}\n.m-l-65 {margin-left: 65px!important;}\n.m-l-66 {margin-left: 66px!important;}\n.m-l-67 {margin-left: 67px!important;}\n.m-l-68 {margin-left: 68px!important;}\n.m-l-69 {margin-left: 69px!important;}\n.m-l-70 {margin-left: 70px!important;}\n.m-l-71 {margin-left: 71px!important;}\n.m-l-72 {margin-left: 72px!important;}\n.m-l-73 {margin-left: 73px!important;}\n.m-l-74 {margin-left: 74px!important;}\n.m-l-75 {margin-left: 75px!important;}\n.m-l-76 {margin-left: 76px!important;}\n.m-l-77 {margin-left: 77px!important;}\n.m-l-78 {margin-left: 78px!important;}\n.m-l-79 {margin-left: 79px!important;}\n.m-l-80 {margin-left: 80px!important;}\n.m-l-81 {margin-left: 81px!important;}\n.m-l-82 {margin-left: 82px!important;}\n.m-l-83 {margin-left: 83px!important;}\n.m-l-84 {margin-left: 84px!important;}\n.m-l-85 {margin-left: 85px!important;}\n.m-l-86 {margin-left: 86px!important;}\n.m-l-87 {margin-left: 87px!important;}\n.m-l-88 {margin-left: 88px!important;}\n.m-l-89 {margin-left: 89px!important;}\n.m-l-90 {margin-left: 90px!important;}\n.m-l-91 {margin-left: 91px!important;}\n.m-l-92 {margin-left: 92px!important;}\n.m-l-93 {margin-left: 93px!important;}\n.m-l-94 {margin-left: 94px!important;}\n.m-l-95 {margin-left: 95px!important;}\n.m-l-96 {margin-left: 96px!important;}\n.m-l-97 {margin-left: 97px!important;}\n.m-l-98 {margin-left: 98px!important;}\n.m-l-99 {margin-left: 99px!important;}\n.m-l-100 {margin-left: 100px!important;}\n.m-l-101 {margin-left: 101px!important;}\n.m-l-102 {margin-left: 102px!important;}\n.m-l-103 {margin-left: 103px!important;}\n.m-l-104 {margin-left: 104px!important;}\n.m-l-105 {margin-left: 105px!important;}\n.m-l-106 {margin-left: 106px!important;}\n.m-l-107 {margin-left: 107px!important;}\n.m-l-108 {margin-left: 108px!important;}\n.m-l-109 {margin-left: 109px!important;}\n.m-l-110 {margin-left: 110px!important;}\n.m-l-111 {margin-left: 111px!important;}\n.m-l-112 {margin-left: 112px!important;}\n.m-l-113 {margin-left: 113px!important;}\n.m-l-114 {margin-left: 114px!important;}\n.m-l-115 {margin-left: 115px!important;}\n.m-l-116 {margin-left: 116px!important;}\n.m-l-117 {margin-left: 117px!important;}\n.m-l-118 {margin-left: 118px!important;}\n.m-l-119 {margin-left: 119px!important;}\n.m-l-120 {margin-left: 120px!important;}\n.m-l-121 {margin-left: 121px!important;}\n.m-l-122 {margin-left: 122px!important;}\n.m-l-123 {margin-left: 123px!important;}\n.m-l-124 {margin-left: 124px!important;}\n.m-l-125 {margin-left: 125px!important;}\n.m-l-126 {margin-left: 126px!important;}\n.m-l-127 {margin-left: 127px!important;}\n.m-l-128 {margin-left: 128px!important;}\n.m-l-129 {margin-left: 129px!important;}\n.m-l-130 {margin-left: 130px!important;}\n.m-l-131 {margin-left: 131px!important;}\n.m-l-132 {margin-left: 132px!important;}\n.m-l-133 {margin-left: 133px!important;}\n.m-l-134 {margin-left: 134px!important;}\n.m-l-135 {margin-left: 135px!important;}\n.m-l-136 {margin-left: 136px!important;}\n.m-l-137 {margin-left: 137px!important;}\n.m-l-138 {margin-left: 138px!important;}\n.m-l-139 {margin-left: 139px!important;}\n.m-l-140 {margin-left: 140px!important;}\n.m-l-141 {margin-left: 141px!important;}\n.m-l-142 {margin-left: 142px!important;}\n.m-l-143 {margin-left: 143px!important;}\n.m-l-144 {margin-left: 144px!important;}\n.m-l-145 {margin-left: 145px!important;}\n.m-l-146 {margin-left: 146px!important;}\n.m-l-147 {margin-left: 147px!important;}\n.m-l-148 {margin-left: 148px!important;}\n.m-l-149 {margin-left: 149px!important;}\n.m-l-150 {margin-left: 150px!important;}\n\n\n\n/*   padding  */\n\n.p-0 {padding: 0px!important; }\n.p-5 {padding: 5px!important; }\n.p-15 {padding: 15px!important; }\n.p-20{padding: 20px!important; }\n.p-22{padding: 22px!important; }\n.p-17 {padding: 17px!important; }\n.p-18 {padding: 18px!important; }\n.p-30 {padding: 30px!important; }\n.p-48 {padding: 48px!important; }\n\n\n/*   padding top */\n\n.p-t-0 {padding-top: 0px!important;}\n.p-t-1 {padding-top: 1px!important;}\n.p-t-2 {padding-top: 2px!important;}\n.p-t-3 {padding-top: 3px!important;}\n.p-t-4 {padding-top: 4px!important;}\n.p-t-5 {padding-top: 5px!important;}\n.p-t-6 {padding-top: 6px!important;}\n.p-t-7 {padding-top: 7px!important;}\n.p-t-8 {padding-top: 8px!important;}\n.p-t-9 {padding-top: 9px!important;}\n.p-t-10 {padding-top: 10px!important;}\n.p-t-11 {padding-top: 11px!important;}\n.p-t-12 {padding-top: 12px!important;}\n.p-t-13 {padding-top: 13px!important;}\n.p-t-14 {padding-top: 14px!important;}\n.p-t-15 {padding-top: 15px!important;}\n.p-t-16 {padding-top: 16px!important;}\n.p-t-17 {padding-top: 17px!important;}\n.p-t-18 {padding-top: 18px!important;}\n.p-t-19 {padding-top: 19px!important;}\n.p-t-20 {padding-top: 20px!important;}\n.p-t-21 {padding-top: 21px!important;}\n.p-t-22 {padding-top: 22px!important;}\n.p-t-23 {padding-top: 23px!important;}\n.p-t-24 {padding-top: 24px!important;}\n.p-t-25 {padding-top: 25px!important;}\n.p-t-26 {padding-top: 26px!important;}\n.p-t-27 {padding-top: 27px!important;}\n.p-t-28 {padding-top: 28px!important;}\n.p-t-29 {padding-top: 29px!important;}\n.p-t-30 {padding-top: 30px!important;}\n.p-t-31 {padding-top: 31px!important;}\n.p-t-32 {padding-top: 32px!important;}\n.p-t-33 {padding-top: 33px!important;}\n.p-t-34 {padding-top: 34px!important;}\n.p-t-35 {padding-top: 35px!important;}\n.p-t-36 {padding-top: 36px!important;}\n.p-t-37 {padding-top: 37px!important;}\n.p-t-38 {padding-top: 38px!important;}\n.p-t-39 {padding-top: 39px!important;}\n.p-t-40 {padding-top: 40px!important;}\n.p-t-41 {padding-top: 4px!important;}\n.p-t-42 {padding-top: 42px!important;}\n.p-t-43 {padding-top: 43px!important;}\n.p-t-44 {padding-top: 44px!important;}\n.p-t-45 {padding-top: 45px!important;}\n.p-t-46 {padding-top: 46px!important;}\n.p-t-47 {padding-top: 47px!important;}\n.p-t-48 {padding-top: 48px!important;}\n.p-t-49 {padding-top: 49px!important;}\n.p-t-50 {padding-top: 50px!important;}\n.p-t-51 {padding-top: 51px!important;}\n.p-t-52 {padding-top: 52px!important;}\n.p-t-53 {padding-top: 53px!important;}\n.p-t-54 {padding-top: 54px!important;}\n.p-t-55 {padding-top: 55px!important;}\n.p-t-56 {padding-top: 56px!important;}\n.p-t-57 {padding-top: 57px!important;}\n.p-t-58 {padding-top: 58px!important;}\n.p-t-59 {padding-top: 59px!important;}\n.p-t-60 {padding-top: 60px!important;}\n.p-t-61 {padding-top: 61px!important;}\n.p-t-62 {padding-top: 62px!important;}\n.p-t-63 {padding-top: 63px!important;}\n.p-t-64 {padding-top: 64px!important;}\n.p-t-65 {padding-top: 65px!important;}\n.p-t-66 {padding-top: 66px!important;}\n.p-t-67 {padding-top: 67px!important;}\n.p-t-68 {padding-top: 68px!important;}\n.p-t-69 {padding-top: 69px!important;}\n.p-t-70 {padding-top: 70px!important;}\n.p-t-71 {padding-top: 71px!important;}\n.p-t-72 {padding-top: 72px!important;}\n.p-t-73 {padding-top: 73px!important;}\n.p-t-74 {padding-top: 74px!important;}\n.p-t-75 {padding-top: 75px!important;}\n.p-t-76 {padding-top: 76px!important;}\n.p-t-77 {padding-top: 77px!important;}\n.p-t-78 {padding-top: 78px!important;}\n.p-t-79 {padding-top: 79px!important;}\n.p-t-80 {padding-top: 80px!important;}\n.p-t-81 {padding-top: 81px!important;}\n.p-t-82 {padding-top: 82px!important;}\n.p-t-83 {padding-top: 83px!important;}\n.p-t-84 {padding-top: 84px!important;}\n.p-t-85 {padding-top: 85px!important;}\n.p-t-86 {padding-top: 86px!important;}\n.p-t-87 {padding-top: 87px!important;}\n.p-t-88 {padding-top: 88px!important;}\n.p-t-89 {padding-top: 89px!important;}\n.p-t-90 {padding-top: 90px!important;}\n.p-t-91 {padding-top: 91px!important;}\n.p-t-92 {padding-top: 92px!important;}\n.p-t-93 {padding-top: 93px!important;}\n.p-t-94 {padding-top: 94px!important;}\n.p-t-95 {padding-top: 95px!important;}\n.p-t-96 {padding-top: 96px!important;}\n.p-t-97 {padding-top: 97px!important;}\n.p-t-98 {padding-top: 98px!important;}\n.p-t-99 {padding-top: 99px!important;}\n.p-t-100 {padding-top: 100px!important;}\n.p-t-101 {padding-top: 101px!important;}\n.p-t-102 {padding-top: 102px!important;}\n.p-t-103 {padding-top: 103px!important;}\n.p-t-104 {padding-top: 104px!important;}\n.p-t-105 {padding-top: 105px!important;}\n.p-t-106 {padding-top: 106px!important;}\n.p-t-107 {padding-top: 107px!important;}\n.p-t-108 {padding-top: 108px!important;}\n.p-t-109 {padding-top: 109px!important;}\n.p-t-110 {padding-top: 110px!important;}\n.p-t-111 {padding-top: 111px!important;}\n.p-t-112 {padding-top: 112px!important;}\n.p-t-113 {padding-top: 113px!important;}\n.p-t-114 {padding-top: 114px!important;}\n.p-t-115 {padding-top: 115px!important;}\n.p-t-116 {padding-top: 116px!important;}\n.p-t-117 {padding-top: 117px!important;}\n.p-t-118 {padding-top: 118px!important;}\n.p-t-119 {padding-top: 119px!important;}\n.p-t-120 {padding-top: 120px!important;}\n.p-t-121 {padding-top: 121px!important;}\n.p-t-122 {padding-top: 122px!important;}\n.p-t-123 {padding-top: 123px!important;}\n.p-t-124 {padding-top: 124px!important;}\n.p-t-125 {padding-top: 125px!important;}\n.p-t-126 {padding-top: 126px!important;}\n.p-t-127 {padding-top: 127px!important;}\n.p-t-128 {padding-top: 128px!important;}\n.p-t-129 {padding-top: 129px!important;}\n.p-t-130 {padding-top: 130px!important;}\n.p-t-131 {padding-top: 131px!important;}\n.p-t-132 {padding-top: 132px!important;}\n.p-t-133 {padding-top: 133px!important;}\n.p-t-134 {padding-top: 134px!important;}\n.p-t-135 {padding-top: 135px!important;}\n.p-t-136 {padding-top: 136px!important;}\n.p-t-137 {padding-top: 137px!important;}\n.p-t-138 {padding-top: 138px!important;}\n.p-t-139 {padding-top: 139px!important;}\n.p-t-140 {padding-top: 140px!important;}\n.p-t-141 {padding-top: 141px!important;}\n.p-t-142 {padding-top: 142px!important;}\n.p-t-143 {padding-top: 143px!important;}\n.p-t-144 {padding-top: 144px!important;}\n.p-t-145 {padding-top: 145px!important;}\n.p-t-146 {padding-top: 146px!important;}\n.p-t-147 {padding-top: 147px!important;}\n.p-t-148 {padding-top: 148px!important;}\n.p-t-149 {padding-top: 149px!important;}\n.p-t-150 {padding-top: 150px!important;}\n\n\n/*   padding right */\n\n.p-r-0 {padding-right: 0px!important;}\n.p-r-1 {padding-right: 1px!important;}\n.p-r-2 {padding-right: 2px!important;}\n.p-r-3 {padding-right: 3px!important;}\n.p-r-4 {padding-right: 4px!important;}\n.p-r-5 {padding-right: 5px!important;}\n.p-r-6 {padding-right: 6px!important;}\n.p-r-7 {padding-right: 7px!important;}\n.p-r-8 {padding-right: 8px!important;}\n.p-r-9 {padding-right: 9px!important;}\n.p-r-10 {padding-right: 10px!important;}\n.p-r-11 {padding-right: 11px!important;}\n.p-r-12 {padding-right: 12px!important;}\n.p-r-13 {padding-right: 13px!important;}\n.p-r-14 {padding-right: 14px!important;}\n.p-r-15 {padding-right: 15px!important;}\n.p-r-16 {padding-right: 16px!important;}\n.p-r-17 {padding-right: 17px!important;}\n.p-r-18 {padding-right: 18px!important;}\n.p-r-19 {padding-right: 19px!important;}\n.p-r-20 {padding-right: 20px!important;}\n.p-r-21 {padding-right: 21px!important;}\n.p-r-22 {padding-right: 22px!important;}\n.p-r-23 {padding-right: 23px!important;}\n.p-r-24 {padding-right: 24px!important;}\n.p-r-25 {padding-right: 25px!important;}\n.p-r-26 {padding-right: 26px!important;}\n.p-r-27 {padding-right: 27px!important;}\n.p-r-28 {padding-right: 28px!important;}\n.p-r-29 {padding-right: 29px!important;}\n.p-r-30 {padding-right: 30px!important;}\n.p-r-31 {padding-right: 31px!important;}\n.p-r-32 {padding-right: 32px!important;}\n.p-r-33 {padding-right: 33px!important;}\n.p-r-34 {padding-right: 34px!important;}\n.p-r-35 {padding-right: 35px!important;}\n.p-r-36 {padding-right: 36px!important;}\n.p-r-37 {padding-right: 37px!important;}\n.p-r-38 {padding-right: 38px!important;}\n.p-r-39 {padding-right: 39px!important;}\n.p-r-40 {padding-right: 40px!important;}\n.p-r-41 {padding-right: 4px!important;}\n.p-r-42 {padding-right: 42px!important;}\n.p-r-43 {padding-right: 43px!important;}\n.p-r-44 {padding-right: 44px!important;}\n.p-r-45 {padding-right: 45px!important;}\n.p-r-46 {padding-right: 46px!important;}\n.p-r-47 {padding-right: 47px!important;}\n.p-r-48 {padding-right: 48px!important;}\n.p-r-49 {padding-right: 49px!important;}\n.p-r-50 {padding-right: 50px!important;}\n.p-r-51 {padding-right: 51px!important;}\n.p-r-52 {padding-right: 52px!important;}\n.p-r-53 {padding-right: 53px!important;}\n.p-r-54 {padding-right: 54px!important;}\n.p-r-55 {padding-right: 55px!important;}\n.p-r-56 {padding-right: 56px!important;}\n.p-r-57 {padding-right: 57px!important;}\n.p-r-58 {padding-right: 58px!important;}\n.p-r-59 {padding-right: 59px!important;}\n.p-r-60 {padding-right: 60px!important;}\n.p-r-61 {padding-right: 61px!important;}\n.p-r-62 {padding-right: 62px!important;}\n.p-r-63 {padding-right: 63px!important;}\n.p-r-64 {padding-right: 64px!important;}\n.p-r-65 {padding-right: 65px!important;}\n.p-r-66 {padding-right: 66px!important;}\n.p-r-67 {padding-right: 67px!important;}\n.p-r-68 {padding-right: 68px!important;}\n.p-r-69 {padding-right: 69px!important;}\n.p-r-70 {padding-right: 70px!important;}\n.p-r-71 {padding-right: 71px!important;}\n.p-r-72 {padding-right: 72px!important;}\n.p-r-73 {padding-right: 73px!important;}\n.p-r-74 {padding-right: 74px!important;}\n.p-r-75 {padding-right: 75px!important;}\n.p-r-76 {padding-right: 76px!important;}\n.p-r-77 {padding-right: 77px!important;}\n.p-r-78 {padding-right: 78px!important;}\n.p-r-79 {padding-right: 79px!important;}\n.p-r-80 {padding-right: 80px!important;}\n.p-r-81 {padding-right: 81px!important;}\n.p-r-82 {padding-right: 82px!important;}\n.p-r-83 {padding-right: 83px!important;}\n.p-r-84 {padding-right: 84px!important;}\n.p-r-85 {padding-right: 85px!important;}\n.p-r-86 {padding-right: 86px!important;}\n.p-r-87 {padding-right: 87px!important;}\n.p-r-88 {padding-right: 88px!important;}\n.p-r-89 {padding-right: 89px!important;}\n.p-r-90 {padding-right: 90px!important;}\n.p-r-91 {padding-right: 91px!important;}\n.p-r-92 {padding-right: 92px!important;}\n.p-r-93 {padding-right: 93px!important;}\n.p-r-94 {padding-right: 94px!important;}\n.p-r-95 {padding-right: 95px!important;}\n.p-r-96 {padding-right: 96px!important;}\n.p-r-97 {padding-right: 97px!important;}\n.p-r-98 {padding-right: 98px!important;}\n.p-r-99 {padding-right: 99px!important;}\n.p-r-100 {padding-right: 100px!important;}\n.p-r-101 {padding-right: 101px!important;}\n.p-r-102 {padding-right: 102px!important;}\n.p-r-103 {padding-right: 103px!important;}\n.p-r-104 {padding-right: 104px!important;}\n.p-r-105 {padding-right: 105px!important;}\n.p-r-106 {padding-right: 106px!important;}\n.p-r-107 {padding-right: 107px!important;}\n.p-r-108 {padding-right: 108px!important;}\n.p-r-109 {padding-right: 109px!important;}\n.p-r-110 {padding-right: 110px!important;}\n.p-r-111 {padding-right: 111px!important;}\n.p-r-112 {padding-right: 112px!important;}\n.p-r-113 {padding-right: 113px!important;}\n.p-r-114 {padding-right: 114px!important;}\n.p-r-115 {padding-right: 115px!important;}\n.p-r-116 {padding-right: 116px!important;}\n.p-r-117 {padding-right: 117px!important;}\n.p-r-118 {padding-right: 118px!important;}\n.p-r-119 {padding-right: 119px!important;}\n.p-r-120 {padding-right: 120px!important;}\n.p-r-121 {padding-right: 121px!important;}\n.p-r-122 {padding-right: 122px!important;}\n.p-r-123 {padding-right: 123px!important;}\n.p-r-124 {padding-right: 124px!important;}\n.p-r-125 {padding-right: 125px!important;}\n.p-r-126 {padding-right: 126px!important;}\n.p-r-127 {padding-right: 127px!important;}\n.p-r-128 {padding-right: 128px!important;}\n.p-r-129 {padding-right: 129px!important;}\n.p-r-130 {padding-right: 130px!important;}\n.p-r-131 {padding-right: 131px!important;}\n.p-r-132 {padding-right: 132px!important;}\n.p-r-133 {padding-right: 133px!important;}\n.p-r-134 {padding-right: 134px!important;}\n.p-r-135 {padding-right: 135px!important;}\n.p-r-136 {padding-right: 136px!important;}\n.p-r-137 {padding-right: 137px!important;}\n.p-r-138 {padding-right: 138px!important;}\n.p-r-139 {padding-right: 139px!important;}\n.p-r-140 {padding-right: 140px!important;}\n.p-r-141 {padding-right: 141px!important;}\n.p-r-142 {padding-right: 142px!important;}\n.p-r-143 {padding-right: 143px!important;}\n.p-r-144 {padding-right: 144px!important;}\n.p-r-145 {padding-right: 145px!important;}\n.p-r-146 {padding-right: 146px!important;}\n.p-r-147 {padding-right: 147px!important;}\n.p-r-148 {padding-right: 148px!important;}\n.p-r-149 {padding-right: 149px!important;}\n.p-r-150 {padding-right: 150px!important;}\n\n\n/*   padding bottom */\n\n.p-b-0 {padding-bottom: 0px!important;}\n.p-b-1 {padding-bottom: 1px!important;}\n.p-b-2 {padding-bottom: 2px!important;}\n.p-b-3 {padding-bottom: 3px!important;}\n.p-b-4 {padding-bottom: 4px!important;}\n.p-b-5 {padding-bottom: 5px!important;}\n.p-b-6 {padding-bottom: 6px!important;}\n.p-b-7 {padding-bottom: 7px!important;}\n.p-b-8 {padding-bottom: 8px!important;}\n.p-b-9 {padding-bottom: 9px!important;}\n.p-b-10 {padding-bottom: 10px!important;}\n.p-b-11 {padding-bottom: 11px!important;}\n.p-b-12 {padding-bottom: 12px!important;}\n.p-b-13 {padding-bottom: 13px!important;}\n.p-b-14 {padding-bottom: 14px!important;}\n.p-b-15 {padding-bottom: 15px!important;}\n.p-b-16 {padding-bottom: 16px!important;}\n.p-b-17 {padding-bottom: 17px!important;}\n.p-b-18 {padding-bottom: 18px!important;}\n.p-b-19 {padding-bottom: 19px!important;}\n.p-b-20 {padding-bottom: 20px!important;}\n.p-b-21 {padding-bottom: 21px!important;}\n.p-b-22 {padding-bottom: 22px!important;}\n.p-b-23 {padding-bottom: 23px!important;}\n.p-b-24 {padding-bottom: 24px!important;}\n.p-b-25 {padding-bottom: 25px!important;}\n.p-b-26 {padding-bottom: 26px!important;}\n.p-b-27 {padding-bottom: 27px!important;}\n.p-b-28 {padding-bottom: 28px!important;}\n.p-b-29 {padding-bottom: 29px!important;}\n.p-b-30 {padding-bottom: 30px!important;}\n.p-b-31 {padding-bottom: 31px!important;}\n.p-b-32 {padding-bottom: 32px!important;}\n.p-b-33 {padding-bottom: 33px!important;}\n.p-b-34 {padding-bottom: 34px!important;}\n.p-b-35 {padding-bottom: 35px!important;}\n.p-b-36 {padding-bottom: 36px!important;}\n.p-b-37 {padding-bottom: 37px!important;}\n.p-b-38 {padding-bottom: 38px!important;}\n.p-b-39 {padding-bottom: 39px!important;}\n.p-b-40 {padding-bottom: 40px!important;}\n.p-b-41 {padding-bottom: 4px!important;}\n.p-b-42 {padding-bottom: 42px!important;}\n.p-b-43 {padding-bottom: 43px!important;}\n.p-b-44 {padding-bottom: 44px!important;}\n.p-b-45 {padding-bottom: 45px!important;}\n.p-b-46 {padding-bottom: 46px!important;}\n.p-b-47 {padding-bottom: 47px!important;}\n.p-b-48 {padding-bottom: 48px!important;}\n.p-b-49 {padding-bottom: 49px!important;}\n.p-b-50 {padding-bottom: 50px!important;}\n.p-b-51 {padding-bottom: 51px!important;}\n.p-b-52 {padding-bottom: 52px!important;}\n.p-b-53 {padding-bottom: 53px!important;}\n.p-b-54 {padding-bottom: 54px!important;}\n.p-b-55 {padding-bottom: 55px!important;}\n.p-b-56 {padding-bottom: 56px!important;}\n.p-b-57 {padding-bottom: 57px!important;}\n.p-b-58 {padding-bottom: 58px!important;}\n.p-b-59 {padding-bottom: 59px!important;}\n.p-b-60 {padding-bottom: 60px!important;}\n.p-b-61 {padding-bottom: 61px!important;}\n.p-b-62 {padding-bottom: 62px!important;}\n.p-b-63 {padding-bottom: 63px!important;}\n.p-b-64 {padding-bottom: 64px!important;}\n.p-b-65 {padding-bottom: 65px!important;}\n.p-b-66 {padding-bottom: 66px!important;}\n.p-b-67 {padding-bottom: 67px!important;}\n.p-b-68 {padding-bottom: 68px!important;}\n.p-b-69 {padding-bottom: 69px!important;}\n.p-b-70 {padding-bottom: 70px!important;}\n.p-b-71 {padding-bottom: 71px!important;}\n.p-b-72 {padding-bottom: 72px!important;}\n.p-b-73 {padding-bottom: 73px!important;}\n.p-b-74 {padding-bottom: 74px!important;}\n.p-b-75 {padding-bottom: 75px!important;}\n.p-b-76 {padding-bottom: 76px!important;}\n.p-b-77 {padding-bottom: 77px!important;}\n.p-b-78 {padding-bottom: 78px!important;}\n.p-b-79 {padding-bottom: 79px!important;}\n.p-b-80 {padding-bottom: 80px!important;}\n.p-b-81 {padding-bottom: 81px!important;}\n.p-b-82 {padding-bottom: 82px!important;}\n.p-b-83 {padding-bottom: 83px!important;}\n.p-b-84 {padding-bottom: 84px!important;}\n.p-b-85 {padding-bottom: 85px!important;}\n.p-b-86 {padding-bottom: 86px!important;}\n.p-b-87 {padding-bottom: 87px!important;}\n.p-b-88 {padding-bottom: 88px!important;}\n.p-b-89 {padding-bottom: 89px!important;}\n.p-b-90 {padding-bottom: 90px!important;}\n.p-b-91 {padding-bottom: 91px!important;}\n.p-b-92 {padding-bottom: 92px!important;}\n.p-b-93 {padding-bottom: 93px!important;}\n.p-b-94 {padding-bottom: 94px!important;}\n.p-b-95 {padding-bottom: 95px!important;}\n.p-b-96 {padding-bottom: 96px!important;}\n.p-b-97 {padding-bottom: 97px!important;}\n.p-b-98 {padding-bottom: 98px!important;}\n.p-b-99 {padding-bottom: 99px!important;}\n.p-b-100 {padding-bottom: 100px!important;}\n.p-b-101 {padding-bottom: 101px!important;}\n.p-b-102 {padding-bottom: 102px!important;}\n.p-b-103 {padding-bottom: 103px!important;}\n.p-b-104 {padding-bottom: 104px!important;}\n.p-b-105 {padding-bottom: 105px!important;}\n.p-b-106 {padding-bottom: 106px!important;}\n.p-b-107 {padding-bottom: 107px!important;}\n.p-b-108 {padding-bottom: 108px!important;}\n.p-b-109 {padding-bottom: 109px!important;}\n.p-b-110 {padding-bottom: 110px!important;}\n.p-b-111 {padding-bottom: 111px!important;}\n.p-b-112 {padding-bottom: 112px!important;}\n.p-b-113 {padding-bottom: 113px!important;}\n.p-b-114 {padding-bottom: 114px!important;}\n.p-b-115 {padding-bottom: 115px!important;}\n.p-b-116 {padding-bottom: 116px!important;}\n.p-b-117 {padding-bottom: 117px!important;}\n.p-b-118 {padding-bottom: 118px!important;}\n.p-b-119 {padding-bottom: 119px!important;}\n.p-b-120 {padding-bottom: 120px!important;}\n.p-b-121 {padding-bottom: 121px!important;}\n.p-b-122 {padding-bottom: 122px!important;}\n.p-b-123 {padding-bottom: 123px!important;}\n.p-b-124 {padding-bottom: 124px!important;}\n.p-b-125 {padding-bottom: 125px!important;}\n.p-b-126 {padding-bottom: 126px!important;}\n.p-b-127 {padding-bottom: 127px!important;}\n.p-b-128 {padding-bottom: 128px!important;}\n.p-b-129 {padding-bottom: 129px!important;}\n.p-b-130 {padding-bottom: 130px!important;}\n.p-b-131 {padding-bottom: 131px!important;}\n.p-b-132 {padding-bottom: 132px!important;}\n.p-b-133 {padding-bottom: 133px!important;}\n.p-b-134 {padding-bottom: 134px!important;}\n.p-b-135 {padding-bottom: 135px!important;}\n.p-b-136 {padding-bottom: 136px!important;}\n.p-b-137 {padding-bottom: 137px!important;}\n.p-b-138 {padding-bottom: 138px!important;}\n.p-b-139 {padding-bottom: 139px!important;}\n.p-b-140 {padding-bottom: 140px!important;}\n.p-b-141 {padding-bottom: 141px!important;}\n.p-b-142 {padding-bottom: 142px!important;}\n.p-b-143 {padding-bottom: 143px!important;}\n.p-b-144 {padding-bottom: 144px!important;}\n.p-b-145 {padding-bottom: 145px!important;}\n.p-b-146 {padding-bottom: 146px!important;}\n.p-b-147 {padding-bottom: 147px!important;}\n.p-b-148 {padding-bottom: 148px!important;}\n.p-b-149 {padding-bottom: 149px!important;}\n.p-b-150 {padding-bottom: 150px!important;}\n\n\n\n/*   padding left */\n\n.p-l-0 {padding-left: 0px!important;}\n.p-l-1 {padding-left: 1px!important;}\n.p-l-2 {padding-left: 2px!important;}\n.p-l-3 {padding-left: 3px!important;}\n.p-l-4 {padding-left: 4px!important;}\n.p-l-5 {padding-left: 5px!important;}\n.p-l-6 {padding-left: 6px!important;}\n.p-l-7 {padding-left: 7px!important;}\n.p-l-8 {padding-left: 8px!important;}\n.p-l-9 {padding-left: 9px!important;}\n.p-l-10 {padding-left: 10px!important;}\n.p-l-11 {padding-left: 11px!important;}\n.p-l-12 {padding-left: 12px!important;}\n.p-l-13 {padding-left: 13px!important;}\n.p-l-14 {padding-left: 14px!important;}\n.p-l-15 {padding-left: 15px!important;}\n.p-l-16 {padding-left: 16px!important;}\n.p-l-17 {padding-left: 17px!important;}\n.p-l-18 {padding-left: 18px!important;}\n.p-l-19 {padding-left: 19px!important;}\n.p-l-20 {padding-left: 20px!important;}\n.p-l-21 {padding-left: 21px!important;}\n.p-l-22 {padding-left: 22px!important;}\n.p-l-23 {padding-left: 23px!important;}\n.p-l-24 {padding-left: 24px!important;}\n.p-l-25 {padding-left: 25px!important;}\n.p-l-26 {padding-left: 26px!important;}\n.p-l-27 {padding-left: 27px!important;}\n.p-l-28 {padding-left: 28px!important;}\n.p-l-29 {padding-left: 29px!important;}\n.p-l-30 {padding-left: 30px!important;}\n.p-l-31 {padding-left: 31px!important;}\n.p-l-32 {padding-left: 32px!important;}\n.p-l-33 {padding-left: 33px!important;}\n.p-l-34 {padding-left: 34px!important;}\n.p-l-35 {padding-left: 35px!important;}\n.p-l-36 {padding-left: 36px!important;}\n.p-l-37 {padding-left: 37px!important;}\n.p-l-38 {padding-left: 38px!important;}\n.p-l-39 {padding-left: 39px!important;}\n.p-l-40 {padding-left: 40px!important;}\n.p-l-41 {padding-left: 4px!important;}\n.p-l-42 {padding-left: 42px!important;}\n.p-l-43 {padding-left: 43px!important;}\n.p-l-44 {padding-left: 44px!important;}\n.p-l-45 {padding-left: 45px!important;}\n.p-l-46 {padding-left: 46px!important;}\n.p-l-47 {padding-left: 47px!important;}\n.p-l-48 {padding-left: 48px!important;}\n.p-l-49 {padding-left: 49px!important;}\n.p-l-50 {padding-left: 50px!important;}\n.p-l-51 {padding-left: 51px!important;}\n.p-l-52 {padding-left: 52px!important;}\n.p-l-53 {padding-left: 53px!important;}\n.p-l-54 {padding-left: 54px!important;}\n.p-l-55 {padding-left: 55px!important;}\n.p-l-56 {padding-left: 56px!important;}\n.p-l-57 {padding-left: 57px!important;}\n.p-l-58 {padding-left: 58px!important;}\n.p-l-59 {padding-left: 59px!important;}\n.p-l-60 {padding-left: 60px!important;}\n.p-l-61 {padding-left: 61px!important;}\n.p-l-62 {padding-left: 62px!important;}\n.p-l-63 {padding-left: 63px!important;}\n.p-l-64 {padding-left: 64px!important;}\n.p-l-65 {padding-left: 65px!important;}\n.p-l-66 {padding-left: 66px!important;}\n.p-l-67 {padding-left: 67px!important;}\n.p-l-68 {padding-left: 68px!important;}\n.p-l-69 {padding-left: 69px!important;}\n.p-l-70 {padding-left: 70px!important;}\n.p-l-71 {padding-left: 71px!important;}\n.p-l-72 {padding-left: 72px!important;}\n.p-l-73 {padding-left: 73px!important;}\n.p-l-74 {padding-left: 74px!important;}\n.p-l-75 {padding-left: 75px!important;}\n.p-l-76 {padding-left: 76px!important;}\n.p-l-77 {padding-left: 77px!important;}\n.p-l-78 {padding-left: 78px!important;}\n.p-l-79 {padding-left: 79px!important;}\n.p-l-80 {padding-left: 80px!important;}\n.p-l-81 {padding-left: 81px!important;}\n.p-l-82 {padding-left: 82px!important;}\n.p-l-83 {padding-left: 83px!important;}\n.p-l-84 {padding-left: 84px!important;}\n.p-l-85 {padding-left: 85px!important;}\n.p-l-86 {padding-left: 86px!important;}\n.p-l-87 {padding-left: 87px!important;}\n.p-l-88 {padding-left: 88px!important;}\n.p-l-89 {padding-left: 89px!important;}\n.p-l-90 {padding-left: 90px!important;}\n.p-l-91 {padding-left: 91px!important;}\n.p-l-92 {padding-left: 92px!important;}\n.p-l-93 {padding-left: 93px!important;}\n.p-l-94 {padding-left: 94px!important;}\n.p-l-95 {padding-left: 95px!important;}\n.p-l-96 {padding-left: 96px!important;}\n.p-l-97 {padding-left: 97px!important;}\n.p-l-98 {padding-left: 98px!important;}\n.p-l-99 {padding-left: 99px!important;}\n.p-l-100 {padding-left: 100px!important;}\n.p-l-101 {padding-left: 101px!important;}\n.p-l-102 {padding-left: 102px!important;}\n.p-l-103 {padding-left: 103px!important;}\n.p-l-104 {padding-left: 104px!important;}\n.p-l-105 {padding-left: 105px!important;}\n.p-l-106 {padding-left: 106px!important;}\n.p-l-107 {padding-left: 107px!important;}\n.p-l-108 {padding-left: 108px!important;}\n.p-l-109 {padding-left: 109px!important;}\n.p-l-110 {padding-left: 110px!important;}\n.p-l-111 {padding-left: 111px!important;}\n.p-l-112 {padding-left: 112px!important;}\n.p-l-113 {padding-left: 113px!important;}\n.p-l-114 {padding-left: 114px!important;}\n.p-l-115 {padding-left: 115px!important;}\n.p-l-116 {padding-left: 116px!important;}\n.p-l-117 {padding-left: 117px!important;}\n.p-l-118 {padding-left: 118px!important;}\n.p-l-119 {padding-left: 119px!important;}\n.p-l-120 {padding-left: 120px!important;}\n.p-l-121 {padding-left: 121px!important;}\n.p-l-122 {padding-left: 122px!important;}\n.p-l-123 {padding-left: 123px!important;}\n.p-l-124 {padding-left: 124px!important;}\n.p-l-125 {padding-left: 125px!important;}\n.p-l-126 {padding-left: 126px!important;}\n.p-l-127 {padding-left: 127px!important;}\n.p-l-128 {padding-left: 128px!important;}\n.p-l-129 {padding-left: 129px!important;}\n.p-l-130 {padding-left: 130px!important;}\n.p-l-131 {padding-left: 131px!important;}\n.p-l-132 {padding-left: 132px!important;}\n.p-l-133 {padding-left: 133px!important;}\n.p-l-134 {padding-left: 134px!important;}\n.p-l-135 {padding-left: 135px!important;}\n.p-l-136 {padding-left: 136px!important;}\n.p-l-137 {padding-left: 137px!important;}\n.p-l-138 {padding-left: 138px!important;}\n.p-l-139 {padding-left: 139px!important;}\n.p-l-140 {padding-left: 140px!important;}\n.p-l-141 {padding-left: 141px!important;}\n.p-l-142 {padding-left: 142px!important;}\n.p-l-143 {padding-left: 143px!important;}\n.p-l-144 {padding-left: 144px!important;}\n.p-l-145 {padding-left: 145px!important;}\n.p-l-146 {padding-left: 146px!important;}\n.p-l-147 {padding-left: 147px!important;}\n.p-l-148 {padding-left: 148px!important;}\n.p-l-149 {padding-left: 149px!important;}\n.p-l-150 {padding-left: 150px!important;}\n\n\n/* Width percentage*/\n\n\n\n\n.w-5{\n    width:5%!important;\n}\n.w-10{\n    width:10%!important;\n}\n.w-15{\n    width:15%!important;\n}\n.w-20{\n    width:20%!important;\n}\n.w-25{\n    width:25%!important;\n}\n.w-30{\n    width:30%!important;\n}\n.w-35{\n    width:35%!important;\n}\n.w-40{\n    width:40%!important;\n}\n.w-45{\n    width:45%!important;\n}\n.w-50{\n    width:50%!important;\n}\n.w-55{\n    width:55%!important;\n}\n.w-60{\n    width:60%!important;\n}\n.w-65{\n    width:65%!important;\n}\n.w-70{\n    width:70%!important;\n}\n.w-75{\n    width:75%!important;\n}\n.w-80{\n    width:80%!important;\n}\n.w-85{\n    width:85%!important;\n}\n.w-90{\n    width:90%!important;\n}\n.w-95{\n    width:95%!important;\n}\n.w-100{\n    width:100%!important;\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "static/css/icons.css",
    "content": "/* ==========================================================================\nIcon packs\n========================================================================== */\n@font-face {\n  font-family: 'icomoon';\n  src:url('../fonts/icomoon.eot');\n  src:url('../fonts/icomoon.eot?#iefix') format('embedded-opentype'),\n    url('../fonts/icomoon.ttf') format('truetype'),\n    url('../fonts/icomoon.woff') format('woff'),\n    url('../fonts/icomoon.svg#icomoon') format('svg');\n  font-weight: normal;\n  font-style: normal;\n}\n\n@font-face {\n  font-family: 'fontAwesome';\n  src: url('../fonts/fontawesome-webfont.eot?v=4.1.0');\n  src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'), \n    url('../fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'), \n    url('../fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'), \n    url('../fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg');\n  font-weight: normal;\n  font-style: normal;\n}\n\n.fa {\n  display: inline-block;\n  font-family: fontAwesome;\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n/* ------------------ Target all icons --------------------*/\n[class^=\"im-\"] {\n  display: inline-block;\n  vertical-align: middle;\n  margin-top: -2px;\n}\n\n\n/* ------------------ Demo styles ( delete it in production ) --------------------*/\n\n.row.icons .panel [class^=\"col-lg-\"] {\n  margin-bottom: 10px;\n}\n.row.icons i {\n  font-size: 24px;\n}\n\n/* ------------------ Ico moon --------------------*/\n[class^=\"im-\"], [class*=\" im-\"] {\n  font-family: 'icomoon';\n  speak: none;\n  font-style: normal;\n  font-weight: normal;\n  font-variant: normal;\n  text-transform: none;\n  line-height: 1;\n\n  /* Better Font Rendering =========== */\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n.im-home:before {\n  content: \"\\e000\";\n}\n.im-home2:before {\n  content: \"\\e001\";\n}\n.im-home3:before {\n  content: \"\\e002\";\n}\n.im-home4:before {\n  content: \"\\e003\";\n}\n.im-home5:before {\n  content: \"\\e004\";\n}\n.im-home6:before {\n  content: \"\\e005\";\n}\n.im-home7:before {\n  content: \"\\e006\";\n}\n.im-home8:before {\n  content: \"\\e007\";\n}\n.im-home9:before {\n  content: \"\\e008\";\n}\n.im-home10:before {\n  content: \"\\e009\";\n}\n.im-home11:before {\n  content: \"\\e00a\";\n}\n.im-office:before {\n  content: \"\\e00b\";\n}\n.im-newspaper:before {\n  content: \"\\e00c\";\n}\n.im-pencil:before {\n  content: \"\\e00d\";\n}\n.im-pencil2:before {\n  content: \"\\e00e\";\n}\n.im-pencil3:before {\n  content: \"\\e00f\";\n}\n.im-pencil4:before {\n  content: \"\\e010\";\n}\n.im-pencil5:before {\n  content: \"\\e011\";\n}\n.im-pencil6:before {\n  content: \"\\e012\";\n}\n.im-quill:before {\n  content: \"\\e013\";\n}\n.im-quill2:before {\n  content: \"\\e014\";\n}\n.im-quill3:before {\n  content: \"\\e015\";\n}\n.im-pen:before {\n  content: \"\\e016\";\n}\n.im-pen2:before {\n  content: \"\\e017\";\n}\n.im-pen3:before {\n  content: \"\\e018\";\n}\n.im-pen4:before {\n  content: \"\\e019\";\n}\n.im-pen5:before {\n  content: \"\\e01a\";\n}\n.im-marker:before {\n  content: \"\\e01b\";\n}\n.im-home12:before {\n  content: \"\\e01c\";\n}\n.im-marker2:before {\n  content: \"\\e01d\";\n}\n.im-blog:before {\n  content: \"\\e01e\";\n}\n.im-blog2:before {\n  content: \"\\e01f\";\n}\n.im-brush:before {\n  content: \"\\e020\";\n}\n.im-palette:before {\n  content: \"\\e021\";\n}\n.im-palette2:before {\n  content: \"\\e022\";\n}\n.im-eyedropper:before {\n  content: \"\\e023\";\n}\n.im-eyedropper2:before {\n  content: \"\\e024\";\n}\n.im-droplet:before {\n  content: \"\\e025\";\n}\n.im-droplet2:before {\n  content: \"\\e026\";\n}\n.im-droplet3:before {\n  content: \"\\e027\";\n}\n.im-droplet4:before {\n  content: \"\\e028\";\n}\n.im-paint-format:before {\n  content: \"\\e029\";\n}\n.im-paint-format2:before {\n  content: \"\\e02a\";\n}\n.im-image:before {\n  content: \"\\e02b\";\n}\n.im-image2:before {\n  content: \"\\e02c\";\n}\n.im-image3:before {\n  content: \"\\e02d\";\n}\n.im-images:before {\n  content: \"\\e02e\";\n}\n.im-image4:before {\n  content: \"\\e02f\";\n}\n.im-image5:before {\n  content: \"\\e030\";\n}\n.im-image6:before {\n  content: \"\\e031\";\n}\n.im-images2:before {\n  content: \"\\e032\";\n}\n.im-image7:before {\n  content: \"\\e033\";\n}\n.im-camera:before {\n  content: \"\\e034\";\n}\n.im-camera2:before {\n  content: \"\\e035\";\n}\n.im-camera3:before {\n  content: \"\\e036\";\n}\n.im-camera4:before {\n  content: \"\\e037\";\n}\n.im-music:before {\n  content: \"\\e038\";\n}\n.im-music2:before {\n  content: \"\\e039\";\n}\n.im-music3:before {\n  content: \"\\e03a\";\n}\n.im-music4:before {\n  content: \"\\e03b\";\n}\n.im-music5:before {\n  content: \"\\e03c\";\n}\n.im-music6:before {\n  content: \"\\e03d\";\n}\n.im-piano:before {\n  content: \"\\e03e\";\n}\n.im-guitar:before {\n  content: \"\\e03f\";\n}\n.im-headphones:before {\n  content: \"\\e040\";\n}\n.im-headphones2:before {\n  content: \"\\e041\";\n}\n.im-play:before {\n  content: \"\\e042\";\n}\n.im-play2:before {\n  content: \"\\e043\";\n}\n.im-movie:before {\n  content: \"\\e044\";\n}\n.im-movie2:before {\n  content: \"\\e045\";\n}\n.im-movie3:before {\n  content: \"\\e046\";\n}\n.im-film:before {\n  content: \"\\e047\";\n}\n.im-film2:before {\n  content: \"\\e048\";\n}\n.im-film3:before {\n  content: \"\\e049\";\n}\n.im-film4:before {\n  content: \"\\e04a\";\n}\n.im-camera5:before {\n  content: \"\\e04b\";\n}\n.im-camera6:before {\n  content: \"\\e04c\";\n}\n.im-camera7:before {\n  content: \"\\e04d\";\n}\n.im-camera8:before {\n  content: \"\\e04e\";\n}\n.im-camera9:before {\n  content: \"\\e04f\";\n}\n.im-dice:before {\n  content: \"\\e050\";\n}\n.im-gamepad:before {\n  content: \"\\e051\";\n}\n.im-gamepad2:before {\n  content: \"\\e052\";\n}\n.im-gamepad3:before {\n  content: \"\\e053\";\n}\n.im-pacman:before {\n  content: \"\\e054\";\n}\n.im-spades:before {\n  content: \"\\e055\";\n}\n.im-clubs:before {\n  content: \"\\e056\";\n}\n.im-diamonds:before {\n  content: \"\\e057\";\n}\n.im-king:before {\n  content: \"\\e058\";\n}\n.im-queen:before {\n  content: \"\\e059\";\n}\n.im-rock:before {\n  content: \"\\e05a\";\n}\n.im-bishop:before {\n  content: \"\\e05b\";\n}\n.im-knight:before {\n  content: \"\\e05c\";\n}\n.im-pawn:before {\n  content: \"\\e05d\";\n}\n.im-chess:before {\n  content: \"\\e05e\";\n}\n.im-bullhorn:before {\n  content: \"\\e05f\";\n}\n.im-megaphone:before {\n  content: \"\\e060\";\n}\n.im-new:before {\n  content: \"\\e061\";\n}\n.im-connection:before {\n  content: \"\\e062\";\n}\n.im-connection2:before {\n  content: \"\\e063\";\n}\n.im-podcast:before {\n  content: \"\\e064\";\n}\n.im-radio:before {\n  content: \"\\e065\";\n}\n.im-feed:before {\n  content: \"\\e066\";\n}\n.im-connection3:before {\n  content: \"\\e067\";\n}\n.im-radio2:before {\n  content: \"\\e068\";\n}\n.im-podcast2:before {\n  content: \"\\e069\";\n}\n.im-podcast3:before {\n  content: \"\\e06a\";\n}\n.im-mic:before {\n  content: \"\\e06b\";\n}\n.im-mic2:before {\n  content: \"\\e06c\";\n}\n.im-mic3:before {\n  content: \"\\e06d\";\n}\n.im-mic4:before {\n  content: \"\\e06e\";\n}\n.im-mic5:before {\n  content: \"\\e06f\";\n}\n.im-book:before {\n  content: \"\\e070\";\n}\n.im-book2:before {\n  content: \"\\e071\";\n}\n.im-books:before {\n  content: \"\\e072\";\n}\n.im-reading:before {\n  content: \"\\e073\";\n}\n.im-library:before {\n  content: \"\\e074\";\n}\n.im-library2:before {\n  content: \"\\e075\";\n}\n.im-graduation:before {\n  content: \"\\e076\";\n}\n.im-file:before {\n  content: \"\\e077\";\n}\n.im-profile:before {\n  content: \"\\e078\";\n}\n.im-file2:before {\n  content: \"\\e079\";\n}\n.im-file3:before {\n  content: \"\\e07a\";\n}\n.im-file4:before {\n  content: \"\\e07b\";\n}\n.im-file5:before {\n  content: \"\\e07c\";\n}\n.im-file6:before {\n  content: \"\\e07d\";\n}\n.im-files:before {\n  content: \"\\e07e\";\n}\n.im-file-plus:before {\n  content: \"\\e07f\";\n}\n.im-file-minus:before {\n  content: \"\\e080\";\n}\n.im-file-download:before {\n  content: \"\\e081\";\n}\n.im-file-upload:before {\n  content: \"\\e082\";\n}\n.im-file-check:before {\n  content: \"\\e083\";\n}\n.im-file-remove:before {\n  content: \"\\e084\";\n}\n.im-file7:before {\n  content: \"\\e085\";\n}\n.im-file8:before {\n  content: \"\\e086\";\n}\n.im-file-plus2:before {\n  content: \"\\e087\";\n}\n.im-file-minus2:before {\n  content: \"\\e088\";\n}\n.im-file-download2:before {\n  content: \"\\e089\";\n}\n.im-file-upload2:before {\n  content: \"\\e08a\";\n}\n.im-file-check2:before {\n  content: \"\\e08b\";\n}\n.im-file-remove2:before {\n  content: \"\\e08c\";\n}\n.im-file9:before {\n  content: \"\\e08d\";\n}\n.im-copy:before {\n  content: \"\\e08e\";\n}\n.im-copy2:before {\n  content: \"\\e08f\";\n}\n.im-copy3:before {\n  content: \"\\e090\";\n}\n.im-copy4:before {\n  content: \"\\e091\";\n}\n.im-paste:before {\n  content: \"\\e092\";\n}\n.im-paste2:before {\n  content: \"\\e093\";\n}\n.im-paste3:before {\n  content: \"\\e094\";\n}\n.im-stack:before {\n  content: \"\\e095\";\n}\n.im-stack2:before {\n  content: \"\\e096\";\n}\n.im-stack3:before {\n  content: \"\\e097\";\n}\n.im-folder:before {\n  content: \"\\e098\";\n}\n.im-folder-download:before {\n  content: \"\\e099\";\n}\n.im-folder-upload:before {\n  content: \"\\e09a\";\n}\n.im-folder-plus:before {\n  content: \"\\e09b\";\n}\n.im-folder-plus2:before {\n  content: \"\\e09c\";\n}\n.im-folder-minus:before {\n  content: \"\\e09d\";\n}\n.im-folder-minus2:before {\n  content: \"\\e09e\";\n}\n.im-folder8:before {\n  content: \"\\e09f\";\n}\n.im-folder-remove:before {\n  content: \"\\e0a0\";\n}\n.im-folder2:before {\n  content: \"\\e0a1\";\n}\n.im-folder-open:before {\n  content: \"\\e0a2\";\n}\n.im-folder3:before {\n  content: \"\\e0a3\";\n}\n.im-folder4:before {\n  content: \"\\e0a4\";\n}\n.im-folder-plus3:before {\n  content: \"\\e0a5\";\n}\n.im-folder-minus3:before {\n  content: \"\\e0a6\";\n}\n.im-folder-plus4:before {\n  content: \"\\e0a7\";\n}\n.im-folder-remove2:before {\n  content: \"\\e0a8\";\n}\n.im-folder-download2:before {\n  content: \"\\e0a9\";\n}\n.im-folder-upload2:before {\n  content: \"\\e0aa\";\n}\n.im-folder-download3:before {\n  content: \"\\e0ab\";\n}\n.im-folder-upload3:before {\n  content: \"\\e0ac\";\n}\n.im-folder5:before {\n  content: \"\\e0ad\";\n}\n.im-folder-open2:before {\n  content: \"\\e0ae\";\n}\n.im-folder6:before {\n  content: \"\\e0af\";\n}\n.im-folder-open3:before {\n  content: \"\\e0b0\";\n}\n.im-certificate:before {\n  content: \"\\e0b1\";\n}\n.im-cc:before {\n  content: \"\\e0b2\";\n}\n.im-tag:before {\n  content: \"\\e0b3\";\n}\n.im-tag2:before {\n  content: \"\\e0b4\";\n}\n.im-tag3:before {\n  content: \"\\e0b5\";\n}\n.im-tag4:before {\n  content: \"\\e0b6\";\n}\n.im-tag5:before {\n  content: \"\\e0b7\";\n}\n.im-tag6:before {\n  content: \"\\e0b8\";\n}\n.im-tag7:before {\n  content: \"\\e0b9\";\n}\n.im-tags:before {\n  content: \"\\e0ba\";\n}\n.im-tags2:before {\n  content: \"\\e0bb\";\n}\n.im-tag8:before {\n  content: \"\\e0bc\";\n}\n.im-barcode:before {\n  content: \"\\e0bd\";\n}\n.im-barcode2:before {\n  content: \"\\e0be\";\n}\n.im-qrcode:before {\n  content: \"\\e0bf\";\n}\n.im-ticket:before {\n  content: \"\\e0c0\";\n}\n.im-cart:before {\n  content: \"\\e0c1\";\n}\n.im-cart2:before {\n  content: \"\\e0c2\";\n}\n.im-cart3:before {\n  content: \"\\e0c3\";\n}\n.im-cart4:before {\n  content: \"\\e0c4\";\n}\n.im-cart5:before {\n  content: \"\\e0c5\";\n}\n.im-cart6:before {\n  content: \"\\e0c6\";\n}\n.im-cart7:before {\n  content: \"\\e0c7\";\n}\n.im-cart-plus:before {\n  content: \"\\e0c8\";\n}\n.im-cart-minus:before {\n  content: \"\\e0c9\";\n}\n.im-cart-add:before {\n  content: \"\\e0ca\";\n}\n.im-cart-remove:before {\n  content: \"\\e0cb\";\n}\n.im-cart-checkout:before {\n  content: \"\\e0cc\";\n}\n.im-cart-remove2:before {\n  content: \"\\e0cd\";\n}\n.im-basket:before {\n  content: \"\\e0ce\";\n}\n.im-basket2:before {\n  content: \"\\e0cf\";\n}\n.im-bag:before {\n  content: \"\\e0d0\";\n}\n.im-bag2:before {\n  content: \"\\e0d1\";\n}\n.im-bag3:before {\n  content: \"\\e0d2\";\n}\n.im-coin:before {\n  content: \"\\e0d3\";\n}\n.im-coins:before {\n  content: \"\\e0d4\";\n}\n.im-credit:before {\n  content: \"\\e0d5\";\n}\n.im-credit2:before {\n  content: \"\\e0d6\";\n}\n.im-calculate:before {\n  content: \"\\e0d7\";\n}\n.im-calculate2:before {\n  content: \"\\e0d8\";\n}\n.im-support:before {\n  content: \"\\e0d9\";\n}\n.im-phone:before {\n  content: \"\\e0da\";\n}\n.im-phone2:before {\n  content: \"\\e0db\";\n}\n.im-phone3:before {\n  content: \"\\e0dc\";\n}\n.im-phone4:before {\n  content: \"\\e0dd\";\n}\n.im-contact-add:before {\n  content: \"\\e0de\";\n}\n.im-contact-remove:before {\n  content: \"\\e0df\";\n}\n.im-contact-add2:before {\n  content: \"\\e0e0\";\n}\n.im-contact-remove2:before {\n  content: \"\\e0e1\";\n}\n.im-call-incoming:before {\n  content: \"\\e0e2\";\n}\n.im-call-outgoing:before {\n  content: \"\\e0e3\";\n}\n.im-phone5:before {\n  content: \"\\e0e4\";\n}\n.im-phone6:before {\n  content: \"\\e0e5\";\n}\n.im-phone-hang-up:before {\n  content: \"\\e0e6\";\n}\n.im-phone-hang-up2:before {\n  content: \"\\e0e7\";\n}\n.im-address-book:before {\n  content: \"\\e0e8\";\n}\n.im-address-book2:before {\n  content: \"\\e0e9\";\n}\n.im-notebook:before {\n  content: \"\\e0ea\";\n}\n.im-envelop:before {\n  content: \"\\e0eb\";\n}\n.im-envelop2:before {\n  content: \"\\e0ec\";\n}\n.im-mail-send:before {\n  content: \"\\e0ed\";\n}\n.im-envelop-opened:before {\n  content: \"\\e0ee\";\n}\n.im-envelop3:before {\n  content: \"\\e0ef\";\n}\n.im-pushpin:before {\n  content: \"\\e0f0\";\n}\n.im-location:before {\n  content: \"\\e0f1\";\n}\n.im-location2:before {\n  content: \"\\e0f2\";\n}\n.im-location3:before {\n  content: \"\\e0f3\";\n}\n.im-location4:before {\n  content: \"\\e0f4\";\n}\n.im-location5:before {\n  content: \"\\e0f5\";\n}\n.im-location6:before {\n  content: \"\\e0f6\";\n}\n.im-location7:before {\n  content: \"\\e0f7\";\n}\n.im-compass:before {\n  content: \"\\e0f8\";\n}\n.im-compass2:before {\n  content: \"\\e0f9\";\n}\n.im-map:before {\n  content: \"\\e0fa\";\n}\n.im-map2:before {\n  content: \"\\e0fb\";\n}\n.im-map3:before {\n  content: \"\\e0fc\";\n}\n.im-map4:before {\n  content: \"\\e0fd\";\n}\n.im-direction:before {\n  content: \"\\e0fe\";\n}\n.im-history:before {\n  content: \"\\e0ff\";\n}\n.im-history2:before {\n  content: \"\\e100\";\n}\n.im-clock:before {\n  content: \"\\e101\";\n}\n.im-clock2:before {\n  content: \"\\e102\";\n}\n.im-clock3:before {\n  content: \"\\e103\";\n}\n.im-clock4:before {\n  content: \"\\e104\";\n}\n.im-watch:before {\n  content: \"\\e105\";\n}\n.im-clock5:before {\n  content: \"\\e106\";\n}\n.im-clock6:before {\n  content: \"\\e107\";\n}\n.im-clock7:before {\n  content: \"\\e108\";\n}\n.im-alarm:before {\n  content: \"\\e109\";\n}\n.im-alarm2:before {\n  content: \"\\e10a\";\n}\n.im-bell:before {\n  content: \"\\e10b\";\n}\n.im-bell2:before {\n  content: \"\\e10c\";\n}\n.im-alarm-plus:before {\n  content: \"\\e10d\";\n}\n.im-alarm-minus:before {\n  content: \"\\e10e\";\n}\n.im-alarm-check:before {\n  content: \"\\e10f\";\n}\n.im-alarm-cancel:before {\n  content: \"\\e110\";\n}\n.im-stopwatch:before {\n  content: \"\\e111\";\n}\n.im-calendar:before {\n  content: \"\\e112\";\n}\n.im-calendar2:before {\n  content: \"\\e113\";\n}\n.im-calendar3:before {\n  content: \"\\e114\";\n}\n.im-calendar4:before {\n  content: \"\\e115\";\n}\n.im-calendar5:before {\n  content: \"\\e116\";\n}\n.im-print:before {\n  content: \"\\e117\";\n}\n.im-print2:before {\n  content: \"\\e118\";\n}\n.im-print3:before {\n  content: \"\\e119\";\n}\n.im-mouse:before {\n  content: \"\\e11a\";\n}\n.im-mouse2:before {\n  content: \"\\e11b\";\n}\n.im-mouse3:before {\n  content: \"\\e11c\";\n}\n.im-mouse4:before {\n  content: \"\\e11d\";\n}\n.im-keyboard:before {\n  content: \"\\e11e\";\n}\n.im-keyboard2:before {\n  content: \"\\e11f\";\n}\n.im-screen:before {\n  content: \"\\e120\";\n}\n.im-screen2:before {\n  content: \"\\e121\";\n}\n.im-screen3:before {\n  content: \"\\e122\";\n}\n.im-screen4:before {\n  content: \"\\e123\";\n}\n.im-laptop:before {\n  content: \"\\e124\";\n}\n.im-mobile:before {\n  content: \"\\e125\";\n}\n.im-mobile2:before {\n  content: \"\\e126\";\n}\n.im-tablet:before {\n  content: \"\\e127\";\n}\n.im-mobile3:before {\n  content: \"\\e128\";\n}\n.im-tv:before {\n  content: \"\\e129\";\n}\n.im-cabinet:before {\n  content: \"\\e12a\";\n}\n.im-archive:before {\n  content: \"\\e12b\";\n}\n.im-drawer:before {\n  content: \"\\e12c\";\n}\n.im-drawer2:before {\n  content: \"\\e12d\";\n}\n.im-drawer3:before {\n  content: \"\\e12e\";\n}\n.im-box:before {\n  content: \"\\e12f\";\n}\n.im-box-add:before {\n  content: \"\\e130\";\n}\n.im-box-remove:before {\n  content: \"\\e131\";\n}\n.im-download:before {\n  content: \"\\e132\";\n}\n.im-upload:before {\n  content: \"\\e133\";\n}\n.im-disk:before {\n  content: \"\\e134\";\n}\n.im-cd:before {\n  content: \"\\e135\";\n}\n.im-storage:before {\n  content: \"\\e136\";\n}\n.im-storage2:before {\n  content: \"\\e137\";\n}\n.im-database:before {\n  content: \"\\e138\";\n}\n.im-database2:before {\n  content: \"\\e139\";\n}\n.im-database3:before {\n  content: \"\\e13a\";\n}\n.im-undo:before {\n  content: \"\\e13b\";\n}\n.im-redo:before {\n  content: \"\\e13c\";\n}\n.im-rotate:before {\n  content: \"\\e13d\";\n}\n.im-rotate2:before {\n  content: \"\\e13e\";\n}\n.im-flip:before {\n  content: \"\\e13f\";\n}\n.im-flip2:before {\n  content: \"\\e140\";\n}\n.im-unite:before {\n  content: \"\\e141\";\n}\n.im-subtract:before {\n  content: \"\\e142\";\n}\n.im-interset:before {\n  content: \"\\e143\";\n}\n.im-exclude:before {\n  content: \"\\e144\";\n}\n.im-align-left:before {\n  content: \"\\e145\";\n}\n.im-align-center-horizontal:before {\n  content: \"\\e146\";\n}\n.im-align-right:before {\n  content: \"\\e147\";\n}\n.im-align-top:before {\n  content: \"\\e148\";\n}\n.im-align-center-vertical:before {\n  content: \"\\e149\";\n}\n.im-align-bottom:before {\n  content: \"\\e14a\";\n}\n.im-undo2:before {\n  content: \"\\e14b\";\n}\n.im-redo2:before {\n  content: \"\\e14c\";\n}\n.im-forward:before {\n  content: \"\\e14d\";\n}\n.im-reply:before {\n  content: \"\\e14e\";\n}\n.im-reply2:before {\n  content: \"\\e14f\";\n}\n.im-bubble:before {\n  content: \"\\e150\";\n}\n.im-bubbles:before {\n  content: \"\\e151\";\n}\n.im-bubbles2:before {\n  content: \"\\e152\";\n}\n.im-bubble2:before {\n  content: \"\\e153\";\n}\n.im-bubbles3:before {\n  content: \"\\e154\";\n}\n.im-bubbles4:before {\n  content: \"\\e155\";\n}\n.im-bubble-notification:before {\n  content: \"\\e156\";\n}\n.im-bubbles5:before {\n  content: \"\\e157\";\n}\n.im-bubbles6:before {\n  content: \"\\e158\";\n}\n.im-bubble3:before {\n  content: \"\\e159\";\n}\n.im-bubble-dots:before {\n  content: \"\\e15a\";\n}\n.im-bubble4:before {\n  content: \"\\e15b\";\n}\n.im-bubble5:before {\n  content: \"\\e15c\";\n}\n.im-bubble-dots2:before {\n  content: \"\\e15d\";\n}\n.im-bubble6:before {\n  content: \"\\e15e\";\n}\n.im-bubble7:before {\n  content: \"\\e15f\";\n}\n.im-bubble8:before {\n  content: \"\\e160\";\n}\n.im-bubbles7:before {\n  content: \"\\e161\";\n}\n.im-bubble9:before {\n  content: \"\\e162\";\n}\n.im-bubbles8:before {\n  content: \"\\e163\";\n}\n.im-bubble10:before {\n  content: \"\\e164\";\n}\n.im-bubble-dots3:before {\n  content: \"\\e165\";\n}\n.im-bubble11:before {\n  content: \"\\e166\";\n}\n.im-bubble12:before {\n  content: \"\\e167\";\n}\n.im-bubble-dots4:before {\n  content: \"\\e168\";\n}\n.im-bubble13:before {\n  content: \"\\e169\";\n}\n.im-bubbles9:before {\n  content: \"\\e16a\";\n}\n.im-bubbles10:before {\n  content: \"\\e16b\";\n}\n.im-bubble-blocked:before {\n  content: \"\\e16c\";\n}\n.im-bubble-quote:before {\n  content: \"\\e16d\";\n}\n.im-bubble-user:before {\n  content: \"\\e16e\";\n}\n.im-bubble-check:before {\n  content: \"\\e16f\";\n}\n.im-bubble-video-chat:before {\n  content: \"\\e170\";\n}\n.im-bubble-link:before {\n  content: \"\\e171\";\n}\n.im-bubble-locked:before {\n  content: \"\\e172\";\n}\n.im-bubble-star:before {\n  content: \"\\e173\";\n}\n.im-bubble-heart:before {\n  content: \"\\e174\";\n}\n.im-bubble-paperclip:before {\n  content: \"\\e175\";\n}\n.im-bubble-cancel:before {\n  content: \"\\e176\";\n}\n.im-bubble-plus:before {\n  content: \"\\e177\";\n}\n.im-bubble-minus:before {\n  content: \"\\e178\";\n}\n.im-bubble-notification2:before {\n  content: \"\\e179\";\n}\n.im-bubble-trash:before {\n  content: \"\\e17a\";\n}\n.im-bubble-left:before {\n  content: \"\\e17b\";\n}\n.im-bubble-right:before {\n  content: \"\\e17c\";\n}\n.im-bubble-up:before {\n  content: \"\\e17d\";\n}\n.im-bubble-down:before {\n  content: \"\\e17e\";\n}\n.im-bubble-first:before {\n  content: \"\\e17f\";\n}\n.im-bubble-last:before {\n  content: \"\\e180\";\n}\n.im-bubble-replu:before {\n  content: \"\\e181\";\n}\n.im-bubble-forward:before {\n  content: \"\\e182\";\n}\n.im-bubble-reply:before {\n  content: \"\\e183\";\n}\n.im-bubble-forward2:before {\n  content: \"\\e184\";\n}\n.im-user:before {\n  content: \"\\e185\";\n}\n.im-users:before {\n  content: \"\\e186\";\n}\n.im-user-plus:before {\n  content: \"\\e187\";\n}\n.im-user-plus2:before {\n  content: \"\\e188\";\n}\n.im-user-minus:before {\n  content: \"\\e189\";\n}\n.im-user-minus2:before {\n  content: \"\\e18a\";\n}\n.im-user-cancel:before {\n  content: \"\\e18b\";\n}\n.im-user-block:before {\n  content: \"\\e18c\";\n}\n.im-users2:before {\n  content: \"\\e18d\";\n}\n.im-user2:before {\n  content: \"\\e18e\";\n}\n.im-users3:before {\n  content: \"\\e18f\";\n}\n.im-user-plus3:before {\n  content: \"\\e190\";\n}\n.im-user-minus3:before {\n  content: \"\\e191\";\n}\n.im-user-cancel2:before {\n  content: \"\\e192\";\n}\n.im-user-block2:before {\n  content: \"\\e193\";\n}\n.im-user3:before {\n  content: \"\\e194\";\n}\n.im-user4:before {\n  content: \"\\e195\";\n}\n.im-user5:before {\n  content: \"\\e196\";\n}\n.im-user6:before {\n  content: \"\\e197\";\n}\n.im-users4:before {\n  content: \"\\e198\";\n}\n.im-user7:before {\n  content: \"\\e199\";\n}\n.im-user8:before {\n  content: \"\\e19a\";\n}\n.im-users5:before {\n  content: \"\\e19b\";\n}\n.im-vcard:before {\n  content: \"\\e19c\";\n}\n.im-tshirt:before {\n  content: \"\\e19d\";\n}\n.im-hanger:before {\n  content: \"\\e19e\";\n}\n.im-quotes-left:before {\n  content: \"\\e19f\";\n}\n.im-quotes-right:before {\n  content: \"\\e1a0\";\n}\n.im-quotes-right2:before {\n  content: \"\\e1a1\";\n}\n.im-quotes-right3:before {\n  content: \"\\e1a2\";\n}\n.im-busy:before {\n  content: \"\\e1a3\";\n}\n.im-busy2:before {\n  content: \"\\e1a4\";\n}\n.im-busy3:before {\n  content: \"\\e1a5\";\n}\n.im-busy4:before {\n  content: \"\\e1a6\";\n}\n.im-spinner:before {\n  content: \"\\e1a7\";\n}\n.im-spinner2:before {\n  content: \"\\e1a8\";\n}\n.im-spinner3:before {\n  content: \"\\e1a9\";\n}\n.im-spinner4:before {\n  content: \"\\e1aa\";\n}\n.im-spinner5:before {\n  content: \"\\e1ab\";\n}\n.im-spinner6:before {\n  content: \"\\e1ac\";\n}\n.im-spinner7:before {\n  content: \"\\e1ad\";\n}\n.im-spinner8:before {\n  content: \"\\e1ae\";\n}\n.im-spinner9:before {\n  content: \"\\e1af\";\n}\n.im-spinner10:before {\n  content: \"\\e1b0\";\n}\n.im-spinner11:before {\n  content: \"\\e1b1\";\n}\n.im-spinner12:before {\n  content: \"\\e1b2\";\n}\n.im-microscope:before {\n  content: \"\\e1b3\";\n}\n.im-binoculars:before {\n  content: \"\\e1b4\";\n}\n.im-binoculars2:before {\n  content: \"\\e1b5\";\n}\n.im-search:before {\n  content: \"\\e1b6\";\n}\n.im-search2:before {\n  content: \"\\e1b7\";\n}\n.im-zoomin:before {\n  content: \"\\e1b8\";\n}\n.im-zoomout:before {\n  content: \"\\e1b9\";\n}\n.im-search3:before {\n  content: \"\\e1ba\";\n}\n.im-search4:before {\n  content: \"\\e1bb\";\n}\n.im-zoomin2:before {\n  content: \"\\e1bc\";\n}\n.im-zoomout2:before {\n  content: \"\\e1bd\";\n}\n.im-search5:before {\n  content: \"\\e1be\";\n}\n.im-expand:before {\n  content: \"\\e1bf\";\n}\n.im-contract:before {\n  content: \"\\e1c0\";\n}\n.im-scale-up:before {\n  content: \"\\e1c1\";\n}\n.im-scale-down:before {\n  content: \"\\e1c2\";\n}\n.im-expand2:before {\n  content: \"\\e1c3\";\n}\n.im-contract2:before {\n  content: \"\\e1c4\";\n}\n.im-scale-up2:before {\n  content: \"\\e1c5\";\n}\n.im-scale-down2:before {\n  content: \"\\e1c6\";\n}\n.im-fullscreen:before {\n  content: \"\\e1c7\";\n}\n.im-expand3:before {\n  content: \"\\e1c8\";\n}\n.im-contract3:before {\n  content: \"\\e1c9\";\n}\n.im-key:before {\n  content: \"\\e1ca\";\n}\n.im-key2:before {\n  content: \"\\e1cb\";\n}\n.im-key3:before {\n  content: \"\\e1cc\";\n}\n.im-key4:before {\n  content: \"\\e1cd\";\n}\n.im-key5:before {\n  content: \"\\e1ce\";\n}\n.im-keyhole:before {\n  content: \"\\e1cf\";\n}\n.im-lock:before {\n  content: \"\\e1d0\";\n}\n.im-lock2:before {\n  content: \"\\e1d1\";\n}\n.im-lock3:before {\n  content: \"\\e1d2\";\n}\n.im-lock4:before {\n  content: \"\\e1d3\";\n}\n.im-unlocked:before {\n  content: \"\\e1d4\";\n}\n.im-lock5:before {\n  content: \"\\e1d5\";\n}\n.im-unlocked2:before {\n  content: \"\\e1d6\";\n}\n.im-wrench:before {\n  content: \"\\e1d7\";\n}\n.im-wrench2:before {\n  content: \"\\e1d8\";\n}\n.im-wrench3:before {\n  content: \"\\e1d9\";\n}\n.im-wrench4:before {\n  content: \"\\e1da\";\n}\n.im-settings:before {\n  content: \"\\e1db\";\n}\n.im-equalizer:before {\n  content: \"\\e1dc\";\n}\n.im-equalizer2:before {\n  content: \"\\e1dd\";\n}\n.im-equalizer3:before {\n  content: \"\\e1de\";\n}\n.im-cog:before {\n  content: \"\\e1df\";\n}\n.im-cogs:before {\n  content: \"\\e1e0\";\n}\n.im-cog2:before {\n  content: \"\\e1e1\";\n}\n.im-cog3:before {\n  content: \"\\e1e2\";\n}\n.im-cog4:before {\n  content: \"\\e1e3\";\n}\n.im-cog5:before {\n  content: \"\\e1e4\";\n}\n.im-cog6:before {\n  content: \"\\e1e5\";\n}\n.im-cog7:before {\n  content: \"\\e1e6\";\n}\n.im-factory:before {\n  content: \"\\e1e7\";\n}\n.im-hammer:before {\n  content: \"\\e1e8\";\n}\n.im-tools:before {\n  content: \"\\e1e9\";\n}\n.im-screwdriver:before {\n  content: \"\\e1ea\";\n}\n.im-screwdriver2:before {\n  content: \"\\e1eb\";\n}\n.im-wand:before {\n  content: \"\\e1ec\";\n}\n.im-wand2:before {\n  content: \"\\e1ed\";\n}\n.im-health:before {\n  content: \"\\e1ee\";\n}\n.im-aid:before {\n  content: \"\\e1ef\";\n}\n.im-patch:before {\n  content: \"\\e1f0\";\n}\n.im-bug:before {\n  content: \"\\e1f1\";\n}\n.im-bug2:before {\n  content: \"\\e1f2\";\n}\n.im-inject:before {\n  content: \"\\e1f3\";\n}\n.im-inject2:before {\n  content: \"\\e1f4\";\n}\n.im-construction:before {\n  content: \"\\e1f5\";\n}\n.im-cone:before {\n  content: \"\\e1f6\";\n}\n.im-pie:before {\n  content: \"\\e1f7\";\n}\n.im-pie2:before {\n  content: \"\\e1f8\";\n}\n.im-pie3:before {\n  content: \"\\e1f9\";\n}\n.im-pie4:before {\n  content: \"\\e1fa\";\n}\n.im-pie5:before {\n  content: \"\\e1fb\";\n}\n.im-pie6:before {\n  content: \"\\e1fc\";\n}\n.im-pie7:before {\n  content: \"\\e1fd\";\n}\n.im-stats:before {\n  content: \"\\e1fe\";\n}\n.im-stats2:before {\n  content: \"\\e1ff\";\n}\n.im-stats3:before {\n  content: \"\\e200\";\n}\n.im-bars:before {\n  content: \"\\e201\";\n}\n.im-bars2:before {\n  content: \"\\e202\";\n}\n.im-bars3:before {\n  content: \"\\e203\";\n}\n.im-bars4:before {\n  content: \"\\e204\";\n}\n.im-bars5:before {\n  content: \"\\e205\";\n}\n.im-bars6:before {\n  content: \"\\e206\";\n}\n.im-stats-up:before {\n  content: \"\\e207\";\n}\n.im-stats-down:before {\n  content: \"\\e208\";\n}\n.im-stairs-down:before {\n  content: \"\\e209\";\n}\n.im-stairs-down2:before {\n  content: \"\\e20a\";\n}\n.im-chart:before {\n  content: \"\\e20b\";\n}\n.im-stairs:before {\n  content: \"\\e20c\";\n}\n.im-stairs2:before {\n  content: \"\\e20d\";\n}\n.im-ladder:before {\n  content: \"\\e20e\";\n}\n.im-cake:before {\n  content: \"\\e20f\";\n}\n.im-gift:before {\n  content: \"\\e210\";\n}\n.im-gift2:before {\n  content: \"\\e211\";\n}\n.im-balloon:before {\n  content: \"\\e212\";\n}\n.im-rating:before {\n  content: \"\\e213\";\n}\n.im-rating2:before {\n  content: \"\\e214\";\n}\n.im-rating3:before {\n  content: \"\\e215\";\n}\n.im-podium:before {\n  content: \"\\e216\";\n}\n.im-medal:before {\n  content: \"\\e217\";\n}\n.im-medal2:before {\n  content: \"\\e218\";\n}\n.im-medal3:before {\n  content: \"\\e219\";\n}\n.im-medal4:before {\n  content: \"\\e21a\";\n}\n.im-medal5:before {\n  content: \"\\e21b\";\n}\n.im-crown:before {\n  content: \"\\e21c\";\n}\n.im-trophy:before {\n  content: \"\\e21d\";\n}\n.im-trophy2:before {\n  content: \"\\e21e\";\n}\n.im-trophy-star:before {\n  content: \"\\e21f\";\n}\n.im-diamond:before {\n  content: \"\\e220\";\n}\n.im-diamond2:before {\n  content: \"\\e221\";\n}\n.im-glass:before {\n  content: \"\\e222\";\n}\n.im-glass2:before {\n  content: \"\\e223\";\n}\n.im-bottle:before {\n  content: \"\\e224\";\n}\n.im-bottle2:before {\n  content: \"\\e225\";\n}\n.im-mug:before {\n  content: \"\\e226\";\n}\n.im-food:before {\n  content: \"\\e227\";\n}\n.im-food2:before {\n  content: \"\\e228\";\n}\n.im-hamburger:before {\n  content: \"\\e229\";\n}\n.im-cup:before {\n  content: \"\\e22a\";\n}\n.im-cup2:before {\n  content: \"\\e22b\";\n}\n.im-leaf:before {\n  content: \"\\e22c\";\n}\n.im-leaf2:before {\n  content: \"\\e22d\";\n}\n.im-apple-fruit:before {\n  content: \"\\e22e\";\n}\n.im-tree:before {\n  content: \"\\e22f\";\n}\n.im-tree2:before {\n  content: \"\\e230\";\n}\n.im-paw:before {\n  content: \"\\e231\";\n}\n.im-steps:before {\n  content: \"\\e232\";\n}\n.im-flower:before {\n  content: \"\\e233\";\n}\n.im-rocket:before {\n  content: \"\\e234\";\n}\n.im-meter:before {\n  content: \"\\e235\";\n}\n.im-meter2:before {\n  content: \"\\e236\";\n}\n.im-meter-slow:before {\n  content: \"\\e237\";\n}\n.im-meter-medium:before {\n  content: \"\\e238\";\n}\n.im-meter-fast:before {\n  content: \"\\e239\";\n}\n.im-dashboard:before {\n  content: \"\\e23a\";\n}\n.im-hammer2:before {\n  content: \"\\e23b\";\n}\n.im-balance:before {\n  content: \"\\e23c\";\n}\n.im-bomb:before {\n  content: \"\\e23d\";\n}\n.im-fire:before {\n  content: \"\\e23e\";\n}\n.im-fire2:before {\n  content: \"\\e23f\";\n}\n.im-lab:before {\n  content: \"\\e240\";\n}\n.im-atom:before {\n  content: \"\\e241\";\n}\n.im-atom2:before {\n  content: \"\\e242\";\n}\n.im-magnet:before {\n  content: \"\\e243\";\n}\n.im-magnet2:before {\n  content: \"\\e244\";\n}\n.im-magnet3:before {\n  content: \"\\e245\";\n}\n.im-magnet4:before {\n  content: \"\\e246\";\n}\n.im-dumbbell:before {\n  content: \"\\e247\";\n}\n.im-skull:before {\n  content: \"\\e248\";\n}\n.im-skull2:before {\n  content: \"\\e249\";\n}\n.im-skull3:before {\n  content: \"\\e24a\";\n}\n.im-lamp:before {\n  content: \"\\e24b\";\n}\n.im-lamp2:before {\n  content: \"\\e24c\";\n}\n.im-lamp3:before {\n  content: \"\\e24d\";\n}\n.im-lamp4:before {\n  content: \"\\e24e\";\n}\n.im-remove:before {\n  content: \"\\e24f\";\n}\n.im-remove2:before {\n  content: \"\\e250\";\n}\n.im-remove3:before {\n  content: \"\\e251\";\n}\n.im-remove4:before {\n  content: \"\\e252\";\n}\n.im-remove5:before {\n  content: \"\\e253\";\n}\n.im-remove6:before {\n  content: \"\\e254\";\n}\n.im-remove7:before {\n  content: \"\\e255\";\n}\n.im-remove8:before {\n  content: \"\\e256\";\n}\n.im-briefcase:before {\n  content: \"\\e257\";\n}\n.im-briefcase2:before {\n  content: \"\\e258\";\n}\n.im-briefcase3:before {\n  content: \"\\e259\";\n}\n.im-airplane:before {\n  content: \"\\e25a\";\n}\n.im-airplane2:before {\n  content: \"\\e25b\";\n}\n.im-paperplane:before {\n  content: \"\\e25c\";\n}\n.im-car:before {\n  content: \"\\e25d\";\n}\n.im-gas-pump:before {\n  content: \"\\e25e\";\n}\n.im-bus:before {\n  content: \"\\e25f\";\n}\n.im-truck:before {\n  content: \"\\e260\";\n}\n.im-bike:before {\n  content: \"\\e261\";\n}\n.im-road:before {\n  content: \"\\e262\";\n}\n.im-train:before {\n  content: \"\\e263\";\n}\n.im-ship:before {\n  content: \"\\e264\";\n}\n.im-boat:before {\n  content: \"\\e265\";\n}\n.im-cube:before {\n  content: \"\\e266\";\n}\n.im-cube2:before {\n  content: \"\\e267\";\n}\n.im-cube3:before {\n  content: \"\\e268\";\n}\n.im-cube4:before {\n  content: \"\\e269\";\n}\n.im-pyramid:before {\n  content: \"\\e26a\";\n}\n.im-pyramid2:before {\n  content: \"\\e26b\";\n}\n.im-cylinder:before {\n  content: \"\\e26c\";\n}\n.im-package:before {\n  content: \"\\e26d\";\n}\n.im-puzzle:before {\n  content: \"\\e26e\";\n}\n.im-puzzle2:before {\n  content: \"\\e26f\";\n}\n.im-puzzle3:before {\n  content: \"\\e270\";\n}\n.im-puzzle4:before {\n  content: \"\\e271\";\n}\n.im-glasses:before {\n  content: \"\\e272\";\n}\n.im-glasses2:before {\n  content: \"\\e273\";\n}\n.im-glasses3:before {\n  content: \"\\e274\";\n}\n.im-sunglasses:before {\n  content: \"\\e275\";\n}\n.im-accessibility:before {\n  content: \"\\e276\";\n}\n.im-accessibility2:before {\n  content: \"\\e277\";\n}\n.im-brain:before {\n  content: \"\\e278\";\n}\n.im-target:before {\n  content: \"\\e279\";\n}\n.im-target2:before {\n  content: \"\\e27a\";\n}\n.im-target3:before {\n  content: \"\\e27b\";\n}\n.im-gun:before {\n  content: \"\\e27c\";\n}\n.im-gun-ban:before {\n  content: \"\\e27d\";\n}\n.im-shield:before {\n  content: \"\\e27e\";\n}\n.im-shield2:before {\n  content: \"\\e27f\";\n}\n.im-shield3:before {\n  content: \"\\e280\";\n}\n.im-shield4:before {\n  content: \"\\e281\";\n}\n.im-soccer:before {\n  content: \"\\e282\";\n}\n.im-football:before {\n  content: \"\\e283\";\n}\n.im-baseball:before {\n  content: \"\\e284\";\n}\n.im-basketball:before {\n  content: \"\\e285\";\n}\n.im-golf:before {\n  content: \"\\e286\";\n}\n.im-hockey:before {\n  content: \"\\e287\";\n}\n.im-racing:before {\n  content: \"\\e288\";\n}\n.im-eightball:before {\n  content: \"\\e289\";\n}\n.im-bowlingball:before {\n  content: \"\\e28a\";\n}\n.im-bowling:before {\n  content: \"\\e28b\";\n}\n.im-bowling2:before {\n  content: \"\\e28c\";\n}\n.im-lightning:before {\n  content: \"\\e28d\";\n}\n.im-power:before {\n  content: \"\\e28e\";\n}\n.im-power2:before {\n  content: \"\\e28f\";\n}\n.im-switch:before {\n  content: \"\\e290\";\n}\n.im-powercord:before {\n  content: \"\\e291\";\n}\n.im-cord:before {\n  content: \"\\e292\";\n}\n.im-socket:before {\n  content: \"\\e293\";\n}\n.im-clipboard:before {\n  content: \"\\e294\";\n}\n.im-clipboard2:before {\n  content: \"\\e295\";\n}\n.im-signup:before {\n  content: \"\\e296\";\n}\n.im-clipboard3:before {\n  content: \"\\e297\";\n}\n.im-clipboard4:before {\n  content: \"\\e298\";\n}\n.im-list:before {\n  content: \"\\e299\";\n}\n.im-list2:before {\n  content: \"\\e29a\";\n}\n.im-list3:before {\n  content: \"\\e29b\";\n}\n.im-numbered-list:before {\n  content: \"\\e29c\";\n}\n.im-list4:before {\n  content: \"\\e29d\";\n}\n.im-list5:before {\n  content: \"\\e29e\";\n}\n.im-playlist:before {\n  content: \"\\e29f\";\n}\n.im-grid:before {\n  content: \"\\e2a0\";\n}\n.im-grid2:before {\n  content: \"\\e2a1\";\n}\n.im-grid3:before {\n  content: \"\\e2a2\";\n}\n.im-grid4:before {\n  content: \"\\e2a3\";\n}\n.im-grid5:before {\n  content: \"\\e2a4\";\n}\n.im-grid6:before {\n  content: \"\\e2a5\";\n}\n.im-tree3:before {\n  content: \"\\e2a6\";\n}\n.im-tree4:before {\n  content: \"\\e2a7\";\n}\n.im-tree5:before {\n  content: \"\\e2a8\";\n}\n.im-menu:before {\n  content: \"\\e2a9\";\n}\n.im-menu2:before {\n  content: \"\\e2aa\";\n}\n.im-circle-small:before {\n  content: \"\\e2ab\";\n}\n.im-menu3:before {\n  content: \"\\e2ac\";\n}\n.im-menu4:before {\n  content: \"\\e2ad\";\n}\n.im-menu5:before {\n  content: \"\\e2ae\";\n}\n.im-menu6:before {\n  content: \"\\e2af\";\n}\n.im-menu7:before {\n  content: \"\\e2b0\";\n}\n.im-menu8:before {\n  content: \"\\e2b1\";\n}\n.im-menu9:before {\n  content: \"\\e2b2\";\n}\n.im-cloud:before {\n  content: \"\\e2b3\";\n}\n.im-cloud2:before {\n  content: \"\\e2b4\";\n}\n.im-cloud3:before {\n  content: \"\\e2b5\";\n}\n.im-cloud-download:before {\n  content: \"\\e2b6\";\n}\n.im-cloud-upload:before {\n  content: \"\\e2b7\";\n}\n.im-download2:before {\n  content: \"\\e2b8\";\n}\n.im-upload2:before {\n  content: \"\\e2b9\";\n}\n.im-download3:before {\n  content: \"\\e2ba\";\n}\n.im-upload3:before {\n  content: \"\\e2bb\";\n}\n.im-download4:before {\n  content: \"\\e2bc\";\n}\n.im-upload4:before {\n  content: \"\\e2bd\";\n}\n.im-download5:before {\n  content: \"\\e2be\";\n}\n.im-upload5:before {\n  content: \"\\e2bf\";\n}\n.im-download6:before {\n  content: \"\\e2c0\";\n}\n.im-upload6:before {\n  content: \"\\e2c1\";\n}\n.im-download7:before {\n  content: \"\\e2c2\";\n}\n.im-upload7:before {\n  content: \"\\e2c3\";\n}\n.im-globe:before {\n  content: \"\\e2c4\";\n}\n.im-globe2:before {\n  content: \"\\e2c5\";\n}\n.im-globe3:before {\n  content: \"\\e2c6\";\n}\n.im-earth:before {\n  content: \"\\e2c7\";\n}\n.im-network:before {\n  content: \"\\e2c8\";\n}\n.im-link:before {\n  content: \"\\e2c9\";\n}\n.im-link2:before {\n  content: \"\\e2ca\";\n}\n.im-link3:before {\n  content: \"\\e2cb\";\n}\n.im-link22:before {\n  content: \"\\e2cc\";\n}\n.im-link4:before {\n  content: \"\\e2cd\";\n}\n.im-link5:before {\n  content: \"\\e2ce\";\n}\n.im-link6:before {\n  content: \"\\e2cf\";\n}\n.im-anchor:before {\n  content: \"\\e2d0\";\n}\n.im-flag:before {\n  content: \"\\e2d1\";\n}\n.im-flag2:before {\n  content: \"\\e2d2\";\n}\n.im-flag3:before {\n  content: \"\\e2d3\";\n}\n.im-flag4:before {\n  content: \"\\e2d4\";\n}\n.im-flag5:before {\n  content: \"\\e2d5\";\n}\n.im-flag6:before {\n  content: \"\\e2d6\";\n}\n.im-attachment:before {\n  content: \"\\e2d7\";\n}\n.im-attachment2:before {\n  content: \"\\e2d8\";\n}\n.im-eye:before {\n  content: \"\\e2d9\";\n}\n.im-eye-blocked:before {\n  content: \"\\e2da\";\n}\n.im-eye2:before {\n  content: \"\\e2db\";\n}\n.im-eye3:before {\n  content: \"\\e2dc\";\n}\n.im-eye-blocked2:before {\n  content: \"\\e2dd\";\n}\n.im-eye4:before {\n  content: \"\\e2de\";\n}\n.im-eye5:before {\n  content: \"\\e2df\";\n}\n.im-eye6:before {\n  content: \"\\e2e0\";\n}\n.im-eye7:before {\n  content: \"\\e2e1\";\n}\n.im-eye8:before {\n  content: \"\\e2e2\";\n}\n.im-bookmark:before {\n  content: \"\\e2e3\";\n}\n.im-bookmark2:before {\n  content: \"\\e2e4\";\n}\n.im-bookmarks:before {\n  content: \"\\e2e5\";\n}\n.im-bookmark3:before {\n  content: \"\\e2e6\";\n}\n.im-spotlight:before {\n  content: \"\\e2e7\";\n}\n.im-starburst:before {\n  content: \"\\e2e8\";\n}\n.im-snowflake:before {\n  content: \"\\e2e9\";\n}\n.im-temperature:before {\n  content: \"\\e2ea\";\n}\n.im-temperature2:before {\n  content: \"\\e2eb\";\n}\n.im-weather-lightning:before {\n  content: \"\\e2ec\";\n}\n.im-weather-rain:before {\n  content: \"\\e2ed\";\n}\n.im-weather-snow:before {\n  content: \"\\e2ee\";\n}\n.im-windy:before {\n  content: \"\\e2ef\";\n}\n.im-fan:before {\n  content: \"\\e2f0\";\n}\n.im-umbrella:before {\n  content: \"\\e2f1\";\n}\n.im-sun:before {\n  content: \"\\e2f2\";\n}\n.im-sun2:before {\n  content: \"\\e2f3\";\n}\n.im-brightness-high:before {\n  content: \"\\e2f4\";\n}\n.im-brightness-medium:before {\n  content: \"\\e2f5\";\n}\n.im-brightness-low:before {\n  content: \"\\e2f6\";\n}\n.im-brightness-contrast:before {\n  content: \"\\e2f7\";\n}\n.im-contrast:before {\n  content: \"\\e2f8\";\n}\n.im-moon:before {\n  content: \"\\e2f9\";\n}\n.im-bed:before {\n  content: \"\\e2fa\";\n}\n.im-bed2:before {\n  content: \"\\e2fb\";\n}\n.im-star:before {\n  content: \"\\e2fc\";\n}\n.im-star2:before {\n  content: \"\\e2fd\";\n}\n.im-star3:before {\n  content: \"\\e2fe\";\n}\n.im-star4:before {\n  content: \"\\e2ff\";\n}\n.im-star5:before {\n  content: \"\\e300\";\n}\n.im-star6:before {\n  content: \"\\e301\";\n}\n.im-heart:before {\n  content: \"\\e302\";\n}\n.im-heart2:before {\n  content: \"\\e303\";\n}\n.im-heart3:before {\n  content: \"\\e304\";\n}\n.im-heart4:before {\n  content: \"\\e305\";\n}\n.im-heart-broken:before {\n  content: \"\\e306\";\n}\n.im-heart5:before {\n  content: \"\\e307\";\n}\n.im-heart6:before {\n  content: \"\\e308\";\n}\n.im-heart-broken2:before {\n  content: \"\\e309\";\n}\n.im-heart7:before {\n  content: \"\\e30a\";\n}\n.im-heart8:before {\n  content: \"\\e30b\";\n}\n.im-heart-broken3:before {\n  content: \"\\e30c\";\n}\n.im-lips:before {\n  content: \"\\e30d\";\n}\n.im-lips2:before {\n  content: \"\\e30e\";\n}\n.im-thumbs-up:before {\n  content: \"\\e30f\";\n}\n.im-thumbs-up2:before {\n  content: \"\\e310\";\n}\n.im-thumbs-down:before {\n  content: \"\\e311\";\n}\n.im-thumbs-down2:before {\n  content: \"\\e312\";\n}\n.im-thumbs-up3:before {\n  content: \"\\e313\";\n}\n.im-thumbs-up4:before {\n  content: \"\\e314\";\n}\n.im-thumbs-up5:before {\n  content: \"\\e315\";\n}\n.im-thumbs-up6:before {\n  content: \"\\e316\";\n}\n.im-people:before {\n  content: \"\\e317\";\n}\n.im-man:before {\n  content: \"\\e318\";\n}\n.im-male:before {\n  content: \"\\e319\";\n}\n.im-woman:before {\n  content: \"\\e31a\";\n}\n.im-female:before {\n  content: \"\\e31b\";\n}\n.im-peace:before {\n  content: \"\\e31c\";\n}\n.im-yin-yang:before {\n  content: \"\\e31d\";\n}\n.im-happy:before {\n  content: \"\\e31e\";\n}\n.im-happy2:before {\n  content: \"\\e31f\";\n}\n.im-smiley:before {\n  content: \"\\e320\";\n}\n.im-smiley2:before {\n  content: \"\\e321\";\n}\n.im-tongue:before {\n  content: \"\\e322\";\n}\n.im-tongue2:before {\n  content: \"\\e323\";\n}\n.im-sad:before {\n  content: \"\\e324\";\n}\n.im-sad2:before {\n  content: \"\\e325\";\n}\n.im-wink:before {\n  content: \"\\e326\";\n}\n.im-wink2:before {\n  content: \"\\e327\";\n}\n.im-grin:before {\n  content: \"\\e328\";\n}\n.im-grin2:before {\n  content: \"\\e329\";\n}\n.im-cool:before {\n  content: \"\\e32a\";\n}\n.im-cool2:before {\n  content: \"\\e32b\";\n}\n.im-angry:before {\n  content: \"\\e32c\";\n}\n.im-angry2:before {\n  content: \"\\e32d\";\n}\n.im-evil:before {\n  content: \"\\e32e\";\n}\n.im-evil2:before {\n  content: \"\\e32f\";\n}\n.im-shocked:before {\n  content: \"\\e330\";\n}\n.im-shocked2:before {\n  content: \"\\e331\";\n}\n.im-confused:before {\n  content: \"\\e332\";\n}\n.im-confused2:before {\n  content: \"\\e333\";\n}\n.im-neutral:before {\n  content: \"\\e334\";\n}\n.im-neutral2:before {\n  content: \"\\e335\";\n}\n.im-wondering:before {\n  content: \"\\e336\";\n}\n.im-wondering2:before {\n  content: \"\\e337\";\n}\n.im-cursor:before {\n  content: \"\\e338\";\n}\n.im-cursor2:before {\n  content: \"\\e339\";\n}\n.im-point-up:before {\n  content: \"\\e33a\";\n}\n.im-point-right:before {\n  content: \"\\e33b\";\n}\n.im-point-down:before {\n  content: \"\\e33c\";\n}\n.im-point-left:before {\n  content: \"\\e33d\";\n}\n.im-pointer:before {\n  content: \"\\e33e\";\n}\n.im-hand:before {\n  content: \"\\e33f\";\n}\n.im-stack-empty:before {\n  content: \"\\e340\";\n}\n.im-stack-plus:before {\n  content: \"\\e341\";\n}\n.im-stack-minus:before {\n  content: \"\\e342\";\n}\n.im-stack-star:before {\n  content: \"\\e343\";\n}\n.im-stack-picture:before {\n  content: \"\\e344\";\n}\n.im-stack-down:before {\n  content: \"\\e345\";\n}\n.im-stack-up:before {\n  content: \"\\e346\";\n}\n.im-stack-cancel:before {\n  content: \"\\e347\";\n}\n.im-stack-checkmark:before {\n  content: \"\\e348\";\n}\n.im-stack-list:before {\n  content: \"\\e349\";\n}\n.im-stack-clubs:before {\n  content: \"\\e34a\";\n}\n.im-stack-spades:before {\n  content: \"\\e34b\";\n}\n.im-stack-hearts:before {\n  content: \"\\e34c\";\n}\n.im-stack-diamonds:before {\n  content: \"\\e34d\";\n}\n.im-stack-user:before {\n  content: \"\\e34e\";\n}\n.im-stack4:before {\n  content: \"\\e34f\";\n}\n.im-stack-music:before {\n  content: \"\\e350\";\n}\n.im-stack-play:before {\n  content: \"\\e351\";\n}\n.im-move:before {\n  content: \"\\e352\";\n}\n.im-resize:before {\n  content: \"\\e353\";\n}\n.im-resize2:before {\n  content: \"\\e354\";\n}\n.im-warning:before {\n  content: \"\\e355\";\n}\n.im-warning2:before {\n  content: \"\\e356\";\n}\n.im-notification:before {\n  content: \"\\e357\";\n}\n.im-notification2:before {\n  content: \"\\e358\";\n}\n.im-question:before {\n  content: \"\\e359\";\n}\n.im-question2:before {\n  content: \"\\e35a\";\n}\n.im-question3:before {\n  content: \"\\e35b\";\n}\n.im-question4:before {\n  content: \"\\e35c\";\n}\n.im-question5:before {\n  content: \"\\e35d\";\n}\n.im-plus-circle:before {\n  content: \"\\e35e\";\n}\n.im-plus-circle2:before {\n  content: \"\\e35f\";\n}\n.im-minus-circle:before {\n  content: \"\\e360\";\n}\n.im-minus-circle2:before {\n  content: \"\\e361\";\n}\n.im-info:before {\n  content: \"\\e362\";\n}\n.im-info2:before {\n  content: \"\\e363\";\n}\n.im-blocked:before {\n  content: \"\\e364\";\n}\n.im-cancel-circle:before {\n  content: \"\\e365\";\n}\n.im-cancel-circle2:before {\n  content: \"\\e366\";\n}\n.im-checkmark-circle:before {\n  content: \"\\e367\";\n}\n.im-checkmark-circle2:before {\n  content: \"\\e368\";\n}\n.im-cancel:before {\n  content: \"\\e369\";\n}\n.im-spam:before {\n  content: \"\\e36a\";\n}\n.im-close:before {\n  content: \"\\e36b\";\n}\n.im-close2:before {\n  content: \"\\e36c\";\n}\n.im-close3:before {\n  content: \"\\e36d\";\n}\n.im-close4:before {\n  content: \"\\e36e\";\n}\n.im-close5:before {\n  content: \"\\e36f\";\n}\n.im-checkmark:before {\n  content: \"\\e370\";\n}\n.im-checkmark2:before {\n  content: \"\\e371\";\n}\n.im-checkmark3:before {\n  content: \"\\e372\";\n}\n.im-checkmark4:before {\n  content: \"\\e373\";\n}\n.im-spell-check:before {\n  content: \"\\e374\";\n}\n.im-minus:before {\n  content: \"\\e375\";\n}\n.im-plus:before {\n  content: \"\\e376\";\n}\n.im-minus2:before {\n  content: \"\\e377\";\n}\n.im-plus2:before {\n  content: \"\\e378\";\n}\n.im-enter:before {\n  content: \"\\e379\";\n}\n.im-exit:before {\n  content: \"\\e37a\";\n}\n.im-enter2:before {\n  content: \"\\e37b\";\n}\n.im-exit2:before {\n  content: \"\\e37c\";\n}\n.im-enter3:before {\n  content: \"\\e37d\";\n}\n.im-exit3:before {\n  content: \"\\e37e\";\n}\n.im-exit4:before {\n  content: \"\\e37f\";\n}\n.im-play3:before {\n  content: \"\\e380\";\n}\n.im-pause:before {\n  content: \"\\e381\";\n}\n.im-stop:before {\n  content: \"\\e382\";\n}\n.im-backward:before {\n  content: \"\\e383\";\n}\n.im-forward2:before {\n  content: \"\\e384\";\n}\n.im-play4:before {\n  content: \"\\e385\";\n}\n.im-pause2:before {\n  content: \"\\e386\";\n}\n.im-stop2:before {\n  content: \"\\e387\";\n}\n.im-backward2:before {\n  content: \"\\e388\";\n}\n.im-forward3:before {\n  content: \"\\e389\";\n}\n.im-first:before {\n  content: \"\\e38a\";\n}\n.im-last:before {\n  content: \"\\e38b\";\n}\n.im-previous:before {\n  content: \"\\e38c\";\n}\n.im-next:before {\n  content: \"\\e38d\";\n}\n.im-eject:before {\n  content: \"\\e38e\";\n}\n.im-volume-high:before {\n  content: \"\\e38f\";\n}\n.im-volume-medium:before {\n  content: \"\\e390\";\n}\n.im-volume-low:before {\n  content: \"\\e391\";\n}\n.im-volume-mute:before {\n  content: \"\\e392\";\n}\n.im-volume-mute2:before {\n  content: \"\\e393\";\n}\n.im-volume-increase:before {\n  content: \"\\e394\";\n}\n.im-volume-decrease:before {\n  content: \"\\e395\";\n}\n.im-volume-high2:before {\n  content: \"\\e396\";\n}\n.im-volume-medium2:before {\n  content: \"\\e397\";\n}\n.im-volume-low2:before {\n  content: \"\\e398\";\n}\n.im-volume-mute3:before {\n  content: \"\\e399\";\n}\n.im-volume-mute4:before {\n  content: \"\\e39a\";\n}\n.im-volume-increase2:before {\n  content: \"\\e39b\";\n}\n.im-volume-decrease2:before {\n  content: \"\\e39c\";\n}\n.im-volume5:before {\n  content: \"\\e39d\";\n}\n.im-volume4:before {\n  content: \"\\e39e\";\n}\n.im-volume3:before {\n  content: \"\\e39f\";\n}\n.im-volume2:before {\n  content: \"\\e3a0\";\n}\n.im-volume1:before {\n  content: \"\\e3a1\";\n}\n.im-volume0:before {\n  content: \"\\e3a2\";\n}\n.im-volume-mute5:before {\n  content: \"\\e3a3\";\n}\n.im-volume-mute6:before {\n  content: \"\\e3a4\";\n}\n.im-loop:before {\n  content: \"\\e3a5\";\n}\n.im-loop2:before {\n  content: \"\\e3a6\";\n}\n.im-loop3:before {\n  content: \"\\e3a7\";\n}\n.im-loop4:before {\n  content: \"\\e3a8\";\n}\n.im-loop5:before {\n  content: \"\\e3a9\";\n}\n.im-shuffle:before {\n  content: \"\\e3aa\";\n}\n.im-shuffle2:before {\n  content: \"\\e3ab\";\n}\n.im-wave:before {\n  content: \"\\e3ac\";\n}\n.im-wave2:before {\n  content: \"\\e3ad\";\n}\n.im-arrow-first:before {\n  content: \"\\e3ae\";\n}\n.im-arrow-right:before {\n  content: \"\\e3af\";\n}\n.im-arrow-up:before {\n  content: \"\\e3b0\";\n}\n.im-arrow-right2:before {\n  content: \"\\e3b1\";\n}\n.im-arrow-down:before {\n  content: \"\\e3b2\";\n}\n.im-arrow-left:before {\n  content: \"\\e3b3\";\n}\n.im-arrow-up2:before {\n  content: \"\\e3b4\";\n}\n.im-arrow-right3:before {\n  content: \"\\e3b5\";\n}\n.im-arrow-down2:before {\n  content: \"\\e3b6\";\n}\n.im-arrow-left2:before {\n  content: \"\\e3b7\";\n}\n.im-arrow-up-left:before {\n  content: \"\\e3b8\";\n}\n.im-arrow-up3:before {\n  content: \"\\e3b9\";\n}\n.im-arrow-up-right:before {\n  content: \"\\e3ba\";\n}\n.im-arrow-right4:before {\n  content: \"\\e3bb\";\n}\n.im-arrow-down-right:before {\n  content: \"\\e3bc\";\n}\n.im-arrow-down3:before {\n  content: \"\\e3bd\";\n}\n.im-arrow-down-left:before {\n  content: \"\\e3be\";\n}\n.im-arrow-left3:before {\n  content: \"\\e3bf\";\n}\n.im-arrow-up-left2:before {\n  content: \"\\e3c0\";\n}\n.im-arrow-up4:before {\n  content: \"\\e3c1\";\n}\n.im-arrow-up-right2:before {\n  content: \"\\e3c2\";\n}\n.im-arrow-right5:before {\n  content: \"\\e3c3\";\n}\n.im-arrow-down-right2:before {\n  content: \"\\e3c4\";\n}\n.im-arrow-down4:before {\n  content: \"\\e3c5\";\n}\n.im-arrow-down-left2:before {\n  content: \"\\e3c6\";\n}\n.im-arrow-left4:before {\n  content: \"\\e3c7\";\n}\n.im-arrow-up-left3:before {\n  content: \"\\e3c8\";\n}\n.im-arrow-up5:before {\n  content: \"\\e3c9\";\n}\n.im-arrow-up-right3:before {\n  content: \"\\e3ca\";\n}\n.im-arrow-right6:before {\n  content: \"\\e3cb\";\n}\n.im-arrow-down-right3:before {\n  content: \"\\e3cc\";\n}\n.im-arrow-down5:before {\n  content: \"\\e3cd\";\n}\n.im-arrow-down-left3:before {\n  content: \"\\e3ce\";\n}\n.im-arrow-left5:before {\n  content: \"\\e3cf\";\n}\n.im-arrow-up-left4:before {\n  content: \"\\e3d0\";\n}\n.im-arrow-up6:before {\n  content: \"\\e3d1\";\n}\n.im-arrow-up-right4:before {\n  content: \"\\e3d2\";\n}\n.im-arrow-right7:before {\n  content: \"\\e3d3\";\n}\n.im-arrow-down-right4:before {\n  content: \"\\e3d4\";\n}\n.im-arrow-down6:before {\n  content: \"\\e3d5\";\n}\n.im-arrow-down-left4:before {\n  content: \"\\e3d6\";\n}\n.im-arrow-left6:before {\n  content: \"\\e3d7\";\n}\n.im-arrow:before {\n  content: \"\\e3d8\";\n}\n.im-arrow2:before {\n  content: \"\\e3d9\";\n}\n.im-arrow3:before {\n  content: \"\\e3da\";\n}\n.im-arrow4:before {\n  content: \"\\e3db\";\n}\n.im-arrow5:before {\n  content: \"\\e3dc\";\n}\n.im-arrow6:before {\n  content: \"\\e3dd\";\n}\n.im-arrow7:before {\n  content: \"\\e3de\";\n}\n.im-arrow8:before {\n  content: \"\\e3df\";\n}\n.im-arrow-up-left5:before {\n  content: \"\\e3e0\";\n}\n.im-arrowsquare:before {\n  content: \"\\e3e1\";\n}\n.im-arrow-up-right5:before {\n  content: \"\\e3e2\";\n}\n.im-arrow-right8:before {\n  content: \"\\e3e3\";\n}\n.im-arrow-down-right5:before {\n  content: \"\\e3e4\";\n}\n.im-arrow-down7:before {\n  content: \"\\e3e5\";\n}\n.im-arrow-down-left5:before {\n  content: \"\\e3e6\";\n}\n.im-arrow-left7:before {\n  content: \"\\e3e7\";\n}\n.im-arrow-up7:before {\n  content: \"\\e3e8\";\n}\n.im-arrow-right9:before {\n  content: \"\\e3e9\";\n}\n.im-arrow-down8:before {\n  content: \"\\e3ea\";\n}\n.im-arrow-left8:before {\n  content: \"\\e3eb\";\n}\n.im-arrow-up8:before {\n  content: \"\\e3ec\";\n}\n.im-arrow-right10:before {\n  content: \"\\e3ed\";\n}\n.im-arrow-bottom:before {\n  content: \"\\e3ee\";\n}\n.im-arrow-left9:before {\n  content: \"\\e3ef\";\n}\n.im-arrow-up-left6:before {\n  content: \"\\e3f0\";\n}\n.im-arrow-up9:before {\n  content: \"\\e3f1\";\n}\n.im-arrow-up-right6:before {\n  content: \"\\e3f2\";\n}\n.im-arrow-right11:before {\n  content: \"\\e3f3\";\n}\n.im-arrow-down-right6:before {\n  content: \"\\e3f4\";\n}\n.im-arrow-down9:before {\n  content: \"\\e3f5\";\n}\n.im-arrow-down-left6:before {\n  content: \"\\e3f6\";\n}\n.im-arrow-left10:before {\n  content: \"\\e3f7\";\n}\n.im-arrow-up-left7:before {\n  content: \"\\e3f8\";\n}\n.im-arrow-up10:before {\n  content: \"\\e3f9\";\n}\n.im-arrow-up-right7:before {\n  content: \"\\e3fa\";\n}\n.im-arrow-right12:before {\n  content: \"\\e3fb\";\n}\n.im-arrow-down-right7:before {\n  content: \"\\e3fc\";\n}\n.im-arrow-down10:before {\n  content: \"\\e3fd\";\n}\n.im-arrow-down-left7:before {\n  content: \"\\e3fe\";\n}\n.im-arrow-left11:before {\n  content: \"\\e3ff\";\n}\n.im-arrow-up11:before {\n  content: \"\\e400\";\n}\n.im-arrow-right13:before {\n  content: \"\\e401\";\n}\n.im-arrow-down11:before {\n  content: \"\\e402\";\n}\n.im-arrow-left12:before {\n  content: \"\\e403\";\n}\n.im-arrow-up12:before {\n  content: \"\\e404\";\n}\n.im-arrow-right14:before {\n  content: \"\\e405\";\n}\n.im-arrow-down12:before {\n  content: \"\\e406\";\n}\n.im-arrow-left13:before {\n  content: \"\\e407\";\n}\n.im-arrow-up13:before {\n  content: \"\\e408\";\n}\n.im-arrow-right15:before {\n  content: \"\\e409\";\n}\n.im-arrow-down13:before {\n  content: \"\\e40a\";\n}\n.im-arrow-left14:before {\n  content: \"\\e40b\";\n}\n.im-arrow-up14:before {\n  content: \"\\e40c\";\n}\n.im-arrow-right16:before {\n  content: \"\\e40d\";\n}\n.im-arrow-down14:before {\n  content: \"\\e40e\";\n}\n.im-arrow-left15:before {\n  content: \"\\e40f\";\n}\n.im-arrow-up15:before {\n  content: \"\\e410\";\n}\n.im-arrow-right17:before {\n  content: \"\\e411\";\n}\n.im-arrow-down15:before {\n  content: \"\\e412\";\n}\n.im-arrow-left16:before {\n  content: \"\\e413\";\n}\n.im-arrow-up16:before {\n  content: \"\\e414\";\n}\n.im-arrow-right18:before {\n  content: \"\\e415\";\n}\n.im-arrow-down16:before {\n  content: \"\\e416\";\n}\n.im-arrow-left17:before {\n  content: \"\\e417\";\n}\n.im-menu10:before {\n  content: \"\\e418\";\n}\n.im-menu11:before {\n  content: \"\\e419\";\n}\n.im-menu-close:before {\n  content: \"\\e41a\";\n}\n.im-menu-close2:before {\n  content: \"\\e41b\";\n}\n.im-enter4:before {\n  content: \"\\e41c\";\n}\n.im-enter5:before {\n  content: \"\\e41d\";\n}\n.im-esc:before {\n  content: \"\\e41e\";\n}\n.im-backspace:before {\n  content: \"\\e41f\";\n}\n.im-backspace2:before {\n  content: \"\\e420\";\n}\n.im-backspace3:before {\n  content: \"\\e421\";\n}\n.im-tab:before {\n  content: \"\\e422\";\n}\n.im-transmission:before {\n  content: \"\\e423\";\n}\n.im-transmission2:before {\n  content: \"\\e424\";\n}\n.im-sort:before {\n  content: \"\\e425\";\n}\n.im-sort2:before {\n  content: \"\\e426\";\n}\n.im-key-keyboard:before {\n  content: \"\\e427\";\n}\n.im-key-A:before {\n  content: \"\\e428\";\n}\n.im-key-up:before {\n  content: \"\\e429\";\n}\n.im-key-right:before {\n  content: \"\\e42a\";\n}\n.im-key-down:before {\n  content: \"\\e42b\";\n}\n.im-key-left:before {\n  content: \"\\e42c\";\n}\n.im-command:before {\n  content: \"\\e42d\";\n}\n.im-checkbox-checked:before {\n  content: \"\\e42e\";\n}\n.im-checkbox-unchecked:before {\n  content: \"\\e42f\";\n}\n.im-square:before {\n  content: \"\\e430\";\n}\n.im-checkbox-partial:before {\n  content: \"\\e431\";\n}\n.im-checkbox:before {\n  content: \"\\e432\";\n}\n.im-checkbox-unchecked2:before {\n  content: \"\\e433\";\n}\n.im-checkbox-partial2:before {\n  content: \"\\e434\";\n}\n.im-checkbox-checked2:before {\n  content: \"\\e435\";\n}\n.im-checkbox-unchecked3:before {\n  content: \"\\e436\";\n}\n.im-checkbox-partial3:before {\n  content: \"\\e437\";\n}\n.im-radio-checked:before {\n  content: \"\\e438\";\n}\n.im-radio-unchecked:before {\n  content: \"\\e439\";\n}\n.im-circle:before {\n  content: \"\\e43a\";\n}\n.im-circle2:before {\n  content: \"\\e43b\";\n}\n.im-crop:before {\n  content: \"\\e43c\";\n}\n.im-crop2:before {\n  content: \"\\e43d\";\n}\n.im-vector:before {\n  content: \"\\e43e\";\n}\n.im-rulers:before {\n  content: \"\\e43f\";\n}\n.im-scissors:before {\n  content: \"\\e440\";\n}\n.im-scissors2:before {\n  content: \"\\e441\";\n}\n.im-scissors3:before {\n  content: \"\\e442\";\n}\n.im-filter:before {\n  content: \"\\e443\";\n}\n.im-filter2:before {\n  content: \"\\e444\";\n}\n.im-filter3:before {\n  content: \"\\e445\";\n}\n.im-filter4:before {\n  content: \"\\e446\";\n}\n.im-font:before {\n  content: \"\\e447\";\n}\n.im-font-size:before {\n  content: \"\\e448\";\n}\n.im-type:before {\n  content: \"\\e449\";\n}\n.im-text-height:before {\n  content: \"\\e44a\";\n}\n.im-text-width:before {\n  content: \"\\e44b\";\n}\n.im-height:before {\n  content: \"\\e44c\";\n}\n.im-width:before {\n  content: \"\\e44d\";\n}\n.im-bold:before {\n  content: \"\\e44e\";\n}\n.im-underline:before {\n  content: \"\\e44f\";\n}\n.im-italic:before {\n  content: \"\\e450\";\n}\n.im-strikethrough:before {\n  content: \"\\e451\";\n}\n.im-strikethrough2:before {\n  content: \"\\e452\";\n}\n.im-font-size2:before {\n  content: \"\\e453\";\n}\n.im-bold2:before {\n  content: \"\\e454\";\n}\n.im-underline2:before {\n  content: \"\\e455\";\n}\n.im-italic2:before {\n  content: \"\\e456\";\n}\n.im-strikethrough3:before {\n  content: \"\\e457\";\n}\n.im-omega:before {\n  content: \"\\e458\";\n}\n.im-sigma:before {\n  content: \"\\e459\";\n}\n.im-nbsp:before {\n  content: \"\\e45a\";\n}\n.im-page-break:before {\n  content: \"\\e45b\";\n}\n.im-page-break2:before {\n  content: \"\\e45c\";\n}\n.im-superscript:before {\n  content: \"\\e45d\";\n}\n.im-subscript:before {\n  content: \"\\e45e\";\n}\n.im-superscript2:before {\n  content: \"\\e45f\";\n}\n.im-subscript2:before {\n  content: \"\\e460\";\n}\n.im-text-color:before {\n  content: \"\\e461\";\n}\n.im-highlight:before {\n  content: \"\\e462\";\n}\n.im-pagebreak:before {\n  content: \"\\e463\";\n}\n.im-clear-formatting:before {\n  content: \"\\e464\";\n}\n.im-table:before {\n  content: \"\\e465\";\n}\n.im-table2:before {\n  content: \"\\e466\";\n}\n.im-insert-template:before {\n  content: \"\\e467\";\n}\n.im-pilcrow:before {\n  content: \"\\e468\";\n}\n.im-lefttoright:before {\n  content: \"\\e469\";\n}\n.im-righttoleft:before {\n  content: \"\\e46a\";\n}\n.im-paragraph-left:before {\n  content: \"\\e46b\";\n}\n.im-paragraph-center:before {\n  content: \"\\e46c\";\n}\n.im-paragraph-right:before {\n  content: \"\\e46d\";\n}\n.im-paragraph-justify:before {\n  content: \"\\e46e\";\n}\n.im-paragraph-left2:before {\n  content: \"\\e46f\";\n}\n.im-paragraph-center2:before {\n  content: \"\\e470\";\n}\n.im-paragraph-right2:before {\n  content: \"\\e471\";\n}\n.im-paragraph-justify2:before {\n  content: \"\\e472\";\n}\n.im-indent-increase:before {\n  content: \"\\e473\";\n}\n.im-indent-decrease:before {\n  content: \"\\e474\";\n}\n.im-paragraph-left3:before {\n  content: \"\\e475\";\n}\n.im-paragraph-center3:before {\n  content: \"\\e476\";\n}\n.im-paragraph-right3:before {\n  content: \"\\e477\";\n}\n.im-paragraph-justify3:before {\n  content: \"\\e478\";\n}\n.im-indent-increase2:before {\n  content: \"\\e479\";\n}\n.im-indent-decrease2:before {\n  content: \"\\e47a\";\n}\n.im-share:before {\n  content: \"\\e47b\";\n}\n.im-newtab:before {\n  content: \"\\e47c\";\n}\n.im-newtab2:before {\n  content: \"\\e47d\";\n}\n.im-popout:before {\n  content: \"\\e47e\";\n}\n.im-embed:before {\n  content: \"\\e47f\";\n}\n.im-code:before {\n  content: \"\\e480\";\n}\n.im-console:before {\n  content: \"\\e481\";\n}\n.im-sevensegment0:before {\n  content: \"\\e482\";\n}\n.im-sevensegment1:before {\n  content: \"\\e483\";\n}\n.im-sevensegment2:before {\n  content: \"\\e484\";\n}\n.im-sevensegment3:before {\n  content: \"\\e485\";\n}\n.im-sevensegment4:before {\n  content: \"\\e486\";\n}\n.im-sevensegment5:before {\n  content: \"\\e487\";\n}\n.im-sevensegment6:before {\n  content: \"\\e488\";\n}\n.im-sevensegment7:before {\n  content: \"\\e489\";\n}\n.im-sevensegment8:before {\n  content: \"\\e48a\";\n}\n.im-sevensegment9:before {\n  content: \"\\e48b\";\n}\n.im-share2:before {\n  content: \"\\e48c\";\n}\n.im-share3:before {\n  content: \"\\e48d\";\n}\n.im-mail:before {\n  content: \"\\e48e\";\n}\n.im-mail2:before {\n  content: \"\\e48f\";\n}\n.im-mail3:before {\n  content: \"\\e490\";\n}\n.im-mail4:before {\n  content: \"\\e491\";\n}\n.im-google:before {\n  content: \"\\e492\";\n}\n.im-googleplus:before {\n  content: \"\\e493\";\n}\n.im-googleplus2:before {\n  content: \"\\e494\";\n}\n.im-googleplus3:before {\n  content: \"\\e495\";\n}\n.im-googleplus4:before {\n  content: \"\\e496\";\n}\n.im-google-drive:before {\n  content: \"\\e497\";\n}\n.im-facebook:before {\n  content: \"\\e498\";\n}\n.im-facebook2:before {\n  content: \"\\e499\";\n}\n.im-facebook3:before {\n  content: \"\\e49a\";\n}\n.im-facebook4:before {\n  content: \"\\e49b\";\n}\n.im-instagram:before {\n  content: \"\\e49c\";\n}\n.im-twitter:before {\n  content: \"\\e49d\";\n}\n.im-twitter2:before {\n  content: \"\\e49e\";\n}\n.im-twitter3:before {\n  content: \"\\e49f\";\n}\n.im-feed2:before {\n  content: \"\\e4a0\";\n}\n.im-feed3:before {\n  content: \"\\e4a1\";\n}\n.im-feed4:before {\n  content: \"\\e4a2\";\n}\n.im-youtube:before {\n  content: \"\\e4a3\";\n}\n.im-youtube2:before {\n  content: \"\\e4a4\";\n}\n.im-vimeo:before {\n  content: \"\\e4a5\";\n}\n.im-vimeo2:before {\n  content: \"\\e4a6\";\n}\n.im-vimeo3:before {\n  content: \"\\e4a7\";\n}\n.im-lanyrd:before {\n  content: \"\\e4a8\";\n}\n.im-flickr:before {\n  content: \"\\e4a9\";\n}\n.im-flickr2:before {\n  content: \"\\e4aa\";\n}\n.im-flickr3:before {\n  content: \"\\e4ab\";\n}\n.im-flickr4:before {\n  content: \"\\e4ac\";\n}\n.im-picassa:before {\n  content: \"\\e4ad\";\n}\n.im-picassa2:before {\n  content: \"\\e4ae\";\n}\n.im-dribbble:before {\n  content: \"\\e4af\";\n}\n.im-dribbble2:before {\n  content: \"\\e4b0\";\n}\n.im-dribbble3:before {\n  content: \"\\e4b1\";\n}\n.im-forrst:before {\n  content: \"\\e4b2\";\n}\n.im-forrst2:before {\n  content: \"\\e4b3\";\n}\n.im-deviantart:before {\n  content: \"\\e4b4\";\n}\n.im-deviantart2:before {\n  content: \"\\e4b5\";\n}\n.im-steam:before {\n  content: \"\\e4b6\";\n}\n.im-steam2:before {\n  content: \"\\e4b7\";\n}\n.im-github:before {\n  content: \"\\e4b8\";\n}\n.im-github2:before {\n  content: \"\\e4b9\";\n}\n.im-github3:before {\n  content: \"\\e4ba\";\n}\n.im-github4:before {\n  content: \"\\e4bb\";\n}\n.im-github5:before {\n  content: \"\\e4bc\";\n}\n.im-wordpress:before {\n  content: \"\\e4bd\";\n}\n.im-wordpress2:before {\n  content: \"\\e4be\";\n}\n.im-joomla:before {\n  content: \"\\e4bf\";\n}\n.im-blogger:before {\n  content: \"\\e4c0\";\n}\n.im-blogger2:before {\n  content: \"\\e4c1\";\n}\n.im-tumblr:before {\n  content: \"\\e4c2\";\n}\n.im-tumblr2:before {\n  content: \"\\e4c3\";\n}\n.im-yahoo:before {\n  content: \"\\e4c4\";\n}\n.im-tux:before {\n  content: \"\\e4c5\";\n}\n.im-apple:before {\n  content: \"\\e4c6\";\n}\n.im-finder:before {\n  content: \"\\e4c7\";\n}\n.im-android:before {\n  content: \"\\e4c8\";\n}\n.im-windows:before {\n  content: \"\\e4c9\";\n}\n.im-windows8:before {\n  content: \"\\e4ca\";\n}\n.im-soundcloud:before {\n  content: \"\\e4cb\";\n}\n.im-soundcloud2:before {\n  content: \"\\e4cc\";\n}\n.im-skype:before {\n  content: \"\\e4cd\";\n}\n.im-reddit:before {\n  content: \"\\e4ce\";\n}\n.im-linkedin:before {\n  content: \"\\e4cf\";\n}\n.im-lastfm:before {\n  content: \"\\e4d0\";\n}\n.im-lastfm2:before {\n  content: \"\\e4d1\";\n}\n.im-delicious:before {\n  content: \"\\e4d2\";\n}\n.im-stumbleupon:before {\n  content: \"\\e4d3\";\n}\n.im-stumbleupon2:before {\n  content: \"\\e4d4\";\n}\n.im-stackoverflow:before {\n  content: \"\\e4d5\";\n}\n.im-pinterest:before {\n  content: \"\\e4d6\";\n}\n.im-pinterest2:before {\n  content: \"\\e4d7\";\n}\n.im-xing:before {\n  content: \"\\e4d8\";\n}\n.im-xing2:before {\n  content: \"\\e4d9\";\n}\n.im-flattr:before {\n  content: \"\\e4da\";\n}\n.im-foursquare:before {\n  content: \"\\e4db\";\n}\n.im-foursquare2:before {\n  content: \"\\e4dc\";\n}\n.im-paypal:before {\n  content: \"\\e4dd\";\n}\n.im-paypal2:before {\n  content: \"\\e4de\";\n}\n.im-paypal3:before {\n  content: \"\\e4df\";\n}\n.im-yelp:before {\n  content: \"\\e4e0\";\n}\n.im-libreoffice:before {\n  content: \"\\e4e1\";\n}\n.im-file-pdf:before {\n  content: \"\\e4e2\";\n}\n.im-file-openoffice:before {\n  content: \"\\e4e3\";\n}\n.im-file-word:before {\n  content: \"\\e4e4\";\n}\n.im-file-excel:before {\n  content: \"\\e4e5\";\n}\n.im-file-zip:before {\n  content: \"\\e4e6\";\n}\n.im-file-powerpoint:before {\n  content: \"\\e4e7\";\n}\n.im-file-xml:before {\n  content: \"\\e4e8\";\n}\n.im-file-css:before {\n  content: \"\\e4e9\";\n}\n.im-html5:before {\n  content: \"\\e4ea\";\n}\n.im-html52:before {\n  content: \"\\e4eb\";\n}\n.im-css3:before {\n  content: \"\\e4ec\";\n}\n.im-chrome:before {\n  content: \"\\e4ed\";\n}\n.im-firefox:before {\n  content: \"\\e4ee\";\n}\n.im-IE:before {\n  content: \"\\e4ef\";\n}\n.im-opera:before {\n  content: \"\\e4f0\";\n}\n.im-safari:before {\n  content: \"\\e4f1\";\n}\n.im-IcoMoon:before {\n  content: \"\\e4f2\";\n}\n\n/* ------------------ Spin icon --------------------*/\n.icon-spin {\n  -webkit-animation: spin 2s infinite linear;\n  animation: spin 2s infinite linear;\n}\n@-webkit-keyframes spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n  }\n}\n@-ms-keyframes spin {\n  0% {\n    -ms-transform: rotate(0deg);\n  }\n  100% {\n    -ms-transform: rotate(359deg);\n  }\n}\n@keyframes spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n    transform: rotate(359deg);\n  }\n}\n\n/* Font awesome */\n/* makes the font 33% larger relative to the icon container */\n.fa-lg {\n  font-size: 1.33333333em;\n  line-height: 0.75em;\n  vertical-align: -15%;\n}\n.fa-2x {\n  font-size: 2em;\n}\n.fa-3x {\n  font-size: 3em;\n}\n.fa-4x {\n  font-size: 4em;\n}\n.fa-5x {\n  font-size: 5em;\n}\n.fa-fw {\n  width: 1.28571429em;\n  text-align: center;\n}\n.fa-ul {\n  padding-left: 0;\n  margin-left: 2.14285714em;\n  list-style-type: none;\n}\n.fa-ul > li {\n  position: relative;\n}\n.fa-li {\n  position: absolute;\n  left: -2.14285714em;\n  width: 2.14285714em;\n  top: 0.14285714em;\n  text-align: center;\n}\n.fa-li.fa-lg {\n  left: -1.85714286em;\n}\n.fa-border {\n  padding: .2em .25em .15em;\n  border: solid 0.08em #eeeeee;\n  border-radius: .1em;\n}\n.pull-right {\n  float: right;\n}\n.pull-left {\n  float: left;\n}\n.fa.pull-left {\n  margin-right: .3em;\n}\n.fa.pull-right {\n  margin-left: .3em;\n}\n.fa-spin {\n  -webkit-animation: spin 2s infinite linear;\n  animation: spin 2s infinite linear;\n}\n@-webkit-keyframes spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n  }\n}\n@keyframes spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n    transform: rotate(359deg);\n  }\n}\n.fa-rotate-90 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);\n  -webkit-transform: rotate(90deg);\n  -ms-transform: rotate(90deg);\n  transform: rotate(90deg);\n}\n.fa-rotate-180 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);\n  -webkit-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  transform: rotate(180deg);\n}\n.fa-rotate-270 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);\n  -webkit-transform: rotate(270deg);\n  -ms-transform: rotate(270deg);\n  transform: rotate(270deg);\n}\n.fa-flip-horizontal {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);\n  -webkit-transform: scale(-1, 1);\n  -ms-transform: scale(-1, 1);\n  transform: scale(-1, 1);\n}\n.fa-flip-vertical {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);\n  -webkit-transform: scale(1, -1);\n  -ms-transform: scale(1, -1);\n  transform: scale(1, -1);\n}\n.fa-stack {\n  position: relative;\n  display: inline-block;\n  width: 2em;\n  height: 2em;\n  line-height: 2em;\n  vertical-align: middle;\n}\n.fa-stack-1x,\n.fa-stack-2x {\n  position: absolute;\n  left: 0;\n  width: 100%;\n  text-align: center;\n}\n.fa-stack-1x {\n  line-height: inherit;\n}\n.fa-stack-2x {\n  font-size: 2em;\n}\n.fa-inverse {\n  color: #ffffff;\n}\n/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen\n   readers do not read off random characters that represent icons */\n.fa-glass:before {\n  content: \"\\f000\";\n}\n.fa-music:before {\n  content: \"\\f001\";\n}\n.fa-search:before {\n  content: \"\\f002\";\n}\n.fa-envelope-o:before {\n  content: \"\\f003\";\n}\n.fa-heart:before {\n  content: \"\\f004\";\n}\n.fa-star:before {\n  content: \"\\f005\";\n}\n.fa-star-o:before {\n  content: \"\\f006\";\n}\n.fa-user:before {\n  content: \"\\f007\";\n}\n.fa-film:before {\n  content: \"\\f008\";\n}\n.fa-th-large:before {\n  content: \"\\f009\";\n}\n.fa-th:before {\n  content: \"\\f00a\";\n}\n.fa-th-list:before {\n  content: \"\\f00b\";\n}\n.fa-check:before {\n  content: \"\\f00c\";\n}\n.fa-times:before {\n  content: \"\\f00d\";\n}\n.fa-search-plus:before {\n  content: \"\\f00e\";\n}\n.fa-search-minus:before {\n  content: \"\\f010\";\n}\n.fa-power-off:before {\n  content: \"\\f011\";\n}\n.fa-signal:before {\n  content: \"\\f012\";\n}\n.fa-gear:before,\n.fa-cog:before {\n  content: \"\\f013\";\n}\n.fa-trash-o:before {\n  content: \"\\f014\";\n}\n.fa-home:before {\n  content: \"\\f015\";\n}\n.fa-file-o:before {\n  content: \"\\f016\";\n}\n.fa-clock-o:before {\n  content: \"\\f017\";\n}\n.fa-road:before {\n  content: \"\\f018\";\n}\n.fa-download:before {\n  content: \"\\f019\";\n}\n.fa-arrow-circle-o-down:before {\n  content: \"\\f01a\";\n}\n.fa-arrow-circle-o-up:before {\n  content: \"\\f01b\";\n}\n.fa-inbox:before {\n  content: \"\\f01c\";\n}\n.fa-play-circle-o:before {\n  content: \"\\f01d\";\n}\n.fa-rotate-right:before,\n.fa-repeat:before {\n  content: \"\\f01e\";\n}\n.fa-refresh:before {\n  content: \"\\f021\";\n}\n.fa-list-alt:before {\n  content: \"\\f022\";\n}\n.fa-lock:before {\n  content: \"\\f023\";\n}\n.fa-flag:before {\n  content: \"\\f024\";\n}\n.fa-headphones:before {\n  content: \"\\f025\";\n}\n.fa-volume-off:before {\n  content: \"\\f026\";\n}\n.fa-volume-down:before {\n  content: \"\\f027\";\n}\n.fa-volume-up:before {\n  content: \"\\f028\";\n}\n.fa-qrcode:before {\n  content: \"\\f029\";\n}\n.fa-barcode:before {\n  content: \"\\f02a\";\n}\n.fa-tag:before {\n  content: \"\\f02b\";\n}\n.fa-tags:before {\n  content: \"\\f02c\";\n}\n.fa-book:before {\n  content: \"\\f02d\";\n}\n.fa-bookmark:before {\n  content: \"\\f02e\";\n}\n.fa-print:before {\n  content: \"\\f02f\";\n}\n.fa-camera:before {\n  content: \"\\f030\";\n}\n.fa-font:before {\n  content: \"\\f031\";\n}\n.fa-bold:before {\n  content: \"\\f032\";\n}\n.fa-italic:before {\n  content: \"\\f033\";\n}\n.fa-text-height:before {\n  content: \"\\f034\";\n}\n.fa-text-width:before {\n  content: \"\\f035\";\n}\n.fa-align-left:before {\n  content: \"\\f036\";\n}\n.fa-align-center:before {\n  content: \"\\f037\";\n}\n.fa-align-right:before {\n  content: \"\\f038\";\n}\n.fa-align-justify:before {\n  content: \"\\f039\";\n}\n.fa-list:before {\n  content: \"\\f03a\";\n}\n.fa-dedent:before,\n.fa-outdent:before {\n  content: \"\\f03b\";\n}\n.fa-indent:before {\n  content: \"\\f03c\";\n}\n.fa-video-camera:before {\n  content: \"\\f03d\";\n}\n.fa-photo:before,\n.fa-image:before,\n.fa-picture-o:before {\n  content: \"\\f03e\";\n}\n.fa-pencil:before {\n  content: \"\\f040\";\n}\n.fa-map-marker:before {\n  content: \"\\f041\";\n}\n.fa-adjust:before {\n  content: \"\\f042\";\n}\n.fa-tint:before {\n  content: \"\\f043\";\n}\n.fa-edit:before,\n.fa-pencil-square-o:before {\n  content: \"\\f044\";\n}\n.fa-share-square-o:before {\n  content: \"\\f045\";\n}\n.fa-check-square-o:before {\n  content: \"\\f046\";\n}\n.fa-arrows:before {\n  content: \"\\f047\";\n}\n.fa-step-backward:before {\n  content: \"\\f048\";\n}\n.fa-fast-backward:before {\n  content: \"\\f049\";\n}\n.fa-backward:before {\n  content: \"\\f04a\";\n}\n.fa-play:before {\n  content: \"\\f04b\";\n}\n.fa-pause:before {\n  content: \"\\f04c\";\n}\n.fa-stop:before {\n  content: \"\\f04d\";\n}\n.fa-forward:before {\n  content: \"\\f04e\";\n}\n.fa-fast-forward:before {\n  content: \"\\f050\";\n}\n.fa-step-forward:before {\n  content: \"\\f051\";\n}\n.fa-eject:before {\n  content: \"\\f052\";\n}\n.fa-chevron-left:before {\n  content: \"\\f053\";\n}\n.fa-chevron-right:before {\n  content: \"\\f054\";\n}\n.fa-plus-circle:before {\n  content: \"\\f055\";\n}\n.fa-minus-circle:before {\n  content: \"\\f056\";\n}\n.fa-times-circle:before {\n  content: \"\\f057\";\n}\n.fa-check-circle:before {\n  content: \"\\f058\";\n}\n.fa-question-circle:before {\n  content: \"\\f059\";\n}\n.fa-info-circle:before {\n  content: \"\\f05a\";\n}\n.fa-crosshairs:before {\n  content: \"\\f05b\";\n}\n.fa-times-circle-o:before {\n  content: \"\\f05c\";\n}\n.fa-check-circle-o:before {\n  content: \"\\f05d\";\n}\n.fa-ban:before {\n  content: \"\\f05e\";\n}\n.fa-arrow-left:before {\n  content: \"\\f060\";\n}\n.fa-arrow-right:before {\n  content: \"\\f061\";\n}\n.fa-arrow-up:before {\n  content: \"\\f062\";\n}\n.fa-arrow-down:before {\n  content: \"\\f063\";\n}\n.fa-mail-forward:before,\n.fa-share:before {\n  content: \"\\f064\";\n}\n.fa-expand:before {\n  content: \"\\f065\";\n}\n.fa-compress:before {\n  content: \"\\f066\";\n}\n.fa-plus:before {\n  content: \"\\f067\";\n}\n.fa-minus:before {\n  content: \"\\f068\";\n}\n.fa-asterisk:before {\n  content: \"\\f069\";\n}\n.fa-exclamation-circle:before {\n  content: \"\\f06a\";\n}\n.fa-gift:before {\n  content: \"\\f06b\";\n}\n.fa-leaf:before {\n  content: \"\\f06c\";\n}\n.fa-fire:before {\n  content: \"\\f06d\";\n}\n.fa-eye:before {\n  content: \"\\f06e\";\n}\n.fa-eye-slash:before {\n  content: \"\\f070\";\n}\n.fa-warning:before,\n.fa-exclamation-triangle:before {\n  content: \"\\f071\";\n}\n.fa-plane:before {\n  content: \"\\f072\";\n}\n.fa-calendar:before {\n  content: \"\\f073\";\n}\n.fa-random:before {\n  content: \"\\f074\";\n}\n.fa-comment:before {\n  content: \"\\f075\";\n}\n.fa-magnet:before {\n  content: \"\\f076\";\n}\n.fa-chevron-up:before {\n  content: \"\\f077\";\n}\n.fa-chevron-down:before {\n  content: \"\\f078\";\n}\n.fa-retweet:before {\n  content: \"\\f079\";\n}\n.fa-shopping-cart:before {\n  content: \"\\f07a\";\n}\n.fa-folder:before {\n  content: \"\\f07b\";\n}\n.fa-folder-open:before {\n  content: \"\\f07c\";\n}\n.fa-arrows-v:before {\n  content: \"\\f07d\";\n}\n.fa-arrows-h:before {\n  content: \"\\f07e\";\n}\n.fa-bar-chart-o:before {\n  content: \"\\f080\";\n}\n.fa-twitter-square:before {\n  content: \"\\f081\";\n}\n.fa-facebook-square:before {\n  content: \"\\f082\";\n}\n.fa-camera-retro:before {\n  content: \"\\f083\";\n}\n.fa-key:before {\n  content: \"\\f084\";\n}\n.fa-gears:before,\n.fa-cogs:before {\n  content: \"\\f085\";\n}\n.fa-comments:before {\n  content: \"\\f086\";\n}\n.fa-thumbs-o-up:before {\n  content: \"\\f087\";\n}\n.fa-thumbs-o-down:before {\n  content: \"\\f088\";\n}\n.fa-star-half:before {\n  content: \"\\f089\";\n}\n.fa-heart-o:before {\n  content: \"\\f08a\";\n}\n.fa-sign-out:before {\n  content: \"\\f08b\";\n}\n.fa-linkedin-square:before {\n  content: \"\\f08c\";\n}\n.fa-thumb-tack:before {\n  content: \"\\f08d\";\n}\n.fa-external-link:before {\n  content: \"\\f08e\";\n}\n.fa-sign-in:before {\n  content: \"\\f090\";\n}\n.fa-trophy:before {\n  content: \"\\f091\";\n}\n.fa-github-square:before {\n  content: \"\\f092\";\n}\n.fa-upload:before {\n  content: \"\\f093\";\n}\n.fa-lemon-o:before {\n  content: \"\\f094\";\n}\n.fa-phone:before {\n  content: \"\\f095\";\n}\n.fa-square-o:before {\n  content: \"\\f096\";\n}\n.fa-bookmark-o:before {\n  content: \"\\f097\";\n}\n.fa-phone-square:before {\n  content: \"\\f098\";\n}\n.fa-twitter:before {\n  content: \"\\f099\";\n}\n.fa-facebook:before {\n  content: \"\\f09a\";\n}\n.fa-github:before {\n  content: \"\\f09b\";\n}\n.fa-unlock:before {\n  content: \"\\f09c\";\n}\n.fa-credit-card:before {\n  content: \"\\f09d\";\n}\n.fa-rss:before {\n  content: \"\\f09e\";\n}\n.fa-hdd-o:before {\n  content: \"\\f0a0\";\n}\n.fa-bullhorn:before {\n  content: \"\\f0a1\";\n}\n.fa-bell:before {\n  content: \"\\f0f3\";\n}\n.fa-certificate:before {\n  content: \"\\f0a3\";\n}\n.fa-hand-o-right:before {\n  content: \"\\f0a4\";\n}\n.fa-hand-o-left:before {\n  content: \"\\f0a5\";\n}\n.fa-hand-o-up:before {\n  content: \"\\f0a6\";\n}\n.fa-hand-o-down:before {\n  content: \"\\f0a7\";\n}\n.fa-arrow-circle-left:before {\n  content: \"\\f0a8\";\n}\n.fa-arrow-circle-right:before {\n  content: \"\\f0a9\";\n}\n.fa-arrow-circle-up:before {\n  content: \"\\f0aa\";\n}\n.fa-arrow-circle-down:before {\n  content: \"\\f0ab\";\n}\n.fa-globe:before {\n  content: \"\\f0ac\";\n}\n.fa-wrench:before {\n  content: \"\\f0ad\";\n}\n.fa-tasks:before {\n  content: \"\\f0ae\";\n}\n.fa-filter:before {\n  content: \"\\f0b0\";\n}\n.fa-briefcase:before {\n  content: \"\\f0b1\";\n}\n.fa-arrows-alt:before {\n  content: \"\\f0b2\";\n}\n.fa-group:before,\n.fa-users:before {\n  content: \"\\f0c0\";\n}\n.fa-chain:before,\n.fa-link:before {\n  content: \"\\f0c1\";\n}\n.fa-cloud:before {\n  content: \"\\f0c2\";\n}\n.fa-flask:before {\n  content: \"\\f0c3\";\n}\n.fa-cut:before,\n.fa-scissors:before {\n  content: \"\\f0c4\";\n}\n.fa-copy:before,\n.fa-files-o:before {\n  content: \"\\f0c5\";\n}\n.fa-paperclip:before {\n  content: \"\\f0c6\";\n}\n.fa-save:before,\n.fa-floppy-o:before {\n  content: \"\\f0c7\";\n}\n.fa-square:before {\n  content: \"\\f0c8\";\n}\n.fa-navicon:before,\n.fa-reorder:before,\n.fa-bars:before {\n  content: \"\\f0c9\";\n}\n.fa-list-ul:before {\n  content: \"\\f0ca\";\n}\n.fa-list-ol:before {\n  content: \"\\f0cb\";\n}\n.fa-strikethrough:before {\n  content: \"\\f0cc\";\n}\n.fa-underline:before {\n  content: \"\\f0cd\";\n}\n.fa-table:before {\n  content: \"\\f0ce\";\n}\n.fa-magic:before {\n  content: \"\\f0d0\";\n}\n.fa-truck:before {\n  content: \"\\f0d1\";\n}\n.fa-pinterest:before {\n  content: \"\\f0d2\";\n}\n.fa-pinterest-square:before {\n  content: \"\\f0d3\";\n}\n.fa-google-plus-square:before {\n  content: \"\\f0d4\";\n}\n.fa-google-plus:before {\n  content: \"\\f0d5\";\n}\n.fa-money:before {\n  content: \"\\f0d6\";\n}\n.fa-caret-down:before {\n  content: \"\\f0d7\";\n}\n.fa-caret-up:before {\n  content: \"\\f0d8\";\n}\n.fa-caret-left:before {\n  content: \"\\f0d9\";\n}\n.fa-caret-right:before {\n  content: \"\\f0da\";\n}\n.fa-columns:before {\n  content: \"\\f0db\";\n}\n.fa-unsorted:before,\n.fa-sort:before {\n  content: \"\\f0dc\";\n}\n.fa-sort-down:before,\n.fa-sort-desc:before {\n  content: \"\\f0dd\";\n}\n.fa-sort-up:before,\n.fa-sort-asc:before {\n  content: \"\\f0de\";\n}\n.fa-envelope:before {\n  content: \"\\f0e0\";\n}\n.fa-linkedin:before {\n  content: \"\\f0e1\";\n}\n.fa-rotate-left:before,\n.fa-undo:before {\n  content: \"\\f0e2\";\n}\n.fa-legal:before,\n.fa-gavel:before {\n  content: \"\\f0e3\";\n}\n.fa-dashboard:before,\n.fa-tachometer:before {\n  content: \"\\f0e4\";\n}\n.fa-comment-o:before {\n  content: \"\\f0e5\";\n}\n.fa-comments-o:before {\n  content: \"\\f0e6\";\n}\n.fa-flash:before,\n.fa-bolt:before {\n  content: \"\\f0e7\";\n}\n.fa-sitemap:before {\n  content: \"\\f0e8\";\n}\n.fa-umbrella:before {\n  content: \"\\f0e9\";\n}\n.fa-paste:before,\n.fa-clipboard:before {\n  content: \"\\f0ea\";\n}\n.fa-lightbulb-o:before {\n  content: \"\\f0eb\";\n}\n.fa-exchange:before {\n  content: \"\\f0ec\";\n}\n.fa-cloud-download:before {\n  content: \"\\f0ed\";\n}\n.fa-cloud-upload:before {\n  content: \"\\f0ee\";\n}\n.fa-user-md:before {\n  content: \"\\f0f0\";\n}\n.fa-stethoscope:before {\n  content: \"\\f0f1\";\n}\n.fa-suitcase:before {\n  content: \"\\f0f2\";\n}\n.fa-bell-o:before {\n  content: \"\\f0a2\";\n}\n.fa-coffee:before {\n  content: \"\\f0f4\";\n}\n.fa-cutlery:before {\n  content: \"\\f0f5\";\n}\n.fa-file-text-o:before {\n  content: \"\\f0f6\";\n}\n.fa-building-o:before {\n  content: \"\\f0f7\";\n}\n.fa-hospital-o:before {\n  content: \"\\f0f8\";\n}\n.fa-ambulance:before {\n  content: \"\\f0f9\";\n}\n.fa-medkit:before {\n  content: \"\\f0fa\";\n}\n.fa-fighter-jet:before {\n  content: \"\\f0fb\";\n}\n.fa-beer:before {\n  content: \"\\f0fc\";\n}\n.fa-h-square:before {\n  content: \"\\f0fd\";\n}\n.fa-plus-square:before {\n  content: \"\\f0fe\";\n}\n.fa-angle-double-left:before {\n  content: \"\\f100\";\n}\n.fa-angle-double-right:before {\n  content: \"\\f101\";\n}\n.fa-angle-double-up:before {\n  content: \"\\f102\";\n}\n.fa-angle-double-down:before {\n  content: \"\\f103\";\n}\n.fa-angle-left:before {\n  content: \"\\f104\";\n}\n.fa-angle-right:before {\n  content: \"\\f105\";\n}\n.fa-angle-up:before {\n  content: \"\\f106\";\n}\n.fa-angle-down:before {\n  content: \"\\f107\";\n}\n.fa-desktop:before {\n  content: \"\\f108\";\n}\n.fa-laptop:before {\n  content: \"\\f109\";\n}\n.fa-tablet:before {\n  content: \"\\f10a\";\n}\n.fa-mobile-phone:before,\n.fa-mobile:before {\n  content: \"\\f10b\";\n}\n.fa-circle-o:before {\n  content: \"\\f10c\";\n}\n.fa-quote-left:before {\n  content: \"\\f10d\";\n}\n.fa-quote-right:before {\n  content: \"\\f10e\";\n}\n.fa-spinner:before {\n  content: \"\\f110\";\n}\n.fa-circle:before {\n  content: \"\\f111\";\n}\n.fa-mail-reply:before,\n.fa-reply:before {\n  content: \"\\f112\";\n}\n.fa-github-alt:before {\n  content: \"\\f113\";\n}\n.fa-folder-o:before {\n  content: \"\\f114\";\n}\n.fa-folder-open-o:before {\n  content: \"\\f115\";\n}\n.fa-smile-o:before {\n  content: \"\\f118\";\n}\n.fa-frown-o:before {\n  content: \"\\f119\";\n}\n.fa-meh-o:before {\n  content: \"\\f11a\";\n}\n.fa-gamepad:before {\n  content: \"\\f11b\";\n}\n.fa-keyboard-o:before {\n  content: \"\\f11c\";\n}\n.fa-flag-o:before {\n  content: \"\\f11d\";\n}\n.fa-flag-checkered:before {\n  content: \"\\f11e\";\n}\n.fa-terminal:before {\n  content: \"\\f120\";\n}\n.fa-code:before {\n  content: \"\\f121\";\n}\n.fa-mail-reply-all:before,\n.fa-reply-all:before {\n  content: \"\\f122\";\n}\n.fa-star-half-empty:before,\n.fa-star-half-full:before,\n.fa-star-half-o:before {\n  content: \"\\f123\";\n}\n.fa-location-arrow:before {\n  content: \"\\f124\";\n}\n.fa-crop:before {\n  content: \"\\f125\";\n}\n.fa-code-fork:before {\n  content: \"\\f126\";\n}\n.fa-unlink:before,\n.fa-chain-broken:before {\n  content: \"\\f127\";\n}\n.fa-question:before {\n  content: \"\\f128\";\n}\n.fa-info:before {\n  content: \"\\f129\";\n}\n.fa-exclamation:before {\n  content: \"\\f12a\";\n}\n.fa-superscript:before {\n  content: \"\\f12b\";\n}\n.fa-subscript:before {\n  content: \"\\f12c\";\n}\n.fa-eraser:before {\n  content: \"\\f12d\";\n}\n.fa-puzzle-piece:before {\n  content: \"\\f12e\";\n}\n.fa-microphone:before {\n  content: \"\\f130\";\n}\n.fa-microphone-slash:before {\n  content: \"\\f131\";\n}\n.fa-shield:before {\n  content: \"\\f132\";\n}\n.fa-calendar-o:before {\n  content: \"\\f133\";\n}\n.fa-fire-extinguisher:before {\n  content: \"\\f134\";\n}\n.fa-rocket:before {\n  content: \"\\f135\";\n}\n.fa-maxcdn:before {\n  content: \"\\f136\";\n}\n.fa-chevron-circle-left:before {\n  content: \"\\f137\";\n}\n.fa-chevron-circle-right:before {\n  content: \"\\f138\";\n}\n.fa-chevron-circle-up:before {\n  content: \"\\f139\";\n}\n.fa-chevron-circle-down:before {\n  content: \"\\f13a\";\n}\n.fa-html5:before {\n  content: \"\\f13b\";\n}\n.fa-css3:before {\n  content: \"\\f13c\";\n}\n.fa-anchor:before {\n  content: \"\\f13d\";\n}\n.fa-unlock-alt:before {\n  content: \"\\f13e\";\n}\n.fa-bullseye:before {\n  content: \"\\f140\";\n}\n.fa-ellipsis-h:before {\n  content: \"\\f141\";\n}\n.fa-ellipsis-v:before {\n  content: \"\\f142\";\n}\n.fa-rss-square:before {\n  content: \"\\f143\";\n}\n.fa-play-circle:before {\n  content: \"\\f144\";\n}\n.fa-ticket:before {\n  content: \"\\f145\";\n}\n.fa-minus-square:before {\n  content: \"\\f146\";\n}\n.fa-minus-square-o:before {\n  content: \"\\f147\";\n}\n.fa-level-up:before {\n  content: \"\\f148\";\n}\n.fa-level-down:before {\n  content: \"\\f149\";\n}\n.fa-check-square:before {\n  content: \"\\f14a\";\n}\n.fa-pencil-square:before {\n  content: \"\\f14b\";\n}\n.fa-external-link-square:before {\n  content: \"\\f14c\";\n}\n.fa-share-square:before {\n  content: \"\\f14d\";\n}\n.fa-compass:before {\n  content: \"\\f14e\";\n}\n.fa-toggle-down:before,\n.fa-caret-square-o-down:before {\n  content: \"\\f150\";\n}\n.fa-toggle-up:before,\n.fa-caret-square-o-up:before {\n  content: \"\\f151\";\n}\n.fa-toggle-right:before,\n.fa-caret-square-o-right:before {\n  content: \"\\f152\";\n}\n.fa-euro:before,\n.fa-eur:before {\n  content: \"\\f153\";\n}\n.fa-gbp:before {\n  content: \"\\f154\";\n}\n.fa-dollar:before,\n.fa-usd:before {\n  content: \"\\f155\";\n}\n.fa-rupee:before,\n.fa-inr:before {\n  content: \"\\f156\";\n}\n.fa-cny:before,\n.fa-rmb:before,\n.fa-yen:before,\n.fa-jpy:before {\n  content: \"\\f157\";\n}\n.fa-ruble:before,\n.fa-rouble:before,\n.fa-rub:before {\n  content: \"\\f158\";\n}\n.fa-won:before,\n.fa-krw:before {\n  content: \"\\f159\";\n}\n.fa-bitcoin:before,\n.fa-btc:before {\n  content: \"\\f15a\";\n}\n.fa-file:before {\n  content: \"\\f15b\";\n}\n.fa-file-text:before {\n  content: \"\\f15c\";\n}\n.fa-sort-alpha-asc:before {\n  content: \"\\f15d\";\n}\n.fa-sort-alpha-desc:before {\n  content: \"\\f15e\";\n}\n.fa-sort-amount-asc:before {\n  content: \"\\f160\";\n}\n.fa-sort-amount-desc:before {\n  content: \"\\f161\";\n}\n.fa-sort-numeric-asc:before {\n  content: \"\\f162\";\n}\n.fa-sort-numeric-desc:before {\n  content: \"\\f163\";\n}\n.fa-thumbs-up:before {\n  content: \"\\f164\";\n}\n.fa-thumbs-down:before {\n  content: \"\\f165\";\n}\n.fa-youtube-square:before {\n  content: \"\\f166\";\n}\n.fa-youtube:before {\n  content: \"\\f167\";\n}\n.fa-xing:before {\n  content: \"\\f168\";\n}\n.fa-xing-square:before {\n  content: \"\\f169\";\n}\n.fa-youtube-play:before {\n  content: \"\\f16a\";\n}\n.fa-dropbox:before {\n  content: \"\\f16b\";\n}\n.fa-stack-overflow:before {\n  content: \"\\f16c\";\n}\n.fa-instagram:before {\n  content: \"\\f16d\";\n}\n.fa-flickr:before {\n  content: \"\\f16e\";\n}\n.fa-adn:before {\n  content: \"\\f170\";\n}\n.fa-bitbucket:before {\n  content: \"\\f171\";\n}\n.fa-bitbucket-square:before {\n  content: \"\\f172\";\n}\n.fa-tumblr:before {\n  content: \"\\f173\";\n}\n.fa-tumblr-square:before {\n  content: \"\\f174\";\n}\n.fa-long-arrow-down:before {\n  content: \"\\f175\";\n}\n.fa-long-arrow-up:before {\n  content: \"\\f176\";\n}\n.fa-long-arrow-left:before {\n  content: \"\\f177\";\n}\n.fa-long-arrow-right:before {\n  content: \"\\f178\";\n}\n.fa-apple:before {\n  content: \"\\f179\";\n}\n.fa-windows:before {\n  content: \"\\f17a\";\n}\n.fa-android:before {\n  content: \"\\f17b\";\n}\n.fa-linux:before {\n  content: \"\\f17c\";\n}\n.fa-dribbble:before {\n  content: \"\\f17d\";\n}\n.fa-skype:before {\n  content: \"\\f17e\";\n}\n.fa-foursquare:before {\n  content: \"\\f180\";\n}\n.fa-trello:before {\n  content: \"\\f181\";\n}\n.fa-female:before {\n  content: \"\\f182\";\n}\n.fa-male:before {\n  content: \"\\f183\";\n}\n.fa-gittip:before {\n  content: \"\\f184\";\n}\n.fa-sun-o:before {\n  content: \"\\f185\";\n}\n.fa-moon-o:before {\n  content: \"\\f186\";\n}\n.fa-archive:before {\n  content: \"\\f187\";\n}\n.fa-bug:before {\n  content: \"\\f188\";\n}\n.fa-vk:before {\n  content: \"\\f189\";\n}\n.fa-weibo:before {\n  content: \"\\f18a\";\n}\n.fa-renren:before {\n  content: \"\\f18b\";\n}\n.fa-pagelines:before {\n  content: \"\\f18c\";\n}\n.fa-stack-exchange:before {\n  content: \"\\f18d\";\n}\n.fa-arrow-circle-o-right:before {\n  content: \"\\f18e\";\n}\n.fa-arrow-circle-o-left:before {\n  content: \"\\f190\";\n}\n.fa-toggle-left:before,\n.fa-caret-square-o-left:before {\n  content: \"\\f191\";\n}\n.fa-dot-circle-o:before {\n  content: \"\\f192\";\n}\n.fa-wheelchair:before {\n  content: \"\\f193\";\n}\n.fa-vimeo-square:before {\n  content: \"\\f194\";\n}\n.fa-turkish-lira:before,\n.fa-try:before {\n  content: \"\\f195\";\n}\n.fa-plus-square-o:before {\n  content: \"\\f196\";\n}\n.fa-space-shuttle:before {\n  content: \"\\f197\";\n}\n.fa-slack:before {\n  content: \"\\f198\";\n}\n.fa-envelope-square:before {\n  content: \"\\f199\";\n}\n.fa-wordpress:before {\n  content: \"\\f19a\";\n}\n.fa-openid:before {\n  content: \"\\f19b\";\n}\n.fa-institution:before,\n.fa-bank:before,\n.fa-university:before {\n  content: \"\\f19c\";\n}\n.fa-mortar-board:before,\n.fa-graduation-cap:before {\n  content: \"\\f19d\";\n}\n.fa-yahoo:before {\n  content: \"\\f19e\";\n}\n.fa-google:before {\n  content: \"\\f1a0\";\n}\n.fa-reddit:before {\n  content: \"\\f1a1\";\n}\n.fa-reddit-square:before {\n  content: \"\\f1a2\";\n}\n.fa-stumbleupon-circle:before {\n  content: \"\\f1a3\";\n}\n.fa-stumbleupon:before {\n  content: \"\\f1a4\";\n}\n.fa-delicious:before {\n  content: \"\\f1a5\";\n}\n.fa-digg:before {\n  content: \"\\f1a6\";\n}\n.fa-pied-piper-square:before,\n.fa-pied-piper:before {\n  content: \"\\f1a7\";\n}\n.fa-pied-piper-alt:before {\n  content: \"\\f1a8\";\n}\n.fa-drupal:before {\n  content: \"\\f1a9\";\n}\n.fa-joomla:before {\n  content: \"\\f1aa\";\n}\n.fa-language:before {\n  content: \"\\f1ab\";\n}\n.fa-fax:before {\n  content: \"\\f1ac\";\n}\n.fa-building:before {\n  content: \"\\f1ad\";\n}\n.fa-child:before {\n  content: \"\\f1ae\";\n}\n.fa-paw:before {\n  content: \"\\f1b0\";\n}\n.fa-spoon:before {\n  content: \"\\f1b1\";\n}\n.fa-cube:before {\n  content: \"\\f1b2\";\n}\n.fa-cubes:before {\n  content: \"\\f1b3\";\n}\n.fa-behance:before {\n  content: \"\\f1b4\";\n}\n.fa-behance-square:before {\n  content: \"\\f1b5\";\n}\n.fa-steam:before {\n  content: \"\\f1b6\";\n}\n.fa-steam-square:before {\n  content: \"\\f1b7\";\n}\n.fa-recycle:before {\n  content: \"\\f1b8\";\n}\n.fa-automobile:before,\n.fa-car:before {\n  content: \"\\f1b9\";\n}\n.fa-cab:before,\n.fa-taxi:before {\n  content: \"\\f1ba\";\n}\n.fa-tree:before {\n  content: \"\\f1bb\";\n}\n.fa-spotify:before {\n  content: \"\\f1bc\";\n}\n.fa-deviantart:before {\n  content: \"\\f1bd\";\n}\n.fa-soundcloud:before {\n  content: \"\\f1be\";\n}\n.fa-database:before {\n  content: \"\\f1c0\";\n}\n.fa-file-pdf-o:before {\n  content: \"\\f1c1\";\n}\n.fa-file-word-o:before {\n  content: \"\\f1c2\";\n}\n.fa-file-excel-o:before {\n  content: \"\\f1c3\";\n}\n.fa-file-powerpoint-o:before {\n  content: \"\\f1c4\";\n}\n.fa-file-photo-o:before,\n.fa-file-picture-o:before,\n.fa-file-image-o:before {\n  content: \"\\f1c5\";\n}\n.fa-file-zip-o:before,\n.fa-file-archive-o:before {\n  content: \"\\f1c6\";\n}\n.fa-file-sound-o:before,\n.fa-file-audio-o:before {\n  content: \"\\f1c7\";\n}\n.fa-file-movie-o:before,\n.fa-file-video-o:before {\n  content: \"\\f1c8\";\n}\n.fa-file-code-o:before {\n  content: \"\\f1c9\";\n}\n.fa-vine:before {\n  content: \"\\f1ca\";\n}\n.fa-codepen:before {\n  content: \"\\f1cb\";\n}\n.fa-jsfiddle:before {\n  content: \"\\f1cc\";\n}\n.fa-life-bouy:before,\n.fa-life-saver:before,\n.fa-support:before,\n.fa-life-ring:before {\n  content: \"\\f1cd\";\n}\n.fa-circle-o-notch:before {\n  content: \"\\f1ce\";\n}\n.fa-ra:before,\n.fa-rebel:before {\n  content: \"\\f1d0\";\n}\n.fa-ge:before,\n.fa-empire:before {\n  content: \"\\f1d1\";\n}\n.fa-git-square:before {\n  content: \"\\f1d2\";\n}\n.fa-git:before {\n  content: \"\\f1d3\";\n}\n.fa-hacker-news:before {\n  content: \"\\f1d4\";\n}\n.fa-tencent-weibo:before {\n  content: \"\\f1d5\";\n}\n.fa-qq:before {\n  content: \"\\f1d6\";\n}\n.fa-wechat:before,\n.fa-weixin:before {\n  content: \"\\f1d7\";\n}\n.fa-send:before,\n.fa-paper-plane:before {\n  content: \"\\f1d8\";\n}\n.fa-send-o:before,\n.fa-paper-plane-o:before {\n  content: \"\\f1d9\";\n}\n.fa-history:before {\n  content: \"\\f1da\";\n}\n.fa-circle-thin:before {\n  content: \"\\f1db\";\n}\n.fa-header:before {\n  content: \"\\f1dc\";\n}\n.fa-paragraph:before {\n  content: \"\\f1dd\";\n}\n.fa-sliders:before {\n  content: \"\\f1de\";\n}\n.fa-share-alt:before {\n  content: \"\\f1e0\";\n}\n.fa-share-alt-square:before {\n  content: \"\\f1e1\";\n}\n.fa-bomb:before {\n  content: \"\\f1e2\";\n}"
  },
  {
    "path": "static/css/lib/bootstrap/bootstrap3.css",
    "content": "/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n    font-family: sans-serif;\n    -webkit-text-size-adjust: 100%;\n        -ms-text-size-adjust: 100%;\n  }\n  body {\n    margin: 0;\n  }\n  article,\n  aside,\n  details,\n  figcaption,\n  figure,\n  footer,\n  header,\n  hgroup,\n  main,\n  menu,\n  nav,\n  section,\n  summary {\n    display: block;\n  }\n  audio,\n  canvas,\n  progress,\n  video {\n    display: inline-block;\n    vertical-align: baseline;\n  }\n  audio:not([controls]) {\n    display: none;\n    height: 0;\n  }\n  [hidden],\n  template {\n    display: none;\n  }\n  a {\n    background-color: transparent;\n  }\n  a:active,\n  a:hover {\n    outline: 0;\n  }\n  abbr[title] {\n    border-bottom: 1px dotted;\n  }\n  b,\n  strong {\n    font-weight: bold;\n  }\n  dfn {\n    font-style: italic;\n  }\n  h1 {\n    margin: .67em 0;\n    font-size: 2em;\n  }\n  mark {\n    color: #000;\n    background: #ff0;\n  }\n  small {\n    font-size: 80%;\n  }\n  sub,\n  sup {\n    position: relative;\n    font-size: 75%;\n    line-height: 0;\n    vertical-align: baseline;\n  }\n  sup {\n    top: -.5em;\n  }\n  sub {\n    bottom: -.25em;\n  }\n  img {\n    border: 0;\n  }\n  svg:not(:root) {\n    overflow: hidden;\n  }\n  figure {\n    margin: 1em 40px;\n  }\n  hr {\n    height: 0;\n    -webkit-box-sizing: content-box;\n       -moz-box-sizing: content-box;\n            box-sizing: content-box;\n  }\n  pre {\n    overflow: auto;\n  }\n  code,\n  kbd,\n  pre,\n  samp {\n    font-family: monospace, monospace;\n    font-size: 1em;\n  }\n  button,\n  input,\n  optgroup,\n  select,\n  textarea {\n    margin: 0;\n    font: inherit;\n    color: inherit;\n  }\n  button {\n    overflow: visible;\n  }\n  button,\n  select {\n    text-transform: none;\n  }\n  button,\n  html input[type=\"button\"],\n  input[type=\"reset\"],\n  input[type=\"submit\"] {\n    -webkit-appearance: button;\n    cursor: pointer;\n  }\n  button[disabled],\n  html input[disabled] {\n    cursor: default;\n  }\n  button::-moz-focus-inner,\n  input::-moz-focus-inner {\n    padding: 0;\n    border: 0;\n  }\n  input {\n    line-height: normal;\n  }\n  input[type=\"checkbox\"],\n  input[type=\"radio\"] {\n    -webkit-box-sizing: border-box;\n       -moz-box-sizing: border-box;\n            box-sizing: border-box;\n    padding: 0;\n  }\n  input[type=\"number\"]::-webkit-inner-spin-button,\n  input[type=\"number\"]::-webkit-outer-spin-button {\n    height: auto;\n  }\n  input[type=\"search\"] {\n    -webkit-box-sizing: content-box;\n       -moz-box-sizing: content-box;\n            box-sizing: content-box;\n    -webkit-appearance: textfield;\n  }\n  input[type=\"search\"]::-webkit-search-cancel-button,\n  input[type=\"search\"]::-webkit-search-decoration {\n    -webkit-appearance: none;\n  }\n  fieldset {\n    padding: .35em .625em .75em;\n    margin: 0 2px;\n    border: 1px solid #c0c0c0;\n  }\n  legend {\n    padding: 0;\n    border: 0;\n  }\n  textarea {\n    overflow: auto;\n  }\n  optgroup {\n    font-weight: bold;\n  }\n  table {\n    border-spacing: 0;\n    border-collapse: collapse;\n  }\n  td,\n  th {\n    padding: 0;\n  }\n  /*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n  @media print {\n    *,\n    *:before,\n    *:after {\n      color: #000 !important;\n      text-shadow: none !important;\n      background: transparent !important;\n      -webkit-box-shadow: none !important;\n              box-shadow: none !important;\n    }\n    a,\n    a:visited {\n      text-decoration: underline;\n    }\n    a[href]:after {\n      content: \" (\" attr(href) \")\";\n    }\n    abbr[title]:after {\n      content: \" (\" attr(title) \")\";\n    }\n    a[href^=\"#\"]:after,\n    a[href^=\"javascript:\"]:after {\n      content: \"\";\n    }\n    pre,\n    blockquote {\n      border: 1px solid #999;\n  \n      page-break-inside: avoid;\n    }\n    thead {\n      display: table-header-group;\n    }\n    tr,\n    img {\n      page-break-inside: avoid;\n    }\n    img {\n      max-width: 100% !important;\n    }\n    p,\n    h2,\n    h3 {\n      orphans: 3;\n      widows: 3;\n    }\n    h2,\n    h3 {\n      page-break-after: avoid;\n    }\n    .navbar {\n      display: none;\n    }\n    .btn > .caret,\n    .dropup > .btn > .caret {\n      border-top-color: #000 !important;\n    }\n    .label {\n      border: 1px solid #000;\n    }\n    .table {\n      border-collapse: collapse !important;\n    }\n    .table td,\n    .table th {\n      background-color: #fff !important;\n    }\n    .table-bordered th,\n    .table-bordered td {\n      border: 1px solid #ddd !important;\n    }\n  }\n  @font-face {\n    font-family: 'Glyphicons Halflings';\n  \n    src: url('../fonts/glyphicons-halflings-regular.eot');\n    src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');\n  }\n  .glyphicon {\n    position: relative;\n    top: 1px;\n    display: inline-block;\n    font-family: 'Glyphicons Halflings';\n    font-style: normal;\n    font-weight: normal;\n    line-height: 1;\n  \n    -webkit-font-smoothing: antialiased;\n    -moz-osx-font-smoothing: grayscale;\n  }\n  .glyphicon-asterisk:before {\n    content: \"\\002a\";\n  }\n  .glyphicon-plus:before {\n    content: \"\\002b\";\n  }\n  .glyphicon-euro:before,\n  .glyphicon-eur:before {\n    content: \"\\20ac\";\n  }\n  .glyphicon-minus:before {\n    content: \"\\2212\";\n  }\n  .glyphicon-cloud:before {\n    content: \"\\2601\";\n  }\n  .glyphicon-envelope:before {\n    content: \"\\2709\";\n  }\n  .glyphicon-pencil:before {\n    content: \"\\270f\";\n  }\n  .glyphicon-glass:before {\n    content: \"\\e001\";\n  }\n  .glyphicon-music:before {\n    content: \"\\e002\";\n  }\n  .glyphicon-search:before {\n    content: \"\\e003\";\n  }\n  .glyphicon-heart:before {\n    content: \"\\e005\";\n  }\n  .glyphicon-star:before {\n    content: \"\\e006\";\n  }\n  .glyphicon-star-empty:before {\n    content: \"\\e007\";\n  }\n  .glyphicon-user:before {\n    content: \"\\e008\";\n  }\n  .glyphicon-film:before {\n    content: \"\\e009\";\n  }\n  .glyphicon-th-large:before {\n    content: \"\\e010\";\n  }\n  .glyphicon-th:before {\n    content: \"\\e011\";\n  }\n  .glyphicon-th-list:before {\n    content: \"\\e012\";\n  }\n  .glyphicon-ok:before {\n    content: \"\\e013\";\n  }\n  .glyphicon-remove:before {\n    content: \"\\e014\";\n  }\n  .glyphicon-zoom-in:before {\n    content: \"\\e015\";\n  }\n  .glyphicon-zoom-out:before {\n    content: \"\\e016\";\n  }\n  .glyphicon-off:before {\n    content: \"\\e017\";\n  }\n  .glyphicon-signal:before {\n    content: \"\\e018\";\n  }\n  .glyphicon-cog:before {\n    content: \"\\e019\";\n  }\n  .glyphicon-trash:before {\n    content: \"\\e020\";\n  }\n  .glyphicon-home:before {\n    content: \"\\e021\";\n  }\n  .glyphicon-file:before {\n    content: \"\\e022\";\n  }\n  .glyphicon-time:before {\n    content: \"\\e023\";\n  }\n  .glyphicon-road:before {\n    content: \"\\e024\";\n  }\n  .glyphicon-download-alt:before {\n    content: \"\\e025\";\n  }\n  .glyphicon-download:before {\n    content: \"\\e026\";\n  }\n  .glyphicon-upload:before {\n    content: \"\\e027\";\n  }\n  .glyphicon-inbox:before {\n    content: \"\\e028\";\n  }\n  .glyphicon-play-circle:before {\n    content: \"\\e029\";\n  }\n  .glyphicon-repeat:before {\n    content: \"\\e030\";\n  }\n  .glyphicon-refresh:before {\n    content: \"\\e031\";\n  }\n  .glyphicon-list-alt:before {\n    content: \"\\e032\";\n  }\n  .glyphicon-lock:before {\n    content: \"\\e033\";\n  }\n  .glyphicon-flag:before {\n    content: \"\\e034\";\n  }\n  .glyphicon-headphones:before {\n    content: \"\\e035\";\n  }\n  .glyphicon-volume-off:before {\n    content: \"\\e036\";\n  }\n  .glyphicon-volume-down:before {\n    content: \"\\e037\";\n  }\n  .glyphicon-volume-up:before {\n    content: \"\\e038\";\n  }\n  .glyphicon-qrcode:before {\n    content: \"\\e039\";\n  }\n  .glyphicon-barcode:before {\n    content: \"\\e040\";\n  }\n  .glyphicon-tag:before {\n    content: \"\\e041\";\n  }\n  .glyphicon-tags:before {\n    content: \"\\e042\";\n  }\n  .glyphicon-book:before {\n    content: \"\\e043\";\n  }\n  .glyphicon-bookmark:before {\n    content: \"\\e044\";\n  }\n  .glyphicon-print:before {\n    content: \"\\e045\";\n  }\n  .glyphicon-camera:before {\n    content: \"\\e046\";\n  }\n  .glyphicon-font:before {\n    content: \"\\e047\";\n  }\n  .glyphicon-bold:before {\n    content: \"\\e048\";\n  }\n  .glyphicon-italic:before {\n    content: \"\\e049\";\n  }\n  .glyphicon-text-height:before {\n    content: \"\\e050\";\n  }\n  .glyphicon-text-width:before {\n    content: \"\\e051\";\n  }\n  .glyphicon-align-left:before {\n    content: \"\\e052\";\n  }\n  .glyphicon-align-center:before {\n    content: \"\\e053\";\n  }\n  .glyphicon-align-right:before {\n    content: \"\\e054\";\n  }\n  .glyphicon-align-justify:before {\n    content: \"\\e055\";\n  }\n  .glyphicon-list:before {\n    content: \"\\e056\";\n  }\n  .glyphicon-indent-left:before {\n    content: \"\\e057\";\n  }\n  .glyphicon-indent-right:before {\n    content: \"\\e058\";\n  }\n  .glyphicon-facetime-video:before {\n    content: \"\\e059\";\n  }\n  .glyphicon-picture:before {\n    content: \"\\e060\";\n  }\n  .glyphicon-map-marker:before {\n    content: \"\\e062\";\n  }\n  .glyphicon-adjust:before {\n    content: \"\\e063\";\n  }\n  .glyphicon-tint:before {\n    content: \"\\e064\";\n  }\n  .glyphicon-edit:before {\n    content: \"\\e065\";\n  }\n  .glyphicon-share:before {\n    content: \"\\e066\";\n  }\n  .glyphicon-check:before {\n    content: \"\\e067\";\n  }\n  .glyphicon-move:before {\n    content: \"\\e068\";\n  }\n  .glyphicon-step-backward:before {\n    content: \"\\e069\";\n  }\n  .glyphicon-fast-backward:before {\n    content: \"\\e070\";\n  }\n  .glyphicon-backward:before {\n    content: \"\\e071\";\n  }\n  .glyphicon-play:before {\n    content: \"\\e072\";\n  }\n  .glyphicon-pause:before {\n    content: \"\\e073\";\n  }\n  .glyphicon-stop:before {\n    content: \"\\e074\";\n  }\n  .glyphicon-forward:before {\n    content: \"\\e075\";\n  }\n  .glyphicon-fast-forward:before {\n    content: \"\\e076\";\n  }\n  .glyphicon-step-forward:before {\n    content: \"\\e077\";\n  }\n  .glyphicon-eject:before {\n    content: \"\\e078\";\n  }\n  .glyphicon-chevron-left:before {\n    content: \"\\e079\";\n  }\n  .glyphicon-chevron-right:before {\n    content: \"\\e080\";\n  }\n  .glyphicon-plus-sign:before {\n    content: \"\\e081\";\n  }\n  .glyphicon-minus-sign:before {\n    content: \"\\e082\";\n  }\n  .glyphicon-remove-sign:before {\n    content: \"\\e083\";\n  }\n  .glyphicon-ok-sign:before {\n    content: \"\\e084\";\n  }\n  .glyphicon-question-sign:before {\n    content: \"\\e085\";\n  }\n  .glyphicon-info-sign:before {\n    content: \"\\e086\";\n  }\n  .glyphicon-screenshot:before {\n    content: \"\\e087\";\n  }\n  .glyphicon-remove-circle:before {\n    content: \"\\e088\";\n  }\n  .glyphicon-ok-circle:before {\n    content: \"\\e089\";\n  }\n  .glyphicon-ban-circle:before {\n    content: \"\\e090\";\n  }\n  .glyphicon-arrow-left:before {\n    content: \"\\e091\";\n  }\n  .glyphicon-arrow-right:before {\n    content: \"\\e092\";\n  }\n  .glyphicon-arrow-up:before {\n    content: \"\\e093\";\n  }\n  .glyphicon-arrow-down:before {\n    content: \"\\e094\";\n  }\n  .glyphicon-share-alt:before {\n    content: \"\\e095\";\n  }\n  .glyphicon-resize-full:before {\n    content: \"\\e096\";\n  }\n  .glyphicon-resize-small:before {\n    content: \"\\e097\";\n  }\n  .glyphicon-exclamation-sign:before {\n    content: \"\\e101\";\n  }\n  .glyphicon-gift:before {\n    content: \"\\e102\";\n  }\n  .glyphicon-leaf:before {\n    content: \"\\e103\";\n  }\n  .glyphicon-fire:before {\n    content: \"\\e104\";\n  }\n  .glyphicon-eye-open:before {\n    content: \"\\e105\";\n  }\n  .glyphicon-eye-close:before {\n    content: \"\\e106\";\n  }\n  .glyphicon-warning-sign:before {\n    content: \"\\e107\";\n  }\n  .glyphicon-plane:before {\n    content: \"\\e108\";\n  }\n  .glyphicon-calendar:before {\n    content: \"\\e109\";\n  }\n  .glyphicon-random:before {\n    content: \"\\e110\";\n  }\n  .glyphicon-comment:before {\n    content: \"\\e111\";\n  }\n  .glyphicon-magnet:before {\n    content: \"\\e112\";\n  }\n  .glyphicon-chevron-up:before {\n    content: \"\\e113\";\n  }\n  .glyphicon-chevron-down:before {\n    content: \"\\e114\";\n  }\n  .glyphicon-retweet:before {\n    content: \"\\e115\";\n  }\n  .glyphicon-shopping-cart:before {\n    content: \"\\e116\";\n  }\n  .glyphicon-folder-close:before {\n    content: \"\\e117\";\n  }\n  .glyphicon-folder-open:before {\n    content: \"\\e118\";\n  }\n  .glyphicon-resize-vertical:before {\n    content: \"\\e119\";\n  }\n  .glyphicon-resize-horizontal:before {\n    content: \"\\e120\";\n  }\n  .glyphicon-hdd:before {\n    content: \"\\e121\";\n  }\n  .glyphicon-bullhorn:before {\n    content: \"\\e122\";\n  }\n  .glyphicon-bell:before {\n    content: \"\\e123\";\n  }\n  .glyphicon-certificate:before {\n    content: \"\\e124\";\n  }\n  .glyphicon-thumbs-up:before {\n    content: \"\\e125\";\n  }\n  .glyphicon-thumbs-down:before {\n    content: \"\\e126\";\n  }\n  .glyphicon-hand-right:before {\n    content: \"\\e127\";\n  }\n  .glyphicon-hand-left:before {\n    content: \"\\e128\";\n  }\n  .glyphicon-hand-up:before {\n    content: \"\\e129\";\n  }\n  .glyphicon-hand-down:before {\n    content: \"\\e130\";\n  }\n  .glyphicon-circle-arrow-right:before {\n    content: \"\\e131\";\n  }\n  .glyphicon-circle-arrow-left:before {\n    content: \"\\e132\";\n  }\n  .glyphicon-circle-arrow-up:before {\n    content: \"\\e133\";\n  }\n  .glyphicon-circle-arrow-down:before {\n    content: \"\\e134\";\n  }\n  .glyphicon-globe:before {\n    content: \"\\e135\";\n  }\n  .glyphicon-wrench:before {\n    content: \"\\e136\";\n  }\n  .glyphicon-tasks:before {\n    content: \"\\e137\";\n  }\n  .glyphicon-filter:before {\n    content: \"\\e138\";\n  }\n  .glyphicon-briefcase:before {\n    content: \"\\e139\";\n  }\n  .glyphicon-fullscreen:before {\n    content: \"\\e140\";\n  }\n  .glyphicon-dashboard:before {\n    content: \"\\e141\";\n  }\n  .glyphicon-paperclip:before {\n    content: \"\\e142\";\n  }\n  .glyphicon-heart-empty:before {\n    content: \"\\e143\";\n  }\n  .glyphicon-link:before {\n    content: \"\\e144\";\n  }\n  .glyphicon-phone:before {\n    content: \"\\e145\";\n  }\n  .glyphicon-pushpin:before {\n    content: \"\\e146\";\n  }\n  .glyphicon-usd:before {\n    content: \"\\e148\";\n  }\n  .glyphicon-gbp:before {\n    content: \"\\e149\";\n  }\n  .glyphicon-sort:before {\n    content: \"\\e150\";\n  }\n  .glyphicon-sort-by-alphabet:before {\n    content: \"\\e151\";\n  }\n  .glyphicon-sort-by-alphabet-alt:before {\n    content: \"\\e152\";\n  }\n  .glyphicon-sort-by-order:before {\n    content: \"\\e153\";\n  }\n  .glyphicon-sort-by-order-alt:before {\n    content: \"\\e154\";\n  }\n  .glyphicon-sort-by-attributes:before {\n    content: \"\\e155\";\n  }\n  .glyphicon-sort-by-attributes-alt:before {\n    content: \"\\e156\";\n  }\n  .glyphicon-unchecked:before {\n    content: \"\\e157\";\n  }\n  .glyphicon-expand:before {\n    content: \"\\e158\";\n  }\n  .glyphicon-collapse-down:before {\n    content: \"\\e159\";\n  }\n  .glyphicon-collapse-up:before {\n    content: \"\\e160\";\n  }\n  .glyphicon-log-in:before {\n    content: \"\\e161\";\n  }\n  .glyphicon-flash:before {\n    content: \"\\e162\";\n  }\n  .glyphicon-log-out:before {\n    content: \"\\e163\";\n  }\n  .glyphicon-new-window:before {\n    content: \"\\e164\";\n  }\n  .glyphicon-record:before {\n    content: \"\\e165\";\n  }\n  .glyphicon-save:before {\n    content: \"\\e166\";\n  }\n  .glyphicon-open:before {\n    content: \"\\e167\";\n  }\n  .glyphicon-saved:before {\n    content: \"\\e168\";\n  }\n  .glyphicon-import:before {\n    content: \"\\e169\";\n  }\n  .glyphicon-export:before {\n    content: \"\\e170\";\n  }\n  .glyphicon-send:before {\n    content: \"\\e171\";\n  }\n  .glyphicon-floppy-disk:before {\n    content: \"\\e172\";\n  }\n  .glyphicon-floppy-saved:before {\n    content: \"\\e173\";\n  }\n  .glyphicon-floppy-remove:before {\n    content: \"\\e174\";\n  }\n  .glyphicon-floppy-save:before {\n    content: \"\\e175\";\n  }\n  .glyphicon-floppy-open:before {\n    content: \"\\e176\";\n  }\n  .glyphicon-credit-card:before {\n    content: \"\\e177\";\n  }\n  .glyphicon-transfer:before {\n    content: \"\\e178\";\n  }\n  .glyphicon-cutlery:before {\n    content: \"\\e179\";\n  }\n  .glyphicon-header:before {\n    content: \"\\e180\";\n  }\n  .glyphicon-compressed:before {\n    content: \"\\e181\";\n  }\n  .glyphicon-earphone:before {\n    content: \"\\e182\";\n  }\n  .glyphicon-phone-alt:before {\n    content: \"\\e183\";\n  }\n  .glyphicon-tower:before {\n    content: \"\\e184\";\n  }\n  .glyphicon-stats:before {\n    content: \"\\e185\";\n  }\n  .glyphicon-sd-video:before {\n    content: \"\\e186\";\n  }\n  .glyphicon-hd-video:before {\n    content: \"\\e187\";\n  }\n  .glyphicon-subtitles:before {\n    content: \"\\e188\";\n  }\n  .glyphicon-sound-stereo:before {\n    content: \"\\e189\";\n  }\n  .glyphicon-sound-dolby:before {\n    content: \"\\e190\";\n  }\n  .glyphicon-sound-5-1:before {\n    content: \"\\e191\";\n  }\n  .glyphicon-sound-6-1:before {\n    content: \"\\e192\";\n  }\n  .glyphicon-sound-7-1:before {\n    content: \"\\e193\";\n  }\n  .glyphicon-copyright-mark:before {\n    content: \"\\e194\";\n  }\n  .glyphicon-registration-mark:before {\n    content: \"\\e195\";\n  }\n  .glyphicon-cloud-download:before {\n    content: \"\\e197\";\n  }\n  .glyphicon-cloud-upload:before {\n    content: \"\\e198\";\n  }\n  .glyphicon-tree-conifer:before {\n    content: \"\\e199\";\n  }\n  .glyphicon-tree-deciduous:before {\n    content: \"\\e200\";\n  }\n  .glyphicon-cd:before {\n    content: \"\\e201\";\n  }\n  .glyphicon-save-file:before {\n    content: \"\\e202\";\n  }\n  .glyphicon-open-file:before {\n    content: \"\\e203\";\n  }\n  .glyphicon-level-up:before {\n    content: \"\\e204\";\n  }\n  .glyphicon-copy:before {\n    content: \"\\e205\";\n  }\n  .glyphicon-paste:before {\n    content: \"\\e206\";\n  }\n  .glyphicon-alert:before {\n    content: \"\\e209\";\n  }\n  .glyphicon-equalizer:before {\n    content: \"\\e210\";\n  }\n  .glyphicon-king:before {\n    content: \"\\e211\";\n  }\n  .glyphicon-queen:before {\n    content: \"\\e212\";\n  }\n  .glyphicon-pawn:before {\n    content: \"\\e213\";\n  }\n  .glyphicon-bishop:before {\n    content: \"\\e214\";\n  }\n  .glyphicon-knight:before {\n    content: \"\\e215\";\n  }\n  .glyphicon-baby-formula:before {\n    content: \"\\e216\";\n  }\n  .glyphicon-tent:before {\n    content: \"\\26fa\";\n  }\n  .glyphicon-blackboard:before {\n    content: \"\\e218\";\n  }\n  .glyphicon-bed:before {\n    content: \"\\e219\";\n  }\n  .glyphicon-apple:before {\n    content: \"\\f8ff\";\n  }\n  .glyphicon-erase:before {\n    content: \"\\e221\";\n  }\n  .glyphicon-hourglass:before {\n    content: \"\\231b\";\n  }\n  .glyphicon-lamp:before {\n    content: \"\\e223\";\n  }\n  .glyphicon-duplicate:before {\n    content: \"\\e224\";\n  }\n  .glyphicon-piggy-bank:before {\n    content: \"\\e225\";\n  }\n  .glyphicon-scissors:before {\n    content: \"\\e226\";\n  }\n  .glyphicon-bitcoin:before {\n    content: \"\\e227\";\n  }\n  .glyphicon-btc:before {\n    content: \"\\e227\";\n  }\n  .glyphicon-xbt:before {\n    content: \"\\e227\";\n  }\n  .glyphicon-yen:before {\n    content: \"\\00a5\";\n  }\n  .glyphicon-jpy:before {\n    content: \"\\00a5\";\n  }\n  .glyphicon-ruble:before {\n    content: \"\\20bd\";\n  }\n  .glyphicon-rub:before {\n    content: \"\\20bd\";\n  }\n  .glyphicon-scale:before {\n    content: \"\\e230\";\n  }\n  .glyphicon-ice-lolly:before {\n    content: \"\\e231\";\n  }\n  .glyphicon-ice-lolly-tasted:before {\n    content: \"\\e232\";\n  }\n  .glyphicon-education:before {\n    content: \"\\e233\";\n  }\n  .glyphicon-option-horizontal:before {\n    content: \"\\e234\";\n  }\n  .glyphicon-option-vertical:before {\n    content: \"\\e235\";\n  }\n  .glyphicon-menu-hamburger:before {\n    content: \"\\e236\";\n  }\n  .glyphicon-modal-window:before {\n    content: \"\\e237\";\n  }\n  .glyphicon-oil:before {\n    content: \"\\e238\";\n  }\n  .glyphicon-grain:before {\n    content: \"\\e239\";\n  }\n  .glyphicon-sunglasses:before {\n    content: \"\\e240\";\n  }\n  .glyphicon-text-size:before {\n    content: \"\\e241\";\n  }\n  .glyphicon-text-color:before {\n    content: \"\\e242\";\n  }\n  .glyphicon-text-background:before {\n    content: \"\\e243\";\n  }\n  .glyphicon-object-align-top:before {\n    content: \"\\e244\";\n  }\n  .glyphicon-object-align-bottom:before {\n    content: \"\\e245\";\n  }\n  .glyphicon-object-align-horizontal:before {\n    content: \"\\e246\";\n  }\n  .glyphicon-object-align-left:before {\n    content: \"\\e247\";\n  }\n  .glyphicon-object-align-vertical:before {\n    content: \"\\e248\";\n  }\n  .glyphicon-object-align-right:before {\n    content: \"\\e249\";\n  }\n  .glyphicon-triangle-right:before {\n    content: \"\\e250\";\n  }\n  .glyphicon-triangle-left:before {\n    content: \"\\e251\";\n  }\n  .glyphicon-triangle-bottom:before {\n    content: \"\\e252\";\n  }\n  .glyphicon-triangle-top:before {\n    content: \"\\e253\";\n  }\n  .glyphicon-console:before {\n    content: \"\\e254\";\n  }\n  .glyphicon-superscript:before {\n    content: \"\\e255\";\n  }\n  .glyphicon-subscript:before {\n    content: \"\\e256\";\n  }\n  .glyphicon-menu-left:before {\n    content: \"\\e257\";\n  }\n  .glyphicon-menu-right:before {\n    content: \"\\e258\";\n  }\n  .glyphicon-menu-down:before {\n    content: \"\\e259\";\n  }\n  .glyphicon-menu-up:before {\n    content: \"\\e260\";\n  }\n  * {\n    -webkit-box-sizing: border-box;\n       -moz-box-sizing: border-box;\n            box-sizing: border-box;\n  }\n  *:before,\n  *:after {\n    -webkit-box-sizing: border-box;\n       -moz-box-sizing: border-box;\n            box-sizing: border-box;\n  }\n  html {\n    font-size: 10px;\n  \n    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n  }\n  body {\n    font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n    font-size: 14px;\n    line-height: 1.42857143;\n    color: #333;\n    background-color: #fff;\n  }\n  input,\n  button,\n  select,\n  textarea {\n    font-family: inherit;\n    font-size: inherit;\n    line-height: inherit;\n  }\n  a {\n    color: #337ab7;\n    text-decoration: none;\n  }\n  a:hover,\n  a:focus {\n    color: #23527c;\n    text-decoration: underline;\n  }\n  a:focus {\n    outline: 5px auto -webkit-focus-ring-color;\n    outline-offset: -2px;\n  }\n  figure {\n    margin: 0;\n  }\n  img {\n    vertical-align: middle;\n  }\n  .img-responsive,\n  .thumbnail > img,\n  .thumbnail a > img,\n  .carousel-inner > .item > img,\n  .carousel-inner > .item > a > img {\n    display: block;\n    max-width: 100%;\n    height: auto;\n  }\n  .img-rounded {\n    border-radius: 6px;\n  }\n  .img-thumbnail {\n    display: inline-block;\n    max-width: 100%;\n    height: auto;\n    padding: 4px;\n    line-height: 1.42857143;\n    background-color: #fff;\n    border: 1px solid #ddd;\n    border-radius: 4px;\n    -webkit-transition: all .2s ease-in-out;\n         -o-transition: all .2s ease-in-out;\n            transition: all .2s ease-in-out;\n  }\n  .img-circle {\n    border-radius: 50%;\n  }\n  hr {\n    margin-top: 20px;\n    margin-bottom: 20px;\n    border: 0;\n    border-top: 1px solid #eee;\n  }\n  .sr-only {\n    position: absolute;\n    width: 1px;\n    height: 1px;\n    padding: 0;\n    margin: -1px;\n    overflow: hidden;\n    clip: rect(0, 0, 0, 0);\n    border: 0;\n  }\n  .sr-only-focusable:active,\n  .sr-only-focusable:focus {\n    position: static;\n    width: auto;\n    height: auto;\n    margin: 0;\n    overflow: visible;\n    clip: auto;\n  }\n  [role=\"button\"] {\n    cursor: pointer;\n  }\n  h1,\n  h2,\n  h3,\n  h4,\n  h5,\n  h6,\n  .h1,\n  .h2,\n  .h3,\n  .h4,\n  .h5,\n  .h6 {\n    font-family: inherit;\n    font-weight: 500;\n    line-height: 1.1;\n    color: inherit;\n  }\n  h1 small,\n  h2 small,\n  h3 small,\n  h4 small,\n  h5 small,\n  h6 small,\n  .h1 small,\n  .h2 small,\n  .h3 small,\n  .h4 small,\n  .h5 small,\n  .h6 small,\n  h1 .small,\n  h2 .small,\n  h3 .small,\n  h4 .small,\n  h5 .small,\n  h6 .small,\n  .h1 .small,\n  .h2 .small,\n  .h3 .small,\n  .h4 .small,\n  .h5 .small,\n  .h6 .small {\n    font-weight: normal;\n    line-height: 1;\n    color: #777;\n  }\n  h1,\n  .h1,\n  h2,\n  .h2,\n  h3,\n  .h3 {\n    margin-top: 20px;\n    margin-bottom: 10px;\n  }\n  h1 small,\n  .h1 small,\n  h2 small,\n  .h2 small,\n  h3 small,\n  .h3 small,\n  h1 .small,\n  .h1 .small,\n  h2 .small,\n  .h2 .small,\n  h3 .small,\n  .h3 .small {\n    font-size: 65%;\n  }\n  h4,\n  .h4,\n  h5,\n  .h5,\n  h6,\n  .h6 {\n    margin-top: 10px;\n    margin-bottom: 10px;\n  }\n  h4 small,\n  .h4 small,\n  h5 small,\n  .h5 small,\n  h6 small,\n  .h6 small,\n  h4 .small,\n  .h4 .small,\n  h5 .small,\n  .h5 .small,\n  h6 .small,\n  .h6 .small {\n    font-size: 75%;\n  }\n  h1,\n  .h1 {\n    font-size: 36px;\n  }\n  h2,\n  .h2 {\n    font-size: 30px;\n  }\n  h3,\n  .h3 {\n    font-size: 24px;\n  }\n  h4,\n  .h4 {\n    font-size: 18px;\n  }\n  h5,\n  .h5 {\n    font-size: 14px;\n  }\n  h6,\n  .h6 {\n    font-size: 12px;\n  }\n  p {\n    margin: 0 0 10px;\n  }\n  .lead {\n    margin-bottom: 20px;\n    font-size: 16px;\n    font-weight: 300;\n    line-height: 1.4;\n  }\n  @media (min-width: 768px) {\n    .lead {\n      font-size: 21px;\n    }\n  }\n  small,\n  .small {\n    font-size: 85%;\n  }\n  mark,\n  .mark {\n    padding: .2em;\n    background-color: #fcf8e3;\n  }\n  .text-left {\n    text-align: left;\n  }\n  .text-right {\n    text-align: right;\n  }\n  .text-center {\n    text-align: center;\n  }\n  .text-justify {\n    text-align: justify;\n  }\n  .text-nowrap {\n    white-space: nowrap;\n  }\n  .text-lowercase {\n    text-transform: lowercase;\n  }\n  .text-uppercase {\n    text-transform: uppercase;\n  }\n  .text-capitalize {\n    text-transform: capitalize;\n  }\n  .text-muted {\n    color: #777;\n  }\n  .text-primary {\n    color: #337ab7;\n  }\n  a.text-primary:hover,\n  a.text-primary:focus {\n    color: #286090;\n  }\n  .text-success {\n    color: #3c763d;\n  }\n  a.text-success:hover,\n  a.text-success:focus {\n    color: #2b542c;\n  }\n  .text-info {\n    color: #31708f;\n  }\n  a.text-info:hover,\n  a.text-info:focus {\n    color: #245269;\n  }\n  .text-warning {\n    color: #8a6d3b;\n  }\n  a.text-warning:hover,\n  a.text-warning:focus {\n    color: #66512c;\n  }\n  .text-danger {\n    color: #a94442;\n  }\n  a.text-danger:hover,\n  a.text-danger:focus {\n    color: #843534;\n  }\n  .bg-primary {\n    color: #fff;\n    background-color: #337ab7;\n  }\n  a.bg-primary:hover,\n  a.bg-primary:focus {\n    background-color: #286090;\n  }\n  .bg-success {\n    background-color: #dff0d8;\n  }\n  a.bg-success:hover,\n  a.bg-success:focus {\n    background-color: #c1e2b3;\n  }\n  .bg-info {\n    background-color: #d9edf7;\n  }\n  a.bg-info:hover,\n  a.bg-info:focus {\n    background-color: #afd9ee;\n  }\n  .bg-warning {\n    background-color: #fcf8e3;\n  }\n  a.bg-warning:hover,\n  a.bg-warning:focus {\n    background-color: #f7ecb5;\n  }\n  .bg-danger {\n    background-color: #f2dede;\n  }\n  a.bg-danger:hover,\n  a.bg-danger:focus {\n    background-color: #e4b9b9;\n  }\n  .page-header {\n    padding-bottom: 9px;\n    margin: 40px 0 20px;\n    border-bottom: 1px solid #eee;\n  }\n  ul,\n  ol {\n    margin-top: 0;\n    margin-bottom: 10px;\n  }\n  ul ul,\n  ol ul,\n  ul ol,\n  ol ol {\n    margin-bottom: 0;\n  }\n  .list-unstyled {\n    padding-left: 0;\n    list-style: none;\n  }\n  .list-inline {\n    padding-left: 0;\n    margin-left: -5px;\n    list-style: none;\n  }\n  .list-inline > li {\n    display: inline-block;\n    padding-right: 5px;\n    padding-left: 5px;\n  }\n  dl {\n    margin-top: 0;\n    margin-bottom: 20px;\n  }\n  dt,\n  dd {\n    line-height: 1.42857143;\n  }\n  dt {\n    font-weight: bold;\n  }\n  dd {\n    margin-left: 0;\n  }\n  @media (min-width: 768px) {\n    .dl-horizontal dt {\n      float: left;\n      width: 160px;\n      overflow: hidden;\n      clear: left;\n      text-align: right;\n      text-overflow: ellipsis;\n      white-space: nowrap;\n    }\n    .dl-horizontal dd {\n      margin-left: 180px;\n    }\n  }\n  abbr[title],\n  abbr[data-original-title] {\n    cursor: help;\n    border-bottom: 1px dotted #777;\n  }\n  .initialism {\n    font-size: 90%;\n    text-transform: uppercase;\n  }\n  blockquote {\n    padding: 10px 20px;\n    margin: 0 0 20px;\n    font-size: 17.5px;\n    border-left: 5px solid #eee;\n  }\n  blockquote p:last-child,\n  blockquote ul:last-child,\n  blockquote ol:last-child {\n    margin-bottom: 0;\n  }\n  blockquote footer,\n  blockquote small,\n  blockquote .small {\n    display: block;\n    font-size: 80%;\n    line-height: 1.42857143;\n    color: #777;\n  }\n  blockquote footer:before,\n  blockquote small:before,\n  blockquote .small:before {\n    content: '\\2014 \\00A0';\n  }\n  .blockquote-reverse,\n  blockquote.pull-right {\n    padding-right: 15px;\n    padding-left: 0;\n    text-align: right;\n    border-right: 5px solid #eee;\n    border-left: 0;\n  }\n  .blockquote-reverse footer:before,\n  blockquote.pull-right footer:before,\n  .blockquote-reverse small:before,\n  blockquote.pull-right small:before,\n  .blockquote-reverse .small:before,\n  blockquote.pull-right .small:before {\n    content: '';\n  }\n  .blockquote-reverse footer:after,\n  blockquote.pull-right footer:after,\n  .blockquote-reverse small:after,\n  blockquote.pull-right small:after,\n  .blockquote-reverse .small:after,\n  blockquote.pull-right .small:after {\n    content: '\\00A0 \\2014';\n  }\n  address {\n    margin-bottom: 20px;\n    font-style: normal;\n    line-height: 1.42857143;\n  }\n  code,\n  kbd,\n  pre,\n  samp {\n    font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n  }\n  code {\n    padding: 2px 4px;\n    font-size: 90%;\n    color: #c7254e;\n    background-color: #f9f2f4;\n    border-radius: 4px;\n  }\n  kbd {\n    padding: 2px 4px;\n    font-size: 90%;\n    color: #fff;\n    background-color: #333;\n    border-radius: 3px;\n    -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n            box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n  }\n  kbd kbd {\n    padding: 0;\n    font-size: 100%;\n    font-weight: bold;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n  pre {\n    display: block;\n    padding: 9.5px;\n    margin: 0 0 10px;\n    font-size: 13px;\n    line-height: 1.42857143;\n    color: #333;\n    word-break: break-all;\n    word-wrap: break-word;\n    background-color: #f5f5f5;\n    border: 1px solid #ccc;\n    border-radius: 4px;\n  }\n  pre code {\n    padding: 0;\n    font-size: inherit;\n    color: inherit;\n    white-space: pre-wrap;\n    background-color: transparent;\n    border-radius: 0;\n  }\n  .pre-scrollable {\n    max-height: 340px;\n    overflow-y: scroll;\n  }\n  .container {\n    padding-right: 15px;\n    padding-left: 15px;\n    margin-right: auto;\n    margin-left: auto;\n  }\n  @media (min-width: 768px) {\n    .container {\n      width: 750px;\n    }\n  }\n  @media (min-width: 992px) {\n    .container {\n      width: 970px;\n    }\n  }\n  @media (min-width: 1200px) {\n    .container {\n      width: 1170px;\n    }\n  }\n  .container-fluid {\n    padding-right: 15px;\n    padding-left: 15px;\n    margin-right: auto;\n    margin-left: auto;\n  }\n  .row {\n    margin-right: -15px;\n    margin-left: -15px;\n  }\n  .col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\n    position: relative;\n    min-height: 1px;\n    padding-right: 15px;\n    padding-left: 15px;\n  }\n  .col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\n    float: left;\n  }\n  .col-xs-12 {\n    width: 100%;\n  }\n  .col-xs-11 {\n    width: 91.66666667%;\n  }\n  .col-xs-10 {\n    width: 83.33333333%;\n  }\n  .col-xs-9 {\n    width: 75%;\n  }\n  .col-xs-8 {\n    width: 66.66666667%;\n  }\n  .col-xs-7 {\n    width: 58.33333333%;\n  }\n  .col-xs-6 {\n    width: 50%;\n  }\n  .col-xs-5 {\n    width: 41.66666667%;\n  }\n  .col-xs-4 {\n    width: 33.33333333%;\n  }\n  .col-xs-3 {\n    width: 25%;\n  }\n  .col-xs-2 {\n    width: 16.66666667%;\n  }\n  .col-xs-1 {\n    width: 8.33333333%;\n  }\n  .col-xs-pull-12 {\n    right: 100%;\n  }\n  .col-xs-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-xs-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-xs-pull-9 {\n    right: 75%;\n  }\n  .col-xs-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-xs-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-xs-pull-6 {\n    right: 50%;\n  }\n  .col-xs-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-xs-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-xs-pull-3 {\n    right: 25%;\n  }\n  .col-xs-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-xs-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-xs-pull-0 {\n    right: auto;\n  }\n  .col-xs-push-12 {\n    left: 100%;\n  }\n  .col-xs-push-11 {\n    left: 91.66666667%;\n  }\n  .col-xs-push-10 {\n    left: 83.33333333%;\n  }\n  .col-xs-push-9 {\n    left: 75%;\n  }\n  .col-xs-push-8 {\n    left: 66.66666667%;\n  }\n  .col-xs-push-7 {\n    left: 58.33333333%;\n  }\n  .col-xs-push-6 {\n    left: 50%;\n  }\n  .col-xs-push-5 {\n    left: 41.66666667%;\n  }\n  .col-xs-push-4 {\n    left: 33.33333333%;\n  }\n  .col-xs-push-3 {\n    left: 25%;\n  }\n  .col-xs-push-2 {\n    left: 16.66666667%;\n  }\n  .col-xs-push-1 {\n    left: 8.33333333%;\n  }\n  .col-xs-push-0 {\n    left: auto;\n  }\n  .col-xs-offset-12 {\n    margin-left: 100%;\n  }\n  .col-xs-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-xs-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-xs-offset-9 {\n    margin-left: 75%;\n  }\n  .col-xs-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-xs-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-xs-offset-6 {\n    margin-left: 50%;\n  }\n  .col-xs-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-xs-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-xs-offset-3 {\n    margin-left: 25%;\n  }\n  .col-xs-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-xs-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-xs-offset-0 {\n    margin-left: 0;\n  }\n  @media (min-width: 768px) {\n    .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {\n      float: left;\n    }\n    .col-sm-12 {\n      width: 100%;\n    }\n    .col-sm-11 {\n      width: 91.66666667%;\n    }\n    .col-sm-10 {\n      width: 83.33333333%;\n    }\n    .col-sm-9 {\n      width: 75%;\n    }\n    .col-sm-8 {\n      width: 66.66666667%;\n    }\n    .col-sm-7 {\n      width: 58.33333333%;\n    }\n    .col-sm-6 {\n      width: 50%;\n    }\n    .col-sm-5 {\n      width: 41.66666667%;\n    }\n    .col-sm-4 {\n      width: 33.33333333%;\n    }\n    .col-sm-3 {\n      width: 25%;\n    }\n    .col-sm-2 {\n      width: 16.66666667%;\n    }\n    .col-sm-1 {\n      width: 8.33333333%;\n    }\n    .col-sm-pull-12 {\n      right: 100%;\n    }\n    .col-sm-pull-11 {\n      right: 91.66666667%;\n    }\n    .col-sm-pull-10 {\n      right: 83.33333333%;\n    }\n    .col-sm-pull-9 {\n      right: 75%;\n    }\n    .col-sm-pull-8 {\n      right: 66.66666667%;\n    }\n    .col-sm-pull-7 {\n      right: 58.33333333%;\n    }\n    .col-sm-pull-6 {\n      right: 50%;\n    }\n    .col-sm-pull-5 {\n      right: 41.66666667%;\n    }\n    .col-sm-pull-4 {\n      right: 33.33333333%;\n    }\n    .col-sm-pull-3 {\n      right: 25%;\n    }\n    .col-sm-pull-2 {\n      right: 16.66666667%;\n    }\n    .col-sm-pull-1 {\n      right: 8.33333333%;\n    }\n    .col-sm-pull-0 {\n      right: auto;\n    }\n    .col-sm-push-12 {\n      left: 100%;\n    }\n    .col-sm-push-11 {\n      left: 91.66666667%;\n    }\n    .col-sm-push-10 {\n      left: 83.33333333%;\n    }\n    .col-sm-push-9 {\n      left: 75%;\n    }\n    .col-sm-push-8 {\n      left: 66.66666667%;\n    }\n    .col-sm-push-7 {\n      left: 58.33333333%;\n    }\n    .col-sm-push-6 {\n      left: 50%;\n    }\n    .col-sm-push-5 {\n      left: 41.66666667%;\n    }\n    .col-sm-push-4 {\n      left: 33.33333333%;\n    }\n    .col-sm-push-3 {\n      left: 25%;\n    }\n    .col-sm-push-2 {\n      left: 16.66666667%;\n    }\n    .col-sm-push-1 {\n      left: 8.33333333%;\n    }\n    .col-sm-push-0 {\n      left: auto;\n    }\n    .col-sm-offset-12 {\n      margin-left: 100%;\n    }\n    .col-sm-offset-11 {\n      margin-left: 91.66666667%;\n    }\n    .col-sm-offset-10 {\n      margin-left: 83.33333333%;\n    }\n    .col-sm-offset-9 {\n      margin-left: 75%;\n    }\n    .col-sm-offset-8 {\n      margin-left: 66.66666667%;\n    }\n    .col-sm-offset-7 {\n      margin-left: 58.33333333%;\n    }\n    .col-sm-offset-6 {\n      margin-left: 50%;\n    }\n    .col-sm-offset-5 {\n      margin-left: 41.66666667%;\n    }\n    .col-sm-offset-4 {\n      margin-left: 33.33333333%;\n    }\n    .col-sm-offset-3 {\n      margin-left: 25%;\n    }\n    .col-sm-offset-2 {\n      margin-left: 16.66666667%;\n    }\n    .col-sm-offset-1 {\n      margin-left: 8.33333333%;\n    }\n    .col-sm-offset-0 {\n      margin-left: 0;\n    }\n  }\n  @media (min-width: 992px) {\n    .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {\n      float: left;\n    }\n    .col-md-12 {\n      width: 100%;\n    }\n    .col-md-11 {\n      width: 91.66666667%;\n    }\n    .col-md-10 {\n      width: 83.33333333%;\n    }\n    .col-md-9 {\n      width: 75%;\n    }\n    .col-md-8 {\n      width: 66.66666667%;\n    }\n    .col-md-7 {\n      width: 58.33333333%;\n    }\n    .col-md-6 {\n      width: 50%;\n    }\n    .col-md-5 {\n      width: 41.66666667%;\n    }\n    .col-md-4 {\n      width: 33.33333333%;\n    }\n    .col-md-3 {\n      width: 25%;\n    }\n    .col-md-2 {\n      width: 16.66666667%;\n    }\n    .col-md-1 {\n      width: 8.33333333%;\n    }\n    .col-md-pull-12 {\n      right: 100%;\n    }\n    .col-md-pull-11 {\n      right: 91.66666667%;\n    }\n    .col-md-pull-10 {\n      right: 83.33333333%;\n    }\n    .col-md-pull-9 {\n      right: 75%;\n    }\n    .col-md-pull-8 {\n      right: 66.66666667%;\n    }\n    .col-md-pull-7 {\n      right: 58.33333333%;\n    }\n    .col-md-pull-6 {\n      right: 50%;\n    }\n    .col-md-pull-5 {\n      right: 41.66666667%;\n    }\n    .col-md-pull-4 {\n      right: 33.33333333%;\n    }\n    .col-md-pull-3 {\n      right: 25%;\n    }\n    .col-md-pull-2 {\n      right: 16.66666667%;\n    }\n    .col-md-pull-1 {\n      right: 8.33333333%;\n    }\n    .col-md-pull-0 {\n      right: auto;\n    }\n    .col-md-push-12 {\n      left: 100%;\n    }\n    .col-md-push-11 {\n      left: 91.66666667%;\n    }\n    .col-md-push-10 {\n      left: 83.33333333%;\n    }\n    .col-md-push-9 {\n      left: 75%;\n    }\n    .col-md-push-8 {\n      left: 66.66666667%;\n    }\n    .col-md-push-7 {\n      left: 58.33333333%;\n    }\n    .col-md-push-6 {\n      left: 50%;\n    }\n    .col-md-push-5 {\n      left: 41.66666667%;\n    }\n    .col-md-push-4 {\n      left: 33.33333333%;\n    }\n    .col-md-push-3 {\n      left: 25%;\n    }\n    .col-md-push-2 {\n      left: 16.66666667%;\n    }\n    .col-md-push-1 {\n      left: 8.33333333%;\n    }\n    .col-md-push-0 {\n      left: auto;\n    }\n    .col-md-offset-12 {\n      margin-left: 100%;\n    }\n    .col-md-offset-11 {\n      margin-left: 91.66666667%;\n    }\n    .col-md-offset-10 {\n      margin-left: 83.33333333%;\n    }\n    .col-md-offset-9 {\n      margin-left: 75%;\n    }\n    .col-md-offset-8 {\n      margin-left: 66.66666667%;\n    }\n    .col-md-offset-7 {\n      margin-left: 58.33333333%;\n    }\n    .col-md-offset-6 {\n      margin-left: 50%;\n    }\n    .col-md-offset-5 {\n      margin-left: 41.66666667%;\n    }\n    .col-md-offset-4 {\n      margin-left: 33.33333333%;\n    }\n    .col-md-offset-3 {\n      margin-left: 25%;\n    }\n    .col-md-offset-2 {\n      margin-left: 16.66666667%;\n    }\n    .col-md-offset-1 {\n      margin-left: 8.33333333%;\n    }\n    .col-md-offset-0 {\n      margin-left: 0;\n    }\n  }\n  @media (min-width: 1200px) {\n    .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {\n      float: left;\n    }\n    .col-lg-12 {\n      width: 100%;\n    }\n    .col-lg-11 {\n      width: 91.66666667%;\n    }\n    .col-lg-10 {\n      width: 83.33333333%;\n    }\n    .col-lg-9 {\n      width: 75%;\n    }\n    .col-lg-8 {\n      width: 66.66666667%;\n    }\n    .col-lg-7 {\n      width: 58.33333333%;\n    }\n    .col-lg-6 {\n      width: 50%;\n    }\n    .col-lg-5 {\n      width: 41.66666667%;\n    }\n    .col-lg-4 {\n      width: 33.33333333%;\n    }\n    .col-lg-3 {\n      width: 25%;\n    }\n    .col-lg-2 {\n      width: 16.66666667%;\n    }\n    .col-lg-1 {\n      width: 8.33333333%;\n    }\n    .col-lg-pull-12 {\n      right: 100%;\n    }\n    .col-lg-pull-11 {\n      right: 91.66666667%;\n    }\n    .col-lg-pull-10 {\n      right: 83.33333333%;\n    }\n    .col-lg-pull-9 {\n      right: 75%;\n    }\n    .col-lg-pull-8 {\n      right: 66.66666667%;\n    }\n    .col-lg-pull-7 {\n      right: 58.33333333%;\n    }\n    .col-lg-pull-6 {\n      right: 50%;\n    }\n    .col-lg-pull-5 {\n      right: 41.66666667%;\n    }\n    .col-lg-pull-4 {\n      right: 33.33333333%;\n    }\n    .col-lg-pull-3 {\n      right: 25%;\n    }\n    .col-lg-pull-2 {\n      right: 16.66666667%;\n    }\n    .col-lg-pull-1 {\n      right: 8.33333333%;\n    }\n    .col-lg-pull-0 {\n      right: auto;\n    }\n    .col-lg-push-12 {\n      left: 100%;\n    }\n    .col-lg-push-11 {\n      left: 91.66666667%;\n    }\n    .col-lg-push-10 {\n      left: 83.33333333%;\n    }\n    .col-lg-push-9 {\n      left: 75%;\n    }\n    .col-lg-push-8 {\n      left: 66.66666667%;\n    }\n    .col-lg-push-7 {\n      left: 58.33333333%;\n    }\n    .col-lg-push-6 {\n      left: 50%;\n    }\n    .col-lg-push-5 {\n      left: 41.66666667%;\n    }\n    .col-lg-push-4 {\n      left: 33.33333333%;\n    }\n    .col-lg-push-3 {\n      left: 25%;\n    }\n    .col-lg-push-2 {\n      left: 16.66666667%;\n    }\n    .col-lg-push-1 {\n      left: 8.33333333%;\n    }\n    .col-lg-push-0 {\n      left: auto;\n    }\n    .col-lg-offset-12 {\n      margin-left: 100%;\n    }\n    .col-lg-offset-11 {\n      margin-left: 91.66666667%;\n    }\n    .col-lg-offset-10 {\n      margin-left: 83.33333333%;\n    }\n    .col-lg-offset-9 {\n      margin-left: 75%;\n    }\n    .col-lg-offset-8 {\n      margin-left: 66.66666667%;\n    }\n    .col-lg-offset-7 {\n      margin-left: 58.33333333%;\n    }\n    .col-lg-offset-6 {\n      margin-left: 50%;\n    }\n    .col-lg-offset-5 {\n      margin-left: 41.66666667%;\n    }\n    .col-lg-offset-4 {\n      margin-left: 33.33333333%;\n    }\n    .col-lg-offset-3 {\n      margin-left: 25%;\n    }\n    .col-lg-offset-2 {\n      margin-left: 16.66666667%;\n    }\n    .col-lg-offset-1 {\n      margin-left: 8.33333333%;\n    }\n    .col-lg-offset-0 {\n      margin-left: 0;\n    }\n  }\n  table {\n    background-color: transparent;\n  }\n  caption {\n    padding-top: 8px;\n    padding-bottom: 8px;\n    color: #777;\n    text-align: left;\n  }\n  th {\n    text-align: left;\n  }\n  .table {\n    width: 100%;\n    max-width: 100%;\n    margin-bottom: 20px;\n  }\n  .table > thead > tr > th,\n  .table > tbody > tr > th,\n  .table > tfoot > tr > th,\n  .table > thead > tr > td,\n  .table > tbody > tr > td,\n  .table > tfoot > tr > td {\n    padding: 8px;\n    line-height: 1.42857143;\n    vertical-align: top;\n    border-top: 1px solid #ddd;\n  }\n  .table > thead > tr > th {\n    vertical-align: bottom;\n    border-bottom: 2px solid #ddd;\n  }\n  .table > caption + thead > tr:first-child > th,\n  .table > colgroup + thead > tr:first-child > th,\n  .table > thead:first-child > tr:first-child > th,\n  .table > caption + thead > tr:first-child > td,\n  .table > colgroup + thead > tr:first-child > td,\n  .table > thead:first-child > tr:first-child > td {\n    border-top: 0;\n  }\n  .table > tbody + tbody {\n    border-top: 2px solid #ddd;\n  }\n  .table .table {\n    background-color: #fff;\n  }\n  .table-condensed > thead > tr > th,\n  .table-condensed > tbody > tr > th,\n  .table-condensed > tfoot > tr > th,\n  .table-condensed > thead > tr > td,\n  .table-condensed > tbody > tr > td,\n  .table-condensed > tfoot > tr > td {\n    padding: 5px;\n  }\n  .table-bordered {\n    border: 1px solid #ddd;\n  }\n  .table-bordered > thead > tr > th,\n  .table-bordered > tbody > tr > th,\n  .table-bordered > tfoot > tr > th,\n  .table-bordered > thead > tr > td,\n  .table-bordered > tbody > tr > td,\n  .table-bordered > tfoot > tr > td {\n    border: 1px solid #ddd;\n  }\n  .table-bordered > thead > tr > th,\n  .table-bordered > thead > tr > td {\n    border-bottom-width: 2px;\n  }\n  .table-striped > tbody > tr:nth-of-type(odd) {\n    background-color: #f9f9f9;\n  }\n  .table-hover > tbody > tr:hover {\n    background-color: #f5f5f5;\n  }\n  table col[class*=\"col-\"] {\n    position: static;\n    display: table-column;\n    float: none;\n  }\n  table td[class*=\"col-\"],\n  table th[class*=\"col-\"] {\n    position: static;\n    display: table-cell;\n    float: none;\n  }\n  .table > thead > tr > td.active,\n  .table > tbody > tr > td.active,\n  .table > tfoot > tr > td.active,\n  .table > thead > tr > th.active,\n  .table > tbody > tr > th.active,\n  .table > tfoot > tr > th.active,\n  .table > thead > tr.active > td,\n  .table > tbody > tr.active > td,\n  .table > tfoot > tr.active > td,\n  .table > thead > tr.active > th,\n  .table > tbody > tr.active > th,\n  .table > tfoot > tr.active > th {\n    background-color: #f5f5f5;\n  }\n  .table-hover > tbody > tr > td.active:hover,\n  .table-hover > tbody > tr > th.active:hover,\n  .table-hover > tbody > tr.active:hover > td,\n  .table-hover > tbody > tr:hover > .active,\n  .table-hover > tbody > tr.active:hover > th {\n    background-color: #e8e8e8;\n  }\n  .table > thead > tr > td.success,\n  .table > tbody > tr > td.success,\n  .table > tfoot > tr > td.success,\n  .table > thead > tr > th.success,\n  .table > tbody > tr > th.success,\n  .table > tfoot > tr > th.success,\n  .table > thead > tr.success > td,\n  .table > tbody > tr.success > td,\n  .table > tfoot > tr.success > td,\n  .table > thead > tr.success > th,\n  .table > tbody > tr.success > th,\n  .table > tfoot > tr.success > th {\n    background-color: #dff0d8;\n  }\n  .table-hover > tbody > tr > td.success:hover,\n  .table-hover > tbody > tr > th.success:hover,\n  .table-hover > tbody > tr.success:hover > td,\n  .table-hover > tbody > tr:hover > .success,\n  .table-hover > tbody > tr.success:hover > th {\n    background-color: #d0e9c6;\n  }\n  .table > thead > tr > td.info,\n  .table > tbody > tr > td.info,\n  .table > tfoot > tr > td.info,\n  .table > thead > tr > th.info,\n  .table > tbody > tr > th.info,\n  .table > tfoot > tr > th.info,\n  .table > thead > tr.info > td,\n  .table > tbody > tr.info > td,\n  .table > tfoot > tr.info > td,\n  .table > thead > tr.info > th,\n  .table > tbody > tr.info > th,\n  .table > tfoot > tr.info > th {\n    background-color: #d9edf7;\n  }\n  .table-hover > tbody > tr > td.info:hover,\n  .table-hover > tbody > tr > th.info:hover,\n  .table-hover > tbody > tr.info:hover > td,\n  .table-hover > tbody > tr:hover > .info,\n  .table-hover > tbody > tr.info:hover > th {\n    background-color: #c4e3f3;\n  }\n  .table > thead > tr > td.warning,\n  .table > tbody > tr > td.warning,\n  .table > tfoot > tr > td.warning,\n  .table > thead > tr > th.warning,\n  .table > tbody > tr > th.warning,\n  .table > tfoot > tr > th.warning,\n  .table > thead > tr.warning > td,\n  .table > tbody > tr.warning > td,\n  .table > tfoot > tr.warning > td,\n  .table > thead > tr.warning > th,\n  .table > tbody > tr.warning > th,\n  .table > tfoot > tr.warning > th {\n    background-color: #fcf8e3;\n  }\n  .table-hover > tbody > tr > td.warning:hover,\n  .table-hover > tbody > tr > th.warning:hover,\n  .table-hover > tbody > tr.warning:hover > td,\n  .table-hover > tbody > tr:hover > .warning,\n  .table-hover > tbody > tr.warning:hover > th {\n    background-color: #faf2cc;\n  }\n  .table > thead > tr > td.danger,\n  .table > tbody > tr > td.danger,\n  .table > tfoot > tr > td.danger,\n  .table > thead > tr > th.danger,\n  .table > tbody > tr > th.danger,\n  .table > tfoot > tr > th.danger,\n  .table > thead > tr.danger > td,\n  .table > tbody > tr.danger > td,\n  .table > tfoot > tr.danger > td,\n  .table > thead > tr.danger > th,\n  .table > tbody > tr.danger > th,\n  .table > tfoot > tr.danger > th {\n    background-color: #f2dede;\n  }\n  .table-hover > tbody > tr > td.danger:hover,\n  .table-hover > tbody > tr > th.danger:hover,\n  .table-hover > tbody > tr.danger:hover > td,\n  .table-hover > tbody > tr:hover > .danger,\n  .table-hover > tbody > tr.danger:hover > th {\n    background-color: #ebcccc;\n  }\n  .table-responsive {\n    min-height: .01%;\n    overflow-x: auto;\n  }\n  @media screen and (max-width: 767px) {\n    .table-responsive {\n      width: 100%;\n      margin-bottom: 15px;\n      overflow-y: hidden;\n      -ms-overflow-style: -ms-autohiding-scrollbar;\n      border: 1px solid #ddd;\n    }\n    .table-responsive > .table {\n      margin-bottom: 0;\n    }\n    .table-responsive > .table > thead > tr > th,\n    .table-responsive > .table > tbody > tr > th,\n    .table-responsive > .table > tfoot > tr > th,\n    .table-responsive > .table > thead > tr > td,\n    .table-responsive > .table > tbody > tr > td,\n    .table-responsive > .table > tfoot > tr > td {\n      white-space: nowrap;\n    }\n    .table-responsive > .table-bordered {\n      border: 0;\n    }\n    .table-responsive > .table-bordered > thead > tr > th:first-child,\n    .table-responsive > .table-bordered > tbody > tr > th:first-child,\n    .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n    .table-responsive > .table-bordered > thead > tr > td:first-child,\n    .table-responsive > .table-bordered > tbody > tr > td:first-child,\n    .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n      border-left: 0;\n    }\n    .table-responsive > .table-bordered > thead > tr > th:last-child,\n    .table-responsive > .table-bordered > tbody > tr > th:last-child,\n    .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n    .table-responsive > .table-bordered > thead > tr > td:last-child,\n    .table-responsive > .table-bordered > tbody > tr > td:last-child,\n    .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n      border-right: 0;\n    }\n    .table-responsive > .table-bordered > tbody > tr:last-child > th,\n    .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n    .table-responsive > .table-bordered > tbody > tr:last-child > td,\n    .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n      border-bottom: 0;\n    }\n  }\n  fieldset {\n    min-width: 0;\n    padding: 0;\n    margin: 0;\n    border: 0;\n  }\n  legend {\n    display: block;\n    width: 100%;\n    padding: 0;\n    margin-bottom: 20px;\n    font-size: 21px;\n    line-height: inherit;\n    color: #333;\n    border: 0;\n    border-bottom: 1px solid #e5e5e5;\n  }\n  label {\n    display: inline-block;\n    max-width: 100%;\n    margin-bottom: 5px;\n    font-weight: bold;\n  }\n  input[type=\"search\"] {\n    -webkit-box-sizing: border-box;\n       -moz-box-sizing: border-box;\n            box-sizing: border-box;\n  }\n  input[type=\"radio\"],\n  input[type=\"checkbox\"] {\n    margin: 4px 0 0;\n    margin-top: 1px \\9;\n    line-height: normal;\n  }\n  input[type=\"file\"] {\n    display: block;\n  }\n  input[type=\"range\"] {\n    display: block;\n    width: 100%;\n  }\n  select[multiple],\n  select[size] {\n    height: auto;\n  }\n  input[type=\"file\"]:focus,\n  input[type=\"radio\"]:focus,\n  input[type=\"checkbox\"]:focus {\n    outline: 5px auto -webkit-focus-ring-color;\n    outline-offset: -2px;\n  }\n  output {\n    display: block;\n    padding-top: 7px;\n    font-size: 14px;\n    line-height: 1.42857143;\n    color: #555;\n  }\n  .form-control {\n    display: block;\n    width: 100%;\n    height: 34px;\n    padding: 6px 12px;\n    font-size: 14px;\n    line-height: 1.42857143;\n    color: #555;\n    background-color: #fff;\n    background-image: none;\n    border: 1px solid #ccc;\n    border-radius: 4px;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n            box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n    -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\n         -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n            transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n  }\n  .form-control:focus {\n    border-color: #66afe9;\n    outline: 0;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);\n            box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);\n  }\n  .form-control::-moz-placeholder {\n    color: #999;\n    opacity: 1;\n  }\n  .form-control:-ms-input-placeholder {\n    color: #999;\n  }\n  .form-control::-webkit-input-placeholder {\n    color: #999;\n  }\n  .form-control::-ms-expand {\n    background-color: transparent;\n    border: 0;\n  }\n  .form-control[disabled],\n  .form-control[readonly],\n  fieldset[disabled] .form-control {\n    background-color: #eee;\n    opacity: 1;\n  }\n  .form-control[disabled],\n  fieldset[disabled] .form-control {\n    cursor: not-allowed;\n  }\n  textarea.form-control {\n    height: auto;\n  }\n  input[type=\"search\"] {\n    -webkit-appearance: none;\n  }\n  @media screen and (-webkit-min-device-pixel-ratio: 0) {\n    input[type=\"date\"].form-control,\n    input[type=\"time\"].form-control,\n    input[type=\"datetime-local\"].form-control,\n    input[type=\"month\"].form-control {\n      line-height: 34px;\n    }\n    input[type=\"date\"].input-sm,\n    input[type=\"time\"].input-sm,\n    input[type=\"datetime-local\"].input-sm,\n    input[type=\"month\"].input-sm,\n    .input-group-sm input[type=\"date\"],\n    .input-group-sm input[type=\"time\"],\n    .input-group-sm input[type=\"datetime-local\"],\n    .input-group-sm input[type=\"month\"] {\n      line-height: 30px;\n    }\n    input[type=\"date\"].input-lg,\n    input[type=\"time\"].input-lg,\n    input[type=\"datetime-local\"].input-lg,\n    input[type=\"month\"].input-lg,\n    .input-group-lg input[type=\"date\"],\n    .input-group-lg input[type=\"time\"],\n    .input-group-lg input[type=\"datetime-local\"],\n    .input-group-lg input[type=\"month\"] {\n      line-height: 46px;\n    }\n  }\n  .form-group {\n    margin-bottom: 15px;\n  }\n  .radio,\n  .checkbox {\n    position: relative;\n    display: block;\n    margin-top: 10px;\n    margin-bottom: 10px;\n  }\n  .radio label,\n  .checkbox label {\n    min-height: 20px;\n    padding-left: 20px;\n    margin-bottom: 0;\n    font-weight: normal;\n    cursor: pointer;\n  }\n  .radio input[type=\"radio\"],\n  .radio-inline input[type=\"radio\"],\n  .checkbox input[type=\"checkbox\"],\n  .checkbox-inline input[type=\"checkbox\"] {\n    position: absolute;\n    margin-top: 4px \\9;\n    margin-left: -20px;\n  }\n  .radio + .radio,\n  .checkbox + .checkbox {\n    margin-top: -5px;\n  }\n  .radio-inline,\n  .checkbox-inline {\n    position: relative;\n    display: inline-block;\n    padding-left: 20px;\n    margin-bottom: 0;\n    font-weight: normal;\n    vertical-align: middle;\n    cursor: pointer;\n  }\n  .radio-inline + .radio-inline,\n  .checkbox-inline + .checkbox-inline {\n    margin-top: 0;\n    margin-left: 10px;\n  }\n  input[type=\"radio\"][disabled],\n  input[type=\"checkbox\"][disabled],\n  input[type=\"radio\"].disabled,\n  input[type=\"checkbox\"].disabled,\n  fieldset[disabled] input[type=\"radio\"],\n  fieldset[disabled] input[type=\"checkbox\"] {\n    cursor: not-allowed;\n  }\n  .radio-inline.disabled,\n  .checkbox-inline.disabled,\n  fieldset[disabled] .radio-inline,\n  fieldset[disabled] .checkbox-inline {\n    cursor: not-allowed;\n  }\n  .radio.disabled label,\n  .checkbox.disabled label,\n  fieldset[disabled] .radio label,\n  fieldset[disabled] .checkbox label {\n    cursor: not-allowed;\n  }\n  .form-control-static {\n    min-height: 34px;\n    padding-top: 7px;\n    padding-bottom: 7px;\n    margin-bottom: 0;\n  }\n  .form-control-static.input-lg,\n  .form-control-static.input-sm {\n    padding-right: 0;\n    padding-left: 0;\n  }\n  .input-sm {\n    height: 30px;\n    padding: 5px 10px;\n    font-size: 12px;\n    line-height: 1.5;\n    border-radius: 3px;\n  }\n  select.input-sm {\n    height: 30px;\n    line-height: 30px;\n  }\n  textarea.input-sm,\n  select[multiple].input-sm {\n    height: auto;\n  }\n  .form-group-sm .form-control {\n    height: 30px;\n    padding: 5px 10px;\n    font-size: 12px;\n    line-height: 1.5;\n    border-radius: 3px;\n  }\n  .form-group-sm select.form-control {\n    height: 30px;\n    line-height: 30px;\n  }\n  .form-group-sm textarea.form-control,\n  .form-group-sm select[multiple].form-control {\n    height: auto;\n  }\n  .form-group-sm .form-control-static {\n    height: 30px;\n    min-height: 32px;\n    padding: 6px 10px;\n    font-size: 12px;\n    line-height: 1.5;\n  }\n  .input-lg {\n    height: 46px;\n    padding: 10px 16px;\n    font-size: 18px;\n    line-height: 1.3333333;\n    border-radius: 6px;\n  }\n  select.input-lg {\n    height: 46px;\n    line-height: 46px;\n  }\n  textarea.input-lg,\n  select[multiple].input-lg {\n    height: auto;\n  }\n  .form-group-lg .form-control {\n    height: 46px;\n    padding: 10px 16px;\n    font-size: 18px;\n    line-height: 1.3333333;\n    border-radius: 6px;\n  }\n  .form-group-lg select.form-control {\n    height: 46px;\n    line-height: 46px;\n  }\n  .form-group-lg textarea.form-control,\n  .form-group-lg select[multiple].form-control {\n    height: auto;\n  }\n  .form-group-lg .form-control-static {\n    height: 46px;\n    min-height: 38px;\n    padding: 11px 16px;\n    font-size: 18px;\n    line-height: 1.3333333;\n  }\n  .has-feedback {\n    position: relative;\n  }\n  .has-feedback .form-control {\n    padding-right: 42.5px;\n  }\n  .form-control-feedback {\n    position: absolute;\n    top: 0;\n    right: 0;\n    z-index: 2;\n    display: block;\n    width: 34px;\n    height: 34px;\n    line-height: 34px;\n    text-align: center;\n    pointer-events: none;\n  }\n  .input-lg + .form-control-feedback,\n  .input-group-lg + .form-control-feedback,\n  .form-group-lg .form-control + .form-control-feedback {\n    width: 46px;\n    height: 46px;\n    line-height: 46px;\n  }\n  .input-sm + .form-control-feedback,\n  .input-group-sm + .form-control-feedback,\n  .form-group-sm .form-control + .form-control-feedback {\n    width: 30px;\n    height: 30px;\n    line-height: 30px;\n  }\n  .has-success .help-block,\n  .has-success .control-label,\n  .has-success .radio,\n  .has-success .checkbox,\n  .has-success .radio-inline,\n  .has-success .checkbox-inline,\n  .has-success.radio label,\n  .has-success.checkbox label,\n  .has-success.radio-inline label,\n  .has-success.checkbox-inline label {\n    color: #3c763d;\n  }\n  .has-success .form-control {\n    border-color: #3c763d;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n            box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n  }\n  .has-success .form-control:focus {\n    border-color: #2b542c;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;\n            box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;\n  }\n  .has-success .input-group-addon {\n    color: #3c763d;\n    background-color: #dff0d8;\n    border-color: #3c763d;\n  }\n  .has-success .form-control-feedback {\n    color: #3c763d;\n  }\n  .has-warning .help-block,\n  .has-warning .control-label,\n  .has-warning .radio,\n  .has-warning .checkbox,\n  .has-warning .radio-inline,\n  .has-warning .checkbox-inline,\n  .has-warning.radio label,\n  .has-warning.checkbox label,\n  .has-warning.radio-inline label,\n  .has-warning.checkbox-inline label {\n    color: #8a6d3b;\n  }\n  .has-warning .form-control {\n    border-color: #8a6d3b;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n            box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n  }\n  .has-warning .form-control:focus {\n    border-color: #66512c;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;\n            box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;\n  }\n  .has-warning .input-group-addon {\n    color: #8a6d3b;\n    background-color: #fcf8e3;\n    border-color: #8a6d3b;\n  }\n  .has-warning .form-control-feedback {\n    color: #8a6d3b;\n  }\n  .has-error .help-block,\n  .has-error .control-label,\n  .has-error .radio,\n  .has-error .checkbox,\n  .has-error .radio-inline,\n  .has-error .checkbox-inline,\n  .has-error.radio label,\n  .has-error.checkbox label,\n  .has-error.radio-inline label,\n  .has-error.checkbox-inline label {\n    color: #a94442;\n  }\n  .has-error .form-control {\n    border-color: #a94442;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n            box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n  }\n  .has-error .form-control:focus {\n    border-color: #843534;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;\n            box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;\n  }\n  .has-error .input-group-addon {\n    color: #a94442;\n    background-color: #f2dede;\n    border-color: #a94442;\n  }\n  .has-error .form-control-feedback {\n    color: #a94442;\n  }\n  .has-feedback label ~ .form-control-feedback {\n    top: 25px;\n  }\n  .has-feedback label.sr-only ~ .form-control-feedback {\n    top: 0;\n  }\n  .help-block {\n    display: block;\n    margin-top: 5px;\n    margin-bottom: 10px;\n    color: #737373;\n  }\n  @media (min-width: 768px) {\n    .form-inline .form-group {\n      display: inline-block;\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n    .form-inline .form-control {\n      display: inline-block;\n      width: auto;\n      vertical-align: middle;\n    }\n    .form-inline .form-control-static {\n      display: inline-block;\n    }\n    .form-inline .input-group {\n      display: inline-table;\n      vertical-align: middle;\n    }\n    .form-inline .input-group .input-group-addon,\n    .form-inline .input-group .input-group-btn,\n    .form-inline .input-group .form-control {\n      width: auto;\n    }\n    .form-inline .input-group > .form-control {\n      width: 100%;\n    }\n    .form-inline .control-label {\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n    .form-inline .radio,\n    .form-inline .checkbox {\n      display: inline-block;\n      margin-top: 0;\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n    .form-inline .radio label,\n    .form-inline .checkbox label {\n      padding-left: 0;\n    }\n    .form-inline .radio input[type=\"radio\"],\n    .form-inline .checkbox input[type=\"checkbox\"] {\n      position: relative;\n      margin-left: 0;\n    }\n    .form-inline .has-feedback .form-control-feedback {\n      top: 0;\n    }\n  }\n  .form-horizontal .radio,\n  .form-horizontal .checkbox,\n  .form-horizontal .radio-inline,\n  .form-horizontal .checkbox-inline {\n    padding-top: 7px;\n    margin-top: 0;\n    margin-bottom: 0;\n  }\n  .form-horizontal .radio,\n  .form-horizontal .checkbox {\n    min-height: 27px;\n  }\n  .form-horizontal .form-group {\n    margin-right: -15px;\n    margin-left: -15px;\n  }\n  @media (min-width: 768px) {\n    .form-horizontal .control-label {\n      padding-top: 7px;\n      margin-bottom: 0;\n      text-align: right;\n    }\n  }\n  .form-horizontal .has-feedback .form-control-feedback {\n    right: 15px;\n  }\n  @media (min-width: 768px) {\n    .form-horizontal .form-group-lg .control-label {\n      padding-top: 11px;\n      font-size: 18px;\n    }\n  }\n  @media (min-width: 768px) {\n    .form-horizontal .form-group-sm .control-label {\n      padding-top: 6px;\n      font-size: 12px;\n    }\n  }\n  .btn {\n    display: inline-block;\n    padding: 6px 12px;\n    margin-bottom: 0;\n    font-size: 14px;\n    font-weight: normal;\n    line-height: 1.42857143;\n    text-align: center;\n    white-space: nowrap;\n    vertical-align: middle;\n    -ms-touch-action: manipulation;\n        touch-action: manipulation;\n    cursor: pointer;\n    -webkit-user-select: none;\n       -moz-user-select: none;\n        -ms-user-select: none;\n            user-select: none;\n    background-image: none;\n    border: 1px solid transparent;\n    border-radius: 4px;\n  }\n  .btn:focus,\n  .btn:active:focus,\n  .btn.active:focus,\n  .btn.focus,\n  .btn:active.focus,\n  .btn.active.focus {\n    outline: 5px auto -webkit-focus-ring-color;\n    outline-offset: -2px;\n  }\n  .btn:hover,\n  .btn:focus,\n  .btn.focus {\n    color: #333;\n    text-decoration: none;\n  }\n  .btn:active,\n  .btn.active {\n    background-image: none;\n    outline: 0;\n    -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n            box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n  }\n  .btn.disabled,\n  .btn[disabled],\n  fieldset[disabled] .btn {\n    cursor: not-allowed;\n    filter: alpha(opacity=65);\n    -webkit-box-shadow: none;\n            box-shadow: none;\n    opacity: .65;\n  }\n  a.btn.disabled,\n  fieldset[disabled] a.btn {\n    pointer-events: none;\n  }\n  .btn-default {\n    color: #333;\n    background-color: #fff;\n    border-color: #ccc;\n  }\n  .btn-default:focus,\n  .btn-default.focus {\n    color: #333;\n    background-color: #e6e6e6;\n    border-color: #8c8c8c;\n  }\n  .btn-default:hover {\n    color: #333;\n    background-color: #e6e6e6;\n    border-color: #adadad;\n  }\n  .btn-default:active,\n  .btn-default.active,\n  .open > .dropdown-toggle.btn-default {\n    color: #333;\n    background-color: #e6e6e6;\n    border-color: #adadad;\n  }\n  .btn-default:active:hover,\n  .btn-default.active:hover,\n  .open > .dropdown-toggle.btn-default:hover,\n  .btn-default:active:focus,\n  .btn-default.active:focus,\n  .open > .dropdown-toggle.btn-default:focus,\n  .btn-default:active.focus,\n  .btn-default.active.focus,\n  .open > .dropdown-toggle.btn-default.focus {\n    color: #333;\n    background-color: #d4d4d4;\n    border-color: #8c8c8c;\n  }\n  .btn-default:active,\n  .btn-default.active,\n  .open > .dropdown-toggle.btn-default {\n    background-image: none;\n  }\n  .btn-default.disabled:hover,\n  .btn-default[disabled]:hover,\n  fieldset[disabled] .btn-default:hover,\n  .btn-default.disabled:focus,\n  .btn-default[disabled]:focus,\n  fieldset[disabled] .btn-default:focus,\n  .btn-default.disabled.focus,\n  .btn-default[disabled].focus,\n  fieldset[disabled] .btn-default.focus {\n    background-color: #fff;\n    border-color: #ccc;\n  }\n  .btn-default .badge {\n    color: #fff;\n    background-color: #333;\n  }\n  .btn-primary {\n    color: #fff;\n    background-color: #337ab7;\n    border-color: #2e6da4;\n  }\n  .btn-primary:focus,\n  .btn-primary.focus {\n    color: #fff;\n    background-color: #286090;\n    border-color: #122b40;\n  }\n  .btn-primary:hover {\n    color: #fff;\n    background-color: #286090;\n    border-color: #204d74;\n  }\n  .btn-primary:active,\n  .btn-primary.active,\n  .open > .dropdown-toggle.btn-primary {\n    color: #fff;\n    background-color: #286090;\n    border-color: #204d74;\n  }\n  .btn-primary:active:hover,\n  .btn-primary.active:hover,\n  .open > .dropdown-toggle.btn-primary:hover,\n  .btn-primary:active:focus,\n  .btn-primary.active:focus,\n  .open > .dropdown-toggle.btn-primary:focus,\n  .btn-primary:active.focus,\n  .btn-primary.active.focus,\n  .open > .dropdown-toggle.btn-primary.focus {\n    color: #fff;\n    background-color: #204d74;\n    border-color: #122b40;\n  }\n  .btn-primary:active,\n  .btn-primary.active,\n  .open > .dropdown-toggle.btn-primary {\n    background-image: none;\n  }\n  .btn-primary.disabled:hover,\n  .btn-primary[disabled]:hover,\n  fieldset[disabled] .btn-primary:hover,\n  .btn-primary.disabled:focus,\n  .btn-primary[disabled]:focus,\n  fieldset[disabled] .btn-primary:focus,\n  .btn-primary.disabled.focus,\n  .btn-primary[disabled].focus,\n  fieldset[disabled] .btn-primary.focus {\n    background-color: #337ab7;\n    border-color: #2e6da4;\n  }\n  .btn-primary .badge {\n    color: #337ab7;\n    background-color: #fff;\n  }\n  .btn-success {\n    color: #fff;\n    background-color: #5cb85c;\n    border-color: #4cae4c;\n  }\n  .btn-success:focus,\n  .btn-success.focus {\n    color: #fff;\n    background-color: #449d44;\n    border-color: #255625;\n  }\n  .btn-success:hover {\n    color: #fff;\n    background-color: #449d44;\n    border-color: #398439;\n  }\n  .btn-success:active,\n  .btn-success.active,\n  .open > .dropdown-toggle.btn-success {\n    color: #fff;\n    background-color: #449d44;\n    border-color: #398439;\n  }\n  .btn-success:active:hover,\n  .btn-success.active:hover,\n  .open > .dropdown-toggle.btn-success:hover,\n  .btn-success:active:focus,\n  .btn-success.active:focus,\n  .open > .dropdown-toggle.btn-success:focus,\n  .btn-success:active.focus,\n  .btn-success.active.focus,\n  .open > .dropdown-toggle.btn-success.focus {\n    color: #fff;\n    background-color: #398439;\n    border-color: #255625;\n  }\n  .btn-success:active,\n  .btn-success.active,\n  .open > .dropdown-toggle.btn-success {\n    background-image: none;\n  }\n  .btn-success.disabled:hover,\n  .btn-success[disabled]:hover,\n  fieldset[disabled] .btn-success:hover,\n  .btn-success.disabled:focus,\n  .btn-success[disabled]:focus,\n  fieldset[disabled] .btn-success:focus,\n  .btn-success.disabled.focus,\n  .btn-success[disabled].focus,\n  fieldset[disabled] .btn-success.focus {\n    background-color: #5cb85c;\n    border-color: #4cae4c;\n  }\n  .btn-success .badge {\n    color: #5cb85c;\n    background-color: #fff;\n  }\n  .btn-info {\n    color: #fff;\n    background-color: #5bc0de;\n    border-color: #46b8da;\n  }\n  .btn-info:focus,\n  .btn-info.focus {\n    color: #fff;\n    background-color: #31b0d5;\n    border-color: #1b6d85;\n  }\n  .btn-info:hover {\n    color: #fff;\n    background-color: #31b0d5;\n    border-color: #269abc;\n  }\n  .btn-info:active,\n  .btn-info.active,\n  .open > .dropdown-toggle.btn-info {\n    color: #fff;\n    background-color: #31b0d5;\n    border-color: #269abc;\n  }\n  .btn-info:active:hover,\n  .btn-info.active:hover,\n  .open > .dropdown-toggle.btn-info:hover,\n  .btn-info:active:focus,\n  .btn-info.active:focus,\n  .open > .dropdown-toggle.btn-info:focus,\n  .btn-info:active.focus,\n  .btn-info.active.focus,\n  .open > .dropdown-toggle.btn-info.focus {\n    color: #fff;\n    background-color: #269abc;\n    border-color: #1b6d85;\n  }\n  .btn-info:active,\n  .btn-info.active,\n  .open > .dropdown-toggle.btn-info {\n    background-image: none;\n  }\n  .btn-info.disabled:hover,\n  .btn-info[disabled]:hover,\n  fieldset[disabled] .btn-info:hover,\n  .btn-info.disabled:focus,\n  .btn-info[disabled]:focus,\n  fieldset[disabled] .btn-info:focus,\n  .btn-info.disabled.focus,\n  .btn-info[disabled].focus,\n  fieldset[disabled] .btn-info.focus {\n    background-color: #5bc0de;\n    border-color: #46b8da;\n  }\n  .btn-info .badge {\n    color: #5bc0de;\n    background-color: #fff;\n  }\n  .btn-warning {\n    color: #fff;\n    background-color: #f0ad4e;\n    border-color: #eea236;\n  }\n  .btn-warning:focus,\n  .btn-warning.focus {\n    color: #fff;\n    background-color: #ec971f;\n    border-color: #985f0d;\n  }\n  .btn-warning:hover {\n    color: #fff;\n    background-color: #ec971f;\n    border-color: #d58512;\n  }\n  .btn-warning:active,\n  .btn-warning.active,\n  .open > .dropdown-toggle.btn-warning {\n    color: #fff;\n    background-color: #ec971f;\n    border-color: #d58512;\n  }\n  .btn-warning:active:hover,\n  .btn-warning.active:hover,\n  .open > .dropdown-toggle.btn-warning:hover,\n  .btn-warning:active:focus,\n  .btn-warning.active:focus,\n  .open > .dropdown-toggle.btn-warning:focus,\n  .btn-warning:active.focus,\n  .btn-warning.active.focus,\n  .open > .dropdown-toggle.btn-warning.focus {\n    color: #fff;\n    background-color: #d58512;\n    border-color: #985f0d;\n  }\n  .btn-warning:active,\n  .btn-warning.active,\n  .open > .dropdown-toggle.btn-warning {\n    background-image: none;\n  }\n  .btn-warning.disabled:hover,\n  .btn-warning[disabled]:hover,\n  fieldset[disabled] .btn-warning:hover,\n  .btn-warning.disabled:focus,\n  .btn-warning[disabled]:focus,\n  fieldset[disabled] .btn-warning:focus,\n  .btn-warning.disabled.focus,\n  .btn-warning[disabled].focus,\n  fieldset[disabled] .btn-warning.focus {\n    background-color: #f0ad4e;\n    border-color: #eea236;\n  }\n  .btn-warning .badge {\n    color: #f0ad4e;\n    background-color: #fff;\n  }\n  .btn-danger {\n    color: #fff;\n    background-color: #d9534f;\n    border-color: #d43f3a;\n  }\n  .btn-danger:focus,\n  .btn-danger.focus {\n    color: #fff;\n    background-color: #c9302c;\n    border-color: #761c19;\n  }\n  .btn-danger:hover {\n    color: #fff;\n    background-color: #c9302c;\n    border-color: #ac2925;\n  }\n  .btn-danger:active,\n  .btn-danger.active,\n  .open > .dropdown-toggle.btn-danger {\n    color: #fff;\n    background-color: #c9302c;\n    border-color: #ac2925;\n  }\n  .btn-danger:active:hover,\n  .btn-danger.active:hover,\n  .open > .dropdown-toggle.btn-danger:hover,\n  .btn-danger:active:focus,\n  .btn-danger.active:focus,\n  .open > .dropdown-toggle.btn-danger:focus,\n  .btn-danger:active.focus,\n  .btn-danger.active.focus,\n  .open > .dropdown-toggle.btn-danger.focus {\n    color: #fff;\n    background-color: #ac2925;\n    border-color: #761c19;\n  }\n  .btn-danger:active,\n  .btn-danger.active,\n  .open > .dropdown-toggle.btn-danger {\n    background-image: none;\n  }\n  .btn-danger.disabled:hover,\n  .btn-danger[disabled]:hover,\n  fieldset[disabled] .btn-danger:hover,\n  .btn-danger.disabled:focus,\n  .btn-danger[disabled]:focus,\n  fieldset[disabled] .btn-danger:focus,\n  .btn-danger.disabled.focus,\n  .btn-danger[disabled].focus,\n  fieldset[disabled] .btn-danger.focus {\n    background-color: #d9534f;\n    border-color: #d43f3a;\n  }\n  .btn-danger .badge {\n    color: #d9534f;\n    background-color: #fff;\n  }\n  .btn-link {\n    font-weight: normal;\n    color: #337ab7;\n    border-radius: 0;\n  }\n  .btn-link,\n  .btn-link:active,\n  .btn-link.active,\n  .btn-link[disabled],\n  fieldset[disabled] .btn-link {\n    background-color: transparent;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n  .btn-link,\n  .btn-link:hover,\n  .btn-link:focus,\n  .btn-link:active {\n    border-color: transparent;\n  }\n  .btn-link:hover,\n  .btn-link:focus {\n    color: #23527c;\n    text-decoration: underline;\n    background-color: transparent;\n  }\n  .btn-link[disabled]:hover,\n  fieldset[disabled] .btn-link:hover,\n  .btn-link[disabled]:focus,\n  fieldset[disabled] .btn-link:focus {\n    color: #777;\n    text-decoration: none;\n  }\n  .btn-lg,\n  .btn-group-lg > .btn {\n    padding: 10px 16px;\n    font-size: 18px;\n    line-height: 1.3333333;\n    border-radius: 6px;\n  }\n  .btn-sm,\n  .btn-group-sm > .btn {\n    padding: 5px 10px;\n    font-size: 12px;\n    line-height: 1.5;\n    border-radius: 3px;\n  }\n  .btn-xs,\n  .btn-group-xs > .btn {\n    padding: 1px 5px;\n    font-size: 12px;\n    line-height: 1.5;\n    border-radius: 3px;\n  }\n  .btn-block {\n    display: block;\n    width: 100%;\n  }\n  .btn-block + .btn-block {\n    margin-top: 5px;\n  }\n  input[type=\"submit\"].btn-block,\n  input[type=\"reset\"].btn-block,\n  input[type=\"button\"].btn-block {\n    width: 100%;\n  }\n  .fade {\n    opacity: 0;\n    -webkit-transition: opacity .15s linear;\n         -o-transition: opacity .15s linear;\n            transition: opacity .15s linear;\n  }\n  .fade.in {\n    opacity: 1;\n  }\n  .collapse {\n    display: none;\n  }\n  .collapse.in {\n    display: block;\n  }\n  tr.collapse.in {\n    display: table-row;\n  }\n  tbody.collapse.in {\n    display: table-row-group;\n  }\n  .collapsing {\n    position: relative;\n    height: 0;\n    overflow: hidden;\n    -webkit-transition-timing-function: ease;\n         -o-transition-timing-function: ease;\n            transition-timing-function: ease;\n    -webkit-transition-duration: .35s;\n         -o-transition-duration: .35s;\n            transition-duration: .35s;\n    -webkit-transition-property: height, visibility;\n         -o-transition-property: height, visibility;\n            transition-property: height, visibility;\n  }\n  .caret {\n    display: inline-block;\n    width: 0;\n    height: 0;\n    margin-left: 2px;\n    vertical-align: middle;\n    border-top: 4px dashed;\n    border-top: 4px solid \\9;\n    border-right: 4px solid transparent;\n    border-left: 4px solid transparent;\n  }\n  .dropup,\n  .dropdown {\n    position: relative;\n  }\n  .dropdown-toggle:focus {\n    outline: 0;\n  }\n  .dropdown-menu {\n    position: absolute;\n    top: 100%;\n    left: 0;\n    z-index: 1000;\n    display: none;\n    float: left;\n    min-width: 160px;\n    padding: 5px 0;\n    margin: 2px 0 0;\n    font-size: 14px;\n    text-align: left;\n    list-style: none;\n    background-color: #fff;\n    -webkit-background-clip: padding-box;\n            background-clip: padding-box;\n    border: 1px solid #ccc;\n    border: 1px solid rgba(0, 0, 0, .15);\n    border-radius: 4px;\n    -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n            box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n  }\n  .dropdown-menu.pull-right {\n    right: 0;\n    left: auto;\n  }\n  .dropdown-menu .divider {\n    height: 1px;\n    margin: 9px 0;\n    overflow: hidden;\n    background-color: #e5e5e5;\n  }\n  .dropdown-menu > li > a {\n    display: block;\n    padding: 3px 20px;\n    clear: both;\n    font-weight: normal;\n    line-height: 1.42857143;\n    color: #333;\n    white-space: nowrap;\n  }\n  .dropdown-menu > li > a:hover,\n  .dropdown-menu > li > a:focus {\n    color: #262626;\n    text-decoration: none;\n    background-color: #f5f5f5;\n  }\n  .dropdown-menu > .active > a,\n  .dropdown-menu > .active > a:hover,\n  .dropdown-menu > .active > a:focus {\n    color: #fff;\n    text-decoration: none;\n    background-color: #337ab7;\n    outline: 0;\n  }\n  .dropdown-menu > .disabled > a,\n  .dropdown-menu > .disabled > a:hover,\n  .dropdown-menu > .disabled > a:focus {\n    color: #777;\n  }\n  .dropdown-menu > .disabled > a:hover,\n  .dropdown-menu > .disabled > a:focus {\n    text-decoration: none;\n    cursor: not-allowed;\n    background-color: transparent;\n    background-image: none;\n    filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  }\n  .open > .dropdown-menu {\n    display: block;\n  }\n  .open > a {\n    outline: 0;\n  }\n  .dropdown-menu-right {\n    right: 0;\n    left: auto;\n  }\n  .dropdown-menu-left {\n    right: auto;\n    left: 0;\n  }\n  .dropdown-header {\n    display: block;\n    padding: 3px 20px;\n    font-size: 12px;\n    line-height: 1.42857143;\n    color: #777;\n    white-space: nowrap;\n  }\n  .dropdown-backdrop {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    z-index: 990;\n  }\n  .pull-right > .dropdown-menu {\n    right: 0;\n    left: auto;\n  }\n  .dropup .caret,\n  .navbar-fixed-bottom .dropdown .caret {\n    content: \"\";\n    border-top: 0;\n    border-bottom: 4px dashed;\n    border-bottom: 4px solid \\9;\n  }\n  .dropup .dropdown-menu,\n  .navbar-fixed-bottom .dropdown .dropdown-menu {\n    top: auto;\n    bottom: 100%;\n    margin-bottom: 2px;\n  }\n  @media (min-width: 768px) {\n    .navbar-right .dropdown-menu {\n      right: 0;\n      left: auto;\n    }\n    .navbar-right .dropdown-menu-left {\n      right: auto;\n      left: 0;\n    }\n  }\n  .btn-group,\n  .btn-group-vertical {\n    position: relative;\n    display: inline-block;\n    vertical-align: middle;\n  }\n  .btn-group > .btn,\n  .btn-group-vertical > .btn {\n    position: relative;\n    float: left;\n  }\n  .btn-group > .btn:hover,\n  .btn-group-vertical > .btn:hover,\n  .btn-group > .btn:focus,\n  .btn-group-vertical > .btn:focus,\n  .btn-group > .btn:active,\n  .btn-group-vertical > .btn:active,\n  .btn-group > .btn.active,\n  .btn-group-vertical > .btn.active {\n    z-index: 2;\n  }\n  .btn-group .btn + .btn,\n  .btn-group .btn + .btn-group,\n  .btn-group .btn-group + .btn,\n  .btn-group .btn-group + .btn-group {\n    margin-left: -1px;\n  }\n  .btn-toolbar {\n    margin-left: -5px;\n  }\n  .btn-toolbar .btn,\n  .btn-toolbar .btn-group,\n  .btn-toolbar .input-group {\n    float: left;\n  }\n  .btn-toolbar > .btn,\n  .btn-toolbar > .btn-group,\n  .btn-toolbar > .input-group {\n    margin-left: 5px;\n  }\n  .btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n    border-radius: 0;\n  }\n  .btn-group > .btn:first-child {\n    margin-left: 0;\n  }\n  .btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n    border-top-right-radius: 0;\n    border-bottom-right-radius: 0;\n  }\n  .btn-group > .btn:last-child:not(:first-child),\n  .btn-group > .dropdown-toggle:not(:first-child) {\n    border-top-left-radius: 0;\n    border-bottom-left-radius: 0;\n  }\n  .btn-group > .btn-group {\n    float: left;\n  }\n  .btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n    border-radius: 0;\n  }\n  .btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n  .btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n    border-top-right-radius: 0;\n    border-bottom-right-radius: 0;\n  }\n  .btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n    border-top-left-radius: 0;\n    border-bottom-left-radius: 0;\n  }\n  .btn-group .dropdown-toggle:active,\n  .btn-group.open .dropdown-toggle {\n    outline: 0;\n  }\n  .btn-group > .btn + .dropdown-toggle {\n    padding-right: 8px;\n    padding-left: 8px;\n  }\n  .btn-group > .btn-lg + .dropdown-toggle {\n    padding-right: 12px;\n    padding-left: 12px;\n  }\n  .btn-group.open .dropdown-toggle {\n    -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n            box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n  }\n  .btn-group.open .dropdown-toggle.btn-link {\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n  .btn .caret {\n    margin-left: 0;\n  }\n  .btn-lg .caret {\n    border-width: 5px 5px 0;\n    border-bottom-width: 0;\n  }\n  .dropup .btn-lg .caret {\n    border-width: 0 5px 5px;\n  }\n  .btn-group-vertical > .btn,\n  .btn-group-vertical > .btn-group,\n  .btn-group-vertical > .btn-group > .btn {\n    display: block;\n    float: none;\n    width: 100%;\n    max-width: 100%;\n  }\n  .btn-group-vertical > .btn-group > .btn {\n    float: none;\n  }\n  .btn-group-vertical > .btn + .btn,\n  .btn-group-vertical > .btn + .btn-group,\n  .btn-group-vertical > .btn-group + .btn,\n  .btn-group-vertical > .btn-group + .btn-group {\n    margin-top: -1px;\n    margin-left: 0;\n  }\n  .btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n    border-radius: 0;\n  }\n  .btn-group-vertical > .btn:first-child:not(:last-child) {\n    border-top-left-radius: 4px;\n    border-top-right-radius: 4px;\n    border-bottom-right-radius: 0;\n    border-bottom-left-radius: 0;\n  }\n  .btn-group-vertical > .btn:last-child:not(:first-child) {\n    border-top-left-radius: 0;\n    border-top-right-radius: 0;\n    border-bottom-right-radius: 4px;\n    border-bottom-left-radius: 4px;\n  }\n  .btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n    border-radius: 0;\n  }\n  .btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n  .btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n    border-bottom-right-radius: 0;\n    border-bottom-left-radius: 0;\n  }\n  .btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n    border-top-left-radius: 0;\n    border-top-right-radius: 0;\n  }\n  .btn-group-justified {\n    display: table;\n    width: 100%;\n    table-layout: fixed;\n    border-collapse: separate;\n  }\n  .btn-group-justified > .btn,\n  .btn-group-justified > .btn-group {\n    display: table-cell;\n    float: none;\n    width: 1%;\n  }\n  .btn-group-justified > .btn-group .btn {\n    width: 100%;\n  }\n  .btn-group-justified > .btn-group .dropdown-menu {\n    left: auto;\n  }\n  [data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n  [data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n  [data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n  [data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n    position: absolute;\n    clip: rect(0, 0, 0, 0);\n    pointer-events: none;\n  }\n  .input-group {\n    position: relative;\n    display: table;\n    border-collapse: separate;\n  }\n  .input-group[class*=\"col-\"] {\n    float: none;\n    padding-right: 0;\n    padding-left: 0;\n  }\n  .input-group .form-control {\n    position: relative;\n    z-index: 2;\n    float: left;\n    width: 100%;\n    margin-bottom: 0;\n  }\n  .input-group .form-control:focus {\n    z-index: 3;\n  }\n  .input-group-lg > .form-control,\n  .input-group-lg > .input-group-addon,\n  .input-group-lg > .input-group-btn > .btn {\n    height: 46px;\n    padding: 10px 16px;\n    font-size: 18px;\n    line-height: 1.3333333;\n    border-radius: 6px;\n  }\n  select.input-group-lg > .form-control,\n  select.input-group-lg > .input-group-addon,\n  select.input-group-lg > .input-group-btn > .btn {\n    height: 46px;\n    line-height: 46px;\n  }\n  textarea.input-group-lg > .form-control,\n  textarea.input-group-lg > .input-group-addon,\n  textarea.input-group-lg > .input-group-btn > .btn,\n  select[multiple].input-group-lg > .form-control,\n  select[multiple].input-group-lg > .input-group-addon,\n  select[multiple].input-group-lg > .input-group-btn > .btn {\n    height: auto;\n  }\n  .input-group-sm > .form-control,\n  .input-group-sm > .input-group-addon,\n  .input-group-sm > .input-group-btn > .btn {\n    height: 30px;\n    padding: 5px 10px;\n    font-size: 12px;\n    line-height: 1.5;\n    border-radius: 3px;\n  }\n  select.input-group-sm > .form-control,\n  select.input-group-sm > .input-group-addon,\n  select.input-group-sm > .input-group-btn > .btn {\n    height: 30px;\n    line-height: 30px;\n  }\n  textarea.input-group-sm > .form-control,\n  textarea.input-group-sm > .input-group-addon,\n  textarea.input-group-sm > .input-group-btn > .btn,\n  select[multiple].input-group-sm > .form-control,\n  select[multiple].input-group-sm > .input-group-addon,\n  select[multiple].input-group-sm > .input-group-btn > .btn {\n    height: auto;\n  }\n  .input-group-addon,\n  .input-group-btn,\n  .input-group .form-control {\n    display: table-cell;\n  }\n  .input-group-addon:not(:first-child):not(:last-child),\n  .input-group-btn:not(:first-child):not(:last-child),\n  .input-group .form-control:not(:first-child):not(:last-child) {\n    border-radius: 0;\n  }\n  .input-group-addon,\n  .input-group-btn {\n    width: 1%;\n    white-space: nowrap;\n    vertical-align: middle;\n  }\n  .input-group-addon {\n    padding: 6px 12px;\n    font-size: 14px;\n    font-weight: normal;\n    line-height: 1;\n    color: #555;\n    text-align: center;\n    background-color: #eee;\n    border: 1px solid #ccc;\n    border-radius: 4px;\n  }\n  .input-group-addon.input-sm {\n    padding: 5px 10px;\n    font-size: 12px;\n    border-radius: 3px;\n  }\n  .input-group-addon.input-lg {\n    padding: 10px 16px;\n    font-size: 18px;\n    border-radius: 6px;\n  }\n  .input-group-addon input[type=\"radio\"],\n  .input-group-addon input[type=\"checkbox\"] {\n    margin-top: 0;\n  }\n  .input-group .form-control:first-child,\n  .input-group-addon:first-child,\n  .input-group-btn:first-child > .btn,\n  .input-group-btn:first-child > .btn-group > .btn,\n  .input-group-btn:first-child > .dropdown-toggle,\n  .input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n  .input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n    border-top-right-radius: 0;\n    border-bottom-right-radius: 0;\n  }\n  .input-group-addon:first-child {\n    border-right: 0;\n  }\n  .input-group .form-control:last-child,\n  .input-group-addon:last-child,\n  .input-group-btn:last-child > .btn,\n  .input-group-btn:last-child > .btn-group > .btn,\n  .input-group-btn:last-child > .dropdown-toggle,\n  .input-group-btn:first-child > .btn:not(:first-child),\n  .input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n    border-top-left-radius: 0;\n    border-bottom-left-radius: 0;\n  }\n  .input-group-addon:last-child {\n    border-left: 0;\n  }\n  .input-group-btn {\n    position: relative;\n    font-size: 0;\n    white-space: nowrap;\n  }\n  .input-group-btn > .btn {\n    position: relative;\n  }\n  .input-group-btn > .btn + .btn {\n    margin-left: -1px;\n  }\n  .input-group-btn > .btn:hover,\n  .input-group-btn > .btn:focus,\n  .input-group-btn > .btn:active {\n    z-index: 2;\n  }\n  .input-group-btn:first-child > .btn,\n  .input-group-btn:first-child > .btn-group {\n    margin-right: -1px;\n  }\n  .input-group-btn:last-child > .btn,\n  .input-group-btn:last-child > .btn-group {\n    z-index: 2;\n    margin-left: -1px;\n  }\n  .nav {\n    padding-left: 0;\n    margin-bottom: 0;\n    list-style: none;\n  }\n  .nav > li {\n    position: relative;\n    display: block;\n  }\n  .nav > li > a {\n    position: relative;\n    display: block;\n    padding: 10px 15px;\n  }\n  .nav > li > a:hover,\n  .nav > li > a:focus {\n    text-decoration: none;\n    background-color: #eee;\n  }\n  .nav > li.disabled > a {\n    color: #777;\n  }\n  .nav > li.disabled > a:hover,\n  .nav > li.disabled > a:focus {\n    color: #777;\n    text-decoration: none;\n    cursor: not-allowed;\n    background-color: transparent;\n  }\n  .nav .open > a,\n  .nav .open > a:hover,\n  .nav .open > a:focus {\n    background-color: #eee;\n    border-color: #337ab7;\n  }\n  .nav .nav-divider {\n    height: 1px;\n    margin: 9px 0;\n    overflow: hidden;\n    background-color: #e5e5e5;\n  }\n  .nav > li > a > img {\n    max-width: none;\n  }\n  .nav-tabs {\n    border-bottom: 1px solid #ddd;\n  }\n  .nav-tabs > li {\n    float: left;\n    margin-bottom: -1px;\n  }\n  .nav-tabs > li > a {\n    margin-right: 2px;\n    line-height: 1.42857143;\n    border: 1px solid transparent;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs > li > a:hover {\n    border-color: #eee #eee #ddd;\n  }\n  .nav-tabs > li.active > a,\n  .nav-tabs > li.active > a:hover,\n  .nav-tabs > li.active > a:focus {\n    color: #555;\n    cursor: default;\n    background-color: #fff;\n    border: 1px solid #ddd;\n    border-bottom-color: transparent;\n  }\n  .nav-tabs.nav-justified {\n    width: 100%;\n    border-bottom: 0;\n  }\n  .nav-tabs.nav-justified > li {\n    float: none;\n  }\n  .nav-tabs.nav-justified > li > a {\n    margin-bottom: 5px;\n    text-align: center;\n  }\n  .nav-tabs.nav-justified > .dropdown .dropdown-menu {\n    top: auto;\n    left: auto;\n  }\n  @media (min-width: 768px) {\n    .nav-tabs.nav-justified > li {\n      display: table-cell;\n      width: 1%;\n    }\n    .nav-tabs.nav-justified > li > a {\n      margin-bottom: 0;\n    }\n  }\n  .nav-tabs.nav-justified > li > a {\n    margin-right: 0;\n    border-radius: 4px;\n  }\n  .nav-tabs.nav-justified > .active > a,\n  .nav-tabs.nav-justified > .active > a:hover,\n  .nav-tabs.nav-justified > .active > a:focus {\n    border: 1px solid #ddd;\n  }\n  @media (min-width: 768px) {\n    .nav-tabs.nav-justified > li > a {\n      border-bottom: 1px solid #ddd;\n      border-radius: 4px 4px 0 0;\n    }\n    .nav-tabs.nav-justified > .active > a,\n    .nav-tabs.nav-justified > .active > a:hover,\n    .nav-tabs.nav-justified > .active > a:focus {\n      border-bottom-color: #fff;\n    }\n  }\n  .nav-pills > li {\n    float: left;\n  }\n  .nav-pills > li > a {\n    border-radius: 4px;\n  }\n  .nav-pills > li + li {\n    margin-left: 2px;\n  }\n  .nav-pills > li.active > a,\n  .nav-pills > li.active > a:hover,\n  .nav-pills > li.active > a:focus {\n    color: #fff;\n    background-color: #337ab7;\n  }\n  .nav-stacked > li {\n    float: none;\n  }\n  .nav-stacked > li + li {\n    margin-top: 2px;\n    margin-left: 0;\n  }\n  .nav-justified {\n    width: 100%;\n  }\n  .nav-justified > li {\n    float: none;\n  }\n  .nav-justified > li > a {\n    margin-bottom: 5px;\n    text-align: center;\n  }\n  .nav-justified > .dropdown .dropdown-menu {\n    top: auto;\n    left: auto;\n  }\n  @media (min-width: 768px) {\n    .nav-justified > li {\n      display: table-cell;\n      width: 1%;\n    }\n    .nav-justified > li > a {\n      margin-bottom: 0;\n    }\n  }\n  .nav-tabs-justified {\n    border-bottom: 0;\n  }\n  .nav-tabs-justified > li > a {\n    margin-right: 0;\n    border-radius: 4px;\n  }\n  .nav-tabs-justified > .active > a,\n  .nav-tabs-justified > .active > a:hover,\n  .nav-tabs-justified > .active > a:focus {\n    border: 1px solid #ddd;\n  }\n  @media (min-width: 768px) {\n    .nav-tabs-justified > li > a {\n      border-bottom: 1px solid #ddd;\n      border-radius: 4px 4px 0 0;\n    }\n    .nav-tabs-justified > .active > a,\n    .nav-tabs-justified > .active > a:hover,\n    .nav-tabs-justified > .active > a:focus {\n      border-bottom-color: #fff;\n    }\n  }\n  .tab-content > .tab-pane {\n    display: none;\n  }\n  .tab-content > .active {\n    display: block;\n  }\n  .nav-tabs .dropdown-menu {\n    margin-top: -1px;\n    border-top-left-radius: 0;\n    border-top-right-radius: 0;\n  }\n  .navbar {\n    position: relative;\n    min-height: 50px;\n    margin-bottom: 20px;\n    border: 1px solid transparent;\n  }\n  @media (min-width: 768px) {\n    .navbar {\n      border-radius: 4px;\n    }\n  }\n  @media (min-width: 768px) {\n    .navbar-header {\n      float: left;\n    }\n  }\n  .navbar-collapse {\n    padding-right: 15px;\n    padding-left: 15px;\n    overflow-x: visible;\n    -webkit-overflow-scrolling: touch;\n    border-top: 1px solid transparent;\n    -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);\n            box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);\n  }\n  .navbar-collapse.in {\n    overflow-y: auto;\n  }\n  @media (min-width: 768px) {\n    .navbar-collapse {\n      width: auto;\n      border-top: 0;\n      -webkit-box-shadow: none;\n              box-shadow: none;\n    }\n    .navbar-collapse.collapse {\n      display: block !important;\n      height: auto !important;\n      padding-bottom: 0;\n      overflow: visible !important;\n    }\n    .navbar-collapse.in {\n      overflow-y: visible;\n    }\n    .navbar-fixed-top .navbar-collapse,\n    .navbar-static-top .navbar-collapse,\n    .navbar-fixed-bottom .navbar-collapse {\n      padding-right: 0;\n      padding-left: 0;\n    }\n  }\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    max-height: 340px;\n  }\n  @media (max-device-width: 480px) and (orientation: landscape) {\n    .navbar-fixed-top .navbar-collapse,\n    .navbar-fixed-bottom .navbar-collapse {\n      max-height: 200px;\n    }\n  }\n  .container > .navbar-header,\n  .container-fluid > .navbar-header,\n  .container > .navbar-collapse,\n  .container-fluid > .navbar-collapse {\n    margin-right: -15px;\n    margin-left: -15px;\n  }\n  @media (min-width: 768px) {\n    .container > .navbar-header,\n    .container-fluid > .navbar-header,\n    .container > .navbar-collapse,\n    .container-fluid > .navbar-collapse {\n      margin-right: 0;\n      margin-left: 0;\n    }\n  }\n  .navbar-static-top {\n    z-index: 1000;\n    border-width: 0 0 1px;\n  }\n  @media (min-width: 768px) {\n    .navbar-static-top {\n      border-radius: 0;\n    }\n  }\n  .navbar-fixed-top,\n  .navbar-fixed-bottom {\n    position: fixed;\n    right: 0;\n    left: 0;\n    z-index: 1030;\n  }\n  @media (min-width: 768px) {\n    .navbar-fixed-top,\n    .navbar-fixed-bottom {\n      border-radius: 0;\n    }\n  }\n  .navbar-fixed-top {\n    top: 0;\n    border-width: 0 0 1px;\n  }\n  .navbar-fixed-bottom {\n    bottom: 0;\n    margin-bottom: 0;\n    border-width: 1px 0 0;\n  }\n  .navbar-brand {\n    float: left;\n    height: 50px;\n    padding: 15px 15px;\n    font-size: 18px;\n    line-height: 20px;\n  }\n  .navbar-brand:hover,\n  .navbar-brand:focus {\n    text-decoration: none;\n  }\n  .navbar-brand > img {\n    display: block;\n  }\n  @media (min-width: 768px) {\n    .navbar > .container .navbar-brand,\n    .navbar > .container-fluid .navbar-brand {\n      margin-left: -15px;\n    }\n  }\n  .navbar-toggle {\n    position: relative;\n    float: right;\n    padding: 9px 10px;\n    margin-top: 8px;\n    margin-right: 15px;\n    margin-bottom: 8px;\n    background-color: transparent;\n    background-image: none;\n    border: 1px solid transparent;\n    border-radius: 4px;\n  }\n  .navbar-toggle:focus {\n    outline: 0;\n  }\n  .navbar-toggle .icon-bar {\n    display: block;\n    width: 22px;\n    height: 2px;\n    border-radius: 1px;\n  }\n  .navbar-toggle .icon-bar + .icon-bar {\n    margin-top: 4px;\n  }\n  @media (min-width: 768px) {\n    .navbar-toggle {\n      display: none;\n    }\n  }\n  .navbar-nav {\n    margin: 7.5px -15px;\n  }\n  .navbar-nav > li > a {\n    padding-top: 10px;\n    padding-bottom: 10px;\n    line-height: 20px;\n  }\n  @media (max-width: 767px) {\n    .navbar-nav .open .dropdown-menu {\n      position: static;\n      float: none;\n      width: auto;\n      margin-top: 0;\n      background-color: transparent;\n      border: 0;\n      -webkit-box-shadow: none;\n              box-shadow: none;\n    }\n    .navbar-nav .open .dropdown-menu > li > a,\n    .navbar-nav .open .dropdown-menu .dropdown-header {\n      padding: 5px 15px 5px 25px;\n    }\n    .navbar-nav .open .dropdown-menu > li > a {\n      line-height: 20px;\n    }\n    .navbar-nav .open .dropdown-menu > li > a:hover,\n    .navbar-nav .open .dropdown-menu > li > a:focus {\n      background-image: none;\n    }\n  }\n  @media (min-width: 768px) {\n    .navbar-nav {\n      float: left;\n      margin: 0;\n    }\n    .navbar-nav > li {\n      float: left;\n    }\n    .navbar-nav > li > a {\n      padding-top: 15px;\n      padding-bottom: 15px;\n    }\n  }\n  .navbar-form {\n    padding: 10px 15px;\n    margin-top: 8px;\n    margin-right: -15px;\n    margin-bottom: 8px;\n    margin-left: -15px;\n    border-top: 1px solid transparent;\n    border-bottom: 1px solid transparent;\n    -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n            box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n  }\n  @media (min-width: 768px) {\n    .navbar-form .form-group {\n      display: inline-block;\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n    .navbar-form .form-control {\n      display: inline-block;\n      width: auto;\n      vertical-align: middle;\n    }\n    .navbar-form .form-control-static {\n      display: inline-block;\n    }\n    .navbar-form .input-group {\n      display: inline-table;\n      vertical-align: middle;\n    }\n    .navbar-form .input-group .input-group-addon,\n    .navbar-form .input-group .input-group-btn,\n    .navbar-form .input-group .form-control {\n      width: auto;\n    }\n    .navbar-form .input-group > .form-control {\n      width: 100%;\n    }\n    .navbar-form .control-label {\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n    .navbar-form .radio,\n    .navbar-form .checkbox {\n      display: inline-block;\n      margin-top: 0;\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n    .navbar-form .radio label,\n    .navbar-form .checkbox label {\n      padding-left: 0;\n    }\n    .navbar-form .radio input[type=\"radio\"],\n    .navbar-form .checkbox input[type=\"checkbox\"] {\n      position: relative;\n      margin-left: 0;\n    }\n    .navbar-form .has-feedback .form-control-feedback {\n      top: 0;\n    }\n  }\n  @media (max-width: 767px) {\n    .navbar-form .form-group {\n      margin-bottom: 5px;\n    }\n    .navbar-form .form-group:last-child {\n      margin-bottom: 0;\n    }\n  }\n  @media (min-width: 768px) {\n    .navbar-form {\n      width: auto;\n      padding-top: 0;\n      padding-bottom: 0;\n      margin-right: 0;\n      margin-left: 0;\n      border: 0;\n      -webkit-box-shadow: none;\n              box-shadow: none;\n    }\n  }\n  .navbar-nav > li > .dropdown-menu {\n    margin-top: 0;\n    border-top-left-radius: 0;\n    border-top-right-radius: 0;\n  }\n  .navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n    margin-bottom: 0;\n    border-top-left-radius: 4px;\n    border-top-right-radius: 4px;\n    border-bottom-right-radius: 0;\n    border-bottom-left-radius: 0;\n  }\n  .navbar-btn {\n    margin-top: 8px;\n    margin-bottom: 8px;\n  }\n  .navbar-btn.btn-sm {\n    margin-top: 10px;\n    margin-bottom: 10px;\n  }\n  .navbar-btn.btn-xs {\n    margin-top: 14px;\n    margin-bottom: 14px;\n  }\n  .navbar-text {\n    margin-top: 15px;\n    margin-bottom: 15px;\n  }\n  @media (min-width: 768px) {\n    .navbar-text {\n      float: left;\n      margin-right: 15px;\n      margin-left: 15px;\n    }\n  }\n  @media (min-width: 768px) {\n    .navbar-left {\n      float: left !important;\n    }\n    .navbar-right {\n      float: right !important;\n      margin-right: -15px;\n    }\n    .navbar-right ~ .navbar-right {\n      margin-right: 0;\n    }\n  }\n  .navbar-default {\n    background-color: #f8f8f8;\n    border-color: #e7e7e7;\n  }\n  .navbar-default .navbar-brand {\n    color: #777;\n  }\n  .navbar-default .navbar-brand:hover,\n  .navbar-default .navbar-brand:focus {\n    color: #5e5e5e;\n    background-color: transparent;\n  }\n  .navbar-default .navbar-text {\n    color: #777;\n  }\n  .navbar-default .navbar-nav > li > a {\n    color: #777;\n  }\n  .navbar-default .navbar-nav > li > a:hover,\n  .navbar-default .navbar-nav > li > a:focus {\n    color: #333;\n    background-color: transparent;\n  }\n  .navbar-default .navbar-nav > .active > a,\n  .navbar-default .navbar-nav > .active > a:hover,\n  .navbar-default .navbar-nav > .active > a:focus {\n    color: #555;\n    background-color: #e7e7e7;\n  }\n  .navbar-default .navbar-nav > .disabled > a,\n  .navbar-default .navbar-nav > .disabled > a:hover,\n  .navbar-default .navbar-nav > .disabled > a:focus {\n    color: #ccc;\n    background-color: transparent;\n  }\n  .navbar-default .navbar-toggle {\n    border-color: #ddd;\n  }\n  .navbar-default .navbar-toggle:hover,\n  .navbar-default .navbar-toggle:focus {\n    background-color: #ddd;\n  }\n  .navbar-default .navbar-toggle .icon-bar {\n    background-color: #888;\n  }\n  .navbar-default .navbar-collapse,\n  .navbar-default .navbar-form {\n    border-color: #e7e7e7;\n  }\n  .navbar-default .navbar-nav > .open > a,\n  .navbar-default .navbar-nav > .open > a:hover,\n  .navbar-default .navbar-nav > .open > a:focus {\n    color: #555;\n    background-color: #e7e7e7;\n  }\n  @media (max-width: 767px) {\n    .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n      color: #777;\n    }\n    .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n    .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n      color: #333;\n      background-color: transparent;\n    }\n    .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n    .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n    .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n      color: #555;\n      background-color: #e7e7e7;\n    }\n    .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n    .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n    .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n      color: #ccc;\n      background-color: transparent;\n    }\n  }\n  .navbar-default .navbar-link {\n    color: #777;\n  }\n  .navbar-default .navbar-link:hover {\n    color: #333;\n  }\n  .navbar-default .btn-link {\n    color: #777;\n  }\n  .navbar-default .btn-link:hover,\n  .navbar-default .btn-link:focus {\n    color: #333;\n  }\n  .navbar-default .btn-link[disabled]:hover,\n  fieldset[disabled] .navbar-default .btn-link:hover,\n  .navbar-default .btn-link[disabled]:focus,\n  fieldset[disabled] .navbar-default .btn-link:focus {\n    color: #ccc;\n  }\n  .navbar-inverse {\n    background-color: #222;\n    border-color: #080808;\n  }\n  .navbar-inverse .navbar-brand {\n    color: #9d9d9d;\n  }\n  .navbar-inverse .navbar-brand:hover,\n  .navbar-inverse .navbar-brand:focus {\n    color: #fff;\n    background-color: transparent;\n  }\n  .navbar-inverse .navbar-text {\n    color: #9d9d9d;\n  }\n  .navbar-inverse .navbar-nav > li > a {\n    color: #9d9d9d;\n  }\n  .navbar-inverse .navbar-nav > li > a:hover,\n  .navbar-inverse .navbar-nav > li > a:focus {\n    color: #fff;\n    background-color: transparent;\n  }\n  .navbar-inverse .navbar-nav > .active > a,\n  .navbar-inverse .navbar-nav > .active > a:hover,\n  .navbar-inverse .navbar-nav > .active > a:focus {\n    color: #fff;\n    background-color: #080808;\n  }\n  .navbar-inverse .navbar-nav > .disabled > a,\n  .navbar-inverse .navbar-nav > .disabled > a:hover,\n  .navbar-inverse .navbar-nav > .disabled > a:focus {\n    color: #444;\n    background-color: transparent;\n  }\n  .navbar-inverse .navbar-toggle {\n    border-color: #333;\n  }\n  .navbar-inverse .navbar-toggle:hover,\n  .navbar-inverse .navbar-toggle:focus {\n    background-color: #333;\n  }\n  .navbar-inverse .navbar-toggle .icon-bar {\n    background-color: #fff;\n  }\n  .navbar-inverse .navbar-collapse,\n  .navbar-inverse .navbar-form {\n    border-color: #101010;\n  }\n  .navbar-inverse .navbar-nav > .open > a,\n  .navbar-inverse .navbar-nav > .open > a:hover,\n  .navbar-inverse .navbar-nav > .open > a:focus {\n    color: #fff;\n    background-color: #080808;\n  }\n  @media (max-width: 767px) {\n    .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n      border-color: #080808;\n    }\n    .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n      background-color: #080808;\n    }\n    .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n      color: #9d9d9d;\n    }\n    .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n    .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n      color: #fff;\n      background-color: transparent;\n    }\n    .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n    .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n    .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n      color: #fff;\n      background-color: #080808;\n    }\n    .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n    .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n    .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n      color: #444;\n      background-color: transparent;\n    }\n  }\n  .navbar-inverse .navbar-link {\n    color: #9d9d9d;\n  }\n  .navbar-inverse .navbar-link:hover {\n    color: #fff;\n  }\n  .navbar-inverse .btn-link {\n    color: #9d9d9d;\n  }\n  .navbar-inverse .btn-link:hover,\n  .navbar-inverse .btn-link:focus {\n    color: #fff;\n  }\n  .navbar-inverse .btn-link[disabled]:hover,\n  fieldset[disabled] .navbar-inverse .btn-link:hover,\n  .navbar-inverse .btn-link[disabled]:focus,\n  fieldset[disabled] .navbar-inverse .btn-link:focus {\n    color: #444;\n  }\n  .breadcrumb {\n    padding: 8px 15px;\n    margin-bottom: 20px;\n    list-style: none;\n    background-color: #f5f5f5;\n    border-radius: 4px;\n  }\n  .breadcrumb > li {\n    display: inline-block;\n  }\n  .breadcrumb > li + li:before {\n    padding: 0 5px;\n    color: #ccc;\n    content: \"/\\00a0\";\n  }\n  .breadcrumb > .active {\n    color: #777;\n  }\n  .pagination {\n    display: inline-block;\n    padding-left: 0;\n    margin: 20px 0;\n    border-radius: 4px;\n  }\n  .pagination > li {\n    display: inline;\n  }\n  .pagination > li > a,\n  .pagination > li > span {\n    position: relative;\n    float: left;\n    padding: 6px 12px;\n    margin-left: -1px;\n    line-height: 1.42857143;\n    color: #337ab7;\n    text-decoration: none;\n    background-color: #fff;\n    border: 1px solid #ddd;\n  }\n  .pagination > li:first-child > a,\n  .pagination > li:first-child > span {\n    margin-left: 0;\n    border-top-left-radius: 4px;\n    border-bottom-left-radius: 4px;\n  }\n  .pagination > li:last-child > a,\n  .pagination > li:last-child > span {\n    border-top-right-radius: 4px;\n    border-bottom-right-radius: 4px;\n  }\n  .pagination > li > a:hover,\n  .pagination > li > span:hover,\n  .pagination > li > a:focus,\n  .pagination > li > span:focus {\n    z-index: 2;\n    color: #23527c;\n    background-color: #eee;\n    border-color: #ddd;\n  }\n  .pagination > .active > a,\n  .pagination > .active > span,\n  .pagination > .active > a:hover,\n  .pagination > .active > span:hover,\n  .pagination > .active > a:focus,\n  .pagination > .active > span:focus {\n    z-index: 3;\n    color: #fff;\n    cursor: default;\n    background-color: #337ab7;\n    border-color: #337ab7;\n  }\n  .pagination > .disabled > span,\n  .pagination > .disabled > span:hover,\n  .pagination > .disabled > span:focus,\n  .pagination > .disabled > a,\n  .pagination > .disabled > a:hover,\n  .pagination > .disabled > a:focus {\n    color: #777;\n    cursor: not-allowed;\n    background-color: #fff;\n    border-color: #ddd;\n  }\n  .pagination-lg > li > a,\n  .pagination-lg > li > span {\n    padding: 10px 16px;\n    font-size: 18px;\n    line-height: 1.3333333;\n  }\n  .pagination-lg > li:first-child > a,\n  .pagination-lg > li:first-child > span {\n    border-top-left-radius: 6px;\n    border-bottom-left-radius: 6px;\n  }\n  .pagination-lg > li:last-child > a,\n  .pagination-lg > li:last-child > span {\n    border-top-right-radius: 6px;\n    border-bottom-right-radius: 6px;\n  }\n  .pagination-sm > li > a,\n  .pagination-sm > li > span {\n    padding: 5px 10px;\n    font-size: 12px;\n    line-height: 1.5;\n  }\n  .pagination-sm > li:first-child > a,\n  .pagination-sm > li:first-child > span {\n    border-top-left-radius: 3px;\n    border-bottom-left-radius: 3px;\n  }\n  .pagination-sm > li:last-child > a,\n  .pagination-sm > li:last-child > span {\n    border-top-right-radius: 3px;\n    border-bottom-right-radius: 3px;\n  }\n  .pager {\n    padding-left: 0;\n    margin: 20px 0;\n    text-align: center;\n    list-style: none;\n  }\n  .pager li {\n    display: inline;\n  }\n  .pager li > a,\n  .pager li > span {\n    display: inline-block;\n    padding: 5px 14px;\n    background-color: #fff;\n    border: 1px solid #ddd;\n    border-radius: 15px;\n  }\n  .pager li > a:hover,\n  .pager li > a:focus {\n    text-decoration: none;\n    background-color: #eee;\n  }\n  .pager .next > a,\n  .pager .next > span {\n    float: right;\n  }\n  .pager .previous > a,\n  .pager .previous > span {\n    float: left;\n  }\n  .pager .disabled > a,\n  .pager .disabled > a:hover,\n  .pager .disabled > a:focus,\n  .pager .disabled > span {\n    color: #777;\n    cursor: not-allowed;\n    background-color: #fff;\n  }\n  .label {\n    display: inline;\n    padding: .2em .6em .3em;\n    font-size: 75%;\n    font-weight: bold;\n    line-height: 1;\n    color: #fff;\n    text-align: center;\n    white-space: nowrap;\n    vertical-align: baseline;\n    border-radius: .25em;\n  }\n  a.label:hover,\n  a.label:focus {\n    color: #fff;\n    text-decoration: none;\n    cursor: pointer;\n  }\n  .label:empty {\n    display: none;\n  }\n  .btn .label {\n    position: relative;\n    top: -1px;\n  }\n  .label-default {\n    background-color: #777;\n  }\n  .label-default[href]:hover,\n  .label-default[href]:focus {\n    background-color: #5e5e5e;\n  }\n  .label-primary {\n    background-color: #337ab7;\n  }\n  .label-primary[href]:hover,\n  .label-primary[href]:focus {\n    background-color: #286090;\n  }\n  .label-success {\n    background-color: #5cb85c;\n  }\n  .label-success[href]:hover,\n  .label-success[href]:focus {\n    background-color: #449d44;\n  }\n  .label-info {\n    background-color: #5bc0de;\n  }\n  .label-info[href]:hover,\n  .label-info[href]:focus {\n    background-color: #31b0d5;\n  }\n  .label-warning {\n    background-color: #f0ad4e;\n  }\n  .label-warning[href]:hover,\n  .label-warning[href]:focus {\n    background-color: #ec971f;\n  }\n  .label-danger {\n    background-color: #d9534f;\n  }\n  .label-danger[href]:hover,\n  .label-danger[href]:focus {\n    background-color: #c9302c;\n  }\n  .badge {\n    display: inline-block;\n    min-width: 10px;\n    padding: 3px 7px;\n    font-size: 12px;\n    font-weight: bold;\n    line-height: 1;\n    color: #fff;\n    text-align: center;\n    white-space: nowrap;\n    vertical-align: middle;\n    background-color: #777;\n    border-radius: 10px;\n  }\n  .badge:empty {\n    display: none;\n  }\n  .btn .badge {\n    position: relative;\n    top: -1px;\n  }\n  .btn-xs .badge,\n  .btn-group-xs > .btn .badge {\n    top: 0;\n    padding: 1px 5px;\n  }\n  a.badge:hover,\n  a.badge:focus {\n    color: #fff;\n    text-decoration: none;\n    cursor: pointer;\n  }\n  .list-group-item.active > .badge,\n  .nav-pills > .active > a > .badge {\n    color: #337ab7;\n    background-color: #fff;\n  }\n  .list-group-item > .badge {\n    float: right;\n  }\n  .list-group-item > .badge + .badge {\n    margin-right: 5px;\n  }\n  .nav-pills > li > a > .badge {\n    margin-left: 3px;\n  }\n  .jumbotron {\n    padding-top: 30px;\n    padding-bottom: 30px;\n    margin-bottom: 30px;\n    color: inherit;\n    background-color: #eee;\n  }\n  .jumbotron h1,\n  .jumbotron .h1 {\n    color: inherit;\n  }\n  .jumbotron p {\n    margin-bottom: 15px;\n    font-size: 21px;\n    font-weight: 200;\n  }\n  .jumbotron > hr {\n    border-top-color: #d5d5d5;\n  }\n  .container .jumbotron,\n  .container-fluid .jumbotron {\n    padding-right: 15px;\n    padding-left: 15px;\n    border-radius: 6px;\n  }\n  .jumbotron .container {\n    max-width: 100%;\n  }\n  @media screen and (min-width: 768px) {\n    .jumbotron {\n      padding-top: 48px;\n      padding-bottom: 48px;\n    }\n    .container .jumbotron,\n    .container-fluid .jumbotron {\n      padding-right: 60px;\n      padding-left: 60px;\n    }\n    .jumbotron h1,\n    .jumbotron .h1 {\n      font-size: 63px;\n    }\n  }\n  .thumbnail {\n    display: block;\n    padding: 4px;\n    margin-bottom: 20px;\n    line-height: 1.42857143;\n    background-color: #fff;\n    border: 1px solid #ddd;\n    border-radius: 4px;\n    -webkit-transition: border .2s ease-in-out;\n         -o-transition: border .2s ease-in-out;\n            transition: border .2s ease-in-out;\n  }\n  .thumbnail > img,\n  .thumbnail a > img {\n    margin-right: auto;\n    margin-left: auto;\n  }\n  a.thumbnail:hover,\n  a.thumbnail:focus,\n  a.thumbnail.active {\n    border-color: #337ab7;\n  }\n  .thumbnail .caption {\n    padding: 9px;\n    color: #333;\n  }\n  .alert {\n    padding: 15px;\n    margin-bottom: 20px;\n    border: 1px solid transparent;\n    border-radius: 4px;\n  }\n  .alert h4 {\n    margin-top: 0;\n    color: inherit;\n  }\n  .alert .alert-link {\n    font-weight: bold;\n  }\n  .alert > p,\n  .alert > ul {\n    margin-bottom: 0;\n  }\n  .alert > p + p {\n    margin-top: 5px;\n  }\n  .alert-dismissable,\n  .alert-dismissible {\n    padding-right: 35px;\n  }\n  .alert-dismissable .close,\n  .alert-dismissible .close {\n    position: relative;\n    top: -2px;\n    right: -21px;\n    color: inherit;\n  }\n  .alert-success {\n    color: #3c763d;\n    background-color: #dff0d8;\n    border-color: #d6e9c6;\n  }\n  .alert-success hr {\n    border-top-color: #c9e2b3;\n  }\n  .alert-success .alert-link {\n    color: #2b542c;\n  }\n  .alert-info {\n    color: #31708f;\n    background-color: #d9edf7;\n    border-color: #bce8f1;\n  }\n  .alert-info hr {\n    border-top-color: #a6e1ec;\n  }\n  .alert-info .alert-link {\n    color: #245269;\n  }\n  .alert-warning {\n    color: #8a6d3b;\n    background-color: #fcf8e3;\n    border-color: #faebcc;\n  }\n  .alert-warning hr {\n    border-top-color: #f7e1b5;\n  }\n  .alert-warning .alert-link {\n    color: #66512c;\n  }\n  .alert-danger {\n    color: #a94442;\n    background-color: #f2dede;\n    border-color: #ebccd1;\n  }\n  .alert-danger hr {\n    border-top-color: #e4b9c0;\n  }\n  .alert-danger .alert-link {\n    color: #843534;\n  }\n  @-webkit-keyframes progress-bar-stripes {\n    from {\n      background-position: 40px 0;\n    }\n    to {\n      background-position: 0 0;\n    }\n  }\n  @-o-keyframes progress-bar-stripes {\n    from {\n      background-position: 40px 0;\n    }\n    to {\n      background-position: 0 0;\n    }\n  }\n  @keyframes progress-bar-stripes {\n    from {\n      background-position: 40px 0;\n    }\n    to {\n      background-position: 0 0;\n    }\n  }\n  .progress {\n    height: 20px;\n    margin-bottom: 20px;\n    overflow: hidden;\n    background-color: #f5f5f5;\n    border-radius: 4px;\n    -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);\n            box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);\n  }\n  .progress-bar {\n    float: left;\n    width: 0;\n    height: 100%;\n    font-size: 12px;\n    line-height: 20px;\n    color: #fff;\n    text-align: center;\n    background-color: #337ab7;\n    -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);\n            box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);\n    -webkit-transition: width .6s ease;\n         -o-transition: width .6s ease;\n            transition: width .6s ease;\n  }\n  .progress-striped .progress-bar,\n  .progress-bar-striped {\n    background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n    background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n    background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n    -webkit-background-size: 40px 40px;\n            background-size: 40px 40px;\n  }\n  .progress.active .progress-bar,\n  .progress-bar.active {\n    -webkit-animation: progress-bar-stripes 2s linear infinite;\n         -o-animation: progress-bar-stripes 2s linear infinite;\n            animation: progress-bar-stripes 2s linear infinite;\n  }\n  .progress-bar-success {\n    background-color: #5cb85c;\n  }\n  .progress-striped .progress-bar-success {\n    background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n    background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n    background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  }\n  .progress-bar-info {\n    background-color: #5bc0de;\n  }\n  .progress-striped .progress-bar-info {\n    background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n    background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n    background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  }\n  .progress-bar-warning {\n    background-color: #f0ad4e;\n  }\n  .progress-striped .progress-bar-warning {\n    background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n    background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n    background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  }\n  .progress-bar-danger {\n    background-color: #d9534f;\n  }\n  .progress-striped .progress-bar-danger {\n    background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n    background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n    background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  }\n  .media {\n    margin-top: 15px;\n  }\n  .media:first-child {\n    margin-top: 0;\n  }\n  .media,\n  .media-body {\n    overflow: hidden;\n    zoom: 1;\n  }\n  .media-body {\n    width: 10000px;\n  }\n  .media-object {\n    display: block;\n  }\n  .media-object.img-thumbnail {\n    max-width: none;\n  }\n  .media-right,\n  .media > .pull-right {\n    padding-left: 10px;\n  }\n  .media-left,\n  .media > .pull-left {\n    padding-right: 10px;\n  }\n  .media-left,\n  .media-right,\n  .media-body {\n    display: table-cell;\n    vertical-align: top;\n  }\n  .media-middle {\n    vertical-align: middle;\n  }\n  .media-bottom {\n    vertical-align: bottom;\n  }\n  .media-heading {\n    margin-top: 0;\n    margin-bottom: 5px;\n  }\n  .media-list {\n    padding-left: 0;\n    list-style: none;\n  }\n  .list-group {\n    padding-left: 0;\n    margin-bottom: 20px;\n  }\n  .list-group-item {\n    position: relative;\n    display: block;\n    padding: 10px 15px;\n    margin-bottom: -1px;\n    background-color: #fff;\n    border: 1px solid #ddd;\n  }\n  .list-group-item:first-child {\n    border-top-left-radius: 4px;\n    border-top-right-radius: 4px;\n  }\n  .list-group-item:last-child {\n    margin-bottom: 0;\n    border-bottom-right-radius: 4px;\n    border-bottom-left-radius: 4px;\n  }\n  a.list-group-item,\n  button.list-group-item {\n    color: #555;\n  }\n  a.list-group-item .list-group-item-heading,\n  button.list-group-item .list-group-item-heading {\n    color: #333;\n  }\n  a.list-group-item:hover,\n  button.list-group-item:hover,\n  a.list-group-item:focus,\n  button.list-group-item:focus {\n    color: #555;\n    text-decoration: none;\n    background-color: #f5f5f5;\n  }\n  button.list-group-item {\n    width: 100%;\n    text-align: left;\n  }\n  .list-group-item.disabled,\n  .list-group-item.disabled:hover,\n  .list-group-item.disabled:focus {\n    color: #777;\n    cursor: not-allowed;\n    background-color: #eee;\n  }\n  .list-group-item.disabled .list-group-item-heading,\n  .list-group-item.disabled:hover .list-group-item-heading,\n  .list-group-item.disabled:focus .list-group-item-heading {\n    color: inherit;\n  }\n  .list-group-item.disabled .list-group-item-text,\n  .list-group-item.disabled:hover .list-group-item-text,\n  .list-group-item.disabled:focus .list-group-item-text {\n    color: #777;\n  }\n  .list-group-item.active,\n  .list-group-item.active:hover,\n  .list-group-item.active:focus {\n    z-index: 2;\n    color: #fff;\n    background-color: #337ab7;\n    border-color: #337ab7;\n  }\n  .list-group-item.active .list-group-item-heading,\n  .list-group-item.active:hover .list-group-item-heading,\n  .list-group-item.active:focus .list-group-item-heading,\n  .list-group-item.active .list-group-item-heading > small,\n  .list-group-item.active:hover .list-group-item-heading > small,\n  .list-group-item.active:focus .list-group-item-heading > small,\n  .list-group-item.active .list-group-item-heading > .small,\n  .list-group-item.active:hover .list-group-item-heading > .small,\n  .list-group-item.active:focus .list-group-item-heading > .small {\n    color: inherit;\n  }\n  .list-group-item.active .list-group-item-text,\n  .list-group-item.active:hover .list-group-item-text,\n  .list-group-item.active:focus .list-group-item-text {\n    color: #c7ddef;\n  }\n  .list-group-item-success {\n    color: #3c763d;\n    background-color: #dff0d8;\n  }\n  a.list-group-item-success,\n  button.list-group-item-success {\n    color: #3c763d;\n  }\n  a.list-group-item-success .list-group-item-heading,\n  button.list-group-item-success .list-group-item-heading {\n    color: inherit;\n  }\n  a.list-group-item-success:hover,\n  button.list-group-item-success:hover,\n  a.list-group-item-success:focus,\n  button.list-group-item-success:focus {\n    color: #3c763d;\n    background-color: #d0e9c6;\n  }\n  a.list-group-item-success.active,\n  button.list-group-item-success.active,\n  a.list-group-item-success.active:hover,\n  button.list-group-item-success.active:hover,\n  a.list-group-item-success.active:focus,\n  button.list-group-item-success.active:focus {\n    color: #fff;\n    background-color: #3c763d;\n    border-color: #3c763d;\n  }\n  .list-group-item-info {\n    color: #31708f;\n    background-color: #d9edf7;\n  }\n  a.list-group-item-info,\n  button.list-group-item-info {\n    color: #31708f;\n  }\n  a.list-group-item-info .list-group-item-heading,\n  button.list-group-item-info .list-group-item-heading {\n    color: inherit;\n  }\n  a.list-group-item-info:hover,\n  button.list-group-item-info:hover,\n  a.list-group-item-info:focus,\n  button.list-group-item-info:focus {\n    color: #31708f;\n    background-color: #c4e3f3;\n  }\n  a.list-group-item-info.active,\n  button.list-group-item-info.active,\n  a.list-group-item-info.active:hover,\n  button.list-group-item-info.active:hover,\n  a.list-group-item-info.active:focus,\n  button.list-group-item-info.active:focus {\n    color: #fff;\n    background-color: #31708f;\n    border-color: #31708f;\n  }\n  .list-group-item-warning {\n    color: #8a6d3b;\n    background-color: #fcf8e3;\n  }\n  a.list-group-item-warning,\n  button.list-group-item-warning {\n    color: #8a6d3b;\n  }\n  a.list-group-item-warning .list-group-item-heading,\n  button.list-group-item-warning .list-group-item-heading {\n    color: inherit;\n  }\n  a.list-group-item-warning:hover,\n  button.list-group-item-warning:hover,\n  a.list-group-item-warning:focus,\n  button.list-group-item-warning:focus {\n    color: #8a6d3b;\n    background-color: #faf2cc;\n  }\n  a.list-group-item-warning.active,\n  button.list-group-item-warning.active,\n  a.list-group-item-warning.active:hover,\n  button.list-group-item-warning.active:hover,\n  a.list-group-item-warning.active:focus,\n  button.list-group-item-warning.active:focus {\n    color: #fff;\n    background-color: #8a6d3b;\n    border-color: #8a6d3b;\n  }\n  .list-group-item-danger {\n    color: #a94442;\n    background-color: #f2dede;\n  }\n  a.list-group-item-danger,\n  button.list-group-item-danger {\n    color: #a94442;\n  }\n  a.list-group-item-danger .list-group-item-heading,\n  button.list-group-item-danger .list-group-item-heading {\n    color: inherit;\n  }\n  a.list-group-item-danger:hover,\n  button.list-group-item-danger:hover,\n  a.list-group-item-danger:focus,\n  button.list-group-item-danger:focus {\n    color: #a94442;\n    background-color: #ebcccc;\n  }\n  a.list-group-item-danger.active,\n  button.list-group-item-danger.active,\n  a.list-group-item-danger.active:hover,\n  button.list-group-item-danger.active:hover,\n  a.list-group-item-danger.active:focus,\n  button.list-group-item-danger.active:focus {\n    color: #fff;\n    background-color: #a94442;\n    border-color: #a94442;\n  }\n  .list-group-item-heading {\n    margin-top: 0;\n    margin-bottom: 5px;\n  }\n  .list-group-item-text {\n    margin-bottom: 0;\n    line-height: 1.3;\n  }\n  .panel {\n    margin-bottom: 20px;\n    background-color: #fff;\n    border: 1px solid transparent;\n    border-radius: 4px;\n    -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\n            box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\n  }\n  .panel-body {\n    padding: 15px;\n  }\n  .panel-heading {\n    padding: 10px 15px;\n    border-bottom: 1px solid transparent;\n    border-top-left-radius: 3px;\n    border-top-right-radius: 3px;\n  }\n  .panel-heading > .dropdown .dropdown-toggle {\n    color: inherit;\n  }\n  .panel-title {\n    margin-top: 0;\n    margin-bottom: 0;\n    font-size: 16px;\n    color: inherit;\n  }\n  .panel-title > a,\n  .panel-title > small,\n  .panel-title > .small,\n  .panel-title > small > a,\n  .panel-title > .small > a {\n    color: inherit;\n  }\n  .panel-footer {\n    padding: 10px 15px;\n    background-color: #f5f5f5;\n    border-top: 1px solid #ddd;\n    border-bottom-right-radius: 3px;\n    border-bottom-left-radius: 3px;\n  }\n  .panel > .list-group,\n  .panel > .panel-collapse > .list-group {\n    margin-bottom: 0;\n  }\n  .panel > .list-group .list-group-item,\n  .panel > .panel-collapse > .list-group .list-group-item {\n    border-width: 1px 0;\n    border-radius: 0;\n  }\n  .panel > .list-group:first-child .list-group-item:first-child,\n  .panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n    border-top: 0;\n    border-top-left-radius: 3px;\n    border-top-right-radius: 3px;\n  }\n  .panel > .list-group:last-child .list-group-item:last-child,\n  .panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n    border-bottom: 0;\n    border-bottom-right-radius: 3px;\n    border-bottom-left-radius: 3px;\n  }\n  .panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n    border-top-left-radius: 0;\n    border-top-right-radius: 0;\n  }\n  .panel-heading + .list-group .list-group-item:first-child {\n    border-top-width: 0;\n  }\n  .list-group + .panel-footer {\n    border-top-width: 0;\n  }\n  .panel > .table,\n  .panel > .table-responsive > .table,\n  .panel > .panel-collapse > .table {\n    margin-bottom: 0;\n  }\n  .panel > .table caption,\n  .panel > .table-responsive > .table caption,\n  .panel > .panel-collapse > .table caption {\n    padding-right: 15px;\n    padding-left: 15px;\n  }\n  .panel > .table:first-child,\n  .panel > .table-responsive:first-child > .table:first-child {\n    border-top-left-radius: 3px;\n    border-top-right-radius: 3px;\n  }\n  .panel > .table:first-child > thead:first-child > tr:first-child,\n  .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n  .panel > .table:first-child > tbody:first-child > tr:first-child,\n  .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n    border-top-left-radius: 3px;\n    border-top-right-radius: 3px;\n  }\n  .panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n  .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n  .panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n  .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n  .panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n  .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n  .panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n  .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n    border-top-left-radius: 3px;\n  }\n  .panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n  .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n  .panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n  .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n  .panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n  .panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n  .panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n  .panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n    border-top-right-radius: 3px;\n  }\n  .panel > .table:last-child,\n  .panel > .table-responsive:last-child > .table:last-child {\n    border-bottom-right-radius: 3px;\n    border-bottom-left-radius: 3px;\n  }\n  .panel > .table:last-child > tbody:last-child > tr:last-child,\n  .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n  .panel > .table:last-child > tfoot:last-child > tr:last-child,\n  .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n    border-bottom-right-radius: 3px;\n    border-bottom-left-radius: 3px;\n  }\n  .panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n  .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n  .panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n  .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n  .panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n  .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n  .panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n  .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n    border-bottom-left-radius: 3px;\n  }\n  .panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n  .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n  .panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n  .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n  .panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n  .panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n  .panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n  .panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n    border-bottom-right-radius: 3px;\n  }\n  .panel > .panel-body + .table,\n  .panel > .panel-body + .table-responsive,\n  .panel > .table + .panel-body,\n  .panel > .table-responsive + .panel-body {\n    border-top: 1px solid #ddd;\n  }\n  .panel > .table > tbody:first-child > tr:first-child th,\n  .panel > .table > tbody:first-child > tr:first-child td {\n    border-top: 0;\n  }\n  .panel > .table-bordered,\n  .panel > .table-responsive > .table-bordered {\n    border: 0;\n  }\n  .panel > .table-bordered > thead > tr > th:first-child,\n  .panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n  .panel > .table-bordered > tbody > tr > th:first-child,\n  .panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n  .panel > .table-bordered > tfoot > tr > th:first-child,\n  .panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n  .panel > .table-bordered > thead > tr > td:first-child,\n  .panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n  .panel > .table-bordered > tbody > tr > td:first-child,\n  .panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n  .panel > .table-bordered > tfoot > tr > td:first-child,\n  .panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n    border-left: 0;\n  }\n  .panel > .table-bordered > thead > tr > th:last-child,\n  .panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n  .panel > .table-bordered > tbody > tr > th:last-child,\n  .panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n  .panel > .table-bordered > tfoot > tr > th:last-child,\n  .panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n  .panel > .table-bordered > thead > tr > td:last-child,\n  .panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n  .panel > .table-bordered > tbody > tr > td:last-child,\n  .panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n  .panel > .table-bordered > tfoot > tr > td:last-child,\n  .panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n    border-right: 0;\n  }\n  .panel > .table-bordered > thead > tr:first-child > td,\n  .panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n  .panel > .table-bordered > tbody > tr:first-child > td,\n  .panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n  .panel > .table-bordered > thead > tr:first-child > th,\n  .panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n  .panel > .table-bordered > tbody > tr:first-child > th,\n  .panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n    border-bottom: 0;\n  }\n  .panel > .table-bordered > tbody > tr:last-child > td,\n  .panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n  .panel > .table-bordered > tfoot > tr:last-child > td,\n  .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n  .panel > .table-bordered > tbody > tr:last-child > th,\n  .panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n  .panel > .table-bordered > tfoot > tr:last-child > th,\n  .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n    border-bottom: 0;\n  }\n  .panel > .table-responsive {\n    margin-bottom: 0;\n    border: 0;\n  }\n  .panel-group {\n    margin-bottom: 20px;\n  }\n  .panel-group .panel {\n    margin-bottom: 0;\n    border-radius: 4px;\n  }\n  .panel-group .panel + .panel {\n    margin-top: 5px;\n  }\n  .panel-group .panel-heading {\n    border-bottom: 0;\n  }\n  .panel-group .panel-heading + .panel-collapse > .panel-body,\n  .panel-group .panel-heading + .panel-collapse > .list-group {\n    border-top: 1px solid #ddd;\n  }\n  .panel-group .panel-footer {\n    border-top: 0;\n  }\n  .panel-group .panel-footer + .panel-collapse .panel-body {\n    border-bottom: 1px solid #ddd;\n  }\n  .panel-default {\n    border-color: #ddd;\n  }\n  .panel-default > .panel-heading {\n    color: #333;\n    background-color: #f5f5f5;\n    border-color: #ddd;\n  }\n  .panel-default > .panel-heading + .panel-collapse > .panel-body {\n    border-top-color: #ddd;\n  }\n  .panel-default > .panel-heading .badge {\n    color: #f5f5f5;\n    background-color: #333;\n  }\n  .panel-default > .panel-footer + .panel-collapse > .panel-body {\n    border-bottom-color: #ddd;\n  }\n  .panel-primary {\n    border-color: #337ab7;\n  }\n  .panel-primary > .panel-heading {\n    color: #fff;\n    background-color: #337ab7;\n    border-color: #337ab7;\n  }\n  .panel-primary > .panel-heading + .panel-collapse > .panel-body {\n    border-top-color: #337ab7;\n  }\n  .panel-primary > .panel-heading .badge {\n    color: #337ab7;\n    background-color: #fff;\n  }\n  .panel-primary > .panel-footer + .panel-collapse > .panel-body {\n    border-bottom-color: #337ab7;\n  }\n  .panel-success {\n    border-color: #d6e9c6;\n  }\n  .panel-success > .panel-heading {\n    color: #3c763d;\n    background-color: #dff0d8;\n    border-color: #d6e9c6;\n  }\n  .panel-success > .panel-heading + .panel-collapse > .panel-body {\n    border-top-color: #d6e9c6;\n  }\n  .panel-success > .panel-heading .badge {\n    color: #dff0d8;\n    background-color: #3c763d;\n  }\n  .panel-success > .panel-footer + .panel-collapse > .panel-body {\n    border-bottom-color: #d6e9c6;\n  }\n  .panel-info {\n    border-color: #bce8f1;\n  }\n  .panel-info > .panel-heading {\n    color: #31708f;\n    background-color: #d9edf7;\n    border-color: #bce8f1;\n  }\n  .panel-info > .panel-heading + .panel-collapse > .panel-body {\n    border-top-color: #bce8f1;\n  }\n  .panel-info > .panel-heading .badge {\n    color: #d9edf7;\n    background-color: #31708f;\n  }\n  .panel-info > .panel-footer + .panel-collapse > .panel-body {\n    border-bottom-color: #bce8f1;\n  }\n  .panel-warning {\n    border-color: #faebcc;\n  }\n  .panel-warning > .panel-heading {\n    color: #8a6d3b;\n    background-color: #fcf8e3;\n    border-color: #faebcc;\n  }\n  .panel-warning > .panel-heading + .panel-collapse > .panel-body {\n    border-top-color: #faebcc;\n  }\n  .panel-warning > .panel-heading .badge {\n    color: #fcf8e3;\n    background-color: #8a6d3b;\n  }\n  .panel-warning > .panel-footer + .panel-collapse > .panel-body {\n    border-bottom-color: #faebcc;\n  }\n  .panel-danger {\n    border-color: #ebccd1;\n  }\n  .panel-danger > .panel-heading {\n    color: #a94442;\n    background-color: #f2dede;\n    border-color: #ebccd1;\n  }\n  .panel-danger > .panel-heading + .panel-collapse > .panel-body {\n    border-top-color: #ebccd1;\n  }\n  .panel-danger > .panel-heading .badge {\n    color: #f2dede;\n    background-color: #a94442;\n  }\n  .panel-danger > .panel-footer + .panel-collapse > .panel-body {\n    border-bottom-color: #ebccd1;\n  }\n  .embed-responsive {\n    position: relative;\n    display: block;\n    height: 0;\n    padding: 0;\n    overflow: hidden;\n  }\n  .embed-responsive .embed-responsive-item,\n  .embed-responsive iframe,\n  .embed-responsive embed,\n  .embed-responsive object,\n  .embed-responsive video {\n    position: absolute;\n    top: 0;\n    bottom: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    border: 0;\n  }\n  .embed-responsive-16by9 {\n    padding-bottom: 56.25%;\n  }\n  .embed-responsive-4by3 {\n    padding-bottom: 75%;\n  }\n  .well {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    border-radius: 4px;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);\n            box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);\n  }\n  .well blockquote {\n    border-color: #ddd;\n    border-color: rgba(0, 0, 0, .15);\n  }\n  .well-lg {\n    padding: 24px;\n    border-radius: 6px;\n  }\n  .well-sm {\n    padding: 9px;\n    border-radius: 3px;\n  }\n  .close {\n    float: right;\n    font-size: 21px;\n    font-weight: bold;\n    line-height: 1;\n    color: #000;\n    text-shadow: 0 1px 0 #fff;\n    filter: alpha(opacity=20);\n    opacity: .2;\n  }\n  .close:hover,\n  .close:focus {\n    color: #000;\n    text-decoration: none;\n    cursor: pointer;\n    filter: alpha(opacity=50);\n    opacity: .5;\n  }\n  button.close {\n    -webkit-appearance: none;\n    padding: 0;\n    cursor: pointer;\n    background: transparent;\n    border: 0;\n  }\n  .modal-open {\n    overflow: hidden;\n  }\n  .modal {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    z-index: 1050;\n    display: none;\n    overflow: hidden;\n    -webkit-overflow-scrolling: touch;\n    outline: 0;\n  }\n  .modal.fade .modal-dialog {\n    -webkit-transition: -webkit-transform .3s ease-out;\n         -o-transition:      -o-transform .3s ease-out;\n            transition:         transform .3s ease-out;\n    -webkit-transform: translate(0, -25%);\n        -ms-transform: translate(0, -25%);\n         -o-transform: translate(0, -25%);\n            transform: translate(0, -25%);\n  }\n  .modal.in .modal-dialog {\n    -webkit-transform: translate(0, 0);\n        -ms-transform: translate(0, 0);\n         -o-transform: translate(0, 0);\n            transform: translate(0, 0);\n  }\n  .modal-open .modal {\n    overflow-x: hidden;\n    overflow-y: auto;\n  }\n  .modal-dialog {\n    position: relative;\n    width: auto;\n    margin: 10px;\n  }\n  .modal-content {\n    position: relative;\n    background-color: #fff;\n    -webkit-background-clip: padding-box;\n            background-clip: padding-box;\n    border: 1px solid #999;\n    border: 1px solid rgba(0, 0, 0, .2);\n    border-radius: 6px;\n    outline: 0;\n    -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);\n            box-shadow: 0 3px 9px rgba(0, 0, 0, .5);\n  }\n  .modal-backdrop {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    z-index: 1040;\n    background-color: #000;\n  }\n  .modal-backdrop.fade {\n    filter: alpha(opacity=0);\n    opacity: 0;\n  }\n  .modal-backdrop.in {\n    filter: alpha(opacity=50);\n    opacity: .5;\n  }\n  .modal-header {\n    padding: 15px;\n    border-bottom: 1px solid #e5e5e5;\n  }\n  .modal-header .close {\n    margin-top: -2px;\n  }\n  .modal-title {\n    margin: 0;\n    line-height: 1.42857143;\n  }\n  .modal-body {\n    position: relative;\n    padding: 15px;\n  }\n  .modal-footer {\n    padding: 15px;\n    text-align: right;\n    border-top: 1px solid #e5e5e5;\n  }\n  .modal-footer .btn + .btn {\n    margin-bottom: 0;\n    margin-left: 5px;\n  }\n  .modal-footer .btn-group .btn + .btn {\n    margin-left: -1px;\n  }\n  .modal-footer .btn-block + .btn-block {\n    margin-left: 0;\n  }\n  .modal-scrollbar-measure {\n    position: absolute;\n    top: -9999px;\n    width: 50px;\n    height: 50px;\n    overflow: scroll;\n  }\n  @media (min-width: 768px) {\n    .modal-dialog {\n      width: 600px;\n      margin: 30px auto;\n    }\n    .modal-content {\n      -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);\n              box-shadow: 0 5px 15px rgba(0, 0, 0, .5);\n    }\n    .modal-sm {\n      width: 300px;\n    }\n  }\n  @media (min-width: 992px) {\n    .modal-lg {\n      width: 900px;\n    }\n  }\n  .tooltip {\n    position: absolute;\n    z-index: 1070;\n    display: block;\n    font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n    font-size: 12px;\n    font-style: normal;\n    font-weight: normal;\n    line-height: 1.42857143;\n    text-align: left;\n    text-align: start;\n    text-decoration: none;\n    text-shadow: none;\n    text-transform: none;\n    letter-spacing: normal;\n    word-break: normal;\n    word-spacing: normal;\n    word-wrap: normal;\n    white-space: normal;\n    filter: alpha(opacity=0);\n    opacity: 0;\n  \n    line-break: auto;\n  }\n  .tooltip.in {\n    filter: alpha(opacity=90);\n    opacity: .9;\n  }\n  .tooltip.top {\n    padding: 5px 0;\n    margin-top: -3px;\n  }\n  .tooltip.right {\n    padding: 0 5px;\n    margin-left: 3px;\n  }\n  .tooltip.bottom {\n    padding: 5px 0;\n    margin-top: 3px;\n  }\n  .tooltip.left {\n    padding: 0 5px;\n    margin-left: -3px;\n  }\n  .tooltip-inner {\n    max-width: 200px;\n    padding: 3px 8px;\n    color: #fff;\n    text-align: center;\n    background-color: #000;\n    border-radius: 4px;\n  }\n  .tooltip-arrow {\n    position: absolute;\n    width: 0;\n    height: 0;\n    border-color: transparent;\n    border-style: solid;\n  }\n  .tooltip.top .tooltip-arrow {\n    bottom: 0;\n    left: 50%;\n    margin-left: -5px;\n    border-width: 5px 5px 0;\n    border-top-color: #000;\n  }\n  .tooltip.top-left .tooltip-arrow {\n    right: 5px;\n    bottom: 0;\n    margin-bottom: -5px;\n    border-width: 5px 5px 0;\n    border-top-color: #000;\n  }\n  .tooltip.top-right .tooltip-arrow {\n    bottom: 0;\n    left: 5px;\n    margin-bottom: -5px;\n    border-width: 5px 5px 0;\n    border-top-color: #000;\n  }\n  .tooltip.right .tooltip-arrow {\n    top: 50%;\n    left: 0;\n    margin-top: -5px;\n    border-width: 5px 5px 5px 0;\n    border-right-color: #000;\n  }\n  .tooltip.left .tooltip-arrow {\n    top: 50%;\n    right: 0;\n    margin-top: -5px;\n    border-width: 5px 0 5px 5px;\n    border-left-color: #000;\n  }\n  .tooltip.bottom .tooltip-arrow {\n    top: 0;\n    left: 50%;\n    margin-left: -5px;\n    border-width: 0 5px 5px;\n    border-bottom-color: #000;\n  }\n  .tooltip.bottom-left .tooltip-arrow {\n    top: 0;\n    right: 5px;\n    margin-top: -5px;\n    border-width: 0 5px 5px;\n    border-bottom-color: #000;\n  }\n  .tooltip.bottom-right .tooltip-arrow {\n    top: 0;\n    left: 5px;\n    margin-top: -5px;\n    border-width: 0 5px 5px;\n    border-bottom-color: #000;\n  }\n  .popover {\n    position: absolute;\n    top: 0;\n    left: 0;\n    z-index: 1060;\n    display: none;\n    max-width: 276px;\n    padding: 1px;\n    font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n    font-size: 14px;\n    font-style: normal;\n    font-weight: normal;\n    line-height: 1.42857143;\n    text-align: left;\n    text-align: start;\n    text-decoration: none;\n    text-shadow: none;\n    text-transform: none;\n    letter-spacing: normal;\n    word-break: normal;\n    word-spacing: normal;\n    word-wrap: normal;\n    white-space: normal;\n    background-color: #fff;\n    -webkit-background-clip: padding-box;\n            background-clip: padding-box;\n    border: 1px solid #ccc;\n    border: 1px solid rgba(0, 0, 0, .2);\n    border-radius: 6px;\n    -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);\n            box-shadow: 0 5px 10px rgba(0, 0, 0, .2);\n  \n    line-break: auto;\n  }\n  .popover.top {\n    margin-top: -10px;\n  }\n  .popover.right {\n    margin-left: 10px;\n  }\n  .popover.bottom {\n    margin-top: 10px;\n  }\n  .popover.left {\n    margin-left: -10px;\n  }\n  .popover-title {\n    padding: 8px 14px;\n    margin: 0;\n    font-size: 14px;\n    background-color: #f7f7f7;\n    border-bottom: 1px solid #ebebeb;\n    border-radius: 5px 5px 0 0;\n  }\n  .popover-content {\n    padding: 9px 14px;\n  }\n  .popover > .arrow,\n  .popover > .arrow:after {\n    position: absolute;\n    display: block;\n    width: 0;\n    height: 0;\n    border-color: transparent;\n    border-style: solid;\n  }\n  .popover > .arrow {\n    border-width: 11px;\n  }\n  .popover > .arrow:after {\n    content: \"\";\n    border-width: 10px;\n  }\n  .popover.top > .arrow {\n    bottom: -11px;\n    left: 50%;\n    margin-left: -11px;\n    border-top-color: #999;\n    border-top-color: rgba(0, 0, 0, .25);\n    border-bottom-width: 0;\n  }\n  .popover.top > .arrow:after {\n    bottom: 1px;\n    margin-left: -10px;\n    content: \" \";\n    border-top-color: #fff;\n    border-bottom-width: 0;\n  }\n  .popover.right > .arrow {\n    top: 50%;\n    left: -11px;\n    margin-top: -11px;\n    border-right-color: #999;\n    border-right-color: rgba(0, 0, 0, .25);\n    border-left-width: 0;\n  }\n  .popover.right > .arrow:after {\n    bottom: -10px;\n    left: 1px;\n    content: \" \";\n    border-right-color: #fff;\n    border-left-width: 0;\n  }\n  .popover.bottom > .arrow {\n    top: -11px;\n    left: 50%;\n    margin-left: -11px;\n    border-top-width: 0;\n    border-bottom-color: #999;\n    border-bottom-color: rgba(0, 0, 0, .25);\n  }\n  .popover.bottom > .arrow:after {\n    top: 1px;\n    margin-left: -10px;\n    content: \" \";\n    border-top-width: 0;\n    border-bottom-color: #fff;\n  }\n  .popover.left > .arrow {\n    top: 50%;\n    right: -11px;\n    margin-top: -11px;\n    border-right-width: 0;\n    border-left-color: #999;\n    border-left-color: rgba(0, 0, 0, .25);\n  }\n  .popover.left > .arrow:after {\n    right: 1px;\n    bottom: -10px;\n    content: \" \";\n    border-right-width: 0;\n    border-left-color: #fff;\n  }\n  .carousel {\n    position: relative;\n  }\n  .carousel-inner {\n    position: relative;\n    width: 100%;\n    overflow: hidden;\n  }\n  .carousel-inner > .item {\n    position: relative;\n    display: none;\n    -webkit-transition: .6s ease-in-out left;\n         -o-transition: .6s ease-in-out left;\n            transition: .6s ease-in-out left;\n  }\n  .carousel-inner > .item > img,\n  .carousel-inner > .item > a > img {\n    line-height: 1;\n  }\n  @media all and (transform-3d), (-webkit-transform-3d) {\n    .carousel-inner > .item {\n      -webkit-transition: -webkit-transform .6s ease-in-out;\n           -o-transition:      -o-transform .6s ease-in-out;\n              transition:         transform .6s ease-in-out;\n  \n      -webkit-backface-visibility: hidden;\n              backface-visibility: hidden;\n      -webkit-perspective: 1000px;\n              perspective: 1000px;\n    }\n    .carousel-inner > .item.next,\n    .carousel-inner > .item.active.right {\n      left: 0;\n      -webkit-transform: translate3d(100%, 0, 0);\n              transform: translate3d(100%, 0, 0);\n    }\n    .carousel-inner > .item.prev,\n    .carousel-inner > .item.active.left {\n      left: 0;\n      -webkit-transform: translate3d(-100%, 0, 0);\n              transform: translate3d(-100%, 0, 0);\n    }\n    .carousel-inner > .item.next.left,\n    .carousel-inner > .item.prev.right,\n    .carousel-inner > .item.active {\n      left: 0;\n      -webkit-transform: translate3d(0, 0, 0);\n              transform: translate3d(0, 0, 0);\n    }\n  }\n  .carousel-inner > .active,\n  .carousel-inner > .next,\n  .carousel-inner > .prev {\n    display: block;\n  }\n  .carousel-inner > .active {\n    left: 0;\n  }\n  .carousel-inner > .next,\n  .carousel-inner > .prev {\n    position: absolute;\n    top: 0;\n    width: 100%;\n  }\n  .carousel-inner > .next {\n    left: 100%;\n  }\n  .carousel-inner > .prev {\n    left: -100%;\n  }\n  .carousel-inner > .next.left,\n  .carousel-inner > .prev.right {\n    left: 0;\n  }\n  .carousel-inner > .active.left {\n    left: -100%;\n  }\n  .carousel-inner > .active.right {\n    left: 100%;\n  }\n  .carousel-control {\n    position: absolute;\n    top: 0;\n    bottom: 0;\n    left: 0;\n    width: 15%;\n    font-size: 20px;\n    color: #fff;\n    text-align: center;\n    text-shadow: 0 1px 2px rgba(0, 0, 0, .6);\n    background-color: rgba(0, 0, 0, 0);\n    filter: alpha(opacity=50);\n    opacity: .5;\n  }\n  .carousel-control.left {\n    background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n    background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n    background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));\n    background-image:         linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n    background-repeat: repeat-x;\n  }\n  .carousel-control.right {\n    right: 0;\n    left: auto;\n    background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n    background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n    background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));\n    background-image:         linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n    background-repeat: repeat-x;\n  }\n  .carousel-control:hover,\n  .carousel-control:focus {\n    color: #fff;\n    text-decoration: none;\n    filter: alpha(opacity=90);\n    outline: 0;\n    opacity: .9;\n  }\n  .carousel-control .icon-prev,\n  .carousel-control .icon-next,\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .glyphicon-chevron-right {\n    position: absolute;\n    top: 50%;\n    z-index: 5;\n    display: inline-block;\n    margin-top: -10px;\n  }\n  .carousel-control .icon-prev,\n  .carousel-control .glyphicon-chevron-left {\n    left: 50%;\n    margin-left: -10px;\n  }\n  .carousel-control .icon-next,\n  .carousel-control .glyphicon-chevron-right {\n    right: 50%;\n    margin-right: -10px;\n  }\n  .carousel-control .icon-prev,\n  .carousel-control .icon-next {\n    width: 20px;\n    height: 20px;\n    font-family: serif;\n    line-height: 1;\n  }\n  .carousel-control .icon-prev:before {\n    content: '\\2039';\n  }\n  .carousel-control .icon-next:before {\n    content: '\\203a';\n  }\n  .carousel-indicators {\n    position: absolute;\n    bottom: 10px;\n    left: 50%;\n    z-index: 15;\n    width: 60%;\n    padding-left: 0;\n    margin-left: -30%;\n    text-align: center;\n    list-style: none;\n  }\n  .carousel-indicators li {\n    display: inline-block;\n    width: 10px;\n    height: 10px;\n    margin: 1px;\n    text-indent: -999px;\n    cursor: pointer;\n    background-color: #000 \\9;\n    background-color: rgba(0, 0, 0, 0);\n    border: 1px solid #fff;\n    border-radius: 10px;\n  }\n  .carousel-indicators .active {\n    width: 12px;\n    height: 12px;\n    margin: 0;\n    background-color: #fff;\n  }\n  .carousel-caption {\n    position: absolute;\n    right: 15%;\n    bottom: 20px;\n    left: 15%;\n    z-index: 10;\n    padding-top: 20px;\n    padding-bottom: 20px;\n    color: #fff;\n    text-align: center;\n    text-shadow: 0 1px 2px rgba(0, 0, 0, .6);\n  }\n  .carousel-caption .btn {\n    text-shadow: none;\n  }\n  @media screen and (min-width: 768px) {\n    .carousel-control .glyphicon-chevron-left,\n    .carousel-control .glyphicon-chevron-right,\n    .carousel-control .icon-prev,\n    .carousel-control .icon-next {\n      width: 30px;\n      height: 30px;\n      margin-top: -10px;\n      font-size: 30px;\n    }\n    .carousel-control .glyphicon-chevron-left,\n    .carousel-control .icon-prev {\n      margin-left: -10px;\n    }\n    .carousel-control .glyphicon-chevron-right,\n    .carousel-control .icon-next {\n      margin-right: -10px;\n    }\n    .carousel-caption {\n      right: 20%;\n      left: 20%;\n      padding-bottom: 30px;\n    }\n    .carousel-indicators {\n      bottom: 20px;\n    }\n  }\n  .clearfix:before,\n  .clearfix:after,\n  .dl-horizontal dd:before,\n  .dl-horizontal dd:after,\n  .container:before,\n  .container:after,\n  .container-fluid:before,\n  .container-fluid:after,\n  .row:before,\n  .row:after,\n  .form-horizontal .form-group:before,\n  .form-horizontal .form-group:after,\n  .btn-toolbar:before,\n  .btn-toolbar:after,\n  .btn-group-vertical > .btn-group:before,\n  .btn-group-vertical > .btn-group:after,\n  .nav:before,\n  .nav:after,\n  .navbar:before,\n  .navbar:after,\n  .navbar-header:before,\n  .navbar-header:after,\n  .navbar-collapse:before,\n  .navbar-collapse:after,\n  .pager:before,\n  .pager:after,\n  .panel-body:before,\n  .panel-body:after,\n  .modal-header:before,\n  .modal-header:after,\n  .modal-footer:before,\n  .modal-footer:after {\n    display: table;\n    content: \" \";\n  }\n  .clearfix:after,\n  .dl-horizontal dd:after,\n  .container:after,\n  .container-fluid:after,\n  .row:after,\n  .form-horizontal .form-group:after,\n  .btn-toolbar:after,\n  .btn-group-vertical > .btn-group:after,\n  .nav:after,\n  .navbar:after,\n  .navbar-header:after,\n  .navbar-collapse:after,\n  .pager:after,\n  .panel-body:after,\n  .modal-header:after,\n  .modal-footer:after {\n    clear: both;\n  }\n  .center-block {\n    display: block;\n    margin-right: auto;\n    margin-left: auto;\n  }\n  .pull-right {\n    float: right !important;\n  }\n  .pull-left {\n    float: left !important;\n  }\n  .hide {\n    display: none !important;\n  }\n  .show {\n    display: block !important;\n  }\n  .invisible {\n    visibility: hidden;\n  }\n  .text-hide {\n    font: 0/0 a;\n    color: transparent;\n    text-shadow: none;\n    background-color: transparent;\n    border: 0;\n  }\n  .hidden {\n    display: none !important;\n  }\n  .affix {\n    position: fixed;\n  }\n  @-ms-viewport {\n    width: device-width;\n  }\n  .visible-xs,\n  .visible-sm,\n  .visible-md,\n  .visible-lg {\n    display: none !important;\n  }\n  .visible-xs-block,\n  .visible-xs-inline,\n  .visible-xs-inline-block,\n  .visible-sm-block,\n  .visible-sm-inline,\n  .visible-sm-inline-block,\n  .visible-md-block,\n  .visible-md-inline,\n  .visible-md-inline-block,\n  .visible-lg-block,\n  .visible-lg-inline,\n  .visible-lg-inline-block {\n    display: none !important;\n  }\n  @media (max-width: 767px) {\n    .visible-xs {\n      display: block !important;\n    }\n    table.visible-xs {\n      display: table !important;\n    }\n    tr.visible-xs {\n      display: table-row !important;\n    }\n    th.visible-xs,\n    td.visible-xs {\n      display: table-cell !important;\n    }\n  }\n  @media (max-width: 767px) {\n    .visible-xs-block {\n      display: block !important;\n    }\n  }\n  @media (max-width: 767px) {\n    .visible-xs-inline {\n      display: inline !important;\n    }\n  }\n  @media (max-width: 767px) {\n    .visible-xs-inline-block {\n      display: inline-block !important;\n    }\n  }\n  @media (min-width: 768px) and (max-width: 991px) {\n    .visible-sm {\n      display: block !important;\n    }\n    table.visible-sm {\n      display: table !important;\n    }\n    tr.visible-sm {\n      display: table-row !important;\n    }\n    th.visible-sm,\n    td.visible-sm {\n      display: table-cell !important;\n    }\n  }\n  @media (min-width: 768px) and (max-width: 991px) {\n    .visible-sm-block {\n      display: block !important;\n    }\n  }\n  @media (min-width: 768px) and (max-width: 991px) {\n    .visible-sm-inline {\n      display: inline !important;\n    }\n  }\n  @media (min-width: 768px) and (max-width: 991px) {\n    .visible-sm-inline-block {\n      display: inline-block !important;\n    }\n  }\n  @media (min-width: 992px) and (max-width: 1199px) {\n    .visible-md {\n      display: block !important;\n    }\n    table.visible-md {\n      display: table !important;\n    }\n    tr.visible-md {\n      display: table-row !important;\n    }\n    th.visible-md,\n    td.visible-md {\n      display: table-cell !important;\n    }\n  }\n  @media (min-width: 992px) and (max-width: 1199px) {\n    .visible-md-block {\n      display: block !important;\n    }\n  }\n  @media (min-width: 992px) and (max-width: 1199px) {\n    .visible-md-inline {\n      display: inline !important;\n    }\n  }\n  @media (min-width: 992px) and (max-width: 1199px) {\n    .visible-md-inline-block {\n      display: inline-block !important;\n    }\n  }\n  @media (min-width: 1200px) {\n    .visible-lg {\n      display: block !important;\n    }\n    table.visible-lg {\n      display: table !important;\n    }\n    tr.visible-lg {\n      display: table-row !important;\n    }\n    th.visible-lg,\n    td.visible-lg {\n      display: table-cell !important;\n    }\n  }\n  @media (min-width: 1200px) {\n    .visible-lg-block {\n      display: block !important;\n    }\n  }\n  @media (min-width: 1200px) {\n    .visible-lg-inline {\n      display: inline !important;\n    }\n  }\n  @media (min-width: 1200px) {\n    .visible-lg-inline-block {\n      display: inline-block !important;\n    }\n  }\n  @media (max-width: 767px) {\n    .hidden-xs {\n      display: none !important;\n    }\n  }\n  @media (min-width: 768px) and (max-width: 991px) {\n    .hidden-sm {\n      display: none !important;\n    }\n  }\n  @media (min-width: 992px) and (max-width: 1199px) {\n    .hidden-md {\n      display: none !important;\n    }\n  }\n  @media (min-width: 1200px) {\n    .hidden-lg {\n      display: none !important;\n    }\n  }\n  .visible-print {\n    display: none !important;\n  }\n  @media print {\n    .visible-print {\n      display: block !important;\n    }\n    table.visible-print {\n      display: table !important;\n    }\n    tr.visible-print {\n      display: table-row !important;\n    }\n    th.visible-print,\n    td.visible-print {\n      display: table-cell !important;\n    }\n  }\n  .visible-print-block {\n    display: none !important;\n  }\n  @media print {\n    .visible-print-block {\n      display: block !important;\n    }\n  }\n  .visible-print-inline {\n    display: none !important;\n  }\n  @media print {\n    .visible-print-inline {\n      display: inline !important;\n    }\n  }\n  .visible-print-inline-block {\n    display: none !important;\n  }\n  @media print {\n    .visible-print-inline-block {\n      display: inline-block !important;\n    }\n  }\n  @media print {\n    .hidden-print {\n      display: none !important;\n    }\n  }\n  /*# sourceMappingURL=bootstrap.css.map */"
  },
  {
    "path": "static/css/login.css",
    "content": ".input-group {\n    padding-top: 10px;\n    padding-bottom: 10px;\n}\n\n/* @font-face {\n    font-family: title-speed;\n    src: url('/fonts/LobsterTwo-Regular.otf');\n} */\n\n.navbar-brand {\n    font-family: title-speed;\n    font-size: 1.2rem;\n    font-weight: 500;\n\n}\n\n#bg {\n    position: fixed;\n    top: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    z-index: 1;\n    background-color: #000;\n}\n\n#bg>div:nth-child(1) {\n    animation-delay: 10s;\n}\n\n#bg>div:nth-child(2) {\n    animation-delay: 20s;\n}\n\n#bg>div {\n    background-size: cover;\n    background-position: center center;\n    width: 100%;\n    height: 100%;\n    position: absolute;\n    top: 0;\n    left: 0;\n    opacity: 0;\n    visibility: hidden;\n    transition: opacity 3s ease, visibility 3s;\n    animation: bg 30s linear infinite;\n}\n\n@keyframes bg {\n    0% {\n        -webkit-transform: scale(1, 1);\n        -moz-transform: scale(1, 1);\n        -ms-transform: scale(1, 1);\n        -o-transform: scale(1, 1);\n        transform: scale(1, 1);\n        visibility: visible;\n        opacity: 0;\n    }\n\n    5% {\n        opacity: 0.5;\n    }\n\n    33% {\n        opacity: 0.5;\n    }\n\n    38% {\n        transform: scale(1.2, 1.2);\n        opacity: 0;\n    }\n\n    39% {\n        visibility: hidden;\n    }\n\n    100% {\n        visibility: hidden;\n        opacity: 0;\n    }\n}\n\n/* .login {\n    background-color: #1a237e;\n    background-image: url(static/svg/motif-blocks.svg);\n    background-repeat: repeat;\n    background-size: 200px;\n    width: 100%;\n    height: 100%;\n    -webkit-animation: loginBgReveal 20s linear infinite;\n    animation: loginBgReveal 20s linear infinite;\n}\n\n.login:before {\n    content: \"\";\n    position: absolute;\n    background-image: url(static/svg/motif-overlay.svg);\n    background-attachment: fixed;\n    background-size: cover;\n    opacity: .001;\n    top: 0;\n    left: 0;\n    width: 100vw;\n    height: 100vh;\n}\n\n@keyframes loginBgReveal {\n    0% {\n        background-position-y: 0;\n    }\n\n    100% {\n        background-position-y: 800px;\n    }\n} */\n\n.form-control,\n.form-group .form-control {\n    background-position: center bottom;\n}\n\n.btn.btn-rose.btn-simple, .navbar .navbar-nav>li>a.btn.btn-rose.btn-simple {\n    background-color: #1976d2;\n    color: #fff;\n    box-shadow: 0 2px 2px 0 rgba(0, 123, 255, 0.14), 0 3px 1px -2px rgba(0, 123, 255, 0.2), 0 1px 5px 0 rgba(0, 123, 255, 0.12);\n}\n\n.btn.btn-lg, .btn-group-lg .btn, .navbar .navbar-nav>li>a.btn.btn-lg, .btn-group-lg .navbar .navbar-nav>li>a.btn {\n    padding: unset;\n}\n\n.card [data-background-color=\"rose\"] {\n    background: linear-gradient(60deg, #0091ea, #1976d2);\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(233, 30, 99, 0.4);\n}\n\n.btn.btn-rose.btn-simple:hover, .btn.btn-rose.btn-simple:focus, .btn.btn-rose.btn-simple:active, .navbar .navbar-nav>li>a.btn.btn-rose.btn-simple:hover, .navbar .navbar-nav>li>a.btn.btn-rose.btn-simple:focus, .navbar .navbar-nav>li>a.btn.btn-rose.btn-simple:active {\n    background-color: #1976d2;\n    color: #fff;\n    box-shadow: 0 2px 2px 0 rgba(0, 123, 255, 0.14), 0 3px 1px -2px rgba(0, 123, 255, 0.2), 0 1px 5px 0 rgba(0, 123, 255, 0.12);\n}\n\n#login {\n    line-height: 0px;\n}\n\n#forget-password {\n    float: right;\n    margin-top: -10px;\n}\n\n#forget-password:hover {\n    color: #039be5;\n}\n\n#forget-password:focus {\n    color: #039be5;\n}\n\nnav ul li.active {\n    background-color: unset;\n}"
  },
  {
    "path": "static/css/material-dash.css",
    "content": ".noUi-target,\n.noUi-target * {\n    -webkit-touch-callout: none;\n    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n    -webkit-user-select: none;\n    -ms-touch-action: none;\n    touch-action: none;\n    -ms-user-select: none;\n    -moz-user-select: none;\n    user-select: none;\n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n}\n\n.noUi-target {\n    position: relative;\n    direction: ltr;\n}\n\n.noUi-base {\n    width: 100%;\n    height: 100%;\n    position: relative;\n    z-index: 1;\n    /* Fix 401 */\n}\n\n.noUi-connect {\n    position: absolute;\n    right: 0;\n    top: 0;\n    left: 0;\n    bottom: 0;\n}\n\n.noUi-origin {\n    position: absolute;\n    height: 0;\n    width: 0;\n}\n\n.noUi-handle {\n    position: relative;\n    z-index: 1;\n}\n\n.noUi-state-tap .noUi-connect,\n.noUi-state-tap .noUi-origin {\n    -webkit-transition: top 0.3s, right 0.3s, bottom 0.3s, left 0.3s;\n    transition: top 0.3s, right 0.3s, bottom 0.3s, left 0.3s;\n}\n\n.noUi-state-drag * {\n    cursor: inherit !important;\n}\n\n\n/* Painting and performance;\n * Browsers can paint handles in their own layer.\n */\n\n.noUi-base,\n.noUi-handle {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n}\n\n\n/* Slider size and handle placement;\n */\n\n.noUi-horizontal {\n    height: 2px;\n}\n\n.noUi-horizontal .noUi-handle {\n    box-sizing: border-box;\n    width: 14px;\n    height: 14px;\n    left: -10px;\n    top: -6px;\n    cursor: pointer;\n    border-radius: 100%;\n    transition: all 0.2s ease-out;\n    border: 1px solid #9c27b0;\n    background: #FFFFFF;\n    box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);\n}\n\n.noUi-vertical {\n    width: 18px;\n}\n\n.noUi-vertical .noUi-handle {\n    width: 28px;\n    height: 34px;\n    left: -6px;\n    top: -17px;\n}\n\n\n/* Styling;\n */\n\n.noUi-target {\n    background-color: #c8c8c8;\n    border-radius: 3px;\n}\n\n.noUi-connect {\n    background: #9c27b0;\n    border-radius: 3px;\n    -webkit-transition: background 450ms;\n    transition: background 450ms;\n}\n\n\n/* Handles and cursors;\n */\n\n.noUi-draggable {\n    cursor: ew-resize;\n}\n\n.noUi-vertical .noUi-draggable {\n    cursor: ns-resize;\n}\n\n.noUi-handle {\n    border-radius: 3px;\n    background: #FFF;\n    cursor: default;\n    box-shadow: inset 0 0 1px #FFF, inset 0 1px 7px #EBEBEB, 0 3px 6px -3px #BBB;\n    -webkit-transition: 300ms ease 0s;\n    -moz-transition: 300ms ease 0s;\n    -ms-transition: 300ms ease 0s;\n    -o-transform: 300ms ease 0s;\n    transition: 300ms ease 0s;\n}\n\n.noUi-active {\n    -webkit-transform: scale3d(1.5, 1.5, 1);\n    -moz-transform: scale3d(1.5, 1.5, 1);\n    -ms-transform: scale3d(1.5, 1.5, 1);\n    -o-transform: scale3d(1.5, 1.5, 1);\n    transform: scale3d(1.5, 1.5, 1);\n}\n\n\n/* Disabled state;\n */\n\n[disabled] .noUi-connect {\n    background: #B8B8B8;\n}\n\n[disabled].noUi-target,\n[disabled].noUi-handle,\n[disabled] .noUi-handle {\n    cursor: not-allowed;\n}\n\n\n/* Base;\n *\n */\n\n.noUi-pips,\n.noUi-pips * {\n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n}\n\n.noUi-pips {\n    position: absolute;\n    color: #999;\n}\n\n\n/* Values;\n *\n */\n\n.noUi-value {\n    position: absolute;\n    text-align: center;\n}\n\n.noUi-value-sub {\n    color: #ccc;\n    font-size: 10px;\n}\n\n\n/* Markings;\n *\n */\n\n.noUi-marker {\n    position: absolute;\n    background: #CCC;\n}\n\n.noUi-marker-sub {\n    background: #AAA;\n}\n\n.noUi-marker-large {\n    background: #AAA;\n}\n\n\n/* Horizontal layout;\n *\n */\n\n.noUi-pips-horizontal {\n    padding: 10px 0;\n    height: 80px;\n    top: 100%;\n    left: 0;\n    width: 100%;\n}\n\n.noUi-value-horizontal {\n    -webkit-transform: translate3d(-50%, 50%, 0);\n    transform: translate3d(-50%, 50%, 0);\n}\n\n.noUi-marker-horizontal.noUi-marker {\n    margin-left: -1px;\n    width: 2px;\n    height: 5px;\n}\n\n.noUi-marker-horizontal.noUi-marker-sub {\n    height: 10px;\n}\n\n.noUi-marker-horizontal.noUi-marker-large {\n    height: 15px;\n}\n\n\n/* Vertical layout;\n *\n */\n\n.noUi-pips-vertical {\n    padding: 0 10px;\n    height: 100%;\n    top: 0;\n    left: 100%;\n}\n\n.noUi-value-vertical {\n    -webkit-transform: translate3d(0, 50%, 0);\n    transform: translate3d(0, 50%, 0);\n    padding-left: 25px;\n}\n\n.noUi-marker-vertical.noUi-marker {\n    width: 5px;\n    height: 2px;\n    margin-top: -1px;\n}\n\n.noUi-marker-vertical.noUi-marker-sub {\n    width: 10px;\n}\n\n.noUi-marker-vertical.noUi-marker-large {\n    width: 15px;\n}\n\n.noUi-tooltip {\n    display: block;\n    position: absolute;\n    border: 1px solid #D9D9D9;\n    border-radius: 3px;\n    background: #fff;\n    color: #000;\n    padding: 5px;\n    text-align: center;\n}\n\n.noUi-horizontal .noUi-tooltip {\n    -webkit-transform: translate(-50%, 0);\n    transform: translate(-50%, 0);\n    left: 50%;\n    bottom: 120%;\n}\n\n.noUi-vertical .noUi-tooltip {\n    -webkit-transform: translate(0, -50%);\n    transform: translate(0, -50%);\n    top: 50%;\n    right: 120%;\n}\n\n.slider {\n    margin-bottom: 15px;\n}\n\n.slider.slider-primary .noUi-connect,\n.slider.slider-primary.noUi-connect {\n    background-color: #9c27b0;\n}\n\n.slider.slider-primary .noUi-handle {\n    border-color: #9c27b0;\n}\n\n.slider.slider-info .noUi-connect,\n.slider.slider-info.noUi-connect {\n    background-color: #00bcd4;\n}\n\n.slider.slider-info .noUi-handle {\n    border-color: #00bcd4;\n}\n\n.slider.slider-success .noUi-connect,\n.slider.slider-success.noUi-connect {\n    background-color: #4caf50;\n}\n\n.slider.slider-success .noUi-handle {\n    border-color: #4caf50;\n}\n\n.slider.slider-warning .noUi-connect,\n.slider.slider-warning.noUi-connect {\n    background-color: #ff9800;\n}\n\n.slider.slider-warning .noUi-handle {\n    border-color: #ff9800;\n}\n\n.slider.slider-danger .noUi-connect,\n.slider.slider-danger.noUi-connect {\n    background-color: #f44336;\n}\n\n.slider.slider-danger .noUi-handle {\n    border-color: #f44336;\n}\n\n\n/*\nAnimate.css - http://daneden.me/animate\nLicensed under the MIT license - http://opensource.org/licenses/MIT\n\nCopyright (c) 2015 Daniel Eden\n*/\n\n.animated {\n    -webkit-animation-duration: 1s;\n    animation-duration: 1s;\n    -webkit-animation-fill-mode: both;\n    animation-fill-mode: both;\n}\n\n.animated.infinite {\n    -webkit-animation-iteration-count: infinite;\n    animation-iteration-count: infinite;\n}\n\n.animated.hinge {\n    -webkit-animation-duration: 2s;\n    animation-duration: 2s;\n}\n\n.animated.bounceIn,\n.animated.bounceOut {\n    -webkit-animation-duration: .75s;\n    animation-duration: .75s;\n}\n\n.animated.flipOutX,\n.animated.flipOutY {\n    -webkit-animation-duration: .75s;\n    animation-duration: .75s;\n}\n\n@-webkit-keyframes shake {\n    from,\n    to {\n        -webkit-transform: translate3d(0, 0, 0);\n        transform: translate3d(0, 0, 0);\n    }\n    10%,\n    30%,\n    50%,\n    70%,\n    90% {\n        -webkit-transform: translate3d(-10px, 0, 0);\n        transform: translate3d(-10px, 0, 0);\n    }\n    20%,\n    40%,\n    60%,\n    80% {\n        -webkit-transform: translate3d(10px, 0, 0);\n        transform: translate3d(10px, 0, 0);\n    }\n}\n\n@keyframes shake {\n    from,\n    to {\n        -webkit-transform: translate3d(0, 0, 0);\n        transform: translate3d(0, 0, 0);\n    }\n    10%,\n    30%,\n    50%,\n    70%,\n    90% {\n        -webkit-transform: translate3d(-10px, 0, 0);\n        transform: translate3d(-10px, 0, 0);\n    }\n    20%,\n    40%,\n    60%,\n    80% {\n        -webkit-transform: translate3d(10px, 0, 0);\n        transform: translate3d(10px, 0, 0);\n    }\n}\n\n.shake {\n    -webkit-animation-name: shake;\n    animation-name: shake;\n}\n\n@-webkit-keyframes fadeInDown {\n    from {\n        opacity: 0;\n        -webkit-transform: translate3d(0, -100%, 0);\n        transform: translate3d(0, -100%, 0);\n    }\n    to {\n        opacity: 1;\n        -webkit-transform: none;\n        transform: none;\n    }\n}\n\n@keyframes fadeInDown {\n    from {\n        opacity: 0;\n        -webkit-transform: translate3d(0, -100%, 0);\n        transform: translate3d(0, -100%, 0);\n    }\n    to {\n        opacity: 1;\n        -webkit-transform: none;\n        transform: none;\n    }\n}\n\n.fadeInDown {\n    -webkit-animation-name: fadeInDown;\n    animation-name: fadeInDown;\n}\n\n@-webkit-keyframes fadeOut {\n    from {\n        opacity: 1;\n    }\n    to {\n        opacity: 0;\n    }\n}\n\n@keyframes fadeOut {\n    from {\n        opacity: 1;\n    }\n    to {\n        opacity: 0;\n    }\n}\n\n.fadeOut {\n    -webkit-animation-name: fadeOut;\n    animation-name: fadeOut;\n}\n\n@-webkit-keyframes fadeOutDown {\n    from {\n        opacity: 1;\n    }\n    to {\n        opacity: 0;\n        -webkit-transform: translate3d(0, 100%, 0);\n        transform: translate3d(0, 100%, 0);\n    }\n}\n\n@keyframes fadeOutDown {\n    from {\n        opacity: 1;\n    }\n    to {\n        opacity: 0;\n        -webkit-transform: translate3d(0, 100%, 0);\n        transform: translate3d(0, 100%, 0);\n    }\n}\n\n.fadeOutDown {\n    -webkit-animation-name: fadeOutDown;\n    animation-name: fadeOutDown;\n}\n\n@-webkit-keyframes fadeOutUp {\n    from {\n        opacity: 1;\n    }\n    to {\n        opacity: 0;\n        -webkit-transform: translate3d(0, -100%, 0);\n        transform: translate3d(0, -100%, 0);\n    }\n}\n\n@keyframes fadeOutUp {\n    from {\n        opacity: 1;\n    }\n    to {\n        opacity: 0;\n        -webkit-transform: translate3d(0, -100%, 0);\n        transform: translate3d(0, -100%, 0);\n    }\n}\n\n.fadeOutUp {\n    -webkit-animation-name: fadeOutUp;\n    animation-name: fadeOutUp;\n}\n\nbody.swal2-in {\n    overflow-y: hidden;\n}\n\nbody.swal2-iosfix {\n    position: fixed;\n    left: 0;\n    right: 0;\n}\n\n.swal2-container {\n    display: -webkit-box;\n    display: -ms-flexbox;\n    display: flex;\n    -webkit-box-align: center;\n    -ms-flex-align: center;\n    align-items: center;\n    position: fixed;\n    top: 0;\n    left: 0;\n    bottom: 0;\n    right: 0;\n    padding: 10px;\n    background-color: transparent;\n    z-index: 1060;\n}\n\n.swal2-container:not(.swal2-in) {\n    pointer-events: none;\n}\n\n.swal2-container.swal2-fade {\n    -webkit-transition: background-color .1s;\n    transition: background-color .1s;\n}\n\n.swal2-container.swal2-in {\n    background-color: rgba(0, 0, 0, 0.4);\n}\n\n.swal2-modal {\n    background-color: #fff;\n    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n    border-radius: 5px;\n    box-sizing: border-box;\n    text-align: center;\n    margin: auto;\n    overflow-x: hidden;\n    overflow-y: auto;\n    display: none;\n    position: relative;\n}\n\n.swal2-modal:focus {\n    outline: none;\n}\n\n.swal2-modal.swal2-loading {\n    overflow-y: hidden;\n}\n\n.swal2-modal h2 {\n    color: #595959;\n    font-size: 30px;\n    text-align: center;\n    font-weight: 600;\n    text-transform: none;\n    position: relative;\n    margin: 0;\n    padding: 0;\n    line-height: 60px;\n    display: block;\n}\n\n.swal2-modal .swal2-spacer {\n    height: 10px;\n    color: transparent;\n    margin-bottom: 0px;\n    border: 0;\n}\n\n.swal2-modal .swal2-styled {\n    border: 0;\n    border-radius: 3px;\n    box-shadow: none;\n    color: #fff;\n    cursor: pointer;\n    font-size: 17px;\n    font-weight: 500;\n    margin: 0 5px;\n    padding: 10px 32px;\n}\n\n.swal2-modal .swal2-styled:not(.swal2-loading)[disabled] {\n    opacity: .4;\n    cursor: no-drop;\n}\n\n.swal2-modal .swal2-styled.swal2-loading {\n    box-sizing: border-box;\n    border: 4px solid transparent;\n    border-color: transparent;\n    width: 40px;\n    height: 40px;\n    padding: 0;\n    margin: -2px 30px;\n    vertical-align: top;\n    background-color: transparent !important;\n    color: transparent;\n    cursor: default;\n    border-radius: 100%;\n    -webkit-animation: rotate-loading 1.5s linear 0s infinite normal;\n    animation: rotate-loading 1.5s linear 0s infinite normal;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n}\n\n.swal2-modal :not(.swal2-styled).swal2-loading::after {\n    display: inline-block;\n    content: '';\n    margin-left: 5px;\n    vertical-align: -1px;\n    height: 6px;\n    width: 6px;\n    border: 3px solid #999999;\n    border-right-color: transparent;\n    border-radius: 50%;\n    -webkit-animation: rotate-loading 1.5s linear 0s infinite normal;\n    animation: rotate-loading 1.5s linear 0s infinite normal;\n}\n\n.swal2-modal .swal2-image {\n    margin: 20px auto;\n    max-width: 100%;\n}\n\n.swal2-modal .swal2-close {\n    font-size: 36px;\n    line-height: 36px;\n    font-family: serif;\n    position: absolute;\n    top: 5px;\n    right: 13px;\n    cursor: pointer;\n    color: #cccccc;\n    -webkit-transition: color .1s ease;\n    transition: color .1s ease;\n}\n\n.swal2-modal .swal2-close:hover {\n    color: #d55;\n}\n\n.swal2-modal>.swal2-input,\n.swal2-modal>.swal2-file,\n.swal2-modal>.swal2-textarea,\n.swal2-modal>.swal2-select,\n.swal2-modal>.swal2-radio,\n.swal2-modal>.swal2-checkbox {\n    display: none;\n}\n\n.swal2-modal .swal2-content {\n    font-size: 18px;\n    text-align: center;\n    font-weight: 300;\n    position: relative;\n    float: none;\n    margin: 0;\n    padding: 0;\n    line-height: normal;\n    color: #545454;\n}\n\n.swal2-modal .swal2-input,\n.swal2-modal .swal2-file,\n.swal2-modal .swal2-textarea,\n.swal2-modal .swal2-select,\n.swal2-modal .swal2-radio,\n.swal2-modal .swal2-checkbox {\n    margin: 20px auto;\n}\n\n.swal2-modal .swal2-input,\n.swal2-modal .swal2-file,\n.swal2-modal .swal2-textarea {\n    width: 100%;\n    box-sizing: border-box;\n    border-radius: 3px;\n    border: 1px solid #d9d9d9;\n    font-size: 18px;\n    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.06);\n    -webkit-transition: border-color box-shadow .3s;\n    transition: border-color box-shadow .3s;\n}\n\n.swal2-modal .swal2-input.swal2-inputerror,\n.swal2-modal .swal2-file.swal2-inputerror,\n.swal2-modal .swal2-textarea.swal2-inputerror {\n    border-color: #f06e57;\n}\n\n.swal2-modal .swal2-input:focus,\n.swal2-modal .swal2-file:focus,\n.swal2-modal .swal2-textarea:focus {\n    outline: none;\n    box-shadow: 0 0 3px #c4e6f5;\n    border: 1px solid #b4dbed;\n}\n\n.swal2-modal .swal2-input:focus::-webkit-input-placeholder,\n.swal2-modal .swal2-file:focus::-webkit-input-placeholder,\n.swal2-modal .swal2-textarea:focus::-webkit-input-placeholder {\n    -webkit-transition: opacity .3s .03s ease;\n    transition: opacity .3s .03s ease;\n    opacity: .8;\n}\n\n.swal2-modal .swal2-input:focus::-moz-placeholder,\n.swal2-modal .swal2-file:focus::-moz-placeholder,\n.swal2-modal .swal2-textarea:focus::-moz-placeholder {\n    -webkit-transition: opacity .3s .03s ease;\n    transition: opacity .3s .03s ease;\n    opacity: .8;\n}\n\n.swal2-modal .swal2-input:focus:-ms-input-placeholder,\n.swal2-modal .swal2-file:focus:-ms-input-placeholder,\n.swal2-modal .swal2-textarea:focus:-ms-input-placeholder {\n    -webkit-transition: opacity .3s .03s ease;\n    transition: opacity .3s .03s ease;\n    opacity: .8;\n}\n\n.swal2-modal .swal2-input:focus::placeholder,\n.swal2-modal .swal2-file:focus::placeholder,\n.swal2-modal .swal2-textarea:focus::placeholder {\n    -webkit-transition: opacity .3s .03s ease;\n    transition: opacity .3s .03s ease;\n    opacity: .8;\n}\n\n.swal2-modal .swal2-input::-webkit-input-placeholder,\n.swal2-modal .swal2-file::-webkit-input-placeholder,\n.swal2-modal .swal2-textarea::-webkit-input-placeholder {\n    color: #e6e6e6;\n}\n\n.swal2-modal .swal2-input::-moz-placeholder,\n.swal2-modal .swal2-file::-moz-placeholder,\n.swal2-modal .swal2-textarea::-moz-placeholder {\n    color: #e6e6e6;\n}\n\n.swal2-modal .swal2-input:-ms-input-placeholder,\n.swal2-modal .swal2-file:-ms-input-placeholder,\n.swal2-modal .swal2-textarea:-ms-input-placeholder {\n    color: #e6e6e6;\n}\n\n.swal2-modal .swal2-input::placeholder,\n.swal2-modal .swal2-file::placeholder,\n.swal2-modal .swal2-textarea::placeholder {\n    color: #e6e6e6;\n}\n\n.swal2-modal .swal2-range input {\n    float: left;\n    width: 80%;\n}\n\n.swal2-modal .swal2-range output {\n    float: right;\n    width: 20%;\n    font-size: 20px;\n    font-weight: 600;\n    text-align: center;\n}\n\n.swal2-modal .swal2-range input,\n.swal2-modal .swal2-range output {\n    height: 43px;\n    line-height: 43px;\n    vertical-align: middle;\n    margin: 20px auto;\n    padding: 0;\n}\n\n.swal2-modal .swal2-input {\n    height: 43px;\n    padding: 0 12px;\n}\n\n.swal2-modal .swal2-input[type='number'] {\n    max-width: 150px;\n}\n\n.swal2-modal .swal2-file {\n    font-size: 20px;\n}\n\n.swal2-modal .swal2-textarea {\n    height: 108px;\n    padding: 12px;\n}\n\n.swal2-modal .swal2-select {\n    color: #545454;\n    font-size: inherit;\n    padding: 5px 10px;\n    min-width: 40%;\n    max-width: 100%;\n}\n\n.swal2-modal .swal2-radio {\n    border: 0;\n}\n\n.swal2-modal .swal2-radio label:not(:first-child) {\n    margin-left: 20px;\n}\n\n.swal2-modal .swal2-radio input,\n.swal2-modal .swal2-radio span {\n    vertical-align: middle;\n}\n\n.swal2-modal .swal2-radio input {\n    margin: 0 3px 0 0;\n}\n\n.swal2-modal .swal2-checkbox {\n    color: #545454;\n}\n\n.swal2-modal .swal2-checkbox input,\n.swal2-modal .swal2-checkbox span {\n    vertical-align: middle;\n}\n\n.swal2-modal .swal2-validationerror {\n    background-color: #f0f0f0;\n    margin: 0 -20px;\n    overflow: hidden;\n    padding: 10px;\n    color: gray;\n    font-size: 16px;\n    font-weight: 300;\n    display: none;\n}\n\n.swal2-modal .swal2-validationerror::before {\n    content: '!';\n    display: inline-block;\n    width: 24px;\n    height: 24px;\n    border-radius: 50%;\n    background-color: #ea7d7d;\n    color: #fff;\n    line-height: 24px;\n    text-align: center;\n    margin-right: 10px;\n}\n\n.swal2-modal button {\n    margin: 0 5px;\n}\n\n@supports (-ms-accelerator: true) {\n    .swal2-range input {\n        width: 100% !important;\n    }\n    .swal2-range output {\n        display: none;\n    }\n}\n\n@media all and (-ms-high-contrast: none),\n(-ms-high-contrast: active) {\n    .swal2-range input {\n        width: 100% !important;\n    }\n    .swal2-range output {\n        display: none;\n    }\n}\n\n.swal2-icon {\n    width: 80px;\n    height: 80px;\n    border: 4px solid transparent;\n    border-radius: 50%;\n    margin: 20px auto 30px;\n    padding: 0;\n    position: relative;\n    box-sizing: content-box;\n    cursor: default;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n}\n\n.swal2-icon.swal2-error {\n    border-color: #f27474;\n}\n\n.swal2-icon.swal2-error .x-mark {\n    position: relative;\n    display: block;\n}\n\n.swal2-icon.swal2-error .line {\n    position: absolute;\n    height: 5px;\n    width: 47px;\n    background-color: #f27474;\n    display: block;\n    top: 37px;\n    border-radius: 2px;\n}\n\n.swal2-icon.swal2-error .line.left {\n    -webkit-transform: rotate(45deg);\n    transform: rotate(45deg);\n    left: 17px;\n}\n\n.swal2-icon.swal2-error .line.right {\n    -webkit-transform: rotate(-45deg);\n    transform: rotate(-45deg);\n    right: 16px;\n}\n\n.swal2-icon.swal2-warning {\n    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n    color: #f8bb86;\n    border-color: #facea8;\n    font-size: 60px;\n    line-height: 80px;\n    text-align: center;\n}\n\n.swal2-icon.swal2-info {\n    font-family: 'Open Sans', sans-serif;\n    color: #3fc3ee;\n    border-color: #9de0f6;\n    font-size: 60px;\n    line-height: 80px;\n    text-align: center;\n}\n\n.swal2-icon.swal2-question {\n    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n    color: #87adbd;\n    border-color: #c9dae1;\n    font-size: 60px;\n    line-height: 80px;\n    text-align: center;\n}\n\n.swal2-icon.swal2-success {\n    border-color: #a5dc86;\n}\n\n.swal2-icon.swal2-success::before,\n.swal2-icon.swal2-success::after {\n    content: '';\n    border-radius: 50%;\n    position: absolute;\n    width: 60px;\n    height: 120px;\n    background: #fff;\n    -webkit-transform: rotate(45deg);\n    transform: rotate(45deg);\n}\n\n.swal2-icon.swal2-success::before {\n    border-radius: 120px 0 0 120px;\n    top: -7px;\n    left: -33px;\n    -webkit-transform: rotate(-45deg);\n    transform: rotate(-45deg);\n    -webkit-transform-origin: 60px 60px;\n    transform-origin: 60px 60px;\n}\n\n.swal2-icon.swal2-success::after {\n    border-radius: 0 120px 120px 0;\n    top: -11px;\n    left: 30px;\n    -webkit-transform: rotate(-45deg);\n    transform: rotate(-45deg);\n    -webkit-transform-origin: 0 60px;\n    transform-origin: 0 60px;\n}\n\n.swal2-icon.swal2-success .placeholder {\n    width: 80px;\n    height: 80px;\n    border: 4px solid rgba(165, 220, 134, 0.2);\n    border-radius: 50%;\n    box-sizing: content-box;\n    position: absolute;\n    left: -4px;\n    top: -4px;\n    z-index: 2;\n}\n\n.swal2-icon.swal2-success .fix {\n    width: 7px;\n    height: 90px;\n    background-color: #fff;\n    position: absolute;\n    left: 28px;\n    top: 8px;\n    z-index: 1;\n    -webkit-transform: rotate(-45deg);\n    transform: rotate(-45deg);\n}\n\n.swal2-icon.swal2-success .line {\n    height: 5px;\n    background-color: #a5dc86;\n    display: block;\n    border-radius: 2px;\n    position: absolute;\n    z-index: 2;\n}\n\n.swal2-icon.swal2-success .line.tip {\n    width: 25px;\n    left: 14px;\n    top: 46px;\n    -webkit-transform: rotate(45deg);\n    transform: rotate(45deg);\n}\n\n.swal2-icon.swal2-success .line.long {\n    width: 47px;\n    right: 8px;\n    top: 38px;\n    -webkit-transform: rotate(-45deg);\n    transform: rotate(-45deg);\n}\n\n.swal2-progresssteps {\n    font-weight: 600;\n    margin: 0 0 20px;\n    padding: 0;\n}\n\n.swal2-progresssteps li {\n    display: inline-block;\n    position: relative;\n}\n\n.swal2-progresssteps .swal2-progresscircle {\n    background: #3085d6;\n    border-radius: 2em;\n    color: #fff;\n    height: 2em;\n    line-height: 2em;\n    text-align: center;\n    width: 2em;\n    z-index: 20;\n}\n\n.swal2-progresssteps .swal2-progresscircle:first-child {\n    margin-left: 0;\n}\n\n.swal2-progresssteps .swal2-progresscircle:last-child {\n    margin-right: 0;\n}\n\n.swal2-progresssteps .swal2-progresscircle.swal2-activeprogressstep {\n    background: #3085d6;\n}\n\n.swal2-progresssteps .swal2-progresscircle.swal2-activeprogressstep~.swal2-progresscircle {\n    background: #add8e6;\n}\n\n.swal2-progresssteps .swal2-progresscircle.swal2-activeprogressstep~.swal2-progressline {\n    background: #add8e6;\n}\n\n.swal2-progresssteps .swal2-progressline {\n    background: #3085d6;\n    height: .4em;\n    margin: 0 -1px;\n    z-index: 10;\n}\n\n[class^='swal2'] {\n    -webkit-tap-highlight-color: transparent;\n}\n\n@-webkit-keyframes showSweetAlert {\n    0% {\n        -webkit-transform: scale(0.7);\n        transform: scale(0.7);\n    }\n    45% {\n        -webkit-transform: scale(1.05);\n        transform: scale(1.05);\n    }\n    80% {\n        -webkit-transform: scale(0.95);\n        transform: scale(0.95);\n    }\n    100% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n    }\n}\n\n@keyframes showSweetAlert {\n    0% {\n        -webkit-transform: scale(0.7);\n        transform: scale(0.7);\n    }\n    45% {\n        -webkit-transform: scale(1.05);\n        transform: scale(1.05);\n    }\n    80% {\n        -webkit-transform: scale(0.95);\n        transform: scale(0.95);\n    }\n    100% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n    }\n}\n\n@-webkit-keyframes hideSweetAlert {\n    0% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n        opacity: 1;\n    }\n    100% {\n        -webkit-transform: scale(0.5);\n        transform: scale(0.5);\n        opacity: 0;\n    }\n}\n\n@keyframes hideSweetAlert {\n    0% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n        opacity: 1;\n    }\n    100% {\n        -webkit-transform: scale(0.5);\n        transform: scale(0.5);\n        opacity: 0;\n    }\n}\n\n.swal2-show {\n    -webkit-animation: showSweetAlert 0.3s;\n    animation: showSweetAlert 0.3s;\n}\n\n.swal2-show.swal2-noanimation {\n    -webkit-animation: none;\n    animation: none;\n}\n\n.swal2-hide {\n    -webkit-animation: hideSweetAlert 0.15s forwards;\n    animation: hideSweetAlert 0.15s forwards;\n}\n\n.swal2-hide.swal2-noanimation {\n    -webkit-animation: none;\n    animation: none;\n}\n\n@-webkit-keyframes animate-success-tip {\n    0% {\n        width: 0;\n        left: 1px;\n        top: 19px;\n    }\n    54% {\n        width: 0;\n        left: 1px;\n        top: 19px;\n    }\n    70% {\n        width: 50px;\n        left: -8px;\n        top: 37px;\n    }\n    84% {\n        width: 17px;\n        left: 21px;\n        top: 48px;\n    }\n    100% {\n        width: 25px;\n        left: 14px;\n        top: 45px;\n    }\n}\n\n@keyframes animate-success-tip {\n    0% {\n        width: 0;\n        left: 1px;\n        top: 19px;\n    }\n    54% {\n        width: 0;\n        left: 1px;\n        top: 19px;\n    }\n    70% {\n        width: 50px;\n        left: -8px;\n        top: 37px;\n    }\n    84% {\n        width: 17px;\n        left: 21px;\n        top: 48px;\n    }\n    100% {\n        width: 25px;\n        left: 14px;\n        top: 45px;\n    }\n}\n\n@-webkit-keyframes animate-success-long {\n    0% {\n        width: 0;\n        right: 46px;\n        top: 54px;\n    }\n    65% {\n        width: 0;\n        right: 46px;\n        top: 54px;\n    }\n    84% {\n        width: 55px;\n        right: 0;\n        top: 35px;\n    }\n    100% {\n        width: 47px;\n        right: 8px;\n        top: 38px;\n    }\n}\n\n@keyframes animate-success-long {\n    0% {\n        width: 0;\n        right: 46px;\n        top: 54px;\n    }\n    65% {\n        width: 0;\n        right: 46px;\n        top: 54px;\n    }\n    84% {\n        width: 55px;\n        right: 0;\n        top: 35px;\n    }\n    100% {\n        width: 47px;\n        right: 8px;\n        top: 38px;\n    }\n}\n\n@-webkit-keyframes rotatePlaceholder {\n    0% {\n        -webkit-transform: rotate(-45deg);\n        transform: rotate(-45deg);\n    }\n    5% {\n        -webkit-transform: rotate(-45deg);\n        transform: rotate(-45deg);\n    }\n    12% {\n        -webkit-transform: rotate(-405deg);\n        transform: rotate(-405deg);\n    }\n    100% {\n        -webkit-transform: rotate(-405deg);\n        transform: rotate(-405deg);\n    }\n}\n\n@keyframes rotatePlaceholder {\n    0% {\n        -webkit-transform: rotate(-45deg);\n        transform: rotate(-45deg);\n    }\n    5% {\n        -webkit-transform: rotate(-45deg);\n        transform: rotate(-45deg);\n    }\n    12% {\n        -webkit-transform: rotate(-405deg);\n        transform: rotate(-405deg);\n    }\n    100% {\n        -webkit-transform: rotate(-405deg);\n        transform: rotate(-405deg);\n    }\n}\n\n.animate-success-tip {\n    -webkit-animation: animate-success-tip 0.75s;\n    animation: animate-success-tip 0.75s;\n}\n\n.animate-success-long {\n    -webkit-animation: animate-success-long 0.75s;\n    animation: animate-success-long 0.75s;\n}\n\n.swal2-success.animate::after {\n    -webkit-animation: rotatePlaceholder 4.25s ease-in;\n    animation: rotatePlaceholder 4.25s ease-in;\n}\n\n@-webkit-keyframes animate-error-icon {\n    0% {\n        -webkit-transform: rotateX(100deg);\n        transform: rotateX(100deg);\n        opacity: 0;\n    }\n    100% {\n        -webkit-transform: rotateX(0deg);\n        transform: rotateX(0deg);\n        opacity: 1;\n    }\n}\n\n@keyframes animate-error-icon {\n    0% {\n        -webkit-transform: rotateX(100deg);\n        transform: rotateX(100deg);\n        opacity: 0;\n    }\n    100% {\n        -webkit-transform: rotateX(0deg);\n        transform: rotateX(0deg);\n        opacity: 1;\n    }\n}\n\n.animate-error-icon {\n    -webkit-animation: animate-error-icon 0.5s;\n    animation: animate-error-icon 0.5s;\n}\n\n@-webkit-keyframes animate-x-mark {\n    0% {\n        -webkit-transform: scale(0.4);\n        transform: scale(0.4);\n        margin-top: 26px;\n        opacity: 0;\n    }\n    50% {\n        -webkit-transform: scale(0.4);\n        transform: scale(0.4);\n        margin-top: 26px;\n        opacity: 0;\n    }\n    80% {\n        -webkit-transform: scale(1.15);\n        transform: scale(1.15);\n        margin-top: -6px;\n    }\n    100% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n        margin-top: 0;\n        opacity: 1;\n    }\n}\n\n@keyframes animate-x-mark {\n    0% {\n        -webkit-transform: scale(0.4);\n        transform: scale(0.4);\n        margin-top: 26px;\n        opacity: 0;\n    }\n    50% {\n        -webkit-transform: scale(0.4);\n        transform: scale(0.4);\n        margin-top: 26px;\n        opacity: 0;\n    }\n    80% {\n        -webkit-transform: scale(1.15);\n        transform: scale(1.15);\n        margin-top: -6px;\n    }\n    100% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n        margin-top: 0;\n        opacity: 1;\n    }\n}\n\n.animate-x-mark {\n    -webkit-animation: animate-x-mark 0.5s;\n    animation: animate-x-mark 0.5s;\n}\n\n@-webkit-keyframes pulse-warning {\n    0% {\n        border-color: #f8d486;\n    }\n    100% {\n        border-color: #f8bb86;\n    }\n}\n\n@keyframes pulse-warning {\n    0% {\n        border-color: #f8d486;\n    }\n    100% {\n        border-color: #f8bb86;\n    }\n}\n\n.pulse-warning {\n    -webkit-animation: pulse-warning 0.75s infinite alternate;\n    animation: pulse-warning 0.75s infinite alternate;\n}\n\n@-webkit-keyframes rotate-loading {\n    0% {\n        -webkit-transform: rotate(0deg);\n        transform: rotate(0deg);\n    }\n    100% {\n        -webkit-transform: rotate(360deg);\n        transform: rotate(360deg);\n    }\n}\n\n@keyframes rotate-loading {\n    0% {\n        -webkit-transform: rotate(0deg);\n        transform: rotate(0deg);\n    }\n    100% {\n        -webkit-transform: rotate(360deg);\n        transform: rotate(360deg);\n    }\n}\n\ntable.dataTable {\n    clear: both;\n    margin-top: 6px !important;\n    margin-bottom: 6px !important;\n    max-width: none !important;\n    border-collapse: separate !important;\n}\n\ntable.dataTable td,\ntable.dataTable th {\n    -webkit-box-sizing: content-box;\n    -moz-box-sizing: content-box;\n    box-sizing: content-box;\n}\n\ntable.dataTable td.dataTables_empty,\ntable.dataTable th.dataTables_empty {\n    text-align: center;\n}\n\ntable.dataTable.nowrap th,\ntable.dataTable.nowrap td {\n    white-space: nowrap;\n}\n\ndiv.dataTables_wrapper div.dataTables_length label {\n    font-weight: normal;\n    text-align: left;\n    white-space: nowrap;\n}\n\ndiv.dataTables_wrapper div.dataTables_length select {\n    width: 75px;\n    display: inline-block;\n}\n\ndiv.dataTables_wrapper div.dataTables_filter {\n    text-align: right;\n}\n\ndiv.dataTables_wrapper div.dataTables_filter label {\n    font-weight: normal;\n    white-space: nowrap;\n    text-align: left;\n}\n\ndiv.dataTables_wrapper div.dataTables_filter input {\n    margin-left: 0.5em;\n    display: inline-block;\n    width: auto;\n}\n\ndiv.dataTables_wrapper div.dataTables_info {\n    padding-top: 8px;\n    white-space: nowrap;\n}\n\ndiv.dataTables_wrapper div.dataTables_paginate {\n    margin: 0;\n    white-space: nowrap;\n    text-align: right;\n}\n\ndiv.dataTables_wrapper div.dataTables_paginate ul.pagination {\n    margin: 2px 0;\n    white-space: nowrap;\n}\n\ndiv.dataTables_wrapper div.dataTables_processing {\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    width: 200px;\n    margin-left: -100px;\n    margin-top: -26px;\n    text-align: center;\n    padding: 1em 0;\n}\n\ntable.dataTable thead>tr>th.sorting_asc,\ntable.dataTable thead>tr>th.sorting_desc,\ntable.dataTable thead>tr>th.sorting,\ntable.dataTable thead>tr>td.sorting_asc,\ntable.dataTable thead>tr>td.sorting_desc,\ntable.dataTable thead>tr>td.sorting {\n    padding-right: 30px;\n}\n\ntable.dataTable thead>tr>th:active,\ntable.dataTable thead>tr>td:active {\n    outline: none;\n}\n\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n    cursor: pointer;\n    position: relative;\n}\n\ntable.dataTable thead .sorting:after,\ntable.dataTable thead .sorting_asc:after,\ntable.dataTable thead .sorting_desc:after,\ntable.dataTable thead .sorting_asc_disabled:after,\ntable.dataTable thead .sorting_desc_disabled:after {\n    position: absolute;\n    bottom: 8px;\n    right: 8px;\n    display: block;\n    font-family: 'Glyphicons Halflings';\n    opacity: 0.5;\n}\n\ntable.dataTable thead .sorting:after {\n    opacity: 0.2;\n    content: \"\\e150\";\n    /* sort */\n}\n\ntable.dataTable thead .sorting_asc:after {\n    content: \"\\e155\";\n    /* sort-by-attributes */\n}\n\ntable.dataTable thead .sorting_desc:after {\n    content: \"\\e156\";\n    /* sort-by-attributes-alt */\n}\n\ntable.dataTable thead .sorting_asc_disabled:after,\ntable.dataTable thead .sorting_desc_disabled:after {\n    color: #eee;\n}\n\ndiv.dataTables_scrollHead table.dataTable {\n    margin-bottom: 0 !important;\n}\n\ndiv.dataTables_scrollBody table {\n    border-top: none;\n    margin-top: 0 !important;\n    margin-bottom: 0 !important;\n}\n\ndiv.dataTables_scrollBody table thead .sorting:after,\ndiv.dataTables_scrollBody table thead .sorting_asc:after,\ndiv.dataTables_scrollBody table thead .sorting_desc:after {\n    display: none;\n}\n\ndiv.dataTables_scrollBody table tbody tr:first-child th,\ndiv.dataTables_scrollBody table tbody tr:first-child td {\n    border-top: none;\n}\n\ndiv.dataTables_scrollFoot table {\n    margin-top: 0 !important;\n    border-top: none;\n}\n\n@media screen and (max-width: 767px) {\n    div.dataTables_wrapper div.dataTables_length,\n    div.dataTables_wrapper div.dataTables_filter,\n    div.dataTables_wrapper div.dataTables_info,\n    div.dataTables_wrapper div.dataTables_paginate {\n        text-align: center;\n    }\n}\n\ntable.dataTable.table-condensed>thead>tr>th {\n    padding-right: 20px;\n}\n\ntable.dataTable.table-condensed .sorting:after,\ntable.dataTable.table-condensed .sorting_asc:after,\ntable.dataTable.table-condensed .sorting_desc:after {\n    top: 6px;\n    right: 6px;\n}\n\ntable.table-bordered.dataTable th,\ntable.table-bordered.dataTable td {\n    border-left-width: 0;\n}\n\ntable.table-bordered.dataTable th:last-child,\ntable.table-bordered.dataTable th:last-child,\ntable.table-bordered.dataTable td:last-child,\ntable.table-bordered.dataTable td:last-child {\n    border-right-width: 0;\n}\n\ntable.table-bordered.dataTable tbody th,\ntable.table-bordered.dataTable tbody td {\n    border-bottom-width: 0;\n}\n\ndiv.dataTables_scrollHead table.table-bordered {\n    border-bottom-width: 0;\n}\n\ndiv.table-responsive>div.dataTables_wrapper>div.row {\n    margin: 0;\n}\n\ndiv.table-responsive>div.dataTables_wrapper>div.row>div[class^=\"col-\"]:first-child {\n    padding-left: 0;\n}\n\ndiv.table-responsive>div.dataTables_wrapper>div.row>div[class^=\"col-\"]:last-child {\n    padding-right: 0;\n}\n\ntable.dataTable .btn-simple.btn-icon {\n    padding: 3px;\n}\n\ntable.dataTable thead .sorting:after,\ntable.dataTable thead .sorting_asc:after,\ntable.dataTable thead .sorting_desc:after,\ntable.dataTable thead .sorting_asc_disabled:after,\ntable.dataTable thead .sorting_desc_disabled:after {\n    position: relative;\n    display: inline-block;\n    bottom: 1px;\n    right: -7px;\n    font-family: 'FontAwesome';\n    opacity: 0.8;\n    font-size: 12px;\n}\n\ntable.dataTable thead .disabled-sorting.sorting:after,\ntable.dataTable thead .disabled-sorting.sorting_asc:after,\ntable.dataTable thead .disabled-sorting.sorting_desc:after,\ntable.dataTable thead .disabled-sorting.sorting_asc_disabled:after,\ntable.dataTable thead .disabled-sorting.sorting_desc_disabled:after {\n    display: none;\n}\n\ntable.dataTable thead .sorting:after {\n    opacity: 0.4;\n    content: \"\\f0dc\";\n}\n\ntable.dataTable thead .sorting_asc:after {\n    content: \"\\f0de\";\n    top: 2px;\n}\n\ntable.dataTable thead .sorting_desc:after {\n    content: \"\\f0dd\";\n    top: -3px;\n}\n\ntable.dataTable>thead>tr>th,\ntable.dataTable>tbody>tr>th,\ntable.dataTable>tfoot>tr>th,\ntable.dataTable>thead>tr>td,\ntable.dataTable>tbody>tr>td,\ntable.dataTable>tfoot>tr>td {\n    padding: 5px !important;\n    outline: 0;\n}\n\ntable.dataTable>thead>tr>th {\n    border: none;\n}\n\n.dataTables_paginate a {\n    outline: 0;\n}\n\ntable.dataTable.dtr-inline.collapsed>tbody>tr>td.child,\ntable.dataTable.dtr-inline.collapsed>tbody>tr>th.child,\ntable.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {\n    cursor: default !important;\n}\n\ntable.dataTable.dtr-inline.collapsed>tbody>tr>td.child:before,\ntable.dataTable.dtr-inline.collapsed>tbody>tr>th.child:before,\ntable.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty:before {\n    display: none !important;\n}\n\ntable.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child,\ntable.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child {\n    position: relative;\n    padding-left: 30px;\n    cursor: pointer;\n}\n\ntable.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child:before,\ntable.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child:before {\n    top: 50%;\n    margin-top: -9px;\n    left: 4px;\n    height: 18px;\n    width: 18px;\n    display: block;\n    position: absolute;\n    color: #4caf50;\n    border: 0px solid white;\n    border-radius: 14px;\n    box-shadow: 0 0 3px #444;\n    box-sizing: content-box;\n    text-align: center;\n    font-family: 'Courier New', Courier, monospace;\n    line-height: 18px;\n    content: '+';\n    background-color: #FFF;\n}\n\ntable.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before,\ntable.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before {\n    content: '-';\n    color: #f44336;\n}\n\ntable.dataTable.dtr-inline.collapsed>tbody>tr.child td:before {\n    display: none;\n}\n\ntable.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child,\ntable.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child {\n    padding-left: 27px;\n}\n\ntable.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child:before,\ntable.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child:before {\n    top: 5px;\n    left: 4px;\n    height: 14px;\n    width: 14px;\n    border-radius: 14px;\n    line-height: 14px;\n    text-indent: 3px;\n}\n\ntable.dataTable.dtr-column>tbody>tr>td.control,\ntable.dataTable.dtr-column>tbody>tr>th.control {\n    position: relative;\n    cursor: pointer;\n}\n\ntable.dataTable.dtr-column>tbody>tr>td.control:before,\ntable.dataTable.dtr-column>tbody>tr>th.control:before {\n    top: 50%;\n    left: 50%;\n    height: 16px;\n    width: 16px;\n    margin-top: -10px;\n    margin-left: -10px;\n    display: block;\n    position: absolute;\n    color: white;\n    border: 2px solid white;\n    border-radius: 14px;\n    box-shadow: 0 0 3px #444;\n    box-sizing: content-box;\n    text-align: center;\n    font-family: 'Courier New', Courier, monospace;\n    line-height: 14px;\n    content: '+';\n    background-color: #31b131;\n}\n\ntable.dataTable.dtr-column>tbody>tr.parent td.control:before,\ntable.dataTable.dtr-column>tbody>tr.parent th.control:before {\n    content: '-';\n    background-color: #d33333;\n}\n\ntable.dataTable>tbody>tr.child {\n    padding: 0.5em 1em;\n}\n\ntable.dataTable>tbody>tr.child:hover {\n    background: transparent !important;\n}\n\ntable.dataTable>tbody>tr.child ul {\n    display: inline-block;\n    list-style-type: none;\n    margin: 0;\n    padding: 0;\n}\n\ntable.dataTable>tbody>tr.child ul li {\n    border-bottom: 1px solid #efefef;\n    padding: 0.5em 0;\n}\n\ntable.dataTable>tbody>tr.child ul li:first-child {\n    padding-top: 0;\n}\n\ntable.dataTable>tbody>tr.child ul li:last-child {\n    border-bottom: none;\n}\n\ntable.dataTable>tbody>tr.child span.dtr-title {\n    display: inline-block;\n    min-width: 75px;\n    font-weight: bold;\n}\n\ndiv.dtr-modal {\n    position: fixed;\n    box-sizing: border-box;\n    top: 0;\n    left: 0;\n    height: 100%;\n    width: 100%;\n    z-index: 100;\n    padding: 10em 1em;\n}\n\ndiv.dtr-modal div.dtr-modal-display {\n    position: absolute;\n    top: 0;\n    left: 0;\n    bottom: 0;\n    right: 0;\n    width: 50%;\n    height: 50%;\n    overflow: auto;\n    margin: auto;\n    z-index: 102;\n    overflow: auto;\n    background-color: #f5f5f7;\n    border: 1px solid black;\n    border-radius: 0.5em;\n    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);\n}\n\ndiv.dtr-modal div.dtr-modal-content {\n    position: relative;\n    padding: 1em;\n}\n\ndiv.dtr-modal div.dtr-modal-close {\n    position: absolute;\n    top: 6px;\n    right: 6px;\n    width: 22px;\n    height: 22px;\n    border: 1px solid #eaeaea;\n    background-color: #f9f9f9;\n    text-align: center;\n    border-radius: 3px;\n    cursor: pointer;\n    z-index: 12;\n}\n\ndiv.dtr-modal div.dtr-modal-close:hover {\n    background-color: #eaeaea;\n}\n\ndiv.dtr-modal div.dtr-modal-background {\n    position: fixed;\n    top: 0;\n    left: 0;\n    right: 0;\n    bottom: 0;\n    z-index: 101;\n    background: rgba(0, 0, 0, 0.6);\n}\n\n.material-datatables .input-sm {\n    height: 35px;\n    padding: 0;\n}\n\n@media screen and (max-width: 767px) {\n    div.dtr-modal div.dtr-modal-display {\n        width: 95%;\n    }\n    table.dataTable>tbody>tr>td:first-child {\n        padding-left: 30px !important;\n    }\n}\n\n@media all and (min-width: 520px) and (max-width: 730px) {\n    table.dataTable .btn-simple.btn-icon {\n        display: block;\n        margin: 0;\n    }\n}\n\nsvg {\n    touch-action: none;\n}\n\n.jvectormap-container {\n    width: 100%;\n    height: 100%;\n    position: relative;\n    overflow: hidden;\n    touch-action: none;\n}\n\n.jvectormap-tip {\n    position: absolute;\n    display: none;\n    color: #555555;\n    line-height: 1.5em;\n    background: #FFFFFF;\n    border: none;\n    border-radius: 30px;\n    box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2);\n    padding: 5px 10px;\n    z-index: 1040;\n}\n\n.jvectormap-zoomin,\n.jvectormap-zoomout,\n.jvectormap-goback {\n    position: absolute;\n    left: 10px;\n    border-radius: 3px;\n    background: #292929;\n    padding: 3px;\n    color: white;\n    cursor: pointer;\n    line-height: 10px;\n    text-align: center;\n    box-sizing: content-box;\n}\n\n.jvectormap-zoomin,\n.jvectormap-zoomout {\n    width: 10px;\n    height: 10px;\n}\n\n.jvectormap-zoomin {\n    top: 10px;\n}\n\n.jvectormap-zoomout {\n    top: 30px;\n}\n\n.jvectormap-goback {\n    bottom: 10px;\n    z-index: 1000;\n    padding: 6px;\n}\n\n.jvectormap-spinner {\n    position: absolute;\n    left: 0;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    background: center no-repeat url(data:image/gif;base64,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);\n}\n\n.jvectormap-legend-title {\n    font-weight: bold;\n    font-size: 14px;\n    text-align: center;\n}\n\n.jvectormap-legend-cnt {\n    position: absolute;\n}\n\n.jvectormap-legend-cnt-h {\n    bottom: 0;\n    right: 0;\n}\n\n.jvectormap-legend-cnt-v {\n    top: 0;\n    right: 0;\n}\n\n.jvectormap-legend {\n    background: black;\n    color: white;\n    border-radius: 3px;\n}\n\n.jvectormap-legend-cnt-h .jvectormap-legend {\n    float: left;\n    margin: 0 10px 10px 0;\n    padding: 3px 3px 1px 3px;\n}\n\n.jvectormap-legend-cnt-h .jvectormap-legend .jvectormap-legend-tick {\n    float: left;\n}\n\n.jvectormap-legend-cnt-v .jvectormap-legend {\n    margin: 10px 10px 0 0;\n    padding: 3px;\n}\n\n.jvectormap-legend-cnt-h .jvectormap-legend-tick {\n    width: 40px;\n}\n\n.jvectormap-legend-cnt-h .jvectormap-legend-tick-sample {\n    height: 15px;\n}\n\n.jvectormap-legend-cnt-v .jvectormap-legend-tick-sample {\n    height: 20px;\n    width: 20px;\n    display: inline-block;\n    vertical-align: middle;\n}\n\n.jvectormap-legend-tick-text {\n    font-size: 12px;\n}\n\n.jvectormap-legend-cnt-h .jvectormap-legend-tick-text {\n    text-align: center;\n}\n\n.jvectormap-legend-cnt-v .jvectormap-legend-tick-text {\n    display: inline-block;\n    vertical-align: middle;\n    line-height: 20px;\n    padding-left: 3px;\n}\n\n\n/*!\n * Datetimepicker for Bootstrap 3\n * ! version : 4.7.14\n * https://github.com/Eonasdan/bootstrap-datetimepicker/\n */\n\n.sr-only,\n.bootstrap-datetimepicker-widget .btn[data-action=\"incrementHours\"]::after,\n.bootstrap-datetimepicker-widget .btn[data-action=\"incrementMinutes\"]::after,\n.bootstrap-datetimepicker-widget .btn[data-action=\"decrementHours\"]::after,\n.bootstrap-datetimepicker-widget .btn[data-action=\"decrementMinutes\"]::after,\n.bootstrap-datetimepicker-widget .btn[data-action=\"showHours\"]::after,\n.bootstrap-datetimepicker-widget .btn[data-action=\"showMinutes\"]::after,\n.bootstrap-datetimepicker-widget .btn[data-action=\"togglePeriod\"]::after,\n.bootstrap-datetimepicker-widget .btn[data-action=\"clear\"]::after,\n.bootstrap-datetimepicker-widget .btn[data-action=\"today\"]::after,\n.bootstrap-datetimepicker-widget .picker-switch::after,\n.bootstrap-datetimepicker-widget table th.prev::after,\n.bootstrap-datetimepicker-widget table th.next::after {\n    position: absolute;\n    width: 1px;\n    height: 1px;\n    margin: -1px;\n    padding: 0;\n    overflow: hidden;\n    clip: rect(0, 0, 0, 0);\n    border: 0;\n}\n\n.bootstrap-datetimepicker-widget {\n    list-style: none;\n}\n\n.bootstrap-datetimepicker-widget a .btn:hover {\n    background-color: transparent;\n}\n\n.bootstrap-datetimepicker-widget.dropdown-menu {\n    padding: 4px;\n    width: 19em;\n}\n\n@media (min-width: 768px) {\n    .bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs {\n        width: 38em;\n    }\n}\n\n@media (min-width: 992px) {\n    .bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs {\n        width: 38em;\n    }\n}\n\n@media (min-width: 1200px) {\n    .bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs {\n        width: 38em;\n    }\n}\n\n.bootstrap-datetimepicker-widget.dropdown-menu.bottom:before,\n.bootstrap-datetimepicker-widget.dropdown-menu.bottom:after {\n    right: auto;\n    left: 12px;\n}\n\n.bootstrap-datetimepicker-widget.dropdown-menu.top {\n    margin-top: auto;\n    margin-bottom: -20px;\n}\n\n.bootstrap-datetimepicker-widget.dropdown-menu.top.open {\n    margin-top: auto;\n    margin-bottom: 5px;\n}\n\n.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:before {\n    left: auto;\n    right: 6px;\n}\n\n.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:after {\n    left: auto;\n    right: 7px;\n}\n\n.bootstrap-datetimepicker-widget .list-unstyled {\n    margin: 0;\n}\n\n.bootstrap-datetimepicker-widget a[data-action] {\n    padding: 0;\n    margin: 0;\n    border-width: 0;\n    background-color: transparent;\n    color: #9c27b0;\n    box-shadow: none;\n}\n\n.bootstrap-datetimepicker-widget a[data-action]:hover {\n    background-color: transparent;\n}\n\n.bootstrap-datetimepicker-widget a[data-action]:hover span {\n    background-color: #eeeeee;\n    color: #9c27b0;\n}\n\n.bootstrap-datetimepicker-widget a[data-action]:active {\n    box-shadow: none;\n}\n\n.bootstrap-datetimepicker-widget .timepicker-hour,\n.bootstrap-datetimepicker-widget .timepicker-minute,\n.bootstrap-datetimepicker-widget .timepicker-second {\n    width: 40px;\n    height: 40px;\n    line-height: 40px;\n    font-weight: 300;\n    font-size: 1.3em;\n    margin: 0;\n    border-radius: 50%;\n}\n\n.bootstrap-datetimepicker-widget button[data-action] {\n    width: 38px;\n    height: 38px;\n    margin-right: 3px;\n    padding: 0;\n}\n\n.bootstrap-datetimepicker-widget .btn[data-action=\"incrementHours\"]::after {\n    content: \"Increment Hours\";\n}\n\n.bootstrap-datetimepicker-widget .btn[data-action=\"incrementMinutes\"]::after {\n    content: \"Increment Minutes\";\n}\n\n.bootstrap-datetimepicker-widget .btn[data-action=\"decrementHours\"]::after {\n    content: \"Decrement Hours\";\n}\n\n.bootstrap-datetimepicker-widget .btn[data-action=\"decrementMinutes\"]::after {\n    content: \"Decrement Minutes\";\n}\n\n.bootstrap-datetimepicker-widget .btn[data-action=\"showHours\"]::after {\n    content: \"Show Hours\";\n}\n\n.bootstrap-datetimepicker-widget .btn[data-action=\"showMinutes\"]::after {\n    content: \"Show Minutes\";\n}\n\n.bootstrap-datetimepicker-widget .btn[data-action=\"togglePeriod\"]::after {\n    content: \"Toggle AM/PM\";\n}\n\n.bootstrap-datetimepicker-widget .btn[data-action=\"clear\"]::after {\n    content: \"Clear the picker\";\n}\n\n.bootstrap-datetimepicker-widget .btn[data-action=\"today\"]::after {\n    content: \"Set the date to today\";\n}\n\n.bootstrap-datetimepicker-widget .picker-switch {\n    text-align: center;\n    border-radius: 3px;\n}\n\n.bootstrap-datetimepicker-widget .picker-switch::after {\n    content: \"Toggle Date and Time Screens\";\n}\n\n.bootstrap-datetimepicker-widget .picker-switch td {\n    padding: 0;\n    margin: 0;\n    height: auto;\n    width: auto;\n    line-height: inherit;\n}\n\n.bootstrap-datetimepicker-widget .picker-switch td span {\n    line-height: 2.5;\n    height: 2.5em;\n    width: 100%;\n    border-radius: 3px;\n    margin: 2px 0px !important;\n}\n\n.bootstrap-datetimepicker-widget table {\n    width: 100%;\n    margin: 0;\n}\n\n.bootstrap-datetimepicker-widget table.table-condensed tr>td {\n    text-align: center;\n}\n\n.bootstrap-datetimepicker-widget table td>div,\n.bootstrap-datetimepicker-widget table th>div {\n    text-align: center;\n}\n\n.bootstrap-datetimepicker-widget table th {\n    height: 20px;\n    line-height: 20px;\n    width: 20px;\n    font-weight: 500;\n}\n\n.bootstrap-datetimepicker-widget table th.picker-switch {\n    width: 145px;\n}\n\n.bootstrap-datetimepicker-widget table th.disabled,\n.bootstrap-datetimepicker-widget table th.disabled:hover {\n    background: none;\n    color: #eeeeee;\n    cursor: not-allowed;\n}\n\n.bootstrap-datetimepicker-widget table th.prev span,\n.bootstrap-datetimepicker-widget table th.next span {\n    border-radius: 3px;\n    height: 27px;\n    width: 27px;\n    line-height: 28px;\n    font-size: 12px;\n    border-radius: 50%;\n    text-align: center;\n}\n\n.bootstrap-datetimepicker-widget table th.prev::after {\n    content: \"Previous Month\";\n}\n\n.bootstrap-datetimepicker-widget table th.next::after {\n    content: \"Next Month\";\n}\n\n.bootstrap-datetimepicker-widget table th.dow {\n    text-align: center;\n    border-bottom: 1px solid #eeeeee;\n    font-size: 12px;\n    text-transform: uppercase;\n    color: #333333;\n    font-weight: 400;\n    padding-bottom: 5px;\n    padding-top: 10px;\n}\n\n.bootstrap-datetimepicker-widget table thead tr:first-child th {\n    cursor: pointer;\n}\n\n.bootstrap-datetimepicker-widget table thead tr:first-child th:hover span,\n.bootstrap-datetimepicker-widget table thead tr:first-child th.picker-switch:hover {\n    background: #eeeeee;\n}\n\n.bootstrap-datetimepicker-widget table td>div {\n    border-radius: 3px;\n    height: 54px;\n    line-height: 54px;\n    width: 54px;\n    text-align: center;\n}\n\n.bootstrap-datetimepicker-widget table td.cw>div {\n    font-size: .8em;\n    height: 20px;\n    line-height: 20px;\n    color: #999999;\n}\n\n.bootstrap-datetimepicker-widget table td.day>div {\n    height: 30px;\n    line-height: 30px;\n    width: 30px;\n    text-align: center;\n    padding: 0px;\n    border-radius: 50%;\n    margin: 0 auto;\n    z-index: -1;\n    position: relative;\n}\n\n.bootstrap-datetimepicker-widget table td.minute>div,\n.bootstrap-datetimepicker-widget table td.hour>div {\n    border-radius: 50%;\n}\n\n.bootstrap-datetimepicker-widget table td.day:hover>div,\n.bootstrap-datetimepicker-widget table td.hour:hover>div,\n.bootstrap-datetimepicker-widget table td.minute:hover>div,\n.bootstrap-datetimepicker-widget table td.second:hover>div {\n    background: #eeeeee;\n    cursor: pointer;\n}\n\n.bootstrap-datetimepicker-widget table td.old>div,\n.bootstrap-datetimepicker-widget table td.new>div {\n    color: #999999;\n}\n\n.bootstrap-datetimepicker-widget table td.today>div {\n    position: relative;\n}\n\n.bootstrap-datetimepicker-widget table td.today>div:before {\n    content: '';\n    display: inline-block;\n    border: 0 0 7px 7px solid transparent;\n    border-bottom-color: #9c27b0;\n    border-top-color: rgba(0, 0, 0, 0.2);\n    position: absolute;\n    bottom: 4px;\n    right: 4px;\n}\n\n.bootstrap-datetimepicker-widget table td.active>div,\n.bootstrap-datetimepicker-widget table td.active:hover>div {\n    background-color: #9c27b0;\n    color: #FFFFFF;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(156, 39, 176, 0.4);\n}\n\n.bootstrap-datetimepicker-widget table td.active.today:before>div {\n    border-bottom-color: #FFFFFF;\n}\n\n.bootstrap-datetimepicker-widget table td.disabled>div,\n.bootstrap-datetimepicker-widget table td.disabled:hover>div {\n    background: none;\n    color: #eeeeee;\n    cursor: not-allowed;\n}\n\n.bootstrap-datetimepicker-widget table td span {\n    display: inline-block;\n    width: 40px;\n    height: 40px;\n    line-height: 40px;\n    margin: 3px 3px;\n    cursor: pointer;\n    border-radius: 50%;\n    text-align: center;\n}\n\n.bootstrap-datetimepicker-widget table td span:hover {\n    background: #eeeeee;\n}\n\n.bootstrap-datetimepicker-widget table td span.active {\n    background-color: #9c27b0;\n    color: #FFFFFF;\n}\n\n.bootstrap-datetimepicker-widget table td span.old {\n    color: #999999;\n}\n\n.bootstrap-datetimepicker-widget table td span.disabled,\n.bootstrap-datetimepicker-widget table td span.disabled:hover {\n    background: none;\n    color: #eeeeee;\n    cursor: not-allowed;\n}\n\n.bootstrap-datetimepicker-widget .timepicker-picker span,\n.bootstrap-datetimepicker-widget .timepicker-hours span,\n.bootstrap-datetimepicker-widget .timepicker-minutes span {\n    border-radius: 50% !important;\n}\n\n.bootstrap-datetimepicker-widget.usetwentyfour td.hour {\n    height: 27px;\n    line-height: 27px;\n}\n\n.input-group.date .input-group-addon {\n    cursor: pointer;\n}\n\n.table-condensed>tbody>tr>td,\n.table-condensed>tbody>tr>th,\n.table-condensed>tfoot>tr>td,\n.table-condensed>tfoot>tr>th,\n.table-condensed>thead>tr>td,\n.table-condensed>thead>tr>th {\n    padding: 1px;\n    text-align: center;\n    z-index: 1;\n}\n\n\n/*!\n * FullCalendar v3.0.1 Stylesheet\n * Docs & License: http://fullcalendar.io/\n * (c) 2016 Adam Shaw\n */\n\n.fc {\n    direction: ltr;\n    text-align: left;\n}\n\n.fc-rtl {\n    text-align: right;\n}\n\nbody .fc {\n    /* extra precedence to overcome jqui */\n    font-size: 1em;\n}\n\n\n/* Colors\n--------------------------------------------------------------------------------------------------*/\n\n.fc-unthemed th,\n.fc-unthemed td,\n.fc-unthemed thead,\n.fc-unthemed tbody,\n.fc-unthemed .fc-divider,\n.fc-unthemed .fc-row,\n.fc-unthemed .fc-content,\n.fc-unthemed .fc-popover,\n.fc-unthemed .fc-list-view,\n.fc-unthemed .fc-list-heading td {\n    border-color: #ddd;\n}\n\n.fc-unthemed .fc-popover {\n    background-color: #FFFFFF;\n}\n\n.fc-unthemed .fc-divider,\n.fc-unthemed .fc-popover .fc-header,\n.fc-unthemed .fc-list-heading td {\n    background: #999999;\n}\n\n.fc-unthemed .fc-popover .fc-header .fc-close {\n    color: #999999;\n}\n\n.fc-unthemed .fc-today {\n    background: #f5f5f5;\n}\n\n.fc-highlight {\n    /* when user is selecting cells */\n    background: #bce8f1;\n    opacity: .3;\n}\n\n.fc-bgevent {\n    /* default look for background events */\n    background: #8fdf82;\n    opacity: .3;\n}\n\n.fc-nonbusiness {\n    /* default look for non-business-hours areas */\n    /* will inherit .fc-bgevent's styles */\n    background: #d7d7d7;\n}\n\n\n/* Icons (inline elements with styled text that mock arrow icons)\n--------------------------------------------------------------------------------------------------*/\n\n.fc-icon {\n    display: inline-block;\n    height: 1em;\n    line-height: 1em;\n    font-size: 1em;\n    text-align: center;\n    overflow: hidden;\n    font-family: \"Courier New\", Courier, monospace;\n    /* don't allow browser text-selection */\n    -webkit-touch-callout: none;\n    -webkit-user-select: none;\n    -khtml-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n}\n\n\n/*\nAcceptable font-family overrides for individual icons:\n\t\"Arial\", sans-serif\n\t\"Times New Roman\", serif\n\nNOTE: use percentage font sizes or else old IE chokes\n*/\n\n.fc-icon:after {\n    position: relative;\n}\n\n.fc-icon-left-single-arrow:after {\n    content: \"\\02039\";\n    font-weight: bold;\n    font-size: 200%;\n    top: -7%;\n}\n\n.fc-icon-right-single-arrow:after {\n    content: \"\\0203A\";\n    font-weight: bold;\n    font-size: 200%;\n    top: -7%;\n}\n\n.fc-icon-left-double-arrow:after {\n    content: \"\\000AB\";\n    font-size: 160%;\n    top: -7%;\n}\n\n.fc-icon-right-double-arrow:after {\n    content: \"\\000BB\";\n    font-size: 160%;\n    top: -7%;\n}\n\n.fc-icon-left-triangle:after {\n    content: \"\\25C4\";\n    font-size: 125%;\n    top: 3%;\n}\n\n.fc-icon-right-triangle:after {\n    content: \"\\25BA\";\n    font-size: 125%;\n    top: 3%;\n}\n\n.fc-icon-down-triangle:after {\n    content: \"\\25BC\";\n    font-size: 125%;\n    top: 2%;\n}\n\n.fc-icon-x:after {\n    content: \"\\000D7\";\n    font-size: 200%;\n    top: 6%;\n}\n\n\n/* Buttons (styled <button> tags, normalized to work cross-browser)\n--------------------------------------------------------------------------------------------------*/\n\n.fc button {\n    border: none;\n    border-radius: 30px;\n    position: relative;\n    padding: 6px 12px;\n    font-weight: 400;\n    letter-spacing: 0;\n    will-change: box-shadow, transform;\n    transition: box-shadow 0.2s cubic-bezier(0.4, 0, 1, 1), background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.fc button::-moz-focus-inner {\n    border: 0;\n}\n\n.fc button,\n.fc button.btn-primary {\n    box-shadow: 0 2px 2px 0 rgba(156, 39, 176, 0.14), 0 3px 1px -2px rgba(156, 39, 176, 0.2), 0 1px 5px 0 rgba(156, 39, 176, 0.12);\n}\n\n.fc button,\n.fc button:hover,\n.fc button:focus,\n.fc button:active,\n.fc button.active,\n.fc button:active:focus,\n.fc button:active:hover,\n.fc button.active:focus,\n.fc button.active:hover,\n.open>.fc button.dropdown-toggle,\n.open>.fc button.dropdown-toggle:focus,\n.open>.fc button.dropdown-toggle:hover,\n.fc button.btn-primary,\n.fc button.btn-primary:hover,\n.fc button.btn-primary:focus,\n.fc button.btn-primary:active,\n.fc button.btn-primary.active,\n.fc button.btn-primary:active:focus,\n.fc button.btn-primary:active:hover,\n.fc button.btn-primary.active:focus,\n.fc button.btn-primary.active:hover,\n.open>.fc button.btn-primary.dropdown-toggle,\n.open>.fc button.btn-primary.dropdown-toggle:focus,\n.open>.fc button.btn-primary.dropdown-toggle:hover {\n    background-color: #9c27b0;\n    color: #FFFFFF;\n}\n\n.fc button:focus,\n.fc button:active,\n.fc button:hover,\n.fc button.btn-primary:focus,\n.fc button.btn-primary:active,\n.fc button.btn-primary:hover {\n    box-shadow: 0 14px 26px -12px rgba(156, 39, 176, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(156, 39, 176, 0.2);\n}\n\n.fc button.disabled,\n.fc button.disabled:hover,\n.fc button.disabled:focus,\n.fc button.disabled.focus,\n.fc button.disabled:active,\n.fc button.disabled.active,\n.fc button:disabled,\n.fc button:disabled:hover,\n.fc button:disabled:focus,\n.fc button:disabled.focus,\n.fc button:disabled:active,\n.fc button:disabled.active,\n.fc button[disabled],\n.fc button[disabled]:hover,\n.fc button[disabled]:focus,\n.fc button[disabled].focus,\n.fc button[disabled]:active,\n.fc button[disabled].active,\nfieldset[disabled] .fc button,\nfieldset[disabled] .fc button:hover,\nfieldset[disabled] .fc button:focus,\nfieldset[disabled] .fc button.focus,\nfieldset[disabled] .fc button:active,\nfieldset[disabled] .fc button.active,\n.fc button.btn-primary.disabled,\n.fc button.btn-primary.disabled:hover,\n.fc button.btn-primary.disabled:focus,\n.fc button.btn-primary.disabled.focus,\n.fc button.btn-primary.disabled:active,\n.fc button.btn-primary.disabled.active,\n.fc button.btn-primary:disabled,\n.fc button.btn-primary:disabled:hover,\n.fc button.btn-primary:disabled:focus,\n.fc button.btn-primary:disabled.focus,\n.fc button.btn-primary:disabled:active,\n.fc button.btn-primary:disabled.active,\n.fc button.btn-primary[disabled],\n.fc button.btn-primary[disabled]:hover,\n.fc button.btn-primary[disabled]:focus,\n.fc button.btn-primary[disabled].focus,\n.fc button.btn-primary[disabled]:active,\n.fc button.btn-primary[disabled].active,\nfieldset[disabled] .fc button.btn-primary,\nfieldset[disabled] .fc button.btn-primary:hover,\nfieldset[disabled] .fc button.btn-primary:focus,\nfieldset[disabled] .fc button.btn-primary.focus,\nfieldset[disabled] .fc button.btn-primary:active,\nfieldset[disabled] .fc button.btn-primary.active {\n    box-shadow: none;\n}\n\n.fc button.btn-simple,\n.fc button.btn-primary.btn-simple {\n    background-color: transparent;\n    color: #9c27b0;\n    box-shadow: none;\n}\n\n.fc button.btn-simple:hover,\n.fc button.btn-simple:focus,\n.fc button.btn-simple:active,\n.fc button.btn-primary.btn-simple:hover,\n.fc button.btn-primary.btn-simple:focus,\n.fc button.btn-primary.btn-simple:active {\n    background-color: transparent;\n    color: #9c27b0;\n}\n\n.fc button[disabled],\n.fc button[disabled]:focus,\n.fc button[disabled]:hover {\n    cursor: default;\n    background-color: #999999;\n    border-color: #999999;\n    box-shadow: 0 2px 2px 0 rgba(153, 153, 153, 0.14), 0 3px 1px -2px rgba(153, 153, 153, 0.2), 0 1px 5px 0 rgba(153, 153, 153, 0.12);\n}\n\n.fc-state-default {\n    /* non-theme */\n    border: 1px solid;\n}\n\n\n/*.fc-state-default.fc-corner-left { non-theme\n\tborder-top-left-radius: 4px;\n\tborder-bottom-left-radius: 4px;\n}\n\n.fc-state-default.fc-corner-right { /* non-theme\n\tborder-top-right-radius: 4px;\n\tborder-bottom-right-radius: 4px;\n}*/\n\n\n/* icons in buttons */\n\n.fc button .fc-icon {\n    /* non-theme */\n    position: relative;\n    top: -0.05em;\n    /* seems to be a good adjustment across browsers */\n    margin: 0 .2em;\n    vertical-align: middle;\n}\n\n\n/*\n  button states\n  borrowed from twitter bootstrap (http://twitter.github.com/bootstrap/)\n*/\n\n.fc-state-hover,\n.fc-state-down,\n.fc-state-active,\n.fc-state-disabled {\n    color: #333333;\n    background-color: #e6e6e6;\n}\n\n.fc-state-hover {\n    color: #333333;\n    text-decoration: none;\n    background-position: 0 -15px;\n    -webkit-transition: background-position 0.1s linear;\n    -moz-transition: background-position 0.1s linear;\n    -o-transition: background-position 0.1s linear;\n    transition: background-position 0.1s linear;\n}\n\n.fc-state-down,\n.fc-state-active {\n    background-color: #cccccc;\n    background-image: none;\n    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.fc-state-disabled {\n    cursor: default;\n    background-image: none;\n    opacity: 0.65;\n    box-shadow: none;\n}\n\n\n/* Buttons Groups\n--------------------------------------------------------------------------------------------------*/\n\n.fc-button-group {\n    display: inline-block;\n}\n\n\n/*\nevery button that is not first in a button group should scootch over one pixel and cover the\nprevious button's border...\n*/\n\n.fc .fc-button-group>* {\n    /* extra precedence b/c buttons have margin set to zero */\n    float: left;\n    margin: 0 0 0 2px;\n}\n\n.fc .fc-button-group> :first-child {\n    /* same */\n    margin-left: 0;\n}\n\n\n/* Popover\n--------------------------------------------------------------------------------------------------*/\n\n.fc-popover {\n    position: absolute;\n    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);\n}\n\n.fc-popover .fc-header {\n    /* TODO: be more consistent with fc-head/fc-body */\n    padding: 2px 4px;\n}\n\n.fc-popover .fc-header .fc-title {\n    margin: 0 2px;\n}\n\n.fc-popover .fc-header .fc-close {\n    cursor: pointer;\n}\n\n.fc-ltr .fc-popover .fc-header .fc-title,\n.fc-rtl .fc-popover .fc-header .fc-close {\n    float: left;\n}\n\n.fc-rtl .fc-popover .fc-header .fc-title,\n.fc-ltr .fc-popover .fc-header .fc-close {\n    float: right;\n}\n\n\n/* unthemed */\n\n.fc-unthemed .fc-popover {\n    border-width: 1px;\n    border-style: solid;\n}\n\n.fc-unthemed .fc-popover .fc-header .fc-close {\n    font-size: .9em;\n    margin-top: 2px;\n}\n\n\n/* jqui themed */\n\n.fc-popover>.ui-widget-header+.ui-widget-content {\n    border-top: 0;\n    /* where they meet, let the header have the border */\n}\n\n\n/* Misc Reusable Components\n--------------------------------------------------------------------------------------------------*/\n\n.fc-divider {\n    border-style: solid;\n    border-width: 1px;\n}\n\nhr.fc-divider {\n    height: 0;\n    margin: 0;\n    padding: 0 0 2px;\n    /* height is unreliable across browsers, so use padding */\n    border-width: 1px 0;\n}\n\n.fc-clear {\n    clear: both;\n}\n\n.fc-bg,\n.fc-bgevent-skeleton,\n.fc-highlight-skeleton,\n.fc-helper-skeleton {\n    /* these element should always cling to top-left/right corners */\n    position: absolute;\n    top: 0;\n    left: 0;\n    right: 0;\n}\n\n.fc-bg {\n    bottom: 0;\n    /* strech bg to bottom edge */\n}\n\n.fc-bg table {\n    height: 100%;\n    /* strech bg to bottom edge */\n}\n\n\n/* Tables\n--------------------------------------------------------------------------------------------------*/\n\n.fc table {\n    width: 100%;\n    box-sizing: border-box;\n    /* fix scrollbar issue in firefox */\n    table-layout: fixed;\n    border-collapse: collapse;\n    border-spacing: 0;\n    font-size: 1em;\n    /* normalize cross-browser */\n}\n\n.fc th {\n    text-align: center;\n}\n\n.fc th,\n.fc td {\n    border-style: solid;\n    border-width: 1px;\n    padding: 0;\n    vertical-align: top;\n}\n\n.fc td.fc-today {\n    border-style: double;\n    /* overcome neighboring borders */\n}\n\n\n/* Internal Nav Links\n--------------------------------------------------------------------------------------------------*/\n\na[data-goto] {\n    cursor: pointer;\n}\n\na[data-goto]:hover {\n    text-decoration: underline;\n}\n\n\n/* Fake Table Rows\n--------------------------------------------------------------------------------------------------*/\n\n.fc .fc-row {\n    /* extra precedence to overcome themes w/ .ui-widget-content forcing a 1px border */\n    /* no visible border by default. but make available if need be (scrollbar width compensation) */\n    border-style: solid;\n    border-width: 0;\n}\n\n.fc-row table {\n    /* don't put left/right border on anything within a fake row.\n     the outer tbody will worry about this */\n    border-left: 0 hidden transparent;\n    border-right: 0 hidden transparent;\n    /* no bottom borders on rows */\n    border-bottom: 0 hidden transparent;\n}\n\n.fc-row:first-child table {\n    border-top: 0 hidden transparent;\n    /* no top border on first row */\n}\n\n\n/* Day Row (used within the header and the DayGrid)\n--------------------------------------------------------------------------------------------------*/\n\n.fc-row {\n    position: relative;\n}\n\n.fc-row .fc-bg {\n    z-index: 1;\n}\n\n\n/* highlighting cells & background event skeleton */\n\n.fc-row .fc-bgevent-skeleton,\n.fc-row .fc-highlight-skeleton {\n    bottom: 0;\n    /* stretch skeleton to bottom of row */\n}\n\n.fc-row .fc-bgevent-skeleton table,\n.fc-row .fc-highlight-skeleton table {\n    height: 100%;\n    /* stretch skeleton to bottom of row */\n}\n\n.fc-row .fc-highlight-skeleton td,\n.fc-row .fc-bgevent-skeleton td {\n    border-color: transparent;\n}\n\n.fc-row .fc-bgevent-skeleton {\n    z-index: 2;\n}\n\n.fc-row .fc-highlight-skeleton {\n    z-index: 3;\n}\n\n\n/*\nrow content (which contains day/week numbers and events) as well as \"helper\" (which contains\ntemporary rendered events).\n*/\n\n.fc-row .fc-content-skeleton {\n    position: relative;\n    z-index: 4;\n    padding-bottom: 2px;\n    /* matches the space above the events */\n}\n\n.fc-row .fc-helper-skeleton {\n    z-index: 5;\n}\n\n.fc-row .fc-content-skeleton td,\n.fc-row .fc-helper-skeleton td {\n    /* see-through to the background below */\n    background: none;\n    /* in case <td>s are globally styled */\n    border-color: transparent;\n    /* don't put a border between events and/or the day number */\n    border-bottom: 0;\n}\n\n.fc-row .fc-content-skeleton tbody td,\n.fc-row .fc-helper-skeleton tbody td {\n    /* don't put a border between event cells */\n    border-top: 0;\n}\n\n\n/* Scrolling Container\n--------------------------------------------------------------------------------------------------*/\n\n.fc-scroller {\n    -webkit-overflow-scrolling: touch;\n}\n\n\n/* TODO: move to agenda/basic */\n\n.fc-scroller>.fc-day-grid,\n.fc-scroller>.fc-time-grid {\n    position: relative;\n    /* re-scope all positions */\n    width: 100%;\n    /* hack to force re-sizing this inner element when scrollbars appear/disappear */\n}\n\n\n/* Global Event Styles\n--------------------------------------------------------------------------------------------------*/\n\n.fc-event {\n    position: relative;\n    /* for resize handle and other inner positioning */\n    display: block;\n    /* make the <a> tag block */\n    font-size: .85em;\n    line-height: 1.3;\n    border-radius: 2px;\n    background-color: #4caf50;\n    /* default BACKGROUND color */\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(76, 175, 80, 0.4);\n    font-weight: normal;\n    /* undo jqui's ui-widget-header bold */\n}\n\n.fc-event.event-azure {\n    background-color: #00bcd4;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(0, 188, 212, 0.4);\n}\n\n.fc-event.event-green {\n    background-color: #4caf50;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(76, 175, 80, 0.4);\n}\n\n.fc-event.event-orange {\n    background-color: #ff9800;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 152, 0, 0.4);\n}\n\n.fc-event.event-red {\n    background-color: #f44336;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(244, 67, 54, 0.4);\n}\n\n.fc-event.event-rose {\n    background-color: #e91e63;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(233, 30, 99, 0.4);\n}\n\n.fc-event.event-default {\n    background-color: #999999;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(153, 153, 153, 0.4);\n}\n\n.fc-event-dot {\n    background-color: #3a87ad;\n    /* default BACKGROUND color */\n}\n\n\n/* overpower some of bootstrap's and jqui's styles on <a> tags */\n\n.fc-event,\n.fc-event:hover,\n.ui-widget .fc-event {\n    color: #FFFFFF;\n    /* default TEXT color */\n    text-decoration: none;\n    /* if <a> has an href */\n}\n\n.fc-event[href],\n.fc-event.fc-draggable {\n    cursor: pointer;\n    /* give events with links and draggable events a hand mouse pointer */\n}\n\n.fc-not-allowed,\n.fc-not-allowed .fc-event {\n    /* to override an event's custom cursor */\n    cursor: not-allowed;\n}\n\n.fc-event .fc-bg {\n    /* the generic .fc-bg already does position */\n    z-index: 1;\n    background: #FFFFFF;\n    opacity: .25;\n}\n\n.fc-event .fc-content {\n    position: relative;\n    z-index: 2;\n}\n\n\n/* resizer (cursor AND touch devices) */\n\n.fc-event .fc-resizer {\n    position: absolute;\n    z-index: 4;\n}\n\n\n/* resizer (touch devices) */\n\n.fc-event .fc-resizer {\n    display: none;\n}\n\n.fc-event.fc-allow-mouse-resize .fc-resizer,\n.fc-event.fc-selected .fc-resizer {\n    /* only show when hovering or selected (with touch) */\n    display: block;\n}\n\n\n/* hit area */\n\n.fc-event.fc-selected .fc-resizer:before {\n    /* 40x40 touch area */\n    content: \"\";\n    position: absolute;\n    z-index: 9999;\n    /* user of this util can scope within a lower z-index */\n    top: 50%;\n    left: 50%;\n    width: 40px;\n    height: 40px;\n    margin-left: -20px;\n    margin-top: -20px;\n}\n\n\n/* Event Selection (only for touch devices)\n--------------------------------------------------------------------------------------------------*/\n\n.fc-event.fc-selected {\n    z-index: 9999 !important;\n    /* overcomes inline z-index */\n    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);\n}\n\n.fc-event.fc-selected.fc-dragging {\n    box-shadow: 0 2px 7px rgba(0, 0, 0, 0.3);\n}\n\n\n/* Horizontal Events\n--------------------------------------------------------------------------------------------------*/\n\n\n/* bigger touch area when selected */\n\n.fc-h-event.fc-selected:before {\n    content: \"\";\n    position: absolute;\n    z-index: 3;\n    /* below resizers */\n    top: -10px;\n    bottom: -10px;\n    left: 0;\n    right: 0;\n}\n\n\n/* events that are continuing to/from another week. kill rounded corners and butt up against edge */\n\n.fc-ltr .fc-h-event.fc-not-start,\n.fc-rtl .fc-h-event.fc-not-end {\n    margin-left: 0;\n    border-left-width: 0;\n    padding-left: 1px;\n    /* replace the border with padding */\n    border-top-left-radius: 0;\n    border-bottom-left-radius: 0;\n}\n\n.fc-ltr .fc-h-event.fc-not-end,\n.fc-rtl .fc-h-event.fc-not-start {\n    margin-right: 0;\n    border-right-width: 0;\n    padding-right: 1px;\n    /* replace the border with padding */\n    border-top-right-radius: 0;\n    border-bottom-right-radius: 0;\n}\n\n\n/* resizer (cursor AND touch devices) */\n\n\n/* left resizer  */\n\n.fc-ltr .fc-h-event .fc-start-resizer,\n.fc-rtl .fc-h-event .fc-end-resizer {\n    cursor: w-resize;\n    left: -1px;\n    /* overcome border */\n}\n\n\n/* right resizer */\n\n.fc-ltr .fc-h-event .fc-end-resizer,\n.fc-rtl .fc-h-event .fc-start-resizer {\n    cursor: e-resize;\n    right: -1px;\n    /* overcome border */\n}\n\n\n/* resizer (mouse devices) */\n\n.fc-h-event.fc-allow-mouse-resize .fc-resizer {\n    width: 7px;\n    top: -1px;\n    /* overcome top border */\n    bottom: -1px;\n    /* overcome bottom border */\n}\n\n\n/* resizer (touch devices) */\n\n.fc-h-event.fc-selected .fc-resizer {\n    /* 8x8 little dot */\n    border-radius: 4px;\n    border-width: 1px;\n    width: 6px;\n    height: 6px;\n    border-style: solid;\n    border-color: inherit;\n    background: #fff;\n    /* vertically center */\n    top: 50%;\n    margin-top: -4px;\n}\n\n\n/* left resizer  */\n\n.fc-ltr .fc-h-event.fc-selected .fc-start-resizer,\n.fc-rtl .fc-h-event.fc-selected .fc-end-resizer {\n    margin-left: -4px;\n    /* centers the 8x8 dot on the left edge */\n}\n\n\n/* right resizer */\n\n.fc-ltr .fc-h-event.fc-selected .fc-end-resizer,\n.fc-rtl .fc-h-event.fc-selected .fc-start-resizer {\n    margin-right: -4px;\n    /* centers the 8x8 dot on the right edge */\n}\n\n\n/* DayGrid events\n----------------------------------------------------------------------------------------------------\nWe use the full \"fc-day-grid-event\" class instead of using descendants because the event won't\nbe a descendant of the grid when it is being dragged.\n*/\n\n.fc-day-grid-event {\n    margin: 2px 5px 0;\n    /* spacing between events and edges */\n    padding: 0 1px;\n}\n\ntr:first-child>td>.fc-day-grid-event {\n    margin-top: 2px;\n    /* a little bit more space before the first event */\n}\n\n.fc-day-grid-event.fc-selected:after {\n    content: \"\";\n    position: absolute;\n    z-index: 1;\n    /* same z-index as fc-bg, behind text */\n    /* overcome the borders */\n    top: -1px;\n    right: -1px;\n    bottom: -1px;\n    left: -1px;\n    /* darkening effect */\n    background: #000;\n    opacity: .25;\n}\n\n.fc-day-grid-event .fc-content {\n    /* force events to be one-line tall */\n    white-space: nowrap;\n    overflow: hidden;\n}\n\n.fc-day-grid-event .fc-time {\n    font-weight: bold;\n}\n\n\n/* resizer (cursor devices) */\n\n\n/* left resizer  */\n\n.fc-ltr .fc-day-grid-event.fc-allow-mouse-resize .fc-start-resizer,\n.fc-rtl .fc-day-grid-event.fc-allow-mouse-resize .fc-end-resizer {\n    margin-left: -2px;\n    /* to the day cell's edge */\n}\n\n\n/* right resizer */\n\n.fc-ltr .fc-day-grid-event.fc-allow-mouse-resize .fc-end-resizer,\n.fc-rtl .fc-day-grid-event.fc-allow-mouse-resize .fc-start-resizer {\n    margin-right: -2px;\n    /* to the day cell's edge */\n}\n\n\n/* Event Limiting\n--------------------------------------------------------------------------------------------------*/\n\n\n/* \"more\" link that represents hidden events */\n\na.fc-more {\n    margin: 1px 3px;\n    font-size: .85em;\n    cursor: pointer;\n    text-decoration: none;\n}\n\na.fc-more:hover {\n    text-decoration: underline;\n}\n\n.fc-limited {\n    /* rows and cells that are hidden because of a \"more\" link */\n    display: none;\n}\n\n\n/* popover that appears when \"more\" link is clicked */\n\n.fc-day-grid .fc-row {\n    z-index: 1;\n    /* make the \"more\" popover one higher than this */\n}\n\n.fc-more-popover {\n    z-index: 2;\n    width: 220px;\n}\n\n.fc-more-popover .fc-event-container {\n    padding: 10px;\n}\n\n\n/* Now Indicator\n--------------------------------------------------------------------------------------------------*/\n\n.fc-now-indicator {\n    position: absolute;\n    border: 0 solid red;\n}\n\n\n/* Utilities\n--------------------------------------------------------------------------------------------------*/\n\n.fc-unselectable {\n    -webkit-user-select: none;\n    -khtml-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n    -webkit-touch-callout: none;\n    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\n\n/* Toolbar\n--------------------------------------------------------------------------------------------------*/\n\n.fc-toolbar {\n    text-align: center;\n    margin-bottom: 1em;\n}\n\n.fc-toolbar .fc-left {\n    float: left;\n}\n\n.fc-toolbar .fc-right {\n    float: right;\n}\n\n.fc-toolbar .fc-center {\n    display: inline-block;\n}\n\n\n/* the things within each left/right/center section */\n\n.fc .fc-toolbar>*>* {\n    /* extra precedence to override button border margins */\n    float: left;\n    margin-left: .75em;\n}\n\n\n/* the first thing within each left/center/right section */\n\n.fc .fc-toolbar>*> :first-child {\n    /* extra precedence to override button border margins */\n    margin-left: 0;\n}\n\n\n/* title text */\n\n.fc-toolbar h2 {\n    margin: 0;\n    font-size: 1.8em;\n}\n\n\n/* button layering (for border precedence) */\n\n.fc-toolbar button {\n    position: relative;\n}\n\n.fc-toolbar .fc-state-hover,\n.fc-toolbar .ui-state-hover {\n    z-index: 2;\n}\n\n.fc-toolbar .fc-state-down {\n    z-index: 3;\n}\n\n.fc-toolbar .fc-state-active,\n.fc-toolbar .ui-state-active {\n    z-index: 4;\n}\n\n.fc-toolbar button:focus {\n    z-index: 5;\n}\n\n\n/* View Structure\n--------------------------------------------------------------------------------------------------*/\n\n\n/* undo twitter bootstrap's box-sizing rules. normalizes positioning techniques */\n\n\n/* don't do this for the toolbar because we'll want bootstrap to style those buttons as some pt */\n\n.fc-view-container *,\n.fc-view-container *:before,\n.fc-view-container *:after {\n    -webkit-box-sizing: content-box;\n    -moz-box-sizing: content-box;\n    box-sizing: content-box;\n}\n\n.fc-view,\n.fc-view>table {\n    /* so dragged elements can be above the view's main element */\n    position: relative;\n    z-index: 1;\n}\n\n\n/* BasicView\n--------------------------------------------------------------------------------------------------*/\n\n\n/* day row structure */\n\n.fc-basicWeek-view .fc-content-skeleton,\n.fc-basicDay-view .fc-content-skeleton {\n    /* there may be week numbers in these views, so no padding-top */\n    padding-bottom: 1em;\n    /* ensure a space at bottom of cell for user selecting/clicking */\n}\n\n.fc-basic-view .fc-body .fc-row {\n    min-height: 4em;\n    /* ensure that all rows are at least this tall */\n}\n\n\n/* a \"rigid\" row will take up a constant amount of height because content-skeleton is absolute */\n\n.fc-row.fc-rigid {\n    overflow: hidden;\n}\n\n.fc-row.fc-rigid .fc-content-skeleton {\n    position: absolute;\n    top: 0;\n    left: 0;\n    right: 0;\n}\n\n\n/* week and day number styling */\n\n.fc-day-top.fc-other-month {\n    opacity: 0.3;\n}\n\n.fc-basic-view .fc-week-number,\n.fc-basic-view .fc-day-number {\n    padding: 2px;\n}\n\n.fc-basic-view th.fc-week-number,\n.fc-basic-view th.fc-day-number {\n    padding: 0 2px;\n    /* column headers can't have as much v space */\n}\n\n.fc-ltr .fc-basic-view .fc-day-top .fc-day-number {\n    float: right;\n}\n\n.fc-rtl .fc-basic-view .fc-day-top .fc-day-number {\n    float: left;\n}\n\n.fc-ltr .fc-basic-view .fc-day-top .fc-week-number {\n    float: left;\n    border-radius: 0 0 3px 0;\n}\n\n.fc-rtl .fc-basic-view .fc-day-top .fc-week-number {\n    float: right;\n    border-radius: 0 0 0 3px;\n}\n\n.fc-basic-view .fc-day-top .fc-week-number {\n    min-width: 1.5em;\n    text-align: center;\n    background-color: #f2f2f2;\n    color: #808080;\n}\n\n\n/* when week/day number have own column */\n\n.fc-basic-view td.fc-week-number {\n    text-align: center;\n}\n\n.fc-basic-view td.fc-week-number>* {\n    /* work around the way we do column resizing and ensure a minimum width */\n    display: inline-block;\n    min-width: 1.25em;\n}\n\n\n/* AgendaView all-day area\n--------------------------------------------------------------------------------------------------*/\n\n.fc-agenda-view .fc-day-grid {\n    position: relative;\n    z-index: 2;\n    /* so the \"more..\" popover will be over the time grid */\n}\n\n.fc-agenda-view .fc-day-grid .fc-row {\n    min-height: 3em;\n    /* all-day section will never get shorter than this */\n}\n\n.fc-agenda-view .fc-day-grid .fc-row .fc-content-skeleton {\n    padding-bottom: 1em;\n    /* give space underneath events for clicking/selecting days */\n}\n\n\n/* TimeGrid axis running down the side (for both the all-day area and the slot area)\n--------------------------------------------------------------------------------------------------*/\n\n.fc .fc-axis {\n    /* .fc to overcome default cell styles */\n    vertical-align: middle;\n    padding: 0 4px;\n    white-space: nowrap;\n}\n\n.fc-ltr .fc-axis {\n    text-align: right;\n}\n\n.fc-rtl .fc-axis {\n    text-align: left;\n}\n\n.ui-widget td.fc-axis {\n    font-weight: normal;\n    /* overcome jqui theme making it bold */\n}\n\n\n/* TimeGrid Structure\n--------------------------------------------------------------------------------------------------*/\n\n.fc-time-grid-container,\n.fc-time-grid {\n    /* so slats/bg/content/etc positions get scoped within here */\n    position: relative;\n    z-index: 1;\n}\n\n.fc-time-grid {\n    min-height: 100%;\n    /* so if height setting is 'auto', .fc-bg stretches to fill height */\n}\n\n.fc-time-grid table {\n    /* don't put outer borders on slats/bg/content/etc */\n    border: 0 hidden transparent;\n}\n\n.fc-time-grid>.fc-bg {\n    z-index: 1;\n}\n\n.fc-time-grid .fc-slats,\n.fc-time-grid>hr {\n    /* the <hr> AgendaView injects when grid is shorter than scroller */\n    position: relative;\n    z-index: 2;\n}\n\n.fc-time-grid .fc-content-col {\n    position: relative;\n    /* because now-indicator lives directly inside */\n}\n\n.fc-time-grid .fc-content-skeleton {\n    position: absolute;\n    z-index: 3;\n    top: 0;\n    left: 0;\n    right: 0;\n}\n\n\n/* divs within a cell within the fc-content-skeleton */\n\n.fc-time-grid .fc-business-container {\n    position: relative;\n    z-index: 1;\n}\n\n.fc-time-grid .fc-bgevent-container {\n    position: relative;\n    z-index: 2;\n}\n\n.fc-time-grid .fc-highlight-container {\n    position: relative;\n    z-index: 3;\n}\n\n.fc-time-grid .fc-event-container {\n    position: relative;\n    z-index: 4;\n}\n\n.fc-time-grid .fc-now-indicator-line {\n    z-index: 5;\n}\n\n.fc-time-grid .fc-helper-container {\n    /* also is fc-event-container */\n    position: relative;\n    z-index: 6;\n}\n\n\n/* TimeGrid Slats (lines that run horizontally)\n--------------------------------------------------------------------------------------------------*/\n\n.fc-time-grid .fc-slats td {\n    height: 1.5em;\n    border-bottom: 0;\n    /* each cell is responsible for its top border */\n}\n\n.fc-time-grid .fc-slats .fc-minor td {\n    border-top-style: dotted;\n}\n\n.fc-time-grid .fc-slats .ui-widget-content {\n    /* for jqui theme */\n    background: none;\n    /* see through to fc-bg */\n}\n\n\n/* TimeGrid Highlighting Slots\n--------------------------------------------------------------------------------------------------*/\n\n.fc-time-grid .fc-highlight-container {\n    /* a div within a cell within the fc-highlight-skeleton */\n    position: relative;\n    /* scopes the left/right of the fc-highlight to be in the column */\n}\n\n.fc-time-grid .fc-highlight {\n    position: absolute;\n    left: 0;\n    right: 0;\n    /* top and bottom will be in by JS */\n}\n\n\n/* TimeGrid Event Containment\n--------------------------------------------------------------------------------------------------*/\n\n.fc-ltr .fc-time-grid .fc-event-container {\n    /* space on the sides of events for LTR (default) */\n    margin: 0 2.5% 0 2px;\n}\n\n.fc-rtl .fc-time-grid .fc-event-container {\n    /* space on the sides of events for RTL */\n    margin: 0 2px 0 2.5%;\n}\n\n.fc-time-grid .fc-event,\n.fc-time-grid .fc-bgevent {\n    position: absolute;\n    z-index: 1;\n    /* scope inner z-index's */\n}\n\n.fc-time-grid .fc-bgevent {\n    /* background events always span full width */\n    left: 0;\n    right: 0;\n}\n\n\n/* Generic Vertical Event\n--------------------------------------------------------------------------------------------------*/\n\n.fc-v-event.fc-not-start {\n    /* events that are continuing from another day */\n    /* replace space made by the top border with padding */\n    border-top-width: 0;\n    padding-top: 1px;\n    /* remove top rounded corners */\n    border-top-left-radius: 0;\n    border-top-right-radius: 0;\n}\n\n.fc-v-event.fc-not-end {\n    /* replace space made by the top border with padding */\n    border-bottom-width: 0;\n    padding-bottom: 1px;\n    /* remove bottom rounded corners */\n    border-bottom-left-radius: 0;\n    border-bottom-right-radius: 0;\n}\n\n\n/* TimeGrid Event Styling\n----------------------------------------------------------------------------------------------------\nWe use the full \"fc-time-grid-event\" class instead of using descendants because the event won't\nbe a descendant of the grid when it is being dragged.\n*/\n\n.fc-time-grid-event {\n    overflow: hidden;\n    /* don't let the bg flow over rounded corners */\n}\n\n.fc-time-grid-event.fc-selected {\n    /* need to allow touch resizers to extend outside event's bounding box */\n    /* common fc-selected styles hide the fc-bg, so don't need this anyway */\n    overflow: visible;\n}\n\n.fc-time-grid-event.fc-selected .fc-bg {\n    display: none;\n    /* hide semi-white background, to appear darker */\n}\n\n.fc-time-grid-event .fc-content {\n    overflow: hidden;\n    /* for when .fc-selected */\n}\n\n.fc-time-grid-event .fc-time,\n.fc-time-grid-event .fc-title {\n    padding: 0 1px;\n}\n\n.fc-time-grid-event .fc-time {\n    font-size: .85em;\n    white-space: nowrap;\n}\n\n\n/* short mode, where time and title are on the same line */\n\n.fc-time-grid-event.fc-short .fc-content {\n    /* don't wrap to second line (now that contents will be inline) */\n    white-space: nowrap;\n}\n\n.fc-time-grid-event.fc-short .fc-time,\n.fc-time-grid-event.fc-short .fc-title {\n    /* put the time and title on the same line */\n    display: inline-block;\n    vertical-align: top;\n}\n\n.fc-time-grid-event.fc-short .fc-time span {\n    display: none;\n    /* don't display the full time text... */\n}\n\n.fc-time-grid-event.fc-short .fc-time:before {\n    content: attr(data-start);\n    /* ...instead, display only the start time */\n}\n\n.fc-time-grid-event.fc-short .fc-time:after {\n    content: \"\\000A0-\\000A0\";\n    /* seperate with a dash, wrapped in nbsp's */\n}\n\n.fc-time-grid-event.fc-short .fc-title {\n    font-size: .85em;\n    /* make the title text the same size as the time */\n    padding: 0;\n    /* undo padding from above */\n}\n\n\n/* resizer (cursor device) */\n\n.fc-time-grid-event.fc-allow-mouse-resize .fc-resizer {\n    left: 0;\n    right: 0;\n    bottom: 0;\n    height: 8px;\n    overflow: hidden;\n    line-height: 8px;\n    font-size: 11px;\n    font-family: monospace;\n    text-align: center;\n    cursor: s-resize;\n}\n\n.fc-time-grid-event.fc-allow-mouse-resize .fc-resizer:after {\n    content: \"=\";\n}\n\n\n/* resizer (touch device) */\n\n.fc-time-grid-event.fc-selected .fc-resizer {\n    /* 10x10 dot */\n    border-radius: 5px;\n    border-width: 1px;\n    width: 8px;\n    height: 8px;\n    border-style: solid;\n    border-color: inherit;\n    background: #fff;\n    /* horizontally center */\n    left: 50%;\n    margin-left: -5px;\n    /* center on the bottom edge */\n    bottom: -5px;\n}\n\n\n/* Now Indicator\n--------------------------------------------------------------------------------------------------*/\n\n.fc-time-grid .fc-now-indicator-line {\n    border-top-width: 1px;\n    left: 0;\n    right: 0;\n}\n\n\n/* arrow on axis */\n\n.fc-time-grid .fc-now-indicator-arrow {\n    margin-top: -5px;\n    /* vertically center on top coordinate */\n}\n\n.fc-ltr .fc-time-grid .fc-now-indicator-arrow {\n    left: 0;\n    /* triangle pointing right... */\n    border-width: 5px 0 5px 6px;\n    border-top-color: transparent;\n    border-bottom-color: transparent;\n}\n\n.fc-rtl .fc-time-grid .fc-now-indicator-arrow {\n    right: 0;\n    /* triangle pointing left... */\n    border-width: 5px 6px 5px 0;\n    border-top-color: transparent;\n    border-bottom-color: transparent;\n}\n\n\n/* List View\n--------------------------------------------------------------------------------------------------*/\n\n\n/* possibly reusable */\n\n.fc-event-dot {\n    display: inline-block;\n    width: 10px;\n    height: 10px;\n    border-radius: 5px;\n}\n\n\n/* view wrapper */\n\n.fc-rtl .fc-list-view {\n    direction: rtl;\n    /* unlike core views, leverage browser RTL */\n}\n\n.fc-list-view {\n    border-width: 1px;\n    border-style: solid;\n}\n\n\n/* table resets */\n\n.fc .fc-list-table {\n    table-layout: auto;\n    /* for shrinkwrapping cell content */\n}\n\n.fc-list-table td {\n    border-width: 1px 0 0;\n    padding: 8px 14px;\n}\n\n.fc-list-table tr:first-child td {\n    border-top-width: 0;\n}\n\n\n/* day headings with the list */\n\n.fc-list-heading {\n    border-bottom-width: 1px;\n}\n\n.fc-list-heading td {\n    font-weight: bold;\n}\n\n.fc-ltr .fc-list-heading-main {\n    float: left;\n}\n\n.fc-ltr .fc-list-heading-alt {\n    float: right;\n}\n\n.fc-rtl .fc-list-heading-main {\n    float: right;\n}\n\n.fc-rtl .fc-list-heading-alt {\n    float: left;\n}\n\n\n/* event list items */\n\n.fc-list-item.fc-has-url {\n    cursor: pointer;\n    /* whole row will be clickable */\n}\n\n.fc-list-item:hover td {\n    background-color: #f5f5f5;\n}\n\n.fc-list-item-marker,\n.fc-list-item-time {\n    white-space: nowrap;\n    width: 1px;\n}\n\n\n/* make the dot closer to the event title */\n\n.fc-ltr .fc-list-item-marker {\n    padding-right: 0;\n}\n\n.fc-rtl .fc-list-item-marker {\n    padding-left: 0;\n}\n\n.fc-list-item-title a {\n    /* every event title cell has an <a> tag */\n    text-decoration: none;\n    color: inherit;\n}\n\n.fc-list-item-title a[href]:hover {\n    /* hover effect only on titles with hrefs */\n    text-decoration: underline;\n}\n\n\n/* message when no events */\n\n.fc-list-empty-wrap2 {\n    position: absolute;\n    top: 0;\n    left: 0;\n    right: 0;\n    bottom: 0;\n}\n\n.fc-list-empty-wrap1 {\n    width: 100%;\n    height: 100%;\n    display: table;\n}\n\n.fc-list-empty {\n    display: table-cell;\n    vertical-align: middle;\n    text-align: center;\n}\n\n.fc-unthemed .fc-list-empty {\n    /* theme will provide own background */\n    background-color: #eee;\n}\n\n.card-calendar table td {\n    text-align: right;\n}\n\n.card-calendar .content {\n    padding: 0 !important;\n}\n\n.card-calendar .fc-toolbar {\n    padding-top: 20px;\n    padding-left: 20px;\n    padding-right: 20px;\n}\n\n.card-calendar .fc td:first-child {\n    border-left: 0;\n}\n\n.card-calendar .fc td:last-child {\n    border-right: 0;\n}\n\n.card-calendar .fc-basic-view td:last-child.fc-week-number span,\n.card-calendar .fc-basic-view td:last-child.fc-day-number {\n    padding-right: 20px;\n}\n\n.card-calendar .fc .fc-day-header:last-child {\n    padding-right: 15px;\n}\n\n.card-calendar .fc .fc-widget-header {\n    border: 0;\n}\n\n.card-calendar .fc .fc-widget-header .fc-title {\n    color: #FFFFFF;\n}\n\n.card-calendar .fc th {\n    text-align: right;\n    color: #999999;\n}\n\n.card-calendar .title {\n    margin-top: -9px;\n}\n\n.card-calendar .fc .fc-row:last-child td {\n    border-bottom: 0;\n}\n\n.card-calendar .fc .fc-body .fc-widget-content {\n    border-bottom: 0;\n}\n\n.wizard-card {\n    min-height: 410px;\n    box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2);\n    opacity: 0;\n    -webkit-transition: all 300ms linear;\n    -moz-transition: all 300ms linear;\n    -o-transition: all 300ms linear;\n    -ms-transition: all 300ms linear;\n    transition: all 300ms linear;\n}\n\n.wizard-card.active {\n    opacity: 1;\n}\n\n.wizard-card .picture-container {\n    position: relative;\n    cursor: pointer;\n    text-align: center;\n}\n\n.wizard-card .wizard-navigation {\n    position: relative;\n}\n\n.wizard-card .picture {\n    width: 106px;\n    height: 106px;\n    background-color: #999999;\n    border: 4px solid #CCCCCC;\n    color: #FFFFFF;\n    border-radius: 50%;\n    margin: 5px auto;\n    overflow: hidden;\n    transition: all 0.2s;\n    -webkit-transition: all 0.2s;\n}\n\n.wizard-card .picture:hover {\n    border-color: #2ca8ff;\n}\n\n.wizard-card .moving-tab {\n    position: absolute;\n    text-align: center;\n    padding: 12px;\n    font-size: 12px;\n    text-transform: uppercase;\n    -webkit-font-smoothing: subpixel-antialiased;\n    top: -4px;\n    left: 0px;\n    border-radius: 4px;\n    color: #FFFFFF;\n    cursor: pointer;\n    font-weight: 500;\n}\n\n.wizard-card[data-color=\"purple\"] .moving-tab {\n    background-color: #9c27b0;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(156, 39, 176, 0.4);\n}\n\n.wizard-card[data-color=\"purple\"] .picture:hover {\n    border-color: #9c27b0;\n}\n\n.wizard-card[data-color=\"purple\"] .choice:hover .icon,\n.wizard-card[data-color=\"purple\"] .choice.active .icon {\n    border-color: #9c27b0;\n    color: #9c27b0;\n}\n\n.wizard-card[data-color=\"purple\"] .form-group .form-control {\n    background-image: linear-gradient(#9c27b0, #9c27b0), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.wizard-card[data-color=\"purple\"] .checkbox input[type=checkbox]:checked+.checkbox-material .check {\n    background-color: #9c27b0;\n}\n\n.wizard-card[data-color=\"purple\"] .radio input[type=radio]:checked~.check {\n    background-color: #9c27b0;\n}\n\n.wizard-card[data-color=\"purple\"] .radio input[type=radio]:checked~.circle {\n    border-color: #9c27b0;\n}\n\n.wizard-card[data-color=\"green\"] .moving-tab {\n    background-color: #4caf50;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(76, 175, 80, 0.4);\n}\n\n.wizard-card[data-color=\"green\"] .picture:hover {\n    border-color: #4caf50;\n}\n\n.wizard-card[data-color=\"green\"] .choice:hover .icon,\n.wizard-card[data-color=\"green\"] .choice.active .icon {\n    border-color: #4caf50;\n    color: #4caf50;\n}\n\n.wizard-card[data-color=\"green\"] .form-group .form-control {\n    background-image: linear-gradient(#4caf50, #4caf50), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.wizard-card[data-color=\"green\"] .checkbox input[type=checkbox]:checked+.checkbox-material .check {\n    background-color: #4caf50;\n}\n\n.wizard-card[data-color=\"green\"] .radio input[type=radio]:checked~.check {\n    background-color: #4caf50;\n}\n\n.wizard-card[data-color=\"green\"] .radio input[type=radio]:checked~.circle {\n    border-color: #4caf50;\n}\n\n.wizard-card[data-color=\"blue\"] .moving-tab {\n    background-color: #00bcd4;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(0, 188, 212, 0.4);\n}\n\n.wizard-card[data-color=\"blue\"] .picture:hover {\n    border-color: #00bcd4;\n}\n\n.wizard-card[data-color=\"blue\"] .choice:hover .icon,\n.wizard-card[data-color=\"blue\"] .choice.active .icon {\n    border-color: #00bcd4;\n    color: #00bcd4;\n}\n\n.wizard-card[data-color=\"blue\"] .form-group .form-control {\n    background-image: linear-gradient(#00bcd4, #00bcd4), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.wizard-card[data-color=\"blue\"] .checkbox input[type=checkbox]:checked+.checkbox-material .check {\n    background-color: #00bcd4;\n}\n\n.wizard-card[data-color=\"blue\"] .radio input[type=radio]:checked~.check {\n    background-color: #00bcd4;\n}\n\n.wizard-card[data-color=\"blue\"] .radio input[type=radio]:checked~.circle {\n    border-color: #00bcd4;\n}\n\n.wizard-card[data-color=\"orange\"] .moving-tab {\n    background-color: #ff9800;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 152, 0, 0.4);\n}\n\n.wizard-card[data-color=\"orange\"] .picture:hover {\n    border-color: #ff9800;\n}\n\n.wizard-card[data-color=\"orange\"] .choice:hover .icon,\n.wizard-card[data-color=\"orange\"] .choice.active .icon {\n    border-color: #ff9800;\n    color: #ff9800;\n}\n\n.wizard-card[data-color=\"orange\"] .form-group .form-control {\n    background-image: linear-gradient(#ff9800, #ff9800), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.wizard-card[data-color=\"orange\"] .checkbox input[type=checkbox]:checked+.checkbox-material .check {\n    background-color: #ff9800;\n}\n\n.wizard-card[data-color=\"orange\"] .radio input[type=radio]:checked~.check {\n    background-color: #ff9800;\n}\n\n.wizard-card[data-color=\"orange\"] .radio input[type=radio]:checked~.circle {\n    border-color: #ff9800;\n}\n\n.wizard-card[data-color=\"red\"] .moving-tab {\n    background-color: #f44336;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(244, 67, 54, 0.4);\n}\n\n.wizard-card[data-color=\"red\"] .picture:hover {\n    border-color: #f44336;\n}\n\n.wizard-card[data-color=\"red\"] .choice:hover .icon,\n.wizard-card[data-color=\"red\"] .choice.active .icon {\n    border-color: #f44336;\n    color: #f44336;\n}\n\n.wizard-card[data-color=\"red\"] .form-group .form-control {\n    background-image: linear-gradient(#f44336, #f44336), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.wizard-card[data-color=\"red\"] .checkbox input[type=checkbox]:checked+.checkbox-material .check {\n    background-color: #f44336;\n}\n\n.wizard-card[data-color=\"red\"] .radio input[type=radio]:checked~.check {\n    background-color: #f44336;\n}\n\n.wizard-card[data-color=\"red\"] .radio input[type=radio]:checked~.circle {\n    border-color: #f44336;\n}\n\n.wizard-card[data-color=\"rose\"] .moving-tab {\n    background-color: #e91e63;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(233, 30, 99, 0.4);\n}\n\n.wizard-card[data-color=\"rose\"] .picture:hover {\n    border-color: #e91e63;\n}\n\n.wizard-card[data-color=\"rose\"] .choice:hover .icon,\n.wizard-card[data-color=\"rose\"] .choice.active .icon {\n    border-color: #e91e63;\n    color: #e91e63;\n}\n\n.wizard-card[data-color=\"rose\"] .form-group .form-control {\n    background-image: linear-gradient(#e91e63, #e91e63), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.wizard-card[data-color=\"rose\"] .checkbox input[type=checkbox]:checked+.checkbox-material .check {\n    background-color: #e91e63;\n}\n\n.wizard-card[data-color=\"rose\"] .radio input[type=radio]:checked~.check {\n    background-color: #e91e63;\n}\n\n.wizard-card[data-color=\"rose\"] .radio input[type=radio]:checked~.circle {\n    border-color: #e91e63;\n}\n\n.wizard-card .picture input[type=\"file\"] {\n    cursor: pointer;\n    display: block;\n    height: 100%;\n    left: 0;\n    opacity: 0 !important;\n    position: absolute;\n    top: 0;\n    width: 100%;\n}\n\n.wizard-card .picture-src {\n    width: 100%;\n}\n\n.wizard-card .tab-content {\n    min-height: 340px;\n    padding: 20px 15px;\n}\n\n.wizard-card .wizard-footer {\n    padding: 0 15px;\n}\n\n.wizard-card .wizard-footer .checkbox {\n    margin-top: 16px;\n}\n\n.wizard-card .disabled {\n    display: none;\n}\n\n.wizard-card .wizard-header {\n    text-align: center;\n    padding: 25px 0 35px;\n}\n\n.wizard-card .wizard-header h5 {\n    margin: 5px 0 0;\n}\n\n.wizard-card .nav-pills>li {\n    text-align: center;\n}\n\n.wizard-card .btn {\n    text-transform: uppercase;\n}\n\n.wizard-card .info-text {\n    text-align: center;\n    font-weight: 300;\n    margin: 10px 0 30px;\n}\n\n.wizard-card .choice {\n    text-align: center;\n    cursor: pointer;\n    margin-top: 20px;\n}\n\n.wizard-card .choice[disabled] {\n    pointer-events: none;\n    cursor: not-allowed;\n    opacity: .26;\n}\n\n.wizard-card .choice .icon {\n    text-align: center;\n    vertical-align: middle;\n    height: 116px;\n    width: 116px;\n    border-radius: 50%;\n    color: #999999;\n    margin: 0 auto 20px;\n    border: 4px solid #CCCCCC;\n    transition: all 0.2s;\n    -webkit-transition: all 0.2s;\n}\n\n.wizard-card .choice i {\n    font-size: 40px;\n    line-height: 111px;\n}\n\n.wizard-card .choice:hover .icon,\n.wizard-card .choice.active .icon {\n    border-color: #2ca8ff;\n}\n\n.wizard-card .choice input[type=\"radio\"],\n.wizard-card .choice input[type=\"checkbox\"] {\n    position: absolute;\n    left: -10000px;\n    z-index: -1;\n}\n\n.wizard-card .btn-finish {\n    display: none;\n}\n\n.wizard-card .description {\n    color: #999999;\n    font-size: 14px;\n}\n\n.wizard-card .wizard-title {\n    margin: 0;\n}\n\n.wizard-card .nav-pills {\n    background-color: rgba(200, 200, 200, 0.2);\n}\n\n.wizard-card .nav-pills>li+li {\n    margin-left: 0;\n}\n\n.wizard-card .nav-pills>li>a {\n    border: 0 !important;\n    border-radius: 0;\n    line-height: 18px;\n    text-transform: uppercase;\n    font-size: 12px;\n    font-weight: 500;\n    min-width: 100px;\n    text-align: center;\n    color: #555555 !important;\n}\n\n.wizard-card .nav-pills>li.active>a,\n.wizard-card .nav-pills>li.active>a:hover,\n.wizard-card .nav-pills>li.active>a:focus,\n.wizard-card .nav-pills>li>a:hover,\n.wizard-card .nav-pills>li>a:focus {\n    background-color: inherit;\n    box-shadow: none;\n}\n\n.wizard-card .nav-pills>li i {\n    display: block;\n    font-size: 30px;\n    padding: 15px 0;\n}\n\n.ct-label {\n    fill: rgba(0, 0, 0, 0.4);\n    color: rgba(0, 0, 0, 0.4);\n    font-size: 1.3rem;\n    line-height: 1;\n}\n\n.ct-chart-line .ct-label,\n.ct-chart-bar .ct-label {\n    display: block;\n    display: -webkit-box;\n    display: -moz-box;\n    display: -ms-flexbox;\n    display: -webkit-flex;\n    display: flex;\n}\n\n.ct-chart-pie .ct-label,\n.ct-chart-donut .ct-label {\n    dominant-baseline: central;\n}\n\n.ct-label.ct-horizontal.ct-start {\n    -webkit-box-align: flex-end;\n    -webkit-align-items: flex-end;\n    -ms-flex-align: flex-end;\n    align-items: flex-end;\n    -webkit-box-pack: flex-start;\n    -webkit-justify-content: flex-start;\n    -ms-flex-pack: flex-start;\n    justify-content: flex-start;\n    text-align: left;\n    text-anchor: start;\n}\n\n.ct-label.ct-horizontal.ct-end {\n    -webkit-box-align: flex-start;\n    -webkit-align-items: flex-start;\n    -ms-flex-align: flex-start;\n    align-items: flex-start;\n    -webkit-box-pack: flex-start;\n    -webkit-justify-content: flex-start;\n    -ms-flex-pack: flex-start;\n    justify-content: flex-start;\n    text-align: left;\n    text-anchor: start;\n}\n\n.ct-label.ct-vertical.ct-start {\n    -webkit-box-align: flex-end;\n    -webkit-align-items: flex-end;\n    -ms-flex-align: flex-end;\n    align-items: flex-end;\n    -webkit-box-pack: flex-end;\n    -webkit-justify-content: flex-end;\n    -ms-flex-pack: flex-end;\n    justify-content: flex-end;\n    text-align: right;\n    text-anchor: end;\n}\n\n.ct-label.ct-vertical.ct-end {\n    -webkit-box-align: flex-end;\n    -webkit-align-items: flex-end;\n    -ms-flex-align: flex-end;\n    align-items: flex-end;\n    -webkit-box-pack: flex-start;\n    -webkit-justify-content: flex-start;\n    -ms-flex-pack: flex-start;\n    justify-content: flex-start;\n    text-align: left;\n    text-anchor: start;\n}\n\n.ct-chart-bar .ct-label.ct-horizontal.ct-start {\n    -webkit-box-align: flex-end;\n    -webkit-align-items: flex-end;\n    -ms-flex-align: flex-end;\n    align-items: flex-end;\n    -webkit-box-pack: center;\n    -webkit-justify-content: center;\n    -ms-flex-pack: center;\n    justify-content: center;\n    text-align: center;\n    text-anchor: start;\n}\n\n.ct-chart-bar .ct-label.ct-horizontal.ct-end {\n    -webkit-box-align: flex-start;\n    -webkit-align-items: flex-start;\n    -ms-flex-align: flex-start;\n    align-items: flex-start;\n    -webkit-box-pack: center;\n    -webkit-justify-content: center;\n    -ms-flex-pack: center;\n    justify-content: center;\n    text-align: center;\n    text-anchor: start;\n}\n\n.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start {\n    -webkit-box-align: flex-end;\n    -webkit-align-items: flex-end;\n    -ms-flex-align: flex-end;\n    align-items: flex-end;\n    -webkit-box-pack: flex-start;\n    -webkit-justify-content: flex-start;\n    -ms-flex-pack: flex-start;\n    justify-content: flex-start;\n    text-align: left;\n    text-anchor: start;\n}\n\n.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end {\n    -webkit-box-align: flex-start;\n    -webkit-align-items: flex-start;\n    -ms-flex-align: flex-start;\n    align-items: flex-start;\n    -webkit-box-pack: flex-start;\n    -webkit-justify-content: flex-start;\n    -ms-flex-pack: flex-start;\n    justify-content: flex-start;\n    text-align: left;\n    text-anchor: start;\n}\n\n.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-start {\n    -webkit-box-align: center;\n    -webkit-align-items: center;\n    -ms-flex-align: center;\n    align-items: center;\n    -webkit-box-pack: flex-end;\n    -webkit-justify-content: flex-end;\n    -ms-flex-pack: flex-end;\n    justify-content: flex-end;\n    text-align: right;\n    text-anchor: end;\n}\n\n.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-end {\n    -webkit-box-align: center;\n    -webkit-align-items: center;\n    -ms-flex-align: center;\n    align-items: center;\n    -webkit-box-pack: flex-start;\n    -webkit-justify-content: flex-start;\n    -ms-flex-pack: flex-start;\n    justify-content: flex-start;\n    text-align: left;\n    text-anchor: end;\n}\n\n.ct-grid {\n    stroke: rgba(0, 0, 0, 0.2);\n    stroke-width: 1px;\n    stroke-dasharray: 2px;\n}\n\n.ct-grid-background {\n    fill: none;\n}\n\n.ct-point {\n    stroke-width: 10px;\n    stroke-linecap: round;\n}\n\n.ct-line {\n    fill: none;\n    stroke-width: 4px;\n}\n\n.ct-area {\n    stroke: none;\n    fill-opacity: 0.1;\n}\n\n.ct-bar {\n    fill: none;\n    stroke-width: 10px;\n}\n\n.ct-slice-donut {\n    fill: none;\n    stroke-width: 60px;\n}\n\n.ct-series-a .ct-point,\n.ct-series-a .ct-line,\n.ct-series-a .ct-bar,\n.ct-series-a .ct-slice-donut {\n    stroke: #00bcd4;\n}\n\n.ct-series-a .ct-slice-pie,\n.ct-series-a .ct-slice-donut-solid,\n.ct-series-a .ct-area {\n    fill: #00bcd4;\n}\n\n.ct-series-b .ct-point,\n.ct-series-b .ct-line,\n.ct-series-b .ct-bar,\n.ct-series-b .ct-slice-donut {\n    stroke: #f44336;\n}\n\n.ct-series-b .ct-slice-pie,\n.ct-series-b .ct-slice-donut-solid,\n.ct-series-b .ct-area {\n    fill: #f44336;\n}\n\n.ct-series-c .ct-point,\n.ct-series-c .ct-line,\n.ct-series-c .ct-bar,\n.ct-series-c .ct-slice-donut {\n    stroke: #ff9800;\n}\n\n.ct-series-c .ct-slice-pie,\n.ct-series-c .ct-slice-donut-solid,\n.ct-series-c .ct-area {\n    fill: #ff9800;\n}\n\n.ct-series-d .ct-point,\n.ct-series-d .ct-line,\n.ct-series-d .ct-bar,\n.ct-series-d .ct-slice-donut {\n    stroke: #9c27b0;\n}\n\n.ct-series-d .ct-slice-pie,\n.ct-series-d .ct-slice-donut-solid,\n.ct-series-d .ct-area {\n    fill: #9c27b0;\n}\n\n.ct-series-e .ct-point,\n.ct-series-e .ct-line,\n.ct-series-e .ct-bar,\n.ct-series-e .ct-slice-donut {\n    stroke: #4caf50;\n}\n\n.ct-series-e .ct-slice-pie,\n.ct-series-e .ct-slice-donut-solid,\n.ct-series-e .ct-area {\n    fill: #4caf50;\n}\n\n.ct-series-f .ct-point,\n.ct-series-f .ct-line,\n.ct-series-f .ct-bar,\n.ct-series-f .ct-slice-donut {\n    stroke: #9C9B99;\n}\n\n.ct-series-f .ct-slice-pie,\n.ct-series-f .ct-slice-donut-solid,\n.ct-series-f .ct-area {\n    fill: #9C9B99;\n}\n\n.ct-series-g .ct-point,\n.ct-series-g .ct-line,\n.ct-series-g .ct-bar,\n.ct-series-g .ct-slice-donut {\n    stroke: #999999;\n}\n\n.ct-series-g .ct-slice-pie,\n.ct-series-g .ct-slice-donut-solid,\n.ct-series-g .ct-area {\n    fill: #999999;\n}\n\n.ct-series-h .ct-point,\n.ct-series-h .ct-line,\n.ct-series-h .ct-bar,\n.ct-series-h .ct-slice-donut {\n    stroke: #dd4b39;\n}\n\n.ct-series-h .ct-slice-pie,\n.ct-series-h .ct-slice-donut-solid,\n.ct-series-h .ct-area {\n    fill: #dd4b39;\n}\n\n.ct-series-i .ct-point,\n.ct-series-i .ct-line,\n.ct-series-i .ct-bar,\n.ct-series-i .ct-slice-donut {\n    stroke: #35465c;\n}\n\n.ct-series-i .ct-slice-pie,\n.ct-series-i .ct-slice-donut-solid,\n.ct-series-i .ct-area {\n    fill: #35465c;\n}\n\n.ct-series-j .ct-point,\n.ct-series-j .ct-line,\n.ct-series-j .ct-bar,\n.ct-series-j .ct-slice-donut {\n    stroke: #e52d27;\n}\n\n.ct-series-j .ct-slice-pie,\n.ct-series-j .ct-slice-donut-solid,\n.ct-series-j .ct-area {\n    fill: #e52d27;\n}\n\n.ct-series-k .ct-point,\n.ct-series-k .ct-line,\n.ct-series-k .ct-bar,\n.ct-series-k .ct-slice-donut {\n    stroke: #55acee;\n}\n\n.ct-series-k .ct-slice-pie,\n.ct-series-k .ct-slice-donut-solid,\n.ct-series-k .ct-area {\n    fill: #55acee;\n}\n\n.ct-series-l .ct-point,\n.ct-series-l .ct-line,\n.ct-series-l .ct-bar,\n.ct-series-l .ct-slice-donut {\n    stroke: #cc2127;\n}\n\n.ct-series-l .ct-slice-pie,\n.ct-series-l .ct-slice-donut-solid,\n.ct-series-l .ct-area {\n    fill: #cc2127;\n}\n\n.ct-series-m .ct-point,\n.ct-series-m .ct-line,\n.ct-series-m .ct-bar,\n.ct-series-m .ct-slice-donut {\n    stroke: #1769ff;\n}\n\n.ct-series-m .ct-slice-pie,\n.ct-series-m .ct-slice-donut-solid,\n.ct-series-m .ct-area {\n    fill: #1769ff;\n}\n\n.ct-series-n .ct-point,\n.ct-series-n .ct-line,\n.ct-series-n .ct-bar,\n.ct-series-n .ct-slice-donut {\n    stroke: #6188e2;\n}\n\n.ct-series-n .ct-slice-pie,\n.ct-series-n .ct-slice-donut-solid,\n.ct-series-n .ct-area {\n    fill: #6188e2;\n}\n\n.ct-series-o .ct-point,\n.ct-series-o .ct-line,\n.ct-series-o .ct-bar,\n.ct-series-o .ct-slice-donut {\n    stroke: #a748ca;\n}\n\n.ct-series-o .ct-slice-pie,\n.ct-series-o .ct-slice-donut-solid,\n.ct-series-o .ct-area {\n    fill: #a748ca;\n}\n\n.ct-square {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-square:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 100%;\n}\n\n.ct-square:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-square>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-minor-second {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-minor-second:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 93.75%;\n}\n\n.ct-minor-second:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-minor-second>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-major-second {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-major-second:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 88.8888888889%;\n}\n\n.ct-major-second:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-major-second>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-minor-third {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-minor-third:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 83.3333333333%;\n}\n\n.ct-minor-third:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-minor-third>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-major-third {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-major-third:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 80%;\n}\n\n.ct-major-third:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-major-third>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-perfect-fourth {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-perfect-fourth:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 75%;\n}\n\n.ct-perfect-fourth:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-perfect-fourth>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-perfect-fifth {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-perfect-fifth:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 66.6666666667%;\n}\n\n.ct-perfect-fifth:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-perfect-fifth>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-minor-sixth {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-minor-sixth:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 62.5%;\n}\n\n.ct-minor-sixth:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-minor-sixth>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-golden-section {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-golden-section:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 61.804697157%;\n}\n\n.ct-golden-section:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-golden-section>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-major-sixth {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-major-sixth:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 60%;\n}\n\n.ct-major-sixth:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-major-sixth>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-minor-seventh {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-minor-seventh:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 56.25%;\n}\n\n.ct-minor-seventh:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-minor-seventh>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-major-seventh {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-major-seventh:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 53.3333333333%;\n}\n\n.ct-major-seventh:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-major-seventh>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-octave {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-octave:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 50%;\n}\n\n.ct-octave:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-octave>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-major-tenth {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-major-tenth:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 40%;\n}\n\n.ct-major-tenth:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-major-tenth>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-major-eleventh {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-major-eleventh:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 37.5%;\n}\n\n.ct-major-eleventh:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-major-eleventh>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-major-twelfth {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-major-twelfth:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 33.3333333333%;\n}\n\n.ct-major-twelfth:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-major-twelfth>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n.ct-double-octave {\n    display: block;\n    position: relative;\n    width: 100%;\n}\n\n.ct-double-octave:before {\n    display: block;\n    float: left;\n    content: \"\";\n    width: 0;\n    height: 0;\n    padding-bottom: 25%;\n}\n\n.ct-double-octave:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.ct-double-octave>svg {\n    display: block;\n    position: absolute;\n    top: 0;\n    left: 0;\n}\n\n\n/*!\n * Bootstrap-select v1.11.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2016 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\nselect.bs-select-hidden,\nselect.selectpicker {\n    display: none !important;\n}\n\n.bootstrap-select {\n    width: 220px \\0;\n    /*IE9 and below*/\n}\n\n.bootstrap-select>.dropdown-toggle {\n    width: 100%;\n    padding-right: 25px;\n    z-index: 1;\n}\n\n.bootstrap-select>select {\n    position: absolute !important;\n    bottom: 0;\n    left: 50%;\n    display: block !important;\n    width: 0.5px !important;\n    height: 100% !important;\n    padding: 0 !important;\n    opacity: 0 !important;\n    border: none;\n}\n\n.bootstrap-select>select.mobile-device {\n    top: 0;\n    left: 0;\n    display: block !important;\n    width: 100% !important;\n    z-index: 2;\n}\n\n.has-error .bootstrap-select .dropdown-toggle,\n.error .bootstrap-select .dropdown-toggle {\n    border-color: #b94a48;\n}\n\n.bootstrap-select.fit-width {\n    width: auto !important;\n}\n\n.bootstrap-select:not([class*=\"col-\"]):not([class*=\"form-control\"]):not(.input-group-btn) {\n    width: 100%;\n}\n\n.bootstrap-select.form-control {\n    margin-bottom: 0;\n    padding: 0;\n    border: none;\n}\n\n.bootstrap-select.form-control:not([class*=\"col-\"]) {\n    width: 100%;\n}\n\n.bootstrap-select.form-control.input-group-btn {\n    z-index: auto;\n}\n\n.bootstrap-select.form-control.input-group-btn:not(:first-child):not(:last-child)>.btn {\n    border-radius: 0;\n}\n\n.bootstrap-select.btn-group:not(.input-group-btn),\n.bootstrap-select.btn-group[class*=\"col-\"] {\n    float: none;\n    display: inline-block;\n    margin-left: 0;\n}\n\n.bootstrap-select.btn-group.dropdown-menu-right,\n.bootstrap-select.btn-group[class*=\"col-\"].dropdown-menu-right,\n.row .bootstrap-select.btn-group[class*=\"col-\"].dropdown-menu-right {\n    float: right;\n}\n\n.form-inline .bootstrap-select.btn-group,\n.form-horizontal .bootstrap-select.btn-group,\n.form-group .bootstrap-select.btn-group {\n    margin-bottom: 0;\n}\n\n.form-group-lg .bootstrap-select.btn-group.form-control,\n.form-group-sm .bootstrap-select.btn-group.form-control {\n    padding: 0;\n}\n\n.form-inline .bootstrap-select.btn-group .form-control {\n    width: 100%;\n}\n\n.bootstrap-select.btn-group .dropdown-menu li.disabled a:hover,\n.bootstrap-select.btn-group .dropdown-menu li.disabled a:focus {\n    box-shadow: none;\n}\n\n.bootstrap-select.btn-group.disabled,\n.bootstrap-select.btn-group>.disabled {\n    cursor: not-allowed;\n}\n\n.bootstrap-select.btn-group.disabled:focus,\n.bootstrap-select.btn-group>.disabled:focus {\n    outline: none !important;\n}\n\n.bootstrap-select.btn-group.bs-container {\n    position: absolute;\n    height: 0 !important;\n    padding: 0 !important;\n}\n\n.bootstrap-select.btn-group.bs-container .dropdown-menu {\n    z-index: 1060;\n}\n\n.bootstrap-select.btn-group .dropdown-toggle .filter-option {\n    display: inline-block;\n    overflow: hidden;\n    width: 100%;\n    text-align: left;\n    text-overflow: ellipsis;\n}\n\n.bootstrap-select.btn-group .dropdown-toggle .caret {\n    position: absolute;\n    top: 50%;\n    right: 16px;\n    margin-top: -2px;\n    vertical-align: middle;\n}\n\n.bootstrap-select.btn-group[class*=\"col-\"] .dropdown-toggle {\n    width: 100%;\n}\n\n.bootstrap-select.btn-group .dropdown-menu {\n    border-radius: 4px;\n    padding: 0;\n    min-width: 100%;\n    -webkit-box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n}\n\n.bootstrap-select.btn-group .dropdown-menu.inner {\n    position: static;\n    float: none;\n    border: 0;\n    padding: 5px 0;\n    margin: 0;\n    -webkit-box-shadow: none;\n    box-shadow: none;\n    -ms-overflow-style: auto;\n}\n\n.bootstrap-select.btn-group .dropdown-menu li {\n    position: relative;\n}\n\n.bootstrap-select.btn-group .dropdown-menu li.active small {\n    color: #fff;\n}\n\n.bootstrap-select.btn-group .dropdown-menu li.disabled a {\n    cursor: not-allowed;\n}\n\n.bootstrap-select.btn-group .dropdown-menu li a {\n    cursor: pointer;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n    outline: 0;\n}\n\n.bootstrap-select.btn-group .dropdown-menu li a:focus,\n.bootstrap-select.btn-group .dropdown-menu li a:hover {\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(156, 39, 176, 0.4);\n}\n\n.bootstrap-select.btn-group .dropdown-menu li a.opt {\n    position: relative;\n    padding-left: 2.25em;\n}\n\n.bootstrap-select.btn-group .dropdown-menu li a span.check-mark {\n    display: none;\n}\n\n.bootstrap-select.btn-group .dropdown-menu li a span.text {\n    display: inline-block;\n}\n\n.bootstrap-select.btn-group .dropdown-menu li small {\n    padding-left: 0.5em;\n}\n\n.bootstrap-select.btn-group .dropdown-menu .notify {\n    position: absolute;\n    bottom: 5px;\n    width: 96%;\n    margin: 0 2%;\n    min-height: 26px;\n    padding: 3px 5px;\n    background: #f5f5f5;\n    border: 1px solid #e3e3e3;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n    pointer-events: none;\n    opacity: 0.9;\n    -webkit-box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n}\n\n.bootstrap-select.btn-group .no-results {\n    padding: 3px;\n    background: #f5f5f5;\n    margin: 0 5px;\n    white-space: nowrap;\n}\n\n.bootstrap-select.btn-group.fit-width .dropdown-toggle .filter-option {\n    position: static;\n}\n\n.bootstrap-select.btn-group.fit-width .dropdown-toggle .caret {\n    position: static;\n    top: auto;\n    margin-top: -1px;\n}\n\n.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a span.check-mark {\n    position: absolute;\n    display: inline-block;\n    right: 15px;\n    font-size: 16px;\n}\n\n.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text {\n    margin-right: 34px;\n}\n\n.bootstrap-select.show-menu-arrow.open>.dropdown-toggle {\n    z-index: 1061;\n}\n\n.bootstrap-select.show-menu-arrow .dropdown-toggle:before {\n    content: '';\n    border-left: 7px solid transparent;\n    border-right: 7px solid transparent;\n    border-bottom: 7px solid rgba(204, 204, 204, 0.2);\n    position: absolute;\n    bottom: -4px;\n    left: 9px;\n    display: none;\n}\n\n.bootstrap-select.show-menu-arrow .dropdown-toggle:after {\n    content: '';\n    border-left: 6px solid transparent;\n    border-right: 6px solid transparent;\n    border-bottom: 6px solid white;\n    position: absolute;\n    bottom: -4px;\n    left: 10px;\n    display: none;\n}\n\n.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before {\n    bottom: auto;\n    top: -3px;\n    border-top: 7px solid rgba(204, 204, 204, 0.2);\n    border-bottom: 0;\n}\n\n.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after {\n    bottom: auto;\n    top: -3px;\n    border-top: 6px solid white;\n    border-bottom: 0;\n}\n\n.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before {\n    right: 12px;\n    left: auto;\n}\n\n.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after {\n    right: 13px;\n    left: auto;\n}\n\n.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:before,\n.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:after {\n    display: block;\n}\n\n.bs-searchbox,\n.bs-actionsbox,\n.bs-donebutton {\n    padding: 4px 8px;\n}\n\n.bs-actionsbox {\n    width: 100%;\n    -webkit-box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n}\n\n.bs-actionsbox .btn-group button {\n    width: 50%;\n}\n\n.bs-donebutton {\n    float: left;\n    width: 100%;\n    -webkit-box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n}\n\n.bs-donebutton .btn-group button {\n    width: 100%;\n}\n\n.bs-searchbox+.bs-actionsbox {\n    padding: 0 8px 4px;\n}\n\n.bs-searchbox .form-control {\n    margin-bottom: 0;\n    width: 100%;\n    float: none;\n}\n\n.select-with-transition {\n    border: 0 !important;\n    background-image: linear-gradient(#9c27b0, #9c27b0), linear-gradient(#D2D2D2, #D2D2D2);\n    background-size: 0 2px, 100% 1px;\n    background-repeat: no-repeat;\n    background-position: center bottom, center calc(100% - 1px);\n    background-color: rgba(0, 0, 0, 0) !important;\n    transition: background 0s ease-out !important;\n    float: none !important;\n    box-shadow: none !important;\n    border-radius: 0 !important;\n    color: #3C4858 !important;\n    height: 34px;\n    padding-left: 0 !important;\n    padding-bottom: 5px !important;\n}\n\n.select-with-transition .caret,\n.select-with-transition .ripple-container {\n    display: none;\n}\n\n.btn-group.bootstrap-select.show-tick.open .select-with-transition {\n    outline: none !important;\n    background-image: linear-gradient(#9c27b0, #9c27b0), linear-gradient(#D2D2D2, #D2D2D2) !important;\n    background-size: 100% 2px, 100% 1px !important;\n    box-shadow: none;\n    transition-duration: 0.3s !important;\n}\n\n\n/* perfect-scrollbar v0.6.13 */\n\n.ps-container {\n    -ms-touch-action: auto;\n    touch-action: auto;\n    overflow: hidden !important;\n    -ms-overflow-style: none;\n}\n\n@supports (-ms-overflow-style: none) {\n    .ps-container {\n        overflow: auto !important;\n    }\n}\n\n@media screen and (-ms-high-contrast: active),\n(-ms-high-contrast: none) {\n    .ps-container {\n        overflow: auto !important;\n    }\n}\n\n.ps-container.ps-active-x>.ps-scrollbar-x-rail,\n.ps-container.ps-active-y>.ps-scrollbar-y-rail {\n    display: block;\n    background-color: transparent;\n}\n\n.ps-container.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail {\n    background-color: #eee;\n    opacity: 0.9;\n}\n\n.ps-container.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail>.ps-scrollbar-x {\n    background-color: #999;\n    height: 11px;\n}\n\n.ps-container.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail {\n    background-color: #eee;\n    opacity: 0.9;\n}\n\n.ps-container.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail>.ps-scrollbar-y {\n    background-color: #999;\n    width: 11px;\n}\n\n.ps-container>.ps-scrollbar-x-rail {\n    display: none;\n    position: absolute;\n    /* please don't change 'position' */\n    opacity: 0;\n    -webkit-transition: background-color .2s linear, opacity .2s linear;\n    -o-transition: background-color .2s linear, opacity .2s linear;\n    -moz-transition: background-color .2s linear, opacity .2s linear;\n    transition: background-color .2s linear, opacity .2s linear;\n    bottom: 0px;\n    /* there must be 'bottom' for ps-scrollbar-x-rail */\n    height: 15px;\n}\n\n.ps-container>.ps-scrollbar-x-rail>.ps-scrollbar-x {\n    position: absolute;\n    /* please don't change 'position' */\n    background-color: #aaa;\n    -webkit-border-radius: 6px;\n    -moz-border-radius: 6px;\n    border-radius: 6px;\n    -webkit-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;\n    transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;\n    -o-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;\n    -moz-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;\n    transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;\n    transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -webkit-border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;\n    bottom: 2px;\n    /* there must be 'bottom' for ps-scrollbar-x */\n    height: 6px;\n}\n\n.ps-container>.ps-scrollbar-x-rail:hover>.ps-scrollbar-x,\n.ps-container>.ps-scrollbar-x-rail:active>.ps-scrollbar-x {\n    height: 11px;\n}\n\n.ps-container>.ps-scrollbar-y-rail {\n    display: none;\n    position: absolute;\n    /* please don't change 'position' */\n    opacity: 0;\n    -webkit-transition: background-color .2s linear, opacity .2s linear;\n    -o-transition: background-color .2s linear, opacity .2s linear;\n    -moz-transition: background-color .2s linear, opacity .2s linear;\n    transition: background-color .2s linear, opacity .2s linear;\n    right: 0;\n    /* there must be 'right' for ps-scrollbar-y-rail */\n    width: 15px;\n}\n\n.ps-container>.ps-scrollbar-y-rail>.ps-scrollbar-y {\n    position: absolute;\n    /* please don't change 'position' */\n    background-color: #aaa;\n    -webkit-border-radius: 6px;\n    -moz-border-radius: 6px;\n    border-radius: 6px;\n    -webkit-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;\n    transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;\n    -o-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;\n    -moz-transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;\n    transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;\n    transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -webkit-border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;\n    right: 2px;\n    /* there must be 'right' for ps-scrollbar-y */\n    width: 6px;\n}\n\n.ps-container>.ps-scrollbar-y-rail:hover>.ps-scrollbar-y,\n.ps-container>.ps-scrollbar-y-rail:active>.ps-scrollbar-y {\n    width: 11px;\n}\n\n.ps-container:hover.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail {\n    background-color: #eee;\n    opacity: 0.9;\n}\n\n.ps-container:hover.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail>.ps-scrollbar-x {\n    background-color: #999;\n    height: 11px;\n}\n\n.ps-container:hover.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail {\n    background-color: #eee;\n    opacity: 0.9;\n}\n\n.ps-container:hover.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail>.ps-scrollbar-y {\n    background-color: #999;\n    width: 11px;\n}\n\n.ps-container:hover>.ps-scrollbar-x-rail,\n.ps-container:hover>.ps-scrollbar-y-rail {\n    opacity: 0.6;\n}\n\n.ps-container:hover>.ps-scrollbar-x-rail:hover {\n    background-color: #eee;\n    opacity: 0.9;\n}\n\n.ps-container:hover>.ps-scrollbar-x-rail:hover>.ps-scrollbar-x {\n    background-color: #999;\n}\n\n.ps-container:hover>.ps-scrollbar-y-rail:hover {\n    background-color: #eee;\n    opacity: 0.9;\n}\n\n.ps-container:hover>.ps-scrollbar-y-rail:hover>.ps-scrollbar-y {\n    background-color: #999;\n}\n\nhtml * {\n    -webkit-font-smoothing: antialiased;\n    -moz-osx-font-smoothing: grayscale;\n}\n\nh1,\n.h1 {\n    font-size: 3.8em;\n    line-height: 1.15em;\n}\n\nh2,\n.h2 {\n    font-size: 2.6em;\n}\n\nh3,\n.h3 {\n    font-size: 1.825em;\n    line-height: 1.4em;\n    margin: 20px 0 10px;\n}\n\nh4,\n.h4 {\n    font-size: 1.3em;\n    line-height: 1.4em;\n}\n\nh5,\n.h5 {\n    font-size: 1.25em;\n    line-height: 1.4em;\n    margin-bottom: 15px;\n}\n\nh6,\n.h6 {\n    font-size: 1em;\n    text-transform: uppercase;\n    font-weight: 500;\n}\n\n.title,\n.title a,\n.card-title,\n.card-title a,\n.info-title,\n.info-title a,\n.footer-brand,\n.footer-brand a,\n.footer-big h5,\n.footer-big h5 a,\n.footer-big h4,\n.footer-big h4 a,\n.media .media-heading,\n.media .media-heading a {\n    color: #3C4858;\n    text-decoration: none;\n}\n\n.card-blog .card-title {\n    font-weight: 700;\n}\n\nh2.title {\n    margin-bottom: 30px;\n}\n\n.description,\n.card-description,\n.footer-big p {\n    color: #999999;\n}\n\n.text-warning {\n    color: #ff9800;\n}\n\n.text-primary {\n    color: #9c27b0;\n}\n\n.text-danger {\n    color: #f44336;\n}\n\n.text-success {\n    color: #4caf50;\n}\n\n.text-info {\n    color: #00bcd4;\n}\n\n.text-rose {\n    color: #e91e63;\n}\n\n.text-gray {\n    color: #999999;\n}\n\n.wrapper {\n    position: relative;\n    top: 0;\n    height: 100vh;\n}\n\n.sidebar {\n    position: fixed;\n    top: 0;\n    bottom: 0;\n    left: 0;\n    z-index: 2;\n    width: 260px;\n    background: #FFFFFF;\n    box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.42), 0 4px 25px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2);\n}\n\n.sidebar[data-background-color=\"black\"] {\n    background-color: #191919;\n}\n\n.sidebar[data-background-color=\"utrust\"] {\n    background-color: #1F234A;\n}\n\n.sidebar .sidebar-wrapper {\n    position: relative;\n    height: calc(100vh - 75px);\n    overflow: auto;\n    width: 260px;\n    z-index: 4;\n    padding-bottom: 30px;\n}\n\n.sidebar .sidebar-wrapper .dropdown .dropdown-backdrop {\n    display: none !important;\n}\n\n.sidebar .sidebar-wrapper .navbar-form {\n    border: none;\n    box-shadow: none;\n}\n\n.sidebar .sidebar-wrapper>.nav [data-toggle=\"collapse\"]~div>ul>li>a span,\n.sidebar .sidebar-wrapper .user .info [data-toggle=\"collapse\"]~div>ul>li>a span {\n    display: inline-block;\n}\n\n.sidebar .sidebar-wrapper>.nav [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal,\n.sidebar .sidebar-wrapper .user .info [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal {\n    margin: 0;\n    position: relative;\n    transform: translateX(0px);\n    opacity: 1;\n    white-space: nowrap;\n    display: block;\n}\n\n.sidebar .sidebar-wrapper>.nav [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-mini,\n.sidebar .sidebar-wrapper .user .info [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-mini {\n    text-transform: uppercase;\n    width: 30px;\n    margin-right: 15px;\n    text-align: center;\n    letter-spacing: 1px;\n    position: relative;\n    float: left;\n    display: inherit;\n}\n\n.sidebar .sidebar-wrapper>.nav [data-toggle=\"collapse\"]~div>ul>li>a i,\n.sidebar .sidebar-wrapper .user .info [data-toggle=\"collapse\"]~div>ul>li>a i {\n    font-size: 17px;\n    line-height: 20px;\n    width: 26px;\n}\n\n.sidebar .logo-tim {\n    border-radius: 50%;\n    border: 1px solid #333;\n    display: block;\n    height: 61px;\n    width: 61px;\n    float: left;\n    overflow: hidden;\n}\n\n.sidebar .logo-tim img {\n    width: 60px;\n    height: 60px;\n}\n\n.sidebar .nav {\n    margin-top: 15px;\n}\n\n.sidebar .nav .caret {\n    margin-top: 13px;\n    position: absolute;\n    right: 18px;\n}\n\n.sidebar .nav li>a {\n    margin: 10px 15px 0;\n    border-radius: 3px;\n    color: #3C4858;\n    padding-left: 10px;\n    padding-right: 10px;\n}\n\n.sidebar .nav li>a:hover,\n.sidebar .nav li>a:focus {\n    background-color: transparent;\n    outline: none;\n}\n\n.sidebar .nav li:first-child>a {\n    margin: 0 15px;\n}\n\n.sidebar .nav li:hover>a,\n.sidebar .nav li.active>[data-toggle=\"collapse\"] {\n    background-color: rgba(200, 200, 200, 0.2);\n    color: #3C4858;\n    box-shadow: none;\n}\n\n.sidebar .nav li.active>[data-toggle=\"collapse\"] i {\n    color: #a9afbb;\n}\n\n.sidebar .nav li.active>a,\n.sidebar .nav li.active>a i {\n    color: #FFFFFF;\n}\n\n.sidebar .nav li.separator {\n    margin: 15px 0;\n}\n\n.sidebar .nav li.separator:after {\n    width: calc(100% - 30px);\n    content: \"\";\n    position: absolute;\n    height: 1px;\n    left: 15px;\n    background-color: rgba(180, 180, 180, 0.3);\n}\n\n.sidebar .nav li.separator+li {\n    margin-top: 31px;\n}\n\n.sidebar .nav p {\n    margin: 0;\n    line-height: 30px;\n    font-size: 14px;\n    position: relative;\n    display: block;\n    height: auto;\n    white-space: nowrap;\n}\n\n.sidebar .nav i {\n    font-size: 24px;\n    float: left;\n    margin-right: 15px;\n    line-height: 30px;\n    width: 30px;\n    text-align: center;\n    color: #a9afbb;\n}\n\n.sidebar:before,\n.sidebar:after {\n    display: block;\n    content: \"\";\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    top: 0;\n    left: 0;\n    z-index: 0;\n    background: #000;\n}\n\n.sidebar .sidebar-background {\n    position: absolute;\n    z-index: 1;\n    height: 100%;\n    width: 100%;\n    display: block;\n    top: 0;\n    left: 0;\n    background-size: cover;\n    background-position: center center;\n}\n\n.sidebar .sidebar-background:after {\n    position: absolute;\n    z-index: 3;\n    width: 100%;\n    height: 100%;\n    content: \"\";\n    display: block;\n    background: #FFFFFF;\n    opacity: .93;\n}\n\n.sidebar .logo {\n    padding: 15px 0px;\n    margin: 0;\n    display: block;\n    position: relative;\n    z-index: 4;\n}\n\n.sidebar .logo a.logo-mini {\n    opacity: 1;\n    float: left;\n    width: 30px;\n    text-align: center;\n    margin-left: 23px;\n    margin-right: 15px;\n}\n\n.sidebar .logo a.logo-normal {\n    display: block;\n    opacity: 1;\n    -webkit-transform: translate3d(0px, 0, 0);\n    -moz-transform: translate3d(0px, 0, 0);\n    -o-transform: translate3d(0px, 0, 0);\n    -ms-transform: translate3d(0px, 0, 0);\n    transform: translate3d(0px, 0, 0);\n}\n\n.sidebar .logo:after {\n    content: '';\n    position: absolute;\n    bottom: 0;\n    right: 15px;\n    height: 1px;\n    width: calc(100% - 30px);\n    background-color: rgba(180, 180, 180, 0.3);\n}\n\n.sidebar .logo p {\n    float: left;\n    font-size: 20px;\n    margin: 10px 10px;\n    color: #FFFFFF;\n    line-height: 20px;\n}\n\n.sidebar .logo .simple-text {\n    text-transform: uppercase;\n    padding: 5px 0px;\n    display: inline-block;\n    font-size: 18px;\n    color: #3C4858;\n    white-space: nowrap;\n    font-weight: 400;\n    line-height: 30px;\n    overflow: hidden;\n}\n\n.sidebar .logo-tim {\n    border-radius: 50%;\n    border: 1px solid #333;\n    display: block;\n    height: 61px;\n    width: 61px;\n    float: left;\n    overflow: hidden;\n}\n\n.sidebar .logo-tim img {\n    width: 60px;\n    height: 60px;\n}\n\n.sidebar .user {\n    padding-bottom: 20px;\n    margin: 20px auto 0;\n    position: relative;\n}\n\n.sidebar .user:after {\n    content: '';\n    position: absolute;\n    bottom: 0;\n    right: 15px;\n    height: 1px;\n    width: calc(100% - 30px);\n    background-color: rgba(180, 180, 180, 0.3);\n}\n\n.sidebar .user .photo {\n    width: 34px;\n    height: 34px;\n    overflow: hidden;\n    float: left;\n    z-index: 5;\n    margin-right: 11px;\n    border-radius: 50%;\n    margin-left: 23px;\n    box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.42), 0 4px 25px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2);\n}\n\n.sidebar .user .photo img {\n    width: 100%;\n}\n\n.sidebar .user a {\n    color: #3C4858;\n    padding: 6px 15px;\n    white-space: nowrap;\n}\n\n.sidebar .user .info>a {\n    display: block;\n    line-height: 22px;\n}\n\n.sidebar .user .info>a>span {\n    display: block;\n    position: relative;\n    opacity: 1;\n}\n\n.sidebar .user .info .caret {\n    position: absolute;\n    top: 10px;\n    right: 27px;\n}\n\n.sidebar[data-background-color=\"black\"] .nav li>a {\n    color: #FFFFFF;\n}\n\n.sidebar[data-background-color=\"black\"] .nav li i {\n    color: rgba(255, 255, 255, 0.8);\n}\n\n.sidebar[data-background-color=\"black\"] .nav li.active>[data-toggle=\"collapse\"],\n.sidebar[data-background-color=\"black\"] .nav li:hover>[data-toggle=\"collapse\"] {\n    color: #FFFFFF;\n}\n\n.sidebar[data-background-color=\"black\"] .nav li.active>[data-toggle=\"collapse\"] i,\n.sidebar[data-background-color=\"black\"] .nav li:hover>[data-toggle=\"collapse\"] i {\n    color: rgba(255, 255, 255, 0.8);\n}\n\n.sidebar[data-background-color=\"black\"] .user a {\n    color: #FFFFFF;\n}\n\n.sidebar[data-background-color=\"black\"] .simple-text {\n    color: #FFFFFF;\n}\n\n.sidebar[data-background-color=\"black\"] .sidebar-background:after {\n    background: #000;\n    opacity: .8;\n}\n\n.sidebar[data-background-color=\"utrust\"] .nav li>a {\n    color: #FFFFFF;\n}\n\n.sidebar[data-background-color=\"utrust\"] .nav li i {\n    color: rgba(255, 255, 255, 0.8);\n}\n\n.sidebar[data-background-color=\"utrust\"] .nav li.active>[data-toggle=\"collapse\"],\n.sidebar[data-background-color=\"utrust\"] .nav li:hover>[data-toggle=\"collapse\"] {\n    color: #FFFFFF;\n}\n\n.sidebar[data-background-color=\"utrust\"] .nav li.active>[data-toggle=\"collapse\"] i,\n.sidebar[data-background-color=\"utrust\"] .nav li:hover>[data-toggle=\"collapse\"] i {\n    color: rgba(255, 255, 255, 0.8);\n}\n\n.sidebar[data-background-color=\"utrust\"] .user a {\n    color: #FFFFFF;\n}\n\n.sidebar[data-background-color=\"utrust\"] .simple-text {\n    color: #FFFFFF;\n}\n\n.sidebar[data-background-color=\"utrust\"] .sidebar-background:after {\n    background: #1F234A;\n    opacity: .8;\n}\n\n.sidebar[data-background-color=\"white\"]:after,\n.sidebar[data-background-color=\"white\"]:before {\n    background: #FFFFFF;\n}\n\n.sidebar[data-active-color=\"purple\"] li.active>a {\n    background-color: #9c27b0;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(156, 39, 176, 0.4);\n}\n\n.sidebar[data-active-color=\"blue\"] li.active>a {\n    background-color: #00bcd4;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(0, 188, 212, 0.4);\n}\n\n.sidebar[data-active-color=\"green\"] li.active>a {\n    background-color: #4caf50;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(76, 175, 80, 0.4);\n}\n\n.sidebar[data-active-color=\"orange\"] li.active>a {\n    background-color: #ff9800;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 152, 0, 0.4);\n}\n\n.sidebar[data-active-color=\"red\"] li.active>a {\n    background-color: #f44336;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(244, 67, 54, 0.4);\n}\n\n.sidebar[data-active-color=\"rose\"] li.active>a {\n    background-color: #e91e63;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(233, 30, 99, 0.4);\n}\n\n.sidebar[data-active-color=\"white\"] li.active>a {\n    background-color: #FFFFFF;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 255, 255, 0.4);\n}\n\n.sidebar[data-active-color=\"white\"] .nav li.active>a:not([data-toggle=\"collapse\"]) {\n    color: #3C4858;\n    opacity: 1;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(60, 72, 88, 0.4);\n}\n\n.sidebar[data-active-color=\"white\"] .nav li.active>a:not([data-toggle=\"collapse\"]) i {\n    color: rgba(60, 72, 88, 0.8);\n}\n\n.sidebar[data-background-color=\"red\"] .nav li>a {\n    color: #FFFFFF;\n}\n\n.sidebar[data-background-color=\"red\"] .nav li i {\n    color: rgba(255, 255, 255, 0.8);\n}\n\n.sidebar[data-background-color=\"red\"] .nav li.active>[data-toggle=\"collapse\"],\n.sidebar[data-background-color=\"red\"] .nav li:hover>[data-toggle=\"collapse\"] {\n    color: #FFFFFF;\n}\n\n.sidebar[data-background-color=\"red\"] .nav li.active>[data-toggle=\"collapse\"] i,\n.sidebar[data-background-color=\"red\"] .nav li:hover>[data-toggle=\"collapse\"] i {\n    color: rgba(255, 255, 255, 0.8);\n}\n\n.sidebar[data-background-color=\"red\"] .user a {\n    color: #FFFFFF;\n}\n\n.sidebar[data-background-color=\"red\"] .simple-text {\n    color: #FFFFFF;\n}\n\n.sidebar[data-background-color=\"red\"] .sidebar-background:after {\n    background: #f44336;\n    opacity: .8;\n}\n\n.sidebar[data-background-color=\"red\"] .user:after,\n.sidebar[data-background-color=\"red\"] .logo:after,\n.sidebar[data-background-color=\"red\"] .nav li.separator:after {\n    background-color: rgba(255, 255, 255, 0.3);\n}\n\n.sidebar[data-background-color=\"red\"] .nav li:hover:not(.active)>a,\n.sidebar[data-background-color=\"red\"] .nav li.active>[data-toggle=\"collapse\"] {\n    background-color: rgba(255, 255, 255, 0.1);\n}\n\n.sidebar[data-image]:after,\n.sidebar.has-image:after {\n    opacity: .77;\n}\n\n.off-canvas-sidebar .navbar-collapse .nav>li>a,\n.off-canvas-sidebar .navbar-collapse .nav>li>a:hover {\n    color: #FFFFFF;\n    margin: 0 15px;\n}\n\n.off-canvas-sidebar .navbar-collapse .nav>li>a:focus,\n.off-canvas-sidebar .navbar-collapse .nav>li>a:hover {\n    background: rgba(200, 200, 200, 0.2);\n}\n\n.main-panel {\n    position: relative;\n    float: right;\n    width: calc(100% - 260px);\n    -webkit-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n    -moz-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n    -o-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n    -ms-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n    transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n}\n\n.main-panel>.content {\n    margin-top: 50px;\n    padding: 15px 15px;\n    min-height: calc(100vh - 123px);\n}\n\n.main-panel>.footer {\n    border-top: 1px solid #e7e7e7;\n}\n\n.main-panel>.navbar {\n    margin-bottom: 0;\n}\n\n.main-panel .header {\n    margin-bottom: 30px;\n}\n\n.main-panel .header .title {\n    margin-top: 10px;\n}\n\n.perfect-scrollbar-on .sidebar,\n.perfect-scrollbar-on .main-panel {\n    height: 100%;\n    max-height: 100%;\n}\n\n.sidebar,\n.main-panel,\n.sidebar-wrapper {\n    -webkit-transition-property: top, bottom, width;\n    transition-property: top, bottom, width;\n    -webkit-transition-duration: .2s, .2s, .35s;\n    transition-duration: .2s, .2s, .35s;\n    -webkit-transition-timing-function: linear, linear, ease;\n    transition-timing-function: linear, linear, ease;\n    -webkit-overflow-scrolling: touch;\n}\n\n.perfect-scrollbar-on .sidebar .sidebar-wrapper,\n.sidebar .sidebar-wrapper,\n.perfect-scrollbar-on .main-panel,\n.main-panel {\n    overflow: hidden;\n}\n\n.perfect-scrollbar-off .sidebar .sidebar-wrapper,\n.perfect-scrollbar-off .main-panel {\n    overflow: auto;\n}\n\n.visible-on-sidebar-regular {\n    display: inline-block !important;\n}\n\n.visible-on-sidebar-mini {\n    display: none !important;\n}\n\n@media (min-width: 992px) {\n    .sidebar-mini .visible-on-sidebar-regular {\n        display: none !important;\n    }\n    .sidebar-mini .visible-on-sidebar-mini {\n        display: inline-block !important;\n    }\n    .sidebar-mini .sidebar,\n    .sidebar-mini .sidebar .sidebar-wrapper {\n        width: 80px;\n    }\n    .sidebar-mini .main-panel {\n        width: calc(100% - 80px);\n    }\n    .sidebar-mini .sidebar {\n        display: block;\n        font-weight: 200;\n        z-index: 9999;\n    }\n    .sidebar-mini .sidebar .logo a.logo-normal {\n        opacity: 0;\n        -webkit-transform: translate3d(-25px, 0, 0);\n        -moz-transform: translate3d(-25px, 0, 0);\n        -o-transform: translate3d(-25px, 0, 0);\n        -ms-transform: translate3d(-25px, 0, 0);\n        transform: translate3d(-25px, 0, 0);\n    }\n    .sidebar-mini .sidebar .sidebar-wrapper>.nav [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal,\n    .sidebar-mini .sidebar .sidebar-wrapper .user .info [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal,\n    .sidebar-mini .sidebar .sidebar-wrapper .user .info>a>span,\n    .sidebar-mini .sidebar .sidebar-wrapper>.nav li>a p {\n        -webkit-transform: translate3d(-25px, 0, 0);\n        -moz-transform: translate3d(-25px, 0, 0);\n        -o-transform: translate3d(-25px, 0, 0);\n        -ms-transform: translate3d(-25px, 0, 0);\n        transform: translate3d(-25px, 0, 0);\n        opacity: 0;\n    }\n    .sidebar-mini .sidebar:hover {\n        width: 260px;\n    }\n    .sidebar-mini .sidebar:hover .logo a.logo-normal {\n        opacity: 1;\n        -webkit-transform: translate3d(0px, 0, 0);\n        -moz-transform: translate3d(0px, 0, 0);\n        -o-transform: translate3d(0px, 0, 0);\n        -ms-transform: translate3d(0px, 0, 0);\n        transform: translate3d(0px, 0, 0);\n    }\n    .sidebar-mini .sidebar:hover .sidebar-wrapper {\n        width: 260px;\n    }\n    .sidebar-mini .sidebar:hover .sidebar-wrapper>.nav li>a p,\n    .sidebar-mini .sidebar:hover .sidebar-wrapper>.nav [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal,\n    .sidebar-mini .sidebar:hover .sidebar-wrapper .user .info [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal,\n    .sidebar-mini .sidebar:hover .sidebar-wrapper .user .info>a>span {\n        -webkit-transform: translate3d(0px, 0, 0);\n        -moz-transform: translate3d(0px, 0, 0);\n        -o-transform: translate3d(0px, 0, 0);\n        -ms-transform: translate3d(0px, 0, 0);\n        transform: translate3d(0px, 0, 0);\n        opacity: 1;\n    }\n}\n\n.btn,\n.navbar .navbar-nav>li>a.btn {\n    border: none;\n    border-radius: 3px;\n    position: relative;\n    padding: 12px 30px;\n    margin: 10px 1px;\n    font-size: 12px;\n    font-weight: 400;\n    text-transform: uppercase;\n    letter-spacing: 0;\n    will-change: box-shadow, transform;\n    transition: box-shadow 0.2s cubic-bezier(0.4, 0, 1, 1), background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.btn::-moz-focus-inner,\n.navbar .navbar-nav>li>a.btn::-moz-focus-inner {\n    border: 0;\n}\n\n.btn,\n.btn.btn-default,\n.navbar .navbar-nav>li>a.btn,\n.navbar .navbar-nav>li>a.btn.btn-default {\n    box-shadow: 0 2px 2px 0 rgba(153, 153, 153, 0.14), 0 3px 1px -2px rgba(153, 153, 153, 0.2), 0 1px 5px 0 rgba(153, 153, 153, 0.12);\n}\n\n.btn,\n.btn:hover,\n.btn:focus,\n.btn:active,\n.btn.active,\n.btn:active:focus,\n.btn:active:hover,\n.btn.active:focus,\n.btn.active:hover,\n.open>.btn.dropdown-toggle,\n.open>.btn.dropdown-toggle:focus,\n.open>.btn.dropdown-toggle:hover,\n.btn.btn-default,\n.btn.btn-default:hover,\n.btn.btn-default:focus,\n.btn.btn-default:active,\n.btn.btn-default.active,\n.btn.btn-default:active:focus,\n.btn.btn-default:active:hover,\n.btn.btn-default.active:focus,\n.btn.btn-default.active:hover,\n.open>.btn.btn-default.dropdown-toggle,\n.open>.btn.btn-default.dropdown-toggle:focus,\n.open>.btn.btn-default.dropdown-toggle:hover,\n.navbar .navbar-nav>li>a.btn,\n.navbar .navbar-nav>li>a.btn:hover,\n.navbar .navbar-nav>li>a.btn:focus,\n.navbar .navbar-nav>li>a.btn:active,\n.navbar .navbar-nav>li>a.btn.active,\n.navbar .navbar-nav>li>a.btn:active:focus,\n.navbar .navbar-nav>li>a.btn:active:hover,\n.navbar .navbar-nav>li>a.btn.active:focus,\n.navbar .navbar-nav>li>a.btn.active:hover,\n.open>.navbar .navbar-nav>li>a.btn.dropdown-toggle,\n.open>.navbar .navbar-nav>li>a.btn.dropdown-toggle:focus,\n.open>.navbar .navbar-nav>li>a.btn.dropdown-toggle:hover,\n.navbar .navbar-nav>li>a.btn.btn-default,\n.navbar .navbar-nav>li>a.btn.btn-default:hover,\n.navbar .navbar-nav>li>a.btn.btn-default:focus,\n.navbar .navbar-nav>li>a.btn.btn-default:active,\n.navbar .navbar-nav>li>a.btn.btn-default.active,\n.navbar .navbar-nav>li>a.btn.btn-default:active:focus,\n.navbar .navbar-nav>li>a.btn.btn-default:active:hover,\n.navbar .navbar-nav>li>a.btn.btn-default.active:focus,\n.navbar .navbar-nav>li>a.btn.btn-default.active:hover,\n.open>.navbar .navbar-nav>li>a.btn.btn-default.dropdown-toggle,\n.open>.navbar .navbar-nav>li>a.btn.btn-default.dropdown-toggle:focus,\n.open>.navbar .navbar-nav>li>a.btn.btn-default.dropdown-toggle:hover {\n    background-color: #999999;\n    color: #FFFFFF;\n}\n\n.btn:focus,\n.btn:active,\n.btn:hover,\n.btn.btn-default:focus,\n.btn.btn-default:active,\n.btn.btn-default:hover,\n.navbar .navbar-nav>li>a.btn:focus,\n.navbar .navbar-nav>li>a.btn:active,\n.navbar .navbar-nav>li>a.btn:hover,\n.navbar .navbar-nav>li>a.btn.btn-default:focus,\n.navbar .navbar-nav>li>a.btn.btn-default:active,\n.navbar .navbar-nav>li>a.btn.btn-default:hover {\n    box-shadow: 0 14px 26px -12px rgba(153, 153, 153, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(153, 153, 153, 0.2);\n}\n\n.btn.disabled,\n.btn.disabled:hover,\n.btn.disabled:focus,\n.btn.disabled.focus,\n.btn.disabled:active,\n.btn.disabled.active,\n.btn:disabled,\n.btn:disabled:hover,\n.btn:disabled:focus,\n.btn:disabled.focus,\n.btn:disabled:active,\n.btn:disabled.active,\n.btn[disabled],\n.btn[disabled]:hover,\n.btn[disabled]:focus,\n.btn[disabled].focus,\n.btn[disabled]:active,\n.btn[disabled].active,\nfieldset[disabled] .btn,\nfieldset[disabled] .btn:hover,\nfieldset[disabled] .btn:focus,\nfieldset[disabled] .btn.focus,\nfieldset[disabled] .btn:active,\nfieldset[disabled] .btn.active,\n.btn.btn-default.disabled,\n.btn.btn-default.disabled:hover,\n.btn.btn-default.disabled:focus,\n.btn.btn-default.disabled.focus,\n.btn.btn-default.disabled:active,\n.btn.btn-default.disabled.active,\n.btn.btn-default:disabled,\n.btn.btn-default:disabled:hover,\n.btn.btn-default:disabled:focus,\n.btn.btn-default:disabled.focus,\n.btn.btn-default:disabled:active,\n.btn.btn-default:disabled.active,\n.btn.btn-default[disabled],\n.btn.btn-default[disabled]:hover,\n.btn.btn-default[disabled]:focus,\n.btn.btn-default[disabled].focus,\n.btn.btn-default[disabled]:active,\n.btn.btn-default[disabled].active,\nfieldset[disabled] .btn.btn-default,\nfieldset[disabled] .btn.btn-default:hover,\nfieldset[disabled] .btn.btn-default:focus,\nfieldset[disabled] .btn.btn-default.focus,\nfieldset[disabled] .btn.btn-default:active,\nfieldset[disabled] .btn.btn-default.active,\n.navbar .navbar-nav>li>a.btn.disabled,\n.navbar .navbar-nav>li>a.btn.disabled:hover,\n.navbar .navbar-nav>li>a.btn.disabled:focus,\n.navbar .navbar-nav>li>a.btn.disabled.focus,\n.navbar .navbar-nav>li>a.btn.disabled:active,\n.navbar .navbar-nav>li>a.btn.disabled.active,\n.navbar .navbar-nav>li>a.btn:disabled,\n.navbar .navbar-nav>li>a.btn:disabled:hover,\n.navbar .navbar-nav>li>a.btn:disabled:focus,\n.navbar .navbar-nav>li>a.btn:disabled.focus,\n.navbar .navbar-nav>li>a.btn:disabled:active,\n.navbar .navbar-nav>li>a.btn:disabled.active,\n.navbar .navbar-nav>li>a.btn[disabled],\n.navbar .navbar-nav>li>a.btn[disabled]:hover,\n.navbar .navbar-nav>li>a.btn[disabled]:focus,\n.navbar .navbar-nav>li>a.btn[disabled].focus,\n.navbar .navbar-nav>li>a.btn[disabled]:active,\n.navbar .navbar-nav>li>a.btn[disabled].active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn:hover,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn:focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn:active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.active,\n.navbar .navbar-nav>li>a.btn.btn-default.disabled,\n.navbar .navbar-nav>li>a.btn.btn-default.disabled:hover,\n.navbar .navbar-nav>li>a.btn.btn-default.disabled:focus,\n.navbar .navbar-nav>li>a.btn.btn-default.disabled.focus,\n.navbar .navbar-nav>li>a.btn.btn-default.disabled:active,\n.navbar .navbar-nav>li>a.btn.btn-default.disabled.active,\n.navbar .navbar-nav>li>a.btn.btn-default:disabled,\n.navbar .navbar-nav>li>a.btn.btn-default:disabled:hover,\n.navbar .navbar-nav>li>a.btn.btn-default:disabled:focus,\n.navbar .navbar-nav>li>a.btn.btn-default:disabled.focus,\n.navbar .navbar-nav>li>a.btn.btn-default:disabled:active,\n.navbar .navbar-nav>li>a.btn.btn-default:disabled.active,\n.navbar .navbar-nav>li>a.btn.btn-default[disabled],\n.navbar .navbar-nav>li>a.btn.btn-default[disabled]:hover,\n.navbar .navbar-nav>li>a.btn.btn-default[disabled]:focus,\n.navbar .navbar-nav>li>a.btn.btn-default[disabled].focus,\n.navbar .navbar-nav>li>a.btn.btn-default[disabled]:active,\n.navbar .navbar-nav>li>a.btn.btn-default[disabled].active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-default,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-default:hover,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-default:focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-default.focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-default:active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-default.active {\n    box-shadow: none;\n}\n\n.btn.btn-simple,\n.btn.btn-default.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-default.btn-simple {\n    background-color: transparent;\n    color: #999999;\n    box-shadow: none;\n}\n\n.btn.btn-simple:hover,\n.btn.btn-simple:focus,\n.btn.btn-simple:active,\n.btn.btn-default.btn-simple:hover,\n.btn.btn-default.btn-simple:focus,\n.btn.btn-default.btn-simple:active,\n.navbar .navbar-nav>li>a.btn.btn-simple:hover,\n.navbar .navbar-nav>li>a.btn.btn-simple:focus,\n.navbar .navbar-nav>li>a.btn.btn-simple:active,\n.navbar .navbar-nav>li>a.btn.btn-default.btn-simple:hover,\n.navbar .navbar-nav>li>a.btn.btn-default.btn-simple:focus,\n.navbar .navbar-nav>li>a.btn.btn-default.btn-simple:active {\n    background-color: transparent;\n    color: #999999;\n}\n\n.btn.btn-primary,\n.navbar .navbar-nav>li>a.btn.btn-primary {\n    box-shadow: 0 2px 2px 0 rgba(156, 39, 176, 0.14), 0 3px 1px -2px rgba(156, 39, 176, 0.2), 0 1px 5px 0 rgba(156, 39, 176, 0.12);\n}\n\n.btn.btn-primary,\n.btn.btn-primary:hover,\n.btn.btn-primary:focus,\n.btn.btn-primary:active,\n.btn.btn-primary.active,\n.btn.btn-primary:active:focus,\n.btn.btn-primary:active:hover,\n.btn.btn-primary.active:focus,\n.btn.btn-primary.active:hover,\n.open>.btn.btn-primary.dropdown-toggle,\n.open>.btn.btn-primary.dropdown-toggle:focus,\n.open>.btn.btn-primary.dropdown-toggle:hover,\n.navbar .navbar-nav>li>a.btn.btn-primary,\n.navbar .navbar-nav>li>a.btn.btn-primary:hover,\n.navbar .navbar-nav>li>a.btn.btn-primary:focus,\n.navbar .navbar-nav>li>a.btn.btn-primary:active,\n.navbar .navbar-nav>li>a.btn.btn-primary.active,\n.navbar .navbar-nav>li>a.btn.btn-primary:active:focus,\n.navbar .navbar-nav>li>a.btn.btn-primary:active:hover,\n.navbar .navbar-nav>li>a.btn.btn-primary.active:focus,\n.navbar .navbar-nav>li>a.btn.btn-primary.active:hover,\n.open>.navbar .navbar-nav>li>a.btn.btn-primary.dropdown-toggle,\n.open>.navbar .navbar-nav>li>a.btn.btn-primary.dropdown-toggle:focus,\n.open>.navbar .navbar-nav>li>a.btn.btn-primary.dropdown-toggle:hover {\n    background-color: #9c27b0;\n    color: #FFFFFF;\n}\n\n.btn.btn-primary:focus,\n.btn.btn-primary:active,\n.btn.btn-primary:hover,\n.navbar .navbar-nav>li>a.btn.btn-primary:focus,\n.navbar .navbar-nav>li>a.btn.btn-primary:active,\n.navbar .navbar-nav>li>a.btn.btn-primary:hover {\n    box-shadow: 0 14px 26px -12px rgba(156, 39, 176, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(156, 39, 176, 0.2);\n}\n\n.btn.btn-primary.disabled,\n.btn.btn-primary.disabled:hover,\n.btn.btn-primary.disabled:focus,\n.btn.btn-primary.disabled.focus,\n.btn.btn-primary.disabled:active,\n.btn.btn-primary.disabled.active,\n.btn.btn-primary:disabled,\n.btn.btn-primary:disabled:hover,\n.btn.btn-primary:disabled:focus,\n.btn.btn-primary:disabled.focus,\n.btn.btn-primary:disabled:active,\n.btn.btn-primary:disabled.active,\n.btn.btn-primary[disabled],\n.btn.btn-primary[disabled]:hover,\n.btn.btn-primary[disabled]:focus,\n.btn.btn-primary[disabled].focus,\n.btn.btn-primary[disabled]:active,\n.btn.btn-primary[disabled].active,\nfieldset[disabled] .btn.btn-primary,\nfieldset[disabled] .btn.btn-primary:hover,\nfieldset[disabled] .btn.btn-primary:focus,\nfieldset[disabled] .btn.btn-primary.focus,\nfieldset[disabled] .btn.btn-primary:active,\nfieldset[disabled] .btn.btn-primary.active,\n.navbar .navbar-nav>li>a.btn.btn-primary.disabled,\n.navbar .navbar-nav>li>a.btn.btn-primary.disabled:hover,\n.navbar .navbar-nav>li>a.btn.btn-primary.disabled:focus,\n.navbar .navbar-nav>li>a.btn.btn-primary.disabled.focus,\n.navbar .navbar-nav>li>a.btn.btn-primary.disabled:active,\n.navbar .navbar-nav>li>a.btn.btn-primary.disabled.active,\n.navbar .navbar-nav>li>a.btn.btn-primary:disabled,\n.navbar .navbar-nav>li>a.btn.btn-primary:disabled:hover,\n.navbar .navbar-nav>li>a.btn.btn-primary:disabled:focus,\n.navbar .navbar-nav>li>a.btn.btn-primary:disabled.focus,\n.navbar .navbar-nav>li>a.btn.btn-primary:disabled:active,\n.navbar .navbar-nav>li>a.btn.btn-primary:disabled.active,\n.navbar .navbar-nav>li>a.btn.btn-primary[disabled],\n.navbar .navbar-nav>li>a.btn.btn-primary[disabled]:hover,\n.navbar .navbar-nav>li>a.btn.btn-primary[disabled]:focus,\n.navbar .navbar-nav>li>a.btn.btn-primary[disabled].focus,\n.navbar .navbar-nav>li>a.btn.btn-primary[disabled]:active,\n.navbar .navbar-nav>li>a.btn.btn-primary[disabled].active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-primary,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-primary:hover,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-primary:focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-primary.focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-primary:active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-primary.active {\n    box-shadow: none;\n}\n\n.btn.btn-primary.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-primary.btn-simple {\n    background-color: transparent;\n    color: #9c27b0;\n    box-shadow: none;\n}\n\n.btn.btn-primary.btn-simple:hover,\n.btn.btn-primary.btn-simple:focus,\n.btn.btn-primary.btn-simple:active,\n.navbar .navbar-nav>li>a.btn.btn-primary.btn-simple:hover,\n.navbar .navbar-nav>li>a.btn.btn-primary.btn-simple:focus,\n.navbar .navbar-nav>li>a.btn.btn-primary.btn-simple:active {\n    background-color: transparent;\n    color: #9c27b0;\n}\n\n.btn.btn-info,\n.navbar .navbar-nav>li>a.btn.btn-info {\n    box-shadow: 0 2px 2px 0 rgba(0, 188, 212, 0.14), 0 3px 1px -2px rgba(0, 188, 212, 0.2), 0 1px 5px 0 rgba(0, 188, 212, 0.12);\n}\n\n.btn.btn-info,\n.btn.btn-info:hover,\n.btn.btn-info:focus,\n.btn.btn-info:active,\n.btn.btn-info.active,\n.btn.btn-info:active:focus,\n.btn.btn-info:active:hover,\n.btn.btn-info.active:focus,\n.btn.btn-info.active:hover,\n.open>.btn.btn-info.dropdown-toggle,\n.open>.btn.btn-info.dropdown-toggle:focus,\n.open>.btn.btn-info.dropdown-toggle:hover,\n.navbar .navbar-nav>li>a.btn.btn-info,\n.navbar .navbar-nav>li>a.btn.btn-info:hover,\n.navbar .navbar-nav>li>a.btn.btn-info:focus,\n.navbar .navbar-nav>li>a.btn.btn-info:active,\n.navbar .navbar-nav>li>a.btn.btn-info.active,\n.navbar .navbar-nav>li>a.btn.btn-info:active:focus,\n.navbar .navbar-nav>li>a.btn.btn-info:active:hover,\n.navbar .navbar-nav>li>a.btn.btn-info.active:focus,\n.navbar .navbar-nav>li>a.btn.btn-info.active:hover,\n.open>.navbar .navbar-nav>li>a.btn.btn-info.dropdown-toggle,\n.open>.navbar .navbar-nav>li>a.btn.btn-info.dropdown-toggle:focus,\n.open>.navbar .navbar-nav>li>a.btn.btn-info.dropdown-toggle:hover {\n    background-color: #00bcd4;\n    color: #FFFFFF;\n}\n\n.btn.btn-info:focus,\n.btn.btn-info:active,\n.btn.btn-info:hover,\n.navbar .navbar-nav>li>a.btn.btn-info:focus,\n.navbar .navbar-nav>li>a.btn.btn-info:active,\n.navbar .navbar-nav>li>a.btn.btn-info:hover {\n    box-shadow: 0 14px 26px -12px rgba(0, 188, 212, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 188, 212, 0.2);\n}\n\n.btn.btn-info.disabled,\n.btn.btn-info.disabled:hover,\n.btn.btn-info.disabled:focus,\n.btn.btn-info.disabled.focus,\n.btn.btn-info.disabled:active,\n.btn.btn-info.disabled.active,\n.btn.btn-info:disabled,\n.btn.btn-info:disabled:hover,\n.btn.btn-info:disabled:focus,\n.btn.btn-info:disabled.focus,\n.btn.btn-info:disabled:active,\n.btn.btn-info:disabled.active,\n.btn.btn-info[disabled],\n.btn.btn-info[disabled]:hover,\n.btn.btn-info[disabled]:focus,\n.btn.btn-info[disabled].focus,\n.btn.btn-info[disabled]:active,\n.btn.btn-info[disabled].active,\nfieldset[disabled] .btn.btn-info,\nfieldset[disabled] .btn.btn-info:hover,\nfieldset[disabled] .btn.btn-info:focus,\nfieldset[disabled] .btn.btn-info.focus,\nfieldset[disabled] .btn.btn-info:active,\nfieldset[disabled] .btn.btn-info.active,\n.navbar .navbar-nav>li>a.btn.btn-info.disabled,\n.navbar .navbar-nav>li>a.btn.btn-info.disabled:hover,\n.navbar .navbar-nav>li>a.btn.btn-info.disabled:focus,\n.navbar .navbar-nav>li>a.btn.btn-info.disabled.focus,\n.navbar .navbar-nav>li>a.btn.btn-info.disabled:active,\n.navbar .navbar-nav>li>a.btn.btn-info.disabled.active,\n.navbar .navbar-nav>li>a.btn.btn-info:disabled,\n.navbar .navbar-nav>li>a.btn.btn-info:disabled:hover,\n.navbar .navbar-nav>li>a.btn.btn-info:disabled:focus,\n.navbar .navbar-nav>li>a.btn.btn-info:disabled.focus,\n.navbar .navbar-nav>li>a.btn.btn-info:disabled:active,\n.navbar .navbar-nav>li>a.btn.btn-info:disabled.active,\n.navbar .navbar-nav>li>a.btn.btn-info[disabled],\n.navbar .navbar-nav>li>a.btn.btn-info[disabled]:hover,\n.navbar .navbar-nav>li>a.btn.btn-info[disabled]:focus,\n.navbar .navbar-nav>li>a.btn.btn-info[disabled].focus,\n.navbar .navbar-nav>li>a.btn.btn-info[disabled]:active,\n.navbar .navbar-nav>li>a.btn.btn-info[disabled].active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-info,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-info:hover,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-info:focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-info.focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-info:active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-info.active {\n    box-shadow: none;\n}\n\n.btn.btn-info.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-info.btn-simple {\n    background-color: transparent;\n    color: #00bcd4;\n    box-shadow: none;\n}\n\n.btn.btn-info.btn-simple:hover,\n.btn.btn-info.btn-simple:focus,\n.btn.btn-info.btn-simple:active,\n.navbar .navbar-nav>li>a.btn.btn-info.btn-simple:hover,\n.navbar .navbar-nav>li>a.btn.btn-info.btn-simple:focus,\n.navbar .navbar-nav>li>a.btn.btn-info.btn-simple:active {\n    background-color: transparent;\n    color: #00bcd4;\n}\n\n.btn.btn-success,\n.navbar .navbar-nav>li>a.btn.btn-success {\n    box-shadow: 0 2px 2px 0 rgba(76, 175, 80, 0.14), 0 3px 1px -2px rgba(76, 175, 80, 0.2), 0 1px 5px 0 rgba(76, 175, 80, 0.12);\n}\n\n.btn.btn-success,\n.btn.btn-success:hover,\n.btn.btn-success:focus,\n.btn.btn-success:active,\n.btn.btn-success.active,\n.btn.btn-success:active:focus,\n.btn.btn-success:active:hover,\n.btn.btn-success.active:focus,\n.btn.btn-success.active:hover,\n.open>.btn.btn-success.dropdown-toggle,\n.open>.btn.btn-success.dropdown-toggle:focus,\n.open>.btn.btn-success.dropdown-toggle:hover,\n.navbar .navbar-nav>li>a.btn.btn-success,\n.navbar .navbar-nav>li>a.btn.btn-success:hover,\n.navbar .navbar-nav>li>a.btn.btn-success:focus,\n.navbar .navbar-nav>li>a.btn.btn-success:active,\n.navbar .navbar-nav>li>a.btn.btn-success.active,\n.navbar .navbar-nav>li>a.btn.btn-success:active:focus,\n.navbar .navbar-nav>li>a.btn.btn-success:active:hover,\n.navbar .navbar-nav>li>a.btn.btn-success.active:focus,\n.navbar .navbar-nav>li>a.btn.btn-success.active:hover,\n.open>.navbar .navbar-nav>li>a.btn.btn-success.dropdown-toggle,\n.open>.navbar .navbar-nav>li>a.btn.btn-success.dropdown-toggle:focus,\n.open>.navbar .navbar-nav>li>a.btn.btn-success.dropdown-toggle:hover {\n    background-color: #4caf50;\n    color: #FFFFFF;\n}\n\n.btn.btn-success:focus,\n.btn.btn-success:active,\n.btn.btn-success:hover,\n.navbar .navbar-nav>li>a.btn.btn-success:focus,\n.navbar .navbar-nav>li>a.btn.btn-success:active,\n.navbar .navbar-nav>li>a.btn.btn-success:hover {\n    box-shadow: 0 14px 26px -12px rgba(76, 175, 80, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(76, 175, 80, 0.2);\n}\n\n.btn.btn-success.disabled,\n.btn.btn-success.disabled:hover,\n.btn.btn-success.disabled:focus,\n.btn.btn-success.disabled.focus,\n.btn.btn-success.disabled:active,\n.btn.btn-success.disabled.active,\n.btn.btn-success:disabled,\n.btn.btn-success:disabled:hover,\n.btn.btn-success:disabled:focus,\n.btn.btn-success:disabled.focus,\n.btn.btn-success:disabled:active,\n.btn.btn-success:disabled.active,\n.btn.btn-success[disabled],\n.btn.btn-success[disabled]:hover,\n.btn.btn-success[disabled]:focus,\n.btn.btn-success[disabled].focus,\n.btn.btn-success[disabled]:active,\n.btn.btn-success[disabled].active,\nfieldset[disabled] .btn.btn-success,\nfieldset[disabled] .btn.btn-success:hover,\nfieldset[disabled] .btn.btn-success:focus,\nfieldset[disabled] .btn.btn-success.focus,\nfieldset[disabled] .btn.btn-success:active,\nfieldset[disabled] .btn.btn-success.active,\n.navbar .navbar-nav>li>a.btn.btn-success.disabled,\n.navbar .navbar-nav>li>a.btn.btn-success.disabled:hover,\n.navbar .navbar-nav>li>a.btn.btn-success.disabled:focus,\n.navbar .navbar-nav>li>a.btn.btn-success.disabled.focus,\n.navbar .navbar-nav>li>a.btn.btn-success.disabled:active,\n.navbar .navbar-nav>li>a.btn.btn-success.disabled.active,\n.navbar .navbar-nav>li>a.btn.btn-success:disabled,\n.navbar .navbar-nav>li>a.btn.btn-success:disabled:hover,\n.navbar .navbar-nav>li>a.btn.btn-success:disabled:focus,\n.navbar .navbar-nav>li>a.btn.btn-success:disabled.focus,\n.navbar .navbar-nav>li>a.btn.btn-success:disabled:active,\n.navbar .navbar-nav>li>a.btn.btn-success:disabled.active,\n.navbar .navbar-nav>li>a.btn.btn-success[disabled],\n.navbar .navbar-nav>li>a.btn.btn-success[disabled]:hover,\n.navbar .navbar-nav>li>a.btn.btn-success[disabled]:focus,\n.navbar .navbar-nav>li>a.btn.btn-success[disabled].focus,\n.navbar .navbar-nav>li>a.btn.btn-success[disabled]:active,\n.navbar .navbar-nav>li>a.btn.btn-success[disabled].active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-success,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-success:hover,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-success:focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-success.focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-success:active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-success.active {\n    box-shadow: none;\n}\n\n.btn.btn-success.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-success.btn-simple {\n    background-color: transparent;\n    color: #4caf50;\n    box-shadow: none;\n}\n\n.btn.btn-success.btn-simple:hover,\n.btn.btn-success.btn-simple:focus,\n.btn.btn-success.btn-simple:active,\n.navbar .navbar-nav>li>a.btn.btn-success.btn-simple:hover,\n.navbar .navbar-nav>li>a.btn.btn-success.btn-simple:focus,\n.navbar .navbar-nav>li>a.btn.btn-success.btn-simple:active {\n    background-color: transparent;\n    color: #4caf50;\n}\n\n.btn.btn-warning,\n.navbar .navbar-nav>li>a.btn.btn-warning {\n    box-shadow: 0 2px 2px 0 rgba(255, 152, 0, 0.14), 0 3px 1px -2px rgba(255, 152, 0, 0.2), 0 1px 5px 0 rgba(255, 152, 0, 0.12);\n}\n\n.btn.btn-warning,\n.btn.btn-warning:hover,\n.btn.btn-warning:focus,\n.btn.btn-warning:active,\n.btn.btn-warning.active,\n.btn.btn-warning:active:focus,\n.btn.btn-warning:active:hover,\n.btn.btn-warning.active:focus,\n.btn.btn-warning.active:hover,\n.open>.btn.btn-warning.dropdown-toggle,\n.open>.btn.btn-warning.dropdown-toggle:focus,\n.open>.btn.btn-warning.dropdown-toggle:hover,\n.navbar .navbar-nav>li>a.btn.btn-warning,\n.navbar .navbar-nav>li>a.btn.btn-warning:hover,\n.navbar .navbar-nav>li>a.btn.btn-warning:focus,\n.navbar .navbar-nav>li>a.btn.btn-warning:active,\n.navbar .navbar-nav>li>a.btn.btn-warning.active,\n.navbar .navbar-nav>li>a.btn.btn-warning:active:focus,\n.navbar .navbar-nav>li>a.btn.btn-warning:active:hover,\n.navbar .navbar-nav>li>a.btn.btn-warning.active:focus,\n.navbar .navbar-nav>li>a.btn.btn-warning.active:hover,\n.open>.navbar .navbar-nav>li>a.btn.btn-warning.dropdown-toggle,\n.open>.navbar .navbar-nav>li>a.btn.btn-warning.dropdown-toggle:focus,\n.open>.navbar .navbar-nav>li>a.btn.btn-warning.dropdown-toggle:hover {\n    background-color: #ff9800;\n    color: #FFFFFF;\n}\n\n.btn.btn-warning:focus,\n.btn.btn-warning:active,\n.btn.btn-warning:hover,\n.navbar .navbar-nav>li>a.btn.btn-warning:focus,\n.navbar .navbar-nav>li>a.btn.btn-warning:active,\n.navbar .navbar-nav>li>a.btn.btn-warning:hover {\n    box-shadow: 0 14px 26px -12px rgba(255, 152, 0, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(255, 152, 0, 0.2);\n}\n\n.btn.btn-warning.disabled,\n.btn.btn-warning.disabled:hover,\n.btn.btn-warning.disabled:focus,\n.btn.btn-warning.disabled.focus,\n.btn.btn-warning.disabled:active,\n.btn.btn-warning.disabled.active,\n.btn.btn-warning:disabled,\n.btn.btn-warning:disabled:hover,\n.btn.btn-warning:disabled:focus,\n.btn.btn-warning:disabled.focus,\n.btn.btn-warning:disabled:active,\n.btn.btn-warning:disabled.active,\n.btn.btn-warning[disabled],\n.btn.btn-warning[disabled]:hover,\n.btn.btn-warning[disabled]:focus,\n.btn.btn-warning[disabled].focus,\n.btn.btn-warning[disabled]:active,\n.btn.btn-warning[disabled].active,\nfieldset[disabled] .btn.btn-warning,\nfieldset[disabled] .btn.btn-warning:hover,\nfieldset[disabled] .btn.btn-warning:focus,\nfieldset[disabled] .btn.btn-warning.focus,\nfieldset[disabled] .btn.btn-warning:active,\nfieldset[disabled] .btn.btn-warning.active,\n.navbar .navbar-nav>li>a.btn.btn-warning.disabled,\n.navbar .navbar-nav>li>a.btn.btn-warning.disabled:hover,\n.navbar .navbar-nav>li>a.btn.btn-warning.disabled:focus,\n.navbar .navbar-nav>li>a.btn.btn-warning.disabled.focus,\n.navbar .navbar-nav>li>a.btn.btn-warning.disabled:active,\n.navbar .navbar-nav>li>a.btn.btn-warning.disabled.active,\n.navbar .navbar-nav>li>a.btn.btn-warning:disabled,\n.navbar .navbar-nav>li>a.btn.btn-warning:disabled:hover,\n.navbar .navbar-nav>li>a.btn.btn-warning:disabled:focus,\n.navbar .navbar-nav>li>a.btn.btn-warning:disabled.focus,\n.navbar .navbar-nav>li>a.btn.btn-warning:disabled:active,\n.navbar .navbar-nav>li>a.btn.btn-warning:disabled.active,\n.navbar .navbar-nav>li>a.btn.btn-warning[disabled],\n.navbar .navbar-nav>li>a.btn.btn-warning[disabled]:hover,\n.navbar .navbar-nav>li>a.btn.btn-warning[disabled]:focus,\n.navbar .navbar-nav>li>a.btn.btn-warning[disabled].focus,\n.navbar .navbar-nav>li>a.btn.btn-warning[disabled]:active,\n.navbar .navbar-nav>li>a.btn.btn-warning[disabled].active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-warning,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-warning:hover,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-warning:focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-warning.focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-warning:active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-warning.active {\n    box-shadow: none;\n}\n\n.btn.btn-warning.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-warning.btn-simple {\n    background-color: transparent;\n    color: #ff9800;\n    box-shadow: none;\n}\n\n.btn.btn-warning.btn-simple:hover,\n.btn.btn-warning.btn-simple:focus,\n.btn.btn-warning.btn-simple:active,\n.navbar .navbar-nav>li>a.btn.btn-warning.btn-simple:hover,\n.navbar .navbar-nav>li>a.btn.btn-warning.btn-simple:focus,\n.navbar .navbar-nav>li>a.btn.btn-warning.btn-simple:active {\n    background-color: transparent;\n    color: #ff9800;\n}\n\n.btn.btn-danger,\n.navbar .navbar-nav>li>a.btn.btn-danger {\n    box-shadow: 0 2px 2px 0 rgba(244, 67, 54, 0.14), 0 3px 1px -2px rgba(244, 67, 54, 0.2), 0 1px 5px 0 rgba(244, 67, 54, 0.12);\n}\n\n.btn.btn-danger,\n.btn.btn-danger:hover,\n.btn.btn-danger:focus,\n.btn.btn-danger:active,\n.btn.btn-danger.active,\n.btn.btn-danger:active:focus,\n.btn.btn-danger:active:hover,\n.btn.btn-danger.active:focus,\n.btn.btn-danger.active:hover,\n.open>.btn.btn-danger.dropdown-toggle,\n.open>.btn.btn-danger.dropdown-toggle:focus,\n.open>.btn.btn-danger.dropdown-toggle:hover,\n.navbar .navbar-nav>li>a.btn.btn-danger,\n.navbar .navbar-nav>li>a.btn.btn-danger:hover,\n.navbar .navbar-nav>li>a.btn.btn-danger:focus,\n.navbar .navbar-nav>li>a.btn.btn-danger:active,\n.navbar .navbar-nav>li>a.btn.btn-danger.active,\n.navbar .navbar-nav>li>a.btn.btn-danger:active:focus,\n.navbar .navbar-nav>li>a.btn.btn-danger:active:hover,\n.navbar .navbar-nav>li>a.btn.btn-danger.active:focus,\n.navbar .navbar-nav>li>a.btn.btn-danger.active:hover,\n.open>.navbar .navbar-nav>li>a.btn.btn-danger.dropdown-toggle,\n.open>.navbar .navbar-nav>li>a.btn.btn-danger.dropdown-toggle:focus,\n.open>.navbar .navbar-nav>li>a.btn.btn-danger.dropdown-toggle:hover {\n    background-color: #f44336;\n    color: #FFFFFF;\n}\n\n.btn.btn-danger:focus,\n.btn.btn-danger:active,\n.btn.btn-danger:hover,\n.navbar .navbar-nav>li>a.btn.btn-danger:focus,\n.navbar .navbar-nav>li>a.btn.btn-danger:active,\n.navbar .navbar-nav>li>a.btn.btn-danger:hover {\n    box-shadow: 0 14px 26px -12px rgba(244, 67, 54, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(244, 67, 54, 0.2);\n}\n\n.btn.btn-danger.disabled,\n.btn.btn-danger.disabled:hover,\n.btn.btn-danger.disabled:focus,\n.btn.btn-danger.disabled.focus,\n.btn.btn-danger.disabled:active,\n.btn.btn-danger.disabled.active,\n.btn.btn-danger:disabled,\n.btn.btn-danger:disabled:hover,\n.btn.btn-danger:disabled:focus,\n.btn.btn-danger:disabled.focus,\n.btn.btn-danger:disabled:active,\n.btn.btn-danger:disabled.active,\n.btn.btn-danger[disabled],\n.btn.btn-danger[disabled]:hover,\n.btn.btn-danger[disabled]:focus,\n.btn.btn-danger[disabled].focus,\n.btn.btn-danger[disabled]:active,\n.btn.btn-danger[disabled].active,\nfieldset[disabled] .btn.btn-danger,\nfieldset[disabled] .btn.btn-danger:hover,\nfieldset[disabled] .btn.btn-danger:focus,\nfieldset[disabled] .btn.btn-danger.focus,\nfieldset[disabled] .btn.btn-danger:active,\nfieldset[disabled] .btn.btn-danger.active,\n.navbar .navbar-nav>li>a.btn.btn-danger.disabled,\n.navbar .navbar-nav>li>a.btn.btn-danger.disabled:hover,\n.navbar .navbar-nav>li>a.btn.btn-danger.disabled:focus,\n.navbar .navbar-nav>li>a.btn.btn-danger.disabled.focus,\n.navbar .navbar-nav>li>a.btn.btn-danger.disabled:active,\n.navbar .navbar-nav>li>a.btn.btn-danger.disabled.active,\n.navbar .navbar-nav>li>a.btn.btn-danger:disabled,\n.navbar .navbar-nav>li>a.btn.btn-danger:disabled:hover,\n.navbar .navbar-nav>li>a.btn.btn-danger:disabled:focus,\n.navbar .navbar-nav>li>a.btn.btn-danger:disabled.focus,\n.navbar .navbar-nav>li>a.btn.btn-danger:disabled:active,\n.navbar .navbar-nav>li>a.btn.btn-danger:disabled.active,\n.navbar .navbar-nav>li>a.btn.btn-danger[disabled],\n.navbar .navbar-nav>li>a.btn.btn-danger[disabled]:hover,\n.navbar .navbar-nav>li>a.btn.btn-danger[disabled]:focus,\n.navbar .navbar-nav>li>a.btn.btn-danger[disabled].focus,\n.navbar .navbar-nav>li>a.btn.btn-danger[disabled]:active,\n.navbar .navbar-nav>li>a.btn.btn-danger[disabled].active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-danger,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-danger:hover,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-danger:focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-danger.focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-danger:active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-danger.active {\n    box-shadow: none;\n}\n\n.btn.btn-danger.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-danger.btn-simple {\n    background-color: transparent;\n    color: #f44336;\n    box-shadow: none;\n}\n\n.btn.btn-danger.btn-simple:hover,\n.btn.btn-danger.btn-simple:focus,\n.btn.btn-danger.btn-simple:active,\n.navbar .navbar-nav>li>a.btn.btn-danger.btn-simple:hover,\n.navbar .navbar-nav>li>a.btn.btn-danger.btn-simple:focus,\n.navbar .navbar-nav>li>a.btn.btn-danger.btn-simple:active {\n    background-color: transparent;\n    color: #f44336;\n}\n\n.btn.btn-rose,\n.navbar .navbar-nav>li>a.btn.btn-rose {\n    box-shadow: 0 2px 2px 0 rgba(233, 30, 99, 0.14), 0 3px 1px -2px rgba(233, 30, 99, 0.2), 0 1px 5px 0 rgba(233, 30, 99, 0.12);\n}\n\n.btn.btn-rose,\n.btn.btn-rose:hover,\n.btn.btn-rose:focus,\n.btn.btn-rose:active,\n.btn.btn-rose.active,\n.btn.btn-rose:active:focus,\n.btn.btn-rose:active:hover,\n.btn.btn-rose.active:focus,\n.btn.btn-rose.active:hover,\n.open>.btn.btn-rose.dropdown-toggle,\n.open>.btn.btn-rose.dropdown-toggle:focus,\n.open>.btn.btn-rose.dropdown-toggle:hover,\n.navbar .navbar-nav>li>a.btn.btn-rose,\n.navbar .navbar-nav>li>a.btn.btn-rose:hover,\n.navbar .navbar-nav>li>a.btn.btn-rose:focus,\n.navbar .navbar-nav>li>a.btn.btn-rose:active,\n.navbar .navbar-nav>li>a.btn.btn-rose.active,\n.navbar .navbar-nav>li>a.btn.btn-rose:active:focus,\n.navbar .navbar-nav>li>a.btn.btn-rose:active:hover,\n.navbar .navbar-nav>li>a.btn.btn-rose.active:focus,\n.navbar .navbar-nav>li>a.btn.btn-rose.active:hover,\n.open>.navbar .navbar-nav>li>a.btn.btn-rose.dropdown-toggle,\n.open>.navbar .navbar-nav>li>a.btn.btn-rose.dropdown-toggle:focus,\n.open>.navbar .navbar-nav>li>a.btn.btn-rose.dropdown-toggle:hover {\n    background-color: #e91e63;\n    color: #FFFFFF;\n}\n\n.btn.btn-rose:focus,\n.btn.btn-rose:active,\n.btn.btn-rose:hover,\n.navbar .navbar-nav>li>a.btn.btn-rose:focus,\n.navbar .navbar-nav>li>a.btn.btn-rose:active,\n.navbar .navbar-nav>li>a.btn.btn-rose:hover {\n    box-shadow: 0 14px 26px -12px rgba(233, 30, 99, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(233, 30, 99, 0.2);\n}\n\n.btn.btn-rose.disabled,\n.btn.btn-rose.disabled:hover,\n.btn.btn-rose.disabled:focus,\n.btn.btn-rose.disabled.focus,\n.btn.btn-rose.disabled:active,\n.btn.btn-rose.disabled.active,\n.btn.btn-rose:disabled,\n.btn.btn-rose:disabled:hover,\n.btn.btn-rose:disabled:focus,\n.btn.btn-rose:disabled.focus,\n.btn.btn-rose:disabled:active,\n.btn.btn-rose:disabled.active,\n.btn.btn-rose[disabled],\n.btn.btn-rose[disabled]:hover,\n.btn.btn-rose[disabled]:focus,\n.btn.btn-rose[disabled].focus,\n.btn.btn-rose[disabled]:active,\n.btn.btn-rose[disabled].active,\nfieldset[disabled] .btn.btn-rose,\nfieldset[disabled] .btn.btn-rose:hover,\nfieldset[disabled] .btn.btn-rose:focus,\nfieldset[disabled] .btn.btn-rose.focus,\nfieldset[disabled] .btn.btn-rose:active,\nfieldset[disabled] .btn.btn-rose.active,\n.navbar .navbar-nav>li>a.btn.btn-rose.disabled,\n.navbar .navbar-nav>li>a.btn.btn-rose.disabled:hover,\n.navbar .navbar-nav>li>a.btn.btn-rose.disabled:focus,\n.navbar .navbar-nav>li>a.btn.btn-rose.disabled.focus,\n.navbar .navbar-nav>li>a.btn.btn-rose.disabled:active,\n.navbar .navbar-nav>li>a.btn.btn-rose.disabled.active,\n.navbar .navbar-nav>li>a.btn.btn-rose:disabled,\n.navbar .navbar-nav>li>a.btn.btn-rose:disabled:hover,\n.navbar .navbar-nav>li>a.btn.btn-rose:disabled:focus,\n.navbar .navbar-nav>li>a.btn.btn-rose:disabled.focus,\n.navbar .navbar-nav>li>a.btn.btn-rose:disabled:active,\n.navbar .navbar-nav>li>a.btn.btn-rose:disabled.active,\n.navbar .navbar-nav>li>a.btn.btn-rose[disabled],\n.navbar .navbar-nav>li>a.btn.btn-rose[disabled]:hover,\n.navbar .navbar-nav>li>a.btn.btn-rose[disabled]:focus,\n.navbar .navbar-nav>li>a.btn.btn-rose[disabled].focus,\n.navbar .navbar-nav>li>a.btn.btn-rose[disabled]:active,\n.navbar .navbar-nav>li>a.btn.btn-rose[disabled].active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-rose,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-rose:hover,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-rose:focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-rose.focus,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-rose:active,\nfieldset[disabled] .navbar .navbar-nav>li>a.btn.btn-rose.active {\n    box-shadow: none;\n}\n\n.btn.btn-rose.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-rose.btn-simple {\n    background-color: transparent;\n    color: #e91e63;\n    box-shadow: none;\n}\n\n.btn.btn-rose.btn-simple:hover,\n.btn.btn-rose.btn-simple:focus,\n.btn.btn-rose.btn-simple:active,\n.navbar .navbar-nav>li>a.btn.btn-rose.btn-simple:hover,\n.navbar .navbar-nav>li>a.btn.btn-rose.btn-simple:focus,\n.navbar .navbar-nav>li>a.btn.btn-rose.btn-simple:active {\n    background-color: transparent;\n    color: #e91e63;\n}\n\n.btn.btn-white,\n.btn.btn-white:focus,\n.btn.btn-white:hover,\n.navbar .navbar-nav>li>a.btn.btn-white,\n.navbar .navbar-nav>li>a.btn.btn-white:focus,\n.navbar .navbar-nav>li>a.btn.btn-white:hover {\n    background-color: #FFFFFF;\n    color: #999999;\n}\n\n.btn.btn-white.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-white.btn-simple {\n    color: #FFFFFF;\n    background: transparent;\n    box-shadow: none;\n}\n\n.btn.btn-facebook,\n.navbar .navbar-nav>li>a.btn.btn-facebook {\n    background-color: #3b5998;\n    color: #fff;\n    box-shadow: 0 2px 2px 0 rgba(59, 89, 152, 0.14), 0 3px 1px -2px rgba(59, 89, 152, 0.2), 0 1px 5px 0 rgba(59, 89, 152, 0.12);\n}\n\n.btn.btn-facebook:focus,\n.btn.btn-facebook:active,\n.btn.btn-facebook:hover,\n.navbar .navbar-nav>li>a.btn.btn-facebook:focus,\n.navbar .navbar-nav>li>a.btn.btn-facebook:active,\n.navbar .navbar-nav>li>a.btn.btn-facebook:hover {\n    background-color: #3b5998;\n    color: #fff;\n    box-shadow: 0 14px 26px -12px rgba(59, 89, 152, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(59, 89, 152, 0.2);\n}\n\n.btn.btn-facebook.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-facebook.btn-simple {\n    color: #3b5998;\n    background-color: transparent;\n    box-shadow: none;\n}\n\n.btn.btn-twitter,\n.navbar .navbar-nav>li>a.btn.btn-twitter {\n    background-color: #55acee;\n    color: #fff;\n    box-shadow: 0 2px 2px 0 rgba(85, 172, 238, 0.14), 0 3px 1px -2px rgba(85, 172, 238, 0.2), 0 1px 5px 0 rgba(85, 172, 238, 0.12);\n}\n\n.btn.btn-twitter:focus,\n.btn.btn-twitter:active,\n.btn.btn-twitter:hover,\n.navbar .navbar-nav>li>a.btn.btn-twitter:focus,\n.navbar .navbar-nav>li>a.btn.btn-twitter:active,\n.navbar .navbar-nav>li>a.btn.btn-twitter:hover {\n    background-color: #55acee;\n    color: #fff;\n    box-shadow: 0 14px 26px -12px rgba(85, 172, 238, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(85, 172, 238, 0.2);\n}\n\n.btn.btn-twitter.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-twitter.btn-simple {\n    color: #55acee;\n    background-color: transparent;\n    box-shadow: none;\n}\n\n.btn.btn-pinterest,\n.navbar .navbar-nav>li>a.btn.btn-pinterest {\n    background-color: #cc2127;\n    color: #fff;\n    box-shadow: 0 2px 2px 0 rgba(204, 33, 39, 0.14), 0 3px 1px -2px rgba(204, 33, 39, 0.2), 0 1px 5px 0 rgba(204, 33, 39, 0.12);\n}\n\n.btn.btn-pinterest:focus,\n.btn.btn-pinterest:active,\n.btn.btn-pinterest:hover,\n.navbar .navbar-nav>li>a.btn.btn-pinterest:focus,\n.navbar .navbar-nav>li>a.btn.btn-pinterest:active,\n.navbar .navbar-nav>li>a.btn.btn-pinterest:hover {\n    background-color: #cc2127;\n    color: #fff;\n    box-shadow: 0 14px 26px -12px rgba(204, 33, 39, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(204, 33, 39, 0.2);\n}\n\n.btn.btn-pinterest.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-pinterest.btn-simple {\n    color: #cc2127;\n    background-color: transparent;\n    box-shadow: none;\n}\n\n.btn.btn-google,\n.navbar .navbar-nav>li>a.btn.btn-google {\n    background-color: #dd4b39;\n    color: #fff;\n    box-shadow: 0 2px 2px 0 rgba(221, 75, 57, 0.14), 0 3px 1px -2px rgba(221, 75, 57, 0.2), 0 1px 5px 0 rgba(221, 75, 57, 0.12);\n}\n\n.btn.btn-google:focus,\n.btn.btn-google:active,\n.btn.btn-google:hover,\n.navbar .navbar-nav>li>a.btn.btn-google:focus,\n.navbar .navbar-nav>li>a.btn.btn-google:active,\n.navbar .navbar-nav>li>a.btn.btn-google:hover {\n    background-color: #dd4b39;\n    color: #fff;\n    box-shadow: 0 14px 26px -12px rgba(221, 75, 57, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(221, 75, 57, 0.2);\n}\n\n.btn.btn-google.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-google.btn-simple {\n    color: #dd4b39;\n    background-color: transparent;\n    box-shadow: none;\n}\n\n.btn.btn-linkedin,\n.navbar .navbar-nav>li>a.btn.btn-linkedin {\n    background-color: #0976b4;\n    color: #fff;\n    box-shadow: 0 2px 2px 0 rgba(9, 118, 180, 0.14), 0 3px 1px -2px rgba(9, 118, 180, 0.2), 0 1px 5px 0 rgba(9, 118, 180, 0.12);\n}\n\n.btn.btn-linkedin:focus,\n.btn.btn-linkedin:active,\n.btn.btn-linkedin:hover,\n.navbar .navbar-nav>li>a.btn.btn-linkedin:focus,\n.navbar .navbar-nav>li>a.btn.btn-linkedin:active,\n.navbar .navbar-nav>li>a.btn.btn-linkedin:hover {\n    background-color: #0976b4;\n    color: #fff;\n    box-shadow: 0 14px 26px -12px rgba(9, 118, 180, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(9, 118, 180, 0.2);\n}\n\n.btn.btn-linkedin.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-linkedin.btn-simple {\n    color: #0976b4;\n    background-color: transparent;\n    box-shadow: none;\n}\n\n.btn.btn-dribbble,\n.navbar .navbar-nav>li>a.btn.btn-dribbble {\n    background-color: #ea4c89;\n    color: #fff;\n    box-shadow: 0 2px 2px 0 rgba(234, 76, 137, 0.14), 0 3px 1px -2px rgba(234, 76, 137, 0.2), 0 1px 5px 0 rgba(234, 76, 137, 0.12);\n}\n\n.btn.btn-dribbble:focus,\n.btn.btn-dribbble:active,\n.btn.btn-dribbble:hover,\n.navbar .navbar-nav>li>a.btn.btn-dribbble:focus,\n.navbar .navbar-nav>li>a.btn.btn-dribbble:active,\n.navbar .navbar-nav>li>a.btn.btn-dribbble:hover {\n    background-color: #ea4c89;\n    color: #fff;\n    box-shadow: 0 14px 26px -12px rgba(234, 76, 137, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(234, 76, 137, 0.2);\n}\n\n.btn.btn-dribbble.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-dribbble.btn-simple {\n    color: #ea4c89;\n    background-color: transparent;\n    box-shadow: none;\n}\n\n.btn.btn-github,\n.navbar .navbar-nav>li>a.btn.btn-github {\n    background-color: #333333;\n    color: #fff;\n    box-shadow: 0 2px 2px 0 rgba(51, 51, 51, 0.14), 0 3px 1px -2px rgba(51, 51, 51, 0.2), 0 1px 5px 0 rgba(51, 51, 51, 0.12);\n}\n\n.btn.btn-github:focus,\n.btn.btn-github:active,\n.btn.btn-github:hover,\n.navbar .navbar-nav>li>a.btn.btn-github:focus,\n.navbar .navbar-nav>li>a.btn.btn-github:active,\n.navbar .navbar-nav>li>a.btn.btn-github:hover {\n    background-color: #333333;\n    color: #fff;\n    box-shadow: 0 14px 26px -12px rgba(51, 51, 51, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(51, 51, 51, 0.2);\n}\n\n.btn.btn-github.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-github.btn-simple {\n    color: #333333;\n    background-color: transparent;\n    box-shadow: none;\n}\n\n.btn.btn-youtube,\n.navbar .navbar-nav>li>a.btn.btn-youtube {\n    background-color: #e52d27;\n    color: #fff;\n    box-shadow: 0 2px 2px 0 rgba(229, 45, 39, 0.14), 0 3px 1px -2px rgba(229, 45, 39, 0.2), 0 1px 5px 0 rgba(229, 45, 39, 0.12);\n}\n\n.btn.btn-youtube:focus,\n.btn.btn-youtube:active,\n.btn.btn-youtube:hover,\n.navbar .navbar-nav>li>a.btn.btn-youtube:focus,\n.navbar .navbar-nav>li>a.btn.btn-youtube:active,\n.navbar .navbar-nav>li>a.btn.btn-youtube:hover {\n    background-color: #e52d27;\n    color: #fff;\n    box-shadow: 0 14px 26px -12px rgba(229, 45, 39, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(229, 45, 39, 0.2);\n}\n\n.btn.btn-youtube.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-youtube.btn-simple {\n    color: #e52d27;\n    background-color: transparent;\n    box-shadow: none;\n}\n\n.btn.btn-instagram,\n.navbar .navbar-nav>li>a.btn.btn-instagram {\n    background-color: #125688;\n    color: #fff;\n    box-shadow: 0 2px 2px 0 rgba(18, 86, 136, 0.14), 0 3px 1px -2px rgba(18, 86, 136, 0.2), 0 1px 5px 0 rgba(18, 86, 136, 0.12);\n}\n\n.btn.btn-instagram:focus,\n.btn.btn-instagram:active,\n.btn.btn-instagram:hover,\n.navbar .navbar-nav>li>a.btn.btn-instagram:focus,\n.navbar .navbar-nav>li>a.btn.btn-instagram:active,\n.navbar .navbar-nav>li>a.btn.btn-instagram:hover {\n    background-color: #125688;\n    color: #fff;\n    box-shadow: 0 14px 26px -12px rgba(18, 86, 136, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(18, 86, 136, 0.2);\n}\n\n.btn.btn-instagram.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-instagram.btn-simple {\n    color: #125688;\n    background-color: transparent;\n    box-shadow: none;\n}\n\n.btn.btn-reddit,\n.navbar .navbar-nav>li>a.btn.btn-reddit {\n    background-color: #ff4500;\n    color: #fff;\n    box-shadow: 0 2px 2px 0 rgba(255, 69, 0, 0.14), 0 3px 1px -2px rgba(255, 69, 0, 0.2), 0 1px 5px 0 rgba(255, 69, 0, 0.12);\n}\n\n.btn.btn-reddit:focus,\n.btn.btn-reddit:active,\n.btn.btn-reddit:hover,\n.navbar .navbar-nav>li>a.btn.btn-reddit:focus,\n.navbar .navbar-nav>li>a.btn.btn-reddit:active,\n.navbar .navbar-nav>li>a.btn.btn-reddit:hover {\n    background-color: #ff4500;\n    color: #fff;\n    box-shadow: 0 14px 26px -12px rgba(255, 69, 0, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(255, 69, 0, 0.2);\n}\n\n.btn.btn-reddit.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-reddit.btn-simple {\n    color: #ff4500;\n    background-color: transparent;\n    box-shadow: none;\n}\n\n.btn.btn-tumblr,\n.navbar .navbar-nav>li>a.btn.btn-tumblr {\n    background-color: #35465c;\n    color: #fff;\n    box-shadow: 0 2px 2px 0 rgba(53, 70, 92, 0.14), 0 3px 1px -2px rgba(53, 70, 92, 0.2), 0 1px 5px 0 rgba(53, 70, 92, 0.12);\n}\n\n.btn.btn-tumblr:focus,\n.btn.btn-tumblr:active,\n.btn.btn-tumblr:hover,\n.navbar .navbar-nav>li>a.btn.btn-tumblr:focus,\n.navbar .navbar-nav>li>a.btn.btn-tumblr:active,\n.navbar .navbar-nav>li>a.btn.btn-tumblr:hover {\n    background-color: #35465c;\n    color: #fff;\n    box-shadow: 0 14px 26px -12px rgba(53, 70, 92, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(53, 70, 92, 0.2);\n}\n\n.btn.btn-tumblr.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-tumblr.btn-simple {\n    color: #35465c;\n    background-color: transparent;\n    box-shadow: none;\n}\n\n.btn.btn-behance,\n.navbar .navbar-nav>li>a.btn.btn-behance {\n    background-color: #1769ff;\n    color: #fff;\n    box-shadow: 0 2px 2px 0 rgba(23, 105, 255, 0.14), 0 3px 1px -2px rgba(23, 105, 255, 0.2), 0 1px 5px 0 rgba(23, 105, 255, 0.12);\n}\n\n.btn.btn-behance:focus,\n.btn.btn-behance:active,\n.btn.btn-behance:hover,\n.navbar .navbar-nav>li>a.btn.btn-behance:focus,\n.navbar .navbar-nav>li>a.btn.btn-behance:active,\n.navbar .navbar-nav>li>a.btn.btn-behance:hover {\n    background-color: #1769ff;\n    color: #fff;\n    box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n}\n\n.btn.btn-behance.btn-simple,\n.navbar .navbar-nav>li>a.btn.btn-behance.btn-simple {\n    color: #1769ff;\n    background-color: transparent;\n    box-shadow: none;\n}\n\n.btn:focus,\n.btn:active,\n.btn:active:focus,\n.navbar .navbar-nav>li>a.btn:focus,\n.navbar .navbar-nav>li>a.btn:active,\n.navbar .navbar-nav>li>a.btn:active:focus {\n    outline: 0;\n}\n\n.btn.btn-round,\n.navbar .navbar-nav>li>a.btn.btn-round {\n    border-radius: 30px;\n}\n\n.btn:not(.btn-just-icon):not(.btn-fab) .fa,\n.navbar .navbar-nav>li>a.btn:not(.btn-just-icon):not(.btn-fab) .fa {\n    font-size: 18px;\n    margin-top: -2px;\n    position: relative;\n    top: 2px;\n}\n\n.btn.btn-fab,\n.navbar .navbar-nav>li>a.btn.btn-fab {\n    border-radius: 50%;\n    font-size: 24px;\n    height: 56px;\n    margin: auto;\n    min-width: 56px;\n    width: 56px;\n    padding: 0;\n    overflow: hidden;\n    position: relative;\n    line-height: normal;\n}\n\n.btn.btn-fab .ripple-container,\n.navbar .navbar-nav>li>a.btn.btn-fab .ripple-container {\n    border-radius: 50%;\n}\n\n.btn.btn-fab.btn-fab-mini,\n.btn-group-sm .btn.btn-fab,\n.navbar .navbar-nav>li>a.btn.btn-fab.btn-fab-mini,\n.btn-group-sm .navbar .navbar-nav>li>a.btn.btn-fab {\n    height: 40px;\n    min-width: 40px;\n    width: 40px;\n}\n\n.btn.btn-fab.btn-fab-mini.material-icons,\n.btn-group-sm .btn.btn-fab.material-icons,\n.navbar .navbar-nav>li>a.btn.btn-fab.btn-fab-mini.material-icons,\n.btn-group-sm .navbar .navbar-nav>li>a.btn.btn-fab.material-icons {\n    top: -3.5px;\n    left: -3.5px;\n}\n\n.btn.btn-fab.btn-fab-mini .material-icons,\n.btn-group-sm .btn.btn-fab .material-icons,\n.navbar .navbar-nav>li>a.btn.btn-fab.btn-fab-mini .material-icons,\n.btn-group-sm .navbar .navbar-nav>li>a.btn.btn-fab .material-icons {\n    font-size: 17px;\n}\n\n.btn.btn-fab i.material-icons,\n.navbar .navbar-nav>li>a.btn.btn-fab i.material-icons {\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    transform: translate(-12px, -12px);\n    line-height: 24px;\n    width: 24px;\n    font-size: 24px;\n}\n\n.btn.btn-lg,\n.btn-group-lg .btn,\n.navbar .navbar-nav>li>a.btn.btn-lg,\n.btn-group-lg .navbar .navbar-nav>li>a.btn {\n    font-size: 14px;\n    padding: 18px 36px;\n}\n\n.btn.btn-sm,\n.btn-group-sm .btn,\n.navbar .navbar-nav>li>a.btn.btn-sm,\n.btn-group-sm .navbar .navbar-nav>li>a.btn {\n    padding: 5px 20px;\n    font-size: 11px;\n}\n\n.btn.btn-xs,\n.btn-group-xs .btn,\n.navbar .navbar-nav>li>a.btn.btn-xs,\n.btn-group-xs .navbar .navbar-nav>li>a.btn {\n    padding: 4px 15px;\n    font-size: 10px;\n}\n\n.btn.btn-just-icon,\n.navbar .navbar-nav>li>a.btn.btn-just-icon {\n    font-size: 20px;\n    padding: 11px 11px;\n    line-height: 1em;\n}\n\n.btn.btn-just-icon i,\n.navbar .navbar-nav>li>a.btn.btn-just-icon i {\n    width: 20px;\n}\n\n.btn.btn-just-icon.btn-lg,\n.navbar .navbar-nav>li>a.btn.btn-just-icon.btn-lg {\n    font-size: 22px;\n    padding: 13px 18px;\n}\n\n.btn .material-icons {\n    vertical-align: middle;\n    font-size: 17px;\n    top: -1px;\n    position: relative;\n}\n\n.btn .caret {\n    margin-left: 2px;\n}\n\n.navbar .navbar-nav>li>a.btn {\n    margin-top: 2px;\n    margin-bottom: 2px;\n}\n\n.navbar .navbar-nav>li>a.btn.btn-fab {\n    margin: 5px 2px;\n}\n\n.navbar .navbar-nav>li>a:not(.btn) .material-icons {\n    margin-top: -3px;\n    top: 0px;\n    position: relative;\n    margin-right: 3px;\n}\n\n.navbar .navbar-nav>li>.profile-photo {\n    margin: 5px 2px;\n}\n\n.navbar-default:not(.navbar-transparent) .navbar-nav>li>a.btn.btn-white.btn-simple {\n    color: #555555;\n}\n\n.btn-group,\n.btn-group-vertical {\n    position: relative;\n    margin: 10px 1px;\n}\n\n.btn-group.open>.dropdown-toggle.btn,\n.btn-group.open>.dropdown-toggle.btn.btn-default,\n.btn-group-vertical.open>.dropdown-toggle.btn,\n.btn-group-vertical.open>.dropdown-toggle.btn.btn-default {\n    background-color: #FFFFFF;\n}\n\n.btn-group.open>.dropdown-toggle.btn.btn-inverse,\n.btn-group-vertical.open>.dropdown-toggle.btn.btn-inverse {\n    background-color: #212121;\n}\n\n.btn-group.open>.dropdown-toggle.btn.btn-primary,\n.btn-group-vertical.open>.dropdown-toggle.btn.btn-primary {\n    background-color: #9c27b0;\n}\n\n.btn-group.open>.dropdown-toggle.btn.btn-success,\n.btn-group-vertical.open>.dropdown-toggle.btn.btn-success {\n    background-color: #4caf50;\n}\n\n.btn-group.open>.dropdown-toggle.btn.btn-info,\n.btn-group-vertical.open>.dropdown-toggle.btn.btn-info {\n    background-color: #00bcd4;\n}\n\n.btn-group.open>.dropdown-toggle.btn.btn-warning,\n.btn-group-vertical.open>.dropdown-toggle.btn.btn-warning {\n    background-color: #ff9800;\n}\n\n.btn-group.open>.dropdown-toggle.btn.btn-danger,\n.btn-group-vertical.open>.dropdown-toggle.btn.btn-danger {\n    background-color: #f44336;\n}\n\n.btn-group.open>.dropdown-toggle.btn.btn-rose,\n.btn-group-vertical.open>.dropdown-toggle.btn.btn-rose {\n    background-color: #e91e63;\n}\n\n.btn-group .dropdown-menu,\n.btn-group-vertical .dropdown-menu {\n    border-radius: 0 0 3px 3px;\n}\n\n.btn-group.btn-group-raised,\n.btn-group-vertical.btn-group-raised {\n    box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);\n}\n\n.btn-group .btn+.btn,\n.btn-group .btn,\n.btn-group .btn:active,\n.btn-group .btn-group,\n.btn-group-vertical .btn+.btn,\n.btn-group-vertical .btn,\n.btn-group-vertical .btn:active,\n.btn-group-vertical .btn-group {\n    margin: 0;\n}\n\n.close {\n    font-size: inherit;\n    color: #FFFFFF;\n    opacity: .9;\n    text-shadow: none;\n}\n\n.close:hover,\n.close:focus {\n    opacity: 1;\n    color: #FFFFFF;\n}\n\n.close i {\n    font-size: 11px;\n}\n\nbody {\n    background-color: #EEEEEE;\n    color: #3C4858;\n}\n\nbody.inverse {\n    background: #333333;\n}\n\nbody.inverse,\nbody.inverse .form-control {\n    color: #ffffff;\n}\n\nbody.inverse .modal,\nbody.inverse .modal .form-control,\nbody.inverse .panel-default,\nbody.inverse .panel-default .form-control,\nbody.inverse .card,\nbody.inverse .card .form-control {\n    background-color: initial;\n    color: initial;\n}\n\nblockquote p {\n    font-style: italic;\n}\n\n.life-of-material-dashboard {\n    background: #FFFFFF;\n}\n\nbody,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4 {\n    font-family: \"Roboto\", \"Helvetica\", \"Arial\", sans-serif;\n    font-weight: 400;\n    line-height: 1.5em;\n}\n\n.serif-font {\n    font-family: \"Roboto Slab\", \"Times New Roman\", serif;\n}\n\n.page-header {\n    height: 60vh;\n    background-position: center center;\n    background-size: cover;\n    margin: 0;\n    padding: 0;\n    border: 0;\n    border-bottom-left-radius: 6px;\n    border-bottom-right-radius: 6px;\n}\n\na {\n    color: #9c27b0;\n}\n\na:hover,\na:focus {\n    color: #89229b;\n    text-decoration: none;\n}\n\na.text-info:hover,\na.text-info:focus {\n    color: #00a5bb;\n}\n\na .material-icons {\n    vertical-align: middle;\n}\n\na[data-toggle=\"collapse\"][aria-expanded=\"true\"] .caret,\n.dropdown.open .caret,\n.dropup.open .caret,\n.btn-group.bootstrap-select.open .caret {\n    filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);\n    -webkit-transform: rotate(180deg);\n    -ms-transform: rotate(180deg);\n    transform: rotate(180deg);\n}\n\n.caret,\n.bootstrap-tagsinput .tag,\n.bootstrap-tagsinput [data-role=\"remove\"] {\n    -webkit-transition: all 150ms ease-in;\n    -moz-transition: all 150ms ease-in;\n    -o-transition: all 150ms ease-in;\n    -ms-transition: all 150ms ease-in;\n    transition: all 150ms ease-in;\n}\n\n\n/*           Animations              */\n\n.animation-transition-general,\n.sidebar .sidebar-wrapper>.nav [data-toggle=\"collapse\"]~div>ul>li>a span,\n.sidebar .sidebar-wrapper .user .info [data-toggle=\"collapse\"]~div>ul>li>a span,\n.sidebar .nav p,\n.sidebar .logo a.logo-mini,\n.sidebar .logo a.logo-normal,\n.sidebar .user .photo,\n.sidebar .user a,\n.sidebar .user .info>a>span,\n.login-page .card-login,\n.lock-page .card-profile {\n    -webkit-transition: all 300ms linear;\n    -moz-transition: all 300ms linear;\n    -o-transition: all 300ms linear;\n    -ms-transition: all 300ms linear;\n    transition: all 300ms linear;\n}\n\n.animation-transition-slow {\n    -webkit-transition: all 370ms linear;\n    -moz-transition: all 370ms linear;\n    -o-transition: all 370ms linear;\n    -ms-transition: all 370ms linear;\n    transition: all 370ms linear;\n}\n\n.animation-transition-fast,\n.bootstrap-datetimepicker-widget table td>div,\n.bootstrap-datetimepicker-widget table th>div,\n.bootstrap-datetimepicker-widget table th,\n.bootstrap-datetimepicker-widget table td span,\n.panel .panel-heading i,\n.navbar {\n    -webkit-transition: all 150ms ease 0s;\n    -moz-transition: all 150ms ease 0s;\n    -o-transition: all 150ms ease 0s;\n    -ms-transition: all 150ms ease 0s;\n    transition: all 150ms ease 0s;\n}\n\nlegend {\n    border-bottom: 0;\n}\n\n* {\n    -webkit-tap-highlight-color: rgba(255, 255, 255, 0);\n    -webkit-tap-highlight-color: transparent;\n}\n\n*:focus {\n    outline: 0;\n}\n\na:focus,\na:active,\nbutton:active,\nbutton:focus,\nbutton:hover,\nbutton::-moz-focus-inner,\ninput[type=\"reset\"]::-moz-focus-inner,\ninput[type=\"button\"]::-moz-focus-inner,\ninput[type=\"submit\"]::-moz-focus-inner,\nselect::-moz-focus-inner,\ninput[type=\"file\"]>input[type=\"button\"]::-moz-focus-inner {\n    outline: 0 !important;\n}\n\n@-webkit-keyframes hinge {\n    0% {\n        -webkit-transform-origin: top left;\n        transform-origin: top left;\n        -webkit-animation-timing-function: ease-in-out;\n        animation-timing-function: ease-in-out;\n    }\n    20%,\n    60% {\n        -webkit-transform: rotate3d(0, 0, 1, 80deg);\n        transform: rotate3d(0, 0, 1, 80deg);\n        -webkit-transform-origin: top left;\n        transform-origin: top left;\n        -webkit-animation-timing-function: ease-in-out;\n        animation-timing-function: ease-in-out;\n    }\n    40%,\n    80% {\n        -webkit-transform: rotate3d(0, 0, 1, 60deg);\n        transform: rotate3d(0, 0, 1, 60deg);\n        -webkit-transform-origin: top left;\n        transform-origin: top left;\n        -webkit-animation-timing-function: ease-in-out;\n        animation-timing-function: ease-in-out;\n        opacity: 1;\n    }\n    to {\n        -webkit-transform: translate3d(0, 700px, 0);\n        transform: translate3d(0, 700px, 0);\n        opacity: 0;\n    }\n}\n\n@keyframes hinge {\n    0% {\n        -webkit-transform-origin: top left;\n        transform-origin: top left;\n        -webkit-animation-timing-function: ease-in-out;\n        animation-timing-function: ease-in-out;\n    }\n    20%,\n    60% {\n        -webkit-transform: rotate3d(0, 0, 1, 80deg);\n        transform: rotate3d(0, 0, 1, 80deg);\n        -webkit-transform-origin: top left;\n        transform-origin: top left;\n        -webkit-animation-timing-function: ease-in-out;\n        animation-timing-function: ease-in-out;\n    }\n    40%,\n    80% {\n        -webkit-transform: rotate3d(0, 0, 1, 60deg);\n        transform: rotate3d(0, 0, 1, 60deg);\n        -webkit-transform-origin: top left;\n        transform-origin: top left;\n        -webkit-animation-timing-function: ease-in-out;\n        animation-timing-function: ease-in-out;\n        opacity: 1;\n    }\n    to {\n        -webkit-transform: translate3d(0, 700px, 0);\n        transform: translate3d(0, 700px, 0);\n        opacity: 0;\n    }\n}\n\n.hinge {\n    -webkit-animation-name: hinge;\n    animation-name: hinge;\n}\n\n.animated.hinge {\n    -webkit-animation-duration: 2s;\n    animation-duration: 2s;\n}\n\n.animated {\n    -webkit-animation-duration: 1s;\n    animation-duration: 1s;\n    -webkit-animation-fill-mode: both;\n    animation-fill-mode: both;\n}\n\nlegend {\n    margin-bottom: 20px;\n    font-size: 21px;\n}\n\noutput {\n    padding-top: 8px;\n    font-size: 14px;\n    line-height: 1.428571429;\n}\n\n.form-control {\n    height: 36px;\n    padding: 7px 0;\n    font-size: 14px;\n    line-height: 1.428571429;\n}\n\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n    input[type=\"date\"].form-control,\n    input[type=\"time\"].form-control,\n    input[type=\"datetime-local\"].form-control,\n    input[type=\"month\"].form-control {\n        line-height: 36px;\n    }\n    input[type=\"date\"].input-sm,\n    .input-group-sm input[type=\"date\"],\n    input[type=\"time\"].input-sm,\n    .input-group-sm input[type=\"time\"],\n    input[type=\"datetime-local\"].input-sm,\n    .input-group-sm input[type=\"datetime-local\"],\n    input[type=\"month\"].input-sm,\n    .input-group-sm input[type=\"month\"] {\n        line-height: 24px;\n    }\n    input[type=\"date\"].input-lg,\n    .input-group-lg input[type=\"date\"],\n    input[type=\"time\"].input-lg,\n    .input-group-lg input[type=\"time\"],\n    input[type=\"datetime-local\"].input-lg,\n    .input-group-lg input[type=\"datetime-local\"],\n    input[type=\"month\"].input-lg,\n    .input-group-lg input[type=\"month\"] {\n        line-height: 44px;\n    }\n}\n\n.radio label,\n.checkbox label {\n    min-height: 20px;\n}\n\n.form-control-static {\n    padding-top: 8px;\n    padding-bottom: 8px;\n    min-height: 34px;\n}\n\n.input-sm .input-sm {\n    height: 24px;\n    padding: 3px 0;\n    font-size: 11px;\n    line-height: 1.5;\n    border-radius: 0;\n}\n\n.input-sm select.input-sm {\n    height: 24px;\n    line-height: 24px;\n}\n\n.input-sm textarea.input-sm,\n.input-sm select[multiple].input-sm {\n    height: auto;\n}\n\n.form-group-sm .form-control {\n    height: 24px;\n    padding: 3px 0;\n    font-size: 11px;\n    line-height: 1.5;\n}\n\n.form-group-sm select.form-control {\n    height: 24px;\n    line-height: 24px;\n}\n\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n    height: auto;\n}\n\n.form-group-sm .form-control-static {\n    height: 24px;\n    min-height: 31px;\n    padding: 4px 0;\n    font-size: 11px;\n    line-height: 1.5;\n}\n\n.input-lg .input-lg {\n    height: 44px;\n    padding: 9px 0;\n    font-size: 18px;\n    line-height: 1.3333333;\n    border-radius: 0;\n}\n\n.input-lg select.input-lg {\n    height: 44px;\n    line-height: 44px;\n}\n\n.input-lg textarea.input-lg,\n.input-lg select[multiple].input-lg {\n    height: auto;\n}\n\n.form-group-lg .form-control {\n    height: 44px;\n    padding: 9px 0;\n    font-size: 18px;\n    line-height: 1.3333333;\n}\n\n.form-group-lg select.form-control {\n    height: 44px;\n    line-height: 44px;\n}\n\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n    height: auto;\n}\n\n.form-group-lg .form-control-static {\n    height: 44px;\n    min-height: 38px;\n    padding: 10px 0;\n    font-size: 18px;\n    line-height: 1.3333333;\n}\n\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n    padding-top: 8px;\n}\n\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n    min-height: 28px;\n}\n\n@media (min-width: 768px) {\n    .form-horizontal .control-label {\n        padding-top: 8px;\n    }\n}\n\n@media (min-width: 768px) {\n    .form-horizontal .form-group-lg .control-label {\n        padding-top: 12.9999997px;\n        font-size: 18px;\n    }\n}\n\n@media (min-width: 768px) {\n    .form-horizontal .form-group-sm .control-label {\n        padding-top: 4px;\n        font-size: 11px;\n    }\n}\n\n\n.form-control,\n.form-group .form-control {\n    border: 0;\n    background-image: linear-gradient(#9c27b0, #9c27b0), linear-gradient(#D2D2D2, #D2D2D2);\n    background-size: 0 2px, 100% 1px;\n    background-repeat: no-repeat;\n    background-position: center bottom, center calc(100% - 1px);\n    background-color: rgba(0, 0, 0, 0);\n    transition: background 0s ease-out;\n    float: none;\n    box-shadow: none;\n    border-radius: 0;\n    font-weight: 400;\n}\n\n.form-control::-moz-placeholder,\n.form-group .form-control::-moz-placeholder {\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-control:-ms-input-placeholder,\n.form-group .form-control:-ms-input-placeholder {\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-control::-webkit-input-placeholder,\n.form-group .form-control::-webkit-input-placeholder {\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-control[readonly],\n.form-control[disabled],\nfieldset[disabled] .form-control,\n.form-group .form-control[readonly],\n.form-group .form-control[disabled],\nfieldset[disabled] .form-group .form-control {\n    background-color: rgba(0, 0, 0, 0);\n}\n\n.form-control[disabled],\nfieldset[disabled] .form-control,\n.form-group .form-control[disabled],\nfieldset[disabled] .form-group .form-control {\n    background-image: none;\n    border-bottom: 1px dotted #D2D2D2;\n}\n\n.form-group {\n    position: relative;\n}\n\n.form-group.label-static label.control-label,\n.form-group.label-placeholder label.control-label,\n.form-group.label-floating label.control-label {\n    position: absolute;\n    pointer-events: none;\n    transition: 0.3s ease all;\n}\n\n.form-group.label-floating label.control-label {\n    will-change: left, top, contents;\n}\n\n.form-group.label-placeholder:not(.is-empty) label.control-label {\n    display: none;\n}\n\n.form-group .help-block {\n    position: absolute;\n    display: none;\n}\n\n.form-group .form-control.valid:focus {\n    background-image: linear-gradient(#4caf50, #4caf50), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.form-group.is-focused .form-control {\n    outline: none;\n    background-image: linear-gradient(#9c27b0, #9c27b0), linear-gradient(#D2D2D2, #D2D2D2);\n    background-size: 100% 2px, 100% 1px;\n    box-shadow: none;\n    transition-duration: 0.3s;\n}\n\n.form-group.is-focused .form-control .material-input:after {\n    background-color: #9c27b0;\n}\n\n.form-group.is-focused.form-info .form-control {\n    background-image: linear-gradient(#00bcd4, #00bcd4), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.form-group.is-focused.form-success .form-control {\n    background-image: linear-gradient(#4caf50, #4caf50), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.form-group.is-focused.form-warning .form-control {\n    background-image: linear-gradient(#ff9800, #ff9800), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.form-group.is-focused.form-danger .form-control {\n    background-image: linear-gradient(#f44336, #f44336), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.form-group.is-focused.form-white .form-control {\n    background-image: linear-gradient(#FFFFFF, #FFFFFF), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.form-group.is-focused.label-placeholder label,\n.form-group.is-focused.label-placeholder label.control-label {\n    color: #AAAAAA;\n}\n\n.form-group.is-focused .help-block {\n    display: block;\n}\n\n.form-group.has-warning .form-control {\n    box-shadow: none;\n}\n\n.form-group.has-warning.is-focused .form-control {\n    background-image: linear-gradient(#ff9800, #ff9800), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.form-group.has-warning label.control-label,\n.form-group.has-warning .help-block {\n    color: #ff9800;\n}\n\n.form-group.has-error .form-control {\n    box-shadow: none;\n}\n\n.form-group.has-error.is-focused .form-control {\n    background-image: linear-gradient(#f44336, #f44336), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.form-group.has-error .form-control {\n    background-image: linear-gradient(#f44336, #f44336), linear-gradient(#D2D2D2, #D2D2D2);\n    background-size: 100% 2px, 100% 1px;\n    transition-duration: 0.3s;\n}\n\n.form-group.has-error label.control-label,\n.form-group.has-error .help-block {\n    color: #f44336;\n}\n\n.form-group.has-success .form-control {\n    box-shadow: none;\n}\n\n.form-group.has-success.is-focused .form-control {\n    background-image: linear-gradient(#4caf50, #4caf50), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.form-group.has-success label.control-label,\n.form-group.has-success .help-block {\n    color: #4caf50;\n}\n\n.form-group.has-info .form-control {\n    box-shadow: none;\n}\n\n.form-group.has-info.is-focused .form-control {\n    background-image: linear-gradient(#00bcd4, #00bcd4), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.form-group.has-info label.control-label,\n.form-group.has-info .help-block {\n    color: #00bcd4;\n}\n\n.form-group textarea {\n    resize: none;\n}\n\n.form-group textarea~.form-control-highlight {\n    margin-top: -11px;\n}\n\n.form-group select {\n    appearance: none;\n}\n\n.form-group select~.material-input:after {\n    display: none;\n}\n\n.form-control::-moz-placeholder {\n    font-size: 14px;\n    line-height: 1.428571429;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-control:-ms-input-placeholder {\n    font-size: 14px;\n    line-height: 1.428571429;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-control::-webkit-input-placeholder {\n    font-size: 14px;\n    line-height: 1.428571429;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.checkbox label,\n.radio label,\nlabel,\n.label-on-left,\n.label-on-right {\n    font-size: 14px;\n    line-height: 1.428571429;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\nlabel.control-label {\n    font-size: 11px;\n    line-height: 1.0714285718;\n    color: #AAAAAA;\n    font-weight: 400;\n    margin: 16px 0 0 0;\n}\n\n.help-block {\n    margin-top: 0;\n    font-size: 11px;\n}\n\n.form-group {\n    padding-bottom: 10px;\n    margin: 8px 0 0 0;\n}\n\n.form-group .form-control::-moz-placeholder {\n    font-size: 14px;\n    line-height: 1.428571429;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-group .form-control:-ms-input-placeholder {\n    font-size: 14px;\n    line-height: 1.428571429;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-group .form-control::-webkit-input-placeholder {\n    font-size: 14px;\n    line-height: 1.428571429;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-group .checkbox label,\n.form-group .radio label,\n.form-group label,\n.form-group .label-on-left,\n.form-group .label-on-right {\n    font-size: 14px;\n    line-height: 1.428571429;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-group label.control-label {\n    font-size: 11px;\n    line-height: 1.0714285718;\n    color: #AAAAAA;\n    font-weight: 400;\n    margin: 16px 0 0 0;\n}\n\n.form-group .help-block {\n    margin-top: 0;\n    font-size: 11px;\n}\n\n.form-group.label-floating label.control-label,\n.form-group.label-placeholder label.control-label {\n    top: -7px;\n    font-size: 14px;\n    line-height: 1.428571429;\n}\n\n.form-group.label-static label.control-label,\n.form-group.label-floating.is-focused label.control-label,\n.form-group.label-floating:not(.is-empty) label.control-label {\n    top: -28px;\n    left: 0;\n    font-size: 11px;\n    line-height: 1.0714285718;\n}\n\n.form-group.label-floating input.form-control:-webkit-autofill~label.control-label label.control-label {\n    top: -28px;\n    left: 0;\n    font-size: 11px;\n    line-height: 1.0714285718;\n}\n\n.form-group.form-group-sm {\n    padding-bottom: 10px;\n    margin: 8px 0 0 0;\n}\n\n.form-group.form-group-sm .form-control::-moz-placeholder {\n    font-size: 11px;\n    line-height: 1.5;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-group.form-group-sm .form-control:-ms-input-placeholder {\n    font-size: 11px;\n    line-height: 1.5;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-group.form-group-sm .form-control::-webkit-input-placeholder {\n    font-size: 11px;\n    line-height: 1.5;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-group.form-group-sm .checkbox label,\n.form-group.form-group-sm .radio label,\n.form-group.form-group-sm label,\n.form-group.form-group-sm .label-on-left,\n.form-group.form-group-sm .label-on-right {\n    font-size: 11px;\n    line-height: 1.5;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-group.form-group-sm label.control-label {\n    font-size: 9px;\n    line-height: 1.125;\n    color: #AAAAAA;\n    font-weight: 400;\n    margin: 16px 0 0 0;\n}\n\n.form-group.form-group-sm .help-block {\n    margin-top: 0;\n    font-size: 9px;\n}\n\n.form-group.form-group-sm.label-floating label.control-label,\n.form-group.form-group-sm.label-placeholder label.control-label {\n    top: -11px;\n    font-size: 11px;\n    line-height: 1.5;\n}\n\n.form-group.form-group-sm.label-static label.control-label,\n.form-group.form-group-sm.label-floating.is-focused label.control-label,\n.form-group.form-group-sm.label-floating:not(.is-empty) label.control-label {\n    top: -25px;\n    left: 0;\n    font-size: 9px;\n    line-height: 1.125;\n}\n\n.form-group.form-group-sm.label-floating input.form-control:-webkit-autofill~label.control-label label.control-label {\n    top: -25px;\n    left: 0;\n    font-size: 9px;\n    line-height: 1.125;\n}\n\n.form-group.form-group-lg {\n    padding-bottom: 10px;\n    margin: 8px 0 0 0;\n}\n\n.form-group.form-group-lg .form-control::-moz-placeholder {\n    font-size: 18px;\n    line-height: 1.3333333;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-group.form-group-lg .form-control:-ms-input-placeholder {\n    font-size: 18px;\n    line-height: 1.3333333;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-group.form-group-lg .form-control::-webkit-input-placeholder {\n    font-size: 18px;\n    line-height: 1.3333333;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-group.form-group-lg .checkbox label,\n.form-group.form-group-lg .radio label,\n.form-group.form-group-lg label,\n.form-group.form-group-lg .label-on-left,\n.form-group.form-group-lg .label-on-right {\n    font-size: 18px;\n    line-height: 1.3333333;\n    color: #AAAAAA;\n    font-weight: 400;\n}\n\n.form-group.form-group-lg label.control-label {\n    font-size: 14px;\n    line-height: 0.999999975;\n    color: #AAAAAA;\n    font-weight: 400;\n    margin: 16px 0 0 0;\n}\n\n.form-group.form-group-lg .help-block {\n    margin-top: 0;\n    font-size: 14px;\n}\n\n.form-group.form-group-lg.label-floating label.control-label,\n.form-group.form-group-lg.label-placeholder label.control-label {\n    top: -5px;\n    font-size: 18px;\n    line-height: 1.3333333;\n}\n\n.form-group.form-group-lg.label-static label.control-label,\n.form-group.form-group-lg.label-floating.is-focused label.control-label,\n.form-group.form-group-lg.label-floating:not(.is-empty) label.control-label {\n    top: -32px;\n    left: 0;\n    font-size: 14px;\n    line-height: 0.999999975;\n}\n\n.form-group.form-group-lg.label-floating input.form-control:-webkit-autofill~label.control-label label.control-label {\n    top: -32px;\n    left: 0;\n    font-size: 14px;\n    line-height: 0.999999975;\n}\n\nselect.form-control {\n    border: 0;\n    box-shadow: none;\n    border-radius: 0;\n}\n\n.form-group.is-focused select.form-control {\n    box-shadow: none;\n    border-color: #D2D2D2;\n}\n\nselect.form-control[multiple],\n.form-group.is-focused select.form-control[multiple] {\n    height: 85px;\n}\n\n.input-group-btn .btn {\n    margin: 0 0 7px 0;\n}\n\n.form-group.form-group-sm .input-group-btn .btn {\n    margin: 0 0 3px 0;\n}\n\n.form-group.form-group-lg .input-group-btn .btn {\n    margin: 0 0 9px 0;\n}\n\n.input-group .input-group-btn {\n    padding: 0 12px;\n}\n\n.input-group .input-group-addon {\n    border: 0;\n    background: transparent;\n    padding: 6px 15px 0px;\n}\n\n.form-group input[type=file] {\n    opacity: 0;\n    position: absolute;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    width: 100%;\n    height: 100%;\n    z-index: 100;\n}\n\n.form-control-feedback {\n    opacity: 0;\n}\n\n.has-success .form-control-feedback {\n    color: #4caf50;\n    opacity: 1;\n}\n\n.has-error .form-control-feedback {\n    color: #f44336;\n    opacity: 1;\n}\n\n.btn-file {\n    position: relative;\n    overflow: hidden;\n    vertical-align: middle;\n}\n\n.btn-file>input {\n    position: absolute;\n    top: 0;\n    right: 0;\n    width: 100%;\n    height: 100%;\n    margin: 0;\n    font-size: 23px;\n    cursor: pointer;\n    filter: alpha(opacity=0);\n    opacity: 0;\n    direction: ltr;\n}\n\n.fileinput {\n    display: inline-block;\n    margin-bottom: 9px;\n}\n\n.fileinput .form-control {\n    display: inline-block;\n    padding-top: 7px;\n    padding-bottom: 5px;\n    margin-bottom: 0;\n    vertical-align: middle;\n    cursor: text;\n}\n\n.fileinput .thumbnail {\n    display: inline-block;\n    margin-bottom: 10px;\n    overflow: hidden;\n    text-align: center;\n    vertical-align: middle;\n    max-width: 250px;\n    box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.42), 0 4px 25px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2);\n}\n\n.fileinput .thumbnail.img-circle {\n    border-radius: 50%;\n    max-width: 100px;\n}\n\n.fileinput .thumbnail>img {\n    max-height: 100%;\n}\n\n.fileinput .btn {\n    vertical-align: middle;\n}\n\n.fileinput-exists .fileinput-new,\n.fileinput-new .fileinput-exists {\n    display: none;\n}\n\n.fileinput-inline .fileinput-controls {\n    display: inline;\n}\n\n.fileinput-filename {\n    display: inline-block;\n    overflow: hidden;\n    vertical-align: middle;\n}\n\n.form-control .fileinput-filename {\n    vertical-align: bottom;\n}\n\n.fileinput.input-group {\n    display: table;\n}\n\n.fileinput.input-group>* {\n    position: relative;\n    z-index: 2;\n}\n\n.fileinput.input-group>.btn-file {\n    z-index: 1;\n}\n\n.fileinput-new.input-group .btn-file,\n.fileinput-new .input-group .btn-file {\n    border-radius: 0 4px 4px 0;\n}\n\n.fileinput-new.input-group .btn-file.btn-xs,\n.fileinput-new .input-group .btn-file.btn-xs,\n.fileinput-new.input-group .btn-file.btn-sm,\n.fileinput-new .input-group .btn-file.btn-sm {\n    border-radius: 0 3px 3px 0;\n}\n\n.fileinput-new.input-group .btn-file.btn-lg,\n.fileinput-new .input-group .btn-file.btn-lg {\n    border-radius: 0 6px 6px 0;\n}\n\n.form-group.has-warning .fileinput .fileinput-preview {\n    color: #ff9800;\n}\n\n.form-group.has-warning .fileinput .thumbnail {\n    border-color: #ff9800;\n}\n\n.form-group.has-error .fileinput .fileinput-preview {\n    color: #f44336;\n}\n\n.form-group.has-error .fileinput .thumbnail {\n    border-color: #f44336;\n}\n\n.form-group.has-success .fileinput .fileinput-preview {\n    color: #4caf50;\n}\n\n.form-group.has-success .fileinput .thumbnail {\n    border-color: #4caf50;\n}\n\n.input-group-addon:not(:first-child) {\n    border-left: 0;\n}\n\n.thumbnail {\n    border: 0 none;\n    border-radius: 4px;\n    padding: 0;\n}\n\n.alert {\n    border: 0;\n    border-radius: 0;\n    position: relative;\n    padding: 20px 15px;\n    line-height: 20px;\n}\n\n.alert b {\n    font-weight: 500;\n    text-transform: uppercase;\n    font-size: 12px;\n}\n\n.alert,\n.alert.alert-default {\n    background-color: white;\n    color: #555555;\n    border-radius: 3px;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 255, 255, 0.4);\n}\n\n.alert a,\n.alert .alert-link,\n.alert.alert-default a,\n.alert.alert-default .alert-link {\n    color: #555555;\n}\n\n.alert.alert-inverse {\n    background-color: #2e2e2e;\n    color: #fff;\n    border-radius: 3px;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(33, 33, 33, 0.4);\n}\n\n.alert.alert-inverse a,\n.alert.alert-inverse .alert-link {\n    color: #fff;\n}\n\n.alert.alert-primary {\n    background-color: #af2cc5;\n    color: #ffffff;\n    border-radius: 3px;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(156, 39, 176, 0.4);\n}\n\n.alert.alert-primary a,\n.alert.alert-primary .alert-link {\n    color: #ffffff;\n}\n\n.alert.alert-success {\n    background-color: #5cb860;\n    color: #ffffff;\n    border-radius: 3px;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(76, 175, 80, 0.4);\n}\n\n.alert.alert-success a,\n.alert.alert-success .alert-link {\n    color: #ffffff;\n}\n\n.alert.alert-info {\n    background-color: #00bcd4;\n    color: #ffffff;\n    border-radius: 3px;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(0, 188, 212, 0.4);\n}\n\n.alert.alert-info a,\n.alert.alert-info .alert-link {\n    color: #ffffff;\n}\n\n.alert.alert-warning {\n    background-color: #ffa21a;\n    color: #ffffff;\n    border-radius: 3px;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 152, 0, 0.4);\n}\n\n.alert.alert-warning a,\n.alert.alert-warning .alert-link {\n    color: #ffffff;\n}\n\n.alert.alert-danger {\n    background-color: #f55a4e;\n    color: #ffffff;\n    border-radius: 3px;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(244, 67, 54, 0.4);\n}\n\n.alert.alert-danger a,\n.alert.alert-danger .alert-link {\n    color: #ffffff;\n}\n\n.alert.alert-rose {\n    background-color: #eb3573;\n    color: #ffffff;\n    border-radius: 3px;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(233, 30, 99, 0.4);\n}\n\n.alert.alert-rose a,\n.alert.alert-rose .alert-link {\n    color: #ffffff;\n}\n\n.alert-info,\n.alert-danger,\n.alert-warning,\n.alert-success,\n.alert-rose {\n    color: #ffffff;\n}\n\n.alert-default a,\n.alert-default .alert-link {\n    color: rgba(0, 0, 0, 0.87);\n}\n\n.alert span {\n    display: block;\n    max-width: 89%;\n}\n\n.alert.alert-danger i {\n    color: #f44336;\n}\n\n.alert.alert-warning i {\n    color: #ff9800;\n}\n\n.alert.alert-success i {\n    color: #4caf50;\n}\n\n.alert.alert-info i {\n    color: #00bcd4;\n}\n\n.alert.alert-primary i {\n    color: #9c27b0;\n}\n\n.alert.alert-rose i {\n    color: #e91e63;\n}\n\n.alert.alert-with-icon {\n    margin-top: 43px;\n    padding-left: 66px;\n}\n\n.alert.alert-with-icon i[data-notify=\"icon\"] {\n    display: block;\n    left: 15px;\n    position: absolute;\n    margin-top: -39px;\n    font-size: 20px;\n    background-color: #FFFFFF;\n    padding: 9px;\n    border-radius: 50%;\n    max-width: 38px;\n    box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.42), 0 4px 25px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2);\n}\n\n.alert .close i {\n    color: #FFFFFF;\n}\n\n.alert i[data-notify=\"icon\"] {\n    display: none;\n}\n\n.alert .alert-icon {\n    display: block;\n    float: left;\n    margin-right: 15px;\n}\n\n.alert .alert-icon i {\n    margin-top: -7px;\n    top: 5px;\n    position: relative;\n}\n\n.alert [data-notify=\"dismiss\"] {\n    margin-right: 5px;\n}\n\n.table>thead>tr>th {\n    border-bottom-width: 1px;\n    font-size: 1.25em;\n    font-weight: 300;\n}\n\n.tab-pane .table tbody>tr>td:first-child {\n    width: 36px;\n}\n\n.table .radio,\n.table .checkbox {\n    margin-top: -1px;\n    margin-bottom: 0;\n    padding: 0;\n    width: 15px;\n}\n\n.table .radio .icons,\n.table .checkbox .icons {\n    position: relative;\n}\n\n.table>thead>tr>th,\n.table>tbody>tr>th,\n.table>tfoot>tr>th,\n.table>thead>tr>td,\n.table>tbody>tr>td,\n.table>tfoot>tr>td {\n    padding: 12px 8px;\n    vertical-align: middle;\n}\n\n.table .th-description {\n    max-width: 150px;\n}\n\n.table .td-price {\n    font-size: 26px;\n    font-weight: 300;\n    margin-top: 5px;\n    text-align: right;\n}\n\n.table .td-total {\n    font-weight: 500;\n    font-size: 1.25em;\n    padding-top: 14px;\n    text-align: right;\n}\n\n.table .td-actions .btn {\n    margin: 0px;\n    padding: 5px;\n}\n\n.table>tbody>tr {\n    position: relative;\n}\n\n.table .flag img {\n    max-width: 18px;\n    margin-top: -2px;\n}\n\n.table-sales {\n    margin-top: 40px;\n}\n\n.table-shopping>thead>tr>th {\n    font-size: 0.9em;\n    text-transform: uppercase;\n}\n\n.table-shopping>tbody>tr>td {\n    font-size: 16px;\n}\n\n.table-shopping>tbody>tr>td b {\n    display: block;\n    margin-bottom: 5px;\n}\n\n.table-shopping .td-name {\n    font-weight: 400;\n    font-size: 1.5em;\n}\n\n.table-shopping .td-name small {\n    color: #999999;\n    font-size: 0.75em;\n    font-weight: 300;\n}\n\n.table-shopping .td-number {\n    font-weight: 300;\n    font-size: 1.3em;\n}\n\n.table-shopping .td-name {\n    min-width: 200px;\n}\n\n.table-shopping .td-name a {\n    color: #3C4858;\n}\n\n.table-shopping .td-name a:hover,\n.table-shopping .td-name a:focus {\n    color: #9c27b0;\n}\n\n.table-shopping .td-number {\n    text-align: right;\n    min-width: 145px;\n}\n\n.table-shopping .td-number small {\n    margin-right: 3px;\n}\n\n.table-shopping .img-container {\n    width: 120px;\n    max-height: 160px;\n    overflow: hidden;\n    display: block;\n}\n\n.table-shopping .img-container img {\n    width: 100%;\n}\n\n.form-category {\n    padding: 10px 0 10px;\n}\n\n.form-category .checkbox {\n    margin: 0;\n}\n\n.form-group.form-checkbox {\n    padding-top: 10px;\n}\n\nform .form-footer .checkbox {\n    padding-top: 5px;\n}\n\n.card .form-horizontal .label-on-left {\n    padding: 28px 5px 0 0;\n    text-align: right;\n}\n\n.card .form-horizontal .label-on-right {\n    padding: 28px 0 0 5px;\n    text-align: left;\n}\n\n.form-horizontal .form-horizontal-checkbox {\n    margin-top: 2px;\n    margin-bottom: 10px;\n}\n\n.form-horizontal .checkbox-radios .checkbox:first-child,\n.form-horizontal .checkbox-radios .radio:first-child {\n    margin-top: 16px;\n}\n\n.form-horizontal .checkbox-radios .radio {\n    padding-top: 10px;\n}\n\n.form-horizontal .form-group {\n    margin-left: 0;\n    margin-right: 0;\n}\n\n.form-horizontal .form-button {\n    padding: 0;\n    margin: 0;\n}\n\n.form-horizontal .checkbox-inline {\n    margin-top: 16px;\n    padding-left: 0;\n}\n\n.form-horizontal .radio label {\n    padding-left: 28px;\n}\n\n.form-horizontal .radio label span {\n    left: 2px;\n}\n\n.form-horizontal label.control-label {\n    margin: 0;\n}\n\n.form-horizontal .form-control[type=\"password\"] {\n    padding-top: 8px;\n    padding-bottom: 6px;\n}\n\n.form-newsletter .input-group,\n.form-newsletter .form-group {\n    float: left;\n    width: 78%;\n    margin-right: 2%;\n    margin-top: 9px;\n}\n\n.form-newsletter .btn {\n    float: left;\n    width: 20%;\n    margin: 9px 0 0;\n}\n\n.checkbox label {\n    cursor: pointer;\n    padding-left: 0;\n    color: rgba(0, 0, 0, 0.26);\n}\n\n.form-group.is-focused .checkbox label {\n    color: rgba(0, 0, 0, 0.26);\n}\n\n.form-group.is-focused .checkbox label:hover,\n.form-group.is-focused .checkbox label:focus {\n    color: rgba(0, 0, 0, .54);\n}\n\nfieldset[disabled] .form-group.is-focused .checkbox label {\n    color: rgba(0, 0, 0, 0.26);\n}\n\n.checkbox input[type=checkbox] {\n    opacity: 0;\n    position: absolute;\n    margin: 0;\n    z-index: -1;\n    width: 0;\n    height: 0;\n    overflow: hidden;\n    left: 0;\n    pointer-events: none;\n}\n\n.checkbox .checkbox-material {\n    vertical-align: middle;\n    position: relative;\n    top: 3px;\n    padding-right: 5px;\n}\n\n.checkbox .checkbox-material:before {\n    display: block;\n    position: absolute;\n    left: 0;\n    content: \"\";\n    background-color: rgba(0, 0, 0, 0.84);\n    height: 20px;\n    width: 20px;\n    border-radius: 100%;\n    z-index: 1;\n    opacity: 0;\n    margin: 0;\n    transform: scale3d(2.3, 2.3, 1);\n    top: -7px;\n}\n\n.checkbox .checkbox-material .check {\n    position: relative;\n    display: inline-block;\n    width: 20px;\n    height: 20px;\n    border: 1px solid rgba(0, 0, 0, .54);\n    overflow: hidden;\n    z-index: 1;\n    border-radius: 3px;\n}\n\n.checkbox .checkbox-material .check:before {\n    position: absolute;\n    content: \"\";\n    transform: rotate(45deg);\n    display: block;\n    margin-top: -3px;\n    margin-left: 7px;\n    width: 0;\n    height: 0;\n    background: red;\n    box-shadow: 0 0 0 0, 0 0 0 0, 0 0 0 0, 0 0 0 0, 0 0 0 0, 0 0 0 0, 0 0 0 0 inset;\n    animation: checkbox-off 0.3s forwards;\n}\n\n.checkbox input[type=checkbox]:focus+.checkbox-material .check:after {\n    opacity: 0.2;\n}\n\n.checkbox input[type=checkbox]:checked+.checkbox-material .check {\n    background: #9c27b0;\n}\n\n.checkbox input[type=checkbox]:checked+.checkbox-material .check:before {\n    color: #FFFFFF;\n    box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px;\n    animation: checkbox-on 0.3s forwards;\n}\n\n.checkbox input[type=checkbox]:checked+.checkbox-material:before {\n    animation: rippleOn 500ms;\n}\n\n.checkbox input[type=checkbox]:checked+.checkbox-material .check:after {\n    animation: rippleOn 500ms forwards;\n}\n\n.checkbox input[type=checkbox]:not(:checked)+.checkbox-material:before {\n    animation: rippleOff 500ms;\n}\n\n.checkbox input[type=checkbox]:not(:checked)+.checkbox-material .check:after {\n    animation: rippleOff 500ms;\n}\n\nfieldset[disabled] .checkbox,\nfieldset[disabled] .checkbox input[type=checkbox],\n.checkbox input[type=checkbox][disabled]~.checkbox-material .check,\n.checkbox input[type=checkbox][disabled]+.circle {\n    opacity: 0.5;\n}\n\n.checkbox input[type=checkbox][disabled]~.checkbox-material .check {\n    border-color: #000000;\n    opacity: .26;\n}\n\n.checkbox input[type=checkbox][disabled]+.checkbox-material .check:after {\n    background-color: rgba(0, 0, 0, 0.87);\n    transform: rotate(-45deg);\n}\n\n.checkbox.has-error label {\n    color: #f44336;\n}\n\n@keyframes checkbox-on {\n    0% {\n        box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 15px 2px 0 11px;\n    }\n    50% {\n        box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px 2px 0 11px;\n    }\n    100% {\n        box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0px 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px;\n    }\n}\n\n@keyframes rippleOn {\n    0% {\n        opacity: 0;\n    }\n    50% {\n        opacity: 0.2;\n    }\n    100% {\n        opacity: 0;\n    }\n}\n\n@keyframes rippleOff {\n    0% {\n        opacity: 0;\n    }\n    50% {\n        opacity: 0.2;\n    }\n    100% {\n        opacity: 0;\n    }\n}\n\n.radio label {\n    cursor: pointer;\n    padding-left: 35px;\n    position: relative;\n    color: rgba(0, 0, 0, 0.26);\n}\n\n.form-group.is-focused .radio label {\n    color: rgba(0, 0, 0, 0.26);\n}\n\n.form-group.is-focused .radio label:hover,\n.form-group.is-focused .radio label:focus {\n    color: rgba(0, 0, 0, .54);\n}\n\nfieldset[disabled] .form-group.is-focused .radio label {\n    color: rgba(0, 0, 0, 0.26);\n}\n\n.radio label span {\n    display: block;\n    position: absolute;\n    left: 10px;\n    top: 2px;\n    transition-duration: 0.2s;\n}\n\n.radio label .circle {\n    border: 1px solid rgba(0, 0, 0, .54);\n    height: 15px;\n    width: 15px;\n    border-radius: 100%;\n}\n\n.radio label .check {\n    height: 15px;\n    width: 15px;\n    border-radius: 100%;\n    background-color: #9c27b0;\n    transform: scale3d(0, 0, 0);\n}\n\n.radio label .check:after {\n    display: block;\n    position: absolute;\n    content: \"\";\n    background-color: rgba(0, 0, 0, 0.87);\n    left: -18px;\n    top: -18px;\n    height: 50px;\n    width: 50px;\n    border-radius: 100%;\n    z-index: 1;\n    opacity: 0;\n    margin: 0;\n    transform: scale3d(1.5, 1.5, 1);\n}\n\n.radio label input[type=radio]:not(:checked)~.check:after {\n    animation: rippleOff 500ms;\n}\n\n.radio label input[type=radio]:checked~.check:after {\n    animation: rippleOn 500ms;\n}\n\n.radio.has-error label {\n    color: #f44336;\n}\n\n.radio input[type=radio] {\n    opacity: 0;\n    height: 0;\n    width: 0;\n    overflow: hidden;\n}\n\n.radio input[type=radio]:checked~.check,\n.radio input[type=radio]:checked~.circle {\n    opacity: 1;\n}\n\n.radio input[type=radio]:checked~.check {\n    background-color: #9c27b0;\n}\n\n.radio input[type=radio]:checked~.circle {\n    border-color: #9c27b0;\n}\n\n.radio input[type=radio]:checked~.check {\n    transform: scale3d(0.65, 0.65, 1);\n}\n\n.radio input[type=radio][disabled]~.check,\n.radio input[type=radio][disabled]~.circle {\n    opacity: 0.26;\n}\n\n.radio input[type=radio][disabled]~.check {\n    background-color: #000000;\n}\n\n.radio input[type=radio][disabled]~.circle {\n    border-color: #000000;\n}\n\n@keyframes rippleOn {\n    0% {\n        opacity: 0;\n    }\n    50% {\n        opacity: 0.2;\n    }\n    100% {\n        opacity: 0;\n    }\n}\n\n@keyframes rippleOff {\n    0% {\n        opacity: 0;\n    }\n    50% {\n        opacity: 0.2;\n    }\n    100% {\n        opacity: 0;\n    }\n}\n\n.progress {\n    height: 4px;\n    border-radius: 0;\n    box-shadow: none;\n    background: #DDDDDD;\n}\n\n.progress .progress-bar {\n    box-shadow: none;\n}\n\n.progress .progress-bar,\n.progress .progress-bar.progress-bar-default {\n    background-color: #FFFFFF;\n}\n\n.progress .progress-bar.progress-bar-inverse {\n    background-color: #212121;\n}\n\n.progress .progress-bar.progress-bar-primary {\n    background-color: #9c27b0;\n}\n\n.progress .progress-bar.progress-bar-success {\n    background-color: #4caf50;\n}\n\n.progress .progress-bar.progress-bar-info {\n    background-color: #00bcd4;\n}\n\n.progress .progress-bar.progress-bar-warning {\n    background-color: #ff9800;\n}\n\n.progress .progress-bar.progress-bar-danger {\n    background-color: #f44336;\n}\n\n.progress .progress-bar.progress-bar-rose {\n    background-color: #e91e63;\n}\n\n.progress.progress-line-primary {\n    background: rgba(156, 39, 176, 0.2);\n}\n\n.progress.progress-line-info {\n    background: rgba(0, 188, 212, 0.2);\n}\n\n.progress.progress-line-success {\n    background: rgba(76, 175, 80, 0.2);\n}\n\n.progress.progress-line-warning {\n    background: rgba(255, 152, 0, 0.2);\n}\n\n.progress.progress-line-danger {\n    background: rgba(244, 67, 54, 0.2);\n}\n\n.progress .progress-bar,\n.progress .progress-bar.progress-bar-default {\n    background-color: #9c27b0;\n}\n\n.togglebutton {\n    vertical-align: middle;\n}\n\n.togglebutton,\n.togglebutton label,\n.togglebutton input,\n.togglebutton .toggle {\n    user-select: none;\n}\n\n.togglebutton label {\n    cursor: pointer;\n    color: rgba(0, 0, 0, 0.26);\n}\n\n.form-group.is-focused .togglebutton label {\n    color: rgba(0, 0, 0, 0.26);\n}\n\n.form-group.is-focused .togglebutton label:hover,\n.form-group.is-focused .togglebutton label:focus {\n    color: rgba(0, 0, 0, .54);\n}\n\nfieldset[disabled] .form-group.is-focused .togglebutton label {\n    color: rgba(0, 0, 0, 0.26);\n}\n\n.togglebutton label input[type=checkbox] {\n    opacity: 0;\n    width: 0;\n    height: 0;\n}\n\n.togglebutton label .toggle {\n    text-align: left;\n    margin-left: 5px;\n}\n\n.togglebutton label .toggle,\n.togglebutton label input[type=checkbox][disabled]+.toggle {\n    content: \"\";\n    display: inline-block;\n    width: 30px;\n    height: 15px;\n    background-color: rgba(80, 80, 80, 0.7);\n    border-radius: 15px;\n    margin-right: 15px;\n    transition: background 0.3s ease;\n    vertical-align: middle;\n}\n\n.togglebutton label .toggle:after {\n    content: \"\";\n    display: inline-block;\n    width: 20px;\n    height: 20px;\n    background-color: #FFFFFF;\n    border-radius: 20px;\n    position: relative;\n    box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.4);\n    left: -5px;\n    top: -3px;\n    border: 1px solid rgba(0, 0, 0, .54);\n    transition: left 0.3s ease, background 0.3s ease, box-shadow 0.1s ease;\n}\n\n.togglebutton label input[type=checkbox][disabled]+.toggle:after,\n.togglebutton label input[type=checkbox][disabled]:checked+.toggle:after {\n    background-color: #BDBDBD;\n}\n\n.togglebutton label input[type=checkbox]+.toggle:active:after,\n.togglebutton label input[type=checkbox][disabled]+.toggle:active:after {\n    box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.4), 0 0 0 15px rgba(0, 0, 0, 0.1);\n}\n\n.togglebutton label input[type=checkbox]:checked+.toggle:after {\n    left: 15px;\n}\n\n.togglebutton label input[type=checkbox]:checked+.toggle {\n    background-color: rgba(156, 39, 176, 0.7);\n}\n\n.togglebutton label input[type=checkbox]:checked+.toggle:after {\n    border-color: #9c27b0;\n}\n\n.togglebutton label input[type=checkbox]:checked+.toggle:active:after {\n    box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.4), 0 0 0 15px rgba(156, 39, 176, 0.1);\n}\n\n.wrapper:after {\n    display: table;\n    clear: both;\n    content: \" \";\n}\n\n.wrapper.wrapper-full-page {\n    height: auto;\n    min-height: 100vh;\n}\n\n.full-page:after,\n.full-page:before {\n    display: block;\n    content: \"\";\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    top: 0;\n    left: 0;\n    z-index: 2;\n}\n\n.full-page:before {\n    background-color: rgba(0, 0, 0, 0.5);\n}\n\n.full-page[filter-color=\"purple\"]:after,\n.full-page[filter-color=\"primary\"]:after {\n    background: rgba(225, 190, 231, 0.56);\n    /* For browsers that do not support gradients */\n    background: -webkit-linear-gradient(60deg, rgba(225, 190, 231, 0.56), rgba(186, 104, 200, 0.95));\n    /* For Safari 5.1 to 6.0 */\n    background: -o-linear-gradient(60deg, rgba(225, 190, 231, 0.56), rgba(186, 104, 200, 0.95));\n    /* For Opera 11.1 to 12.0 */\n    background: -moz-linear-gradient(60deg, rgba(225, 190, 231, 0.56), rgba(186, 104, 200, 0.95));\n    /* For Firefox 3.6 to 15 */\n    background: linear-gradient(60deg, rgba(225, 190, 231, 0.56), rgba(186, 104, 200, 0.95));\n    /* Standard syntax */\n}\n\n.full-page[filter-color=\"purple\"].lock-page .form-group .form-control,\n.full-page[filter-color=\"primary\"].lock-page .form-group .form-control {\n    background-image: linear-gradient(#9c27b0, #9c27b0), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.full-page[filter-color=\"blue\"]:after,\n.full-page[filter-color=\"info\"]:after {\n    background: rgba(178, 235, 242, 0.56);\n    /* For browsers that do not support gradients */\n    background: -webkit-linear-gradient(60deg, rgba(178, 235, 242, 0.56), rgba(77, 208, 225, 0.95));\n    /* For Safari 5.1 to 6.0 */\n    background: -o-linear-gradient(60deg, rgba(178, 235, 242, 0.56), rgba(77, 208, 225, 0.95));\n    /* For Opera 11.1 to 12.0 */\n    background: -moz-linear-gradient(60deg, rgba(178, 235, 242, 0.56), rgba(77, 208, 225, 0.95));\n    /* For Firefox 3.6 to 15 */\n    background: linear-gradient(60deg, rgba(178, 235, 242, 0.56), rgba(77, 208, 225, 0.95));\n    /* Standard syntax */\n}\n\n.full-page[filter-color=\"blue\"].lock-page .form-group .form-control,\n.full-page[filter-color=\"info\"].lock-page .form-group .form-control {\n    background-image: linear-gradient(#00bcd4, #00bcd4), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.full-page[filter-color=\"green\"]:after,\n.full-page[filter-color=\"success\"]:after {\n    background: rgba(165, 214, 167, 0.56);\n    /* For browsers that do not support gradients */\n    background: -webkit-linear-gradient(60deg, rgba(165, 214, 167, 0.56), rgba(102, 187, 106, 0.95));\n    /* For Safari 5.1 to 6.0 */\n    background: -o-linear-gradient(60deg, rgba(165, 214, 167, 0.56), rgba(102, 187, 106, 0.95));\n    /* For Opera 11.1 to 12.0 */\n    background: -moz-linear-gradient(60deg, rgba(165, 214, 167, 0.56), rgba(102, 187, 106, 0.95));\n    /* For Firefox 3.6 to 15 */\n    background: linear-gradient(60deg, rgba(165, 214, 167, 0.56), rgba(102, 187, 106, 0.95));\n    /* Standard syntax */\n}\n\n.full-page[filter-color=\"green\"].lock-page .form-group .form-control,\n.full-page[filter-color=\"success\"].lock-page .form-group .form-control {\n    background-image: linear-gradient(#4caf50, #4caf50), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.full-page[filter-color=\"orange\"]:after,\n.full-page[filter-color=\"warning\"]:after {\n    background: rgba(255, 224, 178, 0.56);\n    /* For browsers that do not support gradients */\n    background: -webkit-linear-gradient(60deg, rgba(255, 224, 178, 0.56), rgba(255, 183, 77, 0.95));\n    /* For Safari 5.1 to 6.0 */\n    background: -o-linear-gradient(60deg, rgba(255, 224, 178, 0.56), rgba(255, 183, 77, 0.95));\n    /* For Opera 11.1 to 12.0 */\n    background: -moz-linear-gradient(60deg, rgba(255, 224, 178, 0.56), rgba(255, 183, 77, 0.95));\n    /* For Firefox 3.6 to 15 */\n    background: linear-gradient(60deg, rgba(255, 224, 178, 0.56), rgba(255, 183, 77, 0.95));\n    /* Standard syntax */\n}\n\n.full-page[filter-color=\"orange\"].lock-page .form-group .form-control,\n.full-page[filter-color=\"warning\"].lock-page .form-group .form-control {\n    background-image: linear-gradient(#ff9800, #ff9800), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.full-page[filter-color=\"red\"]:after,\n.full-page[filter-color=\"danger\"]:after {\n    background: rgba(239, 154, 154, 0.56);\n    /* For browsers that do not support gradients */\n    background: -webkit-linear-gradient(60deg, rgba(239, 154, 154, 0.56), rgba(239, 83, 80, 0.95));\n    /* For Safari 5.1 to 6.0 */\n    background: -o-linear-gradient(60deg, rgba(239, 154, 154, 0.56), rgba(239, 83, 80, 0.95));\n    /* For Opera 11.1 to 12.0 */\n    background: -moz-linear-gradient(60deg, rgba(239, 154, 154, 0.56), rgba(239, 83, 80, 0.95));\n    /* For Firefox 3.6 to 15 */\n    background: linear-gradient(60deg, rgba(239, 154, 154, 0.56), rgba(239, 83, 80, 0.95));\n    /* Standard syntax */\n}\n\n.full-page[filter-color=\"red\"].lock-page .form-group .form-control,\n.full-page[filter-color=\"danger\"].lock-page .form-group .form-control {\n    background-image: linear-gradient(#f44336, #f44336), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.full-page[filter-color=\"rose\"]:after {\n    background: rgba(248, 187, 208, 0.56);\n    /* For browsers that do not support gradients */\n    background: -webkit-linear-gradient(60deg, rgba(248, 187, 208, 0.56), rgba(240, 98, 146, 0.95));\n    /* For Safari 5.1 to 6.0 */\n    background: -o-linear-gradient(60deg, rgba(248, 187, 208, 0.56), rgba(240, 98, 146, 0.95));\n    /* For Opera 11.1 to 12.0 */\n    background: -moz-linear-gradient(60deg, rgba(248, 187, 208, 0.56), rgba(240, 98, 146, 0.95));\n    /* For Firefox 3.6 to 15 */\n    background: linear-gradient(60deg, rgba(248, 187, 208, 0.56), rgba(240, 98, 146, 0.95));\n    /* Standard syntax */\n}\n\n.full-page[filter-color=\"rose\"].lock-page .form-group .form-control {\n    background-image: linear-gradient(#e91e63, #e91e63), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.full-page[data-image]:after {\n    opacity: .8;\n}\n\n.full-page>.content,\n.full-page>.footer {\n    position: relative;\n    z-index: 4;\n}\n\n.full-page>.content {\n    min-height: calc(100vh - 80px);\n}\n\n.full-page .full-page-background {\n    position: absolute;\n    z-index: 1;\n    height: 100%;\n    width: 100%;\n    display: block;\n    top: 0;\n    left: 0;\n    background-size: cover;\n    background-position: center center;\n}\n\n.full-page .footer nav>ul a:not(.btn),\n.full-page .footer,\n.full-page .footer .copyright a {\n    color: #FFFFFF;\n}\n\n.clear-filter:before {\n    display: none;\n}\n\n.login-page>.content,\n.lock-page>.content {\n    padding-top: 18vh;\n}\n\n.login-page .card-login {\n    box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.14);\n    border-radius: 6px;\n    padding-bottom: 20px;\n    -webkit-transform: translate3d(0, 0, 0);\n    -moz-transform: translate3d(0, 0, 0);\n    -o-transform: translate3d(0, 0, 0);\n    -ms-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n}\n\n.login-page .card-login.card-hidden {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -60px, 0);\n    -moz-transform: translate3d(0, -60px, 0);\n    -o-transform: translate3d(0, -60px, 0);\n    -ms-transform: translate3d(0, -60px, 0);\n    transform: translate3d(0, -60px, 0);\n}\n\n.login-page .card-login .btn-wd {\n    min-width: 180px;\n}\n\n.login-page .card-login .card-header {\n    margin-top: -40px;\n    margin-bottom: 20px;\n}\n\n.login-page .card-login .card-header .title {\n    margin-top: 10px;\n}\n\n.lock-page .card-profile {\n    width: 240px;\n    margin: 60px auto 0;\n    color: #FFFFFF;\n    position: absolute;\n    left: 0;\n    right: 0;\n    display: block;\n    -webkit-transform: translate3d(0, 0, 0);\n    -moz-transform: translate3d(0, 0, 0);\n    -o-transform: translate3d(0, 0, 0);\n    -ms-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n}\n\n.lock-page .card-profile.card-hidden {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -60px, 0);\n    -moz-transform: translate3d(0, -60px, 0);\n    -o-transform: translate3d(0, -60px, 0);\n    -ms-transform: translate3d(0, -60px, 0);\n    transform: translate3d(0, -60px, 0);\n}\n\n.lock-page .card-profile .card-avatar {\n    max-width: 90px;\n    max-height: 90px;\n    margin-top: -45px;\n}\n\n.lock-page .card-profile .card-footer {\n    border: none;\n    padding-top: 0;\n}\n\n.lock-page .card-profile .form-group {\n    text-align: left;\n}\n\n.lock-page .card-profile .form-group .form-control {\n    background-image: linear-gradient(#e91e63, #e91e63), linear-gradient(#D2D2D2, #D2D2D2);\n}\n\n.lock-page .card-profile.with-animation {\n    -webkit-transition: all 300ms ease-in;\n    -moz-transition: all 300ms ease-in;\n    -o-transition: all 300ms ease-in;\n    -ms-transition: all 300ms ease-in;\n    transition: all 300ms ease-in;\n}\n\n.register-page .card-signup {\n    border-radius: 6px;\n    box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2);\n    margin-bottom: 100px;\n    padding: 40px 0px;\n}\n\n.register-page .card-signup .info {\n    max-width: 360px;\n    margin: 0 auto;\n    padding: 0px;\n}\n\n.register-page .card-signup .info .info-title {\n    color: #3C4858;\n    margin: 30px 0 15px;\n}\n\n.register-page .card-signup .checkbox {\n    margin-top: 20px;\n    margin-bottom: 0;\n}\n\n.register-page .card-signup .checkbox label {\n    margin-left: 17px;\n}\n\n.register-page .card-signup .checkbox .checkbox-material {\n    padding-right: 20px;\n}\n\n.register-page .card-signup .input-group .input-group-addon {\n    padding-top: 21px;\n}\n\n.register-page .card-signup .info-horizontal .icon {\n    float: left;\n    margin-top: 24px;\n    margin-right: 10px;\n}\n\n.register-page .card-signup .info-horizontal .icon i {\n    font-size: 2.6em;\n}\n\n.register-page .card-signup .info-horizontal .icon.icon-primary {\n    color: #9c27b0;\n}\n\n.register-page .card-signup .info-horizontal .icon.icon-info {\n    color: #00bcd4;\n}\n\n.register-page .card-signup .info-horizontal .icon.icon-success {\n    color: #4caf50;\n}\n\n.register-page .card-signup .info-horizontal .icon.icon-warning {\n    color: #ff9800;\n}\n\n.register-page .card-signup .info-horizontal .icon.icon-danger {\n    color: #f44336;\n}\n\n.register-page .card-signup .info-horizontal .icon.icon-rose {\n    color: #e91e63;\n}\n\n.register-page .card-signup .info-horizontal .description {\n    overflow: hidden;\n}\n\n.register-page .card-signup .form-group {\n    margin: 27px 0 0 7px;\n    padding-bottom: 0;\n}\n\n.register-page .container {\n    position: relative;\n    z-index: 3;\n    padding-top: 15vh;\n}\n\n.register-page .footer .container {\n    padding: 0;\n}\n\n.pricing-page .title {\n    color: #FFFFFF;\n    margin-top: 13vh;\n}\n\n.pricing-page .section-space {\n    display: block;\n    height: 70px;\n}\n\n.pricing-page .card-plain .icon i,\n.pricing-page .card-plain .card-title {\n    color: #FFFFFF;\n}\n\n.pricing-page .description {\n    color: #FFFFFF;\n}\n\n.pricing-page.full-page:before {\n    background-color: rgba(0, 0, 0, 0.65);\n}\n\n\n/*\n * bootstrap-tagsinput v0.8.0\n *\n */\n\n.bootstrap-tagsinput {\n    display: inline-block;\n    padding: 4px 6px;\n    max-width: 100%;\n    line-height: 22px;\n}\n\n.bootstrap-tagsinput input {\n    border: none;\n    box-shadow: none;\n    outline: none;\n    background-color: transparent;\n    margin: 0;\n    width: 74px;\n    max-width: inherit;\n}\n\n.bootstrap-tagsinput input:focus {\n    border: none;\n    box-shadow: none;\n}\n\n.bootstrap-tagsinput.form-control input::-moz-placeholder {\n    color: #777;\n    opacity: 1;\n}\n\n.bootstrap-tagsinput.form-control input:-ms-input-placeholder,\n.bootstrap-tagsinput.form-control input::-webkit-input-placeholder {\n    color: #777;\n}\n\n.bootstrap-tagsinput .tag {\n    cursor: pointer;\n    margin: 5px 3px 5px 0;\n    position: relative;\n    padding: 3px 8px;\n    border-radius: 12px;\n    color: #FFFFFF;\n    font-weight: 500;\n    font-size: 0.75em;\n    text-transform: uppercase;\n    display: inline-block;\n    line-height: 1.5em;\n    padding-left: 0.8em;\n}\n\n.bootstrap-tagsinput .tag.tag-primary {\n    background-color: #9c27b0;\n    color: #FFFFFF;\n}\n\n.bootstrap-tagsinput .tag.tag-info {\n    background-color: #00bcd4;\n    color: #FFFFFF;\n}\n\n.bootstrap-tagsinput .tag.tag-success {\n    background-color: #4caf50;\n    color: #FFFFFF;\n}\n\n.bootstrap-tagsinput .tag.tag-warning {\n    background-color: #ff9800;\n    color: #FFFFFF;\n}\n\n.bootstrap-tagsinput .tag.tag-danger {\n    background-color: #f44336;\n    color: #FFFFFF;\n}\n\n.bootstrap-tagsinput .tag.tag-rose {\n    background-color: #e91e63;\n    color: #FFFFFF;\n}\n\n.bootstrap-tagsinput .tag:hover {\n    padding-right: 18px;\n}\n\n.bootstrap-tagsinput .tag:hover [data-role=\"remove\"] {\n    opacity: 1;\n    padding-right: 6px;\n}\n\n.bootstrap-tagsinput .tag [data-role=\"remove\"] {\n    cursor: pointer;\n    position: absolute;\n    top: 3px;\n    right: 0;\n    opacity: 0;\n}\n\n.bootstrap-tagsinput .tag [data-role=\"remove\"]:after {\n    content: \"x\";\n    padding: 0px 2px;\n}\n\n.timeline {\n    list-style: none;\n    padding: 20px 0 20px;\n    position: relative;\n    margin-top: 30px;\n}\n\n.timeline:before {\n    top: 50px;\n    bottom: 0;\n    position: absolute;\n    content: \" \";\n    width: 3px;\n    background-color: #E5E5E5;\n    left: 50%;\n    margin-left: -1px;\n}\n\n.timeline h6 {\n    color: #333333;\n    font-weight: 400;\n    margin: 10px 0px 0px;\n}\n\n.timeline.timeline-simple {\n    margin-top: 30px;\n    padding: 0 0 20px;\n}\n\n.timeline.timeline-simple:before {\n    left: 5%;\n    background-color: #E5E5E5;\n}\n\n.timeline.timeline-simple>li>.timeline-panel {\n    width: 86%;\n}\n\n.timeline.timeline-simple>li>.timeline-badge {\n    left: 5%;\n}\n\n.timeline>li {\n    margin-bottom: 20px;\n    position: relative;\n}\n\n.timeline>li:before,\n.timeline>li:after {\n    content: \" \";\n    display: table;\n}\n\n.timeline>li:after {\n    clear: both;\n}\n\n.timeline>li>.timeline-panel {\n    width: 45%;\n    float: left;\n    padding: 20px;\n    margin-bottom: 20px;\n    position: relative;\n    box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.14);\n    border-radius: 6px;\n    color: rgba(0, 0, 0, 0.87);\n    background: #fff;\n}\n\n.timeline>li>.timeline-panel:before {\n    position: absolute;\n    top: 26px;\n    right: -15px;\n    display: inline-block;\n    border-top: 15px solid transparent;\n    border-left: 15px solid #e4e4e4;\n    border-right: 0 solid #e4e4e4;\n    border-bottom: 15px solid transparent;\n    content: \" \";\n}\n\n.timeline>li>.timeline-panel:after {\n    position: absolute;\n    top: 27px;\n    right: -14px;\n    display: inline-block;\n    border-top: 14px solid transparent;\n    border-left: 14px solid #FFFFFF;\n    border-right: 0 solid #FFFFFF;\n    border-bottom: 14px solid transparent;\n    content: \" \";\n}\n\n.timeline>li>.timeline-badge {\n    color: #FFFFFF;\n    width: 50px;\n    height: 50px;\n    line-height: 51px;\n    font-size: 1.4em;\n    text-align: center;\n    position: absolute;\n    top: 16px;\n    left: 50%;\n    margin-left: -24px;\n    z-index: 100;\n    border-top-right-radius: 50%;\n    border-top-left-radius: 50%;\n    border-bottom-right-radius: 50%;\n    border-bottom-left-radius: 50%;\n}\n\n.timeline>li>.timeline-badge.primary {\n    background-color: #9c27b0;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(156, 39, 176, 0.4);\n}\n\n.timeline>li>.timeline-badge.success {\n    background-color: #4caf50;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(76, 175, 80, 0.4);\n}\n\n.timeline>li>.timeline-badge.warning {\n    background-color: #ff9800;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 152, 0, 0.4);\n}\n\n.timeline>li>.timeline-badge.info {\n    background-color: #00bcd4;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(0, 188, 212, 0.4);\n}\n\n.timeline>li>.timeline-badge.danger {\n    background-color: #f44336;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(244, 67, 54, 0.4);\n}\n\n.timeline>li>.timeline-badge [class^=\"ti-\"],\n.timeline>li>.timeline-badge [class*=\" ti-\"],\n.timeline>li>.timeline-badge [class=\"material-icons\"] {\n    line-height: inherit;\n}\n\n.timeline>li.timeline-inverted>.timeline-panel {\n    float: right;\n    background-color: #FFFFFF;\n}\n\n.timeline>li.timeline-inverted>.timeline-panel:before {\n    border-left-width: 0;\n    border-right-width: 15px;\n    left: -15px;\n    right: auto;\n}\n\n.timeline>li.timeline-inverted>.timeline-panel:after {\n    border-left-width: 0;\n    border-right-width: 14px;\n    left: -14px;\n    right: auto;\n}\n\n.timeline-heading {\n    margin-bottom: 15px;\n}\n\n.timeline-title {\n    margin-top: 0;\n    color: inherit;\n}\n\n.timeline-body hr {\n    margin-top: 10px;\n    margin-bottom: 5px;\n}\n\n.timeline-body .btn {\n    margin-bottom: 0;\n}\n\n.timeline-body>p,\n.timeline-body>ul {\n    margin-bottom: 0;\n}\n\n.timeline-body>p+p {\n    margin-top: 5px;\n}\n\n.withripple {\n    position: relative;\n}\n\n.ripple-container {\n    position: absolute;\n    top: 0;\n    left: 0;\n    z-index: 1;\n    width: 100%;\n    height: 100%;\n    overflow: hidden;\n    border-radius: inherit;\n    pointer-events: none;\n}\n\n.disabled .ripple-container {\n    display: none;\n}\n\n.ripple {\n    position: absolute;\n    width: 20px;\n    height: 20px;\n    margin-left: -10px;\n    margin-top: -10px;\n    border-radius: 100%;\n    background-color: #000;\n    background-color: rgba(0, 0, 0, 0.05);\n    transform: scale(1);\n    transform-origin: 50%;\n    opacity: 0;\n    pointer-events: none;\n}\n\n.ripple.ripple-on {\n    transition: opacity 0.15s ease-in 0s, transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;\n    opacity: 0.1;\n}\n\n.ripple.ripple-out {\n    transition: opacity 0.1s linear 0s !important;\n    opacity: 0;\n}\n\n.panel {\n    background-color: transparent;\n    border: 0 none;\n    box-shadow: none;\n}\n\n.panel .panel-heading {\n    background-color: transparent;\n    border-bottom: 1px solid #ddd;\n    padding: 25px 10px 5px 0px;\n}\n\n.panel .panel-heading .panel-title {\n    font-size: 15px;\n    font-weight: bolder;\n}\n\n.panel .panel-heading a {\n    color: #3C4858;\n}\n\n.panel .panel-heading a:hover,\n.panel .panel-heading a:active,\n.panel .panel-heading a[aria-expanded=\"true\"] {\n    color: #e91e63;\n}\n\n.panel .panel-heading a[aria-expanded=\"true\"] .panel-title>i,\n.panel .panel-heading a.expanded .panel-title>i {\n    filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);\n    -webkit-transform: rotate(180deg);\n    -ms-transform: rotate(180deg);\n    transform: rotate(180deg);\n}\n\n.panel .panel-heading i {\n    float: right;\n}\n\n.panel .panel-body {\n    border: 0 none;\n    padding: 15px 0px 5px;\n}\n\n.panel.panel-default .panel-heading+.panel-collapse .panel-body {\n    border: 0 none;\n}\n\n.pagination>li>a,\n.pagination>li>span {\n    border: 0;\n    transition: all .3s;\n    margin: 0 3px;\n    min-width: 30px;\n    height: 30px;\n    font-weight: 400;\n    font-size: 12px;\n    text-transform: uppercase;\n    background: transparent;\n    position: relative;\n    float: left;\n    padding: 6px 12px;\n    line-height: 1.42857;\n    text-decoration: none;\n    color: #337ab7;\n    background-color: #fff;\n    border: 1px solid #ddd;\n    border-top-color: rgb(221, 221, 221);\n    border-right-color: rgb(221, 221, 221);\n    border-bottom-color: rgb(221, 221, 221);\n    border-left-color: rgb(221, 221, 221);\n    margin-left: -1px;\n}\n}\n\n.pagination>li>a:hover,\n.pagination>li>a:focus,\n.pagination>li>span:hover,\n.pagination>li>span:focus {\n    color: #999999;\n}\n\n.pagination>.active>a,\n.pagination>.active>span {\n    color: #999999;\n    text-align: center;\n}\n\n.pagination>.active>a,\n.pagination>.active>a:focus,\n.pagination>.active>a:hover,\n.pagination>.active>span,\n.pagination>.active>span:focus,\n.pagination>.active>span:hover {\n    background-color: #9c27b0;\n    border-color: #9c27b0;\n    color: #FFFFFF;\n    box-shadow: 0 4px 5px 0 rgba(156, 39, 176, 0.14), 0 1px 10px 0 rgba(156, 39, 176, 0.12), 0 2px 4px -1px rgba(156, 39, 176, 0.2);\n}\n\n.pagination.pagination-info>.active>a,\n.pagination.pagination-info>.active>a:focus,\n.pagination.pagination-info>.active>a:hover,\n.pagination.pagination-info>.active>span,\n.pagination.pagination-info>.active>span:focus,\n.pagination.pagination-info>.active>span:hover {\n    background-color: #00bcd4;\n    border-color: #00bcd4;\n    box-shadow: 0 4px 5px 0 rgba(0, 188, 212, 0.14), 0 1px 10px 0 rgba(0, 188, 212, 0.12), 0 2px 4px -1px rgba(0, 188, 212, 0.2);\n}\n\n.pagination.pagination-success>.active>a,\n.pagination.pagination-success>.active>a:focus,\n.pagination.pagination-success>.active>a:hover,\n.pagination.pagination-success>.active>span,\n.pagination.pagination-success>.active>span:focus,\n.pagination.pagination-success>.active>span:hover {\n    background-color: #4caf50;\n    border-color: #4caf50;\n    box-shadow: 0 4px 5px 0 rgba(76, 175, 80, 0.14), 0 1px 10px 0 rgba(76, 175, 80, 0.12), 0 2px 4px -1px rgba(76, 175, 80, 0.2);\n}\n\n.pagination.pagination-warning>.active>a,\n.pagination.pagination-warning>.active>a:focus,\n.pagination.pagination-warning>.active>a:hover,\n.pagination.pagination-warning>.active>span,\n.pagination.pagination-warning>.active>span:focus,\n.pagination.pagination-warning>.active>span:hover {\n    background-color: #ff9800;\n    border-color: #ff9800;\n    box-shadow: 0 4px 5px 0 rgba(255, 152, 0, 0.14), 0 1px 10px 0 rgba(255, 152, 0, 0.12), 0 2px 4px -1px rgba(255, 152, 0, 0.2);\n}\n\n.pagination.pagination-danger>.active>a,\n.pagination.pagination-danger>.active>a:focus,\n.pagination.pagination-danger>.active>a:hover,\n.pagination.pagination-danger>.active>span,\n.pagination.pagination-danger>.active>span:focus,\n.pagination.pagination-danger>.active>span:hover {\n    background-color: #f44336;\n    border-color: #f44336;\n    box-shadow: 0 4px 5px 0 rgba(244, 67, 54, 0.14), 0 1px 10px 0 rgba(244, 67, 54, 0.12), 0 2px 4px -1px rgba(244, 67, 54, 0.2);\n}\n\n.section-dark .nav-pills>li>a,\n.section-image .nav-pills>li>a {\n    color: #999999;\n}\n\n.section-dark .nav-pills>li>a:hover,\n.section-dark .nav-pills>li>a:focus,\n.section-image .nav-pills>li>a:hover,\n.section-image .nav-pills>li>a:focus {\n    background-color: #EEEEEE;\n}\n\n.nav-pills>li>a {\n    line-height: 24px;\n    text-transform: uppercase;\n    font-size: 12px;\n    font-weight: 500;\n    min-width: 100px;\n    text-align: center;\n    color: #555555;\n    transition: all .3s;\n}\n\n.nav-pills>li>a:hover {\n    background-color: rgba(200, 200, 200, 0.2);\n}\n\n.nav-pills>li i {\n    display: block;\n    font-size: 30px;\n    padding: 15px 0;\n}\n\n.nav-pills>li.active>a,\n.nav-pills>li.active>a:focus,\n.nav-pills>li.active>a:hover {\n    background-color: #9c27b0;\n    color: #FFFFFF;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(156, 39, 176, 0.4);\n}\n\n.nav-pills:not(.nav-pills-icons)>li>a {\n    border-radius: 30px;\n}\n\n.nav-pills.nav-stacked>li+li {\n    margin: 10px 0;\n}\n\n.nav-pills.nav-pills-info>li.active>a,\n.nav-pills.nav-pills-info>li.active>a:focus,\n.nav-pills.nav-pills-info>li.active>a:hover {\n    background-color: #00bcd4;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(0, 188, 212, 0.4);\n}\n\n.nav-pills.nav-pills-success>li.active>a,\n.nav-pills.nav-pills-success>li.active>a:focus,\n.nav-pills.nav-pills-success>li.active>a:hover {\n    background-color: #4caf50;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(76, 175, 80, 0.4);\n}\n\n.nav-pills.nav-pills-warning>li.active>a,\n.nav-pills.nav-pills-warning>li.active>a:focus,\n.nav-pills.nav-pills-warning>li.active>a:hover {\n    background-color: #ff9800;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 152, 0, 0.4);\n}\n\n.nav-pills.nav-pills-danger>li.active>a,\n.nav-pills.nav-pills-danger>li.active>a:focus,\n.nav-pills.nav-pills-danger>li.active>a:hover {\n    background-color: #f44336;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 152, 0, 0.4);\n}\n\n.nav-pills.nav-pills-rose>li.active>a,\n.nav-pills.nav-pills-rose>li.active>a:focus,\n.nav-pills.nav-pills-rose>li.active>a:hover {\n    background-color: #e91e63;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(233, 30, 99, 0.4);\n}\n\n.tab-space {\n    padding: 20px 0;\n}\n\n.modal-content {\n    box-shadow: 0 27px 24px 0 rgba(0, 0, 0, 0.2), 0 40px 77px 0 rgba(0, 0, 0, 0.22);\n    border-radius: 6px;\n    border: none;\n}\n\n.modal-content .modal-header {\n    border-bottom: none;\n    padding-top: 24px;\n    padding-right: 24px;\n    padding-bottom: 0;\n    padding-left: 24px;\n}\n\n.modal-content .modal-body {\n    padding-top: 24px;\n    padding-right: 24px;\n    padding-bottom: 16px;\n    padding-left: 24px;\n}\n\n.modal-content .modal-footer {\n    border-top: none;\n}\n\n.modal-content .modal-footer.text-center {\n    text-align: center;\n}\n\n.modal-content .modal-footer button {\n    margin: 0;\n    padding-left: 16px;\n    padding-right: 16px;\n    width: auto;\n}\n\n.modal-content .modal-footer button.pull-left {\n    padding-left: 5px;\n    padding-right: 5px;\n    position: relative;\n    left: -5px;\n}\n\n.modal-content .modal-footer button+button {\n    margin-bottom: 16px;\n}\n\n.modal-content .modal-body+.modal-footer {\n    padding-top: 0;\n}\n\n.modal-backdrop {\n    background: rgba(0, 0, 0, 0.3);\n}\n\n.modal .modal-dialog {\n    margin-top: 100px;\n}\n\n.modal .modal-header .close {\n    color: #999999;\n}\n\n.modal .modal-header .close:hover,\n.modal .modal-header .close:focus {\n    opacity: 1;\n}\n\n.modal .modal-header .close i {\n    font-size: 16px;\n}\n\n.modal-notice .instruction {\n    margin-bottom: 25px;\n}\n\n.modal-notice .picture {\n    max-width: 150px;\n}\n\n.modal-notice .modal-content .btn-raised {\n    margin-bottom: 15px;\n}\n\n.modal-small {\n    width: 300px;\n    margin: 0 auto;\n}\n\n.modal-small .modal-body {\n    margin-top: 20px;\n}\n\n.navbar {\n    border: 0;\n    border-radius: 3px;\n    margin-bottom: 0;\n    border-bottom: 1px solid #ededf3;\n    padding: 10px 0;\n}\n\n.navbar .navbar-brand {\n    position: relative;\n    height: 50px;\n    line-height: 30px;\n    color: inherit;\n    padding: 10px 15px;\n}\n\n.navbar .navbar-brand:hover,\n.navbar .navbar-brand:focus {\n    color: inherit;\n    background-color: transparent;\n}\n\n.navbar .navbar-minimize {\n    float: left;\n    padding: 3px 0 0 15px;\n}\n\n.navbar .notification {\n    position: absolute;\n    top: 5px;\n    border: 1px solid #FFF;\n    right: 10px;\n    font-size: 9px;\n    background: #f44336;\n    color: #FFFFFF;\n    min-width: 20px;\n    padding: 0px 5px;\n    height: 20px;\n    border-radius: 10px;\n    text-align: center;\n    line-height: 19px;\n    vertical-align: middle;\n    display: block;\n}\n\n.navbar .navbar-text {\n    color: inherit;\n    margin-top: 15px;\n    margin-bottom: 15px;\n}\n\n.navbar .navbar-nav>li>a {\n    color: inherit;\n    padding-top: 15px;\n    padding-bottom: 15px;\n    font-weight: 500;\n    font-size: 12px;\n    text-transform: uppercase;\n    border-radius: 3px;\n}\n\n.navbar .navbar-nav>li>a:hover,\n.navbar .navbar-nav>li>a:focus {\n    color: inherit;\n    background-color: transparent;\n}\n\n.navbar .navbar-nav>li>a .material-icons,\n.navbar .navbar-nav>li>a .fa {\n    font-size: 20px;\n}\n\n.navbar .navbar-nav>li>a.btn:not(.btn-just-icon) .fa {\n    position: relative;\n    top: 2px;\n    margin-top: -4px;\n    margin-right: 4px;\n}\n\n.navbar .navbar-nav>li>.dropdown-menu {\n    -webkit-transform: translate3d(0, -20px, 0);\n    -moz-transform: translate3d(0, -20px, 0);\n    -o-transform: translate3d(0, -20px, 0);\n    -ms-transform: translate3d(0, -20px, 0);\n    transform: translate3d(0, -20px, 0);\n}\n\n.navbar .navbar-nav>li.open>.dropdown-menu {\n    -webkit-transform: translate3d(0, 0, 0);\n    -moz-transform: translate3d(0, 0, 0);\n    -o-transform: translate3d(0, 0, 0);\n    -ms-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n}\n\n.navbar .navbar-nav>.active>a,\n.navbar .navbar-nav>.active>a:hover,\n.navbar .navbar-nav>.active>a:focus {\n    color: inherit;\n    background-color: rgba(255, 255, 255, 0.1);\n}\n\n.navbar .navbar-nav>.disabled>a,\n.navbar .navbar-nav>.disabled>a:hover,\n.navbar .navbar-nav>.disabled>a:focus {\n    color: inherit;\n    background-color: transparent;\n    opacity: 0.9;\n}\n\n.navbar .navbar-nav .profile-photo {\n    padding: 0 5px 0;\n}\n\n.navbar .navbar-nav .profile-photo .profile-photo-small {\n    height: 40px;\n    width: 40px;\n}\n\n.navbar .navbar-toggle {\n    border: 0;\n}\n\n.navbar .navbar-toggle:hover,\n.navbar .navbar-toggle:focus {\n    background-color: transparent;\n}\n\n.navbar .navbar-toggle .icon-bar {\n    background-color: inherit;\n    border: 1px solid;\n}\n\n.navbar .navbar-default .navbar-toggle,\n.navbar .navbar-inverse .navbar-toggle {\n    border-color: transparent;\n}\n\n.navbar .navbar-collapse,\n.navbar .navbar-form {\n    border-top: none;\n    box-shadow: none;\n}\n\n.navbar .navbar-nav>.open>a,\n.navbar .navbar-nav>.open>a:hover,\n.navbar .navbar-nav>.open>a:focus {\n    background-color: transparent;\n    color: inherit;\n}\n\n@media (max-width: 767px) {\n    .navbar .navbar-nav .navbar-text {\n        color: inherit;\n        margin-top: 15px;\n        margin-bottom: 15px;\n    }\n    .navbar .navbar-nav .open .dropdown-menu>.dropdown-header {\n        border: 0;\n        color: inherit;\n    }\n    .navbar .navbar-nav .open .dropdown-menu .divider {\n        border-bottom: 1px solid;\n        opacity: 0.08;\n    }\n    .navbar .navbar-nav .open .dropdown-menu>li>a {\n        color: inherit;\n    }\n    .navbar .navbar-nav .open .dropdown-menu>li>a:hover,\n    .navbar .navbar-nav .open .dropdown-menu>li>a:focus {\n        color: inherit;\n        background-color: transparent;\n    }\n    .navbar .navbar-nav .open .dropdown-menu>.active>a,\n    .navbar .navbar-nav .open .dropdown-menu>.active>a:hover,\n    .navbar .navbar-nav .open .dropdown-menu>.active>a:focus {\n        color: inherit;\n        background-color: transparent;\n    }\n    .navbar .navbar-nav .open .dropdown-menu>.disabled>a,\n    .navbar .navbar-nav .open .dropdown-menu>.disabled>a:hover,\n    .navbar .navbar-nav .open .dropdown-menu>.disabled>a:focus {\n        color: inherit;\n        background-color: transparent;\n    }\n}\n\n.navbar.navbar-default .logo-container .brand {\n    color: #555555;\n}\n\n.navbar .navbar-link {\n    color: inherit;\n}\n\n.navbar .navbar-link:hover {\n    color: inherit;\n}\n\n.navbar .btn {\n    margin-top: 0;\n    margin-bottom: 0;\n}\n\n.navbar .btn-link {\n    color: inherit;\n}\n\n.navbar .btn-link:hover,\n.navbar .btn-link:focus {\n    color: inherit;\n}\n\n.navbar .btn-link[disabled]:hover,\n.navbar .btn-link[disabled]:focus,\nfieldset[disabled] .navbar .btn-link:hover,\nfieldset[disabled] .navbar .btn-link:focus {\n    color: inherit;\n}\n\n.navbar .navbar-form {\n    margin: 4px 0 0;\n}\n\n.navbar .navbar-form .form-group {\n    margin: 0;\n    padding: 0;\n}\n\n.navbar .navbar-form .form-group .material-input:before,\n.navbar .navbar-form .form-group.is-focused .material-input:after {\n    background-color: inherit;\n}\n\n.navbar .navbar-form .form-group .form-control,\n.navbar .navbar-form .form-control {\n    border-color: inherit;\n    color: inherit;\n    padding: 0;\n    margin: 0;\n    height: 28px;\n    font-size: 14px;\n    line-height: 1.428571429;\n}\n\n.navbar,\n.navbar.navbar-default {\n    background-color: #FFFFFF;\n    color: #555555;\n}\n\n.navbar .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar .navbar-form input.form-control::-moz-placeholder,\n.navbar.navbar-default .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-default .navbar-form input.form-control::-moz-placeholder {\n    color: #555555;\n}\n\n.navbar .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar .navbar-form input.form-control:-ms-input-placeholder,\n.navbar.navbar-default .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-default .navbar-form input.form-control:-ms-input-placeholder {\n    color: #555555;\n}\n\n.navbar .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar .navbar-form input.form-control::-webkit-input-placeholder,\n.navbar.navbar-default .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-default .navbar-form input.form-control::-webkit-input-placeholder {\n    color: #555555;\n}\n\n.navbar .dropdown-menu,\n.navbar.navbar-default .dropdown-menu {\n    border-radius: 3px !important;\n}\n\n.navbar .dropdown-menu li>a:hover,\n.navbar .dropdown-menu li>a:focus,\n.navbar.navbar-default .dropdown-menu li>a:hover,\n.navbar.navbar-default .dropdown-menu li>a:focus {\n    color: #FFFFFF;\n    background-color: #FFFFFF;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 255, 255, 0.4);\n}\n\n.navbar .dropdown-menu .active>a,\n.navbar.navbar-default .dropdown-menu .active>a {\n    background-color: #FFFFFF;\n    color: #555555;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 255, 255, 0.4);\n}\n\n.navbar .dropdown-menu .active>a:hover,\n.navbar .dropdown-menu .active>a:focus,\n.navbar.navbar-default .dropdown-menu .active>a:hover,\n.navbar.navbar-default .dropdown-menu .active>a:focus {\n    color: #555555;\n}\n\n.navbar.navbar-inverse {\n    background-color: #212121;\n    color: #fff;\n}\n\n.navbar.navbar-inverse .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-inverse .navbar-form input.form-control::-moz-placeholder {\n    color: #fff;\n}\n\n.navbar.navbar-inverse .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-inverse .navbar-form input.form-control:-ms-input-placeholder {\n    color: #fff;\n}\n\n.navbar.navbar-inverse .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-inverse .navbar-form input.form-control::-webkit-input-placeholder {\n    color: #fff;\n}\n\n.navbar.navbar-inverse .dropdown-menu {\n    border-radius: 3px !important;\n}\n\n.navbar.navbar-inverse .dropdown-menu li>a:hover,\n.navbar.navbar-inverse .dropdown-menu li>a:focus {\n    color: #FFFFFF;\n    background-color: #212121;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(33, 33, 33, 0.4);\n}\n\n.navbar.navbar-inverse .dropdown-menu .active>a {\n    background-color: #212121;\n    color: #fff;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(33, 33, 33, 0.4);\n}\n\n.navbar.navbar-inverse .dropdown-menu .active>a:hover,\n.navbar.navbar-inverse .dropdown-menu .active>a:focus {\n    color: #fff;\n}\n\n.navbar.navbar-primary {\n    background-color: #9c27b0;\n    color: #ffffff;\n}\n\n.navbar.navbar-primary .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-primary .navbar-form input.form-control::-moz-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-primary .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-primary .navbar-form input.form-control:-ms-input-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-primary .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-primary .navbar-form input.form-control::-webkit-input-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-primary .dropdown-menu {\n    border-radius: 3px !important;\n}\n\n.navbar.navbar-primary .dropdown-menu li>a:hover,\n.navbar.navbar-primary .dropdown-menu li>a:focus {\n    color: #FFFFFF;\n    background-color: #9c27b0;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(156, 39, 176, 0.4);\n}\n\n.navbar.navbar-primary .dropdown-menu .active>a {\n    background-color: #9c27b0;\n    color: #ffffff;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(156, 39, 176, 0.4);\n}\n\n.navbar.navbar-primary .dropdown-menu .active>a:hover,\n.navbar.navbar-primary .dropdown-menu .active>a:focus {\n    color: #ffffff;\n}\n\n.navbar.navbar-success {\n    background-color: #4caf50;\n    color: #ffffff;\n}\n\n.navbar.navbar-success .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-success .navbar-form input.form-control::-moz-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-success .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-success .navbar-form input.form-control:-ms-input-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-success .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-success .navbar-form input.form-control::-webkit-input-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-success .dropdown-menu {\n    border-radius: 3px !important;\n}\n\n.navbar.navbar-success .dropdown-menu li>a:hover,\n.navbar.navbar-success .dropdown-menu li>a:focus {\n    color: #FFFFFF;\n    background-color: #4caf50;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(76, 175, 80, 0.4);\n}\n\n.navbar.navbar-success .dropdown-menu .active>a {\n    background-color: #4caf50;\n    color: #ffffff;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(76, 175, 80, 0.4);\n}\n\n.navbar.navbar-success .dropdown-menu .active>a:hover,\n.navbar.navbar-success .dropdown-menu .active>a:focus {\n    color: #ffffff;\n}\n\n.navbar.navbar-info {\n    background-color: #00bcd4;\n    color: #ffffff;\n}\n\n.navbar.navbar-info .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-info .navbar-form input.form-control::-moz-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-info .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-info .navbar-form input.form-control:-ms-input-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-info .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-info .navbar-form input.form-control::-webkit-input-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-info .dropdown-menu {\n    border-radius: 3px !important;\n}\n\n.navbar.navbar-info .dropdown-menu li>a:hover,\n.navbar.navbar-info .dropdown-menu li>a:focus {\n    color: #FFFFFF;\n    background-color: #00bcd4;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(0, 188, 212, 0.4);\n}\n\n.navbar.navbar-info .dropdown-menu .active>a {\n    background-color: #00bcd4;\n    color: #ffffff;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(0, 188, 212, 0.4);\n}\n\n.navbar.navbar-info .dropdown-menu .active>a:hover,\n.navbar.navbar-info .dropdown-menu .active>a:focus {\n    color: #ffffff;\n}\n\n.navbar.navbar-warning {\n    background-color: #ff9800;\n    color: #ffffff;\n}\n\n.navbar.navbar-warning .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-warning .navbar-form input.form-control::-moz-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-warning .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-warning .navbar-form input.form-control:-ms-input-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-warning .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-warning .navbar-form input.form-control::-webkit-input-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-warning .dropdown-menu {\n    border-radius: 3px !important;\n}\n\n.navbar.navbar-warning .dropdown-menu li>a:hover,\n.navbar.navbar-warning .dropdown-menu li>a:focus {\n    color: #FFFFFF;\n    background-color: #ff9800;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 152, 0, 0.4);\n}\n\n.navbar.navbar-warning .dropdown-menu .active>a {\n    background-color: #ff9800;\n    color: #ffffff;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 152, 0, 0.4);\n}\n\n.navbar.navbar-warning .dropdown-menu .active>a:hover,\n.navbar.navbar-warning .dropdown-menu .active>a:focus {\n    color: #ffffff;\n}\n\n.navbar.navbar-danger {\n    background-color: #f44336;\n    color: #ffffff;\n}\n\n.navbar.navbar-danger .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-danger .navbar-form input.form-control::-moz-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-danger .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-danger .navbar-form input.form-control:-ms-input-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-danger .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-danger .navbar-form input.form-control::-webkit-input-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-danger .dropdown-menu {\n    border-radius: 3px !important;\n}\n\n.navbar.navbar-danger .dropdown-menu li>a:hover,\n.navbar.navbar-danger .dropdown-menu li>a:focus {\n    color: #FFFFFF;\n    background-color: #f44336;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(244, 67, 54, 0.4);\n}\n\n.navbar.navbar-danger .dropdown-menu .active>a {\n    background-color: #f44336;\n    color: #ffffff;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(244, 67, 54, 0.4);\n}\n\n.navbar.navbar-danger .dropdown-menu .active>a:hover,\n.navbar.navbar-danger .dropdown-menu .active>a:focus {\n    color: #ffffff;\n}\n\n.navbar.navbar-rose {\n    background-color: #e91e63;\n    color: #ffffff;\n}\n\n.navbar.navbar-rose .navbar-form .form-group input.form-control::-moz-placeholder,\n.navbar.navbar-rose .navbar-form input.form-control::-moz-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-rose .navbar-form .form-group input.form-control:-ms-input-placeholder,\n.navbar.navbar-rose .navbar-form input.form-control:-ms-input-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-rose .navbar-form .form-group input.form-control::-webkit-input-placeholder,\n.navbar.navbar-rose .navbar-form input.form-control::-webkit-input-placeholder {\n    color: #ffffff;\n}\n\n.navbar.navbar-rose .dropdown-menu {\n    border-radius: 3px !important;\n}\n\n.navbar.navbar-rose .dropdown-menu li>a:hover,\n.navbar.navbar-rose .dropdown-menu li>a:focus {\n    color: #FFFFFF;\n    background-color: #e91e63;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(233, 30, 99, 0.4);\n}\n\n.navbar.navbar-rose .dropdown-menu .active>a {\n    background-color: #e91e63;\n    color: #ffffff;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(233, 30, 99, 0.4);\n}\n\n.navbar.navbar-rose .dropdown-menu .active>a:hover,\n.navbar.navbar-rose .dropdown-menu .active>a:focus {\n    color: #ffffff;\n}\n\n.navbar-inverse {\n    background-color: #3f51b5;\n}\n\n.navbar.navbar-transparent {\n    background-color: transparent;\n    box-shadow: none;\n    border-bottom: 0;\n}\n\n.navbar.navbar-transparent .logo-container .brand {\n    color: #FFFFFF;\n}\n\n.navbar-fixed-top {\n    border-radius: 0;\n}\n\n@media (max-width: 1199px) {\n    .navbar {\n        /*\n        .navbar-form {\n          margin-top: 10px;\n        }\n    */\n    }\n    .navbar .navbar-brand {\n        height: 50px;\n        padding: 10px 15px;\n    }\n    .navbar .navbar-nav>li>a {\n        padding-top: 15px;\n        padding-bottom: 15px;\n    }\n}\n\n.navbar .alert {\n    border-radius: 0;\n    left: 0;\n    position: absolute;\n    right: 0;\n    top: 85px;\n    width: 100%;\n    z-index: 3;\n    transition: all 0.3s;\n}\n\n.nav-center {\n    text-align: center;\n}\n\n.nav-center .nav-pills-icons {\n    display: inline-block;\n}\n\n.nav-align-center {\n    text-align: center;\n}\n\n.nav-align-center .nav-pills {\n    display: inline-block;\n}\n\n.navbar-absolute {\n    position: absolute;\n    width: 100%;\n    padding-top: 10px;\n    z-index: 1029;\n}\n\n.popover,\n.tooltip-inner {\n    color: #555555;\n    line-height: 1.5em;\n    background: #FFFFFF;\n    border: none;\n    border-radius: 3px;\n    box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2);\n}\n\n.popover {\n    padding: 0;\n    box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2);\n}\n\n.popover.left>.arrow,\n.popover.right>.arrow,\n.popover.top>.arrow,\n.popover.bottom>.arrow {\n    border: none;\n}\n\n.popover-title {\n    background-color: #FFFFFF;\n    border: none;\n    padding: 15px 15px 5px;\n    font-size: 1.3em;\n}\n\n.popover-content {\n    padding: 10px 15px 15px;\n    line-height: 1.4;\n}\n\n.tooltip.in {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 0px, 0);\n    -moz-transform: translate3d(0, 0px, 0);\n    -o-transform: translate3d(0, 0px, 0);\n    -ms-transform: translate3d(0, 0px, 0);\n    transform: translate3d(0, 0px, 0);\n}\n\n.tooltip {\n    opacity: 0;\n    transition: opacity, transform .2s ease;\n    -webkit-transform: translate3d(0, 5px, 0);\n    -moz-transform: translate3d(0, 5px, 0);\n    -o-transform: translate3d(0, 5px, 0);\n    -ms-transform: translate3d(0, 5px, 0);\n    transform: translate3d(0, 5px, 0);\n}\n\n.tooltip.left .tooltip-arrow {\n    border-left-color: #FFFFFF;\n}\n\n.tooltip.right .tooltip-arrow {\n    border-right-color: #FFFFFF;\n}\n\n.tooltip.top .tooltip-arrow {\n    border-top-color: #FFFFFF;\n}\n\n.tooltip.bottom .tooltip-arrow {\n    border-bottom-color: #FFFFFF;\n}\n\n.tooltip-inner {\n    padding: 10px 15px;\n    min-width: 130px;\n}\n\nfooter {\n    padding: 15px 0;\n}\n\nfooter ul {\n    margin-bottom: 0;\n    padding: 0;\n    list-style: none;\n}\n\nfooter ul li {\n    display: inline-block;\n}\n\nfooter ul li a {\n    color: inherit;\n    padding: 15px;\n    font-weight: 500;\n    font-size: 12px;\n    text-transform: uppercase;\n    border-radius: 3px;\n    text-decoration: none;\n    position: relative;\n    display: block;\n}\n\nfooter ul li a:hover {\n    text-decoration: none;\n}\n\nfooter .copyright {\n    padding: 15px;\n    margin: 0;\n}\n\nfooter .copyright .material-icons {\n    font-size: 18px;\n    position: relative;\n    top: 3px;\n}\n\nfooter .btn {\n    margin-top: 0;\n    margin-bottom: 0;\n}\n\n.dropdown-menu {\n    border: 0;\n    box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);\n}\n\n.dropdown-menu .divider {\n    background-color: rgba(0, 0, 0, 0.12);\n}\n\n.dropdown-menu li>a {\n    font-size: 13px;\n    padding: 10px 20px;\n    margin: 0 5px;\n    border-radius: 2px;\n    -webkit-transition: all 150ms linear;\n    -moz-transition: all 150ms linear;\n    -o-transition: all 150ms linear;\n    -ms-transition: all 150ms linear;\n    transition: all 150ms linear;\n}\n\n.dropdown-menu li>a:hover,\n.dropdown-menu li>a:focus {\n    box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2);\n}\n\n.dropdown-menu.dropdown-with-icons li>a {\n    padding: 12px 20px 12px 12px;\n}\n\n.dropdown-menu.dropdown-with-icons li>a .material-icons {\n    vertical-align: middle;\n    font-size: 24px;\n    position: relative;\n    margin-top: -4px;\n    top: 1px;\n    margin-right: 12px;\n    opacity: .5;\n}\n\n.dropdown-menu li {\n    position: relative;\n}\n\n.dropdown-menu li a:hover,\n.dropdown-menu li a:focus,\n.dropdown-menu li a:active {\n    background-color: #9c27b0;\n    color: #FFFFFF;\n}\n\n.dropdown-menu .divider {\n    margin: 5px 0;\n}\n\n.navbar .dropdown-menu li a:hover,\n.navbar .dropdown-menu li a:focus,\n.navbar .dropdown-menu li a:active,\n.navbar.navbar-default .dropdown-menu li a:hover,\n.navbar.navbar-default .dropdown-menu li a:focus,\n.navbar.navbar-default .dropdown-menu li a:active,\n.bootstrap-table .dropdown-menu li a:hover,\n.bootstrap-table .dropdown-menu li a:focus,\n.bootstrap-table .dropdown-menu li a:active {\n    background-color: #9c27b0;\n    color: #FFFFFF;\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(156, 39, 176, 0.4);\n}\n\n.dropdown .dropdown-menu,\n.timeline .dropdown .dropdown-menu,\n.dropdown-menu.bootstrap-datetimepicker-widget,\n.bootstrap-table .dropdown-menu {\n    -webkit-transition: all 150ms linear;\n    -moz-transition: all 150ms linear;\n    -o-transition: all 150ms linear;\n    -ms-transition: all 150ms linear;\n    transition: all 150ms linear;\n    -webkit-transform: translate3d(0, -20px, 0);\n    -moz-transform: translate3d(0, -20px, 0);\n    -o-transform: translate3d(0, -20px, 0);\n    -ms-transform: translate3d(0, -20px, 0);\n    transform: translate3d(0, -20px, 0);\n    opacity: 0;\n    filter: alpha(opacity=0);\n    visibility: hidden;\n    display: block;\n}\n\n.dropdown.open .dropdown-menu,\n.dropdown-menu.bootstrap-datetimepicker-widget.open,\n.bootstrap-table .open .dropdown-menu,\n.timeline .dropdown.open .dropdown-menu {\n    opacity: 1;\n    filter: alpha(opacity=100);\n    visibility: visible;\n    -webkit-transform: translate3d(0, 1px, 0);\n    -moz-transform: translate3d(0, 1px, 0);\n    -o-transform: translate3d(0, 1px, 0);\n    -ms-transform: translate3d(0, 1px, 0);\n    transform: translate3d(0, 1px, 0);\n}\n\n.dropup .dropdown-menu {\n    -webkit-transition: all 150ms linear;\n    -moz-transition: all 150ms linear;\n    -o-transition: all 150ms linear;\n    -ms-transition: all 150ms linear;\n    transition: all 150ms linear;\n    -webkit-transform: translate3d(0, 20px, 0);\n    -moz-transform: translate3d(0, 20px, 0);\n    -o-transform: translate3d(0, 20px, 0);\n    -ms-transform: translate3d(0, 20px, 0);\n    transform: translate3d(0, 20px, 0);\n    visibility: hidden;\n    display: block;\n    opacity: 0;\n    filter: alpha(opacity=0);\n}\n\n.dropup.open .dropdown-menu {\n    -webkit-transform: translate3d(0, -2px, 0);\n    -moz-transform: translate3d(0, -2px, 0);\n    -o-transform: translate3d(0, -2px, 0);\n    -ms-transform: translate3d(0, -2px, 0);\n    transform: translate3d(0, -2px, 0);\n    visibility: visible;\n    opacity: 1;\n    filter: alpha(opacity=100);\n}\n\n.card {\n    display: inline-block;\n    position: relative;\n    width: 100%;\n    margin: 25px 0;\n    box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.14);\n    border-radius: 6px;\n    color: rgba(0, 0, 0, 0.87);\n    background: #fff;\n}\n\n.card .card-height-indicator {\n    margin-top: 100%;\n}\n\n.card.row-space .header {\n    padding: 15px 20px 0;\n}\n\n.card .map {\n    height: 280px;\n    border-radius: 6px;\n    margin-top: 15px;\n}\n\n.card .map.map-big {\n    height: 420px;\n}\n\n.card .card-title {\n    margin-top: 0;\n    margin-bottom: 3px;\n}\n\n.card .card-title:not(.card-calendar .card-title) {\n    margin-top: 0;\n    margin-bottom: 5px;\n}\n\n.card .card-image {\n    height: 60%;\n    position: relative;\n    overflow: hidden;\n    margin-left: 15px;\n    margin-right: 15px;\n    margin-top: -30px;\n    border-radius: 6px;\n    z-index: 3;\n    box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.42), 0 4px 25px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2);\n}\n\n.card .card-image img {\n    width: 100%;\n    height: 100%;\n    border-radius: 6px;\n    pointer-events: none;\n}\n\n.card .card-image .card-title {\n    position: absolute;\n    bottom: 15px;\n    left: 15px;\n    color: #fff;\n    font-size: 1.3em;\n    text-shadow: 0 2px 5px rgba(33, 33, 33, 0.5);\n}\n\n.card .category:not([class*=\"text-\"]) {\n    color: #999999;\n    font-size: 14px;\n}\n\n.card .category a .material-icons {\n    vertical-align: initial;\n}\n\n.card .card-content {\n    padding: 15px 20px;\n    position: relative;\n}\n\n.card .card-content .category {\n    margin-bottom: 0;\n}\n\n.card .card-actions {\n    position: absolute;\n    z-index: 1;\n    top: -50px;\n    width: calc(100% - 30px);\n    left: 17px;\n    right: 17px;\n    text-align: center;\n}\n\n.card .card-actions .btn {\n    padding-left: 12px;\n    padding-right: 12px;\n}\n\n.card .card-actions .fix-broken-card {\n    position: absolute;\n    top: -65px;\n}\n\n.card .card-header {\n    padding: 15px 20px 0;\n    z-index: 3;\n}\n\n.card .card-header .category {\n    margin-bottom: 0;\n}\n\n.card .card-header.card-header-text {\n    display: inline-block;\n}\n\n.card .card-header.card-header-text:after {\n    content: \"\";\n    display: table;\n}\n\n.card .card-header.card-header-icon {\n    float: left;\n}\n\n.card .card-header.card-header-icon i {\n    width: 33px;\n    height: 33px;\n    text-align: center;\n    line-height: 33px;\n}\n\n.card .card-header.card-header-tabs .nav-tabs {\n    background: transparent;\n    padding: 0;\n}\n\n.card .card-header.card-header-tabs .nav-tabs-title {\n    float: left;\n    padding: 10px 10px 10px 0;\n    line-height: 24px;\n}\n\n.card .card-header.card-header-icon+.card-content .card-title {\n    padding-bottom: 15px;\n}\n\n.card .social-line {\n    margin-top: 15px;\n    text-align: center;\n    padding: 0;\n}\n\n.card .social-line .btn {\n    color: #FFFFFF;\n    margin-left: 5px;\n    margin-right: 5px;\n}\n\n.card [data-background-color] {\n    box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.42), 0 4px 25px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2);\n    margin: -20px 15px 0;\n    border-radius: 3px;\n    padding: 15px;\n    background-color: #999999;\n    position: relative;\n}\n\n.card [data-background-color] .card-title {\n    color: #FFFFFF;\n}\n\n.card [data-background-color] .category {\n    margin-bottom: 0;\n    color: rgba(255, 255, 255, 0.62);\n}\n\n.card [data-background-color] .ct-label {\n    color: rgba(255, 255, 255, 0.7);\n}\n\n.card [data-background-color] .ct-grid {\n    stroke: rgba(255, 255, 255, 0.2);\n}\n\n.card [data-background-color] .ct-series-a .ct-point,\n.card [data-background-color] .ct-series-a .ct-line,\n.card [data-background-color] .ct-series-a .ct-bar,\n.card [data-background-color] .ct-series-a .ct-slice-donut {\n    stroke: rgba(255, 255, 255, 0.8);\n}\n\n.card [data-background-color] .ct-series-a .ct-slice-pie,\n.card [data-background-color] .ct-series-a .ct-area {\n    fill: rgba(255, 255, 255, 0.4);\n}\n\n.card .chart-title {\n    position: absolute;\n    top: 25px;\n    width: 100%;\n    text-align: center;\n}\n\n.card .chart-title h3 {\n    margin: 0;\n    color: #FFFFFF;\n}\n\n.card .chart-title h6 {\n    margin: 0;\n    color: rgba(255, 255, 255, 0.4);\n}\n\n.card .ct-chart~.card-footer i:nth-child(1n+2) {\n    width: 18px;\n    text-align: center;\n}\n\n.card .card-footer {\n    margin: 0 20px 10px;\n    padding-top: 10px;\n    border-top: 1px solid #eeeeee;\n}\n\n.card .card-footer .form-group {\n    margin: 5px 0 0;\n}\n\n.card .card-footer .content {\n    display: block;\n}\n\n.card .card-footer div {\n    display: inline-block;\n}\n\n.card .card-footer .author {\n    color: #999999;\n}\n\n.card .card-footer .stats {\n    line-height: 22px;\n    color: #999999;\n    font-size: 12px;\n}\n\n.card .card-footer .stats .material-icons {\n    position: relative;\n    top: 4px;\n    font-size: 16px;\n}\n\n.card .card-footer .stats .category {\n    padding-top: 7px;\n    padding-bottom: 7px;\n    margin-bottom: 0;\n}\n\n.card .card-footer h4 {\n    margin: 5px 0;\n}\n\n.card .card-footer .btn {\n    margin-top: 5px;\n    margin-bottom: 5px;\n}\n\n.card .card-footer h6 {\n    color: #999999;\n}\n\n.card form .card-footer {\n    border: none;\n}\n\n.card img {\n    width: 100%;\n    height: auto;\n}\n\n.card .category .material-icons {\n    position: relative;\n    top: 6px;\n    line-height: 0;\n}\n\n.card .category-social .fa {\n    font-size: 24px;\n    position: relative;\n    margin-top: -4px;\n    top: 2px;\n    margin-right: 5px;\n}\n\n.card .author .avatar {\n    width: 30px;\n    height: 30px;\n    overflow: hidden;\n    border-radius: 50%;\n    margin-right: 5px;\n}\n\n.card .author a {\n    color: #3C4858;\n    text-decoration: none;\n}\n\n.card .author a .ripple-container {\n    display: none;\n}\n\n.card .table {\n    margin-bottom: 0;\n}\n\n.card .table tr:first-child td {\n    border-top: none;\n}\n\n.card .nav-pills,\n.card .tab-content {\n    margin-top: 20px;\n}\n\n.card [data-background-color=\"purple\"] {\n    background: linear-gradient(60deg, #ab47bc, #8e24aa);\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(156, 39, 176, 0.4);\n}\n\n.card [data-icon-bg-color=\"purple\"] i {\n    color: #9c27b0;\n}\n\n.card [data-background-color=\"blue\"] {\n    background: linear-gradient(60deg, #26c6da, #00acc1);\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(0, 188, 212, 0.4);\n}\n\n.card [data-icon-bg-color=\"blue\"] i {\n    color: #00bcd4;\n}\n\n.card [data-background-color=\"green\"] {\n    background: linear-gradient(60deg, #66bb6a, #43a047);\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(76, 175, 80, 0.4);\n}\n\n.card [data-icon-bg-color=\"green\"] i {\n    color: #4caf50;\n}\n\n.card [data-background-color=\"orange\"] {\n    background: linear-gradient(60deg, #ffa726, #fb8c00);\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(255, 152, 0, 0.4);\n}\n\n.card [data-icon-bg-color=\"orange\"] i {\n    color: #ff9800;\n}\n\n.card [data-background-color=\"red\"] {\n    background: linear-gradient(60deg, #ef5350, #e53935);\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(244, 67, 54, 0.4);\n}\n\n.card [data-icon-bg-color=\"red\"] i {\n    color: #f44336;\n}\n\n.card [data-background-color=\"rose\"] {\n    background: linear-gradient(60deg, #ec407a, #d81b60);\n    box-shadow: 0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(233, 30, 99, 0.4);\n}\n\n.card [data-icon-bg-color=\"rose\"] i {\n    color: #e91e63;\n}\n\n.card [data-header-animation=\"true\"] {\n    -webkit-transform: translate3d(0, 0, 0);\n    -moz-transform: translate3d(0, 0, 0);\n    -o-transform: translate3d(0, 0, 0);\n    -ms-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    -webkit-transition: all 300ms cubic-bezier(0.34, 1.61, 0.7, 1);\n    -moz-transition: all 300ms cubic-bezier(0.34, 1.61, 0.7, 1);\n    -o-transition: all 300ms cubic-bezier(0.34, 1.61, 0.7, 1);\n    -ms-transition: all 300ms cubic-bezier(0.34, 1.61, 0.7, 1);\n    transition: all 300ms cubic-bezier(0.34, 1.61, 0.7, 1);\n}\n\n.card:hover [data-header-animation=\"true\"] {\n    -webkit-transform: translate3d(0, -50px, 0);\n    -moz-transform: translate3d(0, -50px, 0);\n    -o-transform: translate3d(0, -50px, 0);\n    -ms-transform: translate3d(0, -50px, 0);\n    transform: translate3d(0, -50px, 0);\n}\n\n.card [data-background-color] {\n    color: #FFFFFF;\n}\n\n.card [data-background-color] a {\n    color: #FFFFFF;\n}\n\n.card-chart .card-header {\n    padding: 0;\n    min-height: 160px;\n}\n\n.card-chart .card-header+.content h4 {\n    margin-top: 0;\n}\n\n.card-calendar .card-content {\n    padding: 0;\n}\n\n.card-stats .card-title {\n    margin: 0;\n}\n\n.card-stats .card-header {\n    float: left;\n    text-align: center;\n}\n\n.card-stats .card-header i {\n    font-size: 36px;\n    line-height: 56px;\n    width: 56px;\n    height: 56px;\n}\n\n.card-stats .card-content {\n    text-align: right;\n    padding-top: 10px;\n}\n\n.card-plain {\n    background: transparent;\n    box-shadow: none;\n}\n\n.card-plain .card-header {\n    margin-left: 0;\n    margin-right: 0;\n}\n\n.card-plain .card-header-icon {\n    margin-right: 15px;\n}\n\n.card-plain .content {\n    padding-left: 5px;\n    padding-right: 5px;\n}\n\n.card-plain .card-image {\n    margin: 0;\n    border-radius: 3px;\n}\n\n.card-plain .card-image img {\n    border-radius: 3px;\n}\n\n.card-raised {\n    box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.42), 0 4px 25px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2);\n}\n\n.iframe-container {\n    margin: 0 -20px 0;\n}\n\n.iframe-container iframe {\n    width: 100%;\n    height: 500px;\n    border: 0;\n    box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.42), 0 4px 25px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2);\n}\n\n.card-profile,\n.card-testimonial {\n    margin-top: 30px;\n    text-align: center;\n}\n\n.card-profile .btn-just-icon.btn-raised,\n.card-testimonial .btn-just-icon.btn-raised {\n    margin-left: 6px;\n    margin-right: 6px;\n}\n\n.card-profile .card-avatar,\n.card-testimonial .card-avatar {\n    max-width: 130px;\n    max-height: 130px;\n    margin: -50px auto 0;\n    border-radius: 50%;\n    overflow: hidden;\n    box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.42), 0 4px 25px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2);\n}\n\n.card-profile .card-avatar+.card-content,\n.card-testimonial .card-avatar+.card-content {\n    margin-top: 15px;\n}\n\n.card-profile.card-plain .card-avatar,\n.card-testimonial.card-plain .card-avatar {\n    margin-top: 0;\n}\n\n.card-testimonial {\n    margin-bottom: 65px;\n}\n\n.card-testimonial .card-avatar {\n    max-width: 100px;\n    max-height: 100px;\n}\n\n.card-testimonial .footer {\n    margin-top: 0;\n}\n\n.card-testimonial .footer .card-avatar {\n    margin-top: 10px;\n    margin-bottom: -50px;\n}\n\n.card-testimonial .card-description {\n    font-style: italic;\n}\n\n.card-testimonial .card-description+.card-title {\n    margin-top: 30px;\n}\n\n.card-testimonial .icon {\n    margin-top: 30px;\n}\n\n.card-testimonial .icon .material-icons {\n    font-size: 40px;\n}\n\n.card-pricing {\n    text-align: center;\n}\n\n.card-pricing .card-title {\n    margin-top: 30px;\n}\n\n.card-pricing .content {\n    padding: 15px !important;\n}\n\n.card-pricing .icon {\n    padding: 10px 0 0px;\n    color: #999999;\n}\n\n.card-pricing .icon i {\n    font-size: 55px;\n    border: 1px solid #E5E5E5;\n    border-radius: 50%;\n    width: 100px;\n    line-height: 100px;\n    height: 100px;\n}\n\n.card-pricing .icon.icon-primary {\n    color: #9c27b0;\n}\n\n.card-pricing .icon.icon-info {\n    color: #00bcd4;\n}\n\n.card-pricing .icon.icon-success {\n    color: #4caf50;\n}\n\n.card-pricing .icon.icon-warning {\n    color: #ff9800;\n}\n\n.card-pricing .icon.icon-danger {\n    color: #f44336;\n}\n\n.card-pricing .icon.icon-rose {\n    color: #e91e63;\n}\n\n.card-pricing h1 small {\n    font-size: 18px;\n}\n\n.card-pricing h1 small:first-child {\n    position: relative;\n    top: -17px;\n    font-size: 26px;\n}\n\n.card-pricing ul {\n    list-style: none;\n    padding: 0;\n    max-width: 240px;\n    margin: 10px auto;\n}\n\n.card-pricing ul li {\n    color: #999999;\n    text-align: center;\n    padding: 12px 0;\n    border-bottom: 1px solid rgba(153, 153, 153, 0.3);\n}\n\n.card-pricing ul li:last-child {\n    border: 0;\n}\n\n.card-pricing ul li b {\n    color: #3C4858;\n}\n\n.card-pricing ul li i {\n    top: 6px;\n    position: relative;\n}\n\n.card-pricing.card-background ul li,\n.card-pricing [class*=\"content-\"] ul li {\n    color: #FFFFFF;\n    border-color: rgba(255, 255, 255, 0.3);\n}\n\n.card-pricing.card-background ul li b,\n.card-pricing [class*=\"content-\"] ul li b {\n    color: #FFFFFF;\n}\n\n.card-pricing.card-background [class*=\"text-\"],\n.card-pricing [class*=\"content-\"] [class*=\"text-\"] {\n    color: #FFFFFF;\n}\n\n.card-pricing.card-background:after {\n    background-color: rgba(0, 0, 0, 0.7);\n}\n\n.card-background {\n    background-position: center center;\n    background-size: cover;\n    text-align: center;\n}\n\n.card-background .content {\n    position: relative;\n    z-index: 2;\n    min-height: 280px;\n    padding-top: 40px;\n    padding-bottom: 40px;\n    max-width: 440px;\n    margin: 0 auto;\n}\n\n.card-background .category,\n.card-background .card-description,\n.card-background small {\n    color: rgba(255, 255, 255, 0.7);\n}\n\n.card-background .card-title {\n    color: #FFFFFF;\n    margin-top: 10px;\n}\n\n.card-background:not(.card-pricing) .btn {\n    margin-bottom: 0;\n}\n\n.card-background:after {\n    position: absolute;\n    z-index: 1;\n    width: 100%;\n    height: 100%;\n    display: block;\n    left: 0;\n    top: 0;\n    content: \"\";\n    background-color: rgba(0, 0, 0, 0.56);\n    border-radius: 6px;\n}\n\n.card-product {\n    margin-top: 30px;\n}\n\n.card-product .btn-simple.btn-just-icon {\n    padding: 0;\n}\n\n.card-product .footer {\n    margin-top: 5px;\n}\n\n.card-product .footer .stats .material-icons {\n    margin-top: 4px;\n    top: 0;\n}\n\n.card-product .footer .price h4 {\n    margin-bottom: 0;\n}\n\n.card-product .card-title,\n.card-product .category,\n.card-product .card-description {\n    text-align: center;\n}\n\n.card-login .card-title {\n    margin-top: 10px;\n    margin-bottom: 10px;\n    font-weight: 700;\n}\n\n.card-login i {\n    max-width: 24px;\n    overflow: hidden;\n    display: block;\n}\n\n.card-login .text-divider {\n    margin-top: 30px;\n    margin-bottom: 0px;\n    text-align: center;\n}\n\n.card-login .card-content {\n    padding: 0px 30px 0px 10px;\n}\n\n.card-login .checkbox {\n    margin-top: 20px;\n}\n\n.card-login .checkbox label {\n    margin-left: 17px;\n}\n\n.card-login .checkbox .checkbox-material {\n    padding-right: 12px;\n}\n\n.card-login .social-line {\n    margin-top: 15px;\n    text-align: center;\n    padding: 0;\n}\n\n.card-login .social-line .btn {\n    color: #FFFFFF;\n    margin-left: 5px;\n    margin-right: 5px;\n}\n\n.nav-tabs {\n    background: #9c27b0;\n    border: 0;\n    border-radius: 3px;\n    padding: 0 15px;\n}\n\n.nav-tabs>li>a {\n    color: #FFFFFF;\n    border: 0;\n    margin: 0;\n    border-radius: 3px;\n    line-height: 24px;\n    text-transform: uppercase;\n    font-size: 12px;\n}\n\n.nav-tabs>li>a:hover {\n    background-color: transparent;\n    border: 0;\n}\n\n.nav-tabs>li>a,\n.nav-tabs>li>a:hover,\n.nav-tabs>li>a:focus {\n    background-color: transparent;\n    border: 0 !important;\n    color: #FFFFFF !important;\n    font-weight: 500;\n}\n\n.nav-tabs>li.disabled>a,\n.nav-tabs>li.disabled>a:hover {\n    color: rgba(255, 255, 255, 0.5);\n}\n\n.nav-tabs>li .material-icons {\n    margin: -1px 5px 0 0;\n}\n\n.nav-tabs>li.active>a,\n.nav-tabs>li.active>a:hover,\n.nav-tabs>li.active>a:focus {\n    background-color: rgba(255, 255, 255, 0.2);\n    transition: background-color .1s .2s;\n}\n\n@media (min-width: 992px) {\n    .navbar-form {\n        margin-top: 21px;\n        margin-bottom: 21px;\n        padding-left: 5px;\n        padding-right: 5px;\n    }\n    .navbar-nav.navbar-right>li>.dropdown-menu:before {\n        left: auto;\n        right: 12px;\n    }\n    .navbar-nav.navbar-right>li>.dropdown-menu:after {\n        left: auto;\n        right: 12px;\n    }\n    .footer:not(.footer-big) nav>ul li:first-child {\n        margin-left: 0;\n    }\n    .card form [class*=\"col-\"]:first-child {\n        padding-left: 15px;\n    }\n    .card form [class*=\"col-\"]:last-child {\n        padding-right: 15px;\n    }\n    body>.navbar-collapse.collapse {\n        display: none !important;\n    }\n    .sidebar .navbar-form {\n        display: none !important;\n    }\n    .sidebar .nav-mobile-menu {\n        display: none;\n    }\n    .close-layer {\n        display: none;\n    }\n}\n\n\n/*          Changes for small display      */\n\n@media (max-width: 991px) {\n    .form-group textarea {\n        padding-top: 15px;\n    }\n    .nav-open .menu-on-left .main-panel {\n        position: initial;\n    }\n    html,\n    body {\n      {*  overflow-x: hidden; *}\n    }\n    .nav-open .menu-on-left .main-panel,\n    .nav-open .menu-on-left .wrapper-full-page,\n    .nav-open .menu-on-left .navbar-fixed>div {\n        -webkit-transform: translate3d(260px, 0, 0);\n        -moz-transform: translate3d(260px, 0, 0);\n        -o-transform: translate3d(260px, 0, 0);\n        -ms-transform: translate3d(260px, 0, 0);\n        transform: translate3d(260px, 0, 0);\n    }\n    .menu-on-left .sidebar,\n    .menu-on-left .off-canvas-sidebar {\n        left: 0;\n        right: auto;\n        -webkit-transform: translate3d(-260px, 0, 0);\n        -moz-transform: translate3d(-260px, 0, 0);\n        -o-transform: translate3d(-260px, 0, 0);\n        -ms-transform: translate3d(-260px, 0, 0);\n        transform: translate3d(-260px, 0, 0);\n    }\n    .menu-on-left .close-layer {\n        left: auto;\n        right: 0;\n    }\n    .timeline:before {\n        left: 5%;\n    }\n    .timeline>li>.timeline-badge {\n        left: 5%;\n    }\n    .timeline>li>.timeline-panel {\n        float: right;\n        width: 86%;\n    }\n    .timeline>li>.timeline-panel:before {\n        border-left-width: 0;\n        border-right-width: 15px;\n        left: -15px;\n        right: auto;\n    }\n    .timeline>li>.timeline-panel:after {\n        border-left-width: 0;\n        border-right-width: 14px;\n        left: -14px;\n        right: auto;\n    }\n    .nav-mobile-menu .dropdown .dropdown-menu {\n        display: none;\n    }\n    .nav-mobile-menu .dropdown.open .dropdown-menu {\n        display: block;\n    }\n    .nav-mobile-menu li.active>a {\n        background-color: rgba(255, 255, 255, 0.1);\n    }\n    .navbar-minimize {\n        display: none;\n    }\n    .card .form-horizontal .label-on-left,\n    .card .form-horizontal .label-on-right {\n        padding-left: 15px;\n        padding-top: 8px;\n    }\n    .card .form-horizontal .form-group {\n        margin-top: 0px;\n    }\n    .card .form-horizontal .checkbox-radios {\n        padding-bottom: 15px;\n    }\n    .card .form-horizontal .checkbox-radios .checkbox:first-child,\n    .card .form-horizontal .checkbox-radios .radio:first-child {\n        margin-top: 0;\n    }\n    .card .form-horizontal .checkbox-inline {\n        margin-top: 0;\n    }\n    .sidebar {\n        display: none;\n        box-shadow: none;\n    }\n    .sidebar .sidebar-wrapper {\n        padding-bottom: 60px;\n    }\n    .sidebar .nav-mobile-menu {\n        margin-top: 0;\n    }\n    .sidebar .nav-mobile-menu .notification {\n        float: left;\n        line-height: 30px;\n        margin-right: 8px;\n    }\n    .sidebar .nav-mobile-menu .open .dropdown-menu {\n        position: static;\n        float: none;\n        width: auto;\n        margin-top: 0;\n        background-color: transparent;\n        border: 0;\n        -webkit-box-shadow: none;\n        box-shadow: none;\n    }\n    .main-panel {\n        width: 100%;\n    }\n    .navbar-transparent {\n        padding-top: 15px;\n        background-color: rgba(0, 0, 0, 0.45);\n    }\n    body {\n        position: relative;\n    }\n    .nav-open .main-panel,\n    .nav-open .wrapper-full-page,\n    .nav-open .navbar .container .navbar-header,\n    .nav-open .navbar .container {\n        left: 0;\n        -webkit-transform: translate3d(-260px, 0, 0);\n        -moz-transform: translate3d(-260px, 0, 0);\n        -o-transform: translate3d(-260px, 0, 0);\n        -ms-transform: translate3d(-260px, 0, 0);\n        transform: translate3d(-260px, 0, 0);\n    }\n    .nav-open .sidebar {\n        box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.42), 0 4px 25px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2);\n    }\n    .nav-open .off-canvas-sidebar .navbar-collapse,\n    .nav-open .sidebar {\n        -webkit-transform: translate3d(0, 0, 0);\n        -moz-transform: translate3d(0, 0, 0);\n        -o-transform: translate3d(0, 0, 0);\n        -ms-transform: translate3d(0, 0, 0);\n        transform: translate3d(0, 0, 0);\n    }\n    .wrapper-full-page,\n    .navbar .container .navbar-header,\n    .navbar .container {\n        -webkit-transform: translate3d(0px, 0, 0);\n        -moz-transform: translate3d(0px, 0, 0);\n        -o-transform: translate3d(0px, 0, 0);\n        -ms-transform: translate3d(0px, 0, 0);\n        transform: translate3d(0px, 0, 0);\n        -webkit-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n        -moz-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n        -o-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n        -ms-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n        transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n        left: 0;\n    }\n    .off-canvas-sidebar .navbar .container {\n        transform: none;\n    }\n    .main-panel {\n        -webkit-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n        -moz-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n        -o-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n        -ms-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n        transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n    }\n    .navbar .navbar-collapse.collapse,\n    .navbar .navbar-collapse.collapse.in,\n    .navbar .navbar-collapse.collapsing {\n        display: none !important;\n    }\n    .off-canvas-sidebar .navbar .navbar-collapse.collapse,\n    .off-canvas-sidebar .navbar .navbar-collapse.collapse.in,\n    .off-canvas-sidebar .navbar .navbar-collapse.collapsing {\n        display: block !important;\n    }\n    .navbar-nav>li {\n        float: none;\n        position: relative;\n        display: block;\n    }\n    .off-canvas-sidebar nav .navbar-collapse {\n        margin: 0;\n    }\n    .off-canvas-sidebar nav .navbar-collapse>ul {\n        margin-top: 19px;\n    }\n    .sidebar,\n    .off-canvas-sidebar nav .navbar-collapse {\n        position: fixed;\n        display: block;\n        top: 0;\n        height: 100vh;\n        width: 260px;\n        right: 0;\n        left: auto;\n        z-index: 1032;\n        visibility: visible;\n        background-color: #9A9A9A;\n        overflow-y: visible;\n        border-top: none;\n        text-align: left;\n        padding-right: 0px;\n        padding-left: 0;\n        -webkit-transform: translate3d(260px, 0, 0);\n        -moz-transform: translate3d(260px, 0, 0);\n        -o-transform: translate3d(260px, 0, 0);\n        -ms-transform: translate3d(260px, 0, 0);\n        transform: translate3d(260px, 0, 0);\n        -webkit-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n        -moz-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n        -o-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n        -ms-transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n        transition: all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1);\n    }\n    .sidebar>ul,\n    .off-canvas-sidebar nav .navbar-collapse>ul {\n        position: relative;\n        z-index: 4;\n        width: 100%;\n    }\n    .sidebar::before,\n    .off-canvas-sidebar nav .navbar-collapse::before {\n        top: 0;\n        left: 0;\n        height: 100%;\n        width: 100%;\n        position: absolute;\n        background-color: #282828;\n        display: block;\n        content: \"\";\n        z-index: 1;\n    }\n    .sidebar .logo,\n    .off-canvas-sidebar nav .navbar-collapse .logo {\n        position: relative;\n        z-index: 4;\n    }\n    .sidebar .navbar-form,\n    .off-canvas-sidebar nav .navbar-collapse .navbar-form {\n        margin: 10px 0px;\n        float: none !important;\n        padding-top: 1px;\n        padding-bottom: 1px;\n        position: relative;\n    }\n    .sidebar .table-responsive,\n    .off-canvas-sidebar nav .navbar-collapse .table-responsive {\n        width: 100%;\n        margin-bottom: 15px;\n        overflow-x: scroll;\n        overflow-y: hidden;\n        -ms-overflow-style: -ms-autohiding-scrollbar;\n        -webkit-overflow-scrolling: touch;\n    }\n    .form-group.form-search .form-control {\n        font-size: 1.7em;\n        height: 37px;\n        width: 78%;\n    }\n    .navbar-form .btn {\n        position: absolute;\n        top: 12px;\n        right: 15px;\n    }\n    .close-layer {\n        height: 100%;\n        width: 100%;\n        position: absolute;\n        opacity: 0;\n        top: 0;\n        left: auto;\n        background: rgba(0, 0, 0, 0.35);\n        content: \"\";\n        z-index: 9999;\n        overflow-x: hidden;\n        -webkit-transition: all 370ms ease-in;\n        -moz-transition: all 370ms ease-in;\n        -o-transition: all 370ms ease-in;\n        -ms-transition: all 370ms ease-in;\n        transition: all 370ms ease-in;\n    }\n    .close-layer.visible {\n        opacity: 1;\n    }\n    .navbar-toggle .icon-bar {\n        display: block;\n        position: relative;\n        background: #fff;\n        width: 24px;\n        height: 2px;\n        border-radius: 1px;\n        margin: 0 auto;\n    }\n    .navbar-header .navbar-toggle {\n        padding: 15px;\n        margin-top: 4px;\n        width: 40px;\n        height: 40px;\n    }\n    .bar1,\n    .bar2,\n    .bar3 {\n        outline: 1px solid transparent;\n    }\n    @keyframes topbar-x {\n        0% {\n            top: 0px;\n            transform: rotate(0deg);\n        }\n        45% {\n            top: 6px;\n            transform: rotate(145deg);\n        }\n        75% {\n            transform: rotate(130deg);\n        }\n        100% {\n            transform: rotate(135deg);\n        }\n    }\n    @-webkit-keyframes topbar-x {\n        0% {\n            top: 0px;\n            -webkit-transform: rotate(0deg);\n        }\n        45% {\n            top: 6px;\n            -webkit-transform: rotate(145deg);\n        }\n        75% {\n            -webkit-transform: rotate(130deg);\n        }\n        100% {\n            -webkit-transform: rotate(135deg);\n        }\n    }\n    @-moz-keyframes topbar-x {\n        0% {\n            top: 0px;\n            -moz-transform: rotate(0deg);\n        }\n        45% {\n            top: 6px;\n            -moz-transform: rotate(145deg);\n        }\n        75% {\n            -moz-transform: rotate(130deg);\n        }\n        100% {\n            -moz-transform: rotate(135deg);\n        }\n    }\n    @keyframes topbar-back {\n        0% {\n            top: 6px;\n            transform: rotate(135deg);\n        }\n        45% {\n            transform: rotate(-10deg);\n        }\n        75% {\n            transform: rotate(5deg);\n        }\n        100% {\n            top: 0px;\n            transform: rotate(0);\n        }\n    }\n    @-webkit-keyframes topbar-back {\n        0% {\n            top: 6px;\n            -webkit-transform: rotate(135deg);\n        }\n        45% {\n            -webkit-transform: rotate(-10deg);\n        }\n        75% {\n            -webkit-transform: rotate(5deg);\n        }\n        100% {\n            top: 0px;\n            -webkit-transform: rotate(0);\n        }\n    }\n    @-moz-keyframes topbar-back {\n        0% {\n            top: 6px;\n            -moz-transform: rotate(135deg);\n        }\n        45% {\n            -moz-transform: rotate(-10deg);\n        }\n        75% {\n            -moz-transform: rotate(5deg);\n        }\n        100% {\n            top: 0px;\n            -moz-transform: rotate(0);\n        }\n    }\n    @keyframes bottombar-x {\n        0% {\n            bottom: 0px;\n            transform: rotate(0deg);\n        }\n        45% {\n            bottom: 6px;\n            transform: rotate(-145deg);\n        }\n        75% {\n            transform: rotate(-130deg);\n        }\n        100% {\n            transform: rotate(-135deg);\n        }\n    }\n    @-webkit-keyframes bottombar-x {\n        0% {\n            bottom: 0px;\n            -webkit-transform: rotate(0deg);\n        }\n        45% {\n            bottom: 6px;\n            -webkit-transform: rotate(-145deg);\n        }\n        75% {\n            -webkit-transform: rotate(-130deg);\n        }\n        100% {\n            -webkit-transform: rotate(-135deg);\n        }\n    }\n    @-moz-keyframes bottombar-x {\n        0% {\n            bottom: 0px;\n            -moz-transform: rotate(0deg);\n        }\n        45% {\n            bottom: 6px;\n            -moz-transform: rotate(-145deg);\n        }\n        75% {\n            -moz-transform: rotate(-130deg);\n        }\n        100% {\n            -moz-transform: rotate(-135deg);\n        }\n    }\n    @keyframes bottombar-back {\n        0% {\n            bottom: 6px;\n            transform: rotate(-135deg);\n        }\n        45% {\n            transform: rotate(10deg);\n        }\n        75% {\n            transform: rotate(-5deg);\n        }\n        100% {\n            bottom: 0px;\n            transform: rotate(0);\n        }\n    }\n    @-webkit-keyframes bottombar-back {\n        0% {\n            bottom: 6px;\n            -webkit-transform: rotate(-135deg);\n        }\n        45% {\n            -webkit-transform: rotate(10deg);\n        }\n        75% {\n            -webkit-transform: rotate(-5deg);\n        }\n        100% {\n            bottom: 0px;\n            -webkit-transform: rotate(0);\n        }\n    }\n    @-moz-keyframes bottombar-back {\n        0% {\n            bottom: 6px;\n            -moz-transform: rotate(-135deg);\n        }\n        45% {\n            -moz-transform: rotate(10deg);\n        }\n        75% {\n            -moz-transform: rotate(-5deg);\n        }\n        100% {\n            bottom: 0px;\n            -moz-transform: rotate(0);\n        }\n    }\n    .navbar-toggle .icon-bar:nth-child(2) {\n        top: 0px;\n        -webkit-animation: topbar-back 500ms linear 0s;\n        -moz-animation: topbar-back 500ms linear 0s;\n        animation: topbar-back 500ms 0s;\n        -webkit-animation-fill-mode: forwards;\n        -moz-animation-fill-mode: forwards;\n        animation-fill-mode: forwards;\n    }\n    .navbar-toggle .icon-bar:nth-child(3) {\n        opacity: 1;\n    }\n    .navbar-toggle .icon-bar:nth-child(4) {\n        bottom: 0px;\n        -webkit-animation: bottombar-back 500ms linear 0s;\n        -moz-animation: bottombar-back 500ms linear 0s;\n        animation: bottombar-back 500ms 0s;\n        -webkit-animation-fill-mode: forwards;\n        -moz-animation-fill-mode: forwards;\n        animation-fill-mode: forwards;\n    }\n    .navbar-toggle.toggled .icon-bar:nth-child(2) {\n        top: 6px;\n        -webkit-animation: topbar-x 500ms linear 0s;\n        -moz-animation: topbar-x 500ms linear 0s;\n        animation: topbar-x 500ms 0s;\n        -webkit-animation-fill-mode: forwards;\n        -moz-animation-fill-mode: forwards;\n        animation-fill-mode: forwards;\n    }\n    .navbar-toggle.toggled .icon-bar:nth-child(3) {\n        opacity: 0;\n    }\n    .navbar-toggle.toggled .icon-bar:nth-child(4) {\n        bottom: 6px;\n        -webkit-animation: bottombar-x 500ms linear 0s;\n        -moz-animation: bottombar-x 500ms linear 0s;\n        animation: bottombar-x 500ms 0s;\n        -webkit-animation-fill-mode: forwards;\n        -moz-animation-fill-mode: forwards;\n        animation-fill-mode: forwards;\n    }\n    @-webkit-keyframes fadeIn {\n        0% {\n            opacity: 0;\n        }\n        100% {\n            opacity: 1;\n        }\n    }\n    @-moz-keyframes fadeIn {\n        0% {\n            opacity: 0;\n        }\n        100% {\n            opacity: 1;\n        }\n    }\n    @keyframes fadeIn {\n        0% {\n            opacity: 0;\n        }\n        100% {\n            opacity: 1;\n        }\n    }\n    .dropdown-menu .divider {\n        background-color: rgba(229, 229, 229, 0.15);\n    }\n    .navbar-nav {\n        margin: 1px 0;\n    }\n    .navbar-nav .open .dropdown-menu>li>a {\n        padding: 15px 15px 5px 50px;\n    }\n    .navbar-nav .open .dropdown-menu>li:first-child>a {\n        padding: 5px 15px 5px 50px;\n    }\n    .navbar-nav .open .dropdown-menu>li:last-child>a {\n        padding: 15px 15px 25px 50px;\n    }\n    [class*=\"navbar-\"] .navbar-nav>li>a,\n    [class*=\"navbar-\"] .navbar-nav>li>a:hover,\n    [class*=\"navbar-\"] .navbar-nav>li>a:focus,\n    [class*=\"navbar-\"] .navbar-nav .active>a,\n    [class*=\"navbar-\"] .navbar-nav .active>a:hover,\n    [class*=\"navbar-\"] .navbar-nav .active>a:focus,\n    [class*=\"navbar-\"] .navbar-nav .open .dropdown-menu>li>a,\n    [class*=\"navbar-\"] .navbar-nav .open .dropdown-menu>li>a:hover,\n    [class*=\"navbar-\"] .navbar-nav .open .dropdown-menu>li>a:focus,\n    [class*=\"navbar-\"] .navbar-nav .navbar-nav .open .dropdown-menu>li>a:active {\n        color: white;\n    }\n    [class*=\"navbar-\"] .navbar-nav>li>a,\n    [class*=\"navbar-\"] .navbar-nav>li>a:hover,\n    [class*=\"navbar-\"] .navbar-nav>li>a:focus,\n    [class*=\"navbar-\"] .navbar-nav .open .dropdown-menu>li>a,\n    [class*=\"navbar-\"] .navbar-nav .open .dropdown-menu>li>a:hover,\n    [class*=\"navbar-\"] .navbar-nav .open .dropdown-menu>li>a:focus {\n        opacity: .7;\n        background: transparent;\n    }\n    [class*=\"navbar-\"] .navbar-nav.navbar-nav .open .dropdown-menu>li>a:active {\n        opacity: 1;\n    }\n    [class*=\"navbar-\"] .navbar-nav .dropdown>a:hover .caret {\n        border-bottom-color: #777;\n        border-top-color: #777;\n    }\n    [class*=\"navbar-\"] .navbar-nav .dropdown>a:active .caret {\n        border-bottom-color: white;\n        border-top-color: white;\n    }\n    .dropdown-menu {\n        display: none;\n    }\n    .navbar-fixed-top {\n        -webkit-backface-visibility: hidden;\n    }\n    #bodyClick {\n        height: 100%;\n        width: 100%;\n        position: fixed;\n        opacity: 0;\n        top: 0;\n        left: auto;\n        right: 260px;\n        content: \"\";\n        z-index: 9999;\n        overflow-x: hidden;\n    }\n    .social-line .btn {\n        margin: 0 0 10px 0;\n    }\n    .subscribe-line .form-control {\n        margin: 0 0 10px 0;\n    }\n    .social-line.pull-right {\n        float: none;\n    }\n    .footer:not(.footer-big) nav>ul li {\n        float: none;\n    }\n    .social-area.pull-right {\n        float: none !important;\n    }\n    .form-control+.form-control-feedback {\n        margin-top: -8px;\n    }\n    .navbar-toggle:hover,\n    .navbar-toggle:focus {\n        background-color: transparent !important;\n    }\n    .media-post .author {\n        width: 20%;\n        float: none !important;\n        display: block;\n        margin: 0 auto 10px;\n    }\n    .media-post .media-body {\n        width: 100%;\n    }\n    .navbar-collapse.collapse {\n        height: 100% !important;\n    }\n    .navbar-collapse.collapse.in {\n        display: block;\n    }\n    .navbar-header .collapse,\n    .navbar-toggle {\n        display: block !important;\n    }\n    .navbar-header {\n        float: none;\n    }\n    .navbar-collapse .nav p {\n        font-size: 14px;\n        margin: 0;\n    }\n}\n\n@media (min-width: 768px) {\n    .navbar>.container-fluid .navbar-brand {\n        margin-left: 0;\n    }\n}\n\n.main-panel .content {\n    padding-right: 25px;\n    padding-left: 25px;\n    margin-right: auto;\n    margin-left: auto;\n}\n\n\n@media (max-width: 767px) {\n    .fileinput {\n        display: block;\n    }\n    .card .card-header.card-header-text {\n        display: block;\n    }\n    .navbar-form .form-group {\n        margin-bottom: 0;\n    }\n    .table-responsive {\n        border: none;\n    }\n    .modal-small {\n        width: auto;\n        margin-left: 15px;\n        margin-right: 15px;\n    }\n}\n\n@media (min-width: 992px) {\n    .table-full-width {\n        margin-left: -20px;\n        margin-right: -20px;\n    }\n    .table-responsive {\n        overflow: auto;\n    }\n}\n\n@media all and (max-width: 490px) {\n    .nav-center .nav-pills-icons {\n        max-width: 211px;\n    }\n}\n\n@media screen and (max-width: 470px) {\n    .fc-toolbar .fc-left {\n        margin-bottom: 15px;\n    }\n}\n\n.rtl-active .sidebar,\n.rtl-active .bootstrap-navbar {\n    right: 0;\n    left: auto;\n}\n\n.rtl-active .sidebar .nav-mobile-menu .notification,\n.rtl-active .bootstrap-navbar .nav-mobile-menu .notification {\n    float: right;\n    margin-right: 0;\n    margin-left: 8px;\n}\n\n.rtl-active .sidebar .nav i,\n.rtl-active .bootstrap-navbar .nav i {\n    float: right;\n    margin-left: 15px;\n    margin-right: 0;\n}\n\n.rtl-active .sidebar .nav p,\n.rtl-active .bootstrap-navbar .nav p {\n    margin-right: 45px;\n    text-align: right;\n}\n\n.rtl-active .sidebar .nav .caret,\n.rtl-active .bootstrap-navbar .nav .caret {\n    left: 11px;\n    right: auto;\n}\n\n.rtl-active .sidebar .logo a.logo-mini,\n.rtl-active .bootstrap-navbar .logo a.logo-mini {\n    float: right;\n    margin-right: 30px;\n    margin-left: 10px;\n}\n\n.rtl-active .sidebar .logo .simple-text,\n.rtl-active .bootstrap-navbar .logo .simple-text {\n    text-align: right;\n}\n\n.rtl-active .sidebar .user .info>a>span,\n.rtl-active .bootstrap-navbar .user .info>a>span {\n    text-align: right;\n}\n\n.rtl-active .sidebar .user .photo,\n.rtl-active .bootstrap-navbar .user .photo {\n    float: right;\n    margin-left: 12px;\n    margin-right: 23px;\n}\n\n.rtl-active .sidebar .user .info .caret,\n.rtl-active .bootstrap-navbar .user .info .caret {\n    left: 22px;\n    right: auto;\n}\n\n.rtl-active .sidebar .sidebar-wrapper .nav [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-mini,\n.rtl-active .sidebar .sidebar-wrapper .user .info [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-mini,\n.rtl-active .bootstrap-navbar .sidebar-wrapper .nav [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-mini,\n.rtl-active .bootstrap-navbar .sidebar-wrapper .user .info [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-mini {\n    float: right;\n    margin-left: 15px;\n    margin-right: 0;\n}\n\n.rtl-active .navbar-header .navbar-toggle {\n    margin: 10px 0 10px 15px;\n}\n\n.rtl-active .btn:not(.btn-just-icon):not(.btn-fab) .fa,\n.rtl-active .navbar .navbar-nav>li>a.btn:not(.btn-just-icon):not(.btn-fab) .fa {\n    left: 5px;\n}\n\n.rtl-active .card .card-header.card-header-icon {\n    float: right;\n}\n\n.rtl-active .main-panel {\n    float: left;\n}\n\n.rtl-active .navbar>.container-fluid .navbar-brand {\n    margin-right: 0;\n}\n\n.rtl-active .dropdown-menu {\n    right: 0;\n    left: auto;\n}\n\n.rtl-active .card .card-header.card-header-tabs .nav-tabs-title {\n    float: right;\n    padding: 10px 0 10px 10px;\n}\n\n.rtl-active .card.card-product .card-footer {\n    display: flex;\n    align-items: center;\n    flex-direction: row-reverse;\n    justify-content: space-between;\n}\n\n.rtl-active .navbar-nav.navbar-right>li>.dropdown-menu:before,\n.rtl-active .navbar-nav.navbar-right>li>.dropdown-menu:after {\n    right: auto;\n    left: 12px;\n}\n\n.rtl-active .card .form-horizontal .label-on-left {\n    padding-top: 16px;\n    text-align: left;\n}\n\n.rtl-active .checkbox .checkbox-material .check:before {\n    left: 0;\n}\n\n.rtl-active .form-horizontal .radio label span {\n    right: 2px;\n}\n\n.rtl-active .checkbox .checkbox-material {\n    padding-left: 5px;\n    padding-right: 0;\n}\n\n.rtl-active .checkbox .checkbox-material:before {\n    left: 5px;\n}\n\n.rtl-active .card .checkbox .checkbox-material:before {\n    left: 0;\n}\n\n.rtl-active .nav-pills>li+li {\n    margin-right: 0;\n}\n\n.rtl-active .radio-inline,\n.rtl-active .checkbox-inline {\n    padding-right: 0;\n    margin-top: 5px;\n}\n\n.rtl-active .form-horizontal .checkbox-radios .checkbox:first-child,\n.rtl-active .form-horizontal .checkbox-radios .radio:first-child {\n    margin-top: 5px;\n}\n\n.rtl-active .checkbox label,\n.rtl-active .radio label {\n    padding: 0;\n}\n\n.rtl-active .radio label {\n    padding-right: 28px;\n}\n\n.rtl-active .card .form-horizontal .label-on-right {\n    text-align: right;\n    padding-top: 17px;\n}\n\n.rtl-active .alert button.close {\n    left: 10px !important;\n    right: auto !important;\n}\n\n.rtl-active .alert span[data-notify=\"icon\"] {\n    right: 15px;\n    left: auto;\n}\n\n.rtl-active .alert.alert-with-icon {\n    padding-right: 65px;\n    padding-left: 15px;\n}\n\n.rtl-active .alert.alert-with-icon i[data-notify=\"icon\"] {\n    right: 15px;\n    left: auto;\n}\n\n@media (max-width: 991px) {\n    .rtl-active .sidebar .sidebar-wrapper>.nav [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal,\n    .rtl-active .sidebar .sidebar-wrapper .user .info [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal {\n        text-align: right;\n    }\n}\n\n@media (max-width: 768px) {\n    .rtl-active .navbar>.container-fluid .navbar-brand {\n        margin-right: 15px;\n    }\n    .rtl-active .navbar-header .navbar-toggle {\n        margin-left: 30px;\n    }\n}\n\n@media (min-width: 991px) {\n    .rtl-active.sidebar-mini .sidebar .nav i,\n    .rtl-active.sidebar-mini .bootstrap-navbar .nav i {\n        margin: 0;\n    }\n    .rtl-active.sidebar-mini .sidebar .sidebar-wrapper>.nav [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal,\n    .rtl-active.sidebar-mini .sidebar .sidebar-wrapper .user .info [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal,\n    .rtl-active.sidebar-mini .sidebar .sidebar-wrapper .user .info>a>span,\n    .rtl-active.sidebar-mini .sidebar .sidebar-wrapper>.nav li>a p {\n        position: relative;\n    }\n    .rtl-active.sidebar-mini .sidebar:hover .sidebar-wrapper>.nav li>a p,\n    .rtl-active.sidebar-mini .sidebar:hover .sidebar-wrapper>.nav [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal,\n    .rtl-active.sidebar-mini .sidebar:hover .sidebar-wrapper .user .info [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal,\n    .rtl-active.sidebar-mini .sidebar:hover .sidebar-wrapper .user .info>a>span,\n    .rtl-active.sidebar-mini .sidebar .sidebar-wrapper>.nav [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal,\n    .rtl-active.sidebar-mini .sidebar .sidebar-wrapper .user .info [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal,\n    .rtl-active.sidebar-mini .sidebar .sidebar-wrapper .user .info>a>span,\n    .rtl-active.sidebar-mini .sidebar .sidebar-wrapper>.nav li>a p,\n    .rtl-active.sidebar-mini .sidebar .logo a.logo-normal {\n        -webkit-transform: translatX(25px);\n        -moz-transform: translateX(25px);\n        -o-transform: translateX(25px);\n        -ms-transform: translateX(25px);\n        transform: translateX(25px);\n    }\n    .rtl-active.sidebar-mini .sidebar:hover .sidebar-wrapper>.nav li>a p,\n    .rtl-active.sidebar-mini .sidebar:hover .sidebar-wrapper>.nav [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal,\n    .rtl-active.sidebar-mini .sidebar:hover .sidebar-wrapper .user .info [data-toggle=\"collapse\"]~div>ul>li>a .sidebar-normal,\n    .rtl-active.sidebar-mini .sidebar:hover .sidebar-wrapper .user .info>a>span,\n    .rtl-active.sidebar-mini .sidebar:hover .logo a.logo-normal {\n        -webkit-transform: translat3d(0, 0, 0);\n        -moz-transform: translate3d(0, 0, 0);\n        -o-transform: translate3d(0, 0, 0);\n        -ms-transform: translate3d(0, 0, 0);\n        transform: translate3d(0, 0, 0);\n    }\n}"
  },
  {
    "path": "static/css/rule_list.css",
    "content": "table {\n    font-size: 13px;\n}\n\n/* 表格紧凑 */\n.table > tbody > tr > td, .table > tbody > tr > th, .table > tfoot > tr > td, .table > tfoot > tr > th, .table > thead > tr > td, .table > thead > tr > th{\n    line-height: unset;\n}\n\n/* datatables 搜索框 */\n.dataTables_filter{\n    margin-top:-45px;\n}\n.dataTables_wrapper .dataTables_filter input{\n    width: 300px;\n}\n\n/* datatables 显示 _MENU_ 项结果 */\n.dataTables_length {\n    padding-top: unset;\n    margin-top:  unset;\n}\n.dataTables_wrapper .dataTables_length {\n    margin-left: unset;\n    margin-top : -7;\n}\n.dataTables_length select {\n    padding-bottom: unset;\n}\n\n.container-fluid {\n    padding: 0 0 0;\n}\n\n.pagination {\n    display: inline-block;\n    padding-left: 0;\n    margin: 20px 0;\n    border-radius: 4px;\n    font-size:13px;\n}\n.pagination>li:first-child>a, .pagination>li:first-child>span {\n    margin-left: 0;\n    border-top-left-radius: 4px;\n    border-bottom-left-radius: 4px;\n}\n.pagination>.disabled>a, .pagination>.disabled>a:focus, .pagination>.disabled>a:hover, .pagination>.disabled>span, .pagination>.disabled>span:focus, .pagination>.disabled>span:hover {\n    outline: none;\n    color: #777;\n    cursor: not-allowed;\n    background-color: #fff;\n    border-color: #ddd;\n}\n.pagination > li > a, .pagination > li > span {\n    background-color: #FFFFFF;\n    color: inherit;\n    float: left;\n    line-height: 1.42857;\n    margin-left: -1px;\n    padding: 4px 10px;\n    position: relative;\n    text-decoration: none;\n}\n.pagination>li>a, .pagination>li>span {\n    position: relative;\n    float: left;\n    padding: 6px 12px;\n    margin-left: -1px;\n    line-height: 1.42857143;\n    color: #337ab7;\n    text-decoration: none;\n    background-color: #fff;\n}\n.pagination > li > a, .pagination > li > span {\n    background-color: #FFFFFF;\n    color: inherit;\n    float: left;\n    line-height: 1.42857;\n    margin-left: -1px;\n    padding: 4px 10px;\n    position: relative;\n    text-decoration: none;\n}\n.pagination>li>a:focus, .pagination>li>a:hover, .pagination>li>span:focus, .pagination>li>span:hover {\n    color: #23527c;\n    background-color: #eee;\n    border-color: #ddd;\n}\n\ndiv.dataTables_wrapper div.dataTables_info {\n    padding-top: 0.75em;\n    white-space: nowrap;\n    font-size: 13px;\n}\n\nlabel{\n    font-size: 13px;\n}"
  },
  {
    "path": "static/css/spinners.css",
    "content": "\n\n.preloader{\n  position: relative;\n  margin: 0 auto;\n  width: 100px;\n}\n.preloader:before{\n    content: '';\n    display: block;\n    padding-top: 100%;\n}\n.circular {\n  animation: rotate 2s linear infinite;\n  height: 50px;\n  transform-origin: center center;\n  width: 50px;\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  right: 0;\n  margin: auto;\n}\n.path {\n  stroke-dasharray: 1, 200;\n  stroke-dashoffset: 0;\n  animation: dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite;\n  stroke-linecap: round;\n}\n@keyframes rotate {\n  100% {\n    transform: rotate(360deg);\n  }\n}\n\n@keyframes dash {\n  0% {\n    stroke-dasharray: 1, 200;\n    stroke-dashoffset: 0;\n  }\n  50% {\n    stroke-dasharray: 89, 200;\n    stroke-dashoffset: -35px;\n  }\n  100% {\n    stroke-dasharray: 89, 200;\n    stroke-dashoffset: -124px;\n  }\n}\n\n@keyframes color {\n  100%,\n  0% {\n    stroke: #d62d20;\n  }\n  40% {\n    stroke: #0057e7;\n  }\n  66% {\n    stroke: #008744;\n  }\n  80%,\n  90% {\n    stroke: #ffa700;\n  }\n}\n.bd-booticon{display:block;width:9rem;height:9rem;font-size:6.5rem;line-height:9rem;color:#fff;text-align:center;cursor:default;background-color:#563d7c;border-radius:15%}.bd-booticon.inverse{color:#563d7c;background-color:#fff}.bd-booticon.outline{background-color:transparent;border:1px solid #cdbfe3}.bd-navbar .navbar-nav .nav-link{color:#8e869d}.bd-navbar .navbar-nav .nav-link.active,.bd-navbar .navbar-nav .nav-link:focus,.bd-navbar .navbar-nav .nav-link:hover{color:#292b2c;background-color:transparent}.bd-navbar .navbar-nav .nav-link.active{font-weight:500;color:#040404}.bd-navbar .dropdown-menu{font-size:inherit}.bd-masthead{position:relative;padding:3rem 15px 2rem;color:#cdbfe3;text-align:center;background-image:-webkit-linear-gradient(315deg,#271b38,#563d7c,#7952b3);background-image:-o-linear-gradient(315deg,#271b38,#563d7c,#7952b3);background-image:linear-gradient(135deg,#271b38,#563d7c,#7952b3)}.bd-masthead .bd-booticon{margin:0 auto 2rem;color:#cdbfe3;border-color:#cdbfe3}.bd-masthead h1{font-weight:300;line-height:1}.bd-masthead .lead{margin-right:auto;margin-bottom:2rem;margin-left:auto;font-size:1.25rem;color:#fff}.bd-masthead .version{margin-top:-1rem;margin-bottom:2rem}.bd-masthead .btn{width:100%;padding:1rem 2rem;font-size:1.25rem;font-weight:500;color:#ffe484;border-color:#ffe484}.bd-masthead .btn:hover{color:#2a2730;background-color:#ffe484;border-color:#ffe484}.bd-masthead .carbonad{margin-bottom:-2rem!important}@media (min-width:576px){.bd-masthead{padding-top:8rem;padding-bottom:2rem}.bd-masthead .btn{width:auto}.bd-masthead .carbonad{margin-bottom:0!important}}@media (min-width:768px){.bd-masthead{padding-bottom:4rem}.bd-masthead .bd-header{margin-bottom:4rem}.bd-masthead h1{font-size:4rem}.bd-masthead .lead{font-size:1.5rem}.bd-masthead .carbonad{margin-top:3rem!important}}@media (min-width:992px){.bd-masthead .lead{width:85%;font-size:2rem}}.bd-featurette{padding-top:3rem;padding-bottom:3rem;font-size:1rem;line-height:1.5;color:#555;text-align:center;background-color:#fff;border-top:1px solid #eee}.bd-featurette .highlight{text-align:left}.bd-featurette .lead{margin-right:auto;margin-bottom:2rem;margin-left:auto;font-size:1rem;text-align:center}@media (min-width:576px){.bd-featurette{text-align:left}}@media (min-width:768px){.bd-featurette .col-sm-6:first-child{padding-right:45px}.bd-featurette .col-sm-6:last-child{padding-left:45px}}.bd-featurette-title{margin-bottom:.5rem;font-size:2rem;font-weight:400;color:#333;text-align:center}.half-rule{width:6rem;margin:2.5rem auto}@media (min-width:576px){.half-rule{margin-right:0;margin-left:0}}.bd-featurette h4{margin-top:1rem;margin-bottom:.5rem;font-weight:400;color:#333}.bd-featurette-img{display:block;margin-bottom:1.25rem;color:#333}.bd-featurette-img:hover{color:#0275d8;text-decoration:none}.bd-featurette-img img{display:block;margin-bottom:1rem}@media (min-width:480px){.bd-featurette .img-fluid{margin-top:2rem}}@media (min-width:768px){.bd-featurette{padding-top:6rem;padding-bottom:6rem}.bd-featurette-title{font-size:2.5rem}.bd-featurette-title+.lead{font-size:1.5rem}.bd-featurette .lead{max-width:80%}.bd-featurette .img-fluid{margin-top:0}}.bd-featured-sites{margin-right:-1px;margin-left:-1px}.bd-featured-sites .col-6{padding:1px}.bd-featured-sites .img-fluid{margin-top:0}@media (min-width:768px){.bd-featured-sites .col-sm-3:first-child img{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.bd-featured-sites .col-sm-3:last-child img{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}}#carbonads{display:block;padding:15px 15px 15px 160px;margin:50px -15px 0;overflow:hidden;font-size:13px;line-height:1.5;text-align:left;border:solid #866ab3;border-width:1px 0 0}#carbonads a{color:#fff;text-decoration:none}@media (min-width:576px){#carbonads{max-width:330px;margin:50px auto 0;border-width:1px;border-radius:4px}}@media (min-width:992px){#carbonads{position:absolute;top:0;right:15px;margin-top:0}.bd-masthead #carbonads{position:static}}.carbon-img{float:left;margin-left:-145px}.carbon-poweredby{display:block;color:#cdbfe3!important}.bd-content>table{display:block;width:100%;max-width:100%;margin-bottom:1rem;overflow-y:auto}.bd-content>table>tbody>tr>td,.bd-content>table>tbody>tr>th,.bd-content>table>tfoot>tr>td,.bd-content>table>tfoot>tr>th,.bd-content>table>thead>tr>td,.bd-content>table>thead>tr>th{padding:.75rem;vertical-align:top;border:1px solid #eceeef}.bd-content>table>tbody>tr>td>p:last-child,.bd-content>table>tbody>tr>th>p:last-child,.bd-content>table>tfoot>tr>td>p:last-child,.bd-content>table>tfoot>tr>th>p:last-child,.bd-content>table>thead>tr>td>p:last-child,.bd-content>table>thead>tr>th>p:last-child{margin-bottom:0}.bd-content>table td:first-child>code{white-space:nowrap}.bd-content>h2:not(:first-child){margin-top:3rem}.bd-content>h3{margin-top:1.5rem}.bd-content>ol li,.bd-content>ul li{margin-bottom:.25rem}@media (min-width:576px){.bd-title{font-size:3rem}.bd-title+p{font-size:1.25rem;font-weight:300}}#markdown-toc>li:first-child{display:none}#markdown-toc ul{padding-left:2rem;margin-top:.25rem;margin-bottom:.25rem}.bd-pageheader{padding:2rem 15px;margin-bottom:1.5rem;color:#cdbfe3;text-align:center;background-color:#563d7c}.bd-pageheader .container{position:relative}.bd-pageheader h1{font-size:3rem;font-weight:400;color:#fff}.bd-pageheader p{margin-bottom:0;font-size:1.25rem;font-weight:300}@media (min-width:576px){.bd-pageheader{padding-top:4rem;padding-bottom:4rem;margin-bottom:3rem;text-align:left}.bd-pageheader .carbonad{margin:2rem 0 0!important}}@media (min-width:768px){.bd-pageheader h1{font-size:4rem}.bd-pageheader p{font-size:1.5rem}}@media (min-width:992px){.bd-pageheader h1,.bd-pageheader p{margin-right:380px}.bd-pageheader .carbonad{position:absolute;top:0;right:.75rem;margin:0!important}}#skippy{display:block;padding:1em;color:#fff;background-color:#563d7c;outline:0}#skippy .skiplink-text{padding:.5em;outline:1px dotted}@media (min-width:768px){.bd-sidebar{padding-left:1rem}}.bd-search{position:relative;margin-bottom:1.5rem}.bd-search .form-control{height:2.45rem;padding-top:.4rem;padding-bottom:.4rem;background-color:#fafafa}.bd-search .form-control:focus{background-color:#fff}.bd-search-results{right:0;display:block;padding:0;overflow:hidden;font-size:.9rem}.bd-search-results:empty{display:none}.bd-search-results .dropdown-item{padding-right:.75rem;padding-left:.75rem}.bd-search-results .dropdown-item:first-child{margin-top:.25rem}.bd-search-results .dropdown-item:last-child{margin-bottom:.25rem}.bd-search-results .no-results{padding:.75rem 1rem;color:#7a7a7a;text-align:center;white-space:normal}.bd-sidenav{display:none}.bd-toc-link{display:block;padding:.25rem .75rem;color:#464a4c}.bd-toc-link:focus,.bd-toc-link:hover{color:#0275d8;text-decoration:none}.active>.bd-toc-link{font-weight:500;color:#292b2c}.active>.bd-sidenav{display:block}.bd-toc-item.active{margin-top:1rem;margin-bottom:1rem}.bd-toc-item:first-child{margin-top:0}.bd-toc-item:last-child{margin-bottom:2rem}.bd-sidebar .nav>li>a{display:block;padding:.25rem .75rem;font-size:90%;color:#99979c}.bd-sidebar .nav>li>a:focus,.bd-sidebar .nav>li>a:hover{color:#0275d8;text-decoration:none;background-color:transparent}.bd-sidebar .nav>.active:focus>a,.bd-sidebar .nav>.active:hover>a,.bd-sidebar .nav>.active>a{font-weight:500;color:#292b2c;background-color:transparent}.bd-footer{padding:4rem 0;margin-top:4rem;font-size:85%;text-align:center;background-color:#f7f7f7}.bd-footer a{font-weight:500;color:#464a4c}.bd-footer a:hover{color:#0275d8}.bd-footer p{margin-bottom:0}@media (min-width:576px){.bd-footer{text-align:left}}.bd-footer-links{padding-left:0;margin-bottom:1rem}.bd-footer-links li{display:inline-block}.bd-footer-links li+li{margin-left:1rem}.bd-example-row .row+.row{margin-top:1rem}.bd-example-row .row>.col,.bd-example-row .row>[class^=col-]{padding-top:.75rem;padding-bottom:.75rem;background-color:rgba(86,61,124,.15);border:1px solid rgba(86,61,124,.2)}.bd-example-row .flex-items-bottom,.bd-example-row .flex-items-middle,.bd-example-row .flex-items-top{min-height:6rem;background-color:rgba(255,0,0,.1)}.bd-example-row-flex-cols .row{min-height:10rem;background-color:rgba(255,0,0,.1)}.bd-highlight{background-color:rgba(86,61,124,.15);border:1px solid rgba(86,61,124,.15)}.bd-example-container{min-width:16rem;max-width:25rem;margin-right:auto;margin-left:auto}.bd-example-container-header{height:3rem;margin-bottom:.5rem;background-color:#daeeff;border-radius:.25rem}.bd-example-container-sidebar{float:right;width:4rem;height:8rem;background-color:#fae3c4;border-radius:.25rem}.bd-example-container-body{height:8rem;margin-right:4.5rem;background-color:#957bbe;border-radius:.25rem}.bd-example-container-fluid{max-width:none}.bd-example{position:relative;padding:1rem;margin:1rem -1rem;border:solid #f7f7f9;border-width:.2rem 0 0}.bd-example::after{display:block;content:\"\";clear:both}@media (min-width:576px){.bd-example{padding:1.5rem;margin-right:0;margin-bottom:0;margin-left:0;border-width:.2rem}}.bd-example+.clipboard+.highlight,.bd-example+.highlight{margin-top:0}.bd-example+p{margin-top:2rem}.bd-example .pos-f-t{position:relative;margin:-1rem}@media (min-width:576px){.bd-example .pos-f-t{margin:-1.5rem}}.bd-example>.form-control+.form-control{margin-top:.5rem}.bd-example>.alert+.alert,.bd-example>.nav+.nav,.bd-example>.navbar+.navbar,.bd-example>.progress+.btn,.bd-example>.progress+.progress{margin-top:1rem}.bd-example>.dropdown-menu:first-child{position:static;display:block}.bd-example>.form-group:last-child{margin-bottom:0}.bd-example>.close{float:none}.bd-example-type .table .type-info{color:#999;vertical-align:middle}.bd-example-type .table td{padding:1rem 0;border-color:#eee}.bd-example-type .table tr:first-child td{border-top:0}.bd-example-type h1,.bd-example-type h2,.bd-example-type h3,.bd-example-type h4,.bd-example-type h5,.bd-example-type h6{margin:0}.bd-example-bg-classes p{padding:1rem}.bd-example>img+img{margin-left:.5rem}.bd-example>.btn-group{margin-top:.25rem;margin-bottom:.25rem}.bd-example>.btn-toolbar+.btn-toolbar{margin-top:.5rem}.bd-example-control-sizing input[type=text]+input[type=text],.bd-example-control-sizing select{margin-top:.5rem}.bd-example-form .input-group{margin-bottom:.5rem}.bd-example>textarea.form-control{resize:vertical}.bd-example>.list-group{max-width:400px}.bd-example .fixed-top,.bd-example .sticky-top{position:static;margin:-1rem -1rem 1rem}.bd-example .fixed-bottom{position:static;margin:1rem -1rem -1rem}@media (min-width:576px){.bd-example .fixed-top,.bd-example .sticky-top{margin:-1.5rem -1.5rem 1rem}.bd-example .fixed-bottom{margin:1rem -1.5rem -1.5rem}}.bd-example .pagination{margin-top:.5rem;margin-bottom:.5rem}.bd-example-modal{background-color:#fafafa}.bd-example-modal .modal{position:relative;top:auto;right:auto;bottom:auto;left:auto;z-index:1;display:block}.bd-example-modal .modal-dialog{left:auto;margin-right:auto;margin-left:auto}.bd-example-tabs .nav-tabs{margin-bottom:1rem}.bd-example-tooltips{text-align:center}.bd-example-tooltips>.btn{margin-top:.25rem;margin-bottom:.25rem}.bd-example-popover-static{padding-bottom:1.5rem;background-color:#f9f9f9}.bd-example-popover-static .popover{position:relative;display:block;float:left;width:260px;margin:1.25rem}.tooltip-demo a{white-space:nowrap}.bd-example-tooltip-static .tooltip{position:relative;display:inline-block;margin:10px 20px;opacity:1}.scrollspy-example{position:relative;height:200px;margin-top:.5rem;overflow:auto}.bd-example>.bg-danger:not(.navbar),.bd-example>.bg-faded:not(.navbar),.bd-example>.bg-info:not(.navbar),.bd-example>.bg-inverse:not(.navbar),.bd-example>.bg-primary:not(.navbar),.bd-example>.bg-success:not(.navbar),.bd-example>.bg-warning:not(.navbar){padding:.5rem;margin-top:.5rem;margin-bottom:.5rem}.bd-example-border-utils [class^=border-]{display:inline-block;width:6rem;height:6rem;margin:.25rem;background-color:#f5f5f5;border:1px solid}.highlight{padding:1rem;margin:1rem -15px;background-color:#f7f7f9;-ms-overflow-style:-ms-autohiding-scrollbar}@media (min-width:576px){.highlight{padding:1.5rem;margin-right:0;margin-left:0}}.highlight pre{padding:0;margin-top:0;margin-bottom:0;background-color:transparent;border:0}.highlight pre code{font-size:inherit;color:#292b2c}.table-responsive .highlight pre{white-space:normal}.bd-table th small,.responsive-utilities th small{display:block;font-weight:400;color:#999}.responsive-utilities tbody th{font-weight:400}.responsive-utilities td{text-align:center}.responsive-utilities .is-visible{color:#468847;background-color:#dff0d8!important}.responsive-utilities .is-hidden{color:#ccc;background-color:#f9f9f9!important}.responsive-utilities-test{margin-top:.25rem}.responsive-utilities-test .col-6{margin-top:.5rem;margin-bottom:.5rem}.responsive-utilities-test span{display:block;padding:1rem .5rem;font-size:1rem;font-weight:700;line-height:1.1;text-align:center;border-radius:.25rem}.hidden-on .col-6>.not-visible,.visible-on .col-6>.not-visible{color:#999;border:1px solid #ddd}.hidden-on .col-6 .visible,.visible-on .col-6 .visible{color:#468847;background-color:#dff0d8;border:1px solid #d6e9c6}@media (max-width:575px){.hidden-xs-only{display:none!important}}@media (min-width:576px) and (max-width:767px){.hidden-sm-only{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-md-only{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-lg-only{display:none!important}}@media (min-width:1200px){.hidden-xl-only{display:none!important}}.btn-bs{font-weight:500;color:#7952b3;border-color:#7952b3}.btn-bs:active,.btn-bs:focus,.btn-bs:hover{color:#fff;background-color:#7952b3;border-color:#7952b3}.bd-callout{padding:1.25rem;margin-top:1.25rem;margin-bottom:1.25rem;border:1px solid #eee;border-left-width:.25rem;border-radius:.25rem}.bd-callout h4{margin-top:0;margin-bottom:.25rem}.bd-callout p:last-child{margin-bottom:0}.bd-callout code{border-radius:.25rem}.bd-callout+.bd-callout{margin-top:-.25rem}.bd-callout-info{border-left-color:#5bc0de}.bd-callout-info h4{color:#5bc0de}.bd-callout-warning{border-left-color:#f0ad4e}.bd-callout-warning h4{color:#f0ad4e}.bd-callout-danger{border-left-color:#d9534f}.bd-callout-danger h4{color:#d9534f}.bd-examples .img-thumbnail{margin-bottom:.75rem}.bd-examples h4{margin-bottom:.25rem}.bd-examples p{margin-bottom:1.25rem}@media (max-width:480px){.bd-examples{margin-right:-.75rem;margin-left:-.75rem}.bd-examples>[class^=col-]{padding-right:.75rem;padding-left:.75rem}}.bd-team{margin-bottom:1.5rem}.bd-team .team-member{line-height:2rem;color:#555}.bd-team .team-member:hover{color:#333;text-decoration:none}.bd-team .github-btn{float:right;width:180px;height:1.25rem;margin-top:.25rem;border:0}.bd-team img{float:left;width:2rem;margin-right:.5rem;border-radius:.25rem}.bd-browser-bugs td p{margin-bottom:0}.bd-browser-bugs th:first-child{width:18%}.bd-brand-logos{display:table;width:100%;margin-bottom:1rem;overflow:hidden;color:#563d7c;background-color:#f9f9f9;border-radius:.25rem}.bd-brand-item{padding:4rem 0;text-align:center}.bd-brand-item+.bd-brand-item{border-top:1px solid #fff}.bd-brand-logos .inverse{color:#fff;background-color:#563d7c}.bd-brand-item h1,.bd-brand-item h3{margin-top:0;margin-bottom:0}.bd-brand-item .bd-booticon{margin-right:auto;margin-left:auto}@media (min-width:768px){.bd-brand-item{display:table-cell;width:1%}.bd-brand-item+.bd-brand-item{border-top:0;border-left:1px solid #fff}.bd-brand-item h1{font-size:4rem}}.color-swatches{margin:0 -5px;overflow:hidden}.color-swatch{float:left;width:4rem;height:4rem;margin-right:.25rem;margin-left:.25rem;border-radius:.25rem}@media (min-width:768px){.color-swatch{width:6rem;height:6rem}}.color-swatches .bd-purple{background-color:#563d7c}.color-swatches .bd-purple-light{background-color:#cdbfe3}.color-swatches .bd-purple-lighter{background-color:#e5e1ea}.color-swatches .bd-gray{background-color:#f9f9f9}.bd-clipboard{position:relative;display:none;float:right}.bd-clipboard+.highlight{margin-top:0}.btn-clipboard{position:absolute;top:.5rem;right:.5rem;z-index:10;display:block;padding:.25rem .5rem;font-size:75%;color:#818a91;cursor:pointer;background-color:transparent;border-radius:.25rem}.btn-clipboard:hover{color:#fff;background-color:#027de7}@media (min-width:768px){.bd-clipboard{display:block}}.hll{background-color:#ffc}.c{color:#999}.k{color:#069}.o{color:#555}.cm{color:#999}.cp{color:#099}.c1{color:#999}.cs{color:#999}.gd{background-color:#fcc;border:1px solid #c00}.ge{font-style:italic}.gr{color:red}.gh{color:#030}.gi{background-color:#cfc;border:1px solid #0c0}.go{color:#aaa}.gp{color:#009}.gu{color:#030}.gt{color:#9c6}.kc{color:#069}.kd{color:#069}.kn{color:#069}.kp{color:#069}.kr{color:#069}.kt{color:#078}.m{color:#f60}.s{color:#d44950}.na{color:#4f9fcf}.nb{color:#366}.nc{color:#0a8}.no{color:#360}.nd{color:#99f}.ni{color:#999}.ne{color:#c00}.nf{color:#c0f}.nl{color:#99f}.nn{color:#0cf}.nt{color:#2f6f9f}.nv{color:#033}.ow{color:#000}.w{color:#bbb}.mf{color:#f60}.mh{color:#f60}.mi{color:#f60}.mo{color:#f60}.sb{color:#c30}.sc{color:#c30}.sd{font-style:italic;color:#c30}.s2{color:#c30}.se{color:#c30}.sh{color:#c30}.si{color:#a00}.sx{color:#c30}.sr{color:#3aa}.s1{color:#c30}.ss{color:#fc3}.bp{color:#366}.vc{color:#033}.vg{color:#033}.vi{color:#033}.il{color:#f60}.css .nt+.nt,.css .o,.css .o+.nt{color:#999}.language-bash::before{color:#009;content:\"$ \";-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.language-powershell::before{color:#009;content:\"PM> \";-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.anchorjs-link{color:inherit}@media (max-width:480px){.anchorjs-link{display:none}}:hover>.anchorjs-link{opacity:.75;-webkit-transition:color .16s linear;-o-transition:color .16s linear;transition:color .16s linear}.anchorjs-link:focus,:hover>.anchorjs-link:hover{text-decoration:none;opacity:1}"
  },
  {
    "path": "static/css/style.css",
    "content": "﻿@import url('https://fonts.googleapis.com/css?family=Open+Sans:300i,400,600,700,800');\n@import url(../icons/font-awesome/css/font-awesome.min.css);\n@import url(../icons/simple-line-icons/css/simple-line-icons.css);\n@import url(../icons/weather-icons/css/weather-icons.min.css);\n@import url(../icons/linea-icons/linea.css);\n@import url(../icons/themify-icons/themify-icons.css);\n@import url(../icons/flag-icon-css/flag-icon.min.css);\n@import url(../icons/material-design-iconic-font/css/materialdesignicons.min.css);\n@import url(spinners.css);\n@import url(animate.css);\n/*\n    Template: Ela Admin\n    Author: Zebra Theme\n    Developer by: Zebra Theme\n\n    Table of Content\n    ================\n\n1. variable\n2. fonts\n3. card\n4. global\n5. badge\n6. tab\n7. modal\n8. timeline\n9. data-table\n10. panel\n11. button\n12. header\n13. gmap\n14. chat\n15. carousel\n16. weather\n17. invoice-edit\n18. invoice\n19. widget-stat\n20. recent-comments\n21. recent-message\n22. forms\n23. compose-email\n24. progress-bar\n25. todo-list\n26. datamap\n27. table\n28. order-progress\n29. login\n30. chart\n31. nestable\n32. profile\n33. profile-widget\n34. ui-element-basic\n35. calendar\n36. flot-chart\n37. morris-chart\n38. products_1\n39. products_2\n40. products_3\n41. favourite_menu\n42. order-list\n43. booking-system\n44. scrollable\n45. vector-map\n46. menu-upload\n47. social-media-stats\n48. vertical-carousel\n49. chartist\n50. table-export\n51. ui-widget-v1\n42. responsive\n\n*/\n.preloader {\n  width: 100%;\n  height: 100%;\n  top: 0;\n  position: fixed;\n  z-index: 99999;\n  background: #fff;\n}\n.preloader .cssload-speeding-wheel {\n  position: absolute;\n  top: calc(46.5%);\n  left: calc(46.5%);\n}\n* {\n  outline: none;\n}\nbody {\n  background: #fff;\n  font-family: 'Open Sans', sans-serif;\n  margin: 0;\n  overflow-x: hidden;\n  color: #67757c;\n}\nhtml {\n  position: relative;\n  min-height: 100%;\n  background: #ffffff;\n}\na:focus,\na:hover {\n  text-decoration: none;\n}\na.link {\n  color: #455a64;\n}\na.link:focus,\na.link:hover {\n  color: #1976d2;\n}\n.img-responsive,\n.carousel.vertical .carousel-inner > .item > img,\n.carousel.vertical .carousel-inner > .item > a > img {\n  width: 100%;\n  height: auto;\n  display: inline-block;\n}\n.img-rounded {\n  border-radius: 4px;\n}\n.mdi-set,\n.mdi:before {\n  line-height: initial;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n  color: #455a64;\n  font-weight: 400;\n}\nh1 {\n  line-height: 40px;\n  font-size: 36px;\n}\nh2 {\n  line-height: 36px;\n  font-size: 24px;\n}\nh3 {\n  line-height: 30px;\n  font-size: 21px;\n}\nh4 {\n  line-height: 22px;\n  font-size: 18px;\n}\nh5 {\n  line-height: 18px;\n  font-size: 16px;\n  font-weight: 400;\n}\nh6 {\n  line-height: 16px;\n  font-size: 14px;\n  font-weight: 400;\n}\n.display-5 {\n  font-size: 3rem;\n}\n.display-6 {\n  font-size: 36px;\n}\n.box {\n  border-radius: 4px;\n  padding: 10px;\n}\n.preloader {\n  width: 100%;\n  height: 100%;\n  top: 0;\n  position: fixed;\n  z-index: 99999;\n  background: #fff;\n}\n.preloader .cssload-speeding-wheel {\n  position: absolute;\n  top: calc(46.5%);\n  left: calc(46.5%);\n}\n#main-wrapper {\n  width: 100%;\n}\n.bg-white .card {\n  box-shadow: none;\n}\n.box-shadow {\n  box-shadow: 0 5px 20px rgba(0, 0, 0, 0.05) !important;\n}\n.dropzone {\n  border: 1px dashed #b1b8bb;\n}\n.boxed #main-wrapper {\n  width: 100%;\n  max-width: 1300px;\n  margin: 0 auto;\n  -webkit-box-shadow: 0 0 60px rgba(0, 0, 0, 0.1);\n  box-shadow: 0 0 60px rgba(0, 0, 0, 0.1);\n}\n.boxed #main-wrapper .sidebar-footer {\n  position: absolute;\n}\n.boxed #main-wrapper .footer {\n  display: none;\n}\n.page-wrapper {\n  background: #fafafa;\n  /* padding-bottom: 60px; */\n}\n.container-fluid {\n  /* padding: 0 30px 25px; */\n}\n@media (min-width: 1024px) {\n  .page-wrapper {\n    margin-left: 240px;\n  }\n  .footer {\n    left: 240px;\n  }\n}\n@media (max-width: 1023px) {\n  .page-wrapper {\n    margin-left: 60px;\n    -webkit-transition: 0.2s ease-in;\n    -o-transition: 0.2s ease-in;\n    transition: 0.2s ease-in;\n  }\n  .footer {\n    left: 60px;\n  }\n  .widget-app-columns {\n    -webkit-column-count: 1;\n    -moz-column-count: 1;\n    column-count: 1;\n  }\n}\n.thumb-sm {\n  height: 32px;\n  width: 32px;\n}\n.thumb-md {\n  height: 48px;\n  width: 48px;\n}\n.thumb-lg {\n  height: 88px;\n  width: 88px;\n}\n.hide {\n  display: none;\n}\n.img-circle {\n  border-radius: 100%;\n}\n.radius {\n  border-radius: 4px;\n}\n.text-white {\n  color: #ffffff !important;\n}\n.text-danger {\n  color: #ef5350 !important;\n}\n.text-muted {\n  color: #fff !important;\n}\n.text-warning {\n  color: #ffb22b !important;\n}\n.text-success {\n  color: #26dad2 !important;\n}\n.text-info {\n  color: #1976d2 !important;\n}\n.text-inverse {\n  color: #2f3d4a !important;\n}\n.text-blue {\n  color: #02bec9;\n}\n.text-purple {\n  color: #7460ee;\n}\n.text-primary {\n  color: #007bff;\n}\n.text-megna {\n  color: #00897b;\n}\n.text-dark {\n  color: #67757c;\n}\n.text-themecolor {\n  color: #1976d2;\n}\n.bg-primary {\n  background-color: #5c4ac7 !important;\n}\n.bg-success {\n  background-color: #26dad2 !important;\n}\n.bg-info {\n  background-color: #1976d2 !important;\n}\n.bg-warning {\n  background-color: #ffb22b !important;\n}\n.bg-danger {\n  background-color: #ef5350 !important;\n}\n.bg-megna {\n  background-color: #00897b;\n}\n.bg-theme {\n  background-color: #1976d2;\n}\n.bg-inverse {\n  background-color: #2f3d4a;\n}\n.bg-purple {\n  background-color: #7460ee;\n}\n.bg-light-part {\n  background-color: rgba(0, 0, 0, 0.02);\n}\n.bg-light-primary {\n  background-color: #f1effd;\n}\n.bg-light-success {\n  background-color: #e8fdeb;\n}\n.bg-light-info {\n  background-color: #cfecfe;\n}\n.bg-light-extra {\n  background-color: #ebf3f5;\n}\n.bg-light-warning {\n  background-color: #fff8ec;\n}\n.bg-light-danger {\n  background-color: #f9e7eb;\n}\n.bg-light-inverse {\n  background-color: #f6f6f6;\n}\n.bg-light {\n  background-color: #f2f4f8;\n}\n.bg-white {\n  background-color: #ffffff;\n}\n@media (min-width: 1600px) {\n  .col-xlg-1,\n  .col-xlg-10,\n  .col-xlg-11,\n  .col-xlg-12,\n  .col-xlg-2,\n  .col-xlg-3,\n  .col-xlg-4,\n  .col-xlg-5,\n  .col-xlg-6,\n  .col-xlg-7,\n  .col-xlg-8,\n  .col-xlg-9 {\n    float: left;\n  }\n  .col-xlg-12 {\n    -webkit-box-flex: 0;\n    -webkit-flex: 0 0 100%;\n    -ms-flex: 0 0 100%;\n    flex: 0 0 100%;\n    max-width: 100%;\n  }\n  .col-xlg-11 {\n    -webkit-box-flex: 0;\n    -webkit-flex: 0 0 91.66666667%;\n    -ms-flex: 0 0 91.66666667%;\n    flex: 0 0 91.66666667%;\n    max-width: 91.66666667%;\n  }\n  .col-xlg-10 {\n    -webkit-box-flex: 0;\n    -webkit-flex: 0 0 83.33333333%;\n    -ms-flex: 0 0 83.33333333%;\n    flex: 0 0 83.33333333%;\n    max-width: 83.33333333%;\n  }\n  .col-xlg-9 {\n    -webkit-box-flex: 0;\n    -webkit-flex: 0 0 75%;\n    -ms-flex: 0 0 75%;\n    flex: 0 0 75%;\n    max-width: 75%;\n  }\n  .col-xlg-8 {\n    -webkit-box-flex: 0;\n    -webkit-flex: 0 0 66.66666667%;\n    -ms-flex: 0 0 66.66666667%;\n    flex: 0 0 66.66666667%;\n    max-width: 66.66666667%;\n  }\n  .col-xlg-7 {\n    -webkit-box-flex: 0;\n    -webkit-flex: 0 0 58.33333333%;\n    -ms-flex: 0 0 58.33333333%;\n    flex: 0 0 58.33333333%;\n    max-width: 58.33333333%;\n  }\n  .col-xlg-6 {\n    -webkit-box-flex: 0;\n    -webkit-flex: 0 0 50%;\n    -ms-flex: 0 0 50%;\n    flex: 0 0 50%;\n    max-width: 50%;\n  }\n  .col-xlg-5 {\n    -webkit-box-flex: 0;\n    -webkit-flex: 0 0 41.66666667%;\n    -ms-flex: 0 0 41.66666667%;\n    flex: 0 0 41.66666667%;\n    max-width: 41.66666667%;\n  }\n  .col-xlg-4 {\n    -webkit-box-flex: 0;\n    -webkit-flex: 0 0 33.33333333%;\n    -ms-flex: 0 0 33.33333333%;\n    flex: 0 0 33.33333333%;\n    max-width: 33.33333333%;\n  }\n  .col-xlg-3 {\n    -webkit-box-flex: 0;\n    -webkit-flex: 0 0 25%;\n    -ms-flex: 0 0 25%;\n    flex: 0 0 25%;\n    max-width: 25%;\n  }\n  .col-xlg-2 {\n    -webkit-box-flex: 0;\n    -webkit-flex: 0 0 16.66666667%;\n    -ms-flex: 0 0 16.66666667%;\n    flex: 0 0 16.66666667%;\n    max-width: 16.66666667%;\n  }\n  .col-xlg-1 {\n    -webkit-box-flex: 0;\n    -webkit-flex: 0 0 8.33333333%;\n    -ms-flex: 0 0 8.33333333%;\n    flex: 0 0 8.33333333%;\n    max-width: 8.33333333%;\n  }\n  .col-xlg-pull-12 {\n    right: 100%;\n  }\n  .col-xlg-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-xlg-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-xlg-pull-9 {\n    right: 75%;\n  }\n  .col-xlg-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-xlg-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-xlg-pull-6 {\n    right: 50%;\n  }\n  .col-xlg-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-xlg-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-xlg-pull-3 {\n    right: 25%;\n  }\n  .col-xlg-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-xlg-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-xlg-pull-0 {\n    right: auto;\n  }\n  .col-xlg-push-12 {\n    left: 100%;\n  }\n  .col-xlg-push-11 {\n    left: 91.66666667%;\n  }\n  .col-xlg-push-10 {\n    left: 83.33333333%;\n  }\n  .col-xlg-push-9 {\n    left: 75%;\n  }\n  .col-xlg-push-8 {\n    left: 66.66666667%;\n  }\n  .col-xlg-push-7 {\n    left: 58.33333333%;\n  }\n  .col-xlg-push-6 {\n    left: 50%;\n  }\n  .col-xlg-push-5 {\n    left: 41.66666667%;\n  }\n  .col-xlg-push-4 {\n    left: 33.33333333%;\n  }\n  .col-xlg-push-3 {\n    left: 25%;\n  }\n  .col-xlg-push-2 {\n    left: 16.66666667%;\n  }\n  .col-xlg-push-1 {\n    left: 8.33333333%;\n  }\n  .col-xlg-push-0 {\n    left: auto;\n  }\n  .offset-xlg-12 {\n    margin-left: 100%;\n  }\n  .offset-xlg-11 {\n    margin-left: 91.66666667%;\n  }\n  .offset-xlg-10 {\n    margin-left: 83.33333333%;\n  }\n  .offset-xlg-9 {\n    margin-left: 75%;\n  }\n  .offset-xlg-8 {\n    margin-left: 66.66666667%;\n  }\n  .offset-xlg-7 {\n    margin-left: 58.33333333%;\n  }\n  .offset-xlg-6 {\n    margin-left: 50%;\n  }\n  .offset-xlg-5 {\n    margin-left: 41.66666667%;\n  }\n  .offset-xlg-4 {\n    margin-left: 33.33333333%;\n  }\n  .offset-xlg-3 {\n    margin-left: 25%;\n  }\n  .offset-xlg-2 {\n    margin-left: 16.66666667%;\n  }\n  .offset-xlg-1 {\n    margin-left: 8.33333333%;\n  }\n  .offset-xlg-0 {\n    margin-left: 0;\n  }\n}\n.col-xlg-1,\n.col-xlg-10,\n.col-xlg-11,\n.col-xlg-12,\n.col-xlg-2,\n.col-xlg-3,\n.col-xlg-4,\n.col-xlg-5,\n.col-xlg-6,\n.col-xlg-7,\n.col-xlg-8,\n.col-xlg-9 {\n  position: relative;\n  min-height: 1px;\n  padding-right: 15px;\n  padding-left: 15px;\n}\n.input-group-addon [type=checkbox]:checked,\n.input-group-addon [type=checkbox]:not(:checked),\n.input-group-addon [type=radio]:checked,\n.input-group-addon [type=radio]:not(:checked) {\n  position: initial;\n  opacity: 1;\n}\n.invisible {\n  visibility: hidden !important;\n}\n.hidden-xs-up {\n  display: none !important;\n}\n@media (max-width: 575px) {\n  .hidden-xs-down {\n    display: none !important;\n  }\n}\n@media (min-width: 576px) {\n  .hidden-sm-up {\n    display: none !important;\n  }\n}\n@media (max-width: 767px) {\n  .hidden-sm-down {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) {\n  .hidden-md-up {\n    display: none !important;\n  }\n}\n@media (max-width: 991px) {\n  .hidden-md-down {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) {\n  .hidden-lg-up {\n    display: none !important;\n  }\n}\n@media (max-width: 1199px) {\n  .hidden-lg-down {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-xl-up {\n    display: none !important;\n  }\n}\n.hidden-xl-down {\n  display: none !important;\n}\n@media (min-width: 1650px) {\n  .widget-app-columns {\n    -webkit-column-count: 3;\n    -moz-column-count: 3;\n    column-count: 3;\n  }\n  .campaign {\n    height: 365px !important;\n  }\n}\n@media (max-width: 1370px) {\n  .widget-app-columns {\n    -webkit-column-count: 2;\n    -moz-column-count: 2;\n    column-count: 2;\n  }\n}\na,\nbutton {\n  outline: none!important;\n  text-decoration: none!important;\n  color: #99abb4;\n  transition: all 0.2s ease 0s;\n}\na.active,\nbutton.active,\na:focus,\nbutton:focus,\na:hover,\nbutton:hover {\n  color: #252525;\n  outline: none!important;\n  text-decoration: none!important;\n}\nul {\n  padding: 0;\n  margin: 0;\n}\nli {\n  list-style: none;\n}\np {\n  font-family: 'Poppins', sans-serif;\n  color: #99abb4;\n}\n.h2,\n.h3,\n.h4,\n.h5,\n.h6,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6.h1 {\n  color: #455a64;\n}\n.dib {\n  display: inline-block;\n}\n.rotate-90 {\n  transform: rotate(90deg);\n}\n.rotate-180 {\n  transform: rotate(180deg);\n}\n#main-content {\n  padding: 0 15px;\n}\n.alert h4 {\n  color: #455a64;\n}\n.border-none {\n  border: 1px solid transparent;\n}\n.footer > p {\n  background: #ffffff;\n  margin: 15px -30px 0;\n  padding: 15px 45px;\n  text-align: left;\n}\n.footer > p a {\n  color: #4680ff;\n}\n.bar-hidden {\n  overflow-X: hidden;\n}\n.color-white {\n  color: #ffffff;\n}\n.btn-btn {\n  padding: 15px 25px;\n  border: 0;\n}\n.btn-btn:hover {\n  color: #ffffff;\n}\n.letter-space {\n  letter-spacing: 1px;\n}\n.solid-btn {\n  padding: 15px 42px;\n}\n.notify {\n  position: relative;\n  right: -10px;\n  top: -13px;\n}\n.notify .heartbit {\n  animation: 1s ease-out 0s normal none infinite running heartbit;\n  border: 5px solid #4680ff;\n  border-radius: 70px;\n  height: 25px;\n  position: absolute;\n  right: -4px;\n  top: -20px;\n  width: 25px;\n  z-index: 10;\n}\n.notify .point {\n  background-color: #4680ff;\n  border-radius: 30px;\n  height: 6px;\n  position: absolute;\n  right: 6px;\n  top: -10px;\n  width: 6px;\n}\n@-moz-keyframes heartbit {\n  0% {\n    -moz-transform: scale(0);\n    opacity: 0.0;\n  }\n  25% {\n    -moz-transform: scale(0.1);\n    opacity: 0.1;\n  }\n  50% {\n    -moz-transform: scale(0.5);\n    opacity: 0.3;\n  }\n  75% {\n    -moz-transform: scale(0.8);\n    opacity: 0.5;\n  }\n  to {\n    -moz-transform: scale(1);\n    opacity: 0.0;\n  }\n}\n@-webkit-keyframes heartbit {\n  0% {\n    -webkit-transform: scale(0);\n    opacity: 0.0;\n  }\n  25% {\n    -webkit-transform: scale(0.1);\n    opacity: 0.1;\n  }\n  50% {\n    -webkit-transform: scale(0.5);\n    opacity: 0.3;\n  }\n  75% {\n    -webkit-transform: scale(0.8);\n    opacity: 0.5;\n  }\n  to {\n    -webkit-transform: scale(1);\n    opacity: 0.0;\n  }\n}\n/*    Color Mixins\n-------------------*/\n.color-primary,\n.text-primary {\n  color: #4680ff;\n}\n.color-success,\n.text-success {\n  color: #26dad2;\n}\n.color-info,\n.text-info {\n  color: #62d1f3;\n}\n.color-danger,\n.text-danger {\n  color: #fc6180;\n}\n.color-warning,\n.text-warning {\n  color: #ffb64d;\n}\n.color-pink,\n.text-pink {\n  color: #e6a1f2;\n}\n.color-dark,\n.text-dark {\n  color: #444c67;\n}\n.color-grey,\n.text-grey {\n  color: #ddd;\n}\n/*    Mixins\n--------------------------*/\n.pr {\n  position: relative;\n}\n.pa {\n  position: absolute;\n}\n/*    Background Mixins\n--------------------------*/\n.bg-primary {\n  background: #4680ff !important;\n  color: #ffffff;\n  fill: #4680ff;\n}\n.bg-success {\n  background: #26dad2 !important;\n  color: #ffffff;\n  fill: #26dad2;\n}\n.bg-info {\n  background: #62d1f3 !important;\n  color: #ffffff;\n  fill: #62d1f3;\n}\n.bg-danger {\n  background: #fc6180 !important;\n  color: #ffffff;\n  fill: #fc6180;\n}\n.bg-warning {\n  background: #ffb64d !important;\n  color: #ffffff;\n  fill: #ffb64d;\n}\n.bg-pink {\n  background: #e6a1f2 !important;\n  color: #ffffff;\n  fill: #e6a1f2;\n}\n.bg-dark {\n  background: #444c67 !important;\n  color: #ffffff;\n  fill: #444c67;\n}\n.bg-transparent {\n  background: transparent;\n  color: #252525;\n}\n.no-select-arrow {\n  -moz-appearance: none !important;\n  -webkit-appearance: none !important;\n  border: 1px solid #e7e7e7;\n}\n.bg-ash {\n  background: #f5f5f5;\n}\n.bg-white {\n  background: #ffffff;\n}\n/*    Border Mixins\n--------------------------*/\n.border-primary {\n  border-color: #4680ff;\n}\n.border-success {\n  border-color: #26dad2;\n}\n.border-info {\n  border-color: #62d1f3;\n}\n.border-danger {\n  border-color: #fc6180;\n}\n.border-warning {\n  border-color: #ffb64d;\n}\n.border-pink {\n  border-color: #e6a1f2;\n}\n.border-dark {\n  border-color: #444c67;\n}\n.no-border {\n  border: 0px!important;\n}\n.border-top {\n  border-top: 1px solid #e7e7e7;\n}\n.border-white {\n  border: 1px solid #ffffff;\n}\n.border-bottom {\n  border-bottom: 1px solid #e7e7e7;\n}\n.border-left {\n  border-left: 1px solid #e7e7e7;\n}\n.border-right {\n  border-right: 1px solid #e7e7e7;\n}\n.white-bottom {\n  border-bottom: 1px solid #ffffff;\n}\n.radius-0 {\n  border-radius: 0;\n}\n/*    Brand Background\n-----------------------------*/\n.bg-facebook {\n  background: #3b5998;\n  fill: #3b5998;\n}\n.bg-twitter {\n  background: #1da1f2;\n  fill: #1da1f2;\n}\n.bg-youtube {\n  background: #cd201f;\n  fill: #cd201f;\n}\n.bg-google-plus {\n  background: #dd4b39;\n  fill: #dd4b39;\n}\n.bg-linkedin {\n  background: #007bb6;\n}\n/*    width\n-----------------------------*/\n.w10pr {\n  width: 10%;\n}\n.w12pr {\n  width: 12%;\n}\n.p-28 {\n  padding: 28px;\n}\n.p-10 {\n  padding: 10px;\n}\n/*    Chart Spanrkline\n-------------------------*/\n.jqstooltip {\n  -webkit-box-sizing: content-box;\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n}\n/*    Bootstrap class\n---------------------------*/\n@media (min-width: 1500px) {\n  .container {\n    width: 1400px;\n  }\n}\n@-webkit-keyframes rotate {\n  0% {\n    -webkit-transform: rotate(0deg);\n  }\n  to {\n    -webkit-transform: rotate(360deg);\n  }\n}\n@-moz-keyframes rotate {\n  0% {\n    -moz-transform: rotate(0deg);\n  }\n  to {\n    -moz-transform: rotate(360deg);\n  }\n}\n@keyframes rotate {\n  0% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  to {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-moz-keyframes heartbit {\n  0% {\n    -moz-transform: scale(0);\n    opacity: 0.0;\n  }\n  25% {\n    -moz-transform: scale(0.1);\n    opacity: 0.1;\n  }\n  50% {\n    -moz-transform: scale(0.5);\n    opacity: 0.3;\n  }\n  75% {\n    -moz-transform: scale(0.8);\n    opacity: 0.5;\n  }\n  to {\n    -moz-transform: scale(1);\n    opacity: 0.0;\n  }\n}\n@-webkit-keyframes heartbit {\n  0% {\n    -webkit-transform: scale(0);\n    opacity: 0.0;\n  }\n  25% {\n    -webkit-transform: scale(0.1);\n    opacity: 0.1;\n  }\n  50% {\n    -webkit-transform: scale(0.5);\n    opacity: 0.3;\n  }\n  75% {\n    -webkit-transform: scale(0.8);\n    opacity: 0.5;\n  }\n  to {\n    -webkit-transform: scale(1);\n    opacity: 0.0;\n  }\n}\n.header {\n  position: relative;\n  z-index: 50;\n  /* background: #0078D7; */\n  background: #000;\n  box-shadow: 1px 0 5px rgba(0, 0, 0, 0.1);\n}\n.header .top-navbar {\n  min-height: 50px;\n  padding: 0 15px 0 0;\n}\n.header .top-navbar .dropdown-toggle:after {\n  display: none;\n}\n.header .top-navbar .navbar-header {\n  line-height: 45px;\n  text-align: center;\n  background: #000;\n}\n.header .top-navbar .navbar-header .navbar-brand {\n  margin-right: 0;\n  padding-bottom: 0;\n  padding-top: 0;\n}\n.header .top-navbar .navbar-header .navbar-brand .light-logo {\n  display: none;\n}\n.header .top-navbar .navbar-header .navbar-brand b {\n  line-height: 60px;\n  display: inline-block;\n}\n.header .top-navbar .navbar-nav > .nav-item > .nav-link {\n  padding-left: 0.75rem;\n  padding-right: 0.75rem;\n  font-size: 15px;\n  line-height: 40px;\n}\n.header .top-navbar .navbar-nav > .nav-item.show {\n  background: rgba(0, 0, 0, 0.05);\n}\n.header .top-navbar .mailbox {\n  width: 300px;\n}\n.header .top-navbar .mailbox ul {\n  padding: 0;\n}\n.header .top-navbar .mailbox ul li {\n  list-style: none;\n}\n.header .profile-pic {\n  width: 30px;\n  border-radius: 100%;\n}\n.header .dropdown-menu {\n  box-shadow: 0 3px 12px rgba(0, 0, 0, 0.05);\n  -webkit-box-shadow: 0 3px 12px rgba(0, 0, 0, 0.05);\n  -moz-box-shadow: 0 3px 12px rgba(0, 0, 0, 0.05);\n  border-color: rgba(120, 130, 140, 0.13);\n}\n.header .dropdown-menu .dropdown-item {\n  padding: 7px 1.5rem;\n}\n.header ul.dropdown-user {\n  padding: 0;\n  min-width: 175px;\n}\n.header ul.dropdown-user li {\n  list-style: none;\n  padding: 0;\n  margin: 0;\n}\n.header ul.dropdown-user li .dw-user-box {\n  padding: 10px 15px;\n}\n.header ul.dropdown-user li .dw-user-box .u-img {\n  width: 70px;\n  display: inline-block;\n  vertical-align: top;\n}\n.header ul.dropdown-user li .dw-user-box .u-img img {\n  width: 100%;\n  border-radius: 5px;\n}\n.header ul.dropdown-user li .dw-user-box .u-text {\n  display: inline-block;\n  padding-left: 10px;\n}\n.header ul.dropdown-user li .dw-user-box .u-text h4 {\n  margin: 0;\n  font-size: 15px;\n}\n.header ul.dropdown-user li .dw-user-box .u-text p {\n  margin-bottom: 2px;\n  font-size: 12px;\n}\n.header ul.dropdown-user li .dw-user-box .u-text .btn {\n  color: #ffffff;\n  padding: 5px 10px;\n  display: inline-block;\n}\n.header ul.dropdown-user li .dw-user-box .u-text .btn:hover {\n  background: #e6294b;\n}\n.header ul.dropdown-user li a {\n  padding: 9px 15px;\n  display: block;\n  color: #67757c;\n}\n.header ul.dropdown-user li a:hover {\n  background: #f2f4f8;\n  color: #1976d2;\n  text-decoration: none;\n}\n.header ul.dropdown-user li.divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: rgba(120, 130, 140, 0.13);\n}\n.search-box .app-search {\n  position: absolute;\n  margin: 0;\n  display: block;\n  z-index: 110;\n  width: 100%;\n  top: -1px;\n  -webkit-box-shadow: 2px 0 10px rgba(0, 0, 0, 0.2);\n  box-shadow: 2px 0 10px rgba(0, 0, 0, 0.2);\n  display: none;\n  left: 0;\n}\n.search-box .app-search input {\n  width: 100.5%;\n  padding: 20px 40px 20px 20px;\n  border-radius: 0;\n  font-size: 17px;\n  height: 70px;\n  -webkit-transition: 0.5s ease-in;\n  -o-transition: 0.5s ease-in;\n  transition: 0.5s ease-in;\n}\n.search-box .app-search input:focus {\n  border-color: #ffffff;\n}\n.search-box .app-search .srh-btn {\n  position: absolute;\n  top: 23px;\n  cursor: pointer;\n  background: #ffffff;\n  width: 15px;\n  height: 15px;\n  right: 20px;\n  font-size: 14px;\n}\n.mini-sidebar .top-navbar .navbar-header {\n  width: 60px;\n  text-align: center;\n}\n.logo-center .top-navbar .navbar-header {\n  position: absolute;\n  left: 0;\n  right: 0;\n  margin: 0 auto;\n}\n.notify {\n  position: relative;\n  top: -22px;\n  right: -9px;\n}\n.notify .heartbit {\n  position: absolute;\n  top: -20px;\n  right: -4px;\n  height: 25px;\n  width: 25px;\n  z-index: 10;\n  border: 5px solid #ef5350;\n  border-radius: 70px;\n  -moz-animation: heartbit 1s ease-out;\n  -moz-animation-iteration-count: infinite;\n  -o-animation: heartbit 1s ease-out;\n  -o-animation-iteration-count: infinite;\n  -webkit-animation: heartbit 1s ease-out;\n  -webkit-animation-iteration-count: infinite;\n  animation-iteration-count: infinite;\n}\n.notify .point {\n  width: 6px;\n  height: 6px;\n  -webkit-border-radius: 30px;\n  -moz-border-radius: 30px;\n  border-radius: 30px;\n  background-color: #ef5350;\n  position: absolute;\n  right: 6px;\n  top: -10px;\n}\n.fileupload {\n  overflow: hidden;\n  position: relative;\n}\n.fileupload input.upload {\n  cursor: pointer;\n  filter: alpha(opacity=0);\n  font-size: 20px;\n  margin: 0;\n  opacity: 0;\n  padding: 0;\n  position: absolute;\n  right: 0;\n  top: 0;\n}\n.mega-dropdown {\n  position: static;\n  width: 100%;\n}\n.mega-dropdown .dropdown-menu {\n  width: 100%;\n  padding: 30px;\n  margin-top: 0;\n}\n.mega-dropdown ul {\n  padding: 0;\n}\n.mega-dropdown ul li {\n  list-style: none;\n}\n.mega-dropdown .carousel-item .container {\n  padding: 0;\n}\n.mega-dropdown .nav-accordion .card {\n  margin-bottom: 1px;\n}\n.mega-dropdown .nav-accordion .card-header {\n  background: #ffffff;\n}\n.mega-dropdown .nav-accordion .card-header h5 {\n  margin: 0;\n}\n.mega-dropdown .nav-accordion .card-header h5 a {\n  text-decoration: none;\n  color: #67757c;\n}\nul.list-style-none {\n  margin: 0;\n  padding: 0;\n}\nul.list-style-none li {\n  list-style: none;\n}\nul.list-style-none li a {\n  color: #67757c;\n  padding: 8px 0;\n  display: block;\n  text-decoration: none;\n}\nul.list-style-none li a:hover {\n  color: #1976d2;\n}\n.dropdown-item {\n  padding: 8px 1rem;\n  color: #67757c;\n}\n.custom-select {\n  background: url(\"../../assets/images/custom-select.png\") right 0.75rem center no-repeat;\n}\ntextarea {\n  resize: none;\n}\n.mailbox ul li .drop-title {\n  font-weight: 500;\n  padding: 11px 20px 15px;\n  border-bottom: 1px solid rgba(120, 130, 140, 0.13);\n}\n.mailbox ul li .nav-link {\n  border-top: 1px solid rgba(120, 130, 140, 0.13);\n  padding-top: 15px;\n}\n.mailbox .message-center {\n  height: 200px;\n  overflow: auto;\n  position: relative;\n}\n.mailbox .message-center a {\n  border-bottom: 1px solid rgba(120, 130, 140, 0.13);\n  display: block;\n  text-decoration: none;\n  padding: 9px 15px;\n}\n.mailbox .message-center a:hover {\n  background: #f2f4f8;\n}\n.mailbox .message-center a div {\n  white-space: normal;\n}\n.mailbox .message-center a .user-img {\n  width: 40px;\n  position: relative;\n  display: inline-block;\n  margin: 0 10px 15px 0;\n}\n.mailbox .message-center a .user-img img {\n  width: 100%;\n}\n.mailbox .message-center a .user-img .profile-status {\n  border: 2px solid #ffffff;\n  border-radius: 50%;\n  display: inline-block;\n  height: 10px;\n  left: 30px;\n  position: absolute;\n  top: 1px;\n  width: 10px;\n}\n.mailbox .message-center a .user-img .online {\n  background: #26dad2;\n}\n.mailbox .message-center a .user-img .busy {\n  background: #ef5350;\n}\n.mailbox .message-center a .user-img .away {\n  background: #ffb22b;\n}\n.mailbox .message-center a .user-img .offline {\n  background: #ffb22b;\n}\n.mailbox .message-center a .mail-contnet {\n  display: inline-block;\n  width: 75%;\n  vertical-align: middle;\n}\n.mailbox .message-center a .mail-contnet h5 {\n  margin: 5px 0 0;\n}\n.mailbox .message-center a .mail-contnet .mail-desc {\n  font-size: 12px;\n  display: block;\n  margin: 1px 0;\n  -o-text-overflow: ellipsis;\n  text-overflow: ellipsis;\n  overflow: hidden;\n  color: #67757c;\n  /* white-space: nowrap; */\n}\n.mailbox .message-center a .mail-contnet .time {\n  font-size: 12px;\n  display: block;\n  margin: 1px 0;\n  -o-text-overflow: ellipsis;\n  text-overflow: ellipsis;\n  overflow: hidden;\n  color: #67757c;\n  white-space: nowrap;\n}\n@media (min-width: 768px) {\n  .navbar-header {\n    width: 240px;\n    -webkit-flex-shrink: 0;\n    -ms-flex-negative: 0;\n    flex-shrink: 0;\n  }\n  .navbar-header .navbar-brand {\n    padding-top: 0;\n  }\n  .page-titles .breadcrumb {\n    float: right;\n  }\n  .card-group .card:first-child {\n    border-right: 1px solid rgba(0, 0, 0, 0.03);\n  }\n  .card-group .card:not(:first-child):not(:last-child) {\n    border-right: 1px solid rgba(0, 0, 0, 0.03);\n  }\n  .material-icon-list-demo .icons div {\n    width: 33%;\n    padding: 15px;\n    display: inline-block;\n    line-height: 40px;\n  }\n  .mini-sidebar .page-wrapper {\n    margin-left: 60px;\n  }\n  .mini-sidebar .footer {\n    left: 60px;\n  }\n  .flex-wrap {\n    -ms-flex-wrap: nowrap !important;\n    flex-wrap: nowrap !important;\n    -webkit-flex-wrap: nowrap !important;\n  }\n}\n@media (max-width: 767px) {\n  .header {\n    position: fixed;\n    width: 100%;\n  }\n  .header .top-navbar {\n    padding-right: 15px;\n    -webkit-box-orient: horizontal;\n    -webkit-box-direction: normal;\n    -webkit-flex-direction: row;\n    -ms-flex-direction: row;\n    flex-direction: row;\n    -webkit-flex-wrap: nowrap;\n    -ms-flex-wrap: nowrap;\n    flex-wrap: nowrap;\n    -webkit-align-items: center;\n  }\n  .header .top-navbar .navbar-collapse {\n    display: -webkit-box;\n    display: -webkit-flex;\n    display: -ms-flexbox;\n    display: flex;\n    width: 100%;\n  }\n  .header .top-navbar .navbar-nav {\n    -webkit-box-orient: horizontal;\n    -webkit-box-direction: normal;\n    -webkit-flex-direction: row;\n    -ms-flex-direction: row;\n    flex-direction: row;\n  }\n  .header .top-navbar .navbar-nav > .nav-item.show {\n    position: static;\n  }\n  .header .top-navbar .navbar-nav > .nav-item.show .dropdown-menu {\n    width: 100%;\n    margin-top: 0;\n  }\n  .header .top-navbar .navbar-nav > .nav-item > .nav-link {\n    padding-left: 0.50rem;\n    padding-right: 0.50rem;\n  }\n  .header .top-navbar .navbar-nav .dropdown-menu {\n    position: absolute;\n  }\n  .mega-dropdown .dropdown-menu {\n    height: 480px;\n    overflow: auto;\n  }\n  .mini-sidebar .page-wrapper {\n    margin-left: 0;\n    padding-top: 60px;\n  }\n}\n.left-sidebar {\n  position: absolute;\n  width: 240px;\n  height: 100%;\n  top: 8px;\n  z-index: 20;\n  padding-top: 60px;\n  background: #fff;\n  -webkit-box-shadow: 1px 0 20px rgba(0, 0, 0, 0.08);\n  box-shadow: 1px 0 20px rgba(0, 0, 0, 0.08);\n}\n.fix-sidebar .left-sidebar {\n  position: fixed;\n  background-color: #1976d2;\n}\n.sidebar-footer {\n  position: fixed;\n  z-index: 10;\n  bottom: 0;\n  left: 0;\n  -webkit-transition: 0.2s ease-out;\n  -o-transition: 0.2s ease-out;\n  transition: 0.2s ease-out;\n  width: 240px;\n  background: #fff;\n  border-top: 1px solid rgba(120, 130, 140, 0.13);\n}\n.sidebar-footer a {\n  padding: 15px;\n  width: 33.333337%;\n  float: left;\n  text-align: center;\n  font-size: 18px;\n}\n.scroll-sidebar {\n  padding-bottom: 60px;\n}\n.collapse.in {\n  display: block;\n}\n.sidebar-nav {\n  background: #fff;\n  padding: 0;\n}\n.sidebar-nav ul {\n  margin: 0;\n  padding: 0;\n  background-color: #1976d2;\n}\n.sidebar-nav ul li {\n  list-style: none;\n}\n.sidebar-nav ul li a {\n  color: #fff;\n  padding: 7px 35px 7px 15px;\n  display: block;\n  font-size: 14px;\n  white-space: nowrap;\n  background-color: #1976d2;\n}\n.sidebar-nav ul li a:hover {\n  color: white;\n  background-color: rgba(44,42,165,0.26) !important;\n}\n.sidebar-nav ul li a:hover i {\n  color: #fff;\n}\n/* .sidebar-nav ul li a.active {\n  color: #1976d2;\n  font-weight: 500;\n} */\n.sidebar-nav ul li a.active {\n  color: white;\n  background-color: rgba(44,42,165,0.26) !important;\n}\n.sidebar-nav ul li a.active i {\n  color: #1976d2;\n}\n.sidebar-nav ul li ul {\n  padding-left: 28px;\n}\n.sidebar-nav ul li ul li a {\n  padding: 7px 35px 7px 15px;\n}\n.sidebar-nav ul li ul ul {\n  padding-left: 15px;\n}\n.sidebar-nav ul li.nav-label {\n  font-size: 12px;\n  margin-bottom: 0;\n  /* padding: 14px 14px 14px 20px; */\n  padding: 0 8px;\n  color: #fff;\n  font-weight: 600;\n  text-transform: uppercase;\n}\n.sidebar-nav ul li.nav-devider {\n  height: 1px;\n  background: rgba(120, 130, 140, 0.13);\n  display: block;\n}\n.sidebar-nav > ul > li {\n  margin-bottom: 5px;\n}\n.sidebar-nav > ul > li > a {\n  border-left: 3px solid transparent;\n  /* padding: 0 16px; */\n}\n.sidebar-nav > ul > li > a i {\n  width: 27px;\n  font-size: 16px;\n  display: inline-block;\n  vertical-align: middle;\n  color: #fff;\n}\n.sidebar-nav > ul > li > a .label {\n  position: absolute;\n  right: 35px;\n  top: 8px;\n}\n.sidebar-nav > ul > li > a.active {\n  font-weight: 400;\n  background: #fff;\n  color: #1976d2;\n}\n.sidebar-nav > ul > li.active > a {\n  color: #fff;\n  font-weight: 500;\n  border-left: 3px solid #1976d2;\n}\n.sidebar-nav > ul > li.active > a i {\n  color: #fff;\n}\n.sidebar-nav .has-arrow {\n  position: relative;\n}\n.sidebar-nav .has-arrow:after {\n  position: absolute;\n  content: '';\n  width: 7px;\n  height: 7px;\n  border-width: 1px 0 0 1px;\n  border-style: solid;\n  border-color: #fff;\n  right: 1em;\n  -webkit-transform: rotate(135deg) translate(0, -50%);\n  -ms-transform: rotate(135deg) translate(0, -50%);\n  -o-transform: rotate(135deg) translate(0, -50%);\n  transform: rotate(135deg) translate(0, -50%);\n  -webkit-transform-origin: top;\n  -ms-transform-origin: top;\n  -o-transform-origin: top;\n  transform-origin: top;\n  top: 47%;\n  -webkit-transition: all 0.3s ease-out;\n  -o-transition: all 0.3s ease-out;\n  transition: all 0.3s ease-out;\n}\n.sidebar-nav .active > .has-arrow:after {\n  -webkit-transform: rotate(-135deg) translate(0, -50%);\n  -ms-transform: rotate(-135deg) translate(0, -50%);\n  -o-transform: rotate(-135deg) translate(0, -50%);\n  top: 45%;\n  width: 7px;\n  transform: rotate(-135deg) translate(0, -50%);\n}\n.sidebar-nav .has-arrow[aria-expanded=true]:after {\n  -webkit-transform: rotate(-135deg) translate(0, -50%);\n  -ms-transform: rotate(-135deg) translate(0, -50%);\n  -o-transform: rotate(-135deg) translate(0, -50%);\n  top: 45%;\n  width: 7px;\n  transform: rotate(-135deg) translate(0, -50%);\n}\n.sidebar-nav li > .has-arrow.active:after {\n  -webkit-transform: rotate(-135deg) translate(0, -50%);\n  -ms-transform: rotate(-135deg) translate(0, -50%);\n  -o-transform: rotate(-135deg) translate(0, -50%);\n  top: 45%;\n  width: 7px;\n  transform: rotate(-135deg) translate(0, -50%);\n}\n@media (min-width: 768px) {\n  .mini-sidebar .sidebar-nav {\n    background: transparent;\n  }\n  .mini-sidebar .sidebar-nav #sidebarnav li {\n    position: relative;\n  }\n  .mini-sidebar .sidebar-nav #sidebarnav > li > ul {\n    position: absolute;\n    left: 60px;\n    top: 38px;\n    width: 200px;\n    z-index: 1001;\n    background: #f2f6f8;\n    display: none;\n    padding-left: 1px;\n  }\n  .mini-sidebar .sidebar-nav #sidebarnav > li:hover > ul {\n    height: auto !important;\n    overflow: auto;\n    display: block;\n  }\n  .mini-sidebar .sidebar-nav #sidebarnav > li:hover > ul.collapse {\n    display: block;\n  }\n  /* .mini-sidebar .sidebar-nav #sidebarnav > li:hover > a {\n    width: 0px;\n    background: #f2f6f8;\n     background:#1976d2;\n    display: inline;\n  }\n  .mini-sidebar .sidebar-nav #sidebarnav > li:hover > a .hide-menu {\n    display: inline;\n  } */\n  .mini-sidebar .sidebar-nav #sidebarnav > li:hover > a .label {\n    display: none;\n  }\n  .mini-sidebar .sidebar-nav #sidebarnav > li > a.has-arrow:after {\n    display: none;\n  }\n  .mini-sidebar .sidebar-nav #sidebarnav > li > a {\n    padding: 9px 18px;\n    width: 50px;\n  }\n  .mini-sidebar .user-profile {\n    padding-bottom: 15px;\n    width: 60px;\n    margin-bottom: 7px;\n  }\n  .mini-sidebar .user-profile .profile-img {\n    width: 50px;\n    padding: 15px 0 0;\n    margin: 0 0 0 6px;\n  }\n  .mini-sidebar .user-profile .profile-img .setpos {\n    top: -35px;\n  }\n  .mini-sidebar .user-profile .profile-img:before {\n    top: 15px;\n  }\n  .mini-sidebar .user-profile .profile-text {\n    display: none;\n  }\n  .mini-sidebar .left-sidebar {\n    width: 60px;\n  }\n  .mini-sidebar .scroll-sidebar {\n    padding-bottom: 0;\n    position: absolute;\n    overflow-x: hidden !important;\n  }\n  .mini-sidebar .hide-menu {\n    display: none;\n  }\n  .mini-sidebar .nav-label {\n    display: none;\n  }\n  .mini-sidebar .sidebar-footer {\n    display: none;\n  }\n  .mini-sidebar > .label {\n    display: none;\n  }\n  .mini-sidebar .nav-devider {\n    width: 60px;\n  }\n  .mini-sidebar.fix-sidebar .left-sidebar {\n    position: fixed;\n  }\n}\n@media (max-width: 767px) {\n  .mini-sidebar .left-sidebar {\n    position: fixed;\n    left: -240px;\n  }\n  .mini-sidebar .sidebar-footer {\n    left: -240px;\n  }\n  .mini-sidebar.show-sidebar .left-sidebar {\n    left: 0;\n  }\n  .mini-sidebar.show-sidebar .sidebar-footer {\n    left: 0;\n  }\n}\n.badge {\n  font-weight: 400;\n}\n.badge-xs {\n  font-size: 9px;\n  -webkit-transform: translate(0, -2px);\n  -ms-transform: translate(0, -2px);\n  -o-transform: translate(0, -2px);\n  transform: translate(0, -2px);\n}\n.badge-sm {\n  -webkit-transform: translate(0, -2px);\n  -ms-transform: translate(0, -2px);\n  -o-transform: translate(0, -2px);\n  transform: translate(0, -2px);\n}\n.badge-success {\n  background-color: #26dad2;\n}\n.badge-info {\n  background-color: #1976d2;\n}\n.badge-primary {\n  background-color: #5c4ac7;\n}\n.badge-warning {\n  background-color: #ffb22b;\n}\n.badge-danger {\n  background-color: #ef5350;\n}\n.badge-purple {\n  background-color: #7460ee;\n}\n.badge-red {\n  background-color: #fb3a3a;\n}\n.badge-inverse {\n  background-color: #2f3d4a;\n}\n.label {\n  padding: 3px 10px;\n  line-height: 13px;\n  color: #ffffff;\n  font-weight: 400;\n  border-radius: 4px;\n  font-size: 75%;\n}\n.label-rounded {\n  border-radius: 60px;\n}\n.label-custom {\n  background-color: #00897b;\n}\n.label-success {\n  background-color: #26dad2;\n}\n.label-info {\n  background-color: #1976d2;\n}\n.label-warning {\n  background-color: #ffb22b;\n}\n.label-danger {\n  background-color: #ef5350;\n}\n.label-megna {\n  background-color: #00897b;\n}\n.label-primary {\n  background-color: #5c4ac7;\n}\n.label-purple {\n  background-color: #7460ee;\n}\n.label-red {\n  background-color: #fb3a3a;\n}\n.label-inverse {\n  background-color: #2f3d4a;\n}\n.label-default {\n  background-color: #f2f4f8;\n}\n.label-white {\n  background-color: #ffffff;\n}\n.label-light-success {\n  background-color: #e8fdeb;\n  color: #26dad2;\n}\n.label-light-info {\n  background-color: #cfecfe;\n  color: #1976d2;\n}\n.label-light-warning {\n  background-color: #fff8ec;\n  color: #ffb22b;\n}\n.label-light-danger {\n  background-color: #f9e7eb;\n  color: #ef5350;\n}\n.label-light-megna {\n  background-color: #e0f2f4;\n  color: #00897b;\n}\n.label-light-primary {\n  background-color: #f1effd;\n  color: #5c4ac7;\n}\n.label-light-inverse {\n  background-color: #f6f6f6;\n  color: #2f3d4a;\n}\n.breadcrumb {\n  margin-bottom: 0;\n}\n.page-titles {\n  background: #ffffff;\n  margin: 0 0 0px; /*margin: 0 0 30px;*/\n  padding: 15px 10px;\n  position: relative;\n  z-index: 10;\n  -webkit-box-shadow: 1px 0 5px rgba(0, 0, 0, 0.1);\n  box-shadow: 1px 0 5px rgba(0, 0, 0, 0.1);\n}\n.page-titles h3 {\n  margin-bottom: 0;\n  margin-top: 0;\n}\n.page-titles .breadcrumb {\n  padding: 0;\n  background: transparent;\n  font-size: 14px;\n}\n.page-titles .breadcrumb li {\n  margin-top: 0;\n  margin-bottom: 0;\n}\n.page-titles .breadcrumb .breadcrumb-item + .breadcrumb-item:before {\n  content: \"\\e649\";\n  font-family: themify;\n  color: #a6b7bf;\n  font-size: 11px;\n}\n.page-titles .breadcrumb .breadcrumb-item.active {\n  color: #99abb4;\n}\n\n.pager li > a {\n  -moz-border-radius: 4px;\n  -webkit-border-radius: 4px;\n  border-radius: 4px;\n  color: #263238;\n}\n.pager li > span {\n  -moz-border-radius: 4px;\n  -webkit-border-radius: 4px;\n  border-radius: 4px;\n  color: #263238;\n}\n.footer {\n  background: #ffffff none repeat scroll 0 0;\n  border-top: 1px solid rgba(120, 130, 140, 0.13);\n  color: #67757c;\n  left: 0;\n  padding: 17px 15px;\n  position: absolute;\n  right: 0;\n}\n.footer {\n  left: 240px;\n}\n#chartdiv3 {\n  height: 450px;\n  width: 100%;\n}\n#chartdiv {\n  height: 450px;\n  width: 100%;\n}\n#zoomable {\n  height: 450px;\n  width: 100%;\n}\n#chartMap {\n  height: 450px;\n  width: 100%;\n}\n.amcharts-graph-g2 .amcharts-graph-stroke {\n  stroke-dasharray: 3px 3px;\n  stroke-linejoin: round;\n  stroke-linecap: round;\n  -webkit-animation: am-moving-dashes 1s linear infinite;\n  animation: am-moving-dashes 1s linear infinite;\n}\n@-webkit-keyframes am-moving-dashes {\n  100% {\n    stroke-dashoffset: -31px;\n  }\n}\n@keyframes am-moving-dashes {\n  100% {\n    stroke-dashoffset: -31px;\n  }\n}\n.lastBullet {\n  -webkit-animation: am-pulsating 1s ease-out infinite;\n  animation: am-pulsating 1s ease-out infinite;\n}\n@-webkit-keyframes am-pulsating {\n  0% {\n    stroke-opacity: 1;\n    stroke-width: 0px;\n  }\n  100% {\n    stroke-opacity: 0;\n    stroke-width: 50px;\n  }\n}\n@keyframes am-pulsating {\n  0% {\n    stroke-opacity: 1;\n    stroke-width: 0px;\n  }\n  100% {\n    stroke-opacity: 0;\n    stroke-width: 50px;\n  }\n}\n.amcharts-graph-column-front {\n  -webkit-transition: all 0.3s 0.3s ease-out;\n  transition: all 0.3s 0.3s ease-out;\n}\n.amcharts-graph-column-front:hover {\n  fill: #496375;\n  stroke: #496375;\n  -webkit-transition: all 0.3s ease-out;\n  transition: all 0.3s ease-out;\n}\n.amcharts-graph-g3 {\n  stroke-linejoin: round;\n  stroke-linecap: round;\n  stroke-dasharray: 500%;\n  stroke-dasharray: 0 /;\n  /* fixes IE prob */\n  stroke-dashoffset: 0 /;\n  /* fixes IE prob */\n  -webkit-animation: am-draw 40s;\n  animation: am-draw 40s;\n}\n@-webkit-keyframes am-draw {\n  0% {\n    stroke-dashoffset: 500%;\n  }\n  100% {\n    stroke-dashoffset: 0%;\n  }\n}\n@keyframes am-draw {\n  0% {\n    stroke-dashoffset: 500%;\n  }\n  100% {\n    stroke-dashoffset: 0%;\n  }\n}\n/*    Font Variable\n----------------------*/\n/*    Color Variable\n-----------------------*/\n/*    Solid Color\n------------------*/\n/*    Brand color\n----------------------*/\n.card {\n  margin-bottom: 30px;\n}\n.card .card-subtitle {\n  color: #99abb4;\n  font-weight: 300;\n  margin-bottom: 15px;\n}\n.card-inverse .card-bodyquote .blockquote-footer {\n  color: rgba(255, 255, 255, 0.65);\n}\n.card-inverse .card-link {\n  color: rgba(255, 255, 255, 0.65);\n}\n.card-inverse .card-subtitle {\n  color: rgba(255, 255, 255, 0.65);\n}\n.card-inverse .card-text {\n  color: rgba(255, 255, 255, 0.65);\n}\n.card-success {\n  background: #26dad2 none repeat scroll 0 0;\n  border-color: #26dad2;\n}\n.card-danger {\n  background: #ef5350 none repeat scroll 0 0;\n  border-color: #ef5350;\n}\n.card-warning {\n  background: #ffb22b none repeat scroll 0 0;\n  border-color: #ffb22b;\n}\n.card-info {\n  background: #1976d2 none repeat scroll 0 0;\n  border-color: #1976d2;\n}\n.card-primary {\n  background: #5c4ac7 none repeat scroll 0 0;\n  border-color: #5c4ac7;\n}\n.card-dark {\n  background: #2f3d4a none repeat scroll 0 0;\n  border-color: #2f3d4a;\n}\n.card-megna {\n  background: #00897b none repeat scroll 0 0;\n  border-color: #00897b;\n}\n.card-actions {\n  float: right;\n}\n.card-actions a {\n  color: #67757c;\n  cursor: pointer;\n  font-size: 13px;\n  opacity: 0.7;\n  padding-left: 7px;\n}\n.card-actions a:hover {\n  opacity: 1;\n}\n.card-columns .card {\n  margin-bottom: 20px;\n}\n.collapsing {\n  transition: height 0.08s ease 0s;\n}\n.card-outline-info {\n  border-color: #1976d2;\n}\n.card-outline-info .card-header {\n  background: #1976d2 none repeat scroll 0 0;\n  border-color: #1976d2;\n}\n.card-outline-inverse {\n  border-color: #2f3d4a;\n}\n.card-outline-inverse .card-header {\n  background: #2f3d4a none repeat scroll 0 0;\n  border-color: #2f3d4a;\n}\n.card-outline-warning {\n  border-color: #ffb22b;\n}\n.card-outline-warning .card-header {\n  background: #ffb22b none repeat scroll 0 0;\n  border-color: #ffb22b;\n}\n.card-outline-success {\n  border-color: #26dad2;\n}\n.card-outline-success .card-header {\n  background: #26dad2 none repeat scroll 0 0;\n  border-color: #26dad2;\n}\n.card-outline-danger {\n  border-color: #ef5350;\n}\n.card-outline-danger .card-header {\n  background: #ef5350 none repeat scroll 0 0;\n  border-color: #ef5350;\n}\n.card-outline-primary {\n  border-color: #5c4ac7;\n}\n.card-outline-primary .card-header {\n  background: #5c4ac7 none repeat scroll 0 0;\n  border-color: #5c4ac7;\n}\n.card-body {\n  padding: 0;\n}\n.card {\n  background: #ffffff none repeat scroll 0 0;\n  margin: 15px 0;\n  padding: 20px;\n  border: 0 solid #e7e7e7;\n  border-radius: 5px;\n  box-shadow: 0 5px 20px rgba(0, 0, 0, 0.05);\n}\n.card-subtitle {\n  font-size: 12px;\n  margin: 10px 0;\n}\n.card-title {\n  font-weight: 550;\n  font-size: 18px;\n  line-height: 22px;\n  color: rgb(51,51,51);\n}\n.card-title h4 {\n  display: inline-block;\n  font-weight: 550;\n  font-size: 18px;\n  line-height: 22px;\n  color: rgb(51,51,51);\n}\n.card-title p {\n  font-family: 'Poppins', sans-serif;\n  margin-bottom: 12px;\n}\n.vtabs {\n  display: table;\n}\n.vtabs .tabs-vertical {\n  border-bottom: 0 none;\n  border-right: 1px solid rgba(120, 130, 140, 0.13);\n  display: table-cell;\n  vertical-align: top;\n  width: 150px;\n}\n.vtabs .tabs-vertical li .nav-link {\n  border: 0 none;\n  border-radius: 4px 0 0 4px;\n  color: #263238;\n  margin-bottom: 10px;\n}\n.vtabs .tab-content {\n  display: table-cell;\n  padding: 20px;\n  vertical-align: top;\n}\n.tabs-vertical li .nav-link.active,\n.tabs-vertical li .nav-link.active:focus,\n.tabs-vertical li .nav-link:hover {\n  background: #1976d2 none repeat scroll 0 0;\n  border: 0 none;\n  color: #ffffff;\n}\n.customvtab .tabs-vertical li .nav-link.active,\n.customvtab .tabs-vertical li .nav-link:focus,\n.customvtab .tabs-vertical li .nav-link:hover {\n  -moz-border-bottom-colors: none;\n  -moz-border-left-colors: none;\n  -moz-border-right-colors: none;\n  -moz-border-top-colors: none;\n  background: #ffffff none repeat scroll 0 0;\n  border-color: currentcolor #1976d2 currentcolor currentcolor;\n  border-image: none;\n  border-style: none solid none none;\n  border-width: 0 2px 0 0;\n  color: #1976d2;\n  margin-right: -1px;\n}\n.tabcontent-border {\n  -moz-border-bottom-colors: none;\n  -moz-border-left-colors: none;\n  -moz-border-right-colors: none;\n  -moz-border-top-colors: none;\n  border-color: currentcolor #ddd #ddd;\n  border-image: none;\n  border-style: none solid solid;\n  border-width: 0 1px 1px;\n}\n.customtab2 li a.nav-link {\n  border: 0 none;\n  color: #67757c;\n  margin-right: 3px;\n}\n.customtab2 li a.nav-link.active {\n  background: #1976d2 none repeat scroll 0 0;\n  color: #ffffff;\n}\n.customtab2 li a.nav-link:hover {\n  background: #1976d2 none repeat scroll 0 0;\n  color: #ffffff;\n}\n.modal-dialog {\n  margin: 30px auto;\n  position: relative;\n  top: 50%;\n  transform: translateY(-50%) !important;\n  width: 70%;\n}\n.modal-header .close {\n  font-size: 14px;\n  margin-right: 15px;\n  margin-top: 5px;\n}\n.modal-content {\n  border-radius: 3px;\n}\n.timeline {\n  list-style: none;\n  padding: 0 0 8px;\n  position: relative;\n}\n.timeline:before {\n  top: 7px;\n  bottom: 0;\n  position: absolute;\n  content: \" \";\n  width: 3px;\n  background-color: #e7e7e7;\n  left: 25px;\n  margin-right: -1.5px;\n}\n.timeline-title {\n  margin: 5px 0 !important;\n  font-size: 16px;\n}\n.timeline > li {\n  margin-bottom: 20px;\n  position: relative;\n}\n.timeline > li:after,\n.timeline > li:before {\n  content: \" \";\n  display: table;\n}\n.timeline > li:after {\n  clear: both;\n}\n.timeline > li > .timeline-panel {\n  width: calc(100% - 70px);\n  float: right;\n  border-radius: 2px;\n  padding: 5px 20px;\n  position: relative;\n}\n.timeline > li > .timeline-panel:before {\n  position: absolute;\n  top: 26px;\n  left: -15px;\n  display: inline-block;\n  border-top: 0 solid transparent;\n  border-right: 0 solid #e7e7e7;\n  border-left: 0 solid #e7e7e7;\n  border-bottom: 15px solid transparent;\n  content: \" \";\n}\n.timeline > li > .timeline-panel:after {\n  position: absolute;\n  top: 27px;\n  left: -14px;\n  display: inline-block;\n  border-top: 14px solid transparent;\n  border-right: 14px solid #ffffff;\n  border-left: 0 solid #ffffff;\n  border-bottom: 14px solid transparent;\n  content: \" \";\n}\n.timeline > li > .timeline-badge {\n  color: #ffffff;\n  width: 35px;\n  height: 35px;\n  line-height: 35px;\n  font-size: 1.4em;\n  text-align: center;\n  position: absolute;\n  top: 10px;\n  left: 8px;\n  margin-right: -25px;\n  background-color: #e6a1f2;\n  z-index: 100;\n  border-top-right-radius: 50%;\n  border-top-left-radius: 50%;\n  border-bottom-right-radius: 50%;\n  border-bottom-left-radius: 50%;\n}\n.timeline-body > p {\n  font-size: 12px;\n  margin-bottom: 10px;\n}\n.timeline-badge.primary {\n  background-color: #4680ff !important;\n}\n.timeline-badge.success {\n  background-color: #26dad2 !important;\n}\n.timeline-badge.warning {\n  background-color: #ffb64d !important;\n}\n.timeline-badge.danger {\n  background-color: #fc6180 !important;\n}\n.timeline-badge.info {\n  background-color: #62d1f3 !important;\n}\n.dataTables_wrapper {\n  padding-top: 10px;\n}\n.dt-buttons {\n  display: inline-block;\n  /* margin-bottom: 5px;\n  padding-top: 5px; */\n}\n.dt-buttons .dt-button {\n  background: #1976d2 none repeat scroll 0 0;\n  border-radius: 4px;\n  color: #ffffff;\n  margin-right: 3px;\n  padding: 5px 15px;\n}\n.dt-buttons .dt-button:hover {\n  background: #2f3d4a none repeat scroll 0 0;\n}\n.dataTables_info,\n.dataTables_length {\n  display: inline-block;\n}\n.dataTables_length {\n  margin-top: 10px;\n}\n.dataTables_length select {\n  background-color: transparent;\n  background-image: linear-gradient(#1976d2, #1976d2), linear-gradient(#b1b8bb, #b1b8bb);\n  background-position: center bottom, center calc(99%);\n  background-repeat: no-repeat;\n  background-size: 0 2px, 100% 1px;\n  border: 0 none;\n  padding-bottom: 5px;\n  transition: background 0s ease-out 0s;\n}\n.dataTables_length select:focus {\n  background-image: linear-gradient(#1976d2, #1976d2), linear-gradient(#b1b8bb, #b1b8bb);\n  background-size: 100% 2px, 100% 1px;\n  box-shadow: none;\n  outline: medium none;\n  transition-duration: 0.3s;\n}\n.dataTables_filter {\n  float: right;\n  /* margin-bottom: 5px;\n  padding-top: 5px; */\n}\n.dataTables_filter input {\n  background-color: transparent;\n  background-image: linear-gradient(#1976d2, #1976d2), linear-gradient(#b1b8bb, #b1b8bb);\n  background-position: center bottom, center calc(99%);\n  background-repeat: no-repeat;\n  background-size: 0 2px, 100% 1px;\n  border: 0 none;\n  border-radius: 0;\n  box-shadow: none;\n  float: none;\n  margin-left: 10px;\n  transition: background 0s ease-out 0s;\n}\n.dataTables_filter input:focus {\n  background-image: linear-gradient(#1976d2, #1976d2), linear-gradient(#b1b8bb, #b1b8bb);\n  background-size: 100% 2px, 100% 1px;\n  box-shadow: none;\n  outline: medium none;\n  transition-duration: 0.3s;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_desc_disabled {\n  background: transparent none repeat scroll 0 0;\n}\ntable.dataTable thead .sorting_asc::after {\n  content: \"\";\n  cursor: pointer;\n  font-family: fontawesome;\n  margin-left: 10px;\n}\ntable.dataTable thead .sorting_desc::after {\n  content: \"\";\n  cursor: pointer;\n  font-family: fontawesome;\n  margin-left: 10px;\n}\ntable.dataTable thead .sorting::after {\n  color: rgba(50, 50, 50, 0.5);\n  content: \"\";\n  cursor: pointer;\n  font-family: fontawesome !important;\n  margin-left: 10px;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  padding-top: 0.25em;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  border: 1px solid #ddd;\n  box-sizing: border-box;\n  color: #67757c;\n  cursor: pointer;\n  display: inline-block;\n  min-width: 1.5em;\n  /* padding: 0.5em 1em; */\n  text-align: center;\n  text-decoration: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current,\n.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  background-color: #1976d2;\n  border: 1px solid #1976d2;\n  color: #ffffff !important;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active,\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover {\n  background: transparent none repeat scroll 0 0;\n  border: 1px solid #ddd;\n  box-shadow: none;\n  color: #67757c;\n  cursor: default;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  /* background-color: #1976d2; */\n  border: 1px solid #1976d2;\n  color: white;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  background-color: #67757c;\n  outline: medium none;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.tablesaw-bar .btn-group label {\n  color: #67757c !important;\n}\n.dt-bootstrap {\n  display: block;\n}\n\n.panel {\n  border-radius: 0;\n  margin: 15px 0;\n}\n.panel-body {\n  font-family: 'Poppins', sans-serif;\n}\n.panel-primary {\n  border-color: #4680ff;\n}\n.panel-primary .panel-heading {\n  background: #4680ff;\n  border-color: #4680ff;\n  color: #ffffff;\n}\n.panel-success {\n  border-color: #26dad2;\n}\n.panel-success .panel-heading {\n  background: #26dad2;\n  border-color: #26dad2;\n  color: #ffffff;\n}\n.panel-info {\n  border-color: #62d1f3;\n}\n.panel-info .panel-heading {\n  background: #62d1f3;\n  border-color: #62d1f3;\n  color: #ffffff;\n}\n.panel-danger {\n  border-color: #fc6180;\n}\n.panel-danger .panel-heading {\n  background: #fc6180;\n  border-color: #fc6180;\n  color: #ffffff;\n}\n.panel-warning {\n  border-color: #ffb64d;\n}\n.panel-warning .panel-heading {\n  background: #ffb64d;\n  border-color: #ffb64d;\n  color: #ffffff;\n}\n.panel-pink {\n  border-color: #e6a1f2;\n}\n.panel-pink .panel-heading {\n  background: #e6a1f2;\n  border-color: #e6a1f2;\n  color: #ffffff;\n}\n.panel-dark {\n  border-color: #444c67;\n}\n.panel-dark .panel-heading {\n  background: #444c67;\n  border-color: #444c67;\n  color: #ffffff;\n}\n.panel-white {\n  border-color: #252525;\n}\n.panel-white .panel-heading {\n  background: #ffffff;\n  border-color: #252525;\n  color: #252525;\n}\n.btn {\n  padding: 7px 12px;\n  cursor: pointer;\n}\n.btn-group label {\n  color: #ffffff !important;\n  margin-bottom: 0;\n}\n.btn-group label.btn-secondary {\n  color: #67757c !important;\n}\n.btn-lg {\n  padding: 0.75rem 1.5rem;\n  font-size: 1.25rem;\n}\n.btn-md {\n  padding: 12px 55px;\n  font-size: 16px;\n}\n.btn-circle {\n  border-radius: 100%;\n  width: 40px;\n  height: 40px;\n  padding: 10px;\n}\n.btn-circle.btn-sm {\n  width: 35px;\n  height: 35px;\n  padding: 8px 10px;\n  font-size: 14px;\n}\n.btn-circle.btn-lg {\n  width: 50px;\n  height: 50px;\n  padding: 14px 15px;\n  font-size: 18px;\n  line-height: 22px;\n}\n.btn-circle.btn-xl {\n  width: 70px;\n  height: 70px;\n  padding: 14px 15px;\n  font-size: 24px;\n}\n.btn-sm {\n  padding: 0.25rem 0.5rem;\n  font-size: 12px;\n}\n.btn-xs {\n  padding: 0.25rem 0.5rem;\n  font-size: 10px;\n}\n.button-list a {\n  margin: 5px 12px 5px 0;\n}\n.button-list button {\n  margin: 5px 12px 5px 0;\n}\n.btn-outline {\n  color: inherit;\n  background-color: transparent;\n  -webkit-transition: all 0.5s;\n  -o-transition: all 0.5s;\n  transition: all 0.5s;\n}\n.btn-rounded {\n  border-radius: 60px;\n  padding: 7px 18px;\n}\n.btn-rounded.btn-lg {\n  padding: 0.75rem 1.5rem;\n}\n.btn-rounded.btn-sm {\n  padding: 0.25rem 0.5rem;\n  font-size: 12px;\n}\n.btn-rounded.btn-xs {\n  padding: 0.25rem 0.5rem;\n  font-size: 10px;\n}\n.btn-rounded.btn-md {\n  padding: 12px 35px;\n  font-size: 16px;\n}\n.btn-secondary {\n  -webkit-box-shadow: 0 2px 2px 0 rgba(169, 169, 169, 0.14), 0 3px 1px -2px rgba(169, 169, 169, 0.2), 0 1px 5px 0 rgba(169, 169, 169, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(169, 169, 169, 0.14), 0 3px 1px -2px rgba(169, 169, 169, 0.2), 0 1px 5px 0 rgba(169, 169, 169, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n  background-color: #ffffff;\n  color: #67757c;\n  border-color: #b1b8bb;\n}\n.btn-secondary:hover {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n}\n.btn-secondary:active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n}\n.btn-secondary:focus {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n}\n.btn-secondary.disabled {\n  -webkit-box-shadow: 0 2px 2px 0 rgba(169, 169, 169, 0.14), 0 3px 1px -2px rgba(169, 169, 169, 0.2), 0 1px 5px 0 rgba(169, 169, 169, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(169, 169, 169, 0.14), 0 3px 1px -2px rgba(169, 169, 169, 0.2), 0 1px 5px 0 rgba(169, 169, 169, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n  background-color: #ffffff;\n  color: #67757c;\n  border-color: #b1b8bb;\n}\n.btn-secondary.disabled:hover {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n}\n.btn-secondary.disabled:active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n}\n.btn-secondary.disabled:focus {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n}\n.btn-secondary.active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n}\n.btn-secondary.disabled.active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n}\n.btn-primary {\n  background: #007bff;\n  border: 1px solid #007bff;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(116, 96, 238, 0.14), 0 3px 1px -2px rgba(116, 96, 238, 0.2), 0 1px 5px 0 rgba(116, 96, 238, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(116, 96, 238, 0.14), 0 3px 1px -2px rgba(116, 96, 238, 0.2), 0 1px 5px 0 rgba(116, 96, 238, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n}\n.btn-primary:hover {\n  background: #007bff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  border: 1px solid #007bff;\n}\n.btn-primary:active {\n  background: #6352ce;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n}\n.btn-primary:active:focus {\n  background-color: #6352ce;\n  border: 1px solid #6352ce;\n}\n.btn-primary:active:hover {\n  background-color: #6352ce;\n  border: 1px solid #6352ce;\n}\n.btn-primary:focus {\n  background: #6352ce;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  background-color: #6352ce;\n  border: 1px solid #6352ce;\n  color: #fff;\n}\n.btn-primary.disabled {\n  background: #5c4ac7;\n  border: 1px solid #5c4ac7;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(116, 96, 238, 0.14), 0 3px 1px -2px rgba(116, 96, 238, 0.2), 0 1px 5px 0 rgba(116, 96, 238, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(116, 96, 238, 0.14), 0 3px 1px -2px rgba(116, 96, 238, 0.2), 0 1px 5px 0 rgba(116, 96, 238, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n}\n.btn-primary.disabled:hover {\n  background: #5c4ac7;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  border: 1px solid #5c4ac7;\n}\n.btn-primary.disabled:active {\n  background: #6352ce;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n}\n.btn-primary.disabled:focus {\n  background: #6352ce;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n}\n.btn-primary.active {\n  background: #6352ce;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n}\n.btn-primary.active:focus {\n  background-color: #6352ce;\n  border: 1px solid #6352ce;\n}\n.btn-primary.active:hover {\n  background-color: #6352ce;\n  border: 1px solid #6352ce;\n}\n.btn-primary.disabled.active {\n  background: #6352ce;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n}\n.btn-themecolor {\n  background: #1976d2;\n  color: #ffffff;\n  border: 1px solid #1976d2;\n}\n.btn-themecolor:hover {\n  background: #1976d2;\n  opacity: 0.7;\n  border: 1px solid #1976d2;\n}\n.btn-themecolor:active {\n  background: #028ee1;\n}\n.btn-themecolor:focus {\n  background: #028ee1;\n}\n.btn-themecolor.disabled {\n  background: #1976d2;\n  color: #ffffff;\n  border: 1px solid #1976d2;\n}\n.btn-themecolor.disabled:hover {\n  background: #1976d2;\n  opacity: 0.7;\n  border: 1px solid #1976d2;\n}\n.btn-themecolor.disabled:active {\n  background: #028ee1;\n}\n.btn-themecolor.disabled:focus {\n  background: #028ee1;\n}\n.btn-themecolor.active {\n  background: #028ee1;\n}\n.btn-themecolor.disabled.active {\n  background: #028ee1;\n}\n.btn-success {\n  background: #26dad2;\n  border: 1px solid #26dad2;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(40, 190, 189, 0.14), 0 3px 1px -2px rgba(40, 190, 189, 0.2), 0 1px 5px 0 rgba(40, 190, 189, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(40, 190, 189, 0.14), 0 3px 1px -2px rgba(40, 190, 189, 0.2), 0 1px 5px 0 rgba(40, 190, 189, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n}\n.btn-success:hover {\n  background: #26dad2;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  border: 1px solid #26dad2;\n}\n.btn-success:active {\n  background: #1eacbe;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n}\n.btn-success:active:focus {\n  background-color: #1eacbe;\n  border: 1px solid #1eacbe;\n}\n.btn-success:active:hover {\n  background-color: #1eacbe;\n  border: 1px solid #1eacbe;\n}\n.btn-success:focus {\n  background: #1eacbe;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  background-color: #1eacbe;\n  border: 1px solid #1eacbe;\n}\n.btn-success.disabled {\n  background: #26dad2;\n  border: 1px solid #26dad2;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(40, 190, 189, 0.14), 0 3px 1px -2px rgba(40, 190, 189, 0.2), 0 1px 5px 0 rgba(40, 190, 189, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(40, 190, 189, 0.14), 0 3px 1px -2px rgba(40, 190, 189, 0.2), 0 1px 5px 0 rgba(40, 190, 189, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n}\n.btn-success.disabled:hover {\n  background: #26dad2;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  border: 1px solid #26dad2;\n}\n.btn-success.disabled:active {\n  background: #1eacbe;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n}\n.btn-success.disabled:focus {\n  background: #1eacbe;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n}\n.btn-success.active {\n  background: #1eacbe;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n}\n.btn-success.active:focus {\n  background-color: #1eacbe;\n  border: 1px solid #1eacbe;\n}\n.btn-success.active:hover {\n  background-color: #1eacbe;\n  border: 1px solid #1eacbe;\n}\n.btn-success.disabled.active {\n  background: #1eacbe;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n}\n.btn-info {\n  background: #1976d2;\n  border: 1px solid #1976d2;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(66, 165, 245, 0.14), 0 3px 1px -2px rgba(66, 165, 245, 0.2), 0 1px 5px 0 rgba(66, 165, 245, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(66, 165, 245, 0.14), 0 3px 1px -2px rgba(66, 165, 245, 0.2), 0 1px 5px 0 rgba(66, 165, 245, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n}\n.btn-info:hover {\n  background: #1976d2;\n  border: 1px solid #1976d2;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n}\n.btn-info:active {\n  background: #028ee1;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n}\n.btn-info:active:focus {\n  background-color: #028ee1;\n  border: 1px solid #028ee1;\n}\n.btn-info:active:hover {\n  background-color: #028ee1;\n  border: 1px solid #028ee1;\n}\n.btn-info:focus {\n  background: #028ee1;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  background-color: #028ee1;\n  border: 1px solid #028ee1;\n}\n.btn-info.disabled {\n  background: #1976d2;\n  border: 1px solid #1976d2;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(66, 165, 245, 0.14), 0 3px 1px -2px rgba(66, 165, 245, 0.2), 0 1px 5px 0 rgba(66, 165, 245, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(66, 165, 245, 0.14), 0 3px 1px -2px rgba(66, 165, 245, 0.2), 0 1px 5px 0 rgba(66, 165, 245, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n}\n.btn-info.disabled:hover {\n  background: #1976d2;\n  border: 1px solid #1976d2;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n}\n.btn-info.disabled:active {\n  background: #028ee1;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n}\n.btn-info.disabled:focus {\n  background: #028ee1;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n}\n.btn-info.active {\n  background: #028ee1;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n}\n.btn-info.active:focus {\n  background-color: #028ee1;\n  border: 1px solid #028ee1;\n}\n.btn-info.active:hover {\n  background-color: #028ee1;\n  border: 1px solid #028ee1;\n}\n.btn-info.disabled.active {\n  background: #028ee1;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n}\n.btn-warning {\n  background: #ffb22b;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(248, 194, 0, 0.14), 0 3px 1px -2px rgba(248, 194, 0, 0.2), 0 1px 5px 0 rgba(248, 194, 0, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(248, 194, 0, 0.14), 0 3px 1px -2px rgba(248, 194, 0, 0.2), 0 1px 5px 0 rgba(248, 194, 0, 0.12);\n  border: 1px solid #ffb22b;\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n  color: #ffffff;\n}\n.btn-warning:hover {\n  background: #ffb22b;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  border: 1px solid #ffb22b;\n}\n.btn-warning:active {\n  background: #e9ab2e;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n}\n.btn-warning:active:focus {\n  background-color: #e9ab2e;\n  border: 1px solid #e9ab2e;\n}\n.btn-warning:active:hover {\n  background-color: #e9ab2e;\n  border: 1px solid #e9ab2e;\n}\n.btn-warning:focus {\n  background: #e9ab2e;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  background-color: #e9ab2e;\n  border: 1px solid #e9ab2e;\n}\n.btn-warning.disabled {\n  background: #ffb22b;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(248, 194, 0, 0.14), 0 3px 1px -2px rgba(248, 194, 0, 0.2), 0 1px 5px 0 rgba(248, 194, 0, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(248, 194, 0, 0.14), 0 3px 1px -2px rgba(248, 194, 0, 0.2), 0 1px 5px 0 rgba(248, 194, 0, 0.12);\n  border: 1px solid #ffb22b;\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n  color: #ffffff;\n}\n.btn-warning.disabled:hover {\n  background: #ffb22b;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  border: 1px solid #ffb22b;\n}\n.btn-warning.disabled:active {\n  background: #e9ab2e;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n}\n.btn-warning.disabled:focus {\n  background: #e9ab2e;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n}\n.btn-warning.active {\n  background: #e9ab2e;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n}\n.btn-warning.active:focus {\n  background-color: #e9ab2e;\n  border: 1px solid #e9ab2e;\n}\n.btn-warning.active:hover {\n  background-color: #e9ab2e;\n  border: 1px solid #e9ab2e;\n}\n.btn-warning.disabled.active {\n  background: #e9ab2e;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n}\n.btn-danger {\n  background: #ef5350;\n  border: 1px solid #ef5350;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(239, 83, 80, 0.14), 0 3px 1px -2px rgba(239, 83, 80, 0.2), 0 1px 5px 0 rgba(239, 83, 80, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(239, 83, 80, 0.14), 0 3px 1px -2px rgba(239, 83, 80, 0.2), 0 1px 5px 0 rgba(239, 83, 80, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n}\n.btn-danger:hover {\n  background: #ef5350;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  border: 1px solid #ef5350;\n}\n.btn-danger:active {\n  background: #e6294b;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n}\n.btn-danger:active:focus {\n  background-color: #e6294b;\n  border: 1px solid #e6294b;\n}\n.btn-danger:active:hover {\n  background-color: #e6294b;\n  border: 1px solid #e6294b;\n}\n.btn-danger:focus {\n  background: #e6294b;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  background-color: #e6294b;\n  border: 1px solid #e6294b;\n}\n.btn-danger.disabled {\n  background: #ef5350;\n  border: 1px solid #ef5350;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(239, 83, 80, 0.14), 0 3px 1px -2px rgba(239, 83, 80, 0.2), 0 1px 5px 0 rgba(239, 83, 80, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(239, 83, 80, 0.14), 0 3px 1px -2px rgba(239, 83, 80, 0.2), 0 1px 5px 0 rgba(239, 83, 80, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n}\n.btn-danger.disabled:hover {\n  background: #ef5350;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  border: 1px solid #ef5350;\n}\n.btn-danger.disabled:active {\n  background: #e6294b;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n}\n.btn-danger.disabled:focus {\n  background: #e6294b;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n}\n.btn-danger.active {\n  background: #e6294b;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n}\n.btn-danger.active:focus {\n  background-color: #e6294b;\n  border: 1px solid #e6294b;\n}\n.btn-danger.active:hover {\n  background-color: #e6294b;\n  border: 1px solid #e6294b;\n}\n.btn-danger.disabled.active {\n  background: #e6294b;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n}\n.btn-inverse {\n  background: #2f3d4a;\n  border: 1px solid #2f3d4a;\n  color: #ffffff;\n}\n.btn-inverse:hover {\n  background: #2f3d4a;\n  opacity: 0.7;\n  color: #ffffff;\n  border: 1px solid #2f3d4a;\n  background-color: #232a37;\n  border: 1px solid #232a37;\n}\n.btn-inverse:active {\n  background: #232a37;\n  color: #ffffff;\n  background-color: #232a37;\n  border: 1px solid #232a37;\n}\n.btn-inverse:focus {\n  background: #232a37;\n  color: #ffffff;\n  background-color: #232a37;\n  border: 1px solid #232a37;\n}\n.btn-inverse.disabled {\n  background: #2f3d4a;\n  border: 1px solid #2f3d4a;\n  color: #ffffff;\n}\n.btn-inverse.disabled:hover {\n  background: #2f3d4a;\n  opacity: 0.7;\n  color: #ffffff;\n  border: 1px solid #2f3d4a;\n}\n.btn-inverse.disabled:active {\n  background: #232a37;\n  color: #ffffff;\n}\n.btn-inverse.disabled:focus {\n  background: #232a37;\n  color: #ffffff;\n}\n.btn-inverse.active {\n  background: #232a37;\n  color: #ffffff;\n  background-color: #232a37;\n  border: 1px solid #232a37;\n}\n.btn-inverse.disabled.active {\n  background: #232a37;\n  color: #ffffff;\n}\n.btn-red {\n  background: #fb3a3a;\n  border: 1px solid #fb3a3a;\n  color: #ffffff;\n}\n.btn-red:hover {\n  opacity: 0.7;\n  border: 1px solid #fb3a3a;\n  background: #fb3a3a;\n  background-color: #d61f1f;\n  border: 1px solid #d61f1f;\n  color: #ffffff;\n}\n.btn-red:active {\n  background: #e6294b;\n  background-color: #d61f1f;\n  border: 1px solid #d61f1f;\n  color: #ffffff;\n}\n.btn-red:focus {\n  background: #e6294b;\n  background-color: #d61f1f;\n  border: 1px solid #d61f1f;\n  color: #ffffff;\n}\n.btn-red.disabled {\n  background: #fb3a3a;\n  border: 1px solid #fb3a3a;\n  color: #ffffff;\n}\n.btn-red.disabled:hover {\n  opacity: 0.7;\n  border: 1px solid #fb3a3a;\n  background: #fb3a3a;\n}\n.btn-red.disabled:active {\n  background: #e6294b;\n}\n.btn-red.disabled:focus {\n  background: #e6294b;\n}\n.btn-red.active {\n  background: #e6294b;\n  background-color: #d61f1f;\n  border: 1px solid #d61f1f;\n  color: #ffffff;\n}\n.btn-red.disabled.active {\n  background: #e6294b;\n}\n.btn-outline-secondary {\n  background-color: #ffffff;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(169, 169, 169, 0.14), 0 3px 1px -2px rgba(169, 169, 169, 0.2), 0 1px 5px 0 rgba(169, 169, 169, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(169, 169, 169, 0.14), 0 3px 1px -2px rgba(169, 169, 169, 0.2), 0 1px 5px 0 rgba(169, 169, 169, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n}\n.btn-outline-secondary:focus {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n}\n.btn-outline-secondary:hover {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n}\n.btn-outline-secondary:active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n}\n.btn-outline-secondary.focus {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n}\n.btn-outline-secondary.active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(169, 169, 169, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(169, 169, 169, 0.2);\n}\n.btn-outline-primary {\n  color: #5c4ac7;\n  background-color: #ffffff;\n  border-color: #5c4ac7;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(116, 96, 238, 0.14), 0 3px 1px -2px rgba(116, 96, 238, 0.2), 0 1px 5px 0 rgba(116, 96, 238, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(116, 96, 238, 0.14), 0 3px 1px -2px rgba(116, 96, 238, 0.2), 0 1px 5px 0 rgba(116, 96, 238, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n}\n.btn-outline-primary:focus {\n  background: #5c4ac7;\n  color: #ffffff;\n  border-color: #5c4ac7;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  background: #6352ce;\n}\n.btn-outline-primary:hover {\n  background: #5c4ac7;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  color: #ffffff;\n  border-color: #5c4ac7;\n}\n.btn-outline-primary:active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  background: #6352ce;\n}\n.btn-outline-primary.focus {\n  background: #5c4ac7;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  color: #ffffff;\n  border-color: #5c4ac7;\n}\n.btn-outline-primary.active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(116, 96, 238, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(116, 96, 238, 0.2);\n  background: #6352ce;\n}\n.btn-outline-success {\n  color: #26dad2;\n  background-color: transparent;\n  border-color: #26dad2;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(40, 190, 189, 0.14), 0 3px 1px -2px rgba(40, 190, 189, 0.2), 0 1px 5px 0 rgba(40, 190, 189, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(40, 190, 189, 0.14), 0 3px 1px -2px rgba(40, 190, 189, 0.2), 0 1px 5px 0 rgba(40, 190, 189, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n}\n.btn-outline-success:focus {\n  background: #26dad2;\n  border-color: #26dad2;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  background: #1eacbe;\n}\n.btn-outline-success:hover {\n  background: #26dad2;\n  border-color: #26dad2;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n}\n.btn-outline-success:active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  background: #1eacbe;\n}\n.btn-outline-success.focus {\n  background: #26dad2;\n  border-color: #26dad2;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n}\n.btn-outline-success.active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(40, 190, 189, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(40, 190, 189, 0.2);\n  background: #1eacbe;\n}\n.btn-outline-info {\n  color: #1976d2;\n  background-color: transparent;\n  border-color: #1976d2;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(66, 165, 245, 0.14), 0 3px 1px -2px rgba(66, 165, 245, 0.2), 0 1px 5px 0 rgba(66, 165, 245, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(66, 165, 245, 0.14), 0 3px 1px -2px rgba(66, 165, 245, 0.2), 0 1px 5px 0 rgba(66, 165, 245, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n}\n.btn-outline-info:focus {\n  background: #1976d2;\n  border-color: #1976d2;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  background: #028ee1;\n}\n.btn-outline-info:hover {\n  background: #1976d2;\n  border-color: #1976d2;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n}\n.btn-outline-info:active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  background: #028ee1;\n}\n.btn-outline-info.focus {\n  background: #1976d2;\n  border-color: #1976d2;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n}\n.btn-outline-info.active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2);\n  background: #028ee1;\n}\n.btn-outline-warning {\n  color: #ffb22b;\n  background-color: transparent;\n  border-color: #ffb22b;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(248, 194, 0, 0.14), 0 3px 1px -2px rgba(248, 194, 0, 0.2), 0 1px 5px 0 rgba(248, 194, 0, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(248, 194, 0, 0.14), 0 3px 1px -2px rgba(248, 194, 0, 0.2), 0 1px 5px 0 rgba(248, 194, 0, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n}\n.btn-outline-warning:focus {\n  background: #ffb22b;\n  border-color: #ffb22b;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  background: #e9ab2e;\n}\n.btn-outline-warning:hover {\n  background: #ffb22b;\n  border-color: #ffb22b;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n}\n.btn-outline-warning:active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  background: #e9ab2e;\n}\n.btn-outline-warning.focus {\n  background: #ffb22b;\n  border-color: #ffb22b;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n}\n.btn-outline-warning.active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(248, 194, 0, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(248, 194, 0, 0.2);\n  background: #e9ab2e;\n}\n.btn-outline-danger {\n  color: #ef5350;\n  background-color: transparent;\n  border-color: #ef5350;\n  -webkit-box-shadow: 0 2px 2px 0 rgba(239, 83, 80, 0.14), 0 3px 1px -2px rgba(239, 83, 80, 0.2), 0 1px 5px 0 rgba(239, 83, 80, 0.12);\n  box-shadow: 0 2px 2px 0 rgba(239, 83, 80, 0.14), 0 3px 1px -2px rgba(239, 83, 80, 0.2), 0 1px 5px 0 rgba(239, 83, 80, 0.12);\n  -webkit-transition: 0.2s ease-in;\n  -o-transition: 0.2s ease-in;\n  transition: 0.2s ease-in;\n}\n.btn-outline-danger:focus {\n  background: #ef5350;\n  border-color: #ef5350;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  background: #e6294b;\n}\n.btn-outline-danger:hover {\n  background: #ef5350;\n  border-color: #ef5350;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n}\n.btn-outline-danger:active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  background: #e6294b;\n}\n.btn-outline-danger.focus {\n  background: #ef5350;\n  border-color: #ef5350;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n}\n.btn-outline-danger.active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  background: #e6294b;\n}\n.btn-outline-red {\n  color: #fb3a3a;\n  background-color: transparent;\n  border-color: #fb3a3a;\n}\n.btn-outline-red:focus {\n  background: #fb3a3a;\n  border-color: #fb3a3a;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  background: #e6294b;\n}\n.btn-outline-red:hover {\n  background: #fb3a3a;\n  border-color: #fb3a3a;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n}\n.btn-outline-red:active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  background: #e6294b;\n}\n.btn-outline-red.focus {\n  background: #fb3a3a;\n  border-color: #fb3a3a;\n  color: #ffffff;\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n}\n.btn-outline-red.active {\n  -webkit-box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  box-shadow: 0 14px 26px -12px rgba(239, 83, 80, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(239, 83, 80, 0.2);\n  background: #e6294b;\n}\n.btn-outline-inverse {\n  color: #2f3d4a;\n  background-color: transparent;\n  border-color: #2f3d4a;\n}\n.btn-outline-inverse:focus {\n  background: #2f3d4a;\n  border-color: #2f3d4a;\n  color: #ffffff;\n}\n.btn-outline-inverse:hover {\n  background: #2f3d4a;\n  border-color: #2f3d4a;\n  color: #ffffff;\n}\n.btn-outline-inverse.focus {\n  background: #2f3d4a;\n  border-color: #2f3d4a;\n  color: #ffffff;\n}\n.btn-primary.active.focus {\n  background-color: #6352ce;\n  border: 1px solid #6352ce;\n}\n.btn-primary.focus {\n  background-color: #6352ce;\n  border: 1px solid #6352ce;\n}\n.btn-primary.focus:active {\n  background-color: #6352ce;\n  border: 1px solid #6352ce;\n}\n.open > .dropdown-toggle.btn-primary.focus {\n  background-color: #6352ce;\n  border: 1px solid #6352ce;\n}\n.open > .dropdown-toggle.btn-primary:focus {\n  background-color: #6352ce;\n  border: 1px solid #6352ce;\n}\n.open > .dropdown-toggle.btn-primary:hover {\n  background-color: #6352ce;\n  border: 1px solid #6352ce;\n}\n.open > .dropdown-toggle.btn-success.focus {\n  background-color: #1eacbe;\n  border: 1px solid #1eacbe;\n}\n.open > .dropdown-toggle.btn-success:focus {\n  background-color: #1eacbe;\n  border: 1px solid #1eacbe;\n}\n.open > .dropdown-toggle.btn-success:hover {\n  background-color: #1eacbe;\n  border: 1px solid #1eacbe;\n}\n.open > .dropdown-toggle.btn-info.focus {\n  background-color: #028ee1;\n  border: 1px solid #028ee1;\n}\n.open > .dropdown-toggle.btn-info:focus {\n  background-color: #028ee1;\n  border: 1px solid #028ee1;\n}\n.open > .dropdown-toggle.btn-info:hover {\n  background-color: #028ee1;\n  border: 1px solid #028ee1;\n}\n.open > .dropdown-toggle.btn-warning.focus {\n  background-color: #e9ab2e;\n  border: 1px solid #e9ab2e;\n}\n.open > .dropdown-toggle.btn-warning:focus {\n  background-color: #e9ab2e;\n  border: 1px solid #e9ab2e;\n}\n.open > .dropdown-toggle.btn-warning:hover {\n  background-color: #e9ab2e;\n  border: 1px solid #e9ab2e;\n}\n.open > .dropdown-toggle.btn-danger.focus {\n  background-color: #e6294b;\n  border: 1px solid #e6294b;\n}\n.open > .dropdown-toggle.btn-danger:focus {\n  background-color: #e6294b;\n  border: 1px solid #e6294b;\n}\n.open > .dropdown-toggle.btn-danger:hover {\n  background-color: #e6294b;\n  border: 1px solid #e6294b;\n}\n.open > .dropdown-toggle.btn-inverse {\n  background-color: #232a37;\n  border: 1px solid #232a37;\n}\n.open > .dropdown-toggle.btn-red {\n  background-color: #d61f1f;\n  border: 1px solid #d61f1f;\n  color: #ffffff;\n}\n.btn-success.active.focus {\n  background-color: #1eacbe;\n  border: 1px solid #1eacbe;\n}\n.btn-success.focus {\n  background-color: #1eacbe;\n  border: 1px solid #1eacbe;\n}\n.btn-success.focus:active {\n  background-color: #1eacbe;\n  border: 1px solid #1eacbe;\n}\n.btn-info.active.focus {\n  background-color: #028ee1;\n  border: 1px solid #028ee1;\n}\n.btn-info.focus {\n  background-color: #028ee1;\n  border: 1px solid #028ee1;\n}\n.btn-info.focus:active {\n  background-color: #028ee1;\n  border: 1px solid #028ee1;\n}\n.btn-warning.active.focus {\n  background-color: #e9ab2e;\n  border: 1px solid #e9ab2e;\n}\n.btn-warning.focus {\n  background-color: #e9ab2e;\n  border: 1px solid #e9ab2e;\n}\n.btn-warning.focus:active {\n  background-color: #e9ab2e;\n  border: 1px solid #e9ab2e;\n}\n.btn-danger.active.focus {\n  background-color: #e6294b;\n  border: 1px solid #e6294b;\n}\n.btn-danger.focus {\n  background-color: #e6294b;\n  border: 1px solid #e6294b;\n}\n.btn-danger.focus:active {\n  background-color: #e6294b;\n  border: 1px solid #e6294b;\n}\n.btn-inverse.focus {\n  background-color: #232a37;\n  border: 1px solid #232a37;\n}\n.btn-red.focus {\n  background-color: #d61f1f;\n  border: 1px solid #d61f1f;\n  color: #ffffff;\n}\n.button-box .btn {\n  margin: 0 8px 8px 0;\n}\n.btn-label {\n  background: rgba(0, 0, 0, 0.05);\n  display: inline-block;\n  margin: -6px 12px -6px -14px;\n  padding: 7px 15px;\n}\n.btn-facebook {\n  color: #ffffff;\n  background-color: #3b5998;\n}\n.btn-twitter {\n  color: #ffffff;\n  background-color: #55acee;\n}\n.btn-linkedin {\n  color: #ffffff;\n  background-color: #007bb6;\n}\n.btn-dribbble {\n  color: #ffffff;\n  background-color: #ea4c89;\n}\n.btn-googleplus {\n  color: #ffffff;\n  background-color: #dd4b39;\n}\n.btn-instagram {\n  color: #ffffff;\n  background-color: #3f729b;\n}\n.btn-pinterest {\n  color: #ffffff;\n  background-color: #cb2027;\n}\n.btn-dropbox {\n  color: #ffffff;\n  background-color: #007ee5;\n}\n.btn-flickr {\n  color: #ffffff;\n  background-color: #ff0084;\n}\n.btn-tumblr {\n  color: #ffffff;\n  background-color: #32506d;\n}\n.btn-skype {\n  color: #ffffff;\n  background-color: #00aff0;\n}\n.btn-youtube {\n  color: #ffffff;\n  background-color: #bb0000;\n}\n.btn-github {\n  color: #ffffff;\n  background-color: #171515;\n}\n.map {\n  width: 100%;\n  height: 400px;\n}\n.chat-sidebar {\n  background-color: #eef5f9;\n  border-left: 1px solid #e7e7e7;\n  position: fixed;\n  right: -240px;\n  bottom: 0;\n  top: 55px;\n  width: 240px;\n  z-index: 2;\n  -webkit-transition: all 0.5s ease 0s;\n  transition: all 0.5s ease 0s;\n}\n.chat-sidebar .user-name {\n  font-family: 'Poppins', sans-serif;\n}\n.chat-sidebar .content {\n  font-family: 'Poppins', sans-serif;\n}\n.chat-sidebar .textarea {\n  font-family: 'Poppins', sans-serif;\n}\n.chat-sidebar .seen {\n  font-family: 'Poppins', sans-serif;\n}\n.chat-sidebar.is-active {\n  right: 0;\n}\n.chat-user-search .input-group-addon {\n  background: #ffffff;\n  border-radius: 0px;\n  border: 0px;\n}\n.chat-user-search .form-control {\n  border: 0px;\n}\n.hidden {\n  display: none;\n}\n/*    Home Chat Widget\n---------------------------------*/\n.chat-widget .chat_window {\n  position: relative;\n  width: 100%;\n  height: 500px;\n  border-radius: 10px;\n  background-color: #ffffff;\n  background-color: #f8f8f8;\n  overflow: hidden;\n}\n.chat-widget .messages {\n  position: relative;\n  list-style: none;\n  padding: 20px 10px 0 10px;\n  margin: 0;\n  min-height: 350px;\n  overflow: scroll;\n}\n.chat-widget .messages .message {\n  clear: both;\n  overflow: hidden;\n  margin-bottom: 20px;\n  transition: all 0.5s linear;\n  opacity: 0;\n}\n.chat-widget .messages .message .avatar {\n  width: 60px;\n  height: 60px;\n  border-radius: 50%;\n  display: inline-block;\n}\n.chat-widget .messages .message .text_wrapper {\n  display: inline-block;\n  padding: 20px;\n  border-radius: 6px;\n  width: calc(100% - 100px);\n  min-width: 100px;\n  position: relative;\n}\n.chat-widget .messages .message .text_wrapper .text {\n  font-size: 18px;\n  font-weight: 300;\n}\n.chat-widget .messages .message .text_wrapper::after {\n  top: 18px;\n  border: solid transparent;\n  content: \" \";\n  height: 0;\n  width: 0;\n  position: absolute;\n  pointer-events: none;\n  border-width: 13px;\n  margin-top: 0px;\n}\n.chat-widget .messages .message .text_wrapper:before {\n  top: 18px;\n  border: solid transparent;\n  content: \" \";\n  height: 0;\n  width: 0;\n  position: absolute;\n  pointer-events: none;\n}\n.chat-widget .messages .message .text_wrapper::before {\n  border-width: 15px;\n  margin-top: -2px;\n}\n.chat-widget .messages .message.left .text_wrapper::after,\n.chat-widget .messages .message.left .text_wrapper::before {\n  right: 100%;\n  border-right-color: #ffe6cb;\n}\n.chat-widget .messages .message.left .avatar {\n  background-color: #f5886e;\n  float: left;\n}\n.chat-widget .messages .message.left .text_wrapper {\n  background-color: #ffe6cb;\n  margin-left: 20px;\n}\n.chat-widget .messages .message.left .text {\n  color: #c48843;\n}\n.chat-widget .messages .message.right .text_wrapper::after,\n.chat-widget .messages .message.right .text_wrapper::before {\n  left: 100%;\n  border-left-color: #c7eafc;\n}\n.chat-widget .messages .message.right .avatar {\n  background-color: #fdbf68;\n  float: right;\n}\n.chat-widget .messages .message.right .text_wrapper {\n  background-color: #c7eafc;\n  margin-right: 20px;\n  float: right;\n}\n.chat-widget .messages .message.right .text {\n  color: #45829b;\n}\n.chat-widget .messages .message.appeared {\n  opacity: 1;\n}\n.chat-widget .bottom_wrapper {\n  position: relative;\n  position: absolute;\n  width: 100%;\n  background-color: #ffffff;\n  padding: 20px 20px;\n  bottom: 0;\n}\n.chat-widget .bottom_wrapper .message_input_wrapper {\n  display: inline-block;\n  height: 50px;\n  border-radius: 25px;\n  border: 1px solid #bcbdc0;\n  width: calc(100% - 160px);\n  position: relative;\n  padding: 0 20px;\n}\n.chat-widget .bottom_wrapper .message_input_wrapper .message_input {\n  border: none;\n  height: 100%;\n  box-sizing: border-box;\n  width: calc(100% - 45px);\n  position: absolute;\n  outline-width: 0;\n  color: gray;\n}\n.chat-widget .bottom_wrapper .send_message {\n  width: 140px;\n  height: 50px;\n  display: inline-block;\n  border-radius: 50px;\n  background-color: #a3d063;\n  border: 2px solid #a3d063;\n  color: #ffffff;\n  cursor: pointer;\n  transition: all 0.2s linear;\n  text-align: center;\n  float: right;\n}\n.chat-widget .bottom_wrapper .send_message .text {\n  font-size: 18px;\n  font-weight: 300;\n  display: inline-block;\n  line-height: 48px;\n}\n.chat-widget .bottom_wrapper .send_message:hover {\n  color: #a3d063;\n  background-color: #ffffff;\n}\n.chat-widget .message_template {\n  display: none;\n}\n.testimonial-widget-one .testimonial-content {\n  text-align: center;\n}\n.testimonial-widget-one .testimonial-text {\n  margin-bottom: 15px;\n}\n.testimonial-widget-one .testimonial-author-position {\n  font-family: 'Poppins', sans-serif;\n  position: relative;\n  top: -5px;\n  margin-top: 5px;\n  text-align: center;\n  font-size: 12px;\n}\n.testimonial-widget-one .testimonial-author {\n  padding-top: 15px;\n  position: relative;\n  top: -5px;\n  font-weight: 600;\n  color: #ffffff;\n  text-align: center;\n}\n.testimonial-widget-one .testimonial-author-img {\n  border-radius: 100px;\n  height: 50px !important;\n  width: 50px !important;\n  margin: 0 auto;\n}\n.weather-one i {\n  font-size: 100px;\n  position: relative;\n  top: 5px;\n  color: #ffffff;\n}\n.weather-one h2 {\n  display: inline-block;\n  float: right;\n  font-size: 48px;\n  color: #ffffff;\n}\n.weather-one .city {\n  position: relative;\n  text-align: right;\n  top: -25px;\n}\n.weather-one .currently {\n  font-size: 16px;\n  font-weight: 400;\n  position: relative;\n  top: 25px;\n}\n.weather-one .celcious {\n  text-align: right;\n  font-size: 20px;\n  color: #ffffff;\n}\n[contenteditable]:hover,\n[contenteditable]:focus {\n  background: #93b5ff;\n}\n.control-bar {\n  position: relative;\n  z-index: 100;\n  background: #4680ff;\n  color: #ffffff;\n  padding: 15px;\n  margin-bottom: 30px;\n}\n.control-bar .slogan {\n  font-weight: bold;\n  font-size: 1.2rem;\n  display: inline-block;\n  margin-right: 2rem;\n}\n.control-bar label {\n  margin: 0px;\n  color: #ffffff;\n}\n.control-bar a {\n  margin: 0;\n  padding: .5em 1em;\n  background: #ffffff;\n  color: #455a64;\n}\n.control-bar a:hover {\n  background: #93b5ff;\n}\n.control-bar input {\n  border: none;\n  background: #93b5ff;\n  max-width: 30px;\n  text-align: center;\n  color: #455a64;\n}\n.control-bar input:hover {\n  background: #93b5ff;\n}\n.hidetax .taxrelated {\n  display: none;\n}\n.showtax .notaxrelated {\n  display: none;\n}\n.hidedate .daterelated {\n  display: none;\n}\n.showdate .notdaterelated {\n  display: none;\n}\n.details input {\n  display: inline;\n  margin: 0 0 0 .5rem;\n  border: none;\n  width: 55px;\n  min-width: 0;\n  background: transparent;\n  text-align: left;\n}\n.invoice-edit .rate:before,\n.invoice-edit .price:before,\n.invoice-edit .sum:before,\n.invoice-edit .tax:before,\n.invoice-edit #total_price:before,\n.invoice-edit #total_tax:before {\n  content: '€';\n}\n.invoice-edit .me,\n.invoice-edit .info,\n.invoice-edit .bank,\n.invoice-edit .smallme,\n.invoice-edit .client,\n.invoice-edit .bill,\n.invoice-edit .details {\n  padding: 15px;\n}\n.invoice-logo img {\n  display: block;\n  vertical-align: top;\n  width: 50px;\n}\n/**\n * INVOICELIST BODY\n */\n.invoicelist-body {\n  margin: 1rem;\n}\n.invoicelist-body table {\n  width: 100%;\n}\n.invoicelist-body thead {\n  text-align: left;\n  border-bottom: 2pt solid #666;\n}\n.invoicelist-body td,\n.invoicelist-body th {\n  position: relative;\n  padding: 1rem;\n}\n.invoicelist-body tr:nth-child(even) {\n  background: #eef5f9;\n}\n.invoicelist-body tr:hover .removeRow {\n  display: block;\n}\n.invoicelist-body input {\n  display: inline;\n  margin: 0;\n  border: none;\n  width: 80%;\n  min-width: 0;\n  background: transparent;\n  text-align: left;\n}\n.invoicelist-body .control {\n  display: inline-block;\n  color: white;\n  background: #4680ff;\n  padding: 3px 7px;\n  font-size: .9rem;\n  text-transform: uppercase;\n  cursor: pointer;\n}\n.invoicelist-body .control:hover {\n  background: #6092ff;\n}\n.invoicelist-body .newRow {\n  margin: .5rem 0;\n  float: left;\n}\n.invoicelist-body .removeRow {\n  display: none;\n  position: absolute;\n  top: .1rem;\n  bottom: .1rem;\n  left: -1.3rem;\n  font-size: .7rem;\n  border-radius: 3px 0 0 3px;\n  padding: .5rem;\n}\n/**\n * INVOICE LIST FOOTER\n */\n.invoicelist-footer {\n  margin: 1rem;\n}\n.invoicelist-footer table {\n  float: right;\n  width: 25%;\n}\n.invoicelist-footer table td {\n  padding: 1rem 2rem 0 1rem;\n  text-align: right;\n}\n.invoicelist-footer table tr:nth-child(2) td {\n  padding-top: 0;\n}\n.invoicelist-footer table #total_price {\n  font-size: 2rem;\n  color: #4680ff;\n}\n/**\n * NOTE\n */\n.note {\n  margin: 75px 15px;\n}\n.hidenote .note {\n  display: none;\n}\n.note h2 {\n  margin: 0;\n  font-size: 12px;\n  font-weight: bold;\n}\n.note p {\n  font-size: 12px;\n  padding: 0px 5px;\n}\n/**\n * FOOTER\n */\nfooter {\n  display: block;\n  /* margin: 1rem 0; */\n  /* padding: 1rem 0 0; */\n}\nfooter p {\n  font-size: 12px;\n}\n/**\n * PRINT STYLE\n */\n@media print {\n  .header,\n  .sidebar,\n  .chat-sidebar,\n  .control,\n  .control-bar {\n    display: none !important;\n  }\n  [contenteditable]:hover,\n  [contenteditable]:focus {\n    outline: none;\n  }\n}\n#invoice {\n  position: relative;\n  /*  top: -290px;*/\n  margin-bottom: 120px;\n  /*  width: 700px;*/\n  background: #ffffff;\n  padding: 30px;\n}\n#invoice-table {\n  /* Targets all id with 'col-' */\n  border-bottom: 1px solid #e7e7e7;\n  padding: 30px 0px;\n}\n#invoice-top {\n  min-height: 120px;\n}\n#invoice-mid {\n  min-height: 120px;\n}\n#invoice-bot {\n  min-height: 250px;\n}\n.invoice-logo {\n  float: left;\n  height: 60px;\n  width: 60px;\n  background: url(http://michaeltruong.ca/images/logo1.png) no-repeat;\n  background-size: 60px 60px;\n}\n.clientlogo {\n  float: left;\n  height: 60px;\n  width: 60px;\n  background: url(http://michaeltruong.ca/images/client.jpg) no-repeat;\n  background-size: 60px 60px;\n  border-radius: 50px;\n}\n.invoice-info {\n  display: block;\n  float: left;\n  margin-left: 20px;\n}\n.invoice-info h2 {\n  color: #455a64;\n  font-size: 14px;\n}\n.invoice-info p {\n  font-size: 12px;\n}\n.title {\n  float: right;\n}\n.title h4 {\n  color: #455a64;\n  text-align: right;\n}\n.title p {\n  text-align: right;\n  font-size: 12px;\n}\n#project {\n  margin-left: 52%;\n}\n#project p {\n  font-size: 12px;\n}\n#invoice-table h2 {\n  font-size: 18px;\n}\n.tabletitle {\n  padding: 5px;\n  background: #e7e7e7;\n}\n.service {\n  border: 1px solid #e7e7e7;\n}\n.table-item {\n  width: 50%;\n}\n.itemtext {\n  font-size: .9em;\n}\n#legalcopy {\n  margin-top: 30px;\n}\n#legalcopy p {\n  font-size: 12px;\n}\n.effect2 {\n  position: relative;\n}\n.effect2:before,\n.effect2:after {\n  z-index: -1;\n  position: absolute;\n  content: \"\";\n  bottom: 15px;\n  left: 10px;\n  width: 50%;\n  top: 80%;\n  max-width: 300px;\n  background: #777;\n  -webkit-box-shadow: 0 15px 10px #777;\n  -moz-box-shadow: 0 15px 10px #777;\n  box-shadow: 0 15px 10px #777;\n  -webkit-transform: rotate(-3deg);\n  -moz-transform: rotate(-3deg);\n  -o-transform: rotate(-3deg);\n  -ms-transform: rotate(-3deg);\n  transform: rotate(-3deg);\n}\n.effect2:after {\n  -webkit-transform: rotate(3deg);\n  -moz-transform: rotate(3deg);\n  -o-transform: rotate(3deg);\n  -ms-transform: rotate(3deg);\n  transform: rotate(3deg);\n  right: 10px;\n  left: auto;\n}\n.legal {\n  width: 70%;\n}\n/* All Invoice Page Responsive\n--------------------------- */\n@media (max-width: 480px) {\n  .control-bar {\n    padding: 15px 15px 40px;\n  }\n}\n@media (max-width: 360px) {\n  .notaxrelated {\n    margin-top: 15px;\n  }\n}\n/*    Widget One\n---------------------------*/\n.stat-widget-one .stat-icon {\n  vertical-align: top;\n}\n.stat-widget-one .stat-icon i {\n  font-size: 30px;\n  border-width: 3px;\n  border-style: solid;\n  border-radius: 100px;\n  padding: 15px;\n  font-weight: 900;\n  display: inline-block;\n}\n.stat-widget-one .stat-content {\n  margin-left: 30px;\n  margin-top: 7px;\n}\n.stat-widget-one .stat-text {\n  font-size: 14px;\n  color: #99abb4;\n}\n.stat-widget-one .stat-digit {\n  font-size: 24px;\n  color: #455a64;\n}\n/*    Widget Two\n---------------------------*/\n.stat-widget-two {\n  text-align: center;\n}\n.stat-widget-two .stat-digit {\n  font-size: 40px;\n  font-weight: 700;\n  color: #455a64;\n}\n.stat-widget-two .stat-text {\n  font-size: 20px;\n  margin-bottom: 5px;\n  color: #99abb4;\n}\n.stat-widget-two .progress {\n  height: 8px;\n  margin-bottom: 0;\n  margin-top: 20px;\n  box-shadow: none;\n}\n.stat-widget-two .progress-bar {\n  box-shadow: none;\n}\n/*    Widget Three\n---------------------------*/\n.stat-widget-three .stat-icon {\n  display: inline-block;\n  padding: 33px;\n  position: absolute;\n  line-height: 21px;\n}\n.stat-widget-three .stat-icon i {\n  font-size: 30px;\n  color: #ffffff;\n}\n.stat-widget-three .stat-content {\n  text-align: center;\n  padding: 15px;\n  margin-left: 90px;\n}\n.stat-widget-three .stat-digit {\n  font-size: 30px;\n}\n.stat-widget-three .stat-text {\n  padding-top: 7px;\n}\n.home-widget-three .stat-icon {\n  line-height: 19px;\n  padding: 27px;\n}\n.home-widget-three .stat-digit {\n  font-size: 24px;\n  font-weight: 300;\n  color: #455a64;\n}\n.home-widget-three .stat-content {\n  text-align: center;\n  margin-left: 60px;\n  padding: 13px;\n}\n.stat-widget-four {\n  position: relative;\n}\n.stat-widget-four .stat-icon {\n  display: inline-block;\n  position: absolute;\n  top: 5px;\n}\n.stat-widget-four i {\n  display: block;\n  font-size: 36px;\n}\n.stat-widget-four .stat-content {\n  margin-left: 40px;\n  text-align: center;\n}\n.stat-widget-four .stat-heading {\n  font-size: 20px;\n}\n.stat-widget-five .stat-icon {\n  border-radius: 100px;\n  display: inline-block;\n  position: absolute;\n}\n.stat-widget-five i {\n  border-radius: 100px;\n  display: block;\n  font-size: 36px;\n  padding: 30px;\n}\n.stat-widget-five .stat-content {\n  margin-left: 100px;\n  padding: 24px 0;\n  position: relative;\n  text-align: right;\n  vertical-align: middle;\n}\n.stat-widget-five .stat-heading {\n  text-align: right;\n  padding-left: 80px;\n  font-size: 20px;\n  font-weight: 200;\n}\n.stat-widget-six {\n  position: relative;\n}\n.stat-widget-six .stat-icon {\n  display: inline-block;\n  position: absolute;\n  top: 5px;\n}\n.stat-widget-six i {\n  display: block;\n  font-size: 36px;\n}\n.stat-widget-six .stat-content {\n  margin-left: 40px;\n  text-align: center;\n}\n.stat-widget-six .stat-heading {\n  font-size: 16px;\n  font-weight: 300;\n}\n.stat-widget-six .stat-text {\n  font-size: 12px;\n  padding-top: 4px;\n}\n.stat-widget-seven .stat-heading {\n  text-align: center;\n}\n.stat-widget-seven .gradient-circle {\n  text-align: center;\n  position: relative;\n  margin: 30px auto;\n  display: inline-block;\n  width: 100%;\n}\n.stat-widget-seven .gradient-circle i {\n  position: absolute;\n  left: 0;\n  right: 0;\n  text-align: center;\n  top: 35px;\n  font-size: 30px;\n}\n.stat-widget-seven .stat-footer {\n  text-align: center;\n  margin-top: 30px;\n}\n.stat-widget-seven .stat-footer .stat-count {\n  padding-left: 5px;\n}\n.stat-widget-seven .count-header {\n  color: #252525;\n  font-size: 12px;\n  font-weight: 400;\n  line-height: 30px;\n}\n.stat-widget-seven .stat-count {\n  font-size: 18px;\n  font-weight: 400;\n  color: #252525;\n}\n.stat-widget-seven .analytic-arrow {\n  position: relative;\n}\n.stat-widget-seven .analytic-arrow i {\n  font-size: 12px;\n}\n/* Stat widget Eight\n--------------------------- */\n.stat-widget-eight {\n  padding: 15px;\n}\n.stat-widget-eight .header-title {\n  font-size: 20px;\n  font-weight: 300;\n}\n.stat-widget-eight .ti-more-alt {\n  color: #878787;\n  cursor: pointer;\n  left: -5px;\n  position: absolute;\n  transform: rotate(90deg);\n}\n.stat-widget-eight .stat-content {\n  margin-top: 50px;\n}\n.stat-widget-eight .stat-content .ti-arrow-up {\n  font-size: 30px;\n  color: #26dad2;\n}\n.stat-widget-eight .stat-content .stat-digit {\n  font-size: 24px;\n  font-weight: 300;\n  margin-left: 15px;\n}\n.stat-widget-eight .stat-content .progress-stats {\n  color: #aaadb2;\n  font-weight: 400;\n  position: relative;\n  top: 10px;\n}\n.stat-widget-eight .progress {\n  margin-bottom: 0;\n  margin-top: 30px;\n  height: 7px;\n  background: #EAEAEA;\n  box-shadow: none;\n}\n.stat-widget-nine .all-like {\n  float: right;\n}\n.stat-widget-nine .stat-icon i {\n  font-size: 22px;\n}\n.stat-widget-nine .stat-text {\n  font-size: 14px;\n}\n.stat-widget-nine .stat-digit {\n  font-size: 14px;\n}\n.stat-widget-nine .like-count {\n  font-size: 30px;\n}\n.horizontal {\n  position: relative;\n}\n.horizontal:before {\n  background: #ffffff;\n  bottom: 0;\n  content: \"\";\n  height: 38px;\n  left: 0;\n  margin: 0 auto;\n  position: absolute;\n  right: 0;\n  width: 1px;\n}\n.widget-ten span i {\n  color: #ffffff;\n  opacity: 0.5;\n}\n.widget-ten h5 {\n  color: #ffffff;\n}\n.widget-ten p {\n  color: #ffffff !important;\n  opacity: 0.75;\n}\n/*\n=================================================\n    Responsive\n=================================================\n*/\n@media (max-width: 768px) {\n  .card {\n    display: inline-block;\n    width: 100%;\n  }\n}\n@media (max-width: 360px) {\n  .stat-widget-five .stat-heading {\n    padding-left: 0;\n  }\n  .stat-widget-two .stat-digit {\n    font-size: 16px;\n  }\n  .stat-widget-two .stat-text {\n    font-size: 14px;\n  }\n  .stat-widget-three .stat-digit {\n    font-size: 20px;\n  }\n  .stat-widget-four .stat-heading {\n    font-size: 18px;\n  }\n  .stat-widget-three .stat-icon {\n    padding: 26px;\n  }\n}\n.round-widget {\n  border: 1px solid red;\n  border-radius: 100px;\n  display: inline-block;\n  height: 60px;\n  line-height: 60px;\n  text-align: center;\n  width: 60px;\n}\n.recent-comment .media {\n  border-bottom: 1px solid #e7e7e7;\n  padding-bottom: 10px;\n  padding-top: 10px;\n}\n.recent-comment .media-left {\n  padding-right: 25px;\n}\n.recent-comment .media-left img {\n  border-radius: 100px;\n  width: 40px;\n}\n.recent-comment .media-body {\n  position: relative;\n}\n.recent-comment .media-body h4 {\n  font-size: 16px;\n  margin-bottom: 10px;\n}\n.recent-comment .media-body p {\n  margin-bottom: 10px;\n  line-height: 16px;\n  color: #99abb4;\n}\n.recent-comment .comment-date {\n  position: absolute;\n  right: 0;\n  top: 0;\n  color: #455a64;\n  font-family: 'Poppins', sans-serif;\n  font-size: 12px;\n}\n.comment-action {\n  float: left;\n}\n.comment-action .badge {\n  text-transform: uppercase;\n  font-family: 'Poppins', sans-serif;\n}\n.comment-action i {\n  padding: 0 5px;\n}\n.recent-meaasge {\n  margin-top: 15px;\n}\n.recent-meaasge .media {\n  border-bottom: 1px solid #e7e7e7;\n  padding-top: 10px;\n  padding-bottom: 10px;\n}\n.recent-meaasge .media-left {\n  padding-right: 25px;\n}\n.recent-meaasge .media-left img {\n  border-radius: 100px;\n  width: 50px;\n}\n.recent-meaasge .media-body {\n  position: relative;\n}\n.recent-meaasge .media-body h4 {\n  font-size: 16px;\n}\n.recent-meaasge .media-body p {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.meaasge-date {\n  float: right;\n  color: #455a64;\n  position: absolute;\n  right: 0;\n  top: 0;\n  font-size: 12px;\n}\n/*    Input Style\n------------------------*/\n.form-group {\n  margin-bottom: 20px;\n}\n.form-control {\n  height: 42px;\n  border-radius: 0;\n  box-shadow: none;\n  border-color: #e7e7e7;\n  font-family: 'Poppins', sans-serif;\n}\n.form-control:hover {\n  box-shadow: none;\n  border-color: #e7e7e7;\n}\n.form-control.active,\n.form-control:focus {\n  box-shadow: none;\n  border-color: #878787;\n}\n.input-default {\n  border-radius: 4px;\n}\n.input-flat {\n  border-radius: 0;\n}\n.input-rounded {\n  border-radius: 100px;\n}\n.input-focus {\n  border-color: #4680ff;\n}\n.input-focus:focus {\n  border-color: #4680ff;\n}\n/*    Search Box Input Button\n--------------------------------*/\n.input-group-btn .btn {\n  padding: 10px 12px;\n}\n.input-group-default .form-control {\n  border-radius: 4px;\n}\n.input-group-flat .form-control {\n  border-radius: 4px;\n}\n.input-group-flat .btn {\n  border-radius: 0;\n}\n.input-group-rounded .form-control {\n  border-radius: 100px;\n}\n.input-group-rounded .btn-group-left {\n  border-top-left-radius: 100px;\n  border-bottom-left-radius: 100px;\n}\n.input-group-rounded .btn-group-right {\n  border-top-right-radius: 100px;\n  border-bottom-right-radius: 100px;\n}\n.input-group-close-icon {\n  background: none;\n  color: #252525;\n  border-color: #e7e7e7;\n}\n.input-group-close-icon.active,\n.input-group-close-icon:focus,\n.input-group-close-icon:hover {\n  background: none;\n  border-color: #e7e7e7;\n  color: #252525;\n}\n/*    Input States\n-----------------------*/\n.has-default .form-control.active,\n.has-error .form-control.active,\n.has-success .form-control.active,\n.has-warning .form-control.active,\n.has-default .form-control:focus,\n.has-error .form-control:focus,\n.has-success .form-control:focus,\n.has-warning .form-control:focus,\n.has-default .form-control:hover,\n.has-error .form-control:hover,\n.has-success .form-control:hover,\n.has-warning .form-control:hover {\n  box-shadow: none;\n}\n.has-default .control-label {\n  color: #878787;\n}\n.has-default .form-control {\n  border-color: #878787;\n}\n.has-default .form-control.active,\n.has-default .form-control:focus,\n.has-default .form-control:hover {\n  border-color: #878787;\n}\n.has-success .control-label {\n  color: #26dad2;\n}\n.has-success .form-control {\n  border-color: #26dad2;\n}\n.has-success .form-control.active,\n.has-success .form-control:focus,\n.has-success .form-control:hover {\n  border-color: #26dad2;\n}\n.has-warning .control-label {\n  color: #ffb64d;\n}\n.has-warning .form-control {\n  border-color: #ffb64d;\n}\n.has-warning .form-control.active,\n.has-warning .form-control:focus,\n.has-warning .form-control:hover {\n  border-color: #ffb64d;\n}\n.has-error .control-label {\n  color: #fc6180;\n}\n.has-error .form-control {\n  border-color: #fc6180;\n}\n.has-error .form-control.active,\n.has-error .form-control:focus,\n.has-error .form-control:hover {\n  border-color: #fc6180;\n}\n.has-feedback label ~ .form-control-feedback {\n  top: 35px;\n}\n.form-horizontal .has-feedback .form-control-feedback {\n  top: 5px;\n}\n.has-success .form-control-feedback {\n  color: #26dad2;\n}\n.has-warning .form-control-feedback {\n  color: #ffb64d;\n}\n.has-error .form-control-feedback {\n  color: #fc6180;\n}\n.has-success .input-group-addon {\n  background-color: #93ede9;\n  border-color: #26dad2;\n  color: #26dad2;\n}\n.has-warning .input-group-addon {\n  background-color: #ffeacd;\n  border-color: #ffb64d;\n  color: #ffb64d;\n}\n.has-error .input-group-addon {\n  background-color: #fedee5;\n  border-color: #fc6180;\n  color: #fc6180;\n}\n/*    Input Size\n--------------------*/\n.input-sm {\n  font-size: 12px;\n  height: 30px;\n  line-height: 1.5;\n}\n.input-lg {\n  font-size: 18px;\n  height: 46px;\n  line-height: 1.33333;\n}\n/*    Basic form\n----------------------*/\nlabel {\n  font-weight: 400;\n  margin-bottom: 10px;\n}\n/*    Form Horizontal\n----------------------*/\n.form-horizontal .control-label {\n  padding-top: 12px;\n}\n.form-horizontal .form-group {\n  margin-left: 0;\n  margin-right: 0;\n}\n.dropdown-menu li {\n  font-size: 14px;\n  padding: 5px 15px;\n}\n.is-invalid .form-control {\n  border-color: #fc6180;\n}\n.invalid-feedback {\n  color: #ef5350;\n  display: none;\n  margin-top: 0.25rem;\n}\n.is-invalid .invalid-feedback,\n.is-invalid .invalid-tooltip {\n  display: block;\n}\n.inbox-leftbar {\n  width: 240px;\n  float: left;\n  padding: 0 20px 20px 10px;\n}\n.inbox-rightbar {\n  margin-left: 250px;\n}\n.message-list {\n  display: block;\n  padding-left: 0;\n}\n.message-list li {\n  position: relative;\n  display: block;\n  height: 50px;\n  line-height: 50px;\n  cursor: default;\n  transition-duration: 0.3s;\n}\n.message-list li a {\n  color: #797979;\n}\n.message-list li:hover {\n  background: rgba(152, 166, 173, 0.15);\n  transition-duration: 0.05s;\n}\n.message-list li .col-mail {\n  float: left;\n  position: relative;\n}\n.message-list li .col-mail-1 {\n  width: 320px;\n}\n.message-list li .col-mail-1 .star-toggle {\n  display: block;\n  float: left;\n  margin-top: 18px;\n  font-size: 16px;\n  margin-left: 5px;\n}\n.message-list li .col-mail-1 .checkbox-wrapper-mail {\n  display: block;\n  float: left;\n  margin: 15px 10px 0 20px;\n}\n.message-list li .col-mail-1 .dot {\n  display: block;\n  float: left;\n  border: 4px solid transparent;\n  border-radius: 100px;\n  margin: 22px 26px 0;\n  height: 0;\n  width: 0;\n  line-height: 0;\n  font-size: 0;\n}\n.message-list li .col-mail-1 .title {\n  position: absolute;\n  left: 110px;\n  right: 0;\n  text-overflow: ellipsis;\n  overflow: hidden;\n  white-space: nowrap;\n}\n.message-list li .col-mail-2 {\n  position: absolute;\n  top: 0;\n  left: 320px;\n  right: 0;\n  bottom: 0;\n}\n.message-list li .col-mail-2 .subject {\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 200px;\n  text-overflow: ellipsis;\n  overflow: hidden;\n  white-space: nowrap;\n}\n.message-list li .col-mail-2 .date {\n  position: absolute;\n  top: 0;\n  right: 0;\n  width: 170px;\n  padding-left: 80px;\n}\n.message-list li.active {\n  background: rgba(152, 166, 173, 0.15);\n  transition-duration: 0.05s;\n  box-shadow: inset 3px 0 0 #3c86d8;\n}\n.message-list li.active:hover {\n  box-shadow: inset 3px 0 0 #3c86d8;\n}\n.message-list li.selected {\n  background: rgba(152, 166, 173, 0.15);\n  transition-duration: 0.05s;\n}\n.message-list li.unread a {\n  font-weight: 600;\n  color: #272e37 !important;\n}\n.message-list li.blue-dot .col-mail-1 .dot {\n  border-color: #5d6dc3;\n}\n.message-list li.orange-dot .col-mail-1 .dot {\n  border-color: #f9bc0b;\n}\n.message-list li.green-dot .col-mail-1 .dot {\n  border-color: #3ec396;\n}\n.message-list .checkbox-wrapper-mail {\n  cursor: pointer;\n  height: 20px;\n  width: 20px;\n  position: relative;\n  display: inline-block;\n  box-shadow: inset 0 0 0 1px #98a6ad;\n  border-radius: 1px;\n}\n.message-list .checkbox-wrapper-mail input {\n  opacity: 0;\n  cursor: pointer;\n}\n.message-list .checkbox-wrapper-mail input:checked label {\n  opacity: 1;\n}\n.message-list .checkbox-wrapper-mail label {\n  position: absolute;\n  top: 3px;\n  left: 3px;\n  right: 3px;\n  bottom: 3px;\n  cursor: pointer;\n  background: #98a6ad;\n  opacity: 0;\n  margin-bottom: 0 !important;\n  transition-duration: 0.05s;\n}\n.message-list .checkbox-wrapper-mail label:active {\n  background: #87949b;\n}\n.mail-list a {\n  font-family: \"Roboto\", sans-serif;\n  vertical-align: middle;\n  color: #797979;\n  padding: 10px 15px;\n  display: block;\n}\n@media (max-width: 648px) {\n  .inbox-leftbar {\n    width: 100%;\n  }\n  .inbox-rightbar {\n    margin-left: 0;\n  }\n}\n@media (max-width: 520px) {\n  .message-list li .col-mail-1 {\n    width: 150px;\n  }\n  .message-list li .col-mail-1 .title {\n    left: 80px;\n  }\n  .message-list li .col-mail-2 {\n    left: 160px;\n  }\n  .message-list li .col-mail-2 .date {\n    text-align: right;\n    padding-right: 10px;\n    padding-left: 20px;\n  }\n}\n.progress-bar {\n  background-color: #4680ff;\n}\n.progress-bar-primary {\n  background-color: #4680ff;\n}\n.progress-bar-success {\n  background-color: #26dad2;\n}\n.progress-bar-info {\n  background-color: #62d1f3;\n}\n.progress-bar-danger {\n  background-color: #fc6180;\n}\n.progress-bar-warning {\n  background-color: #ffb64d;\n}\n.progress-bar-pink {\n  background-color: #e6a1f2;\n}\n.progress {\n  height: 6px;\n}\n.progress-bar.active,\n.progress.active .progress-bar {\n  animation: 2s linear 0s normal none infinite running progress-bar-stripes;\n}\n.progress-vertical {\n  display: inline-block;\n  height: 250px;\n  margin-bottom: 0;\n  margin-right: 20px;\n  min-height: 250px;\n  position: relative;\n}\n.progress-vertical-bottom {\n  display: inline-block;\n  height: 250px;\n  margin-bottom: 0;\n  margin-right: 20px;\n  min-height: 250px;\n  position: relative;\n  transform: rotate(180deg);\n}\n.progress-animated {\n  animation-duration: 5s;\n  animation-name: myanimation;\n  transition: all 5s ease 0s;\n}\n@keyframes myanimation {\n  0% {\n    width: 0;\n  }\n}\n@keyframes myanimation {\n  0% {\n    width: 0;\n  }\n}\n.browser .progress {\n  height: 8px;\n}\n.tdl-holder {\n  margin: 0 auto;\n}\n.tdl-holder ul {\n  list-style: none;\n  margin: 0;\n  padding: 0;\n}\n.tdl-holder li {\n  background-color: transparent;\n  list-style: outside none none;\n  margin: 0;\n  padding: 10px 0;\n}\n.tdl-holder li span {\n  margin-left: 30px;\n  font-family: 'Poppins', sans-serif;\n  vertical-align: middle;\n  -webkit-transition: all 0.2s linear;\n  -moz-transition: all 0.2s linear;\n  -o-transition: all 0.2s linear;\n  transition: all 0.2s linear;\n}\n.tdl-holder label {\n  cursor: pointer;\n  display: block;\n  line-height: 40px;\n  padding: 0 15px;\n  position: relative;\n  margin: 0 !important;\n}\n.tdl-holder label:hover {\n  background-color: #eef5f9;\n  color: #99abb4;\n}\n.tdl-holder label:hover a {\n  display: block;\n}\n.tdl-holder label a {\n  border-radius: 50%;\n  color: #99abb4;\n  display: none;\n  float: right;\n  font-weight: bold;\n  line-height: normal;\n  height: 16px;\n  margin-top: 15px;\n  text-align: center;\n  text-decoration: none;\n  width: 16px;\n  -webkit-transition: all 0.2s linear;\n  -moz-transition: all 0.2s linear;\n  -o-transition: all 0.2s linear;\n  transition: all 0.2s linear;\n}\n.tdl-holder input[type=\"checkbox\"] {\n  cursor: pointer;\n  opacity: 0;\n  position: absolute;\n}\n.tdl-holder input[type=\"checkbox\"] + i {\n  background-color: #ffffff;\n  display: block;\n  height: 18px;\n  position: absolute;\n  top: 15px;\n  width: 18px;\n  z-index: 1;\n}\n.tdl-holder input[type=\"checkbox\"]:checked + i::after {\n  content: \"\\e64c\";\n  font-family: 'themify';\n  display: block;\n  left: 0;\n  position: absolute;\n  top: -17px;\n  z-index: 2;\n}\n.tdl-holder input[type=\"checkbox\"]:checked ~ span {\n  text-decoration: line-through;\n}\n.tdl-holder input[type=\"text\"] {\n  height: 60px;\n  margin-top: 20px;\n  font-size: 14px;\n}\n.datamap-sales-hover-tooltip {\n  background: #444c67;\n  font-family: 'Poppins', sans-serif;\n  padding: 5px 10px;\n  color: #ffffff;\n  font-weight: 400;\n  font-size: 12px;\n  text-transform: capitalize;\n  border-radius: 3px;\n}\nthead tr th {\n  color: #455a64;\n  font-weight: 500;\n  text-align: center;\n}\ntbody tr th {\n  color: #455a64;\n  font-family: 'Poppins', sans-serif;\n  font-weight: normal;\n  text-align: center;\n}\ntbody tr td {\n  font-family: 'Poppins', sans-serif;\n  color: #000000;\n  text-align: center;\n}\n.table > tbody > tr > td,\n.table > tbody > tr > th,\n.table > tfoot > tr > td,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > thead > tr > th {\n  line-height: 32px;\n  vertical-align: top;\n}\n.table > thead > tr > th {\n  border-bottom: 1px solid #e7e7e7;\n  font-weight: 600;\n}\n.table {\n  margin-bottom: 0;\n}\n.table .badge {\n  text-transform: uppercase;\n}\n.student-data-table label {\n  margin-right: 7px;\n}\n.student-data-table td span a {\n  padding: 3px;\n}\n.search-action {\n  bottom: 0;\n  display: inline-block;\n  position: absolute;\n  right: 92px;\n  text-align: right;\n}\n.search-type .form-control {\n  height: 30px;\n}\n@media (max-width: 1199px) {\n  .search-action {\n    text-align: center;\n    position: relative;\n    right: 0;\n  }\n  .search-type .form-control {\n    margin-bottom: 8px;\n    margin-top: 8px;\n  }\n}\n.table td,\n.table th {\n  padding: 0.55rem;\n}\n.table .round-img img {\n  width: 38px;\n}\n.current-progress {\n  margin-top: 15px;\n}\n.progress-content {\n  margin-bottom: 20px;\n}\n.progress-content:last-child {\n  margin-bottom: 0px;\n}\n.current-progressbar {\n  margin-top: 3px;\n}\n.current-progressbar .progress {\n  height: 15px;\n  margin: 0px;\n  box-shadow: none;\n}\n.current-progressbar .progress-bar {\n  box-shadow: 0px;\n  line-height: 14px;\n  font-size: 11px;\n  box-shadow: none;\n}\n.login-logo {\n  text-align: center;\n  margin-bottom: 15px;\n}\n.login-logo span {\n  color: #ffffff;\n  font-size: 24px;\n}\n.login-logo img {\n  height: 75px;\n}\n.login-content {\n  margin: 100px 0;\n}\n.login-form {\n  background: #ffffff;\n  padding: 30px 30px 20px;\n  border-radius: 2px;\n}\n.login-form h4 {\n  color: #455a64;\n  text-align: center;\n  margin-bottom: 50px;\n}\n.login-form .checkbox {\n  color: #455a64;\n}\n.login-form .checkbox label {\n  text-transform: none;\n}\n.login-form .btn {\n  width: 100%;\n  text-transform: uppercase;\n  font-size: 14px;\n  padding: 15px;\n  border: 0px;\n}\n.login-form label {\n  color: #455a64;\n  text-transform: uppercase;\n}\n.login-form label a {\n  color: #4680ff;\n}\n.social-login-content {\n  margin: 0px -30px;\n  border-top: 1px solid #e7e7e7;\n  border-bottom: 1px solid #e7e7e7;\n  padding: 30px 0px;\n  background: #fcfcfc;\n}\n.social-button {\n  padding: 0 30px;\n}\n.social-button i {\n  padding: 19px;\n}\n.register-link a {\n  color: #4680ff;\n}\n.cpu-load {\n  width: 100%;\n  height: 272px;\n  font-size: 14px;\n  line-height: 1.2em;\n}\n.cpu-load-data-content {\n  font-size: 18px;\n  font-weight: 400;\n  line-height: 40px;\n}\n.cpu-load-data {\n  margin-bottom: 30px;\n}\n.cpu-load-data li {\n  display: inline-block;\n  width: 32.5%;\n  text-align: center;\n  border-right: 1px solid #e7e7e7;\n}\n.cpu-load-data li:last-child {\n  border-right: 0px;\n}\n#barChart {\n  height: 400px!important;\n}\n.nestable-cart {\n  overflow: hidden;\n}\n.dd-handle,\n.dd3-content {\n  color: #000!important;\n}\n.profiletimeline {\n  border-left: 1px solid rgba(120, 130, 140, 0.13);\n  margin-left: 30px;\n  margin-right: 10px;\n  padding-left: 40px;\n  position: relative;\n}\n.profiletimeline .sl-left {\n  float: left;\n  margin-left: -60px;\n  margin-right: 15px;\n  z-index: 1;\n}\n.profiletimeline .sl-left img {\n  max-width: 40px;\n}\n.profiletimeline .sl-item {\n  margin-bottom: 30px;\n  margin-top: 8px;\n}\n.profiletimeline .sl-date {\n  color: #99abb4;\n  font-size: 12px;\n}\n.profiletimeline .time-item {\n  border-color: rgba(120, 130, 140, 0.13);\n  padding-bottom: 1px;\n  position: relative;\n}\n.profiletimeline .time-item::before {\n  content: \" \";\n  display: table;\n}\n.profiletimeline .time-item::after {\n  background-color: #ffffff;\n  border-color: rgba(120, 130, 140, 0.13);\n  border-radius: 10px;\n  border-style: solid;\n  border-width: 2px;\n  bottom: 0;\n  content: \"\";\n  height: 14px;\n  left: 0;\n  margin-left: -8px;\n  position: absolute;\n  top: 5px;\n  width: 14px;\n}\n.profiletimeline .time-item-item::after {\n  content: \" \";\n  display: table;\n}\n.profiletimeline .item-info {\n  margin-bottom: 15px;\n  margin-left: 15px;\n}\n.profiletimeline .item-info p {\n  margin-bottom: 10px !important;\n}\n.customtab li a.nav-link,\n.profile-tab li a.nav-link {\n  border: 0 none;\n  color: #455a64;\n  padding: 15px 20px;\n}\n.customtab li a.nav-link.active,\n.profile-tab li a.nav-link.active {\n  border-bottom: 2px solid #1976d2;\n  color: #1976d2;\n}\n.card-two {\n  position: relative;\n  margin: 0 !important;\n  border: 0;\n}\n.card-two header {\n  position: relative;\n  width: 100%;\n  height: 60px;\n}\n.card-two header .avatar {\n  position: absolute;\n  left: 50%;\n  top: 30px;\n  margin-left: -50px;\n  z-index: 5;\n  width: 100px;\n  height: 100px;\n  border-radius: 50%;\n  overflow: hidden;\n  background: #ccc;\n  border: 3px solid #fff;\n}\n.card-two header .avatar img {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  -webkit-transform: translate(-50%, -50%);\n  transform: translate(-50%, -50%);\n  width: 100px;\n  height: auto;\n}\n.card-two h3 {\n  position: relative;\n  margin: 80px 0 30px;\n  text-align: center;\n}\n.card-two h3::after {\n  content: '';\n  position: absolute;\n  bottom: -15px;\n  left: 50%;\n  margin-left: -15px;\n  width: 30px;\n  height: 1px;\n  background: #000;\n}\n.card-two .desc {\n  padding: 0 1rem 2rem;\n  text-align: center;\n  line-height: 1.5;\n  color: #777;\n}\n.card-two .contacts {\n  width: 200px;\n  max-width: 100%;\n  margin: 0 auto 3.5rem;\n}\n.card-two .contacts a {\n  display: block;\n  width: 33.333333%;\n  float: left;\n  text-align: center;\n  color: #1976d2;\n}\n.card-two .contacts a:hover {\n  color: #333;\n}\n.card-two .contacts a:hover .fa::before {\n  color: #fff;\n}\n.card-two .contacts a:hover .fa::after {\n  top: 0;\n}\n.card-two .contacts a .fa {\n  position: relative;\n  width: 40px;\n  height: 40px;\n  line-height: 39px;\n  overflow: hidden;\n  text-align: center;\n  border: 2px solid #1976d2;\n  border-radius: 50%;\n}\n.card-two .contacts a .fa:before {\n  position: relative;\n  z-index: 1;\n}\n.card-two .contacts a .fa::after {\n  content: '';\n  position: absolute;\n  top: -50px;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  -webkit-transition: top 0.3s;\n  transition: top 0.3s;\n  background: #1976d2;\n}\n.card-two .contacts a:last-of-type .fa {\n  line-height: 36px;\n}\n.profile-widget-one .profile-one-bg {\n  position: relative;\n}\n.profile-widget-one .profile-one-user-photo {\n  position: relative;\n}\n.profile-widget-one .profile-one-user-photo .bg-overlay {\n  background: rgba(0, 0, 0, 0.6);\n  bottom: 0;\n  left: 0;\n  position: absolute;\n  right: 0;\n  top: 0;\n}\n.profile-widget-one .profile-one-user-photo .user-photo {\n  bottom: 0;\n  height: 100%;\n  position: absolute;\n  text-align: center;\n  top: 0;\n  width: 100%;\n}\n.profile-widget-one .profile-one-user-photo .user-photo img {\n  border-radius: 100px;\n  height: 100px;\n  position: relative;\n  top: 50%;\n  transform: translateY(-50%);\n  width: 100px;\n}\n.profile-widget-one .profile-one-user-content ul li {\n  background: #ffffff;\n  border-right: 1px solid #e7e7e7;\n  border-bottom: 1px solid #e7e7e7;\n  display: block;\n  float: left;\n  padding: 10px 0;\n  text-align: center;\n  width: 32%;\n}\n.profile-widget-one .profile-one-user-content ul li:last-child {\n  border-right: 0px;\n}\n.profile-widget-one .profile-one-user-content h4 {\n  line-height: 30px;\n  font-size: 14px;\n  margin: 0px;\n}\n.profile-widget-one .profile-one-user-content .earning-amount,\n.profile-widget-one .profile-one-user-content .sold-amount {\n  color: #26dad2;\n  font-size: 24px;\n  font-weight: 400;\n  margin-top: 10px;\n}\n.profile-widget-one .profile-one-user-content .sold-amount {\n  color: #4680ff;\n  font-size: 24px;\n  font-weight: 400;\n  margin-top: 10px;\n}\n.profile-widget-one .profile-one-user-button {\n  text-align: center;\n  padding: 26px 0px;\n}\n.profile-widget-one .profile-btn-one {\n  font-size: 18px;\n  text-transform: uppercase;\n  padding: 8px 15px;\n  font-weight: 400;\n  color: #4680ff;\n}\n/*Aleart\n-------------*/\n.alert-primary {\n  background-color: #a2bfff;\n  border-color: #a2bfff;\n  color: #4680ff;\n}\n.alert-success {\n  background-color: #93ede9;\n  border-color: #93ede9;\n  color: #26dad2;\n}\n.alert-warning {\n  background-color: #ffeacd;\n  border-color: #ffeacd;\n  color: #ffb64d;\n}\n.alert-danger {\n  background-color: #fedee5;\n  border-color: #fedee5;\n  color: #fc6180;\n}\n.alert-pink {\n  background-color: #f8e4fb;\n  border-color: #f8e4fb;\n  color: #e6a1f2;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n  color: rgba(0, 0, 0, 0.8);\n}\n/*    Labels\n------------------*/\n.label-default {\n  background-color: #878787;\n}\n.label-primary {\n  background-color: #4680ff;\n}\n.label-success {\n  background-color: #26dad2;\n}\n.label-info {\n  background-color: #62d1f3;\n}\n.label-danger {\n  background-color: #fc6180;\n}\n.label-warning {\n  background-color: #ffb64d;\n}\n/* Calendar\n================================================== */\n/* =============\n   Calendar\n============= */\n.calendar {\n  float: left;\n  margin-bottom: 0px;\n}\n.fc-view {\n  margin-top: 30px;\n}\n.none-border .modal-footer {\n  border-top: none;\n}\n.fc-toolbar {\n  margin-bottom: 5px;\n  margin-top: 15px;\n}\n.fc-toolbar h2 {\n  font-size: 18px;\n  font-weight: 600;\n  line-height: 30px;\n  text-transform: uppercase;\n}\n.fc-day {\n  background: #ffffff;\n}\n.fc-toolbar .fc-state-active,\n.fc-toolbar .ui-state-active,\n.fc-toolbar button:focus,\n.fc-toolbar button:hover,\n.fc-toolbar .ui-state-hover {\n  z-index: 0;\n}\n.fc-widget-header {\n  border: 1px solid #e7e7e7;\n}\n.fc-widget-content {\n  border: 1px solid #e7e7e7;\n}\n.fc th.fc-widget-header {\n  background: #e7e7e7;\n  font-size: 14px;\n  line-height: 20px;\n  padding: 10px 0px;\n  text-transform: uppercase;\n}\n.fc-button {\n  background: #ffffff;\n  border: 1px solid #e7e7e7;\n  color: #455a64;\n  text-transform: capitalize;\n}\n.fc-text-arrow {\n  font-family: inherit;\n  font-size: 16px;\n}\n.fc-state-hover {\n  background: #eef5f9 !important;\n}\n.fc-state-highlight {\n  background: #eef5f9 !important;\n}\n.fc-cell-overlay {\n  background: #eef5f9 !important;\n}\n.fc-unthemed .fc-today {\n  background: #ffffff !important;\n}\n.fc-event {\n  border-radius: 2px;\n  border: none;\n  cursor: move;\n  font-size: 13px;\n  margin: 5px 7px;\n  padding: 5px 5px;\n  text-align: center;\n}\n.external-event {\n  color: #ffffff;\n  cursor: move;\n  margin: 10px 0;\n  padding: 6px 10px;\n}\n.fc-basic-view td.fc-week-number span {\n  padding-right: 5px;\n}\n.fc-basic-view td.fc-day-number {\n  padding-right: 5px;\n}\n#drop-remove {\n  margin: 0px;\n  top: 3px;\n}\n#event-modal .modal-dialog,\n#add-category .modal-dialog {\n  max-width: 600px;\n}\n.flotTip {\n  background: #252525;\n  border: 1px solid #252525;\n  padding: 5px 15px;\n  color: #ffffff;\n}\n.flot-container {\n  box-sizing: border-box;\n  width: 100%;\n  height: 275px;\n  padding: 20px 15px 15px;\n  margin: 15px auto 30px;\n  background: transparent;\n}\n.flot-pie-container {\n  height: 275px;\n}\n.flotBar-container {\n  height: 275px;\n}\n.flot-line {\n  width: 100%;\n  height: 100%;\n  font-size: 14px;\n  line-height: 1.2em;\n}\n.legend table {\n  border-spacing: 5px;\n}\n#chart1,\n#flotBar,\n#flotCurve {\n  width: 100%;\n  height: 275px;\n}\n.cpu-load {\n  height: 345px;\n}\n.morris-hover {\n  position: absolute;\n  z-index: 1;\n}\n.morris-hover.morris-default-style .morris-hover-row-label {\n  font-weight: bold;\n  margin: 0.25em 0;\n}\n.morris-hover.morris-default-style .morris-hover-point {\n  white-space: nowrap;\n  margin: 0.1em 0;\n}\n.morris-hover.morris-default-style {\n  border-radius: 2px;\n  padding: 10px 12px;\n  color: #666;\n  background: rgba(0, 0, 0, 0.7);\n  border: none;\n  color: #fff!important;\n}\n.morris-hover-point {\n  color: rgba(255, 255, 255, 0.8) !important;\n}\n#morris-bar-chart,\n#morris-line-chart {\n  height: 300px;\n}\n.products_1 {\n  padding-top: 5px;\n  padding-bottom: 5px;\n}\n.products_1 .pr_img_price {\n  position: relative;\n}\n.products_1 .pr_img_price .product_price {\n  min-width: 50px;\n  min-height: 50px;\n  background: #26dad2;\n  border-radius: 100%;\n  position: absolute;\n  top: 0;\n  right: 0;\n}\n.products_1 .pr_img_price .product_price p {\n  padding-top: 15px;\n  color: #ffffff;\n  font-size: 14px;\n  font-weight: 600;\n}\n.products_1 .product_details .product_name {\n  padding-top: 30px;\n}\n.products_1 .product_details .prdt_add_to_cart {\n  padding-top: 10px;\n}\n.products_1 .product_details .prdt_add_to_cart button {\n  padding: 10px 20px;\n  text-transform: uppercase;\n  font-weight: 600;\n}\n.product-2-details .table > tbody > tr > td {\n  border: none;\n}\n.product-2-details .product-2-des {\n  margin-top: 25px;\n}\n.product-2-details .product-2-des .product_name h4 {\n  font-size: 15px;\n  font-weight: 600;\n}\n.product-2-details .product-2-des .product_des p {\n  font-size: 13px;\n  font-style: italic;\n}\n.product-2-details .product-2-button {\n  border-left: 1px solid #e7e7e7;\n  margin-top: 25px;\n}\n.product-2-details .product-2-button .prdt_add_to_curt {\n  padding-top: 10px;\n}\n.product-2-details .product-2-button .prdt_add_to_curt button {\n  font-size: 11px;\n  text-transform: uppercase;\n  font-weight: 600;\n}\n.product-3-img img {\n  width: 100%;\n}\n.product_details_3 {\n  padding: 15px 0px;\n}\n.product_details_3 .product_name h4 {\n  font-size: 15px;\n  font-weight: 600;\n}\n.product_details_3 .product_des {\n  padding-bottom: 5px;\n}\n.product_details_3 .prdt_add_to_curt {\n  padding-top: 10px;\n}\n.product_details_3 .prdt_add_to_curt button {\n  text-transform: uppercase;\n  font-weight: 600;\n}\n.favourite-menu-details .table > tbody > tr > td {\n  border-top: none;\n  border-bottom: 1px solid #e7e7e7;\n}\n.favourite-menu-details .favourite-menu-img {\n  border-right: 1px solid #e7e7e7;\n  margin-bottom: 25px;\n  width: 120px;\n}\n.favourite-menu-details .favourite-menu-des {\n  margin-top: 40px;\n  margin-right: 465px;\n}\n.favourite-menu-details .favourite-menu-des .product_name h4 {\n  font-weight: 600;\n  text-align: left;\n}\n.favourite-menu-details .favourite-menu-button {\n  margin-top: 40px;\n}\n.favourite-menu-details .favourite-menu-button .prdt_add_to_curt {\n  padding-top: 10px;\n}\n.favourite-menu-details .favourite-menu-button .prdt_add_to_curt button {\n  font-size: 11px;\n  text-transform: uppercase;\n  font-weight: 600;\n}\n.order-list-item table tbody > tr > td {\n  padding-top: 8px;\n  border-top: 1px solid #e7e7e7;\n}\n.order-list-item table thead > tr > th {\n  border-bottom: 1px solid #e7e7e7;\n}\n.order-list-item thead {\n  background: #4680ff;\n  text-align: left;\n}\n.order-list-item thead th {\n  color: #ffffff;\n  font-weight: bold;\n}\n.order-list-item tbody {\n  background: #ffffff;\n  text-align: left;\n}\n.order-list-item tbody td {\n  color: #444444;\n}\n.booking-system-feedback {\n  top: 5px !important;\n  right: 15px;\n}\n.booking-system-top {\n  padding-top: 15px;\n}\n.media-body {\n  vertical-align: middle;\n}\n.media-body span {\n  font-size: 10px;\n  color: #4680ff;\n}\n.media-body p {\n  color: #99abb4;\n  line-height: 15px;\n}\n.example {\n  overflow: hidden;\n  border: 1px solid #e7e7e7;\n  -webkit-box-shadow: 1px 1px 2px 0px rgba(200, 200, 200, 0.3);\n  -moz-box-shadow: 1px 1px 2px 0px rgba(200, 200, 200, 0.3);\n  box-shadow: 1px 1px 2px 0px rgba(200, 200, 200, 0.3);\n  background-color: #eef5f9;\n  text-align: justify;\n}\n.example p {\n  padding: 20px 20px 0px 20px;\n  font-size: 12px;\n}\n.box,\n.simple {\n  height: 300px;\n}\n.scrollable-auto-x {\n  overflow-x: auto;\n  overflow-y: hidden;\n}\n.scrollable-auto-y {\n  overflow-y: auto;\n  overflow-x: hidden;\n}\n.scrollable-auto {\n  overflow: auto;\n}\n.vmap {\n  width: 100%;\n  height: 400px;\n}\n.dark-browse-input-box {\n  border-radius: 0;\n  -webkit-border-radius: 0 !important;\n  -moz-border-radius: 0 !important;\n  -webkit-box-shadow: none !important;\n  -moz-box-shadow: none !important;\n  box-shadow: none !important;\n  font-size: 12px;\n  color: #000000;\n  border: 1px solid #e7e7e7;\n}\n.dark-browse-input-box .dark-input-button {\n  border-radius: 0;\n  -webkit-border-radius: 0 !important;\n  -moz-border-radius: 0 !important;\n  background: #ffffff;\n  border: none !important;\n  color: #4680ff;\n}\n.dark-browse-input-box .dark-input-button i {\n  font-weight: bold;\n  font-size: 17px;\n}\n.dark-browse-input-box .dark-input-button:hover {\n  background: #ffffff;\n  color: #4680ff;\n  -webkit-transition: all 0.3s;\n  -moz-transition: all 0.3s;\n  transition: all 0.3s;\n  border: none !important;\n}\n.dark-browse-input-box .dark-input-button:focus {\n  outline: none;\n  border: none !important;\n  background: none !important;\n}\n.file-input {\n  position: relative;\n  font-size: 14px;\n}\n.file-input label {\n  position: absolute;\n  top: -2px;\n  right: 0;\n  bottom: 0;\n  margin: 0;\n}\n.file-input label:focus {\n  outline: none;\n  border: none !important;\n  background: none !important;\n}\n.file-input .btn {\n  position: absolute;\n  right: 6px;\n  top: 7px;\n  bottom: 6px;\n  max-width: 100px;\n  padding-top: 0;\n  padding-bottom: 0;\n  font-size: 12px;\n  line-height: 32px;\n}\n.file-input .btn input {\n  width: 0;\n  height: 0;\n}\n.file-input .file-name {\n  float: left;\n  width: 100%;\n  border: 0;\n  background: transparent;\n}\n.media-stats-content .stats-content {\n  padding: 30px 0px;\n}\n.media-stats-content .stats-content .stats-digit {\n  font-size: 24px;\n  font-weight: 300;\n  margin-bottom: 10px;\n}\n.media-stats-content .stats-content .stats-text {\n  font-size: 14px;\n}\n.media-stats-content .stats-content .table td {\n  line-height: 40px!important;\n}\n.carousel.vertical .carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n}\n.carousel.vertical .carousel-inner > .item {\n  display: none;\n  position: relative;\n  transition: top 0.6s ease-in-out;\n}\n.carousel.vertical .carousel-inner > .item > img,\n.carousel.vertical .carousel-inner > .item > a > img {\n  line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n  .carousel.vertical .carousel-inner > .item {\n    transition: transform 0.6s ease-in-out;\n    backface-visibility: hidden;\n    perspective: 1000;\n  }\n  .carousel.vertical .carousel-inner > .item.next,\n  .carousel.vertical .carousel-inner > .item.active.right {\n    transform: translate3d(0, 100%, 0);\n    top: 0;\n  }\n  .carousel.vertical .carousel-inner > .item.prev,\n  .carousel.vertical .carousel-inner > .item.active.left {\n    transform: translate3d(0, -100%, 0);\n    top: 0;\n  }\n  .carousel.vertical .carousel-inner > .item.next.left,\n  .carousel.vertical .carousel-inner > .item.prev.right,\n  .carousel.vertical .carousel-inner > .item.active {\n    transform: translate3d(0, 0, 0);\n    top: 0;\n    width: 100%;\n  }\n}\n.carousel.vertical .carousel-inner > .active,\n.carousel.vertical .carousel-inner > .next,\n.carousel.vertical .carousel-inner > .prev {\n  display: block;\n}\n.carousel.vertical .carousel-inner > .active {\n  top: 0;\n}\n.carousel.vertical .carousel-inner > .next,\n.carousel.vertical .carousel-inner > .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n.carousel.vertical .carousel-inner > .next {\n  top: 100%;\n}\n.carousel.vertical .carousel-inner > .prev {\n  top: -100%;\n}\n.carousel.vertical .carousel-inner > .next.left,\n.carousel.vertical .carousel-inner > .prev.right {\n  top: 0;\n}\n.carousel.vertical .carousel-inner > .active.left {\n  top: -100%;\n}\n.carousel.vertical .carousel-inner > .active.right {\n  top: 100%;\n}\n.ct-label {\n  color: rgba(0, 0, 0, 0.8);\n  fill: rgba(0, 0, 0, 0.8);\n  font-size: 10px;\n}\n.ct-chart-pie .ct-label {\n  color: rgba(0, 0, 0, 0.8);\n  fill: rgba(0, 0, 0, 0.8);\n  font-size: 12px;\n}\n.ct-series-a .ct-bar,\n.ct-series-a .ct-line,\n.ct-series-a .ct-point,\n.ct-series-a .ct-slice-donut {\n  stroke: #26dad2;\n}\n.ct-series-b .ct-bar,\n.ct-series-b .ct-line,\n.ct-series-b .ct-point,\n.ct-series-b .ct-slice-donut {\n  stroke: #4680ff;\n}\n.ct-series-c .ct-bar,\n.ct-series-c .ct-line,\n.ct-series-c .ct-point,\n.ct-series-c .ct-slice-donut {\n  stroke: #fc6180;\n}\n.ct-series-d .ct-bar,\n.ct-series-d .ct-line,\n.ct-series-d .ct-point,\n.ct-series-d .ct-slice-donut {\n  stroke: #ffb64d;\n}\n.ct-series-a .ct-area,\n.ct-series-a .ct-slice-donut-solid,\n.ct-series-a .ct-slice-pie {\n  fill: #26dad2;\n}\n.ct-series-b .ct-area,\n.ct-series-b .ct-slice-donut-solid,\n.ct-series-b .ct-slice-pie {\n  fill: #4680ff;\n}\n.ct-series-c .ct-area,\n.ct-series-c .ct-slice-donut-solid,\n.ct-series-c .ct-slice-pie {\n  fill: #fc6180;\n}\n@media (max-width: 667px) {\n  .dt-buttons {\n    margin-left: 10px;\n  }\n}\n@media (max-width: 480px) {\n  .dt-buttons {\n    display: inline-block;\n  }\n}\n.pace {\n  -webkit-pointer-events: none;\n  pointer-events: none;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  user-select: none;\n}\n.pace-inactive {\n  display: none;\n}\n.pace .pace-progress {\n  background: #26dad2;\n  position: fixed;\n  z-index: 2000;\n  top: 0;\n  right: 100%;\n  width: 100%;\n  height: 2px;\n}\n.pace .pace-progress-inner {\n  display: block;\n  position: absolute;\n  right: 0px;\n  width: 100px;\n  height: 100%;\n  box-shadow: 0 0 10px #29d, 0 0 5px #29d;\n  opacity: 1.0;\n  -webkit-transform: rotate(3deg) translate(0px, -4px);\n  -moz-transform: rotate(3deg) translate(0px, -4px);\n  -ms-transform: rotate(3deg) translate(0px, -4px);\n  -o-transform: rotate(3deg) translate(0px, -4px);\n  transform: rotate(3deg) translate(0px, -4px);\n}\n.pace .pace-activity {\n  display: block;\n  position: fixed;\n  z-index: 2000;\n  top: 5px;\n  right: 5px;\n  width: 14px;\n  height: 14px;\n  border: solid 2px transparent;\n  border-top-color: #26dad2;\n  border-left-color: #26dad2;\n  border-radius: 10px;\n  -webkit-animation: pace-spinner 400ms linear infinite;\n  -moz-animation: pace-spinner 400ms linear infinite;\n  -ms-animation: pace-spinner 400ms linear infinite;\n  -o-animation: pace-spinner 400ms linear infinite;\n  animation: pace-spinner 400ms linear infinite;\n}\n@-webkit-keyframes pace-spinner {\n  0% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-moz-keyframes pace-spinner {\n  0% {\n    -moz-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -moz-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-o-keyframes pace-spinner {\n  0% {\n    -o-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -o-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-ms-keyframes pace-spinner {\n  0% {\n    -ms-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -ms-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@keyframes pace-spinner {\n  0% {\n    transform: rotate(0deg);\n  }\n  100% {\n    transform: rotate(360deg);\n  }\n}\n.superpose {\n  color: #EEE;\n  height: 350px;\n  width: 100%;\n}\n.superclock {\n  position: relative;\n  width: 300px;\n  margin: auto;\n}\n.superclock1 {\n  position: absolute;\n  left: 10px;\n  top: 10px;\n}\n.superclock2 {\n  position: absolute;\n  left: 60px;\n  top: 60px;\n}\n.superclock3 {\n  position: absolute;\n  left: 110px;\n  top: 110px;\n}\n.header-search {\n  float: right;\n  margin-left: 15px;\n  position: relative;\n}\n.header-search .form-control {\n  height: 36px;\n  width: 250px;\n  border-radius: 5px;\n  font-size: 14px;\n}\n.header-search i {\n  position: absolute;\n  right: 5px;\n  top: 5px;\n  cursor: pointer;\n  height: 30px;\n  padding: 5px;\n  width: 30px;\n}\n.media-text-right {\n  text-align: right;\n}\n.media-text-left {\n  text-align: left;\n}\n.boxshadow-none {\n  box-shadow: none;\n}\n.progress-sm {\n  height: 8px;\n}\n.bg-warning-dark {\n  background: #e7b63a;\n}\n.bg-info-dark {\n  background: #8b67c9;\n}\n.bg-danger-dark {\n  background: #e63327;\n}\n.bg-success-dark {\n  background: #2ed3aa;\n}\n.bg-primary-dark {\n  background: #0095e1;\n}\n.widget-card-circle i {\n  font-size: 30px;\n  left: 0;\n  line-height: 97px;\n  right: 0;\n  text-align: center;\n}\n.widget-line-list li {\n  display: inline-block;\n  font-size: 1.2em;\n  line-height: 27px;\n  padding: 5px 20px 0 15px;\n}\n.widget-line-list li span {\n  font-size: 14px;\n}\n.height-150 {\n  height: 150px;\n}\n.social-connect ul li {\n  display: inline-block;\n}\n.social-connect ul li a {\n  display: inline-block;\n  margin: 0 5px;\n  padding: 12px 15px;\n  border-radius: 4px;\n}\n.user-card-absolute {\n  top: 115px;\n  left: 0;\n  right: 0;\n}\n.box-shadow {\n  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);\n}\n.social-pad {\n  padding: 40px 30px 110px;\n}\n.round-img img {\n  border-radius: 100px;\n}\n.blockquote-box {\n  border-right: 5px solid #E6E6E6;\n  margin-bottom: 25px;\n}\n.blockquote-box .square {\n  width: 100px;\n  min-height: 50px;\n  margin-right: 22px;\n  text-align: center!important;\n  background-color: #E6E6E6;\n  padding: 20px 0;\n}\n.blockquote-box .blockquote-primary {\n  border-color: #4680ff;\n}\n.blockquote-box .blockquote-primary .square {\n  background-color: #4680ff;\n  color: #ffffff;\n}\n.blockquote-box .blockquote-success {\n  border-color: #26dad2;\n}\n.blockquote-box .blockquote-success .square {\n  background-color: #26dad2;\n  color: #ffffff;\n}\n.blockquote-box .blockquote-info {\n  border-color: #62d1f3;\n}\n.blockquote-box .blockquote-info .square {\n  background-color: #62d1f3;\n  color: #ffffff;\n}\n.blockquote-box .blockquote-warning {\n  border-color: #ffb64d;\n}\n.blockquote-box .blockquote-warning .square {\n  background-color: #ffb64d;\n  color: #ffffff;\n}\n.blockquote-box .blockquote-danger {\n  border-color: #d43f3a;\n}\n.blockquote-box .blockquote-danger .square {\n  background-color: #fc6180;\n  color: #ffffff;\n}\n.error-box {\n  height: 100%;\n  position: fixed;\n  width: 100%;\n}\n.error-box .footer {\n  left: 0;\n  right: 0;\n  width: 100%;\n}\n.error-body {\n  left: 0;\n  position: absolute;\n  right: 0;\n  top: 50%;\n  transform: translateY(-50%);\n}\n.error-body h1 {\n  font-size: 150px;\n  font-weight: 900;\n  line-height: 210px;\n  color: #444c67;\n}\n/*\n/* Version: 1.0\n*/\n/*-------- css code for responsive layout  --------*/\n/*  To make Responsive\n---------------------------------------------------------------------- /\n*\t1 - media screen and (max-width: 1750px)\n*   2 - media screen and (max-width: 1680px)\n*   3 - media screen and (max-width: 1280px)\n*   4 - media screen and (max-width: 1199px)\n*   5 - media screen and (max-width: 1024px)\n*   6 - media screen and (max-width: 991px)\n*   7 - media screen and (max-width: 767px)\n*   8 - media screen and (max-width: 680px)\n*   9 - media screen and (max-width: 480px)\n*   10 - media screen and (max-width: 320px)\n*\n---------------------------------------------------------------------- */\n/*  1 - media screen and (max-width: 1750px)\n---------------------------------------------------------------------- */\n/*  1 - media screen and (max-width: 1750px)\n---------------------------------------------------------------------- */\n/*  1 - media screen and (max-width: 1750px) End\n---------------------------------------------------------------------- */\n/*  2 - media screen and (max-width: 1680px)\n---------------------------------------------------------------------- */\n/*  2 - media screen and (max-width: 1680px) End\n---------------------------------------------------------------------- */\n/*  3 - media screen and (max-width: 1280px)\n---------------------------------------------------------------------- */\n/*  3 - media screen and (max-width: 1280px) End\n---------------------------------------------------------------------- */\n/*  4 - media screen and (max-width: 1199px)\n---------------------------------------------------------------------- */\n/*  4 - media screen and (max-width: 1199px) End\n---------------------------------------------------------------------- */\n/*  5 - media screen and (max-width: 1024px)\n---------------------------------------------------------------------- */\n@media (min-width: 992px) and (max-width: 1199px) {\n  .title-margin-right {\n    margin-right: 7px !important;\n  }\n  .title-margin-left {\n    margin-left: 7px !important;\n  }\n}\n/*  5 - media screen and (max-width: 1024px) End\n---------------------------------------------------------------------- */\n/*  6 - media screen and (max-width: 991px)\n---------------------------------------------------------------------- */\n@media (min-width: 768px) and (max-width: 991px) {\n  .title-margin-right {\n    margin-right: 7px !important;\n  }\n  .title-margin-left {\n    margin-left: 7px !important;\n  }\n}\n/*  6 - media screen and (max-width: 991px) End\n---------------------------------------------------------------------- */\n/*  7 - media screen and (max-width: 767px)\n---------------------------------------------------------------------- */\n@media (min-width: 680px) and (max-width: 767px) {\n  .title-margin-right {\n    margin-right: 7px !important;\n  }\n  .title-margin-left {\n    margin-left: 7px !important;\n  }\n  .footer {\n    left: 0;\n  }\n}\n/*  7 - media screen and (max-width: 767px) End\n---------------------------------------------------------------------- */\n/*  8 - media screen and (max-width: 680px)\n---------------------------------------------------------------------- */\n@media (min-width: 480px) and (max-width: 679px) {\n  .title-margin-right {\n    margin-right: 7px !important;\n  }\n  .title-margin-left {\n    margin-left: 7px !important;\n  }\n  .inbox-pagination {\n    margin-top: 30px;\n    float: left !important;\n  }\n  .card-badge .label {\n    display: inline-block;\n    margin-bottom: 5px;\n    padding: 5px;\n  }\n  .mail-box .sm-side {\n    width: 100%;\n  }\n  .mail-box aside {\n    display: inline;\n  }\n  .footer {\n    left: 0;\n  }\n}\n/*  8 - media screen and (max-width: 680px) End\n---------------------------------------------------------------------- */\n/*  9 - media screen and (max-width: 480px)\n---------------------------------------------------------------------- */\n@media (min-width: 360px) and (max-width: 479px) {\n  .title-margin-right {\n    margin-right: 7px !important;\n  }\n  .title-margin-left {\n    margin-left: 7px !important;\n  }\n  #project {\n    margin-left: 0;\n  }\n  .fc-toolbar .fc-right {\n    float: left;\n    margin-top: 15px;\n  }\n  .card-badge .label {\n    display: inline-block;\n    margin-bottom: 5px;\n    padding: 5px;\n  }\n  .mail-box .sm-side {\n    width: 100%;\n  }\n  .mail-box aside {\n    display: inline;\n  }\n  .footer {\n    left: 0;\n  }\n}\n/*  9 - media screen and (max-width: 360px) End\n---------------------------------------------------------------------- */\n/*  10 - media screen and (max-width: 320px)\n---------------------------------------------------------------------- */\n@media (min-width: 320px) and (max-width: 359px) {\n  .title-margin-right {\n    margin-right: 7px !important;\n  }\n  .title-margin-left {\n    margin-left: 7px !important;\n  }\n  #project {\n    margin-left: 0;\n  }\n  .fc-toolbar .fc-right {\n    float: left;\n    margin-top: 15px;\n  }\n  .br-theme-bars-pill .br-widget a {\n    padding: 7px 12px;\n  }\n  .br-theme-bars-reversed .br-widget .br-current-rating {\n    padding: 0;\n  }\n  .alert-rating {\n    padding-bottom: 40px;\n  }\n  .card-badge .label {\n    display: inline-block;\n    margin-bottom: 5px;\n    padding: 5px;\n  }\n  .mail-box .sm-side {\n    width: 100%;\n  }\n  .mail-box aside {\n    display: inline;\n  }\n  .chk-group {\n    margin-bottom: 10px;\n  }\n\n  .inner-append {\n    position: relative;\n  }\n  .inner-append .append-btn {\n    position: absolute;\n    right: 0;\n    top: 0;\n  }\n  .input-text {\n    margin-bottom: 12px;\n  }\n  .footer {\n    left: 0;\n  }\n}\n/*  10 - media screen and (max-width: 320px)\n---------------------------------------------------------------------- */\n/*---------------------------------------------------------------*/\n/* Retina */\n/*---------------------------------------------------------------*/\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .default-logo {\n    display: none !important;\n  }\n  .retina-logo {\n    display: inline-block !important;\n  }\n}\n"
  },
  {
    "path": "static/css/sweetalert.css",
    "content": "body.stop-scrolling {\n  height: 100%;\n  overflow: hidden; }\n\n.sweet-overlay {\n  background-color: black;\n  /* IE8 */\n  -ms-filter: \"progid:DXImageTransform.Microsoft.Alpha(Opacity=40)\";\n  /* IE8 */\n  background-color: rgba(0, 0, 0, 0.4);\n  position: fixed;\n  left: 0;\n  right: 0;\n  top: 0;\n  bottom: 0;\n  display: none;\n  z-index: 10000; }\n\n.sweet-alert {\n  background-color: white;\n  font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;\n  width: 478px;\n  padding: 17px;\n  border-radius: 5px;\n  text-align: center;\n  position: fixed;\n  left: 50%;\n  top: 50%;\n  margin-left: -256px;\n  margin-top: -200px;\n  overflow: hidden;\n  display: none;\n  z-index: 99999; }\n  @media all and (max-width: 540px) {\n    .sweet-alert {\n      width: auto;\n      margin-left: 0;\n      margin-right: 0;\n      left: 15px;\n      right: 15px; } }\n  .sweet-alert h2 {\n    color: #575757;\n    font-size: 30px;\n    text-align: center;\n    font-weight: 600;\n    text-transform: none;\n    position: relative;\n    margin: 25px 0;\n    padding: 0;\n    line-height: 40px;\n    display: block; }\n  .sweet-alert p {\n    color: #797979;\n    font-size: 16px;\n    text-align: center;\n    font-weight: 300;\n    position: relative;\n    text-align: inherit;\n    float: none;\n    margin: 0;\n    padding: 0;\n    line-height: normal; }\n  .sweet-alert fieldset {\n    border: none;\n    position: relative; }\n  .sweet-alert .sa-error-container {\n    background-color: #f1f1f1;\n    margin-left: -17px;\n    margin-right: -17px;\n    overflow: hidden;\n    padding: 0 10px;\n    max-height: 0;\n    webkit-transition: padding 0.15s, max-height 0.15s;\n    transition: padding 0.15s, max-height 0.15s; }\n    .sweet-alert .sa-error-container.show {\n      padding: 10px 0;\n      max-height: 100px;\n      webkit-transition: padding 0.2s, max-height 0.2s;\n      transition: padding 0.25s, max-height 0.25s; }\n    .sweet-alert .sa-error-container .icon {\n      display: inline-block;\n      width: 24px;\n      height: 24px;\n      border-radius: 50%;\n      background-color: #ea7d7d;\n      color: white;\n      line-height: 24px;\n      text-align: center;\n      margin-right: 3px; }\n    .sweet-alert .sa-error-container p {\n      display: inline-block; }\n  .sweet-alert .sa-input-error {\n    position: absolute;\n    top: 29px;\n    right: 26px;\n    width: 20px;\n    height: 20px;\n    opacity: 0;\n    -webkit-transform: scale(0.5);\n    transform: scale(0.5);\n    -webkit-transform-origin: 50% 50%;\n    transform-origin: 50% 50%;\n    -webkit-transition: all 0.1s;\n    transition: all 0.1s; }\n    .sweet-alert .sa-input-error::before, .sweet-alert .sa-input-error::after {\n      content: \"\";\n      width: 20px;\n      height: 6px;\n      background-color: #f06e57;\n      border-radius: 3px;\n      position: absolute;\n      top: 50%;\n      margin-top: -4px;\n      left: 50%;\n      margin-left: -9px; }\n    .sweet-alert .sa-input-error::before {\n      -webkit-transform: rotate(-45deg);\n      transform: rotate(-45deg); }\n    .sweet-alert .sa-input-error::after {\n      -webkit-transform: rotate(45deg);\n      transform: rotate(45deg); }\n    .sweet-alert .sa-input-error.show {\n      opacity: 1;\n      -webkit-transform: scale(1);\n      transform: scale(1); }\n  .sweet-alert input {\n    width: 100%;\n    box-sizing: border-box;\n    border-radius: 3px;\n    border: 1px solid #d7d7d7;\n    height: 43px;\n    margin-top: 10px;\n    margin-bottom: 17px;\n    font-size: 18px;\n    box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.06);\n    padding: 0 12px;\n    display: none;\n    -webkit-transition: all 0.3s;\n    transition: all 0.3s; }\n    .sweet-alert input:focus {\n      outline: none;\n      box-shadow: 0px 0px 3px #c4e6f5;\n      border: 1px solid #b4dbed; }\n      .sweet-alert input:focus::-moz-placeholder {\n        transition: opacity 0.3s 0.03s ease;\n        opacity: 0.5; }\n      .sweet-alert input:focus:-ms-input-placeholder {\n        transition: opacity 0.3s 0.03s ease;\n        opacity: 0.5; }\n      .sweet-alert input:focus::-webkit-input-placeholder {\n        transition: opacity 0.3s 0.03s ease;\n        opacity: 0.5; }\n    .sweet-alert input::-moz-placeholder {\n      color: #bdbdbd; }\n    .sweet-alert input::-ms-clear {\n      display: none; }\n    .sweet-alert input:-ms-input-placeholder {\n      color: #bdbdbd; }\n    .sweet-alert input::-webkit-input-placeholder {\n      color: #bdbdbd; }\n  .sweet-alert.show-input input {\n    display: block; }\n  .sweet-alert .sa-confirm-button-container {\n    display: inline-block;\n    position: relative; }\n  .sweet-alert .la-ball-fall {\n    position: absolute;\n    left: 50%;\n    top: 50%;\n    margin-left: -27px;\n    margin-top: 4px;\n    opacity: 0;\n    visibility: hidden; }\n  .sweet-alert button {\n    background-color: #8CD4F5;\n    color: white;\n    border: none;\n    box-shadow: none;\n    font-size: 17px;\n    font-weight: 500;\n    -webkit-border-radius: 4px;\n    border-radius: 5px;\n    padding: 10px 32px;\n    margin: 26px 5px 0 5px;\n    cursor: pointer; }\n    .sweet-alert button:focus {\n      outline: none;\n      box-shadow: 0 0 2px rgba(128, 179, 235, 0.5), inset 0 0 0 1px rgba(0, 0, 0, 0.05); }\n    .sweet-alert button:hover {\n      background-color: #7ecff4; }\n    .sweet-alert button:active {\n      background-color: #5dc2f1; }\n    .sweet-alert button.cancel {\n      background-color: #C1C1C1; }\n      .sweet-alert button.cancel:hover {\n        background-color: #b9b9b9; }\n      .sweet-alert button.cancel:active {\n        background-color: #a8a8a8; }\n      .sweet-alert button.cancel:focus {\n        box-shadow: rgba(197, 205, 211, 0.8) 0px 0px 2px, rgba(0, 0, 0, 0.0470588) 0px 0px 0px 1px inset !important; }\n    .sweet-alert button[disabled] {\n      opacity: .6;\n      cursor: default; }\n    .sweet-alert button.confirm[disabled] {\n      color: transparent; }\n      .sweet-alert button.confirm[disabled] ~ .la-ball-fall {\n        opacity: 1;\n        visibility: visible;\n        transition-delay: 0s; }\n    .sweet-alert button::-moz-focus-inner {\n      border: 0; }\n  .sweet-alert[data-has-cancel-button=false] button {\n    box-shadow: none !important; }\n  .sweet-alert[data-has-confirm-button=false][data-has-cancel-button=false] {\n    padding-bottom: 40px; }\n  .sweet-alert .sa-icon {\n    width: 80px;\n    height: 80px;\n    border: 4px solid gray;\n    -webkit-border-radius: 40px;\n    border-radius: 40px;\n    border-radius: 50%;\n    margin: 20px auto;\n    padding: 0;\n    position: relative;\n    box-sizing: content-box; }\n    .sweet-alert .sa-icon.sa-error {\n      border-color: #F27474; }\n      .sweet-alert .sa-icon.sa-error .sa-x-mark {\n        position: relative;\n        display: block; }\n      .sweet-alert .sa-icon.sa-error .sa-line {\n        position: absolute;\n        height: 5px;\n        width: 47px;\n        background-color: #F27474;\n        display: block;\n        top: 37px;\n        border-radius: 2px; }\n        .sweet-alert .sa-icon.sa-error .sa-line.sa-left {\n          -webkit-transform: rotate(45deg);\n          transform: rotate(45deg);\n          left: 17px; }\n        .sweet-alert .sa-icon.sa-error .sa-line.sa-right {\n          -webkit-transform: rotate(-45deg);\n          transform: rotate(-45deg);\n          right: 16px; }\n    .sweet-alert .sa-icon.sa-warning {\n      border-color: #F8BB86; }\n      .sweet-alert .sa-icon.sa-warning .sa-body {\n        position: absolute;\n        width: 5px;\n        height: 47px;\n        left: 50%;\n        top: 10px;\n        -webkit-border-radius: 2px;\n        border-radius: 2px;\n        margin-left: -2px;\n        background-color: #F8BB86; }\n      .sweet-alert .sa-icon.sa-warning .sa-dot {\n        position: absolute;\n        width: 7px;\n        height: 7px;\n        -webkit-border-radius: 50%;\n        border-radius: 50%;\n        margin-left: -3px;\n        left: 50%;\n        bottom: 10px;\n        background-color: #F8BB86; }\n    .sweet-alert .sa-icon.sa-info {\n      border-color: #C9DAE1; }\n      .sweet-alert .sa-icon.sa-info::before {\n        content: \"\";\n        position: absolute;\n        width: 5px;\n        height: 29px;\n        left: 50%;\n        bottom: 17px;\n        border-radius: 2px;\n        margin-left: -2px;\n        background-color: #C9DAE1; }\n      .sweet-alert .sa-icon.sa-info::after {\n        content: \"\";\n        position: absolute;\n        width: 7px;\n        height: 7px;\n        border-radius: 50%;\n        margin-left: -3px;\n        top: 19px;\n        background-color: #C9DAE1;\n        left: 50%; }\n    .sweet-alert .sa-icon.sa-success {\n      border-color: #A5DC86; }\n      .sweet-alert .sa-icon.sa-success::before, .sweet-alert .sa-icon.sa-success::after {\n        content: '';\n        -webkit-border-radius: 40px;\n        border-radius: 40px;\n        border-radius: 50%;\n        position: absolute;\n        width: 60px;\n        height: 120px;\n        background: white;\n        -webkit-transform: rotate(45deg);\n        transform: rotate(45deg); }\n      .sweet-alert .sa-icon.sa-success::before {\n        -webkit-border-radius: 120px 0 0 120px;\n        border-radius: 120px 0 0 120px;\n        top: -7px;\n        left: -33px;\n        -webkit-transform: rotate(-45deg);\n        transform: rotate(-45deg);\n        -webkit-transform-origin: 60px 60px;\n        transform-origin: 60px 60px; }\n      .sweet-alert .sa-icon.sa-success::after {\n        -webkit-border-radius: 0 120px 120px 0;\n        border-radius: 0 120px 120px 0;\n        top: -11px;\n        left: 30px;\n        -webkit-transform: rotate(-45deg);\n        transform: rotate(-45deg);\n        -webkit-transform-origin: 0px 60px;\n        transform-origin: 0px 60px; }\n      .sweet-alert .sa-icon.sa-success .sa-placeholder {\n        width: 80px;\n        height: 80px;\n        border: 4px solid rgba(165, 220, 134, 0.2);\n        -webkit-border-radius: 40px;\n        border-radius: 40px;\n        border-radius: 50%;\n        box-sizing: content-box;\n        position: absolute;\n        left: -4px;\n        top: -4px;\n        z-index: 2; }\n      .sweet-alert .sa-icon.sa-success .sa-fix {\n        width: 5px;\n        height: 90px;\n        background-color: white;\n        position: absolute;\n        left: 28px;\n        top: 8px;\n        z-index: 1;\n        -webkit-transform: rotate(-45deg);\n        transform: rotate(-45deg); }\n      .sweet-alert .sa-icon.sa-success .sa-line {\n        height: 5px;\n        background-color: #A5DC86;\n        display: block;\n        border-radius: 2px;\n        position: absolute;\n        z-index: 2; }\n        .sweet-alert .sa-icon.sa-success .sa-line.sa-tip {\n          width: 25px;\n          left: 14px;\n          top: 46px;\n          -webkit-transform: rotate(45deg);\n          transform: rotate(45deg); }\n        .sweet-alert .sa-icon.sa-success .sa-line.sa-long {\n          width: 47px;\n          right: 8px;\n          top: 38px;\n          -webkit-transform: rotate(-45deg);\n          transform: rotate(-45deg); }\n    .sweet-alert .sa-icon.sa-custom {\n      background-size: contain;\n      border-radius: 0;\n      border: none;\n      background-position: center center;\n      background-repeat: no-repeat; }\n\n/*\n * Animations\n */\n@-webkit-keyframes showSweetAlert {\n  0% {\n    transform: scale(0.7);\n    -webkit-transform: scale(0.7); }\n  45% {\n    transform: scale(1.05);\n    -webkit-transform: scale(1.05); }\n  80% {\n    transform: scale(0.95);\n    -webkit-transform: scale(0.95); }\n  100% {\n    transform: scale(1);\n    -webkit-transform: scale(1); } }\n\n@keyframes showSweetAlert {\n  0% {\n    transform: scale(0.7);\n    -webkit-transform: scale(0.7); }\n  45% {\n    transform: scale(1.05);\n    -webkit-transform: scale(1.05); }\n  80% {\n    transform: scale(0.95);\n    -webkit-transform: scale(0.95); }\n  100% {\n    transform: scale(1);\n    -webkit-transform: scale(1); } }\n\n@-webkit-keyframes hideSweetAlert {\n  0% {\n    transform: scale(1);\n    -webkit-transform: scale(1); }\n  100% {\n    transform: scale(0.5);\n    -webkit-transform: scale(0.5); } }\n\n@keyframes hideSweetAlert {\n  0% {\n    transform: scale(1);\n    -webkit-transform: scale(1); }\n  100% {\n    transform: scale(0.5);\n    -webkit-transform: scale(0.5); } }\n\n@-webkit-keyframes slideFromTop {\n  0% {\n    top: 0%; }\n  100% {\n    top: 50%; } }\n\n@keyframes slideFromTop {\n  0% {\n    top: 0%; }\n  100% {\n    top: 50%; } }\n\n@-webkit-keyframes slideToTop {\n  0% {\n    top: 50%; }\n  100% {\n    top: 0%; } }\n\n@keyframes slideToTop {\n  0% {\n    top: 50%; }\n  100% {\n    top: 0%; } }\n\n@-webkit-keyframes slideFromBottom {\n  0% {\n    top: 70%; }\n  100% {\n    top: 50%; } }\n\n@keyframes slideFromBottom {\n  0% {\n    top: 70%; }\n  100% {\n    top: 50%; } }\n\n@-webkit-keyframes slideToBottom {\n  0% {\n    top: 50%; }\n  100% {\n    top: 70%; } }\n\n@keyframes slideToBottom {\n  0% {\n    top: 50%; }\n  100% {\n    top: 70%; } }\n\n.showSweetAlert[data-animation=pop] {\n  -webkit-animation: showSweetAlert 0.3s;\n  animation: showSweetAlert 0.3s; }\n\n.showSweetAlert[data-animation=none] {\n  -webkit-animation: none;\n  animation: none; }\n\n.showSweetAlert[data-animation=slide-from-top] {\n  -webkit-animation: slideFromTop 0.3s;\n  animation: slideFromTop 0.3s; }\n\n.showSweetAlert[data-animation=slide-from-bottom] {\n  -webkit-animation: slideFromBottom 0.3s;\n  animation: slideFromBottom 0.3s; }\n\n.hideSweetAlert[data-animation=pop] {\n  -webkit-animation: hideSweetAlert 0.2s;\n  animation: hideSweetAlert 0.2s; }\n\n.hideSweetAlert[data-animation=none] {\n  -webkit-animation: none;\n  animation: none; }\n\n.hideSweetAlert[data-animation=slide-from-top] {\n  -webkit-animation: slideToTop 0.4s;\n  animation: slideToTop 0.4s; }\n\n.hideSweetAlert[data-animation=slide-from-bottom] {\n  -webkit-animation: slideToBottom 0.3s;\n  animation: slideToBottom 0.3s; }\n\n@-webkit-keyframes animateSuccessTip {\n  0% {\n    width: 0;\n    left: 1px;\n    top: 19px; }\n  54% {\n    width: 0;\n    left: 1px;\n    top: 19px; }\n  70% {\n    width: 50px;\n    left: -8px;\n    top: 37px; }\n  84% {\n    width: 17px;\n    left: 21px;\n    top: 48px; }\n  100% {\n    width: 25px;\n    left: 14px;\n    top: 45px; } }\n\n@keyframes animateSuccessTip {\n  0% {\n    width: 0;\n    left: 1px;\n    top: 19px; }\n  54% {\n    width: 0;\n    left: 1px;\n    top: 19px; }\n  70% {\n    width: 50px;\n    left: -8px;\n    top: 37px; }\n  84% {\n    width: 17px;\n    left: 21px;\n    top: 48px; }\n  100% {\n    width: 25px;\n    left: 14px;\n    top: 45px; } }\n\n@-webkit-keyframes animateSuccessLong {\n  0% {\n    width: 0;\n    right: 46px;\n    top: 54px; }\n  65% {\n    width: 0;\n    right: 46px;\n    top: 54px; }\n  84% {\n    width: 55px;\n    right: 0px;\n    top: 35px; }\n  100% {\n    width: 47px;\n    right: 8px;\n    top: 38px; } }\n\n@keyframes animateSuccessLong {\n  0% {\n    width: 0;\n    right: 46px;\n    top: 54px; }\n  65% {\n    width: 0;\n    right: 46px;\n    top: 54px; }\n  84% {\n    width: 55px;\n    right: 0px;\n    top: 35px; }\n  100% {\n    width: 47px;\n    right: 8px;\n    top: 38px; } }\n\n@-webkit-keyframes rotatePlaceholder {\n  0% {\n    transform: rotate(-45deg);\n    -webkit-transform: rotate(-45deg); }\n  5% {\n    transform: rotate(-45deg);\n    -webkit-transform: rotate(-45deg); }\n  12% {\n    transform: rotate(-405deg);\n    -webkit-transform: rotate(-405deg); }\n  100% {\n    transform: rotate(-405deg);\n    -webkit-transform: rotate(-405deg); } }\n\n@keyframes rotatePlaceholder {\n  0% {\n    transform: rotate(-45deg);\n    -webkit-transform: rotate(-45deg); }\n  5% {\n    transform: rotate(-45deg);\n    -webkit-transform: rotate(-45deg); }\n  12% {\n    transform: rotate(-405deg);\n    -webkit-transform: rotate(-405deg); }\n  100% {\n    transform: rotate(-405deg);\n    -webkit-transform: rotate(-405deg); } }\n\n.animateSuccessTip {\n  -webkit-animation: animateSuccessTip 0.75s;\n  animation: animateSuccessTip 0.75s; }\n\n.animateSuccessLong {\n  -webkit-animation: animateSuccessLong 0.75s;\n  animation: animateSuccessLong 0.75s; }\n\n.sa-icon.sa-success.animate::after {\n  -webkit-animation: rotatePlaceholder 4.25s ease-in;\n  animation: rotatePlaceholder 4.25s ease-in; }\n\n@-webkit-keyframes animateErrorIcon {\n  0% {\n    transform: rotateX(100deg);\n    -webkit-transform: rotateX(100deg);\n    opacity: 0; }\n  100% {\n    transform: rotateX(0deg);\n    -webkit-transform: rotateX(0deg);\n    opacity: 1; } }\n\n@keyframes animateErrorIcon {\n  0% {\n    transform: rotateX(100deg);\n    -webkit-transform: rotateX(100deg);\n    opacity: 0; }\n  100% {\n    transform: rotateX(0deg);\n    -webkit-transform: rotateX(0deg);\n    opacity: 1; } }\n\n.animateErrorIcon {\n  -webkit-animation: animateErrorIcon 0.5s;\n  animation: animateErrorIcon 0.5s; }\n\n@-webkit-keyframes animateXMark {\n  0% {\n    transform: scale(0.4);\n    -webkit-transform: scale(0.4);\n    margin-top: 26px;\n    opacity: 0; }\n  50% {\n    transform: scale(0.4);\n    -webkit-transform: scale(0.4);\n    margin-top: 26px;\n    opacity: 0; }\n  80% {\n    transform: scale(1.15);\n    -webkit-transform: scale(1.15);\n    margin-top: -6px; }\n  100% {\n    transform: scale(1);\n    -webkit-transform: scale(1);\n    margin-top: 0;\n    opacity: 1; } }\n\n@keyframes animateXMark {\n  0% {\n    transform: scale(0.4);\n    -webkit-transform: scale(0.4);\n    margin-top: 26px;\n    opacity: 0; }\n  50% {\n    transform: scale(0.4);\n    -webkit-transform: scale(0.4);\n    margin-top: 26px;\n    opacity: 0; }\n  80% {\n    transform: scale(1.15);\n    -webkit-transform: scale(1.15);\n    margin-top: -6px; }\n  100% {\n    transform: scale(1);\n    -webkit-transform: scale(1);\n    margin-top: 0;\n    opacity: 1; } }\n\n.animateXMark {\n  -webkit-animation: animateXMark 0.5s;\n  animation: animateXMark 0.5s; }\n\n@-webkit-keyframes pulseWarning {\n  0% {\n    border-color: #F8D486; }\n  100% {\n    border-color: #F8BB86; } }\n\n@keyframes pulseWarning {\n  0% {\n    border-color: #F8D486; }\n  100% {\n    border-color: #F8BB86; } }\n\n.pulseWarning {\n  -webkit-animation: pulseWarning 0.75s infinite alternate;\n  animation: pulseWarning 0.75s infinite alternate; }\n\n@-webkit-keyframes pulseWarningIns {\n  0% {\n    background-color: #F8D486; }\n  100% {\n    background-color: #F8BB86; } }\n\n@keyframes pulseWarningIns {\n  0% {\n    background-color: #F8D486; }\n  100% {\n    background-color: #F8BB86; } }\n\n.pulseWarningIns {\n  -webkit-animation: pulseWarningIns 0.75s infinite alternate;\n  animation: pulseWarningIns 0.75s infinite alternate; }\n\n@-webkit-keyframes rotate-loading {\n  0% {\n    transform: rotate(0deg); }\n  100% {\n    transform: rotate(360deg); } }\n\n@keyframes rotate-loading {\n  0% {\n    transform: rotate(0deg); }\n  100% {\n    transform: rotate(360deg); } }\n\n/* Internet Explorer 9 has some special quirks that are fixed here */\n/* The icons are not animated. */\n/* This file is automatically merged into sweet-alert.min.js through Gulp */\n/* Error icon */\n.sweet-alert .sa-icon.sa-error .sa-line.sa-left {\n  -ms-transform: rotate(45deg) \\9; }\n\n.sweet-alert .sa-icon.sa-error .sa-line.sa-right {\n  -ms-transform: rotate(-45deg) \\9; }\n\n/* Success icon */\n.sweet-alert .sa-icon.sa-success {\n  border-color: transparent\\9; }\n\n.sweet-alert .sa-icon.sa-success .sa-line.sa-tip {\n  -ms-transform: rotate(45deg) \\9; }\n\n.sweet-alert .sa-icon.sa-success .sa-line.sa-long {\n  -ms-transform: rotate(-45deg) \\9; }\n\n/*!\n * Load Awesome v1.1.0 (http://github.danielcardoso.net/load-awesome/)\n * Copyright 2015 Daniel Cardoso <@DanielCardoso>\n * Licensed under MIT\n */\n.la-ball-fall,\n.la-ball-fall > div {\n  position: relative;\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box; }\n\n.la-ball-fall {\n  display: block;\n  font-size: 0;\n  color: #fff; }\n\n.la-ball-fall.la-dark {\n  color: #333; }\n\n.la-ball-fall > div {\n  display: inline-block;\n  float: none;\n  background-color: currentColor;\n  border: 0 solid currentColor; }\n\n.la-ball-fall {\n  width: 54px;\n  height: 18px; }\n\n.la-ball-fall > div {\n  width: 10px;\n  height: 10px;\n  margin: 4px;\n  border-radius: 100%;\n  opacity: 0;\n  -webkit-animation: ball-fall 1s ease-in-out infinite;\n  -moz-animation: ball-fall 1s ease-in-out infinite;\n  -o-animation: ball-fall 1s ease-in-out infinite;\n  animation: ball-fall 1s ease-in-out infinite; }\n\n.la-ball-fall > div:nth-child(1) {\n  -webkit-animation-delay: -200ms;\n  -moz-animation-delay: -200ms;\n  -o-animation-delay: -200ms;\n  animation-delay: -200ms; }\n\n.la-ball-fall > div:nth-child(2) {\n  -webkit-animation-delay: -100ms;\n  -moz-animation-delay: -100ms;\n  -o-animation-delay: -100ms;\n  animation-delay: -100ms; }\n\n.la-ball-fall > div:nth-child(3) {\n  -webkit-animation-delay: 0ms;\n  -moz-animation-delay: 0ms;\n  -o-animation-delay: 0ms;\n  animation-delay: 0ms; }\n\n.la-ball-fall.la-sm {\n  width: 26px;\n  height: 8px; }\n\n.la-ball-fall.la-sm > div {\n  width: 4px;\n  height: 4px;\n  margin: 2px; }\n\n.la-ball-fall.la-2x {\n  width: 108px;\n  height: 36px; }\n\n.la-ball-fall.la-2x > div {\n  width: 20px;\n  height: 20px;\n  margin: 8px; }\n\n.la-ball-fall.la-3x {\n  width: 162px;\n  height: 54px; }\n\n.la-ball-fall.la-3x > div {\n  width: 30px;\n  height: 30px;\n  margin: 12px; }\n\n/*\n * Animation\n */\n@-webkit-keyframes ball-fall {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(-145%);\n    transform: translateY(-145%); }\n  10% {\n    opacity: .5; }\n  20% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    transform: translateY(0); }\n  80% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    transform: translateY(0); }\n  90% {\n    opacity: .5; }\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(145%);\n    transform: translateY(145%); } }\n\n@-moz-keyframes ball-fall {\n  0% {\n    opacity: 0;\n    -moz-transform: translateY(-145%);\n    transform: translateY(-145%); }\n  10% {\n    opacity: .5; }\n  20% {\n    opacity: 1;\n    -moz-transform: translateY(0);\n    transform: translateY(0); }\n  80% {\n    opacity: 1;\n    -moz-transform: translateY(0);\n    transform: translateY(0); }\n  90% {\n    opacity: .5; }\n  100% {\n    opacity: 0;\n    -moz-transform: translateY(145%);\n    transform: translateY(145%); } }\n\n@-o-keyframes ball-fall {\n  0% {\n    opacity: 0;\n    -o-transform: translateY(-145%);\n    transform: translateY(-145%); }\n  10% {\n    opacity: .5; }\n  20% {\n    opacity: 1;\n    -o-transform: translateY(0);\n    transform: translateY(0); }\n  80% {\n    opacity: 1;\n    -o-transform: translateY(0);\n    transform: translateY(0); }\n  90% {\n    opacity: .5; }\n  100% {\n    opacity: 0;\n    -o-transform: translateY(145%);\n    transform: translateY(145%); } }\n\n@keyframes ball-fall {\n  0% {\n    opacity: 0;\n    -webkit-transform: translateY(-145%);\n    -moz-transform: translateY(-145%);\n    -o-transform: translateY(-145%);\n    transform: translateY(-145%); }\n  10% {\n    opacity: .5; }\n  20% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    -moz-transform: translateY(0);\n    -o-transform: translateY(0);\n    transform: translateY(0); }\n  80% {\n    opacity: 1;\n    -webkit-transform: translateY(0);\n    -moz-transform: translateY(0);\n    -o-transform: translateY(0);\n    transform: translateY(0); }\n  90% {\n    opacity: .5; }\n  100% {\n    opacity: 0;\n    -webkit-transform: translateY(145%);\n    -moz-transform: translateY(145%);\n    -o-transform: translateY(145%);\n    transform: translateY(145%); } }"
  },
  {
    "path": "static/icons/linea-icons/linea.css",
    "content": "@charset \"UTF-8\";\n.glyphs.character-mapping {\n  margin: 0 0 20px 0;\n  padding: 20px 0 20px 30px;\n  color: rgba(0,0,0,0.5);\n  border: 1px solid #d8e0e5;\n  -webkit-border-radius: 3px;\n  border-radius: 3px;\n}\n.glyphs.character-mapping li {\n  margin: 0 30px 20px 0;\n  display: inline-block;\n  width: 90px;\n  text-align: center;\n  font-size: 24px;\n  color: ;\n}\n.linea-icon {\n  position: relative;\n}\n.linea-icon svg {\n  fill: #000;\n}\n.glyphs.character-mapping input {\n  margin: 0;\n  padding: 5px 0;\n  line-height: 12px;\n  font-size: 12px;\n  display: block;\n  width: 100%;\n  border: 1px solid #d8e0e5;\n  text-align: center;\n  outline: 0;\n}\n.glyphs.character-mapping input:focus {\n  border: 1px solid #fbde4a;\n  -webkit-box-shadow: inset 0 0 3px #fbde4a;\n  box-shadow: inset 0 0 3px #fbde4a;\n}\n.glyphs.character-mapping input:hover {\n  -webkit-box-shadow: inset 0 0 3px #fbde4a;\n  box-shadow: inset 0 0 3px #fbde4a;\n}\n@font-face {\n  font-family: \"linea-arrows-10\";\n  src: url(\"fonts/linea-arrows-10.eot\");\n  src: url(\"fonts/linea-arrows-10d41d.eot?#iefix\") format(\"embedded-opentype\"), url(\"fonts/linea-arrows-10.woff\") format(\"woff\"), url(\"fonts/linea-arrows-10.ttf\") format(\"truetype\"), url(\"fonts/linea-arrows-10.svg#linea-arrows-10\") format(\"svg\");\n  font-weight: normal;\n  font-style: normal;\n}\n.linea-aerrow[data-icon]:before {\n  font-family: \"linea-arrows-10\" !important;\n  content: attr(data-icon);\n  font-style: normal !important;\n  font-weight: normal !important;\n  font-variant: normal !important;\n  text-transform: none !important;\n  speak: none;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n[class^=\"linea-icon-\"]:before,\n[class*=\"linea- icon-\"]:before {\n  font-family: \"linea-arrows-10\" !important;\n  font-style: normal !important;\n  font-weight: normal !important;\n  font-variant: normal !important;\n  text-transform: none !important;\n  speak: none;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.icon-arrows-anticlockwise:before {\n  content: \"\\e000\";\n}\n.icon-arrows-anticlockwise-dashed:before {\n  content: \"\\e001\";\n}\n.icon-arrows-button-down:before {\n  content: \"\\e002\";\n}\n.icon-arrows-button-off:before {\n  content: \"\\e003\";\n}\n.icon-arrows-button-on:before {\n  content: \"\\e004\";\n}\n.icon-arrows-button-up:before {\n  content: \"\\e005\";\n}\n.icon-arrows-check:before {\n  content: \"\\e006\";\n}\n.icon-arrows-circle-check:before {\n  content: \"\\e007\";\n}\n.icon-arrows-circle-down:before {\n  content: \"\\e008\";\n}\n.icon-arrows-circle-downleft:before {\n  content: \"\\e009\";\n}\n.icon-arrows-circle-downright:before {\n  content: \"\\e00a\";\n}\n.icon-arrows-circle-left:before {\n  content: \"\\e00b\";\n}\n.icon-arrows-circle-minus:before {\n  content: \"\\e00c\";\n}\n.icon-arrows-circle-plus:before {\n  content: \"\\e00d\";\n}\n.icon-arrows-circle-remove:before {\n  content: \"\\e00e\";\n}\n.icon-arrows-circle-right:before {\n  content: \"\\e00f\";\n}\n.icon-arrows-circle-up:before {\n  content: \"\\e010\";\n}\n.icon-arrows-circle-upleft:before {\n  content: \"\\e011\";\n}\n.icon-arrows-circle-upright:before {\n  content: \"\\e012\";\n}\n.icon-arrows-clockwise:before {\n  content: \"\\e013\";\n}\n.icon-arrows-clockwise-dashed:before {\n  content: \"\\e014\";\n}\n.icon-arrows-compress:before {\n  content: \"\\e015\";\n}\n.icon-arrows-deny:before {\n  content: \"\\e016\";\n}\n.icon-arrows-diagonal:before {\n  content: \"\\e017\";\n}\n.icon-arrows-diagonal2:before {\n  content: \"\\e018\";\n}\n.icon-arrows-down:before {\n  content: \"\\e019\";\n}\n.icon-arrows-down-double:before {\n  content: \"\\e01a\";\n}\n.icon-arrows-downleft:before {\n  content: \"\\e01b\";\n}\n.icon-arrows-downright:before {\n  content: \"\\e01c\";\n}\n.icon-arrows-drag-down:before {\n  content: \"\\e01d\";\n}\n.icon-arrows-drag-down-dashed:before {\n  content: \"\\e01e\";\n}\n.icon-arrows-drag-horiz:before {\n  content: \"\\e01f\";\n}\n.icon-arrows-drag-left:before {\n  content: \"\\e020\";\n}\n.icon-arrows-drag-left-dashed:before {\n  content: \"\\e021\";\n}\n.icon-arrows-drag-right:before {\n  content: \"\\e022\";\n}\n.icon-arrows-drag-right-dashed:before {\n  content: \"\\e023\";\n}\n.icon-arrows-drag-up:before {\n  content: \"\\e024\";\n}\n.icon-arrows-drag-up-dashed:before {\n  content: \"\\e025\";\n}\n.icon-arrows-drag-vert:before {\n  content: \"\\e026\";\n}\n.icon-arrows-exclamation:before {\n  content: \"\\e027\";\n}\n.icon-arrows-expand:before {\n  content: \"\\e028\";\n}\n.icon-arrows-expand-diagonal1:before {\n  content: \"\\e029\";\n}\n.icon-arrows-expand-horizontal1:before {\n  content: \"\\e02a\";\n}\n.icon-arrows-expand-vertical1:before {\n  content: \"\\e02b\";\n}\n.icon-arrows-fit-horizontal:before {\n  content: \"\\e02c\";\n}\n.icon-arrows-fit-vertical:before {\n  content: \"\\e02d\";\n}\n.icon-arrows-glide:before {\n  content: \"\\e02e\";\n}\n.icon-arrows-glide-horizontal:before {\n  content: \"\\e02f\";\n}\n.icon-arrows-glide-vertical:before {\n  content: \"\\e030\";\n}\n.icon-arrows-hamburger1:before {\n  content: \"\\e031\";\n}\n.icon-arrows-hamburger-2:before {\n  content: \"\\e032\";\n}\n.icon-arrows-horizontal:before {\n  content: \"\\e033\";\n}\n.icon-arrows-info:before {\n  content: \"\\e034\";\n}\n.icon-arrows-keyboard-alt:before {\n  content: \"\\e035\";\n}\n.icon-arrows-keyboard-cmd:before {\n  content: \"\\e036\";\n}\n.icon-arrows-keyboard-delete:before {\n  content: \"\\e037\";\n}\n.icon-arrows-keyboard-down:before {\n  content: \"\\e038\";\n}\n.icon-arrows-keyboard-left:before {\n  content: \"\\e039\";\n}\n.icon-arrows-keyboard-return:before {\n  content: \"\\e03a\";\n}\n.icon-arrows-keyboard-right:before {\n  content: \"\\e03b\";\n}\n.icon-arrows-keyboard-shift:before {\n  content: \"\\e03c\";\n}\n.icon-arrows-keyboard-tab:before {\n  content: \"\\e03d\";\n}\n.icon-arrows-keyboard-up:before {\n  content: \"\\e03e\";\n}\n.icon-arrows-left:before {\n  content: \"\\e03f\";\n}\n.icon-arrows-left-double-32:before {\n  content: \"\\e040\";\n}\n.icon-arrows-minus:before {\n  content: \"\\e041\";\n}\n.icon-arrows-move:before {\n  content: \"\\e042\";\n}\n.icon-arrows-move2:before {\n  content: \"\\e043\";\n}\n.icon-arrows-move-bottom:before {\n  content: \"\\e044\";\n}\n.icon-arrows-move-left:before {\n  content: \"\\e045\";\n}\n.icon-arrows-move-right:before {\n  content: \"\\e046\";\n}\n.icon-arrows-move-top:before {\n  content: \"\\e047\";\n}\n.icon-arrows-plus:before {\n  content: \"\\e048\";\n}\n.icon-arrows-question:before {\n  content: \"\\e049\";\n}\n.icon-arrows-remove:before {\n  content: \"\\e04a\";\n}\n.icon-arrows-right:before {\n  content: \"\\e04b\";\n}\n.icon-arrows-right-double:before {\n  content: \"\\e04c\";\n}\n.icon-arrows-rotate:before {\n  content: \"\\e04d\";\n}\n.icon-arrows-rotate-anti:before {\n  content: \"\\e04e\";\n}\n.icon-arrows-rotate-anti-dashed:before {\n  content: \"\\e04f\";\n}\n.icon-arrows-rotate-dashed:before {\n  content: \"\\e050\";\n}\n.icon-arrows-shrink:before {\n  content: \"\\e051\";\n}\n.icon-arrows-shrink-diagonal1:before {\n  content: \"\\e052\";\n}\n.icon-arrows-shrink-diagonal2:before {\n  content: \"\\e053\";\n}\n.icon-arrows-shrink-horizonal2:before {\n  content: \"\\e054\";\n}\n.icon-arrows-shrink-horizontal1:before {\n  content: \"\\e055\";\n}\n.icon-arrows-shrink-vertical1:before {\n  content: \"\\e056\";\n}\n.icon-arrows-shrink-vertical2:before {\n  content: \"\\e057\";\n}\n.icon-arrows-sign-down:before {\n  content: \"\\e058\";\n}\n.icon-arrows-sign-left:before {\n  content: \"\\e059\";\n}\n.icon-arrows-sign-right:before {\n  content: \"\\e05a\";\n}\n.icon-arrows-sign-up:before {\n  content: \"\\e05b\";\n}\n.icon-arrows-slide-down1:before {\n  content: \"\\e05c\";\n}\n.icon-arrows-slide-down2:before {\n  content: \"\\e05d\";\n}\n.icon-arrows-slide-left1:before {\n  content: \"\\e05e\";\n}\n.icon-arrows-slide-left2:before {\n  content: \"\\e05f\";\n}\n.icon-arrows-slide-right1:before {\n  content: \"\\e060\";\n}\n.icon-arrows-slide-right2:before {\n  content: \"\\e061\";\n}\n.icon-arrows-slide-up1:before {\n  content: \"\\e062\";\n}\n.icon-arrows-slide-up2:before {\n  content: \"\\e063\";\n}\n.icon-arrows-slim-down:before {\n  content: \"\\e064\";\n}\n.icon-arrows-slim-down-dashed:before {\n  content: \"\\e065\";\n}\n.icon-arrows-slim-left:before {\n  content: \"\\e066\";\n}\n.icon-arrows-slim-left-dashed:before {\n  content: \"\\e067\";\n}\n.icon-arrows-slim-right:before {\n  content: \"\\e068\";\n}\n.icon-arrows-slim-right-dashed:before {\n  content: \"\\e069\";\n}\n.icon-arrows-slim-up:before {\n  content: \"\\e06a\";\n}\n.icon-arrows-slim-up-dashed:before {\n  content: \"\\e06b\";\n}\n.icon-arrows-square-check:before {\n  content: \"\\e06c\";\n}\n.icon-arrows-square-down:before {\n  content: \"\\e06d\";\n}\n.icon-arrows-square-downleft:before {\n  content: \"\\e06e\";\n}\n.icon-arrows-square-downright:before {\n  content: \"\\e06f\";\n}\n.icon-arrows-square-left:before {\n  content: \"\\e070\";\n}\n.icon-arrows-square-minus:before {\n  content: \"\\e071\";\n}\n.icon-arrows-square-plus:before {\n  content: \"\\e072\";\n}\n.icon-arrows-square-remove:before {\n  content: \"\\e073\";\n}\n.icon-arrows-square-right:before {\n  content: \"\\e074\";\n}\n.icon-arrows-square-up:before {\n  content: \"\\e075\";\n}\n.icon-arrows-square-upleft:before {\n  content: \"\\e076\";\n}\n.icon-arrows-square-upright:before {\n  content: \"\\e077\";\n}\n.icon-arrows-squares:before {\n  content: \"\\e078\";\n}\n.icon-arrows-stretch-diagonal1:before {\n  content: \"\\e079\";\n}\n.icon-arrows-stretch-diagonal2:before {\n  content: \"\\e07a\";\n}\n.icon-arrows-stretch-diagonal3:before {\n  content: \"\\e07b\";\n}\n.icon-arrows-stretch-diagonal4:before {\n  content: \"\\e07c\";\n}\n.icon-arrows-stretch-horizontal1:before {\n  content: \"\\e07d\";\n}\n.icon-arrows-stretch-horizontal2:before {\n  content: \"\\e07e\";\n}\n.icon-arrows-stretch-vertical1:before {\n  content: \"\\e07f\";\n}\n.icon-arrows-stretch-vertical2:before {\n  content: \"\\e080\";\n}\n.icon-arrows-switch-horizontal:before {\n  content: \"\\e081\";\n}\n.icon-arrows-switch-vertical:before {\n  content: \"\\e082\";\n}\n.icon-arrows-up:before {\n  content: \"\\e083\";\n}\n.icon-arrows-up-double-33:before {\n  content: \"\\e084\";\n}\n.icon-arrows-upleft:before {\n  content: \"\\e085\";\n}\n.icon-arrows-upright:before {\n  content: \"\\e086\";\n}\n.icon-arrows-vertical:before {\n  content: \"\\e087\";\n}\n@font-face {\n  font-family: \"linea-basic-10\";\n  src: url(\"fonts/linea-basic-10.eot\");\n  src: url(\"fonts/linea-basic-10d41d.eot?#iefix\") format(\"embedded-opentype\"), url(\"fonts/linea-basic-10.woff\") format(\"woff\"), url(\"fonts/linea-basic-10.ttf\") format(\"truetype\"), url(\"fonts/linea-basic-10.svg#linea-basic-10\") format(\"svg\");\n  font-weight: normal;\n  font-style: normal;\n}\n.linea-basic[data-icon]:before {\n  font-family: \"linea-basic-10\" !important;\n  content: attr(data-icon);\n  font-style: normal !important;\n  font-weight: normal !important;\n  font-variant: normal !important;\n  text-transform: none !important;\n  speak: none;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n[class^=\"linea-icon-\"]:before,\n[class*=\"linea- icon-\"]:before {\n  font-family: \"linea-basic-10\" !important;\n  font-style: normal !important;\n  font-weight: normal !important;\n  font-variant: normal !important;\n  text-transform: none !important;\n  speak: none;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.icon-basic-accelerator:before {\n  content: \"a\";\n}\n.icon-basic-alarm:before {\n  content: \"b\";\n}\n.icon-basic-anchor:before {\n  content: \"c\";\n}\n.icon-basic-anticlockwise:before {\n  content: \"d\";\n}\n.icon-basic-archive:before {\n  content: \"e\";\n}\n.icon-basic-archive-full:before {\n  content: \"f\";\n}\n.icon-basic-ban:before {\n  content: \"g\";\n}\n.icon-basic-battery-charge:before {\n  content: \"h\";\n}\n.icon-basic-battery-empty:before {\n  content: \"i\";\n}\n.icon-basic-battery-full:before {\n  content: \"j\";\n}\n.icon-basic-battery-half:before {\n  content: \"k\";\n}\n.icon-basic-bolt:before {\n  content: \"l\";\n}\n.icon-basic-book:before {\n  content: \"m\";\n}\n.icon-basic-book-pen:before {\n  content: \"n\";\n}\n.icon-basic-book-pencil:before {\n  content: \"o\";\n}\n.icon-basic-bookmark:before {\n  content: \"p\";\n}\n.icon-basic-calculator:before {\n  content: \"q\";\n}\n.icon-basic-calendar:before {\n  content: \"r\";\n}\n.icon-basic-cards-diamonds:before {\n  content: \"s\";\n}\n.icon-basic-cards-hearts:before {\n  content: \"t\";\n}\n.icon-basic-case:before {\n  content: \"u\";\n}\n.icon-basic-chronometer:before {\n  content: \"v\";\n}\n.icon-basic-clessidre:before {\n  content: \"w\";\n}\n.icon-basic-clock:before {\n  content: \"x\";\n}\n.icon-basic-clockwise:before {\n  content: \"y\";\n}\n.icon-basic-cloud:before {\n  content: \"z\";\n}\n.icon-basic-clubs:before {\n  content: \"A\";\n}\n.icon-basic-compass:before {\n  content: \"B\";\n}\n.icon-basic-cup:before {\n  content: \"C\";\n}\n.icon-basic-diamonds:before {\n  content: \"D\";\n}\n.icon-basic-display:before {\n  content: \"E\";\n}\n.icon-basic-download:before {\n  content: \"F\";\n}\n.icon-basic-exclamation:before {\n  content: \"G\";\n}\n.icon-basic-eye:before {\n  content: \"H\";\n}\n.icon-basic-eye-closed:before {\n  content: \"I\";\n}\n.icon-basic-female:before {\n  content: \"J\";\n}\n.icon-basic-flag1:before {\n  content: \"K\";\n}\n.icon-basic-flag2:before {\n  content: \"L\";\n}\n.icon-basic-floppydisk:before {\n  content: \"M\";\n}\n.icon-basic-folder:before {\n  content: \"N\";\n}\n.icon-basic-folder-multiple:before {\n  content: \"O\";\n}\n.icon-basic-gear:before {\n  content: \"P\";\n}\n.icon-basic-geolocalize-01:before {\n  content: \"Q\";\n}\n.icon-basic-geolocalize-05:before {\n  content: \"R\";\n}\n.icon-basic-globe:before {\n  content: \"S\";\n}\n.icon-basic-gunsight:before {\n  content: \"T\";\n}\n.icon-basic-hammer:before {\n  content: \"U\";\n}\n.icon-basic-headset:before {\n  content: \"V\";\n}\n.icon-basic-heart:before {\n  content: \"W\";\n}\n.icon-basic-heart-broken:before {\n  content: \"X\";\n}\n.icon-basic-helm:before {\n  content: \"Y\";\n}\n.icon-basic-home:before {\n  content: \"Z\";\n}\n.icon-basic-info:before {\n  content: \"0\";\n}\n.icon-basic-ipod:before {\n  content: \"1\";\n}\n.icon-basic-joypad:before {\n  content: \"2\";\n}\n.icon-basic-key:before {\n  content: \"3\";\n}\n.icon-basic-keyboard:before {\n  content: \"4\";\n}\n.icon-basic-laptop:before {\n  content: \"5\";\n}\n.icon-basic-life-buoy:before {\n  content: \"6\";\n}\n.icon-basic-lightbulb:before {\n  content: \"7\";\n}\n.icon-basic-link:before {\n  content: \"8\";\n}\n.icon-basic-lock:before {\n  content: \"9\";\n}\n.icon-basic-lock-open:before {\n  content: \"!\";\n}\n.icon-basic-magic-mouse:before {\n  content: \"\\\"\";\n}\n.icon-basic-magnifier:before {\n  content: \"#\";\n}\n.icon-basic-magnifier-minus:before {\n  content: \"$\";\n}\n.icon-basic-magnifier-plus:before {\n  content: \"%\";\n}\n.icon-basic-mail:before {\n  content: \"&\";\n}\n.icon-basic-mail-multiple:before {\n  content: \"'\";\n}\n.icon-basic-mail-open:before {\n  content: \"(\";\n}\n.icon-basic-mail-open-text:before {\n  content: \")\";\n}\n.icon-basic-male:before {\n  content: \"*\";\n}\n.icon-basic-map:before {\n  content: \"+\";\n}\n.icon-basic-message:before {\n  content: \",\";\n}\n.icon-basic-message-multiple:before {\n  content: \"-\";\n}\n.icon-basic-message-txt:before {\n  content: \".\";\n}\n.icon-basic-mixer2:before {\n  content: \"/\";\n}\n.icon-basic-mouse:before {\n  content: \":\";\n}\n.icon-basic-notebook:before {\n  content: \";\";\n}\n.icon-basic-notebook-pen:before {\n  content: \"<\";\n}\n.icon-basic-notebook-pencil:before {\n  content: \"=\";\n}\n.icon-basic-paperplane:before {\n  content: \">\";\n}\n.icon-basic-pencil-ruler:before {\n  content: \"?\";\n}\n.icon-basic-pencil-ruler-pen:before {\n  content: \"@\";\n}\n.icon-basic-photo:before {\n  content: \"[\";\n}\n.icon-basic-picture:before {\n  content: \"]\";\n}\n.icon-basic-picture-multiple:before {\n  content: \"^\";\n}\n.icon-basic-pin1:before {\n  content: \"_\";\n}\n.icon-basic-pin2:before {\n  content: \"`\";\n}\n.icon-basic-postcard:before {\n  content: \"{\";\n}\n.icon-basic-postcard-multiple:before {\n  content: \"|\";\n}\n.icon-basic-printer:before {\n  content: \"}\";\n}\n.icon-basic-question:before {\n  content: \"~\";\n}\n.icon-basic-rss:before {\n  content: \"\";\n}\n.icon-basic-server:before {\n  content: \"\\e000\";\n}\n.icon-basic-server2:before {\n  content: \"\\e001\";\n}\n.icon-basic-server-cloud:before {\n  content: \"\\e002\";\n}\n.icon-basic-server-download:before {\n  content: \"\\e003\";\n}\n.icon-basic-server-upload:before {\n  content: \"\\e004\";\n}\n.icon-basic-settings:before {\n  content: \"\\e005\";\n}\n.icon-basic-share:before {\n  content: \"\\e006\";\n}\n.icon-basic-sheet:before {\n  content: \"\\e007\";\n}\n.icon-basic-sheet-multiple:before {\n  content: \"\\e008\";\n}\n.icon-basic-sheet-pen:before {\n  content: \"\\e009\";\n}\n.icon-basic-sheet-pencil:before {\n  content: \"\\e00a\";\n}\n.icon-basic-sheet-txt:before {\n  content: \"\\e00b\";\n}\n.icon-basic-signs:before {\n  content: \"\\e00c\";\n}\n.icon-basic-smartphone:before {\n  content: \"\\e00d\";\n}\n.icon-basic-spades:before {\n  content: \"\\e00e\";\n}\n.icon-basic-spread:before {\n  content: \"\\e00f\";\n}\n.icon-basic-spread-bookmark:before {\n  content: \"\\e010\";\n}\n.icon-basic-spread-text:before {\n  content: \"\\e011\";\n}\n.icon-basic-spread-text-bookmark:before {\n  content: \"\\e012\";\n}\n.icon-basic-star:before {\n  content: \"\\e013\";\n}\n.icon-basic-tablet:before {\n  content: \"\\e014\";\n}\n.icon-basic-target:before {\n  content: \"\\e015\";\n}\n.icon-basic-todo:before {\n  content: \"\\e016\";\n}\n.icon-basic-todo-pen:before {\n  content: \"\\e017\";\n}\n.icon-basic-todo-pencil:before {\n  content: \"\\e018\";\n}\n.icon-basic-todo-txt:before {\n  content: \"\\e019\";\n}\n.icon-basic-todolist-pen:before {\n  content: \"\\e01a\";\n}\n.icon-basic-todolist-pencil:before {\n  content: \"\\e01b\";\n}\n.icon-basic-trashcan:before {\n  content: \"\\e01c\";\n}\n.icon-basic-trashcan-full:before {\n  content: \"\\e01d\";\n}\n.icon-basic-trashcan-refresh:before {\n  content: \"\\e01e\";\n}\n.icon-basic-trashcan-remove:before {\n  content: \"\\e01f\";\n}\n.icon-basic-upload:before {\n  content: \"\\e020\";\n}\n.icon-basic-usb:before {\n  content: \"\\e021\";\n}\n.icon-basic-video:before {\n  content: \"\\e022\";\n}\n.icon-basic-watch:before {\n  content: \"\\e023\";\n}\n.icon-basic-webpage:before {\n  content: \"\\e024\";\n}\n.icon-basic-webpage-img-txt:before {\n  content: \"\\e025\";\n}\n.icon-basic-webpage-multiple:before {\n  content: \"\\e026\";\n}\n.icon-basic-webpage-txt:before {\n  content: \"\\e027\";\n}\n.icon-basic-world:before {\n  content: \"\\e028\";\n}\n@font-face {\n  font-family: \"linea-basic-elaboration-10\";\n  src: url(\"fonts/linea-basic-elaboration-10.eot\");\n  src: url(\"fonts/linea-basic-elaboration-10d41d.eot?#iefix\") format(\"embedded-opentype\"), url(\"fonts/linea-basic-elaboration-10.woff\") format(\"woff\"), url(\"fonts/linea-basic-elaboration-10.ttf\") format(\"truetype\"), url(\"fonts/linea-basic-elaboration-10.svg#linea-basic-elaboration-10\") format(\"svg\");\n  font-weight: normal;\n  font-style: normal;\n}\n.linea-elaborate[data-icon]:before {\n  font-family: \"linea-basic-elaboration-10\" !important;\n  content: attr(data-icon);\n  font-style: normal !important;\n  font-weight: normal !important;\n  font-variant: normal !important;\n  text-transform: none !important;\n  speak: none;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n[class^=\"linea-icon-\"]:before,\n[class*=\"linea- icon-\"]:before {\n  font-family: \"linea-basic-elaboration-10\" !important;\n  font-style: normal !important;\n  font-weight: normal !important;\n  font-variant: normal !important;\n  text-transform: none !important;\n  speak: none;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.icon-basic-elaboration-bookmark-checck:before {\n  content: \"a\";\n}\n.icon-basic-elaboration-bookmark-minus:before {\n  content: \"b\";\n}\n.icon-basic-elaboration-bookmark-plus:before {\n  content: \"c\";\n}\n.icon-basic-elaboration-bookmark-remove:before {\n  content: \"d\";\n}\n.icon-basic-elaboration-briefcase-check:before {\n  content: \"e\";\n}\n.icon-basic-elaboration-briefcase-download:before {\n  content: \"f\";\n}\n.icon-basic-elaboration-briefcase-flagged:before {\n  content: \"g\";\n}\n.icon-basic-elaboration-briefcase-minus:before {\n  content: \"h\";\n}\n.icon-basic-elaboration-briefcase-plus:before {\n  content: \"i\";\n}\n.icon-basic-elaboration-briefcase-refresh:before {\n  content: \"j\";\n}\n.icon-basic-elaboration-briefcase-remove:before {\n  content: \"k\";\n}\n.icon-basic-elaboration-briefcase-search:before {\n  content: \"l\";\n}\n.icon-basic-elaboration-briefcase-star:before {\n  content: \"m\";\n}\n.icon-basic-elaboration-briefcase-upload:before {\n  content: \"n\";\n}\n.icon-basic-elaboration-browser-check:before {\n  content: \"o\";\n}\n.icon-basic-elaboration-browser-download:before {\n  content: \"p\";\n}\n.icon-basic-elaboration-browser-minus:before {\n  content: \"q\";\n}\n.icon-basic-elaboration-browser-plus:before {\n  content: \"r\";\n}\n.icon-basic-elaboration-browser-refresh:before {\n  content: \"s\";\n}\n.icon-basic-elaboration-browser-remove:before {\n  content: \"t\";\n}\n.icon-basic-elaboration-browser-search:before {\n  content: \"u\";\n}\n.icon-basic-elaboration-browser-star:before {\n  content: \"v\";\n}\n.icon-basic-elaboration-browser-upload:before {\n  content: \"w\";\n}\n.icon-basic-elaboration-calendar-check:before {\n  content: \"x\";\n}\n.icon-basic-elaboration-calendar-cloud:before {\n  content: \"y\";\n}\n.icon-basic-elaboration-calendar-download:before {\n  content: \"z\";\n}\n.icon-basic-elaboration-calendar-empty:before {\n  content: \"A\";\n}\n.icon-basic-elaboration-calendar-flagged:before {\n  content: \"B\";\n}\n.icon-basic-elaboration-calendar-heart:before {\n  content: \"C\";\n}\n.icon-basic-elaboration-calendar-minus:before {\n  content: \"D\";\n}\n.icon-basic-elaboration-calendar-next:before {\n  content: \"E\";\n}\n.icon-basic-elaboration-calendar-noaccess:before {\n  content: \"F\";\n}\n.icon-basic-elaboration-calendar-pencil:before {\n  content: \"G\";\n}\n.icon-basic-elaboration-calendar-plus:before {\n  content: \"H\";\n}\n.icon-basic-elaboration-calendar-previous:before {\n  content: \"I\";\n}\n.icon-basic-elaboration-calendar-refresh:before {\n  content: \"J\";\n}\n.icon-basic-elaboration-calendar-remove:before {\n  content: \"K\";\n}\n.icon-basic-elaboration-calendar-search:before {\n  content: \"L\";\n}\n.icon-basic-elaboration-calendar-star:before {\n  content: \"M\";\n}\n.icon-basic-elaboration-calendar-upload:before {\n  content: \"N\";\n}\n.icon-basic-elaboration-cloud-check:before {\n  content: \"O\";\n}\n.icon-basic-elaboration-cloud-download:before {\n  content: \"P\";\n}\n.icon-basic-elaboration-cloud-minus:before {\n  content: \"Q\";\n}\n.icon-basic-elaboration-cloud-noaccess:before {\n  content: \"R\";\n}\n.icon-basic-elaboration-cloud-plus:before {\n  content: \"S\";\n}\n.icon-basic-elaboration-cloud-refresh:before {\n  content: \"T\";\n}\n.icon-basic-elaboration-cloud-remove:before {\n  content: \"U\";\n}\n.icon-basic-elaboration-cloud-search:before {\n  content: \"V\";\n}\n.icon-basic-elaboration-cloud-upload:before {\n  content: \"W\";\n}\n.icon-basic-elaboration-document-check:before {\n  content: \"X\";\n}\n.icon-basic-elaboration-document-cloud:before {\n  content: \"Y\";\n}\n.icon-basic-elaboration-document-download:before {\n  content: \"Z\";\n}\n.icon-basic-elaboration-document-flagged:before {\n  content: \"0\";\n}\n.icon-basic-elaboration-document-graph:before {\n  content: \"1\";\n}\n.icon-basic-elaboration-document-heart:before {\n  content: \"2\";\n}\n.icon-basic-elaboration-document-minus:before {\n  content: \"3\";\n}\n.icon-basic-elaboration-document-next:before {\n  content: \"4\";\n}\n.icon-basic-elaboration-document-noaccess:before {\n  content: \"5\";\n}\n.icon-basic-elaboration-document-note:before {\n  content: \"6\";\n}\n.icon-basic-elaboration-document-pencil:before {\n  content: \"7\";\n}\n.icon-basic-elaboration-document-picture:before {\n  content: \"8\";\n}\n.icon-basic-elaboration-document-plus:before {\n  content: \"9\";\n}\n.icon-basic-elaboration-document-previous:before {\n  content: \"!\";\n}\n.icon-basic-elaboration-document-refresh:before {\n  content: \"\\\"\";\n}\n.icon-basic-elaboration-document-remove:before {\n  content: \"#\";\n}\n.icon-basic-elaboration-document-search:before {\n  content: \"$\";\n}\n.icon-basic-elaboration-document-star:before {\n  content: \"%\";\n}\n.icon-basic-elaboration-document-upload:before {\n  content: \"&\";\n}\n.icon-basic-elaboration-folder-check:before {\n  content: \"'\";\n}\n.icon-basic-elaboration-folder-cloud:before {\n  content: \"(\";\n}\n.icon-basic-elaboration-folder-document:before {\n  content: \")\";\n}\n.icon-basic-elaboration-folder-download:before {\n  content: \"*\";\n}\n.icon-basic-elaboration-folder-flagged:before {\n  content: \"+\";\n}\n.icon-basic-elaboration-folder-graph:before {\n  content: \",\";\n}\n.icon-basic-elaboration-folder-heart:before {\n  content: \"-\";\n}\n.icon-basic-elaboration-folder-minus:before {\n  content: \".\";\n}\n.icon-basic-elaboration-folder-next:before {\n  content: \"/\";\n}\n.icon-basic-elaboration-folder-noaccess:before {\n  content: \":\";\n}\n.icon-basic-elaboration-folder-note:before {\n  content: \";\";\n}\n.icon-basic-elaboration-folder-pencil:before {\n  content: \"<\";\n}\n.icon-basic-elaboration-folder-picture:before {\n  content: \"=\";\n}\n.icon-basic-elaboration-folder-plus:before {\n  content: \">\";\n}\n.icon-basic-elaboration-folder-previous:before {\n  content: \"?\";\n}\n.icon-basic-elaboration-folder-refresh:before {\n  content: \"@\";\n}\n.icon-basic-elaboration-folder-remove:before {\n  content: \"[\";\n}\n.icon-basic-elaboration-folder-search:before {\n  content: \"]\";\n}\n.icon-basic-elaboration-folder-star:before {\n  content: \"^\";\n}\n.icon-basic-elaboration-folder-upload:before {\n  content: \"_\";\n}\n.icon-basic-elaboration-mail-check:before {\n  content: \"`\";\n}\n.icon-basic-elaboration-mail-cloud:before {\n  content: \"{\";\n}\n.icon-basic-elaboration-mail-document:before {\n  content: \"|\";\n}\n.icon-basic-elaboration-mail-download:before {\n  content: \"}\";\n}\n.icon-basic-elaboration-mail-flagged:before {\n  content: \"~\";\n}\n.icon-basic-elaboration-mail-heart:before {\n  content: \"\";\n}\n.icon-basic-elaboration-mail-next:before {\n  content: \"\\e000\";\n}\n.icon-basic-elaboration-mail-noaccess:before {\n  content: \"\\e001\";\n}\n.icon-basic-elaboration-mail-note:before {\n  content: \"\\e002\";\n}\n.icon-basic-elaboration-mail-pencil:before {\n  content: \"\\e003\";\n}\n.icon-basic-elaboration-mail-picture:before {\n  content: \"\\e004\";\n}\n.icon-basic-elaboration-mail-previous:before {\n  content: \"\\e005\";\n}\n.icon-basic-elaboration-mail-refresh:before {\n  content: \"\\e006\";\n}\n.icon-basic-elaboration-mail-remove:before {\n  content: \"\\e007\";\n}\n.icon-basic-elaboration-mail-search:before {\n  content: \"\\e008\";\n}\n.icon-basic-elaboration-mail-star:before {\n  content: \"\\e009\";\n}\n.icon-basic-elaboration-mail-upload:before {\n  content: \"\\e00a\";\n}\n.icon-basic-elaboration-message-check:before {\n  content: \"\\e00b\";\n}\n.icon-basic-elaboration-message-dots:before {\n  content: \"\\e00c\";\n}\n.icon-basic-elaboration-message-happy:before {\n  content: \"\\e00d\";\n}\n.icon-basic-elaboration-message-heart:before {\n  content: \"\\e00e\";\n}\n.icon-basic-elaboration-message-minus:before {\n  content: \"\\e00f\";\n}\n.icon-basic-elaboration-message-note:before {\n  content: \"\\e010\";\n}\n.icon-basic-elaboration-message-plus:before {\n  content: \"\\e011\";\n}\n.icon-basic-elaboration-message-refresh:before {\n  content: \"\\e012\";\n}\n.icon-basic-elaboration-message-remove:before {\n  content: \"\\e013\";\n}\n.icon-basic-elaboration-message-sad:before {\n  content: \"\\e014\";\n}\n.icon-basic-elaboration-smartphone-cloud:before {\n  content: \"\\e015\";\n}\n.icon-basic-elaboration-smartphone-heart:before {\n  content: \"\\e016\";\n}\n.icon-basic-elaboration-smartphone-noaccess:before {\n  content: \"\\e017\";\n}\n.icon-basic-elaboration-smartphone-note:before {\n  content: \"\\e018\";\n}\n.icon-basic-elaboration-smartphone-pencil:before {\n  content: \"\\e019\";\n}\n.icon-basic-elaboration-smartphone-picture:before {\n  content: \"\\e01a\";\n}\n.icon-basic-elaboration-smartphone-refresh:before {\n  content: \"\\e01b\";\n}\n.icon-basic-elaboration-smartphone-search:before {\n  content: \"\\e01c\";\n}\n.icon-basic-elaboration-tablet-cloud:before {\n  content: \"\\e01d\";\n}\n.icon-basic-elaboration-tablet-heart:before {\n  content: \"\\e01e\";\n}\n.icon-basic-elaboration-tablet-noaccess:before {\n  content: \"\\e01f\";\n}\n.icon-basic-elaboration-tablet-note:before {\n  content: \"\\e020\";\n}\n.icon-basic-elaboration-tablet-pencil:before {\n  content: \"\\e021\";\n}\n.icon-basic-elaboration-tablet-picture:before {\n  content: \"\\e022\";\n}\n.icon-basic-elaboration-tablet-refresh:before {\n  content: \"\\e023\";\n}\n.icon-basic-elaboration-tablet-search:before {\n  content: \"\\e024\";\n}\n.icon-basic-elaboration-todolist-2:before {\n  content: \"\\e025\";\n}\n.icon-basic-elaboration-todolist-check:before {\n  content: \"\\e026\";\n}\n.icon-basic-elaboration-todolist-cloud:before {\n  content: \"\\e027\";\n}\n.icon-basic-elaboration-todolist-download:before {\n  content: \"\\e028\";\n}\n.icon-basic-elaboration-todolist-flagged:before {\n  content: \"\\e029\";\n}\n.icon-basic-elaboration-todolist-minus:before {\n  content: \"\\e02a\";\n}\n.icon-basic-elaboration-todolist-noaccess:before {\n  content: \"\\e02b\";\n}\n.icon-basic-elaboration-todolist-pencil:before {\n  content: \"\\e02c\";\n}\n.icon-basic-elaboration-todolist-plus:before {\n  content: \"\\e02d\";\n}\n.icon-basic-elaboration-todolist-refresh:before {\n  content: \"\\e02e\";\n}\n.icon-basic-elaboration-todolist-remove:before {\n  content: \"\\e02f\";\n}\n.icon-basic-elaboration-todolist-search:before {\n  content: \"\\e030\";\n}\n.icon-basic-elaboration-todolist-star:before {\n  content: \"\\e031\";\n}\n.icon-basic-elaboration-todolist-upload:before {\n  content: \"\\e032\";\n}\n@font-face {\n  font-family: \"linea-ecommerce-10\";\n  src: url(\"fonts/linea-ecommerce-10.eot\");\n  src: url(\"fonts/linea-ecommerce-10d41d.eot?#iefix\") format(\"embedded-opentype\"), url(\"fonts/linea-ecommerce-10.woff\") format(\"woff\"), url(\"fonts/linea-ecommerce-10.ttf\") format(\"truetype\"), url(\"fonts/linea-ecommerce-10.svg#linea-ecommerce-10\") format(\"svg\");\n  font-weight: normal;\n  font-style: normal;\n}\n.linea-ecommerce[data-icon]:before {\n  font-family: \"linea-ecommerce-10\" !important;\n  content: attr(data-icon);\n  font-style: normal !important;\n  font-weight: normal !important;\n  font-variant: normal !important;\n  text-transform: none !important;\n  speak: none;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n[class^=\"linea-icon-\"]:before,\n[class*=\"linea- icon-\"]:before {\n  font-family: \"linea-ecommerce-10\" !important;\n  font-style: normal !important;\n  font-weight: normal !important;\n  font-variant: normal !important;\n  text-transform: none !important;\n  speak: none;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.icon-ecommerce-bag:before {\n  content: \"a\";\n}\n.icon-ecommerce-bag-check:before {\n  content: \"b\";\n}\n.icon-ecommerce-bag-cloud:before {\n  content: \"c\";\n}\n.icon-ecommerce-bag-download:before {\n  content: \"d\";\n}\n.icon-ecommerce-bag-minus:before {\n  content: \"e\";\n}\n.icon-ecommerce-bag-plus:before {\n  content: \"f\";\n}\n.icon-ecommerce-bag-refresh:before {\n  content: \"g\";\n}\n.icon-ecommerce-bag-remove:before {\n  content: \"h\";\n}\n.icon-ecommerce-bag-search:before {\n  content: \"i\";\n}\n.icon-ecommerce-bag-upload:before {\n  content: \"j\";\n}\n.icon-ecommerce-banknote:before {\n  content: \"k\";\n}\n.icon-ecommerce-banknotes:before {\n  content: \"l\";\n}\n.icon-ecommerce-basket:before {\n  content: \"m\";\n}\n.icon-ecommerce-basket-check:before {\n  content: \"n\";\n}\n.icon-ecommerce-basket-cloud:before {\n  content: \"o\";\n}\n.icon-ecommerce-basket-download:before {\n  content: \"p\";\n}\n.icon-ecommerce-basket-minus:before {\n  content: \"q\";\n}\n.icon-ecommerce-basket-plus:before {\n  content: \"r\";\n}\n.icon-ecommerce-basket-refresh:before {\n  content: \"s\";\n}\n.icon-ecommerce-basket-remove:before {\n  content: \"t\";\n}\n.icon-ecommerce-basket-search:before {\n  content: \"u\";\n}\n.icon-ecommerce-basket-upload:before {\n  content: \"v\";\n}\n.icon-ecommerce-bath:before {\n  content: \"w\";\n}\n.icon-ecommerce-cart:before {\n  content: \"x\";\n}\n.icon-ecommerce-cart-check:before {\n  content: \"y\";\n}\n.icon-ecommerce-cart-cloud:before {\n  content: \"z\";\n}\n.icon-ecommerce-cart-content:before {\n  content: \"A\";\n}\n.icon-ecommerce-cart-download:before {\n  content: \"B\";\n}\n.icon-ecommerce-cart-minus:before {\n  content: \"C\";\n}\n.icon-ecommerce-cart-plus:before {\n  content: \"D\";\n}\n.icon-ecommerce-cart-refresh:before {\n  content: \"E\";\n}\n.icon-ecommerce-cart-remove:before {\n  content: \"F\";\n}\n.icon-ecommerce-cart-search:before {\n  content: \"G\";\n}\n.icon-ecommerce-cart-upload:before {\n  content: \"H\";\n}\n.icon-ecommerce-cent:before {\n  content: \"I\";\n}\n.icon-ecommerce-colon:before {\n  content: \"J\";\n}\n.icon-ecommerce-creditcard:before {\n  content: \"K\";\n}\n.icon-ecommerce-diamond:before {\n  content: \"L\";\n}\n.icon-ecommerce-dollar:before {\n  content: \"M\";\n}\n.icon-ecommerce-euro:before {\n  content: \"N\";\n}\n.icon-ecommerce-franc:before {\n  content: \"O\";\n}\n.icon-ecommerce-gift:before {\n  content: \"P\";\n}\n.icon-ecommerce-graph1:before {\n  content: \"Q\";\n}\n.icon-ecommerce-graph2:before {\n  content: \"R\";\n}\n.icon-ecommerce-graph3:before {\n  content: \"S\";\n}\n.icon-ecommerce-graph-decrease:before {\n  content: \"T\";\n}\n.icon-ecommerce-graph-increase:before {\n  content: \"U\";\n}\n.icon-ecommerce-guarani:before {\n  content: \"V\";\n}\n.icon-ecommerce-kips:before {\n  content: \"W\";\n}\n.icon-ecommerce-lira:before {\n  content: \"X\";\n}\n.icon-ecommerce-megaphone:before {\n  content: \"Y\";\n}\n.icon-ecommerce-money:before {\n  content: \"Z\";\n}\n.icon-ecommerce-naira:before {\n  content: \"0\";\n}\n.icon-ecommerce-pesos:before {\n  content: \"1\";\n}\n.icon-ecommerce-pound:before {\n  content: \"2\";\n}\n.icon-ecommerce-receipt:before {\n  content: \"3\";\n}\n.icon-ecommerce-receipt-bath:before {\n  content: \"4\";\n}\n.icon-ecommerce-receipt-cent:before {\n  content: \"5\";\n}\n.icon-ecommerce-receipt-dollar:before {\n  content: \"6\";\n}\n.icon-ecommerce-receipt-euro:before {\n  content: \"7\";\n}\n.icon-ecommerce-receipt-franc:before {\n  content: \"8\";\n}\n.icon-ecommerce-receipt-guarani:before {\n  content: \"9\";\n}\n.icon-ecommerce-receipt-kips:before {\n  content: \"!\";\n}\n.icon-ecommerce-receipt-lira:before {\n  content: \"\\\"\";\n}\n.icon-ecommerce-receipt-naira:before {\n  content: \"#\";\n}\n.icon-ecommerce-receipt-pesos:before {\n  content: \"$\";\n}\n.icon-ecommerce-receipt-pound:before {\n  content: \"%\";\n}\n.icon-ecommerce-receipt-rublo:before {\n  content: \"&\";\n}\n.icon-ecommerce-receipt-rupee:before {\n  content: \"'\";\n}\n.icon-ecommerce-receipt-tugrik:before {\n  content: \"(\";\n}\n.icon-ecommerce-receipt-won:before {\n  content: \")\";\n}\n.icon-ecommerce-receipt-yen:before {\n  content: \"*\";\n}\n.icon-ecommerce-receipt-yen2:before {\n  content: \"+\";\n}\n.icon-ecommerce-recept-colon:before {\n  content: \",\";\n}\n.icon-ecommerce-rublo:before {\n  content: \"-\";\n}\n.icon-ecommerce-rupee:before {\n  content: \".\";\n}\n.icon-ecommerce-safe:before {\n  content: \"/\";\n}\n.icon-ecommerce-sale:before {\n  content: \":\";\n}\n.icon-ecommerce-sales:before {\n  content: \";\";\n}\n.icon-ecommerce-ticket:before {\n  content: \"<\";\n}\n.icon-ecommerce-tugriks:before {\n  content: \"=\";\n}\n.icon-ecommerce-wallet:before {\n  content: \">\";\n}\n.icon-ecommerce-won:before {\n  content: \"?\";\n}\n.icon-ecommerce-yen:before {\n  content: \"@\";\n}\n.icon-ecommerce-yen2:before {\n  content: \"[\";\n}\n@font-face {\n  font-family: \"linea-music-10\";\n  src: url(\"fonts/linea-music-10.eot\");\n  src: url(\"fonts/linea-music-10d41d.eot?#iefix\") format(\"embedded-opentype\"), url(\"fonts/linea-music-10.woff\") format(\"woff\"), url(\"fonts/linea-music-10.ttf\") format(\"truetype\"), url(\"fonts/linea-music-10.svg#linea-music-10\") format(\"svg\");\n  font-weight: normal;\n  font-style: normal;\n}\n.linea-music[data-icon]:before {\n  font-family: \"linea-music-10\" !important;\n  content: attr(data-icon);\n  font-style: normal !important;\n  font-weight: normal !important;\n  font-variant: normal !important;\n  text-transform: none !important;\n  speak: none;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n[class^=\"linea-icon-\"]:before,\n[class*=\"linea- icon-\"]:before {\n  font-family: \"linea-music-10\" !important;\n  font-style: normal !important;\n  font-weight: normal !important;\n  font-variant: normal !important;\n  text-transform: none !important;\n  speak: none;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.icon-music-beginning-button:before {\n  content: \"a\";\n}\n.icon-music-bell:before {\n  content: \"b\";\n}\n.icon-music-cd:before {\n  content: \"c\";\n}\n.icon-music-diapason:before {\n  content: \"d\";\n}\n.icon-music-eject-button:before {\n  content: \"e\";\n}\n.icon-music-end-button:before {\n  content: \"f\";\n}\n.icon-music-fastforward-button:before {\n  content: \"g\";\n}\n.icon-music-headphones:before {\n  content: \"h\";\n}\n.icon-music-ipod:before {\n  content: \"i\";\n}\n.icon-music-loudspeaker:before {\n  content: \"j\";\n}\n.icon-music-microphone:before {\n  content: \"k\";\n}\n.icon-music-microphone-old:before {\n  content: \"l\";\n}\n.icon-music-mixer:before {\n  content: \"m\";\n}\n.icon-music-mute:before {\n  content: \"n\";\n}\n.icon-music-note-multiple:before {\n  content: \"o\";\n}\n.icon-music-note-single:before {\n  content: \"p\";\n}\n.icon-music-pause-button:before {\n  content: \"q\";\n}\n.icon-music-play-button:before {\n  content: \"r\";\n}\n.icon-music-playlist:before {\n  content: \"s\";\n}\n.icon-music-radio-ghettoblaster:before {\n  content: \"t\";\n}\n.icon-music-radio-portable:before {\n  content: \"u\";\n}\n.icon-music-record:before {\n  content: \"v\";\n}\n.icon-music-recordplayer:before {\n  content: \"w\";\n}\n.icon-music-repeat-button:before {\n  content: \"x\";\n}\n.icon-music-rewind-button:before {\n  content: \"y\";\n}\n.icon-music-shuffle-button:before {\n  content: \"z\";\n}\n.icon-music-stop-button:before {\n  content: \"A\";\n}\n.icon-music-tape:before {\n  content: \"B\";\n}\n.icon-music-volume-down:before {\n  content: \"C\";\n}\n.icon-music-volume-up:before {\n  content: \"D\";\n}\n@font-face {\n  font-family: \"linea-software-10\";\n  src: url(\"fonts/linea-software-10.eot\");\n  src: url(\"fonts/linea-software-10d41d.eot?#iefix\") format(\"embedded-opentype\"), url(\"fonts/linea-software-10.woff\") format(\"woff\"), url(\"fonts/linea-software-10.ttf\") format(\"truetype\"), url(\"fonts/linea-software-10.svg#linea-software-10\") format(\"svg\");\n  font-weight: normal;\n  font-style: normal;\n}\n.linea-software[data-icon]:before {\n  font-family: \"linea-software-10\" !important;\n  content: attr(data-icon);\n  font-style: normal !important;\n  font-weight: normal !important;\n  font-variant: normal !important;\n  text-transform: none !important;\n  speak: none;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n[class^=\"linea-icon-\"]:before,\n[class*=\"linea- icon-\"]:before {\n  font-family: \"linea-software-10\" !important;\n  font-style: normal !important;\n  font-weight: normal !important;\n  font-variant: normal !important;\n  text-transform: none !important;\n  speak: none;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.icon-software-add-vectorpoint:before {\n  content: \"a\";\n}\n.icon-software-box-oval:before {\n  content: \"b\";\n}\n.icon-software-box-polygon:before {\n  content: \"c\";\n}\n.icon-software-box-rectangle:before {\n  content: \"d\";\n}\n.icon-software-box-roundedrectangle:before {\n  content: \"e\";\n}\n.icon-software-character:before {\n  content: \"f\";\n}\n.icon-software-crop:before {\n  content: \"g\";\n}\n.icon-software-eyedropper:before {\n  content: \"h\";\n}\n.icon-software-font-allcaps:before {\n  content: \"i\";\n}\n.icon-software-font-baseline-shift:before {\n  content: \"j\";\n}\n.icon-software-font-horizontal-scale:before {\n  content: \"k\";\n}\n.icon-software-font-kerning:before {\n  content: \"l\";\n}\n.icon-software-font-leading:before {\n  content: \"m\";\n}\n.icon-software-font-size:before {\n  content: \"n\";\n}\n.icon-software-font-smallcapital:before {\n  content: \"o\";\n}\n.icon-software-font-smallcaps:before {\n  content: \"p\";\n}\n.icon-software-font-strikethrough:before {\n  content: \"q\";\n}\n.icon-software-font-tracking:before {\n  content: \"r\";\n}\n.icon-software-font-underline:before {\n  content: \"s\";\n}\n.icon-software-font-vertical-scale:before {\n  content: \"t\";\n}\n.icon-software-horizontal-align-center:before {\n  content: \"u\";\n}\n.icon-software-horizontal-align-left:before {\n  content: \"v\";\n}\n.icon-software-horizontal-align-right:before {\n  content: \"w\";\n}\n.icon-software-horizontal-distribute-center:before {\n  content: \"x\";\n}\n.icon-software-horizontal-distribute-left:before {\n  content: \"y\";\n}\n.icon-software-horizontal-distribute-right:before {\n  content: \"z\";\n}\n.icon-software-indent-firstline:before {\n  content: \"A\";\n}\n.icon-software-indent-left:before {\n  content: \"B\";\n}\n.icon-software-indent-right:before {\n  content: \"C\";\n}\n.icon-software-lasso:before {\n  content: \"D\";\n}\n.icon-software-layers1:before {\n  content: \"E\";\n}\n.icon-software-layers2:before {\n  content: \"F\";\n}\n.icon-software-layout:before {\n  content: \"G\";\n}\n.icon-software-layout-2columns:before {\n  content: \"H\";\n}\n.icon-software-layout-3columns:before {\n  content: \"I\";\n}\n.icon-software-layout-4boxes:before {\n  content: \"J\";\n}\n.icon-software-layout-4columns:before {\n  content: \"K\";\n}\n.icon-software-layout-4lines:before {\n  content: \"L\";\n}\n.icon-software-layout-8boxes:before {\n  content: \"M\";\n}\n.icon-software-layout-header:before {\n  content: \"N\";\n}\n.icon-software-layout-header-2columns:before {\n  content: \"O\";\n}\n.icon-software-layout-header-3columns:before {\n  content: \"P\";\n}\n.icon-software-layout-header-4boxes:before {\n  content: \"Q\";\n}\n.icon-software-layout-header-4columns:before {\n  content: \"R\";\n}\n.icon-software-layout-header-complex:before {\n  content: \"S\";\n}\n.icon-software-layout-header-complex2:before {\n  content: \"T\";\n}\n.icon-software-layout-header-complex3:before {\n  content: \"U\";\n}\n.icon-software-layout-header-complex4:before {\n  content: \"V\";\n}\n.icon-software-layout-header-sideleft:before {\n  content: \"W\";\n}\n.icon-software-layout-header-sideright:before {\n  content: \"X\";\n}\n.icon-software-layout-sidebar-left:before {\n  content: \"Y\";\n}\n.icon-software-layout-sidebar-right:before {\n  content: \"Z\";\n}\n.icon-software-magnete:before {\n  content: \"0\";\n}\n.icon-software-pages:before {\n  content: \"1\";\n}\n.icon-software-paintbrush:before {\n  content: \"2\";\n}\n.icon-software-paintbucket:before {\n  content: \"3\";\n}\n.icon-software-paintroller:before {\n  content: \"4\";\n}\n.icon-software-paragraph:before {\n  content: \"5\";\n}\n.icon-software-paragraph-align-left:before {\n  content: \"6\";\n}\n.icon-software-paragraph-align-right:before {\n  content: \"7\";\n}\n.icon-software-paragraph-center:before {\n  content: \"8\";\n}\n.icon-software-paragraph-justify-all:before {\n  content: \"9\";\n}\n.icon-software-paragraph-justify-center:before {\n  content: \"!\";\n}\n.icon-software-paragraph-justify-left:before {\n  content: \"\\\"\";\n}\n.icon-software-paragraph-justify-right:before {\n  content: \"#\";\n}\n.icon-software-paragraph-space-after:before {\n  content: \"$\";\n}\n.icon-software-paragraph-space-before:before {\n  content: \"%\";\n}\n.icon-software-pathfinder-exclude:before {\n  content: \"&\";\n}\n.icon-software-pathfinder-intersect:before {\n  content: \"'\";\n}\n.icon-software-pathfinder-subtract:before {\n  content: \"(\";\n}\n.icon-software-pathfinder-unite:before {\n  content: \")\";\n}\n.icon-software-pen:before {\n  content: \"*\";\n}\n.icon-software-pen-add:before {\n  content: \"+\";\n}\n.icon-software-pen-remove:before {\n  content: \",\";\n}\n.icon-software-pencil:before {\n  content: \"-\";\n}\n.icon-software-polygonallasso:before {\n  content: \".\";\n}\n.icon-software-reflect-horizontal:before {\n  content: \"/\";\n}\n.icon-software-reflect-vertical:before {\n  content: \":\";\n}\n.icon-software-remove-vectorpoint:before {\n  content: \";\";\n}\n.icon-software-scale-expand:before {\n  content: \"<\";\n}\n.icon-software-scale-reduce:before {\n  content: \"=\";\n}\n.icon-software-selection-oval:before {\n  content: \">\";\n}\n.icon-software-selection-polygon:before {\n  content: \"?\";\n}\n.icon-software-selection-rectangle:before {\n  content: \"@\";\n}\n.icon-software-selection-roundedrectangle:before {\n  content: \"[\";\n}\n.icon-software-shape-oval:before {\n  content: \"]\";\n}\n.icon-software-shape-polygon:before {\n  content: \"^\";\n}\n.icon-software-shape-rectangle:before {\n  content: \"_\";\n}\n.icon-software-shape-roundedrectangle:before {\n  content: \"`\";\n}\n.icon-software-slice:before {\n  content: \"{\";\n}\n.icon-software-transform-bezier:before {\n  content: \"|\";\n}\n.icon-software-vector-box:before {\n  content: \"}\";\n}\n.icon-software-vector-composite:before {\n  content: \"~\";\n}\n.icon-software-vector-line:before {\n  content: \"\";\n}\n.icon-software-vertical-align-bottom:before {\n  content: \"\\e000\";\n}\n.icon-software-vertical-align-center:before {\n  content: \"\\e001\";\n}\n.icon-software-vertical-align-top:before {\n  content: \"\\e002\";\n}\n.icon-software-vertical-distribute-bottom:before {\n  content: \"\\e003\";\n}\n.icon-software-vertical-distribute-center:before {\n  content: \"\\e004\";\n}\n.icon-software-vertical-distribute-top:before {\n  content: \"\\e005\";\n}\n@font-face {\n  font-family: \"linea-weather-10\";\n  src: url(\"fonts/linea-weather-10.eot\");\n  src: url(\"fonts/linea-weather-10d41d.eot?#iefix\") format(\"embedded-opentype\"), url(\"fonts/linea-weather-10.woff\") format(\"woff\"), url(\"fonts/linea-weather-10.ttf\") format(\"truetype\"), url(\"fonts/linea-weather-10.svg#linea-weather-10\") format(\"svg\");\n  font-weight: normal;\n  font-style: normal;\n}\n.linea-weather[data-icon]:before {\n  font-family: \"linea-weather-10\" !important;\n  content: attr(data-icon);\n  font-style: normal !important;\n  font-weight: normal !important;\n  font-variant: normal !important;\n  text-transform: none !important;\n  speak: none;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n[class^=\"linea-icon-\"]:before,\n[class*=\"linea- icon-\"]:before {\n  font-family: \"linea-weather-10\" !important;\n  font-style: normal !important;\n  font-weight: normal !important;\n  font-variant: normal !important;\n  text-transform: none !important;\n  speak: none;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.icon-weather-aquarius:before {\n  content: \"\\e000\";\n}\n.icon-weather-aries:before {\n  content: \"\\e001\";\n}\n.icon-weather-cancer:before {\n  content: \"\\e002\";\n}\n.icon-weather-capricorn:before {\n  content: \"\\e003\";\n}\n.icon-weather-cloud:before {\n  content: \"\\e004\";\n}\n.icon-weather-cloud-drop:before {\n  content: \"\\e005\";\n}\n.icon-weather-cloud-lightning:before {\n  content: \"\\e006\";\n}\n.icon-weather-cloud-snowflake:before {\n  content: \"\\e007\";\n}\n.icon-weather-downpour-fullmoon:before {\n  content: \"\\e008\";\n}\n.icon-weather-downpour-halfmoon:before {\n  content: \"\\e009\";\n}\n.icon-weather-downpour-sun:before {\n  content: \"\\e00a\";\n}\n.icon-weather-drop:before {\n  content: \"\\e00b\";\n}\n.icon-weather-first-quarter:before {\n  content: \"\\e00c\";\n}\n.icon-weather-fog:before {\n  content: \"\\e00d\";\n}\n.icon-weather-fog-fullmoon:before {\n  content: \"\\e00e\";\n}\n.icon-weather-fog-halfmoon:before {\n  content: \"\\e00f\";\n}\n.icon-weather-fog-sun:before {\n  content: \"\\e010\";\n}\n.icon-weather-fullmoon:before {\n  content: \"\\e011\";\n}\n.icon-weather-gemini:before {\n  content: \"\\e012\";\n}\n.icon-weather-hail:before {\n  content: \"\\e013\";\n}\n.icon-weather-hail-fullmoon:before {\n  content: \"\\e014\";\n}\n.icon-weather-hail-halfmoon:before {\n  content: \"\\e015\";\n}\n.icon-weather-hail-sun:before {\n  content: \"\\e016\";\n}\n.icon-weather-last-quarter:before {\n  content: \"\\e017\";\n}\n.icon-weather-leo:before {\n  content: \"\\e018\";\n}\n.icon-weather-libra:before {\n  content: \"\\e019\";\n}\n.icon-weather-lightning:before {\n  content: \"\\e01a\";\n}\n.icon-weather-mistyrain:before {\n  content: \"\\e01b\";\n}\n.icon-weather-mistyrain-fullmoon:before {\n  content: \"\\e01c\";\n}\n.icon-weather-mistyrain-halfmoon:before {\n  content: \"\\e01d\";\n}\n.icon-weather-mistyrain-sun:before {\n  content: \"\\e01e\";\n}\n.icon-weather-moon:before {\n  content: \"\\e01f\";\n}\n.icon-weather-moondown-full:before {\n  content: \"\\e020\";\n}\n.icon-weather-moondown-half:before {\n  content: \"\\e021\";\n}\n.icon-weather-moonset-full:before {\n  content: \"\\e022\";\n}\n.icon-weather-moonset-half:before {\n  content: \"\\e023\";\n}\n.icon-weather-move2:before {\n  content: \"\\e024\";\n}\n.icon-weather-newmoon:before {\n  content: \"\\e025\";\n}\n.icon-weather-pisces:before {\n  content: \"\\e026\";\n}\n.icon-weather-rain:before {\n  content: \"\\e027\";\n}\n.icon-weather-rain-fullmoon:before {\n  content: \"\\e028\";\n}\n.icon-weather-rain-halfmoon:before {\n  content: \"\\e029\";\n}\n.icon-weather-rain-sun:before {\n  content: \"\\e02a\";\n}\n.icon-weather-sagittarius:before {\n  content: \"\\e02b\";\n}\n.icon-weather-scorpio:before {\n  content: \"\\e02c\";\n}\n.icon-weather-snow:before {\n  content: \"\\e02d\";\n}\n.icon-weather-snow-fullmoon:before {\n  content: \"\\e02e\";\n}\n.icon-weather-snow-halfmoon:before {\n  content: \"\\e02f\";\n}\n.icon-weather-snow-sun:before {\n  content: \"\\e030\";\n}\n.icon-weather-snowflake:before {\n  content: \"\\e031\";\n}\n.icon-weather-star:before {\n  content: \"\\e032\";\n}\n.icon-weather-storm-11:before {\n  content: \"\\e033\";\n}\n.icon-weather-storm-32:before {\n  content: \"\\e034\";\n}\n.icon-weather-storm-fullmoon:before {\n  content: \"\\e035\";\n}\n.icon-weather-storm-halfmoon:before {\n  content: \"\\e036\";\n}\n.icon-weather-storm-sun:before {\n  content: \"\\e037\";\n}\n.icon-weather-sun:before {\n  content: \"\\e038\";\n}\n.icon-weather-sundown:before {\n  content: \"\\e039\";\n}\n.icon-weather-sunset:before {\n  content: \"\\e03a\";\n}\n.icon-weather-taurus:before {\n  content: \"\\e03b\";\n}\n.icon-weather-tempest:before {\n  content: \"\\e03c\";\n}\n.icon-weather-tempest-fullmoon:before {\n  content: \"\\e03d\";\n}\n.icon-weather-tempest-halfmoon:before {\n  content: \"\\e03e\";\n}\n.icon-weather-tempest-sun:before {\n  content: \"\\e03f\";\n}\n.icon-weather-variable-fullmoon:before {\n  content: \"\\e040\";\n}\n.icon-weather-variable-halfmoon:before {\n  content: \"\\e041\";\n}\n.icon-weather-variable-sun:before {\n  content: \"\\e042\";\n}\n.icon-weather-virgo:before {\n  content: \"\\e043\";\n}\n.icon-weather-waning-cresent:before {\n  content: \"\\e044\";\n}\n.icon-weather-waning-gibbous:before {\n  content: \"\\e045\";\n}\n.icon-weather-waxing-cresent:before {\n  content: \"\\e046\";\n}\n.icon-weather-waxing-gibbous:before {\n  content: \"\\e047\";\n}\n.icon-weather-wind:before {\n  content: \"\\e048\";\n}\n.icon-weather-wind-e:before {\n  content: \"\\e049\";\n}\n.icon-weather-wind-fullmoon:before {\n  content: \"\\e04a\";\n}\n.icon-weather-wind-halfmoon:before {\n  content: \"\\e04b\";\n}\n.icon-weather-wind-n:before {\n  content: \"\\e04c\";\n}\n.icon-weather-wind-ne:before {\n  content: \"\\e04d\";\n}\n.icon-weather-wind-nw:before {\n  content: \"\\e04e\";\n}\n.icon-weather-wind-s:before {\n  content: \"\\e04f\";\n}\n.icon-weather-wind-se:before {\n  content: \"\\e050\";\n}\n.icon-weather-wind-sun:before {\n  content: \"\\e051\";\n}\n.icon-weather-wind-sw:before {\n  content: \"\\e052\";\n}\n.icon-weather-wind-w:before {\n  content: \"\\e053\";\n}\n.icon-weather-windgust:before {\n  content: \"\\e054\";\n}"
  },
  {
    "path": "static/icons/simple-line-icons/css/simple-line-icons.css",
    "content": "@font-face {\n  font-family: 'simple-line-icons';\n  src: url('../fonts/Simple-Line-Icons4c82.eot?-i3a2kk');\n  src: url('../fonts/Simple-Line-Iconsd41d.eot?#iefix-i3a2kk') format('embedded-opentype'), url('../fonts/Simple-Line-Icons4c82.ttf?-i3a2kk') format('truetype'), url('../fonts/Simple-Line-Icons4c82.woff2?-i3a2kk') format('woff2'), url('../fonts/Simple-Line-Icons4c82.woff?-i3a2kk') format('woff'), url('../fonts/Simple-Line-Icons4c82.svg?-i3a2kk#simple-line-icons') format('svg');\n  font-weight: normal;\n  font-style: normal;\n}\n/*\n Use the following CSS code if you want to have a class per icon.\n Instead of a list of all class selectors, you can use the generic [class*=\"icon-\"] selector, but it's slower: \n*/\n.icon-user,\n.icon-people,\n.icon-user-female,\n.icon-user-follow,\n.icon-user-following,\n.icon-user-unfollow,\n.icon-login,\n.icon-logout,\n.icon-emotsmile,\n.icon-phone,\n.icon-call-end,\n.icon-call-in,\n.icon-call-out,\n.icon-map,\n.icon-location-pin,\n.icon-direction,\n.icon-directions,\n.icon-compass,\n.icon-layers,\n.icon-menu,\n.icon-list,\n.icon-options-vertical,\n.icon-options,\n.icon-arrow-down,\n.icon-arrow-left,\n.icon-arrow-right,\n.icon-arrow-up,\n.icon-arrow-up-circle,\n.icon-arrow-left-circle,\n.icon-arrow-right-circle,\n.icon-arrow-down-circle,\n.icon-check,\n.icon-clock,\n.icon-plus,\n.icon-close,\n.icon-trophy,\n.icon-screen-smartphone,\n.icon-screen-desktop,\n.icon-plane,\n.icon-notebook,\n.icon-mustache,\n.icon-mouse,\n.icon-magnet,\n.icon-energy,\n.icon-disc,\n.icon-cursor,\n.icon-cursor-move,\n.icon-crop,\n.icon-chemistry,\n.icon-speedometer,\n.icon-shield,\n.icon-screen-tablet,\n.icon-magic-wand,\n.icon-hourglass,\n.icon-graduation,\n.icon-ghost,\n.icon-game-controller,\n.icon-fire,\n.icon-eyeglass,\n.icon-envelope-open,\n.icon-envelope-letter,\n.icon-bell,\n.icon-badge,\n.icon-anchor,\n.icon-wallet,\n.icon-vector,\n.icon-speech,\n.icon-puzzle,\n.icon-printer,\n.icon-present,\n.icon-playlist,\n.icon-pin,\n.icon-picture,\n.icon-handbag,\n.icon-globe-alt,\n.icon-globe,\n.icon-folder-alt,\n.icon-folder,\n.icon-film,\n.icon-feed,\n.icon-drop,\n.icon-drawar,\n.icon-docs,\n.icon-doc,\n.icon-diamond,\n.icon-cup,\n.icon-calculator,\n.icon-bubbles,\n.icon-briefcase,\n.icon-book-open,\n.icon-basket-loaded,\n.icon-basket,\n.icon-bag,\n.icon-action-undo,\n.icon-action-redo,\n.icon-wrench,\n.icon-umbrella,\n.icon-trash,\n.icon-tag,\n.icon-support,\n.icon-frame,\n.icon-size-fullscreen,\n.icon-size-actual,\n.icon-shuffle,\n.icon-share-alt,\n.icon-share,\n.icon-rocket,\n.icon-question,\n.icon-pie-chart,\n.icon-pencil,\n.icon-note,\n.icon-loop,\n.icon-home,\n.icon-grid,\n.icon-graph,\n.icon-microphone,\n.icon-music-tone-alt,\n.icon-music-tone,\n.icon-earphones-alt,\n.icon-earphones,\n.icon-equalizer,\n.icon-like,\n.icon-dislike,\n.icon-control-start,\n.icon-control-rewind,\n.icon-control-play,\n.icon-control-pause,\n.icon-control-forward,\n.icon-control-end,\n.icon-volume-1,\n.icon-volume-2,\n.icon-volume-off,\n.icon-calender,\n.icon-bulb,\n.icon-chart,\n.icon-ban,\n.icon-bubble,\n.icon-camrecorder,\n.icon-camera,\n.icon-cloud-download,\n.icon-cloud-upload,\n.icon-envelope,\n.icon-eye,\n.icon-flag,\n.icon-heart,\n.icon-info,\n.icon-key,\n.icon-link,\n.icon-lock,\n.icon-lock-open,\n.icon-magnifier,\n.icon-magnifier-add,\n.icon-magnifier-remove,\n.icon-paper-clip,\n.icon-paper-plane,\n.icon-power,\n.icon-refresh,\n.icon-reload,\n.icon-settings,\n.icon-star,\n.icon-symble-female,\n.icon-symbol-male,\n.icon-target,\n.icon-credit-card,\n.icon-paypal,\n.icon-social-tumblr,\n.icon-social-twitter,\n.icon-social-facebook,\n.icon-social-instagram,\n.icon-social-linkedin,\n.icon-social-pintarest,\n.icon-social-github,\n.icon-social-gplus,\n.icon-social-reddit,\n.icon-social-skype,\n.icon-social-dribbble,\n.icon-social-behance,\n.icon-social-foursqare,\n.icon-social-soundcloud,\n.icon-social-spotify,\n.icon-social-stumbleupon,\n.icon-social-youtube,\n.icon-social-dropbox {\n  font-family: 'simple-line-icons';\n  speak: none;\n  font-style: normal;\n  font-weight: normal;\n  font-variant: normal;\n  text-transform: none;\n  line-height: 1;\n  /* Better Font Rendering =========== */\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.icon-user:before {\n  content: \"\\e005\";\n}\n.icon-people:before {\n  content: \"\\e001\";\n}\n.icon-user-female:before {\n  content: \"\\e000\";\n}\n.icon-user-follow:before {\n  content: \"\\e002\";\n}\n.icon-user-following:before {\n  content: \"\\e003\";\n}\n.icon-user-unfollow:before {\n  content: \"\\e004\";\n}\n.icon-login:before {\n  content: \"\\e066\";\n}\n.icon-logout:before {\n  content: \"\\e065\";\n}\n.icon-emotsmile:before {\n  content: \"\\e021\";\n}\n.icon-phone:before {\n  content: \"\\e600\";\n}\n.icon-call-end:before {\n  content: \"\\e048\";\n}\n.icon-call-in:before {\n  content: \"\\e047\";\n}\n.icon-call-out:before {\n  content: \"\\e046\";\n}\n.icon-map:before {\n  content: \"\\e033\";\n}\n.icon-location-pin:before {\n  content: \"\\e096\";\n}\n.icon-direction:before {\n  content: \"\\e042\";\n}\n.icon-directions:before {\n  content: \"\\e041\";\n}\n.icon-compass:before {\n  content: \"\\e045\";\n}\n.icon-layers:before {\n  content: \"\\e034\";\n}\n.icon-menu:before {\n  content: \"\\e601\";\n}\n.icon-list:before {\n  content: \"\\e067\";\n}\n.icon-options-vertical:before {\n  content: \"\\e602\";\n}\n.icon-options:before {\n  content: \"\\e603\";\n}\n.icon-arrow-down:before {\n  content: \"\\e604\";\n}\n.icon-arrow-left:before {\n  content: \"\\e605\";\n}\n.icon-arrow-right:before {\n  content: \"\\e606\";\n}\n.icon-arrow-up:before {\n  content: \"\\e607\";\n}\n.icon-arrow-up-circle:before {\n  content: \"\\e078\";\n}\n.icon-arrow-left-circle:before {\n  content: \"\\e07a\";\n}\n.icon-arrow-right-circle:before {\n  content: \"\\e079\";\n}\n.icon-arrow-down-circle:before {\n  content: \"\\e07b\";\n}\n.icon-check:before {\n  content: \"\\e080\";\n}\n.icon-clock:before {\n  content: \"\\e081\";\n}\n.icon-plus:before {\n  content: \"\\e095\";\n}\n.icon-close:before {\n  content: \"\\e082\";\n}\n.icon-trophy:before {\n  content: \"\\e006\";\n}\n.icon-screen-smartphone:before {\n  content: \"\\e010\";\n}\n.icon-screen-desktop:before {\n  content: \"\\e011\";\n}\n.icon-plane:before {\n  content: \"\\e012\";\n}\n.icon-notebook:before {\n  content: \"\\e013\";\n}\n.icon-mustache:before {\n  content: \"\\e014\";\n}\n.icon-mouse:before {\n  content: \"\\e015\";\n}\n.icon-magnet:before {\n  content: \"\\e016\";\n}\n.icon-energy:before {\n  content: \"\\e020\";\n}\n.icon-disc:before {\n  content: \"\\e022\";\n}\n.icon-cursor:before {\n  content: \"\\e06e\";\n}\n.icon-cursor-move:before {\n  content: \"\\e023\";\n}\n.icon-crop:before {\n  content: \"\\e024\";\n}\n.icon-chemistry:before {\n  content: \"\\e026\";\n}\n.icon-speedometer:before {\n  content: \"\\e007\";\n}\n.icon-shield:before {\n  content: \"\\e00e\";\n}\n.icon-screen-tablet:before {\n  content: \"\\e00f\";\n}\n.icon-magic-wand:before {\n  content: \"\\e017\";\n}\n.icon-hourglass:before {\n  content: \"\\e018\";\n}\n.icon-graduation:before {\n  content: \"\\e019\";\n}\n.icon-ghost:before {\n  content: \"\\e01a\";\n}\n.icon-game-controller:before {\n  content: \"\\e01b\";\n}\n.icon-fire:before {\n  content: \"\\e01c\";\n}\n.icon-eyeglass:before {\n  content: \"\\e01d\";\n}\n.icon-envelope-open:before {\n  content: \"\\e01e\";\n}\n.icon-envelope-letter:before {\n  content: \"\\e01f\";\n}\n.icon-bell:before {\n  content: \"\\e027\";\n}\n.icon-badge:before {\n  content: \"\\e028\";\n}\n.icon-anchor:before {\n  content: \"\\e029\";\n}\n.icon-wallet:before {\n  content: \"\\e02a\";\n}\n.icon-vector:before {\n  content: \"\\e02b\";\n}\n.icon-speech:before {\n  content: \"\\e02c\";\n}\n.icon-puzzle:before {\n  content: \"\\e02d\";\n}\n.icon-printer:before {\n  content: \"\\e02e\";\n}\n.icon-present:before {\n  content: \"\\e02f\";\n}\n.icon-playlist:before {\n  content: \"\\e030\";\n}\n.icon-pin:before {\n  content: \"\\e031\";\n}\n.icon-picture:before {\n  content: \"\\e032\";\n}\n.icon-handbag:before {\n  content: \"\\e035\";\n}\n.icon-globe-alt:before {\n  content: \"\\e036\";\n}\n.icon-globe:before {\n  content: \"\\e037\";\n}\n.icon-folder-alt:before {\n  content: \"\\e039\";\n}\n.icon-folder:before {\n  content: \"\\e089\";\n}\n.icon-film:before {\n  content: \"\\e03a\";\n}\n.icon-feed:before {\n  content: \"\\e03b\";\n}\n.icon-drop:before {\n  content: \"\\e03e\";\n}\n.icon-drawar:before {\n  content: \"\\e03f\";\n}\n.icon-docs:before {\n  content: \"\\e040\";\n}\n.icon-doc:before {\n  content: \"\\e085\";\n}\n.icon-diamond:before {\n  content: \"\\e043\";\n}\n.icon-cup:before {\n  content: \"\\e044\";\n}\n.icon-calculator:before {\n  content: \"\\e049\";\n}\n.icon-bubbles:before {\n  content: \"\\e04a\";\n}\n.icon-briefcase:before {\n  content: \"\\e04b\";\n}\n.icon-book-open:before {\n  content: \"\\e04c\";\n}\n.icon-basket-loaded:before {\n  content: \"\\e04d\";\n}\n.icon-basket:before {\n  content: \"\\e04e\";\n}\n.icon-bag:before {\n  content: \"\\e04f\";\n}\n.icon-action-undo:before {\n  content: \"\\e050\";\n}\n.icon-action-redo:before {\n  content: \"\\e051\";\n}\n.icon-wrench:before {\n  content: \"\\e052\";\n}\n.icon-umbrella:before {\n  content: \"\\e053\";\n}\n.icon-trash:before {\n  content: \"\\e054\";\n}\n.icon-tag:before {\n  content: \"\\e055\";\n}\n.icon-support:before {\n  content: \"\\e056\";\n}\n.icon-frame:before {\n  content: \"\\e038\";\n}\n.icon-size-fullscreen:before {\n  content: \"\\e057\";\n}\n.icon-size-actual:before {\n  content: \"\\e058\";\n}\n.icon-shuffle:before {\n  content: \"\\e059\";\n}\n.icon-share-alt:before {\n  content: \"\\e05a\";\n}\n.icon-share:before {\n  content: \"\\e05b\";\n}\n.icon-rocket:before {\n  content: \"\\e05c\";\n}\n.icon-question:before {\n  content: \"\\e05d\";\n}\n.icon-pie-chart:before {\n  content: \"\\e05e\";\n}\n.icon-pencil:before {\n  content: \"\\e05f\";\n}\n.icon-note:before {\n  content: \"\\e060\";\n}\n.icon-loop:before {\n  content: \"\\e064\";\n}\n.icon-home:before {\n  content: \"\\e069\";\n}\n.icon-grid:before {\n  content: \"\\e06a\";\n}\n.icon-graph:before {\n  content: \"\\e06b\";\n}\n.icon-microphone:before {\n  content: \"\\e063\";\n}\n.icon-music-tone-alt:before {\n  content: \"\\e061\";\n}\n.icon-music-tone:before {\n  content: \"\\e062\";\n}\n.icon-earphones-alt:before {\n  content: \"\\e03c\";\n}\n.icon-earphones:before {\n  content: \"\\e03d\";\n}\n.icon-equalizer:before {\n  content: \"\\e06c\";\n}\n.icon-like:before {\n  content: \"\\e068\";\n}\n.icon-dislike:before {\n  content: \"\\e06d\";\n}\n.icon-control-start:before {\n  content: \"\\e06f\";\n}\n.icon-control-rewind:before {\n  content: \"\\e070\";\n}\n.icon-control-play:before {\n  content: \"\\e071\";\n}\n.icon-control-pause:before {\n  content: \"\\e072\";\n}\n.icon-control-forward:before {\n  content: \"\\e073\";\n}\n.icon-control-end:before {\n  content: \"\\e074\";\n}\n.icon-volume-1:before {\n  content: \"\\e09f\";\n}\n.icon-volume-2:before {\n  content: \"\\e0a0\";\n}\n.icon-volume-off:before {\n  content: \"\\e0a1\";\n}\n.icon-calender:before {\n  content: \"\\e075\";\n}\n.icon-bulb:before {\n  content: \"\\e076\";\n}\n.icon-chart:before {\n  content: \"\\e077\";\n}\n.icon-ban:before {\n  content: \"\\e07c\";\n}\n.icon-bubble:before {\n  content: \"\\e07d\";\n}\n.icon-camrecorder:before {\n  content: \"\\e07e\";\n}\n.icon-camera:before {\n  content: \"\\e07f\";\n}\n.icon-cloud-download:before {\n  content: \"\\e083\";\n}\n.icon-cloud-upload:before {\n  content: \"\\e084\";\n}\n.icon-envelope:before {\n  content: \"\\e086\";\n}\n.icon-eye:before {\n  content: \"\\e087\";\n}\n.icon-flag:before {\n  content: \"\\e088\";\n}\n.icon-heart:before {\n  content: \"\\e08a\";\n}\n.icon-info:before {\n  content: \"\\e08b\";\n}\n.icon-key:before {\n  content: \"\\e08c\";\n}\n.icon-link:before {\n  content: \"\\e08d\";\n}\n.icon-lock:before {\n  content: \"\\e08e\";\n}\n.icon-lock-open:before {\n  content: \"\\e08f\";\n}\n.icon-magnifier:before {\n  content: \"\\e090\";\n}\n.icon-magnifier-add:before {\n  content: \"\\e091\";\n}\n.icon-magnifier-remove:before {\n  content: \"\\e092\";\n}\n.icon-paper-clip:before {\n  content: \"\\e093\";\n}\n.icon-paper-plane:before {\n  content: \"\\e094\";\n}\n.icon-power:before {\n  content: \"\\e097\";\n}\n.icon-refresh:before {\n  content: \"\\e098\";\n}\n.icon-reload:before {\n  content: \"\\e099\";\n}\n.icon-settings:before {\n  content: \"\\e09a\";\n}\n.icon-star:before {\n  content: \"\\e09b\";\n}\n.icon-symble-female:before {\n  content: \"\\e09c\";\n}\n.icon-symbol-male:before {\n  content: \"\\e09d\";\n}\n.icon-target:before {\n  content: \"\\e09e\";\n}\n.icon-credit-card:before {\n  content: \"\\e025\";\n}\n.icon-paypal:before {\n  content: \"\\e608\";\n}\n.icon-social-tumblr:before {\n  content: \"\\e00a\";\n}\n.icon-social-twitter:before {\n  content: \"\\e009\";\n}\n.icon-social-facebook:before {\n  content: \"\\e00b\";\n}\n.icon-social-instagram:before {\n  content: \"\\e609\";\n}\n.icon-social-linkedin:before {\n  content: \"\\e60a\";\n}\n.icon-social-pintarest:before {\n  content: \"\\e60b\";\n}\n.icon-social-github:before {\n  content: \"\\e60c\";\n}\n.icon-social-gplus:before {\n  content: \"\\e60d\";\n}\n.icon-social-reddit:before {\n  content: \"\\e60e\";\n}\n.icon-social-skype:before {\n  content: \"\\e60f\";\n}\n.icon-social-dribbble:before {\n  content: \"\\e00d\";\n}\n.icon-social-behance:before {\n  content: \"\\e610\";\n}\n.icon-social-foursqare:before {\n  content: \"\\e611\";\n}\n.icon-social-soundcloud:before {\n  content: \"\\e612\";\n}\n.icon-social-spotify:before {\n  content: \"\\e613\";\n}\n.icon-social-stumbleupon:before {\n  content: \"\\e614\";\n}\n.icon-social-youtube:before {\n  content: \"\\e008\";\n}\n.icon-social-dropbox:before {\n  content: \"\\e00c\";\n}\n"
  },
  {
    "path": "static/icons/themify-icons/themify-icons.css",
    "content": "@font-face {\n\tfont-family: 'themify';\n\tsrc:url('fonts/themify9f24.eot?-fvbane');\n\tsrc:url('fonts/themifyd41d.eot?#iefix-fvbane') format('embedded-opentype'),\n\t\turl('fonts/themify.woff') format('woff'),\n\t\turl('fonts/themify.ttf') format('truetype'),\n\t\turl('fonts/themify9f24.svg?-fvbane#themify') format('svg');\n\tfont-weight: normal;\n\tfont-style: normal;\n}\n\n[class^=\"ti-\"], [class*=\" ti-\"] {\n\tfont-family: 'themify';\n\tspeak: none;\n\tfont-style: normal;\n\tfont-weight: normal;\n\tfont-variant: normal;\n\ttext-transform: none;\n\tline-height: 1;\n\n\t/* Better Font Rendering =========== */\n\t-webkit-font-smoothing: antialiased;\n\t-moz-osx-font-smoothing: grayscale;\n}\n\n.ti-wand:before {\n\tcontent: \"\\e600\";\n}\n.ti-volume:before {\n\tcontent: \"\\e601\";\n}\n.ti-user:before {\n\tcontent: \"\\e602\";\n}\n.ti-unlock:before {\n\tcontent: \"\\e603\";\n}\n.ti-unlink:before {\n\tcontent: \"\\e604\";\n}\n.ti-trash:before {\n\tcontent: \"\\e605\";\n}\n.ti-thought:before {\n\tcontent: \"\\e606\";\n}\n.ti-target:before {\n\tcontent: \"\\e607\";\n}\n.ti-tag:before {\n\tcontent: \"\\e608\";\n}\n.ti-tablet:before {\n\tcontent: \"\\e609\";\n}\n.ti-star:before {\n\tcontent: \"\\e60a\";\n}\n.ti-spray:before {\n\tcontent: \"\\e60b\";\n}\n.ti-signal:before {\n\tcontent: \"\\e60c\";\n}\n.ti-shopping-cart:before {\n\tcontent: \"\\e60d\";\n}\n.ti-shopping-cart-full:before {\n\tcontent: \"\\e60e\";\n}\n.ti-settings:before {\n\tcontent: \"\\e60f\";\n}\n.ti-search:before {\n\tcontent: \"\\e610\";\n}\n.ti-zoom-in:before {\n\tcontent: \"\\e611\";\n}\n.ti-zoom-out:before {\n\tcontent: \"\\e612\";\n}\n.ti-cut:before {\n\tcontent: \"\\e613\";\n}\n.ti-ruler:before {\n\tcontent: \"\\e614\";\n}\n.ti-ruler-pencil:before {\n\tcontent: \"\\e615\";\n}\n.ti-ruler-alt:before {\n\tcontent: \"\\e616\";\n}\n.ti-bookmark:before {\n\tcontent: \"\\e617\";\n}\n.ti-bookmark-alt:before {\n\tcontent: \"\\e618\";\n}\n.ti-reload:before {\n\tcontent: \"\\e619\";\n}\n.ti-plus:before {\n\tcontent: \"\\e61a\";\n}\n.ti-pin:before {\n\tcontent: \"\\e61b\";\n}\n.ti-pencil:before {\n\tcontent: \"\\e61c\";\n}\n.ti-pencil-alt:before {\n\tcontent: \"\\e61d\";\n}\n.ti-paint-roller:before {\n\tcontent: \"\\e61e\";\n}\n.ti-paint-bucket:before {\n\tcontent: \"\\e61f\";\n}\n.ti-na:before {\n\tcontent: \"\\e620\";\n}\n.ti-mobile:before {\n\tcontent: \"\\e621\";\n}\n.ti-minus:before {\n\tcontent: \"\\e622\";\n}\n.ti-medall:before {\n\tcontent: \"\\e623\";\n}\n.ti-medall-alt:before {\n\tcontent: \"\\e624\";\n}\n.ti-marker:before {\n\tcontent: \"\\e625\";\n}\n.ti-marker-alt:before {\n\tcontent: \"\\e626\";\n}\n.ti-arrow-up:before {\n\tcontent: \"\\e627\";\n}\n.ti-arrow-right:before {\n\tcontent: \"\\e628\";\n}\n.ti-arrow-left:before {\n\tcontent: \"\\e629\";\n}\n.ti-arrow-down:before {\n\tcontent: \"\\e62a\";\n}\n.ti-lock:before {\n\tcontent: \"\\e62b\";\n}\n.ti-location-arrow:before {\n\tcontent: \"\\e62c\";\n}\n.ti-link:before {\n\tcontent: \"\\e62d\";\n}\n.ti-layout:before {\n\tcontent: \"\\e62e\";\n}\n.ti-layers:before {\n\tcontent: \"\\e62f\";\n}\n.ti-layers-alt:before {\n\tcontent: \"\\e630\";\n}\n.ti-key:before {\n\tcontent: \"\\e631\";\n}\n.ti-import:before {\n\tcontent: \"\\e632\";\n}\n.ti-image:before {\n\tcontent: \"\\e633\";\n}\n.ti-heart:before {\n\tcontent: \"\\e634\";\n}\n.ti-heart-broken:before {\n\tcontent: \"\\e635\";\n}\n.ti-hand-stop:before {\n\tcontent: \"\\e636\";\n}\n.ti-hand-open:before {\n\tcontent: \"\\e637\";\n}\n.ti-hand-drag:before {\n\tcontent: \"\\e638\";\n}\n.ti-folder:before {\n\tcontent: \"\\e639\";\n}\n.ti-flag:before {\n\tcontent: \"\\e63a\";\n}\n.ti-flag-alt:before {\n\tcontent: \"\\e63b\";\n}\n.ti-flag-alt-2:before {\n\tcontent: \"\\e63c\";\n}\n.ti-eye:before {\n\tcontent: \"\\e63d\";\n}\n.ti-export:before {\n\tcontent: \"\\e63e\";\n}\n.ti-exchange-vertical:before {\n\tcontent: \"\\e63f\";\n}\n.ti-desktop:before {\n\tcontent: \"\\e640\";\n}\n.ti-cup:before {\n\tcontent: \"\\e641\";\n}\n.ti-crown:before {\n\tcontent: \"\\e642\";\n}\n.ti-comments:before {\n\tcontent: \"\\e643\";\n}\n.ti-comment:before {\n\tcontent: \"\\e644\";\n}\n.ti-comment-alt:before {\n\tcontent: \"\\e645\";\n}\n.ti-close:before {\n\tcontent: \"\\e646\";\n}\n.ti-clip:before {\n\tcontent: \"\\e647\";\n}\n.ti-angle-up:before {\n\tcontent: \"\\e648\";\n}\n.ti-angle-right:before {\n\tcontent: \"\\e649\";\n}\n.ti-angle-left:before {\n\tcontent: \"\\e64a\";\n}\n.ti-angle-down:before {\n\tcontent: \"\\e64b\";\n}\n.ti-check:before {\n\tcontent: \"\\e64c\";\n}\n.ti-check-box:before {\n\tcontent: \"\\e64d\";\n}\n.ti-camera:before {\n\tcontent: \"\\e64e\";\n}\n.ti-announcement:before {\n\tcontent: \"\\e64f\";\n}\n.ti-brush:before {\n\tcontent: \"\\e650\";\n}\n.ti-briefcase:before {\n\tcontent: \"\\e651\";\n}\n.ti-bolt:before {\n\tcontent: \"\\e652\";\n}\n.ti-bolt-alt:before {\n\tcontent: \"\\e653\";\n}\n.ti-blackboard:before {\n\tcontent: \"\\e654\";\n}\n.ti-bag:before {\n\tcontent: \"\\e655\";\n}\n.ti-move:before {\n\tcontent: \"\\e656\";\n}\n.ti-arrows-vertical:before {\n\tcontent: \"\\e657\";\n}\n.ti-arrows-horizontal:before {\n\tcontent: \"\\e658\";\n}\n.ti-fullscreen:before {\n\tcontent: \"\\e659\";\n}\n.ti-arrow-top-right:before {\n\tcontent: \"\\e65a\";\n}\n.ti-arrow-top-left:before {\n\tcontent: \"\\e65b\";\n}\n.ti-arrow-circle-up:before {\n\tcontent: \"\\e65c\";\n}\n.ti-arrow-circle-right:before {\n\tcontent: \"\\e65d\";\n}\n.ti-arrow-circle-left:before {\n\tcontent: \"\\e65e\";\n}\n.ti-arrow-circle-down:before {\n\tcontent: \"\\e65f\";\n}\n.ti-angle-double-up:before {\n\tcontent: \"\\e660\";\n}\n.ti-angle-double-right:before {\n\tcontent: \"\\e661\";\n}\n.ti-angle-double-left:before {\n\tcontent: \"\\e662\";\n}\n.ti-angle-double-down:before {\n\tcontent: \"\\e663\";\n}\n.ti-zip:before {\n\tcontent: \"\\e664\";\n}\n.ti-world:before {\n\tcontent: \"\\e665\";\n}\n.ti-wheelchair:before {\n\tcontent: \"\\e666\";\n}\n.ti-view-list:before {\n\tcontent: \"\\e667\";\n}\n.ti-view-list-alt:before {\n\tcontent: \"\\e668\";\n}\n.ti-view-grid:before {\n\tcontent: \"\\e669\";\n}\n.ti-uppercase:before {\n\tcontent: \"\\e66a\";\n}\n.ti-upload:before {\n\tcontent: \"\\e66b\";\n}\n.ti-underline:before {\n\tcontent: \"\\e66c\";\n}\n.ti-truck:before {\n\tcontent: \"\\e66d\";\n}\n.ti-timer:before {\n\tcontent: \"\\e66e\";\n}\n.ti-ticket:before {\n\tcontent: \"\\e66f\";\n}\n.ti-thumb-up:before {\n\tcontent: \"\\e670\";\n}\n.ti-thumb-down:before {\n\tcontent: \"\\e671\";\n}\n.ti-text:before {\n\tcontent: \"\\e672\";\n}\n.ti-stats-up:before {\n\tcontent: \"\\e673\";\n}\n.ti-stats-down:before {\n\tcontent: \"\\e674\";\n}\n.ti-split-v:before {\n\tcontent: \"\\e675\";\n}\n.ti-split-h:before {\n\tcontent: \"\\e676\";\n}\n.ti-smallcap:before {\n\tcontent: \"\\e677\";\n}\n.ti-shine:before {\n\tcontent: \"\\e678\";\n}\n.ti-shift-right:before {\n\tcontent: \"\\e679\";\n}\n.ti-shift-left:before {\n\tcontent: \"\\e67a\";\n}\n.ti-shield:before {\n\tcontent: \"\\e67b\";\n}\n.ti-notepad:before {\n\tcontent: \"\\e67c\";\n}\n.ti-server:before {\n\tcontent: \"\\e67d\";\n}\n.ti-quote-right:before {\n\tcontent: \"\\e67e\";\n}\n.ti-quote-left:before {\n\tcontent: \"\\e67f\";\n}\n.ti-pulse:before {\n\tcontent: \"\\e680\";\n}\n.ti-printer:before {\n\tcontent: \"\\e681\";\n}\n.ti-power-off:before {\n\tcontent: \"\\e682\";\n}\n.ti-plug:before {\n\tcontent: \"\\e683\";\n}\n.ti-pie-chart:before {\n\tcontent: \"\\e684\";\n}\n.ti-paragraph:before {\n\tcontent: \"\\e685\";\n}\n.ti-panel:before {\n\tcontent: \"\\e686\";\n}\n.ti-package:before {\n\tcontent: \"\\e687\";\n}\n.ti-music:before {\n\tcontent: \"\\e688\";\n}\n.ti-music-alt:before {\n\tcontent: \"\\e689\";\n}\n.ti-mouse:before {\n\tcontent: \"\\e68a\";\n}\n.ti-mouse-alt:before {\n\tcontent: \"\\e68b\";\n}\n.ti-money:before {\n\tcontent: \"\\e68c\";\n}\n.ti-microphone:before {\n\tcontent: \"\\e68d\";\n}\n.ti-menu:before {\n\tcontent: \"\\e68e\";\n}\n.ti-menu-alt:before {\n\tcontent: \"\\e68f\";\n}\n.ti-map:before {\n\tcontent: \"\\e690\";\n}\n.ti-map-alt:before {\n\tcontent: \"\\e691\";\n}\n.ti-loop:before {\n\tcontent: \"\\e692\";\n}\n.ti-location-pin:before {\n\tcontent: \"\\e693\";\n}\n.ti-list:before {\n\tcontent: \"\\e694\";\n}\n.ti-light-bulb:before {\n\tcontent: \"\\e695\";\n}\n.ti-Italic:before {\n\tcontent: \"\\e696\";\n}\n.ti-info:before {\n\tcontent: \"\\e697\";\n}\n.ti-infinite:before {\n\tcontent: \"\\e698\";\n}\n.ti-id-badge:before {\n\tcontent: \"\\e699\";\n}\n.ti-hummer:before {\n\tcontent: \"\\e69a\";\n}\n.ti-home:before {\n\tcontent: \"\\e69b\";\n}\n.ti-help:before {\n\tcontent: \"\\e69c\";\n}\n.ti-headphone:before {\n\tcontent: \"\\e69d\";\n}\n.ti-harddrives:before {\n\tcontent: \"\\e69e\";\n}\n.ti-harddrive:before {\n\tcontent: \"\\e69f\";\n}\n.ti-gift:before {\n\tcontent: \"\\e6a0\";\n}\n.ti-game:before {\n\tcontent: \"\\e6a1\";\n}\n.ti-filter:before {\n\tcontent: \"\\e6a2\";\n}\n.ti-files:before {\n\tcontent: \"\\e6a3\";\n}\n.ti-file:before {\n\tcontent: \"\\e6a4\";\n}\n.ti-eraser:before {\n\tcontent: \"\\e6a5\";\n}\n.ti-envelope:before {\n\tcontent: \"\\e6a6\";\n}\n.ti-download:before {\n\tcontent: \"\\e6a7\";\n}\n.ti-direction:before {\n\tcontent: \"\\e6a8\";\n}\n.ti-direction-alt:before {\n\tcontent: \"\\e6a9\";\n}\n.ti-dashboard:before {\n\tcontent: \"\\e6aa\";\n}\n.ti-control-stop:before {\n\tcontent: \"\\e6ab\";\n}\n.ti-control-shuffle:before {\n\tcontent: \"\\e6ac\";\n}\n.ti-control-play:before {\n\tcontent: \"\\e6ad\";\n}\n.ti-control-pause:before {\n\tcontent: \"\\e6ae\";\n}\n.ti-control-forward:before {\n\tcontent: \"\\e6af\";\n}\n.ti-control-backward:before {\n\tcontent: \"\\e6b0\";\n}\n.ti-cloud:before {\n\tcontent: \"\\e6b1\";\n}\n.ti-cloud-up:before {\n\tcontent: \"\\e6b2\";\n}\n.ti-cloud-down:before {\n\tcontent: \"\\e6b3\";\n}\n.ti-clipboard:before {\n\tcontent: \"\\e6b4\";\n}\n.ti-car:before {\n\tcontent: \"\\e6b5\";\n}\n.ti-calendar:before {\n\tcontent: \"\\e6b6\";\n}\n.ti-book:before {\n\tcontent: \"\\e6b7\";\n}\n.ti-bell:before {\n\tcontent: \"\\e6b8\";\n}\n.ti-basketball:before {\n\tcontent: \"\\e6b9\";\n}\n.ti-bar-chart:before {\n\tcontent: \"\\e6ba\";\n}\n.ti-bar-chart-alt:before {\n\tcontent: \"\\e6bb\";\n}\n.ti-back-right:before {\n\tcontent: \"\\e6bc\";\n}\n.ti-back-left:before {\n\tcontent: \"\\e6bd\";\n}\n.ti-arrows-corner:before {\n\tcontent: \"\\e6be\";\n}\n.ti-archive:before {\n\tcontent: \"\\e6bf\";\n}\n.ti-anchor:before {\n\tcontent: \"\\e6c0\";\n}\n.ti-align-right:before {\n\tcontent: \"\\e6c1\";\n}\n.ti-align-left:before {\n\tcontent: \"\\e6c2\";\n}\n.ti-align-justify:before {\n\tcontent: \"\\e6c3\";\n}\n.ti-align-center:before {\n\tcontent: \"\\e6c4\";\n}\n.ti-alert:before {\n\tcontent: \"\\e6c5\";\n}\n.ti-alarm-clock:before {\n\tcontent: \"\\e6c6\";\n}\n.ti-agenda:before {\n\tcontent: \"\\e6c7\";\n}\n.ti-write:before {\n\tcontent: \"\\e6c8\";\n}\n.ti-window:before {\n\tcontent: \"\\e6c9\";\n}\n.ti-widgetized:before {\n\tcontent: \"\\e6ca\";\n}\n.ti-widget:before {\n\tcontent: \"\\e6cb\";\n}\n.ti-widget-alt:before {\n\tcontent: \"\\e6cc\";\n}\n.ti-wallet:before {\n\tcontent: \"\\e6cd\";\n}\n.ti-video-clapper:before {\n\tcontent: \"\\e6ce\";\n}\n.ti-video-camera:before {\n\tcontent: \"\\e6cf\";\n}\n.ti-vector:before {\n\tcontent: \"\\e6d0\";\n}\n.ti-themify-logo:before {\n\tcontent: \"\\e6d1\";\n}\n.ti-themify-favicon:before {\n\tcontent: \"\\e6d2\";\n}\n.ti-themify-favicon-alt:before {\n\tcontent: \"\\e6d3\";\n}\n.ti-support:before {\n\tcontent: \"\\e6d4\";\n}\n.ti-stamp:before {\n\tcontent: \"\\e6d5\";\n}\n.ti-split-v-alt:before {\n\tcontent: \"\\e6d6\";\n}\n.ti-slice:before {\n\tcontent: \"\\e6d7\";\n}\n.ti-shortcode:before {\n\tcontent: \"\\e6d8\";\n}\n.ti-shift-right-alt:before {\n\tcontent: \"\\e6d9\";\n}\n.ti-shift-left-alt:before {\n\tcontent: \"\\e6da\";\n}\n.ti-ruler-alt-2:before {\n\tcontent: \"\\e6db\";\n}\n.ti-receipt:before {\n\tcontent: \"\\e6dc\";\n}\n.ti-pin2:before {\n\tcontent: \"\\e6dd\";\n}\n.ti-pin-alt:before {\n\tcontent: \"\\e6de\";\n}\n.ti-pencil-alt2:before {\n\tcontent: \"\\e6df\";\n}\n.ti-palette:before {\n\tcontent: \"\\e6e0\";\n}\n.ti-more:before {\n\tcontent: \"\\e6e1\";\n}\n.ti-more-alt:before {\n\tcontent: \"\\e6e2\";\n}\n.ti-microphone-alt:before {\n\tcontent: \"\\e6e3\";\n}\n.ti-magnet:before {\n\tcontent: \"\\e6e4\";\n}\n.ti-line-double:before {\n\tcontent: \"\\e6e5\";\n}\n.ti-line-dotted:before {\n\tcontent: \"\\e6e6\";\n}\n.ti-line-dashed:before {\n\tcontent: \"\\e6e7\";\n}\n.ti-layout-width-full:before {\n\tcontent: \"\\e6e8\";\n}\n.ti-layout-width-default:before {\n\tcontent: \"\\e6e9\";\n}\n.ti-layout-width-default-alt:before {\n\tcontent: \"\\e6ea\";\n}\n.ti-layout-tab:before {\n\tcontent: \"\\e6eb\";\n}\n.ti-layout-tab-window:before {\n\tcontent: \"\\e6ec\";\n}\n.ti-layout-tab-v:before {\n\tcontent: \"\\e6ed\";\n}\n.ti-layout-tab-min:before {\n\tcontent: \"\\e6ee\";\n}\n.ti-layout-slider:before {\n\tcontent: \"\\e6ef\";\n}\n.ti-layout-slider-alt:before {\n\tcontent: \"\\e6f0\";\n}\n.ti-layout-sidebar-right:before {\n\tcontent: \"\\e6f1\";\n}\n.ti-layout-sidebar-none:before {\n\tcontent: \"\\e6f2\";\n}\n.ti-layout-sidebar-left:before {\n\tcontent: \"\\e6f3\";\n}\n.ti-layout-placeholder:before {\n\tcontent: \"\\e6f4\";\n}\n.ti-layout-menu:before {\n\tcontent: \"\\e6f5\";\n}\n.ti-layout-menu-v:before {\n\tcontent: \"\\e6f6\";\n}\n.ti-layout-menu-separated:before {\n\tcontent: \"\\e6f7\";\n}\n.ti-layout-menu-full:before {\n\tcontent: \"\\e6f8\";\n}\n.ti-layout-media-right-alt:before {\n\tcontent: \"\\e6f9\";\n}\n.ti-layout-media-right:before {\n\tcontent: \"\\e6fa\";\n}\n.ti-layout-media-overlay:before {\n\tcontent: \"\\e6fb\";\n}\n.ti-layout-media-overlay-alt:before {\n\tcontent: \"\\e6fc\";\n}\n.ti-layout-media-overlay-alt-2:before {\n\tcontent: \"\\e6fd\";\n}\n.ti-layout-media-left-alt:before {\n\tcontent: \"\\e6fe\";\n}\n.ti-layout-media-left:before {\n\tcontent: \"\\e6ff\";\n}\n.ti-layout-media-center-alt:before {\n\tcontent: \"\\e700\";\n}\n.ti-layout-media-center:before {\n\tcontent: \"\\e701\";\n}\n.ti-layout-list-thumb:before {\n\tcontent: \"\\e702\";\n}\n.ti-layout-list-thumb-alt:before {\n\tcontent: \"\\e703\";\n}\n.ti-layout-list-post:before {\n\tcontent: \"\\e704\";\n}\n.ti-layout-list-large-image:before {\n\tcontent: \"\\e705\";\n}\n.ti-layout-line-solid:before {\n\tcontent: \"\\e706\";\n}\n.ti-layout-grid4:before {\n\tcontent: \"\\e707\";\n}\n.ti-layout-grid3:before {\n\tcontent: \"\\e708\";\n}\n.ti-layout-grid2:before {\n\tcontent: \"\\e709\";\n}\n.ti-layout-grid2-thumb:before {\n\tcontent: \"\\e70a\";\n}\n.ti-layout-cta-right:before {\n\tcontent: \"\\e70b\";\n}\n.ti-layout-cta-left:before {\n\tcontent: \"\\e70c\";\n}\n.ti-layout-cta-center:before {\n\tcontent: \"\\e70d\";\n}\n.ti-layout-cta-btn-right:before {\n\tcontent: \"\\e70e\";\n}\n.ti-layout-cta-btn-left:before {\n\tcontent: \"\\e70f\";\n}\n.ti-layout-column4:before {\n\tcontent: \"\\e710\";\n}\n.ti-layout-column3:before {\n\tcontent: \"\\e711\";\n}\n.ti-layout-column2:before {\n\tcontent: \"\\e712\";\n}\n.ti-layout-accordion-separated:before {\n\tcontent: \"\\e713\";\n}\n.ti-layout-accordion-merged:before {\n\tcontent: \"\\e714\";\n}\n.ti-layout-accordion-list:before {\n\tcontent: \"\\e715\";\n}\n.ti-ink-pen:before {\n\tcontent: \"\\e716\";\n}\n.ti-info-alt:before {\n\tcontent: \"\\e717\";\n}\n.ti-help-alt:before {\n\tcontent: \"\\e718\";\n}\n.ti-headphone-alt:before {\n\tcontent: \"\\e719\";\n}\n.ti-hand-point-up:before {\n\tcontent: \"\\e71a\";\n}\n.ti-hand-point-right:before {\n\tcontent: \"\\e71b\";\n}\n.ti-hand-point-left:before {\n\tcontent: \"\\e71c\";\n}\n.ti-hand-point-down:before {\n\tcontent: \"\\e71d\";\n}\n.ti-gallery:before {\n\tcontent: \"\\e71e\";\n}\n.ti-face-smile:before {\n\tcontent: \"\\e71f\";\n}\n.ti-face-sad:before {\n\tcontent: \"\\e720\";\n}\n.ti-credit-card:before {\n\tcontent: \"\\e721\";\n}\n.ti-control-skip-forward:before {\n\tcontent: \"\\e722\";\n}\n.ti-control-skip-backward:before {\n\tcontent: \"\\e723\";\n}\n.ti-control-record:before {\n\tcontent: \"\\e724\";\n}\n.ti-control-eject:before {\n\tcontent: \"\\e725\";\n}\n.ti-comments-smiley:before {\n\tcontent: \"\\e726\";\n}\n.ti-brush-alt:before {\n\tcontent: \"\\e727\";\n}\n.ti-youtube:before {\n\tcontent: \"\\e728\";\n}\n.ti-vimeo:before {\n\tcontent: \"\\e729\";\n}\n.ti-twitter:before {\n\tcontent: \"\\e72a\";\n}\n.ti-time:before {\n\tcontent: \"\\e72b\";\n}\n.ti-tumblr:before {\n\tcontent: \"\\e72c\";\n}\n.ti-skype:before {\n\tcontent: \"\\e72d\";\n}\n.ti-share:before {\n\tcontent: \"\\e72e\";\n}\n.ti-share-alt:before {\n\tcontent: \"\\e72f\";\n}\n.ti-rocket:before {\n\tcontent: \"\\e730\";\n}\n.ti-pinterest:before {\n\tcontent: \"\\e731\";\n}\n.ti-new-window:before {\n\tcontent: \"\\e732\";\n}\n.ti-microsoft:before {\n\tcontent: \"\\e733\";\n}\n.ti-list-ol:before {\n\tcontent: \"\\e734\";\n}\n.ti-linkedin:before {\n\tcontent: \"\\e735\";\n}\n.ti-layout-sidebar-2:before {\n\tcontent: \"\\e736\";\n}\n.ti-layout-grid4-alt:before {\n\tcontent: \"\\e737\";\n}\n.ti-layout-grid3-alt:before {\n\tcontent: \"\\e738\";\n}\n.ti-layout-grid2-alt:before {\n\tcontent: \"\\e739\";\n}\n.ti-layout-column4-alt:before {\n\tcontent: \"\\e73a\";\n}\n.ti-layout-column3-alt:before {\n\tcontent: \"\\e73b\";\n}\n.ti-layout-column2-alt:before {\n\tcontent: \"\\e73c\";\n}\n.ti-instagram:before {\n\tcontent: \"\\e73d\";\n}\n.ti-google:before {\n\tcontent: \"\\e73e\";\n}\n.ti-github:before {\n\tcontent: \"\\e73f\";\n}\n.ti-flickr:before {\n\tcontent: \"\\e740\";\n}\n.ti-facebook:before {\n\tcontent: \"\\e741\";\n}\n.ti-dropbox:before {\n\tcontent: \"\\e742\";\n}\n.ti-dribbble:before {\n\tcontent: \"\\e743\";\n}\n.ti-apple:before {\n\tcontent: \"\\e744\";\n}\n.ti-android:before {\n\tcontent: \"\\e745\";\n}\n.ti-save:before {\n\tcontent: \"\\e746\";\n}\n.ti-save-alt:before {\n\tcontent: \"\\e747\";\n}\n.ti-yahoo:before {\n\tcontent: \"\\e748\";\n}\n.ti-wordpress:before {\n\tcontent: \"\\e749\";\n}\n.ti-vimeo-alt:before {\n\tcontent: \"\\e74a\";\n}\n.ti-twitter-alt:before {\n\tcontent: \"\\e74b\";\n}\n.ti-tumblr-alt:before {\n\tcontent: \"\\e74c\";\n}\n.ti-trello:before {\n\tcontent: \"\\e74d\";\n}\n.ti-stack-overflow:before {\n\tcontent: \"\\e74e\";\n}\n.ti-soundcloud:before {\n\tcontent: \"\\e74f\";\n}\n.ti-sharethis:before {\n\tcontent: \"\\e750\";\n}\n.ti-sharethis-alt:before {\n\tcontent: \"\\e751\";\n}\n.ti-reddit:before {\n\tcontent: \"\\e752\";\n}\n.ti-pinterest-alt:before {\n\tcontent: \"\\e753\";\n}\n.ti-microsoft-alt:before {\n\tcontent: \"\\e754\";\n}\n.ti-linux:before {\n\tcontent: \"\\e755\";\n}\n.ti-jsfiddle:before {\n\tcontent: \"\\e756\";\n}\n.ti-joomla:before {\n\tcontent: \"\\e757\";\n}\n.ti-html5:before {\n\tcontent: \"\\e758\";\n}\n.ti-flickr-alt:before {\n\tcontent: \"\\e759\";\n}\n.ti-email:before {\n\tcontent: \"\\e75a\";\n}\n.ti-drupal:before {\n\tcontent: \"\\e75b\";\n}\n.ti-dropbox-alt:before {\n\tcontent: \"\\e75c\";\n}\n.ti-css3:before {\n\tcontent: \"\\e75d\";\n}\n.ti-rss:before {\n\tcontent: \"\\e75e\";\n}\n.ti-rss-alt:before {\n\tcontent: \"\\e75f\";\n}\n"
  },
  {
    "path": "static/js/DataTables/AutoFill-2.3.3/css/autoFill.bootstrap.css",
    "content": "div.dt-autofill-handle {\n  position: absolute;\n  height: 8px;\n  width: 8px;\n  z-index: 102;\n  box-sizing: border-box;\n  background: #337ab7;\n  cursor: pointer;\n}\n\ndiv.dtk-focus-alt div.dt-autofill-handle {\n  background: #ff8b33;\n}\n\ndiv.dt-autofill-select {\n  position: absolute;\n  z-index: 1001;\n  background-color: #337ab7;\n  background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.5) 5px, rgba(255, 255, 255, 0.5) 10px);\n}\ndiv.dt-autofill-select.top, div.dt-autofill-select.bottom {\n  height: 3px;\n  margin-top: -1px;\n}\ndiv.dt-autofill-select.left, div.dt-autofill-select.right {\n  width: 3px;\n  margin-left: -1px;\n}\n\ndiv.dt-autofill-list {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  width: 500px;\n  margin-left: -250px;\n  background-color: white;\n  border-radius: 6px;\n  box-shadow: 0 0 5px #555;\n  border: 2px solid #444;\n  z-index: 11;\n  box-sizing: border-box;\n  padding: 1.5em 2em;\n}\ndiv.dt-autofill-list ul {\n  display: table;\n  margin: 0;\n  padding: 0;\n  list-style: none;\n  width: 100%;\n}\ndiv.dt-autofill-list ul li {\n  display: table-row;\n}\ndiv.dt-autofill-list ul li:last-child div.dt-autofill-question, div.dt-autofill-list ul li:last-child div.dt-autofill-button {\n  border-bottom: none;\n}\ndiv.dt-autofill-list ul li:hover {\n  background-color: #f6f6f6;\n}\ndiv.dt-autofill-list div.dt-autofill-question {\n  display: table-cell;\n  padding: 0.5em 0;\n  border-bottom: 1px solid #ccc;\n}\ndiv.dt-autofill-list div.dt-autofill-question input[type=number] {\n  padding: 6px;\n  width: 30px;\n  margin: -2px 0;\n}\ndiv.dt-autofill-list div.dt-autofill-button {\n  display: table-cell;\n  padding: 0.5em 0;\n  border-bottom: 1px solid #ccc;\n}\n\ndiv.dt-autofill-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: rgba(0, 0, 0, 0.7);\n  background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  z-index: 10;\n}\n\ndiv.dt-autofill-list div.dt-autofill-question input[type=number] {\n  padding: 6px;\n  width: 60px;\n  margin: -2px 0;\n}\n"
  },
  {
    "path": "static/js/DataTables/AutoFill-2.3.3/css/autoFill.bootstrap4.css",
    "content": "div.dt-autofill-handle {\n  position: absolute;\n  height: 8px;\n  width: 8px;\n  z-index: 102;\n  box-sizing: border-box;\n  background: #0275d8;\n  cursor: pointer;\n}\n\ndiv.dtk-focus-alt div.dt-autofill-handle {\n  background: #ff8b33;\n}\n\ndiv.dt-autofill-select {\n  position: absolute;\n  z-index: 1001;\n  background-color: #0275d8;\n  background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.5) 5px, rgba(255, 255, 255, 0.5) 10px);\n}\ndiv.dt-autofill-select.top, div.dt-autofill-select.bottom {\n  height: 3px;\n  margin-top: -1px;\n}\ndiv.dt-autofill-select.left, div.dt-autofill-select.right {\n  width: 3px;\n  margin-left: -1px;\n}\n\ndiv.dt-autofill-list {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  width: 500px;\n  margin-left: -250px;\n  background-color: white;\n  border-radius: 6px;\n  box-shadow: 0 0 5px #555;\n  border: 2px solid #444;\n  z-index: 11;\n  box-sizing: border-box;\n  padding: 1.5em 2em;\n}\ndiv.dt-autofill-list ul {\n  display: table;\n  margin: 0;\n  padding: 0;\n  list-style: none;\n  width: 100%;\n}\ndiv.dt-autofill-list ul li {\n  display: table-row;\n}\ndiv.dt-autofill-list ul li:last-child div.dt-autofill-question, div.dt-autofill-list ul li:last-child div.dt-autofill-button {\n  border-bottom: none;\n}\ndiv.dt-autofill-list ul li:hover {\n  background-color: #f6f6f6;\n}\ndiv.dt-autofill-list div.dt-autofill-question {\n  display: table-cell;\n  padding: 0.5em 0;\n  border-bottom: 1px solid #ccc;\n}\ndiv.dt-autofill-list div.dt-autofill-question input[type=number] {\n  padding: 6px;\n  width: 30px;\n  margin: -2px 0;\n}\ndiv.dt-autofill-list div.dt-autofill-button {\n  display: table-cell;\n  padding: 0.5em 0;\n  border-bottom: 1px solid #ccc;\n}\n\ndiv.dt-autofill-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: rgba(0, 0, 0, 0.7);\n  background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  z-index: 10;\n}\n\ndiv.dt-autofill-list div.dt-autofill-question input[type=number] {\n  padding: 6px;\n  width: 60px;\n  margin: -2px 0;\n}\n"
  },
  {
    "path": "static/js/DataTables/AutoFill-2.3.3/css/autoFill.dataTables.css",
    "content": "div.dt-autofill-handle {\n  position: absolute;\n  height: 8px;\n  width: 8px;\n  z-index: 102;\n  box-sizing: border-box;\n  background: #3366ff;\n  cursor: pointer;\n}\n\ndiv.dtk-focus-alt div.dt-autofill-handle {\n  background: #ff8b33;\n}\n\ndiv.dt-autofill-select {\n  position: absolute;\n  z-index: 1001;\n  background-color: #4989de;\n  background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.5) 5px, rgba(255, 255, 255, 0.5) 10px);\n}\ndiv.dt-autofill-select.top, div.dt-autofill-select.bottom {\n  height: 3px;\n  margin-top: -1px;\n}\ndiv.dt-autofill-select.left, div.dt-autofill-select.right {\n  width: 3px;\n  margin-left: -1px;\n}\n\ndiv.dt-autofill-list {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  width: 500px;\n  margin-left: -250px;\n  background-color: white;\n  border-radius: 6px;\n  box-shadow: 0 0 5px #555;\n  border: 2px solid #444;\n  z-index: 11;\n  box-sizing: border-box;\n  padding: 1.5em 2em;\n}\ndiv.dt-autofill-list ul {\n  display: table;\n  margin: 0;\n  padding: 0;\n  list-style: none;\n  width: 100%;\n}\ndiv.dt-autofill-list ul li {\n  display: table-row;\n}\ndiv.dt-autofill-list ul li:last-child div.dt-autofill-question, div.dt-autofill-list ul li:last-child div.dt-autofill-button {\n  border-bottom: none;\n}\ndiv.dt-autofill-list ul li:hover {\n  background-color: #f6f6f6;\n}\ndiv.dt-autofill-list div.dt-autofill-question {\n  display: table-cell;\n  padding: 0.5em 0;\n  border-bottom: 1px solid #ccc;\n}\ndiv.dt-autofill-list div.dt-autofill-question input[type=number] {\n  padding: 6px;\n  width: 30px;\n  margin: -2px 0;\n}\ndiv.dt-autofill-list div.dt-autofill-button {\n  display: table-cell;\n  padding: 0.5em 0;\n  border-bottom: 1px solid #ccc;\n}\ndiv.dt-autofill-list div.dt-autofill-button button {\n  color: white;\n  margin: 0;\n  padding: 6px 12px;\n  text-align: center;\n  border: 1px solid #2e6da4;\n  background-color: #337ab7;\n  border-radius: 4px;\n  cursor: pointer;\n  vertical-align: middle;\n}\n\ndiv.dt-autofill-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: rgba(0, 0, 0, 0.7);\n  background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  z-index: 10;\n}\n"
  },
  {
    "path": "static/js/DataTables/AutoFill-2.3.3/css/autoFill.foundation.css",
    "content": "div.dt-autofill-handle {\n  position: absolute;\n  height: 8px;\n  width: 8px;\n  z-index: 102;\n  box-sizing: border-box;\n  background: #008CBA;\n  cursor: pointer;\n}\n\ndiv.dtk-focus-alt div.dt-autofill-handle {\n  background: #ff8b33;\n}\n\ndiv.dt-autofill-select {\n  position: absolute;\n  z-index: 1001;\n  background-color: #008CBA;\n  background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.5) 5px, rgba(255, 255, 255, 0.5) 10px);\n}\ndiv.dt-autofill-select.top, div.dt-autofill-select.bottom {\n  height: 3px;\n  margin-top: -1px;\n}\ndiv.dt-autofill-select.left, div.dt-autofill-select.right {\n  width: 3px;\n  margin-left: -1px;\n}\n\ndiv.dt-autofill-list {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  width: 500px;\n  margin-left: -250px;\n  background-color: white;\n  border-radius: 6px;\n  box-shadow: 0 0 5px #555;\n  border: 2px solid #444;\n  z-index: 11;\n  box-sizing: border-box;\n  padding: 1.5em 2em;\n}\ndiv.dt-autofill-list ul {\n  display: table;\n  margin: 0;\n  padding: 0;\n  list-style: none;\n  width: 100%;\n}\ndiv.dt-autofill-list ul li {\n  display: table-row;\n}\ndiv.dt-autofill-list ul li:last-child div.dt-autofill-question, div.dt-autofill-list ul li:last-child div.dt-autofill-button {\n  border-bottom: none;\n}\ndiv.dt-autofill-list ul li:hover {\n  background-color: #f6f6f6;\n}\ndiv.dt-autofill-list div.dt-autofill-question {\n  display: table-cell;\n  padding: 0.5em 0;\n  border-bottom: 1px solid #ccc;\n}\ndiv.dt-autofill-list div.dt-autofill-question input[type=number] {\n  padding: 6px;\n  width: 30px;\n  margin: -2px 0;\n}\ndiv.dt-autofill-list div.dt-autofill-button {\n  display: table-cell;\n  padding: 0.5em 0;\n  border-bottom: 1px solid #ccc;\n}\n\ndiv.dt-autofill-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: rgba(0, 0, 0, 0.7);\n  background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  z-index: 10;\n}\n\ndiv.dt-autofill-list button {\n  margin: 0;\n}\n"
  },
  {
    "path": "static/js/DataTables/AutoFill-2.3.3/css/autoFill.jqueryui.css",
    "content": "div.dt-autofill-handle {\n  position: absolute;\n  height: 8px;\n  width: 8px;\n  z-index: 102;\n  box-sizing: border-box;\n  background: #3366ff;\n  cursor: pointer;\n}\n\ndiv.dtk-focus-alt div.dt-autofill-handle {\n  background: #ff8b33;\n}\n\ndiv.dt-autofill-select {\n  position: absolute;\n  z-index: 1001;\n  background-color: #4989de;\n  background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.5) 5px, rgba(255, 255, 255, 0.5) 10px);\n}\ndiv.dt-autofill-select.top, div.dt-autofill-select.bottom {\n  height: 3px;\n  margin-top: -1px;\n}\ndiv.dt-autofill-select.left, div.dt-autofill-select.right {\n  width: 3px;\n  margin-left: -1px;\n}\n\ndiv.dt-autofill-list {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  width: 500px;\n  margin-left: -250px;\n  background-color: white;\n  border-radius: 6px;\n  box-shadow: 0 0 5px #555;\n  border: 2px solid #444;\n  z-index: 11;\n  box-sizing: border-box;\n  padding: 1.5em 2em;\n}\ndiv.dt-autofill-list ul {\n  display: table;\n  margin: 0;\n  padding: 0;\n  list-style: none;\n  width: 100%;\n}\ndiv.dt-autofill-list ul li {\n  display: table-row;\n}\ndiv.dt-autofill-list ul li:last-child div.dt-autofill-question, div.dt-autofill-list ul li:last-child div.dt-autofill-button {\n  border-bottom: none;\n}\ndiv.dt-autofill-list ul li:hover {\n  background-color: #f6f6f6;\n}\ndiv.dt-autofill-list div.dt-autofill-question {\n  display: table-cell;\n  padding: 0.5em 0;\n  border-bottom: 1px solid #ccc;\n}\ndiv.dt-autofill-list div.dt-autofill-question input[type=number] {\n  padding: 6px;\n  width: 30px;\n  margin: -2px 0;\n}\ndiv.dt-autofill-list div.dt-autofill-button {\n  display: table-cell;\n  padding: 0.5em 0;\n  border-bottom: 1px solid #ccc;\n}\n\ndiv.dt-autofill-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: rgba(0, 0, 0, 0.7);\n  background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  z-index: 10;\n}\n\ndiv.dt-autofill-list button {\n  padding: 0.35em 1em;\n}\n"
  },
  {
    "path": "static/js/DataTables/AutoFill-2.3.3/css/autoFill.semanticui.css",
    "content": "div.dt-autofill-handle {\n  position: absolute;\n  height: 8px;\n  width: 8px;\n  z-index: 102;\n  box-sizing: border-box;\n  background: #888;\n  cursor: pointer;\n}\n\ndiv.dtk-focus-alt div.dt-autofill-handle {\n  background: #ff8b33;\n}\n\ndiv.dt-autofill-select {\n  position: absolute;\n  z-index: 1001;\n  background-color: #888;\n  background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255, 255, 255, 0.5) 5px, rgba(255, 255, 255, 0.5) 10px);\n}\ndiv.dt-autofill-select.top, div.dt-autofill-select.bottom {\n  height: 3px;\n  margin-top: -1px;\n}\ndiv.dt-autofill-select.left, div.dt-autofill-select.right {\n  width: 3px;\n  margin-left: -1px;\n}\n\ndiv.dt-autofill-list {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  width: 500px;\n  margin-left: -250px;\n  background-color: white;\n  border-radius: 6px;\n  box-shadow: 0 0 5px #555;\n  border: 2px solid #444;\n  z-index: 11;\n  box-sizing: border-box;\n  padding: 1.5em 2em;\n}\ndiv.dt-autofill-list ul {\n  display: table;\n  margin: 0;\n  padding: 0;\n  list-style: none;\n  width: 100%;\n}\ndiv.dt-autofill-list ul li {\n  display: table-row;\n}\ndiv.dt-autofill-list ul li:last-child div.dt-autofill-question, div.dt-autofill-list ul li:last-child div.dt-autofill-button {\n  border-bottom: none;\n}\ndiv.dt-autofill-list ul li:hover {\n  background-color: #f6f6f6;\n}\ndiv.dt-autofill-list div.dt-autofill-question {\n  display: table-cell;\n  padding: 0.5em 0;\n  border-bottom: 1px solid #ccc;\n}\ndiv.dt-autofill-list div.dt-autofill-question input[type=number] {\n  padding: 6px;\n  width: 30px;\n  margin: -2px 0;\n}\ndiv.dt-autofill-list div.dt-autofill-button {\n  display: table-cell;\n  padding: 0.5em 0;\n  border-bottom: 1px solid #ccc;\n}\n\ndiv.dt-autofill-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: rgba(0, 0, 0, 0.7);\n  background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  z-index: 10;\n}\n"
  },
  {
    "path": "static/js/DataTables/AutoFill-2.3.3/js/autoFill.bootstrap.js",
    "content": "/*! Bootstrap integration for DataTables' AutoFill\n * ©2015 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs', 'datatables.net-autofill'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.AutoFill ) {\n\t\t\t\trequire('datatables.net-autofill')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nDataTable.AutoFill.classes.btn = 'btn btn-primary';\n\n\nreturn DataTable;\n}));"
  },
  {
    "path": "static/js/DataTables/AutoFill-2.3.3/js/autoFill.bootstrap4.js",
    "content": "/*! Bootstrap integration for DataTables' AutoFill\n * ©2015 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs4', 'datatables.net-autofill'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs4')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.AutoFill ) {\n\t\t\t\trequire('datatables.net-autofill')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nDataTable.AutoFill.classes.btn = 'btn btn-primary';\n\n\nreturn DataTable;\n}));"
  },
  {
    "path": "static/js/DataTables/AutoFill-2.3.3/js/autoFill.foundation.js",
    "content": "/*! Foundation integration for DataTables' AutoFill\n * ©2015 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-zf', 'datatables.net-autofill'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-zf')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.AutoFill ) {\n\t\t\t\trequire('datatables.net-autofill')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nDataTable.AutoFill.classes.btn = 'button tiny';\n\n\nreturn DataTable;\n}));"
  },
  {
    "path": "static/js/DataTables/AutoFill-2.3.3/js/autoFill.jqueryui.js",
    "content": "/*! jQuery UI integration for DataTables' AutoFill\n * ©2015 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-jqui', 'datatables.net-autofill'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-jqui')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.AutoFill ) {\n\t\t\t\trequire('datatables.net-autofill')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nDataTable.AutoFill.classes.btn = 'ui-button ui-state-default ui-corner-all';\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "static/js/DataTables/AutoFill-2.3.3/js/autoFill.semanticui.js",
    "content": "/*! Bootstrap integration for DataTables' AutoFill\n * ©2015 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-se', 'datatables.net-autofill'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-se')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.AutoFill ) {\n\t\t\t\trequire('datatables.net-autofill')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nDataTable.AutoFill.classes.btn = 'ui button';\n\n\nreturn DataTable;\n}));"
  },
  {
    "path": "static/js/DataTables/AutoFill-2.3.3/js/dataTables.autoFill.js",
    "content": "/*! AutoFill 2.3.3\n * ©2008-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     AutoFill\n * @description Add Excel like click and drag auto-fill options to DataTables\n * @version     2.3.3\n * @file        dataTables.autoFill.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2010-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar _instance = 0;\n\n/** \n * AutoFill provides Excel like auto-fill features for a DataTable\n *\n * @class AutoFill\n * @constructor\n * @param {object} oTD DataTables settings object\n * @param {object} oConfig Configuration object for AutoFill\n */\nvar AutoFill = function( dt, opts )\n{\n\tif ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {\n\t\tthrow( \"Warning: AutoFill requires DataTables 1.10.8 or greater\");\n\t}\n\n\t// User and defaults configuration object\n\tthis.c = $.extend( true, {},\n\t\tDataTable.defaults.autoFill,\n\t\tAutoFill.defaults,\n\t\topts\n\t);\n\n\t/**\n\t * @namespace Settings object which contains customisable information for AutoFill instance\n\t */\n\tthis.s = {\n\t\t/** @type {DataTable.Api} DataTables' API instance */\n\t\tdt: new DataTable.Api( dt ),\n\n\t\t/** @type {String} Unique namespace for events attached to the document */\n\t\tnamespace: '.autoFill'+(_instance++),\n\n\t\t/** @type {Object} Cached dimension information for use in the mouse move event handler */\n\t\tscroll: {},\n\n\t\t/** @type {integer} Interval object used for smooth scrolling */\n\t\tscrollInterval: null,\n\n\t\thandle: {\n\t\t\theight: 0,\n\t\t\twidth: 0\n\t\t},\n\n\t\t/**\n\t\t * Enabled setting\n\t\t * @type {Boolean}\n\t\t */\n\t\tenabled: false\n\t};\n\n\n\t/**\n\t * @namespace Common and useful DOM elements for the class instance\n\t */\n\tthis.dom = {\n\t\t/** @type {jQuery} AutoFill handle */\n\t\thandle: $('<div class=\"dt-autofill-handle\"/>'),\n\n\t\t/**\n\t\t * @type {Object} Selected cells outline - Need to use 4 elements,\n\t\t *   otherwise the mouse over if you back into the selected rectangle\n\t\t *   will be over that element, rather than the cells!\n\t\t */\n\t\tselect: {\n\t\t\ttop:    $('<div class=\"dt-autofill-select top\"/>'),\n\t\t\tright:  $('<div class=\"dt-autofill-select right\"/>'),\n\t\t\tbottom: $('<div class=\"dt-autofill-select bottom\"/>'),\n\t\t\tleft:   $('<div class=\"dt-autofill-select left\"/>')\n\t\t},\n\n\t\t/** @type {jQuery} Fill type chooser background */\n\t\tbackground: $('<div class=\"dt-autofill-background\"/>'),\n\n\t\t/** @type {jQuery} Fill type chooser */\n\t\tlist: $('<div class=\"dt-autofill-list\">'+this.s.dt.i18n('autoFill.info', '')+'<ul/></div>'),\n\n\t\t/** @type {jQuery} DataTables scrolling container */\n\t\tdtScroll: null,\n\n\t\t/** @type {jQuery} Offset parent element */\n\t\toffsetParent: null\n\t};\n\n\n\t/* Constructor logic */\n\tthis._constructor();\n};\n\n\n\n$.extend( AutoFill.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Public methods (exposed via the DataTables API below)\n\t */\n\tenabled: function ()\n\t{\n\t\treturn this.s.enabled;\n\t},\n\n\n\tenable: function ( flag )\n\t{\n\t\tvar that = this;\n\n\t\tif ( flag === false ) {\n\t\t\treturn this.disable();\n\t\t}\n\n\t\tthis.s.enabled = true;\n\n\t\tthis._focusListener();\n\n\t\tthis.dom.handle.on( 'mousedown', function (e) {\n\t\t\tthat._mousedown( e );\n\t\t\treturn false;\n\t\t} );\n\n\t\treturn this;\n\t},\n\n\tdisable: function ()\n\t{\n\t\tthis.s.enabled = false;\n\n\t\tthis._focusListenerRemove();\n\n\t\treturn this;\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\n\t/**\n\t * Initialise the RowReorder instance\n\t *\n\t * @private\n\t */\n\t_constructor: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar dtScroll = $('div.dataTables_scrollBody', this.s.dt.table().container());\n\n\t\t// Make the instance accessible to the API\n\t\tdt.settings()[0].autoFill = this;\n\n\t\tif ( dtScroll.length ) {\n\t\t\tthis.dom.dtScroll = dtScroll;\n\n\t\t\t// Need to scroll container to be the offset parent\n\t\t\tif ( dtScroll.css('position') === 'static' ) {\n\t\t\t\tdtScroll.css( 'position', 'relative' );\n\t\t\t}\n\t\t}\n\n\t\tif ( this.c.enable !== false ) {\n\t\t\tthis.enable();\n\t\t}\n\n\t\tdt.on( 'destroy.autoFill', function () {\n\t\t\tthat._focusListenerRemove();\n\t\t} );\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\n\t/**\n\t * Display the AutoFill drag handle by appending it to a table cell. This\n\t * is the opposite of the _detach method.\n\t *\n\t * @param  {node} node TD/TH cell to insert the handle into\n\t * @private\n\t */\n\t_attach: function ( node )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar idx = dt.cell( node ).index();\n\t\tvar handle = this.dom.handle;\n\t\tvar handleDim = this.s.handle;\n\n\t\tif ( ! idx || dt.columns( this.c.columns ).indexes().indexOf( idx.column ) === -1 ) {\n\t\t\tthis._detach();\n\t\t\treturn;\n\t\t}\n\n\t\tif ( ! this.dom.offsetParent ) {\n\t\t\t// We attach to the table's offset parent\n\t\t\tthis.dom.offsetParent = $( dt.table().node() ).offsetParent();\n\t\t}\n\n\t\tif ( ! handleDim.height || ! handleDim.width ) {\n\t\t\t// Append to document so we can get its size. Not expecting it to\n\t\t\t// change during the life time of the page\n\t\t\thandle.appendTo( 'body' );\n\t\t\thandleDim.height = handle.outerHeight();\n\t\t\thandleDim.width = handle.outerWidth();\n\t\t}\n\n\t\t// Might need to go through multiple offset parents\n\t\tvar offset = this._getPosition( node, this.dom.offsetParent );\n\n\t\tthis.dom.attachedTo = node;\n\t\thandle\n\t\t\t.css( {\n\t\t\t\ttop: offset.top + node.offsetHeight - handleDim.height,\n\t\t\t\tleft: offset.left + node.offsetWidth - handleDim.width\n\t\t\t} )\n\t\t\t.appendTo( this.dom.offsetParent );\n\t},\n\n\n\t/**\n\t * Determine can the fill type should be. This can be automatic, or ask the\n\t * end user.\n\t *\n\t * @param {array} cells Information about the selected cells from the key\n\t *     up function\n\t * @private\n\t */\n\t_actionSelector: function ( cells )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar actions = AutoFill.actions;\n\t\tvar available = [];\n\n\t\t// \"Ask\" each plug-in if it wants to handle this data\n\t\t$.each( actions, function ( key, action ) {\n\t\t\tif ( action.available( dt, cells ) ) {\n\t\t\t\tavailable.push( key );\n\t\t\t}\n\t\t} );\n\n\t\tif ( available.length === 1 && this.c.alwaysAsk === false ) {\n\t\t\t// Only one action available - enact it immediately\n\t\t\tvar result = actions[ available[0] ].execute( dt, cells );\n\t\t\tthis._update( result, cells );\n\t\t}\n\t\telse {\n\t\t\t// Multiple actions available - ask the end user what they want to do\n\t\t\tvar list = this.dom.list.children('ul').empty();\n\n\t\t\t// Add a cancel option\n\t\t\tavailable.push( 'cancel' );\n\n\t\t\t$.each( available, function ( i, name ) {\n\t\t\t\tlist.append( $('<li/>')\n\t\t\t\t\t.append(\n\t\t\t\t\t\t'<div class=\"dt-autofill-question\">'+\n\t\t\t\t\t\t\tactions[ name ].option( dt, cells )+\n\t\t\t\t\t\t'<div>'\n\t\t\t\t\t)\n\t\t\t\t\t.append( $('<div class=\"dt-autofill-button\">' )\n\t\t\t\t\t\t.append( $('<button class=\"'+AutoFill.classes.btn+'\">'+dt.i18n('autoFill.button', '&gt;')+'</button>')\n\t\t\t\t\t\t\t.on( 'click', function () {\n\t\t\t\t\t\t\t\tvar result = actions[ name ].execute(\n\t\t\t\t\t\t\t\t\tdt, cells, $(this).closest('li')\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tthat._update( result, cells );\n\n\t\t\t\t\t\t\t\tthat.dom.background.remove();\n\t\t\t\t\t\t\t\tthat.dom.list.remove();\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} );\n\n\t\t\tthis.dom.background.appendTo( 'body' );\n\t\t\tthis.dom.list.appendTo( 'body' );\n\n\t\t\tthis.dom.list.css( 'margin-top', this.dom.list.outerHeight()/2 * -1 );\n\t\t}\n\t},\n\n\n\t/**\n\t * Remove the AutoFill handle from the document\n\t *\n\t * @private\n\t */\n\t_detach: function ()\n\t{\n\t\tthis.dom.attachedTo = null;\n\t\tthis.dom.handle.detach();\n\t},\n\n\n\t/**\n\t * Draw the selection outline by calculating the range between the start\n\t * and end cells, then placing the highlighting elements to draw a rectangle\n\t *\n\t * @param  {node}   target End cell\n\t * @param  {object} e      Originating event\n\t * @private\n\t */\n\t_drawSelection: function ( target, e )\n\t{\n\t\t// Calculate boundary for start cell to this one\n\t\tvar dt = this.s.dt;\n\t\tvar start = this.s.start;\n\t\tvar startCell = $(this.dom.start);\n\t\tvar end = {\n\t\t\trow: this.c.vertical ?\n\t\t\t\tdt.rows( { page: 'current' } ).nodes().indexOf( target.parentNode ) :\n\t\t\t\tstart.row,\n\t\t\tcolumn: this.c.horizontal ?\n\t\t\t\t$(target).index() :\n\t\t\t\tstart.column\n\t\t};\n\t\tvar colIndx = dt.column.index( 'toData', end.column );\n\t\tvar endRow =  dt.row( ':eq('+end.row+')', { page: 'current' } ); // Workaround for M581\n\t\tvar endCell = $( dt.cell( endRow.index(), colIndx ).node() );\n\n\t\t// Be sure that is a DataTables controlled cell\n\t\tif ( ! dt.cell( endCell ).any() ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// if target is not in the columns available - do nothing\n\t\tif ( dt.columns( this.c.columns ).indexes().indexOf( colIndx ) === -1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.s.end = end;\n\n\t\tvar top, bottom, left, right, height, width;\n\n\t\ttop    = start.row    < end.row    ? startCell : endCell;\n\t\tbottom = start.row    < end.row    ? endCell   : startCell;\n\t\tleft   = start.column < end.column ? startCell : endCell;\n\t\tright  = start.column < end.column ? endCell   : startCell;\n\n\t\ttop    = this._getPosition( top.get(0) ).top;\n\t\tleft   = this._getPosition( left.get(0) ).left;\n\t\theight = this._getPosition( bottom.get(0) ).top + bottom.outerHeight() - top;\n\t\twidth  = this._getPosition( right.get(0) ).left + right.outerWidth() - left;\n\n\t\tvar select = this.dom.select;\n\t\tselect.top.css( {\n\t\t\ttop: top,\n\t\t\tleft: left,\n\t\t\twidth: width\n\t\t} );\n\n\t\tselect.left.css( {\n\t\t\ttop: top,\n\t\t\tleft: left,\n\t\t\theight: height\n\t\t} );\n\n\t\tselect.bottom.css( {\n\t\t\ttop: top + height,\n\t\t\tleft: left,\n\t\t\twidth: width\n\t\t} );\n\n\t\tselect.right.css( {\n\t\t\ttop: top,\n\t\t\tleft: left + width,\n\t\t\theight: height\n\t\t} );\n\t},\n\n\n\t/**\n\t * Use the Editor API to perform an update based on the new data for the\n\t * cells\n\t *\n\t * @param {array} cells Information about the selected cells from the key\n\t *     up function\n\t * @private\n\t */\n\t_editor: function ( cells )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar editor = this.c.editor;\n\n\t\tif ( ! editor ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Build the object structure for Editor's multi-row editing\n\t\tvar idValues = {};\n\t\tvar nodes = [];\n\t\tvar fields = editor.fields();\n\n\t\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\tfor ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {\n\t\t\t\tvar cell = cells[i][j];\n\n\t\t\t\t// Determine the field name for the cell being edited\n\t\t\t\tvar col = dt.settings()[0].aoColumns[ cell.index.column ];\n\t\t\t\tvar fieldName = col.editField;\n\n\t\t\t\tif ( fieldName === undefined ) {\n\t\t\t\t\tvar dataSrc = col.mData;\n\n\t\t\t\t\t// dataSrc is the `field.data` property, but we need to set\n\t\t\t\t\t// using the field name, so we need to translate from the\n\t\t\t\t\t// data to the name\n\t\t\t\t\tfor ( var k=0, ken=fields.length ; k<ken ; k++ ) {\n\t\t\t\t\t\tvar field = editor.field( fields[k] );\n\n\t\t\t\t\t\tif ( field.dataSrc() === dataSrc ) {\n\t\t\t\t\t\t\tfieldName = field.name();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( ! fieldName ) {\n\t\t\t\t\tthrow 'Could not automatically determine field data. '+\n\t\t\t\t\t\t'Please see https://datatables.net/tn/11';\n\t\t\t\t}\n\n\t\t\t\tif ( ! idValues[ fieldName ] ) {\n\t\t\t\t\tidValues[ fieldName ] = {};\n\t\t\t\t}\n\n\t\t\t\tvar id = dt.row( cell.index.row ).id();\n\t\t\t\tidValues[ fieldName ][ id ] = cell.set;\n\n\t\t\t\t// Keep a list of cells so we can activate the bubble editing\n\t\t\t\t// with them\n\t\t\t\tnodes.push( cell.index );\n\t\t\t}\n\t\t}\n\n\t\t// Perform the edit using bubble editing as it allows us to specify\n\t\t// the cells to be edited, rather than using full rows\n\t\teditor\n\t\t\t.bubble( nodes, false )\n\t\t\t.multiSet( idValues )\n\t\t\t.submit();\n\t},\n\n\n\t/**\n\t * Emit an event on the DataTable for listeners\n\t *\n\t * @param  {string} name Event name\n\t * @param  {array} args Event arguments\n\t * @private\n\t */\n\t_emitEvent: function ( name, args )\n\t{\n\t\tthis.s.dt.iterator( 'table', function ( ctx, i ) {\n\t\t\t$(ctx.nTable).triggerHandler( name+'.dt', args );\n\t\t} );\n\t},\n\n\n\t/**\n\t * Attach suitable listeners (based on the configuration) that will attach\n\t * and detach the AutoFill handle in the document.\n\t *\n\t * @private\n\t */\n\t_focusListener: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar namespace = this.s.namespace;\n\t\tvar focus = this.c.focus !== null ?\n\t\t\tthis.c.focus :\n\t\t\tdt.init().keys || dt.settings()[0].keytable ?\n\t\t\t\t'focus' :\n\t\t\t\t'hover';\n\n\t\t// All event listeners attached here are removed in the `destroy`\n\t\t// callback in the constructor\n\t\tif ( focus === 'focus' ) {\n\t\t\tdt\n\t\t\t\t.on( 'key-focus.autoFill', function ( e, dt, cell ) {\n\t\t\t\t\tthat._attach( cell.node() );\n\t\t\t\t} )\n\t\t\t\t.on( 'key-blur.autoFill', function ( e, dt, cell ) {\n\t\t\t\t\tthat._detach();\n\t\t\t\t} );\n\t\t}\n\t\telse if ( focus === 'click' ) {\n\t\t\t$(dt.table().body()).on( 'click'+namespace, 'td, th', function (e) {\n\t\t\t\tthat._attach( this );\n\t\t\t} );\n\n\t\t\t$(document.body).on( 'click'+namespace, function (e) {\n\t\t\t\tif ( ! $(e.target).parents().filter( dt.table().body() ).length ) {\n\t\t\t\t\tthat._detach();\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\telse {\n\t\t\t$(dt.table().body())\n\t\t\t\t.on( 'mouseenter'+namespace, 'td, th', function (e) {\n\t\t\t\t\tthat._attach( this );\n\t\t\t\t} )\n\t\t\t\t.on( 'mouseleave'+namespace, function (e) {\n\t\t\t\t\tif ( $(e.relatedTarget).hasClass('dt-autofill-handle') ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tthat._detach();\n\t\t\t\t} );\n\t\t}\n\t},\n\n\n\t_focusListenerRemove: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\n\t\tdt.off( '.autoFill' );\n\t\t$(dt.table().body()).off( this.s.namespace );\n\t\t$(document.body).off( this.s.namespace );\n\t},\n\n\n\t/**\n\t * Get the position of a node, relative to another, including any scrolling\n\t * offsets.\n\t * @param  {Node}   node         Node to get the position of\n\t * @param  {jQuery} targetParent Node to use as the parent\n\t * @return {object}              Offset calculation\n\t * @private\n\t */\n\t_getPosition: function ( node, targetParent )\n\t{\n\t\tvar\n\t\t\tcurrNode = node,\n\t\t\tcurrOffsetParent,\n\t\t\ttop = 0,\n\t\t\tleft = 0;\n\n\t\tif ( ! targetParent ) {\n\t\t\ttargetParent = $( $( this.s.dt.table().node() )[0].offsetParent );\n\t\t}\n\n\t\tdo {\n\t\t\t// Don't use jQuery().position() the behaviour changes between 1.x and 3.x for\n\t\t\t// tables\n\t\t\tvar positionTop = currNode.offsetTop;\n\t\t\tvar positionLeft = currNode.offsetLeft;\n\n\t\t\t// jQuery doesn't give a `table` as the offset parent oddly, so use DOM directly\n\t\t\tcurrOffsetParent = $( currNode.offsetParent );\n\n\t\t\ttop += positionTop + currOffsetParent.scrollTop();\n\t\t\tleft += positionLeft + currOffsetParent.scrollLeft();\n\n\t\t\ttop += parseInt( currOffsetParent.css('margin-top') ) * 1;\n\t\t\ttop += parseInt( currOffsetParent.css('border-top-width') ) * 1;\n\n\t\t\t// Emergency fall back. Shouldn't happen, but just in case!\n\t\t\tif ( currNode.nodeName.toLowerCase() === 'body' ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcurrNode = currOffsetParent.get(0); // for next loop\n\t\t}\n\t\twhile ( currOffsetParent.get(0) !== targetParent.get(0) )\n\n\t\treturn {\n\t\t\ttop: top,\n\t\t\tleft: left\n\t\t};\n\t},\n\n\n\t/**\n\t * Start mouse drag - selects the start cell\n\t *\n\t * @param  {object} e Mouse down event\n\t * @private\n\t */\n\t_mousedown: function ( e )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\n\t\tthis.dom.start = this.dom.attachedTo;\n\t\tthis.s.start = {\n\t\t\trow: dt.rows( { page: 'current' } ).nodes().indexOf( $(this.dom.start).parent()[0] ),\n\t\t\tcolumn: $(this.dom.start).index()\n\t\t};\n\n\t\t$(document.body)\n\t\t\t.on( 'mousemove.autoFill', function (e) {\n\t\t\t\tthat._mousemove( e );\n\t\t\t} )\n\t\t\t.on( 'mouseup.autoFill', function (e) {\n\t\t\t\tthat._mouseup( e );\n\t\t\t} );\n\n\t\tvar select = this.dom.select;\n\t\tvar offsetParent = $( dt.table().node() ).offsetParent();\n\t\tselect.top.appendTo( offsetParent );\n\t\tselect.left.appendTo( offsetParent );\n\t\tselect.right.appendTo( offsetParent );\n\t\tselect.bottom.appendTo( offsetParent );\n\n\t\tthis._drawSelection( this.dom.start, e );\n\n\t\tthis.dom.handle.css( 'display', 'none' );\n\n\t\t// Cache scrolling information so mouse move doesn't need to read.\n\t\t// This assumes that the window and DT scroller will not change size\n\t\t// during an AutoFill drag, which I think is a fair assumption\n\t\tvar scrollWrapper = this.dom.dtScroll;\n\t\tthis.s.scroll = {\n\t\t\twindowHeight: $(window).height(),\n\t\t\twindowWidth:  $(window).width(),\n\t\t\tdtTop:        scrollWrapper ? scrollWrapper.offset().top : null,\n\t\t\tdtLeft:       scrollWrapper ? scrollWrapper.offset().left : null,\n\t\t\tdtHeight:     scrollWrapper ? scrollWrapper.outerHeight() : null,\n\t\t\tdtWidth:      scrollWrapper ? scrollWrapper.outerWidth() : null\n\t\t};\n\t},\n\n\n\t/**\n\t * Mouse drag - selects the end cell and update the selection display for\n\t * the end user\n\t *\n\t * @param  {object} e Mouse move event\n\t * @private\n\t */\n\t_mousemove: function ( e )\n\t{\t\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar name = e.target.nodeName.toLowerCase();\n\t\tif ( name !== 'td' && name !== 'th' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._drawSelection( e.target, e );\n\t\tthis._shiftScroll( e );\n\t},\n\n\n\t/**\n\t * End mouse drag - perform the update actions\n\t *\n\t * @param  {object} e Mouse up event\n\t * @private\n\t */\n\t_mouseup: function ( e )\n\t{\n\t\t$(document.body).off( '.autoFill' );\n\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar select = this.dom.select;\n\t\tselect.top.remove();\n\t\tselect.left.remove();\n\t\tselect.right.remove();\n\t\tselect.bottom.remove();\n\n\t\tthis.dom.handle.css( 'display', 'block' );\n\n\t\t// Display complete - now do something useful with the selection!\n\t\tvar start = this.s.start;\n\t\tvar end = this.s.end;\n\n\t\t// Haven't selected multiple cells, so nothing to do\n\t\tif ( start.row === end.row && start.column === end.column ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar startDt = dt.cell( ':eq('+start.row+')', start.column+':visible', {page:'current'} );\n\n\t\t// If Editor is active inside this cell (inline editing) we need to wait for Editor to\n\t\t// submit and then we can loop back and trigger the fill.\n\t\tif ( $('div.DTE', startDt.node()).length ) {\n\t\t\tvar editor = dt.editor();\n\n\t\t\teditor\n\t\t\t\t.on( 'submitSuccess.dtaf close.dtaf', function () {\n\t\t\t\t\teditor.off( '.dtaf');\n\n\t\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t\tthat._mouseup( e );\n\t\t\t\t\t}, 100 );\n\t\t\t\t} )\n\t\t\t\t.on( 'submitComplete.dtaf preSubmitCancelled.dtaf close.dtaf', function () {\n\t\t\t\t\teditor.off( '.dtaf');\n\t\t\t\t} );\n\n\t\t\t// Make the current input submit\n\t\t\teditor.submit();\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Build a matrix representation of the selected rows\n\t\tvar rows       = this._range( start.row, end.row );\n\t\tvar columns    = this._range( start.column, end.column );\n\t\tvar selected   = [];\n\t\tvar dtSettings = dt.settings()[0];\n\t\tvar dtColumns  = dtSettings.aoColumns;\n\n\t\t// Can't use Array.prototype.map as IE8 doesn't support it\n\t\t// Can't use $.map as jQuery flattens 2D arrays\n\t\t// Need to use a good old fashioned for loop\n\t\tfor ( var rowIdx=0 ; rowIdx<rows.length ; rowIdx++ ) {\n\t\t\tselected.push(\n\t\t\t\t$.map( columns, function (column) {\n\t\t\t\t\tvar row = dt.row( ':eq('+rows[rowIdx]+')', {page:'current'} ); // Workaround for M581\n\t\t\t\t\tvar cell = dt.cell( row.index(), column+':visible' );\n\t\t\t\t\tvar data = cell.data();\n\t\t\t\t\tvar cellIndex = cell.index();\n\t\t\t\t\tvar editField = dtColumns[ cellIndex.column ].editField;\n\n\t\t\t\t\tif ( editField !== undefined ) {\n\t\t\t\t\t\tdata = dtSettings.oApi._fnGetObjectDataFn( editField )( dt.row( cellIndex.row ).data() );\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcell:  cell,\n\t\t\t\t\t\tdata:  data,\n\t\t\t\t\t\tlabel: cell.data(),\n\t\t\t\t\t\tindex: cellIndex\n\t\t\t\t\t};\n\t\t\t\t} )\n\t\t\t);\n\t\t}\n\n\t\tthis._actionSelector( selected );\n\t\t\n\t\t// Stop shiftScroll\n\t\tclearInterval( this.s.scrollInterval );\n\t\tthis.s.scrollInterval = null;\n\t},\n\n\n\t/**\n\t * Create an array with a range of numbers defined by the start and end\n\t * parameters passed in (inclusive!).\n\t * \n\t * @param  {integer} start Start\n\t * @param  {integer} end   End\n\t * @private\n\t */\n\t_range: function ( start, end )\n\t{\n\t\tvar out = [];\n\t\tvar i;\n\n\t\tif ( start <= end ) {\n\t\t\tfor ( i=start ; i<=end ; i++ ) {\n\t\t\t\tout.push( i );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( i=start ; i>=end ; i-- ) {\n\t\t\t\tout.push( i );\n\t\t\t}\n\t\t}\n\n\t\treturn out;\n\t},\n\n\n\t/**\n\t * Move the window and DataTables scrolling during a drag to scroll new\n\t * content into view. This is done by proximity to the edge of the scrolling\n\t * container of the mouse - for example near the top edge of the window\n\t * should scroll up. This is a little complicated as there are two elements\n\t * that can be scrolled - the window and the DataTables scrolling view port\n\t * (if scrollX and / or scrollY is enabled).\n\t *\n\t * @param  {object} e Mouse move event object\n\t * @private\n\t */\n\t_shiftScroll: function ( e )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar scroll = this.s.scroll;\n\t\tvar runInterval = false;\n\t\tvar scrollSpeed = 5;\n\t\tvar buffer = 65;\n\t\tvar\n\t\t\twindowY = e.pageY - document.body.scrollTop,\n\t\t\twindowX = e.pageX - document.body.scrollLeft,\n\t\t\twindowVert, windowHoriz,\n\t\t\tdtVert, dtHoriz;\n\n\t\t// Window calculations - based on the mouse position in the window,\n\t\t// regardless of scrolling\n\t\tif ( windowY < buffer ) {\n\t\t\twindowVert = scrollSpeed * -1;\n\t\t}\n\t\telse if ( windowY > scroll.windowHeight - buffer ) {\n\t\t\twindowVert = scrollSpeed;\n\t\t}\n\n\t\tif ( windowX < buffer ) {\n\t\t\twindowHoriz = scrollSpeed * -1;\n\t\t}\n\t\telse if ( windowX > scroll.windowWidth - buffer ) {\n\t\t\twindowHoriz = scrollSpeed;\n\t\t}\n\n\t\t// DataTables scrolling calculations - based on the table's position in\n\t\t// the document and the mouse position on the page\n\t\tif ( scroll.dtTop !== null && e.pageY < scroll.dtTop + buffer ) {\n\t\t\tdtVert = scrollSpeed * -1;\n\t\t}\n\t\telse if ( scroll.dtTop !== null && e.pageY > scroll.dtTop + scroll.dtHeight - buffer ) {\n\t\t\tdtVert = scrollSpeed;\n\t\t}\n\n\t\tif ( scroll.dtLeft !== null && e.pageX < scroll.dtLeft + buffer ) {\n\t\t\tdtHoriz = scrollSpeed * -1;\n\t\t}\n\t\telse if ( scroll.dtLeft !== null && e.pageX > scroll.dtLeft + scroll.dtWidth - buffer ) {\n\t\t\tdtHoriz = scrollSpeed;\n\t\t}\n\n\t\t// This is where it gets interesting. We want to continue scrolling\n\t\t// without requiring a mouse move, so we need an interval to be\n\t\t// triggered. The interval should continue until it is no longer needed,\n\t\t// but it must also use the latest scroll commands (for example consider\n\t\t// that the mouse might move from scrolling up to scrolling left, all\n\t\t// with the same interval running. We use the `scroll` object to \"pass\"\n\t\t// this information to the interval. Can't use local variables as they\n\t\t// wouldn't be the ones that are used by an already existing interval!\n\t\tif ( windowVert || windowHoriz || dtVert || dtHoriz ) {\n\t\t\tscroll.windowVert = windowVert;\n\t\t\tscroll.windowHoriz = windowHoriz;\n\t\t\tscroll.dtVert = dtVert;\n\t\t\tscroll.dtHoriz = dtHoriz;\n\t\t\trunInterval = true;\n\t\t}\n\t\telse if ( this.s.scrollInterval ) {\n\t\t\t// Don't need to scroll - remove any existing timer\n\t\t\tclearInterval( this.s.scrollInterval );\n\t\t\tthis.s.scrollInterval = null;\n\t\t}\n\n\t\t// If we need to run the interval to scroll and there is no existing\n\t\t// interval (if there is an existing one, it will continue to run)\n\t\tif ( ! this.s.scrollInterval && runInterval ) {\n\t\t\tthis.s.scrollInterval = setInterval( function () {\n\t\t\t\t// Don't need to worry about setting scroll <0 or beyond the\n\t\t\t\t// scroll bound as the browser will just reject that.\n\t\t\t\tif ( scroll.windowVert ) {\n\t\t\t\t\tdocument.body.scrollTop += scroll.windowVert;\n\t\t\t\t}\n\t\t\t\tif ( scroll.windowHoriz ) {\n\t\t\t\t\tdocument.body.scrollLeft += scroll.windowHoriz;\n\t\t\t\t}\n\n\t\t\t\t// DataTables scrolling\n\t\t\t\tif ( scroll.dtVert || scroll.dtHoriz ) {\n\t\t\t\t\tvar scroller = that.dom.dtScroll[0];\n\n\t\t\t\t\tif ( scroll.dtVert ) {\n\t\t\t\t\t\tscroller.scrollTop += scroll.dtVert;\n\t\t\t\t\t}\n\t\t\t\t\tif ( scroll.dtHoriz ) {\n\t\t\t\t\t\tscroller.scrollLeft += scroll.dtHoriz;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, 20 );\n\t\t}\n\t},\n\n\n\t/**\n\t * Update the DataTable after the user has selected what they want to do\n\t *\n\t * @param  {false|undefined} result Return from the `execute` method - can\n\t *   be false internally to do nothing. This is not documented for plug-ins\n\t *   and is used only by the cancel option.\n\t * @param {array} cells Information about the selected cells from the key\n\t *     up function, argumented with the set values\n\t * @private\n\t */\n\t_update: function ( result, cells )\n\t{\n\t\t// Do nothing on `false` return from an execute function\n\t\tif ( result === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar dt = this.s.dt;\n\t\tvar cell;\n\t\tvar columns = dt.columns( this.c.columns ).indexes();\n\n\t\t// Potentially allow modifications to the cells matrix\n\t\tthis._emitEvent( 'preAutoFill', [ dt, cells ] );\n\n\t\tthis._editor( cells );\n\n\t\t// Automatic updates are not performed if `update` is null and the\n\t\t// `editor` parameter is passed in - the reason being that Editor will\n\t\t// update the data once submitted\n\t\tvar update = this.c.update !== null ?\n\t\t\tthis.c.update :\n\t\t\tthis.c.editor ?\n\t\t\t\tfalse :\n\t\t\t\ttrue;\n\n\t\tif ( update ) {\n\t\t\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tfor ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {\n\t\t\t\t\tcell = cells[i][j];\n\n\t\t\t\t\tif ( columns.indexOf(cell.index.column) !== -1 ) {\n\t\t\t\t\t\tcell.cell.data( cell.set );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdt.draw(false);\n\t\t}\n\n\t\tthis._emitEvent( 'autoFill', [ dt, cells ] );\n\t}\n} );\n\n\n/**\n * AutoFill actions. The options here determine how AutoFill will fill the data\n * in the table when the user has selected a range of cells. Please see the\n * documentation on the DataTables site for full details on how to create plug-\n * ins.\n *\n * @type {Object}\n */\nAutoFill.actions = {\n\tincrement: {\n\t\tavailable: function ( dt, cells ) {\n\t\t\tvar d = cells[0][0].label;\n\n\t\t\t// is numeric test based on jQuery's old `isNumeric` function\n\t\t\treturn !isNaN( d - parseFloat( d ) );\n\t\t},\n\n\t\toption: function ( dt, cells ) {\n\t\t\treturn dt.i18n(\n\t\t\t\t'autoFill.increment',\n\t\t\t\t'Increment / decrement each cell by: <input type=\"number\" value=\"1\">'\n\t\t\t);\n\t\t},\n\n\t\texecute: function ( dt, cells, node ) {\n\t\t\tvar value = cells[0][0].data * 1;\n\t\t\tvar increment = $('input', node).val() * 1;\n\n\t\t\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tfor ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {\n\t\t\t\t\tcells[i][j].set = value;\n\n\t\t\t\t\tvalue += increment;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tfill: {\n\t\tavailable: function ( dt, cells ) {\n\t\t\treturn true;\n\t\t},\n\n\t\toption: function ( dt, cells ) {\n\t\t\treturn dt.i18n('autoFill.fill', 'Fill all cells with <i>'+cells[0][0].label+'</i>' );\n\t\t},\n\n\t\texecute: function ( dt, cells, node ) {\n\t\t\tvar value = cells[0][0].data;\n\n\t\t\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tfor ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {\n\t\t\t\t\tcells[i][j].set = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tfillHorizontal: {\n\t\tavailable: function ( dt, cells ) {\n\t\t\treturn cells.length > 1 && cells[0].length > 1;\n\t\t},\n\n\t\toption: function ( dt, cells ) {\n\t\t\treturn dt.i18n('autoFill.fillHorizontal', 'Fill cells horizontally' );\n\t\t},\n\n\t\texecute: function ( dt, cells, node ) {\n\t\t\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tfor ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {\n\t\t\t\t\tcells[i][j].set = cells[i][0].data;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tfillVertical: {\n\t\tavailable: function ( dt, cells ) {\n\t\t\treturn cells.length > 1 && cells[0].length > 1;\n\t\t},\n\n\t\toption: function ( dt, cells ) {\n\t\t\treturn dt.i18n('autoFill.fillVertical', 'Fill cells vertically' );\n\t\t},\n\n\t\texecute: function ( dt, cells, node ) {\n\t\t\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tfor ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {\n\t\t\t\t\tcells[i][j].set = cells[0][j].data;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Special type that does not make itself available, but is added\n\t// automatically by AutoFill if a multi-choice list is shown. This allows\n\t// sensible code reuse\n\tcancel: {\n\t\tavailable: function () {\n\t\t\treturn false;\n\t\t},\n\n\t\toption: function ( dt ) {\n\t\t\treturn dt.i18n('autoFill.cancel', 'Cancel' );\n\t\t},\n\n\t\texecute: function () {\n\t\t\treturn false;\n\t\t}\n\t}\n};\n\n\n/**\n * AutoFill version\n * \n * @static\n * @type      String\n */\nAutoFill.version = '2.3.3';\n\n\n/**\n * AutoFill defaults\n * \n * @namespace\n */\nAutoFill.defaults = {\n\t/** @type {Boolean} Ask user what they want to do, even for a single option */\n\talwaysAsk: false,\n\n\t/** @type {string|null} What will trigger a focus */\n\tfocus: null, // focus, click, hover\n\n\t/** @type {column-selector} Columns to provide auto fill for */\n\tcolumns: '', // all\n\n\t/** @type {Boolean} Enable AutoFill on load */\n\tenable: true,\n\n\t/** @type {boolean|null} Update the cells after a drag */\n\tupdate: null, // false is editor given, true otherwise\n\n\t/** @type {DataTable.Editor} Editor instance for automatic submission */\n\teditor: null,\n\n\t/** @type {boolean} Enable vertical fill */\n\tvertical: true,\n\n\t/** @type {boolean} Enable horizontal fill */\n\thorizontal: true\n};\n\n\n/**\n * Classes used by AutoFill that are configurable\n * \n * @namespace\n */\nAutoFill.classes = {\n\t/** @type {String} Class used by the selection button */\n\tbtn: 'btn'\n};\n\n\n/*\n * API\n */\nvar Api = $.fn.dataTable.Api;\n\n// Doesn't do anything - Not documented\nApi.register( 'autoFill()', function () {\n\treturn this;\n} );\n\nApi.register( 'autoFill().enabled()', function () {\n\tvar ctx = this.context[0];\n\n\treturn ctx.autoFill ?\n\t\tctx.autoFill.enabled() :\n\t\tfalse;\n} );\n\nApi.register( 'autoFill().enable()', function ( flag ) {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx.autoFill ) {\n\t\t\tctx.autoFill.enable( flag );\n\t\t}\n\t} );\n} );\n\nApi.register( 'autoFill().disable()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx.autoFill ) {\n\t\t\tctx.autoFill.disable();\n\t\t}\n\t} );\n} );\n\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'preInit.dt.autofill', function (e, settings, json) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.autoFill;\n\tvar defaults = DataTable.defaults.autoFill;\n\n\tif ( init || defaults ) {\n\t\tvar opts = $.extend( {}, init, defaults );\n\n\t\tif ( init !== false ) {\n\t\t\tnew AutoFill( settings, opts  );\n\t\t}\n\t}\n} );\n\n\n// Alias for access\nDataTable.AutoFill = AutoFill;\nDataTable.AutoFill = AutoFill;\n\n\nreturn AutoFill;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/css/buttons.bootstrap.css",
    "content": "@keyframes dtb-spinner {\n  100% {\n    transform: rotate(360deg);\n  }\n}\n@-o-keyframes dtb-spinner {\n  100% {\n    -o-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-ms-keyframes dtb-spinner {\n  100% {\n    -ms-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-webkit-keyframes dtb-spinner {\n  100% {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-moz-keyframes dtb-spinner {\n  100% {\n    -moz-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\ndiv.dt-button-info {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  width: 400px;\n  margin-top: -100px;\n  margin-left: -200px;\n  background-color: white;\n  border: 2px solid #111;\n  box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);\n  border-radius: 3px;\n  text-align: center;\n  z-index: 21;\n}\ndiv.dt-button-info h2 {\n  padding: 0.5em;\n  margin: 0;\n  font-weight: normal;\n  border-bottom: 1px solid #ddd;\n  background-color: #f3f3f3;\n}\ndiv.dt-button-info > div {\n  padding: 1em;\n}\n\ndiv.dt-button-collection-title {\n  text-align: center;\n  padding: 0.3em 0 0.5em;\n  font-size: 0.9em;\n}\n\ndiv.dt-button-collection-title:empty {\n  display: none;\n}\n\nul.dt-button-collection.dropdown-menu {\n  display: block;\n  z-index: 2002;\n  -webkit-column-gap: 8px;\n  -moz-column-gap: 8px;\n  -ms-column-gap: 8px;\n  -o-column-gap: 8px;\n  column-gap: 8px;\n}\nul.dt-button-collection.dropdown-menu.fixed {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  margin-left: -75px;\n  border-radius: 0;\n}\nul.dt-button-collection.dropdown-menu.fixed.two-column {\n  margin-left: -150px;\n}\nul.dt-button-collection.dropdown-menu.fixed.three-column {\n  margin-left: -225px;\n}\nul.dt-button-collection.dropdown-menu.fixed.four-column {\n  margin-left: -300px;\n}\nul.dt-button-collection.dropdown-menu > * {\n  -webkit-column-break-inside: avoid;\n  break-inside: avoid;\n}\nul.dt-button-collection.dropdown-menu.two-column {\n  width: 300px;\n  padding-bottom: 1px;\n  -webkit-column-count: 2;\n  -moz-column-count: 2;\n  -ms-column-count: 2;\n  -o-column-count: 2;\n  column-count: 2;\n}\nul.dt-button-collection.dropdown-menu.three-column {\n  width: 450px;\n  padding-bottom: 1px;\n  -webkit-column-count: 3;\n  -moz-column-count: 3;\n  -ms-column-count: 3;\n  -o-column-count: 3;\n  column-count: 3;\n}\nul.dt-button-collection.dropdown-menu.four-column {\n  width: 600px;\n  padding-bottom: 1px;\n  -webkit-column-count: 4;\n  -moz-column-count: 4;\n  -ms-column-count: 4;\n  -o-column-count: 4;\n  column-count: 4;\n}\nul.dt-button-collection.dropdown-menu .dt-button {\n  border-radius: 0;\n}\n\ndiv.dt-button-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  z-index: 2001;\n}\n\n@media screen and (max-width: 767px) {\n  div.dt-buttons {\n    float: none;\n    width: 100%;\n    text-align: center;\n    margin-bottom: 0.5em;\n  }\n  div.dt-buttons a.btn {\n    float: none;\n  }\n}\ndiv.dt-buttons button.btn.processing,\ndiv.dt-buttons div.btn.processing,\ndiv.dt-buttons a.btn.processing {\n  color: rgba(0, 0, 0, 0.2);\n}\ndiv.dt-buttons button.btn.processing:after,\ndiv.dt-buttons div.btn.processing:after,\ndiv.dt-buttons a.btn.processing:after {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 16px;\n  height: 16px;\n  margin: -8px 0 0 -8px;\n  box-sizing: border-box;\n  display: block;\n  content: ' ';\n  border: 2px solid #282828;\n  border-radius: 50%;\n  border-left-color: transparent;\n  border-right-color: transparent;\n  animation: dtb-spinner 1500ms infinite linear;\n  -o-animation: dtb-spinner 1500ms infinite linear;\n  -ms-animation: dtb-spinner 1500ms infinite linear;\n  -webkit-animation: dtb-spinner 1500ms infinite linear;\n  -moz-animation: dtb-spinner 1500ms infinite linear;\n}\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/css/buttons.bootstrap4.css",
    "content": "@keyframes dtb-spinner {\n  100% {\n    transform: rotate(360deg);\n  }\n}\n@-o-keyframes dtb-spinner {\n  100% {\n    -o-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-ms-keyframes dtb-spinner {\n  100% {\n    -ms-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-webkit-keyframes dtb-spinner {\n  100% {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-moz-keyframes dtb-spinner {\n  100% {\n    -moz-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\ndiv.dt-button-info {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  width: 400px;\n  margin-top: -100px;\n  margin-left: -200px;\n  background-color: white;\n  border: 2px solid #111;\n  box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);\n  border-radius: 3px;\n  text-align: center;\n  z-index: 21;\n}\ndiv.dt-button-info h2 {\n  padding: 0.5em;\n  margin: 0;\n  font-weight: normal;\n  border-bottom: 1px solid #ddd;\n  background-color: #f3f3f3;\n}\ndiv.dt-button-info > div {\n  padding: 1em;\n}\n\ndiv.dt-button-collection-title {\n  text-align: center;\n  padding: 0.3em 0 0.5em;\n  font-size: 0.9em;\n}\n\ndiv.dt-button-collection-title:empty {\n  display: none;\n}\n\ndiv.dt-button-collection.dropdown-menu {\n  display: block;\n  z-index: 2002;\n  -webkit-column-gap: 8px;\n  -moz-column-gap: 8px;\n  -ms-column-gap: 8px;\n  -o-column-gap: 8px;\n  column-gap: 8px;\n}\ndiv.dt-button-collection.dropdown-menu.fixed {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  margin-left: -75px;\n  border-radius: 0;\n}\ndiv.dt-button-collection.dropdown-menu.fixed.two-column {\n  margin-left: -150px;\n}\ndiv.dt-button-collection.dropdown-menu.fixed.three-column {\n  margin-left: -225px;\n}\ndiv.dt-button-collection.dropdown-menu.fixed.four-column {\n  margin-left: -300px;\n}\ndiv.dt-button-collection.dropdown-menu > * {\n  -webkit-column-break-inside: avoid;\n  break-inside: avoid;\n}\ndiv.dt-button-collection.dropdown-menu.two-column {\n  width: 300px;\n  padding-bottom: 1px;\n  -webkit-column-count: 2;\n  -moz-column-count: 2;\n  -ms-column-count: 2;\n  -o-column-count: 2;\n  column-count: 2;\n}\ndiv.dt-button-collection.dropdown-menu.three-column {\n  width: 450px;\n  padding-bottom: 1px;\n  -webkit-column-count: 3;\n  -moz-column-count: 3;\n  -ms-column-count: 3;\n  -o-column-count: 3;\n  column-count: 3;\n}\ndiv.dt-button-collection.dropdown-menu.four-column {\n  width: 600px;\n  padding-bottom: 1px;\n  -webkit-column-count: 4;\n  -moz-column-count: 4;\n  -ms-column-count: 4;\n  -o-column-count: 4;\n  column-count: 4;\n}\ndiv.dt-button-collection.dropdown-menu .dt-button {\n  border-radius: 0;\n}\n\ndiv.dt-button-collection {\n  -webkit-column-gap: 8px;\n  -moz-column-gap: 8px;\n  -ms-column-gap: 8px;\n  -o-column-gap: 8px;\n  column-gap: 8px;\n}\ndiv.dt-button-collection.fixed {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  margin-left: -75px;\n  border-radius: 0;\n}\ndiv.dt-button-collection.fixed.two-column {\n  margin-left: -150px;\n}\ndiv.dt-button-collection.fixed.three-column {\n  margin-left: -225px;\n}\ndiv.dt-button-collection.fixed.four-column {\n  margin-left: -300px;\n}\ndiv.dt-button-collection > * {\n  -webkit-column-break-inside: avoid;\n  break-inside: avoid;\n}\ndiv.dt-button-collection.two-column {\n  width: 300px;\n  padding-bottom: 1px;\n  -webkit-column-count: 2;\n  -moz-column-count: 2;\n  -ms-column-count: 2;\n  -o-column-count: 2;\n  column-count: 2;\n}\ndiv.dt-button-collection.three-column {\n  width: 450px;\n  padding-bottom: 1px;\n  -webkit-column-count: 3;\n  -moz-column-count: 3;\n  -ms-column-count: 3;\n  -o-column-count: 3;\n  column-count: 3;\n}\ndiv.dt-button-collection.four-column {\n  width: 600px;\n  padding-bottom: 1px;\n  -webkit-column-count: 4;\n  -moz-column-count: 4;\n  -ms-column-count: 4;\n  -o-column-count: 4;\n  column-count: 4;\n}\ndiv.dt-button-collection .dt-button {\n  border-radius: 0;\n}\ndiv.dt-button-collection.fixed {\n  max-width: none;\n}\ndiv.dt-button-collection.fixed:before, div.dt-button-collection.fixed:after {\n  display: none;\n}\n\ndiv.dt-button-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  z-index: 999;\n}\n\n@media screen and (max-width: 767px) {\n  div.dt-buttons {\n    float: none;\n    width: 100%;\n    text-align: center;\n    margin-bottom: 0.5em;\n  }\n  div.dt-buttons a.btn {\n    float: none;\n  }\n}\ndiv.dt-buttons button.btn.processing,\ndiv.dt-buttons div.btn.processing,\ndiv.dt-buttons a.btn.processing {\n  color: rgba(0, 0, 0, 0.2);\n}\ndiv.dt-buttons button.btn.processing:after,\ndiv.dt-buttons div.btn.processing:after,\ndiv.dt-buttons a.btn.processing:after {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 16px;\n  height: 16px;\n  margin: -8px 0 0 -8px;\n  box-sizing: border-box;\n  display: block;\n  content: ' ';\n  border: 2px solid #282828;\n  border-radius: 50%;\n  border-left-color: transparent;\n  border-right-color: transparent;\n  animation: dtb-spinner 1500ms infinite linear;\n  -o-animation: dtb-spinner 1500ms infinite linear;\n  -ms-animation: dtb-spinner 1500ms infinite linear;\n  -webkit-animation: dtb-spinner 1500ms infinite linear;\n  -moz-animation: dtb-spinner 1500ms infinite linear;\n}\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/css/buttons.dataTables.css",
    "content": "@keyframes dtb-spinner {\n  100% {\n    transform: rotate(360deg);\n  }\n}\n@-o-keyframes dtb-spinner {\n  100% {\n    -o-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-ms-keyframes dtb-spinner {\n  100% {\n    -ms-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-webkit-keyframes dtb-spinner {\n  100% {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-moz-keyframes dtb-spinner {\n  100% {\n    -moz-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\ndiv.dt-button-info {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  width: 400px;\n  margin-top: -100px;\n  margin-left: -200px;\n  background-color: white;\n  border: 2px solid #111;\n  box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);\n  border-radius: 3px;\n  text-align: center;\n  z-index: 21;\n}\ndiv.dt-button-info h2 {\n  padding: 0.5em;\n  margin: 0;\n  font-weight: normal;\n  border-bottom: 1px solid #ddd;\n  background-color: #f3f3f3;\n}\ndiv.dt-button-info > div {\n  padding: 1em;\n}\n\ndiv.dt-button-collection-title {\n  text-align: center;\n  padding: 0.3em 0 0.5em;\n  font-size: 0.9em;\n}\n\ndiv.dt-button-collection-title:empty {\n  display: none;\n}\n\nbutton.dt-button,\ndiv.dt-button,\na.dt-button {\n  position: relative;\n  display: inline-block;\n  box-sizing: border-box;\n  margin-right: 0.333em;\n  margin-bottom: 0.333em;\n  padding: 0.5em 1em;\n  border: 1px solid #999;\n  border-radius: 2px;\n  cursor: pointer;\n  font-size: 0.88em;\n  line-height: 1.6em;\n  color: black;\n  white-space: nowrap;\n  overflow: hidden;\n  background-color: #e9e9e9;\n  /* Fallback */\n  background-image: -webkit-linear-gradient(top, white 0%, #e9e9e9 100%);\n  /* Chrome 10+, Saf5.1+, iOS 5+ */\n  background-image: -moz-linear-gradient(top, white 0%, #e9e9e9 100%);\n  /* FF3.6 */\n  background-image: -ms-linear-gradient(top, white 0%, #e9e9e9 100%);\n  /* IE10 */\n  background-image: -o-linear-gradient(top, white 0%, #e9e9e9 100%);\n  /* Opera 11.10+ */\n  background-image: linear-gradient(to bottom, white 0%, #e9e9e9 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='white', EndColorStr='#e9e9e9');\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  text-decoration: none;\n  outline: none;\n}\nbutton.dt-button.disabled,\ndiv.dt-button.disabled,\na.dt-button.disabled {\n  color: #999;\n  border: 1px solid #d0d0d0;\n  cursor: default;\n  background-color: #f9f9f9;\n  /* Fallback */\n  background-image: -webkit-linear-gradient(top, #ffffff 0%, #f9f9f9 100%);\n  /* Chrome 10+, Saf5.1+, iOS 5+ */\n  background-image: -moz-linear-gradient(top, #ffffff 0%, #f9f9f9 100%);\n  /* FF3.6 */\n  background-image: -ms-linear-gradient(top, #ffffff 0%, #f9f9f9 100%);\n  /* IE10 */\n  background-image: -o-linear-gradient(top, #ffffff 0%, #f9f9f9 100%);\n  /* Opera 11.10+ */\n  background-image: linear-gradient(to bottom, #ffffff 0%, #f9f9f9 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#ffffff', EndColorStr='#f9f9f9');\n}\nbutton.dt-button:active:not(.disabled), button.dt-button.active:not(.disabled),\ndiv.dt-button:active:not(.disabled),\ndiv.dt-button.active:not(.disabled),\na.dt-button:active:not(.disabled),\na.dt-button.active:not(.disabled) {\n  background-color: #e2e2e2;\n  /* Fallback */\n  background-image: -webkit-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);\n  /* Chrome 10+, Saf5.1+, iOS 5+ */\n  background-image: -moz-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);\n  /* FF3.6 */\n  background-image: -ms-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);\n  /* IE10 */\n  background-image: -o-linear-gradient(top, #f3f3f3 0%, #e2e2e2 100%);\n  /* Opera 11.10+ */\n  background-image: linear-gradient(to bottom, #f3f3f3 0%, #e2e2e2 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f3f3f3', EndColorStr='#e2e2e2');\n  box-shadow: inset 1px 1px 3px #999999;\n}\nbutton.dt-button:active:not(.disabled):hover:not(.disabled), button.dt-button.active:not(.disabled):hover:not(.disabled),\ndiv.dt-button:active:not(.disabled):hover:not(.disabled),\ndiv.dt-button.active:not(.disabled):hover:not(.disabled),\na.dt-button:active:not(.disabled):hover:not(.disabled),\na.dt-button.active:not(.disabled):hover:not(.disabled) {\n  box-shadow: inset 1px 1px 3px #999999;\n  background-color: #cccccc;\n  /* Fallback */\n  background-image: -webkit-linear-gradient(top, #eaeaea 0%, #cccccc 100%);\n  /* Chrome 10+, Saf5.1+, iOS 5+ */\n  background-image: -moz-linear-gradient(top, #eaeaea 0%, #cccccc 100%);\n  /* FF3.6 */\n  background-image: -ms-linear-gradient(top, #eaeaea 0%, #cccccc 100%);\n  /* IE10 */\n  background-image: -o-linear-gradient(top, #eaeaea 0%, #cccccc 100%);\n  /* Opera 11.10+ */\n  background-image: linear-gradient(to bottom, #eaeaea 0%, #cccccc 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#eaeaea', EndColorStr='#cccccc');\n}\nbutton.dt-button:hover,\ndiv.dt-button:hover,\na.dt-button:hover {\n  text-decoration: none;\n}\nbutton.dt-button:hover:not(.disabled),\ndiv.dt-button:hover:not(.disabled),\na.dt-button:hover:not(.disabled) {\n  border: 1px solid #666;\n  background-color: #e0e0e0;\n  /* Fallback */\n  background-image: -webkit-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);\n  /* Chrome 10+, Saf5.1+, iOS 5+ */\n  background-image: -moz-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);\n  /* FF3.6 */\n  background-image: -ms-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);\n  /* IE10 */\n  background-image: -o-linear-gradient(top, #f9f9f9 0%, #e0e0e0 100%);\n  /* Opera 11.10+ */\n  background-image: linear-gradient(to bottom, #f9f9f9 0%, #e0e0e0 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f9f9f9', EndColorStr='#e0e0e0');\n}\nbutton.dt-button:focus:not(.disabled),\ndiv.dt-button:focus:not(.disabled),\na.dt-button:focus:not(.disabled) {\n  border: 1px solid #426c9e;\n  text-shadow: 0 1px 0 #c4def1;\n  outline: none;\n  background-color: #79ace9;\n  /* Fallback */\n  background-image: -webkit-linear-gradient(top, #bddef4 0%, #79ace9 100%);\n  /* Chrome 10+, Saf5.1+, iOS 5+ */\n  background-image: -moz-linear-gradient(top, #bddef4 0%, #79ace9 100%);\n  /* FF3.6 */\n  background-image: -ms-linear-gradient(top, #bddef4 0%, #79ace9 100%);\n  /* IE10 */\n  background-image: -o-linear-gradient(top, #bddef4 0%, #79ace9 100%);\n  /* Opera 11.10+ */\n  background-image: linear-gradient(to bottom, #bddef4 0%, #79ace9 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#bddef4', EndColorStr='#79ace9');\n}\n\n.dt-button embed {\n  outline: none;\n}\n\ndiv.dt-buttons {\n  position: relative;\n  float: left;\n}\ndiv.dt-buttons.buttons-right {\n  float: right;\n}\n\ndiv.dt-button-collection {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 150px;\n  margin-top: 3px;\n  padding: 8px 8px 4px 8px;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, 0.4);\n  background-color: white;\n  overflow: hidden;\n  z-index: 2002;\n  border-radius: 5px;\n  box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3);\n  -webkit-column-gap: 8px;\n  -moz-column-gap: 8px;\n  -ms-column-gap: 8px;\n  -o-column-gap: 8px;\n  column-gap: 8px;\n}\ndiv.dt-button-collection button.dt-button,\ndiv.dt-button-collection div.dt-button,\ndiv.dt-button-collection a.dt-button {\n  position: relative;\n  left: 0;\n  right: 0;\n  width: 100%;\n  display: block;\n  float: none;\n  margin-bottom: 4px;\n  margin-right: 0;\n}\ndiv.dt-button-collection button.dt-button:active:not(.disabled), div.dt-button-collection button.dt-button.active:not(.disabled),\ndiv.dt-button-collection div.dt-button:active:not(.disabled),\ndiv.dt-button-collection div.dt-button.active:not(.disabled),\ndiv.dt-button-collection a.dt-button:active:not(.disabled),\ndiv.dt-button-collection a.dt-button.active:not(.disabled) {\n  background-color: #dadada;\n  /* Fallback */\n  background-image: -webkit-linear-gradient(top, #f0f0f0 0%, #dadada 100%);\n  /* Chrome 10+, Saf5.1+, iOS 5+ */\n  background-image: -moz-linear-gradient(top, #f0f0f0 0%, #dadada 100%);\n  /* FF3.6 */\n  background-image: -ms-linear-gradient(top, #f0f0f0 0%, #dadada 100%);\n  /* IE10 */\n  background-image: -o-linear-gradient(top, #f0f0f0 0%, #dadada 100%);\n  /* Opera 11.10+ */\n  background-image: linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#f0f0f0', EndColorStr='#dadada');\n  box-shadow: inset 1px 1px 3px #666;\n}\ndiv.dt-button-collection.fixed {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  margin-left: -75px;\n  border-radius: 0;\n}\ndiv.dt-button-collection.fixed.two-column {\n  margin-left: -150px;\n}\ndiv.dt-button-collection.fixed.three-column {\n  margin-left: -225px;\n}\ndiv.dt-button-collection.fixed.four-column {\n  margin-left: -300px;\n}\ndiv.dt-button-collection > * {\n  -webkit-column-break-inside: avoid;\n  break-inside: avoid;\n}\ndiv.dt-button-collection.two-column {\n  width: 300px;\n  padding-bottom: 1px;\n  -webkit-column-count: 2;\n  -moz-column-count: 2;\n  -ms-column-count: 2;\n  -o-column-count: 2;\n  column-count: 2;\n}\ndiv.dt-button-collection.three-column {\n  width: 450px;\n  padding-bottom: 1px;\n  -webkit-column-count: 3;\n  -moz-column-count: 3;\n  -ms-column-count: 3;\n  -o-column-count: 3;\n  column-count: 3;\n}\ndiv.dt-button-collection.four-column {\n  width: 600px;\n  padding-bottom: 1px;\n  -webkit-column-count: 4;\n  -moz-column-count: 4;\n  -ms-column-count: 4;\n  -o-column-count: 4;\n  column-count: 4;\n}\ndiv.dt-button-collection .dt-button {\n  border-radius: 0;\n}\n\ndiv.dt-button-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: rgba(0, 0, 0, 0.7);\n  /* Fallback */\n  background: -ms-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  /* IE10 Consumer Preview */\n  background: -moz-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  /* Firefox */\n  background: -o-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  /* Opera */\n  background: -webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0, 0, 0, 0.3)), color-stop(1, rgba(0, 0, 0, 0.7)));\n  /* Webkit (Safari/Chrome 10) */\n  background: -webkit-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  /* Webkit (Chrome 11+) */\n  background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  /* W3C Markup, IE10 Release Preview */\n  z-index: 2001;\n}\n\n@media screen and (max-width: 640px) {\n  div.dt-buttons {\n    float: none !important;\n    text-align: center;\n  }\n}\nbutton.dt-button.processing,\ndiv.dt-button.processing,\na.dt-button.processing {\n  color: rgba(0, 0, 0, 0.2);\n}\nbutton.dt-button.processing:after,\ndiv.dt-button.processing:after,\na.dt-button.processing:after {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 16px;\n  height: 16px;\n  margin: -8px 0 0 -8px;\n  box-sizing: border-box;\n  display: block;\n  content: ' ';\n  border: 2px solid #282828;\n  border-radius: 50%;\n  border-left-color: transparent;\n  border-right-color: transparent;\n  animation: dtb-spinner 1500ms infinite linear;\n  -o-animation: dtb-spinner 1500ms infinite linear;\n  -ms-animation: dtb-spinner 1500ms infinite linear;\n  -webkit-animation: dtb-spinner 1500ms infinite linear;\n  -moz-animation: dtb-spinner 1500ms infinite linear;\n}\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/css/buttons.foundation.css",
    "content": "@keyframes dtb-spinner {\n  100% {\n    transform: rotate(360deg);\n  }\n}\n@-o-keyframes dtb-spinner {\n  100% {\n    -o-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-ms-keyframes dtb-spinner {\n  100% {\n    -ms-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-webkit-keyframes dtb-spinner {\n  100% {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-moz-keyframes dtb-spinner {\n  100% {\n    -moz-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\ndiv.dt-button-info {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  width: 400px;\n  margin-top: -100px;\n  margin-left: -200px;\n  background-color: white;\n  border: 2px solid #111;\n  box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);\n  border-radius: 3px;\n  text-align: center;\n  z-index: 21;\n}\ndiv.dt-button-info h2 {\n  padding: 0.5em;\n  margin: 0;\n  font-weight: normal;\n  border-bottom: 1px solid #ddd;\n  background-color: #f3f3f3;\n}\ndiv.dt-button-info > div {\n  padding: 1em;\n}\n\ndiv.dt-button-collection-title {\n  text-align: center;\n  padding: 0.3em 0 0.5em;\n  font-size: 0.9em;\n}\n\ndiv.dt-button-collection-title:empty {\n  display: none;\n}\n\nul.dt-buttons li {\n  margin: 0;\n}\nul.dt-buttons li.active a {\n  box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.6);\n}\n\nul.dt-buttons.button-group a {\n  margin-bottom: 0;\n}\n\nul.dt-button-collection.f-dropdown {\n  -webkit-column-gap: 8px;\n  -moz-column-gap: 8px;\n  -ms-column-gap: 8px;\n  -o-column-gap: 8px;\n  column-gap: 8px;\n}\nul.dt-button-collection.f-dropdown.fixed {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  margin-left: -75px;\n  border-radius: 0;\n}\nul.dt-button-collection.f-dropdown.fixed.two-column {\n  margin-left: -150px;\n}\nul.dt-button-collection.f-dropdown.fixed.three-column {\n  margin-left: -225px;\n}\nul.dt-button-collection.f-dropdown.fixed.four-column {\n  margin-left: -300px;\n}\nul.dt-button-collection.f-dropdown > * {\n  -webkit-column-break-inside: avoid;\n  break-inside: avoid;\n}\nul.dt-button-collection.f-dropdown.two-column {\n  width: 300px;\n  padding-bottom: 1px;\n  -webkit-column-count: 2;\n  -moz-column-count: 2;\n  -ms-column-count: 2;\n  -o-column-count: 2;\n  column-count: 2;\n}\nul.dt-button-collection.f-dropdown.three-column {\n  width: 450px;\n  padding-bottom: 1px;\n  -webkit-column-count: 3;\n  -moz-column-count: 3;\n  -ms-column-count: 3;\n  -o-column-count: 3;\n  column-count: 3;\n}\nul.dt-button-collection.f-dropdown.four-column {\n  width: 600px;\n  padding-bottom: 1px;\n  -webkit-column-count: 4;\n  -moz-column-count: 4;\n  -ms-column-count: 4;\n  -o-column-count: 4;\n  column-count: 4;\n}\nul.dt-button-collection.f-dropdown .dt-button {\n  border-radius: 0;\n}\nul.dt-button-collection.f-dropdown.fixed {\n  max-width: none;\n}\nul.dt-button-collection.f-dropdown.fixed:before, ul.dt-button-collection.f-dropdown.fixed:after {\n  display: none;\n}\n\ndiv.dt-button-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  z-index: 88;\n}\n\n@media screen and (max-width: 767px) {\n  ul.dt-buttons {\n    float: none;\n    width: 100%;\n    text-align: center;\n    margin-bottom: 0.5rem;\n  }\n  ul.dt-buttons li {\n    float: none;\n  }\n}\ndiv.button-group.stacked.dropdown-pane {\n  margin-top: 2px;\n  padding: 1px;\n  z-index: 89;\n}\ndiv.button-group.stacked.dropdown-pane a.button {\n  display: block;\n  margin-bottom: 1px;\n  border-right: none;\n}\ndiv.button-group.stacked.dropdown-pane a.button:last-child {\n  margin-bottom: 0;\n  margin-right: 1px;\n}\n\ndiv.dt-buttons button.button.processing,\ndiv.dt-buttons div.button.processing,\ndiv.dt-buttons a.button.processing {\n  color: rgba(0, 0, 0, 0.2);\n  color: rgba(255, 255, 255, 0.2);\n  border-top-color: white;\n  border-bottom-color: white;\n}\ndiv.dt-buttons button.button.processing:after,\ndiv.dt-buttons div.button.processing:after,\ndiv.dt-buttons a.button.processing:after {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 16px;\n  height: 16px;\n  margin: -8px 0 0 -8px;\n  box-sizing: border-box;\n  display: block;\n  content: ' ';\n  border: 2px solid #282828;\n  border-radius: 50%;\n  border-left-color: transparent;\n  border-right-color: transparent;\n  animation: dtb-spinner 1500ms infinite linear;\n  -o-animation: dtb-spinner 1500ms infinite linear;\n  -ms-animation: dtb-spinner 1500ms infinite linear;\n  -webkit-animation: dtb-spinner 1500ms infinite linear;\n  -moz-animation: dtb-spinner 1500ms infinite linear;\n}\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/css/buttons.jqueryui.css",
    "content": "@keyframes dtb-spinner {\n  100% {\n    transform: rotate(360deg);\n  }\n}\n@-o-keyframes dtb-spinner {\n  100% {\n    -o-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-ms-keyframes dtb-spinner {\n  100% {\n    -ms-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-webkit-keyframes dtb-spinner {\n  100% {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-moz-keyframes dtb-spinner {\n  100% {\n    -moz-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\ndiv.dt-button-info {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  width: 400px;\n  margin-top: -100px;\n  margin-left: -200px;\n  background-color: white;\n  border: 2px solid #111;\n  box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);\n  border-radius: 3px;\n  text-align: center;\n  z-index: 21;\n}\ndiv.dt-button-info h2 {\n  padding: 0.5em;\n  margin: 0;\n  font-weight: normal;\n  border-bottom: 1px solid #ddd;\n  background-color: #f3f3f3;\n}\ndiv.dt-button-info > div {\n  padding: 1em;\n}\n\ndiv.dt-button-collection-title {\n  text-align: center;\n  padding: 0.3em 0 0.5em;\n  font-size: 0.9em;\n}\n\ndiv.dt-button-collection-title:empty {\n  display: none;\n}\n\ndiv.dt-buttons {\n  position: relative;\n  float: left;\n}\ndiv.dt-buttons .dt-button {\n  margin-right: 0;\n}\ndiv.dt-buttons .dt-button span.ui-icon {\n  display: inline-block;\n  vertical-align: middle;\n  margin-top: -2px;\n}\ndiv.dt-buttons .dt-button:active {\n  outline: none;\n}\ndiv.dt-buttons .dt-button:hover > span {\n  background-color: rgba(0, 0, 0, 0.05);\n}\n\ndiv.dt-button-collection {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 150px;\n  margin-top: 3px;\n  padding: 8px 8px 4px 8px;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, 0.4);\n  background-color: #f3f3f3;\n  background-color: rgba(255, 255, 255, 0.3);\n  overflow: hidden;\n  z-index: 2002;\n  border-radius: 5px;\n  box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3);\n  z-index: 2002;\n  -webkit-column-gap: 8px;\n  -moz-column-gap: 8px;\n  -ms-column-gap: 8px;\n  -o-column-gap: 8px;\n  column-gap: 8px;\n  -webkit-column-gap: 0;\n  -moz-column-gap: 0;\n  -ms-column-gap: 0;\n  -o-column-gap: 0;\n  column-gap: 0;\n}\ndiv.dt-button-collection .dt-button {\n  position: relative;\n  left: 0;\n  right: 0;\n  width: 100%;\n  box-sizing: border-box;\n  display: block;\n  float: none;\n  margin-right: 0;\n  margin-bottom: 4px;\n}\ndiv.dt-button-collection .dt-button:hover > span {\n  background-color: rgba(0, 0, 0, 0.05);\n}\ndiv.dt-button-collection.fixed {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  margin-left: -75px;\n  border-radius: 0;\n}\ndiv.dt-button-collection.fixed.two-column {\n  margin-left: -150px;\n}\ndiv.dt-button-collection.fixed.three-column {\n  margin-left: -225px;\n}\ndiv.dt-button-collection.fixed.four-column {\n  margin-left: -300px;\n}\ndiv.dt-button-collection > * {\n  -webkit-column-break-inside: avoid;\n  break-inside: avoid;\n}\ndiv.dt-button-collection.two-column {\n  width: 300px;\n  padding-bottom: 1px;\n  -webkit-column-count: 2;\n  -moz-column-count: 2;\n  -ms-column-count: 2;\n  -o-column-count: 2;\n  column-count: 2;\n}\ndiv.dt-button-collection.three-column {\n  width: 450px;\n  padding-bottom: 1px;\n  -webkit-column-count: 3;\n  -moz-column-count: 3;\n  -ms-column-count: 3;\n  -o-column-count: 3;\n  column-count: 3;\n}\ndiv.dt-button-collection.four-column {\n  width: 600px;\n  padding-bottom: 1px;\n  -webkit-column-count: 4;\n  -moz-column-count: 4;\n  -ms-column-count: 4;\n  -o-column-count: 4;\n  column-count: 4;\n}\ndiv.dt-button-collection .dt-button {\n  border-radius: 0;\n}\n\ndiv.dt-button-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  background: rgba(0, 0, 0, 0.7);\n  /* Fallback */\n  background: -ms-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  /* IE10 Consumer Preview */\n  background: -moz-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  /* Firefox */\n  background: -o-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  /* Opera */\n  background: -webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, rgba(0, 0, 0, 0.3)), color-stop(1, rgba(0, 0, 0, 0.7)));\n  /* Webkit (Safari/Chrome 10) */\n  background: -webkit-radial-gradient(center, ellipse farthest-corner, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  /* Webkit (Chrome 11+) */\n  background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);\n  /* W3C Markup, IE10 Release Preview */\n  z-index: 2001;\n}\n\n@media screen and (max-width: 640px) {\n  div.dt-buttons {\n    float: none !important;\n    text-align: center;\n  }\n}\nbutton.dt-button.processing,\ndiv.dt-button.processing,\na.dt-button.processing {\n  color: rgba(0, 0, 0, 0.2);\n}\nbutton.dt-button.processing:after,\ndiv.dt-button.processing:after,\na.dt-button.processing:after {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 16px;\n  height: 16px;\n  margin: -8px 0 0 -8px;\n  box-sizing: border-box;\n  display: block;\n  content: ' ';\n  border: 2px solid #282828;\n  border-radius: 50%;\n  border-left-color: transparent;\n  border-right-color: transparent;\n  animation: dtb-spinner 1500ms infinite linear;\n  -o-animation: dtb-spinner 1500ms infinite linear;\n  -ms-animation: dtb-spinner 1500ms infinite linear;\n  -webkit-animation: dtb-spinner 1500ms infinite linear;\n  -moz-animation: dtb-spinner 1500ms infinite linear;\n}\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/css/buttons.semanticui.css",
    "content": "@charset \"UTF-8\";\n@keyframes dtb-spinner {\n  100% {\n    transform: rotate(360deg);\n  }\n}\n@-o-keyframes dtb-spinner {\n  100% {\n    -o-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-ms-keyframes dtb-spinner {\n  100% {\n    -ms-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-webkit-keyframes dtb-spinner {\n  100% {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-moz-keyframes dtb-spinner {\n  100% {\n    -moz-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\ndiv.dt-button-info {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  width: 400px;\n  margin-top: -100px;\n  margin-left: -200px;\n  background-color: white;\n  border: 2px solid #111;\n  box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);\n  border-radius: 3px;\n  text-align: center;\n  z-index: 21;\n}\ndiv.dt-button-info h2 {\n  padding: 0.5em;\n  margin: 0;\n  font-weight: normal;\n  border-bottom: 1px solid #ddd;\n  background-color: #f3f3f3;\n}\ndiv.dt-button-info > div {\n  padding: 1em;\n}\n\ndiv.dt-button-collection-title {\n  text-align: center;\n  padding: 0.3em 0 0.5em;\n  font-size: 0.9em;\n}\n\ndiv.dt-button-collection-title:empty {\n  display: none;\n}\n\ndiv.dt-button-collection {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 150px;\n  margin-top: 3px !important;\n  z-index: 2002;\n  background: white;\n  -webkit-column-gap: 8px;\n  -moz-column-gap: 8px;\n  -ms-column-gap: 8px;\n  -o-column-gap: 8px;\n  column-gap: 8px;\n}\ndiv.dt-button-collection.fixed {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  margin-left: -75px;\n  border-radius: 0;\n}\ndiv.dt-button-collection.fixed.two-column {\n  margin-left: -150px;\n}\ndiv.dt-button-collection.fixed.three-column {\n  margin-left: -225px;\n}\ndiv.dt-button-collection.fixed.four-column {\n  margin-left: -300px;\n}\ndiv.dt-button-collection > * {\n  -webkit-column-break-inside: avoid;\n  break-inside: avoid;\n}\ndiv.dt-button-collection.two-column {\n  width: 300px;\n  padding-bottom: 1px;\n  -webkit-column-count: 2;\n  -moz-column-count: 2;\n  -ms-column-count: 2;\n  -o-column-count: 2;\n  column-count: 2;\n}\ndiv.dt-button-collection.three-column {\n  width: 450px;\n  padding-bottom: 1px;\n  -webkit-column-count: 3;\n  -moz-column-count: 3;\n  -ms-column-count: 3;\n  -o-column-count: 3;\n  column-count: 3;\n}\ndiv.dt-button-collection.four-column {\n  width: 600px;\n  padding-bottom: 1px;\n  -webkit-column-count: 4;\n  -moz-column-count: 4;\n  -ms-column-count: 4;\n  -o-column-count: 4;\n  column-count: 4;\n}\ndiv.dt-button-collection .dt-button {\n  border-radius: 0;\n}\n\nbutton.buttons-collection.ui.button span:after {\n  display: inline-block;\n  content: \"▾\";\n  padding-left: 0.5em;\n}\n\ndiv.dt-button-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  z-index: 2001;\n}\n\n@media screen and (max-width: 767px) {\n  div.dt-buttons {\n    float: none;\n    width: 100%;\n    text-align: center;\n    margin-bottom: 0.5em;\n  }\n  div.dt-buttons a.btn {\n    float: none;\n  }\n}\ndiv.dt-buttons button.button.processing,\ndiv.dt-buttons div.button.processing,\ndiv.dt-buttons a.button.processing {\n  position: relative;\n  color: rgba(0, 0, 0, 0.2);\n}\ndiv.dt-buttons button.button.processing:after,\ndiv.dt-buttons div.button.processing:after,\ndiv.dt-buttons a.button.processing:after {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 16px;\n  height: 16px;\n  margin: -8px 0 0 -8px;\n  box-sizing: border-box;\n  display: block;\n  content: ' ';\n  border: 2px solid #282828;\n  border-radius: 50%;\n  border-left-color: transparent;\n  border-right-color: transparent;\n  animation: dtb-spinner 1500ms infinite linear;\n  -o-animation: dtb-spinner 1500ms infinite linear;\n  -ms-animation: dtb-spinner 1500ms infinite linear;\n  -webkit-animation: dtb-spinner 1500ms infinite linear;\n  -moz-animation: dtb-spinner 1500ms infinite linear;\n}\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/css/common.scss",
    "content": "\ndiv.dt-button-info {\n\tposition: fixed;\n\ttop: 50%;\n\tleft: 50%;\n\twidth: 400px;\n\tmargin-top: -100px;\n\tmargin-left: -200px;\n\tbackground-color: white;\n\tborder: 2px solid #111;\n\tbox-shadow: 3px 3px 8px rgba( 0, 0, 0, 0.3);\n\tborder-radius: 3px;\n\ttext-align: center;\n\tz-index: 21;\n\n\th2 {\n\t\tpadding: 0.5em;\n\t\tmargin: 0;\n\t\tfont-weight: normal;\n\t\tborder-bottom: 1px solid #ddd;\n\t\tbackground-color: #f3f3f3;\n\t}\n\n\t> div {\n\t\tpadding: 1em;\n\t}\n}\n\ndiv.dt-button-collection-title {\n\ttext-align: center;\n\tpadding: 0.3em 0 0.5em;\n\tfont-size: 0.9em;\n}\n\ndiv.dt-button-collection-title:empty {\n\tdisplay: none;\n}\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/css/mixins.scss",
    "content": "\n@mixin dtb-two-stop-gradient($fromColor, $toColor) {\n\tbackground-color: $toColor; /* Fallback */\n\tbackground-image: -webkit-linear-gradient(top, $fromColor 0%, $toColor 100%); /* Chrome 10+, Saf5.1+, iOS 5+ */\n\tbackground-image:    -moz-linear-gradient(top, $fromColor 0%, $toColor 100%); /* FF3.6 */\n\tbackground-image:     -ms-linear-gradient(top, $fromColor 0%, $toColor 100%); /* IE10 */\n\tbackground-image:      -o-linear-gradient(top, $fromColor 0%, $toColor 100%); /* Opera 11.10+ */\n\tbackground-image:         linear-gradient(to bottom, $fromColor 0%, $toColor 100%);\n\tfilter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#{nth( $fromColor, 1 )}', EndColorStr='#{nth( $toColor, 1 )}');\n}\n\n@mixin dtb-radial-gradient ($fromColor, $toColor ) {\n\tbackground: $toColor; /* Fallback */\n\tbackground:     -ms-radial-gradient(center, ellipse farthest-corner, $fromColor 0%, $toColor 100%); /* IE10 Consumer Preview */ \n\tbackground:    -moz-radial-gradient(center, ellipse farthest-corner, $fromColor 0%, $toColor 100%); /* Firefox */ \n\tbackground:      -o-radial-gradient(center, ellipse farthest-corner, $fromColor 0%, $toColor 100%); /* Opera */ \n\tbackground: -webkit-gradient(radial, center center, 0, center center, 497, color-stop(0, $fromColor), color-stop(1, $toColor)); /* Webkit (Safari/Chrome 10) */ \n\tbackground: -webkit-radial-gradient(center, ellipse farthest-corner, $fromColor 0%, $toColor 100%); /* Webkit (Chrome 11+) */ \n\tbackground: radial-gradient(ellipse farthest-corner at center, $fromColor 0%, $toColor 100%); /* W3C Markup, IE10 Release Preview */ \n}\n\n\n@mixin dtb-fixed-collection {\n\t// Fixed positioning feature\n\t&.fixed {\n\t\tposition: fixed;\n\t\ttop: 50%;\n\t\tleft: 50%;\n\t\tmargin-left: -75px;\n\t\tborder-radius: 0;\n\n\t\t&.two-column {\n\t\t\tmargin-left: -150px;\n\t\t}\n\n\t\t&.three-column {\n\t\t\tmargin-left: -225px;\n\t\t}\n\n\t\t&.four-column {\n\t\t\tmargin-left: -300px;\n\t\t}\n\t}\n\n\t// Multi-column layout feature\n\t-webkit-column-gap: 8px;\n\t   -moz-column-gap: 8px;\n\t    -ms-column-gap: 8px;\n\t     -o-column-gap: 8px;\n\tcolumn-gap: 8px;\n\n\t> * {\n\t\t-webkit-column-break-inside: avoid;\n\t\tbreak-inside: avoid;\n\t}\n\n\t&.two-column {\n\t\twidth: 300px;\n\t\tpadding-bottom: 1px;\n\n\t\t-webkit-column-count: 2;\n\t\t   -moz-column-count: 2;\n\t\t    -ms-column-count: 2;\n\t\t     -o-column-count: 2;\n\t\tcolumn-count: 2;\n\t}\n\n\t&.three-column {\n\t\twidth: 450px;\n\t\tpadding-bottom: 1px;\n\n\t\t-webkit-column-count: 3;\n\t\t   -moz-column-count: 3;\n\t\t    -ms-column-count: 3;\n\t\t     -o-column-count: 3;\n\t\tcolumn-count: 3;\n\t}\n\n\t&.four-column {\n\t\twidth: 600px;\n\t\tpadding-bottom: 1px;\n\n\t\t-webkit-column-count: 4;\n\t\t   -moz-column-count: 4;\n\t\t    -ms-column-count: 4;\n\t\t     -o-column-count: 4;\n\t\tcolumn-count: 4;\n\t}\n\n\t// Chrome fix - 531528\n\t.dt-button {\n\t\tborder-radius: 0;\n\t}\n}\n\n\n@mixin dtb-processing {\n\tcolor: rgba(0, 0, 0, 0.2);\n\n\t&:after {\n\t\tposition: absolute;\n\t    top: 50%;\n\t\tleft: 50%;\n\t\twidth: 16px;\n\t\theight: 16px;\n\t\tmargin: -8px 0 0 -8px;\n\t\tbox-sizing: border-box;\n\n\t\tdisplay: block;\n\t\tcontent: ' ';\n\t\tborder: 2px solid rgb(40,40,40);\n\t\tborder-radius: 50%;\n\t\tborder-left-color: transparent;\n\t\tborder-right-color: transparent;\n\t\tanimation: dtb-spinner 1500ms infinite linear;\n\t\t\t-o-animation: dtb-spinner 1500ms infinite linear;\n\t\t\t-ms-animation: dtb-spinner 1500ms infinite linear;\n\t\t\t-webkit-animation: dtb-spinner 1500ms infinite linear;\n\t\t\t-moz-animation: dtb-spinner 1500ms infinite linear;\n\t}\n}\n\n@keyframes dtb-spinner {\n\t100%{ transform: rotate(360deg); }\n}\n\n@-o-keyframes dtb-spinner {\n\t100%{ -o-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@-ms-keyframes dtb-spinner {\n\t100%{ -ms-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@-webkit-keyframes dtb-spinner {\n\t100%{ -webkit-transform: rotate(360deg); transform: rotate(360deg); }\n}\n\n@-moz-keyframes dtb-spinner {\n\t100%{ -moz-transform: rotate(360deg); transform: rotate(360deg); }\n}\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/js/buttons.bootstrap.js",
    "content": "/*! Bootstrap integration for DataTables' Buttons\n * ©2016 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs', 'datatables.net-buttons'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Buttons ) {\n\t\t\t\trequire('datatables.net-buttons')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n$.extend( true, DataTable.Buttons.defaults, {\n\tdom: {\n\t\tcontainer: {\n\t\t\tclassName: 'dt-buttons btn-group'\n\t\t},\n\t\tbutton: {\n\t\t\tclassName: 'btn btn-default'\n\t\t},\n\t\tcollection: {\n\t\t\ttag: 'ul',\n\t\t\tclassName: 'dt-button-collection dropdown-menu',\n\t\t\tbutton: {\n\t\t\t\ttag: 'li',\n\t\t\t\tclassName: 'dt-button',\n\t\t\t\tactive: 'active',\n\t\t\t\tdisabled: 'disabled'\n\t\t\t},\n\t\t\tbuttonLiner: {\n\t\t\t\ttag: 'a',\n\t\t\t\tclassName: ''\n\t\t\t}\n\t\t}\n\t}\n} );\n\nDataTable.ext.buttons.collection.text = function ( dt ) {\n\treturn dt.i18n('buttons.collection', 'Collection <span class=\"caret\"/>');\n};\n\n\nreturn DataTable.Buttons;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/js/buttons.bootstrap4.js",
    "content": "/*! Bootstrap integration for DataTables' Buttons\n * ©2016 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs4', 'datatables.net-buttons'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs4')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Buttons ) {\n\t\t\t\trequire('datatables.net-buttons')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n$.extend( true, DataTable.Buttons.defaults, {\n\tdom: {\n\t\tcontainer: {\n\t\t\tclassName: 'dt-buttons btn-group'\n\t\t},\n\t\tbutton: {\n\t\t\tclassName: 'btn btn-secondary'\n\t\t},\n\t\tcollection: {\n\t\t\ttag: 'div',\n\t\t\tclassName: 'dt-button-collection dropdown-menu',\n\t\t\tbutton: {\n\t\t\t\ttag: 'a',\n\t\t\t\tclassName: 'dt-button dropdown-item',\n\t\t\t\tactive: 'active',\n\t\t\t\tdisabled: 'disabled'\n\t\t\t}\n\t\t}\n\t},\n\tbuttonCreated: function ( config, button ) {\n\t\treturn config.buttons ?\n\t\t\t$('<div class=\"btn-group\"/>').append(button) :\n\t\t\tbutton;\n\t}\n} );\n\nDataTable.ext.buttons.collection.className += ' dropdown-toggle';\nDataTable.ext.buttons.collection.rightAlignClassName = 'dropdown-menu-right';\n\nreturn DataTable.Buttons;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/js/buttons.colVis.js",
    "content": "/*!\n * Column visibility buttons for Buttons and DataTables.\n * 2016 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Buttons ) {\n\t\t\t\trequire('datatables.net-buttons')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n$.extend( DataTable.ext.buttons, {\n\t// A collection of column visibility buttons\n\tcolvis: function ( dt, conf ) {\n\t\treturn {\n\t\t\textend: 'collection',\n\t\t\ttext: function ( dt ) {\n\t\t\t\treturn dt.i18n( 'buttons.colvis', 'Column visibility' );\n\t\t\t},\n\t\t\tclassName: 'buttons-colvis',\n\t\t\tbuttons: [ {\n\t\t\t\textend: 'columnsToggle',\n\t\t\t\tcolumns: conf.columns,\n\t\t\t\tcolumnText: conf.columnText\n\t\t\t} ]\n\t\t};\n\t},\n\n\t// Selected columns with individual buttons - toggle column visibility\n\tcolumnsToggle: function ( dt, conf ) {\n\t\tvar columns = dt.columns( conf.columns ).indexes().map( function ( idx ) {\n\t\t\treturn {\n\t\t\t\textend: 'columnToggle',\n\t\t\t\tcolumns: idx,\n\t\t\t\tcolumnText: conf.columnText\n\t\t\t};\n\t\t} ).toArray();\n\n\t\treturn columns;\n\t},\n\n\t// Single button to toggle column visibility\n\tcolumnToggle: function ( dt, conf ) {\n\t\treturn {\n\t\t\textend: 'columnVisibility',\n\t\t\tcolumns: conf.columns,\n\t\t\tcolumnText: conf.columnText\n\t\t};\n\t},\n\n\t// Selected columns with individual buttons - set column visibility\n\tcolumnsVisibility: function ( dt, conf ) {\n\t\tvar columns = dt.columns( conf.columns ).indexes().map( function ( idx ) {\n\t\t\treturn {\n\t\t\t\textend: 'columnVisibility',\n\t\t\t\tcolumns: idx,\n\t\t\t\tvisibility: conf.visibility,\n\t\t\t\tcolumnText: conf.columnText\n\t\t\t};\n\t\t} ).toArray();\n\n\t\treturn columns;\n\t},\n\n\t// Single button to set column visibility\n\tcolumnVisibility: {\n\t\tcolumns: undefined, // column selector\n\t\ttext: function ( dt, button, conf ) {\n\t\t\treturn conf._columnText( dt, conf );\n\t\t},\n\t\tclassName: 'buttons-columnVisibility',\n\t\taction: function ( e, dt, button, conf ) {\n\t\t\tvar col = dt.columns( conf.columns );\n\t\t\tvar curr = col.visible();\n\n\t\t\tcol.visible( conf.visibility !== undefined ?\n\t\t\t\tconf.visibility :\n\t\t\t\t! (curr.length ? curr[0] : false )\n\t\t\t);\n\t\t},\n\t\tinit: function ( dt, button, conf ) {\n\t\t\tvar that = this;\n\t\t\tbutton.attr( 'data-cv-idx', conf.columns );\n\n\t\t\tdt\n\t\t\t\t.on( 'column-visibility.dt'+conf.namespace, function (e, settings) {\n\t\t\t\t\tif ( ! settings.bDestroying && settings.nTable == dt.settings()[0].nTable ) {\n\t\t\t\t\t\tthat.active( dt.column( conf.columns ).visible() );\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t\t.on( 'column-reorder.dt'+conf.namespace, function (e, settings, details) {\n\t\t\t\t\t// Don't rename buttons based on column name if the button\n\t\t\t\t\t// controls more than one column!\n\t\t\t\t\tif ( dt.columns( conf.columns ).count() !== 1 ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconf.columns = $.inArray( conf.columns, details.mapping );\n\t\t\t\t\tbutton.attr( 'data-cv-idx', conf.columns );\n\n\t\t\t\t\t// Reorder buttons for new table order\n\t\t\t\t\tbutton\n\t\t\t\t\t\t.parent()\n\t\t\t\t\t\t.children('[data-cv-idx]')\n\t\t\t\t\t\t.sort( function (a, b) {\n\t\t\t\t\t\t\treturn (a.getAttribute('data-cv-idx')*1) - (b.getAttribute('data-cv-idx')*1);\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.appendTo(button.parent());\n\t\t\t\t} );\n\n\t\t\tthis.active( dt.column( conf.columns ).visible() );\n\t\t},\n\t\tdestroy: function ( dt, button, conf ) {\n\t\t\tdt\n\t\t\t\t.off( 'column-visibility.dt'+conf.namespace )\n\t\t\t\t.off( 'column-reorder.dt'+conf.namespace );\n\t\t},\n\n\t\t_columnText: function ( dt, conf ) {\n\t\t\t// Use DataTables' internal data structure until this is presented\n\t\t\t// is a public API. The other option is to use\n\t\t\t// `$( column(col).node() ).text()` but the node might not have been\n\t\t\t// populated when Buttons is constructed.\n\t\t\tvar idx = dt.column( conf.columns ).index();\n\t\t\tvar title = dt.settings()[0].aoColumns[ idx ].sTitle\n\t\t\t\t.replace(/\\n/g,\" \")        // remove new lines\n\t\t\t\t.replace(/<br\\s*\\/?>/gi, \" \")  // replace line breaks with spaces\n\t\t\t\t.replace(/<select(.*?)<\\/select>/g, \"\") // remove select tags, including options text\n\t\t\t\t.replace(/<!\\-\\-.*?\\-\\->/g, \"\") // strip HTML comments\n\t\t\t\t.replace(/<.*?>/g, \"\")   // strip HTML\n\t\t\t\t.replace(/^\\s+|\\s+$/g,\"\"); // trim\n\n\t\t\treturn conf.columnText ?\n\t\t\t\tconf.columnText( dt, idx, title ) :\n\t\t\t\ttitle;\n\t\t}\n\t},\n\n\n\tcolvisRestore: {\n\t\tclassName: 'buttons-colvisRestore',\n\n\t\ttext: function ( dt ) {\n\t\t\treturn dt.i18n( 'buttons.colvisRestore', 'Restore visibility' );\n\t\t},\n\n\t\tinit: function ( dt, button, conf ) {\n\t\t\tconf._visOriginal = dt.columns().indexes().map( function ( idx ) {\n\t\t\t\treturn dt.column( idx ).visible();\n\t\t\t} ).toArray();\n\t\t},\n\n\t\taction: function ( e, dt, button, conf ) {\n\t\t\tdt.columns().every( function ( i ) {\n\t\t\t\t// Take into account that ColReorder might have disrupted our\n\t\t\t\t// indexes\n\t\t\t\tvar idx = dt.colReorder && dt.colReorder.transpose ?\n\t\t\t\t\tdt.colReorder.transpose( i, 'toOriginal' ) :\n\t\t\t\t\ti;\n\n\t\t\t\tthis.visible( conf._visOriginal[ idx ] );\n\t\t\t} );\n\t\t}\n\t},\n\n\n\tcolvisGroup: {\n\t\tclassName: 'buttons-colvisGroup',\n\n\t\taction: function ( e, dt, button, conf ) {\n\t\t\tdt.columns( conf.show ).visible( true, false );\n\t\t\tdt.columns( conf.hide ).visible( false, false );\n\n\t\t\tdt.columns.adjust();\n\t\t},\n\n\t\tshow: [],\n\n\t\thide: []\n\t}\n} );\n\n\nreturn DataTable.Buttons;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/js/buttons.flash.js",
    "content": "/*!\n * Flash export buttons for Buttons and DataTables.\n * 2015-2017 SpryMedia Ltd - datatables.net/license\n *\n * ZeroClipbaord - MIT license\n * Copyright (c) 2012 Joseph Huckaby\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Buttons ) {\n\t\t\t\trequire('datatables.net-buttons')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * ZeroClipboard dependency\n */\n\n/*\n * ZeroClipboard 1.0.4 with modifications\n * Author: Joseph Huckaby\n * License: MIT\n *\n * Copyright (c) 2012 Joseph Huckaby\n */\nvar ZeroClipboard_TableTools = {\n\tversion: \"1.0.4-TableTools2\",\n\tclients: {}, // registered upload clients on page, indexed by id\n\tmoviePath: '', // URL to movie\n\tnextId: 1, // ID of next movie\n\n\t$: function(thingy) {\n\t\t// simple DOM lookup utility function\n\t\tif (typeof(thingy) == 'string') {\n\t\t\tthingy = document.getElementById(thingy);\n\t\t}\n\t\tif (!thingy.addClass) {\n\t\t\t// extend element with a few useful methods\n\t\t\tthingy.hide = function() { this.style.display = 'none'; };\n\t\t\tthingy.show = function() { this.style.display = ''; };\n\t\t\tthingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };\n\t\t\tthingy.removeClass = function(name) {\n\t\t\t\tthis.className = this.className.replace( new RegExp(\"\\\\s*\" + name + \"\\\\s*\"), \" \").replace(/^\\s+/, '').replace(/\\s+$/, '');\n\t\t\t};\n\t\t\tthingy.hasClass = function(name) {\n\t\t\t\treturn !!this.className.match( new RegExp(\"\\\\s*\" + name + \"\\\\s*\") );\n\t\t\t};\n\t\t}\n\t\treturn thingy;\n\t},\n\n\tsetMoviePath: function(path) {\n\t\t// set path to ZeroClipboard.swf\n\t\tthis.moviePath = path;\n\t},\n\n\tdispatch: function(id, eventName, args) {\n\t\t// receive event from flash movie, send to client\n\t\tvar client = this.clients[id];\n\t\tif (client) {\n\t\t\tclient.receiveEvent(eventName, args);\n\t\t}\n\t},\n\n\tlog: function ( str ) {\n\t\tconsole.log( 'Flash: '+str );\n\t},\n\n\tregister: function(id, client) {\n\t\t// register new client to receive events\n\t\tthis.clients[id] = client;\n\t},\n\n\tgetDOMObjectPosition: function(obj) {\n\t\t// get absolute coordinates for dom element\n\t\tvar info = {\n\t\t\tleft: 0,\n\t\t\ttop: 0,\n\t\t\twidth: obj.width ? obj.width : obj.offsetWidth,\n\t\t\theight: obj.height ? obj.height : obj.offsetHeight\n\t\t};\n\n\t\tif ( obj.style.width !== \"\" ) {\n\t\t\tinfo.width = obj.style.width.replace(\"px\",\"\");\n\t\t}\n\n\t\tif ( obj.style.height !== \"\" ) {\n\t\t\tinfo.height = obj.style.height.replace(\"px\",\"\");\n\t\t}\n\n\t\twhile (obj) {\n\t\t\tinfo.left += obj.offsetLeft;\n\t\t\tinfo.top += obj.offsetTop;\n\t\t\tobj = obj.offsetParent;\n\t\t}\n\n\t\treturn info;\n\t},\n\n\tClient: function(elem) {\n\t\t// constructor for new simple upload client\n\t\tthis.handlers = {};\n\n\t\t// unique ID\n\t\tthis.id = ZeroClipboard_TableTools.nextId++;\n\t\tthis.movieId = 'ZeroClipboard_TableToolsMovie_' + this.id;\n\n\t\t// register client with singleton to receive flash events\n\t\tZeroClipboard_TableTools.register(this.id, this);\n\n\t\t// create movie\n\t\tif (elem) {\n\t\t\tthis.glue(elem);\n\t\t}\n\t}\n};\n\nZeroClipboard_TableTools.Client.prototype = {\n\n\tid: 0, // unique ID for us\n\tready: false, // whether movie is ready to receive events or not\n\tmovie: null, // reference to movie object\n\tclipText: '', // text to copy to clipboard\n\tfileName: '', // default file save name\n\taction: 'copy', // action to perform\n\thandCursorEnabled: true, // whether to show hand cursor, or default pointer cursor\n\tcssEffects: true, // enable CSS mouse effects on dom container\n\thandlers: null, // user event handlers\n\tsized: false,\n\tsheetName: '', // default sheet name for excel export\n\n\tglue: function(elem, title) {\n\t\t// glue to DOM element\n\t\t// elem can be ID or actual DOM element object\n\t\tthis.domElement = ZeroClipboard_TableTools.$(elem);\n\n\t\t// float just above object, or zIndex 99 if dom element isn't set\n\t\tvar zIndex = 99;\n\t\tif (this.domElement.style.zIndex) {\n\t\t\tzIndex = parseInt(this.domElement.style.zIndex, 10) + 1;\n\t\t}\n\n\t\t// find X/Y position of domElement\n\t\tvar box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);\n\n\t\t// create floating DIV above element\n\t\tthis.div = document.createElement('div');\n\t\tvar style = this.div.style;\n\t\tstyle.position = 'absolute';\n\t\tstyle.left = '0px';\n\t\tstyle.top = '0px';\n\t\tstyle.width = (box.width) + 'px';\n\t\tstyle.height = box.height + 'px';\n\t\tstyle.zIndex = zIndex;\n\n\t\tif ( typeof title != \"undefined\" && title !== \"\" ) {\n\t\t\tthis.div.title = title;\n\t\t}\n\t\tif ( box.width !== 0 && box.height !== 0 ) {\n\t\t\tthis.sized = true;\n\t\t}\n\n\t\t// style.backgroundColor = '#f00'; // debug\n\t\tif ( this.domElement ) {\n\t\t\tthis.domElement.appendChild(this.div);\n\t\t\tthis.div.innerHTML = this.getHTML( box.width, box.height ).replace(/&/g, '&amp;');\n\t\t}\n\t},\n\n\tpositionElement: function() {\n\t\tvar box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);\n\t\tvar style = this.div.style;\n\n\t\tstyle.position = 'absolute';\n\t\t//style.left = (this.domElement.offsetLeft)+'px';\n\t\t//style.top = this.domElement.offsetTop+'px';\n\t\tstyle.width = box.width + 'px';\n\t\tstyle.height = box.height + 'px';\n\n\t\tif ( box.width !== 0 && box.height !== 0 ) {\n\t\t\tthis.sized = true;\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\n\t\tvar flash = this.div.childNodes[0];\n\t\tflash.width = box.width;\n\t\tflash.height = box.height;\n\t},\n\n\tgetHTML: function(width, height) {\n\t\t// return HTML for movie\n\t\tvar html = '';\n\t\tvar flashvars = 'id=' + this.id +\n\t\t\t'&width=' + width +\n\t\t\t'&height=' + height;\n\n\t\tif (navigator.userAgent.match(/MSIE/)) {\n\t\t\t// IE gets an OBJECT tag\n\t\t\tvar protocol = location.href.match(/^https/i) ? 'https://' : 'http://';\n\t\t\thtml += '<object classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" codebase=\"'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,0,0\" width=\"'+width+'\" height=\"'+height+'\" id=\"'+this.movieId+'\" align=\"middle\"><param name=\"allowScriptAccess\" value=\"always\" /><param name=\"allowFullScreen\" value=\"false\" /><param name=\"movie\" value=\"'+ZeroClipboard_TableTools.moviePath+'\" /><param name=\"loop\" value=\"false\" /><param name=\"menu\" value=\"false\" /><param name=\"quality\" value=\"best\" /><param name=\"bgcolor\" value=\"#ffffff\" /><param name=\"flashvars\" value=\"'+flashvars+'\"/><param name=\"wmode\" value=\"transparent\"/></object>';\n\t\t}\n\t\telse {\n\t\t\t// all other browsers get an EMBED tag\n\t\t\thtml += '<embed id=\"'+this.movieId+'\" src=\"'+ZeroClipboard_TableTools.moviePath+'\" loop=\"false\" menu=\"false\" quality=\"best\" bgcolor=\"#ffffff\" width=\"'+width+'\" height=\"'+height+'\" name=\"'+this.movieId+'\" align=\"middle\" allowScriptAccess=\"always\" allowFullScreen=\"false\" type=\"application/x-shockwave-flash\" pluginspage=\"http://www.macromedia.com/go/getflashplayer\" flashvars=\"'+flashvars+'\" wmode=\"transparent\" />';\n\t\t}\n\t\treturn html;\n\t},\n\n\thide: function() {\n\t\t// temporarily hide floater offscreen\n\t\tif (this.div) {\n\t\t\tthis.div.style.left = '-2000px';\n\t\t}\n\t},\n\n\tshow: function() {\n\t\t// show ourselves after a call to hide()\n\t\tthis.reposition();\n\t},\n\n\tdestroy: function() {\n\t\t// destroy control and floater\n\t\tvar that = this;\n\n\t\tif (this.domElement && this.div) {\n\t\t\t$(this.div).remove();\n\n\t\t\tthis.domElement = null;\n\t\t\tthis.div = null;\n\n\t\t\t$.each( ZeroClipboard_TableTools.clients, function ( id, client ) {\n\t\t\t\tif ( client === that ) {\n\t\t\t\t\tdelete ZeroClipboard_TableTools.clients[ id ];\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t},\n\n\treposition: function(elem) {\n\t\t// reposition our floating div, optionally to new container\n\t\t// warning: container CANNOT change size, only position\n\t\tif (elem) {\n\t\t\tthis.domElement = ZeroClipboard_TableTools.$(elem);\n\t\t\tif (!this.domElement) {\n\t\t\t\tthis.hide();\n\t\t\t}\n\t\t}\n\n\t\tif (this.domElement && this.div) {\n\t\t\tvar box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);\n\t\t\tvar style = this.div.style;\n\t\t\tstyle.left = '' + box.left + 'px';\n\t\t\tstyle.top = '' + box.top + 'px';\n\t\t}\n\t},\n\n\tclearText: function() {\n\t\t// clear the text to be copy / saved\n\t\tthis.clipText = '';\n\t\tif (this.ready) {\n\t\t\tthis.movie.clearText();\n\t\t}\n\t},\n\n\tappendText: function(newText) {\n\t\t// append text to that which is to be copied / saved\n\t\tthis.clipText += newText;\n\t\tif (this.ready) { this.movie.appendText(newText) ;}\n\t},\n\n\tsetText: function(newText) {\n\t\t// set text to be copied to be copied / saved\n\t\tthis.clipText = newText;\n\t\tif (this.ready) { this.movie.setText(newText) ;}\n\t},\n\n\tsetFileName: function(newText) {\n\t\t// set the file name\n\t\tthis.fileName = newText;\n\t\tif (this.ready) {\n\t\t\tthis.movie.setFileName(newText);\n\t\t}\n\t},\n\n\tsetSheetData: function(data) {\n\t\t// set the xlsx sheet data\n\t\tif (this.ready) {\n\t\t\tthis.movie.setSheetData( JSON.stringify( data ) );\n\t\t}\n\t},\n\n\tsetAction: function(newText) {\n\t\t// set action (save or copy)\n\t\tthis.action = newText;\n\t\tif (this.ready) {\n\t\t\tthis.movie.setAction(newText);\n\t\t}\n\t},\n\n\taddEventListener: function(eventName, func) {\n\t\t// add user event listener for event\n\t\t// event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel\n\t\teventName = eventName.toString().toLowerCase().replace(/^on/, '');\n\t\tif (!this.handlers[eventName]) {\n\t\t\tthis.handlers[eventName] = [];\n\t\t}\n\t\tthis.handlers[eventName].push(func);\n\t},\n\n\tsetHandCursor: function(enabled) {\n\t\t// enable hand cursor (true), or default arrow cursor (false)\n\t\tthis.handCursorEnabled = enabled;\n\t\tif (this.ready) {\n\t\t\tthis.movie.setHandCursor(enabled);\n\t\t}\n\t},\n\n\tsetCSSEffects: function(enabled) {\n\t\t// enable or disable CSS effects on DOM container\n\t\tthis.cssEffects = !!enabled;\n\t},\n\n\treceiveEvent: function(eventName, args) {\n\t\tvar self;\n\n\t\t// receive event from flash\n\t\teventName = eventName.toString().toLowerCase().replace(/^on/, '');\n\n\t\t// special behavior for certain events\n\t\tswitch (eventName) {\n\t\t\tcase 'load':\n\t\t\t\t// movie claims it is ready, but in IE this isn't always the case...\n\t\t\t\t// bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function\n\t\t\t\tthis.movie = document.getElementById(this.movieId);\n\t\t\t\tif (!this.movie) {\n\t\t\t\t\tself = this;\n\t\t\t\t\tsetTimeout( function() { self.receiveEvent('load', null); }, 1 );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// firefox on pc needs a \"kick\" in order to set these in certain cases\n\t\t\t\tif (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {\n\t\t\t\t\tself = this;\n\t\t\t\t\tsetTimeout( function() { self.receiveEvent('load', null); }, 100 );\n\t\t\t\t\tthis.ready = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.ready = true;\n\t\t\t\tthis.movie.clearText();\n\t\t\t\tthis.movie.appendText( this.clipText );\n\t\t\t\tthis.movie.setFileName( this.fileName );\n\t\t\t\tthis.movie.setAction( this.action );\n\t\t\t\tthis.movie.setHandCursor( this.handCursorEnabled );\n\t\t\t\tbreak;\n\n\t\t\tcase 'mouseover':\n\t\t\t\tif (this.domElement && this.cssEffects) {\n\t\t\t\t\t//this.domElement.addClass('hover');\n\t\t\t\t\tif (this.recoverActive) {\n\t\t\t\t\t\tthis.domElement.addClass('active');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'mouseout':\n\t\t\t\tif (this.domElement && this.cssEffects) {\n\t\t\t\t\tthis.recoverActive = false;\n\t\t\t\t\tif (this.domElement.hasClass('active')) {\n\t\t\t\t\t\tthis.domElement.removeClass('active');\n\t\t\t\t\t\tthis.recoverActive = true;\n\t\t\t\t\t}\n\t\t\t\t\t//this.domElement.removeClass('hover');\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'mousedown':\n\t\t\t\tif (this.domElement && this.cssEffects) {\n\t\t\t\t\tthis.domElement.addClass('active');\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'mouseup':\n\t\t\t\tif (this.domElement && this.cssEffects) {\n\t\t\t\t\tthis.domElement.removeClass('active');\n\t\t\t\t\tthis.recoverActive = false;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t} // switch eventName\n\n\t\tif (this.handlers[eventName]) {\n\t\t\tfor (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {\n\t\t\t\tvar func = this.handlers[eventName][idx];\n\n\t\t\t\tif (typeof(func) == 'function') {\n\t\t\t\t\t// actual function reference\n\t\t\t\t\tfunc(this, args);\n\t\t\t\t}\n\t\t\t\telse if ((typeof(func) == 'object') && (func.length == 2)) {\n\t\t\t\t\t// PHP style object + method, i.e. [myObject, 'myMethod']\n\t\t\t\t\tfunc[0][ func[1] ](this, args);\n\t\t\t\t}\n\t\t\t\telse if (typeof(func) == 'string') {\n\t\t\t\t\t// name of function\n\t\t\t\t\twindow[func](this, args);\n\t\t\t\t}\n\t\t\t} // foreach event handler defined\n\t\t} // user defined handler for event\n\t}\n};\n\nZeroClipboard_TableTools.hasFlash = function ()\n{\n\ttry {\n\t\tvar fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');\n\t\tif (fo) {\n\t\t\treturn true;\n\t\t}\n\t}\n\tcatch (e) {\n\t\tif (\n\t\t\tnavigator.mimeTypes &&\n\t\t\tnavigator.mimeTypes['application/x-shockwave-flash'] !== undefined &&\n\t\t\tnavigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n};\n\n// For the Flash binding to work, ZeroClipboard_TableTools must be on the global\n// object list\nwindow.ZeroClipboard_TableTools = ZeroClipboard_TableTools;\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Local (private) functions\n */\n\n/**\n * If a Buttons instance is initlaised before it is placed into the DOM, Flash\n * won't be able to bind to it, so we need to wait until it is available, this\n * method abstracts that out.\n *\n * @param {ZeroClipboard} flash ZeroClipboard instance\n * @param {jQuery} node  Button\n */\nvar _glue = function ( flash, node )\n{\n\tvar id = node.attr('id');\n\n\tif ( node.parents('html').length ) {\n\t\tflash.glue( node[0], '' );\n\t}\n\telse {\n\t\tsetTimeout( function () {\n\t\t\t_glue( flash, node );\n\t\t}, 500 );\n\t}\n};\n\n/**\n * Get the sheet name for Excel exports.\n *\n * @param {object}  config       Button configuration\n */\nvar _sheetname = function ( config )\n{\n\tvar sheetName = 'Sheet1';\n\n\tif ( config.sheetName ) {\n\t\tsheetName = config.sheetName.replace(/[\\[\\]\\*\\/\\\\\\?\\:]/g, '');\n\t}\n\n\treturn sheetName;\n};\n\n/**\n * Set the flash text. This has to be broken up into chunks as the Javascript /\n * Flash bridge has a size limit. There is no indication in the Flash\n * documentation what this is, and it probably depends upon the browser.\n * Experimentation shows that the point is around 50k when data starts to get\n * lost, so an 8K limit used here is safe.\n *\n * @param {ZeroClipboard} flash ZeroClipboard instance\n * @param {string}        data  Data to send to Flash\n */\nvar _setText = function ( flash, data )\n{\n\tvar parts = data.match(/[\\s\\S]{1,8192}/g) || [];\n\n\tflash.clearText();\n\tfor ( var i=0, len=parts.length ; i<len ; i++ )\n\t{\n\t\tflash.appendText( parts[i] );\n\t}\n};\n\n/**\n * Get the newline character(s)\n *\n * @param {object}  config Button configuration\n * @return {string}        Newline character\n */\nvar _newLine = function ( config )\n{\n\treturn config.newline ?\n\t\tconfig.newline :\n\t\tnavigator.userAgent.match(/Windows/) ?\n\t\t\t'\\r\\n' :\n\t\t\t'\\n';\n};\n\n/**\n * Combine the data from the `buttons.exportData` method into a string that\n * will be used in the export file.\n *\n * @param  {DataTable.Api} dt     DataTables API instance\n * @param  {object}        config Button configuration\n * @return {object}               The data to export\n */\nvar _exportData = function ( dt, config )\n{\n\tvar newLine = _newLine( config );\n\tvar data = dt.buttons.exportData( config.exportOptions );\n\tvar boundary = config.fieldBoundary;\n\tvar separator = config.fieldSeparator;\n\tvar reBoundary = new RegExp( boundary, 'g' );\n\tvar escapeChar = config.escapeChar !== undefined ?\n\t\tconfig.escapeChar :\n\t\t'\\\\';\n\tvar join = function ( a ) {\n\t\tvar s = '';\n\n\t\t// If there is a field boundary, then we might need to escape it in\n\t\t// the source data\n\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\tif ( i > 0 ) {\n\t\t\t\ts += separator;\n\t\t\t}\n\n\t\t\ts += boundary ?\n\t\t\t\tboundary + ('' + a[i]).replace( reBoundary, escapeChar+boundary ) + boundary :\n\t\t\t\ta[i];\n\t\t}\n\n\t\treturn s;\n\t};\n\n\tvar header = config.header ? join( data.header )+newLine : '';\n\tvar footer = config.footer && data.footer ? newLine+join( data.footer ) : '';\n\tvar body = [];\n\n\tfor ( var i=0, ien=data.body.length ; i<ien ; i++ ) {\n\t\tbody.push( join( data.body[i] ) );\n\t}\n\n\treturn {\n\t\tstr: header + body.join( newLine ) + footer,\n\t\trows: body.length\n\t};\n};\n\n\n// Basic initialisation for the buttons is common between them\nvar flashButton = {\n\tavailable: function () {\n\t\treturn ZeroClipboard_TableTools.hasFlash();\n\t},\n\n\tinit: function ( dt, button, config ) {\n\t\t// Insert the Flash movie\n\t\tZeroClipboard_TableTools.moviePath = DataTable.Buttons.swfPath;\n\t\tvar flash = new ZeroClipboard_TableTools.Client();\n\n\t\tflash.setHandCursor( true );\n\t\tflash.addEventListener('mouseDown', function(client) {\n\t\t\tconfig._fromFlash = true;\n\t\t\tdt.button( button[0] ).trigger();\n\t\t\tconfig._fromFlash = false;\n\t\t} );\n\n\t\t_glue( flash, button );\n\n\t\tconfig._flash = flash;\n\t},\n\n\tdestroy: function ( dt, button, config ) {\n\t\tconfig._flash.destroy();\n\t},\n\n\tfieldSeparator: ',',\n\n\tfieldBoundary: '\"',\n\n\texportOptions: {},\n\n\ttitle: '*',\n\n\tmessageTop: '*',\n\n\tmessageBottom: '*',\n\n\tfilename: '*',\n\n\textension: '.csv',\n\n\theader: true,\n\n\tfooter: false\n};\n\n\n/**\n * Convert from numeric position to letter for column names in Excel\n * @param  {int} n Column number\n * @return {string} Column letter(s) name\n */\nfunction createCellPos( n ){\n\tvar ordA = 'A'.charCodeAt(0);\n\tvar ordZ = 'Z'.charCodeAt(0);\n\tvar len = ordZ - ordA + 1;\n\tvar s = \"\";\n\n\twhile( n >= 0 ) {\n\t\ts = String.fromCharCode(n % len + ordA) + s;\n\t\tn = Math.floor(n / len) - 1;\n\t}\n\n\treturn s;\n}\n\n/**\n * Create an XML node and add any children, attributes, etc without needing to\n * be verbose in the DOM.\n *\n * @param  {object} doc      XML document\n * @param  {string} nodeName Node name\n * @param  {object} opts     Options - can be `attr` (attributes), `children`\n *   (child nodes) and `text` (text content)\n * @return {node}            Created node\n */\nfunction _createNode( doc, nodeName, opts ){\n\tvar tempNode = doc.createElement( nodeName );\n\n\tif ( opts ) {\n\t\tif ( opts.attr ) {\n\t\t\t$(tempNode).attr( opts.attr );\n\t\t}\n\n\t\tif ( opts.children ) {\n\t\t\t$.each( opts.children, function ( key, value ) {\n\t\t\t\ttempNode.appendChild( value );\n\t\t\t} );\n\t\t}\n\n\t\tif ( opts.text !== null && opts.text !== undefined ) {\n\t\t\ttempNode.appendChild( doc.createTextNode( opts.text ) );\n\t\t}\n\t}\n\n\treturn tempNode;\n}\n\n/**\n * Get the width for an Excel column based on the contents of that column\n * @param  {object} data Data for export\n * @param  {int}    col  Column index\n * @return {int}         Column width\n */\nfunction _excelColWidth( data, col ) {\n\tvar max = data.header[col].length;\n\tvar len, lineSplit, str;\n\n\tif ( data.footer && data.footer[col].length > max ) {\n\t\tmax = data.footer[col].length;\n\t}\n\n\tfor ( var i=0, ien=data.body.length ; i<ien ; i++ ) {\n\t\tvar point = data.body[i][col];\n\t\tstr = point !== null && point !== undefined ?\n\t\t\tpoint.toString() :\n\t\t\t'';\n\n\t\t// If there is a newline character, workout the width of the column\n\t\t// based on the longest line in the string\n\t\tif ( str.indexOf('\\n') !== -1 ) {\n\t\t\tlineSplit = str.split('\\n');\n\t\t\tlineSplit.sort( function (a, b) {\n\t\t\t\treturn b.length - a.length;\n\t\t\t} );\n\n\t\t\tlen = lineSplit[0].length;\n\t\t}\n\t\telse {\n\t\t\tlen = str.length;\n\t\t}\n\n\t\tif ( len > max ) {\n\t\t\tmax = len;\n\t\t}\n\n\t\t// Max width rather than having potentially massive column widths\n\t\tif ( max > 40 ) {\n\t\t\treturn 52; // 40 * 1.3\n\t\t}\n\t}\n\n\tmax *= 1.3;\n\n\t// And a min width\n\treturn max > 6 ? max : 6;\n}\n\n  var _serialiser = \"\";\n    if (typeof window.XMLSerializer === 'undefined') {\n        _serialiser = new function () {\n            this.serializeToString = function (input) {\n                return input.xml\n            }\n        };\n    } else {\n        _serialiser =  new XMLSerializer();\n    }\n\n    var _ieExcel;\n\n\n/**\n * Convert XML documents in an object to strings\n * @param  {object} obj XLSX document object\n */\nfunction _xlsxToStrings( obj ) {\n\tif ( _ieExcel === undefined ) {\n\t\t// Detect if we are dealing with IE's _awful_ serialiser by seeing if it\n\t\t// drop attributes\n\t\t_ieExcel = _serialiser\n\t\t\t.serializeToString(\n\t\t\t\t$.parseXML( excelStrings['xl/worksheets/sheet1.xml'] )\n\t\t\t)\n\t\t\t.indexOf( 'xmlns:r' ) === -1;\n\t}\n\n\t$.each( obj, function ( name, val ) {\n\t\tif ( $.isPlainObject( val ) ) {\n\t\t\t_xlsxToStrings( val );\n\t\t}\n\t\telse {\n\t\t\tif ( _ieExcel ) {\n\t\t\t\t// IE's XML serialiser will drop some name space attributes from\n\t\t\t\t// from the root node, so we need to save them. Do this by\n\t\t\t\t// replacing the namespace nodes with a regular attribute that\n\t\t\t\t// we convert back when serialised. Edge does not have this\n\t\t\t\t// issue\n\t\t\t\tvar worksheet = val.childNodes[0];\n\t\t\t\tvar i, ien;\n\t\t\t\tvar attrs = [];\n\n\t\t\t\tfor ( i=worksheet.attributes.length-1 ; i>=0 ; i-- ) {\n\t\t\t\t\tvar attrName = worksheet.attributes[i].nodeName;\n\t\t\t\t\tvar attrValue = worksheet.attributes[i].nodeValue;\n\n\t\t\t\t\tif ( attrName.indexOf( ':' ) !== -1 ) {\n\t\t\t\t\t\tattrs.push( { name: attrName, value: attrValue } );\n\n\t\t\t\t\t\tworksheet.removeAttribute( attrName );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor ( i=0, ien=attrs.length ; i<ien ; i++ ) {\n\t\t\t\t\tvar attr = val.createAttribute( attrs[i].name.replace( ':', '_dt_b_namespace_token_' ) );\n\t\t\t\t\tattr.value = attrs[i].value;\n\t\t\t\t\tworksheet.setAttributeNode( attr );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar str = _serialiser.serializeToString(val);\n\n\t\t\t// Fix IE's XML\n\t\t\tif ( _ieExcel ) {\n\t\t\t\t// IE doesn't include the XML declaration\n\t\t\t\tif ( str.indexOf( '<?xml' ) === -1 ) {\n\t\t\t\t\tstr = '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+str;\n\t\t\t\t}\n\n\t\t\t\t// Return namespace attributes to being as such\n\t\t\t\tstr = str.replace( /_dt_b_namespace_token_/g, ':' );\n\t\t\t}\n\n\t\t\t// Safari, IE and Edge will put empty name space attributes onto\n\t\t\t// various elements making them useless. This strips them out\n\t\t\tstr = str.replace( /<([^<>]*?) xmlns=\"\"([^<>]*?)>/g, '<$1 $2>' );\n\n\t\t\tobj[ name ] = str;\n\t\t}\n\t} );\n}\n\n// Excel - Pre-defined strings to build a basic XLSX file\nvar excelStrings = {\n\t\"_rels/.rels\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">'+\n\t\t\t'<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"xl/workbook.xml\"/>'+\n\t\t'</Relationships>',\n\n\t\"xl/_rels/workbook.xml.rels\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">'+\n\t\t\t'<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\" Target=\"worksheets/sheet1.xml\"/>'+\n\t\t\t'<Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>'+\n\t\t'</Relationships>',\n\n\t\"[Content_Types].xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">'+\n\t\t\t'<Default Extension=\"xml\" ContentType=\"application/xml\" />'+\n\t\t\t'<Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\" />'+\n\t\t\t'<Default Extension=\"jpeg\" ContentType=\"image/jpeg\" />'+\n\t\t\t'<Override PartName=\"/xl/workbook.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\" />'+\n\t\t\t'<Override PartName=\"/xl/worksheets/sheet1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\" />'+\n\t\t\t'<Override PartName=\"/xl/styles.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\" />'+\n\t\t'</Types>',\n\n\t\"xl/workbook.xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">'+\n\t\t\t'<fileVersion appName=\"xl\" lastEdited=\"5\" lowestEdited=\"5\" rupBuild=\"24816\"/>'+\n\t\t\t'<workbookPr showInkAnnotation=\"0\" autoCompressPictures=\"0\"/>'+\n\t\t\t'<bookViews>'+\n\t\t\t\t'<workbookView xWindow=\"0\" yWindow=\"0\" windowWidth=\"25600\" windowHeight=\"19020\" tabRatio=\"500\"/>'+\n\t\t\t'</bookViews>'+\n\t\t\t'<sheets>'+\n\t\t\t\t'<sheet name=\"\" sheetId=\"1\" r:id=\"rId1\"/>'+\n\t\t\t'</sheets>'+\n\t\t'</workbook>',\n\n\t\"xl/worksheets/sheet1.xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" mc:Ignorable=\"x14ac\" xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\">'+\n\t\t\t'<sheetData/>'+\n\t\t\t'<mergeCells count=\"0\"/>'+\n\t\t'</worksheet>',\n\n\t\"xl/styles.xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\"?>'+\n\t\t'<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" mc:Ignorable=\"x14ac\" xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\">'+\n\t\t\t'<numFmts count=\"6\">'+\n\t\t\t\t'<numFmt numFmtId=\"164\" formatCode=\"#,##0.00_-\\ [$$-45C]\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"165\" formatCode=\"&quot;£&quot;#,##0.00\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"166\" formatCode=\"[$€-2]\\ #,##0.00\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"167\" formatCode=\"0.0%\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"168\" formatCode=\"#,##0;(#,##0)\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"169\" formatCode=\"#,##0.00;(#,##0.00)\"/>'+\n\t\t\t'</numFmts>'+\n\t\t\t'<fonts count=\"5\" x14ac:knownFonts=\"1\">'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<color rgb=\"FFFFFFFF\" />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<b />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<i />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<u />'+\n\t\t\t\t'</font>'+\n\t\t\t'</fonts>'+\n\t\t\t'<fills count=\"6\">'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"none\" />'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+ // Excel appears to use this as a dotted background regardless of values but\n\t\t\t\t\t'<patternFill patternType=\"none\" />'+ // to be valid to the schema, use a patternFill\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"FFD9D9D9\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"FFD99795\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"ffc6efce\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"ffc6cfef\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t'</fills>'+\n\t\t\t'<borders count=\"2\">'+\n\t\t\t\t'<border>'+\n\t\t\t\t\t'<left />'+\n\t\t\t\t\t'<right />'+\n\t\t\t\t\t'<top />'+\n\t\t\t\t\t'<bottom />'+\n\t\t\t\t\t'<diagonal />'+\n\t\t\t\t'</border>'+\n\t\t\t\t'<border diagonalUp=\"false\" diagonalDown=\"false\">'+\n\t\t\t\t\t'<left style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</left>'+\n\t\t\t\t\t'<right style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</right>'+\n\t\t\t\t\t'<top style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</top>'+\n\t\t\t\t\t'<bottom style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</bottom>'+\n\t\t\t\t\t'<diagonal />'+\n\t\t\t\t'</border>'+\n\t\t\t'</borders>'+\n\t\t\t'<cellStyleXfs count=\"1\">'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" />'+\n\t\t\t'</cellStyleXfs>'+\n\t\t\t'<cellXfs count=\"61\">'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"left\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"center\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"right\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"fill\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment textRotation=\"90\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment wrapText=\"1\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"9\"   fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"164\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"165\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"166\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"167\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"168\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"169\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"3\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"4\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t'</cellXfs>'+\n\t\t\t'<cellStyles count=\"1\">'+\n\t\t\t\t'<cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\" />'+\n\t\t\t'</cellStyles>'+\n\t\t\t'<dxfs count=\"0\" />'+\n\t\t\t'<tableStyles count=\"0\" defaultTableStyle=\"TableStyleMedium9\" defaultPivotStyle=\"PivotStyleMedium4\" />'+\n\t\t'</styleSheet>'\n};\n// Note we could use 3 `for` loops for the styles, but when gzipped there is\n// virtually no difference in size, since the above can be easily compressed\n\n// Pattern matching for special number formats. Perhaps this should be exposed\n// via an API in future?\nvar _excelSpecials = [\n\t{ match: /^\\-?\\d+\\.\\d%$/,       style: 60, fmt: function (d) { return d/100; } }, // Precent with d.p.\n\t{ match: /^\\-?\\d+\\.?\\d*%$/,     style: 56, fmt: function (d) { return d/100; } }, // Percent\n\t{ match: /^\\-?\\$[\\d,]+.?\\d*$/,  style: 57 }, // Dollars\n\t{ match: /^\\-?£[\\d,]+.?\\d*$/,   style: 58 }, // Pounds\n\t{ match: /^\\-?€[\\d,]+.?\\d*$/,   style: 59 }, // Euros\n\t{ match: /^\\([\\d,]+\\)$/,        style: 61, fmt: function (d) { return -1 * d.replace(/[\\(\\)]/g, ''); } },  // Negative numbers indicated by brackets\n\t{ match: /^\\([\\d,]+\\.\\d{2}\\)$/, style: 62, fmt: function (d) { return -1 * d.replace(/[\\(\\)]/g, ''); } },  // Negative numbers indicated by brackets - 2d.p.\n\t{ match: /^[\\d,]+$/,            style: 63 }, // Numbers with thousand separators\n\t{ match: /^[\\d,]+\\.\\d{2}$/,     style: 64 }  // Numbers with 2d.p. and thousands separators\n];\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables options and methods\n */\n\n// Set the default SWF path\nDataTable.Buttons.swfPath = '//cdn.datatables.net/buttons/'+DataTable.Buttons.version+'/swf/flashExport.swf';\n\n// Method to allow Flash buttons to be resized when made visible - as they are\n// of zero height and width if initialised hidden\nDataTable.Api.register( 'buttons.resize()', function () {\n\t$.each( ZeroClipboard_TableTools.clients, function ( i, client ) {\n\t\tif ( client.domElement !== undefined && client.domElement.parentNode ) {\n\t\t\tclient.positionElement();\n\t\t}\n\t} );\n} );\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Button definitions\n */\n\n// Copy to clipboard\nDataTable.ext.buttons.copyFlash = $.extend( {}, flashButton, {\n\tclassName: 'buttons-copy buttons-flash',\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.copy', 'Copy' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\t// Check that the trigger did actually occur due to a Flash activation\n\t\tif ( ! config._fromFlash ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.processing( true );\n\n\t\tvar flash = config._flash;\n\t\tvar exportData = _exportData( dt, config );\n\t\tvar info = dt.buttons.exportInfo( config );\n\t\tvar newline = _newLine(config);\n\t\tvar output = exportData.str;\n\n\t\tif ( info.title ) {\n\t\t\toutput = info.title + newline + newline + output;\n\t\t}\n\n\t\tif ( info.messageTop ) {\n\t\t\toutput = info.messageTop + newline + newline + output;\n\t\t}\n\n\t\tif ( info.messageBottom ) {\n\t\t\toutput = output + newline + newline + info.messageBottom;\n\t\t}\n\n\t\tif ( config.customize ) {\n\t\t\toutput = config.customize( output, config, dt );\n\t\t}\n\n\t\tflash.setAction( 'copy' );\n\t\t_setText( flash, output );\n\n\t\tthis.processing( false );\n\n\t\tdt.buttons.info(\n\t\t\tdt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),\n\t\t\tdt.i18n( 'buttons.copySuccess', {\n\t\t\t\t_: 'Copied %d rows to clipboard',\n\t\t\t\t1: 'Copied 1 row to clipboard'\n\t\t\t}, data.rows ),\n\t\t\t3000\n\t\t);\n\t},\n\n\tfieldSeparator: '\\t',\n\n\tfieldBoundary: ''\n} );\n\n// CSV save file\nDataTable.ext.buttons.csvFlash = $.extend( {}, flashButton, {\n\tclassName: 'buttons-csv buttons-flash',\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.csv', 'CSV' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\t// Set the text\n\t\tvar flash = config._flash;\n\t\tvar data = _exportData( dt, config );\n\t\tvar info = dt.buttons.exportInfo( config );\n\t\tvar output = config.customize ?\n\t\t\tconfig.customize( data.str, config, dt ) :\n\t\t\tdata.str;\n\n\t\tflash.setAction( 'csv' );\n\t\tflash.setFileName( info.filename );\n\t\t_setText( flash, output );\n\t},\n\n\tescapeChar: '\"'\n} );\n\n// Excel save file - this is really a CSV file using UTF-8 that Excel can read\nDataTable.ext.buttons.excelFlash = $.extend( {}, flashButton, {\n\tclassName: 'buttons-excel buttons-flash',\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.excel', 'Excel' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\tthis.processing( true );\n\n\t\tvar flash = config._flash;\n\t\tvar rowPos = 0;\n\t\tvar rels = $.parseXML( excelStrings['xl/worksheets/sheet1.xml'] ) ; //Parses xml\n\t\tvar relsGet = rels.getElementsByTagName( \"sheetData\" )[0];\n\n\t\tvar xlsx = {\n\t\t\t_rels: {\n\t\t\t\t\".rels\": $.parseXML( excelStrings['_rels/.rels'] )\n\t\t\t},\n\t\t\txl: {\n\t\t\t\t_rels: {\n\t\t\t\t\t\"workbook.xml.rels\": $.parseXML( excelStrings['xl/_rels/workbook.xml.rels'] )\n\t\t\t\t},\n\t\t\t\t\"workbook.xml\": $.parseXML( excelStrings['xl/workbook.xml'] ),\n\t\t\t\t\"styles.xml\": $.parseXML( excelStrings['xl/styles.xml'] ),\n\t\t\t\t\"worksheets\": {\n\t\t\t\t\t\"sheet1.xml\": rels\n\t\t\t\t}\n\n\t\t\t},\n\t\t\t\"[Content_Types].xml\": $.parseXML( excelStrings['[Content_Types].xml'])\n\t\t};\n\n\t\tvar data = dt.buttons.exportData( config.exportOptions );\n\t\tvar currentRow, rowNode;\n\t\tvar addRow = function ( row ) {\n\t\t\tcurrentRow = rowPos+1;\n\t\t\trowNode = _createNode( rels, \"row\", { attr: {r:currentRow} } );\n\n\t\t\tfor ( var i=0, ien=row.length ; i<ien ; i++ ) {\n\t\t\t\t// Concat both the Cell Columns as a letter and the Row of the cell.\n\t\t\t\tvar cellId = createCellPos(i) + '' + currentRow;\n\t\t\t\tvar cell = null;\n\n\t\t\t\t// For null, undefined of blank cell, continue so it doesn't create the _createNode\n\t\t\t\tif ( row[i] === null || row[i] === undefined || row[i] === '' ) {\n\t\t\t\t\tif ( config.createEmptyCells === true ) {\n\t\t\t\t\t\trow[i] = '';\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\trow[i] = $.trim( row[i] );\n\n\t\t\t\t// Special number formatting options\n\t\t\t\tfor ( var j=0, jen=_excelSpecials.length ; j<jen ; j++ ) {\n\t\t\t\t\tvar special = _excelSpecials[j];\n\n\t\t\t\t\t// TODO Need to provide the ability for the specials to say\n\t\t\t\t\t// if they are returning a string, since at the moment it is\n\t\t\t\t\t// assumed to be a number\n\t\t\t\t\tif ( row[i].match && ! row[i].match(/^0\\d+/) && row[i].match( special.match ) ) {\n\t\t\t\t\t\tvar val = row[i].replace(/[^\\d\\.\\-]/g, '');\n\n\t\t\t\t\t\tif ( special.fmt ) {\n\t\t\t\t\t\t\tval = special.fmt( val );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcell = _createNode( rels, 'c', {\n\t\t\t\t\t\t\tattr: {\n\t\t\t\t\t\t\t\tr: cellId,\n\t\t\t\t\t\t\t\ts: special.style\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren: [\n\t\t\t\t\t\t\t\t_createNode( rels, 'v', { text: val } )\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( ! cell ) {\n\t\t\t\t\tif ( typeof row[i] === 'number' || (\n\t\t\t\t\t\trow[i].match &&\n\t\t\t\t\t\trow[i].match(/^-?\\d+(\\.\\d+)?$/) &&\n\t\t\t\t\t\t! row[i].match(/^0\\d+/) )\n\t\t\t\t\t) {\n\t\t\t\t\t\t// Detect numbers - don't match numbers with leading zeros\n\t\t\t\t\t\t// or a negative anywhere but the start\n\t\t\t\t\t\tcell = _createNode( rels, 'c', {\n\t\t\t\t\t\t\tattr: {\n\t\t\t\t\t\t\t\tt: 'n',\n\t\t\t\t\t\t\t\tr: cellId\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren: [\n\t\t\t\t\t\t\t\t_createNode( rels, 'v', { text: row[i] } )\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// String output - replace non standard characters for text output\n\t\t\t\t\t\tvar text = ! row[i].replace ?\n\t\t\t\t\t\t\trow[i] :\n\t\t\t\t\t\t\trow[i].replace(/[\\x00-\\x09\\x0B\\x0C\\x0E-\\x1F\\x7F-\\x9F]/g, '');\n\n\t\t\t\t\t\tcell = _createNode( rels, 'c', {\n\t\t\t\t\t\t\tattr: {\n\t\t\t\t\t\t\t\tt: 'inlineStr',\n\t\t\t\t\t\t\t\tr: cellId\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren:{\n\t\t\t\t\t\t\t\trow: _createNode( rels, 'is', {\n\t\t\t\t\t\t\t\t\tchildren: {\n\t\t\t\t\t\t\t\t\t\trow: _createNode( rels, 't', {\n\t\t\t\t\t\t\t\t\t\t\ttext: text\n\t\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\trowNode.appendChild( cell );\n\t\t\t}\n\n\t\t\trelsGet.appendChild(rowNode);\n\t\t\trowPos++;\n\t\t};\n\n\t\t$( 'sheets sheet', xlsx.xl['workbook.xml'] ).attr( 'name', _sheetname( config ) );\n\n\t\tif ( config.customizeData ) {\n\t\t\tconfig.customizeData( data );\n\t\t}\n\n\t\tvar mergeCells = function ( row, colspan ) {\n\t\t\tvar mergeCells = $('mergeCells', rels);\n\n\t\t\tmergeCells[0].appendChild( _createNode( rels, 'mergeCell', {\n\t\t\t\tattr: {\n\t\t\t\t\tref: 'A'+row+':'+createCellPos(colspan)+row\n\t\t\t\t}\n\t\t\t} ) );\n\t\t\tmergeCells.attr( 'count', mergeCells.attr( 'count' )+1 );\n\t\t\t$('row:eq('+(row-1)+') c', rels).attr( 's', '51' ); // centre\n\t\t};\n\n\t\t// Title and top messages\n\t\tvar exportInfo = dt.buttons.exportInfo( config );\n\t\tif ( exportInfo.title ) {\n\t\t\taddRow( [exportInfo.title], rowPos );\n\t\t\tmergeCells( rowPos, data.header.length-1 );\n\t\t}\n\n\t\tif ( exportInfo.messageTop ) {\n\t\t\taddRow( [exportInfo.messageTop], rowPos );\n\t\t\tmergeCells( rowPos, data.header.length-1 );\n\t\t}\n\n\t\t// Table itself\n\t\tif ( config.header ) {\n\t\t\taddRow( data.header, rowPos );\n\t\t\t$('row:last c', rels).attr( 's', '2' ); // bold\n\t\t}\n\n\t\tfor ( var n=0, ie=data.body.length ; n<ie ; n++ ) {\n\t\t\taddRow( data.body[n], rowPos );\n\t\t}\n\n\t\tif ( config.footer && data.footer ) {\n\t\t\taddRow( data.footer, rowPos);\n\t\t\t$('row:last c', rels).attr( 's', '2' ); // bold\n\t\t}\n\n\t\t// Below the table\n\t\tif ( exportInfo.messageBottom ) {\n\t\t\taddRow( [exportInfo.messageBottom], rowPos );\n\t\t\tmergeCells( rowPos, data.header.length-1 );\n\t\t}\n\n\t\t// Set column widths\n\t\tvar cols = _createNode( rels, 'cols' );\n\t\t$('worksheet', rels).prepend( cols );\n\n\t\tfor ( var i=0, ien=data.header.length ; i<ien ; i++ ) {\n\t\t\tcols.appendChild( _createNode( rels, 'col', {\n\t\t\t\tattr: {\n\t\t\t\t\tmin: i+1,\n\t\t\t\t\tmax: i+1,\n\t\t\t\t\twidth: _excelColWidth( data, i ),\n\t\t\t\t\tcustomWidth: 1\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\t// Let the developer customise the document if they want to\n\t\tif ( config.customize ) {\n\t\t\tconfig.customize( xlsx, config, dt );\n\t\t}\n\n\t\t_xlsxToStrings( xlsx );\n\n\t\tflash.setAction( 'excel' );\n\t\tflash.setFileName( exportInfo.filename );\n\t\tflash.setSheetData( xlsx );\n\t\t_setText( flash, '' );\n\n\t\tthis.processing( false );\n\t},\n\n\textension: '.xlsx',\n\t\n\tcreateEmptyCells: false\n} );\n\n\n\n// PDF export\nDataTable.ext.buttons.pdfFlash = $.extend( {}, flashButton, {\n\tclassName: 'buttons-pdf buttons-flash',\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.pdf', 'PDF' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\tthis.processing( true );\n\n\t\t// Set the text\n\t\tvar flash = config._flash;\n\t\tvar data = dt.buttons.exportData( config.exportOptions );\n\t\tvar info = dt.buttons.exportInfo( config );\n\t\tvar totalWidth = dt.table().node().offsetWidth;\n\n\t\t// Calculate the column width ratios for layout of the table in the PDF\n\t\tvar ratios = dt.columns( config.columns ).indexes().map( function ( idx ) {\n\t\t\treturn dt.column( idx ).header().offsetWidth / totalWidth;\n\t\t} );\n\n\t\tflash.setAction( 'pdf' );\n\t\tflash.setFileName( info.filename );\n\n\t\t_setText( flash, JSON.stringify( {\n\t\t\ttitle:         info.title || '',\n\t\t\tmessageTop:    info.messageTop || '',\n\t\t\tmessageBottom: info.messageBottom || '',\n\t\t\tcolWidth:      ratios.toArray(),\n\t\t\torientation:   config.orientation,\n\t\t\tsize:          config.pageSize,\n\t\t\theader:        config.header ? data.header : null,\n\t\t\tfooter:        config.footer ? data.footer : null,\n\t\t\tbody:          data.body\n\t\t} ) );\n\n\t\tthis.processing( false );\n\t},\n\n\textension: '.pdf',\n\n\torientation: 'portrait',\n\n\tpageSize: 'A4',\n\n\tnewline: '\\n'\n} );\n\n\nreturn DataTable.Buttons;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/js/buttons.foundation.js",
    "content": "/*! Foundation integration for DataTables' Buttons\n * ©2016 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-zf', 'datatables.net-buttons'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-zf')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Buttons ) {\n\t\t\t\trequire('datatables.net-buttons')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n// F6 has different requirements for the dropdown button set. We can use the\n// Foundation version found by DataTables in order to support both F5 and F6 in\n// the same file, but not that this requires DataTables 1.10.11+ for F6 support.\nvar collection = DataTable.ext.foundationVersion === 6 ?\n\t{\n\t\ttag: 'div',\n\t\tclassName: 'dt-button-collection dropdown-pane is-open button-group stacked'\n\t} :\n\t{\n\t\ttag: 'ul',\n\t\tclassName: 'dt-button-collection f-dropdown open dropdown-pane is-open',\n\t\tbutton: {\n\t\t\ttag: 'li',\n\t\t\tclassName: 'small',\n\t\t\tactive: 'active',\n\t\t\tdisabled: 'disabled'\n\t\t},\n\t\tbuttonLiner: {\n\t\t\ttag: 'a'\n\t\t}\n\t};\n\n$.extend( true, DataTable.Buttons.defaults, {\n\tdom: {\n\t\tcontainer: {\n\t\t\ttag: 'div',\n\t\t\tclassName: 'dt-buttons button-group'\n\t\t},\n\t\tbuttonContainer: {\n\t\t\ttag: null,\n\t\t\tclassName: ''\n\t\t},\n\t\tbutton: {\n\t\t\ttag: 'a',\n\t\t\tclassName: 'button small',\n\t\t\tactive: 'secondary'\n\t\t},\n\t\tbuttonLiner: {\n\t\t\ttag: null\n\t\t},\n\t\tcollection: collection\n\t}\n} );\n\n\nDataTable.ext.buttons.collection.className = 'buttons-collection dropdown';\n\n\nreturn DataTable.Buttons;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/js/buttons.html5.js",
    "content": "/*!\n * HTML5 export buttons for Buttons and DataTables.\n * 2016 SpryMedia Ltd - datatables.net/license\n *\n * FileSaver.js (1.3.3) - MIT license\n * Copyright © 2016 Eli Grey - http://eligrey.com\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $, jszip, pdfmake) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Buttons ) {\n\t\t\t\trequire('datatables.net-buttons')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document, jszip, pdfmake );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, jszip, pdfmake, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n// Allow the constructor to pass in JSZip and PDFMake from external requires.\n// Otherwise, use globally defined variables, if they are available.\nfunction _jsZip () {\n\treturn jszip || window.JSZip;\n}\nfunction _pdfMake () {\n\treturn pdfmake || window.pdfMake;\n}\n\nDataTable.Buttons.pdfMake = function (_) {\n\tif ( ! _ ) {\n\t\treturn _pdfMake();\n\t}\n\tpdfmake = m_ake;\n}\n\nDataTable.Buttons.jszip = function (_) {\n\tif ( ! _ ) {\n\t\treturn _jsZip();\n\t}\n\tjszip = _;\n}\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * FileSaver.js dependency\n */\n\n/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */\n\nvar _saveAs = (function(view) {\n\t\"use strict\";\n\t// IE <10 is explicitly unsupported\n\tif (typeof view === \"undefined\" || typeof navigator !== \"undefined\" && /MSIE [1-9]\\./.test(navigator.userAgent)) {\n\t\treturn;\n\t}\n\tvar\n\t\t  doc = view.document\n\t\t  // only get URL when necessary in case Blob.js hasn't overridden it yet\n\t\t, get_URL = function() {\n\t\t\treturn view.URL || view.webkitURL || view;\n\t\t}\n\t\t, save_link = doc.createElementNS(\"http://www.w3.org/1999/xhtml\", \"a\")\n\t\t, can_use_save_link = \"download\" in save_link\n\t\t, click = function(node) {\n\t\t\tvar event = new MouseEvent(\"click\");\n\t\t\tnode.dispatchEvent(event);\n\t\t}\n\t\t, is_safari = /constructor/i.test(view.HTMLElement) || view.safari\n\t\t, is_chrome_ios =/CriOS\\/[\\d]+/.test(navigator.userAgent)\n\t\t, throw_outside = function(ex) {\n\t\t\t(view.setImmediate || view.setTimeout)(function() {\n\t\t\t\tthrow ex;\n\t\t\t}, 0);\n\t\t}\n\t\t, force_saveable_type = \"application/octet-stream\"\n\t\t// the Blob API is fundamentally broken as there is no \"downloadfinished\" event to subscribe to\n\t\t, arbitrary_revoke_timeout = 1000 * 40 // in ms\n\t\t, revoke = function(file) {\n\t\t\tvar revoker = function() {\n\t\t\t\tif (typeof file === \"string\") { // file is an object URL\n\t\t\t\t\tget_URL().revokeObjectURL(file);\n\t\t\t\t} else { // file is a File\n\t\t\t\t\tfile.remove();\n\t\t\t\t}\n\t\t\t};\n\t\t\tsetTimeout(revoker, arbitrary_revoke_timeout);\n\t\t}\n\t\t, dispatch = function(filesaver, event_types, event) {\n\t\t\tevent_types = [].concat(event_types);\n\t\t\tvar i = event_types.length;\n\t\t\twhile (i--) {\n\t\t\t\tvar listener = filesaver[\"on\" + event_types[i]];\n\t\t\t\tif (typeof listener === \"function\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tlistener.call(filesaver, event || filesaver);\n\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\tthrow_outside(ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t, auto_bom = function(blob) {\n\t\t\t// prepend BOM for UTF-8 XML and text/* types (including HTML)\n\t\t\t// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF\n\t\t\tif (/^\\s*(?:text\\/\\S*|application\\/xml|\\S*\\/\\S*\\+xml)\\s*;.*charset\\s*=\\s*utf-8/i.test(blob.type)) {\n\t\t\t\treturn new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});\n\t\t\t}\n\t\t\treturn blob;\n\t\t}\n\t\t, FileSaver = function(blob, name, no_auto_bom) {\n\t\t\tif (!no_auto_bom) {\n\t\t\t\tblob = auto_bom(blob);\n\t\t\t}\n\t\t\t// First try a.download, then web filesystem, then object URLs\n\t\t\tvar\n\t\t\t\t  filesaver = this\n\t\t\t\t, type = blob.type\n\t\t\t\t, force = type === force_saveable_type\n\t\t\t\t, object_url\n\t\t\t\t, dispatch_all = function() {\n\t\t\t\t\tdispatch(filesaver, \"writestart progress write writeend\".split(\" \"));\n\t\t\t\t}\n\t\t\t\t// on any filesys errors revert to saving with object URLs\n\t\t\t\t, fs_error = function() {\n\t\t\t\t\tif ((is_chrome_ios || (force && is_safari)) && view.FileReader) {\n\t\t\t\t\t\t// Safari doesn't allow downloading of blob urls\n\t\t\t\t\t\tvar reader = new FileReader();\n\t\t\t\t\t\treader.onloadend = function() {\n\t\t\t\t\t\t\tvar url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');\n\t\t\t\t\t\t\tvar popup = view.open(url, '_blank');\n\t\t\t\t\t\t\tif(!popup) view.location.href = url;\n\t\t\t\t\t\t\turl=undefined; // release reference before dispatching\n\t\t\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t\t\t\tdispatch_all();\n\t\t\t\t\t\t};\n\t\t\t\t\t\treader.readAsDataURL(blob);\n\t\t\t\t\t\tfilesaver.readyState = filesaver.INIT;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// don't create more object URLs than needed\n\t\t\t\t\tif (!object_url) {\n\t\t\t\t\t\tobject_url = get_URL().createObjectURL(blob);\n\t\t\t\t\t}\n\t\t\t\t\tif (force) {\n\t\t\t\t\t\tview.location.href = object_url;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar opened = view.open(object_url, \"_blank\");\n\t\t\t\t\t\tif (!opened) {\n\t\t\t\t\t\t\t// Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html\n\t\t\t\t\t\t\tview.location.href = object_url;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t\tdispatch_all();\n\t\t\t\t\trevoke(object_url);\n\t\t\t\t}\n\t\t\t;\n\t\t\tfilesaver.readyState = filesaver.INIT;\n\n\t\t\tif (can_use_save_link) {\n\t\t\t\tobject_url = get_URL().createObjectURL(blob);\n\t\t\t\tsetTimeout(function() {\n\t\t\t\t\tsave_link.href = object_url;\n\t\t\t\t\tsave_link.download = name;\n\t\t\t\t\tclick(save_link);\n\t\t\t\t\tdispatch_all();\n\t\t\t\t\trevoke(object_url);\n\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfs_error();\n\t\t}\n\t\t, FS_proto = FileSaver.prototype\n\t\t, saveAs = function(blob, name, no_auto_bom) {\n\t\t\treturn new FileSaver(blob, name || blob.name || \"download\", no_auto_bom);\n\t\t}\n\t;\n\t// IE 10+ (native saveAs)\n\tif (typeof navigator !== \"undefined\" && navigator.msSaveOrOpenBlob) {\n\t\treturn function(blob, name, no_auto_bom) {\n\t\t\tname = name || blob.name || \"download\";\n\n\t\t\tif (!no_auto_bom) {\n\t\t\t\tblob = auto_bom(blob);\n\t\t\t}\n\t\t\treturn navigator.msSaveOrOpenBlob(blob, name);\n\t\t};\n\t}\n\n\tFS_proto.abort = function(){};\n\tFS_proto.readyState = FS_proto.INIT = 0;\n\tFS_proto.WRITING = 1;\n\tFS_proto.DONE = 2;\n\n\tFS_proto.error =\n\tFS_proto.onwritestart =\n\tFS_proto.onprogress =\n\tFS_proto.onwrite =\n\tFS_proto.onabort =\n\tFS_proto.onerror =\n\tFS_proto.onwriteend =\n\t\tnull;\n\n\treturn saveAs;\n}(\n\t   typeof self !== \"undefined\" && self\n\t|| typeof window !== \"undefined\" && window\n\t|| this.content\n));\n\n\n// Expose file saver on the DataTables API. Can't attach to `DataTables.Buttons`\n// since this file can be loaded before Button's core!\nDataTable.fileSave = _saveAs;\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Local (private) functions\n */\n\n/**\n * Get the sheet name for Excel exports.\n *\n * @param {object}\tconfig Button configuration\n */\nvar _sheetname = function ( config )\n{\n\tvar sheetName = 'Sheet1';\n\n\tif ( config.sheetName ) {\n\t\tsheetName = config.sheetName.replace(/[\\[\\]\\*\\/\\\\\\?\\:]/g, '');\n\t}\n\n\treturn sheetName;\n};\n\n/**\n * Get the newline character(s)\n *\n * @param {object}\tconfig Button configuration\n * @return {string}\t\t\t\tNewline character\n */\nvar _newLine = function ( config )\n{\n\treturn config.newline ?\n\t\tconfig.newline :\n\t\tnavigator.userAgent.match(/Windows/) ?\n\t\t\t'\\r\\n' :\n\t\t\t'\\n';\n};\n\n/**\n * Combine the data from the `buttons.exportData` method into a string that\n * will be used in the export file.\n *\n * @param\t{DataTable.Api} dt\t\t DataTables API instance\n * @param\t{object}\t\t\t\tconfig Button configuration\n * @return {object}\t\t\t\t\t\t\t The data to export\n */\nvar _exportData = function ( dt, config )\n{\n\tvar newLine = _newLine( config );\n\tvar data = dt.buttons.exportData( config.exportOptions );\n\tvar boundary = config.fieldBoundary;\n\tvar separator = config.fieldSeparator;\n\tvar reBoundary = new RegExp( boundary, 'g' );\n\tvar escapeChar = config.escapeChar !== undefined ?\n\t\tconfig.escapeChar :\n\t\t'\\\\';\n\tvar join = function ( a ) {\n\t\tvar s = '';\n\n\t\t// If there is a field boundary, then we might need to escape it in\n\t\t// the source data\n\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\tif ( i > 0 ) {\n\t\t\t\ts += separator;\n\t\t\t}\n\n\t\t\ts += boundary ?\n\t\t\t\tboundary + ('' + a[i]).replace( reBoundary, escapeChar+boundary ) + boundary :\n\t\t\t\ta[i];\n\t\t}\n\n\t\treturn s;\n\t};\n\n\tvar header = config.header ? join( data.header )+newLine : '';\n\tvar footer = config.footer && data.footer ? newLine+join( data.footer ) : '';\n\tvar body = [];\n\n\tfor ( var i=0, ien=data.body.length ; i<ien ; i++ ) {\n\t\tbody.push( join( data.body[i] ) );\n\t}\n\n\treturn {\n\t\tstr: header + body.join( newLine ) + footer,\n\t\trows: body.length\n\t};\n};\n\n/**\n * Older versions of Safari (prior to tech preview 18) don't support the\n * download option required.\n *\n * @return {Boolean} `true` if old Safari\n */\nvar _isDuffSafari = function ()\n{\n\tvar safari = navigator.userAgent.indexOf('Safari') !== -1 &&\n\t\tnavigator.userAgent.indexOf('Chrome') === -1 &&\n\t\tnavigator.userAgent.indexOf('Opera') === -1;\n\n\tif ( ! safari ) {\n\t\treturn false;\n\t}\n\n\tvar version = navigator.userAgent.match( /AppleWebKit\\/(\\d+\\.\\d+)/ );\n\tif ( version && version.length > 1 && version[1]*1 < 603.1 ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\n/**\n * Convert from numeric position to letter for column names in Excel\n * @param  {int} n Column number\n * @return {string} Column letter(s) name\n */\nfunction createCellPos( n ){\n\tvar ordA = 'A'.charCodeAt(0);\n\tvar ordZ = 'Z'.charCodeAt(0);\n\tvar len = ordZ - ordA + 1;\n\tvar s = \"\";\n\n\twhile( n >= 0 ) {\n\t\ts = String.fromCharCode(n % len + ordA) + s;\n\t\tn = Math.floor(n / len) - 1;\n\t}\n\n\treturn s;\n}\n\ntry {\n\tvar _serialiser = new XMLSerializer();\n\tvar _ieExcel;\n}\ncatch (t) {}\n\n/**\n * Recursively add XML files from an object's structure to a ZIP file. This\n * allows the XSLX file to be easily defined with an object's structure matching\n * the files structure.\n *\n * @param {JSZip} zip ZIP package\n * @param {object} obj Object to add (recursive)\n */\nfunction _addToZip( zip, obj ) {\n\tif ( _ieExcel === undefined ) {\n\t\t// Detect if we are dealing with IE's _awful_ serialiser by seeing if it\n\t\t// drop attributes\n\t\t_ieExcel = _serialiser\n\t\t\t.serializeToString(\n\t\t\t\t$.parseXML( excelStrings['xl/worksheets/sheet1.xml'] )\n\t\t\t)\n\t\t\t.indexOf( 'xmlns:r' ) === -1;\n\t}\n\n\t$.each( obj, function ( name, val ) {\n\t\tif ( $.isPlainObject( val ) ) {\n\t\t\tvar newDir = zip.folder( name );\n\t\t\t_addToZip( newDir, val );\n\t\t}\n\t\telse {\n\t\t\tif ( _ieExcel ) {\n\t\t\t\t// IE's XML serialiser will drop some name space attributes from\n\t\t\t\t// from the root node, so we need to save them. Do this by\n\t\t\t\t// replacing the namespace nodes with a regular attribute that\n\t\t\t\t// we convert back when serialised. Edge does not have this\n\t\t\t\t// issue\n\t\t\t\tvar worksheet = val.childNodes[0];\n\t\t\t\tvar i, ien;\n\t\t\t\tvar attrs = [];\n\n\t\t\t\tfor ( i=worksheet.attributes.length-1 ; i>=0 ; i-- ) {\n\t\t\t\t\tvar attrName = worksheet.attributes[i].nodeName;\n\t\t\t\t\tvar attrValue = worksheet.attributes[i].nodeValue;\n\n\t\t\t\t\tif ( attrName.indexOf( ':' ) !== -1 ) {\n\t\t\t\t\t\tattrs.push( { name: attrName, value: attrValue } );\n\n\t\t\t\t\t\tworksheet.removeAttribute( attrName );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor ( i=0, ien=attrs.length ; i<ien ; i++ ) {\n\t\t\t\t\tvar attr = val.createAttribute( attrs[i].name.replace( ':', '_dt_b_namespace_token_' ) );\n\t\t\t\t\tattr.value = attrs[i].value;\n\t\t\t\t\tworksheet.setAttributeNode( attr );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar str = _serialiser.serializeToString(val);\n\n\t\t\t// Fix IE's XML\n\t\t\tif ( _ieExcel ) {\n\t\t\t\t// IE doesn't include the XML declaration\n\t\t\t\tif ( str.indexOf( '<?xml' ) === -1 ) {\n\t\t\t\t\tstr = '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+str;\n\t\t\t\t}\n\n\t\t\t\t// Return namespace attributes to being as such\n\t\t\t\tstr = str.replace( /_dt_b_namespace_token_/g, ':' );\n\n\t\t\t\t// Remove testing name space that IE puts into the space preserve attr\n\t\t\t\tstr = str.replace( /xmlns:NS[\\d]+=\"\" NS[\\d]+:/g, '' );\n\t\t\t}\n\n\t\t\t// Safari, IE and Edge will put empty name space attributes onto\n\t\t\t// various elements making them useless. This strips them out\n\t\t\tstr = str.replace( /<([^<>]*?) xmlns=\"\"([^<>]*?)>/g, '<$1 $2>' );\n\n\t\t\tzip.file( name, str );\n\t\t}\n\t} );\n}\n\n/**\n * Create an XML node and add any children, attributes, etc without needing to\n * be verbose in the DOM.\n *\n * @param  {object} doc      XML document\n * @param  {string} nodeName Node name\n * @param  {object} opts     Options - can be `attr` (attributes), `children`\n *   (child nodes) and `text` (text content)\n * @return {node}            Created node\n */\nfunction _createNode( doc, nodeName, opts ) {\n\tvar tempNode = doc.createElement( nodeName );\n\n\tif ( opts ) {\n\t\tif ( opts.attr ) {\n\t\t\t$(tempNode).attr( opts.attr );\n\t\t}\n\n\t\tif ( opts.children ) {\n\t\t\t$.each( opts.children, function ( key, value ) {\n\t\t\t\ttempNode.appendChild( value );\n\t\t\t} );\n\t\t}\n\n\t\tif ( opts.text !== null && opts.text !== undefined ) {\n\t\t\ttempNode.appendChild( doc.createTextNode( opts.text ) );\n\t\t}\n\t}\n\n\treturn tempNode;\n}\n\n/**\n * Get the width for an Excel column based on the contents of that column\n * @param  {object} data Data for export\n * @param  {int}    col  Column index\n * @return {int}         Column width\n */\nfunction _excelColWidth( data, col ) {\n\tvar max = data.header[col].length;\n\tvar len, lineSplit, str;\n\n\tif ( data.footer && data.footer[col].length > max ) {\n\t\tmax = data.footer[col].length;\n\t}\n\n\tfor ( var i=0, ien=data.body.length ; i<ien ; i++ ) {\n\t\tvar point = data.body[i][col];\n\t\tstr = point !== null && point !== undefined ?\n\t\t\tpoint.toString() :\n\t\t\t'';\n\n\t\t// If there is a newline character, workout the width of the column\n\t\t// based on the longest line in the string\n\t\tif ( str.indexOf('\\n') !== -1 ) {\n\t\t\tlineSplit = str.split('\\n');\n\t\t\tlineSplit.sort( function (a, b) {\n\t\t\t\treturn b.length - a.length;\n\t\t\t} );\n\n\t\t\tlen = lineSplit[0].length;\n\t\t}\n\t\telse {\n\t\t\tlen = str.length;\n\t\t}\n\n\t\tif ( len > max ) {\n\t\t\tmax = len;\n\t\t}\n\n\t\t// Max width rather than having potentially massive column widths\n\t\tif ( max > 40 ) {\n\t\t\treturn 54; // 40 * 1.35\n\t\t}\n\t}\n\n\tmax *= 1.35;\n\n\t// And a min width\n\treturn max > 6 ? max : 6;\n}\n\n// Excel - Pre-defined strings to build a basic XLSX file\nvar excelStrings = {\n\t\"_rels/.rels\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">'+\n\t\t\t'<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"xl/workbook.xml\"/>'+\n\t\t'</Relationships>',\n\n\t\"xl/_rels/workbook.xml.rels\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">'+\n\t\t\t'<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\" Target=\"worksheets/sheet1.xml\"/>'+\n\t\t\t'<Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>'+\n\t\t'</Relationships>',\n\n\t\"[Content_Types].xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">'+\n\t\t\t'<Default Extension=\"xml\" ContentType=\"application/xml\" />'+\n\t\t\t'<Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\" />'+\n\t\t\t'<Default Extension=\"jpeg\" ContentType=\"image/jpeg\" />'+\n\t\t\t'<Override PartName=\"/xl/workbook.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\" />'+\n\t\t\t'<Override PartName=\"/xl/worksheets/sheet1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\" />'+\n\t\t\t'<Override PartName=\"/xl/styles.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\" />'+\n\t\t'</Types>',\n\n\t\"xl/workbook.xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">'+\n\t\t\t'<fileVersion appName=\"xl\" lastEdited=\"5\" lowestEdited=\"5\" rupBuild=\"24816\"/>'+\n\t\t\t'<workbookPr showInkAnnotation=\"0\" autoCompressPictures=\"0\"/>'+\n\t\t\t'<bookViews>'+\n\t\t\t\t'<workbookView xWindow=\"0\" yWindow=\"0\" windowWidth=\"25600\" windowHeight=\"19020\" tabRatio=\"500\"/>'+\n\t\t\t'</bookViews>'+\n\t\t\t'<sheets>'+\n\t\t\t\t'<sheet name=\"Sheet1\" sheetId=\"1\" r:id=\"rId1\"/>'+\n\t\t\t'</sheets>'+\n\t\t\t'<definedNames/>'+\n\t\t'</workbook>',\n\n\t\"xl/worksheets/sheet1.xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" mc:Ignorable=\"x14ac\" xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\">'+\n\t\t\t'<sheetData/>'+\n\t\t\t'<mergeCells count=\"0\"/>'+\n\t\t'</worksheet>',\n\n\t\"xl/styles.xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\"?>'+\n\t\t'<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" mc:Ignorable=\"x14ac\" xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\">'+\n\t\t\t'<numFmts count=\"6\">'+\n\t\t\t\t'<numFmt numFmtId=\"164\" formatCode=\"#,##0.00_-\\ [$$-45C]\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"165\" formatCode=\"&quot;£&quot;#,##0.00\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"166\" formatCode=\"[$€-2]\\ #,##0.00\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"167\" formatCode=\"0.0%\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"168\" formatCode=\"#,##0;(#,##0)\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"169\" formatCode=\"#,##0.00;(#,##0.00)\"/>'+\n\t\t\t'</numFmts>'+\n\t\t\t'<fonts count=\"5\" x14ac:knownFonts=\"1\">'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<color rgb=\"FFFFFFFF\" />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<b />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<i />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<u />'+\n\t\t\t\t'</font>'+\n\t\t\t'</fonts>'+\n\t\t\t'<fills count=\"6\">'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"none\" />'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+ // Excel appears to use this as a dotted background regardless of values but\n\t\t\t\t\t'<patternFill patternType=\"none\" />'+ // to be valid to the schema, use a patternFill\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"FFD9D9D9\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"FFD99795\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"ffc6efce\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"ffc6cfef\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t'</fills>'+\n\t\t\t'<borders count=\"2\">'+\n\t\t\t\t'<border>'+\n\t\t\t\t\t'<left />'+\n\t\t\t\t\t'<right />'+\n\t\t\t\t\t'<top />'+\n\t\t\t\t\t'<bottom />'+\n\t\t\t\t\t'<diagonal />'+\n\t\t\t\t'</border>'+\n\t\t\t\t'<border diagonalUp=\"false\" diagonalDown=\"false\">'+\n\t\t\t\t\t'<left style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</left>'+\n\t\t\t\t\t'<right style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</right>'+\n\t\t\t\t\t'<top style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</top>'+\n\t\t\t\t\t'<bottom style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</bottom>'+\n\t\t\t\t\t'<diagonal />'+\n\t\t\t\t'</border>'+\n\t\t\t'</borders>'+\n\t\t\t'<cellStyleXfs count=\"1\">'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" />'+\n\t\t\t'</cellStyleXfs>'+\n\t\t\t'<cellXfs count=\"67\">'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"left\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"center\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"right\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"fill\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment textRotation=\"90\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment wrapText=\"1\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"9\"   fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"164\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"165\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"166\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"167\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"168\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"169\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"3\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"4\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"1\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"2\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t'</cellXfs>'+\n\t\t\t'<cellStyles count=\"1\">'+\n\t\t\t\t'<cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\" />'+\n\t\t\t'</cellStyles>'+\n\t\t\t'<dxfs count=\"0\" />'+\n\t\t\t'<tableStyles count=\"0\" defaultTableStyle=\"TableStyleMedium9\" defaultPivotStyle=\"PivotStyleMedium4\" />'+\n\t\t'</styleSheet>'\n};\n// Note we could use 3 `for` loops for the styles, but when gzipped there is\n// virtually no difference in size, since the above can be easily compressed\n\n// Pattern matching for special number formats. Perhaps this should be exposed\n// via an API in future?\n// Ref: section 3.8.30 - built in formatters in open spreadsheet\n//   https://www.ecma-international.org/news/TC45_current_work/Office%20Open%20XML%20Part%204%20-%20Markup%20Language%20Reference.pdf\nvar _excelSpecials = [\n\t{ match: /^\\-?\\d+\\.\\d%$/,       style: 60, fmt: function (d) { return d/100; } }, // Precent with d.p.\n\t{ match: /^\\-?\\d+\\.?\\d*%$/,     style: 56, fmt: function (d) { return d/100; } }, // Percent\n\t{ match: /^\\-?\\$[\\d,]+.?\\d*$/,  style: 57 }, // Dollars\n\t{ match: /^\\-?£[\\d,]+.?\\d*$/,   style: 58 }, // Pounds\n\t{ match: /^\\-?€[\\d,]+.?\\d*$/,   style: 59 }, // Euros\n\t{ match: /^\\-?\\d+$/,            style: 65 }, // Numbers without thousand separators\n\t{ match: /^\\-?\\d+\\.\\d{2}$/,     style: 66 }, // Numbers 2 d.p. without thousands separators\n\t{ match: /^\\([\\d,]+\\)$/,        style: 61, fmt: function (d) { return -1 * d.replace(/[\\(\\)]/g, ''); } },  // Negative numbers indicated by brackets\n\t{ match: /^\\([\\d,]+\\.\\d{2}\\)$/, style: 62, fmt: function (d) { return -1 * d.replace(/[\\(\\)]/g, ''); } },  // Negative numbers indicated by brackets - 2d.p.\n\t{ match: /^\\-?[\\d,]+$/,         style: 63 }, // Numbers with thousand separators\n\t{ match: /^\\-?[\\d,]+\\.\\d{2}$/,  style: 64 }  // Numbers with 2 d.p. and thousands separators\n];\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Buttons\n */\n\n//\n// Copy to clipboard\n//\nDataTable.ext.buttons.copyHtml5 = {\n\tclassName: 'buttons-copy buttons-html5',\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.copy', 'Copy' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\tthis.processing( true );\n\n\t\tvar that = this;\n\t\tvar exportData = _exportData( dt, config );\n\t\tvar info = dt.buttons.exportInfo( config );\n\t\tvar newline = _newLine(config);\n\t\tvar output = exportData.str;\n\t\tvar hiddenDiv = $('<div/>')\n\t\t\t.css( {\n\t\t\t\theight: 1,\n\t\t\t\twidth: 1,\n\t\t\t\toverflow: 'hidden',\n\t\t\t\tposition: 'fixed',\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0\n\t\t\t} );\n\n\t\tif ( info.title ) {\n\t\t\toutput = info.title + newline + newline + output;\n\t\t}\n\n\t\tif ( info.messageTop ) {\n\t\t\toutput = info.messageTop + newline + newline + output;\n\t\t}\n\n\t\tif ( info.messageBottom ) {\n\t\t\toutput = output + newline + newline + info.messageBottom;\n\t\t}\n\n\t\tif ( config.customize ) {\n\t\t\toutput = config.customize( output, config, dt );\n\t\t}\n\n\t\tvar textarea = $('<textarea readonly/>')\n\t\t\t.val( output )\n\t\t\t.appendTo( hiddenDiv );\n\n\t\t// For browsers that support the copy execCommand, try to use it\n\t\tif ( document.queryCommandSupported('copy') ) {\n\t\t\thiddenDiv.appendTo( dt.table().container() );\n\t\t\ttextarea[0].focus();\n\t\t\ttextarea[0].select();\n\n\t\t\ttry {\n\t\t\t\tvar successful = document.execCommand( 'copy' );\n\t\t\t\thiddenDiv.remove();\n\n\t\t\t\tif (successful) {\n\t\t\t\t\tdt.buttons.info(\n\t\t\t\t\t\tdt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),\n\t\t\t\t\t\tdt.i18n( 'buttons.copySuccess', {\n\t\t\t\t\t\t\t1: 'Copied one row to clipboard',\n\t\t\t\t\t\t\t_: 'Copied %d rows to clipboard'\n\t\t\t\t\t\t}, exportData.rows ),\n\t\t\t\t\t\t2000\n\t\t\t\t\t);\n\n\t\t\t\t\tthis.processing( false );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (t) {}\n\t\t}\n\n\t\t// Otherwise we show the text box and instruct the user to use it\n\t\tvar message = $('<span>'+dt.i18n( 'buttons.copyKeys',\n\t\t\t\t'Press <i>ctrl</i> or <i>\\u2318</i> + <i>C</i> to copy the table data<br>to your system clipboard.<br><br>'+\n\t\t\t\t'To cancel, click this message or press escape.' )+'</span>'\n\t\t\t)\n\t\t\t.append( hiddenDiv );\n\n\t\tdt.buttons.info( dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ), message, 0 );\n\n\t\t// Select the text so when the user activates their system clipboard\n\t\t// it will copy that text\n\t\ttextarea[0].focus();\n\t\ttextarea[0].select();\n\n\t\t// Event to hide the message when the user is done\n\t\tvar container = $(message).closest('.dt-button-info');\n\t\tvar close = function () {\n\t\t\tcontainer.off( 'click.buttons-copy' );\n\t\t\t$(document).off( '.buttons-copy' );\n\t\t\tdt.buttons.info( false );\n\t\t};\n\n\t\tcontainer.on( 'click.buttons-copy', close );\n\t\t$(document)\n\t\t\t.on( 'keydown.buttons-copy', function (e) {\n\t\t\t\tif ( e.keyCode === 27 ) { // esc\n\t\t\t\t\tclose();\n\t\t\t\t\tthat.processing( false );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'copy.buttons-copy cut.buttons-copy', function () {\n\t\t\t\tclose();\n\t\t\t\tthat.processing( false );\n\t\t\t} );\n\t},\n\n\texportOptions: {},\n\n\tfieldSeparator: '\\t',\n\n\tfieldBoundary: '',\n\n\theader: true,\n\n\tfooter: false,\n\n\ttitle: '*',\n\n\tmessageTop: '*',\n\n\tmessageBottom: '*'\n};\n\n//\n// CSV export\n//\nDataTable.ext.buttons.csvHtml5 = {\n\tbom: false,\n\n\tclassName: 'buttons-csv buttons-html5',\n\n\tavailable: function () {\n\t\treturn window.FileReader !== undefined && window.Blob;\n\t},\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.csv', 'CSV' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\tthis.processing( true );\n\n\t\t// Set the text\n\t\tvar output = _exportData( dt, config ).str;\n\t\tvar info = dt.buttons.exportInfo(config);\n\t\tvar charset = config.charset;\n\n\t\tif ( config.customize ) {\n\t\t\toutput = config.customize( output, config, dt );\n\t\t}\n\n\t\tif ( charset !== false ) {\n\t\t\tif ( ! charset ) {\n\t\t\t\tcharset = document.characterSet || document.charset;\n\t\t\t}\n\n\t\t\tif ( charset ) {\n\t\t\t\tcharset = ';charset='+charset;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tcharset = '';\n\t\t}\n\n\t\tif ( config.bom ) {\n\t\t\toutput = '\\ufeff' + output;\n\t\t}\n\n\t\t_saveAs(\n\t\t\tnew Blob( [output], {type: 'text/csv'+charset} ),\n\t\t\tinfo.filename,\n\t\t\ttrue\n\t\t);\n\n\t\tthis.processing( false );\n\t},\n\n\tfilename: '*',\n\n\textension: '.csv',\n\n\texportOptions: {},\n\n\tfieldSeparator: ',',\n\n\tfieldBoundary: '\"',\n\n\tescapeChar: '\"',\n\n\tcharset: null,\n\n\theader: true,\n\n\tfooter: false\n};\n\n//\n// Excel (xlsx) export\n//\nDataTable.ext.buttons.excelHtml5 = {\n\tclassName: 'buttons-excel buttons-html5',\n\n\tavailable: function () {\n\t\treturn window.FileReader !== undefined && _jsZip() !== undefined && ! _isDuffSafari() && _serialiser;\n\t},\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.excel', 'Excel' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\tthis.processing( true );\n\n\t\tvar that = this;\n\t\tvar rowPos = 0;\n\t\tvar dataStartRow, dataEndRow;\n\t\tvar getXml = function ( type ) {\n\t\t\tvar str = excelStrings[ type ];\n\n\t\t\t//str = str.replace( /xmlns:/g, 'xmlns_' ).replace( /mc:/g, 'mc_' );\n\n\t\t\treturn $.parseXML( str );\n\t\t};\n\t\tvar rels = getXml('xl/worksheets/sheet1.xml');\n\t\tvar relsGet = rels.getElementsByTagName( \"sheetData\" )[0];\n\n\t\tvar xlsx = {\n\t\t\t_rels: {\n\t\t\t\t\".rels\": getXml('_rels/.rels')\n\t\t\t},\n\t\t\txl: {\n\t\t\t\t_rels: {\n\t\t\t\t\t\"workbook.xml.rels\": getXml('xl/_rels/workbook.xml.rels')\n\t\t\t\t},\n\t\t\t\t\"workbook.xml\": getXml('xl/workbook.xml'),\n\t\t\t\t\"styles.xml\": getXml('xl/styles.xml'),\n\t\t\t\t\"worksheets\": {\n\t\t\t\t\t\"sheet1.xml\": rels\n\t\t\t\t}\n\n\t\t\t},\n\t\t\t\"[Content_Types].xml\": getXml('[Content_Types].xml')\n\t\t};\n\n\t\tvar data = dt.buttons.exportData( config.exportOptions );\n\t\tvar currentRow, rowNode;\n\t\tvar addRow = function ( row ) {\n\t\t\tcurrentRow = rowPos+1;\n\t\t\trowNode = _createNode( rels, \"row\", { attr: {r:currentRow} } );\n\n\t\t\tfor ( var i=0, ien=row.length ; i<ien ; i++ ) {\n\t\t\t\t// Concat both the Cell Columns as a letter and the Row of the cell.\n\t\t\t\tvar cellId = createCellPos(i) + '' + currentRow;\n\t\t\t\tvar cell = null;\n\n\t\t\t\t// For null, undefined of blank cell, continue so it doesn't create the _createNode\n\t\t\t\tif ( row[i] === null || row[i] === undefined || row[i] === '' ) {\n\t\t\t\t\tif ( config.createEmptyCells === true ) {\n\t\t\t\t\t\trow[i] = '';\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar originalContent = row[i];\n\t\t\t\trow[i] = $.trim( row[i] );\n\n\t\t\t\t// Special number formatting options\n\t\t\t\tfor ( var j=0, jen=_excelSpecials.length ; j<jen ; j++ ) {\n\t\t\t\t\tvar special = _excelSpecials[j];\n\n\t\t\t\t\t// TODO Need to provide the ability for the specials to say\n\t\t\t\t\t// if they are returning a string, since at the moment it is\n\t\t\t\t\t// assumed to be a number\n\t\t\t\t\tif ( row[i].match && ! row[i].match(/^0\\d+/) && row[i].match( special.match ) ) {\n\t\t\t\t\t\tvar val = row[i].replace(/[^\\d\\.\\-]/g, '');\n\n\t\t\t\t\t\tif ( special.fmt ) {\n\t\t\t\t\t\t\tval = special.fmt( val );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcell = _createNode( rels, 'c', {\n\t\t\t\t\t\t\tattr: {\n\t\t\t\t\t\t\t\tr: cellId,\n\t\t\t\t\t\t\t\ts: special.style\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren: [\n\t\t\t\t\t\t\t\t_createNode( rels, 'v', { text: val } )\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( ! cell ) {\n\t\t\t\t\tif ( typeof row[i] === 'number' || (\n\t\t\t\t\t\trow[i].match &&\n\t\t\t\t\t\trow[i].match(/^-?\\d+(\\.\\d+)?$/) &&\n\t\t\t\t\t\t! row[i].match(/^0\\d+/) )\n\t\t\t\t\t) {\n\t\t\t\t\t\t// Detect numbers - don't match numbers with leading zeros\n\t\t\t\t\t\t// or a negative anywhere but the start\n\t\t\t\t\t\tcell = _createNode( rels, 'c', {\n\t\t\t\t\t\t\tattr: {\n\t\t\t\t\t\t\t\tt: 'n',\n\t\t\t\t\t\t\t\tr: cellId\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren: [\n\t\t\t\t\t\t\t\t_createNode( rels, 'v', { text: row[i] } )\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// String output - replace non standard characters for text output\n\t\t\t\t\t\tvar text = ! originalContent.replace ?\n\t\t\t\t\t\t\toriginalContent :\n\t\t\t\t\t\t\toriginalContent.replace(/[\\x00-\\x09\\x0B\\x0C\\x0E-\\x1F\\x7F-\\x9F]/g, '');\n\n\t\t\t\t\t\tcell = _createNode( rels, 'c', {\n\t\t\t\t\t\t\tattr: {\n\t\t\t\t\t\t\t\tt: 'inlineStr',\n\t\t\t\t\t\t\t\tr: cellId\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren:{\n\t\t\t\t\t\t\t\trow: _createNode( rels, 'is', {\n\t\t\t\t\t\t\t\t\tchildren: {\n\t\t\t\t\t\t\t\t\t\trow: _createNode( rels, 't', {\n\t\t\t\t\t\t\t\t\t\t\ttext: text,\n\t\t\t\t\t\t\t\t\t\t\tattr: {\n\t\t\t\t\t\t\t\t\t\t\t\t'xml:space': 'preserve'\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\trowNode.appendChild( cell );\n\t\t\t}\n\n\t\t\trelsGet.appendChild(rowNode);\n\t\t\trowPos++;\n\t\t};\n\n\t\tif ( config.customizeData ) {\n\t\t\tconfig.customizeData( data );\n\t\t}\n\n\t\tvar mergeCells = function ( row, colspan ) {\n\t\t\tvar mergeCells = $('mergeCells', rels);\n\n\t\t\tmergeCells[0].appendChild( _createNode( rels, 'mergeCell', {\n\t\t\t\tattr: {\n\t\t\t\t\tref: 'A'+row+':'+createCellPos(colspan)+row\n\t\t\t\t}\n\t\t\t} ) );\n\t\t\tmergeCells.attr( 'count', parseFloat(mergeCells.attr( 'count' ))+1 );\n\t\t\t$('row:eq('+(row-1)+') c', rels).attr( 's', '51' ); // centre\n\t\t};\n\n\t\t// Title and top messages\n\t\tvar exportInfo = dt.buttons.exportInfo( config );\n\t\tif ( exportInfo.title ) {\n\t\t\taddRow( [exportInfo.title], rowPos );\n\t\t\tmergeCells( rowPos, data.header.length-1 );\n\t\t}\n\n\t\tif ( exportInfo.messageTop ) {\n\t\t\taddRow( [exportInfo.messageTop], rowPos );\n\t\t\tmergeCells( rowPos, data.header.length-1 );\n\t\t}\n\n\n\t\t// Table itself\n\t\tif ( config.header ) {\n\t\t\taddRow( data.header, rowPos );\n\t\t\t$('row:last c', rels).attr( 's', '2' ); // bold\n\t\t}\n\t\n\t\tdataStartRow = rowPos;\n\n\t\tfor ( var n=0, ie=data.body.length ; n<ie ; n++ ) {\n\t\t\taddRow( data.body[n], rowPos );\n\t\t}\n\t\n\t\tdataEndRow = rowPos;\n\n\t\tif ( config.footer && data.footer ) {\n\t\t\taddRow( data.footer, rowPos);\n\t\t\t$('row:last c', rels).attr( 's', '2' ); // bold\n\t\t}\n\n\t\t// Below the table\n\t\tif ( exportInfo.messageBottom ) {\n\t\t\taddRow( [exportInfo.messageBottom], rowPos );\n\t\t\tmergeCells( rowPos, data.header.length-1 );\n\t\t}\n\n\t\t// Set column widths\n\t\tvar cols = _createNode( rels, 'cols' );\n\t\t$('worksheet', rels).prepend( cols );\n\n\t\tfor ( var i=0, ien=data.header.length ; i<ien ; i++ ) {\n\t\t\tcols.appendChild( _createNode( rels, 'col', {\n\t\t\t\tattr: {\n\t\t\t\t\tmin: i+1,\n\t\t\t\t\tmax: i+1,\n\t\t\t\t\twidth: _excelColWidth( data, i ),\n\t\t\t\t\tcustomWidth: 1\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\t// Workbook modifications\n\t\tvar workbook = xlsx.xl['workbook.xml'];\n\n\t\t$( 'sheets sheet', workbook ).attr( 'name', _sheetname( config ) );\n\n\t\t// Auto filter for columns\n\t\tif ( config.autoFilter ) {\n\t\t\t$('mergeCells', rels).before( _createNode( rels, 'autoFilter', {\n\t\t\t\tattr: {\n\t\t\t\t\tref: 'A'+dataStartRow+':'+createCellPos(data.header.length-1)+dataEndRow\n\t\t\t\t}\n\t\t\t} ) );\n\n\t\t\t$('definedNames', workbook).append( _createNode( workbook, 'definedName', {\n\t\t\t\tattr: {\n\t\t\t\t\tname: '_xlnm._FilterDatabase',\n\t\t\t\t\tlocalSheetId: '0',\n\t\t\t\t\thidden: 1\n\t\t\t\t},\n\t\t\t\ttext: _sheetname(config)+'!$A$'+dataStartRow+':'+createCellPos(data.header.length-1)+dataEndRow\n\t\t\t} ) );\n\t\t}\n\n\t\t// Let the developer customise the document if they want to\n\t\tif ( config.customize ) {\n\t\t\tconfig.customize( xlsx, config, dt );\n\t\t}\n\n\t\t// Excel doesn't like an empty mergeCells tag\n\t\tif ( $('mergeCells', rels).children().length === 0 ) {\n\t\t\t$('mergeCells', rels).remove();\n\t\t}\n\n\t\tvar jszip = _jsZip();\n\t\tvar zip = new jszip();\n\t\tvar zipConfig = {\n\t\t\ttype: 'blob',\n\t\t\tmimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'\n\t\t};\n\n\t\t_addToZip( zip, xlsx );\n\n\t\tif ( zip.generateAsync ) {\n\t\t\t// JSZip 3+\n\t\t\tzip\n\t\t\t\t.generateAsync( zipConfig )\n\t\t\t\t.then( function ( blob ) {\n\t\t\t\t\t_saveAs( blob, exportInfo.filename );\n\t\t\t\t\tthat.processing( false );\n\t\t\t\t} );\n\t\t}\n\t\telse {\n\t\t\t// JSZip 2.5\n\t\t\t_saveAs(\n\t\t\t\tzip.generate( zipConfig ),\n\t\t\t\texportInfo.filename\n\t\t\t);\n\t\t\tthis.processing( false );\n\t\t}\n\t},\n\n\tfilename: '*',\n\n\textension: '.xlsx',\n\n\texportOptions: {},\n\n\theader: true,\n\n\tfooter: false,\n\n\ttitle: '*',\n\n\tmessageTop: '*',\n\n\tmessageBottom: '*',\n\n\tcreateEmptyCells: false,\n\n\tautoFilter: false,\n\n\tsheetName: ''\n};\n\n//\n// PDF export - using pdfMake - http://pdfmake.org\n//\nDataTable.ext.buttons.pdfHtml5 = {\n\tclassName: 'buttons-pdf buttons-html5',\n\n\tavailable: function () {\n\t\treturn window.FileReader !== undefined && _pdfMake();\n\t},\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.pdf', 'PDF' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\tthis.processing( true );\n\n\t\tvar that = this;\n\t\tvar data = dt.buttons.exportData( config.exportOptions );\n\t\tvar info = dt.buttons.exportInfo( config );\n\t\tvar rows = [];\n\n\t\tif ( config.header ) {\n\t\t\trows.push( $.map( data.header, function ( d ) {\n\t\t\t\treturn {\n\t\t\t\t\ttext: typeof d === 'string' ? d : d+'',\n\t\t\t\t\tstyle: 'tableHeader'\n\t\t\t\t};\n\t\t\t} ) );\n\t\t}\n\n\t\tfor ( var i=0, ien=data.body.length ; i<ien ; i++ ) {\n\t\t\trows.push( $.map( data.body[i], function ( d ) {\n\t\t\t\tif ( d === null || d === undefined ) {\n\t\t\t\t\td = '';\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\ttext: typeof d === 'string' ? d : d+'',\n\t\t\t\t\tstyle: i % 2 ? 'tableBodyEven' : 'tableBodyOdd'\n\t\t\t\t};\n\t\t\t} ) );\n\t\t}\n\n\t\tif ( config.footer && data.footer) {\n\t\t\trows.push( $.map( data.footer, function ( d ) {\n\t\t\t\treturn {\n\t\t\t\t\ttext: typeof d === 'string' ? d : d+'',\n\t\t\t\t\tstyle: 'tableFooter'\n\t\t\t\t};\n\t\t\t} ) );\n\t\t}\n\n\t\tvar doc = {\n\t\t\tpageSize: config.pageSize,\n\t\t\tpageOrientation: config.orientation,\n\t\t\tcontent: [\n\t\t\t\t{\n\t\t\t\t\ttable: {\n\t\t\t\t\t\theaderRows: 1,\n\t\t\t\t\t\tbody: rows\n\t\t\t\t\t},\n\t\t\t\t\tlayout: 'noBorders'\n\t\t\t\t}\n\t\t\t],\n\t\t\tstyles: {\n\t\t\t\ttableHeader: {\n\t\t\t\t\tbold: true,\n\t\t\t\t\tfontSize: 11,\n\t\t\t\t\tcolor: 'white',\n\t\t\t\t\tfillColor: '#2d4154',\n\t\t\t\t\talignment: 'center'\n\t\t\t\t},\n\t\t\t\ttableBodyEven: {},\n\t\t\t\ttableBodyOdd: {\n\t\t\t\t\tfillColor: '#f3f3f3'\n\t\t\t\t},\n\t\t\t\ttableFooter: {\n\t\t\t\t\tbold: true,\n\t\t\t\t\tfontSize: 11,\n\t\t\t\t\tcolor: 'white',\n\t\t\t\t\tfillColor: '#2d4154'\n\t\t\t\t},\n\t\t\t\ttitle: {\n\t\t\t\t\talignment: 'center',\n\t\t\t\t\tfontSize: 15\n\t\t\t\t},\n\t\t\t\tmessage: {}\n\t\t\t},\n\t\t\tdefaultStyle: {\n\t\t\t\tfontSize: 10\n\t\t\t}\n\t\t};\n\n\t\tif ( info.messageTop ) {\n\t\t\tdoc.content.unshift( {\n\t\t\t\ttext: info.messageTop,\n\t\t\t\tstyle: 'message',\n\t\t\t\tmargin: [ 0, 0, 0, 12 ]\n\t\t\t} );\n\t\t}\n\n\t\tif ( info.messageBottom ) {\n\t\t\tdoc.content.push( {\n\t\t\t\ttext: info.messageBottom,\n\t\t\t\tstyle: 'message',\n\t\t\t\tmargin: [ 0, 0, 0, 12 ]\n\t\t\t} );\n\t\t}\n\n\t\tif ( info.title ) {\n\t\t\tdoc.content.unshift( {\n\t\t\t\ttext: info.title,\n\t\t\t\tstyle: 'title',\n\t\t\t\tmargin: [ 0, 0, 0, 12 ]\n\t\t\t} );\n\t\t}\n\n\t\tif ( config.customize ) {\n\t\t\tconfig.customize( doc, config, dt );\n\t\t}\n\n\t\tvar pdf = _pdfMake().createPdf( doc );\n\n\t\tif ( config.download === 'open' && ! _isDuffSafari() ) {\n\t\t\tpdf.open();\n\t\t}\n\t\telse {\n\t\t\tpdf.download( info.filename );\n\t\t}\n\n\t\tthis.processing( false );\n\t},\n\n\ttitle: '*',\n\n\tfilename: '*',\n\n\textension: '.pdf',\n\n\texportOptions: {},\n\n\torientation: 'portrait',\n\n\tpageSize: 'A4',\n\n\theader: true,\n\n\tfooter: false,\n\n\tmessageTop: '*',\n\n\tmessageBottom: '*',\n\n\tcustomize: null,\n\n\tdownload: 'download'\n};\n\n\nreturn DataTable.Buttons;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/js/buttons.jqueryui.js",
    "content": "/*! jQuery UI integration for DataTables' Buttons\n * ©2016 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-jqui', 'datatables.net-buttons'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-jqui')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Buttons ) {\n\t\t\t\trequire('datatables.net-buttons')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n$.extend( true, DataTable.Buttons.defaults, {\n\tdom: {\n\t\tcontainer: {\n\t\t\tclassName: 'dt-buttons ui-buttonset'\n\t\t},\n\t\tbutton: {\n\t\t\tclassName: 'dt-button ui-button ui-state-default ui-button-text-only',\n\t\t\tdisabled: 'ui-state-disabled',\n\t\t\tactive: 'ui-state-active'\n\t\t},\n\t\tbuttonLiner: {\n\t\t\ttag: 'span',\n\t\t\tclassName: 'ui-button-text'\n\t\t}\n\t}\n} );\n\nDataTable.ext.buttons.collection.text = function ( dt ) {\n\treturn dt.i18n('buttons.collection', 'Collection <span class=\"ui-button-icon-primary ui-icon ui-icon-triangle-1-s\"/>');\n};\n\n\nreturn DataTable.Buttons;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/js/buttons.print.js",
    "content": "/*!\n * Print button for Buttons and DataTables.\n * 2016 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Buttons ) {\n\t\t\t\trequire('datatables.net-buttons')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar _link = document.createElement( 'a' );\n\n/**\n * Clone link and style tags, taking into account the need to change the source\n * path.\n *\n * @param  {node}     el Element to convert\n */\nvar _styleToAbs = function( el ) {\n\tvar url;\n\tvar clone = $(el).clone()[0];\n\tvar linkHost;\n\n\tif ( clone.nodeName.toLowerCase() === 'link' ) {\n\t\tclone.href = _relToAbs( clone.href );\n\t}\n\n\treturn clone.outerHTML;\n};\n\n/**\n * Convert a URL from a relative to an absolute address so it will work\n * correctly in the popup window which has no base URL.\n *\n * @param  {string} href URL\n */\nvar _relToAbs = function( href ) {\n\t// Assign to a link on the original page so the browser will do all the\n\t// hard work of figuring out where the file actually is\n\t_link.href = href;\n\tvar linkHost = _link.host;\n\n\t// IE doesn't have a trailing slash on the host\n\t// Chrome has it on the pathname\n\tif ( linkHost.indexOf('/') === -1 && _link.pathname.indexOf('/') !== 0) {\n\t\tlinkHost += '/';\n\t}\n\n\treturn _link.protocol+\"//\"+linkHost+_link.pathname+_link.search;\n};\n\n\nDataTable.ext.buttons.print = {\n\tclassName: 'buttons-print',\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.print', 'Print' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\tvar data = dt.buttons.exportData(\n\t\t\t$.extend( {decodeEntities: false}, config.exportOptions ) // XSS protection\n\t\t);\n\t\tvar exportInfo = dt.buttons.exportInfo( config );\n\t\tvar columnClasses = dt\n\t\t\t.columns( config.exportOptions.columns )\n\t\t\t.flatten()\n\t\t\t.map( function (idx) {\n\t\t\t\treturn dt.settings()[0].aoColumns[dt.column(idx).index()].sClass;\n\t\t\t} )\n\t\t\t.toArray();\n\n\t\tvar addRow = function ( d, tag ) {\n\t\t\tvar str = '<tr>';\n\n\t\t\tfor ( var i=0, ien=d.length ; i<ien ; i++ ) {\n\t\t\t\t// null and undefined aren't useful in the print output\n\t\t\t\tvar dataOut = d[i] === null || d[i] === undefined ?\n\t\t\t\t\t'' :\n\t\t\t\t\td[i];\n\t\t\t\tvar classAttr = columnClasses[i] ?\n\t\t\t\t\t'class=\"'+columnClasses[i]+'\"' :\n\t\t\t\t\t'';\n\n\t\t\t\tstr += '<'+tag+' '+classAttr+'>'+dataOut+'</'+tag+'>';\n\t\t\t}\n\n\t\t\treturn str + '</tr>';\n\t\t};\n\n\t\t// Construct a table for printing\n\t\tvar html = '<table class=\"'+dt.table().node().className+'\">';\n\n\t\tif ( config.header ) {\n\t\t\thtml += '<thead>'+ addRow( data.header, 'th' ) +'</thead>';\n\t\t}\n\n\t\thtml += '<tbody>';\n\t\tfor ( var i=0, ien=data.body.length ; i<ien ; i++ ) {\n\t\t\thtml += addRow( data.body[i], 'td' );\n\t\t}\n\t\thtml += '</tbody>';\n\n\t\tif ( config.footer && data.footer ) {\n\t\t\thtml += '<tfoot>'+ addRow( data.footer, 'th' ) +'</tfoot>';\n\t\t}\n\t\thtml += '</table>';\n\n\t\t// Open a new window for the printable table\n\t\tvar win = window.open( '', '' );\n\t\twin.document.close();\n\n\t\t// Inject the title and also a copy of the style and link tags from this\n\t\t// document so the table can retain its base styling. Note that we have\n\t\t// to use string manipulation as IE won't allow elements to be created\n\t\t// in the host document and then appended to the new window.\n\t\tvar head = '<title>'+exportInfo.title+'</title>';\n\t\t$('style, link').each( function () {\n\t\t\thead += _styleToAbs( this );\n\t\t} );\n\n\t\ttry {\n\t\t\twin.document.head.innerHTML = head; // Work around for Edge\n\t\t}\n\t\tcatch (e) {\n\t\t\t$(win.document.head).html( head ); // Old IE\n\t\t}\n\n\t\t// Inject the table and other surrounding information\n\t\twin.document.body.innerHTML =\n\t\t\t'<h1>'+exportInfo.title+'</h1>'+\n\t\t\t'<div>'+(exportInfo.messageTop || '')+'</div>'+\n\t\t\thtml+\n\t\t\t'<div>'+(exportInfo.messageBottom || '')+'</div>';\n\n\t\t$(win.document.body).addClass('dt-print-view');\n\n\t\t$('img', win.document.body).each( function ( i, img ) {\n\t\t\timg.setAttribute( 'src', _relToAbs( img.getAttribute('src') ) );\n\t\t} );\n\n\t\tif ( config.customize ) {\n\t\t\tconfig.customize( win, config, dt );\n\t\t}\n\n\t\t// Allow stylesheets time to load\n\t\tvar autoPrint = function () {\n\t\t\tif ( config.autoPrint ) {\n\t\t\t\twin.print(); // blocking - so close will not\n\t\t\t\twin.close(); // execute until this is done\n\t\t\t}\n\t\t};\n\n\t\tif ( navigator.userAgent.match(/Trident\\/\\d.\\d/) ) { // IE needs to call this without a setTimeout\n\t\t\tautoPrint();\n\t\t}\n\t\telse {\n\t\t\twin.setTimeout( autoPrint, 1000 );\n\t\t}\n\t},\n\n\ttitle: '*',\n\n\tmessageTop: '*',\n\n\tmessageBottom: '*',\n\n\texportOptions: {},\n\n\theader: true,\n\n\tfooter: false,\n\n\tautoPrint: true,\n\n\tcustomize: null\n};\n\n\nreturn DataTable.Buttons;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/js/buttons.semanticui.js",
    "content": "/*! Bootstrap integration for DataTables' Buttons\n * ©2016 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-se', 'datatables.net-buttons'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-se')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Buttons ) {\n\t\t\t\trequire('datatables.net-buttons')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n$.extend( true, DataTable.Buttons.defaults, {\n\tdom: {\n\t\tcontainer: {\n\t\t\tclassName: 'dt-buttons ui basic buttons'\n\t\t},\n\t\tbutton: {\n\t\t\ttag: 'button',\n\t\t\tclassName: 'ui button'\n\t\t},\n\t\tcollection: {\n\t\t\ttag: 'div',\n\t\t\tclassName: 'dt-button-collection ui basic vertical buttons'\n\t\t}\n\t}\n} );\n\n\nreturn DataTable.Buttons;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Buttons-1.5.6/js/dataTables.buttons.js",
    "content": "/*! Buttons for DataTables 1.5.6\n * ©2016-2019 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n// Used for namespacing events added to the document by each instance, so they\n// can be removed on destroy\nvar _instCounter = 0;\n\n// Button namespacing counter for namespacing events on individual buttons\nvar _buttonCounter = 0;\n\nvar _dtButtons = DataTable.ext.buttons;\n\n/**\n * [Buttons description]\n * @param {[type]}\n * @param {[type]}\n */\nvar Buttons = function( dt, config )\n{\n\t// If not created with a `new` keyword then we return a wrapper function that\n\t// will take the settings object for a DT. This allows easy use of new instances\n\t// with the `layout` option - e.g. `topLeft: $.fn.dataTable.Buttons( ... )`.\n\tif ( !(this instanceof Buttons) ) {\n\t\treturn function (settings) {\n\t\t\treturn new Buttons( settings, dt ).container();\n\t\t};\n\t}\n\n\t// If there is no config set it to an empty object\n\tif ( typeof( config ) === 'undefined' ) {\n\t\tconfig = {};\t\n\t}\n\t\n\t// Allow a boolean true for defaults\n\tif ( config === true ) {\n\t\tconfig = {};\n\t}\n\n\t// For easy configuration of buttons an array can be given\n\tif ( $.isArray( config ) ) {\n\t\tconfig = { buttons: config };\n\t}\n\n\tthis.c = $.extend( true, {}, Buttons.defaults, config );\n\n\t// Don't want a deep copy for the buttons\n\tif ( config.buttons ) {\n\t\tthis.c.buttons = config.buttons;\n\t}\n\n\tthis.s = {\n\t\tdt: new DataTable.Api( dt ),\n\t\tbuttons: [],\n\t\tlistenKeys: '',\n\t\tnamespace: 'dtb'+(_instCounter++)\n\t};\n\n\tthis.dom = {\n\t\tcontainer: $('<'+this.c.dom.container.tag+'/>')\n\t\t\t.addClass( this.c.dom.container.className )\n\t};\n\n\tthis._constructor();\n};\n\n\n$.extend( Buttons.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Public methods\n\t */\n\n\t/**\n\t * Get the action of a button\n\t * @param  {int|string} Button index\n\t * @return {function}\n\t *//**\n\t * Set the action of a button\n\t * @param  {node} node Button element\n\t * @param  {function} action Function to set\n\t * @return {Buttons} Self for chaining\n\t */\n\taction: function ( node, action )\n\t{\n\t\tvar button = this._nodeToButton( node );\n\n\t\tif ( action === undefined ) {\n\t\t\treturn button.conf.action;\n\t\t}\n\n\t\tbutton.conf.action = action;\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Add an active class to the button to make to look active or get current\n\t * active state.\n\t * @param  {node} node Button element\n\t * @param  {boolean} [flag] Enable / disable flag\n\t * @return {Buttons} Self for chaining or boolean for getter\n\t */\n\tactive: function ( node, flag ) {\n\t\tvar button = this._nodeToButton( node );\n\t\tvar klass = this.c.dom.button.active;\n\t\tvar jqNode = $(button.node);\n\n\t\tif ( flag === undefined ) {\n\t\t\treturn jqNode.hasClass( klass );\n\t\t}\n\n\t\tjqNode.toggleClass( klass, flag === undefined ? true : flag );\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Add a new button\n\t * @param {object} config Button configuration object, base string name or function\n\t * @param {int|string} [idx] Button index for where to insert the button\n\t * @return {Buttons} Self for chaining\n\t */\n\tadd: function ( config, idx )\n\t{\n\t\tvar buttons = this.s.buttons;\n\n\t\tif ( typeof idx === 'string' ) {\n\t\t\tvar split = idx.split('-');\n\t\t\tvar base = this.s;\n\n\t\t\tfor ( var i=0, ien=split.length-1 ; i<ien ; i++ ) {\n\t\t\t\tbase = base.buttons[ split[i]*1 ];\n\t\t\t}\n\n\t\t\tbuttons = base.buttons;\n\t\t\tidx = split[ split.length-1 ]*1;\n\t\t}\n\n\t\tthis._expandButton( buttons, config, false, idx );\n\t\tthis._draw();\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Get the container node for the buttons\n\t * @return {jQuery} Buttons node\n\t */\n\tcontainer: function ()\n\t{\n\t\treturn this.dom.container;\n\t},\n\n\t/**\n\t * Disable a button\n\t * @param  {node} node Button node\n\t * @return {Buttons} Self for chaining\n\t */\n\tdisable: function ( node ) {\n\t\tvar button = this._nodeToButton( node );\n\n\t\t$(button.node).addClass( this.c.dom.button.disabled );\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Destroy the instance, cleaning up event handlers and removing DOM\n\t * elements\n\t * @return {Buttons} Self for chaining\n\t */\n\tdestroy: function ()\n\t{\n\t\t// Key event listener\n\t\t$('body').off( 'keyup.'+this.s.namespace );\n\n\t\t// Individual button destroy (so they can remove their own events if\n\t\t// needed). Take a copy as the array is modified by `remove`\n\t\tvar buttons = this.s.buttons.slice();\n\t\tvar i, ien;\n\t\t\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tthis.remove( buttons[i].node );\n\t\t}\n\n\t\t// Container\n\t\tthis.dom.container.remove();\n\n\t\t// Remove from the settings object collection\n\t\tvar buttonInsts = this.s.dt.settings()[0];\n\n\t\tfor ( i=0, ien=buttonInsts.length ; i<ien ; i++ ) {\n\t\t\tif ( buttonInsts.inst === this ) {\n\t\t\t\tbuttonInsts.splice( i, 1 );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Enable / disable a button\n\t * @param  {node} node Button node\n\t * @param  {boolean} [flag=true] Enable / disable flag\n\t * @return {Buttons} Self for chaining\n\t */\n\tenable: function ( node, flag )\n\t{\n\t\tif ( flag === false ) {\n\t\t\treturn this.disable( node );\n\t\t}\n\n\t\tvar button = this._nodeToButton( node );\n\t\t$(button.node).removeClass( this.c.dom.button.disabled );\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Get the instance name for the button set selector\n\t * @return {string} Instance name\n\t */\n\tname: function ()\n\t{\n\t\treturn this.c.name;\n\t},\n\n\t/**\n\t * Get a button's node of the buttons container if no button is given\n\t * @param  {node} [node] Button node\n\t * @return {jQuery} Button element, or container\n\t */\n\tnode: function ( node )\n\t{\n\t\tif ( ! node ) {\n\t\t\treturn this.dom.container;\n\t\t}\n\n\t\tvar button = this._nodeToButton( node );\n\t\treturn $(button.node);\n\t},\n\n\t/**\n\t * Set / get a processing class on the selected button\n\t * @param  {boolean} flag true to add, false to remove, undefined to get\n\t * @return {boolean|Buttons} Getter value or this if a setter.\n\t */\n\tprocessing: function ( node, flag )\n\t{\n\t\tvar button = this._nodeToButton( node );\n\n\t\tif ( flag === undefined ) {\n\t\t\treturn $(button.node).hasClass( 'processing' );\n\t\t}\n\n\t\t$(button.node).toggleClass( 'processing', flag );\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Remove a button.\n\t * @param  {node} node Button node\n\t * @return {Buttons} Self for chaining\n\t */\n\tremove: function ( node )\n\t{\n\t\tvar button = this._nodeToButton( node );\n\t\tvar host = this._nodeToHost( node );\n\t\tvar dt = this.s.dt;\n\n\t\t// Remove any child buttons first\n\t\tif ( button.buttons.length ) {\n\t\t\tfor ( var i=button.buttons.length-1 ; i>=0 ; i-- ) {\n\t\t\t\tthis.remove( button.buttons[i].node );\n\t\t\t}\n\t\t}\n\n\t\t// Allow the button to remove event handlers, etc\n\t\tif ( button.conf.destroy ) {\n\t\t\tbutton.conf.destroy.call( dt.button(node), dt, $(node), button.conf );\n\t\t}\n\n\t\tthis._removeKey( button.conf );\n\n\t\t$(button.node).remove();\n\n\t\tvar idx = $.inArray( button, host );\n\t\thost.splice( idx, 1 );\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Get the text for a button\n\t * @param  {int|string} node Button index\n\t * @return {string} Button text\n\t *//**\n\t * Set the text for a button\n\t * @param  {int|string|function} node Button index\n\t * @param  {string} label Text\n\t * @return {Buttons} Self for chaining\n\t */\n\ttext: function ( node, label )\n\t{\n\t\tvar button = this._nodeToButton( node );\n\t\tvar buttonLiner = this.c.dom.collection.buttonLiner;\n\t\tvar linerTag = button.inCollection && buttonLiner && buttonLiner.tag ?\n\t\t\tbuttonLiner.tag :\n\t\t\tthis.c.dom.buttonLiner.tag;\n\t\tvar dt = this.s.dt;\n\t\tvar jqNode = $(button.node);\n\t\tvar text = function ( opt ) {\n\t\t\treturn typeof opt === 'function' ?\n\t\t\t\topt( dt, jqNode, button.conf ) :\n\t\t\t\topt;\n\t\t};\n\n\t\tif ( label === undefined ) {\n\t\t\treturn text( button.conf.text );\n\t\t}\n\n\t\tbutton.conf.text = label;\n\n\t\tif ( linerTag ) {\n\t\t\tjqNode.children( linerTag ).html( text(label) );\n\t\t}\n\t\telse {\n\t\t\tjqNode.html( text(label) );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\n\t/**\n\t * Buttons constructor\n\t * @private\n\t */\n\t_constructor: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar dtSettings = dt.settings()[0];\n\t\tvar buttons =  this.c.buttons;\n\n\t\tif ( ! dtSettings._buttons ) {\n\t\t\tdtSettings._buttons = [];\n\t\t}\n\n\t\tdtSettings._buttons.push( {\n\t\t\tinst: this,\n\t\t\tname: this.c.name\n\t\t} );\n\n\t\tfor ( var i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tthis.add( buttons[i] );\n\t\t}\n\n\t\tdt.on( 'destroy', function ( e, settings ) {\n\t\t\tif ( settings === dtSettings ) {\n\t\t\t\tthat.destroy();\n\t\t\t}\n\t\t} );\n\n\t\t// Global key event binding to listen for button keys\n\t\t$('body').on( 'keyup.'+this.s.namespace, function ( e ) {\n\t\t\tif ( ! document.activeElement || document.activeElement === document.body ) {\n\t\t\t\t// SUse a string of characters for fast lookup of if we need to\n\t\t\t\t// handle this\n\t\t\t\tvar character = String.fromCharCode(e.keyCode).toLowerCase();\n\n\t\t\t\tif ( that.s.listenKeys.toLowerCase().indexOf( character ) !== -1 ) {\n\t\t\t\t\tthat._keypress( character, e );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\n\t/**\n\t * Add a new button to the key press listener\n\t * @param {object} conf Resolved button configuration object\n\t * @private\n\t */\n\t_addKey: function ( conf )\n\t{\n\t\tif ( conf.key ) {\n\t\t\tthis.s.listenKeys += $.isPlainObject( conf.key ) ?\n\t\t\t\tconf.key.key :\n\t\t\t\tconf.key;\n\t\t}\n\t},\n\n\t/**\n\t * Insert the buttons into the container. Call without parameters!\n\t * @param  {node} [container] Recursive only - Insert point\n\t * @param  {array} [buttons] Recursive only - Buttons array\n\t * @private\n\t */\n\t_draw: function ( container, buttons )\n\t{\n\t\tif ( ! container ) {\n\t\t\tcontainer = this.dom.container;\n\t\t\tbuttons = this.s.buttons;\n\t\t}\n\n\t\tcontainer.children().detach();\n\n\t\tfor ( var i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tcontainer.append( buttons[i].inserter );\n\t\t\tcontainer.append( ' ' );\n\n\t\t\tif ( buttons[i].buttons && buttons[i].buttons.length ) {\n\t\t\t\tthis._draw( buttons[i].collection, buttons[i].buttons );\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * Create buttons from an array of buttons\n\t * @param  {array} attachTo Buttons array to attach to\n\t * @param  {object} button Button definition\n\t * @param  {boolean} inCollection true if the button is in a collection\n\t * @private\n\t */\n\t_expandButton: function ( attachTo, button, inCollection, attachPoint )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar buttonCounter = 0;\n\t\tvar buttons = ! $.isArray( button ) ?\n\t\t\t[ button ] :\n\t\t\tbutton;\n\n\t\tfor ( var i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tvar conf = this._resolveExtends( buttons[i] );\n\n\t\t\tif ( ! conf ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If the configuration is an array, then expand the buttons at this\n\t\t\t// point\n\t\t\tif ( $.isArray( conf ) ) {\n\t\t\t\tthis._expandButton( attachTo, conf, inCollection, attachPoint );\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tvar built = this._buildButton( conf, inCollection );\n\t\t\tif ( ! built ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ( attachPoint !== undefined ) {\n\t\t\t\tattachTo.splice( attachPoint, 0, built );\n\t\t\t\tattachPoint++;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tattachTo.push( built );\n\t\t\t}\n\n\t\t\tif ( built.conf.buttons ) {\n\t\t\t\tvar collectionDom = this.c.dom.collection;\n\t\t\t\tbuilt.collection = $('<'+collectionDom.tag+'/>')\n\t\t\t\t\t.addClass( collectionDom.className )\n\t\t\t\t\t.attr( 'role', 'menu' ) ;\n\t\t\t\tbuilt.conf._collection = built.collection;\n\n\t\t\t\tthis._expandButton( built.buttons, built.conf.buttons, true, attachPoint );\n\t\t\t}\n\n\t\t\t// init call is made here, rather than buildButton as it needs to\n\t\t\t// be selectable, and for that it needs to be in the buttons array\n\t\t\tif ( conf.init ) {\n\t\t\t\tconf.init.call( dt.button( built.node ), dt, $(built.node), conf );\n\t\t\t}\n\n\t\t\tbuttonCounter++;\n\t\t}\n\t},\n\n\t/**\n\t * Create an individual button\n\t * @param  {object} config            Resolved button configuration\n\t * @param  {boolean} inCollection `true` if a collection button\n\t * @return {jQuery} Created button node (jQuery)\n\t * @private\n\t */\n\t_buildButton: function ( config, inCollection )\n\t{\n\t\tvar buttonDom = this.c.dom.button;\n\t\tvar linerDom = this.c.dom.buttonLiner;\n\t\tvar collectionDom = this.c.dom.collection;\n\t\tvar dt = this.s.dt;\n\t\tvar text = function ( opt ) {\n\t\t\treturn typeof opt === 'function' ?\n\t\t\t\topt( dt, button, config ) :\n\t\t\t\topt;\n\t\t};\n\n\t\tif ( inCollection && collectionDom.button ) {\n\t\t\tbuttonDom = collectionDom.button;\n\t\t}\n\n\t\tif ( inCollection && collectionDom.buttonLiner ) {\n\t\t\tlinerDom = collectionDom.buttonLiner;\n\t\t}\n\n\t\t// Make sure that the button is available based on whatever requirements\n\t\t// it has. For example, Flash buttons require Flash\n\t\tif ( config.available && ! config.available( dt, config ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tvar action = function ( e, dt, button, config ) {\n\t\t\tconfig.action.call( dt.button( button ), e, dt, button, config );\n\n\t\t\t$(dt.table().node()).triggerHandler( 'buttons-action.dt', [\n\t\t\t\tdt.button( button ), dt, button, config \n\t\t\t] );\n\t\t};\n\n\t\tvar tag = config.tag || buttonDom.tag;\n\t\tvar clickBlurs = config.clickBlurs === undefined ? true : config.clickBlurs\n\t\tvar button = $('<'+tag+'/>')\n\t\t\t.addClass( buttonDom.className )\n\t\t\t.attr( 'tabindex', this.s.dt.settings()[0].iTabIndex )\n\t\t\t.attr( 'aria-controls', this.s.dt.table().node().id )\n\t\t\t.on( 'click.dtb', function (e) {\n\t\t\t\te.preventDefault();\n\n\t\t\t\tif ( ! button.hasClass( buttonDom.disabled ) && config.action ) {\n\t\t\t\t\taction( e, dt, button, config );\n\t\t\t\t}\n\t\t\t\tif( clickBlurs ) {\n\t\t\t\t\tbutton.blur();\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'keyup.dtb', function (e) {\n\t\t\t\tif ( e.keyCode === 13 ) {\n\t\t\t\t\tif ( ! button.hasClass( buttonDom.disabled ) && config.action ) {\n\t\t\t\t\t\taction( e, dt, button, config );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\n\t\t// Make `a` tags act like a link\n\t\tif ( tag.toLowerCase() === 'a' ) {\n\t\t\tbutton.attr( 'href', '#' );\n\t\t}\n\n\t\t// Button tags should have `type=button` so they don't have any default behaviour\n\t\tif ( tag.toLowerCase() === 'button' ) {\n\t\t\tbutton.attr( 'type', 'button' );\n\t\t}\n\n\t\tif ( linerDom.tag ) {\n\t\t\tvar liner = $('<'+linerDom.tag+'/>')\n\t\t\t\t.html( text( config.text ) )\n\t\t\t\t.addClass( linerDom.className );\n\n\t\t\tif ( linerDom.tag.toLowerCase() === 'a' ) {\n\t\t\t\tliner.attr( 'href', '#' );\n\t\t\t}\n\n\t\t\tbutton.append( liner );\n\t\t}\n\t\telse {\n\t\t\tbutton.html( text( config.text ) );\n\t\t}\n\n\t\tif ( config.enabled === false ) {\n\t\t\tbutton.addClass( buttonDom.disabled );\n\t\t}\n\n\t\tif ( config.className ) {\n\t\t\tbutton.addClass( config.className );\n\t\t}\n\n\t\tif ( config.titleAttr ) {\n\t\t\tbutton.attr( 'title', text( config.titleAttr ) );\n\t\t}\n\n\t\tif ( config.attr ) {\n\t\t\tbutton.attr( config.attr );\n\t\t}\n\n\t\tif ( ! config.namespace ) {\n\t\t\tconfig.namespace = '.dt-button-'+(_buttonCounter++);\n\t\t}\n\n\t\tvar buttonContainer = this.c.dom.buttonContainer;\n\t\tvar inserter;\n\t\tif ( buttonContainer && buttonContainer.tag ) {\n\t\t\tinserter = $('<'+buttonContainer.tag+'/>')\n\t\t\t\t.addClass( buttonContainer.className )\n\t\t\t\t.append( button );\n\t\t}\n\t\telse {\n\t\t\tinserter = button;\n\t\t}\n\n\t\tthis._addKey( config );\n\n\t\t// Style integration callback for DOM manipulation\n\t\t// Note that this is _not_ documented. It is currently\n\t\t// for style integration only\n\t\tif( this.c.buttonCreated ) {\n\t\t\tinserter = this.c.buttonCreated( config, inserter );\n\t\t}\n\n\t\treturn {\n\t\t\tconf:         config,\n\t\t\tnode:         button.get(0),\n\t\t\tinserter:     inserter,\n\t\t\tbuttons:      [],\n\t\t\tinCollection: inCollection,\n\t\t\tcollection:   null\n\t\t};\n\t},\n\n\t/**\n\t * Get the button object from a node (recursive)\n\t * @param  {node} node Button node\n\t * @param  {array} [buttons] Button array, uses base if not defined\n\t * @return {object} Button object\n\t * @private\n\t */\n\t_nodeToButton: function ( node, buttons )\n\t{\n\t\tif ( ! buttons ) {\n\t\t\tbuttons = this.s.buttons;\n\t\t}\n\n\t\tfor ( var i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tif ( buttons[i].node === node ) {\n\t\t\t\treturn buttons[i];\n\t\t\t}\n\n\t\t\tif ( buttons[i].buttons.length ) {\n\t\t\t\tvar ret = this._nodeToButton( node, buttons[i].buttons );\n\n\t\t\t\tif ( ret ) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * Get container array for a button from a button node (recursive)\n\t * @param  {node} node Button node\n\t * @param  {array} [buttons] Button array, uses base if not defined\n\t * @return {array} Button's host array\n\t * @private\n\t */\n\t_nodeToHost: function ( node, buttons )\n\t{\n\t\tif ( ! buttons ) {\n\t\t\tbuttons = this.s.buttons;\n\t\t}\n\n\t\tfor ( var i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tif ( buttons[i].node === node ) {\n\t\t\t\treturn buttons;\n\t\t\t}\n\n\t\t\tif ( buttons[i].buttons.length ) {\n\t\t\t\tvar ret = this._nodeToHost( node, buttons[i].buttons );\n\n\t\t\t\tif ( ret ) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * Handle a key press - determine if any button's key configured matches\n\t * what was typed and trigger the action if so.\n\t * @param  {string} character The character pressed\n\t * @param  {object} e Key event that triggered this call\n\t * @private\n\t */\n\t_keypress: function ( character, e )\n\t{\n\t\t// Check if this button press already activated on another instance of Buttons\n\t\tif ( e._buttonsHandled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar run = function ( conf, node ) {\n\t\t\tif ( ! conf.key ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( conf.key === character ) {\n\t\t\t\te._buttonsHandled = true;\n\t\t\t\t$(node).click();\n\t\t\t}\n\t\t\telse if ( $.isPlainObject( conf.key ) ) {\n\t\t\t\tif ( conf.key.key !== character ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( conf.key.shiftKey && ! e.shiftKey ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( conf.key.altKey && ! e.altKey ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( conf.key.ctrlKey && ! e.ctrlKey ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( conf.key.metaKey && ! e.metaKey ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Made it this far - it is good\n\t\t\t\te._buttonsHandled = true;\n\t\t\t\t$(node).click();\n\t\t\t}\n\t\t};\n\n\t\tvar recurse = function ( a ) {\n\t\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\t\trun( a[i].conf, a[i].node );\n\n\t\t\t\tif ( a[i].buttons.length ) {\n\t\t\t\t\trecurse( a[i].buttons );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\trecurse( this.s.buttons );\n\t},\n\n\t/**\n\t * Remove a key from the key listener for this instance (to be used when a\n\t * button is removed)\n\t * @param  {object} conf Button configuration\n\t * @private\n\t */\n\t_removeKey: function ( conf )\n\t{\n\t\tif ( conf.key ) {\n\t\t\tvar character = $.isPlainObject( conf.key ) ?\n\t\t\t\tconf.key.key :\n\t\t\t\tconf.key;\n\n\t\t\t// Remove only one character, as multiple buttons could have the\n\t\t\t// same listening key\n\t\t\tvar a = this.s.listenKeys.split('');\n\t\t\tvar idx = $.inArray( character, a );\n\t\t\ta.splice( idx, 1 );\n\t\t\tthis.s.listenKeys = a.join('');\n\t\t}\n\t},\n\n\t/**\n\t * Resolve a button configuration\n\t * @param  {string|function|object} conf Button config to resolve\n\t * @return {object} Button configuration\n\t * @private\n\t */\n\t_resolveExtends: function ( conf )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar i, ien;\n\t\tvar toConfObject = function ( base ) {\n\t\t\tvar loop = 0;\n\n\t\t\t// Loop until we have resolved to a button configuration, or an\n\t\t\t// array of button configurations (which will be iterated\n\t\t\t// separately)\n\t\t\twhile ( ! $.isPlainObject(base) && ! $.isArray(base) ) {\n\t\t\t\tif ( base === undefined ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( typeof base === 'function' ) {\n\t\t\t\t\tbase = base( dt, conf );\n\n\t\t\t\t\tif ( ! base ) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( typeof base === 'string' ) {\n\t\t\t\t\tif ( ! _dtButtons[ base ] ) {\n\t\t\t\t\t\tthrow 'Unknown button type: '+base;\n\t\t\t\t\t}\n\n\t\t\t\t\tbase = _dtButtons[ base ];\n\t\t\t\t}\n\n\t\t\t\tloop++;\n\t\t\t\tif ( loop > 30 ) {\n\t\t\t\t\t// Protect against misconfiguration killing the browser\n\t\t\t\t\tthrow 'Buttons: Too many iterations';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn $.isArray( base ) ?\n\t\t\t\tbase :\n\t\t\t\t$.extend( {}, base );\n\t\t};\n\n\t\tconf = toConfObject( conf );\n\n\t\twhile ( conf && conf.extend ) {\n\t\t\t// Use `toConfObject` in case the button definition being extended\n\t\t\t// is itself a string or a function\n\t\t\tif ( ! _dtButtons[ conf.extend ] ) {\n\t\t\t\tthrow 'Cannot extend unknown button type: '+conf.extend;\n\t\t\t}\n\n\t\t\tvar objArray = toConfObject( _dtButtons[ conf.extend ] );\n\t\t\tif ( $.isArray( objArray ) ) {\n\t\t\t\treturn objArray;\n\t\t\t}\n\t\t\telse if ( ! objArray ) {\n\t\t\t\t// This is a little brutal as it might be possible to have a\n\t\t\t\t// valid button without the extend, but if there is no extend\n\t\t\t\t// then the host button would be acting in an undefined state\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Stash the current class name\n\t\t\tvar originalClassName = objArray.className;\n\n\t\t\tconf = $.extend( {}, objArray, conf );\n\n\t\t\t// The extend will have overwritten the original class name if the\n\t\t\t// `conf` object also assigned a class, but we want to concatenate\n\t\t\t// them so they are list that is combined from all extended buttons\n\t\t\tif ( originalClassName && conf.className !== originalClassName ) {\n\t\t\t\tconf.className = originalClassName+' '+conf.className;\n\t\t\t}\n\n\t\t\t// Buttons to be added to a collection  -gives the ability to define\n\t\t\t// if buttons should be added to the start or end of a collection\n\t\t\tvar postfixButtons = conf.postfixButtons;\n\t\t\tif ( postfixButtons ) {\n\t\t\t\tif ( ! conf.buttons ) {\n\t\t\t\t\tconf.buttons = [];\n\t\t\t\t}\n\n\t\t\t\tfor ( i=0, ien=postfixButtons.length ; i<ien ; i++ ) {\n\t\t\t\t\tconf.buttons.push( postfixButtons[i] );\n\t\t\t\t}\n\n\t\t\t\tconf.postfixButtons = null;\n\t\t\t}\n\n\t\t\tvar prefixButtons = conf.prefixButtons;\n\t\t\tif ( prefixButtons ) {\n\t\t\t\tif ( ! conf.buttons ) {\n\t\t\t\t\tconf.buttons = [];\n\t\t\t\t}\n\n\t\t\t\tfor ( i=0, ien=prefixButtons.length ; i<ien ; i++ ) {\n\t\t\t\t\tconf.buttons.splice( i, 0, prefixButtons[i] );\n\t\t\t\t}\n\n\t\t\t\tconf.prefixButtons = null;\n\t\t\t}\n\n\t\t\t// Although we want the `conf` object to overwrite almost all of\n\t\t\t// the properties of the object being extended, the `extend`\n\t\t\t// property should come from the object being extended\n\t\t\tconf.extend = objArray.extend;\n\t\t}\n\n\t\treturn conf;\n\t}\n} );\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Statics\n */\n\n/**\n * Show / hide a background layer behind a collection\n * @param  {boolean} Flag to indicate if the background should be shown or\n *   hidden \n * @param  {string} Class to assign to the background\n * @static\n */\nButtons.background = function ( show, className, fade, insertPoint ) {\n\tif ( fade === undefined ) {\n\t\tfade = 400;\n\t}\n\tif ( ! insertPoint ) {\n\t\tinsertPoint = document.body;\n\t}\n\n\tif ( show ) {\n\t\t$('<div/>')\n\t\t\t.addClass( className )\n\t\t\t.css( 'display', 'none' )\n\t\t\t.insertAfter( insertPoint )\n\t\t\t.stop()\n\t\t\t.fadeIn( fade );\n\t}\n\telse {\n\t\t$('div.'+className)\n\t\t\t.stop()\n\t\t\t.fadeOut( fade, function () {\n\t\t\t\t$(this)\n\t\t\t\t\t.removeClass( className )\n\t\t\t\t\t.remove();\n\t\t\t} );\n\t}\n};\n\n/**\n * Instance selector - select Buttons instances based on an instance selector\n * value from the buttons assigned to a DataTable. This is only useful if\n * multiple instances are attached to a DataTable.\n * @param  {string|int|array} Instance selector - see `instance-selector`\n *   documentation on the DataTables site\n * @param  {array} Button instance array that was attached to the DataTables\n *   settings object\n * @return {array} Buttons instances\n * @static\n */\nButtons.instanceSelector = function ( group, buttons )\n{\n\tif ( ! group ) {\n\t\treturn $.map( buttons, function ( v ) {\n\t\t\treturn v.inst;\n\t\t} );\n\t}\n\n\tvar ret = [];\n\tvar names = $.map( buttons, function ( v ) {\n\t\treturn v.name;\n\t} );\n\n\t// Flatten the group selector into an array of single options\n\tvar process = function ( input ) {\n\t\tif ( $.isArray( input ) ) {\n\t\t\tfor ( var i=0, ien=input.length ; i<ien ; i++ ) {\n\t\t\t\tprocess( input[i] );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif ( typeof input === 'string' ) {\n\t\t\tif ( input.indexOf( ',' ) !== -1 ) {\n\t\t\t\t// String selector, list of names\n\t\t\t\tprocess( input.split(',') );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// String selector individual name\n\t\t\t\tvar idx = $.inArray( $.trim(input), names );\n\n\t\t\t\tif ( idx !== -1 ) {\n\t\t\t\t\tret.push( buttons[ idx ].inst );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if ( typeof input === 'number' ) {\n\t\t\t// Index selector\n\t\t\tret.push( buttons[ input ].inst );\n\t\t}\n\t};\n\t\n\tprocess( group );\n\n\treturn ret;\n};\n\n/**\n * Button selector - select one or more buttons from a selector input so some\n * operation can be performed on them.\n * @param  {array} Button instances array that the selector should operate on\n * @param  {string|int|node|jQuery|array} Button selector - see\n *   `button-selector` documentation on the DataTables site\n * @return {array} Array of objects containing `inst` and `idx` properties of\n *   the selected buttons so you know which instance each button belongs to.\n * @static\n */\nButtons.buttonSelector = function ( insts, selector )\n{\n\tvar ret = [];\n\tvar nodeBuilder = function ( a, buttons, baseIdx ) {\n\t\tvar button;\n\t\tvar idx;\n\n\t\tfor ( var i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( button ) {\n\t\t\t\tidx = baseIdx !== undefined ?\n\t\t\t\t\tbaseIdx+i :\n\t\t\t\t\ti+'';\n\n\t\t\t\ta.push( {\n\t\t\t\t\tnode: button.node,\n\t\t\t\t\tname: button.conf.name,\n\t\t\t\t\tidx:  idx\n\t\t\t\t} );\n\n\t\t\t\tif ( button.buttons ) {\n\t\t\t\t\tnodeBuilder( a, button.buttons, idx+'-' );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\tvar run = function ( selector, inst ) {\n\t\tvar i, ien;\n\t\tvar buttons = [];\n\t\tnodeBuilder( buttons, inst.s.buttons );\n\n\t\tvar nodes = $.map( buttons, function (v) {\n\t\t\treturn v.node;\n\t\t} );\n\n\t\tif ( $.isArray( selector ) || selector instanceof $ ) {\n\t\t\tfor ( i=0, ien=selector.length ; i<ien ; i++ ) {\n\t\t\t\trun( selector[i], inst );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif ( selector === null || selector === undefined || selector === '*' ) {\n\t\t\t// Select all\n\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\tret.push( {\n\t\t\t\t\tinst: inst,\n\t\t\t\t\tnode: buttons[i].node\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\telse if ( typeof selector === 'number' ) {\n\t\t\t// Main button index selector\n\t\t\tret.push( {\n\t\t\t\tinst: inst,\n\t\t\t\tnode: inst.s.buttons[ selector ].node\n\t\t\t} );\n\t\t}\n\t\telse if ( typeof selector === 'string' ) {\n\t\t\tif ( selector.indexOf( ',' ) !== -1 ) {\n\t\t\t\t// Split\n\t\t\t\tvar a = selector.split(',');\n\n\t\t\t\tfor ( i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\t\t\trun( $.trim(a[i]), inst );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( selector.match( /^\\d+(\\-\\d+)*$/ ) ) {\n\t\t\t\t// Sub-button index selector\n\t\t\t\tvar indexes = $.map( buttons, function (v) {\n\t\t\t\t\treturn v.idx;\n\t\t\t\t} );\n\n\t\t\t\tret.push( {\n\t\t\t\t\tinst: inst,\n\t\t\t\t\tnode: buttons[ $.inArray( selector, indexes ) ].node\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse if ( selector.indexOf( ':name' ) !== -1 ) {\n\t\t\t\t// Button name selector\n\t\t\t\tvar name = selector.replace( ':name', '' );\n\n\t\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( buttons[i].name === name ) {\n\t\t\t\t\t\tret.push( {\n\t\t\t\t\t\t\tinst: inst,\n\t\t\t\t\t\t\tnode: buttons[i].node\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// jQuery selector on the nodes\n\t\t\t\t$( nodes ).filter( selector ).each( function () {\n\t\t\t\t\tret.push( {\n\t\t\t\t\t\tinst: inst,\n\t\t\t\t\t\tnode: this\n\t\t\t\t\t} );\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\telse if ( typeof selector === 'object' && selector.nodeName ) {\n\t\t\t// Node selector\n\t\t\tvar idx = $.inArray( selector, nodes );\n\n\t\t\tif ( idx !== -1 ) {\n\t\t\t\tret.push( {\n\t\t\t\t\tinst: inst,\n\t\t\t\t\tnode: nodes[ idx ]\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t};\n\n\n\tfor ( var i=0, ien=insts.length ; i<ien ; i++ ) {\n\t\tvar inst = insts[i];\n\n\t\trun( selector, inst );\n\t}\n\n\treturn ret;\n};\n\n\n/**\n * Buttons defaults. For full documentation, please refer to the docs/option\n * directory or the DataTables site.\n * @type {Object}\n * @static\n */\nButtons.defaults = {\n\tbuttons: [ 'copy', 'excel', 'csv', 'pdf', 'print' ],\n\tname: 'main',\n\ttabIndex: 0,\n\tdom: {\n\t\tcontainer: {\n\t\t\ttag: 'div',\n\t\t\tclassName: 'dt-buttons'\n\t\t},\n\t\tcollection: {\n\t\t\ttag: 'div',\n\t\t\tclassName: 'dt-button-collection'\n\t\t},\n\t\tbutton: {\n\t\t\t// Flash buttons will not work with `<button>` in IE - it has to be `<a>`\n\t\t\ttag: 'ActiveXObject' in window ?\n\t\t\t\t'a' :\n\t\t\t\t'button',\n\t\t\tclassName: 'dt-button',\n\t\t\tactive: 'active',\n\t\t\tdisabled: 'disabled'\n\t\t},\n\t\tbuttonLiner: {\n\t\t\ttag: 'span',\n\t\t\tclassName: ''\n\t\t}\n\t}\n};\n\n/**\n * Version information\n * @type {string}\n * @static\n */\nButtons.version = '1.5.6';\n\n\n$.extend( _dtButtons, {\n\tcollection: {\n\t\ttext: function ( dt ) {\n\t\t\treturn dt.i18n( 'buttons.collection', 'Collection' );\n\t\t},\n\t\tclassName: 'buttons-collection',\n\t\tinit: function ( dt, button, config ) {\n\t\t\tbutton.attr( 'aria-expanded', false );\n\t\t},\n\t\taction: function ( e, dt, button, config ) {\n\t\t\tvar close = function () {\n\t\t\t\tdt.buttons( '[aria-haspopup=\"true\"][aria-expanded=\"true\"]' ).nodes().each( function() {\n\t\t\t\t\tvar collection = $(this).siblings('.dt-button-collection');\n\n\t\t\t\t\tif ( collection.length ) {\n\t\t\t\t\t\tcollection.stop().fadeOut( config.fade, function () {\n\t\t\t\t\t\t\tcollection.detach();\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\n\t\t\t\t\t$(this).attr( 'aria-expanded', 'false' );\n\t\t\t\t});\n\n\t\t\t\t$('div.dt-button-background').off( 'click.dtb-collection' );\n\t\t\t\tButtons.background( false, config.backgroundClassName, config.fade, insertPoint );\n\n\t\t\t\t$('body').off( '.dtb-collection' );\n\t\t\t\tdt.off( 'buttons-action.b-internal' );\n\t\t\t};\n\n\t\t\tvar wasExpanded = button.attr( 'aria-expanded' ) === 'true';\n\n\t\t\tclose();\n\n\t\t\tif (!wasExpanded) {\n\t\t\t\tvar host = button;\n\t\t\t\tvar collectionParent = $(button).parents('div.dt-button-collection');\n\t\t\t\tvar hostPosition = host.position();\n\t\t\t\tvar tableContainer = $( dt.table().container() );\n\t\t\t\tvar multiLevel = false;\n\t\t\t\tvar insertPoint = host;\n\n\t\t\t\tbutton.attr( 'aria-expanded', 'true' );\n\n\t\t\t\t// Remove any old collection\n\t\t\t\tif ( collectionParent.length ) {\n\t\t\t\t\tmultiLevel = $('.dt-button-collection').position();\n\t\t\t\t\tinsertPoint = collectionParent;\n\t\t\t\t\t$('body').trigger( 'click.dtb-collection' );\n\t\t\t\t}\n\n\t\t\t\tif ( insertPoint.parents('body')[0] !== document.body ) {\n\t\t\t\t\tinsertPoint = document.body.lastChild;\n\t\t\t\t}\n\n\t\t\t\tconfig._collection.find('.dt-button-collection-title').remove();\n\t\t\t\tconfig._collection.prepend('<div class=\"dt-button-collection-title\">'+config.collectionTitle+'</div>');\n\n\t\t\t\tconfig._collection\n\t\t\t\t\t.addClass( config.collectionLayout )\n\t\t\t\t\t.css( 'display', 'none' )\n\t\t\t\t\t.insertAfter( insertPoint )\n\t\t\t\t\t.stop()\n\t\t\t\t\t.fadeIn( config.fade );\n\n\t\t\t\tvar position = config._collection.css( 'position' );\n\n\t\t\t\tif ( multiLevel && position === 'absolute' ) {\n\t\t\t\t\tconfig._collection.css( {\n\t\t\t\t\t\ttop: multiLevel.top,\n\t\t\t\t\t\tleft: multiLevel.left\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\telse if ( position === 'absolute' ) {\n\t\t\t\t\tconfig._collection.css( {\n\t\t\t\t\t\ttop: hostPosition.top + host.outerHeight(),\n\t\t\t\t\t\tleft: hostPosition.left\n\t\t\t\t\t} );\n\n\t\t\t\t\t// calculate overflow when positioned beneath\n\t\t\t\t\tvar tableBottom = tableContainer.offset().top + tableContainer.height();\n\t\t\t\t\tvar listBottom = hostPosition.top + host.outerHeight() + config._collection.outerHeight();\n\t\t\t\t\tvar bottomOverflow = listBottom - tableBottom;\n\n\t\t\t\t\t// calculate overflow when positioned above\n\t\t\t\t\tvar listTop = hostPosition.top - config._collection.outerHeight();\n\t\t\t\t\tvar tableTop = tableContainer.offset().top;\n\t\t\t\t\tvar topOverflow = tableTop - listTop;\n\n\t\t\t\t\t// if bottom overflow is larger, move to the top because it fits better, or if dropup is requested\n\t\t\t\t\tif (bottomOverflow > topOverflow || config.dropup) {\n\t\t\t\t\t\tconfig._collection.css( 'top', hostPosition.top - config._collection.outerHeight() - 5);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Right alignment is enabled on a class, e.g. bootstrap:\n\t\t\t\t\t// $.fn.dataTable.Buttons.defaults.dom.collection.className += \" dropdown-menu-right\"; \n\t\t\t\t\tif ( config._collection.hasClass( config.rightAlignClassName ) ) {\n\t\t\t\t\t\tconfig._collection.css( 'left', hostPosition.left + host.outerWidth() - config._collection.outerWidth() );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Right alignment in table container\n\t\t\t\t\tvar listRight = hostPosition.left + config._collection.outerWidth();\n\t\t\t\t\tvar tableRight = tableContainer.offset().left + tableContainer.width();\n\t\t\t\t\tif ( listRight > tableRight ) {\n\t\t\t\t\t\tconfig._collection.css( 'left', hostPosition.left - ( listRight - tableRight ) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Right alignment to window\n\t\t\t\t\tvar listOffsetRight = host.offset().left + config._collection.outerWidth();\n\t\t\t\t\tif ( listOffsetRight > $(window).width() ) {\n\t\t\t\t\t\tconfig._collection.css( 'left', hostPosition.left - (listOffsetRight-$(window).width()) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Fix position - centre on screen\n\t\t\t\t\tvar top = config._collection.height() / 2;\n\t\t\t\t\tif ( top > $(window).height() / 2 ) {\n\t\t\t\t\t\ttop = $(window).height() / 2;\n\t\t\t\t\t}\n\n\t\t\t\t\tconfig._collection.css( 'marginTop', top*-1 );\n\t\t\t\t}\n\n\t\t\t\tif ( config.background ) {\n\t\t\t\t\tButtons.background( true, config.backgroundClassName, config.fade, insertPoint );\n\t\t\t\t}\n\n\t\t\t\t// Need to break the 'thread' for the collection button being\n\t\t\t\t// activated by a click - it would also trigger this event\n\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t// This is bonkers, but if we don't have a click listener on the\n\t\t\t\t\t// background element, iOS Safari will ignore the body click\n\t\t\t\t\t// listener below. An empty function here is all that is\n\t\t\t\t\t// required to make it work...\n\t\t\t\t\t$('div.dt-button-background').on( 'click.dtb-collection', function () {} );\n\n\t\t\t\t\t$('body')\n\t\t\t\t\t\t.on( 'click.dtb-collection', function (e) {\n\t\t\t\t\t\t\t// andSelf is deprecated in jQ1.8, but we want 1.7 compat\n\t\t\t\t\t\t\tvar back = $.fn.addBack ? 'addBack' : 'andSelf';\n\n\t\t\t\t\t\t\tif ( ! $(e.target).parents()[back]().filter( config._collection ).length ) {\n\t\t\t\t\t\t\t\tclose();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.on( 'keyup.dtb-collection', function (e) {\n\t\t\t\t\t\t\tif ( e.keyCode === 27 ) {\n\t\t\t\t\t\t\t\tclose();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\n\t\t\t\t\tif ( config.autoClose ) {\n\t\t\t\t\t\tdt.on( 'buttons-action.b-internal', function () {\n\t\t\t\t\t\t\tclose();\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}, 10 );\n\t\t\t}\n\t\t},\n\t\tbackground: true,\n\t\tcollectionLayout: '',\n\t\tcollectionTitle: '',\n\t\tbackgroundClassName: 'dt-button-background',\n\t\trightAlignClassName: 'dt-button-right',\n\t\tautoClose: false,\n\t\tfade: 400,\n\t\tattr: {\n\t\t\t'aria-haspopup': true\n\t\t}\n\t},\n\tcopy: function ( dt, conf ) {\n\t\tif ( _dtButtons.copyHtml5 ) {\n\t\t\treturn 'copyHtml5';\n\t\t}\n\t\tif ( _dtButtons.copyFlash && _dtButtons.copyFlash.available( dt, conf ) ) {\n\t\t\treturn 'copyFlash';\n\t\t}\n\t},\n\tcsv: function ( dt, conf ) {\n\t\t// Common option that will use the HTML5 or Flash export buttons\n\t\tif ( _dtButtons.csvHtml5 && _dtButtons.csvHtml5.available( dt, conf ) ) {\n\t\t\treturn 'csvHtml5';\n\t\t}\n\t\tif ( _dtButtons.csvFlash && _dtButtons.csvFlash.available( dt, conf ) ) {\n\t\t\treturn 'csvFlash';\n\t\t}\n\t},\n\texcel: function ( dt, conf ) {\n\t\t// Common option that will use the HTML5 or Flash export buttons\n\t\tif ( _dtButtons.excelHtml5 && _dtButtons.excelHtml5.available( dt, conf ) ) {\n\t\t\treturn 'excelHtml5';\n\t\t}\n\t\tif ( _dtButtons.excelFlash && _dtButtons.excelFlash.available( dt, conf ) ) {\n\t\t\treturn 'excelFlash';\n\t\t}\n\t},\n\tpdf: function ( dt, conf ) {\n\t\t// Common option that will use the HTML5 or Flash export buttons\n\t\tif ( _dtButtons.pdfHtml5 && _dtButtons.pdfHtml5.available( dt, conf ) ) {\n\t\t\treturn 'pdfHtml5';\n\t\t}\n\t\tif ( _dtButtons.pdfFlash && _dtButtons.pdfFlash.available( dt, conf ) ) {\n\t\t\treturn 'pdfFlash';\n\t\t}\n\t},\n\tpageLength: function ( dt ) {\n\t\tvar lengthMenu = dt.settings()[0].aLengthMenu;\n\t\tvar vals = $.isArray( lengthMenu[0] ) ? lengthMenu[0] : lengthMenu;\n\t\tvar lang = $.isArray( lengthMenu[0] ) ? lengthMenu[1] : lengthMenu;\n\t\tvar text = function ( dt ) {\n\t\t\treturn dt.i18n( 'buttons.pageLength', {\n\t\t\t\t\"-1\": 'Show all rows',\n\t\t\t\t_:    'Show %d rows'\n\t\t\t}, dt.page.len() );\n\t\t};\n\n\t\treturn {\n\t\t\textend: 'collection',\n\t\t\ttext: text,\n\t\t\tclassName: 'buttons-page-length',\n\t\t\tautoClose: true,\n\t\t\tbuttons: $.map( vals, function ( val, i ) {\n\t\t\t\treturn {\n\t\t\t\t\ttext: lang[i],\n\t\t\t\t\tclassName: 'button-page-length',\n\t\t\t\t\taction: function ( e, dt ) {\n\t\t\t\t\t\tdt.page.len( val ).draw();\n\t\t\t\t\t},\n\t\t\t\t\tinit: function ( dt, node, conf ) {\n\t\t\t\t\t\tvar that = this;\n\t\t\t\t\t\tvar fn = function () {\n\t\t\t\t\t\t\tthat.active( dt.page.len() === val );\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tdt.on( 'length.dt'+conf.namespace, fn );\n\t\t\t\t\t\tfn();\n\t\t\t\t\t},\n\t\t\t\t\tdestroy: function ( dt, node, conf ) {\n\t\t\t\t\t\tdt.off( 'length.dt'+conf.namespace );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t} ),\n\t\t\tinit: function ( dt, node, conf ) {\n\t\t\t\tvar that = this;\n\t\t\t\tdt.on( 'length.dt'+conf.namespace, function () {\n\t\t\t\t\tthat.text( conf.text );\n\t\t\t\t} );\n\t\t\t},\n\t\t\tdestroy: function ( dt, node, conf ) {\n\t\t\t\tdt.off( 'length.dt'+conf.namespace );\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables API\n *\n * For complete documentation, please refer to the docs/api directory or the\n * DataTables site\n */\n\n// Buttons group and individual button selector\nDataTable.Api.register( 'buttons()', function ( group, selector ) {\n\t// Argument shifting\n\tif ( selector === undefined ) {\n\t\tselector = group;\n\t\tgroup = undefined;\n\t}\n\n\tthis.selector.buttonGroup = group;\n\n\tvar res = this.iterator( true, 'table', function ( ctx ) {\n\t\tif ( ctx._buttons ) {\n\t\t\treturn Buttons.buttonSelector(\n\t\t\t\tButtons.instanceSelector( group, ctx._buttons ),\n\t\t\t\tselector\n\t\t\t);\n\t\t}\n\t}, true );\n\n\tres._groupSelector = group;\n\treturn res;\n} );\n\n// Individual button selector\nDataTable.Api.register( 'button()', function ( group, selector ) {\n\t// just run buttons() and truncate\n\tvar buttons = this.buttons( group, selector );\n\n\tif ( buttons.length > 1 ) {\n\t\tbuttons.splice( 1, buttons.length );\n\t}\n\n\treturn buttons;\n} );\n\n// Active buttons\nDataTable.Api.registerPlural( 'buttons().active()', 'button().active()', function ( flag ) {\n\tif ( flag === undefined ) {\n\t\treturn this.map( function ( set ) {\n\t\t\treturn set.inst.active( set.node );\n\t\t} );\n\t}\n\n\treturn this.each( function ( set ) {\n\t\tset.inst.active( set.node, flag );\n\t} );\n} );\n\n// Get / set button action\nDataTable.Api.registerPlural( 'buttons().action()', 'button().action()', function ( action ) {\n\tif ( action === undefined ) {\n\t\treturn this.map( function ( set ) {\n\t\t\treturn set.inst.action( set.node );\n\t\t} );\n\t}\n\n\treturn this.each( function ( set ) {\n\t\tset.inst.action( set.node, action );\n\t} );\n} );\n\n// Enable / disable buttons\nDataTable.Api.register( ['buttons().enable()', 'button().enable()'], function ( flag ) {\n\treturn this.each( function ( set ) {\n\t\tset.inst.enable( set.node, flag );\n\t} );\n} );\n\n// Disable buttons\nDataTable.Api.register( ['buttons().disable()', 'button().disable()'], function () {\n\treturn this.each( function ( set ) {\n\t\tset.inst.disable( set.node );\n\t} );\n} );\n\n// Get button nodes\nDataTable.Api.registerPlural( 'buttons().nodes()', 'button().node()', function () {\n\tvar jq = $();\n\n\t// jQuery will automatically reduce duplicates to a single entry\n\t$( this.each( function ( set ) {\n\t\tjq = jq.add( set.inst.node( set.node ) );\n\t} ) );\n\n\treturn jq;\n} );\n\n// Get / set button processing state\nDataTable.Api.registerPlural( 'buttons().processing()', 'button().processing()', function ( flag ) {\n\tif ( flag === undefined ) {\n\t\treturn this.map( function ( set ) {\n\t\t\treturn set.inst.processing( set.node );\n\t\t} );\n\t}\n\n\treturn this.each( function ( set ) {\n\t\tset.inst.processing( set.node, flag );\n\t} );\n} );\n\n// Get / set button text (i.e. the button labels)\nDataTable.Api.registerPlural( 'buttons().text()', 'button().text()', function ( label ) {\n\tif ( label === undefined ) {\n\t\treturn this.map( function ( set ) {\n\t\t\treturn set.inst.text( set.node );\n\t\t} );\n\t}\n\n\treturn this.each( function ( set ) {\n\t\tset.inst.text( set.node, label );\n\t} );\n} );\n\n// Trigger a button's action\nDataTable.Api.registerPlural( 'buttons().trigger()', 'button().trigger()', function () {\n\treturn this.each( function ( set ) {\n\t\tset.inst.node( set.node ).trigger( 'click' );\n\t} );\n} );\n\n// Get the container elements\nDataTable.Api.registerPlural( 'buttons().containers()', 'buttons().container()', function () {\n\tvar jq = $();\n\tvar groupSelector = this._groupSelector;\n\n\t// We need to use the group selector directly, since if there are no buttons\n\t// the result set will be empty\n\tthis.iterator( true, 'table', function ( ctx ) {\n\t\tif ( ctx._buttons ) {\n\t\t\tvar insts = Buttons.instanceSelector( groupSelector, ctx._buttons );\n\n\t\t\tfor ( var i=0, ien=insts.length ; i<ien ; i++ ) {\n\t\t\t\tjq = jq.add( insts[i].container() );\n\t\t\t}\n\t\t}\n\t} );\n\n\treturn jq;\n} );\n\n// Add a new button\nDataTable.Api.register( 'button().add()', function ( idx, conf ) {\n\tvar ctx = this.context;\n\n\t// Don't use `this` as it could be empty - select the instances directly\n\tif ( ctx.length ) {\n\t\tvar inst = Buttons.instanceSelector( this._groupSelector, ctx[0]._buttons );\n\n\t\tif ( inst.length ) {\n\t\t\tinst[0].add( conf, idx );\n\t\t}\n\t}\n\n\treturn this.button( this._groupSelector, idx );\n} );\n\n// Destroy the button sets selected\nDataTable.Api.register( 'buttons().destroy()', function () {\n\tthis.pluck( 'inst' ).unique().each( function ( inst ) {\n\t\tinst.destroy();\n\t} );\n\n\treturn this;\n} );\n\n// Remove a button\nDataTable.Api.registerPlural( 'buttons().remove()', 'buttons().remove()', function () {\n\tthis.each( function ( set ) {\n\t\tset.inst.remove( set.node );\n\t} );\n\n\treturn this;\n} );\n\n// Information box that can be used by buttons\nvar _infoTimer;\nDataTable.Api.register( 'buttons.info()', function ( title, message, time ) {\n\tvar that = this;\n\n\tif ( title === false ) {\n\t\t$('#datatables_buttons_info').fadeOut( function () {\n\t\t\t$(this).remove();\n\t\t} );\n\t\tclearTimeout( _infoTimer );\n\t\t_infoTimer = null;\n\n\t\treturn this;\n\t}\n\n\tif ( _infoTimer ) {\n\t\tclearTimeout( _infoTimer );\n\t}\n\n\tif ( $('#datatables_buttons_info').length ) {\n\t\t$('#datatables_buttons_info').remove();\n\t}\n\n\ttitle = title ? '<h2>'+title+'</h2>' : '';\n\n\t$('<div id=\"datatables_buttons_info\" class=\"dt-button-info\"/>')\n\t\t.html( title )\n\t\t.append( $('<div/>')[ typeof message === 'string' ? 'html' : 'append' ]( message ) )\n\t\t.css( 'display', 'none' )\n\t\t.appendTo( 'body' )\n\t\t.fadeIn();\n\n\tif ( time !== undefined && time !== 0 ) {\n\t\t_infoTimer = setTimeout( function () {\n\t\t\tthat.buttons.info( false );\n\t\t}, time );\n\t}\n\n\treturn this;\n} );\n\n// Get data from the table for export - this is common to a number of plug-in\n// buttons so it is included in the Buttons core library\nDataTable.Api.register( 'buttons.exportData()', function ( options ) {\n\tif ( this.context.length ) {\n\t\treturn _exportData( new DataTable.Api( this.context[0] ), options );\n\t}\n} );\n\n// Get information about the export that is common to many of the export data\n// types (DRY)\nDataTable.Api.register( 'buttons.exportInfo()', function ( conf ) {\n\tif ( ! conf ) {\n\t\tconf = {};\n\t}\n\n\treturn {\n\t\tfilename: _filename( conf ),\n\t\ttitle: _title( conf ),\n\t\tmessageTop: _message(this, conf.message || conf.messageTop, 'top'),\n\t\tmessageBottom: _message(this, conf.messageBottom, 'bottom')\n\t};\n} );\n\n\n\n/**\n * Get the file name for an exported file.\n *\n * @param {object}\tconfig Button configuration\n * @param {boolean} incExtension Include the file name extension\n */\nvar _filename = function ( config )\n{\n\t// Backwards compatibility\n\tvar filename = config.filename === '*' && config.title !== '*' && config.title !== undefined && config.title !== null && config.title !== '' ?\n\t\tconfig.title :\n\t\tconfig.filename;\n\n\tif ( typeof filename === 'function' ) {\n\t\tfilename = filename();\n\t}\n\n\tif ( filename === undefined || filename === null ) {\n\t\treturn null;\n\t}\n\n\tif ( filename.indexOf( '*' ) !== -1 ) {\n\t\tfilename = $.trim( filename.replace( '*', $('head > title').text() ) );\n\t}\n\n\t// Strip characters which the OS will object to\n\tfilename = filename.replace(/[^a-zA-Z0-9_\\u00A1-\\uFFFF\\.,\\-_ !\\(\\)]/g, \"\");\n\n\tvar extension = _stringOrFunction( config.extension );\n\tif ( ! extension ) {\n\t\textension = '';\n\t}\n\n\treturn filename + extension;\n};\n\n/**\n * Simply utility method to allow parameters to be given as a function\n *\n * @param {undefined|string|function} option Option\n * @return {null|string} Resolved value\n */\nvar _stringOrFunction = function ( option )\n{\n\tif ( option === null || option === undefined ) {\n\t\treturn null;\n\t}\n\telse if ( typeof option === 'function' ) {\n\t\treturn option();\n\t}\n\treturn option;\n};\n\n/**\n * Get the title for an exported file.\n *\n * @param {object} config\tButton configuration\n */\nvar _title = function ( config )\n{\n\tvar title = _stringOrFunction( config.title );\n\n\treturn title === null ?\n\t\tnull : title.indexOf( '*' ) !== -1 ?\n\t\t\ttitle.replace( '*', $('head > title').text() || 'Exported data' ) :\n\t\t\ttitle;\n};\n\nvar _message = function ( dt, option, position )\n{\n\tvar message = _stringOrFunction( option );\n\tif ( message === null ) {\n\t\treturn null;\n\t}\n\n\tvar caption = $('caption', dt.table().container()).eq(0);\n\tif ( message === '*' ) {\n\t\tvar side = caption.css( 'caption-side' );\n\t\tif ( side !== position ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn caption.length ?\n\t\t\tcaption.text() :\n\t\t\t'';\n\t}\n\n\treturn message;\n};\n\n\n\n\n\n\n\nvar _exportTextarea = $('<textarea/>')[0];\nvar _exportData = function ( dt, inOpts )\n{\n\tvar config = $.extend( true, {}, {\n\t\trows:           null,\n\t\tcolumns:        '',\n\t\tmodifier:       {\n\t\t\tsearch: 'applied',\n\t\t\torder:  'applied'\n\t\t},\n\t\torthogonal:     'display',\n\t\tstripHtml:      true,\n\t\tstripNewlines:  true,\n\t\tdecodeEntities: true,\n\t\ttrim:           true,\n\t\tformat:         {\n\t\t\theader: function ( d ) {\n\t\t\t\treturn strip( d );\n\t\t\t},\n\t\t\tfooter: function ( d ) {\n\t\t\t\treturn strip( d );\n\t\t\t},\n\t\t\tbody: function ( d ) {\n\t\t\t\treturn strip( d );\n\t\t\t}\n\t\t},\n\t\tcustomizeData: null\n\t}, inOpts );\n\n\tvar strip = function ( str ) {\n\t\tif ( typeof str !== 'string' ) {\n\t\t\treturn str;\n\t\t}\n\n\t\t// Always remove script tags\n\t\tstr = str.replace( /<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi, '' );\n\n\t\t// Always remove comments\n\t\tstr = str.replace( /<!\\-\\-.*?\\-\\->/g, '' );\n\n\t\tif ( config.stripHtml ) {\n\t\t\tstr = str.replace( /<[^>]*>/g, '' );\n\t\t}\n\n\t\tif ( config.trim ) {\n\t\t\tstr = str.replace( /^\\s+|\\s+$/g, '' );\n\t\t}\n\n\t\tif ( config.stripNewlines ) {\n\t\t\tstr = str.replace( /\\n/g, ' ' );\n\t\t}\n\n\t\tif ( config.decodeEntities ) {\n\t\t\t_exportTextarea.innerHTML = str;\n\t\t\tstr = _exportTextarea.value;\n\t\t}\n\n\t\treturn str;\n\t};\n\n\n\tvar header = dt.columns( config.columns ).indexes().map( function (idx) {\n\t\tvar el = dt.column( idx ).header();\n\t\treturn config.format.header( el.innerHTML, idx, el );\n\t} ).toArray();\n\n\tvar footer = dt.table().footer() ?\n\t\tdt.columns( config.columns ).indexes().map( function (idx) {\n\t\t\tvar el = dt.column( idx ).footer();\n\t\t\treturn config.format.footer( el ? el.innerHTML : '', idx, el );\n\t\t} ).toArray() :\n\t\tnull;\n\t\n\t// If Select is available on this table, and any rows are selected, limit the export\n\t// to the selected rows. If no rows are selected, all rows will be exported. Specify\n\t// a `selected` modifier to control directly.\n\tvar modifier = $.extend( {}, config.modifier );\n\tif ( dt.select && typeof dt.select.info === 'function' && modifier.selected === undefined ) {\n\t\tif ( dt.rows( config.rows, $.extend( { selected: true }, modifier ) ).any() ) {\n\t\t\t$.extend( modifier, { selected: true } )\n\t\t}\n\t}\n\n\tvar rowIndexes = dt.rows( config.rows, modifier ).indexes().toArray();\n\tvar selectedCells = dt.cells( rowIndexes, config.columns );\n\tvar cells = selectedCells\n\t\t.render( config.orthogonal )\n\t\t.toArray();\n\tvar cellNodes = selectedCells\n\t\t.nodes()\n\t\t.toArray();\n\n\tvar columns = header.length;\n\tvar rows = columns > 0 ? cells.length / columns : 0;\n\tvar body = [];\n\tvar cellCounter = 0;\n\n\tfor ( var i=0, ien=rows ; i<ien ; i++ ) {\n\t\tvar row = [ columns ];\n\n\t\tfor ( var j=0 ; j<columns ; j++ ) {\n\t\t\trow[j] = config.format.body( cells[ cellCounter ], i, j, cellNodes[ cellCounter ] );\n\t\t\tcellCounter++;\n\t\t}\n\n\t\tbody[i] = row;\n\t}\n\n\tvar data = {\n\t\theader: header,\n\t\tfooter: footer,\n\t\tbody:   body\n\t};\n\n\tif ( config.customizeData ) {\n\t\tconfig.customizeData( data );\n\t}\n\n\treturn data;\n};\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables interface\n */\n\n// Attach to DataTables objects for global access\n$.fn.dataTable.Buttons = Buttons;\n$.fn.DataTable.Buttons = Buttons;\n\n\n\n// DataTables creation - check if the buttons have been defined for this table,\n// they will have been if the `B` option was used in `dom`, otherwise we should\n// create the buttons instance here so they can be inserted into the document\n// using the API. Listen for `init` for compatibility with pre 1.10.10, but to\n// be removed in future.\n$(document).on( 'init.dt plugin-init.dt', function (e, settings) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar opts = settings.oInit.buttons || DataTable.defaults.buttons;\n\n\tif ( opts && ! settings._buttons ) {\n\t\tnew Buttons( settings, opts ).container();\n\t}\n} );\n\nfunction _init ( settings ) {\n\tvar api = new DataTable.Api( settings );\n\tvar opts = api.init().buttons || DataTable.defaults.buttons;\n\n\treturn new Buttons( api, opts ).container();\n}\n\n// DataTables `dom` feature option\nDataTable.ext.feature.push( {\n\tfnInit: _init,\n\tcFeature: \"B\"\n} );\n\n// DataTables 2 layout feature\nif ( DataTable.ext.features ) {\n\tDataTable.ext.features.register( 'buttons', _init );\n}\n\n\nreturn Buttons;\n}));\n"
  },
  {
    "path": "static/js/DataTables/ColReorder-1.5.0/css/colReorder.bootstrap.css",
    "content": "table.DTCR_clonedTable.dataTable {\n  position: absolute !important;\n  background-color: rgba(255, 255, 255, 0.7);\n  z-index: 202;\n}\n\ndiv.DTCR_pointer {\n  width: 1px;\n  background-color: #337ab7;\n  z-index: 201;\n}\n"
  },
  {
    "path": "static/js/DataTables/ColReorder-1.5.0/css/colReorder.bootstrap4.css",
    "content": "table.DTCR_clonedTable.dataTable {\n  position: absolute !important;\n  background-color: rgba(255, 255, 255, 0.7);\n  z-index: 202;\n}\n\ndiv.DTCR_pointer {\n  width: 1px;\n  background-color: #0275d8;\n  z-index: 201;\n}\n"
  },
  {
    "path": "static/js/DataTables/ColReorder-1.5.0/css/colReorder.dataTables.css",
    "content": "table.DTCR_clonedTable.dataTable {\n  position: absolute !important;\n  background-color: rgba(255, 255, 255, 0.7);\n  z-index: 202;\n}\n\ndiv.DTCR_pointer {\n  width: 1px;\n  background-color: #0259C4;\n  z-index: 201;\n}\n"
  },
  {
    "path": "static/js/DataTables/ColReorder-1.5.0/css/colReorder.foundation.css",
    "content": "table.DTCR_clonedTable.dataTable {\n  position: absolute !important;\n  background-color: rgba(255, 255, 255, 0.7);\n  z-index: 202;\n}\n\ndiv.DTCR_pointer {\n  width: 1px;\n  background-color: #008CBA;\n  z-index: 201;\n}\n"
  },
  {
    "path": "static/js/DataTables/ColReorder-1.5.0/css/colReorder.jqueryui.css",
    "content": "table.DTCR_clonedTable.dataTable {\n  position: absolute !important;\n  background-color: rgba(255, 255, 255, 0.7);\n  z-index: 202;\n}\n\ndiv.DTCR_pointer {\n  width: 1px;\n  background-color: #0259C4;\n  z-index: 201;\n}\n"
  },
  {
    "path": "static/js/DataTables/ColReorder-1.5.0/css/colReorder.semanticui.css",
    "content": "table.DTCR_clonedTable.dataTable {\n  position: absolute !important;\n  background-color: rgba(255, 255, 255, 0.7);\n  z-index: 202;\n}\n\ndiv.DTCR_pointer {\n  width: 1px;\n  background-color: #888;\n  z-index: 201;\n}\n"
  },
  {
    "path": "static/js/DataTables/ColReorder-1.5.0/js/colReorder.bootstrap.js",
    "content": "/*! Bootstrap 3 styling wrapper for ColReorder\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs', 'datatables.net-colreorder'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.ColReorder ) {\n\t\t\t\trequire('datatables.net-colreorder')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/ColReorder-1.5.0/js/colReorder.bootstrap4.js",
    "content": "/*! Bootstrap 4 styling wrapper for ColReorder\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs4', 'datatables.net-colreorder'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs4')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.ColReorder ) {\n\t\t\t\trequire('datatables.net-colreorder')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/ColReorder-1.5.0/js/colReorder.dataTables.js",
    "content": "/*! DataTables styling wrapper for ColReorder\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-dt', 'datatables.net-colreorder'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-dt')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.ColReorder ) {\n\t\t\t\trequire('datatables.net-colreorder')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/ColReorder-1.5.0/js/colReorder.foundation.js",
    "content": "/*! Bootstrap 4 styling wrapper for ColReorder\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-zf', 'datatables.net-colreorder'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-zf')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.ColReorder ) {\n\t\t\t\trequire('datatables.net-colreorder')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/ColReorder-1.5.0/js/colReorder.jqueryui.js",
    "content": "/*! jQuery UI styling wrapper for ColReorder\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-jqui', 'datatables.net-colreorder'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-jqui')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.ColReorder ) {\n\t\t\t\trequire('datatables.net-colreorder')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/ColReorder-1.5.0/js/colReorder.semanicui.js",
    "content": "/*! Semanic UI styling wrapper for ColReorder\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-se', 'datatables.net-colreorder'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-se')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.ColReorder ) {\n\t\t\t\trequire('datatables.net-colreorder')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/ColReorder-1.5.0/js/colReorder.semanticui.js",
    "content": "/*! Semanic UI styling wrapper for ColReorder\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-se', 'datatables.net-colreorder'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-se')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.ColReorder ) {\n\t\t\t\trequire('datatables.net-colreorder')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/ColReorder-1.5.0/js/dataTables.colReorder.js",
    "content": "/*! ColReorder 1.5.0\n * ©2010-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     ColReorder\n * @description Provide the ability to reorder columns in a DataTable\n * @version     1.5.0\n * @file        dataTables.colReorder.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2010-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/**\n * Switch the key value pairing of an index array to be value key (i.e. the old value is now the\n * key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ].\n *  @method  fnInvertKeyValues\n *  @param   array aIn Array to switch around\n *  @returns array\n */\nfunction fnInvertKeyValues( aIn )\n{\n\tvar aRet=[];\n\tfor ( var i=0, iLen=aIn.length ; i<iLen ; i++ )\n\t{\n\t\taRet[ aIn[i] ] = i;\n\t}\n\treturn aRet;\n}\n\n\n/**\n * Modify an array by switching the position of two elements\n *  @method  fnArraySwitch\n *  @param   array aArray Array to consider, will be modified by reference (i.e. no return)\n *  @param   int iFrom From point\n *  @param   int iTo Insert point\n *  @returns void\n */\nfunction fnArraySwitch( aArray, iFrom, iTo )\n{\n\tvar mStore = aArray.splice( iFrom, 1 )[0];\n\taArray.splice( iTo, 0, mStore );\n}\n\n\n/**\n * Switch the positions of nodes in a parent node (note this is specifically designed for\n * table rows). Note this function considers all element nodes under the parent!\n *  @method  fnDomSwitch\n *  @param   string sTag Tag to consider\n *  @param   int iFrom Element to move\n *  @param   int Point to element the element to (before this point), can be null for append\n *  @returns void\n */\nfunction fnDomSwitch( nParent, iFrom, iTo )\n{\n\tvar anTags = [];\n\tfor ( var i=0, iLen=nParent.childNodes.length ; i<iLen ; i++ )\n\t{\n\t\tif ( nParent.childNodes[i].nodeType == 1 )\n\t\t{\n\t\t\tanTags.push( nParent.childNodes[i] );\n\t\t}\n\t}\n\tvar nStore = anTags[ iFrom ];\n\n\tif ( iTo !== null )\n\t{\n\t\tnParent.insertBefore( nStore, anTags[iTo] );\n\t}\n\telse\n\t{\n\t\tnParent.appendChild( nStore );\n\t}\n}\n\n\n/**\n * Plug-in for DataTables which will reorder the internal column structure by taking the column\n * from one position (iFrom) and insert it into a given point (iTo).\n *  @method  $.fn.dataTableExt.oApi.fnColReorder\n *  @param   object oSettings DataTables settings object - automatically added by DataTables!\n *  @param   int iFrom Take the column to be repositioned from this point\n *  @param   int iTo and insert it into this point\n *  @param   bool drop Indicate if the reorder is the final one (i.e. a drop)\n *    not a live reorder\n *  @param   bool invalidateRows speeds up processing if false passed\n *  @returns void\n */\n$.fn.dataTableExt.oApi.fnColReorder = function ( oSettings, iFrom, iTo, drop, invalidateRows )\n{\n\tvar i, iLen, j, jLen, jen, iCols=oSettings.aoColumns.length, nTrs, oCol;\n\tvar attrMap = function ( obj, prop, mapping ) {\n\t\tif ( ! obj[ prop ] || typeof obj[ prop ] === 'function' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar a = obj[ prop ].split('.');\n\t\tvar num = a.shift();\n\n\t\tif ( isNaN( num*1 ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tobj[ prop ] = mapping[ num*1 ]+'.'+a.join('.');\n\t};\n\n\t/* Sanity check in the input */\n\tif ( iFrom == iTo )\n\t{\n\t\t/* Pointless reorder */\n\t\treturn;\n\t}\n\n\tif ( iFrom < 0 || iFrom >= iCols )\n\t{\n\t\tthis.oApi._fnLog( oSettings, 1, \"ColReorder 'from' index is out of bounds: \"+iFrom );\n\t\treturn;\n\t}\n\n\tif ( iTo < 0 || iTo >= iCols )\n\t{\n\t\tthis.oApi._fnLog( oSettings, 1, \"ColReorder 'to' index is out of bounds: \"+iTo );\n\t\treturn;\n\t}\n\n\t/*\n\t * Calculate the new column array index, so we have a mapping between the old and new\n\t */\n\tvar aiMapping = [];\n\tfor ( i=0, iLen=iCols ; i<iLen ; i++ )\n\t{\n\t\taiMapping[i] = i;\n\t}\n\tfnArraySwitch( aiMapping, iFrom, iTo );\n\tvar aiInvertMapping = fnInvertKeyValues( aiMapping );\n\n\n\t/*\n\t * Convert all internal indexing to the new column order indexes\n\t */\n\t/* Sorting */\n\tfor ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )\n\t{\n\t\toSettings.aaSorting[i][0] = aiInvertMapping[ oSettings.aaSorting[i][0] ];\n\t}\n\n\t/* Fixed sorting */\n\tif ( oSettings.aaSortingFixed !== null )\n\t{\n\t\tfor ( i=0, iLen=oSettings.aaSortingFixed.length ; i<iLen ; i++ )\n\t\t{\n\t\t\toSettings.aaSortingFixed[i][0] = aiInvertMapping[ oSettings.aaSortingFixed[i][0] ];\n\t\t}\n\t}\n\n\t/* Data column sorting (the column which the sort for a given column should take place on) */\n\tfor ( i=0, iLen=iCols ; i<iLen ; i++ )\n\t{\n\t\toCol = oSettings.aoColumns[i];\n\t\tfor ( j=0, jLen=oCol.aDataSort.length ; j<jLen ; j++ )\n\t\t{\n\t\t\toCol.aDataSort[j] = aiInvertMapping[ oCol.aDataSort[j] ];\n\t\t}\n\n\t\t// Update the column indexes\n\t\toCol.idx = aiInvertMapping[ oCol.idx ];\n\t}\n\n\t// Update 1.10 optimised sort class removal variable\n\t$.each( oSettings.aLastSort, function (i, val) {\n\t\toSettings.aLastSort[i].src = aiInvertMapping[ val.src ];\n\t} );\n\n\t/* Update the Get and Set functions for each column */\n\tfor ( i=0, iLen=iCols ; i<iLen ; i++ )\n\t{\n\t\toCol = oSettings.aoColumns[i];\n\n\t\tif ( typeof oCol.mData == 'number' ) {\n\t\t\toCol.mData = aiInvertMapping[ oCol.mData ];\n\t\t}\n\t\telse if ( $.isPlainObject( oCol.mData ) ) {\n\t\t\t// HTML5 data sourced\n\t\t\tattrMap( oCol.mData, '_',      aiInvertMapping );\n\t\t\tattrMap( oCol.mData, 'filter', aiInvertMapping );\n\t\t\tattrMap( oCol.mData, 'sort',   aiInvertMapping );\n\t\t\tattrMap( oCol.mData, 'type',   aiInvertMapping );\n\t\t}\n\t}\n\n\t/*\n\t * Move the DOM elements\n\t */\n\tif ( oSettings.aoColumns[iFrom].bVisible )\n\t{\n\t\t/* Calculate the current visible index and the point to insert the node before. The insert\n\t\t * before needs to take into account that there might not be an element to insert before,\n\t\t * in which case it will be null, and an appendChild should be used\n\t\t */\n\t\tvar iVisibleIndex = this.oApi._fnColumnIndexToVisible( oSettings, iFrom );\n\t\tvar iInsertBeforeIndex = null;\n\n\t\ti = iTo < iFrom ? iTo : iTo + 1;\n\t\twhile ( iInsertBeforeIndex === null && i < iCols )\n\t\t{\n\t\t\tiInsertBeforeIndex = this.oApi._fnColumnIndexToVisible( oSettings, i );\n\t\t\ti++;\n\t\t}\n\n\t\t/* Header */\n\t\tnTrs = oSettings.nTHead.getElementsByTagName('tr');\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );\n\t\t}\n\n\t\t/* Footer */\n\t\tif ( oSettings.nTFoot !== null )\n\t\t{\n\t\t\tnTrs = oSettings.nTFoot.getElementsByTagName('tr');\n\t\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );\n\t\t\t}\n\t\t}\n\n\t\t/* Body */\n\t\tfor ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( oSettings.aoData[i].nTr !== null )\n\t\t\t{\n\t\t\t\tfnDomSwitch( oSettings.aoData[i].nTr, iVisibleIndex, iInsertBeforeIndex );\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t * Move the internal array elements\n\t */\n\t/* Columns */\n\tfnArraySwitch( oSettings.aoColumns, iFrom, iTo );\n\n\t// regenerate the get / set functions\n\tfor ( i=0, iLen=iCols ; i<iLen ; i++ ) {\n\t\toSettings.oApi._fnColumnOptions( oSettings, i, {} );\n\t}\n\n\t/* Search columns */\n\tfnArraySwitch( oSettings.aoPreSearchCols, iFrom, iTo );\n\n\t/* Array array - internal data anodes cache */\n\tfor ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )\n\t{\n\t\tvar data = oSettings.aoData[i];\n\t\tvar cells = data.anCells;\n\n\t\tif ( cells ) {\n\t\t\tfnArraySwitch( cells, iFrom, iTo );\n\n\t\t\t// Longer term, should this be moved into the DataTables' invalidate\n\t\t\t// methods?\n\t\t\tfor ( j=0, jen=cells.length ; j<jen ; j++ ) {\n\t\t\t\tif ( cells[j] && cells[j]._DT_CellIndex ) {\n\t\t\t\t\tcells[j]._DT_CellIndex.column = j;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// For DOM sourced data, the invalidate will reread the cell into\n\t\t// the data array, but for data sources as an array, they need to\n\t\t// be flipped\n\t\tif ( data.src !== 'dom' && $.isArray( data._aData ) ) {\n\t\t\tfnArraySwitch( data._aData, iFrom, iTo );\n\t\t}\n\t}\n\n\t/* Reposition the header elements in the header layout array */\n\tfor ( i=0, iLen=oSettings.aoHeader.length ; i<iLen ; i++ )\n\t{\n\t\tfnArraySwitch( oSettings.aoHeader[i], iFrom, iTo );\n\t}\n\n\tif ( oSettings.aoFooter !== null )\n\t{\n\t\tfor ( i=0, iLen=oSettings.aoFooter.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfnArraySwitch( oSettings.aoFooter[i], iFrom, iTo );\n\t\t}\n\t}\n\n\tif ( invalidateRows || invalidateRows === undefined )\n\t{\n\t\t$.fn.dataTable.Api( oSettings ).rows().invalidate();\n\t}\n\n\t/*\n\t * Update DataTables' event handlers\n\t */\n\n\t/* Sort listener */\n\tfor ( i=0, iLen=iCols ; i<iLen ; i++ )\n\t{\n\t\t$(oSettings.aoColumns[i].nTh).off('.DT');\n\t\tthis.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );\n\t}\n\n\n\t/* Fire an event so other plug-ins can update */\n\t$(oSettings.oInstance).trigger( 'column-reorder.dt', [ oSettings, {\n\t\tfrom: iFrom,\n\t\tto: iTo,\n\t\tmapping: aiInvertMapping,\n\t\tdrop: drop,\n\n\t\t// Old style parameters for compatibility\n\t\tiFrom: iFrom,\n\t\tiTo: iTo,\n\t\taiInvertMapping: aiInvertMapping\n\t} ] );\n};\n\n/**\n * ColReorder provides column visibility control for DataTables\n * @class ColReorder\n * @constructor\n * @param {object} dt DataTables settings object\n * @param {object} opts ColReorder options\n */\nvar ColReorder = function( dt, opts )\n{\n\tvar settings = new $.fn.dataTable.Api( dt ).settings()[0];\n\n\t// Ensure that we can't initialise on the same table twice\n\tif ( settings._colReorder ) {\n\t\treturn settings._colReorder;\n\t}\n\n\t// Allow the options to be a boolean for defaults\n\tif ( opts === true ) {\n\t\topts = {};\n\t}\n\n\t// Convert from camelCase to Hungarian, just as DataTables does\n\tvar camelToHungarian = $.fn.dataTable.camelToHungarian;\n\tif ( camelToHungarian ) {\n\t\tcamelToHungarian( ColReorder.defaults, ColReorder.defaults, true );\n\t\tcamelToHungarian( ColReorder.defaults, opts || {} );\n\t}\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Public class variables\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\t/**\n\t * @namespace Settings object which contains customisable information for ColReorder instance\n\t */\n\tthis.s = {\n\t\t/**\n\t\t * DataTables settings object\n\t\t *  @property dt\n\t\t *  @type     Object\n\t\t *  @default  null\n\t\t */\n\t\t\"dt\": null,\n\n\t\t/**\n\t\t * Enable flag\n\t\t *  @property dt\n\t\t *  @type     Object\n\t\t *  @default  null\n\t\t */\n\t\t\"enable\": null,\n\n\t\t/**\n\t\t * Initialisation object used for this instance\n\t\t *  @property init\n\t\t *  @type     object\n\t\t *  @default  {}\n\t\t */\n\t\t\"init\": $.extend( true, {}, ColReorder.defaults, opts ),\n\n\t\t/**\n\t\t * Number of columns to fix (not allow to be reordered)\n\t\t *  @property fixed\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t */\n\t\t\"fixed\": 0,\n\n\t\t/**\n\t\t * Number of columns to fix counting from right (not allow to be reordered)\n\t\t *  @property fixedRight\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t */\n\t\t\"fixedRight\": 0,\n\n\t\t/**\n\t\t * Callback function for once the reorder has been done\n\t\t *  @property reorderCallback\n\t\t *  @type     function\n\t\t *  @default  null\n\t\t */\n\t\t\"reorderCallback\": null,\n\n\t\t/**\n\t\t * @namespace Information used for the mouse drag\n\t\t */\n\t\t\"mouse\": {\n\t\t\t\"startX\": -1,\n\t\t\t\"startY\": -1,\n\t\t\t\"offsetX\": -1,\n\t\t\t\"offsetY\": -1,\n\t\t\t\"target\": -1,\n\t\t\t\"targetIndex\": -1,\n\t\t\t\"fromIndex\": -1\n\t\t},\n\n\t\t/**\n\t\t * Information which is used for positioning the insert cusor and knowing where to do the\n\t\t * insert. Array of objects with the properties:\n\t\t *   x: x-axis position\n\t\t *   to: insert point\n\t\t *  @property aoTargets\n\t\t *  @type     array\n\t\t *  @default  []\n\t\t */\n\t\t\"aoTargets\": []\n\t};\n\n\n\t/**\n\t * @namespace Common and useful DOM elements for the class instance\n\t */\n\tthis.dom = {\n\t\t/**\n\t\t * Dragging element (the one the mouse is moving)\n\t\t *  @property drag\n\t\t *  @type     element\n\t\t *  @default  null\n\t\t */\n\t\t\"drag\": null,\n\n\t\t/**\n\t\t * The insert cursor\n\t\t *  @property pointer\n\t\t *  @type     element\n\t\t *  @default  null\n\t\t */\n\t\t\"pointer\": null\n\t};\n\n\t/* Constructor logic */\n\tthis.s.enable = this.s.init.bEnable;\n\tthis.s.dt = settings;\n\tthis.s.dt._colReorder = this;\n\tthis._fnConstruct();\n\n\treturn this;\n};\n\n\n\n$.extend( ColReorder.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Public methods\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\t/**\n\t * Enable / disable end user interaction\n\t */\n\tfnEnable: function ( flag )\n\t{\n\t\tif ( flag === false ) {\n\t\t\treturn fnDisable();\n\t\t}\n\n\t\tthis.s.enable = true;\n\t},\n\n\t/**\n\t * Disable end user interaction\n\t */\n\tfnDisable: function ()\n\t{\n\t\tthis.s.enable = false;\n\t},\n\n\t/**\n\t * Reset the column ordering to the original ordering that was detected on\n\t * start up.\n\t *  @return {this} Returns `this` for chaining.\n\t *\n\t *  @example\n\t *    // DataTables initialisation with ColReorder\n\t *    var table = $('#example').dataTable( {\n\t *        \"sDom\": 'Rlfrtip'\n\t *    } );\n\t *\n\t *    // Add click event to a button to reset the ordering\n\t *    $('#resetOrdering').click( function (e) {\n\t *        e.preventDefault();\n\t *        $.fn.dataTable.ColReorder( table ).fnReset();\n\t *    } );\n\t */\n\t\"fnReset\": function ()\n\t{\n\t\tthis._fnOrderColumns( this.fnOrder() );\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * `Deprecated` - Get the current order of the columns, as an array.\n\t *  @return {array} Array of column identifiers\n\t *  @deprecated `fnOrder` should be used in preference to this method.\n\t *      `fnOrder` acts as a getter/setter.\n\t */\n\t\"fnGetCurrentOrder\": function ()\n\t{\n\t\treturn this.fnOrder();\n\t},\n\n\t/**\n\t * Get the current order of the columns, as an array. Note that the values\n\t * given in the array are unique identifiers for each column. Currently\n\t * these are the original ordering of the columns that was detected on\n\t * start up, but this could potentially change in future.\n\t *  @return {array} Array of column identifiers\n\t *\n\t *  @example\n\t *    // Get column ordering for the table\n\t *    var order = $.fn.dataTable.ColReorder( dataTable ).fnOrder();\n\t *//**\n\t * Set the order of the columns, from the positions identified in the\n\t * ordering array given. Note that ColReorder takes a brute force approach\n\t * to reordering, so it is possible multiple reordering events will occur\n\t * before the final order is settled upon.\n\t *  @param {array} [set] Array of column identifiers in the new order. Note\n\t *    that every column must be included, uniquely, in this array.\n\t *  @return {this} Returns `this` for chaining.\n\t *\n\t *  @example\n\t *    // Swap the first and second columns\n\t *    $.fn.dataTable.ColReorder( dataTable ).fnOrder( [1, 0, 2, 3, 4] );\n\t *\n\t *  @example\n\t *    // Move the first column to the end for the table `#example`\n\t *    var curr = $.fn.dataTable.ColReorder( '#example' ).fnOrder();\n\t *    var first = curr.shift();\n\t *    curr.push( first );\n\t *    $.fn.dataTable.ColReorder( '#example' ).fnOrder( curr );\n\t *\n\t *  @example\n\t *    // Reverse the table's order\n\t *    $.fn.dataTable.ColReorder( '#example' ).fnOrder(\n\t *      $.fn.dataTable.ColReorder( '#example' ).fnOrder().reverse()\n\t *    );\n\t */\n\t\"fnOrder\": function ( set, original )\n\t{\n\t\tvar a = [], i, ien, j, jen;\n\t\tvar columns = this.s.dt.aoColumns;\n\n\t\tif ( set === undefined ){\n\t\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\t\ta.push( columns[i]._ColReorder_iOrigCol );\n\t\t\t}\n\n\t\t\treturn a;\n\t\t}\n\n\t\t// The order given is based on the original indexes, rather than the\n\t\t// existing ones, so we need to translate from the original to current\n\t\t// before then doing the order\n\t\tif ( original ) {\n\t\t\tvar order = this.fnOrder();\n\n\t\t\tfor ( i=0, ien=set.length ; i<ien ; i++ ) {\n\t\t\t\ta.push( $.inArray( set[i], order ) );\n\t\t\t}\n\n\t\t\tset = a;\n\t\t}\n\n\t\tthis._fnOrderColumns( fnInvertKeyValues( set ) );\n\n\t\treturn this;\n\t},\n\n\n\t/**\n\t * Convert from the original column index, to the original\n\t *\n\t * @param  {int|array} idx Index(es) to convert\n\t * @param  {string} dir Transpose direction - `fromOriginal` / `toCurrent`\n\t *   or `'toOriginal` / `fromCurrent`\n\t * @return {int|array}     Converted values\n\t */\n\tfnTranspose: function ( idx, dir )\n\t{\n\t\tif ( ! dir ) {\n\t\t\tdir = 'toCurrent';\n\t\t}\n\n\t\tvar order = this.fnOrder();\n\t\tvar columns = this.s.dt.aoColumns;\n\n\t\tif ( dir === 'toCurrent' ) {\n\t\t\t// Given an original index, want the current\n\t\t\treturn ! $.isArray( idx ) ?\n\t\t\t\t$.inArray( idx, order ) :\n\t\t\t\t$.map( idx, function ( index ) {\n\t\t\t\t\treturn $.inArray( index, order );\n\t\t\t\t} );\n\t\t}\n\t\telse {\n\t\t\t// Given a current index, want the original\n\t\t\treturn ! $.isArray( idx ) ?\n\t\t\t\tcolumns[idx]._ColReorder_iOrigCol :\n\t\t\t\t$.map( idx, function ( index ) {\n\t\t\t\t\treturn columns[index]._ColReorder_iOrigCol;\n\t\t\t\t} );\n\t\t}\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods (they are of course public in JS, but recommended as private)\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\t/**\n\t * Constructor logic\n\t *  @method  _fnConstruct\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnConstruct\": function ()\n\t{\n\t\tvar that = this;\n\t\tvar iLen = this.s.dt.aoColumns.length;\n\t\tvar table = this.s.dt.nTable;\n\t\tvar i;\n\n\t\t/* Columns discounted from reordering - counting left to right */\n\t\tif ( this.s.init.iFixedColumns )\n\t\t{\n\t\t\tthis.s.fixed = this.s.init.iFixedColumns;\n\t\t}\n\n\t\tif ( this.s.init.iFixedColumnsLeft )\n\t\t{\n\t\t\tthis.s.fixed = this.s.init.iFixedColumnsLeft;\n\t\t}\n\n\t\t/* Columns discounted from reordering - counting right to left */\n\t\tthis.s.fixedRight = this.s.init.iFixedColumnsRight ?\n\t\t\tthis.s.init.iFixedColumnsRight :\n\t\t\t0;\n\n\t\t/* Drop callback initialisation option */\n\t\tif ( this.s.init.fnReorderCallback )\n\t\t{\n\t\t\tthis.s.reorderCallback = this.s.init.fnReorderCallback;\n\t\t}\n\n\t\t/* Add event handlers for the drag and drop, and also mark the original column order */\n\t\tfor ( i = 0; i < iLen; i++ )\n\t\t{\n\t\t\tif ( i > this.s.fixed-1 && i < iLen - this.s.fixedRight )\n\t\t\t{\n\t\t\t\tthis._fnMouseListener( i, this.s.dt.aoColumns[i].nTh );\n\t\t\t}\n\n\t\t\t/* Mark the original column order for later reference */\n\t\t\tthis.s.dt.aoColumns[i]._ColReorder_iOrigCol = i;\n\t\t}\n\n\t\t/* State saving */\n\t\tthis.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {\n\t\t\tthat._fnStateSave.call( that, oData );\n\t\t}, \"ColReorder_State\" );\n\n\t\t/* An initial column order has been specified */\n\t\tvar aiOrder = null;\n\t\tif ( this.s.init.aiOrder )\n\t\t{\n\t\t\taiOrder = this.s.init.aiOrder.slice();\n\t\t}\n\n\t\t/* State loading, overrides the column order given */\n\t\tif ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' &&\n\t\t  this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length )\n\t\t{\n\t\t\taiOrder = this.s.dt.oLoadedState.ColReorder;\n\t\t}\n\n\t\t/* If we have an order to apply - do so */\n\t\tif ( aiOrder )\n\t\t{\n\t\t\t/* We might be called during or after the DataTables initialisation. If before, then we need\n\t\t\t * to wait until the draw is done, if after, then do what we need to do right away\n\t\t\t */\n\t\t\tif ( !that.s.dt._bInitComplete )\n\t\t\t{\n\t\t\t\tvar bDone = false;\n\t\t\t\t$(table).on( 'draw.dt.colReorder', function () {\n\t\t\t\t\tif ( !that.s.dt._bInitComplete && !bDone )\n\t\t\t\t\t{\n\t\t\t\t\t\tbDone = true;\n\t\t\t\t\t\tvar resort = fnInvertKeyValues( aiOrder );\n\t\t\t\t\t\tthat._fnOrderColumns.call( that, resort );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tvar resort = fnInvertKeyValues( aiOrder );\n\t\t\t\tthat._fnOrderColumns.call( that, resort );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tthis._fnSetColumnIndexes();\n\t\t}\n\n\t\t// Destroy clean up\n\t\t$(table).on( 'destroy.dt.colReorder', function () {\n\t\t\t$(table).off( 'destroy.dt.colReorder draw.dt.colReorder' );\n\n\t\t\t$.each( that.s.dt.aoColumns, function (i, column) {\n\t\t\t\t$(column.nTh).off('.ColReorder');\n\t\t\t\t$(column.nTh).removeAttr('data-column-index');\n\t\t\t} );\n\n\t\t\tthat.s.dt._colReorder = null;\n\t\t\tthat.s = null;\n\t\t} );\n\t},\n\n\n\t/**\n\t * Set the column order from an array\n\t *  @method  _fnOrderColumns\n\t *  @param   array a An array of integers which dictate the column order that should be applied\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnOrderColumns\": function ( a )\n\t{\n\t\tvar changed = false;\n\n\t\tif ( a.length != this.s.dt.aoColumns.length )\n\t\t{\n\t\t\tthis.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, \"ColReorder - array reorder does not \"+\n\t\t\t\t\"match known number of columns. Skipping.\" );\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar currIndex = $.inArray( i, a );\n\t\t\tif ( i != currIndex )\n\t\t\t{\n\t\t\t\t/* Reorder our switching array */\n\t\t\t\tfnArraySwitch( a, currIndex, i );\n\n\t\t\t\t/* Do the column reorder in the table */\n\t\t\t\tthis.s.dt.oInstance.fnColReorder( currIndex, i, true, false );\n\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\tthis._fnSetColumnIndexes();\n\n\t\t// Has anything actually changed? If not, then nothing else to do\n\t\tif ( ! changed ) {\n\t\t\treturn;\n\t\t}\n\n\t\t$.fn.dataTable.Api( this.s.dt ).rows().invalidate();\n\n\t\t/* When scrolling we need to recalculate the column sizes to allow for the shift */\n\t\tif ( this.s.dt.oScroll.sX !== \"\" || this.s.dt.oScroll.sY !== \"\" )\n\t\t{\n\t\t\tthis.s.dt.oInstance.fnAdjustColumnSizing( false );\n\t\t}\n\n\t\t/* Save the state */\n\t\tthis.s.dt.oInstance.oApi._fnSaveState( this.s.dt );\n\n\t\tif ( this.s.reorderCallback !== null )\n\t\t{\n\t\t\tthis.s.reorderCallback.call( this );\n\t\t}\n\t},\n\n\n\t/**\n\t * Because we change the indexes of columns in the table, relative to their starting point\n\t * we need to reorder the state columns to what they are at the starting point so we can\n\t * then rearrange them again on state load!\n\t *  @method  _fnStateSave\n\t *  @param   object oState DataTables state\n\t *  @returns string JSON encoded cookie string for DataTables\n\t *  @private\n\t */\n\t\"_fnStateSave\": function ( oState )\n\t{\n\t\tvar i, iLen, aCopy, iOrigColumn;\n\t\tvar oSettings = this.s.dt;\n\t\tvar columns = oSettings.aoColumns;\n\n\t\toState.ColReorder = [];\n\n\t\t/* Sorting */\n\t\tif ( oState.aaSorting ) {\n\t\t\t// 1.10.0-\n\t\t\tfor ( i=0 ; i<oState.aaSorting.length ; i++ ) {\n\t\t\t\toState.aaSorting[i][0] = columns[ oState.aaSorting[i][0] ]._ColReorder_iOrigCol;\n\t\t\t}\n\n\t\t\tvar aSearchCopy = $.extend( true, [], oState.aoSearchCols );\n\n\t\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tiOrigColumn = columns[i]._ColReorder_iOrigCol;\n\n\t\t\t\t/* Column filter */\n\t\t\t\toState.aoSearchCols[ iOrigColumn ] = aSearchCopy[i];\n\n\t\t\t\t/* Visibility */\n\t\t\t\toState.abVisCols[ iOrigColumn ] = columns[i].bVisible;\n\n\t\t\t\t/* Column reordering */\n\t\t\t\toState.ColReorder.push( iOrigColumn );\n\t\t\t}\n\t\t}\n\t\telse if ( oState.order ) {\n\t\t\t// 1.10.1+\n\t\t\tfor ( i=0 ; i<oState.order.length ; i++ ) {\n\t\t\t\toState.order[i][0] = columns[ oState.order[i][0] ]._ColReorder_iOrigCol;\n\t\t\t}\n\n\t\t\tvar stateColumnsCopy = $.extend( true, [], oState.columns );\n\n\t\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tiOrigColumn = columns[i]._ColReorder_iOrigCol;\n\n\t\t\t\t/* Columns */\n\t\t\t\toState.columns[ iOrigColumn ] = stateColumnsCopy[i];\n\n\t\t\t\t/* Column reordering */\n\t\t\t\toState.ColReorder.push( iOrigColumn );\n\t\t\t}\n\t\t}\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Mouse drop and drag\n\t */\n\n\t/**\n\t * Add a mouse down listener to a particluar TH element\n\t *  @method  _fnMouseListener\n\t *  @param   int i Column index\n\t *  @param   element nTh TH element clicked on\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnMouseListener\": function ( i, nTh )\n\t{\n\t\tvar that = this;\n\t\t$(nTh)\n\t\t\t.on( 'mousedown.ColReorder', function (e) {\n\t\t\t\tif ( that.s.enable ) {\n\t\t\t\t\tthat._fnMouseDown.call( that, e, nTh );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'touchstart.ColReorder', function (e) {\n\t\t\t\tif ( that.s.enable ) {\n\t\t\t\t\tthat._fnMouseDown.call( that, e, nTh );\n\t\t\t\t}\n\t\t\t} );\n\t},\n\n\n\t/**\n\t * Mouse down on a TH element in the table header\n\t *  @method  _fnMouseDown\n\t *  @param   event e Mouse event\n\t *  @param   element nTh TH element to be dragged\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnMouseDown\": function ( e, nTh )\n\t{\n\t\tvar that = this;\n\n\t\t/* Store information about the mouse position */\n\t\tvar target = $(e.target).closest('th, td');\n\t\tvar offset = target.offset();\n\t\tvar idx = parseInt( $(nTh).attr('data-column-index'), 10 );\n\n\t\tif ( idx === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.s.mouse.startX = this._fnCursorPosition( e, 'pageX' );\n\t\tthis.s.mouse.startY = this._fnCursorPosition( e, 'pageY' );\n\t\tthis.s.mouse.offsetX = this._fnCursorPosition( e, 'pageX' ) - offset.left;\n\t\tthis.s.mouse.offsetY = this._fnCursorPosition( e, 'pageY' ) - offset.top;\n\t\tthis.s.mouse.target = this.s.dt.aoColumns[ idx ].nTh;//target[0];\n\t\tthis.s.mouse.targetIndex = idx;\n\t\tthis.s.mouse.fromIndex = idx;\n\n\t\tthis._fnRegions();\n\n\t\t/* Add event handlers to the document */\n\t\t$(document)\n\t\t\t.on( 'mousemove.ColReorder touchmove.ColReorder', function (e) {\n\t\t\t\tthat._fnMouseMove.call( that, e );\n\t\t\t} )\n\t\t\t.on( 'mouseup.ColReorder touchend.ColReorder', function (e) {\n\t\t\t\tthat._fnMouseUp.call( that, e );\n\t\t\t} );\n\t},\n\n\n\t/**\n\t * Deal with a mouse move event while dragging a node\n\t *  @method  _fnMouseMove\n\t *  @param   event e Mouse event\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnMouseMove\": function ( e )\n\t{\n\t\tvar that = this;\n\n\t\tif ( this.dom.drag === null )\n\t\t{\n\t\t\t/* Only create the drag element if the mouse has moved a specific distance from the start\n\t\t\t * point - this allows the user to make small mouse movements when sorting and not have a\n\t\t\t * possibly confusing drag element showing up\n\t\t\t */\n\t\t\tif ( Math.pow(\n\t\t\t\tMath.pow(this._fnCursorPosition( e, 'pageX') - this.s.mouse.startX, 2) +\n\t\t\t\tMath.pow(this._fnCursorPosition( e, 'pageY') - this.s.mouse.startY, 2), 0.5 ) < 5 )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._fnCreateDragNode();\n\t\t}\n\n\t\t/* Position the element - we respect where in the element the click occured */\n\t\tthis.dom.drag.css( {\n\t\t\tleft: this._fnCursorPosition( e, 'pageX' ) - this.s.mouse.offsetX,\n\t\t\ttop: this._fnCursorPosition( e, 'pageY' ) - this.s.mouse.offsetY\n\t\t} );\n\n\t\t/* Based on the current mouse position, calculate where the insert should go */\n\t\tvar bSet = false;\n\t\tvar lastToIndex = this.s.mouse.toIndex;\n\n\t\tfor ( var i=1, iLen=this.s.aoTargets.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( this._fnCursorPosition(e, 'pageX') < this.s.aoTargets[i-1].x + ((this.s.aoTargets[i].x-this.s.aoTargets[i-1].x)/2) )\n\t\t\t{\n\t\t\t\tthis.dom.pointer.css( 'left', this.s.aoTargets[i-1].x );\n\t\t\t\tthis.s.mouse.toIndex = this.s.aoTargets[i-1].to;\n\t\t\t\tbSet = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// The insert element wasn't positioned in the array (less than\n\t\t// operator), so we put it at the end\n\t\tif ( !bSet )\n\t\t{\n\t\t\tthis.dom.pointer.css( 'left', this.s.aoTargets[this.s.aoTargets.length-1].x );\n\t\t\tthis.s.mouse.toIndex = this.s.aoTargets[this.s.aoTargets.length-1].to;\n\t\t}\n\n\t\t// Perform reordering if realtime updating is on and the column has moved\n\t\tif ( this.s.init.bRealtime && lastToIndex !== this.s.mouse.toIndex ) {\n\t\t\tthis.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex );\n\t\t\tthis.s.mouse.fromIndex = this.s.mouse.toIndex;\n\n\t\t\t// Not great for performance, but required to keep everything in alignment\n\t\t\tif ( this.s.dt.oScroll.sX !== \"\" || this.s.dt.oScroll.sY !== \"\" )\n\t\t\t{\n\t\t\t\tthis.s.dt.oInstance.fnAdjustColumnSizing( false );\n\t\t\t}\n\n\t\t\tthis._fnRegions();\n\t\t}\n\t},\n\n\n\t/**\n\t * Finish off the mouse drag and insert the column where needed\n\t *  @method  _fnMouseUp\n\t *  @param   event e Mouse event\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnMouseUp\": function ( e )\n\t{\n\t\tvar that = this;\n\n\t\t$(document).off( '.ColReorder' );\n\n\t\tif ( this.dom.drag !== null )\n\t\t{\n\t\t\t/* Remove the guide elements */\n\t\t\tthis.dom.drag.remove();\n\t\t\tthis.dom.pointer.remove();\n\t\t\tthis.dom.drag = null;\n\t\t\tthis.dom.pointer = null;\n\n\t\t\t/* Actually do the reorder */\n\t\t\tthis.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex, true );\n\t\t\tthis._fnSetColumnIndexes();\n\n\t\t\t/* When scrolling we need to recalculate the column sizes to allow for the shift */\n\t\t\tif ( this.s.dt.oScroll.sX !== \"\" || this.s.dt.oScroll.sY !== \"\" )\n\t\t\t{\n\t\t\t\tthis.s.dt.oInstance.fnAdjustColumnSizing( false );\n\t\t\t}\n\n\t\t\t/* Save the state */\n\t\t\tthis.s.dt.oInstance.oApi._fnSaveState( this.s.dt );\n\n\t\t\tif ( this.s.reorderCallback !== null )\n\t\t\t{\n\t\t\t\tthis.s.reorderCallback.call( this );\n\t\t\t}\n\t\t}\n\t},\n\n\n\t/**\n\t * Calculate a cached array with the points of the column inserts, and the\n\t * 'to' points\n\t *  @method  _fnRegions\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnRegions\": function ()\n\t{\n\t\tvar aoColumns = this.s.dt.aoColumns;\n\n\t\tthis.s.aoTargets.splice( 0, this.s.aoTargets.length );\n\n\t\tthis.s.aoTargets.push( {\n\t\t\t\"x\":  $(this.s.dt.nTable).offset().left,\n\t\t\t\"to\": 0\n\t\t} );\n\n\t\tvar iToPoint = 0;\n\t\tvar total = this.s.aoTargets[0].x;\n\n\t\tfor ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\t/* For the column / header in question, we want it's position to remain the same if the\n\t\t\t * position is just to it's immediate left or right, so we only increment the counter for\n\t\t\t * other columns\n\t\t\t */\n\t\t\tif ( i != this.s.mouse.fromIndex )\n\t\t\t{\n\t\t\t\tiToPoint++;\n\t\t\t}\n\n\t\t\tif ( aoColumns[i].bVisible && aoColumns[i].nTh.style.display !=='none' )\n\t\t\t{\n\t\t\t\ttotal += $(aoColumns[i].nTh).outerWidth();\n\n\t\t\t\tthis.s.aoTargets.push( {\n\t\t\t\t\t\"x\":  total,\n\t\t\t\t\t\"to\": iToPoint\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\n\t\t/* Disallow columns for being reordered by drag and drop, counting right to left */\n\t\tif ( this.s.fixedRight !== 0 )\n\t\t{\n\t\t\tthis.s.aoTargets.splice( this.s.aoTargets.length - this.s.fixedRight );\n\t\t}\n\n\t\t/* Disallow columns for being reordered by drag and drop, counting left to right */\n\t\tif ( this.s.fixed !== 0 )\n\t\t{\n\t\t\tthis.s.aoTargets.splice( 0, this.s.fixed );\n\t\t}\n\t},\n\n\n\t/**\n\t * Copy the TH element that is being drags so the user has the idea that they are actually\n\t * moving it around the page.\n\t *  @method  _fnCreateDragNode\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnCreateDragNode\": function ()\n\t{\n\t\tvar scrolling = this.s.dt.oScroll.sX !== \"\" || this.s.dt.oScroll.sY !== \"\";\n\n\t\tvar origCell = this.s.dt.aoColumns[ this.s.mouse.targetIndex ].nTh;\n\t\tvar origTr = origCell.parentNode;\n\t\tvar origThead = origTr.parentNode;\n\t\tvar origTable = origThead.parentNode;\n\t\tvar cloneCell = $(origCell).clone();\n\n\t\t// This is a slightly odd combination of jQuery and DOM, but it is the\n\t\t// fastest and least resource intensive way I could think of cloning\n\t\t// the table with just a single header cell in it.\n\t\tthis.dom.drag = $(origTable.cloneNode(false))\n\t\t\t.addClass( 'DTCR_clonedTable' )\n\t\t\t.append(\n\t\t\t\t$(origThead.cloneNode(false)).append(\n\t\t\t\t\t$(origTr.cloneNode(false)).append(\n\t\t\t\t\t\tcloneCell[0]\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t\t\t.css( {\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0,\n\t\t\t\twidth: $(origCell).outerWidth(),\n\t\t\t\theight: $(origCell).outerHeight()\n\t\t\t} )\n\t\t\t.appendTo( 'body' );\n\n\t\tthis.dom.pointer = $('<div></div>')\n\t\t\t.addClass( 'DTCR_pointer' )\n\t\t\t.css( {\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttop: scrolling ?\n\t\t\t\t\t$('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top :\n\t\t\t\t\t$(this.s.dt.nTable).offset().top,\n\t\t\t\theight : scrolling ?\n\t\t\t\t\t$('div.dataTables_scroll', this.s.dt.nTableWrapper).height() :\n\t\t\t\t\t$(this.s.dt.nTable).height()\n\t\t\t} )\n\t\t\t.appendTo( 'body' );\n\t},\n\n\n\t/**\n\t * Add a data attribute to the column headers, so we know the index of\n\t * the row to be reordered. This allows fast detection of the index, and\n\t * for this plug-in to work with FixedHeader which clones the nodes.\n\t *  @private\n\t */\n\t\"_fnSetColumnIndexes\": function ()\n\t{\n\t\t$.each( this.s.dt.aoColumns, function (i, column) {\n\t\t\t$(column.nTh).attr('data-column-index', i);\n\t\t} );\n\t},\n\n\n\t/**\n\t * Get cursor position regardless of mouse or touch input\n\t * @param  {Event}  e    jQuery Event\n\t * @param  {string} prop Property to get\n\t * @return {number}      Value\n\t */\n\t_fnCursorPosition: function ( e, prop ) {\n\t\tif ( e.type.indexOf('touch') !== -1 ) {\n\t\t\treturn e.originalEvent.touches[0][ prop ];\n\t\t}\n\t\treturn e[ prop ];\n\t}\n} );\n\n\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Static parameters\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\n/**\n * ColReorder default settings for initialisation\n *  @namespace\n *  @static\n */\nColReorder.defaults = {\n\t/**\n\t * Predefined ordering for the columns that will be applied automatically\n\t * on initialisation. If not specified then the order that the columns are\n\t * found to be in the HTML is the order used.\n\t *  @type array\n\t *  @default null\n\t *  @static\n\t */\n\taiOrder: null,\n\n\t/**\n\t * ColReorder enable on initialisation\n\t *  @type boolean\n\t *  @default true\n\t *  @static\n\t */\n\tbEnable: true,\n\n\t/**\n\t * Redraw the table's column ordering as the end user draws the column\n\t * (`true`) or wait until the mouse is released (`false` - default). Note\n\t * that this will perform a redraw on each reordering, which involves an\n\t * Ajax request each time if you are using server-side processing in\n\t * DataTables.\n\t *  @type boolean\n\t *  @default false\n\t *  @static\n\t */\n\tbRealtime: true,\n\n\t/**\n\t * Indicate how many columns should be fixed in position (counting from the\n\t * left). This will typically be 1 if used, but can be as high as you like.\n\t *  @type int\n\t *  @default 0\n\t *  @static\n\t */\n\tiFixedColumnsLeft: 0,\n\n\t/**\n\t * As `iFixedColumnsRight` but counting from the right.\n\t *  @type int\n\t *  @default 0\n\t *  @static\n\t */\n\tiFixedColumnsRight: 0,\n\n\t/**\n\t * Callback function that is fired when columns are reordered. The `column-\n\t * reorder` event is preferred over this callback\n\t *  @type function():void\n\t *  @default null\n\t *  @static\n\t */\n\tfnReorderCallback: null\n};\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Constants\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n/**\n * ColReorder version\n *  @constant  version\n *  @type      String\n *  @default   As code\n */\nColReorder.version = \"1.5.0\";\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables interfaces\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n// Expose\n$.fn.dataTable.ColReorder = ColReorder;\n$.fn.DataTable.ColReorder = ColReorder;\n\n\n// Register a new feature with DataTables\nif ( typeof $.fn.dataTable == \"function\" &&\n     typeof $.fn.dataTableExt.fnVersionCheck == \"function\" &&\n     $.fn.dataTableExt.fnVersionCheck('1.10.8') )\n{\n\t$.fn.dataTableExt.aoFeatures.push( {\n\t\t\"fnInit\": function( settings ) {\n\t\t\tvar table = settings.oInstance;\n\n\t\t\tif ( ! settings._colReorder ) {\n\t\t\t\tvar dtInit = settings.oInit;\n\t\t\t\tvar opts = dtInit.colReorder || dtInit.oColReorder || {};\n\n\t\t\t\tnew ColReorder( settings, opts );\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttable.oApi._fnLog( settings, 1, \"ColReorder attempted to initialise twice. Ignoring second\" );\n\t\t\t}\n\n\t\t\treturn null; /* No node for DataTables to insert */\n\t\t},\n\t\t\"cFeature\": \"R\",\n\t\t\"sFeature\": \"ColReorder\"\n\t} );\n}\nelse {\n\talert( \"Warning: ColReorder requires DataTables 1.10.8 or greater - www.datatables.net/download\");\n}\n\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'preInit.dt.colReorder', function (e, settings) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.colReorder;\n\tvar defaults = DataTable.defaults.colReorder;\n\n\tif ( init || defaults ) {\n\t\tvar opts = $.extend( {}, init, defaults );\n\n\t\tif ( init !== false ) {\n\t\t\tnew ColReorder( settings, opts  );\n\t\t}\n\t}\n} );\n\n\n// API augmentation\n$.fn.dataTable.Api.register( 'colReorder.reset()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tctx._colReorder.fnReset();\n\t} );\n} );\n\n$.fn.dataTable.Api.register( 'colReorder.order()', function ( set, original ) {\n\tif ( set ) {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\tctx._colReorder.fnOrder( set, original );\n\t\t} );\n\t}\n\n\treturn this.context.length ?\n\t\tthis.context[0]._colReorder.fnOrder() :\n\t\tnull;\n} );\n\n$.fn.dataTable.Api.register( 'colReorder.transpose()', function ( idx, dir ) {\n\treturn this.context.length && this.context[0]._colReorder ?\n\t\tthis.context[0]._colReorder.fnTranspose( idx, dir ) :\n\t\tidx;\n} );\n\n$.fn.dataTable.Api.register( 'colReorder.move()', function( from, to, drop, invalidateRows ) {\n\tif (this.context.length) {\n\t\tthis.context[0]._colReorder.s.dt.oInstance.fnColReorder( from, to, drop, invalidateRows );\n\t}\n\treturn this;\n} );\n\n$.fn.dataTable.Api.register( 'colReorder.enable()', function( flag ) {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx._colReorder ) {\n\t\t\tctx._colReorder.fnEnable( flag );\n\t\t}\n\t} );\n} );\n\n$.fn.dataTable.Api.register( 'colReorder.disable()', function() {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx._colReorder ) {\n\t\t\tctx._colReorder.fnDisable();\n\t\t}\n\t} );\n} );\n\n\nreturn ColReorder;\n}));\n"
  },
  {
    "path": "static/js/DataTables/DataTables-1.10.18/css/dataTables.bootstrap.css",
    "content": "table.dataTable {\n  clear: both;\n  margin-top: 6px !important;\n  margin-bottom: 6px !important;\n  max-width: none !important;\n  border-collapse: separate !important;\n}\ntable.dataTable td,\ntable.dataTable th {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\ntable.dataTable td.dataTables_empty,\ntable.dataTable th.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable.nowrap th,\ntable.dataTable.nowrap td {\n  white-space: nowrap;\n}\n\ndiv.dataTables_wrapper div.dataTables_length label {\n  font-weight: normal;\n  text-align: left;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_length select {\n  width: 75px;\n  display: inline-block;\n}\ndiv.dataTables_wrapper div.dataTables_filter {\n  text-align: right;\n}\ndiv.dataTables_wrapper div.dataTables_filter label {\n  font-weight: normal;\n  white-space: nowrap;\n  text-align: left;\n}\ndiv.dataTables_wrapper div.dataTables_filter input {\n  margin-left: 0.5em;\n  display: inline-block;\n  width: auto;\n}\ndiv.dataTables_wrapper div.dataTables_info {\n  padding-top: 8px;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_paginate {\n  margin: 0;\n  white-space: nowrap;\n  text-align: right;\n}\ndiv.dataTables_wrapper div.dataTables_paginate ul.pagination {\n  margin: 2px 0;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  margin-left: -100px;\n  margin-top: -26px;\n  text-align: center;\n  padding: 1em 0;\n}\n\ntable.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting,\ntable.dataTable thead > tr > td.sorting_asc,\ntable.dataTable thead > tr > td.sorting_desc,\ntable.dataTable thead > tr > td.sorting {\n  padding-right: 30px;\n}\ntable.dataTable thead > tr > th:active,\ntable.dataTable thead > tr > td:active {\n  outline: none;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  cursor: pointer;\n  position: relative;\n}\ntable.dataTable thead .sorting:after,\ntable.dataTable thead .sorting_asc:after,\ntable.dataTable thead .sorting_desc:after,\ntable.dataTable thead .sorting_asc_disabled:after,\ntable.dataTable thead .sorting_desc_disabled:after {\n  position: absolute;\n  bottom: 8px;\n  right: 8px;\n  display: block;\n  font-family: 'Glyphicons Halflings';\n  opacity: 0.5;\n}\ntable.dataTable thead .sorting:after {\n  opacity: 0.2;\n  content: \"\\e150\";\n  /* sort */\n}\ntable.dataTable thead .sorting_asc:after {\n  content: \"\\e155\";\n  /* sort-by-attributes */\n}\ntable.dataTable thead .sorting_desc:after {\n  content: \"\\e156\";\n  /* sort-by-attributes-alt */\n}\ntable.dataTable thead .sorting_asc_disabled:after,\ntable.dataTable thead .sorting_desc_disabled:after {\n  color: #eee;\n}\n\ndiv.dataTables_scrollHead table.dataTable {\n  margin-bottom: 0 !important;\n}\n\ndiv.dataTables_scrollBody > table {\n  border-top: none;\n  margin-top: 0 !important;\n  margin-bottom: 0 !important;\n}\ndiv.dataTables_scrollBody > table > thead .sorting:after,\ndiv.dataTables_scrollBody > table > thead .sorting_asc:after,\ndiv.dataTables_scrollBody > table > thead .sorting_desc:after {\n  display: none;\n}\ndiv.dataTables_scrollBody > table > tbody > tr:first-child > th,\ndiv.dataTables_scrollBody > table > tbody > tr:first-child > td {\n  border-top: none;\n}\n\ndiv.dataTables_scrollFoot > .dataTables_scrollFootInner {\n  box-sizing: content-box;\n}\ndiv.dataTables_scrollFoot > .dataTables_scrollFootInner > table {\n  margin-top: 0 !important;\n  border-top: none;\n}\n\n@media screen and (max-width: 767px) {\n  div.dataTables_wrapper div.dataTables_length,\n  div.dataTables_wrapper div.dataTables_filter,\n  div.dataTables_wrapper div.dataTables_info,\n  div.dataTables_wrapper div.dataTables_paginate {\n    text-align: center;\n  }\n}\ntable.dataTable.table-condensed > thead > tr > th {\n  padding-right: 20px;\n}\ntable.dataTable.table-condensed .sorting:after,\ntable.dataTable.table-condensed .sorting_asc:after,\ntable.dataTable.table-condensed .sorting_desc:after {\n  top: 6px;\n  right: 6px;\n}\n\ntable.table-bordered.dataTable th,\ntable.table-bordered.dataTable td {\n  border-left-width: 0;\n}\ntable.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child,\ntable.table-bordered.dataTable td:last-child,\ntable.table-bordered.dataTable td:last-child {\n  border-right-width: 0;\n}\ntable.table-bordered.dataTable tbody th,\ntable.table-bordered.dataTable tbody td {\n  border-bottom-width: 0;\n}\n\ndiv.dataTables_scrollHead table.table-bordered {\n  border-bottom-width: 0;\n}\n\ndiv.table-responsive > div.dataTables_wrapper > div.row {\n  margin: 0;\n}\ndiv.table-responsive > div.dataTables_wrapper > div.row > div[class^=\"col-\"]:first-child {\n  padding-left: 0;\n}\ndiv.table-responsive > div.dataTables_wrapper > div.row > div[class^=\"col-\"]:last-child {\n  padding-right: 0;\n}\n"
  },
  {
    "path": "static/js/DataTables/DataTables-1.10.18/css/dataTables.bootstrap4.css",
    "content": "table.dataTable {\n  clear: both;\n  margin-top: 6px !important;\n  margin-bottom: 6px !important;\n  max-width: none !important;\n  border-collapse: separate !important;\n  border-spacing: 0;\n}\ntable.dataTable td,\ntable.dataTable th {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\ntable.dataTable td.dataTables_empty,\ntable.dataTable th.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable.nowrap th,\ntable.dataTable.nowrap td {\n  white-space: nowrap;\n}\n\ndiv.dataTables_wrapper div.dataTables_length label {\n  font-weight: normal;\n  text-align: left;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_length select {\n  width: auto;\n  display: inline-block;\n}\ndiv.dataTables_wrapper div.dataTables_filter {\n  text-align: right;\n}\ndiv.dataTables_wrapper div.dataTables_filter label {\n  font-weight: normal;\n  white-space: nowrap;\n  text-align: left;\n}\ndiv.dataTables_wrapper div.dataTables_filter input {\n  margin-left: 0.5em;\n  display: inline-block;\n  width: auto;\n}\ndiv.dataTables_wrapper div.dataTables_info {\n  padding-top: 0.85em;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_paginate {\n  margin: 0;\n  white-space: nowrap;\n  text-align: right;\n}\ndiv.dataTables_wrapper div.dataTables_paginate ul.pagination {\n  margin: 2px 0;\n  white-space: nowrap;\n  justify-content: flex-end;\n}\ndiv.dataTables_wrapper div.dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  margin-left: -100px;\n  margin-top: -26px;\n  text-align: center;\n  padding: 1em 0;\n}\n\ntable.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting,\ntable.dataTable thead > tr > td.sorting_asc,\ntable.dataTable thead > tr > td.sorting_desc,\ntable.dataTable thead > tr > td.sorting {\n  padding-right: 30px;\n}\ntable.dataTable thead > tr > th:active,\ntable.dataTable thead > tr > td:active {\n  outline: none;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  cursor: pointer;\n  position: relative;\n}\ntable.dataTable thead .sorting:before, table.dataTable thead .sorting:after,\ntable.dataTable thead .sorting_asc:before,\ntable.dataTable thead .sorting_asc:after,\ntable.dataTable thead .sorting_desc:before,\ntable.dataTable thead .sorting_desc:after,\ntable.dataTable thead .sorting_asc_disabled:before,\ntable.dataTable thead .sorting_asc_disabled:after,\ntable.dataTable thead .sorting_desc_disabled:before,\ntable.dataTable thead .sorting_desc_disabled:after {\n  position: absolute;\n  bottom: 0.9em;\n  display: block;\n  opacity: 0.3;\n}\ntable.dataTable thead .sorting:before,\ntable.dataTable thead .sorting_asc:before,\ntable.dataTable thead .sorting_desc:before,\ntable.dataTable thead .sorting_asc_disabled:before,\ntable.dataTable thead .sorting_desc_disabled:before {\n  right: 1em;\n  content: \"\\2191\";\n}\ntable.dataTable thead .sorting:after,\ntable.dataTable thead .sorting_asc:after,\ntable.dataTable thead .sorting_desc:after,\ntable.dataTable thead .sorting_asc_disabled:after,\ntable.dataTable thead .sorting_desc_disabled:after {\n  right: 0.5em;\n  content: \"\\2193\";\n}\ntable.dataTable thead .sorting_asc:before,\ntable.dataTable thead .sorting_desc:after {\n  opacity: 1;\n}\ntable.dataTable thead .sorting_asc_disabled:before,\ntable.dataTable thead .sorting_desc_disabled:after {\n  opacity: 0;\n}\n\ndiv.dataTables_scrollHead table.dataTable {\n  margin-bottom: 0 !important;\n}\n\ndiv.dataTables_scrollBody table {\n  border-top: none;\n  margin-top: 0 !important;\n  margin-bottom: 0 !important;\n}\ndiv.dataTables_scrollBody table thead .sorting:before,\ndiv.dataTables_scrollBody table thead .sorting_asc:before,\ndiv.dataTables_scrollBody table thead .sorting_desc:before,\ndiv.dataTables_scrollBody table thead .sorting:after,\ndiv.dataTables_scrollBody table thead .sorting_asc:after,\ndiv.dataTables_scrollBody table thead .sorting_desc:after {\n  display: none;\n}\ndiv.dataTables_scrollBody table tbody tr:first-child th,\ndiv.dataTables_scrollBody table tbody tr:first-child td {\n  border-top: none;\n}\n\ndiv.dataTables_scrollFoot > .dataTables_scrollFootInner {\n  box-sizing: content-box;\n}\ndiv.dataTables_scrollFoot > .dataTables_scrollFootInner > table {\n  margin-top: 0 !important;\n  border-top: none;\n}\n\n@media screen and (max-width: 767px) {\n  div.dataTables_wrapper div.dataTables_length,\n  div.dataTables_wrapper div.dataTables_filter,\n  div.dataTables_wrapper div.dataTables_info,\n  div.dataTables_wrapper div.dataTables_paginate {\n    text-align: center;\n  }\n}\ntable.dataTable.table-sm > thead > tr > th {\n  padding-right: 20px;\n}\ntable.dataTable.table-sm .sorting:before,\ntable.dataTable.table-sm .sorting_asc:before,\ntable.dataTable.table-sm .sorting_desc:before {\n  top: 5px;\n  right: 0.85em;\n}\ntable.dataTable.table-sm .sorting:after,\ntable.dataTable.table-sm .sorting_asc:after,\ntable.dataTable.table-sm .sorting_desc:after {\n  top: 5px;\n}\n\ntable.table-bordered.dataTable th,\ntable.table-bordered.dataTable td {\n  border-left-width: 0;\n}\ntable.table-bordered.dataTable th:last-child, table.table-bordered.dataTable th:last-child,\ntable.table-bordered.dataTable td:last-child,\ntable.table-bordered.dataTable td:last-child {\n  border-right-width: 0;\n}\ntable.table-bordered.dataTable tbody th,\ntable.table-bordered.dataTable tbody td {\n  border-bottom-width: 0;\n}\n\ndiv.dataTables_scrollHead table.table-bordered {\n  border-bottom-width: 0;\n}\n\ndiv.table-responsive > div.dataTables_wrapper > div.row {\n  margin: 0;\n}\ndiv.table-responsive > div.dataTables_wrapper > div.row > div[class^=\"col-\"]:first-child {\n  padding-left: 0;\n}\ndiv.table-responsive > div.dataTables_wrapper > div.row > div[class^=\"col-\"]:last-child {\n  padding-right: 0;\n}\n"
  },
  {
    "path": "static/js/DataTables/DataTables-1.10.18/css/dataTables.foundation.css",
    "content": "table.dataTable {\n  clear: both;\n  margin: 0.5em 0 !important;\n  max-width: none !important;\n  width: 100%;\n}\ntable.dataTable td,\ntable.dataTable th {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\ntable.dataTable td.dataTables_empty,\ntable.dataTable th.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\n\ndiv.dataTables_wrapper {\n  position: relative;\n}\ndiv.dataTables_wrapper div.dataTables_length label {\n  float: left;\n  text-align: left;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_length select {\n  width: 75px;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_filter label {\n  float: right;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_filter input {\n  display: inline-block !important;\n  width: auto !important;\n  margin-bottom: 0;\n  margin-left: 0.5em;\n}\ndiv.dataTables_wrapper div.dataTables_info {\n  padding-top: 2px;\n}\ndiv.dataTables_wrapper div.dataTables_paginate {\n  float: right;\n  margin: 0;\n}\ndiv.dataTables_wrapper div.dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  margin-left: -100px;\n  margin-top: -26px;\n  text-align: center;\n  padding: 1rem 0;\n}\n\ntable.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting,\ntable.dataTable thead > tr > td.sorting_asc,\ntable.dataTable thead > tr > td.sorting_desc,\ntable.dataTable thead > tr > td.sorting {\n  padding-right: 1.5rem;\n}\ntable.dataTable thead > tr > th:active,\ntable.dataTable thead > tr > td:active {\n  outline: none;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  cursor: pointer;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"../images/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"../images/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"../images/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"../images/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"../images/sort_desc_disabled.png\");\n}\n\ndiv.dataTables_scrollHead table {\n  margin-bottom: 0 !important;\n}\n\ndiv.dataTables_scrollBody table {\n  border-top: none;\n  margin-top: 0 !important;\n  margin-bottom: 0 !important;\n}\ndiv.dataTables_scrollBody table tbody tr:first-child th,\ndiv.dataTables_scrollBody table tbody tr:first-child td {\n  border-top: none;\n}\n\ndiv.dataTables_scrollFoot table {\n  margin-top: 0 !important;\n  border-top: none;\n}\n"
  },
  {
    "path": "static/js/DataTables/DataTables-1.10.18/css/dataTables.jqueryui.css",
    "content": "/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th,\ntable.dataTable thead td {\n  padding: 10px 18px;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 10px 18px 6px 18px;\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #acbad4;\n}\ntable.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n  background-color: #f6f6f6;\n}\ntable.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n  background-color: #aab7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #fafafa;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a8b5cf;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b7d1;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #fafafa;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fcfcfc;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fefefe;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #aebcd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n  background-color: #ececec;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n  background-color: #efefef;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n  background-color: #a2aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n  background-color: #a3b0c9;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n  background-color: #a5b2cb;\n}\ntable.dataTable.no-footer {\n  border-bottom: 1px solid #111;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 4px 17px 4px 4px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 4px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.755em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n  padding-top: 0.25em;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em 1em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n  border-radius: 2px;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  color: #333 !important;\n  border: 1px solid #979797;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n  cursor: default;\n  color: #666 !important;\n  border: 1px solid transparent;\n  background: transparent;\n  box-shadow: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  color: white !important;\n  border: 1px solid #111;\n  background-color: #585858;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #585858 0%, #111 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #585858 0%, #111 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #585858 0%, #111 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #585858 0%, #111 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #585858 0%, #111 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  outline: none;\n  background-color: #2b2b2b;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);\n  /* W3C */\n  box-shadow: inset 0 0 3px #111;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td {\n  vertical-align: middle;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td > div.dataTables_sizing, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td > div.dataTables_sizing {\n  height: 0;\n  overflow: hidden;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: 1px solid #111;\n}\n.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,\n.dataTables_wrapper.no-footer div.dataTables_scrollBody > table {\n  border-bottom: none;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em;\n  }\n}\ntable.dataTable thead th div.DataTables_sort_wrapper {\n  position: relative;\n}\ntable.dataTable thead th div.DataTables_sort_wrapper span {\n  position: absolute;\n  top: 50%;\n  margin-top: -8px;\n  right: -18px;\n}\ntable.dataTable thead th.ui-state-default,\ntable.dataTable tfoot th.ui-state-default {\n  border-left-width: 0;\n}\ntable.dataTable thead th.ui-state-default:first-child,\ntable.dataTable tfoot th.ui-state-default:first-child {\n  border-left-width: 1px;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper .dataTables_paginate .fg-button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  border: 1px solid transparent;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:active {\n  outline: none;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:first-child {\n  border-top-left-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.dataTables_wrapper .dataTables_paginate .fg-button:last-child {\n  border-top-right-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.dataTables_wrapper .ui-widget-header {\n  font-weight: normal;\n}\n.dataTables_wrapper .ui-toolbar {\n  padding: 8px;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: none;\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: inherit;\n}\n"
  },
  {
    "path": "static/js/DataTables/DataTables-1.10.18/css/dataTables.semanticui.css",
    "content": "/*\n * Styling for DataTables with Semantic UI\n */\ntable.dataTable.table {\n  margin: 0;\n}\ntable.dataTable.table thead th,\ntable.dataTable.table thead td {\n  position: relative;\n}\ntable.dataTable.table thead th.sorting, table.dataTable.table thead th.sorting_asc, table.dataTable.table thead th.sorting_desc,\ntable.dataTable.table thead td.sorting,\ntable.dataTable.table thead td.sorting_asc,\ntable.dataTable.table thead td.sorting_desc {\n  padding-right: 20px;\n}\ntable.dataTable.table thead th.sorting:after, table.dataTable.table thead th.sorting_asc:after, table.dataTable.table thead th.sorting_desc:after,\ntable.dataTable.table thead td.sorting:after,\ntable.dataTable.table thead td.sorting_asc:after,\ntable.dataTable.table thead td.sorting_desc:after {\n  position: absolute;\n  top: 12px;\n  right: 8px;\n  display: block;\n  font-family: Icons;\n}\ntable.dataTable.table thead th.sorting:after,\ntable.dataTable.table thead td.sorting:after {\n  content: \"\\f0dc\";\n  color: #ddd;\n  font-size: 0.8em;\n}\ntable.dataTable.table thead th.sorting_asc:after,\ntable.dataTable.table thead td.sorting_asc:after {\n  content: \"\\f0de\";\n}\ntable.dataTable.table thead th.sorting_desc:after,\ntable.dataTable.table thead td.sorting_desc:after {\n  content: \"\\f0dd\";\n}\ntable.dataTable.table td,\ntable.dataTable.table th {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\ntable.dataTable.table td.dataTables_empty,\ntable.dataTable.table th.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable.table.nowrap th,\ntable.dataTable.table.nowrap td {\n  white-space: nowrap;\n}\n\ndiv.dataTables_wrapper div.dataTables_length select {\n  vertical-align: middle;\n  min-height: 2.7142em;\n}\ndiv.dataTables_wrapper div.dataTables_length .ui.selection.dropdown {\n  min-width: 0;\n}\ndiv.dataTables_wrapper div.dataTables_filter span.input {\n  margin-left: 0.5em;\n}\ndiv.dataTables_wrapper div.dataTables_info {\n  padding-top: 13px;\n  white-space: nowrap;\n}\ndiv.dataTables_wrapper div.dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  margin-left: -100px;\n  text-align: center;\n}\ndiv.dataTables_wrapper div.row.dt-table {\n  padding: 0;\n}\ndiv.dataTables_wrapper div.dataTables_scrollHead table.dataTable {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n  border-bottom: none;\n}\ndiv.dataTables_wrapper div.dataTables_scrollBody thead .sorting:after,\ndiv.dataTables_wrapper div.dataTables_scrollBody thead .sorting_asc:after,\ndiv.dataTables_wrapper div.dataTables_scrollBody thead .sorting_desc:after {\n  display: none;\n}\ndiv.dataTables_wrapper div.dataTables_scrollBody table.dataTable {\n  border-radius: 0;\n  border-top: none;\n  border-bottom-width: 0;\n}\ndiv.dataTables_wrapper div.dataTables_scrollBody table.dataTable.no-footer {\n  border-bottom-width: 1px;\n}\ndiv.dataTables_wrapper div.dataTables_scrollFoot table.dataTable {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n  border-top: none;\n}\n"
  },
  {
    "path": "static/js/DataTables/DataTables-1.10.18/css/jquery.dataTables.css",
    "content": "/*\n * Table styles\n */\ntable.dataTable {\n  width: 100%;\n  margin: 0 auto;\n  clear: both;\n  border-collapse: separate;\n  border-spacing: 0;\n  /*\n   * Header and footer styles\n   */\n  /*\n   * Body styles\n   */\n}\ntable.dataTable thead th,\ntable.dataTable tfoot th {\n  font-weight: bold;\n}\ntable.dataTable thead th,\ntable.dataTable thead td {\n  padding: 10px 18px;\n  border-bottom: 1px solid #111;\n}\ntable.dataTable thead th:active,\ntable.dataTable thead td:active {\n  outline: none;\n}\ntable.dataTable tfoot th,\ntable.dataTable tfoot td {\n  padding: 10px 18px 6px 18px;\n  border-top: 1px solid #111;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  cursor: pointer;\n  *cursor: hand;\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"../images/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"../images/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"../images/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"../images/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"../images/sort_desc_disabled.png\");\n}\ntable.dataTable tbody tr {\n  background-color: #ffffff;\n}\ntable.dataTable tbody tr.selected {\n  background-color: #B0BED9;\n}\ntable.dataTable tbody th,\ntable.dataTable tbody td {\n  padding: 8px 10px;\n}\ntable.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {\n  border-top: 1px solid #ddd;\n}\ntable.dataTable.row-border tbody tr:first-child th,\ntable.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,\ntable.dataTable.display tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {\n  border-top: 1px solid #ddd;\n  border-right: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr th:first-child,\ntable.dataTable.cell-border tbody tr td:first-child {\n  border-left: 1px solid #ddd;\n}\ntable.dataTable.cell-border tbody tr:first-child th,\ntable.dataTable.cell-border tbody tr:first-child td {\n  border-top: none;\n}\ntable.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {\n  background-color: #f9f9f9;\n}\ntable.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {\n  background-color: #acbad4;\n}\ntable.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {\n  background-color: #f6f6f6;\n}\ntable.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {\n  background-color: #aab7d1;\n}\ntable.dataTable.order-column tbody tr > .sorting_1,\ntable.dataTable.order-column tbody tr > .sorting_2,\ntable.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,\ntable.dataTable.display tbody tr > .sorting_2,\ntable.dataTable.display tbody tr > .sorting_3 {\n  background-color: #fafafa;\n}\ntable.dataTable.order-column tbody tr.selected > .sorting_1,\ntable.dataTable.order-column tbody tr.selected > .sorting_2,\ntable.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,\ntable.dataTable.display tbody tr.selected > .sorting_2,\ntable.dataTable.display tbody tr.selected > .sorting_3 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {\n  background-color: #f1f1f1;\n}\ntable.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {\n  background-color: #f3f3f3;\n}\ntable.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {\n  background-color: whitesmoke;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {\n  background-color: #a8b5cf;\n}\ntable.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {\n  background-color: #a9b7d1;\n}\ntable.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {\n  background-color: #fafafa;\n}\ntable.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {\n  background-color: #fcfcfc;\n}\ntable.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {\n  background-color: #fefefe;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {\n  background-color: #aebcd6;\n}\ntable.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {\n  background-color: #eaeaea;\n}\ntable.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {\n  background-color: #ececec;\n}\ntable.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {\n  background-color: #efefef;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {\n  background-color: #a2aec7;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {\n  background-color: #a3b0c9;\n}\ntable.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {\n  background-color: #a5b2cb;\n}\ntable.dataTable.no-footer {\n  border-bottom: 1px solid #111;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\ntable.dataTable.compact thead th,\ntable.dataTable.compact thead td {\n  padding: 4px 17px 4px 4px;\n}\ntable.dataTable.compact tfoot th,\ntable.dataTable.compact tfoot td {\n  padding: 4px;\n}\ntable.dataTable.compact tbody th,\ntable.dataTable.compact tbody td {\n  padding: 4px;\n}\ntable.dataTable th.dt-left,\ntable.dataTable td.dt-left {\n  text-align: left;\n}\ntable.dataTable th.dt-center,\ntable.dataTable td.dt-center,\ntable.dataTable td.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable th.dt-right,\ntable.dataTable td.dt-right {\n  text-align: right;\n}\ntable.dataTable th.dt-justify,\ntable.dataTable td.dt-justify {\n  text-align: justify;\n}\ntable.dataTable th.dt-nowrap,\ntable.dataTable td.dt-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable thead th.dt-head-left,\ntable.dataTable thead td.dt-head-left,\ntable.dataTable tfoot th.dt-head-left,\ntable.dataTable tfoot td.dt-head-left {\n  text-align: left;\n}\ntable.dataTable thead th.dt-head-center,\ntable.dataTable thead td.dt-head-center,\ntable.dataTable tfoot th.dt-head-center,\ntable.dataTable tfoot td.dt-head-center {\n  text-align: center;\n}\ntable.dataTable thead th.dt-head-right,\ntable.dataTable thead td.dt-head-right,\ntable.dataTable tfoot th.dt-head-right,\ntable.dataTable tfoot td.dt-head-right {\n  text-align: right;\n}\ntable.dataTable thead th.dt-head-justify,\ntable.dataTable thead td.dt-head-justify,\ntable.dataTable tfoot th.dt-head-justify,\ntable.dataTable tfoot td.dt-head-justify {\n  text-align: justify;\n}\ntable.dataTable thead th.dt-head-nowrap,\ntable.dataTable thead td.dt-head-nowrap,\ntable.dataTable tfoot th.dt-head-nowrap,\ntable.dataTable tfoot td.dt-head-nowrap {\n  white-space: nowrap;\n}\ntable.dataTable tbody th.dt-body-left,\ntable.dataTable tbody td.dt-body-left {\n  text-align: left;\n}\ntable.dataTable tbody th.dt-body-center,\ntable.dataTable tbody td.dt-body-center {\n  text-align: center;\n}\ntable.dataTable tbody th.dt-body-right,\ntable.dataTable tbody td.dt-body-right {\n  text-align: right;\n}\ntable.dataTable tbody th.dt-body-justify,\ntable.dataTable tbody td.dt-body-justify {\n  text-align: justify;\n}\ntable.dataTable tbody th.dt-body-nowrap,\ntable.dataTable tbody td.dt-body-nowrap {\n  white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable th,\ntable.dataTable td {\n  box-sizing: content-box;\n}\n\n/*\n * Control feature layout\n */\n.dataTables_wrapper {\n  position: relative;\n  clear: both;\n  *zoom: 1;\n  zoom: 1;\n}\n.dataTables_wrapper .dataTables_length {\n  float: left;\n}\n.dataTables_wrapper .dataTables_filter {\n  float: right;\n  text-align: right;\n}\n.dataTables_wrapper .dataTables_filter input {\n  margin-left: 0.5em;\n}\n.dataTables_wrapper .dataTables_info {\n  clear: both;\n  float: left;\n  padding-top: 0.755em;\n}\n.dataTables_wrapper .dataTables_paginate {\n  float: right;\n  text-align: right;\n  padding-top: 0.25em;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button {\n  box-sizing: border-box;\n  display: inline-block;\n  min-width: 1.5em;\n  padding: 0.5em 1em;\n  margin-left: 2px;\n  text-align: center;\n  text-decoration: none !important;\n  cursor: pointer;\n  *cursor: hand;\n  color: #333 !important;\n  border: 1px solid transparent;\n  border-radius: 2px;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {\n  color: #333 !important;\n  border: 1px solid #979797;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {\n  cursor: default;\n  color: #666 !important;\n  border: 1px solid transparent;\n  background: transparent;\n  box-shadow: none;\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:hover {\n  color: white !important;\n  border: 1px solid #111;\n  background-color: #585858;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #585858 0%, #111 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #585858 0%, #111 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #585858 0%, #111 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #585858 0%, #111 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #585858 0%, #111 100%);\n  /* W3C */\n}\n.dataTables_wrapper .dataTables_paginate .paginate_button:active {\n  outline: none;\n  background-color: #2b2b2b;\n  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));\n  /* Chrome,Safari4+ */\n  background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Chrome10+,Safari5.1+ */\n  background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* FF3.6+ */\n  background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* IE10+ */\n  background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);\n  /* Opera 11.10+ */\n  background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);\n  /* W3C */\n  box-shadow: inset 0 0 3px #111;\n}\n.dataTables_wrapper .dataTables_paginate .ellipsis {\n  padding: 0 1em;\n}\n.dataTables_wrapper .dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 100%;\n  height: 40px;\n  margin-left: -50%;\n  margin-top: -25px;\n  padding-top: 20px;\n  text-align: center;\n  font-size: 1.2em;\n  background-color: white;\n  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));\n  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);\n}\n.dataTables_wrapper .dataTables_length,\n.dataTables_wrapper .dataTables_filter,\n.dataTables_wrapper .dataTables_info,\n.dataTables_wrapper .dataTables_processing,\n.dataTables_wrapper .dataTables_paginate {\n  color: #333;\n}\n.dataTables_wrapper .dataTables_scroll {\n  clear: both;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {\n  *margin-top: -1px;\n  -webkit-overflow-scrolling: touch;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td {\n  vertical-align: middle;\n}\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td > div.dataTables_sizing, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th > div.dataTables_sizing,\n.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td > div.dataTables_sizing {\n  height: 0;\n  overflow: hidden;\n  margin: 0 !important;\n  padding: 0 !important;\n}\n.dataTables_wrapper.no-footer .dataTables_scrollBody {\n  border-bottom: 1px solid #111;\n}\n.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,\n.dataTables_wrapper.no-footer div.dataTables_scrollBody > table {\n  border-bottom: none;\n}\n.dataTables_wrapper:after {\n  visibility: hidden;\n  display: block;\n  content: \"\";\n  clear: both;\n  height: 0;\n}\n\n@media screen and (max-width: 767px) {\n  .dataTables_wrapper .dataTables_info,\n  .dataTables_wrapper .dataTables_paginate {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_paginate {\n    margin-top: 0.5em;\n  }\n}\n@media screen and (max-width: 640px) {\n  .dataTables_wrapper .dataTables_length,\n  .dataTables_wrapper .dataTables_filter {\n    float: none;\n    text-align: center;\n  }\n  .dataTables_wrapper .dataTables_filter {\n    margin-top: 0.5em;\n  }\n}\n"
  },
  {
    "path": "static/js/DataTables/DataTables-1.10.18/js/dataTables.bootstrap.js",
    "content": "/*! DataTables Bootstrap 3 integration\n * ©2011-2015 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Bootstrap 3. This requires Bootstrap 3 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t// Require DataTables, which attaches to jQuery, including\n\t\t\t\t// jQuery if needed and have a $ property so we can access the\n\t\t\t\t// jQuery object that is used\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'row'<'col-sm-6'l><'col-sm-6'f>>\" +\n\t\t\"<'row'<'col-sm-12'tr>>\" +\n\t\t\"<'row'<'col-sm-5'i><'col-sm-7'p>>\",\n\trenderer: 'bootstrap'\n} );\n\n\n/* Default class modification */\n$.extend( DataTable.ext.classes, {\n\tsWrapper:      \"dataTables_wrapper form-inline dt-bootstrap\",\n\tsFilterInput:  \"form-control input-sm\",\n\tsLengthSelect: \"form-control input-sm\",\n\tsProcessing:   \"dataTables_processing panel panel-default\"\n} );\n\n\n/* Bootstrap paging button renderer */\nDataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api     = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang    = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass, counter=0;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '&#x2026;';\n\t\t\t\t\t\tbtnClass = 'disabled';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'active' : '';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<li>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append( $('<a>', {\n\t\t\t\t\t\t\t\t'href': '#',\n\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\n\t\t\t\t\tcounter++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t// inside an iframe or frame. \n\tvar activeEl;\n\n\ttry {\n\t\t// Because this approach is destroying and recreating the paging\n\t\t// elements, focus is lost on the select button which is bad for\n\t\t// accessibility. So we want to restore focus once the draw has\n\t\t// completed\n\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t}\n\tcatch (e) {}\n\n\tattach(\n\t\t$(host).empty().html('<ul class=\"pagination\"/>').children('ul'),\n\t\tbuttons\n\t);\n\n\tif ( activeEl !== undefined ) {\n\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t}\n};\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "static/js/DataTables/DataTables-1.10.18/js/dataTables.bootstrap4.js",
    "content": "/*! DataTables Bootstrap 4 integration\n * ©2011-2017 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Bootstrap 4. This requires Bootstrap 4 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t// Require DataTables, which attaches to jQuery, including\n\t\t\t\t// jQuery if needed and have a $ property so we can access the\n\t\t\t\t// jQuery object that is used\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>>\" +\n\t\t\"<'row'<'col-sm-12'tr>>\" +\n\t\t\"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>\",\n\trenderer: 'bootstrap'\n} );\n\n\n/* Default class modification */\n$.extend( DataTable.ext.classes, {\n\tsWrapper:      \"dataTables_wrapper dt-bootstrap4\",\n\tsFilterInput:  \"form-control form-control-sm\",\n\tsLengthSelect: \"custom-select custom-select-sm form-control form-control-sm\",\n\tsProcessing:   \"dataTables_processing card\",\n\tsPageButton:   \"paginate_button page-item\"\n} );\n\n\n/* Bootstrap paging button renderer */\nDataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api     = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang    = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass, counter=0;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '&#x2026;';\n\t\t\t\t\t\tbtnClass = 'disabled';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'active' : '';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<li>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append( $('<a>', {\n\t\t\t\t\t\t\t\t'href': '#',\n\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t\t'class': 'page-link'\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\n\t\t\t\t\tcounter++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t// inside an iframe or frame. \n\tvar activeEl;\n\n\ttry {\n\t\t// Because this approach is destroying and recreating the paging\n\t\t// elements, focus is lost on the select button which is bad for\n\t\t// accessibility. So we want to restore focus once the draw has\n\t\t// completed\n\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t}\n\tcatch (e) {}\n\n\tattach(\n\t\t$(host).empty().html('<ul class=\"pagination\"/>').children('ul'),\n\t\tbuttons\n\t);\n\n\tif ( activeEl !== undefined ) {\n\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t}\n};\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "static/js/DataTables/DataTables-1.10.18/js/dataTables.foundation.js",
    "content": "/*! DataTables Foundation integration\n * ©2011-2015 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Foundation. This requires Foundation 5 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Foundation. See http://datatables.net/manual/styling/foundation\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n// Detect Foundation 5 / 6 as they have different element and class requirements\nvar meta = $('<meta class=\"foundation-mq\"/>').appendTo('head');\nDataTable.ext.foundationVersion = meta.css('font-family').match(/small|medium|large/) ? 6 : 5;\nmeta.remove();\n\n\n$.extend( DataTable.ext.classes, {\n\tsWrapper:    \"dataTables_wrapper dt-foundation\",\n\tsProcessing: \"dataTables_processing panel callout\"\n} );\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'row grid-x'<'small-6 columns cell'l><'small-6 columns cell'f>r>\"+\n\t\t\"t\"+\n\t\t\"<'row grid-x'<'small-6 columns cell'i><'small-6 columns cell'p>>\",\n\trenderer: 'foundation'\n} );\n\n\n/* Page button renderer */\nDataTable.ext.renderer.pageButton.foundation = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass;\n\tvar tag;\n\tvar v5 = DataTable.ext.foundationVersion === 5;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('unavailable') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\t\t\t\ttag = null;\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '&#x2026;';\n\t\t\t\t\t\tbtnClass = 'unavailable disabled';\n\t\t\t\t\t\ttag = null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page > 0 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page > 0 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page < pages-1 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page < pages-1 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'current' : '';\n\t\t\t\t\t\ttag = page === button ?\n\t\t\t\t\t\t\tnull : 'a';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( v5 ) {\n\t\t\t\t\ttag = 'a';\n\t\t\t\t}\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<li>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append( tag ?\n\t\t\t\t\t\t\t$('<'+tag+'/>', {'href': '#'} ).html( btnDisplay ) :\n\t\t\t\t\t\t\tbtnDisplay\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\tattach(\n\t\t$(host).empty().html('<ul class=\"pagination\"/>').children('ul'),\n\t\tbuttons\n\t);\n};\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "static/js/DataTables/DataTables-1.10.18/js/dataTables.jqueryui.js",
    "content": "/*! DataTables jQuery UI integration\n * ©2011-2014 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for jQuery UI. This requires jQuery UI and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using jQuery UI. See http://datatables.net/manual/styling/jqueryui\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar sort_prefix = 'css_right ui-icon ui-icon-';\nvar toolbar_prefix = 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix ui-corner-';\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t'<\"'+toolbar_prefix+'tl ui-corner-tr\"lfr>'+\n\t\t't'+\n\t\t'<\"'+toolbar_prefix+'bl ui-corner-br\"ip>',\n\trenderer: 'jqueryui'\n} );\n\n\n$.extend( DataTable.ext.classes, {\n\t\"sWrapper\":            \"dataTables_wrapper dt-jqueryui\",\n\n\t/* Full numbers paging buttons */\n\t\"sPageButton\":         \"fg-button ui-button ui-state-default\",\n\t\"sPageButtonActive\":   \"ui-state-disabled\",\n\t\"sPageButtonDisabled\": \"ui-state-disabled\",\n\n\t/* Features */\n\t\"sPaging\": \"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi \"+\n\t\t\"ui-buttonset-multi paging_\", /* Note that the type is postfixed */\n\n\t/* Sorting */\n\t\"sSortAsc\":            \"ui-state-default sorting_asc\",\n\t\"sSortDesc\":           \"ui-state-default sorting_desc\",\n\t\"sSortable\":           \"ui-state-default sorting\",\n\t\"sSortableAsc\":        \"ui-state-default sorting_asc_disabled\",\n\t\"sSortableDesc\":       \"ui-state-default sorting_desc_disabled\",\n\t\"sSortableNone\":       \"ui-state-default sorting_disabled\",\n\t\"sSortIcon\":           \"DataTables_sort_icon\",\n\n\t/* Scrolling */\n\t\"sScrollHead\": \"dataTables_scrollHead \"+\"ui-state-default\",\n\t\"sScrollFoot\": \"dataTables_scrollFoot \"+\"ui-state-default\",\n\n\t/* Misc */\n\t\"sHeaderTH\":  \"ui-state-default\",\n\t\"sFooterTH\":  \"ui-state-default\"\n} );\n\n\nDataTable.ext.renderer.header.jqueryui = function ( settings, cell, column, classes ) {\n\t// Calculate what the unsorted class should be\n\tvar noSortAppliedClass = sort_prefix+'caret-2-n-s';\n\tvar asc = $.inArray('asc', column.asSorting) !== -1;\n\tvar desc = $.inArray('desc', column.asSorting) !== -1;\n\n\tif ( !column.bSortable || (!asc && !desc) ) {\n\t\tnoSortAppliedClass = '';\n\t}\n\telse if ( asc && !desc ) {\n\t\tnoSortAppliedClass = sort_prefix+'caret-1-n';\n\t}\n\telse if ( !asc && desc ) {\n\t\tnoSortAppliedClass = sort_prefix+'caret-1-s';\n\t}\n\n\t// Setup the DOM structure\n\t$('<div/>')\n\t\t.addClass( 'DataTables_sort_wrapper' )\n\t\t.append( cell.contents() )\n\t\t.append( $('<span/>')\n\t\t\t.addClass( classes.sSortIcon+' '+noSortAppliedClass )\n\t\t)\n\t\t.appendTo( cell );\n\n\t// Attach a sort listener to update on sort\n\t$(settings.nTable).on( 'order.dt', function ( e, ctx, sorting, columns ) {\n\t\tif ( settings !== ctx ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar colIdx = column.idx;\n\n\t\tcell\n\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\tcolumn.sSortingClass\n\t\t\t);\n\n\t\tcell\n\t\t\t.find( 'span.'+classes.sSortIcon )\n\t\t\t.removeClass(\n\t\t\t\tsort_prefix+'triangle-1-n' +\" \"+\n\t\t\t\tsort_prefix+'triangle-1-s' +\" \"+\n\t\t\t\tsort_prefix+'caret-2-n-s' +\" \"+\n\t\t\t\tsort_prefix+'caret-1-n' +\" \"+\n\t\t\t\tsort_prefix+'caret-1-s'\n\t\t\t)\n\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\tsort_prefix+'triangle-1-n' : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\tsort_prefix+'triangle-1-s' :\n\t\t\t\t\tnoSortAppliedClass\n\t\t\t);\n\t} );\n};\n\n\n/*\n * TableTools jQuery UI compatibility\n * Required TableTools 2.1+\n */\nif ( DataTable.TableTools ) {\n\t$.extend( true, DataTable.TableTools.classes, {\n\t\t\"container\": \"DTTT_container ui-buttonset ui-buttonset-multi\",\n\t\t\"buttons\": {\n\t\t\t\"normal\": \"DTTT_button ui-button ui-state-default\"\n\t\t},\n\t\t\"collection\": {\n\t\t\t\"container\": \"DTTT_collection ui-buttonset ui-buttonset-multi\"\n\t\t}\n\t} );\n}\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "static/js/DataTables/DataTables-1.10.18/js/dataTables.semanticui.js",
    "content": "/*! DataTables Bootstrap 3 integration\n * ©2011-2015 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Bootstrap 3. This requires Bootstrap 3 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t// Require DataTables, which attaches to jQuery, including\n\t\t\t\t// jQuery if needed and have a $ property so we can access the\n\t\t\t\t// jQuery object that is used\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'ui stackable grid'\"+\n\t\t\t\"<'row'\"+\n\t\t\t\t\"<'eight wide column'l>\"+\n\t\t\t\t\"<'right aligned eight wide column'f>\"+\n\t\t\t\">\"+\n\t\t\t\"<'row dt-table'\"+\n\t\t\t\t\"<'sixteen wide column'tr>\"+\n\t\t\t\">\"+\n\t\t\t\"<'row'\"+\n\t\t\t\t\"<'seven wide column'i>\"+\n\t\t\t\t\"<'right aligned nine wide column'p>\"+\n\t\t\t\">\"+\n\t\t\">\",\n\trenderer: 'semanticUI'\n} );\n\n\n/* Default class modification */\n$.extend( DataTable.ext.classes, {\n\tsWrapper:      \"dataTables_wrapper dt-semanticUI\",\n\tsFilter:       \"dataTables_filter ui input\",\n\tsProcessing:   \"dataTables_processing ui segment\",\n\tsPageButton:   \"paginate_button item\"\n} );\n\n\n/* Bootstrap paging button renderer */\nDataTable.ext.renderer.pageButton.semanticUI = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api     = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang    = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass, counter=0;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '&#x2026;';\n\t\t\t\t\t\tbtnClass = 'disabled';\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' disabled');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'active' : '';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tvar tag = btnClass.indexOf( 'disabled' ) === -1 ?\n\t\t\t\t\t'a' :\n\t\t\t\t\t'div';\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<'+tag+'>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t'href': '#',\n\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t'tabindex': settings.iTabIndex\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\n\t\t\t\t\tcounter++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t// inside an iframe or frame. \n\tvar activeEl;\n\n\ttry {\n\t\t// Because this approach is destroying and recreating the paging\n\t\t// elements, focus is lost on the select button which is bad for\n\t\t// accessibility. So we want to restore focus once the draw has\n\t\t// completed\n\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t}\n\tcatch (e) {}\n\n\tattach(\n\t\t$(host).empty().html('<div class=\"ui stackable pagination menu\"/>').children(),\n\t\tbuttons\n\t);\n\n\tif ( activeEl !== undefined ) {\n\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t}\n};\n\n\n// Javascript enhancements on table initialisation\n$(document).on( 'init.dt', function (e, ctx) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar api = new $.fn.dataTable.Api( ctx );\n\n\t// Length menu drop down\n\tif ( $.fn.dropdown ) {\n\t\t$( 'div.dataTables_length select', api.table().container() ).dropdown();\n\t}\n\n\t// Filtering input\n\t$( 'div.dataTables_filter.ui.input', api.table().container() ).removeClass('input').addClass('form');\n\t$( 'div.dataTables_filter input', api.table().container() ).wrap( '<span class=\"ui input\" />' );\n} );\n\n\nreturn DataTable;\n}));\n"
  },
  {
    "path": "static/js/DataTables/DataTables-1.10.18/js/jquery.dataTables.js",
    "content": "/*! DataTables 1.10.18\n * ©2008-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     DataTables\n * @description Paginate, search and order HTML tables\n * @version     1.10.18\n * @file        jquery.dataTables.js\n * @author      SpryMedia Ltd\n * @contact     www.datatables.net\n * @copyright   Copyright 2008-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n/*jslint evil: true, undef: true, browser: true */\n/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/\n\n(function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\t// CommonJS environments without a window global must pass a\n\t\t\t\t// root. This will give an error otherwise\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ ) {\n\t\t\t\t$ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window\n\t\t\t\t\trequire('jquery') :\n\t\t\t\t\trequire('jquery')( root );\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}\n(function( $, window, document, undefined ) {\n\t\"use strict\";\n\n\t/**\n\t * DataTables is a plug-in for the jQuery Javascript library. It is a highly\n\t * flexible tool, based upon the foundations of progressive enhancement,\n\t * which will add advanced interaction controls to any HTML table. For a\n\t * full list of features please refer to\n\t * [DataTables.net](href=\"http://datatables.net).\n\t *\n\t * Note that the `DataTable` object is not a global variable but is aliased\n\t * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may\n\t * be  accessed.\n\t *\n\t *  @class\n\t *  @param {object} [init={}] Configuration object for DataTables. Options\n\t *    are defined by {@link DataTable.defaults}\n\t *  @requires jQuery 1.7+\n\t *\n\t *  @example\n\t *    // Basic initialisation\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable();\n\t *    } );\n\t *\n\t *  @example\n\t *    // Initialisation with configuration options - in this case, disable\n\t *    // pagination and sorting.\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable( {\n\t *        \"paginate\": false,\n\t *        \"sort\": false\n\t *      } );\n\t *    } );\n\t */\n\tvar DataTable = function ( options )\n\t{\n\t\t/**\n\t\t * Perform a jQuery selector action on the table's TR elements (from the tbody) and\n\t\t * return the resulting jQuery object.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter\n\t\t *    criterion (\"applied\") or all TR elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {object} jQuery object, filtered by the given selector.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Highlight every second row\n\t\t *      oTable.$('tr:odd').css('backgroundColor', 'blue');\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to rows with 'Webkit' in them, add a background colour and then\n\t\t *      // remove the filter, thus highlighting the 'Webkit' rows only.\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      oTable.$('tr', {\"search\": \"applied\"}).css('backgroundColor', 'blue');\n\t\t *      oTable.fnFilter('');\n\t\t *    } );\n\t\t */\n\t\tthis.$ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).$( sSelector, oOpts );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Almost identical to $ in operation, but in this case returns the data for the matched\n\t\t * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes\n\t\t * rather than any descendants, so the data can be obtained for the row/cell. If matching\n\t\t * rows are found, the data returned is the original data array/object that was used to\n\t\t * create the row (or a generated array if from a DOM source).\n\t\t *\n\t\t * This method is often useful in-combination with $ where both functions are given the\n\t\t * same parameters and the array indexes will match identically.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select elements that meet the current filter\n\t\t *    criterion (\"applied\") or all elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the data in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {array} Data for the matched elements. If any elements, as a result of the\n\t\t *    selector, were not TR, TD or TH elements in the DataTable, they will have a null\n\t\t *    entry in the array.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the data from the first row in the table\n\t\t *      var data = oTable._('tr:first');\n\t\t *\n\t\t *      // Do something useful with the data\n\t\t *      alert( \"First cell is: \"+data[0] );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to 'Webkit' and get all data for\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      var data = oTable._('tr', {\"search\": \"applied\"});\n\t\t *\n\t\t *      // Do something with the data\n\t\t *      alert( data.length+\" rows matched the search\" );\n\t\t *    } );\n\t\t */\n\t\tthis._ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).rows( sSelector, oOpts ).data();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Create a DataTables Api instance, with the currently selected tables for\n\t\t * the Api's context.\n\t\t * @param {boolean} [traditional=false] Set the API instance's context to be\n\t\t *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was\n\t\t *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),\n\t\t *   or if all tables captured in the jQuery object should be used.\n\t\t * @return {DataTables.Api}\n\t\t */\n\t\tthis.api = function ( traditional )\n\t\t{\n\t\t\treturn traditional ?\n\t\t\t\tnew _Api(\n\t\t\t\t\t_fnSettingsFromNode( this[ _ext.iApiIndex ] )\n\t\t\t\t) :\n\t\t\t\tnew _Api( this );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Add a single new row or multiple rows of data to the table. Please note\n\t\t * that this is suitable for client-side processing only - if you are using\n\t\t * server-side processing (i.e. \"bServerSide\": true), then to add data, you\n\t\t * must add it to the data source, i.e. the server-side, through an Ajax call.\n\t\t *  @param {array|object} data The data to be added to the table. This can be:\n\t\t *    <ul>\n\t\t *      <li>1D array of data - add a single row with the data provided</li>\n\t\t *      <li>2D array of arrays - add multiple rows in a single call</li>\n\t\t *      <li>object - data object when using <i>mData</i></li>\n\t\t *      <li>array of objects - multiple data objects when using <i>mData</i></li>\n\t\t *    </ul>\n\t\t *  @param {bool} [redraw=true] redraw the table or not\n\t\t *  @returns {array} An array of integers, representing the list of indexes in\n\t\t *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to\n\t\t *    the table.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Global var for counter\n\t\t *    var giCount = 2;\n\t\t *\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example').dataTable();\n\t\t *    } );\n\t\t *\n\t\t *    function fnClickAddRow() {\n\t\t *      $('#example').dataTable().fnAddData( [\n\t\t *        giCount+\".1\",\n\t\t *        giCount+\".2\",\n\t\t *        giCount+\".3\",\n\t\t *        giCount+\".4\" ]\n\t\t *      );\n\t\t *\n\t\t *      giCount++;\n\t\t *    }\n\t\t */\n\t\tthis.fnAddData = function( data, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\t/* Check if we want to add multiple rows or not */\n\t\t\tvar rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?\n\t\t\t\tapi.rows.add( data ) :\n\t\t\t\tapi.row.add( data );\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn rows.flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will make DataTables recalculate the column sizes, based on the data\n\t\t * contained in the table and the sizes applied to the columns (in the DOM, CSS or\n\t\t * through the sWidth parameter). This can be useful when the width of the table's\n\t\t * parent element changes (for example a window resize).\n\t\t *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable( {\n\t\t *        \"sScrollY\": \"200px\",\n\t\t *        \"bPaginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      $(window).on('resize', function () {\n\t\t *        oTable.fnAdjustColumnSizing();\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnAdjustColumnSizing = function ( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).columns.adjust();\n\t\t\tvar settings = api.settings()[0];\n\t\t\tvar scroll = settings.oScroll;\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw( false );\n\t\t\t}\n\t\t\telse if ( scroll.sX !== \"\" || scroll.sY !== \"\" ) {\n\t\t\t\t/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */\n\t\t\t\t_fnScrollDraw( settings );\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Quickly and simply clear a table\n\t\t *  @param {bool} [bRedraw=true] redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)\n\t\t *      oTable.fnClearTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClearTable = function( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).clear();\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * The exact opposite of 'opening' a row, this function will close any rows which\n\t\t * are currently 'open'.\n\t\t *  @param {node} nTr the table row to 'close'\n\t\t *  @returns {int} 0 on success, or 1 if failed (can't find the row)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClose = function( nTr )\n\t\t{\n\t\t\tthis.api( true ).row( nTr ).child.hide();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Remove a row for the table\n\t\t *  @param {mixed} target The index of the row from aoData to be deleted, or\n\t\t *    the TR element you want to delete\n\t\t *  @param {function|null} [callBack] Callback function\n\t\t *  @param {bool} [redraw=true] Redraw the table or not\n\t\t *  @returns {array} The row that was deleted\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately remove the first row\n\t\t *      oTable.fnDeleteRow( 0 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnDeleteRow = function( target, callback, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar rows = api.rows( target );\n\t\t\tvar settings = rows.settings()[0];\n\t\t\tvar data = settings.aoData[ rows[0][0] ];\n\t\t\n\t\t\trows.remove();\n\t\t\n\t\t\tif ( callback ) {\n\t\t\t\tcallback.call( this, settings, data );\n\t\t\t}\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn data;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Restore the table to it's original state in the DOM by removing all of DataTables\n\t\t * enhancements, alterations to the DOM structure of the table and event listeners.\n\t\t *  @param {boolean} [remove=false] Completely remove the table from the DOM\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      // This example is fairly pointless in reality, but shows how fnDestroy can be used\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnDestroy();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDestroy = function ( remove )\n\t\t{\n\t\t\tthis.api( true ).destroy( remove );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Redraw the table\n\t\t *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)\n\t\t *      oTable.fnDraw();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDraw = function( complete )\n\t\t{\n\t\t\t// Note that this isn't an exact match to the old call to _fnDraw - it takes\n\t\t\t// into account the new data, but can hold position.\n\t\t\tthis.api( true ).draw( complete );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Filter the input based on data\n\t\t *  @param {string} sInput String to filter the table on\n\t\t *  @param {int|null} [iColumn] Column to limit filtering to\n\t\t *  @param {bool} [bRegex=false] Treat as regular expression or not\n\t\t *  @param {bool} [bSmart=true] Perform smart filtering or not\n\t\t *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)\n\t\t *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sometime later - filter...\n\t\t *      oTable.fnFilter( 'test string' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === null || iColumn === undefined ) {\n\t\t\t\tapi.search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\n\t\t\tapi.draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the data for the whole table, an individual row or an individual cell based on the\n\t\t * provided parameters.\n\t\t *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as\n\t\t *    a TR node then the data source for the whole row will be returned. If given as a\n\t\t *    TD/TH cell node then iCol will be automatically calculated and the data for the\n\t\t *    cell returned. If given as an integer, then this is treated as the aoData internal\n\t\t *    data index for the row (see fnGetPosition) and the data for that row used.\n\t\t *  @param {int} [col] Optional column index that you want the data of.\n\t\t *  @returns {array|object|string} If mRow is undefined, then the data for all rows is\n\t\t *    returned. If mRow is defined, just data for that row, and is iCol is\n\t\t *    defined, only data for the designated cell is returned.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Row data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('tr').click( function () {\n\t\t *        var data = oTable.fnGetData( this );\n\t\t *        // ... do something with the array / object of data for the row\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Individual cell data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('td').click( function () {\n\t\t *        var sData = oTable.fnGetData( this );\n\t\t *        alert( 'The cell clicked on had the value of '+sData );\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetData = function( src, col )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( src !== undefined ) {\n\t\t\t\tvar type = src.nodeName ? src.nodeName.toLowerCase() : '';\n\t\t\n\t\t\t\treturn col !== undefined || type == 'td' || type == 'th' ?\n\t\t\t\t\tapi.cell( src, col ).data() :\n\t\t\t\t\tapi.row( src ).data() || null;\n\t\t\t}\n\t\t\n\t\t\treturn api.data().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get an array of the TR nodes that are used in the table's body. Note that you will\n\t\t * typically want to use the '$' API method in preference to this as it is more\n\t\t * flexible.\n\t\t *  @param {int} [iRow] Optional row index for the TR element you want\n\t\t *  @returns {array|node} If iRow is undefined, returns an array of all TR elements\n\t\t *    in the table's body, or iRow is defined, just the TR element requested.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the nodes from the table\n\t\t *      var nNodes = oTable.fnGetNodes( );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetNodes = function( iRow )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\treturn iRow !== undefined ?\n\t\t\t\tapi.row( iRow ).node() :\n\t\t\t\tapi.rows().nodes().flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the array indexes of a particular cell from it's DOM element\n\t\t * and column index including hidden columns\n\t\t *  @param {node} node this can either be a TR, TD or TH in the table's body\n\t\t *  @returns {int} If nNode is given as a TR, then a single index is returned, or\n\t\t *    if given as a cell, an array of [row index, column index (visible),\n\t\t *    column index (all)] is given.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example tbody td').click( function () {\n\t\t *        // Get the position of the current data from the node\n\t\t *        var aPos = oTable.fnGetPosition( this );\n\t\t *\n\t\t *        // Get the data array for this row\n\t\t *        var aData = oTable.fnGetData( aPos[0] );\n\t\t *\n\t\t *        // Update the data array and return the value\n\t\t *        aData[ aPos[1] ] = 'clicked';\n\t\t *        this.innerHTML = 'clicked';\n\t\t *      } );\n\t\t *\n\t\t *      // Init DataTables\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetPosition = function( node )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar nodeName = node.nodeName.toUpperCase();\n\t\t\n\t\t\tif ( nodeName == 'TR' ) {\n\t\t\t\treturn api.row( node ).index();\n\t\t\t}\n\t\t\telse if ( nodeName == 'TD' || nodeName == 'TH' ) {\n\t\t\t\tvar cell = api.cell( node ).index();\n\t\t\n\t\t\t\treturn [\n\t\t\t\t\tcell.row,\n\t\t\t\t\tcell.columnVisible,\n\t\t\t\t\tcell.column\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Check to see if a row is 'open' or not.\n\t\t *  @param {node} nTr the table row to check\n\t\t *  @returns {boolean} true if the row is currently open, false otherwise\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnIsOpen = function( nTr )\n\t\t{\n\t\t\treturn this.api( true ).row( nTr ).child.isShown();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will place a new row directly after a row which is currently\n\t\t * on display on the page, with the HTML contents that is passed into the\n\t\t * function. This can be used, for example, to ask for confirmation that a\n\t\t * particular record should be deleted.\n\t\t *  @param {node} nTr The table row to 'open'\n\t\t *  @param {string|node|jQuery} mHtml The HTML to put into the row\n\t\t *  @param {string} sClass Class to give the new TD cell\n\t\t *  @returns {node} The row opened. Note that if the table row passed in as the\n\t\t *    first parameter, is not found in the table, this method will silently\n\t\t *    return.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnOpen = function( nTr, mHtml, sClass )\n\t\t{\n\t\t\treturn this.api( true )\n\t\t\t\t.row( nTr )\n\t\t\t\t.child( mHtml, sClass )\n\t\t\t\t.show()\n\t\t\t\t.child()[0];\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Change the pagination - provides the internal logic for pagination in a simple API\n\t\t * function. With this function you can have a DataTables table go to the next,\n\t\t * previous, first or last pages.\n\t\t *  @param {string|int} mAction Paging action to take: \"first\", \"previous\", \"next\" or \"last\"\n\t\t *    or page number to jump to (integer), note that page 0 is the first page.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnPageChange( 'next' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnPageChange = function ( mAction, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).page( mAction );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw(false);\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Show a particular column\n\t\t *  @param {int} iCol The column whose display should be changed\n\t\t *  @param {bool} bShow Show (true) or hide (false) the column\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Hide the second column after initialisation\n\t\t *      oTable.fnSetColumnVis( 1, false );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSetColumnVis = function ( iCol, bShow, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).column( iCol ).visible( bShow );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.columns.adjust().draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the settings for a particular table for external manipulation\n\t\t *  @returns {object} DataTables settings object. See\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      var oSettings = oTable.fnSettings();\n\t\t *\n\t\t *      // Show an example parameter from the settings\n\t\t *      alert( oSettings._iDisplayStart );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSettings = function()\n\t\t{\n\t\t\treturn _fnSettingsFromNode( this[_ext.iApiIndex] );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Sort the table by a particular column\n\t\t *  @param {int} iCol the data index to sort on. Note that this will not match the\n\t\t *    'display index' if you have hidden data entries\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort immediately with columns 0 and 1\n\t\t *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSort = function( aaSort )\n\t\t{\n\t\t\tthis.api( true ).order( aaSort ).draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Attach a sort listener to an element for a given column\n\t\t *  @param {node} nNode the element to attach the sort listener to\n\t\t *  @param {int} iColumn the column that a click on this node will sort on\n\t\t *  @param {function} [fnCallback] callback function when sort is run\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort on column 1, when 'sorter' is clicked on\n\t\t *      oTable.fnSortListener( document.getElementById('sorter'), 1 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSortListener = function( nNode, iColumn, fnCallback )\n\t\t{\n\t\t\tthis.api( true ).order.listener( nNode, iColumn, fnCallback );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Update a table cell or row - this method will accept either a single value to\n\t\t * update the cell with, an array of values with one element for each column or\n\t\t * an object in the same format as the original data source. The function is\n\t\t * self-referencing in order to make the multi column updates easier.\n\t\t *  @param {object|array|string} mData Data to update the cell/row with\n\t\t *  @param {node|int} mRow TR element you want to update or the aoData index\n\t\t *  @param {int} [iColumn] The column to update, give as null or undefined to\n\t\t *    update a whole row.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @param {bool} [bAction=true] Perform pre-draw actions or not\n\t\t *  @returns {int} 0 on success, 1 on error\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell\n\t\t *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row\n\t\t *    } );\n\t\t */\n\t\tthis.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === undefined || iColumn === null ) {\n\t\t\t\tapi.row( mRow ).data( mData );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.cell( mRow, iColumn ).data( mData );\n\t\t\t}\n\t\t\n\t\t\tif ( bAction === undefined || bAction ) {\n\t\t\t\tapi.columns.adjust();\n\t\t\t}\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Provide a common method for plug-ins to check the version of DataTables being used, in order\n\t\t * to ensure compatibility.\n\t\t *  @param {string} sVersion Version string to check for, in the format \"X.Y.Z\". Note that the\n\t\t *    formats \"X\" and \"X.Y\" are also acceptable.\n\t\t *  @returns {boolean} true if this version of DataTables is greater or equal to the required\n\t\t *    version, or false if this version of DataTales is not suitable\n\t\t *  @method\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      alert( oTable.fnVersionCheck( '1.9.0' ) );\n\t\t *    } );\n\t\t */\n\t\tthis.fnVersionCheck = _ext.fnVersionCheck;\n\t\t\n\n\t\tvar _that = this;\n\t\tvar emptyInit = options === undefined;\n\t\tvar len = this.length;\n\n\t\tif ( emptyInit ) {\n\t\t\toptions = {};\n\t\t}\n\n\t\tthis.oApi = this.internal = _ext.internal;\n\n\t\t// Extend with old style plug-in API methods\n\t\tfor ( var fn in DataTable.ext.internal ) {\n\t\t\tif ( fn ) {\n\t\t\t\tthis[fn] = _fnExternApiFunc(fn);\n\t\t\t}\n\t\t}\n\n\t\tthis.each(function() {\n\t\t\t// For each initialisation we want to give it a clean initialisation\n\t\t\t// object that can be bashed around\n\t\t\tvar o = {};\n\t\t\tvar oInit = len > 1 ? // optimisation for single table case\n\t\t\t\t_fnExtend( o, options, true ) :\n\t\t\t\toptions;\n\n\t\t\t/*global oInit,_that,emptyInit*/\n\t\t\tvar i=0, iLen, j, jLen, k, kLen;\n\t\t\tvar sId = this.getAttribute( 'id' );\n\t\t\tvar bInitHandedOff = false;\n\t\t\tvar defaults = DataTable.defaults;\n\t\t\tvar $this = $(this);\n\t\t\t\n\t\t\t\n\t\t\t/* Sanity check */\n\t\t\tif ( this.nodeName.toLowerCase() != 'table' )\n\t\t\t{\n\t\t\t\t_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t/* Backwards compatibility for the defaults */\n\t\t\t_fnCompatOpts( defaults );\n\t\t\t_fnCompatCols( defaults.column );\n\t\t\t\n\t\t\t/* Convert the camel-case defaults to Hungarian */\n\t\t\t_fnCamelToHungarian( defaults, defaults, true );\n\t\t\t_fnCamelToHungarian( defaults.column, defaults.column, true );\n\t\t\t\n\t\t\t/* Setting up the initialisation object */\n\t\t\t_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/* Check to see if we are re-initialising a table */\n\t\t\tvar allSettings = DataTable.settings;\n\t\t\tfor ( i=0, iLen=allSettings.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tvar s = allSettings[i];\n\t\t\t\n\t\t\t\t/* Base check on table node */\n\t\t\t\tif (\n\t\t\t\t\ts.nTable == this ||\n\t\t\t\t\t(s.nTHead && s.nTHead.parentNode == this) ||\n\t\t\t\t\t(s.nTFoot && s.nTFoot.parentNode == this)\n\t\t\t\t) {\n\t\t\t\t\tvar bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;\n\t\t\t\t\tvar bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;\n\t\t\t\n\t\t\t\t\tif ( emptyInit || bRetrieve )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn s.oInstance;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( bDestroy )\n\t\t\t\t\t{\n\t\t\t\t\t\ts.oInstance.fnDestroy();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* If the element we are initialising has the same ID as a table which was previously\n\t\t\t\t * initialised, but the table nodes don't match (from before) then we destroy the old\n\t\t\t\t * instance by simply deleting it. This is under the assumption that the table has been\n\t\t\t\t * destroyed by other methods. Anyone using non-id selectors will need to do this manually\n\t\t\t\t */\n\t\t\t\tif ( s.sTableId == this.id )\n\t\t\t\t{\n\t\t\t\t\tallSettings.splice( i, 1 );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Ensure the table has an ID - required for accessibility */\n\t\t\tif ( sId === null || sId === \"\" )\n\t\t\t{\n\t\t\t\tsId = \"DataTables_Table_\"+(DataTable.ext._unique++);\n\t\t\t\tthis.id = sId;\n\t\t\t}\n\t\t\t\n\t\t\t/* Create the settings object for this table and set some of the default parameters */\n\t\t\tvar oSettings = $.extend( true, {}, DataTable.models.oSettings, {\n\t\t\t\t\"sDestroyWidth\": $this[0].style.width,\n\t\t\t\t\"sInstance\":     sId,\n\t\t\t\t\"sTableId\":      sId\n\t\t\t} );\n\t\t\toSettings.nTable = this;\n\t\t\toSettings.oApi   = _that.internal;\n\t\t\toSettings.oInit  = oInit;\n\t\t\t\n\t\t\tallSettings.push( oSettings );\n\t\t\t\n\t\t\t// Need to add the instance after the instance after the settings object has been added\n\t\t\t// to the settings array, so we can self reference the table instance if more than one\n\t\t\toSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();\n\t\t\t\n\t\t\t// Backwards compatibility, before we apply all the defaults\n\t\t\t_fnCompatOpts( oInit );\n\t\t\t_fnLanguageCompat( oInit.oLanguage );\n\t\t\t\n\t\t\t// If the length menu is given, but the init display length is not, use the length menu\n\t\t\tif ( oInit.aLengthMenu && ! oInit.iDisplayLength )\n\t\t\t{\n\t\t\t\toInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?\n\t\t\t\t\toInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];\n\t\t\t}\n\t\t\t\n\t\t\t// Apply the defaults and init options to make a single init object will all\n\t\t\t// options defined from defaults and instance options.\n\t\t\toInit = _fnExtend( $.extend( true, {}, defaults ), oInit );\n\t\t\t\n\t\t\t\n\t\t\t// Map the initialisation options onto the settings object\n\t\t\t_fnMap( oSettings.oFeatures, oInit, [\n\t\t\t\t\"bPaginate\",\n\t\t\t\t\"bLengthChange\",\n\t\t\t\t\"bFilter\",\n\t\t\t\t\"bSort\",\n\t\t\t\t\"bSortMulti\",\n\t\t\t\t\"bInfo\",\n\t\t\t\t\"bProcessing\",\n\t\t\t\t\"bAutoWidth\",\n\t\t\t\t\"bSortClasses\",\n\t\t\t\t\"bServerSide\",\n\t\t\t\t\"bDeferRender\"\n\t\t\t] );\n\t\t\t_fnMap( oSettings, oInit, [\n\t\t\t\t\"asStripeClasses\",\n\t\t\t\t\"ajax\",\n\t\t\t\t\"fnServerData\",\n\t\t\t\t\"fnFormatNumber\",\n\t\t\t\t\"sServerMethod\",\n\t\t\t\t\"aaSorting\",\n\t\t\t\t\"aaSortingFixed\",\n\t\t\t\t\"aLengthMenu\",\n\t\t\t\t\"sPaginationType\",\n\t\t\t\t\"sAjaxSource\",\n\t\t\t\t\"sAjaxDataProp\",\n\t\t\t\t\"iStateDuration\",\n\t\t\t\t\"sDom\",\n\t\t\t\t\"bSortCellsTop\",\n\t\t\t\t\"iTabIndex\",\n\t\t\t\t\"fnStateLoadCallback\",\n\t\t\t\t\"fnStateSaveCallback\",\n\t\t\t\t\"renderer\",\n\t\t\t\t\"searchDelay\",\n\t\t\t\t\"rowId\",\n\t\t\t\t[ \"iCookieDuration\", \"iStateDuration\" ], // backwards compat\n\t\t\t\t[ \"oSearch\", \"oPreviousSearch\" ],\n\t\t\t\t[ \"aoSearchCols\", \"aoPreSearchCols\" ],\n\t\t\t\t[ \"iDisplayLength\", \"_iDisplayLength\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oScroll, oInit, [\n\t\t\t\t[ \"sScrollX\", \"sX\" ],\n\t\t\t\t[ \"sScrollXInner\", \"sXInner\" ],\n\t\t\t\t[ \"sScrollY\", \"sY\" ],\n\t\t\t\t[ \"bScrollCollapse\", \"bCollapse\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oLanguage, oInit, \"fnInfoCallback\" );\n\t\t\t\n\t\t\t/* Callback functions which are array driven */\n\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );\n\t\t\t\n\t\t\toSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );\n\t\t\t\n\t\t\t/* Browser support detection */\n\t\t\t_fnBrowserDetect( oSettings );\n\t\t\t\n\t\t\tvar oClasses = oSettings.oClasses;\n\t\t\t\n\t\t\t$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );\n\t\t\t$this.addClass( oClasses.sTable );\n\t\t\t\n\t\t\t\n\t\t\tif ( oSettings.iInitDisplayStart === undefined )\n\t\t\t{\n\t\t\t\t/* Display start point, taking into account the save saving */\n\t\t\t\toSettings.iInitDisplayStart = oInit.iDisplayStart;\n\t\t\t\toSettings._iDisplayStart = oInit.iDisplayStart;\n\t\t\t}\n\t\t\t\n\t\t\tif ( oInit.iDeferLoading !== null )\n\t\t\t{\n\t\t\t\toSettings.bDeferLoading = true;\n\t\t\t\tvar tmp = $.isArray( oInit.iDeferLoading );\n\t\t\t\toSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;\n\t\t\t\toSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;\n\t\t\t}\n\t\t\t\n\t\t\t/* Language definitions */\n\t\t\tvar oLanguage = oSettings.oLanguage;\n\t\t\t$.extend( true, oLanguage, oInit.oLanguage );\n\t\t\t\n\t\t\tif ( oLanguage.sUrl )\n\t\t\t{\n\t\t\t\t/* Get the language definitions from a file - because this Ajax call makes the language\n\t\t\t\t * get async to the remainder of this function we use bInitHandedOff to indicate that\n\t\t\t\t * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor\n\t\t\t\t */\n\t\t\t\t$.ajax( {\n\t\t\t\t\tdataType: 'json',\n\t\t\t\t\turl: oLanguage.sUrl,\n\t\t\t\t\tsuccess: function ( json ) {\n\t\t\t\t\t\t_fnLanguageCompat( json );\n\t\t\t\t\t\t_fnCamelToHungarian( defaults.oLanguage, json );\n\t\t\t\t\t\t$.extend( true, oLanguage, json );\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t},\n\t\t\t\t\terror: function () {\n\t\t\t\t\t\t// Error occurred loading language file, continue on as best we can\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\tbInitHandedOff = true;\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Stripes\n\t\t\t */\n\t\t\tif ( oInit.asStripeClasses === null )\n\t\t\t{\n\t\t\t\toSettings.asStripeClasses =[\n\t\t\t\t\toClasses.sStripeOdd,\n\t\t\t\t\toClasses.sStripeEven\n\t\t\t\t];\n\t\t\t}\n\t\t\t\n\t\t\t/* Remove row stripe classes if they are already on the table row */\n\t\t\tvar stripeClasses = oSettings.asStripeClasses;\n\t\t\tvar rowOne = $this.children('tbody').find('tr').eq(0);\n\t\t\tif ( $.inArray( true, $.map( stripeClasses, function(el, i) {\n\t\t\t\treturn rowOne.hasClass(el);\n\t\t\t} ) ) !== -1 ) {\n\t\t\t\t$('tbody tr', this).removeClass( stripeClasses.join(' ') );\n\t\t\t\toSettings.asDestroyStripes = stripeClasses.slice();\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Columns\n\t\t\t * See if we should load columns automatically or use defined ones\n\t\t\t */\n\t\t\tvar anThs = [];\n\t\t\tvar aoColumnsInit;\n\t\t\tvar nThead = this.getElementsByTagName('thead');\n\t\t\tif ( nThead.length !== 0 )\n\t\t\t{\n\t\t\t\t_fnDetectHeader( oSettings.aoHeader, nThead[0] );\n\t\t\t\tanThs = _fnGetUniqueThs( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* If not given a column array, generate one with nulls */\n\t\t\tif ( oInit.aoColumns === null )\n\t\t\t{\n\t\t\t\taoColumnsInit = [];\n\t\t\t\tfor ( i=0, iLen=anThs.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\taoColumnsInit.push( null );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taoColumnsInit = oInit.aoColumns;\n\t\t\t}\n\t\t\t\n\t\t\t/* Add the columns */\n\t\t\tfor ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t_fnAddColumn( oSettings, anThs ? anThs[i] : null );\n\t\t\t}\n\t\t\t\n\t\t\t/* Apply the column definitions */\n\t\t\t_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {\n\t\t\t\t_fnColumnOptions( oSettings, iCol, oDef );\n\t\t\t} );\n\t\t\t\n\t\t\t/* HTML5 attribute detection - build an mData object automatically if the\n\t\t\t * attributes are found\n\t\t\t */\n\t\t\tif ( rowOne.length ) {\n\t\t\t\tvar a = function ( cell, name ) {\n\t\t\t\t\treturn cell.getAttribute( 'data-'+name ) !== null ? name : null;\n\t\t\t\t};\n\t\t\t\n\t\t\t\t$( rowOne[0] ).children('th, td').each( function (i, cell) {\n\t\t\t\t\tvar col = oSettings.aoColumns[i];\n\t\t\t\n\t\t\t\t\tif ( col.mData === i ) {\n\t\t\t\t\t\tvar sort = a( cell, 'sort' ) || a( cell, 'order' );\n\t\t\t\t\t\tvar filter = a( cell, 'filter' ) || a( cell, 'search' );\n\t\t\t\n\t\t\t\t\t\tif ( sort !== null || filter !== null ) {\n\t\t\t\t\t\t\tcol.mData = {\n\t\t\t\t\t\t\t\t_:      i+'.display',\n\t\t\t\t\t\t\t\tsort:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\ttype:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\tfilter: filter !== null ? i+'.@data-'+filter : undefined\n\t\t\t\t\t\t\t};\n\t\t\t\n\t\t\t\t\t\t\t_fnColumnOptions( oSettings, i );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\t\n\t\t\tvar features = oSettings.oFeatures;\n\t\t\tvar loadedInit = function () {\n\t\t\t\t/*\n\t\t\t\t * Sorting\n\t\t\t\t * @todo For modularisation (1.11) this needs to do into a sort start up handler\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// If aaSorting is not defined, then we use the first indicator in asSorting\n\t\t\t\t// in case that has been altered, so the default sort reflects that option\n\t\t\t\tif ( oInit.aaSorting === undefined ) {\n\t\t\t\t\tvar sorting = oSettings.aaSorting;\n\t\t\t\t\tfor ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {\n\t\t\t\t\t\tsorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Do a first pass on the sorting classes (allows any size changes to be taken into\n\t\t\t\t * account, and also will apply sorting disabled classes if disabled\n\t\t\t\t */\n\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\n\t\t\t\tif ( features.bSort ) {\n\t\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\t\tif ( oSettings.bSorted ) {\n\t\t\t\t\t\t\tvar aSort = _fnSortFlatten( oSettings );\n\t\t\t\t\t\t\tvar sortedColumns = {};\n\t\t\t\n\t\t\t\t\t\t\t$.each( aSort, function (i, val) {\n\t\t\t\t\t\t\t\tsortedColumns[ val.src ] = val.dir;\n\t\t\t\t\t\t\t} );\n\t\t\t\n\t\t\t\t\t\t\t_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );\n\t\t\t\t\t\t\t_fnSortAria( oSettings );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\tif ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {\n\t\t\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\t\t}\n\t\t\t\t}, 'sc' );\n\t\t\t\n\t\t\t\n\t\t\t\t/*\n\t\t\t\t * Final init\n\t\t\t\t * Cache the header, body and footer as required, creating them if needed\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// Work around for Webkit bug 83867 - store the caption-side before removing from doc\n\t\t\t\tvar captions = $this.children('caption').each( function () {\n\t\t\t\t\tthis._captionSide = $(this).css('caption-side');\n\t\t\t\t} );\n\t\t\t\n\t\t\t\tvar thead = $this.children('thead');\n\t\t\t\tif ( thead.length === 0 ) {\n\t\t\t\t\tthead = $('<thead/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTHead = thead[0];\n\t\t\t\n\t\t\t\tvar tbody = $this.children('tbody');\n\t\t\t\tif ( tbody.length === 0 ) {\n\t\t\t\t\ttbody = $('<tbody/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTBody = tbody[0];\n\t\t\t\n\t\t\t\tvar tfoot = $this.children('tfoot');\n\t\t\t\tif ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== \"\" || oSettings.oScroll.sY !== \"\") ) {\n\t\t\t\t\t// If we are a scrolling table, and no footer has been given, then we need to create\n\t\t\t\t\t// a tfoot element for the caption element to be appended to\n\t\t\t\t\ttfoot = $('<tfoot/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( tfoot.length === 0 || tfoot.children().length === 0 ) {\n\t\t\t\t\t$this.addClass( oClasses.sNoFooter );\n\t\t\t\t}\n\t\t\t\telse if ( tfoot.length > 0 ) {\n\t\t\t\t\toSettings.nTFoot = tfoot[0];\n\t\t\t\t\t_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Check if there is data passing into the constructor */\n\t\t\t\tif ( oInit.aaData ) {\n\t\t\t\t\tfor ( i=0 ; i<oInit.aaData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( oSettings, oInit.aaData[ i ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {\n\t\t\t\t\t/* Grab the data from the page - only do this when deferred loading or no Ajax\n\t\t\t\t\t * source since there is no point in reading the DOM data if we are then going\n\t\t\t\t\t * to replace it with Ajax data\n\t\t\t\t\t */\n\t\t\t\t\t_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Copy the data index array */\n\t\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\n\t\t\t\t/* Initialisation complete - table can be drawn */\n\t\t\t\toSettings.bInitialised = true;\n\t\t\t\n\t\t\t\t/* Check if we need to initialise the table (it might not have been handed off to the\n\t\t\t\t * language processor)\n\t\t\t\t */\n\t\t\t\tif ( bInitHandedOff === false ) {\n\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t}\n\t\t\t};\n\t\t\t\n\t\t\t/* Must be done after everything which can be overridden by the state saving! */\n\t\t\tif ( oInit.bStateSave )\n\t\t\t{\n\t\t\t\tfeatures.bStateSave = true;\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );\n\t\t\t\t_fnLoadState( oSettings, oInit, loadedInit );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadedInit();\n\t\t\t}\n\t\t\t\n\t\t} );\n\t\t_that = null;\n\t\treturn this;\n\t};\n\n\t\n\t/*\n\t * It is useful to have variables which are scoped locally so only the\n\t * DataTables functions can access them and they don't leak into global space.\n\t * At the same time these functions are often useful over multiple files in the\n\t * core and API, so we list, or at least document, all variables which are used\n\t * by DataTables as private variables here. This also ensures that there is no\n\t * clashing of variable names and that they can easily referenced for reuse.\n\t */\n\t\n\t\n\t// Defined else where\n\t//  _selector_run\n\t//  _selector_opts\n\t//  _selector_first\n\t//  _selector_row_indexes\n\t\n\tvar _ext; // DataTable.ext\n\tvar _Api; // DataTable.Api\n\tvar _api_register; // DataTable.Api.register\n\tvar _api_registerPlural; // DataTable.Api.registerPlural\n\t\n\tvar _re_dic = {};\n\tvar _re_new_lines = /[\\r\\n]/g;\n\tvar _re_html = /<.*?>/g;\n\t\n\t// This is not strict ISO8601 - Date.parse() is quite lax, although\n\t// implementations differ between browsers.\n\tvar _re_date = /^\\d{2,4}[\\.\\/\\-]\\d{1,2}[\\.\\/\\-]\\d{1,2}([T ]{1}\\d{1,2}[:\\.]\\d{2}([\\.:]\\d{2})?)?$/;\n\t\n\t// Escape regular expression special characters\n\tvar _re_escape_regex = new RegExp( '(\\\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\\\', '$', '^', '-' ].join('|\\\\') + ')', 'g' );\n\t\n\t// http://en.wikipedia.org/wiki/Foreign_exchange_market\n\t// - \\u20BD - Russian ruble.\n\t// - \\u20a9 - South Korean Won\n\t// - \\u20BA - Turkish Lira\n\t// - \\u20B9 - Indian Rupee\n\t// - R - Brazil (R$) and South Africa\n\t// - fr - Swiss Franc\n\t// - kr - Swedish krona, Norwegian krone and Danish krone\n\t// - \\u2009 is thin space and \\u202F is narrow no-break space, both used in many\n\t// - Ƀ - Bitcoin\n\t// - Ξ - Ethereum\n\t//   standards as thousands separators.\n\tvar _re_formatted_numeric = /[',$£€¥%\\u2009\\u202F\\u20BD\\u20a9\\u20BArfkɃΞ]/gi;\n\t\n\t\n\tvar _empty = function ( d ) {\n\t\treturn !d || d === true || d === '-' ? true : false;\n\t};\n\t\n\t\n\tvar _intVal = function ( s ) {\n\t\tvar integer = parseInt( s, 10 );\n\t\treturn !isNaN(integer) && isFinite(s) ? integer : null;\n\t};\n\t\n\t// Convert from a formatted number with characters other than `.` as the\n\t// decimal place, to a Javascript number\n\tvar _numToDecimal = function ( num, decimalPoint ) {\n\t\t// Cache created regular expressions for speed as this function is called often\n\t\tif ( ! _re_dic[ decimalPoint ] ) {\n\t\t\t_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );\n\t\t}\n\t\treturn typeof num === 'string' && decimalPoint !== '.' ?\n\t\t\tnum.replace( /\\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :\n\t\t\tnum;\n\t};\n\t\n\t\n\tvar _isNumber = function ( d, decimalPoint, formatted ) {\n\t\tvar strType = typeof d === 'string';\n\t\n\t\t// If empty return immediately so there must be a number if it is a\n\t\t// formatted string (this stops the string \"k\", or \"kr\", etc being detected\n\t\t// as a formatted number for currency\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tif ( decimalPoint && strType ) {\n\t\t\td = _numToDecimal( d, decimalPoint );\n\t\t}\n\t\n\t\tif ( formatted && strType ) {\n\t\t\td = d.replace( _re_formatted_numeric, '' );\n\t\t}\n\t\n\t\treturn !isNaN( parseFloat(d) ) && isFinite( d );\n\t};\n\t\n\t\n\t// A string without HTML in it can be considered to be HTML still\n\tvar _isHtml = function ( d ) {\n\t\treturn _empty( d ) || typeof d === 'string';\n\t};\n\t\n\t\n\tvar _htmlNumeric = function ( d, decimalPoint, formatted ) {\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tvar html = _isHtml( d );\n\t\treturn ! html ?\n\t\t\tnull :\n\t\t\t_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?\n\t\t\t\ttrue :\n\t\t\t\tnull;\n\t};\n\t\n\t\n\tvar _pluck = function ( a, prop, prop2 ) {\n\t\tvar out = [];\n\t\tvar i=0, ien=a.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] && a[i][ prop ] ) {\n\t\t\t\t\tout.push( a[i][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] ) {\n\t\t\t\t\tout.push( a[i][ prop ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t// Basically the same as _pluck, but rather than looping over `a` we use `order`\n\t// as the indexes to pick from `a`\n\tvar _pluck_order = function ( a, order, prop, prop2 )\n\t{\n\t\tvar out = [];\n\t\tvar i=0, ien=order.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[ order[i] ][ prop ] ) {\n\t\t\t\t\tout.push( a[ order[i] ][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tout.push( a[ order[i] ][ prop ] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _range = function ( len, start )\n\t{\n\t\tvar out = [];\n\t\tvar end;\n\t\n\t\tif ( start === undefined ) {\n\t\t\tstart = 0;\n\t\t\tend = len;\n\t\t}\n\t\telse {\n\t\t\tend = start;\n\t\t\tstart = len;\n\t\t}\n\t\n\t\tfor ( var i=start ; i<end ; i++ ) {\n\t\t\tout.push( i );\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _removeEmpty = function ( a )\n\t{\n\t\tvar out = [];\n\t\n\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\tif ( a[i] ) { // careful - will remove all falsy values!\n\t\t\t\tout.push( a[i] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _stripHtml = function ( d ) {\n\t\treturn d.replace( _re_html, '' );\n\t};\n\t\n\t\n\t/**\n\t * Determine if all values in the array are unique. This means we can short\n\t * cut the _unique method at the cost of a single loop. A sorted array is used\n\t * to easily check the values.\n\t *\n\t * @param  {array} src Source array\n\t * @return {boolean} true if all unique, false otherwise\n\t * @ignore\n\t */\n\tvar _areAllUnique = function ( src ) {\n\t\tif ( src.length < 2 ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tvar sorted = src.slice().sort();\n\t\tvar last = sorted[0];\n\t\n\t\tfor ( var i=1, ien=sorted.length ; i<ien ; i++ ) {\n\t\t\tif ( sorted[i] === last ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\n\t\t\tlast = sorted[i];\n\t\t}\n\t\n\t\treturn true;\n\t};\n\t\n\t\n\t/**\n\t * Find the unique elements in a source array.\n\t *\n\t * @param  {array} src Source array\n\t * @return {array} Array of unique items\n\t * @ignore\n\t */\n\tvar _unique = function ( src )\n\t{\n\t\tif ( _areAllUnique( src ) ) {\n\t\t\treturn src.slice();\n\t\t}\n\t\n\t\t// A faster unique method is to use object keys to identify used values,\n\t\t// but this doesn't work with arrays or objects, which we must also\n\t\t// consider. See jsperf.com/compare-array-unique-versions/4 for more\n\t\t// information.\n\t\tvar\n\t\t\tout = [],\n\t\t\tval,\n\t\t\ti, ien=src.length,\n\t\t\tj, k=0;\n\t\n\t\tagain: for ( i=0 ; i<ien ; i++ ) {\n\t\t\tval = src[i];\n\t\n\t\t\tfor ( j=0 ; j<k ; j++ ) {\n\t\t\t\tif ( out[j] === val ) {\n\t\t\t\t\tcontinue again;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tout.push( val );\n\t\t\tk++;\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t/**\n\t * DataTables utility methods\n\t * \n\t * This namespace provides helper methods that DataTables uses internally to\n\t * create a DataTable, but which are not exclusively used only for DataTables.\n\t * These methods can be used by extension authors to save the duplication of\n\t * code.\n\t *\n\t *  @namespace\n\t */\n\tDataTable.util = {\n\t\t/**\n\t\t * Throttle the calls to a function. Arguments and context are maintained\n\t\t * for the throttled function.\n\t\t *\n\t\t * @param {function} fn Function to be called\n\t\t * @param {integer} freq Call frequency in mS\n\t\t * @return {function} Wrapped function\n\t\t */\n\t\tthrottle: function ( fn, freq ) {\n\t\t\tvar\n\t\t\t\tfrequency = freq !== undefined ? freq : 200,\n\t\t\t\tlast,\n\t\t\t\ttimer;\n\t\n\t\t\treturn function () {\n\t\t\t\tvar\n\t\t\t\t\tthat = this,\n\t\t\t\t\tnow  = +new Date(),\n\t\t\t\t\targs = arguments;\n\t\n\t\t\t\tif ( last && now < last + frequency ) {\n\t\t\t\t\tclearTimeout( timer );\n\t\n\t\t\t\t\ttimer = setTimeout( function () {\n\t\t\t\t\t\tlast = undefined;\n\t\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t\t}, frequency );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlast = now;\n\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Escape a string such that it can be used in a regular expression\n\t\t *\n\t\t *  @param {string} val string to escape\n\t\t *  @returns {string} escaped string\n\t\t */\n\t\tescapeRegex: function ( val ) {\n\t\t\treturn val.replace( _re_escape_regex, '\\\\$1' );\n\t\t}\n\t};\n\t\n\t\n\t\n\t/**\n\t * Create a mapping object that allows camel case parameters to be looked up\n\t * for their Hungarian counterparts. The mapping is stored in a private\n\t * parameter called `_hungarianMap` which can be accessed on the source object.\n\t *  @param {object} o\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnHungarianMap ( o )\n\t{\n\t\tvar\n\t\t\thungarian = 'a aa ai ao as b fn i m o s ',\n\t\t\tmatch,\n\t\t\tnewKey,\n\t\t\tmap = {};\n\t\n\t\t$.each( o, function (key, val) {\n\t\t\tmatch = key.match(/^([^A-Z]+?)([A-Z])/);\n\t\n\t\t\tif ( match && hungarian.indexOf(match[1]+' ') !== -1 )\n\t\t\t{\n\t\t\t\tnewKey = key.replace( match[0], match[2].toLowerCase() );\n\t\t\t\tmap[ newKey ] = key;\n\t\n\t\t\t\tif ( match[1] === 'o' )\n\t\t\t\t{\n\t\t\t\t\t_fnHungarianMap( o[key] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t\n\t\to._hungarianMap = map;\n\t}\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian, based on a Hungarian map\n\t * created by _fnHungarianMap.\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCamelToHungarian ( src, user, force )\n\t{\n\t\tif ( ! src._hungarianMap ) {\n\t\t\t_fnHungarianMap( src );\n\t\t}\n\t\n\t\tvar hungarianKey;\n\t\n\t\t$.each( user, function (key, val) {\n\t\t\thungarianKey = src._hungarianMap[ key ];\n\t\n\t\t\tif ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )\n\t\t\t{\n\t\t\t\t// For objects, we need to buzz down into the object to copy parameters\n\t\t\t\tif ( hungarianKey.charAt(0) === 'o' )\n\t\t\t\t{\n\t\t\t\t\t// Copy the camelCase options over to the hungarian\n\t\t\t\t\tif ( ! user[ hungarianKey ] ) {\n\t\t\t\t\t\tuser[ hungarianKey ] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, user[hungarianKey], user[key] );\n\t\n\t\t\t\t\t_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tuser[hungarianKey] = user[ key ];\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Language compatibility - when certain options are given, and others aren't, we\n\t * need to duplicate the values over, in order to provide backwards compatibility\n\t * with older language files.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLanguageCompat( lang )\n\t{\n\t\t// Note the use of the Hungarian notation for the parameters in this method as\n\t\t// this is called after the mapping of camelCase to Hungarian\n\t\tvar defaults = DataTable.defaults.oLanguage;\n\t\n\t\t// Default mapping\n\t\tvar defaultDecimal = defaults.sDecimal;\n\t\tif ( defaultDecimal ) {\n\t\t\t_addNumericSort( defaultDecimal );\n\t\t}\n\t\n\t\tif ( lang ) {\n\t\t\tvar zeroRecords = lang.sZeroRecords;\n\t\n\t\t\t// Backwards compatibility - if there is no sEmptyTable given, then use the same as\n\t\t\t// sZeroRecords - assuming that is given.\n\t\t\tif ( ! lang.sEmptyTable && zeroRecords &&\n\t\t\t\tdefaults.sEmptyTable === \"No data available in table\" )\n\t\t\t{\n\t\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );\n\t\t\t}\n\t\n\t\t\t// Likewise with loading records\n\t\t\tif ( ! lang.sLoadingRecords && zeroRecords &&\n\t\t\t\tdefaults.sLoadingRecords === \"Loading...\" )\n\t\t\t{\n\t\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );\n\t\t\t}\n\t\n\t\t\t// Old parameter name of the thousands separator mapped onto the new\n\t\t\tif ( lang.sInfoThousands ) {\n\t\t\t\tlang.sThousands = lang.sInfoThousands;\n\t\t\t}\n\t\n\t\t\tvar decimal = lang.sDecimal;\n\t\t\tif ( decimal && defaultDecimal !== decimal ) {\n\t\t\t\t_addNumericSort( decimal );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Map one parameter onto another\n\t *  @param {object} o Object to map\n\t *  @param {*} knew The new parameter name\n\t *  @param {*} old The old parameter name\n\t */\n\tvar _fnCompatMap = function ( o, knew, old ) {\n\t\tif ( o[ knew ] !== undefined ) {\n\t\t\to[ old ] = o[ knew ];\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for the main DT options. Note that the new\n\t * options are mapped onto the old parameters, so this is an external interface\n\t * change only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatOpts ( init )\n\t{\n\t\t_fnCompatMap( init, 'ordering',      'bSort' );\n\t\t_fnCompatMap( init, 'orderMulti',    'bSortMulti' );\n\t\t_fnCompatMap( init, 'orderClasses',  'bSortClasses' );\n\t\t_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );\n\t\t_fnCompatMap( init, 'order',         'aaSorting' );\n\t\t_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );\n\t\t_fnCompatMap( init, 'paging',        'bPaginate' );\n\t\t_fnCompatMap( init, 'pagingType',    'sPaginationType' );\n\t\t_fnCompatMap( init, 'pageLength',    'iDisplayLength' );\n\t\t_fnCompatMap( init, 'searching',     'bFilter' );\n\t\n\t\t// Boolean initialisation of x-scrolling\n\t\tif ( typeof init.sScrollX === 'boolean' ) {\n\t\t\tinit.sScrollX = init.sScrollX ? '100%' : '';\n\t\t}\n\t\tif ( typeof init.scrollX === 'boolean' ) {\n\t\t\tinit.scrollX = init.scrollX ? '100%' : '';\n\t\t}\n\t\n\t\t// Column search objects are in an array, so it needs to be converted\n\t\t// element by element\n\t\tvar searchCols = init.aoSearchCols;\n\t\n\t\tif ( searchCols ) {\n\t\t\tfor ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {\n\t\t\t\tif ( searchCols[i] ) {\n\t\t\t\t\t_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for column options. Note that the new options\n\t * are mapped onto the old parameters, so this is an external interface change\n\t * only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatCols ( init )\n\t{\n\t\t_fnCompatMap( init, 'orderable',     'bSortable' );\n\t\t_fnCompatMap( init, 'orderData',     'aDataSort' );\n\t\t_fnCompatMap( init, 'orderSequence', 'asSorting' );\n\t\t_fnCompatMap( init, 'orderDataType', 'sortDataType' );\n\t\n\t\t// orderData can be given as an integer\n\t\tvar dataSort = init.aDataSort;\n\t\tif ( typeof dataSort === 'number' && ! $.isArray( dataSort ) ) {\n\t\t\tinit.aDataSort = [ dataSort ];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Browser feature detection for capabilities, quirks\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBrowserDetect( settings )\n\t{\n\t\t// We don't need to do this every time DataTables is constructed, the values\n\t\t// calculated are specific to the browser and OS configuration which we\n\t\t// don't expect to change between initialisations\n\t\tif ( ! DataTable.__browser ) {\n\t\t\tvar browser = {};\n\t\t\tDataTable.__browser = browser;\n\t\n\t\t\t// Scrolling feature / quirks detection\n\t\t\tvar n = $('<div/>')\n\t\t\t\t.css( {\n\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: $(window).scrollLeft()*-1, // allow for scrolling\n\t\t\t\t\theight: 1,\n\t\t\t\t\twidth: 1,\n\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t} )\n\t\t\t\t.append(\n\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\ttop: 1,\n\t\t\t\t\t\t\tleft: 1,\n\t\t\t\t\t\t\twidth: 100,\n\t\t\t\t\t\t\toverflow: 'scroll'\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t\t\t\theight: 10\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t.appendTo( 'body' );\n\t\n\t\t\tvar outer = n.children();\n\t\t\tvar inner = outer.children();\n\t\n\t\t\t// Numbers below, in order, are:\n\t\t\t// inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth\n\t\t\t//\n\t\t\t// IE6 XP:                           100 100 100  83\n\t\t\t// IE7 Vista:                        100 100 100  83\n\t\t\t// IE 8+ Windows:                     83  83 100  83\n\t\t\t// Evergreen Windows:                 83  83 100  83\n\t\t\t// Evergreen Mac with scrollbars:     85  85 100  85\n\t\t\t// Evergreen Mac without scrollbars: 100 100 100 100\n\t\n\t\t\t// Get scrollbar width\n\t\t\tbrowser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;\n\t\n\t\t\t// IE6/7 will oversize a width 100% element inside a scrolling element, to\n\t\t\t// include the width of the scrollbar, while other browsers ensure the inner\n\t\t\t// element is contained without forcing scrolling\n\t\t\tbrowser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;\n\t\n\t\t\t// In rtl text layout, some browsers (most, but not all) will place the\n\t\t\t// scrollbar on the left, rather than the right.\n\t\t\tbrowser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;\n\t\n\t\t\t// IE8- don't provide height and width for getBoundingClientRect\n\t\t\tbrowser.bBounding = n[0].getBoundingClientRect().width ? true : false;\n\t\n\t\t\tn.remove();\n\t\t}\n\t\n\t\t$.extend( settings.oBrowser, DataTable.__browser );\n\t\tsettings.oScroll.iBarWidth = DataTable.__browser.barWidth;\n\t}\n\t\n\t\n\t/**\n\t * Array.prototype reduce[Right] method, used for browsers which don't support\n\t * JS 1.6. Done this way to reduce code size, since we iterate either way\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReduce ( that, fn, init, start, end, inc )\n\t{\n\t\tvar\n\t\t\ti = start,\n\t\t\tvalue,\n\t\t\tisSet = false;\n\t\n\t\tif ( init !== undefined ) {\n\t\t\tvalue = init;\n\t\t\tisSet = true;\n\t\t}\n\t\n\t\twhile ( i !== end ) {\n\t\t\tif ( ! that.hasOwnProperty(i) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\tvalue = isSet ?\n\t\t\t\tfn( value, that[i], i, that ) :\n\t\t\t\tthat[i];\n\t\n\t\t\tisSet = true;\n\t\t\ti += inc;\n\t\t}\n\t\n\t\treturn value;\n\t}\n\t\n\t/**\n\t * Add a column to the list used for the table with default values\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nTh The th element for this column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddColumn( oSettings, nTh )\n\t{\n\t\t// Add column to aoColumns array\n\t\tvar oDefaults = DataTable.defaults.column;\n\t\tvar iCol = oSettings.aoColumns.length;\n\t\tvar oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {\n\t\t\t\"nTh\": nTh ? nTh : document.createElement('th'),\n\t\t\t\"sTitle\":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',\n\t\t\t\"aDataSort\": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],\n\t\t\t\"mData\": oDefaults.mData ? oDefaults.mData : iCol,\n\t\t\tidx: iCol\n\t\t} );\n\t\toSettings.aoColumns.push( oCol );\n\t\n\t\t// Add search object for column specific search. Note that the `searchCols[ iCol ]`\n\t\t// passed into extend can be undefined. This allows the user to give a default\n\t\t// with only some of the parameters defined, and also not give a default\n\t\tvar searchCols = oSettings.aoPreSearchCols;\n\t\tsearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );\n\t\n\t\t// Use the default column options function to initialise classes etc\n\t\t_fnColumnOptions( oSettings, iCol, $(nTh).data() );\n\t}\n\t\n\t\n\t/**\n\t * Apply options for a column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iCol column index to consider\n\t *  @param {object} oOptions object with sType, bVisible and bSearchable etc\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnOptions( oSettings, iCol, oOptions )\n\t{\n\t\tvar oCol = oSettings.aoColumns[ iCol ];\n\t\tvar oClasses = oSettings.oClasses;\n\t\tvar th = $(oCol.nTh);\n\t\n\t\t// Try to get width information from the DOM. We can't get it from CSS\n\t\t// as we'd need to parse the CSS stylesheet. `width` option can override\n\t\tif ( ! oCol.sWidthOrig ) {\n\t\t\t// Width attribute\n\t\t\toCol.sWidthOrig = th.attr('width') || null;\n\t\n\t\t\t// Style attribute\n\t\t\tvar t = (th.attr('style') || '').match(/width:\\s*(\\d+[pxem%]+)/);\n\t\t\tif ( t ) {\n\t\t\t\toCol.sWidthOrig = t[1];\n\t\t\t}\n\t\t}\n\t\n\t\t/* User specified column options */\n\t\tif ( oOptions !== undefined && oOptions !== null )\n\t\t{\n\t\t\t// Backwards compatibility\n\t\t\t_fnCompatCols( oOptions );\n\t\n\t\t\t// Map camel case parameters to their Hungarian counterparts\n\t\t\t_fnCamelToHungarian( DataTable.defaults.column, oOptions );\n\t\n\t\t\t/* Backwards compatibility for mDataProp */\n\t\t\tif ( oOptions.mDataProp !== undefined && !oOptions.mData )\n\t\t\t{\n\t\t\t\toOptions.mData = oOptions.mDataProp;\n\t\t\t}\n\t\n\t\t\tif ( oOptions.sType )\n\t\t\t{\n\t\t\t\toCol._sManualType = oOptions.sType;\n\t\t\t}\n\t\n\t\t\t// `class` is a reserved word in Javascript, so we need to provide\n\t\t\t// the ability to use a valid name for the camel case input\n\t\t\tif ( oOptions.className && ! oOptions.sClass )\n\t\t\t{\n\t\t\t\toOptions.sClass = oOptions.className;\n\t\t\t}\n\t\t\tif ( oOptions.sClass ) {\n\t\t\t\tth.addClass( oOptions.sClass );\n\t\t\t}\n\t\n\t\t\t$.extend( oCol, oOptions );\n\t\t\t_fnMap( oCol, oOptions, \"sWidth\", \"sWidthOrig\" );\n\t\n\t\t\t/* iDataSort to be applied (backwards compatibility), but aDataSort will take\n\t\t\t * priority if defined\n\t\t\t */\n\t\t\tif ( oOptions.iDataSort !== undefined )\n\t\t\t{\n\t\t\t\toCol.aDataSort = [ oOptions.iDataSort ];\n\t\t\t}\n\t\t\t_fnMap( oCol, oOptions, \"aDataSort\" );\n\t\t}\n\t\n\t\t/* Cache the data get and set functions for speed */\n\t\tvar mDataSrc = oCol.mData;\n\t\tvar mData = _fnGetObjectDataFn( mDataSrc );\n\t\tvar mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;\n\t\n\t\tvar attrTest = function( src ) {\n\t\t\treturn typeof src === 'string' && src.indexOf('@') !== -1;\n\t\t};\n\t\toCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (\n\t\t\tattrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)\n\t\t);\n\t\toCol._setter = null;\n\t\n\t\toCol.fnGetData = function (rowData, type, meta) {\n\t\t\tvar innerData = mData( rowData, type, undefined, meta );\n\t\n\t\t\treturn mRender && type ?\n\t\t\t\tmRender( innerData, type, rowData, meta ) :\n\t\t\t\tinnerData;\n\t\t};\n\t\toCol.fnSetData = function ( rowData, val, meta ) {\n\t\t\treturn _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );\n\t\t};\n\t\n\t\t// Indicate if DataTables should read DOM data as an object or array\n\t\t// Used in _fnGetRowElements\n\t\tif ( typeof mDataSrc !== 'number' ) {\n\t\t\toSettings._rowReadObject = true;\n\t\t}\n\t\n\t\t/* Feature sorting overrides column specific when off */\n\t\tif ( !oSettings.oFeatures.bSort )\n\t\t{\n\t\t\toCol.bSortable = false;\n\t\t\tth.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called\n\t\t}\n\t\n\t\t/* Check that the class assignment is correct for sorting */\n\t\tvar bAsc = $.inArray('asc', oCol.asSorting) !== -1;\n\t\tvar bDesc = $.inArray('desc', oCol.asSorting) !== -1;\n\t\tif ( !oCol.bSortable || (!bAsc && !bDesc) )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableNone;\n\t\t\toCol.sSortingClassJUI = \"\";\n\t\t}\n\t\telse if ( bAsc && !bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableAsc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;\n\t\t}\n\t\telse if ( !bAsc && bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableDesc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;\n\t\t}\n\t\telse\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortable;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUI;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Adjust the table column widths for new data. Note: you would probably want to\n\t * do a redraw after calling this function!\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAdjustColumnSizing ( settings )\n\t{\n\t\t/* Not interested in doing column width calculation if auto-width is disabled */\n\t\tif ( settings.oFeatures.bAutoWidth !== false )\n\t\t{\n\t\t\tvar columns = settings.aoColumns;\n\t\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t\tfor ( var i=0 , iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tcolumns[i].nTh.style.width = columns[i].sWidth;\n\t\t\t}\n\t\t}\n\t\n\t\tvar scroll = settings.oScroll;\n\t\tif ( scroll.sY !== '' || scroll.sX !== '')\n\t\t{\n\t\t\t_fnScrollDraw( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'column-sizing', [settings] );\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of a visible column to the index in the data array (take account\n\t * of hidden columns)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iMatch Visible column index to lookup\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisibleToColumnIndex( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\n\t\treturn typeof aiVis[iMatch] === 'number' ?\n\t\t\taiVis[iMatch] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of an index in the data array and convert it to the visible\n\t *   column index (take account of hidden columns)\n\t *  @param {int} iMatch Column index to lookup\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnIndexToVisible( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\tvar iPos = $.inArray( iMatch, aiVis );\n\t\n\t\treturn iPos !== -1 ? iPos : null;\n\t}\n\t\n\t\n\t/**\n\t * Get the number of visible columns\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the number of visible columns\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisbleColumns( oSettings )\n\t{\n\t\tvar vis = 0;\n\t\n\t\t// No reduce in IE8, use a loop for now\n\t\t$.each( oSettings.aoColumns, function ( i, col ) {\n\t\t\tif ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {\n\t\t\t\tvis++;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn vis;\n\t}\n\t\n\t\n\t/**\n\t * Get an array of column indexes that match a given property\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sParam Parameter in aoColumns to look for - typically\n\t *    bVisible or bSearchable\n\t *  @returns {array} Array of indexes with matched properties\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetColumns( oSettings, sParam )\n\t{\n\t\tvar a = [];\n\t\n\t\t$.map( oSettings.aoColumns, function(val, i) {\n\t\t\tif ( val[sParam] ) {\n\t\t\t\ta.push( i );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn a;\n\t}\n\t\n\t\n\t/**\n\t * Calculate the 'type' of a column\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnTypes ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar data = settings.aoData;\n\t\tvar types = DataTable.ext.type.detect;\n\t\tvar i, ien, j, jen, k, ken;\n\t\tvar col, cell, detectedType, cache;\n\t\n\t\t// For each column, spin over the \n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcol = columns[i];\n\t\t\tcache = [];\n\t\n\t\t\tif ( ! col.sType && col._sManualType ) {\n\t\t\t\tcol.sType = col._sManualType;\n\t\t\t}\n\t\t\telse if ( ! col.sType ) {\n\t\t\t\tfor ( j=0, jen=types.length ; j<jen ; j++ ) {\n\t\t\t\t\tfor ( k=0, ken=data.length ; k<ken ; k++ ) {\n\t\t\t\t\t\t// Use a cache array so we only need to get the type data\n\t\t\t\t\t\t// from the formatter once (when using multiple detectors)\n\t\t\t\t\t\tif ( cache[k] === undefined ) {\n\t\t\t\t\t\t\tcache[k] = _fnGetCellData( settings, k, i, 'type' );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tdetectedType = types[j]( cache[k], settings );\n\t\n\t\t\t\t\t\t// If null, then this type can't apply to this column, so\n\t\t\t\t\t\t// rather than testing all cells, break out. There is an\n\t\t\t\t\t\t// exception for the last type which is `html`. We need to\n\t\t\t\t\t\t// scan all rows since it is possible to mix string and HTML\n\t\t\t\t\t\t// types\n\t\t\t\t\t\tif ( ! detectedType && j !== types.length-1 ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Only a single match is needed for html type since it is\n\t\t\t\t\t\t// bottom of the pile and very similar to string\n\t\t\t\t\t\tif ( detectedType === 'html' ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Type is valid for all data points in the column - use this\n\t\t\t\t\t// type\n\t\t\t\t\tif ( detectedType ) {\n\t\t\t\t\t\tcol.sType = detectedType;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Fall back - if no type was detected, always use string\n\t\t\t\tif ( ! col.sType ) {\n\t\t\t\t\tcol.sType = 'string';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Take the column definitions and static columns arrays and calculate how\n\t * they relate to column indexes. The callback function will then apply the\n\t * definition found for a column to a suitable configuration object.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aoColDefs The aoColumnDefs array that is to be applied\n\t *  @param {array} aoCols The aoColumns array that defines columns individually\n\t *  @param {function} fn Callback function - takes two parameters, the calculated\n\t *    column index and the definition for that column.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, def;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Column definitions with aTargets\n\t\tif ( aoColDefs )\n\t\t{\n\t\t\t/* Loop over the definitions array - loop in reverse so first instance has priority */\n\t\t\tfor ( i=aoColDefs.length-1 ; i>=0 ; i-- )\n\t\t\t{\n\t\t\t\tdef = aoColDefs[i];\n\t\n\t\t\t\t/* Each definition can target multiple columns, as it is an array */\n\t\t\t\tvar aTargets = def.targets !== undefined ?\n\t\t\t\t\tdef.targets :\n\t\t\t\t\tdef.aTargets;\n\t\n\t\t\t\tif ( ! $.isArray( aTargets ) )\n\t\t\t\t{\n\t\t\t\t\taTargets = [ aTargets ];\n\t\t\t\t}\n\t\n\t\t\t\tfor ( j=0, jLen=aTargets.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Add columns that we don't yet know about */\n\t\t\t\t\t\twhile( columns.length <= aTargets[j] )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_fnAddColumn( oSettings );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t/* Integer, basic index */\n\t\t\t\t\t\tfn( aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Negative integer, right to left column counting */\n\t\t\t\t\t\tfn( columns.length+aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'string' )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Class name matching on TH element */\n\t\t\t\t\t\tfor ( k=0, kLen=columns.length ; k<kLen ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( aTargets[j] == \"_all\" ||\n\t\t\t\t\t\t\t     $(columns[k].nTh).hasClass( aTargets[j] ) )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfn( k, def );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// Statically defined columns array\n\t\tif ( aoCols )\n\t\t{\n\t\t\tfor ( i=0, iLen=aoCols.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfn( i, aoCols[i] );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * Add a data array to the table, creating DOM node etc. This is the parallel to\n\t * _fnGatherData, but for adding rows from a Javascript source, rather than a\n\t * DOM source.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aData data array to be added\n\t *  @param {node} [nTr] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddData ( oSettings, aDataIn, nTr, anTds )\n\t{\n\t\t/* Create the object for storing information about this new row */\n\t\tvar iRow = oSettings.aoData.length;\n\t\tvar oData = $.extend( true, {}, DataTable.models.oRow, {\n\t\t\tsrc: nTr ? 'dom' : 'data',\n\t\t\tidx: iRow\n\t\t} );\n\t\n\t\toData._aData = aDataIn;\n\t\toSettings.aoData.push( oData );\n\t\n\t\t/* Create the cells */\n\t\tvar nTd, sThisType;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Invalidate the column types as the new data needs to be revalidated\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tcolumns[i].sType = null;\n\t\t}\n\t\n\t\t/* Add to the display array */\n\t\toSettings.aiDisplayMaster.push( iRow );\n\t\n\t\tvar id = oSettings.rowIdFn( aDataIn );\n\t\tif ( id !== undefined ) {\n\t\t\toSettings.aIds[ id ] = oData;\n\t\t}\n\t\n\t\t/* Create the DOM information, or register it if already present */\n\t\tif ( nTr || ! oSettings.oFeatures.bDeferRender )\n\t\t{\n\t\t\t_fnCreateTr( oSettings, iRow, nTr, anTds );\n\t\t}\n\t\n\t\treturn iRow;\n\t}\n\t\n\t\n\t/**\n\t * Add one or more TR elements to the table. Generally we'd expect to\n\t * use this for reading data from a DOM sourced table, but it could be\n\t * used for an TR element. Note that if a TR is given, it is used (i.e.\n\t * it is not cloned).\n\t *  @param {object} settings dataTables settings object\n\t *  @param {array|node|jQuery} trs The TR element(s) to add to the table\n\t *  @returns {array} Array of indexes for the added rows\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddTr( settings, trs )\n\t{\n\t\tvar row;\n\t\n\t\t// Allow an individual node to be passed in\n\t\tif ( ! (trs instanceof $) ) {\n\t\t\ttrs = $(trs);\n\t\t}\n\t\n\t\treturn trs.map( function (i, el) {\n\t\t\trow = _fnGetRowElements( settings, el );\n\t\t\treturn _fnAddData( settings, row.data, el, row.cells );\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Take a TR element and convert it to an index in aoData\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} n the TR element to find\n\t *  @returns {int} index if the node is found, null if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToDataIndex( oSettings, n )\n\t{\n\t\treturn (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;\n\t}\n\t\n\t\n\t/**\n\t * Take a TD element and convert it into a column data index (not the visible index)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow The row number the TD/TH can be found in\n\t *  @param {node} n The TD/TH element to find\n\t *  @returns {int} index if the node is found, -1 if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToColumnIndex( oSettings, iRow, n )\n\t{\n\t\treturn $.inArray( n, oSettings.aoData[ iRow ].anCells );\n\t}\n\t\n\t\n\t/**\n\t * Get the data for a given cell from the internal cache, taking into account data mapping\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {string} type data get type ('display', 'type' 'filter' 'sort')\n\t *  @returns {*} Cell data\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetCellData( settings, rowIdx, colIdx, type )\n\t{\n\t\tvar draw           = settings.iDraw;\n\t\tvar col            = settings.aoColumns[colIdx];\n\t\tvar rowData        = settings.aoData[rowIdx]._aData;\n\t\tvar defaultContent = col.sDefaultContent;\n\t\tvar cellData       = col.fnGetData( rowData, type, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t} );\n\t\n\t\tif ( cellData === undefined ) {\n\t\t\tif ( settings.iDrawError != draw && defaultContent === null ) {\n\t\t\t\t_fnLog( settings, 0, \"Requested unknown parameter \"+\n\t\t\t\t\t(typeof col.mData=='function' ? '{function}' : \"'\"+col.mData+\"'\")+\n\t\t\t\t\t\" for row \"+rowIdx+\", column \"+colIdx, 4 );\n\t\t\t\tsettings.iDrawError = draw;\n\t\t\t}\n\t\t\treturn defaultContent;\n\t\t}\n\t\n\t\t// When the data source is null and a specific data type is requested (i.e.\n\t\t// not the original data), we can use default column data\n\t\tif ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {\n\t\t\tcellData = defaultContent;\n\t\t}\n\t\telse if ( typeof cellData === 'function' ) {\n\t\t\t// If the data source is a function, then we run it and use the return,\n\t\t\t// executing in the scope of the data object (for instances)\n\t\t\treturn cellData.call( rowData );\n\t\t}\n\t\n\t\tif ( cellData === null && type == 'display' ) {\n\t\t\treturn '';\n\t\t}\n\t\treturn cellData;\n\t}\n\t\n\t\n\t/**\n\t * Set the value for a specific cell, into the internal data cache\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {*} val Value to set\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetCellData( settings, rowIdx, colIdx, val )\n\t{\n\t\tvar col     = settings.aoColumns[colIdx];\n\t\tvar rowData = settings.aoData[rowIdx]._aData;\n\t\n\t\tcol.fnSetData( rowData, val, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t}  );\n\t}\n\t\n\t\n\t// Private variable that is used to match action syntax in the data property object\n\tvar __reArray = /\\[.*?\\]$/;\n\tvar __reFn = /\\(\\)$/;\n\t\n\t/**\n\t * Split string on periods, taking into account escaped periods\n\t * @param  {string} str String to split\n\t * @return {array} Split string\n\t */\n\tfunction _fnSplitObjNotation( str )\n\t{\n\t\treturn $.map( str.match(/(\\\\.|[^\\.])+/g) || [''], function ( s ) {\n\t\t\treturn s.replace(/\\\\\\./g, '.');\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to get data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data get function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Build an object of get functions, and wrap them in a single call */\n\t\t\tvar o = {};\n\t\t\t$.each( mSource, function (key, val) {\n\t\t\t\tif ( val ) {\n\t\t\t\t\to[key] = _fnGetObjectDataFn( val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\tvar t = o[type] || o._;\n\t\t\t\treturn t !== undefined ?\n\t\t\t\t\tt(data, type, row, meta) :\n\t\t\t\t\tdata;\n\t\t\t};\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Give an empty string for rendering / sorting etc */\n\t\t\treturn function (data) { // type, row and meta also passed, but not used\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\treturn mSource( data, type, row, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* If there is a . in the source string then the data source is in a\n\t\t\t * nested object so we loop over the data for each level to get the next\n\t\t\t * level down. On each loop we test for undefined, and if found immediately\n\t\t\t * return. This allows entire objects to be missing and sDefaultContent to\n\t\t\t * be used if defined, rather than throwing an error\n\t\t\t */\n\t\t\tvar fetchData = function (data, type, src) {\n\t\t\t\tvar arrayNotation, funcNotation, out, innerSrc;\n\t\n\t\t\t\tif ( src !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tvar a = _fnSplitObjNotation( src );\n\t\n\t\t\t\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check if we are dealing with special notation\n\t\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Array notation\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\n\t\t\t\t\t\t\t// Condition allows simply [] to be passed in\n\t\t\t\t\t\t\tif ( a[i] !== \"\" ) {\n\t\t\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tout = [];\n\t\n\t\t\t\t\t\t\t// Get the remainder of the nested object to get\n\t\t\t\t\t\t\ta.splice( 0, i+1 );\n\t\t\t\t\t\t\tinnerSrc = a.join('.');\n\t\n\t\t\t\t\t\t\t// Traverse each entry in the array getting the properties requested\n\t\t\t\t\t\t\tif ( $.isArray( data ) ) {\n\t\t\t\t\t\t\t\tfor ( var j=0, jLen=data.length ; j<jLen ; j++ ) {\n\t\t\t\t\t\t\t\t\tout.push( fetchData( data[j], type, innerSrc ) );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\t// If a string is given in between the array notation indicators, that\n\t\t\t\t\t\t\t// is used to join the strings together, otherwise an array is returned\n\t\t\t\t\t\t\tvar join = arrayNotation[0].substring(1, arrayNotation[0].length-1);\n\t\t\t\t\t\t\tdata = (join===\"\") ? out : out.join(join);\n\t\n\t\t\t\t\t\t\t// The inner call to fetchData has already traversed through the remainder\n\t\t\t\t\t\t\t// of the source requested, so we exit from the loop\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Function call\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\t\tdata = data[ a[i] ]();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( data === null || data[ a[i] ] === undefined )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn data;\n\t\t\t};\n\t\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn fetchData( data, type, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn data[mSource];\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to set data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data set function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Unlike get, only the underscore (global) option is used for for\n\t\t\t * setting data since we don't know the type here. This is why an object\n\t\t\t * option is not documented for `mData` (which is read/write), but it is\n\t\t\t * for `mRender` which is read only.\n\t\t\t */\n\t\t\treturn _fnSetObjectDataFn( mSource._ );\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Nothing to do when the data source is null */\n\t\t\treturn function () {};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, val, meta) {\n\t\t\t\tmSource( data, 'set', val, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* Like the get, we need to get data from a nested object */\n\t\t\tvar setData = function (data, val, src) {\n\t\t\t\tvar a = _fnSplitObjNotation( src ), b;\n\t\t\t\tvar aLast = a[a.length-1];\n\t\t\t\tvar arrayNotation, funcNotation, o, innerSrc;\n\t\n\t\t\t\tfor ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\t// Check if we are dealing with an array notation request\n\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\t\t\t\t\tdata[ a[i] ] = [];\n\t\n\t\t\t\t\t\t// Get the remainder of the nested object to set so we can recurse\n\t\t\t\t\t\tb = a.slice();\n\t\t\t\t\t\tb.splice( 0, i+1 );\n\t\t\t\t\t\tinnerSrc = b.join('.');\n\t\n\t\t\t\t\t\t// Traverse each entry in the array setting the properties requested\n\t\t\t\t\t\tif ( $.isArray( val ) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor ( var j=0, jLen=val.length ; j<jLen ; j++ )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\to = {};\n\t\t\t\t\t\t\t\tsetData( o, val[j], innerSrc );\n\t\t\t\t\t\t\t\tdata[ a[i] ].push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We've been asked to save data to an array, but it\n\t\t\t\t\t\t\t// isn't array data to be saved. Best that can be done\n\t\t\t\t\t\t\t// is to just save the value.\n\t\t\t\t\t\t\tdata[ a[i] ] = val;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// The inner call to setData has already traversed through the remainder\n\t\t\t\t\t\t// of the source and has set the data, thus we can exit here\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Function call\n\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\tdata = data[ a[i] ]( val );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If the nested object doesn't currently exist - since we are\n\t\t\t\t\t// trying to set the value - create it\n\t\t\t\t\tif ( data[ a[i] ] === null || data[ a[i] ] === undefined )\n\t\t\t\t\t{\n\t\t\t\t\t\tdata[ a[i] ] = {};\n\t\t\t\t\t}\n\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t}\n\t\n\t\t\t\t// Last item in the input - i.e, the actual set\n\t\t\t\tif ( aLast.match(__reFn ) )\n\t\t\t\t{\n\t\t\t\t\t// Function call\n\t\t\t\t\tdata = data[ aLast.replace(__reFn, '') ]( val );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// If array notation is used, we just want to strip it and use the property name\n\t\t\t\t\t// and assign the value. If it isn't used, then we get the result we want anyway\n\t\t\t\t\tdata[ aLast.replace(__reArray, '') ] = val;\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\treturn setData( data, val, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\tdata[mSource] = val;\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return an array with the full table data\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns array {array} aData Master data array\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetDataMaster ( settings )\n\t{\n\t\treturn _pluck( settings.aoData, '_aData' );\n\t}\n\t\n\t\n\t/**\n\t * Nuke the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnClearTable( settings )\n\t{\n\t\tsettings.aoData.length = 0;\n\t\tsettings.aiDisplayMaster.length = 0;\n\t\tsettings.aiDisplay.length = 0;\n\t\tsettings.aIds = {};\n\t}\n\t\n\t\n\t /**\n\t * Take an array of integers (index array) and remove a target integer (value - not\n\t * the key!)\n\t *  @param {array} a Index array to target\n\t *  @param {int} iTarget value to find\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDeleteIndex( a, iTarget, splice )\n\t{\n\t\tvar iTargetIndex = -1;\n\t\n\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( a[i] == iTarget )\n\t\t\t{\n\t\t\t\tiTargetIndex = i;\n\t\t\t}\n\t\t\telse if ( a[i] > iTarget )\n\t\t\t{\n\t\t\t\ta[i]--;\n\t\t\t}\n\t\t}\n\t\n\t\tif ( iTargetIndex != -1 && splice === undefined )\n\t\t{\n\t\t\ta.splice( iTargetIndex, 1 );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Mark cached data as invalid such that a re-read of the data will occur when\n\t * the cached data is next requested. Also update from the data source object.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {int}    rowIdx   Row index to invalidate\n\t * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'\n\t *     or 'data'\n\t * @param {int}    [colIdx] Column index to invalidate. If undefined the whole\n\t *     row will be invalidated\n\t * @memberof DataTable#oApi\n\t *\n\t * @todo For the modularisation of v1.11 this will need to become a callback, so\n\t *   the sort and filter methods can subscribe to it. That will required\n\t *   initialisation options for sorting, which is why it is not already baked in\n\t */\n\tfunction _fnInvalidate( settings, rowIdx, src, colIdx )\n\t{\n\t\tvar row = settings.aoData[ rowIdx ];\n\t\tvar i, ien;\n\t\tvar cellWrite = function ( cell, col ) {\n\t\t\t// This is very frustrating, but in IE if you just write directly\n\t\t\t// to innerHTML, and elements that are overwritten are GC'ed,\n\t\t\t// even if there is a reference to them elsewhere\n\t\t\twhile ( cell.childNodes.length ) {\n\t\t\t\tcell.removeChild( cell.firstChild );\n\t\t\t}\n\t\n\t\t\tcell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );\n\t\t};\n\t\n\t\t// Are we reading last data from DOM or the data object?\n\t\tif ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {\n\t\t\t// Read the data from the DOM\n\t\t\trow._aData = _fnGetRowElements(\n\t\t\t\t\tsettings, row, colIdx, colIdx === undefined ? undefined : row._aData\n\t\t\t\t)\n\t\t\t\t.data;\n\t\t}\n\t\telse {\n\t\t\t// Reading from data object, update the DOM\n\t\t\tvar cells = row.anCells;\n\t\n\t\t\tif ( cells ) {\n\t\t\t\tif ( colIdx !== undefined ) {\n\t\t\t\t\tcellWrite( cells[colIdx], colIdx );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tcellWrite( cells[i], i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// For both row and cell invalidation, the cached data for sorting and\n\t\t// filtering is nulled out\n\t\trow._aSortData = null;\n\t\trow._aFilterData = null;\n\t\n\t\t// Invalidate the type for a specific column (if given) or all columns since\n\t\t// the data might have changed\n\t\tvar cols = settings.aoColumns;\n\t\tif ( colIdx !== undefined ) {\n\t\t\tcols[ colIdx ].sType = null;\n\t\t}\n\t\telse {\n\t\t\tfor ( i=0, ien=cols.length ; i<ien ; i++ ) {\n\t\t\t\tcols[i].sType = null;\n\t\t\t}\n\t\n\t\t\t// Update DataTables special `DT_*` attributes for the row\n\t\t\t_fnRowAttributes( settings, row );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a data source object from an HTML row, reading the contents of the\n\t * cells that are in the row.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {node|object} TR element from which to read data or existing row\n\t *   object from which to re-read the data from the cells\n\t * @param {int} [colIdx] Optional column index\n\t * @param {array|object} [d] Data source object. If `colIdx` is given then this\n\t *   parameter should also be given and will be used to write the data into.\n\t *   Only the column in question will be written\n\t * @returns {object} Object with two parameters: `data` the data read, in\n\t *   document order, and `cells` and array of nodes (they can be useful to the\n\t *   caller, so rather than needing a second traversal to get them, just return\n\t *   them from here).\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetRowElements( settings, row, colIdx, d )\n\t{\n\t\tvar\n\t\t\ttds = [],\n\t\t\ttd = row.firstChild,\n\t\t\tname, col, o, i=0, contents,\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tobjectRead = settings._rowReadObject;\n\t\n\t\t// Allow the data object to be passed in, or construct\n\t\td = d !== undefined ?\n\t\t\td :\n\t\t\tobjectRead ?\n\t\t\t\t{} :\n\t\t\t\t[];\n\t\n\t\tvar attr = function ( str, td  ) {\n\t\t\tif ( typeof str === 'string' ) {\n\t\t\t\tvar idx = str.indexOf('@');\n\t\n\t\t\t\tif ( idx !== -1 ) {\n\t\t\t\t\tvar attr = str.substring( idx+1 );\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( str );\n\t\t\t\t\tsetter( d, td.getAttribute( attr ) );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\n\t\t// Read data from a cell and store into the data object\n\t\tvar cellProcess = function ( cell ) {\n\t\t\tif ( colIdx === undefined || colIdx === i ) {\n\t\t\t\tcol = columns[i];\n\t\t\t\tcontents = $.trim(cell.innerHTML);\n\t\n\t\t\t\tif ( col && col._bAttrSrc ) {\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( col.mData._ );\n\t\t\t\t\tsetter( d, contents );\n\t\n\t\t\t\t\tattr( col.mData.sort, cell );\n\t\t\t\t\tattr( col.mData.type, cell );\n\t\t\t\t\tattr( col.mData.filter, cell );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Depending on the `data` option for the columns the data can\n\t\t\t\t\t// be read to either an object or an array.\n\t\t\t\t\tif ( objectRead ) {\n\t\t\t\t\t\tif ( ! col._setter ) {\n\t\t\t\t\t\t\t// Cache the setter function\n\t\t\t\t\t\t\tcol._setter = _fnSetObjectDataFn( col.mData );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcol._setter( d, contents );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\td[i] = contents;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t};\n\t\n\t\tif ( td ) {\n\t\t\t// `tr` element was passed in\n\t\t\twhile ( td ) {\n\t\t\t\tname = td.nodeName.toUpperCase();\n\t\n\t\t\t\tif ( name == \"TD\" || name == \"TH\" ) {\n\t\t\t\t\tcellProcess( td );\n\t\t\t\t\ttds.push( td );\n\t\t\t\t}\n\t\n\t\t\t\ttd = td.nextSibling;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Existing row object passed in\n\t\t\ttds = row.anCells;\n\t\n\t\t\tfor ( var j=0, jen=tds.length ; j<jen ; j++ ) {\n\t\t\t\tcellProcess( tds[j] );\n\t\t\t}\n\t\t}\n\t\n\t\t// Read the ID from the DOM if present\n\t\tvar rowNode = row.firstChild ? row : row.nTr;\n\t\n\t\tif ( rowNode ) {\n\t\t\tvar id = rowNode.getAttribute( 'id' );\n\t\n\t\t\tif ( id ) {\n\t\t\t\t_fnSetObjectDataFn( settings.rowId )( d, id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn {\n\t\t\tdata: d,\n\t\t\tcells: tds\n\t\t};\n\t}\n\t/**\n\t * Create a new TR element (and it's TD children) for a row\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow Row to consider\n\t *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCreateTr ( oSettings, iRow, nTrIn, anTds )\n\t{\n\t\tvar\n\t\t\trow = oSettings.aoData[iRow],\n\t\t\trowData = row._aData,\n\t\t\tcells = [],\n\t\t\tnTr, nTd, oCol,\n\t\t\ti, iLen;\n\t\n\t\tif ( row.nTr === null )\n\t\t{\n\t\t\tnTr = nTrIn || document.createElement('tr');\n\t\n\t\t\trow.nTr = nTr;\n\t\t\trow.anCells = cells;\n\t\n\t\t\t/* Use a private property on the node to allow reserve mapping from the node\n\t\t\t * to the aoData array for fast look up\n\t\t\t */\n\t\t\tnTr._DT_RowIndex = iRow;\n\t\n\t\t\t/* Special parameters can be given by the data source to be used on the row */\n\t\t\t_fnRowAttributes( oSettings, row );\n\t\n\t\t\t/* Process each column */\n\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toCol = oSettings.aoColumns[i];\n\t\n\t\t\t\tnTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );\n\t\t\t\tnTd._DT_CellIndex = {\n\t\t\t\t\trow: iRow,\n\t\t\t\t\tcolumn: i\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tcells.push( nTd );\n\t\n\t\t\t\t// Need to create the HTML if new, or if a rendering function is defined\n\t\t\t\tif ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&\n\t\t\t\t\t (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')\n\t\t\t\t) {\n\t\t\t\t\tnTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );\n\t\t\t\t}\n\t\n\t\t\t\t/* Add user defined class */\n\t\t\t\tif ( oCol.sClass )\n\t\t\t\t{\n\t\t\t\t\tnTd.className += ' '+oCol.sClass;\n\t\t\t\t}\n\t\n\t\t\t\t// Visibility - add or remove as required\n\t\t\t\tif ( oCol.bVisible && ! nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTr.appendChild( nTd );\n\t\t\t\t}\n\t\t\t\telse if ( ! oCol.bVisible && nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTd.parentNode.removeChild( nTd );\n\t\t\t\t}\n\t\n\t\t\t\tif ( oCol.fnCreatedCell )\n\t\t\t\t{\n\t\t\t\t\toCol.fnCreatedCell.call( oSettings.oInstance,\n\t\t\t\t\t\tnTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] );\n\t\t}\n\t\n\t\t// Remove once webkit bug 131819 and Chromium bug 365619 have been resolved\n\t\t// and deployed\n\t\trow.nTr.setAttribute( 'role', 'row' );\n\t}\n\t\n\t\n\t/**\n\t * Add attributes to a row based on the special `DT_*` parameters in a data\n\t * source object.\n\t *  @param {object} settings DataTables settings object\n\t *  @param {object} DataTables row object for the row to be modified\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnRowAttributes( settings, row )\n\t{\n\t\tvar tr = row.nTr;\n\t\tvar data = row._aData;\n\t\n\t\tif ( tr ) {\n\t\t\tvar id = settings.rowIdFn( data );\n\t\n\t\t\tif ( id ) {\n\t\t\t\ttr.id = id;\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowClass ) {\n\t\t\t\t// Remove any classes added by DT_RowClass before\n\t\t\t\tvar a = data.DT_RowClass.split(' ');\n\t\t\t\trow.__rowc = row.__rowc ?\n\t\t\t\t\t_unique( row.__rowc.concat( a ) ) :\n\t\t\t\t\ta;\n\t\n\t\t\t\t$(tr)\n\t\t\t\t\t.removeClass( row.__rowc.join(' ') )\n\t\t\t\t\t.addClass( data.DT_RowClass );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowAttr ) {\n\t\t\t\t$(tr).attr( data.DT_RowAttr );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowData ) {\n\t\t\t\t$(tr).data( data.DT_RowData );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Create the HTML header for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBuildHead( oSettings )\n\t{\n\t\tvar i, ien, cell, row, column;\n\t\tvar thead = oSettings.nTHead;\n\t\tvar tfoot = oSettings.nTFoot;\n\t\tvar createHeader = $('th, td', thead).length === 0;\n\t\tvar classes = oSettings.oClasses;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\tif ( createHeader ) {\n\t\t\trow = $('<tr/>').appendTo( thead );\n\t\t}\n\t\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcell = $( column.nTh ).addClass( column.sClass );\n\t\n\t\t\tif ( createHeader ) {\n\t\t\t\tcell.appendTo( row );\n\t\t\t}\n\t\n\t\t\t// 1.11 move into sorting\n\t\t\tif ( oSettings.oFeatures.bSort ) {\n\t\t\t\tcell.addClass( column.sSortingClass );\n\t\n\t\t\t\tif ( column.bSortable !== false ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.attr( 'tabindex', oSettings.iTabIndex )\n\t\t\t\t\t\t.attr( 'aria-controls', oSettings.sTableId );\n\t\n\t\t\t\t\t_fnSortAttachListener( oSettings, column.nTh, i );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( column.sTitle != cell[0].innerHTML ) {\n\t\t\t\tcell.html( column.sTitle );\n\t\t\t}\n\t\n\t\t\t_fnRenderer( oSettings, 'header' )(\n\t\t\t\toSettings, cell, column, classes\n\t\t\t);\n\t\t}\n\t\n\t\tif ( createHeader ) {\n\t\t\t_fnDetectHeader( oSettings.aoHeader, thead );\n\t\t}\n\t\t\n\t\t/* ARIA role for the rows */\n\t \t$(thead).find('>tr').attr('role', 'row');\n\t\n\t\t/* Deal with the footer - add classes if required */\n\t\t$(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );\n\t\t$(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );\n\t\n\t\t// Cache the footer cells. Note that we only take the cells from the first\n\t\t// row in the footer. If there is more than one row the user wants to\n\t\t// interact with, they need to use the table().foot() method. Note also this\n\t\t// allows cells to be used for multiple columns using colspan\n\t\tif ( tfoot !== null ) {\n\t\t\tvar cells = oSettings.aoFooter[0];\n\t\n\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tcolumn = columns[i];\n\t\t\t\tcolumn.nTf = cells[i].cell;\n\t\n\t\t\t\tif ( column.sClass ) {\n\t\t\t\t\t$(column.nTf).addClass( column.sClass );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the header (or footer) element based on the column visibility states. The\n\t * methodology here is to use the layout array from _fnDetectHeader, modified for\n\t * the instantaneous column visibility, to construct the new layout. The grid is\n\t * traversed over cell at a time in a rows x columns grid fashion, although each\n\t * cell insert can cover multiple elements in the grid - which is tracks using the\n\t * aApplied array. Cell inserts in the grid will only occur where there isn't\n\t * already a cell in that position.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param array {objects} aoSource Layout array from _fnDetectHeader\n\t *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDrawHead( oSettings, aoSource, bIncludeHidden )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, n, nLocalTr;\n\t\tvar aoLocal = [];\n\t\tvar aApplied = [];\n\t\tvar iColumns = oSettings.aoColumns.length;\n\t\tvar iRowspan, iColspan;\n\t\n\t\tif ( ! aoSource )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif (  bIncludeHidden === undefined )\n\t\t{\n\t\t\tbIncludeHidden = false;\n\t\t}\n\t\n\t\t/* Make a copy of the master layout array, but without the visible columns in it */\n\t\tfor ( i=0, iLen=aoSource.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taoLocal[i] = aoSource[i].slice();\n\t\t\taoLocal[i].nTr = aoSource[i].nTr;\n\t\n\t\t\t/* Remove any columns which are currently hidden */\n\t\t\tfor ( j=iColumns-1 ; j>=0 ; j-- )\n\t\t\t{\n\t\t\t\tif ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )\n\t\t\t\t{\n\t\t\t\t\taoLocal[i].splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Prep the applied array - it needs an element for each row */\n\t\t\taApplied.push( [] );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnLocalTr = aoLocal[i].nTr;\n\t\n\t\t\t/* All cells are going to be replaced, so empty out the row */\n\t\t\tif ( nLocalTr )\n\t\t\t{\n\t\t\t\twhile( (n = nLocalTr.firstChild) )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.removeChild( n );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tfor ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tiRowspan = 1;\n\t\t\t\tiColspan = 1;\n\t\n\t\t\t\t/* Check to see if there is already a cell (row/colspan) covering our target\n\t\t\t\t * insert point. If there is, then there is nothing to do.\n\t\t\t\t */\n\t\t\t\tif ( aApplied[i][j] === undefined )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.appendChild( aoLocal[i][j].cell );\n\t\t\t\t\taApplied[i][j] = 1;\n\t\n\t\t\t\t\t/* Expand the cell to cover as many rows as needed */\n\t\t\t\t\twhile ( aoLocal[i+iRowspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\taApplied[i+iRowspan][j] = 1;\n\t\t\t\t\t\tiRowspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Expand the cell to cover as many columns as needed */\n\t\t\t\t\twhile ( aoLocal[i][j+iColspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Must update the applied array over the rows for the columns */\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taApplied[i+k][j+iColspan] = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiColspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Do the actual expansion in the DOM */\n\t\t\t\t\t$(aoLocal[i][j].cell)\n\t\t\t\t\t\t.attr('rowspan', iRowspan)\n\t\t\t\t\t\t.attr('colspan', iColspan);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Insert the required TR nodes into the table for display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDraw( oSettings )\n\t{\n\t\t/* Provide a pre-callback function which can be used to cancel the draw is false is returned */\n\t\tvar aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );\n\t\tif ( $.inArray( false, aPreDraw ) !== -1 )\n\t\t{\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar i, iLen, n;\n\t\tvar anRows = [];\n\t\tvar iRowCount = 0;\n\t\tvar asStripeClasses = oSettings.asStripeClasses;\n\t\tvar iStripes = asStripeClasses.length;\n\t\tvar iOpenRows = oSettings.aoOpenRows.length;\n\t\tvar oLang = oSettings.oLanguage;\n\t\tvar iInitDisplayStart = oSettings.iInitDisplayStart;\n\t\tvar bServerSide = _fnDataSource( oSettings ) == 'ssp';\n\t\tvar aiDisplay = oSettings.aiDisplay;\n\t\n\t\toSettings.bDrawing = true;\n\t\n\t\t/* Check and see if we have an initial draw position from state saving */\n\t\tif ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )\n\t\t{\n\t\t\toSettings._iDisplayStart = bServerSide ?\n\t\t\t\tiInitDisplayStart :\n\t\t\t\tiInitDisplayStart >= oSettings.fnRecordsDisplay() ?\n\t\t\t\t\t0 :\n\t\t\t\t\tiInitDisplayStart;\n\t\n\t\t\toSettings.iInitDisplayStart = -1;\n\t\t}\n\t\n\t\tvar iDisplayStart = oSettings._iDisplayStart;\n\t\tvar iDisplayEnd = oSettings.fnDisplayEnd();\n\t\n\t\t/* Server-side processing draw intercept */\n\t\tif ( oSettings.bDeferLoading )\n\t\t{\n\t\t\toSettings.bDeferLoading = false;\n\t\t\toSettings.iDraw++;\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t}\n\t\telse if ( !bServerSide )\n\t\t{\n\t\t\toSettings.iDraw++;\n\t\t}\n\t\telse if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( aiDisplay.length !== 0 )\n\t\t{\n\t\t\tvar iStart = bServerSide ? 0 : iDisplayStart;\n\t\t\tvar iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;\n\t\n\t\t\tfor ( var j=iStart ; j<iEnd ; j++ )\n\t\t\t{\n\t\t\t\tvar iDataIndex = aiDisplay[j];\n\t\t\t\tvar aoData = oSettings.aoData[ iDataIndex ];\n\t\t\t\tif ( aoData.nTr === null )\n\t\t\t\t{\n\t\t\t\t\t_fnCreateTr( oSettings, iDataIndex );\n\t\t\t\t}\n\t\n\t\t\t\tvar nRow = aoData.nTr;\n\t\n\t\t\t\t/* Remove the old striping classes and then add the new one */\n\t\t\t\tif ( iStripes !== 0 )\n\t\t\t\t{\n\t\t\t\t\tvar sStripe = asStripeClasses[ iRowCount % iStripes ];\n\t\t\t\t\tif ( aoData._sRowStripe != sStripe )\n\t\t\t\t\t{\n\t\t\t\t\t\t$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );\n\t\t\t\t\t\taoData._sRowStripe = sStripe;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Row callback functions - might want to manipulate the row\n\t\t\t\t// iRowCount and j are not currently documented. Are they at all\n\t\t\t\t// useful?\n\t\t\t\t_fnCallbackFire( oSettings, 'aoRowCallback', null,\n\t\t\t\t\t[nRow, aoData._aData, iRowCount, j, iDataIndex] );\n\t\n\t\t\t\tanRows.push( nRow );\n\t\t\t\tiRowCount++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Table is empty - create a row with an empty message in it */\n\t\t\tvar sZero = oLang.sZeroRecords;\n\t\t\tif ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )\n\t\t\t{\n\t\t\t\tsZero = oLang.sLoadingRecords;\n\t\t\t}\n\t\t\telse if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )\n\t\t\t{\n\t\t\t\tsZero = oLang.sEmptyTable;\n\t\t\t}\n\t\n\t\t\tanRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )\n\t\t\t\t.append( $('<td />', {\n\t\t\t\t\t'valign':  'top',\n\t\t\t\t\t'colSpan': _fnVisbleColumns( oSettings ),\n\t\t\t\t\t'class':   oSettings.oClasses.sRowEmpty\n\t\t\t\t} ).html( sZero ) )[0];\n\t\t}\n\t\n\t\t/* Header and footer callbacks */\n\t\t_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\t_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\tvar body = $(oSettings.nTBody);\n\t\n\t\tbody.children().detach();\n\t\tbody.append( $(anRows) );\n\t\n\t\t/* Call all required callback functions for the end of a draw */\n\t\t_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );\n\t\n\t\t/* Draw is complete, sorting and filtering must be as well */\n\t\toSettings.bSorted = false;\n\t\toSettings.bFiltered = false;\n\t\toSettings.bDrawing = false;\n\t}\n\t\n\t\n\t/**\n\t * Redraw the table - taking account of the various features which are enabled\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {boolean} [holdPosition] Keep the current paging position. By default\n\t *    the paging is reset to the first page\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReDraw( settings, holdPosition )\n\t{\n\t\tvar\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tsort     = features.bSort,\n\t\t\tfilter   = features.bFilter;\n\t\n\t\tif ( sort ) {\n\t\t\t_fnSort( settings );\n\t\t}\n\t\n\t\tif ( filter ) {\n\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch );\n\t\t}\n\t\telse {\n\t\t\t// No filtering, so we want to just use the display master\n\t\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\t}\n\t\n\t\tif ( holdPosition !== true ) {\n\t\t\tsettings._iDisplayStart = 0;\n\t\t}\n\t\n\t\t// Let any modules know about the draw hold position state (used by\n\t\t// scrolling internally)\n\t\tsettings._drawHold = holdPosition;\n\t\n\t\t_fnDraw( settings );\n\t\n\t\tsettings._drawHold = false;\n\t}\n\t\n\t\n\t/**\n\t * Add the options to the page HTML for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddOptionsHtml ( oSettings )\n\t{\n\t\tvar classes = oSettings.oClasses;\n\t\tvar table = $(oSettings.nTable);\n\t\tvar holding = $('<div/>').insertBefore( table ); // Holding element for speed\n\t\tvar features = oSettings.oFeatures;\n\t\n\t\t// All DataTables are wrapped in a div\n\t\tvar insert = $('<div/>', {\n\t\t\tid:      oSettings.sTableId+'_wrapper',\n\t\t\t'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)\n\t\t} );\n\t\n\t\toSettings.nHolding = holding[0];\n\t\toSettings.nTableWrapper = insert[0];\n\t\toSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;\n\t\n\t\t/* Loop over the user set positioning and place the elements as needed */\n\t\tvar aDom = oSettings.sDom.split('');\n\t\tvar featureNode, cOption, nNewNode, cNext, sAttr, j;\n\t\tfor ( var i=0 ; i<aDom.length ; i++ )\n\t\t{\n\t\t\tfeatureNode = null;\n\t\t\tcOption = aDom[i];\n\t\n\t\t\tif ( cOption == '<' )\n\t\t\t{\n\t\t\t\t/* New container div */\n\t\t\t\tnNewNode = $('<div/>')[0];\n\t\n\t\t\t\t/* Check to see if we should append an id and/or a class name to the container */\n\t\t\t\tcNext = aDom[i+1];\n\t\t\t\tif ( cNext == \"'\" || cNext == '\"' )\n\t\t\t\t{\n\t\t\t\t\tsAttr = \"\";\n\t\t\t\t\tj = 2;\n\t\t\t\t\twhile ( aDom[i+j] != cNext )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr += aDom[i+j];\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Replace jQuery UI constants @todo depreciated */\n\t\t\t\t\tif ( sAttr == \"H\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIHeader;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr == \"F\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIFooter;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* The attribute can be in the format of \"#id.class\", \"#id\" or \"class\" This logic\n\t\t\t\t\t * breaks the string into parts and applies them as needed\n\t\t\t\t\t */\n\t\t\t\t\tif ( sAttr.indexOf('.') != -1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar aSplit = sAttr.split('.');\n\t\t\t\t\t\tnNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);\n\t\t\t\t\t\tnNewNode.className = aSplit[1];\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr.charAt(0) == \"#\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.id = sAttr.substr(1, sAttr.length-1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.className = sAttr;\n\t\t\t\t\t}\n\t\n\t\t\t\t\ti += j; /* Move along the position array */\n\t\t\t\t}\n\t\n\t\t\t\tinsert.append( nNewNode );\n\t\t\t\tinsert = $(nNewNode);\n\t\t\t}\n\t\t\telse if ( cOption == '>' )\n\t\t\t{\n\t\t\t\t/* End container div */\n\t\t\t\tinsert = insert.parent();\n\t\t\t}\n\t\t\t// @todo Move options into their own plugins?\n\t\t\telse if ( cOption == 'l' && features.bPaginate && features.bLengthChange )\n\t\t\t{\n\t\t\t\t/* Length */\n\t\t\t\tfeatureNode = _fnFeatureHtmlLength( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'f' && features.bFilter )\n\t\t\t{\n\t\t\t\t/* Filter */\n\t\t\t\tfeatureNode = _fnFeatureHtmlFilter( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'r' && features.bProcessing )\n\t\t\t{\n\t\t\t\t/* pRocessing */\n\t\t\t\tfeatureNode = _fnFeatureHtmlProcessing( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 't' )\n\t\t\t{\n\t\t\t\t/* Table */\n\t\t\t\tfeatureNode = _fnFeatureHtmlTable( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption ==  'i' && features.bInfo )\n\t\t\t{\n\t\t\t\t/* Info */\n\t\t\t\tfeatureNode = _fnFeatureHtmlInfo( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'p' && features.bPaginate )\n\t\t\t{\n\t\t\t\t/* Pagination */\n\t\t\t\tfeatureNode = _fnFeatureHtmlPaginate( oSettings );\n\t\t\t}\n\t\t\telse if ( DataTable.ext.feature.length !== 0 )\n\t\t\t{\n\t\t\t\t/* Plug-in features */\n\t\t\t\tvar aoFeatures = DataTable.ext.feature;\n\t\t\t\tfor ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )\n\t\t\t\t{\n\t\t\t\t\tif ( cOption == aoFeatures[k].cFeature )\n\t\t\t\t\t{\n\t\t\t\t\t\tfeatureNode = aoFeatures[k].fnInit( oSettings );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Add to the 2D features array */\n\t\t\tif ( featureNode )\n\t\t\t{\n\t\t\t\tvar aanFeatures = oSettings.aanFeatures;\n\t\n\t\t\t\tif ( ! aanFeatures[cOption] )\n\t\t\t\t{\n\t\t\t\t\taanFeatures[cOption] = [];\n\t\t\t\t}\n\t\n\t\t\t\taanFeatures[cOption].push( featureNode );\n\t\t\t\tinsert.append( featureNode );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Built our DOM structure - replace the holding div with what we want */\n\t\tholding.replaceWith( insert );\n\t\toSettings.nHolding = null;\n\t}\n\t\n\t\n\t/**\n\t * Use the DOM source to create up an array of header cells. The idea here is to\n\t * create a layout grid (array) of rows x columns, which contains a reference\n\t * to the cell that that point in the grid (regardless of col/rowspan), such that\n\t * any column / row could be removed and the new grid constructed\n\t *  @param array {object} aLayout Array to store the calculated layout in\n\t *  @param {node} nThead The header/footer element for the table\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDetectHeader ( aLayout, nThead )\n\t{\n\t\tvar nTrs = $(nThead).children('tr');\n\t\tvar nTr, nCell;\n\t\tvar i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;\n\t\tvar bUnique;\n\t\tvar fnShiftCol = function ( a, i, j ) {\n\t\t\tvar k = a[i];\n\t                while ( k[j] ) {\n\t\t\t\tj++;\n\t\t\t}\n\t\t\treturn j;\n\t\t};\n\t\n\t\taLayout.splice( 0, aLayout.length );\n\t\n\t\t/* We know how many rows there are in the layout - so prep it */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taLayout.push( [] );\n\t\t}\n\t\n\t\t/* Calculate a layout array */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnTr = nTrs[i];\n\t\t\tiColumn = 0;\n\t\n\t\t\t/* For every cell in the row... */\n\t\t\tnCell = nTr.firstChild;\n\t\t\twhile ( nCell ) {\n\t\t\t\tif ( nCell.nodeName.toUpperCase() == \"TD\" ||\n\t\t\t\t     nCell.nodeName.toUpperCase() == \"TH\" )\n\t\t\t\t{\n\t\t\t\t\t/* Get the col and rowspan attributes from the DOM and sanitise them */\n\t\t\t\t\tiColspan = nCell.getAttribute('colspan') * 1;\n\t\t\t\t\tiRowspan = nCell.getAttribute('rowspan') * 1;\n\t\t\t\t\tiColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;\n\t\t\t\t\tiRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;\n\t\n\t\t\t\t\t/* There might be colspan cells already in this row, so shift our target\n\t\t\t\t\t * accordingly\n\t\t\t\t\t */\n\t\t\t\t\tiColShifted = fnShiftCol( aLayout, i, iColumn );\n\t\n\t\t\t\t\t/* Cache calculation for unique columns */\n\t\t\t\t\tbUnique = iColspan === 1 ? true : false;\n\t\n\t\t\t\t\t/* If there is col / rowspan, copy the information into the layout grid */\n\t\t\t\t\tfor ( l=0 ; l<iColspan ; l++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taLayout[i+k][iColShifted+l] = {\n\t\t\t\t\t\t\t\t\"cell\": nCell,\n\t\t\t\t\t\t\t\t\"unique\": bUnique\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\taLayout[i+k].nTr = nTr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnCell = nCell.nextSibling;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Get an array of unique th elements, one for each column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nHeader automatically detect the layout from this node - optional\n\t *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional\n\t *  @returns array {node} aReturn list of unique th's\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetUniqueThs ( oSettings, nHeader, aLayout )\n\t{\n\t\tvar aReturn = [];\n\t\tif ( !aLayout )\n\t\t{\n\t\t\taLayout = oSettings.aoHeader;\n\t\t\tif ( nHeader )\n\t\t\t{\n\t\t\t\taLayout = [];\n\t\t\t\t_fnDetectHeader( aLayout, nHeader );\n\t\t\t}\n\t\t}\n\t\n\t\tfor ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfor ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tif ( aLayout[i][j].unique &&\n\t\t\t\t\t (!aReturn[j] || !oSettings.bSortCellsTop) )\n\t\t\t\t{\n\t\t\t\t\taReturn[j] = aLayout[i][j].cell;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn aReturn;\n\t}\n\t\n\t/**\n\t * Create an Ajax call based on the table's settings, taking into account that\n\t * parameters can have multiple forms, and backwards compatibility.\n\t *\n\t * @param {object} oSettings dataTables settings object\n\t * @param {array} data Data to send to the server, required by\n\t *     DataTables - may be augmented by developer callbacks\n\t * @param {function} fn Callback function to run when data is obtained\n\t */\n\tfunction _fnBuildAjax( oSettings, data, fn )\n\t{\n\t\t// Compatibility with 1.9-, allow fnServerData and event to manipulate\n\t\t_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );\n\t\n\t\t// Convert to object based for 1.10+ if using the old array scheme which can\n\t\t// come from server-side processing or serverParams\n\t\tif ( data && $.isArray(data) ) {\n\t\t\tvar tmp = {};\n\t\t\tvar rbracket = /(.*?)\\[\\]$/;\n\t\n\t\t\t$.each( data, function (key, val) {\n\t\t\t\tvar match = val.name.match(rbracket);\n\t\n\t\t\t\tif ( match ) {\n\t\t\t\t\t// Support for arrays\n\t\t\t\t\tvar name = match[0];\n\t\n\t\t\t\t\tif ( ! tmp[ name ] ) {\n\t\t\t\t\t\ttmp[ name ] = [];\n\t\t\t\t\t}\n\t\t\t\t\ttmp[ name ].push( val.value );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttmp[val.name] = val.value;\n\t\t\t\t}\n\t\t\t} );\n\t\t\tdata = tmp;\n\t\t}\n\t\n\t\tvar ajaxData;\n\t\tvar ajax = oSettings.ajax;\n\t\tvar instance = oSettings.oInstance;\n\t\tvar callback = function ( json ) {\n\t\t\t_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );\n\t\t\tfn( json );\n\t\t};\n\t\n\t\tif ( $.isPlainObject( ajax ) && ajax.data )\n\t\t{\n\t\t\tajaxData = ajax.data;\n\t\n\t\t\tvar newData = typeof ajaxData === 'function' ?\n\t\t\t\tajaxData( data, oSettings ) :  // fn can manipulate data or return\n\t\t\t\tajaxData;                      // an object object or array to merge\n\t\n\t\t\t// If the function returned something, use that alone\n\t\t\tdata = typeof ajaxData === 'function' && newData ?\n\t\t\t\tnewData :\n\t\t\t\t$.extend( true, data, newData );\n\t\n\t\t\t// Remove the data property as we've resolved it already and don't want\n\t\t\t// jQuery to do it again (it is restored at the end of the function)\n\t\t\tdelete ajax.data;\n\t\t}\n\t\n\t\tvar baseAjax = {\n\t\t\t\"data\": data,\n\t\t\t\"success\": function (json) {\n\t\t\t\tvar error = json.error || json.sError;\n\t\t\t\tif ( error ) {\n\t\t\t\t\t_fnLog( oSettings, 0, error );\n\t\t\t\t}\n\t\n\t\t\t\toSettings.json = json;\n\t\t\t\tcallback( json );\n\t\t\t},\n\t\t\t\"dataType\": \"json\",\n\t\t\t\"cache\": false,\n\t\t\t\"type\": oSettings.sServerMethod,\n\t\t\t\"error\": function (xhr, error, thrown) {\n\t\t\t\tvar ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );\n\t\n\t\t\t\tif ( $.inArray( true, ret ) === -1 ) {\n\t\t\t\t\tif ( error == \"parsererror\" ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Invalid JSON response', 1 );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( xhr.readyState === 4 ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Ajax error', 7 );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\t}\n\t\t};\n\t\n\t\t// Store the data submitted for the API\n\t\toSettings.oAjaxData = data;\n\t\n\t\t// Allow plug-ins and external processes to modify the data\n\t\t_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );\n\t\n\t\tif ( oSettings.fnServerData )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.fnServerData.call( instance,\n\t\t\t\toSettings.sAjaxSource,\n\t\t\t\t$.map( data, function (val, key) { // Need to convert back to 1.9 trad format\n\t\t\t\t\treturn { name: key, value: val };\n\t\t\t\t} ),\n\t\t\t\tcallback,\n\t\t\t\toSettings\n\t\t\t);\n\t\t}\n\t\telse if ( oSettings.sAjaxSource || typeof ajax === 'string' )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, {\n\t\t\t\turl: ajax || oSettings.sAjaxSource\n\t\t\t} ) );\n\t\t}\n\t\telse if ( typeof ajax === 'function' )\n\t\t{\n\t\t\t// Is a function - let the caller define what needs to be done\n\t\t\toSettings.jqXHR = ajax.call( instance, data, callback, oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Object to extend the base settings\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );\n\t\n\t\t\t// Restore for next time around\n\t\t\tajax.data = ajaxData;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Update the table using an Ajax call\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {boolean} Block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdate( settings )\n\t{\n\t\tif ( settings.bAjaxDataGet ) {\n\t\t\tsettings.iDraw++;\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t_fnBuildAjax(\n\t\t\t\tsettings,\n\t\t\t\t_fnAjaxParameters( settings ),\n\t\t\t\tfunction(json) {\n\t\t\t\t\t_fnAjaxUpdateDraw( settings, json );\n\t\t\t\t}\n\t\t\t);\n\t\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\t\n\t/**\n\t * Build up the parameters in an object needed for a server-side processing\n\t * request. Note that this is basically done twice, is different ways - a modern\n\t * method which is used by default in DataTables 1.10 which uses objects and\n\t * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if\n\t * the sAjaxSource option is used in the initialisation, or the legacyAjax\n\t * option is set.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {bool} block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxParameters( settings )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tcolumnCount = columns.length,\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tpreSearch = settings.oPreviousSearch,\n\t\t\tpreColSearch = settings.aoPreSearchCols,\n\t\t\ti, data = [], dataProp, column, columnSearch,\n\t\t\tsort = _fnSortFlatten( settings ),\n\t\t\tdisplayStart = settings._iDisplayStart,\n\t\t\tdisplayLength = features.bPaginate !== false ?\n\t\t\t\tsettings._iDisplayLength :\n\t\t\t\t-1;\n\t\n\t\tvar param = function ( name, value ) {\n\t\t\tdata.push( { 'name': name, 'value': value } );\n\t\t};\n\t\n\t\t// DataTables 1.9- compatible method\n\t\tparam( 'sEcho',          settings.iDraw );\n\t\tparam( 'iColumns',       columnCount );\n\t\tparam( 'sColumns',       _pluck( columns, 'sName' ).join(',') );\n\t\tparam( 'iDisplayStart',  displayStart );\n\t\tparam( 'iDisplayLength', displayLength );\n\t\n\t\t// DataTables 1.10+ method\n\t\tvar d = {\n\t\t\tdraw:    settings.iDraw,\n\t\t\tcolumns: [],\n\t\t\torder:   [],\n\t\t\tstart:   displayStart,\n\t\t\tlength:  displayLength,\n\t\t\tsearch:  {\n\t\t\t\tvalue: preSearch.sSearch,\n\t\t\t\tregex: preSearch.bRegex\n\t\t\t}\n\t\t};\n\t\n\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcolumnSearch = preColSearch[i];\n\t\t\tdataProp = typeof column.mData==\"function\" ? 'function' : column.mData ;\n\t\n\t\t\td.columns.push( {\n\t\t\t\tdata:       dataProp,\n\t\t\t\tname:       column.sName,\n\t\t\t\tsearchable: column.bSearchable,\n\t\t\t\torderable:  column.bSortable,\n\t\t\t\tsearch:     {\n\t\t\t\t\tvalue: columnSearch.sSearch,\n\t\t\t\t\tregex: columnSearch.bRegex\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\tparam( \"mDataProp_\"+i, dataProp );\n\t\n\t\t\tif ( features.bFilter ) {\n\t\t\t\tparam( 'sSearch_'+i,     columnSearch.sSearch );\n\t\t\t\tparam( 'bRegex_'+i,      columnSearch.bRegex );\n\t\t\t\tparam( 'bSearchable_'+i, column.bSearchable );\n\t\t\t}\n\t\n\t\t\tif ( features.bSort ) {\n\t\t\t\tparam( 'bSortable_'+i, column.bSortable );\n\t\t\t}\n\t\t}\n\t\n\t\tif ( features.bFilter ) {\n\t\t\tparam( 'sSearch', preSearch.sSearch );\n\t\t\tparam( 'bRegex', preSearch.bRegex );\n\t\t}\n\t\n\t\tif ( features.bSort ) {\n\t\t\t$.each( sort, function ( i, val ) {\n\t\t\t\td.order.push( { column: val.col, dir: val.dir } );\n\t\n\t\t\t\tparam( 'iSortCol_'+i, val.col );\n\t\t\t\tparam( 'sSortDir_'+i, val.dir );\n\t\t\t} );\n\t\n\t\t\tparam( 'iSortingCols', sort.length );\n\t\t}\n\t\n\t\t// If the legacy.ajax parameter is null, then we automatically decide which\n\t\t// form to use, based on sAjaxSource\n\t\tvar legacy = DataTable.ext.legacy.ajax;\n\t\tif ( legacy === null ) {\n\t\t\treturn settings.sAjaxSource ? data : d;\n\t\t}\n\t\n\t\t// Otherwise, if legacy has been specified then we use that to decide on the\n\t\t// form\n\t\treturn legacy ? data : d;\n\t}\n\t\n\t\n\t/**\n\t * Data the data from the server (nuking the old) and redraw the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} json json data return from the server.\n\t *  @param {string} json.sEcho Tracking flag for DataTables to match requests\n\t *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering\n\t *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering\n\t *  @param {array} json.aaData The data to display on this page\n\t *  @param {string} [json.sColumns] Column ordering (sName, comma separated)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdateDraw ( settings, json )\n\t{\n\t\t// v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.\n\t\t// Support both\n\t\tvar compat = function ( old, modern ) {\n\t\t\treturn json[old] !== undefined ? json[old] : json[modern];\n\t\t};\n\t\n\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\tvar draw            = compat( 'sEcho',                'draw' );\n\t\tvar recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );\n\t\tvar recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );\n\t\n\t\tif ( draw ) {\n\t\t\t// Protect against out of sequence returns\n\t\t\tif ( draw*1 < settings.iDraw ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettings.iDraw = draw * 1;\n\t\t}\n\t\n\t\t_fnClearTable( settings );\n\t\tsettings._iRecordsTotal   = parseInt(recordsTotal, 10);\n\t\tsettings._iRecordsDisplay = parseInt(recordsFiltered, 10);\n\t\n\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t_fnAddData( settings, data[i] );\n\t\t}\n\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\n\t\tsettings.bAjaxDataGet = false;\n\t\t_fnDraw( settings );\n\t\n\t\tif ( ! settings._bInitComplete ) {\n\t\t\t_fnInitComplete( settings, json );\n\t\t}\n\t\n\t\tsettings.bAjaxDataGet = true;\n\t\t_fnProcessingDisplay( settings, false );\n\t}\n\t\n\t\n\t/**\n\t * Get the data from the JSON data source to use for drawing a table. Using\n\t * `_fnGetObjectDataFn` allows the data to be sourced from a property of the\n\t * source object, or from a processing function.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param  {object} json Data source object / array from the server\n\t *  @return {array} Array of data to use\n\t */\n\tfunction _fnAjaxDataSrc ( oSettings, json )\n\t{\n\t\tvar dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?\n\t\t\toSettings.ajax.dataSrc :\n\t\t\toSettings.sAjaxDataProp; // Compatibility with 1.9-.\n\t\n\t\t// Compatibility with 1.9-. In order to read from aaData, check if the\n\t\t// default has been changed, if not, check for aaData\n\t\tif ( dataSrc === 'data' ) {\n\t\t\treturn json.aaData || json[dataSrc];\n\t\t}\n\t\n\t\treturn dataSrc !== \"\" ?\n\t\t\t_fnGetObjectDataFn( dataSrc )( json ) :\n\t\t\tjson;\n\t}\n\t\n\t/**\n\t * Generate the node required for filtering text\n\t *  @returns {node} Filter control element\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlFilter ( settings )\n\t{\n\t\tvar classes = settings.oClasses;\n\t\tvar tableId = settings.sTableId;\n\t\tvar language = settings.oLanguage;\n\t\tvar previousSearch = settings.oPreviousSearch;\n\t\tvar features = settings.aanFeatures;\n\t\tvar input = '<input type=\"search\" class=\"'+classes.sFilterInput+'\"/>';\n\t\n\t\tvar str = language.sSearch;\n\t\tstr = str.match(/_INPUT_/) ?\n\t\t\tstr.replace('_INPUT_', input) :\n\t\t\tstr+input;\n\t\n\t\tvar filter = $('<div/>', {\n\t\t\t\t'id': ! features.f ? tableId+'_filter' : null,\n\t\t\t\t'class': classes.sFilter\n\t\t\t} )\n\t\t\t.append( $('<label/>' ).append( str ) );\n\t\n\t\tvar searchFn = function() {\n\t\t\t/* Update all other filter input elements for the new display */\n\t\t\tvar n = features.f;\n\t\t\tvar val = !this.value ? \"\" : this.value; // mental IE8 fix :-(\n\t\n\t\t\t/* Now do the filter */\n\t\t\tif ( val != previousSearch.sSearch ) {\n\t\t\t\t_fnFilterComplete( settings, {\n\t\t\t\t\t\"sSearch\": val,\n\t\t\t\t\t\"bRegex\": previousSearch.bRegex,\n\t\t\t\t\t\"bSmart\": previousSearch.bSmart ,\n\t\t\t\t\t\"bCaseInsensitive\": previousSearch.bCaseInsensitive\n\t\t\t\t} );\n\t\n\t\t\t\t// Need to redraw, without resorting\n\t\t\t\tsettings._iDisplayStart = 0;\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t};\n\t\n\t\tvar searchDelay = settings.searchDelay !== null ?\n\t\t\tsettings.searchDelay :\n\t\t\t_fnDataSource( settings ) === 'ssp' ?\n\t\t\t\t400 :\n\t\t\t\t0;\n\t\n\t\tvar jqFilter = $('input', filter)\n\t\t\t.val( previousSearch.sSearch )\n\t\t\t.attr( 'placeholder', language.sSearchPlaceholder )\n\t\t\t.on(\n\t\t\t\t'keyup.DT search.DT input.DT paste.DT cut.DT',\n\t\t\t\tsearchDelay ?\n\t\t\t\t\t_fnThrottle( searchFn, searchDelay ) :\n\t\t\t\t\tsearchFn\n\t\t\t)\n\t\t\t.on( 'keypress.DT', function(e) {\n\t\t\t\t/* Prevent form submission */\n\t\t\t\tif ( e.keyCode == 13 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.attr('aria-controls', tableId);\n\t\n\t\t// Update the input elements whenever the table is filtered\n\t\t$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame...\n\t\t\t\ttry {\n\t\t\t\t\tif ( jqFilter[0] !== document.activeElement ) {\n\t\t\t\t\t\tjqFilter.val( previousSearch.sSearch );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch ( e ) {}\n\t\t\t}\n\t\t} );\n\t\n\t\treturn filter[0];\n\t}\n\t\n\t\n\t/**\n\t * Filter the table using both the global filter and column based filtering\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oSearch search information\n\t *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterComplete ( oSettings, oInput, iForce )\n\t{\n\t\tvar oPrevSearch = oSettings.oPreviousSearch;\n\t\tvar aoPrevSearch = oSettings.aoPreSearchCols;\n\t\tvar fnSaveFilter = function ( oFilter ) {\n\t\t\t/* Save the filtering values */\n\t\t\toPrevSearch.sSearch = oFilter.sSearch;\n\t\t\toPrevSearch.bRegex = oFilter.bRegex;\n\t\t\toPrevSearch.bSmart = oFilter.bSmart;\n\t\t\toPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;\n\t\t};\n\t\tvar fnRegex = function ( o ) {\n\t\t\t// Backwards compatibility with the bEscapeRegex option\n\t\t\treturn o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;\n\t\t};\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo As per sort - can this be moved into an event handler?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\t/* In server-side processing all filtering is done by the server, so no point hanging around here */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' )\n\t\t{\n\t\t\t/* Global filter */\n\t\t\t_fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );\n\t\t\tfnSaveFilter( oInput );\n\t\n\t\t\t/* Now do the individual column filter */\n\t\t\tfor ( var i=0 ; i<aoPrevSearch.length ; i++ )\n\t\t\t{\n\t\t\t\t_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),\n\t\t\t\t\taoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );\n\t\t\t}\n\t\n\t\t\t/* Custom filtering */\n\t\t\t_fnFilterCustom( oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfnSaveFilter( oInput );\n\t\t}\n\t\n\t\t/* Tell the draw function we have been filtering */\n\t\toSettings.bFiltered = true;\n\t\t_fnCallbackFire( oSettings, null, 'search', [oSettings] );\n\t}\n\t\n\t\n\t/**\n\t * Apply custom filtering functions\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCustom( settings )\n\t{\n\t\tvar filters = DataTable.ext.search;\n\t\tvar displayRows = settings.aiDisplay;\n\t\tvar row, rowIdx;\n\t\n\t\tfor ( var i=0, ien=filters.length ; i<ien ; i++ ) {\n\t\t\tvar rows = [];\n\t\n\t\t\t// Loop over each row and see if it should be included\n\t\t\tfor ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {\n\t\t\t\trowIdx = displayRows[ j ];\n\t\t\t\trow = settings.aoData[ rowIdx ];\n\t\n\t\t\t\tif ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {\n\t\t\t\t\trows.push( rowIdx );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// So the array reference doesn't break set the results into the\n\t\t\t// existing array\n\t\t\tdisplayRows.length = 0;\n\t\t\t$.merge( displayRows, rows );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Filter the table on a per-column basis\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sInput string to filter on\n\t *  @param {int} iColumn column to filter\n\t *  @param {bool} bRegex treat search string as a regular expression or not\n\t *  @param {bool} bSmart use smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )\n\t{\n\t\tif ( searchStr === '' ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar data;\n\t\tvar out = [];\n\t\tvar display = settings.aiDisplay;\n\t\tvar rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );\n\t\n\t\tfor ( var i=0 ; i<display.length ; i++ ) {\n\t\t\tdata = settings.aoData[ display[i] ]._aFilterData[ colIdx ];\n\t\n\t\t\tif ( rpSearch.test( data ) ) {\n\t\t\t\tout.push( display[i] );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aiDisplay = out;\n\t}\n\t\n\t\n\t/**\n\t * Filter the data table based on user input and draw the table\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} input string to filter on\n\t *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)\n\t *  @param {bool} regex treat as a regular expression or not\n\t *  @param {bool} smart perform smart filtering or not\n\t *  @param {bool} caseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilter( settings, input, force, regex, smart, caseInsensitive )\n\t{\n\t\tvar rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );\n\t\tvar prevSearch = settings.oPreviousSearch.sSearch;\n\t\tvar displayMaster = settings.aiDisplayMaster;\n\t\tvar display, invalidated, i;\n\t\tvar filtered = [];\n\t\n\t\t// Need to take account of custom filtering functions - always filter\n\t\tif ( DataTable.ext.search.length !== 0 ) {\n\t\t\tforce = true;\n\t\t}\n\t\n\t\t// Check if any of the rows were invalidated\n\t\tinvalidated = _fnFilterData( settings );\n\t\n\t\t// If the input is blank - we just want the full data set\n\t\tif ( input.length <= 0 ) {\n\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t}\n\t\telse {\n\t\t\t// New search - start from the master array\n\t\t\tif ( invalidated ||\n\t\t\t\t force ||\n\t\t\t\t prevSearch.length > input.length ||\n\t\t\t\t input.indexOf(prevSearch) !== 0 ||\n\t\t\t\t settings.bSorted // On resort, the display master needs to be\n\t\t\t\t                  // re-filtered since indexes will have changed\n\t\t\t) {\n\t\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t\t}\n\t\n\t\t\t// Search the display array\n\t\t\tdisplay = settings.aiDisplay;\n\t\n\t\t\tfor ( i=0 ; i<display.length ; i++ ) {\n\t\t\t\tif ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {\n\t\t\t\t\tfiltered.push( display[i] );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tsettings.aiDisplay = filtered;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a regular expression object suitable for searching a table\n\t *  @param {string} sSearch string to search for\n\t *  @param {bool} bRegex treat as a regular expression or not\n\t *  @param {bool} bSmart perform smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insensitive matching or not\n\t *  @returns {RegExp} constructed object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCreateSearch( search, regex, smart, caseInsensitive )\n\t{\n\t\tsearch = regex ?\n\t\t\tsearch :\n\t\t\t_fnEscapeRegex( search );\n\t\t\n\t\tif ( smart ) {\n\t\t\t/* For smart filtering we want to allow the search to work regardless of\n\t\t\t * word order. We also want double quoted text to be preserved, so word\n\t\t\t * order is important - a la google. So this is what we want to\n\t\t\t * generate:\n\t\t\t * \n\t\t\t * ^(?=.*?\\bone\\b)(?=.*?\\btwo three\\b)(?=.*?\\bfour\\b).*$\n\t\t\t */\n\t\t\tvar a = $.map( search.match( /\"[^\"]+\"|[^ ]+/g ) || [''], function ( word ) {\n\t\t\t\tif ( word.charAt(0) === '\"' ) {\n\t\t\t\t\tvar m = word.match( /^\"(.*)\"$/ );\n\t\t\t\t\tword = m ? m[1] : word;\n\t\t\t\t}\n\t\n\t\t\t\treturn word.replace('\"', '');\n\t\t\t} );\n\t\n\t\t\tsearch = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';\n\t\t}\n\t\n\t\treturn new RegExp( search, caseInsensitive ? 'i' : '' );\n\t}\n\t\n\t\n\t/**\n\t * Escape a string such that it can be used in a regular expression\n\t *  @param {string} sVal string to escape\n\t *  @returns {string} escaped string\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnEscapeRegex = DataTable.util.escapeRegex;\n\t\n\tvar __filter_div = $('<div>')[0];\n\tvar __filter_div_textContent = __filter_div.textContent !== undefined;\n\t\n\t// Update the filtering data for each row if needed (by invalidation or first run)\n\tfunction _fnFilterData ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar column;\n\t\tvar i, j, ien, jen, filterData, cellData, row;\n\t\tvar fomatters = DataTable.ext.type.search;\n\t\tvar wasInvalidated = false;\n\t\n\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aFilterData ) {\n\t\t\t\tfilterData = [];\n\t\n\t\t\t\tfor ( j=0, jen=columns.length ; j<jen ; j++ ) {\n\t\t\t\t\tcolumn = columns[j];\n\t\n\t\t\t\t\tif ( column.bSearchable ) {\n\t\t\t\t\t\tcellData = _fnGetCellData( settings, i, j, 'filter' );\n\t\n\t\t\t\t\t\tif ( fomatters[ column.sType ] ) {\n\t\t\t\t\t\t\tcellData = fomatters[ column.sType ]( cellData );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Search in DataTables 1.10 is string based. In 1.11 this\n\t\t\t\t\t\t// should be altered to also allow strict type checking.\n\t\t\t\t\t\tif ( cellData === null ) {\n\t\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( typeof cellData !== 'string' && cellData.toString ) {\n\t\t\t\t\t\t\tcellData = cellData.toString();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If it looks like there is an HTML entity in the string,\n\t\t\t\t\t// attempt to decode it so sorting works as expected. Note that\n\t\t\t\t\t// we could use a single line of jQuery to do this, but the DOM\n\t\t\t\t\t// method used here is much faster http://jsperf.com/html-decode\n\t\t\t\t\tif ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {\n\t\t\t\t\t\t__filter_div.innerHTML = cellData;\n\t\t\t\t\t\tcellData = __filter_div_textContent ?\n\t\t\t\t\t\t\t__filter_div.textContent :\n\t\t\t\t\t\t\t__filter_div.innerText;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tif ( cellData.replace ) {\n\t\t\t\t\t\tcellData = cellData.replace(/[\\r\\n]/g, '');\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfilterData.push( cellData );\n\t\t\t\t}\n\t\n\t\t\t\trow._aFilterData = filterData;\n\t\t\t\trow._sFilterRow = filterData.join('  ');\n\t\t\t\twasInvalidated = true;\n\t\t\t}\n\t\t}\n\t\n\t\treturn wasInvalidated;\n\t}\n\t\n\t\n\t/**\n\t * Convert from the internal Hungarian notation to camelCase for external\n\t * interaction\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToCamel ( obj )\n\t{\n\t\treturn {\n\t\t\tsearch:          obj.sSearch,\n\t\t\tsmart:           obj.bSmart,\n\t\t\tregex:           obj.bRegex,\n\t\t\tcaseInsensitive: obj.bCaseInsensitive\n\t\t};\n\t}\n\t\n\t\n\t\n\t/**\n\t * Convert from camelCase notation to the internal Hungarian. We could use the\n\t * Hungarian convert function here, but this is cleaner\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToHung ( obj )\n\t{\n\t\treturn {\n\t\t\tsSearch:          obj.search,\n\t\t\tbSmart:           obj.smart,\n\t\t\tbRegex:           obj.regex,\n\t\t\tbCaseInsensitive: obj.caseInsensitive\n\t\t};\n\t}\n\t\n\t/**\n\t * Generate the node required for the info display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Information element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlInfo ( settings )\n\t{\n\t\tvar\n\t\t\ttid = settings.sTableId,\n\t\t\tnodes = settings.aanFeatures.i,\n\t\t\tn = $('<div/>', {\n\t\t\t\t'class': settings.oClasses.sInfo,\n\t\t\t\t'id': ! nodes ? tid+'_info' : null\n\t\t\t} );\n\t\n\t\tif ( ! nodes ) {\n\t\t\t// Update display on each draw\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": _fnUpdateInfo,\n\t\t\t\t\"sName\": \"information\"\n\t\t\t} );\n\t\n\t\t\tn\n\t\t\t\t.attr( 'role', 'status' )\n\t\t\t\t.attr( 'aria-live', 'polite' );\n\t\n\t\t\t// Table is described by our info div\n\t\t\t$(settings.nTable).attr( 'aria-describedby', tid+'_info' );\n\t\t}\n\t\n\t\treturn n[0];\n\t}\n\t\n\t\n\t/**\n\t * Update the information elements in the display\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnUpdateInfo ( settings )\n\t{\n\t\t/* Show information about the table */\n\t\tvar nodes = settings.aanFeatures.i;\n\t\tif ( nodes.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\tlang  = settings.oLanguage,\n\t\t\tstart = settings._iDisplayStart+1,\n\t\t\tend   = settings.fnDisplayEnd(),\n\t\t\tmax   = settings.fnRecordsTotal(),\n\t\t\ttotal = settings.fnRecordsDisplay(),\n\t\t\tout   = total ?\n\t\t\t\tlang.sInfo :\n\t\t\t\tlang.sInfoEmpty;\n\t\n\t\tif ( total !== max ) {\n\t\t\t/* Record set after filtering */\n\t\t\tout += ' ' + lang.sInfoFiltered;\n\t\t}\n\t\n\t\t// Convert the macros\n\t\tout += lang.sInfoPostFix;\n\t\tout = _fnInfoMacros( settings, out );\n\t\n\t\tvar callback = lang.fnInfoCallback;\n\t\tif ( callback !== null ) {\n\t\t\tout = callback.call( settings.oInstance,\n\t\t\t\tsettings, start, end, max, total, out\n\t\t\t);\n\t\t}\n\t\n\t\t$(nodes).html( out );\n\t}\n\t\n\t\n\tfunction _fnInfoMacros ( settings, str )\n\t{\n\t\t// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only\n\t\t// internally\n\t\tvar\n\t\t\tformatter  = settings.fnFormatNumber,\n\t\t\tstart      = settings._iDisplayStart+1,\n\t\t\tlen        = settings._iDisplayLength,\n\t\t\tvis        = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn str.\n\t\t\treplace(/_START_/g, formatter.call( settings, start ) ).\n\t\t\treplace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).\n\t\t\treplace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).\n\t\t\treplace(/_TOTAL_/g, formatter.call( settings, vis ) ).\n\t\t\treplace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).\n\t\t\treplace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );\n\t}\n\t\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitialise ( settings )\n\t{\n\t\tvar i, iLen, iAjaxStart=settings.iInitDisplayStart;\n\t\tvar columns = settings.aoColumns, column;\n\t\tvar features = settings.oFeatures;\n\t\tvar deferLoading = settings.bDeferLoading; // value modified by the draw\n\t\n\t\t/* Ensure that the table data is fully initialised */\n\t\tif ( ! settings.bInitialised ) {\n\t\t\tsetTimeout( function(){ _fnInitialise( settings ); }, 200 );\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Show the display HTML options */\n\t\t_fnAddOptionsHtml( settings );\n\t\n\t\t/* Build and draw the header / footer for the table */\n\t\t_fnBuildHead( settings );\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t/* Okay to show that something is going on now */\n\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t/* Calculate sizes for columns */\n\t\tif ( features.bAutoWidth ) {\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\n\t\t\tif ( column.sWidth ) {\n\t\t\t\tcolumn.nTh.style.width = _fnStringToCss( column.sWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'preInit', [settings] );\n\t\n\t\t// If there is default sorting required - let's do it. The sort function\n\t\t// will do the drawing for us. Otherwise we draw the table regardless of the\n\t\t// Ajax source - this allows the table to look initialised for Ajax sourcing\n\t\t// data (show 'loading' message possibly)\n\t\t_fnReDraw( settings );\n\t\n\t\t// Server-side processing init complete is done by _fnAjaxUpdateDraw\n\t\tvar dataSrc = _fnDataSource( settings );\n\t\tif ( dataSrc != 'ssp' || deferLoading ) {\n\t\t\t// if there is an ajax source load the data\n\t\t\tif ( dataSrc == 'ajax' ) {\n\t\t\t\t_fnBuildAjax( settings, [], function(json) {\n\t\t\t\t\tvar aData = _fnAjaxDataSrc( settings, json );\n\t\n\t\t\t\t\t// Got the data - add it to the table\n\t\t\t\t\tfor ( i=0 ; i<aData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( settings, aData[i] );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Reset the init display for cookie saving. We've already done\n\t\t\t\t\t// a filter, and therefore cleared it before. So we need to make\n\t\t\t\t\t// it appear 'fresh'\n\t\t\t\t\tsettings.iInitDisplayStart = iAjaxStart;\n\t\n\t\t\t\t\t_fnReDraw( settings );\n\t\n\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t_fnInitComplete( settings, json );\n\t\t\t\t}, settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t_fnInitComplete( settings );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} [json] JSON from the server that completed the table, if using Ajax source\n\t *    with client-side processing (optional)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitComplete ( settings, json )\n\t{\n\t\tsettings._bInitComplete = true;\n\t\n\t\t// When data was added after the initialisation (data or Ajax) we need to\n\t\t// calculate the column sizing\n\t\tif ( json || settings.oInit.aaData ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'plugin-init', [settings, json] );\n\t\t_fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );\n\t}\n\t\n\t\n\tfunction _fnLengthChange ( settings, val )\n\t{\n\t\tvar len = parseInt( val, 10 );\n\t\tsettings._iDisplayLength = len;\n\t\n\t\t_fnLengthOverflow( settings );\n\t\n\t\t// Fire length change event\n\t\t_fnCallbackFire( settings, null, 'length', [settings, len] );\n\t}\n\t\n\t\n\t/**\n\t * Generate the node required for user display length changing\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Display length feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlLength ( settings )\n\t{\n\t\tvar\n\t\t\tclasses  = settings.oClasses,\n\t\t\ttableId  = settings.sTableId,\n\t\t\tmenu     = settings.aLengthMenu,\n\t\t\td2       = $.isArray( menu[0] ),\n\t\t\tlengths  = d2 ? menu[0] : menu,\n\t\t\tlanguage = d2 ? menu[1] : menu;\n\t\n\t\tvar select = $('<select/>', {\n\t\t\t'name':          tableId+'_length',\n\t\t\t'aria-controls': tableId,\n\t\t\t'class':         classes.sLengthSelect\n\t\t} );\n\t\n\t\tfor ( var i=0, ien=lengths.length ; i<ien ; i++ ) {\n\t\t\tselect[0][ i ] = new Option(\n\t\t\t\ttypeof language[i] === 'number' ?\n\t\t\t\t\tsettings.fnFormatNumber( language[i] ) :\n\t\t\t\t\tlanguage[i],\n\t\t\t\tlengths[i]\n\t\t\t);\n\t\t}\n\t\n\t\tvar div = $('<div><label/></div>').addClass( classes.sLength );\n\t\tif ( ! settings.aanFeatures.l ) {\n\t\t\tdiv[0].id = tableId+'_length';\n\t\t}\n\t\n\t\tdiv.children().append(\n\t\t\tsettings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )\n\t\t);\n\t\n\t\t// Can't use `select` variable as user might provide their own and the\n\t\t// reference is broken by the use of outerHTML\n\t\t$('select', div)\n\t\t\t.val( settings._iDisplayLength )\n\t\t\t.on( 'change.DT', function(e) {\n\t\t\t\t_fnLengthChange( settings, $(this).val() );\n\t\t\t\t_fnDraw( settings );\n\t\t\t} );\n\t\n\t\t// Update node value whenever anything changes the table's length\n\t\t$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t$('select', div).val( len );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn div[0];\n\t}\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Note that most of the paging logic is done in\n\t * DataTable.ext.pager\n\t */\n\t\n\t/**\n\t * Generate the node required for default pagination\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Pagination feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlPaginate ( settings )\n\t{\n\t\tvar\n\t\t\ttype   = settings.sPaginationType,\n\t\t\tplugin = DataTable.ext.pager[ type ],\n\t\t\tmodern = typeof plugin === 'function',\n\t\t\tredraw = function( settings ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t},\n\t\t\tnode = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],\n\t\t\tfeatures = settings.aanFeatures;\n\t\n\t\tif ( ! modern ) {\n\t\t\tplugin.fnInit( settings, node, redraw );\n\t\t}\n\t\n\t\t/* Add a draw callback for the pagination on first instance, to update the paging display */\n\t\tif ( ! features.p )\n\t\t{\n\t\t\tnode.id = settings.sTableId+'_paginate';\n\t\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": function( settings ) {\n\t\t\t\t\tif ( modern ) {\n\t\t\t\t\t\tvar\n\t\t\t\t\t\t\tstart      = settings._iDisplayStart,\n\t\t\t\t\t\t\tlen        = settings._iDisplayLength,\n\t\t\t\t\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\t\t\t\t\tall        = len === -1,\n\t\t\t\t\t\t\tpage = all ? 0 : Math.ceil( start / len ),\n\t\t\t\t\t\t\tpages = all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\t\t\t\tbuttons = plugin(page, pages),\n\t\t\t\t\t\t\ti, ien;\n\t\n\t\t\t\t\t\tfor ( i=0, ien=features.p.length ; i<ien ; i++ ) {\n\t\t\t\t\t\t\t_fnRenderer( settings, 'pageButton' )(\n\t\t\t\t\t\t\t\tsettings, features.p[i], i, buttons, page, pages\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tplugin.fnUpdate( settings, redraw );\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"sName\": \"pagination\"\n\t\t\t} );\n\t\t}\n\t\n\t\treturn node;\n\t}\n\t\n\t\n\t/**\n\t * Alter the display settings to change the page\n\t *  @param {object} settings DataTables settings object\n\t *  @param {string|int} action Paging action to take: \"first\", \"previous\",\n\t *    \"next\" or \"last\" or page number to jump to (integer)\n\t *  @param [bool] redraw Automatically draw the update or not\n\t *  @returns {bool} true page has changed, false - no change\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnPageChange ( settings, action, redraw )\n\t{\n\t\tvar\n\t\t\tstart     = settings._iDisplayStart,\n\t\t\tlen       = settings._iDisplayLength,\n\t\t\trecords   = settings.fnRecordsDisplay();\n\t\n\t\tif ( records === 0 || len === -1 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( typeof action === \"number\" )\n\t\t{\n\t\t\tstart = action * len;\n\t\n\t\t\tif ( start > records )\n\t\t\t{\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"first\" )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( action == \"previous\" )\n\t\t{\n\t\t\tstart = len >= 0 ?\n\t\t\t\tstart - len :\n\t\t\t\t0;\n\t\n\t\t\tif ( start < 0 )\n\t\t\t{\n\t\t\t  start = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"next\" )\n\t\t{\n\t\t\tif ( start + len < records )\n\t\t\t{\n\t\t\t\tstart += len;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"last\" )\n\t\t{\n\t\t\tstart = Math.floor( (records-1) / len) * len;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_fnLog( settings, 0, \"Unknown paging action: \"+action, 5 );\n\t\t}\n\t\n\t\tvar changed = settings._iDisplayStart !== start;\n\t\tsettings._iDisplayStart = start;\n\t\n\t\tif ( changed ) {\n\t\t\t_fnCallbackFire( settings, null, 'page', [settings] );\n\t\n\t\t\tif ( redraw ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t}\n\t\n\t\treturn changed;\n\t}\n\t\n\t\n\t\n\t/**\n\t * Generate the node required for the processing node\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Processing element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlProcessing ( settings )\n\t{\n\t\treturn $('<div/>', {\n\t\t\t\t'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,\n\t\t\t\t'class': settings.oClasses.sProcessing\n\t\t\t} )\n\t\t\t.html( settings.oLanguage.sProcessing )\n\t\t\t.insertBefore( settings.nTable )[0];\n\t}\n\t\n\t\n\t/**\n\t * Display or hide the processing indicator\n\t *  @param {object} settings dataTables settings object\n\t *  @param {bool} show Show the processing indicator (true) or not (false)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnProcessingDisplay ( settings, show )\n\t{\n\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t$(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'processing', [settings, show] );\n\t}\n\t\n\t/**\n\t * Add any control elements for the table - specifically scrolling\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Node to add to the DOM\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlTable ( settings )\n\t{\n\t\tvar table = $(settings.nTable);\n\t\n\t\t// Add the ARIA grid role to the table\n\t\ttable.attr( 'role', 'grid' );\n\t\n\t\t// Scrolling from here on in\n\t\tvar scroll = settings.oScroll;\n\t\n\t\tif ( scroll.sX === '' && scroll.sY === '' ) {\n\t\t\treturn settings.nTable;\n\t\t}\n\t\n\t\tvar scrollX = scroll.sX;\n\t\tvar scrollY = scroll.sY;\n\t\tvar classes = settings.oClasses;\n\t\tvar caption = table.children('caption');\n\t\tvar captionSide = caption.length ? caption[0]._captionSide : null;\n\t\tvar headerClone = $( table[0].cloneNode(false) );\n\t\tvar footerClone = $( table[0].cloneNode(false) );\n\t\tvar footer = table.children('tfoot');\n\t\tvar _div = '<div/>';\n\t\tvar size = function ( s ) {\n\t\t\treturn !s ? null : _fnStringToCss( s );\n\t\t};\n\t\n\t\tif ( ! footer.length ) {\n\t\t\tfooter = null;\n\t\t}\n\t\n\t\t/*\n\t\t * The HTML structure that we want to generate in this function is:\n\t\t *  div - scroller\n\t\t *    div - scroll head\n\t\t *      div - scroll head inner\n\t\t *        table - scroll head table\n\t\t *          thead - thead\n\t\t *    div - scroll body\n\t\t *      table - table (master table)\n\t\t *        thead - thead clone for sizing\n\t\t *        tbody - tbody\n\t\t *    div - scroll foot\n\t\t *      div - scroll foot inner\n\t\t *        table - scroll foot table\n\t\t *          tfoot - tfoot\n\t\t */\n\t\tvar scroller = $( _div, { 'class': classes.sScrollWrapper } )\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollHead } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollHeadInner } )\n\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t'box-sizing': 'content-box',\n\t\t\t\t\t\t\t\twidth: scroll.sXInner || '100%'\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\theaderClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'top' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('thead')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t)\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollBody } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\toverflow: 'auto',\n\t\t\t\t\t\twidth: size( scrollX )\n\t\t\t\t\t} )\n\t\t\t\t\t.append( table )\n\t\t\t);\n\t\n\t\tif ( footer ) {\n\t\t\tscroller.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollFoot } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollFootInner } )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\tfooterClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'bottom' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('tfoot')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\n\t\tvar children = scroller.children();\n\t\tvar scrollHead = children[0];\n\t\tvar scrollBody = children[1];\n\t\tvar scrollFoot = footer ? children[2] : null;\n\t\n\t\t// When the body is scrolled, then we also want to scroll the headers\n\t\tif ( scrollX ) {\n\t\t\t$(scrollBody).on( 'scroll.DT', function (e) {\n\t\t\t\tvar scrollLeft = this.scrollLeft;\n\t\n\t\t\t\tscrollHead.scrollLeft = scrollLeft;\n\t\n\t\t\t\tif ( footer ) {\n\t\t\t\t\tscrollFoot.scrollLeft = scrollLeft;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\n\t\t$(scrollBody).css(\n\t\t\tscrollY && scroll.bCollapse ? 'max-height' : 'height', \n\t\t\tscrollY\n\t\t);\n\t\n\t\tsettings.nScrollHead = scrollHead;\n\t\tsettings.nScrollBody = scrollBody;\n\t\tsettings.nScrollFoot = scrollFoot;\n\t\n\t\t// On redraw - align columns\n\t\tsettings.aoDrawCallback.push( {\n\t\t\t\"fn\": _fnScrollDraw,\n\t\t\t\"sName\": \"scrolling\"\n\t\t} );\n\t\n\t\treturn scroller[0];\n\t}\n\t\n\t\n\t\n\t/**\n\t * Update the header, footer and body tables for resizing - i.e. column\n\t * alignment.\n\t *\n\t * Welcome to the most horrible function DataTables. The process that this\n\t * function follows is basically:\n\t *   1. Re-create the table inside the scrolling div\n\t *   2. Take live measurements from the DOM\n\t *   3. Apply the measurements to align the columns\n\t *   4. Clean up\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnScrollDraw ( settings )\n\t{\n\t\t// Given that this is such a monster function, a lot of variables are use\n\t\t// to try and keep the minimised size as small as possible\n\t\tvar\n\t\t\tscroll         = settings.oScroll,\n\t\t\tscrollX        = scroll.sX,\n\t\t\tscrollXInner   = scroll.sXInner,\n\t\t\tscrollY        = scroll.sY,\n\t\t\tbarWidth       = scroll.iBarWidth,\n\t\t\tdivHeader      = $(settings.nScrollHead),\n\t\t\tdivHeaderStyle = divHeader[0].style,\n\t\t\tdivHeaderInner = divHeader.children('div'),\n\t\t\tdivHeaderInnerStyle = divHeaderInner[0].style,\n\t\t\tdivHeaderTable = divHeaderInner.children('table'),\n\t\t\tdivBodyEl      = settings.nScrollBody,\n\t\t\tdivBody        = $(divBodyEl),\n\t\t\tdivBodyStyle   = divBodyEl.style,\n\t\t\tdivFooter      = $(settings.nScrollFoot),\n\t\t\tdivFooterInner = divFooter.children('div'),\n\t\t\tdivFooterTable = divFooterInner.children('table'),\n\t\t\theader         = $(settings.nTHead),\n\t\t\ttable          = $(settings.nTable),\n\t\t\ttableEl        = table[0],\n\t\t\ttableStyle     = tableEl.style,\n\t\t\tfooter         = settings.nTFoot ? $(settings.nTFoot) : null,\n\t\t\tbrowser        = settings.oBrowser,\n\t\t\tie67           = browser.bScrollOversize,\n\t\t\tdtHeaderCells  = _pluck( settings.aoColumns, 'nTh' ),\n\t\t\theaderTrgEls, footerTrgEls,\n\t\t\theaderSrcEls, footerSrcEls,\n\t\t\theaderCopy, footerCopy,\n\t\t\theaderWidths=[], footerWidths=[],\n\t\t\theaderContent=[], footerContent=[],\n\t\t\tidx, correction, sanityWidth,\n\t\t\tzeroOut = function(nSizer) {\n\t\t\t\tvar style = nSizer.style;\n\t\t\t\tstyle.paddingTop = \"0\";\n\t\t\t\tstyle.paddingBottom = \"0\";\n\t\t\t\tstyle.borderTopWidth = \"0\";\n\t\t\t\tstyle.borderBottomWidth = \"0\";\n\t\t\t\tstyle.height = 0;\n\t\t\t};\n\t\n\t\t// If the scrollbar visibility has changed from the last draw, we need to\n\t\t// adjust the column sizes as the table width will have changed to account\n\t\t// for the scrollbar\n\t\tvar scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;\n\t\t\n\t\tif ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t\treturn; // adjust column sizing will call this function again\n\t\t}\n\t\telse {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t}\n\t\n\t\t/*\n\t\t * 1. Re-create the table inside the scrolling div\n\t\t */\n\t\n\t\t// Remove the old minimised thead and tfoot elements in the inner table\n\t\ttable.children('thead, tfoot').remove();\n\t\n\t\tif ( footer ) {\n\t\t\tfooterCopy = footer.clone().prependTo( table );\n\t\t\tfooterTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized\n\t\t\tfooterSrcEls = footerCopy.find('tr');\n\t\t}\n\t\n\t\t// Clone the current header and footer elements and then place it into the inner table\n\t\theaderCopy = header.clone().prependTo( table );\n\t\theaderTrgEls = header.find('tr'); // original header is in its own table\n\t\theaderSrcEls = headerCopy.find('tr');\n\t\theaderCopy.find('th, td').removeAttr('tabindex');\n\t\n\t\n\t\t/*\n\t\t * 2. Take live measurements from the DOM - do not alter the DOM itself!\n\t\t */\n\t\n\t\t// Remove old sizing and apply the calculated column widths\n\t\t// Get the unique column headers in the newly created (cloned) header. We want to apply the\n\t\t// calculated sizes to this header\n\t\tif ( ! scrollX )\n\t\t{\n\t\t\tdivBodyStyle.width = '100%';\n\t\t\tdivHeader[0].style.width = '100%';\n\t\t}\n\t\n\t\t$.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {\n\t\t\tidx = _fnVisibleToColumnIndex( settings, i );\n\t\t\tel.style.width = settings.aoColumns[idx].sWidth;\n\t\t} );\n\t\n\t\tif ( footer ) {\n\t\t\t_fnApplyToChildren( function(n) {\n\t\t\t\tn.style.width = \"\";\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Size the table as a whole\n\t\tsanityWidth = table.outerWidth();\n\t\tif ( scrollX === \"\" ) {\n\t\t\t// No x scrolling\n\t\t\ttableStyle.width = \"100%\";\n\t\n\t\t\t// IE7 will make the width of the table when 100% include the scrollbar\n\t\t\t// - which is shouldn't. When there is a scrollbar we need to take this\n\t\t\t// into account.\n\t\t\tif ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);\n\t\t\t}\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\telse if ( scrollXInner !== \"\" ) {\n\t\t\t// legacy x scroll inner has been given - use it\n\t\t\ttableStyle.width = _fnStringToCss(scrollXInner);\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\n\t\t// Hidden header should have zero height, so remove padding and borders. Then\n\t\t// set the width based on the real headers\n\t\n\t\t// Apply all styles in one pass\n\t\t_fnApplyToChildren( zeroOut, headerSrcEls );\n\t\n\t\t// Read all widths in next pass\n\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\theaderContent.push( nSizer.innerHTML );\n\t\t\theaderWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t}, headerSrcEls );\n\t\n\t\t// Apply all widths in final pass\n\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t// Only apply widths to the DataTables detected header cells - this\n\t\t\t// prevents complex headers from having contradictory sizes applied\n\t\t\tif ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {\n\t\t\t\tnToSize.style.width = headerWidths[i];\n\t\t\t}\n\t\t}, headerTrgEls );\n\t\n\t\t$(headerSrcEls).height(0);\n\t\n\t\t/* Same again with the footer if we have one */\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( zeroOut, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\t\tfooterContent.push( nSizer.innerHTML );\n\t\t\t\tfooterWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t\t}, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t\tnToSize.style.width = footerWidths[i];\n\t\t\t}, footerTrgEls );\n\t\n\t\t\t$(footerSrcEls).height(0);\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 3. Apply the measurements\n\t\t */\n\t\n\t\t// \"Hide\" the header and footer that we used for the sizing. We need to keep\n\t\t// the content of the cell so that the width applied to the header and body\n\t\t// both match, but we want to hide it completely. We want to also fix their\n\t\t// width to what they currently are\n\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\">'+headerContent[i]+'</div>';\n\t\t\tnSizer.childNodes[0].style.height = \"0\";\n\t\t\tnSizer.childNodes[0].style.overflow = \"hidden\";\n\t\t\tnSizer.style.width = headerWidths[i];\n\t\t}, headerSrcEls );\n\t\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\">'+footerContent[i]+'</div>';\n\t\t\t\tnSizer.childNodes[0].style.height = \"0\";\n\t\t\t\tnSizer.childNodes[0].style.overflow = \"hidden\";\n\t\t\t\tnSizer.style.width = footerWidths[i];\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Sanity check that the table is of a sensible width. If not then we are going to get\n\t\t// misalignment - try to prevent this by not allowing the table to shrink below its min width\n\t\tif ( table.outerWidth() < sanityWidth )\n\t\t{\n\t\t\t// The min width depends upon if we have a vertical scrollbar visible or not */\n\t\t\tcorrection = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")) ?\n\t\t\t\t\tsanityWidth+barWidth :\n\t\t\t\t\tsanityWidth;\n\t\n\t\t\t// IE6/7 are a law unto themselves...\n\t\t\tif ( ie67 && (divBodyEl.scrollHeight >\n\t\t\t\tdivBodyEl.offsetHeight || divBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( correction-barWidth );\n\t\t\t}\n\t\n\t\t\t// And give the user a warning that we've stopped the table getting too small\n\t\t\tif ( scrollX === \"\" || scrollXInner !== \"\" ) {\n\t\t\t\t_fnLog( settings, 1, 'Possible column misalignment', 6 );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcorrection = '100%';\n\t\t}\n\t\n\t\t// Apply to the container elements\n\t\tdivBodyStyle.width = _fnStringToCss( correction );\n\t\tdivHeaderStyle.width = _fnStringToCss( correction );\n\t\n\t\tif ( footer ) {\n\t\t\tsettings.nScrollFoot.style.width = _fnStringToCss( correction );\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 4. Clean up\n\t\t */\n\t\tif ( ! scrollY ) {\n\t\t\t/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting\n\t\t\t * the scrollbar height from the visible display, rather than adding it on. We need to\n\t\t\t * set the height in order to sort this. Don't want to do it in any other browsers.\n\t\t\t */\n\t\t\tif ( ie67 ) {\n\t\t\t\tdivBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Finally set the width's of the header and footer tables */\n\t\tvar iOuterWidth = table.outerWidth();\n\t\tdivHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\tdivHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );\n\t\n\t\t// Figure out if there are scrollbar present - if so then we need a the header and footer to\n\t\t// provide a bit more space to allow \"overflow\" scrolling (i.e. past the scrollbar)\n\t\tvar bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == \"scroll\";\n\t\tvar padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );\n\t\tdivHeaderInnerStyle[ padding ] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\n\t\tif ( footer ) {\n\t\t\tdivFooterTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style[padding] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\t}\n\t\n\t\t// Correct DOM ordering for colgroup - comes before the thead\n\t\ttable.children('colgroup').insertBefore( table.children('thead') );\n\t\n\t\t/* Adjust the position of the header in case we loose the y-scrollbar */\n\t\tdivBody.scroll();\n\t\n\t\t// If sorting or filtering has occurred, jump the scrolling back to the top\n\t\t// only if we aren't holding the position\n\t\tif ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {\n\t\t\tdivBodyEl.scrollTop = 0;\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Apply a given function to the display child nodes of an element array (typically\n\t * TD children of TR rows\n\t *  @param {function} fn Method to apply to the objects\n\t *  @param array {nodes} an1 List of elements to look through for display children\n\t *  @param array {nodes} an2 Another list (identical structure to the first) - optional\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyToChildren( fn, an1, an2 )\n\t{\n\t\tvar index=0, i=0, iLen=an1.length;\n\t\tvar nNode1, nNode2;\n\t\n\t\twhile ( i < iLen ) {\n\t\t\tnNode1 = an1[i].firstChild;\n\t\t\tnNode2 = an2 ? an2[i].firstChild : null;\n\t\n\t\t\twhile ( nNode1 ) {\n\t\t\t\tif ( nNode1.nodeType === 1 ) {\n\t\t\t\t\tif ( an2 ) {\n\t\t\t\t\t\tfn( nNode1, nNode2, index );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfn( nNode1, index );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\n\t\t\t\tnNode1 = nNode1.nextSibling;\n\t\t\t\tnNode2 = an2 ? nNode2.nextSibling : null;\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t}\n\t}\n\t\n\t\n\t\n\tvar __re_html_remove = /<.*?>/g;\n\t\n\t\n\t/**\n\t * Calculate the width of columns for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCalculateColumnWidths ( oSettings )\n\t{\n\t\tvar\n\t\t\ttable = oSettings.nTable,\n\t\t\tcolumns = oSettings.aoColumns,\n\t\t\tscroll = oSettings.oScroll,\n\t\t\tscrollY = scroll.sY,\n\t\t\tscrollX = scroll.sX,\n\t\t\tscrollXInner = scroll.sXInner,\n\t\t\tcolumnCount = columns.length,\n\t\t\tvisibleColumns = _fnGetColumns( oSettings, 'bVisible' ),\n\t\t\theaderCells = $('th', oSettings.nTHead),\n\t\t\ttableWidthAttr = table.getAttribute('width'), // from DOM element\n\t\t\ttableContainer = table.parentNode,\n\t\t\tuserInputs = false,\n\t\t\ti, column, columnIdx, width, outerWidth,\n\t\t\tbrowser = oSettings.oBrowser,\n\t\t\tie67 = browser.bScrollOversize;\n\t\n\t\tvar styleWidth = table.style.width;\n\t\tif ( styleWidth && styleWidth.indexOf('%') !== -1 ) {\n\t\t\ttableWidthAttr = styleWidth;\n\t\t}\n\t\n\t\t/* Convert any user input sizes into pixel sizes */\n\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\tif ( column.sWidth !== null ) {\n\t\t\t\tcolumn.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );\n\t\n\t\t\t\tuserInputs = true;\n\t\t\t}\n\t\t}\n\t\n\t\t/* If the number of columns in the DOM equals the number that we have to\n\t\t * process in DataTables, then we can use the offsets that are created by\n\t\t * the web- browser. No custom sizes can be set in order for this to happen,\n\t\t * nor scrolling used\n\t\t */\n\t\tif ( ie67 || ! userInputs && ! scrollX && ! scrollY &&\n\t\t     columnCount == _fnVisbleColumns( oSettings ) &&\n\t\t     columnCount == headerCells.length\n\t\t) {\n\t\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\t\tvar colIdx = _fnVisibleToColumnIndex( oSettings, i );\n\t\n\t\t\t\tif ( colIdx !== null ) {\n\t\t\t\t\tcolumns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise construct a single row, worst case, table with the widest\n\t\t\t// node in the data, assign any user defined widths, then insert it into\n\t\t\t// the DOM and allow the browser to do all the hard work of calculating\n\t\t\t// table widths\n\t\t\tvar tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table\n\t\t\t\t.css( 'visibility', 'hidden' )\n\t\t\t\t.removeAttr( 'id' );\n\t\n\t\t\t// Clean up the table body\n\t\t\ttmpTable.find('tbody tr').remove();\n\t\t\tvar tr = $('<tr/>').appendTo( tmpTable.find('tbody') );\n\t\n\t\t\t// Clone the table header and footer - we can't use the header / footer\n\t\t\t// from the cloned table, since if scrolling is active, the table's\n\t\t\t// real header and footer are contained in different table tags\n\t\t\ttmpTable.find('thead, tfoot').remove();\n\t\t\ttmpTable\n\t\t\t\t.append( $(oSettings.nTHead).clone() )\n\t\t\t\t.append( $(oSettings.nTFoot).clone() );\n\t\n\t\t\t// Remove any assigned widths from the footer (from scrolling)\n\t\t\ttmpTable.find('tfoot th, tfoot td').css('width', '');\n\t\n\t\t\t// Apply custom sizing to the cloned header\n\t\t\theaderCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );\n\t\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\t\theaderCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?\n\t\t\t\t\t_fnStringToCss( column.sWidthOrig ) :\n\t\t\t\t\t'';\n\t\n\t\t\t\t// For scrollX we need to force the column width otherwise the\n\t\t\t\t// browser will collapse it. If this width is smaller than the\n\t\t\t\t// width the column requires, then it will have no effect\n\t\t\t\tif ( column.sWidthOrig && scrollX ) {\n\t\t\t\t\t$( headerCells[i] ).append( $('<div/>').css( {\n\t\t\t\t\t\twidth: column.sWidthOrig,\n\t\t\t\t\t\tmargin: 0,\n\t\t\t\t\t\tpadding: 0,\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\theight: 1\n\t\t\t\t\t} ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Find the widest cell for each column and put it into the table\n\t\t\tif ( oSettings.aoData.length ) {\n\t\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\t\tcolumnIdx = visibleColumns[i];\n\t\t\t\t\tcolumn = columns[ columnIdx ];\n\t\n\t\t\t\t\t$( _fnGetWidestNode( oSettings, columnIdx ) )\n\t\t\t\t\t\t.clone( false )\n\t\t\t\t\t\t.append( column.sContentPadding )\n\t\t\t\t\t\t.appendTo( tr );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Tidy the temporary table - remove name attributes so there aren't\n\t\t\t// duplicated in the dom (radio elements for example)\n\t\t\t$('[name]', tmpTable).removeAttr('name');\n\t\n\t\t\t// Table has been built, attach to the document so we can work with it.\n\t\t\t// A holding element is used, positioned at the top of the container\n\t\t\t// with minimal height, so it has no effect on if the container scrolls\n\t\t\t// or not. Otherwise it might trigger scrolling when it actually isn't\n\t\t\t// needed\n\t\t\tvar holder = $('<div/>').css( scrollX || scrollY ?\n\t\t\t\t\t{\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\theight: 1,\n\t\t\t\t\t\tright: 0,\n\t\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t\t} :\n\t\t\t\t\t{}\n\t\t\t\t)\n\t\t\t\t.append( tmpTable )\n\t\t\t\t.appendTo( tableContainer );\n\t\n\t\t\t// When scrolling (X or Y) we want to set the width of the table as \n\t\t\t// appropriate. However, when not scrolling leave the table width as it\n\t\t\t// is. This results in slightly different, but I think correct behaviour\n\t\t\tif ( scrollX && scrollXInner ) {\n\t\t\t\ttmpTable.width( scrollXInner );\n\t\t\t}\n\t\t\telse if ( scrollX ) {\n\t\t\t\ttmpTable.css( 'width', 'auto' );\n\t\t\t\ttmpTable.removeAttr('width');\n\t\n\t\t\t\t// If there is no width attribute or style, then allow the table to\n\t\t\t\t// collapse\n\t\t\t\tif ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {\n\t\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( scrollY ) {\n\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t}\n\t\t\telse if ( tableWidthAttr ) {\n\t\t\t\ttmpTable.width( tableWidthAttr );\n\t\t\t}\n\t\n\t\t\t// Get the width of each column in the constructed table - we need to\n\t\t\t// know the inner width (so it can be assigned to the other table's\n\t\t\t// cells) and the outer width so we can calculate the full width of the\n\t\t\t// table. This is safe since DataTables requires a unique cell for each\n\t\t\t// column, but if ever a header can span multiple columns, this will\n\t\t\t// need to be modified.\n\t\t\tvar total = 0;\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tvar cell = $(headerCells[i]);\n\t\t\t\tvar border = cell.outerWidth() - cell.width();\n\t\n\t\t\t\t// Use getBounding... where possible (not IE8-) because it can give\n\t\t\t\t// sub-pixel accuracy, which we then want to round up!\n\t\t\t\tvar bounding = browser.bBounding ?\n\t\t\t\t\tMath.ceil( headerCells[i].getBoundingClientRect().width ) :\n\t\t\t\t\tcell.outerWidth();\n\t\n\t\t\t\t// Total is tracked to remove any sub-pixel errors as the outerWidth\n\t\t\t\t// of the table might not equal the total given here (IE!).\n\t\t\t\ttotal += bounding;\n\t\n\t\t\t\t// Width for each column to use\n\t\t\t\tcolumns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );\n\t\t\t}\n\t\n\t\t\ttable.style.width = _fnStringToCss( total );\n\t\n\t\t\t// Finished with the table - ditch it\n\t\t\tholder.remove();\n\t\t}\n\t\n\t\t// If there is a width attr, we want to attach an event listener which\n\t\t// allows the table sizing to automatically adjust when the window is\n\t\t// resized. Use the width attr rather than CSS, since we can't know if the\n\t\t// CSS is a relative value or absolute - DOM read is always px.\n\t\tif ( tableWidthAttr ) {\n\t\t\ttable.style.width = _fnStringToCss( tableWidthAttr );\n\t\t}\n\t\n\t\tif ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {\n\t\t\tvar bindResize = function () {\n\t\t\t\t$(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {\n\t\t\t\t\t_fnAdjustColumnSizing( oSettings );\n\t\t\t\t} ) );\n\t\t\t};\n\t\n\t\t\t// IE6/7 will crash if we bind a resize event handler on page load.\n\t\t\t// To be removed in 1.11 which drops IE6/7 support\n\t\t\tif ( ie67 ) {\n\t\t\t\tsetTimeout( bindResize, 1000 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbindResize();\n\t\t\t}\n\t\n\t\t\toSettings._reszEvt = true;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Throttle the calls to a function. Arguments and context are maintained for\n\t * the throttled function\n\t *  @param {function} fn Function to be called\n\t *  @param {int} [freq=200] call frequency in mS\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnThrottle = DataTable.util.throttle;\n\t\n\t\n\t/**\n\t * Convert a CSS unit width to pixels (e.g. 2em)\n\t *  @param {string} width width to be converted\n\t *  @param {node} parent parent to get the with for (required for relative widths) - optional\n\t *  @returns {int} width in pixels\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnConvertToWidth ( width, parent )\n\t{\n\t\tif ( ! width ) {\n\t\t\treturn 0;\n\t\t}\n\t\n\t\tvar n = $('<div/>')\n\t\t\t.css( 'width', _fnStringToCss( width ) )\n\t\t\t.appendTo( parent || document.body );\n\t\n\t\tvar val = n[0].offsetWidth;\n\t\tn.remove();\n\t\n\t\treturn val;\n\t}\n\t\n\t\n\t/**\n\t * Get the widest node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {node} widest table node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetWidestNode( settings, colIdx )\n\t{\n\t\tvar idx = _fnGetMaxLenString( settings, colIdx );\n\t\tif ( idx < 0 ) {\n\t\t\treturn null;\n\t\t}\n\t\n\t\tvar data = settings.aoData[ idx ];\n\t\treturn ! data.nTr ? // Might not have been created when deferred rendering\n\t\t\t$('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :\n\t\t\tdata.anCells[ colIdx ];\n\t}\n\t\n\t\n\t/**\n\t * Get the maximum strlen for each data column\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {string} max string length for each column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetMaxLenString( settings, colIdx )\n\t{\n\t\tvar s, max=-1, maxIdx = -1;\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\ts = _fnGetCellData( settings, i, colIdx, 'display' )+'';\n\t\t\ts = s.replace( __re_html_remove, '' );\n\t\t\ts = s.replace( /&nbsp;/g, ' ' );\n\t\n\t\t\tif ( s.length > max ) {\n\t\t\t\tmax = s.length;\n\t\t\t\tmaxIdx = i;\n\t\t\t}\n\t\t}\n\t\n\t\treturn maxIdx;\n\t}\n\t\n\t\n\t/**\n\t * Append a CSS unit (only if required) to a string\n\t *  @param {string} value to css-ify\n\t *  @returns {string} value with css unit\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnStringToCss( s )\n\t{\n\t\tif ( s === null ) {\n\t\t\treturn '0px';\n\t\t}\n\t\n\t\tif ( typeof s == 'number' ) {\n\t\t\treturn s < 0 ?\n\t\t\t\t'0px' :\n\t\t\t\ts+'px';\n\t\t}\n\t\n\t\t// Check it has a unit character already\n\t\treturn s.match(/\\d$/) ?\n\t\t\ts+'px' :\n\t\t\ts;\n\t}\n\t\n\t\n\t\n\tfunction _fnSortFlatten ( settings )\n\t{\n\t\tvar\n\t\t\ti, iLen, k, kLen,\n\t\t\taSort = [],\n\t\t\taiOrig = [],\n\t\t\taoColumns = settings.aoColumns,\n\t\t\taDataSort, iCol, sType, srcCol,\n\t\t\tfixed = settings.aaSortingFixed,\n\t\t\tfixedObj = $.isPlainObject( fixed ),\n\t\t\tnestedSort = [],\n\t\t\tadd = function ( a ) {\n\t\t\t\tif ( a.length && ! $.isArray( a[0] ) ) {\n\t\t\t\t\t// 1D array\n\t\t\t\t\tnestedSort.push( a );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// 2D array\n\t\t\t\t\t$.merge( nestedSort, a );\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t// Build the sort array, with pre-fix and post-fix options if they have been\n\t\t// specified\n\t\tif ( $.isArray( fixed ) ) {\n\t\t\tadd( fixed );\n\t\t}\n\t\n\t\tif ( fixedObj && fixed.pre ) {\n\t\t\tadd( fixed.pre );\n\t\t}\n\t\n\t\tadd( settings.aaSorting );\n\t\n\t\tif (fixedObj && fixed.post ) {\n\t\t\tadd( fixed.post );\n\t\t}\n\t\n\t\tfor ( i=0 ; i<nestedSort.length ; i++ )\n\t\t{\n\t\t\tsrcCol = nestedSort[i][0];\n\t\t\taDataSort = aoColumns[ srcCol ].aDataSort;\n\t\n\t\t\tfor ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )\n\t\t\t{\n\t\t\t\tiCol = aDataSort[k];\n\t\t\t\tsType = aoColumns[ iCol ].sType || 'string';\n\t\n\t\t\t\tif ( nestedSort[i]._idx === undefined ) {\n\t\t\t\t\tnestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );\n\t\t\t\t}\n\t\n\t\t\t\taSort.push( {\n\t\t\t\t\tsrc:       srcCol,\n\t\t\t\t\tcol:       iCol,\n\t\t\t\t\tdir:       nestedSort[i][1],\n\t\t\t\t\tindex:     nestedSort[i]._idx,\n\t\t\t\t\ttype:      sType,\n\t\t\t\t\tformatter: DataTable.ext.type.order[ sType+\"-pre\" ]\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\treturn aSort;\n\t}\n\t\n\t/**\n\t * Change the order of the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t *  @todo This really needs split up!\n\t */\n\tfunction _fnSort ( oSettings )\n\t{\n\t\tvar\n\t\t\ti, ien, iLen, j, jLen, k, kLen,\n\t\t\tsDataType, nTh,\n\t\t\taiOrig = [],\n\t\t\toExtSort = DataTable.ext.type.order,\n\t\t\taoData = oSettings.aoData,\n\t\t\taoColumns = oSettings.aoColumns,\n\t\t\taDataSort, data, iCol, sType, oSort,\n\t\t\tformatters = 0,\n\t\t\tsortCol,\n\t\t\tdisplayMaster = oSettings.aiDisplayMaster,\n\t\t\taSort;\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo Can this be moved into a 'data-ready' handler which is called when\n\t\t//   data is going to be used in the table?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\taSort = _fnSortFlatten( oSettings );\n\t\n\t\tfor ( i=0, ien=aSort.length ; i<ien ; i++ ) {\n\t\t\tsortCol = aSort[i];\n\t\n\t\t\t// Track if we can use the fast sort algorithm\n\t\t\tif ( sortCol.formatter ) {\n\t\t\t\tformatters++;\n\t\t\t}\n\t\n\t\t\t// Load the data needed for the sort, for each cell\n\t\t\t_fnSortData( oSettings, sortCol.col );\n\t\t}\n\t\n\t\t/* No sorting required if server-side or no sorting array */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )\n\t\t{\n\t\t\t// Create a value - key array of the current row positions such that we can use their\n\t\t\t// current position during the sort, if values match, in order to perform stable sorting\n\t\t\tfor ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {\n\t\t\t\taiOrig[ displayMaster[i] ] = i;\n\t\t\t}\n\t\n\t\t\t/* Do the sort - here we want multi-column sorting based on a given data source (column)\n\t\t\t * and sorting function (from oSort) in a certain direction. It's reasonably complex to\n\t\t\t * follow on it's own, but this is what we want (example two column sorting):\n\t\t\t *  fnLocalSorting = function(a,b){\n\t\t\t *    var iTest;\n\t\t\t *    iTest = oSort['string-asc']('data11', 'data12');\n\t\t\t *      if (iTest !== 0)\n\t\t\t *        return iTest;\n\t\t\t *    iTest = oSort['numeric-desc']('data21', 'data22');\n\t\t\t *    if (iTest !== 0)\n\t\t\t *      return iTest;\n\t\t\t *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );\n\t\t\t *  }\n\t\t\t * Basically we have a test for each sorting column, if the data in that column is equal,\n\t\t\t * test the next column. If all columns match, then we use a numeric sort on the row\n\t\t\t * positions in the original data array to provide a stable sort.\n\t\t\t *\n\t\t\t * Note - I know it seems excessive to have two sorting methods, but the first is around\n\t\t\t * 15% faster, so the second is only maintained for backwards compatibility with sorting\n\t\t\t * methods which do not have a pre-sort formatting function.\n\t\t\t */\n\t\t\tif ( formatters === aSort.length ) {\n\t\t\t\t// All sort types have formatting functions\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, test, sort,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\ttest = x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn sort.dir === 'asc' ? test : -test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Depreciated - remove in 1.11 (providing a plug-in option)\n\t\t\t\t// Not all sort types have formatting methods, so we have to call their sorting\n\t\t\t\t// methods.\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, l, test, sort, fn,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\tfn = oExtSort[ sort.type+\"-\"+sort.dir ] || oExtSort[ \"string-\"+sort.dir ];\n\t\t\t\t\t\ttest = fn( x, y );\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Tell the draw function that we have sorted the data */\n\t\toSettings.bSorted = true;\n\t}\n\t\n\t\n\tfunction _fnSortAria ( settings )\n\t{\n\t\tvar label;\n\t\tvar nextSort;\n\t\tvar columns = settings.aoColumns;\n\t\tvar aSort = _fnSortFlatten( settings );\n\t\tvar oAria = settings.oLanguage.oAria;\n\t\n\t\t// ARIA attributes - need to loop all columns, to update all (removing old\n\t\t// attributes as needed)\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar col = columns[i];\n\t\t\tvar asSorting = col.asSorting;\n\t\t\tvar sTitle = col.sTitle.replace( /<.*?>/g, \"\" );\n\t\t\tvar th = col.nTh;\n\t\n\t\t\t// IE7 is throwing an error when setting these properties with jQuery's\n\t\t\t// attr() and removeAttr() methods...\n\t\t\tth.removeAttribute('aria-sort');\n\t\n\t\t\t/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */\n\t\t\tif ( col.bSortable ) {\n\t\t\t\tif ( aSort.length > 0 && aSort[0].col == i ) {\n\t\t\t\t\tth.setAttribute('aria-sort', aSort[0].dir==\"asc\" ? \"ascending\" : \"descending\" );\n\t\t\t\t\tnextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tnextSort = asSorting[0];\n\t\t\t\t}\n\t\n\t\t\t\tlabel = sTitle + ( nextSort === \"asc\" ?\n\t\t\t\t\toAria.sSortAscending :\n\t\t\t\t\toAria.sSortDescending\n\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlabel = sTitle;\n\t\t\t}\n\t\n\t\t\tth.setAttribute('aria-label', label);\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Function to run on user sort request\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {boolean} [append=false] Append the requested sort to the existing\n\t *    sort if true (i.e. multi-column sort)\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortListener ( settings, colIdx, append, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\tvar sorting = settings.aaSorting;\n\t\tvar asSorting = col.asSorting;\n\t\tvar nextSortIdx;\n\t\tvar next = function ( a, overflow ) {\n\t\t\tvar idx = a._idx;\n\t\t\tif ( idx === undefined ) {\n\t\t\t\tidx = $.inArray( a[1], asSorting );\n\t\t\t}\n\t\n\t\t\treturn idx+1 < asSorting.length ?\n\t\t\t\tidx+1 :\n\t\t\t\toverflow ?\n\t\t\t\t\tnull :\n\t\t\t\t\t0;\n\t\t};\n\t\n\t\t// Convert to 2D array if needed\n\t\tif ( typeof sorting[0] === 'number' ) {\n\t\t\tsorting = settings.aaSorting = [ sorting ];\n\t\t}\n\t\n\t\t// If appending the sort then we are multi-column sorting\n\t\tif ( append && settings.oFeatures.bSortMulti ) {\n\t\t\t// Are we already doing some kind of sort on this column?\n\t\t\tvar sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );\n\t\n\t\t\tif ( sortIdx !== -1 ) {\n\t\t\t\t// Yes, modify the sort\n\t\t\t\tnextSortIdx = next( sorting[sortIdx], true );\n\t\n\t\t\t\tif ( nextSortIdx === null && sorting.length === 1 ) {\n\t\t\t\t\tnextSortIdx = 0; // can't remove sorting completely\n\t\t\t\t}\n\t\n\t\t\t\tif ( nextSortIdx === null ) {\n\t\t\t\t\tsorting.splice( sortIdx, 1 );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tsorting[sortIdx][1] = asSorting[ nextSortIdx ];\n\t\t\t\t\tsorting[sortIdx]._idx = nextSortIdx;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// No sort on this column yet\n\t\t\t\tsorting.push( [ colIdx, asSorting[0], 0 ] );\n\t\t\t\tsorting[sorting.length-1]._idx = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( sorting.length && sorting[0][0] == colIdx ) {\n\t\t\t// Single column - already sorting on this column, modify the sort\n\t\t\tnextSortIdx = next( sorting[0] );\n\t\n\t\t\tsorting.length = 1;\n\t\t\tsorting[0][1] = asSorting[ nextSortIdx ];\n\t\t\tsorting[0]._idx = nextSortIdx;\n\t\t}\n\t\telse {\n\t\t\t// Single column - sort only on this column\n\t\t\tsorting.length = 0;\n\t\t\tsorting.push( [ colIdx, asSorting[0] ] );\n\t\t\tsorting[0]._idx = 0;\n\t\t}\n\t\n\t\t// Run the sort by calling a full redraw\n\t\t_fnReDraw( settings );\n\t\n\t\t// callback used for async user interaction\n\t\tif ( typeof callback == 'function' ) {\n\t\t\tcallback( settings );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Attach a sort handler (click) to a node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortAttachListener ( settings, attachTo, colIdx, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\n\t\t_fnBindAction( attachTo, {}, function (e) {\n\t\t\t/* If the column is not sortable - don't to anything */\n\t\t\tif ( col.bSortable === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If processing is enabled use a timeout to allow the processing\n\t\t\t// display to be shown - otherwise to it synchronously\n\t\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t\tsetTimeout( function() {\n\t\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\n\t\t\t\t\t// In server-side processing, the draw callback will remove the\n\t\t\t\t\t// processing display\n\t\t\t\t\tif ( _fnDataSource( settings ) !== 'ssp' ) {\n\t\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t}\n\t\t\t\t}, 0 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Set the sorting classes on table's body, Note: it is safe to call this function\n\t * when bSort and bSortClasses are false\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortingClasses( settings )\n\t{\n\t\tvar oldSort = settings.aLastSort;\n\t\tvar sortClass = settings.oClasses.sSortColumn;\n\t\tvar sort = _fnSortFlatten( settings );\n\t\tvar features = settings.oFeatures;\n\t\tvar i, ien, colIdx;\n\t\n\t\tif ( features.bSort && features.bSortClasses ) {\n\t\t\t// Remove old sorting classes\n\t\t\tfor ( i=0, ien=oldSort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = oldSort[i].src;\n\t\n\t\t\t\t// Remove column sorting\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.removeClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\n\t\t\t// Add new column sorting\n\t\t\tfor ( i=0, ien=sort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = sort[i].src;\n\t\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.addClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aLastSort = sort;\n\t}\n\t\n\t\n\t// Get the data to sort a column, be it from cache, fresh (populating the\n\t// cache), or from a sort formatter\n\tfunction _fnSortData( settings, idx )\n\t{\n\t\t// Custom sorting function - provided by the sort data type\n\t\tvar column = settings.aoColumns[ idx ];\n\t\tvar customSort = DataTable.ext.order[ column.sSortDataType ];\n\t\tvar customData;\n\t\n\t\tif ( customSort ) {\n\t\t\tcustomData = customSort.call( settings.oInstance, settings, idx,\n\t\t\t\t_fnColumnIndexToVisible( settings, idx )\n\t\t\t);\n\t\t}\n\t\n\t\t// Use / populate cache\n\t\tvar row, cellData;\n\t\tvar formatter = DataTable.ext.type.order[ column.sType+\"-pre\" ];\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aSortData ) {\n\t\t\t\trow._aSortData = [];\n\t\t\t}\n\t\n\t\t\tif ( ! row._aSortData[idx] || customSort ) {\n\t\t\t\tcellData = customSort ?\n\t\t\t\t\tcustomData[i] : // If there was a custom sort function, use data from there\n\t\t\t\t\t_fnGetCellData( settings, i, idx, 'sort' );\n\t\n\t\t\t\trow._aSortData[ idx ] = formatter ?\n\t\t\t\t\tformatter( cellData ) :\n\t\t\t\t\tcellData;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Save the state of a table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSaveState ( settings )\n\t{\n\t\tif ( !settings.oFeatures.bStateSave || settings.bDestroying )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Store the interesting variables */\n\t\tvar state = {\n\t\t\ttime:    +new Date(),\n\t\t\tstart:   settings._iDisplayStart,\n\t\t\tlength:  settings._iDisplayLength,\n\t\t\torder:   $.extend( true, [], settings.aaSorting ),\n\t\t\tsearch:  _fnSearchToCamel( settings.oPreviousSearch ),\n\t\t\tcolumns: $.map( settings.aoColumns, function ( col, i ) {\n\t\t\t\treturn {\n\t\t\t\t\tvisible: col.bVisible,\n\t\t\t\t\tsearch: _fnSearchToCamel( settings.aoPreSearchCols[i] )\n\t\t\t\t};\n\t\t\t} )\n\t\t};\n\t\n\t\t_fnCallbackFire( settings, \"aoStateSaveParams\", 'stateSaveParams', [settings, state] );\n\t\n\t\tsettings.oSavedState = state;\n\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, state );\n\t}\n\t\n\t\n\t/**\n\t * Attempt to load a saved table state\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oInit DataTables init object so we can override settings\n\t *  @param {function} callback Callback to execute when the state has been loaded\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLoadState ( settings, oInit, callback )\n\t{\n\t\tvar i, ien;\n\t\tvar columns = settings.aoColumns;\n\t\tvar loaded = function ( s ) {\n\t\t\tif ( ! s || ! s.time ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Allow custom and plug-in manipulation functions to alter the saved data set and\n\t\t\t// cancelling of loading by returning false\n\t\t\tvar abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );\n\t\t\tif ( $.inArray( false, abStateLoad ) !== -1 ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Reject old data\n\t\t\tvar duration = settings.iStateDuration;\n\t\t\tif ( duration > 0 && s.time < +new Date() - (duration*1000) ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Number of columns have changed - all bets are off, no restore of settings\n\t\t\tif ( s.columns && columns.length !== s.columns.length ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Store the saved state so it might be accessed at any time\n\t\t\tsettings.oLoadedState = $.extend( true, {}, s );\n\t\n\t\t\t// Restore key features - todo - for 1.11 this needs to be done by\n\t\t\t// subscribed events\n\t\t\tif ( s.start !== undefined ) {\n\t\t\t\tsettings._iDisplayStart    = s.start;\n\t\t\t\tsettings.iInitDisplayStart = s.start;\n\t\t\t}\n\t\t\tif ( s.length !== undefined ) {\n\t\t\t\tsettings._iDisplayLength   = s.length;\n\t\t\t}\n\t\n\t\t\t// Order\n\t\t\tif ( s.order !== undefined ) {\n\t\t\t\tsettings.aaSorting = [];\n\t\t\t\t$.each( s.order, function ( i, col ) {\n\t\t\t\t\tsettings.aaSorting.push( col[0] >= columns.length ?\n\t\t\t\t\t\t[ 0, col[1] ] :\n\t\t\t\t\t\tcol\n\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Search\n\t\t\tif ( s.search !== undefined ) {\n\t\t\t\t$.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );\n\t\t\t}\n\t\n\t\t\t// Columns\n\t\t\t//\n\t\t\tif ( s.columns ) {\n\t\t\t\tfor ( i=0, ien=s.columns.length ; i<ien ; i++ ) {\n\t\t\t\t\tvar col = s.columns[i];\n\t\n\t\t\t\t\t// Visibility\n\t\t\t\t\tif ( col.visible !== undefined ) {\n\t\t\t\t\t\tcolumns[i].bVisible = col.visible;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Search\n\t\t\t\t\tif ( col.search !== undefined ) {\n\t\t\t\t\t\t$.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );\n\t\t\tcallback();\n\t\t}\n\t\n\t\tif ( ! settings.oFeatures.bStateSave ) {\n\t\t\tcallback();\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );\n\t\n\t\tif ( state !== undefined ) {\n\t\t\tloaded( state );\n\t\t}\n\t\t// otherwise, wait for the loaded callback to be executed\n\t}\n\t\n\t\n\t/**\n\t * Return the settings object for a particular table\n\t *  @param {node} table table we are using as a dataTable\n\t *  @returns {object} Settings object - or null if not found\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSettingsFromNode ( table )\n\t{\n\t\tvar settings = DataTable.settings;\n\t\tvar idx = $.inArray( table, _pluck( settings, 'nTable' ) );\n\t\n\t\treturn idx !== -1 ?\n\t\t\tsettings[ idx ] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Log an error message\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} level log error messages, or display them to the user\n\t *  @param {string} msg error message\n\t *  @param {int} tn Technical note id to get more information about the error.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLog( settings, level, msg, tn )\n\t{\n\t\tmsg = 'DataTables warning: '+\n\t\t\t(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;\n\t\n\t\tif ( tn ) {\n\t\t\tmsg += '. For more information about this error, please see '+\n\t\t\t'http://datatables.net/tn/'+tn;\n\t\t}\n\t\n\t\tif ( ! level  ) {\n\t\t\t// Backwards compatibility pre 1.10\n\t\t\tvar ext = DataTable.ext;\n\t\t\tvar type = ext.sErrMode || ext.errMode;\n\t\n\t\t\tif ( settings ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );\n\t\t\t}\n\t\n\t\t\tif ( type == 'alert' ) {\n\t\t\t\talert( msg );\n\t\t\t}\n\t\t\telse if ( type == 'throw' ) {\n\t\t\t\tthrow new Error(msg);\n\t\t\t}\n\t\t\telse if ( typeof type == 'function' ) {\n\t\t\t\ttype( settings, tn, msg );\n\t\t\t}\n\t\t}\n\t\telse if ( window.console && console.log ) {\n\t\t\tconsole.log( msg );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * See if a property is defined on one object, if so assign it to the other object\n\t *  @param {object} ret target object\n\t *  @param {object} src source object\n\t *  @param {string} name property\n\t *  @param {string} [mappedName] name to map too - optional, name used if not given\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnMap( ret, src, name, mappedName )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\t$.each( name, function (i, val) {\n\t\t\t\tif ( $.isArray( val ) ) {\n\t\t\t\t\t_fnMap( ret, src, val[0], val[1] );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_fnMap( ret, src, val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( mappedName === undefined ) {\n\t\t\tmappedName = name;\n\t\t}\n\t\n\t\tif ( src[name] !== undefined ) {\n\t\t\tret[mappedName] = src[name];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Extend objects - very similar to jQuery.extend, but deep copy objects, and\n\t * shallow copy arrays. The reason we need to do this, is that we don't want to\n\t * deep copy array init values (such as aaSorting) since the dev wouldn't be\n\t * able to override them, but we do want to deep copy arrays.\n\t *  @param {object} out Object to extend\n\t *  @param {object} extender Object from which the properties will be applied to\n\t *      out\n\t *  @param {boolean} breakRefs If true, then arrays will be sliced to take an\n\t *      independent copy with the exception of the `data` or `aaData` parameters\n\t *      if they are present. This is so you can pass in a collection to\n\t *      DataTables and have that used as your data source without breaking the\n\t *      references\n\t *  @returns {object} out Reference, just for convenience - out === the return.\n\t *  @memberof DataTable#oApi\n\t *  @todo This doesn't take account of arrays inside the deep copied objects.\n\t */\n\tfunction _fnExtend( out, extender, breakRefs )\n\t{\n\t\tvar val;\n\t\n\t\tfor ( var prop in extender ) {\n\t\t\tif ( extender.hasOwnProperty(prop) ) {\n\t\t\t\tval = extender[prop];\n\t\n\t\t\t\tif ( $.isPlainObject( val ) ) {\n\t\t\t\t\tif ( ! $.isPlainObject( out[prop] ) ) {\n\t\t\t\t\t\tout[prop] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, out[prop], val );\n\t\t\t\t}\n\t\t\t\telse if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {\n\t\t\t\t\tout[prop] = val.slice();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tout[prop] = val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t}\n\t\n\t\n\t/**\n\t * Bind an event handers to allow a click or return key to activate the callback.\n\t * This is good for accessibility since a return on the keyboard will have the\n\t * same effect as a click, if the element has focus.\n\t *  @param {element} n Element to bind the action to\n\t *  @param {object} oData Data object to pass to the triggered function\n\t *  @param {function} fn Callback function for when the event is triggered\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBindAction( n, oData, fn )\n\t{\n\t\t$(n)\n\t\t\t.on( 'click.DT', oData, function (e) {\n\t\t\t\t\t$(n).blur(); // Remove focus outline for mouse users\n\t\t\t\t\tfn(e);\n\t\t\t\t} )\n\t\t\t.on( 'keypress.DT', oData, function (e){\n\t\t\t\t\tif ( e.which === 13 ) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tfn(e);\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t.on( 'selectstart.DT', function () {\n\t\t\t\t\t/* Take the brutal approach to cancelling text selection */\n\t\t\t\t\treturn false;\n\t\t\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Register a callback function. Easily allows a callback function to be added to\n\t * an array store of callback functions that can then all be called together.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sStore Name of the array storage for the callbacks in oSettings\n\t *  @param {function} fn Function to be called back\n\t *  @param {string} sName Identifying name for the callback (i.e. a label)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackReg( oSettings, sStore, fn, sName )\n\t{\n\t\tif ( fn )\n\t\t{\n\t\t\toSettings[sStore].push( {\n\t\t\t\t\"fn\": fn,\n\t\t\t\t\"sName\": sName\n\t\t\t} );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Fire callback functions and trigger events. Note that the loop over the\n\t * callback array store is done backwards! Further note that you do not want to\n\t * fire off triggers in time sensitive applications (for example cell creation)\n\t * as its slow.\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} callbackArr Name of the array storage for the callbacks in\n\t *      oSettings\n\t *  @param {string} eventName Name of the jQuery custom event to trigger. If\n\t *      null no trigger is fired\n\t *  @param {array} args Array of arguments to pass to the callback function /\n\t *      trigger\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackFire( settings, callbackArr, eventName, args )\n\t{\n\t\tvar ret = [];\n\t\n\t\tif ( callbackArr ) {\n\t\t\tret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {\n\t\t\t\treturn val.fn.apply( settings.oInstance, args );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( eventName !== null ) {\n\t\t\tvar e = $.Event( eventName+'.dt' );\n\t\n\t\t\t$(settings.nTable).trigger( e, args );\n\t\n\t\t\tret.push( e.result );\n\t\t}\n\t\n\t\treturn ret;\n\t}\n\t\n\t\n\tfunction _fnLengthOverflow ( settings )\n\t{\n\t\tvar\n\t\t\tstart = settings._iDisplayStart,\n\t\t\tend = settings.fnDisplayEnd(),\n\t\t\tlen = settings._iDisplayLength;\n\t\n\t\t/* If we have space to show extra rows (backing up from the end point - then do so */\n\t\tif ( start >= end )\n\t\t{\n\t\t\tstart = end - len;\n\t\t}\n\t\n\t\t// Keep the start record on the current page\n\t\tstart -= (start % len);\n\t\n\t\tif ( len === -1 || start < 0 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\n\t\tsettings._iDisplayStart = start;\n\t}\n\t\n\t\n\tfunction _fnRenderer( settings, type )\n\t{\n\t\tvar renderer = settings.renderer;\n\t\tvar host = DataTable.ext.renderer[type];\n\t\n\t\tif ( $.isPlainObject( renderer ) && renderer[type] ) {\n\t\t\t// Specific renderer for this type. If available use it, otherwise use\n\t\t\t// the default.\n\t\t\treturn host[renderer[type]] || host._;\n\t\t}\n\t\telse if ( typeof renderer === 'string' ) {\n\t\t\t// Common renderer - if there is one available for this type use it,\n\t\t\t// otherwise use the default\n\t\t\treturn host[renderer] || host._;\n\t\t}\n\t\n\t\t// Use the default\n\t\treturn host._;\n\t}\n\t\n\t\n\t/**\n\t * Detect the data source being used for the table. Used to simplify the code\n\t * a little (ajax) and to make it compress a little smaller.\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {string} Data source\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDataSource ( settings )\n\t{\n\t\tif ( settings.oFeatures.bServerSide ) {\n\t\t\treturn 'ssp';\n\t\t}\n\t\telse if ( settings.ajax || settings.sAjaxSource ) {\n\t\t\treturn 'ajax';\n\t\t}\n\t\treturn 'dom';\n\t}\n\t\n\n\t\n\t\n\t/**\n\t * Computed structure of the DataTables API, defined by the options passed to\n\t * `DataTable.Api.register()` when building the API.\n\t *\n\t * The structure is built in order to speed creation and extension of the Api\n\t * objects since the extensions are effectively pre-parsed.\n\t *\n\t * The array is an array of objects with the following structure, where this\n\t * base array represents the Api prototype base:\n\t *\n\t *     [\n\t *       {\n\t *         name:      'data'                -- string   - Property name\n\t *         val:       function () {},       -- function - Api method (or undefined if just an object\n\t *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t *       },\n\t *       {\n\t *         name:     'row'\n\t *         val:       {},\n\t *         methodExt: [ ... ],\n\t *         propExt:   [\n\t *           {\n\t *             name:      'data'\n\t *             val:       function () {},\n\t *             methodExt: [ ... ],\n\t *             propExt:   [ ... ]\n\t *           },\n\t *           ...\n\t *         ]\n\t *       }\n\t *     ]\n\t *\n\t * @type {Array}\n\t * @ignore\n\t */\n\tvar __apiStruct = [];\n\t\n\t\n\t/**\n\t * `Array.prototype` reference.\n\t *\n\t * @type object\n\t * @ignore\n\t */\n\tvar __arrayProto = Array.prototype;\n\t\n\t\n\t/**\n\t * Abstraction for `context` parameter of the `Api` constructor to allow it to\n\t * take several different forms for ease of use.\n\t *\n\t * Each of the input parameter types will be converted to a DataTables settings\n\t * object where possible.\n\t *\n\t * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one\n\t *   of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t *   * `DataTables.Api` - API instance\n\t * @return {array|null} Matching DataTables settings objects. `null` or\n\t *   `undefined` is returned if no matching DataTable is found.\n\t * @ignore\n\t */\n\tvar _toSettings = function ( mixed )\n\t{\n\t\tvar idx, jq;\n\t\tvar settings = DataTable.settings;\n\t\tvar tables = $.map( settings, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\tif ( ! mixed ) {\n\t\t\treturn [];\n\t\t}\n\t\telse if ( mixed.nTable && mixed.oApi ) {\n\t\t\t// DataTables settings object\n\t\t\treturn [ mixed ];\n\t\t}\n\t\telse if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {\n\t\t\t// Table node\n\t\t\tidx = $.inArray( mixed, tables );\n\t\t\treturn idx !== -1 ? [ settings[idx] ] : null;\n\t\t}\n\t\telse if ( mixed && typeof mixed.settings === 'function' ) {\n\t\t\treturn mixed.settings().toArray();\n\t\t}\n\t\telse if ( typeof mixed === 'string' ) {\n\t\t\t// jQuery selector\n\t\t\tjq = $(mixed);\n\t\t}\n\t\telse if ( mixed instanceof $ ) {\n\t\t\t// jQuery object (also DataTables instance)\n\t\t\tjq = mixed;\n\t\t}\n\t\n\t\tif ( jq ) {\n\t\t\treturn jq.map( function(i) {\n\t\t\t\tidx = $.inArray( this, tables );\n\t\t\t\treturn idx !== -1 ? settings[idx] : null;\n\t\t\t} ).toArray();\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * DataTables API class - used to control and interface with  one or more\n\t * DataTables enhanced tables.\n\t *\n\t * The API class is heavily based on jQuery, presenting a chainable interface\n\t * that you can use to interact with tables. Each instance of the API class has\n\t * a \"context\" - i.e. the tables that it will operate on. This could be a single\n\t * table, all tables on a page or a sub-set thereof.\n\t *\n\t * Additionally the API is designed to allow you to easily work with the data in\n\t * the tables, retrieving and manipulating it as required. This is done by\n\t * presenting the API class as an array like interface. The contents of the\n\t * array depend upon the actions requested by each method (for example\n\t * `rows().nodes()` will return an array of nodes, while `rows().data()` will\n\t * return an array of objects or arrays depending upon your table's\n\t * configuration). The API object has a number of array like methods (`push`,\n\t * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,\n\t * `unique` etc) to assist your working with the data held in a table.\n\t *\n\t * Most methods (those which return an Api instance) are chainable, which means\n\t * the return from a method call also has all of the methods available that the\n\t * top level object had. For example, these two calls are equivalent:\n\t *\n\t *     // Not chained\n\t *     api.row.add( {...} );\n\t *     api.draw();\n\t *\n\t *     // Chained\n\t *     api.row.add( {...} ).draw();\n\t *\n\t * @class DataTable.Api\n\t * @param {array|object|string|jQuery} context DataTable identifier. This is\n\t *   used to define which DataTables enhanced tables this API will operate on.\n\t *   Can be one of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t * @param {array} [data] Data to initialise the Api instance with.\n\t *\n\t * @example\n\t *   // Direct initialisation during DataTables construction\n\t *   var api = $('#example').DataTable();\n\t *\n\t * @example\n\t *   // Initialisation using a DataTables jQuery object\n\t *   var api = $('#example').dataTable().api();\n\t *\n\t * @example\n\t *   // Initialisation as a constructor\n\t *   var api = new $.fn.DataTable.Api( 'table.dataTable' );\n\t */\n\t_Api = function ( context, data )\n\t{\n\t\tif ( ! (this instanceof _Api) ) {\n\t\t\treturn new _Api( context, data );\n\t\t}\n\t\n\t\tvar settings = [];\n\t\tvar ctxSettings = function ( o ) {\n\t\t\tvar a = _toSettings( o );\n\t\t\tif ( a ) {\n\t\t\t\tsettings = settings.concat( a );\n\t\t\t}\n\t\t};\n\t\n\t\tif ( $.isArray( context ) ) {\n\t\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tctxSettings( context[i] );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tctxSettings( context );\n\t\t}\n\t\n\t\t// Remove duplicates\n\t\tthis.context = _unique( settings );\n\t\n\t\t// Initial data\n\t\tif ( data ) {\n\t\t\t$.merge( this, data );\n\t\t}\n\t\n\t\t// selector\n\t\tthis.selector = {\n\t\t\trows: null,\n\t\t\tcols: null,\n\t\t\topts: null\n\t\t};\n\t\n\t\t_Api.extend( this, this, __apiStruct );\n\t};\n\t\n\tDataTable.Api = _Api;\n\t\n\t// Don't destroy the existing prototype, just extend it. Required for jQuery 2's\n\t// isPlainObject.\n\t$.extend( _Api.prototype, {\n\t\tany: function ()\n\t\t{\n\t\t\treturn this.count() !== 0;\n\t\t},\n\t\n\t\n\t\tconcat:  __arrayProto.concat,\n\t\n\t\n\t\tcontext: [], // array of table settings objects\n\t\n\t\n\t\tcount: function ()\n\t\t{\n\t\t\treturn this.flatten().length;\n\t\t},\n\t\n\t\n\t\teach: function ( fn )\n\t\t{\n\t\t\tfor ( var i=0, ien=this.length ; i<ien; i++ ) {\n\t\t\t\tfn.call( this, this[i], i, this );\n\t\t\t}\n\t\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\teq: function ( idx )\n\t\t{\n\t\t\tvar ctx = this.context;\n\t\n\t\t\treturn ctx.length > idx ?\n\t\t\t\tnew _Api( ctx[idx], this[idx] ) :\n\t\t\t\tnull;\n\t\t},\n\t\n\t\n\t\tfilter: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.filter ) {\n\t\t\t\ta = __arrayProto.filter.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( fn.call( this, this[i], i, this ) ) {\n\t\t\t\t\t\ta.push( this[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tflatten: function ()\n\t\t{\n\t\t\tvar a = [];\n\t\t\treturn new _Api( this.context, a.concat.apply( a, this.toArray() ) );\n\t\t},\n\t\n\t\n\t\tjoin:    __arrayProto.join,\n\t\n\t\n\t\tindexOf: __arrayProto.indexOf || function (obj, start)\n\t\t{\n\t\t\tfor ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {\n\t\t\t\tif ( this[i] === obj ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn -1;\n\t\t},\n\t\n\t\titerator: function ( flatten, type, fn, alwaysNew ) {\n\t\t\tvar\n\t\t\t\ta = [], ret,\n\t\t\t\ti, ien, j, jen,\n\t\t\t\tcontext = this.context,\n\t\t\t\trows, items, item,\n\t\t\t\tselector = this.selector;\n\t\n\t\t\t// Argument shifting\n\t\t\tif ( typeof flatten === 'string' ) {\n\t\t\t\talwaysNew = fn;\n\t\t\t\tfn = type;\n\t\t\t\ttype = flatten;\n\t\t\t\tflatten = false;\n\t\t\t}\n\t\n\t\t\tfor ( i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tvar apiInst = new _Api( context[i] );\n\t\n\t\t\t\tif ( type === 'table' ) {\n\t\t\t\t\tret = fn.call( apiInst, context[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'columns' || type === 'rows' ) {\n\t\t\t\t\t// this has same length as context - one entry for each table\n\t\t\t\t\tret = fn.call( apiInst, context[i], this[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {\n\t\t\t\t\t// columns and rows share the same structure.\n\t\t\t\t\t// 'this' is an array of column indexes for each context\n\t\t\t\t\titems = this[i];\n\t\n\t\t\t\t\tif ( type === 'column-rows' ) {\n\t\t\t\t\t\trows = _selector_row_indexes( context[i], selector.opts );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfor ( j=0, jen=items.length ; j<jen ; j++ ) {\n\t\t\t\t\t\titem = items[j];\n\t\n\t\t\t\t\t\tif ( type === 'cell' ) {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item.row, item.column, i, j );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item, i, j, rows );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( a.length || alwaysNew ) {\n\t\t\t\tvar api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );\n\t\t\t\tvar apiSelector = api.selector;\n\t\t\t\tapiSelector.rows = selector.rows;\n\t\t\t\tapiSelector.cols = selector.cols;\n\t\t\t\tapiSelector.opts = selector.opts;\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\tlastIndexOf: __arrayProto.lastIndexOf || function (obj, start)\n\t\t{\n\t\t\t// Bit cheeky...\n\t\t\treturn this.indexOf.apply( this.toArray.reverse(), arguments );\n\t\t},\n\t\n\t\n\t\tlength:  0,\n\t\n\t\n\t\tmap: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.map ) {\n\t\t\t\ta = __arrayProto.map.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\ta.push( fn.call( this, this[i], i ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tpluck: function ( prop )\n\t\t{\n\t\t\treturn this.map( function ( el ) {\n\t\t\t\treturn el[ prop ];\n\t\t\t} );\n\t\t},\n\t\n\t\tpop:     __arrayProto.pop,\n\t\n\t\n\t\tpush:    __arrayProto.push,\n\t\n\t\n\t\t// Does not return an API instance\n\t\treduce: __arrayProto.reduce || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, 0, this.length, 1 );\n\t\t},\n\t\n\t\n\t\treduceRight: __arrayProto.reduceRight || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, this.length-1, -1, -1 );\n\t\t},\n\t\n\t\n\t\treverse: __arrayProto.reverse,\n\t\n\t\n\t\t// Object with rows, columns and opts\n\t\tselector: null,\n\t\n\t\n\t\tshift:   __arrayProto.shift,\n\t\n\t\n\t\tslice: function () {\n\t\t\treturn new _Api( this.context, this );\n\t\t},\n\t\n\t\n\t\tsort:    __arrayProto.sort, // ? name - order?\n\t\n\t\n\t\tsplice:  __arrayProto.splice,\n\t\n\t\n\t\ttoArray: function ()\n\t\t{\n\t\t\treturn __arrayProto.slice.call( this );\n\t\t},\n\t\n\t\n\t\tto$: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\ttoJQuery: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\tunique: function ()\n\t\t{\n\t\t\treturn new _Api( this.context, _unique(this) );\n\t\t},\n\t\n\t\n\t\tunshift: __arrayProto.unshift\n\t} );\n\t\n\t\n\t_Api.extend = function ( scope, obj, ext )\n\t{\n\t\t// Only extend API instances and static properties of the API\n\t\tif ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\tj, jen,\n\t\t\tstruct, inner,\n\t\t\tmethodScoping = function ( scope, fn, struc ) {\n\t\t\t\treturn function () {\n\t\t\t\t\tvar ret = fn.apply( scope, arguments );\n\t\n\t\t\t\t\t// Method extension\n\t\t\t\t\t_Api.extend( ret, ret, struc.methodExt );\n\t\t\t\t\treturn ret;\n\t\t\t\t};\n\t\t\t};\n\t\n\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\tstruct = ext[i];\n\t\n\t\t\t// Value\n\t\t\tobj[ struct.name ] = typeof struct.val === 'function' ?\n\t\t\t\tmethodScoping( scope, struct.val, struct ) :\n\t\t\t\t$.isPlainObject( struct.val ) ?\n\t\t\t\t\t{} :\n\t\t\t\t\tstruct.val;\n\t\n\t\t\tobj[ struct.name ].__dt_wrapper = true;\n\t\n\t\t\t// Property extension\n\t\t\t_Api.extend( scope, obj[ struct.name ], struct.propExt );\n\t\t}\n\t};\n\t\n\t\n\t// @todo - Is there need for an augment function?\n\t// _Api.augment = function ( inst, name )\n\t// {\n\t// \t// Find src object in the structure from the name\n\t// \tvar parts = name.split('.');\n\t\n\t// \t_Api.extend( inst, obj );\n\t// };\n\t\n\t\n\t//     [\n\t//       {\n\t//         name:      'data'                -- string   - Property name\n\t//         val:       function () {},       -- function - Api method (or undefined if just an object\n\t//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t//       },\n\t//       {\n\t//         name:     'row'\n\t//         val:       {},\n\t//         methodExt: [ ... ],\n\t//         propExt:   [\n\t//           {\n\t//             name:      'data'\n\t//             val:       function () {},\n\t//             methodExt: [ ... ],\n\t//             propExt:   [ ... ]\n\t//           },\n\t//           ...\n\t//         ]\n\t//       }\n\t//     ]\n\t\n\t_Api.register = _api_register = function ( name, val )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\tfor ( var j=0, jen=name.length ; j<jen ; j++ ) {\n\t\t\t\t_Api.register( name[j], val );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\their = name.split('.'),\n\t\t\tstruct = __apiStruct,\n\t\t\tkey, method;\n\t\n\t\tvar find = function ( src, name ) {\n\t\t\tfor ( var i=0, ien=src.length ; i<ien ; i++ ) {\n\t\t\t\tif ( src[i].name === name ) {\n\t\t\t\t\treturn src[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\n\t\tfor ( i=0, ien=heir.length ; i<ien ; i++ ) {\n\t\t\tmethod = heir[i].indexOf('()') !== -1;\n\t\t\tkey = method ?\n\t\t\t\their[i].replace('()', '') :\n\t\t\t\their[i];\n\t\n\t\t\tvar src = find( struct, key );\n\t\t\tif ( ! src ) {\n\t\t\t\tsrc = {\n\t\t\t\t\tname:      key,\n\t\t\t\t\tval:       {},\n\t\t\t\t\tmethodExt: [],\n\t\t\t\t\tpropExt:   []\n\t\t\t\t};\n\t\t\t\tstruct.push( src );\n\t\t\t}\n\t\n\t\t\tif ( i === ien-1 ) {\n\t\t\t\tsrc.val = val;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstruct = method ?\n\t\t\t\t\tsrc.methodExt :\n\t\t\t\t\tsrc.propExt;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\t_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {\n\t\t_Api.register( pluralName, val );\n\t\n\t\t_Api.register( singularName, function () {\n\t\t\tvar ret = val.apply( this, arguments );\n\t\n\t\t\tif ( ret === this ) {\n\t\t\t\t// Returned item is the API instance that was passed in, return it\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\telse if ( ret instanceof _Api ) {\n\t\t\t\t// New API instance returned, want the value from the first item\n\t\t\t\t// in the returned array for the singular result.\n\t\t\t\treturn ret.length ?\n\t\t\t\t\t$.isArray( ret[0] ) ?\n\t\t\t\t\t\tnew _Api( ret.context, ret[0] ) : // Array results are 'enhanced'\n\t\t\t\t\t\tret[0] :\n\t\t\t\t\tundefined;\n\t\t\t}\n\t\n\t\t\t// Non-API return - just fire it back\n\t\t\treturn ret;\n\t\t} );\n\t};\n\t\n\t\n\t/**\n\t * Selector for HTML tables. Apply the given selector to the give array of\n\t * DataTables settings objects.\n\t *\n\t * @param {string|integer} [selector] jQuery selector string or integer\n\t * @param  {array} Array of DataTables settings objects to be filtered\n\t * @return {array}\n\t * @ignore\n\t */\n\tvar __table_selector = function ( selector, a )\n\t{\n\t\t// Integer is used to pick out a table by index\n\t\tif ( typeof selector === 'number' ) {\n\t\t\treturn [ a[ selector ] ];\n\t\t}\n\t\n\t\t// Perform a jQuery selector on the table nodes\n\t\tvar nodes = $.map( a, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\treturn $(nodes)\n\t\t\t.filter( selector )\n\t\t\t.map( function (i) {\n\t\t\t\t// Need to translate back from the table node to the settings\n\t\t\t\tvar idx = $.inArray( this, nodes );\n\t\t\t\treturn a[ idx ];\n\t\t\t} )\n\t\t\t.toArray();\n\t};\n\t\n\t\n\t\n\t/**\n\t * Context selector for the API's context (i.e. the tables the API instance\n\t * refers to.\n\t *\n\t * @name    DataTable.Api#tables\n\t * @param {string|integer} [selector] Selector to pick which tables the iterator\n\t *   should operate on. If not given, all tables in the current context are\n\t *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to\n\t *   select multiple tables or as an integer to select a single table.\n\t * @returns {DataTable.Api} Returns a new API instance if a selector is given.\n\t */\n\t_api_register( 'tables()', function ( selector ) {\n\t\t// A new instance is created if there was a selector specified\n\t\treturn selector ?\n\t\t\tnew _Api( __table_selector( selector, this.context ) ) :\n\t\t\tthis;\n\t} );\n\t\n\t\n\t_api_register( 'table()', function ( selector ) {\n\t\tvar tables = this.tables( selector );\n\t\tvar ctx = tables.context;\n\t\n\t\t// Truncate to the first matched table\n\t\treturn ctx.length ?\n\t\t\tnew _Api( ctx[0] ) :\n\t\t\ttables;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().nodes()', 'table().node()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTable;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().body()', 'table().body()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTBody;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().header()', 'table().header()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTHead;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().footer()', 'table().footer()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTFoot;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().containers()', 'table().container()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTableWrapper;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Redraw the tables in the current context.\n\t */\n\t_api_register( 'draw()', function ( paging ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( paging === 'page' ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif ( typeof paging === 'string' ) {\n\t\t\t\t\tpaging = paging === 'full-hold' ?\n\t\t\t\t\t\tfalse :\n\t\t\t\t\t\ttrue;\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, paging===false );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get the current page index.\n\t *\n\t * @return {integer} Current page index (zero based)\n\t *//**\n\t * Set the current page.\n\t *\n\t * Note that if you attempt to show a page which does not exist, DataTables will\n\t * not throw an error, but rather reset the paging.\n\t *\n\t * @param {integer|string} action The paging action to take. This can be one of:\n\t *  * `integer` - The page index to jump to\n\t *  * `string` - An action to take:\n\t *    * `first` - Jump to first page.\n\t *    * `next` - Jump to the next page\n\t *    * `previous` - Jump to previous page\n\t *    * `last` - Jump to the last page.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page()', function ( action ) {\n\t\tif ( action === undefined ) {\n\t\t\treturn this.page.info().page; // not an expensive call\n\t\t}\n\t\n\t\t// else, have an action to take on all tables\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnPageChange( settings, action );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Paging information for the first table in the current context.\n\t *\n\t * If you require paging information for another table, use the `table()` method\n\t * with a suitable selector.\n\t *\n\t * @return {object} Object with the following properties set:\n\t *  * `page` - Current page index (zero based - i.e. the first page is `0`)\n\t *  * `pages` - Total number of pages\n\t *  * `start` - Display index for the first record shown on the current page\n\t *  * `end` - Display index for the last record shown on the current page\n\t *  * `length` - Display length (number of records). Note that generally `start\n\t *    + length = end`, but this is not always true, for example if there are\n\t *    only 2 records to show on the final page, with a length of 10.\n\t *  * `recordsTotal` - Full data set length\n\t *  * `recordsDisplay` - Data set length once the current filtering criterion\n\t *    are applied.\n\t */\n\t_api_register( 'page.info()', function ( action ) {\n\t\tif ( this.context.length === 0 ) {\n\t\t\treturn undefined;\n\t\t}\n\t\n\t\tvar\n\t\t\tsettings   = this.context[0],\n\t\t\tstart      = settings._iDisplayStart,\n\t\t\tlen        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,\n\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn {\n\t\t\t\"page\":           all ? 0 : Math.floor( start / len ),\n\t\t\t\"pages\":          all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\"start\":          start,\n\t\t\t\"end\":            settings.fnDisplayEnd(),\n\t\t\t\"length\":         len,\n\t\t\t\"recordsTotal\":   settings.fnRecordsTotal(),\n\t\t\t\"recordsDisplay\": visRecords,\n\t\t\t\"serverSide\":     _fnDataSource( settings ) === 'ssp'\n\t\t};\n\t} );\n\t\n\t\n\t/**\n\t * Get the current page length.\n\t *\n\t * @return {integer} Current page length. Note `-1` indicates that all records\n\t *   are to be shown.\n\t *//**\n\t * Set the current page length.\n\t *\n\t * @param {integer} Page length to set. Use `-1` to show all records.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page.len()', function ( len ) {\n\t\t// Note that we can't call this function 'length()' because `length`\n\t\t// is a Javascript property of functions which defines how many arguments\n\t\t// the function expects.\n\t\tif ( len === undefined ) {\n\t\t\treturn this.context.length !== 0 ?\n\t\t\t\tthis.context[0]._iDisplayLength :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// else, set the page length\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnLengthChange( settings, len );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\tvar __reload = function ( settings, holdPosition, callback ) {\n\t\t// Use the draw event to trigger a callback\n\t\tif ( callback ) {\n\t\t\tvar api = new _Api( settings );\n\t\n\t\t\tapi.one( 'draw', function () {\n\t\t\t\tcallback( api.ajax.json() );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t_fnReDraw( settings, holdPosition );\n\t\t}\n\t\telse {\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t// Cancel an existing request\n\t\t\tvar xhr = settings.jqXHR;\n\t\t\tif ( xhr && xhr.readyState !== 4 ) {\n\t\t\t\txhr.abort();\n\t\t\t}\n\t\n\t\t\t// Trigger xhr\n\t\t\t_fnBuildAjax( settings, [], function( json ) {\n\t\t\t\t_fnClearTable( settings );\n\t\n\t\t\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\t_fnAddData( settings, data[i] );\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, holdPosition );\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Get the JSON response from the last Ajax request that DataTables made to the\n\t * server. Note that this returns the JSON from the first table in the current\n\t * context.\n\t *\n\t * @return {object} JSON received from the server.\n\t */\n\t_api_register( 'ajax.json()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].json;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Get the data submitted in the last Ajax request\n\t */\n\t_api_register( 'ajax.params()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].oAjaxData;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Reload tables from the Ajax data source. Note that this function will\n\t * automatically re-draw the table when the remote data has been loaded.\n\t *\n\t * @param {boolean} [reset=true] Reset (default) or hold the current paging\n\t *   position. A full re-sort and re-filter is performed when this method is\n\t *   called, which is why the pagination reset is the default action.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.reload()', function ( callback, resetPaging ) {\n\t\treturn this.iterator( 'table', function (settings) {\n\t\t\t__reload( settings, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Get the current Ajax URL. Note that this returns the URL from the first\n\t * table in the current context.\n\t *\n\t * @return {string} Current Ajax source URL\n\t *//**\n\t * Set the Ajax URL. Note that this will set the URL for all tables in the\n\t * current context.\n\t *\n\t * @param {string} url URL to set.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url()', function ( url ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( url === undefined ) {\n\t\t\t// get\n\t\t\tif ( ctx.length === 0 ) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tctx = ctx[0];\n\t\n\t\t\treturn ctx.ajax ?\n\t\t\t\t$.isPlainObject( ctx.ajax ) ?\n\t\t\t\t\tctx.ajax.url :\n\t\t\t\t\tctx.ajax :\n\t\t\t\tctx.sAjaxSource;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( $.isPlainObject( settings.ajax ) ) {\n\t\t\t\tsettings.ajax.url = url;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsettings.ajax = url;\n\t\t\t}\n\t\t\t// No need to consider sAjaxSource here since DataTables gives priority\n\t\t\t// to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any\n\t\t\t// value of `sAjaxSource` redundant.\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Load data from the newly set Ajax URL. Note that this method is only\n\t * available when `ajax.url()` is used to set a URL. Additionally, this method\n\t * has the same effect as calling `ajax.reload()` but is provided for\n\t * convenience when setting a new URL. Like `ajax.reload()` it will\n\t * automatically redraw the table once the remote data has been loaded.\n\t *\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {\n\t\t// Same as a reload, but makes sense to present it for easy access after a\n\t\t// url change\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\t__reload( ctx, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t\n\tvar _selector_run = function ( type, selector, selectFn, settings, opts )\n\t{\n\t\tvar\n\t\t\tout = [], res,\n\t\t\ta, i, ien, j, jen,\n\t\t\tselectorType = typeof selector;\n\t\n\t\t// Can't just check for isArray here, as an API or jQuery instance might be\n\t\t// given with their array like look\n\t\tif ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {\n\t\t\tselector = [ selector ];\n\t\t}\n\t\n\t\tfor ( i=0, ien=selector.length ; i<ien ; i++ ) {\n\t\t\t// Only split on simple strings - complex expressions will be jQuery selectors\n\t\t\ta = selector[i] && selector[i].split && ! selector[i].match(/[\\[\\(:]/) ?\n\t\t\t\tselector[i].split(',') :\n\t\t\t\t[ selector[i] ];\n\t\n\t\t\tfor ( j=0, jen=a.length ; j<jen ; j++ ) {\n\t\t\t\tres = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );\n\t\n\t\t\t\tif ( res && res.length ) {\n\t\t\t\t\tout = out.concat( res );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// selector extensions\n\t\tvar ext = _ext.selector[ type ];\n\t\tif ( ext.length ) {\n\t\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\t\tout = ext[i]( settings, opts, out );\n\t\t\t}\n\t\t}\n\t\n\t\treturn _unique( out );\n\t};\n\t\n\t\n\tvar _selector_opts = function ( opts )\n\t{\n\t\tif ( ! opts ) {\n\t\t\topts = {};\n\t\t}\n\t\n\t\t// Backwards compatibility for 1.9- which used the terminology filter rather\n\t\t// than search\n\t\tif ( opts.filter && opts.search === undefined ) {\n\t\t\topts.search = opts.filter;\n\t\t}\n\t\n\t\treturn $.extend( {\n\t\t\tsearch: 'none',\n\t\t\torder: 'current',\n\t\t\tpage: 'all'\n\t\t}, opts );\n\t};\n\t\n\t\n\tvar _selector_first = function ( inst )\n\t{\n\t\t// Reduce the API instance to the first item found\n\t\tfor ( var i=0, ien=inst.length ; i<ien ; i++ ) {\n\t\t\tif ( inst[i].length > 0 ) {\n\t\t\t\t// Assign the first element to the first item in the instance\n\t\t\t\t// and truncate the instance and context\n\t\t\t\tinst[0] = inst[i];\n\t\t\t\tinst[0].length = 1;\n\t\t\t\tinst.length = 1;\n\t\t\t\tinst.context = [ inst.context[i] ];\n\t\n\t\t\t\treturn inst;\n\t\t\t}\n\t\t}\n\t\n\t\t// Not found - return an empty instance\n\t\tinst.length = 0;\n\t\treturn inst;\n\t};\n\t\n\t\n\tvar _selector_row_indexes = function ( settings, opts )\n\t{\n\t\tvar\n\t\t\ti, ien, tmp, a=[],\n\t\t\tdisplayFiltered = settings.aiDisplay,\n\t\t\tdisplayMaster = settings.aiDisplayMaster;\n\t\n\t\tvar\n\t\t\tsearch = opts.search,  // none, applied, removed\n\t\t\torder  = opts.order,   // applied, current, index (original - compatibility with 1.9)\n\t\t\tpage   = opts.page;    // all, current\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t// In server-side processing mode, most options are irrelevant since\n\t\t\t// rows not shown don't exist and the index order is the applied order\n\t\t\t// Removed is a special case - for consistency just return an empty\n\t\t\t// array\n\t\t\treturn search === 'removed' ?\n\t\t\t\t[] :\n\t\t\t\t_range( 0, displayMaster.length );\n\t\t}\n\t\telse if ( page == 'current' ) {\n\t\t\t// Current page implies that order=current and fitler=applied, since it is\n\t\t\t// fairly senseless otherwise, regardless of what order and search actually\n\t\t\t// are\n\t\t\tfor ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {\n\t\t\t\ta.push( displayFiltered[i] );\n\t\t\t}\n\t\t}\n\t\telse if ( order == 'current' || order == 'applied' ) {\n\t\t\tif ( search == 'none') {\n\t\t\t\ta = displayMaster.slice();\n\t\t\t}\n\t\t\telse if ( search == 'applied' ) {\n\t\t\t\ta = displayFiltered.slice();\n\t\t\t}\n\t\t\telse if ( search == 'removed' ) {\n\t\t\t\t// O(n+m) solution by creating a hash map\n\t\t\t\tvar displayFilteredMap = {};\n\t\n\t\t\t\tfor ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) {\n\t\t\t\t\tdisplayFilteredMap[displayFiltered[i]] = null;\n\t\t\t\t}\n\t\n\t\t\t\ta = $.map( displayMaster, function (el) {\n\t\t\t\t\treturn ! displayFilteredMap.hasOwnProperty(el) ?\n\t\t\t\t\t\tel :\n\t\t\t\t\t\tnull;\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\telse if ( order == 'index' || order == 'original' ) {\n\t\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tif ( search == 'none' ) {\n\t\t\t\t\ta.push( i );\n\t\t\t\t}\n\t\t\t\telse { // applied | removed\n\t\t\t\t\ttmp = $.inArray( i, displayFiltered );\n\t\n\t\t\t\t\tif ((tmp === -1 && search == 'removed') ||\n\t\t\t\t\t\t(tmp >= 0   && search == 'applied') )\n\t\t\t\t\t{\n\t\t\t\t\t\ta.push( i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn a;\n\t};\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Rows\n\t *\n\t * {}          - no selector - use all available rows\n\t * {integer}   - row aoData index\n\t * {node}      - TR node\n\t * {string}    - jQuery selector to apply to the TR elements\n\t * {array}     - jQuery array of nodes, or simply an array of TR nodes\n\t *\n\t */\n\tvar __row_selector = function ( settings, selector, opts )\n\t{\n\t\tvar rows;\n\t\tvar run = function ( sel ) {\n\t\t\tvar selInt = _intVal( sel );\n\t\t\tvar i, ien;\n\t\t\tvar aoData = settings.aoData;\n\t\n\t\t\t// Short cut - selector is a number and no options provided (default is\n\t\t\t// all records, so no need to check if the index is in there, since it\n\t\t\t// must be - dev error if the index doesn't exist).\n\t\t\tif ( selInt !== null && ! opts ) {\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\n\t\t\tif ( ! rows ) {\n\t\t\t\trows = _selector_row_indexes( settings, opts );\n\t\t\t}\n\t\n\t\t\tif ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {\n\t\t\t\t// Selector - integer\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\t\telse if ( sel === null || sel === undefined || sel === '' ) {\n\t\t\t\t// Selector - none\n\t\t\t\treturn rows;\n\t\t\t}\n\t\n\t\t\t// Selector - function\n\t\t\tif ( typeof sel === 'function' ) {\n\t\t\t\treturn $.map( rows, function (idx) {\n\t\t\t\t\tvar row = aoData[ idx ];\n\t\t\t\t\treturn sel( idx, row._aData, row.nTr ) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Selector - node\n\t\t\tif ( sel.nodeName ) {\n\t\t\t\tvar rowIdx = sel._DT_RowIndex;  // Property added by DT for fast lookup\n\t\t\t\tvar cellIdx = sel._DT_CellIndex;\n\t\n\t\t\t\tif ( rowIdx !== undefined ) {\n\t\t\t\t\t// Make sure that the row is actually still present in the table\n\t\t\t\t\treturn aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?\n\t\t\t\t\t\t[ rowIdx ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t\telse if ( cellIdx ) {\n\t\t\t\t\treturn aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel ?\n\t\t\t\t\t\t[ cellIdx.row ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tvar host = $(sel).closest('*[data-dt-row]');\n\t\t\t\t\treturn host.length ?\n\t\t\t\t\t\t[ host.data('dt-row') ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// ID selector. Want to always be able to select rows by id, regardless\n\t\t\t// of if the tr element has been created or not, so can't rely upon\n\t\t\t// jQuery here - hence a custom implementation. This does not match\n\t\t\t// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,\n\t\t\t// but to select it using a CSS selector engine (like Sizzle or\n\t\t\t// querySelect) it would need to need to be escaped for some characters.\n\t\t\t// DataTables simplifies this for row selectors since you can select\n\t\t\t// only a row. A # indicates an id any anything that follows is the id -\n\t\t\t// unescaped.\n\t\t\tif ( typeof sel === 'string' && sel.charAt(0) === '#' ) {\n\t\t\t\t// get row index from id\n\t\t\t\tvar rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];\n\t\t\t\tif ( rowObj !== undefined ) {\n\t\t\t\t\treturn [ rowObj.idx ];\n\t\t\t\t}\n\t\n\t\t\t\t// need to fall through to jQuery in case there is DOM id that\n\t\t\t\t// matches\n\t\t\t}\n\t\t\t\n\t\t\t// Get nodes in the order from the `rows` array with null values removed\n\t\t\tvar nodes = _removeEmpty(\n\t\t\t\t_pluck_order( settings.aoData, rows, 'nTr' )\n\t\t\t);\n\t\n\t\t\t// Selector - jQuery selector string, array of nodes or jQuery object/\n\t\t\t// As jQuery's .filter() allows jQuery objects to be passed in filter,\n\t\t\t// it also allows arrays, so this will cope with all three options\n\t\t\treturn $(nodes)\n\t\t\t\t.filter( sel )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn this._DT_RowIndex;\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\t};\n\t\n\t\treturn _selector_run( 'row', selector, run, settings, opts );\n\t};\n\t\n\t\n\t_api_register( 'rows()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __row_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in __row_selector?\n\t\tinst.selector.rows = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_register( 'rows().nodes()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn settings.aoData[ row ].nTr || undefined;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'rows().data()', function () {\n\t\treturn this.iterator( true, 'rows', function ( settings, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, '_aData' );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\tvar r = settings.aoData[ row ];\n\t\t\treturn type === 'search' ? r._aFilterData : r._aSortData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\t_fnInvalidate( settings, row, src );\n\t\t} );\n\t} );\n\t\n\t_api_registerPlural( 'rows().indexes()', 'row().index()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn row;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {\n\t\tvar a = [];\n\t\tvar context = this.context;\n\t\n\t\t// `iterator` will drop undefined values, but in this case we want them\n\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\tfor ( var j=0, jen=this[i].length ; j<jen ; j++ ) {\n\t\t\t\tvar id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );\n\t\t\t\ta.push( (hash === true ? '#' : '' )+ id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn new _Api( context, a );\n\t} );\n\t\n\t_api_registerPlural( 'rows().remove()', 'row().remove()', function () {\n\t\tvar that = this;\n\t\n\t\tthis.iterator( 'row', function ( settings, row, thatIdx ) {\n\t\t\tvar data = settings.aoData;\n\t\t\tvar rowData = data[ row ];\n\t\t\tvar i, ien, j, jen;\n\t\t\tvar loopRow, loopCells;\n\t\n\t\t\tdata.splice( row, 1 );\n\t\n\t\t\t// Update the cached indexes\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\tloopRow = data[i];\n\t\t\t\tloopCells = loopRow.anCells;\n\t\n\t\t\t\t// Rows\n\t\t\t\tif ( loopRow.nTr !== null ) {\n\t\t\t\t\tloopRow.nTr._DT_RowIndex = i;\n\t\t\t\t}\n\t\n\t\t\t\t// Cells\n\t\t\t\tif ( loopCells !== null ) {\n\t\t\t\t\tfor ( j=0, jen=loopCells.length ; j<jen ; j++ ) {\n\t\t\t\t\t\tloopCells[j]._DT_CellIndex.row = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Delete from the display arrays\n\t\t\t_fnDeleteIndex( settings.aiDisplayMaster, row );\n\t\t\t_fnDeleteIndex( settings.aiDisplay, row );\n\t\t\t_fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes\n\t\n\t\t\t// For server-side processing tables - subtract the deleted row from the count\n\t\t\tif ( settings._iRecordsDisplay > 0 ) {\n\t\t\t\tsettings._iRecordsDisplay--;\n\t\t\t}\n\t\n\t\t\t// Check for an 'overflow' they case for displaying the table\n\t\t\t_fnLengthOverflow( settings );\n\t\n\t\t\t// Remove the row's ID reference if there is one\n\t\t\tvar id = settings.rowIdFn( rowData._aData );\n\t\t\tif ( id !== undefined ) {\n\t\t\t\tdelete settings.aIds[ id ];\n\t\t\t}\n\t\t} );\n\t\n\t\tthis.iterator( 'table', function ( settings ) {\n\t\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tsettings.aoData[i].idx = i;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'rows.add()', function ( rows ) {\n\t\tvar newRows = this.iterator( 'table', function ( settings ) {\n\t\t\t\tvar row, i, ien;\n\t\t\t\tvar out = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\t\t\tout.push( _fnAddTr( settings, row )[0] );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tout.push( _fnAddData( settings, row ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn out;\n\t\t\t}, 1 );\n\t\n\t\t// Return an Api.rows() extended instance, so rows().nodes() etc can be used\n\t\tvar modRows = this.rows( -1 );\n\t\tmodRows.pop();\n\t\t$.merge( modRows, newRows );\n\t\n\t\treturn modRows;\n\t} );\n\t\n\t\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( 'row()', function ( selector, opts ) {\n\t\treturn _selector_first( this.rows( selector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'row().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._aData :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\tvar row = ctx[0].aoData[ this[0] ];\n\t\trow._aData = data;\n\t\n\t\t// If the DOM has an id, and the data source is an array\n\t\tif ( $.isArray( data ) && row.nTr.id ) {\n\t\t\t_fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );\n\t\t}\n\t\n\t\t// Automatically invalidate\n\t\t_fnInvalidate( ctx[0], this[0], 'data' );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'row().node()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\treturn ctx.length && this.length ?\n\t\t\tctx[0].aoData[ this[0] ].nTr || null :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'row.add()', function ( row ) {\n\t\t// Allow a jQuery object to be passed in - only a single row is added from\n\t\t// it though - the first element in the set\n\t\tif ( row instanceof $ && row.length ) {\n\t\t\trow = row[0];\n\t\t}\n\t\n\t\tvar rows = this.iterator( 'table', function ( settings ) {\n\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\treturn _fnAddTr( settings, row )[0];\n\t\t\t}\n\t\t\treturn _fnAddData( settings, row );\n\t\t} );\n\t\n\t\t// Return an Api.rows() extended instance, with the newly added row selected\n\t\treturn this.row( rows[0] );\n\t} );\n\t\n\t\n\t\n\tvar __details_add = function ( ctx, row, data, klass )\n\t{\n\t\t// Convert to array of TR elements\n\t\tvar rows = [];\n\t\tvar addRow = function ( r, k ) {\n\t\t\t// Recursion to allow for arrays of jQuery objects\n\t\t\tif ( $.isArray( r ) || r instanceof $ ) {\n\t\t\t\tfor ( var i=0, ien=r.length ; i<ien ; i++ ) {\n\t\t\t\t\taddRow( r[i], k );\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If we get a TR element, then just add it directly - up to the dev\n\t\t\t// to add the correct number of columns etc\n\t\t\tif ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {\n\t\t\t\trows.push( r );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Otherwise create a row with a wrapper\n\t\t\t\tvar created = $('<tr><td/></tr>').addClass( k );\n\t\t\t\t$('td', created)\n\t\t\t\t\t.addClass( k )\n\t\t\t\t\t.html( r )\n\t\t\t\t\t[0].colSpan = _fnVisbleColumns( ctx );\n\t\n\t\t\t\trows.push( created[0] );\n\t\t\t}\n\t\t};\n\t\n\t\taddRow( data, klass );\n\t\n\t\tif ( row._details ) {\n\t\t\trow._details.detach();\n\t\t}\n\t\n\t\trow._details = $(rows);\n\t\n\t\t// If the children were already shown, that state should be retained\n\t\tif ( row._detailsShow ) {\n\t\t\trow._details.insertAfter( row.nTr );\n\t\t}\n\t};\n\t\n\t\n\tvar __details_remove = function ( api, idx )\n\t{\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length ) {\n\t\t\tvar row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];\n\t\n\t\t\tif ( row && row._details ) {\n\t\t\t\trow._details.remove();\n\t\n\t\t\t\trow._detailsShow = undefined;\n\t\t\t\trow._details = undefined;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_display = function ( api, show ) {\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length && api.length ) {\n\t\t\tvar row = ctx[0].aoData[ api[0] ];\n\t\n\t\t\tif ( row._details ) {\n\t\t\t\trow._detailsShow = show;\n\t\n\t\t\t\tif ( show ) {\n\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\trow._details.detach();\n\t\t\t\t}\n\t\n\t\t\t\t__details_events( ctx[0] );\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_events = function ( settings )\n\t{\n\t\tvar api = new _Api( settings );\n\t\tvar namespace = '.dt.DT_details';\n\t\tvar drawEvent = 'draw'+namespace;\n\t\tvar colvisEvent = 'column-visibility'+namespace;\n\t\tvar destroyEvent = 'destroy'+namespace;\n\t\tvar data = settings.aoData;\n\t\n\t\tapi.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );\n\t\n\t\tif ( _pluck( data, '_details' ).length > 0 ) {\n\t\t\t// On each draw, insert the required elements into the document\n\t\t\tapi.on( drawEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tapi.rows( {page:'current'} ).eq(0).each( function (idx) {\n\t\t\t\t\t// Internal data grab\n\t\t\t\t\tvar row = data[ idx ];\n\t\n\t\t\t\t\tif ( row._detailsShow ) {\n\t\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\n\t\t\t// Column visibility change - update the colspan\n\t\t\tapi.on( colvisEvent, function ( e, ctx, idx, vis ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t// Update the colspan for the details rows (note, only if it already has\n\t\t\t\t// a colspan)\n\t\t\t\tvar row, visible = _fnVisbleColumns( ctx );\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = data[i];\n\t\n\t\t\t\t\tif ( row._details ) {\n\t\t\t\t\t\trow._details.children('td[colspan]').attr('colspan', visible );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\t// Table destroyed - nuke any child rows\n\t\t\tapi.on( destroyEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( data[i]._details ) {\n\t\t\t\t\t\t__details_remove( api, i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t// Strings for the method names to help minification\n\tvar _emp = '';\n\tvar _child_obj = _emp+'row().child';\n\tvar _child_mth = _child_obj+'()';\n\t\n\t// data can be:\n\t//  tr\n\t//  string\n\t//  jQuery or array of any of the above\n\t_api_register( _child_mth, function ( data, klass ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._details :\n\t\t\t\tundefined;\n\t\t}\n\t\telse if ( data === true ) {\n\t\t\t// show\n\t\t\tthis.child.show();\n\t\t}\n\t\telse if ( data === false ) {\n\t\t\t// remove\n\t\t\t__details_remove( this );\n\t\t}\n\t\telse if ( ctx.length && this.length ) {\n\t\t\t// set\n\t\t\t__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );\n\t\t}\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.show()',\n\t\t_child_mth+'.show()' // only when `child()` was called with parameters (without\n\t], function ( show ) {   // it returns an object and this method is not executed)\n\t\t__details_display( this, true );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.hide()',\n\t\t_child_mth+'.hide()' // only when `child()` was called with parameters (without\n\t], function () {         // it returns an object and this method is not executed)\n\t\t__details_display( this, false );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.remove()',\n\t\t_child_mth+'.remove()' // only when `child()` was called with parameters (without\n\t], function () {           // it returns an object and this method is not executed)\n\t\t__details_remove( this );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( _child_obj+'.isShown()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length && this.length ) {\n\t\t\t// _detailsShown as false or undefined will fall through to return false\n\t\t\treturn ctx[0].aoData[ this[0] ]._detailsShow || false;\n\t\t}\n\t\treturn false;\n\t} );\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Columns\n\t *\n\t * {integer}           - column index (>=0 count from left, <0 count from right)\n\t * \"{integer}:visIdx\"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)\n\t * \"{integer}:visible\" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)\n\t * \"{string}:name\"     - column name\n\t * \"{string}\"          - jQuery selector on column header nodes\n\t *\n\t */\n\t\n\t// can be an array of these items, comma separated list, or an array of comma\n\t// separated lists\n\t\n\tvar __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;\n\t\n\t\n\t// r1 and r2 are redundant - but it means that the parameters match for the\n\t// iterator callback in columns().data()\n\tvar __columnData = function ( settings, column, r1, r2, rows ) {\n\t\tvar a = [];\n\t\tfor ( var row=0, ien=rows.length ; row<ien ; row++ ) {\n\t\t\ta.push( _fnGetCellData( settings, rows[row], column ) );\n\t\t}\n\t\treturn a;\n\t};\n\t\n\t\n\tvar __column_selector = function ( settings, selector, opts )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tnames = _pluck( columns, 'sName' ),\n\t\t\tnodes = _pluck( columns, 'nTh' );\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar selInt = _intVal( s );\n\t\n\t\t\t// Selector - all\n\t\t\tif ( s === '' ) {\n\t\t\t\treturn _range( columns.length );\n\t\t\t}\n\t\n\t\t\t// Selector - index\n\t\t\tif ( selInt !== null ) {\n\t\t\t\treturn [ selInt >= 0 ?\n\t\t\t\t\tselInt : // Count from left\n\t\t\t\t\tcolumns.length + selInt // Count from right (+ because its a negative value)\n\t\t\t\t];\n\t\t\t}\n\t\n\t\t\t// Selector = function\n\t\t\tif ( typeof s === 'function' ) {\n\t\t\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\n\t\t\t\treturn $.map( columns, function (col, idx) {\n\t\t\t\t\treturn s(\n\t\t\t\t\t\t\tidx,\n\t\t\t\t\t\t\t__columnData( settings, idx, 0, 0, rows ),\n\t\t\t\t\t\t\tnodes[ idx ]\n\t\t\t\t\t\t) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// jQuery or string selector\n\t\t\tvar match = typeof s === 'string' ?\n\t\t\t\ts.match( __re_column_selector ) :\n\t\t\t\t'';\n\t\n\t\t\tif ( match ) {\n\t\t\t\tswitch( match[2] ) {\n\t\t\t\t\tcase 'visIdx':\n\t\t\t\t\tcase 'visible':\n\t\t\t\t\t\tvar idx = parseInt( match[1], 10 );\n\t\t\t\t\t\t// Visible index given, convert to column index\n\t\t\t\t\t\tif ( idx < 0 ) {\n\t\t\t\t\t\t\t// Counting from the right\n\t\t\t\t\t\t\tvar visColumns = $.map( columns, function (col,i) {\n\t\t\t\t\t\t\t\treturn col.bVisible ? i : null;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\treturn [ visColumns[ visColumns.length + idx ] ];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Counting from the left\n\t\t\t\t\t\treturn [ _fnVisibleToColumnIndex( settings, idx ) ];\n\t\n\t\t\t\t\tcase 'name':\n\t\t\t\t\t\t// match by name. `names` is column index complete and in order\n\t\t\t\t\t\treturn $.map( names, function (name, i) {\n\t\t\t\t\t\t\treturn name === match[1] ? i : null;\n\t\t\t\t\t\t} );\n\t\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Cell in the table body\n\t\t\tif ( s.nodeName && s._DT_CellIndex ) {\n\t\t\t\treturn [ s._DT_CellIndex.column ];\n\t\t\t}\n\t\n\t\t\t// jQuery selector on the TH elements for the columns\n\t\t\tvar jqResult = $( nodes )\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn $.inArray( this, nodes ); // `nodes` is column index complete and in order\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise a node which might have a `dt-column` data attribute, or be\n\t\t\t// a child or such an element\n\t\t\tvar host = $(s).closest('*[data-dt-column]');\n\t\t\treturn host.length ?\n\t\t\t\t[ host.data('dt-column') ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'column', selector, run, settings, opts );\n\t};\n\t\n\t\n\tvar __setColumnVis = function ( settings, column, vis ) {\n\t\tvar\n\t\t\tcols = settings.aoColumns,\n\t\t\tcol  = cols[ column ],\n\t\t\tdata = settings.aoData,\n\t\t\trow, cells, i, ien, tr;\n\t\n\t\t// Get\n\t\tif ( vis === undefined ) {\n\t\t\treturn col.bVisible;\n\t\t}\n\t\n\t\t// Set\n\t\t// No change\n\t\tif ( col.bVisible === vis ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( vis ) {\n\t\t\t// Insert column\n\t\t\t// Need to decide if we should use appendChild or insertBefore\n\t\t\tvar insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );\n\t\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\ttr = data[i].nTr;\n\t\t\t\tcells = data[i].anCells;\n\t\n\t\t\t\tif ( tr ) {\n\t\t\t\t\t// insertBefore can act like appendChild if 2nd arg is null\n\t\t\t\t\ttr.insertBefore( cells[ column ], cells[ insertBefore ] || null );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Remove column\n\t\t\t$( _pluck( settings.aoData, 'anCells', column ) ).detach();\n\t\t}\n\t\n\t\t// Common actions\n\t\tcol.bVisible = vis;\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t// Update colspan for no records display. Child rows and extensions will use their own\n\t\t// listeners to do this - only need to update the empty table item here\n\t\tif ( ! settings.aiDisplay.length ) {\n\t\t\t$(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));\n\t\t}\n\t\n\t\t_fnSaveState( settings );\n\t};\n\t\n\t\n\t_api_register( 'columns()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __column_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in _row_selector?\n\t\tinst.selector.cols = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTh;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTf;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().data()', 'column().data()', function () {\n\t\treturn this.iterator( 'column-rows', __columnData, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].mData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows,\n\t\t\t\ttype === 'search' ? '_aFilterData' : '_aSortData', column\n\t\t\t);\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, 'anCells', column ) ;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {\n\t\tvar ret = this.iterator( 'column', function ( settings, column ) {\n\t\t\tif ( vis === undefined ) {\n\t\t\t\treturn settings.aoColumns[ column ].bVisible;\n\t\t\t} // else\n\t\t\t__setColumnVis( settings, column, vis );\n\t\t} );\n\t\n\t\t// Group the column visibility changes\n\t\tif ( vis !== undefined ) {\n\t\t\t// Second loop once the first is done for events\n\t\t\tthis.iterator( 'column', function ( settings, column ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );\n\t\t\t} );\n\t\n\t\t\tif ( calc === undefined || calc ) {\n\t\t\t\tthis.columns.adjust();\n\t\t\t}\n\t\t}\n\t\n\t\treturn ret;\n\t} );\n\t\n\t_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn type === 'visible' ?\n\t\t\t\t_fnColumnIndexToVisible( settings, column ) :\n\t\t\t\tcolumn;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'columns.adjust()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'column.index()', function ( type, idx ) {\n\t\tif ( this.context.length !== 0 ) {\n\t\t\tvar ctx = this.context[0];\n\t\n\t\t\tif ( type === 'fromVisible' || type === 'toData' ) {\n\t\t\t\treturn _fnVisibleToColumnIndex( ctx, idx );\n\t\t\t}\n\t\t\telse if ( type === 'fromData' || type === 'toVisible' ) {\n\t\t\t\treturn _fnColumnIndexToVisible( ctx, idx );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t_api_register( 'column()', function ( selector, opts ) {\n\t\treturn _selector_first( this.columns( selector, opts ) );\n\t} );\n\t\n\t\n\t\n\tvar __cell_selector = function ( settings, selector, opts )\n\t{\n\t\tvar data = settings.aoData;\n\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\tvar cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );\n\t\tvar allCells = $( [].concat.apply([], cells) );\n\t\tvar row;\n\t\tvar columns = settings.aoColumns.length;\n\t\tvar a, i, ien, j, o, host;\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar fnSelector = typeof s === 'function';\n\t\n\t\t\tif ( s === null || s === undefined || fnSelector ) {\n\t\t\t\t// All cells and function selectors\n\t\t\t\ta = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tfor ( j=0 ; j<columns ; j++ ) {\n\t\t\t\t\t\to = {\n\t\t\t\t\t\t\trow: row,\n\t\t\t\t\t\t\tcolumn: j\n\t\t\t\t\t\t};\n\t\n\t\t\t\t\t\tif ( fnSelector ) {\n\t\t\t\t\t\t\t// Selector - function\n\t\t\t\t\t\t\thost = data[ row ];\n\t\n\t\t\t\t\t\t\tif ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {\n\t\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Selector - all\n\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn a;\n\t\t\t}\n\t\t\t\n\t\t\t// Selector - index\n\t\t\tif ( $.isPlainObject( s ) ) {\n\t\t\t\t// Valid cell index and its in the array of selectable rows\n\t\t\t\treturn s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ?\n\t\t\t\t\t[s] :\n\t\t\t\t\t[];\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery filtered cells\n\t\t\tvar jqResult = allCells\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function (i, el) {\n\t\t\t\t\treturn { // use a new object, in case someone changes the values\n\t\t\t\t\t\trow:    el._DT_CellIndex.row,\n\t\t\t\t\t\tcolumn: el._DT_CellIndex.column\n\t \t\t\t\t};\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise the selector is a node, and there is one last option - the\n\t\t\t// element might be a child of an element which has dt-row and dt-column\n\t\t\t// data attributes\n\t\t\thost = $(s).closest('*[data-dt-row]');\n\t\t\treturn host.length ?\n\t\t\t\t[ {\n\t\t\t\t\trow: host.data('dt-row'),\n\t\t\t\t\tcolumn: host.data('dt-column')\n\t\t\t\t} ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'cell', selector, run, settings, opts );\n\t};\n\t\n\t\n\t\n\t\n\t_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {\n\t\t// Argument shifting\n\t\tif ( $.isPlainObject( rowSelector ) ) {\n\t\t\t// Indexes\n\t\t\tif ( rowSelector.row === undefined ) {\n\t\t\t\t// Selector options in first parameter\n\t\t\t\topts = rowSelector;\n\t\t\t\trowSelector = null;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Cell index objects in first parameter\n\t\t\t\topts = columnSelector;\n\t\t\t\tcolumnSelector = null;\n\t\t\t}\n\t\t}\n\t\tif ( $.isPlainObject( columnSelector ) ) {\n\t\t\topts = columnSelector;\n\t\t\tcolumnSelector = null;\n\t\t}\n\t\n\t\t// Cell selector\n\t\tif ( columnSelector === null || columnSelector === undefined ) {\n\t\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t\treturn __cell_selector( settings, rowSelector, _selector_opts( opts ) );\n\t\t\t} );\n\t\t}\n\t\n\t\t// Row + column selector\n\t\tvar columns = this.columns( columnSelector );\n\t\tvar rows = this.rows( rowSelector );\n\t\tvar a, i, ien, j, jen;\n\t\n\t\tthis.iterator( 'table', function ( settings, idx ) {\n\t\t\ta = [];\n\t\n\t\t\tfor ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {\n\t\t\t\tfor ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {\n\t\t\t\t\ta.push( {\n\t\t\t\t\t\trow:    rows[idx][i],\n\t\t\t\t\t\tcolumn: columns[idx][j]\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}, 1 );\n\t\n\t    // Now pass through the cell selector for options\n\t    var cells = this.cells( a, opts );\n\t\n\t\t$.extend( cells.selector, {\n\t\t\tcols: columnSelector,\n\t\t\trows: rowSelector,\n\t\t\topts: opts\n\t\t} );\n\t\n\t\treturn cells;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\tvar data = settings.aoData[ row ];\n\t\n\t\t\treturn data && data.anCells ?\n\t\t\t\tdata.anCells[ column ] :\n\t\t\t\tundefined;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_register( 'cells().data()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {\n\t\ttype = type === 'search' ? '_aFilterData' : '_aSortData';\n\t\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn settings.aoData[ row ][ type ][ column ];\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column, type );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn {\n\t\t\t\trow: row,\n\t\t\t\tcolumn: column,\n\t\t\t\tcolumnVisible: _fnColumnIndexToVisible( settings, column )\n\t\t\t};\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\t_fnInvalidate( settings, row, src, column );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {\n\t\treturn _selector_first( this.cells( rowSelector, columnSelector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'cell().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\tvar cell = this[0];\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && cell.length ?\n\t\t\t\t_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\t_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );\n\t\t_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get current ordering (sorting) that has been applied to the table.\n\t *\n\t * @returns {array} 2D array containing the sorting information for the first\n\t *   table in the current context. Each element in the parent array represents\n\t *   a column being sorted upon (i.e. multi-sorting with two columns would have\n\t *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is\n\t *   the column index that the sorting condition applies to, the second is the\n\t *   direction of the sort (`desc` or `asc`) and, optionally, the third is the\n\t *   index of the sorting order from the `column.sorting` initialisation array.\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {integer} order Column index to sort upon.\n\t * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 1D array of sorting information to be applied.\n\t * @param {array} [...] Optional additional sorting conditions\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 2D array of sorting information to be applied.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order()', function ( order, dir ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( order === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].aaSorting :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\tif ( typeof order === 'number' ) {\n\t\t\t// Simple column / direction passed in\n\t\t\torder = [ [ order, dir ] ];\n\t\t}\n\t\telse if ( order.length && ! $.isArray( order[0] ) ) {\n\t\t\t// Arguments passed in (list of 1D arrays)\n\t\t\torder = Array.prototype.slice.call( arguments );\n\t\t}\n\t\t// otherwise a 2D array was passed in\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSorting = order.slice();\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Attach a sort listener to an element for a given column\n\t *\n\t * @param {node|jQuery|string} node Identifier for the element(s) to attach the\n\t *   listener to. This can take the form of a single DOM node, a jQuery\n\t *   collection of nodes or a jQuery selector which will identify the node(s).\n\t * @param {integer} column the column that a click on this node will sort on\n\t * @param {function} [callback] callback function when sort is run\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order.listener()', function ( node, column, callback ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSortAttachListener( settings, node, column, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'order.fixed()', function ( set ) {\n\t\tif ( ! set ) {\n\t\t\tvar ctx = this.context;\n\t\t\tvar fixed = ctx.length ?\n\t\t\t\tctx[0].aaSortingFixed :\n\t\t\t\tundefined;\n\t\n\t\t\treturn $.isArray( fixed ) ?\n\t\t\t\t{ pre: fixed } :\n\t\t\t\tfixed;\n\t\t}\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSortingFixed = $.extend( true, {}, set );\n\t\t} );\n\t} );\n\t\n\t\n\t// Order by the selected column(s)\n\t_api_register( [\n\t\t'columns().order()',\n\t\t'column().order()'\n\t], function ( dir ) {\n\t\tvar that = this;\n\t\n\t\treturn this.iterator( 'table', function ( settings, i ) {\n\t\t\tvar sort = [];\n\t\n\t\t\t$.each( that[i], function (j, col) {\n\t\t\t\tsort.push( [ col, dir ] );\n\t\t\t} );\n\t\n\t\t\tsettings.aaSorting = sort;\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'search()', function ( input, regex, smart, caseInsen ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( input === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].oPreviousSearch.sSearch :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t_fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {\n\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t} ), 1 );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural(\n\t\t'columns().search()',\n\t\t'column().search()',\n\t\tfunction ( input, regex, smart, caseInsen ) {\n\t\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\t\tvar preSearch = settings.aoPreSearchCols;\n\t\n\t\t\t\tif ( input === undefined ) {\n\t\t\t\t\t// get\n\t\t\t\t\treturn preSearch[ column ].sSearch;\n\t\t\t\t}\n\t\n\t\t\t\t// set\n\t\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t$.extend( preSearch[ column ], {\n\t\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t\t} );\n\t\n\t\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch, 1 );\n\t\t\t} );\n\t\t}\n\t);\n\t\n\t/*\n\t * State API methods\n\t */\n\t\n\t_api_register( 'state()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oSavedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t// Save an empty object\n\t\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, {} );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'state.loaded()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oLoadedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.save()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSaveState( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Provide a common method for plug-ins to check the version of DataTables being\n\t * used, in order to ensure compatibility.\n\t *\n\t *  @param {string} version Version string to check for, in the format \"X.Y.Z\".\n\t *    Note that the formats \"X\" and \"X.Y\" are also acceptable.\n\t *  @returns {boolean} true if this version of DataTables is greater or equal to\n\t *    the required version, or false if this version of DataTales is not\n\t *    suitable\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );\n\t */\n\tDataTable.versionCheck = DataTable.fnVersionCheck = function( version )\n\t{\n\t\tvar aThis = DataTable.version.split('.');\n\t\tvar aThat = version.split('.');\n\t\tvar iThis, iThat;\n\t\n\t\tfor ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {\n\t\t\tiThis = parseInt( aThis[i], 10 ) || 0;\n\t\t\tiThat = parseInt( aThat[i], 10 ) || 0;\n\t\n\t\t\t// Parts are the same, keep comparing\n\t\t\tif (iThis === iThat) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\t// Parts are different, return immediately\n\t\t\treturn iThis > iThat;\n\t\t}\n\t\n\t\treturn true;\n\t};\n\t\n\t\n\t/**\n\t * Check if a `<table>` node is a DataTable table already or not.\n\t *\n\t *  @param {node|jquery|string} table Table node, jQuery object or jQuery\n\t *      selector for the table to test. Note that if more than more than one\n\t *      table is passed on, only the first will be checked\n\t *  @returns {boolean} true the table given is a DataTable, or false otherwise\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {\n\t *      $('#example').dataTable();\n\t *    }\n\t */\n\tDataTable.isDataTable = DataTable.fnIsDataTable = function ( table )\n\t{\n\t\tvar t = $(table).get(0);\n\t\tvar is = false;\n\t\n\t\tif ( table instanceof DataTable.Api ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\t$.each( DataTable.settings, function (i, o) {\n\t\t\tvar head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;\n\t\t\tvar foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;\n\t\n\t\t\tif ( o.nTable === t || head === t || foot === t ) {\n\t\t\t\tis = true;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn is;\n\t};\n\t\n\t\n\t/**\n\t * Get all DataTable tables that have been initialised - optionally you can\n\t * select to get only currently visible tables.\n\t *\n\t *  @param {boolean} [visible=false] Flag to indicate if you want all (default)\n\t *    or visible tables only.\n\t *  @returns {array} Array of `table` nodes (not DataTable instances) which are\n\t *    DataTables\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    $.each( $.fn.dataTable.tables(true), function () {\n\t *      $(table).DataTable().columns.adjust();\n\t *    } );\n\t */\n\tDataTable.tables = DataTable.fnTables = function ( visible )\n\t{\n\t\tvar api = false;\n\t\n\t\tif ( $.isPlainObject( visible ) ) {\n\t\t\tapi = visible.api;\n\t\t\tvisible = visible.visible;\n\t\t}\n\t\n\t\tvar a = $.map( DataTable.settings, function (o) {\n\t\t\tif ( !visible || (visible && $(o.nTable).is(':visible')) ) {\n\t\t\t\treturn o.nTable;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn api ?\n\t\t\tnew _Api( a ) :\n\t\t\ta;\n\t};\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian notation. This is made public\n\t * for the extensions to provide the same ability as DataTables core to accept\n\t * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase\n\t * parameters.\n\t *\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t */\n\tDataTable.camelToHungarian = _fnCamelToHungarian;\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( '$()', function ( selector, opts ) {\n\t\tvar\n\t\t\trows   = this.rows( opts ).nodes(), // Get all rows\n\t\t\tjqRows = $(rows);\n\t\n\t\treturn $( [].concat(\n\t\t\tjqRows.filter( selector ).toArray(),\n\t\t\tjqRows.find( selector ).toArray()\n\t\t) );\n\t} );\n\t\n\t\n\t// jQuery functions to operate on the tables\n\t$.each( [ 'on', 'one', 'off' ], function (i, key) {\n\t\t_api_register( key+'()', function ( /* event, handler */ ) {\n\t\t\tvar args = Array.prototype.slice.call(arguments);\n\t\n\t\t\t// Add the `dt` namespace automatically if it isn't already present\n\t\t\targs[0] = $.map( args[0].split( /\\s/ ), function ( e ) {\n\t\t\t\treturn ! e.match(/\\.dt\\b/) ?\n\t\t\t\t\te+'.dt' :\n\t\t\t\t\te;\n\t\t\t\t} ).join( ' ' );\n\t\n\t\t\tvar inst = $( this.tables().nodes() );\n\t\t\tinst[key].apply( inst, args );\n\t\t\treturn this;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnClearTable( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'settings()', function () {\n\t\treturn new _Api( this.context, this.context );\n\t} );\n\t\n\t\n\t_api_register( 'init()', function () {\n\t\tvar ctx = this.context;\n\t\treturn ctx.length ? ctx[0].oInit : null;\n\t} );\n\t\n\t\n\t_api_register( 'data()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\treturn _pluck( settings.aoData, '_aData' );\n\t\t} ).flatten();\n\t} );\n\t\n\t\n\t_api_register( 'destroy()', function ( remove ) {\n\t\tremove = remove || false;\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tvar orig      = settings.nTableWrapper.parentNode;\n\t\t\tvar classes   = settings.oClasses;\n\t\t\tvar table     = settings.nTable;\n\t\t\tvar tbody     = settings.nTBody;\n\t\t\tvar thead     = settings.nTHead;\n\t\t\tvar tfoot     = settings.nTFoot;\n\t\t\tvar jqTable   = $(table);\n\t\t\tvar jqTbody   = $(tbody);\n\t\t\tvar jqWrapper = $(settings.nTableWrapper);\n\t\t\tvar rows      = $.map( settings.aoData, function (r) { return r.nTr; } );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Flag to note that the table is currently being destroyed - no action\n\t\t\t// should be taken\n\t\t\tsettings.bDestroying = true;\n\t\n\t\t\t// Fire off the destroy callbacks for plug-ins etc\n\t\t\t_fnCallbackFire( settings, \"aoDestroyCallback\", \"destroy\", [settings] );\n\t\n\t\t\t// If not being removed from the document, make all columns visible\n\t\t\tif ( ! remove ) {\n\t\t\t\tnew _Api( settings ).columns().visible( true );\n\t\t\t}\n\t\n\t\t\t// Blitz all `DT` namespaced events (these are internal events, the\n\t\t\t// lowercase, `dt` events are user subscribed and they are responsible\n\t\t\t// for removing them\n\t\t\tjqWrapper.off('.DT').find(':not(tbody *)').off('.DT');\n\t\t\t$(window).off('.DT-'+settings.sInstance);\n\t\n\t\t\t// When scrolling we had to break the table up - restore it\n\t\t\tif ( table != thead.parentNode ) {\n\t\t\t\tjqTable.children('thead').detach();\n\t\t\t\tjqTable.append( thead );\n\t\t\t}\n\t\n\t\t\tif ( tfoot && table != tfoot.parentNode ) {\n\t\t\t\tjqTable.children('tfoot').detach();\n\t\t\t\tjqTable.append( tfoot );\n\t\t\t}\n\t\n\t\t\tsettings.aaSorting = [];\n\t\t\tsettings.aaSortingFixed = [];\n\t\t\t_fnSortingClasses( settings );\n\t\n\t\t\t$( rows ).removeClass( settings.asStripeClasses.join(' ') );\n\t\n\t\t\t$('th, td', thead).removeClass( classes.sSortable+' '+\n\t\t\t\tclasses.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone\n\t\t\t);\n\t\n\t\t\t// Add the TR elements back into the table in their original order\n\t\t\tjqTbody.children().detach();\n\t\t\tjqTbody.append( rows );\n\t\n\t\t\t// Remove the DataTables generated nodes, events and classes\n\t\t\tvar removedMethod = remove ? 'remove' : 'detach';\n\t\t\tjqTable[ removedMethod ]();\n\t\t\tjqWrapper[ removedMethod ]();\n\t\n\t\t\t// If we need to reattach the table to the document\n\t\t\tif ( ! remove && orig ) {\n\t\t\t\t// insertBefore acts like appendChild if !arg[1]\n\t\t\t\torig.insertBefore( table, settings.nTableReinsertBefore );\n\t\n\t\t\t\t// Restore the width of the original table - was read from the style property,\n\t\t\t\t// so we can restore directly to that\n\t\t\t\tjqTable\n\t\t\t\t\t.css( 'width', settings.sDestroyWidth )\n\t\t\t\t\t.removeClass( classes.sTable );\n\t\n\t\t\t\t// If the were originally stripe classes - then we add them back here.\n\t\t\t\t// Note this is not fool proof (for example if not all rows had stripe\n\t\t\t\t// classes - but it's a good effort without getting carried away\n\t\t\t\tien = settings.asDestroyStripes.length;\n\t\n\t\t\t\tif ( ien ) {\n\t\t\t\t\tjqTbody.children().each( function (i) {\n\t\t\t\t\t\t$(this).addClass( settings.asDestroyStripes[i % ien] );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Remove the settings object from the settings array */\n\t\t\tvar idx = $.inArray( settings, DataTable.settings );\n\t\t\tif ( idx !== -1 ) {\n\t\t\t\tDataTable.settings.splice( idx, 1 );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t// Add the `every()` method for rows, columns and cells in a compact form\n\t$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {\n\t\t_api_register( type+'s().every()', function ( fn ) {\n\t\t\tvar opts = this.selector.opts;\n\t\t\tvar api = this;\n\t\n\t\t\treturn this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {\n\t\t\t\t// Rows and columns:\n\t\t\t\t//  arg1 - index\n\t\t\t\t//  arg2 - table counter\n\t\t\t\t//  arg3 - loop counter\n\t\t\t\t//  arg4 - undefined\n\t\t\t\t// Cells:\n\t\t\t\t//  arg1 - row index\n\t\t\t\t//  arg2 - column index\n\t\t\t\t//  arg3 - table counter\n\t\t\t\t//  arg4 - loop counter\n\t\t\t\tfn.call(\n\t\t\t\t\tapi[ type ](\n\t\t\t\t\t\targ1,\n\t\t\t\t\t\ttype==='cell' ? arg2 : opts,\n\t\t\t\t\t\ttype==='cell' ? opts : undefined\n\t\t\t\t\t),\n\t\t\t\t\targ1, arg2, arg3, arg4\n\t\t\t\t);\n\t\t\t} );\n\t\t} );\n\t} );\n\t\n\t\n\t// i18n method for extensions to be able to use the language object from the\n\t// DataTable\n\t_api_register( 'i18n()', function ( token, def, plural ) {\n\t\tvar ctx = this.context[0];\n\t\tvar resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );\n\t\n\t\tif ( resolved === undefined ) {\n\t\t\tresolved = def;\n\t\t}\n\t\n\t\tif ( plural !== undefined && $.isPlainObject( resolved ) ) {\n\t\t\tresolved = resolved[ plural ] !== undefined ?\n\t\t\t\tresolved[ plural ] :\n\t\t\t\tresolved._;\n\t\t}\n\t\n\t\treturn resolved.replace( '%d', plural ); // nb: plural might be undefined,\n\t} );\n\n\t/**\n\t * Version string for plug-ins to check compatibility. Allowed format is\n\t * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used\n\t * only for non-release builds. See http://semver.org/ for more information.\n\t *  @member\n\t *  @type string\n\t *  @default Version number\n\t */\n\tDataTable.version = \"1.10.18\";\n\n\t/**\n\t * Private data store, containing all of the settings objects that are\n\t * created for the tables on a given page.\n\t *\n\t * Note that the `DataTable.settings` object is aliased to\n\t * `jQuery.fn.dataTableExt` through which it may be accessed and\n\t * manipulated, or `jQuery.fn.dataTable.settings`.\n\t *  @member\n\t *  @type array\n\t *  @default []\n\t *  @private\n\t */\n\tDataTable.settings = [];\n\n\t/**\n\t * Object models container, for the various models that DataTables has\n\t * available to it. These models define the objects that are used to hold\n\t * the active state and configuration of the table.\n\t *  @namespace\n\t */\n\tDataTable.models = {};\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * search information for the global filter and individual column filters.\n\t *  @namespace\n\t */\n\tDataTable.models.oSearch = {\n\t\t/**\n\t\t * Flag to indicate if the filtering should be case insensitive or not\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bCaseInsensitive\": true,\n\t\n\t\t/**\n\t\t * Applied search term\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sSearch\": \"\",\n\t\n\t\t/**\n\t\t * Flag to indicate if the search term should be interpreted as a\n\t\t * regular expression (true) or not (false) and therefore and special\n\t\t * regex characters escaped.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bRegex\": false,\n\t\n\t\t/**\n\t\t * Flag to indicate if DataTables is to use its smart filtering or not.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bSmart\": true\n\t};\n\t\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * each individual row. This is the object format used for the settings\n\t * aoData array.\n\t *  @namespace\n\t */\n\tDataTable.models.oRow = {\n\t\t/**\n\t\t * TR element for the row\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTr\": null,\n\t\n\t\t/**\n\t\t * Array of TD elements for each row. This is null until the row has been\n\t\t * created.\n\t\t *  @type array nodes\n\t\t *  @default []\n\t\t */\n\t\t\"anCells\": null,\n\t\n\t\t/**\n\t\t * Data object from the original data source for the row. This is either\n\t\t * an array if using the traditional form of DataTables, or an object if\n\t\t * using mData options. The exact type will depend on the passed in\n\t\t * data from the data source, or will be an array if using DOM a data\n\t\t * source.\n\t\t *  @type array|object\n\t\t *  @default []\n\t\t */\n\t\t\"_aData\": [],\n\t\n\t\t/**\n\t\t * Sorting data cache - this array is ostensibly the same length as the\n\t\t * number of columns (although each index is generated only as it is\n\t\t * needed), and holds the data that is used for sorting each column in the\n\t\t * row. We do this cache generation at the start of the sort in order that\n\t\t * the formatting of the sort data need be done only once for each cell\n\t\t * per sort. This array should not be read from or written to by anything\n\t\t * other than the master sorting methods.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aSortData\": null,\n\t\n\t\t/**\n\t\t * Per cell filtering data cache. As per the sort data cache, used to\n\t\t * increase the performance of the filtering in DataTables\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aFilterData\": null,\n\t\n\t\t/**\n\t\t * Filtering data cache. This is the same as the cell filtering cache, but\n\t\t * in this case a string rather than an array. This is easily computed with\n\t\t * a join on `_aFilterData`, but is provided as a cache so the join isn't\n\t\t * needed on every search (memory traded for performance)\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sFilterRow\": null,\n\t\n\t\t/**\n\t\t * Cache of the class name that DataTables has applied to the row, so we\n\t\t * can quickly look at this variable rather than needing to do a DOM check\n\t\t * on className for the nTr property.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *  @private\n\t\t */\n\t\t\"_sRowStripe\": \"\",\n\t\n\t\t/**\n\t\t * Denote if the original data source was from the DOM, or the data source\n\t\t * object. This is used for invalidating data, so DataTables can\n\t\t * automatically read data from the original source, unless uninstructed\n\t\t * otherwise.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"src\": null,\n\t\n\t\t/**\n\t\t * Index in the aoData array. This saves an indexOf lookup when we have the\n\t\t * object, but want to know the index\n\t\t *  @type integer\n\t\t *  @default -1\n\t\t *  @private\n\t\t */\n\t\t\"idx\": -1\n\t};\n\t\n\t\n\t/**\n\t * Template object for the column information object in DataTables. This object\n\t * is held in the settings aoColumns array and contains all the information that\n\t * DataTables needs about each individual column.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults.column}\n\t * but this one is the internal data store for DataTables's cache of columns.\n\t * It should NOT be manipulated outside of DataTables. Any configuration should\n\t * be done through the initialisation options.\n\t *  @namespace\n\t */\n\tDataTable.models.oColumn = {\n\t\t/**\n\t\t * Column index. This could be worked out on-the-fly with $.inArray, but it\n\t\t * is faster to just hold it as a variable\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"idx\": null,\n\t\n\t\t/**\n\t\t * A list of the columns that sorting should occur on when this column\n\t\t * is sorted. That this property is an array allows multi-column sorting\n\t\t * to be defined for a column (for example first name / last name columns\n\t\t * would benefit from this). The values are integers pointing to the\n\t\t * columns to be sorted on (typically it will be a single integer pointing\n\t\t * at itself, but that doesn't need to be the case).\n\t\t *  @type array\n\t\t */\n\t\t\"aDataSort\": null,\n\t\n\t\t/**\n\t\t * Define the sorting directions that are applied to the column, in sequence\n\t\t * as the column is repeatedly sorted upon - i.e. the first value is used\n\t\t * as the sorting direction when the column if first sorted (clicked on).\n\t\t * Sort it again (click again) and it will move on to the next index.\n\t\t * Repeat until loop.\n\t\t *  @type array\n\t\t */\n\t\t\"asSorting\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is searchable, and thus should be included\n\t\t * in the filtering or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSearchable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is sortable or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is currently visible in the table or not\n\t\t *  @type boolean\n\t\t */\n\t\t\"bVisible\": null,\n\t\n\t\t/**\n\t\t * Store for manual type assignment using the `column.type` option. This\n\t\t * is held in store so we can manipulate the column's `sType` property.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sManualType\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if HTML5 data attributes should be used as the data\n\t\t * source for filtering or sorting. True is either are.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @private\n\t\t */\n\t\t\"_bAttrSrc\": false,\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} nTd The TD node that has been created\n\t\t *  @param {*} sData The Data for the cell\n\t\t *  @param {array|object} oData The data for the whole row\n\t\t *  @param {int} iRow The row index for the aoData data store\n\t\t *  @default null\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\t/**\n\t\t * Function to get data from a cell in a column. You should <b>never</b>\n\t\t * access data directly through _aData internally in DataTables - always use\n\t\t * the method attached to this property. It allows mData to function as\n\t\t * required. This function is automatically assigned by the column\n\t\t * initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {string} sSpecific The specific data type you want to get -\n\t\t *    'display', 'type' 'filter' 'sort'\n\t\t *  @returns {*} The data for the cell from the given row's data\n\t\t *  @default null\n\t\t */\n\t\t\"fnGetData\": null,\n\t\n\t\t/**\n\t\t * Function to set data for a cell in the column. You should <b>never</b>\n\t\t * set the data directly to _aData internally in DataTables - always use\n\t\t * this method. It allows mData to function as required. This function\n\t\t * is automatically assigned by the column initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {*} sValue Value to set\n\t\t *  @default null\n\t\t */\n\t\t\"fnSetData\": null,\n\t\n\t\t/**\n\t\t * Property to read the value for the cells in the column from the data\n\t\t * source array / object. If null, then the default content is used, if a\n\t\t * function is given then the return from the function is used.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\t/**\n\t\t * Partner property to mData which is used (only when defined) to get\n\t\t * the data - i.e. it is basically the same as mData, but without the\n\t\t * 'set' option, and also the data fed to it is the result from mData.\n\t\t * This is the rendering method to match the data method of mData.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\t/**\n\t\t * Unique header TH/TD element for this column - this is what the sorting\n\t\t * listener is attached to (if sorting is enabled.)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTh\": null,\n\t\n\t\t/**\n\t\t * Unique footer TH/TD element for this column (if there is one). Not used\n\t\t * in DataTables as such, but can be used for plug-ins to reference the\n\t\t * footer for each column.\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTf\": null,\n\t\n\t\t/**\n\t\t * The class to apply to all TD elements in the table's TBODY for the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sClass\": null,\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t *  @type string\n\t\t */\n\t\t\"sContentPadding\": null,\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because mData\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\t/**\n\t\t * Name for the column, allowing reference to the column by name as well as\n\t\t * by index (needs a lookup to work by name).\n\t\t *  @type string\n\t\t */\n\t\t\"sName\": null,\n\t\n\t\t/**\n\t\t * Custom sorting data type - defines which of the available plug-ins in\n\t\t * afnSortData the custom sorting will use - if any is defined.\n\t\t *  @type string\n\t\t *  @default std\n\t\t */\n\t\t\"sSortDataType\": 'std',\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClass\": null,\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column -\n\t\t * when jQuery UI theming is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClassJUI\": null,\n\t\n\t\t/**\n\t\t * Title of the column - what is seen in the TH element (nTh).\n\t\t *  @type string\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\t/**\n\t\t * Column sorting and filtering type\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\t/**\n\t\t * Width of the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidth\": null,\n\t\n\t\t/**\n\t\t * Width of the column when it was first \"encountered\"\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidthOrig\": null\n\t};\n\t\n\t\n\t/*\n\t * Developer note: The properties of the object below are given in Hungarian\n\t * notation, that was used as the interface for DataTables prior to v1.10, however\n\t * from v1.10 onwards the primary interface is camel case. In order to avoid\n\t * breaking backwards compatibility utterly with this change, the Hungarian\n\t * version is still, internally the primary interface, but is is not documented\n\t * - hence the @name tags in each doc comment. This allows a Javascript function\n\t * to create a map from Hungarian notation to camel case (going the other direction\n\t * would require each property to be listed, which would at around 3K to the size\n\t * of DataTables, while this method is about a 0.5K hit.\n\t *\n\t * Ultimately this does pave the way for Hungarian notation to be dropped\n\t * completely, but that is a massive amount of work and will break current\n\t * installs (therefore is on-hold until v2).\n\t */\n\t\n\t/**\n\t * Initialisation options that can be given to DataTables at initialisation\n\t * time.\n\t *  @namespace\n\t */\n\tDataTable.defaults = {\n\t\t/**\n\t\t * An array of data to use for the table, passed in at initialisation which\n\t\t * will be used in preference to any data which is already in the DOM. This is\n\t\t * particularly useful for constructing tables purely in Javascript, for\n\t\t * example with a custom Ajax call.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.data\n\t\t *\n\t\t *  @example\n\t\t *    // Using a 2D array data source\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],\n\t\t *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\" },\n\t\t *          { \"title\": \"Browser\" },\n\t\t *          { \"title\": \"Platform\" },\n\t\t *          { \"title\": \"Version\" },\n\t\t *          { \"title\": \"Grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using an array of objects as a data source (`data`)\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 4.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  4,\n\t\t *            \"grade\":    \"X\"\n\t\t *          },\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 5.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  5,\n\t\t *            \"grade\":    \"C\"\n\t\t *          }\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\",   \"data\": \"engine\" },\n\t\t *          { \"title\": \"Browser\",  \"data\": \"browser\" },\n\t\t *          { \"title\": \"Platform\", \"data\": \"platform\" },\n\t\t *          { \"title\": \"Version\",  \"data\": \"version\" },\n\t\t *          { \"title\": \"Grade\",    \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaData\": null,\n\t\n\t\n\t\t/**\n\t\t * If ordering is enabled, then DataTables will perform a first pass sort on\n\t\t * initialisation. You can define which column(s) the sort is performed\n\t\t * upon, and the sorting direction, with this variable. The `sorting` array\n\t\t * should contain an array for each column to be sorted initially containing\n\t\t * the column's index and a direction string ('asc' or 'desc').\n\t\t *  @type array\n\t\t *  @default [[0,'asc']]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.order\n\t\t *\n\t\t *  @example\n\t\t *    // Sort by 3rd column first, and then 4th column\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": [[2,'asc'], [3,'desc']]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *    // No initial sorting\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": []\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaSorting\": [[0,'asc']],\n\t\n\t\n\t\t/**\n\t\t * This parameter is basically identical to the `sorting` parameter, but\n\t\t * cannot be overridden by user interaction with the table. What this means\n\t\t * is that you could have a column (visible or hidden) which the sorting\n\t\t * will always be forced on first - any sorting after that (from the user)\n\t\t * will then be performed as required. This can be useful for grouping rows\n\t\t * together.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.orderFixed\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderFixed\": [[0,'asc']]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\n\t\t/**\n\t\t * DataTables can be instructed to load data to display in the table from a\n\t\t * Ajax source. This option defines how that Ajax call is made and where to.\n\t\t *\n\t\t * The `ajax` property has three different modes of operation, depending on\n\t\t * how it is defined. These are:\n\t\t *\n\t\t * * `string` - Set the URL from where the data should be loaded from.\n\t\t * * `object` - Define properties for `jQuery.ajax`.\n\t\t * * `function` - Custom data get function\n\t\t *\n\t\t * `string`\n\t\t * --------\n\t\t *\n\t\t * As a string, the `ajax` property simply defines the URL from which\n\t\t * DataTables will load data.\n\t\t *\n\t\t * `object`\n\t\t * --------\n\t\t *\n\t\t * As an object, the parameters in the object are passed to\n\t\t * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control\n\t\t * of the Ajax request. DataTables has a number of default parameters which\n\t\t * you can override using this option. Please refer to the jQuery\n\t\t * documentation for a full description of the options available, although\n\t\t * the following parameters provide additional options in DataTables or\n\t\t * require special consideration:\n\t\t *\n\t\t * * `data` - As with jQuery, `data` can be provided as an object, but it\n\t\t *   can also be used as a function to manipulate the data DataTables sends\n\t\t *   to the server. The function takes a single parameter, an object of\n\t\t *   parameters with the values that DataTables has readied for sending. An\n\t\t *   object may be returned which will be merged into the DataTables\n\t\t *   defaults, or you can add the items to the object that was passed in and\n\t\t *   not return anything from the function. This supersedes `fnServerParams`\n\t\t *   from DataTables 1.9-.\n\t\t *\n\t\t * * `dataSrc` - By default DataTables will look for the property `data` (or\n\t\t *   `aaData` for compatibility with DataTables 1.9-) when obtaining data\n\t\t *   from an Ajax source or for server-side processing - this parameter\n\t\t *   allows that property to be changed. You can use Javascript dotted\n\t\t *   object notation to get a data source for multiple levels of nesting, or\n\t\t *   it my be used as a function. As a function it takes a single parameter,\n\t\t *   the JSON returned from the server, which can be manipulated as\n\t\t *   required, with the returned value being that used by DataTables as the\n\t\t *   data source for the table. This supersedes `sAjaxDataProp` from\n\t\t *   DataTables 1.9-.\n\t\t *\n\t\t * * `success` - Should not be overridden it is used internally in\n\t\t *   DataTables. To manipulate / transform the data returned by the server\n\t\t *   use `ajax.dataSrc`, or use `ajax` as a function (see below).\n\t\t *\n\t\t * `function`\n\t\t * ----------\n\t\t *\n\t\t * As a function, making the Ajax call is left up to yourself allowing\n\t\t * complete control of the Ajax request. Indeed, if desired, a method other\n\t\t * than Ajax could be used to obtain the required data, such as Web storage\n\t\t * or an AIR database.\n\t\t *\n\t\t * The function is given four parameters and no return is required. The\n\t\t * parameters are:\n\t\t *\n\t\t * 1. _object_ - Data to send to the server\n\t\t * 2. _function_ - Callback function that must be executed when the required\n\t\t *    data has been obtained. That data should be passed into the callback\n\t\t *    as the only parameter\n\t\t * 3. _object_ - DataTables settings object for the table\n\t\t *\n\t\t * Note that this supersedes `fnServerData` from DataTables 1.9-.\n\t\t *\n\t\t *  @type string|object|function\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.ajax\n\t\t *  @since 1.10.0\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax.\n\t\t *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": \"data.json\"\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to change\n\t\t *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"tableData\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to read data\n\t\t *   // from a plain array rather than an array in an object\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Manipulate the data returned from the server - add a link to data\n\t\t *   // (note this can, should, be done using `render` for the column - this\n\t\t *   // is just a simple example of how the data can be manipulated).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": function ( json ) {\n\t\t *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {\n\t\t *           json[i][0] = '<a href=\"/message/'+json[i][0]+'>View message</a>';\n\t\t *         }\n\t\t *         return json;\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Add data to the request\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"data\": function ( d ) {\n\t\t *         return {\n\t\t *           \"extra_search\": $('#extra').val()\n\t\t *         };\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Send request as POST\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"type\": \"POST\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get the data from localStorage (could interface with a form for\n\t\t *   // adding, editing and removing rows).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": function (data, callback, settings) {\n\t\t *       callback(\n\t\t *         JSON.parse( localStorage.getItem('dataTablesData') )\n\t\t *       );\n\t\t *     }\n\t\t *   } );\n\t\t */\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to readily specify the entries in the length drop\n\t\t * down menu that DataTables shows when pagination is enabled. It can be\n\t\t * either a 1D array of options which will be used for both the displayed\n\t\t * option and the value, or a 2D array which will use the array in the first\n\t\t * position as the value, and the array in the second position as the\n\t\t * displayed options (useful for language strings such as 'All').\n\t\t *\n\t\t * Note that the `pageLength` property will be automatically set to the\n\t\t * first value given in this array, unless `pageLength` is also provided.\n\t\t *  @type array\n\t\t *  @default [ 10, 25, 50, 100 ]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.lengthMenu\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthMenu\": [[10, 25, 50, -1], [10, 25, 50, \"All\"]]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aLengthMenu\": [ 10, 25, 50, 100 ],\n\t\n\t\n\t\t/**\n\t\t * The `columns` option in the initialisation parameter allows you to define\n\t\t * details about the way individual columns behave. For a full list of\n\t\t * column options that can be set, please see\n\t\t * {@link DataTable.defaults.column}. Note that if you use `columns` to\n\t\t * define your columns, you must have an entry in the array for every single\n\t\t * column that you have in your table (these can be null if you don't which\n\t\t * to specify any options).\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.column\n\t\t */\n\t\t\"aoColumns\": null,\n\t\n\t\t/**\n\t\t * Very similar to `columns`, `columnDefs` allows you to target a specific\n\t\t * column, multiple columns, or all columns, using the `targets` property of\n\t\t * each object in the array. This allows great flexibility when creating\n\t\t * tables, as the `columnDefs` arrays can be of any length, targeting the\n\t\t * columns you specifically want. `columnDefs` may use any of the column\n\t\t * options available: {@link DataTable.defaults.column}, but it _must_\n\t\t * have `targets` defined in each object in the array. Values in the `targets`\n\t\t * array may be:\n\t\t *   <ul>\n\t\t *     <li>a string - class name will be matched on the TH for the column</li>\n\t\t *     <li>0 or a positive integer - column index counting from the left</li>\n\t\t *     <li>a negative integer - column index counting from the right</li>\n\t\t *     <li>the string \"_all\" - all columns (i.e. assign a default)</li>\n\t\t *   </ul>\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.columnDefs\n\t\t */\n\t\t\"aoColumnDefs\": null,\n\t\n\t\n\t\t/**\n\t\t * Basically the same as `search`, this parameter defines the individual column\n\t\t * filtering state at initialisation time. The array must be of the same size\n\t\t * as the number of columns, and each element be an object with the parameters\n\t\t * `search` and `escapeRegex` (the latter is optional). 'null' is also\n\t\t * accepted and the default will be used.\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.searchCols\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchCols\": [\n\t\t *          null,\n\t\t *          { \"search\": \"My filter\" },\n\t\t *          null,\n\t\t *          { \"search\": \"^[0-9]\", \"escapeRegex\": false }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aoSearchCols\": [],\n\t\n\t\n\t\t/**\n\t\t * An array of CSS classes that should be applied to displayed rows. This\n\t\t * array may be of any length, and DataTables will apply each class\n\t\t * sequentially, looping when required.\n\t\t *  @type array\n\t\t *  @default null <i>Will take the values determined by the `oClasses.stripe*`\n\t\t *    options</i>\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.stripeClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stripeClasses\": [ 'strip1', 'strip2', 'strip3' ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable automatic column width calculation. This can be disabled\n\t\t * as an optimisation (it takes some time to calculate the widths) if the\n\t\t * tables widths are passed in using `columns`.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.autoWidth\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"autoWidth\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bAutoWidth\": true,\n\t\n\t\n\t\t/**\n\t\t * Deferred rendering can provide DataTables with a huge speed boost when you\n\t\t * are using an Ajax or JS data source for the table. This option, when set to\n\t\t * true, will cause DataTables to defer the creation of the table elements for\n\t\t * each row until they are needed for a draw - saving a significant amount of\n\t\t * time.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.deferRender\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajax\": \"sources/arrays.txt\",\n\t\t *        \"deferRender\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDeferRender\": false,\n\t\n\t\n\t\t/**\n\t\t * Replace a DataTable which matches the given selector and replace it with\n\t\t * one which has the properties of the new initialisation object passed. If no\n\t\t * table matches the selector, then the new DataTable will be constructed as\n\t\t * per normal.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.destroy\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"srollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      // Some time later....\n\t\t *      $('#example').dataTable( {\n\t\t *        \"filter\": false,\n\t\t *        \"destroy\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDestroy\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering of data. Filtering in DataTables is \"smart\" in\n\t\t * that it allows the end user to input multiple words (space separated) and\n\t\t * will match a row containing those words, even if not in the order that was\n\t\t * specified (this allow matching across multiple columns). Note that if you\n\t\t * wish to use filtering in DataTables this must remain 'true' - to remove the\n\t\t * default filtering input box and retain filtering abilities, please use\n\t\t * {@link DataTable.defaults.dom}.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.searching\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searching\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bFilter\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the table information display. This shows information\n\t\t * about the data that is currently visible on the page, including information\n\t\t * about filtered data if that action is being performed.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.info\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"info\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bInfo\": true,\n\t\n\t\n\t\t/**\n\t\t * Allows the end user to select the size of a formatted page from a select\n\t\t * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.lengthChange\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthChange\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bLengthChange\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable pagination.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.paging\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"paging\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bPaginate\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of a 'processing' indicator when the table is\n\t\t * being processed (e.g. a sort). This is particularly useful for tables with\n\t\t * large amounts of data where it can take a noticeable amount of time to sort\n\t\t * the entries.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.processing\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"processing\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bProcessing\": false,\n\t\n\t\n\t\t/**\n\t\t * Retrieve the DataTables object for the given selector. Note that if the\n\t\t * table has already been initialised, this parameter will cause DataTables\n\t\t * to simply return the object that has already been set up - it will not take\n\t\t * account of any changes you might have made to the initialisation object\n\t\t * passed to DataTables (setting this parameter to true is an acknowledgement\n\t\t * that you understand this). `destroy` can be used to reinitialise a table if\n\t\t * you need.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.retrieve\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      initTable();\n\t\t *      tableActions();\n\t\t *    } );\n\t\t *\n\t\t *    function initTable ()\n\t\t *    {\n\t\t *      return $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false,\n\t\t *        \"retrieve\": true\n\t\t *      } );\n\t\t *    }\n\t\t *\n\t\t *    function tableActions ()\n\t\t *    {\n\t\t *      var table = initTable();\n\t\t *      // perform API operations with oTable\n\t\t *    }\n\t\t */\n\t\t\"bRetrieve\": false,\n\t\n\t\n\t\t/**\n\t\t * When vertical (y) scrolling is enabled, DataTables will force the height of\n\t\t * the table's viewport to the given height at all times (useful for layout).\n\t\t * However, this can look odd when filtering data down to a small data set,\n\t\t * and the footer is left \"floating\" further down. This parameter (when\n\t\t * enabled) will cause DataTables to collapse the table's viewport down when\n\t\t * the result set will fit within the given Y height.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollCollapse\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200\",\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bScrollCollapse\": false,\n\t\n\t\n\t\t/**\n\t\t * Configure DataTables to use server-side processing. Note that the\n\t\t * `ajax` parameter must also be given in order to give DataTables a\n\t\t * source to obtain the required data for each draw.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverSide\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"xhr.php\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bServerSide\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable sorting of columns. Sorting of individual columns can be\n\t\t * disabled by the `sortable` option for each column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.ordering\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ordering\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSort\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or display DataTables' ability to sort multiple columns at the\n\t\t * same time (activated by shift-click by the user).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderMulti\n\t\t *\n\t\t *  @example\n\t\t *    // Disable multiple column sorting ability\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderMulti\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortMulti\": true,\n\t\n\t\n\t\t/**\n\t\t * Allows control over whether DataTables should use the top (true) unique\n\t\t * cell that is found for a single column, or the bottom (false - default).\n\t\t * This is useful when using complex headers.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderCellsTop\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderCellsTop\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortCellsTop\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the addition of the classes `sorting\\_1`, `sorting\\_2` and\n\t\t * `sorting\\_3` to the columns which are currently being sorted on. This is\n\t\t * presented as a feature switch as it can increase processing time (while\n\t\t * classes are removed and added) so for large data sets you might want to\n\t\t * turn this off.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.orderClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderClasses\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortClasses\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable state saving. When enabled HTML5 `localStorage` will be\n\t\t * used to save table display information such as pagination information,\n\t\t * display length, filtering and sorting. As such when the end user reloads\n\t\t * the page the display display will match what thy had previously set up.\n\t\t *\n\t\t * Due to the use of `localStorage` the default state saving is not supported\n\t\t * in IE6 or 7. If state saving is required in those browsers, use\n\t\t * `stateSaveCallback` to provide a storage solution such as cookies.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.stateSave\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bStateSave\": false,\n\t\n\t\n\t\t/**\n\t\t * This function is called when a TR element is created (and all TD child\n\t\t * elements have been inserted), or registered if using a DOM source, allowing\n\t\t * manipulation of the TR element (adding classes etc).\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} dataIndex The index of this row in the internal aoData array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.createdRow\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"createdRow\": function( row, data, dataIndex ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" )\n\t\t *          {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedRow\": null,\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify any aspect you want about the created DOM.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.drawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"drawCallback\": function( settings ) {\n\t\t *          alert( 'DataTables has redrawn the table' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Identical to fnHeaderCallback() but for the table footer this function\n\t\t * allows you to modify the table footer on every 'draw' event.\n\t\t *  @type function\n\t\t *  @param {node} foot \"TR\" element for the footer\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.footerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"footerCallback\": function( tfoot, data, start, end, display ) {\n\t\t *          tfoot.getElementsByTagName('th')[0].innerHTML = \"Starting index is \"+start;\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnFooterCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * When rendering large numbers in the information element for the table\n\t\t * (i.e. \"Showing 1 to 10 of 57 entries\") DataTables will render large numbers\n\t\t * to have a comma separator for the 'thousands' units (e.g. 1 million is\n\t\t * rendered as \"1,000,000\") to help readability for the end user. This\n\t\t * function will override the default method DataTables uses.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {int} toFormat number to be formatted\n\t\t *  @returns {string} formatted string for DataTables to show the number\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.formatNumber\n\t\t *\n\t\t *  @example\n\t\t *    // Format a number using a single quote for the separator (note that\n\t\t *    // this can also be done with the language.thousands option)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"formatNumber\": function ( toFormat ) {\n\t\t *          return toFormat.toString().replace(\n\t\t *            /\\B(?=(\\d{3})+(?!\\d))/g, \"'\"\n\t\t *          );\n\t\t *        };\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnFormatNumber\": function ( toFormat ) {\n\t\t\treturn toFormat.toString().replace(\n\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g,\n\t\t\t\tthis.oLanguage.sThousands\n\t\t\t);\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify the header row. This can be used to calculate and\n\t\t * display useful information about the table.\n\t\t *  @type function\n\t\t *  @param {node} head \"TR\" element for the header\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.headerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"fheaderCallback\": function( head, data, start, end, display ) {\n\t\t *          head.getElementsByTagName('th')[0].innerHTML = \"Displaying \"+(end-start)+\" records\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnHeaderCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * The information element can be used to convey information about the current\n\t\t * state of the table. Although the internationalisation options presented by\n\t\t * DataTables are quite capable of dealing with most customisations, there may\n\t\t * be times where you wish to customise the string further. This callback\n\t\t * allows you to do exactly that.\n\t\t *  @type function\n\t\t *  @param {object} oSettings DataTables settings object\n\t\t *  @param {int} start Starting position in data for the draw\n\t\t *  @param {int} end End position in data for the draw\n\t\t *  @param {int} max Total number of rows in the table (regardless of\n\t\t *    filtering)\n\t\t *  @param {int} total Total number of rows in the data set, after filtering\n\t\t *  @param {string} pre The string that DataTables has formatted using it's\n\t\t *    own rules\n\t\t *  @returns {string} The string to be displayed in the information element.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.infoCallback\n\t\t *\n\t\t *  @example\n\t\t *    $('#example').dataTable( {\n\t\t *      \"infoCallback\": function( settings, start, end, max, total, pre ) {\n\t\t *        return start +\" to \"+ end;\n\t\t *      }\n\t\t *    } );\n\t\t */\n\t\t\"fnInfoCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Called when the table has been initialised. Normally DataTables will\n\t\t * initialise sequentially and there will be no need for this function,\n\t\t * however, this does not hold true when using external language information\n\t\t * since that is obtained using an async XHR call.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} json The JSON object request from the server - only\n\t\t *    present if client-side Ajax sourced data is used\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.initComplete\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"initComplete\": function(settings, json) {\n\t\t *          alert( 'DataTables has finished its initialisation.' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnInitComplete\": null,\n\t\n\t\n\t\t/**\n\t\t * Called at the very start of each table draw and can be used to cancel the\n\t\t * draw by returning false, any other return (including undefined) results in\n\t\t * the full draw occurring).\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @returns {boolean} False will cancel the draw, anything else (including no\n\t\t *    return) will allow it to complete.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.preDrawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"preDrawCallback\": function( settings ) {\n\t\t *          if ( $('#test').val() == 1 ) {\n\t\t *            return false;\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnPreDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * This function allows you to 'post process' each row after it have been\n\t\t * generated for each table draw, but before it is rendered on screen. This\n\t\t * function might be used for setting the row class name etc.\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} displayIndex The display index for the current table draw\n\t\t *  @param {int} displayIndexFull The index of the data in the full list of\n\t\t *    rows (after filtering)\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.rowCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"rowCallback\": function( row, data, displayIndex, displayIndexFull ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" ) {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnRowCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * This parameter allows you to override the default function which obtains\n\t\t * the data from the server so something more suitable for your application.\n\t\t * For example you could use POST data, or pull information from a Gears or\n\t\t * AIR database.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {string} source HTTP source to obtain the data from (`ajax`)\n\t\t *  @param {array} data A key/value pair object containing the data to send\n\t\t *    to the server\n\t\t *  @param {function} callback to be called on completion of the data get\n\t\t *    process that will draw the data on the page.\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverData\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t *  It is often useful to send extra data to the server when making an Ajax\n\t\t * request - for example custom filtering information, and this callback\n\t\t * function makes it trivial to send extra information to the server. The\n\t\t * passed in parameter is the data set that has been constructed by\n\t\t * DataTables, and you can add to this or modify it as you require.\n\t\t *  @type function\n\t\t *  @param {array} data Data array (array of objects which are name/value\n\t\t *    pairs) that has been constructed by DataTables and will be sent to the\n\t\t *    server. In the case of Ajax sourced data with server-side processing\n\t\t *    this will be an empty array, for server-side processing there will be a\n\t\t *    significant number of parameters!\n\t\t *  @returns {undefined} Ensure that you modify the data array passed in,\n\t\t *    as this is passed by reference.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverParams\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Load the table state. With this function you can define from where, and how, the\n\t\t * state of a table is loaded. By default DataTables will load from `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} callback Callback that can be executed when done. It\n\t\t *    should be passed the loaded state object.\n\t\t *  @return {object} The DataTables state object to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadCallback\": function (settings, callback) {\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_load\",\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"success\": function (json) {\n\t\t *              callback( json );\n\t\t *            }\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadCallback\": function ( settings ) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(\n\t\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(\n\t\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the saved state prior to loading that state.\n\t\t * This callback is called when the table is loading state from the stored data, but\n\t\t * prior to the settings object being modified by the saved state. Note that for\n\t\t * plug-in authors, you should use the `stateLoadParams` event to load parameters for\n\t\t * a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that is to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never loaded\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Disallow state loading by returning false\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          return false;\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Callback that is called when the state has been loaded from the state saving method\n\t\t * and the DataTables settings object has been modified as a result of the loaded state.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that was loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoaded\n\t\t *\n\t\t *  @example\n\t\t *    // Show an alert with the filtering value that was saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoaded\": function (settings, data) {\n\t\t *          alert( 'Saved filter was: '+data.oSearch.sSearch );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoaded\": null,\n\t\n\t\n\t\t/**\n\t\t * Save the table state. This function allows you to define where and how the state\n\t\t * information for the table is stored By default DataTables will use `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveCallback\": function (settings, data) {\n\t\t *          // Send an Ajax request to the server with the state object\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_save\",\n\t\t *            \"data\": data,\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"method\": \"POST\"\n\t\t *            \"success\": function () {}\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveCallback\": function ( settings, data ) {\n\t\t\ttry {\n\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(\n\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname,\n\t\t\t\t\tJSON.stringify( data )\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the state to be saved. Called when the table\n\t\t * has changed state a new state save is required. This method allows modification of\n\t\t * the state saving object prior to actually doing the save, including addition or\n\t\t * other state properties or modification. Note that for plug-in authors, you should\n\t\t * use the `stateSaveParams` event to save parameters for a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Duration for which the saved state information is considered valid. After this period\n\t\t * has elapsed the state will be returned to the default.\n\t\t * Value is given in seconds.\n\t\t *  @type int\n\t\t *  @default 7200 <i>(2 hours)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.stateDuration\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateDuration\": 60*60*24; // 1 day\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iStateDuration\": 7200,\n\t\n\t\n\t\t/**\n\t\t * When enabled DataTables will not make a request to the server for the first\n\t\t * page draw - rather it will use the data already on the page (no sorting etc\n\t\t * will be applied to it), thus saving on an XHR at load time. `deferLoading`\n\t\t * is used to indicate that deferred loading is required, but it is also used\n\t\t * to tell DataTables how many records there are in the full table (allowing\n\t\t * the information element and pagination to be displayed correctly). In the case\n\t\t * where a filtering is applied to the table on initial load, this can be\n\t\t * indicated by giving the parameter as an array, where the first element is\n\t\t * the number of records available after filtering and the second element is the\n\t\t * number of records without filtering (allowing the table information element\n\t\t * to be shown correctly).\n\t\t *  @type int | array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.deferLoading\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records available in the table, no filtering applied\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": 57\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records after filtering, 100 without filtering (an initial filter applied)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": [ 57, 100 ],\n\t\t *        \"search\": {\n\t\t *          \"search\": \"my_filter\"\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iDeferLoading\": null,\n\t\n\t\n\t\t/**\n\t\t * Number of rows to display on a single page when using pagination. If\n\t\t * feature enabled (`lengthChange`) then the end user will be able to override\n\t\t * this to a custom setting using a pop-up menu.\n\t\t *  @type int\n\t\t *  @default 10\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pageLength\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pageLength\": 50\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayLength\": 10,\n\t\n\t\n\t\t/**\n\t\t * Define the starting point for data display when using DataTables with\n\t\t * pagination. Note that this parameter is the number of records, rather than\n\t\t * the page number, so if you have 10 records per page and want to start on\n\t\t * the third page, it should be \"20\".\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.displayStart\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"displayStart\": 20\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayStart\": 0,\n\t\n\t\n\t\t/**\n\t\t * By default DataTables allows keyboard navigation of the table (sorting, paging,\n\t\t * and filtering) by adding a `tabindex` attribute to the required elements. This\n\t\t * allows you to tab through the controls and press the enter key to activate them.\n\t\t * The tabindex is default 0, meaning that the tab follows the flow of the document.\n\t\t * You can overrule this using this parameter if you wish. Use a value of -1 to\n\t\t * disable built-in keyboard navigation.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.tabIndex\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"tabIndex\": 1\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\n\t\t/**\n\t\t * Classes that DataTables assigns to the various components and features\n\t\t * that it adds to the HTML table. This allows classes to be configured\n\t\t * during initialisation in addition to through the static\n\t\t * {@link DataTable.ext.oStdClasses} object).\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.classes\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\n\t\t/**\n\t\t * All strings that DataTables uses in the user interface that it creates\n\t\t * are defined in this object, allowing you to modified them individually or\n\t\t * completely replace them all as required.\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.language\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Strings that are used for WAI-ARIA labels and controls only (these are not\n\t\t\t * actually visible on the page, but will be read by screenreaders, and thus\n\t\t\t * must be internationalised as well).\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.aria\n\t\t\t */\n\t\t\t\"oAria\": {\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted ascending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortAscending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortAscending\": \" - click/return to sort ascending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortAscending\": \": activate to sort column ascending\",\n\t\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted descending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortDescending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortDescending\": \" - click/return to sort descending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortDescending\": \": activate to sort column descending\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * Pagination string used by DataTables for the built-in pagination\n\t\t\t * control types.\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.paginate\n\t\t\t */\n\t\t\t\"oPaginate\": {\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the first page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default First\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.first\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"first\": \"First page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sFirst\": \"First\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the last page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Last\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.last\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"last\": \"Last page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sLast\": \"Last\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'next' pagination button (to take the user to the\n\t\t\t\t * next page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Next\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.next\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"next\": \"Next page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sNext\": \"Next\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'previous' pagination button (to take the user to\n\t\t\t\t * the previous page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Previous\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.previous\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"previous\": \"Previous page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sPrevious\": \"Previous\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * This string is shown in preference to `zeroRecords` when the table is\n\t\t\t * empty of data (regardless of filtering). Note that this is an optional\n\t\t\t * parameter - if it is not given, the value of `zeroRecords` will be used\n\t\t\t * instead (either the default or given value).\n\t\t\t *  @type string\n\t\t\t *  @default No data available in table\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.emptyTable\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"emptyTable\": \"No data available in table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sEmptyTable\": \"No data available in table\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This string gives information to the end user about the information\n\t\t\t * that is current on display on the page. The following tokens can be\n\t\t\t * used in the string and will be dynamically replaced as the table\n\t\t\t * display updates. This tokens can be placed anywhere in the string, or\n\t\t\t * removed as needed by the language requires:\n\t\t\t *\n\t\t\t * * `\\_START\\_` - Display index of the first record on the current page\n\t\t\t * * `\\_END\\_` - Display index of the last record on the current page\n\t\t\t * * `\\_TOTAL\\_` - Number of records in the table after filtering\n\t\t\t * * `\\_MAX\\_` - Number of records in the table without filtering\n\t\t\t * * `\\_PAGE\\_` - Current page number\n\t\t\t * * `\\_PAGES\\_` - Total number of pages of data in the table\n\t\t\t *\n\t\t\t *  @type string\n\t\t\t *  @default Showing _START_ to _END_ of _TOTAL_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.info\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"info\": \"Showing page _PAGE_ of _PAGES_\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfo\": \"Showing _START_ to _END_ of _TOTAL_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Display information string for when the table is empty. Typically the\n\t\t\t * format of this string should match `info`.\n\t\t\t *  @type string\n\t\t\t *  @default Showing 0 to 0 of 0 entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoEmpty\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoEmpty\": \"No entries to show\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoEmpty\": \"Showing 0 to 0 of 0 entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When a user filters the information in a table, this string is appended\n\t\t\t * to the information (`info`) to give an idea of how strong the filtering\n\t\t\t * is. The variable _MAX_ is dynamically updated.\n\t\t\t *  @type string\n\t\t\t *  @default (filtered from _MAX_ total entries)\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoFiltered\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoFiltered\": \" - filtering from _MAX_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoFiltered\": \"(filtered from _MAX_ total entries)\",\n\t\n\t\n\t\t\t/**\n\t\t\t * If can be useful to append extra information to the info string at times,\n\t\t\t * and this variable does exactly that. This information will be appended to\n\t\t\t * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are\n\t\t\t * being used) at all times.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoPostFix\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoPostFix\": \"All records shown are derived from real information.\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoPostFix\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This decimal place operator is a little different from the other\n\t\t\t * language options since DataTables doesn't output floating point\n\t\t\t * numbers, so it won't ever use this for display of a number. Rather,\n\t\t\t * what this parameter does is modify the sort methods of the table so\n\t\t\t * that numbers which are in a format which has a character other than\n\t\t\t * a period (`.`) as a decimal place will be sorted numerically.\n\t\t\t *\n\t\t\t * Note that numbers with different decimal places cannot be shown in\n\t\t\t * the same table and still be sortable, the table must be consistent.\n\t\t\t * However, multiple different tables on the page can use different\n\t\t\t * decimal place characters.\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.decimal\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"decimal\": \",\"\n\t\t\t *          \"thousands\": \".\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sDecimal\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * DataTables has a build in number formatter (`formatNumber`) which is\n\t\t\t * used to format large numbers that are used in the table information.\n\t\t\t * By default a comma is used, but this can be trivially changed to any\n\t\t\t * character you wish with this parameter.\n\t\t\t *  @type string\n\t\t\t *  @default ,\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.thousands\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"thousands\": \"'\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sThousands\": \",\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Detail the action that will be taken when the drop down menu for the\n\t\t\t * pagination length option is changed. The '_MENU_' variable is replaced\n\t\t\t * with a default select list of 10, 25, 50 and 100, and can be replaced\n\t\t\t * with a custom select box if required.\n\t\t\t *  @type string\n\t\t\t *  @default Show _MENU_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.lengthMenu\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language change only\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": \"Display _MENU_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language and options change\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": 'Display <select>'+\n\t\t\t *            '<option value=\"10\">10</option>'+\n\t\t\t *            '<option value=\"20\">20</option>'+\n\t\t\t *            '<option value=\"30\">30</option>'+\n\t\t\t *            '<option value=\"40\">40</option>'+\n\t\t\t *            '<option value=\"50\">50</option>'+\n\t\t\t *            '<option value=\"-1\">All</option>'+\n\t\t\t *            '</select> records'\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLengthMenu\": \"Show _MENU_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When using Ajax sourced data and during the first draw when DataTables is\n\t\t\t * gathering the data, this message is shown in an empty row in the table to\n\t\t\t * indicate to the end user the the data is being loaded. Note that this\n\t\t\t * parameter is not used when loading data by server-side processing, just\n\t\t\t * Ajax sourced data with client-side processing.\n\t\t\t *  @type string\n\t\t\t *  @default Loading...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.loadingRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"loadingRecords\": \"Please wait - loading...\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLoadingRecords\": \"Loading...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text which is displayed when the table is processing a user action\n\t\t\t * (usually a sort command or similar).\n\t\t\t *  @type string\n\t\t\t *  @default Processing...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.processing\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"processing\": \"DataTables is currently busy\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sProcessing\": \"Processing...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Details the actions that will be taken when the user types into the\n\t\t\t * filtering input text box. The variable \"_INPUT_\", if used in the string,\n\t\t\t * is replaced with the HTML text box for the filtering input allowing\n\t\t\t * control over where it appears in the string. If \"_INPUT_\" is not given\n\t\t\t * then the input box is appended to the string automatically.\n\t\t\t *  @type string\n\t\t\t *  @default Search:\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.search\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Input text box will be appended at the end automatically\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Filter records:\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Specify where the filter should appear\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Apply filter _INPUT_ to table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sSearch\": \"Search:\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Assign a `placeholder` attribute to the search `input` element\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.searchPlaceholder\n\t\t\t */\n\t\t\t\"sSearchPlaceholder\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * All of the language information can be stored in a file on the\n\t\t\t * server-side, which DataTables will look up if this parameter is passed.\n\t\t\t * It must store the URL of the language file, which is in a JSON format,\n\t\t\t * and the object has the same properties as the oLanguage object in the\n\t\t\t * initialiser object (i.e. the above parameters). Please refer to one of\n\t\t\t * the example language files to see how this works in action.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string - i.e. disabled</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.url\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"url\": \"http://www.sprymedia.co.uk/dataTables/lang.txt\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sUrl\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text shown inside the table records when the is no information to be\n\t\t\t * displayed after filtering. `emptyTable` is shown when there is simply no\n\t\t\t * information in the table at all (regardless of filtering).\n\t\t\t *  @type string\n\t\t\t *  @default No matching records found\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.zeroRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"zeroRecords\": \"No records to display\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sZeroRecords\": \"No matching records found\"\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to have define the global filtering state at\n\t\t * initialisation time. As an object the `search` parameter must be\n\t\t * defined, but all other parameters are optional. When `regex` is true,\n\t\t * the search string will be treated as a regular expression, when false\n\t\t * (default) it will be treated as a straight string. When `smart`\n\t\t * DataTables will use it's smart filtering methods (to word match at\n\t\t * any point in the data), when false this will not be done.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.search\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"search\": {\"search\": \"Initial search\"}\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"oSearch\": $.extend( {}, DataTable.models.oSearch ),\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * By default DataTables will look for the property `data` (or `aaData` for\n\t\t * compatibility with DataTables 1.9-) when obtaining data from an Ajax\n\t\t * source or for server-side processing - this parameter allows that\n\t\t * property to be changed. You can use Javascript dotted object notation to\n\t\t * get a data source for multiple levels of nesting.\n\t\t *  @type string\n\t\t *  @default data\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxDataProp\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxDataProp\": \"data\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * You can instruct DataTables to load data from an external\n\t\t * source using this parameter (use aData if you want to pass data in you\n\t\t * already have). Simply provide a url a JSON object can be obtained from.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxSource\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\n\t\t/**\n\t\t * This initialisation variable allows you to specify exactly where in the\n\t\t * DOM you want DataTables to inject the various controls it adds to the page\n\t\t * (for example you might want the pagination controls at the top of the\n\t\t * table). DIV elements (with or without a custom class) can also be added to\n\t\t * aid styling. The follow syntax is used:\n\t\t *   <ul>\n\t\t *     <li>The following options are allowed:\n\t\t *       <ul>\n\t\t *         <li>'l' - Length changing</li>\n\t\t *         <li>'f' - Filtering input</li>\n\t\t *         <li>'t' - The table!</li>\n\t\t *         <li>'i' - Information</li>\n\t\t *         <li>'p' - Pagination</li>\n\t\t *         <li>'r' - pRocessing</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following constants are allowed:\n\t\t *       <ul>\n\t\t *         <li>'H' - jQueryUI theme \"header\" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>\n\t\t *         <li>'F' - jQueryUI theme \"footer\" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following syntax is expected:\n\t\t *       <ul>\n\t\t *         <li>'&lt;' and '&gt;' - div elements</li>\n\t\t *         <li>'&lt;\"class\" and '&gt;' - div with a class</li>\n\t\t *         <li>'&lt;\"#id\" and '&gt;' - div with an ID</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>Examples:\n\t\t *       <ul>\n\t\t *         <li>'&lt;\"wrapper\"flipt&gt;'</li>\n\t\t *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *   </ul>\n\t\t *  @type string\n\t\t *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>\n\t\t *    <\"H\"lfr>t<\"F\"ip> <i>(when `jQueryUI` is true)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.dom\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"dom\": '&lt;\"top\"i&gt;rt&lt;\"bottom\"flp&gt;&lt;\"clear\"&gt;'\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDom\": \"lfrtip\",\n\t\n\t\n\t\t/**\n\t\t * Search delay option. This will throttle full table searches that use the\n\t\t * DataTables provided search input element (it does not effect calls to\n\t\t * `dt-api search()`, providing a delay before the search is made.\n\t\t *  @type integer\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.searchDelay\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchDelay\": 200\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\n\t\t/**\n\t\t * DataTables features six different built-in options for the buttons to\n\t\t * display for pagination control:\n\t\t *\n\t\t * * `numbers` - Page number buttons only\n\t\t * * `simple` - 'Previous' and 'Next' buttons only\n\t\t * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers\n\t\t * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons\n\t\t * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers\n\t\t * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers\n\t\t *  \n\t\t * Further methods can be added using {@link DataTable.ext.oPagination}.\n\t\t *  @type string\n\t\t *  @default simple_numbers\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pagingType\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pagingType\": \"full_numbers\"\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"sPaginationType\": \"simple_numbers\",\n\t\n\t\n\t\t/**\n\t\t * Enable horizontal scrolling. When a table is too wide to fit into a\n\t\t * certain layout, or you have a large number of columns in the table, you\n\t\t * can enable x-scrolling to show the table in a viewport, which can be\n\t\t * scrolled. This property can be `true` which will allow the table to\n\t\t * scroll horizontally when needed, or any CSS unit, or a number (in which\n\t\t * case it will be treated as a pixel measurement). Setting as simply `true`\n\t\t * is recommended.\n\t\t *  @type boolean|string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollX\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": true,\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollX\": \"\",\n\t\n\t\n\t\t/**\n\t\t * This property can be used to force a DataTable to use more width than it\n\t\t * might otherwise do when x-scrolling is enabled. For example if you have a\n\t\t * table which requires to be well spaced, this parameter is useful for\n\t\t * \"over-sizing\" the table, and thus forcing scrolling. This property can by\n\t\t * any CSS unit, or a number (in which case it will be treated as a pixel\n\t\t * measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollXInner\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": \"100%\",\n\t\t *        \"scrollXInner\": \"110%\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollXInner\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Enable vertical scrolling. Vertical scrolling will constrain the DataTable\n\t\t * to the given height, and enable scrolling for any data which overflows the\n\t\t * current viewport. This can be used as an alternative to paging to display\n\t\t * a lot of data in a small area (although paging and scrolling can both be\n\t\t * enabled at the same time). This property can be any CSS unit, or a number\n\t\t * (in which case it will be treated as a pixel measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollY\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollY\": \"\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * Set the HTTP method that is used to make the Ajax call for server-side\n\t\t * processing or Ajax sourced data.\n\t\t *  @type string\n\t\t *  @default GET\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverMethod\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sServerMethod\": \"GET\",\n\t\n\t\n\t\t/**\n\t\t * DataTables makes use of renderers when displaying HTML elements for\n\t\t * a table. These renderers can be added or modified by plug-ins to\n\t\t * generate suitable mark-up for a site. For example the Bootstrap\n\t\t * integration plug-in for DataTables uses a paging button renderer to\n\t\t * display pagination buttons in the mark-up required by Bootstrap.\n\t\t *\n\t\t * For further information about the renderers available see\n\t\t * DataTable.ext.renderer\n\t\t *  @type string|object\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.renderer\n\t\t *\n\t\t */\n\t\t\"renderer\": null,\n\t\n\t\n\t\t/**\n\t\t * Set the data property name that DataTables should use to get a row's id\n\t\t * to set as the `id` property in the node.\n\t\t *  @type string\n\t\t *  @default DT_RowId\n\t\t *\n\t\t *  @name DataTable.defaults.rowId\n\t\t */\n\t\t\"rowId\": \"DT_RowId\"\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults );\n\t\n\t\n\t\n\t/*\n\t * Developer note - See note in model.defaults.js about the use of Hungarian\n\t * notation and camel case.\n\t */\n\t\n\t/**\n\t * Column options that can be given to DataTables at initialisation time.\n\t *  @namespace\n\t */\n\tDataTable.defaults.column = {\n\t\t/**\n\t\t * Define which column(s) an order will occur on for this column. This\n\t\t * allows a column's ordering to take multiple columns into account when\n\t\t * doing a sort or use the data from a different column. For example first\n\t\t * name / last name columns make sense to do a multi-column sort over the\n\t\t * two columns.\n\t\t *  @type array|int\n\t\t *  @default null <i>Takes the value of the column index automatically</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderData\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderData\": [ 0, 1 ], \"targets\": [ 0 ] },\n\t\t *          { \"orderData\": [ 1, 0 ], \"targets\": [ 1 ] },\n\t\t *          { \"orderData\": 2, \"targets\": [ 2 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderData\": [ 0, 1 ] },\n\t\t *          { \"orderData\": [ 1, 0 ] },\n\t\t *          { \"orderData\": 2 },\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aDataSort\": null,\n\t\t\"iDataSort\": -1,\n\t\n\t\n\t\t/**\n\t\t * You can control the default ordering direction, and even alter the\n\t\t * behaviour of the sort handler (i.e. only allow ascending ordering etc)\n\t\t * using this parameter.\n\t\t *  @type array\n\t\t *  @default [ 'asc', 'desc' ]\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderSequence\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderSequence\": [ \"asc\" ], \"targets\": [ 1 ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ], \"targets\": [ 2 ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ], \"targets\": [ 3 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          { \"orderSequence\": [ \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ] },\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"asSorting\": [ 'asc', 'desc' ],\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering on the data in this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.searchable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"searchable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"searchable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSearchable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable ordering on this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.visible\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"visible\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"visible\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bVisible\": true,\n\t\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} td The TD node that has been created\n\t\t *  @param {*} cellData The Data for the cell\n\t\t *  @param {array|object} rowData The data for the whole row\n\t\t *  @param {int} row The row index for the aoData data store\n\t\t *  @param {int} col The column index for aoColumns\n\t\t *\n\t\t *  @name DataTable.defaults.column.createdCell\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [3],\n\t\t *          \"createdCell\": function (td, cellData, rowData, row, col) {\n\t\t *            if ( cellData == \"1.7\" ) {\n\t\t *              $(td).css('color', 'blue')\n\t\t *            }\n\t\t *          }\n\t\t *        } ]\n\t\t *      });\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter has been replaced by `data` in DataTables to ensure naming\n\t\t * consistency. `dataProp` can still be used, as there is backwards\n\t\t * compatibility in DataTables for this option, but it is strongly\n\t\t * recommended that you use `data` in preference to `dataProp`.\n\t\t *  @name DataTable.defaults.column.dataProp\n\t\t */\n\t\n\t\n\t\t/**\n\t\t * This property can be used to read data from any data source property,\n\t\t * including deeply nested objects / properties. `data` can be given in a\n\t\t * number of different ways which effect its behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object. Note that\n\t\t *      function notation is recommended for use in `render` rather than\n\t\t *      `data` as it is much simpler to use as a renderer.\n\t\t * * `null` - use the original data source for the row rather than plucking\n\t\t *   data directly from it. This action has effects on two other\n\t\t *   initialisation options:\n\t\t *    * `defaultContent` - When null is given as the `data` option and\n\t\t *      `defaultContent` is specified for the column, the value defined by\n\t\t *      `defaultContent` will be used for the cell.\n\t\t *    * `render` - When null is used for the `data` option and the `render`\n\t\t *      option is specified for the column, the whole data source for the\n\t\t *      row is used for the renderer.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * `{array|object}` The data source for the row\n\t\t *      * `{string}` The type call data requested - this will be 'set' when\n\t\t *        setting data or 'filter', 'display', 'type', 'sort' or undefined\n\t\t *        when gathering data. Note that when `undefined` is given for the\n\t\t *        type DataTables expects to get the raw data for the object back<\n\t\t *      * `{*}` Data to set when the second parameter is 'set'.\n\t\t *    * Return:\n\t\t *      * The return value from the function is not required when 'set' is\n\t\t *        the type of call, but otherwise the return is what will be used\n\t\t *        for the data requested.\n\t\t *\n\t\t * Note that `data` is a getter and setter option. If you just require\n\t\t * formatting of data for output, you will likely want to use `render` which\n\t\t * is simply a getter and thus simpler to use.\n\t\t *\n\t\t * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The\n\t\t * name change reflects the flexibility of this property and is consistent\n\t\t * with the naming of mRender. If 'mDataProp' is given, then it will still\n\t\t * be used by DataTables, as it automatically maps the old name to the new\n\t\t * if required.\n\t\t *\n\t\t *  @type string|int|function|null\n\t\t *  @default null <i>Use automatically calculated column index</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.data\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Read table data from objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {value},\n\t\t *    //      \"version\": {value},\n\t\t *    //      \"grade\": {value}\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/objects.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform\" },\n\t\t *          { \"data\": \"version\" },\n\t\t *          { \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Read information from deeply nested objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {\n\t\t *    //         \"inner\": {value}\n\t\t *    //      },\n\t\t *    //      \"details\": [\n\t\t *    //         {value}, {value}\n\t\t *    //      ]\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform.inner\" },\n\t\t *          { \"data\": \"details.0\" },\n\t\t *          { \"data\": \"details.1\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `data` as a function to provide different information for\n\t\t *    // sorting, filtering and display. In this case, currency (price)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": function ( source, type, val ) {\n\t\t *            if (type === 'set') {\n\t\t *              source.price = val;\n\t\t *              // Store the computed dislay and filter values for efficiency\n\t\t *              source.price_display = val==\"\" ? \"\" : \"$\"+numberFormat(val);\n\t\t *              source.price_filter  = val==\"\" ? \"\" : \"$\"+numberFormat(val)+\" \"+val;\n\t\t *              return;\n\t\t *            }\n\t\t *            else if (type === 'display') {\n\t\t *              return source.price_display;\n\t\t *            }\n\t\t *            else if (type === 'filter') {\n\t\t *              return source.price_filter;\n\t\t *            }\n\t\t *            // 'sort', 'type' and undefined all just use the integer\n\t\t *            return source.price;\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using default content\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null,\n\t\t *          \"defaultContent\": \"Click to edit\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using array notation - outputting a list from an array\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"name[, ]\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\n\t\t/**\n\t\t * This property is the rendering partner to `data` and it is suggested that\n\t\t * when you want to manipulate data for display (including filtering,\n\t\t * sorting etc) without altering the underlying data for the table, use this\n\t\t * property. `render` can be considered to be the the read only companion to\n\t\t * `data` which is read / write (then as such more complex). Like `data`\n\t\t * this option can be given in a number of different ways to effect its\n\t\t * behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object.\n\t\t * * `object` - use different data for the different data types requested by\n\t\t *   DataTables ('filter', 'display', 'type' or 'sort'). The property names\n\t\t *   of the object is the data type the property refers to and the value can\n\t\t *   defined using an integer, string or function using the same rules as\n\t\t *   `render` normally does. Note that an `_` option _must_ be specified.\n\t\t *   This is the default value to use if you haven't specified a value for\n\t\t *   the data type requested by DataTables.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * {array|object} The data source for the row (based on `data`)\n\t\t *      * {string} The type call data requested - this will be 'filter',\n\t\t *        'display', 'type' or 'sort'.\n\t\t *      * {array|object} The full data source for the row (not based on\n\t\t *        `data`)\n\t\t *    * Return:\n\t\t *      * The return value from the function is what will be used for the\n\t\t *        data requested.\n\t\t *\n\t\t *  @type string|int|function|object|null\n\t\t *  @default null Use the data source value.\n\t\t *\n\t\t *  @name DataTable.defaults.column.render\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Create a comma separated list from an array of objects\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          {\n\t\t *            \"data\": \"platform\",\n\t\t *            \"render\": \"[, ].name\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Execute a function to obtain data\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": \"browserName()\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // As an object, extracting different data for the different types\n\t\t *    // This would be used with a data source such as:\n\t\t *    //   { \"phone\": 5552368, \"phone_filter\": \"5552368 555-2368\", \"phone_display\": \"555-2368\" }\n\t\t *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`\n\t\t *    // (which has both forms) is used for filtering for if a user inputs either format, while\n\t\t *    // the formatted phone number is the one that is shown in the table.\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": {\n\t\t *            \"_\": \"phone\",\n\t\t *            \"filter\": \"phone_filter\",\n\t\t *            \"display\": \"phone_display\"\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Use as a function to create a link from the data source\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"download_link\",\n\t\t *          \"render\": function ( data, type, full ) {\n\t\t *            return '<a href=\"'+data+'\">Download</a>';\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\n\t\t/**\n\t\t * Change the cell type created for the column - either TD cells or TH cells. This\n\t\t * can be useful as TH cells have semantic meaning in the table body, allowing them\n\t\t * to act as a header for a row (you may wish to add scope='row' to the TH elements).\n\t\t *  @type string\n\t\t *  @default td\n\t\t *\n\t\t *  @name DataTable.defaults.column.cellType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Make the first column use TH cells\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"cellType\": \"th\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sCellType\": \"td\",\n\t\n\t\n\t\t/**\n\t\t * Class to give to each cell in this column.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.class\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"class\": \"my_class\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"class\": \"my_class\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sClass\": \"\",\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t * Generally you shouldn't need this!\n\t\t *  @type string\n\t\t *  @default <i>Empty string<i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.contentPadding\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"contentPadding\": \"mmm\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sContentPadding\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because `data`\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.column.defaultContent\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\",\n\t\t *            \"targets\": [ -1 ]\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter is only used in DataTables' server-side processing. It can\n\t\t * be exceptionally useful to know what columns are being displayed on the\n\t\t * client side, and to map these to database fields. When defined, the names\n\t\t * also allow DataTables to reorder information from the server if it comes\n\t\t * back in an unexpected order (i.e. if you switch your columns around on the\n\t\t * client-side, your server-side code does not also need updating).\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.name\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"name\": \"engine\", \"targets\": [ 0 ] },\n\t\t *          { \"name\": \"browser\", \"targets\": [ 1 ] },\n\t\t *          { \"name\": \"platform\", \"targets\": [ 2 ] },\n\t\t *          { \"name\": \"version\", \"targets\": [ 3 ] },\n\t\t *          { \"name\": \"grade\", \"targets\": [ 4 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"name\": \"engine\" },\n\t\t *          { \"name\": \"browser\" },\n\t\t *          { \"name\": \"platform\" },\n\t\t *          { \"name\": \"version\" },\n\t\t *          { \"name\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sName\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Defines a data source type for the ordering which can be used to read\n\t\t * real-time information from the table (updating the internally cached\n\t\t * version) prior to ordering. This allows ordering to occur on user\n\t\t * editable elements such as form inputs.\n\t\t *  @type string\n\t\t *  @default std\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderDataType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderDataType\": \"dom-text\", \"targets\": [ 2, 3 ] },\n\t\t *          { \"type\": \"numeric\", \"targets\": [ 3 ] },\n\t\t *          { \"orderDataType\": \"dom-select\", \"targets\": [ 4 ] },\n\t\t *          { \"orderDataType\": \"dom-checkbox\", \"targets\": [ 5 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          { \"orderDataType\": \"dom-text\" },\n\t\t *          { \"orderDataType\": \"dom-text\", \"type\": \"numeric\" },\n\t\t *          { \"orderDataType\": \"dom-select\" },\n\t\t *          { \"orderDataType\": \"dom-checkbox\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sSortDataType\": \"std\",\n\t\n\t\n\t\t/**\n\t\t * The title of this column.\n\t\t *  @type string\n\t\t *  @default null <i>Derived from the 'TH' value for this column in the\n\t\t *    original HTML table.</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.title\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"title\": \"My column title\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"My column title\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\n\t\t/**\n\t\t * The type allows you to specify how the data for this column will be\n\t\t * ordered. Four types (string, numeric, date and html (which will strip\n\t\t * HTML tags before ordering)) are currently available. Note that only date\n\t\t * formats understood by Javascript's Date() object will be accepted as type\n\t\t * date. For example: \"Mar 26, 2008 5:03 PM\". May take the values: 'string',\n\t\t * 'numeric', 'date' or 'html' (by default). Further types can be adding\n\t\t * through plug-ins.\n\t\t *  @type string\n\t\t *  @default null <i>Auto-detected from raw data</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.type\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"type\": \"html\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"type\": \"html\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\n\t\t/**\n\t\t * Defining the width of the column, this parameter may take any CSS value\n\t\t * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not\n\t\t * been given a specific width through this interface ensuring that the table\n\t\t * remains readable.\n\t\t *  @type string\n\t\t *  @default null <i>Automatic</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.width\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"width\": \"20%\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"width\": \"20%\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sWidth\": null\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults.column );\n\t\n\t\n\t\n\t/**\n\t * DataTables settings object - this holds all the information needed for a\n\t * given table, including configuration, data and current application of the\n\t * table options. DataTables does not have a single instance for each DataTable\n\t * with the settings attached to that instance, but rather instances of the\n\t * DataTable \"class\" are created on-the-fly as needed (typically by a\n\t * $().dataTable() call) and the settings object is then applied to that\n\t * instance.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults} but this\n\t * one is the internal data store for DataTables's cache of columns. It should\n\t * NOT be manipulated outside of DataTables. Any configuration should be done\n\t * through the initialisation options.\n\t *  @namespace\n\t *  @todo Really should attach the settings object to individual instances so we\n\t *    don't need to create new instances on each $().dataTable() call (if the\n\t *    table already exists). It would also save passing oSettings around and\n\t *    into every single function. However, this is a very significant\n\t *    architecture change for DataTables and will almost certainly break\n\t *    backwards compatibility with older installations. This is something that\n\t *    will be done in 2.0.\n\t */\n\tDataTable.models.oSettings = {\n\t\t/**\n\t\t * Primary features of DataTables and their enablement state.\n\t\t *  @namespace\n\t\t */\n\t\t\"oFeatures\": {\n\t\n\t\t\t/**\n\t\t\t * Flag to say if DataTables should automatically try to calculate the\n\t\t\t * optimum table and columns widths (true) or not (false).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bAutoWidth\": null,\n\t\n\t\t\t/**\n\t\t\t * Delay the creation of TR and TD elements until they are actually\n\t\t\t * needed by a driven page draw. This can give a significant speed\n\t\t\t * increase for Ajax source and Javascript source data, but makes no\n\t\t\t * difference at all fro DOM and server-side processing tables.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bDeferRender\": null,\n\t\n\t\t\t/**\n\t\t\t * Enable filtering on the table or not. Note that if this is disabled\n\t\t\t * then there is no filtering at all on the table, including fnFilter.\n\t\t\t * To just remove the filtering input use sDom and remove the 'f' option.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bFilter\": null,\n\t\n\t\t\t/**\n\t\t\t * Table information element (the 'Showing x of y records' div) enable\n\t\t\t * flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bInfo\": null,\n\t\n\t\t\t/**\n\t\t\t * Present a user control allowing the end user to change the page size\n\t\t\t * when pagination is enabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bLengthChange\": null,\n\t\n\t\t\t/**\n\t\t\t * Pagination enabled or not. Note that if this is disabled then length\n\t\t\t * changing must also be disabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bPaginate\": null,\n\t\n\t\t\t/**\n\t\t\t * Processing indicator enable flag whenever DataTables is enacting a\n\t\t\t * user request - typically an Ajax request for server-side processing.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bProcessing\": null,\n\t\n\t\t\t/**\n\t\t\t * Server-side processing enabled flag - when enabled DataTables will\n\t\t\t * get all data from the server for every draw - there is no filtering,\n\t\t\t * sorting or paging done on the client-side.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bServerSide\": null,\n\t\n\t\t\t/**\n\t\t\t * Sorting enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSort\": null,\n\t\n\t\t\t/**\n\t\t\t * Multi-column sorting\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortMulti\": null,\n\t\n\t\t\t/**\n\t\t\t * Apply a class to the columns which are being sorted to provide a\n\t\t\t * visual highlight or not. This can slow things down when enabled since\n\t\t\t * there is a lot of DOM interaction.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortClasses\": null,\n\t\n\t\t\t/**\n\t\t\t * State saving enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bStateSave\": null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Scrolling settings for a table.\n\t\t *  @namespace\n\t\t */\n\t\t\"oScroll\": {\n\t\t\t/**\n\t\t\t * When the table is shorter in height than sScrollY, collapse the\n\t\t\t * table container down to the height of the table (when true).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bCollapse\": null,\n\t\n\t\t\t/**\n\t\t\t * Width of the scrollbar for the web-browser's platform. Calculated\n\t\t\t * during table initialisation.\n\t\t\t *  @type int\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"iBarWidth\": 0,\n\t\n\t\t\t/**\n\t\t\t * Viewport width for horizontal scrolling. Horizontal scrolling is\n\t\t\t * disabled if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sX\": null,\n\t\n\t\t\t/**\n\t\t\t * Width to expand the table to when using x-scrolling. Typically you\n\t\t\t * should not need to use this.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t *  @deprecated\n\t\t\t */\n\t\t\t\"sXInner\": null,\n\t\n\t\t\t/**\n\t\t\t * Viewport height for vertical scrolling. Vertical scrolling is disabled\n\t\t\t * if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sY\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Language information for the table.\n\t\t *  @namespace\n\t\t *  @extends DataTable.defaults.oLanguage\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Information callback function. See\n\t\t\t * {@link DataTable.defaults.fnInfoCallback}\n\t\t\t *  @type function\n\t\t\t *  @default null\n\t\t\t */\n\t\t\t\"fnInfoCallback\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Browser support parameters\n\t\t *  @namespace\n\t\t */\n\t\t\"oBrowser\": {\n\t\t\t/**\n\t\t\t * Indicate if the browser incorrectly calculates width:100% inside a\n\t\t\t * scrolling element (IE6/7)\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollOversize\": false,\n\t\n\t\t\t/**\n\t\t\t * Determine if the vertical scrollbar is on the right or left of the\n\t\t\t * scrolling container - needed for rtl language layout, although not\n\t\t\t * all browsers move the scrollbar (Safari).\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollbarLeft\": false,\n\t\n\t\t\t/**\n\t\t\t * Flag for if `getBoundingClientRect` is fully supported or not\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bBounding\": false,\n\t\n\t\t\t/**\n\t\t\t * Browser scrollbar width\n\t\t\t *  @type integer\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"barWidth\": 0\n\t\t},\n\t\n\t\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * Array referencing the nodes which are used for the features. The\n\t\t * parameters of this object match what is allowed by sDom - i.e.\n\t\t *   <ul>\n\t\t *     <li>'l' - Length changing</li>\n\t\t *     <li>'f' - Filtering input</li>\n\t\t *     <li>'t' - The table!</li>\n\t\t *     <li>'i' - Information</li>\n\t\t *     <li>'p' - Pagination</li>\n\t\t *     <li>'r' - pRocessing</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aanFeatures\": [],\n\t\n\t\t/**\n\t\t * Store data information - see {@link DataTable.models.oRow} for detailed\n\t\t * information.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoData\": [],\n\t\n\t\t/**\n\t\t * Array of indexes which are in the current display (after filtering etc)\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplay\": [],\n\t\n\t\t/**\n\t\t * Array of indexes for display - no filtering\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplayMaster\": [],\n\t\n\t\t/**\n\t\t * Map of row ids to data indexes\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"aIds\": {},\n\t\n\t\t/**\n\t\t * Store information about each column that is in use\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoColumns\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's header\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeader\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's footer\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooter\": [],\n\t\n\t\t/**\n\t\t * Store the applied global search information in case we want to force a\n\t\t * research or compare the old search to a new one.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t */\n\t\t\"oPreviousSearch\": {},\n\t\n\t\t/**\n\t\t * Store the applied search for each column - see\n\t\t * {@link DataTable.models.oSearch} for the format that is used for the\n\t\t * filtering information for each column.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreSearchCols\": [],\n\t\n\t\t/**\n\t\t * Sorting that is applied to the table. Note that the inner arrays are\n\t\t * used in the following manner:\n\t\t * <ul>\n\t\t *   <li>Index 0 - column number</li>\n\t\t *   <li>Index 1 - current sorting direction</li>\n\t\t * </ul>\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @todo These inner arrays should really be objects\n\t\t */\n\t\t\"aaSorting\": null,\n\t\n\t\t/**\n\t\t * Sorting that is always applied to the table (i.e. prefixed in front of\n\t\t * aaSorting).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\t/**\n\t\t * Classes to use for the striping of a table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its striping classes as well\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asDestroyStripes\": [],\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its width\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"sDestroyWidth\": 0,\n\t\n\t\t/**\n\t\t * Callback functions array for every time a row is inserted (i.e. on a draw).\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for the header on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeaderCallback\": [],\n\t\n\t\t/**\n\t\t * Callback function for the footer on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooterCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for draw callback functions\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for row created function\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCreatedCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for just before the table is redrawn. A return of\n\t\t * false will be used to cancel the draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for when the table has been initialised.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoInitComplete\": [],\n\t\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings to be stored for state saving, prior to\n\t\t * saving state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSaveParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings that have been stored for state saving\n\t\t * prior to using the stored values to restore the state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoadParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for operating on the settings object once the saved state has been\n\t\t * loaded\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoaded\": [],\n\t\n\t\t/**\n\t\t * Cache the table ID for quick access\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sTableId\": \"\",\n\t\n\t\t/**\n\t\t * The TABLE node for the main table\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTable\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the thead element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTHead\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tfoot element - if it exists\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTFoot\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tbody element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTBody\": null,\n\t\n\t\t/**\n\t\t * Cache the wrapper node (contains all DataTables controlled elements)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTableWrapper\": null,\n\t\n\t\t/**\n\t\t * Indicate if when using server-side processing the loading of data\n\t\t * should be deferred until the second draw.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDeferLoading\": false,\n\t\n\t\t/**\n\t\t * Indicate if all required information has been read in\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bInitialised\": false,\n\t\n\t\t/**\n\t\t * Information about open rows. Each object in the array has the parameters\n\t\t * 'nTr' and 'nParent'\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoOpenRows\": [],\n\t\n\t\t/**\n\t\t * Dictate the positioning of DataTables' control elements - see\n\t\t * {@link DataTable.model.oInit.sDom}.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDom\": null,\n\t\n\t\t/**\n\t\t * Search delay (in mS)\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\t/**\n\t\t * Which type of pagination should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default two_button\n\t\t */\n\t\t\"sPaginationType\": \"two_button\",\n\t\n\t\t/**\n\t\t * The state duration (for `stateSave`) in seconds.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iStateDuration\": 0,\n\t\n\t\t/**\n\t\t * Array of callback functions for state saving. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the JSON string to save that has been thus far created. Returns\n\t\t *       a JSON string to be inserted into a json object\n\t\t *       (i.e. '\"param\": [ 0, 1, 2]')</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSave\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for state loading. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the object stored. May return false to cancel state loading</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoad\": [],\n\t\n\t\t/**\n\t\t * State that was saved. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oSavedState\": null,\n\t\n\t\t/**\n\t\t * State that was loaded. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oLoadedState\": null,\n\t\n\t\t/**\n\t\t * Source url for AJAX data for the table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\t/**\n\t\t * Property from a given object from which to read the table data from. This\n\t\t * can be an empty string (when not server-side processing), in which case\n\t\t * it is  assumed an an array is given directly.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sAjaxDataProp\": null,\n\t\n\t\t/**\n\t\t * Note if draw should be blocked while getting data\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bAjaxDataGet\": true,\n\t\n\t\t/**\n\t\t * The last jQuery XHR object that was used for server-side data gathering.\n\t\t * This can be used for working with the XHR information in one of the\n\t\t * callbacks\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"jqXHR\": null,\n\t\n\t\t/**\n\t\t * JSON returned from the server in the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"json\": undefined,\n\t\n\t\t/**\n\t\t * Data submitted as part of the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"oAjaxData\": undefined,\n\t\n\t\t/**\n\t\t * Function to get the server-side data.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\t/**\n\t\t * Functions which are called prior to sending an Ajax request so extra\n\t\t * parameters can easily be sent to the server\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoServerParams\": [],\n\t\n\t\t/**\n\t\t * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if\n\t\t * required).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sServerMethod\": null,\n\t\n\t\t/**\n\t\t * Format numbers for display.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnFormatNumber\": null,\n\t\n\t\t/**\n\t\t * List of options that can be used for the user selectable length menu.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLengthMenu\": null,\n\t\n\t\t/**\n\t\t * Counter for the draws that the table does. Also used as a tracker for\n\t\t * server-side processing\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iDraw\": 0,\n\t\n\t\t/**\n\t\t * Indicate if a redraw is being done - useful for Ajax\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDrawing\": false,\n\t\n\t\t/**\n\t\t * Draw index (iDraw) of the last error when parsing the returned data\n\t\t *  @type int\n\t\t *  @default -1\n\t\t */\n\t\t\"iDrawError\": -1,\n\t\n\t\t/**\n\t\t * Paging display length\n\t\t *  @type int\n\t\t *  @default 10\n\t\t */\n\t\t\"_iDisplayLength\": 10,\n\t\n\t\t/**\n\t\t * Paging start point - aiDisplay index\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"_iDisplayStart\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the result set\n\t\t * (i.e. before filtering), Use fnRecordsTotal rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsTotal\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the current display set\n\t\t * (i.e. after filtering). Use fnRecordsDisplay rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type boolean\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsDisplay\": 0,\n\t\n\t\t/**\n\t\t * The classes to use for the table\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if filtering has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bFiltered\": false,\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if sorting has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bSorted\": false,\n\t\n\t\t/**\n\t\t * Indicate that if multiple rows are in the header and there is more than\n\t\t * one unique cell per column, if the top one (true) or bottom one (false)\n\t\t * should be used for sorting / title by DataTables.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortCellsTop\": null,\n\t\n\t\t/**\n\t\t * Initialisation object that is used for the table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInit\": null,\n\t\n\t\t/**\n\t\t * Destroy callback functions - for plug-ins to attach themselves to the\n\t\t * destroy so they can clean up markup and events.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDestroyCallback\": [],\n\t\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, before filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsTotal\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsTotal * 1 :\n\t\t\t\tthis.aiDisplayMaster.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, after filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsDisplay\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsDisplay * 1 :\n\t\t\t\tthis.aiDisplay.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the display end point - aiDisplay index\n\t\t *  @type function\n\t\t */\n\t\t\"fnDisplayEnd\": function ()\n\t\t{\n\t\t\tvar\n\t\t\t\tlen      = this._iDisplayLength,\n\t\t\t\tstart    = this._iDisplayStart,\n\t\t\t\tcalc     = start + len,\n\t\t\t\trecords  = this.aiDisplay.length,\n\t\t\t\tfeatures = this.oFeatures,\n\t\t\t\tpaginate = features.bPaginate;\n\t\n\t\t\tif ( features.bServerSide ) {\n\t\t\t\treturn paginate === false || len === -1 ?\n\t\t\t\t\tstart + records :\n\t\t\t\t\tMath.min( start+len, this._iRecordsDisplay );\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn ! paginate || calc>records || len===-1 ?\n\t\t\t\t\trecords :\n\t\t\t\t\tcalc;\n\t\t\t}\n\t\t},\n\t\n\t\t/**\n\t\t * The DataTables object for this table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInstance\": null,\n\t\n\t\t/**\n\t\t * Unique identifier for each instance of the DataTables object. If there\n\t\t * is an ID on the table node, then it takes that value, otherwise an\n\t\t * incrementing internal counter is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sInstance\": null,\n\t\n\t\t/**\n\t\t * tabindex attribute value that is added to DataTables control elements, allowing\n\t\t * keyboard navigation of the table and its controls.\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollHead\": null,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollFoot\": null,\n\t\n\t\t/**\n\t\t * Last applied sort\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLastSort\": [],\n\t\n\t\t/**\n\t\t * Stored plug-in instances\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oPlugins\": {},\n\t\n\t\t/**\n\t\t * Function used to get a row's id from the row's data\n\t\t *  @type function\n\t\t *  @default null\n\t\t */\n\t\t\"rowIdFn\": null,\n\t\n\t\t/**\n\t\t * Data location where to store a row's id\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"rowId\": null\n\t};\n\n\t/**\n\t * Extension object for DataTables that is used to provide all extension\n\t * options.\n\t *\n\t * Note that the `DataTable.ext` object is available through\n\t * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is\n\t * also aliased to `jQuery.fn.dataTableExt` for historic reasons.\n\t *  @namespace\n\t *  @extends DataTable.models.ext\n\t */\n\t\n\t\n\t/**\n\t * DataTables extensions\n\t * \n\t * This namespace acts as a collection area for plug-ins that can be used to\n\t * extend DataTables capabilities. Indeed many of the build in methods\n\t * use this method to provide their own capabilities (sorting methods for\n\t * example).\n\t *\n\t * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy\n\t * reasons\n\t *\n\t *  @namespace\n\t */\n\tDataTable.ext = _ext = {\n\t\t/**\n\t\t * Buttons. For use with the Buttons extension for DataTables. This is\n\t\t * defined here so other extensions can define buttons regardless of load\n\t\t * order. It is _not_ used by DataTables core.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tbuttons: {},\n\t\n\t\n\t\t/**\n\t\t * Element class names\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tclasses: {},\n\t\n\t\n\t\t/**\n\t\t * DataTables build type (expanded by the download builder)\n\t\t *\n\t\t *  @type string\n\t\t */\n\t\tbuilder: \"-source-\",\n\t\n\t\n\t\t/**\n\t\t * Error reporting.\n\t\t * \n\t\t * How should DataTables report an error. Can take the value 'alert',\n\t\t * 'throw', 'none' or a function.\n\t\t *\n\t\t *  @type string|function\n\t\t *  @default alert\n\t\t */\n\t\terrMode: \"alert\",\n\t\n\t\n\t\t/**\n\t\t * Feature plug-ins.\n\t\t * \n\t\t * This is an array of objects which describe the feature plug-ins that are\n\t\t * available to DataTables. These feature plug-ins are then available for\n\t\t * use through the `dom` initialisation option.\n\t\t * \n\t\t * Each feature plug-in is described by an object which must have the\n\t\t * following properties:\n\t\t * \n\t\t * * `fnInit` - function that is used to initialise the plug-in,\n\t\t * * `cFeature` - a character so the feature can be enabled by the `dom`\n\t\t *   instillation option. This is case sensitive.\n\t\t *\n\t\t * The `fnInit` function has the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *\n\t\t * And the following return is expected:\n\t\t * \n\t\t * * {node|null} The element which contains your feature. Note that the\n\t\t *   return may also be void if your plug-in does not require to inject any\n\t\t *   DOM elements into DataTables control (`dom`) - for example this might\n\t\t *   be useful when developing a plug-in which allows table control via\n\t\t *   keyboard entry\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    $.fn.dataTable.ext.features.push( {\n\t\t *      \"fnInit\": function( oSettings ) {\n\t\t *        return new TableTools( { \"oDTSettings\": oSettings } );\n\t\t *      },\n\t\t *      \"cFeature\": \"T\"\n\t\t *    } );\n\t\t */\n\t\tfeature: [],\n\t\n\t\n\t\t/**\n\t\t * Row searching.\n\t\t * \n\t\t * This method of searching is complimentary to the default type based\n\t\t * searching, and a lot more comprehensive as it allows you complete control\n\t\t * over the searching logic. Each element in this array is a function\n\t\t * (parameters described below) that is called for every row in the table,\n\t\t * and your logic decides if it should be included in the searching data set\n\t\t * or not.\n\t\t *\n\t\t * Searching functions have the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{array|object}` Data for the row to be processed (same as the\n\t\t *    original format that was passed in as the data source, or an array\n\t\t *    from a DOM data source\n\t\t * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which\n\t\t *    can be useful to retrieve the `TR` element if you need DOM interaction.\n\t\t *\n\t\t * And the following return is expected:\n\t\t *\n\t\t * * {boolean} Include the row in the searched result set (true) or not\n\t\t *   (false)\n\t\t *\n\t\t * Note that as with the main search ability in DataTables, technically this\n\t\t * is \"filtering\", since it is subtractive. However, for consistency in\n\t\t * naming we call it searching here.\n\t\t *\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @example\n\t\t *    // The following example shows custom search being applied to the\n\t\t *    // fourth column (i.e. the data[3] index) based on two input values\n\t\t *    // from the end-user, matching the data in a certain range.\n\t\t *    $.fn.dataTable.ext.search.push(\n\t\t *      function( settings, data, dataIndex ) {\n\t\t *        var min = document.getElementById('min').value * 1;\n\t\t *        var max = document.getElementById('max').value * 1;\n\t\t *        var version = data[3] == \"-\" ? 0 : data[3]*1;\n\t\t *\n\t\t *        if ( min == \"\" && max == \"\" ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min == \"\" && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && \"\" == max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        return false;\n\t\t *      }\n\t\t *    );\n\t\t */\n\t\tsearch: [],\n\t\n\t\n\t\t/**\n\t\t * Selector extensions\n\t\t *\n\t\t * The `selector` option can be used to extend the options available for the\n\t\t * selector modifier options (`selector-modifier` object data type) that\n\t\t * each of the three built in selector types offer (row, column and cell +\n\t\t * their plural counterparts). For example the Select extension uses this\n\t\t * mechanism to provide an option to select only rows, columns and cells\n\t\t * that have been marked as selected by the end user (`{selected: true}`),\n\t\t * which can be used in conjunction with the existing built in selector\n\t\t * options.\n\t\t *\n\t\t * Each property is an array to which functions can be pushed. The functions\n\t\t * take three attributes:\n\t\t *\n\t\t * * Settings object for the host table\n\t\t * * Options object (`selector-modifier` object type)\n\t\t * * Array of selected item indexes\n\t\t *\n\t\t * The return is an array of the resulting item indexes after the custom\n\t\t * selector has been applied.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tselector: {\n\t\t\tcell: [],\n\t\t\tcolumn: [],\n\t\t\trow: []\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Internal functions, exposed for used in plug-ins.\n\t\t * \n\t\t * Please note that you should not need to use the internal methods for\n\t\t * anything other than a plug-in (and even then, try to avoid if possible).\n\t\t * The internal function may change between releases.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tinternal: {},\n\t\n\t\n\t\t/**\n\t\t * Legacy configuration options. Enable and disable legacy options that\n\t\t * are available in DataTables.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tlegacy: {\n\t\t\t/**\n\t\t\t * Enable / disable DataTables 1.9 compatible server-side processing\n\t\t\t * requests\n\t\t\t *\n\t\t\t *  @type boolean\n\t\t\t *  @default null\n\t\t\t */\n\t\t\tajax: null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Pagination plug-in methods.\n\t\t * \n\t\t * Each entry in this object is a function and defines which buttons should\n\t\t * be shown by the pagination rendering method that is used for the table:\n\t\t * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the\n\t\t * buttons are displayed in the document, while the functions here tell it\n\t\t * what buttons to display. This is done by returning an array of button\n\t\t * descriptions (what each button will do).\n\t\t *\n\t\t * Pagination types (the four built in options and any additional plug-in\n\t\t * options defined here) can be used through the `paginationType`\n\t\t * initialisation parameter.\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{int} page` The current page index\n\t\t * 2. `{int} pages` The number of pages in the table\n\t\t *\n\t\t * Each function is expected to return an array where each element of the\n\t\t * array can be one of:\n\t\t *\n\t\t * * `first` - Jump to first page when activated\n\t\t * * `last` - Jump to last page when activated\n\t\t * * `previous` - Show previous page when activated\n\t\t * * `next` - Show next page when activated\n\t\t * * `{int}` - Show page of the index given\n\t\t * * `{array}` - A nested array containing the above elements to add a\n\t\t *   containing 'DIV' element (might be useful for styling).\n\t\t *\n\t\t * Note that DataTables v1.9- used this object slightly differently whereby\n\t\t * an object with two functions would be defined for each plug-in. That\n\t\t * ability is still supported by DataTables 1.10+ to provide backwards\n\t\t * compatibility, but this option of use is now decremented and no longer\n\t\t * documented in DataTables 1.10+.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t *\n\t\t *  @example\n\t\t *    // Show previous, next and current page buttons only\n\t\t *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {\n\t\t *      return [ 'previous', page, 'next' ];\n\t\t *    };\n\t\t */\n\t\tpager: {},\n\t\n\t\n\t\trenderer: {\n\t\t\tpageButton: {},\n\t\t\theader: {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Ordering plug-ins - custom data source\n\t\t * \n\t\t * The extension options for ordering of data available here is complimentary\n\t\t * to the default type based ordering that DataTables typically uses. It\n\t\t * allows much greater control over the the data that is being used to\n\t\t * order a column, but is necessarily therefore more complex.\n\t\t * \n\t\t * This type of ordering is useful if you want to do ordering based on data\n\t\t * live from the DOM (for example the contents of an 'input' element) rather\n\t\t * than just the static string that DataTables knows of.\n\t\t * \n\t\t * The way these plug-ins work is that you create an array of the values you\n\t\t * wish to be ordering for the column in question and then return that\n\t\t * array. The data in the array much be in the index order of the rows in\n\t\t * the table (not the currently ordering order!). Which order data gathering\n\t\t * function is run here depends on the `dt-init columns.orderDataType`\n\t\t * parameter that is used for the column (if any).\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{int}` Target column index\n\t\t *\n\t\t * Each function is expected to return an array:\n\t\t *\n\t\t * * `{array}` Data for the column to be ordering upon\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    // Ordering using `input` node values\n\t\t *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )\n\t\t *    {\n\t\t *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {\n\t\t *        return $('input', td).val();\n\t\t *      } );\n\t\t *    }\n\t\t */\n\t\torder: {},\n\t\n\t\n\t\t/**\n\t\t * Type based plug-ins.\n\t\t *\n\t\t * Each column in DataTables has a type assigned to it, either by automatic\n\t\t * detection or by direct assignment using the `type` option for the column.\n\t\t * The type of a column will effect how it is ordering and search (plug-ins\n\t\t * can also make use of the column type if required).\n\t\t *\n\t\t * @namespace\n\t\t */\n\t\ttype: {\n\t\t\t/**\n\t\t\t * Type detection functions.\n\t\t\t *\n\t\t\t * The functions defined in this object are used to automatically detect\n\t\t\t * a column's type, making initialisation of DataTables super easy, even\n\t\t\t * when complex data is in the table.\n\t\t\t *\n\t\t\t * The functions defined take two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be analysed\n\t\t     *  2. `{settings}` DataTables settings object. This can be used to\n\t\t     *     perform context specific type detection - for example detection\n\t\t     *     based on language settings such as using a comma for a decimal\n\t\t     *     place. Generally speaking the options from the settings will not\n\t\t     *     be required\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Data type detected, or null if unknown (and thus\n\t\t\t *   pass it on to the other type detection functions.\n\t\t\t *\n\t\t\t *  @type array\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Currency type detection plug-in:\n\t\t\t *    $.fn.dataTable.ext.type.detect.push(\n\t\t\t *      function ( data, settings ) {\n\t\t\t *        // Check the numeric part\n\t\t\t *        if ( ! data.substring(1).match(/[0-9]/) ) {\n\t\t\t *          return null;\n\t\t\t *        }\n\t\t\t *\n\t\t\t *        // Check prefixed by currency\n\t\t\t *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {\n\t\t\t *          return 'currency';\n\t\t\t *        }\n\t\t\t *        return null;\n\t\t\t *      }\n\t\t\t *    );\n\t\t\t */\n\t\t\tdetect: [],\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based search formatting.\n\t\t\t *\n\t\t\t * The type based searching functions can be used to pre-format the\n\t\t\t * data to be search on. For example, it can be used to strip HTML\n\t\t\t * tags or to de-format telephone numbers for numeric only searching.\n\t\t\t *\n\t\t\t * Note that is a search is not defined for a column of a given type,\n\t\t\t * no search formatting will be performed.\n\t\t\t * \n\t\t\t * Pre-processing of searching data plug-ins - When you assign the sType\n\t\t\t * for a column (or have it automatically detected for you by DataTables\n\t\t\t * or a type detection plug-in), you will typically be using this for\n\t\t\t * custom sorting, but it can also be used to provide custom searching\n\t\t\t * by allowing you to pre-processing the data and returning the data in\n\t\t\t * the format that should be searched upon. This is done by adding\n\t\t\t * functions this object with a parameter name which matches the sType\n\t\t\t * for that target column. This is the corollary of <i>afnSortData</i>\n\t\t\t * for searching data.\n\t\t\t *\n\t\t\t * The functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for searching\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Formatted string that will be used for the searching.\n\t\t\t *\n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {\n\t\t\t *      return d.replace(/\\n/g,\" \").replace( /<.*?>/g, \"\" );\n\t\t\t *    }\n\t\t\t */\n\t\t\tsearch: {},\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based ordering.\n\t\t\t *\n\t\t\t * The column type tells DataTables what ordering to apply to the table\n\t\t\t * when a column is sorted upon. The order for each type that is defined,\n\t\t\t * is defined by the functions available in this object.\n\t\t\t *\n\t\t\t * Each ordering option can be described by three properties added to\n\t\t\t * this object:\n\t\t\t *\n\t\t\t * * `{type}-pre` - Pre-formatting function\n\t\t\t * * `{type}-asc` - Ascending order function\n\t\t\t * * `{type}-desc` - Descending order function\n\t\t\t *\n\t\t\t * All three can be used together, only `{type}-pre` or only\n\t\t\t * `{type}-asc` and `{type}-desc` together. It is generally recommended\n\t\t\t * that only `{type}-pre` is used, as this provides the optimal\n\t\t\t * implementation in terms of speed, although the others are provided\n\t\t\t * for compatibility with existing Javascript sort functions.\n\t\t\t *\n\t\t\t * `{type}-pre`: Functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for ordering\n\t\t\t *\n\t\t\t * And return:\n\t\t\t *\n\t\t\t * * `{*}` Data to be sorted upon\n\t\t\t *\n\t\t\t * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort\n\t\t\t * functions, taking two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data to compare to the second parameter\n\t\t     *  2. `{*}` Data to compare to the first parameter\n\t\t\t *\n\t\t\t * And returning:\n\t\t\t *\n\t\t\t * * `{*}` Ordering match: <0 if first parameter should be sorted lower\n\t\t\t *   than the second parameter, ===0 if the two parameters are equal and\n\t\t\t *   >0 if the first parameter should be sorted height than the second\n\t\t\t *   parameter.\n\t\t\t * \n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Numeric ordering of formatted numbers with a pre-formatter\n\t\t\t *    $.extend( $.fn.dataTable.ext.type.order, {\n\t\t\t *      \"string-pre\": function(x) {\n\t\t\t *        a = (a === \"-\" || a === \"\") ? 0 : a.replace( /[^\\d\\-\\.]/g, \"\" );\n\t\t\t *        return parseFloat( a );\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Case-sensitive string ordering, with no pre-formatting method\n\t\t\t *    $.extend( $.fn.dataTable.ext.order, {\n\t\t\t *      \"string-case-asc\": function(x,y) {\n\t\t\t *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t\t *      },\n\t\t\t *      \"string-case-desc\": function(x,y) {\n\t\t\t *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t */\n\t\t\torder: {}\n\t\t},\n\t\n\t\t/**\n\t\t * Unique DataTables instance counter\n\t\t *\n\t\t * @type int\n\t\t * @private\n\t\t */\n\t\t_unique: 0,\n\t\n\t\n\t\t//\n\t\t// Depreciated\n\t\t// The following properties are retained for backwards compatiblity only.\n\t\t// The should not be used in new projects and will be removed in a future\n\t\t// version\n\t\t//\n\t\n\t\t/**\n\t\t * Version check function.\n\t\t *  @type function\n\t\t *  @depreciated Since 1.10\n\t\t */\n\t\tfnVersionCheck: DataTable.fnVersionCheck,\n\t\n\t\n\t\t/**\n\t\t * Index for what 'this' index API functions should use\n\t\t *  @type int\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tiApiIndex: 0,\n\t\n\t\n\t\t/**\n\t\t * jQuery UI class container\n\t\t *  @type object\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\toJUIClasses: {},\n\t\n\t\n\t\t/**\n\t\t * Software version\n\t\t *  @type string\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tsVersion: DataTable.version\n\t};\n\t\n\t\n\t//\n\t// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts\n\t//\n\t$.extend( _ext, {\n\t\tafnFiltering: _ext.search,\n\t\taTypes:       _ext.type.detect,\n\t\tofnSearch:    _ext.type.search,\n\t\toSort:        _ext.type.order,\n\t\tafnSortData:  _ext.order,\n\t\taoFeatures:   _ext.feature,\n\t\toApi:         _ext.internal,\n\t\toStdClasses:  _ext.classes,\n\t\toPagination:  _ext.pager\n\t} );\n\t\n\t\n\t$.extend( DataTable.ext.classes, {\n\t\t\"sTable\": \"dataTable\",\n\t\t\"sNoFooter\": \"no-footer\",\n\t\n\t\t/* Paging buttons */\n\t\t\"sPageButton\": \"paginate_button\",\n\t\t\"sPageButtonActive\": \"current\",\n\t\t\"sPageButtonDisabled\": \"disabled\",\n\t\n\t\t/* Striping classes */\n\t\t\"sStripeOdd\": \"odd\",\n\t\t\"sStripeEven\": \"even\",\n\t\n\t\t/* Empty row */\n\t\t\"sRowEmpty\": \"dataTables_empty\",\n\t\n\t\t/* Features */\n\t\t\"sWrapper\": \"dataTables_wrapper\",\n\t\t\"sFilter\": \"dataTables_filter\",\n\t\t\"sInfo\": \"dataTables_info\",\n\t\t\"sPaging\": \"dataTables_paginate paging_\", /* Note that the type is postfixed */\n\t\t\"sLength\": \"dataTables_length\",\n\t\t\"sProcessing\": \"dataTables_processing\",\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\": \"sorting_asc\",\n\t\t\"sSortDesc\": \"sorting_desc\",\n\t\t\"sSortable\": \"sorting\", /* Sortable in both directions */\n\t\t\"sSortableAsc\": \"sorting_asc_disabled\",\n\t\t\"sSortableDesc\": \"sorting_desc_disabled\",\n\t\t\"sSortableNone\": \"sorting_disabled\",\n\t\t\"sSortColumn\": \"sorting_\", /* Note that an int is postfixed for the sorting order */\n\t\n\t\t/* Filtering */\n\t\t\"sFilterInput\": \"\",\n\t\n\t\t/* Page length */\n\t\t\"sLengthSelect\": \"\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollWrapper\": \"dataTables_scroll\",\n\t\t\"sScrollHead\": \"dataTables_scrollHead\",\n\t\t\"sScrollHeadInner\": \"dataTables_scrollHeadInner\",\n\t\t\"sScrollBody\": \"dataTables_scrollBody\",\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot\",\n\t\t\"sScrollFootInner\": \"dataTables_scrollFootInner\",\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\": \"\",\n\t\t\"sFooterTH\": \"\",\n\t\n\t\t// Deprecated\n\t\t\"sSortJUIAsc\": \"\",\n\t\t\"sSortJUIDesc\": \"\",\n\t\t\"sSortJUI\": \"\",\n\t\t\"sSortJUIAscAllowed\": \"\",\n\t\t\"sSortJUIDescAllowed\": \"\",\n\t\t\"sSortJUIWrapper\": \"\",\n\t\t\"sSortIcon\": \"\",\n\t\t\"sJUIHeader\": \"\",\n\t\t\"sJUIFooter\": \"\"\n\t} );\n\t\n\t\n\tvar extPagination = DataTable.ext.pager;\n\t\n\tfunction _numbers ( page, pages ) {\n\t\tvar\n\t\t\tnumbers = [],\n\t\t\tbuttons = extPagination.numbers_length,\n\t\t\thalf = Math.floor( buttons / 2 ),\n\t\t\ti = 1;\n\t\n\t\tif ( pages <= buttons ) {\n\t\t\tnumbers = _range( 0, pages );\n\t\t}\n\t\telse if ( page <= half ) {\n\t\t\tnumbers = _range( 0, buttons-2 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t}\n\t\telse if ( page >= pages - 1 - half ) {\n\t\t\tnumbers = _range( pages-(buttons-2), pages );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\telse {\n\t\t\tnumbers = _range( page-half+2, page+half-1 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' );\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\n\t\tnumbers.DT_el = 'span';\n\t\treturn numbers;\n\t}\n\t\n\t\n\t$.extend( extPagination, {\n\t\tsimple: function ( page, pages ) {\n\t\t\treturn [ 'previous', 'next' ];\n\t\t},\n\t\n\t\tfull: function ( page, pages ) {\n\t\t\treturn [  'first', 'previous', 'next', 'last' ];\n\t\t},\n\t\n\t\tnumbers: function ( page, pages ) {\n\t\t\treturn [ _numbers(page, pages) ];\n\t\t},\n\t\n\t\tsimple_numbers: function ( page, pages ) {\n\t\t\treturn [ 'previous', _numbers(page, pages), 'next' ];\n\t\t},\n\t\n\t\tfull_numbers: function ( page, pages ) {\n\t\t\treturn [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];\n\t\t},\n\t\t\n\t\tfirst_last_numbers: function (page, pages) {\n\t \t\treturn ['first', _numbers(page, pages), 'last'];\n\t \t},\n\t\n\t\t// For testing and plug-ins to use\n\t\t_numbers: _numbers,\n\t\n\t\t// Number of number buttons (including ellipsis) to show. _Must be odd!_\n\t\tnumbers_length: 7\n\t} );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\tpageButton: {\n\t\t\t_: function ( settings, host, idx, buttons, page, pages ) {\n\t\t\t\tvar classes = settings.oClasses;\n\t\t\t\tvar lang = settings.oLanguage.oPaginate;\n\t\t\t\tvar aria = settings.oLanguage.oAria.paginate || {};\n\t\t\t\tvar btnDisplay, btnClass, counter=0;\n\t\n\t\t\t\tvar attach = function( container, buttons ) {\n\t\t\t\t\tvar i, ien, node, button;\n\t\t\t\t\tvar clickHandler = function ( e ) {\n\t\t\t\t\t\t_fnPageChange( settings, e.data.action, true );\n\t\t\t\t\t};\n\t\n\t\t\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tbutton = buttons[i];\n\t\n\t\t\t\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\t\t\t\tvar inner = $( '<'+(button.DT_el || 'div')+'/>' )\n\t\t\t\t\t\t\t\t.appendTo( container );\n\t\t\t\t\t\t\tattach( inner, button );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tbtnDisplay = null;\n\t\t\t\t\t\t\tbtnClass = '';\n\t\n\t\t\t\t\t\t\tswitch ( button ) {\n\t\t\t\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\t\t\t\tcontainer.append('<span class=\"ellipsis\">&#x2026;</span>');\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'first':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'next':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'last':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t\t\t\tclasses.sPageButtonActive : '';\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\tif ( btnDisplay !== null ) {\n\t\t\t\t\t\t\t\tnode = $('<a>', {\n\t\t\t\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t\t\t\t.appendTo( container );\n\t\n\t\t\t\t\t\t\t\t_fnBindAction(\n\t\t\t\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t\t\t\t);\n\t\n\t\t\t\t\t\t\t\tcounter++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame. Try / catch the error. Not good for\n\t\t\t\t// accessibility, but neither are frames.\n\t\t\t\tvar activeEl;\n\t\n\t\t\t\ttry {\n\t\t\t\t\t// Because this approach is destroying and recreating the paging\n\t\t\t\t\t// elements, focus is lost on the select button which is bad for\n\t\t\t\t\t// accessibility. So we want to restore focus once the draw has\n\t\t\t\t\t// completed\n\t\t\t\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t\t\t\t}\n\t\t\t\tcatch (e) {}\n\t\n\t\t\t\tattach( $(host).empty(), buttons );\n\t\n\t\t\t\tif ( activeEl !== undefined ) {\n\t\t\t\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t\n\t\n\t// Built in type detection. See model.ext.aTypes for information about\n\t// what is required from this methods.\n\t$.extend( DataTable.ext.type.detect, [\n\t\t// Plain numbers - first since V8 detects some plain numbers as dates\n\t\t// e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal ) ? 'num'+decimal : null;\n\t\t},\n\t\n\t\t// Dates (only those recognised by the browser's Date.parse)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\t// V8 tries _very_ hard to make a string passed into `Date.parse()`\n\t\t\t// valid, so we need to use a regex to restrict date formats. Use a\n\t\t\t// plug-in for anything other than ISO8601 style strings\n\t\t\tif ( d && !(d instanceof Date) && ! _re_date.test(d) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tvar parsed = Date.parse(d);\n\t\t\treturn (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;\n\t\t},\n\t\n\t\t// Formatted numbers\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric, formatted\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML (this is strict checking - there must be html)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\treturn _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?\n\t\t\t\t'html' : null;\n\t\t}\n\t] );\n\t\n\t\n\t\n\t// Filter formatting functions. See model.ext.ofnSearch for information about\n\t// what is required from these methods.\n\t// \n\t// Note that additional search methods are added for the html numbers and\n\t// html formatted numbers by `_addNumericSort()` when we know what the decimal\n\t// place is\n\t\n\t\n\t$.extend( DataTable.ext.type.search, {\n\t\thtml: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata\n\t\t\t\t\t\t.replace( _re_new_lines, \" \" )\n\t\t\t\t\t\t.replace( _re_html, \"\" ) :\n\t\t\t\t\t'';\n\t\t},\n\t\n\t\tstring: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata.replace( _re_new_lines, \" \" ) :\n\t\t\t\t\tdata;\n\t\t}\n\t} );\n\t\n\t\n\t\n\tvar __numericReplace = function ( d, decimalPlace, re1, re2 ) {\n\t\tif ( d !== 0 && (!d || d === '-') ) {\n\t\t\treturn -Infinity;\n\t\t}\n\t\n\t\t// If a decimal place other than `.` is used, it needs to be given to the\n\t\t// function so we can detect it and replace with a `.` which is the only\n\t\t// decimal place Javascript recognises - it is not locale aware.\n\t\tif ( decimalPlace ) {\n\t\t\td = _numToDecimal( d, decimalPlace );\n\t\t}\n\t\n\t\tif ( d.replace ) {\n\t\t\tif ( re1 ) {\n\t\t\t\td = d.replace( re1, '' );\n\t\t\t}\n\t\n\t\t\tif ( re2 ) {\n\t\t\t\td = d.replace( re2, '' );\n\t\t\t}\n\t\t}\n\t\n\t\treturn d * 1;\n\t};\n\t\n\t\n\t// Add the numeric 'deformatting' functions for sorting and search. This is done\n\t// in a function to provide an easy ability for the language options to add\n\t// additional methods if a non-period decimal place is used.\n\tfunction _addNumericSort ( decimalPlace ) {\n\t\t$.each(\n\t\t\t{\n\t\t\t\t// Plain numbers\n\t\t\t\t\"num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace );\n\t\t\t\t},\n\t\n\t\t\t\t// Formatted numbers\n\t\t\t\t\"num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_formatted_numeric );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric\n\t\t\t\t\"html-num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric, formatted\n\t\t\t\t\"html-num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );\n\t\t\t\t}\n\t\t\t},\n\t\t\tfunction ( key, fn ) {\n\t\t\t\t// Add the ordering method\n\t\t\t\t_ext.type.order[ key+decimalPlace+'-pre' ] = fn;\n\t\n\t\t\t\t// For HTML types add a search formatter that will strip the HTML\n\t\t\t\tif ( key.match(/^html\\-/) ) {\n\t\t\t\t\t_ext.type.search[ key+decimalPlace ] = _ext.type.search.html;\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\t\n\t\n\t// Default sort methods\n\t$.extend( _ext.type.order, {\n\t\t// Dates\n\t\t\"date-pre\": function ( d ) {\n\t\t\tvar ts = Date.parse( d );\n\t\t\treturn isNaN(ts) ? -Infinity : ts;\n\t\t},\n\t\n\t\t// html\n\t\t\"html-pre\": function ( a ) {\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ta.replace ?\n\t\t\t\t\ta.replace( /<.*?>/g, \"\" ).toLowerCase() :\n\t\t\t\t\ta+'';\n\t\t},\n\t\n\t\t// string\n\t\t\"string-pre\": function ( a ) {\n\t\t\t// This is a little complex, but faster than always calling toString,\n\t\t\t// http://jsperf.com/tostring-v-check\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ttypeof a === 'string' ?\n\t\t\t\t\ta.toLowerCase() :\n\t\t\t\t\t! a.toString ?\n\t\t\t\t\t\t'' :\n\t\t\t\t\t\ta.toString();\n\t\t},\n\t\n\t\t// string-asc and -desc are retained only for compatibility with the old\n\t\t// sort methods\n\t\t\"string-asc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t},\n\t\n\t\t\"string-desc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t}\n\t} );\n\t\n\t\n\t// Numeric sorting types - order doesn't matter here\n\t_addNumericSort( '' );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\theader: {\n\t\t\t_: function ( settings, cell, column, classes ) {\n\t\t\t\t// No additional mark-up required\n\t\t\t\t// Attach a sort listener to update on sort - note that using the\n\t\t\t\t// `DT` namespace will allow the event to be removed automatically\n\t\t\t\t// on destroy, while the `dt` namespaced event is the one we are\n\t\t\t\t// listening for\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) { // need to check this this is the host\n\t\t\t\t\t\treturn;               // table, not a nested one\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tcolumn.sSortingClass +' '+\n\t\t\t\t\t\t\tclasses.sSortAsc +' '+\n\t\t\t\t\t\t\tclasses.sSortDesc\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t},\n\t\n\t\t\tjqueryui: function ( settings, cell, column, classes ) {\n\t\t\t\t$('<div/>')\n\t\t\t\t\t.addClass( classes.sSortJUIWrapper )\n\t\t\t\t\t.append( cell.contents() )\n\t\t\t\t\t.append( $('<span/>')\n\t\t\t\t\t\t.addClass( classes.sSortIcon+' '+column.sSortingClassJUI )\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo( cell );\n\t\n\t\t\t\t// Attach a sort listener to update on sort\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.find( 'span.'+classes.sSortIcon )\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tclasses.sSortJUIAsc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDesc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUI +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIAscAllowed +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDescAllowed\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortJUIAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortJUIDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClassJUI\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t/*\n\t * Public helper functions. These aren't used internally by DataTables, or\n\t * called by any of the options passed into DataTables, but they can be used\n\t * externally by developers working with DataTables. They are helper functions\n\t * to make working with DataTables a little bit easier.\n\t */\n\t\n\tvar __htmlEscapeEntities = function ( d ) {\n\t\treturn typeof d === 'string' ?\n\t\t\td.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;') :\n\t\t\td;\n\t};\n\t\n\t/**\n\t * Helpers for `columns.render`.\n\t *\n\t * The options defined here can be used with the `columns.render` initialisation\n\t * option to provide a display renderer. The following functions are defined:\n\t *\n\t * * `number` - Will format numeric data (defined by `columns.data`) for\n\t *   display, retaining the original unformatted data for sorting and filtering.\n\t *   It takes 5 parameters:\n\t *   * `string` - Thousands grouping separator\n\t *   * `string` - Decimal point indicator\n\t *   * `integer` - Number of decimal points to show\n\t *   * `string` (optional) - Prefix.\n\t *   * `string` (optional) - Postfix (/suffix).\n\t * * `text` - Escape HTML to help prevent XSS attacks. It has no optional\n\t *   parameters.\n\t *\n\t * @example\n\t *   // Column definition using the number renderer\n\t *   {\n\t *     data: \"salary\",\n\t *     render: $.fn.dataTable.render.number( '\\'', '.', 0, '$' )\n\t *   }\n\t *\n\t * @namespace\n\t */\n\tDataTable.render = {\n\t\tnumber: function ( thousands, decimal, precision, prefix, postfix ) {\n\t\t\treturn {\n\t\t\t\tdisplay: function ( d ) {\n\t\t\t\t\tif ( typeof d !== 'number' && typeof d !== 'string' ) {\n\t\t\t\t\t\treturn d;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar negative = d < 0 ? '-' : '';\n\t\t\t\t\tvar flo = parseFloat( d );\n\t\n\t\t\t\t\t// If NaN then there isn't much formatting that we can do - just\n\t\t\t\t\t// return immediately, escaping any HTML (this was supposed to\n\t\t\t\t\t// be a number after all)\n\t\t\t\t\tif ( isNaN( flo ) ) {\n\t\t\t\t\t\treturn __htmlEscapeEntities( d );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tflo = flo.toFixed( precision );\n\t\t\t\t\td = Math.abs( flo );\n\t\n\t\t\t\t\tvar intPart = parseInt( d, 10 );\n\t\t\t\t\tvar floatPart = precision ?\n\t\t\t\t\t\tdecimal+(d - intPart).toFixed( precision ).substring( 2 ):\n\t\t\t\t\t\t'';\n\t\n\t\t\t\t\treturn negative + (prefix||'') +\n\t\t\t\t\t\tintPart.toString().replace(\n\t\t\t\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g, thousands\n\t\t\t\t\t\t) +\n\t\t\t\t\t\tfloatPart +\n\t\t\t\t\t\t(postfix||'');\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\ttext: function () {\n\t\t\treturn {\n\t\t\t\tdisplay: __htmlEscapeEntities\n\t\t\t};\n\t\t}\n\t};\n\t\n\t\n\t/*\n\t * This is really a good bit rubbish this method of exposing the internal methods\n\t * publicly... - To be fixed in 2.0 using methods on the prototype\n\t */\n\t\n\t\n\t/**\n\t * Create a wrapper function for exporting an internal functions to an external API.\n\t *  @param {string} fn API function name\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#internal\n\t */\n\tfunction _fnExternApiFunc (fn)\n\t{\n\t\treturn function() {\n\t\t\tvar args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(\n\t\t\t\tArray.prototype.slice.call(arguments)\n\t\t\t);\n\t\t\treturn DataTable.ext.internal[fn].apply( this, args );\n\t\t};\n\t}\n\t\n\t\n\t/**\n\t * Reference to internal functions for use by plug-in developers. Note that\n\t * these methods are references to internal functions and are considered to be\n\t * private. If you use these methods, be aware that they are liable to change\n\t * between versions.\n\t *  @namespace\n\t */\n\t$.extend( DataTable.ext.internal, {\n\t\t_fnExternApiFunc: _fnExternApiFunc,\n\t\t_fnBuildAjax: _fnBuildAjax,\n\t\t_fnAjaxUpdate: _fnAjaxUpdate,\n\t\t_fnAjaxParameters: _fnAjaxParameters,\n\t\t_fnAjaxUpdateDraw: _fnAjaxUpdateDraw,\n\t\t_fnAjaxDataSrc: _fnAjaxDataSrc,\n\t\t_fnAddColumn: _fnAddColumn,\n\t\t_fnColumnOptions: _fnColumnOptions,\n\t\t_fnAdjustColumnSizing: _fnAdjustColumnSizing,\n\t\t_fnVisibleToColumnIndex: _fnVisibleToColumnIndex,\n\t\t_fnColumnIndexToVisible: _fnColumnIndexToVisible,\n\t\t_fnVisbleColumns: _fnVisbleColumns,\n\t\t_fnGetColumns: _fnGetColumns,\n\t\t_fnColumnTypes: _fnColumnTypes,\n\t\t_fnApplyColumnDefs: _fnApplyColumnDefs,\n\t\t_fnHungarianMap: _fnHungarianMap,\n\t\t_fnCamelToHungarian: _fnCamelToHungarian,\n\t\t_fnLanguageCompat: _fnLanguageCompat,\n\t\t_fnBrowserDetect: _fnBrowserDetect,\n\t\t_fnAddData: _fnAddData,\n\t\t_fnAddTr: _fnAddTr,\n\t\t_fnNodeToDataIndex: _fnNodeToDataIndex,\n\t\t_fnNodeToColumnIndex: _fnNodeToColumnIndex,\n\t\t_fnGetCellData: _fnGetCellData,\n\t\t_fnSetCellData: _fnSetCellData,\n\t\t_fnSplitObjNotation: _fnSplitObjNotation,\n\t\t_fnGetObjectDataFn: _fnGetObjectDataFn,\n\t\t_fnSetObjectDataFn: _fnSetObjectDataFn,\n\t\t_fnGetDataMaster: _fnGetDataMaster,\n\t\t_fnClearTable: _fnClearTable,\n\t\t_fnDeleteIndex: _fnDeleteIndex,\n\t\t_fnInvalidate: _fnInvalidate,\n\t\t_fnGetRowElements: _fnGetRowElements,\n\t\t_fnCreateTr: _fnCreateTr,\n\t\t_fnBuildHead: _fnBuildHead,\n\t\t_fnDrawHead: _fnDrawHead,\n\t\t_fnDraw: _fnDraw,\n\t\t_fnReDraw: _fnReDraw,\n\t\t_fnAddOptionsHtml: _fnAddOptionsHtml,\n\t\t_fnDetectHeader: _fnDetectHeader,\n\t\t_fnGetUniqueThs: _fnGetUniqueThs,\n\t\t_fnFeatureHtmlFilter: _fnFeatureHtmlFilter,\n\t\t_fnFilterComplete: _fnFilterComplete,\n\t\t_fnFilterCustom: _fnFilterCustom,\n\t\t_fnFilterColumn: _fnFilterColumn,\n\t\t_fnFilter: _fnFilter,\n\t\t_fnFilterCreateSearch: _fnFilterCreateSearch,\n\t\t_fnEscapeRegex: _fnEscapeRegex,\n\t\t_fnFilterData: _fnFilterData,\n\t\t_fnFeatureHtmlInfo: _fnFeatureHtmlInfo,\n\t\t_fnUpdateInfo: _fnUpdateInfo,\n\t\t_fnInfoMacros: _fnInfoMacros,\n\t\t_fnInitialise: _fnInitialise,\n\t\t_fnInitComplete: _fnInitComplete,\n\t\t_fnLengthChange: _fnLengthChange,\n\t\t_fnFeatureHtmlLength: _fnFeatureHtmlLength,\n\t\t_fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,\n\t\t_fnPageChange: _fnPageChange,\n\t\t_fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,\n\t\t_fnProcessingDisplay: _fnProcessingDisplay,\n\t\t_fnFeatureHtmlTable: _fnFeatureHtmlTable,\n\t\t_fnScrollDraw: _fnScrollDraw,\n\t\t_fnApplyToChildren: _fnApplyToChildren,\n\t\t_fnCalculateColumnWidths: _fnCalculateColumnWidths,\n\t\t_fnThrottle: _fnThrottle,\n\t\t_fnConvertToWidth: _fnConvertToWidth,\n\t\t_fnGetWidestNode: _fnGetWidestNode,\n\t\t_fnGetMaxLenString: _fnGetMaxLenString,\n\t\t_fnStringToCss: _fnStringToCss,\n\t\t_fnSortFlatten: _fnSortFlatten,\n\t\t_fnSort: _fnSort,\n\t\t_fnSortAria: _fnSortAria,\n\t\t_fnSortListener: _fnSortListener,\n\t\t_fnSortAttachListener: _fnSortAttachListener,\n\t\t_fnSortingClasses: _fnSortingClasses,\n\t\t_fnSortData: _fnSortData,\n\t\t_fnSaveState: _fnSaveState,\n\t\t_fnLoadState: _fnLoadState,\n\t\t_fnSettingsFromNode: _fnSettingsFromNode,\n\t\t_fnLog: _fnLog,\n\t\t_fnMap: _fnMap,\n\t\t_fnBindAction: _fnBindAction,\n\t\t_fnCallbackReg: _fnCallbackReg,\n\t\t_fnCallbackFire: _fnCallbackFire,\n\t\t_fnLengthOverflow: _fnLengthOverflow,\n\t\t_fnRenderer: _fnRenderer,\n\t\t_fnDataSource: _fnDataSource,\n\t\t_fnRowAttributes: _fnRowAttributes,\n\t\t_fnExtend: _fnExtend,\n\t\t_fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant\n\t\t                                // in 1.10, so this dead-end function is\n\t\t                                // added to prevent errors\n\t} );\n\t\n\n\t// jQuery access\n\t$.fn.dataTable = DataTable;\n\n\t// Provide access to the host jQuery object (circular reference)\n\tDataTable.$ = $;\n\n\t// Legacy aliases\n\t$.fn.dataTableSettings = DataTable.settings;\n\t$.fn.dataTableExt = DataTable.ext;\n\n\t// With a capital `D` we return a DataTables API instance rather than a\n\t// jQuery object\n\t$.fn.DataTable = function ( opts ) {\n\t\treturn $(this).dataTable( opts ).api();\n\t};\n\n\t// All properties that are available to $.fn.dataTable should also be\n\t// available on $.fn.DataTable\n\t$.each( DataTable, function ( prop, val ) {\n\t\t$.fn.DataTable[ prop ] = val;\n\t} );\n\n\n\t// Information about events fired by DataTables - for documentation.\n\t/**\n\t * Draw event, fired whenever the table is redrawn on the page, at the same\n\t * point as fnDrawCallback. This may be useful for binding events or\n\t * performing calculations when the table is altered at all.\n\t *  @name DataTable#draw.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Search event, fired when the searching applied to the table (using the\n\t * built-in global search, or column filters) is altered.\n\t *  @name DataTable#search.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page change event, fired when the paging of the table is altered.\n\t *  @name DataTable#page.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Order event, fired when the ordering applied to the table is altered.\n\t *  @name DataTable#order.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * DataTables initialisation complete event, fired when the table is fully\n\t * drawn, including Ajax data loaded, if Ajax data is required.\n\t *  @name DataTable#init.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The JSON object request from the server - only\n\t *    present if client-side Ajax sourced data is used</li></ol>\n\t */\n\n\t/**\n\t * State save event, fired when the table has changed state a new state save\n\t * is required. This event allows modification of the state saving object\n\t * prior to actually doing the save, including addition or other state\n\t * properties (for plug-ins) or modification of a DataTables core property.\n\t *  @name DataTable#stateSaveParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The state information to be saved\n\t */\n\n\t/**\n\t * State load event, fired when the table is loading state from the stored\n\t * data, but prior to the settings object being modified by the saved state\n\t * - allowing modification of the saved state is required or loading of\n\t * state for a plug-in.\n\t *  @name DataTable#stateLoadParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * State loaded event, fired when state has been loaded from stored data and\n\t * the settings object has been modified by the loaded data.\n\t *  @name DataTable#stateLoaded.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * Processing event, fired when DataTables is doing some kind of processing\n\t * (be it, order, searcg or anything else). It can be used to indicate to\n\t * the end user that there is something happening, or that something has\n\t * finished.\n\t *  @name DataTable#processing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {boolean} bShow Flag for if DataTables is doing processing or not\n\t */\n\n\t/**\n\t * Ajax (XHR) event, fired whenever an Ajax request is completed from a\n\t * request to made to the server for new data. This event is called before\n\t * DataTables processed the returned data, so it can also be used to pre-\n\t * process the data returned from the server, if needed.\n\t *\n\t * Note that this trigger is called in `fnServerData`, if you override\n\t * `fnServerData` and which to use this event, you need to trigger it in you\n\t * success function.\n\t *  @name DataTable#xhr.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {object} json JSON returned from the server\n\t *\n\t *  @example\n\t *     // Use a custom property returned from the server in another DOM element\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       $('#status').html( json.status );\n\t *     } );\n\t *\n\t *  @example\n\t *     // Pre-process the data returned from the server\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {\n\t *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;\n\t *       }\n\t *       // Note no return - manipulate the data directly in the JSON object.\n\t *     } );\n\t */\n\n\t/**\n\t * Destroy event, fired when the DataTable is destroyed by calling fnDestroy\n\t * or passing the bDestroy:true parameter in the initialisation object. This\n\t * can be used to remove bound events, added DOM nodes, etc.\n\t *  @name DataTable#destroy.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page length change event, fired when number of records to show on each\n\t * page (the length) is changed.\n\t *  @name DataTable#length.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {integer} len New length\n\t */\n\n\t/**\n\t * Column sizing has changed.\n\t *  @name DataTable#column-sizing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Column visibility has changed.\n\t *  @name DataTable#column-visibility.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {int} column Column index\n\t *  @param {bool} vis `false` if column now hidden, or `true` if visible\n\t */\n\n\treturn $.fn.dataTable;\n}));\n"
  },
  {
    "path": "static/js/DataTables/FixedColumns-3.2.5/css/fixedColumns.bootstrap.css",
    "content": "table.DTFC_Cloned tr {\n  background-color: white;\n  margin-bottom: 0;\n}\n\ndiv.DTFC_LeftHeadWrapper table,\ndiv.DTFC_RightHeadWrapper table {\n  border-bottom: none !important;\n  margin-bottom: 0 !important;\n  background-color: white;\n}\n\ndiv.DTFC_LeftBodyWrapper table,\ndiv.DTFC_RightBodyWrapper table {\n  border-top: none;\n  margin: 0 !important;\n}\ndiv.DTFC_LeftBodyWrapper table thead .sorting:after,\ndiv.DTFC_LeftBodyWrapper table thead .sorting_asc:after,\ndiv.DTFC_LeftBodyWrapper table thead .sorting_desc:after,\ndiv.DTFC_LeftBodyWrapper table thead .sorting:after,\ndiv.DTFC_LeftBodyWrapper table thead .sorting_asc:after,\ndiv.DTFC_LeftBodyWrapper table thead .sorting_desc:after,\ndiv.DTFC_RightBodyWrapper table thead .sorting:after,\ndiv.DTFC_RightBodyWrapper table thead .sorting_asc:after,\ndiv.DTFC_RightBodyWrapper table thead .sorting_desc:after,\ndiv.DTFC_RightBodyWrapper table thead .sorting:after,\ndiv.DTFC_RightBodyWrapper table thead .sorting_asc:after,\ndiv.DTFC_RightBodyWrapper table thead .sorting_desc:after {\n  display: none;\n}\ndiv.DTFC_LeftBodyWrapper table tbody tr:first-child th,\ndiv.DTFC_LeftBodyWrapper table tbody tr:first-child td,\ndiv.DTFC_RightBodyWrapper table tbody tr:first-child th,\ndiv.DTFC_RightBodyWrapper table tbody tr:first-child td {\n  border-top: none;\n}\n\ndiv.DTFC_LeftFootWrapper table,\ndiv.DTFC_RightFootWrapper table {\n  border-top: none;\n  margin-top: 0 !important;\n  background-color: white;\n}\n\ndiv.DTFC_Blocker {\n  background-color: white;\n}\n"
  },
  {
    "path": "static/js/DataTables/FixedColumns-3.2.5/css/fixedColumns.bootstrap4.css",
    "content": "table.DTFC_Cloned tr {\n  background-color: white;\n  margin-bottom: 0;\n}\n\ndiv.DTFC_LeftHeadWrapper table,\ndiv.DTFC_RightHeadWrapper table {\n  border-bottom: none !important;\n  margin-bottom: 0 !important;\n  background-color: white;\n}\n\ndiv.DTFC_LeftBodyWrapper table,\ndiv.DTFC_RightBodyWrapper table {\n  border-top: none;\n  margin: 0 !important;\n}\ndiv.DTFC_LeftBodyWrapper table thead .sorting:after,\ndiv.DTFC_LeftBodyWrapper table thead .sorting_asc:after,\ndiv.DTFC_LeftBodyWrapper table thead .sorting_desc:after,\ndiv.DTFC_LeftBodyWrapper table thead .sorting:after,\ndiv.DTFC_LeftBodyWrapper table thead .sorting_asc:after,\ndiv.DTFC_LeftBodyWrapper table thead .sorting_desc:after,\ndiv.DTFC_RightBodyWrapper table thead .sorting:after,\ndiv.DTFC_RightBodyWrapper table thead .sorting_asc:after,\ndiv.DTFC_RightBodyWrapper table thead .sorting_desc:after,\ndiv.DTFC_RightBodyWrapper table thead .sorting:after,\ndiv.DTFC_RightBodyWrapper table thead .sorting_asc:after,\ndiv.DTFC_RightBodyWrapper table thead .sorting_desc:after {\n  display: none;\n}\ndiv.DTFC_LeftBodyWrapper table tbody tr:first-child th,\ndiv.DTFC_LeftBodyWrapper table tbody tr:first-child td,\ndiv.DTFC_RightBodyWrapper table tbody tr:first-child th,\ndiv.DTFC_RightBodyWrapper table tbody tr:first-child td {\n  border-top: none;\n}\n\ndiv.DTFC_LeftFootWrapper table,\ndiv.DTFC_RightFootWrapper table {\n  border-top: none;\n  margin-top: 0 !important;\n  background-color: white;\n}\n\ndiv.DTFC_Blocker {\n  background-color: white;\n}\n\ntable.dataTable.table-striped.DTFC_Cloned tbody {\n  background-color: white;\n}\n"
  },
  {
    "path": "static/js/DataTables/FixedColumns-3.2.5/css/fixedColumns.dataTables.css",
    "content": "table.DTFC_Cloned thead,\ntable.DTFC_Cloned tfoot {\n  background-color: white;\n}\n\ndiv.DTFC_Blocker {\n  background-color: white;\n}\n\ndiv.DTFC_LeftWrapper table.dataTable,\ndiv.DTFC_RightWrapper table.dataTable {\n  margin-bottom: 0;\n  z-index: 2;\n}\ndiv.DTFC_LeftWrapper table.dataTable.no-footer,\ndiv.DTFC_RightWrapper table.dataTable.no-footer {\n  border-bottom: none;\n}\n"
  },
  {
    "path": "static/js/DataTables/FixedColumns-3.2.5/css/fixedColumns.foundation.css",
    "content": "div.DTFC_LeftHeadWrapper table,\ndiv.DTFC_LeftBodyWrapper table,\ndiv.DTFC_LeftFootWrapper table {\n  border-right-width: 0;\n}\n\ndiv.DTFC_RightHeadWrapper table,\ndiv.DTFC_RightBodyWrapper table,\ndiv.DTFC_RightFootWrapper table {\n  border-left-width: 0;\n}\n\ndiv.DTFC_LeftHeadWrapper table,\ndiv.DTFC_RightHeadWrapper table {\n  margin-bottom: 0 !important;\n}\n\ndiv.DTFC_LeftBodyWrapper table,\ndiv.DTFC_RightBodyWrapper table {\n  border-top: none;\n  margin: 0 !important;\n}\n\ndiv.DTFC_LeftFootWrapper table,\ndiv.DTFC_RightFootWrapper table {\n  margin-top: 0 !important;\n}\n\ndiv.DTFC_Blocker {\n  background-color: white;\n}\n"
  },
  {
    "path": "static/js/DataTables/FixedColumns-3.2.5/css/fixedColumns.jqueryui.css",
    "content": "div.DTFC_LeftWrapper table.dataTable,\ndiv.DTFC_RightWrapper table.dataTable {\n  z-index: 2;\n}\ndiv.DTFC_LeftWrapper table.dataTable.no-footer,\ndiv.DTFC_RightWrapper table.dataTable.no-footer {\n  border-bottom: none;\n}\n\ndiv.DTFC_Blocker {\n  background-color: white;\n}\n"
  },
  {
    "path": "static/js/DataTables/FixedColumns-3.2.5/css/fixedColumns.semanticui.css",
    "content": "div.DTFC_LeftWrapper table.ui.table.dataTable {\n  border-right: none;\n}\n\ndiv.DTFC_RightWrapper table.ui.table.dataTable {\n  border-left: none;\n}\n\ndiv.DTFC_Blocker {\n  background-color: white;\n}\n\ndiv.DTFC_LeftWrapper table.dataTable,\ndiv.DTFC_RightWrapper table.dataTable {\n  z-index: 2;\n}\n\ndiv.DTFC_LeftHeadWrapper table.ui.table.dataTable,\ndiv.DTFC_RightHeadWrapper table.ui.table.dataTable {\n  border-bottom: none;\n}\n\ndiv.DTFC_LeftBodyWrapper table.ui.table.dataTable,\ndiv.DTFC_RightBodyWrapper table.ui.table.dataTable {\n  border-top: none;\n}\ndiv.DTFC_LeftBodyWrapper table.ui.table.dataTable thead .sorting:after,\ndiv.DTFC_LeftBodyWrapper table.ui.table.dataTable thead .sorting_asc:after,\ndiv.DTFC_LeftBodyWrapper table.ui.table.dataTable thead .sorting_desc:after,\ndiv.DTFC_LeftBodyWrapper table.ui.table.dataTable thead .sorting:after,\ndiv.DTFC_LeftBodyWrapper table.ui.table.dataTable thead .sorting_asc:after,\ndiv.DTFC_LeftBodyWrapper table.ui.table.dataTable thead .sorting_desc:after,\ndiv.DTFC_RightBodyWrapper table.ui.table.dataTable thead .sorting:after,\ndiv.DTFC_RightBodyWrapper table.ui.table.dataTable thead .sorting_asc:after,\ndiv.DTFC_RightBodyWrapper table.ui.table.dataTable thead .sorting_desc:after,\ndiv.DTFC_RightBodyWrapper table.ui.table.dataTable thead .sorting:after,\ndiv.DTFC_RightBodyWrapper table.ui.table.dataTable thead .sorting_asc:after,\ndiv.DTFC_RightBodyWrapper table.ui.table.dataTable thead .sorting_desc:after {\n  display: none;\n}\n"
  },
  {
    "path": "static/js/DataTables/FixedColumns-3.2.5/js/dataTables.fixedColumns.js",
    "content": "/*! FixedColumns 3.2.5\n * ©2010-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     FixedColumns\n * @description Freeze columns in place on a scrolling DataTable\n * @version     3.2.5\n * @file        dataTables.fixedColumns.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2010-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\nvar _firefoxScroll;\n\n/**\n * When making use of DataTables' x-axis scrolling feature, you may wish to\n * fix the left most column in place. This plug-in for DataTables provides\n * exactly this option (note for non-scrolling tables, please use the\n * FixedHeader plug-in, which can fix headers and footers). Key\n * features include:\n *\n * * Freezes the left or right most columns to the side of the table\n * * Option to freeze two or more columns\n * * Full integration with DataTables' scrolling options\n * * Speed - FixedColumns is fast in its operation\n *\n *  @class\n *  @constructor\n *  @global\n *  @param {object} dt DataTables instance. With DataTables 1.10 this can also\n *    be a jQuery collection, a jQuery selector, DataTables API instance or\n *    settings object.\n *  @param {object} [init={}] Configuration object for FixedColumns. Options are\n *    defined by {@link FixedColumns.defaults}\n *\n *  @requires jQuery 1.7+\n *  @requires DataTables 1.8.0+\n *\n *  @example\n *      var table = $('#example').dataTable( {\n *        \"scrollX\": \"100%\"\n *      } );\n *      new $.fn.dataTable.fixedColumns( table );\n */\nvar FixedColumns = function ( dt, init ) {\n\tvar that = this;\n\n\t/* Sanity check - you just know it will happen */\n\tif ( ! ( this instanceof FixedColumns ) ) {\n\t\talert( \"FixedColumns warning: FixedColumns must be initialised with the 'new' keyword.\" );\n\t\treturn;\n\t}\n\n\tif ( init === undefined || init === true ) {\n\t\tinit = {};\n\t}\n\n\t// Use the DataTables Hungarian notation mapping method, if it exists to\n\t// provide forwards compatibility for camel case variables\n\tvar camelToHungarian = $.fn.dataTable.camelToHungarian;\n\tif ( camelToHungarian ) {\n\t\tcamelToHungarian( FixedColumns.defaults, FixedColumns.defaults, true );\n\t\tcamelToHungarian( FixedColumns.defaults, init );\n\t}\n\n\t// v1.10 allows the settings object to be got form a number of sources\n\tvar dtSettings = new $.fn.dataTable.Api( dt ).settings()[0];\n\n\t/**\n\t * Settings object which contains customisable information for FixedColumns instance\n\t * @namespace\n\t * @extends FixedColumns.defaults\n\t * @private\n\t */\n\tthis.s = {\n\t\t/**\n\t\t * DataTables settings objects\n\t\t *  @type     object\n\t\t *  @default  Obtained from DataTables instance\n\t\t */\n\t\t\"dt\": dtSettings,\n\n\t\t/**\n\t\t * Number of columns in the DataTable - stored for quick access\n\t\t *  @type     int\n\t\t *  @default  Obtained from DataTables instance\n\t\t */\n\t\t\"iTableColumns\": dtSettings.aoColumns.length,\n\n\t\t/**\n\t\t * Original outer widths of the columns as rendered by DataTables - used to calculate\n\t\t * the FixedColumns grid bounding box\n\t\t *  @type     array.<int>\n\t\t *  @default  []\n\t\t */\n\t\t\"aiOuterWidths\": [],\n\n\t\t/**\n\t\t * Original inner widths of the columns as rendered by DataTables - used to apply widths\n\t\t * to the columns\n\t\t *  @type     array.<int>\n\t\t *  @default  []\n\t\t */\n\t\t\"aiInnerWidths\": [],\n\n\n\t\t/**\n\t\t * Is the document layout right-to-left\n\t\t * @type boolean\n\t\t */\n\t\trtl: $(dtSettings.nTable).css('direction') === 'rtl'\n\t};\n\n\n\t/**\n\t * DOM elements used by the class instance\n\t * @namespace\n\t * @private\n\t *\n\t */\n\tthis.dom = {\n\t\t/**\n\t\t * DataTables scrolling element\n\t\t *  @type     node\n\t\t *  @default  null\n\t\t */\n\t\t\"scroller\": null,\n\n\t\t/**\n\t\t * DataTables header table\n\t\t *  @type     node\n\t\t *  @default  null\n\t\t */\n\t\t\"header\": null,\n\n\t\t/**\n\t\t * DataTables body table\n\t\t *  @type     node\n\t\t *  @default  null\n\t\t */\n\t\t\"body\": null,\n\n\t\t/**\n\t\t * DataTables footer table\n\t\t *  @type     node\n\t\t *  @default  null\n\t\t */\n\t\t\"footer\": null,\n\n\t\t/**\n\t\t * Display grid elements\n\t\t * @namespace\n\t\t */\n\t\t\"grid\": {\n\t\t\t/**\n\t\t\t * Grid wrapper. This is the container element for the 3x3 grid\n\t\t\t *  @type     node\n\t\t\t *  @default  null\n\t\t\t */\n\t\t\t\"wrapper\": null,\n\n\t\t\t/**\n\t\t\t * DataTables scrolling element. This element is the DataTables\n\t\t\t * component in the display grid (making up the main table - i.e.\n\t\t\t * not the fixed columns).\n\t\t\t *  @type     node\n\t\t\t *  @default  null\n\t\t\t */\n\t\t\t\"dt\": null,\n\n\t\t\t/**\n\t\t\t * Left fixed column grid components\n\t\t\t * @namespace\n\t\t\t */\n\t\t\t\"left\": {\n\t\t\t\t\"wrapper\": null,\n\t\t\t\t\"head\": null,\n\t\t\t\t\"body\": null,\n\t\t\t\t\"foot\": null\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Right fixed column grid components\n\t\t\t * @namespace\n\t\t\t */\n\t\t\t\"right\": {\n\t\t\t\t\"wrapper\": null,\n\t\t\t\t\"head\": null,\n\t\t\t\t\"body\": null,\n\t\t\t\t\"foot\": null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Cloned table nodes\n\t\t * @namespace\n\t\t */\n\t\t\"clone\": {\n\t\t\t/**\n\t\t\t * Left column cloned table nodes\n\t\t\t * @namespace\n\t\t\t */\n\t\t\t\"left\": {\n\t\t\t\t/**\n\t\t\t\t * Cloned header table\n\t\t\t\t *  @type     node\n\t\t\t\t *  @default  null\n\t\t\t\t */\n\t\t\t\t\"header\": null,\n\n\t\t\t\t/**\n\t\t\t\t * Cloned body table\n\t\t\t\t *  @type     node\n\t\t\t\t *  @default  null\n\t\t\t\t */\n\t\t\t\t\"body\": null,\n\n\t\t\t\t/**\n\t\t\t\t * Cloned footer table\n\t\t\t\t *  @type     node\n\t\t\t\t *  @default  null\n\t\t\t\t */\n\t\t\t\t\"footer\": null\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Right column cloned table nodes\n\t\t\t * @namespace\n\t\t\t */\n\t\t\t\"right\": {\n\t\t\t\t/**\n\t\t\t\t * Cloned header table\n\t\t\t\t *  @type     node\n\t\t\t\t *  @default  null\n\t\t\t\t */\n\t\t\t\t\"header\": null,\n\n\t\t\t\t/**\n\t\t\t\t * Cloned body table\n\t\t\t\t *  @type     node\n\t\t\t\t *  @default  null\n\t\t\t\t */\n\t\t\t\t\"body\": null,\n\n\t\t\t\t/**\n\t\t\t\t * Cloned footer table\n\t\t\t\t *  @type     node\n\t\t\t\t *  @default  null\n\t\t\t\t */\n\t\t\t\t\"footer\": null\n\t\t\t}\n\t\t}\n\t};\n\n\tif ( dtSettings._oFixedColumns ) {\n\t\tthrow 'FixedColumns already initialised on this table';\n\t}\n\n\t/* Attach the instance to the DataTables instance so it can be accessed easily */\n\tdtSettings._oFixedColumns = this;\n\n\t/* Let's do it */\n\tif ( ! dtSettings._bInitComplete )\n\t{\n\t\tdtSettings.oApi._fnCallbackReg( dtSettings, 'aoInitComplete', function () {\n\t\t\tthat._fnConstruct( init );\n\t\t}, 'FixedColumns' );\n\t}\n\telse\n\t{\n\t\tthis._fnConstruct( init );\n\t}\n};\n\n\n\n$.extend( FixedColumns.prototype , {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Public methods\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\t/**\n\t * Update the fixed columns - including headers and footers. Note that FixedColumns will\n\t * automatically update the display whenever the host DataTable redraws.\n\t *  @returns {void}\n\t *  @example\n\t *      var table = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      var fc = new $.fn.dataTable.fixedColumns( table );\n\t *\n\t *      // at some later point when the table has been manipulated....\n\t *      fc.fnUpdate();\n\t */\n\t\"fnUpdate\": function ()\n\t{\n\t\tthis._fnDraw( true );\n\t},\n\n\n\t/**\n\t * Recalculate the resizes of the 3x3 grid that FixedColumns uses for display of the table.\n\t * This is useful if you update the width of the table container. Note that FixedColumns will\n\t * perform this function automatically when the window.resize event is fired.\n\t *  @returns {void}\n\t *  @example\n\t *      var table = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      var fc = new $.fn.dataTable.fixedColumns( table );\n\t *\n\t *      // Resize the table container and then have FixedColumns adjust its layout....\n\t *      $('#content').width( 1200 );\n\t *      fc.fnRedrawLayout();\n\t */\n\t\"fnRedrawLayout\": function ()\n\t{\n\t\tthis._fnColCalc();\n\t\tthis._fnGridLayout();\n\t\tthis.fnUpdate();\n\t},\n\n\n\t/**\n\t * Mark a row such that it's height should be recalculated when using 'semiauto' row\n\t * height matching. This function will have no effect when 'none' or 'auto' row height\n\t * matching is used.\n\t *  @param   {Node} nTr TR element that should have it's height recalculated\n\t *  @returns {void}\n\t *  @example\n\t *      var table = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      var fc = new $.fn.dataTable.fixedColumns( table );\n\t *\n\t *      // manipulate the table - mark the row as needing an update then update the table\n\t *      // this allows the redraw performed by DataTables fnUpdate to recalculate the row\n\t *      // height\n\t *      fc.fnRecalculateHeight();\n\t *      table.fnUpdate( $('#example tbody tr:eq(0)')[0], [\"insert date\", 1, 2, 3 ... ]);\n\t */\n\t\"fnRecalculateHeight\": function ( nTr )\n\t{\n\t\tdelete nTr._DTTC_iHeight;\n\t\tnTr.style.height = 'auto';\n\t},\n\n\n\t/**\n\t * Set the height of a given row - provides cross browser compatibility\n\t *  @param   {Node} nTarget TR element that should have it's height recalculated\n\t *  @param   {int} iHeight Height in pixels to set\n\t *  @returns {void}\n\t *  @example\n\t *      var table = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      var fc = new $.fn.dataTable.fixedColumns( table );\n\t *\n\t *      // You may want to do this after manipulating a row in the fixed column\n\t *      fc.fnSetRowHeight( $('#example tbody tr:eq(0)')[0], 50 );\n\t */\n\t\"fnSetRowHeight\": function ( nTarget, iHeight )\n\t{\n\t\tnTarget.style.height = iHeight+\"px\";\n\t},\n\n\n\t/**\n\t * Get data index information about a row or cell in the table body.\n\t * This function is functionally identical to fnGetPosition in DataTables,\n\t * taking the same parameter (TH, TD or TR node) and returning exactly the\n\t * the same information (data index information). THe difference between\n\t * the two is that this method takes into account the fixed columns in the\n\t * table, so you can pass in nodes from the master table, or the cloned\n\t * tables and get the index position for the data in the main table.\n\t *  @param {node} node TR, TH or TD element to get the information about\n\t *  @returns {int} If nNode is given as a TR, then a single index is \n\t *    returned, or if given as a cell, an array of [row index, column index\n\t *    (visible), column index (all)] is given.\n\t */\n\t\"fnGetPosition\": function ( node )\n\t{\n\t\tvar idx;\n\t\tvar inst = this.s.dt.oInstance;\n\n\t\tif ( ! $(node).parents('.DTFC_Cloned').length )\n\t\t{\n\t\t\t// Not in a cloned table\n\t\t\treturn inst.fnGetPosition( node );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Its in the cloned table, so need to look up position\n\t\t\tif ( node.nodeName.toLowerCase() === 'tr' ) {\n\t\t\t\tidx = $(node).index();\n\t\t\t\treturn inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tvar colIdx = $(node).index();\n\t\t\t\tidx = $(node.parentNode).index();\n\t\t\t\tvar row = inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );\n\n\t\t\t\treturn [\n\t\t\t\t\trow,\n\t\t\t\t\tcolIdx,\n\t\t\t\t\tinst.oApi._fnVisibleToColumnIndex( this.s.dt, colIdx )\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\t},\n\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods (they are of course public in JS, but recommended as private)\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\t/**\n\t * Initialisation for FixedColumns\n\t *  @param   {Object} oInit User settings for initialisation\n\t *  @returns {void}\n\t *  @private\n\t */\n\t\"_fnConstruct\": function ( oInit )\n\t{\n\t\tvar i, iLen, iWidth,\n\t\t\tthat = this;\n\n\t\t/* Sanity checking */\n\t\tif ( typeof this.s.dt.oInstance.fnVersionCheck != 'function' ||\n\t\t     this.s.dt.oInstance.fnVersionCheck( '1.8.0' ) !== true )\n\t\t{\n\t\t\talert( \"FixedColumns \"+FixedColumns.VERSION+\" required DataTables 1.8.0 or later. \"+\n\t\t\t\t\"Please upgrade your DataTables installation\" );\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this.s.dt.oScroll.sX === \"\" )\n\t\t{\n\t\t\tthis.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, \"FixedColumns is not needed (no \"+\n\t\t\t\t\"x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for \"+\n\t\t\t\t\"column fixing when scrolling is not enabled\" );\n\t\t\treturn;\n\t\t}\n\n\t\t/* Apply the settings from the user / defaults */\n\t\tthis.s = $.extend( true, this.s, FixedColumns.defaults, oInit );\n\n\t\t/* Set up the DOM as we need it and cache nodes */\n\t\tvar classes = this.s.dt.oClasses;\n\t\tthis.dom.grid.dt = $(this.s.dt.nTable).parents('div.'+classes.sScrollWrapper)[0];\n\t\tthis.dom.scroller = $('div.'+classes.sScrollBody, this.dom.grid.dt )[0];\n\n\t\t/* Set up the DOM that we want for the fixed column layout grid */\n\t\tthis._fnColCalc();\n\t\tthis._fnGridSetup();\n\n\t\t/* Event handlers */\n\t\tvar mouseController;\n\t\tvar mouseDown = false;\n\n\t\t// When the mouse is down (drag scroll) the mouse controller cannot\n\t\t// change, as the browser keeps the original element as the scrolling one\n\t\t$(this.s.dt.nTableWrapper).on( 'mousedown.DTFC', function (e) {\n\t\t\tif ( e.button === 0 ) {\n\t\t\t\tmouseDown = true;\n\n\t\t\t\t$(document).one( 'mouseup', function () {\n\t\t\t\t\tmouseDown = false;\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\t// When the body is scrolled - scroll the left and right columns\n\t\t$(this.dom.scroller)\n\t\t\t.on( 'mouseover.DTFC touchstart.DTFC', function () {\n\t\t\t\tif ( ! mouseDown ) {\n\t\t\t\t\tmouseController = 'main';\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'scroll.DTFC', function (e) {\n\t\t\t\tif ( ! mouseController && e.originalEvent ) {\n\t\t\t\t\tmouseController = 'main';\n\t\t\t\t}\n\n\t\t\t\tif ( mouseController === 'main' ) {\n\t\t\t\t\tif ( that.s.iLeftColumns > 0 ) {\n\t\t\t\t\t\tthat.dom.grid.left.liner.scrollTop = that.dom.scroller.scrollTop;\n\t\t\t\t\t}\n\t\t\t\t\tif ( that.s.iRightColumns > 0 ) {\n\t\t\t\t\t\tthat.dom.grid.right.liner.scrollTop = that.dom.scroller.scrollTop;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\n\t\tvar wheelType = 'onwheel' in document.createElement('div') ?\n\t\t\t'wheel.DTFC' :\n\t\t\t'mousewheel.DTFC';\n\n\t\tif ( that.s.iLeftColumns > 0 ) {\n\t\t\t// When scrolling the left column, scroll the body and right column\n\t\t\t$(that.dom.grid.left.liner)\n\t\t\t\t.on( 'mouseover.DTFC touchstart.DTFC', function () {\n\t\t\t\t\tif ( ! mouseDown ) {\n\t\t\t\t\t\tmouseController = 'left';\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t\t.on( 'scroll.DTFC', function ( e ) {\n\t\t\t\t\tif ( ! mouseController && e.originalEvent ) {\n\t\t\t\t\t\tmouseController = 'left';\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( mouseController === 'left' ) {\n\t\t\t\t\t\tthat.dom.scroller.scrollTop = that.dom.grid.left.liner.scrollTop;\n\t\t\t\t\t\tif ( that.s.iRightColumns > 0 ) {\n\t\t\t\t\t\t\tthat.dom.grid.right.liner.scrollTop = that.dom.grid.left.liner.scrollTop;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t\t.on( wheelType, function(e) {\n\t\t\t\t\t// Pass horizontal scrolling through\n\t\t\t\t\tvar xDelta = e.type === 'wheel' ?\n\t\t\t\t\t\t-e.originalEvent.deltaX :\n\t\t\t\t\t\te.originalEvent.wheelDeltaX;\n\t\t\t\t\tthat.dom.scroller.scrollLeft -= xDelta;\n\t\t\t\t} );\n\t\t}\n\n\t\tif ( that.s.iRightColumns > 0 ) {\n\t\t\t// When scrolling the right column, scroll the body and the left column\n\t\t\t$(that.dom.grid.right.liner)\n\t\t\t\t.on( 'mouseover.DTFC touchstart.DTFC', function () {\n\t\t\t\t\tif ( ! mouseDown ) {\n\t\t\t\t\t\tmouseController = 'right';\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t\t.on( 'scroll.DTFC', function ( e ) {\n\t\t\t\t\tif ( ! mouseController && e.originalEvent ) {\n\t\t\t\t\t\tmouseController = 'right';\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( mouseController === 'right' ) {\n\t\t\t\t\t\tthat.dom.scroller.scrollTop = that.dom.grid.right.liner.scrollTop;\n\t\t\t\t\t\tif ( that.s.iLeftColumns > 0 ) {\n\t\t\t\t\t\t\tthat.dom.grid.left.liner.scrollTop = that.dom.grid.right.liner.scrollTop;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t\t.on( wheelType, function(e) {\n\t\t\t\t\t// Pass horizontal scrolling through\n\t\t\t\t\tvar xDelta = e.type === 'wheel' ?\n\t\t\t\t\t\t-e.originalEvent.deltaX :\n\t\t\t\t\t\te.originalEvent.wheelDeltaX;\n\t\t\t\t\tthat.dom.scroller.scrollLeft -= xDelta;\n\t\t\t\t} );\n\t\t}\n\n\t\t$(window).on( 'resize.DTFC', function () {\n\t\t\tthat._fnGridLayout.call( that );\n\t\t} );\n\n\t\tvar bFirstDraw = true;\n\t\tvar jqTable = $(this.s.dt.nTable);\n\n\t\tjqTable\n\t\t\t.on( 'draw.dt.DTFC', function () {\n\t\t\t\tthat._fnColCalc();\n\t\t\t\tthat._fnDraw.call( that, bFirstDraw );\n\t\t\t\tbFirstDraw = false;\n\t\t\t} )\n\t\t\t.on( 'column-sizing.dt.DTFC', function () {\n\t\t\t\tthat._fnColCalc();\n\t\t\t\tthat._fnGridLayout( that );\n\t\t\t} )\n\t\t\t.on( 'column-visibility.dt.DTFC', function ( e, settings, column, vis, recalc ) {\n\t\t\t\tif ( recalc === undefined || recalc ) {\n\t\t\t\t\tthat._fnColCalc();\n\t\t\t\t\tthat._fnGridLayout( that );\n\t\t\t\t\tthat._fnDraw( true );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'select.dt.DTFC deselect.dt.DTFC', function ( e, dt, type, indexes ) {\n\t\t\t\tif ( e.namespace === 'dt' ) {\n\t\t\t\t\tthat._fnDraw( false );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'destroy.dt.DTFC', function () {\n\t\t\t\tjqTable.off( '.DTFC' );\n\n\t\t\t\t$(that.dom.scroller).off( '.DTFC' );\n\t\t\t\t$(window).off( '.DTFC' );\n\t\t\t\t$(that.s.dt.nTableWrapper).off( '.DTFC' );\n\n\t\t\t\t$(that.dom.grid.left.liner).off( '.DTFC '+wheelType );\n\t\t\t\t$(that.dom.grid.left.wrapper).remove();\n\n\t\t\t\t$(that.dom.grid.right.liner).off( '.DTFC '+wheelType );\n\t\t\t\t$(that.dom.grid.right.wrapper).remove();\n\t\t\t} );\n\n\t\t/* Get things right to start with - note that due to adjusting the columns, there must be\n\t\t * another redraw of the main table. It doesn't need to be a full redraw however.\n\t\t */\n\t\tthis._fnGridLayout();\n\t\tthis.s.dt.oInstance.fnDraw(false);\n\t},\n\n\n\t/**\n\t * Calculate the column widths for the grid layout\n\t *  @returns {void}\n\t *  @private\n\t */\n\t\"_fnColCalc\": function ()\n\t{\n\t\tvar that = this;\n\t\tvar iLeftWidth = 0;\n\t\tvar iRightWidth = 0;\n\n\t\tthis.s.aiInnerWidths = [];\n\t\tthis.s.aiOuterWidths = [];\n\n\t\t$.each( this.s.dt.aoColumns, function (i, col) {\n\t\t\tvar th = $(col.nTh);\n\t\t\tvar border;\n\n\t\t\tif ( ! th.filter(':visible').length ) {\n\t\t\t\tthat.s.aiInnerWidths.push( 0 );\n\t\t\t\tthat.s.aiOuterWidths.push( 0 );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Inner width is used to assign widths to cells\n\t\t\t\t// Outer width is used to calculate the container\n\t\t\t\tvar iWidth = th.outerWidth();\n\n\t\t\t\t// When working with the left most-cell, need to add on the\n\t\t\t\t// table's border to the outerWidth, since we need to take\n\t\t\t\t// account of it, but it isn't in any cell\n\t\t\t\tif ( that.s.aiOuterWidths.length === 0 ) {\n\t\t\t\t\tborder = $(that.s.dt.nTable).css('border-left-width');\n\t\t\t\t\tiWidth += typeof border === 'string' && border.indexOf('px') === -1 ?\n\t\t\t\t\t\t1 :\n\t\t\t\t\t\tparseInt( border, 10 );\n\t\t\t\t}\n\n\t\t\t\t// Likewise with the final column on the right\n\t\t\t\tif ( that.s.aiOuterWidths.length === that.s.dt.aoColumns.length-1 ) {\n\t\t\t\t\tborder = $(that.s.dt.nTable).css('border-right-width');\n\t\t\t\t\tiWidth += typeof border === 'string' && border.indexOf('px') === -1 ?\n\t\t\t\t\t\t1 :\n\t\t\t\t\t\tparseInt( border, 10 );\n\t\t\t\t}\n\n\t\t\t\tthat.s.aiOuterWidths.push( iWidth );\n\t\t\t\tthat.s.aiInnerWidths.push( th.width() );\n\n\t\t\t\tif ( i < that.s.iLeftColumns )\n\t\t\t\t{\n\t\t\t\t\tiLeftWidth += iWidth;\n\t\t\t\t}\n\n\t\t\t\tif ( that.s.iTableColumns-that.s.iRightColumns <= i )\n\t\t\t\t{\n\t\t\t\t\tiRightWidth += iWidth;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\tthis.s.iLeftWidth = iLeftWidth;\n\t\tthis.s.iRightWidth = iRightWidth;\n\t},\n\n\n\t/**\n\t * Set up the DOM for the fixed column. The way the layout works is to create a 1x3 grid\n\t * for the left column, the DataTable (for which we just reuse the scrolling element DataTable\n\t * puts into the DOM) and the right column. In each of he two fixed column elements there is a\n\t * grouping wrapper element and then a head, body and footer wrapper. In each of these we then\n\t * place the cloned header, body or footer tables. This effectively gives as 3x3 grid structure.\n\t *  @returns {void}\n\t *  @private\n\t */\n\t\"_fnGridSetup\": function ()\n\t{\n\t\tvar that = this;\n\t\tvar oOverflow = this._fnDTOverflow();\n\t\tvar block;\n\n\t\tthis.dom.body = this.s.dt.nTable;\n\t\tthis.dom.header = this.s.dt.nTHead.parentNode;\n\t\tthis.dom.header.parentNode.parentNode.style.position = \"relative\";\n\n\t\tvar nSWrapper =\n\t\t\t$('<div class=\"DTFC_ScrollWrapper\" style=\"position:relative; clear:both;\">'+\n\t\t\t\t'<div class=\"DTFC_LeftWrapper\" style=\"position:absolute; top:0; left:0;\" aria-hidden=\"true\">'+\n\t\t\t\t\t'<div class=\"DTFC_LeftHeadWrapper\" style=\"position:relative; top:0; left:0; overflow:hidden;\"></div>'+\n\t\t\t\t\t'<div class=\"DTFC_LeftBodyWrapper\" style=\"position:relative; top:0; left:0; overflow:hidden;\">'+\n\t\t\t\t\t\t'<div class=\"DTFC_LeftBodyLiner\" style=\"position:relative; top:0; left:0; overflow-y:scroll;\"></div>'+\n\t\t\t\t\t'</div>'+\n\t\t\t\t\t'<div class=\"DTFC_LeftFootWrapper\" style=\"position:relative; top:0; left:0; overflow:hidden;\"></div>'+\n\t\t\t\t'</div>'+\n\t\t\t\t'<div class=\"DTFC_RightWrapper\" style=\"position:absolute; top:0; right:0;\" aria-hidden=\"true\">'+\n\t\t\t\t\t'<div class=\"DTFC_RightHeadWrapper\" style=\"position:relative; top:0; left:0;\">'+\n\t\t\t\t\t\t'<div class=\"DTFC_RightHeadBlocker DTFC_Blocker\" style=\"position:absolute; top:0; bottom:0;\"></div>'+\n\t\t\t\t\t'</div>'+\n\t\t\t\t\t'<div class=\"DTFC_RightBodyWrapper\" style=\"position:relative; top:0; left:0; overflow:hidden;\">'+\n\t\t\t\t\t\t'<div class=\"DTFC_RightBodyLiner\" style=\"position:relative; top:0; left:0; overflow-y:scroll;\"></div>'+\n\t\t\t\t\t'</div>'+\n\t\t\t\t\t'<div class=\"DTFC_RightFootWrapper\" style=\"position:relative; top:0; left:0;\">'+\n\t\t\t\t\t\t'<div class=\"DTFC_RightFootBlocker DTFC_Blocker\" style=\"position:absolute; top:0; bottom:0;\"></div>'+\n\t\t\t\t\t'</div>'+\n\t\t\t\t'</div>'+\n\t\t\t'</div>')[0];\n\t\tvar nLeft = nSWrapper.childNodes[0];\n\t\tvar nRight = nSWrapper.childNodes[1];\n\n\t\tthis.dom.grid.dt.parentNode.insertBefore( nSWrapper, this.dom.grid.dt );\n\t\tnSWrapper.appendChild( this.dom.grid.dt );\n\n\t\tthis.dom.grid.wrapper = nSWrapper;\n\n\t\tif ( this.s.iLeftColumns > 0 )\n\t\t{\n\t\t\tthis.dom.grid.left.wrapper = nLeft;\n\t\t\tthis.dom.grid.left.head = nLeft.childNodes[0];\n\t\t\tthis.dom.grid.left.body = nLeft.childNodes[1];\n\t\t\tthis.dom.grid.left.liner = $('div.DTFC_LeftBodyLiner', nSWrapper)[0];\n\n\t\t\tnSWrapper.appendChild( nLeft );\n\t\t}\n\n\t\tif ( this.s.iRightColumns > 0 )\n\t\t{\n\t\t\tthis.dom.grid.right.wrapper = nRight;\n\t\t\tthis.dom.grid.right.head = nRight.childNodes[0];\n\t\t\tthis.dom.grid.right.body = nRight.childNodes[1];\n\t\t\tthis.dom.grid.right.liner = $('div.DTFC_RightBodyLiner', nSWrapper)[0];\n\n\t\t\tnRight.style.right = oOverflow.bar+\"px\";\n\n\t\t\tblock = $('div.DTFC_RightHeadBlocker', nSWrapper)[0];\n\t\t\tblock.style.width = oOverflow.bar+\"px\";\n\t\t\tblock.style.right = -oOverflow.bar+\"px\";\n\t\t\tthis.dom.grid.right.headBlock = block;\n\n\t\t\tblock = $('div.DTFC_RightFootBlocker', nSWrapper)[0];\n\t\t\tblock.style.width = oOverflow.bar+\"px\";\n\t\t\tblock.style.right = -oOverflow.bar+\"px\";\n\t\t\tthis.dom.grid.right.footBlock = block;\n\n\t\t\tnSWrapper.appendChild( nRight );\n\t\t}\n\n\t\tif ( this.s.dt.nTFoot )\n\t\t{\n\t\t\tthis.dom.footer = this.s.dt.nTFoot.parentNode;\n\t\t\tif ( this.s.iLeftColumns > 0 )\n\t\t\t{\n\t\t\t\tthis.dom.grid.left.foot = nLeft.childNodes[2];\n\t\t\t}\n\t\t\tif ( this.s.iRightColumns > 0 )\n\t\t\t{\n\t\t\t\tthis.dom.grid.right.foot = nRight.childNodes[2];\n\t\t\t}\n\t\t}\n\n\t\t// RTL support - swap the position of the left and right columns (#48)\n\t\tif ( this.s.rtl ) {\n\t\t\t$('div.DTFC_RightHeadBlocker', nSWrapper).css( {\n\t\t\t\tleft: -oOverflow.bar+'px',\n\t\t\t\tright: ''\n\t\t\t} );\n\t\t}\n\t},\n\n\n\t/**\n\t * Style and position the grid used for the FixedColumns layout\n\t *  @returns {void}\n\t *  @private\n\t */\n\t\"_fnGridLayout\": function ()\n\t{\n\t\tvar that = this;\n\t\tvar oGrid = this.dom.grid;\n\t\tvar iWidth = $(oGrid.wrapper).width();\n\t\tvar iBodyHeight = this.s.dt.nTable.parentNode.offsetHeight;\n\t\tvar iFullHeight = this.s.dt.nTable.parentNode.parentNode.offsetHeight;\n\t\tvar oOverflow = this._fnDTOverflow();\n\t\tvar iLeftWidth = this.s.iLeftWidth;\n\t\tvar iRightWidth = this.s.iRightWidth;\n\t\tvar rtl = $(this.dom.body).css('direction') === 'rtl';\n\t\tvar wrapper;\n\t\tvar scrollbarAdjust = function ( node, width ) {\n\t\t\tif ( ! oOverflow.bar ) {\n\t\t\t\t// If there is no scrollbar (Macs) we need to hide the auto scrollbar\n\t\t\t\tnode.style.width = (width+20)+\"px\";\n\t\t\t\tnode.style.paddingRight = \"20px\";\n\t\t\t\tnode.style.boxSizing = \"border-box\";\n\t\t\t}\n\t\t\telse if ( that._firefoxScrollError() ) {\n\t\t\t\t// See the above function for why this is required\n\t\t\t\tif ( $(node).height() > 34 ) {\n\t\t\t\t\tnode.style.width = (width+oOverflow.bar)+\"px\";\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Otherwise just overflow by the scrollbar\n\t\t\t\tnode.style.width = (width+oOverflow.bar)+\"px\";\n\t\t\t}\n\t\t};\n\n\t\t// When x scrolling - don't paint the fixed columns over the x scrollbar\n\t\tif ( oOverflow.x )\n\t\t{\n\t\t\tiBodyHeight -= oOverflow.bar;\n\t\t}\n\n\t\toGrid.wrapper.style.height = iFullHeight+\"px\";\n\n\t\tif ( this.s.iLeftColumns > 0 )\n\t\t{\n\t\t\twrapper = oGrid.left.wrapper;\n\t\t\twrapper.style.width = iLeftWidth+'px';\n\t\t\twrapper.style.height = '1px';\n\n\t\t\t// Swap the position of the left and right columns for rtl (#48)\n\t\t\t// This is always up against the edge, scrollbar on the far side\n\t\t\tif ( rtl ) {\n\t\t\t\twrapper.style.left = '';\n\t\t\t\twrapper.style.right = 0;\n\t\t\t}\n\t\t\telse {\n\t\t\t\twrapper.style.left = 0;\n\t\t\t\twrapper.style.right = '';\n\t\t\t}\n\n\t\t\toGrid.left.body.style.height = iBodyHeight+\"px\";\n\t\t\tif ( oGrid.left.foot ) {\n\t\t\t\toGrid.left.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+\"px\"; // shift footer for scrollbar\n\t\t\t}\n\n\t\t\tscrollbarAdjust( oGrid.left.liner, iLeftWidth );\n\t\t\toGrid.left.liner.style.height = iBodyHeight+\"px\";\n\t\t\toGrid.left.liner.style.maxHeight = iBodyHeight+\"px\";\n\t\t}\n\n\t\tif ( this.s.iRightColumns > 0 )\n\t\t{\n\t\t\twrapper = oGrid.right.wrapper;\n\t\t\twrapper.style.width = iRightWidth+'px';\n\t\t\twrapper.style.height = '1px';\n\n\t\t\t// Need to take account of the vertical scrollbar\n\t\t\tif ( this.s.rtl ) {\n\t\t\t\twrapper.style.left = oOverflow.y ? oOverflow.bar+'px' : 0;\n\t\t\t\twrapper.style.right = '';\n\t\t\t}\n\t\t\telse {\n\t\t\t\twrapper.style.left = '';\n\t\t\t\twrapper.style.right = oOverflow.y ? oOverflow.bar+'px' : 0;\n\t\t\t}\n\n\t\t\toGrid.right.body.style.height = iBodyHeight+\"px\";\n\t\t\tif ( oGrid.right.foot ) {\n\t\t\t\toGrid.right.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+\"px\";\n\t\t\t}\n\n\t\t\tscrollbarAdjust( oGrid.right.liner, iRightWidth );\n\t\t\toGrid.right.liner.style.height = iBodyHeight+\"px\";\n\t\t\toGrid.right.liner.style.maxHeight = iBodyHeight+\"px\";\n\n\t\t\toGrid.right.headBlock.style.display = oOverflow.y ? 'block' : 'none';\n\t\t\toGrid.right.footBlock.style.display = oOverflow.y ? 'block' : 'none';\n\t\t}\n\t},\n\n\n\t/**\n\t * Get information about the DataTable's scrolling state - specifically if the table is scrolling\n\t * on either the x or y axis, and also the scrollbar width.\n\t *  @returns {object} Information about the DataTables scrolling state with the properties:\n\t *    'x', 'y' and 'bar'\n\t *  @private\n\t */\n\t\"_fnDTOverflow\": function ()\n\t{\n\t\tvar nTable = this.s.dt.nTable;\n\t\tvar nTableScrollBody = nTable.parentNode;\n\t\tvar out = {\n\t\t\t\"x\": false,\n\t\t\t\"y\": false,\n\t\t\t\"bar\": this.s.dt.oScroll.iBarWidth\n\t\t};\n\n\t\tif ( nTable.offsetWidth > nTableScrollBody.clientWidth )\n\t\t{\n\t\t\tout.x = true;\n\t\t}\n\n\t\tif ( nTable.offsetHeight > nTableScrollBody.clientHeight )\n\t\t{\n\t\t\tout.y = true;\n\t\t}\n\n\t\treturn out;\n\t},\n\n\n\t/**\n\t * Clone and position the fixed columns\n\t *  @returns {void}\n\t *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)\n\t *  @private\n\t */\n\t\"_fnDraw\": function ( bAll )\n\t{\n\t\tthis._fnGridLayout();\n\t\tthis._fnCloneLeft( bAll );\n\t\tthis._fnCloneRight( bAll );\n\n\t\t/* Draw callback function */\n\t\tif ( this.s.fnDrawCallback !== null )\n\t\t{\n\t\t\tthis.s.fnDrawCallback.call( this, this.dom.clone.left, this.dom.clone.right );\n\t\t}\n\n\t\t/* Event triggering */\n\t\t$(this).trigger( 'draw.dtfc', {\n\t\t\t\"leftClone\": this.dom.clone.left,\n\t\t\t\"rightClone\": this.dom.clone.right\n\t\t} );\n\t},\n\n\n\t/**\n\t * Clone the right columns\n\t *  @returns {void}\n\t *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)\n\t *  @private\n\t */\n\t\"_fnCloneRight\": function ( bAll )\n\t{\n\t\tif ( this.s.iRightColumns <= 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar that = this,\n\t\t\ti, jq,\n\t\t\taiColumns = [];\n\n\t\tfor ( i=this.s.iTableColumns-this.s.iRightColumns ; i<this.s.iTableColumns ; i++ ) {\n\t\t\tif ( this.s.dt.aoColumns[i].bVisible ) {\n\t\t\t\taiColumns.push( i );\n\t\t\t}\n\t\t}\n\n\t\tthis._fnClone( this.dom.clone.right, this.dom.grid.right, aiColumns, bAll );\n\t},\n\n\n\t/**\n\t * Clone the left columns\n\t *  @returns {void}\n\t *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)\n\t *  @private\n\t */\n\t\"_fnCloneLeft\": function ( bAll )\n\t{\n\t\tif ( this.s.iLeftColumns <= 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar that = this,\n\t\t\ti, jq,\n\t\t\taiColumns = [];\n\n\t\tfor ( i=0 ; i<this.s.iLeftColumns ; i++ ) {\n\t\t\tif ( this.s.dt.aoColumns[i].bVisible ) {\n\t\t\t\taiColumns.push( i );\n\t\t\t}\n\t\t}\n\n\t\tthis._fnClone( this.dom.clone.left, this.dom.grid.left, aiColumns, bAll );\n\t},\n\n\n\t/**\n\t * Make a copy of the layout object for a header or footer element from DataTables. Note that\n\t * this method will clone the nodes in the layout object.\n\t *  @returns {Array} Copy of the layout array\n\t *  @param   {Object} aoOriginal Layout array from DataTables (aoHeader or aoFooter)\n\t *  @param   {Object} aiColumns Columns to copy\n\t *  @param   {boolean} events Copy cell events or not\n\t *  @private\n\t */\n\t\"_fnCopyLayout\": function ( aoOriginal, aiColumns, events )\n\t{\n\t\tvar aReturn = [];\n\t\tvar aClones = [];\n\t\tvar aCloned = [];\n\n\t\tfor ( var i=0, iLen=aoOriginal.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar aRow = [];\n\t\t\taRow.nTr = $(aoOriginal[i].nTr).clone(events, false)[0];\n\n\t\t\tfor ( var j=0, jLen=this.s.iTableColumns ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tif ( $.inArray( j, aiColumns ) === -1 )\n\t\t\t\t{\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tvar iCloned = $.inArray( aoOriginal[i][j].cell, aCloned );\n\t\t\t\tif ( iCloned === -1 )\n\t\t\t\t{\n\t\t\t\t\tvar nClone = $(aoOriginal[i][j].cell).clone(events, false)[0];\n\t\t\t\t\taClones.push( nClone );\n\t\t\t\t\taCloned.push( aoOriginal[i][j].cell );\n\n\t\t\t\t\taRow.push( {\n\t\t\t\t\t\t\"cell\": nClone,\n\t\t\t\t\t\t\"unique\": aoOriginal[i][j].unique\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\taRow.push( {\n\t\t\t\t\t\t\"cell\": aClones[ iCloned ],\n\t\t\t\t\t\t\"unique\": aoOriginal[i][j].unique\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\taReturn.push( aRow );\n\t\t}\n\n\t\treturn aReturn;\n\t},\n\n\n\t/**\n\t * Clone the DataTable nodes and place them in the DOM (sized correctly)\n\t *  @returns {void}\n\t *  @param   {Object} oClone Object containing the header, footer and body cloned DOM elements\n\t *  @param   {Object} oGrid Grid object containing the display grid elements for the cloned\n\t *                    column (left or right)\n\t *  @param   {Array} aiColumns Column indexes which should be operated on from the DataTable\n\t *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)\n\t *  @private\n\t */\n\t\"_fnClone\": function ( oClone, oGrid, aiColumns, bAll )\n\t{\n\t\tvar that = this,\n\t\t\ti, iLen, j, jLen, jq, nTarget, iColumn, nClone, iIndex, aoCloneLayout,\n\t\t\tjqCloneThead, aoFixedHeader,\n\t\t\tdt = this.s.dt;\n\n\t\t/*\n\t\t * Header\n\t\t */\n\t\tif ( bAll )\n\t\t{\n\t\t\t$(oClone.header).remove();\n\n\t\t\toClone.header = $(this.dom.header).clone(true, false)[0];\n\t\t\toClone.header.className += \" DTFC_Cloned\";\n\t\t\toClone.header.style.width = \"100%\";\n\t\t\toGrid.head.appendChild( oClone.header );\n\n\t\t\t/* Copy the DataTables layout cache for the header for our floating column */\n\t\t\taoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns, true );\n\t\t\tjqCloneThead = $('>thead', oClone.header);\n\t\t\tjqCloneThead.empty();\n\n\t\t\t/* Add the created cloned TR elements to the table */\n\t\t\tfor ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tjqCloneThead[0].appendChild( aoCloneLayout[i].nTr );\n\t\t\t}\n\n\t\t\t/* Use the handy _fnDrawHead function in DataTables to do the rowspan/colspan\n\t\t\t * calculations for us\n\t\t\t */\n\t\t\tdt.oApi._fnDrawHead( dt, aoCloneLayout, true );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* To ensure that we copy cell classes exactly, regardless of colspan, multiple rows\n\t\t\t * etc, we make a copy of the header from the DataTable again, but don't insert the\n\t\t\t * cloned cells, just copy the classes across. To get the matching layout for the\n\t\t\t * fixed component, we use the DataTables _fnDetectHeader method, allowing 1:1 mapping\n\t\t\t */\n\t\t\taoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns, false );\n\t\t\taoFixedHeader=[];\n\n\t\t\tdt.oApi._fnDetectHeader( aoFixedHeader, $('>thead', oClone.header)[0] );\n\n\t\t\tfor ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfor ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\taoFixedHeader[i][j].cell.className = aoCloneLayout[i][j].cell.className;\n\n\t\t\t\t\t// If jQuery UI theming is used we need to copy those elements as well\n\t\t\t\t\t$('span.DataTables_sort_icon', aoFixedHeader[i][j].cell).each( function () {\n\t\t\t\t\t\tthis.className = $('span.DataTables_sort_icon', aoCloneLayout[i][j].cell)[0].className;\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis._fnEqualiseHeights( 'thead', this.dom.header, oClone.header );\n\n\t\t/*\n\t\t * Body\n\t\t */\n\t\tif ( this.s.sHeightMatch == 'auto' )\n\t\t{\n\t\t\t/* Remove any heights which have been applied already and let the browser figure it out */\n\t\t\t$('>tbody>tr', that.dom.body).css('height', 'auto');\n\t\t}\n\n\t\tif ( oClone.body !== null )\n\t\t{\n\t\t\t$(oClone.body).remove();\n\t\t\toClone.body = null;\n\t\t}\n\n\t\toClone.body = $(this.dom.body).clone(true)[0];\n\t\toClone.body.className += \" DTFC_Cloned\";\n\t\toClone.body.style.paddingBottom = dt.oScroll.iBarWidth+\"px\";\n\t\toClone.body.style.marginBottom = (dt.oScroll.iBarWidth*2)+\"px\"; /* For IE */\n\t\tif ( oClone.body.getAttribute('id') !== null )\n\t\t{\n\t\t\toClone.body.removeAttribute('id');\n\t\t}\n\n\t\t$('>thead>tr', oClone.body).empty();\n\t\t$('>tfoot', oClone.body).remove();\n\n\t\tvar nBody = $('tbody', oClone.body)[0];\n\t\t$(nBody).empty();\n\t\tif ( dt.aiDisplay.length > 0 )\n\t\t{\n\t\t\t/* Copy the DataTables' header elements to force the column width in exactly the\n\t\t\t * same way that DataTables does it - have the header element, apply the width and\n\t\t\t * colapse it down\n\t\t\t */\n\t\t\tvar nInnerThead = $('>thead>tr', oClone.body)[0];\n\t\t\tfor ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )\n\t\t\t{\n\t\t\t\tiColumn = aiColumns[iIndex];\n\n\t\t\t\tnClone = $(dt.aoColumns[iColumn].nTh).clone(true)[0];\n\t\t\t\tnClone.innerHTML = \"\";\n\n\t\t\t\tvar oStyle = nClone.style;\n\t\t\t\toStyle.paddingTop = \"0\";\n\t\t\t\toStyle.paddingBottom = \"0\";\n\t\t\t\toStyle.borderTopWidth = \"0\";\n\t\t\t\toStyle.borderBottomWidth = \"0\";\n\t\t\t\toStyle.height = 0;\n\t\t\t\toStyle.width = that.s.aiInnerWidths[iColumn]+\"px\";\n\n\t\t\t\tnInnerThead.appendChild( nClone );\n\t\t\t}\n\n\t\t\t/* Add in the tbody elements, cloning form the master table */\n\t\t\t$('>tbody>tr', that.dom.body).each( function (z) {\n\t\t\t\tvar i = that.s.dt.oFeatures.bServerSide===false ?\n\t\t\t\t\tthat.s.dt.aiDisplay[ that.s.dt._iDisplayStart+z ] : z;\n\t\t\t\tvar aTds = that.s.dt.aoData[ i ].anCells || $(this).children('td, th');\n\n\t\t\t\tvar n = this.cloneNode(false);\n\t\t\t\tn.removeAttribute('id');\n\t\t\t\tn.setAttribute( 'data-dt-row', i );\n\n\t\t\t\tfor ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )\n\t\t\t\t{\n\t\t\t\t\tiColumn = aiColumns[iIndex];\n\n\t\t\t\t\tif ( aTds.length > 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\tnClone = $( aTds[iColumn] ).clone(true, true)[0];\n\t\t\t\t\t\tnClone.removeAttribute( 'id' );\n\t\t\t\t\t\tnClone.setAttribute( 'data-dt-row', i );\n\t\t\t\t\t\tnClone.setAttribute( 'data-dt-column', iColumn );\n\t\t\t\t\t\tn.appendChild( nClone );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnBody.appendChild( n );\n\t\t\t} );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$('>tbody>tr', that.dom.body).each( function (z) {\n\t\t\t\tnClone = this.cloneNode(true);\n\t\t\t\tnClone.className += ' DTFC_NoData';\n\t\t\t\t$('td', nClone).html('');\n\t\t\t\tnBody.appendChild( nClone );\n\t\t\t} );\n\t\t}\n\n\t\toClone.body.style.width = \"100%\";\n\t\toClone.body.style.margin = \"0\";\n\t\toClone.body.style.padding = \"0\";\n\n\t\t// Interop with Scroller - need to use a height forcing element in the\n\t\t// scrolling area in the same way that Scroller does in the body scroll.\n\t\tif ( dt.oScroller !== undefined )\n\t\t{\n\t\t\tvar scrollerForcer = dt.oScroller.dom.force;\n\n\t\t\tif ( ! oGrid.forcer ) {\n\t\t\t\toGrid.forcer = scrollerForcer.cloneNode( true );\n\t\t\t\toGrid.liner.appendChild( oGrid.forcer );\n\t\t\t}\n\t\t\telse {\n\t\t\t\toGrid.forcer.style.height = scrollerForcer.style.height;\n\t\t\t}\n\t\t}\n\n\t\toGrid.liner.appendChild( oClone.body );\n\n\t\tthis._fnEqualiseHeights( 'tbody', that.dom.body, oClone.body );\n\n\t\t/*\n\t\t * Footer\n\t\t */\n\t\tif ( dt.nTFoot !== null )\n\t\t{\n\t\t\tif ( bAll )\n\t\t\t{\n\t\t\t\tif ( oClone.footer !== null )\n\t\t\t\t{\n\t\t\t\t\toClone.footer.parentNode.removeChild( oClone.footer );\n\t\t\t\t}\n\t\t\t\toClone.footer = $(this.dom.footer).clone(true, true)[0];\n\t\t\t\toClone.footer.className += \" DTFC_Cloned\";\n\t\t\t\toClone.footer.style.width = \"100%\";\n\t\t\t\toGrid.foot.appendChild( oClone.footer );\n\n\t\t\t\t/* Copy the footer just like we do for the header */\n\t\t\t\taoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, true );\n\t\t\t\tvar jqCloneTfoot = $('>tfoot', oClone.footer);\n\t\t\t\tjqCloneTfoot.empty();\n\n\t\t\t\tfor ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tjqCloneTfoot[0].appendChild( aoCloneLayout[i].nTr );\n\t\t\t\t}\n\t\t\t\tdt.oApi._fnDrawHead( dt, aoCloneLayout, true );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, false );\n\t\t\t\tvar aoCurrFooter=[];\n\n\t\t\t\tdt.oApi._fnDetectHeader( aoCurrFooter, $('>tfoot', oClone.footer)[0] );\n\n\t\t\t\tfor ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tfor ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )\n\t\t\t\t\t{\n\t\t\t\t\t\taoCurrFooter[i][j].cell.className = aoCloneLayout[i][j].cell.className;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._fnEqualiseHeights( 'tfoot', this.dom.footer, oClone.footer );\n\t\t}\n\n\t\t/* Equalise the column widths between the header footer and body - body get's priority */\n\t\tvar anUnique = dt.oApi._fnGetUniqueThs( dt, $('>thead', oClone.header)[0] );\n\t\t$(anUnique).each( function (i) {\n\t\t\tiColumn = aiColumns[i];\n\t\t\tthis.style.width = that.s.aiInnerWidths[iColumn]+\"px\";\n\t\t} );\n\n\t\tif ( that.s.dt.nTFoot !== null )\n\t\t{\n\t\t\tanUnique = dt.oApi._fnGetUniqueThs( dt, $('>tfoot', oClone.footer)[0] );\n\t\t\t$(anUnique).each( function (i) {\n\t\t\t\tiColumn = aiColumns[i];\n\t\t\t\tthis.style.width = that.s.aiInnerWidths[iColumn]+\"px\";\n\t\t\t} );\n\t\t}\n\t},\n\n\n\t/**\n\t * From a given table node (THEAD etc), get a list of TR direct child elements\n\t *  @param   {Node} nIn Table element to search for TR elements (THEAD, TBODY or TFOOT element)\n\t *  @returns {Array} List of TR elements found\n\t *  @private\n\t */\n\t\"_fnGetTrNodes\": function ( nIn )\n\t{\n\t\tvar aOut = [];\n\t\tfor ( var i=0, iLen=nIn.childNodes.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( nIn.childNodes[i].nodeName.toUpperCase() == \"TR\" )\n\t\t\t{\n\t\t\t\taOut.push( nIn.childNodes[i] );\n\t\t\t}\n\t\t}\n\t\treturn aOut;\n\t},\n\n\n\t/**\n\t * Equalise the heights of the rows in a given table node in a cross browser way\n\t *  @returns {void}\n\t *  @param   {String} nodeName Node type - thead, tbody or tfoot\n\t *  @param   {Node} original Original node to take the heights from\n\t *  @param   {Node} clone Copy the heights to\n\t *  @private\n\t */\n\t\"_fnEqualiseHeights\": function ( nodeName, original, clone )\n\t{\n\t\tif ( this.s.sHeightMatch == 'none' && nodeName !== 'thead' && nodeName !== 'tfoot' )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tvar that = this,\n\t\t\ti, iLen, iHeight, iHeight2, iHeightOriginal, iHeightClone,\n\t\t\trootOriginal = original.getElementsByTagName(nodeName)[0],\n\t\t\trootClone    = clone.getElementsByTagName(nodeName)[0],\n\t\t\tjqBoxHack    = $('>'+nodeName+'>tr:eq(0)', original).children(':first'),\n\t\t\tiBoxHack     = jqBoxHack.outerHeight() - jqBoxHack.height(),\n\t\t\tanOriginal   = this._fnGetTrNodes( rootOriginal ),\n\t\t\tanClone      = this._fnGetTrNodes( rootClone ),\n\t\t\theights      = [];\n\n\t\tfor ( i=0, iLen=anClone.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tiHeightOriginal = anOriginal[i].offsetHeight;\n\t\t\tiHeightClone = anClone[i].offsetHeight;\n\t\t\tiHeight = iHeightClone > iHeightOriginal ? iHeightClone : iHeightOriginal;\n\n\t\t\tif ( this.s.sHeightMatch == 'semiauto' )\n\t\t\t{\n\t\t\t\tanOriginal[i]._DTTC_iHeight = iHeight;\n\t\t\t}\n\n\t\t\theights.push( iHeight );\n\t\t}\n\n\t\tfor ( i=0, iLen=anClone.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tanClone[i].style.height = heights[i]+\"px\";\n\t\t\tanOriginal[i].style.height = heights[i]+\"px\";\n\t\t}\n\t},\n\n\t/**\n\t * Determine if the UA suffers from Firefox's overflow:scroll scrollbars\n\t * not being shown bug.\n\t *\n\t * Firefox doesn't draw scrollbars, even if it is told to using\n\t * overflow:scroll, if the div is less than 34px height. See bugs 292284 and\n\t * 781885. Using UA detection here since this is particularly hard to detect\n\t * using objects - its a straight up rendering error in Firefox.\n\t *\n\t * @return {boolean} True if Firefox error is present, false otherwise\n\t */\n\t_firefoxScrollError: function () {\n\t\tif ( _firefoxScroll === undefined ) {\n\t\t\tvar test = $('<div/>')\n\t\t\t\t.css( {\n\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: 0,\n\t\t\t\t\theight: 10,\n\t\t\t\t\twidth: 50,\n\t\t\t\t\toverflow: 'scroll'\n\t\t\t\t} )\n\t\t\t\t.appendTo( 'body' );\n\n\t\t\t// Make sure this doesn't apply on Macs with 0 width scrollbars\n\t\t\t_firefoxScroll = (\n\t\t\t\ttest[0].clientWidth === test[0].offsetWidth && this._fnDTOverflow().bar !== 0\n\t\t\t);\n\n\t\t\ttest.remove();\n\t\t}\n\n\t\treturn _firefoxScroll;\n\t}\n} );\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Statics\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n/**\n * FixedColumns default settings for initialisation\n *  @name FixedColumns.defaults\n *  @namespace\n *  @static\n */\nFixedColumns.defaults = /** @lends FixedColumns.defaults */{\n\t/**\n\t * Number of left hand columns to fix in position\n\t *  @type     int\n\t *  @default  1\n\t *  @static\n\t *  @example\n\t *      var  = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      new $.fn.dataTable.fixedColumns( table, {\n\t *          \"leftColumns\": 2\n\t *      } );\n\t */\n\t\"iLeftColumns\": 1,\n\n\t/**\n\t * Number of right hand columns to fix in position\n\t *  @type     int\n\t *  @default  0\n\t *  @static\n\t *  @example\n\t *      var table = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      new $.fn.dataTable.fixedColumns( table, {\n\t *          \"rightColumns\": 1\n\t *      } );\n\t */\n\t\"iRightColumns\": 0,\n\n\t/**\n\t * Draw callback function which is called when FixedColumns has redrawn the fixed assets\n\t *  @type     function(object, object):void\n\t *  @default  null\n\t *  @static\n\t *  @example\n\t *      var table = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      new $.fn.dataTable.fixedColumns( table, {\n\t *          \"drawCallback\": function () {\n\t *\t            alert( \"FixedColumns redraw\" );\n\t *\t        }\n\t *      } );\n\t */\n\t\"fnDrawCallback\": null,\n\n\t/**\n\t * Height matching algorthim to use. This can be \"none\" which will result in no height\n\t * matching being applied by FixedColumns (height matching could be forced by CSS in this\n\t * case), \"semiauto\" whereby the height calculation will be performed once, and the result\n\t * cached to be used again (fnRecalculateHeight can be used to force recalculation), or\n\t * \"auto\" when height matching is performed on every draw (slowest but must accurate)\n\t *  @type     string\n\t *  @default  semiauto\n\t *  @static\n\t *  @example\n\t *      var table = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      new $.fn.dataTable.fixedColumns( table, {\n\t *          \"heightMatch\": \"auto\"\n\t *      } );\n\t */\n\t\"sHeightMatch\": \"semiauto\"\n};\n\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Constants\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n/**\n * FixedColumns version\n *  @name      FixedColumns.version\n *  @type      String\n *  @default   See code\n *  @static\n */\nFixedColumns.version = \"3.2.5\";\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables API integration\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\nDataTable.Api.register( 'fixedColumns()', function () {\n\treturn this;\n} );\n\nDataTable.Api.register( 'fixedColumns().update()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx._oFixedColumns ) {\n\t\t\tctx._oFixedColumns.fnUpdate();\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'fixedColumns().relayout()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx._oFixedColumns ) {\n\t\t\tctx._oFixedColumns.fnRedrawLayout();\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'rows().recalcHeight()', function () {\n\treturn this.iterator( 'row', function ( ctx, idx ) {\n\t\tif ( ctx._oFixedColumns ) {\n\t\t\tctx._oFixedColumns.fnRecalculateHeight( this.row(idx).node() );\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'fixedColumns().rowIndex()', function ( row ) {\n\trow = $(row);\n\n\treturn row.parents('.DTFC_Cloned').length ?\n\t\tthis.rows( { page: 'current' } ).indexes()[ row.index() ] :\n\t\tthis.row( row ).index();\n} );\n\nDataTable.Api.register( 'fixedColumns().cellIndex()', function ( cell ) {\n\tcell = $(cell);\n\n\tif ( cell.parents('.DTFC_Cloned').length ) {\n\t\tvar rowClonedIdx = cell.parent().index();\n\t\tvar rowIdx = this.rows( { page: 'current' } ).indexes()[ rowClonedIdx ];\n\t\tvar columnIdx;\n\n\t\tif ( cell.parents('.DTFC_LeftWrapper').length ) {\n\t\t\tcolumnIdx = cell.index();\n\t\t}\n\t\telse {\n\t\t\tvar columns = this.columns().flatten().length;\n\t\t\tcolumnIdx = columns - this.context[0]._oFixedColumns.s.iRightColumns + cell.index();\n\t\t}\n\n\t\treturn {\n\t\t\trow: rowIdx,\n\t\t\tcolumn: this.column.index( 'toData', columnIdx ),\n\t\t\tcolumnVisible: columnIdx\n\t\t};\n\t}\n\telse {\n\t\treturn this.cell( cell ).index();\n\t}\n} );\n\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Initialisation\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'init.dt.fixedColumns', function (e, settings) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.fixedColumns;\n\tvar defaults = DataTable.defaults.fixedColumns;\n\n\tif ( init || defaults ) {\n\t\tvar opts = $.extend( {}, init, defaults );\n\n\t\tif ( init !== false ) {\n\t\t\tnew FixedColumns( settings, opts );\n\t\t}\n\t}\n} );\n\n\n\n// Make FixedColumns accessible from the DataTables instance\n$.fn.dataTable.FixedColumns = FixedColumns;\n$.fn.DataTable.FixedColumns = FixedColumns;\n\nreturn FixedColumns;\n}));\n"
  },
  {
    "path": "static/js/DataTables/FixedColumns-3.2.5/js/fixedColumns.bootstrap.js",
    "content": "/*! Bootstrap 3 styling wrapper for FixedColumns\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs', 'datatables.net-fixedcolumns'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.FixedColumns ) {\n\t\t\t\trequire('datatables.net-fixedcolumns')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/FixedColumns-3.2.5/js/fixedColumns.bootstrap4.js",
    "content": "/*! Bootstrap 4 styling wrapper for FixedColumns\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs4', 'datatables.net-fixedcolumns'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs4')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.FixedColumns ) {\n\t\t\t\trequire('datatables.net-fixedcolumns')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/FixedColumns-3.2.5/js/fixedColumns.dataTables.js",
    "content": "/*! DataTables styling wrapper for FixedColumns\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-dt', 'datatables.net-fixedcolumns'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-dt')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.FixedColumns ) {\n\t\t\t\trequire('datatables.net-fixedcolumns')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/FixedColumns-3.2.5/js/fixedColumns.foundation.js",
    "content": "/*! Bootstrap 4 styling wrapper for FixedColumns\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-zf', 'datatables.net-fixedcolumns'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-zf')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.FixedColumns ) {\n\t\t\t\trequire('datatables.net-fixedcolumns')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/FixedColumns-3.2.5/js/fixedColumns.jqueryui.js",
    "content": "/*! jQuery UI styling wrapper for FixedColumns\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-jqui', 'datatables.net-fixedcolumns'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-jqui')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.FixedColumns ) {\n\t\t\t\trequire('datatables.net-fixedcolumns')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/FixedColumns-3.2.5/js/fixedColumns.semanicui.js",
    "content": "/*! Semanic UI styling wrapper for FixedColumns\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-se', 'datatables.net-fixedcolumns'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-se')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.FixedColumns ) {\n\t\t\t\trequire('datatables.net-fixedcolumns')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/FixedColumns-3.2.5/js/fixedColumns.semanticui.js",
    "content": "/*! Semanic UI styling wrapper for FixedColumns\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-se', 'datatables.net-fixedcolumns'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-se')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.FixedColumns ) {\n\t\t\t\trequire('datatables.net-fixedcolumns')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/FixedHeader-3.1.4/css/fixedHeader.bootstrap.css",
    "content": "table.dataTable.fixedHeader-floating,\ntable.dataTable.fixedHeader-locked {\n  background-color: white;\n  margin-top: 0 !important;\n  margin-bottom: 0 !important;\n}\n\ntable.dataTable.fixedHeader-floating {\n  position: fixed !important;\n}\n\ntable.dataTable.fixedHeader-locked {\n  position: absolute !important;\n}\n\n@media print {\n  table.fixedHeader-floating {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "static/js/DataTables/FixedHeader-3.1.4/css/fixedHeader.bootstrap4.css",
    "content": "table.dataTable.fixedHeader-floating,\ntable.dataTable.fixedHeader-locked {\n  background-color: white;\n  margin-top: 0 !important;\n  margin-bottom: 0 !important;\n}\n\ntable.dataTable.fixedHeader-floating {\n  position: fixed !important;\n}\n\ntable.dataTable.fixedHeader-locked {\n  position: absolute !important;\n}\n\n@media print {\n  table.fixedHeader-floating {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "static/js/DataTables/FixedHeader-3.1.4/css/fixedHeader.dataTables.css",
    "content": "table.fixedHeader-floating {\n  position: fixed !important;\n  background-color: white;\n}\n\ntable.fixedHeader-floating.no-footer {\n  border-bottom-width: 0;\n}\n\ntable.fixedHeader-locked {\n  position: absolute !important;\n  background-color: white;\n}\n\n@media print {\n  table.fixedHeader-floating {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "static/js/DataTables/FixedHeader-3.1.4/css/fixedHeader.foundation.css",
    "content": "table.dataTable.fixedHeader-floating,\ntable.dataTable.fixedHeader-locked {\n  background-color: white;\n  margin-top: 0 !important;\n  margin-bottom: 0 !important;\n}\n\ntable.dataTable.fixedHeader-floating {\n  position: fixed !important;\n}\n\ntable.dataTable.fixedHeader-locked {\n  position: absolute !important;\n}\n\n@media print {\n  table.fixedHeader-floating {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "static/js/DataTables/FixedHeader-3.1.4/css/fixedHeader.jqueryui.css",
    "content": "table.fixedHeader-floating {\n  position: fixed !important;\n  background-color: white;\n}\n\ntable.fixedHeader-locked {\n  position: absolute !important;\n  background-color: white;\n}\n\n@media print {\n  table.fixedHeader-floating {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "static/js/DataTables/FixedHeader-3.1.4/css/fixedHeader.semanticui.css",
    "content": "table.fixedHeader-floating {\n  position: fixed !important;\n  border-bottom-width: 0 !important;\n}\n\ntable.fixedHeader-locked {\n  position: absolute !important;\n}\n\n@media print {\n  table.fixedHeader-floating {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "static/js/DataTables/FixedHeader-3.1.4/js/dataTables.fixedHeader.js",
    "content": "/*! FixedHeader 3.1.4\n * ©2009-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     FixedHeader\n * @description Fix a table's header or footer, so it is always visible while\n *              scrolling\n * @version     3.1.4\n * @file        dataTables.fixedHeader.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2009-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar _instCounter = 0;\n\nvar FixedHeader = function ( dt, config ) {\n\t// Sanity check - you just know it will happen\n\tif ( ! (this instanceof FixedHeader) ) {\n\t\tthrow \"FixedHeader must be initialised with the 'new' keyword.\";\n\t}\n\n\t// Allow a boolean true for defaults\n\tif ( config === true ) {\n\t\tconfig = {};\n\t}\n\n\tdt = new DataTable.Api( dt );\n\n\tthis.c = $.extend( true, {}, FixedHeader.defaults, config );\n\n\tthis.s = {\n\t\tdt: dt,\n\t\tposition: {\n\t\t\ttheadTop: 0,\n\t\t\ttbodyTop: 0,\n\t\t\ttfootTop: 0,\n\t\t\ttfootBottom: 0,\n\t\t\twidth: 0,\n\t\t\tleft: 0,\n\t\t\ttfootHeight: 0,\n\t\t\ttheadHeight: 0,\n\t\t\twindowHeight: $(window).height(),\n\t\t\tvisible: true\n\t\t},\n\t\theaderMode: null,\n\t\tfooterMode: null,\n\t\tautoWidth: dt.settings()[0].oFeatures.bAutoWidth,\n\t\tnamespace: '.dtfc'+(_instCounter++),\n\t\tscrollLeft: {\n\t\t\theader: -1,\n\t\t\tfooter: -1\n\t\t},\n\t\tenable: true\n\t};\n\n\tthis.dom = {\n\t\tfloatingHeader: null,\n\t\tthead: $(dt.table().header()),\n\t\ttbody: $(dt.table().body()),\n\t\ttfoot: $(dt.table().footer()),\n\t\theader: {\n\t\t\thost: null,\n\t\t\tfloating: null,\n\t\t\tplaceholder: null\n\t\t},\n\t\tfooter: {\n\t\t\thost: null,\n\t\t\tfloating: null,\n\t\t\tplaceholder: null\n\t\t}\n\t};\n\n\tthis.dom.header.host = this.dom.thead.parent();\n\tthis.dom.footer.host = this.dom.tfoot.parent();\n\n\tvar dtSettings = dt.settings()[0];\n\tif ( dtSettings._fixedHeader ) {\n\t\tthrow \"FixedHeader already initialised on table \"+dtSettings.nTable.id;\n\t}\n\n\tdtSettings._fixedHeader = this;\n\n\tthis._constructor();\n};\n\n\n/*\n * Variable: FixedHeader\n * Purpose:  Prototype for FixedHeader\n * Scope:    global\n */\n$.extend( FixedHeader.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * API methods\n\t */\n\t\n\t/**\n\t * Enable / disable the fixed elements\n\t *\n\t * @param  {boolean} enable `true` to enable, `false` to disable\n\t */\n\tenable: function ( enable )\n\t{\n\t\tthis.s.enable = enable;\n\n\t\tif ( this.c.header ) {\n\t\t\tthis._modeChange( 'in-place', 'header', true );\n\t\t}\n\n\t\tif ( this.c.footer && this.dom.tfoot.length ) {\n\t\t\tthis._modeChange( 'in-place', 'footer', true );\n\t\t}\n\n\t\tthis.update();\n\t},\n\t\n\t/**\n\t * Set header offset \n\t *\n\t * @param  {int} new value for headerOffset\n\t */\n\theaderOffset: function ( offset )\n\t{\n\t\tif ( offset !== undefined ) {\n\t\t\tthis.c.headerOffset = offset;\n\t\t\tthis.update();\n\t\t}\n\n\t\treturn this.c.headerOffset;\n\t},\n\t\n\t/**\n\t * Set footer offset\n\t *\n\t * @param  {int} new value for footerOffset\n\t */\n\tfooterOffset: function ( offset )\n\t{\n\t\tif ( offset !== undefined ) {\n\t\t\tthis.c.footerOffset = offset;\n\t\t\tthis.update();\n\t\t}\n\n\t\treturn this.c.footerOffset;\n\t},\n\n\t\n\t/**\n\t * Recalculate the position of the fixed elements and force them into place\n\t */\n\tupdate: function ()\n\t{\n\t\tthis._positions();\n\t\tthis._scroll( true );\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\t\n\t/**\n\t * FixedHeader constructor - adding the required event listeners and\n\t * simple initialisation\n\t *\n\t * @private\n\t */\n\t_constructor: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\n\t\t$(window)\n\t\t\t.on( 'scroll'+this.s.namespace, function () {\n\t\t\t\tthat._scroll();\n\t\t\t} )\n\t\t\t.on( 'resize'+this.s.namespace, DataTable.util.throttle( function () {\n\t\t\t\tthat.s.position.windowHeight = $(window).height();\n\t\t\t\tthat.update();\n\t\t\t}, 50 ) );\n\n\t\tvar autoHeader = $('.fh-fixedHeader');\n\t\tif ( ! this.c.headerOffset && autoHeader.length ) {\n\t\t\tthis.c.headerOffset = autoHeader.outerHeight();\n\t\t}\n\n\t\tvar autoFooter = $('.fh-fixedFooter');\n\t\tif ( ! this.c.footerOffset && autoFooter.length ) {\n\t\t\tthis.c.footerOffset = autoFooter.outerHeight();\n\t\t}\n\n\t\tdt.on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc responsive-display.dt.dtfc', function () {\n\t\t\tthat.update();\n\t\t} );\n\n\t\tdt.on( 'destroy.dtfc', function () {\n\t\t\tif ( that.c.header ) {\n\t\t\t\tthat._modeChange( 'in-place', 'header', true );\n\t\t\t}\n\n\t\t\tif ( that.c.footer && that.dom.tfoot.length ) {\n\t\t\t\tthat._modeChange( 'in-place', 'footer', true );\n\t\t\t}\n\n\t\t\tdt.off( '.dtfc' );\n\t\t\t$(window).off( that.s.namespace );\n\t\t} );\n\n\t\tthis._positions();\n\t\tthis._scroll();\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\n\t/**\n\t * Clone a fixed item to act as a place holder for the original element\n\t * which is moved into a clone of the table element, and moved around the\n\t * document to give the fixed effect.\n\t *\n\t * @param  {string}  item  'header' or 'footer'\n\t * @param  {boolean} force Force the clone to happen, or allow automatic\n\t *   decision (reuse existing if available)\n\t * @private\n\t */\n\t_clone: function ( item, force )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar itemDom = this.dom[ item ];\n\t\tvar itemElement = item === 'header' ?\n\t\t\tthis.dom.thead :\n\t\t\tthis.dom.tfoot;\n\n\t\tif ( ! force && itemDom.floating ) {\n\t\t\t// existing floating element - reuse it\n\t\t\titemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' );\n\t\t}\n\t\telse {\n\t\t\tif ( itemDom.floating ) {\n\t\t\t\titemDom.placeholder.remove();\n\t\t\t\tthis._unsize( item );\n\t\t\t\titemDom.floating.children().detach();\n\t\t\t\titemDom.floating.remove();\n\t\t\t}\n\n\t\t\titemDom.floating = $( dt.table().node().cloneNode( false ) )\n\t\t\t\t.css( 'table-layout', 'fixed' )\n\t\t\t\t.attr( 'aria-hidden', 'true' )\n\t\t\t\t.removeAttr( 'id' )\n\t\t\t\t.append( itemElement )\n\t\t\t\t.appendTo( 'body' );\n\n\t\t\t// Insert a fake thead/tfoot into the DataTable to stop it jumping around\n\t\t\titemDom.placeholder = itemElement.clone( false )\n\t\t\titemDom.placeholder\n\t\t\t\t.find( '*[id]' )\n\t\t\t\t.removeAttr( 'id' );\n\n\t\t\titemDom.host.prepend( itemDom.placeholder );\n\n\t\t\t// Clone widths\n\t\t\tthis._matchWidths( itemDom.placeholder, itemDom.floating );\n\t\t}\n\t},\n\n\t/**\n\t * Copy widths from the cells in one element to another. This is required\n\t * for the footer as the footer in the main table takes its sizes from the\n\t * header columns. That isn't present in the footer so to have it still\n\t * align correctly, the sizes need to be copied over. It is also required\n\t * for the header when auto width is not enabled\n\t *\n\t * @param  {jQuery} from Copy widths from\n\t * @param  {jQuery} to   Copy widths to\n\t * @private\n\t */\n\t_matchWidths: function ( from, to ) {\n\t\tvar get = function ( name ) {\n\t\t\treturn $(name, from)\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn $(this).width();\n\t\t\t\t} ).toArray();\n\t\t};\n\n\t\tvar set = function ( name, toWidths ) {\n\t\t\t$(name, to).each( function ( i ) {\n\t\t\t\t$(this).css( {\n\t\t\t\t\twidth: toWidths[i],\n\t\t\t\t\tminWidth: toWidths[i]\n\t\t\t\t} );\n\t\t\t} );\n\t\t};\n\n\t\tvar thWidths = get( 'th' );\n\t\tvar tdWidths = get( 'td' );\n\n\t\tset( 'th', thWidths );\n\t\tset( 'td', tdWidths );\n\t},\n\n\t/**\n\t * Remove assigned widths from the cells in an element. This is required\n\t * when inserting the footer back into the main table so the size is defined\n\t * by the header columns and also when auto width is disabled in the\n\t * DataTable.\n\t *\n\t * @param  {string} item The `header` or `footer`\n\t * @private\n\t */\n\t_unsize: function ( item ) {\n\t\tvar el = this.dom[ item ].floating;\n\n\t\tif ( el && (item === 'footer' || (item === 'header' && ! this.s.autoWidth)) ) {\n\t\t\t$('th, td', el).css( {\n\t\t\t\twidth: '',\n\t\t\t\tminWidth: ''\n\t\t\t} );\n\t\t}\n\t\telse if ( el && item === 'header' ) {\n\t\t\t$('th, td', el).css( 'min-width', '' );\n\t\t}\n\t},\n\n\t/**\n\t * Reposition the floating elements to take account of horizontal page\n\t * scroll\n\t *\n\t * @param  {string} item       The `header` or `footer`\n\t * @param  {int}    scrollLeft Document scrollLeft\n\t * @private\n\t */\n\t_horizontal: function ( item, scrollLeft )\n\t{\n\t\tvar itemDom = this.dom[ item ];\n\t\tvar position = this.s.position;\n\t\tvar lastScrollLeft = this.s.scrollLeft;\n\n\t\tif ( itemDom.floating && lastScrollLeft[ item ] !== scrollLeft ) {\n\t\t\titemDom.floating.css( 'left', position.left - scrollLeft );\n\n\t\t\tlastScrollLeft[ item ] = scrollLeft;\n\t\t}\n\t},\n\n\t/**\n\t * Change from one display mode to another. Each fixed item can be in one\n\t * of:\n\t *\n\t * * `in-place` - In the main DataTable\n\t * * `in` - Floating over the DataTable\n\t * * `below` - (Header only) Fixed to the bottom of the table body\n\t * * `above` - (Footer only) Fixed to the top of the table body\n\t * \n\t * @param  {string}  mode        Mode that the item should be shown in\n\t * @param  {string}  item        'header' or 'footer'\n\t * @param  {boolean} forceChange Force a redraw of the mode, even if already\n\t *     in that mode.\n\t * @private\n\t */\n\t_modeChange: function ( mode, item, forceChange )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar itemDom = this.dom[ item ];\n\t\tvar position = this.s.position;\n\n\t\t// Record focus. Browser's will cause input elements to loose focus if\n\t\t// they are inserted else where in the doc\n\t\tvar tablePart = this.dom[ item==='footer' ? 'tfoot' : 'thead' ];\n\t\tvar focus = $.contains( tablePart[0], document.activeElement ) ?\n\t\t\tdocument.activeElement :\n\t\t\tnull;\n\t\t\n\t\tif ( focus ) {\n\t\t\tfocus.blur();\n\t\t}\n\n\t\tif ( mode === 'in-place' ) {\n\t\t\t// Insert the header back into the table's real header\n\t\t\tif ( itemDom.placeholder ) {\n\t\t\t\titemDom.placeholder.remove();\n\t\t\t\titemDom.placeholder = null;\n\t\t\t}\n\n\t\t\tthis._unsize( item );\n\n\t\t\tif ( item === 'header' ) {\n\t\t\t\titemDom.host.prepend( tablePart );\n\t\t\t}\n\t\t\telse {\n\t\t\t\titemDom.host.append( tablePart );\n\t\t\t}\n\n\t\t\tif ( itemDom.floating ) {\n\t\t\t\titemDom.floating.remove();\n\t\t\t\titemDom.floating = null;\n\t\t\t}\n\t\t}\n\t\telse if ( mode === 'in' ) {\n\t\t\t// Remove the header from the read header and insert into a fixed\n\t\t\t// positioned floating table clone\n\t\t\tthis._clone( item, forceChange );\n\n\t\t\titemDom.floating\n\t\t\t\t.addClass( 'fixedHeader-floating' )\n\t\t\t\t.css( item === 'header' ? 'top' : 'bottom', this.c[item+'Offset'] )\n\t\t\t\t.css( 'left', position.left+'px' )\n\t\t\t\t.css( 'width', position.width+'px' );\n\n\t\t\tif ( item === 'footer' ) {\n\t\t\t\titemDom.floating.css( 'top', '' );\n\t\t\t}\n\t\t}\n\t\telse if ( mode === 'below' ) { // only used for the header\n\t\t\t// Fix the position of the floating header at base of the table body\n\t\t\tthis._clone( item, forceChange );\n\n\t\t\titemDom.floating\n\t\t\t\t.addClass( 'fixedHeader-locked' )\n\t\t\t\t.css( 'top', position.tfootTop - position.theadHeight )\n\t\t\t\t.css( 'left', position.left+'px' )\n\t\t\t\t.css( 'width', position.width+'px' );\n\t\t}\n\t\telse if ( mode === 'above' ) { // only used for the footer\n\t\t\t// Fix the position of the floating footer at top of the table body\n\t\t\tthis._clone( item, forceChange );\n\n\t\t\titemDom.floating\n\t\t\t\t.addClass( 'fixedHeader-locked' )\n\t\t\t\t.css( 'top', position.tbodyTop )\n\t\t\t\t.css( 'left', position.left+'px' )\n\t\t\t\t.css( 'width', position.width+'px' );\n\t\t}\n\n\t\t// Restore focus if it was lost\n\t\tif ( focus && focus !== document.activeElement ) {\n\t\t\tsetTimeout( function () {\n\t\t\t\tfocus.focus();\n\t\t\t}, 10 );\n\t\t}\n\n\t\tthis.s.scrollLeft.header = -1;\n\t\tthis.s.scrollLeft.footer = -1;\n\t\tthis.s[item+'Mode'] = mode;\n\t},\n\n\t/**\n\t * Cache the positional information that is required for the mode\n\t * calculations that FixedHeader performs.\n\t *\n\t * @private\n\t */\n\t_positions: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar table = dt.table();\n\t\tvar position = this.s.position;\n\t\tvar dom = this.dom;\n\t\tvar tableNode = $(table.node());\n\n\t\t// Need to use the header and footer that are in the main table,\n\t\t// regardless of if they are clones, since they hold the positions we\n\t\t// want to measure from\n\t\tvar thead = tableNode.children('thead');\n\t\tvar tfoot = tableNode.children('tfoot');\n\t\tvar tbody = dom.tbody;\n\n\t\tposition.visible = tableNode.is(':visible');\n\t\tposition.width = tableNode.outerWidth();\n\t\tposition.left = tableNode.offset().left;\n\t\tposition.theadTop = thead.offset().top;\n\t\tposition.tbodyTop = tbody.offset().top;\n\t\tposition.theadHeight = position.tbodyTop - position.theadTop;\n\n\t\tif ( tfoot.length ) {\n\t\t\tposition.tfootTop = tfoot.offset().top;\n\t\t\tposition.tfootBottom = position.tfootTop + tfoot.outerHeight();\n\t\t\tposition.tfootHeight = position.tfootBottom - position.tfootTop;\n\t\t}\n\t\telse {\n\t\t\tposition.tfootTop = position.tbodyTop + tbody.outerHeight();\n\t\t\tposition.tfootBottom = position.tfootTop;\n\t\t\tposition.tfootHeight = position.tfootTop;\n\t\t}\n\t},\n\n\n\t/**\n\t * Mode calculation - determine what mode the fixed items should be placed\n\t * into.\n\t *\n\t * @param  {boolean} forceChange Force a redraw of the mode, even if already\n\t *     in that mode.\n\t * @private\n\t */\n\t_scroll: function ( forceChange )\n\t{\n\t\tvar windowTop = $(document).scrollTop();\n\t\tvar windowLeft = $(document).scrollLeft();\n\t\tvar position = this.s.position;\n\t\tvar headerMode, footerMode;\n\n\t\tif ( ! this.s.enable ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this.c.header ) {\n\t\t\tif ( ! position.visible || windowTop <= position.theadTop - this.c.headerOffset ) {\n\t\t\t\theaderMode = 'in-place';\n\t\t\t}\n\t\t\telse if ( windowTop <= position.tfootTop - position.theadHeight - this.c.headerOffset ) {\n\t\t\t\theaderMode = 'in';\n\t\t\t}\n\t\t\telse {\n\t\t\t\theaderMode = 'below';\n\t\t\t}\n\n\t\t\tif ( forceChange || headerMode !== this.s.headerMode ) {\n\t\t\t\tthis._modeChange( headerMode, 'header', forceChange );\n\t\t\t}\n\n\t\t\tthis._horizontal( 'header', windowLeft );\n\t\t}\n\n\t\tif ( this.c.footer && this.dom.tfoot.length ) {\n\t\t\tif ( ! position.visible || windowTop + position.windowHeight >= position.tfootBottom + this.c.footerOffset ) {\n\t\t\t\tfooterMode = 'in-place';\n\t\t\t}\n\t\t\telse if ( position.windowHeight + windowTop > position.tbodyTop + position.tfootHeight + this.c.footerOffset ) {\n\t\t\t\tfooterMode = 'in';\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfooterMode = 'above';\n\t\t\t}\n\n\t\t\tif ( forceChange || footerMode !== this.s.footerMode ) {\n\t\t\t\tthis._modeChange( footerMode, 'footer', forceChange );\n\t\t\t}\n\n\t\t\tthis._horizontal( 'footer', windowLeft );\n\t\t}\n\t}\n} );\n\n\n/**\n * Version\n * @type {String}\n * @static\n */\nFixedHeader.version = \"3.1.4\";\n\n/**\n * Defaults\n * @type {Object}\n * @static\n */\nFixedHeader.defaults = {\n\theader: true,\n\tfooter: false,\n\theaderOffset: 0,\n\tfooterOffset: 0\n};\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables interfaces\n */\n\n// Attach for constructor access\n$.fn.dataTable.FixedHeader = FixedHeader;\n$.fn.DataTable.FixedHeader = FixedHeader;\n\n\n// DataTables creation - check if the FixedHeader option has been defined on the\n// table and if so, initialise\n$(document).on( 'init.dt.dtfh', function (e, settings, json) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.fixedHeader;\n\tvar defaults = DataTable.defaults.fixedHeader;\n\n\tif ( (init || defaults) && ! settings._fixedHeader ) {\n\t\tvar opts = $.extend( {}, defaults, init );\n\n\t\tif ( init !== false ) {\n\t\t\tnew FixedHeader( settings, opts );\n\t\t}\n\t}\n} );\n\n// DataTables API methods\nDataTable.Api.register( 'fixedHeader()', function () {} );\n\nDataTable.Api.register( 'fixedHeader.adjust()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tvar fh = ctx._fixedHeader;\n\n\t\tif ( fh ) {\n\t\t\tfh.update();\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'fixedHeader.enable()', function ( flag ) {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tvar fh = ctx._fixedHeader;\n\n\t\tflag = ( flag !== undefined ? flag : true );\n\t\tif ( fh && flag !== fh.s.enable ) {\n\t\t\tfh.enable( flag );\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'fixedHeader.disable()', function ( ) {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tvar fh = ctx._fixedHeader;\n\n\t\tif ( fh && fh.s.enable ) {\n\t\t\tfh.enable( false );\n\t\t}\n\t} );\n} );\n\n$.each( ['header', 'footer'], function ( i, el ) {\n\tDataTable.Api.register( 'fixedHeader.'+el+'Offset()', function ( offset ) {\n\t\tvar ctx = this.context;\n\n\t\tif ( offset === undefined ) {\n\t\t\treturn ctx.length && ctx[0]._fixedHeader ?\n\t\t\t\tctx[0]._fixedHeader[el +'Offset']() :\n\t\t\t\tundefined;\n\t\t}\n\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\tvar fh = ctx._fixedHeader;\n\n\t\t\tif ( fh ) {\n\t\t\t\tfh[ el +'Offset' ]( offset );\n\t\t\t}\n\t\t} );\n\t} );\n} );\n\n\nreturn FixedHeader;\n}));\n"
  },
  {
    "path": "static/js/DataTables/FixedHeader-3.1.4/js/fixedHeader.bootstrap.js",
    "content": "/*! Bootstrap 3 styling wrapper for FixedHeader\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs', 'datatables.net-fixedheader'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.FixedHeader ) {\n\t\t\t\trequire('datatables.net-fixedheader')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/FixedHeader-3.1.4/js/fixedHeader.bootstrap4.js",
    "content": "/*! Bootstrap 4 styling wrapper for FixedHeader\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs4', 'datatables.net-fixedheader'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs4')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.FixedHeader ) {\n\t\t\t\trequire('datatables.net-fixedheader')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/FixedHeader-3.1.4/js/fixedHeader.dataTables.js",
    "content": "/*! DataTables styling wrapper for FixedHeader\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-dt', 'datatables.net-fixedheader'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-dt')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.FixedHeader ) {\n\t\t\t\trequire('datatables.net-fixedheader')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/FixedHeader-3.1.4/js/fixedHeader.foundation.js",
    "content": "/*! Bootstrap 4 styling wrapper for FixedHeader\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-zf', 'datatables.net-fixedheader'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-zf')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.FixedHeader ) {\n\t\t\t\trequire('datatables.net-fixedheader')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/FixedHeader-3.1.4/js/fixedHeader.jqueryui.js",
    "content": "/*! jQuery UI styling wrapper for FixedHeader\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-jqui', 'datatables.net-fixedheader'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-jqui')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.FixedHeader ) {\n\t\t\t\trequire('datatables.net-fixedheader')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/FixedHeader-3.1.4/js/fixedHeader.semanicui.js",
    "content": "/*! Semanic UI styling wrapper for FixedHeader\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-se', 'datatables.net-fixedheader'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-se')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.FixedHeader ) {\n\t\t\t\trequire('datatables.net-fixedheader')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/FixedHeader-3.1.4/js/fixedHeader.semanticui.js",
    "content": "/*! Semanic UI styling wrapper for FixedHeader\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-se', 'datatables.net-fixedheader'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-se')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.FixedHeader ) {\n\t\t\t\trequire('datatables.net-fixedheader')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/JSZip-2.5.0/jszip.js",
    "content": "/*!\n\nJSZip - A Javascript class for generating and reading zip files\n<http://stuartk.com/jszip>\n\n(c) 2009-2014 Stuart Knightley <stuart [at] stuartk.com>\nDual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown.\n\nJSZip uses the library pako released under the MIT license :\nhttps://github.com/nodeca/pako/blob/master/LICENSE\n*/\n!function(e){if(\"object\"==typeof exports&&\"undefined\"!=typeof module)module.exports=e();else if(\"function\"==typeof define&&define.amd)define([],e);else{var f;\"undefined\"!=typeof window?f=window:\"undefined\"!=typeof global?f=global:\"undefined\"!=typeof self&&(f=self),f.JSZip=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error(\"Cannot find module '\"+o+\"'\")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){\n'use strict';\n// private property\nvar _keyStr = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\n\n// public method for encoding\nexports.encode = function(input, utf8) {\n    var output = \"\";\n    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;\n    var i = 0;\n\n    while (i < input.length) {\n\n        chr1 = input.charCodeAt(i++);\n        chr2 = input.charCodeAt(i++);\n        chr3 = input.charCodeAt(i++);\n\n        enc1 = chr1 >> 2;\n        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n        enc4 = chr3 & 63;\n\n        if (isNaN(chr2)) {\n            enc3 = enc4 = 64;\n        }\n        else if (isNaN(chr3)) {\n            enc4 = 64;\n        }\n\n        output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4);\n\n    }\n\n    return output;\n};\n\n// public method for decoding\nexports.decode = function(input, utf8) {\n    var output = \"\";\n    var chr1, chr2, chr3;\n    var enc1, enc2, enc3, enc4;\n    var i = 0;\n\n    input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n    while (i < input.length) {\n\n        enc1 = _keyStr.indexOf(input.charAt(i++));\n        enc2 = _keyStr.indexOf(input.charAt(i++));\n        enc3 = _keyStr.indexOf(input.charAt(i++));\n        enc4 = _keyStr.indexOf(input.charAt(i++));\n\n        chr1 = (enc1 << 2) | (enc2 >> 4);\n        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n        chr3 = ((enc3 & 3) << 6) | enc4;\n\n        output = output + String.fromCharCode(chr1);\n\n        if (enc3 != 64) {\n            output = output + String.fromCharCode(chr2);\n        }\n        if (enc4 != 64) {\n            output = output + String.fromCharCode(chr3);\n        }\n\n    }\n\n    return output;\n\n};\n\n},{}],2:[function(_dereq_,module,exports){\n'use strict';\nfunction CompressedObject() {\n    this.compressedSize = 0;\n    this.uncompressedSize = 0;\n    this.crc32 = 0;\n    this.compressionMethod = null;\n    this.compressedContent = null;\n}\n\nCompressedObject.prototype = {\n    /**\n     * Return the decompressed content in an unspecified format.\n     * The format will depend on the decompressor.\n     * @return {Object} the decompressed content.\n     */\n    getContent: function() {\n        return null; // see implementation\n    },\n    /**\n     * Return the compressed content in an unspecified format.\n     * The format will depend on the compressed conten source.\n     * @return {Object} the compressed content.\n     */\n    getCompressedContent: function() {\n        return null; // see implementation\n    }\n};\nmodule.exports = CompressedObject;\n\n},{}],3:[function(_dereq_,module,exports){\n'use strict';\nexports.STORE = {\n    magic: \"\\x00\\x00\",\n    compress: function(content, compressionOptions) {\n        return content; // no compression\n    },\n    uncompress: function(content) {\n        return content; // no compression\n    },\n    compressInputType: null,\n    uncompressInputType: null\n};\nexports.DEFLATE = _dereq_('./flate');\n\n},{\"./flate\":8}],4:[function(_dereq_,module,exports){\n'use strict';\n\nvar utils = _dereq_('./utils');\n\nvar table = [\n    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,\n    0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,\n    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,\n    0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,\n    0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,\n    0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,\n    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,\n    0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,\n    0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,\n    0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,\n    0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,\n    0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,\n    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,\n    0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,\n    0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,\n    0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,\n    0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,\n    0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,\n    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,\n    0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,\n    0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,\n    0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,\n    0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,\n    0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,\n    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,\n    0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,\n    0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,\n    0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,\n    0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,\n    0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,\n    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,\n    0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,\n    0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,\n    0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,\n    0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,\n    0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,\n    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,\n    0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,\n    0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,\n    0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,\n    0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,\n    0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,\n    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,\n    0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,\n    0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,\n    0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,\n    0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,\n    0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,\n    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,\n    0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,\n    0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,\n    0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,\n    0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,\n    0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,\n    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,\n    0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,\n    0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,\n    0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,\n    0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,\n    0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,\n    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,\n    0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,\n    0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,\n    0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D\n];\n\n/**\n *\n *  Javascript crc32\n *  http://www.webtoolkit.info/\n *\n */\nmodule.exports = function crc32(input, crc) {\n    if (typeof input === \"undefined\" || !input.length) {\n        return 0;\n    }\n\n    var isArray = utils.getTypeOf(input) !== \"string\";\n\n    if (typeof(crc) == \"undefined\") {\n        crc = 0;\n    }\n    var x = 0;\n    var y = 0;\n    var b = 0;\n\n    crc = crc ^ (-1);\n    for (var i = 0, iTop = input.length; i < iTop; i++) {\n        b = isArray ? input[i] : input.charCodeAt(i);\n        y = (crc ^ b) & 0xFF;\n        x = table[y];\n        crc = (crc >>> 8) ^ x;\n    }\n\n    return crc ^ (-1);\n};\n// vim: set shiftwidth=4 softtabstop=4:\n\n},{\"./utils\":21}],5:[function(_dereq_,module,exports){\n'use strict';\nvar utils = _dereq_('./utils');\n\nfunction DataReader(data) {\n    this.data = null; // type : see implementation\n    this.length = 0;\n    this.index = 0;\n}\nDataReader.prototype = {\n    /**\n     * Check that the offset will not go too far.\n     * @param {string} offset the additional offset to check.\n     * @throws {Error} an Error if the offset is out of bounds.\n     */\n    checkOffset: function(offset) {\n        this.checkIndex(this.index + offset);\n    },\n    /**\n     * Check that the specifed index will not be too far.\n     * @param {string} newIndex the index to check.\n     * @throws {Error} an Error if the index is out of bounds.\n     */\n    checkIndex: function(newIndex) {\n        if (this.length < newIndex || newIndex < 0) {\n            throw new Error(\"End of data reached (data length = \" + this.length + \", asked index = \" + (newIndex) + \"). Corrupted zip ?\");\n        }\n    },\n    /**\n     * Change the index.\n     * @param {number} newIndex The new index.\n     * @throws {Error} if the new index is out of the data.\n     */\n    setIndex: function(newIndex) {\n        this.checkIndex(newIndex);\n        this.index = newIndex;\n    },\n    /**\n     * Skip the next n bytes.\n     * @param {number} n the number of bytes to skip.\n     * @throws {Error} if the new index is out of the data.\n     */\n    skip: function(n) {\n        this.setIndex(this.index + n);\n    },\n    /**\n     * Get the byte at the specified index.\n     * @param {number} i the index to use.\n     * @return {number} a byte.\n     */\n    byteAt: function(i) {\n        // see implementations\n    },\n    /**\n     * Get the next number with a given byte size.\n     * @param {number} size the number of bytes to read.\n     * @return {number} the corresponding number.\n     */\n    readInt: function(size) {\n        var result = 0,\n            i;\n        this.checkOffset(size);\n        for (i = this.index + size - 1; i >= this.index; i--) {\n            result = (result << 8) + this.byteAt(i);\n        }\n        this.index += size;\n        return result;\n    },\n    /**\n     * Get the next string with a given byte size.\n     * @param {number} size the number of bytes to read.\n     * @return {string} the corresponding string.\n     */\n    readString: function(size) {\n        return utils.transformTo(\"string\", this.readData(size));\n    },\n    /**\n     * Get raw data without conversion, <size> bytes.\n     * @param {number} size the number of bytes to read.\n     * @return {Object} the raw data, implementation specific.\n     */\n    readData: function(size) {\n        // see implementations\n    },\n    /**\n     * Find the last occurence of a zip signature (4 bytes).\n     * @param {string} sig the signature to find.\n     * @return {number} the index of the last occurence, -1 if not found.\n     */\n    lastIndexOfSignature: function(sig) {\n        // see implementations\n    },\n    /**\n     * Get the next date.\n     * @return {Date} the date.\n     */\n    readDate: function() {\n        var dostime = this.readInt(4);\n        return new Date(\n        ((dostime >> 25) & 0x7f) + 1980, // year\n        ((dostime >> 21) & 0x0f) - 1, // month\n        (dostime >> 16) & 0x1f, // day\n        (dostime >> 11) & 0x1f, // hour\n        (dostime >> 5) & 0x3f, // minute\n        (dostime & 0x1f) << 1); // second\n    }\n};\nmodule.exports = DataReader;\n\n},{\"./utils\":21}],6:[function(_dereq_,module,exports){\n'use strict';\nexports.base64 = false;\nexports.binary = false;\nexports.dir = false;\nexports.createFolders = false;\nexports.date = null;\nexports.compression = null;\nexports.compressionOptions = null;\nexports.comment = null;\nexports.unixPermissions = null;\nexports.dosPermissions = null;\n\n},{}],7:[function(_dereq_,module,exports){\n'use strict';\nvar utils = _dereq_('./utils');\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.string2binary = function(str) {\n    return utils.string2binary(str);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.string2Uint8Array = function(str) {\n    return utils.transformTo(\"uint8array\", str);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.uint8Array2String = function(array) {\n    return utils.transformTo(\"string\", array);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.string2Blob = function(str) {\n    var buffer = utils.transformTo(\"arraybuffer\", str);\n    return utils.arrayBuffer2Blob(buffer);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.arrayBuffer2Blob = function(buffer) {\n    return utils.arrayBuffer2Blob(buffer);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.transformTo = function(outputType, input) {\n    return utils.transformTo(outputType, input);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.getTypeOf = function(input) {\n    return utils.getTypeOf(input);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.checkSupport = function(type) {\n    return utils.checkSupport(type);\n};\n\n/**\n * @deprecated\n * This value will be removed in a future version without replacement.\n */\nexports.MAX_VALUE_16BITS = utils.MAX_VALUE_16BITS;\n\n/**\n * @deprecated\n * This value will be removed in a future version without replacement.\n */\nexports.MAX_VALUE_32BITS = utils.MAX_VALUE_32BITS;\n\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.pretty = function(str) {\n    return utils.pretty(str);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.findCompression = function(compressionMethod) {\n    return utils.findCompression(compressionMethod);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.isRegExp = function (object) {\n    return utils.isRegExp(object);\n};\n\n\n},{\"./utils\":21}],8:[function(_dereq_,module,exports){\n'use strict';\nvar USE_TYPEDARRAY = (typeof Uint8Array !== 'undefined') && (typeof Uint16Array !== 'undefined') && (typeof Uint32Array !== 'undefined');\n\nvar pako = _dereq_(\"pako\");\nexports.uncompressInputType = USE_TYPEDARRAY ? \"uint8array\" : \"array\";\nexports.compressInputType = USE_TYPEDARRAY ? \"uint8array\" : \"array\";\n\nexports.magic = \"\\x08\\x00\";\nexports.compress = function(input, compressionOptions) {\n    return pako.deflateRaw(input, {\n        level : compressionOptions.level || -1 // default compression\n    });\n};\nexports.uncompress =  function(input) {\n    return pako.inflateRaw(input);\n};\n\n},{\"pako\":24}],9:[function(_dereq_,module,exports){\n'use strict';\n\nvar base64 = _dereq_('./base64');\n\n/**\nUsage:\n   zip = new JSZip();\n   zip.file(\"hello.txt\", \"Hello, World!\").file(\"tempfile\", \"nothing\");\n   zip.folder(\"images\").file(\"smile.gif\", base64Data, {base64: true});\n   zip.file(\"Xmas.txt\", \"Ho ho ho !\", {date : new Date(\"December 25, 2007 00:00:01\")});\n   zip.remove(\"tempfile\");\n\n   base64zip = zip.generate();\n\n**/\n\n/**\n * Representation a of zip file in js\n * @constructor\n * @param {String=|ArrayBuffer=|Uint8Array=} data the data to load, if any (optional).\n * @param {Object=} options the options for creating this objects (optional).\n */\nfunction JSZip(data, options) {\n    // if this constructor is used without `new`, it adds `new` before itself:\n    if(!(this instanceof JSZip)) return new JSZip(data, options);\n\n    // object containing the files :\n    // {\n    //   \"folder/\" : {...},\n    //   \"folder/data.txt\" : {...}\n    // }\n    this.files = {};\n\n    this.comment = null;\n\n    // Where we are in the hierarchy\n    this.root = \"\";\n    if (data) {\n        this.load(data, options);\n    }\n    this.clone = function() {\n        var newObj = new JSZip();\n        for (var i in this) {\n            if (typeof this[i] !== \"function\") {\n                newObj[i] = this[i];\n            }\n        }\n        return newObj;\n    };\n}\nJSZip.prototype = _dereq_('./object');\nJSZip.prototype.load = _dereq_('./load');\nJSZip.support = _dereq_('./support');\nJSZip.defaults = _dereq_('./defaults');\n\n/**\n * @deprecated\n * This namespace will be removed in a future version without replacement.\n */\nJSZip.utils = _dereq_('./deprecatedPublicUtils');\n\nJSZip.base64 = {\n    /**\n     * @deprecated\n     * This method will be removed in a future version without replacement.\n     */\n    encode : function(input) {\n        return base64.encode(input);\n    },\n    /**\n     * @deprecated\n     * This method will be removed in a future version without replacement.\n     */\n    decode : function(input) {\n        return base64.decode(input);\n    }\n};\nJSZip.compressions = _dereq_('./compressions');\nmodule.exports = JSZip;\n\n},{\"./base64\":1,\"./compressions\":3,\"./defaults\":6,\"./deprecatedPublicUtils\":7,\"./load\":10,\"./object\":13,\"./support\":17}],10:[function(_dereq_,module,exports){\n'use strict';\nvar base64 = _dereq_('./base64');\nvar ZipEntries = _dereq_('./zipEntries');\nmodule.exports = function(data, options) {\n    var files, zipEntries, i, input;\n    options = options || {};\n    if (options.base64) {\n        data = base64.decode(data);\n    }\n\n    zipEntries = new ZipEntries(data, options);\n    files = zipEntries.files;\n    for (i = 0; i < files.length; i++) {\n        input = files[i];\n        this.file(input.fileName, input.decompressed, {\n            binary: true,\n            optimizedBinaryString: true,\n            date: input.date,\n            dir: input.dir,\n            comment : input.fileComment.length ? input.fileComment : null,\n            unixPermissions : input.unixPermissions,\n            dosPermissions : input.dosPermissions,\n            createFolders: options.createFolders\n        });\n    }\n    if (zipEntries.zipComment.length) {\n        this.comment = zipEntries.zipComment;\n    }\n\n    return this;\n};\n\n},{\"./base64\":1,\"./zipEntries\":22}],11:[function(_dereq_,module,exports){\n(function (Buffer){\n'use strict';\nmodule.exports = function(data, encoding){\n    return new Buffer(data, encoding);\n};\nmodule.exports.test = function(b){\n    return Buffer.isBuffer(b);\n};\n\n}).call(this,(typeof Buffer !== \"undefined\" ? Buffer : undefined))\n},{}],12:[function(_dereq_,module,exports){\n'use strict';\nvar Uint8ArrayReader = _dereq_('./uint8ArrayReader');\n\nfunction NodeBufferReader(data) {\n    this.data = data;\n    this.length = this.data.length;\n    this.index = 0;\n}\nNodeBufferReader.prototype = new Uint8ArrayReader();\n\n/**\n * @see DataReader.readData\n */\nNodeBufferReader.prototype.readData = function(size) {\n    this.checkOffset(size);\n    var result = this.data.slice(this.index, this.index + size);\n    this.index += size;\n    return result;\n};\nmodule.exports = NodeBufferReader;\n\n},{\"./uint8ArrayReader\":18}],13:[function(_dereq_,module,exports){\n'use strict';\nvar support = _dereq_('./support');\nvar utils = _dereq_('./utils');\nvar crc32 = _dereq_('./crc32');\nvar signature = _dereq_('./signature');\nvar defaults = _dereq_('./defaults');\nvar base64 = _dereq_('./base64');\nvar compressions = _dereq_('./compressions');\nvar CompressedObject = _dereq_('./compressedObject');\nvar nodeBuffer = _dereq_('./nodeBuffer');\nvar utf8 = _dereq_('./utf8');\nvar StringWriter = _dereq_('./stringWriter');\nvar Uint8ArrayWriter = _dereq_('./uint8ArrayWriter');\n\n/**\n * Returns the raw data of a ZipObject, decompress the content if necessary.\n * @param {ZipObject} file the file to use.\n * @return {String|ArrayBuffer|Uint8Array|Buffer} the data.\n */\nvar getRawData = function(file) {\n    if (file._data instanceof CompressedObject) {\n        file._data = file._data.getContent();\n        file.options.binary = true;\n        file.options.base64 = false;\n\n        if (utils.getTypeOf(file._data) === \"uint8array\") {\n            var copy = file._data;\n            // when reading an arraybuffer, the CompressedObject mechanism will keep it and subarray() a Uint8Array.\n            // if we request a file in the same format, we might get the same Uint8Array or its ArrayBuffer (the original zip file).\n            file._data = new Uint8Array(copy.length);\n            // with an empty Uint8Array, Opera fails with a \"Offset larger than array size\"\n            if (copy.length !== 0) {\n                file._data.set(copy, 0);\n            }\n        }\n    }\n    return file._data;\n};\n\n/**\n * Returns the data of a ZipObject in a binary form. If the content is an unicode string, encode it.\n * @param {ZipObject} file the file to use.\n * @return {String|ArrayBuffer|Uint8Array|Buffer} the data.\n */\nvar getBinaryData = function(file) {\n    var result = getRawData(file),\n        type = utils.getTypeOf(result);\n    if (type === \"string\") {\n        if (!file.options.binary) {\n            // unicode text !\n            // unicode string => binary string is a painful process, check if we can avoid it.\n            if (support.nodebuffer) {\n                return nodeBuffer(result, \"utf-8\");\n            }\n        }\n        return file.asBinary();\n    }\n    return result;\n};\n\n/**\n * Transform this._data into a string.\n * @param {function} filter a function String -> String, applied if not null on the result.\n * @return {String} the string representing this._data.\n */\nvar dataToString = function(asUTF8) {\n    var result = getRawData(this);\n    if (result === null || typeof result === \"undefined\") {\n        return \"\";\n    }\n    // if the data is a base64 string, we decode it before checking the encoding !\n    if (this.options.base64) {\n        result = base64.decode(result);\n    }\n    if (asUTF8 && this.options.binary) {\n        // JSZip.prototype.utf8decode supports arrays as input\n        // skip to array => string step, utf8decode will do it.\n        result = out.utf8decode(result);\n    }\n    else {\n        // no utf8 transformation, do the array => string step.\n        result = utils.transformTo(\"string\", result);\n    }\n\n    if (!asUTF8 && !this.options.binary) {\n        result = utils.transformTo(\"string\", out.utf8encode(result));\n    }\n    return result;\n};\n/**\n * A simple object representing a file in the zip file.\n * @constructor\n * @param {string} name the name of the file\n * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data\n * @param {Object} options the options of the file\n */\nvar ZipObject = function(name, data, options) {\n    this.name = name;\n    this.dir = options.dir;\n    this.date = options.date;\n    this.comment = options.comment;\n    this.unixPermissions = options.unixPermissions;\n    this.dosPermissions = options.dosPermissions;\n\n    this._data = data;\n    this.options = options;\n\n    /*\n     * This object contains initial values for dir and date.\n     * With them, we can check if the user changed the deprecated metadata in\n     * `ZipObject#options` or not.\n     */\n    this._initialMetadata = {\n      dir : options.dir,\n      date : options.date\n    };\n};\n\nZipObject.prototype = {\n    /**\n     * Return the content as UTF8 string.\n     * @return {string} the UTF8 string.\n     */\n    asText: function() {\n        return dataToString.call(this, true);\n    },\n    /**\n     * Returns the binary content.\n     * @return {string} the content as binary.\n     */\n    asBinary: function() {\n        return dataToString.call(this, false);\n    },\n    /**\n     * Returns the content as a nodejs Buffer.\n     * @return {Buffer} the content as a Buffer.\n     */\n    asNodeBuffer: function() {\n        var result = getBinaryData(this);\n        return utils.transformTo(\"nodebuffer\", result);\n    },\n    /**\n     * Returns the content as an Uint8Array.\n     * @return {Uint8Array} the content as an Uint8Array.\n     */\n    asUint8Array: function() {\n        var result = getBinaryData(this);\n        return utils.transformTo(\"uint8array\", result);\n    },\n    /**\n     * Returns the content as an ArrayBuffer.\n     * @return {ArrayBuffer} the content as an ArrayBufer.\n     */\n    asArrayBuffer: function() {\n        return this.asUint8Array().buffer;\n    }\n};\n\n/**\n * Transform an integer into a string in hexadecimal.\n * @private\n * @param {number} dec the number to convert.\n * @param {number} bytes the number of bytes to generate.\n * @returns {string} the result.\n */\nvar decToHex = function(dec, bytes) {\n    var hex = \"\",\n        i;\n    for (i = 0; i < bytes; i++) {\n        hex += String.fromCharCode(dec & 0xff);\n        dec = dec >>> 8;\n    }\n    return hex;\n};\n\n/**\n * Merge the objects passed as parameters into a new one.\n * @private\n * @param {...Object} var_args All objects to merge.\n * @return {Object} a new object with the data of the others.\n */\nvar extend = function() {\n    var result = {}, i, attr;\n    for (i = 0; i < arguments.length; i++) { // arguments is not enumerable in some browsers\n        for (attr in arguments[i]) {\n            if (arguments[i].hasOwnProperty(attr) && typeof result[attr] === \"undefined\") {\n                result[attr] = arguments[i][attr];\n            }\n        }\n    }\n    return result;\n};\n\n/**\n * Transforms the (incomplete) options from the user into the complete\n * set of options to create a file.\n * @private\n * @param {Object} o the options from the user.\n * @return {Object} the complete set of options.\n */\nvar prepareFileAttrs = function(o) {\n    o = o || {};\n    if (o.base64 === true && (o.binary === null || o.binary === undefined)) {\n        o.binary = true;\n    }\n    o = extend(o, defaults);\n    o.date = o.date || new Date();\n    if (o.compression !== null) o.compression = o.compression.toUpperCase();\n\n    return o;\n};\n\n/**\n * Add a file in the current folder.\n * @private\n * @param {string} name the name of the file\n * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data of the file\n * @param {Object} o the options of the file\n * @return {Object} the new file.\n */\nvar fileAdd = function(name, data, o) {\n    // be sure sub folders exist\n    var dataType = utils.getTypeOf(data),\n        parent;\n\n    o = prepareFileAttrs(o);\n\n    if (typeof o.unixPermissions === \"string\") {\n        o.unixPermissions = parseInt(o.unixPermissions, 8);\n    }\n\n    // UNX_IFDIR  0040000 see zipinfo.c\n    if (o.unixPermissions && (o.unixPermissions & 0x4000)) {\n        o.dir = true;\n    }\n    // Bit 4    Directory\n    if (o.dosPermissions && (o.dosPermissions & 0x0010)) {\n        o.dir = true;\n    }\n\n    if (o.dir) {\n        name = forceTrailingSlash(name);\n    }\n\n    if (o.createFolders && (parent = parentFolder(name))) {\n        folderAdd.call(this, parent, true);\n    }\n\n    if (o.dir || data === null || typeof data === \"undefined\") {\n        o.base64 = false;\n        o.binary = false;\n        data = null;\n        dataType = null;\n    }\n    else if (dataType === \"string\") {\n        if (o.binary && !o.base64) {\n            // optimizedBinaryString == true means that the file has already been filtered with a 0xFF mask\n            if (o.optimizedBinaryString !== true) {\n                // this is a string, not in a base64 format.\n                // Be sure that this is a correct \"binary string\"\n                data = utils.string2binary(data);\n            }\n        }\n    }\n    else { // arraybuffer, uint8array, ...\n        o.base64 = false;\n        o.binary = true;\n\n        if (!dataType && !(data instanceof CompressedObject)) {\n            throw new Error(\"The data of '\" + name + \"' is in an unsupported format !\");\n        }\n\n        // special case : it's way easier to work with Uint8Array than with ArrayBuffer\n        if (dataType === \"arraybuffer\") {\n            data = utils.transformTo(\"uint8array\", data);\n        }\n    }\n\n    var object = new ZipObject(name, data, o);\n    this.files[name] = object;\n    return object;\n};\n\n/**\n * Find the parent folder of the path.\n * @private\n * @param {string} path the path to use\n * @return {string} the parent folder, or \"\"\n */\nvar parentFolder = function (path) {\n    if (path.slice(-1) == '/') {\n        path = path.substring(0, path.length - 1);\n    }\n    var lastSlash = path.lastIndexOf('/');\n    return (lastSlash > 0) ? path.substring(0, lastSlash) : \"\";\n};\n\n\n/**\n * Returns the path with a slash at the end.\n * @private\n * @param {String} path the path to check.\n * @return {String} the path with a trailing slash.\n */\nvar forceTrailingSlash = function(path) {\n    // Check the name ends with a /\n    if (path.slice(-1) != \"/\") {\n        path += \"/\"; // IE doesn't like substr(-1)\n    }\n    return path;\n};\n/**\n * Add a (sub) folder in the current folder.\n * @private\n * @param {string} name the folder's name\n * @param {boolean=} [createFolders] If true, automatically create sub\n *  folders. Defaults to false.\n * @return {Object} the new folder.\n */\nvar folderAdd = function(name, createFolders) {\n    createFolders = (typeof createFolders !== 'undefined') ? createFolders : false;\n\n    name = forceTrailingSlash(name);\n\n    // Does this folder already exist?\n    if (!this.files[name]) {\n        fileAdd.call(this, name, null, {\n            dir: true,\n            createFolders: createFolders\n        });\n    }\n    return this.files[name];\n};\n\n/**\n * Generate a JSZip.CompressedObject for a given zipOject.\n * @param {ZipObject} file the object to read.\n * @param {JSZip.compression} compression the compression to use.\n * @param {Object} compressionOptions the options to use when compressing.\n * @return {JSZip.CompressedObject} the compressed result.\n */\nvar generateCompressedObjectFrom = function(file, compression, compressionOptions) {\n    var result = new CompressedObject(),\n        content;\n\n    // the data has not been decompressed, we might reuse things !\n    if (file._data instanceof CompressedObject) {\n        result.uncompressedSize = file._data.uncompressedSize;\n        result.crc32 = file._data.crc32;\n\n        if (result.uncompressedSize === 0 || file.dir) {\n            compression = compressions['STORE'];\n            result.compressedContent = \"\";\n            result.crc32 = 0;\n        }\n        else if (file._data.compressionMethod === compression.magic) {\n            result.compressedContent = file._data.getCompressedContent();\n        }\n        else {\n            content = file._data.getContent();\n            // need to decompress / recompress\n            result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions);\n        }\n    }\n    else {\n        // have uncompressed data\n        content = getBinaryData(file);\n        if (!content || content.length === 0 || file.dir) {\n            compression = compressions['STORE'];\n            content = \"\";\n        }\n        result.uncompressedSize = content.length;\n        result.crc32 = crc32(content);\n        result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions);\n    }\n\n    result.compressedSize = result.compressedContent.length;\n    result.compressionMethod = compression.magic;\n\n    return result;\n};\n\n\n\n\n/**\n * Generate the UNIX part of the external file attributes.\n * @param {Object} unixPermissions the unix permissions or null.\n * @param {Boolean} isDir true if the entry is a directory, false otherwise.\n * @return {Number} a 32 bit integer.\n *\n * adapted from http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute :\n *\n * TTTTsstrwxrwxrwx0000000000ADVSHR\n * ^^^^____________________________ file type, see zipinfo.c (UNX_*)\n *     ^^^_________________________ setuid, setgid, sticky\n *        ^^^^^^^^^________________ permissions\n *                 ^^^^^^^^^^______ not used ?\n *                           ^^^^^^ DOS attribute bits : Archive, Directory, Volume label, System file, Hidden, Read only\n */\nvar generateUnixExternalFileAttr = function (unixPermissions, isDir) {\n\n    var result = unixPermissions;\n    if (!unixPermissions) {\n        // I can't use octal values in strict mode, hence the hexa.\n        //  040775 => 0x41fd\n        // 0100664 => 0x81b4\n        result = isDir ? 0x41fd : 0x81b4;\n    }\n\n    return (result & 0xFFFF) << 16;\n};\n\n/**\n * Generate the DOS part of the external file attributes.\n * @param {Object} dosPermissions the dos permissions or null.\n * @param {Boolean} isDir true if the entry is a directory, false otherwise.\n * @return {Number} a 32 bit integer.\n *\n * Bit 0     Read-Only\n * Bit 1     Hidden\n * Bit 2     System\n * Bit 3     Volume Label\n * Bit 4     Directory\n * Bit 5     Archive\n */\nvar generateDosExternalFileAttr = function (dosPermissions, isDir) {\n\n    // the dir flag is already set for compatibility\n\n    return (dosPermissions || 0)  & 0x3F;\n};\n\n/**\n * Generate the various parts used in the construction of the final zip file.\n * @param {string} name the file name.\n * @param {ZipObject} file the file content.\n * @param {JSZip.CompressedObject} compressedObject the compressed object.\n * @param {number} offset the current offset from the start of the zip file.\n * @param {String} platform let's pretend we are this platform (change platform dependents fields)\n * @return {object} the zip parts.\n */\nvar generateZipParts = function(name, file, compressedObject, offset, platform) {\n    var data = compressedObject.compressedContent,\n        utfEncodedFileName = utils.transformTo(\"string\", utf8.utf8encode(file.name)),\n        comment = file.comment || \"\",\n        utfEncodedComment = utils.transformTo(\"string\", utf8.utf8encode(comment)),\n        useUTF8ForFileName = utfEncodedFileName.length !== file.name.length,\n        useUTF8ForComment = utfEncodedComment.length !== comment.length,\n        o = file.options,\n        dosTime,\n        dosDate,\n        extraFields = \"\",\n        unicodePathExtraField = \"\",\n        unicodeCommentExtraField = \"\",\n        dir, date;\n\n\n    // handle the deprecated options.dir\n    if (file._initialMetadata.dir !== file.dir) {\n        dir = file.dir;\n    } else {\n        dir = o.dir;\n    }\n\n    // handle the deprecated options.date\n    if(file._initialMetadata.date !== file.date) {\n        date = file.date;\n    } else {\n        date = o.date;\n    }\n\n    var extFileAttr = 0;\n    var versionMadeBy = 0;\n    if (dir) {\n        // dos or unix, we set the dos dir flag\n        extFileAttr |= 0x00010;\n    }\n    if(platform === \"UNIX\") {\n        versionMadeBy = 0x031E; // UNIX, version 3.0\n        extFileAttr |= generateUnixExternalFileAttr(file.unixPermissions, dir);\n    } else { // DOS or other, fallback to DOS\n        versionMadeBy = 0x0014; // DOS, version 2.0\n        extFileAttr |= generateDosExternalFileAttr(file.dosPermissions, dir);\n    }\n\n    // date\n    // @see http://www.delorie.com/djgpp/doc/rbinter/it/52/13.html\n    // @see http://www.delorie.com/djgpp/doc/rbinter/it/65/16.html\n    // @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html\n\n    dosTime = date.getHours();\n    dosTime = dosTime << 6;\n    dosTime = dosTime | date.getMinutes();\n    dosTime = dosTime << 5;\n    dosTime = dosTime | date.getSeconds() / 2;\n\n    dosDate = date.getFullYear() - 1980;\n    dosDate = dosDate << 4;\n    dosDate = dosDate | (date.getMonth() + 1);\n    dosDate = dosDate << 5;\n    dosDate = dosDate | date.getDate();\n\n    if (useUTF8ForFileName) {\n        // set the unicode path extra field. unzip needs at least one extra\n        // field to correctly handle unicode path, so using the path is as good\n        // as any other information. This could improve the situation with\n        // other archive managers too.\n        // This field is usually used without the utf8 flag, with a non\n        // unicode path in the header (winrar, winzip). This helps (a bit)\n        // with the messy Windows' default compressed folders feature but\n        // breaks on p7zip which doesn't seek the unicode path extra field.\n        // So for now, UTF-8 everywhere !\n        unicodePathExtraField =\n            // Version\n            decToHex(1, 1) +\n            // NameCRC32\n            decToHex(crc32(utfEncodedFileName), 4) +\n            // UnicodeName\n            utfEncodedFileName;\n\n        extraFields +=\n            // Info-ZIP Unicode Path Extra Field\n            \"\\x75\\x70\" +\n            // size\n            decToHex(unicodePathExtraField.length, 2) +\n            // content\n            unicodePathExtraField;\n    }\n\n    if(useUTF8ForComment) {\n\n        unicodeCommentExtraField =\n            // Version\n            decToHex(1, 1) +\n            // CommentCRC32\n            decToHex(this.crc32(utfEncodedComment), 4) +\n            // UnicodeName\n            utfEncodedComment;\n\n        extraFields +=\n            // Info-ZIP Unicode Path Extra Field\n            \"\\x75\\x63\" +\n            // size\n            decToHex(unicodeCommentExtraField.length, 2) +\n            // content\n            unicodeCommentExtraField;\n    }\n\n    var header = \"\";\n\n    // version needed to extract\n    header += \"\\x0A\\x00\";\n    // general purpose bit flag\n    // set bit 11 if utf8\n    header += (useUTF8ForFileName || useUTF8ForComment) ? \"\\x00\\x08\" : \"\\x00\\x00\";\n    // compression method\n    header += compressedObject.compressionMethod;\n    // last mod file time\n    header += decToHex(dosTime, 2);\n    // last mod file date\n    header += decToHex(dosDate, 2);\n    // crc-32\n    header += decToHex(compressedObject.crc32, 4);\n    // compressed size\n    header += decToHex(compressedObject.compressedSize, 4);\n    // uncompressed size\n    header += decToHex(compressedObject.uncompressedSize, 4);\n    // file name length\n    header += decToHex(utfEncodedFileName.length, 2);\n    // extra field length\n    header += decToHex(extraFields.length, 2);\n\n\n    var fileRecord = signature.LOCAL_FILE_HEADER + header + utfEncodedFileName + extraFields;\n\n    var dirRecord = signature.CENTRAL_FILE_HEADER +\n    // version made by (00: DOS)\n    decToHex(versionMadeBy, 2) +\n    // file header (common to file and central directory)\n    header +\n    // file comment length\n    decToHex(utfEncodedComment.length, 2) +\n    // disk number start\n    \"\\x00\\x00\" +\n    // internal file attributes TODO\n    \"\\x00\\x00\" +\n    // external file attributes\n    decToHex(extFileAttr, 4) +\n    // relative offset of local header\n    decToHex(offset, 4) +\n    // file name\n    utfEncodedFileName +\n    // extra field\n    extraFields +\n    // file comment\n    utfEncodedComment;\n\n    return {\n        fileRecord: fileRecord,\n        dirRecord: dirRecord,\n        compressedObject: compressedObject\n    };\n};\n\n\n// return the actual prototype of JSZip\nvar out = {\n    /**\n     * Read an existing zip and merge the data in the current JSZip object.\n     * The implementation is in jszip-load.js, don't forget to include it.\n     * @param {String|ArrayBuffer|Uint8Array|Buffer} stream  The stream to load\n     * @param {Object} options Options for loading the stream.\n     *  options.base64 : is the stream in base64 ? default : false\n     * @return {JSZip} the current JSZip object\n     */\n    load: function(stream, options) {\n        throw new Error(\"Load method is not defined. Is the file jszip-load.js included ?\");\n    },\n\n    /**\n     * Filter nested files/folders with the specified function.\n     * @param {Function} search the predicate to use :\n     * function (relativePath, file) {...}\n     * It takes 2 arguments : the relative path and the file.\n     * @return {Array} An array of matching elements.\n     */\n    filter: function(search) {\n        var result = [],\n            filename, relativePath, file, fileClone;\n        for (filename in this.files) {\n            if (!this.files.hasOwnProperty(filename)) {\n                continue;\n            }\n            file = this.files[filename];\n            // return a new object, don't let the user mess with our internal objects :)\n            fileClone = new ZipObject(file.name, file._data, extend(file.options));\n            relativePath = filename.slice(this.root.length, filename.length);\n            if (filename.slice(0, this.root.length) === this.root && // the file is in the current root\n            search(relativePath, fileClone)) { // and the file matches the function\n                result.push(fileClone);\n            }\n        }\n        return result;\n    },\n\n    /**\n     * Add a file to the zip file, or search a file.\n     * @param   {string|RegExp} name The name of the file to add (if data is defined),\n     * the name of the file to find (if no data) or a regex to match files.\n     * @param   {String|ArrayBuffer|Uint8Array|Buffer} data  The file data, either raw or base64 encoded\n     * @param   {Object} o     File options\n     * @return  {JSZip|Object|Array} this JSZip object (when adding a file),\n     * a file (when searching by string) or an array of files (when searching by regex).\n     */\n    file: function(name, data, o) {\n        if (arguments.length === 1) {\n            if (utils.isRegExp(name)) {\n                var regexp = name;\n                return this.filter(function(relativePath, file) {\n                    return !file.dir && regexp.test(relativePath);\n                });\n            }\n            else { // text\n                return this.filter(function(relativePath, file) {\n                    return !file.dir && relativePath === name;\n                })[0] || null;\n            }\n        }\n        else { // more than one argument : we have data !\n            name = this.root + name;\n            fileAdd.call(this, name, data, o);\n        }\n        return this;\n    },\n\n    /**\n     * Add a directory to the zip file, or search.\n     * @param   {String|RegExp} arg The name of the directory to add, or a regex to search folders.\n     * @return  {JSZip} an object with the new directory as the root, or an array containing matching folders.\n     */\n    folder: function(arg) {\n        if (!arg) {\n            return this;\n        }\n\n        if (utils.isRegExp(arg)) {\n            return this.filter(function(relativePath, file) {\n                return file.dir && arg.test(relativePath);\n            });\n        }\n\n        // else, name is a new folder\n        var name = this.root + arg;\n        var newFolder = folderAdd.call(this, name);\n\n        // Allow chaining by returning a new object with this folder as the root\n        var ret = this.clone();\n        ret.root = newFolder.name;\n        return ret;\n    },\n\n    /**\n     * Delete a file, or a directory and all sub-files, from the zip\n     * @param {string} name the name of the file to delete\n     * @return {JSZip} this JSZip object\n     */\n    remove: function(name) {\n        name = this.root + name;\n        var file = this.files[name];\n        if (!file) {\n            // Look for any folders\n            if (name.slice(-1) != \"/\") {\n                name += \"/\";\n            }\n            file = this.files[name];\n        }\n\n        if (file && !file.dir) {\n            // file\n            delete this.files[name];\n        } else {\n            // maybe a folder, delete recursively\n            var kids = this.filter(function(relativePath, file) {\n                return file.name.slice(0, name.length) === name;\n            });\n            for (var i = 0; i < kids.length; i++) {\n                delete this.files[kids[i].name];\n            }\n        }\n\n        return this;\n    },\n\n    /**\n     * Generate the complete zip file\n     * @param {Object} options the options to generate the zip file :\n     * - base64, (deprecated, use type instead) true to generate base64.\n     * - compression, \"STORE\" by default.\n     * - type, \"base64\" by default. Values are : string, base64, uint8array, arraybuffer, blob.\n     * @return {String|Uint8Array|ArrayBuffer|Buffer|Blob} the zip file\n     */\n    generate: function(options) {\n        options = extend(options || {}, {\n            base64: true,\n            compression: \"STORE\",\n            compressionOptions : null,\n            type: \"base64\",\n            platform: \"DOS\",\n            comment: null,\n            mimeType: 'application/zip'\n        });\n\n        utils.checkSupport(options.type);\n\n        // accept nodejs `process.platform`\n        if(\n          options.platform === 'darwin' ||\n          options.platform === 'freebsd' ||\n          options.platform === 'linux' ||\n          options.platform === 'sunos'\n        ) {\n          options.platform = \"UNIX\";\n        }\n        if (options.platform === 'win32') {\n          options.platform = \"DOS\";\n        }\n\n        var zipData = [],\n            localDirLength = 0,\n            centralDirLength = 0,\n            writer, i,\n            utfEncodedComment = utils.transformTo(\"string\", this.utf8encode(options.comment || this.comment || \"\"));\n\n        // first, generate all the zip parts.\n        for (var name in this.files) {\n            if (!this.files.hasOwnProperty(name)) {\n                continue;\n            }\n            var file = this.files[name];\n\n            var compressionName = file.options.compression || options.compression.toUpperCase();\n            var compression = compressions[compressionName];\n            if (!compression) {\n                throw new Error(compressionName + \" is not a valid compression method !\");\n            }\n            var compressionOptions = file.options.compressionOptions || options.compressionOptions || {};\n\n            var compressedObject = generateCompressedObjectFrom.call(this, file, compression, compressionOptions);\n\n            var zipPart = generateZipParts.call(this, name, file, compressedObject, localDirLength, options.platform);\n            localDirLength += zipPart.fileRecord.length + compressedObject.compressedSize;\n            centralDirLength += zipPart.dirRecord.length;\n            zipData.push(zipPart);\n        }\n\n        var dirEnd = \"\";\n\n        // end of central dir signature\n        dirEnd = signature.CENTRAL_DIRECTORY_END +\n        // number of this disk\n        \"\\x00\\x00\" +\n        // number of the disk with the start of the central directory\n        \"\\x00\\x00\" +\n        // total number of entries in the central directory on this disk\n        decToHex(zipData.length, 2) +\n        // total number of entries in the central directory\n        decToHex(zipData.length, 2) +\n        // size of the central directory   4 bytes\n        decToHex(centralDirLength, 4) +\n        // offset of start of central directory with respect to the starting disk number\n        decToHex(localDirLength, 4) +\n        // .ZIP file comment length\n        decToHex(utfEncodedComment.length, 2) +\n        // .ZIP file comment\n        utfEncodedComment;\n\n\n        // we have all the parts (and the total length)\n        // time to create a writer !\n        var typeName = options.type.toLowerCase();\n        if(typeName===\"uint8array\"||typeName===\"arraybuffer\"||typeName===\"blob\"||typeName===\"nodebuffer\") {\n            writer = new Uint8ArrayWriter(localDirLength + centralDirLength + dirEnd.length);\n        }else{\n            writer = new StringWriter(localDirLength + centralDirLength + dirEnd.length);\n        }\n\n        for (i = 0; i < zipData.length; i++) {\n            writer.append(zipData[i].fileRecord);\n            writer.append(zipData[i].compressedObject.compressedContent);\n        }\n        for (i = 0; i < zipData.length; i++) {\n            writer.append(zipData[i].dirRecord);\n        }\n\n        writer.append(dirEnd);\n\n        var zip = writer.finalize();\n\n\n\n        switch(options.type.toLowerCase()) {\n            // case \"zip is an Uint8Array\"\n            case \"uint8array\" :\n            case \"arraybuffer\" :\n            case \"nodebuffer\" :\n               return utils.transformTo(options.type.toLowerCase(), zip);\n            case \"blob\" :\n               return utils.arrayBuffer2Blob(utils.transformTo(\"arraybuffer\", zip), options.mimeType);\n            // case \"zip is a string\"\n            case \"base64\" :\n               return (options.base64) ? base64.encode(zip) : zip;\n            default : // case \"string\" :\n               return zip;\n         }\n\n    },\n\n    /**\n     * @deprecated\n     * This method will be removed in a future version without replacement.\n     */\n    crc32: function (input, crc) {\n        return crc32(input, crc);\n    },\n\n    /**\n     * @deprecated\n     * This method will be removed in a future version without replacement.\n     */\n    utf8encode: function (string) {\n        return utils.transformTo(\"string\", utf8.utf8encode(string));\n    },\n\n    /**\n     * @deprecated\n     * This method will be removed in a future version without replacement.\n     */\n    utf8decode: function (input) {\n        return utf8.utf8decode(input);\n    }\n};\nmodule.exports = out;\n\n},{\"./base64\":1,\"./compressedObject\":2,\"./compressions\":3,\"./crc32\":4,\"./defaults\":6,\"./nodeBuffer\":11,\"./signature\":14,\"./stringWriter\":16,\"./support\":17,\"./uint8ArrayWriter\":19,\"./utf8\":20,\"./utils\":21}],14:[function(_dereq_,module,exports){\n'use strict';\nexports.LOCAL_FILE_HEADER = \"PK\\x03\\x04\";\nexports.CENTRAL_FILE_HEADER = \"PK\\x01\\x02\";\nexports.CENTRAL_DIRECTORY_END = \"PK\\x05\\x06\";\nexports.ZIP64_CENTRAL_DIRECTORY_LOCATOR = \"PK\\x06\\x07\";\nexports.ZIP64_CENTRAL_DIRECTORY_END = \"PK\\x06\\x06\";\nexports.DATA_DESCRIPTOR = \"PK\\x07\\x08\";\n\n},{}],15:[function(_dereq_,module,exports){\n'use strict';\nvar DataReader = _dereq_('./dataReader');\nvar utils = _dereq_('./utils');\n\nfunction StringReader(data, optimizedBinaryString) {\n    this.data = data;\n    if (!optimizedBinaryString) {\n        this.data = utils.string2binary(this.data);\n    }\n    this.length = this.data.length;\n    this.index = 0;\n}\nStringReader.prototype = new DataReader();\n/**\n * @see DataReader.byteAt\n */\nStringReader.prototype.byteAt = function(i) {\n    return this.data.charCodeAt(i);\n};\n/**\n * @see DataReader.lastIndexOfSignature\n */\nStringReader.prototype.lastIndexOfSignature = function(sig) {\n    return this.data.lastIndexOf(sig);\n};\n/**\n * @see DataReader.readData\n */\nStringReader.prototype.readData = function(size) {\n    this.checkOffset(size);\n    // this will work because the constructor applied the \"& 0xff\" mask.\n    var result = this.data.slice(this.index, this.index + size);\n    this.index += size;\n    return result;\n};\nmodule.exports = StringReader;\n\n},{\"./dataReader\":5,\"./utils\":21}],16:[function(_dereq_,module,exports){\n'use strict';\n\nvar utils = _dereq_('./utils');\n\n/**\n * An object to write any content to a string.\n * @constructor\n */\nvar StringWriter = function() {\n    this.data = [];\n};\nStringWriter.prototype = {\n    /**\n     * Append any content to the current string.\n     * @param {Object} input the content to add.\n     */\n    append: function(input) {\n        input = utils.transformTo(\"string\", input);\n        this.data.push(input);\n    },\n    /**\n     * Finalize the construction an return the result.\n     * @return {string} the generated string.\n     */\n    finalize: function() {\n        return this.data.join(\"\");\n    }\n};\n\nmodule.exports = StringWriter;\n\n},{\"./utils\":21}],17:[function(_dereq_,module,exports){\n(function (Buffer){\n'use strict';\nexports.base64 = true;\nexports.array = true;\nexports.string = true;\nexports.arraybuffer = typeof ArrayBuffer !== \"undefined\" && typeof Uint8Array !== \"undefined\";\n// contains true if JSZip can read/generate nodejs Buffer, false otherwise.\n// Browserify will provide a Buffer implementation for browsers, which is\n// an augmented Uint8Array (i.e., can be used as either Buffer or U8).\nexports.nodebuffer = typeof Buffer !== \"undefined\";\n// contains true if JSZip can read/generate Uint8Array, false otherwise.\nexports.uint8array = typeof Uint8Array !== \"undefined\";\n\nif (typeof ArrayBuffer === \"undefined\") {\n    exports.blob = false;\n}\nelse {\n    var buffer = new ArrayBuffer(0);\n    try {\n        exports.blob = new Blob([buffer], {\n            type: \"application/zip\"\n        }).size === 0;\n    }\n    catch (e) {\n        try {\n            var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;\n            var builder = new Builder();\n            builder.append(buffer);\n            exports.blob = builder.getBlob('application/zip').size === 0;\n        }\n        catch (e) {\n            exports.blob = false;\n        }\n    }\n}\n\n}).call(this,(typeof Buffer !== \"undefined\" ? Buffer : undefined))\n},{}],18:[function(_dereq_,module,exports){\n'use strict';\nvar DataReader = _dereq_('./dataReader');\n\nfunction Uint8ArrayReader(data) {\n    if (data) {\n        this.data = data;\n        this.length = this.data.length;\n        this.index = 0;\n    }\n}\nUint8ArrayReader.prototype = new DataReader();\n/**\n * @see DataReader.byteAt\n */\nUint8ArrayReader.prototype.byteAt = function(i) {\n    return this.data[i];\n};\n/**\n * @see DataReader.lastIndexOfSignature\n */\nUint8ArrayReader.prototype.lastIndexOfSignature = function(sig) {\n    var sig0 = sig.charCodeAt(0),\n        sig1 = sig.charCodeAt(1),\n        sig2 = sig.charCodeAt(2),\n        sig3 = sig.charCodeAt(3);\n    for (var i = this.length - 4; i >= 0; --i) {\n        if (this.data[i] === sig0 && this.data[i + 1] === sig1 && this.data[i + 2] === sig2 && this.data[i + 3] === sig3) {\n            return i;\n        }\n    }\n\n    return -1;\n};\n/**\n * @see DataReader.readData\n */\nUint8ArrayReader.prototype.readData = function(size) {\n    this.checkOffset(size);\n    if(size === 0) {\n        // in IE10, when using subarray(idx, idx), we get the array [0x00] instead of [].\n        return new Uint8Array(0);\n    }\n    var result = this.data.subarray(this.index, this.index + size);\n    this.index += size;\n    return result;\n};\nmodule.exports = Uint8ArrayReader;\n\n},{\"./dataReader\":5}],19:[function(_dereq_,module,exports){\n'use strict';\n\nvar utils = _dereq_('./utils');\n\n/**\n * An object to write any content to an Uint8Array.\n * @constructor\n * @param {number} length The length of the array.\n */\nvar Uint8ArrayWriter = function(length) {\n    this.data = new Uint8Array(length);\n    this.index = 0;\n};\nUint8ArrayWriter.prototype = {\n    /**\n     * Append any content to the current array.\n     * @param {Object} input the content to add.\n     */\n    append: function(input) {\n        if (input.length !== 0) {\n            // with an empty Uint8Array, Opera fails with a \"Offset larger than array size\"\n            input = utils.transformTo(\"uint8array\", input);\n            this.data.set(input, this.index);\n            this.index += input.length;\n        }\n    },\n    /**\n     * Finalize the construction an return the result.\n     * @return {Uint8Array} the generated array.\n     */\n    finalize: function() {\n        return this.data;\n    }\n};\n\nmodule.exports = Uint8ArrayWriter;\n\n},{\"./utils\":21}],20:[function(_dereq_,module,exports){\n'use strict';\n\nvar utils = _dereq_('./utils');\nvar support = _dereq_('./support');\nvar nodeBuffer = _dereq_('./nodeBuffer');\n\n/**\n * The following functions come from pako, from pako/lib/utils/strings\n * released under the MIT license, see pako https://github.com/nodeca/pako/\n */\n\n// Table with utf8 lengths (calculated by first byte of sequence)\n// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,\n// because max possible codepoint is 0x10ffff\nvar _utf8len = new Array(256);\nfor (var i=0; i<256; i++) {\n  _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1);\n}\n_utf8len[254]=_utf8len[254]=1; // Invalid sequence start\n\n// convert string to array (typed, when possible)\nvar string2buf = function (str) {\n    var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;\n\n    // count binary size\n    for (m_pos = 0; m_pos < str_len; m_pos++) {\n        c = str.charCodeAt(m_pos);\n        if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {\n            c2 = str.charCodeAt(m_pos+1);\n            if ((c2 & 0xfc00) === 0xdc00) {\n                c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);\n                m_pos++;\n            }\n        }\n        buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;\n    }\n\n    // allocate buffer\n    if (support.uint8array) {\n        buf = new Uint8Array(buf_len);\n    } else {\n        buf = new Array(buf_len);\n    }\n\n    // convert\n    for (i=0, m_pos = 0; i < buf_len; m_pos++) {\n        c = str.charCodeAt(m_pos);\n        if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {\n            c2 = str.charCodeAt(m_pos+1);\n            if ((c2 & 0xfc00) === 0xdc00) {\n                c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);\n                m_pos++;\n            }\n        }\n        if (c < 0x80) {\n            /* one byte */\n            buf[i++] = c;\n        } else if (c < 0x800) {\n            /* two bytes */\n            buf[i++] = 0xC0 | (c >>> 6);\n            buf[i++] = 0x80 | (c & 0x3f);\n        } else if (c < 0x10000) {\n            /* three bytes */\n            buf[i++] = 0xE0 | (c >>> 12);\n            buf[i++] = 0x80 | (c >>> 6 & 0x3f);\n            buf[i++] = 0x80 | (c & 0x3f);\n        } else {\n            /* four bytes */\n            buf[i++] = 0xf0 | (c >>> 18);\n            buf[i++] = 0x80 | (c >>> 12 & 0x3f);\n            buf[i++] = 0x80 | (c >>> 6 & 0x3f);\n            buf[i++] = 0x80 | (c & 0x3f);\n        }\n    }\n\n    return buf;\n};\n\n// Calculate max possible position in utf8 buffer,\n// that will not break sequence. If that's not possible\n// - (very small limits) return max size as is.\n//\n// buf[] - utf8 bytes array\n// max   - length limit (mandatory);\nvar utf8border = function(buf, max) {\n    var pos;\n\n    max = max || buf.length;\n    if (max > buf.length) { max = buf.length; }\n\n    // go back from last position, until start of sequence found\n    pos = max-1;\n    while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }\n\n    // Fuckup - very small and broken sequence,\n    // return max, because we should return something anyway.\n    if (pos < 0) { return max; }\n\n    // If we came to start of buffer - that means vuffer is too small,\n    // return max too.\n    if (pos === 0) { return max; }\n\n    return (pos + _utf8len[buf[pos]] > max) ? pos : max;\n};\n\n// convert array to string\nvar buf2string = function (buf) {\n    var str, i, out, c, c_len;\n    var len = buf.length;\n\n    // Reserve max possible length (2 words per char)\n    // NB: by unknown reasons, Array is significantly faster for\n    //     String.fromCharCode.apply than Uint16Array.\n    var utf16buf = new Array(len*2);\n\n    for (out=0, i=0; i<len;) {\n        c = buf[i++];\n        // quick process ascii\n        if (c < 0x80) { utf16buf[out++] = c; continue; }\n\n        c_len = _utf8len[c];\n        // skip 5 & 6 byte codes\n        if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; }\n\n        // apply mask on first byte\n        c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;\n        // join the rest\n        while (c_len > 1 && i < len) {\n            c = (c << 6) | (buf[i++] & 0x3f);\n            c_len--;\n        }\n\n        // terminated by end of string?\n        if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }\n\n        if (c < 0x10000) {\n            utf16buf[out++] = c;\n        } else {\n            c -= 0x10000;\n            utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);\n            utf16buf[out++] = 0xdc00 | (c & 0x3ff);\n        }\n    }\n\n    // shrinkBuf(utf16buf, out)\n    if (utf16buf.length !== out) {\n        if(utf16buf.subarray) {\n            utf16buf = utf16buf.subarray(0, out);\n        } else {\n            utf16buf.length = out;\n        }\n    }\n\n    // return String.fromCharCode.apply(null, utf16buf);\n    return utils.applyFromCharCode(utf16buf);\n};\n\n\n// That's all for the pako functions.\n\n\n/**\n * Transform a javascript string into an array (typed if possible) of bytes,\n * UTF-8 encoded.\n * @param {String} str the string to encode\n * @return {Array|Uint8Array|Buffer} the UTF-8 encoded string.\n */\nexports.utf8encode = function utf8encode(str) {\n    if (support.nodebuffer) {\n        return nodeBuffer(str, \"utf-8\");\n    }\n\n    return string2buf(str);\n};\n\n\n/**\n * Transform a bytes array (or a representation) representing an UTF-8 encoded\n * string into a javascript string.\n * @param {Array|Uint8Array|Buffer} buf the data de decode\n * @return {String} the decoded string.\n */\nexports.utf8decode = function utf8decode(buf) {\n    if (support.nodebuffer) {\n        return utils.transformTo(\"nodebuffer\", buf).toString(\"utf-8\");\n    }\n\n    buf = utils.transformTo(support.uint8array ? \"uint8array\" : \"array\", buf);\n\n    // return buf2string(buf);\n    // Chrome prefers to work with \"small\" chunks of data\n    // for the method buf2string.\n    // Firefox and Chrome has their own shortcut, IE doesn't seem to really care.\n    var result = [], k = 0, len = buf.length, chunk = 65536;\n    while (k < len) {\n        var nextBoundary = utf8border(buf, Math.min(k + chunk, len));\n        if (support.uint8array) {\n            result.push(buf2string(buf.subarray(k, nextBoundary)));\n        } else {\n            result.push(buf2string(buf.slice(k, nextBoundary)));\n        }\n        k = nextBoundary;\n    }\n    return result.join(\"\");\n\n};\n// vim: set shiftwidth=4 softtabstop=4:\n\n},{\"./nodeBuffer\":11,\"./support\":17,\"./utils\":21}],21:[function(_dereq_,module,exports){\n'use strict';\nvar support = _dereq_('./support');\nvar compressions = _dereq_('./compressions');\nvar nodeBuffer = _dereq_('./nodeBuffer');\n/**\n * Convert a string to a \"binary string\" : a string containing only char codes between 0 and 255.\n * @param {string} str the string to transform.\n * @return {String} the binary string.\n */\nexports.string2binary = function(str) {\n    var result = \"\";\n    for (var i = 0; i < str.length; i++) {\n        result += String.fromCharCode(str.charCodeAt(i) & 0xff);\n    }\n    return result;\n};\nexports.arrayBuffer2Blob = function(buffer, mimeType) {\n    exports.checkSupport(\"blob\");\n\tmimeType = mimeType || 'application/zip';\n\n    try {\n        // Blob constructor\n        return new Blob([buffer], {\n            type: mimeType\n        });\n    }\n    catch (e) {\n\n        try {\n            // deprecated, browser only, old way\n            var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;\n            var builder = new Builder();\n            builder.append(buffer);\n            return builder.getBlob(mimeType);\n        }\n        catch (e) {\n\n            // well, fuck ?!\n            throw new Error(\"Bug : can't construct the Blob.\");\n        }\n    }\n\n\n};\n/**\n * The identity function.\n * @param {Object} input the input.\n * @return {Object} the same input.\n */\nfunction identity(input) {\n    return input;\n}\n\n/**\n * Fill in an array with a string.\n * @param {String} str the string to use.\n * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to fill in (will be mutated).\n * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated array.\n */\nfunction stringToArrayLike(str, array) {\n    for (var i = 0; i < str.length; ++i) {\n        array[i] = str.charCodeAt(i) & 0xFF;\n    }\n    return array;\n}\n\n/**\n * Transform an array-like object to a string.\n * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to transform.\n * @return {String} the result.\n */\nfunction arrayLikeToString(array) {\n    // Performances notes :\n    // --------------------\n    // String.fromCharCode.apply(null, array) is the fastest, see\n    // see http://jsperf.com/converting-a-uint8array-to-a-string/2\n    // but the stack is limited (and we can get huge arrays !).\n    //\n    // result += String.fromCharCode(array[i]); generate too many strings !\n    //\n    // This code is inspired by http://jsperf.com/arraybuffer-to-string-apply-performance/2\n    var chunk = 65536;\n    var result = [],\n        len = array.length,\n        type = exports.getTypeOf(array),\n        k = 0,\n        canUseApply = true;\n      try {\n         switch(type) {\n            case \"uint8array\":\n               String.fromCharCode.apply(null, new Uint8Array(0));\n               break;\n            case \"nodebuffer\":\n               String.fromCharCode.apply(null, nodeBuffer(0));\n               break;\n         }\n      } catch(e) {\n         canUseApply = false;\n      }\n\n      // no apply : slow and painful algorithm\n      // default browser on android 4.*\n      if (!canUseApply) {\n         var resultStr = \"\";\n         for(var i = 0; i < array.length;i++) {\n            resultStr += String.fromCharCode(array[i]);\n         }\n    return resultStr;\n    }\n    while (k < len && chunk > 1) {\n        try {\n            if (type === \"array\" || type === \"nodebuffer\") {\n                result.push(String.fromCharCode.apply(null, array.slice(k, Math.min(k + chunk, len))));\n            }\n            else {\n                result.push(String.fromCharCode.apply(null, array.subarray(k, Math.min(k + chunk, len))));\n            }\n            k += chunk;\n        }\n        catch (e) {\n            chunk = Math.floor(chunk / 2);\n        }\n    }\n    return result.join(\"\");\n}\n\nexports.applyFromCharCode = arrayLikeToString;\n\n\n/**\n * Copy the data from an array-like to an other array-like.\n * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayFrom the origin array.\n * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayTo the destination array which will be mutated.\n * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated destination array.\n */\nfunction arrayLikeToArrayLike(arrayFrom, arrayTo) {\n    for (var i = 0; i < arrayFrom.length; i++) {\n        arrayTo[i] = arrayFrom[i];\n    }\n    return arrayTo;\n}\n\n// a matrix containing functions to transform everything into everything.\nvar transform = {};\n\n// string to ?\ntransform[\"string\"] = {\n    \"string\": identity,\n    \"array\": function(input) {\n        return stringToArrayLike(input, new Array(input.length));\n    },\n    \"arraybuffer\": function(input) {\n        return transform[\"string\"][\"uint8array\"](input).buffer;\n    },\n    \"uint8array\": function(input) {\n        return stringToArrayLike(input, new Uint8Array(input.length));\n    },\n    \"nodebuffer\": function(input) {\n        return stringToArrayLike(input, nodeBuffer(input.length));\n    }\n};\n\n// array to ?\ntransform[\"array\"] = {\n    \"string\": arrayLikeToString,\n    \"array\": identity,\n    \"arraybuffer\": function(input) {\n        return (new Uint8Array(input)).buffer;\n    },\n    \"uint8array\": function(input) {\n        return new Uint8Array(input);\n    },\n    \"nodebuffer\": function(input) {\n        return nodeBuffer(input);\n    }\n};\n\n// arraybuffer to ?\ntransform[\"arraybuffer\"] = {\n    \"string\": function(input) {\n        return arrayLikeToString(new Uint8Array(input));\n    },\n    \"array\": function(input) {\n        return arrayLikeToArrayLike(new Uint8Array(input), new Array(input.byteLength));\n    },\n    \"arraybuffer\": identity,\n    \"uint8array\": function(input) {\n        return new Uint8Array(input);\n    },\n    \"nodebuffer\": function(input) {\n        return nodeBuffer(new Uint8Array(input));\n    }\n};\n\n// uint8array to ?\ntransform[\"uint8array\"] = {\n    \"string\": arrayLikeToString,\n    \"array\": function(input) {\n        return arrayLikeToArrayLike(input, new Array(input.length));\n    },\n    \"arraybuffer\": function(input) {\n        return input.buffer;\n    },\n    \"uint8array\": identity,\n    \"nodebuffer\": function(input) {\n        return nodeBuffer(input);\n    }\n};\n\n// nodebuffer to ?\ntransform[\"nodebuffer\"] = {\n    \"string\": arrayLikeToString,\n    \"array\": function(input) {\n        return arrayLikeToArrayLike(input, new Array(input.length));\n    },\n    \"arraybuffer\": function(input) {\n        return transform[\"nodebuffer\"][\"uint8array\"](input).buffer;\n    },\n    \"uint8array\": function(input) {\n        return arrayLikeToArrayLike(input, new Uint8Array(input.length));\n    },\n    \"nodebuffer\": identity\n};\n\n/**\n * Transform an input into any type.\n * The supported output type are : string, array, uint8array, arraybuffer, nodebuffer.\n * If no output type is specified, the unmodified input will be returned.\n * @param {String} outputType the output type.\n * @param {String|Array|ArrayBuffer|Uint8Array|Buffer} input the input to convert.\n * @throws {Error} an Error if the browser doesn't support the requested output type.\n */\nexports.transformTo = function(outputType, input) {\n    if (!input) {\n        // undefined, null, etc\n        // an empty string won't harm.\n        input = \"\";\n    }\n    if (!outputType) {\n        return input;\n    }\n    exports.checkSupport(outputType);\n    var inputType = exports.getTypeOf(input);\n    var result = transform[inputType][outputType](input);\n    return result;\n};\n\n/**\n * Return the type of the input.\n * The type will be in a format valid for JSZip.utils.transformTo : string, array, uint8array, arraybuffer.\n * @param {Object} input the input to identify.\n * @return {String} the (lowercase) type of the input.\n */\nexports.getTypeOf = function(input) {\n    if (typeof input === \"string\") {\n        return \"string\";\n    }\n    if (Object.prototype.toString.call(input) === \"[object Array]\") {\n        return \"array\";\n    }\n    if (support.nodebuffer && nodeBuffer.test(input)) {\n        return \"nodebuffer\";\n    }\n    if (support.uint8array && input instanceof Uint8Array) {\n        return \"uint8array\";\n    }\n    if (support.arraybuffer && input instanceof ArrayBuffer) {\n        return \"arraybuffer\";\n    }\n};\n\n/**\n * Throw an exception if the type is not supported.\n * @param {String} type the type to check.\n * @throws {Error} an Error if the browser doesn't support the requested type.\n */\nexports.checkSupport = function(type) {\n    var supported = support[type.toLowerCase()];\n    if (!supported) {\n        throw new Error(type + \" is not supported by this browser\");\n    }\n};\nexports.MAX_VALUE_16BITS = 65535;\nexports.MAX_VALUE_32BITS = -1; // well, \"\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\" is parsed as -1\n\n/**\n * Prettify a string read as binary.\n * @param {string} str the string to prettify.\n * @return {string} a pretty string.\n */\nexports.pretty = function(str) {\n    var res = '',\n        code, i;\n    for (i = 0; i < (str || \"\").length; i++) {\n        code = str.charCodeAt(i);\n        res += '\\\\x' + (code < 16 ? \"0\" : \"\") + code.toString(16).toUpperCase();\n    }\n    return res;\n};\n\n/**\n * Find a compression registered in JSZip.\n * @param {string} compressionMethod the method magic to find.\n * @return {Object|null} the JSZip compression object, null if none found.\n */\nexports.findCompression = function(compressionMethod) {\n    for (var method in compressions) {\n        if (!compressions.hasOwnProperty(method)) {\n            continue;\n        }\n        if (compressions[method].magic === compressionMethod) {\n            return compressions[method];\n        }\n    }\n    return null;\n};\n/**\n* Cross-window, cross-Node-context regular expression detection\n* @param  {Object}  object Anything\n* @return {Boolean}        true if the object is a regular expression,\n* false otherwise\n*/\nexports.isRegExp = function (object) {\n    return Object.prototype.toString.call(object) === \"[object RegExp]\";\n};\n\n\n},{\"./compressions\":3,\"./nodeBuffer\":11,\"./support\":17}],22:[function(_dereq_,module,exports){\n'use strict';\nvar StringReader = _dereq_('./stringReader');\nvar NodeBufferReader = _dereq_('./nodeBufferReader');\nvar Uint8ArrayReader = _dereq_('./uint8ArrayReader');\nvar utils = _dereq_('./utils');\nvar sig = _dereq_('./signature');\nvar ZipEntry = _dereq_('./zipEntry');\nvar support = _dereq_('./support');\nvar jszipProto = _dereq_('./object');\n//  class ZipEntries {{{\n/**\n * All the entries in the zip file.\n * @constructor\n * @param {String|ArrayBuffer|Uint8Array} data the binary stream to load.\n * @param {Object} loadOptions Options for loading the stream.\n */\nfunction ZipEntries(data, loadOptions) {\n    this.files = [];\n    this.loadOptions = loadOptions;\n    if (data) {\n        this.load(data);\n    }\n}\nZipEntries.prototype = {\n    /**\n     * Check that the reader is on the speficied signature.\n     * @param {string} expectedSignature the expected signature.\n     * @throws {Error} if it is an other signature.\n     */\n    checkSignature: function(expectedSignature) {\n        var signature = this.reader.readString(4);\n        if (signature !== expectedSignature) {\n            throw new Error(\"Corrupted zip or bug : unexpected signature \" + \"(\" + utils.pretty(signature) + \", expected \" + utils.pretty(expectedSignature) + \")\");\n        }\n    },\n    /**\n     * Read the end of the central directory.\n     */\n    readBlockEndOfCentral: function() {\n        this.diskNumber = this.reader.readInt(2);\n        this.diskWithCentralDirStart = this.reader.readInt(2);\n        this.centralDirRecordsOnThisDisk = this.reader.readInt(2);\n        this.centralDirRecords = this.reader.readInt(2);\n        this.centralDirSize = this.reader.readInt(4);\n        this.centralDirOffset = this.reader.readInt(4);\n\n        this.zipCommentLength = this.reader.readInt(2);\n        // warning : the encoding depends of the system locale\n        // On a linux machine with LANG=en_US.utf8, this field is utf8 encoded.\n        // On a windows machine, this field is encoded with the localized windows code page.\n        this.zipComment = this.reader.readString(this.zipCommentLength);\n        // To get consistent behavior with the generation part, we will assume that\n        // this is utf8 encoded.\n        this.zipComment = jszipProto.utf8decode(this.zipComment);\n    },\n    /**\n     * Read the end of the Zip 64 central directory.\n     * Not merged with the method readEndOfCentral :\n     * The end of central can coexist with its Zip64 brother,\n     * I don't want to read the wrong number of bytes !\n     */\n    readBlockZip64EndOfCentral: function() {\n        this.zip64EndOfCentralSize = this.reader.readInt(8);\n        this.versionMadeBy = this.reader.readString(2);\n        this.versionNeeded = this.reader.readInt(2);\n        this.diskNumber = this.reader.readInt(4);\n        this.diskWithCentralDirStart = this.reader.readInt(4);\n        this.centralDirRecordsOnThisDisk = this.reader.readInt(8);\n        this.centralDirRecords = this.reader.readInt(8);\n        this.centralDirSize = this.reader.readInt(8);\n        this.centralDirOffset = this.reader.readInt(8);\n\n        this.zip64ExtensibleData = {};\n        var extraDataSize = this.zip64EndOfCentralSize - 44,\n            index = 0,\n            extraFieldId,\n            extraFieldLength,\n            extraFieldValue;\n        while (index < extraDataSize) {\n            extraFieldId = this.reader.readInt(2);\n            extraFieldLength = this.reader.readInt(4);\n            extraFieldValue = this.reader.readString(extraFieldLength);\n            this.zip64ExtensibleData[extraFieldId] = {\n                id: extraFieldId,\n                length: extraFieldLength,\n                value: extraFieldValue\n            };\n        }\n    },\n    /**\n     * Read the end of the Zip 64 central directory locator.\n     */\n    readBlockZip64EndOfCentralLocator: function() {\n        this.diskWithZip64CentralDirStart = this.reader.readInt(4);\n        this.relativeOffsetEndOfZip64CentralDir = this.reader.readInt(8);\n        this.disksCount = this.reader.readInt(4);\n        if (this.disksCount > 1) {\n            throw new Error(\"Multi-volumes zip are not supported\");\n        }\n    },\n    /**\n     * Read the local files, based on the offset read in the central part.\n     */\n    readLocalFiles: function() {\n        var i, file;\n        for (i = 0; i < this.files.length; i++) {\n            file = this.files[i];\n            this.reader.setIndex(file.localHeaderOffset);\n            this.checkSignature(sig.LOCAL_FILE_HEADER);\n            file.readLocalPart(this.reader);\n            file.handleUTF8();\n            file.processAttributes();\n        }\n    },\n    /**\n     * Read the central directory.\n     */\n    readCentralDir: function() {\n        var file;\n\n        this.reader.setIndex(this.centralDirOffset);\n        while (this.reader.readString(4) === sig.CENTRAL_FILE_HEADER) {\n            file = new ZipEntry({\n                zip64: this.zip64\n            }, this.loadOptions);\n            file.readCentralPart(this.reader);\n            this.files.push(file);\n        }\n    },\n    /**\n     * Read the end of central directory.\n     */\n    readEndOfCentral: function() {\n        var offset = this.reader.lastIndexOfSignature(sig.CENTRAL_DIRECTORY_END);\n        if (offset === -1) {\n            // Check if the content is a truncated zip or complete garbage.\n            // A \"LOCAL_FILE_HEADER\" is not required at the beginning (auto\n            // extractible zip for example) but it can give a good hint.\n            // If an ajax request was used without responseType, we will also\n            // get unreadable data.\n            var isGarbage = true;\n            try {\n                this.reader.setIndex(0);\n                this.checkSignature(sig.LOCAL_FILE_HEADER);\n                isGarbage = false;\n            } catch (e) {}\n\n            if (isGarbage) {\n                throw new Error(\"Can't find end of central directory : is this a zip file ? \" +\n                                \"If it is, see http://stuk.github.io/jszip/documentation/howto/read_zip.html\");\n            } else {\n                throw new Error(\"Corrupted zip : can't find end of central directory\");\n            }\n        }\n        this.reader.setIndex(offset);\n        this.checkSignature(sig.CENTRAL_DIRECTORY_END);\n        this.readBlockEndOfCentral();\n\n\n        /* extract from the zip spec :\n            4)  If one of the fields in the end of central directory\n                record is too small to hold required data, the field\n                should be set to -1 (0xFFFF or 0xFFFFFFFF) and the\n                ZIP64 format record should be created.\n            5)  The end of central directory record and the\n                Zip64 end of central directory locator record must\n                reside on the same disk when splitting or spanning\n                an archive.\n         */\n        if (this.diskNumber === utils.MAX_VALUE_16BITS || this.diskWithCentralDirStart === utils.MAX_VALUE_16BITS || this.centralDirRecordsOnThisDisk === utils.MAX_VALUE_16BITS || this.centralDirRecords === utils.MAX_VALUE_16BITS || this.centralDirSize === utils.MAX_VALUE_32BITS || this.centralDirOffset === utils.MAX_VALUE_32BITS) {\n            this.zip64 = true;\n\n            /*\n            Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from\n            the zip file can fit into a 32bits integer. This cannot be solved : Javascript represents\n            all numbers as 64-bit double precision IEEE 754 floating point numbers.\n            So, we have 53bits for integers and bitwise operations treat everything as 32bits.\n            see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators\n            and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf section 8.5\n            */\n\n            // should look for a zip64 EOCD locator\n            offset = this.reader.lastIndexOfSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR);\n            if (offset === -1) {\n                throw new Error(\"Corrupted zip : can't find the ZIP64 end of central directory locator\");\n            }\n            this.reader.setIndex(offset);\n            this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR);\n            this.readBlockZip64EndOfCentralLocator();\n\n            // now the zip64 EOCD record\n            this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir);\n            this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_END);\n            this.readBlockZip64EndOfCentral();\n        }\n    },\n    prepareReader: function(data) {\n        var type = utils.getTypeOf(data);\n        if (type === \"string\" && !support.uint8array) {\n            this.reader = new StringReader(data, this.loadOptions.optimizedBinaryString);\n        }\n        else if (type === \"nodebuffer\") {\n            this.reader = new NodeBufferReader(data);\n        }\n        else {\n            this.reader = new Uint8ArrayReader(utils.transformTo(\"uint8array\", data));\n        }\n    },\n    /**\n     * Read a zip file and create ZipEntries.\n     * @param {String|ArrayBuffer|Uint8Array|Buffer} data the binary string representing a zip file.\n     */\n    load: function(data) {\n        this.prepareReader(data);\n        this.readEndOfCentral();\n        this.readCentralDir();\n        this.readLocalFiles();\n    }\n};\n// }}} end of ZipEntries\nmodule.exports = ZipEntries;\n\n},{\"./nodeBufferReader\":12,\"./object\":13,\"./signature\":14,\"./stringReader\":15,\"./support\":17,\"./uint8ArrayReader\":18,\"./utils\":21,\"./zipEntry\":23}],23:[function(_dereq_,module,exports){\n'use strict';\nvar StringReader = _dereq_('./stringReader');\nvar utils = _dereq_('./utils');\nvar CompressedObject = _dereq_('./compressedObject');\nvar jszipProto = _dereq_('./object');\n\nvar MADE_BY_DOS = 0x00;\nvar MADE_BY_UNIX = 0x03;\n\n// class ZipEntry {{{\n/**\n * An entry in the zip file.\n * @constructor\n * @param {Object} options Options of the current file.\n * @param {Object} loadOptions Options for loading the stream.\n */\nfunction ZipEntry(options, loadOptions) {\n    this.options = options;\n    this.loadOptions = loadOptions;\n}\nZipEntry.prototype = {\n    /**\n     * say if the file is encrypted.\n     * @return {boolean} true if the file is encrypted, false otherwise.\n     */\n    isEncrypted: function() {\n        // bit 1 is set\n        return (this.bitFlag & 0x0001) === 0x0001;\n    },\n    /**\n     * say if the file has utf-8 filename/comment.\n     * @return {boolean} true if the filename/comment is in utf-8, false otherwise.\n     */\n    useUTF8: function() {\n        // bit 11 is set\n        return (this.bitFlag & 0x0800) === 0x0800;\n    },\n    /**\n     * Prepare the function used to generate the compressed content from this ZipFile.\n     * @param {DataReader} reader the reader to use.\n     * @param {number} from the offset from where we should read the data.\n     * @param {number} length the length of the data to read.\n     * @return {Function} the callback to get the compressed content (the type depends of the DataReader class).\n     */\n    prepareCompressedContent: function(reader, from, length) {\n        return function() {\n            var previousIndex = reader.index;\n            reader.setIndex(from);\n            var compressedFileData = reader.readData(length);\n            reader.setIndex(previousIndex);\n\n            return compressedFileData;\n        };\n    },\n    /**\n     * Prepare the function used to generate the uncompressed content from this ZipFile.\n     * @param {DataReader} reader the reader to use.\n     * @param {number} from the offset from where we should read the data.\n     * @param {number} length the length of the data to read.\n     * @param {JSZip.compression} compression the compression used on this file.\n     * @param {number} uncompressedSize the uncompressed size to expect.\n     * @return {Function} the callback to get the uncompressed content (the type depends of the DataReader class).\n     */\n    prepareContent: function(reader, from, length, compression, uncompressedSize) {\n        return function() {\n\n            var compressedFileData = utils.transformTo(compression.uncompressInputType, this.getCompressedContent());\n            var uncompressedFileData = compression.uncompress(compressedFileData);\n\n            if (uncompressedFileData.length !== uncompressedSize) {\n                throw new Error(\"Bug : uncompressed data size mismatch\");\n            }\n\n            return uncompressedFileData;\n        };\n    },\n    /**\n     * Read the local part of a zip file and add the info in this object.\n     * @param {DataReader} reader the reader to use.\n     */\n    readLocalPart: function(reader) {\n        var compression, localExtraFieldsLength;\n\n        // we already know everything from the central dir !\n        // If the central dir data are false, we are doomed.\n        // On the bright side, the local part is scary  : zip64, data descriptors, both, etc.\n        // The less data we get here, the more reliable this should be.\n        // Let's skip the whole header and dash to the data !\n        reader.skip(22);\n        // in some zip created on windows, the filename stored in the central dir contains \\ instead of /.\n        // Strangely, the filename here is OK.\n        // I would love to treat these zip files as corrupted (see http://www.info-zip.org/FAQ.html#backslashes\n        // or APPNOTE#4.4.17.1, \"All slashes MUST be forward slashes '/'\") but there are a lot of bad zip generators...\n        // Search \"unzip mismatching \"local\" filename continuing with \"central\" filename version\" on\n        // the internet.\n        //\n        // I think I see the logic here : the central directory is used to display\n        // content and the local directory is used to extract the files. Mixing / and \\\n        // may be used to display \\ to windows users and use / when extracting the files.\n        // Unfortunately, this lead also to some issues : http://seclists.org/fulldisclosure/2009/Sep/394\n        this.fileNameLength = reader.readInt(2);\n        localExtraFieldsLength = reader.readInt(2); // can't be sure this will be the same as the central dir\n        this.fileName = reader.readString(this.fileNameLength);\n        reader.skip(localExtraFieldsLength);\n\n        if (this.compressedSize == -1 || this.uncompressedSize == -1) {\n            throw new Error(\"Bug or corrupted zip : didn't get enough informations from the central directory \" + \"(compressedSize == -1 || uncompressedSize == -1)\");\n        }\n\n        compression = utils.findCompression(this.compressionMethod);\n        if (compression === null) { // no compression found\n            throw new Error(\"Corrupted zip : compression \" + utils.pretty(this.compressionMethod) + \" unknown (inner file : \" + this.fileName + \")\");\n        }\n        this.decompressed = new CompressedObject();\n        this.decompressed.compressedSize = this.compressedSize;\n        this.decompressed.uncompressedSize = this.uncompressedSize;\n        this.decompressed.crc32 = this.crc32;\n        this.decompressed.compressionMethod = this.compressionMethod;\n        this.decompressed.getCompressedContent = this.prepareCompressedContent(reader, reader.index, this.compressedSize, compression);\n        this.decompressed.getContent = this.prepareContent(reader, reader.index, this.compressedSize, compression, this.uncompressedSize);\n\n        // we need to compute the crc32...\n        if (this.loadOptions.checkCRC32) {\n            this.decompressed = utils.transformTo(\"string\", this.decompressed.getContent());\n            if (jszipProto.crc32(this.decompressed) !== this.crc32) {\n                throw new Error(\"Corrupted zip : CRC32 mismatch\");\n            }\n        }\n    },\n\n    /**\n     * Read the central part of a zip file and add the info in this object.\n     * @param {DataReader} reader the reader to use.\n     */\n    readCentralPart: function(reader) {\n        this.versionMadeBy = reader.readInt(2);\n        this.versionNeeded = reader.readInt(2);\n        this.bitFlag = reader.readInt(2);\n        this.compressionMethod = reader.readString(2);\n        this.date = reader.readDate();\n        this.crc32 = reader.readInt(4);\n        this.compressedSize = reader.readInt(4);\n        this.uncompressedSize = reader.readInt(4);\n        this.fileNameLength = reader.readInt(2);\n        this.extraFieldsLength = reader.readInt(2);\n        this.fileCommentLength = reader.readInt(2);\n        this.diskNumberStart = reader.readInt(2);\n        this.internalFileAttributes = reader.readInt(2);\n        this.externalFileAttributes = reader.readInt(4);\n        this.localHeaderOffset = reader.readInt(4);\n\n        if (this.isEncrypted()) {\n            throw new Error(\"Encrypted zip are not supported\");\n        }\n\n        this.fileName = reader.readString(this.fileNameLength);\n        this.readExtraFields(reader);\n        this.parseZIP64ExtraField(reader);\n        this.fileComment = reader.readString(this.fileCommentLength);\n    },\n\n    /**\n     * Parse the external file attributes and get the unix/dos permissions.\n     */\n    processAttributes: function () {\n        this.unixPermissions = null;\n        this.dosPermissions = null;\n        var madeBy = this.versionMadeBy >> 8;\n\n        // Check if we have the DOS directory flag set.\n        // We look for it in the DOS and UNIX permissions\n        // but some unknown platform could set it as a compatibility flag.\n        this.dir = this.externalFileAttributes & 0x0010 ? true : false;\n\n        if(madeBy === MADE_BY_DOS) {\n            // first 6 bits (0 to 5)\n            this.dosPermissions = this.externalFileAttributes & 0x3F;\n        }\n\n        if(madeBy === MADE_BY_UNIX) {\n            this.unixPermissions = (this.externalFileAttributes >> 16) & 0xFFFF;\n            // the octal permissions are in (this.unixPermissions & 0x01FF).toString(8);\n        }\n\n        // fail safe : if the name ends with a / it probably means a folder\n        if (!this.dir && this.fileName.slice(-1) === '/') {\n            this.dir = true;\n        }\n    },\n\n    /**\n     * Parse the ZIP64 extra field and merge the info in the current ZipEntry.\n     * @param {DataReader} reader the reader to use.\n     */\n    parseZIP64ExtraField: function(reader) {\n\n        if (!this.extraFields[0x0001]) {\n            return;\n        }\n\n        // should be something, preparing the extra reader\n        var extraReader = new StringReader(this.extraFields[0x0001].value);\n\n        // I really hope that these 64bits integer can fit in 32 bits integer, because js\n        // won't let us have more.\n        if (this.uncompressedSize === utils.MAX_VALUE_32BITS) {\n            this.uncompressedSize = extraReader.readInt(8);\n        }\n        if (this.compressedSize === utils.MAX_VALUE_32BITS) {\n            this.compressedSize = extraReader.readInt(8);\n        }\n        if (this.localHeaderOffset === utils.MAX_VALUE_32BITS) {\n            this.localHeaderOffset = extraReader.readInt(8);\n        }\n        if (this.diskNumberStart === utils.MAX_VALUE_32BITS) {\n            this.diskNumberStart = extraReader.readInt(4);\n        }\n    },\n    /**\n     * Read the central part of a zip file and add the info in this object.\n     * @param {DataReader} reader the reader to use.\n     */\n    readExtraFields: function(reader) {\n        var start = reader.index,\n            extraFieldId,\n            extraFieldLength,\n            extraFieldValue;\n\n        this.extraFields = this.extraFields || {};\n\n        while (reader.index < start + this.extraFieldsLength) {\n            extraFieldId = reader.readInt(2);\n            extraFieldLength = reader.readInt(2);\n            extraFieldValue = reader.readString(extraFieldLength);\n\n            this.extraFields[extraFieldId] = {\n                id: extraFieldId,\n                length: extraFieldLength,\n                value: extraFieldValue\n            };\n        }\n    },\n    /**\n     * Apply an UTF8 transformation if needed.\n     */\n    handleUTF8: function() {\n        if (this.useUTF8()) {\n            this.fileName = jszipProto.utf8decode(this.fileName);\n            this.fileComment = jszipProto.utf8decode(this.fileComment);\n        } else {\n            var upath = this.findExtraFieldUnicodePath();\n            if (upath !== null) {\n                this.fileName = upath;\n            }\n            var ucomment = this.findExtraFieldUnicodeComment();\n            if (ucomment !== null) {\n                this.fileComment = ucomment;\n            }\n        }\n    },\n\n    /**\n     * Find the unicode path declared in the extra field, if any.\n     * @return {String} the unicode path, null otherwise.\n     */\n    findExtraFieldUnicodePath: function() {\n        var upathField = this.extraFields[0x7075];\n        if (upathField) {\n            var extraReader = new StringReader(upathField.value);\n\n            // wrong version\n            if (extraReader.readInt(1) !== 1) {\n                return null;\n            }\n\n            // the crc of the filename changed, this field is out of date.\n            if (jszipProto.crc32(this.fileName) !== extraReader.readInt(4)) {\n                return null;\n            }\n\n            return jszipProto.utf8decode(extraReader.readString(upathField.length - 5));\n        }\n        return null;\n    },\n\n    /**\n     * Find the unicode comment declared in the extra field, if any.\n     * @return {String} the unicode comment, null otherwise.\n     */\n    findExtraFieldUnicodeComment: function() {\n        var ucommentField = this.extraFields[0x6375];\n        if (ucommentField) {\n            var extraReader = new StringReader(ucommentField.value);\n\n            // wrong version\n            if (extraReader.readInt(1) !== 1) {\n                return null;\n            }\n\n            // the crc of the comment changed, this field is out of date.\n            if (jszipProto.crc32(this.fileComment) !== extraReader.readInt(4)) {\n                return null;\n            }\n\n            return jszipProto.utf8decode(extraReader.readString(ucommentField.length - 5));\n        }\n        return null;\n    }\n};\nmodule.exports = ZipEntry;\n\n},{\"./compressedObject\":2,\"./object\":13,\"./stringReader\":15,\"./utils\":21}],24:[function(_dereq_,module,exports){\n// Top level file is just a mixin of submodules & constants\n'use strict';\n\nvar assign    = _dereq_('./lib/utils/common').assign;\n\nvar deflate   = _dereq_('./lib/deflate');\nvar inflate   = _dereq_('./lib/inflate');\nvar constants = _dereq_('./lib/zlib/constants');\n\nvar pako = {};\n\nassign(pako, deflate, inflate, constants);\n\nmodule.exports = pako;\n},{\"./lib/deflate\":25,\"./lib/inflate\":26,\"./lib/utils/common\":27,\"./lib/zlib/constants\":30}],25:[function(_dereq_,module,exports){\n'use strict';\n\n\nvar zlib_deflate = _dereq_('./zlib/deflate.js');\nvar utils = _dereq_('./utils/common');\nvar strings = _dereq_('./utils/strings');\nvar msg = _dereq_('./zlib/messages');\nvar zstream = _dereq_('./zlib/zstream');\n\n\n/* Public constants ==========================================================*/\n/* ===========================================================================*/\n\nvar Z_NO_FLUSH      = 0;\nvar Z_FINISH        = 4;\n\nvar Z_OK            = 0;\nvar Z_STREAM_END    = 1;\n\nvar Z_DEFAULT_COMPRESSION = -1;\n\nvar Z_DEFAULT_STRATEGY    = 0;\n\nvar Z_DEFLATED  = 8;\n\n/* ===========================================================================*/\n\n\n/**\n * class Deflate\n *\n * Generic JS-style wrapper for zlib calls. If you don't need\n * streaming behaviour - use more simple functions: [[deflate]],\n * [[deflateRaw]] and [[gzip]].\n **/\n\n/* internal\n * Deflate.chunks -> Array\n *\n * Chunks of output data, if [[Deflate#onData]] not overriden.\n **/\n\n/**\n * Deflate.result -> Uint8Array|Array\n *\n * Compressed result, generated by default [[Deflate#onData]]\n * and [[Deflate#onEnd]] handlers. Filled after you push last chunk\n * (call [[Deflate#push]] with `Z_FINISH` / `true` param).\n **/\n\n/**\n * Deflate.err -> Number\n *\n * Error code after deflate finished. 0 (Z_OK) on success.\n * You will not need it in real life, because deflate errors\n * are possible only on wrong options or bad `onData` / `onEnd`\n * custom handlers.\n **/\n\n/**\n * Deflate.msg -> String\n *\n * Error message, if [[Deflate.err]] != 0\n **/\n\n\n/**\n * new Deflate(options)\n * - options (Object): zlib deflate options.\n *\n * Creates new deflator instance with specified params. Throws exception\n * on bad params. Supported options:\n *\n * - `level`\n * - `windowBits`\n * - `memLevel`\n * - `strategy`\n *\n * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)\n * for more information on these.\n *\n * Additional options, for internal needs:\n *\n * - `chunkSize` - size of generated data chunks (16K by default)\n * - `raw` (Boolean) - do raw deflate\n * - `gzip` (Boolean) - create gzip wrapper\n * - `to` (String) - if equal to 'string', then result will be \"binary string\"\n *    (each char code [0..255])\n * - `header` (Object) - custom header for gzip\n *   - `text` (Boolean) - true if compressed data believed to be text\n *   - `time` (Number) - modification time, unix timestamp\n *   - `os` (Number) - operation system code\n *   - `extra` (Array) - array of bytes with extra data (max 65536)\n *   - `name` (String) - file name (binary string)\n *   - `comment` (String) - comment (binary string)\n *   - `hcrc` (Boolean) - true if header crc should be added\n *\n * ##### Example:\n *\n * ```javascript\n * var pako = require('pako')\n *   , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])\n *   , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);\n *\n * var deflate = new pako.Deflate({ level: 3});\n *\n * deflate.push(chunk1, false);\n * deflate.push(chunk2, true);  // true -> last chunk\n *\n * if (deflate.err) { throw new Error(deflate.err); }\n *\n * console.log(deflate.result);\n * ```\n **/\nvar Deflate = function(options) {\n\n  this.options = utils.assign({\n    level: Z_DEFAULT_COMPRESSION,\n    method: Z_DEFLATED,\n    chunkSize: 16384,\n    windowBits: 15,\n    memLevel: 8,\n    strategy: Z_DEFAULT_STRATEGY,\n    to: ''\n  }, options || {});\n\n  var opt = this.options;\n\n  if (opt.raw && (opt.windowBits > 0)) {\n    opt.windowBits = -opt.windowBits;\n  }\n\n  else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {\n    opt.windowBits += 16;\n  }\n\n  this.err    = 0;      // error code, if happens (0 = Z_OK)\n  this.msg    = '';     // error message\n  this.ended  = false;  // used to avoid multiple onEnd() calls\n  this.chunks = [];     // chunks of compressed data\n\n  this.strm = new zstream();\n  this.strm.avail_out = 0;\n\n  var status = zlib_deflate.deflateInit2(\n    this.strm,\n    opt.level,\n    opt.method,\n    opt.windowBits,\n    opt.memLevel,\n    opt.strategy\n  );\n\n  if (status !== Z_OK) {\n    throw new Error(msg[status]);\n  }\n\n  if (opt.header) {\n    zlib_deflate.deflateSetHeader(this.strm, opt.header);\n  }\n};\n\n/**\n * Deflate#push(data[, mode]) -> Boolean\n * - data (Uint8Array|Array|String): input data. Strings will be converted to\n *   utf8 byte sequence.\n * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.\n *   See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.\n *\n * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with\n * new compressed chunks. Returns `true` on success. The last data block must have\n * mode Z_FINISH (or `true`). That flush internal pending buffers and call\n * [[Deflate#onEnd]].\n *\n * On fail call [[Deflate#onEnd]] with error code and return false.\n *\n * We strongly recommend to use `Uint8Array` on input for best speed (output\n * array format is detected automatically). Also, don't skip last param and always\n * use the same type in your code (boolean or number). That will improve JS speed.\n *\n * For regular `Array`-s make sure all elements are [0..255].\n *\n * ##### Example\n *\n * ```javascript\n * push(chunk, false); // push one of data chunks\n * ...\n * push(chunk, true);  // push last chunk\n * ```\n **/\nDeflate.prototype.push = function(data, mode) {\n  var strm = this.strm;\n  var chunkSize = this.options.chunkSize;\n  var status, _mode;\n\n  if (this.ended) { return false; }\n\n  _mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH);\n\n  // Convert data if needed\n  if (typeof data === 'string') {\n    // If we need to compress text, change encoding to utf8.\n    strm.input = strings.string2buf(data);\n  } else {\n    strm.input = data;\n  }\n\n  strm.next_in = 0;\n  strm.avail_in = strm.input.length;\n\n  do {\n    if (strm.avail_out === 0) {\n      strm.output = new utils.Buf8(chunkSize);\n      strm.next_out = 0;\n      strm.avail_out = chunkSize;\n    }\n    status = zlib_deflate.deflate(strm, _mode);    /* no bad return value */\n\n    if (status !== Z_STREAM_END && status !== Z_OK) {\n      this.onEnd(status);\n      this.ended = true;\n      return false;\n    }\n    if (strm.avail_out === 0 || (strm.avail_in === 0 && _mode === Z_FINISH)) {\n      if (this.options.to === 'string') {\n        this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out)));\n      } else {\n        this.onData(utils.shrinkBuf(strm.output, strm.next_out));\n      }\n    }\n  } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END);\n\n  // Finalize on the last chunk.\n  if (_mode === Z_FINISH) {\n    status = zlib_deflate.deflateEnd(this.strm);\n    this.onEnd(status);\n    this.ended = true;\n    return status === Z_OK;\n  }\n\n  return true;\n};\n\n\n/**\n * Deflate#onData(chunk) -> Void\n * - chunk (Uint8Array|Array|String): ouput data. Type of array depends\n *   on js engine support. When string output requested, each chunk\n *   will be string.\n *\n * By default, stores data blocks in `chunks[]` property and glue\n * those in `onEnd`. Override this handler, if you need another behaviour.\n **/\nDeflate.prototype.onData = function(chunk) {\n  this.chunks.push(chunk);\n};\n\n\n/**\n * Deflate#onEnd(status) -> Void\n * - status (Number): deflate status. 0 (Z_OK) on success,\n *   other if not.\n *\n * Called once after you tell deflate that input stream complete\n * or error happenned. By default - join collected chunks,\n * free memory and fill `results` / `err` properties.\n **/\nDeflate.prototype.onEnd = function(status) {\n  // On success - join\n  if (status === Z_OK) {\n    if (this.options.to === 'string') {\n      this.result = this.chunks.join('');\n    } else {\n      this.result = utils.flattenChunks(this.chunks);\n    }\n  }\n  this.chunks = [];\n  this.err = status;\n  this.msg = this.strm.msg;\n};\n\n\n/**\n * deflate(data[, options]) -> Uint8Array|Array|String\n * - data (Uint8Array|Array|String): input data to compress.\n * - options (Object): zlib deflate options.\n *\n * Compress `data` with deflate alrorythm and `options`.\n *\n * Supported options are:\n *\n * - level\n * - windowBits\n * - memLevel\n * - strategy\n *\n * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)\n * for more information on these.\n *\n * Sugar (options):\n *\n * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify\n *   negative windowBits implicitly.\n * - `to` (String) - if equal to 'string', then result will be \"binary string\"\n *    (each char code [0..255])\n *\n * ##### Example:\n *\n * ```javascript\n * var pako = require('pako')\n *   , data = Uint8Array([1,2,3,4,5,6,7,8,9]);\n *\n * console.log(pako.deflate(data));\n * ```\n **/\nfunction deflate(input, options) {\n  var deflator = new Deflate(options);\n\n  deflator.push(input, true);\n\n  // That will never happens, if you don't cheat with options :)\n  if (deflator.err) { throw deflator.msg; }\n\n  return deflator.result;\n}\n\n\n/**\n * deflateRaw(data[, options]) -> Uint8Array|Array|String\n * - data (Uint8Array|Array|String): input data to compress.\n * - options (Object): zlib deflate options.\n *\n * The same as [[deflate]], but creates raw data, without wrapper\n * (header and adler32 crc).\n **/\nfunction deflateRaw(input, options) {\n  options = options || {};\n  options.raw = true;\n  return deflate(input, options);\n}\n\n\n/**\n * gzip(data[, options]) -> Uint8Array|Array|String\n * - data (Uint8Array|Array|String): input data to compress.\n * - options (Object): zlib deflate options.\n *\n * The same as [[deflate]], but create gzip wrapper instead of\n * deflate one.\n **/\nfunction gzip(input, options) {\n  options = options || {};\n  options.gzip = true;\n  return deflate(input, options);\n}\n\n\nexports.Deflate = Deflate;\nexports.deflate = deflate;\nexports.deflateRaw = deflateRaw;\nexports.gzip = gzip;\n},{\"./utils/common\":27,\"./utils/strings\":28,\"./zlib/deflate.js\":32,\"./zlib/messages\":37,\"./zlib/zstream\":39}],26:[function(_dereq_,module,exports){\n'use strict';\n\n\nvar zlib_inflate = _dereq_('./zlib/inflate.js');\nvar utils = _dereq_('./utils/common');\nvar strings = _dereq_('./utils/strings');\nvar c = _dereq_('./zlib/constants');\nvar msg = _dereq_('./zlib/messages');\nvar zstream = _dereq_('./zlib/zstream');\nvar gzheader = _dereq_('./zlib/gzheader');\n\n\n/**\n * class Inflate\n *\n * Generic JS-style wrapper for zlib calls. If you don't need\n * streaming behaviour - use more simple functions: [[inflate]]\n * and [[inflateRaw]].\n **/\n\n/* internal\n * inflate.chunks -> Array\n *\n * Chunks of output data, if [[Inflate#onData]] not overriden.\n **/\n\n/**\n * Inflate.result -> Uint8Array|Array|String\n *\n * Uncompressed result, generated by default [[Inflate#onData]]\n * and [[Inflate#onEnd]] handlers. Filled after you push last chunk\n * (call [[Inflate#push]] with `Z_FINISH` / `true` param).\n **/\n\n/**\n * Inflate.err -> Number\n *\n * Error code after inflate finished. 0 (Z_OK) on success.\n * Should be checked if broken data possible.\n **/\n\n/**\n * Inflate.msg -> String\n *\n * Error message, if [[Inflate.err]] != 0\n **/\n\n\n/**\n * new Inflate(options)\n * - options (Object): zlib inflate options.\n *\n * Creates new inflator instance with specified params. Throws exception\n * on bad params. Supported options:\n *\n * - `windowBits`\n *\n * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)\n * for more information on these.\n *\n * Additional options, for internal needs:\n *\n * - `chunkSize` - size of generated data chunks (16K by default)\n * - `raw` (Boolean) - do raw inflate\n * - `to` (String) - if equal to 'string', then result will be converted\n *   from utf8 to utf16 (javascript) string. When string output requested,\n *   chunk length can differ from `chunkSize`, depending on content.\n *\n * By default, when no options set, autodetect deflate/gzip data format via\n * wrapper header.\n *\n * ##### Example:\n *\n * ```javascript\n * var pako = require('pako')\n *   , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])\n *   , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);\n *\n * var inflate = new pako.Inflate({ level: 3});\n *\n * inflate.push(chunk1, false);\n * inflate.push(chunk2, true);  // true -> last chunk\n *\n * if (inflate.err) { throw new Error(inflate.err); }\n *\n * console.log(inflate.result);\n * ```\n **/\nvar Inflate = function(options) {\n\n  this.options = utils.assign({\n    chunkSize: 16384,\n    windowBits: 0,\n    to: ''\n  }, options || {});\n\n  var opt = this.options;\n\n  // Force window size for `raw` data, if not set directly,\n  // because we have no header for autodetect.\n  if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {\n    opt.windowBits = -opt.windowBits;\n    if (opt.windowBits === 0) { opt.windowBits = -15; }\n  }\n\n  // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate\n  if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&\n      !(options && options.windowBits)) {\n    opt.windowBits += 32;\n  }\n\n  // Gzip header has no info about windows size, we can do autodetect only\n  // for deflate. So, if window size not set, force it to max when gzip possible\n  if ((opt.windowBits > 15) && (opt.windowBits < 48)) {\n    // bit 3 (16) -> gzipped data\n    // bit 4 (32) -> autodetect gzip/deflate\n    if ((opt.windowBits & 15) === 0) {\n      opt.windowBits |= 15;\n    }\n  }\n\n  this.err    = 0;      // error code, if happens (0 = Z_OK)\n  this.msg    = '';     // error message\n  this.ended  = false;  // used to avoid multiple onEnd() calls\n  this.chunks = [];     // chunks of compressed data\n\n  this.strm   = new zstream();\n  this.strm.avail_out = 0;\n\n  var status  = zlib_inflate.inflateInit2(\n    this.strm,\n    opt.windowBits\n  );\n\n  if (status !== c.Z_OK) {\n    throw new Error(msg[status]);\n  }\n\n  this.header = new gzheader();\n\n  zlib_inflate.inflateGetHeader(this.strm, this.header);\n};\n\n/**\n * Inflate#push(data[, mode]) -> Boolean\n * - data (Uint8Array|Array|String): input data\n * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.\n *   See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.\n *\n * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with\n * new output chunks. Returns `true` on success. The last data block must have\n * mode Z_FINISH (or `true`). That flush internal pending buffers and call\n * [[Inflate#onEnd]].\n *\n * On fail call [[Inflate#onEnd]] with error code and return false.\n *\n * We strongly recommend to use `Uint8Array` on input for best speed (output\n * format is detected automatically). Also, don't skip last param and always\n * use the same type in your code (boolean or number). That will improve JS speed.\n *\n * For regular `Array`-s make sure all elements are [0..255].\n *\n * ##### Example\n *\n * ```javascript\n * push(chunk, false); // push one of data chunks\n * ...\n * push(chunk, true);  // push last chunk\n * ```\n **/\nInflate.prototype.push = function(data, mode) {\n  var strm = this.strm;\n  var chunkSize = this.options.chunkSize;\n  var status, _mode;\n  var next_out_utf8, tail, utf8str;\n\n  if (this.ended) { return false; }\n  _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH);\n\n  // Convert data if needed\n  if (typeof data === 'string') {\n    // Only binary strings can be decompressed on practice\n    strm.input = strings.binstring2buf(data);\n  } else {\n    strm.input = data;\n  }\n\n  strm.next_in = 0;\n  strm.avail_in = strm.input.length;\n\n  do {\n    if (strm.avail_out === 0) {\n      strm.output = new utils.Buf8(chunkSize);\n      strm.next_out = 0;\n      strm.avail_out = chunkSize;\n    }\n\n    status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH);    /* no bad return value */\n\n    if (status !== c.Z_STREAM_END && status !== c.Z_OK) {\n      this.onEnd(status);\n      this.ended = true;\n      return false;\n    }\n\n    if (strm.next_out) {\n      if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && _mode === c.Z_FINISH)) {\n\n        if (this.options.to === 'string') {\n\n          next_out_utf8 = strings.utf8border(strm.output, strm.next_out);\n\n          tail = strm.next_out - next_out_utf8;\n          utf8str = strings.buf2string(strm.output, next_out_utf8);\n\n          // move tail\n          strm.next_out = tail;\n          strm.avail_out = chunkSize - tail;\n          if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); }\n\n          this.onData(utf8str);\n\n        } else {\n          this.onData(utils.shrinkBuf(strm.output, strm.next_out));\n        }\n      }\n    }\n  } while ((strm.avail_in > 0) && status !== c.Z_STREAM_END);\n\n  if (status === c.Z_STREAM_END) {\n    _mode = c.Z_FINISH;\n  }\n  // Finalize on the last chunk.\n  if (_mode === c.Z_FINISH) {\n    status = zlib_inflate.inflateEnd(this.strm);\n    this.onEnd(status);\n    this.ended = true;\n    return status === c.Z_OK;\n  }\n\n  return true;\n};\n\n\n/**\n * Inflate#onData(chunk) -> Void\n * - chunk (Uint8Array|Array|String): ouput data. Type of array depends\n *   on js engine support. When string output requested, each chunk\n *   will be string.\n *\n * By default, stores data blocks in `chunks[]` property and glue\n * those in `onEnd`. Override this handler, if you need another behaviour.\n **/\nInflate.prototype.onData = function(chunk) {\n  this.chunks.push(chunk);\n};\n\n\n/**\n * Inflate#onEnd(status) -> Void\n * - status (Number): inflate status. 0 (Z_OK) on success,\n *   other if not.\n *\n * Called once after you tell inflate that input stream complete\n * or error happenned. By default - join collected chunks,\n * free memory and fill `results` / `err` properties.\n **/\nInflate.prototype.onEnd = function(status) {\n  // On success - join\n  if (status === c.Z_OK) {\n    if (this.options.to === 'string') {\n      // Glue & convert here, until we teach pako to send\n      // utf8 alligned strings to onData\n      this.result = this.chunks.join('');\n    } else {\n      this.result = utils.flattenChunks(this.chunks);\n    }\n  }\n  this.chunks = [];\n  this.err = status;\n  this.msg = this.strm.msg;\n};\n\n\n/**\n * inflate(data[, options]) -> Uint8Array|Array|String\n * - data (Uint8Array|Array|String): input data to decompress.\n * - options (Object): zlib inflate options.\n *\n * Decompress `data` with inflate/ungzip and `options`. Autodetect\n * format via wrapper header by default. That's why we don't provide\n * separate `ungzip` method.\n *\n * Supported options are:\n *\n * - windowBits\n *\n * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)\n * for more information.\n *\n * Sugar (options):\n *\n * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify\n *   negative windowBits implicitly.\n * - `to` (String) - if equal to 'string', then result will be converted\n *   from utf8 to utf16 (javascript) string. When string output requested,\n *   chunk length can differ from `chunkSize`, depending on content.\n *\n *\n * ##### Example:\n *\n * ```javascript\n * var pako = require('pako')\n *   , input = pako.deflate([1,2,3,4,5,6,7,8,9])\n *   , output;\n *\n * try {\n *   output = pako.inflate(input);\n * } catch (err)\n *   console.log(err);\n * }\n * ```\n **/\nfunction inflate(input, options) {\n  var inflator = new Inflate(options);\n\n  inflator.push(input, true);\n\n  // That will never happens, if you don't cheat with options :)\n  if (inflator.err) { throw inflator.msg; }\n\n  return inflator.result;\n}\n\n\n/**\n * inflateRaw(data[, options]) -> Uint8Array|Array|String\n * - data (Uint8Array|Array|String): input data to decompress.\n * - options (Object): zlib inflate options.\n *\n * The same as [[inflate]], but creates raw data, without wrapper\n * (header and adler32 crc).\n **/\nfunction inflateRaw(input, options) {\n  options = options || {};\n  options.raw = true;\n  return inflate(input, options);\n}\n\n\n/**\n * ungzip(data[, options]) -> Uint8Array|Array|String\n * - data (Uint8Array|Array|String): input data to decompress.\n * - options (Object): zlib inflate options.\n *\n * Just shortcut to [[inflate]], because it autodetects format\n * by header.content. Done for convenience.\n **/\n\n\nexports.Inflate = Inflate;\nexports.inflate = inflate;\nexports.inflateRaw = inflateRaw;\nexports.ungzip  = inflate;\n\n},{\"./utils/common\":27,\"./utils/strings\":28,\"./zlib/constants\":30,\"./zlib/gzheader\":33,\"./zlib/inflate.js\":35,\"./zlib/messages\":37,\"./zlib/zstream\":39}],27:[function(_dereq_,module,exports){\n'use strict';\n\n\nvar TYPED_OK =  (typeof Uint8Array !== 'undefined') &&\n                (typeof Uint16Array !== 'undefined') &&\n                (typeof Int32Array !== 'undefined');\n\n\nexports.assign = function (obj /*from1, from2, from3, ...*/) {\n  var sources = Array.prototype.slice.call(arguments, 1);\n  while (sources.length) {\n    var source = sources.shift();\n    if (!source) { continue; }\n\n    if (typeof(source) !== 'object') {\n      throw new TypeError(source + 'must be non-object');\n    }\n\n    for (var p in source) {\n      if (source.hasOwnProperty(p)) {\n        obj[p] = source[p];\n      }\n    }\n  }\n\n  return obj;\n};\n\n\n// reduce buffer size, avoiding mem copy\nexports.shrinkBuf = function (buf, size) {\n  if (buf.length === size) { return buf; }\n  if (buf.subarray) { return buf.subarray(0, size); }\n  buf.length = size;\n  return buf;\n};\n\n\nvar fnTyped = {\n  arraySet: function (dest, src, src_offs, len, dest_offs) {\n    if (src.subarray && dest.subarray) {\n      dest.set(src.subarray(src_offs, src_offs+len), dest_offs);\n      return;\n    }\n    // Fallback to ordinary array\n    for(var i=0; i<len; i++) {\n      dest[dest_offs + i] = src[src_offs + i];\n    }\n  },\n  // Join array of chunks to single array.\n  flattenChunks: function(chunks) {\n    var i, l, len, pos, chunk, result;\n\n    // calculate data length\n    len = 0;\n    for (i=0, l=chunks.length; i<l; i++) {\n      len += chunks[i].length;\n    }\n\n    // join chunks\n    result = new Uint8Array(len);\n    pos = 0;\n    for (i=0, l=chunks.length; i<l; i++) {\n      chunk = chunks[i];\n      result.set(chunk, pos);\n      pos += chunk.length;\n    }\n\n    return result;\n  }\n};\n\nvar fnUntyped = {\n  arraySet: function (dest, src, src_offs, len, dest_offs) {\n    for(var i=0; i<len; i++) {\n      dest[dest_offs + i] = src[src_offs + i];\n    }\n  },\n  // Join array of chunks to single array.\n  flattenChunks: function(chunks) {\n    return [].concat.apply([], chunks);\n  }\n};\n\n\n// Enable/Disable typed arrays use, for testing\n//\nexports.setTyped = function (on) {\n  if (on) {\n    exports.Buf8  = Uint8Array;\n    exports.Buf16 = Uint16Array;\n    exports.Buf32 = Int32Array;\n    exports.assign(exports, fnTyped);\n  } else {\n    exports.Buf8  = Array;\n    exports.Buf16 = Array;\n    exports.Buf32 = Array;\n    exports.assign(exports, fnUntyped);\n  }\n};\n\nexports.setTyped(TYPED_OK);\n},{}],28:[function(_dereq_,module,exports){\n// String encode/decode helpers\n'use strict';\n\n\nvar utils = _dereq_('./common');\n\n\n// Quick check if we can use fast array to bin string conversion\n//\n// - apply(Array) can fail on Android 2.2\n// - apply(Uint8Array) can fail on iOS 5.1 Safary\n//\nvar STR_APPLY_OK = true;\nvar STR_APPLY_UIA_OK = true;\n\ntry { String.fromCharCode.apply(null, [0]); } catch(__) { STR_APPLY_OK = false; }\ntry { String.fromCharCode.apply(null, new Uint8Array(1)); } catch(__) { STR_APPLY_UIA_OK = false; }\n\n\n// Table with utf8 lengths (calculated by first byte of sequence)\n// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,\n// because max possible codepoint is 0x10ffff\nvar _utf8len = new utils.Buf8(256);\nfor (var i=0; i<256; i++) {\n  _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1);\n}\n_utf8len[254]=_utf8len[254]=1; // Invalid sequence start\n\n\n// convert string to array (typed, when possible)\nexports.string2buf = function (str) {\n  var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;\n\n  // count binary size\n  for (m_pos = 0; m_pos < str_len; m_pos++) {\n    c = str.charCodeAt(m_pos);\n    if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {\n      c2 = str.charCodeAt(m_pos+1);\n      if ((c2 & 0xfc00) === 0xdc00) {\n        c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);\n        m_pos++;\n      }\n    }\n    buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;\n  }\n\n  // allocate buffer\n  buf = new utils.Buf8(buf_len);\n\n  // convert\n  for (i=0, m_pos = 0; i < buf_len; m_pos++) {\n    c = str.charCodeAt(m_pos);\n    if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {\n      c2 = str.charCodeAt(m_pos+1);\n      if ((c2 & 0xfc00) === 0xdc00) {\n        c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);\n        m_pos++;\n      }\n    }\n    if (c < 0x80) {\n      /* one byte */\n      buf[i++] = c;\n    } else if (c < 0x800) {\n      /* two bytes */\n      buf[i++] = 0xC0 | (c >>> 6);\n      buf[i++] = 0x80 | (c & 0x3f);\n    } else if (c < 0x10000) {\n      /* three bytes */\n      buf[i++] = 0xE0 | (c >>> 12);\n      buf[i++] = 0x80 | (c >>> 6 & 0x3f);\n      buf[i++] = 0x80 | (c & 0x3f);\n    } else {\n      /* four bytes */\n      buf[i++] = 0xf0 | (c >>> 18);\n      buf[i++] = 0x80 | (c >>> 12 & 0x3f);\n      buf[i++] = 0x80 | (c >>> 6 & 0x3f);\n      buf[i++] = 0x80 | (c & 0x3f);\n    }\n  }\n\n  return buf;\n};\n\n// Helper (used in 2 places)\nfunction buf2binstring(buf, len) {\n  // use fallback for big arrays to avoid stack overflow\n  if (len < 65537) {\n    if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) {\n      return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len));\n    }\n  }\n\n  var result = '';\n  for(var i=0; i < len; i++) {\n    result += String.fromCharCode(buf[i]);\n  }\n  return result;\n}\n\n\n// Convert byte array to binary string\nexports.buf2binstring = function(buf) {\n  return buf2binstring(buf, buf.length);\n};\n\n\n// Convert binary string (typed, when possible)\nexports.binstring2buf = function(str) {\n  var buf = new utils.Buf8(str.length);\n  for(var i=0, len=buf.length; i < len; i++) {\n    buf[i] = str.charCodeAt(i);\n  }\n  return buf;\n};\n\n\n// convert array to string\nexports.buf2string = function (buf, max) {\n  var i, out, c, c_len;\n  var len = max || buf.length;\n\n  // Reserve max possible length (2 words per char)\n  // NB: by unknown reasons, Array is significantly faster for\n  //     String.fromCharCode.apply than Uint16Array.\n  var utf16buf = new Array(len*2);\n\n  for (out=0, i=0; i<len;) {\n    c = buf[i++];\n    // quick process ascii\n    if (c < 0x80) { utf16buf[out++] = c; continue; }\n\n    c_len = _utf8len[c];\n    // skip 5 & 6 byte codes\n    if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; }\n\n    // apply mask on first byte\n    c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;\n    // join the rest\n    while (c_len > 1 && i < len) {\n      c = (c << 6) | (buf[i++] & 0x3f);\n      c_len--;\n    }\n\n    // terminated by end of string?\n    if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }\n\n    if (c < 0x10000) {\n      utf16buf[out++] = c;\n    } else {\n      c -= 0x10000;\n      utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);\n      utf16buf[out++] = 0xdc00 | (c & 0x3ff);\n    }\n  }\n\n  return buf2binstring(utf16buf, out);\n};\n\n\n// Calculate max possible position in utf8 buffer,\n// that will not break sequence. If that's not possible\n// - (very small limits) return max size as is.\n//\n// buf[] - utf8 bytes array\n// max   - length limit (mandatory);\nexports.utf8border = function(buf, max) {\n  var pos;\n\n  max = max || buf.length;\n  if (max > buf.length) { max = buf.length; }\n\n  // go back from last position, until start of sequence found\n  pos = max-1;\n  while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }\n\n  // Fuckup - very small and broken sequence,\n  // return max, because we should return something anyway.\n  if (pos < 0) { return max; }\n\n  // If we came to start of buffer - that means vuffer is too small,\n  // return max too.\n  if (pos === 0) { return max; }\n\n  return (pos + _utf8len[buf[pos]] > max) ? pos : max;\n};\n\n},{\"./common\":27}],29:[function(_dereq_,module,exports){\n'use strict';\n\n// Note: adler32 takes 12% for level 0 and 2% for level 6.\n// It doesn't worth to make additional optimizationa as in original.\n// Small size is preferable.\n\nfunction adler32(adler, buf, len, pos) {\n  var s1 = (adler & 0xffff) |0\n    , s2 = ((adler >>> 16) & 0xffff) |0\n    , n = 0;\n\n  while (len !== 0) {\n    // Set limit ~ twice less than 5552, to keep\n    // s2 in 31-bits, because we force signed ints.\n    // in other case %= will fail.\n    n = len > 2000 ? 2000 : len;\n    len -= n;\n\n    do {\n      s1 = (s1 + buf[pos++]) |0;\n      s2 = (s2 + s1) |0;\n    } while (--n);\n\n    s1 %= 65521;\n    s2 %= 65521;\n  }\n\n  return (s1 | (s2 << 16)) |0;\n}\n\n\nmodule.exports = adler32;\n},{}],30:[function(_dereq_,module,exports){\nmodule.exports = {\n\n  /* Allowed flush values; see deflate() and inflate() below for details */\n  Z_NO_FLUSH:         0,\n  Z_PARTIAL_FLUSH:    1,\n  Z_SYNC_FLUSH:       2,\n  Z_FULL_FLUSH:       3,\n  Z_FINISH:           4,\n  Z_BLOCK:            5,\n  Z_TREES:            6,\n\n  /* Return codes for the compression/decompression functions. Negative values\n  * are errors, positive values are used for special but normal events.\n  */\n  Z_OK:               0,\n  Z_STREAM_END:       1,\n  Z_NEED_DICT:        2,\n  Z_ERRNO:           -1,\n  Z_STREAM_ERROR:    -2,\n  Z_DATA_ERROR:      -3,\n  //Z_MEM_ERROR:     -4,\n  Z_BUF_ERROR:       -5,\n  //Z_VERSION_ERROR: -6,\n\n  /* compression levels */\n  Z_NO_COMPRESSION:         0,\n  Z_BEST_SPEED:             1,\n  Z_BEST_COMPRESSION:       9,\n  Z_DEFAULT_COMPRESSION:   -1,\n\n\n  Z_FILTERED:               1,\n  Z_HUFFMAN_ONLY:           2,\n  Z_RLE:                    3,\n  Z_FIXED:                  4,\n  Z_DEFAULT_STRATEGY:       0,\n\n  /* Possible values of the data_type field (though see inflate()) */\n  Z_BINARY:                 0,\n  Z_TEXT:                   1,\n  //Z_ASCII:                1, // = Z_TEXT (deprecated)\n  Z_UNKNOWN:                2,\n\n  /* The deflate compression method */\n  Z_DEFLATED:               8\n  //Z_NULL:                 null // Use -1 or null inline, depending on var type\n};\n},{}],31:[function(_dereq_,module,exports){\n'use strict';\n\n// Note: we can't get significant speed boost here.\n// So write code to minimize size - no pregenerated tables\n// and array tools dependencies.\n\n\n// Use ordinary array, since untyped makes no boost here\nfunction makeTable() {\n  var c, table = [];\n\n  for(var n =0; n < 256; n++){\n    c = n;\n    for(var k =0; k < 8; k++){\n      c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));\n    }\n    table[n] = c;\n  }\n\n  return table;\n}\n\n// Create table on load. Just 255 signed longs. Not a problem.\nvar crcTable = makeTable();\n\n\nfunction crc32(crc, buf, len, pos) {\n  var t = crcTable\n    , end = pos + len;\n\n  crc = crc ^ (-1);\n\n  for (var i = pos; i < end; i++ ) {\n    crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];\n  }\n\n  return (crc ^ (-1)); // >>> 0;\n}\n\n\nmodule.exports = crc32;\n},{}],32:[function(_dereq_,module,exports){\n'use strict';\n\nvar utils   = _dereq_('../utils/common');\nvar trees   = _dereq_('./trees');\nvar adler32 = _dereq_('./adler32');\nvar crc32   = _dereq_('./crc32');\nvar msg   = _dereq_('./messages');\n\n/* Public constants ==========================================================*/\n/* ===========================================================================*/\n\n\n/* Allowed flush values; see deflate() and inflate() below for details */\nvar Z_NO_FLUSH      = 0;\nvar Z_PARTIAL_FLUSH = 1;\n//var Z_SYNC_FLUSH    = 2;\nvar Z_FULL_FLUSH    = 3;\nvar Z_FINISH        = 4;\nvar Z_BLOCK         = 5;\n//var Z_TREES         = 6;\n\n\n/* Return codes for the compression/decompression functions. Negative values\n * are errors, positive values are used for special but normal events.\n */\nvar Z_OK            = 0;\nvar Z_STREAM_END    = 1;\n//var Z_NEED_DICT     = 2;\n//var Z_ERRNO         = -1;\nvar Z_STREAM_ERROR  = -2;\nvar Z_DATA_ERROR    = -3;\n//var Z_MEM_ERROR     = -4;\nvar Z_BUF_ERROR     = -5;\n//var Z_VERSION_ERROR = -6;\n\n\n/* compression levels */\n//var Z_NO_COMPRESSION      = 0;\n//var Z_BEST_SPEED          = 1;\n//var Z_BEST_COMPRESSION    = 9;\nvar Z_DEFAULT_COMPRESSION = -1;\n\n\nvar Z_FILTERED            = 1;\nvar Z_HUFFMAN_ONLY        = 2;\nvar Z_RLE                 = 3;\nvar Z_FIXED               = 4;\nvar Z_DEFAULT_STRATEGY    = 0;\n\n/* Possible values of the data_type field (though see inflate()) */\n//var Z_BINARY              = 0;\n//var Z_TEXT                = 1;\n//var Z_ASCII               = 1; // = Z_TEXT\nvar Z_UNKNOWN             = 2;\n\n\n/* The deflate compression method */\nvar Z_DEFLATED  = 8;\n\n/*============================================================================*/\n\n\nvar MAX_MEM_LEVEL = 9;\n/* Maximum value for memLevel in deflateInit2 */\nvar MAX_WBITS = 15;\n/* 32K LZ77 window */\nvar DEF_MEM_LEVEL = 8;\n\n\nvar LENGTH_CODES  = 29;\n/* number of length codes, not counting the special END_BLOCK code */\nvar LITERALS      = 256;\n/* number of literal bytes 0..255 */\nvar L_CODES       = LITERALS + 1 + LENGTH_CODES;\n/* number of Literal or Length codes, including the END_BLOCK code */\nvar D_CODES       = 30;\n/* number of distance codes */\nvar BL_CODES      = 19;\n/* number of codes used to transfer the bit lengths */\nvar HEAP_SIZE     = 2*L_CODES + 1;\n/* maximum heap size */\nvar MAX_BITS  = 15;\n/* All codes must not exceed MAX_BITS bits */\n\nvar MIN_MATCH = 3;\nvar MAX_MATCH = 258;\nvar MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);\n\nvar PRESET_DICT = 0x20;\n\nvar INIT_STATE = 42;\nvar EXTRA_STATE = 69;\nvar NAME_STATE = 73;\nvar COMMENT_STATE = 91;\nvar HCRC_STATE = 103;\nvar BUSY_STATE = 113;\nvar FINISH_STATE = 666;\n\nvar BS_NEED_MORE      = 1; /* block not completed, need more input or more output */\nvar BS_BLOCK_DONE     = 2; /* block flush performed */\nvar BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */\nvar BS_FINISH_DONE    = 4; /* finish done, accept no more input or output */\n\nvar OS_CODE = 0x03; // Unix :) . Don't detect, use this default.\n\nfunction err(strm, errorCode) {\n  strm.msg = msg[errorCode];\n  return errorCode;\n}\n\nfunction rank(f) {\n  return ((f) << 1) - ((f) > 4 ? 9 : 0);\n}\n\nfunction zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }\n\n\n/* =========================================================================\n * Flush as much pending output as possible. All deflate() output goes\n * through this function so some applications may wish to modify it\n * to avoid allocating a large strm->output buffer and copying into it.\n * (See also read_buf()).\n */\nfunction flush_pending(strm) {\n  var s = strm.state;\n\n  //_tr_flush_bits(s);\n  var len = s.pending;\n  if (len > strm.avail_out) {\n    len = strm.avail_out;\n  }\n  if (len === 0) { return; }\n\n  utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out);\n  strm.next_out += len;\n  s.pending_out += len;\n  strm.total_out += len;\n  strm.avail_out -= len;\n  s.pending -= len;\n  if (s.pending === 0) {\n    s.pending_out = 0;\n  }\n}\n\n\nfunction flush_block_only (s, last) {\n  trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);\n  s.block_start = s.strstart;\n  flush_pending(s.strm);\n}\n\n\nfunction put_byte(s, b) {\n  s.pending_buf[s.pending++] = b;\n}\n\n\n/* =========================================================================\n * Put a short in the pending buffer. The 16-bit value is put in MSB order.\n * IN assertion: the stream state is correct and there is enough room in\n * pending_buf.\n */\nfunction putShortMSB(s, b) {\n//  put_byte(s, (Byte)(b >> 8));\n//  put_byte(s, (Byte)(b & 0xff));\n  s.pending_buf[s.pending++] = (b >>> 8) & 0xff;\n  s.pending_buf[s.pending++] = b & 0xff;\n}\n\n\n/* ===========================================================================\n * Read a new buffer from the current input stream, update the adler32\n * and total number of bytes read.  All deflate() input goes through\n * this function so some applications may wish to modify it to avoid\n * allocating a large strm->input buffer and copying from it.\n * (See also flush_pending()).\n */\nfunction read_buf(strm, buf, start, size) {\n  var len = strm.avail_in;\n\n  if (len > size) { len = size; }\n  if (len === 0) { return 0; }\n\n  strm.avail_in -= len;\n\n  utils.arraySet(buf, strm.input, strm.next_in, len, start);\n  if (strm.state.wrap === 1) {\n    strm.adler = adler32(strm.adler, buf, len, start);\n  }\n\n  else if (strm.state.wrap === 2) {\n    strm.adler = crc32(strm.adler, buf, len, start);\n  }\n\n  strm.next_in += len;\n  strm.total_in += len;\n\n  return len;\n}\n\n\n/* ===========================================================================\n * Set match_start to the longest match starting at the given string and\n * return its length. Matches shorter or equal to prev_length are discarded,\n * in which case the result is equal to prev_length and match_start is\n * garbage.\n * IN assertions: cur_match is the head of the hash chain for the current\n *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1\n * OUT assertion: the match length is not greater than s->lookahead.\n */\nfunction longest_match(s, cur_match) {\n  var chain_length = s.max_chain_length;      /* max hash chain length */\n  var scan = s.strstart; /* current string */\n  var match;                       /* matched string */\n  var len;                           /* length of current match */\n  var best_len = s.prev_length;              /* best match length so far */\n  var nice_match = s.nice_match;             /* stop if match long enough */\n  var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?\n      s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;\n\n  var _win = s.window; // shortcut\n\n  var wmask = s.w_mask;\n  var prev  = s.prev;\n\n  /* Stop when cur_match becomes <= limit. To simplify the code,\n   * we prevent matches with the string of window index 0.\n   */\n\n  var strend = s.strstart + MAX_MATCH;\n  var scan_end1  = _win[scan + best_len - 1];\n  var scan_end   = _win[scan + best_len];\n\n  /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.\n   * It is easy to get rid of this optimization if necessary.\n   */\n  // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, \"Code too clever\");\n\n  /* Do not waste too much time if we already have a good match: */\n  if (s.prev_length >= s.good_match) {\n    chain_length >>= 2;\n  }\n  /* Do not look for matches beyond the end of the input. This is necessary\n   * to make deflate deterministic.\n   */\n  if (nice_match > s.lookahead) { nice_match = s.lookahead; }\n\n  // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, \"need lookahead\");\n\n  do {\n    // Assert(cur_match < s->strstart, \"no future\");\n    match = cur_match;\n\n    /* Skip to next match if the match length cannot increase\n     * or if the match length is less than 2.  Note that the checks below\n     * for insufficient lookahead only occur occasionally for performance\n     * reasons.  Therefore uninitialized memory will be accessed, and\n     * conditional jumps will be made that depend on those values.\n     * However the length of the match is limited to the lookahead, so\n     * the output of deflate is not affected by the uninitialized values.\n     */\n\n    if (_win[match + best_len]     !== scan_end  ||\n        _win[match + best_len - 1] !== scan_end1 ||\n        _win[match]                !== _win[scan] ||\n        _win[++match]              !== _win[scan + 1]) {\n      continue;\n    }\n\n    /* The check at best_len-1 can be removed because it will be made\n     * again later. (This heuristic is not always a win.)\n     * It is not necessary to compare scan[2] and match[2] since they\n     * are always equal when the other bytes match, given that\n     * the hash keys are equal and that HASH_BITS >= 8.\n     */\n    scan += 2;\n    match++;\n    // Assert(*scan == *match, \"match[2]?\");\n\n    /* We check for insufficient lookahead only every 8th comparison;\n     * the 256th check will be made at strstart+258.\n     */\n    do {\n      /*jshint noempty:false*/\n    } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             scan < strend);\n\n    // Assert(scan <= s->window+(unsigned)(s->window_size-1), \"wild scan\");\n\n    len = MAX_MATCH - (strend - scan);\n    scan = strend - MAX_MATCH;\n\n    if (len > best_len) {\n      s.match_start = cur_match;\n      best_len = len;\n      if (len >= nice_match) {\n        break;\n      }\n      scan_end1  = _win[scan + best_len - 1];\n      scan_end   = _win[scan + best_len];\n    }\n  } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);\n\n  if (best_len <= s.lookahead) {\n    return best_len;\n  }\n  return s.lookahead;\n}\n\n\n/* ===========================================================================\n * Fill the window when the lookahead becomes insufficient.\n * Updates strstart and lookahead.\n *\n * IN assertion: lookahead < MIN_LOOKAHEAD\n * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD\n *    At least one byte has been read, or avail_in == 0; reads are\n *    performed for at least two bytes (required for the zip translate_eol\n *    option -- not supported here).\n */\nfunction fill_window(s) {\n  var _w_size = s.w_size;\n  var p, n, m, more, str;\n\n  //Assert(s->lookahead < MIN_LOOKAHEAD, \"already enough lookahead\");\n\n  do {\n    more = s.window_size - s.lookahead - s.strstart;\n\n    // JS ints have 32 bit, block below not needed\n    /* Deal with !@#$% 64K limit: */\n    //if (sizeof(int) <= 2) {\n    //    if (more == 0 && s->strstart == 0 && s->lookahead == 0) {\n    //        more = wsize;\n    //\n    //  } else if (more == (unsigned)(-1)) {\n    //        /* Very unlikely, but possible on 16 bit machine if\n    //         * strstart == 0 && lookahead == 1 (input done a byte at time)\n    //         */\n    //        more--;\n    //    }\n    //}\n\n\n    /* If the window is almost full and there is insufficient lookahead,\n     * move the upper half to the lower one to make room in the upper half.\n     */\n    if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {\n\n      utils.arraySet(s.window, s.window, _w_size, _w_size, 0);\n      s.match_start -= _w_size;\n      s.strstart -= _w_size;\n      /* we now have strstart >= MAX_DIST */\n      s.block_start -= _w_size;\n\n      /* Slide the hash table (could be avoided with 32 bit values\n       at the expense of memory usage). We slide even when level == 0\n       to keep the hash table consistent if we switch back to level > 0\n       later. (Using level 0 permanently is not an optimal usage of\n       zlib, so we don't care about this pathological case.)\n       */\n\n      n = s.hash_size;\n      p = n;\n      do {\n        m = s.head[--p];\n        s.head[p] = (m >= _w_size ? m - _w_size : 0);\n      } while (--n);\n\n      n = _w_size;\n      p = n;\n      do {\n        m = s.prev[--p];\n        s.prev[p] = (m >= _w_size ? m - _w_size : 0);\n        /* If n is not on any hash chain, prev[n] is garbage but\n         * its value will never be used.\n         */\n      } while (--n);\n\n      more += _w_size;\n    }\n    if (s.strm.avail_in === 0) {\n      break;\n    }\n\n    /* If there was no sliding:\n     *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&\n     *    more == window_size - lookahead - strstart\n     * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)\n     * => more >= window_size - 2*WSIZE + 2\n     * In the BIG_MEM or MMAP case (not yet supported),\n     *   window_size == input_size + MIN_LOOKAHEAD  &&\n     *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.\n     * Otherwise, window_size == 2*WSIZE so more >= 2.\n     * If there was sliding, more >= WSIZE. So in all cases, more >= 2.\n     */\n    //Assert(more >= 2, \"more < 2\");\n    n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);\n    s.lookahead += n;\n\n    /* Initialize the hash value now that we have some input: */\n    if (s.lookahead + s.insert >= MIN_MATCH) {\n      str = s.strstart - s.insert;\n      s.ins_h = s.window[str];\n\n      /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */\n      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask;\n//#if MIN_MATCH != 3\n//        Call update_hash() MIN_MATCH-3 more times\n//#endif\n      while (s.insert) {\n        /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */\n        s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH-1]) & s.hash_mask;\n\n        s.prev[str & s.w_mask] = s.head[s.ins_h];\n        s.head[s.ins_h] = str;\n        str++;\n        s.insert--;\n        if (s.lookahead + s.insert < MIN_MATCH) {\n          break;\n        }\n      }\n    }\n    /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,\n     * but this is not important since only literal bytes will be emitted.\n     */\n\n  } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);\n\n  /* If the WIN_INIT bytes after the end of the current data have never been\n   * written, then zero those bytes in order to avoid memory check reports of\n   * the use of uninitialized (or uninitialised as Julian writes) bytes by\n   * the longest match routines.  Update the high water mark for the next\n   * time through here.  WIN_INIT is set to MAX_MATCH since the longest match\n   * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.\n   */\n//  if (s.high_water < s.window_size) {\n//    var curr = s.strstart + s.lookahead;\n//    var init = 0;\n//\n//    if (s.high_water < curr) {\n//      /* Previous high water mark below current data -- zero WIN_INIT\n//       * bytes or up to end of window, whichever is less.\n//       */\n//      init = s.window_size - curr;\n//      if (init > WIN_INIT)\n//        init = WIN_INIT;\n//      zmemzero(s->window + curr, (unsigned)init);\n//      s->high_water = curr + init;\n//    }\n//    else if (s->high_water < (ulg)curr + WIN_INIT) {\n//      /* High water mark at or above current data, but below current data\n//       * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up\n//       * to end of window, whichever is less.\n//       */\n//      init = (ulg)curr + WIN_INIT - s->high_water;\n//      if (init > s->window_size - s->high_water)\n//        init = s->window_size - s->high_water;\n//      zmemzero(s->window + s->high_water, (unsigned)init);\n//      s->high_water += init;\n//    }\n//  }\n//\n//  Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,\n//    \"not enough room for search\");\n}\n\n/* ===========================================================================\n * Copy without compression as much as possible from the input stream, return\n * the current block state.\n * This function does not insert new strings in the dictionary since\n * uncompressible data is probably not useful. This function is used\n * only for the level=0 compression option.\n * NOTE: this function should be optimized to avoid extra copying from\n * window to pending_buf.\n */\nfunction deflate_stored(s, flush) {\n  /* Stored blocks are limited to 0xffff bytes, pending_buf is limited\n   * to pending_buf_size, and each stored block has a 5 byte header:\n   */\n  var max_block_size = 0xffff;\n\n  if (max_block_size > s.pending_buf_size - 5) {\n    max_block_size = s.pending_buf_size - 5;\n  }\n\n  /* Copy as much as possible from input to output: */\n  for (;;) {\n    /* Fill the window as much as possible: */\n    if (s.lookahead <= 1) {\n\n      //Assert(s->strstart < s->w_size+MAX_DIST(s) ||\n      //  s->block_start >= (long)s->w_size, \"slide too late\");\n//      if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) ||\n//        s.block_start >= s.w_size)) {\n//        throw  new Error(\"slide too late\");\n//      }\n\n      fill_window(s);\n      if (s.lookahead === 0 && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n\n      if (s.lookahead === 0) {\n        break;\n      }\n      /* flush the current block */\n    }\n    //Assert(s->block_start >= 0L, \"block gone\");\n//    if (s.block_start < 0) throw new Error(\"block gone\");\n\n    s.strstart += s.lookahead;\n    s.lookahead = 0;\n\n    /* Emit a stored block if pending_buf will be full: */\n    var max_start = s.block_start + max_block_size;\n\n    if (s.strstart === 0 || s.strstart >= max_start) {\n      /* strstart == 0 is possible when wraparound on 16-bit machine */\n      s.lookahead = s.strstart - max_start;\n      s.strstart = max_start;\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n\n\n    }\n    /* Flush if we may have to slide, otherwise block_start may become\n     * negative and the data will be gone:\n     */\n    if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n\n  s.insert = 0;\n\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n\n  if (s.strstart > s.block_start) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n\n  return BS_NEED_MORE;\n}\n\n/* ===========================================================================\n * Compress as much as possible from the input stream, return the current\n * block state.\n * This function does not perform lazy evaluation of matches and inserts\n * new strings in the dictionary only for unmatched strings or for short\n * matches. It is used only for the fast compression options.\n */\nfunction deflate_fast(s, flush) {\n  var hash_head;        /* head of the hash chain */\n  var bflush;           /* set if current block must be flushed */\n\n  for (;;) {\n    /* Make sure that we always have enough lookahead, except\n     * at the end of the input file. We need MAX_MATCH bytes\n     * for the next match, plus MIN_MATCH bytes to insert the\n     * string following the next match.\n     */\n    if (s.lookahead < MIN_LOOKAHEAD) {\n      fill_window(s);\n      if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n      if (s.lookahead === 0) {\n        break; /* flush the current block */\n      }\n    }\n\n    /* Insert the string window[strstart .. strstart+2] in the\n     * dictionary, and set hash_head to the head of the hash chain:\n     */\n    hash_head = 0/*NIL*/;\n    if (s.lookahead >= MIN_MATCH) {\n      /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n      hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n      s.head[s.ins_h] = s.strstart;\n      /***/\n    }\n\n    /* Find the longest match, discarding those <= prev_length.\n     * At this point we have always match_length < MIN_MATCH\n     */\n    if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {\n      /* To simplify the code, we prevent matches with the string\n       * of window index 0 (in particular we have to avoid a match\n       * of the string with itself at the start of the input file).\n       */\n      s.match_length = longest_match(s, hash_head);\n      /* longest_match() sets match_start */\n    }\n    if (s.match_length >= MIN_MATCH) {\n      // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only\n\n      /*** _tr_tally_dist(s, s.strstart - s.match_start,\n                     s.match_length - MIN_MATCH, bflush); ***/\n      bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);\n\n      s.lookahead -= s.match_length;\n\n      /* Insert new strings in the hash table only if the match length\n       * is not too large. This saves time but degrades compression.\n       */\n      if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) {\n        s.match_length--; /* string at strstart already in table */\n        do {\n          s.strstart++;\n          /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n          s.head[s.ins_h] = s.strstart;\n          /***/\n          /* strstart never exceeds WSIZE-MAX_MATCH, so there are\n           * always MIN_MATCH bytes ahead.\n           */\n        } while (--s.match_length !== 0);\n        s.strstart++;\n      } else\n      {\n        s.strstart += s.match_length;\n        s.match_length = 0;\n        s.ins_h = s.window[s.strstart];\n        /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */\n        s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask;\n\n//#if MIN_MATCH != 3\n//                Call UPDATE_HASH() MIN_MATCH-3 more times\n//#endif\n        /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not\n         * matter since it will be recomputed at next deflate call.\n         */\n      }\n    } else {\n      /* No match, output a literal byte */\n      //Tracevv((stderr,\"%c\", s.window[s.strstart]));\n      /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/\n      bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n\n      s.lookahead--;\n      s.strstart++;\n    }\n    if (bflush) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n  s.insert = ((s.strstart < (MIN_MATCH-1)) ? s.strstart : MIN_MATCH-1);\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n  return BS_BLOCK_DONE;\n}\n\n/* ===========================================================================\n * Same as above, but achieves better compression. We use a lazy\n * evaluation for matches: a match is finally adopted only if there is\n * no better match at the next window position.\n */\nfunction deflate_slow(s, flush) {\n  var hash_head;          /* head of hash chain */\n  var bflush;              /* set if current block must be flushed */\n\n  var max_insert;\n\n  /* Process the input block. */\n  for (;;) {\n    /* Make sure that we always have enough lookahead, except\n     * at the end of the input file. We need MAX_MATCH bytes\n     * for the next match, plus MIN_MATCH bytes to insert the\n     * string following the next match.\n     */\n    if (s.lookahead < MIN_LOOKAHEAD) {\n      fill_window(s);\n      if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n      if (s.lookahead === 0) { break; } /* flush the current block */\n    }\n\n    /* Insert the string window[strstart .. strstart+2] in the\n     * dictionary, and set hash_head to the head of the hash chain:\n     */\n    hash_head = 0/*NIL*/;\n    if (s.lookahead >= MIN_MATCH) {\n      /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n      hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n      s.head[s.ins_h] = s.strstart;\n      /***/\n    }\n\n    /* Find the longest match, discarding those <= prev_length.\n     */\n    s.prev_length = s.match_length;\n    s.prev_match = s.match_start;\n    s.match_length = MIN_MATCH-1;\n\n    if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&\n        s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {\n      /* To simplify the code, we prevent matches with the string\n       * of window index 0 (in particular we have to avoid a match\n       * of the string with itself at the start of the input file).\n       */\n      s.match_length = longest_match(s, hash_head);\n      /* longest_match() sets match_start */\n\n      if (s.match_length <= 5 &&\n         (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {\n\n        /* If prev_match is also MIN_MATCH, match_start is garbage\n         * but we will ignore the current match anyway.\n         */\n        s.match_length = MIN_MATCH-1;\n      }\n    }\n    /* If there was a match at the previous step and the current\n     * match is not better, output the previous match:\n     */\n    if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {\n      max_insert = s.strstart + s.lookahead - MIN_MATCH;\n      /* Do not insert strings in hash table beyond this. */\n\n      //check_match(s, s.strstart-1, s.prev_match, s.prev_length);\n\n      /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,\n                     s.prev_length - MIN_MATCH, bflush);***/\n      bflush = trees._tr_tally(s, s.strstart - 1- s.prev_match, s.prev_length - MIN_MATCH);\n      /* Insert in hash table all strings up to the end of the match.\n       * strstart-1 and strstart are already inserted. If there is not\n       * enough lookahead, the last two strings are not inserted in\n       * the hash table.\n       */\n      s.lookahead -= s.prev_length-1;\n      s.prev_length -= 2;\n      do {\n        if (++s.strstart <= max_insert) {\n          /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n          s.head[s.ins_h] = s.strstart;\n          /***/\n        }\n      } while (--s.prev_length !== 0);\n      s.match_available = 0;\n      s.match_length = MIN_MATCH-1;\n      s.strstart++;\n\n      if (bflush) {\n        /*** FLUSH_BLOCK(s, 0); ***/\n        flush_block_only(s, false);\n        if (s.strm.avail_out === 0) {\n          return BS_NEED_MORE;\n        }\n        /***/\n      }\n\n    } else if (s.match_available) {\n      /* If there was no match at the previous position, output a\n       * single literal. If there was a match but the current match\n       * is longer, truncate the previous match to a single literal.\n       */\n      //Tracevv((stderr,\"%c\", s->window[s->strstart-1]));\n      /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/\n      bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]);\n\n      if (bflush) {\n        /*** FLUSH_BLOCK_ONLY(s, 0) ***/\n        flush_block_only(s, false);\n        /***/\n      }\n      s.strstart++;\n      s.lookahead--;\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n    } else {\n      /* There is no previous match to compare with, wait for\n       * the next step to decide.\n       */\n      s.match_available = 1;\n      s.strstart++;\n      s.lookahead--;\n    }\n  }\n  //Assert (flush != Z_NO_FLUSH, \"no flush?\");\n  if (s.match_available) {\n    //Tracevv((stderr,\"%c\", s->window[s->strstart-1]));\n    /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/\n    bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]);\n\n    s.match_available = 0;\n  }\n  s.insert = s.strstart < MIN_MATCH-1 ? s.strstart : MIN_MATCH-1;\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n\n  return BS_BLOCK_DONE;\n}\n\n\n/* ===========================================================================\n * For Z_RLE, simply look for runs of bytes, generate matches only of distance\n * one.  Do not maintain a hash table.  (It will be regenerated if this run of\n * deflate switches away from Z_RLE.)\n */\nfunction deflate_rle(s, flush) {\n  var bflush;            /* set if current block must be flushed */\n  var prev;              /* byte at distance one to match */\n  var scan, strend;      /* scan goes up to strend for length of run */\n\n  var _win = s.window;\n\n  for (;;) {\n    /* Make sure that we always have enough lookahead, except\n     * at the end of the input file. We need MAX_MATCH bytes\n     * for the longest run, plus one for the unrolled loop.\n     */\n    if (s.lookahead <= MAX_MATCH) {\n      fill_window(s);\n      if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n      if (s.lookahead === 0) { break; } /* flush the current block */\n    }\n\n    /* See how many times the previous byte repeats */\n    s.match_length = 0;\n    if (s.lookahead >= MIN_MATCH && s.strstart > 0) {\n      scan = s.strstart - 1;\n      prev = _win[scan];\n      if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {\n        strend = s.strstart + MAX_MATCH;\n        do {\n          /*jshint noempty:false*/\n        } while (prev === _win[++scan] && prev === _win[++scan] &&\n                 prev === _win[++scan] && prev === _win[++scan] &&\n                 prev === _win[++scan] && prev === _win[++scan] &&\n                 prev === _win[++scan] && prev === _win[++scan] &&\n                 scan < strend);\n        s.match_length = MAX_MATCH - (strend - scan);\n        if (s.match_length > s.lookahead) {\n          s.match_length = s.lookahead;\n        }\n      }\n      //Assert(scan <= s->window+(uInt)(s->window_size-1), \"wild scan\");\n    }\n\n    /* Emit match if have run of MIN_MATCH or longer, else emit literal */\n    if (s.match_length >= MIN_MATCH) {\n      //check_match(s, s.strstart, s.strstart - 1, s.match_length);\n\n      /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/\n      bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH);\n\n      s.lookahead -= s.match_length;\n      s.strstart += s.match_length;\n      s.match_length = 0;\n    } else {\n      /* No match, output a literal byte */\n      //Tracevv((stderr,\"%c\", s->window[s->strstart]));\n      /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/\n      bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n\n      s.lookahead--;\n      s.strstart++;\n    }\n    if (bflush) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n  s.insert = 0;\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n  return BS_BLOCK_DONE;\n}\n\n/* ===========================================================================\n * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.\n * (It will be regenerated if this run of deflate switches away from Huffman.)\n */\nfunction deflate_huff(s, flush) {\n  var bflush;             /* set if current block must be flushed */\n\n  for (;;) {\n    /* Make sure that we have a literal to write. */\n    if (s.lookahead === 0) {\n      fill_window(s);\n      if (s.lookahead === 0) {\n        if (flush === Z_NO_FLUSH) {\n          return BS_NEED_MORE;\n        }\n        break;      /* flush the current block */\n      }\n    }\n\n    /* Output a literal byte */\n    s.match_length = 0;\n    //Tracevv((stderr,\"%c\", s->window[s->strstart]));\n    /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/\n    bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n    s.lookahead--;\n    s.strstart++;\n    if (bflush) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n  s.insert = 0;\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n  return BS_BLOCK_DONE;\n}\n\n/* Values for max_lazy_match, good_match and max_chain_length, depending on\n * the desired pack level (0..9). The values given below have been tuned to\n * exclude worst case performance for pathological files. Better values may be\n * found for specific files.\n */\nvar Config = function (good_length, max_lazy, nice_length, max_chain, func) {\n  this.good_length = good_length;\n  this.max_lazy = max_lazy;\n  this.nice_length = nice_length;\n  this.max_chain = max_chain;\n  this.func = func;\n};\n\nvar configuration_table;\n\nconfiguration_table = [\n  /*      good lazy nice chain */\n  new Config(0, 0, 0, 0, deflate_stored),          /* 0 store only */\n  new Config(4, 4, 8, 4, deflate_fast),            /* 1 max speed, no lazy matches */\n  new Config(4, 5, 16, 8, deflate_fast),           /* 2 */\n  new Config(4, 6, 32, 32, deflate_fast),          /* 3 */\n\n  new Config(4, 4, 16, 16, deflate_slow),          /* 4 lazy matches */\n  new Config(8, 16, 32, 32, deflate_slow),         /* 5 */\n  new Config(8, 16, 128, 128, deflate_slow),       /* 6 */\n  new Config(8, 32, 128, 256, deflate_slow),       /* 7 */\n  new Config(32, 128, 258, 1024, deflate_slow),    /* 8 */\n  new Config(32, 258, 258, 4096, deflate_slow)     /* 9 max compression */\n];\n\n\n/* ===========================================================================\n * Initialize the \"longest match\" routines for a new zlib stream\n */\nfunction lm_init(s) {\n  s.window_size = 2 * s.w_size;\n\n  /*** CLEAR_HASH(s); ***/\n  zero(s.head); // Fill with NIL (= 0);\n\n  /* Set the default configuration parameters:\n   */\n  s.max_lazy_match = configuration_table[s.level].max_lazy;\n  s.good_match = configuration_table[s.level].good_length;\n  s.nice_match = configuration_table[s.level].nice_length;\n  s.max_chain_length = configuration_table[s.level].max_chain;\n\n  s.strstart = 0;\n  s.block_start = 0;\n  s.lookahead = 0;\n  s.insert = 0;\n  s.match_length = s.prev_length = MIN_MATCH - 1;\n  s.match_available = 0;\n  s.ins_h = 0;\n}\n\n\nfunction DeflateState() {\n  this.strm = null;            /* pointer back to this zlib stream */\n  this.status = 0;            /* as the name implies */\n  this.pending_buf = null;      /* output still pending */\n  this.pending_buf_size = 0;  /* size of pending_buf */\n  this.pending_out = 0;       /* next pending byte to output to the stream */\n  this.pending = 0;           /* nb of bytes in the pending buffer */\n  this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */\n  this.gzhead = null;         /* gzip header information to write */\n  this.gzindex = 0;           /* where in extra, name, or comment */\n  this.method = Z_DEFLATED; /* can only be DEFLATED */\n  this.last_flush = -1;   /* value of flush param for previous deflate call */\n\n  this.w_size = 0;  /* LZ77 window size (32K by default) */\n  this.w_bits = 0;  /* log2(w_size)  (8..16) */\n  this.w_mask = 0;  /* w_size - 1 */\n\n  this.window = null;\n  /* Sliding window. Input bytes are read into the second half of the window,\n   * and move to the first half later to keep a dictionary of at least wSize\n   * bytes. With this organization, matches are limited to a distance of\n   * wSize-MAX_MATCH bytes, but this ensures that IO is always\n   * performed with a length multiple of the block size.\n   */\n\n  this.window_size = 0;\n  /* Actual size of window: 2*wSize, except when the user input buffer\n   * is directly used as sliding window.\n   */\n\n  this.prev = null;\n  /* Link to older string with same hash index. To limit the size of this\n   * array to 64K, this link is maintained only for the last 32K strings.\n   * An index in this array is thus a window index modulo 32K.\n   */\n\n  this.head = null;   /* Heads of the hash chains or NIL. */\n\n  this.ins_h = 0;       /* hash index of string to be inserted */\n  this.hash_size = 0;   /* number of elements in hash table */\n  this.hash_bits = 0;   /* log2(hash_size) */\n  this.hash_mask = 0;   /* hash_size-1 */\n\n  this.hash_shift = 0;\n  /* Number of bits by which ins_h must be shifted at each input\n   * step. It must be such that after MIN_MATCH steps, the oldest\n   * byte no longer takes part in the hash key, that is:\n   *   hash_shift * MIN_MATCH >= hash_bits\n   */\n\n  this.block_start = 0;\n  /* Window position at the beginning of the current output block. Gets\n   * negative when the window is moved backwards.\n   */\n\n  this.match_length = 0;      /* length of best match */\n  this.prev_match = 0;        /* previous match */\n  this.match_available = 0;   /* set if previous match exists */\n  this.strstart = 0;          /* start of string to insert */\n  this.match_start = 0;       /* start of matching string */\n  this.lookahead = 0;         /* number of valid bytes ahead in window */\n\n  this.prev_length = 0;\n  /* Length of the best match at previous step. Matches not greater than this\n   * are discarded. This is used in the lazy match evaluation.\n   */\n\n  this.max_chain_length = 0;\n  /* To speed up deflation, hash chains are never searched beyond this\n   * length.  A higher limit improves compression ratio but degrades the\n   * speed.\n   */\n\n  this.max_lazy_match = 0;\n  /* Attempt to find a better match only when the current match is strictly\n   * smaller than this value. This mechanism is used only for compression\n   * levels >= 4.\n   */\n  // That's alias to max_lazy_match, don't use directly\n  //this.max_insert_length = 0;\n  /* Insert new strings in the hash table only if the match length is not\n   * greater than this length. This saves time but degrades compression.\n   * max_insert_length is used only for compression levels <= 3.\n   */\n\n  this.level = 0;     /* compression level (1..9) */\n  this.strategy = 0;  /* favor or force Huffman coding*/\n\n  this.good_match = 0;\n  /* Use a faster search when the previous match is longer than this */\n\n  this.nice_match = 0; /* Stop searching when current match exceeds this */\n\n              /* used by trees.c: */\n\n  /* Didn't use ct_data typedef below to suppress compiler warning */\n\n  // struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */\n  // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */\n  // struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */\n\n  // Use flat array of DOUBLE size, with interleaved fata,\n  // because JS does not support effective\n  this.dyn_ltree  = new utils.Buf16(HEAP_SIZE * 2);\n  this.dyn_dtree  = new utils.Buf16((2*D_CODES+1) * 2);\n  this.bl_tree    = new utils.Buf16((2*BL_CODES+1) * 2);\n  zero(this.dyn_ltree);\n  zero(this.dyn_dtree);\n  zero(this.bl_tree);\n\n  this.l_desc   = null;         /* desc. for literal tree */\n  this.d_desc   = null;         /* desc. for distance tree */\n  this.bl_desc  = null;         /* desc. for bit length tree */\n\n  //ush bl_count[MAX_BITS+1];\n  this.bl_count = new utils.Buf16(MAX_BITS+1);\n  /* number of codes at each bit length for an optimal tree */\n\n  //int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */\n  this.heap = new utils.Buf16(2*L_CODES+1);  /* heap used to build the Huffman trees */\n  zero(this.heap);\n\n  this.heap_len = 0;               /* number of elements in the heap */\n  this.heap_max = 0;               /* element of largest frequency */\n  /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.\n   * The same heap array is used to build all trees.\n   */\n\n  this.depth = new utils.Buf16(2*L_CODES+1); //uch depth[2*L_CODES+1];\n  zero(this.depth);\n  /* Depth of each subtree used as tie breaker for trees of equal frequency\n   */\n\n  this.l_buf = 0;          /* buffer index for literals or lengths */\n\n  this.lit_bufsize = 0;\n  /* Size of match buffer for literals/lengths.  There are 4 reasons for\n   * limiting lit_bufsize to 64K:\n   *   - frequencies can be kept in 16 bit counters\n   *   - if compression is not successful for the first block, all input\n   *     data is still in the window so we can still emit a stored block even\n   *     when input comes from standard input.  (This can also be done for\n   *     all blocks if lit_bufsize is not greater than 32K.)\n   *   - if compression is not successful for a file smaller than 64K, we can\n   *     even emit a stored file instead of a stored block (saving 5 bytes).\n   *     This is applicable only for zip (not gzip or zlib).\n   *   - creating new Huffman trees less frequently may not provide fast\n   *     adaptation to changes in the input data statistics. (Take for\n   *     example a binary file with poorly compressible code followed by\n   *     a highly compressible string table.) Smaller buffer sizes give\n   *     fast adaptation but have of course the overhead of transmitting\n   *     trees more frequently.\n   *   - I can't count above 4\n   */\n\n  this.last_lit = 0;      /* running index in l_buf */\n\n  this.d_buf = 0;\n  /* Buffer index for distances. To simplify the code, d_buf and l_buf have\n   * the same number of elements. To use different lengths, an extra flag\n   * array would be necessary.\n   */\n\n  this.opt_len = 0;       /* bit length of current block with optimal trees */\n  this.static_len = 0;    /* bit length of current block with static trees */\n  this.matches = 0;       /* number of string matches in current block */\n  this.insert = 0;        /* bytes at end of window left to insert */\n\n\n  this.bi_buf = 0;\n  /* Output buffer. bits are inserted starting at the bottom (least\n   * significant bits).\n   */\n  this.bi_valid = 0;\n  /* Number of valid bits in bi_buf.  All bits above the last valid bit\n   * are always zero.\n   */\n\n  // Used for window memory init. We safely ignore it for JS. That makes\n  // sense only for pointers and memory check tools.\n  //this.high_water = 0;\n  /* High water mark offset in window for initialized bytes -- bytes above\n   * this are set to zero in order to avoid memory check warnings when\n   * longest match routines access bytes past the input.  This is then\n   * updated to the new high water mark.\n   */\n}\n\n\nfunction deflateResetKeep(strm) {\n  var s;\n\n  if (!strm || !strm.state) {\n    return err(strm, Z_STREAM_ERROR);\n  }\n\n  strm.total_in = strm.total_out = 0;\n  strm.data_type = Z_UNKNOWN;\n\n  s = strm.state;\n  s.pending = 0;\n  s.pending_out = 0;\n\n  if (s.wrap < 0) {\n    s.wrap = -s.wrap;\n    /* was made negative by deflate(..., Z_FINISH); */\n  }\n  s.status = (s.wrap ? INIT_STATE : BUSY_STATE);\n  strm.adler = (s.wrap === 2) ?\n    0  // crc32(0, Z_NULL, 0)\n  :\n    1; // adler32(0, Z_NULL, 0)\n  s.last_flush = Z_NO_FLUSH;\n  trees._tr_init(s);\n  return Z_OK;\n}\n\n\nfunction deflateReset(strm) {\n  var ret = deflateResetKeep(strm);\n  if (ret === Z_OK) {\n    lm_init(strm.state);\n  }\n  return ret;\n}\n\n\nfunction deflateSetHeader(strm, head) {\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; }\n  strm.state.gzhead = head;\n  return Z_OK;\n}\n\n\nfunction deflateInit2(strm, level, method, windowBits, memLevel, strategy) {\n  if (!strm) { // === Z_NULL\n    return Z_STREAM_ERROR;\n  }\n  var wrap = 1;\n\n  if (level === Z_DEFAULT_COMPRESSION) {\n    level = 6;\n  }\n\n  if (windowBits < 0) { /* suppress zlib wrapper */\n    wrap = 0;\n    windowBits = -windowBits;\n  }\n\n  else if (windowBits > 15) {\n    wrap = 2;           /* write gzip wrapper instead */\n    windowBits -= 16;\n  }\n\n\n  if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED ||\n    windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||\n    strategy < 0 || strategy > Z_FIXED) {\n    return err(strm, Z_STREAM_ERROR);\n  }\n\n\n  if (windowBits === 8) {\n    windowBits = 9;\n  }\n  /* until 256-byte window bug fixed */\n\n  var s = new DeflateState();\n\n  strm.state = s;\n  s.strm = strm;\n\n  s.wrap = wrap;\n  s.gzhead = null;\n  s.w_bits = windowBits;\n  s.w_size = 1 << s.w_bits;\n  s.w_mask = s.w_size - 1;\n\n  s.hash_bits = memLevel + 7;\n  s.hash_size = 1 << s.hash_bits;\n  s.hash_mask = s.hash_size - 1;\n  s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);\n\n  s.window = new utils.Buf8(s.w_size * 2);\n  s.head = new utils.Buf16(s.hash_size);\n  s.prev = new utils.Buf16(s.w_size);\n\n  // Don't need mem init magic for JS.\n  //s.high_water = 0;  /* nothing written to s->window yet */\n\n  s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */\n\n  s.pending_buf_size = s.lit_bufsize * 4;\n  s.pending_buf = new utils.Buf8(s.pending_buf_size);\n\n  s.d_buf = s.lit_bufsize >> 1;\n  s.l_buf = (1 + 2) * s.lit_bufsize;\n\n  s.level = level;\n  s.strategy = strategy;\n  s.method = method;\n\n  return deflateReset(strm);\n}\n\nfunction deflateInit(strm, level) {\n  return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);\n}\n\n\nfunction deflate(strm, flush) {\n  var old_flush, s;\n  var beg, val; // for gzip header write only\n\n  if (!strm || !strm.state ||\n    flush > Z_BLOCK || flush < 0) {\n    return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR;\n  }\n\n  s = strm.state;\n\n  if (!strm.output ||\n      (!strm.input && strm.avail_in !== 0) ||\n      (s.status === FINISH_STATE && flush !== Z_FINISH)) {\n    return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR);\n  }\n\n  s.strm = strm; /* just in case */\n  old_flush = s.last_flush;\n  s.last_flush = flush;\n\n  /* Write the header */\n  if (s.status === INIT_STATE) {\n\n    if (s.wrap === 2) { // GZIP header\n      strm.adler = 0;  //crc32(0L, Z_NULL, 0);\n      put_byte(s, 31);\n      put_byte(s, 139);\n      put_byte(s, 8);\n      if (!s.gzhead) { // s->gzhead == Z_NULL\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, s.level === 9 ? 2 :\n                    (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?\n                     4 : 0));\n        put_byte(s, OS_CODE);\n        s.status = BUSY_STATE;\n      }\n      else {\n        put_byte(s, (s.gzhead.text ? 1 : 0) +\n                    (s.gzhead.hcrc ? 2 : 0) +\n                    (!s.gzhead.extra ? 0 : 4) +\n                    (!s.gzhead.name ? 0 : 8) +\n                    (!s.gzhead.comment ? 0 : 16)\n                );\n        put_byte(s, s.gzhead.time & 0xff);\n        put_byte(s, (s.gzhead.time >> 8) & 0xff);\n        put_byte(s, (s.gzhead.time >> 16) & 0xff);\n        put_byte(s, (s.gzhead.time >> 24) & 0xff);\n        put_byte(s, s.level === 9 ? 2 :\n                    (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?\n                     4 : 0));\n        put_byte(s, s.gzhead.os & 0xff);\n        if (s.gzhead.extra && s.gzhead.extra.length) {\n          put_byte(s, s.gzhead.extra.length & 0xff);\n          put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);\n        }\n        if (s.gzhead.hcrc) {\n          strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0);\n        }\n        s.gzindex = 0;\n        s.status = EXTRA_STATE;\n      }\n    }\n    else // DEFLATE header\n    {\n      var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8;\n      var level_flags = -1;\n\n      if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {\n        level_flags = 0;\n      } else if (s.level < 6) {\n        level_flags = 1;\n      } else if (s.level === 6) {\n        level_flags = 2;\n      } else {\n        level_flags = 3;\n      }\n      header |= (level_flags << 6);\n      if (s.strstart !== 0) { header |= PRESET_DICT; }\n      header += 31 - (header % 31);\n\n      s.status = BUSY_STATE;\n      putShortMSB(s, header);\n\n      /* Save the adler32 of the preset dictionary: */\n      if (s.strstart !== 0) {\n        putShortMSB(s, strm.adler >>> 16);\n        putShortMSB(s, strm.adler & 0xffff);\n      }\n      strm.adler = 1; // adler32(0L, Z_NULL, 0);\n    }\n  }\n\n//#ifdef GZIP\n  if (s.status === EXTRA_STATE) {\n    if (s.gzhead.extra/* != Z_NULL*/) {\n      beg = s.pending;  /* start of bytes to update crc */\n\n      while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {\n        if (s.pending === s.pending_buf_size) {\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          flush_pending(strm);\n          beg = s.pending;\n          if (s.pending === s.pending_buf_size) {\n            break;\n          }\n        }\n        put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);\n        s.gzindex++;\n      }\n      if (s.gzhead.hcrc && s.pending > beg) {\n        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n      }\n      if (s.gzindex === s.gzhead.extra.length) {\n        s.gzindex = 0;\n        s.status = NAME_STATE;\n      }\n    }\n    else {\n      s.status = NAME_STATE;\n    }\n  }\n  if (s.status === NAME_STATE) {\n    if (s.gzhead.name/* != Z_NULL*/) {\n      beg = s.pending;  /* start of bytes to update crc */\n      //int val;\n\n      do {\n        if (s.pending === s.pending_buf_size) {\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          flush_pending(strm);\n          beg = s.pending;\n          if (s.pending === s.pending_buf_size) {\n            val = 1;\n            break;\n          }\n        }\n        // JS specific: little magic to add zero terminator to end of string\n        if (s.gzindex < s.gzhead.name.length) {\n          val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;\n        } else {\n          val = 0;\n        }\n        put_byte(s, val);\n      } while (val !== 0);\n\n      if (s.gzhead.hcrc && s.pending > beg){\n        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n      }\n      if (val === 0) {\n        s.gzindex = 0;\n        s.status = COMMENT_STATE;\n      }\n    }\n    else {\n      s.status = COMMENT_STATE;\n    }\n  }\n  if (s.status === COMMENT_STATE) {\n    if (s.gzhead.comment/* != Z_NULL*/) {\n      beg = s.pending;  /* start of bytes to update crc */\n      //int val;\n\n      do {\n        if (s.pending === s.pending_buf_size) {\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          flush_pending(strm);\n          beg = s.pending;\n          if (s.pending === s.pending_buf_size) {\n            val = 1;\n            break;\n          }\n        }\n        // JS specific: little magic to add zero terminator to end of string\n        if (s.gzindex < s.gzhead.comment.length) {\n          val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;\n        } else {\n          val = 0;\n        }\n        put_byte(s, val);\n      } while (val !== 0);\n\n      if (s.gzhead.hcrc && s.pending > beg) {\n        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n      }\n      if (val === 0) {\n        s.status = HCRC_STATE;\n      }\n    }\n    else {\n      s.status = HCRC_STATE;\n    }\n  }\n  if (s.status === HCRC_STATE) {\n    if (s.gzhead.hcrc) {\n      if (s.pending + 2 > s.pending_buf_size) {\n        flush_pending(strm);\n      }\n      if (s.pending + 2 <= s.pending_buf_size) {\n        put_byte(s, strm.adler & 0xff);\n        put_byte(s, (strm.adler >> 8) & 0xff);\n        strm.adler = 0; //crc32(0L, Z_NULL, 0);\n        s.status = BUSY_STATE;\n      }\n    }\n    else {\n      s.status = BUSY_STATE;\n    }\n  }\n//#endif\n\n  /* Flush as much pending output as possible */\n  if (s.pending !== 0) {\n    flush_pending(strm);\n    if (strm.avail_out === 0) {\n      /* Since avail_out is 0, deflate will be called again with\n       * more output space, but possibly with both pending and\n       * avail_in equal to zero. There won't be anything to do,\n       * but this is not an error situation so make sure we\n       * return OK instead of BUF_ERROR at next call of deflate:\n       */\n      s.last_flush = -1;\n      return Z_OK;\n    }\n\n    /* Make sure there is something to do and avoid duplicate consecutive\n     * flushes. For repeated and useless calls with Z_FINISH, we keep\n     * returning Z_STREAM_END instead of Z_BUF_ERROR.\n     */\n  } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&\n    flush !== Z_FINISH) {\n    return err(strm, Z_BUF_ERROR);\n  }\n\n  /* User must not provide more input after the first FINISH: */\n  if (s.status === FINISH_STATE && strm.avail_in !== 0) {\n    return err(strm, Z_BUF_ERROR);\n  }\n\n  /* Start a new block or continue the current one.\n   */\n  if (strm.avail_in !== 0 || s.lookahead !== 0 ||\n    (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) {\n    var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) :\n      (s.strategy === Z_RLE ? deflate_rle(s, flush) :\n        configuration_table[s.level].func(s, flush));\n\n    if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {\n      s.status = FINISH_STATE;\n    }\n    if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {\n      if (strm.avail_out === 0) {\n        s.last_flush = -1;\n        /* avoid BUF_ERROR next call, see above */\n      }\n      return Z_OK;\n      /* If flush != Z_NO_FLUSH && avail_out == 0, the next call\n       * of deflate should use the same flush parameter to make sure\n       * that the flush is complete. So we don't have to output an\n       * empty block here, this will be done at next call. This also\n       * ensures that for a very small output buffer, we emit at most\n       * one empty block.\n       */\n    }\n    if (bstate === BS_BLOCK_DONE) {\n      if (flush === Z_PARTIAL_FLUSH) {\n        trees._tr_align(s);\n      }\n      else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */\n\n        trees._tr_stored_block(s, 0, 0, false);\n        /* For a full flush, this empty block will be recognized\n         * as a special marker by inflate_sync().\n         */\n        if (flush === Z_FULL_FLUSH) {\n          /*** CLEAR_HASH(s); ***/             /* forget history */\n          zero(s.head); // Fill with NIL (= 0);\n\n          if (s.lookahead === 0) {\n            s.strstart = 0;\n            s.block_start = 0;\n            s.insert = 0;\n          }\n        }\n      }\n      flush_pending(strm);\n      if (strm.avail_out === 0) {\n        s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */\n        return Z_OK;\n      }\n    }\n  }\n  //Assert(strm->avail_out > 0, \"bug2\");\n  //if (strm.avail_out <= 0) { throw new Error(\"bug2\");}\n\n  if (flush !== Z_FINISH) { return Z_OK; }\n  if (s.wrap <= 0) { return Z_STREAM_END; }\n\n  /* Write the trailer */\n  if (s.wrap === 2) {\n    put_byte(s, strm.adler & 0xff);\n    put_byte(s, (strm.adler >> 8) & 0xff);\n    put_byte(s, (strm.adler >> 16) & 0xff);\n    put_byte(s, (strm.adler >> 24) & 0xff);\n    put_byte(s, strm.total_in & 0xff);\n    put_byte(s, (strm.total_in >> 8) & 0xff);\n    put_byte(s, (strm.total_in >> 16) & 0xff);\n    put_byte(s, (strm.total_in >> 24) & 0xff);\n  }\n  else\n  {\n    putShortMSB(s, strm.adler >>> 16);\n    putShortMSB(s, strm.adler & 0xffff);\n  }\n\n  flush_pending(strm);\n  /* If avail_out is zero, the application will call deflate again\n   * to flush the rest.\n   */\n  if (s.wrap > 0) { s.wrap = -s.wrap; }\n  /* write the trailer only once! */\n  return s.pending !== 0 ? Z_OK : Z_STREAM_END;\n}\n\nfunction deflateEnd(strm) {\n  var status;\n\n  if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {\n    return Z_STREAM_ERROR;\n  }\n\n  status = strm.state.status;\n  if (status !== INIT_STATE &&\n    status !== EXTRA_STATE &&\n    status !== NAME_STATE &&\n    status !== COMMENT_STATE &&\n    status !== HCRC_STATE &&\n    status !== BUSY_STATE &&\n    status !== FINISH_STATE\n  ) {\n    return err(strm, Z_STREAM_ERROR);\n  }\n\n  strm.state = null;\n\n  return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK;\n}\n\n/* =========================================================================\n * Copy the source state to the destination state\n */\n//function deflateCopy(dest, source) {\n//\n//}\n\nexports.deflateInit = deflateInit;\nexports.deflateInit2 = deflateInit2;\nexports.deflateReset = deflateReset;\nexports.deflateResetKeep = deflateResetKeep;\nexports.deflateSetHeader = deflateSetHeader;\nexports.deflate = deflate;\nexports.deflateEnd = deflateEnd;\nexports.deflateInfo = 'pako deflate (from Nodeca project)';\n\n/* Not implemented\nexports.deflateBound = deflateBound;\nexports.deflateCopy = deflateCopy;\nexports.deflateSetDictionary = deflateSetDictionary;\nexports.deflateParams = deflateParams;\nexports.deflatePending = deflatePending;\nexports.deflatePrime = deflatePrime;\nexports.deflateTune = deflateTune;\n*/\n},{\"../utils/common\":27,\"./adler32\":29,\"./crc32\":31,\"./messages\":37,\"./trees\":38}],33:[function(_dereq_,module,exports){\n'use strict';\n\n\nfunction GZheader() {\n  /* true if compressed data believed to be text */\n  this.text       = 0;\n  /* modification time */\n  this.time       = 0;\n  /* extra flags (not used when writing a gzip file) */\n  this.xflags     = 0;\n  /* operating system */\n  this.os         = 0;\n  /* pointer to extra field or Z_NULL if none */\n  this.extra      = null;\n  /* extra field length (valid if extra != Z_NULL) */\n  this.extra_len  = 0; // Actually, we don't need it in JS,\n                       // but leave for few code modifications\n\n  //\n  // Setup limits is not necessary because in js we should not preallocate memory \n  // for inflate use constant limit in 65536 bytes\n  //\n\n  /* space at extra (only when reading header) */\n  // this.extra_max  = 0;\n  /* pointer to zero-terminated file name or Z_NULL */\n  this.name       = '';\n  /* space at name (only when reading header) */\n  // this.name_max   = 0;\n  /* pointer to zero-terminated comment or Z_NULL */\n  this.comment    = '';\n  /* space at comment (only when reading header) */\n  // this.comm_max   = 0;\n  /* true if there was or will be a header crc */\n  this.hcrc       = 0;\n  /* true when done reading gzip header (not used when writing a gzip file) */\n  this.done       = false;\n}\n\nmodule.exports = GZheader;\n},{}],34:[function(_dereq_,module,exports){\n'use strict';\n\n// See state defs from inflate.js\nvar BAD = 30;       /* got a data error -- remain here until reset */\nvar TYPE = 12;      /* i: waiting for type bits, including last-flag bit */\n\n/*\n   Decode literal, length, and distance codes and write out the resulting\n   literal and match bytes until either not enough input or output is\n   available, an end-of-block is encountered, or a data error is encountered.\n   When large enough input and output buffers are supplied to inflate(), for\n   example, a 16K input buffer and a 64K output buffer, more than 95% of the\n   inflate execution time is spent in this routine.\n\n   Entry assumptions:\n\n        state.mode === LEN\n        strm.avail_in >= 6\n        strm.avail_out >= 258\n        start >= strm.avail_out\n        state.bits < 8\n\n   On return, state.mode is one of:\n\n        LEN -- ran out of enough output space or enough available input\n        TYPE -- reached end of block code, inflate() to interpret next block\n        BAD -- error in block data\n\n   Notes:\n\n    - The maximum input bits used by a length/distance pair is 15 bits for the\n      length code, 5 bits for the length extra, 15 bits for the distance code,\n      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.\n      Therefore if strm.avail_in >= 6, then there is enough input to avoid\n      checking for available input while decoding.\n\n    - The maximum bytes that a single length/distance pair can output is 258\n      bytes, which is the maximum length that can be coded.  inflate_fast()\n      requires strm.avail_out >= 258 for each loop to avoid checking for\n      output space.\n */\nmodule.exports = function inflate_fast(strm, start) {\n  var state;\n  var _in;                    /* local strm.input */\n  var last;                   /* have enough input while in < last */\n  var _out;                   /* local strm.output */\n  var beg;                    /* inflate()'s initial strm.output */\n  var end;                    /* while out < end, enough space available */\n//#ifdef INFLATE_STRICT\n  var dmax;                   /* maximum distance from zlib header */\n//#endif\n  var wsize;                  /* window size or zero if not using window */\n  var whave;                  /* valid bytes in the window */\n  var wnext;                  /* window write index */\n  var window;                 /* allocated sliding window, if wsize != 0 */\n  var hold;                   /* local strm.hold */\n  var bits;                   /* local strm.bits */\n  var lcode;                  /* local strm.lencode */\n  var dcode;                  /* local strm.distcode */\n  var lmask;                  /* mask for first level of length codes */\n  var dmask;                  /* mask for first level of distance codes */\n  var here;                   /* retrieved table entry */\n  var op;                     /* code bits, operation, extra bits, or */\n                              /*  window position, window bytes to copy */\n  var len;                    /* match length, unused bytes */\n  var dist;                   /* match distance */\n  var from;                   /* where to copy match from */\n  var from_source;\n\n\n  var input, output; // JS specific, because we have no pointers\n\n  /* copy state to local variables */\n  state = strm.state;\n  //here = state.here;\n  _in = strm.next_in;\n  input = strm.input;\n  last = _in + (strm.avail_in - 5);\n  _out = strm.next_out;\n  output = strm.output;\n  beg = _out - (start - strm.avail_out);\n  end = _out + (strm.avail_out - 257);\n//#ifdef INFLATE_STRICT\n  dmax = state.dmax;\n//#endif\n  wsize = state.wsize;\n  whave = state.whave;\n  wnext = state.wnext;\n  window = state.window;\n  hold = state.hold;\n  bits = state.bits;\n  lcode = state.lencode;\n  dcode = state.distcode;\n  lmask = (1 << state.lenbits) - 1;\n  dmask = (1 << state.distbits) - 1;\n\n\n  /* decode literals and length/distances until end-of-block or not enough\n     input data or output space */\n\n  top:\n  do {\n    if (bits < 15) {\n      hold += input[_in++] << bits;\n      bits += 8;\n      hold += input[_in++] << bits;\n      bits += 8;\n    }\n\n    here = lcode[hold & lmask];\n\n    dolen:\n    for (;;) { // Goto emulation\n      op = here >>> 24/*here.bits*/;\n      hold >>>= op;\n      bits -= op;\n      op = (here >>> 16) & 0xff/*here.op*/;\n      if (op === 0) {                          /* literal */\n        //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?\n        //        \"inflate:         literal '%c'\\n\" :\n        //        \"inflate:         literal 0x%02x\\n\", here.val));\n        output[_out++] = here & 0xffff/*here.val*/;\n      }\n      else if (op & 16) {                     /* length base */\n        len = here & 0xffff/*here.val*/;\n        op &= 15;                           /* number of extra bits */\n        if (op) {\n          if (bits < op) {\n            hold += input[_in++] << bits;\n            bits += 8;\n          }\n          len += hold & ((1 << op) - 1);\n          hold >>>= op;\n          bits -= op;\n        }\n        //Tracevv((stderr, \"inflate:         length %u\\n\", len));\n        if (bits < 15) {\n          hold += input[_in++] << bits;\n          bits += 8;\n          hold += input[_in++] << bits;\n          bits += 8;\n        }\n        here = dcode[hold & dmask];\n\n        dodist:\n        for (;;) { // goto emulation\n          op = here >>> 24/*here.bits*/;\n          hold >>>= op;\n          bits -= op;\n          op = (here >>> 16) & 0xff/*here.op*/;\n\n          if (op & 16) {                      /* distance base */\n            dist = here & 0xffff/*here.val*/;\n            op &= 15;                       /* number of extra bits */\n            if (bits < op) {\n              hold += input[_in++] << bits;\n              bits += 8;\n              if (bits < op) {\n                hold += input[_in++] << bits;\n                bits += 8;\n              }\n            }\n            dist += hold & ((1 << op) - 1);\n//#ifdef INFLATE_STRICT\n            if (dist > dmax) {\n              strm.msg = 'invalid distance too far back';\n              state.mode = BAD;\n              break top;\n            }\n//#endif\n            hold >>>= op;\n            bits -= op;\n            //Tracevv((stderr, \"inflate:         distance %u\\n\", dist));\n            op = _out - beg;                /* max distance in output */\n            if (dist > op) {                /* see if copy from window */\n              op = dist - op;               /* distance back in window */\n              if (op > whave) {\n                if (state.sane) {\n                  strm.msg = 'invalid distance too far back';\n                  state.mode = BAD;\n                  break top;\n                }\n\n// (!) This block is disabled in zlib defailts,\n// don't enable it for binary compatibility\n//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR\n//                if (len <= op - whave) {\n//                  do {\n//                    output[_out++] = 0;\n//                  } while (--len);\n//                  continue top;\n//                }\n//                len -= op - whave;\n//                do {\n//                  output[_out++] = 0;\n//                } while (--op > whave);\n//                if (op === 0) {\n//                  from = _out - dist;\n//                  do {\n//                    output[_out++] = output[from++];\n//                  } while (--len);\n//                  continue top;\n//                }\n//#endif\n              }\n              from = 0; // window index\n              from_source = window;\n              if (wnext === 0) {           /* very common case */\n                from += wsize - op;\n                if (op < len) {         /* some from window */\n                  len -= op;\n                  do {\n                    output[_out++] = window[from++];\n                  } while (--op);\n                  from = _out - dist;  /* rest from output */\n                  from_source = output;\n                }\n              }\n              else if (wnext < op) {      /* wrap around window */\n                from += wsize + wnext - op;\n                op -= wnext;\n                if (op < len) {         /* some from end of window */\n                  len -= op;\n                  do {\n                    output[_out++] = window[from++];\n                  } while (--op);\n                  from = 0;\n                  if (wnext < len) {  /* some from start of window */\n                    op = wnext;\n                    len -= op;\n                    do {\n                      output[_out++] = window[from++];\n                    } while (--op);\n                    from = _out - dist;      /* rest from output */\n                    from_source = output;\n                  }\n                }\n              }\n              else {                      /* contiguous in window */\n                from += wnext - op;\n                if (op < len) {         /* some from window */\n                  len -= op;\n                  do {\n                    output[_out++] = window[from++];\n                  } while (--op);\n                  from = _out - dist;  /* rest from output */\n                  from_source = output;\n                }\n              }\n              while (len > 2) {\n                output[_out++] = from_source[from++];\n                output[_out++] = from_source[from++];\n                output[_out++] = from_source[from++];\n                len -= 3;\n              }\n              if (len) {\n                output[_out++] = from_source[from++];\n                if (len > 1) {\n                  output[_out++] = from_source[from++];\n                }\n              }\n            }\n            else {\n              from = _out - dist;          /* copy direct from output */\n              do {                        /* minimum length is three */\n                output[_out++] = output[from++];\n                output[_out++] = output[from++];\n                output[_out++] = output[from++];\n                len -= 3;\n              } while (len > 2);\n              if (len) {\n                output[_out++] = output[from++];\n                if (len > 1) {\n                  output[_out++] = output[from++];\n                }\n              }\n            }\n          }\n          else if ((op & 64) === 0) {          /* 2nd level distance code */\n            here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];\n            continue dodist;\n          }\n          else {\n            strm.msg = 'invalid distance code';\n            state.mode = BAD;\n            break top;\n          }\n\n          break; // need to emulate goto via \"continue\"\n        }\n      }\n      else if ((op & 64) === 0) {              /* 2nd level length code */\n        here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];\n        continue dolen;\n      }\n      else if (op & 32) {                     /* end-of-block */\n        //Tracevv((stderr, \"inflate:         end of block\\n\"));\n        state.mode = TYPE;\n        break top;\n      }\n      else {\n        strm.msg = 'invalid literal/length code';\n        state.mode = BAD;\n        break top;\n      }\n\n      break; // need to emulate goto via \"continue\"\n    }\n  } while (_in < last && _out < end);\n\n  /* return unused bytes (on entry, bits < 8, so in won't go too far back) */\n  len = bits >> 3;\n  _in -= len;\n  bits -= len << 3;\n  hold &= (1 << bits) - 1;\n\n  /* update state and return */\n  strm.next_in = _in;\n  strm.next_out = _out;\n  strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));\n  strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));\n  state.hold = hold;\n  state.bits = bits;\n  return;\n};\n\n},{}],35:[function(_dereq_,module,exports){\n'use strict';\n\n\nvar utils = _dereq_('../utils/common');\nvar adler32 = _dereq_('./adler32');\nvar crc32   = _dereq_('./crc32');\nvar inflate_fast = _dereq_('./inffast');\nvar inflate_table = _dereq_('./inftrees');\n\nvar CODES = 0;\nvar LENS = 1;\nvar DISTS = 2;\n\n/* Public constants ==========================================================*/\n/* ===========================================================================*/\n\n\n/* Allowed flush values; see deflate() and inflate() below for details */\n//var Z_NO_FLUSH      = 0;\n//var Z_PARTIAL_FLUSH = 1;\n//var Z_SYNC_FLUSH    = 2;\n//var Z_FULL_FLUSH    = 3;\nvar Z_FINISH        = 4;\nvar Z_BLOCK         = 5;\nvar Z_TREES         = 6;\n\n\n/* Return codes for the compression/decompression functions. Negative values\n * are errors, positive values are used for special but normal events.\n */\nvar Z_OK            = 0;\nvar Z_STREAM_END    = 1;\nvar Z_NEED_DICT     = 2;\n//var Z_ERRNO         = -1;\nvar Z_STREAM_ERROR  = -2;\nvar Z_DATA_ERROR    = -3;\nvar Z_MEM_ERROR     = -4;\nvar Z_BUF_ERROR     = -5;\n//var Z_VERSION_ERROR = -6;\n\n/* The deflate compression method */\nvar Z_DEFLATED  = 8;\n\n\n/* STATES ====================================================================*/\n/* ===========================================================================*/\n\n\nvar    HEAD = 1;       /* i: waiting for magic header */\nvar    FLAGS = 2;      /* i: waiting for method and flags (gzip) */\nvar    TIME = 3;       /* i: waiting for modification time (gzip) */\nvar    OS = 4;         /* i: waiting for extra flags and operating system (gzip) */\nvar    EXLEN = 5;      /* i: waiting for extra length (gzip) */\nvar    EXTRA = 6;      /* i: waiting for extra bytes (gzip) */\nvar    NAME = 7;       /* i: waiting for end of file name (gzip) */\nvar    COMMENT = 8;    /* i: waiting for end of comment (gzip) */\nvar    HCRC = 9;       /* i: waiting for header crc (gzip) */\nvar    DICTID = 10;    /* i: waiting for dictionary check value */\nvar    DICT = 11;      /* waiting for inflateSetDictionary() call */\nvar        TYPE = 12;      /* i: waiting for type bits, including last-flag bit */\nvar        TYPEDO = 13;    /* i: same, but skip check to exit inflate on new block */\nvar        STORED = 14;    /* i: waiting for stored size (length and complement) */\nvar        COPY_ = 15;     /* i/o: same as COPY below, but only first time in */\nvar        COPY = 16;      /* i/o: waiting for input or output to copy stored block */\nvar        TABLE = 17;     /* i: waiting for dynamic block table lengths */\nvar        LENLENS = 18;   /* i: waiting for code length code lengths */\nvar        CODELENS = 19;  /* i: waiting for length/lit and distance code lengths */\nvar            LEN_ = 20;      /* i: same as LEN below, but only first time in */\nvar            LEN = 21;       /* i: waiting for length/lit/eob code */\nvar            LENEXT = 22;    /* i: waiting for length extra bits */\nvar            DIST = 23;      /* i: waiting for distance code */\nvar            DISTEXT = 24;   /* i: waiting for distance extra bits */\nvar            MATCH = 25;     /* o: waiting for output space to copy string */\nvar            LIT = 26;       /* o: waiting for output space to write literal */\nvar    CHECK = 27;     /* i: waiting for 32-bit check value */\nvar    LENGTH = 28;    /* i: waiting for 32-bit length (gzip) */\nvar    DONE = 29;      /* finished check, done -- remain here until reset */\nvar    BAD = 30;       /* got a data error -- remain here until reset */\nvar    MEM = 31;       /* got an inflate() memory error -- remain here until reset */\nvar    SYNC = 32;      /* looking for synchronization bytes to restart inflate() */\n\n/* ===========================================================================*/\n\n\n\nvar ENOUGH_LENS = 852;\nvar ENOUGH_DISTS = 592;\n//var ENOUGH =  (ENOUGH_LENS+ENOUGH_DISTS);\n\nvar MAX_WBITS = 15;\n/* 32K LZ77 window */\nvar DEF_WBITS = MAX_WBITS;\n\n\nfunction ZSWAP32(q) {\n  return  (((q >>> 24) & 0xff) +\n          ((q >>> 8) & 0xff00) +\n          ((q & 0xff00) << 8) +\n          ((q & 0xff) << 24));\n}\n\n\nfunction InflateState() {\n  this.mode = 0;             /* current inflate mode */\n  this.last = false;          /* true if processing last block */\n  this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */\n  this.havedict = false;      /* true if dictionary provided */\n  this.flags = 0;             /* gzip header method and flags (0 if zlib) */\n  this.dmax = 0;              /* zlib header max distance (INFLATE_STRICT) */\n  this.check = 0;             /* protected copy of check value */\n  this.total = 0;             /* protected copy of output count */\n  // TODO: may be {}\n  this.head = null;           /* where to save gzip header information */\n\n  /* sliding window */\n  this.wbits = 0;             /* log base 2 of requested window size */\n  this.wsize = 0;             /* window size or zero if not using window */\n  this.whave = 0;             /* valid bytes in the window */\n  this.wnext = 0;             /* window write index */\n  this.window = null;         /* allocated sliding window, if needed */\n\n  /* bit accumulator */\n  this.hold = 0;              /* input bit accumulator */\n  this.bits = 0;              /* number of bits in \"in\" */\n\n  /* for string and stored block copying */\n  this.length = 0;            /* literal or length of data to copy */\n  this.offset = 0;            /* distance back to copy string from */\n\n  /* for table and code decoding */\n  this.extra = 0;             /* extra bits needed */\n\n  /* fixed and dynamic code tables */\n  this.lencode = null;          /* starting table for length/literal codes */\n  this.distcode = null;         /* starting table for distance codes */\n  this.lenbits = 0;           /* index bits for lencode */\n  this.distbits = 0;          /* index bits for distcode */\n\n  /* dynamic table building */\n  this.ncode = 0;             /* number of code length code lengths */\n  this.nlen = 0;              /* number of length code lengths */\n  this.ndist = 0;             /* number of distance code lengths */\n  this.have = 0;              /* number of code lengths in lens[] */\n  this.next = null;              /* next available space in codes[] */\n\n  this.lens = new utils.Buf16(320); /* temporary storage for code lengths */\n  this.work = new utils.Buf16(288); /* work area for code table building */\n\n  /*\n   because we don't have pointers in js, we use lencode and distcode directly\n   as buffers so we don't need codes\n  */\n  //this.codes = new utils.Buf32(ENOUGH);       /* space for code tables */\n  this.lendyn = null;              /* dynamic table for length/literal codes (JS specific) */\n  this.distdyn = null;             /* dynamic table for distance codes (JS specific) */\n  this.sane = 0;                   /* if false, allow invalid distance too far */\n  this.back = 0;                   /* bits back of last unprocessed length/lit */\n  this.was = 0;                    /* initial length of match */\n}\n\nfunction inflateResetKeep(strm) {\n  var state;\n\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n  strm.total_in = strm.total_out = state.total = 0;\n  strm.msg = ''; /*Z_NULL*/\n  if (state.wrap) {       /* to support ill-conceived Java test suite */\n    strm.adler = state.wrap & 1;\n  }\n  state.mode = HEAD;\n  state.last = 0;\n  state.havedict = 0;\n  state.dmax = 32768;\n  state.head = null/*Z_NULL*/;\n  state.hold = 0;\n  state.bits = 0;\n  //state.lencode = state.distcode = state.next = state.codes;\n  state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS);\n  state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS);\n\n  state.sane = 1;\n  state.back = -1;\n  //Tracev((stderr, \"inflate: reset\\n\"));\n  return Z_OK;\n}\n\nfunction inflateReset(strm) {\n  var state;\n\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n  state.wsize = 0;\n  state.whave = 0;\n  state.wnext = 0;\n  return inflateResetKeep(strm);\n\n}\n\nfunction inflateReset2(strm, windowBits) {\n  var wrap;\n  var state;\n\n  /* get the state */\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n\n  /* extract wrap request from windowBits parameter */\n  if (windowBits < 0) {\n    wrap = 0;\n    windowBits = -windowBits;\n  }\n  else {\n    wrap = (windowBits >> 4) + 1;\n    if (windowBits < 48) {\n      windowBits &= 15;\n    }\n  }\n\n  /* set number of window bits, free window if different */\n  if (windowBits && (windowBits < 8 || windowBits > 15)) {\n    return Z_STREAM_ERROR;\n  }\n  if (state.window !== null && state.wbits !== windowBits) {\n    state.window = null;\n  }\n\n  /* update state and reset the rest of it */\n  state.wrap = wrap;\n  state.wbits = windowBits;\n  return inflateReset(strm);\n}\n\nfunction inflateInit2(strm, windowBits) {\n  var ret;\n  var state;\n\n  if (!strm) { return Z_STREAM_ERROR; }\n  //strm.msg = Z_NULL;                 /* in case we return an error */\n\n  state = new InflateState();\n\n  //if (state === Z_NULL) return Z_MEM_ERROR;\n  //Tracev((stderr, \"inflate: allocated\\n\"));\n  strm.state = state;\n  state.window = null/*Z_NULL*/;\n  ret = inflateReset2(strm, windowBits);\n  if (ret !== Z_OK) {\n    strm.state = null/*Z_NULL*/;\n  }\n  return ret;\n}\n\nfunction inflateInit(strm) {\n  return inflateInit2(strm, DEF_WBITS);\n}\n\n\n/*\n Return state with length and distance decoding tables and index sizes set to\n fixed code decoding.  Normally this returns fixed tables from inffixed.h.\n If BUILDFIXED is defined, then instead this routine builds the tables the\n first time it's called, and returns those tables the first time and\n thereafter.  This reduces the size of the code by about 2K bytes, in\n exchange for a little execution time.  However, BUILDFIXED should not be\n used for threaded applications, since the rewriting of the tables and virgin\n may not be thread-safe.\n */\nvar virgin = true;\n\nvar lenfix, distfix; // We have no pointers in JS, so keep tables separate\n\nfunction fixedtables(state) {\n  /* build fixed huffman tables if first call (may not be thread safe) */\n  if (virgin) {\n    var sym;\n\n    lenfix = new utils.Buf32(512);\n    distfix = new utils.Buf32(32);\n\n    /* literal/length table */\n    sym = 0;\n    while (sym < 144) { state.lens[sym++] = 8; }\n    while (sym < 256) { state.lens[sym++] = 9; }\n    while (sym < 280) { state.lens[sym++] = 7; }\n    while (sym < 288) { state.lens[sym++] = 8; }\n\n    inflate_table(LENS,  state.lens, 0, 288, lenfix,   0, state.work, {bits: 9});\n\n    /* distance table */\n    sym = 0;\n    while (sym < 32) { state.lens[sym++] = 5; }\n\n    inflate_table(DISTS, state.lens, 0, 32,   distfix, 0, state.work, {bits: 5});\n\n    /* do this just once */\n    virgin = false;\n  }\n\n  state.lencode = lenfix;\n  state.lenbits = 9;\n  state.distcode = distfix;\n  state.distbits = 5;\n}\n\n\n/*\n Update the window with the last wsize (normally 32K) bytes written before\n returning.  If window does not exist yet, create it.  This is only called\n when a window is already in use, or when output has been written during this\n inflate call, but the end of the deflate stream has not been reached yet.\n It is also called to create a window for dictionary data when a dictionary\n is loaded.\n\n Providing output buffers larger than 32K to inflate() should provide a speed\n advantage, since only the last 32K of output is copied to the sliding window\n upon return from inflate(), and since all distances after the first 32K of\n output will fall in the output data, making match copies simpler and faster.\n The advantage may be dependent on the size of the processor's data caches.\n */\nfunction updatewindow(strm, src, end, copy) {\n  var dist;\n  var state = strm.state;\n\n  /* if it hasn't been done already, allocate space for the window */\n  if (state.window === null) {\n    state.wsize = 1 << state.wbits;\n    state.wnext = 0;\n    state.whave = 0;\n\n    state.window = new utils.Buf8(state.wsize);\n  }\n\n  /* copy state->wsize or less output bytes into the circular window */\n  if (copy >= state.wsize) {\n    utils.arraySet(state.window,src, end - state.wsize, state.wsize, 0);\n    state.wnext = 0;\n    state.whave = state.wsize;\n  }\n  else {\n    dist = state.wsize - state.wnext;\n    if (dist > copy) {\n      dist = copy;\n    }\n    //zmemcpy(state->window + state->wnext, end - copy, dist);\n    utils.arraySet(state.window,src, end - copy, dist, state.wnext);\n    copy -= dist;\n    if (copy) {\n      //zmemcpy(state->window, end - copy, copy);\n      utils.arraySet(state.window,src, end - copy, copy, 0);\n      state.wnext = copy;\n      state.whave = state.wsize;\n    }\n    else {\n      state.wnext += dist;\n      if (state.wnext === state.wsize) { state.wnext = 0; }\n      if (state.whave < state.wsize) { state.whave += dist; }\n    }\n  }\n  return 0;\n}\n\nfunction inflate(strm, flush) {\n  var state;\n  var input, output;          // input/output buffers\n  var next;                   /* next input INDEX */\n  var put;                    /* next output INDEX */\n  var have, left;             /* available input and output */\n  var hold;                   /* bit buffer */\n  var bits;                   /* bits in bit buffer */\n  var _in, _out;              /* save starting available input and output */\n  var copy;                   /* number of stored or match bytes to copy */\n  var from;                   /* where to copy match bytes from */\n  var from_source;\n  var here = 0;               /* current decoding table entry */\n  var here_bits, here_op, here_val; // paked \"here\" denormalized (JS specific)\n  //var last;                   /* parent table entry */\n  var last_bits, last_op, last_val; // paked \"last\" denormalized (JS specific)\n  var len;                    /* length to copy for repeats, bits to drop */\n  var ret;                    /* return code */\n  var hbuf = new utils.Buf8(4);    /* buffer for gzip header crc calculation */\n  var opts;\n\n  var n; // temporary var for NEED_BITS\n\n  var order = /* permutation of code lengths */\n    [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];\n\n\n  if (!strm || !strm.state || !strm.output ||\n      (!strm.input && strm.avail_in !== 0)) {\n    return Z_STREAM_ERROR;\n  }\n\n  state = strm.state;\n  if (state.mode === TYPE) { state.mode = TYPEDO; }    /* skip check */\n\n\n  //--- LOAD() ---\n  put = strm.next_out;\n  output = strm.output;\n  left = strm.avail_out;\n  next = strm.next_in;\n  input = strm.input;\n  have = strm.avail_in;\n  hold = state.hold;\n  bits = state.bits;\n  //---\n\n  _in = have;\n  _out = left;\n  ret = Z_OK;\n\n  inf_leave: // goto emulation\n  for (;;) {\n    switch (state.mode) {\n    case HEAD:\n      if (state.wrap === 0) {\n        state.mode = TYPEDO;\n        break;\n      }\n      //=== NEEDBITS(16);\n      while (bits < 16) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      if ((state.wrap & 2) && hold === 0x8b1f) {  /* gzip header */\n        state.check = 0/*crc32(0L, Z_NULL, 0)*/;\n        //=== CRC2(state.check, hold);\n        hbuf[0] = hold & 0xff;\n        hbuf[1] = (hold >>> 8) & 0xff;\n        state.check = crc32(state.check, hbuf, 2, 0);\n        //===//\n\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        state.mode = FLAGS;\n        break;\n      }\n      state.flags = 0;           /* expect zlib header */\n      if (state.head) {\n        state.head.done = false;\n      }\n      if (!(state.wrap & 1) ||   /* check if zlib header allowed */\n        (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {\n        strm.msg = 'incorrect header check';\n        state.mode = BAD;\n        break;\n      }\n      if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {\n        strm.msg = 'unknown compression method';\n        state.mode = BAD;\n        break;\n      }\n      //--- DROPBITS(4) ---//\n      hold >>>= 4;\n      bits -= 4;\n      //---//\n      len = (hold & 0x0f)/*BITS(4)*/ + 8;\n      if (state.wbits === 0) {\n        state.wbits = len;\n      }\n      else if (len > state.wbits) {\n        strm.msg = 'invalid window size';\n        state.mode = BAD;\n        break;\n      }\n      state.dmax = 1 << len;\n      //Tracev((stderr, \"inflate:   zlib header ok\\n\"));\n      strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;\n      state.mode = hold & 0x200 ? DICTID : TYPE;\n      //=== INITBITS();\n      hold = 0;\n      bits = 0;\n      //===//\n      break;\n    case FLAGS:\n      //=== NEEDBITS(16); */\n      while (bits < 16) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      state.flags = hold;\n      if ((state.flags & 0xff) !== Z_DEFLATED) {\n        strm.msg = 'unknown compression method';\n        state.mode = BAD;\n        break;\n      }\n      if (state.flags & 0xe000) {\n        strm.msg = 'unknown header flags set';\n        state.mode = BAD;\n        break;\n      }\n      if (state.head) {\n        state.head.text = ((hold >> 8) & 1);\n      }\n      if (state.flags & 0x0200) {\n        //=== CRC2(state.check, hold);\n        hbuf[0] = hold & 0xff;\n        hbuf[1] = (hold >>> 8) & 0xff;\n        state.check = crc32(state.check, hbuf, 2, 0);\n        //===//\n      }\n      //=== INITBITS();\n      hold = 0;\n      bits = 0;\n      //===//\n      state.mode = TIME;\n      /* falls through */\n    case TIME:\n      //=== NEEDBITS(32); */\n      while (bits < 32) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      if (state.head) {\n        state.head.time = hold;\n      }\n      if (state.flags & 0x0200) {\n        //=== CRC4(state.check, hold)\n        hbuf[0] = hold & 0xff;\n        hbuf[1] = (hold >>> 8) & 0xff;\n        hbuf[2] = (hold >>> 16) & 0xff;\n        hbuf[3] = (hold >>> 24) & 0xff;\n        state.check = crc32(state.check, hbuf, 4, 0);\n        //===\n      }\n      //=== INITBITS();\n      hold = 0;\n      bits = 0;\n      //===//\n      state.mode = OS;\n      /* falls through */\n    case OS:\n      //=== NEEDBITS(16); */\n      while (bits < 16) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      if (state.head) {\n        state.head.xflags = (hold & 0xff);\n        state.head.os = (hold >> 8);\n      }\n      if (state.flags & 0x0200) {\n        //=== CRC2(state.check, hold);\n        hbuf[0] = hold & 0xff;\n        hbuf[1] = (hold >>> 8) & 0xff;\n        state.check = crc32(state.check, hbuf, 2, 0);\n        //===//\n      }\n      //=== INITBITS();\n      hold = 0;\n      bits = 0;\n      //===//\n      state.mode = EXLEN;\n      /* falls through */\n    case EXLEN:\n      if (state.flags & 0x0400) {\n        //=== NEEDBITS(16); */\n        while (bits < 16) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        state.length = hold;\n        if (state.head) {\n          state.head.extra_len = hold;\n        }\n        if (state.flags & 0x0200) {\n          //=== CRC2(state.check, hold);\n          hbuf[0] = hold & 0xff;\n          hbuf[1] = (hold >>> 8) & 0xff;\n          state.check = crc32(state.check, hbuf, 2, 0);\n          //===//\n        }\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n      }\n      else if (state.head) {\n        state.head.extra = null/*Z_NULL*/;\n      }\n      state.mode = EXTRA;\n      /* falls through */\n    case EXTRA:\n      if (state.flags & 0x0400) {\n        copy = state.length;\n        if (copy > have) { copy = have; }\n        if (copy) {\n          if (state.head) {\n            len = state.head.extra_len - state.length;\n            if (!state.head.extra) {\n              // Use untyped array for more conveniend processing later\n              state.head.extra = new Array(state.head.extra_len);\n            }\n            utils.arraySet(\n              state.head.extra,\n              input,\n              next,\n              // extra field is limited to 65536 bytes\n              // - no need for additional size check\n              copy,\n              /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/\n              len\n            );\n            //zmemcpy(state.head.extra + len, next,\n            //        len + copy > state.head.extra_max ?\n            //        state.head.extra_max - len : copy);\n          }\n          if (state.flags & 0x0200) {\n            state.check = crc32(state.check, input, copy, next);\n          }\n          have -= copy;\n          next += copy;\n          state.length -= copy;\n        }\n        if (state.length) { break inf_leave; }\n      }\n      state.length = 0;\n      state.mode = NAME;\n      /* falls through */\n    case NAME:\n      if (state.flags & 0x0800) {\n        if (have === 0) { break inf_leave; }\n        copy = 0;\n        do {\n          // TODO: 2 or 1 bytes?\n          len = input[next + copy++];\n          /* use constant limit because in js we should not preallocate memory */\n          if (state.head && len &&\n              (state.length < 65536 /*state.head.name_max*/)) {\n            state.head.name += String.fromCharCode(len);\n          }\n        } while (len && copy < have);\n\n        if (state.flags & 0x0200) {\n          state.check = crc32(state.check, input, copy, next);\n        }\n        have -= copy;\n        next += copy;\n        if (len) { break inf_leave; }\n      }\n      else if (state.head) {\n        state.head.name = null;\n      }\n      state.length = 0;\n      state.mode = COMMENT;\n      /* falls through */\n    case COMMENT:\n      if (state.flags & 0x1000) {\n        if (have === 0) { break inf_leave; }\n        copy = 0;\n        do {\n          len = input[next + copy++];\n          /* use constant limit because in js we should not preallocate memory */\n          if (state.head && len &&\n              (state.length < 65536 /*state.head.comm_max*/)) {\n            state.head.comment += String.fromCharCode(len);\n          }\n        } while (len && copy < have);\n        if (state.flags & 0x0200) {\n          state.check = crc32(state.check, input, copy, next);\n        }\n        have -= copy;\n        next += copy;\n        if (len) { break inf_leave; }\n      }\n      else if (state.head) {\n        state.head.comment = null;\n      }\n      state.mode = HCRC;\n      /* falls through */\n    case HCRC:\n      if (state.flags & 0x0200) {\n        //=== NEEDBITS(16); */\n        while (bits < 16) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        if (hold !== (state.check & 0xffff)) {\n          strm.msg = 'header crc mismatch';\n          state.mode = BAD;\n          break;\n        }\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n      }\n      if (state.head) {\n        state.head.hcrc = ((state.flags >> 9) & 1);\n        state.head.done = true;\n      }\n      strm.adler = state.check = 0 /*crc32(0L, Z_NULL, 0)*/;\n      state.mode = TYPE;\n      break;\n    case DICTID:\n      //=== NEEDBITS(32); */\n      while (bits < 32) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      strm.adler = state.check = ZSWAP32(hold);\n      //=== INITBITS();\n      hold = 0;\n      bits = 0;\n      //===//\n      state.mode = DICT;\n      /* falls through */\n    case DICT:\n      if (state.havedict === 0) {\n        //--- RESTORE() ---\n        strm.next_out = put;\n        strm.avail_out = left;\n        strm.next_in = next;\n        strm.avail_in = have;\n        state.hold = hold;\n        state.bits = bits;\n        //---\n        return Z_NEED_DICT;\n      }\n      strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;\n      state.mode = TYPE;\n      /* falls through */\n    case TYPE:\n      if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }\n      /* falls through */\n    case TYPEDO:\n      if (state.last) {\n        //--- BYTEBITS() ---//\n        hold >>>= bits & 7;\n        bits -= bits & 7;\n        //---//\n        state.mode = CHECK;\n        break;\n      }\n      //=== NEEDBITS(3); */\n      while (bits < 3) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      state.last = (hold & 0x01)/*BITS(1)*/;\n      //--- DROPBITS(1) ---//\n      hold >>>= 1;\n      bits -= 1;\n      //---//\n\n      switch ((hold & 0x03)/*BITS(2)*/) {\n      case 0:                             /* stored block */\n        //Tracev((stderr, \"inflate:     stored block%s\\n\",\n        //        state.last ? \" (last)\" : \"\"));\n        state.mode = STORED;\n        break;\n      case 1:                             /* fixed block */\n        fixedtables(state);\n        //Tracev((stderr, \"inflate:     fixed codes block%s\\n\",\n        //        state.last ? \" (last)\" : \"\"));\n        state.mode = LEN_;             /* decode codes */\n        if (flush === Z_TREES) {\n          //--- DROPBITS(2) ---//\n          hold >>>= 2;\n          bits -= 2;\n          //---//\n          break inf_leave;\n        }\n        break;\n      case 2:                             /* dynamic block */\n        //Tracev((stderr, \"inflate:     dynamic codes block%s\\n\",\n        //        state.last ? \" (last)\" : \"\"));\n        state.mode = TABLE;\n        break;\n      case 3:\n        strm.msg = 'invalid block type';\n        state.mode = BAD;\n      }\n      //--- DROPBITS(2) ---//\n      hold >>>= 2;\n      bits -= 2;\n      //---//\n      break;\n    case STORED:\n      //--- BYTEBITS() ---// /* go to byte boundary */\n      hold >>>= bits & 7;\n      bits -= bits & 7;\n      //---//\n      //=== NEEDBITS(32); */\n      while (bits < 32) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {\n        strm.msg = 'invalid stored block lengths';\n        state.mode = BAD;\n        break;\n      }\n      state.length = hold & 0xffff;\n      //Tracev((stderr, \"inflate:       stored length %u\\n\",\n      //        state.length));\n      //=== INITBITS();\n      hold = 0;\n      bits = 0;\n      //===//\n      state.mode = COPY_;\n      if (flush === Z_TREES) { break inf_leave; }\n      /* falls through */\n    case COPY_:\n      state.mode = COPY;\n      /* falls through */\n    case COPY:\n      copy = state.length;\n      if (copy) {\n        if (copy > have) { copy = have; }\n        if (copy > left) { copy = left; }\n        if (copy === 0) { break inf_leave; }\n        //--- zmemcpy(put, next, copy); ---\n        utils.arraySet(output, input, next, copy, put);\n        //---//\n        have -= copy;\n        next += copy;\n        left -= copy;\n        put += copy;\n        state.length -= copy;\n        break;\n      }\n      //Tracev((stderr, \"inflate:       stored end\\n\"));\n      state.mode = TYPE;\n      break;\n    case TABLE:\n      //=== NEEDBITS(14); */\n      while (bits < 14) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;\n      //--- DROPBITS(5) ---//\n      hold >>>= 5;\n      bits -= 5;\n      //---//\n      state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;\n      //--- DROPBITS(5) ---//\n      hold >>>= 5;\n      bits -= 5;\n      //---//\n      state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;\n      //--- DROPBITS(4) ---//\n      hold >>>= 4;\n      bits -= 4;\n      //---//\n//#ifndef PKZIP_BUG_WORKAROUND\n      if (state.nlen > 286 || state.ndist > 30) {\n        strm.msg = 'too many length or distance symbols';\n        state.mode = BAD;\n        break;\n      }\n//#endif\n      //Tracev((stderr, \"inflate:       table sizes ok\\n\"));\n      state.have = 0;\n      state.mode = LENLENS;\n      /* falls through */\n    case LENLENS:\n      while (state.have < state.ncode) {\n        //=== NEEDBITS(3);\n        while (bits < 3) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);\n        //--- DROPBITS(3) ---//\n        hold >>>= 3;\n        bits -= 3;\n        //---//\n      }\n      while (state.have < 19) {\n        state.lens[order[state.have++]] = 0;\n      }\n      // We have separate tables & no pointers. 2 commented lines below not needed.\n      //state.next = state.codes;\n      //state.lencode = state.next;\n      // Switch to use dynamic table\n      state.lencode = state.lendyn;\n      state.lenbits = 7;\n\n      opts = {bits: state.lenbits};\n      ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);\n      state.lenbits = opts.bits;\n\n      if (ret) {\n        strm.msg = 'invalid code lengths set';\n        state.mode = BAD;\n        break;\n      }\n      //Tracev((stderr, \"inflate:       code lengths ok\\n\"));\n      state.have = 0;\n      state.mode = CODELENS;\n      /* falls through */\n    case CODELENS:\n      while (state.have < state.nlen + state.ndist) {\n        for (;;) {\n          here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/\n          here_bits = here >>> 24;\n          here_op = (here >>> 16) & 0xff;\n          here_val = here & 0xffff;\n\n          if ((here_bits) <= bits) { break; }\n          //--- PULLBYTE() ---//\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n          //---//\n        }\n        if (here_val < 16) {\n          //--- DROPBITS(here.bits) ---//\n          hold >>>= here_bits;\n          bits -= here_bits;\n          //---//\n          state.lens[state.have++] = here_val;\n        }\n        else {\n          if (here_val === 16) {\n            //=== NEEDBITS(here.bits + 2);\n            n = here_bits + 2;\n            while (bits < n) {\n              if (have === 0) { break inf_leave; }\n              have--;\n              hold += input[next++] << bits;\n              bits += 8;\n            }\n            //===//\n            //--- DROPBITS(here.bits) ---//\n            hold >>>= here_bits;\n            bits -= here_bits;\n            //---//\n            if (state.have === 0) {\n              strm.msg = 'invalid bit length repeat';\n              state.mode = BAD;\n              break;\n            }\n            len = state.lens[state.have - 1];\n            copy = 3 + (hold & 0x03);//BITS(2);\n            //--- DROPBITS(2) ---//\n            hold >>>= 2;\n            bits -= 2;\n            //---//\n          }\n          else if (here_val === 17) {\n            //=== NEEDBITS(here.bits + 3);\n            n = here_bits + 3;\n            while (bits < n) {\n              if (have === 0) { break inf_leave; }\n              have--;\n              hold += input[next++] << bits;\n              bits += 8;\n            }\n            //===//\n            //--- DROPBITS(here.bits) ---//\n            hold >>>= here_bits;\n            bits -= here_bits;\n            //---//\n            len = 0;\n            copy = 3 + (hold & 0x07);//BITS(3);\n            //--- DROPBITS(3) ---//\n            hold >>>= 3;\n            bits -= 3;\n            //---//\n          }\n          else {\n            //=== NEEDBITS(here.bits + 7);\n            n = here_bits + 7;\n            while (bits < n) {\n              if (have === 0) { break inf_leave; }\n              have--;\n              hold += input[next++] << bits;\n              bits += 8;\n            }\n            //===//\n            //--- DROPBITS(here.bits) ---//\n            hold >>>= here_bits;\n            bits -= here_bits;\n            //---//\n            len = 0;\n            copy = 11 + (hold & 0x7f);//BITS(7);\n            //--- DROPBITS(7) ---//\n            hold >>>= 7;\n            bits -= 7;\n            //---//\n          }\n          if (state.have + copy > state.nlen + state.ndist) {\n            strm.msg = 'invalid bit length repeat';\n            state.mode = BAD;\n            break;\n          }\n          while (copy--) {\n            state.lens[state.have++] = len;\n          }\n        }\n      }\n\n      /* handle error breaks in while */\n      if (state.mode === BAD) { break; }\n\n      /* check for end-of-block code (better have one) */\n      if (state.lens[256] === 0) {\n        strm.msg = 'invalid code -- missing end-of-block';\n        state.mode = BAD;\n        break;\n      }\n\n      /* build code tables -- note: do not change the lenbits or distbits\n         values here (9 and 6) without reading the comments in inftrees.h\n         concerning the ENOUGH constants, which depend on those values */\n      state.lenbits = 9;\n\n      opts = {bits: state.lenbits};\n      ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);\n      // We have separate tables & no pointers. 2 commented lines below not needed.\n      // state.next_index = opts.table_index;\n      state.lenbits = opts.bits;\n      // state.lencode = state.next;\n\n      if (ret) {\n        strm.msg = 'invalid literal/lengths set';\n        state.mode = BAD;\n        break;\n      }\n\n      state.distbits = 6;\n      //state.distcode.copy(state.codes);\n      // Switch to use dynamic table\n      state.distcode = state.distdyn;\n      opts = {bits: state.distbits};\n      ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);\n      // We have separate tables & no pointers. 2 commented lines below not needed.\n      // state.next_index = opts.table_index;\n      state.distbits = opts.bits;\n      // state.distcode = state.next;\n\n      if (ret) {\n        strm.msg = 'invalid distances set';\n        state.mode = BAD;\n        break;\n      }\n      //Tracev((stderr, 'inflate:       codes ok\\n'));\n      state.mode = LEN_;\n      if (flush === Z_TREES) { break inf_leave; }\n      /* falls through */\n    case LEN_:\n      state.mode = LEN;\n      /* falls through */\n    case LEN:\n      if (have >= 6 && left >= 258) {\n        //--- RESTORE() ---\n        strm.next_out = put;\n        strm.avail_out = left;\n        strm.next_in = next;\n        strm.avail_in = have;\n        state.hold = hold;\n        state.bits = bits;\n        //---\n        inflate_fast(strm, _out);\n        //--- LOAD() ---\n        put = strm.next_out;\n        output = strm.output;\n        left = strm.avail_out;\n        next = strm.next_in;\n        input = strm.input;\n        have = strm.avail_in;\n        hold = state.hold;\n        bits = state.bits;\n        //---\n\n        if (state.mode === TYPE) {\n          state.back = -1;\n        }\n        break;\n      }\n      state.back = 0;\n      for (;;) {\n        here = state.lencode[hold & ((1 << state.lenbits) -1)];  /*BITS(state.lenbits)*/\n        here_bits = here >>> 24;\n        here_op = (here >>> 16) & 0xff;\n        here_val = here & 0xffff;\n\n        if (here_bits <= bits) { break; }\n        //--- PULLBYTE() ---//\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n        //---//\n      }\n      if (here_op && (here_op & 0xf0) === 0) {\n        last_bits = here_bits;\n        last_op = here_op;\n        last_val = here_val;\n        for (;;) {\n          here = state.lencode[last_val +\n                  ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)];\n          here_bits = here >>> 24;\n          here_op = (here >>> 16) & 0xff;\n          here_val = here & 0xffff;\n\n          if ((last_bits + here_bits) <= bits) { break; }\n          //--- PULLBYTE() ---//\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n          //---//\n        }\n        //--- DROPBITS(last.bits) ---//\n        hold >>>= last_bits;\n        bits -= last_bits;\n        //---//\n        state.back += last_bits;\n      }\n      //--- DROPBITS(here.bits) ---//\n      hold >>>= here_bits;\n      bits -= here_bits;\n      //---//\n      state.back += here_bits;\n      state.length = here_val;\n      if (here_op === 0) {\n        //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?\n        //        \"inflate:         literal '%c'\\n\" :\n        //        \"inflate:         literal 0x%02x\\n\", here.val));\n        state.mode = LIT;\n        break;\n      }\n      if (here_op & 32) {\n        //Tracevv((stderr, \"inflate:         end of block\\n\"));\n        state.back = -1;\n        state.mode = TYPE;\n        break;\n      }\n      if (here_op & 64) {\n        strm.msg = 'invalid literal/length code';\n        state.mode = BAD;\n        break;\n      }\n      state.extra = here_op & 15;\n      state.mode = LENEXT;\n      /* falls through */\n    case LENEXT:\n      if (state.extra) {\n        //=== NEEDBITS(state.extra);\n        n = state.extra;\n        while (bits < n) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        state.length += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/;\n        //--- DROPBITS(state.extra) ---//\n        hold >>>= state.extra;\n        bits -= state.extra;\n        //---//\n        state.back += state.extra;\n      }\n      //Tracevv((stderr, \"inflate:         length %u\\n\", state.length));\n      state.was = state.length;\n      state.mode = DIST;\n      /* falls through */\n    case DIST:\n      for (;;) {\n        here = state.distcode[hold & ((1 << state.distbits) -1)];/*BITS(state.distbits)*/\n        here_bits = here >>> 24;\n        here_op = (here >>> 16) & 0xff;\n        here_val = here & 0xffff;\n\n        if ((here_bits) <= bits) { break; }\n        //--- PULLBYTE() ---//\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n        //---//\n      }\n      if ((here_op & 0xf0) === 0) {\n        last_bits = here_bits;\n        last_op = here_op;\n        last_val = here_val;\n        for (;;) {\n          here = state.distcode[last_val +\n                  ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)];\n          here_bits = here >>> 24;\n          here_op = (here >>> 16) & 0xff;\n          here_val = here & 0xffff;\n\n          if ((last_bits + here_bits) <= bits) { break; }\n          //--- PULLBYTE() ---//\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n          //---//\n        }\n        //--- DROPBITS(last.bits) ---//\n        hold >>>= last_bits;\n        bits -= last_bits;\n        //---//\n        state.back += last_bits;\n      }\n      //--- DROPBITS(here.bits) ---//\n      hold >>>= here_bits;\n      bits -= here_bits;\n      //---//\n      state.back += here_bits;\n      if (here_op & 64) {\n        strm.msg = 'invalid distance code';\n        state.mode = BAD;\n        break;\n      }\n      state.offset = here_val;\n      state.extra = (here_op) & 15;\n      state.mode = DISTEXT;\n      /* falls through */\n    case DISTEXT:\n      if (state.extra) {\n        //=== NEEDBITS(state.extra);\n        n = state.extra;\n        while (bits < n) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        state.offset += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/;\n        //--- DROPBITS(state.extra) ---//\n        hold >>>= state.extra;\n        bits -= state.extra;\n        //---//\n        state.back += state.extra;\n      }\n//#ifdef INFLATE_STRICT\n      if (state.offset > state.dmax) {\n        strm.msg = 'invalid distance too far back';\n        state.mode = BAD;\n        break;\n      }\n//#endif\n      //Tracevv((stderr, \"inflate:         distance %u\\n\", state.offset));\n      state.mode = MATCH;\n      /* falls through */\n    case MATCH:\n      if (left === 0) { break inf_leave; }\n      copy = _out - left;\n      if (state.offset > copy) {         /* copy from window */\n        copy = state.offset - copy;\n        if (copy > state.whave) {\n          if (state.sane) {\n            strm.msg = 'invalid distance too far back';\n            state.mode = BAD;\n            break;\n          }\n// (!) This block is disabled in zlib defailts,\n// don't enable it for binary compatibility\n//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR\n//          Trace((stderr, \"inflate.c too far\\n\"));\n//          copy -= state.whave;\n//          if (copy > state.length) { copy = state.length; }\n//          if (copy > left) { copy = left; }\n//          left -= copy;\n//          state.length -= copy;\n//          do {\n//            output[put++] = 0;\n//          } while (--copy);\n//          if (state.length === 0) { state.mode = LEN; }\n//          break;\n//#endif\n        }\n        if (copy > state.wnext) {\n          copy -= state.wnext;\n          from = state.wsize - copy;\n        }\n        else {\n          from = state.wnext - copy;\n        }\n        if (copy > state.length) { copy = state.length; }\n        from_source = state.window;\n      }\n      else {                              /* copy from output */\n        from_source = output;\n        from = put - state.offset;\n        copy = state.length;\n      }\n      if (copy > left) { copy = left; }\n      left -= copy;\n      state.length -= copy;\n      do {\n        output[put++] = from_source[from++];\n      } while (--copy);\n      if (state.length === 0) { state.mode = LEN; }\n      break;\n    case LIT:\n      if (left === 0) { break inf_leave; }\n      output[put++] = state.length;\n      left--;\n      state.mode = LEN;\n      break;\n    case CHECK:\n      if (state.wrap) {\n        //=== NEEDBITS(32);\n        while (bits < 32) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          // Use '|' insdead of '+' to make sure that result is signed\n          hold |= input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        _out -= left;\n        strm.total_out += _out;\n        state.total += _out;\n        if (_out) {\n          strm.adler = state.check =\n              /*UPDATE(state.check, put - _out, _out);*/\n              (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out));\n\n        }\n        _out = left;\n        // NB: crc32 stored as signed 32-bit int, ZSWAP32 returns signed too\n        if ((state.flags ? hold : ZSWAP32(hold)) !== state.check) {\n          strm.msg = 'incorrect data check';\n          state.mode = BAD;\n          break;\n        }\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        //Tracev((stderr, \"inflate:   check matches trailer\\n\"));\n      }\n      state.mode = LENGTH;\n      /* falls through */\n    case LENGTH:\n      if (state.wrap && state.flags) {\n        //=== NEEDBITS(32);\n        while (bits < 32) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        if (hold !== (state.total & 0xffffffff)) {\n          strm.msg = 'incorrect length check';\n          state.mode = BAD;\n          break;\n        }\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        //Tracev((stderr, \"inflate:   length matches trailer\\n\"));\n      }\n      state.mode = DONE;\n      /* falls through */\n    case DONE:\n      ret = Z_STREAM_END;\n      break inf_leave;\n    case BAD:\n      ret = Z_DATA_ERROR;\n      break inf_leave;\n    case MEM:\n      return Z_MEM_ERROR;\n    case SYNC:\n      /* falls through */\n    default:\n      return Z_STREAM_ERROR;\n    }\n  }\n\n  // inf_leave <- here is real place for \"goto inf_leave\", emulated via \"break inf_leave\"\n\n  /*\n     Return from inflate(), updating the total counts and the check value.\n     If there was no progress during the inflate() call, return a buffer\n     error.  Call updatewindow() to create and/or update the window state.\n     Note: a memory error from inflate() is non-recoverable.\n   */\n\n  //--- RESTORE() ---\n  strm.next_out = put;\n  strm.avail_out = left;\n  strm.next_in = next;\n  strm.avail_in = have;\n  state.hold = hold;\n  state.bits = bits;\n  //---\n\n  if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&\n                      (state.mode < CHECK || flush !== Z_FINISH))) {\n    if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {\n      state.mode = MEM;\n      return Z_MEM_ERROR;\n    }\n  }\n  _in -= strm.avail_in;\n  _out -= strm.avail_out;\n  strm.total_in += _in;\n  strm.total_out += _out;\n  state.total += _out;\n  if (state.wrap && _out) {\n    strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/\n      (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out));\n  }\n  strm.data_type = state.bits + (state.last ? 64 : 0) +\n                    (state.mode === TYPE ? 128 : 0) +\n                    (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);\n  if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) {\n    ret = Z_BUF_ERROR;\n  }\n  return ret;\n}\n\nfunction inflateEnd(strm) {\n\n  if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {\n    return Z_STREAM_ERROR;\n  }\n\n  var state = strm.state;\n  if (state.window) {\n    state.window = null;\n  }\n  strm.state = null;\n  return Z_OK;\n}\n\nfunction inflateGetHeader(strm, head) {\n  var state;\n\n  /* check state */\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n  if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; }\n\n  /* save header structure */\n  state.head = head;\n  head.done = false;\n  return Z_OK;\n}\n\n\nexports.inflateReset = inflateReset;\nexports.inflateReset2 = inflateReset2;\nexports.inflateResetKeep = inflateResetKeep;\nexports.inflateInit = inflateInit;\nexports.inflateInit2 = inflateInit2;\nexports.inflate = inflate;\nexports.inflateEnd = inflateEnd;\nexports.inflateGetHeader = inflateGetHeader;\nexports.inflateInfo = 'pako inflate (from Nodeca project)';\n\n/* Not implemented\nexports.inflateCopy = inflateCopy;\nexports.inflateGetDictionary = inflateGetDictionary;\nexports.inflateMark = inflateMark;\nexports.inflatePrime = inflatePrime;\nexports.inflateSetDictionary = inflateSetDictionary;\nexports.inflateSync = inflateSync;\nexports.inflateSyncPoint = inflateSyncPoint;\nexports.inflateUndermine = inflateUndermine;\n*/\n},{\"../utils/common\":27,\"./adler32\":29,\"./crc32\":31,\"./inffast\":34,\"./inftrees\":36}],36:[function(_dereq_,module,exports){\n'use strict';\n\n\nvar utils = _dereq_('../utils/common');\n\nvar MAXBITS = 15;\nvar ENOUGH_LENS = 852;\nvar ENOUGH_DISTS = 592;\n//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);\n\nvar CODES = 0;\nvar LENS = 1;\nvar DISTS = 2;\n\nvar lbase = [ /* Length codes 257..285 base */\n  3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,\n  35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0\n];\n\nvar lext = [ /* Length codes 257..285 extra */\n  16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,\n  19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78\n];\n\nvar dbase = [ /* Distance codes 0..29 base */\n  1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,\n  257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,\n  8193, 12289, 16385, 24577, 0, 0\n];\n\nvar dext = [ /* Distance codes 0..29 extra */\n  16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,\n  23, 23, 24, 24, 25, 25, 26, 26, 27, 27,\n  28, 28, 29, 29, 64, 64\n];\n\nmodule.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts)\n{\n  var bits = opts.bits;\n      //here = opts.here; /* table entry for duplication */\n\n  var len = 0;               /* a code's length in bits */\n  var sym = 0;               /* index of code symbols */\n  var min = 0, max = 0;          /* minimum and maximum code lengths */\n  var root = 0;              /* number of index bits for root table */\n  var curr = 0;              /* number of index bits for current table */\n  var drop = 0;              /* code bits to drop for sub-table */\n  var left = 0;                   /* number of prefix codes available */\n  var used = 0;              /* code entries in table used */\n  var huff = 0;              /* Huffman code */\n  var incr;              /* for incrementing code, index */\n  var fill;              /* index for replicating entries */\n  var low;               /* low bits for current root entry */\n  var mask;              /* mask for low root bits */\n  var next;             /* next available space in table */\n  var base = null;     /* base value table to use */\n  var base_index = 0;\n//  var shoextra;    /* extra bits table to use */\n  var end;                    /* use base and extra for symbol > end */\n  var count = new utils.Buf16(MAXBITS+1); //[MAXBITS+1];    /* number of codes of each length */\n  var offs = new utils.Buf16(MAXBITS+1); //[MAXBITS+1];     /* offsets in table for each length */\n  var extra = null;\n  var extra_index = 0;\n\n  var here_bits, here_op, here_val;\n\n  /*\n   Process a set of code lengths to create a canonical Huffman code.  The\n   code lengths are lens[0..codes-1].  Each length corresponds to the\n   symbols 0..codes-1.  The Huffman code is generated by first sorting the\n   symbols by length from short to long, and retaining the symbol order\n   for codes with equal lengths.  Then the code starts with all zero bits\n   for the first code of the shortest length, and the codes are integer\n   increments for the same length, and zeros are appended as the length\n   increases.  For the deflate format, these bits are stored backwards\n   from their more natural integer increment ordering, and so when the\n   decoding tables are built in the large loop below, the integer codes\n   are incremented backwards.\n\n   This routine assumes, but does not check, that all of the entries in\n   lens[] are in the range 0..MAXBITS.  The caller must assure this.\n   1..MAXBITS is interpreted as that code length.  zero means that that\n   symbol does not occur in this code.\n\n   The codes are sorted by computing a count of codes for each length,\n   creating from that a table of starting indices for each length in the\n   sorted table, and then entering the symbols in order in the sorted\n   table.  The sorted table is work[], with that space being provided by\n   the caller.\n\n   The length counts are used for other purposes as well, i.e. finding\n   the minimum and maximum length codes, determining if there are any\n   codes at all, checking for a valid set of lengths, and looking ahead\n   at length counts to determine sub-table sizes when building the\n   decoding tables.\n   */\n\n  /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */\n  for (len = 0; len <= MAXBITS; len++) {\n    count[len] = 0;\n  }\n  for (sym = 0; sym < codes; sym++) {\n    count[lens[lens_index + sym]]++;\n  }\n\n  /* bound code lengths, force root to be within code lengths */\n  root = bits;\n  for (max = MAXBITS; max >= 1; max--) {\n    if (count[max] !== 0) { break; }\n  }\n  if (root > max) {\n    root = max;\n  }\n  if (max === 0) {                     /* no symbols to code at all */\n    //table.op[opts.table_index] = 64;  //here.op = (var char)64;    /* invalid code marker */\n    //table.bits[opts.table_index] = 1;   //here.bits = (var char)1;\n    //table.val[opts.table_index++] = 0;   //here.val = (var short)0;\n    table[table_index++] = (1 << 24) | (64 << 16) | 0;\n\n\n    //table.op[opts.table_index] = 64;\n    //table.bits[opts.table_index] = 1;\n    //table.val[opts.table_index++] = 0;\n    table[table_index++] = (1 << 24) | (64 << 16) | 0;\n\n    opts.bits = 1;\n    return 0;     /* no symbols, but wait for decoding to report error */\n  }\n  for (min = 1; min < max; min++) {\n    if (count[min] !== 0) { break; }\n  }\n  if (root < min) {\n    root = min;\n  }\n\n  /* check for an over-subscribed or incomplete set of lengths */\n  left = 1;\n  for (len = 1; len <= MAXBITS; len++) {\n    left <<= 1;\n    left -= count[len];\n    if (left < 0) {\n      return -1;\n    }        /* over-subscribed */\n  }\n  if (left > 0 && (type === CODES || max !== 1)) {\n    return -1;                      /* incomplete set */\n  }\n\n  /* generate offsets into symbol table for each length for sorting */\n  offs[1] = 0;\n  for (len = 1; len < MAXBITS; len++) {\n    offs[len + 1] = offs[len] + count[len];\n  }\n\n  /* sort symbols by length, by symbol order within each length */\n  for (sym = 0; sym < codes; sym++) {\n    if (lens[lens_index + sym] !== 0) {\n      work[offs[lens[lens_index + sym]]++] = sym;\n    }\n  }\n\n  /*\n   Create and fill in decoding tables.  In this loop, the table being\n   filled is at next and has curr index bits.  The code being used is huff\n   with length len.  That code is converted to an index by dropping drop\n   bits off of the bottom.  For codes where len is less than drop + curr,\n   those top drop + curr - len bits are incremented through all values to\n   fill the table with replicated entries.\n\n   root is the number of index bits for the root table.  When len exceeds\n   root, sub-tables are created pointed to by the root entry with an index\n   of the low root bits of huff.  This is saved in low to check for when a\n   new sub-table should be started.  drop is zero when the root table is\n   being filled, and drop is root when sub-tables are being filled.\n\n   When a new sub-table is needed, it is necessary to look ahead in the\n   code lengths to determine what size sub-table is needed.  The length\n   counts are used for this, and so count[] is decremented as codes are\n   entered in the tables.\n\n   used keeps track of how many table entries have been allocated from the\n   provided *table space.  It is checked for LENS and DIST tables against\n   the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in\n   the initial root table size constants.  See the comments in inftrees.h\n   for more information.\n\n   sym increments through all symbols, and the loop terminates when\n   all codes of length max, i.e. all codes, have been processed.  This\n   routine permits incomplete codes, so another loop after this one fills\n   in the rest of the decoding tables with invalid code markers.\n   */\n\n  /* set up for code type */\n  // poor man optimization - use if-else instead of switch,\n  // to avoid deopts in old v8\n  if (type === CODES) {\n      base = extra = work;    /* dummy value--not used */\n      end = 19;\n  } else if (type === LENS) {\n      base = lbase;\n      base_index -= 257;\n      extra = lext;\n      extra_index -= 257;\n      end = 256;\n  } else {                    /* DISTS */\n      base = dbase;\n      extra = dext;\n      end = -1;\n  }\n\n  /* initialize opts for loop */\n  huff = 0;                   /* starting code */\n  sym = 0;                    /* starting code symbol */\n  len = min;                  /* starting code length */\n  next = table_index;              /* current table to fill in */\n  curr = root;                /* current table index bits */\n  drop = 0;                   /* current bits to drop from code for index */\n  low = -1;                   /* trigger new sub-table when len > root */\n  used = 1 << root;          /* use root table entries */\n  mask = used - 1;            /* mask for comparing low */\n\n  /* check available table space */\n  if ((type === LENS && used > ENOUGH_LENS) ||\n    (type === DISTS && used > ENOUGH_DISTS)) {\n    return 1;\n  }\n\n  var i=0;\n  /* process all codes and make table entries */\n  for (;;) {\n    i++;\n    /* create table entry */\n    here_bits = len - drop;\n    if (work[sym] < end) {\n      here_op = 0;\n      here_val = work[sym];\n    }\n    else if (work[sym] > end) {\n      here_op = extra[extra_index + work[sym]];\n      here_val = base[base_index + work[sym]];\n    }\n    else {\n      here_op = 32 + 64;         /* end of block */\n      here_val = 0;\n    }\n\n    /* replicate for those indices with low len bits equal to huff */\n    incr = 1 << (len - drop);\n    fill = 1 << curr;\n    min = fill;                 /* save offset to next table */\n    do {\n      fill -= incr;\n      table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;\n    } while (fill !== 0);\n\n    /* backwards increment the len-bit code huff */\n    incr = 1 << (len - 1);\n    while (huff & incr) {\n      incr >>= 1;\n    }\n    if (incr !== 0) {\n      huff &= incr - 1;\n      huff += incr;\n    } else {\n      huff = 0;\n    }\n\n    /* go to next symbol, update count, len */\n    sym++;\n    if (--count[len] === 0) {\n      if (len === max) { break; }\n      len = lens[lens_index + work[sym]];\n    }\n\n    /* create new sub-table if needed */\n    if (len > root && (huff & mask) !== low) {\n      /* if first time, transition to sub-tables */\n      if (drop === 0) {\n        drop = root;\n      }\n\n      /* increment past last table */\n      next += min;            /* here min is 1 << curr */\n\n      /* determine length of next table */\n      curr = len - drop;\n      left = 1 << curr;\n      while (curr + drop < max) {\n        left -= count[curr + drop];\n        if (left <= 0) { break; }\n        curr++;\n        left <<= 1;\n      }\n\n      /* check for enough space */\n      used += 1 << curr;\n      if ((type === LENS && used > ENOUGH_LENS) ||\n        (type === DISTS && used > ENOUGH_DISTS)) {\n        return 1;\n      }\n\n      /* point entry in root table to sub-table */\n      low = huff & mask;\n      /*table.op[low] = curr;\n      table.bits[low] = root;\n      table.val[low] = next - opts.table_index;*/\n      table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;\n    }\n  }\n\n  /* fill in remaining table entry if code is incomplete (guaranteed to have\n   at most one remaining entry, since if the code is incomplete, the\n   maximum code length that was allowed to get this far is one bit) */\n  if (huff !== 0) {\n    //table.op[next + huff] = 64;            /* invalid code marker */\n    //table.bits[next + huff] = len - drop;\n    //table.val[next + huff] = 0;\n    table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;\n  }\n\n  /* set return parameters */\n  //opts.table_index += used;\n  opts.bits = root;\n  return 0;\n};\n\n},{\"../utils/common\":27}],37:[function(_dereq_,module,exports){\n'use strict';\n\nmodule.exports = {\n  '2':    'need dictionary',     /* Z_NEED_DICT       2  */\n  '1':    'stream end',          /* Z_STREAM_END      1  */\n  '0':    '',                    /* Z_OK              0  */\n  '-1':   'file error',          /* Z_ERRNO         (-1) */\n  '-2':   'stream error',        /* Z_STREAM_ERROR  (-2) */\n  '-3':   'data error',          /* Z_DATA_ERROR    (-3) */\n  '-4':   'insufficient memory', /* Z_MEM_ERROR     (-4) */\n  '-5':   'buffer error',        /* Z_BUF_ERROR     (-5) */\n  '-6':   'incompatible version' /* Z_VERSION_ERROR (-6) */\n};\n},{}],38:[function(_dereq_,module,exports){\n'use strict';\n\n\nvar utils = _dereq_('../utils/common');\n\n/* Public constants ==========================================================*/\n/* ===========================================================================*/\n\n\n//var Z_FILTERED          = 1;\n//var Z_HUFFMAN_ONLY      = 2;\n//var Z_RLE               = 3;\nvar Z_FIXED               = 4;\n//var Z_DEFAULT_STRATEGY  = 0;\n\n/* Possible values of the data_type field (though see inflate()) */\nvar Z_BINARY              = 0;\nvar Z_TEXT                = 1;\n//var Z_ASCII             = 1; // = Z_TEXT\nvar Z_UNKNOWN             = 2;\n\n/*============================================================================*/\n\n\nfunction zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }\n\n// From zutil.h\n\nvar STORED_BLOCK = 0;\nvar STATIC_TREES = 1;\nvar DYN_TREES    = 2;\n/* The three kinds of block type */\n\nvar MIN_MATCH    = 3;\nvar MAX_MATCH    = 258;\n/* The minimum and maximum match lengths */\n\n// From deflate.h\n/* ===========================================================================\n * Internal compression state.\n */\n\nvar LENGTH_CODES  = 29;\n/* number of length codes, not counting the special END_BLOCK code */\n\nvar LITERALS      = 256;\n/* number of literal bytes 0..255 */\n\nvar L_CODES       = LITERALS + 1 + LENGTH_CODES;\n/* number of Literal or Length codes, including the END_BLOCK code */\n\nvar D_CODES       = 30;\n/* number of distance codes */\n\nvar BL_CODES      = 19;\n/* number of codes used to transfer the bit lengths */\n\nvar HEAP_SIZE     = 2*L_CODES + 1;\n/* maximum heap size */\n\nvar MAX_BITS      = 15;\n/* All codes must not exceed MAX_BITS bits */\n\nvar Buf_size      = 16;\n/* size of bit buffer in bi_buf */\n\n\n/* ===========================================================================\n * Constants\n */\n\nvar MAX_BL_BITS = 7;\n/* Bit length codes must not exceed MAX_BL_BITS bits */\n\nvar END_BLOCK   = 256;\n/* end of block literal code */\n\nvar REP_3_6     = 16;\n/* repeat previous bit length 3-6 times (2 bits of repeat count) */\n\nvar REPZ_3_10   = 17;\n/* repeat a zero length 3-10 times  (3 bits of repeat count) */\n\nvar REPZ_11_138 = 18;\n/* repeat a zero length 11-138 times  (7 bits of repeat count) */\n\nvar extra_lbits =   /* extra bits for each length code */\n  [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0];\n\nvar extra_dbits =   /* extra bits for each distance code */\n  [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];\n\nvar extra_blbits =  /* extra bits for each bit length code */\n  [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];\n\nvar bl_order =\n  [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];\n/* The lengths of the bit length codes are sent in order of decreasing\n * probability, to avoid transmitting the lengths for unused bit length codes.\n */\n\n/* ===========================================================================\n * Local data. These are initialized only once.\n */\n\n// We pre-fill arrays with 0 to avoid uninitialized gaps\n\nvar DIST_CODE_LEN = 512; /* see definition of array dist_code below */\n\n// !!!! Use flat array insdead of structure, Freq = i*2, Len = i*2+1\nvar static_ltree  = new Array((L_CODES+2) * 2);\nzero(static_ltree);\n/* The static literal tree. Since the bit lengths are imposed, there is no\n * need for the L_CODES extra codes used during heap construction. However\n * The codes 286 and 287 are needed to build a canonical tree (see _tr_init\n * below).\n */\n\nvar static_dtree  = new Array(D_CODES * 2);\nzero(static_dtree);\n/* The static distance tree. (Actually a trivial tree since all codes use\n * 5 bits.)\n */\n\nvar _dist_code    = new Array(DIST_CODE_LEN);\nzero(_dist_code);\n/* Distance codes. The first 256 values correspond to the distances\n * 3 .. 258, the last 256 values correspond to the top 8 bits of\n * the 15 bit distances.\n */\n\nvar _length_code  = new Array(MAX_MATCH-MIN_MATCH+1);\nzero(_length_code);\n/* length code for each normalized match length (0 == MIN_MATCH) */\n\nvar base_length   = new Array(LENGTH_CODES);\nzero(base_length);\n/* First normalized length for each code (0 = MIN_MATCH) */\n\nvar base_dist     = new Array(D_CODES);\nzero(base_dist);\n/* First normalized distance for each code (0 = distance of 1) */\n\n\nvar StaticTreeDesc = function (static_tree, extra_bits, extra_base, elems, max_length) {\n\n  this.static_tree  = static_tree;  /* static tree or NULL */\n  this.extra_bits   = extra_bits;   /* extra bits for each code or NULL */\n  this.extra_base   = extra_base;   /* base index for extra_bits */\n  this.elems        = elems;        /* max number of elements in the tree */\n  this.max_length   = max_length;   /* max bit length for the codes */\n\n  // show if `static_tree` has data or dummy - needed for monomorphic objects\n  this.has_stree    = static_tree && static_tree.length;\n};\n\n\nvar static_l_desc;\nvar static_d_desc;\nvar static_bl_desc;\n\n\nvar TreeDesc = function(dyn_tree, stat_desc) {\n  this.dyn_tree = dyn_tree;     /* the dynamic tree */\n  this.max_code = 0;            /* largest code with non zero frequency */\n  this.stat_desc = stat_desc;   /* the corresponding static tree */\n};\n\n\n\nfunction d_code(dist) {\n  return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];\n}\n\n\n/* ===========================================================================\n * Output a short LSB first on the stream.\n * IN assertion: there is enough room in pendingBuf.\n */\nfunction put_short (s, w) {\n//    put_byte(s, (uch)((w) & 0xff));\n//    put_byte(s, (uch)((ush)(w) >> 8));\n  s.pending_buf[s.pending++] = (w) & 0xff;\n  s.pending_buf[s.pending++] = (w >>> 8) & 0xff;\n}\n\n\n/* ===========================================================================\n * Send a value on a given number of bits.\n * IN assertion: length <= 16 and value fits in length bits.\n */\nfunction send_bits(s, value, length) {\n  if (s.bi_valid > (Buf_size - length)) {\n    s.bi_buf |= (value << s.bi_valid) & 0xffff;\n    put_short(s, s.bi_buf);\n    s.bi_buf = value >> (Buf_size - s.bi_valid);\n    s.bi_valid += length - Buf_size;\n  } else {\n    s.bi_buf |= (value << s.bi_valid) & 0xffff;\n    s.bi_valid += length;\n  }\n}\n\n\nfunction send_code(s, c, tree) {\n  send_bits(s, tree[c*2]/*.Code*/, tree[c*2 + 1]/*.Len*/);\n}\n\n\n/* ===========================================================================\n * Reverse the first len bits of a code, using straightforward code (a faster\n * method would use a table)\n * IN assertion: 1 <= len <= 15\n */\nfunction bi_reverse(code, len) {\n  var res = 0;\n  do {\n    res |= code & 1;\n    code >>>= 1;\n    res <<= 1;\n  } while (--len > 0);\n  return res >>> 1;\n}\n\n\n/* ===========================================================================\n * Flush the bit buffer, keeping at most 7 bits in it.\n */\nfunction bi_flush(s) {\n  if (s.bi_valid === 16) {\n    put_short(s, s.bi_buf);\n    s.bi_buf = 0;\n    s.bi_valid = 0;\n\n  } else if (s.bi_valid >= 8) {\n    s.pending_buf[s.pending++] = s.bi_buf & 0xff;\n    s.bi_buf >>= 8;\n    s.bi_valid -= 8;\n  }\n}\n\n\n/* ===========================================================================\n * Compute the optimal bit lengths for a tree and update the total bit length\n * for the current block.\n * IN assertion: the fields freq and dad are set, heap[heap_max] and\n *    above are the tree nodes sorted by increasing frequency.\n * OUT assertions: the field len is set to the optimal bit length, the\n *     array bl_count contains the frequencies for each bit length.\n *     The length opt_len is updated; static_len is also updated if stree is\n *     not null.\n */\nfunction gen_bitlen(s, desc)\n//    deflate_state *s;\n//    tree_desc *desc;    /* the tree descriptor */\n{\n  var tree            = desc.dyn_tree;\n  var max_code        = desc.max_code;\n  var stree           = desc.stat_desc.static_tree;\n  var has_stree       = desc.stat_desc.has_stree;\n  var extra           = desc.stat_desc.extra_bits;\n  var base            = desc.stat_desc.extra_base;\n  var max_length      = desc.stat_desc.max_length;\n  var h;              /* heap index */\n  var n, m;           /* iterate over the tree elements */\n  var bits;           /* bit length */\n  var xbits;          /* extra bits */\n  var f;              /* frequency */\n  var overflow = 0;   /* number of elements with bit length too large */\n\n  for (bits = 0; bits <= MAX_BITS; bits++) {\n    s.bl_count[bits] = 0;\n  }\n\n  /* In a first pass, compute the optimal bit lengths (which may\n   * overflow in the case of the bit length tree).\n   */\n  tree[s.heap[s.heap_max]*2 + 1]/*.Len*/ = 0; /* root of the heap */\n\n  for (h = s.heap_max+1; h < HEAP_SIZE; h++) {\n    n = s.heap[h];\n    bits = tree[tree[n*2 +1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;\n    if (bits > max_length) {\n      bits = max_length;\n      overflow++;\n    }\n    tree[n*2 + 1]/*.Len*/ = bits;\n    /* We overwrite tree[n].Dad which is no longer needed */\n\n    if (n > max_code) { continue; } /* not a leaf node */\n\n    s.bl_count[bits]++;\n    xbits = 0;\n    if (n >= base) {\n      xbits = extra[n-base];\n    }\n    f = tree[n * 2]/*.Freq*/;\n    s.opt_len += f * (bits + xbits);\n    if (has_stree) {\n      s.static_len += f * (stree[n*2 + 1]/*.Len*/ + xbits);\n    }\n  }\n  if (overflow === 0) { return; }\n\n  // Trace((stderr,\"\\nbit length overflow\\n\"));\n  /* This happens for example on obj2 and pic of the Calgary corpus */\n\n  /* Find the first bit length which could increase: */\n  do {\n    bits = max_length-1;\n    while (s.bl_count[bits] === 0) { bits--; }\n    s.bl_count[bits]--;      /* move one leaf down the tree */\n    s.bl_count[bits+1] += 2; /* move one overflow item as its brother */\n    s.bl_count[max_length]--;\n    /* The brother of the overflow item also moves one step up,\n     * but this does not affect bl_count[max_length]\n     */\n    overflow -= 2;\n  } while (overflow > 0);\n\n  /* Now recompute all bit lengths, scanning in increasing frequency.\n   * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all\n   * lengths instead of fixing only the wrong ones. This idea is taken\n   * from 'ar' written by Haruhiko Okumura.)\n   */\n  for (bits = max_length; bits !== 0; bits--) {\n    n = s.bl_count[bits];\n    while (n !== 0) {\n      m = s.heap[--h];\n      if (m > max_code) { continue; }\n      if (tree[m*2 + 1]/*.Len*/ !== bits) {\n        // Trace((stderr,\"code %d bits %d->%d\\n\", m, tree[m].Len, bits));\n        s.opt_len += (bits - tree[m*2 + 1]/*.Len*/)*tree[m*2]/*.Freq*/;\n        tree[m*2 + 1]/*.Len*/ = bits;\n      }\n      n--;\n    }\n  }\n}\n\n\n/* ===========================================================================\n * Generate the codes for a given tree and bit counts (which need not be\n * optimal).\n * IN assertion: the array bl_count contains the bit length statistics for\n * the given tree and the field len is set for all tree elements.\n * OUT assertion: the field code is set for all tree elements of non\n *     zero code length.\n */\nfunction gen_codes(tree, max_code, bl_count)\n//    ct_data *tree;             /* the tree to decorate */\n//    int max_code;              /* largest code with non zero frequency */\n//    ushf *bl_count;            /* number of codes at each bit length */\n{\n  var next_code = new Array(MAX_BITS+1); /* next code value for each bit length */\n  var code = 0;              /* running code value */\n  var bits;                  /* bit index */\n  var n;                     /* code index */\n\n  /* The distribution counts are first used to generate the code values\n   * without bit reversal.\n   */\n  for (bits = 1; bits <= MAX_BITS; bits++) {\n    next_code[bits] = code = (code + bl_count[bits-1]) << 1;\n  }\n  /* Check that the bit counts in bl_count are consistent. The last code\n   * must be all ones.\n   */\n  //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,\n  //        \"inconsistent bit counts\");\n  //Tracev((stderr,\"\\ngen_codes: max_code %d \", max_code));\n\n  for (n = 0;  n <= max_code; n++) {\n    var len = tree[n*2 + 1]/*.Len*/;\n    if (len === 0) { continue; }\n    /* Now reverse the bits */\n    tree[n*2]/*.Code*/ = bi_reverse(next_code[len]++, len);\n\n    //Tracecv(tree != static_ltree, (stderr,\"\\nn %3d %c l %2d c %4x (%x) \",\n    //     n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));\n  }\n}\n\n\n/* ===========================================================================\n * Initialize the various 'constant' tables.\n */\nfunction tr_static_init() {\n  var n;        /* iterates over tree elements */\n  var bits;     /* bit counter */\n  var length;   /* length value */\n  var code;     /* code value */\n  var dist;     /* distance index */\n  var bl_count = new Array(MAX_BITS+1);\n  /* number of codes at each bit length for an optimal tree */\n\n  // do check in _tr_init()\n  //if (static_init_done) return;\n\n  /* For some embedded targets, global variables are not initialized: */\n/*#ifdef NO_INIT_GLOBAL_POINTERS\n  static_l_desc.static_tree = static_ltree;\n  static_l_desc.extra_bits = extra_lbits;\n  static_d_desc.static_tree = static_dtree;\n  static_d_desc.extra_bits = extra_dbits;\n  static_bl_desc.extra_bits = extra_blbits;\n#endif*/\n\n  /* Initialize the mapping length (0..255) -> length code (0..28) */\n  length = 0;\n  for (code = 0; code < LENGTH_CODES-1; code++) {\n    base_length[code] = length;\n    for (n = 0; n < (1<<extra_lbits[code]); n++) {\n      _length_code[length++] = code;\n    }\n  }\n  //Assert (length == 256, \"tr_static_init: length != 256\");\n  /* Note that the length 255 (match length 258) can be represented\n   * in two different ways: code 284 + 5 bits or code 285, so we\n   * overwrite length_code[255] to use the best encoding:\n   */\n  _length_code[length-1] = code;\n\n  /* Initialize the mapping dist (0..32K) -> dist code (0..29) */\n  dist = 0;\n  for (code = 0 ; code < 16; code++) {\n    base_dist[code] = dist;\n    for (n = 0; n < (1<<extra_dbits[code]); n++) {\n      _dist_code[dist++] = code;\n    }\n  }\n  //Assert (dist == 256, \"tr_static_init: dist != 256\");\n  dist >>= 7; /* from now on, all distances are divided by 128 */\n  for ( ; code < D_CODES; code++) {\n    base_dist[code] = dist << 7;\n    for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {\n      _dist_code[256 + dist++] = code;\n    }\n  }\n  //Assert (dist == 256, \"tr_static_init: 256+dist != 512\");\n\n  /* Construct the codes of the static literal tree */\n  for (bits = 0; bits <= MAX_BITS; bits++) {\n    bl_count[bits] = 0;\n  }\n\n  n = 0;\n  while (n <= 143) {\n    static_ltree[n*2 + 1]/*.Len*/ = 8;\n    n++;\n    bl_count[8]++;\n  }\n  while (n <= 255) {\n    static_ltree[n*2 + 1]/*.Len*/ = 9;\n    n++;\n    bl_count[9]++;\n  }\n  while (n <= 279) {\n    static_ltree[n*2 + 1]/*.Len*/ = 7;\n    n++;\n    bl_count[7]++;\n  }\n  while (n <= 287) {\n    static_ltree[n*2 + 1]/*.Len*/ = 8;\n    n++;\n    bl_count[8]++;\n  }\n  /* Codes 286 and 287 do not exist, but we must include them in the\n   * tree construction to get a canonical Huffman tree (longest code\n   * all ones)\n   */\n  gen_codes(static_ltree, L_CODES+1, bl_count);\n\n  /* The static distance tree is trivial: */\n  for (n = 0; n < D_CODES; n++) {\n    static_dtree[n*2 + 1]/*.Len*/ = 5;\n    static_dtree[n*2]/*.Code*/ = bi_reverse(n, 5);\n  }\n\n  // Now data ready and we can init static trees\n  static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS);\n  static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS);\n  static_bl_desc =new StaticTreeDesc(new Array(0), extra_blbits, 0,         BL_CODES, MAX_BL_BITS);\n\n  //static_init_done = true;\n}\n\n\n/* ===========================================================================\n * Initialize a new block.\n */\nfunction init_block(s) {\n  var n; /* iterates over tree elements */\n\n  /* Initialize the trees. */\n  for (n = 0; n < L_CODES;  n++) { s.dyn_ltree[n*2]/*.Freq*/ = 0; }\n  for (n = 0; n < D_CODES;  n++) { s.dyn_dtree[n*2]/*.Freq*/ = 0; }\n  for (n = 0; n < BL_CODES; n++) { s.bl_tree[n*2]/*.Freq*/ = 0; }\n\n  s.dyn_ltree[END_BLOCK*2]/*.Freq*/ = 1;\n  s.opt_len = s.static_len = 0;\n  s.last_lit = s.matches = 0;\n}\n\n\n/* ===========================================================================\n * Flush the bit buffer and align the output on a byte boundary\n */\nfunction bi_windup(s)\n{\n  if (s.bi_valid > 8) {\n    put_short(s, s.bi_buf);\n  } else if (s.bi_valid > 0) {\n    //put_byte(s, (Byte)s->bi_buf);\n    s.pending_buf[s.pending++] = s.bi_buf;\n  }\n  s.bi_buf = 0;\n  s.bi_valid = 0;\n}\n\n/* ===========================================================================\n * Copy a stored block, storing first the length and its\n * one's complement if requested.\n */\nfunction copy_block(s, buf, len, header)\n//DeflateState *s;\n//charf    *buf;    /* the input data */\n//unsigned len;     /* its length */\n//int      header;  /* true if block header must be written */\n{\n  bi_windup(s);        /* align on byte boundary */\n\n  if (header) {\n    put_short(s, len);\n    put_short(s, ~len);\n  }\n//  while (len--) {\n//    put_byte(s, *buf++);\n//  }\n  utils.arraySet(s.pending_buf, s.window, buf, len, s.pending);\n  s.pending += len;\n}\n\n/* ===========================================================================\n * Compares to subtrees, using the tree depth as tie breaker when\n * the subtrees have equal frequency. This minimizes the worst case length.\n */\nfunction smaller(tree, n, m, depth) {\n  var _n2 = n*2;\n  var _m2 = m*2;\n  return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||\n         (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m]));\n}\n\n/* ===========================================================================\n * Restore the heap property by moving down the tree starting at node k,\n * exchanging a node with the smallest of its two sons if necessary, stopping\n * when the heap property is re-established (each father smaller than its\n * two sons).\n */\nfunction pqdownheap(s, tree, k)\n//    deflate_state *s;\n//    ct_data *tree;  /* the tree to restore */\n//    int k;               /* node to move down */\n{\n  var v = s.heap[k];\n  var j = k << 1;  /* left son of k */\n  while (j <= s.heap_len) {\n    /* Set j to the smallest of the two sons: */\n    if (j < s.heap_len &&\n      smaller(tree, s.heap[j+1], s.heap[j], s.depth)) {\n      j++;\n    }\n    /* Exit if v is smaller than both sons */\n    if (smaller(tree, v, s.heap[j], s.depth)) { break; }\n\n    /* Exchange v with the smallest son */\n    s.heap[k] = s.heap[j];\n    k = j;\n\n    /* And continue down the tree, setting j to the left son of k */\n    j <<= 1;\n  }\n  s.heap[k] = v;\n}\n\n\n// inlined manually\n// var SMALLEST = 1;\n\n/* ===========================================================================\n * Send the block data compressed using the given Huffman trees\n */\nfunction compress_block(s, ltree, dtree)\n//    deflate_state *s;\n//    const ct_data *ltree; /* literal tree */\n//    const ct_data *dtree; /* distance tree */\n{\n  var dist;           /* distance of matched string */\n  var lc;             /* match length or unmatched char (if dist == 0) */\n  var lx = 0;         /* running index in l_buf */\n  var code;           /* the code to send */\n  var extra;          /* number of extra bits to send */\n\n  if (s.last_lit !== 0) {\n    do {\n      dist = (s.pending_buf[s.d_buf + lx*2] << 8) | (s.pending_buf[s.d_buf + lx*2 + 1]);\n      lc = s.pending_buf[s.l_buf + lx];\n      lx++;\n\n      if (dist === 0) {\n        send_code(s, lc, ltree); /* send a literal byte */\n        //Tracecv(isgraph(lc), (stderr,\" '%c' \", lc));\n      } else {\n        /* Here, lc is the match length - MIN_MATCH */\n        code = _length_code[lc];\n        send_code(s, code+LITERALS+1, ltree); /* send the length code */\n        extra = extra_lbits[code];\n        if (extra !== 0) {\n          lc -= base_length[code];\n          send_bits(s, lc, extra);       /* send the extra length bits */\n        }\n        dist--; /* dist is now the match distance - 1 */\n        code = d_code(dist);\n        //Assert (code < D_CODES, \"bad d_code\");\n\n        send_code(s, code, dtree);       /* send the distance code */\n        extra = extra_dbits[code];\n        if (extra !== 0) {\n          dist -= base_dist[code];\n          send_bits(s, dist, extra);   /* send the extra distance bits */\n        }\n      } /* literal or match pair ? */\n\n      /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */\n      //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,\n      //       \"pendingBuf overflow\");\n\n    } while (lx < s.last_lit);\n  }\n\n  send_code(s, END_BLOCK, ltree);\n}\n\n\n/* ===========================================================================\n * Construct one Huffman tree and assigns the code bit strings and lengths.\n * Update the total bit length for the current block.\n * IN assertion: the field freq is set for all tree elements.\n * OUT assertions: the fields len and code are set to the optimal bit length\n *     and corresponding code. The length opt_len is updated; static_len is\n *     also updated if stree is not null. The field max_code is set.\n */\nfunction build_tree(s, desc)\n//    deflate_state *s;\n//    tree_desc *desc; /* the tree descriptor */\n{\n  var tree     = desc.dyn_tree;\n  var stree    = desc.stat_desc.static_tree;\n  var has_stree = desc.stat_desc.has_stree;\n  var elems    = desc.stat_desc.elems;\n  var n, m;          /* iterate over heap elements */\n  var max_code = -1; /* largest code with non zero frequency */\n  var node;          /* new node being created */\n\n  /* Construct the initial heap, with least frequent element in\n   * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].\n   * heap[0] is not used.\n   */\n  s.heap_len = 0;\n  s.heap_max = HEAP_SIZE;\n\n  for (n = 0; n < elems; n++) {\n    if (tree[n * 2]/*.Freq*/ !== 0) {\n      s.heap[++s.heap_len] = max_code = n;\n      s.depth[n] = 0;\n\n    } else {\n      tree[n*2 + 1]/*.Len*/ = 0;\n    }\n  }\n\n  /* The pkzip format requires that at least one distance code exists,\n   * and that at least one bit should be sent even if there is only one\n   * possible code. So to avoid special checks later on we force at least\n   * two codes of non zero frequency.\n   */\n  while (s.heap_len < 2) {\n    node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);\n    tree[node * 2]/*.Freq*/ = 1;\n    s.depth[node] = 0;\n    s.opt_len--;\n\n    if (has_stree) {\n      s.static_len -= stree[node*2 + 1]/*.Len*/;\n    }\n    /* node is 0 or 1 so it does not have extra bits */\n  }\n  desc.max_code = max_code;\n\n  /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,\n   * establish sub-heaps of increasing lengths:\n   */\n  for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); }\n\n  /* Construct the Huffman tree by repeatedly combining the least two\n   * frequent nodes.\n   */\n  node = elems;              /* next internal node of the tree */\n  do {\n    //pqremove(s, tree, n);  /* n = node of least frequency */\n    /*** pqremove ***/\n    n = s.heap[1/*SMALLEST*/];\n    s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];\n    pqdownheap(s, tree, 1/*SMALLEST*/);\n    /***/\n\n    m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */\n\n    s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */\n    s.heap[--s.heap_max] = m;\n\n    /* Create a new node father of n and m */\n    tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;\n    s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;\n    tree[n*2 + 1]/*.Dad*/ = tree[m*2 + 1]/*.Dad*/ = node;\n\n    /* and insert the new node in the heap */\n    s.heap[1/*SMALLEST*/] = node++;\n    pqdownheap(s, tree, 1/*SMALLEST*/);\n\n  } while (s.heap_len >= 2);\n\n  s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];\n\n  /* At this point, the fields freq and dad are set. We can now\n   * generate the bit lengths.\n   */\n  gen_bitlen(s, desc);\n\n  /* The field len is now set, we can generate the bit codes */\n  gen_codes(tree, max_code, s.bl_count);\n}\n\n\n/* ===========================================================================\n * Scan a literal or distance tree to determine the frequencies of the codes\n * in the bit length tree.\n */\nfunction scan_tree(s, tree, max_code)\n//    deflate_state *s;\n//    ct_data *tree;   /* the tree to be scanned */\n//    int max_code;    /* and its largest code of non zero frequency */\n{\n  var n;                     /* iterates over all tree elements */\n  var prevlen = -1;          /* last emitted length */\n  var curlen;                /* length of current code */\n\n  var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */\n\n  var count = 0;             /* repeat count of the current code */\n  var max_count = 7;         /* max repeat count */\n  var min_count = 4;         /* min repeat count */\n\n  if (nextlen === 0) {\n    max_count = 138;\n    min_count = 3;\n  }\n  tree[(max_code+1)*2 + 1]/*.Len*/ = 0xffff; /* guard */\n\n  for (n = 0; n <= max_code; n++) {\n    curlen = nextlen;\n    nextlen = tree[(n+1)*2 + 1]/*.Len*/;\n\n    if (++count < max_count && curlen === nextlen) {\n      continue;\n\n    } else if (count < min_count) {\n      s.bl_tree[curlen * 2]/*.Freq*/ += count;\n\n    } else if (curlen !== 0) {\n\n      if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; }\n      s.bl_tree[REP_3_6*2]/*.Freq*/++;\n\n    } else if (count <= 10) {\n      s.bl_tree[REPZ_3_10*2]/*.Freq*/++;\n\n    } else {\n      s.bl_tree[REPZ_11_138*2]/*.Freq*/++;\n    }\n\n    count = 0;\n    prevlen = curlen;\n\n    if (nextlen === 0) {\n      max_count = 138;\n      min_count = 3;\n\n    } else if (curlen === nextlen) {\n      max_count = 6;\n      min_count = 3;\n\n    } else {\n      max_count = 7;\n      min_count = 4;\n    }\n  }\n}\n\n\n/* ===========================================================================\n * Send a literal or distance tree in compressed form, using the codes in\n * bl_tree.\n */\nfunction send_tree(s, tree, max_code)\n//    deflate_state *s;\n//    ct_data *tree; /* the tree to be scanned */\n//    int max_code;       /* and its largest code of non zero frequency */\n{\n  var n;                     /* iterates over all tree elements */\n  var prevlen = -1;          /* last emitted length */\n  var curlen;                /* length of current code */\n\n  var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */\n\n  var count = 0;             /* repeat count of the current code */\n  var max_count = 7;         /* max repeat count */\n  var min_count = 4;         /* min repeat count */\n\n  /* tree[max_code+1].Len = -1; */  /* guard already set */\n  if (nextlen === 0) {\n    max_count = 138;\n    min_count = 3;\n  }\n\n  for (n = 0; n <= max_code; n++) {\n    curlen = nextlen;\n    nextlen = tree[(n+1)*2 + 1]/*.Len*/;\n\n    if (++count < max_count && curlen === nextlen) {\n      continue;\n\n    } else if (count < min_count) {\n      do { send_code(s, curlen, s.bl_tree); } while (--count !== 0);\n\n    } else if (curlen !== 0) {\n      if (curlen !== prevlen) {\n        send_code(s, curlen, s.bl_tree);\n        count--;\n      }\n      //Assert(count >= 3 && count <= 6, \" 3_6?\");\n      send_code(s, REP_3_6, s.bl_tree);\n      send_bits(s, count-3, 2);\n\n    } else if (count <= 10) {\n      send_code(s, REPZ_3_10, s.bl_tree);\n      send_bits(s, count-3, 3);\n\n    } else {\n      send_code(s, REPZ_11_138, s.bl_tree);\n      send_bits(s, count-11, 7);\n    }\n\n    count = 0;\n    prevlen = curlen;\n    if (nextlen === 0) {\n      max_count = 138;\n      min_count = 3;\n\n    } else if (curlen === nextlen) {\n      max_count = 6;\n      min_count = 3;\n\n    } else {\n      max_count = 7;\n      min_count = 4;\n    }\n  }\n}\n\n\n/* ===========================================================================\n * Construct the Huffman tree for the bit lengths and return the index in\n * bl_order of the last bit length code to send.\n */\nfunction build_bl_tree(s) {\n  var max_blindex;  /* index of last bit length code of non zero freq */\n\n  /* Determine the bit length frequencies for literal and distance trees */\n  scan_tree(s, s.dyn_ltree, s.l_desc.max_code);\n  scan_tree(s, s.dyn_dtree, s.d_desc.max_code);\n\n  /* Build the bit length tree: */\n  build_tree(s, s.bl_desc);\n  /* opt_len now includes the length of the tree representations, except\n   * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.\n   */\n\n  /* Determine the number of bit length codes to send. The pkzip format\n   * requires that at least 4 bit length codes be sent. (appnote.txt says\n   * 3 but the actual value used is 4.)\n   */\n  for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {\n    if (s.bl_tree[bl_order[max_blindex]*2 + 1]/*.Len*/ !== 0) {\n      break;\n    }\n  }\n  /* Update opt_len to include the bit length tree and counts */\n  s.opt_len += 3*(max_blindex+1) + 5+5+4;\n  //Tracev((stderr, \"\\ndyn trees: dyn %ld, stat %ld\",\n  //        s->opt_len, s->static_len));\n\n  return max_blindex;\n}\n\n\n/* ===========================================================================\n * Send the header for a block using dynamic Huffman trees: the counts, the\n * lengths of the bit length codes, the literal tree and the distance tree.\n * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.\n */\nfunction send_all_trees(s, lcodes, dcodes, blcodes)\n//    deflate_state *s;\n//    int lcodes, dcodes, blcodes; /* number of codes for each tree */\n{\n  var rank;                    /* index in bl_order */\n\n  //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, \"not enough codes\");\n  //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,\n  //        \"too many codes\");\n  //Tracev((stderr, \"\\nbl counts: \"));\n  send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */\n  send_bits(s, dcodes-1,   5);\n  send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */\n  for (rank = 0; rank < blcodes; rank++) {\n    //Tracev((stderr, \"\\nbl code %2d \", bl_order[rank]));\n    send_bits(s, s.bl_tree[bl_order[rank]*2 + 1]/*.Len*/, 3);\n  }\n  //Tracev((stderr, \"\\nbl tree: sent %ld\", s->bits_sent));\n\n  send_tree(s, s.dyn_ltree, lcodes-1); /* literal tree */\n  //Tracev((stderr, \"\\nlit tree: sent %ld\", s->bits_sent));\n\n  send_tree(s, s.dyn_dtree, dcodes-1); /* distance tree */\n  //Tracev((stderr, \"\\ndist tree: sent %ld\", s->bits_sent));\n}\n\n\n/* ===========================================================================\n * Check if the data type is TEXT or BINARY, using the following algorithm:\n * - TEXT if the two conditions below are satisfied:\n *    a) There are no non-portable control characters belonging to the\n *       \"black list\" (0..6, 14..25, 28..31).\n *    b) There is at least one printable character belonging to the\n *       \"white list\" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).\n * - BINARY otherwise.\n * - The following partially-portable control characters form a\n *   \"gray list\" that is ignored in this detection algorithm:\n *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).\n * IN assertion: the fields Freq of dyn_ltree are set.\n */\nfunction detect_data_type(s) {\n  /* black_mask is the bit mask of black-listed bytes\n   * set bits 0..6, 14..25, and 28..31\n   * 0xf3ffc07f = binary 11110011111111111100000001111111\n   */\n  var black_mask = 0xf3ffc07f;\n  var n;\n\n  /* Check for non-textual (\"black-listed\") bytes. */\n  for (n = 0; n <= 31; n++, black_mask >>>= 1) {\n    if ((black_mask & 1) && (s.dyn_ltree[n*2]/*.Freq*/ !== 0)) {\n      return Z_BINARY;\n    }\n  }\n\n  /* Check for textual (\"white-listed\") bytes. */\n  if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||\n      s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {\n    return Z_TEXT;\n  }\n  for (n = 32; n < LITERALS; n++) {\n    if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {\n      return Z_TEXT;\n    }\n  }\n\n  /* There are no \"black-listed\" or \"white-listed\" bytes:\n   * this stream either is empty or has tolerated (\"gray-listed\") bytes only.\n   */\n  return Z_BINARY;\n}\n\n\nvar static_init_done = false;\n\n/* ===========================================================================\n * Initialize the tree data structures for a new zlib stream.\n */\nfunction _tr_init(s)\n{\n\n  if (!static_init_done) {\n    tr_static_init();\n    static_init_done = true;\n  }\n\n  s.l_desc  = new TreeDesc(s.dyn_ltree, static_l_desc);\n  s.d_desc  = new TreeDesc(s.dyn_dtree, static_d_desc);\n  s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);\n\n  s.bi_buf = 0;\n  s.bi_valid = 0;\n\n  /* Initialize the first block of the first file: */\n  init_block(s);\n}\n\n\n/* ===========================================================================\n * Send a stored block\n */\nfunction _tr_stored_block(s, buf, stored_len, last)\n//DeflateState *s;\n//charf *buf;       /* input block */\n//ulg stored_len;   /* length of input block */\n//int last;         /* one if this is the last block for a file */\n{\n  send_bits(s, (STORED_BLOCK<<1)+(last ? 1 : 0), 3);    /* send block type */\n  copy_block(s, buf, stored_len, true); /* with header */\n}\n\n\n/* ===========================================================================\n * Send one empty static block to give enough lookahead for inflate.\n * This takes 10 bits, of which 7 may remain in the bit buffer.\n */\nfunction _tr_align(s) {\n  send_bits(s, STATIC_TREES<<1, 3);\n  send_code(s, END_BLOCK, static_ltree);\n  bi_flush(s);\n}\n\n\n/* ===========================================================================\n * Determine the best encoding for the current block: dynamic trees, static\n * trees or store, and output the encoded block to the zip file.\n */\nfunction _tr_flush_block(s, buf, stored_len, last)\n//DeflateState *s;\n//charf *buf;       /* input block, or NULL if too old */\n//ulg stored_len;   /* length of input block */\n//int last;         /* one if this is the last block for a file */\n{\n  var opt_lenb, static_lenb;  /* opt_len and static_len in bytes */\n  var max_blindex = 0;        /* index of last bit length code of non zero freq */\n\n  /* Build the Huffman trees unless a stored block is forced */\n  if (s.level > 0) {\n\n    /* Check if the file is binary or text */\n    if (s.strm.data_type === Z_UNKNOWN) {\n      s.strm.data_type = detect_data_type(s);\n    }\n\n    /* Construct the literal and distance trees */\n    build_tree(s, s.l_desc);\n    // Tracev((stderr, \"\\nlit data: dyn %ld, stat %ld\", s->opt_len,\n    //        s->static_len));\n\n    build_tree(s, s.d_desc);\n    // Tracev((stderr, \"\\ndist data: dyn %ld, stat %ld\", s->opt_len,\n    //        s->static_len));\n    /* At this point, opt_len and static_len are the total bit lengths of\n     * the compressed block data, excluding the tree representations.\n     */\n\n    /* Build the bit length tree for the above two trees, and get the index\n     * in bl_order of the last bit length code to send.\n     */\n    max_blindex = build_bl_tree(s);\n\n    /* Determine the best encoding. Compute the block lengths in bytes. */\n    opt_lenb = (s.opt_len+3+7) >>> 3;\n    static_lenb = (s.static_len+3+7) >>> 3;\n\n    // Tracev((stderr, \"\\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u \",\n    //        opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,\n    //        s->last_lit));\n\n    if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; }\n\n  } else {\n    // Assert(buf != (char*)0, \"lost buf\");\n    opt_lenb = static_lenb = stored_len + 5; /* force a stored block */\n  }\n\n  if ((stored_len+4 <= opt_lenb) && (buf !== -1)) {\n    /* 4: two words for the lengths */\n\n    /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.\n     * Otherwise we can't have processed more than WSIZE input bytes since\n     * the last block flush, because compression would have been\n     * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to\n     * transform a block into a stored block.\n     */\n    _tr_stored_block(s, buf, stored_len, last);\n\n  } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) {\n\n    send_bits(s, (STATIC_TREES<<1) + (last ? 1 : 0), 3);\n    compress_block(s, static_ltree, static_dtree);\n\n  } else {\n    send_bits(s, (DYN_TREES<<1) + (last ? 1 : 0), 3);\n    send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1, max_blindex+1);\n    compress_block(s, s.dyn_ltree, s.dyn_dtree);\n  }\n  // Assert (s->compressed_len == s->bits_sent, \"bad compressed size\");\n  /* The above check is made mod 2^32, for files larger than 512 MB\n   * and uLong implemented on 32 bits.\n   */\n  init_block(s);\n\n  if (last) {\n    bi_windup(s);\n  }\n  // Tracev((stderr,\"\\ncomprlen %lu(%lu) \", s->compressed_len>>3,\n  //       s->compressed_len-7*last));\n}\n\n/* ===========================================================================\n * Save the match info and tally the frequency counts. Return true if\n * the current block must be flushed.\n */\nfunction _tr_tally(s, dist, lc)\n//    deflate_state *s;\n//    unsigned dist;  /* distance of matched string */\n//    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */\n{\n  //var out_length, in_length, dcode;\n\n  s.pending_buf[s.d_buf + s.last_lit * 2]     = (dist >>> 8) & 0xff;\n  s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff;\n\n  s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff;\n  s.last_lit++;\n\n  if (dist === 0) {\n    /* lc is the unmatched char */\n    s.dyn_ltree[lc*2]/*.Freq*/++;\n  } else {\n    s.matches++;\n    /* Here, lc is the match length - MIN_MATCH */\n    dist--;             /* dist = match distance - 1 */\n    //Assert((ush)dist < (ush)MAX_DIST(s) &&\n    //       (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&\n    //       (ush)d_code(dist) < (ush)D_CODES,  \"_tr_tally: bad match\");\n\n    s.dyn_ltree[(_length_code[lc]+LITERALS+1) * 2]/*.Freq*/++;\n    s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;\n  }\n\n// (!) This block is disabled in zlib defailts,\n// don't enable it for binary compatibility\n\n//#ifdef TRUNCATE_BLOCK\n//  /* Try to guess if it is profitable to stop the current block here */\n//  if ((s.last_lit & 0x1fff) === 0 && s.level > 2) {\n//    /* Compute an upper bound for the compressed length */\n//    out_length = s.last_lit*8;\n//    in_length = s.strstart - s.block_start;\n//\n//    for (dcode = 0; dcode < D_CODES; dcode++) {\n//      out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]);\n//    }\n//    out_length >>>= 3;\n//    //Tracev((stderr,\"\\nlast_lit %u, in %ld, out ~%ld(%ld%%) \",\n//    //       s->last_lit, in_length, out_length,\n//    //       100L - out_length*100L/in_length));\n//    if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) {\n//      return true;\n//    }\n//  }\n//#endif\n\n  return (s.last_lit === s.lit_bufsize-1);\n  /* We avoid equality with lit_bufsize because of wraparound at 64K\n   * on 16 bit machines and because stored blocks are restricted to\n   * 64K-1 bytes.\n   */\n}\n\nexports._tr_init  = _tr_init;\nexports._tr_stored_block = _tr_stored_block;\nexports._tr_flush_block  = _tr_flush_block;\nexports._tr_tally = _tr_tally;\nexports._tr_align = _tr_align;\n},{\"../utils/common\":27}],39:[function(_dereq_,module,exports){\n'use strict';\n\n\nfunction ZStream() {\n  /* next input byte */\n  this.input = null; // JS specific, because we have no pointers\n  this.next_in = 0;\n  /* number of bytes available at input */\n  this.avail_in = 0;\n  /* total number of input bytes read so far */\n  this.total_in = 0;\n  /* next output byte should be put there */\n  this.output = null; // JS specific, because we have no pointers\n  this.next_out = 0;\n  /* remaining free space at output */\n  this.avail_out = 0;\n  /* total number of bytes output so far */\n  this.total_out = 0;\n  /* last error message, NULL if no error */\n  this.msg = ''/*Z_NULL*/;\n  /* not visible by applications */\n  this.state = null;\n  /* best guess about the data type: binary or text */\n  this.data_type = 2/*Z_UNKNOWN*/;\n  /* adler32 value of the uncompressed data */\n  this.adler = 0;\n}\n\nmodule.exports = ZStream;\n},{}]},{},[9])\n(9)\n});"
  },
  {
    "path": "static/js/DataTables/KeyTable-2.5.0/css/keyTable.bootstrap.css",
    "content": "table.dataTable tbody th.focus,\ntable.dataTable tbody td.focus {\n  box-shadow: inset 0 0 1px 2px #337ab7;\n}\n\ndiv.dtk-focus-alt table.dataTable tbody th.focus,\ndiv.dtk-focus-alt table.dataTable tbody td.focus {\n  box-shadow: inset 0 0 1px 2px #ff8b33;\n}\n"
  },
  {
    "path": "static/js/DataTables/KeyTable-2.5.0/css/keyTable.bootstrap4.css",
    "content": "table.dataTable tbody th.focus,\ntable.dataTable tbody td.focus {\n  box-shadow: inset 0 0 1px 2px #0275d8;\n}\n\ndiv.dtk-focus-alt table.dataTable tbody th.focus,\ndiv.dtk-focus-alt table.dataTable tbody td.focus {\n  box-shadow: inset 0 0 1px 2px #ff8b33;\n}\n"
  },
  {
    "path": "static/js/DataTables/KeyTable-2.5.0/css/keyTable.dataTables.css",
    "content": "table.dataTable tbody th.focus,\ntable.dataTable tbody td.focus {\n  box-shadow: inset 0 0 1px 2px #3366ff;\n}\n\ndiv.dtk-focus-alt table.dataTable tbody th.focus,\ndiv.dtk-focus-alt table.dataTable tbody td.focus {\n  box-shadow: inset 0 0 1px 2px #ff8b33;\n}\n"
  },
  {
    "path": "static/js/DataTables/KeyTable-2.5.0/css/keyTable.foundation.css",
    "content": "table.dataTable tbody th.focus,\ntable.dataTable tbody td.focus {\n  box-shadow: inset 0 0 1px 2px #008CBA;\n}\n\ndiv.dtk-focus-alt table.dataTable tbody th.focus,\ndiv.dtk-focus-alt table.dataTable tbody td.focus {\n  box-shadow: inset 0 0 1px 2px #ff8b33;\n}\n"
  },
  {
    "path": "static/js/DataTables/KeyTable-2.5.0/css/keyTable.jqueryui.css",
    "content": "table.dataTable tbody th.focus,\ntable.dataTable tbody td.focus {\n  box-shadow: inset 0 0 1px 2px #3366ff;\n}\n\ndiv.dtk-focus-alt table.dataTable tbody th.focus,\ndiv.dtk-focus-alt table.dataTable tbody td.focus {\n  box-shadow: inset 0 0 1px 2px #ff8b33;\n}\n"
  },
  {
    "path": "static/js/DataTables/KeyTable-2.5.0/css/keyTable.semanticui.css",
    "content": "table.dataTable tbody th.focus,\ntable.dataTable tbody td.focus {\n  box-shadow: inset 0 0 1px 2px #888;\n}\n\ndiv.dtk-focus-alt table.dataTable tbody th.focus,\ndiv.dtk-focus-alt table.dataTable tbody td.focus {\n  box-shadow: inset 0 0 1px 2px #ff8b33;\n}\n"
  },
  {
    "path": "static/js/DataTables/KeyTable-2.5.0/js/dataTables.keyTable.js",
    "content": "/*! KeyTable 2.5.0\n * ©2009-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     KeyTable\n * @description Spreadsheet like keyboard navigation for DataTables\n * @version     2.5.0\n * @file        dataTables.keyTable.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2009-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar KeyTable = function ( dt, opts ) {\n\t// Sanity check that we are using DataTables 1.10 or newer\n\tif ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {\n\t\tthrow 'KeyTable requires DataTables 1.10.8 or newer';\n\t}\n\n\t// User and defaults configuration object\n\tthis.c = $.extend( true, {},\n\t\tDataTable.defaults.keyTable,\n\t\tKeyTable.defaults,\n\t\topts\n\t);\n\n\t// Internal settings\n\tthis.s = {\n\t\t/** @type {DataTable.Api} DataTables' API instance */\n\t\tdt: new DataTable.Api( dt ),\n\n\t\tenable: true,\n\n\t\t/** @type {bool} Flag for if a draw is triggered by focus */\n\t\tfocusDraw: false,\n\n\t\t/** @type {bool} Flag to indicate when waiting for a draw to happen.\n\t\t  *   Will ignore key presses at this point\n\t\t  */\n\t\twaitingForDraw: false,\n\n\t\t/** @type {object} Information about the last cell that was focused */\n\t\tlastFocus: null\n\t};\n\n\t// DOM items\n\tthis.dom = {\n\n\t};\n\n\t// Check if row reorder has already been initialised on this table\n\tvar settings = this.s.dt.settings()[0];\n\tvar exisiting = settings.keytable;\n\tif ( exisiting ) {\n\t\treturn exisiting;\n\t}\n\n\tsettings.keytable = this;\n\tthis._constructor();\n};\n\n\n$.extend( KeyTable.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * API methods for DataTables API interface\n\t */\n\n\t/**\n\t * Blur the table's cell focus\n\t */\n\tblur: function ()\n\t{\n\t\tthis._blur();\n\t},\n\n\t/**\n\t * Enable cell focus for the table\n\t *\n\t * @param  {string} state Can be `true`, `false` or `-string navigation-only`\n\t */\n\tenable: function ( state )\n\t{\n\t\tthis.s.enable = state;\n\t},\n\n\t/**\n\t * Focus on a cell\n\t * @param  {integer} row    Row index\n\t * @param  {integer} column Column index\n\t */\n\tfocus: function ( row, column )\n\t{\n\t\tthis._focus( this.s.dt.cell( row, column ) );\n\t},\n\n\t/**\n\t * Is the cell focused\n\t * @param  {object} cell Cell index to check\n\t * @returns {boolean} true if focused, false otherwise\n\t */\n\tfocused: function ( cell )\n\t{\n\t\tvar lastFocus = this.s.lastFocus;\n\n\t\tif ( ! lastFocus ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tvar lastIdx = this.s.lastFocus.cell.index();\n\t\treturn cell.row === lastIdx.row && cell.column === lastIdx.column;\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\n\t/**\n\t * Initialise the KeyTable instance\n\t *\n\t * @private\n\t */\n\t_constructor: function ()\n\t{\n\t\tthis._tabInput();\n\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar table = $( dt.table().node() );\n\n\t\t// Need to be able to calculate the cell positions relative to the table\n\t\tif ( table.css('position') === 'static' ) {\n\t\t\ttable.css( 'position', 'relative' );\n\t\t}\n\n\t\t// Click to focus\n\t\t$( dt.table().body() ).on( 'click.keyTable', 'th, td', function (e) {\n\t\t\tif ( that.s.enable === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar cell = dt.cell( this );\n\n\t\t\tif ( ! cell.any() ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthat._focus( cell, null, false, e );\n\t\t} );\n\n\t\t// Key events\n\t\t$( document ).on( 'keydown.keyTable', function (e) {\n\t\t\tthat._key( e );\n\t\t} );\n\n\t\t// Click blur\n\t\tif ( this.c.blurable ) {\n\t\t\t$( document ).on( 'mousedown.keyTable', function ( e ) {\n\t\t\t\t// Click on the search input will blur focus\n\t\t\t\tif ( $(e.target).parents( '.dataTables_filter' ).length ) {\n\t\t\t\t\tthat._blur();\n\t\t\t\t}\n\n\t\t\t\t// If the click was inside the DataTables container, don't blur\n\t\t\t\tif ( $(e.target).parents().filter( dt.table().container() ).length ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Don't blur in Editor form\n\t\t\t\tif ( $(e.target).parents('div.DTE').length ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Or an Editor date input\n\t\t\t\tif ( $(e.target).parents('div.editor-datetime').length ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t//If the click was inside the fixed columns container, don't blur\n\t\t\t\tif ( $(e.target).parents().filter('.DTFC_Cloned').length ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthat._blur();\n\t\t\t} );\n\t\t}\n\n\t\tif ( this.c.editor ) {\n\t\t\tvar editor = this.c.editor;\n\n\t\t\t// Need to disable KeyTable when the main editor is shown\n\t\t\teditor.on( 'open.keyTableMain', function (e, mode, action) {\n\t\t\t\tif ( mode !== 'inline' && that.s.enable ) {\n\t\t\t\t\tthat.enable( false );\n\n\t\t\t\t\teditor.one( 'close.keyTable', function () {\n\t\t\t\t\t\tthat.enable( true );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tif ( this.c.editOnFocus ) {\n\t\t\t\tdt.on( 'key-focus.keyTable key-refocus.keyTable', function ( e, dt, cell, orig ) {\n\t\t\t\t\tthat._editor( null, orig, true );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// Activate Editor when a key is pressed (will be ignored, if\n\t\t\t// already active).\n\t\t\tdt.on( 'key.keyTable', function ( e, dt, key, cell, orig ) {\n\t\t\t\tthat._editor( key, orig, false );\n\t\t\t} );\n\n\t\t\t// Active editing on double click - it will already have focus from\n\t\t\t// the click event handler above\n\t\t\t$( dt.table().body() ).on( 'dblclick.keyTable', 'th, td', function (e) {\n\t\t\t\tif ( that.s.enable === false ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar cell = dt.cell( this );\n\n\t\t\t\tif ( ! cell.any() ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthat._editor( null, e, true );\n\t\t\t} );\n\t\t}\n\n\t\t// Stave saving\n\t\tif ( dt.settings()[0].oFeatures.bStateSave ) {\n\t\t\tdt.on( 'stateSaveParams.keyTable', function (e, s, d) {\n\t\t\t\td.keyTable = that.s.lastFocus ?\n\t\t\t\t\tthat.s.lastFocus.cell.index() :\n\t\t\t\t\tnull;\n\t\t\t} );\n\t\t}\n\n\t\t// Redraw - retain focus on the current cell\n\t\tdt.on( 'draw.keyTable', function (e) {\n\t\t\tif ( that.s.focusDraw ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar lastFocus = that.s.lastFocus;\n\n\t\t\tif ( lastFocus && lastFocus.node && $(lastFocus.node).closest('body') === document.body ) {\n\t\t\t\tvar relative = that.s.lastFocus.relative;\n\t\t\t\tvar info = dt.page.info();\n\t\t\t\tvar row = relative.row + info.start;\n\n\t\t\t\tif ( info.recordsDisplay === 0 ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Reverse if needed\n\t\t\t\tif ( row >= info.recordsDisplay ) {\n\t\t\t\t\trow = info.recordsDisplay - 1;\n\t\t\t\t}\n\n\t\t\t\tthat._focus( row, relative.column, true, e );\n\t\t\t}\n\t\t} );\n\n\t\t// Clipboard support\n\t\tif ( this.c.clipboard ) {\n\t\t\tthis._clipboard();\n\t\t}\n\n\t\tdt.on( 'destroy.keyTable', function () {\n\t\t\tdt.off( '.keyTable' );\n\t\t\t$( dt.table().body() ).off( 'click.keyTable', 'th, td' );\n\t\t\t$( document )\n\t\t\t\t.off( 'keydown.keyTable' )\n\t\t\t\t.off( 'click.keyTable' )\n\t\t\t\t.off( 'copy.keyTable' )\n\t\t\t\t.off( 'paste.keyTable' );\n\t\t} );\n\n\t\t// Initial focus comes from state or options\n\t\tvar state = dt.state.loaded();\n\n\t\tif ( state && state.keyTable ) {\n\t\t\t// Wait until init is done\n\t\t\tdt.one( 'init', function () {\n\t\t\t\tvar cell = dt.cell( state.keyTable );\n\n\t\t\t\t// Ensure that the saved cell still exists\n\t\t\t\tif ( cell.any() ) {\n\t\t\t\t\tcell.focus();\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\telse if ( this.c.focus ) {\n\t\t\tdt.cell( this.c.focus ).focus();\n\t\t}\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\n\t/**\n\t * Blur the control\n\t *\n\t * @private\n\t */\n\t_blur: function ()\n\t{\n\t\tif ( ! this.s.enable || ! this.s.lastFocus ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar cell = this.s.lastFocus.cell;\n\n\t\t$( cell.node() ).removeClass( this.c.className );\n\t\tthis.s.lastFocus = null;\n\n\t\tthis._updateFixedColumns(cell.index().column);\n\n\t\tthis._emitEvent( 'key-blur', [ this.s.dt, cell ] );\n\t},\n\n\n\t/**\n\t * Clipboard interaction handlers\n\t *\n\t * @private\n\t */\n\t_clipboard: function () {\n\t\tvar dt = this.s.dt;\n\t\tvar that = this;\n\n\t\t// IE8 doesn't support getting selected text\n\t\tif ( ! window.getSelection ) {\n\t\t\treturn;\n\t\t}\n\n\t\t$(document).on( 'copy.keyTable', function (ejq) {\n\t\t\tvar e = ejq.originalEvent;\n\t\t\tvar selection = window.getSelection().toString();\n\t\t\tvar focused = that.s.lastFocus;\n\n\t\t\t// Only copy cell text to clipboard if there is no other selection\n\t\t\t// and there is a focused cell\n\t\t\tif ( ! selection && focused ) {\n\t\t\t\te.clipboardData.setData(\n\t\t\t\t\t'text/plain',\n\t\t\t\t\tfocused.cell.render( that.c.clipboardOrthogonal )\n\t\t\t\t);\n\t\t\t\te.preventDefault();\n\t\t\t}\n\t\t} );\n\n\t\t$(document).on( 'paste.keyTable', function (ejq) {\n\t\t\tvar e = ejq.originalEvent;\n\t\t\tvar focused = that.s.lastFocus;\n\t\t\tvar activeEl = document.activeElement;\n\t\t\tvar editor = that.c.editor;\n\t\t\tvar pastedText;\n\n\t\t\tif ( focused && (! activeEl || activeEl.nodeName.toLowerCase() === 'body') ) {\n\t\t\t\te.preventDefault();\n\n\t\t\t\tif ( window.clipboardData && window.clipboardData.getData ) {\n\t\t\t\t\t// IE\n\t\t\t\t\tpastedText = window.clipboardData.getData('Text');\n\t\t\t\t}\n\t\t\t\telse if ( e.clipboardData && e.clipboardData.getData ) {\n\t\t\t\t\t// Everything else\n\t\t\t\t\tpastedText = e.clipboardData.getData('text/plain');\n\t\t\t\t}\n\n\t\t\t\tif ( editor ) {\n\t\t\t\t\t// Got Editor - need to activate inline editing,\n\t\t\t\t\t// set the value and submit\n\t\t\t\t\teditor\n\t\t\t\t\t\t.inline( focused.cell.index() )\n\t\t\t\t\t\t.set( editor.displayed()[0], pastedText )\n\t\t\t\t\t\t.submit();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// No editor, so just dump the data in\n\t\t\t\t\tfocused.cell.data( pastedText );\n\t\t\t\t\tdt.draw(false);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\n\t/**\n\t * Get an array of the column indexes that KeyTable can operate on. This\n\t * is a merge of the user supplied columns and the visible columns.\n\t *\n\t * @private\n\t */\n\t_columns: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar user = dt.columns( this.c.columns ).indexes();\n\t\tvar out = [];\n\n\t\tdt.columns( ':visible' ).every( function (i) {\n\t\t\tif ( user.indexOf( i ) !== -1 ) {\n\t\t\t\tout.push( i );\n\t\t\t}\n\t\t} );\n\n\t\treturn out;\n\t},\n\n\n\t/**\n\t * Perform excel like navigation for Editor by triggering an edit on key\n\t * press\n\t *\n\t * @param  {integer} key Key code for the pressed key\n\t * @param  {object} orig Original event\n\t * @private\n\t */\n\t_editor: function ( key, orig, hardEdit )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar editor = this.c.editor;\n\t\tvar editCell = this.s.lastFocus.cell;\n\n\t\t// Do nothing if there is already an inline edit in this cell\n\t\tif ( $('div.DTE', editCell.node()).length ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Don't activate Editor on control key presses\n\t\tif ( key !== null && (\n\t\t\t(key >= 0x00 && key <= 0x09) ||\n\t\t\tkey === 0x0b ||\n\t\t\tkey === 0x0c ||\n\t\t\t(key >= 0x0e && key <= 0x1f) ||\n\t\t\t(key >= 0x70 && key <= 0x7b) ||\n\t\t\t(key >= 0x7f && key <= 0x9f)\n\t\t) ) {\n\t\t\treturn;\n\t\t}\n\n\t\torig.stopPropagation();\n\n\t\t// Return key should do nothing - for textareas it would empty the\n\t\t// contents\n\t\tif ( key === 13 ) {\n\t\t\torig.preventDefault();\n\t\t}\n\n\t\tvar editInline = function () {\n\t\t\teditor\n\t\t\t\t.one( 'open.keyTable', function () {\n\t\t\t\t\t// Remove cancel open\n\t\t\t\t\teditor.off( 'cancelOpen.keyTable' );\n\n\t\t\t\t\t// Excel style - select all text\n\t\t\t\t\tif ( ! hardEdit ) {\n\t\t\t\t\t\t$('div.DTE_Field_InputControl input, div.DTE_Field_InputControl textarea').select();\n\t\t\t\t\t}\n\n\t\t\t\t\t// Reduce the keys the Keys listens for\n\t\t\t\t\tdt.keys.enable( hardEdit ? 'tab-only' : 'navigation-only' );\n\n\t\t\t\t\t// On blur of the navigation submit\n\t\t\t\t\tdt.on( 'key-blur.editor', function () {\n\t\t\t\t\t\tif ( editor.displayed() ) {\n\t\t\t\t\t\t\teditor.submit();\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\n\t\t\t\t\t// Highlight the cell a different colour on full edit\n\t\t\t\t\tif ( hardEdit ) {\n\t\t\t\t\t\t$( dt.table().container() ).addClass('dtk-focus-alt');\n\t\t\t\t\t}\n\n\t\t\t\t\teditor.on( 'submitUnsuccessful.keyTable', function () {\n\t\t\t\t\t\tthat._focus( editCell, null, false );\n\t\t\t\t\t} );\n\n\t\t\t\t\t// Restore full key navigation on close\n\t\t\t\t\teditor.one( 'close', function () {\n\t\t\t\t\t\tdt.keys.enable( true );\n\t\t\t\t\t\tdt.off( 'key-blur.editor' );\n\t\t\t\t\t\teditor.off( '.keyTable' );\n\t\t\t\t\t\t$( dt.table().container() ).removeClass('dtk-focus-alt');\n\t\t\t\t\t} );\n\t\t\t\t} )\n\t\t\t\t.one( 'cancelOpen.keyTable', function () {\n\t\t\t\t\t// `preOpen` can cancel the display of the form, so it\n\t\t\t\t\t// might be that the open event handler isn't needed\n\t\t\t\t\teditor.off( '.keyTable' );\n\t\t\t\t} )\n\t\t\t\t.inline( editCell.index() );\n\t\t};\n\n\t\t// Editor 1.7 listens for `return` on keyup, so if return is the trigger\n\t\t// key, we need to wait for `keyup` otherwise Editor would just submit\n\t\t// the content triggered by this keypress.\n\t\tif ( key === 13 ) {\n\t\t\thardEdit = true;\n\n\t\t\t$(document).one( 'keyup', function () { // immediately removed\n\t\t\t\teditInline();\n\t\t\t} );\n\t\t}\n\t\telse {\n\t\t\teditInline();\n\t\t}\n\t},\n\n\n\t/**\n\t * Emit an event on the DataTable for listeners\n\t *\n\t * @param  {string} name Event name\n\t * @param  {array} args Event arguments\n\t * @private\n\t */\n\t_emitEvent: function ( name, args )\n\t{\n\t\tthis.s.dt.iterator( 'table', function ( ctx, i ) {\n\t\t\t$(ctx.nTable).triggerHandler( name, args );\n\t\t} );\n\t},\n\n\n\t/**\n\t * Focus on a particular cell, shifting the table's paging if required\n\t *\n\t * @param  {DataTables.Api|integer} row Can be given as an API instance that\n\t *   contains the cell to focus or as an integer. As the latter it is the\n\t *   visible row index (from the whole data set) - NOT the data index\n\t * @param  {integer} [column] Not required if a cell is given as the first\n\t *   parameter. Otherwise this is the column data index for the cell to\n\t *   focus on\n\t * @param {boolean} [shift=true] Should the viewport be moved to show cell\n\t * @private\n\t */\n\t_focus: function ( row, column, shift, originalEvent )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar pageInfo = dt.page.info();\n\t\tvar lastFocus = this.s.lastFocus;\n\n\t\tif ( ! originalEvent) {\n\t\t\toriginalEvent = null;\n\t\t}\n\n\t\tif ( ! this.s.enable ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( typeof row !== 'number' ) {\n\t\t\t// Its an API instance - check that there is actually a row\n\t\t\tif ( ! row.any() ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Convert the cell to a row and column\n\t\t\tvar index = row.index();\n\t\t\tcolumn = index.column;\n\t\t\trow = dt\n\t\t\t\t.rows( { filter: 'applied', order: 'applied' } )\n\t\t\t\t.indexes()\n\t\t\t\t.indexOf( index.row );\n\t\t\t\n\t\t\t// Don't focus rows that were filtered out.\n\t\t\tif ( row < 0 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// For server-side processing normalise the row by adding the start\n\t\t\t// point, since `rows().indexes()` includes only rows that are\n\t\t\t// available at the client-side\n\t\t\tif ( pageInfo.serverSide ) {\n\t\t\t\trow += pageInfo.start;\n\t\t\t}\n\t\t}\n\n\t\t// Is the row on the current page? If not, we need to redraw to show the\n\t\t// page\n\t\tif ( pageInfo.length !== -1 && (row < pageInfo.start || row >= pageInfo.start+pageInfo.length) ) {\n\t\t\tthis.s.focusDraw = true;\n\t\t\tthis.s.waitingForDraw = true;\n\n\t\t\tdt\n\t\t\t\t.one( 'draw', function () {\n\t\t\t\t\tthat.s.focusDraw = false;\n\t\t\t\t\tthat.s.waitingForDraw = false;\n\t\t\t\t\tthat._focus( row, column, undefined, originalEvent );\n\t\t\t\t} )\n\t\t\t\t.page( Math.floor( row / pageInfo.length ) )\n\t\t\t\t.draw( false );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// In the available columns?\n\t\tif ( $.inArray( column, this._columns() ) === -1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// De-normalise the server-side processing row, so we select the row\n\t\t// in its displayed position\n\t\tif ( pageInfo.serverSide ) {\n\t\t\trow -= pageInfo.start;\n\t\t}\n\n\t\t// Get the cell from the current position - ignoring any cells which might\n\t\t// not have been rendered (therefore can't use `:eq()` selector).\n\t\tvar cells = dt.cells( null, column, {search: 'applied', order: 'applied'} ).flatten();\n\t\tvar cell = dt.cell( cells[ row ] );\n\n\t\tif ( lastFocus ) {\n\t\t\t// Don't trigger a refocus on the same cell\n\t\t\tif ( lastFocus.node === cell.node() ) {\n\t\t\t\tthis._emitEvent( 'key-refocus', [ this.s.dt, cell, originalEvent || null ] );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Otherwise blur the old focus\n\t\t\tthis._blur();\n\t\t}\n\n\t\tvar node = $( cell.node() );\n\t\tnode.addClass( this.c.className );\n\n\t\tthis._updateFixedColumns(column);\n\n\t\t// Shift viewpoint and page to make cell visible\n\t\tif ( shift === undefined || shift === true ) {\n\t\t\tthis._scroll( $(window), $(document.body), node, 'offset' );\n\n\t\t\tvar bodyParent = dt.table().body().parentNode;\n\t\t\tif ( bodyParent !== dt.table().header().parentNode ) {\n\t\t\t\tvar parent = $(bodyParent.parentNode);\n\n\t\t\t\tthis._scroll( parent, parent, node, 'position' );\n\t\t\t}\n\t\t}\n\n\t\t// Event and finish\n\t\tthis.s.lastFocus = {\n\t\t\tcell: cell,\n\t\t\tnode: cell.node(),\n\t\t\trelative: {\n\t\t\t\trow: dt.rows( { page: 'current' } ).indexes().indexOf( cell.index().row ),\n\t\t\t\tcolumn: cell.index().column\n\t\t\t}\n\t\t};\n\n\t\tthis._emitEvent( 'key-focus', [ this.s.dt, cell, originalEvent || null ] );\n\t\tdt.state.save();\n\t},\n\n\n\t/**\n\t * Handle key press\n\t *\n\t * @param  {object} e Event\n\t * @private\n\t */\n\t_key: function ( e )\n\t{\n\t\t// If we are waiting for a draw to happen from another key event, then\n\t\t// do nothing for this new key press.\n\t\tif ( this.s.waitingForDraw ) {\n\t\t\te.preventDefault();\n\t\t\treturn;\n\t\t}\n\n\t\tvar enable = this.s.enable;\n\t\tvar navEnable = enable === true || enable === 'navigation-only';\n\t\tif ( ! enable ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( (e.keyCode === 0 || e.ctrlKey || e.metaKey || e.altKey) && !(e.ctrlKey && e.altKey) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If not focused, then there is no key action to take\n\t\tvar lastFocus = this.s.lastFocus;\n\t\tif ( ! lastFocus ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar scrolling = this.s.dt.settings()[0].oScroll.sY ? true : false;\n\n\t\t// If we are not listening for this key, do nothing\n\t\tif ( this.c.keys && $.inArray( e.keyCode, this.c.keys ) === -1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tswitch( e.keyCode ) {\n\t\t\tcase 9: // tab\n\t\t\t\t// `enable` can be tab-only\n\t\t\t\tthis._shift( e, e.shiftKey ? 'left' : 'right', true );\n\t\t\t\tbreak;\n\n\t\t\tcase 27: // esc\n\t\t\t\tif ( this.s.blurable && enable === true ) {\n\t\t\t\t\tthis._blur();\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 33: // page up (previous page)\n\t\t\tcase 34: // page down (next page)\n\t\t\t\tif ( navEnable && !scrolling ) {\n\t\t\t\t\te.preventDefault();\n\n\t\t\t\t\tdt\n\t\t\t\t\t\t.page( e.keyCode === 33 ? 'previous' : 'next' )\n\t\t\t\t\t\t.draw( false );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 35: // end (end of current page)\n\t\t\tcase 36: // home (start of current page)\n\t\t\t\tif ( navEnable ) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tvar indexes = dt.cells( {page: 'current'} ).indexes();\n\t\t\t\t\tvar colIndexes = this._columns();\n\n\t\t\t\t\tthis._focus( dt.cell(\n\t\t\t\t\t\tindexes[ e.keyCode === 35 ? indexes.length-1 : colIndexes[0] ]\n\t\t\t\t\t), null, true, e );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 37: // left arrow\n\t\t\t\tif ( navEnable ) {\n\t\t\t\t\tthis._shift( e, 'left' );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 38: // up arrow\n\t\t\t\tif ( navEnable ) {\n\t\t\t\t\tthis._shift( e, 'up' );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 39: // right arrow\n\t\t\t\tif ( navEnable ) {\n\t\t\t\t\tthis._shift( e, 'right' );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 40: // down arrow\n\t\t\t\tif ( navEnable ) {\n\t\t\t\t\tthis._shift( e, 'down' );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\t// Everything else - pass through only when fully enabled\n\t\t\t\tif ( enable === true ) {\n\t\t\t\t\tthis._emitEvent( 'key', [ dt, e.keyCode, this.s.lastFocus.cell, e ] );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t},\n\n\n\t/**\n\t * Scroll a container to make a cell visible in it. This can be used for\n\t * both DataTables scrolling and native window scrolling.\n\t *\n\t * @param  {jQuery} container Scrolling container\n\t * @param  {jQuery} scroller  Item being scrolled\n\t * @param  {jQuery} cell      Cell in the scroller\n\t * @param  {string} posOff    `position` or `offset` - which to use for the\n\t *   calculation. `offset` for the document, otherwise `position`\n\t * @private\n\t */\n\t_scroll: function ( container, scroller, cell, posOff )\n\t{\n\t\tvar offset = cell[posOff]();\n\t\tvar height = cell.outerHeight();\n\t\tvar width = cell.outerWidth();\n\n\t\tvar scrollTop = scroller.scrollTop();\n\t\tvar scrollLeft = scroller.scrollLeft();\n\t\tvar containerHeight = container.height();\n\t\tvar containerWidth = container.width();\n\n\t\t// If Scroller is being used, the table can be `position: absolute` and that\n\t\t// needs to be taken account of in the offset. If no Scroller, this will be 0\n\t\tif ( posOff === 'position' ) {\n\t\t\toffset.top += parseInt( cell.closest('table').css('top'), 10 );\n\t\t}\n\n\t\t// Top correction\n\t\tif ( offset.top < scrollTop ) {\n\t\t\tscroller.scrollTop( offset.top );\n\t\t}\n\n\t\t// Left correction\n\t\tif ( offset.left < scrollLeft ) {\n\t\t\tscroller.scrollLeft( offset.left );\n\t\t}\n\n\t\t// Bottom correction\n\t\tif ( offset.top + height > scrollTop + containerHeight && height < containerHeight ) {\n\t\t\tscroller.scrollTop( offset.top + height - containerHeight );\n\t\t}\n\n\t\t// Right correction\n\t\tif ( offset.left + width > scrollLeft + containerWidth && width < containerWidth ) {\n\t\t\tscroller.scrollLeft( offset.left + width - containerWidth );\n\t\t}\n\t},\n\n\n\t/**\n\t * Calculate a single offset movement in the table - up, down, left and\n\t * right and then perform the focus if possible\n\t *\n\t * @param  {object}  e           Event object\n\t * @param  {string}  direction   Movement direction\n\t * @param  {boolean} keyBlurable `true` if the key press can result in the\n\t *   table being blurred. This is so arrow keys won't blur the table, but\n\t *   tab will.\n\t * @private\n\t */\n\t_shift: function ( e, direction, keyBlurable )\n\t{\n\t\tvar that         = this;\n\t\tvar dt           = this.s.dt;\n\t\tvar pageInfo     = dt.page.info();\n\t\tvar rows         = pageInfo.recordsDisplay;\n\t\tvar currentCell  = this.s.lastFocus.cell;\n\t\tvar columns      = this._columns();\n\n\t\tif ( ! currentCell ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar currRow = dt\n\t\t\t.rows( { filter: 'applied', order: 'applied' } )\n\t\t\t.indexes()\n\t\t\t.indexOf( currentCell.index().row );\n\n\t\t// When server-side processing, `rows().indexes()` only gives the rows\n\t\t// that are available at the client-side, so we need to normalise the\n\t\t// row's current position by the display start point\n\t\tif ( pageInfo.serverSide ) {\n\t\t\tcurrRow += pageInfo.start;\n\t\t}\n\n\t\tvar currCol = dt\n\t\t\t.columns( columns )\n\t\t\t.indexes()\n\t\t\t.indexOf( currentCell.index().column );\n\n\t\tvar\n\t\t\trow = currRow,\n\t\t\tcolumn = columns[ currCol ]; // row is the display, column is an index\n\n\t\tif ( direction === 'right' ) {\n\t\t\tif ( currCol >= columns.length - 1 ) {\n\t\t\t\trow++;\n\t\t\t\tcolumn = columns[0];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcolumn = columns[ currCol+1 ];\n\t\t\t}\n\t\t}\n\t\telse if ( direction === 'left' ) {\n\t\t\tif ( currCol === 0 ) {\n\t\t\t\trow--;\n\t\t\t\tcolumn = columns[ columns.length - 1 ];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcolumn = columns[ currCol-1 ];\n\t\t\t}\n\t\t}\n\t\telse if ( direction === 'up' ) {\n\t\t\trow--;\n\t\t}\n\t\telse if ( direction === 'down' ) {\n\t\t\trow++;\n\t\t}\n\n\t\tif ( row >= 0 && row < rows && $.inArray( column, columns ) !== -1\n\t\t) {\n\t\t\te.preventDefault();\n\n\t\t\tthis._focus( row, column, true, e );\n\t\t}\n\t\telse if ( ! keyBlurable || ! this.c.blurable ) {\n\t\t\t// No new focus, but if the table isn't blurable, then don't loose\n\t\t\t// focus\n\t\t\te.preventDefault();\n\t\t}\n\t\telse {\n\t\t\tthis._blur();\n\t\t}\n\t},\n\n\n\t/**\n\t * Create a hidden input element that can receive focus on behalf of the\n\t * table\n\t *\n\t * @private\n\t */\n\t_tabInput: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar tabIndex = this.c.tabIndex !== null ?\n\t\t\tthis.c.tabIndex :\n\t\t\tdt.settings()[0].iTabIndex;\n\n\t\tif ( tabIndex == -1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar div = $('<div><input type=\"text\" tabindex=\"'+tabIndex+'\"/></div>')\n\t\t\t.css( {\n\t\t\t\tposition: 'absolute',\n\t\t\t\theight: 1,\n\t\t\t\twidth: 0,\n\t\t\t\toverflow: 'hidden'\n\t\t\t} )\n\t\t\t.insertBefore( dt.table().node() );\n\n\t\tdiv.children().on( 'focus', function (e) {\n\t\t\tif ( dt.cell(':eq(0)', {page: 'current'}).any() ) {\n\t\t\t\tthat._focus( dt.cell(':eq(0)', '0:visible', {page: 'current'}), null, true, e );\n\t\t\t}\n\t\t} );\n\t},\n\n\t/**\n\t * Update fixed columns if they are enabled and if the cell we are\n\t * focusing is inside a fixed column\n\t * @param  {integer} column Index of the column being changed\n\t * @private\n\t */\n\t_updateFixedColumns: function( column )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar settings = dt.settings()[0];\n\n\t\tif ( settings._oFixedColumns ) {\n\t\t\tvar leftCols = settings._oFixedColumns.s.iLeftColumns;\n\t\t\tvar rightCols = settings.aoColumns.length - settings._oFixedColumns.s.iRightColumns;\n\n\t\t\tif (column < leftCols || column >= rightCols) {\n\t\t\t\tdt.fixedColumns().update();\n\t\t\t}\n\t\t}\n\t}\n} );\n\n\n/**\n * KeyTable default settings for initialisation\n *\n * @namespace\n * @name KeyTable.defaults\n * @static\n */\nKeyTable.defaults = {\n\t/**\n\t * Can focus be removed from the table\n\t * @type {Boolean}\n\t */\n\tblurable: true,\n\n\t/**\n\t * Class to give to the focused cell\n\t * @type {String}\n\t */\n\tclassName: 'focus',\n\n\t/**\n\t * Enable or disable clipboard support\n\t * @type {Boolean}\n\t */\n\tclipboard: true,\n\n\t/**\n\t * Orthogonal data that should be copied to clipboard\n\t * @type {string}\n\t */\n\tclipboardOrthogonal: 'display',\n\n\t/**\n\t * Columns that can be focused. This is automatically merged with the\n\t * visible columns as only visible columns can gain focus.\n\t * @type {String}\n\t */\n\tcolumns: '', // all\n\n\t/**\n\t * Editor instance to automatically perform Excel like navigation\n\t * @type {Editor}\n\t */\n\teditor: null,\n\n\t/**\n\t * Trigger editing immediately on focus\n\t * @type {boolean}\n\t */\n\teditOnFocus: false,\n\n\t/**\n\t * Select a cell to automatically select on start up. `null` for no\n\t * automatic selection\n\t * @type {cell-selector}\n\t */\n\tfocus: null,\n\n\t/**\n\t * Array of keys to listen for\n\t * @type {null|array}\n\t */\n\tkeys: null,\n\n\t/**\n\t * Tab index for where the table should sit in the document's tab flow\n\t * @type {integer|null}\n\t */\n\ttabIndex: null\n};\n\n\n\nKeyTable.version = \"2.5.0\";\n\n\n$.fn.dataTable.KeyTable = KeyTable;\n$.fn.DataTable.KeyTable = KeyTable;\n\n\nDataTable.Api.register( 'cell.blur()', function () {\n\treturn this.iterator( 'table', function (ctx) {\n\t\tif ( ctx.keytable ) {\n\t\t\tctx.keytable.blur();\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'cell().focus()', function () {\n\treturn this.iterator( 'cell', function (ctx, row, column) {\n\t\tif ( ctx.keytable ) {\n\t\t\tctx.keytable.focus( row, column );\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'keys.disable()', function () {\n\treturn this.iterator( 'table', function (ctx) {\n\t\tif ( ctx.keytable ) {\n\t\t\tctx.keytable.enable( false );\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'keys.enable()', function ( opts ) {\n\treturn this.iterator( 'table', function (ctx) {\n\t\tif ( ctx.keytable ) {\n\t\t\tctx.keytable.enable( opts === undefined ? true : opts );\n\t\t}\n\t} );\n} );\n\n// Cell selector\nDataTable.ext.selector.cell.push( function ( settings, opts, cells ) {\n\tvar focused = opts.focused;\n\tvar kt = settings.keytable;\n\tvar out = [];\n\n\tif ( ! kt || focused === undefined ) {\n\t\treturn cells;\n\t}\n\n\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\tif ( (focused === true &&  kt.focused( cells[i] ) ) ||\n\t\t\t (focused === false && ! kt.focused( cells[i] ) )\n\t\t) {\n\t\t\tout.push( cells[i] );\n\t\t}\n\t}\n\n\treturn out;\n} );\n\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'preInit.dt.dtk', function (e, settings, json) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.keys;\n\tvar defaults = DataTable.defaults.keys;\n\n\tif ( init || defaults ) {\n\t\tvar opts = $.extend( {}, defaults, init );\n\n\t\tif ( init !== false ) {\n\t\t\tnew KeyTable( settings, opts  );\n\t\t}\n\t}\n} );\n\n\nreturn KeyTable;\n}));\n"
  },
  {
    "path": "static/js/DataTables/KeyTable-2.5.0/js/keyTable.bootstrap.js",
    "content": "/*! Bootstrap 3 styling wrapper for KeyTable\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs', 'datatables.net-keytable'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.KeyTable ) {\n\t\t\t\trequire('datatables.net-keytable')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/KeyTable-2.5.0/js/keyTable.bootstrap4.js",
    "content": "/*! Bootstrap 4 styling wrapper for KeyTable\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs4', 'datatables.net-keytable'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs4')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.KeyTable ) {\n\t\t\t\trequire('datatables.net-keytable')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/KeyTable-2.5.0/js/keyTable.dataTables.js",
    "content": "/*! DataTables styling wrapper for KeyTable\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-dt', 'datatables.net-keytable'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-dt')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.KeyTable ) {\n\t\t\t\trequire('datatables.net-keytable')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/KeyTable-2.5.0/js/keyTable.foundation.js",
    "content": "/*! Bootstrap 4 styling wrapper for KeyTable\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-zf', 'datatables.net-keytable'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-zf')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.KeyTable ) {\n\t\t\t\trequire('datatables.net-keytable')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/KeyTable-2.5.0/js/keyTable.jqueryui.js",
    "content": "/*! jQuery UI styling wrapper for KeyTable\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-jqui', 'datatables.net-keytable'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-jqui')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.KeyTable ) {\n\t\t\t\trequire('datatables.net-keytable')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/KeyTable-2.5.0/js/keyTable.semanicui.js",
    "content": ""
  },
  {
    "path": "static/js/DataTables/KeyTable-2.5.0/js/keyTable.semanticui.js",
    "content": "/*! Semanic UI styling wrapper for KeyTable\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-se', 'datatables.net-keytable'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-se')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.KeyTable ) {\n\t\t\t\trequire('datatables.net-keytable')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/Responsive-2.2.2/css/responsive.bootstrap.css",
    "content": "table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > th.child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {\n  cursor: default !important;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {\n  display: none !important;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > td:first-child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > th:first-child {\n  position: relative;\n  padding-left: 30px;\n  cursor: pointer;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > th:first-child:before {\n  top: 9px;\n  left: 4px;\n  height: 14px;\n  width: 14px;\n  display: block;\n  position: absolute;\n  color: white;\n  border: 2px solid white;\n  border-radius: 14px;\n  box-shadow: 0 0 3px #444;\n  box-sizing: content-box;\n  text-align: center;\n  text-indent: 0 !important;\n  font-family: 'Courier New', Courier, monospace;\n  line-height: 14px;\n  content: '+';\n  background-color: #337ab7;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before {\n  content: '-';\n  background-color: #d33333;\n}\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child,\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child {\n  padding-left: 27px;\n}\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before {\n  top: 5px;\n  left: 4px;\n  height: 14px;\n  width: 14px;\n  border-radius: 14px;\n  line-height: 14px;\n  text-indent: 3px;\n}\ntable.dataTable.dtr-column > tbody > tr > td.control,\ntable.dataTable.dtr-column > tbody > tr > th.control {\n  position: relative;\n  cursor: pointer;\n}\ntable.dataTable.dtr-column > tbody > tr > td.control:before,\ntable.dataTable.dtr-column > tbody > tr > th.control:before {\n  top: 50%;\n  left: 50%;\n  height: 16px;\n  width: 16px;\n  margin-top: -10px;\n  margin-left: -10px;\n  display: block;\n  position: absolute;\n  color: white;\n  border: 2px solid white;\n  border-radius: 14px;\n  box-shadow: 0 0 3px #444;\n  box-sizing: content-box;\n  text-align: center;\n  text-indent: 0 !important;\n  font-family: 'Courier New', Courier, monospace;\n  line-height: 14px;\n  content: '+';\n  background-color: #337ab7;\n}\ntable.dataTable.dtr-column > tbody > tr.parent td.control:before,\ntable.dataTable.dtr-column > tbody > tr.parent th.control:before {\n  content: '-';\n  background-color: #d33333;\n}\ntable.dataTable > tbody > tr.child {\n  padding: 0.5em 1em;\n}\ntable.dataTable > tbody > tr.child:hover {\n  background: transparent !important;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details {\n  display: inline-block;\n  list-style-type: none;\n  margin: 0;\n  padding: 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li {\n  border-bottom: 1px solid #efefef;\n  padding: 0.5em 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li:first-child {\n  padding-top: 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li:last-child {\n  border-bottom: none;\n}\ntable.dataTable > tbody > tr.child span.dtr-title {\n  display: inline-block;\n  min-width: 75px;\n  font-weight: bold;\n}\n\ndiv.dtr-modal {\n  position: fixed;\n  box-sizing: border-box;\n  top: 0;\n  left: 0;\n  height: 100%;\n  width: 100%;\n  z-index: 100;\n  padding: 10em 1em;\n}\ndiv.dtr-modal div.dtr-modal-display {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  width: 50%;\n  height: 50%;\n  overflow: auto;\n  margin: auto;\n  z-index: 102;\n  overflow: auto;\n  background-color: #f5f5f7;\n  border: 1px solid black;\n  border-radius: 0.5em;\n  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);\n}\ndiv.dtr-modal div.dtr-modal-content {\n  position: relative;\n  padding: 1em;\n}\ndiv.dtr-modal div.dtr-modal-close {\n  position: absolute;\n  top: 6px;\n  right: 6px;\n  width: 22px;\n  height: 22px;\n  border: 1px solid #eaeaea;\n  background-color: #f9f9f9;\n  text-align: center;\n  border-radius: 3px;\n  cursor: pointer;\n  z-index: 12;\n}\ndiv.dtr-modal div.dtr-modal-close:hover {\n  background-color: #eaeaea;\n}\ndiv.dtr-modal div.dtr-modal-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  z-index: 101;\n  background: rgba(0, 0, 0, 0.6);\n}\n\n@media screen and (max-width: 767px) {\n  div.dtr-modal div.dtr-modal-display {\n    width: 95%;\n  }\n}\ndiv.dtr-bs-modal table.table tr:first-child td {\n  border-top: none;\n}\n"
  },
  {
    "path": "static/js/DataTables/Responsive-2.2.2/css/responsive.bootstrap4.css",
    "content": "table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > th.child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {\n  cursor: default !important;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {\n  display: none !important;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > td:first-child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > th:first-child {\n  position: relative;\n  padding-left: 30px;\n  cursor: pointer;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > th:first-child:before {\n  top: 12px;\n  left: 4px;\n  height: 14px;\n  width: 14px;\n  display: block;\n  position: absolute;\n  color: white;\n  border: 2px solid white;\n  border-radius: 14px;\n  box-shadow: 0 0 3px #444;\n  box-sizing: content-box;\n  text-align: center;\n  text-indent: 0 !important;\n  font-family: 'Courier New', Courier, monospace;\n  line-height: 14px;\n  content: '+';\n  background-color: #0275d8;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before {\n  content: '-';\n  background-color: #d33333;\n}\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child,\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child {\n  padding-left: 27px;\n}\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before {\n  top: 5px;\n  left: 4px;\n  height: 14px;\n  width: 14px;\n  border-radius: 14px;\n  line-height: 14px;\n  text-indent: 3px;\n}\ntable.dataTable.dtr-column > tbody > tr > td.control,\ntable.dataTable.dtr-column > tbody > tr > th.control {\n  position: relative;\n  cursor: pointer;\n}\ntable.dataTable.dtr-column > tbody > tr > td.control:before,\ntable.dataTable.dtr-column > tbody > tr > th.control:before {\n  top: 50%;\n  left: 50%;\n  height: 16px;\n  width: 16px;\n  margin-top: -10px;\n  margin-left: -10px;\n  display: block;\n  position: absolute;\n  color: white;\n  border: 2px solid white;\n  border-radius: 14px;\n  box-shadow: 0 0 3px #444;\n  box-sizing: content-box;\n  text-align: center;\n  text-indent: 0 !important;\n  font-family: 'Courier New', Courier, monospace;\n  line-height: 14px;\n  content: '+';\n  background-color: #0275d8;\n}\ntable.dataTable.dtr-column > tbody > tr.parent td.control:before,\ntable.dataTable.dtr-column > tbody > tr.parent th.control:before {\n  content: '-';\n  background-color: #d33333;\n}\ntable.dataTable > tbody > tr.child {\n  padding: 0.5em 1em;\n}\ntable.dataTable > tbody > tr.child:hover {\n  background: transparent !important;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details {\n  display: inline-block;\n  list-style-type: none;\n  margin: 0;\n  padding: 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li {\n  border-bottom: 1px solid #efefef;\n  padding: 0.5em 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li:first-child {\n  padding-top: 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li:last-child {\n  border-bottom: none;\n}\ntable.dataTable > tbody > tr.child span.dtr-title {\n  display: inline-block;\n  min-width: 75px;\n  font-weight: bold;\n}\n\ndiv.dtr-modal {\n  position: fixed;\n  box-sizing: border-box;\n  top: 0;\n  left: 0;\n  height: 100%;\n  width: 100%;\n  z-index: 100;\n  padding: 10em 1em;\n}\ndiv.dtr-modal div.dtr-modal-display {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  width: 50%;\n  height: 50%;\n  overflow: auto;\n  margin: auto;\n  z-index: 102;\n  overflow: auto;\n  background-color: #f5f5f7;\n  border: 1px solid black;\n  border-radius: 0.5em;\n  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);\n}\ndiv.dtr-modal div.dtr-modal-content {\n  position: relative;\n  padding: 1em;\n}\ndiv.dtr-modal div.dtr-modal-close {\n  position: absolute;\n  top: 6px;\n  right: 6px;\n  width: 22px;\n  height: 22px;\n  border: 1px solid #eaeaea;\n  background-color: #f9f9f9;\n  text-align: center;\n  border-radius: 3px;\n  cursor: pointer;\n  z-index: 12;\n}\ndiv.dtr-modal div.dtr-modal-close:hover {\n  background-color: #eaeaea;\n}\ndiv.dtr-modal div.dtr-modal-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  z-index: 101;\n  background: rgba(0, 0, 0, 0.6);\n}\n\n@media screen and (max-width: 767px) {\n  div.dtr-modal div.dtr-modal-display {\n    width: 95%;\n  }\n}\ndiv.dtr-bs-modal table.table tr:first-child td {\n  border-top: none;\n}\n"
  },
  {
    "path": "static/js/DataTables/Responsive-2.2.2/css/responsive.dataTables.css",
    "content": "table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > th.child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {\n  cursor: default !important;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {\n  display: none !important;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > td:first-child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > th:first-child {\n  position: relative;\n  padding-left: 30px;\n  cursor: pointer;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > th:first-child:before {\n  top: 9px;\n  left: 4px;\n  height: 14px;\n  width: 14px;\n  display: block;\n  position: absolute;\n  color: white;\n  border: 2px solid white;\n  border-radius: 14px;\n  box-shadow: 0 0 3px #444;\n  box-sizing: content-box;\n  text-align: center;\n  text-indent: 0 !important;\n  font-family: 'Courier New', Courier, monospace;\n  line-height: 14px;\n  content: '+';\n  background-color: #31b131;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before {\n  content: '-';\n  background-color: #d33333;\n}\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child,\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child {\n  padding-left: 27px;\n}\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before {\n  top: 5px;\n  left: 4px;\n  height: 14px;\n  width: 14px;\n  border-radius: 14px;\n  line-height: 14px;\n  text-indent: 3px;\n}\ntable.dataTable.dtr-column > tbody > tr > td.control,\ntable.dataTable.dtr-column > tbody > tr > th.control {\n  position: relative;\n  cursor: pointer;\n}\ntable.dataTable.dtr-column > tbody > tr > td.control:before,\ntable.dataTable.dtr-column > tbody > tr > th.control:before {\n  top: 50%;\n  left: 50%;\n  height: 16px;\n  width: 16px;\n  margin-top: -10px;\n  margin-left: -10px;\n  display: block;\n  position: absolute;\n  color: white;\n  border: 2px solid white;\n  border-radius: 14px;\n  box-shadow: 0 0 3px #444;\n  box-sizing: content-box;\n  text-align: center;\n  text-indent: 0 !important;\n  font-family: 'Courier New', Courier, monospace;\n  line-height: 14px;\n  content: '+';\n  background-color: #31b131;\n}\ntable.dataTable.dtr-column > tbody > tr.parent td.control:before,\ntable.dataTable.dtr-column > tbody > tr.parent th.control:before {\n  content: '-';\n  background-color: #d33333;\n}\ntable.dataTable > tbody > tr.child {\n  padding: 0.5em 1em;\n}\ntable.dataTable > tbody > tr.child:hover {\n  background: transparent !important;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details {\n  display: inline-block;\n  list-style-type: none;\n  margin: 0;\n  padding: 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li {\n  border-bottom: 1px solid #efefef;\n  padding: 0.5em 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li:first-child {\n  padding-top: 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li:last-child {\n  border-bottom: none;\n}\ntable.dataTable > tbody > tr.child span.dtr-title {\n  display: inline-block;\n  min-width: 75px;\n  font-weight: bold;\n}\n\ndiv.dtr-modal {\n  position: fixed;\n  box-sizing: border-box;\n  top: 0;\n  left: 0;\n  height: 100%;\n  width: 100%;\n  z-index: 100;\n  padding: 10em 1em;\n}\ndiv.dtr-modal div.dtr-modal-display {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  width: 50%;\n  height: 50%;\n  overflow: auto;\n  margin: auto;\n  z-index: 102;\n  overflow: auto;\n  background-color: #f5f5f7;\n  border: 1px solid black;\n  border-radius: 0.5em;\n  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);\n}\ndiv.dtr-modal div.dtr-modal-content {\n  position: relative;\n  padding: 1em;\n}\ndiv.dtr-modal div.dtr-modal-close {\n  position: absolute;\n  top: 6px;\n  right: 6px;\n  width: 22px;\n  height: 22px;\n  border: 1px solid #eaeaea;\n  background-color: #f9f9f9;\n  text-align: center;\n  border-radius: 3px;\n  cursor: pointer;\n  z-index: 12;\n}\ndiv.dtr-modal div.dtr-modal-close:hover {\n  background-color: #eaeaea;\n}\ndiv.dtr-modal div.dtr-modal-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  z-index: 101;\n  background: rgba(0, 0, 0, 0.6);\n}\n\n@media screen and (max-width: 767px) {\n  div.dtr-modal div.dtr-modal-display {\n    width: 95%;\n  }\n}\n"
  },
  {
    "path": "static/js/DataTables/Responsive-2.2.2/css/responsive.foundation.css",
    "content": "table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > th.child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {\n  cursor: default !important;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {\n  display: none !important;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > td:first-child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > th:first-child {\n  position: relative;\n  padding-left: 30px;\n  cursor: pointer;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > th:first-child:before {\n  top: 9px;\n  left: 4px;\n  height: 14px;\n  width: 14px;\n  display: block;\n  position: absolute;\n  color: white;\n  border: 2px solid white;\n  border-radius: 14px;\n  box-shadow: 0 0 3px #444;\n  box-sizing: content-box;\n  text-align: center;\n  text-indent: 0 !important;\n  font-family: 'Courier New', Courier, monospace;\n  line-height: 14px;\n  content: '+';\n  background-color: #008CBA;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before {\n  content: '-';\n  background-color: #d33333;\n}\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child,\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child {\n  padding-left: 27px;\n}\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before {\n  top: 5px;\n  left: 4px;\n  height: 14px;\n  width: 14px;\n  border-radius: 14px;\n  line-height: 14px;\n  text-indent: 3px;\n}\ntable.dataTable.dtr-column > tbody > tr > td.control,\ntable.dataTable.dtr-column > tbody > tr > th.control {\n  position: relative;\n  cursor: pointer;\n}\ntable.dataTable.dtr-column > tbody > tr > td.control:before,\ntable.dataTable.dtr-column > tbody > tr > th.control:before {\n  top: 50%;\n  left: 50%;\n  height: 16px;\n  width: 16px;\n  margin-top: -10px;\n  margin-left: -10px;\n  display: block;\n  position: absolute;\n  color: white;\n  border: 2px solid white;\n  border-radius: 14px;\n  box-shadow: 0 0 3px #444;\n  box-sizing: content-box;\n  text-align: center;\n  text-indent: 0 !important;\n  font-family: 'Courier New', Courier, monospace;\n  line-height: 14px;\n  content: '+';\n  background-color: #008CBA;\n}\ntable.dataTable.dtr-column > tbody > tr.parent td.control:before,\ntable.dataTable.dtr-column > tbody > tr.parent th.control:before {\n  content: '-';\n  background-color: #d33333;\n}\ntable.dataTable > tbody > tr.child {\n  padding: 0.5em 1em;\n}\ntable.dataTable > tbody > tr.child:hover {\n  background: transparent !important;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details {\n  display: inline-block;\n  list-style-type: none;\n  margin: 0;\n  padding: 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li {\n  border-bottom: 1px solid #efefef;\n  padding: 0.5em 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li:first-child {\n  padding-top: 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li:last-child {\n  border-bottom: none;\n}\ntable.dataTable > tbody > tr.child span.dtr-title {\n  display: inline-block;\n  min-width: 75px;\n  font-weight: bold;\n}\n\ndiv.dtr-modal {\n  position: fixed;\n  box-sizing: border-box;\n  top: 0;\n  left: 0;\n  height: 100%;\n  width: 100%;\n  z-index: 100;\n  padding: 10em 1em;\n}\ndiv.dtr-modal div.dtr-modal-display {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  width: 50%;\n  height: 50%;\n  overflow: auto;\n  margin: auto;\n  z-index: 102;\n  overflow: auto;\n  background-color: #f5f5f7;\n  border: 1px solid black;\n  border-radius: 0.5em;\n  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);\n}\ndiv.dtr-modal div.dtr-modal-content {\n  position: relative;\n  padding: 1em;\n}\ndiv.dtr-modal div.dtr-modal-close {\n  position: absolute;\n  top: 6px;\n  right: 6px;\n  width: 22px;\n  height: 22px;\n  border: 1px solid #eaeaea;\n  background-color: #f9f9f9;\n  text-align: center;\n  border-radius: 3px;\n  cursor: pointer;\n  z-index: 12;\n}\ndiv.dtr-modal div.dtr-modal-close:hover {\n  background-color: #eaeaea;\n}\ndiv.dtr-modal div.dtr-modal-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  z-index: 101;\n  background: rgba(0, 0, 0, 0.6);\n}\n\n@media screen and (max-width: 767px) {\n  div.dtr-modal div.dtr-modal-display {\n    width: 95%;\n  }\n}\ntable.dataTable > tbody > tr.child ul {\n  font-size: 1em;\n}\n"
  },
  {
    "path": "static/js/DataTables/Responsive-2.2.2/css/responsive.jqueryui.css",
    "content": "table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > th.child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {\n  cursor: default !important;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {\n  display: none !important;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > td:first-child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > th:first-child {\n  position: relative;\n  padding-left: 30px;\n  cursor: pointer;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > th:first-child:before {\n  top: 9px;\n  left: 4px;\n  height: 14px;\n  width: 14px;\n  display: block;\n  position: absolute;\n  color: white;\n  border: 2px solid white;\n  border-radius: 14px;\n  box-shadow: 0 0 3px #444;\n  box-sizing: content-box;\n  text-align: center;\n  text-indent: 0 !important;\n  font-family: 'Courier New', Courier, monospace;\n  line-height: 14px;\n  content: '+';\n  background-color: #31b131;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before {\n  content: '-';\n  background-color: #d33333;\n}\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child,\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child {\n  padding-left: 27px;\n}\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before {\n  top: 5px;\n  left: 4px;\n  height: 14px;\n  width: 14px;\n  border-radius: 14px;\n  line-height: 14px;\n  text-indent: 3px;\n}\ntable.dataTable.dtr-column > tbody > tr > td.control,\ntable.dataTable.dtr-column > tbody > tr > th.control {\n  position: relative;\n  cursor: pointer;\n}\ntable.dataTable.dtr-column > tbody > tr > td.control:before,\ntable.dataTable.dtr-column > tbody > tr > th.control:before {\n  top: 50%;\n  left: 50%;\n  height: 16px;\n  width: 16px;\n  margin-top: -10px;\n  margin-left: -10px;\n  display: block;\n  position: absolute;\n  color: white;\n  border: 2px solid white;\n  border-radius: 14px;\n  box-shadow: 0 0 3px #444;\n  box-sizing: content-box;\n  text-align: center;\n  text-indent: 0 !important;\n  font-family: 'Courier New', Courier, monospace;\n  line-height: 14px;\n  content: '+';\n  background-color: #31b131;\n}\ntable.dataTable.dtr-column > tbody > tr.parent td.control:before,\ntable.dataTable.dtr-column > tbody > tr.parent th.control:before {\n  content: '-';\n  background-color: #d33333;\n}\ntable.dataTable > tbody > tr.child {\n  padding: 0.5em 1em;\n}\ntable.dataTable > tbody > tr.child:hover {\n  background: transparent !important;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details {\n  display: inline-block;\n  list-style-type: none;\n  margin: 0;\n  padding: 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li {\n  border-bottom: 1px solid #efefef;\n  padding: 0.5em 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li:first-child {\n  padding-top: 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li:last-child {\n  border-bottom: none;\n}\ntable.dataTable > tbody > tr.child span.dtr-title {\n  display: inline-block;\n  min-width: 75px;\n  font-weight: bold;\n}\n\ndiv.dtr-modal {\n  position: fixed;\n  box-sizing: border-box;\n  top: 0;\n  left: 0;\n  height: 100%;\n  width: 100%;\n  z-index: 100;\n  padding: 10em 1em;\n}\ndiv.dtr-modal div.dtr-modal-display {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  width: 50%;\n  height: 50%;\n  overflow: auto;\n  margin: auto;\n  z-index: 102;\n  overflow: auto;\n  background-color: #f5f5f7;\n  border: 1px solid black;\n  border-radius: 0.5em;\n  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);\n}\ndiv.dtr-modal div.dtr-modal-content {\n  position: relative;\n  padding: 1em;\n}\ndiv.dtr-modal div.dtr-modal-close {\n  position: absolute;\n  top: 6px;\n  right: 6px;\n  width: 22px;\n  height: 22px;\n  border: 1px solid #eaeaea;\n  background-color: #f9f9f9;\n  text-align: center;\n  border-radius: 3px;\n  cursor: pointer;\n  z-index: 12;\n}\ndiv.dtr-modal div.dtr-modal-close:hover {\n  background-color: #eaeaea;\n}\ndiv.dtr-modal div.dtr-modal-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  z-index: 101;\n  background: rgba(0, 0, 0, 0.6);\n}\n\n@media screen and (max-width: 767px) {\n  div.dtr-modal div.dtr-modal-display {\n    width: 95%;\n  }\n}\n"
  },
  {
    "path": "static/js/DataTables/Responsive-2.2.2/css/responsive.semanticui.css",
    "content": "table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > th.child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {\n  cursor: default !important;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {\n  display: none !important;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > td:first-child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > th:first-child {\n  position: relative;\n  padding-left: 30px;\n  cursor: pointer;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > th:first-child:before {\n  top: 9px;\n  left: 4px;\n  height: 14px;\n  width: 14px;\n  display: block;\n  position: absolute;\n  color: white;\n  border: 2px solid white;\n  border-radius: 14px;\n  box-shadow: 0 0 3px #444;\n  box-sizing: content-box;\n  text-align: center;\n  text-indent: 0 !important;\n  font-family: 'Courier New', Courier, monospace;\n  line-height: 14px;\n  content: '+';\n  background-color: #21ba45;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before {\n  content: '-';\n  background-color: #d33333;\n}\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child,\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child {\n  padding-left: 27px;\n}\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before {\n  top: 5px;\n  left: 4px;\n  height: 14px;\n  width: 14px;\n  border-radius: 14px;\n  line-height: 14px;\n  text-indent: 3px;\n}\ntable.dataTable.dtr-column > tbody > tr > td.control,\ntable.dataTable.dtr-column > tbody > tr > th.control {\n  position: relative;\n  cursor: pointer;\n}\ntable.dataTable.dtr-column > tbody > tr > td.control:before,\ntable.dataTable.dtr-column > tbody > tr > th.control:before {\n  top: 50%;\n  left: 50%;\n  height: 16px;\n  width: 16px;\n  margin-top: -10px;\n  margin-left: -10px;\n  display: block;\n  position: absolute;\n  color: white;\n  border: 2px solid white;\n  border-radius: 14px;\n  box-shadow: 0 0 3px #444;\n  box-sizing: content-box;\n  text-align: center;\n  text-indent: 0 !important;\n  font-family: 'Courier New', Courier, monospace;\n  line-height: 14px;\n  content: '+';\n  background-color: #21ba45;\n}\ntable.dataTable.dtr-column > tbody > tr.parent td.control:before,\ntable.dataTable.dtr-column > tbody > tr.parent th.control:before {\n  content: '-';\n  background-color: #d33333;\n}\ntable.dataTable > tbody > tr.child {\n  padding: 0.5em 1em;\n}\ntable.dataTable > tbody > tr.child:hover {\n  background: transparent !important;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details {\n  display: inline-block;\n  list-style-type: none;\n  margin: 0;\n  padding: 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li {\n  border-bottom: 1px solid #efefef;\n  padding: 0.5em 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li:first-child {\n  padding-top: 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li:last-child {\n  border-bottom: none;\n}\ntable.dataTable > tbody > tr.child span.dtr-title {\n  display: inline-block;\n  min-width: 75px;\n  font-weight: bold;\n}\n\ndiv.dtr-modal {\n  position: fixed;\n  box-sizing: border-box;\n  top: 0;\n  left: 0;\n  height: 100%;\n  width: 100%;\n  z-index: 100;\n  padding: 10em 1em;\n}\ndiv.dtr-modal div.dtr-modal-display {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  width: 50%;\n  height: 50%;\n  overflow: auto;\n  margin: auto;\n  z-index: 102;\n  overflow: auto;\n  background-color: #f5f5f7;\n  border: 1px solid black;\n  border-radius: 0.5em;\n  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);\n}\ndiv.dtr-modal div.dtr-modal-content {\n  position: relative;\n  padding: 1em;\n}\ndiv.dtr-modal div.dtr-modal-close {\n  position: absolute;\n  top: 6px;\n  right: 6px;\n  width: 22px;\n  height: 22px;\n  border: 1px solid #eaeaea;\n  background-color: #f9f9f9;\n  text-align: center;\n  border-radius: 3px;\n  cursor: pointer;\n  z-index: 12;\n}\ndiv.dtr-modal div.dtr-modal-close:hover {\n  background-color: #eaeaea;\n}\ndiv.dtr-modal div.dtr-modal-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  z-index: 101;\n  background: rgba(0, 0, 0, 0.6);\n}\n\n@media screen and (max-width: 767px) {\n  div.dtr-modal div.dtr-modal-display {\n    width: 95%;\n  }\n}\ndiv.dtr-bs-modal table.table tr:first-child td {\n  border-top: none;\n}\n"
  },
  {
    "path": "static/js/DataTables/Responsive-2.2.2/js/dataTables.responsive.js",
    "content": "/*! Responsive 2.2.2\n * 2014-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     Responsive\n * @description Responsive tables plug-in for DataTables\n * @version     2.2.2\n * @file        dataTables.responsive.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2014-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/**\n * Responsive is a plug-in for the DataTables library that makes use of\n * DataTables' ability to change the visibility of columns, changing the\n * visibility of columns so the displayed columns fit into the table container.\n * The end result is that complex tables will be dynamically adjusted to fit\n * into the viewport, be it on a desktop, tablet or mobile browser.\n *\n * Responsive for DataTables has two modes of operation, which can used\n * individually or combined:\n *\n * * Class name based control - columns assigned class names that match the\n *   breakpoint logic can be shown / hidden as required for each breakpoint.\n * * Automatic control - columns are automatically hidden when there is no\n *   room left to display them. Columns removed from the right.\n *\n * In additional to column visibility control, Responsive also has built into\n * options to use DataTables' child row display to show / hide the information\n * from the table that has been hidden. There are also two modes of operation\n * for this child row display:\n *\n * * Inline - when the control element that the user can use to show / hide\n *   child rows is displayed inside the first column of the table.\n * * Column - where a whole column is dedicated to be the show / hide control.\n *\n * Initialisation of Responsive is performed by:\n *\n * * Adding the class `responsive` or `dt-responsive` to the table. In this case\n *   Responsive will automatically be initialised with the default configuration\n *   options when the DataTable is created.\n * * Using the `responsive` option in the DataTables configuration options. This\n *   can also be used to specify the configuration options, or simply set to\n *   `true` to use the defaults.\n *\n *  @class\n *  @param {object} settings DataTables settings object for the host table\n *  @param {object} [opts] Configuration options\n *  @requires jQuery 1.7+\n *  @requires DataTables 1.10.3+\n *\n *  @example\n *      $('#example').DataTable( {\n *        responsive: true\n *      } );\n *    } );\n */\nvar Responsive = function ( settings, opts ) {\n\t// Sanity check that we are using DataTables 1.10 or newer\n\tif ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.10' ) ) {\n\t\tthrow 'DataTables Responsive requires DataTables 1.10.10 or newer';\n\t}\n\n\tthis.s = {\n\t\tdt: new DataTable.Api( settings ),\n\t\tcolumns: [],\n\t\tcurrent: []\n\t};\n\n\t// Check if responsive has already been initialised on this table\n\tif ( this.s.dt.settings()[0].responsive ) {\n\t\treturn;\n\t}\n\n\t// details is an object, but for simplicity the user can give it as a string\n\t// or a boolean\n\tif ( opts && typeof opts.details === 'string' ) {\n\t\topts.details = { type: opts.details };\n\t}\n\telse if ( opts && opts.details === false ) {\n\t\topts.details = { type: false };\n\t}\n\telse if ( opts && opts.details === true ) {\n\t\topts.details = { type: 'inline' };\n\t}\n\n\tthis.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts );\n\tsettings.responsive = this;\n\tthis._constructor();\n};\n\n$.extend( Responsive.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\n\t/**\n\t * Initialise the Responsive instance\n\t *\n\t * @private\n\t */\n\t_constructor: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar dtPrivateSettings = dt.settings()[0];\n\t\tvar oldWindowWidth = $(window).width();\n\n\t\tdt.settings()[0]._responsive = this;\n\n\t\t// Use DataTables' throttle function to avoid processor thrashing on\n\t\t// resize\n\t\t$(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () {\n\t\t\t// iOS has a bug whereby resize can fire when only scrolling\n\t\t\t// See: http://stackoverflow.com/questions/8898412\n\t\t\tvar width = $(window).width();\n\n\t\t\tif ( width !== oldWindowWidth ) {\n\t\t\t\tthat._resize();\n\t\t\t\toldWindowWidth = width;\n\t\t\t}\n\t\t} ) );\n\n\t\t// DataTables doesn't currently trigger an event when a row is added, so\n\t\t// we need to hook into its private API to enforce the hidden rows when\n\t\t// new data is added\n\t\tdtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) {\n\t\t\tif ( $.inArray( false, that.s.current ) !== -1 ) {\n\t\t\t\t$('>td, >th', tr).each( function ( i ) {\n\t\t\t\t\tvar idx = dt.column.index( 'toData', i );\n\n\t\t\t\t\tif ( that.s.current[idx] === false ) {\n\t\t\t\t\t\t$(this).css('display', 'none');\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\t// Destroy event handler\n\t\tdt.on( 'destroy.dtr', function () {\n\t\t\tdt.off( '.dtr' );\n\t\t\t$( dt.table().body() ).off( '.dtr' );\n\t\t\t$(window).off( 'resize.dtr orientationchange.dtr' );\n\n\t\t\t// Restore the columns that we've hidden\n\t\t\t$.each( that.s.current, function ( i, val ) {\n\t\t\t\tif ( val === false ) {\n\t\t\t\t\tthat._setColumnVis( i, true );\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\n\t\t// Reorder the breakpoints array here in case they have been added out\n\t\t// of order\n\t\tthis.c.breakpoints.sort( function (a, b) {\n\t\t\treturn a.width < b.width ? 1 :\n\t\t\t\ta.width > b.width ? -1 : 0;\n\t\t} );\n\n\t\tthis._classLogic();\n\t\tthis._resizeAuto();\n\n\t\t// Details handler\n\t\tvar details = this.c.details;\n\n\t\tif ( details.type !== false ) {\n\t\t\tthat._detailsInit();\n\n\t\t\t// DataTables will trigger this event on every column it shows and\n\t\t\t// hides individually\n\t\t\tdt.on( 'column-visibility.dtr', function () {\n\t\t\t\t// Use a small debounce to allow multiple columns to be set together\n\t\t\t\tif ( that._timer ) {\n\t\t\t\t\tclearTimeout( that._timer );\n\t\t\t\t}\n\n\t\t\t\tthat._timer = setTimeout( function () {\n\t\t\t\t\tthat._timer = null;\n\n\t\t\t\t\tthat._classLogic();\n\t\t\t\t\tthat._resizeAuto();\n\t\t\t\t\tthat._resize();\n\n\t\t\t\t\tthat._redrawChildren();\n\t\t\t\t}, 100 );\n\t\t\t} );\n\n\t\t\t// Redraw the details box on each draw which will happen if the data\n\t\t\t// has changed. This is used until DataTables implements a native\n\t\t\t// `updated` event for rows\n\t\t\tdt.on( 'draw.dtr', function () {\n\t\t\t\tthat._redrawChildren();\n\t\t\t} );\n\n\t\t\t$(dt.table().node()).addClass( 'dtr-'+details.type );\n\t\t}\n\n\t\tdt.on( 'column-reorder.dtr', function (e, settings, details) {\n\t\t\tthat._classLogic();\n\t\t\tthat._resizeAuto();\n\t\t\tthat._resize();\n\t\t} );\n\n\t\t// Change in column sizes means we need to calc\n\t\tdt.on( 'column-sizing.dtr', function () {\n\t\t\tthat._resizeAuto();\n\t\t\tthat._resize();\n\t\t});\n\n\t\t// On Ajax reload we want to reopen any child rows which are displayed\n\t\t// by responsive\n\t\tdt.on( 'preXhr.dtr', function () {\n\t\t\tvar rowIds = [];\n\t\t\tdt.rows().every( function () {\n\t\t\t\tif ( this.child.isShown() ) {\n\t\t\t\t\trowIds.push( this.id(true) );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tdt.one( 'draw.dtr', function () {\n\t\t\t\tthat._resizeAuto();\n\t\t\t\tthat._resize();\n\n\t\t\t\tdt.rows( rowIds ).every( function () {\n\t\t\t\t\tthat._detailsDisplay( this, false );\n\t\t\t\t} );\n\t\t\t} );\n\t\t});\n\n\t\tdt.on( 'init.dtr', function (e, settings, details) {\n\t\t\tthat._resizeAuto();\n\t\t\tthat._resize();\n\n\t\t\t// If columns were hidden, then DataTables needs to adjust the\n\t\t\t// column sizing\n\t\t\tif ( $.inArray( false, that.s.current ) ) {\n\t\t\t\tdt.columns.adjust();\n\t\t\t}\n\t\t} );\n\n\t\t// First pass - draw the table for the current viewport size\n\t\tthis._resize();\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\n\t/**\n\t * Calculate the visibility for the columns in a table for a given\n\t * breakpoint. The result is pre-determined based on the class logic if\n\t * class names are used to control all columns, but the width of the table\n\t * is also used if there are columns which are to be automatically shown\n\t * and hidden.\n\t *\n\t * @param  {string} breakpoint Breakpoint name to use for the calculation\n\t * @return {array} Array of boolean values initiating the visibility of each\n\t *   column.\n\t *  @private\n\t */\n\t_columnsVisiblity: function ( breakpoint )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar columns = this.s.columns;\n\t\tvar i, ien;\n\n\t\t// Create an array that defines the column ordering based first on the\n\t\t// column's priority, and secondly the column index. This allows the\n\t\t// columns to be removed from the right if the priority matches\n\t\tvar order = columns\n\t\t\t.map( function ( col, idx ) {\n\t\t\t\treturn {\n\t\t\t\t\tcolumnIdx: idx,\n\t\t\t\t\tpriority: col.priority\n\t\t\t\t};\n\t\t\t} )\n\t\t\t.sort( function ( a, b ) {\n\t\t\t\tif ( a.priority !== b.priority ) {\n\t\t\t\t\treturn a.priority - b.priority;\n\t\t\t\t}\n\t\t\t\treturn a.columnIdx - b.columnIdx;\n\t\t\t} );\n\n\t\t// Class logic - determine which columns are in this breakpoint based\n\t\t// on the classes. If no class control (i.e. `auto`) then `-` is used\n\t\t// to indicate this to the rest of the function\n\t\tvar display = $.map( columns, function ( col, i ) {\n\t\t\tif ( dt.column(i).visible() === false ) {\n\t\t\t\treturn 'not-visible';\n\t\t\t}\n\t\t\treturn col.auto && col.minWidth === null ?\n\t\t\t\tfalse :\n\t\t\t\tcol.auto === true ?\n\t\t\t\t\t'-' :\n\t\t\t\t\t$.inArray( breakpoint, col.includeIn ) !== -1;\n\t\t} );\n\n\t\t// Auto column control - first pass: how much width is taken by the\n\t\t// ones that must be included from the non-auto columns\n\t\tvar requiredWidth = 0;\n\t\tfor ( i=0, ien=display.length ; i<ien ; i++ ) {\n\t\t\tif ( display[i] === true ) {\n\t\t\t\trequiredWidth += columns[i].minWidth;\n\t\t\t}\n\t\t}\n\n\t\t// Second pass, use up any remaining width for other columns. For\n\t\t// scrolling tables we need to subtract the width of the scrollbar. It\n\t\t// may not be requires which makes this sub-optimal, but it would\n\t\t// require another full redraw to make complete use of those extra few\n\t\t// pixels\n\t\tvar scrolling = dt.settings()[0].oScroll;\n\t\tvar bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0;\n\t\tvar widthAvailable = dt.table().container().offsetWidth - bar;\n\t\tvar usedWidth = widthAvailable - requiredWidth;\n\n\t\t// Control column needs to always be included. This makes it sub-\n\t\t// optimal in terms of using the available with, but to stop layout\n\t\t// thrashing or overflow. Also we need to account for the control column\n\t\t// width first so we know how much width is available for the other\n\t\t// columns, since the control column might not be the first one shown\n\t\tfor ( i=0, ien=display.length ; i<ien ; i++ ) {\n\t\t\tif ( columns[i].control ) {\n\t\t\t\tusedWidth -= columns[i].minWidth;\n\t\t\t}\n\t\t}\n\n\t\t// Allow columns to be shown (counting by priority and then right to\n\t\t// left) until we run out of room\n\t\tvar empty = false;\n\t\tfor ( i=0, ien=order.length ; i<ien ; i++ ) {\n\t\t\tvar colIdx = order[i].columnIdx;\n\n\t\t\tif ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) {\n\t\t\t\t// Once we've found a column that won't fit we don't let any\n\t\t\t\t// others display either, or columns might disappear in the\n\t\t\t\t// middle of the table\n\t\t\t\tif ( empty || usedWidth - columns[colIdx].minWidth < 0 ) {\n\t\t\t\t\tempty = true;\n\t\t\t\t\tdisplay[colIdx] = false;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdisplay[colIdx] = true;\n\t\t\t\t}\n\n\t\t\t\tusedWidth -= columns[colIdx].minWidth;\n\t\t\t}\n\t\t}\n\n\t\t// Determine if the 'control' column should be shown (if there is one).\n\t\t// This is the case when there is a hidden column (that is not the\n\t\t// control column). The two loops look inefficient here, but they are\n\t\t// trivial and will fly through. We need to know the outcome from the\n\t\t// first , before the action in the second can be taken\n\t\tvar showControl = false;\n\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tif ( ! columns[i].control && ! columns[i].never && display[i] === false ) {\n\t\t\t\tshowControl = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tif ( columns[i].control ) {\n\t\t\t\tdisplay[i] = showControl;\n\t\t\t}\n\n\t\t\t// Replace not visible string with false from the control column detection above\n\t\t\tif ( display[i] === 'not-visible' ) {\n\t\t\t\tdisplay[i] = false;\n\t\t\t}\n\t\t}\n\n\t\t// Finally we need to make sure that there is at least one column that\n\t\t// is visible\n\t\tif ( $.inArray( true, display ) === -1 ) {\n\t\t\tdisplay[0] = true;\n\t\t}\n\n\t\treturn display;\n\t},\n\n\n\t/**\n\t * Create the internal `columns` array with information about the columns\n\t * for the table. This includes determining which breakpoints the column\n\t * will appear in, based upon class names in the column, which makes up the\n\t * vast majority of this method.\n\t *\n\t * @private\n\t */\n\t_classLogic: function ()\n\t{\n\t\tvar that = this;\n\t\tvar calc = {};\n\t\tvar breakpoints = this.c.breakpoints;\n\t\tvar dt = this.s.dt;\n\t\tvar columns = dt.columns().eq(0).map( function (i) {\n\t\t\tvar column = this.column(i);\n\t\t\tvar className = column.header().className;\n\t\t\tvar priority = dt.settings()[0].aoColumns[i].responsivePriority;\n\n\t\t\tif ( priority === undefined ) {\n\t\t\t\tvar dataPriority = $(column.header()).data('priority');\n\n\t\t\t\tpriority = dataPriority !== undefined ?\n\t\t\t\t\tdataPriority * 1 :\n\t\t\t\t\t10000;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tclassName: className,\n\t\t\t\tincludeIn: [],\n\t\t\t\tauto:      false,\n\t\t\t\tcontrol:   false,\n\t\t\t\tnever:     className.match(/\\bnever\\b/) ? true : false,\n\t\t\t\tpriority:  priority\n\t\t\t};\n\t\t} );\n\n\t\t// Simply add a breakpoint to `includeIn` array, ensuring that there are\n\t\t// no duplicates\n\t\tvar add = function ( colIdx, name ) {\n\t\t\tvar includeIn = columns[ colIdx ].includeIn;\n\n\t\t\tif ( $.inArray( name, includeIn ) === -1 ) {\n\t\t\t\tincludeIn.push( name );\n\t\t\t}\n\t\t};\n\n\t\tvar column = function ( colIdx, name, operator, matched ) {\n\t\t\tvar size, i, ien;\n\n\t\t\tif ( ! operator ) {\n\t\t\t\tcolumns[ colIdx ].includeIn.push( name );\n\t\t\t}\n\t\t\telse if ( operator === 'max-' ) {\n\t\t\t\t// Add this breakpoint and all smaller\n\t\t\t\tsize = that._find( name ).width;\n\n\t\t\t\tfor ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( breakpoints[i].width <= size ) {\n\t\t\t\t\t\tadd( colIdx, breakpoints[i].name );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( operator === 'min-' ) {\n\t\t\t\t// Add this breakpoint and all larger\n\t\t\t\tsize = that._find( name ).width;\n\n\t\t\t\tfor ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( breakpoints[i].width >= size ) {\n\t\t\t\t\t\tadd( colIdx, breakpoints[i].name );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( operator === 'not-' ) {\n\t\t\t\t// Add all but this breakpoint\n\t\t\t\tfor ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( breakpoints[i].name.indexOf( matched ) === -1 ) {\n\t\t\t\t\t\tadd( colIdx, breakpoints[i].name );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Loop over each column and determine if it has a responsive control\n\t\t// class\n\t\tcolumns.each( function ( col, i ) {\n\t\t\tvar classNames = col.className.split(' ');\n\t\t\tvar hasClass = false;\n\n\t\t\t// Split the class name up so multiple rules can be applied if needed\n\t\t\tfor ( var k=0, ken=classNames.length ; k<ken ; k++ ) {\n\t\t\t\tvar className = $.trim( classNames[k] );\n\n\t\t\t\tif ( className === 'all' ) {\n\t\t\t\t\t// Include in all\n\t\t\t\t\thasClass = true;\n\t\t\t\t\tcol.includeIn = $.map( breakpoints, function (a) {\n\t\t\t\t\t\treturn a.name;\n\t\t\t\t\t} );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\telse if ( className === 'none' || col.never ) {\n\t\t\t\t\t// Include in none (default) and no auto\n\t\t\t\t\thasClass = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\telse if ( className === 'control' ) {\n\t\t\t\t\t// Special column that is only visible, when one of the other\n\t\t\t\t\t// columns is hidden. This is used for the details control\n\t\t\t\t\thasClass = true;\n\t\t\t\t\tcol.control = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t$.each( breakpoints, function ( j, breakpoint ) {\n\t\t\t\t\t// Does this column have a class that matches this breakpoint?\n\t\t\t\t\tvar brokenPoint = breakpoint.name.split('-');\n\t\t\t\t\tvar re = new RegExp( '(min\\\\-|max\\\\-|not\\\\-)?('+brokenPoint[0]+')(\\\\-[_a-zA-Z0-9])?' );\n\t\t\t\t\tvar match = className.match( re );\n\n\t\t\t\t\tif ( match ) {\n\t\t\t\t\t\thasClass = true;\n\n\t\t\t\t\t\tif ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {\n\t\t\t\t\t\t\t// Class name matches breakpoint name fully\n\t\t\t\t\t\t\tcolumn( i, breakpoint.name, match[1], match[2]+match[3] );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( match[2] === brokenPoint[0] && ! match[3] ) {\n\t\t\t\t\t\t\t// Class name matched primary breakpoint name with no qualifier\n\t\t\t\t\t\t\tcolumn( i, breakpoint.name, match[1], match[2] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// If there was no control class, then automatic sizing is used\n\t\t\tif ( ! hasClass ) {\n\t\t\t\tcol.auto = true;\n\t\t\t}\n\t\t} );\n\n\t\tthis.s.columns = columns;\n\t},\n\n\n\t/**\n\t * Show the details for the child row\n\t *\n\t * @param  {DataTables.Api} row    API instance for the row\n\t * @param  {boolean}        update Update flag\n\t * @private\n\t */\n\t_detailsDisplay: function ( row, update )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar details = this.c.details;\n\n\t\tif ( details && details.type !== false ) {\n\t\t\tvar res = details.display( row, update, function () {\n\t\t\t\treturn details.renderer(\n\t\t\t\t\tdt, row[0], that._detailsObj(row[0])\n\t\t\t\t);\n\t\t\t} );\n\n\t\t\tif ( res === true || res === false ) {\n\t\t\t\t$(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] );\n\t\t\t}\n\t\t}\n\t},\n\n\n\t/**\n\t * Initialisation for the details handler\n\t *\n\t * @private\n\t */\n\t_detailsInit: function ()\n\t{\n\t\tvar that    = this;\n\t\tvar dt      = this.s.dt;\n\t\tvar details = this.c.details;\n\n\t\t// The inline type always uses the first child as the target\n\t\tif ( details.type === 'inline' ) {\n\t\t\tdetails.target = 'td:first-child, th:first-child';\n\t\t}\n\n\t\t// Keyboard accessibility\n\t\tdt.on( 'draw.dtr', function () {\n\t\t\tthat._tabIndexes();\n\t\t} );\n\t\tthat._tabIndexes(); // Initial draw has already happened\n\n\t\t$( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) {\n\t\t\tif ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) {\n\t\t\t\t$(this).click();\n\t\t\t}\n\t\t} );\n\n\t\t// type.target can be a string jQuery selector or a column index\n\t\tvar target   = details.target;\n\t\tvar selector = typeof target === 'string' ? target : 'td, th';\n\n\t\t// Click handler to show / hide the details rows when they are available\n\t\t$( dt.table().body() )\n\t\t\t.on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) {\n\t\t\t\t// If the table is not collapsed (i.e. there is no hidden columns)\n\t\t\t\t// then take no action\n\t\t\t\tif ( ! $(dt.table().node()).hasClass('collapsed' ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Check that the row is actually a DataTable's controlled node\n\t\t\t\tif ( $.inArray( $(this).closest('tr').get(0), dt.rows().nodes().toArray() ) === -1 ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// For column index, we determine if we should act or not in the\n\t\t\t\t// handler - otherwise it is already okay\n\t\t\t\tif ( typeof target === 'number' ) {\n\t\t\t\t\tvar targetIdx = target < 0 ?\n\t\t\t\t\t\tdt.columns().eq(0).length + target :\n\t\t\t\t\t\ttarget;\n\n\t\t\t\t\tif ( dt.cell( this ).index().column !== targetIdx ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// $().closest() includes itself in its check\n\t\t\t\tvar row = dt.row( $(this).closest('tr') );\n\n\t\t\t\t// Check event type to do an action\n\t\t\t\tif ( e.type === 'click' ) {\n\t\t\t\t\t// The renderer is given as a function so the caller can execute it\n\t\t\t\t\t// only when they need (i.e. if hiding there is no point is running\n\t\t\t\t\t// the renderer)\n\t\t\t\t\tthat._detailsDisplay( row, false );\n\t\t\t\t}\n\t\t\t\telse if ( e.type === 'mousedown' ) {\n\t\t\t\t\t// For mouse users, prevent the focus ring from showing\n\t\t\t\t\t$(this).css('outline', 'none');\n\t\t\t\t}\n\t\t\t\telse if ( e.type === 'mouseup' ) {\n\t\t\t\t\t// And then re-allow at the end of the click\n\t\t\t\t\t$(this).blur().css('outline', '');\n\t\t\t\t}\n\t\t\t} );\n\t},\n\n\n\t/**\n\t * Get the details to pass to a renderer for a row\n\t * @param  {int} rowIdx Row index\n\t * @private\n\t */\n\t_detailsObj: function ( rowIdx )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\n\t\treturn $.map( this.s.columns, function( col, i ) {\n\t\t\t// Never and control columns should not be passed to the renderer\n\t\t\tif ( col.never || col.control ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttitle:       dt.settings()[0].aoColumns[ i ].sTitle,\n\t\t\t\tdata:        dt.cell( rowIdx, i ).render( that.c.orthogonal ),\n\t\t\t\thidden:      dt.column( i ).visible() && !that.s.current[ i ],\n\t\t\t\tcolumnIndex: i,\n\t\t\t\trowIndex:    rowIdx\n\t\t\t};\n\t\t} );\n\t},\n\n\n\t/**\n\t * Find a breakpoint object from a name\n\t *\n\t * @param  {string} name Breakpoint name to find\n\t * @return {object}      Breakpoint description object\n\t * @private\n\t */\n\t_find: function ( name )\n\t{\n\t\tvar breakpoints = this.c.breakpoints;\n\n\t\tfor ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {\n\t\t\tif ( breakpoints[i].name === name ) {\n\t\t\t\treturn breakpoints[i];\n\t\t\t}\n\t\t}\n\t},\n\n\n\t/**\n\t * Re-create the contents of the child rows as the display has changed in\n\t * some way.\n\t *\n\t * @private\n\t */\n\t_redrawChildren: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\n\t\tdt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {\n\t\t\tvar row = dt.row( idx );\n\n\t\t\tthat._detailsDisplay( dt.row( idx ), true );\n\t\t} );\n\t},\n\n\n\t/**\n\t * Alter the table display for a resized viewport. This involves first\n\t * determining what breakpoint the window currently is in, getting the\n\t * column visibilities to apply and then setting them.\n\t *\n\t * @private\n\t */\n\t_resize: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar width = $(window).width();\n\t\tvar breakpoints = this.c.breakpoints;\n\t\tvar breakpoint = breakpoints[0].name;\n\t\tvar columns = this.s.columns;\n\t\tvar i, ien;\n\t\tvar oldVis = this.s.current.slice();\n\n\t\t// Determine what breakpoint we are currently at\n\t\tfor ( i=breakpoints.length-1 ; i>=0 ; i-- ) {\n\t\t\tif ( width <= breakpoints[i].width ) {\n\t\t\t\tbreakpoint = breakpoints[i].name;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Show the columns for that break point\n\t\tvar columnsVis = this._columnsVisiblity( breakpoint );\n\t\tthis.s.current = columnsVis;\n\n\t\t// Set the class before the column visibility is changed so event\n\t\t// listeners know what the state is. Need to determine if there are\n\t\t// any columns that are not visible but can be shown\n\t\tvar collapsedClass = false;\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tif ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control && ! dt.column(i).visible() === false ) {\n\t\t\t\tcollapsedClass = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t$( dt.table().node() ).toggleClass( 'collapsed', collapsedClass );\n\n\t\tvar changed = false;\n\t\tvar visible = 0;\n\n\t\tdt.columns().eq(0).each( function ( colIdx, i ) {\n\t\t\tif ( columnsVis[i] === true ) {\n\t\t\t\tvisible++;\n\t\t\t}\n\n\t\t\tif ( columnsVis[i] !== oldVis[i] ) {\n\t\t\t\tchanged = true;\n\t\t\t\tthat._setColumnVis( colIdx, columnsVis[i] );\n\t\t\t}\n\t\t} );\n\n\t\tif ( changed ) {\n\t\t\tthis._redrawChildren();\n\n\t\t\t// Inform listeners of the change\n\t\t\t$(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] );\n\n\t\t\t// If no records, update the \"No records\" display element\n\t\t\tif ( dt.page.info().recordsDisplay === 0 ) {\n\t\t\t\t$('td', dt.table().body()).eq(0).attr('colspan', visible);\n\t\t\t}\n\t\t}\n\t},\n\n\n\t/**\n\t * Determine the width of each column in the table so the auto column hiding\n\t * has that information to work with. This method is never going to be 100%\n\t * perfect since column widths can change slightly per page, but without\n\t * seriously compromising performance this is quite effective.\n\t *\n\t * @private\n\t */\n\t_resizeAuto: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar columns = this.s.columns;\n\n\t\t// Are we allowed to do auto sizing?\n\t\tif ( ! this.c.auto ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Are there any columns that actually need auto-sizing, or do they all\n\t\t// have classes defined\n\t\tif ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Need to restore all children. They will be reinstated by a re-render\n\t\tif ( ! $.isEmptyObject( _childNodeStore ) ) {\n\t\t\t$.each( _childNodeStore, function ( key ) {\n\t\t\t\tvar idx = key.split('-');\n\n\t\t\t\t_childNodesRestore( dt, idx[0]*1, idx[1]*1 );\n\t\t\t} );\n\t\t}\n\n\t\t// Clone the table with the current data in it\n\t\tvar tableWidth   = dt.table().node().offsetWidth;\n\t\tvar columnWidths = dt.columns;\n\t\tvar clonedTable  = dt.table().node().cloneNode( false );\n\t\tvar clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );\n\t\tvar clonedBody   = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8\n\n\t\t// Header\n\t\tvar headerCells = dt.columns()\n\t\t\t.header()\n\t\t\t.filter( function (idx) {\n\t\t\t\treturn dt.column(idx).visible();\n\t\t\t} )\n\t\t\t.to$()\n\t\t\t.clone( false )\n\t\t\t.css( 'display', 'table-cell' )\n\t\t\t.css( 'min-width', 0 );\n\n\t\t// Body rows - we don't need to take account of DataTables' column\n\t\t// visibility since we implement our own here (hence the `display` set)\n\t\t$(clonedBody)\n\t\t\t.append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) )\n\t\t\t.find( 'th, td' ).css( 'display', '' );\n\n\t\t// Footer\n\t\tvar footer = dt.table().footer();\n\t\tif ( footer ) {\n\t\t\tvar clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable );\n\t\t\tvar footerCells = dt.columns()\n\t\t\t\t.footer()\n\t\t\t\t.filter( function (idx) {\n\t\t\t\t\treturn dt.column(idx).visible();\n\t\t\t\t} )\n\t\t\t\t.to$()\n\t\t\t\t.clone( false )\n\t\t\t\t.css( 'display', 'table-cell' );\n\n\t\t\t$('<tr/>')\n\t\t\t\t.append( footerCells )\n\t\t\t\t.appendTo( clonedFooter );\n\t\t}\n\n\t\t$('<tr/>')\n\t\t\t.append( headerCells )\n\t\t\t.appendTo( clonedHeader );\n\n\t\t// In the inline case extra padding is applied to the first column to\n\t\t// give space for the show / hide icon. We need to use this in the\n\t\t// calculation\n\t\tif ( this.c.details.type === 'inline' ) {\n\t\t\t$(clonedTable).addClass( 'dtr-inline collapsed' );\n\t\t}\n\t\t\n\t\t// It is unsafe to insert elements with the same name into the DOM\n\t\t// multiple times. For example, cloning and inserting a checked radio\n\t\t// clears the chcecked state of the original radio.\n\t\t$( clonedTable ).find( '[name]' ).removeAttr( 'name' );\n\n\t\t// A position absolute table would take the table out of the flow of\n\t\t// our container element, bypassing the height and width (Scroller)\n\t\t$( clonedTable ).css( 'position', 'relative' )\n\t\t\n\t\tvar inserted = $('<div/>')\n\t\t\t.css( {\n\t\t\t\twidth: 1,\n\t\t\t\theight: 1,\n\t\t\t\toverflow: 'hidden',\n\t\t\t\tclear: 'both'\n\t\t\t} )\n\t\t\t.append( clonedTable );\n\n\t\tinserted.insertBefore( dt.table().node() );\n\n\t\t// The cloned header now contains the smallest that each column can be\n\t\theaderCells.each( function (i) {\n\t\t\tvar idx = dt.column.index( 'fromVisible', i );\n\t\t\tcolumns[ idx ].minWidth =  this.offsetWidth || 0;\n\t\t} );\n\n\t\tinserted.remove();\n\t},\n\n\t/**\n\t * Set a column's visibility.\n\t *\n\t * We don't use DataTables' column visibility controls in order to ensure\n\t * that column visibility can Responsive can no-exist. Since only IE8+ is\n\t * supported (and all evergreen browsers of course) the control of the\n\t * display attribute works well.\n\t *\n\t * @param {integer} col      Column index\n\t * @param {boolean} showHide Show or hide (true or false)\n\t * @private\n\t */\n\t_setColumnVis: function ( col, showHide )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar display = showHide ? '' : 'none'; // empty string will remove the attr\n\n\t\t$( dt.column( col ).header() ).css( 'display', display );\n\t\t$( dt.column( col ).footer() ).css( 'display', display );\n\t\tdt.column( col ).nodes().to$().css( 'display', display );\n\n\t\t// If the are child nodes stored, we might need to reinsert them\n\t\tif ( ! $.isEmptyObject( _childNodeStore ) ) {\n\t\t\tdt.cells( null, col ).indexes().each( function (idx) {\n\t\t\t\t_childNodesRestore( dt, idx.row, idx.column );\n\t\t\t} );\n\t\t}\n\t},\n\n\n\t/**\n\t * Update the cell tab indexes for keyboard accessibility. This is called on\n\t * every table draw - that is potentially inefficient, but also the least\n\t * complex option given that column visibility can change on the fly. Its a\n\t * shame user-focus was removed from CSS 3 UI, as it would have solved this\n\t * issue with a single CSS statement.\n\t *\n\t * @private\n\t */\n\t_tabIndexes: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar cells = dt.cells( { page: 'current' } ).nodes().to$();\n\t\tvar ctx = dt.settings()[0];\n\t\tvar target = this.c.details.target;\n\n\t\tcells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );\n\n\t\tif ( typeof target === 'number' ) {\n\t\t\tdt.cells( null, target, { page: 'current' } ).nodes().to$()\n\t\t\t\t.attr( 'tabIndex', ctx.iTabIndex )\n\t\t\t\t.data( 'dtr-keyboard', 1 );\n\t\t}\n\t\telse {\n\t\t\t// This is a bit of a hack - we need to limit the selected nodes to just\n\t\t\t// those of this table\n\t\t\tif ( target === 'td:first-child, th:first-child' ) {\n\t\t\t\ttarget = '>td:first-child, >th:first-child';\n\t\t\t}\n\n\t\t\t$( target, dt.rows( { page: 'current' } ).nodes() )\n\t\t\t\t.attr( 'tabIndex', ctx.iTabIndex )\n\t\t\t\t.data( 'dtr-keyboard', 1 );\n\t\t}\n\t}\n} );\n\n\n/**\n * List of default breakpoints. Each item in the array is an object with two\n * properties:\n *\n * * `name` - the breakpoint name.\n * * `width` - the breakpoint width\n *\n * @name Responsive.breakpoints\n * @static\n */\nResponsive.breakpoints = [\n\t{ name: 'desktop',  width: Infinity },\n\t{ name: 'tablet-l', width: 1024 },\n\t{ name: 'tablet-p', width: 768 },\n\t{ name: 'mobile-l', width: 480 },\n\t{ name: 'mobile-p', width: 320 }\n];\n\n\n/**\n * Display methods - functions which define how the hidden data should be shown\n * in the table.\n *\n * @namespace\n * @name Responsive.defaults\n * @static\n */\nResponsive.display = {\n\tchildRow: function ( row, update, render ) {\n\t\tif ( update ) {\n\t\t\tif ( $(row.node()).hasClass('parent') ) {\n\t\t\t\trow.child( render(), 'child' ).show();\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif ( ! row.child.isShown()  ) {\n\t\t\t\trow.child( render(), 'child' ).show();\n\t\t\t\t$( row.node() ).addClass( 'parent' );\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse {\n\t\t\t\trow.child( false );\n\t\t\t\t$( row.node() ).removeClass( 'parent' );\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t},\n\n\tchildRowImmediate: function ( row, update, render ) {\n\t\tif ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {\n\t\t\t// User interaction and the row is show, or nothing to show\n\t\t\trow.child( false );\n\t\t\t$( row.node() ).removeClass( 'parent' );\n\n\t\t\treturn false;\n\t\t}\n\t\telse {\n\t\t\t// Display\n\t\t\trow.child( render(), 'child' ).show();\n\t\t\t$( row.node() ).addClass( 'parent' );\n\n\t\t\treturn true;\n\t\t}\n\t},\n\n\t// This is a wrapper so the modal options for Bootstrap and jQuery UI can\n\t// have options passed into them. This specific one doesn't need to be a\n\t// function but it is for consistency in the `modal` name\n\tmodal: function ( options ) {\n\t\treturn function ( row, update, render ) {\n\t\t\tif ( ! update ) {\n\t\t\t\t// Show a modal\n\t\t\t\tvar close = function () {\n\t\t\t\t\tmodal.remove(); // will tidy events for us\n\t\t\t\t\t$(document).off( 'keypress.dtr' );\n\t\t\t\t};\n\n\t\t\t\tvar modal = $('<div class=\"dtr-modal\"/>')\n\t\t\t\t\t.append( $('<div class=\"dtr-modal-display\"/>')\n\t\t\t\t\t\t.append( $('<div class=\"dtr-modal-content\"/>')\n\t\t\t\t\t\t\t.append( render() )\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.append( $('<div class=\"dtr-modal-close\">&times;</div>' )\n\t\t\t\t\t\t\t.click( function () {\n\t\t\t\t\t\t\t\tclose();\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t.append( $('<div class=\"dtr-modal-background\"/>')\n\t\t\t\t\t\t.click( function () {\n\t\t\t\t\t\t\tclose();\n\t\t\t\t\t\t} )\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo( 'body' );\n\n\t\t\t\t$(document).on( 'keyup.dtr', function (e) {\n\t\t\t\t\tif ( e.keyCode === 27 ) {\n\t\t\t\t\t\te.stopPropagation();\n\n\t\t\t\t\t\tclose();\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$('div.dtr-modal-content')\n\t\t\t\t\t.empty()\n\t\t\t\t\t.append( render() );\n\t\t\t}\n\n\t\t\tif ( options && options.header ) {\n\t\t\t\t$('div.dtr-modal-content').prepend(\n\t\t\t\t\t'<h2>'+options.header( row )+'</h2>'\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\t}\n};\n\n\nvar _childNodeStore = {};\n\nfunction _childNodes( dt, row, col ) {\n\tvar name = row+'-'+col;\n\n\tif ( _childNodeStore[ name ] ) {\n\t\treturn _childNodeStore[ name ];\n\t}\n\n\t// https://jsperf.com/childnodes-array-slice-vs-loop\n\tvar nodes = [];\n\tvar children = dt.cell( row, col ).node().childNodes;\n\tfor ( var i=0, ien=children.length ; i<ien ; i++ ) {\n\t\tnodes.push( children[i] );\n\t}\n\n\t_childNodeStore[ name ] = nodes;\n\n\treturn nodes;\n}\n\nfunction _childNodesRestore( dt, row, col ) {\n\tvar name = row+'-'+col;\n\n\tif ( ! _childNodeStore[ name ] ) {\n\t\treturn;\n\t}\n\n\tvar node = dt.cell( row, col ).node();\n\tvar store = _childNodeStore[ name ];\n\tvar parent = store[0].parentNode;\n\tvar parentChildren = parent.childNodes;\n\tvar a = [];\n\n\tfor ( var i=0, ien=parentChildren.length ; i<ien ; i++ ) {\n\t\ta.push( parentChildren[i] );\n\t}\n\n\tfor ( var j=0, jen=a.length ; j<jen ; j++ ) {\n\t\tnode.appendChild( a[j] );\n\t}\n\n\t_childNodeStore[ name ] = undefined;\n}\n\n\n/**\n * Display methods - functions which define how the hidden data should be shown\n * in the table.\n *\n * @namespace\n * @name Responsive.defaults\n * @static\n */\nResponsive.renderer = {\n\tlistHiddenNodes: function () {\n\t\treturn function ( api, rowIdx, columns ) {\n\t\t\tvar ul = $('<ul data-dtr-index=\"'+rowIdx+'\" class=\"dtr-details\"/>');\n\t\t\tvar found = false;\n\n\t\t\tvar data = $.each( columns, function ( i, col ) {\n\t\t\t\tif ( col.hidden ) {\n\t\t\t\t\t$(\n\t\t\t\t\t\t'<li data-dtr-index=\"'+col.columnIndex+'\" data-dt-row=\"'+col.rowIndex+'\" data-dt-column=\"'+col.columnIndex+'\">'+\n\t\t\t\t\t\t\t'<span class=\"dtr-title\">'+\n\t\t\t\t\t\t\t\tcol.title+\n\t\t\t\t\t\t\t'</span> '+\n\t\t\t\t\t\t'</li>'\n\t\t\t\t\t)\n\t\t\t\t\t\t.append( $('<span class=\"dtr-data\"/>').append( _childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) )\n\t\t\t\t\t\t.appendTo( ul );\n\n\t\t\t\t\tfound = true;\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\treturn found ?\n\t\t\t\tul :\n\t\t\t\tfalse;\n\t\t};\n\t},\n\n\tlistHidden: function () {\n\t\treturn function ( api, rowIdx, columns ) {\n\t\t\tvar data = $.map( columns, function ( col ) {\n\t\t\t\treturn col.hidden ?\n\t\t\t\t\t'<li data-dtr-index=\"'+col.columnIndex+'\" data-dt-row=\"'+col.rowIndex+'\" data-dt-column=\"'+col.columnIndex+'\">'+\n\t\t\t\t\t\t'<span class=\"dtr-title\">'+\n\t\t\t\t\t\t\tcol.title+\n\t\t\t\t\t\t'</span> '+\n\t\t\t\t\t\t'<span class=\"dtr-data\">'+\n\t\t\t\t\t\t\tcol.data+\n\t\t\t\t\t\t'</span>'+\n\t\t\t\t\t'</li>' :\n\t\t\t\t\t'';\n\t\t\t} ).join('');\n\n\t\t\treturn data ?\n\t\t\t\t$('<ul data-dtr-index=\"'+rowIdx+'\" class=\"dtr-details\"/>').append( data ) :\n\t\t\t\tfalse;\n\t\t}\n\t},\n\n\ttableAll: function ( options ) {\n\t\toptions = $.extend( {\n\t\t\ttableClass: ''\n\t\t}, options );\n\n\t\treturn function ( api, rowIdx, columns ) {\n\t\t\tvar data = $.map( columns, function ( col ) {\n\t\t\t\treturn '<tr data-dt-row=\"'+col.rowIndex+'\" data-dt-column=\"'+col.columnIndex+'\">'+\n\t\t\t\t\t\t'<td>'+col.title+':'+'</td> '+\n\t\t\t\t\t\t'<td>'+col.data+'</td>'+\n\t\t\t\t\t'</tr>';\n\t\t\t} ).join('');\n\n\t\t\treturn $('<table class=\"'+options.tableClass+' dtr-details\" width=\"100%\"/>').append( data );\n\t\t}\n\t}\n};\n\n/**\n * Responsive default settings for initialisation\n *\n * @namespace\n * @name Responsive.defaults\n * @static\n */\nResponsive.defaults = {\n\t/**\n\t * List of breakpoints for the instance. Note that this means that each\n\t * instance can have its own breakpoints. Additionally, the breakpoints\n\t * cannot be changed once an instance has been creased.\n\t *\n\t * @type {Array}\n\t * @default Takes the value of `Responsive.breakpoints`\n\t */\n\tbreakpoints: Responsive.breakpoints,\n\n\t/**\n\t * Enable / disable auto hiding calculations. It can help to increase\n\t * performance slightly if you disable this option, but all columns would\n\t * need to have breakpoint classes assigned to them\n\t *\n\t * @type {Boolean}\n\t * @default  `true`\n\t */\n\tauto: true,\n\n\t/**\n\t * Details control. If given as a string value, the `type` property of the\n\t * default object is set to that value, and the defaults used for the rest\n\t * of the object - this is for ease of implementation.\n\t *\n\t * The object consists of the following properties:\n\t *\n\t * * `display` - A function that is used to show and hide the hidden details\n\t * * `renderer` - function that is called for display of the child row data.\n\t *   The default function will show the data from the hidden columns\n\t * * `target` - Used as the selector for what objects to attach the child\n\t *   open / close to\n\t * * `type` - `false` to disable the details display, `inline` or `column`\n\t *   for the two control types\n\t *\n\t * @type {Object|string}\n\t */\n\tdetails: {\n\t\tdisplay: Responsive.display.childRow,\n\n\t\trenderer: Responsive.renderer.listHidden(),\n\n\t\ttarget: 0,\n\n\t\ttype: 'inline'\n\t},\n\n\t/**\n\t * Orthogonal data request option. This is used to define the data type\n\t * requested when Responsive gets the data to show in the child row.\n\t *\n\t * @type {String}\n\t */\n\torthogonal: 'display'\n};\n\n\n/*\n * API\n */\nvar Api = $.fn.dataTable.Api;\n\n// Doesn't do anything - work around for a bug in DT... Not documented\nApi.register( 'responsive()', function () {\n\treturn this;\n} );\n\nApi.register( 'responsive.index()', function ( li ) {\n\tli = $(li);\n\n\treturn {\n\t\tcolumn: li.data('dtr-index'),\n\t\trow:    li.parent().data('dtr-index')\n\t};\n} );\n\nApi.register( 'responsive.rebuild()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx._responsive ) {\n\t\t\tctx._responsive._classLogic();\n\t\t}\n\t} );\n} );\n\nApi.register( 'responsive.recalc()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx._responsive ) {\n\t\t\tctx._responsive._resizeAuto();\n\t\t\tctx._responsive._resize();\n\t\t}\n\t} );\n} );\n\nApi.register( 'responsive.hasHidden()', function () {\n\tvar ctx = this.context[0];\n\n\treturn ctx._responsive ?\n\t\t$.inArray( false, ctx._responsive.s.current ) !== -1 :\n\t\tfalse;\n} );\n\nApi.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () {\n\treturn this.iterator( 'column', function ( settings, column ) {\n\t\treturn settings._responsive ?\n\t\t\tsettings._responsive.s.current[ column ] :\n\t\t\tfalse;\n\t}, 1 );\n} );\n\n\n/**\n * Version information\n *\n * @name Responsive.version\n * @static\n */\nResponsive.version = '2.2.2';\n\n\n$.fn.dataTable.Responsive = Responsive;\n$.fn.DataTable.Responsive = Responsive;\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'preInit.dt.dtr', function (e, settings, json) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tif ( $(settings.nTable).hasClass( 'responsive' ) ||\n\t\t $(settings.nTable).hasClass( 'dt-responsive' ) ||\n\t\t settings.oInit.responsive ||\n\t\t DataTable.defaults.responsive\n\t) {\n\t\tvar init = settings.oInit.responsive;\n\n\t\tif ( init !== false ) {\n\t\t\tnew Responsive( settings, $.isPlainObject( init ) ? init : {}  );\n\t\t}\n\t}\n} );\n\n\nreturn Responsive;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Responsive-2.2.2/js/responsive.bootstrap.js",
    "content": "/*! Bootstrap integration for DataTables' Responsive\n * ©2015-2016 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs', 'datatables.net-responsive'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Responsive ) {\n\t\t\t\trequire('datatables.net-responsive')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar _display = DataTable.Responsive.display;\nvar _original = _display.modal;\nvar _modal = $(\n\t'<div class=\"modal fade dtr-bs-modal\" role=\"dialog\">'+\n\t\t'<div class=\"modal-dialog\" role=\"document\">'+\n\t\t\t'<div class=\"modal-content\">'+\n\t\t\t\t'<div class=\"modal-header\">'+\n\t\t\t\t\t'<button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>'+\n\t\t\t\t'</div>'+\n\t\t\t\t'<div class=\"modal-body\"/>'+\n\t\t\t'</div>'+\n\t\t'</div>'+\n\t'</div>'\n);\n\n_display.modal = function ( options ) {\n\treturn function ( row, update, render ) {\n\t\tif ( ! $.fn.modal ) {\n\t\t\t_original( row, update, render );\n\t\t}\n\t\telse {\n\t\t\tif ( ! update ) {\n\t\t\t\tif ( options && options.header ) {\n\t\t\t\t\tvar header = _modal.find('div.modal-header');\n\t\t\t\t\tvar button = header.find('button').detach();\n\t\t\t\t\t\n\t\t\t\t\theader\n\t\t\t\t\t\t.empty()\n\t\t\t\t\t\t.append( '<h4 class=\"modal-title\">'+options.header( row )+'</h4>' )\n\t\t\t\t\t\t.prepend( button );\n\t\t\t\t}\n\n\t\t\t\t_modal.find( 'div.modal-body' )\n\t\t\t\t\t.empty()\n\t\t\t\t\t.append( render() );\n\n\t\t\t\t_modal\n\t\t\t\t\t.appendTo( 'body' )\n\t\t\t\t\t.modal();\n\t\t\t}\n\t\t}\n\t};\n};\n\n\nreturn DataTable.Responsive;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Responsive-2.2.2/js/responsive.bootstrap4.js",
    "content": "/*! Bootstrap 4 integration for DataTables' Responsive\n * ©2016 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs4', 'datatables.net-responsive'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs4')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Responsive ) {\n\t\t\t\trequire('datatables.net-responsive')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar _display = DataTable.Responsive.display;\nvar _original = _display.modal;\nvar _modal = $(\n\t'<div class=\"modal fade dtr-bs-modal\" role=\"dialog\">'+\n\t\t'<div class=\"modal-dialog\" role=\"document\">'+\n\t\t\t'<div class=\"modal-content\">'+\n\t\t\t\t'<div class=\"modal-header\">'+\n\t\t\t\t\t'<button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>'+\n\t\t\t\t'</div>'+\n\t\t\t\t'<div class=\"modal-body\"/>'+\n\t\t\t'</div>'+\n\t\t'</div>'+\n\t'</div>'\n);\n\n_display.modal = function ( options ) {\n\treturn function ( row, update, render ) {\n\t\tif ( ! $.fn.modal ) {\n\t\t\t_original( row, update, render );\n\t\t}\n\t\telse {\n\t\t\tif ( ! update ) {\n\t\t\t\tif ( options && options.header ) {\n\t\t\t\t\tvar header = _modal.find('div.modal-header');\n\t\t\t\t\tvar button = header.find('button').detach();\n\t\t\t\t\t\n\t\t\t\t\theader\n\t\t\t\t\t\t.empty()\n\t\t\t\t\t\t.append( '<h4 class=\"modal-title\">'+options.header( row )+'</h4>' )\n\t\t\t\t\t\t.append( button );\n\t\t\t\t}\n\n\t\t\t\t_modal.find( 'div.modal-body' )\n\t\t\t\t\t.empty()\n\t\t\t\t\t.append( render() );\n\n\t\t\t\t_modal\n\t\t\t\t\t.appendTo( 'body' )\n\t\t\t\t\t.modal();\n\t\t\t}\n\t\t}\n\t};\n};\n\n\nreturn DataTable.Responsive;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Responsive-2.2.2/js/responsive.foundation.js",
    "content": "/*! Foundation integration for DataTables' Responsive\n * ©2015 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-zf', 'datatables.net-responsive'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-zf')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Responsive ) {\n\t\t\t\trequire('datatables.net-responsive')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar _display = DataTable.Responsive.display;\nvar _original = _display.modal;\n\n_display.modal = function ( options ) {\n\treturn function ( row, update, render ) {\n\t\tif ( ! $.fn.foundation ) {\n\t\t\t_original( row, update, render );\n\t\t}\n\t\telse {\n\t\t\tif ( ! update ) {\n\t\t\t\t$( '<div class=\"reveal-modal\" data-reveal/>' )\n\t\t\t\t\t.append( '<a class=\"close-reveal-modal\" aria-label=\"Close\">&#215;</a>' )\n\t\t\t\t\t.append( options && options.header ? '<h4>'+options.header( row )+'</h4>' : null )\n\t\t\t\t\t.append( render() )\n\t\t\t\t\t.appendTo( 'body' )\n\t\t\t\t\t.foundation( 'reveal', 'open' );\n\t\t\t}\n\t\t}\n\t};\n};\n\n\nreturn DataTable.Responsive;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Responsive-2.2.2/js/responsive.jqueryui.js",
    "content": "/*! jQuery UI integration for DataTables' Responsive\n * ©2015 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-jqui', 'datatables.net-responsive'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-jqui')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Responsive ) {\n\t\t\t\trequire('datatables.net-responsive')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar _display = DataTable.Responsive.display;\nvar _original = _display.modal;\n\n_display.modal = function ( options ) {\n\treturn function ( row, update, render ) {\n\t\tif ( ! $.fn.dialog ) {\n\t\t\t_original( row, update, render );\n\t\t}\n\t\telse {\n\t\t\tif ( ! update ) {\n\t\t\t\t$( '<div/>' )\n\t\t\t\t\t.append( render() )\n\t\t\t\t\t.appendTo( 'body' )\n\t\t\t\t\t.dialog( $.extend( true, {\n\t\t\t\t\t\ttitle: options && options.header ? options.header( row ) : '',\n\t\t\t\t\t\twidth: 500\n\t\t\t\t\t}, options.dialog ) );\n\t\t\t}\n\t\t}\n\t};\n};\n\n\nreturn DataTable.Responsive;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Responsive-2.2.2/js/responsive.semanticui.js",
    "content": "/*! Bootstrap integration for DataTables' Responsive\n * ©2015-2016 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-se', 'datatables.net-responsive'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-se')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Responsive ) {\n\t\t\t\trequire('datatables.net-responsive')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar _display = DataTable.Responsive.display;\nvar _original = _display.modal;\nvar _modal = $(\n\t'<div class=\"ui modal\" role=\"dialog\">'+\n\t\t'<div class=\"header\">'+\n\t\t\t'<button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>'+\n\t\t'</div>'+\n\t\t'<div class=\"content\"/>'+\n\t'</div>'\n);\n\n_display.modal = function ( options ) {\n\treturn function ( row, update, render ) {\n\t\tif ( ! $.fn.modal ) {\n\t\t\t_original( row, update, render );\n\t\t}\n\t\telse {\n\t\t\tif ( ! update ) {\n\t\t\t\tif ( options && options.header ) {\n\t\t\t\t\t_modal.find('div.header')\n\t\t\t\t\t\t.empty()\n\t\t\t\t\t\t.append( '<h4 class=\"title\">'+options.header( row )+'</h4>' );\n\t\t\t\t}\n\n\t\t\t\t_modal.find( 'div.content' )\n\t\t\t\t\t.empty()\n\t\t\t\t\t.append( render() );\n\n\t\t\t\t_modal\n\t\t\t\t\t.appendTo( 'body' )\n\t\t\t\t\t.modal('show');\n\t\t\t}\n\t\t}\n\t};\n};\n\n\nreturn DataTable.Responsive;\n}));\n"
  },
  {
    "path": "static/js/DataTables/RowGroup-1.1.0/css/rowGroup.bootstrap.css",
    "content": "table.dataTable tr.dtrg-group td {\n  background-color: #e0e0e0;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-0 td {\n  font-weight: bold;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-1 td,\ntable.dataTable tr.dtrg-group.dtrg-level-2 td {\n  background-color: #f0f0f0;\n  padding-top: 0.25em;\n  padding-bottom: 0.25em;\n  padding-left: 2em;\n  font-size: 0.9em;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-2 td {\n  background-color: #f3f3f3;\n}\n"
  },
  {
    "path": "static/js/DataTables/RowGroup-1.1.0/css/rowGroup.bootstrap4.css",
    "content": "table.dataTable tr.dtrg-group td {\n  background-color: #e0e0e0;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-0 td {\n  font-weight: bold;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-1 td,\ntable.dataTable tr.dtrg-group.dtrg-level-2 td {\n  background-color: #f0f0f0;\n  padding-top: 0.25em;\n  padding-bottom: 0.25em;\n  padding-left: 2em;\n  font-size: 0.9em;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-2 td {\n  background-color: #f3f3f3;\n}\n"
  },
  {
    "path": "static/js/DataTables/RowGroup-1.1.0/css/rowGroup.dataTables.css",
    "content": "table.dataTable tr.dtrg-group td {\n  background-color: #e0e0e0;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-0 td {\n  font-weight: bold;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-1 td,\ntable.dataTable tr.dtrg-group.dtrg-level-2 td {\n  background-color: #f0f0f0;\n  padding-top: 0.25em;\n  padding-bottom: 0.25em;\n  padding-left: 2em;\n  font-size: 0.9em;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-2 td {\n  background-color: #f3f3f3;\n}\n"
  },
  {
    "path": "static/js/DataTables/RowGroup-1.1.0/css/rowGroup.foundation.css",
    "content": "table.dataTable tr.dtrg-group td {\n  background-color: #e0e0e0;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-0 td {\n  font-weight: bold;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-1 td,\ntable.dataTable tr.dtrg-group.dtrg-level-2 td {\n  background-color: #f0f0f0;\n  padding-top: 0.25em;\n  padding-bottom: 0.25em;\n  padding-left: 2em;\n  font-size: 0.9em;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-2 td {\n  background-color: #f3f3f3;\n}\n"
  },
  {
    "path": "static/js/DataTables/RowGroup-1.1.0/css/rowGroup.jqueryui.css",
    "content": "table.dataTable tr.dtrg-group td {\n  background-color: #e0e0e0;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-0 td {\n  font-weight: bold;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-1 td,\ntable.dataTable tr.dtrg-group.dtrg-level-2 td {\n  background-color: #f0f0f0;\n  padding-top: 0.25em;\n  padding-bottom: 0.25em;\n  padding-left: 2em;\n  font-size: 0.9em;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-2 td {\n  background-color: #f3f3f3;\n}\n"
  },
  {
    "path": "static/js/DataTables/RowGroup-1.1.0/css/rowGroup.semanticui.css",
    "content": "table.dataTable tr.dtrg-group td {\n  background-color: #F9FAFB;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-0 td {\n  font-weight: bold;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-1 td,\ntable.dataTable tr.dtrg-group.dtrg-level-2 td {\n  background-color: #f0f0f0;\n  padding-top: 0.25em;\n  padding-bottom: 0.25em;\n  padding-left: 2em;\n  font-size: 0.9em;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-2 td {\n  background-color: #f3f3f3;\n}\n"
  },
  {
    "path": "static/js/DataTables/RowGroup-1.1.0/js/dataTables.rowGroup.js",
    "content": "/*! RowGroup 1.1.0\n * ©2017-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     RowGroup\n * @description RowGrouping for DataTables\n * @version     1.1.0\n * @file        dataTables.rowGroup.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     datatables.net\n * @copyright   Copyright 2017-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar RowGroup = function ( dt, opts ) {\n\t// Sanity check that we are using DataTables 1.10 or newer\n\tif ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {\n\t\tthrow 'RowGroup requires DataTables 1.10.8 or newer';\n\t}\n\n\t// User and defaults configuration object\n\tthis.c = $.extend( true, {},\n\t\tDataTable.defaults.rowGroup,\n\t\tRowGroup.defaults,\n\t\topts\n\t);\n\n\t// Internal settings\n\tthis.s = {\n\t\tdt: new DataTable.Api( dt )\n\t};\n\n\t// DOM items\n\tthis.dom = {\n\n\t};\n\n\t// Check if row grouping has already been initialised on this table\n\tvar settings = this.s.dt.settings()[0];\n\tvar existing = settings.rowGroup;\n\tif ( existing ) {\n\t\treturn existing;\n\t}\n\n\tsettings.rowGroup = this;\n\tthis._constructor();\n};\n\n\n$.extend( RowGroup.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * API methods for DataTables API interface\n\t */\n\n\t/**\n\t * Get/set the grouping data source - need to call draw after this is\n\t * executed as a setter\n\t * @returns string~RowGroup\n\t */\n\tdataSrc: function ( val )\n\t{\n\t\tif ( val === undefined ) {\n\t\t\treturn this.c.dataSrc;\n\t\t}\n\n\t\tvar dt = this.s.dt;\n\n\t\tthis.c.dataSrc = val;\n\n\t\t$(dt.table().node()).triggerHandler( 'rowgroup-datasrc.dt', [ dt, val ] );\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Disable - need to call draw after this is executed\n\t * @returns RowGroup\n\t */\n\tdisable: function ()\n\t{\n\t\tthis.c.enable = false;\n\t\treturn this;\n\t},\n\n\t/**\n\t * Enable - need to call draw after this is executed\n\t * @returns RowGroup\n\t */\n\tenable: function ( flag )\n\t{\n\t\tif ( flag === false ) {\n\t\t\treturn this.disable();\n\t\t}\n\n\t\tthis.c.enable = true;\n\t\treturn this;\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\t_constructor: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\n\t\tdt.on( 'draw.dtrg', function () {\n\t\t\tif ( that.c.enable ) {\n\t\t\t\tthat._draw();\n\t\t\t}\n\t\t} );\n\n\t\tdt.on( 'column-visibility.dt.dtrg responsive-resize.dt.dtrg', function () {\n\t\t\tthat._adjustColspan();\n\t\t} );\n\n\t\tdt.on( 'destroy', function () {\n\t\t\tdt.off( '.dtrg' );\n\t\t} );\n\n\t\tdt.on('responsive-resize.dt', function () {\n\t\t\tthat._adjustColspan();\n\t\t})\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\n\t/**\n\t * Adjust column span when column visibility changes\n\t * @private\n\t */\n\t_adjustColspan: function ()\n\t{\n\t\t$( 'tr.'+this.c.className, this.s.dt.table().body() ).find('td')\n\t\t\t.attr( 'colspan', this._colspan() );\n\t},\n\n\t/**\n\t * Get the number of columns that a grouping row should span\n\t * @private\n\t */\n\t_colspan: function ()\n\t{\n\t\treturn this.s.dt.columns().visible().reduce( function (a, b) {\n\t\t\treturn a + b;\n\t\t}, 0 );\n\t},\n\n\n\t/**\n\t * Update function that is called whenever we need to draw the grouping rows.\n\t * This is basically a bootstrap for the self iterative _group and _groupDisplay\n\t * methods\n\t * @private\n\t */\n\t_draw: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar groupedRows = this._group( 0, dt.rows( { page: 'current' } ).indexes() );\n\n\t\tthis._groupDisplay( 0, groupedRows );\n\t},\n\n\t/**\n\t * Get the grouping information from a data set (index) of rows\n\t * @param {number} level Nesting level\n\t * @param {DataTables.Api} rows API of the rows to consider for this group\n\t * @returns {object[]} Nested grouping information - it is structured like this:\n\t *\t{\n\t *\t\tdataPoint: 'Edinburgh',\n\t *\t\trows: [ 1,2,3,4,5,6,7 ],\n\t *\t\tchildren: [ {\n\t *\t\t\tdataPoint: 'developer'\n\t *\t\t\trows: [ 1, 2, 3 ]\n\t *\t\t},\n\t *\t\t{\n\t *\t\t\tdataPoint: 'support',\n\t *\t\t\trows: [ 4, 5, 6, 7 ]\n\t *\t\t} ]\n\t *\t}\n\t * @private\n\t */\n\t_group: function ( level, rows ) {\n\t\tvar fns = $.isArray( this.c.dataSrc ) ? this.c.dataSrc : [ this.c.dataSrc ];\n\t\tvar fn = DataTable.ext.oApi._fnGetObjectDataFn( fns[ level ] );\n\t\tvar dt = this.s.dt;\n\t\tvar group, last;\n\t\tvar data = [];\n\n\t\tfor ( var i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\tvar rowIndex = rows[i];\n\t\t\tvar rowData = dt.row( rowIndex ).data();\n\t\t\tvar group = fn( rowData );\n\n\t\t\tif ( group === null || group === undefined ) {\n\t\t\t\tgroup = that.c.emptyDataGroup;\n\t\t\t}\n\t\t\t\n\t\t\tif ( last === undefined || group !== last ) {\n\t\t\t\tdata.push( {\n\t\t\t\t\tdataPoint: group,\n\t\t\t\t\trows: []\n\t\t\t\t} );\n\n\t\t\t\tlast = group;\n\t\t\t}\n\n\t\t\tdata[ data.length-1 ].rows.push( rowIndex );\n\t\t}\n\n\t\tif ( fns[ level+1 ] !== undefined ) {\n\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\tdata[i].children = this._group( level+1, data[i].rows );\n\t\t\t}\n\t\t}\n\n\t\treturn data;\n\t},\n\n\t/**\n\t * Row group display - insert the rows into the document\n\t * @param {number} level Nesting level\n\t * @param {object[]} groups Takes the nested array from `_group`\n\t * @private\n\t */\n\t_groupDisplay: function ( level, groups )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar display;\n\t\n\t\tfor ( var i=0, ien=groups.length ; i<ien ; i++ ) {\n\t\t\tvar group = groups[i];\n\t\t\tvar groupName = group.dataPoint;\n\t\t\tvar row;\n\t\t\tvar rows = group.rows;\n\n\t\t\tif ( this.c.startRender ) {\n\t\t\t\tdisplay = this.c.startRender.call( this, dt.rows(rows), groupName, level );\n\t\t\t\trow = this._rowWrap( display, this.c.startClassName, level );\n\n\t\t\t\tif ( row ) {\n\t\t\t\t\trow.insertBefore( dt.row( rows[0] ).node() );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( this.c.endRender ) {\n\t\t\t\tdisplay = this.c.endRender.call( this, dt.rows(rows), groupName, level );\n\t\t\t\trow = this._rowWrap( display, this.c.endClassName, level );\n\n\t\t\t\tif ( row ) {\n\t\t\t\t\trow.insertAfter( dt.row( rows[ rows.length-1 ] ).node() );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( group.children ) {\n\t\t\t\tthis._groupDisplay( level+1, group.children );\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * Take a rendered value from an end user and make it suitable for display\n\t * as a row, by wrapping it in a row, or detecting that it is a row.\n\t * @param {node|jQuery|string} display Display value\n\t * @param {string} className Class to add to the row\n\t * @param {array} group\n\t * @param {number} group level\n\t * @private\n\t */\n\t_rowWrap: function ( display, className, level )\n\t{\n\t\tvar row;\n\t\t\n\t\tif ( display === null || display === '' ) {\n\t\t\tdisplay = this.c.emptyDataGroup;\n\t\t}\n\n\t\tif ( display === undefined ) {\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\tif ( typeof display === 'object' && display.nodeName && display.nodeName.toLowerCase() === 'tr') {\n\t\t\trow = $(display);\n\t\t}\n\t\telse if (display instanceof $ && display.length && display[0].nodeName.toLowerCase() === 'tr') {\n\t\t\trow = display;\n\t\t}\n\t\telse {\n\t\t\trow = $('<tr/>')\n\t\t\t\t.append(\n\t\t\t\t\t$('<td/>')\n\t\t\t\t\t\t.attr( 'colspan', this._colspan() )\n\t\t\t\t\t\t.append( display  )\n\t\t\t\t);\n\t\t}\n\n\t\treturn row\n\t\t\t.addClass( this.c.className )\n\t\t\t.addClass( className )\n\t\t\t.addClass( 'dtrg-level-'+level );\n\t}\n} );\n\n\n/**\n * RowGroup default settings for initialisation\n *\n * @namespace\n * @name RowGroup.defaults\n * @static\n */\nRowGroup.defaults = {\n\t/**\n\t * Class to apply to grouping rows - applied to both the start and\n\t * end grouping rows.\n\t * @type string\n\t */\n\tclassName: 'dtrg-group',\n\n\t/**\n\t * Data property from which to read the grouping information\n\t * @type string|integer|array\n\t */\n\tdataSrc: 0,\n\n\t/**\n\t * Text to show if no data is found for a group\n\t * @type string\n\t */\n\temptyDataGroup: 'No group',\n\n\t/**\n\t * Initial enablement state\n\t * @boolean\n\t */\n\tenable: true,\n\n\t/**\n\t * Class name to give to the end grouping row\n\t * @type string\n\t */\n\tendClassName: 'dtrg-end',\n\n\t/**\n\t * End grouping label function\n\t * @function\n\t */\n\tendRender: null,\n\n\t/**\n\t * Class name to give to the start grouping row\n\t * @type string\n\t */\n\tstartClassName: 'dtrg-start',\n\n\t/**\n\t * Start grouping label function\n\t * @function\n\t */\n\tstartRender: function ( rows, group ) {\n\t\treturn group;\n\t}\n};\n\n\nRowGroup.version = \"1.1.0\";\n\n\n$.fn.dataTable.RowGroup = RowGroup;\n$.fn.DataTable.RowGroup = RowGroup;\n\n\nDataTable.Api.register( 'rowGroup()', function () {\n\treturn this;\n} );\n\nDataTable.Api.register( 'rowGroup().disable()', function () {\n\treturn this.iterator( 'table', function (ctx) {\n\t\tif ( ctx.rowGroup ) {\n\t\t\tctx.rowGroup.enable( false );\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'rowGroup().enable()', function ( opts ) {\n\treturn this.iterator( 'table', function (ctx) {\n\t\tif ( ctx.rowGroup ) {\n\t\t\tctx.rowGroup.enable( opts === undefined ? true : opts );\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'rowGroup().dataSrc()', function ( val ) {\n\tif ( val === undefined ) {\n\t\treturn this.context[0].rowGroup.dataSrc();\n\t}\n\n\treturn this.iterator( 'table', function (ctx) {\n\t\tif ( ctx.rowGroup ) {\n\t\t\tctx.rowGroup.dataSrc( val );\n\t\t}\n\t} );\n} );\n\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'preInit.dt.dtrg', function (e, settings, json) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.rowGroup;\n\tvar defaults = DataTable.defaults.rowGroup;\n\n\tif ( init || defaults ) {\n\t\tvar opts = $.extend( {}, defaults, init );\n\n\t\tif ( init !== false ) {\n\t\t\tnew RowGroup( settings, opts  );\n\t\t}\n\t}\n} );\n\n\nreturn RowGroup;\n\n}));\n"
  },
  {
    "path": "static/js/DataTables/RowGroup-1.1.0/js/rowGroup.bootstrap.js",
    "content": "/*! Bootstrap 3 styling wrapper for RowGroup\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs', 'datatables.net-rowgroup'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.RowGroup ) {\n\t\t\t\trequire('datatables.net-rowgroup')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/RowGroup-1.1.0/js/rowGroup.bootstrap4.js",
    "content": "/*! Bootstrap 4 styling wrapper for RowGroup\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs4', 'datatables.net-rowgroup'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs4')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.RowGroup ) {\n\t\t\t\trequire('datatables.net-rowgroup')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/RowGroup-1.1.0/js/rowGroup.dataTables.js",
    "content": "/*! DataTables styling wrapper for RowGroup\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-dt', 'datatables.net-rowgroup'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-dt')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.RowGroup ) {\n\t\t\t\trequire('datatables.net-rowgroup')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/RowGroup-1.1.0/js/rowGroup.foundation.js",
    "content": "/*! Bootstrap 4 styling wrapper for RowGroup\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-zf', 'datatables.net-rowgroup'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-zf')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.RowGroup ) {\n\t\t\t\trequire('datatables.net-rowgroup')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/RowGroup-1.1.0/js/rowGroup.jqueryui.js",
    "content": "/*! jQuery UI styling wrapper for RowGroup\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-jqui', 'datatables.net-rowgroup'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-jqui')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.RowGroup ) {\n\t\t\t\trequire('datatables.net-rowgroup')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/RowGroup-1.1.0/js/rowGroup.semanicui.js",
    "content": ""
  },
  {
    "path": "static/js/DataTables/RowGroup-1.1.0/js/rowGroup.semanticui.js",
    "content": "/*! Semanic UI styling wrapper for RowGroup\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-se', 'datatables.net-rowgroup'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-se')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.RowGroup ) {\n\t\t\t\trequire('datatables.net-rowgroup')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/RowReorder-1.2.4/css/rowReorder.bootstrap.css",
    "content": "table.dt-rowReorder-float {\n  position: absolute !important;\n  opacity: 0.8;\n  table-layout: fixed;\n  outline: 2px solid #337ab7;\n  outline-offset: -2px;\n  z-index: 2001;\n}\n\ntr.dt-rowReorder-moving {\n  outline: 2px solid #888;\n  outline-offset: -2px;\n}\n\nbody.dt-rowReorder-noOverflow {\n  overflow-x: hidden;\n}\n\ntable.dataTable td.reorder {\n  text-align: center;\n  cursor: move;\n}\n"
  },
  {
    "path": "static/js/DataTables/RowReorder-1.2.4/css/rowReorder.bootstrap4.css",
    "content": "table.dt-rowReorder-float {\n  position: absolute !important;\n  opacity: 0.8;\n  table-layout: fixed;\n  outline: 2px solid #0275d8;\n  outline-offset: -2px;\n  z-index: 2001;\n}\n\ntr.dt-rowReorder-moving {\n  outline: 2px solid #888;\n  outline-offset: -2px;\n}\n\nbody.dt-rowReorder-noOverflow {\n  overflow-x: hidden;\n}\n\ntable.dataTable td.reorder {\n  text-align: center;\n  cursor: move;\n}\n"
  },
  {
    "path": "static/js/DataTables/RowReorder-1.2.4/css/rowReorder.dataTables.css",
    "content": "table.dt-rowReorder-float {\n  position: absolute !important;\n  opacity: 0.8;\n  table-layout: fixed;\n  outline: 2px solid #888;\n  outline-offset: -2px;\n  z-index: 2001;\n}\n\ntr.dt-rowReorder-moving {\n  outline: 2px solid #555;\n  outline-offset: -2px;\n}\n\nbody.dt-rowReorder-noOverflow {\n  overflow-x: hidden;\n}\n\ntable.dataTable td.reorder {\n  text-align: center;\n  cursor: move;\n}\n"
  },
  {
    "path": "static/js/DataTables/RowReorder-1.2.4/css/rowReorder.foundation.css",
    "content": "table.dt-rowReorder-float {\n  position: absolute !important;\n  opacity: 0.8;\n  table-layout: fixed;\n  outline: 2px solid #337ab7;\n  outline-offset: -2px;\n  z-index: 2001;\n}\n\ntr.dt-rowReorder-moving {\n  outline: 2px solid #888;\n  outline-offset: -2px;\n}\n\nbody.dt-rowReorder-noOverflow {\n  overflow-x: hidden;\n}\n\ntable.dataTable td.reorder {\n  text-align: center;\n  cursor: move;\n}\n"
  },
  {
    "path": "static/js/DataTables/RowReorder-1.2.4/css/rowReorder.jqueryui.css",
    "content": "table.dt-rowReorder-float {\n  position: absolute !important;\n  opacity: 0.8;\n  table-layout: fixed;\n  outline: 2px solid #888;\n  outline-offset: -2px;\n  z-index: 2001;\n}\n\ntr.dt-rowReorder-moving {\n  outline: 2px solid #555;\n  outline-offset: -2px;\n}\n\nbody.dt-rowReorder-noOverflow {\n  overflow-x: hidden;\n}\n\ntable.dataTable td.reorder {\n  text-align: center;\n  cursor: move;\n}\n"
  },
  {
    "path": "static/js/DataTables/RowReorder-1.2.4/css/rowReorder.semanticui.css",
    "content": "table.dt-rowReorder-float {\n  position: absolute !important;\n  opacity: 0.8;\n  table-layout: fixed;\n  outline: 2px solid rgba(0, 0, 0, 0.05);\n  outline-offset: -2px;\n  z-index: 2001;\n}\n\ntr.dt-rowReorder-moving {\n  outline: 2px solid #888;\n  outline-offset: -2px;\n}\n\nbody.dt-rowReorder-noOverflow {\n  overflow-x: hidden;\n}\n\ntable.dataTable td.reorder {\n  text-align: center;\n  cursor: move;\n}\n"
  },
  {
    "path": "static/js/DataTables/RowReorder-1.2.4/js/dataTables.rowReorder.js",
    "content": "/*! RowReorder 1.2.4\n * 2015-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     RowReorder\n * @description Row reordering extension for DataTables\n * @version     1.2.4\n * @file        dataTables.rowReorder.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2015-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/**\n * RowReorder provides the ability in DataTables to click and drag rows to\n * reorder them. When a row is dropped the data for the rows effected will be\n * updated to reflect the change. Normally this data point should also be the\n * column being sorted upon in the DataTable but this does not need to be the\n * case. RowReorder implements a \"data swap\" method - so the rows being\n * reordered take the value of the data point from the row that used to occupy\n * the row's new position.\n *\n * Initialisation is done by either:\n *\n * * `rowReorder` parameter in the DataTable initialisation object\n * * `new $.fn.dataTable.RowReorder( table, opts )` after DataTables\n *   initialisation.\n * \n *  @class\n *  @param {object} settings DataTables settings object for the host table\n *  @param {object} [opts] Configuration options\n *  @requires jQuery 1.7+\n *  @requires DataTables 1.10.7+\n */\nvar RowReorder = function ( dt, opts ) {\n\t// Sanity check that we are using DataTables 1.10 or newer\n\tif ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {\n\t\tthrow 'DataTables RowReorder requires DataTables 1.10.8 or newer';\n\t}\n\n\t// User and defaults configuration object\n\tthis.c = $.extend( true, {},\n\t\tDataTable.defaults.rowReorder,\n\t\tRowReorder.defaults,\n\t\topts\n\t);\n\n\t// Internal settings\n\tthis.s = {\n\t\t/** @type {integer} Scroll body top cache */\n\t\tbodyTop: null,\n\n\t\t/** @type {DataTable.Api} DataTables' API instance */\n\t\tdt: new DataTable.Api( dt ),\n\n\t\t/** @type {function} Data fetch function */\n\t\tgetDataFn: DataTable.ext.oApi._fnGetObjectDataFn( this.c.dataSrc ),\n\n\t\t/** @type {array} Pixel positions for row insertion calculation */\n\t\tmiddles: null,\n\n\t\t/** @type {Object} Cached dimension information for use in the mouse move event handler */\n\t\tscroll: {},\n\n\t\t/** @type {integer} Interval object used for smooth scrolling */\n\t\tscrollInterval: null,\n\n\t\t/** @type {function} Data set function */\n\t\tsetDataFn: DataTable.ext.oApi._fnSetObjectDataFn( this.c.dataSrc ),\n\n\t\t/** @type {Object} Mouse down information */\n\t\tstart: {\n\t\t\ttop: 0,\n\t\t\tleft: 0,\n\t\t\toffsetTop: 0,\n\t\t\toffsetLeft: 0,\n\t\t\tnodes: []\n\t\t},\n\n\t\t/** @type {integer} Window height cached value */\n\t\twindowHeight: 0,\n\n\t\t/** @type {integer} Document outer height cached value */\n\t\tdocumentOuterHeight: 0,\n\n\t\t/** @type {integer} DOM clone outer height cached value */\n\t\tdomCloneOuterHeight: 0\n\t};\n\n\t// DOM items\n\tthis.dom = {\n\t\t/** @type {jQuery} Cloned row being moved around */\n\t\tclone: null,\n\n\t\t/** @type {jQuery} DataTables scrolling container */\n\t\tdtScroll: $('div.dataTables_scrollBody', this.s.dt.table().container())\n\t};\n\n\t// Check if row reorder has already been initialised on this table\n\tvar settings = this.s.dt.settings()[0];\n\tvar exisiting = settings.rowreorder;\n\tif ( exisiting ) {\n\t\treturn exisiting;\n\t}\n\n\tsettings.rowreorder = this;\n\tthis._constructor();\n};\n\n\n$.extend( RowReorder.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\n\t/**\n\t * Initialise the RowReorder instance\n\t *\n\t * @private\n\t */\n\t_constructor: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar table = $( dt.table().node() );\n\n\t\t// Need to be able to calculate the row positions relative to the table\n\t\tif ( table.css('position') === 'static' ) {\n\t\t\ttable.css( 'position', 'relative' );\n\t\t}\n\n\t\t// listen for mouse down on the target column - we have to implement\n\t\t// this rather than using HTML5 drag and drop as drag and drop doesn't\n\t\t// appear to work on table rows at this time. Also mobile browsers are\n\t\t// not supported.\n\t\t// Use `table().container()` rather than just the table node for IE8 -\n\t\t// otherwise it only works once...\n\t\t$(dt.table().container()).on( 'mousedown.rowReorder touchstart.rowReorder', this.c.selector, function (e) {\n\t\t\tif ( ! that.c.enable ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Ignore excluded children of the selector\n\t\t\tif ( $(e.target).is(that.c.excludedChildren) ) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tvar tr = $(this).closest('tr');\n\t\t\tvar row = dt.row( tr );\n\n\t\t\t// Double check that it is a DataTable row\n\t\t\tif ( row.any() ) {\n\t\t\t\tthat._emitEvent( 'pre-row-reorder', {\n\t\t\t\t\tnode: row.node(),\n\t\t\t\t\tindex: row.index()\n\t\t\t\t} );\n\n\t\t\t\tthat._mouseDown( e, tr );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} );\n\n\t\tdt.on( 'destroy.rowReorder', function () {\n\t\t\t$(dt.table().container()).off( '.rowReorder' );\n\t\t\tdt.off( '.rowReorder' );\n\t\t} );\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\t\n\t/**\n\t * Cache the measurements that RowReorder needs in the mouse move handler\n\t * to attempt to speed things up, rather than reading from the DOM.\n\t *\n\t * @private\n\t */\n\t_cachePositions: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\n\t\t// Frustratingly, if we add `position:relative` to the tbody, the\n\t\t// position is still relatively to the parent. So we need to adjust\n\t\t// for that\n\t\tvar headerHeight = $( dt.table().node() ).find('thead').outerHeight();\n\n\t\t// Need to pass the nodes through jQuery to get them in document order,\n\t\t// not what DataTables thinks it is, since we have been altering the\n\t\t// order\n\t\tvar nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );\n\t\tvar tops = $.map( nodes, function ( node, i ) {\n\t\t\treturn $(node).position().top - headerHeight;\n\t\t} );\n\n\t\tvar middles = $.map( tops, function ( top, i ) {\n\t\t\treturn tops.length < i-1 ?\n\t\t\t\t(top + tops[i+1]) / 2 :\n\t\t\t\t(top + top + $( dt.row( ':last-child' ).node() ).outerHeight() ) / 2;\n\t\t} );\n\n\t\tthis.s.middles = middles;\n\t\tthis.s.bodyTop = $( dt.table().body() ).offset().top;\n\t\tthis.s.windowHeight = $(window).height();\n\t\tthis.s.documentOuterHeight = $(document).outerHeight();\n\t},\n\n\n\t/**\n\t * Clone a row so it can be floated around the screen\n\t *\n\t * @param  {jQuery} target Node to be cloned\n\t * @private\n\t */\n\t_clone: function ( target )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar clone = $( dt.table().node().cloneNode(false) )\n\t\t\t.addClass( 'dt-rowReorder-float' )\n\t\t\t.append('<tbody/>')\n\t\t\t.append( target.clone( false ) );\n\n\t\t// Match the table and column widths - read all sizes before setting\n\t\t// to reduce reflows\n\t\tvar tableWidth = target.outerWidth();\n\t\tvar tableHeight = target.outerHeight();\n\t\tvar sizes = target.children().map( function () {\n\t\t\treturn $(this).width();\n\t\t} );\n\n\t\tclone\n\t\t\t.width( tableWidth )\n\t\t\t.height( tableHeight )\n\t\t\t.find('tr').children().each( function (i) {\n\t\t\t\tthis.style.width = sizes[i]+'px';\n\t\t\t} );\n\n\t\t// Insert into the document to have it floating around\n\t\tclone.appendTo( 'body' );\n\n\t\tthis.dom.clone = clone;\n\t\tthis.s.domCloneOuterHeight = clone.outerHeight();\n\t},\n\n\n\t/**\n\t * Update the cloned item's position in the document\n\t *\n\t * @param  {object} e Event giving the mouse's position\n\t * @private\n\t */\n\t_clonePosition: function ( e )\n\t{\n\t\tvar start = this.s.start;\n\t\tvar topDiff = this._eventToPage( e, 'Y' ) - start.top;\n\t\tvar leftDiff = this._eventToPage( e, 'X' ) - start.left;\n\t\tvar snap = this.c.snapX;\n\t\tvar left;\n\t\tvar top = topDiff + start.offsetTop;\n\n\t\tif ( snap === true ) {\n\t\t\tleft = start.offsetLeft;\n\t\t}\n\t\telse if ( typeof snap === 'number' ) {\n\t\t\tleft = start.offsetLeft + snap;\n\t\t}\n\t\telse {\n\t\t\tleft = leftDiff + start.offsetLeft;\n\t\t}\n\n\t\tif(top < 0) {\n\t\t\ttop = 0\n\t\t}\n\t\telse if(top + this.s.domCloneOuterHeight > this.s.documentOuterHeight) {\n\t\t\ttop = this.s.documentOuterHeight - this.s.domCloneOuterHeight;\n\t\t}\n\n\t\tthis.dom.clone.css( {\n\t\t\ttop: top,\n\t\t\tleft: left\n\t\t} );\n\t},\n\n\n\t/**\n\t * Emit an event on the DataTable for listeners\n\t *\n\t * @param  {string} name Event name\n\t * @param  {array} args Event arguments\n\t * @private\n\t */\n\t_emitEvent: function ( name, args )\n\t{\n\t\tthis.s.dt.iterator( 'table', function ( ctx, i ) {\n\t\t\t$(ctx.nTable).triggerHandler( name+'.dt', args );\n\t\t} );\n\t},\n\n\n\t/**\n\t * Get pageX/Y position from an event, regardless of if it is a mouse or\n\t * touch event.\n\t *\n\t * @param  {object} e Event\n\t * @param  {string} pos X or Y (must be a capital)\n\t * @private\n\t */\n\t_eventToPage: function ( e, pos )\n\t{\n\t\tif ( e.type.indexOf( 'touch' ) !== -1 ) {\n\t\t\treturn e.originalEvent.touches[0][ 'page'+pos ];\n\t\t}\n\n\t\treturn e[ 'page'+pos ];\n\t},\n\n\n\t/**\n\t * Mouse down event handler. Read initial positions and add event handlers\n\t * for the move.\n\t *\n\t * @param  {object} e      Mouse event\n\t * @param  {jQuery} target TR element that is to be moved\n\t * @private\n\t */\n\t_mouseDown: function ( e, target )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar start = this.s.start;\n\n\t\tvar offset = target.offset();\n\t\tstart.top = this._eventToPage( e, 'Y' );\n\t\tstart.left = this._eventToPage( e, 'X' );\n\t\tstart.offsetTop = offset.top;\n\t\tstart.offsetLeft = offset.left;\n\t\tstart.nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );\n\n\t\tthis._cachePositions();\n\t\tthis._clone( target );\n\t\tthis._clonePosition( e );\n\n\t\tthis.dom.target = target;\n\t\ttarget.addClass( 'dt-rowReorder-moving' );\n\n\t\t$( document )\n\t\t\t.on( 'mouseup.rowReorder touchend.rowReorder', function (e) {\n\t\t\t\tthat._mouseUp(e);\n\t\t\t} )\n\t\t\t.on( 'mousemove.rowReorder touchmove.rowReorder', function (e) {\n\t\t\t\tthat._mouseMove(e);\n\t\t\t} );\n\n\t\t// Check if window is x-scrolling - if not, disable it for the duration\n\t\t// of the drag\n\t\tif ( $(window).width() === $(document).width() ) {\n\t\t\t$(document.body).addClass( 'dt-rowReorder-noOverflow' );\n\t\t}\n\n\t\t// Cache scrolling information so mouse move doesn't need to read.\n\t\t// This assumes that the window and DT scroller will not change size\n\t\t// during an row drag, which I think is a fair assumption\n\t\tvar scrollWrapper = this.dom.dtScroll;\n\t\tthis.s.scroll = {\n\t\t\twindowHeight: $(window).height(),\n\t\t\twindowWidth:  $(window).width(),\n\t\t\tdtTop:        scrollWrapper.length ? scrollWrapper.offset().top : null,\n\t\t\tdtLeft:       scrollWrapper.length ? scrollWrapper.offset().left : null,\n\t\t\tdtHeight:     scrollWrapper.length ? scrollWrapper.outerHeight() : null,\n\t\t\tdtWidth:      scrollWrapper.length ? scrollWrapper.outerWidth() : null\n\t\t};\n\t},\n\n\n\t/**\n\t * Mouse move event handler - move the cloned row and shuffle the table's\n\t * rows if required.\n\t *\n\t * @param  {object} e Mouse event\n\t * @private\n\t */\n\t_mouseMove: function ( e )\n\t{\n\t\tthis._clonePosition( e );\n\n\t\t// Transform the mouse position into a position in the table's body\n\t\tvar bodyY = this._eventToPage( e, 'Y' ) - this.s.bodyTop;\n\t\tvar middles = this.s.middles;\n\t\tvar insertPoint = null;\n\t\tvar dt = this.s.dt;\n\t\tvar body = dt.table().body();\n\n\t\t// Determine where the row should be inserted based on the mouse\n\t\t// position\n\t\tfor ( var i=0, ien=middles.length ; i<ien ; i++ ) {\n\t\t\tif ( bodyY < middles[i] ) {\n\t\t\t\tinsertPoint = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif ( insertPoint === null ) {\n\t\t\tinsertPoint = middles.length;\n\t\t}\n\n\t\t// Perform the DOM shuffle if it has changed from last time\n\t\tif ( this.s.lastInsert === null || this.s.lastInsert !== insertPoint ) {\n\t\t\tif ( insertPoint === 0 ) {\n\t\t\t\tthis.dom.target.prependTo( body );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tvar nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );\n\n\t\t\t\tif ( insertPoint > this.s.lastInsert ) {\n\t\t\t\t\tthis.dom.target.insertAfter( nodes[ insertPoint-1 ] );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis.dom.target.insertBefore( nodes[ insertPoint ] );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._cachePositions();\n\n\t\t\tthis.s.lastInsert = insertPoint;\n\t\t}\n\n\t\tthis._shiftScroll( e );\n\t},\n\n\n\t/**\n\t * Mouse up event handler - release the event handlers and perform the\n\t * table updates\n\t *\n\t * @param  {object} e Mouse event\n\t * @private\n\t */\n\t_mouseUp: function ( e )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar i, ien;\n\t\tvar dataSrc = this.c.dataSrc;\n\n\t\tthis.dom.clone.remove();\n\t\tthis.dom.clone = null;\n\n\t\tthis.dom.target.removeClass( 'dt-rowReorder-moving' );\n\t\t//this.dom.target = null;\n\n\t\t$(document).off( '.rowReorder' );\n\t\t$(document.body).removeClass( 'dt-rowReorder-noOverflow' );\n\n\t\tclearInterval( this.s.scrollInterval );\n\t\tthis.s.scrollInterval = null;\n\n\t\t// Calculate the difference\n\t\tvar startNodes = this.s.start.nodes;\n\t\tvar endNodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );\n\t\tvar idDiff = {};\n\t\tvar fullDiff = [];\n\t\tvar diffNodes = [];\n\t\tvar getDataFn = this.s.getDataFn;\n\t\tvar setDataFn = this.s.setDataFn;\n\n\t\tfor ( i=0, ien=startNodes.length ; i<ien ; i++ ) {\n\t\t\tif ( startNodes[i] !== endNodes[i] ) {\n\t\t\t\tvar id = dt.row( endNodes[i] ).id();\n\t\t\t\tvar endRowData = dt.row( endNodes[i] ).data();\n\t\t\t\tvar startRowData = dt.row( startNodes[i] ).data();\n\n\t\t\t\tif ( id ) {\n\t\t\t\t\tidDiff[ id ] = getDataFn( startRowData );\n\t\t\t\t}\n\n\t\t\t\tfullDiff.push( {\n\t\t\t\t\tnode: endNodes[i],\n\t\t\t\t\toldData: getDataFn( endRowData ),\n\t\t\t\t\tnewData: getDataFn( startRowData ),\n\t\t\t\t\tnewPosition: i,\n\t\t\t\t\toldPosition: $.inArray( endNodes[i], startNodes )\n\t\t\t\t} );\n\n\t\t\t\tdiffNodes.push( endNodes[i] );\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Create event args\n\t\tvar eventArgs = [ fullDiff, {\n\t\t\tdataSrc:    dataSrc,\n\t\t\tnodes:      diffNodes,\n\t\t\tvalues:     idDiff,\n\t\t\ttriggerRow: dt.row( this.dom.target )\n\t\t} ];\n\t\t\n\t\t// Emit event\n\t\tthis._emitEvent( 'row-reorder', eventArgs );\n\n\t\tvar update = function () {\n\t\t\tif ( that.c.update ) {\n\t\t\t\tfor ( i=0, ien=fullDiff.length ; i<ien ; i++ ) {\n\t\t\t\t\tvar row = dt.row( fullDiff[i].node );\n\t\t\t\t\tvar rowData = row.data();\n\n\t\t\t\t\tsetDataFn( rowData, fullDiff[i].newData );\n\n\t\t\t\t\t// Invalidate the cell that has the same data source as the dataSrc\n\t\t\t\t\tdt.columns().every( function () {\n\t\t\t\t\t\tif ( this.dataSrc() === dataSrc ) {\n\t\t\t\t\t\t\tdt.cell( fullDiff[i].node, this.index() ).invalidate( 'data' );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\t// Trigger row reordered event\n\t\t\t\tthat._emitEvent( 'row-reordered', eventArgs );\n\n\t\t\t\tdt.draw( false );\n\t\t\t}\n\t\t};\n\n\t\t// Editor interface\n\t\tif ( this.c.editor ) {\n\t\t\t// Disable user interaction while Editor is submitting\n\t\t\tthis.c.enable = false;\n\n\t\t\tthis.c.editor\n\t\t\t\t.edit(\n\t\t\t\t\tdiffNodes,\n\t\t\t\t\tfalse,\n\t\t\t\t\t$.extend( {submit: 'changed'}, this.c.formOptions )\n\t\t\t\t)\n\t\t\t\t.multiSet( dataSrc, idDiff )\n\t\t\t\t.one( 'preSubmitCancelled.rowReorder', function () {\n\t\t\t\t\tthat.c.enable = true;\n\t\t\t\t\tthat.c.editor.off( '.rowReorder' );\n\t\t\t\t\tdt.draw( false );\n\t\t\t\t} )\n\t\t\t\t.one( 'submitUnsuccessful.rowReorder', function () {\n\t\t\t\t\tdt.draw( false );\n\t\t\t\t} )\n\t\t\t\t.one( 'submitSuccess.rowReorder', function () {\n\t\t\t\t\tupdate();\n\t\t\t\t} )\n\t\t\t\t.one( 'submitComplete', function () {\n\t\t\t\t\tthat.c.enable = true;\n\t\t\t\t\tthat.c.editor.off( '.rowReorder' );\n\t\t\t\t} )\n\t\t\t\t.submit();\n\t\t}\n\t\telse {\n\t\t\tupdate();\n\t\t}\n\t},\n\n\n\t/**\n\t * Move the window and DataTables scrolling during a drag to scroll new\n\t * content into view.\n\t *\n\t * This matches the `_shiftScroll` method used in AutoFill, but only\n\t * horizontal scrolling is considered here.\n\t *\n\t * @param  {object} e Mouse move event object\n\t * @private\n\t */\n\t_shiftScroll: function ( e )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar scroll = this.s.scroll;\n\t\tvar runInterval = false;\n\t\tvar scrollSpeed = 5;\n\t\tvar buffer = 65;\n\t\tvar\n\t\t\twindowY = e.pageY - document.body.scrollTop,\n\t\t\twindowVert,\n\t\t\tdtVert;\n\n\t\t// Window calculations - based on the mouse position in the window,\n\t\t// regardless of scrolling\n\t\tif ( windowY < buffer ) {\n\t\t\twindowVert = scrollSpeed * -1;\n\t\t}\n\t\telse if ( windowY > scroll.windowHeight - buffer ) {\n\t\t\twindowVert = scrollSpeed;\n\t\t}\n\n\t\t// DataTables scrolling calculations - based on the table's position in\n\t\t// the document and the mouse position on the page\n\t\tif ( scroll.dtTop !== null && e.pageY < scroll.dtTop + buffer ) {\n\t\t\tdtVert = scrollSpeed * -1;\n\t\t}\n\t\telse if ( scroll.dtTop !== null && e.pageY > scroll.dtTop + scroll.dtHeight - buffer ) {\n\t\t\tdtVert = scrollSpeed;\n\t\t}\n\n\t\t// This is where it gets interesting. We want to continue scrolling\n\t\t// without requiring a mouse move, so we need an interval to be\n\t\t// triggered. The interval should continue until it is no longer needed,\n\t\t// but it must also use the latest scroll commands (for example consider\n\t\t// that the mouse might move from scrolling up to scrolling left, all\n\t\t// with the same interval running. We use the `scroll` object to \"pass\"\n\t\t// this information to the interval. Can't use local variables as they\n\t\t// wouldn't be the ones that are used by an already existing interval!\n\t\tif ( windowVert || dtVert ) {\n\t\t\tscroll.windowVert = windowVert;\n\t\t\tscroll.dtVert = dtVert;\n\t\t\trunInterval = true;\n\t\t}\n\t\telse if ( this.s.scrollInterval ) {\n\t\t\t// Don't need to scroll - remove any existing timer\n\t\t\tclearInterval( this.s.scrollInterval );\n\t\t\tthis.s.scrollInterval = null;\n\t\t}\n\n\t\t// If we need to run the interval to scroll and there is no existing\n\t\t// interval (if there is an existing one, it will continue to run)\n\t\tif ( ! this.s.scrollInterval && runInterval ) {\n\t\t\tthis.s.scrollInterval = setInterval( function () {\n\t\t\t\t// Don't need to worry about setting scroll <0 or beyond the\n\t\t\t\t// scroll bound as the browser will just reject that.\n\t\t\t\tif ( scroll.windowVert ) {\n\t\t\t\t\tdocument.body.scrollTop += scroll.windowVert;\n\t\t\t\t}\n\n\t\t\t\t// DataTables scrolling\n\t\t\t\tif ( scroll.dtVert ) {\n\t\t\t\t\tvar scroller = that.dom.dtScroll[0];\n\n\t\t\t\t\tif ( scroll.dtVert ) {\n\t\t\t\t\t\tscroller.scrollTop += scroll.dtVert;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, 20 );\n\t\t}\n\t}\n} );\n\n\n\n/**\n * RowReorder default settings for initialisation\n *\n * @namespace\n * @name RowReorder.defaults\n * @static\n */\nRowReorder.defaults = {\n\t/**\n\t * Data point in the host row's data source object for where to get and set\n\t * the data to reorder. This will normally also be the sorting column.\n\t *\n\t * @type {Number}\n\t */\n\tdataSrc: 0,\n\n\t/**\n\t * Editor instance that will be used to perform the update\n\t *\n\t * @type {DataTable.Editor}\n\t */\n\teditor: null,\n\n\t/**\n\t * Enable / disable RowReorder's user interaction\n\t * @type {Boolean}\n\t */\n\tenable: true,\n\n\t/**\n\t * Form options to pass to Editor when submitting a change in the row order.\n\t * See the Editor `from-options` object for details of the options\n\t * available.\n\t * @type {Object}\n\t */\n\tformOptions: {},\n\n\t/**\n\t * Drag handle selector. This defines the element that when dragged will\n\t * reorder a row.\n\t *\n\t * @type {String}\n\t */\n\tselector: 'td:first-child',\n\n\t/**\n\t * Optionally lock the dragged row's x-position. This can be `true` to\n\t * fix the position match the host table's, `false` to allow free movement\n\t * of the row, or a number to define an offset from the host table.\n\t *\n\t * @type {Boolean|number}\n\t */\n\tsnapX: false,\n\n\t/**\n\t * Update the table's data on drop\n\t *\n\t * @type {Boolean}\n\t */\n\tupdate: true,\n\n\t/**\n\t * Selector for children of the drag handle selector that mouseDown events\n\t * will be passed through to and drag will not activate\n\t *\n\t * @type {String}\n\t */\n\texcludedChildren: 'a'\n};\n\n\n/*\n * API\n */\nvar Api = $.fn.dataTable.Api;\n\n// Doesn't do anything - work around for a bug in DT... Not documented\nApi.register( 'rowReorder()', function () {\n\treturn this;\n} );\n\nApi.register( 'rowReorder.enable()', function ( toggle ) {\n\tif ( toggle === undefined ) {\n\t\ttoggle = true;\n\t}\n\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx.rowreorder ) {\n\t\t\tctx.rowreorder.c.enable = toggle;\n\t\t}\n\t} );\n} );\n\nApi.register( 'rowReorder.disable()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx.rowreorder ) {\n\t\t\tctx.rowreorder.c.enable = false;\n\t\t}\n\t} );\n} );\n\n\n/**\n * Version information\n *\n * @name RowReorder.version\n * @static\n */\nRowReorder.version = '1.2.4';\n\n\n$.fn.dataTable.RowReorder = RowReorder;\n$.fn.DataTable.RowReorder = RowReorder;\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'init.dt.dtr', function (e, settings, json) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.rowReorder;\n\tvar defaults = DataTable.defaults.rowReorder;\n\n\tif ( init || defaults ) {\n\t\tvar opts = $.extend( {}, init, defaults );\n\n\t\tif ( init !== false ) {\n\t\t\tnew RowReorder( settings, opts  );\n\t\t}\n\t}\n} );\n\n\nreturn RowReorder;\n}));\n"
  },
  {
    "path": "static/js/DataTables/RowReorder-1.2.4/js/rowReorder.bootstrap.js",
    "content": "/*! Bootstrap 3 styling wrapper for RowReorder\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs', 'datatables.net-rowreorder'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.RowReorder ) {\n\t\t\t\trequire('datatables.net-rowreorder')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/RowReorder-1.2.4/js/rowReorder.bootstrap4.js",
    "content": "/*! Bootstrap 4 styling wrapper for RowReorder\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs4', 'datatables.net-rowreorder'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs4')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.RowReorder ) {\n\t\t\t\trequire('datatables.net-rowreorder')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/RowReorder-1.2.4/js/rowReorder.dataTables.js",
    "content": "/*! DataTables styling wrapper for RowReorder\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-dt', 'datatables.net-rowreorder'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-dt')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.RowReorder ) {\n\t\t\t\trequire('datatables.net-rowreorder')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/RowReorder-1.2.4/js/rowReorder.foundation.js",
    "content": "/*! Bootstrap 4 styling wrapper for RowReorder\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-zf', 'datatables.net-rowreorder'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-zf')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.RowReorder ) {\n\t\t\t\trequire('datatables.net-rowreorder')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/RowReorder-1.2.4/js/rowReorder.jqueryui.js",
    "content": "/*! jQuery UI styling wrapper for RowReorder\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-jqui', 'datatables.net-rowreorder'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-jqui')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.RowReorder ) {\n\t\t\t\trequire('datatables.net-rowreorder')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/RowReorder-1.2.4/js/rowReorder.semanticui.js",
    "content": "/*! Semanic UI styling wrapper for RowReorder\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-se', 'datatables.net-rowreorder'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-se')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.RowReorder ) {\n\t\t\t\trequire('datatables.net-rowreorder')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/Scroller-2.0.0/css/scroller.bootstrap.css",
    "content": "div.dts {\n  display: block !important;\n}\ndiv.dts tbody th,\ndiv.dts tbody td {\n  white-space: nowrap;\n}\ndiv.dts div.dts_loading {\n  z-index: 1;\n}\ndiv.dts div.dts_label {\n  position: absolute;\n  right: 10px;\n  background: rgba(0, 0, 0, 0.8);\n  color: white;\n  box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.5);\n  text-align: right;\n  border-radius: 3px;\n  padding: 0.4em;\n  z-index: 2;\n  display: none;\n}\ndiv.dts div.dataTables_scrollBody {\n  background: repeating-linear-gradient(45deg, #edeeff, #edeeff 10px, white 10px, white 20px);\n}\ndiv.dts div.dataTables_scrollBody table {\n  z-index: 2;\n}\ndiv.dts div.dataTables_paginate,\ndiv.dts div.dataTables_length {\n  display: none;\n}\n\ndiv.DTS tbody tr {\n  background-color: white;\n}\n"
  },
  {
    "path": "static/js/DataTables/Scroller-2.0.0/css/scroller.bootstrap4.css",
    "content": "div.dts {\n  display: block !important;\n}\ndiv.dts tbody th,\ndiv.dts tbody td {\n  white-space: nowrap;\n}\ndiv.dts div.dts_loading {\n  z-index: 1;\n}\ndiv.dts div.dts_label {\n  position: absolute;\n  right: 10px;\n  background: rgba(0, 0, 0, 0.8);\n  color: white;\n  box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.5);\n  text-align: right;\n  border-radius: 3px;\n  padding: 0.4em;\n  z-index: 2;\n  display: none;\n}\ndiv.dts div.dataTables_scrollBody {\n  background: repeating-linear-gradient(45deg, #edeeff, #edeeff 10px, white 10px, white 20px);\n}\ndiv.dts div.dataTables_scrollBody table {\n  z-index: 2;\n}\ndiv.dts div.dataTables_paginate,\ndiv.dts div.dataTables_length {\n  display: none;\n}\n\ndiv.DTS div.dataTables_scrollBody table {\n  background-color: white;\n}\n"
  },
  {
    "path": "static/js/DataTables/Scroller-2.0.0/css/scroller.dataTables.css",
    "content": "div.dts {\n  display: block !important;\n}\ndiv.dts tbody th,\ndiv.dts tbody td {\n  white-space: nowrap;\n}\ndiv.dts div.dts_loading {\n  z-index: 1;\n}\ndiv.dts div.dts_label {\n  position: absolute;\n  right: 10px;\n  background: rgba(0, 0, 0, 0.8);\n  color: white;\n  box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.5);\n  text-align: right;\n  border-radius: 3px;\n  padding: 0.4em;\n  z-index: 2;\n  display: none;\n}\ndiv.dts div.dataTables_scrollBody {\n  background: repeating-linear-gradient(45deg, #edeeff, #edeeff 10px, white 10px, white 20px);\n}\ndiv.dts div.dataTables_scrollBody table {\n  z-index: 2;\n}\ndiv.dts div.dataTables_paginate,\ndiv.dts div.dataTables_length {\n  display: none;\n}\n"
  },
  {
    "path": "static/js/DataTables/Scroller-2.0.0/css/scroller.foundation.css",
    "content": "div.DTS tbody th,\ndiv.DTS tbody td {\n  white-space: nowrap;\n}\ndiv.DTS div.DTS_Loading {\n  z-index: 1;\n}\ndiv.DTS div.dataTables_scrollBody {\n  background: repeating-linear-gradient(45deg, #edeeff, #edeeff 10px, white 10px, white 20px);\n}\ndiv.DTS div.dataTables_scrollBody table {\n  z-index: 2;\n}\ndiv.DTS div.dataTables_paginate,\ndiv.DTS div.dataTables_length {\n  display: none;\n}\n"
  },
  {
    "path": "static/js/DataTables/Scroller-2.0.0/css/scroller.jqueryui.css",
    "content": "div.dts {\n  display: block !important;\n}\ndiv.dts tbody th,\ndiv.dts tbody td {\n  white-space: nowrap;\n}\ndiv.dts div.dts_loading {\n  z-index: 1;\n}\ndiv.dts div.dts_label {\n  position: absolute;\n  right: 10px;\n  background: rgba(0, 0, 0, 0.8);\n  color: white;\n  box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.5);\n  text-align: right;\n  border-radius: 3px;\n  padding: 0.4em;\n  z-index: 2;\n  display: none;\n}\ndiv.dts div.dataTables_scrollBody {\n  background: repeating-linear-gradient(45deg, #edeeff, #edeeff 10px, white 10px, white 20px);\n}\ndiv.dts div.dataTables_scrollBody table {\n  z-index: 2;\n}\ndiv.dts div.dataTables_paginate,\ndiv.dts div.dataTables_length {\n  display: none;\n}\n"
  },
  {
    "path": "static/js/DataTables/Scroller-2.0.0/css/scroller.semanticui.css",
    "content": "div.dts {\n  display: block !important;\n}\ndiv.dts tbody th,\ndiv.dts tbody td {\n  white-space: nowrap;\n}\ndiv.dts div.dts_loading {\n  z-index: 1;\n}\ndiv.dts div.dts_label {\n  position: absolute;\n  right: 10px;\n  background: rgba(0, 0, 0, 0.8);\n  color: white;\n  box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.5);\n  text-align: right;\n  border-radius: 3px;\n  padding: 0.4em;\n  z-index: 2;\n  display: none;\n}\ndiv.dts div.dataTables_scrollBody {\n  background: repeating-linear-gradient(45deg, #edeeff, #edeeff 10px, white 10px, white 20px);\n}\ndiv.dts div.dataTables_scrollBody table {\n  z-index: 2;\n}\ndiv.dts div.dataTables_paginate,\ndiv.dts div.dataTables_length {\n  display: none;\n}\n"
  },
  {
    "path": "static/js/DataTables/Scroller-2.0.0/js/dataTables.scroller.js",
    "content": "/*! Scroller 2.0.0\n * ©2011-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     Scroller\n * @description Virtual rendering for DataTables\n * @version     2.0.0\n * @file        dataTables.scroller.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2011-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/**\n * Scroller is a virtual rendering plug-in for DataTables which allows large\n * datasets to be drawn on screen every quickly. What the virtual rendering means\n * is that only the visible portion of the table (and a bit to either side to make\n * the scrolling smooth) is drawn, while the scrolling container gives the\n * visual impression that the whole table is visible. This is done by making use\n * of the pagination abilities of DataTables and moving the table around in the\n * scrolling container DataTables adds to the page. The scrolling container is\n * forced to the height it would be for the full table display using an extra\n * element.\n *\n * Note that rows in the table MUST all be the same height. Information in a cell\n * which expands on to multiple lines will cause some odd behaviour in the scrolling.\n *\n * Scroller is initialised by simply including the letter 'S' in the sDom for the\n * table you want to have this feature enabled on. Note that the 'S' must come\n * AFTER the 't' parameter in `dom`.\n *\n * Key features include:\n *   <ul class=\"limit_length\">\n *     <li>Speed! The aim of Scroller for DataTables is to make rendering large data sets fast</li>\n *     <li>Full compatibility with deferred rendering in DataTables for maximum speed</li>\n *     <li>Display millions of rows</li>\n *     <li>Integration with state saving in DataTables (scrolling position is saved)</li>\n *     <li>Easy to use</li>\n *   </ul>\n *\n *  @class\n *  @constructor\n *  @global\n *  @param {object} dt DataTables settings object or API instance\n *  @param {object} [opts={}] Configuration object for FixedColumns. Options \n *    are defined by {@link Scroller.defaults}\n *\n *  @requires jQuery 1.7+\n *  @requires DataTables 1.10.0+\n *\n *  @example\n *    $(document).ready(function() {\n *        $('#example').DataTable( {\n *            \"scrollY\": \"200px\",\n *            \"ajax\": \"media/dataset/large.txt\",\n *            \"scroller\": true,\n *            \"deferRender\": true\n *        } );\n *    } );\n */\nvar Scroller = function ( dt, opts ) {\n\t/* Sanity check - you just know it will happen */\n\tif ( ! (this instanceof Scroller) ) {\n\t\talert( \"Scroller warning: Scroller must be initialised with the 'new' keyword.\" );\n\t\treturn;\n\t}\n\n\tif ( opts === undefined ) {\n\t\topts = {};\n\t}\n\n\tvar dtApi = $.fn.dataTable.Api( dt );\n\n\t/**\n\t * Settings object which contains customisable information for the Scroller instance\n\t * @namespace\n\t * @private\n\t * @extends Scroller.defaults\n\t */\n\tthis.s = {\n\t\t/**\n\t\t * DataTables settings object\n\t\t *  @type     object\n\t\t *  @default  Passed in as first parameter to constructor\n\t\t */\n\t\tdt: dtApi.settings()[0],\n\n\t\t/**\n\t\t * DataTables API instance\n\t\t *  @type     DataTable.Api\n\t\t */\n\t\tdtApi: dtApi,\n\n\t\t/**\n\t\t * Pixel location of the top of the drawn table in the viewport\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t */\n\t\ttableTop: 0,\n\n\t\t/**\n\t\t * Pixel location of the bottom of the drawn table in the viewport\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t */\n\t\ttableBottom: 0,\n\n\t\t/**\n\t\t * Pixel location of the boundary for when the next data set should be loaded and drawn\n\t\t * when scrolling up the way.\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t *  @private\n\t\t */\n\t\tredrawTop: 0,\n\n\t\t/**\n\t\t * Pixel location of the boundary for when the next data set should be loaded and drawn\n\t\t * when scrolling down the way. Note that this is actually calculated as the offset from\n\t\t * the top.\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t *  @private\n\t\t */\n\t\tredrawBottom: 0,\n\n\t\t/**\n\t\t * Auto row height or not indicator\n\t\t *  @type     bool\n\t\t *  @default  0\n\t\t */\n\t\tautoHeight: true,\n\n\t\t/**\n\t\t * Number of rows calculated as visible in the visible viewport\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t */\n\t\tviewportRows: 0,\n\n\t\t/**\n\t\t * setTimeout reference for state saving, used when state saving is enabled in the DataTable\n\t\t * and when the user scrolls the viewport in order to stop the cookie set taking too much\n\t\t * CPU!\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t */\n\t\tstateTO: null,\n\n\t\t/**\n\t\t * setTimeout reference for the redraw, used when server-side processing is enabled in the\n\t\t * DataTables in order to prevent DoSing the server\n\t\t *  @type     int\n\t\t *  @default  null\n\t\t */\n\t\tdrawTO: null,\n\n\t\theights: {\n\t\t\tjump: null,\n\t\t\tpage: null,\n\t\t\tvirtual: null,\n\t\t\tscroll: null,\n\n\t\t\t/**\n\t\t\t * Height of rows in the table\n\t\t\t *  @type     int\n\t\t\t *  @default  0\n\t\t\t */\n\t\t\trow: null,\n\n\t\t\t/**\n\t\t\t * Pixel height of the viewport\n\t\t\t *  @type     int\n\t\t\t *  @default  0\n\t\t\t */\n\t\t\tviewport: null,\n\t\t\tlabelFactor: 1\n\t\t},\n\n\t\ttopRowFloat: 0,\n\t\tscrollDrawDiff: null,\n\t\tloaderVisible: false,\n\t\tforceReposition: false,\n\t\tbaseRowTop: 0,\n\t\tbaseScrollTop: 0,\n\t\tmousedown: false,\n\t\tlastScrollTop: 0\n\t};\n\n\t// @todo The defaults should extend a `c` property and the internal settings\n\t// only held in the `s` property. At the moment they are mixed\n\tthis.s = $.extend( this.s, Scroller.oDefaults, opts );\n\n\t// Workaround for row height being read from height object (see above comment)\n\tthis.s.heights.row = this.s.rowHeight;\n\n\t/**\n\t * DOM elements used by the class instance\n\t * @private\n\t * @namespace\n\t *\n\t */\n\tthis.dom = {\n\t\t\"force\":    document.createElement('div'),\n\t\t\"label\":    $('<div class=\"dts_label\">0</div>'),\n\t\t\"scroller\": null,\n\t\t\"table\":    null,\n\t\t\"loader\":   null\n\t};\n\n\t// Attach the instance to the DataTables instance so it can be accessed in\n\t// future. Don't initialise Scroller twice on the same table\n\tif ( this.s.dt.oScroller ) {\n\t\treturn;\n\t}\n\n\tthis.s.dt.oScroller = this;\n\n\t/* Let's do it */\n\tthis.construct();\n};\n\n\n\n$.extend( Scroller.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Public methods - to be exposed via the DataTables API\n\t */\n\n\t/**\n\t * Calculate and store information about how many rows are to be displayed\n\t * in the scrolling viewport, based on current dimensions in the browser's\n\t * rendering. This can be particularly useful if the table is initially\n\t * drawn in a hidden element - for example in a tab.\n\t *  @param {bool} [redraw=true] Redraw the table automatically after the recalculation, with\n\t *    the new dimensions forming the basis for the draw.\n\t *  @returns {void}\n\t */\n\tmeasure: function ( redraw )\n\t{\n\t\tif ( this.s.autoHeight )\n\t\t{\n\t\t\tthis._calcRowHeight();\n\t\t}\n\n\t\tvar heights = this.s.heights;\n\n\t\tif ( heights.row ) {\n\t\t\theights.viewport = $.contains(document, this.dom.scroller) ?\n\t\t\t\tthis.dom.scroller.clientHeight :\n\t\t\t\tthis._parseHeight($(this.dom.scroller).css('height'));\n\n\t\t\t// If collapsed (no height) use the max-height parameter\n\t\t\tif ( ! heights.viewport ) {\n\t\t\t\theights.viewport = this._parseHeight($(this.dom.scroller).css('max-height'));\n\t\t\t}\n\n\t\t\tthis.s.viewportRows = parseInt( heights.viewport / heights.row, 10 )+1;\n\t\t\tthis.s.dt._iDisplayLength = this.s.viewportRows * this.s.displayBuffer;\n\t\t}\n\n\t\tvar label = this.dom.label.outerHeight();\n\t\theights.labelFactor = (heights.viewport-label) / heights.scroll;\n\n\t\tif ( redraw === undefined || redraw )\n\t\t{\n\t\t\tthis.s.dt.oInstance.fnDraw( false );\n\t\t}\n\t},\n\n\t/**\n\t * Get information about current displayed record range. This corresponds to\n\t * the information usually displayed in the \"Info\" block of the table.\n\t *\n\t * @returns {object} info as an object:\n\t *  {\n\t *      start: {int}, // the 0-indexed record at the top of the viewport\n\t *      end:   {int}, // the 0-indexed record at the bottom of the viewport\n\t *  }\n\t*/\n\tpageInfo: function()\n\t{\n\t\tvar \n\t\t\tdt = this.s.dt,\n\t\t\tiScrollTop = this.dom.scroller.scrollTop,\n\t\t\tiTotal = dt.fnRecordsDisplay(),\n\t\t\tiPossibleEnd = Math.ceil(this.pixelsToRow(iScrollTop + this.s.heights.viewport, false, this.s.ani));\n\n\t\treturn {\n\t\t\tstart: Math.floor(this.pixelsToRow(iScrollTop, false, this.s.ani)),\n\t\t\tend: iTotal < iPossibleEnd ? iTotal-1 : iPossibleEnd-1\n\t\t};\n\t},\n\n\t/**\n\t * Calculate the row number that will be found at the given pixel position\n\t * (y-scroll).\n\t *\n\t * Please note that when the height of the full table exceeds 1 million\n\t * pixels, Scroller switches into a non-linear mode for the scrollbar to fit\n\t * all of the records into a finite area, but this function returns a linear\n\t * value (relative to the last non-linear positioning).\n\t *  @param {int} pixels Offset from top to calculate the row number of\n\t *  @param {int} [intParse=true] If an integer value should be returned\n\t *  @param {int} [virtual=false] Perform the calculations in the virtual domain\n\t *  @returns {int} Row index\n\t */\n\tpixelsToRow: function ( pixels, intParse, virtual )\n\t{\n\t\tvar diff = pixels - this.s.baseScrollTop;\n\t\tvar row = virtual ?\n\t\t\t(this._domain( 'physicalToVirtual', this.s.baseScrollTop ) + diff) / this.s.heights.row :\n\t\t\t( diff / this.s.heights.row ) + this.s.baseRowTop;\n\n\t\treturn intParse || intParse === undefined ?\n\t\t\tparseInt( row, 10 ) :\n\t\t\trow;\n\t},\n\n\t/**\n\t * Calculate the pixel position from the top of the scrolling container for\n\t * a given row\n\t *  @param {int} iRow Row number to calculate the position of\n\t *  @returns {int} Pixels\n\t */\n\trowToPixels: function ( rowIdx, intParse, virtual )\n\t{\n\t\tvar pixels;\n\t\tvar diff = rowIdx - this.s.baseRowTop;\n\n\t\tif ( virtual ) {\n\t\t\tpixels = this._domain( 'virtualToPhysical', this.s.baseScrollTop );\n\t\t\tpixels += diff * this.s.heights.row;\n\t\t}\n\t\telse {\n\t\t\tpixels = this.s.baseScrollTop;\n\t\t\tpixels += diff * this.s.heights.row;\n\t\t}\n\n\t\treturn intParse || intParse === undefined ?\n\t\t\tparseInt( pixels, 10 ) :\n\t\t\tpixels;\n\t},\n\n\n\t/**\n\t * Calculate the row number that will be found at the given pixel position (y-scroll)\n\t *  @param {int} row Row index to scroll to\n\t *  @param {bool} [animate=true] Animate the transition or not\n\t *  @returns {void}\n\t */\n\tscrollToRow: function ( row, animate )\n\t{\n\t\tvar that = this;\n\t\tvar ani = false;\n\t\tvar px = this.rowToPixels( row );\n\n\t\t// We need to know if the table will redraw or not before doing the\n\t\t// scroll. If it will not redraw, then we need to use the currently\n\t\t// displayed table, and scroll with the physical pixels. Otherwise, we\n\t\t// need to calculate the table's new position from the virtual\n\t\t// transform.\n\t\tvar preRows = ((this.s.displayBuffer-1)/2) * this.s.viewportRows;\n\t\tvar drawRow = row - preRows;\n\t\tif ( drawRow < 0 ) {\n\t\t\tdrawRow = 0;\n\t\t}\n\n\t\tif ( (px > this.s.redrawBottom || px < this.s.redrawTop) && this.s.dt._iDisplayStart !== drawRow ) {\n\t\t\tani = true;\n\t\t\tpx = this._domain( 'virtualToPhysical', row * this.s.heights.row );\n\n\t\t\t// If we need records outside the current draw region, but the new\n\t\t\t// scrolling position is inside that (due to the non-linear nature\n\t\t\t// for larger numbers of records), we need to force position update.\n\t\t\tif ( this.s.redrawTop < px && px < this.s.redrawBottom ) {\n\t\t\t\tthis.s.forceReposition = true;\n\t\t\t\tanimate = false;\n\t\t\t}\n\t\t}\n\n\t\tif ( typeof animate == 'undefined' || animate )\n\t\t{\n\t\t\tthis.s.ani = ani;\n\t\t\t$(this.dom.scroller).animate( {\n\t\t\t\t\"scrollTop\": px\n\t\t\t}, function () {\n\t\t\t\t// This needs to happen after the animation has completed and\n\t\t\t\t// the final scroll event fired\n\t\t\t\tsetTimeout( function () {\n\t\t\t\t\tthat.s.ani = false;\n\t\t\t\t}, 25 );\n\t\t\t} );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$(this.dom.scroller).scrollTop( px );\n\t\t}\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\n\t/**\n\t * Initialisation for Scroller\n\t *  @returns {void}\n\t *  @private\n\t */\n\tconstruct: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dtApi;\n\n\t\t/* Sanity check */\n\t\tif ( !this.s.dt.oFeatures.bPaginate ) {\n\t\t\tthis.s.dt.oApi._fnLog( this.s.dt, 0, 'Pagination must be enabled for Scroller' );\n\t\t\treturn;\n\t\t}\n\n\t\t/* Insert a div element that we can use to force the DT scrolling container to\n\t\t * the height that would be required if the whole table was being displayed\n\t\t */\n\t\tthis.dom.force.style.position = \"relative\";\n\t\tthis.dom.force.style.top = \"0px\";\n\t\tthis.dom.force.style.left = \"0px\";\n\t\tthis.dom.force.style.width = \"1px\";\n\n\t\tthis.dom.scroller = $('div.'+this.s.dt.oClasses.sScrollBody, this.s.dt.nTableWrapper)[0];\n\t\tthis.dom.scroller.appendChild( this.dom.force );\n\t\tthis.dom.scroller.style.position = \"relative\";\n\n\t\tthis.dom.table = $('>table', this.dom.scroller)[0];\n\t\tthis.dom.table.style.position = \"absolute\";\n\t\tthis.dom.table.style.top = \"0px\";\n\t\tthis.dom.table.style.left = \"0px\";\n\n\t\t// Add class to 'announce' that we are a Scroller table\n\t\t$(dt.table().container()).addClass('dts DTS');\n\n\t\t// Add a 'loading' indicator\n\t\tif ( this.s.loadingIndicator )\n\t\t{\n\t\t\tthis.dom.loader = $('<div class=\"dataTables_processing dts_loading\">'+this.s.dt.oLanguage.sLoadingRecords+'</div>')\n\t\t\t\t.css('display', 'none');\n\n\t\t\t$(this.dom.scroller.parentNode)\n\t\t\t\t.css('position', 'relative')\n\t\t\t\t.append( this.dom.loader );\n\t\t}\n\n\t\tthis.dom.label.appendTo(this.dom.scroller);\n\n\t\t/* Initial size calculations */\n\t\tif ( this.s.heights.row && this.s.heights.row != 'auto' )\n\t\t{\n\t\t\tthis.s.autoHeight = false;\n\t\t}\n\t\tthis.measure( false );\n\n\t\t// Scrolling callback to see if a page change is needed - use a throttled\n\t\t// function for the save save callback so we aren't hitting it on every\n\t\t// scroll\n\t\tthis.s.ingnoreScroll = true;\n\t\tthis.s.stateSaveThrottle = this.s.dt.oApi._fnThrottle( function () {\n\t\t\tthat.s.dtApi.state.save();\n\t\t}, 500 );\n\t\t$(this.dom.scroller).on( 'scroll.dt-scroller', function (e) {\n\t\t\tthat._scroll.call( that );\n\t\t} );\n\n\t\t// In iOS we catch the touchstart event in case the user tries to scroll\n\t\t// while the display is already scrolling\n\t\t$(this.dom.scroller).on('touchstart.dt-scroller', function () {\n\t\t\tthat._scroll.call( that );\n\t\t} );\n\n\t\t$(this.dom.scroller)\n\t\t\t.on('mousedown.dt-scroller', function () {\n\t\t\t\tthat.s.mousedown = true;\n\t\t\t})\n\t\t\t.on('mouseup.dt-scroller', function () {\n\t\t\t\tthat.s.mouseup = false;\n\t\t\t\tthat.dom.label.css('display', 'none');\n\t\t\t});\n\n\t\t// On resize, update the information element, since the number of rows shown might change\n\t\t$(window).on( 'resize.dt-scroller', function () {\n\t\t\tthat.measure( false );\n\t\t\tthat._info();\n\t\t} );\n\n\t\t// Add a state saving parameter to the DT state saving so we can restore the exact\n\t\t// position of the scrolling. Slightly surprisingly the scroll position isn't actually\n\t\t// stored, but rather tha base units which are needed to calculate it. This allows for\n\t\t// virtual scrolling as well.\n\t\tvar initialStateSave = true;\n\t\tvar loadedState = dt.state.loaded();\n\n\t\tdt.on( 'stateSaveParams.scroller', function ( e, settings, data ) {\n\t\t\t// Need to used the saved position on init\n\t\t\tdata.scroller = {\n\t\t\t\ttopRow: initialStateSave && loadedState && loadedState.scroller ?\n\t\t\t\t\tloadedState.scroller.topRow :\n\t\t\t\t\tthat.s.topRowFloat,\n\t\t\t\tbaseScrollTop: that.s.baseScrollTop,\n\t\t\t\tbaseRowTop: that.s.baseRowTop\n\t\t\t};\n\n\t\t\tinitialStateSave = false;\n\t\t} );\n\n\t\tif ( loadedState && loadedState.scroller ) {\n\t\t\tthis.s.topRowFloat = loadedState.scroller.topRow;\n\t\t\tthis.s.baseScrollTop = loadedState.scroller.baseScrollTop;\n\t\t\tthis.s.baseRowTop = loadedState.scroller.baseRowTop;\n\t\t}\n\n\t\tdt.on( 'init.scroller', function () {\n\t\t\tthat.measure( false );\n\n\t\t\tthat._draw();\n\n\t\t\t// Update the scroller when the DataTable is redrawn\n\t\t\tdt.on( 'draw.scroller', function () {\n\t\t\t\tthat._draw();\n\t\t\t});\n\t\t} );\n\n\t\t// Set height before the draw happens, allowing everything else to update\n\t\t// on draw complete without worry for roder.\n\t\tdt.on( 'preDraw.dt.scroller', function () {\n\t\t\tthat._scrollForce();\n\t\t} );\n\n\t\t// Destructor\n\t\tdt.on( 'destroy.scroller', function () {\n\t\t\t$(window).off( 'resize.dt-scroller' );\n\t\t\t$(that.dom.scroller).off('.dt-scroller');\n\t\t\t$(that.s.dt.nTable).off( '.scroller' );\n\n\t\t\t$(that.s.dt.nTableWrapper).removeClass('DTS');\n\t\t\t$('div.DTS_Loading', that.dom.scroller.parentNode).remove();\n\n\t\t\tthat.dom.table.style.position = \"\";\n\t\t\tthat.dom.table.style.top = \"\";\n\t\t\tthat.dom.table.style.left = \"\";\n\t\t} );\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\n\t/**\n\t * Automatic calculation of table row height. This is just a little tricky here as using\n\t * initialisation DataTables has tale the table out of the document, so we need to create\n\t * a new table and insert it into the document, calculate the row height and then whip the\n\t * table out.\n\t *  @returns {void}\n\t *  @private\n\t */\n\t_calcRowHeight: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar origTable = dt.nTable;\n\t\tvar nTable = origTable.cloneNode( false );\n\t\tvar tbody = $('<tbody/>').appendTo( nTable );\n\t\tvar container = $(\n\t\t\t'<div class=\"'+dt.oClasses.sWrapper+' DTS\">'+\n\t\t\t\t'<div class=\"'+dt.oClasses.sScrollWrapper+'\">'+\n\t\t\t\t\t'<div class=\"'+dt.oClasses.sScrollBody+'\"></div>'+\n\t\t\t\t'</div>'+\n\t\t\t'</div>'\n\t\t);\n\n\t\t// Want 3 rows in the sizing table so :first-child and :last-child\n\t\t// CSS styles don't come into play - take the size of the middle row\n\t\t$('tbody tr:lt(4)', origTable).clone().appendTo( tbody );\n        var rowsCount = $('tr', tbody).length;\n\n        if ( rowsCount === 1 ) {\n            tbody.prepend('<tr><td>&#160;</td></tr>');\n            tbody.append('<tr><td>&#160;</td></tr>');\n\t\t}\n\t\telse {\n            for (; rowsCount < 3; rowsCount++) {\n                tbody.append('<tr><td>&#160;</td></tr>');\n            }\n\t\t}\n\t\n\t\t$('div.'+dt.oClasses.sScrollBody, container).append( nTable );\n\n\t\t// If initialised using `dom`, use the holding element as the insert point\n\t\tvar insertEl = this.s.dt.nHolding || origTable.parentNode;\n\n\t\tif ( ! $(insertEl).is(':visible') ) {\n\t\t\tinsertEl = 'body';\n\t\t}\n\n\t\tcontainer.appendTo( insertEl );\n\t\tthis.s.heights.row = $('tr', tbody).eq(1).outerHeight();\n\n\t\tcontainer.remove();\n\t},\n\n\t/**\n\t * Draw callback function which is fired when the DataTable is redrawn. The main function of\n\t * this method is to position the drawn table correctly the scrolling container for the rows\n\t * that is displays as a result of the scrolling position.\n\t *  @returns {void}\n\t *  @private\n\t */\n\t_draw: function ()\n\t{\n\t\tvar\n\t\t\tthat = this,\n\t\t\theights = this.s.heights,\n\t\t\tiScrollTop = this.dom.scroller.scrollTop,\n\t\t\tiActualScrollTop = iScrollTop,\n\t\t\tiScrollBottom = iScrollTop + heights.viewport,\n\t\t\tiTableHeight = $(this.s.dt.nTable).height(),\n\t\t\tdisplayStart = this.s.dt._iDisplayStart,\n\t\t\tdisplayLen = this.s.dt._iDisplayLength,\n\t\t\tdisplayEnd = this.s.dt.fnRecordsDisplay();\n\n\t\t// Disable the scroll event listener while we are updating the DOM\n\t\tthis.s.skip = true;\n\n\t\t// If paging is reset\n\t\tif ( (this.s.dt.bSorted || this.s.dt.bFiltered) && displayStart === 0 && !this.s.dt._drawHold ) {\n\t\t\tthis.s.topRowFloat = 0;\n\t\t}\n\n\t\tiScrollTop = this.scrollType === 'jump' ?\n\t\t\tthis._domain( 'physicalToVirtual', this.s.topRowFloat * heights.row ) :\n\t\t\tiScrollTop;\n\n\t\t// This doesn't work when scrolling with the mouse wheel\n\t\t$(that.dom.scroller).scrollTop(iScrollTop);\n\n\t\t// Store positional information so positional calculations can be based\n\t\t// upon the current table draw position\n\t\tthis.s.baseScrollTop = iScrollTop;\n\t\tthis.s.baseRowTop = this.s.topRowFloat;\n\n\t\t// Position the table in the virtual scroller\n\t\tvar tableTop = iScrollTop - ((this.s.topRowFloat - displayStart) * heights.row);\n\t\tif ( displayStart === 0 ) {\n\t\t\ttableTop = 0;\n\t\t}\n\t\telse if ( displayStart + displayLen >= displayEnd ) {\n\t\t\ttableTop = heights.scroll - iTableHeight;\n\t\t}\n\n\t\tthis.dom.table.style.top = tableTop+'px';\n\n\t\t/* Cache some information for the scroller */\n\t\tthis.s.tableTop = tableTop;\n\t\tthis.s.tableBottom = iTableHeight + this.s.tableTop;\n\n\t\t// Calculate the boundaries for where a redraw will be triggered by the\n\t\t// scroll event listener\n\t\tvar boundaryPx = (iScrollTop - this.s.tableTop) * this.s.boundaryScale;\n\t\tthis.s.redrawTop = iScrollTop - boundaryPx;\n\t\tthis.s.redrawBottom = iScrollTop + boundaryPx > heights.scroll - heights.viewport - heights.row ?\n\t\t\theights.scroll - heights.viewport - heights.row :\n\t\t\tiScrollTop + boundaryPx;\n\n\t\tthis.s.skip = false;\n\n\t\t// Restore the scrolling position that was saved by DataTable's state\n\t\t// saving Note that this is done on the second draw when data is Ajax\n\t\t// sourced, and the first draw when DOM soured\n\t\tif ( this.s.dt.oFeatures.bStateSave && this.s.dt.oLoadedState !== null &&\n\t\t\t typeof this.s.dt.oLoadedState.iScroller != 'undefined' )\n\t\t{\n\t\t\t// A quirk of DataTables is that the draw callback will occur on an\n\t\t\t// empty set if Ajax sourced, but not if server-side processing.\n\t\t\tvar ajaxSourced = (this.s.dt.sAjaxSource || that.s.dt.ajax) && ! this.s.dt.oFeatures.bServerSide ?\n\t\t\t\ttrue :\n\t\t\t\tfalse;\n\n\t\t\tif ( ( ajaxSourced && this.s.dt.iDraw == 2) ||\n\t\t\t     (!ajaxSourced && this.s.dt.iDraw == 1) )\n\t\t\t{\n\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t$(that.dom.scroller).scrollTop( that.s.dt.oLoadedState.iScroller );\n\t\t\t\t\tthat.s.redrawTop = that.s.dt.oLoadedState.iScroller - (heights.viewport/2);\n\n\t\t\t\t\t// In order to prevent layout thrashing we need another\n\t\t\t\t\t// small delay\n\t\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t\tthat.s.ingnoreScroll = false;\n\t\t\t\t\t}, 0 );\n\t\t\t\t}, 0 );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tthat.s.ingnoreScroll = false;\n\t\t}\n\n\t\t// Because of the order of the DT callbacks, the info update will\n\t\t// take precedence over the one we want here. So a 'thread' break is\n\t\t// needed.  Only add the thread break if bInfo is set\n\t\tif ( this.s.dt.oFeatures.bInfo ) {\n\t\t\tsetTimeout( function () {\n\t\t\t\tthat._info.call( that );\n\t\t\t}, 0 );\n\t\t}\n\n\t\t// Hide the loading indicator\n\t\tif ( this.dom.loader && this.s.loaderVisible ) {\n\t\t\tthis.dom.loader.css( 'display', 'none' );\n\t\t\tthis.s.loaderVisible = false;\n\t\t}\n\t},\n\n\t/**\n\t * Convert from one domain to another. The physical domain is the actual\n\t * pixel count on the screen, while the virtual is if we had browsers which\n\t * had scrolling containers of infinite height (i.e. the absolute value)\n\t *\n\t *  @param {string} dir Domain transform direction, `virtualToPhysical` or\n\t *    `physicalToVirtual` \n\t *  @returns {number} Calculated transform\n\t *  @private\n\t */\n\t_domain: function ( dir, val )\n\t{\n\t\tvar heights = this.s.heights;\n\t\tvar diff;\n\t\tvar magic = 10000; // the point at which the non-linear calculations start to happen\n\n\t\t// If the virtual and physical height match, then we use a linear\n\t\t// transform between the two, allowing the scrollbar to be linear\n\t\tif ( heights.virtual === heights.scroll ) {\n\t\t\treturn val;\n\t\t}\n\n\t\t// In the first 10k pixels and the last 10k pixels, we want the scrolling\n\t\t// to be linear. After that it can be non-linear. It would be unusual for\n\t\t// anyone to mouse wheel through that much.\n\t\tif ( val < magic ) {\n\t\t\treturn val;\n\t\t}\n\t\telse if ( dir === 'virtualToPhysical' && val > heights.virtual - magic ) {\n\t\t\tdiff = heights.virtual - val;\n\t\t\treturn heights.scroll - diff;\n\t\t}\n\t\telse if ( dir === 'physicalToVirtual' && val > heights.scroll - magic ) {\n\t\t\tdiff = heights.scroll - val;\n\t\t\treturn heights.virtual - diff;\n\t\t}\n\n\t\t// Otherwise, we want a non-linear scrollbar to take account of the\n\t\t// redrawing regions at the start and end of the table, otherwise these\n\t\t// can stutter badly - on large tables 30px (for example) scroll might\n\t\t// be hundreds of rows, so the table would be redrawing every few px at\n\t\t// the start and end. Use a simple linear eq. to stop this, effectively\n\t\t// causing a kink in the scrolling ratio. It does mean the scrollbar is\n\t\t// non-linear, but with such massive data sets, the scrollbar is going\n\t\t// to be a best guess anyway\n\t\tvar xMax = dir === 'virtualToPhysical' ?\n\t\t\theights.virtual :\n\t\t\theights.scroll;\n\t\tvar yMax = dir === 'virtualToPhysical' ?\n\t\t\theights.scroll :\n\t\t\theights.virtual;\n\n\t\tvar m = (yMax - magic) / (xMax - magic);\n\t\tvar c = magic - (m*magic);\n\n\t\treturn (m*val) + c;\n\t},\n\n\t/**\n\t * Update any information elements that are controlled by the DataTable based on the scrolling\n\t * viewport and what rows are visible in it. This function basically acts in the same way as\n\t * _fnUpdateInfo in DataTables, and effectively replaces that function.\n\t *  @returns {void}\n\t *  @private\n\t */\n\t_info: function ()\n\t{\n\t\tif ( !this.s.dt.oFeatures.bInfo )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tvar\n\t\t\tdt = this.s.dt,\n\t\t\tlanguage = dt.oLanguage,\n\t\t\tiScrollTop = this.dom.scroller.scrollTop,\n\t\t\tiStart = Math.floor( this.pixelsToRow(iScrollTop, false, this.s.ani)+1 ),\n\t\t\tiMax = dt.fnRecordsTotal(),\n\t\t\tiTotal = dt.fnRecordsDisplay(),\n\t\t\tiPossibleEnd = Math.ceil( this.pixelsToRow(iScrollTop+this.s.heights.viewport, false, this.s.ani) ),\n\t\t\tiEnd = iTotal < iPossibleEnd ? iTotal : iPossibleEnd,\n\t\t\tsStart = dt.fnFormatNumber( iStart ),\n\t\t\tsEnd = dt.fnFormatNumber( iEnd ),\n\t\t\tsMax = dt.fnFormatNumber( iMax ),\n\t\t\tsTotal = dt.fnFormatNumber( iTotal ),\n\t\t\tsOut;\n\n\t\tif ( dt.fnRecordsDisplay() === 0 &&\n\t\t\t   dt.fnRecordsDisplay() == dt.fnRecordsTotal() )\n\t\t{\n\t\t\t/* Empty record set */\n\t\t\tsOut = language.sInfoEmpty+ language.sInfoPostFix;\n\t\t}\n\t\telse if ( dt.fnRecordsDisplay() === 0 )\n\t\t{\n\t\t\t/* Empty record set after filtering */\n\t\t\tsOut = language.sInfoEmpty +' '+\n\t\t\t\tlanguage.sInfoFiltered.replace('_MAX_', sMax)+\n\t\t\t\t\tlanguage.sInfoPostFix;\n\t\t}\n\t\telse if ( dt.fnRecordsDisplay() == dt.fnRecordsTotal() )\n\t\t{\n\t\t\t/* Normal record set */\n\t\t\tsOut = language.sInfo.\n\t\t\t\t\treplace('_START_', sStart).\n\t\t\t\t\treplace('_END_',   sEnd).\n\t\t\t\t\treplace('_MAX_',   sMax).\n\t\t\t\t\treplace('_TOTAL_', sTotal)+\n\t\t\t\tlanguage.sInfoPostFix;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Record set after filtering */\n\t\t\tsOut = language.sInfo.\n\t\t\t\t\treplace('_START_', sStart).\n\t\t\t\t\treplace('_END_',   sEnd).\n\t\t\t\t\treplace('_MAX_',   sMax).\n\t\t\t\t\treplace('_TOTAL_', sTotal) +' '+\n\t\t\t\tlanguage.sInfoFiltered.replace(\n\t\t\t\t\t'_MAX_',\n\t\t\t\t\tdt.fnFormatNumber(dt.fnRecordsTotal())\n\t\t\t\t)+\n\t\t\t\tlanguage.sInfoPostFix;\n\t\t}\n\n\t\tvar callback = language.fnInfoCallback;\n\t\tif ( callback ) {\n\t\t\tsOut = callback.call( dt.oInstance,\n\t\t\t\tdt, iStart, iEnd, iMax, iTotal, sOut\n\t\t\t);\n\t\t}\n\n\t\tvar n = dt.aanFeatures.i;\n\t\tif ( typeof n != 'undefined' )\n\t\t{\n\t\t\tfor ( var i=0, iLen=n.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t$(n[i]).html( sOut );\n\t\t\t}\n\t\t}\n\n\t\t// DT doesn't actually (yet) trigger this event, but it will in future\n\t\t$(dt.nTable).triggerHandler( 'info.dt' );\n\t},\n\n\t/**\n\t * Parse CSS height property string as number\n\t *\n\t * An attempt is made to parse the string as a number. Currently supported units are 'px',\n\t * 'vh', and 'rem'. 'em' is partially supported; it works as long as the parent element's\n\t * font size matches the body element. Zero is returned for unrecognized strings.\n\t *  @param {string} cssHeight CSS height property string\n\t *  @returns {number} height\n\t *  @private\n\t */\n\t_parseHeight: function(cssHeight) {\n\t\tvar height;\n\t\tvar matches = /^([+-]?(?:\\d+(?:\\.\\d+)?|\\.\\d+))(px|em|rem|vh)$/.exec(cssHeight);\n\n\t\tif (matches === null) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar value = parseFloat(matches[1]);\n\t\tvar unit = matches[2];\n\n\t\tif ( unit === 'px' ) {\n\t\t\theight = value;\n\t\t}\n\t\telse if ( unit === 'vh' ) {\n\t\t\theight = ( value / 100 ) * $(window).height();\n\t\t}\n\t\telse if ( unit === 'rem' ) {\n\t\t\theight = value * parseFloat($(':root').css('font-size'));\n\t\t}\n\t\telse if ( unit === 'em' ) {\n\t\t\theight = value * parseFloat($('body').css('font-size'));\n\t\t}\n\n\t\treturn height ?\n\t\t\theight :\n\t\t\t0;\n\t},\n\n\t/**\n\t * Scrolling function - fired whenever the scrolling position is changed.\n\t * This method needs to use the stored values to see if the table should be\n\t * redrawn as we are moving towards the end of the information that is\n\t * currently drawn or not. If needed, then it will redraw the table based on\n\t * the new position.\n\t *  @returns {void}\n\t *  @private\n\t */\n\t_scroll: function ()\n\t{\n\t\tvar\n\t\t\tthat = this,\n\t\t\theights = this.s.heights,\n\t\t\tiScrollTop = this.dom.scroller.scrollTop,\n\t\t\tiTopRow;\n\n\t\tif ( this.s.skip ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this.s.ingnoreScroll ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( iScrollTop === this.s.lastScrollTop ) {\n\t\t\treturn;\n\t\t}\n\n\t\t/* If the table has been sorted or filtered, then we use the redraw that\n\t\t * DataTables as done, rather than performing our own\n\t\t */\n\t\tif ( this.s.dt.bFiltered || this.s.dt.bSorted ) {\n\t\t\tthis.s.lastScrollTop = 0;\n\t\t\treturn;\n\t\t}\n\n\t\t/* Update the table's information display for what is now in the viewport */\n\t\tthis._info();\n\n\t\t/* We don't want to state save on every scroll event - that's heavy\n\t\t * handed, so use a timeout to update the state saving only when the\n\t\t * scrolling has finished\n\t\t */\n\t\tclearTimeout( this.s.stateTO );\n\t\tthis.s.stateTO = setTimeout( function () {\n\t\t\tthat.s.dtApi.state.save();\n\t\t}, 250 );\n\n\t\tthis.s.scrollType = Math.abs(iScrollTop - this.s.lastScrollTop) > heights.viewport ?\n\t\t\t'jump' :\n\t\t\t'cont';\n\n\t\tthis.s.topRowFloat = this.s.scrollType === 'cont' ?\n\t\t\tthis.pixelsToRow( iScrollTop, false, false ) :\n\t\t\tthis._domain( 'physicalToVirtual', iScrollTop ) / heights.row;\n\n\t\tif ( this.s.topRowFloat < 0 ) {\n\t\t\tthis.s.topRowFloat = 0;\n\t\t}\n\n\t\t/* Check if the scroll point is outside the trigger boundary which would required\n\t\t * a DataTables redraw\n\t\t */\n\t\tif ( this.s.forceReposition || iScrollTop < this.s.redrawTop || iScrollTop > this.s.redrawBottom ) {\n\t\t\tvar preRows = Math.ceil( ((this.s.displayBuffer-1)/2) * this.s.viewportRows );\n\n\t\t\tiTopRow = parseInt(this.s.topRowFloat, 10) - preRows;\n\t\t\tthis.s.forceReposition = false;\n\n\t\t\tif ( iTopRow <= 0 ) {\n\t\t\t\t/* At the start of the table */\n\t\t\t\tiTopRow = 0;\n\t\t\t}\n\t\t\telse if ( iTopRow + this.s.dt._iDisplayLength > this.s.dt.fnRecordsDisplay() ) {\n\t\t\t\t/* At the end of the table */\n\t\t\t\tiTopRow = this.s.dt.fnRecordsDisplay() - this.s.dt._iDisplayLength;\n\t\t\t\tif ( iTopRow < 0 ) {\n\t\t\t\t\tiTopRow = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( iTopRow % 2 !== 0 ) {\n\t\t\t\t// For the row-striping classes (odd/even) we want only to start\n\t\t\t\t// on evens otherwise the stripes will change between draws and\n\t\t\t\t// look rubbish\n\t\t\t\tiTopRow++;\n\t\t\t}\n\n\n\t\t\tif ( iTopRow != this.s.dt._iDisplayStart ) {\n\t\t\t\t/* Cache the new table position for quick lookups */\n\t\t\t\tthis.s.tableTop = $(this.s.dt.nTable).offset().top;\n\t\t\t\tthis.s.tableBottom = $(this.s.dt.nTable).height() + this.s.tableTop;\n\n\t\t\t\tvar draw =  function () {\n\t\t\t\t\tif ( that.s.scrollDrawReq === null ) {\n\t\t\t\t\t\tthat.s.scrollDrawReq = iScrollTop;\n\t\t\t\t\t}\n\n\t\t\t\t\tthat.s.dt._iDisplayStart = iTopRow;\n\t\t\t\t\tthat.s.dt.oApi._fnDraw( that.s.dt );\n\t\t\t\t};\n\n\t\t\t\t/* Do the DataTables redraw based on the calculated start point - note that when\n\t\t\t\t * using server-side processing we introduce a small delay to not DoS the server...\n\t\t\t\t */\n\t\t\t\tif ( this.s.dt.oFeatures.bServerSide ) {\n\t\t\t\t\tclearTimeout( this.s.drawTO );\n\t\t\t\t\tthis.s.drawTO = setTimeout( draw, this.s.serverWait );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdraw();\n\t\t\t\t}\n\n\t\t\t\tif ( this.dom.loader && ! this.s.loaderVisible ) {\n\t\t\t\t\tthis.dom.loader.css( 'display', 'block' );\n\t\t\t\t\tthis.s.loaderVisible = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tthis.s.topRowFloat = this.pixelsToRow( iScrollTop, false, true );\n\t\t}\n\n\t\tthis.s.lastScrollTop = iScrollTop;\n\t\tthis.s.stateSaveThrottle();\n\n\t\tif ( this.s.scrollType === 'jump' && this.s.mousedown ) {\n\t\t\tthis.dom.label\n\t\t\t\t.html( this.s.dt.fnFormatNumber( parseInt( this.s.topRowFloat, 10 )+1 ) )\n\t\t\t\t.css( 'top', iScrollTop + (iScrollTop * heights.labelFactor ) )\n\t\t\t\t.css( 'display', 'block' );\n\t\t}\n\t},\n\n\t/**\n\t * Force the scrolling container to have height beyond that of just the\n\t * table that has been drawn so the user can scroll the whole data set.\n\t *\n\t * Note that if the calculated required scrolling height exceeds a maximum\n\t * value (1 million pixels - hard-coded) the forcing element will be set\n\t * only to that maximum value and virtual / physical domain transforms will\n\t * be used to allow Scroller to display tables of any number of records.\n\t *  @returns {void}\n\t *  @private\n\t */\n\t_scrollForce: function ()\n\t{\n\t\tvar heights = this.s.heights;\n\t\tvar max = 1000000;\n\n\t\theights.virtual = heights.row * this.s.dt.fnRecordsDisplay();\n\t\theights.scroll = heights.virtual;\n\n\t\tif ( heights.scroll > max ) {\n\t\t\theights.scroll = max;\n\t\t}\n\n\t\t// Minimum height so there is always a row visible (the 'no rows found'\n\t\t// if reduced to zero filtering)\n\t\tthis.dom.force.style.height = heights.scroll > this.s.heights.row ?\n\t\t\theights.scroll+'px' :\n\t\t\tthis.s.heights.row+'px';\n\t}\n} );\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Statics\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\n/**\n * Scroller default settings for initialisation\n *  @namespace\n *  @name Scroller.defaults\n *  @static\n */\nScroller.defaults = {\n\t/**\n\t * Scroller uses the boundary scaling factor to decide when to redraw the table - which it\n\t * typically does before you reach the end of the currently loaded data set (in order to\n\t * allow the data to look continuous to a user scrolling through the data). If given as 0\n\t * then the table will be redrawn whenever the viewport is scrolled, while 1 would not\n\t * redraw the table until the currently loaded data has all been shown. You will want\n\t * something in the middle - the default factor of 0.5 is usually suitable.\n\t *  @type     float\n\t *  @default  0.5\n\t *  @static\n\t */\n\tboundaryScale: 0.5,\n\n\t/**\n\t * The display buffer is what Scroller uses to calculate how many rows it should pre-fetch\n\t * for scrolling. Scroller automatically adjusts DataTables' display length to pre-fetch\n\t * rows that will be shown in \"near scrolling\" (i.e. just beyond the current display area).\n\t * The value is based upon the number of rows that can be displayed in the viewport (i.e.\n\t * a value of 1), and will apply the display range to records before before and after the\n\t * current viewport - i.e. a factor of 3 will allow Scroller to pre-fetch 1 viewport's worth\n\t * of rows before the current viewport, the current viewport's rows and 1 viewport's worth\n\t * of rows after the current viewport. Adjusting this value can be useful for ensuring\n\t * smooth scrolling based on your data set.\n\t *  @type     int\n\t *  @default  7\n\t *  @static\n\t */\n\tdisplayBuffer: 9,\n\n\t/**\n\t * Show (or not) the loading element in the background of the table. Note that you should\n\t * include the dataTables.scroller.css file for this to be displayed correctly.\n\t *  @type     boolean\n\t *  @default  false\n\t *  @static\n\t */\n\tloadingIndicator: false,\n\n\t/**\n\t * Scroller will attempt to automatically calculate the height of rows for it's internal\n\t * calculations. However the height that is used can be overridden using this parameter.\n\t *  @type     int|string\n\t *  @default  auto\n\t *  @static\n\t */\n\trowHeight: \"auto\",\n\n\t/**\n\t * When using server-side processing, Scroller will wait a small amount of time to allow\n\t * the scrolling to finish before requesting more data from the server. This prevents\n\t * you from DoSing your own server! The wait time can be configured by this parameter.\n\t *  @type     int\n\t *  @default  200\n\t *  @static\n\t */\n\tserverWait: 200\n};\n\nScroller.oDefaults = Scroller.defaults;\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Constants\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n/**\n * Scroller version\n *  @type      String\n *  @default   See code\n *  @name      Scroller.version\n *  @static\n */\nScroller.version = \"2.0.0\";\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Initialisation\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'preInit.dt.dtscroller', function (e, settings) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.scroller;\n\tvar defaults = DataTable.defaults.scroller;\n\n\tif ( init || defaults ) {\n\t\tvar opts = $.extend( {}, init, defaults );\n\n\t\tif ( init !== false ) {\n\t\t\tnew Scroller( settings, opts  );\n\t\t}\n\t}\n} );\n\n\n// Attach Scroller to DataTables so it can be accessed as an 'extra'\n$.fn.dataTable.Scroller = Scroller;\n$.fn.DataTable.Scroller = Scroller;\n\n\n// DataTables 1.10 API method aliases\nvar Api = $.fn.dataTable.Api;\n\nApi.register( 'scroller()', function () {\n\treturn this;\n} );\n\n// Undocumented and deprecated - is it actually useful at all?\nApi.register( 'scroller().rowToPixels()', function ( rowIdx, intParse, virtual ) {\n\tvar ctx = this.context;\n\n\tif ( ctx.length && ctx[0].oScroller ) {\n\t\treturn ctx[0].oScroller.rowToPixels( rowIdx, intParse, virtual );\n\t}\n\t// undefined\n} );\n\n// Undocumented and deprecated - is it actually useful at all?\nApi.register( 'scroller().pixelsToRow()', function ( pixels, intParse, virtual ) {\n\tvar ctx = this.context;\n\n\tif ( ctx.length && ctx[0].oScroller ) {\n\t\treturn ctx[0].oScroller.pixelsToRow( pixels, intParse, virtual );\n\t}\n\t// undefined\n} );\n\n// `scroller().scrollToRow()` is undocumented and deprecated. Use `scroller.toPosition()\nApi.register( ['scroller().scrollToRow()', 'scroller.toPosition()'], function ( idx, ani ) {\n\tthis.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx.oScroller ) {\n\t\t\tctx.oScroller.scrollToRow( idx, ani );\n\t\t}\n\t} );\n\n\treturn this;\n} );\n\nApi.register( 'row().scrollTo()', function ( ani ) {\n\tvar that = this;\n\n\tthis.iterator( 'row', function ( ctx, rowIdx ) {\n\t\tif ( ctx.oScroller ) {\n\t\t\tvar displayIdx = that\n\t\t\t\t.rows( { order: 'applied', search: 'applied' } )\n\t\t\t\t.indexes()\n\t\t\t\t.indexOf( rowIdx );\n\n\t\t\tctx.oScroller.scrollToRow( displayIdx, ani );\n\t\t}\n\t} );\n\n\treturn this;\n} );\n\nApi.register( 'scroller.measure()', function ( redraw ) {\n\tthis.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx.oScroller ) {\n\t\t\tctx.oScroller.measure( redraw );\n\t\t}\n\t} );\n\n\treturn this;\n} );\n\nApi.register( 'scroller.page()', function() {\n\tvar ctx = this.context;\n\n\tif ( ctx.length && ctx[0].oScroller ) {\n\t\treturn ctx[0].oScroller.pageInfo();\n\t}\n\t// undefined\n} );\n\nreturn Scroller;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Scroller-2.0.0/js/scroller.bootstrap.js",
    "content": "/*! Bootstrap 3 styling wrapper for Scroller\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs', 'datatables.net-scroller'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Scroller ) {\n\t\t\t\trequire('datatables.net-scroller')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/Scroller-2.0.0/js/scroller.bootstrap4.js",
    "content": "/*! Bootstrap 4 styling wrapper for Scroller\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs4', 'datatables.net-scroller'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs4')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Scroller ) {\n\t\t\t\trequire('datatables.net-scroller')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/Scroller-2.0.0/js/scroller.dataTables.js",
    "content": "/*! DataTables styling wrapper for Scroller\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-dt', 'datatables.net-scroller'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-dt')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Scroller ) {\n\t\t\t\trequire('datatables.net-scroller')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/Scroller-2.0.0/js/scroller.foundation.js",
    "content": "/*! Bootstrap 4 styling wrapper for Scroller\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-zf', 'datatables.net-scroller'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-zf')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Scroller ) {\n\t\t\t\trequire('datatables.net-scroller')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/Scroller-2.0.0/js/scroller.jqueryui.js",
    "content": "/*! jQuery UI styling wrapper for Scroller\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-jqui', 'datatables.net-scroller'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-jqui')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Scroller ) {\n\t\t\t\trequire('datatables.net-scroller')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/Scroller-2.0.0/js/scroller.semanicui.js",
    "content": ""
  },
  {
    "path": "static/js/DataTables/Scroller-2.0.0/js/scroller.semanticui.js",
    "content": "/*! Semanic UI styling wrapper for Scroller\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-se', 'datatables.net-scroller'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-se')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Scroller ) {\n\t\t\t\trequire('datatables.net-scroller')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/Select-1.3.0/css/select.bootstrap.css",
    "content": "table.dataTable tbody > tr.selected,\ntable.dataTable tbody > tr > .selected {\n  background-color: #08C;\n}\ntable.dataTable.stripe tbody > tr.odd.selected,\ntable.dataTable.stripe tbody > tr.odd > .selected, table.dataTable.display tbody > tr.odd.selected,\ntable.dataTable.display tbody > tr.odd > .selected {\n  background-color: #0085c7;\n}\ntable.dataTable.hover tbody > tr.selected:hover,\ntable.dataTable.hover tbody > tr > .selected:hover, table.dataTable.display tbody > tr.selected:hover,\ntable.dataTable.display tbody > tr > .selected:hover {\n  background-color: #0083c5;\n}\ntable.dataTable.order-column tbody > tr.selected > .sorting_1,\ntable.dataTable.order-column tbody > tr.selected > .sorting_2,\ntable.dataTable.order-column tbody > tr.selected > .sorting_3,\ntable.dataTable.order-column tbody > tr > .selected, table.dataTable.display tbody > tr.selected > .sorting_1,\ntable.dataTable.display tbody > tr.selected > .sorting_2,\ntable.dataTable.display tbody > tr.selected > .sorting_3,\ntable.dataTable.display tbody > tr > .selected {\n  background-color: #0085c8;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_1 {\n  background-color: #0081c1;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_2 {\n  background-color: #0082c2;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_3 {\n  background-color: #0083c4;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_1 {\n  background-color: #0085c8;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_2 {\n  background-color: #0086ca;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_3 {\n  background-color: #0087cb;\n}\ntable.dataTable.display tbody > tr.odd > .selected, table.dataTable.order-column.stripe tbody > tr.odd > .selected {\n  background-color: #0081c1;\n}\ntable.dataTable.display tbody > tr.even > .selected, table.dataTable.order-column.stripe tbody > tr.even > .selected {\n  background-color: #0085c8;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_1, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_1 {\n  background-color: #007dbb;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_2, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_2 {\n  background-color: #007ebd;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_3, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_3 {\n  background-color: #007fbf;\n}\ntable.dataTable.display tbody > tr:hover > .selected,\ntable.dataTable.display tbody > tr > .selected:hover, table.dataTable.order-column.hover tbody > tr:hover > .selected,\ntable.dataTable.order-column.hover tbody > tr > .selected:hover {\n  background-color: #007dbb;\n}\ntable.dataTable tbody td.select-checkbox,\ntable.dataTable tbody th.select-checkbox {\n  position: relative;\n}\ntable.dataTable tbody td.select-checkbox:before, table.dataTable tbody td.select-checkbox:after,\ntable.dataTable tbody th.select-checkbox:before,\ntable.dataTable tbody th.select-checkbox:after {\n  display: block;\n  position: absolute;\n  top: 1.2em;\n  left: 50%;\n  width: 12px;\n  height: 12px;\n  box-sizing: border-box;\n}\ntable.dataTable tbody td.select-checkbox:before,\ntable.dataTable tbody th.select-checkbox:before {\n  content: ' ';\n  margin-top: -6px;\n  margin-left: -6px;\n  border: 1px solid black;\n  border-radius: 3px;\n}\ntable.dataTable tr.selected td.select-checkbox:after,\ntable.dataTable tr.selected th.select-checkbox:after {\n  content: '\\2714';\n  margin-top: -11px;\n  margin-left: -4px;\n  text-align: center;\n  text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9;\n}\n\ndiv.dataTables_wrapper span.select-info,\ndiv.dataTables_wrapper span.select-item {\n  margin-left: 0.5em;\n}\n\n@media screen and (max-width: 640px) {\n  div.dataTables_wrapper span.select-info,\n  div.dataTables_wrapper span.select-item {\n    margin-left: 0;\n    display: block;\n  }\n}\ntable.dataTable tbody tr.selected,\ntable.dataTable tbody th.selected,\ntable.dataTable tbody td.selected {\n  color: white;\n}\ntable.dataTable tbody tr.selected a,\ntable.dataTable tbody th.selected a,\ntable.dataTable tbody td.selected a {\n  color: #a2d4ed;\n}\n"
  },
  {
    "path": "static/js/DataTables/Select-1.3.0/css/select.bootstrap4.css",
    "content": "table.dataTable tbody > tr.selected,\ntable.dataTable tbody > tr > .selected {\n  background-color: #0275d8;\n}\ntable.dataTable.stripe tbody > tr.odd.selected,\ntable.dataTable.stripe tbody > tr.odd > .selected, table.dataTable.display tbody > tr.odd.selected,\ntable.dataTable.display tbody > tr.odd > .selected {\n  background-color: #0272d3;\n}\ntable.dataTable.hover tbody > tr.selected:hover,\ntable.dataTable.hover tbody > tr > .selected:hover, table.dataTable.display tbody > tr.selected:hover,\ntable.dataTable.display tbody > tr > .selected:hover {\n  background-color: #0271d0;\n}\ntable.dataTable.order-column tbody > tr.selected > .sorting_1,\ntable.dataTable.order-column tbody > tr.selected > .sorting_2,\ntable.dataTable.order-column tbody > tr.selected > .sorting_3,\ntable.dataTable.order-column tbody > tr > .selected, table.dataTable.display tbody > tr.selected > .sorting_1,\ntable.dataTable.display tbody > tr.selected > .sorting_2,\ntable.dataTable.display tbody > tr.selected > .sorting_3,\ntable.dataTable.display tbody > tr > .selected {\n  background-color: #0273d4;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_1 {\n  background-color: #026fcc;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_2 {\n  background-color: #0270ce;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_3 {\n  background-color: #0270d0;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_1 {\n  background-color: #0273d4;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_2 {\n  background-color: #0274d5;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_3 {\n  background-color: #0275d7;\n}\ntable.dataTable.display tbody > tr.odd > .selected, table.dataTable.order-column.stripe tbody > tr.odd > .selected {\n  background-color: #026fcc;\n}\ntable.dataTable.display tbody > tr.even > .selected, table.dataTable.order-column.stripe tbody > tr.even > .selected {\n  background-color: #0273d4;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_1, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_1 {\n  background-color: #026bc6;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_2, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_2 {\n  background-color: #026cc8;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_3, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_3 {\n  background-color: #026eca;\n}\ntable.dataTable.display tbody > tr:hover > .selected,\ntable.dataTable.display tbody > tr > .selected:hover, table.dataTable.order-column.hover tbody > tr:hover > .selected,\ntable.dataTable.order-column.hover tbody > tr > .selected:hover {\n  background-color: #026bc6;\n}\ntable.dataTable tbody td.select-checkbox,\ntable.dataTable tbody th.select-checkbox {\n  position: relative;\n}\ntable.dataTable tbody td.select-checkbox:before, table.dataTable tbody td.select-checkbox:after,\ntable.dataTable tbody th.select-checkbox:before,\ntable.dataTable tbody th.select-checkbox:after {\n  display: block;\n  position: absolute;\n  top: 1.2em;\n  left: 50%;\n  width: 12px;\n  height: 12px;\n  box-sizing: border-box;\n}\ntable.dataTable tbody td.select-checkbox:before,\ntable.dataTable tbody th.select-checkbox:before {\n  content: ' ';\n  margin-top: -6px;\n  margin-left: -6px;\n  border: 1px solid black;\n  border-radius: 3px;\n}\ntable.dataTable tr.selected td.select-checkbox:after,\ntable.dataTable tr.selected th.select-checkbox:after {\n  content: '\\2714';\n  margin-top: -11px;\n  margin-left: -4px;\n  text-align: center;\n  text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9;\n}\n\ndiv.dataTables_wrapper span.select-info,\ndiv.dataTables_wrapper span.select-item {\n  margin-left: 0.5em;\n}\n\n@media screen and (max-width: 640px) {\n  div.dataTables_wrapper span.select-info,\n  div.dataTables_wrapper span.select-item {\n    margin-left: 0;\n    display: block;\n  }\n}\ntable.dataTable tbody tr.selected,\ntable.dataTable tbody th.selected,\ntable.dataTable tbody td.selected {\n  color: white;\n}\ntable.dataTable tbody tr.selected a,\ntable.dataTable tbody th.selected a,\ntable.dataTable tbody td.selected a {\n  color: #a2d4ed;\n}\n"
  },
  {
    "path": "static/js/DataTables/Select-1.3.0/css/select.dataTables.css",
    "content": "table.dataTable tbody > tr.selected,\ntable.dataTable tbody > tr > .selected {\n  background-color: #B0BED9;\n}\ntable.dataTable.stripe tbody > tr.odd.selected,\ntable.dataTable.stripe tbody > tr.odd > .selected, table.dataTable.display tbody > tr.odd.selected,\ntable.dataTable.display tbody > tr.odd > .selected {\n  background-color: #acbad4;\n}\ntable.dataTable.hover tbody > tr.selected:hover,\ntable.dataTable.hover tbody > tr > .selected:hover, table.dataTable.display tbody > tr.selected:hover,\ntable.dataTable.display tbody > tr > .selected:hover {\n  background-color: #aab7d1;\n}\ntable.dataTable.order-column tbody > tr.selected > .sorting_1,\ntable.dataTable.order-column tbody > tr.selected > .sorting_2,\ntable.dataTable.order-column tbody > tr.selected > .sorting_3,\ntable.dataTable.order-column tbody > tr > .selected, table.dataTable.display tbody > tr.selected > .sorting_1,\ntable.dataTable.display tbody > tr.selected > .sorting_2,\ntable.dataTable.display tbody > tr.selected > .sorting_3,\ntable.dataTable.display tbody > tr > .selected {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_1 {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_2 {\n  background-color: #a8b5cf;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_3 {\n  background-color: #a9b7d1;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_1 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_2 {\n  background-color: #aebcd6;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody > tr.odd > .selected, table.dataTable.order-column.stripe tbody > tr.odd > .selected {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody > tr.even > .selected, table.dataTable.order-column.stripe tbody > tr.even > .selected {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_1, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_1 {\n  background-color: #a2aec7;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_2, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_2 {\n  background-color: #a3b0c9;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_3, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_3 {\n  background-color: #a5b2cb;\n}\ntable.dataTable.display tbody > tr:hover > .selected,\ntable.dataTable.display tbody > tr > .selected:hover, table.dataTable.order-column.hover tbody > tr:hover > .selected,\ntable.dataTable.order-column.hover tbody > tr > .selected:hover {\n  background-color: #a2aec7;\n}\ntable.dataTable tbody td.select-checkbox,\ntable.dataTable tbody th.select-checkbox {\n  position: relative;\n}\ntable.dataTable tbody td.select-checkbox:before, table.dataTable tbody td.select-checkbox:after,\ntable.dataTable tbody th.select-checkbox:before,\ntable.dataTable tbody th.select-checkbox:after {\n  display: block;\n  position: absolute;\n  top: 1.2em;\n  left: 50%;\n  width: 12px;\n  height: 12px;\n  box-sizing: border-box;\n}\ntable.dataTable tbody td.select-checkbox:before,\ntable.dataTable tbody th.select-checkbox:before {\n  content: ' ';\n  margin-top: -6px;\n  margin-left: -6px;\n  border: 1px solid black;\n  border-radius: 3px;\n}\ntable.dataTable tr.selected td.select-checkbox:after,\ntable.dataTable tr.selected th.select-checkbox:after {\n  content: '\\2714';\n  margin-top: -11px;\n  margin-left: -4px;\n  text-align: center;\n  text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9;\n}\n\ndiv.dataTables_wrapper span.select-info,\ndiv.dataTables_wrapper span.select-item {\n  margin-left: 0.5em;\n}\n\n@media screen and (max-width: 640px) {\n  div.dataTables_wrapper span.select-info,\n  div.dataTables_wrapper span.select-item {\n    margin-left: 0;\n    display: block;\n  }\n}\n"
  },
  {
    "path": "static/js/DataTables/Select-1.3.0/css/select.foundation.css",
    "content": "table.dataTable tbody > tr.selected,\ntable.dataTable tbody > tr > .selected {\n  background-color: #008cba;\n}\ntable.dataTable.stripe tbody > tr.odd.selected,\ntable.dataTable.stripe tbody > tr.odd > .selected, table.dataTable.display tbody > tr.odd.selected,\ntable.dataTable.display tbody > tr.odd > .selected {\n  background-color: #0089b6;\n}\ntable.dataTable.hover tbody > tr.selected:hover,\ntable.dataTable.hover tbody > tr > .selected:hover, table.dataTable.display tbody > tr.selected:hover,\ntable.dataTable.display tbody > tr > .selected:hover {\n  background-color: #0087b3;\n}\ntable.dataTable.order-column tbody > tr.selected > .sorting_1,\ntable.dataTable.order-column tbody > tr.selected > .sorting_2,\ntable.dataTable.order-column tbody > tr.selected > .sorting_3,\ntable.dataTable.order-column tbody > tr > .selected, table.dataTable.display tbody > tr.selected > .sorting_1,\ntable.dataTable.display tbody > tr.selected > .sorting_2,\ntable.dataTable.display tbody > tr.selected > .sorting_3,\ntable.dataTable.display tbody > tr > .selected {\n  background-color: #0089b6;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_1 {\n  background-color: #0084b0;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_2 {\n  background-color: #0085b1;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_3 {\n  background-color: #0087b3;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_1 {\n  background-color: #0089b6;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_2 {\n  background-color: #008ab8;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_3 {\n  background-color: #008bb9;\n}\ntable.dataTable.display tbody > tr.odd > .selected, table.dataTable.order-column.stripe tbody > tr.odd > .selected {\n  background-color: #0084b0;\n}\ntable.dataTable.display tbody > tr.even > .selected, table.dataTable.order-column.stripe tbody > tr.even > .selected {\n  background-color: #0089b6;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_1, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_1 {\n  background-color: #0081ab;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_2, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_2 {\n  background-color: #0082ac;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_3, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_3 {\n  background-color: #0083ae;\n}\ntable.dataTable.display tbody > tr:hover > .selected,\ntable.dataTable.display tbody > tr > .selected:hover, table.dataTable.order-column.hover tbody > tr:hover > .selected,\ntable.dataTable.order-column.hover tbody > tr > .selected:hover {\n  background-color: #0081ab;\n}\ntable.dataTable tbody td.select-checkbox,\ntable.dataTable tbody th.select-checkbox {\n  position: relative;\n}\ntable.dataTable tbody td.select-checkbox:before, table.dataTable tbody td.select-checkbox:after,\ntable.dataTable tbody th.select-checkbox:before,\ntable.dataTable tbody th.select-checkbox:after {\n  display: block;\n  position: absolute;\n  top: 1.2em;\n  left: 50%;\n  width: 12px;\n  height: 12px;\n  box-sizing: border-box;\n}\ntable.dataTable tbody td.select-checkbox:before,\ntable.dataTable tbody th.select-checkbox:before {\n  content: ' ';\n  margin-top: -6px;\n  margin-left: -6px;\n  border: 1px solid black;\n  border-radius: 3px;\n}\ntable.dataTable tr.selected td.select-checkbox:after,\ntable.dataTable tr.selected th.select-checkbox:after {\n  content: '\\2714';\n  margin-top: -11px;\n  margin-left: -4px;\n  text-align: center;\n  text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9;\n}\n\ndiv.dataTables_wrapper span.select-info,\ndiv.dataTables_wrapper span.select-item {\n  margin-left: 0.5em;\n}\n\n@media screen and (max-width: 640px) {\n  div.dataTables_wrapper span.select-info,\n  div.dataTables_wrapper span.select-item {\n    margin-left: 0;\n    display: block;\n  }\n}\ntable.dataTable tbody tr.selected th,\ntable.dataTable tbody tr.selected td,\ntable.dataTable tbody th.selected,\ntable.dataTable tbody td.selected {\n  color: white;\n}\ntable.dataTable tbody tr.selected th a,\ntable.dataTable tbody tr.selected td a,\ntable.dataTable tbody th.selected a,\ntable.dataTable tbody td.selected a {\n  color: #a2d4ed;\n}\n"
  },
  {
    "path": "static/js/DataTables/Select-1.3.0/css/select.jqueryui.css",
    "content": "table.dataTable tbody > tr.selected,\ntable.dataTable tbody > tr > .selected {\n  background-color: #B0BED9;\n}\ntable.dataTable.stripe tbody > tr.odd.selected,\ntable.dataTable.stripe tbody > tr.odd > .selected, table.dataTable.display tbody > tr.odd.selected,\ntable.dataTable.display tbody > tr.odd > .selected {\n  background-color: #acbad4;\n}\ntable.dataTable.hover tbody > tr.selected:hover,\ntable.dataTable.hover tbody > tr > .selected:hover, table.dataTable.display tbody > tr.selected:hover,\ntable.dataTable.display tbody > tr > .selected:hover {\n  background-color: #aab7d1;\n}\ntable.dataTable.order-column tbody > tr.selected > .sorting_1,\ntable.dataTable.order-column tbody > tr.selected > .sorting_2,\ntable.dataTable.order-column tbody > tr.selected > .sorting_3,\ntable.dataTable.order-column tbody > tr > .selected, table.dataTable.display tbody > tr.selected > .sorting_1,\ntable.dataTable.display tbody > tr.selected > .sorting_2,\ntable.dataTable.display tbody > tr.selected > .sorting_3,\ntable.dataTable.display tbody > tr > .selected {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_1 {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_2 {\n  background-color: #a8b5cf;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_3 {\n  background-color: #a9b7d1;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_1 {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_2 {\n  background-color: #aebcd6;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_3 {\n  background-color: #afbdd8;\n}\ntable.dataTable.display tbody > tr.odd > .selected, table.dataTable.order-column.stripe tbody > tr.odd > .selected {\n  background-color: #a6b4cd;\n}\ntable.dataTable.display tbody > tr.even > .selected, table.dataTable.order-column.stripe tbody > tr.even > .selected {\n  background-color: #acbad5;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_1, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_1 {\n  background-color: #a2aec7;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_2, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_2 {\n  background-color: #a3b0c9;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_3, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_3 {\n  background-color: #a5b2cb;\n}\ntable.dataTable.display tbody > tr:hover > .selected,\ntable.dataTable.display tbody > tr > .selected:hover, table.dataTable.order-column.hover tbody > tr:hover > .selected,\ntable.dataTable.order-column.hover tbody > tr > .selected:hover {\n  background-color: #a2aec7;\n}\ntable.dataTable tbody td.select-checkbox,\ntable.dataTable tbody th.select-checkbox {\n  position: relative;\n}\ntable.dataTable tbody td.select-checkbox:before, table.dataTable tbody td.select-checkbox:after,\ntable.dataTable tbody th.select-checkbox:before,\ntable.dataTable tbody th.select-checkbox:after {\n  display: block;\n  position: absolute;\n  top: 1.2em;\n  left: 50%;\n  width: 12px;\n  height: 12px;\n  box-sizing: border-box;\n}\ntable.dataTable tbody td.select-checkbox:before,\ntable.dataTable tbody th.select-checkbox:before {\n  content: ' ';\n  margin-top: -6px;\n  margin-left: -6px;\n  border: 1px solid black;\n  border-radius: 3px;\n}\ntable.dataTable tr.selected td.select-checkbox:after,\ntable.dataTable tr.selected th.select-checkbox:after {\n  content: '\\2714';\n  margin-top: -11px;\n  margin-left: -4px;\n  text-align: center;\n  text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9;\n}\n\ndiv.dataTables_wrapper span.select-info,\ndiv.dataTables_wrapper span.select-item {\n  margin-left: 0.5em;\n}\n\n@media screen and (max-width: 640px) {\n  div.dataTables_wrapper span.select-info,\n  div.dataTables_wrapper span.select-item {\n    margin-left: 0;\n    display: block;\n  }\n}\n"
  },
  {
    "path": "static/js/DataTables/Select-1.3.0/css/select.semanticui.css",
    "content": "table.dataTable tbody > tr.selected,\ntable.dataTable tbody > tr > .selected {\n  background-color: rgba(0, 0, 0, 0.05);\n}\ntable.dataTable.stripe tbody > tr.odd.selected,\ntable.dataTable.stripe tbody > tr.odd > .selected, table.dataTable.display tbody > tr.odd.selected,\ntable.dataTable.display tbody > tr.odd > .selected {\n  background-color: rgba(0, 0, 0, 0.072325);\n}\ntable.dataTable.hover tbody > tr.selected:hover,\ntable.dataTable.hover tbody > tr > .selected:hover, table.dataTable.display tbody > tr.selected:hover,\ntable.dataTable.display tbody > tr > .selected:hover {\n  background-color: rgba(0, 0, 0, 0.0842);\n}\ntable.dataTable.order-column tbody > tr.selected > .sorting_1,\ntable.dataTable.order-column tbody > tr.selected > .sorting_2,\ntable.dataTable.order-column tbody > tr.selected > .sorting_3,\ntable.dataTable.order-column tbody > tr > .selected, table.dataTable.display tbody > tr.selected > .sorting_1,\ntable.dataTable.display tbody > tr.selected > .sorting_2,\ntable.dataTable.display tbody > tr.selected > .sorting_3,\ntable.dataTable.display tbody > tr > .selected {\n  background-color: rgba(0, 0, 0, 0.069);\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_1 {\n  background-color: rgba(0, 0, 0, 0.1013);\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_2 {\n  background-color: rgba(0, 0, 0, 0.09465);\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_3 {\n  background-color: rgba(0, 0, 0, 0.08705);\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_1 {\n  background-color: rgba(0, 0, 0, 0.069);\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_2 {\n  background-color: rgba(0, 0, 0, 0.0614);\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_3 {\n  background-color: rgba(0, 0, 0, 0.0538);\n}\ntable.dataTable.display tbody > tr.odd > .selected, table.dataTable.order-column.stripe tbody > tr.odd > .selected {\n  background-color: rgba(0, 0, 0, 0.1013);\n}\ntable.dataTable.display tbody > tr.even > .selected, table.dataTable.order-column.stripe tbody > tr.even > .selected {\n  background-color: rgba(0, 0, 0, 0.069);\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_1, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_1 {\n  background-color: rgba(0, 0, 0, 0.1279);\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_2, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_2 {\n  background-color: rgba(0, 0, 0, 0.12125);\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_3, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_3 {\n  background-color: rgba(0, 0, 0, 0.10985);\n}\ntable.dataTable.display tbody > tr:hover > .selected,\ntable.dataTable.display tbody > tr > .selected:hover, table.dataTable.order-column.hover tbody > tr:hover > .selected,\ntable.dataTable.order-column.hover tbody > tr > .selected:hover {\n  background-color: rgba(0, 0, 0, 0.1279);\n}\ntable.dataTable tbody td.select-checkbox,\ntable.dataTable tbody th.select-checkbox {\n  position: relative;\n}\ntable.dataTable tbody td.select-checkbox:before, table.dataTable tbody td.select-checkbox:after,\ntable.dataTable tbody th.select-checkbox:before,\ntable.dataTable tbody th.select-checkbox:after {\n  display: block;\n  position: absolute;\n  top: 1.2em;\n  left: 50%;\n  width: 12px;\n  height: 12px;\n  box-sizing: border-box;\n}\ntable.dataTable tbody td.select-checkbox:before,\ntable.dataTable tbody th.select-checkbox:before {\n  content: ' ';\n  margin-top: -6px;\n  margin-left: -6px;\n  border: 1px solid black;\n  border-radius: 3px;\n}\ntable.dataTable tr.selected td.select-checkbox:after,\ntable.dataTable tr.selected th.select-checkbox:after {\n  content: '\\2714';\n  margin-top: -11px;\n  margin-left: -4px;\n  text-align: center;\n  text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9;\n}\n\ndiv.dataTables_wrapper span.select-info,\ndiv.dataTables_wrapper span.select-item {\n  margin-left: 0.5em;\n}\n\n@media screen and (max-width: 640px) {\n  div.dataTables_wrapper span.select-info,\n  div.dataTables_wrapper span.select-item {\n    margin-left: 0;\n    display: block;\n  }\n}\ntable.dataTable tbody tr.selected,\ntable.dataTable tbody th.selected,\ntable.dataTable tbody td.selected {\n  color: rgba(0, 0, 0, 0.95);\n}\n"
  },
  {
    "path": "static/js/DataTables/Select-1.3.0/js/dataTables.select.js",
    "content": "/*! Select for DataTables 1.3.0\n * 2015-2018 SpryMedia Ltd - datatables.net/license/mit\n */\n\n/**\n * @summary     Select for DataTables\n * @description A collection of API methods, events and buttons for DataTables\n *   that provides selection options of the items in a DataTable\n * @version     1.3.0\n * @file        dataTables.select.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     datatables.net/forums\n * @copyright   Copyright 2015-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net/extensions/select\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n// Version information for debugger\nDataTable.select = {};\n\nDataTable.select.version = '1.3.0';\n\nDataTable.select.init = function ( dt ) {\n\tvar ctx = dt.settings()[0];\n\tvar init = ctx.oInit.select;\n\tvar defaults = DataTable.defaults.select;\n\tvar opts = init === undefined ?\n\t\tdefaults :\n\t\tinit;\n\n\t// Set defaults\n\tvar items = 'row';\n\tvar style = 'api';\n\tvar blurable = false;\n\tvar info = true;\n\tvar selector = 'td, th';\n\tvar className = 'selected';\n\tvar setStyle = false;\n\n\tctx._select = {};\n\n\t// Initialisation customisations\n\tif ( opts === true ) {\n\t\tstyle = 'os';\n\t\tsetStyle = true;\n\t}\n\telse if ( typeof opts === 'string' ) {\n\t\tstyle = opts;\n\t\tsetStyle = true;\n\t}\n\telse if ( $.isPlainObject( opts ) ) {\n\t\tif ( opts.blurable !== undefined ) {\n\t\t\tblurable = opts.blurable;\n\t\t}\n\n\t\tif ( opts.info !== undefined ) {\n\t\t\tinfo = opts.info;\n\t\t}\n\n\t\tif ( opts.items !== undefined ) {\n\t\t\titems = opts.items;\n\t\t}\n\n\t\tif ( opts.style !== undefined ) {\n\t\t\tstyle = opts.style;\n\t\t\tsetStyle = true;\n\t\t}\n\t\telse {\n\t\t\tstyle = 'os';\n\t\t\tsetStyle = true;\n\t\t}\n\n\t\tif ( opts.selector !== undefined ) {\n\t\t\tselector = opts.selector;\n\t\t}\n\n\t\tif ( opts.className !== undefined ) {\n\t\t\tclassName = opts.className;\n\t\t}\n\t}\n\n\tdt.select.selector( selector );\n\tdt.select.items( items );\n\tdt.select.style( style );\n\tdt.select.blurable( blurable );\n\tdt.select.info( info );\n\tctx._select.className = className;\n\n\n\t// Sort table based on selected rows. Requires Select Datatables extension\n\t$.fn.dataTable.ext.order['select-checkbox'] = function ( settings, col ) {\n\t\treturn this.api().column( col, {order: 'index'} ).nodes().map( function ( td ) {\n\t\t\tif ( settings._select.items === 'row' ) {\n\t\t\t\treturn $( td ).parent().hasClass( settings._select.className );\n\t\t\t} else if ( settings._select.items === 'cell' ) {\n\t\t\t\treturn $( td ).hasClass( settings._select.className );\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\t};\n\n\t// If the init options haven't enabled select, but there is a selectable\n\t// class name, then enable\n\tif ( ! setStyle && $( dt.table().node() ).hasClass( 'selectable' ) ) {\n\t\tdt.select.style( 'os' );\n\t}\n};\n\n/*\n\nSelect is a collection of API methods, event handlers, event emitters and\nbuttons (for the `Buttons` extension) for DataTables. It provides the following\nfeatures, with an overview of how they are implemented:\n\n## Selection of rows, columns and cells. Whether an item is selected or not is\n   stored in:\n\n* rows: a `_select_selected` property which contains a boolean value of the\n  DataTables' `aoData` object for each row\n* columns: a `_select_selected` property which contains a boolean value of the\n  DataTables' `aoColumns` object for each column\n* cells: a `_selected_cells` property which contains an array of boolean values\n  of the `aoData` object for each row. The array is the same length as the\n  columns array, with each element of it representing a cell.\n\nThis method of using boolean flags allows Select to operate when nodes have not\nbeen created for rows / cells (DataTables' defer rendering feature).\n\n## API methods\n\nA range of API methods are available for triggering selection and de-selection\nof rows. Methods are also available to configure the selection events that can\nbe triggered by an end user (such as which items are to be selected). To a large\nextent, these of API methods *is* Select. It is basically a collection of helper\nfunctions that can be used to select items in a DataTable.\n\nConfiguration of select is held in the object `_select` which is attached to the\nDataTables settings object on initialisation. Select being available on a table\nis not optional when Select is loaded, but its default is for selection only to\nbe available via the API - so the end user wouldn't be able to select rows\nwithout additional configuration.\n\nThe `_select` object contains the following properties:\n\n```\n{\n\titems:string     - Can be `rows`, `columns` or `cells`. Defines what item \n\t                   will be selected if the user is allowed to activate row\n\t                   selection using the mouse.\n\tstyle:string     - Can be `none`, `single`, `multi` or `os`. Defines the\n\t                   interaction style when selecting items\n\tblurable:boolean - If row selection can be cleared by clicking outside of\n\t                   the table\n\tinfo:boolean     - If the selection summary should be shown in the table\n\t                   information elements\n}\n```\n\nIn addition to the API methods, Select also extends the DataTables selector\noptions for rows, columns and cells adding a `selected` option to the selector\noptions object, allowing the developer to select only selected items or\nunselected items.\n\n## Mouse selection of items\n\nClicking on items can be used to select items. This is done by a simple event\nhandler that will select the items using the API methods.\n\n */\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Local functions\n */\n\n/**\n * Add one or more cells to the selection when shift clicking in OS selection\n * style cell selection.\n *\n * Cell range is more complicated than row and column as we want to select\n * in the visible grid rather than by index in sequence. For example, if you\n * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1\n * should also be selected (and not 1-3, 1-4. etc)\n * \n * @param  {DataTable.Api} dt   DataTable\n * @param  {object}        idx  Cell index to select to\n * @param  {object}        last Cell index to select from\n * @private\n */\nfunction cellRange( dt, idx, last )\n{\n\tvar indexes;\n\tvar columnIndexes;\n\tvar rowIndexes;\n\tvar selectColumns = function ( start, end ) {\n\t\tif ( start > end ) {\n\t\t\tvar tmp = end;\n\t\t\tend = start;\n\t\t\tstart = tmp;\n\t\t}\n\t\t\n\t\tvar record = false;\n\t\treturn dt.columns( ':visible' ).indexes().filter( function (i) {\n\t\t\tif ( i === start ) {\n\t\t\t\trecord = true;\n\t\t\t}\n\t\t\t\n\t\t\tif ( i === end ) { // not else if, as start might === end\n\t\t\t\trecord = false;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn record;\n\t\t} );\n\t};\n\n\tvar selectRows = function ( start, end ) {\n\t\tvar indexes = dt.rows( { search: 'applied' } ).indexes();\n\n\t\t// Which comes first - might need to swap\n\t\tif ( indexes.indexOf( start ) > indexes.indexOf( end ) ) {\n\t\t\tvar tmp = end;\n\t\t\tend = start;\n\t\t\tstart = tmp;\n\t\t}\n\n\t\tvar record = false;\n\t\treturn indexes.filter( function (i) {\n\t\t\tif ( i === start ) {\n\t\t\t\trecord = true;\n\t\t\t}\n\t\t\t\n\t\t\tif ( i === end ) {\n\t\t\t\trecord = false;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn record;\n\t\t} );\n\t};\n\n\tif ( ! dt.cells( { selected: true } ).any() && ! last ) {\n\t\t// select from the top left cell to this one\n\t\tcolumnIndexes = selectColumns( 0, idx.column );\n\t\trowIndexes = selectRows( 0 , idx.row );\n\t}\n\telse {\n\t\t// Get column indexes between old and new\n\t\tcolumnIndexes = selectColumns( last.column, idx.column );\n\t\trowIndexes = selectRows( last.row , idx.row );\n\t}\n\n\tindexes = dt.cells( rowIndexes, columnIndexes ).flatten();\n\n\tif ( ! dt.cells( idx, { selected: true } ).any() ) {\n\t\t// Select range\n\t\tdt.cells( indexes ).select();\n\t}\n\telse {\n\t\t// Deselect range\n\t\tdt.cells( indexes ).deselect();\n\t}\n}\n\n/**\n * Disable mouse selection by removing the selectors\n *\n * @param {DataTable.Api} dt DataTable to remove events from\n * @private\n */\nfunction disableMouseSelection( dt )\n{\n\tvar ctx = dt.settings()[0];\n\tvar selector = ctx._select.selector;\n\n\t$( dt.table().container() )\n\t\t.off( 'mousedown.dtSelect', selector )\n\t\t.off( 'mouseup.dtSelect', selector )\n\t\t.off( 'click.dtSelect', selector );\n\n\t$('body').off( 'click.dtSelect' + dt.table().node().id );\n}\n\n/**\n * Attach mouse listeners to the table to allow mouse selection of items\n *\n * @param {DataTable.Api} dt DataTable to remove events from\n * @private\n */\nfunction enableMouseSelection ( dt )\n{\n\tvar container = $( dt.table().container() );\n\tvar ctx = dt.settings()[0];\n\tvar selector = ctx._select.selector;\n\tvar matchSelection;\n\n\tcontainer\n\t\t.on( 'mousedown.dtSelect', selector, function(e) {\n\t\t\t// Disallow text selection for shift clicking on the table so multi\n\t\t\t// element selection doesn't look terrible!\n\t\t\tif ( e.shiftKey || e.metaKey || e.ctrlKey ) {\n\t\t\t\tcontainer\n\t\t\t\t\t.css( '-moz-user-select', 'none' )\n\t\t\t\t\t.one('selectstart.dtSelect', selector, function () {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t} );\n\t\t\t}\n\n\t\t\tif ( window.getSelection ) {\n\t\t\t\tmatchSelection = window.getSelection();\n\t\t\t}\n\t\t} )\n\t\t.on( 'mouseup.dtSelect', selector, function() {\n\t\t\t// Allow text selection to occur again, Mozilla style (tested in FF\n\t\t\t// 35.0.1 - still required)\n\t\t\tcontainer.css( '-moz-user-select', '' );\n\t\t} )\n\t\t.on( 'click.dtSelect', selector, function ( e ) {\n\t\t\tvar items = dt.select.items();\n\t\t\tvar idx;\n\n\t\t\t// If text was selected (click and drag), then we shouldn't change\n\t\t\t// the row's selected state\n\t\t\tif ( matchSelection ) {\n\t\t\t\tvar selection = window.getSelection();\n\n\t\t\t\t// If the element that contains the selection is not in the table, we can ignore it\n\t\t\t\t// This can happen if the developer selects text from the click event\n\t\t\t\tif ( ! selection.anchorNode || $(selection.anchorNode).closest('table')[0] === dt.table().node() ) {\n\t\t\t\t\tif ( selection !== matchSelection ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar ctx = dt.settings()[0];\n\t\t\tvar wrapperClass = $.trim(dt.settings()[0].oClasses.sWrapper).replace(/ +/g, '.');\n\n\t\t\t// Ignore clicks inside a sub-table\n\t\t\tif ( $(e.target).closest('div.'+wrapperClass)[0] != dt.table().container() ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar cell = dt.cell( $(e.target).closest('td, th') );\n\n\t\t\t// Check the cell actually belongs to the host DataTable (so child\n\t\t\t// rows, etc, are ignored)\n\t\t\tif ( ! cell.any() ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar event = $.Event('user-select.dt');\n\t\t\teventTrigger( dt, event, [ items, cell, e ] );\n\n\t\t\tif ( event.isDefaultPrevented() ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar cellIndex = cell.index();\n\t\t\tif ( items === 'row' ) {\n\t\t\t\tidx = cellIndex.row;\n\t\t\t\ttypeSelect( e, dt, ctx, 'row', idx );\n\t\t\t}\n\t\t\telse if ( items === 'column' ) {\n\t\t\t\tidx = cell.index().column;\n\t\t\t\ttypeSelect( e, dt, ctx, 'column', idx );\n\t\t\t}\n\t\t\telse if ( items === 'cell' ) {\n\t\t\t\tidx = cell.index();\n\t\t\t\ttypeSelect( e, dt, ctx, 'cell', idx );\n\t\t\t}\n\n\t\t\tctx._select_lastCell = cellIndex;\n\t\t} );\n\n\t// Blurable\n\t$('body').on( 'click.dtSelect' + dt.table().node().id, function ( e ) {\n\t\tif ( ctx._select.blurable ) {\n\t\t\t// If the click was inside the DataTables container, don't blur\n\t\t\tif ( $(e.target).parents().filter( dt.table().container() ).length ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Ignore elements which have been removed from the DOM (i.e. paging\n\t\t\t// buttons)\n\t\t\tif ( $(e.target).parents('html').length === 0 ) {\n\t\t\t \treturn;\n\t\t\t}\n\n\t\t\t// Don't blur in Editor form\n\t\t\tif ( $(e.target).parents('div.DTE').length ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tclear( ctx, true );\n\t\t}\n\t} );\n}\n\n/**\n * Trigger an event on a DataTable\n *\n * @param {DataTable.Api} api      DataTable to trigger events on\n * @param  {boolean}      selected true if selected, false if deselected\n * @param  {string}       type     Item type acting on\n * @param  {boolean}      any      Require that there are values before\n *     triggering\n * @private\n */\nfunction eventTrigger ( api, type, args, any )\n{\n\tif ( any && ! api.flatten().length ) {\n\t\treturn;\n\t}\n\n\tif ( typeof type === 'string' ) {\n\t\ttype = type +'.dt';\n\t}\n\n\targs.unshift( api );\n\n\t$(api.table().node()).trigger( type, args );\n}\n\n/**\n * Update the information element of the DataTable showing information about the\n * items selected. This is done by adding tags to the existing text\n * \n * @param {DataTable.Api} api DataTable to update\n * @private\n */\nfunction info ( api )\n{\n\tvar ctx = api.settings()[0];\n\n\tif ( ! ctx._select.info || ! ctx.aanFeatures.i ) {\n\t\treturn;\n\t}\n\n\tif ( api.select.style() === 'api' ) {\n\t\treturn;\n\t}\n\n\tvar rows    = api.rows( { selected: true } ).flatten().length;\n\tvar columns = api.columns( { selected: true } ).flatten().length;\n\tvar cells   = api.cells( { selected: true } ).flatten().length;\n\n\tvar add = function ( el, name, num ) {\n\t\tel.append( $('<span class=\"select-item\"/>').append( api.i18n(\n\t\t\t'select.'+name+'s',\n\t\t\t{ _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' },\n\t\t\tnum\n\t\t) ) );\n\t};\n\n\t// Internal knowledge of DataTables to loop over all information elements\n\t$.each( ctx.aanFeatures.i, function ( i, el ) {\n\t\tel = $(el);\n\n\t\tvar output  = $('<span class=\"select-info\"/>');\n\t\tadd( output, 'row', rows );\n\t\tadd( output, 'column', columns );\n\t\tadd( output, 'cell', cells  );\n\n\t\tvar exisiting = el.children('span.select-info');\n\t\tif ( exisiting.length ) {\n\t\t\texisiting.remove();\n\t\t}\n\n\t\tif ( output.text() !== '' ) {\n\t\t\tel.append( output );\n\t\t}\n\t} );\n}\n\n/**\n * Initialisation of a new table. Attach event handlers and callbacks to allow\n * Select to operate correctly.\n *\n * This will occur _after_ the initial DataTables initialisation, although\n * before Ajax data is rendered, if there is ajax data\n *\n * @param  {DataTable.settings} ctx Settings object to operate on\n * @private\n */\nfunction init ( ctx ) {\n\tvar api = new DataTable.Api( ctx );\n\n\t// Row callback so that classes can be added to rows and cells if the item\n\t// was selected before the element was created. This will happen with the\n\t// `deferRender` option enabled.\n\t// \n\t// This method of attaching to `aoRowCreatedCallback` is a hack until\n\t// DataTables has proper events for row manipulation If you are reviewing\n\t// this code to create your own plug-ins, please do not do this!\n\tctx.aoRowCreatedCallback.push( {\n\t\tfn: function ( row, data, index ) {\n\t\t\tvar i, ien;\n\t\t\tvar d = ctx.aoData[ index ];\n\n\t\t\t// Row\n\t\t\tif ( d._select_selected ) {\n\t\t\t\t$( row ).addClass( ctx._select.className );\n\t\t\t}\n\n\t\t\t// Cells and columns - if separated out, we would need to do two\n\t\t\t// loops, so it makes sense to combine them into a single one\n\t\t\tfor ( i=0, ien=ctx.aoColumns.length ; i<ien ; i++ ) {\n\t\t\t\tif ( ctx.aoColumns[i]._select_selected || (d._selected_cells && d._selected_cells[i]) ) {\n\t\t\t\t\t$(d.anCells[i]).addClass( ctx._select.className );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tsName: 'select-deferRender'\n\t} );\n\n\t// On Ajax reload we want to reselect all rows which are currently selected,\n\t// if there is an rowId (i.e. a unique value to identify each row with)\n\tapi.on( 'preXhr.dt.dtSelect', function () {\n\t\t// note that column selection doesn't need to be cached and then\n\t\t// reselected, as they are already selected\n\t\tvar rows = api.rows( { selected: true } ).ids( true ).filter( function ( d ) {\n\t\t\treturn d !== undefined;\n\t\t} );\n\n\t\tvar cells = api.cells( { selected: true } ).eq(0).map( function ( cellIdx ) {\n\t\t\tvar id = api.row( cellIdx.row ).id( true );\n\t\t\treturn id ?\n\t\t\t\t{ row: id, column: cellIdx.column } :\n\t\t\t\tundefined;\n\t\t} ).filter( function ( d ) {\n\t\t\treturn d !== undefined;\n\t\t} );\n\n\t\t// On the next draw, reselect the currently selected items\n\t\tapi.one( 'draw.dt.dtSelect', function () {\n\t\t\tapi.rows( rows ).select();\n\n\t\t\t// `cells` is not a cell index selector, so it needs a loop\n\t\t\tif ( cells.any() ) {\n\t\t\t\tcells.each( function ( id ) {\n\t\t\t\t\tapi.cells( id.row, id.column ).select();\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t} );\n\n\t// Update the table information element with selected item summary\n\tapi.on( 'draw.dtSelect.dt select.dtSelect.dt deselect.dtSelect.dt info.dt', function () {\n\t\tinfo( api );\n\t} );\n\n\t// Clean up and release\n\tapi.on( 'destroy.dtSelect', function () {\n\t\tdisableMouseSelection( api );\n\t\tapi.off( '.dtSelect' );\n\t} );\n}\n\n/**\n * Add one or more items (rows or columns) to the selection when shift clicking\n * in OS selection style\n *\n * @param  {DataTable.Api} dt   DataTable\n * @param  {string}        type Row or column range selector\n * @param  {object}        idx  Item index to select to\n * @param  {object}        last Item index to select from\n * @private\n */\nfunction rowColumnRange( dt, type, idx, last )\n{\n\t// Add a range of rows from the last selected row to this one\n\tvar indexes = dt[type+'s']( { search: 'applied' } ).indexes();\n\tvar idx1 = $.inArray( last, indexes );\n\tvar idx2 = $.inArray( idx, indexes );\n\n\tif ( ! dt[type+'s']( { selected: true } ).any() && idx1 === -1 ) {\n\t\t// select from top to here - slightly odd, but both Windows and Mac OS\n\t\t// do this\n\t\tindexes.splice( $.inArray( idx, indexes )+1, indexes.length );\n\t}\n\telse {\n\t\t// reverse so we can shift click 'up' as well as down\n\t\tif ( idx1 > idx2 ) {\n\t\t\tvar tmp = idx2;\n\t\t\tidx2 = idx1;\n\t\t\tidx1 = tmp;\n\t\t}\n\n\t\tindexes.splice( idx2+1, indexes.length );\n\t\tindexes.splice( 0, idx1 );\n\t}\n\n\tif ( ! dt[type]( idx, { selected: true } ).any() ) {\n\t\t// Select range\n\t\tdt[type+'s']( indexes ).select();\n\t}\n\telse {\n\t\t// Deselect range - need to keep the clicked on row selected\n\t\tindexes.splice( $.inArray( idx, indexes ), 1 );\n\t\tdt[type+'s']( indexes ).deselect();\n\t}\n}\n\n/**\n * Clear all selected items\n *\n * @param  {DataTable.settings} ctx Settings object of the host DataTable\n * @param  {boolean} [force=false] Force the de-selection to happen, regardless\n *     of selection style\n * @private\n */\nfunction clear( ctx, force )\n{\n\tif ( force || ctx._select.style === 'single' ) {\n\t\tvar api = new DataTable.Api( ctx );\n\t\t\n\t\tapi.rows( { selected: true } ).deselect();\n\t\tapi.columns( { selected: true } ).deselect();\n\t\tapi.cells( { selected: true } ).deselect();\n\t}\n}\n\n/**\n * Select items based on the current configuration for style and items.\n *\n * @param  {object}             e    Mouse event object\n * @param  {DataTables.Api}     dt   DataTable\n * @param  {DataTable.settings} ctx  Settings object of the host DataTable\n * @param  {string}             type Items to select\n * @param  {int|object}         idx  Index of the item to select\n * @private\n */\nfunction typeSelect ( e, dt, ctx, type, idx )\n{\n\tvar style = dt.select.style();\n\tvar isSelected = dt[type]( idx, { selected: true } ).any();\n\n\tif ( style === 'os' ) {\n\t\tif ( e.ctrlKey || e.metaKey ) {\n\t\t\t// Add or remove from the selection\n\t\t\tdt[type]( idx ).select( ! isSelected );\n\t\t}\n\t\telse if ( e.shiftKey ) {\n\t\t\tif ( type === 'cell' ) {\n\t\t\t\tcellRange( dt, idx, ctx._select_lastCell || null );\n\t\t\t}\n\t\t\telse {\n\t\t\t\trowColumnRange( dt, type, idx, ctx._select_lastCell ?\n\t\t\t\t\tctx._select_lastCell[type] :\n\t\t\t\t\tnull\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// No cmd or shift click - deselect if selected, or select\n\t\t\t// this row only\n\t\t\tvar selected = dt[type+'s']( { selected: true } );\n\n\t\t\tif ( isSelected && selected.flatten().length === 1 ) {\n\t\t\t\tdt[type]( idx ).deselect();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tselected.deselect();\n\t\t\t\tdt[type]( idx ).select();\n\t\t\t}\n\t\t}\n\t} else if ( style == 'multi+shift' ) {\n\t\tif ( e.shiftKey ) {\n\t\t\tif ( type === 'cell' ) {\n\t\t\t\tcellRange( dt, idx, ctx._select_lastCell || null );\n\t\t\t}\n\t\t\telse {\n\t\t\t\trowColumnRange( dt, type, idx, ctx._select_lastCell ?\n\t\t\t\t\tctx._select_lastCell[type] :\n\t\t\t\t\tnull\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tdt[ type ]( idx ).select( ! isSelected );\n\t\t}\n\t}\n\telse {\n\t\tdt[ type ]( idx ).select( ! isSelected );\n\t}\n}\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables selectors\n */\n\n// row and column are basically identical just assigned to different properties\n// and checking a different array, so we can dynamically create the functions to\n// reduce the code size\n$.each( [\n\t{ type: 'row', prop: 'aoData' },\n\t{ type: 'column', prop: 'aoColumns' }\n], function ( i, o ) {\n\tDataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) {\n\t\tvar selected = opts.selected;\n\t\tvar data;\n\t\tvar out = [];\n\n\t\tif ( selected !== true && selected !== false ) {\n\t\t\treturn indexes;\n\t\t}\n\n\t\tfor ( var i=0, ien=indexes.length ; i<ien ; i++ ) {\n\t\t\tdata = settings[ o.prop ][ indexes[i] ];\n\n\t\t\tif ( (selected === true && data._select_selected === true) ||\n\t\t\t     (selected === false && ! data._select_selected )\n\t\t\t) {\n\t\t\t\tout.push( indexes[i] );\n\t\t\t}\n\t\t}\n\n\t\treturn out;\n\t} );\n} );\n\nDataTable.ext.selector.cell.push( function ( settings, opts, cells ) {\n\tvar selected = opts.selected;\n\tvar rowData;\n\tvar out = [];\n\n\tif ( selected === undefined ) {\n\t\treturn cells;\n\t}\n\n\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\trowData = settings.aoData[ cells[i].row ];\n\n\t\tif ( (selected === true && rowData._selected_cells && rowData._selected_cells[ cells[i].column ] === true) ||\n\t\t     (selected === false && ( ! rowData._selected_cells || ! rowData._selected_cells[ cells[i].column ] ) )\n\t\t) {\n\t\t\tout.push( cells[i] );\n\t\t}\n\t}\n\n\treturn out;\n} );\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables API\n *\n * For complete documentation, please refer to the docs/api directory or the\n * DataTables site\n */\n\n// Local variables to improve compression\nvar apiRegister = DataTable.Api.register;\nvar apiRegisterPlural = DataTable.Api.registerPlural;\n\napiRegister( 'select()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tDataTable.select.init( new DataTable.Api( ctx ) );\n\t} );\n} );\n\napiRegister( 'select.blurable()', function ( flag ) {\n\tif ( flag === undefined ) {\n\t\treturn this.context[0]._select.blurable;\n\t}\n\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tctx._select.blurable = flag;\n\t} );\n} );\n\napiRegister( 'select.info()', function ( flag ) {\n\tif ( info === undefined ) {\n\t\treturn this.context[0]._select.info;\n\t}\n\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tctx._select.info = flag;\n\t} );\n} );\n\napiRegister( 'select.items()', function ( items ) {\n\tif ( items === undefined ) {\n\t\treturn this.context[0]._select.items;\n\t}\n\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tctx._select.items = items;\n\n\t\teventTrigger( new DataTable.Api( ctx ), 'selectItems', [ items ] );\n\t} );\n} );\n\n// Takes effect from the _next_ selection. None disables future selection, but\n// does not clear the current selection. Use the `deselect` methods for that\napiRegister( 'select.style()', function ( style ) {\n\tif ( style === undefined ) {\n\t\treturn this.context[0]._select.style;\n\t}\n\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tctx._select.style = style;\n\n\t\tif ( ! ctx._select_init ) {\n\t\t\tinit( ctx );\n\t\t}\n\n\t\t// Add / remove mouse event handlers. They aren't required when only\n\t\t// API selection is available\n\t\tvar dt = new DataTable.Api( ctx );\n\t\tdisableMouseSelection( dt );\n\t\t\n\t\tif ( style !== 'api' ) {\n\t\t\tenableMouseSelection( dt );\n\t\t}\n\n\t\teventTrigger( new DataTable.Api( ctx ), 'selectStyle', [ style ] );\n\t} );\n} );\n\napiRegister( 'select.selector()', function ( selector ) {\n\tif ( selector === undefined ) {\n\t\treturn this.context[0]._select.selector;\n\t}\n\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tdisableMouseSelection( new DataTable.Api( ctx ) );\n\n\t\tctx._select.selector = selector;\n\n\t\tif ( ctx._select.style !== 'api' ) {\n\t\t\tenableMouseSelection( new DataTable.Api( ctx ) );\n\t\t}\n\t} );\n} );\n\n\n\napiRegisterPlural( 'rows().select()', 'row().select()', function ( select ) {\n\tvar api = this;\n\n\tif ( select === false ) {\n\t\treturn this.deselect();\n\t}\n\n\tthis.iterator( 'row', function ( ctx, idx ) {\n\t\tclear( ctx );\n\n\t\tctx.aoData[ idx ]._select_selected = true;\n\t\t$( ctx.aoData[ idx ].nTr ).addClass( ctx._select.className );\n\t} );\n\n\tthis.iterator( 'table', function ( ctx, i ) {\n\t\teventTrigger( api, 'select', [ 'row', api[i] ], true );\n\t} );\n\n\treturn this;\n} );\n\napiRegisterPlural( 'columns().select()', 'column().select()', function ( select ) {\n\tvar api = this;\n\n\tif ( select === false ) {\n\t\treturn this.deselect();\n\t}\n\n\tthis.iterator( 'column', function ( ctx, idx ) {\n\t\tclear( ctx );\n\n\t\tctx.aoColumns[ idx ]._select_selected = true;\n\n\t\tvar column = new DataTable.Api( ctx ).column( idx );\n\n\t\t$( column.header() ).addClass( ctx._select.className );\n\t\t$( column.footer() ).addClass( ctx._select.className );\n\n\t\tcolumn.nodes().to$().addClass( ctx._select.className );\n\t} );\n\n\tthis.iterator( 'table', function ( ctx, i ) {\n\t\teventTrigger( api, 'select', [ 'column', api[i] ], true );\n\t} );\n\n\treturn this;\n} );\n\napiRegisterPlural( 'cells().select()', 'cell().select()', function ( select ) {\n\tvar api = this;\n\n\tif ( select === false ) {\n\t\treturn this.deselect();\n\t}\n\n\tthis.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {\n\t\tclear( ctx );\n\n\t\tvar data = ctx.aoData[ rowIdx ];\n\n\t\tif ( data._selected_cells === undefined ) {\n\t\t\tdata._selected_cells = [];\n\t\t}\n\n\t\tdata._selected_cells[ colIdx ] = true;\n\n\t\tif ( data.anCells ) {\n\t\t\t$( data.anCells[ colIdx ] ).addClass( ctx._select.className );\n\t\t}\n\t} );\n\n\tthis.iterator( 'table', function ( ctx, i ) {\n\t\teventTrigger( api, 'select', [ 'cell', api[i] ], true );\n\t} );\n\n\treturn this;\n} );\n\n\napiRegisterPlural( 'rows().deselect()', 'row().deselect()', function () {\n\tvar api = this;\n\n\tthis.iterator( 'row', function ( ctx, idx ) {\n\t\tctx.aoData[ idx ]._select_selected = false;\n\t\t$( ctx.aoData[ idx ].nTr ).removeClass( ctx._select.className );\n\t} );\n\n\tthis.iterator( 'table', function ( ctx, i ) {\n\t\teventTrigger( api, 'deselect', [ 'row', api[i] ], true );\n\t} );\n\n\treturn this;\n} );\n\napiRegisterPlural( 'columns().deselect()', 'column().deselect()', function () {\n\tvar api = this;\n\n\tthis.iterator( 'column', function ( ctx, idx ) {\n\t\tctx.aoColumns[ idx ]._select_selected = false;\n\n\t\tvar api = new DataTable.Api( ctx );\n\t\tvar column = api.column( idx );\n\n\t\t$( column.header() ).removeClass( ctx._select.className );\n\t\t$( column.footer() ).removeClass( ctx._select.className );\n\n\t\t// Need to loop over each cell, rather than just using\n\t\t// `column().nodes()` as cells which are individually selected should\n\t\t// not have the `selected` class removed from them\n\t\tapi.cells( null, idx ).indexes().each( function (cellIdx) {\n\t\t\tvar data = ctx.aoData[ cellIdx.row ];\n\t\t\tvar cellSelected = data._selected_cells;\n\n\t\t\tif ( data.anCells && (! cellSelected || ! cellSelected[ cellIdx.column ]) ) {\n\t\t\t\t$( data.anCells[ cellIdx.column  ] ).removeClass( ctx._select.className );\n\t\t\t}\n\t\t} );\n\t} );\n\n\tthis.iterator( 'table', function ( ctx, i ) {\n\t\teventTrigger( api, 'deselect', [ 'column', api[i] ], true );\n\t} );\n\n\treturn this;\n} );\n\napiRegisterPlural( 'cells().deselect()', 'cell().deselect()', function () {\n\tvar api = this;\n\n\tthis.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {\n\t\tvar data = ctx.aoData[ rowIdx ];\n\n\t\tdata._selected_cells[ colIdx ] = false;\n\n\t\t// Remove class only if the cells exist, and the cell is not column\n\t\t// selected, in which case the class should remain (since it is selected\n\t\t// in the column)\n\t\tif ( data.anCells && ! ctx.aoColumns[ colIdx ]._select_selected ) {\n\t\t\t$( data.anCells[ colIdx ] ).removeClass( ctx._select.className );\n\t\t}\n\t} );\n\n\tthis.iterator( 'table', function ( ctx, i ) {\n\t\teventTrigger( api, 'deselect', [ 'cell', api[i] ], true );\n\t} );\n\n\treturn this;\n} );\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Buttons\n */\nfunction i18n( label, def ) {\n\treturn function (dt) {\n\t\treturn dt.i18n( 'buttons.'+label, def );\n\t};\n}\n\n// Common events with suitable namespaces\nfunction namespacedEvents ( config ) {\n\tvar unique = config._eventNamespace;\n\n\treturn 'draw.dt.DT'+unique+' select.dt.DT'+unique+' deselect.dt.DT'+unique;\n}\n\nfunction enabled ( dt, config ) {\n\tif ( $.inArray( 'rows', config.limitTo ) !== -1 && dt.rows( { selected: true } ).any() ) {\n\t\treturn true;\n\t}\n\n\tif ( $.inArray( 'columns', config.limitTo ) !== -1 && dt.columns( { selected: true } ).any() ) {\n\t\treturn true;\n\t}\n\n\tif ( $.inArray( 'cells', config.limitTo ) !== -1 && dt.cells( { selected: true } ).any() ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nvar _buttonNamespace = 0;\n\n$.extend( DataTable.ext.buttons, {\n\tselected: {\n\t\ttext: i18n( 'selected', 'Selected' ),\n\t\tclassName: 'buttons-selected',\n\t\tlimitTo: [ 'rows', 'columns', 'cells' ],\n\t\tinit: function ( dt, node, config ) {\n\t\t\tvar that = this;\n\t\t\tconfig._eventNamespace = '.select'+(_buttonNamespace++);\n\n\t\t\t// .DT namespace listeners are removed by DataTables automatically\n\t\t\t// on table destroy\n\t\t\tdt.on( namespacedEvents(config), function () {\n\t\t\t\tthat.enable( enabled(dt, config) );\n\t\t\t} );\n\n\t\t\tthis.disable();\n\t\t},\n\t\tdestroy: function ( dt, node, config ) {\n\t\t\tdt.off( config._eventNamespace );\n\t\t}\n\t},\n\tselectedSingle: {\n\t\ttext: i18n( 'selectedSingle', 'Selected single' ),\n\t\tclassName: 'buttons-selected-single',\n\t\tinit: function ( dt, node, config ) {\n\t\t\tvar that = this;\n\t\t\tconfig._eventNamespace = '.select'+(_buttonNamespace++);\n\n\t\t\tdt.on( namespacedEvents(config), function () {\n\t\t\t\tvar count = dt.rows( { selected: true } ).flatten().length +\n\t\t\t\t            dt.columns( { selected: true } ).flatten().length +\n\t\t\t\t            dt.cells( { selected: true } ).flatten().length;\n\n\t\t\t\tthat.enable( count === 1 );\n\t\t\t} );\n\n\t\t\tthis.disable();\n\t\t},\n\t\tdestroy: function ( dt, node, config ) {\n\t\t\tdt.off( config._eventNamespace );\n\t\t}\n\t},\n\tselectAll: {\n\t\ttext: i18n( 'selectAll', 'Select all' ),\n\t\tclassName: 'buttons-select-all',\n\t\taction: function () {\n\t\t\tvar items = this.select.items();\n\t\t\tthis[ items+'s' ]().select();\n\t\t}\n\t},\n\tselectNone: {\n\t\ttext: i18n( 'selectNone', 'Deselect all' ),\n\t\tclassName: 'buttons-select-none',\n\t\taction: function () {\n\t\t\tclear( this.settings()[0], true );\n\t\t},\n\t\tinit: function ( dt, node, config ) {\n\t\t\tvar that = this;\n\t\t\tconfig._eventNamespace = '.select'+(_buttonNamespace++);\n\n\t\t\tdt.on( namespacedEvents(config), function () {\n\t\t\t\tvar count = dt.rows( { selected: true } ).flatten().length +\n\t\t\t\t            dt.columns( { selected: true } ).flatten().length +\n\t\t\t\t            dt.cells( { selected: true } ).flatten().length;\n\n\t\t\t\tthat.enable( count > 0 );\n\t\t\t} );\n\n\t\t\tthis.disable();\n\t\t},\n\t\tdestroy: function ( dt, node, config ) {\n\t\t\tdt.off( config._eventNamespace );\n\t\t}\n\t}\n} );\n\n$.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) {\n\tvar lc = item.toLowerCase();\n\n\tDataTable.ext.buttons[ 'select'+item+'s' ] = {\n\t\ttext: i18n( 'select'+item+'s', 'Select '+lc+'s' ),\n\t\tclassName: 'buttons-select-'+lc+'s',\n\t\taction: function () {\n\t\t\tthis.select.items( lc );\n\t\t},\n\t\tinit: function ( dt ) {\n\t\t\tvar that = this;\n\n\t\t\tdt.on( 'selectItems.dt.DT', function ( e, ctx, items ) {\n\t\t\t\tthat.active( items === lc );\n\t\t\t} );\n\t\t}\n\t};\n} );\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Initialisation\n */\n\n// DataTables creation - check if select has been defined in the options. Note\n// this required that the table be in the document! If it isn't then something\n// needs to trigger this method unfortunately. The next major release of\n// DataTables will rework the events and address this.\n$(document).on( 'preInit.dt.dtSelect', function (e, ctx) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tDataTable.select.init( new DataTable.Api( ctx ) );\n} );\n\n\nreturn DataTable.select;\n}));\n"
  },
  {
    "path": "static/js/DataTables/Select-1.3.0/js/select.bootstrap.js",
    "content": "/*! Bootstrap 3 styling wrapper for Select\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs', 'datatables.net-select'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.select ) {\n\t\t\t\trequire('datatables.net-select')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/Select-1.3.0/js/select.bootstrap4.js",
    "content": "/*! Bootstrap 4 styling wrapper for Select\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-bs4', 'datatables.net-select'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-bs4')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.select ) {\n\t\t\t\trequire('datatables.net-select')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/Select-1.3.0/js/select.dataTables.js",
    "content": "/*! DataTables styling wrapper for Select\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-dt', 'datatables.net-select'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-dt')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.select ) {\n\t\t\t\trequire('datatables.net-select')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/Select-1.3.0/js/select.foundation.js",
    "content": "/*! Bootstrap 4 styling wrapper for Select\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-zf', 'datatables.net-select'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-zf')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.select ) {\n\t\t\t\trequire('datatables.net-select')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/Select-1.3.0/js/select.jqueryui.js",
    "content": "/*! jQuery UI styling wrapper for Select\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-jqui', 'datatables.net-select'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-jqui')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.select ) {\n\t\t\t\trequire('datatables.net-select')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/Select-1.3.0/js/select.semanticui.js",
    "content": "/*! Semanic UI styling wrapper for Select\n * ©2018 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-se', 'datatables.net-select'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-se')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.select ) {\n\t\t\t\trequire('datatables.net-select')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n\nreturn $.fn.dataTable;\n\n}));"
  },
  {
    "path": "static/js/DataTables/datatables.css",
    "content": "/*\n * This combined file was created by the DataTables downloader builder:\n *   https://datatables.net/download\n *\n * To rebuild or modify this file with the latest versions of the included\n * software please visit:\n *   https://datatables.net/download/#zf/jq-3.3.1/jszip-2.5.0/pdfmake-0.1.36/dt-1.10.18/af-2.3.3/b-1.5.6/b-colvis-1.5.6/b-flash-1.5.6/b-html5-1.5.6/b-print-1.5.6/cr-1.5.0/fc-3.2.5/fh-3.1.4/kt-2.5.0/r-2.2.2/rg-1.1.0/rr-1.2.4/sc-2.0.0/sl-1.3.0\n *\n * Included libraries:\n *   jQuery 3 3.3.1, JSZip 2.5.0, pdfmake 0.1.36, DataTables 1.10.18, AutoFill 2.3.3, Buttons 1.5.6, Column visibility 1.5.6, Flash export 1.5.6, HTML5 export 1.5.6, Print view 1.5.6, ColReorder 1.5.0, FixedColumns 3.2.5, FixedHeader 3.1.4, KeyTable 2.5.0, Responsive 2.2.2, RowGroup 1.1.0, RowReorder 1.2.4, Scroller 2.0.0, Select 1.3.0\n */\n\ntable.dataTable {\n  clear: both;\n  margin: 0.5em 0 !important;\n  max-width: none !important;\n  width: 100%;\n}\ntable.dataTable td,\ntable.dataTable th {\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\ntable.dataTable td.dataTables_empty,\ntable.dataTable th.dataTables_empty {\n  text-align: center;\n}\ntable.dataTable.nowrap th, table.dataTable.nowrap td {\n  white-space: nowrap;\n}\n\ndiv.dataTables_wrapper {\n  position: relative;\n}\ndiv.dataTables_wrapper div.dataTables_length label {\n  float: left;\n  text-align: left;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_length select {\n  width: 75px;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_filter label {\n  float: right;\n  margin-bottom: 0;\n}\ndiv.dataTables_wrapper div.dataTables_filter input {\n  display: inline-block !important;\n  width: auto !important;\n  margin-bottom: 0;\n  margin-left: 0.5em;\n}\ndiv.dataTables_wrapper div.dataTables_info {\n  padding-top: 2px;\n}\ndiv.dataTables_wrapper div.dataTables_paginate {\n  float: right;\n  margin: 0;\n}\ndiv.dataTables_wrapper div.dataTables_processing {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 200px;\n  margin-left: -100px;\n  margin-top: -26px;\n  text-align: center;\n  padding: 1rem 0;\n}\n\ntable.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting,\ntable.dataTable thead > tr > td.sorting_asc,\ntable.dataTable thead > tr > td.sorting_desc,\ntable.dataTable thead > tr > td.sorting {\n  padding-right: 1.5rem;\n}\ntable.dataTable thead > tr > th:active,\ntable.dataTable thead > tr > td:active {\n  outline: none;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  cursor: pointer;\n}\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n  background-repeat: no-repeat;\n  background-position: center right;\n}\ntable.dataTable thead .sorting {\n  background-image: url(\"DataTables-1.10.18/images/sort_both.png\");\n}\ntable.dataTable thead .sorting_asc {\n  background-image: url(\"DataTables-1.10.18/images/sort_asc.png\");\n}\ntable.dataTable thead .sorting_desc {\n  background-image: url(\"DataTables-1.10.18/images/sort_desc.png\");\n}\ntable.dataTable thead .sorting_asc_disabled {\n  background-image: url(\"DataTables-1.10.18/images/sort_asc_disabled.png\");\n}\ntable.dataTable thead .sorting_desc_disabled {\n  background-image: url(\"DataTables-1.10.18/images/sort_desc_disabled.png\");\n}\n\ndiv.dataTables_scrollHead table {\n  margin-bottom: 0 !important;\n}\n\ndiv.dataTables_scrollBody table {\n  border-top: none;\n  margin-top: 0 !important;\n  margin-bottom: 0 !important;\n}\ndiv.dataTables_scrollBody table tbody tr:first-child th,\ndiv.dataTables_scrollBody table tbody tr:first-child td {\n  border-top: none;\n}\n\ndiv.dataTables_scrollFoot table {\n  margin-top: 0 !important;\n  border-top: none;\n}\n\n\ndiv.dt-autofill-handle{position:absolute;height:8px;width:8px;z-index:102;box-sizing:border-box;background:#008CBA;cursor:pointer}div.dtk-focus-alt div.dt-autofill-handle{background:#ff8b33}div.dt-autofill-select{position:absolute;z-index:1001;background-color:#008CBA;background-image:repeating-linear-gradient(45deg, transparent, transparent 5px, rgba(255,255,255,0.5) 5px, rgba(255,255,255,0.5) 10px)}div.dt-autofill-select.top,div.dt-autofill-select.bottom{height:3px;margin-top:-1px}div.dt-autofill-select.left,div.dt-autofill-select.right{width:3px;margin-left:-1px}div.dt-autofill-list{position:fixed;top:50%;left:50%;width:500px;margin-left:-250px;background-color:white;border-radius:6px;box-shadow:0 0 5px #555;border:2px solid #444;z-index:11;box-sizing:border-box;padding:1.5em 2em}div.dt-autofill-list ul{display:table;margin:0;padding:0;list-style:none;width:100%}div.dt-autofill-list ul li{display:table-row}div.dt-autofill-list ul li:last-child div.dt-autofill-question,div.dt-autofill-list ul li:last-child div.dt-autofill-button{border-bottom:none}div.dt-autofill-list ul li:hover{background-color:#f6f6f6}div.dt-autofill-list div.dt-autofill-question{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-list div.dt-autofill-question input[type=number]{padding:6px;width:30px;margin:-2px 0}div.dt-autofill-list div.dt-autofill-button{display:table-cell;padding:0.5em 0;border-bottom:1px solid #ccc}div.dt-autofill-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);background:radial-gradient(ellipse farthest-corner at center, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.7) 100%);z-index:10}div.dt-autofill-list button{margin:0}\n\n\n@keyframes dtb-spinner {\n  100% {\n    transform: rotate(360deg);\n  }\n}\n@-o-keyframes dtb-spinner {\n  100% {\n    -o-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-ms-keyframes dtb-spinner {\n  100% {\n    -ms-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-webkit-keyframes dtb-spinner {\n  100% {\n    -webkit-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\n@-moz-keyframes dtb-spinner {\n  100% {\n    -moz-transform: rotate(360deg);\n    transform: rotate(360deg);\n  }\n}\ndiv.dt-button-info {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  width: 400px;\n  margin-top: -100px;\n  margin-left: -200px;\n  background-color: white;\n  border: 2px solid #111;\n  box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.3);\n  border-radius: 3px;\n  text-align: center;\n  z-index: 21;\n}\ndiv.dt-button-info h2 {\n  padding: 0.5em;\n  margin: 0;\n  font-weight: normal;\n  border-bottom: 1px solid #ddd;\n  background-color: #f3f3f3;\n}\ndiv.dt-button-info > div {\n  padding: 1em;\n}\n\ndiv.dt-button-collection-title {\n  text-align: center;\n  padding: 0.3em 0 0.5em;\n  font-size: 0.9em;\n}\n\ndiv.dt-button-collection-title:empty {\n  display: none;\n}\n\nul.dt-buttons li {\n  margin: 0;\n}\nul.dt-buttons li.active a {\n  box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.6);\n}\n\nul.dt-buttons.button-group a {\n  margin-bottom: 0;\n}\n\nul.dt-button-collection.f-dropdown {\n  -webkit-column-gap: 8px;\n  -moz-column-gap: 8px;\n  -ms-column-gap: 8px;\n  -o-column-gap: 8px;\n  column-gap: 8px;\n}\nul.dt-button-collection.f-dropdown.fixed {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  margin-left: -75px;\n  border-radius: 0;\n}\nul.dt-button-collection.f-dropdown.fixed.two-column {\n  margin-left: -150px;\n}\nul.dt-button-collection.f-dropdown.fixed.three-column {\n  margin-left: -225px;\n}\nul.dt-button-collection.f-dropdown.fixed.four-column {\n  margin-left: -300px;\n}\nul.dt-button-collection.f-dropdown > * {\n  -webkit-column-break-inside: avoid;\n  break-inside: avoid;\n}\nul.dt-button-collection.f-dropdown.two-column {\n  width: 300px;\n  padding-bottom: 1px;\n  -webkit-column-count: 2;\n  -moz-column-count: 2;\n  -ms-column-count: 2;\n  -o-column-count: 2;\n  column-count: 2;\n}\nul.dt-button-collection.f-dropdown.three-column {\n  width: 450px;\n  padding-bottom: 1px;\n  -webkit-column-count: 3;\n  -moz-column-count: 3;\n  -ms-column-count: 3;\n  -o-column-count: 3;\n  column-count: 3;\n}\nul.dt-button-collection.f-dropdown.four-column {\n  width: 600px;\n  padding-bottom: 1px;\n  -webkit-column-count: 4;\n  -moz-column-count: 4;\n  -ms-column-count: 4;\n  -o-column-count: 4;\n  column-count: 4;\n}\nul.dt-button-collection.f-dropdown .dt-button {\n  border-radius: 0;\n}\nul.dt-button-collection.f-dropdown.fixed {\n  max-width: none;\n}\nul.dt-button-collection.f-dropdown.fixed:before, ul.dt-button-collection.f-dropdown.fixed:after {\n  display: none;\n}\n\ndiv.dt-button-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  z-index: 88;\n}\n\n@media screen and (max-width: 767px) {\n  ul.dt-buttons {\n    float: none;\n    width: 100%;\n    text-align: center;\n    margin-bottom: 0.5rem;\n  }\n  ul.dt-buttons li {\n    float: none;\n  }\n}\ndiv.button-group.stacked.dropdown-pane {\n  margin-top: 2px;\n  padding: 1px;\n  z-index: 89;\n}\ndiv.button-group.stacked.dropdown-pane a.button {\n  display: block;\n  margin-bottom: 1px;\n  border-right: none;\n}\ndiv.button-group.stacked.dropdown-pane a.button:last-child {\n  margin-bottom: 0;\n  margin-right: 1px;\n}\n\ndiv.dt-buttons button.button.processing,\ndiv.dt-buttons div.button.processing,\ndiv.dt-buttons a.button.processing {\n  color: rgba(0, 0, 0, 0.2);\n  color: rgba(255, 255, 255, 0.2);\n  border-top-color: white;\n  border-bottom-color: white;\n}\ndiv.dt-buttons button.button.processing:after,\ndiv.dt-buttons div.button.processing:after,\ndiv.dt-buttons a.button.processing:after {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 16px;\n  height: 16px;\n  margin: -8px 0 0 -8px;\n  box-sizing: border-box;\n  display: block;\n  content: ' ';\n  border: 2px solid #282828;\n  border-radius: 50%;\n  border-left-color: transparent;\n  border-right-color: transparent;\n  animation: dtb-spinner 1500ms infinite linear;\n  -o-animation: dtb-spinner 1500ms infinite linear;\n  -ms-animation: dtb-spinner 1500ms infinite linear;\n  -webkit-animation: dtb-spinner 1500ms infinite linear;\n  -moz-animation: dtb-spinner 1500ms infinite linear;\n}\n\n\ntable.DTCR_clonedTable.dataTable {\n  position: absolute !important;\n  background-color: rgba(255, 255, 255, 0.7);\n  z-index: 202;\n}\n\ndiv.DTCR_pointer {\n  width: 1px;\n  background-color: #008CBA;\n  z-index: 201;\n}\n\n\ndiv.DTFC_LeftHeadWrapper table,\ndiv.DTFC_LeftBodyWrapper table,\ndiv.DTFC_LeftFootWrapper table {\n  border-right-width: 0;\n}\n\ndiv.DTFC_RightHeadWrapper table,\ndiv.DTFC_RightBodyWrapper table,\ndiv.DTFC_RightFootWrapper table {\n  border-left-width: 0;\n}\n\ndiv.DTFC_LeftHeadWrapper table,\ndiv.DTFC_RightHeadWrapper table {\n  margin-bottom: 0 !important;\n}\n\ndiv.DTFC_LeftBodyWrapper table,\ndiv.DTFC_RightBodyWrapper table {\n  border-top: none;\n  margin: 0 !important;\n}\n\ndiv.DTFC_LeftFootWrapper table,\ndiv.DTFC_RightFootWrapper table {\n  margin-top: 0 !important;\n}\n\ndiv.DTFC_Blocker {\n  background-color: white;\n}\n\n\ntable.dataTable.fixedHeader-floating,\ntable.dataTable.fixedHeader-locked {\n  background-color: white;\n  margin-top: 0 !important;\n  margin-bottom: 0 !important;\n}\n\ntable.dataTable.fixedHeader-floating {\n  position: fixed !important;\n}\n\ntable.dataTable.fixedHeader-locked {\n  position: absolute !important;\n}\n\n@media print {\n  table.fixedHeader-floating {\n    display: none;\n  }\n}\n\n\ntable.dataTable tbody th.focus,\ntable.dataTable tbody td.focus {\n  box-shadow: inset 0 0 1px 2px #008CBA;\n}\n\ndiv.dtk-focus-alt table.dataTable tbody th.focus,\ndiv.dtk-focus-alt table.dataTable tbody td.focus {\n  box-shadow: inset 0 0 1px 2px #ff8b33;\n}\n\n\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > th.child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {\n  cursor: default !important;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {\n  display: none !important;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > td:first-child,\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > th:first-child {\n  position: relative;\n  padding-left: 30px;\n  cursor: pointer;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr[role=\"row\"] > th:first-child:before {\n  top: 9px;\n  left: 4px;\n  height: 14px;\n  width: 14px;\n  display: block;\n  position: absolute;\n  color: white;\n  border: 2px solid white;\n  border-radius: 14px;\n  box-shadow: 0 0 3px #444;\n  box-sizing: content-box;\n  text-align: center;\n  text-indent: 0 !important;\n  font-family: 'Courier New', Courier, monospace;\n  line-height: 14px;\n  content: '+';\n  background-color: #008CBA;\n}\ntable.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before {\n  content: '-';\n  background-color: #d33333;\n}\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child,\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child {\n  padding-left: 27px;\n}\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before,\ntable.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before {\n  top: 5px;\n  left: 4px;\n  height: 14px;\n  width: 14px;\n  border-radius: 14px;\n  line-height: 14px;\n  text-indent: 3px;\n}\ntable.dataTable.dtr-column > tbody > tr > td.control,\ntable.dataTable.dtr-column > tbody > tr > th.control {\n  position: relative;\n  cursor: pointer;\n}\ntable.dataTable.dtr-column > tbody > tr > td.control:before,\ntable.dataTable.dtr-column > tbody > tr > th.control:before {\n  top: 50%;\n  left: 50%;\n  height: 16px;\n  width: 16px;\n  margin-top: -10px;\n  margin-left: -10px;\n  display: block;\n  position: absolute;\n  color: white;\n  border: 2px solid white;\n  border-radius: 14px;\n  box-shadow: 0 0 3px #444;\n  box-sizing: content-box;\n  text-align: center;\n  text-indent: 0 !important;\n  font-family: 'Courier New', Courier, monospace;\n  line-height: 14px;\n  content: '+';\n  background-color: #008CBA;\n}\ntable.dataTable.dtr-column > tbody > tr.parent td.control:before,\ntable.dataTable.dtr-column > tbody > tr.parent th.control:before {\n  content: '-';\n  background-color: #d33333;\n}\ntable.dataTable > tbody > tr.child {\n  padding: 0.5em 1em;\n}\ntable.dataTable > tbody > tr.child:hover {\n  background: transparent !important;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details {\n  display: inline-block;\n  list-style-type: none;\n  margin: 0;\n  padding: 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li {\n  border-bottom: 1px solid #efefef;\n  padding: 0.5em 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li:first-child {\n  padding-top: 0;\n}\ntable.dataTable > tbody > tr.child ul.dtr-details > li:last-child {\n  border-bottom: none;\n}\ntable.dataTable > tbody > tr.child span.dtr-title {\n  display: inline-block;\n  min-width: 75px;\n  font-weight: bold;\n}\n\ndiv.dtr-modal {\n  position: fixed;\n  box-sizing: border-box;\n  top: 0;\n  left: 0;\n  height: 100%;\n  width: 100%;\n  z-index: 100;\n  padding: 10em 1em;\n}\ndiv.dtr-modal div.dtr-modal-display {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  width: 50%;\n  height: 50%;\n  overflow: auto;\n  margin: auto;\n  z-index: 102;\n  overflow: auto;\n  background-color: #f5f5f7;\n  border: 1px solid black;\n  border-radius: 0.5em;\n  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);\n}\ndiv.dtr-modal div.dtr-modal-content {\n  position: relative;\n  padding: 1em;\n}\ndiv.dtr-modal div.dtr-modal-close {\n  position: absolute;\n  top: 6px;\n  right: 6px;\n  width: 22px;\n  height: 22px;\n  border: 1px solid #eaeaea;\n  background-color: #f9f9f9;\n  text-align: center;\n  border-radius: 3px;\n  cursor: pointer;\n  z-index: 12;\n}\ndiv.dtr-modal div.dtr-modal-close:hover {\n  background-color: #eaeaea;\n}\ndiv.dtr-modal div.dtr-modal-background {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  z-index: 101;\n  background: rgba(0, 0, 0, 0.6);\n}\n\n@media screen and (max-width: 767px) {\n  div.dtr-modal div.dtr-modal-display {\n    width: 95%;\n  }\n}\ntable.dataTable > tbody > tr.child ul {\n  font-size: 1em;\n}\n\n\ntable.dataTable tr.dtrg-group td {\n  background-color: #e0e0e0;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-0 td {\n  font-weight: bold;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-1 td,\ntable.dataTable tr.dtrg-group.dtrg-level-2 td {\n  background-color: #f0f0f0;\n  padding-top: 0.25em;\n  padding-bottom: 0.25em;\n  padding-left: 2em;\n  font-size: 0.9em;\n}\n\ntable.dataTable tr.dtrg-group.dtrg-level-2 td {\n  background-color: #f3f3f3;\n}\n\n\ntable.dt-rowReorder-float {\n  position: absolute !important;\n  opacity: 0.8;\n  table-layout: fixed;\n  outline: 2px solid #337ab7;\n  outline-offset: -2px;\n  z-index: 2001;\n}\n\ntr.dt-rowReorder-moving {\n  outline: 2px solid #888;\n  outline-offset: -2px;\n}\n\nbody.dt-rowReorder-noOverflow {\n  overflow-x: hidden;\n}\n\ntable.dataTable td.reorder {\n  text-align: center;\n  cursor: move;\n}\n\n\ndiv.DTS tbody th,\ndiv.DTS tbody td {\n  white-space: nowrap;\n}\ndiv.DTS div.DTS_Loading {\n  z-index: 1;\n}\ndiv.DTS div.dataTables_scrollBody {\n  background: repeating-linear-gradient(45deg, #edeeff, #edeeff 10px, white 10px, white 20px);\n}\ndiv.DTS div.dataTables_scrollBody table {\n  z-index: 2;\n}\ndiv.DTS div.dataTables_paginate,\ndiv.DTS div.dataTables_length {\n  display: none;\n}\n\n\ntable.dataTable tbody > tr.selected,\ntable.dataTable tbody > tr > .selected {\n  background-color: #008cba;\n}\ntable.dataTable.stripe tbody > tr.odd.selected,\ntable.dataTable.stripe tbody > tr.odd > .selected, table.dataTable.display tbody > tr.odd.selected,\ntable.dataTable.display tbody > tr.odd > .selected {\n  background-color: #0089b6;\n}\ntable.dataTable.hover tbody > tr.selected:hover,\ntable.dataTable.hover tbody > tr > .selected:hover, table.dataTable.display tbody > tr.selected:hover,\ntable.dataTable.display tbody > tr > .selected:hover {\n  background-color: #0087b3;\n}\ntable.dataTable.order-column tbody > tr.selected > .sorting_1,\ntable.dataTable.order-column tbody > tr.selected > .sorting_2,\ntable.dataTable.order-column tbody > tr.selected > .sorting_3,\ntable.dataTable.order-column tbody > tr > .selected, table.dataTable.display tbody > tr.selected > .sorting_1,\ntable.dataTable.display tbody > tr.selected > .sorting_2,\ntable.dataTable.display tbody > tr.selected > .sorting_3,\ntable.dataTable.display tbody > tr > .selected {\n  background-color: #0089b6;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_1 {\n  background-color: #0084b0;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_2 {\n  background-color: #0085b1;\n}\ntable.dataTable.display tbody > tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_3 {\n  background-color: #0087b3;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_1 {\n  background-color: #0089b6;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_2 {\n  background-color: #008ab8;\n}\ntable.dataTable.display tbody > tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_3 {\n  background-color: #008bb9;\n}\ntable.dataTable.display tbody > tr.odd > .selected, table.dataTable.order-column.stripe tbody > tr.odd > .selected {\n  background-color: #0084b0;\n}\ntable.dataTable.display tbody > tr.even > .selected, table.dataTable.order-column.stripe tbody > tr.even > .selected {\n  background-color: #0089b6;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_1, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_1 {\n  background-color: #0081ab;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_2, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_2 {\n  background-color: #0082ac;\n}\ntable.dataTable.display tbody > tr.selected:hover > .sorting_3, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_3 {\n  background-color: #0083ae;\n}\ntable.dataTable.display tbody > tr:hover > .selected,\ntable.dataTable.display tbody > tr > .selected:hover, table.dataTable.order-column.hover tbody > tr:hover > .selected,\ntable.dataTable.order-column.hover tbody > tr > .selected:hover {\n  background-color: #0081ab;\n}\ntable.dataTable tbody td.select-checkbox,\ntable.dataTable tbody th.select-checkbox {\n  position: relative;\n}\ntable.dataTable tbody td.select-checkbox:before, table.dataTable tbody td.select-checkbox:after,\ntable.dataTable tbody th.select-checkbox:before,\ntable.dataTable tbody th.select-checkbox:after {\n  display: block;\n  position: absolute;\n  top: 1.2em;\n  left: 50%;\n  width: 12px;\n  height: 12px;\n  box-sizing: border-box;\n}\ntable.dataTable tbody td.select-checkbox:before,\ntable.dataTable tbody th.select-checkbox:before {\n  content: ' ';\n  margin-top: -6px;\n  margin-left: -6px;\n  border: 1px solid black;\n  border-radius: 3px;\n}\ntable.dataTable tr.selected td.select-checkbox:after,\ntable.dataTable tr.selected th.select-checkbox:after {\n  content: '\\2714';\n  margin-top: -11px;\n  margin-left: -4px;\n  text-align: center;\n  text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9;\n}\n\ndiv.dataTables_wrapper span.select-info,\ndiv.dataTables_wrapper span.select-item {\n  margin-left: 0.5em;\n}\n\n@media screen and (max-width: 640px) {\n  div.dataTables_wrapper span.select-info,\n  div.dataTables_wrapper span.select-item {\n    margin-left: 0;\n    display: block;\n  }\n}\ntable.dataTable tbody tr.selected th,\ntable.dataTable tbody tr.selected td,\ntable.dataTable tbody th.selected,\ntable.dataTable tbody td.selected {\n  color: white;\n}\ntable.dataTable tbody tr.selected th a,\ntable.dataTable tbody tr.selected td a,\ntable.dataTable tbody th.selected a,\ntable.dataTable tbody td.selected a {\n  color: #a2d4ed;\n}\n\n\n"
  },
  {
    "path": "static/js/DataTables/datatables.js",
    "content": "/*\n * This combined file was created by the DataTables downloader builder:\n *   https://datatables.net/download\n *\n * To rebuild or modify this file with the latest versions of the included\n * software please visit:\n *   https://datatables.net/download/#zf/jq-3.3.1/jszip-2.5.0/pdfmake-0.1.36/dt-1.10.18/af-2.3.3/b-1.5.6/b-colvis-1.5.6/b-flash-1.5.6/b-html5-1.5.6/b-print-1.5.6/cr-1.5.0/fc-3.2.5/fh-3.1.4/kt-2.5.0/r-2.2.2/rg-1.1.0/rr-1.2.4/sc-2.0.0/sl-1.3.0\n *\n * Included libraries:\n *   jQuery 3 3.3.1, JSZip 2.5.0, pdfmake 0.1.36, DataTables 1.10.18, AutoFill 2.3.3, Buttons 1.5.6, Column visibility 1.5.6, Flash export 1.5.6, HTML5 export 1.5.6, Print view 1.5.6, ColReorder 1.5.0, FixedColumns 3.2.5, FixedHeader 3.1.4, KeyTable 2.5.0, Responsive 2.2.2, RowGroup 1.1.0, RowReorder 1.2.4, Scroller 2.0.0, Select 1.3.0\n */\n\n/*!\n * jQuery JavaScript Library v3.3.1\n * https://jquery.com/\n *\n * Includes Sizzle.js\n * https://sizzlejs.com/\n *\n * Copyright JS Foundation and other contributors\n * Released under the MIT license\n * https://jquery.org/license\n *\n * Date: 2018-01-20T17:24Z\n */\n( function( global, factory ) {\n\n\t\"use strict\";\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\t// For environments that do not have a `window` with a `document`\n\t\t// (such as Node.js), expose a factory as module.exports.\n\t\t// This accentuates the need for the creation of a real `window`.\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket #14549 for more info.\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n} )( typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1\n// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode\n// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common\n// enough that all such attempts are guarded in a try block.\n\"use strict\";\n\nvar arr = [];\n\nvar document = window.document;\n\nvar getProto = Object.getPrototypeOf;\n\nvar slice = arr.slice;\n\nvar concat = arr.concat;\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar fnToString = hasOwn.toString;\n\nvar ObjectFunctionString = fnToString.call( Object );\n\nvar support = {};\n\nvar isFunction = function isFunction( obj ) {\n\n      // Support: Chrome <=57, Firefox <=52\n      // In some browsers, typeof returns \"function\" for HTML <object> elements\n      // (i.e., `typeof document.createElement( \"object\" ) === \"function\"`).\n      // We don't want to classify *any* DOM node as a function.\n      return typeof obj === \"function\" && typeof obj.nodeType !== \"number\";\n  };\n\n\nvar isWindow = function isWindow( obj ) {\n\t\treturn obj != null && obj === obj.window;\n\t};\n\n\n\n\n\tvar preservedScriptAttributes = {\n\t\ttype: true,\n\t\tsrc: true,\n\t\tnoModule: true\n\t};\n\n\tfunction DOMEval( code, doc, node ) {\n\t\tdoc = doc || document;\n\n\t\tvar i,\n\t\t\tscript = doc.createElement( \"script\" );\n\n\t\tscript.text = code;\n\t\tif ( node ) {\n\t\t\tfor ( i in preservedScriptAttributes ) {\n\t\t\t\tif ( node[ i ] ) {\n\t\t\t\t\tscript[ i ] = node[ i ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdoc.head.appendChild( script ).parentNode.removeChild( script );\n\t}\n\n\nfunction toType( obj ) {\n\tif ( obj == null ) {\n\t\treturn obj + \"\";\n\t}\n\n\t// Support: Android <=2.3 only (functionish RegExp)\n\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\ttypeof obj;\n}\n/* global Symbol */\n// Defining this global in .eslintrc.json would create a danger of using the global\n// unguarded in another place, it seems safer to define global only for this module\n\n\n\nvar\n\tversion = \"3.3.1\",\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t},\n\n\t// Support: Android <=4.0 only\n\t// Make sure we trim BOM and NBSP\n\trtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;\n\njQuery.fn = jQuery.prototype = {\n\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\n\t\t// Return all the elements in a clean array\n\t\tif ( num == null ) {\n\t\t\treturn slice.call( this );\n\t\t}\n\n\t\t// Return just the one element from the set\n\t\treturn num < 0 ? this[ num + this.length ] : this[ num ];\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\teach: function( callback ) {\n\t\treturn jQuery.each( this, callback );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map( this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t} ) );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor();\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: arr.sort,\n\tsplice: arr.splice\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[ 0 ] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !isFunction( target ) ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\n\t\t// Only deal with non-null/undefined values\n\t\tif ( ( options = arguments[ i ] ) != null ) {\n\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tsrc = target[ name ];\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject( copy ) ||\n\t\t\t\t\t( copyIsArray = Array.isArray( copy ) ) ) ) {\n\n\t\t\t\t\tif ( copyIsArray ) {\n\t\t\t\t\t\tcopyIsArray = false;\n\t\t\t\t\t\tclone = src && Array.isArray( src ) ? src : [];\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src && jQuery.isPlainObject( src ) ? src : {};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend( {\n\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisPlainObject: function( obj ) {\n\t\tvar proto, Ctor;\n\n\t\t// Detect obvious negatives\n\t\t// Use toString instead of jQuery.type to catch host objects\n\t\tif ( !obj || toString.call( obj ) !== \"[object Object]\" ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tproto = getProto( obj );\n\n\t\t// Objects with no prototype (e.g., `Object.create( null )`) are plain\n\t\tif ( !proto ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Objects with prototype are plain iff they were constructed by a global Object function\n\t\tCtor = hasOwn.call( proto, \"constructor\" ) && proto.constructor;\n\t\treturn typeof Ctor === \"function\" && fnToString.call( Ctor ) === ObjectFunctionString;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\n\t\t/* eslint-disable no-unused-vars */\n\t\t// See https://github.com/eslint/eslint/issues/6125\n\t\tvar name;\n\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\t// Evaluates a script in a global context\n\tglobalEval: function( code ) {\n\t\tDOMEval( code );\n\t},\n\n\teach: function( obj, callback ) {\n\t\tvar length, i = 0;\n\n\t\tif ( isArrayLike( obj ) ) {\n\t\t\tlength = obj.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( i in obj ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\t// Support: Android <=4.0 only\n\ttrim: function( text ) {\n\t\treturn text == null ?\n\t\t\t\"\" :\n\t\t\t( text + \"\" ).replace( rtrim, \"\" );\n\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArrayLike( Object( arr ) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t// push.apply(_, arraylike) throws on ancient WebKit\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar length, value,\n\t\t\ti = 0,\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArrayLike( elems ) ) {\n\t\t\tlength = elems.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn concat.apply( [], ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n} );\n\nif ( typeof Symbol === \"function\" ) {\n\tjQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n}\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\nfunction( i, name ) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n} );\n\nfunction isArrayLike( obj ) {\n\n\t// Support: real iOS 8.2 only (not reproducible in simulator)\n\t// `in` check used to prevent JIT error (gh-2145)\n\t// hasOwn isn't used here due to false negatives\n\t// regarding Nodelist length in IE\n\tvar length = !!obj && \"length\" in obj && obj.length,\n\t\ttype = toType( obj );\n\n\tif ( isFunction( obj ) || isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\nvar Sizzle =\n/*!\n * Sizzle CSS Selector Engine v2.3.3\n * https://sizzlejs.com/\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2016-08-08\n */\n(function( window ) {\n\nvar i,\n\tsupport,\n\tExpr,\n\tgetText,\n\tisXML,\n\ttokenize,\n\tcompile,\n\tselect,\n\toutermostContext,\n\tsortInput,\n\thasDuplicate,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsHTML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + 1 * new Date(),\n\tpreferredDoc = window.document,\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn 0;\n\t},\n\n\t// Instance methods\n\thasOwn = ({}).hasOwnProperty,\n\tarr = [],\n\tpop = arr.pop,\n\tpush_native = arr.push,\n\tpush = arr.push,\n\tslice = arr.slice,\n\t// Use a stripped-down indexOf as it's faster than native\n\t// https://jsperf.com/thor-indexof-vs-for/5\n\tindexOf = function( list, elem ) {\n\t\tvar i = 0,\n\t\t\tlen = list.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( list[i] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\tbooleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",\n\n\t// Regular expressions\n\n\t// http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\n\t// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier\n\tidentifier = \"(?:\\\\\\\\.|[\\\\w-]|[^\\0-\\\\xa0])+\",\n\n\t// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n\t\t// Operator (capture 2)\n\t\t\"*([*^$|!~]?=)\" + whitespace +\n\t\t// \"Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]\"\n\t\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" + whitespace +\n\t\t\"*\\\\]\",\n\n\tpseudos = \":(\" + identifier + \")(?:\\\\((\" +\n\t\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\t\t// 2. simple (capture 6)\n\t\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\t\t// 3. anything else (capture 2)\n\t\t\".*\" +\n\t\t\")\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace + \"*\" ),\n\n\trattributeQuotes = new RegExp( \"=\" + whitespace + \"*([^\\\\]'\\\"]*?)\" + whitespace + \"*\\\\]\", \"g\" ),\n\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + identifier + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + identifier + \"|[*])\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" + whitespace +\n\t\t\t\"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" + whitespace +\n\t\t\t\"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t\"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace + \"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" +\n\t\t\twhitespace + \"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trsibling = /[+~]/,\n\n\t// CSS escapes\n\t// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = new RegExp( \"\\\\\\\\([\\\\da-f]{1,6}\" + whitespace + \"?|(\" + whitespace + \")|.)\", \"ig\" ),\n\tfunescape = function( _, escaped, escapedWhitespace ) {\n\t\tvar high = \"0x\" + escaped - 0x10000;\n\t\t// NaN means non-codepoint\n\t\t// Support: Firefox<24\n\t\t// Workaround erroneous numeric interpretation of +\"0x\"\n\t\treturn high !== high || escapedWhitespace ?\n\t\t\tescaped :\n\t\t\thigh < 0 ?\n\t\t\t\t// BMP codepoint\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\t// Supplemental Plane codepoint (surrogate pair)\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t},\n\n\t// CSS string/identifier serialization\n\t// https://drafts.csswg.org/cssom/#common-serializing-idioms\n\trcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,\n\tfcssescape = function( ch, asCodePoint ) {\n\t\tif ( asCodePoint ) {\n\n\t\t\t// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n\t\t\tif ( ch === \"\\0\" ) {\n\t\t\t\treturn \"\\uFFFD\";\n\t\t\t}\n\n\t\t\t// Control characters and (dependent upon position) numbers get escaped as code points\n\t\t\treturn ch.slice( 0, -1 ) + \"\\\\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + \" \";\n\t\t}\n\n\t\t// Other potentially-special ASCII characters get backslash-escaped\n\t\treturn \"\\\\\" + ch;\n\t},\n\n\t// Used for iframes\n\t// See setDocument()\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t},\n\n\tdisabledAncestor = addCombinator(\n\t\tfunction( elem ) {\n\t\t\treturn elem.disabled === true && (\"form\" in elem || \"label\" in elem);\n\t\t},\n\t\t{ dir: \"parentNode\", next: \"legend\" }\n\t);\n\n// Optimize for push.apply( _, NodeList )\ntry {\n\tpush.apply(\n\t\t(arr = slice.call( preferredDoc.childNodes )),\n\t\tpreferredDoc.childNodes\n\t);\n\t// Support: Android<4.0\n\t// Detect silently failing push.apply\n\tarr[ preferredDoc.childNodes.length ].nodeType;\n} catch ( e ) {\n\tpush = { apply: arr.length ?\n\n\t\t// Leverage slice if possible\n\t\tfunction( target, els ) {\n\t\t\tpush_native.apply( target, slice.call(els) );\n\t\t} :\n\n\t\t// Support: IE<9\n\t\t// Otherwise append directly\n\t\tfunction( target, els ) {\n\t\t\tvar j = target.length,\n\t\t\t\ti = 0;\n\t\t\t// Can't trust NodeList.length\n\t\t\twhile ( (target[j++] = els[i++]) ) {}\n\t\t\ttarget.length = j - 1;\n\t\t}\n\t};\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar m, i, elem, nid, match, groups, newSelector,\n\t\tnewContext = context && context.ownerDocument,\n\n\t\t// nodeType defaults to 9, since context defaults to document\n\t\tnodeType = context ? context.nodeType : 9;\n\n\tresults = results || [];\n\n\t// Return early from calls with invalid selector or context\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\t// Try to shortcut find operations (as opposed to filters) in HTML documents\n\tif ( !seed ) {\n\n\t\tif ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {\n\t\t\tsetDocument( context );\n\t\t}\n\t\tcontext = context || document;\n\n\t\tif ( documentIsHTML ) {\n\n\t\t\t// If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n\t\t\t// (excepting DocumentFragment context, where the methods don't exist)\n\t\t\tif ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {\n\n\t\t\t\t// ID selector\n\t\t\t\tif ( (m = match[1]) ) {\n\n\t\t\t\t\t// Document context\n\t\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\t\tif ( (elem = context.getElementById( m )) ) {\n\n\t\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t// Element context\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\tif ( newContext && (elem = newContext.getElementById( m )) &&\n\t\t\t\t\t\t\tcontains( context, elem ) &&\n\t\t\t\t\t\t\telem.id === m ) {\n\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// Type selector\n\t\t\t\t} else if ( match[2] ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\t\treturn results;\n\n\t\t\t\t// Class selector\n\t\t\t\t} else if ( (m = match[3]) && support.getElementsByClassName &&\n\t\t\t\t\tcontext.getElementsByClassName ) {\n\n\t\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Take advantage of querySelectorAll\n\t\t\tif ( support.qsa &&\n\t\t\t\t!compilerCache[ selector + \" \" ] &&\n\t\t\t\t(!rbuggyQSA || !rbuggyQSA.test( selector )) ) {\n\n\t\t\t\tif ( nodeType !== 1 ) {\n\t\t\t\t\tnewContext = context;\n\t\t\t\t\tnewSelector = selector;\n\n\t\t\t\t// qSA looks outside Element context, which is not what we want\n\t\t\t\t// Thanks to Andrew Dupont for this workaround technique\n\t\t\t\t// Support: IE <=8\n\t\t\t\t// Exclude object elements\n\t\t\t\t} else if ( context.nodeName.toLowerCase() !== \"object\" ) {\n\n\t\t\t\t\t// Capture the context ID, setting it first if necessary\n\t\t\t\t\tif ( (nid = context.getAttribute( \"id\" )) ) {\n\t\t\t\t\t\tnid = nid.replace( rcssescape, fcssescape );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontext.setAttribute( \"id\", (nid = expando) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prefix every selector in the list\n\t\t\t\t\tgroups = tokenize( selector );\n\t\t\t\t\ti = groups.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tgroups[i] = \"#\" + nid + \" \" + toSelector( groups[i] );\n\t\t\t\t\t}\n\t\t\t\t\tnewSelector = groups.join( \",\" );\n\n\t\t\t\t\t// Expand context for sibling selectors\n\t\t\t\t\tnewContext = rsibling.test( selector ) && testContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext;\n\t\t\t\t}\n\n\t\t\t\tif ( newSelector ) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t} catch ( qsaError ) {\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif ( nid === expando ) {\n\t\t\t\t\t\t\tcontext.removeAttribute( \"id\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {function(string, object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn (cache[ key + \" \" ] = value);\n\t}\n\treturn cache;\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created element and returns a boolean result\n */\nfunction assert( fn ) {\n\tvar el = document.createElement(\"fieldset\");\n\n\ttry {\n\t\treturn !!fn( el );\n\t} catch (e) {\n\t\treturn false;\n\t} finally {\n\t\t// Remove from its parent by default\n\t\tif ( el.parentNode ) {\n\t\t\tel.parentNode.removeChild( el );\n\t\t}\n\t\t// release memory in IE\n\t\tel = null;\n\t}\n}\n\n/**\n * Adds the same handler for all of the specified attrs\n * @param {String} attrs Pipe-separated list of attributes\n * @param {Function} handler The method that will be applied\n */\nfunction addHandle( attrs, handler ) {\n\tvar arr = attrs.split(\"|\"),\n\t\ti = arr.length;\n\n\twhile ( i-- ) {\n\t\tExpr.attrHandle[ arr[i] ] = handler;\n\t}\n}\n\n/**\n * Checks document order of two siblings\n * @param {Element} a\n * @param {Element} b\n * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n */\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n\t\t\ta.sourceIndex - b.sourceIndex;\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( (cur = cur.nextSibling) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn (name === \"input\" || name === \"button\") && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for :enabled/:disabled\n * @param {Boolean} disabled true for :disabled; false for :enabled\n */\nfunction createDisabledPseudo( disabled ) {\n\n\t// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable\n\treturn function( elem ) {\n\n\t\t// Only certain elements can match :enabled or :disabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled\n\t\tif ( \"form\" in elem ) {\n\n\t\t\t// Check for inherited disabledness on relevant non-disabled elements:\n\t\t\t// * listed form-associated elements in a disabled fieldset\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#category-listed\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled\n\t\t\t// * option elements in a disabled optgroup\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled\n\t\t\t// All such elements have a \"form\" property.\n\t\t\tif ( elem.parentNode && elem.disabled === false ) {\n\n\t\t\t\t// Option elements defer to a parent optgroup if present\n\t\t\t\tif ( \"label\" in elem ) {\n\t\t\t\t\tif ( \"label\" in elem.parentNode ) {\n\t\t\t\t\t\treturn elem.parentNode.disabled === disabled;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn elem.disabled === disabled;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Support: IE 6 - 11\n\t\t\t\t// Use the isDisabled shortcut property to check for disabled fieldset ancestors\n\t\t\t\treturn elem.isDisabled === disabled ||\n\n\t\t\t\t\t// Where there is no isDisabled, check manually\n\t\t\t\t\t/* jshint -W018 */\n\t\t\t\t\telem.isDisabled !== !disabled &&\n\t\t\t\t\t\tdisabledAncestor( elem ) === disabled;\n\t\t\t}\n\n\t\t\treturn elem.disabled === disabled;\n\n\t\t// Try to winnow out elements that can't be disabled before trusting the disabled property.\n\t\t// Some victims get caught in our net (label, legend, menu, track), but it shouldn't\n\t\t// even exist on them, let alone have a boolean value.\n\t\t} else if ( \"label\" in elem ) {\n\t\t\treturn elem.disabled === disabled;\n\t\t}\n\n\t\t// Remaining elements are neither :enabled nor :disabled\n\t\treturn false;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction(function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction(function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ (j = matchIndexes[i]) ] ) {\n\t\t\t\t\tseed[j] = !(matches[j] = seed[j]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Checks a node for validity as a Sizzle context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Expose support vars for convenience\nsupport = Sizzle.support = {};\n\n/**\n * Detects XML nodes\n * @param {Element|Object} elem An element or a document\n * @returns {Boolean} True iff elem is a non-HTML XML node\n */\nisXML = Sizzle.isXML = function( elem ) {\n\t// documentElement is verified for cases where it doesn't yet exist\n\t// (such as loading iframes in IE - #4833)\n\tvar documentElement = elem && (elem.ownerDocument || elem).documentElement;\n\treturn documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar hasCompare, subWindow,\n\t\tdoc = node ? node.ownerDocument || node : preferredDoc;\n\n\t// Return early if doc is invalid or already selected\n\tif ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Update global variables\n\tdocument = doc;\n\tdocElem = document.documentElement;\n\tdocumentIsHTML = !isXML( document );\n\n\t// Support: IE 9-11, Edge\n\t// Accessing iframe documents after unload throws \"permission denied\" errors (jQuery #13936)\n\tif ( preferredDoc !== document &&\n\t\t(subWindow = document.defaultView) && subWindow.top !== subWindow ) {\n\n\t\t// Support: IE 11, Edge\n\t\tif ( subWindow.addEventListener ) {\n\t\t\tsubWindow.addEventListener( \"unload\", unloadHandler, false );\n\n\t\t// Support: IE 9 - 10 only\n\t\t} else if ( subWindow.attachEvent ) {\n\t\t\tsubWindow.attachEvent( \"onunload\", unloadHandler );\n\t\t}\n\t}\n\n\t/* Attributes\n\t---------------------------------------------------------------------- */\n\n\t// Support: IE<8\n\t// Verify that getAttribute really returns attributes and not properties\n\t// (excepting IE8 booleans)\n\tsupport.attributes = assert(function( el ) {\n\t\tel.className = \"i\";\n\t\treturn !el.getAttribute(\"className\");\n\t});\n\n\t/* getElement(s)By*\n\t---------------------------------------------------------------------- */\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.getElementsByTagName = assert(function( el ) {\n\t\tel.appendChild( document.createComment(\"\") );\n\t\treturn !el.getElementsByTagName(\"*\").length;\n\t});\n\n\t// Support: IE<9\n\tsupport.getElementsByClassName = rnative.test( document.getElementsByClassName );\n\n\t// Support: IE<10\n\t// Check if getElementById returns elements by name\n\t// The broken getElementById methods don't pick up programmatically-set names,\n\t// so use a roundabout getElementsByName test\n\tsupport.getById = assert(function( el ) {\n\t\tdocElem.appendChild( el ).id = expando;\n\t\treturn !document.getElementsByName || !document.getElementsByName( expando ).length;\n\t});\n\n\t// ID filter and find\n\tif ( support.getById ) {\n\t\tExpr.filter[\"ID\"] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"id\") === attrId;\n\t\t\t};\n\t\t};\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar elem = context.getElementById( id );\n\t\t\t\treturn elem ? [ elem ] : [];\n\t\t\t}\n\t\t};\n\t} else {\n\t\tExpr.filter[\"ID\"] =  function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" &&\n\t\t\t\t\telem.getAttributeNode(\"id\");\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\n\t\t// Support: IE 6 - 7 only\n\t\t// getElementById is not reliable as a find shortcut\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar node, i, elems,\n\t\t\t\t\telem = context.getElementById( id );\n\n\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t// Verify the id attribute\n\t\t\t\t\tnode = elem.getAttributeNode(\"id\");\n\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fall back on getElementsByName\n\t\t\t\t\telems = context.getElementsByName( id );\n\t\t\t\t\ti = 0;\n\t\t\t\t\twhile ( (elem = elems[i++]) ) {\n\t\t\t\t\t\tnode = elem.getAttributeNode(\"id\");\n\t\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn [];\n\t\t\t}\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[\"TAG\"] = support.getElementsByTagName ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else if ( support.qsa ) {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t} :\n\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\t\t\t\t// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( (elem = results[i++]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Class\n\tExpr.find[\"CLASS\"] = support.getElementsByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t/* QSA/matchesSelector\n\t---------------------------------------------------------------------- */\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21)\n\t// We allow this because of a bug in IE8/9 that throws an error\n\t// whenever `document.activeElement` is accessed on an iframe\n\t// So, we allow :focus to pass through QSA all the time to avoid the IE error\n\t// See https://bugs.jquery.com/ticket/13378\n\trbuggyQSA = [];\n\n\tif ( (support.qsa = rnative.test( document.querySelectorAll )) ) {\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert(function( el ) {\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explicitly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// https://bugs.jquery.com/ticket/12359\n\t\t\tdocElem.appendChild( el ).innerHTML = \"<a id='\" + expando + \"'></a>\" +\n\t\t\t\t\"<select id='\" + expando + \"-\\r\\\\' msallowcapture=''>\" +\n\t\t\t\t\"<option selected=''></option></select>\";\n\n\t\t\t// Support: IE8, Opera 11-12.16\n\t\t\t// Nothing should be selected when empty strings follow ^= or $= or *=\n\t\t\t// The test attribute must be unknown in Opera but \"safe\" for WinRT\n\t\t\t// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section\n\t\t\tif ( el.querySelectorAll(\"[msallowcapture^='']\").length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Support: IE8\n\t\t\t// Boolean attributes and \"value\" are not treated correctly\n\t\t\tif ( !el.querySelectorAll(\"[selected]\").length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n\t\t\t}\n\n\t\t\t// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+\n\t\t\tif ( !el.querySelectorAll( \"[id~=\" + expando + \"-]\" ).length ) {\n\t\t\t\trbuggyQSA.push(\"~=\");\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !el.querySelectorAll(\":checked\").length ) {\n\t\t\t\trbuggyQSA.push(\":checked\");\n\t\t\t}\n\n\t\t\t// Support: Safari 8+, iOS 8+\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=136851\n\t\t\t// In-page `selector#id sibling-combinator selector` fails\n\t\t\tif ( !el.querySelectorAll( \"a#\" + expando + \"+*\" ).length ) {\n\t\t\t\trbuggyQSA.push(\".#.+[+~]\");\n\t\t\t}\n\t\t});\n\n\t\tassert(function( el ) {\n\t\t\tel.innerHTML = \"<a href='' disabled='disabled'></a>\" +\n\t\t\t\t\"<select disabled='disabled'><option/></select>\";\n\n\t\t\t// Support: Windows 8 Native Apps\n\t\t\t// The type and name attributes are restricted during .innerHTML assignment\n\t\t\tvar input = document.createElement(\"input\");\n\t\t\tinput.setAttribute( \"type\", \"hidden\" );\n\t\t\tel.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n\t\t\t// Support: IE8\n\t\t\t// Enforce case-sensitivity of name attribute\n\t\t\tif ( el.querySelectorAll(\"[name=d]\").length ) {\n\t\t\t\trbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( el.querySelectorAll(\":enabled\").length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Support: IE9-11+\n\t\t\t// IE's :disabled selector does not pick up the children of disabled fieldsets\n\t\t\tdocElem.appendChild( el ).disabled = true;\n\t\t\tif ( el.querySelectorAll(\":disabled\").length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tel.querySelectorAll(\"*,:x\");\n\t\t\trbuggyQSA.push(\",.*:\");\n\t\t});\n\t}\n\n\tif ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||\n\t\tdocElem.webkitMatchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector) )) ) {\n\n\t\tassert(function( el ) {\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( el, \"*\" );\n\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( el, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t});\n\t}\n\n\trbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join(\"|\") );\n\trbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join(\"|\") );\n\n\t/* Contains\n\t---------------------------------------------------------------------- */\n\thasCompare = rnative.test( docElem.compareDocumentPosition );\n\n\t// Element contains another\n\t// Purposefully self-exclusive\n\t// As in, an element does not contain itself\n\tcontains = hasCompare || rnative.test( docElem.contains ) ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t));\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( (b = b.parentNode) ) {\n\t\t\t\t\tif ( b === a ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t/* Sorting\n\t---------------------------------------------------------------------- */\n\n\t// Document order sorting\n\tsortOrder = hasCompare ?\n\tfunction( a, b ) {\n\n\t\t// Flag for duplicate removal\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Sort on method existence if only one input has compareDocumentPosition\n\t\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\t\tif ( compare ) {\n\t\t\treturn compare;\n\t\t}\n\n\t\t// Calculate position if both inputs belong to the same document\n\t\tcompare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?\n\t\t\ta.compareDocumentPosition( b ) :\n\n\t\t\t// Otherwise we know they are disconnected\n\t\t\t1;\n\n\t\t// Disconnected nodes\n\t\tif ( compare & 1 ||\n\t\t\t(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {\n\n\t\t\t// Choose the first element that is related to our preferred document\n\t\t\tif ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// Maintain original order\n\t\t\treturn sortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\t\t}\n\n\t\treturn compare & 4 ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\tif ( !aup || !bup ) {\n\t\t\treturn a === document ? -1 :\n\t\t\t\tb === document ? 1 :\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\tsortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[i] === bp[i] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[i], bp[i] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\tap[i] === preferredDoc ? -1 :\n\t\t\tbp[i] === preferredDoc ? 1 :\n\t\t\t0;\n\t};\n\n\treturn document;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\t// Make sure that attribute selectors are quoted\n\texpr = expr.replace( rattributeQuotes, \"='$1']\" );\n\n\tif ( support.matchesSelector && documentIsHTML &&\n\t\t!compilerCache[ expr + \" \" ] &&\n\t\t( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n\t\t( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\t\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t\t// fragment in IE 9\n\t\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch (e) {}\n\t}\n\n\treturn Sizzle( expr, document, null, [ elem ] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\t// Set document vars if needed\n\tif ( ( context.ownerDocument || context ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tvar fn = Expr.attrHandle[ name.toLowerCase() ],\n\t\t// Don't get fooled by Object.prototype properties (jQuery #13807)\n\t\tval = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n\t\t\tfn( elem, name, !documentIsHTML ) :\n\t\t\tundefined;\n\n\treturn val !== undefined ?\n\t\tval :\n\t\tsupport.attributes || !documentIsHTML ?\n\t\t\telem.getAttribute( name ) :\n\t\t\t(val = elem.getAttributeNode(name)) && val.specified ?\n\t\t\t\tval.value :\n\t\t\t\tnull;\n};\n\nSizzle.escape = function( sel ) {\n\treturn (sel + \"\").replace( rcssescape, fcssescape );\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tsortInput = !support.sortStable && results.slice( 0 );\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( (elem = results[i++]) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\t// Clear input after sorting to release objects\n\t// See https://github.com/jquery/sizzle/pull/225\n\tsortInput = null;\n\n\treturn results;\n};\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\t\t// If no nodeType, this is expected to be an array\n\t\twhile ( (node = elem[i++]) ) {\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (jQuery #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tattrHandle: {},\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[1] = match[1].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[3] = ( match[3] || match[4] || match[5] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[3] = \" \" + match[3] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[1] = match[1].toLowerCase();\n\n\t\t\tif ( match[1].slice( 0, 3 ) === \"nth\" ) {\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[3] ) {\n\t\t\t\t\tSizzle.error( match[0] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === \"even\" || match[3] === \"odd\" ) );\n\t\t\t\tmatch[5] = +( ( match[7] + match[8] ) || match[3] === \"odd\" );\n\n\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[3] ) {\n\t\t\t\tSizzle.error( match[0] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[6] && match[2];\n\n\t\t\tif ( matchExpr[\"CHILD\"].test( match[0] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[3] ) {\n\t\t\t\tmatch[2] = match[4] || match[5] || \"\";\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t(excess = tokenize( unquoted, true )) &&\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t(excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[0] = match[0].slice( 0, excess );\n\t\t\t\tmatch[2] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeNameSelector ) {\n\t\t\tvar nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\t\t\t\tfunction() { return true; } :\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t(pattern = new RegExp( \"(^|\" + whitespace + \")\" + className + \"(\" + whitespace + \"|$)\" )) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test( typeof elem.className === \"string\" && elem.className || typeof elem.getAttribute !== \"undefined\" && elem.getAttribute(\"class\") || \"\" );\n\t\t\t\t});\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tvar cache, uniqueCache, outerCache, node, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType,\n\t\t\t\t\t\tdiff = false;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( (node = node[ dir ]) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) {\n\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\n\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\tnode = parent;\n\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\tdiff = nodeIndex && cache[ 2 ];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\t\tdiff = nodeIndex;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// xml :nth-child(...)\n\t\t\t\t\t\t\t// or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t\tif ( diff === false ) {\n\t\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t\tif ( ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) &&\n\t\t\t\t\t\t\t\t\t\t++diff ) {\n\n\t\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction(function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf( seed, matched[i] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction(function( selector ) {\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction(function( seed, matches, context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = unmatched[i]) ) {\n\t\t\t\t\t\t\tseed[i] = !(matches[i] = elem);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}) :\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tinput[0] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\t\t\t\t\t// Don't keep the element (issue #299)\n\t\t\t\t\tinput[0] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t}),\n\n\t\t\"has\": markFunction(function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t}),\n\n\t\t\"contains\": markFunction(function( text ) {\n\t\t\ttext = text.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t}),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test(lang || \"\") ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( (elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute(\"xml:lang\") || elem.getAttribute(\"lang\")) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( (elem = elem.parentNode) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t}),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": createDisabledPseudo( false ),\n\t\t\"disabled\": createDisabledPseudo( true ),\n\n\t\t\"checked\": function( elem ) {\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn (nodeName === \"input\" && !!elem.checked) || (nodeName === \"option\" && !!elem.selected);\n\t\t},\n\n\t\t\"selected\": function( elem ) {\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t//   but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[\"empty\"]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\n\t\t\t\t// Support: IE<8\n\t\t\t\t// New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n\t\t\t\t( (attr = elem.getAttribute(\"type\")) == null || attr.toLowerCase() === \"text\" );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo(function() {\n\t\t\treturn [ 0 ];\n\t\t}),\n\n\t\t\"last\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t}),\n\n\t\t\"eq\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t}),\n\n\t\t\"even\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"odd\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"lt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"gt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t})\n\t}\n};\n\nExpr.pseudos[\"nth\"] = Expr.pseudos[\"eq\"];\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = Expr.filters = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\ntokenize = Sizzle.tokenize = function( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || (match = rcomma.exec( soFar )) ) {\n\t\t\tif ( match ) {\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[0].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( (tokens = []) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( (match = rcombinators.exec( soFar )) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push({\n\t\t\t\tvalue: matched,\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[0].replace( rtrim, \" \" )\n\t\t\t});\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||\n\t\t\t\t(match = preFilters[ type ]( match ))) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push({\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t});\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[i].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tskip = combinator.next,\n\t\tkey = skip || dir,\n\t\tcheckNonElements = base && key === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, uniqueCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || (elem[ expando ] = {});\n\n\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\tuniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});\n\n\t\t\t\t\t\tif ( skip && skip === elem.nodeName.toLowerCase() ) {\n\t\t\t\t\t\t\telem = elem[ dir ] || elem;\n\t\t\t\t\t\t} else if ( (oldCache = uniqueCache[ key ]) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn (newCache[ 2 ] = oldCache[ 2 ]);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\tuniqueCache[ key ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[i]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[0];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[i], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (elem = unmatched[i]) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction(function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts( selector || \"*\", context.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( (elem = temp[i]) ) {\n\t\t\t\t\tmatcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = matcherOut[i]) ) {\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( (matcherIn[i] = elem) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, (matcherOut = []), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( (elem = matcherOut[i]) &&\n\t\t\t\t\t\t(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {\n\n\t\t\t\t\t\tseed[temp] = !(results[temp] = elem);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[0].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[\" \"],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\tvar ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t(checkContext = context).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\t\t\t// Avoid hanging onto element (issue #299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (matcher = Expr.relative[ tokens[i].type ]) ) {\n\t\t\tmatchers = [ addCombinator(elementMatcher( matchers ), matcher) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[j].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\t\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\t\ttokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" })\n\t\t\t\t\t).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( (tokens = tokens.slice( j )) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && Expr.find[\"TAG\"]( \"*\", outermost ),\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),\n\t\t\t\tlen = elems.length;\n\n\t\t\tif ( outermost ) {\n\t\t\t\toutermostContext = context === document || context || outermost;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Support: IE<9, Safari\n\t\t\t// Tolerate NodeList properties (IE: \"length\"; Safari: <number>) matching elements by id\n\t\t\tfor ( ; i !== len && (elem = elems[i]) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\tif ( !context && elem.ownerDocument !== document ) {\n\t\t\t\t\t\tsetDocument( elem );\n\t\t\t\t\t\txml = !documentIsHTML;\n\t\t\t\t\t}\n\t\t\t\t\twhile ( (matcher = elementMatchers[j++]) ) {\n\t\t\t\t\t\tif ( matcher( elem, context || document, xml) ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( (elem = !matcher && elem) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// `i` is now the count of elements visited above, and adding it to `matchedCount`\n\t\t\t// makes the latter nonnegative.\n\t\t\tmatchedCount += i;\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n\t\t\t// equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n\t\t\t// no element matchers and no seed.\n\t\t\t// Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n\t\t\t// case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n\t\t\t// numerically zero.\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (matcher = setMatchers[j++]) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !(unmatched[i] || setMatched[i]) ) {\n\t\t\t\t\t\t\t\tsetMatched[i] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[i] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n};\n\n/**\n * A low-level selection function that works with Sizzle's compiled\n *  selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n *  selector function built with Sizzle.compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nselect = Sizzle.select = function( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( (selector = compiled.selector || selector) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is only one selector in the list and no seed\n\t// (the latter of which guarantees us context)\n\tif ( match.length === 1 ) {\n\n\t\t// Reduce context if the leading compound selector is an ID\n\t\ttokens = match[0] = match[0].slice( 0 );\n\t\tif ( tokens.length > 2 && (token = tokens[0]).type === \"ID\" &&\n\t\t\t\tcontext.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) {\n\n\t\t\tcontext = ( Expr.find[\"ID\"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr[\"needsContext\"].test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[i];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( Expr.relative[ (type = token.type) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( (find = Expr.find[ type ]) ) {\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( (seed = find(\n\t\t\t\t\ttoken.matches[0].replace( runescape, funescape ),\n\t\t\t\t\trsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context\n\t\t\t\t)) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\t!context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n};\n\n// One-time assignments\n\n// Sort stability\nsupport.sortStable = expando.split(\"\").sort( sortOrder ).join(\"\") === expando;\n\n// Support: Chrome 14-35+\n// Always assume duplicates if they aren't passed to the comparison function\nsupport.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\nsetDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\nsupport.sortDetached = assert(function( el ) {\n\t// Should return 1, but returns 4 (following)\n\treturn el.compareDocumentPosition( document.createElement(\"fieldset\") ) & 1;\n});\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !assert(function( el ) {\n\tel.innerHTML = \"<a href='#'></a>\";\n\treturn el.firstChild.getAttribute(\"href\") === \"#\" ;\n}) ) {\n\taddHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n\t\tif ( !isXML ) {\n\t\t\treturn elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\nif ( !support.attributes || !assert(function( el ) {\n\tel.innerHTML = \"<input/>\";\n\tel.firstChild.setAttribute( \"value\", \"\" );\n\treturn el.firstChild.getAttribute( \"value\" ) === \"\";\n}) ) {\n\taddHandle( \"value\", function( elem, name, isXML ) {\n\t\tif ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n\t\t\treturn elem.defaultValue;\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\nif ( !assert(function( el ) {\n\treturn el.getAttribute(\"disabled\") == null;\n}) ) {\n\taddHandle( booleans, function( elem, name, isXML ) {\n\t\tvar val;\n\t\tif ( !isXML ) {\n\t\t\treturn elem[ name ] === true ? name.toLowerCase() :\n\t\t\t\t\t(val = elem.getAttributeNode( name )) && val.specified ?\n\t\t\t\t\tval.value :\n\t\t\t\tnull;\n\t\t}\n\t});\n}\n\nreturn Sizzle;\n\n})( window );\n\n\n\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\n\n// Deprecated\njQuery.expr[ \":\" ] = jQuery.expr.pseudos;\njQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\njQuery.escapeSelector = Sizzle.escape;\n\n\n\n\nvar dir = function( elem, dir, until ) {\n\tvar matched = [],\n\t\ttruncate = until !== undefined;\n\n\twhile ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmatched.push( elem );\n\t\t}\n\t}\n\treturn matched;\n};\n\n\nvar siblings = function( n, elem ) {\n\tvar matched = [];\n\n\tfor ( ; n; n = n.nextSibling ) {\n\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\tmatched.push( n );\n\t\t}\n\t}\n\n\treturn matched;\n};\n\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\n\n\nfunction nodeName( elem, name ) {\n\n  return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\n};\nvar rsingleTag = ( /^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i );\n\n\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( isFunction( qualifier ) ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t} );\n\t}\n\n\t// Single element\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t} );\n\t}\n\n\t// Arraylike of elements (jQuery, arguments, Array)\n\tif ( typeof qualifier !== \"string\" ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( indexOf.call( qualifier, elem ) > -1 ) !== not;\n\t\t} );\n\t}\n\n\t// Filtered directly for both simple and complex selectors\n\treturn jQuery.filter( qualifier, elements, not );\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\tif ( elems.length === 1 && elem.nodeType === 1 ) {\n\t\treturn jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];\n\t}\n\n\treturn jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\treturn elem.nodeType === 1;\n\t} ) );\n};\n\njQuery.fn.extend( {\n\tfind: function( selector ) {\n\t\tvar i, ret,\n\t\t\tlen = this.length,\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter( function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\tret = this.pushStack( [] );\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\treturn len > 1 ? jQuery.uniqueSort( ret ) : ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], false ) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], true ) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n} );\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\t// Shortcut simple #id case for speed\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/,\n\n\tinit = jQuery.fn.init = function( selector, context, root ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Method init() accepts an alternate rootjQuery\n\t\t// so migrate can support jQuery.sub (gh-2101)\n\t\troot = root || rootjQuery;\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector[ 0 ] === \"<\" &&\n\t\t\t\tselector[ selector.length - 1 ] === \">\" &&\n\t\t\t\tselector.length >= 3 ) {\n\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\tif ( match && ( match[ 1 ] || !context ) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[ 1 ] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[ 0 ] : context;\n\n\t\t\t\t\t// Option to run scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[ 1 ],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[ 2 ] );\n\n\t\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis[ 0 ] = elem;\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || root ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis[ 0 ] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( isFunction( selector ) ) {\n\t\t\treturn root.ready !== undefined ?\n\t\t\t\troot.ready( selector ) :\n\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document );\n\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\n\t// Methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend( {\n\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter( function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[ i ] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\ttargets = typeof selectors !== \"string\" && jQuery( selectors );\n\n\t\t// Positional selectors never match, since there's no _selection_ context\n\t\tif ( !rneedsContext.test( selectors ) ) {\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tfor ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {\n\n\t\t\t\t\t// Always skip document fragments\n\t\t\t\t\tif ( cur.nodeType < 11 && ( targets ?\n\t\t\t\t\t\ttargets.index( cur ) > -1 :\n\n\t\t\t\t\t\t// Don't pass non-elements to Sizzle\n\t\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\t\tjQuery.find.matchesSelector( cur, selectors ) ) ) {\n\n\t\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within the set\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// Index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.uniqueSort(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter( selector )\n\t\t);\n\t}\n} );\n\nfunction sibling( cur, dir ) {\n\twhile ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}\n\treturn cur;\n}\n\njQuery.each( {\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn siblings( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn siblings( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n        if ( nodeName( elem, \"iframe\" ) ) {\n            return elem.contentDocument;\n        }\n\n        // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only\n        // Treat the template element as a regular one in browsers that\n        // don't support it.\n        if ( nodeName( elem, \"template\" ) ) {\n            elem = elem.content || elem;\n        }\n\n        return jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.uniqueSort( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n} );\nvar rnothtmlwhite = ( /[^\\x20\\t\\r\\n\\f]+/g );\n\n\n\n// Convert String-formatted options into Object-formatted ones\nfunction createOptions( options ) {\n\tvar object = {};\n\tjQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t} );\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\tcreateOptions( options ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Flag to know if list is currently firing\n\t\tfiring,\n\n\t\t// Last fire value for non-forgettable lists\n\t\tmemory,\n\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\n\t\t// Flag to prevent firing\n\t\tlocked,\n\n\t\t// Actual callback list\n\t\tlist = [],\n\n\t\t// Queue of execution data for repeatable lists\n\t\tqueue = [],\n\n\t\t// Index of currently firing callback (modified by add/remove as needed)\n\t\tfiringIndex = -1,\n\n\t\t// Fire callbacks\n\t\tfire = function() {\n\n\t\t\t// Enforce single-firing\n\t\t\tlocked = locked || options.once;\n\n\t\t\t// Execute callbacks for all pending executions,\n\t\t\t// respecting firingIndex overrides and runtime changes\n\t\t\tfired = firing = true;\n\t\t\tfor ( ; queue.length; firingIndex = -1 ) {\n\t\t\t\tmemory = queue.shift();\n\t\t\t\twhile ( ++firingIndex < list.length ) {\n\n\t\t\t\t\t// Run callback and check for early termination\n\t\t\t\t\tif ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&\n\t\t\t\t\t\toptions.stopOnFalse ) {\n\n\t\t\t\t\t\t// Jump to end and forget the data so .add doesn't re-fire\n\t\t\t\t\t\tfiringIndex = list.length;\n\t\t\t\t\t\tmemory = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Forget the data if we're done with it\n\t\t\tif ( !options.memory ) {\n\t\t\t\tmemory = false;\n\t\t\t}\n\n\t\t\tfiring = false;\n\n\t\t\t// Clean up if we're done firing for good\n\t\t\tif ( locked ) {\n\n\t\t\t\t// Keep an empty list if we have data for future add calls\n\t\t\t\tif ( memory ) {\n\t\t\t\t\tlist = [];\n\n\t\t\t\t// Otherwise, this object is spent\n\t\t\t\t} else {\n\t\t\t\t\tlist = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t// Actual Callbacks object\n\t\tself = {\n\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\n\t\t\t\t\t// If we have memory from a past run, we should fire after adding\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfiringIndex = list.length - 1;\n\t\t\t\t\t\tqueue.push( memory );\n\t\t\t\t\t}\n\n\t\t\t\t\t( function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tif ( isFunction( arg ) ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && toType( arg ) !== \"string\" ) {\n\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t} )( arguments );\n\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\tvar index;\n\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\tlist.splice( index, 1 );\n\n\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ?\n\t\t\t\t\tjQuery.inArray( fn, list ) > -1 :\n\t\t\t\t\tlist.length > 0;\n\t\t\t},\n\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Disable .fire and .add\n\t\t\t// Abort any current/pending executions\n\t\t\t// Clear all callbacks and values\n\t\t\tdisable: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tlist = memory = \"\";\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\n\t\t\t// Disable .fire\n\t\t\t// Also disable .add unless we have memory (since it would have no effect)\n\t\t\t// Abort any pending executions\n\t\t\tlock: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tif ( !memory && !firing ) {\n\t\t\t\t\tlist = memory = \"\";\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tlocked: function() {\n\t\t\t\treturn !!locked;\n\t\t\t},\n\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( !locked ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tqueue.push( args );\n\t\t\t\t\tif ( !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\nfunction Identity( v ) {\n\treturn v;\n}\nfunction Thrower( ex ) {\n\tthrow ex;\n}\n\nfunction adoptValue( value, resolve, reject, noValue ) {\n\tvar method;\n\n\ttry {\n\n\t\t// Check for promise aspect first to privilege synchronous behavior\n\t\tif ( value && isFunction( ( method = value.promise ) ) ) {\n\t\t\tmethod.call( value ).done( resolve ).fail( reject );\n\n\t\t// Other thenables\n\t\t} else if ( value && isFunction( ( method = value.then ) ) ) {\n\t\t\tmethod.call( value, resolve, reject );\n\n\t\t// Other non-thenables\n\t\t} else {\n\n\t\t\t// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:\n\t\t\t// * false: [ value ].slice( 0 ) => resolve( value )\n\t\t\t// * true: [ value ].slice( 1 ) => resolve()\n\t\t\tresolve.apply( undefined, [ value ].slice( noValue ) );\n\t\t}\n\n\t// For Promises/A+, convert exceptions into rejections\n\t// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in\n\t// Deferred#then to conditionally suppress rejection.\n\t} catch ( value ) {\n\n\t\t// Support: Android 4.0 only\n\t\t// Strict mode functions invoked without .call/.apply get global-object context\n\t\treject.apply( undefined, [ value ] );\n\t}\n}\n\njQuery.extend( {\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\n\t\t\t\t// action, add listener, callbacks,\n\t\t\t\t// ... .then handlers, argument index, [final state]\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks( \"memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"memory\" ), 2 ],\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 0, \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 1, \"rejected\" ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\t\"catch\": function( fn ) {\n\t\t\t\t\treturn promise.then( null, fn );\n\t\t\t\t},\n\n\t\t\t\t// Keep pipe for back-compat\n\t\t\t\tpipe: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( i, tuple ) {\n\n\t\t\t\t\t\t\t// Map tuples (progress, done, fail) to arguments (done, fail, progress)\n\t\t\t\t\t\t\tvar fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];\n\n\t\t\t\t\t\t\t// deferred.progress(function() { bind to newDefer or newDefer.notify })\n\t\t\t\t\t\t\t// deferred.done(function() { bind to newDefer or newDefer.resolve })\n\t\t\t\t\t\t\t// deferred.fail(function() { bind to newDefer or newDefer.reject })\n\t\t\t\t\t\t\tdeferred[ tuple[ 1 ] ]( function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify )\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ](\n\t\t\t\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\t\t\t\tfn ? [ returned ] : arguments\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\t\t\t\tthen: function( onFulfilled, onRejected, onProgress ) {\n\t\t\t\t\tvar maxDepth = 0;\n\t\t\t\t\tfunction resolve( depth, deferred, handler, special ) {\n\t\t\t\t\t\treturn function() {\n\t\t\t\t\t\t\tvar that = this,\n\t\t\t\t\t\t\t\targs = arguments,\n\t\t\t\t\t\t\t\tmightThrow = function() {\n\t\t\t\t\t\t\t\t\tvar returned, then;\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.3\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-59\n\t\t\t\t\t\t\t\t\t// Ignore double-resolution attempts\n\t\t\t\t\t\t\t\t\tif ( depth < maxDepth ) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturned = handler.apply( that, args );\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.1\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-48\n\t\t\t\t\t\t\t\t\tif ( returned === deferred.promise() ) {\n\t\t\t\t\t\t\t\t\t\tthrow new TypeError( \"Thenable self-resolution\" );\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ sections 2.3.3.1, 3.5\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-54\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-75\n\t\t\t\t\t\t\t\t\t// Retrieve `then` only once\n\t\t\t\t\t\t\t\t\tthen = returned &&\n\n\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.4\n\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-64\n\t\t\t\t\t\t\t\t\t\t// Only check objects and functions for thenability\n\t\t\t\t\t\t\t\t\t\t( typeof returned === \"object\" ||\n\t\t\t\t\t\t\t\t\t\t\ttypeof returned === \"function\" ) &&\n\t\t\t\t\t\t\t\t\t\treturned.then;\n\n\t\t\t\t\t\t\t\t\t// Handle a returned thenable\n\t\t\t\t\t\t\t\t\tif ( isFunction( then ) ) {\n\n\t\t\t\t\t\t\t\t\t\t// Special processors (notify) just wait for resolution\n\t\t\t\t\t\t\t\t\t\tif ( special ) {\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special )\n\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t// Normal processors (resolve) also hook into progress\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\t// ...and disregard older resolution values\n\t\t\t\t\t\t\t\t\t\t\tmaxDepth++;\n\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdeferred.notifyWith )\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Handle all other returned values\n\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\tif ( handler !== Identity ) {\n\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\targs = [ returned ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Process the value(s)\n\t\t\t\t\t\t\t\t\t\t// Default process is resolve\n\t\t\t\t\t\t\t\t\t\t( special || deferred.resolveWith )( that, args );\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\t\t// Only normal processors (resolve) catch and reject exceptions\n\t\t\t\t\t\t\t\tprocess = special ?\n\t\t\t\t\t\t\t\t\tmightThrow :\n\t\t\t\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tmightThrow();\n\t\t\t\t\t\t\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t\t\t\t\t\t\tif ( jQuery.Deferred.exceptionHook ) {\n\t\t\t\t\t\t\t\t\t\t\t\tjQuery.Deferred.exceptionHook( e,\n\t\t\t\t\t\t\t\t\t\t\t\t\tprocess.stackTrace );\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.4.1\n\t\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-61\n\t\t\t\t\t\t\t\t\t\t\t// Ignore post-resolution exceptions\n\t\t\t\t\t\t\t\t\t\t\tif ( depth + 1 >= maxDepth ) {\n\n\t\t\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\t\t\tif ( handler !== Thrower ) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\targs = [ e ];\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\tdeferred.rejectWith( that, args );\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.1\n\t\t\t\t\t\t\t// https://promisesaplus.com/#point-57\n\t\t\t\t\t\t\t// Re-resolve promises immediately to dodge false rejection from\n\t\t\t\t\t\t\t// subsequent errors\n\t\t\t\t\t\t\tif ( depth ) {\n\t\t\t\t\t\t\t\tprocess();\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// Call an optional hook to record the stack, in case of exception\n\t\t\t\t\t\t\t\t// since it's otherwise lost when execution goes async\n\t\t\t\t\t\t\t\tif ( jQuery.Deferred.getStackHook ) {\n\t\t\t\t\t\t\t\t\tprocess.stackTrace = jQuery.Deferred.getStackHook();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\twindow.setTimeout( process );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\n\t\t\t\t\t\t// progress_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 0 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onProgress ) ?\n\t\t\t\t\t\t\t\t\tonProgress :\n\t\t\t\t\t\t\t\t\tIdentity,\n\t\t\t\t\t\t\t\tnewDefer.notifyWith\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// fulfilled_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 1 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onFulfilled ) ?\n\t\t\t\t\t\t\t\t\tonFulfilled :\n\t\t\t\t\t\t\t\t\tIdentity\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// rejected_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 2 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onRejected ) ?\n\t\t\t\t\t\t\t\t\tonRejected :\n\t\t\t\t\t\t\t\t\tThrower\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 5 ];\n\n\t\t\t// promise.progress = list.add\n\t\t\t// promise.done = list.add\n\t\t\t// promise.fail = list.add\n\t\t\tpromise[ tuple[ 1 ] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(\n\t\t\t\t\tfunction() {\n\n\t\t\t\t\t\t// state = \"resolved\" (i.e., fulfilled)\n\t\t\t\t\t\t// state = \"rejected\"\n\t\t\t\t\t\tstate = stateString;\n\t\t\t\t\t},\n\n\t\t\t\t\t// rejected_callbacks.disable\n\t\t\t\t\t// fulfilled_callbacks.disable\n\t\t\t\t\ttuples[ 3 - i ][ 2 ].disable,\n\n\t\t\t\t\t// rejected_handlers.disable\n\t\t\t\t\t// fulfilled_handlers.disable\n\t\t\t\t\ttuples[ 3 - i ][ 3 ].disable,\n\n\t\t\t\t\t// progress_callbacks.lock\n\t\t\t\t\ttuples[ 0 ][ 2 ].lock,\n\n\t\t\t\t\t// progress_handlers.lock\n\t\t\t\t\ttuples[ 0 ][ 3 ].lock\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// progress_handlers.fire\n\t\t\t// fulfilled_handlers.fire\n\t\t\t// rejected_handlers.fire\n\t\t\tlist.add( tuple[ 3 ].fire );\n\n\t\t\t// deferred.notify = function() { deferred.notifyWith(...) }\n\t\t\t// deferred.resolve = function() { deferred.resolveWith(...) }\n\t\t\t// deferred.reject = function() { deferred.rejectWith(...) }\n\t\t\tdeferred[ tuple[ 0 ] ] = function() {\n\t\t\t\tdeferred[ tuple[ 0 ] + \"With\" ]( this === deferred ? undefined : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\n\t\t\t// deferred.notifyWith = list.fireWith\n\t\t\t// deferred.resolveWith = list.fireWith\n\t\t\t// deferred.rejectWith = list.fireWith\n\t\t\tdeferred[ tuple[ 0 ] + \"With\" ] = list.fireWith;\n\t\t} );\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( singleValue ) {\n\t\tvar\n\n\t\t\t// count of uncompleted subordinates\n\t\t\tremaining = arguments.length,\n\n\t\t\t// count of unprocessed arguments\n\t\t\ti = remaining,\n\n\t\t\t// subordinate fulfillment data\n\t\t\tresolveContexts = Array( i ),\n\t\t\tresolveValues = slice.call( arguments ),\n\n\t\t\t// the master Deferred\n\t\t\tmaster = jQuery.Deferred(),\n\n\t\t\t// subordinate callback factory\n\t\t\tupdateFunc = function( i ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tresolveContexts[ i ] = this;\n\t\t\t\t\tresolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( !( --remaining ) ) {\n\t\t\t\t\t\tmaster.resolveWith( resolveContexts, resolveValues );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\n\t\t// Single- and empty arguments are adopted like Promise.resolve\n\t\tif ( remaining <= 1 ) {\n\t\t\tadoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,\n\t\t\t\t!remaining );\n\n\t\t\t// Use .then() to unwrap secondary thenables (cf. gh-3000)\n\t\t\tif ( master.state() === \"pending\" ||\n\t\t\t\tisFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {\n\n\t\t\t\treturn master.then();\n\t\t\t}\n\t\t}\n\n\t\t// Multiple arguments are aggregated like Promise.all array elements\n\t\twhile ( i-- ) {\n\t\t\tadoptValue( resolveValues[ i ], updateFunc( i ), master.reject );\n\t\t}\n\n\t\treturn master.promise();\n\t}\n} );\n\n\n// These usually indicate a programmer mistake during development,\n// warn about them ASAP rather than swallowing them by default.\nvar rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;\n\njQuery.Deferred.exceptionHook = function( error, stack ) {\n\n\t// Support: IE 8 - 9 only\n\t// Console exists when dev tools are open, which can happen at any time\n\tif ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {\n\t\twindow.console.warn( \"jQuery.Deferred exception: \" + error.message, error.stack, stack );\n\t}\n};\n\n\n\n\njQuery.readyException = function( error ) {\n\twindow.setTimeout( function() {\n\t\tthrow error;\n\t} );\n};\n\n\n\n\n// The deferred used on DOM ready\nvar readyList = jQuery.Deferred();\n\njQuery.fn.ready = function( fn ) {\n\n\treadyList\n\t\t.then( fn )\n\n\t\t// Wrap jQuery.readyException in a function so that the lookup\n\t\t// happens at the time of error handling instead of callback\n\t\t// registration.\n\t\t.catch( function( error ) {\n\t\t\tjQuery.readyException( error );\n\t\t} );\n\n\treturn this;\n};\n\njQuery.extend( {\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\t}\n} );\n\njQuery.ready.then = readyList.then;\n\n// The ready event handler and self cleanup method\nfunction completed() {\n\tdocument.removeEventListener( \"DOMContentLoaded\", completed );\n\twindow.removeEventListener( \"load\", completed );\n\tjQuery.ready();\n}\n\n// Catch cases where $(document).ready() is called\n// after the browser event has already occurred.\n// Support: IE <=9 - 10 only\n// Older IE sometimes signals \"interactive\" too soon\nif ( document.readyState === \"complete\" ||\n\t( document.readyState !== \"loading\" && !document.documentElement.doScroll ) ) {\n\n\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\twindow.setTimeout( jQuery.ready );\n\n} else {\n\n\t// Use the handy event callback\n\tdocument.addEventListener( \"DOMContentLoaded\", completed );\n\n\t// A fallback to window.onload, that will always work\n\twindow.addEventListener( \"load\", completed );\n}\n\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nvar access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( toType( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\taccess( elems, fn, i, key[ i ], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( !isFunction( value ) ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn(\n\t\t\t\t\telems[ i ], key, raw ?\n\t\t\t\t\tvalue :\n\t\t\t\t\tvalue.call( elems[ i ], i, fn( elems[ i ], key ) )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( chainable ) {\n\t\treturn elems;\n\t}\n\n\t// Gets\n\tif ( bulk ) {\n\t\treturn fn.call( elems );\n\t}\n\n\treturn len ? fn( elems[ 0 ], key ) : emptyGet;\n};\n\n\n// Matches dashed string for camelizing\nvar rmsPrefix = /^-ms-/,\n\trdashAlpha = /-([a-z])/g;\n\n// Used by camelCase as callback to replace()\nfunction fcamelCase( all, letter ) {\n\treturn letter.toUpperCase();\n}\n\n// Convert dashed to camelCase; used by the css and data modules\n// Support: IE <=9 - 11, Edge 12 - 15\n// Microsoft forgot to hump their vendor prefix (#9572)\nfunction camelCase( string ) {\n\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n}\nvar acceptData = function( owner ) {\n\n\t// Accepts only:\n\t//  - Node\n\t//    - Node.ELEMENT_NODE\n\t//    - Node.DOCUMENT_NODE\n\t//  - Object\n\t//    - Any\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n};\n\n\n\n\nfunction Data() {\n\tthis.expando = jQuery.expando + Data.uid++;\n}\n\nData.uid = 1;\n\nData.prototype = {\n\n\tcache: function( owner ) {\n\n\t\t// Check if the owner object already has a cache\n\t\tvar value = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !value ) {\n\t\t\tvalue = {};\n\n\t\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t\t// but we should not, see #8335.\n\t\t\t// Always return an empty object.\n\t\t\tif ( acceptData( owner ) ) {\n\n\t\t\t\t// If it is a node unlikely to be stringify-ed or looped over\n\t\t\t\t// use plain assignment\n\t\t\t\tif ( owner.nodeType ) {\n\t\t\t\t\towner[ this.expando ] = value;\n\n\t\t\t\t// Otherwise secure it in a non-enumerable property\n\t\t\t\t// configurable must be true to allow the property to be\n\t\t\t\t// deleted when data is removed\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty( owner, this.expando, {\n\t\t\t\t\t\tvalue: value,\n\t\t\t\t\t\tconfigurable: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\tcache = this.cache( owner );\n\n\t\t// Handle: [ owner, key, value ] args\n\t\t// Always use camelCase key (gh-2257)\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ camelCase( data ) ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\n\t\t\t// Copy the properties one-by-one to the cache object\n\t\t\tfor ( prop in data ) {\n\t\t\t\tcache[ camelCase( prop ) ] = data[ prop ];\n\t\t\t}\n\t\t}\n\t\treturn cache;\n\t},\n\tget: function( owner, key ) {\n\t\treturn key === undefined ?\n\t\t\tthis.cache( owner ) :\n\n\t\t\t// Always use camelCase key (gh-2257)\n\t\t\towner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];\n\t},\n\taccess: function( owner, key, value ) {\n\n\t\t// In cases where either:\n\t\t//\n\t\t//   1. No key was specified\n\t\t//   2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t//   1. The entire cache object\n\t\t//   2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t( ( key && typeof key === \"string\" ) && value === undefined ) ) {\n\n\t\t\treturn this.get( owner, key );\n\t\t}\n\n\t\t// When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t//   1. An object of properties\n\t\t//   2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i,\n\t\t\tcache = owner[ this.expando ];\n\n\t\tif ( cache === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key !== undefined ) {\n\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( Array.isArray( key ) ) {\n\n\t\t\t\t// If key is an array of keys...\n\t\t\t\t// We always set camelCase keys, so remove that.\n\t\t\t\tkey = key.map( camelCase );\n\t\t\t} else {\n\t\t\t\tkey = camelCase( key );\n\n\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\tkey = key in cache ?\n\t\t\t\t\t[ key ] :\n\t\t\t\t\t( key.match( rnothtmlwhite ) || [] );\n\t\t\t}\n\n\t\t\ti = key.length;\n\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ key[ i ] ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if there's no more data\n\t\tif ( key === undefined || jQuery.isEmptyObject( cache ) ) {\n\n\t\t\t// Support: Chrome <=35 - 45\n\t\t\t// Webkit & Blink performance suffers when deleting properties\n\t\t\t// from DOM nodes, so set to undefined instead\n\t\t\t// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)\n\t\t\tif ( owner.nodeType ) {\n\t\t\t\towner[ this.expando ] = undefined;\n\t\t\t} else {\n\t\t\t\tdelete owner[ this.expando ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\tvar cache = owner[ this.expando ];\n\t\treturn cache !== undefined && !jQuery.isEmptyObject( cache );\n\t}\n};\nvar dataPriv = new Data();\n\nvar dataUser = new Data();\n\n\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /[A-Z]/g;\n\nfunction getData( data ) {\n\tif ( data === \"true\" ) {\n\t\treturn true;\n\t}\n\n\tif ( data === \"false\" ) {\n\t\treturn false;\n\t}\n\n\tif ( data === \"null\" ) {\n\t\treturn null;\n\t}\n\n\t// Only convert to a number if it doesn't change the string\n\tif ( data === +data + \"\" ) {\n\t\treturn +data;\n\t}\n\n\tif ( rbrace.test( data ) ) {\n\t\treturn JSON.parse( data );\n\t}\n\n\treturn data;\n}\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tname = \"data-\" + key.replace( rmultiDash, \"-$&\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = getData( data );\n\t\t\t} catch ( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tdataUser.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend( {\n\thasData: function( elem ) {\n\t\treturn dataUser.hasData( elem ) || dataPriv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn dataUser.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdataUser.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to dataPriv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn dataPriv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdataPriv.remove( elem, name );\n\t}\n} );\n\njQuery.fn.extend( {\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = dataUser.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !dataPriv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\n\t\t\t\t\t\t// Support: IE 11 only\n\t\t\t\t\t\t// The attrs elements can be null (#14894)\n\t\t\t\t\t\tif ( attrs[ i ] ) {\n\t\t\t\t\t\t\tname = attrs[ i ].name;\n\t\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\t\tname = camelCase( name.slice( 5 ) );\n\t\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdataPriv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tdataUser.set( this, key );\n\t\t\t} );\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data;\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// The key will always be camelCased in Data\n\t\t\t\tdata = dataUser.get( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tthis.each( function() {\n\n\t\t\t\t// We always store the camelCased key\n\t\t\t\tdataUser.set( this, key, value );\n\t\t\t} );\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each( function() {\n\t\t\tdataUser.remove( this, key );\n\t\t} );\n\t}\n} );\n\n\njQuery.extend( {\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = dataPriv.get( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || Array.isArray( data ) ) {\n\t\t\t\t\tqueue = dataPriv.access( elem, type, jQuery.makeArray( data ) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// Clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// Not public - generate a queueHooks object, or return the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn dataPriv.get( elem, key ) || dataPriv.access( elem, key, {\n\t\t\tempty: jQuery.Callbacks( \"once memory\" ).add( function() {\n\t\t\t\tdataPriv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t} )\n\t\t} );\n\t}\n} );\n\njQuery.fn.extend( {\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[ 0 ], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each( function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// Ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[ 0 ] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t} );\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t} );\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = dataPriv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n} );\nvar pnum = ( /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/ ).source;\n\nvar rcssNum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" );\n\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\nvar isHiddenWithinTree = function( elem, el ) {\n\n\t\t// isHiddenWithinTree might be called from jQuery#filter function;\n\t\t// in that case, element will be second argument\n\t\telem = el || elem;\n\n\t\t// Inline style trumps all\n\t\treturn elem.style.display === \"none\" ||\n\t\t\telem.style.display === \"\" &&\n\n\t\t\t// Otherwise, check computed style\n\t\t\t// Support: Firefox <=43 - 45\n\t\t\t// Disconnected elements can have computed display: none, so first confirm that elem is\n\t\t\t// in the document.\n\t\t\tjQuery.contains( elem.ownerDocument, elem ) &&\n\n\t\t\tjQuery.css( elem, \"display\" ) === \"none\";\n\t};\n\nvar swap = function( elem, options, callback, args ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.apply( elem, args || [] );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\n\n\nfunction adjustCSS( elem, prop, valueParts, tween ) {\n\tvar adjusted, scale,\n\t\tmaxIterations = 20,\n\t\tcurrentValue = tween ?\n\t\t\tfunction() {\n\t\t\t\treturn tween.cur();\n\t\t\t} :\n\t\t\tfunction() {\n\t\t\t\treturn jQuery.css( elem, prop, \"\" );\n\t\t\t},\n\t\tinitial = currentValue(),\n\t\tunit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n\t\t// Starting value computation is required for potential unit mismatches\n\t\tinitialInUnit = ( jQuery.cssNumber[ prop ] || unit !== \"px\" && +initial ) &&\n\t\t\trcssNum.exec( jQuery.css( elem, prop ) );\n\n\tif ( initialInUnit && initialInUnit[ 3 ] !== unit ) {\n\n\t\t// Support: Firefox <=54\n\t\t// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)\n\t\tinitial = initial / 2;\n\n\t\t// Trust units reported by jQuery.css\n\t\tunit = unit || initialInUnit[ 3 ];\n\n\t\t// Iteratively approximate from a nonzero starting point\n\t\tinitialInUnit = +initial || 1;\n\n\t\twhile ( maxIterations-- ) {\n\n\t\t\t// Evaluate and update our best guess (doubling guesses that zero out).\n\t\t\t// Finish if the scale equals or crosses 1 (making the old*new product non-positive).\n\t\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\t\t\tif ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {\n\t\t\t\tmaxIterations = 0;\n\t\t\t}\n\t\t\tinitialInUnit = initialInUnit / scale;\n\n\t\t}\n\n\t\tinitialInUnit = initialInUnit * 2;\n\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\n\t\t// Make sure we update the tween properties later on\n\t\tvalueParts = valueParts || [];\n\t}\n\n\tif ( valueParts ) {\n\t\tinitialInUnit = +initialInUnit || +initial || 0;\n\n\t\t// Apply relative offset (+=/-=) if specified\n\t\tadjusted = valueParts[ 1 ] ?\n\t\t\tinitialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :\n\t\t\t+valueParts[ 2 ];\n\t\tif ( tween ) {\n\t\t\ttween.unit = unit;\n\t\t\ttween.start = initialInUnit;\n\t\t\ttween.end = adjusted;\n\t\t}\n\t}\n\treturn adjusted;\n}\n\n\nvar defaultDisplayMap = {};\n\nfunction getDefaultDisplay( elem ) {\n\tvar temp,\n\t\tdoc = elem.ownerDocument,\n\t\tnodeName = elem.nodeName,\n\t\tdisplay = defaultDisplayMap[ nodeName ];\n\n\tif ( display ) {\n\t\treturn display;\n\t}\n\n\ttemp = doc.body.appendChild( doc.createElement( nodeName ) );\n\tdisplay = jQuery.css( temp, \"display\" );\n\n\ttemp.parentNode.removeChild( temp );\n\n\tif ( display === \"none\" ) {\n\t\tdisplay = \"block\";\n\t}\n\tdefaultDisplayMap[ nodeName ] = display;\n\n\treturn display;\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\t// Determine new display value for elements that need to change\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\n\t\t\t// Since we force visibility upon cascade-hidden elements, an immediate (and slow)\n\t\t\t// check is required in this first loop unless we have a nonempty display value (either\n\t\t\t// inline or about-to-be-restored)\n\t\t\tif ( display === \"none\" ) {\n\t\t\t\tvalues[ index ] = dataPriv.get( elem, \"display\" ) || null;\n\t\t\t\tif ( !values[ index ] ) {\n\t\t\t\t\telem.style.display = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( elem.style.display === \"\" && isHiddenWithinTree( elem ) ) {\n\t\t\t\tvalues[ index ] = getDefaultDisplay( elem );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( display !== \"none\" ) {\n\t\t\t\tvalues[ index ] = \"none\";\n\n\t\t\t\t// Remember what we're overwriting\n\t\t\t\tdataPriv.set( elem, \"display\", display );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of the elements in a second loop to avoid constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\tif ( values[ index ] != null ) {\n\t\t\telements[ index ].style.display = values[ index ];\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.fn.extend( {\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tif ( isHiddenWithinTree( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t} );\n\t}\n} );\nvar rcheckableType = ( /^(?:checkbox|radio)$/i );\n\nvar rtagName = ( /<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]+)/i );\n\nvar rscriptType = ( /^$|^module$|\\/(?:java|ecma)script/i );\n\n\n\n// We have to close these tags to support XHTML (#13200)\nvar wrapMap = {\n\n\t// Support: IE <=9 only\n\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\n\t// XHTML parsers do not magically insert elements in the\n\t// same way that tag soup parsers do. So we cannot shorten\n\t// this by omitting <tbody> or other required elements.\n\tthead: [ 1, \"<table>\", \"</table>\" ],\n\tcol: [ 2, \"<table><colgroup>\", \"</colgroup></table>\" ],\n\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t_default: [ 0, \"\", \"\" ]\n};\n\n// Support: IE <=9 only\nwrapMap.optgroup = wrapMap.option;\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n\nfunction getAll( context, tag ) {\n\n\t// Support: IE <=9 - 11 only\n\t// Use typeof to avoid zero-argument method invocation on host objects (#15151)\n\tvar ret;\n\n\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\tret = context.getElementsByTagName( tag || \"*\" );\n\n\t} else if ( typeof context.querySelectorAll !== \"undefined\" ) {\n\t\tret = context.querySelectorAll( tag || \"*\" );\n\n\t} else {\n\t\tret = [];\n\t}\n\n\tif ( tag === undefined || tag && nodeName( context, tag ) ) {\n\t\treturn jQuery.merge( [ context ], ret );\n\t}\n\n\treturn ret;\n}\n\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdataPriv.set(\n\t\t\telems[ i ],\n\t\t\t\"globalEval\",\n\t\t\t!refElements || dataPriv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\n\nvar rhtml = /<|&#?\\w+;/;\n\nfunction buildFragment( elems, context, scripts, selection, ignored ) {\n\tvar elem, tmp, tag, wrap, contains, j,\n\t\tfragment = context.createDocumentFragment(),\n\t\tnodes = [],\n\t\ti = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\telem = elems[ i ];\n\n\t\tif ( elem || elem === 0 ) {\n\n\t\t\t// Add nodes directly\n\t\t\tif ( toType( elem ) === \"object\" ) {\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t// Convert non-html into a text node\n\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t// Convert html into DOM nodes\n\t\t\t} else {\n\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement( \"div\" ) );\n\n\t\t\t\t// Deserialize a standard representation\n\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\t\t\t\ttmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];\n\n\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\tj = wrap[ 0 ];\n\t\t\t\twhile ( j-- ) {\n\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t}\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t// Remember the top-level container\n\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t// Ensure the created nodes are orphaned (#12392)\n\t\t\t\ttmp.textContent = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove wrapper from fragment\n\tfragment.textContent = \"\";\n\n\ti = 0;\n\twhile ( ( elem = nodes[ i++ ] ) ) {\n\n\t\t// Skip elements already in the context collection (trac-4087)\n\t\tif ( selection && jQuery.inArray( elem, selection ) > -1 ) {\n\t\t\tif ( ignored ) {\n\t\t\t\tignored.push( elem );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tcontains = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t// Append to fragment\n\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t// Preserve script evaluation history\n\t\tif ( contains ) {\n\t\t\tsetGlobalEval( tmp );\n\t\t}\n\n\t\t// Capture executables\n\t\tif ( scripts ) {\n\t\t\tj = 0;\n\t\t\twhile ( ( elem = tmp[ j++ ] ) ) {\n\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\tscripts.push( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fragment;\n}\n\n\n( function() {\n\tvar fragment = document.createDocumentFragment(),\n\t\tdiv = fragment.appendChild( document.createElement( \"div\" ) ),\n\t\tinput = document.createElement( \"input\" );\n\n\t// Support: Android 4.0 - 4.3 only\n\t// Check state lost if the name is set (#11217)\n\t// Support: Windows Web Apps (WWA)\n\t// `name` and `type` must use .setAttribute for WWA (#14901)\n\tinput.setAttribute( \"type\", \"radio\" );\n\tinput.setAttribute( \"checked\", \"checked\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tdiv.appendChild( input );\n\n\t// Support: Android <=4.1 only\n\t// Older WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE <=11 only\n\t// Make sure textarea (and checkbox) defaultValue is properly cloned\n\tdiv.innerHTML = \"<textarea>x</textarea>\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n} )();\nvar documentElement = document.documentElement;\n\n\n\nvar\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\n// Support: IE <=9 only\n// See #13393 for more info\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\nfunction on( elem, types, selector, data, fn, one ) {\n\tvar origFn, type;\n\n\t// Types can be a map of types/handlers\n\tif ( typeof types === \"object\" ) {\n\n\t\t// ( types-Object, selector, data )\n\t\tif ( typeof selector !== \"string\" ) {\n\n\t\t\t// ( types-Object, data )\n\t\t\tdata = data || selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tfor ( type in types ) {\n\t\t\ton( elem, type, selector, data, types[ type ], one );\n\t\t}\n\t\treturn elem;\n\t}\n\n\tif ( data == null && fn == null ) {\n\n\t\t// ( types, fn )\n\t\tfn = selector;\n\t\tdata = selector = undefined;\n\t} else if ( fn == null ) {\n\t\tif ( typeof selector === \"string\" ) {\n\n\t\t\t// ( types, selector, fn )\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t} else {\n\n\t\t\t// ( types, data, fn )\n\t\t\tfn = data;\n\t\t\tdata = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t}\n\tif ( fn === false ) {\n\t\tfn = returnFalse;\n\t} else if ( !fn ) {\n\t\treturn elem;\n\t}\n\n\tif ( one === 1 ) {\n\t\torigFn = fn;\n\t\tfn = function( event ) {\n\n\t\t\t// Can use an empty set, since event contains the info\n\t\t\tjQuery().off( event );\n\t\t\treturn origFn.apply( this, arguments );\n\t\t};\n\n\t\t// Use same guid so caller can remove using origFn\n\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t}\n\treturn elem.each( function() {\n\t\tjQuery.event.add( this, types, fn, data, selector );\n\t} );\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.get( elem );\n\n\t\t// Don't attach events to noData or text/comment nodes (but allow plain objects)\n\t\tif ( !elemData ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Ensure that invalid selectors throw exceptions at attach time\n\t\t// Evaluate against documentElement in case elem is a non-element node (e.g., document)\n\t\tif ( selector ) {\n\t\t\tjQuery.find.matchesSelector( documentElement, selector );\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !( events = elemData.events ) ) {\n\t\t\tevents = elemData.events = {};\n\t\t}\n\t\tif ( !( eventHandle = elemData.handle ) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend( {\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join( \".\" )\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !( handlers = events[ type ] ) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup ||\n\t\t\t\t\tspecial.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.hasData( elem ) && dataPriv.get( elem );\n\n\t\tif ( !elemData || !( events = elemData.events ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[ 2 ] &&\n\t\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector ||\n\t\t\t\t\t\tselector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown ||\n\t\t\t\t\tspecial.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove data and the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdataPriv.remove( elem, \"handle events\" );\n\t\t}\n\t},\n\n\tdispatch: function( nativeEvent ) {\n\n\t\t// Make a writable jQuery.Event from the native event object\n\t\tvar event = jQuery.event.fix( nativeEvent );\n\n\t\tvar i, j, ret, matched, handleObj, handlerQueue,\n\t\t\targs = new Array( arguments.length ),\n\t\t\thandlers = ( dataPriv.get( this, \"events\" ) || {} )[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[ 0 ] = event;\n\n\t\tfor ( i = 1; i < arguments.length; i++ ) {\n\t\t\targs[ i ] = arguments[ i ];\n\t\t}\n\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( ( handleObj = matched.handlers[ j++ ] ) &&\n\t\t\t\t!event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// Triggered event must either 1) have no namespace, or 2) have namespace(s)\n\t\t\t\t// a subset or equal to those in the bound event (both can have no namespace).\n\t\t\t\tif ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||\n\t\t\t\t\t\thandleObj.handler ).apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( ( event.result = ret ) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, handleObj, sel, matchedHandlers, matchedSelectors,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\tif ( delegateCount &&\n\n\t\t\t// Support: IE <=9\n\t\t\t// Black-hole SVG <use> instance trees (trac-13180)\n\t\t\tcur.nodeType &&\n\n\t\t\t// Support: Firefox <=42\n\t\t\t// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)\n\t\t\t// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click\n\t\t\t// Support: IE 11 only\n\t\t\t// ...but not arrow key \"clicks\" of radio inputs, which can have `button` -1 (gh-2343)\n\t\t\t!( event.type === \"click\" && event.button >= 1 ) ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't check non-elements (#13208)\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.nodeType === 1 && !( event.type === \"click\" && cur.disabled === true ) ) {\n\t\t\t\t\tmatchedHandlers = [];\n\t\t\t\t\tmatchedSelectors = {};\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatchedSelectors[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) > -1 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] ) {\n\t\t\t\t\t\t\tmatchedHandlers.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matchedHandlers.length ) {\n\t\t\t\t\t\thandlerQueue.push( { elem: cur, handlers: matchedHandlers } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tcur = this;\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\taddProp: function( name, hook ) {\n\t\tObject.defineProperty( jQuery.Event.prototype, name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\n\t\t\tget: isFunction( hook ) ?\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\t\treturn hook( this.originalEvent );\n\t\t\t\t\t}\n\t\t\t\t} :\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\t\treturn this.originalEvent[ name ];\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\tset: function( value ) {\n\t\t\t\tObject.defineProperty( this, name, {\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t\tvalue: value\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t},\n\n\tfix: function( originalEvent ) {\n\t\treturn originalEvent[ jQuery.expando ] ?\n\t\t\toriginalEvent :\n\t\t\tnew jQuery.Event( originalEvent );\n\t},\n\n\tspecial: {\n\t\tload: {\n\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tfocus: {\n\n\t\t\t// Fire native event if possible so blur/focus sequence is correct\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this !== safeActiveElement() && this.focus ) {\n\t\t\t\t\tthis.focus();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusin\"\n\t\t},\n\t\tblur: {\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this === safeActiveElement() && this.blur ) {\n\t\t\t\t\tthis.blur();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusout\"\n\t\t},\n\t\tclick: {\n\n\t\t\t// For checkbox, fire native event so checked state will be right\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this.type === \"checkbox\" && this.click && nodeName( this, \"input\" ) ) {\n\t\t\t\t\tthis.click();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, don't fire native .click() on links\n\t\t\t_default: function( event ) {\n\t\t\t\treturn nodeName( event.target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Support: Firefox 20+\n\t\t\t\t// Firefox doesn't alert if the returnValue field is not set.\n\t\t\t\tif ( event.result !== undefined && event.originalEvent ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n};\n\njQuery.removeEvent = function( elem, type, handle ) {\n\n\t// This \"if\" is needed for plain objects\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\n\t// Allow instantiation without the 'new' keyword\n\tif ( !( this instanceof jQuery.Event ) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ||\n\t\t\t\tsrc.defaultPrevented === undefined &&\n\n\t\t\t\t// Support: Android <=2.3 only\n\t\t\t\tsrc.returnValue === false ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t\t// Create target properties\n\t\t// Support: Safari <=6 - 7 only\n\t\t// Target should not be a text node (#504, #13143)\n\t\tthis.target = ( src.target && src.target.nodeType === 3 ) ?\n\t\t\tsrc.target.parentNode :\n\t\t\tsrc.target;\n\n\t\tthis.currentTarget = src.currentTarget;\n\t\tthis.relatedTarget = src.relatedTarget;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || Date.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tconstructor: jQuery.Event,\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\tisSimulated: false,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Includes all common event props including KeyEvent and MouseEvent specific props\njQuery.each( {\n\taltKey: true,\n\tbubbles: true,\n\tcancelable: true,\n\tchangedTouches: true,\n\tctrlKey: true,\n\tdetail: true,\n\teventPhase: true,\n\tmetaKey: true,\n\tpageX: true,\n\tpageY: true,\n\tshiftKey: true,\n\tview: true,\n\t\"char\": true,\n\tcharCode: true,\n\tkey: true,\n\tkeyCode: true,\n\tbutton: true,\n\tbuttons: true,\n\tclientX: true,\n\tclientY: true,\n\toffsetX: true,\n\toffsetY: true,\n\tpointerId: true,\n\tpointerType: true,\n\tscreenX: true,\n\tscreenY: true,\n\ttargetTouches: true,\n\ttoElement: true,\n\ttouches: true,\n\n\twhich: function( event ) {\n\t\tvar button = event.button;\n\n\t\t// Add which for key events\n\t\tif ( event.which == null && rkeyEvent.test( event.type ) ) {\n\t\t\treturn event.charCode != null ? event.charCode : event.keyCode;\n\t\t}\n\n\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\tif ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {\n\t\t\tif ( button & 1 ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tif ( button & 2 ) {\n\t\t\t\treturn 3;\n\t\t\t}\n\n\t\t\tif ( button & 4 ) {\n\t\t\t\treturn 2;\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn event.which;\n\t}\n}, jQuery.event.addProp );\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// so that event delegation works in jQuery.\n// Do the same for pointerenter/pointerleave and pointerover/pointerout\n//\n// Support: Safari 7 only\n// Safari sends mouseenter too often; see:\n// https://bugs.chromium.org/p/chromium/issues/detail?id=470258\n// for the description of the bug (it existed in older Chrome versions as well).\njQuery.each( {\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mouseenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n} );\n\njQuery.fn.extend( {\n\n\ton: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn );\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ?\n\t\t\t\t\thandleObj.origType + \".\" + handleObj.namespace :\n\t\t\t\t\thandleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t} );\n\t}\n} );\n\n\nvar\n\n\t/* eslint-disable max-len */\n\n\t// See https://github.com/eslint/eslint/issues/3229\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,\n\n\t/* eslint-enable */\n\n\t// Support: IE <=10 - 11, Edge 12 - 13 only\n\t// In IE/Edge using regex groups here causes severe slowdowns.\n\t// See https://connect.microsoft.com/IE/feedback/details/1736512/\n\trnoInnerhtml = /<script|<style|<link/i,\n\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;\n\n// Prefer a tbody over its parent table for containing new rows\nfunction manipulationTarget( elem, content ) {\n\tif ( nodeName( elem, \"table\" ) &&\n\t\tnodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ) {\n\n\t\treturn jQuery( elem ).children( \"tbody\" )[ 0 ] || elem;\n\t}\n\n\treturn elem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = ( elem.getAttribute( \"type\" ) !== null ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tif ( ( elem.type || \"\" ).slice( 0, 5 ) === \"true/\" ) {\n\t\telem.type = elem.type.slice( 5 );\n\t} else {\n\t\telem.removeAttribute( \"type\" );\n\t}\n\n\treturn elem;\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\tvar i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;\n\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// 1. Copy private data: events, handlers, etc.\n\tif ( dataPriv.hasData( src ) ) {\n\t\tpdataOld = dataPriv.access( src );\n\t\tpdataCur = dataPriv.set( dest, pdataOld );\n\t\tevents = pdataOld.events;\n\n\t\tif ( events ) {\n\t\t\tdelete pdataCur.handle;\n\t\t\tpdataCur.events = {};\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Copy user data\n\tif ( dataUser.hasData( src ) ) {\n\t\tudataOld = dataUser.access( src );\n\t\tudataCur = jQuery.extend( {}, udataOld );\n\n\t\tdataUser.set( dest, udataCur );\n\t}\n}\n\n// Fix IE bugs, see support tests\nfunction fixInput( src, dest ) {\n\tvar nodeName = dest.nodeName.toLowerCase();\n\n\t// Fails to persist the checked state of a cloned checkbox or radio button.\n\tif ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n\t\tdest.checked = src.checked;\n\n\t// Fails to return the selected option to the default selected state when cloning options\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\nfunction domManip( collection, args, callback, ignored ) {\n\n\t// Flatten any nested arrays\n\targs = concat.apply( [], args );\n\n\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\ti = 0,\n\t\tl = collection.length,\n\t\tiNoClone = l - 1,\n\t\tvalue = args[ 0 ],\n\t\tvalueIsFunction = isFunction( value );\n\n\t// We can't cloneNode fragments that contain checked, in WebKit\n\tif ( valueIsFunction ||\n\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\treturn collection.each( function( index ) {\n\t\t\tvar self = collection.eq( index );\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\t}\n\t\t\tdomManip( self, args, callback, ignored );\n\t\t} );\n\t}\n\n\tif ( l ) {\n\t\tfragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );\n\t\tfirst = fragment.firstChild;\n\n\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\tfragment = first;\n\t\t}\n\n\t\t// Require either new content or an interest in ignored elements to invoke the callback\n\t\tif ( first || ignored ) {\n\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\thasScripts = scripts.length;\n\n\t\t\t// Use the original fragment for the last item\n\t\t\t// instead of the first because it can end up\n\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tnode = fragment;\n\n\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\tif ( hasScripts ) {\n\n\t\t\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcallback.call( collection[ i ], node, i );\n\t\t\t}\n\n\t\t\tif ( hasScripts ) {\n\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t// Reenable scripts\n\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t!dataPriv.access( node, \"globalEval\" ) &&\n\t\t\t\t\t\tjQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\tif ( node.src && ( node.type || \"\" ).toLowerCase()  !== \"module\" ) {\n\n\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\tif ( jQuery._evalUrl ) {\n\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tDOMEval( node.textContent.replace( rcleanScript, \"\" ), doc, node );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn collection;\n}\n\nfunction remove( elem, selector, keepData ) {\n\tvar node,\n\t\tnodes = selector ? jQuery.filter( selector, elem ) : elem,\n\t\ti = 0;\n\n\tfor ( ; ( node = nodes[ i ] ) != null; i++ ) {\n\t\tif ( !keepData && node.nodeType === 1 ) {\n\t\t\tjQuery.cleanData( getAll( node ) );\n\t\t}\n\n\t\tif ( node.parentNode ) {\n\t\t\tif ( keepData && jQuery.contains( node.ownerDocument, node ) ) {\n\t\t\t\tsetGlobalEval( getAll( node, \"script\" ) );\n\t\t\t}\n\t\t\tnode.parentNode.removeChild( node );\n\t\t}\n\t}\n\n\treturn elem;\n}\n\njQuery.extend( {\n\thtmlPrefilter: function( html ) {\n\t\treturn html.replace( rxhtmlTag, \"<$1></$2>\" );\n\t},\n\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar i, l, srcElements, destElements,\n\t\t\tclone = elem.cloneNode( true ),\n\t\t\tinPage = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t// Fix IE cloning issues\n\t\tif ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n\t\t\t\t!jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\tfixInput( srcElements[ i ], destElements[ i ] );\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[ i ], destElements[ i ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {\n\t\t\tif ( acceptData( elem ) ) {\n\t\t\t\tif ( ( data = elem[ dataPriv.expando ] ) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataPriv.expando ] = undefined;\n\t\t\t\t}\n\t\t\t\tif ( elem[ dataUser.expando ] ) {\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataUser.expando ] = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} );\n\njQuery.fn.extend( {\n\tdetach: function( selector ) {\n\t\treturn remove( this, selector, true );\n\t},\n\n\tremove: function( selector ) {\n\t\treturn remove( this, selector );\n\t},\n\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each( function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t} );\n\t},\n\n\tprepend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t} );\n\t},\n\n\tbefore: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t} );\n\t},\n\n\tafter: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t} );\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = this[ i ] ) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t} );\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = jQuery.htmlPrefilter( value );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch ( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar ignored = [];\n\n\t\t// Make the changes, replacing each non-ignored context element with the new content\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tvar parent = this.parentNode;\n\n\t\t\tif ( jQuery.inArray( this, ignored ) < 0 ) {\n\t\t\t\tjQuery.cleanData( getAll( this ) );\n\t\t\t\tif ( parent ) {\n\t\t\t\t\tparent.replaceChild( elem, this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Force callback invocation\n\t\t}, ignored );\n\t}\n} );\n\njQuery.each( {\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\n\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t// .get() because push.apply(_, arraylike) throws on ancient WebKit\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n} );\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar getStyles = function( elem ) {\n\n\t\t// Support: IE <=11 only, Firefox <=30 (#15098, #14150)\n\t\t// IE throws on elements created in popups\n\t\t// FF meanwhile throws on frame elements through \"defaultView.getComputedStyle\"\n\t\tvar view = elem.ownerDocument.defaultView;\n\n\t\tif ( !view || !view.opener ) {\n\t\t\tview = window;\n\t\t}\n\n\t\treturn view.getComputedStyle( elem );\n\t};\n\nvar rboxStyle = new RegExp( cssExpand.join( \"|\" ), \"i\" );\n\n\n\n( function() {\n\n\t// Executing both pixelPosition & boxSizingReliable tests require only one layout\n\t// so they're executed at the same time to save the second computation.\n\tfunction computeStyleTests() {\n\n\t\t// This is a singleton, we need to execute it only once\n\t\tif ( !div ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcontainer.style.cssText = \"position:absolute;left:-11111px;width:60px;\" +\n\t\t\t\"margin-top:1px;padding:0;border:0\";\n\t\tdiv.style.cssText =\n\t\t\t\"position:relative;display:block;box-sizing:border-box;overflow:scroll;\" +\n\t\t\t\"margin:auto;border:1px;padding:1px;\" +\n\t\t\t\"width:60%;top:1%\";\n\t\tdocumentElement.appendChild( container ).appendChild( div );\n\n\t\tvar divStyle = window.getComputedStyle( div );\n\t\tpixelPositionVal = divStyle.top !== \"1%\";\n\n\t\t// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44\n\t\treliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;\n\n\t\t// Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3\n\t\t// Some styles come back with percentage values, even though they shouldn't\n\t\tdiv.style.right = \"60%\";\n\t\tpixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;\n\n\t\t// Support: IE 9 - 11 only\n\t\t// Detect misreporting of content dimensions for box-sizing:border-box elements\n\t\tboxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;\n\n\t\t// Support: IE 9 only\n\t\t// Detect overflow:scroll screwiness (gh-3699)\n\t\tdiv.style.position = \"absolute\";\n\t\tscrollboxSizeVal = div.offsetWidth === 36 || \"absolute\";\n\n\t\tdocumentElement.removeChild( container );\n\n\t\t// Nullify the div so it wouldn't be stored in the memory and\n\t\t// it will also be a sign that checks already performed\n\t\tdiv = null;\n\t}\n\n\tfunction roundPixelMeasures( measure ) {\n\t\treturn Math.round( parseFloat( measure ) );\n\t}\n\n\tvar pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,\n\t\treliableMarginLeftVal,\n\t\tcontainer = document.createElement( \"div\" ),\n\t\tdiv = document.createElement( \"div\" );\n\n\t// Finish early in limited (non-browser) environments\n\tif ( !div.style ) {\n\t\treturn;\n\t}\n\n\t// Support: IE <=9 - 11 only\n\t// Style of cloned element affects source element cloned (#8908)\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\tjQuery.extend( support, {\n\t\tboxSizingReliable: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn boxSizingReliableVal;\n\t\t},\n\t\tpixelBoxStyles: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelBoxStylesVal;\n\t\t},\n\t\tpixelPosition: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelPositionVal;\n\t\t},\n\t\treliableMarginLeft: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn reliableMarginLeftVal;\n\t\t},\n\t\tscrollboxSize: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn scrollboxSizeVal;\n\t\t}\n\t} );\n} )();\n\n\nfunction curCSS( elem, name, computed ) {\n\tvar width, minWidth, maxWidth, ret,\n\n\t\t// Support: Firefox 51+\n\t\t// Retrieving style before computed somehow\n\t\t// fixes an issue with getting wrong values\n\t\t// on detached elements\n\t\tstyle = elem.style;\n\n\tcomputed = computed || getStyles( elem );\n\n\t// getPropertyValue is needed for:\n\t//   .css('filter') (IE 9 only, #12537)\n\t//   .css('--customProperty) (#3144)\n\tif ( computed ) {\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\n\t\tif ( ret === \"\" && !jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// Android Browser returns percentage for some values,\n\t\t// but width seems to be reliably pixels.\n\t\t// This is against the CSSOM draft spec:\n\t\t// https://drafts.csswg.org/cssom/#resolved-values\n\t\tif ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\twidth = style.width;\n\t\t\tminWidth = style.minWidth;\n\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\tret = computed.width;\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.width = width;\n\t\t\tstyle.minWidth = minWidth;\n\t\t\tstyle.maxWidth = maxWidth;\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\n\t\t// Support: IE <=9 - 11 only\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tif ( conditionFn() ) {\n\n\t\t\t\t// Hook not needed (or it's not possible to use it due\n\t\t\t\t// to missing dependency), remove it.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\t\t\treturn ( this.get = hookFn ).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\nvar\n\n\t// Swappable if display is none or starts with table\n\t// except \"table\", \"table-cell\", or \"table-caption\"\n\t// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trcustomProp = /^--/,\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t},\n\n\tcssPrefixes = [ \"Webkit\", \"Moz\", \"ms\" ],\n\temptyStyle = document.createElement( \"div\" ).style;\n\n// Return a css property mapped to a potentially vendor prefixed property\nfunction vendorPropName( name ) {\n\n\t// Shortcut for names that are not vendor prefixed\n\tif ( name in emptyStyle ) {\n\t\treturn name;\n\t}\n\n\t// Check for vendor prefixed names\n\tvar capName = name[ 0 ].toUpperCase() + name.slice( 1 ),\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in emptyStyle ) {\n\t\t\treturn name;\n\t\t}\n\t}\n}\n\n// Return a property mapped along what jQuery.cssProps suggests or to\n// a vendor prefixed property.\nfunction finalPropName( name ) {\n\tvar ret = jQuery.cssProps[ name ];\n\tif ( !ret ) {\n\t\tret = jQuery.cssProps[ name ] = vendorPropName( name ) || name;\n\t}\n\treturn ret;\n}\n\nfunction setPositiveNumber( elem, value, subtract ) {\n\n\t// Any relative (+/-) values have already been\n\t// normalized at this point\n\tvar matches = rcssNum.exec( value );\n\treturn matches ?\n\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {\n\tvar i = dimension === \"width\" ? 1 : 0,\n\t\textra = 0,\n\t\tdelta = 0;\n\n\t// Adjustment may not be necessary\n\tif ( box === ( isBorderBox ? \"border\" : \"content\" ) ) {\n\t\treturn 0;\n\t}\n\n\tfor ( ; i < 4; i += 2 ) {\n\n\t\t// Both box models exclude margin\n\t\tif ( box === \"margin\" ) {\n\t\t\tdelta += jQuery.css( elem, box + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\t// If we get here with a content-box, we're seeking \"padding\" or \"border\" or \"margin\"\n\t\tif ( !isBorderBox ) {\n\n\t\t\t// Add padding\n\t\t\tdelta += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// For \"border\" or \"margin\", add border\n\t\t\tif ( box !== \"padding\" ) {\n\t\t\t\tdelta += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\n\t\t\t// But still keep track of it otherwise\n\t\t\t} else {\n\t\t\t\textra += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\n\t\t// If we get here with a border-box (content + padding + border), we're seeking \"content\" or\n\t\t// \"padding\" or \"margin\"\n\t\t} else {\n\n\t\t\t// For \"content\", subtract padding\n\t\t\tif ( box === \"content\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// For \"content\" or \"padding\", subtract border\n\t\t\tif ( box !== \"margin\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Account for positive content-box scroll gutter when requested by providing computedVal\n\tif ( !isBorderBox && computedVal >= 0 ) {\n\n\t\t// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border\n\t\t// Assuming integer scroll gutter, subtract the rest and round down\n\t\tdelta += Math.max( 0, Math.ceil(\n\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\tcomputedVal -\n\t\t\tdelta -\n\t\t\textra -\n\t\t\t0.5\n\t\t) );\n\t}\n\n\treturn delta;\n}\n\nfunction getWidthOrHeight( elem, dimension, extra ) {\n\n\t// Start with computed style\n\tvar styles = getStyles( elem ),\n\t\tval = curCSS( elem, dimension, styles ),\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\tvalueIsBorderBox = isBorderBox;\n\n\t// Support: Firefox <=54\n\t// Return a confounding non-pixel value or feign ignorance, as appropriate.\n\tif ( rnumnonpx.test( val ) ) {\n\t\tif ( !extra ) {\n\t\t\treturn val;\n\t\t}\n\t\tval = \"auto\";\n\t}\n\n\t// Check for style in case a browser which returns unreliable values\n\t// for getComputedStyle silently falls back to the reliable elem.style\n\tvalueIsBorderBox = valueIsBorderBox &&\n\t\t( support.boxSizingReliable() || val === elem.style[ dimension ] );\n\n\t// Fall back to offsetWidth/offsetHeight when value is \"auto\"\n\t// This happens for inline elements with no explicit setting (gh-3571)\n\t// Support: Android <=4.1 - 4.3 only\n\t// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)\n\tif ( val === \"auto\" ||\n\t\t!parseFloat( val ) && jQuery.css( elem, \"display\", false, styles ) === \"inline\" ) {\n\n\t\tval = elem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ];\n\n\t\t// offsetWidth/offsetHeight provide border-box values\n\t\tvalueIsBorderBox = true;\n\t}\n\n\t// Normalize \"\" and auto\n\tval = parseFloat( val ) || 0;\n\n\t// Adjust for the element's box model\n\treturn ( val +\n\t\tboxModelAdjustment(\n\t\t\telem,\n\t\t\tdimension,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles,\n\n\t\t\t// Provide the current computed size to request scroll gutter calculation (gh-3589)\n\t\t\tval\n\t\t)\n\t) + \"px\";\n}\n\njQuery.extend( {\n\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"animationIterationCount\": true,\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"flexGrow\": true,\n\t\t\"flexShrink\": true,\n\t\t\"fontWeight\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name ),\n\t\t\tstyle = elem.style;\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to query the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Convert \"+=\" or \"-=\" to relative numbers (#7345)\n\t\t\tif ( type === \"string\" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {\n\t\t\t\tvalue = adjustCSS( elem, name, ret );\n\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (#7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add the unit (except for certain CSS properties)\n\t\t\tif ( type === \"number\" ) {\n\t\t\t\tvalue += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? \"\" : \"px\" );\n\t\t\t}\n\n\t\t\t// background-* props affect original clone's values\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !( \"set\" in hooks ) ||\n\t\t\t\t( value = hooks.set( elem, value, extra ) ) !== undefined ) {\n\n\t\t\t\tif ( isCustomProp ) {\n\t\t\t\t\tstyle.setProperty( name, value );\n\t\t\t\t} else {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks &&\n\t\t\t\t( ret = hooks.get( elem, false, extra ) ) !== undefined ) {\n\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name );\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to modify the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || isFinite( num ) ? num || 0 : val;\n\t\t}\n\n\t\treturn val;\n\t}\n} );\n\njQuery.each( [ \"height\", \"width\" ], function( i, dimension ) {\n\tjQuery.cssHooks[ dimension ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Certain elements can have dimension info if we invisibly show them\n\t\t\t\t// but it must have a current display style that would benefit\n\t\t\t\treturn rdisplayswap.test( jQuery.css( elem, \"display\" ) ) &&\n\n\t\t\t\t\t// Support: Safari 8+\n\t\t\t\t\t// Table columns in Safari have non-zero offsetWidth & zero\n\t\t\t\t\t// getBoundingClientRect().width unless display is changed.\n\t\t\t\t\t// Support: IE <=11 only\n\t\t\t\t\t// Running getBoundingClientRect on a disconnected node\n\t\t\t\t\t// in IE throws an error.\n\t\t\t\t\t( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?\n\t\t\t\t\t\tswap( elem, cssShow, function() {\n\t\t\t\t\t\t\treturn getWidthOrHeight( elem, dimension, extra );\n\t\t\t\t\t\t} ) :\n\t\t\t\t\t\tgetWidthOrHeight( elem, dimension, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar matches,\n\t\t\t\tstyles = getStyles( elem ),\n\t\t\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\tsubtract = extra && boxModelAdjustment(\n\t\t\t\t\telem,\n\t\t\t\t\tdimension,\n\t\t\t\t\textra,\n\t\t\t\t\tisBorderBox,\n\t\t\t\t\tstyles\n\t\t\t\t);\n\n\t\t\t// Account for unreliable border-box dimensions by comparing offset* to computed and\n\t\t\t// faking a content-box to get border and padding (gh-3699)\n\t\t\tif ( isBorderBox && support.scrollboxSize() === styles.position ) {\n\t\t\t\tsubtract -= Math.ceil(\n\t\t\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\t\t\tparseFloat( styles[ dimension ] ) -\n\t\t\t\t\tboxModelAdjustment( elem, dimension, \"border\", false, styles ) -\n\t\t\t\t\t0.5\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Convert to pixels if value adjustment is needed\n\t\t\tif ( subtract && ( matches = rcssNum.exec( value ) ) &&\n\t\t\t\t( matches[ 3 ] || \"px\" ) !== \"px\" ) {\n\n\t\t\t\telem.style[ dimension ] = value;\n\t\t\t\tvalue = jQuery.css( elem, dimension );\n\t\t\t}\n\n\t\t\treturn setPositiveNumber( elem, value, subtract );\n\t\t}\n\t};\n} );\n\njQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn ( parseFloat( curCSS( elem, \"marginLeft\" ) ) ||\n\t\t\t\telem.getBoundingClientRect().left -\n\t\t\t\t\tswap( elem, { marginLeft: 0 }, function() {\n\t\t\t\t\t\treturn elem.getBoundingClientRect().left;\n\t\t\t\t\t} )\n\t\t\t\t) + \"px\";\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each( {\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split( \" \" ) : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( prefix !== \"margin\" ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n} );\n\njQuery.fn.extend( {\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( Array.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t}\n} );\n\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || jQuery.easing._default;\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\t// Use a property on the element directly when it is not a DOM element,\n\t\t\t// or when there is no matching style property that exists.\n\t\t\tif ( tween.elem.nodeType !== 1 ||\n\t\t\t\ttween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// Passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails.\n\t\t\t// Simple values such as \"10px\" are parsed to Float;\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as-is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\n\t\t\t// Use step hook for back compat.\n\t\t\t// Use cssHook if its there.\n\t\t\t// Use .style if available and use plain properties where available.\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.nodeType === 1 &&\n\t\t\t\t( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||\n\t\t\t\t\tjQuery.cssHooks[ tween.prop ] ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Support: IE <=9 only\n// Panic based approach to setting things on disconnected nodes\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t},\n\t_default: \"swing\"\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back compat <1.8 extension point\njQuery.fx.step = {};\n\n\n\n\nvar\n\tfxNow, inProgress,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trrun = /queueHooks$/;\n\nfunction schedule() {\n\tif ( inProgress ) {\n\t\tif ( document.hidden === false && window.requestAnimationFrame ) {\n\t\t\twindow.requestAnimationFrame( schedule );\n\t\t} else {\n\t\t\twindow.setTimeout( schedule, jQuery.fx.interval );\n\t\t}\n\n\t\tjQuery.fx.tick();\n\t}\n}\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\twindow.setTimeout( function() {\n\t\tfxNow = undefined;\n\t} );\n\treturn ( fxNow = Date.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// If we include width, step value is 1 to do all cssExpand values,\n\t// otherwise step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {\n\n\t\t\t// We're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\tvar prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,\n\t\tisBox = \"width\" in props || \"height\" in props,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHiddenWithinTree( elem ),\n\t\tdataShow = dataPriv.get( elem, \"fxshow\" );\n\n\t// Queue-skipping animations hijack the fx hooks\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always( function() {\n\n\t\t\t// Ensure the complete handler is called before this completes\n\t\t\tanim.always( function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t// Detect show/hide animations\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.test( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// Pretend to be hidden if this is a \"show\" and\n\t\t\t\t// there is still data from a stopped show/hide\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\n\t\t\t\t// Ignore all other no-op show/hide data\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\t\t}\n\t}\n\n\t// Bail out if this is a no-op like .hide().hide()\n\tpropTween = !jQuery.isEmptyObject( props );\n\tif ( !propTween && jQuery.isEmptyObject( orig ) ) {\n\t\treturn;\n\t}\n\n\t// Restrict \"overflow\" and \"display\" styles during box animations\n\tif ( isBox && elem.nodeType === 1 ) {\n\n\t\t// Support: IE <=9 - 11, Edge 12 - 15\n\t\t// Record all 3 overflow attributes because IE does not infer the shorthand\n\t\t// from identically-valued overflowX and overflowY and Edge just mirrors\n\t\t// the overflowX value there.\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Identify a display type, preferring old show/hide data over the CSS cascade\n\t\trestoreDisplay = dataShow && dataShow.display;\n\t\tif ( restoreDisplay == null ) {\n\t\t\trestoreDisplay = dataPriv.get( elem, \"display\" );\n\t\t}\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\tif ( display === \"none\" ) {\n\t\t\tif ( restoreDisplay ) {\n\t\t\t\tdisplay = restoreDisplay;\n\t\t\t} else {\n\n\t\t\t\t// Get nonempty value(s) by temporarily forcing visibility\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t\trestoreDisplay = elem.style.display || restoreDisplay;\n\t\t\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\t\t\tshowHide( [ elem ] );\n\t\t\t}\n\t\t}\n\n\t\t// Animate inline elements as inline-block\n\t\tif ( display === \"inline\" || display === \"inline-block\" && restoreDisplay != null ) {\n\t\t\tif ( jQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\t\t// Restore the original display value at the end of pure show/hide animations\n\t\t\t\tif ( !propTween ) {\n\t\t\t\t\tanim.done( function() {\n\t\t\t\t\t\tstyle.display = restoreDisplay;\n\t\t\t\t\t} );\n\t\t\t\t\tif ( restoreDisplay == null ) {\n\t\t\t\t\t\tdisplay = style.display;\n\t\t\t\t\t\trestoreDisplay = display === \"none\" ? \"\" : display;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstyle.display = \"inline-block\";\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always( function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t} );\n\t}\n\n\t// Implement show/hide animations\n\tpropTween = false;\n\tfor ( prop in orig ) {\n\n\t\t// General show/hide setup for this element animation\n\t\tif ( !propTween ) {\n\t\t\tif ( dataShow ) {\n\t\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\t\thidden = dataShow.hidden;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdataShow = dataPriv.access( elem, \"fxshow\", { display: restoreDisplay } );\n\t\t\t}\n\n\t\t\t// Store hidden/visible for toggle so `.stop().toggle()` \"reverses\"\n\t\t\tif ( toggle ) {\n\t\t\t\tdataShow.hidden = !hidden;\n\t\t\t}\n\n\t\t\t// Show elements before animating them\n\t\t\tif ( hidden ) {\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t}\n\n\t\t\t/* eslint-disable no-loop-func */\n\n\t\t\tanim.done( function() {\n\n\t\t\t/* eslint-enable no-loop-func */\n\n\t\t\t\t// The final step of a \"hide\" animation is actually hiding the element\n\t\t\t\tif ( !hidden ) {\n\t\t\t\t\tshowHide( [ elem ] );\n\t\t\t\t}\n\t\t\t\tdataPriv.remove( elem, \"fxshow\" );\n\t\t\t\tfor ( prop in orig ) {\n\t\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\t// Per-property setup\n\t\tpropTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\t\tif ( !( prop in dataShow ) ) {\n\t\t\tdataShow[ prop ] = propTween.start;\n\t\t\tif ( hidden ) {\n\t\t\t\tpropTween.end = propTween.start;\n\t\t\t\tpropTween.start = 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( Array.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// Not quite $.extend, this won't overwrite existing keys.\n\t\t\t// Reusing 'index' because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = Animation.prefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\n\t\t\t// Don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t} ),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\n\t\t\t\t// Support: Android 2.3 only\n\t\t\t\t// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ] );\n\n\t\t\t// If there's more to do, yield\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t}\n\n\t\t\t// If this was an empty animation, synthesize a final progress notification\n\t\t\tif ( !length ) {\n\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t}\n\n\t\t\t// Resolve the animation and report its conclusion\n\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\treturn false;\n\t\t},\n\t\tanimation = deferred.promise( {\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, {\n\t\t\t\tspecialEasing: {},\n\t\t\t\teasing: jQuery.easing._default\n\t\t\t}, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\n\t\t\t\t\t// If we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// Resolve when we played the last frame; otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t} ),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length; index++ ) {\n\t\tresult = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\tif ( isFunction( result.stop ) ) {\n\t\t\t\tjQuery._queueHooks( animation.elem, animation.opts.queue ).stop =\n\t\t\t\t\tresult.stop.bind( result );\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\t// Attach callbacks from options\n\tanimation\n\t\t.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t} )\n\t);\n\n\treturn animation;\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweeners: {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value );\n\t\t\tadjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );\n\t\t\treturn tween;\n\t\t} ]\n\t},\n\n\ttweener: function( props, callback ) {\n\t\tif ( isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.match( rnothtmlwhite );\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\tAnimation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];\n\t\t\tAnimation.tweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilters: [ defaultPrefilter ],\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tAnimation.prefilters.unshift( callback );\n\t\t} else {\n\t\t\tAnimation.prefilters.push( callback );\n\t\t}\n\t}\n} );\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tisFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !isFunction( easing ) && easing\n\t};\n\n\t// Go to the end state if fx are off\n\tif ( jQuery.fx.off ) {\n\t\topt.duration = 0;\n\n\t} else {\n\t\tif ( typeof opt.duration !== \"number\" ) {\n\t\t\tif ( opt.duration in jQuery.fx.speeds ) {\n\t\t\t\topt.duration = jQuery.fx.speeds[ opt.duration ];\n\n\t\t\t} else {\n\t\t\t\topt.duration = jQuery.fx.speeds._default;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend( {\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// Show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHiddenWithinTree ).css( \"opacity\", 0 ).show()\n\n\t\t\t// Animate to the value specified\n\t\t\t.end().animate( { opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || dataPriv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\t\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue && type !== false ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = dataPriv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this &&\n\t\t\t\t\t( type == null || timers[ index ].queue === type ) ) {\n\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Start the next in the queue if the last step wasn't forced.\n\t\t\t// Timers currently will call their complete callbacks, which\n\t\t\t// will dequeue but only if they were gotoEnd.\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t} );\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tvar index,\n\t\t\t\tdata = dataPriv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// Enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// Empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// Look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t} );\n\t}\n} );\n\njQuery.each( [ \"toggle\", \"show\", \"hide\" ], function( i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n} );\n\n// Generate shortcuts for custom animations\njQuery.each( {\n\tslideDown: genFx( \"show\" ),\n\tslideUp: genFx( \"hide\" ),\n\tslideToggle: genFx( \"toggle\" ),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n} );\n\njQuery.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = Date.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\n\t\t// Run the timer and safely remove it when done (allowing for external removal)\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tjQuery.fx.start();\n};\n\njQuery.fx.interval = 13;\njQuery.fx.start = function() {\n\tif ( inProgress ) {\n\t\treturn;\n\t}\n\n\tinProgress = true;\n\tschedule();\n};\n\njQuery.fx.stop = function() {\n\tinProgress = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\n\t// Default speed\n\t_default: 400\n};\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = window.setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\twindow.clearTimeout( timeout );\n\t\t};\n\t} );\n};\n\n\n( function() {\n\tvar input = document.createElement( \"input\" ),\n\t\tselect = document.createElement( \"select\" ),\n\t\topt = select.appendChild( document.createElement( \"option\" ) );\n\n\tinput.type = \"checkbox\";\n\n\t// Support: Android <=4.3 only\n\t// Default value for a checkbox should be \"on\"\n\tsupport.checkOn = input.value !== \"\";\n\n\t// Support: IE <=11 only\n\t// Must access selectedIndex to make default options select\n\tsupport.optSelected = opt.selected;\n\n\t// Support: IE <=11 only\n\t// An input loses its value after becoming a radio\n\tinput = document.createElement( \"input\" );\n\tinput.value = \"t\";\n\tinput.type = \"radio\";\n\tsupport.radioValue = input.value === \"t\";\n} )();\n\n\nvar boolHook,\n\tattrHandle = jQuery.expr.attrHandle;\n\njQuery.fn.extend( {\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set attributes on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// Attribute hooks are determined by the lowercase version\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\thooks = jQuery.attrHooks[ name.toLowerCase() ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\treturn value;\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tret = jQuery.find.attr( elem, name );\n\n\t\t// Non-existent attributes return null, we normalize to undefined\n\t\treturn ret == null ? undefined : ret;\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !support.radioValue && value === \"radio\" &&\n\t\t\t\t\tnodeName( elem, \"input\" ) ) {\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name,\n\t\t\ti = 0,\n\n\t\t\t// Attribute names can contain non-HTML whitespace characters\n\t\t\t// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2\n\t\t\tattrNames = value && value.match( rnothtmlwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( ( name = attrNames[ i++ ] ) ) {\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Hooks for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\telem.setAttribute( name, name );\n\t\t}\n\t\treturn name;\n\t}\n};\n\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( i, name ) {\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = function( elem, name, isXML ) {\n\t\tvar ret, handle,\n\t\t\tlowercaseName = name.toLowerCase();\n\n\t\tif ( !isXML ) {\n\n\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\thandle = attrHandle[ lowercaseName ];\n\t\t\tattrHandle[ lowercaseName ] = ret;\n\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\tlowercaseName :\n\t\t\t\tnull;\n\t\t\tattrHandle[ lowercaseName ] = handle;\n\t\t}\n\t\treturn ret;\n\t};\n} );\n\n\n\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i,\n\trclickable = /^(?:a|area)$/i;\n\njQuery.fn.extend( {\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\treturn ( elem[ name ] = value );\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\treturn elem[ name ];\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\t// Support: IE <=9 - 11 only\n\t\t\t\t// elem.tabIndex doesn't always return the\n\t\t\t\t// correct value when it hasn't been explicitly set\n\t\t\t\t// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\t// Use proper attribute retrieval(#12072)\n\t\t\t\tvar tabindex = jQuery.find.attr( elem, \"tabindex\" );\n\n\t\t\t\tif ( tabindex ) {\n\t\t\t\t\treturn parseInt( tabindex, 10 );\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\trfocusable.test( elem.nodeName ) ||\n\t\t\t\t\trclickable.test( elem.nodeName ) &&\n\t\t\t\t\telem.href\n\t\t\t\t) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t}\n} );\n\n// Support: IE <=11 only\n// Accessing the selectedIndex property\n// forces the browser to respect setting selected\n// on the option\n// The getter ensures a default option is selected\n// when in an optgroup\n// eslint rule \"no-unused-expressions\" is disabled for this code\n// since it considers such accessions noop\nif ( !support.optSelected ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tset: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\njQuery.each( [\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n} );\n\n\n\n\n\t// Strip and collapse whitespace according to HTML spec\n\t// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace\n\tfunction stripAndCollapse( value ) {\n\t\tvar tokens = value.match( rnothtmlwhite ) || [];\n\t\treturn tokens.join( \" \" );\n\t}\n\n\nfunction getClass( elem ) {\n\treturn elem.getAttribute && elem.getAttribute( \"class\" ) || \"\";\n}\n\nfunction classesToArray( value ) {\n\tif ( Array.isArray( value ) ) {\n\t\treturn value;\n\t}\n\tif ( typeof value === \"string\" ) {\n\t\treturn value.match( rnothtmlwhite ) || [];\n\t}\n\treturn [];\n}\n\njQuery.fn.extend( {\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( !arguments.length ) {\n\t\t\treturn this.attr( \"class\", \"\" );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) > -1 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value,\n\t\t\tisValidValue = type === \"string\" || Array.isArray( value );\n\n\t\tif ( typeof stateVal === \"boolean\" && isValidValue ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).toggleClass(\n\t\t\t\t\tvalue.call( this, i, getClass( this ), stateVal ),\n\t\t\t\t\tstateVal\n\t\t\t\t);\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar className, i, self, classNames;\n\n\t\t\tif ( isValidValue ) {\n\n\t\t\t\t// Toggle individual class names\n\t\t\t\ti = 0;\n\t\t\t\tself = jQuery( this );\n\t\t\t\tclassNames = classesToArray( value );\n\n\t\t\t\twhile ( ( className = classNames[ i++ ] ) ) {\n\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( value === undefined || type === \"boolean\" ) {\n\t\t\t\tclassName = getClass( this );\n\t\t\t\tif ( className ) {\n\n\t\t\t\t\t// Store className if set\n\t\t\t\t\tdataPriv.set( this, \"__className__\", className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed `false`,\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tif ( this.setAttribute ) {\n\t\t\t\t\tthis.setAttribute( \"class\",\n\t\t\t\t\t\tclassName || value === false ?\n\t\t\t\t\t\t\"\" :\n\t\t\t\t\t\tdataPriv.get( this, \"__className__\" ) || \"\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className, elem,\n\t\t\ti = 0;\n\n\t\tclassName = \" \" + selector + \" \";\n\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\tif ( elem.nodeType === 1 &&\n\t\t\t\t( \" \" + stripAndCollapse( getClass( elem ) ) + \" \" ).indexOf( className ) > -1 ) {\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n} );\n\n\n\n\nvar rreturn = /\\r/g;\n\njQuery.fn.extend( {\n\tval: function( value ) {\n\t\tvar hooks, ret, valueIsFunction,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] ||\n\t\t\t\t\tjQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks &&\n\t\t\t\t\t\"get\" in hooks &&\n\t\t\t\t\t( ret = hooks.get( elem, \"value\" ) ) !== undefined\n\t\t\t\t) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\t// Handle most common string cases\n\t\t\t\tif ( typeof ret === \"string\" ) {\n\t\t\t\t\treturn ret.replace( rreturn, \"\" );\n\t\t\t\t}\n\n\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\treturn ret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tvalueIsFunction = isFunction( value );\n\n\t\treturn this.each( function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( Array.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !( \"set\" in hooks ) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\tvar val = jQuery.find.attr( elem, \"value\" );\n\t\t\t\treturn val != null ?\n\t\t\t\t\tval :\n\n\t\t\t\t\t// Support: IE <=10 - 11 only\n\t\t\t\t\t// option.text throws exceptions (#14686, #14858)\n\t\t\t\t\t// Strip and collapse whitespace\n\t\t\t\t\t// https://html.spec.whatwg.org/#strip-and-collapse-whitespace\n\t\t\t\t\tstripAndCollapse( jQuery.text( elem ) );\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option, i,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\",\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length;\n\n\t\t\t\tif ( index < 0 ) {\n\t\t\t\t\ti = max;\n\n\t\t\t\t} else {\n\t\t\t\t\ti = one ? index : 0;\n\t\t\t\t}\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t// IE8-9 doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t!option.disabled &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled ||\n\t\t\t\t\t\t\t\t!nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t/* eslint-disable no-cond-assign */\n\n\t\t\t\t\tif ( option.selected =\n\t\t\t\t\t\tjQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1\n\t\t\t\t\t) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* eslint-enable no-cond-assign */\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Radios and checkboxes getter/setter\njQuery.each( [ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( Array.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );\n\t\t\t}\n\t\t}\n\t};\n\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\treturn elem.getAttribute( \"value\" ) === null ? \"on\" : elem.value;\n\t\t};\n\t}\n} );\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\nsupport.focusin = \"onfocusin\" in window;\n\n\nvar rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\tstopPropagationCallback = function( e ) {\n\t\te.stopPropagation();\n\t};\n\njQuery.extend( jQuery.event, {\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special, lastElement,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split( \".\" ) : [];\n\n\t\tcur = lastElement = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf( \".\" ) > -1 ) {\n\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split( \".\" );\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf( \":\" ) < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join( \".\" );\n\t\tevent.rnamespace = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === ( elem.ownerDocument || document ) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tlastElement = cur;\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( dataPriv.get( cur, \"events\" ) || {} )[ event.type ] &&\n\t\t\t\tdataPriv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( ( !special._default ||\n\t\t\t\tspecial._default.apply( eventPath.pop(), data ) === false ) &&\n\t\t\t\tacceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.addEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\telem[ type ]();\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.removeEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\t// Piggyback on a donor event to simulate a different one\n\t// Used only for `focus(in | out)` events\n\tsimulate: function( type, elem, event ) {\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true\n\t\t\t}\n\t\t);\n\n\t\tjQuery.event.trigger( e, null, elem );\n\t}\n\n} );\n\njQuery.fn.extend( {\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t} );\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[ 0 ];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n} );\n\n\n// Support: Firefox <=44\n// Firefox doesn't have focus(in | out) events\n// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787\n//\n// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1\n// focus(in | out) events fire after focus & blur events,\n// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order\n// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857\nif ( !support.focusin ) {\n\tjQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );\n\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tdataPriv.access( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tdataPriv.remove( doc, fix );\n\n\t\t\t\t} else {\n\t\t\t\t\tdataPriv.access( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t} );\n}\nvar location = window.location;\n\nvar nonce = Date.now();\n\nvar rquery = ( /\\?/ );\n\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE 9 - 11 only\n\t// IE throws on parseFromString with invalid input.\n\ttry {\n\t\txml = ( new window.DOMParser() ).parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {\n\t\txml = undefined;\n\t}\n\n\tif ( !xml || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\tjQuery.error( \"Invalid XML: \" + data );\n\t}\n\treturn xml;\n};\n\n\nvar\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( Array.isArray( obj ) ) {\n\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams(\n\t\t\t\t\tprefix + \"[\" + ( typeof v === \"object\" && v != null ? i : \"\" ) + \"]\",\n\t\t\t\t\tv,\n\t\t\t\t\ttraditional,\n\t\t\t\t\tadd\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t} else if ( !traditional && toType( obj ) === \"object\" ) {\n\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, valueOrFunction ) {\n\n\t\t\t// If value is a function, invoke it and use its return value\n\t\t\tvar value = isFunction( valueOrFunction ) ?\n\t\t\t\tvalueOrFunction() :\n\t\t\t\tvalueOrFunction;\n\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" +\n\t\t\t\tencodeURIComponent( value == null ? \"\" : value );\n\t\t};\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t} );\n\n\t} else {\n\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" );\n};\n\njQuery.fn.extend( {\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map( function() {\n\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t} )\n\t\t.filter( function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t} )\n\t\t.map( function( i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\tif ( val == null ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( Array.isArray( val ) ) {\n\t\t\t\treturn jQuery.map( val, function( val ) {\n\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t} ).get();\n\t}\n} );\n\n\nvar\n\tr20 = /%20/g,\n\trhash = /#.*$/,\n\trantiCache = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t *    - BEFORE asking for a transport\n\t *    - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat( \"*\" ),\n\n\t// Anchor tag for parsing the document origin\n\toriginAnchor = document.createElement( \"a\" );\n\toriginAnchor.href = location.href;\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];\n\n\t\tif ( isFunction( func ) ) {\n\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( ( dataType = dataTypes[ i++ ] ) ) {\n\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[ 0 ] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" &&\n\t\t\t\t!seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t} );\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\n\n\t// Remove auto dataType and get content-type in the process\n\twhile ( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader( \"Content-Type\" );\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[ 0 ] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n/* Chain conversions given the request and the original response\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s.throws ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tstate: \"parsererror\",\n\t\t\t\t\t\t\t\terror: conv ? e : \"No conversion from \" + prev + \" to \" + current\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\njQuery.extend( {\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: location.href,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( location.protocol ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /\\bxml\\b/,\n\t\t\thtml: /\\bhtml/,\n\t\t\tjson: /\\bjson\\b/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": JSON.parse,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// Url cleanup var\n\t\t\turlAnchor,\n\n\t\t\t// Request state (becomes false upon send and true upon completion)\n\t\t\tcompleted,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\t// Loop variable\n\t\t\ti,\n\n\t\t\t// uncached part of the url\n\t\t\tuncached,\n\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context &&\n\t\t\t\t( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\t\tjQuery.event,\n\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks( \"once memory\" ),\n\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( completed ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( ( match = rheaders.exec( responseHeadersString ) ) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match;\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn completed ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\tname = requestHeadersNames[ name.toLowerCase() ] =\n\t\t\t\t\t\t\trequestHeadersNames[ name.toLowerCase() ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( completed ) {\n\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Lazy-add the new callbacks in a way that preserves old ones\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR );\n\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || location.href ) + \"\" )\n\t\t\t.replace( rprotocol, location.protocol + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = ( s.dataType || \"*\" ).toLowerCase().match( rnothtmlwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when the origin doesn't match the current origin.\n\t\tif ( s.crossDomain == null ) {\n\t\t\turlAnchor = document.createElement( \"a\" );\n\n\t\t\t// Support: IE <=8 - 11, Edge 12 - 15\n\t\t\t// IE throws exception on accessing the href property if url is malformed,\n\t\t\t// e.g. http://example.com:80x/\n\t\t\ttry {\n\t\t\t\turlAnchor.href = s.url;\n\n\t\t\t\t// Support: IE <=8 - 11 only\n\t\t\t\t// Anchor's host property isn't correctly set when s.url is relative\n\t\t\t\turlAnchor.href = urlAnchor.href;\n\t\t\t\ts.crossDomain = originAnchor.protocol + \"//\" + originAnchor.host !==\n\t\t\t\t\turlAnchor.protocol + \"//\" + urlAnchor.host;\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// If there is an error parsing the URL, assume it is crossDomain,\n\t\t\t\t// it can be rejected by the transport if it is invalid\n\t\t\t\ts.crossDomain = true;\n\t\t\t}\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( completed ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\t// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)\n\t\tfireGlobals = jQuery.event && s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger( \"ajaxStart\" );\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\t// Remove hash to simplify url manipulation\n\t\tcacheURL = s.url.replace( rhash, \"\" );\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// Remember the hash so we can put it back\n\t\t\tuncached = s.url.slice( cacheURL.length );\n\n\t\t\t// If data is available and should be processed, append data to url\n\t\t\tif ( s.data && ( s.processData || typeof s.data === \"string\" ) ) {\n\t\t\t\tcacheURL += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data;\n\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add or update anti-cache param if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\tcacheURL = cacheURL.replace( rantiCache, \"$1\" );\n\t\t\t\tuncached = ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + ( nonce++ ) + uncached;\n\t\t\t}\n\n\t\t\t// Put hash and anti-cache on the URL that will be requested (gh-1732)\n\t\t\ts.url = cacheURL + uncached;\n\n\t\t// Change '%20' to '+' if this is encoded form body content (gh-2658)\n\t\t} else if ( s.data && s.processData &&\n\t\t\t( s.contentType || \"\" ).indexOf( \"application/x-www-form-urlencoded\" ) === 0 ) {\n\t\t\ts.data = s.data.replace( r20, \"+\" );\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[ 0 ] ] +\n\t\t\t\t\t( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend &&\n\t\t\t( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {\n\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// Aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tcompleteDeferred.add( s.complete );\n\t\tjqXHR.done( s.success );\n\t\tjqXHR.fail( s.error );\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\n\t\t\t// If request was aborted inside ajaxSend, stop there\n\t\t\tif ( completed ) {\n\t\t\t\treturn jqXHR;\n\t\t\t}\n\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = window.setTimeout( function() {\n\t\t\t\t\tjqXHR.abort( \"timeout\" );\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tcompleted = false;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// Rethrow post-completion exceptions\n\t\t\t\tif ( completed ) {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\n\t\t\t\t// Propagate others as results\n\t\t\t\tdone( -1, e );\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Ignore repeat invocations\n\t\t\tif ( completed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcompleted = true;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\twindow.clearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"Last-Modified\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"etag\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\n\t\t\t\t// Extract error from statusText and normalize for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n} );\n\njQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\n\t\t// Shift arguments if data argument was omitted\n\t\tif ( isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\t// The url can be an options object (which then must have .url)\n\t\treturn jQuery.ajax( jQuery.extend( {\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t}, jQuery.isPlainObject( url ) && url ) );\n\t};\n} );\n\n\njQuery._evalUrl = function( url ) {\n\treturn jQuery.ajax( {\n\t\turl: url,\n\n\t\t// Make this explicit, since user can override this through ajaxSetup (#11264)\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tcache: true,\n\t\tasync: false,\n\t\tglobal: false,\n\t\t\"throws\": true\n\t} );\n};\n\n\njQuery.fn.extend( {\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( this[ 0 ] ) {\n\t\t\tif ( isFunction( html ) ) {\n\t\t\t\thtml = html.call( this[ 0 ] );\n\t\t\t}\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map( function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t} ).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( isFunction( html ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call( this, i ) );\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t} );\n\t},\n\n\twrap: function( html ) {\n\t\tvar htmlIsFunction = isFunction( html );\n\n\t\treturn this.each( function( i ) {\n\t\t\tjQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );\n\t\t} );\n\t},\n\n\tunwrap: function( selector ) {\n\t\tthis.parent( selector ).not( \"body\" ).each( function() {\n\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t} );\n\t\treturn this;\n\t}\n} );\n\n\njQuery.expr.pseudos.hidden = function( elem ) {\n\treturn !jQuery.expr.pseudos.visible( elem );\n};\njQuery.expr.pseudos.visible = function( elem ) {\n\treturn !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );\n};\n\n\n\n\njQuery.ajaxSettings.xhr = function() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch ( e ) {}\n};\n\nvar xhrSuccessStatus = {\n\n\t\t// File protocol always yields status code 0, assume 200\n\t\t0: 200,\n\n\t\t// Support: IE <=9 only\n\t\t// #1450: sometimes IE returns 1223 when it should be 204\n\t\t1223: 204\n\t},\n\txhrSupported = jQuery.ajaxSettings.xhr();\n\nsupport.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nsupport.ajax = xhrSupported = !!xhrSupported;\n\njQuery.ajaxTransport( function( options ) {\n\tvar callback, errorCallback;\n\n\t// Cross domain only allowed if supported through XMLHttpRequest\n\tif ( support.cors || xhrSupported && !options.crossDomain ) {\n\t\treturn {\n\t\t\tsend: function( headers, complete ) {\n\t\t\t\tvar i,\n\t\t\t\t\txhr = options.xhr();\n\n\t\t\t\txhr.open(\n\t\t\t\t\toptions.type,\n\t\t\t\t\toptions.url,\n\t\t\t\t\toptions.async,\n\t\t\t\t\toptions.username,\n\t\t\t\t\toptions.password\n\t\t\t\t);\n\n\t\t\t\t// Apply custom fields if provided\n\t\t\t\tif ( options.xhrFields ) {\n\t\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Override mime type if needed\n\t\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t\t}\n\n\t\t\t\t// X-Requested-With header\n\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\tif ( !options.crossDomain && !headers[ \"X-Requested-With\" ] ) {\n\t\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n\t\t\t\t}\n\n\t\t\t\t// Set headers\n\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t}\n\n\t\t\t\t// Callback\n\t\t\t\tcallback = function( type ) {\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\tcallback = errorCallback = xhr.onload =\n\t\t\t\t\t\t\t\txhr.onerror = xhr.onabort = xhr.ontimeout =\n\t\t\t\t\t\t\t\t\txhr.onreadystatechange = null;\n\n\t\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\n\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t// On a manual native abort, IE9 throws\n\t\t\t\t\t\t\t\t// errors on any property access that is not readyState\n\t\t\t\t\t\t\t\tif ( typeof xhr.status !== \"number\" ) {\n\t\t\t\t\t\t\t\t\tcomplete( 0, \"error\" );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcomplete(\n\n\t\t\t\t\t\t\t\t\t\t// File: protocol always yields status 0; see #8605, #14207\n\t\t\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\t\t\txhr.statusText\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText,\n\n\t\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t\t// IE9 has no XHR2 but throws on binary (trac-11426)\n\t\t\t\t\t\t\t\t\t// For XHR2 non-text, let the caller handle it (gh-2498)\n\t\t\t\t\t\t\t\t\t( xhr.responseType || \"text\" ) !== \"text\"  ||\n\t\t\t\t\t\t\t\t\ttypeof xhr.responseText !== \"string\" ?\n\t\t\t\t\t\t\t\t\t\t{ binary: xhr.response } :\n\t\t\t\t\t\t\t\t\t\t{ text: xhr.responseText },\n\t\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t};\n\n\t\t\t\t// Listen to events\n\t\t\t\txhr.onload = callback();\n\t\t\t\terrorCallback = xhr.onerror = xhr.ontimeout = callback( \"error\" );\n\n\t\t\t\t// Support: IE 9 only\n\t\t\t\t// Use onreadystatechange to replace onabort\n\t\t\t\t// to handle uncaught aborts\n\t\t\t\tif ( xhr.onabort !== undefined ) {\n\t\t\t\t\txhr.onabort = errorCallback;\n\t\t\t\t} else {\n\t\t\t\t\txhr.onreadystatechange = function() {\n\n\t\t\t\t\t\t// Check readyState before timeout as it changes\n\t\t\t\t\t\tif ( xhr.readyState === 4 ) {\n\n\t\t\t\t\t\t\t// Allow onerror to be called first,\n\t\t\t\t\t\t\t// but that will not handle a native abort\n\t\t\t\t\t\t\t// Also, save errorCallback to a variable\n\t\t\t\t\t\t\t// as xhr.onerror cannot be accessed\n\t\t\t\t\t\t\twindow.setTimeout( function() {\n\t\t\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\t\t\terrorCallback();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Create the abort callback\n\t\t\t\tcallback = callback( \"abort\" );\n\n\t\t\t\ttry {\n\n\t\t\t\t\t// Do send the request (this may raise an exception)\n\t\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t// #14683: Only rethrow if this hasn't been notified as an error yet\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\n// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)\njQuery.ajaxPrefilter( function( s ) {\n\tif ( s.crossDomain ) {\n\t\ts.contents.script = false;\n\t}\n} );\n\n// Install script dataType\njQuery.ajaxSetup( {\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, \" +\n\t\t\t\"application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /\\b(?:java|ecma)script\\b/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n} );\n\n// Handle cache's special case and crossDomain\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t}\n} );\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\n\t// This transport only deals with cross domain requests\n\tif ( s.crossDomain ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery( \"<script>\" ).prop( {\n\t\t\t\t\tcharset: s.scriptCharset,\n\t\t\t\t\tsrc: s.url\n\t\t\t\t} ).on(\n\t\t\t\t\t\"load error\",\n\t\t\t\t\tcallback = function( evt ) {\n\t\t\t\t\t\tscript.remove();\n\t\t\t\t\t\tcallback = null;\n\t\t\t\t\t\tif ( evt ) {\n\t\t\t\t\t\t\tcomplete( evt.type === \"error\" ? 404 : 200, evt.type );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t);\n\n\t\t\t\t// Use native DOM manipulation to avoid our domManip AJAX trickery\n\t\t\t\tdocument.head.appendChild( script[ 0 ] );\n\t\t\t},\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\nvar oldCallbacks = [],\n\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\njQuery.ajaxSetup( {\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\tvar callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( nonce++ ) );\n\t\tthis[ callback ] = true;\n\t\treturn callback;\n\t}\n} );\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n\tvar callbackName, overwritten, responseContainer,\n\t\tjsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n\t\t\t\"url\" :\n\t\t\ttypeof s.data === \"string\" &&\n\t\t\t\t( s.contentType || \"\" )\n\t\t\t\t\t.indexOf( \"application/x-www-form-urlencoded\" ) === 0 &&\n\t\t\t\trjsonp.test( s.data ) && \"data\"\n\t\t);\n\n\t// Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n\tif ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n\t\t// Get callback name, remembering preexisting value associated with it\n\t\tcallbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?\n\t\t\ts.jsonpCallback() :\n\t\t\ts.jsonpCallback;\n\n\t\t// Insert callback into url or form data\n\t\tif ( jsonProp ) {\n\t\t\ts[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n\t\t} else if ( s.jsonp !== false ) {\n\t\t\ts.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\n\t\t}\n\n\t\t// Use data converter to retrieve json after script execution\n\t\ts.converters[ \"script json\" ] = function() {\n\t\t\tif ( !responseContainer ) {\n\t\t\t\tjQuery.error( callbackName + \" was not called\" );\n\t\t\t}\n\t\t\treturn responseContainer[ 0 ];\n\t\t};\n\n\t\t// Force json dataType\n\t\ts.dataTypes[ 0 ] = \"json\";\n\n\t\t// Install callback\n\t\toverwritten = window[ callbackName ];\n\t\twindow[ callbackName ] = function() {\n\t\t\tresponseContainer = arguments;\n\t\t};\n\n\t\t// Clean-up function (fires after converters)\n\t\tjqXHR.always( function() {\n\n\t\t\t// If previous value didn't exist - remove it\n\t\t\tif ( overwritten === undefined ) {\n\t\t\t\tjQuery( window ).removeProp( callbackName );\n\n\t\t\t// Otherwise restore preexisting value\n\t\t\t} else {\n\t\t\t\twindow[ callbackName ] = overwritten;\n\t\t\t}\n\n\t\t\t// Save back as free\n\t\t\tif ( s[ callbackName ] ) {\n\n\t\t\t\t// Make sure that re-using the options doesn't screw things around\n\t\t\t\ts.jsonpCallback = originalSettings.jsonpCallback;\n\n\t\t\t\t// Save the callback name for future use\n\t\t\t\toldCallbacks.push( callbackName );\n\t\t\t}\n\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && isFunction( overwritten ) ) {\n\t\t\t\toverwritten( responseContainer[ 0 ] );\n\t\t\t}\n\n\t\t\tresponseContainer = overwritten = undefined;\n\t\t} );\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n} );\n\n\n\n\n// Support: Safari 8 only\n// In Safari 8 documents created via document.implementation.createHTMLDocument\n// collapse sibling forms: the second one becomes a child of the first one.\n// Because of that, this security measure has to be disabled in Safari 8.\n// https://bugs.webkit.org/show_bug.cgi?id=137337\nsupport.createHTMLDocument = ( function() {\n\tvar body = document.implementation.createHTMLDocument( \"\" ).body;\n\tbody.innerHTML = \"<form></form><form></form>\";\n\treturn body.childNodes.length === 2;\n} )();\n\n\n// Argument \"data\" should be string of html\n// context (optional): If specified, the fragment will be created in this context,\n// defaults to document\n// keepScripts (optional): If true, will include scripts passed in the html string\njQuery.parseHTML = function( data, context, keepScripts ) {\n\tif ( typeof data !== \"string\" ) {\n\t\treturn [];\n\t}\n\tif ( typeof context === \"boolean\" ) {\n\t\tkeepScripts = context;\n\t\tcontext = false;\n\t}\n\n\tvar base, parsed, scripts;\n\n\tif ( !context ) {\n\n\t\t// Stop scripts or inline event handlers from being executed immediately\n\t\t// by using document.implementation\n\t\tif ( support.createHTMLDocument ) {\n\t\t\tcontext = document.implementation.createHTMLDocument( \"\" );\n\n\t\t\t// Set the base href for the created document\n\t\t\t// so any parsed elements with URLs\n\t\t\t// are based on the document's URL (gh-2965)\n\t\t\tbase = context.createElement( \"base\" );\n\t\t\tbase.href = document.location.href;\n\t\t\tcontext.head.appendChild( base );\n\t\t} else {\n\t\t\tcontext = document;\n\t\t}\n\t}\n\n\tparsed = rsingleTag.exec( data );\n\tscripts = !keepScripts && [];\n\n\t// Single tag\n\tif ( parsed ) {\n\t\treturn [ context.createElement( parsed[ 1 ] ) ];\n\t}\n\n\tparsed = buildFragment( [ data ], context, scripts );\n\n\tif ( scripts && scripts.length ) {\n\t\tjQuery( scripts ).remove();\n\t}\n\n\treturn jQuery.merge( [], parsed.childNodes );\n};\n\n\n/**\n * Load a url into a page\n */\njQuery.fn.load = function( url, params, callback ) {\n\tvar selector, type, response,\n\t\tself = this,\n\t\toff = url.indexOf( \" \" );\n\n\tif ( off > -1 ) {\n\t\tselector = stripAndCollapse( url.slice( off ) );\n\t\turl = url.slice( 0, off );\n\t}\n\n\t// If it's a function\n\tif ( isFunction( params ) ) {\n\n\t\t// We assume that it's the callback\n\t\tcallback = params;\n\t\tparams = undefined;\n\n\t// Otherwise, build a param string\n\t} else if ( params && typeof params === \"object\" ) {\n\t\ttype = \"POST\";\n\t}\n\n\t// If we have elements to modify, make the request\n\tif ( self.length > 0 ) {\n\t\tjQuery.ajax( {\n\t\t\turl: url,\n\n\t\t\t// If \"type\" variable is undefined, then \"GET\" method will be used.\n\t\t\t// Make value of this field explicit since\n\t\t\t// user can override it through ajaxSetup method\n\t\t\ttype: type || \"GET\",\n\t\t\tdataType: \"html\",\n\t\t\tdata: params\n\t\t} ).done( function( responseText ) {\n\n\t\t\t// Save response for use in complete callback\n\t\t\tresponse = arguments;\n\n\t\t\tself.html( selector ?\n\n\t\t\t\t// If a selector was specified, locate the right elements in a dummy div\n\t\t\t\t// Exclude scripts to avoid IE 'Permission Denied' errors\n\t\t\t\tjQuery( \"<div>\" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t// If the request succeeds, this function gets \"data\", \"status\", \"jqXHR\"\n\t\t// but they are ignored because response was set above.\n\t\t// If it fails, this function gets \"jqXHR\", \"status\", \"error\"\n\t\t} ).always( callback && function( jqXHR, status ) {\n\t\t\tself.each( function() {\n\t\t\t\tcallback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t\t} );\n\t\t} );\n\t}\n\n\treturn this;\n};\n\n\n\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( [\n\t\"ajaxStart\",\n\t\"ajaxStop\",\n\t\"ajaxComplete\",\n\t\"ajaxError\",\n\t\"ajaxSuccess\",\n\t\"ajaxSend\"\n], function( i, type ) {\n\tjQuery.fn[ type ] = function( fn ) {\n\t\treturn this.on( type, fn );\n\t};\n} );\n\n\n\n\njQuery.expr.pseudos.animated = function( elem ) {\n\treturn jQuery.grep( jQuery.timers, function( fn ) {\n\t\treturn elem === fn.elem;\n\t} ).length;\n};\n\n\n\n\njQuery.offset = {\n\tsetOffset: function( elem, options, i ) {\n\t\tvar curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n\t\t\tposition = jQuery.css( elem, \"position\" ),\n\t\t\tcurElem = jQuery( elem ),\n\t\t\tprops = {};\n\n\t\t// Set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tcurOffset = curElem.offset();\n\t\tcurCSSTop = jQuery.css( elem, \"top\" );\n\t\tcurCSSLeft = jQuery.css( elem, \"left\" );\n\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n\t\t\t( curCSSTop + curCSSLeft ).indexOf( \"auto\" ) > -1;\n\n\t\t// Need to be able to calculate position if either\n\t\t// top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( isFunction( options ) ) {\n\n\t\t\t// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)\n\t\t\toptions = options.call( elem, i, jQuery.extend( {}, curOffset ) );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\njQuery.fn.extend( {\n\n\t// offset() relates an element's border box to the document origin\n\toffset: function( options ) {\n\n\t\t// Preserve chaining for setter\n\t\tif ( arguments.length ) {\n\t\t\treturn options === undefined ?\n\t\t\t\tthis :\n\t\t\t\tthis.each( function( i ) {\n\t\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t\t} );\n\t\t}\n\n\t\tvar rect, win,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !elem ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Return zeros for disconnected and hidden (display: none) elements (gh-2310)\n\t\t// Support: IE <=11 only\n\t\t// Running getBoundingClientRect on a\n\t\t// disconnected node in IE throws an error\n\t\tif ( !elem.getClientRects().length ) {\n\t\t\treturn { top: 0, left: 0 };\n\t\t}\n\n\t\t// Get document-relative position by adding viewport scroll to viewport-relative gBCR\n\t\trect = elem.getBoundingClientRect();\n\t\twin = elem.ownerDocument.defaultView;\n\t\treturn {\n\t\t\ttop: rect.top + win.pageYOffset,\n\t\t\tleft: rect.left + win.pageXOffset\n\t\t};\n\t},\n\n\t// position() relates an element's margin box to its offset parent's padding box\n\t// This corresponds to the behavior of CSS absolute positioning\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset, doc,\n\t\t\telem = this[ 0 ],\n\t\t\tparentOffset = { top: 0, left: 0 };\n\n\t\t// position:fixed elements are offset from the viewport, which itself always has zero offset\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\n\t\t\t// Assume position:fixed implies availability of getBoundingClientRect\n\t\t\toffset = elem.getBoundingClientRect();\n\n\t\t} else {\n\t\t\toffset = this.offset();\n\n\t\t\t// Account for the *real* offset parent, which can be the document or its root element\n\t\t\t// when a statically positioned element is identified\n\t\t\tdoc = elem.ownerDocument;\n\t\t\toffsetParent = elem.offsetParent || doc.documentElement;\n\t\t\twhile ( offsetParent &&\n\t\t\t\t( offsetParent === doc.body || offsetParent === doc.documentElement ) &&\n\t\t\t\tjQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\n\t\t\t\toffsetParent = offsetParent.parentNode;\n\t\t\t}\n\t\t\tif ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {\n\n\t\t\t\t// Incorporate borders into its offset, since they are outside its content origin\n\t\t\t\tparentOffset = jQuery( offsetParent ).offset();\n\t\t\t\tparentOffset.top += jQuery.css( offsetParent, \"borderTopWidth\", true );\n\t\t\t\tparentOffset.left += jQuery.css( offsetParent, \"borderLeftWidth\", true );\n\t\t\t}\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\treturn {\n\t\t\ttop: offset.top - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true )\n\t\t};\n\t},\n\n\t// This method will return documentElement in the following cases:\n\t// 1) For the element inside the iframe without offsetParent, this method will return\n\t//    documentElement of the parent window\n\t// 2) For the hidden or detached element\n\t// 3) For body or html element, i.e. in case of the html node - it will return itself\n\t//\n\t// but those exceptions were never presented as a real life use-cases\n\t// and might be considered as more preferable results.\n\t//\n\t// This logic, however, is not guaranteed and can change at any point in the future\n\toffsetParent: function() {\n\t\treturn this.map( function() {\n\t\t\tvar offsetParent = this.offsetParent;\n\n\t\t\twhile ( offsetParent && jQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\n\t\t\treturn offsetParent || documentElement;\n\t\t} );\n\t}\n} );\n\n// Create scrollLeft and scrollTop methods\njQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n\tvar top = \"pageYOffset\" === prop;\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn access( this, function( elem, method, val ) {\n\n\t\t\t// Coalesce documents and windows\n\t\t\tvar win;\n\t\t\tif ( isWindow( elem ) ) {\n\t\t\t\twin = elem;\n\t\t\t} else if ( elem.nodeType === 9 ) {\n\t\t\t\twin = elem.defaultView;\n\t\t\t}\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? win[ prop ] : elem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : win.pageXOffset,\n\t\t\t\t\ttop ? val : win.pageYOffset\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length );\n\t};\n} );\n\n// Support: Safari <=7 - 9.1, Chrome <=37 - 49\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347\n// getComputedStyle returns percent when specified for top/left/bottom/right;\n// rather than make the css module depend on the offset module, just check for it here\njQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n\tjQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n\t\tfunction( elem, computed ) {\n\t\t\tif ( computed ) {\n\t\t\t\tcomputed = curCSS( elem, prop );\n\n\t\t\t\t// If curCSS returns percentage, fallback to offset\n\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\tcomputed;\n\t\t\t}\n\t\t}\n\t);\n} );\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name },\n\t\tfunction( defaultExtra, funcName ) {\n\n\t\t// Margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( isWindow( elem ) ) {\n\n\t\t\t\t\t// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)\n\t\t\t\t\treturn funcName.indexOf( \"outer\" ) === 0 ?\n\t\t\t\t\t\telem[ \"inner\" + name ] :\n\t\t\t\t\t\telem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],\n\t\t\t\t\t// whichever is greatest\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable );\n\t\t};\n\t} );\n} );\n\n\njQuery.each( ( \"blur focus focusin focusout resize scroll click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup contextmenu\" ).split( \" \" ),\n\tfunction( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( data, fn ) {\n\t\treturn arguments.length > 0 ?\n\t\t\tthis.on( name, null, data, fn ) :\n\t\t\tthis.trigger( name );\n\t};\n} );\n\njQuery.fn.extend( {\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t}\n} );\n\n\n\n\njQuery.fn.extend( {\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ?\n\t\t\tthis.off( selector, \"**\" ) :\n\t\t\tthis.off( types, selector || \"**\", fn );\n\t}\n} );\n\n// Bind a function to a context, optionally partially applying any\n// arguments.\n// jQuery.proxy is deprecated to promote standards (specifically Function#bind)\n// However, it is not slated for removal any time soon\njQuery.proxy = function( fn, context ) {\n\tvar tmp, args, proxy;\n\n\tif ( typeof context === \"string\" ) {\n\t\ttmp = fn[ context ];\n\t\tcontext = fn;\n\t\tfn = tmp;\n\t}\n\n\t// Quick check to determine if target is callable, in the spec\n\t// this throws a TypeError, but we will just return undefined.\n\tif ( !isFunction( fn ) ) {\n\t\treturn undefined;\n\t}\n\n\t// Simulated bind\n\targs = slice.call( arguments, 2 );\n\tproxy = function() {\n\t\treturn fn.apply( context || this, args.concat( slice.call( arguments ) ) );\n\t};\n\n\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\tproxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n\treturn proxy;\n};\n\njQuery.holdReady = function( hold ) {\n\tif ( hold ) {\n\t\tjQuery.readyWait++;\n\t} else {\n\t\tjQuery.ready( true );\n\t}\n};\njQuery.isArray = Array.isArray;\njQuery.parseJSON = JSON.parse;\njQuery.nodeName = nodeName;\njQuery.isFunction = isFunction;\njQuery.isWindow = isWindow;\njQuery.camelCase = camelCase;\njQuery.type = toType;\n\njQuery.now = Date.now;\n\njQuery.isNumeric = function( obj ) {\n\n\t// As of jQuery 3.0, isNumeric is limited to\n\t// strings and numbers (primitives or objects)\n\t// that can be coerced to finite numbers (gh-2662)\n\tvar type = jQuery.type( obj );\n\treturn ( type === \"number\" || type === \"string\" ) &&\n\n\t\t// parseFloat NaNs numeric-cast false positives (\"\")\n\t\t// ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n\t\t// subtraction forces infinities to NaN\n\t\t!isNaN( obj - parseFloat( obj ) );\n};\n\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\n\n// Note that for maximum portability, libraries that are not jQuery should\n// declare themselves as anonymous modules, and avoid setting a global if an\n// AMD loader is present. jQuery is a special case. For more information, see\n// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon\n\nif ( typeof define === \"function\" && define.amd ) {\n\tdefine( \"jquery\", [], function() {\n\t\treturn jQuery;\n\t} );\n}\n\n\n\n\nvar\n\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$;\n\njQuery.noConflict = function( deep ) {\n\tif ( window.$ === jQuery ) {\n\t\twindow.$ = _$;\n\t}\n\n\tif ( deep && window.jQuery === jQuery ) {\n\t\twindow.jQuery = _jQuery;\n\t}\n\n\treturn jQuery;\n};\n\n// Expose jQuery and $ identifiers, even in AMD\n// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\nif ( !noGlobal ) {\n\twindow.jQuery = window.$ = jQuery;\n}\n\n\n\n\nreturn jQuery;\n} );\n\n\n/*!\n\nJSZip - A Javascript class for generating and reading zip files\n<http://stuartk.com/jszip>\n\n(c) 2009-2014 Stuart Knightley <stuart [at] stuartk.com>\nDual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown.\n\nJSZip uses the library pako released under the MIT license :\nhttps://github.com/nodeca/pako/blob/master/LICENSE\n*/\n!function(e){if(\"object\"==typeof exports&&\"undefined\"!=typeof module)module.exports=e();else if(\"function\"==typeof define&&define.amd)define([],e);else{var f;\"undefined\"!=typeof window?f=window:\"undefined\"!=typeof global?f=global:\"undefined\"!=typeof self&&(f=self),f.JSZip=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error(\"Cannot find module '\"+o+\"'\")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){\n'use strict';\n// private property\nvar _keyStr = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\n\n// public method for encoding\nexports.encode = function(input, utf8) {\n    var output = \"\";\n    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;\n    var i = 0;\n\n    while (i < input.length) {\n\n        chr1 = input.charCodeAt(i++);\n        chr2 = input.charCodeAt(i++);\n        chr3 = input.charCodeAt(i++);\n\n        enc1 = chr1 >> 2;\n        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n        enc4 = chr3 & 63;\n\n        if (isNaN(chr2)) {\n            enc3 = enc4 = 64;\n        }\n        else if (isNaN(chr3)) {\n            enc4 = 64;\n        }\n\n        output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4);\n\n    }\n\n    return output;\n};\n\n// public method for decoding\nexports.decode = function(input, utf8) {\n    var output = \"\";\n    var chr1, chr2, chr3;\n    var enc1, enc2, enc3, enc4;\n    var i = 0;\n\n    input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\");\n\n    while (i < input.length) {\n\n        enc1 = _keyStr.indexOf(input.charAt(i++));\n        enc2 = _keyStr.indexOf(input.charAt(i++));\n        enc3 = _keyStr.indexOf(input.charAt(i++));\n        enc4 = _keyStr.indexOf(input.charAt(i++));\n\n        chr1 = (enc1 << 2) | (enc2 >> 4);\n        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n        chr3 = ((enc3 & 3) << 6) | enc4;\n\n        output = output + String.fromCharCode(chr1);\n\n        if (enc3 != 64) {\n            output = output + String.fromCharCode(chr2);\n        }\n        if (enc4 != 64) {\n            output = output + String.fromCharCode(chr3);\n        }\n\n    }\n\n    return output;\n\n};\n\n},{}],2:[function(_dereq_,module,exports){\n'use strict';\nfunction CompressedObject() {\n    this.compressedSize = 0;\n    this.uncompressedSize = 0;\n    this.crc32 = 0;\n    this.compressionMethod = null;\n    this.compressedContent = null;\n}\n\nCompressedObject.prototype = {\n    /**\n     * Return the decompressed content in an unspecified format.\n     * The format will depend on the decompressor.\n     * @return {Object} the decompressed content.\n     */\n    getContent: function() {\n        return null; // see implementation\n    },\n    /**\n     * Return the compressed content in an unspecified format.\n     * The format will depend on the compressed conten source.\n     * @return {Object} the compressed content.\n     */\n    getCompressedContent: function() {\n        return null; // see implementation\n    }\n};\nmodule.exports = CompressedObject;\n\n},{}],3:[function(_dereq_,module,exports){\n'use strict';\nexports.STORE = {\n    magic: \"\\x00\\x00\",\n    compress: function(content, compressionOptions) {\n        return content; // no compression\n    },\n    uncompress: function(content) {\n        return content; // no compression\n    },\n    compressInputType: null,\n    uncompressInputType: null\n};\nexports.DEFLATE = _dereq_('./flate');\n\n},{\"./flate\":8}],4:[function(_dereq_,module,exports){\n'use strict';\n\nvar utils = _dereq_('./utils');\n\nvar table = [\n    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,\n    0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,\n    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,\n    0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,\n    0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,\n    0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,\n    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,\n    0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,\n    0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,\n    0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,\n    0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,\n    0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,\n    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,\n    0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,\n    0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,\n    0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,\n    0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,\n    0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,\n    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,\n    0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,\n    0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,\n    0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,\n    0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,\n    0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,\n    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,\n    0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,\n    0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,\n    0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,\n    0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,\n    0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,\n    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,\n    0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,\n    0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,\n    0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,\n    0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,\n    0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,\n    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,\n    0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,\n    0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,\n    0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,\n    0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,\n    0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,\n    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,\n    0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,\n    0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,\n    0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,\n    0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,\n    0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,\n    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,\n    0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,\n    0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,\n    0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,\n    0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,\n    0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,\n    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,\n    0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,\n    0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,\n    0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,\n    0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,\n    0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,\n    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,\n    0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,\n    0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,\n    0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D\n];\n\n/**\n *\n *  Javascript crc32\n *  http://www.webtoolkit.info/\n *\n */\nmodule.exports = function crc32(input, crc) {\n    if (typeof input === \"undefined\" || !input.length) {\n        return 0;\n    }\n\n    var isArray = utils.getTypeOf(input) !== \"string\";\n\n    if (typeof(crc) == \"undefined\") {\n        crc = 0;\n    }\n    var x = 0;\n    var y = 0;\n    var b = 0;\n\n    crc = crc ^ (-1);\n    for (var i = 0, iTop = input.length; i < iTop; i++) {\n        b = isArray ? input[i] : input.charCodeAt(i);\n        y = (crc ^ b) & 0xFF;\n        x = table[y];\n        crc = (crc >>> 8) ^ x;\n    }\n\n    return crc ^ (-1);\n};\n// vim: set shiftwidth=4 softtabstop=4:\n\n},{\"./utils\":21}],5:[function(_dereq_,module,exports){\n'use strict';\nvar utils = _dereq_('./utils');\n\nfunction DataReader(data) {\n    this.data = null; // type : see implementation\n    this.length = 0;\n    this.index = 0;\n}\nDataReader.prototype = {\n    /**\n     * Check that the offset will not go too far.\n     * @param {string} offset the additional offset to check.\n     * @throws {Error} an Error if the offset is out of bounds.\n     */\n    checkOffset: function(offset) {\n        this.checkIndex(this.index + offset);\n    },\n    /**\n     * Check that the specifed index will not be too far.\n     * @param {string} newIndex the index to check.\n     * @throws {Error} an Error if the index is out of bounds.\n     */\n    checkIndex: function(newIndex) {\n        if (this.length < newIndex || newIndex < 0) {\n            throw new Error(\"End of data reached (data length = \" + this.length + \", asked index = \" + (newIndex) + \"). Corrupted zip ?\");\n        }\n    },\n    /**\n     * Change the index.\n     * @param {number} newIndex The new index.\n     * @throws {Error} if the new index is out of the data.\n     */\n    setIndex: function(newIndex) {\n        this.checkIndex(newIndex);\n        this.index = newIndex;\n    },\n    /**\n     * Skip the next n bytes.\n     * @param {number} n the number of bytes to skip.\n     * @throws {Error} if the new index is out of the data.\n     */\n    skip: function(n) {\n        this.setIndex(this.index + n);\n    },\n    /**\n     * Get the byte at the specified index.\n     * @param {number} i the index to use.\n     * @return {number} a byte.\n     */\n    byteAt: function(i) {\n        // see implementations\n    },\n    /**\n     * Get the next number with a given byte size.\n     * @param {number} size the number of bytes to read.\n     * @return {number} the corresponding number.\n     */\n    readInt: function(size) {\n        var result = 0,\n            i;\n        this.checkOffset(size);\n        for (i = this.index + size - 1; i >= this.index; i--) {\n            result = (result << 8) + this.byteAt(i);\n        }\n        this.index += size;\n        return result;\n    },\n    /**\n     * Get the next string with a given byte size.\n     * @param {number} size the number of bytes to read.\n     * @return {string} the corresponding string.\n     */\n    readString: function(size) {\n        return utils.transformTo(\"string\", this.readData(size));\n    },\n    /**\n     * Get raw data without conversion, <size> bytes.\n     * @param {number} size the number of bytes to read.\n     * @return {Object} the raw data, implementation specific.\n     */\n    readData: function(size) {\n        // see implementations\n    },\n    /**\n     * Find the last occurence of a zip signature (4 bytes).\n     * @param {string} sig the signature to find.\n     * @return {number} the index of the last occurence, -1 if not found.\n     */\n    lastIndexOfSignature: function(sig) {\n        // see implementations\n    },\n    /**\n     * Get the next date.\n     * @return {Date} the date.\n     */\n    readDate: function() {\n        var dostime = this.readInt(4);\n        return new Date(\n        ((dostime >> 25) & 0x7f) + 1980, // year\n        ((dostime >> 21) & 0x0f) - 1, // month\n        (dostime >> 16) & 0x1f, // day\n        (dostime >> 11) & 0x1f, // hour\n        (dostime >> 5) & 0x3f, // minute\n        (dostime & 0x1f) << 1); // second\n    }\n};\nmodule.exports = DataReader;\n\n},{\"./utils\":21}],6:[function(_dereq_,module,exports){\n'use strict';\nexports.base64 = false;\nexports.binary = false;\nexports.dir = false;\nexports.createFolders = false;\nexports.date = null;\nexports.compression = null;\nexports.compressionOptions = null;\nexports.comment = null;\nexports.unixPermissions = null;\nexports.dosPermissions = null;\n\n},{}],7:[function(_dereq_,module,exports){\n'use strict';\nvar utils = _dereq_('./utils');\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.string2binary = function(str) {\n    return utils.string2binary(str);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.string2Uint8Array = function(str) {\n    return utils.transformTo(\"uint8array\", str);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.uint8Array2String = function(array) {\n    return utils.transformTo(\"string\", array);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.string2Blob = function(str) {\n    var buffer = utils.transformTo(\"arraybuffer\", str);\n    return utils.arrayBuffer2Blob(buffer);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.arrayBuffer2Blob = function(buffer) {\n    return utils.arrayBuffer2Blob(buffer);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.transformTo = function(outputType, input) {\n    return utils.transformTo(outputType, input);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.getTypeOf = function(input) {\n    return utils.getTypeOf(input);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.checkSupport = function(type) {\n    return utils.checkSupport(type);\n};\n\n/**\n * @deprecated\n * This value will be removed in a future version without replacement.\n */\nexports.MAX_VALUE_16BITS = utils.MAX_VALUE_16BITS;\n\n/**\n * @deprecated\n * This value will be removed in a future version without replacement.\n */\nexports.MAX_VALUE_32BITS = utils.MAX_VALUE_32BITS;\n\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.pretty = function(str) {\n    return utils.pretty(str);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.findCompression = function(compressionMethod) {\n    return utils.findCompression(compressionMethod);\n};\n\n/**\n * @deprecated\n * This function will be removed in a future version without replacement.\n */\nexports.isRegExp = function (object) {\n    return utils.isRegExp(object);\n};\n\n\n},{\"./utils\":21}],8:[function(_dereq_,module,exports){\n'use strict';\nvar USE_TYPEDARRAY = (typeof Uint8Array !== 'undefined') && (typeof Uint16Array !== 'undefined') && (typeof Uint32Array !== 'undefined');\n\nvar pako = _dereq_(\"pako\");\nexports.uncompressInputType = USE_TYPEDARRAY ? \"uint8array\" : \"array\";\nexports.compressInputType = USE_TYPEDARRAY ? \"uint8array\" : \"array\";\n\nexports.magic = \"\\x08\\x00\";\nexports.compress = function(input, compressionOptions) {\n    return pako.deflateRaw(input, {\n        level : compressionOptions.level || -1 // default compression\n    });\n};\nexports.uncompress =  function(input) {\n    return pako.inflateRaw(input);\n};\n\n},{\"pako\":24}],9:[function(_dereq_,module,exports){\n'use strict';\n\nvar base64 = _dereq_('./base64');\n\n/**\nUsage:\n   zip = new JSZip();\n   zip.file(\"hello.txt\", \"Hello, World!\").file(\"tempfile\", \"nothing\");\n   zip.folder(\"images\").file(\"smile.gif\", base64Data, {base64: true});\n   zip.file(\"Xmas.txt\", \"Ho ho ho !\", {date : new Date(\"December 25, 2007 00:00:01\")});\n   zip.remove(\"tempfile\");\n\n   base64zip = zip.generate();\n\n**/\n\n/**\n * Representation a of zip file in js\n * @constructor\n * @param {String=|ArrayBuffer=|Uint8Array=} data the data to load, if any (optional).\n * @param {Object=} options the options for creating this objects (optional).\n */\nfunction JSZip(data, options) {\n    // if this constructor is used without `new`, it adds `new` before itself:\n    if(!(this instanceof JSZip)) return new JSZip(data, options);\n\n    // object containing the files :\n    // {\n    //   \"folder/\" : {...},\n    //   \"folder/data.txt\" : {...}\n    // }\n    this.files = {};\n\n    this.comment = null;\n\n    // Where we are in the hierarchy\n    this.root = \"\";\n    if (data) {\n        this.load(data, options);\n    }\n    this.clone = function() {\n        var newObj = new JSZip();\n        for (var i in this) {\n            if (typeof this[i] !== \"function\") {\n                newObj[i] = this[i];\n            }\n        }\n        return newObj;\n    };\n}\nJSZip.prototype = _dereq_('./object');\nJSZip.prototype.load = _dereq_('./load');\nJSZip.support = _dereq_('./support');\nJSZip.defaults = _dereq_('./defaults');\n\n/**\n * @deprecated\n * This namespace will be removed in a future version without replacement.\n */\nJSZip.utils = _dereq_('./deprecatedPublicUtils');\n\nJSZip.base64 = {\n    /**\n     * @deprecated\n     * This method will be removed in a future version without replacement.\n     */\n    encode : function(input) {\n        return base64.encode(input);\n    },\n    /**\n     * @deprecated\n     * This method will be removed in a future version without replacement.\n     */\n    decode : function(input) {\n        return base64.decode(input);\n    }\n};\nJSZip.compressions = _dereq_('./compressions');\nmodule.exports = JSZip;\n\n},{\"./base64\":1,\"./compressions\":3,\"./defaults\":6,\"./deprecatedPublicUtils\":7,\"./load\":10,\"./object\":13,\"./support\":17}],10:[function(_dereq_,module,exports){\n'use strict';\nvar base64 = _dereq_('./base64');\nvar ZipEntries = _dereq_('./zipEntries');\nmodule.exports = function(data, options) {\n    var files, zipEntries, i, input;\n    options = options || {};\n    if (options.base64) {\n        data = base64.decode(data);\n    }\n\n    zipEntries = new ZipEntries(data, options);\n    files = zipEntries.files;\n    for (i = 0; i < files.length; i++) {\n        input = files[i];\n        this.file(input.fileName, input.decompressed, {\n            binary: true,\n            optimizedBinaryString: true,\n            date: input.date,\n            dir: input.dir,\n            comment : input.fileComment.length ? input.fileComment : null,\n            unixPermissions : input.unixPermissions,\n            dosPermissions : input.dosPermissions,\n            createFolders: options.createFolders\n        });\n    }\n    if (zipEntries.zipComment.length) {\n        this.comment = zipEntries.zipComment;\n    }\n\n    return this;\n};\n\n},{\"./base64\":1,\"./zipEntries\":22}],11:[function(_dereq_,module,exports){\n(function (Buffer){\n'use strict';\nmodule.exports = function(data, encoding){\n    return new Buffer(data, encoding);\n};\nmodule.exports.test = function(b){\n    return Buffer.isBuffer(b);\n};\n\n}).call(this,(typeof Buffer !== \"undefined\" ? Buffer : undefined))\n},{}],12:[function(_dereq_,module,exports){\n'use strict';\nvar Uint8ArrayReader = _dereq_('./uint8ArrayReader');\n\nfunction NodeBufferReader(data) {\n    this.data = data;\n    this.length = this.data.length;\n    this.index = 0;\n}\nNodeBufferReader.prototype = new Uint8ArrayReader();\n\n/**\n * @see DataReader.readData\n */\nNodeBufferReader.prototype.readData = function(size) {\n    this.checkOffset(size);\n    var result = this.data.slice(this.index, this.index + size);\n    this.index += size;\n    return result;\n};\nmodule.exports = NodeBufferReader;\n\n},{\"./uint8ArrayReader\":18}],13:[function(_dereq_,module,exports){\n'use strict';\nvar support = _dereq_('./support');\nvar utils = _dereq_('./utils');\nvar crc32 = _dereq_('./crc32');\nvar signature = _dereq_('./signature');\nvar defaults = _dereq_('./defaults');\nvar base64 = _dereq_('./base64');\nvar compressions = _dereq_('./compressions');\nvar CompressedObject = _dereq_('./compressedObject');\nvar nodeBuffer = _dereq_('./nodeBuffer');\nvar utf8 = _dereq_('./utf8');\nvar StringWriter = _dereq_('./stringWriter');\nvar Uint8ArrayWriter = _dereq_('./uint8ArrayWriter');\n\n/**\n * Returns the raw data of a ZipObject, decompress the content if necessary.\n * @param {ZipObject} file the file to use.\n * @return {String|ArrayBuffer|Uint8Array|Buffer} the data.\n */\nvar getRawData = function(file) {\n    if (file._data instanceof CompressedObject) {\n        file._data = file._data.getContent();\n        file.options.binary = true;\n        file.options.base64 = false;\n\n        if (utils.getTypeOf(file._data) === \"uint8array\") {\n            var copy = file._data;\n            // when reading an arraybuffer, the CompressedObject mechanism will keep it and subarray() a Uint8Array.\n            // if we request a file in the same format, we might get the same Uint8Array or its ArrayBuffer (the original zip file).\n            file._data = new Uint8Array(copy.length);\n            // with an empty Uint8Array, Opera fails with a \"Offset larger than array size\"\n            if (copy.length !== 0) {\n                file._data.set(copy, 0);\n            }\n        }\n    }\n    return file._data;\n};\n\n/**\n * Returns the data of a ZipObject in a binary form. If the content is an unicode string, encode it.\n * @param {ZipObject} file the file to use.\n * @return {String|ArrayBuffer|Uint8Array|Buffer} the data.\n */\nvar getBinaryData = function(file) {\n    var result = getRawData(file),\n        type = utils.getTypeOf(result);\n    if (type === \"string\") {\n        if (!file.options.binary) {\n            // unicode text !\n            // unicode string => binary string is a painful process, check if we can avoid it.\n            if (support.nodebuffer) {\n                return nodeBuffer(result, \"utf-8\");\n            }\n        }\n        return file.asBinary();\n    }\n    return result;\n};\n\n/**\n * Transform this._data into a string.\n * @param {function} filter a function String -> String, applied if not null on the result.\n * @return {String} the string representing this._data.\n */\nvar dataToString = function(asUTF8) {\n    var result = getRawData(this);\n    if (result === null || typeof result === \"undefined\") {\n        return \"\";\n    }\n    // if the data is a base64 string, we decode it before checking the encoding !\n    if (this.options.base64) {\n        result = base64.decode(result);\n    }\n    if (asUTF8 && this.options.binary) {\n        // JSZip.prototype.utf8decode supports arrays as input\n        // skip to array => string step, utf8decode will do it.\n        result = out.utf8decode(result);\n    }\n    else {\n        // no utf8 transformation, do the array => string step.\n        result = utils.transformTo(\"string\", result);\n    }\n\n    if (!asUTF8 && !this.options.binary) {\n        result = utils.transformTo(\"string\", out.utf8encode(result));\n    }\n    return result;\n};\n/**\n * A simple object representing a file in the zip file.\n * @constructor\n * @param {string} name the name of the file\n * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data\n * @param {Object} options the options of the file\n */\nvar ZipObject = function(name, data, options) {\n    this.name = name;\n    this.dir = options.dir;\n    this.date = options.date;\n    this.comment = options.comment;\n    this.unixPermissions = options.unixPermissions;\n    this.dosPermissions = options.dosPermissions;\n\n    this._data = data;\n    this.options = options;\n\n    /*\n     * This object contains initial values for dir and date.\n     * With them, we can check if the user changed the deprecated metadata in\n     * `ZipObject#options` or not.\n     */\n    this._initialMetadata = {\n      dir : options.dir,\n      date : options.date\n    };\n};\n\nZipObject.prototype = {\n    /**\n     * Return the content as UTF8 string.\n     * @return {string} the UTF8 string.\n     */\n    asText: function() {\n        return dataToString.call(this, true);\n    },\n    /**\n     * Returns the binary content.\n     * @return {string} the content as binary.\n     */\n    asBinary: function() {\n        return dataToString.call(this, false);\n    },\n    /**\n     * Returns the content as a nodejs Buffer.\n     * @return {Buffer} the content as a Buffer.\n     */\n    asNodeBuffer: function() {\n        var result = getBinaryData(this);\n        return utils.transformTo(\"nodebuffer\", result);\n    },\n    /**\n     * Returns the content as an Uint8Array.\n     * @return {Uint8Array} the content as an Uint8Array.\n     */\n    asUint8Array: function() {\n        var result = getBinaryData(this);\n        return utils.transformTo(\"uint8array\", result);\n    },\n    /**\n     * Returns the content as an ArrayBuffer.\n     * @return {ArrayBuffer} the content as an ArrayBufer.\n     */\n    asArrayBuffer: function() {\n        return this.asUint8Array().buffer;\n    }\n};\n\n/**\n * Transform an integer into a string in hexadecimal.\n * @private\n * @param {number} dec the number to convert.\n * @param {number} bytes the number of bytes to generate.\n * @returns {string} the result.\n */\nvar decToHex = function(dec, bytes) {\n    var hex = \"\",\n        i;\n    for (i = 0; i < bytes; i++) {\n        hex += String.fromCharCode(dec & 0xff);\n        dec = dec >>> 8;\n    }\n    return hex;\n};\n\n/**\n * Merge the objects passed as parameters into a new one.\n * @private\n * @param {...Object} var_args All objects to merge.\n * @return {Object} a new object with the data of the others.\n */\nvar extend = function() {\n    var result = {}, i, attr;\n    for (i = 0; i < arguments.length; i++) { // arguments is not enumerable in some browsers\n        for (attr in arguments[i]) {\n            if (arguments[i].hasOwnProperty(attr) && typeof result[attr] === \"undefined\") {\n                result[attr] = arguments[i][attr];\n            }\n        }\n    }\n    return result;\n};\n\n/**\n * Transforms the (incomplete) options from the user into the complete\n * set of options to create a file.\n * @private\n * @param {Object} o the options from the user.\n * @return {Object} the complete set of options.\n */\nvar prepareFileAttrs = function(o) {\n    o = o || {};\n    if (o.base64 === true && (o.binary === null || o.binary === undefined)) {\n        o.binary = true;\n    }\n    o = extend(o, defaults);\n    o.date = o.date || new Date();\n    if (o.compression !== null) o.compression = o.compression.toUpperCase();\n\n    return o;\n};\n\n/**\n * Add a file in the current folder.\n * @private\n * @param {string} name the name of the file\n * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data of the file\n * @param {Object} o the options of the file\n * @return {Object} the new file.\n */\nvar fileAdd = function(name, data, o) {\n    // be sure sub folders exist\n    var dataType = utils.getTypeOf(data),\n        parent;\n\n    o = prepareFileAttrs(o);\n\n    if (typeof o.unixPermissions === \"string\") {\n        o.unixPermissions = parseInt(o.unixPermissions, 8);\n    }\n\n    // UNX_IFDIR  0040000 see zipinfo.c\n    if (o.unixPermissions && (o.unixPermissions & 0x4000)) {\n        o.dir = true;\n    }\n    // Bit 4    Directory\n    if (o.dosPermissions && (o.dosPermissions & 0x0010)) {\n        o.dir = true;\n    }\n\n    if (o.dir) {\n        name = forceTrailingSlash(name);\n    }\n\n    if (o.createFolders && (parent = parentFolder(name))) {\n        folderAdd.call(this, parent, true);\n    }\n\n    if (o.dir || data === null || typeof data === \"undefined\") {\n        o.base64 = false;\n        o.binary = false;\n        data = null;\n        dataType = null;\n    }\n    else if (dataType === \"string\") {\n        if (o.binary && !o.base64) {\n            // optimizedBinaryString == true means that the file has already been filtered with a 0xFF mask\n            if (o.optimizedBinaryString !== true) {\n                // this is a string, not in a base64 format.\n                // Be sure that this is a correct \"binary string\"\n                data = utils.string2binary(data);\n            }\n        }\n    }\n    else { // arraybuffer, uint8array, ...\n        o.base64 = false;\n        o.binary = true;\n\n        if (!dataType && !(data instanceof CompressedObject)) {\n            throw new Error(\"The data of '\" + name + \"' is in an unsupported format !\");\n        }\n\n        // special case : it's way easier to work with Uint8Array than with ArrayBuffer\n        if (dataType === \"arraybuffer\") {\n            data = utils.transformTo(\"uint8array\", data);\n        }\n    }\n\n    var object = new ZipObject(name, data, o);\n    this.files[name] = object;\n    return object;\n};\n\n/**\n * Find the parent folder of the path.\n * @private\n * @param {string} path the path to use\n * @return {string} the parent folder, or \"\"\n */\nvar parentFolder = function (path) {\n    if (path.slice(-1) == '/') {\n        path = path.substring(0, path.length - 1);\n    }\n    var lastSlash = path.lastIndexOf('/');\n    return (lastSlash > 0) ? path.substring(0, lastSlash) : \"\";\n};\n\n\n/**\n * Returns the path with a slash at the end.\n * @private\n * @param {String} path the path to check.\n * @return {String} the path with a trailing slash.\n */\nvar forceTrailingSlash = function(path) {\n    // Check the name ends with a /\n    if (path.slice(-1) != \"/\") {\n        path += \"/\"; // IE doesn't like substr(-1)\n    }\n    return path;\n};\n/**\n * Add a (sub) folder in the current folder.\n * @private\n * @param {string} name the folder's name\n * @param {boolean=} [createFolders] If true, automatically create sub\n *  folders. Defaults to false.\n * @return {Object} the new folder.\n */\nvar folderAdd = function(name, createFolders) {\n    createFolders = (typeof createFolders !== 'undefined') ? createFolders : false;\n\n    name = forceTrailingSlash(name);\n\n    // Does this folder already exist?\n    if (!this.files[name]) {\n        fileAdd.call(this, name, null, {\n            dir: true,\n            createFolders: createFolders\n        });\n    }\n    return this.files[name];\n};\n\n/**\n * Generate a JSZip.CompressedObject for a given zipOject.\n * @param {ZipObject} file the object to read.\n * @param {JSZip.compression} compression the compression to use.\n * @param {Object} compressionOptions the options to use when compressing.\n * @return {JSZip.CompressedObject} the compressed result.\n */\nvar generateCompressedObjectFrom = function(file, compression, compressionOptions) {\n    var result = new CompressedObject(),\n        content;\n\n    // the data has not been decompressed, we might reuse things !\n    if (file._data instanceof CompressedObject) {\n        result.uncompressedSize = file._data.uncompressedSize;\n        result.crc32 = file._data.crc32;\n\n        if (result.uncompressedSize === 0 || file.dir) {\n            compression = compressions['STORE'];\n            result.compressedContent = \"\";\n            result.crc32 = 0;\n        }\n        else if (file._data.compressionMethod === compression.magic) {\n            result.compressedContent = file._data.getCompressedContent();\n        }\n        else {\n            content = file._data.getContent();\n            // need to decompress / recompress\n            result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions);\n        }\n    }\n    else {\n        // have uncompressed data\n        content = getBinaryData(file);\n        if (!content || content.length === 0 || file.dir) {\n            compression = compressions['STORE'];\n            content = \"\";\n        }\n        result.uncompressedSize = content.length;\n        result.crc32 = crc32(content);\n        result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions);\n    }\n\n    result.compressedSize = result.compressedContent.length;\n    result.compressionMethod = compression.magic;\n\n    return result;\n};\n\n\n\n\n/**\n * Generate the UNIX part of the external file attributes.\n * @param {Object} unixPermissions the unix permissions or null.\n * @param {Boolean} isDir true if the entry is a directory, false otherwise.\n * @return {Number} a 32 bit integer.\n *\n * adapted from http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute :\n *\n * TTTTsstrwxrwxrwx0000000000ADVSHR\n * ^^^^____________________________ file type, see zipinfo.c (UNX_*)\n *     ^^^_________________________ setuid, setgid, sticky\n *        ^^^^^^^^^________________ permissions\n *                 ^^^^^^^^^^______ not used ?\n *                           ^^^^^^ DOS attribute bits : Archive, Directory, Volume label, System file, Hidden, Read only\n */\nvar generateUnixExternalFileAttr = function (unixPermissions, isDir) {\n\n    var result = unixPermissions;\n    if (!unixPermissions) {\n        // I can't use octal values in strict mode, hence the hexa.\n        //  040775 => 0x41fd\n        // 0100664 => 0x81b4\n        result = isDir ? 0x41fd : 0x81b4;\n    }\n\n    return (result & 0xFFFF) << 16;\n};\n\n/**\n * Generate the DOS part of the external file attributes.\n * @param {Object} dosPermissions the dos permissions or null.\n * @param {Boolean} isDir true if the entry is a directory, false otherwise.\n * @return {Number} a 32 bit integer.\n *\n * Bit 0     Read-Only\n * Bit 1     Hidden\n * Bit 2     System\n * Bit 3     Volume Label\n * Bit 4     Directory\n * Bit 5     Archive\n */\nvar generateDosExternalFileAttr = function (dosPermissions, isDir) {\n\n    // the dir flag is already set for compatibility\n\n    return (dosPermissions || 0)  & 0x3F;\n};\n\n/**\n * Generate the various parts used in the construction of the final zip file.\n * @param {string} name the file name.\n * @param {ZipObject} file the file content.\n * @param {JSZip.CompressedObject} compressedObject the compressed object.\n * @param {number} offset the current offset from the start of the zip file.\n * @param {String} platform let's pretend we are this platform (change platform dependents fields)\n * @return {object} the zip parts.\n */\nvar generateZipParts = function(name, file, compressedObject, offset, platform) {\n    var data = compressedObject.compressedContent,\n        utfEncodedFileName = utils.transformTo(\"string\", utf8.utf8encode(file.name)),\n        comment = file.comment || \"\",\n        utfEncodedComment = utils.transformTo(\"string\", utf8.utf8encode(comment)),\n        useUTF8ForFileName = utfEncodedFileName.length !== file.name.length,\n        useUTF8ForComment = utfEncodedComment.length !== comment.length,\n        o = file.options,\n        dosTime,\n        dosDate,\n        extraFields = \"\",\n        unicodePathExtraField = \"\",\n        unicodeCommentExtraField = \"\",\n        dir, date;\n\n\n    // handle the deprecated options.dir\n    if (file._initialMetadata.dir !== file.dir) {\n        dir = file.dir;\n    } else {\n        dir = o.dir;\n    }\n\n    // handle the deprecated options.date\n    if(file._initialMetadata.date !== file.date) {\n        date = file.date;\n    } else {\n        date = o.date;\n    }\n\n    var extFileAttr = 0;\n    var versionMadeBy = 0;\n    if (dir) {\n        // dos or unix, we set the dos dir flag\n        extFileAttr |= 0x00010;\n    }\n    if(platform === \"UNIX\") {\n        versionMadeBy = 0x031E; // UNIX, version 3.0\n        extFileAttr |= generateUnixExternalFileAttr(file.unixPermissions, dir);\n    } else { // DOS or other, fallback to DOS\n        versionMadeBy = 0x0014; // DOS, version 2.0\n        extFileAttr |= generateDosExternalFileAttr(file.dosPermissions, dir);\n    }\n\n    // date\n    // @see http://www.delorie.com/djgpp/doc/rbinter/it/52/13.html\n    // @see http://www.delorie.com/djgpp/doc/rbinter/it/65/16.html\n    // @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html\n\n    dosTime = date.getHours();\n    dosTime = dosTime << 6;\n    dosTime = dosTime | date.getMinutes();\n    dosTime = dosTime << 5;\n    dosTime = dosTime | date.getSeconds() / 2;\n\n    dosDate = date.getFullYear() - 1980;\n    dosDate = dosDate << 4;\n    dosDate = dosDate | (date.getMonth() + 1);\n    dosDate = dosDate << 5;\n    dosDate = dosDate | date.getDate();\n\n    if (useUTF8ForFileName) {\n        // set the unicode path extra field. unzip needs at least one extra\n        // field to correctly handle unicode path, so using the path is as good\n        // as any other information. This could improve the situation with\n        // other archive managers too.\n        // This field is usually used without the utf8 flag, with a non\n        // unicode path in the header (winrar, winzip). This helps (a bit)\n        // with the messy Windows' default compressed folders feature but\n        // breaks on p7zip which doesn't seek the unicode path extra field.\n        // So for now, UTF-8 everywhere !\n        unicodePathExtraField =\n            // Version\n            decToHex(1, 1) +\n            // NameCRC32\n            decToHex(crc32(utfEncodedFileName), 4) +\n            // UnicodeName\n            utfEncodedFileName;\n\n        extraFields +=\n            // Info-ZIP Unicode Path Extra Field\n            \"\\x75\\x70\" +\n            // size\n            decToHex(unicodePathExtraField.length, 2) +\n            // content\n            unicodePathExtraField;\n    }\n\n    if(useUTF8ForComment) {\n\n        unicodeCommentExtraField =\n            // Version\n            decToHex(1, 1) +\n            // CommentCRC32\n            decToHex(this.crc32(utfEncodedComment), 4) +\n            // UnicodeName\n            utfEncodedComment;\n\n        extraFields +=\n            // Info-ZIP Unicode Path Extra Field\n            \"\\x75\\x63\" +\n            // size\n            decToHex(unicodeCommentExtraField.length, 2) +\n            // content\n            unicodeCommentExtraField;\n    }\n\n    var header = \"\";\n\n    // version needed to extract\n    header += \"\\x0A\\x00\";\n    // general purpose bit flag\n    // set bit 11 if utf8\n    header += (useUTF8ForFileName || useUTF8ForComment) ? \"\\x00\\x08\" : \"\\x00\\x00\";\n    // compression method\n    header += compressedObject.compressionMethod;\n    // last mod file time\n    header += decToHex(dosTime, 2);\n    // last mod file date\n    header += decToHex(dosDate, 2);\n    // crc-32\n    header += decToHex(compressedObject.crc32, 4);\n    // compressed size\n    header += decToHex(compressedObject.compressedSize, 4);\n    // uncompressed size\n    header += decToHex(compressedObject.uncompressedSize, 4);\n    // file name length\n    header += decToHex(utfEncodedFileName.length, 2);\n    // extra field length\n    header += decToHex(extraFields.length, 2);\n\n\n    var fileRecord = signature.LOCAL_FILE_HEADER + header + utfEncodedFileName + extraFields;\n\n    var dirRecord = signature.CENTRAL_FILE_HEADER +\n    // version made by (00: DOS)\n    decToHex(versionMadeBy, 2) +\n    // file header (common to file and central directory)\n    header +\n    // file comment length\n    decToHex(utfEncodedComment.length, 2) +\n    // disk number start\n    \"\\x00\\x00\" +\n    // internal file attributes TODO\n    \"\\x00\\x00\" +\n    // external file attributes\n    decToHex(extFileAttr, 4) +\n    // relative offset of local header\n    decToHex(offset, 4) +\n    // file name\n    utfEncodedFileName +\n    // extra field\n    extraFields +\n    // file comment\n    utfEncodedComment;\n\n    return {\n        fileRecord: fileRecord,\n        dirRecord: dirRecord,\n        compressedObject: compressedObject\n    };\n};\n\n\n// return the actual prototype of JSZip\nvar out = {\n    /**\n     * Read an existing zip and merge the data in the current JSZip object.\n     * The implementation is in jszip-load.js, don't forget to include it.\n     * @param {String|ArrayBuffer|Uint8Array|Buffer} stream  The stream to load\n     * @param {Object} options Options for loading the stream.\n     *  options.base64 : is the stream in base64 ? default : false\n     * @return {JSZip} the current JSZip object\n     */\n    load: function(stream, options) {\n        throw new Error(\"Load method is not defined. Is the file jszip-load.js included ?\");\n    },\n\n    /**\n     * Filter nested files/folders with the specified function.\n     * @param {Function} search the predicate to use :\n     * function (relativePath, file) {...}\n     * It takes 2 arguments : the relative path and the file.\n     * @return {Array} An array of matching elements.\n     */\n    filter: function(search) {\n        var result = [],\n            filename, relativePath, file, fileClone;\n        for (filename in this.files) {\n            if (!this.files.hasOwnProperty(filename)) {\n                continue;\n            }\n            file = this.files[filename];\n            // return a new object, don't let the user mess with our internal objects :)\n            fileClone = new ZipObject(file.name, file._data, extend(file.options));\n            relativePath = filename.slice(this.root.length, filename.length);\n            if (filename.slice(0, this.root.length) === this.root && // the file is in the current root\n            search(relativePath, fileClone)) { // and the file matches the function\n                result.push(fileClone);\n            }\n        }\n        return result;\n    },\n\n    /**\n     * Add a file to the zip file, or search a file.\n     * @param   {string|RegExp} name The name of the file to add (if data is defined),\n     * the name of the file to find (if no data) or a regex to match files.\n     * @param   {String|ArrayBuffer|Uint8Array|Buffer} data  The file data, either raw or base64 encoded\n     * @param   {Object} o     File options\n     * @return  {JSZip|Object|Array} this JSZip object (when adding a file),\n     * a file (when searching by string) or an array of files (when searching by regex).\n     */\n    file: function(name, data, o) {\n        if (arguments.length === 1) {\n            if (utils.isRegExp(name)) {\n                var regexp = name;\n                return this.filter(function(relativePath, file) {\n                    return !file.dir && regexp.test(relativePath);\n                });\n            }\n            else { // text\n                return this.filter(function(relativePath, file) {\n                    return !file.dir && relativePath === name;\n                })[0] || null;\n            }\n        }\n        else { // more than one argument : we have data !\n            name = this.root + name;\n            fileAdd.call(this, name, data, o);\n        }\n        return this;\n    },\n\n    /**\n     * Add a directory to the zip file, or search.\n     * @param   {String|RegExp} arg The name of the directory to add, or a regex to search folders.\n     * @return  {JSZip} an object with the new directory as the root, or an array containing matching folders.\n     */\n    folder: function(arg) {\n        if (!arg) {\n            return this;\n        }\n\n        if (utils.isRegExp(arg)) {\n            return this.filter(function(relativePath, file) {\n                return file.dir && arg.test(relativePath);\n            });\n        }\n\n        // else, name is a new folder\n        var name = this.root + arg;\n        var newFolder = folderAdd.call(this, name);\n\n        // Allow chaining by returning a new object with this folder as the root\n        var ret = this.clone();\n        ret.root = newFolder.name;\n        return ret;\n    },\n\n    /**\n     * Delete a file, or a directory and all sub-files, from the zip\n     * @param {string} name the name of the file to delete\n     * @return {JSZip} this JSZip object\n     */\n    remove: function(name) {\n        name = this.root + name;\n        var file = this.files[name];\n        if (!file) {\n            // Look for any folders\n            if (name.slice(-1) != \"/\") {\n                name += \"/\";\n            }\n            file = this.files[name];\n        }\n\n        if (file && !file.dir) {\n            // file\n            delete this.files[name];\n        } else {\n            // maybe a folder, delete recursively\n            var kids = this.filter(function(relativePath, file) {\n                return file.name.slice(0, name.length) === name;\n            });\n            for (var i = 0; i < kids.length; i++) {\n                delete this.files[kids[i].name];\n            }\n        }\n\n        return this;\n    },\n\n    /**\n     * Generate the complete zip file\n     * @param {Object} options the options to generate the zip file :\n     * - base64, (deprecated, use type instead) true to generate base64.\n     * - compression, \"STORE\" by default.\n     * - type, \"base64\" by default. Values are : string, base64, uint8array, arraybuffer, blob.\n     * @return {String|Uint8Array|ArrayBuffer|Buffer|Blob} the zip file\n     */\n    generate: function(options) {\n        options = extend(options || {}, {\n            base64: true,\n            compression: \"STORE\",\n            compressionOptions : null,\n            type: \"base64\",\n            platform: \"DOS\",\n            comment: null,\n            mimeType: 'application/zip'\n        });\n\n        utils.checkSupport(options.type);\n\n        // accept nodejs `process.platform`\n        if(\n          options.platform === 'darwin' ||\n          options.platform === 'freebsd' ||\n          options.platform === 'linux' ||\n          options.platform === 'sunos'\n        ) {\n          options.platform = \"UNIX\";\n        }\n        if (options.platform === 'win32') {\n          options.platform = \"DOS\";\n        }\n\n        var zipData = [],\n            localDirLength = 0,\n            centralDirLength = 0,\n            writer, i,\n            utfEncodedComment = utils.transformTo(\"string\", this.utf8encode(options.comment || this.comment || \"\"));\n\n        // first, generate all the zip parts.\n        for (var name in this.files) {\n            if (!this.files.hasOwnProperty(name)) {\n                continue;\n            }\n            var file = this.files[name];\n\n            var compressionName = file.options.compression || options.compression.toUpperCase();\n            var compression = compressions[compressionName];\n            if (!compression) {\n                throw new Error(compressionName + \" is not a valid compression method !\");\n            }\n            var compressionOptions = file.options.compressionOptions || options.compressionOptions || {};\n\n            var compressedObject = generateCompressedObjectFrom.call(this, file, compression, compressionOptions);\n\n            var zipPart = generateZipParts.call(this, name, file, compressedObject, localDirLength, options.platform);\n            localDirLength += zipPart.fileRecord.length + compressedObject.compressedSize;\n            centralDirLength += zipPart.dirRecord.length;\n            zipData.push(zipPart);\n        }\n\n        var dirEnd = \"\";\n\n        // end of central dir signature\n        dirEnd = signature.CENTRAL_DIRECTORY_END +\n        // number of this disk\n        \"\\x00\\x00\" +\n        // number of the disk with the start of the central directory\n        \"\\x00\\x00\" +\n        // total number of entries in the central directory on this disk\n        decToHex(zipData.length, 2) +\n        // total number of entries in the central directory\n        decToHex(zipData.length, 2) +\n        // size of the central directory   4 bytes\n        decToHex(centralDirLength, 4) +\n        // offset of start of central directory with respect to the starting disk number\n        decToHex(localDirLength, 4) +\n        // .ZIP file comment length\n        decToHex(utfEncodedComment.length, 2) +\n        // .ZIP file comment\n        utfEncodedComment;\n\n\n        // we have all the parts (and the total length)\n        // time to create a writer !\n        var typeName = options.type.toLowerCase();\n        if(typeName===\"uint8array\"||typeName===\"arraybuffer\"||typeName===\"blob\"||typeName===\"nodebuffer\") {\n            writer = new Uint8ArrayWriter(localDirLength + centralDirLength + dirEnd.length);\n        }else{\n            writer = new StringWriter(localDirLength + centralDirLength + dirEnd.length);\n        }\n\n        for (i = 0; i < zipData.length; i++) {\n            writer.append(zipData[i].fileRecord);\n            writer.append(zipData[i].compressedObject.compressedContent);\n        }\n        for (i = 0; i < zipData.length; i++) {\n            writer.append(zipData[i].dirRecord);\n        }\n\n        writer.append(dirEnd);\n\n        var zip = writer.finalize();\n\n\n\n        switch(options.type.toLowerCase()) {\n            // case \"zip is an Uint8Array\"\n            case \"uint8array\" :\n            case \"arraybuffer\" :\n            case \"nodebuffer\" :\n               return utils.transformTo(options.type.toLowerCase(), zip);\n            case \"blob\" :\n               return utils.arrayBuffer2Blob(utils.transformTo(\"arraybuffer\", zip), options.mimeType);\n            // case \"zip is a string\"\n            case \"base64\" :\n               return (options.base64) ? base64.encode(zip) : zip;\n            default : // case \"string\" :\n               return zip;\n         }\n\n    },\n\n    /**\n     * @deprecated\n     * This method will be removed in a future version without replacement.\n     */\n    crc32: function (input, crc) {\n        return crc32(input, crc);\n    },\n\n    /**\n     * @deprecated\n     * This method will be removed in a future version without replacement.\n     */\n    utf8encode: function (string) {\n        return utils.transformTo(\"string\", utf8.utf8encode(string));\n    },\n\n    /**\n     * @deprecated\n     * This method will be removed in a future version without replacement.\n     */\n    utf8decode: function (input) {\n        return utf8.utf8decode(input);\n    }\n};\nmodule.exports = out;\n\n},{\"./base64\":1,\"./compressedObject\":2,\"./compressions\":3,\"./crc32\":4,\"./defaults\":6,\"./nodeBuffer\":11,\"./signature\":14,\"./stringWriter\":16,\"./support\":17,\"./uint8ArrayWriter\":19,\"./utf8\":20,\"./utils\":21}],14:[function(_dereq_,module,exports){\n'use strict';\nexports.LOCAL_FILE_HEADER = \"PK\\x03\\x04\";\nexports.CENTRAL_FILE_HEADER = \"PK\\x01\\x02\";\nexports.CENTRAL_DIRECTORY_END = \"PK\\x05\\x06\";\nexports.ZIP64_CENTRAL_DIRECTORY_LOCATOR = \"PK\\x06\\x07\";\nexports.ZIP64_CENTRAL_DIRECTORY_END = \"PK\\x06\\x06\";\nexports.DATA_DESCRIPTOR = \"PK\\x07\\x08\";\n\n},{}],15:[function(_dereq_,module,exports){\n'use strict';\nvar DataReader = _dereq_('./dataReader');\nvar utils = _dereq_('./utils');\n\nfunction StringReader(data, optimizedBinaryString) {\n    this.data = data;\n    if (!optimizedBinaryString) {\n        this.data = utils.string2binary(this.data);\n    }\n    this.length = this.data.length;\n    this.index = 0;\n}\nStringReader.prototype = new DataReader();\n/**\n * @see DataReader.byteAt\n */\nStringReader.prototype.byteAt = function(i) {\n    return this.data.charCodeAt(i);\n};\n/**\n * @see DataReader.lastIndexOfSignature\n */\nStringReader.prototype.lastIndexOfSignature = function(sig) {\n    return this.data.lastIndexOf(sig);\n};\n/**\n * @see DataReader.readData\n */\nStringReader.prototype.readData = function(size) {\n    this.checkOffset(size);\n    // this will work because the constructor applied the \"& 0xff\" mask.\n    var result = this.data.slice(this.index, this.index + size);\n    this.index += size;\n    return result;\n};\nmodule.exports = StringReader;\n\n},{\"./dataReader\":5,\"./utils\":21}],16:[function(_dereq_,module,exports){\n'use strict';\n\nvar utils = _dereq_('./utils');\n\n/**\n * An object to write any content to a string.\n * @constructor\n */\nvar StringWriter = function() {\n    this.data = [];\n};\nStringWriter.prototype = {\n    /**\n     * Append any content to the current string.\n     * @param {Object} input the content to add.\n     */\n    append: function(input) {\n        input = utils.transformTo(\"string\", input);\n        this.data.push(input);\n    },\n    /**\n     * Finalize the construction an return the result.\n     * @return {string} the generated string.\n     */\n    finalize: function() {\n        return this.data.join(\"\");\n    }\n};\n\nmodule.exports = StringWriter;\n\n},{\"./utils\":21}],17:[function(_dereq_,module,exports){\n(function (Buffer){\n'use strict';\nexports.base64 = true;\nexports.array = true;\nexports.string = true;\nexports.arraybuffer = typeof ArrayBuffer !== \"undefined\" && typeof Uint8Array !== \"undefined\";\n// contains true if JSZip can read/generate nodejs Buffer, false otherwise.\n// Browserify will provide a Buffer implementation for browsers, which is\n// an augmented Uint8Array (i.e., can be used as either Buffer or U8).\nexports.nodebuffer = typeof Buffer !== \"undefined\";\n// contains true if JSZip can read/generate Uint8Array, false otherwise.\nexports.uint8array = typeof Uint8Array !== \"undefined\";\n\nif (typeof ArrayBuffer === \"undefined\") {\n    exports.blob = false;\n}\nelse {\n    var buffer = new ArrayBuffer(0);\n    try {\n        exports.blob = new Blob([buffer], {\n            type: \"application/zip\"\n        }).size === 0;\n    }\n    catch (e) {\n        try {\n            var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;\n            var builder = new Builder();\n            builder.append(buffer);\n            exports.blob = builder.getBlob('application/zip').size === 0;\n        }\n        catch (e) {\n            exports.blob = false;\n        }\n    }\n}\n\n}).call(this,(typeof Buffer !== \"undefined\" ? Buffer : undefined))\n},{}],18:[function(_dereq_,module,exports){\n'use strict';\nvar DataReader = _dereq_('./dataReader');\n\nfunction Uint8ArrayReader(data) {\n    if (data) {\n        this.data = data;\n        this.length = this.data.length;\n        this.index = 0;\n    }\n}\nUint8ArrayReader.prototype = new DataReader();\n/**\n * @see DataReader.byteAt\n */\nUint8ArrayReader.prototype.byteAt = function(i) {\n    return this.data[i];\n};\n/**\n * @see DataReader.lastIndexOfSignature\n */\nUint8ArrayReader.prototype.lastIndexOfSignature = function(sig) {\n    var sig0 = sig.charCodeAt(0),\n        sig1 = sig.charCodeAt(1),\n        sig2 = sig.charCodeAt(2),\n        sig3 = sig.charCodeAt(3);\n    for (var i = this.length - 4; i >= 0; --i) {\n        if (this.data[i] === sig0 && this.data[i + 1] === sig1 && this.data[i + 2] === sig2 && this.data[i + 3] === sig3) {\n            return i;\n        }\n    }\n\n    return -1;\n};\n/**\n * @see DataReader.readData\n */\nUint8ArrayReader.prototype.readData = function(size) {\n    this.checkOffset(size);\n    if(size === 0) {\n        // in IE10, when using subarray(idx, idx), we get the array [0x00] instead of [].\n        return new Uint8Array(0);\n    }\n    var result = this.data.subarray(this.index, this.index + size);\n    this.index += size;\n    return result;\n};\nmodule.exports = Uint8ArrayReader;\n\n},{\"./dataReader\":5}],19:[function(_dereq_,module,exports){\n'use strict';\n\nvar utils = _dereq_('./utils');\n\n/**\n * An object to write any content to an Uint8Array.\n * @constructor\n * @param {number} length The length of the array.\n */\nvar Uint8ArrayWriter = function(length) {\n    this.data = new Uint8Array(length);\n    this.index = 0;\n};\nUint8ArrayWriter.prototype = {\n    /**\n     * Append any content to the current array.\n     * @param {Object} input the content to add.\n     */\n    append: function(input) {\n        if (input.length !== 0) {\n            // with an empty Uint8Array, Opera fails with a \"Offset larger than array size\"\n            input = utils.transformTo(\"uint8array\", input);\n            this.data.set(input, this.index);\n            this.index += input.length;\n        }\n    },\n    /**\n     * Finalize the construction an return the result.\n     * @return {Uint8Array} the generated array.\n     */\n    finalize: function() {\n        return this.data;\n    }\n};\n\nmodule.exports = Uint8ArrayWriter;\n\n},{\"./utils\":21}],20:[function(_dereq_,module,exports){\n'use strict';\n\nvar utils = _dereq_('./utils');\nvar support = _dereq_('./support');\nvar nodeBuffer = _dereq_('./nodeBuffer');\n\n/**\n * The following functions come from pako, from pako/lib/utils/strings\n * released under the MIT license, see pako https://github.com/nodeca/pako/\n */\n\n// Table with utf8 lengths (calculated by first byte of sequence)\n// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,\n// because max possible codepoint is 0x10ffff\nvar _utf8len = new Array(256);\nfor (var i=0; i<256; i++) {\n  _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1);\n}\n_utf8len[254]=_utf8len[254]=1; // Invalid sequence start\n\n// convert string to array (typed, when possible)\nvar string2buf = function (str) {\n    var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;\n\n    // count binary size\n    for (m_pos = 0; m_pos < str_len; m_pos++) {\n        c = str.charCodeAt(m_pos);\n        if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {\n            c2 = str.charCodeAt(m_pos+1);\n            if ((c2 & 0xfc00) === 0xdc00) {\n                c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);\n                m_pos++;\n            }\n        }\n        buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;\n    }\n\n    // allocate buffer\n    if (support.uint8array) {\n        buf = new Uint8Array(buf_len);\n    } else {\n        buf = new Array(buf_len);\n    }\n\n    // convert\n    for (i=0, m_pos = 0; i < buf_len; m_pos++) {\n        c = str.charCodeAt(m_pos);\n        if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {\n            c2 = str.charCodeAt(m_pos+1);\n            if ((c2 & 0xfc00) === 0xdc00) {\n                c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);\n                m_pos++;\n            }\n        }\n        if (c < 0x80) {\n            /* one byte */\n            buf[i++] = c;\n        } else if (c < 0x800) {\n            /* two bytes */\n            buf[i++] = 0xC0 | (c >>> 6);\n            buf[i++] = 0x80 | (c & 0x3f);\n        } else if (c < 0x10000) {\n            /* three bytes */\n            buf[i++] = 0xE0 | (c >>> 12);\n            buf[i++] = 0x80 | (c >>> 6 & 0x3f);\n            buf[i++] = 0x80 | (c & 0x3f);\n        } else {\n            /* four bytes */\n            buf[i++] = 0xf0 | (c >>> 18);\n            buf[i++] = 0x80 | (c >>> 12 & 0x3f);\n            buf[i++] = 0x80 | (c >>> 6 & 0x3f);\n            buf[i++] = 0x80 | (c & 0x3f);\n        }\n    }\n\n    return buf;\n};\n\n// Calculate max possible position in utf8 buffer,\n// that will not break sequence. If that's not possible\n// - (very small limits) return max size as is.\n//\n// buf[] - utf8 bytes array\n// max   - length limit (mandatory);\nvar utf8border = function(buf, max) {\n    var pos;\n\n    max = max || buf.length;\n    if (max > buf.length) { max = buf.length; }\n\n    // go back from last position, until start of sequence found\n    pos = max-1;\n    while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }\n\n    // Fuckup - very small and broken sequence,\n    // return max, because we should return something anyway.\n    if (pos < 0) { return max; }\n\n    // If we came to start of buffer - that means vuffer is too small,\n    // return max too.\n    if (pos === 0) { return max; }\n\n    return (pos + _utf8len[buf[pos]] > max) ? pos : max;\n};\n\n// convert array to string\nvar buf2string = function (buf) {\n    var str, i, out, c, c_len;\n    var len = buf.length;\n\n    // Reserve max possible length (2 words per char)\n    // NB: by unknown reasons, Array is significantly faster for\n    //     String.fromCharCode.apply than Uint16Array.\n    var utf16buf = new Array(len*2);\n\n    for (out=0, i=0; i<len;) {\n        c = buf[i++];\n        // quick process ascii\n        if (c < 0x80) { utf16buf[out++] = c; continue; }\n\n        c_len = _utf8len[c];\n        // skip 5 & 6 byte codes\n        if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; }\n\n        // apply mask on first byte\n        c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;\n        // join the rest\n        while (c_len > 1 && i < len) {\n            c = (c << 6) | (buf[i++] & 0x3f);\n            c_len--;\n        }\n\n        // terminated by end of string?\n        if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }\n\n        if (c < 0x10000) {\n            utf16buf[out++] = c;\n        } else {\n            c -= 0x10000;\n            utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);\n            utf16buf[out++] = 0xdc00 | (c & 0x3ff);\n        }\n    }\n\n    // shrinkBuf(utf16buf, out)\n    if (utf16buf.length !== out) {\n        if(utf16buf.subarray) {\n            utf16buf = utf16buf.subarray(0, out);\n        } else {\n            utf16buf.length = out;\n        }\n    }\n\n    // return String.fromCharCode.apply(null, utf16buf);\n    return utils.applyFromCharCode(utf16buf);\n};\n\n\n// That's all for the pako functions.\n\n\n/**\n * Transform a javascript string into an array (typed if possible) of bytes,\n * UTF-8 encoded.\n * @param {String} str the string to encode\n * @return {Array|Uint8Array|Buffer} the UTF-8 encoded string.\n */\nexports.utf8encode = function utf8encode(str) {\n    if (support.nodebuffer) {\n        return nodeBuffer(str, \"utf-8\");\n    }\n\n    return string2buf(str);\n};\n\n\n/**\n * Transform a bytes array (or a representation) representing an UTF-8 encoded\n * string into a javascript string.\n * @param {Array|Uint8Array|Buffer} buf the data de decode\n * @return {String} the decoded string.\n */\nexports.utf8decode = function utf8decode(buf) {\n    if (support.nodebuffer) {\n        return utils.transformTo(\"nodebuffer\", buf).toString(\"utf-8\");\n    }\n\n    buf = utils.transformTo(support.uint8array ? \"uint8array\" : \"array\", buf);\n\n    // return buf2string(buf);\n    // Chrome prefers to work with \"small\" chunks of data\n    // for the method buf2string.\n    // Firefox and Chrome has their own shortcut, IE doesn't seem to really care.\n    var result = [], k = 0, len = buf.length, chunk = 65536;\n    while (k < len) {\n        var nextBoundary = utf8border(buf, Math.min(k + chunk, len));\n        if (support.uint8array) {\n            result.push(buf2string(buf.subarray(k, nextBoundary)));\n        } else {\n            result.push(buf2string(buf.slice(k, nextBoundary)));\n        }\n        k = nextBoundary;\n    }\n    return result.join(\"\");\n\n};\n// vim: set shiftwidth=4 softtabstop=4:\n\n},{\"./nodeBuffer\":11,\"./support\":17,\"./utils\":21}],21:[function(_dereq_,module,exports){\n'use strict';\nvar support = _dereq_('./support');\nvar compressions = _dereq_('./compressions');\nvar nodeBuffer = _dereq_('./nodeBuffer');\n/**\n * Convert a string to a \"binary string\" : a string containing only char codes between 0 and 255.\n * @param {string} str the string to transform.\n * @return {String} the binary string.\n */\nexports.string2binary = function(str) {\n    var result = \"\";\n    for (var i = 0; i < str.length; i++) {\n        result += String.fromCharCode(str.charCodeAt(i) & 0xff);\n    }\n    return result;\n};\nexports.arrayBuffer2Blob = function(buffer, mimeType) {\n    exports.checkSupport(\"blob\");\n\tmimeType = mimeType || 'application/zip';\n\n    try {\n        // Blob constructor\n        return new Blob([buffer], {\n            type: mimeType\n        });\n    }\n    catch (e) {\n\n        try {\n            // deprecated, browser only, old way\n            var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;\n            var builder = new Builder();\n            builder.append(buffer);\n            return builder.getBlob(mimeType);\n        }\n        catch (e) {\n\n            // well, fuck ?!\n            throw new Error(\"Bug : can't construct the Blob.\");\n        }\n    }\n\n\n};\n/**\n * The identity function.\n * @param {Object} input the input.\n * @return {Object} the same input.\n */\nfunction identity(input) {\n    return input;\n}\n\n/**\n * Fill in an array with a string.\n * @param {String} str the string to use.\n * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to fill in (will be mutated).\n * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated array.\n */\nfunction stringToArrayLike(str, array) {\n    for (var i = 0; i < str.length; ++i) {\n        array[i] = str.charCodeAt(i) & 0xFF;\n    }\n    return array;\n}\n\n/**\n * Transform an array-like object to a string.\n * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to transform.\n * @return {String} the result.\n */\nfunction arrayLikeToString(array) {\n    // Performances notes :\n    // --------------------\n    // String.fromCharCode.apply(null, array) is the fastest, see\n    // see http://jsperf.com/converting-a-uint8array-to-a-string/2\n    // but the stack is limited (and we can get huge arrays !).\n    //\n    // result += String.fromCharCode(array[i]); generate too many strings !\n    //\n    // This code is inspired by http://jsperf.com/arraybuffer-to-string-apply-performance/2\n    var chunk = 65536;\n    var result = [],\n        len = array.length,\n        type = exports.getTypeOf(array),\n        k = 0,\n        canUseApply = true;\n      try {\n         switch(type) {\n            case \"uint8array\":\n               String.fromCharCode.apply(null, new Uint8Array(0));\n               break;\n            case \"nodebuffer\":\n               String.fromCharCode.apply(null, nodeBuffer(0));\n               break;\n         }\n      } catch(e) {\n         canUseApply = false;\n      }\n\n      // no apply : slow and painful algorithm\n      // default browser on android 4.*\n      if (!canUseApply) {\n         var resultStr = \"\";\n         for(var i = 0; i < array.length;i++) {\n            resultStr += String.fromCharCode(array[i]);\n         }\n    return resultStr;\n    }\n    while (k < len && chunk > 1) {\n        try {\n            if (type === \"array\" || type === \"nodebuffer\") {\n                result.push(String.fromCharCode.apply(null, array.slice(k, Math.min(k + chunk, len))));\n            }\n            else {\n                result.push(String.fromCharCode.apply(null, array.subarray(k, Math.min(k + chunk, len))));\n            }\n            k += chunk;\n        }\n        catch (e) {\n            chunk = Math.floor(chunk / 2);\n        }\n    }\n    return result.join(\"\");\n}\n\nexports.applyFromCharCode = arrayLikeToString;\n\n\n/**\n * Copy the data from an array-like to an other array-like.\n * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayFrom the origin array.\n * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayTo the destination array which will be mutated.\n * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated destination array.\n */\nfunction arrayLikeToArrayLike(arrayFrom, arrayTo) {\n    for (var i = 0; i < arrayFrom.length; i++) {\n        arrayTo[i] = arrayFrom[i];\n    }\n    return arrayTo;\n}\n\n// a matrix containing functions to transform everything into everything.\nvar transform = {};\n\n// string to ?\ntransform[\"string\"] = {\n    \"string\": identity,\n    \"array\": function(input) {\n        return stringToArrayLike(input, new Array(input.length));\n    },\n    \"arraybuffer\": function(input) {\n        return transform[\"string\"][\"uint8array\"](input).buffer;\n    },\n    \"uint8array\": function(input) {\n        return stringToArrayLike(input, new Uint8Array(input.length));\n    },\n    \"nodebuffer\": function(input) {\n        return stringToArrayLike(input, nodeBuffer(input.length));\n    }\n};\n\n// array to ?\ntransform[\"array\"] = {\n    \"string\": arrayLikeToString,\n    \"array\": identity,\n    \"arraybuffer\": function(input) {\n        return (new Uint8Array(input)).buffer;\n    },\n    \"uint8array\": function(input) {\n        return new Uint8Array(input);\n    },\n    \"nodebuffer\": function(input) {\n        return nodeBuffer(input);\n    }\n};\n\n// arraybuffer to ?\ntransform[\"arraybuffer\"] = {\n    \"string\": function(input) {\n        return arrayLikeToString(new Uint8Array(input));\n    },\n    \"array\": function(input) {\n        return arrayLikeToArrayLike(new Uint8Array(input), new Array(input.byteLength));\n    },\n    \"arraybuffer\": identity,\n    \"uint8array\": function(input) {\n        return new Uint8Array(input);\n    },\n    \"nodebuffer\": function(input) {\n        return nodeBuffer(new Uint8Array(input));\n    }\n};\n\n// uint8array to ?\ntransform[\"uint8array\"] = {\n    \"string\": arrayLikeToString,\n    \"array\": function(input) {\n        return arrayLikeToArrayLike(input, new Array(input.length));\n    },\n    \"arraybuffer\": function(input) {\n        return input.buffer;\n    },\n    \"uint8array\": identity,\n    \"nodebuffer\": function(input) {\n        return nodeBuffer(input);\n    }\n};\n\n// nodebuffer to ?\ntransform[\"nodebuffer\"] = {\n    \"string\": arrayLikeToString,\n    \"array\": function(input) {\n        return arrayLikeToArrayLike(input, new Array(input.length));\n    },\n    \"arraybuffer\": function(input) {\n        return transform[\"nodebuffer\"][\"uint8array\"](input).buffer;\n    },\n    \"uint8array\": function(input) {\n        return arrayLikeToArrayLike(input, new Uint8Array(input.length));\n    },\n    \"nodebuffer\": identity\n};\n\n/**\n * Transform an input into any type.\n * The supported output type are : string, array, uint8array, arraybuffer, nodebuffer.\n * If no output type is specified, the unmodified input will be returned.\n * @param {String} outputType the output type.\n * @param {String|Array|ArrayBuffer|Uint8Array|Buffer} input the input to convert.\n * @throws {Error} an Error if the browser doesn't support the requested output type.\n */\nexports.transformTo = function(outputType, input) {\n    if (!input) {\n        // undefined, null, etc\n        // an empty string won't harm.\n        input = \"\";\n    }\n    if (!outputType) {\n        return input;\n    }\n    exports.checkSupport(outputType);\n    var inputType = exports.getTypeOf(input);\n    var result = transform[inputType][outputType](input);\n    return result;\n};\n\n/**\n * Return the type of the input.\n * The type will be in a format valid for JSZip.utils.transformTo : string, array, uint8array, arraybuffer.\n * @param {Object} input the input to identify.\n * @return {String} the (lowercase) type of the input.\n */\nexports.getTypeOf = function(input) {\n    if (typeof input === \"string\") {\n        return \"string\";\n    }\n    if (Object.prototype.toString.call(input) === \"[object Array]\") {\n        return \"array\";\n    }\n    if (support.nodebuffer && nodeBuffer.test(input)) {\n        return \"nodebuffer\";\n    }\n    if (support.uint8array && input instanceof Uint8Array) {\n        return \"uint8array\";\n    }\n    if (support.arraybuffer && input instanceof ArrayBuffer) {\n        return \"arraybuffer\";\n    }\n};\n\n/**\n * Throw an exception if the type is not supported.\n * @param {String} type the type to check.\n * @throws {Error} an Error if the browser doesn't support the requested type.\n */\nexports.checkSupport = function(type) {\n    var supported = support[type.toLowerCase()];\n    if (!supported) {\n        throw new Error(type + \" is not supported by this browser\");\n    }\n};\nexports.MAX_VALUE_16BITS = 65535;\nexports.MAX_VALUE_32BITS = -1; // well, \"\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\" is parsed as -1\n\n/**\n * Prettify a string read as binary.\n * @param {string} str the string to prettify.\n * @return {string} a pretty string.\n */\nexports.pretty = function(str) {\n    var res = '',\n        code, i;\n    for (i = 0; i < (str || \"\").length; i++) {\n        code = str.charCodeAt(i);\n        res += '\\\\x' + (code < 16 ? \"0\" : \"\") + code.toString(16).toUpperCase();\n    }\n    return res;\n};\n\n/**\n * Find a compression registered in JSZip.\n * @param {string} compressionMethod the method magic to find.\n * @return {Object|null} the JSZip compression object, null if none found.\n */\nexports.findCompression = function(compressionMethod) {\n    for (var method in compressions) {\n        if (!compressions.hasOwnProperty(method)) {\n            continue;\n        }\n        if (compressions[method].magic === compressionMethod) {\n            return compressions[method];\n        }\n    }\n    return null;\n};\n/**\n* Cross-window, cross-Node-context regular expression detection\n* @param  {Object}  object Anything\n* @return {Boolean}        true if the object is a regular expression,\n* false otherwise\n*/\nexports.isRegExp = function (object) {\n    return Object.prototype.toString.call(object) === \"[object RegExp]\";\n};\n\n\n},{\"./compressions\":3,\"./nodeBuffer\":11,\"./support\":17}],22:[function(_dereq_,module,exports){\n'use strict';\nvar StringReader = _dereq_('./stringReader');\nvar NodeBufferReader = _dereq_('./nodeBufferReader');\nvar Uint8ArrayReader = _dereq_('./uint8ArrayReader');\nvar utils = _dereq_('./utils');\nvar sig = _dereq_('./signature');\nvar ZipEntry = _dereq_('./zipEntry');\nvar support = _dereq_('./support');\nvar jszipProto = _dereq_('./object');\n//  class ZipEntries {{{\n/**\n * All the entries in the zip file.\n * @constructor\n * @param {String|ArrayBuffer|Uint8Array} data the binary stream to load.\n * @param {Object} loadOptions Options for loading the stream.\n */\nfunction ZipEntries(data, loadOptions) {\n    this.files = [];\n    this.loadOptions = loadOptions;\n    if (data) {\n        this.load(data);\n    }\n}\nZipEntries.prototype = {\n    /**\n     * Check that the reader is on the speficied signature.\n     * @param {string} expectedSignature the expected signature.\n     * @throws {Error} if it is an other signature.\n     */\n    checkSignature: function(expectedSignature) {\n        var signature = this.reader.readString(4);\n        if (signature !== expectedSignature) {\n            throw new Error(\"Corrupted zip or bug : unexpected signature \" + \"(\" + utils.pretty(signature) + \", expected \" + utils.pretty(expectedSignature) + \")\");\n        }\n    },\n    /**\n     * Read the end of the central directory.\n     */\n    readBlockEndOfCentral: function() {\n        this.diskNumber = this.reader.readInt(2);\n        this.diskWithCentralDirStart = this.reader.readInt(2);\n        this.centralDirRecordsOnThisDisk = this.reader.readInt(2);\n        this.centralDirRecords = this.reader.readInt(2);\n        this.centralDirSize = this.reader.readInt(4);\n        this.centralDirOffset = this.reader.readInt(4);\n\n        this.zipCommentLength = this.reader.readInt(2);\n        // warning : the encoding depends of the system locale\n        // On a linux machine with LANG=en_US.utf8, this field is utf8 encoded.\n        // On a windows machine, this field is encoded with the localized windows code page.\n        this.zipComment = this.reader.readString(this.zipCommentLength);\n        // To get consistent behavior with the generation part, we will assume that\n        // this is utf8 encoded.\n        this.zipComment = jszipProto.utf8decode(this.zipComment);\n    },\n    /**\n     * Read the end of the Zip 64 central directory.\n     * Not merged with the method readEndOfCentral :\n     * The end of central can coexist with its Zip64 brother,\n     * I don't want to read the wrong number of bytes !\n     */\n    readBlockZip64EndOfCentral: function() {\n        this.zip64EndOfCentralSize = this.reader.readInt(8);\n        this.versionMadeBy = this.reader.readString(2);\n        this.versionNeeded = this.reader.readInt(2);\n        this.diskNumber = this.reader.readInt(4);\n        this.diskWithCentralDirStart = this.reader.readInt(4);\n        this.centralDirRecordsOnThisDisk = this.reader.readInt(8);\n        this.centralDirRecords = this.reader.readInt(8);\n        this.centralDirSize = this.reader.readInt(8);\n        this.centralDirOffset = this.reader.readInt(8);\n\n        this.zip64ExtensibleData = {};\n        var extraDataSize = this.zip64EndOfCentralSize - 44,\n            index = 0,\n            extraFieldId,\n            extraFieldLength,\n            extraFieldValue;\n        while (index < extraDataSize) {\n            extraFieldId = this.reader.readInt(2);\n            extraFieldLength = this.reader.readInt(4);\n            extraFieldValue = this.reader.readString(extraFieldLength);\n            this.zip64ExtensibleData[extraFieldId] = {\n                id: extraFieldId,\n                length: extraFieldLength,\n                value: extraFieldValue\n            };\n        }\n    },\n    /**\n     * Read the end of the Zip 64 central directory locator.\n     */\n    readBlockZip64EndOfCentralLocator: function() {\n        this.diskWithZip64CentralDirStart = this.reader.readInt(4);\n        this.relativeOffsetEndOfZip64CentralDir = this.reader.readInt(8);\n        this.disksCount = this.reader.readInt(4);\n        if (this.disksCount > 1) {\n            throw new Error(\"Multi-volumes zip are not supported\");\n        }\n    },\n    /**\n     * Read the local files, based on the offset read in the central part.\n     */\n    readLocalFiles: function() {\n        var i, file;\n        for (i = 0; i < this.files.length; i++) {\n            file = this.files[i];\n            this.reader.setIndex(file.localHeaderOffset);\n            this.checkSignature(sig.LOCAL_FILE_HEADER);\n            file.readLocalPart(this.reader);\n            file.handleUTF8();\n            file.processAttributes();\n        }\n    },\n    /**\n     * Read the central directory.\n     */\n    readCentralDir: function() {\n        var file;\n\n        this.reader.setIndex(this.centralDirOffset);\n        while (this.reader.readString(4) === sig.CENTRAL_FILE_HEADER) {\n            file = new ZipEntry({\n                zip64: this.zip64\n            }, this.loadOptions);\n            file.readCentralPart(this.reader);\n            this.files.push(file);\n        }\n    },\n    /**\n     * Read the end of central directory.\n     */\n    readEndOfCentral: function() {\n        var offset = this.reader.lastIndexOfSignature(sig.CENTRAL_DIRECTORY_END);\n        if (offset === -1) {\n            // Check if the content is a truncated zip or complete garbage.\n            // A \"LOCAL_FILE_HEADER\" is not required at the beginning (auto\n            // extractible zip for example) but it can give a good hint.\n            // If an ajax request was used without responseType, we will also\n            // get unreadable data.\n            var isGarbage = true;\n            try {\n                this.reader.setIndex(0);\n                this.checkSignature(sig.LOCAL_FILE_HEADER);\n                isGarbage = false;\n            } catch (e) {}\n\n            if (isGarbage) {\n                throw new Error(\"Can't find end of central directory : is this a zip file ? \" +\n                                \"If it is, see http://stuk.github.io/jszip/documentation/howto/read_zip.html\");\n            } else {\n                throw new Error(\"Corrupted zip : can't find end of central directory\");\n            }\n        }\n        this.reader.setIndex(offset);\n        this.checkSignature(sig.CENTRAL_DIRECTORY_END);\n        this.readBlockEndOfCentral();\n\n\n        /* extract from the zip spec :\n            4)  If one of the fields in the end of central directory\n                record is too small to hold required data, the field\n                should be set to -1 (0xFFFF or 0xFFFFFFFF) and the\n                ZIP64 format record should be created.\n            5)  The end of central directory record and the\n                Zip64 end of central directory locator record must\n                reside on the same disk when splitting or spanning\n                an archive.\n         */\n        if (this.diskNumber === utils.MAX_VALUE_16BITS || this.diskWithCentralDirStart === utils.MAX_VALUE_16BITS || this.centralDirRecordsOnThisDisk === utils.MAX_VALUE_16BITS || this.centralDirRecords === utils.MAX_VALUE_16BITS || this.centralDirSize === utils.MAX_VALUE_32BITS || this.centralDirOffset === utils.MAX_VALUE_32BITS) {\n            this.zip64 = true;\n\n            /*\n            Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from\n            the zip file can fit into a 32bits integer. This cannot be solved : Javascript represents\n            all numbers as 64-bit double precision IEEE 754 floating point numbers.\n            So, we have 53bits for integers and bitwise operations treat everything as 32bits.\n            see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators\n            and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf section 8.5\n            */\n\n            // should look for a zip64 EOCD locator\n            offset = this.reader.lastIndexOfSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR);\n            if (offset === -1) {\n                throw new Error(\"Corrupted zip : can't find the ZIP64 end of central directory locator\");\n            }\n            this.reader.setIndex(offset);\n            this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR);\n            this.readBlockZip64EndOfCentralLocator();\n\n            // now the zip64 EOCD record\n            this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir);\n            this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_END);\n            this.readBlockZip64EndOfCentral();\n        }\n    },\n    prepareReader: function(data) {\n        var type = utils.getTypeOf(data);\n        if (type === \"string\" && !support.uint8array) {\n            this.reader = new StringReader(data, this.loadOptions.optimizedBinaryString);\n        }\n        else if (type === \"nodebuffer\") {\n            this.reader = new NodeBufferReader(data);\n        }\n        else {\n            this.reader = new Uint8ArrayReader(utils.transformTo(\"uint8array\", data));\n        }\n    },\n    /**\n     * Read a zip file and create ZipEntries.\n     * @param {String|ArrayBuffer|Uint8Array|Buffer} data the binary string representing a zip file.\n     */\n    load: function(data) {\n        this.prepareReader(data);\n        this.readEndOfCentral();\n        this.readCentralDir();\n        this.readLocalFiles();\n    }\n};\n// }}} end of ZipEntries\nmodule.exports = ZipEntries;\n\n},{\"./nodeBufferReader\":12,\"./object\":13,\"./signature\":14,\"./stringReader\":15,\"./support\":17,\"./uint8ArrayReader\":18,\"./utils\":21,\"./zipEntry\":23}],23:[function(_dereq_,module,exports){\n'use strict';\nvar StringReader = _dereq_('./stringReader');\nvar utils = _dereq_('./utils');\nvar CompressedObject = _dereq_('./compressedObject');\nvar jszipProto = _dereq_('./object');\n\nvar MADE_BY_DOS = 0x00;\nvar MADE_BY_UNIX = 0x03;\n\n// class ZipEntry {{{\n/**\n * An entry in the zip file.\n * @constructor\n * @param {Object} options Options of the current file.\n * @param {Object} loadOptions Options for loading the stream.\n */\nfunction ZipEntry(options, loadOptions) {\n    this.options = options;\n    this.loadOptions = loadOptions;\n}\nZipEntry.prototype = {\n    /**\n     * say if the file is encrypted.\n     * @return {boolean} true if the file is encrypted, false otherwise.\n     */\n    isEncrypted: function() {\n        // bit 1 is set\n        return (this.bitFlag & 0x0001) === 0x0001;\n    },\n    /**\n     * say if the file has utf-8 filename/comment.\n     * @return {boolean} true if the filename/comment is in utf-8, false otherwise.\n     */\n    useUTF8: function() {\n        // bit 11 is set\n        return (this.bitFlag & 0x0800) === 0x0800;\n    },\n    /**\n     * Prepare the function used to generate the compressed content from this ZipFile.\n     * @param {DataReader} reader the reader to use.\n     * @param {number} from the offset from where we should read the data.\n     * @param {number} length the length of the data to read.\n     * @return {Function} the callback to get the compressed content (the type depends of the DataReader class).\n     */\n    prepareCompressedContent: function(reader, from, length) {\n        return function() {\n            var previousIndex = reader.index;\n            reader.setIndex(from);\n            var compressedFileData = reader.readData(length);\n            reader.setIndex(previousIndex);\n\n            return compressedFileData;\n        };\n    },\n    /**\n     * Prepare the function used to generate the uncompressed content from this ZipFile.\n     * @param {DataReader} reader the reader to use.\n     * @param {number} from the offset from where we should read the data.\n     * @param {number} length the length of the data to read.\n     * @param {JSZip.compression} compression the compression used on this file.\n     * @param {number} uncompressedSize the uncompressed size to expect.\n     * @return {Function} the callback to get the uncompressed content (the type depends of the DataReader class).\n     */\n    prepareContent: function(reader, from, length, compression, uncompressedSize) {\n        return function() {\n\n            var compressedFileData = utils.transformTo(compression.uncompressInputType, this.getCompressedContent());\n            var uncompressedFileData = compression.uncompress(compressedFileData);\n\n            if (uncompressedFileData.length !== uncompressedSize) {\n                throw new Error(\"Bug : uncompressed data size mismatch\");\n            }\n\n            return uncompressedFileData;\n        };\n    },\n    /**\n     * Read the local part of a zip file and add the info in this object.\n     * @param {DataReader} reader the reader to use.\n     */\n    readLocalPart: function(reader) {\n        var compression, localExtraFieldsLength;\n\n        // we already know everything from the central dir !\n        // If the central dir data are false, we are doomed.\n        // On the bright side, the local part is scary  : zip64, data descriptors, both, etc.\n        // The less data we get here, the more reliable this should be.\n        // Let's skip the whole header and dash to the data !\n        reader.skip(22);\n        // in some zip created on windows, the filename stored in the central dir contains \\ instead of /.\n        // Strangely, the filename here is OK.\n        // I would love to treat these zip files as corrupted (see http://www.info-zip.org/FAQ.html#backslashes\n        // or APPNOTE#4.4.17.1, \"All slashes MUST be forward slashes '/'\") but there are a lot of bad zip generators...\n        // Search \"unzip mismatching \"local\" filename continuing with \"central\" filename version\" on\n        // the internet.\n        //\n        // I think I see the logic here : the central directory is used to display\n        // content and the local directory is used to extract the files. Mixing / and \\\n        // may be used to display \\ to windows users and use / when extracting the files.\n        // Unfortunately, this lead also to some issues : http://seclists.org/fulldisclosure/2009/Sep/394\n        this.fileNameLength = reader.readInt(2);\n        localExtraFieldsLength = reader.readInt(2); // can't be sure this will be the same as the central dir\n        this.fileName = reader.readString(this.fileNameLength);\n        reader.skip(localExtraFieldsLength);\n\n        if (this.compressedSize == -1 || this.uncompressedSize == -1) {\n            throw new Error(\"Bug or corrupted zip : didn't get enough informations from the central directory \" + \"(compressedSize == -1 || uncompressedSize == -1)\");\n        }\n\n        compression = utils.findCompression(this.compressionMethod);\n        if (compression === null) { // no compression found\n            throw new Error(\"Corrupted zip : compression \" + utils.pretty(this.compressionMethod) + \" unknown (inner file : \" + this.fileName + \")\");\n        }\n        this.decompressed = new CompressedObject();\n        this.decompressed.compressedSize = this.compressedSize;\n        this.decompressed.uncompressedSize = this.uncompressedSize;\n        this.decompressed.crc32 = this.crc32;\n        this.decompressed.compressionMethod = this.compressionMethod;\n        this.decompressed.getCompressedContent = this.prepareCompressedContent(reader, reader.index, this.compressedSize, compression);\n        this.decompressed.getContent = this.prepareContent(reader, reader.index, this.compressedSize, compression, this.uncompressedSize);\n\n        // we need to compute the crc32...\n        if (this.loadOptions.checkCRC32) {\n            this.decompressed = utils.transformTo(\"string\", this.decompressed.getContent());\n            if (jszipProto.crc32(this.decompressed) !== this.crc32) {\n                throw new Error(\"Corrupted zip : CRC32 mismatch\");\n            }\n        }\n    },\n\n    /**\n     * Read the central part of a zip file and add the info in this object.\n     * @param {DataReader} reader the reader to use.\n     */\n    readCentralPart: function(reader) {\n        this.versionMadeBy = reader.readInt(2);\n        this.versionNeeded = reader.readInt(2);\n        this.bitFlag = reader.readInt(2);\n        this.compressionMethod = reader.readString(2);\n        this.date = reader.readDate();\n        this.crc32 = reader.readInt(4);\n        this.compressedSize = reader.readInt(4);\n        this.uncompressedSize = reader.readInt(4);\n        this.fileNameLength = reader.readInt(2);\n        this.extraFieldsLength = reader.readInt(2);\n        this.fileCommentLength = reader.readInt(2);\n        this.diskNumberStart = reader.readInt(2);\n        this.internalFileAttributes = reader.readInt(2);\n        this.externalFileAttributes = reader.readInt(4);\n        this.localHeaderOffset = reader.readInt(4);\n\n        if (this.isEncrypted()) {\n            throw new Error(\"Encrypted zip are not supported\");\n        }\n\n        this.fileName = reader.readString(this.fileNameLength);\n        this.readExtraFields(reader);\n        this.parseZIP64ExtraField(reader);\n        this.fileComment = reader.readString(this.fileCommentLength);\n    },\n\n    /**\n     * Parse the external file attributes and get the unix/dos permissions.\n     */\n    processAttributes: function () {\n        this.unixPermissions = null;\n        this.dosPermissions = null;\n        var madeBy = this.versionMadeBy >> 8;\n\n        // Check if we have the DOS directory flag set.\n        // We look for it in the DOS and UNIX permissions\n        // but some unknown platform could set it as a compatibility flag.\n        this.dir = this.externalFileAttributes & 0x0010 ? true : false;\n\n        if(madeBy === MADE_BY_DOS) {\n            // first 6 bits (0 to 5)\n            this.dosPermissions = this.externalFileAttributes & 0x3F;\n        }\n\n        if(madeBy === MADE_BY_UNIX) {\n            this.unixPermissions = (this.externalFileAttributes >> 16) & 0xFFFF;\n            // the octal permissions are in (this.unixPermissions & 0x01FF).toString(8);\n        }\n\n        // fail safe : if the name ends with a / it probably means a folder\n        if (!this.dir && this.fileName.slice(-1) === '/') {\n            this.dir = true;\n        }\n    },\n\n    /**\n     * Parse the ZIP64 extra field and merge the info in the current ZipEntry.\n     * @param {DataReader} reader the reader to use.\n     */\n    parseZIP64ExtraField: function(reader) {\n\n        if (!this.extraFields[0x0001]) {\n            return;\n        }\n\n        // should be something, preparing the extra reader\n        var extraReader = new StringReader(this.extraFields[0x0001].value);\n\n        // I really hope that these 64bits integer can fit in 32 bits integer, because js\n        // won't let us have more.\n        if (this.uncompressedSize === utils.MAX_VALUE_32BITS) {\n            this.uncompressedSize = extraReader.readInt(8);\n        }\n        if (this.compressedSize === utils.MAX_VALUE_32BITS) {\n            this.compressedSize = extraReader.readInt(8);\n        }\n        if (this.localHeaderOffset === utils.MAX_VALUE_32BITS) {\n            this.localHeaderOffset = extraReader.readInt(8);\n        }\n        if (this.diskNumberStart === utils.MAX_VALUE_32BITS) {\n            this.diskNumberStart = extraReader.readInt(4);\n        }\n    },\n    /**\n     * Read the central part of a zip file and add the info in this object.\n     * @param {DataReader} reader the reader to use.\n     */\n    readExtraFields: function(reader) {\n        var start = reader.index,\n            extraFieldId,\n            extraFieldLength,\n            extraFieldValue;\n\n        this.extraFields = this.extraFields || {};\n\n        while (reader.index < start + this.extraFieldsLength) {\n            extraFieldId = reader.readInt(2);\n            extraFieldLength = reader.readInt(2);\n            extraFieldValue = reader.readString(extraFieldLength);\n\n            this.extraFields[extraFieldId] = {\n                id: extraFieldId,\n                length: extraFieldLength,\n                value: extraFieldValue\n            };\n        }\n    },\n    /**\n     * Apply an UTF8 transformation if needed.\n     */\n    handleUTF8: function() {\n        if (this.useUTF8()) {\n            this.fileName = jszipProto.utf8decode(this.fileName);\n            this.fileComment = jszipProto.utf8decode(this.fileComment);\n        } else {\n            var upath = this.findExtraFieldUnicodePath();\n            if (upath !== null) {\n                this.fileName = upath;\n            }\n            var ucomment = this.findExtraFieldUnicodeComment();\n            if (ucomment !== null) {\n                this.fileComment = ucomment;\n            }\n        }\n    },\n\n    /**\n     * Find the unicode path declared in the extra field, if any.\n     * @return {String} the unicode path, null otherwise.\n     */\n    findExtraFieldUnicodePath: function() {\n        var upathField = this.extraFields[0x7075];\n        if (upathField) {\n            var extraReader = new StringReader(upathField.value);\n\n            // wrong version\n            if (extraReader.readInt(1) !== 1) {\n                return null;\n            }\n\n            // the crc of the filename changed, this field is out of date.\n            if (jszipProto.crc32(this.fileName) !== extraReader.readInt(4)) {\n                return null;\n            }\n\n            return jszipProto.utf8decode(extraReader.readString(upathField.length - 5));\n        }\n        return null;\n    },\n\n    /**\n     * Find the unicode comment declared in the extra field, if any.\n     * @return {String} the unicode comment, null otherwise.\n     */\n    findExtraFieldUnicodeComment: function() {\n        var ucommentField = this.extraFields[0x6375];\n        if (ucommentField) {\n            var extraReader = new StringReader(ucommentField.value);\n\n            // wrong version\n            if (extraReader.readInt(1) !== 1) {\n                return null;\n            }\n\n            // the crc of the comment changed, this field is out of date.\n            if (jszipProto.crc32(this.fileComment) !== extraReader.readInt(4)) {\n                return null;\n            }\n\n            return jszipProto.utf8decode(extraReader.readString(ucommentField.length - 5));\n        }\n        return null;\n    }\n};\nmodule.exports = ZipEntry;\n\n},{\"./compressedObject\":2,\"./object\":13,\"./stringReader\":15,\"./utils\":21}],24:[function(_dereq_,module,exports){\n// Top level file is just a mixin of submodules & constants\n'use strict';\n\nvar assign    = _dereq_('./lib/utils/common').assign;\n\nvar deflate   = _dereq_('./lib/deflate');\nvar inflate   = _dereq_('./lib/inflate');\nvar constants = _dereq_('./lib/zlib/constants');\n\nvar pako = {};\n\nassign(pako, deflate, inflate, constants);\n\nmodule.exports = pako;\n},{\"./lib/deflate\":25,\"./lib/inflate\":26,\"./lib/utils/common\":27,\"./lib/zlib/constants\":30}],25:[function(_dereq_,module,exports){\n'use strict';\n\n\nvar zlib_deflate = _dereq_('./zlib/deflate.js');\nvar utils = _dereq_('./utils/common');\nvar strings = _dereq_('./utils/strings');\nvar msg = _dereq_('./zlib/messages');\nvar zstream = _dereq_('./zlib/zstream');\n\n\n/* Public constants ==========================================================*/\n/* ===========================================================================*/\n\nvar Z_NO_FLUSH      = 0;\nvar Z_FINISH        = 4;\n\nvar Z_OK            = 0;\nvar Z_STREAM_END    = 1;\n\nvar Z_DEFAULT_COMPRESSION = -1;\n\nvar Z_DEFAULT_STRATEGY    = 0;\n\nvar Z_DEFLATED  = 8;\n\n/* ===========================================================================*/\n\n\n/**\n * class Deflate\n *\n * Generic JS-style wrapper for zlib calls. If you don't need\n * streaming behaviour - use more simple functions: [[deflate]],\n * [[deflateRaw]] and [[gzip]].\n **/\n\n/* internal\n * Deflate.chunks -> Array\n *\n * Chunks of output data, if [[Deflate#onData]] not overriden.\n **/\n\n/**\n * Deflate.result -> Uint8Array|Array\n *\n * Compressed result, generated by default [[Deflate#onData]]\n * and [[Deflate#onEnd]] handlers. Filled after you push last chunk\n * (call [[Deflate#push]] with `Z_FINISH` / `true` param).\n **/\n\n/**\n * Deflate.err -> Number\n *\n * Error code after deflate finished. 0 (Z_OK) on success.\n * You will not need it in real life, because deflate errors\n * are possible only on wrong options or bad `onData` / `onEnd`\n * custom handlers.\n **/\n\n/**\n * Deflate.msg -> String\n *\n * Error message, if [[Deflate.err]] != 0\n **/\n\n\n/**\n * new Deflate(options)\n * - options (Object): zlib deflate options.\n *\n * Creates new deflator instance with specified params. Throws exception\n * on bad params. Supported options:\n *\n * - `level`\n * - `windowBits`\n * - `memLevel`\n * - `strategy`\n *\n * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)\n * for more information on these.\n *\n * Additional options, for internal needs:\n *\n * - `chunkSize` - size of generated data chunks (16K by default)\n * - `raw` (Boolean) - do raw deflate\n * - `gzip` (Boolean) - create gzip wrapper\n * - `to` (String) - if equal to 'string', then result will be \"binary string\"\n *    (each char code [0..255])\n * - `header` (Object) - custom header for gzip\n *   - `text` (Boolean) - true if compressed data believed to be text\n *   - `time` (Number) - modification time, unix timestamp\n *   - `os` (Number) - operation system code\n *   - `extra` (Array) - array of bytes with extra data (max 65536)\n *   - `name` (String) - file name (binary string)\n *   - `comment` (String) - comment (binary string)\n *   - `hcrc` (Boolean) - true if header crc should be added\n *\n * ##### Example:\n *\n * ```javascript\n * var pako = require('pako')\n *   , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])\n *   , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);\n *\n * var deflate = new pako.Deflate({ level: 3});\n *\n * deflate.push(chunk1, false);\n * deflate.push(chunk2, true);  // true -> last chunk\n *\n * if (deflate.err) { throw new Error(deflate.err); }\n *\n * console.log(deflate.result);\n * ```\n **/\nvar Deflate = function(options) {\n\n  this.options = utils.assign({\n    level: Z_DEFAULT_COMPRESSION,\n    method: Z_DEFLATED,\n    chunkSize: 16384,\n    windowBits: 15,\n    memLevel: 8,\n    strategy: Z_DEFAULT_STRATEGY,\n    to: ''\n  }, options || {});\n\n  var opt = this.options;\n\n  if (opt.raw && (opt.windowBits > 0)) {\n    opt.windowBits = -opt.windowBits;\n  }\n\n  else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {\n    opt.windowBits += 16;\n  }\n\n  this.err    = 0;      // error code, if happens (0 = Z_OK)\n  this.msg    = '';     // error message\n  this.ended  = false;  // used to avoid multiple onEnd() calls\n  this.chunks = [];     // chunks of compressed data\n\n  this.strm = new zstream();\n  this.strm.avail_out = 0;\n\n  var status = zlib_deflate.deflateInit2(\n    this.strm,\n    opt.level,\n    opt.method,\n    opt.windowBits,\n    opt.memLevel,\n    opt.strategy\n  );\n\n  if (status !== Z_OK) {\n    throw new Error(msg[status]);\n  }\n\n  if (opt.header) {\n    zlib_deflate.deflateSetHeader(this.strm, opt.header);\n  }\n};\n\n/**\n * Deflate#push(data[, mode]) -> Boolean\n * - data (Uint8Array|Array|String): input data. Strings will be converted to\n *   utf8 byte sequence.\n * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.\n *   See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.\n *\n * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with\n * new compressed chunks. Returns `true` on success. The last data block must have\n * mode Z_FINISH (or `true`). That flush internal pending buffers and call\n * [[Deflate#onEnd]].\n *\n * On fail call [[Deflate#onEnd]] with error code and return false.\n *\n * We strongly recommend to use `Uint8Array` on input for best speed (output\n * array format is detected automatically). Also, don't skip last param and always\n * use the same type in your code (boolean or number). That will improve JS speed.\n *\n * For regular `Array`-s make sure all elements are [0..255].\n *\n * ##### Example\n *\n * ```javascript\n * push(chunk, false); // push one of data chunks\n * ...\n * push(chunk, true);  // push last chunk\n * ```\n **/\nDeflate.prototype.push = function(data, mode) {\n  var strm = this.strm;\n  var chunkSize = this.options.chunkSize;\n  var status, _mode;\n\n  if (this.ended) { return false; }\n\n  _mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH);\n\n  // Convert data if needed\n  if (typeof data === 'string') {\n    // If we need to compress text, change encoding to utf8.\n    strm.input = strings.string2buf(data);\n  } else {\n    strm.input = data;\n  }\n\n  strm.next_in = 0;\n  strm.avail_in = strm.input.length;\n\n  do {\n    if (strm.avail_out === 0) {\n      strm.output = new utils.Buf8(chunkSize);\n      strm.next_out = 0;\n      strm.avail_out = chunkSize;\n    }\n    status = zlib_deflate.deflate(strm, _mode);    /* no bad return value */\n\n    if (status !== Z_STREAM_END && status !== Z_OK) {\n      this.onEnd(status);\n      this.ended = true;\n      return false;\n    }\n    if (strm.avail_out === 0 || (strm.avail_in === 0 && _mode === Z_FINISH)) {\n      if (this.options.to === 'string') {\n        this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out)));\n      } else {\n        this.onData(utils.shrinkBuf(strm.output, strm.next_out));\n      }\n    }\n  } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END);\n\n  // Finalize on the last chunk.\n  if (_mode === Z_FINISH) {\n    status = zlib_deflate.deflateEnd(this.strm);\n    this.onEnd(status);\n    this.ended = true;\n    return status === Z_OK;\n  }\n\n  return true;\n};\n\n\n/**\n * Deflate#onData(chunk) -> Void\n * - chunk (Uint8Array|Array|String): ouput data. Type of array depends\n *   on js engine support. When string output requested, each chunk\n *   will be string.\n *\n * By default, stores data blocks in `chunks[]` property and glue\n * those in `onEnd`. Override this handler, if you need another behaviour.\n **/\nDeflate.prototype.onData = function(chunk) {\n  this.chunks.push(chunk);\n};\n\n\n/**\n * Deflate#onEnd(status) -> Void\n * - status (Number): deflate status. 0 (Z_OK) on success,\n *   other if not.\n *\n * Called once after you tell deflate that input stream complete\n * or error happenned. By default - join collected chunks,\n * free memory and fill `results` / `err` properties.\n **/\nDeflate.prototype.onEnd = function(status) {\n  // On success - join\n  if (status === Z_OK) {\n    if (this.options.to === 'string') {\n      this.result = this.chunks.join('');\n    } else {\n      this.result = utils.flattenChunks(this.chunks);\n    }\n  }\n  this.chunks = [];\n  this.err = status;\n  this.msg = this.strm.msg;\n};\n\n\n/**\n * deflate(data[, options]) -> Uint8Array|Array|String\n * - data (Uint8Array|Array|String): input data to compress.\n * - options (Object): zlib deflate options.\n *\n * Compress `data` with deflate alrorythm and `options`.\n *\n * Supported options are:\n *\n * - level\n * - windowBits\n * - memLevel\n * - strategy\n *\n * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)\n * for more information on these.\n *\n * Sugar (options):\n *\n * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify\n *   negative windowBits implicitly.\n * - `to` (String) - if equal to 'string', then result will be \"binary string\"\n *    (each char code [0..255])\n *\n * ##### Example:\n *\n * ```javascript\n * var pako = require('pako')\n *   , data = Uint8Array([1,2,3,4,5,6,7,8,9]);\n *\n * console.log(pako.deflate(data));\n * ```\n **/\nfunction deflate(input, options) {\n  var deflator = new Deflate(options);\n\n  deflator.push(input, true);\n\n  // That will never happens, if you don't cheat with options :)\n  if (deflator.err) { throw deflator.msg; }\n\n  return deflator.result;\n}\n\n\n/**\n * deflateRaw(data[, options]) -> Uint8Array|Array|String\n * - data (Uint8Array|Array|String): input data to compress.\n * - options (Object): zlib deflate options.\n *\n * The same as [[deflate]], but creates raw data, without wrapper\n * (header and adler32 crc).\n **/\nfunction deflateRaw(input, options) {\n  options = options || {};\n  options.raw = true;\n  return deflate(input, options);\n}\n\n\n/**\n * gzip(data[, options]) -> Uint8Array|Array|String\n * - data (Uint8Array|Array|String): input data to compress.\n * - options (Object): zlib deflate options.\n *\n * The same as [[deflate]], but create gzip wrapper instead of\n * deflate one.\n **/\nfunction gzip(input, options) {\n  options = options || {};\n  options.gzip = true;\n  return deflate(input, options);\n}\n\n\nexports.Deflate = Deflate;\nexports.deflate = deflate;\nexports.deflateRaw = deflateRaw;\nexports.gzip = gzip;\n},{\"./utils/common\":27,\"./utils/strings\":28,\"./zlib/deflate.js\":32,\"./zlib/messages\":37,\"./zlib/zstream\":39}],26:[function(_dereq_,module,exports){\n'use strict';\n\n\nvar zlib_inflate = _dereq_('./zlib/inflate.js');\nvar utils = _dereq_('./utils/common');\nvar strings = _dereq_('./utils/strings');\nvar c = _dereq_('./zlib/constants');\nvar msg = _dereq_('./zlib/messages');\nvar zstream = _dereq_('./zlib/zstream');\nvar gzheader = _dereq_('./zlib/gzheader');\n\n\n/**\n * class Inflate\n *\n * Generic JS-style wrapper for zlib calls. If you don't need\n * streaming behaviour - use more simple functions: [[inflate]]\n * and [[inflateRaw]].\n **/\n\n/* internal\n * inflate.chunks -> Array\n *\n * Chunks of output data, if [[Inflate#onData]] not overriden.\n **/\n\n/**\n * Inflate.result -> Uint8Array|Array|String\n *\n * Uncompressed result, generated by default [[Inflate#onData]]\n * and [[Inflate#onEnd]] handlers. Filled after you push last chunk\n * (call [[Inflate#push]] with `Z_FINISH` / `true` param).\n **/\n\n/**\n * Inflate.err -> Number\n *\n * Error code after inflate finished. 0 (Z_OK) on success.\n * Should be checked if broken data possible.\n **/\n\n/**\n * Inflate.msg -> String\n *\n * Error message, if [[Inflate.err]] != 0\n **/\n\n\n/**\n * new Inflate(options)\n * - options (Object): zlib inflate options.\n *\n * Creates new inflator instance with specified params. Throws exception\n * on bad params. Supported options:\n *\n * - `windowBits`\n *\n * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)\n * for more information on these.\n *\n * Additional options, for internal needs:\n *\n * - `chunkSize` - size of generated data chunks (16K by default)\n * - `raw` (Boolean) - do raw inflate\n * - `to` (String) - if equal to 'string', then result will be converted\n *   from utf8 to utf16 (javascript) string. When string output requested,\n *   chunk length can differ from `chunkSize`, depending on content.\n *\n * By default, when no options set, autodetect deflate/gzip data format via\n * wrapper header.\n *\n * ##### Example:\n *\n * ```javascript\n * var pako = require('pako')\n *   , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])\n *   , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);\n *\n * var inflate = new pako.Inflate({ level: 3});\n *\n * inflate.push(chunk1, false);\n * inflate.push(chunk2, true);  // true -> last chunk\n *\n * if (inflate.err) { throw new Error(inflate.err); }\n *\n * console.log(inflate.result);\n * ```\n **/\nvar Inflate = function(options) {\n\n  this.options = utils.assign({\n    chunkSize: 16384,\n    windowBits: 0,\n    to: ''\n  }, options || {});\n\n  var opt = this.options;\n\n  // Force window size for `raw` data, if not set directly,\n  // because we have no header for autodetect.\n  if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {\n    opt.windowBits = -opt.windowBits;\n    if (opt.windowBits === 0) { opt.windowBits = -15; }\n  }\n\n  // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate\n  if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&\n      !(options && options.windowBits)) {\n    opt.windowBits += 32;\n  }\n\n  // Gzip header has no info about windows size, we can do autodetect only\n  // for deflate. So, if window size not set, force it to max when gzip possible\n  if ((opt.windowBits > 15) && (opt.windowBits < 48)) {\n    // bit 3 (16) -> gzipped data\n    // bit 4 (32) -> autodetect gzip/deflate\n    if ((opt.windowBits & 15) === 0) {\n      opt.windowBits |= 15;\n    }\n  }\n\n  this.err    = 0;      // error code, if happens (0 = Z_OK)\n  this.msg    = '';     // error message\n  this.ended  = false;  // used to avoid multiple onEnd() calls\n  this.chunks = [];     // chunks of compressed data\n\n  this.strm   = new zstream();\n  this.strm.avail_out = 0;\n\n  var status  = zlib_inflate.inflateInit2(\n    this.strm,\n    opt.windowBits\n  );\n\n  if (status !== c.Z_OK) {\n    throw new Error(msg[status]);\n  }\n\n  this.header = new gzheader();\n\n  zlib_inflate.inflateGetHeader(this.strm, this.header);\n};\n\n/**\n * Inflate#push(data[, mode]) -> Boolean\n * - data (Uint8Array|Array|String): input data\n * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.\n *   See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.\n *\n * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with\n * new output chunks. Returns `true` on success. The last data block must have\n * mode Z_FINISH (or `true`). That flush internal pending buffers and call\n * [[Inflate#onEnd]].\n *\n * On fail call [[Inflate#onEnd]] with error code and return false.\n *\n * We strongly recommend to use `Uint8Array` on input for best speed (output\n * format is detected automatically). Also, don't skip last param and always\n * use the same type in your code (boolean or number). That will improve JS speed.\n *\n * For regular `Array`-s make sure all elements are [0..255].\n *\n * ##### Example\n *\n * ```javascript\n * push(chunk, false); // push one of data chunks\n * ...\n * push(chunk, true);  // push last chunk\n * ```\n **/\nInflate.prototype.push = function(data, mode) {\n  var strm = this.strm;\n  var chunkSize = this.options.chunkSize;\n  var status, _mode;\n  var next_out_utf8, tail, utf8str;\n\n  if (this.ended) { return false; }\n  _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH);\n\n  // Convert data if needed\n  if (typeof data === 'string') {\n    // Only binary strings can be decompressed on practice\n    strm.input = strings.binstring2buf(data);\n  } else {\n    strm.input = data;\n  }\n\n  strm.next_in = 0;\n  strm.avail_in = strm.input.length;\n\n  do {\n    if (strm.avail_out === 0) {\n      strm.output = new utils.Buf8(chunkSize);\n      strm.next_out = 0;\n      strm.avail_out = chunkSize;\n    }\n\n    status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH);    /* no bad return value */\n\n    if (status !== c.Z_STREAM_END && status !== c.Z_OK) {\n      this.onEnd(status);\n      this.ended = true;\n      return false;\n    }\n\n    if (strm.next_out) {\n      if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && _mode === c.Z_FINISH)) {\n\n        if (this.options.to === 'string') {\n\n          next_out_utf8 = strings.utf8border(strm.output, strm.next_out);\n\n          tail = strm.next_out - next_out_utf8;\n          utf8str = strings.buf2string(strm.output, next_out_utf8);\n\n          // move tail\n          strm.next_out = tail;\n          strm.avail_out = chunkSize - tail;\n          if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); }\n\n          this.onData(utf8str);\n\n        } else {\n          this.onData(utils.shrinkBuf(strm.output, strm.next_out));\n        }\n      }\n    }\n  } while ((strm.avail_in > 0) && status !== c.Z_STREAM_END);\n\n  if (status === c.Z_STREAM_END) {\n    _mode = c.Z_FINISH;\n  }\n  // Finalize on the last chunk.\n  if (_mode === c.Z_FINISH) {\n    status = zlib_inflate.inflateEnd(this.strm);\n    this.onEnd(status);\n    this.ended = true;\n    return status === c.Z_OK;\n  }\n\n  return true;\n};\n\n\n/**\n * Inflate#onData(chunk) -> Void\n * - chunk (Uint8Array|Array|String): ouput data. Type of array depends\n *   on js engine support. When string output requested, each chunk\n *   will be string.\n *\n * By default, stores data blocks in `chunks[]` property and glue\n * those in `onEnd`. Override this handler, if you need another behaviour.\n **/\nInflate.prototype.onData = function(chunk) {\n  this.chunks.push(chunk);\n};\n\n\n/**\n * Inflate#onEnd(status) -> Void\n * - status (Number): inflate status. 0 (Z_OK) on success,\n *   other if not.\n *\n * Called once after you tell inflate that input stream complete\n * or error happenned. By default - join collected chunks,\n * free memory and fill `results` / `err` properties.\n **/\nInflate.prototype.onEnd = function(status) {\n  // On success - join\n  if (status === c.Z_OK) {\n    if (this.options.to === 'string') {\n      // Glue & convert here, until we teach pako to send\n      // utf8 alligned strings to onData\n      this.result = this.chunks.join('');\n    } else {\n      this.result = utils.flattenChunks(this.chunks);\n    }\n  }\n  this.chunks = [];\n  this.err = status;\n  this.msg = this.strm.msg;\n};\n\n\n/**\n * inflate(data[, options]) -> Uint8Array|Array|String\n * - data (Uint8Array|Array|String): input data to decompress.\n * - options (Object): zlib inflate options.\n *\n * Decompress `data` with inflate/ungzip and `options`. Autodetect\n * format via wrapper header by default. That's why we don't provide\n * separate `ungzip` method.\n *\n * Supported options are:\n *\n * - windowBits\n *\n * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)\n * for more information.\n *\n * Sugar (options):\n *\n * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify\n *   negative windowBits implicitly.\n * - `to` (String) - if equal to 'string', then result will be converted\n *   from utf8 to utf16 (javascript) string. When string output requested,\n *   chunk length can differ from `chunkSize`, depending on content.\n *\n *\n * ##### Example:\n *\n * ```javascript\n * var pako = require('pako')\n *   , input = pako.deflate([1,2,3,4,5,6,7,8,9])\n *   , output;\n *\n * try {\n *   output = pako.inflate(input);\n * } catch (err)\n *   console.log(err);\n * }\n * ```\n **/\nfunction inflate(input, options) {\n  var inflator = new Inflate(options);\n\n  inflator.push(input, true);\n\n  // That will never happens, if you don't cheat with options :)\n  if (inflator.err) { throw inflator.msg; }\n\n  return inflator.result;\n}\n\n\n/**\n * inflateRaw(data[, options]) -> Uint8Array|Array|String\n * - data (Uint8Array|Array|String): input data to decompress.\n * - options (Object): zlib inflate options.\n *\n * The same as [[inflate]], but creates raw data, without wrapper\n * (header and adler32 crc).\n **/\nfunction inflateRaw(input, options) {\n  options = options || {};\n  options.raw = true;\n  return inflate(input, options);\n}\n\n\n/**\n * ungzip(data[, options]) -> Uint8Array|Array|String\n * - data (Uint8Array|Array|String): input data to decompress.\n * - options (Object): zlib inflate options.\n *\n * Just shortcut to [[inflate]], because it autodetects format\n * by header.content. Done for convenience.\n **/\n\n\nexports.Inflate = Inflate;\nexports.inflate = inflate;\nexports.inflateRaw = inflateRaw;\nexports.ungzip  = inflate;\n\n},{\"./utils/common\":27,\"./utils/strings\":28,\"./zlib/constants\":30,\"./zlib/gzheader\":33,\"./zlib/inflate.js\":35,\"./zlib/messages\":37,\"./zlib/zstream\":39}],27:[function(_dereq_,module,exports){\n'use strict';\n\n\nvar TYPED_OK =  (typeof Uint8Array !== 'undefined') &&\n                (typeof Uint16Array !== 'undefined') &&\n                (typeof Int32Array !== 'undefined');\n\n\nexports.assign = function (obj /*from1, from2, from3, ...*/) {\n  var sources = Array.prototype.slice.call(arguments, 1);\n  while (sources.length) {\n    var source = sources.shift();\n    if (!source) { continue; }\n\n    if (typeof(source) !== 'object') {\n      throw new TypeError(source + 'must be non-object');\n    }\n\n    for (var p in source) {\n      if (source.hasOwnProperty(p)) {\n        obj[p] = source[p];\n      }\n    }\n  }\n\n  return obj;\n};\n\n\n// reduce buffer size, avoiding mem copy\nexports.shrinkBuf = function (buf, size) {\n  if (buf.length === size) { return buf; }\n  if (buf.subarray) { return buf.subarray(0, size); }\n  buf.length = size;\n  return buf;\n};\n\n\nvar fnTyped = {\n  arraySet: function (dest, src, src_offs, len, dest_offs) {\n    if (src.subarray && dest.subarray) {\n      dest.set(src.subarray(src_offs, src_offs+len), dest_offs);\n      return;\n    }\n    // Fallback to ordinary array\n    for(var i=0; i<len; i++) {\n      dest[dest_offs + i] = src[src_offs + i];\n    }\n  },\n  // Join array of chunks to single array.\n  flattenChunks: function(chunks) {\n    var i, l, len, pos, chunk, result;\n\n    // calculate data length\n    len = 0;\n    for (i=0, l=chunks.length; i<l; i++) {\n      len += chunks[i].length;\n    }\n\n    // join chunks\n    result = new Uint8Array(len);\n    pos = 0;\n    for (i=0, l=chunks.length; i<l; i++) {\n      chunk = chunks[i];\n      result.set(chunk, pos);\n      pos += chunk.length;\n    }\n\n    return result;\n  }\n};\n\nvar fnUntyped = {\n  arraySet: function (dest, src, src_offs, len, dest_offs) {\n    for(var i=0; i<len; i++) {\n      dest[dest_offs + i] = src[src_offs + i];\n    }\n  },\n  // Join array of chunks to single array.\n  flattenChunks: function(chunks) {\n    return [].concat.apply([], chunks);\n  }\n};\n\n\n// Enable/Disable typed arrays use, for testing\n//\nexports.setTyped = function (on) {\n  if (on) {\n    exports.Buf8  = Uint8Array;\n    exports.Buf16 = Uint16Array;\n    exports.Buf32 = Int32Array;\n    exports.assign(exports, fnTyped);\n  } else {\n    exports.Buf8  = Array;\n    exports.Buf16 = Array;\n    exports.Buf32 = Array;\n    exports.assign(exports, fnUntyped);\n  }\n};\n\nexports.setTyped(TYPED_OK);\n},{}],28:[function(_dereq_,module,exports){\n// String encode/decode helpers\n'use strict';\n\n\nvar utils = _dereq_('./common');\n\n\n// Quick check if we can use fast array to bin string conversion\n//\n// - apply(Array) can fail on Android 2.2\n// - apply(Uint8Array) can fail on iOS 5.1 Safary\n//\nvar STR_APPLY_OK = true;\nvar STR_APPLY_UIA_OK = true;\n\ntry { String.fromCharCode.apply(null, [0]); } catch(__) { STR_APPLY_OK = false; }\ntry { String.fromCharCode.apply(null, new Uint8Array(1)); } catch(__) { STR_APPLY_UIA_OK = false; }\n\n\n// Table with utf8 lengths (calculated by first byte of sequence)\n// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,\n// because max possible codepoint is 0x10ffff\nvar _utf8len = new utils.Buf8(256);\nfor (var i=0; i<256; i++) {\n  _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1);\n}\n_utf8len[254]=_utf8len[254]=1; // Invalid sequence start\n\n\n// convert string to array (typed, when possible)\nexports.string2buf = function (str) {\n  var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;\n\n  // count binary size\n  for (m_pos = 0; m_pos < str_len; m_pos++) {\n    c = str.charCodeAt(m_pos);\n    if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {\n      c2 = str.charCodeAt(m_pos+1);\n      if ((c2 & 0xfc00) === 0xdc00) {\n        c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);\n        m_pos++;\n      }\n    }\n    buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;\n  }\n\n  // allocate buffer\n  buf = new utils.Buf8(buf_len);\n\n  // convert\n  for (i=0, m_pos = 0; i < buf_len; m_pos++) {\n    c = str.charCodeAt(m_pos);\n    if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {\n      c2 = str.charCodeAt(m_pos+1);\n      if ((c2 & 0xfc00) === 0xdc00) {\n        c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);\n        m_pos++;\n      }\n    }\n    if (c < 0x80) {\n      /* one byte */\n      buf[i++] = c;\n    } else if (c < 0x800) {\n      /* two bytes */\n      buf[i++] = 0xC0 | (c >>> 6);\n      buf[i++] = 0x80 | (c & 0x3f);\n    } else if (c < 0x10000) {\n      /* three bytes */\n      buf[i++] = 0xE0 | (c >>> 12);\n      buf[i++] = 0x80 | (c >>> 6 & 0x3f);\n      buf[i++] = 0x80 | (c & 0x3f);\n    } else {\n      /* four bytes */\n      buf[i++] = 0xf0 | (c >>> 18);\n      buf[i++] = 0x80 | (c >>> 12 & 0x3f);\n      buf[i++] = 0x80 | (c >>> 6 & 0x3f);\n      buf[i++] = 0x80 | (c & 0x3f);\n    }\n  }\n\n  return buf;\n};\n\n// Helper (used in 2 places)\nfunction buf2binstring(buf, len) {\n  // use fallback for big arrays to avoid stack overflow\n  if (len < 65537) {\n    if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) {\n      return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len));\n    }\n  }\n\n  var result = '';\n  for(var i=0; i < len; i++) {\n    result += String.fromCharCode(buf[i]);\n  }\n  return result;\n}\n\n\n// Convert byte array to binary string\nexports.buf2binstring = function(buf) {\n  return buf2binstring(buf, buf.length);\n};\n\n\n// Convert binary string (typed, when possible)\nexports.binstring2buf = function(str) {\n  var buf = new utils.Buf8(str.length);\n  for(var i=0, len=buf.length; i < len; i++) {\n    buf[i] = str.charCodeAt(i);\n  }\n  return buf;\n};\n\n\n// convert array to string\nexports.buf2string = function (buf, max) {\n  var i, out, c, c_len;\n  var len = max || buf.length;\n\n  // Reserve max possible length (2 words per char)\n  // NB: by unknown reasons, Array is significantly faster for\n  //     String.fromCharCode.apply than Uint16Array.\n  var utf16buf = new Array(len*2);\n\n  for (out=0, i=0; i<len;) {\n    c = buf[i++];\n    // quick process ascii\n    if (c < 0x80) { utf16buf[out++] = c; continue; }\n\n    c_len = _utf8len[c];\n    // skip 5 & 6 byte codes\n    if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; }\n\n    // apply mask on first byte\n    c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;\n    // join the rest\n    while (c_len > 1 && i < len) {\n      c = (c << 6) | (buf[i++] & 0x3f);\n      c_len--;\n    }\n\n    // terminated by end of string?\n    if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }\n\n    if (c < 0x10000) {\n      utf16buf[out++] = c;\n    } else {\n      c -= 0x10000;\n      utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);\n      utf16buf[out++] = 0xdc00 | (c & 0x3ff);\n    }\n  }\n\n  return buf2binstring(utf16buf, out);\n};\n\n\n// Calculate max possible position in utf8 buffer,\n// that will not break sequence. If that's not possible\n// - (very small limits) return max size as is.\n//\n// buf[] - utf8 bytes array\n// max   - length limit (mandatory);\nexports.utf8border = function(buf, max) {\n  var pos;\n\n  max = max || buf.length;\n  if (max > buf.length) { max = buf.length; }\n\n  // go back from last position, until start of sequence found\n  pos = max-1;\n  while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }\n\n  // Fuckup - very small and broken sequence,\n  // return max, because we should return something anyway.\n  if (pos < 0) { return max; }\n\n  // If we came to start of buffer - that means vuffer is too small,\n  // return max too.\n  if (pos === 0) { return max; }\n\n  return (pos + _utf8len[buf[pos]] > max) ? pos : max;\n};\n\n},{\"./common\":27}],29:[function(_dereq_,module,exports){\n'use strict';\n\n// Note: adler32 takes 12% for level 0 and 2% for level 6.\n// It doesn't worth to make additional optimizationa as in original.\n// Small size is preferable.\n\nfunction adler32(adler, buf, len, pos) {\n  var s1 = (adler & 0xffff) |0\n    , s2 = ((adler >>> 16) & 0xffff) |0\n    , n = 0;\n\n  while (len !== 0) {\n    // Set limit ~ twice less than 5552, to keep\n    // s2 in 31-bits, because we force signed ints.\n    // in other case %= will fail.\n    n = len > 2000 ? 2000 : len;\n    len -= n;\n\n    do {\n      s1 = (s1 + buf[pos++]) |0;\n      s2 = (s2 + s1) |0;\n    } while (--n);\n\n    s1 %= 65521;\n    s2 %= 65521;\n  }\n\n  return (s1 | (s2 << 16)) |0;\n}\n\n\nmodule.exports = adler32;\n},{}],30:[function(_dereq_,module,exports){\nmodule.exports = {\n\n  /* Allowed flush values; see deflate() and inflate() below for details */\n  Z_NO_FLUSH:         0,\n  Z_PARTIAL_FLUSH:    1,\n  Z_SYNC_FLUSH:       2,\n  Z_FULL_FLUSH:       3,\n  Z_FINISH:           4,\n  Z_BLOCK:            5,\n  Z_TREES:            6,\n\n  /* Return codes for the compression/decompression functions. Negative values\n  * are errors, positive values are used for special but normal events.\n  */\n  Z_OK:               0,\n  Z_STREAM_END:       1,\n  Z_NEED_DICT:        2,\n  Z_ERRNO:           -1,\n  Z_STREAM_ERROR:    -2,\n  Z_DATA_ERROR:      -3,\n  //Z_MEM_ERROR:     -4,\n  Z_BUF_ERROR:       -5,\n  //Z_VERSION_ERROR: -6,\n\n  /* compression levels */\n  Z_NO_COMPRESSION:         0,\n  Z_BEST_SPEED:             1,\n  Z_BEST_COMPRESSION:       9,\n  Z_DEFAULT_COMPRESSION:   -1,\n\n\n  Z_FILTERED:               1,\n  Z_HUFFMAN_ONLY:           2,\n  Z_RLE:                    3,\n  Z_FIXED:                  4,\n  Z_DEFAULT_STRATEGY:       0,\n\n  /* Possible values of the data_type field (though see inflate()) */\n  Z_BINARY:                 0,\n  Z_TEXT:                   1,\n  //Z_ASCII:                1, // = Z_TEXT (deprecated)\n  Z_UNKNOWN:                2,\n\n  /* The deflate compression method */\n  Z_DEFLATED:               8\n  //Z_NULL:                 null // Use -1 or null inline, depending on var type\n};\n},{}],31:[function(_dereq_,module,exports){\n'use strict';\n\n// Note: we can't get significant speed boost here.\n// So write code to minimize size - no pregenerated tables\n// and array tools dependencies.\n\n\n// Use ordinary array, since untyped makes no boost here\nfunction makeTable() {\n  var c, table = [];\n\n  for(var n =0; n < 256; n++){\n    c = n;\n    for(var k =0; k < 8; k++){\n      c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));\n    }\n    table[n] = c;\n  }\n\n  return table;\n}\n\n// Create table on load. Just 255 signed longs. Not a problem.\nvar crcTable = makeTable();\n\n\nfunction crc32(crc, buf, len, pos) {\n  var t = crcTable\n    , end = pos + len;\n\n  crc = crc ^ (-1);\n\n  for (var i = pos; i < end; i++ ) {\n    crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];\n  }\n\n  return (crc ^ (-1)); // >>> 0;\n}\n\n\nmodule.exports = crc32;\n},{}],32:[function(_dereq_,module,exports){\n'use strict';\n\nvar utils   = _dereq_('../utils/common');\nvar trees   = _dereq_('./trees');\nvar adler32 = _dereq_('./adler32');\nvar crc32   = _dereq_('./crc32');\nvar msg   = _dereq_('./messages');\n\n/* Public constants ==========================================================*/\n/* ===========================================================================*/\n\n\n/* Allowed flush values; see deflate() and inflate() below for details */\nvar Z_NO_FLUSH      = 0;\nvar Z_PARTIAL_FLUSH = 1;\n//var Z_SYNC_FLUSH    = 2;\nvar Z_FULL_FLUSH    = 3;\nvar Z_FINISH        = 4;\nvar Z_BLOCK         = 5;\n//var Z_TREES         = 6;\n\n\n/* Return codes for the compression/decompression functions. Negative values\n * are errors, positive values are used for special but normal events.\n */\nvar Z_OK            = 0;\nvar Z_STREAM_END    = 1;\n//var Z_NEED_DICT     = 2;\n//var Z_ERRNO         = -1;\nvar Z_STREAM_ERROR  = -2;\nvar Z_DATA_ERROR    = -3;\n//var Z_MEM_ERROR     = -4;\nvar Z_BUF_ERROR     = -5;\n//var Z_VERSION_ERROR = -6;\n\n\n/* compression levels */\n//var Z_NO_COMPRESSION      = 0;\n//var Z_BEST_SPEED          = 1;\n//var Z_BEST_COMPRESSION    = 9;\nvar Z_DEFAULT_COMPRESSION = -1;\n\n\nvar Z_FILTERED            = 1;\nvar Z_HUFFMAN_ONLY        = 2;\nvar Z_RLE                 = 3;\nvar Z_FIXED               = 4;\nvar Z_DEFAULT_STRATEGY    = 0;\n\n/* Possible values of the data_type field (though see inflate()) */\n//var Z_BINARY              = 0;\n//var Z_TEXT                = 1;\n//var Z_ASCII               = 1; // = Z_TEXT\nvar Z_UNKNOWN             = 2;\n\n\n/* The deflate compression method */\nvar Z_DEFLATED  = 8;\n\n/*============================================================================*/\n\n\nvar MAX_MEM_LEVEL = 9;\n/* Maximum value for memLevel in deflateInit2 */\nvar MAX_WBITS = 15;\n/* 32K LZ77 window */\nvar DEF_MEM_LEVEL = 8;\n\n\nvar LENGTH_CODES  = 29;\n/* number of length codes, not counting the special END_BLOCK code */\nvar LITERALS      = 256;\n/* number of literal bytes 0..255 */\nvar L_CODES       = LITERALS + 1 + LENGTH_CODES;\n/* number of Literal or Length codes, including the END_BLOCK code */\nvar D_CODES       = 30;\n/* number of distance codes */\nvar BL_CODES      = 19;\n/* number of codes used to transfer the bit lengths */\nvar HEAP_SIZE     = 2*L_CODES + 1;\n/* maximum heap size */\nvar MAX_BITS  = 15;\n/* All codes must not exceed MAX_BITS bits */\n\nvar MIN_MATCH = 3;\nvar MAX_MATCH = 258;\nvar MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);\n\nvar PRESET_DICT = 0x20;\n\nvar INIT_STATE = 42;\nvar EXTRA_STATE = 69;\nvar NAME_STATE = 73;\nvar COMMENT_STATE = 91;\nvar HCRC_STATE = 103;\nvar BUSY_STATE = 113;\nvar FINISH_STATE = 666;\n\nvar BS_NEED_MORE      = 1; /* block not completed, need more input or more output */\nvar BS_BLOCK_DONE     = 2; /* block flush performed */\nvar BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */\nvar BS_FINISH_DONE    = 4; /* finish done, accept no more input or output */\n\nvar OS_CODE = 0x03; // Unix :) . Don't detect, use this default.\n\nfunction err(strm, errorCode) {\n  strm.msg = msg[errorCode];\n  return errorCode;\n}\n\nfunction rank(f) {\n  return ((f) << 1) - ((f) > 4 ? 9 : 0);\n}\n\nfunction zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }\n\n\n/* =========================================================================\n * Flush as much pending output as possible. All deflate() output goes\n * through this function so some applications may wish to modify it\n * to avoid allocating a large strm->output buffer and copying into it.\n * (See also read_buf()).\n */\nfunction flush_pending(strm) {\n  var s = strm.state;\n\n  //_tr_flush_bits(s);\n  var len = s.pending;\n  if (len > strm.avail_out) {\n    len = strm.avail_out;\n  }\n  if (len === 0) { return; }\n\n  utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out);\n  strm.next_out += len;\n  s.pending_out += len;\n  strm.total_out += len;\n  strm.avail_out -= len;\n  s.pending -= len;\n  if (s.pending === 0) {\n    s.pending_out = 0;\n  }\n}\n\n\nfunction flush_block_only (s, last) {\n  trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);\n  s.block_start = s.strstart;\n  flush_pending(s.strm);\n}\n\n\nfunction put_byte(s, b) {\n  s.pending_buf[s.pending++] = b;\n}\n\n\n/* =========================================================================\n * Put a short in the pending buffer. The 16-bit value is put in MSB order.\n * IN assertion: the stream state is correct and there is enough room in\n * pending_buf.\n */\nfunction putShortMSB(s, b) {\n//  put_byte(s, (Byte)(b >> 8));\n//  put_byte(s, (Byte)(b & 0xff));\n  s.pending_buf[s.pending++] = (b >>> 8) & 0xff;\n  s.pending_buf[s.pending++] = b & 0xff;\n}\n\n\n/* ===========================================================================\n * Read a new buffer from the current input stream, update the adler32\n * and total number of bytes read.  All deflate() input goes through\n * this function so some applications may wish to modify it to avoid\n * allocating a large strm->input buffer and copying from it.\n * (See also flush_pending()).\n */\nfunction read_buf(strm, buf, start, size) {\n  var len = strm.avail_in;\n\n  if (len > size) { len = size; }\n  if (len === 0) { return 0; }\n\n  strm.avail_in -= len;\n\n  utils.arraySet(buf, strm.input, strm.next_in, len, start);\n  if (strm.state.wrap === 1) {\n    strm.adler = adler32(strm.adler, buf, len, start);\n  }\n\n  else if (strm.state.wrap === 2) {\n    strm.adler = crc32(strm.adler, buf, len, start);\n  }\n\n  strm.next_in += len;\n  strm.total_in += len;\n\n  return len;\n}\n\n\n/* ===========================================================================\n * Set match_start to the longest match starting at the given string and\n * return its length. Matches shorter or equal to prev_length are discarded,\n * in which case the result is equal to prev_length and match_start is\n * garbage.\n * IN assertions: cur_match is the head of the hash chain for the current\n *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1\n * OUT assertion: the match length is not greater than s->lookahead.\n */\nfunction longest_match(s, cur_match) {\n  var chain_length = s.max_chain_length;      /* max hash chain length */\n  var scan = s.strstart; /* current string */\n  var match;                       /* matched string */\n  var len;                           /* length of current match */\n  var best_len = s.prev_length;              /* best match length so far */\n  var nice_match = s.nice_match;             /* stop if match long enough */\n  var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?\n      s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;\n\n  var _win = s.window; // shortcut\n\n  var wmask = s.w_mask;\n  var prev  = s.prev;\n\n  /* Stop when cur_match becomes <= limit. To simplify the code,\n   * we prevent matches with the string of window index 0.\n   */\n\n  var strend = s.strstart + MAX_MATCH;\n  var scan_end1  = _win[scan + best_len - 1];\n  var scan_end   = _win[scan + best_len];\n\n  /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.\n   * It is easy to get rid of this optimization if necessary.\n   */\n  // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, \"Code too clever\");\n\n  /* Do not waste too much time if we already have a good match: */\n  if (s.prev_length >= s.good_match) {\n    chain_length >>= 2;\n  }\n  /* Do not look for matches beyond the end of the input. This is necessary\n   * to make deflate deterministic.\n   */\n  if (nice_match > s.lookahead) { nice_match = s.lookahead; }\n\n  // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, \"need lookahead\");\n\n  do {\n    // Assert(cur_match < s->strstart, \"no future\");\n    match = cur_match;\n\n    /* Skip to next match if the match length cannot increase\n     * or if the match length is less than 2.  Note that the checks below\n     * for insufficient lookahead only occur occasionally for performance\n     * reasons.  Therefore uninitialized memory will be accessed, and\n     * conditional jumps will be made that depend on those values.\n     * However the length of the match is limited to the lookahead, so\n     * the output of deflate is not affected by the uninitialized values.\n     */\n\n    if (_win[match + best_len]     !== scan_end  ||\n        _win[match + best_len - 1] !== scan_end1 ||\n        _win[match]                !== _win[scan] ||\n        _win[++match]              !== _win[scan + 1]) {\n      continue;\n    }\n\n    /* The check at best_len-1 can be removed because it will be made\n     * again later. (This heuristic is not always a win.)\n     * It is not necessary to compare scan[2] and match[2] since they\n     * are always equal when the other bytes match, given that\n     * the hash keys are equal and that HASH_BITS >= 8.\n     */\n    scan += 2;\n    match++;\n    // Assert(*scan == *match, \"match[2]?\");\n\n    /* We check for insufficient lookahead only every 8th comparison;\n     * the 256th check will be made at strstart+258.\n     */\n    do {\n      /*jshint noempty:false*/\n    } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             scan < strend);\n\n    // Assert(scan <= s->window+(unsigned)(s->window_size-1), \"wild scan\");\n\n    len = MAX_MATCH - (strend - scan);\n    scan = strend - MAX_MATCH;\n\n    if (len > best_len) {\n      s.match_start = cur_match;\n      best_len = len;\n      if (len >= nice_match) {\n        break;\n      }\n      scan_end1  = _win[scan + best_len - 1];\n      scan_end   = _win[scan + best_len];\n    }\n  } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);\n\n  if (best_len <= s.lookahead) {\n    return best_len;\n  }\n  return s.lookahead;\n}\n\n\n/* ===========================================================================\n * Fill the window when the lookahead becomes insufficient.\n * Updates strstart and lookahead.\n *\n * IN assertion: lookahead < MIN_LOOKAHEAD\n * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD\n *    At least one byte has been read, or avail_in == 0; reads are\n *    performed for at least two bytes (required for the zip translate_eol\n *    option -- not supported here).\n */\nfunction fill_window(s) {\n  var _w_size = s.w_size;\n  var p, n, m, more, str;\n\n  //Assert(s->lookahead < MIN_LOOKAHEAD, \"already enough lookahead\");\n\n  do {\n    more = s.window_size - s.lookahead - s.strstart;\n\n    // JS ints have 32 bit, block below not needed\n    /* Deal with !@#$% 64K limit: */\n    //if (sizeof(int) <= 2) {\n    //    if (more == 0 && s->strstart == 0 && s->lookahead == 0) {\n    //        more = wsize;\n    //\n    //  } else if (more == (unsigned)(-1)) {\n    //        /* Very unlikely, but possible on 16 bit machine if\n    //         * strstart == 0 && lookahead == 1 (input done a byte at time)\n    //         */\n    //        more--;\n    //    }\n    //}\n\n\n    /* If the window is almost full and there is insufficient lookahead,\n     * move the upper half to the lower one to make room in the upper half.\n     */\n    if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {\n\n      utils.arraySet(s.window, s.window, _w_size, _w_size, 0);\n      s.match_start -= _w_size;\n      s.strstart -= _w_size;\n      /* we now have strstart >= MAX_DIST */\n      s.block_start -= _w_size;\n\n      /* Slide the hash table (could be avoided with 32 bit values\n       at the expense of memory usage). We slide even when level == 0\n       to keep the hash table consistent if we switch back to level > 0\n       later. (Using level 0 permanently is not an optimal usage of\n       zlib, so we don't care about this pathological case.)\n       */\n\n      n = s.hash_size;\n      p = n;\n      do {\n        m = s.head[--p];\n        s.head[p] = (m >= _w_size ? m - _w_size : 0);\n      } while (--n);\n\n      n = _w_size;\n      p = n;\n      do {\n        m = s.prev[--p];\n        s.prev[p] = (m >= _w_size ? m - _w_size : 0);\n        /* If n is not on any hash chain, prev[n] is garbage but\n         * its value will never be used.\n         */\n      } while (--n);\n\n      more += _w_size;\n    }\n    if (s.strm.avail_in === 0) {\n      break;\n    }\n\n    /* If there was no sliding:\n     *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&\n     *    more == window_size - lookahead - strstart\n     * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)\n     * => more >= window_size - 2*WSIZE + 2\n     * In the BIG_MEM or MMAP case (not yet supported),\n     *   window_size == input_size + MIN_LOOKAHEAD  &&\n     *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.\n     * Otherwise, window_size == 2*WSIZE so more >= 2.\n     * If there was sliding, more >= WSIZE. So in all cases, more >= 2.\n     */\n    //Assert(more >= 2, \"more < 2\");\n    n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);\n    s.lookahead += n;\n\n    /* Initialize the hash value now that we have some input: */\n    if (s.lookahead + s.insert >= MIN_MATCH) {\n      str = s.strstart - s.insert;\n      s.ins_h = s.window[str];\n\n      /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */\n      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask;\n//#if MIN_MATCH != 3\n//        Call update_hash() MIN_MATCH-3 more times\n//#endif\n      while (s.insert) {\n        /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */\n        s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH-1]) & s.hash_mask;\n\n        s.prev[str & s.w_mask] = s.head[s.ins_h];\n        s.head[s.ins_h] = str;\n        str++;\n        s.insert--;\n        if (s.lookahead + s.insert < MIN_MATCH) {\n          break;\n        }\n      }\n    }\n    /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,\n     * but this is not important since only literal bytes will be emitted.\n     */\n\n  } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);\n\n  /* If the WIN_INIT bytes after the end of the current data have never been\n   * written, then zero those bytes in order to avoid memory check reports of\n   * the use of uninitialized (or uninitialised as Julian writes) bytes by\n   * the longest match routines.  Update the high water mark for the next\n   * time through here.  WIN_INIT is set to MAX_MATCH since the longest match\n   * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.\n   */\n//  if (s.high_water < s.window_size) {\n//    var curr = s.strstart + s.lookahead;\n//    var init = 0;\n//\n//    if (s.high_water < curr) {\n//      /* Previous high water mark below current data -- zero WIN_INIT\n//       * bytes or up to end of window, whichever is less.\n//       */\n//      init = s.window_size - curr;\n//      if (init > WIN_INIT)\n//        init = WIN_INIT;\n//      zmemzero(s->window + curr, (unsigned)init);\n//      s->high_water = curr + init;\n//    }\n//    else if (s->high_water < (ulg)curr + WIN_INIT) {\n//      /* High water mark at or above current data, but below current data\n//       * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up\n//       * to end of window, whichever is less.\n//       */\n//      init = (ulg)curr + WIN_INIT - s->high_water;\n//      if (init > s->window_size - s->high_water)\n//        init = s->window_size - s->high_water;\n//      zmemzero(s->window + s->high_water, (unsigned)init);\n//      s->high_water += init;\n//    }\n//  }\n//\n//  Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,\n//    \"not enough room for search\");\n}\n\n/* ===========================================================================\n * Copy without compression as much as possible from the input stream, return\n * the current block state.\n * This function does not insert new strings in the dictionary since\n * uncompressible data is probably not useful. This function is used\n * only for the level=0 compression option.\n * NOTE: this function should be optimized to avoid extra copying from\n * window to pending_buf.\n */\nfunction deflate_stored(s, flush) {\n  /* Stored blocks are limited to 0xffff bytes, pending_buf is limited\n   * to pending_buf_size, and each stored block has a 5 byte header:\n   */\n  var max_block_size = 0xffff;\n\n  if (max_block_size > s.pending_buf_size - 5) {\n    max_block_size = s.pending_buf_size - 5;\n  }\n\n  /* Copy as much as possible from input to output: */\n  for (;;) {\n    /* Fill the window as much as possible: */\n    if (s.lookahead <= 1) {\n\n      //Assert(s->strstart < s->w_size+MAX_DIST(s) ||\n      //  s->block_start >= (long)s->w_size, \"slide too late\");\n//      if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) ||\n//        s.block_start >= s.w_size)) {\n//        throw  new Error(\"slide too late\");\n//      }\n\n      fill_window(s);\n      if (s.lookahead === 0 && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n\n      if (s.lookahead === 0) {\n        break;\n      }\n      /* flush the current block */\n    }\n    //Assert(s->block_start >= 0L, \"block gone\");\n//    if (s.block_start < 0) throw new Error(\"block gone\");\n\n    s.strstart += s.lookahead;\n    s.lookahead = 0;\n\n    /* Emit a stored block if pending_buf will be full: */\n    var max_start = s.block_start + max_block_size;\n\n    if (s.strstart === 0 || s.strstart >= max_start) {\n      /* strstart == 0 is possible when wraparound on 16-bit machine */\n      s.lookahead = s.strstart - max_start;\n      s.strstart = max_start;\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n\n\n    }\n    /* Flush if we may have to slide, otherwise block_start may become\n     * negative and the data will be gone:\n     */\n    if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n\n  s.insert = 0;\n\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n\n  if (s.strstart > s.block_start) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n\n  return BS_NEED_MORE;\n}\n\n/* ===========================================================================\n * Compress as much as possible from the input stream, return the current\n * block state.\n * This function does not perform lazy evaluation of matches and inserts\n * new strings in the dictionary only for unmatched strings or for short\n * matches. It is used only for the fast compression options.\n */\nfunction deflate_fast(s, flush) {\n  var hash_head;        /* head of the hash chain */\n  var bflush;           /* set if current block must be flushed */\n\n  for (;;) {\n    /* Make sure that we always have enough lookahead, except\n     * at the end of the input file. We need MAX_MATCH bytes\n     * for the next match, plus MIN_MATCH bytes to insert the\n     * string following the next match.\n     */\n    if (s.lookahead < MIN_LOOKAHEAD) {\n      fill_window(s);\n      if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n      if (s.lookahead === 0) {\n        break; /* flush the current block */\n      }\n    }\n\n    /* Insert the string window[strstart .. strstart+2] in the\n     * dictionary, and set hash_head to the head of the hash chain:\n     */\n    hash_head = 0/*NIL*/;\n    if (s.lookahead >= MIN_MATCH) {\n      /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n      hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n      s.head[s.ins_h] = s.strstart;\n      /***/\n    }\n\n    /* Find the longest match, discarding those <= prev_length.\n     * At this point we have always match_length < MIN_MATCH\n     */\n    if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {\n      /* To simplify the code, we prevent matches with the string\n       * of window index 0 (in particular we have to avoid a match\n       * of the string with itself at the start of the input file).\n       */\n      s.match_length = longest_match(s, hash_head);\n      /* longest_match() sets match_start */\n    }\n    if (s.match_length >= MIN_MATCH) {\n      // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only\n\n      /*** _tr_tally_dist(s, s.strstart - s.match_start,\n                     s.match_length - MIN_MATCH, bflush); ***/\n      bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);\n\n      s.lookahead -= s.match_length;\n\n      /* Insert new strings in the hash table only if the match length\n       * is not too large. This saves time but degrades compression.\n       */\n      if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) {\n        s.match_length--; /* string at strstart already in table */\n        do {\n          s.strstart++;\n          /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n          s.head[s.ins_h] = s.strstart;\n          /***/\n          /* strstart never exceeds WSIZE-MAX_MATCH, so there are\n           * always MIN_MATCH bytes ahead.\n           */\n        } while (--s.match_length !== 0);\n        s.strstart++;\n      } else\n      {\n        s.strstart += s.match_length;\n        s.match_length = 0;\n        s.ins_h = s.window[s.strstart];\n        /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */\n        s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask;\n\n//#if MIN_MATCH != 3\n//                Call UPDATE_HASH() MIN_MATCH-3 more times\n//#endif\n        /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not\n         * matter since it will be recomputed at next deflate call.\n         */\n      }\n    } else {\n      /* No match, output a literal byte */\n      //Tracevv((stderr,\"%c\", s.window[s.strstart]));\n      /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/\n      bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n\n      s.lookahead--;\n      s.strstart++;\n    }\n    if (bflush) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n  s.insert = ((s.strstart < (MIN_MATCH-1)) ? s.strstart : MIN_MATCH-1);\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n  return BS_BLOCK_DONE;\n}\n\n/* ===========================================================================\n * Same as above, but achieves better compression. We use a lazy\n * evaluation for matches: a match is finally adopted only if there is\n * no better match at the next window position.\n */\nfunction deflate_slow(s, flush) {\n  var hash_head;          /* head of hash chain */\n  var bflush;              /* set if current block must be flushed */\n\n  var max_insert;\n\n  /* Process the input block. */\n  for (;;) {\n    /* Make sure that we always have enough lookahead, except\n     * at the end of the input file. We need MAX_MATCH bytes\n     * for the next match, plus MIN_MATCH bytes to insert the\n     * string following the next match.\n     */\n    if (s.lookahead < MIN_LOOKAHEAD) {\n      fill_window(s);\n      if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n      if (s.lookahead === 0) { break; } /* flush the current block */\n    }\n\n    /* Insert the string window[strstart .. strstart+2] in the\n     * dictionary, and set hash_head to the head of the hash chain:\n     */\n    hash_head = 0/*NIL*/;\n    if (s.lookahead >= MIN_MATCH) {\n      /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n      hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n      s.head[s.ins_h] = s.strstart;\n      /***/\n    }\n\n    /* Find the longest match, discarding those <= prev_length.\n     */\n    s.prev_length = s.match_length;\n    s.prev_match = s.match_start;\n    s.match_length = MIN_MATCH-1;\n\n    if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&\n        s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {\n      /* To simplify the code, we prevent matches with the string\n       * of window index 0 (in particular we have to avoid a match\n       * of the string with itself at the start of the input file).\n       */\n      s.match_length = longest_match(s, hash_head);\n      /* longest_match() sets match_start */\n\n      if (s.match_length <= 5 &&\n         (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {\n\n        /* If prev_match is also MIN_MATCH, match_start is garbage\n         * but we will ignore the current match anyway.\n         */\n        s.match_length = MIN_MATCH-1;\n      }\n    }\n    /* If there was a match at the previous step and the current\n     * match is not better, output the previous match:\n     */\n    if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {\n      max_insert = s.strstart + s.lookahead - MIN_MATCH;\n      /* Do not insert strings in hash table beyond this. */\n\n      //check_match(s, s.strstart-1, s.prev_match, s.prev_length);\n\n      /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,\n                     s.prev_length - MIN_MATCH, bflush);***/\n      bflush = trees._tr_tally(s, s.strstart - 1- s.prev_match, s.prev_length - MIN_MATCH);\n      /* Insert in hash table all strings up to the end of the match.\n       * strstart-1 and strstart are already inserted. If there is not\n       * enough lookahead, the last two strings are not inserted in\n       * the hash table.\n       */\n      s.lookahead -= s.prev_length-1;\n      s.prev_length -= 2;\n      do {\n        if (++s.strstart <= max_insert) {\n          /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n          s.head[s.ins_h] = s.strstart;\n          /***/\n        }\n      } while (--s.prev_length !== 0);\n      s.match_available = 0;\n      s.match_length = MIN_MATCH-1;\n      s.strstart++;\n\n      if (bflush) {\n        /*** FLUSH_BLOCK(s, 0); ***/\n        flush_block_only(s, false);\n        if (s.strm.avail_out === 0) {\n          return BS_NEED_MORE;\n        }\n        /***/\n      }\n\n    } else if (s.match_available) {\n      /* If there was no match at the previous position, output a\n       * single literal. If there was a match but the current match\n       * is longer, truncate the previous match to a single literal.\n       */\n      //Tracevv((stderr,\"%c\", s->window[s->strstart-1]));\n      /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/\n      bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]);\n\n      if (bflush) {\n        /*** FLUSH_BLOCK_ONLY(s, 0) ***/\n        flush_block_only(s, false);\n        /***/\n      }\n      s.strstart++;\n      s.lookahead--;\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n    } else {\n      /* There is no previous match to compare with, wait for\n       * the next step to decide.\n       */\n      s.match_available = 1;\n      s.strstart++;\n      s.lookahead--;\n    }\n  }\n  //Assert (flush != Z_NO_FLUSH, \"no flush?\");\n  if (s.match_available) {\n    //Tracevv((stderr,\"%c\", s->window[s->strstart-1]));\n    /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/\n    bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]);\n\n    s.match_available = 0;\n  }\n  s.insert = s.strstart < MIN_MATCH-1 ? s.strstart : MIN_MATCH-1;\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n\n  return BS_BLOCK_DONE;\n}\n\n\n/* ===========================================================================\n * For Z_RLE, simply look for runs of bytes, generate matches only of distance\n * one.  Do not maintain a hash table.  (It will be regenerated if this run of\n * deflate switches away from Z_RLE.)\n */\nfunction deflate_rle(s, flush) {\n  var bflush;            /* set if current block must be flushed */\n  var prev;              /* byte at distance one to match */\n  var scan, strend;      /* scan goes up to strend for length of run */\n\n  var _win = s.window;\n\n  for (;;) {\n    /* Make sure that we always have enough lookahead, except\n     * at the end of the input file. We need MAX_MATCH bytes\n     * for the longest run, plus one for the unrolled loop.\n     */\n    if (s.lookahead <= MAX_MATCH) {\n      fill_window(s);\n      if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n      if (s.lookahead === 0) { break; } /* flush the current block */\n    }\n\n    /* See how many times the previous byte repeats */\n    s.match_length = 0;\n    if (s.lookahead >= MIN_MATCH && s.strstart > 0) {\n      scan = s.strstart - 1;\n      prev = _win[scan];\n      if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {\n        strend = s.strstart + MAX_MATCH;\n        do {\n          /*jshint noempty:false*/\n        } while (prev === _win[++scan] && prev === _win[++scan] &&\n                 prev === _win[++scan] && prev === _win[++scan] &&\n                 prev === _win[++scan] && prev === _win[++scan] &&\n                 prev === _win[++scan] && prev === _win[++scan] &&\n                 scan < strend);\n        s.match_length = MAX_MATCH - (strend - scan);\n        if (s.match_length > s.lookahead) {\n          s.match_length = s.lookahead;\n        }\n      }\n      //Assert(scan <= s->window+(uInt)(s->window_size-1), \"wild scan\");\n    }\n\n    /* Emit match if have run of MIN_MATCH or longer, else emit literal */\n    if (s.match_length >= MIN_MATCH) {\n      //check_match(s, s.strstart, s.strstart - 1, s.match_length);\n\n      /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/\n      bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH);\n\n      s.lookahead -= s.match_length;\n      s.strstart += s.match_length;\n      s.match_length = 0;\n    } else {\n      /* No match, output a literal byte */\n      //Tracevv((stderr,\"%c\", s->window[s->strstart]));\n      /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/\n      bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n\n      s.lookahead--;\n      s.strstart++;\n    }\n    if (bflush) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n  s.insert = 0;\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n  return BS_BLOCK_DONE;\n}\n\n/* ===========================================================================\n * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.\n * (It will be regenerated if this run of deflate switches away from Huffman.)\n */\nfunction deflate_huff(s, flush) {\n  var bflush;             /* set if current block must be flushed */\n\n  for (;;) {\n    /* Make sure that we have a literal to write. */\n    if (s.lookahead === 0) {\n      fill_window(s);\n      if (s.lookahead === 0) {\n        if (flush === Z_NO_FLUSH) {\n          return BS_NEED_MORE;\n        }\n        break;      /* flush the current block */\n      }\n    }\n\n    /* Output a literal byte */\n    s.match_length = 0;\n    //Tracevv((stderr,\"%c\", s->window[s->strstart]));\n    /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/\n    bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n    s.lookahead--;\n    s.strstart++;\n    if (bflush) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n  s.insert = 0;\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n  return BS_BLOCK_DONE;\n}\n\n/* Values for max_lazy_match, good_match and max_chain_length, depending on\n * the desired pack level (0..9). The values given below have been tuned to\n * exclude worst case performance for pathological files. Better values may be\n * found for specific files.\n */\nvar Config = function (good_length, max_lazy, nice_length, max_chain, func) {\n  this.good_length = good_length;\n  this.max_lazy = max_lazy;\n  this.nice_length = nice_length;\n  this.max_chain = max_chain;\n  this.func = func;\n};\n\nvar configuration_table;\n\nconfiguration_table = [\n  /*      good lazy nice chain */\n  new Config(0, 0, 0, 0, deflate_stored),          /* 0 store only */\n  new Config(4, 4, 8, 4, deflate_fast),            /* 1 max speed, no lazy matches */\n  new Config(4, 5, 16, 8, deflate_fast),           /* 2 */\n  new Config(4, 6, 32, 32, deflate_fast),          /* 3 */\n\n  new Config(4, 4, 16, 16, deflate_slow),          /* 4 lazy matches */\n  new Config(8, 16, 32, 32, deflate_slow),         /* 5 */\n  new Config(8, 16, 128, 128, deflate_slow),       /* 6 */\n  new Config(8, 32, 128, 256, deflate_slow),       /* 7 */\n  new Config(32, 128, 258, 1024, deflate_slow),    /* 8 */\n  new Config(32, 258, 258, 4096, deflate_slow)     /* 9 max compression */\n];\n\n\n/* ===========================================================================\n * Initialize the \"longest match\" routines for a new zlib stream\n */\nfunction lm_init(s) {\n  s.window_size = 2 * s.w_size;\n\n  /*** CLEAR_HASH(s); ***/\n  zero(s.head); // Fill with NIL (= 0);\n\n  /* Set the default configuration parameters:\n   */\n  s.max_lazy_match = configuration_table[s.level].max_lazy;\n  s.good_match = configuration_table[s.level].good_length;\n  s.nice_match = configuration_table[s.level].nice_length;\n  s.max_chain_length = configuration_table[s.level].max_chain;\n\n  s.strstart = 0;\n  s.block_start = 0;\n  s.lookahead = 0;\n  s.insert = 0;\n  s.match_length = s.prev_length = MIN_MATCH - 1;\n  s.match_available = 0;\n  s.ins_h = 0;\n}\n\n\nfunction DeflateState() {\n  this.strm = null;            /* pointer back to this zlib stream */\n  this.status = 0;            /* as the name implies */\n  this.pending_buf = null;      /* output still pending */\n  this.pending_buf_size = 0;  /* size of pending_buf */\n  this.pending_out = 0;       /* next pending byte to output to the stream */\n  this.pending = 0;           /* nb of bytes in the pending buffer */\n  this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */\n  this.gzhead = null;         /* gzip header information to write */\n  this.gzindex = 0;           /* where in extra, name, or comment */\n  this.method = Z_DEFLATED; /* can only be DEFLATED */\n  this.last_flush = -1;   /* value of flush param for previous deflate call */\n\n  this.w_size = 0;  /* LZ77 window size (32K by default) */\n  this.w_bits = 0;  /* log2(w_size)  (8..16) */\n  this.w_mask = 0;  /* w_size - 1 */\n\n  this.window = null;\n  /* Sliding window. Input bytes are read into the second half of the window,\n   * and move to the first half later to keep a dictionary of at least wSize\n   * bytes. With this organization, matches are limited to a distance of\n   * wSize-MAX_MATCH bytes, but this ensures that IO is always\n   * performed with a length multiple of the block size.\n   */\n\n  this.window_size = 0;\n  /* Actual size of window: 2*wSize, except when the user input buffer\n   * is directly used as sliding window.\n   */\n\n  this.prev = null;\n  /* Link to older string with same hash index. To limit the size of this\n   * array to 64K, this link is maintained only for the last 32K strings.\n   * An index in this array is thus a window index modulo 32K.\n   */\n\n  this.head = null;   /* Heads of the hash chains or NIL. */\n\n  this.ins_h = 0;       /* hash index of string to be inserted */\n  this.hash_size = 0;   /* number of elements in hash table */\n  this.hash_bits = 0;   /* log2(hash_size) */\n  this.hash_mask = 0;   /* hash_size-1 */\n\n  this.hash_shift = 0;\n  /* Number of bits by which ins_h must be shifted at each input\n   * step. It must be such that after MIN_MATCH steps, the oldest\n   * byte no longer takes part in the hash key, that is:\n   *   hash_shift * MIN_MATCH >= hash_bits\n   */\n\n  this.block_start = 0;\n  /* Window position at the beginning of the current output block. Gets\n   * negative when the window is moved backwards.\n   */\n\n  this.match_length = 0;      /* length of best match */\n  this.prev_match = 0;        /* previous match */\n  this.match_available = 0;   /* set if previous match exists */\n  this.strstart = 0;          /* start of string to insert */\n  this.match_start = 0;       /* start of matching string */\n  this.lookahead = 0;         /* number of valid bytes ahead in window */\n\n  this.prev_length = 0;\n  /* Length of the best match at previous step. Matches not greater than this\n   * are discarded. This is used in the lazy match evaluation.\n   */\n\n  this.max_chain_length = 0;\n  /* To speed up deflation, hash chains are never searched beyond this\n   * length.  A higher limit improves compression ratio but degrades the\n   * speed.\n   */\n\n  this.max_lazy_match = 0;\n  /* Attempt to find a better match only when the current match is strictly\n   * smaller than this value. This mechanism is used only for compression\n   * levels >= 4.\n   */\n  // That's alias to max_lazy_match, don't use directly\n  //this.max_insert_length = 0;\n  /* Insert new strings in the hash table only if the match length is not\n   * greater than this length. This saves time but degrades compression.\n   * max_insert_length is used only for compression levels <= 3.\n   */\n\n  this.level = 0;     /* compression level (1..9) */\n  this.strategy = 0;  /* favor or force Huffman coding*/\n\n  this.good_match = 0;\n  /* Use a faster search when the previous match is longer than this */\n\n  this.nice_match = 0; /* Stop searching when current match exceeds this */\n\n              /* used by trees.c: */\n\n  /* Didn't use ct_data typedef below to suppress compiler warning */\n\n  // struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */\n  // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */\n  // struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */\n\n  // Use flat array of DOUBLE size, with interleaved fata,\n  // because JS does not support effective\n  this.dyn_ltree  = new utils.Buf16(HEAP_SIZE * 2);\n  this.dyn_dtree  = new utils.Buf16((2*D_CODES+1) * 2);\n  this.bl_tree    = new utils.Buf16((2*BL_CODES+1) * 2);\n  zero(this.dyn_ltree);\n  zero(this.dyn_dtree);\n  zero(this.bl_tree);\n\n  this.l_desc   = null;         /* desc. for literal tree */\n  this.d_desc   = null;         /* desc. for distance tree */\n  this.bl_desc  = null;         /* desc. for bit length tree */\n\n  //ush bl_count[MAX_BITS+1];\n  this.bl_count = new utils.Buf16(MAX_BITS+1);\n  /* number of codes at each bit length for an optimal tree */\n\n  //int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */\n  this.heap = new utils.Buf16(2*L_CODES+1);  /* heap used to build the Huffman trees */\n  zero(this.heap);\n\n  this.heap_len = 0;               /* number of elements in the heap */\n  this.heap_max = 0;               /* element of largest frequency */\n  /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.\n   * The same heap array is used to build all trees.\n   */\n\n  this.depth = new utils.Buf16(2*L_CODES+1); //uch depth[2*L_CODES+1];\n  zero(this.depth);\n  /* Depth of each subtree used as tie breaker for trees of equal frequency\n   */\n\n  this.l_buf = 0;          /* buffer index for literals or lengths */\n\n  this.lit_bufsize = 0;\n  /* Size of match buffer for literals/lengths.  There are 4 reasons for\n   * limiting lit_bufsize to 64K:\n   *   - frequencies can be kept in 16 bit counters\n   *   - if compression is not successful for the first block, all input\n   *     data is still in the window so we can still emit a stored block even\n   *     when input comes from standard input.  (This can also be done for\n   *     all blocks if lit_bufsize is not greater than 32K.)\n   *   - if compression is not successful for a file smaller than 64K, we can\n   *     even emit a stored file instead of a stored block (saving 5 bytes).\n   *     This is applicable only for zip (not gzip or zlib).\n   *   - creating new Huffman trees less frequently may not provide fast\n   *     adaptation to changes in the input data statistics. (Take for\n   *     example a binary file with poorly compressible code followed by\n   *     a highly compressible string table.) Smaller buffer sizes give\n   *     fast adaptation but have of course the overhead of transmitting\n   *     trees more frequently.\n   *   - I can't count above 4\n   */\n\n  this.last_lit = 0;      /* running index in l_buf */\n\n  this.d_buf = 0;\n  /* Buffer index for distances. To simplify the code, d_buf and l_buf have\n   * the same number of elements. To use different lengths, an extra flag\n   * array would be necessary.\n   */\n\n  this.opt_len = 0;       /* bit length of current block with optimal trees */\n  this.static_len = 0;    /* bit length of current block with static trees */\n  this.matches = 0;       /* number of string matches in current block */\n  this.insert = 0;        /* bytes at end of window left to insert */\n\n\n  this.bi_buf = 0;\n  /* Output buffer. bits are inserted starting at the bottom (least\n   * significant bits).\n   */\n  this.bi_valid = 0;\n  /* Number of valid bits in bi_buf.  All bits above the last valid bit\n   * are always zero.\n   */\n\n  // Used for window memory init. We safely ignore it for JS. That makes\n  // sense only for pointers and memory check tools.\n  //this.high_water = 0;\n  /* High water mark offset in window for initialized bytes -- bytes above\n   * this are set to zero in order to avoid memory check warnings when\n   * longest match routines access bytes past the input.  This is then\n   * updated to the new high water mark.\n   */\n}\n\n\nfunction deflateResetKeep(strm) {\n  var s;\n\n  if (!strm || !strm.state) {\n    return err(strm, Z_STREAM_ERROR);\n  }\n\n  strm.total_in = strm.total_out = 0;\n  strm.data_type = Z_UNKNOWN;\n\n  s = strm.state;\n  s.pending = 0;\n  s.pending_out = 0;\n\n  if (s.wrap < 0) {\n    s.wrap = -s.wrap;\n    /* was made negative by deflate(..., Z_FINISH); */\n  }\n  s.status = (s.wrap ? INIT_STATE : BUSY_STATE);\n  strm.adler = (s.wrap === 2) ?\n    0  // crc32(0, Z_NULL, 0)\n  :\n    1; // adler32(0, Z_NULL, 0)\n  s.last_flush = Z_NO_FLUSH;\n  trees._tr_init(s);\n  return Z_OK;\n}\n\n\nfunction deflateReset(strm) {\n  var ret = deflateResetKeep(strm);\n  if (ret === Z_OK) {\n    lm_init(strm.state);\n  }\n  return ret;\n}\n\n\nfunction deflateSetHeader(strm, head) {\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; }\n  strm.state.gzhead = head;\n  return Z_OK;\n}\n\n\nfunction deflateInit2(strm, level, method, windowBits, memLevel, strategy) {\n  if (!strm) { // === Z_NULL\n    return Z_STREAM_ERROR;\n  }\n  var wrap = 1;\n\n  if (level === Z_DEFAULT_COMPRESSION) {\n    level = 6;\n  }\n\n  if (windowBits < 0) { /* suppress zlib wrapper */\n    wrap = 0;\n    windowBits = -windowBits;\n  }\n\n  else if (windowBits > 15) {\n    wrap = 2;           /* write gzip wrapper instead */\n    windowBits -= 16;\n  }\n\n\n  if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED ||\n    windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||\n    strategy < 0 || strategy > Z_FIXED) {\n    return err(strm, Z_STREAM_ERROR);\n  }\n\n\n  if (windowBits === 8) {\n    windowBits = 9;\n  }\n  /* until 256-byte window bug fixed */\n\n  var s = new DeflateState();\n\n  strm.state = s;\n  s.strm = strm;\n\n  s.wrap = wrap;\n  s.gzhead = null;\n  s.w_bits = windowBits;\n  s.w_size = 1 << s.w_bits;\n  s.w_mask = s.w_size - 1;\n\n  s.hash_bits = memLevel + 7;\n  s.hash_size = 1 << s.hash_bits;\n  s.hash_mask = s.hash_size - 1;\n  s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);\n\n  s.window = new utils.Buf8(s.w_size * 2);\n  s.head = new utils.Buf16(s.hash_size);\n  s.prev = new utils.Buf16(s.w_size);\n\n  // Don't need mem init magic for JS.\n  //s.high_water = 0;  /* nothing written to s->window yet */\n\n  s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */\n\n  s.pending_buf_size = s.lit_bufsize * 4;\n  s.pending_buf = new utils.Buf8(s.pending_buf_size);\n\n  s.d_buf = s.lit_bufsize >> 1;\n  s.l_buf = (1 + 2) * s.lit_bufsize;\n\n  s.level = level;\n  s.strategy = strategy;\n  s.method = method;\n\n  return deflateReset(strm);\n}\n\nfunction deflateInit(strm, level) {\n  return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);\n}\n\n\nfunction deflate(strm, flush) {\n  var old_flush, s;\n  var beg, val; // for gzip header write only\n\n  if (!strm || !strm.state ||\n    flush > Z_BLOCK || flush < 0) {\n    return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR;\n  }\n\n  s = strm.state;\n\n  if (!strm.output ||\n      (!strm.input && strm.avail_in !== 0) ||\n      (s.status === FINISH_STATE && flush !== Z_FINISH)) {\n    return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR);\n  }\n\n  s.strm = strm; /* just in case */\n  old_flush = s.last_flush;\n  s.last_flush = flush;\n\n  /* Write the header */\n  if (s.status === INIT_STATE) {\n\n    if (s.wrap === 2) { // GZIP header\n      strm.adler = 0;  //crc32(0L, Z_NULL, 0);\n      put_byte(s, 31);\n      put_byte(s, 139);\n      put_byte(s, 8);\n      if (!s.gzhead) { // s->gzhead == Z_NULL\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, s.level === 9 ? 2 :\n                    (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?\n                     4 : 0));\n        put_byte(s, OS_CODE);\n        s.status = BUSY_STATE;\n      }\n      else {\n        put_byte(s, (s.gzhead.text ? 1 : 0) +\n                    (s.gzhead.hcrc ? 2 : 0) +\n                    (!s.gzhead.extra ? 0 : 4) +\n                    (!s.gzhead.name ? 0 : 8) +\n                    (!s.gzhead.comment ? 0 : 16)\n                );\n        put_byte(s, s.gzhead.time & 0xff);\n        put_byte(s, (s.gzhead.time >> 8) & 0xff);\n        put_byte(s, (s.gzhead.time >> 16) & 0xff);\n        put_byte(s, (s.gzhead.time >> 24) & 0xff);\n        put_byte(s, s.level === 9 ? 2 :\n                    (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?\n                     4 : 0));\n        put_byte(s, s.gzhead.os & 0xff);\n        if (s.gzhead.extra && s.gzhead.extra.length) {\n          put_byte(s, s.gzhead.extra.length & 0xff);\n          put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);\n        }\n        if (s.gzhead.hcrc) {\n          strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0);\n        }\n        s.gzindex = 0;\n        s.status = EXTRA_STATE;\n      }\n    }\n    else // DEFLATE header\n    {\n      var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8;\n      var level_flags = -1;\n\n      if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {\n        level_flags = 0;\n      } else if (s.level < 6) {\n        level_flags = 1;\n      } else if (s.level === 6) {\n        level_flags = 2;\n      } else {\n        level_flags = 3;\n      }\n      header |= (level_flags << 6);\n      if (s.strstart !== 0) { header |= PRESET_DICT; }\n      header += 31 - (header % 31);\n\n      s.status = BUSY_STATE;\n      putShortMSB(s, header);\n\n      /* Save the adler32 of the preset dictionary: */\n      if (s.strstart !== 0) {\n        putShortMSB(s, strm.adler >>> 16);\n        putShortMSB(s, strm.adler & 0xffff);\n      }\n      strm.adler = 1; // adler32(0L, Z_NULL, 0);\n    }\n  }\n\n//#ifdef GZIP\n  if (s.status === EXTRA_STATE) {\n    if (s.gzhead.extra/* != Z_NULL*/) {\n      beg = s.pending;  /* start of bytes to update crc */\n\n      while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {\n        if (s.pending === s.pending_buf_size) {\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          flush_pending(strm);\n          beg = s.pending;\n          if (s.pending === s.pending_buf_size) {\n            break;\n          }\n        }\n        put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);\n        s.gzindex++;\n      }\n      if (s.gzhead.hcrc && s.pending > beg) {\n        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n      }\n      if (s.gzindex === s.gzhead.extra.length) {\n        s.gzindex = 0;\n        s.status = NAME_STATE;\n      }\n    }\n    else {\n      s.status = NAME_STATE;\n    }\n  }\n  if (s.status === NAME_STATE) {\n    if (s.gzhead.name/* != Z_NULL*/) {\n      beg = s.pending;  /* start of bytes to update crc */\n      //int val;\n\n      do {\n        if (s.pending === s.pending_buf_size) {\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          flush_pending(strm);\n          beg = s.pending;\n          if (s.pending === s.pending_buf_size) {\n            val = 1;\n            break;\n          }\n        }\n        // JS specific: little magic to add zero terminator to end of string\n        if (s.gzindex < s.gzhead.name.length) {\n          val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;\n        } else {\n          val = 0;\n        }\n        put_byte(s, val);\n      } while (val !== 0);\n\n      if (s.gzhead.hcrc && s.pending > beg){\n        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n      }\n      if (val === 0) {\n        s.gzindex = 0;\n        s.status = COMMENT_STATE;\n      }\n    }\n    else {\n      s.status = COMMENT_STATE;\n    }\n  }\n  if (s.status === COMMENT_STATE) {\n    if (s.gzhead.comment/* != Z_NULL*/) {\n      beg = s.pending;  /* start of bytes to update crc */\n      //int val;\n\n      do {\n        if (s.pending === s.pending_buf_size) {\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          flush_pending(strm);\n          beg = s.pending;\n          if (s.pending === s.pending_buf_size) {\n            val = 1;\n            break;\n          }\n        }\n        // JS specific: little magic to add zero terminator to end of string\n        if (s.gzindex < s.gzhead.comment.length) {\n          val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;\n        } else {\n          val = 0;\n        }\n        put_byte(s, val);\n      } while (val !== 0);\n\n      if (s.gzhead.hcrc && s.pending > beg) {\n        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n      }\n      if (val === 0) {\n        s.status = HCRC_STATE;\n      }\n    }\n    else {\n      s.status = HCRC_STATE;\n    }\n  }\n  if (s.status === HCRC_STATE) {\n    if (s.gzhead.hcrc) {\n      if (s.pending + 2 > s.pending_buf_size) {\n        flush_pending(strm);\n      }\n      if (s.pending + 2 <= s.pending_buf_size) {\n        put_byte(s, strm.adler & 0xff);\n        put_byte(s, (strm.adler >> 8) & 0xff);\n        strm.adler = 0; //crc32(0L, Z_NULL, 0);\n        s.status = BUSY_STATE;\n      }\n    }\n    else {\n      s.status = BUSY_STATE;\n    }\n  }\n//#endif\n\n  /* Flush as much pending output as possible */\n  if (s.pending !== 0) {\n    flush_pending(strm);\n    if (strm.avail_out === 0) {\n      /* Since avail_out is 0, deflate will be called again with\n       * more output space, but possibly with both pending and\n       * avail_in equal to zero. There won't be anything to do,\n       * but this is not an error situation so make sure we\n       * return OK instead of BUF_ERROR at next call of deflate:\n       */\n      s.last_flush = -1;\n      return Z_OK;\n    }\n\n    /* Make sure there is something to do and avoid duplicate consecutive\n     * flushes. For repeated and useless calls with Z_FINISH, we keep\n     * returning Z_STREAM_END instead of Z_BUF_ERROR.\n     */\n  } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&\n    flush !== Z_FINISH) {\n    return err(strm, Z_BUF_ERROR);\n  }\n\n  /* User must not provide more input after the first FINISH: */\n  if (s.status === FINISH_STATE && strm.avail_in !== 0) {\n    return err(strm, Z_BUF_ERROR);\n  }\n\n  /* Start a new block or continue the current one.\n   */\n  if (strm.avail_in !== 0 || s.lookahead !== 0 ||\n    (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) {\n    var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) :\n      (s.strategy === Z_RLE ? deflate_rle(s, flush) :\n        configuration_table[s.level].func(s, flush));\n\n    if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {\n      s.status = FINISH_STATE;\n    }\n    if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {\n      if (strm.avail_out === 0) {\n        s.last_flush = -1;\n        /* avoid BUF_ERROR next call, see above */\n      }\n      return Z_OK;\n      /* If flush != Z_NO_FLUSH && avail_out == 0, the next call\n       * of deflate should use the same flush parameter to make sure\n       * that the flush is complete. So we don't have to output an\n       * empty block here, this will be done at next call. This also\n       * ensures that for a very small output buffer, we emit at most\n       * one empty block.\n       */\n    }\n    if (bstate === BS_BLOCK_DONE) {\n      if (flush === Z_PARTIAL_FLUSH) {\n        trees._tr_align(s);\n      }\n      else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */\n\n        trees._tr_stored_block(s, 0, 0, false);\n        /* For a full flush, this empty block will be recognized\n         * as a special marker by inflate_sync().\n         */\n        if (flush === Z_FULL_FLUSH) {\n          /*** CLEAR_HASH(s); ***/             /* forget history */\n          zero(s.head); // Fill with NIL (= 0);\n\n          if (s.lookahead === 0) {\n            s.strstart = 0;\n            s.block_start = 0;\n            s.insert = 0;\n          }\n        }\n      }\n      flush_pending(strm);\n      if (strm.avail_out === 0) {\n        s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */\n        return Z_OK;\n      }\n    }\n  }\n  //Assert(strm->avail_out > 0, \"bug2\");\n  //if (strm.avail_out <= 0) { throw new Error(\"bug2\");}\n\n  if (flush !== Z_FINISH) { return Z_OK; }\n  if (s.wrap <= 0) { return Z_STREAM_END; }\n\n  /* Write the trailer */\n  if (s.wrap === 2) {\n    put_byte(s, strm.adler & 0xff);\n    put_byte(s, (strm.adler >> 8) & 0xff);\n    put_byte(s, (strm.adler >> 16) & 0xff);\n    put_byte(s, (strm.adler >> 24) & 0xff);\n    put_byte(s, strm.total_in & 0xff);\n    put_byte(s, (strm.total_in >> 8) & 0xff);\n    put_byte(s, (strm.total_in >> 16) & 0xff);\n    put_byte(s, (strm.total_in >> 24) & 0xff);\n  }\n  else\n  {\n    putShortMSB(s, strm.adler >>> 16);\n    putShortMSB(s, strm.adler & 0xffff);\n  }\n\n  flush_pending(strm);\n  /* If avail_out is zero, the application will call deflate again\n   * to flush the rest.\n   */\n  if (s.wrap > 0) { s.wrap = -s.wrap; }\n  /* write the trailer only once! */\n  return s.pending !== 0 ? Z_OK : Z_STREAM_END;\n}\n\nfunction deflateEnd(strm) {\n  var status;\n\n  if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {\n    return Z_STREAM_ERROR;\n  }\n\n  status = strm.state.status;\n  if (status !== INIT_STATE &&\n    status !== EXTRA_STATE &&\n    status !== NAME_STATE &&\n    status !== COMMENT_STATE &&\n    status !== HCRC_STATE &&\n    status !== BUSY_STATE &&\n    status !== FINISH_STATE\n  ) {\n    return err(strm, Z_STREAM_ERROR);\n  }\n\n  strm.state = null;\n\n  return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK;\n}\n\n/* =========================================================================\n * Copy the source state to the destination state\n */\n//function deflateCopy(dest, source) {\n//\n//}\n\nexports.deflateInit = deflateInit;\nexports.deflateInit2 = deflateInit2;\nexports.deflateReset = deflateReset;\nexports.deflateResetKeep = deflateResetKeep;\nexports.deflateSetHeader = deflateSetHeader;\nexports.deflate = deflate;\nexports.deflateEnd = deflateEnd;\nexports.deflateInfo = 'pako deflate (from Nodeca project)';\n\n/* Not implemented\nexports.deflateBound = deflateBound;\nexports.deflateCopy = deflateCopy;\nexports.deflateSetDictionary = deflateSetDictionary;\nexports.deflateParams = deflateParams;\nexports.deflatePending = deflatePending;\nexports.deflatePrime = deflatePrime;\nexports.deflateTune = deflateTune;\n*/\n},{\"../utils/common\":27,\"./adler32\":29,\"./crc32\":31,\"./messages\":37,\"./trees\":38}],33:[function(_dereq_,module,exports){\n'use strict';\n\n\nfunction GZheader() {\n  /* true if compressed data believed to be text */\n  this.text       = 0;\n  /* modification time */\n  this.time       = 0;\n  /* extra flags (not used when writing a gzip file) */\n  this.xflags     = 0;\n  /* operating system */\n  this.os         = 0;\n  /* pointer to extra field or Z_NULL if none */\n  this.extra      = null;\n  /* extra field length (valid if extra != Z_NULL) */\n  this.extra_len  = 0; // Actually, we don't need it in JS,\n                       // but leave for few code modifications\n\n  //\n  // Setup limits is not necessary because in js we should not preallocate memory \n  // for inflate use constant limit in 65536 bytes\n  //\n\n  /* space at extra (only when reading header) */\n  // this.extra_max  = 0;\n  /* pointer to zero-terminated file name or Z_NULL */\n  this.name       = '';\n  /* space at name (only when reading header) */\n  // this.name_max   = 0;\n  /* pointer to zero-terminated comment or Z_NULL */\n  this.comment    = '';\n  /* space at comment (only when reading header) */\n  // this.comm_max   = 0;\n  /* true if there was or will be a header crc */\n  this.hcrc       = 0;\n  /* true when done reading gzip header (not used when writing a gzip file) */\n  this.done       = false;\n}\n\nmodule.exports = GZheader;\n},{}],34:[function(_dereq_,module,exports){\n'use strict';\n\n// See state defs from inflate.js\nvar BAD = 30;       /* got a data error -- remain here until reset */\nvar TYPE = 12;      /* i: waiting for type bits, including last-flag bit */\n\n/*\n   Decode literal, length, and distance codes and write out the resulting\n   literal and match bytes until either not enough input or output is\n   available, an end-of-block is encountered, or a data error is encountered.\n   When large enough input and output buffers are supplied to inflate(), for\n   example, a 16K input buffer and a 64K output buffer, more than 95% of the\n   inflate execution time is spent in this routine.\n\n   Entry assumptions:\n\n        state.mode === LEN\n        strm.avail_in >= 6\n        strm.avail_out >= 258\n        start >= strm.avail_out\n        state.bits < 8\n\n   On return, state.mode is one of:\n\n        LEN -- ran out of enough output space or enough available input\n        TYPE -- reached end of block code, inflate() to interpret next block\n        BAD -- error in block data\n\n   Notes:\n\n    - The maximum input bits used by a length/distance pair is 15 bits for the\n      length code, 5 bits for the length extra, 15 bits for the distance code,\n      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.\n      Therefore if strm.avail_in >= 6, then there is enough input to avoid\n      checking for available input while decoding.\n\n    - The maximum bytes that a single length/distance pair can output is 258\n      bytes, which is the maximum length that can be coded.  inflate_fast()\n      requires strm.avail_out >= 258 for each loop to avoid checking for\n      output space.\n */\nmodule.exports = function inflate_fast(strm, start) {\n  var state;\n  var _in;                    /* local strm.input */\n  var last;                   /* have enough input while in < last */\n  var _out;                   /* local strm.output */\n  var beg;                    /* inflate()'s initial strm.output */\n  var end;                    /* while out < end, enough space available */\n//#ifdef INFLATE_STRICT\n  var dmax;                   /* maximum distance from zlib header */\n//#endif\n  var wsize;                  /* window size or zero if not using window */\n  var whave;                  /* valid bytes in the window */\n  var wnext;                  /* window write index */\n  var window;                 /* allocated sliding window, if wsize != 0 */\n  var hold;                   /* local strm.hold */\n  var bits;                   /* local strm.bits */\n  var lcode;                  /* local strm.lencode */\n  var dcode;                  /* local strm.distcode */\n  var lmask;                  /* mask for first level of length codes */\n  var dmask;                  /* mask for first level of distance codes */\n  var here;                   /* retrieved table entry */\n  var op;                     /* code bits, operation, extra bits, or */\n                              /*  window position, window bytes to copy */\n  var len;                    /* match length, unused bytes */\n  var dist;                   /* match distance */\n  var from;                   /* where to copy match from */\n  var from_source;\n\n\n  var input, output; // JS specific, because we have no pointers\n\n  /* copy state to local variables */\n  state = strm.state;\n  //here = state.here;\n  _in = strm.next_in;\n  input = strm.input;\n  last = _in + (strm.avail_in - 5);\n  _out = strm.next_out;\n  output = strm.output;\n  beg = _out - (start - strm.avail_out);\n  end = _out + (strm.avail_out - 257);\n//#ifdef INFLATE_STRICT\n  dmax = state.dmax;\n//#endif\n  wsize = state.wsize;\n  whave = state.whave;\n  wnext = state.wnext;\n  window = state.window;\n  hold = state.hold;\n  bits = state.bits;\n  lcode = state.lencode;\n  dcode = state.distcode;\n  lmask = (1 << state.lenbits) - 1;\n  dmask = (1 << state.distbits) - 1;\n\n\n  /* decode literals and length/distances until end-of-block or not enough\n     input data or output space */\n\n  top:\n  do {\n    if (bits < 15) {\n      hold += input[_in++] << bits;\n      bits += 8;\n      hold += input[_in++] << bits;\n      bits += 8;\n    }\n\n    here = lcode[hold & lmask];\n\n    dolen:\n    for (;;) { // Goto emulation\n      op = here >>> 24/*here.bits*/;\n      hold >>>= op;\n      bits -= op;\n      op = (here >>> 16) & 0xff/*here.op*/;\n      if (op === 0) {                          /* literal */\n        //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?\n        //        \"inflate:         literal '%c'\\n\" :\n        //        \"inflate:         literal 0x%02x\\n\", here.val));\n        output[_out++] = here & 0xffff/*here.val*/;\n      }\n      else if (op & 16) {                     /* length base */\n        len = here & 0xffff/*here.val*/;\n        op &= 15;                           /* number of extra bits */\n        if (op) {\n          if (bits < op) {\n            hold += input[_in++] << bits;\n            bits += 8;\n          }\n          len += hold & ((1 << op) - 1);\n          hold >>>= op;\n          bits -= op;\n        }\n        //Tracevv((stderr, \"inflate:         length %u\\n\", len));\n        if (bits < 15) {\n          hold += input[_in++] << bits;\n          bits += 8;\n          hold += input[_in++] << bits;\n          bits += 8;\n        }\n        here = dcode[hold & dmask];\n\n        dodist:\n        for (;;) { // goto emulation\n          op = here >>> 24/*here.bits*/;\n          hold >>>= op;\n          bits -= op;\n          op = (here >>> 16) & 0xff/*here.op*/;\n\n          if (op & 16) {                      /* distance base */\n            dist = here & 0xffff/*here.val*/;\n            op &= 15;                       /* number of extra bits */\n            if (bits < op) {\n              hold += input[_in++] << bits;\n              bits += 8;\n              if (bits < op) {\n                hold += input[_in++] << bits;\n                bits += 8;\n              }\n            }\n            dist += hold & ((1 << op) - 1);\n//#ifdef INFLATE_STRICT\n            if (dist > dmax) {\n              strm.msg = 'invalid distance too far back';\n              state.mode = BAD;\n              break top;\n            }\n//#endif\n            hold >>>= op;\n            bits -= op;\n            //Tracevv((stderr, \"inflate:         distance %u\\n\", dist));\n            op = _out - beg;                /* max distance in output */\n            if (dist > op) {                /* see if copy from window */\n              op = dist - op;               /* distance back in window */\n              if (op > whave) {\n                if (state.sane) {\n                  strm.msg = 'invalid distance too far back';\n                  state.mode = BAD;\n                  break top;\n                }\n\n// (!) This block is disabled in zlib defailts,\n// don't enable it for binary compatibility\n//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR\n//                if (len <= op - whave) {\n//                  do {\n//                    output[_out++] = 0;\n//                  } while (--len);\n//                  continue top;\n//                }\n//                len -= op - whave;\n//                do {\n//                  output[_out++] = 0;\n//                } while (--op > whave);\n//                if (op === 0) {\n//                  from = _out - dist;\n//                  do {\n//                    output[_out++] = output[from++];\n//                  } while (--len);\n//                  continue top;\n//                }\n//#endif\n              }\n              from = 0; // window index\n              from_source = window;\n              if (wnext === 0) {           /* very common case */\n                from += wsize - op;\n                if (op < len) {         /* some from window */\n                  len -= op;\n                  do {\n                    output[_out++] = window[from++];\n                  } while (--op);\n                  from = _out - dist;  /* rest from output */\n                  from_source = output;\n                }\n              }\n              else if (wnext < op) {      /* wrap around window */\n                from += wsize + wnext - op;\n                op -= wnext;\n                if (op < len) {         /* some from end of window */\n                  len -= op;\n                  do {\n                    output[_out++] = window[from++];\n                  } while (--op);\n                  from = 0;\n                  if (wnext < len) {  /* some from start of window */\n                    op = wnext;\n                    len -= op;\n                    do {\n                      output[_out++] = window[from++];\n                    } while (--op);\n                    from = _out - dist;      /* rest from output */\n                    from_source = output;\n                  }\n                }\n              }\n              else {                      /* contiguous in window */\n                from += wnext - op;\n                if (op < len) {         /* some from window */\n                  len -= op;\n                  do {\n                    output[_out++] = window[from++];\n                  } while (--op);\n                  from = _out - dist;  /* rest from output */\n                  from_source = output;\n                }\n              }\n              while (len > 2) {\n                output[_out++] = from_source[from++];\n                output[_out++] = from_source[from++];\n                output[_out++] = from_source[from++];\n                len -= 3;\n              }\n              if (len) {\n                output[_out++] = from_source[from++];\n                if (len > 1) {\n                  output[_out++] = from_source[from++];\n                }\n              }\n            }\n            else {\n              from = _out - dist;          /* copy direct from output */\n              do {                        /* minimum length is three */\n                output[_out++] = output[from++];\n                output[_out++] = output[from++];\n                output[_out++] = output[from++];\n                len -= 3;\n              } while (len > 2);\n              if (len) {\n                output[_out++] = output[from++];\n                if (len > 1) {\n                  output[_out++] = output[from++];\n                }\n              }\n            }\n          }\n          else if ((op & 64) === 0) {          /* 2nd level distance code */\n            here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];\n            continue dodist;\n          }\n          else {\n            strm.msg = 'invalid distance code';\n            state.mode = BAD;\n            break top;\n          }\n\n          break; // need to emulate goto via \"continue\"\n        }\n      }\n      else if ((op & 64) === 0) {              /* 2nd level length code */\n        here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];\n        continue dolen;\n      }\n      else if (op & 32) {                     /* end-of-block */\n        //Tracevv((stderr, \"inflate:         end of block\\n\"));\n        state.mode = TYPE;\n        break top;\n      }\n      else {\n        strm.msg = 'invalid literal/length code';\n        state.mode = BAD;\n        break top;\n      }\n\n      break; // need to emulate goto via \"continue\"\n    }\n  } while (_in < last && _out < end);\n\n  /* return unused bytes (on entry, bits < 8, so in won't go too far back) */\n  len = bits >> 3;\n  _in -= len;\n  bits -= len << 3;\n  hold &= (1 << bits) - 1;\n\n  /* update state and return */\n  strm.next_in = _in;\n  strm.next_out = _out;\n  strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));\n  strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));\n  state.hold = hold;\n  state.bits = bits;\n  return;\n};\n\n},{}],35:[function(_dereq_,module,exports){\n'use strict';\n\n\nvar utils = _dereq_('../utils/common');\nvar adler32 = _dereq_('./adler32');\nvar crc32   = _dereq_('./crc32');\nvar inflate_fast = _dereq_('./inffast');\nvar inflate_table = _dereq_('./inftrees');\n\nvar CODES = 0;\nvar LENS = 1;\nvar DISTS = 2;\n\n/* Public constants ==========================================================*/\n/* ===========================================================================*/\n\n\n/* Allowed flush values; see deflate() and inflate() below for details */\n//var Z_NO_FLUSH      = 0;\n//var Z_PARTIAL_FLUSH = 1;\n//var Z_SYNC_FLUSH    = 2;\n//var Z_FULL_FLUSH    = 3;\nvar Z_FINISH        = 4;\nvar Z_BLOCK         = 5;\nvar Z_TREES         = 6;\n\n\n/* Return codes for the compression/decompression functions. Negative values\n * are errors, positive values are used for special but normal events.\n */\nvar Z_OK            = 0;\nvar Z_STREAM_END    = 1;\nvar Z_NEED_DICT     = 2;\n//var Z_ERRNO         = -1;\nvar Z_STREAM_ERROR  = -2;\nvar Z_DATA_ERROR    = -3;\nvar Z_MEM_ERROR     = -4;\nvar Z_BUF_ERROR     = -5;\n//var Z_VERSION_ERROR = -6;\n\n/* The deflate compression method */\nvar Z_DEFLATED  = 8;\n\n\n/* STATES ====================================================================*/\n/* ===========================================================================*/\n\n\nvar    HEAD = 1;       /* i: waiting for magic header */\nvar    FLAGS = 2;      /* i: waiting for method and flags (gzip) */\nvar    TIME = 3;       /* i: waiting for modification time (gzip) */\nvar    OS = 4;         /* i: waiting for extra flags and operating system (gzip) */\nvar    EXLEN = 5;      /* i: waiting for extra length (gzip) */\nvar    EXTRA = 6;      /* i: waiting for extra bytes (gzip) */\nvar    NAME = 7;       /* i: waiting for end of file name (gzip) */\nvar    COMMENT = 8;    /* i: waiting for end of comment (gzip) */\nvar    HCRC = 9;       /* i: waiting for header crc (gzip) */\nvar    DICTID = 10;    /* i: waiting for dictionary check value */\nvar    DICT = 11;      /* waiting for inflateSetDictionary() call */\nvar        TYPE = 12;      /* i: waiting for type bits, including last-flag bit */\nvar        TYPEDO = 13;    /* i: same, but skip check to exit inflate on new block */\nvar        STORED = 14;    /* i: waiting for stored size (length and complement) */\nvar        COPY_ = 15;     /* i/o: same as COPY below, but only first time in */\nvar        COPY = 16;      /* i/o: waiting for input or output to copy stored block */\nvar        TABLE = 17;     /* i: waiting for dynamic block table lengths */\nvar        LENLENS = 18;   /* i: waiting for code length code lengths */\nvar        CODELENS = 19;  /* i: waiting for length/lit and distance code lengths */\nvar            LEN_ = 20;      /* i: same as LEN below, but only first time in */\nvar            LEN = 21;       /* i: waiting for length/lit/eob code */\nvar            LENEXT = 22;    /* i: waiting for length extra bits */\nvar            DIST = 23;      /* i: waiting for distance code */\nvar            DISTEXT = 24;   /* i: waiting for distance extra bits */\nvar            MATCH = 25;     /* o: waiting for output space to copy string */\nvar            LIT = 26;       /* o: waiting for output space to write literal */\nvar    CHECK = 27;     /* i: waiting for 32-bit check value */\nvar    LENGTH = 28;    /* i: waiting for 32-bit length (gzip) */\nvar    DONE = 29;      /* finished check, done -- remain here until reset */\nvar    BAD = 30;       /* got a data error -- remain here until reset */\nvar    MEM = 31;       /* got an inflate() memory error -- remain here until reset */\nvar    SYNC = 32;      /* looking for synchronization bytes to restart inflate() */\n\n/* ===========================================================================*/\n\n\n\nvar ENOUGH_LENS = 852;\nvar ENOUGH_DISTS = 592;\n//var ENOUGH =  (ENOUGH_LENS+ENOUGH_DISTS);\n\nvar MAX_WBITS = 15;\n/* 32K LZ77 window */\nvar DEF_WBITS = MAX_WBITS;\n\n\nfunction ZSWAP32(q) {\n  return  (((q >>> 24) & 0xff) +\n          ((q >>> 8) & 0xff00) +\n          ((q & 0xff00) << 8) +\n          ((q & 0xff) << 24));\n}\n\n\nfunction InflateState() {\n  this.mode = 0;             /* current inflate mode */\n  this.last = false;          /* true if processing last block */\n  this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */\n  this.havedict = false;      /* true if dictionary provided */\n  this.flags = 0;             /* gzip header method and flags (0 if zlib) */\n  this.dmax = 0;              /* zlib header max distance (INFLATE_STRICT) */\n  this.check = 0;             /* protected copy of check value */\n  this.total = 0;             /* protected copy of output count */\n  // TODO: may be {}\n  this.head = null;           /* where to save gzip header information */\n\n  /* sliding window */\n  this.wbits = 0;             /* log base 2 of requested window size */\n  this.wsize = 0;             /* window size or zero if not using window */\n  this.whave = 0;             /* valid bytes in the window */\n  this.wnext = 0;             /* window write index */\n  this.window = null;         /* allocated sliding window, if needed */\n\n  /* bit accumulator */\n  this.hold = 0;              /* input bit accumulator */\n  this.bits = 0;              /* number of bits in \"in\" */\n\n  /* for string and stored block copying */\n  this.length = 0;            /* literal or length of data to copy */\n  this.offset = 0;            /* distance back to copy string from */\n\n  /* for table and code decoding */\n  this.extra = 0;             /* extra bits needed */\n\n  /* fixed and dynamic code tables */\n  this.lencode = null;          /* starting table for length/literal codes */\n  this.distcode = null;         /* starting table for distance codes */\n  this.lenbits = 0;           /* index bits for lencode */\n  this.distbits = 0;          /* index bits for distcode */\n\n  /* dynamic table building */\n  this.ncode = 0;             /* number of code length code lengths */\n  this.nlen = 0;              /* number of length code lengths */\n  this.ndist = 0;             /* number of distance code lengths */\n  this.have = 0;              /* number of code lengths in lens[] */\n  this.next = null;              /* next available space in codes[] */\n\n  this.lens = new utils.Buf16(320); /* temporary storage for code lengths */\n  this.work = new utils.Buf16(288); /* work area for code table building */\n\n  /*\n   because we don't have pointers in js, we use lencode and distcode directly\n   as buffers so we don't need codes\n  */\n  //this.codes = new utils.Buf32(ENOUGH);       /* space for code tables */\n  this.lendyn = null;              /* dynamic table for length/literal codes (JS specific) */\n  this.distdyn = null;             /* dynamic table for distance codes (JS specific) */\n  this.sane = 0;                   /* if false, allow invalid distance too far */\n  this.back = 0;                   /* bits back of last unprocessed length/lit */\n  this.was = 0;                    /* initial length of match */\n}\n\nfunction inflateResetKeep(strm) {\n  var state;\n\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n  strm.total_in = strm.total_out = state.total = 0;\n  strm.msg = ''; /*Z_NULL*/\n  if (state.wrap) {       /* to support ill-conceived Java test suite */\n    strm.adler = state.wrap & 1;\n  }\n  state.mode = HEAD;\n  state.last = 0;\n  state.havedict = 0;\n  state.dmax = 32768;\n  state.head = null/*Z_NULL*/;\n  state.hold = 0;\n  state.bits = 0;\n  //state.lencode = state.distcode = state.next = state.codes;\n  state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS);\n  state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS);\n\n  state.sane = 1;\n  state.back = -1;\n  //Tracev((stderr, \"inflate: reset\\n\"));\n  return Z_OK;\n}\n\nfunction inflateReset(strm) {\n  var state;\n\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n  state.wsize = 0;\n  state.whave = 0;\n  state.wnext = 0;\n  return inflateResetKeep(strm);\n\n}\n\nfunction inflateReset2(strm, windowBits) {\n  var wrap;\n  var state;\n\n  /* get the state */\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n\n  /* extract wrap request from windowBits parameter */\n  if (windowBits < 0) {\n    wrap = 0;\n    windowBits = -windowBits;\n  }\n  else {\n    wrap = (windowBits >> 4) + 1;\n    if (windowBits < 48) {\n      windowBits &= 15;\n    }\n  }\n\n  /* set number of window bits, free window if different */\n  if (windowBits && (windowBits < 8 || windowBits > 15)) {\n    return Z_STREAM_ERROR;\n  }\n  if (state.window !== null && state.wbits !== windowBits) {\n    state.window = null;\n  }\n\n  /* update state and reset the rest of it */\n  state.wrap = wrap;\n  state.wbits = windowBits;\n  return inflateReset(strm);\n}\n\nfunction inflateInit2(strm, windowBits) {\n  var ret;\n  var state;\n\n  if (!strm) { return Z_STREAM_ERROR; }\n  //strm.msg = Z_NULL;                 /* in case we return an error */\n\n  state = new InflateState();\n\n  //if (state === Z_NULL) return Z_MEM_ERROR;\n  //Tracev((stderr, \"inflate: allocated\\n\"));\n  strm.state = state;\n  state.window = null/*Z_NULL*/;\n  ret = inflateReset2(strm, windowBits);\n  if (ret !== Z_OK) {\n    strm.state = null/*Z_NULL*/;\n  }\n  return ret;\n}\n\nfunction inflateInit(strm) {\n  return inflateInit2(strm, DEF_WBITS);\n}\n\n\n/*\n Return state with length and distance decoding tables and index sizes set to\n fixed code decoding.  Normally this returns fixed tables from inffixed.h.\n If BUILDFIXED is defined, then instead this routine builds the tables the\n first time it's called, and returns those tables the first time and\n thereafter.  This reduces the size of the code by about 2K bytes, in\n exchange for a little execution time.  However, BUILDFIXED should not be\n used for threaded applications, since the rewriting of the tables and virgin\n may not be thread-safe.\n */\nvar virgin = true;\n\nvar lenfix, distfix; // We have no pointers in JS, so keep tables separate\n\nfunction fixedtables(state) {\n  /* build fixed huffman tables if first call (may not be thread safe) */\n  if (virgin) {\n    var sym;\n\n    lenfix = new utils.Buf32(512);\n    distfix = new utils.Buf32(32);\n\n    /* literal/length table */\n    sym = 0;\n    while (sym < 144) { state.lens[sym++] = 8; }\n    while (sym < 256) { state.lens[sym++] = 9; }\n    while (sym < 280) { state.lens[sym++] = 7; }\n    while (sym < 288) { state.lens[sym++] = 8; }\n\n    inflate_table(LENS,  state.lens, 0, 288, lenfix,   0, state.work, {bits: 9});\n\n    /* distance table */\n    sym = 0;\n    while (sym < 32) { state.lens[sym++] = 5; }\n\n    inflate_table(DISTS, state.lens, 0, 32,   distfix, 0, state.work, {bits: 5});\n\n    /* do this just once */\n    virgin = false;\n  }\n\n  state.lencode = lenfix;\n  state.lenbits = 9;\n  state.distcode = distfix;\n  state.distbits = 5;\n}\n\n\n/*\n Update the window with the last wsize (normally 32K) bytes written before\n returning.  If window does not exist yet, create it.  This is only called\n when a window is already in use, or when output has been written during this\n inflate call, but the end of the deflate stream has not been reached yet.\n It is also called to create a window for dictionary data when a dictionary\n is loaded.\n\n Providing output buffers larger than 32K to inflate() should provide a speed\n advantage, since only the last 32K of output is copied to the sliding window\n upon return from inflate(), and since all distances after the first 32K of\n output will fall in the output data, making match copies simpler and faster.\n The advantage may be dependent on the size of the processor's data caches.\n */\nfunction updatewindow(strm, src, end, copy) {\n  var dist;\n  var state = strm.state;\n\n  /* if it hasn't been done already, allocate space for the window */\n  if (state.window === null) {\n    state.wsize = 1 << state.wbits;\n    state.wnext = 0;\n    state.whave = 0;\n\n    state.window = new utils.Buf8(state.wsize);\n  }\n\n  /* copy state->wsize or less output bytes into the circular window */\n  if (copy >= state.wsize) {\n    utils.arraySet(state.window,src, end - state.wsize, state.wsize, 0);\n    state.wnext = 0;\n    state.whave = state.wsize;\n  }\n  else {\n    dist = state.wsize - state.wnext;\n    if (dist > copy) {\n      dist = copy;\n    }\n    //zmemcpy(state->window + state->wnext, end - copy, dist);\n    utils.arraySet(state.window,src, end - copy, dist, state.wnext);\n    copy -= dist;\n    if (copy) {\n      //zmemcpy(state->window, end - copy, copy);\n      utils.arraySet(state.window,src, end - copy, copy, 0);\n      state.wnext = copy;\n      state.whave = state.wsize;\n    }\n    else {\n      state.wnext += dist;\n      if (state.wnext === state.wsize) { state.wnext = 0; }\n      if (state.whave < state.wsize) { state.whave += dist; }\n    }\n  }\n  return 0;\n}\n\nfunction inflate(strm, flush) {\n  var state;\n  var input, output;          // input/output buffers\n  var next;                   /* next input INDEX */\n  var put;                    /* next output INDEX */\n  var have, left;             /* available input and output */\n  var hold;                   /* bit buffer */\n  var bits;                   /* bits in bit buffer */\n  var _in, _out;              /* save starting available input and output */\n  var copy;                   /* number of stored or match bytes to copy */\n  var from;                   /* where to copy match bytes from */\n  var from_source;\n  var here = 0;               /* current decoding table entry */\n  var here_bits, here_op, here_val; // paked \"here\" denormalized (JS specific)\n  //var last;                   /* parent table entry */\n  var last_bits, last_op, last_val; // paked \"last\" denormalized (JS specific)\n  var len;                    /* length to copy for repeats, bits to drop */\n  var ret;                    /* return code */\n  var hbuf = new utils.Buf8(4);    /* buffer for gzip header crc calculation */\n  var opts;\n\n  var n; // temporary var for NEED_BITS\n\n  var order = /* permutation of code lengths */\n    [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];\n\n\n  if (!strm || !strm.state || !strm.output ||\n      (!strm.input && strm.avail_in !== 0)) {\n    return Z_STREAM_ERROR;\n  }\n\n  state = strm.state;\n  if (state.mode === TYPE) { state.mode = TYPEDO; }    /* skip check */\n\n\n  //--- LOAD() ---\n  put = strm.next_out;\n  output = strm.output;\n  left = strm.avail_out;\n  next = strm.next_in;\n  input = strm.input;\n  have = strm.avail_in;\n  hold = state.hold;\n  bits = state.bits;\n  //---\n\n  _in = have;\n  _out = left;\n  ret = Z_OK;\n\n  inf_leave: // goto emulation\n  for (;;) {\n    switch (state.mode) {\n    case HEAD:\n      if (state.wrap === 0) {\n        state.mode = TYPEDO;\n        break;\n      }\n      //=== NEEDBITS(16);\n      while (bits < 16) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      if ((state.wrap & 2) && hold === 0x8b1f) {  /* gzip header */\n        state.check = 0/*crc32(0L, Z_NULL, 0)*/;\n        //=== CRC2(state.check, hold);\n        hbuf[0] = hold & 0xff;\n        hbuf[1] = (hold >>> 8) & 0xff;\n        state.check = crc32(state.check, hbuf, 2, 0);\n        //===//\n\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        state.mode = FLAGS;\n        break;\n      }\n      state.flags = 0;           /* expect zlib header */\n      if (state.head) {\n        state.head.done = false;\n      }\n      if (!(state.wrap & 1) ||   /* check if zlib header allowed */\n        (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {\n        strm.msg = 'incorrect header check';\n        state.mode = BAD;\n        break;\n      }\n      if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {\n        strm.msg = 'unknown compression method';\n        state.mode = BAD;\n        break;\n      }\n      //--- DROPBITS(4) ---//\n      hold >>>= 4;\n      bits -= 4;\n      //---//\n      len = (hold & 0x0f)/*BITS(4)*/ + 8;\n      if (state.wbits === 0) {\n        state.wbits = len;\n      }\n      else if (len > state.wbits) {\n        strm.msg = 'invalid window size';\n        state.mode = BAD;\n        break;\n      }\n      state.dmax = 1 << len;\n      //Tracev((stderr, \"inflate:   zlib header ok\\n\"));\n      strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;\n      state.mode = hold & 0x200 ? DICTID : TYPE;\n      //=== INITBITS();\n      hold = 0;\n      bits = 0;\n      //===//\n      break;\n    case FLAGS:\n      //=== NEEDBITS(16); */\n      while (bits < 16) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      state.flags = hold;\n      if ((state.flags & 0xff) !== Z_DEFLATED) {\n        strm.msg = 'unknown compression method';\n        state.mode = BAD;\n        break;\n      }\n      if (state.flags & 0xe000) {\n        strm.msg = 'unknown header flags set';\n        state.mode = BAD;\n        break;\n      }\n      if (state.head) {\n        state.head.text = ((hold >> 8) & 1);\n      }\n      if (state.flags & 0x0200) {\n        //=== CRC2(state.check, hold);\n        hbuf[0] = hold & 0xff;\n        hbuf[1] = (hold >>> 8) & 0xff;\n        state.check = crc32(state.check, hbuf, 2, 0);\n        //===//\n      }\n      //=== INITBITS();\n      hold = 0;\n      bits = 0;\n      //===//\n      state.mode = TIME;\n      /* falls through */\n    case TIME:\n      //=== NEEDBITS(32); */\n      while (bits < 32) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      if (state.head) {\n        state.head.time = hold;\n      }\n      if (state.flags & 0x0200) {\n        //=== CRC4(state.check, hold)\n        hbuf[0] = hold & 0xff;\n        hbuf[1] = (hold >>> 8) & 0xff;\n        hbuf[2] = (hold >>> 16) & 0xff;\n        hbuf[3] = (hold >>> 24) & 0xff;\n        state.check = crc32(state.check, hbuf, 4, 0);\n        //===\n      }\n      //=== INITBITS();\n      hold = 0;\n      bits = 0;\n      //===//\n      state.mode = OS;\n      /* falls through */\n    case OS:\n      //=== NEEDBITS(16); */\n      while (bits < 16) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      if (state.head) {\n        state.head.xflags = (hold & 0xff);\n        state.head.os = (hold >> 8);\n      }\n      if (state.flags & 0x0200) {\n        //=== CRC2(state.check, hold);\n        hbuf[0] = hold & 0xff;\n        hbuf[1] = (hold >>> 8) & 0xff;\n        state.check = crc32(state.check, hbuf, 2, 0);\n        //===//\n      }\n      //=== INITBITS();\n      hold = 0;\n      bits = 0;\n      //===//\n      state.mode = EXLEN;\n      /* falls through */\n    case EXLEN:\n      if (state.flags & 0x0400) {\n        //=== NEEDBITS(16); */\n        while (bits < 16) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        state.length = hold;\n        if (state.head) {\n          state.head.extra_len = hold;\n        }\n        if (state.flags & 0x0200) {\n          //=== CRC2(state.check, hold);\n          hbuf[0] = hold & 0xff;\n          hbuf[1] = (hold >>> 8) & 0xff;\n          state.check = crc32(state.check, hbuf, 2, 0);\n          //===//\n        }\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n      }\n      else if (state.head) {\n        state.head.extra = null/*Z_NULL*/;\n      }\n      state.mode = EXTRA;\n      /* falls through */\n    case EXTRA:\n      if (state.flags & 0x0400) {\n        copy = state.length;\n        if (copy > have) { copy = have; }\n        if (copy) {\n          if (state.head) {\n            len = state.head.extra_len - state.length;\n            if (!state.head.extra) {\n              // Use untyped array for more conveniend processing later\n              state.head.extra = new Array(state.head.extra_len);\n            }\n            utils.arraySet(\n              state.head.extra,\n              input,\n              next,\n              // extra field is limited to 65536 bytes\n              // - no need for additional size check\n              copy,\n              /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/\n              len\n            );\n            //zmemcpy(state.head.extra + len, next,\n            //        len + copy > state.head.extra_max ?\n            //        state.head.extra_max - len : copy);\n          }\n          if (state.flags & 0x0200) {\n            state.check = crc32(state.check, input, copy, next);\n          }\n          have -= copy;\n          next += copy;\n          state.length -= copy;\n        }\n        if (state.length) { break inf_leave; }\n      }\n      state.length = 0;\n      state.mode = NAME;\n      /* falls through */\n    case NAME:\n      if (state.flags & 0x0800) {\n        if (have === 0) { break inf_leave; }\n        copy = 0;\n        do {\n          // TODO: 2 or 1 bytes?\n          len = input[next + copy++];\n          /* use constant limit because in js we should not preallocate memory */\n          if (state.head && len &&\n              (state.length < 65536 /*state.head.name_max*/)) {\n            state.head.name += String.fromCharCode(len);\n          }\n        } while (len && copy < have);\n\n        if (state.flags & 0x0200) {\n          state.check = crc32(state.check, input, copy, next);\n        }\n        have -= copy;\n        next += copy;\n        if (len) { break inf_leave; }\n      }\n      else if (state.head) {\n        state.head.name = null;\n      }\n      state.length = 0;\n      state.mode = COMMENT;\n      /* falls through */\n    case COMMENT:\n      if (state.flags & 0x1000) {\n        if (have === 0) { break inf_leave; }\n        copy = 0;\n        do {\n          len = input[next + copy++];\n          /* use constant limit because in js we should not preallocate memory */\n          if (state.head && len &&\n              (state.length < 65536 /*state.head.comm_max*/)) {\n            state.head.comment += String.fromCharCode(len);\n          }\n        } while (len && copy < have);\n        if (state.flags & 0x0200) {\n          state.check = crc32(state.check, input, copy, next);\n        }\n        have -= copy;\n        next += copy;\n        if (len) { break inf_leave; }\n      }\n      else if (state.head) {\n        state.head.comment = null;\n      }\n      state.mode = HCRC;\n      /* falls through */\n    case HCRC:\n      if (state.flags & 0x0200) {\n        //=== NEEDBITS(16); */\n        while (bits < 16) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        if (hold !== (state.check & 0xffff)) {\n          strm.msg = 'header crc mismatch';\n          state.mode = BAD;\n          break;\n        }\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n      }\n      if (state.head) {\n        state.head.hcrc = ((state.flags >> 9) & 1);\n        state.head.done = true;\n      }\n      strm.adler = state.check = 0 /*crc32(0L, Z_NULL, 0)*/;\n      state.mode = TYPE;\n      break;\n    case DICTID:\n      //=== NEEDBITS(32); */\n      while (bits < 32) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      strm.adler = state.check = ZSWAP32(hold);\n      //=== INITBITS();\n      hold = 0;\n      bits = 0;\n      //===//\n      state.mode = DICT;\n      /* falls through */\n    case DICT:\n      if (state.havedict === 0) {\n        //--- RESTORE() ---\n        strm.next_out = put;\n        strm.avail_out = left;\n        strm.next_in = next;\n        strm.avail_in = have;\n        state.hold = hold;\n        state.bits = bits;\n        //---\n        return Z_NEED_DICT;\n      }\n      strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;\n      state.mode = TYPE;\n      /* falls through */\n    case TYPE:\n      if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }\n      /* falls through */\n    case TYPEDO:\n      if (state.last) {\n        //--- BYTEBITS() ---//\n        hold >>>= bits & 7;\n        bits -= bits & 7;\n        //---//\n        state.mode = CHECK;\n        break;\n      }\n      //=== NEEDBITS(3); */\n      while (bits < 3) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      state.last = (hold & 0x01)/*BITS(1)*/;\n      //--- DROPBITS(1) ---//\n      hold >>>= 1;\n      bits -= 1;\n      //---//\n\n      switch ((hold & 0x03)/*BITS(2)*/) {\n      case 0:                             /* stored block */\n        //Tracev((stderr, \"inflate:     stored block%s\\n\",\n        //        state.last ? \" (last)\" : \"\"));\n        state.mode = STORED;\n        break;\n      case 1:                             /* fixed block */\n        fixedtables(state);\n        //Tracev((stderr, \"inflate:     fixed codes block%s\\n\",\n        //        state.last ? \" (last)\" : \"\"));\n        state.mode = LEN_;             /* decode codes */\n        if (flush === Z_TREES) {\n          //--- DROPBITS(2) ---//\n          hold >>>= 2;\n          bits -= 2;\n          //---//\n          break inf_leave;\n        }\n        break;\n      case 2:                             /* dynamic block */\n        //Tracev((stderr, \"inflate:     dynamic codes block%s\\n\",\n        //        state.last ? \" (last)\" : \"\"));\n        state.mode = TABLE;\n        break;\n      case 3:\n        strm.msg = 'invalid block type';\n        state.mode = BAD;\n      }\n      //--- DROPBITS(2) ---//\n      hold >>>= 2;\n      bits -= 2;\n      //---//\n      break;\n    case STORED:\n      //--- BYTEBITS() ---// /* go to byte boundary */\n      hold >>>= bits & 7;\n      bits -= bits & 7;\n      //---//\n      //=== NEEDBITS(32); */\n      while (bits < 32) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {\n        strm.msg = 'invalid stored block lengths';\n        state.mode = BAD;\n        break;\n      }\n      state.length = hold & 0xffff;\n      //Tracev((stderr, \"inflate:       stored length %u\\n\",\n      //        state.length));\n      //=== INITBITS();\n      hold = 0;\n      bits = 0;\n      //===//\n      state.mode = COPY_;\n      if (flush === Z_TREES) { break inf_leave; }\n      /* falls through */\n    case COPY_:\n      state.mode = COPY;\n      /* falls through */\n    case COPY:\n      copy = state.length;\n      if (copy) {\n        if (copy > have) { copy = have; }\n        if (copy > left) { copy = left; }\n        if (copy === 0) { break inf_leave; }\n        //--- zmemcpy(put, next, copy); ---\n        utils.arraySet(output, input, next, copy, put);\n        //---//\n        have -= copy;\n        next += copy;\n        left -= copy;\n        put += copy;\n        state.length -= copy;\n        break;\n      }\n      //Tracev((stderr, \"inflate:       stored end\\n\"));\n      state.mode = TYPE;\n      break;\n    case TABLE:\n      //=== NEEDBITS(14); */\n      while (bits < 14) {\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n      }\n      //===//\n      state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;\n      //--- DROPBITS(5) ---//\n      hold >>>= 5;\n      bits -= 5;\n      //---//\n      state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;\n      //--- DROPBITS(5) ---//\n      hold >>>= 5;\n      bits -= 5;\n      //---//\n      state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;\n      //--- DROPBITS(4) ---//\n      hold >>>= 4;\n      bits -= 4;\n      //---//\n//#ifndef PKZIP_BUG_WORKAROUND\n      if (state.nlen > 286 || state.ndist > 30) {\n        strm.msg = 'too many length or distance symbols';\n        state.mode = BAD;\n        break;\n      }\n//#endif\n      //Tracev((stderr, \"inflate:       table sizes ok\\n\"));\n      state.have = 0;\n      state.mode = LENLENS;\n      /* falls through */\n    case LENLENS:\n      while (state.have < state.ncode) {\n        //=== NEEDBITS(3);\n        while (bits < 3) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);\n        //--- DROPBITS(3) ---//\n        hold >>>= 3;\n        bits -= 3;\n        //---//\n      }\n      while (state.have < 19) {\n        state.lens[order[state.have++]] = 0;\n      }\n      // We have separate tables & no pointers. 2 commented lines below not needed.\n      //state.next = state.codes;\n      //state.lencode = state.next;\n      // Switch to use dynamic table\n      state.lencode = state.lendyn;\n      state.lenbits = 7;\n\n      opts = {bits: state.lenbits};\n      ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);\n      state.lenbits = opts.bits;\n\n      if (ret) {\n        strm.msg = 'invalid code lengths set';\n        state.mode = BAD;\n        break;\n      }\n      //Tracev((stderr, \"inflate:       code lengths ok\\n\"));\n      state.have = 0;\n      state.mode = CODELENS;\n      /* falls through */\n    case CODELENS:\n      while (state.have < state.nlen + state.ndist) {\n        for (;;) {\n          here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/\n          here_bits = here >>> 24;\n          here_op = (here >>> 16) & 0xff;\n          here_val = here & 0xffff;\n\n          if ((here_bits) <= bits) { break; }\n          //--- PULLBYTE() ---//\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n          //---//\n        }\n        if (here_val < 16) {\n          //--- DROPBITS(here.bits) ---//\n          hold >>>= here_bits;\n          bits -= here_bits;\n          //---//\n          state.lens[state.have++] = here_val;\n        }\n        else {\n          if (here_val === 16) {\n            //=== NEEDBITS(here.bits + 2);\n            n = here_bits + 2;\n            while (bits < n) {\n              if (have === 0) { break inf_leave; }\n              have--;\n              hold += input[next++] << bits;\n              bits += 8;\n            }\n            //===//\n            //--- DROPBITS(here.bits) ---//\n            hold >>>= here_bits;\n            bits -= here_bits;\n            //---//\n            if (state.have === 0) {\n              strm.msg = 'invalid bit length repeat';\n              state.mode = BAD;\n              break;\n            }\n            len = state.lens[state.have - 1];\n            copy = 3 + (hold & 0x03);//BITS(2);\n            //--- DROPBITS(2) ---//\n            hold >>>= 2;\n            bits -= 2;\n            //---//\n          }\n          else if (here_val === 17) {\n            //=== NEEDBITS(here.bits + 3);\n            n = here_bits + 3;\n            while (bits < n) {\n              if (have === 0) { break inf_leave; }\n              have--;\n              hold += input[next++] << bits;\n              bits += 8;\n            }\n            //===//\n            //--- DROPBITS(here.bits) ---//\n            hold >>>= here_bits;\n            bits -= here_bits;\n            //---//\n            len = 0;\n            copy = 3 + (hold & 0x07);//BITS(3);\n            //--- DROPBITS(3) ---//\n            hold >>>= 3;\n            bits -= 3;\n            //---//\n          }\n          else {\n            //=== NEEDBITS(here.bits + 7);\n            n = here_bits + 7;\n            while (bits < n) {\n              if (have === 0) { break inf_leave; }\n              have--;\n              hold += input[next++] << bits;\n              bits += 8;\n            }\n            //===//\n            //--- DROPBITS(here.bits) ---//\n            hold >>>= here_bits;\n            bits -= here_bits;\n            //---//\n            len = 0;\n            copy = 11 + (hold & 0x7f);//BITS(7);\n            //--- DROPBITS(7) ---//\n            hold >>>= 7;\n            bits -= 7;\n            //---//\n          }\n          if (state.have + copy > state.nlen + state.ndist) {\n            strm.msg = 'invalid bit length repeat';\n            state.mode = BAD;\n            break;\n          }\n          while (copy--) {\n            state.lens[state.have++] = len;\n          }\n        }\n      }\n\n      /* handle error breaks in while */\n      if (state.mode === BAD) { break; }\n\n      /* check for end-of-block code (better have one) */\n      if (state.lens[256] === 0) {\n        strm.msg = 'invalid code -- missing end-of-block';\n        state.mode = BAD;\n        break;\n      }\n\n      /* build code tables -- note: do not change the lenbits or distbits\n         values here (9 and 6) without reading the comments in inftrees.h\n         concerning the ENOUGH constants, which depend on those values */\n      state.lenbits = 9;\n\n      opts = {bits: state.lenbits};\n      ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);\n      // We have separate tables & no pointers. 2 commented lines below not needed.\n      // state.next_index = opts.table_index;\n      state.lenbits = opts.bits;\n      // state.lencode = state.next;\n\n      if (ret) {\n        strm.msg = 'invalid literal/lengths set';\n        state.mode = BAD;\n        break;\n      }\n\n      state.distbits = 6;\n      //state.distcode.copy(state.codes);\n      // Switch to use dynamic table\n      state.distcode = state.distdyn;\n      opts = {bits: state.distbits};\n      ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);\n      // We have separate tables & no pointers. 2 commented lines below not needed.\n      // state.next_index = opts.table_index;\n      state.distbits = opts.bits;\n      // state.distcode = state.next;\n\n      if (ret) {\n        strm.msg = 'invalid distances set';\n        state.mode = BAD;\n        break;\n      }\n      //Tracev((stderr, 'inflate:       codes ok\\n'));\n      state.mode = LEN_;\n      if (flush === Z_TREES) { break inf_leave; }\n      /* falls through */\n    case LEN_:\n      state.mode = LEN;\n      /* falls through */\n    case LEN:\n      if (have >= 6 && left >= 258) {\n        //--- RESTORE() ---\n        strm.next_out = put;\n        strm.avail_out = left;\n        strm.next_in = next;\n        strm.avail_in = have;\n        state.hold = hold;\n        state.bits = bits;\n        //---\n        inflate_fast(strm, _out);\n        //--- LOAD() ---\n        put = strm.next_out;\n        output = strm.output;\n        left = strm.avail_out;\n        next = strm.next_in;\n        input = strm.input;\n        have = strm.avail_in;\n        hold = state.hold;\n        bits = state.bits;\n        //---\n\n        if (state.mode === TYPE) {\n          state.back = -1;\n        }\n        break;\n      }\n      state.back = 0;\n      for (;;) {\n        here = state.lencode[hold & ((1 << state.lenbits) -1)];  /*BITS(state.lenbits)*/\n        here_bits = here >>> 24;\n        here_op = (here >>> 16) & 0xff;\n        here_val = here & 0xffff;\n\n        if (here_bits <= bits) { break; }\n        //--- PULLBYTE() ---//\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n        //---//\n      }\n      if (here_op && (here_op & 0xf0) === 0) {\n        last_bits = here_bits;\n        last_op = here_op;\n        last_val = here_val;\n        for (;;) {\n          here = state.lencode[last_val +\n                  ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)];\n          here_bits = here >>> 24;\n          here_op = (here >>> 16) & 0xff;\n          here_val = here & 0xffff;\n\n          if ((last_bits + here_bits) <= bits) { break; }\n          //--- PULLBYTE() ---//\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n          //---//\n        }\n        //--- DROPBITS(last.bits) ---//\n        hold >>>= last_bits;\n        bits -= last_bits;\n        //---//\n        state.back += last_bits;\n      }\n      //--- DROPBITS(here.bits) ---//\n      hold >>>= here_bits;\n      bits -= here_bits;\n      //---//\n      state.back += here_bits;\n      state.length = here_val;\n      if (here_op === 0) {\n        //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?\n        //        \"inflate:         literal '%c'\\n\" :\n        //        \"inflate:         literal 0x%02x\\n\", here.val));\n        state.mode = LIT;\n        break;\n      }\n      if (here_op & 32) {\n        //Tracevv((stderr, \"inflate:         end of block\\n\"));\n        state.back = -1;\n        state.mode = TYPE;\n        break;\n      }\n      if (here_op & 64) {\n        strm.msg = 'invalid literal/length code';\n        state.mode = BAD;\n        break;\n      }\n      state.extra = here_op & 15;\n      state.mode = LENEXT;\n      /* falls through */\n    case LENEXT:\n      if (state.extra) {\n        //=== NEEDBITS(state.extra);\n        n = state.extra;\n        while (bits < n) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        state.length += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/;\n        //--- DROPBITS(state.extra) ---//\n        hold >>>= state.extra;\n        bits -= state.extra;\n        //---//\n        state.back += state.extra;\n      }\n      //Tracevv((stderr, \"inflate:         length %u\\n\", state.length));\n      state.was = state.length;\n      state.mode = DIST;\n      /* falls through */\n    case DIST:\n      for (;;) {\n        here = state.distcode[hold & ((1 << state.distbits) -1)];/*BITS(state.distbits)*/\n        here_bits = here >>> 24;\n        here_op = (here >>> 16) & 0xff;\n        here_val = here & 0xffff;\n\n        if ((here_bits) <= bits) { break; }\n        //--- PULLBYTE() ---//\n        if (have === 0) { break inf_leave; }\n        have--;\n        hold += input[next++] << bits;\n        bits += 8;\n        //---//\n      }\n      if ((here_op & 0xf0) === 0) {\n        last_bits = here_bits;\n        last_op = here_op;\n        last_val = here_val;\n        for (;;) {\n          here = state.distcode[last_val +\n                  ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)];\n          here_bits = here >>> 24;\n          here_op = (here >>> 16) & 0xff;\n          here_val = here & 0xffff;\n\n          if ((last_bits + here_bits) <= bits) { break; }\n          //--- PULLBYTE() ---//\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n          //---//\n        }\n        //--- DROPBITS(last.bits) ---//\n        hold >>>= last_bits;\n        bits -= last_bits;\n        //---//\n        state.back += last_bits;\n      }\n      //--- DROPBITS(here.bits) ---//\n      hold >>>= here_bits;\n      bits -= here_bits;\n      //---//\n      state.back += here_bits;\n      if (here_op & 64) {\n        strm.msg = 'invalid distance code';\n        state.mode = BAD;\n        break;\n      }\n      state.offset = here_val;\n      state.extra = (here_op) & 15;\n      state.mode = DISTEXT;\n      /* falls through */\n    case DISTEXT:\n      if (state.extra) {\n        //=== NEEDBITS(state.extra);\n        n = state.extra;\n        while (bits < n) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        state.offset += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/;\n        //--- DROPBITS(state.extra) ---//\n        hold >>>= state.extra;\n        bits -= state.extra;\n        //---//\n        state.back += state.extra;\n      }\n//#ifdef INFLATE_STRICT\n      if (state.offset > state.dmax) {\n        strm.msg = 'invalid distance too far back';\n        state.mode = BAD;\n        break;\n      }\n//#endif\n      //Tracevv((stderr, \"inflate:         distance %u\\n\", state.offset));\n      state.mode = MATCH;\n      /* falls through */\n    case MATCH:\n      if (left === 0) { break inf_leave; }\n      copy = _out - left;\n      if (state.offset > copy) {         /* copy from window */\n        copy = state.offset - copy;\n        if (copy > state.whave) {\n          if (state.sane) {\n            strm.msg = 'invalid distance too far back';\n            state.mode = BAD;\n            break;\n          }\n// (!) This block is disabled in zlib defailts,\n// don't enable it for binary compatibility\n//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR\n//          Trace((stderr, \"inflate.c too far\\n\"));\n//          copy -= state.whave;\n//          if (copy > state.length) { copy = state.length; }\n//          if (copy > left) { copy = left; }\n//          left -= copy;\n//          state.length -= copy;\n//          do {\n//            output[put++] = 0;\n//          } while (--copy);\n//          if (state.length === 0) { state.mode = LEN; }\n//          break;\n//#endif\n        }\n        if (copy > state.wnext) {\n          copy -= state.wnext;\n          from = state.wsize - copy;\n        }\n        else {\n          from = state.wnext - copy;\n        }\n        if (copy > state.length) { copy = state.length; }\n        from_source = state.window;\n      }\n      else {                              /* copy from output */\n        from_source = output;\n        from = put - state.offset;\n        copy = state.length;\n      }\n      if (copy > left) { copy = left; }\n      left -= copy;\n      state.length -= copy;\n      do {\n        output[put++] = from_source[from++];\n      } while (--copy);\n      if (state.length === 0) { state.mode = LEN; }\n      break;\n    case LIT:\n      if (left === 0) { break inf_leave; }\n      output[put++] = state.length;\n      left--;\n      state.mode = LEN;\n      break;\n    case CHECK:\n      if (state.wrap) {\n        //=== NEEDBITS(32);\n        while (bits < 32) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          // Use '|' insdead of '+' to make sure that result is signed\n          hold |= input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        _out -= left;\n        strm.total_out += _out;\n        state.total += _out;\n        if (_out) {\n          strm.adler = state.check =\n              /*UPDATE(state.check, put - _out, _out);*/\n              (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out));\n\n        }\n        _out = left;\n        // NB: crc32 stored as signed 32-bit int, ZSWAP32 returns signed too\n        if ((state.flags ? hold : ZSWAP32(hold)) !== state.check) {\n          strm.msg = 'incorrect data check';\n          state.mode = BAD;\n          break;\n        }\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        //Tracev((stderr, \"inflate:   check matches trailer\\n\"));\n      }\n      state.mode = LENGTH;\n      /* falls through */\n    case LENGTH:\n      if (state.wrap && state.flags) {\n        //=== NEEDBITS(32);\n        while (bits < 32) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        if (hold !== (state.total & 0xffffffff)) {\n          strm.msg = 'incorrect length check';\n          state.mode = BAD;\n          break;\n        }\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        //Tracev((stderr, \"inflate:   length matches trailer\\n\"));\n      }\n      state.mode = DONE;\n      /* falls through */\n    case DONE:\n      ret = Z_STREAM_END;\n      break inf_leave;\n    case BAD:\n      ret = Z_DATA_ERROR;\n      break inf_leave;\n    case MEM:\n      return Z_MEM_ERROR;\n    case SYNC:\n      /* falls through */\n    default:\n      return Z_STREAM_ERROR;\n    }\n  }\n\n  // inf_leave <- here is real place for \"goto inf_leave\", emulated via \"break inf_leave\"\n\n  /*\n     Return from inflate(), updating the total counts and the check value.\n     If there was no progress during the inflate() call, return a buffer\n     error.  Call updatewindow() to create and/or update the window state.\n     Note: a memory error from inflate() is non-recoverable.\n   */\n\n  //--- RESTORE() ---\n  strm.next_out = put;\n  strm.avail_out = left;\n  strm.next_in = next;\n  strm.avail_in = have;\n  state.hold = hold;\n  state.bits = bits;\n  //---\n\n  if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&\n                      (state.mode < CHECK || flush !== Z_FINISH))) {\n    if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {\n      state.mode = MEM;\n      return Z_MEM_ERROR;\n    }\n  }\n  _in -= strm.avail_in;\n  _out -= strm.avail_out;\n  strm.total_in += _in;\n  strm.total_out += _out;\n  state.total += _out;\n  if (state.wrap && _out) {\n    strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/\n      (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out));\n  }\n  strm.data_type = state.bits + (state.last ? 64 : 0) +\n                    (state.mode === TYPE ? 128 : 0) +\n                    (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);\n  if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) {\n    ret = Z_BUF_ERROR;\n  }\n  return ret;\n}\n\nfunction inflateEnd(strm) {\n\n  if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {\n    return Z_STREAM_ERROR;\n  }\n\n  var state = strm.state;\n  if (state.window) {\n    state.window = null;\n  }\n  strm.state = null;\n  return Z_OK;\n}\n\nfunction inflateGetHeader(strm, head) {\n  var state;\n\n  /* check state */\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n  if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; }\n\n  /* save header structure */\n  state.head = head;\n  head.done = false;\n  return Z_OK;\n}\n\n\nexports.inflateReset = inflateReset;\nexports.inflateReset2 = inflateReset2;\nexports.inflateResetKeep = inflateResetKeep;\nexports.inflateInit = inflateInit;\nexports.inflateInit2 = inflateInit2;\nexports.inflate = inflate;\nexports.inflateEnd = inflateEnd;\nexports.inflateGetHeader = inflateGetHeader;\nexports.inflateInfo = 'pako inflate (from Nodeca project)';\n\n/* Not implemented\nexports.inflateCopy = inflateCopy;\nexports.inflateGetDictionary = inflateGetDictionary;\nexports.inflateMark = inflateMark;\nexports.inflatePrime = inflatePrime;\nexports.inflateSetDictionary = inflateSetDictionary;\nexports.inflateSync = inflateSync;\nexports.inflateSyncPoint = inflateSyncPoint;\nexports.inflateUndermine = inflateUndermine;\n*/\n},{\"../utils/common\":27,\"./adler32\":29,\"./crc32\":31,\"./inffast\":34,\"./inftrees\":36}],36:[function(_dereq_,module,exports){\n'use strict';\n\n\nvar utils = _dereq_('../utils/common');\n\nvar MAXBITS = 15;\nvar ENOUGH_LENS = 852;\nvar ENOUGH_DISTS = 592;\n//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);\n\nvar CODES = 0;\nvar LENS = 1;\nvar DISTS = 2;\n\nvar lbase = [ /* Length codes 257..285 base */\n  3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,\n  35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0\n];\n\nvar lext = [ /* Length codes 257..285 extra */\n  16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,\n  19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78\n];\n\nvar dbase = [ /* Distance codes 0..29 base */\n  1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,\n  257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,\n  8193, 12289, 16385, 24577, 0, 0\n];\n\nvar dext = [ /* Distance codes 0..29 extra */\n  16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,\n  23, 23, 24, 24, 25, 25, 26, 26, 27, 27,\n  28, 28, 29, 29, 64, 64\n];\n\nmodule.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts)\n{\n  var bits = opts.bits;\n      //here = opts.here; /* table entry for duplication */\n\n  var len = 0;               /* a code's length in bits */\n  var sym = 0;               /* index of code symbols */\n  var min = 0, max = 0;          /* minimum and maximum code lengths */\n  var root = 0;              /* number of index bits for root table */\n  var curr = 0;              /* number of index bits for current table */\n  var drop = 0;              /* code bits to drop for sub-table */\n  var left = 0;                   /* number of prefix codes available */\n  var used = 0;              /* code entries in table used */\n  var huff = 0;              /* Huffman code */\n  var incr;              /* for incrementing code, index */\n  var fill;              /* index for replicating entries */\n  var low;               /* low bits for current root entry */\n  var mask;              /* mask for low root bits */\n  var next;             /* next available space in table */\n  var base = null;     /* base value table to use */\n  var base_index = 0;\n//  var shoextra;    /* extra bits table to use */\n  var end;                    /* use base and extra for symbol > end */\n  var count = new utils.Buf16(MAXBITS+1); //[MAXBITS+1];    /* number of codes of each length */\n  var offs = new utils.Buf16(MAXBITS+1); //[MAXBITS+1];     /* offsets in table for each length */\n  var extra = null;\n  var extra_index = 0;\n\n  var here_bits, here_op, here_val;\n\n  /*\n   Process a set of code lengths to create a canonical Huffman code.  The\n   code lengths are lens[0..codes-1].  Each length corresponds to the\n   symbols 0..codes-1.  The Huffman code is generated by first sorting the\n   symbols by length from short to long, and retaining the symbol order\n   for codes with equal lengths.  Then the code starts with all zero bits\n   for the first code of the shortest length, and the codes are integer\n   increments for the same length, and zeros are appended as the length\n   increases.  For the deflate format, these bits are stored backwards\n   from their more natural integer increment ordering, and so when the\n   decoding tables are built in the large loop below, the integer codes\n   are incremented backwards.\n\n   This routine assumes, but does not check, that all of the entries in\n   lens[] are in the range 0..MAXBITS.  The caller must assure this.\n   1..MAXBITS is interpreted as that code length.  zero means that that\n   symbol does not occur in this code.\n\n   The codes are sorted by computing a count of codes for each length,\n   creating from that a table of starting indices for each length in the\n   sorted table, and then entering the symbols in order in the sorted\n   table.  The sorted table is work[], with that space being provided by\n   the caller.\n\n   The length counts are used for other purposes as well, i.e. finding\n   the minimum and maximum length codes, determining if there are any\n   codes at all, checking for a valid set of lengths, and looking ahead\n   at length counts to determine sub-table sizes when building the\n   decoding tables.\n   */\n\n  /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */\n  for (len = 0; len <= MAXBITS; len++) {\n    count[len] = 0;\n  }\n  for (sym = 0; sym < codes; sym++) {\n    count[lens[lens_index + sym]]++;\n  }\n\n  /* bound code lengths, force root to be within code lengths */\n  root = bits;\n  for (max = MAXBITS; max >= 1; max--) {\n    if (count[max] !== 0) { break; }\n  }\n  if (root > max) {\n    root = max;\n  }\n  if (max === 0) {                     /* no symbols to code at all */\n    //table.op[opts.table_index] = 64;  //here.op = (var char)64;    /* invalid code marker */\n    //table.bits[opts.table_index] = 1;   //here.bits = (var char)1;\n    //table.val[opts.table_index++] = 0;   //here.val = (var short)0;\n    table[table_index++] = (1 << 24) | (64 << 16) | 0;\n\n\n    //table.op[opts.table_index] = 64;\n    //table.bits[opts.table_index] = 1;\n    //table.val[opts.table_index++] = 0;\n    table[table_index++] = (1 << 24) | (64 << 16) | 0;\n\n    opts.bits = 1;\n    return 0;     /* no symbols, but wait for decoding to report error */\n  }\n  for (min = 1; min < max; min++) {\n    if (count[min] !== 0) { break; }\n  }\n  if (root < min) {\n    root = min;\n  }\n\n  /* check for an over-subscribed or incomplete set of lengths */\n  left = 1;\n  for (len = 1; len <= MAXBITS; len++) {\n    left <<= 1;\n    left -= count[len];\n    if (left < 0) {\n      return -1;\n    }        /* over-subscribed */\n  }\n  if (left > 0 && (type === CODES || max !== 1)) {\n    return -1;                      /* incomplete set */\n  }\n\n  /* generate offsets into symbol table for each length for sorting */\n  offs[1] = 0;\n  for (len = 1; len < MAXBITS; len++) {\n    offs[len + 1] = offs[len] + count[len];\n  }\n\n  /* sort symbols by length, by symbol order within each length */\n  for (sym = 0; sym < codes; sym++) {\n    if (lens[lens_index + sym] !== 0) {\n      work[offs[lens[lens_index + sym]]++] = sym;\n    }\n  }\n\n  /*\n   Create and fill in decoding tables.  In this loop, the table being\n   filled is at next and has curr index bits.  The code being used is huff\n   with length len.  That code is converted to an index by dropping drop\n   bits off of the bottom.  For codes where len is less than drop + curr,\n   those top drop + curr - len bits are incremented through all values to\n   fill the table with replicated entries.\n\n   root is the number of index bits for the root table.  When len exceeds\n   root, sub-tables are created pointed to by the root entry with an index\n   of the low root bits of huff.  This is saved in low to check for when a\n   new sub-table should be started.  drop is zero when the root table is\n   being filled, and drop is root when sub-tables are being filled.\n\n   When a new sub-table is needed, it is necessary to look ahead in the\n   code lengths to determine what size sub-table is needed.  The length\n   counts are used for this, and so count[] is decremented as codes are\n   entered in the tables.\n\n   used keeps track of how many table entries have been allocated from the\n   provided *table space.  It is checked for LENS and DIST tables against\n   the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in\n   the initial root table size constants.  See the comments in inftrees.h\n   for more information.\n\n   sym increments through all symbols, and the loop terminates when\n   all codes of length max, i.e. all codes, have been processed.  This\n   routine permits incomplete codes, so another loop after this one fills\n   in the rest of the decoding tables with invalid code markers.\n   */\n\n  /* set up for code type */\n  // poor man optimization - use if-else instead of switch,\n  // to avoid deopts in old v8\n  if (type === CODES) {\n      base = extra = work;    /* dummy value--not used */\n      end = 19;\n  } else if (type === LENS) {\n      base = lbase;\n      base_index -= 257;\n      extra = lext;\n      extra_index -= 257;\n      end = 256;\n  } else {                    /* DISTS */\n      base = dbase;\n      extra = dext;\n      end = -1;\n  }\n\n  /* initialize opts for loop */\n  huff = 0;                   /* starting code */\n  sym = 0;                    /* starting code symbol */\n  len = min;                  /* starting code length */\n  next = table_index;              /* current table to fill in */\n  curr = root;                /* current table index bits */\n  drop = 0;                   /* current bits to drop from code for index */\n  low = -1;                   /* trigger new sub-table when len > root */\n  used = 1 << root;          /* use root table entries */\n  mask = used - 1;            /* mask for comparing low */\n\n  /* check available table space */\n  if ((type === LENS && used > ENOUGH_LENS) ||\n    (type === DISTS && used > ENOUGH_DISTS)) {\n    return 1;\n  }\n\n  var i=0;\n  /* process all codes and make table entries */\n  for (;;) {\n    i++;\n    /* create table entry */\n    here_bits = len - drop;\n    if (work[sym] < end) {\n      here_op = 0;\n      here_val = work[sym];\n    }\n    else if (work[sym] > end) {\n      here_op = extra[extra_index + work[sym]];\n      here_val = base[base_index + work[sym]];\n    }\n    else {\n      here_op = 32 + 64;         /* end of block */\n      here_val = 0;\n    }\n\n    /* replicate for those indices with low len bits equal to huff */\n    incr = 1 << (len - drop);\n    fill = 1 << curr;\n    min = fill;                 /* save offset to next table */\n    do {\n      fill -= incr;\n      table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;\n    } while (fill !== 0);\n\n    /* backwards increment the len-bit code huff */\n    incr = 1 << (len - 1);\n    while (huff & incr) {\n      incr >>= 1;\n    }\n    if (incr !== 0) {\n      huff &= incr - 1;\n      huff += incr;\n    } else {\n      huff = 0;\n    }\n\n    /* go to next symbol, update count, len */\n    sym++;\n    if (--count[len] === 0) {\n      if (len === max) { break; }\n      len = lens[lens_index + work[sym]];\n    }\n\n    /* create new sub-table if needed */\n    if (len > root && (huff & mask) !== low) {\n      /* if first time, transition to sub-tables */\n      if (drop === 0) {\n        drop = root;\n      }\n\n      /* increment past last table */\n      next += min;            /* here min is 1 << curr */\n\n      /* determine length of next table */\n      curr = len - drop;\n      left = 1 << curr;\n      while (curr + drop < max) {\n        left -= count[curr + drop];\n        if (left <= 0) { break; }\n        curr++;\n        left <<= 1;\n      }\n\n      /* check for enough space */\n      used += 1 << curr;\n      if ((type === LENS && used > ENOUGH_LENS) ||\n        (type === DISTS && used > ENOUGH_DISTS)) {\n        return 1;\n      }\n\n      /* point entry in root table to sub-table */\n      low = huff & mask;\n      /*table.op[low] = curr;\n      table.bits[low] = root;\n      table.val[low] = next - opts.table_index;*/\n      table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;\n    }\n  }\n\n  /* fill in remaining table entry if code is incomplete (guaranteed to have\n   at most one remaining entry, since if the code is incomplete, the\n   maximum code length that was allowed to get this far is one bit) */\n  if (huff !== 0) {\n    //table.op[next + huff] = 64;            /* invalid code marker */\n    //table.bits[next + huff] = len - drop;\n    //table.val[next + huff] = 0;\n    table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;\n  }\n\n  /* set return parameters */\n  //opts.table_index += used;\n  opts.bits = root;\n  return 0;\n};\n\n},{\"../utils/common\":27}],37:[function(_dereq_,module,exports){\n'use strict';\n\nmodule.exports = {\n  '2':    'need dictionary',     /* Z_NEED_DICT       2  */\n  '1':    'stream end',          /* Z_STREAM_END      1  */\n  '0':    '',                    /* Z_OK              0  */\n  '-1':   'file error',          /* Z_ERRNO         (-1) */\n  '-2':   'stream error',        /* Z_STREAM_ERROR  (-2) */\n  '-3':   'data error',          /* Z_DATA_ERROR    (-3) */\n  '-4':   'insufficient memory', /* Z_MEM_ERROR     (-4) */\n  '-5':   'buffer error',        /* Z_BUF_ERROR     (-5) */\n  '-6':   'incompatible version' /* Z_VERSION_ERROR (-6) */\n};\n},{}],38:[function(_dereq_,module,exports){\n'use strict';\n\n\nvar utils = _dereq_('../utils/common');\n\n/* Public constants ==========================================================*/\n/* ===========================================================================*/\n\n\n//var Z_FILTERED          = 1;\n//var Z_HUFFMAN_ONLY      = 2;\n//var Z_RLE               = 3;\nvar Z_FIXED               = 4;\n//var Z_DEFAULT_STRATEGY  = 0;\n\n/* Possible values of the data_type field (though see inflate()) */\nvar Z_BINARY              = 0;\nvar Z_TEXT                = 1;\n//var Z_ASCII             = 1; // = Z_TEXT\nvar Z_UNKNOWN             = 2;\n\n/*============================================================================*/\n\n\nfunction zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }\n\n// From zutil.h\n\nvar STORED_BLOCK = 0;\nvar STATIC_TREES = 1;\nvar DYN_TREES    = 2;\n/* The three kinds of block type */\n\nvar MIN_MATCH    = 3;\nvar MAX_MATCH    = 258;\n/* The minimum and maximum match lengths */\n\n// From deflate.h\n/* ===========================================================================\n * Internal compression state.\n */\n\nvar LENGTH_CODES  = 29;\n/* number of length codes, not counting the special END_BLOCK code */\n\nvar LITERALS      = 256;\n/* number of literal bytes 0..255 */\n\nvar L_CODES       = LITERALS + 1 + LENGTH_CODES;\n/* number of Literal or Length codes, including the END_BLOCK code */\n\nvar D_CODES       = 30;\n/* number of distance codes */\n\nvar BL_CODES      = 19;\n/* number of codes used to transfer the bit lengths */\n\nvar HEAP_SIZE     = 2*L_CODES + 1;\n/* maximum heap size */\n\nvar MAX_BITS      = 15;\n/* All codes must not exceed MAX_BITS bits */\n\nvar Buf_size      = 16;\n/* size of bit buffer in bi_buf */\n\n\n/* ===========================================================================\n * Constants\n */\n\nvar MAX_BL_BITS = 7;\n/* Bit length codes must not exceed MAX_BL_BITS bits */\n\nvar END_BLOCK   = 256;\n/* end of block literal code */\n\nvar REP_3_6     = 16;\n/* repeat previous bit length 3-6 times (2 bits of repeat count) */\n\nvar REPZ_3_10   = 17;\n/* repeat a zero length 3-10 times  (3 bits of repeat count) */\n\nvar REPZ_11_138 = 18;\n/* repeat a zero length 11-138 times  (7 bits of repeat count) */\n\nvar extra_lbits =   /* extra bits for each length code */\n  [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0];\n\nvar extra_dbits =   /* extra bits for each distance code */\n  [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];\n\nvar extra_blbits =  /* extra bits for each bit length code */\n  [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];\n\nvar bl_order =\n  [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];\n/* The lengths of the bit length codes are sent in order of decreasing\n * probability, to avoid transmitting the lengths for unused bit length codes.\n */\n\n/* ===========================================================================\n * Local data. These are initialized only once.\n */\n\n// We pre-fill arrays with 0 to avoid uninitialized gaps\n\nvar DIST_CODE_LEN = 512; /* see definition of array dist_code below */\n\n// !!!! Use flat array insdead of structure, Freq = i*2, Len = i*2+1\nvar static_ltree  = new Array((L_CODES+2) * 2);\nzero(static_ltree);\n/* The static literal tree. Since the bit lengths are imposed, there is no\n * need for the L_CODES extra codes used during heap construction. However\n * The codes 286 and 287 are needed to build a canonical tree (see _tr_init\n * below).\n */\n\nvar static_dtree  = new Array(D_CODES * 2);\nzero(static_dtree);\n/* The static distance tree. (Actually a trivial tree since all codes use\n * 5 bits.)\n */\n\nvar _dist_code    = new Array(DIST_CODE_LEN);\nzero(_dist_code);\n/* Distance codes. The first 256 values correspond to the distances\n * 3 .. 258, the last 256 values correspond to the top 8 bits of\n * the 15 bit distances.\n */\n\nvar _length_code  = new Array(MAX_MATCH-MIN_MATCH+1);\nzero(_length_code);\n/* length code for each normalized match length (0 == MIN_MATCH) */\n\nvar base_length   = new Array(LENGTH_CODES);\nzero(base_length);\n/* First normalized length for each code (0 = MIN_MATCH) */\n\nvar base_dist     = new Array(D_CODES);\nzero(base_dist);\n/* First normalized distance for each code (0 = distance of 1) */\n\n\nvar StaticTreeDesc = function (static_tree, extra_bits, extra_base, elems, max_length) {\n\n  this.static_tree  = static_tree;  /* static tree or NULL */\n  this.extra_bits   = extra_bits;   /* extra bits for each code or NULL */\n  this.extra_base   = extra_base;   /* base index for extra_bits */\n  this.elems        = elems;        /* max number of elements in the tree */\n  this.max_length   = max_length;   /* max bit length for the codes */\n\n  // show if `static_tree` has data or dummy - needed for monomorphic objects\n  this.has_stree    = static_tree && static_tree.length;\n};\n\n\nvar static_l_desc;\nvar static_d_desc;\nvar static_bl_desc;\n\n\nvar TreeDesc = function(dyn_tree, stat_desc) {\n  this.dyn_tree = dyn_tree;     /* the dynamic tree */\n  this.max_code = 0;            /* largest code with non zero frequency */\n  this.stat_desc = stat_desc;   /* the corresponding static tree */\n};\n\n\n\nfunction d_code(dist) {\n  return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];\n}\n\n\n/* ===========================================================================\n * Output a short LSB first on the stream.\n * IN assertion: there is enough room in pendingBuf.\n */\nfunction put_short (s, w) {\n//    put_byte(s, (uch)((w) & 0xff));\n//    put_byte(s, (uch)((ush)(w) >> 8));\n  s.pending_buf[s.pending++] = (w) & 0xff;\n  s.pending_buf[s.pending++] = (w >>> 8) & 0xff;\n}\n\n\n/* ===========================================================================\n * Send a value on a given number of bits.\n * IN assertion: length <= 16 and value fits in length bits.\n */\nfunction send_bits(s, value, length) {\n  if (s.bi_valid > (Buf_size - length)) {\n    s.bi_buf |= (value << s.bi_valid) & 0xffff;\n    put_short(s, s.bi_buf);\n    s.bi_buf = value >> (Buf_size - s.bi_valid);\n    s.bi_valid += length - Buf_size;\n  } else {\n    s.bi_buf |= (value << s.bi_valid) & 0xffff;\n    s.bi_valid += length;\n  }\n}\n\n\nfunction send_code(s, c, tree) {\n  send_bits(s, tree[c*2]/*.Code*/, tree[c*2 + 1]/*.Len*/);\n}\n\n\n/* ===========================================================================\n * Reverse the first len bits of a code, using straightforward code (a faster\n * method would use a table)\n * IN assertion: 1 <= len <= 15\n */\nfunction bi_reverse(code, len) {\n  var res = 0;\n  do {\n    res |= code & 1;\n    code >>>= 1;\n    res <<= 1;\n  } while (--len > 0);\n  return res >>> 1;\n}\n\n\n/* ===========================================================================\n * Flush the bit buffer, keeping at most 7 bits in it.\n */\nfunction bi_flush(s) {\n  if (s.bi_valid === 16) {\n    put_short(s, s.bi_buf);\n    s.bi_buf = 0;\n    s.bi_valid = 0;\n\n  } else if (s.bi_valid >= 8) {\n    s.pending_buf[s.pending++] = s.bi_buf & 0xff;\n    s.bi_buf >>= 8;\n    s.bi_valid -= 8;\n  }\n}\n\n\n/* ===========================================================================\n * Compute the optimal bit lengths for a tree and update the total bit length\n * for the current block.\n * IN assertion: the fields freq and dad are set, heap[heap_max] and\n *    above are the tree nodes sorted by increasing frequency.\n * OUT assertions: the field len is set to the optimal bit length, the\n *     array bl_count contains the frequencies for each bit length.\n *     The length opt_len is updated; static_len is also updated if stree is\n *     not null.\n */\nfunction gen_bitlen(s, desc)\n//    deflate_state *s;\n//    tree_desc *desc;    /* the tree descriptor */\n{\n  var tree            = desc.dyn_tree;\n  var max_code        = desc.max_code;\n  var stree           = desc.stat_desc.static_tree;\n  var has_stree       = desc.stat_desc.has_stree;\n  var extra           = desc.stat_desc.extra_bits;\n  var base            = desc.stat_desc.extra_base;\n  var max_length      = desc.stat_desc.max_length;\n  var h;              /* heap index */\n  var n, m;           /* iterate over the tree elements */\n  var bits;           /* bit length */\n  var xbits;          /* extra bits */\n  var f;              /* frequency */\n  var overflow = 0;   /* number of elements with bit length too large */\n\n  for (bits = 0; bits <= MAX_BITS; bits++) {\n    s.bl_count[bits] = 0;\n  }\n\n  /* In a first pass, compute the optimal bit lengths (which may\n   * overflow in the case of the bit length tree).\n   */\n  tree[s.heap[s.heap_max]*2 + 1]/*.Len*/ = 0; /* root of the heap */\n\n  for (h = s.heap_max+1; h < HEAP_SIZE; h++) {\n    n = s.heap[h];\n    bits = tree[tree[n*2 +1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;\n    if (bits > max_length) {\n      bits = max_length;\n      overflow++;\n    }\n    tree[n*2 + 1]/*.Len*/ = bits;\n    /* We overwrite tree[n].Dad which is no longer needed */\n\n    if (n > max_code) { continue; } /* not a leaf node */\n\n    s.bl_count[bits]++;\n    xbits = 0;\n    if (n >= base) {\n      xbits = extra[n-base];\n    }\n    f = tree[n * 2]/*.Freq*/;\n    s.opt_len += f * (bits + xbits);\n    if (has_stree) {\n      s.static_len += f * (stree[n*2 + 1]/*.Len*/ + xbits);\n    }\n  }\n  if (overflow === 0) { return; }\n\n  // Trace((stderr,\"\\nbit length overflow\\n\"));\n  /* This happens for example on obj2 and pic of the Calgary corpus */\n\n  /* Find the first bit length which could increase: */\n  do {\n    bits = max_length-1;\n    while (s.bl_count[bits] === 0) { bits--; }\n    s.bl_count[bits]--;      /* move one leaf down the tree */\n    s.bl_count[bits+1] += 2; /* move one overflow item as its brother */\n    s.bl_count[max_length]--;\n    /* The brother of the overflow item also moves one step up,\n     * but this does not affect bl_count[max_length]\n     */\n    overflow -= 2;\n  } while (overflow > 0);\n\n  /* Now recompute all bit lengths, scanning in increasing frequency.\n   * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all\n   * lengths instead of fixing only the wrong ones. This idea is taken\n   * from 'ar' written by Haruhiko Okumura.)\n   */\n  for (bits = max_length; bits !== 0; bits--) {\n    n = s.bl_count[bits];\n    while (n !== 0) {\n      m = s.heap[--h];\n      if (m > max_code) { continue; }\n      if (tree[m*2 + 1]/*.Len*/ !== bits) {\n        // Trace((stderr,\"code %d bits %d->%d\\n\", m, tree[m].Len, bits));\n        s.opt_len += (bits - tree[m*2 + 1]/*.Len*/)*tree[m*2]/*.Freq*/;\n        tree[m*2 + 1]/*.Len*/ = bits;\n      }\n      n--;\n    }\n  }\n}\n\n\n/* ===========================================================================\n * Generate the codes for a given tree and bit counts (which need not be\n * optimal).\n * IN assertion: the array bl_count contains the bit length statistics for\n * the given tree and the field len is set for all tree elements.\n * OUT assertion: the field code is set for all tree elements of non\n *     zero code length.\n */\nfunction gen_codes(tree, max_code, bl_count)\n//    ct_data *tree;             /* the tree to decorate */\n//    int max_code;              /* largest code with non zero frequency */\n//    ushf *bl_count;            /* number of codes at each bit length */\n{\n  var next_code = new Array(MAX_BITS+1); /* next code value for each bit length */\n  var code = 0;              /* running code value */\n  var bits;                  /* bit index */\n  var n;                     /* code index */\n\n  /* The distribution counts are first used to generate the code values\n   * without bit reversal.\n   */\n  for (bits = 1; bits <= MAX_BITS; bits++) {\n    next_code[bits] = code = (code + bl_count[bits-1]) << 1;\n  }\n  /* Check that the bit counts in bl_count are consistent. The last code\n   * must be all ones.\n   */\n  //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,\n  //        \"inconsistent bit counts\");\n  //Tracev((stderr,\"\\ngen_codes: max_code %d \", max_code));\n\n  for (n = 0;  n <= max_code; n++) {\n    var len = tree[n*2 + 1]/*.Len*/;\n    if (len === 0) { continue; }\n    /* Now reverse the bits */\n    tree[n*2]/*.Code*/ = bi_reverse(next_code[len]++, len);\n\n    //Tracecv(tree != static_ltree, (stderr,\"\\nn %3d %c l %2d c %4x (%x) \",\n    //     n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));\n  }\n}\n\n\n/* ===========================================================================\n * Initialize the various 'constant' tables.\n */\nfunction tr_static_init() {\n  var n;        /* iterates over tree elements */\n  var bits;     /* bit counter */\n  var length;   /* length value */\n  var code;     /* code value */\n  var dist;     /* distance index */\n  var bl_count = new Array(MAX_BITS+1);\n  /* number of codes at each bit length for an optimal tree */\n\n  // do check in _tr_init()\n  //if (static_init_done) return;\n\n  /* For some embedded targets, global variables are not initialized: */\n/*#ifdef NO_INIT_GLOBAL_POINTERS\n  static_l_desc.static_tree = static_ltree;\n  static_l_desc.extra_bits = extra_lbits;\n  static_d_desc.static_tree = static_dtree;\n  static_d_desc.extra_bits = extra_dbits;\n  static_bl_desc.extra_bits = extra_blbits;\n#endif*/\n\n  /* Initialize the mapping length (0..255) -> length code (0..28) */\n  length = 0;\n  for (code = 0; code < LENGTH_CODES-1; code++) {\n    base_length[code] = length;\n    for (n = 0; n < (1<<extra_lbits[code]); n++) {\n      _length_code[length++] = code;\n    }\n  }\n  //Assert (length == 256, \"tr_static_init: length != 256\");\n  /* Note that the length 255 (match length 258) can be represented\n   * in two different ways: code 284 + 5 bits or code 285, so we\n   * overwrite length_code[255] to use the best encoding:\n   */\n  _length_code[length-1] = code;\n\n  /* Initialize the mapping dist (0..32K) -> dist code (0..29) */\n  dist = 0;\n  for (code = 0 ; code < 16; code++) {\n    base_dist[code] = dist;\n    for (n = 0; n < (1<<extra_dbits[code]); n++) {\n      _dist_code[dist++] = code;\n    }\n  }\n  //Assert (dist == 256, \"tr_static_init: dist != 256\");\n  dist >>= 7; /* from now on, all distances are divided by 128 */\n  for ( ; code < D_CODES; code++) {\n    base_dist[code] = dist << 7;\n    for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {\n      _dist_code[256 + dist++] = code;\n    }\n  }\n  //Assert (dist == 256, \"tr_static_init: 256+dist != 512\");\n\n  /* Construct the codes of the static literal tree */\n  for (bits = 0; bits <= MAX_BITS; bits++) {\n    bl_count[bits] = 0;\n  }\n\n  n = 0;\n  while (n <= 143) {\n    static_ltree[n*2 + 1]/*.Len*/ = 8;\n    n++;\n    bl_count[8]++;\n  }\n  while (n <= 255) {\n    static_ltree[n*2 + 1]/*.Len*/ = 9;\n    n++;\n    bl_count[9]++;\n  }\n  while (n <= 279) {\n    static_ltree[n*2 + 1]/*.Len*/ = 7;\n    n++;\n    bl_count[7]++;\n  }\n  while (n <= 287) {\n    static_ltree[n*2 + 1]/*.Len*/ = 8;\n    n++;\n    bl_count[8]++;\n  }\n  /* Codes 286 and 287 do not exist, but we must include them in the\n   * tree construction to get a canonical Huffman tree (longest code\n   * all ones)\n   */\n  gen_codes(static_ltree, L_CODES+1, bl_count);\n\n  /* The static distance tree is trivial: */\n  for (n = 0; n < D_CODES; n++) {\n    static_dtree[n*2 + 1]/*.Len*/ = 5;\n    static_dtree[n*2]/*.Code*/ = bi_reverse(n, 5);\n  }\n\n  // Now data ready and we can init static trees\n  static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS);\n  static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS);\n  static_bl_desc =new StaticTreeDesc(new Array(0), extra_blbits, 0,         BL_CODES, MAX_BL_BITS);\n\n  //static_init_done = true;\n}\n\n\n/* ===========================================================================\n * Initialize a new block.\n */\nfunction init_block(s) {\n  var n; /* iterates over tree elements */\n\n  /* Initialize the trees. */\n  for (n = 0; n < L_CODES;  n++) { s.dyn_ltree[n*2]/*.Freq*/ = 0; }\n  for (n = 0; n < D_CODES;  n++) { s.dyn_dtree[n*2]/*.Freq*/ = 0; }\n  for (n = 0; n < BL_CODES; n++) { s.bl_tree[n*2]/*.Freq*/ = 0; }\n\n  s.dyn_ltree[END_BLOCK*2]/*.Freq*/ = 1;\n  s.opt_len = s.static_len = 0;\n  s.last_lit = s.matches = 0;\n}\n\n\n/* ===========================================================================\n * Flush the bit buffer and align the output on a byte boundary\n */\nfunction bi_windup(s)\n{\n  if (s.bi_valid > 8) {\n    put_short(s, s.bi_buf);\n  } else if (s.bi_valid > 0) {\n    //put_byte(s, (Byte)s->bi_buf);\n    s.pending_buf[s.pending++] = s.bi_buf;\n  }\n  s.bi_buf = 0;\n  s.bi_valid = 0;\n}\n\n/* ===========================================================================\n * Copy a stored block, storing first the length and its\n * one's complement if requested.\n */\nfunction copy_block(s, buf, len, header)\n//DeflateState *s;\n//charf    *buf;    /* the input data */\n//unsigned len;     /* its length */\n//int      header;  /* true if block header must be written */\n{\n  bi_windup(s);        /* align on byte boundary */\n\n  if (header) {\n    put_short(s, len);\n    put_short(s, ~len);\n  }\n//  while (len--) {\n//    put_byte(s, *buf++);\n//  }\n  utils.arraySet(s.pending_buf, s.window, buf, len, s.pending);\n  s.pending += len;\n}\n\n/* ===========================================================================\n * Compares to subtrees, using the tree depth as tie breaker when\n * the subtrees have equal frequency. This minimizes the worst case length.\n */\nfunction smaller(tree, n, m, depth) {\n  var _n2 = n*2;\n  var _m2 = m*2;\n  return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||\n         (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m]));\n}\n\n/* ===========================================================================\n * Restore the heap property by moving down the tree starting at node k,\n * exchanging a node with the smallest of its two sons if necessary, stopping\n * when the heap property is re-established (each father smaller than its\n * two sons).\n */\nfunction pqdownheap(s, tree, k)\n//    deflate_state *s;\n//    ct_data *tree;  /* the tree to restore */\n//    int k;               /* node to move down */\n{\n  var v = s.heap[k];\n  var j = k << 1;  /* left son of k */\n  while (j <= s.heap_len) {\n    /* Set j to the smallest of the two sons: */\n    if (j < s.heap_len &&\n      smaller(tree, s.heap[j+1], s.heap[j], s.depth)) {\n      j++;\n    }\n    /* Exit if v is smaller than both sons */\n    if (smaller(tree, v, s.heap[j], s.depth)) { break; }\n\n    /* Exchange v with the smallest son */\n    s.heap[k] = s.heap[j];\n    k = j;\n\n    /* And continue down the tree, setting j to the left son of k */\n    j <<= 1;\n  }\n  s.heap[k] = v;\n}\n\n\n// inlined manually\n// var SMALLEST = 1;\n\n/* ===========================================================================\n * Send the block data compressed using the given Huffman trees\n */\nfunction compress_block(s, ltree, dtree)\n//    deflate_state *s;\n//    const ct_data *ltree; /* literal tree */\n//    const ct_data *dtree; /* distance tree */\n{\n  var dist;           /* distance of matched string */\n  var lc;             /* match length or unmatched char (if dist == 0) */\n  var lx = 0;         /* running index in l_buf */\n  var code;           /* the code to send */\n  var extra;          /* number of extra bits to send */\n\n  if (s.last_lit !== 0) {\n    do {\n      dist = (s.pending_buf[s.d_buf + lx*2] << 8) | (s.pending_buf[s.d_buf + lx*2 + 1]);\n      lc = s.pending_buf[s.l_buf + lx];\n      lx++;\n\n      if (dist === 0) {\n        send_code(s, lc, ltree); /* send a literal byte */\n        //Tracecv(isgraph(lc), (stderr,\" '%c' \", lc));\n      } else {\n        /* Here, lc is the match length - MIN_MATCH */\n        code = _length_code[lc];\n        send_code(s, code+LITERALS+1, ltree); /* send the length code */\n        extra = extra_lbits[code];\n        if (extra !== 0) {\n          lc -= base_length[code];\n          send_bits(s, lc, extra);       /* send the extra length bits */\n        }\n        dist--; /* dist is now the match distance - 1 */\n        code = d_code(dist);\n        //Assert (code < D_CODES, \"bad d_code\");\n\n        send_code(s, code, dtree);       /* send the distance code */\n        extra = extra_dbits[code];\n        if (extra !== 0) {\n          dist -= base_dist[code];\n          send_bits(s, dist, extra);   /* send the extra distance bits */\n        }\n      } /* literal or match pair ? */\n\n      /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */\n      //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,\n      //       \"pendingBuf overflow\");\n\n    } while (lx < s.last_lit);\n  }\n\n  send_code(s, END_BLOCK, ltree);\n}\n\n\n/* ===========================================================================\n * Construct one Huffman tree and assigns the code bit strings and lengths.\n * Update the total bit length for the current block.\n * IN assertion: the field freq is set for all tree elements.\n * OUT assertions: the fields len and code are set to the optimal bit length\n *     and corresponding code. The length opt_len is updated; static_len is\n *     also updated if stree is not null. The field max_code is set.\n */\nfunction build_tree(s, desc)\n//    deflate_state *s;\n//    tree_desc *desc; /* the tree descriptor */\n{\n  var tree     = desc.dyn_tree;\n  var stree    = desc.stat_desc.static_tree;\n  var has_stree = desc.stat_desc.has_stree;\n  var elems    = desc.stat_desc.elems;\n  var n, m;          /* iterate over heap elements */\n  var max_code = -1; /* largest code with non zero frequency */\n  var node;          /* new node being created */\n\n  /* Construct the initial heap, with least frequent element in\n   * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].\n   * heap[0] is not used.\n   */\n  s.heap_len = 0;\n  s.heap_max = HEAP_SIZE;\n\n  for (n = 0; n < elems; n++) {\n    if (tree[n * 2]/*.Freq*/ !== 0) {\n      s.heap[++s.heap_len] = max_code = n;\n      s.depth[n] = 0;\n\n    } else {\n      tree[n*2 + 1]/*.Len*/ = 0;\n    }\n  }\n\n  /* The pkzip format requires that at least one distance code exists,\n   * and that at least one bit should be sent even if there is only one\n   * possible code. So to avoid special checks later on we force at least\n   * two codes of non zero frequency.\n   */\n  while (s.heap_len < 2) {\n    node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);\n    tree[node * 2]/*.Freq*/ = 1;\n    s.depth[node] = 0;\n    s.opt_len--;\n\n    if (has_stree) {\n      s.static_len -= stree[node*2 + 1]/*.Len*/;\n    }\n    /* node is 0 or 1 so it does not have extra bits */\n  }\n  desc.max_code = max_code;\n\n  /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,\n   * establish sub-heaps of increasing lengths:\n   */\n  for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); }\n\n  /* Construct the Huffman tree by repeatedly combining the least two\n   * frequent nodes.\n   */\n  node = elems;              /* next internal node of the tree */\n  do {\n    //pqremove(s, tree, n);  /* n = node of least frequency */\n    /*** pqremove ***/\n    n = s.heap[1/*SMALLEST*/];\n    s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];\n    pqdownheap(s, tree, 1/*SMALLEST*/);\n    /***/\n\n    m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */\n\n    s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */\n    s.heap[--s.heap_max] = m;\n\n    /* Create a new node father of n and m */\n    tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;\n    s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;\n    tree[n*2 + 1]/*.Dad*/ = tree[m*2 + 1]/*.Dad*/ = node;\n\n    /* and insert the new node in the heap */\n    s.heap[1/*SMALLEST*/] = node++;\n    pqdownheap(s, tree, 1/*SMALLEST*/);\n\n  } while (s.heap_len >= 2);\n\n  s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];\n\n  /* At this point, the fields freq and dad are set. We can now\n   * generate the bit lengths.\n   */\n  gen_bitlen(s, desc);\n\n  /* The field len is now set, we can generate the bit codes */\n  gen_codes(tree, max_code, s.bl_count);\n}\n\n\n/* ===========================================================================\n * Scan a literal or distance tree to determine the frequencies of the codes\n * in the bit length tree.\n */\nfunction scan_tree(s, tree, max_code)\n//    deflate_state *s;\n//    ct_data *tree;   /* the tree to be scanned */\n//    int max_code;    /* and its largest code of non zero frequency */\n{\n  var n;                     /* iterates over all tree elements */\n  var prevlen = -1;          /* last emitted length */\n  var curlen;                /* length of current code */\n\n  var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */\n\n  var count = 0;             /* repeat count of the current code */\n  var max_count = 7;         /* max repeat count */\n  var min_count = 4;         /* min repeat count */\n\n  if (nextlen === 0) {\n    max_count = 138;\n    min_count = 3;\n  }\n  tree[(max_code+1)*2 + 1]/*.Len*/ = 0xffff; /* guard */\n\n  for (n = 0; n <= max_code; n++) {\n    curlen = nextlen;\n    nextlen = tree[(n+1)*2 + 1]/*.Len*/;\n\n    if (++count < max_count && curlen === nextlen) {\n      continue;\n\n    } else if (count < min_count) {\n      s.bl_tree[curlen * 2]/*.Freq*/ += count;\n\n    } else if (curlen !== 0) {\n\n      if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; }\n      s.bl_tree[REP_3_6*2]/*.Freq*/++;\n\n    } else if (count <= 10) {\n      s.bl_tree[REPZ_3_10*2]/*.Freq*/++;\n\n    } else {\n      s.bl_tree[REPZ_11_138*2]/*.Freq*/++;\n    }\n\n    count = 0;\n    prevlen = curlen;\n\n    if (nextlen === 0) {\n      max_count = 138;\n      min_count = 3;\n\n    } else if (curlen === nextlen) {\n      max_count = 6;\n      min_count = 3;\n\n    } else {\n      max_count = 7;\n      min_count = 4;\n    }\n  }\n}\n\n\n/* ===========================================================================\n * Send a literal or distance tree in compressed form, using the codes in\n * bl_tree.\n */\nfunction send_tree(s, tree, max_code)\n//    deflate_state *s;\n//    ct_data *tree; /* the tree to be scanned */\n//    int max_code;       /* and its largest code of non zero frequency */\n{\n  var n;                     /* iterates over all tree elements */\n  var prevlen = -1;          /* last emitted length */\n  var curlen;                /* length of current code */\n\n  var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */\n\n  var count = 0;             /* repeat count of the current code */\n  var max_count = 7;         /* max repeat count */\n  var min_count = 4;         /* min repeat count */\n\n  /* tree[max_code+1].Len = -1; */  /* guard already set */\n  if (nextlen === 0) {\n    max_count = 138;\n    min_count = 3;\n  }\n\n  for (n = 0; n <= max_code; n++) {\n    curlen = nextlen;\n    nextlen = tree[(n+1)*2 + 1]/*.Len*/;\n\n    if (++count < max_count && curlen === nextlen) {\n      continue;\n\n    } else if (count < min_count) {\n      do { send_code(s, curlen, s.bl_tree); } while (--count !== 0);\n\n    } else if (curlen !== 0) {\n      if (curlen !== prevlen) {\n        send_code(s, curlen, s.bl_tree);\n        count--;\n      }\n      //Assert(count >= 3 && count <= 6, \" 3_6?\");\n      send_code(s, REP_3_6, s.bl_tree);\n      send_bits(s, count-3, 2);\n\n    } else if (count <= 10) {\n      send_code(s, REPZ_3_10, s.bl_tree);\n      send_bits(s, count-3, 3);\n\n    } else {\n      send_code(s, REPZ_11_138, s.bl_tree);\n      send_bits(s, count-11, 7);\n    }\n\n    count = 0;\n    prevlen = curlen;\n    if (nextlen === 0) {\n      max_count = 138;\n      min_count = 3;\n\n    } else if (curlen === nextlen) {\n      max_count = 6;\n      min_count = 3;\n\n    } else {\n      max_count = 7;\n      min_count = 4;\n    }\n  }\n}\n\n\n/* ===========================================================================\n * Construct the Huffman tree for the bit lengths and return the index in\n * bl_order of the last bit length code to send.\n */\nfunction build_bl_tree(s) {\n  var max_blindex;  /* index of last bit length code of non zero freq */\n\n  /* Determine the bit length frequencies for literal and distance trees */\n  scan_tree(s, s.dyn_ltree, s.l_desc.max_code);\n  scan_tree(s, s.dyn_dtree, s.d_desc.max_code);\n\n  /* Build the bit length tree: */\n  build_tree(s, s.bl_desc);\n  /* opt_len now includes the length of the tree representations, except\n   * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.\n   */\n\n  /* Determine the number of bit length codes to send. The pkzip format\n   * requires that at least 4 bit length codes be sent. (appnote.txt says\n   * 3 but the actual value used is 4.)\n   */\n  for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {\n    if (s.bl_tree[bl_order[max_blindex]*2 + 1]/*.Len*/ !== 0) {\n      break;\n    }\n  }\n  /* Update opt_len to include the bit length tree and counts */\n  s.opt_len += 3*(max_blindex+1) + 5+5+4;\n  //Tracev((stderr, \"\\ndyn trees: dyn %ld, stat %ld\",\n  //        s->opt_len, s->static_len));\n\n  return max_blindex;\n}\n\n\n/* ===========================================================================\n * Send the header for a block using dynamic Huffman trees: the counts, the\n * lengths of the bit length codes, the literal tree and the distance tree.\n * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.\n */\nfunction send_all_trees(s, lcodes, dcodes, blcodes)\n//    deflate_state *s;\n//    int lcodes, dcodes, blcodes; /* number of codes for each tree */\n{\n  var rank;                    /* index in bl_order */\n\n  //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, \"not enough codes\");\n  //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,\n  //        \"too many codes\");\n  //Tracev((stderr, \"\\nbl counts: \"));\n  send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */\n  send_bits(s, dcodes-1,   5);\n  send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */\n  for (rank = 0; rank < blcodes; rank++) {\n    //Tracev((stderr, \"\\nbl code %2d \", bl_order[rank]));\n    send_bits(s, s.bl_tree[bl_order[rank]*2 + 1]/*.Len*/, 3);\n  }\n  //Tracev((stderr, \"\\nbl tree: sent %ld\", s->bits_sent));\n\n  send_tree(s, s.dyn_ltree, lcodes-1); /* literal tree */\n  //Tracev((stderr, \"\\nlit tree: sent %ld\", s->bits_sent));\n\n  send_tree(s, s.dyn_dtree, dcodes-1); /* distance tree */\n  //Tracev((stderr, \"\\ndist tree: sent %ld\", s->bits_sent));\n}\n\n\n/* ===========================================================================\n * Check if the data type is TEXT or BINARY, using the following algorithm:\n * - TEXT if the two conditions below are satisfied:\n *    a) There are no non-portable control characters belonging to the\n *       \"black list\" (0..6, 14..25, 28..31).\n *    b) There is at least one printable character belonging to the\n *       \"white list\" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).\n * - BINARY otherwise.\n * - The following partially-portable control characters form a\n *   \"gray list\" that is ignored in this detection algorithm:\n *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).\n * IN assertion: the fields Freq of dyn_ltree are set.\n */\nfunction detect_data_type(s) {\n  /* black_mask is the bit mask of black-listed bytes\n   * set bits 0..6, 14..25, and 28..31\n   * 0xf3ffc07f = binary 11110011111111111100000001111111\n   */\n  var black_mask = 0xf3ffc07f;\n  var n;\n\n  /* Check for non-textual (\"black-listed\") bytes. */\n  for (n = 0; n <= 31; n++, black_mask >>>= 1) {\n    if ((black_mask & 1) && (s.dyn_ltree[n*2]/*.Freq*/ !== 0)) {\n      return Z_BINARY;\n    }\n  }\n\n  /* Check for textual (\"white-listed\") bytes. */\n  if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||\n      s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {\n    return Z_TEXT;\n  }\n  for (n = 32; n < LITERALS; n++) {\n    if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {\n      return Z_TEXT;\n    }\n  }\n\n  /* There are no \"black-listed\" or \"white-listed\" bytes:\n   * this stream either is empty or has tolerated (\"gray-listed\") bytes only.\n   */\n  return Z_BINARY;\n}\n\n\nvar static_init_done = false;\n\n/* ===========================================================================\n * Initialize the tree data structures for a new zlib stream.\n */\nfunction _tr_init(s)\n{\n\n  if (!static_init_done) {\n    tr_static_init();\n    static_init_done = true;\n  }\n\n  s.l_desc  = new TreeDesc(s.dyn_ltree, static_l_desc);\n  s.d_desc  = new TreeDesc(s.dyn_dtree, static_d_desc);\n  s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);\n\n  s.bi_buf = 0;\n  s.bi_valid = 0;\n\n  /* Initialize the first block of the first file: */\n  init_block(s);\n}\n\n\n/* ===========================================================================\n * Send a stored block\n */\nfunction _tr_stored_block(s, buf, stored_len, last)\n//DeflateState *s;\n//charf *buf;       /* input block */\n//ulg stored_len;   /* length of input block */\n//int last;         /* one if this is the last block for a file */\n{\n  send_bits(s, (STORED_BLOCK<<1)+(last ? 1 : 0), 3);    /* send block type */\n  copy_block(s, buf, stored_len, true); /* with header */\n}\n\n\n/* ===========================================================================\n * Send one empty static block to give enough lookahead for inflate.\n * This takes 10 bits, of which 7 may remain in the bit buffer.\n */\nfunction _tr_align(s) {\n  send_bits(s, STATIC_TREES<<1, 3);\n  send_code(s, END_BLOCK, static_ltree);\n  bi_flush(s);\n}\n\n\n/* ===========================================================================\n * Determine the best encoding for the current block: dynamic trees, static\n * trees or store, and output the encoded block to the zip file.\n */\nfunction _tr_flush_block(s, buf, stored_len, last)\n//DeflateState *s;\n//charf *buf;       /* input block, or NULL if too old */\n//ulg stored_len;   /* length of input block */\n//int last;         /* one if this is the last block for a file */\n{\n  var opt_lenb, static_lenb;  /* opt_len and static_len in bytes */\n  var max_blindex = 0;        /* index of last bit length code of non zero freq */\n\n  /* Build the Huffman trees unless a stored block is forced */\n  if (s.level > 0) {\n\n    /* Check if the file is binary or text */\n    if (s.strm.data_type === Z_UNKNOWN) {\n      s.strm.data_type = detect_data_type(s);\n    }\n\n    /* Construct the literal and distance trees */\n    build_tree(s, s.l_desc);\n    // Tracev((stderr, \"\\nlit data: dyn %ld, stat %ld\", s->opt_len,\n    //        s->static_len));\n\n    build_tree(s, s.d_desc);\n    // Tracev((stderr, \"\\ndist data: dyn %ld, stat %ld\", s->opt_len,\n    //        s->static_len));\n    /* At this point, opt_len and static_len are the total bit lengths of\n     * the compressed block data, excluding the tree representations.\n     */\n\n    /* Build the bit length tree for the above two trees, and get the index\n     * in bl_order of the last bit length code to send.\n     */\n    max_blindex = build_bl_tree(s);\n\n    /* Determine the best encoding. Compute the block lengths in bytes. */\n    opt_lenb = (s.opt_len+3+7) >>> 3;\n    static_lenb = (s.static_len+3+7) >>> 3;\n\n    // Tracev((stderr, \"\\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u \",\n    //        opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,\n    //        s->last_lit));\n\n    if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; }\n\n  } else {\n    // Assert(buf != (char*)0, \"lost buf\");\n    opt_lenb = static_lenb = stored_len + 5; /* force a stored block */\n  }\n\n  if ((stored_len+4 <= opt_lenb) && (buf !== -1)) {\n    /* 4: two words for the lengths */\n\n    /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.\n     * Otherwise we can't have processed more than WSIZE input bytes since\n     * the last block flush, because compression would have been\n     * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to\n     * transform a block into a stored block.\n     */\n    _tr_stored_block(s, buf, stored_len, last);\n\n  } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) {\n\n    send_bits(s, (STATIC_TREES<<1) + (last ? 1 : 0), 3);\n    compress_block(s, static_ltree, static_dtree);\n\n  } else {\n    send_bits(s, (DYN_TREES<<1) + (last ? 1 : 0), 3);\n    send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1, max_blindex+1);\n    compress_block(s, s.dyn_ltree, s.dyn_dtree);\n  }\n  // Assert (s->compressed_len == s->bits_sent, \"bad compressed size\");\n  /* The above check is made mod 2^32, for files larger than 512 MB\n   * and uLong implemented on 32 bits.\n   */\n  init_block(s);\n\n  if (last) {\n    bi_windup(s);\n  }\n  // Tracev((stderr,\"\\ncomprlen %lu(%lu) \", s->compressed_len>>3,\n  //       s->compressed_len-7*last));\n}\n\n/* ===========================================================================\n * Save the match info and tally the frequency counts. Return true if\n * the current block must be flushed.\n */\nfunction _tr_tally(s, dist, lc)\n//    deflate_state *s;\n//    unsigned dist;  /* distance of matched string */\n//    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */\n{\n  //var out_length, in_length, dcode;\n\n  s.pending_buf[s.d_buf + s.last_lit * 2]     = (dist >>> 8) & 0xff;\n  s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff;\n\n  s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff;\n  s.last_lit++;\n\n  if (dist === 0) {\n    /* lc is the unmatched char */\n    s.dyn_ltree[lc*2]/*.Freq*/++;\n  } else {\n    s.matches++;\n    /* Here, lc is the match length - MIN_MATCH */\n    dist--;             /* dist = match distance - 1 */\n    //Assert((ush)dist < (ush)MAX_DIST(s) &&\n    //       (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&\n    //       (ush)d_code(dist) < (ush)D_CODES,  \"_tr_tally: bad match\");\n\n    s.dyn_ltree[(_length_code[lc]+LITERALS+1) * 2]/*.Freq*/++;\n    s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;\n  }\n\n// (!) This block is disabled in zlib defailts,\n// don't enable it for binary compatibility\n\n//#ifdef TRUNCATE_BLOCK\n//  /* Try to guess if it is profitable to stop the current block here */\n//  if ((s.last_lit & 0x1fff) === 0 && s.level > 2) {\n//    /* Compute an upper bound for the compressed length */\n//    out_length = s.last_lit*8;\n//    in_length = s.strstart - s.block_start;\n//\n//    for (dcode = 0; dcode < D_CODES; dcode++) {\n//      out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]);\n//    }\n//    out_length >>>= 3;\n//    //Tracev((stderr,\"\\nlast_lit %u, in %ld, out ~%ld(%ld%%) \",\n//    //       s->last_lit, in_length, out_length,\n//    //       100L - out_length*100L/in_length));\n//    if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) {\n//      return true;\n//    }\n//  }\n//#endif\n\n  return (s.last_lit === s.lit_bufsize-1);\n  /* We avoid equality with lit_bufsize because of wraparound at 64K\n   * on 16 bit machines and because stored blocks are restricted to\n   * 64K-1 bytes.\n   */\n}\n\nexports._tr_init  = _tr_init;\nexports._tr_stored_block = _tr_stored_block;\nexports._tr_flush_block  = _tr_flush_block;\nexports._tr_tally = _tr_tally;\nexports._tr_align = _tr_align;\n},{\"../utils/common\":27}],39:[function(_dereq_,module,exports){\n'use strict';\n\n\nfunction ZStream() {\n  /* next input byte */\n  this.input = null; // JS specific, because we have no pointers\n  this.next_in = 0;\n  /* number of bytes available at input */\n  this.avail_in = 0;\n  /* total number of input bytes read so far */\n  this.total_in = 0;\n  /* next output byte should be put there */\n  this.output = null; // JS specific, because we have no pointers\n  this.next_out = 0;\n  /* remaining free space at output */\n  this.avail_out = 0;\n  /* total number of bytes output so far */\n  this.total_out = 0;\n  /* last error message, NULL if no error */\n  this.msg = ''/*Z_NULL*/;\n  /* not visible by applications */\n  this.state = null;\n  /* best guess about the data type: binary or text */\n  this.data_type = 2/*Z_UNKNOWN*/;\n  /* adler32 value of the uncompressed data */\n  this.adler = 0;\n}\n\nmodule.exports = ZStream;\n},{}]},{},[9])\n(9)\n});\n\n/*! pdfmake v0.1.36, @license MIT, @link http://pdfmake.org */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse {\n\t\tvar a = factory();\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n\t}\n})(typeof self !== 'undefined' ? self : this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 122);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nfunction isString(variable) {\n\treturn typeof variable === 'string' || variable instanceof String;\n}\n\nfunction isNumber(variable) {\n\treturn typeof variable === 'number' || variable instanceof Number;\n}\n\nfunction isBoolean(variable) {\n\treturn typeof variable === 'boolean';\n}\n\nfunction isArray(variable) {\n\treturn Array.isArray(variable);\n}\n\nfunction isFunction(variable) {\n\treturn typeof variable === 'function';\n}\n\nfunction isObject(variable) {\n\treturn variable !== null && typeof variable === 'object';\n}\n\nfunction isNull(variable) {\n\treturn variable === null;\n}\n\nfunction isUndefined(variable) {\n\treturn variable === undefined;\n}\n\nfunction pack() {\n\tvar result = {};\n\n\tfor (var i = 0, l = arguments.length; i < l; i++) {\n\t\tvar obj = arguments[i];\n\n\t\tif (obj) {\n\t\t\tfor (var key in obj) {\n\t\t\t\tif (obj.hasOwnProperty(key)) {\n\t\t\t\t\tresult[key] = obj[key];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction offsetVector(vector, x, y) {\n\tswitch (vector.type) {\n\t\tcase 'ellipse':\n\t\tcase 'rect':\n\t\t\tvector.x += x;\n\t\t\tvector.y += y;\n\t\t\tbreak;\n\t\tcase 'line':\n\t\t\tvector.x1 += x;\n\t\t\tvector.x2 += x;\n\t\t\tvector.y1 += y;\n\t\t\tvector.y2 += y;\n\t\t\tbreak;\n\t\tcase 'polyline':\n\t\t\tfor (var i = 0, l = vector.points.length; i < l; i++) {\n\t\t\t\tvector.points[i].x += x;\n\t\t\t\tvector.points[i].y += y;\n\t\t\t}\n\t\t\tbreak;\n\t}\n}\n\nfunction fontStringify(key, val) {\n\tif (key === 'font') {\n\t\treturn 'font';\n\t}\n\treturn val;\n}\n\nmodule.exports = {\n\tisString: isString,\n\tisNumber: isNumber,\n\tisBoolean: isBoolean,\n\tisArray: isArray,\n\tisFunction: isFunction,\n\tisObject: isObject,\n\tisNull: isNull,\n\tisUndefined: isUndefined,\n\tpack: pack,\n\tfontStringify: fontStringify,\n\toffsetVector: offsetVector\n};\n\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(global) {/*!\n * The buffer module from node.js, for the browser.\n *\n * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>\n * @license  MIT\n */\n/* eslint-disable no-proto */\n\n\n\nvar base64 = __webpack_require__(124)\nvar ieee754 = __webpack_require__(125)\nvar isArray = __webpack_require__(76)\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n *   === true    Use Uint8Array implementation (fastest)\n *   === false   Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n *   - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n *     See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n *   - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n *   - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n *     incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n  ? global.TYPED_ARRAY_SUPPORT\n  : typedArraySupport()\n\n/*\n * Export kMaxLength after typed array support is determined.\n */\nexports.kMaxLength = kMaxLength()\n\nfunction typedArraySupport () {\n  try {\n    var arr = new Uint8Array(1)\n    arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}\n    return arr.foo() === 42 && // typed array instances can be augmented\n        typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n        arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n  } catch (e) {\n    return false\n  }\n}\n\nfunction kMaxLength () {\n  return Buffer.TYPED_ARRAY_SUPPORT\n    ? 0x7fffffff\n    : 0x3fffffff\n}\n\nfunction createBuffer (that, length) {\n  if (kMaxLength() < length) {\n    throw new RangeError('Invalid typed array length')\n  }\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    // Return an augmented `Uint8Array` instance, for best performance\n    that = new Uint8Array(length)\n    that.__proto__ = Buffer.prototype\n  } else {\n    // Fallback: Return an object instance of the Buffer class\n    if (that === null) {\n      that = new Buffer(length)\n    }\n    that.length = length\n  }\n\n  return that\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\n\nfunction Buffer (arg, encodingOrOffset, length) {\n  if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {\n    return new Buffer(arg, encodingOrOffset, length)\n  }\n\n  // Common case.\n  if (typeof arg === 'number') {\n    if (typeof encodingOrOffset === 'string') {\n      throw new Error(\n        'If encoding is specified then the first argument must be a string'\n      )\n    }\n    return allocUnsafe(this, arg)\n  }\n  return from(this, arg, encodingOrOffset, length)\n}\n\nBuffer.poolSize = 8192 // not used by this implementation\n\n// TODO: Legacy, not needed anymore. Remove in next major version.\nBuffer._augment = function (arr) {\n  arr.__proto__ = Buffer.prototype\n  return arr\n}\n\nfunction from (that, value, encodingOrOffset, length) {\n  if (typeof value === 'number') {\n    throw new TypeError('\"value\" argument must not be a number')\n  }\n\n  if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n    return fromArrayBuffer(that, value, encodingOrOffset, length)\n  }\n\n  if (typeof value === 'string') {\n    return fromString(that, value, encodingOrOffset)\n  }\n\n  return fromObject(that, value)\n}\n\n/**\n * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n * if value is a number.\n * Buffer.from(str[, encoding])\n * Buffer.from(array)\n * Buffer.from(buffer)\n * Buffer.from(arrayBuffer[, byteOffset[, length]])\n **/\nBuffer.from = function (value, encodingOrOffset, length) {\n  return from(null, value, encodingOrOffset, length)\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n  Buffer.prototype.__proto__ = Uint8Array.prototype\n  Buffer.__proto__ = Uint8Array\n  if (typeof Symbol !== 'undefined' && Symbol.species &&\n      Buffer[Symbol.species] === Buffer) {\n    // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97\n    Object.defineProperty(Buffer, Symbol.species, {\n      value: null,\n      configurable: true\n    })\n  }\n}\n\nfunction assertSize (size) {\n  if (typeof size !== 'number') {\n    throw new TypeError('\"size\" argument must be a number')\n  } else if (size < 0) {\n    throw new RangeError('\"size\" argument must not be negative')\n  }\n}\n\nfunction alloc (that, size, fill, encoding) {\n  assertSize(size)\n  if (size <= 0) {\n    return createBuffer(that, size)\n  }\n  if (fill !== undefined) {\n    // Only pay attention to encoding if it's a string. This\n    // prevents accidentally sending in a number that would\n    // be interpretted as a start offset.\n    return typeof encoding === 'string'\n      ? createBuffer(that, size).fill(fill, encoding)\n      : createBuffer(that, size).fill(fill)\n  }\n  return createBuffer(that, size)\n}\n\n/**\n * Creates a new filled Buffer instance.\n * alloc(size[, fill[, encoding]])\n **/\nBuffer.alloc = function (size, fill, encoding) {\n  return alloc(null, size, fill, encoding)\n}\n\nfunction allocUnsafe (that, size) {\n  assertSize(size)\n  that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)\n  if (!Buffer.TYPED_ARRAY_SUPPORT) {\n    for (var i = 0; i < size; ++i) {\n      that[i] = 0\n    }\n  }\n  return that\n}\n\n/**\n * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n * */\nBuffer.allocUnsafe = function (size) {\n  return allocUnsafe(null, size)\n}\n/**\n * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n */\nBuffer.allocUnsafeSlow = function (size) {\n  return allocUnsafe(null, size)\n}\n\nfunction fromString (that, string, encoding) {\n  if (typeof encoding !== 'string' || encoding === '') {\n    encoding = 'utf8'\n  }\n\n  if (!Buffer.isEncoding(encoding)) {\n    throw new TypeError('\"encoding\" must be a valid string encoding')\n  }\n\n  var length = byteLength(string, encoding) | 0\n  that = createBuffer(that, length)\n\n  var actual = that.write(string, encoding)\n\n  if (actual !== length) {\n    // Writing a hex string, for example, that contains invalid characters will\n    // cause everything after the first invalid character to be ignored. (e.g.\n    // 'abxxcd' will be treated as 'ab')\n    that = that.slice(0, actual)\n  }\n\n  return that\n}\n\nfunction fromArrayLike (that, array) {\n  var length = array.length < 0 ? 0 : checked(array.length) | 0\n  that = createBuffer(that, length)\n  for (var i = 0; i < length; i += 1) {\n    that[i] = array[i] & 255\n  }\n  return that\n}\n\nfunction fromArrayBuffer (that, array, byteOffset, length) {\n  array.byteLength // this throws if `array` is not a valid ArrayBuffer\n\n  if (byteOffset < 0 || array.byteLength < byteOffset) {\n    throw new RangeError('\\'offset\\' is out of bounds')\n  }\n\n  if (array.byteLength < byteOffset + (length || 0)) {\n    throw new RangeError('\\'length\\' is out of bounds')\n  }\n\n  if (byteOffset === undefined && length === undefined) {\n    array = new Uint8Array(array)\n  } else if (length === undefined) {\n    array = new Uint8Array(array, byteOffset)\n  } else {\n    array = new Uint8Array(array, byteOffset, length)\n  }\n\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    // Return an augmented `Uint8Array` instance, for best performance\n    that = array\n    that.__proto__ = Buffer.prototype\n  } else {\n    // Fallback: Return an object instance of the Buffer class\n    that = fromArrayLike(that, array)\n  }\n  return that\n}\n\nfunction fromObject (that, obj) {\n  if (Buffer.isBuffer(obj)) {\n    var len = checked(obj.length) | 0\n    that = createBuffer(that, len)\n\n    if (that.length === 0) {\n      return that\n    }\n\n    obj.copy(that, 0, 0, len)\n    return that\n  }\n\n  if (obj) {\n    if ((typeof ArrayBuffer !== 'undefined' &&\n        obj.buffer instanceof ArrayBuffer) || 'length' in obj) {\n      if (typeof obj.length !== 'number' || isnan(obj.length)) {\n        return createBuffer(that, 0)\n      }\n      return fromArrayLike(that, obj)\n    }\n\n    if (obj.type === 'Buffer' && isArray(obj.data)) {\n      return fromArrayLike(that, obj.data)\n    }\n  }\n\n  throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')\n}\n\nfunction checked (length) {\n  // Note: cannot use `length < kMaxLength()` here because that fails when\n  // length is NaN (which is otherwise coerced to zero.)\n  if (length >= kMaxLength()) {\n    throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n                         'size: 0x' + kMaxLength().toString(16) + ' bytes')\n  }\n  return length | 0\n}\n\nfunction SlowBuffer (length) {\n  if (+length != length) { // eslint-disable-line eqeqeq\n    length = 0\n  }\n  return Buffer.alloc(+length)\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n  return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n  if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n    throw new TypeError('Arguments must be Buffers')\n  }\n\n  if (a === b) return 0\n\n  var x = a.length\n  var y = b.length\n\n  for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n    if (a[i] !== b[i]) {\n      x = a[i]\n      y = b[i]\n      break\n    }\n  }\n\n  if (x < y) return -1\n  if (y < x) return 1\n  return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n  switch (String(encoding).toLowerCase()) {\n    case 'hex':\n    case 'utf8':\n    case 'utf-8':\n    case 'ascii':\n    case 'latin1':\n    case 'binary':\n    case 'base64':\n    case 'ucs2':\n    case 'ucs-2':\n    case 'utf16le':\n    case 'utf-16le':\n      return true\n    default:\n      return false\n  }\n}\n\nBuffer.concat = function concat (list, length) {\n  if (!isArray(list)) {\n    throw new TypeError('\"list\" argument must be an Array of Buffers')\n  }\n\n  if (list.length === 0) {\n    return Buffer.alloc(0)\n  }\n\n  var i\n  if (length === undefined) {\n    length = 0\n    for (i = 0; i < list.length; ++i) {\n      length += list[i].length\n    }\n  }\n\n  var buffer = Buffer.allocUnsafe(length)\n  var pos = 0\n  for (i = 0; i < list.length; ++i) {\n    var buf = list[i]\n    if (!Buffer.isBuffer(buf)) {\n      throw new TypeError('\"list\" argument must be an Array of Buffers')\n    }\n    buf.copy(buffer, pos)\n    pos += buf.length\n  }\n  return buffer\n}\n\nfunction byteLength (string, encoding) {\n  if (Buffer.isBuffer(string)) {\n    return string.length\n  }\n  if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&\n      (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n    return string.byteLength\n  }\n  if (typeof string !== 'string') {\n    string = '' + string\n  }\n\n  var len = string.length\n  if (len === 0) return 0\n\n  // Use a for loop to avoid recursion\n  var loweredCase = false\n  for (;;) {\n    switch (encoding) {\n      case 'ascii':\n      case 'latin1':\n      case 'binary':\n        return len\n      case 'utf8':\n      case 'utf-8':\n      case undefined:\n        return utf8ToBytes(string).length\n      case 'ucs2':\n      case 'ucs-2':\n      case 'utf16le':\n      case 'utf-16le':\n        return len * 2\n      case 'hex':\n        return len >>> 1\n      case 'base64':\n        return base64ToBytes(string).length\n      default:\n        if (loweredCase) return utf8ToBytes(string).length // assume utf8\n        encoding = ('' + encoding).toLowerCase()\n        loweredCase = true\n    }\n  }\n}\nBuffer.byteLength = byteLength\n\nfunction slowToString (encoding, start, end) {\n  var loweredCase = false\n\n  // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n  // property of a typed array.\n\n  // This behaves neither like String nor Uint8Array in that we set start/end\n  // to their upper/lower bounds if the value passed is out of range.\n  // undefined is handled specially as per ECMA-262 6th Edition,\n  // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n  if (start === undefined || start < 0) {\n    start = 0\n  }\n  // Return early if start > this.length. Done here to prevent potential uint32\n  // coercion fail below.\n  if (start > this.length) {\n    return ''\n  }\n\n  if (end === undefined || end > this.length) {\n    end = this.length\n  }\n\n  if (end <= 0) {\n    return ''\n  }\n\n  // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n  end >>>= 0\n  start >>>= 0\n\n  if (end <= start) {\n    return ''\n  }\n\n  if (!encoding) encoding = 'utf8'\n\n  while (true) {\n    switch (encoding) {\n      case 'hex':\n        return hexSlice(this, start, end)\n\n      case 'utf8':\n      case 'utf-8':\n        return utf8Slice(this, start, end)\n\n      case 'ascii':\n        return asciiSlice(this, start, end)\n\n      case 'latin1':\n      case 'binary':\n        return latin1Slice(this, start, end)\n\n      case 'base64':\n        return base64Slice(this, start, end)\n\n      case 'ucs2':\n      case 'ucs-2':\n      case 'utf16le':\n      case 'utf-16le':\n        return utf16leSlice(this, start, end)\n\n      default:\n        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n        encoding = (encoding + '').toLowerCase()\n        loweredCase = true\n    }\n  }\n}\n\n// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n// Buffer instances.\nBuffer.prototype._isBuffer = true\n\nfunction swap (b, n, m) {\n  var i = b[n]\n  b[n] = b[m]\n  b[m] = i\n}\n\nBuffer.prototype.swap16 = function swap16 () {\n  var len = this.length\n  if (len % 2 !== 0) {\n    throw new RangeError('Buffer size must be a multiple of 16-bits')\n  }\n  for (var i = 0; i < len; i += 2) {\n    swap(this, i, i + 1)\n  }\n  return this\n}\n\nBuffer.prototype.swap32 = function swap32 () {\n  var len = this.length\n  if (len % 4 !== 0) {\n    throw new RangeError('Buffer size must be a multiple of 32-bits')\n  }\n  for (var i = 0; i < len; i += 4) {\n    swap(this, i, i + 3)\n    swap(this, i + 1, i + 2)\n  }\n  return this\n}\n\nBuffer.prototype.swap64 = function swap64 () {\n  var len = this.length\n  if (len % 8 !== 0) {\n    throw new RangeError('Buffer size must be a multiple of 64-bits')\n  }\n  for (var i = 0; i < len; i += 8) {\n    swap(this, i, i + 7)\n    swap(this, i + 1, i + 6)\n    swap(this, i + 2, i + 5)\n    swap(this, i + 3, i + 4)\n  }\n  return this\n}\n\nBuffer.prototype.toString = function toString () {\n  var length = this.length | 0\n  if (length === 0) return ''\n  if (arguments.length === 0) return utf8Slice(this, 0, length)\n  return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n  if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n  if (this === b) return true\n  return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n  var str = ''\n  var max = exports.INSPECT_MAX_BYTES\n  if (this.length > 0) {\n    str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n    if (this.length > max) str += ' ... '\n  }\n  return '<Buffer ' + str + '>'\n}\n\nBuffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {\n  if (!Buffer.isBuffer(target)) {\n    throw new TypeError('Argument must be a Buffer')\n  }\n\n  if (start === undefined) {\n    start = 0\n  }\n  if (end === undefined) {\n    end = target ? target.length : 0\n  }\n  if (thisStart === undefined) {\n    thisStart = 0\n  }\n  if (thisEnd === undefined) {\n    thisEnd = this.length\n  }\n\n  if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n    throw new RangeError('out of range index')\n  }\n\n  if (thisStart >= thisEnd && start >= end) {\n    return 0\n  }\n  if (thisStart >= thisEnd) {\n    return -1\n  }\n  if (start >= end) {\n    return 1\n  }\n\n  start >>>= 0\n  end >>>= 0\n  thisStart >>>= 0\n  thisEnd >>>= 0\n\n  if (this === target) return 0\n\n  var x = thisEnd - thisStart\n  var y = end - start\n  var len = Math.min(x, y)\n\n  var thisCopy = this.slice(thisStart, thisEnd)\n  var targetCopy = target.slice(start, end)\n\n  for (var i = 0; i < len; ++i) {\n    if (thisCopy[i] !== targetCopy[i]) {\n      x = thisCopy[i]\n      y = targetCopy[i]\n      break\n    }\n  }\n\n  if (x < y) return -1\n  if (y < x) return 1\n  return 0\n}\n\n// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,\n// OR the last index of `val` in `buffer` at offset <= `byteOffset`.\n//\n// Arguments:\n// - buffer - a Buffer to search\n// - val - a string, Buffer, or number\n// - byteOffset - an index into `buffer`; will be clamped to an int32\n// - encoding - an optional encoding, relevant is val is a string\n// - dir - true for indexOf, false for lastIndexOf\nfunction bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {\n  // Empty buffer means no match\n  if (buffer.length === 0) return -1\n\n  // Normalize byteOffset\n  if (typeof byteOffset === 'string') {\n    encoding = byteOffset\n    byteOffset = 0\n  } else if (byteOffset > 0x7fffffff) {\n    byteOffset = 0x7fffffff\n  } else if (byteOffset < -0x80000000) {\n    byteOffset = -0x80000000\n  }\n  byteOffset = +byteOffset  // Coerce to Number.\n  if (isNaN(byteOffset)) {\n    // byteOffset: it it's undefined, null, NaN, \"foo\", etc, search whole buffer\n    byteOffset = dir ? 0 : (buffer.length - 1)\n  }\n\n  // Normalize byteOffset: negative offsets start from the end of the buffer\n  if (byteOffset < 0) byteOffset = buffer.length + byteOffset\n  if (byteOffset >= buffer.length) {\n    if (dir) return -1\n    else byteOffset = buffer.length - 1\n  } else if (byteOffset < 0) {\n    if (dir) byteOffset = 0\n    else return -1\n  }\n\n  // Normalize val\n  if (typeof val === 'string') {\n    val = Buffer.from(val, encoding)\n  }\n\n  // Finally, search either indexOf (if dir is true) or lastIndexOf\n  if (Buffer.isBuffer(val)) {\n    // Special case: looking for empty string/buffer always fails\n    if (val.length === 0) {\n      return -1\n    }\n    return arrayIndexOf(buffer, val, byteOffset, encoding, dir)\n  } else if (typeof val === 'number') {\n    val = val & 0xFF // Search for a byte value [0-255]\n    if (Buffer.TYPED_ARRAY_SUPPORT &&\n        typeof Uint8Array.prototype.indexOf === 'function') {\n      if (dir) {\n        return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)\n      } else {\n        return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)\n      }\n    }\n    return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)\n  }\n\n  throw new TypeError('val must be string, number or Buffer')\n}\n\nfunction arrayIndexOf (arr, val, byteOffset, encoding, dir) {\n  var indexSize = 1\n  var arrLength = arr.length\n  var valLength = val.length\n\n  if (encoding !== undefined) {\n    encoding = String(encoding).toLowerCase()\n    if (encoding === 'ucs2' || encoding === 'ucs-2' ||\n        encoding === 'utf16le' || encoding === 'utf-16le') {\n      if (arr.length < 2 || val.length < 2) {\n        return -1\n      }\n      indexSize = 2\n      arrLength /= 2\n      valLength /= 2\n      byteOffset /= 2\n    }\n  }\n\n  function read (buf, i) {\n    if (indexSize === 1) {\n      return buf[i]\n    } else {\n      return buf.readUInt16BE(i * indexSize)\n    }\n  }\n\n  var i\n  if (dir) {\n    var foundIndex = -1\n    for (i = byteOffset; i < arrLength; i++) {\n      if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n        if (foundIndex === -1) foundIndex = i\n        if (i - foundIndex + 1 === valLength) return foundIndex * indexSize\n      } else {\n        if (foundIndex !== -1) i -= i - foundIndex\n        foundIndex = -1\n      }\n    }\n  } else {\n    if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength\n    for (i = byteOffset; i >= 0; i--) {\n      var found = true\n      for (var j = 0; j < valLength; j++) {\n        if (read(arr, i + j) !== read(val, j)) {\n          found = false\n          break\n        }\n      }\n      if (found) return i\n    }\n  }\n\n  return -1\n}\n\nBuffer.prototype.includes = function includes (val, byteOffset, encoding) {\n  return this.indexOf(val, byteOffset, encoding) !== -1\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {\n  return bidirectionalIndexOf(this, val, byteOffset, encoding, true)\n}\n\nBuffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {\n  return bidirectionalIndexOf(this, val, byteOffset, encoding, false)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n  offset = Number(offset) || 0\n  var remaining = buf.length - offset\n  if (!length) {\n    length = remaining\n  } else {\n    length = Number(length)\n    if (length > remaining) {\n      length = remaining\n    }\n  }\n\n  // must be an even number of digits\n  var strLen = string.length\n  if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')\n\n  if (length > strLen / 2) {\n    length = strLen / 2\n  }\n  for (var i = 0; i < length; ++i) {\n    var parsed = parseInt(string.substr(i * 2, 2), 16)\n    if (isNaN(parsed)) return i\n    buf[offset + i] = parsed\n  }\n  return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n  return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n  return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction latin1Write (buf, string, offset, length) {\n  return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n  return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n  return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n  // Buffer#write(string)\n  if (offset === undefined) {\n    encoding = 'utf8'\n    length = this.length\n    offset = 0\n  // Buffer#write(string, encoding)\n  } else if (length === undefined && typeof offset === 'string') {\n    encoding = offset\n    length = this.length\n    offset = 0\n  // Buffer#write(string, offset[, length][, encoding])\n  } else if (isFinite(offset)) {\n    offset = offset | 0\n    if (isFinite(length)) {\n      length = length | 0\n      if (encoding === undefined) encoding = 'utf8'\n    } else {\n      encoding = length\n      length = undefined\n    }\n  // legacy write(string, encoding, offset, length) - remove in v0.13\n  } else {\n    throw new Error(\n      'Buffer.write(string, encoding, offset[, length]) is no longer supported'\n    )\n  }\n\n  var remaining = this.length - offset\n  if (length === undefined || length > remaining) length = remaining\n\n  if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n    throw new RangeError('Attempt to write outside buffer bounds')\n  }\n\n  if (!encoding) encoding = 'utf8'\n\n  var loweredCase = false\n  for (;;) {\n    switch (encoding) {\n      case 'hex':\n        return hexWrite(this, string, offset, length)\n\n      case 'utf8':\n      case 'utf-8':\n        return utf8Write(this, string, offset, length)\n\n      case 'ascii':\n        return asciiWrite(this, string, offset, length)\n\n      case 'latin1':\n      case 'binary':\n        return latin1Write(this, string, offset, length)\n\n      case 'base64':\n        // Warning: maxLength not taken into account in base64Write\n        return base64Write(this, string, offset, length)\n\n      case 'ucs2':\n      case 'ucs-2':\n      case 'utf16le':\n      case 'utf-16le':\n        return ucs2Write(this, string, offset, length)\n\n      default:\n        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n        encoding = ('' + encoding).toLowerCase()\n        loweredCase = true\n    }\n  }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n  return {\n    type: 'Buffer',\n    data: Array.prototype.slice.call(this._arr || this, 0)\n  }\n}\n\nfunction base64Slice (buf, start, end) {\n  if (start === 0 && end === buf.length) {\n    return base64.fromByteArray(buf)\n  } else {\n    return base64.fromByteArray(buf.slice(start, end))\n  }\n}\n\nfunction utf8Slice (buf, start, end) {\n  end = Math.min(buf.length, end)\n  var res = []\n\n  var i = start\n  while (i < end) {\n    var firstByte = buf[i]\n    var codePoint = null\n    var bytesPerSequence = (firstByte > 0xEF) ? 4\n      : (firstByte > 0xDF) ? 3\n      : (firstByte > 0xBF) ? 2\n      : 1\n\n    if (i + bytesPerSequence <= end) {\n      var secondByte, thirdByte, fourthByte, tempCodePoint\n\n      switch (bytesPerSequence) {\n        case 1:\n          if (firstByte < 0x80) {\n            codePoint = firstByte\n          }\n          break\n        case 2:\n          secondByte = buf[i + 1]\n          if ((secondByte & 0xC0) === 0x80) {\n            tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n            if (tempCodePoint > 0x7F) {\n              codePoint = tempCodePoint\n            }\n          }\n          break\n        case 3:\n          secondByte = buf[i + 1]\n          thirdByte = buf[i + 2]\n          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n            tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n            if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n              codePoint = tempCodePoint\n            }\n          }\n          break\n        case 4:\n          secondByte = buf[i + 1]\n          thirdByte = buf[i + 2]\n          fourthByte = buf[i + 3]\n          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n            tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n            if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n              codePoint = tempCodePoint\n            }\n          }\n      }\n    }\n\n    if (codePoint === null) {\n      // we did not generate a valid codePoint so insert a\n      // replacement char (U+FFFD) and advance only 1 byte\n      codePoint = 0xFFFD\n      bytesPerSequence = 1\n    } else if (codePoint > 0xFFFF) {\n      // encode to utf16 (surrogate pair dance)\n      codePoint -= 0x10000\n      res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n      codePoint = 0xDC00 | codePoint & 0x3FF\n    }\n\n    res.push(codePoint)\n    i += bytesPerSequence\n  }\n\n  return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n  var len = codePoints.length\n  if (len <= MAX_ARGUMENTS_LENGTH) {\n    return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n  }\n\n  // Decode in chunks to avoid \"call stack size exceeded\".\n  var res = ''\n  var i = 0\n  while (i < len) {\n    res += String.fromCharCode.apply(\n      String,\n      codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n    )\n  }\n  return res\n}\n\nfunction asciiSlice (buf, start, end) {\n  var ret = ''\n  end = Math.min(buf.length, end)\n\n  for (var i = start; i < end; ++i) {\n    ret += String.fromCharCode(buf[i] & 0x7F)\n  }\n  return ret\n}\n\nfunction latin1Slice (buf, start, end) {\n  var ret = ''\n  end = Math.min(buf.length, end)\n\n  for (var i = start; i < end; ++i) {\n    ret += String.fromCharCode(buf[i])\n  }\n  return ret\n}\n\nfunction hexSlice (buf, start, end) {\n  var len = buf.length\n\n  if (!start || start < 0) start = 0\n  if (!end || end < 0 || end > len) end = len\n\n  var out = ''\n  for (var i = start; i < end; ++i) {\n    out += toHex(buf[i])\n  }\n  return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n  var bytes = buf.slice(start, end)\n  var res = ''\n  for (var i = 0; i < bytes.length; i += 2) {\n    res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n  }\n  return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n  var len = this.length\n  start = ~~start\n  end = end === undefined ? len : ~~end\n\n  if (start < 0) {\n    start += len\n    if (start < 0) start = 0\n  } else if (start > len) {\n    start = len\n  }\n\n  if (end < 0) {\n    end += len\n    if (end < 0) end = 0\n  } else if (end > len) {\n    end = len\n  }\n\n  if (end < start) end = start\n\n  var newBuf\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    newBuf = this.subarray(start, end)\n    newBuf.__proto__ = Buffer.prototype\n  } else {\n    var sliceLen = end - start\n    newBuf = new Buffer(sliceLen, undefined)\n    for (var i = 0; i < sliceLen; ++i) {\n      newBuf[i] = this[i + start]\n    }\n  }\n\n  return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n  if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n  if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n  var val = this[offset]\n  var mul = 1\n  var i = 0\n  while (++i < byteLength && (mul *= 0x100)) {\n    val += this[offset + i] * mul\n  }\n\n  return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) {\n    checkOffset(offset, byteLength, this.length)\n  }\n\n  var val = this[offset + --byteLength]\n  var mul = 1\n  while (byteLength > 0 && (mul *= 0x100)) {\n    val += this[offset + --byteLength] * mul\n  }\n\n  return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 1, this.length)\n  return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return ((this[offset]) |\n      (this[offset + 1] << 8) |\n      (this[offset + 2] << 16)) +\n      (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return (this[offset] * 0x1000000) +\n    ((this[offset + 1] << 16) |\n    (this[offset + 2] << 8) |\n    this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n  var val = this[offset]\n  var mul = 1\n  var i = 0\n  while (++i < byteLength && (mul *= 0x100)) {\n    val += this[offset + i] * mul\n  }\n  mul *= 0x80\n\n  if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n  return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n  var i = byteLength\n  var mul = 1\n  var val = this[offset + --i]\n  while (i > 0 && (mul *= 0x100)) {\n    val += this[offset + --i] * mul\n  }\n  mul *= 0x80\n\n  if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n  return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 1, this.length)\n  if (!(this[offset] & 0x80)) return (this[offset])\n  return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  var val = this[offset] | (this[offset + 1] << 8)\n  return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  var val = this[offset + 1] | (this[offset] << 8)\n  return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return (this[offset]) |\n    (this[offset + 1] << 8) |\n    (this[offset + 2] << 16) |\n    (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return (this[offset] << 24) |\n    (this[offset + 1] << 16) |\n    (this[offset + 2] << 8) |\n    (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n  return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n  return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 8, this.length)\n  return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 8, this.length)\n  return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n  if (!Buffer.isBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance')\n  if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds')\n  if (offset + ext > buf.length) throw new RangeError('Index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) {\n    var maxBytes = Math.pow(2, 8 * byteLength) - 1\n    checkInt(this, value, offset, byteLength, maxBytes, 0)\n  }\n\n  var mul = 1\n  var i = 0\n  this[offset] = value & 0xFF\n  while (++i < byteLength && (mul *= 0x100)) {\n    this[offset + i] = (value / mul) & 0xFF\n  }\n\n  return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) {\n    var maxBytes = Math.pow(2, 8 * byteLength) - 1\n    checkInt(this, value, offset, byteLength, maxBytes, 0)\n  }\n\n  var i = byteLength - 1\n  var mul = 1\n  this[offset + i] = value & 0xFF\n  while (--i >= 0 && (mul *= 0x100)) {\n    this[offset + i] = (value / mul) & 0xFF\n  }\n\n  return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n  this[offset] = (value & 0xff)\n  return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n  if (value < 0) value = 0xffff + value + 1\n  for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n    buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n      (littleEndian ? i : 1 - i) * 8\n  }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value & 0xff)\n    this[offset + 1] = (value >>> 8)\n  } else {\n    objectWriteUInt16(this, value, offset, true)\n  }\n  return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 8)\n    this[offset + 1] = (value & 0xff)\n  } else {\n    objectWriteUInt16(this, value, offset, false)\n  }\n  return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n  if (value < 0) value = 0xffffffff + value + 1\n  for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n    buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n  }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset + 3] = (value >>> 24)\n    this[offset + 2] = (value >>> 16)\n    this[offset + 1] = (value >>> 8)\n    this[offset] = (value & 0xff)\n  } else {\n    objectWriteUInt32(this, value, offset, true)\n  }\n  return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 24)\n    this[offset + 1] = (value >>> 16)\n    this[offset + 2] = (value >>> 8)\n    this[offset + 3] = (value & 0xff)\n  } else {\n    objectWriteUInt32(this, value, offset, false)\n  }\n  return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) {\n    var limit = Math.pow(2, 8 * byteLength - 1)\n\n    checkInt(this, value, offset, byteLength, limit - 1, -limit)\n  }\n\n  var i = 0\n  var mul = 1\n  var sub = 0\n  this[offset] = value & 0xFF\n  while (++i < byteLength && (mul *= 0x100)) {\n    if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n      sub = 1\n    }\n    this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n  }\n\n  return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) {\n    var limit = Math.pow(2, 8 * byteLength - 1)\n\n    checkInt(this, value, offset, byteLength, limit - 1, -limit)\n  }\n\n  var i = byteLength - 1\n  var mul = 1\n  var sub = 0\n  this[offset + i] = value & 0xFF\n  while (--i >= 0 && (mul *= 0x100)) {\n    if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n      sub = 1\n    }\n    this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n  }\n\n  return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n  if (value < 0) value = 0xff + value + 1\n  this[offset] = (value & 0xff)\n  return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value & 0xff)\n    this[offset + 1] = (value >>> 8)\n  } else {\n    objectWriteUInt16(this, value, offset, true)\n  }\n  return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 8)\n    this[offset + 1] = (value & 0xff)\n  } else {\n    objectWriteUInt16(this, value, offset, false)\n  }\n  return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value & 0xff)\n    this[offset + 1] = (value >>> 8)\n    this[offset + 2] = (value >>> 16)\n    this[offset + 3] = (value >>> 24)\n  } else {\n    objectWriteUInt32(this, value, offset, true)\n  }\n  return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n  if (value < 0) value = 0xffffffff + value + 1\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 24)\n    this[offset + 1] = (value >>> 16)\n    this[offset + 2] = (value >>> 8)\n    this[offset + 3] = (value & 0xff)\n  } else {\n    objectWriteUInt32(this, value, offset, false)\n  }\n  return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n  if (offset + ext > buf.length) throw new RangeError('Index out of range')\n  if (offset < 0) throw new RangeError('Index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n  if (!noAssert) {\n    checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n  }\n  ieee754.write(buf, value, offset, littleEndian, 23, 4)\n  return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n  return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n  return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n  if (!noAssert) {\n    checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n  }\n  ieee754.write(buf, value, offset, littleEndian, 52, 8)\n  return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n  return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n  return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n  if (!start) start = 0\n  if (!end && end !== 0) end = this.length\n  if (targetStart >= target.length) targetStart = target.length\n  if (!targetStart) targetStart = 0\n  if (end > 0 && end < start) end = start\n\n  // Copy 0 bytes; we're done\n  if (end === start) return 0\n  if (target.length === 0 || this.length === 0) return 0\n\n  // Fatal error conditions\n  if (targetStart < 0) {\n    throw new RangeError('targetStart out of bounds')\n  }\n  if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n  if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n  // Are we oob?\n  if (end > this.length) end = this.length\n  if (target.length - targetStart < end - start) {\n    end = target.length - targetStart + start\n  }\n\n  var len = end - start\n  var i\n\n  if (this === target && start < targetStart && targetStart < end) {\n    // descending copy from end\n    for (i = len - 1; i >= 0; --i) {\n      target[i + targetStart] = this[i + start]\n    }\n  } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n    // ascending copy from start\n    for (i = 0; i < len; ++i) {\n      target[i + targetStart] = this[i + start]\n    }\n  } else {\n    Uint8Array.prototype.set.call(\n      target,\n      this.subarray(start, start + len),\n      targetStart\n    )\n  }\n\n  return len\n}\n\n// Usage:\n//    buffer.fill(number[, offset[, end]])\n//    buffer.fill(buffer[, offset[, end]])\n//    buffer.fill(string[, offset[, end]][, encoding])\nBuffer.prototype.fill = function fill (val, start, end, encoding) {\n  // Handle string cases:\n  if (typeof val === 'string') {\n    if (typeof start === 'string') {\n      encoding = start\n      start = 0\n      end = this.length\n    } else if (typeof end === 'string') {\n      encoding = end\n      end = this.length\n    }\n    if (val.length === 1) {\n      var code = val.charCodeAt(0)\n      if (code < 256) {\n        val = code\n      }\n    }\n    if (encoding !== undefined && typeof encoding !== 'string') {\n      throw new TypeError('encoding must be a string')\n    }\n    if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n      throw new TypeError('Unknown encoding: ' + encoding)\n    }\n  } else if (typeof val === 'number') {\n    val = val & 255\n  }\n\n  // Invalid ranges are not set to a default, so can range check early.\n  if (start < 0 || this.length < start || this.length < end) {\n    throw new RangeError('Out of range index')\n  }\n\n  if (end <= start) {\n    return this\n  }\n\n  start = start >>> 0\n  end = end === undefined ? this.length : end >>> 0\n\n  if (!val) val = 0\n\n  var i\n  if (typeof val === 'number') {\n    for (i = start; i < end; ++i) {\n      this[i] = val\n    }\n  } else {\n    var bytes = Buffer.isBuffer(val)\n      ? val\n      : utf8ToBytes(new Buffer(val, encoding).toString())\n    var len = bytes.length\n    for (i = 0; i < end - start; ++i) {\n      this[i + start] = bytes[i % len]\n    }\n  }\n\n  return this\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n  // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n  str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n  // Node converts strings with length < 2 to ''\n  if (str.length < 2) return ''\n  // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n  while (str.length % 4 !== 0) {\n    str = str + '='\n  }\n  return str\n}\n\nfunction stringtrim (str) {\n  if (str.trim) return str.trim()\n  return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n  if (n < 16) return '0' + n.toString(16)\n  return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n  units = units || Infinity\n  var codePoint\n  var length = string.length\n  var leadSurrogate = null\n  var bytes = []\n\n  for (var i = 0; i < length; ++i) {\n    codePoint = string.charCodeAt(i)\n\n    // is surrogate component\n    if (codePoint > 0xD7FF && codePoint < 0xE000) {\n      // last char was a lead\n      if (!leadSurrogate) {\n        // no lead yet\n        if (codePoint > 0xDBFF) {\n          // unexpected trail\n          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n          continue\n        } else if (i + 1 === length) {\n          // unpaired lead\n          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n          continue\n        }\n\n        // valid lead\n        leadSurrogate = codePoint\n\n        continue\n      }\n\n      // 2 leads in a row\n      if (codePoint < 0xDC00) {\n        if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n        leadSurrogate = codePoint\n        continue\n      }\n\n      // valid surrogate pair\n      codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n    } else if (leadSurrogate) {\n      // valid bmp char, but last char was a lead\n      if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n    }\n\n    leadSurrogate = null\n\n    // encode utf8\n    if (codePoint < 0x80) {\n      if ((units -= 1) < 0) break\n      bytes.push(codePoint)\n    } else if (codePoint < 0x800) {\n      if ((units -= 2) < 0) break\n      bytes.push(\n        codePoint >> 0x6 | 0xC0,\n        codePoint & 0x3F | 0x80\n      )\n    } else if (codePoint < 0x10000) {\n      if ((units -= 3) < 0) break\n      bytes.push(\n        codePoint >> 0xC | 0xE0,\n        codePoint >> 0x6 & 0x3F | 0x80,\n        codePoint & 0x3F | 0x80\n      )\n    } else if (codePoint < 0x110000) {\n      if ((units -= 4) < 0) break\n      bytes.push(\n        codePoint >> 0x12 | 0xF0,\n        codePoint >> 0xC & 0x3F | 0x80,\n        codePoint >> 0x6 & 0x3F | 0x80,\n        codePoint & 0x3F | 0x80\n      )\n    } else {\n      throw new Error('Invalid code point')\n    }\n  }\n\n  return bytes\n}\n\nfunction asciiToBytes (str) {\n  var byteArray = []\n  for (var i = 0; i < str.length; ++i) {\n    // Node's code seems to be doing this and not & 0x7F..\n    byteArray.push(str.charCodeAt(i) & 0xFF)\n  }\n  return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n  var c, hi, lo\n  var byteArray = []\n  for (var i = 0; i < str.length; ++i) {\n    if ((units -= 2) < 0) break\n\n    c = str.charCodeAt(i)\n    hi = c >> 8\n    lo = c % 256\n    byteArray.push(lo)\n    byteArray.push(hi)\n  }\n\n  return byteArray\n}\n\nfunction base64ToBytes (str) {\n  return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n  for (var i = 0; i < length; ++i) {\n    if ((i + offset >= dst.length) || (i >= src.length)) break\n    dst[i + offset] = src[i]\n  }\n  return i\n}\n\nfunction isnan (val) {\n  return val !== val // eslint-disable-line no-self-compare\n}\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports) {\n\nvar core = module.exports = { version: '2.5.3' };\nif (typeof __e == 'number') __e = core; // eslint-disable-line no-undef\n\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar global = __webpack_require__(10);\nvar core = __webpack_require__(2);\nvar ctx = __webpack_require__(20);\nvar hide = __webpack_require__(13);\nvar PROTOTYPE = 'prototype';\n\nvar $export = function (type, name, source) {\n  var IS_FORCED = type & $export.F;\n  var IS_GLOBAL = type & $export.G;\n  var IS_STATIC = type & $export.S;\n  var IS_PROTO = type & $export.P;\n  var IS_BIND = type & $export.B;\n  var IS_WRAP = type & $export.W;\n  var exports = IS_GLOBAL ? core : core[name] || (core[name] = {});\n  var expProto = exports[PROTOTYPE];\n  var target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE];\n  var key, own, out;\n  if (IS_GLOBAL) source = name;\n  for (key in source) {\n    // contains in native\n    own = !IS_FORCED && target && target[key] !== undefined;\n    if (own && key in exports) continue;\n    // export native or passed\n    out = own ? target[key] : source[key];\n    // prevent global pollution for namespaces\n    exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key]\n    // bind timers to global for call from export context\n    : IS_BIND && own ? ctx(out, global)\n    // wrap global constructors for prevent change them in library\n    : IS_WRAP && target[key] == out ? (function (C) {\n      var F = function (a, b, c) {\n        if (this instanceof C) {\n          switch (arguments.length) {\n            case 0: return new C();\n            case 1: return new C(a);\n            case 2: return new C(a, b);\n          } return new C(a, b, c);\n        } return C.apply(this, arguments);\n      };\n      F[PROTOTYPE] = C[PROTOTYPE];\n      return F;\n    // make static versions for prototype methods\n    })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out;\n    // export proto methods to core.%CONSTRUCTOR%.methods.%NAME%\n    if (IS_PROTO) {\n      (exports.virtual || (exports.virtual = {}))[key] = out;\n      // export proto methods to core.%CONSTRUCTOR%.prototype.%NAME%\n      if (type & $export.R && expProto && !expProto[key]) hide(expProto, key, out);\n    }\n  }\n};\n// type bitmap\n$export.F = 1;   // forced\n$export.G = 2;   // global\n$export.S = 4;   // static\n$export.P = 8;   // proto\n$export.B = 16;  // bind\n$export.W = 32;  // wrap\n$export.U = 64;  // safe\n$export.R = 128; // real proto method for `library`\nmodule.exports = $export;\n\n\n/***/ }),\n/* 4 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar store = __webpack_require__(65)('wks');\nvar uid = __webpack_require__(38);\nvar Symbol = __webpack_require__(10).Symbol;\nvar USE_SYMBOL = typeof Symbol == 'function';\n\nvar $exports = module.exports = function (name) {\n  return store[name] || (store[name] =\n    USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name));\n};\n\n$exports.store = store;\n\n\n/***/ }),\n/* 5 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Thank's IE8 for his funny defineProperty\nmodule.exports = !__webpack_require__(19)(function () {\n  return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a != 7;\n});\n\n\n/***/ }),\n/* 6 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar anObject = __webpack_require__(14);\nvar IE8_DOM_DEFINE = __webpack_require__(95);\nvar toPrimitive = __webpack_require__(58);\nvar dP = Object.defineProperty;\n\nexports.f = __webpack_require__(5) ? Object.defineProperty : function defineProperty(O, P, Attributes) {\n  anObject(O);\n  P = toPrimitive(P, true);\n  anObject(Attributes);\n  if (IE8_DOM_DEFINE) try {\n    return dP(O, P, Attributes);\n  } catch (e) { /* empty */ }\n  if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported!');\n  if ('value' in Attributes) O[P] = Attributes.value;\n  return O;\n};\n\n\n/***/ }),\n/* 7 */\n/***/ (function(module, exports) {\n\nvar g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || Function(\"return this\")() || (1,eval)(\"this\");\n} catch(e) {\n\t// This works if the window reference is available\n\tif(typeof window === \"object\")\n\t\tg = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n\n\n/***/ }),\n/* 8 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(Buffer, __dirname) {\n\nfunction VirtualFileSystem() {\n\tthis.fileSystem = {};\n\tthis.baseSystem = {};\n}\n\nVirtualFileSystem.prototype.readFileSync = function (filename) {\n\tfilename = fixFilename(filename);\n\n\tvar base64content = this.baseSystem[filename];\n\tif (base64content) {\n\t\treturn new Buffer(base64content, 'base64');\n\t}\n\n\tvar content = this.fileSystem[filename];\n\tif (content) {\n\t\treturn content;\n\t}\n\n\tthrow 'File \\'' + filename + '\\' not found in virtual file system';\n};\n\nVirtualFileSystem.prototype.writeFileSync = function (filename, content) {\n\tthis.fileSystem[fixFilename(filename)] = content;\n};\n\nVirtualFileSystem.prototype.bindFS = function (data) {\n\tthis.baseSystem = data || {};\n};\n\n\nfunction fixFilename(filename) {\n\tif (filename.indexOf(__dirname) === 0) {\n\t\tfilename = filename.substring(__dirname.length);\n\t}\n\n\tif (filename.indexOf('/') === 0) {\n\t\tfilename = filename.substring(1);\n\t}\n\n\treturn filename;\n}\n\nmodule.exports = new VirtualFileSystem();\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer, \"/\"))\n\n/***/ }),\n/* 9 */\n/***/ (function(module, exports) {\n\nmodule.exports = function (it) {\n  return typeof it === 'object' ? it !== null : typeof it === 'function';\n};\n\n\n/***/ }),\n/* 10 */\n/***/ (function(module, exports) {\n\n// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028\nvar global = module.exports = typeof window != 'undefined' && window.Math == Math\n  ? window : typeof self != 'undefined' && self.Math == Math ? self\n  // eslint-disable-next-line no-new-func\n  : Function('return this')();\nif (typeof __g == 'number') __g = global; // eslint-disable-line no-undef\n\n\n/***/ }),\n/* 11 */\n/***/ (function(module, exports) {\n\n// shim for using process in browser\nvar process = module.exports = {};\n\n// cached from whatever global is present so that test runners that stub it\n// don't break things.  But we need to wrap it in a try catch in case it is\n// wrapped in strict mode code which doesn't define any globals.  It's inside a\n// function because try/catches deoptimize in certain engines.\n\nvar cachedSetTimeout;\nvar cachedClearTimeout;\n\nfunction defaultSetTimout() {\n    throw new Error('setTimeout has not been defined');\n}\nfunction defaultClearTimeout () {\n    throw new Error('clearTimeout has not been defined');\n}\n(function () {\n    try {\n        if (typeof setTimeout === 'function') {\n            cachedSetTimeout = setTimeout;\n        } else {\n            cachedSetTimeout = defaultSetTimout;\n        }\n    } catch (e) {\n        cachedSetTimeout = defaultSetTimout;\n    }\n    try {\n        if (typeof clearTimeout === 'function') {\n            cachedClearTimeout = clearTimeout;\n        } else {\n            cachedClearTimeout = defaultClearTimeout;\n        }\n    } catch (e) {\n        cachedClearTimeout = defaultClearTimeout;\n    }\n} ())\nfunction runTimeout(fun) {\n    if (cachedSetTimeout === setTimeout) {\n        //normal enviroments in sane situations\n        return setTimeout(fun, 0);\n    }\n    // if setTimeout wasn't available but was latter defined\n    if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\n        cachedSetTimeout = setTimeout;\n        return setTimeout(fun, 0);\n    }\n    try {\n        // when when somebody has screwed with setTimeout but no I.E. maddness\n        return cachedSetTimeout(fun, 0);\n    } catch(e){\n        try {\n            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n            return cachedSetTimeout.call(null, fun, 0);\n        } catch(e){\n            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n            return cachedSetTimeout.call(this, fun, 0);\n        }\n    }\n\n\n}\nfunction runClearTimeout(marker) {\n    if (cachedClearTimeout === clearTimeout) {\n        //normal enviroments in sane situations\n        return clearTimeout(marker);\n    }\n    // if clearTimeout wasn't available but was latter defined\n    if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\n        cachedClearTimeout = clearTimeout;\n        return clearTimeout(marker);\n    }\n    try {\n        // when when somebody has screwed with setTimeout but no I.E. maddness\n        return cachedClearTimeout(marker);\n    } catch (e){\n        try {\n            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally\n            return cachedClearTimeout.call(null, marker);\n        } catch (e){\n            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n            // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n            return cachedClearTimeout.call(this, marker);\n        }\n    }\n\n\n\n}\nvar queue = [];\nvar draining = false;\nvar currentQueue;\nvar queueIndex = -1;\n\nfunction cleanUpNextTick() {\n    if (!draining || !currentQueue) {\n        return;\n    }\n    draining = false;\n    if (currentQueue.length) {\n        queue = currentQueue.concat(queue);\n    } else {\n        queueIndex = -1;\n    }\n    if (queue.length) {\n        drainQueue();\n    }\n}\n\nfunction drainQueue() {\n    if (draining) {\n        return;\n    }\n    var timeout = runTimeout(cleanUpNextTick);\n    draining = true;\n\n    var len = queue.length;\n    while(len) {\n        currentQueue = queue;\n        queue = [];\n        while (++queueIndex < len) {\n            if (currentQueue) {\n                currentQueue[queueIndex].run();\n            }\n        }\n        queueIndex = -1;\n        len = queue.length;\n    }\n    currentQueue = null;\n    draining = false;\n    runClearTimeout(timeout);\n}\n\nprocess.nextTick = function (fun) {\n    var args = new Array(arguments.length - 1);\n    if (arguments.length > 1) {\n        for (var i = 1; i < arguments.length; i++) {\n            args[i - 1] = arguments[i];\n        }\n    }\n    queue.push(new Item(fun, args));\n    if (queue.length === 1 && !draining) {\n        runTimeout(drainQueue);\n    }\n};\n\n// v8 likes predictible objects\nfunction Item(fun, array) {\n    this.fun = fun;\n    this.array = array;\n}\nItem.prototype.run = function () {\n    this.fun.apply(null, this.array);\n};\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\nprocess.version = ''; // empty string to avoid regexp issues\nprocess.versions = {};\n\nfunction noop() {}\n\nprocess.on = noop;\nprocess.addListener = noop;\nprocess.once = noop;\nprocess.off = noop;\nprocess.removeListener = noop;\nprocess.removeAllListeners = noop;\nprocess.emit = noop;\nprocess.prependListener = noop;\nprocess.prependOnceListener = noop;\n\nprocess.listeners = function (name) { return [] }\n\nprocess.binding = function (name) {\n    throw new Error('process.binding is not supported');\n};\n\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n    throw new Error('process.chdir is not supported');\n};\nprocess.umask = function() { return 0; };\n\n\n/***/ }),\n/* 12 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var NumberT, PropertyDescriptor;\n\n  NumberT = __webpack_require__(22).Number;\n\n  exports.resolveLength = function(length, stream, parent) {\n    var res;\n    if (typeof length === 'number') {\n      res = length;\n    } else if (typeof length === 'function') {\n      res = length.call(parent, parent);\n    } else if (parent && typeof length === 'string') {\n      res = parent[length];\n    } else if (stream && length instanceof NumberT) {\n      res = length.decode(stream);\n    }\n    if (isNaN(res)) {\n      throw new Error('Not a fixed size');\n    }\n    return res;\n  };\n\n  PropertyDescriptor = (function() {\n    function PropertyDescriptor(opts) {\n      var key, val;\n      if (opts == null) {\n        opts = {};\n      }\n      this.enumerable = true;\n      this.configurable = true;\n      for (key in opts) {\n        val = opts[key];\n        this[key] = val;\n      }\n    }\n\n    return PropertyDescriptor;\n\n  })();\n\n  exports.PropertyDescriptor = PropertyDescriptor;\n\n}).call(this);\n\n\n/***/ }),\n/* 13 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar dP = __webpack_require__(6);\nvar createDesc = __webpack_require__(27);\nmodule.exports = __webpack_require__(5) ? function (object, key, value) {\n  return dP.f(object, key, createDesc(1, value));\n} : function (object, key, value) {\n  object[key] = value;\n  return object;\n};\n\n\n/***/ }),\n/* 14 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar isObject = __webpack_require__(9);\nmodule.exports = function (it) {\n  if (!isObject(it)) throw TypeError(it + ' is not an object!');\n  return it;\n};\n\n\n/***/ }),\n/* 15 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nmodule.exports = Stream;\n\nvar EE = __webpack_require__(31).EventEmitter;\nvar inherits = __webpack_require__(21);\n\ninherits(Stream, EE);\nStream.Readable = __webpack_require__(45);\nStream.Writable = __webpack_require__(146);\nStream.Duplex = __webpack_require__(147);\nStream.Transform = __webpack_require__(148);\nStream.PassThrough = __webpack_require__(149);\n\n// Backwards-compat with node 0.4.x\nStream.Stream = Stream;\n\n\n\n// old-style streams.  Note that the pipe method (the only relevant\n// part of this class) is overridden in the Readable class.\n\nfunction Stream() {\n  EE.call(this);\n}\n\nStream.prototype.pipe = function(dest, options) {\n  var source = this;\n\n  function ondata(chunk) {\n    if (dest.writable) {\n      if (false === dest.write(chunk) && source.pause) {\n        source.pause();\n      }\n    }\n  }\n\n  source.on('data', ondata);\n\n  function ondrain() {\n    if (source.readable && source.resume) {\n      source.resume();\n    }\n  }\n\n  dest.on('drain', ondrain);\n\n  // If the 'end' option is not supplied, dest.end() will be called when\n  // source gets the 'end' or 'close' events.  Only dest.end() once.\n  if (!dest._isStdio && (!options || options.end !== false)) {\n    source.on('end', onend);\n    source.on('close', onclose);\n  }\n\n  var didOnEnd = false;\n  function onend() {\n    if (didOnEnd) return;\n    didOnEnd = true;\n\n    dest.end();\n  }\n\n\n  function onclose() {\n    if (didOnEnd) return;\n    didOnEnd = true;\n\n    if (typeof dest.destroy === 'function') dest.destroy();\n  }\n\n  // don't leave dangling pipes when there are errors.\n  function onerror(er) {\n    cleanup();\n    if (EE.listenerCount(this, 'error') === 0) {\n      throw er; // Unhandled stream error in pipe.\n    }\n  }\n\n  source.on('error', onerror);\n  dest.on('error', onerror);\n\n  // remove all the event listeners that were added.\n  function cleanup() {\n    source.removeListener('data', ondata);\n    dest.removeListener('drain', ondrain);\n\n    source.removeListener('end', onend);\n    source.removeListener('close', onclose);\n\n    source.removeListener('error', onerror);\n    dest.removeListener('error', onerror);\n\n    source.removeListener('end', cleanup);\n    source.removeListener('close', cleanup);\n\n    dest.removeListener('close', cleanup);\n  }\n\n  source.on('end', cleanup);\n  source.on('close', cleanup);\n\n  dest.on('close', cleanup);\n\n  dest.emit('pipe', source);\n\n  // Allow for unix-like usage: A.pipe(B).pipe(C)\n  return dest;\n};\n\n\n/***/ }),\n/* 16 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// a duplex stream is just a stream that is both readable and writable.\n// Since JS doesn't have multiple prototypal inheritance, this class\n// prototypally inherits from Readable, and then parasitically from\n// Writable.\n\n\n\n/*<replacement>*/\n\nvar processNextTick = __webpack_require__(32).nextTick;\n/*</replacement>*/\n\n/*<replacement>*/\nvar objectKeys = Object.keys || function (obj) {\n  var keys = [];\n  for (var key in obj) {\n    keys.push(key);\n  }return keys;\n};\n/*</replacement>*/\n\nmodule.exports = Duplex;\n\n/*<replacement>*/\nvar util = __webpack_require__(25);\nutil.inherits = __webpack_require__(21);\n/*</replacement>*/\n\nvar Readable = __webpack_require__(83);\nvar Writable = __webpack_require__(46);\n\nutil.inherits(Duplex, Readable);\n\nvar keys = objectKeys(Writable.prototype);\nfor (var v = 0; v < keys.length; v++) {\n  var method = keys[v];\n  if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];\n}\n\nfunction Duplex(options) {\n  if (!(this instanceof Duplex)) return new Duplex(options);\n\n  Readable.call(this, options);\n  Writable.call(this, options);\n\n  if (options && options.readable === false) this.readable = false;\n\n  if (options && options.writable === false) this.writable = false;\n\n  this.allowHalfOpen = true;\n  if (options && options.allowHalfOpen === false) this.allowHalfOpen = false;\n\n  this.once('end', onend);\n}\n\n// the no-half-open enforcer\nfunction onend() {\n  // if we allow half-open state, or if the writable side ended,\n  // then we're ok.\n  if (this.allowHalfOpen || this._writableState.ended) return;\n\n  // no more data can be written.\n  // But allow more writes to happen in this tick.\n  processNextTick(onEndNT, this);\n}\n\nfunction onEndNT(self) {\n  self.end();\n}\n\nObject.defineProperty(Duplex.prototype, 'destroyed', {\n  get: function () {\n    if (this._readableState === undefined || this._writableState === undefined) {\n      return false;\n    }\n    return this._readableState.destroyed && this._writableState.destroyed;\n  },\n  set: function (value) {\n    // we ignore the value if the stream\n    // has not been initialized yet\n    if (this._readableState === undefined || this._writableState === undefined) {\n      return;\n    }\n\n    // backward compatibility, the user is explicitly\n    // managing destroyed\n    this._readableState.destroyed = value;\n    this._writableState.destroyed = value;\n  }\n});\n\nDuplex.prototype._destroy = function (err, cb) {\n  this.push(null);\n  this.end();\n\n  processNextTick(cb, err);\n};\n\nfunction forEach(xs, f) {\n  for (var i = 0, l = xs.length; i < l; i++) {\n    f(xs[i], i);\n  }\n}\n\n/***/ }),\n/* 17 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// to indexed object, toObject with fallback for non-array-like ES3 strings\nvar IObject = __webpack_require__(54);\nvar defined = __webpack_require__(56);\nmodule.exports = function (it) {\n  return IObject(defined(it));\n};\n\n\n/***/ }),\n/* 18 */\n/***/ (function(module, exports) {\n\nvar hasOwnProperty = {}.hasOwnProperty;\nmodule.exports = function (it, key) {\n  return hasOwnProperty.call(it, key);\n};\n\n\n/***/ }),\n/* 19 */\n/***/ (function(module, exports) {\n\nmodule.exports = function (exec) {\n  try {\n    return !!exec();\n  } catch (e) {\n    return true;\n  }\n};\n\n\n/***/ }),\n/* 20 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// optional / simple context binding\nvar aFunction = __webpack_require__(97);\nmodule.exports = function (fn, that, length) {\n  aFunction(fn);\n  if (that === undefined) return fn;\n  switch (length) {\n    case 1: return function (a) {\n      return fn.call(that, a);\n    };\n    case 2: return function (a, b) {\n      return fn.call(that, a, b);\n    };\n    case 3: return function (a, b, c) {\n      return fn.call(that, a, b, c);\n    };\n  }\n  return function (/* ...args */) {\n    return fn.apply(that, arguments);\n  };\n};\n\n\n/***/ }),\n/* 21 */\n/***/ (function(module, exports) {\n\nif (typeof Object.create === 'function') {\n  // implementation from standard node.js 'util' module\n  module.exports = function inherits(ctor, superCtor) {\n    ctor.super_ = superCtor\n    ctor.prototype = Object.create(superCtor.prototype, {\n      constructor: {\n        value: ctor,\n        enumerable: false,\n        writable: true,\n        configurable: true\n      }\n    });\n  };\n} else {\n  // old school shim for old browsers\n  module.exports = function inherits(ctor, superCtor) {\n    ctor.super_ = superCtor\n    var TempCtor = function () {}\n    TempCtor.prototype = superCtor.prototype\n    ctor.prototype = new TempCtor()\n    ctor.prototype.constructor = ctor\n  }\n}\n\n\n/***/ }),\n/* 22 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var DecodeStream, Fixed, NumberT,\n    __hasProp = {}.hasOwnProperty,\n    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n  DecodeStream = __webpack_require__(51);\n\n  NumberT = (function() {\n    function NumberT(type, endian) {\n      this.type = type;\n      this.endian = endian != null ? endian : 'BE';\n      this.fn = this.type;\n      if (this.type[this.type.length - 1] !== '8') {\n        this.fn += this.endian;\n      }\n    }\n\n    NumberT.prototype.size = function() {\n      return DecodeStream.TYPES[this.type];\n    };\n\n    NumberT.prototype.decode = function(stream) {\n      return stream['read' + this.fn]();\n    };\n\n    NumberT.prototype.encode = function(stream, val) {\n      return stream['write' + this.fn](val);\n    };\n\n    return NumberT;\n\n  })();\n\n  exports.Number = NumberT;\n\n  exports.uint8 = new NumberT('UInt8');\n\n  exports.uint16be = exports.uint16 = new NumberT('UInt16', 'BE');\n\n  exports.uint16le = new NumberT('UInt16', 'LE');\n\n  exports.uint24be = exports.uint24 = new NumberT('UInt24', 'BE');\n\n  exports.uint24le = new NumberT('UInt24', 'LE');\n\n  exports.uint32be = exports.uint32 = new NumberT('UInt32', 'BE');\n\n  exports.uint32le = new NumberT('UInt32', 'LE');\n\n  exports.int8 = new NumberT('Int8');\n\n  exports.int16be = exports.int16 = new NumberT('Int16', 'BE');\n\n  exports.int16le = new NumberT('Int16', 'LE');\n\n  exports.int24be = exports.int24 = new NumberT('Int24', 'BE');\n\n  exports.int24le = new NumberT('Int24', 'LE');\n\n  exports.int32be = exports.int32 = new NumberT('Int32', 'BE');\n\n  exports.int32le = new NumberT('Int32', 'LE');\n\n  exports.floatbe = exports.float = new NumberT('Float', 'BE');\n\n  exports.floatle = new NumberT('Float', 'LE');\n\n  exports.doublebe = exports.double = new NumberT('Double', 'BE');\n\n  exports.doublele = new NumberT('Double', 'LE');\n\n  Fixed = (function(_super) {\n    __extends(Fixed, _super);\n\n    function Fixed(size, endian, fracBits) {\n      if (fracBits == null) {\n        fracBits = size >> 1;\n      }\n      Fixed.__super__.constructor.call(this, \"Int\" + size, endian);\n      this._point = 1 << fracBits;\n    }\n\n    Fixed.prototype.decode = function(stream) {\n      return Fixed.__super__.decode.call(this, stream) / this._point;\n    };\n\n    Fixed.prototype.encode = function(stream, val) {\n      return Fixed.__super__.encode.call(this, stream, val * this._point | 0);\n    };\n\n    return Fixed;\n\n  })(NumberT);\n\n  exports.Fixed = Fixed;\n\n  exports.fixed16be = exports.fixed16 = new Fixed(16, 'BE');\n\n  exports.fixed16le = new Fixed(16, 'LE');\n\n  exports.fixed32be = exports.fixed32 = new Fixed(32, 'BE');\n\n  exports.fixed32le = new Fixed(32, 'LE');\n\n}).call(this);\n\n\n/***/ }),\n/* 23 */\n/***/ (function(module, exports) {\n\nmodule.exports = {};\n\n\n/***/ }),\n/* 24 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar $at = __webpack_require__(207)(true);\n\n// 21.1.3.27 String.prototype[@@iterator]()\n__webpack_require__(61)(String, 'String', function (iterated) {\n  this._t = String(iterated); // target\n  this._i = 0;                // next index\n// 21.1.5.2.1 %StringIteratorPrototype%.next()\n}, function () {\n  var O = this._t;\n  var index = this._i;\n  var point;\n  if (index >= O.length) return { value: undefined, done: true };\n  point = $at(O, index);\n  this._i += point.length;\n  return { value: point, done: false };\n});\n\n\n/***/ }),\n/* 25 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// NOTE: These type checking functions intentionally don't use `instanceof`\n// because it is fragile and can be easily faked with `Object.create()`.\n\nfunction isArray(arg) {\n  if (Array.isArray) {\n    return Array.isArray(arg);\n  }\n  return objectToString(arg) === '[object Array]';\n}\nexports.isArray = isArray;\n\nfunction isBoolean(arg) {\n  return typeof arg === 'boolean';\n}\nexports.isBoolean = isBoolean;\n\nfunction isNull(arg) {\n  return arg === null;\n}\nexports.isNull = isNull;\n\nfunction isNullOrUndefined(arg) {\n  return arg == null;\n}\nexports.isNullOrUndefined = isNullOrUndefined;\n\nfunction isNumber(arg) {\n  return typeof arg === 'number';\n}\nexports.isNumber = isNumber;\n\nfunction isString(arg) {\n  return typeof arg === 'string';\n}\nexports.isString = isString;\n\nfunction isSymbol(arg) {\n  return typeof arg === 'symbol';\n}\nexports.isSymbol = isSymbol;\n\nfunction isUndefined(arg) {\n  return arg === void 0;\n}\nexports.isUndefined = isUndefined;\n\nfunction isRegExp(re) {\n  return objectToString(re) === '[object RegExp]';\n}\nexports.isRegExp = isRegExp;\n\nfunction isObject(arg) {\n  return typeof arg === 'object' && arg !== null;\n}\nexports.isObject = isObject;\n\nfunction isDate(d) {\n  return objectToString(d) === '[object Date]';\n}\nexports.isDate = isDate;\n\nfunction isError(e) {\n  return (objectToString(e) === '[object Error]' || e instanceof Error);\n}\nexports.isError = isError;\n\nfunction isFunction(arg) {\n  return typeof arg === 'function';\n}\nexports.isFunction = isFunction;\n\nfunction isPrimitive(arg) {\n  return arg === null ||\n         typeof arg === 'boolean' ||\n         typeof arg === 'number' ||\n         typeof arg === 'string' ||\n         typeof arg === 'symbol' ||  // ES6 symbol\n         typeof arg === 'undefined';\n}\nexports.isPrimitive = isPrimitive;\n\nexports.isBuffer = Buffer.isBuffer;\n\nfunction objectToString(o) {\n  return Object.prototype.toString.call(o);\n}\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 26 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6\n\n/*\nPDFObject - converts JavaScript types into their corrisponding PDF types.\nBy Devon Govett\n */\n\n(function() {\n  var PDFObject, PDFReference;\n\n  PDFObject = (function() {\n    var escapable, escapableRe, pad, swapBytes;\n\n    function PDFObject() {}\n\n    pad = function(str, length) {\n      return (Array(length + 1).join('0') + str).slice(-length);\n    };\n\n    escapableRe = /[\\n\\r\\t\\b\\f\\(\\)\\\\]/g;\n\n    escapable = {\n      '\\n': '\\\\n',\n      '\\r': '\\\\r',\n      '\\t': '\\\\t',\n      '\\b': '\\\\b',\n      '\\f': '\\\\f',\n      '\\\\': '\\\\\\\\',\n      '(': '\\\\(',\n      ')': '\\\\)'\n    };\n\n    swapBytes = function(buff) {\n      var a, i, j, l, ref;\n      l = buff.length;\n      if (l & 0x01) {\n        throw new Error(\"Buffer length must be even\");\n      } else {\n        for (i = j = 0, ref = l - 1; j < ref; i = j += 2) {\n          a = buff[i];\n          buff[i] = buff[i + 1];\n          buff[i + 1] = a;\n        }\n      }\n      return buff;\n    };\n\n    PDFObject.convert = function(object) {\n      var e, i, isUnicode, items, j, key, out, ref, string, val;\n      if (typeof object === 'string') {\n        return '/' + object;\n      } else if (object instanceof String) {\n        string = object;\n        isUnicode = false;\n        for (i = j = 0, ref = string.length; j < ref; i = j += 1) {\n          if (string.charCodeAt(i) > 0x7f) {\n            isUnicode = true;\n            break;\n          }\n        }\n        if (isUnicode) {\n          string = swapBytes(new Buffer('\\ufeff' + string, 'utf16le')).toString('binary');\n        }\n        string = string.replace(escapableRe, function(c) {\n          return escapable[c];\n        });\n        return '(' + string + ')';\n      } else if (Buffer.isBuffer(object)) {\n        return '<' + object.toString('hex') + '>';\n      } else if (object instanceof PDFReference) {\n        return object.toString();\n      } else if (object instanceof Date) {\n        return '(D:' + pad(object.getUTCFullYear(), 4) + pad(object.getUTCMonth() + 1, 2) + pad(object.getUTCDate(), 2) + pad(object.getUTCHours(), 2) + pad(object.getUTCMinutes(), 2) + pad(object.getUTCSeconds(), 2) + 'Z)';\n      } else if (Array.isArray(object)) {\n        items = ((function() {\n          var k, len, results;\n          results = [];\n          for (k = 0, len = object.length; k < len; k++) {\n            e = object[k];\n            results.push(PDFObject.convert(e));\n          }\n          return results;\n        })()).join(' ');\n        return '[' + items + ']';\n      } else if ({}.toString.call(object) === '[object Object]') {\n        out = ['<<'];\n        for (key in object) {\n          val = object[key];\n          out.push('/' + key + ' ' + PDFObject.convert(val));\n        }\n        out.push('>>');\n        return out.join('\\n');\n      } else if (typeof object === 'number') {\n        return PDFObject.number(object);\n      } else {\n        return '' + object;\n      }\n    };\n\n    PDFObject.number = function(n) {\n      if (n > -1e21 && n < 1e21) {\n        return Math.round(n * 1e6) / 1e6;\n      }\n      throw new Error(\"unsupported number: \" + n);\n    };\n\n    return PDFObject;\n\n  })();\n\n  module.exports = PDFObject;\n\n  PDFReference = __webpack_require__(87);\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 27 */\n/***/ (function(module, exports) {\n\nmodule.exports = function (bitmap, value) {\n  return {\n    enumerable: !(bitmap & 1),\n    configurable: !(bitmap & 2),\n    writable: !(bitmap & 4),\n    value: value\n  };\n};\n\n\n/***/ }),\n/* 28 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(201);\nvar global = __webpack_require__(10);\nvar hide = __webpack_require__(13);\nvar Iterators = __webpack_require__(23);\nvar TO_STRING_TAG = __webpack_require__(4)('toStringTag');\n\nvar DOMIterables = ('CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,' +\n  'DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,' +\n  'MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,' +\n  'SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,' +\n  'TextTrackList,TouchList').split(',');\n\nfor (var i = 0; i < DOMIterables.length; i++) {\n  var NAME = DOMIterables[i];\n  var Collection = global[NAME];\n  var proto = Collection && Collection.prototype;\n  if (proto && !proto[TO_STRING_TAG]) hide(proto, TO_STRING_TAG, NAME);\n  Iterators[NAME] = Iterators.Array;\n}\n\n\n/***/ }),\n/* 29 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.2.14 / 15.2.3.14 Object.keys(O)\nvar $keys = __webpack_require__(101);\nvar enumBugKeys = __webpack_require__(66);\n\nmodule.exports = Object.keys || function keys(O) {\n  return $keys(O, enumBugKeys);\n};\n\n\n/***/ }),\n/* 30 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 7.1.13 ToObject(argument)\nvar defined = __webpack_require__(56);\nmodule.exports = function (it) {\n  return Object(defined(it));\n};\n\n\n/***/ }),\n/* 31 */\n/***/ (function(module, exports) {\n\n// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nfunction EventEmitter() {\n  this._events = this._events || {};\n  this._maxListeners = this._maxListeners || undefined;\n}\nmodule.exports = EventEmitter;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nEventEmitter.defaultMaxListeners = 10;\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function(n) {\n  if (!isNumber(n) || n < 0 || isNaN(n))\n    throw TypeError('n must be a positive number');\n  this._maxListeners = n;\n  return this;\n};\n\nEventEmitter.prototype.emit = function(type) {\n  var er, handler, len, args, i, listeners;\n\n  if (!this._events)\n    this._events = {};\n\n  // If there is no 'error' event listener then throw.\n  if (type === 'error') {\n    if (!this._events.error ||\n        (isObject(this._events.error) && !this._events.error.length)) {\n      er = arguments[1];\n      if (er instanceof Error) {\n        throw er; // Unhandled 'error' event\n      } else {\n        // At least give some kind of context to the user\n        var err = new Error('Uncaught, unspecified \"error\" event. (' + er + ')');\n        err.context = er;\n        throw err;\n      }\n    }\n  }\n\n  handler = this._events[type];\n\n  if (isUndefined(handler))\n    return false;\n\n  if (isFunction(handler)) {\n    switch (arguments.length) {\n      // fast cases\n      case 1:\n        handler.call(this);\n        break;\n      case 2:\n        handler.call(this, arguments[1]);\n        break;\n      case 3:\n        handler.call(this, arguments[1], arguments[2]);\n        break;\n      // slower\n      default:\n        args = Array.prototype.slice.call(arguments, 1);\n        handler.apply(this, args);\n    }\n  } else if (isObject(handler)) {\n    args = Array.prototype.slice.call(arguments, 1);\n    listeners = handler.slice();\n    len = listeners.length;\n    for (i = 0; i < len; i++)\n      listeners[i].apply(this, args);\n  }\n\n  return true;\n};\n\nEventEmitter.prototype.addListener = function(type, listener) {\n  var m;\n\n  if (!isFunction(listener))\n    throw TypeError('listener must be a function');\n\n  if (!this._events)\n    this._events = {};\n\n  // To avoid recursion in the case that type === \"newListener\"! Before\n  // adding it to the listeners, first emit \"newListener\".\n  if (this._events.newListener)\n    this.emit('newListener', type,\n              isFunction(listener.listener) ?\n              listener.listener : listener);\n\n  if (!this._events[type])\n    // Optimize the case of one listener. Don't need the extra array object.\n    this._events[type] = listener;\n  else if (isObject(this._events[type]))\n    // If we've already got an array, just append.\n    this._events[type].push(listener);\n  else\n    // Adding the second element, need to change to array.\n    this._events[type] = [this._events[type], listener];\n\n  // Check for listener leak\n  if (isObject(this._events[type]) && !this._events[type].warned) {\n    if (!isUndefined(this._maxListeners)) {\n      m = this._maxListeners;\n    } else {\n      m = EventEmitter.defaultMaxListeners;\n    }\n\n    if (m && m > 0 && this._events[type].length > m) {\n      this._events[type].warned = true;\n      console.error('(node) warning: possible EventEmitter memory ' +\n                    'leak detected. %d listeners added. ' +\n                    'Use emitter.setMaxListeners() to increase limit.',\n                    this._events[type].length);\n      if (typeof console.trace === 'function') {\n        // not supported in IE 10\n        console.trace();\n      }\n    }\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.once = function(type, listener) {\n  if (!isFunction(listener))\n    throw TypeError('listener must be a function');\n\n  var fired = false;\n\n  function g() {\n    this.removeListener(type, g);\n\n    if (!fired) {\n      fired = true;\n      listener.apply(this, arguments);\n    }\n  }\n\n  g.listener = listener;\n  this.on(type, g);\n\n  return this;\n};\n\n// emits a 'removeListener' event iff the listener was removed\nEventEmitter.prototype.removeListener = function(type, listener) {\n  var list, position, length, i;\n\n  if (!isFunction(listener))\n    throw TypeError('listener must be a function');\n\n  if (!this._events || !this._events[type])\n    return this;\n\n  list = this._events[type];\n  length = list.length;\n  position = -1;\n\n  if (list === listener ||\n      (isFunction(list.listener) && list.listener === listener)) {\n    delete this._events[type];\n    if (this._events.removeListener)\n      this.emit('removeListener', type, listener);\n\n  } else if (isObject(list)) {\n    for (i = length; i-- > 0;) {\n      if (list[i] === listener ||\n          (list[i].listener && list[i].listener === listener)) {\n        position = i;\n        break;\n      }\n    }\n\n    if (position < 0)\n      return this;\n\n    if (list.length === 1) {\n      list.length = 0;\n      delete this._events[type];\n    } else {\n      list.splice(position, 1);\n    }\n\n    if (this._events.removeListener)\n      this.emit('removeListener', type, listener);\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.removeAllListeners = function(type) {\n  var key, listeners;\n\n  if (!this._events)\n    return this;\n\n  // not listening for removeListener, no need to emit\n  if (!this._events.removeListener) {\n    if (arguments.length === 0)\n      this._events = {};\n    else if (this._events[type])\n      delete this._events[type];\n    return this;\n  }\n\n  // emit removeListener for all listeners on all events\n  if (arguments.length === 0) {\n    for (key in this._events) {\n      if (key === 'removeListener') continue;\n      this.removeAllListeners(key);\n    }\n    this.removeAllListeners('removeListener');\n    this._events = {};\n    return this;\n  }\n\n  listeners = this._events[type];\n\n  if (isFunction(listeners)) {\n    this.removeListener(type, listeners);\n  } else if (listeners) {\n    // LIFO order\n    while (listeners.length)\n      this.removeListener(type, listeners[listeners.length - 1]);\n  }\n  delete this._events[type];\n\n  return this;\n};\n\nEventEmitter.prototype.listeners = function(type) {\n  var ret;\n  if (!this._events || !this._events[type])\n    ret = [];\n  else if (isFunction(this._events[type]))\n    ret = [this._events[type]];\n  else\n    ret = this._events[type].slice();\n  return ret;\n};\n\nEventEmitter.prototype.listenerCount = function(type) {\n  if (this._events) {\n    var evlistener = this._events[type];\n\n    if (isFunction(evlistener))\n      return 1;\n    else if (evlistener)\n      return evlistener.length;\n  }\n  return 0;\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n  return emitter.listenerCount(type);\n};\n\nfunction isFunction(arg) {\n  return typeof arg === 'function';\n}\n\nfunction isNumber(arg) {\n  return typeof arg === 'number';\n}\n\nfunction isObject(arg) {\n  return typeof arg === 'object' && arg !== null;\n}\n\nfunction isUndefined(arg) {\n  return arg === void 0;\n}\n\n\n/***/ }),\n/* 32 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(process) {\n\nif (!process.version ||\n    process.version.indexOf('v0.') === 0 ||\n    process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) {\n  module.exports = { nextTick: nextTick };\n} else {\n  module.exports = process\n}\n\nfunction nextTick(fn, arg1, arg2, arg3) {\n  if (typeof fn !== 'function') {\n    throw new TypeError('\"callback\" argument must be a function');\n  }\n  var len = arguments.length;\n  var args, i;\n  switch (len) {\n  case 0:\n  case 1:\n    return process.nextTick(fn);\n  case 2:\n    return process.nextTick(function afterTickOne() {\n      fn.call(null, arg1);\n    });\n  case 3:\n    return process.nextTick(function afterTickTwo() {\n      fn.call(null, arg1, arg2);\n    });\n  case 4:\n    return process.nextTick(function afterTickThree() {\n      fn.call(null, arg1, arg2, arg3);\n    });\n  default:\n    args = new Array(len - 1);\n    i = 0;\n    while (i < args.length) {\n      args[i++] = arguments[i];\n    }\n    return process.nextTick(function afterTick() {\n      fn.apply(null, args);\n    });\n  }\n}\n\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11)))\n\n/***/ }),\n/* 33 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* eslint-disable node/no-deprecated-api */\nvar buffer = __webpack_require__(1)\nvar Buffer = buffer.Buffer\n\n// alternative to using Object.keys for old browsers\nfunction copyProps (src, dst) {\n  for (var key in src) {\n    dst[key] = src[key]\n  }\n}\nif (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {\n  module.exports = buffer\n} else {\n  // Copy properties from require('buffer')\n  copyProps(buffer, exports)\n  exports.Buffer = SafeBuffer\n}\n\nfunction SafeBuffer (arg, encodingOrOffset, length) {\n  return Buffer(arg, encodingOrOffset, length)\n}\n\n// Copy static methods from Buffer\ncopyProps(Buffer, SafeBuffer)\n\nSafeBuffer.from = function (arg, encodingOrOffset, length) {\n  if (typeof arg === 'number') {\n    throw new TypeError('Argument must not be a number')\n  }\n  return Buffer(arg, encodingOrOffset, length)\n}\n\nSafeBuffer.alloc = function (size, fill, encoding) {\n  if (typeof size !== 'number') {\n    throw new TypeError('Argument must be a number')\n  }\n  var buf = Buffer(size)\n  if (fill !== undefined) {\n    if (typeof encoding === 'string') {\n      buf.fill(fill, encoding)\n    } else {\n      buf.fill(fill)\n    }\n  } else {\n    buf.fill(0)\n  }\n  return buf\n}\n\nSafeBuffer.allocUnsafe = function (size) {\n  if (typeof size !== 'number') {\n    throw new TypeError('Argument must be a number')\n  }\n  return Buffer(size)\n}\n\nSafeBuffer.allocUnsafeSlow = function (size) {\n  if (typeof size !== 'number') {\n    throw new TypeError('Argument must be a number')\n  }\n  return buffer.SlowBuffer(size)\n}\n\n\n/***/ }),\n/* 34 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n\nvar TYPED_OK =  (typeof Uint8Array !== 'undefined') &&\n                (typeof Uint16Array !== 'undefined') &&\n                (typeof Int32Array !== 'undefined');\n\nfunction _has(obj, key) {\n  return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\nexports.assign = function (obj /*from1, from2, from3, ...*/) {\n  var sources = Array.prototype.slice.call(arguments, 1);\n  while (sources.length) {\n    var source = sources.shift();\n    if (!source) { continue; }\n\n    if (typeof source !== 'object') {\n      throw new TypeError(source + 'must be non-object');\n    }\n\n    for (var p in source) {\n      if (_has(source, p)) {\n        obj[p] = source[p];\n      }\n    }\n  }\n\n  return obj;\n};\n\n\n// reduce buffer size, avoiding mem copy\nexports.shrinkBuf = function (buf, size) {\n  if (buf.length === size) { return buf; }\n  if (buf.subarray) { return buf.subarray(0, size); }\n  buf.length = size;\n  return buf;\n};\n\n\nvar fnTyped = {\n  arraySet: function (dest, src, src_offs, len, dest_offs) {\n    if (src.subarray && dest.subarray) {\n      dest.set(src.subarray(src_offs, src_offs + len), dest_offs);\n      return;\n    }\n    // Fallback to ordinary array\n    for (var i = 0; i < len; i++) {\n      dest[dest_offs + i] = src[src_offs + i];\n    }\n  },\n  // Join array of chunks to single array.\n  flattenChunks: function (chunks) {\n    var i, l, len, pos, chunk, result;\n\n    // calculate data length\n    len = 0;\n    for (i = 0, l = chunks.length; i < l; i++) {\n      len += chunks[i].length;\n    }\n\n    // join chunks\n    result = new Uint8Array(len);\n    pos = 0;\n    for (i = 0, l = chunks.length; i < l; i++) {\n      chunk = chunks[i];\n      result.set(chunk, pos);\n      pos += chunk.length;\n    }\n\n    return result;\n  }\n};\n\nvar fnUntyped = {\n  arraySet: function (dest, src, src_offs, len, dest_offs) {\n    for (var i = 0; i < len; i++) {\n      dest[dest_offs + i] = src[src_offs + i];\n    }\n  },\n  // Join array of chunks to single array.\n  flattenChunks: function (chunks) {\n    return [].concat.apply([], chunks);\n  }\n};\n\n\n// Enable/Disable typed arrays use, for testing\n//\nexports.setTyped = function (on) {\n  if (on) {\n    exports.Buf8  = Uint8Array;\n    exports.Buf16 = Uint16Array;\n    exports.Buf32 = Int32Array;\n    exports.assign(exports, fnTyped);\n  } else {\n    exports.Buf8  = Array;\n    exports.Buf16 = Array;\n    exports.Buf32 = Array;\n    exports.assign(exports, fnUntyped);\n  }\n};\n\nexports.setTyped(TYPED_OK);\n\n\n/***/ }),\n/* 35 */\n/***/ (function(module, exports) {\n\nexports.f = {}.propertyIsEnumerable;\n\n\n/***/ }),\n/* 36 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])\nvar anObject = __webpack_require__(14);\nvar dPs = __webpack_require__(100);\nvar enumBugKeys = __webpack_require__(66);\nvar IE_PROTO = __webpack_require__(64)('IE_PROTO');\nvar Empty = function () { /* empty */ };\nvar PROTOTYPE = 'prototype';\n\n// Create object with fake `null` prototype: use iframe Object with cleared prototype\nvar createDict = function () {\n  // Thrash, waste and sodomy: IE GC bug\n  var iframe = __webpack_require__(96)('iframe');\n  var i = enumBugKeys.length;\n  var lt = '<';\n  var gt = '>';\n  var iframeDocument;\n  iframe.style.display = 'none';\n  __webpack_require__(205).appendChild(iframe);\n  iframe.src = 'javascript:'; // eslint-disable-line no-script-url\n  // createDict = iframe.contentWindow.Object;\n  // html.removeChild(iframe);\n  iframeDocument = iframe.contentWindow.document;\n  iframeDocument.open();\n  iframeDocument.write(lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt);\n  iframeDocument.close();\n  createDict = iframeDocument.F;\n  while (i--) delete createDict[PROTOTYPE][enumBugKeys[i]];\n  return createDict();\n};\n\nmodule.exports = Object.create || function create(O, Properties) {\n  var result;\n  if (O !== null) {\n    Empty[PROTOTYPE] = anObject(O);\n    result = new Empty();\n    Empty[PROTOTYPE] = null;\n    // add \"__proto__\" for Object.getPrototypeOf polyfill\n    result[IE_PROTO] = O;\n  } else result = createDict();\n  return Properties === undefined ? result : dPs(result, Properties);\n};\n\n\n/***/ }),\n/* 37 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 7.1.15 ToLength\nvar toInteger = __webpack_require__(63);\nvar min = Math.min;\nmodule.exports = function (it) {\n  return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991\n};\n\n\n/***/ }),\n/* 38 */\n/***/ (function(module, exports) {\n\nvar id = 0;\nvar px = Math.random();\nmodule.exports = function (key) {\n  return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36));\n};\n\n\n/***/ }),\n/* 39 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar def = __webpack_require__(6).f;\nvar has = __webpack_require__(18);\nvar TAG = __webpack_require__(4)('toStringTag');\n\nmodule.exports = function (it, tag, stat) {\n  if (it && !has(it = stat ? it : it.prototype, TAG)) def(it, TAG, { configurable: true, value: tag });\n};\n\n\n/***/ }),\n/* 40 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar META = __webpack_require__(38)('meta');\nvar isObject = __webpack_require__(9);\nvar has = __webpack_require__(18);\nvar setDesc = __webpack_require__(6).f;\nvar id = 0;\nvar isExtensible = Object.isExtensible || function () {\n  return true;\n};\nvar FREEZE = !__webpack_require__(19)(function () {\n  return isExtensible(Object.preventExtensions({}));\n});\nvar setMeta = function (it) {\n  setDesc(it, META, { value: {\n    i: 'O' + ++id, // object ID\n    w: {}          // weak collections IDs\n  } });\n};\nvar fastKey = function (it, create) {\n  // return primitive with prefix\n  if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;\n  if (!has(it, META)) {\n    // can't set metadata to uncaught frozen object\n    if (!isExtensible(it)) return 'F';\n    // not necessary to add metadata\n    if (!create) return 'E';\n    // add missing metadata\n    setMeta(it);\n  // return object ID\n  } return it[META].i;\n};\nvar getWeak = function (it, create) {\n  if (!has(it, META)) {\n    // can't set metadata to uncaught frozen object\n    if (!isExtensible(it)) return true;\n    // not necessary to add metadata\n    if (!create) return false;\n    // add missing metadata\n    setMeta(it);\n  // return hash weak collections IDs\n  } return it[META].w;\n};\n// add metadata on freeze-family methods calling\nvar onFreeze = function (it) {\n  if (FREEZE && meta.NEED && isExtensible(it) && !has(it, META)) setMeta(it);\n  return it;\n};\nvar meta = module.exports = {\n  KEY: META,\n  NEED: false,\n  fastKey: fastKey,\n  getWeak: getWeak,\n  onFreeze: onFreeze\n};\n\n\n/***/ }),\n/* 41 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar ctx = __webpack_require__(20);\nvar call = __webpack_require__(111);\nvar isArrayIter = __webpack_require__(112);\nvar anObject = __webpack_require__(14);\nvar toLength = __webpack_require__(37);\nvar getIterFn = __webpack_require__(67);\nvar BREAK = {};\nvar RETURN = {};\nvar exports = module.exports = function (iterable, entries, fn, that, ITERATOR) {\n  var iterFn = ITERATOR ? function () { return iterable; } : getIterFn(iterable);\n  var f = ctx(fn, that, entries ? 2 : 1);\n  var index = 0;\n  var length, step, iterator, result;\n  if (typeof iterFn != 'function') throw TypeError(iterable + ' is not iterable!');\n  // fast case for arrays with default iterator\n  if (isArrayIter(iterFn)) for (length = toLength(iterable.length); length > index; index++) {\n    result = entries ? f(anObject(step = iterable[index])[0], step[1]) : f(iterable[index]);\n    if (result === BREAK || result === RETURN) return result;\n  } else for (iterator = iterFn.call(iterable); !(step = iterator.next()).done;) {\n    result = call(iterator, f, step.value, entries);\n    if (result === BREAK || result === RETURN) return result;\n  }\n};\nexports.BREAK = BREAK;\nexports.RETURN = RETURN;\n\n\n/***/ }),\n/* 42 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar isString = __webpack_require__(0).isString;\nvar isNumber = __webpack_require__(0).isNumber;\nvar isObject = __webpack_require__(0).isObject;\nvar isArray = __webpack_require__(0).isArray;\nvar LineBreaker = __webpack_require__(78);\n\nvar LEADING = /^(\\s)+/g;\nvar TRAILING = /(\\s)+$/g;\n\n/**\n * Creates an instance of TextTools - text measurement utility\n *\n * @constructor\n * @param {FontProvider} fontProvider\n */\nfunction TextTools(fontProvider) {\n\tthis.fontProvider = fontProvider;\n}\n\n/**\n * Converts an array of strings (or inline-definition-objects) into a collection\n * of inlines and calculated minWidth/maxWidth.\n * and their min/max widths\n * @param  {Object} textArray - an array of inline-definition-objects (or strings)\n * @param  {Object} styleContextStack current style stack\n * @return {Object}                   collection of inlines, minWidth, maxWidth\n */\nTextTools.prototype.buildInlines = function (textArray, styleContextStack) {\n\tvar measured = measure(this.fontProvider, textArray, styleContextStack);\n\n\tvar minWidth = 0,\n\t\tmaxWidth = 0,\n\t\tcurrentLineWidth;\n\n\tmeasured.forEach(function (inline) {\n\t\tminWidth = Math.max(minWidth, inline.width - inline.leadingCut - inline.trailingCut);\n\n\t\tif (!currentLineWidth) {\n\t\t\tcurrentLineWidth = {width: 0, leadingCut: inline.leadingCut, trailingCut: 0};\n\t\t}\n\n\t\tcurrentLineWidth.width += inline.width;\n\t\tcurrentLineWidth.trailingCut = inline.trailingCut;\n\n\t\tmaxWidth = Math.max(maxWidth, getTrimmedWidth(currentLineWidth));\n\n\t\tif (inline.lineEnd) {\n\t\t\tcurrentLineWidth = null;\n\t\t}\n\t});\n\n\tif (getStyleProperty({}, styleContextStack, 'noWrap', false)) {\n\t\tminWidth = maxWidth;\n\t}\n\n\treturn {\n\t\titems: measured,\n\t\tminWidth: minWidth,\n\t\tmaxWidth: maxWidth\n\t};\n\n\tfunction getTrimmedWidth(item) {\n\t\treturn Math.max(0, item.width - item.leadingCut - item.trailingCut);\n\t}\n};\n\n/**\n * Returns size of the specified string (without breaking it) using the current style\n * @param  {String} text              text to be measured\n * @param  {Object} styleContextStack current style stack\n * @return {Object}                   size of the specified string\n */\nTextTools.prototype.sizeOfString = function (text, styleContextStack) {\n\ttext = text ? text.toString().replace(/\\t/g, '    ') : '';\n\n\t//TODO: refactor - extract from measure\n\tvar fontName = getStyleProperty({}, styleContextStack, 'font', 'Roboto');\n\tvar fontSize = getStyleProperty({}, styleContextStack, 'fontSize', 12);\n\tvar fontFeatures = getStyleProperty({}, styleContextStack, 'fontFeatures', null);\n\tvar bold = getStyleProperty({}, styleContextStack, 'bold', false);\n\tvar italics = getStyleProperty({}, styleContextStack, 'italics', false);\n\tvar lineHeight = getStyleProperty({}, styleContextStack, 'lineHeight', 1);\n\tvar characterSpacing = getStyleProperty({}, styleContextStack, 'characterSpacing', 0);\n\n\tvar font = this.fontProvider.provideFont(fontName, bold, italics);\n\n\treturn {\n\t\twidth: widthOfString(text, font, fontSize, characterSpacing, fontFeatures),\n\t\theight: font.lineHeight(fontSize) * lineHeight,\n\t\tfontSize: fontSize,\n\t\tlineHeight: lineHeight,\n\t\tascender: font.ascender / 1000 * fontSize,\n\t\tdescender: font.descender / 1000 * fontSize\n\t};\n};\n\nTextTools.prototype.widthOfString = function (text, font, fontSize, characterSpacing, fontFeatures) {\n\treturn widthOfString(text, font, fontSize, characterSpacing, fontFeatures);\n};\n\nfunction splitWords(text, noWrap) {\n\tvar results = [];\n\ttext = text.replace(/\\t/g, '    ');\n\n\tif (noWrap) {\n\t\tresults.push({text: text});\n\t\treturn results;\n\t}\n\n\tvar breaker = new LineBreaker(text);\n\tvar last = 0;\n\tvar bk;\n\n\twhile (bk = breaker.nextBreak()) {\n\t\tvar word = text.slice(last, bk.position);\n\n\t\tif (bk.required || word.match(/\\r?\\n$|\\r$/)) { // new line\n\t\t\tword = word.replace(/\\r?\\n$|\\r$/, '');\n\t\t\tresults.push({text: word, lineEnd: true});\n\t\t} else {\n\t\t\tresults.push({text: word});\n\t\t}\n\n\t\tlast = bk.position;\n\t}\n\n\treturn results;\n}\n\nfunction copyStyle(source, destination) {\n\tdestination = destination || {};\n\tsource = source || {}; //TODO: default style\n\n\tfor (var key in source) {\n\t\tif (key != 'text' && source.hasOwnProperty(key)) {\n\t\t\tdestination[key] = source[key];\n\t\t}\n\t}\n\n\treturn destination;\n}\n\nfunction normalizeTextArray(array, styleContextStack) {\n\tfunction flatten(array) {\n\t\treturn array.reduce(function (prev, cur) {\n\t\t\tvar current = isArray(cur.text) ? flatten(cur.text) : cur;\n\t\t\tvar more = [].concat(current).some(Array.isArray);\n\t\t\treturn prev.concat(more ? flatten(current) : current);\n\t\t}, []);\n\t}\n\n\tvar results = [];\n\n\tif (!isArray(array)) {\n\t\tarray = [array];\n\t}\n\n\tarray = flatten(array);\n\n\tfor (var i = 0, l = array.length; i < l; i++) {\n\t\tvar item = array[i];\n\t\tvar style = null;\n\t\tvar words;\n\n\t\tvar noWrap = getStyleProperty(item || {}, styleContextStack, 'noWrap', false);\n\t\tif (isObject(item)) {\n\t\t\twords = splitWords(normalizeString(item.text), noWrap);\n\t\t\tstyle = copyStyle(item);\n\t\t} else {\n\t\t\twords = splitWords(normalizeString(item), noWrap);\n\t\t}\n\n\t\tfor (var i2 = 0, l2 = words.length; i2 < l2; i2++) {\n\t\t\tvar result = {\n\t\t\t\ttext: words[i2].text\n\t\t\t};\n\n\t\t\tif (words[i2].lineEnd) {\n\t\t\t\tresult.lineEnd = true;\n\t\t\t}\n\n\t\t\tcopyStyle(style, result);\n\n\t\t\tresults.push(result);\n\t\t}\n\t}\n\n\treturn results;\n}\n\nfunction normalizeString(value) {\n\tif (value === undefined || value === null) {\n\t\treturn '';\n\t} else if (isNumber(value)) {\n\t\treturn value.toString();\n\t} else if (isString(value)) {\n\t\treturn value;\n\t} else {\n\t\treturn value.toString();\n\t}\n}\n\nfunction getStyleProperty(item, styleContextStack, property, defaultValue) {\n\tvar value;\n\n\tif (item[property] !== undefined && item[property] !== null) {\n\t\t// item defines this property\n\t\treturn item[property];\n\t}\n\n\tif (!styleContextStack) {\n\t\treturn defaultValue;\n\t}\n\n\tstyleContextStack.auto(item, function () {\n\t\tvalue = styleContextStack.getProperty(property);\n\t});\n\n\tif (value !== null && value !== undefined) {\n\t\treturn value;\n\t} else {\n\t\treturn defaultValue;\n\t}\n}\n\nfunction measure(fontProvider, textArray, styleContextStack) {\n\tvar normalized = normalizeTextArray(textArray, styleContextStack);\n\n\tif (normalized.length) {\n\t\tvar leadingIndent = getStyleProperty(normalized[0], styleContextStack, 'leadingIndent', 0);\n\n\t\tif (leadingIndent) {\n\t\t\tnormalized[0].leadingCut = -leadingIndent;\n\t\t\tnormalized[0].leadingIndent = leadingIndent;\n\t\t}\n\t}\n\n\tnormalized.forEach(function (item) {\n\t\tvar fontName = getStyleProperty(item, styleContextStack, 'font', 'Roboto');\n\t\tvar fontSize = getStyleProperty(item, styleContextStack, 'fontSize', 12);\n\t\tvar fontFeatures = getStyleProperty(item, styleContextStack, 'fontFeatures', null);\n\t\tvar bold = getStyleProperty(item, styleContextStack, 'bold', false);\n\t\tvar italics = getStyleProperty(item, styleContextStack, 'italics', false);\n\t\tvar color = getStyleProperty(item, styleContextStack, 'color', 'black');\n\t\tvar decoration = getStyleProperty(item, styleContextStack, 'decoration', null);\n\t\tvar decorationColor = getStyleProperty(item, styleContextStack, 'decorationColor', null);\n\t\tvar decorationStyle = getStyleProperty(item, styleContextStack, 'decorationStyle', null);\n\t\tvar background = getStyleProperty(item, styleContextStack, 'background', null);\n\t\tvar lineHeight = getStyleProperty(item, styleContextStack, 'lineHeight', 1);\n\t\tvar characterSpacing = getStyleProperty(item, styleContextStack, 'characterSpacing', 0);\n\t\tvar link = getStyleProperty(item, styleContextStack, 'link', null);\n\t\tvar linkToPage = getStyleProperty(item, styleContextStack, 'linkToPage', null);\n\t\tvar noWrap = getStyleProperty(item, styleContextStack, 'noWrap', null);\n\t\tvar preserveLeadingSpaces = getStyleProperty(item, styleContextStack, 'preserveLeadingSpaces', false);\n\n\t\tvar font = fontProvider.provideFont(fontName, bold, italics);\n\n\t\titem.width = widthOfString(item.text, font, fontSize, characterSpacing, fontFeatures);\n\t\titem.height = font.lineHeight(fontSize) * lineHeight;\n\n\t\tvar leadingSpaces = item.text.match(LEADING);\n\n\t\tif (!item.leadingCut) {\n\t\t\titem.leadingCut = 0;\n\t\t}\n\n\t\tif (leadingSpaces && !preserveLeadingSpaces) {\n\t\t\titem.leadingCut += widthOfString(leadingSpaces[0], font, fontSize, characterSpacing, fontFeatures);\n\t\t}\n\n\t\tvar trailingSpaces = item.text.match(TRAILING);\n\t\tif (trailingSpaces) {\n\t\t\titem.trailingCut = widthOfString(trailingSpaces[0], font, fontSize, characterSpacing, fontFeatures);\n\t\t} else {\n\t\t\titem.trailingCut = 0;\n\t\t}\n\n\t\titem.alignment = getStyleProperty(item, styleContextStack, 'alignment', 'left');\n\t\titem.font = font;\n\t\titem.fontSize = fontSize;\n\t\titem.fontFeatures = fontFeatures;\n\t\titem.characterSpacing = characterSpacing;\n\t\titem.color = color;\n\t\titem.decoration = decoration;\n\t\titem.decorationColor = decorationColor;\n\t\titem.decorationStyle = decorationStyle;\n\t\titem.background = background;\n\t\titem.link = link;\n\t\titem.linkToPage = linkToPage;\n\t\titem.noWrap = noWrap;\n\t});\n\n\treturn normalized;\n}\n\nfunction widthOfString(text, font, fontSize, characterSpacing, fontFeatures) {\n\treturn font.widthOfString(text, fontSize, fontFeatures) + ((characterSpacing || 0) * (text.length - 1));\n}\n\nmodule.exports = TextTools;\n\n\n/***/ }),\n/* 43 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\nvar UnicodeTrie, inflate;\n\ninflate = __webpack_require__(79);\n\nUnicodeTrie = (function() {\n  var DATA_BLOCK_LENGTH, DATA_GRANULARITY, DATA_MASK, INDEX_1_OFFSET, INDEX_2_BLOCK_LENGTH, INDEX_2_BMP_LENGTH, INDEX_2_MASK, INDEX_SHIFT, LSCP_INDEX_2_LENGTH, LSCP_INDEX_2_OFFSET, OMITTED_BMP_INDEX_1_LENGTH, SHIFT_1, SHIFT_1_2, SHIFT_2, UTF8_2B_INDEX_2_LENGTH, UTF8_2B_INDEX_2_OFFSET;\n\n  SHIFT_1 = 6 + 5;\n\n  SHIFT_2 = 5;\n\n  SHIFT_1_2 = SHIFT_1 - SHIFT_2;\n\n  OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> SHIFT_1;\n\n  INDEX_2_BLOCK_LENGTH = 1 << SHIFT_1_2;\n\n  INDEX_2_MASK = INDEX_2_BLOCK_LENGTH - 1;\n\n  INDEX_SHIFT = 2;\n\n  DATA_BLOCK_LENGTH = 1 << SHIFT_2;\n\n  DATA_MASK = DATA_BLOCK_LENGTH - 1;\n\n  LSCP_INDEX_2_OFFSET = 0x10000 >> SHIFT_2;\n\n  LSCP_INDEX_2_LENGTH = 0x400 >> SHIFT_2;\n\n  INDEX_2_BMP_LENGTH = LSCP_INDEX_2_OFFSET + LSCP_INDEX_2_LENGTH;\n\n  UTF8_2B_INDEX_2_OFFSET = INDEX_2_BMP_LENGTH;\n\n  UTF8_2B_INDEX_2_LENGTH = 0x800 >> 6;\n\n  INDEX_1_OFFSET = UTF8_2B_INDEX_2_OFFSET + UTF8_2B_INDEX_2_LENGTH;\n\n  DATA_GRANULARITY = 1 << INDEX_SHIFT;\n\n  function UnicodeTrie(data) {\n    var isBuffer, uncompressedLength, view;\n    isBuffer = typeof data.readUInt32BE === 'function' && typeof data.slice === 'function';\n    if (isBuffer || data instanceof Uint8Array) {\n      if (isBuffer) {\n        this.highStart = data.readUInt32BE(0);\n        this.errorValue = data.readUInt32BE(4);\n        uncompressedLength = data.readUInt32BE(8);\n        data = data.slice(12);\n      } else {\n        view = new DataView(data.buffer);\n        this.highStart = view.getUint32(0);\n        this.errorValue = view.getUint32(4);\n        uncompressedLength = view.getUint32(8);\n        data = data.subarray(12);\n      }\n      data = inflate(data, new Uint8Array(uncompressedLength));\n      data = inflate(data, new Uint8Array(uncompressedLength));\n      this.data = new Uint32Array(data.buffer);\n    } else {\n      this.data = data.data, this.highStart = data.highStart, this.errorValue = data.errorValue;\n    }\n  }\n\n  UnicodeTrie.prototype.get = function(codePoint) {\n    var index;\n    if (codePoint < 0 || codePoint > 0x10ffff) {\n      return this.errorValue;\n    }\n    if (codePoint < 0xd800 || (codePoint > 0xdbff && codePoint <= 0xffff)) {\n      index = (this.data[codePoint >> SHIFT_2] << INDEX_SHIFT) + (codePoint & DATA_MASK);\n      return this.data[index];\n    }\n    if (codePoint <= 0xffff) {\n      index = (this.data[LSCP_INDEX_2_OFFSET + ((codePoint - 0xd800) >> SHIFT_2)] << INDEX_SHIFT) + (codePoint & DATA_MASK);\n      return this.data[index];\n    }\n    if (codePoint < this.highStart) {\n      index = this.data[(INDEX_1_OFFSET - OMITTED_BMP_INDEX_1_LENGTH) + (codePoint >> SHIFT_1)];\n      index = this.data[index + ((codePoint >> SHIFT_2) & INDEX_2_MASK)];\n      index = (index << INDEX_SHIFT) + (codePoint & DATA_MASK);\n      return this.data[index];\n    }\n    return this.data[this.data.length - DATA_GRANULARITY];\n  };\n\n  return UnicodeTrie;\n\n})();\n\nmodule.exports = UnicodeTrie;\n\n\n/***/ }),\n/* 44 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar isString = __webpack_require__(0).isString;\n\nfunction buildColumnWidths(columns, availableWidth) {\n\tvar autoColumns = [],\n\t\tautoMin = 0, autoMax = 0,\n\t\tstarColumns = [],\n\t\tstarMaxMin = 0,\n\t\tstarMaxMax = 0,\n\t\tfixedColumns = [],\n\t\tinitial_availableWidth = availableWidth;\n\n\tcolumns.forEach(function (column) {\n\t\tif (isAutoColumn(column)) {\n\t\t\tautoColumns.push(column);\n\t\t\tautoMin += column._minWidth;\n\t\t\tautoMax += column._maxWidth;\n\t\t} else if (isStarColumn(column)) {\n\t\t\tstarColumns.push(column);\n\t\t\tstarMaxMin = Math.max(starMaxMin, column._minWidth);\n\t\t\tstarMaxMax = Math.max(starMaxMax, column._maxWidth);\n\t\t} else {\n\t\t\tfixedColumns.push(column);\n\t\t}\n\t});\n\n\tfixedColumns.forEach(function (col) {\n\t\t// width specified as %\n\t\tif (isString(col.width) && /\\d+%/.test(col.width)) {\n\t\t\tcol.width = parseFloat(col.width) * initial_availableWidth / 100;\n\t\t}\n\t\tif (col.width < (col._minWidth) && col.elasticWidth) {\n\t\t\tcol._calcWidth = col._minWidth;\n\t\t} else {\n\t\t\tcol._calcWidth = col.width;\n\t\t}\n\n\t\tavailableWidth -= col._calcWidth;\n\t});\n\n\t// http://www.freesoft.org/CIE/RFC/1942/18.htm\n\t// http://www.w3.org/TR/CSS2/tables.html#width-layout\n\t// http://dev.w3.org/csswg/css3-tables-algorithms/Overview.src.htm\n\tvar minW = autoMin + starMaxMin * starColumns.length;\n\tvar maxW = autoMax + starMaxMax * starColumns.length;\n\tif (minW >= availableWidth) {\n\t\t// case 1 - there's no way to fit all columns within available width\n\t\t// that's actually pretty bad situation with PDF as we have no horizontal scroll\n\t\t// no easy workaround (unless we decide, in the future, to split single words)\n\t\t// currently we simply use minWidths for all columns\n\t\tautoColumns.forEach(function (col) {\n\t\t\tcol._calcWidth = col._minWidth;\n\t\t});\n\n\t\tstarColumns.forEach(function (col) {\n\t\t\tcol._calcWidth = starMaxMin; // starMaxMin already contains padding\n\t\t});\n\t} else {\n\t\tif (maxW < availableWidth) {\n\t\t\t// case 2 - we can fit rest of the table within available space\n\t\t\tautoColumns.forEach(function (col) {\n\t\t\t\tcol._calcWidth = col._maxWidth;\n\t\t\t\tavailableWidth -= col._calcWidth;\n\t\t\t});\n\t\t} else {\n\t\t\t// maxW is too large, but minW fits within available width\n\t\t\tvar W = availableWidth - minW;\n\t\t\tvar D = maxW - minW;\n\n\t\t\tautoColumns.forEach(function (col) {\n\t\t\t\tvar d = col._maxWidth - col._minWidth;\n\t\t\t\tcol._calcWidth = col._minWidth + d * W / D;\n\t\t\t\tavailableWidth -= col._calcWidth;\n\t\t\t});\n\t\t}\n\n\t\tif (starColumns.length > 0) {\n\t\t\tvar starSize = availableWidth / starColumns.length;\n\n\t\t\tstarColumns.forEach(function (col) {\n\t\t\t\tcol._calcWidth = starSize;\n\t\t\t});\n\t\t}\n\t}\n}\n\nfunction isAutoColumn(column) {\n\treturn column.width === 'auto';\n}\n\nfunction isStarColumn(column) {\n\treturn column.width === null || column.width === undefined || column.width === '*' || column.width === 'star';\n}\n\n//TODO: refactor and reuse in measureTable\nfunction measureMinMax(columns) {\n\tvar result = {min: 0, max: 0};\n\n\tvar maxStar = {min: 0, max: 0};\n\tvar starCount = 0;\n\n\tfor (var i = 0, l = columns.length; i < l; i++) {\n\t\tvar c = columns[i];\n\n\t\tif (isStarColumn(c)) {\n\t\t\tmaxStar.min = Math.max(maxStar.min, c._minWidth);\n\t\t\tmaxStar.max = Math.max(maxStar.max, c._maxWidth);\n\t\t\tstarCount++;\n\t\t} else if (isAutoColumn(c)) {\n\t\t\tresult.min += c._minWidth;\n\t\t\tresult.max += c._maxWidth;\n\t\t} else {\n\t\t\tresult.min += ((c.width !== undefined && c.width) || c._minWidth);\n\t\t\tresult.max += ((c.width !== undefined && c.width) || c._maxWidth);\n\t\t}\n\t}\n\n\tif (starCount) {\n\t\tresult.min += starCount * maxStar.min;\n\t\tresult.max += starCount * maxStar.max;\n\t}\n\n\treturn result;\n}\n\n/**\n * Calculates column widths\n * @private\n */\nmodule.exports = {\n\tbuildColumnWidths: buildColumnWidths,\n\tmeasureMinMax: measureMinMax,\n\tisAutoColumn: isAutoColumn,\n\tisStarColumn: isStarColumn\n};\n\n\n/***/ }),\n/* 45 */\n/***/ (function(module, exports, __webpack_require__) {\n\nexports = module.exports = __webpack_require__(83);\nexports.Stream = exports;\nexports.Readable = exports;\nexports.Writable = __webpack_require__(46);\nexports.Duplex = __webpack_require__(16);\nexports.Transform = __webpack_require__(86);\nexports.PassThrough = __webpack_require__(145);\n\n\n/***/ }),\n/* 46 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(process, setImmediate, global) {// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// A bit simpler than readable streams.\n// Implement an async ._write(chunk, encoding, cb), and it'll handle all\n// the drain event emission and buffering.\n\n\n\n/*<replacement>*/\n\nvar processNextTick = __webpack_require__(32).nextTick;\n/*</replacement>*/\n\nmodule.exports = Writable;\n\n/* <replacement> */\nfunction WriteReq(chunk, encoding, cb) {\n  this.chunk = chunk;\n  this.encoding = encoding;\n  this.callback = cb;\n  this.next = null;\n}\n\n// It seems a linked list but it is not\n// there will be only 2 of these for each stream\nfunction CorkedRequest(state) {\n  var _this = this;\n\n  this.next = null;\n  this.entry = null;\n  this.finish = function () {\n    onCorkedFinish(_this, state);\n  };\n}\n/* </replacement> */\n\n/*<replacement>*/\nvar asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : processNextTick;\n/*</replacement>*/\n\n/*<replacement>*/\nvar Duplex;\n/*</replacement>*/\n\nWritable.WritableState = WritableState;\n\n/*<replacement>*/\nvar util = __webpack_require__(25);\nutil.inherits = __webpack_require__(21);\n/*</replacement>*/\n\n/*<replacement>*/\nvar internalUtil = {\n  deprecate: __webpack_require__(144)\n};\n/*</replacement>*/\n\n/*<replacement>*/\nvar Stream = __webpack_require__(84);\n/*</replacement>*/\n\n/*<replacement>*/\n\nvar Buffer = __webpack_require__(33).Buffer;\nvar OurUint8Array = global.Uint8Array || function () {};\nfunction _uint8ArrayToBuffer(chunk) {\n  return Buffer.from(chunk);\n}\nfunction _isUint8Array(obj) {\n  return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;\n}\n\n/*</replacement>*/\n\nvar destroyImpl = __webpack_require__(85);\n\nutil.inherits(Writable, Stream);\n\nfunction nop() {}\n\nfunction WritableState(options, stream) {\n  Duplex = Duplex || __webpack_require__(16);\n\n  options = options || {};\n\n  // Duplex streams are both readable and writable, but share\n  // the same options object.\n  // However, some cases require setting options to different\n  // values for the readable and the writable sides of the duplex stream.\n  // These options can be provided separately as readableXXX and writableXXX.\n  var isDuplex = stream instanceof Duplex;\n\n  // object stream flag to indicate whether or not this stream\n  // contains buffers or objects.\n  this.objectMode = !!options.objectMode;\n\n  if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode;\n\n  // the point at which write() starts returning false\n  // Note: 0 is a valid value, means that we always return false if\n  // the entire buffer is not flushed immediately on write()\n  var hwm = options.highWaterMark;\n  var writableHwm = options.writableHighWaterMark;\n  var defaultHwm = this.objectMode ? 16 : 16 * 1024;\n\n  if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (writableHwm || writableHwm === 0)) this.highWaterMark = writableHwm;else this.highWaterMark = defaultHwm;\n\n  // cast to ints.\n  this.highWaterMark = Math.floor(this.highWaterMark);\n\n  // if _final has been called\n  this.finalCalled = false;\n\n  // drain event flag.\n  this.needDrain = false;\n  // at the start of calling end()\n  this.ending = false;\n  // when end() has been called, and returned\n  this.ended = false;\n  // when 'finish' is emitted\n  this.finished = false;\n\n  // has it been destroyed\n  this.destroyed = false;\n\n  // should we decode strings into buffers before passing to _write?\n  // this is here so that some node-core streams can optimize string\n  // handling at a lower level.\n  var noDecode = options.decodeStrings === false;\n  this.decodeStrings = !noDecode;\n\n  // Crypto is kind of old and crusty.  Historically, its default string\n  // encoding is 'binary' so we have to make this configurable.\n  // Everything else in the universe uses 'utf8', though.\n  this.defaultEncoding = options.defaultEncoding || 'utf8';\n\n  // not an actual buffer we keep track of, but a measurement\n  // of how much we're waiting to get pushed to some underlying\n  // socket or file.\n  this.length = 0;\n\n  // a flag to see when we're in the middle of a write.\n  this.writing = false;\n\n  // when true all writes will be buffered until .uncork() call\n  this.corked = 0;\n\n  // a flag to be able to tell if the onwrite cb is called immediately,\n  // or on a later tick.  We set this to true at first, because any\n  // actions that shouldn't happen until \"later\" should generally also\n  // not happen before the first write call.\n  this.sync = true;\n\n  // a flag to know if we're processing previously buffered items, which\n  // may call the _write() callback in the same tick, so that we don't\n  // end up in an overlapped onwrite situation.\n  this.bufferProcessing = false;\n\n  // the callback that's passed to _write(chunk,cb)\n  this.onwrite = function (er) {\n    onwrite(stream, er);\n  };\n\n  // the callback that the user supplies to write(chunk,encoding,cb)\n  this.writecb = null;\n\n  // the amount that is being written when _write is called.\n  this.writelen = 0;\n\n  this.bufferedRequest = null;\n  this.lastBufferedRequest = null;\n\n  // number of pending user-supplied write callbacks\n  // this must be 0 before 'finish' can be emitted\n  this.pendingcb = 0;\n\n  // emit prefinish if the only thing we're waiting for is _write cbs\n  // This is relevant for synchronous Transform streams\n  this.prefinished = false;\n\n  // True if the error was already emitted and should not be thrown again\n  this.errorEmitted = false;\n\n  // count buffered requests\n  this.bufferedRequestCount = 0;\n\n  // allocate the first CorkedRequest, there is always\n  // one allocated and free to use, and we maintain at most two\n  this.corkedRequestsFree = new CorkedRequest(this);\n}\n\nWritableState.prototype.getBuffer = function getBuffer() {\n  var current = this.bufferedRequest;\n  var out = [];\n  while (current) {\n    out.push(current);\n    current = current.next;\n  }\n  return out;\n};\n\n(function () {\n  try {\n    Object.defineProperty(WritableState.prototype, 'buffer', {\n      get: internalUtil.deprecate(function () {\n        return this.getBuffer();\n      }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003')\n    });\n  } catch (_) {}\n})();\n\n// Test _writableState for inheritance to account for Duplex streams,\n// whose prototype chain only points to Readable.\nvar realHasInstance;\nif (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') {\n  realHasInstance = Function.prototype[Symbol.hasInstance];\n  Object.defineProperty(Writable, Symbol.hasInstance, {\n    value: function (object) {\n      if (realHasInstance.call(this, object)) return true;\n      if (this !== Writable) return false;\n\n      return object && object._writableState instanceof WritableState;\n    }\n  });\n} else {\n  realHasInstance = function (object) {\n    return object instanceof this;\n  };\n}\n\nfunction Writable(options) {\n  Duplex = Duplex || __webpack_require__(16);\n\n  // Writable ctor is applied to Duplexes, too.\n  // `realHasInstance` is necessary because using plain `instanceof`\n  // would return false, as no `_writableState` property is attached.\n\n  // Trying to use the custom `instanceof` for Writable here will also break the\n  // Node.js LazyTransform implementation, which has a non-trivial getter for\n  // `_writableState` that would lead to infinite recursion.\n  if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) {\n    return new Writable(options);\n  }\n\n  this._writableState = new WritableState(options, this);\n\n  // legacy.\n  this.writable = true;\n\n  if (options) {\n    if (typeof options.write === 'function') this._write = options.write;\n\n    if (typeof options.writev === 'function') this._writev = options.writev;\n\n    if (typeof options.destroy === 'function') this._destroy = options.destroy;\n\n    if (typeof options.final === 'function') this._final = options.final;\n  }\n\n  Stream.call(this);\n}\n\n// Otherwise people can pipe Writable streams, which is just wrong.\nWritable.prototype.pipe = function () {\n  this.emit('error', new Error('Cannot pipe, not readable'));\n};\n\nfunction writeAfterEnd(stream, cb) {\n  var er = new Error('write after end');\n  // TODO: defer error events consistently everywhere, not just the cb\n  stream.emit('error', er);\n  processNextTick(cb, er);\n}\n\n// Checks that a user-supplied chunk is valid, especially for the particular\n// mode the stream is in. Currently this means that `null` is never accepted\n// and undefined/non-string values are only allowed in object mode.\nfunction validChunk(stream, state, chunk, cb) {\n  var valid = true;\n  var er = false;\n\n  if (chunk === null) {\n    er = new TypeError('May not write null values to stream');\n  } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {\n    er = new TypeError('Invalid non-string/buffer chunk');\n  }\n  if (er) {\n    stream.emit('error', er);\n    processNextTick(cb, er);\n    valid = false;\n  }\n  return valid;\n}\n\nWritable.prototype.write = function (chunk, encoding, cb) {\n  var state = this._writableState;\n  var ret = false;\n  var isBuf = !state.objectMode && _isUint8Array(chunk);\n\n  if (isBuf && !Buffer.isBuffer(chunk)) {\n    chunk = _uint8ArrayToBuffer(chunk);\n  }\n\n  if (typeof encoding === 'function') {\n    cb = encoding;\n    encoding = null;\n  }\n\n  if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding;\n\n  if (typeof cb !== 'function') cb = nop;\n\n  if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) {\n    state.pendingcb++;\n    ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);\n  }\n\n  return ret;\n};\n\nWritable.prototype.cork = function () {\n  var state = this._writableState;\n\n  state.corked++;\n};\n\nWritable.prototype.uncork = function () {\n  var state = this._writableState;\n\n  if (state.corked) {\n    state.corked--;\n\n    if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);\n  }\n};\n\nWritable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {\n  // node::ParseEncoding() requires lower case.\n  if (typeof encoding === 'string') encoding = encoding.toLowerCase();\n  if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding);\n  this._writableState.defaultEncoding = encoding;\n  return this;\n};\n\nfunction decodeChunk(state, chunk, encoding) {\n  if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {\n    chunk = Buffer.from(chunk, encoding);\n  }\n  return chunk;\n}\n\n// if we're already writing something, then just put this\n// in the queue, and wait our turn.  Otherwise, call _write\n// If we return false, then we need a drain event, so set that flag.\nfunction writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {\n  if (!isBuf) {\n    var newChunk = decodeChunk(state, chunk, encoding);\n    if (chunk !== newChunk) {\n      isBuf = true;\n      encoding = 'buffer';\n      chunk = newChunk;\n    }\n  }\n  var len = state.objectMode ? 1 : chunk.length;\n\n  state.length += len;\n\n  var ret = state.length < state.highWaterMark;\n  // we must ensure that previous needDrain will not be reset to false.\n  if (!ret) state.needDrain = true;\n\n  if (state.writing || state.corked) {\n    var last = state.lastBufferedRequest;\n    state.lastBufferedRequest = {\n      chunk: chunk,\n      encoding: encoding,\n      isBuf: isBuf,\n      callback: cb,\n      next: null\n    };\n    if (last) {\n      last.next = state.lastBufferedRequest;\n    } else {\n      state.bufferedRequest = state.lastBufferedRequest;\n    }\n    state.bufferedRequestCount += 1;\n  } else {\n    doWrite(stream, state, false, len, chunk, encoding, cb);\n  }\n\n  return ret;\n}\n\nfunction doWrite(stream, state, writev, len, chunk, encoding, cb) {\n  state.writelen = len;\n  state.writecb = cb;\n  state.writing = true;\n  state.sync = true;\n  if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite);\n  state.sync = false;\n}\n\nfunction onwriteError(stream, state, sync, er, cb) {\n  --state.pendingcb;\n\n  if (sync) {\n    // defer the callback if we are being called synchronously\n    // to avoid piling up things on the stack\n    processNextTick(cb, er);\n    // this can emit finish, and it will always happen\n    // after error\n    processNextTick(finishMaybe, stream, state);\n    stream._writableState.errorEmitted = true;\n    stream.emit('error', er);\n  } else {\n    // the caller expect this to happen before if\n    // it is async\n    cb(er);\n    stream._writableState.errorEmitted = true;\n    stream.emit('error', er);\n    // this can emit finish, but finish must\n    // always follow error\n    finishMaybe(stream, state);\n  }\n}\n\nfunction onwriteStateUpdate(state) {\n  state.writing = false;\n  state.writecb = null;\n  state.length -= state.writelen;\n  state.writelen = 0;\n}\n\nfunction onwrite(stream, er) {\n  var state = stream._writableState;\n  var sync = state.sync;\n  var cb = state.writecb;\n\n  onwriteStateUpdate(state);\n\n  if (er) onwriteError(stream, state, sync, er, cb);else {\n    // Check if we're actually ready to finish, but don't emit yet\n    var finished = needFinish(state);\n\n    if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {\n      clearBuffer(stream, state);\n    }\n\n    if (sync) {\n      /*<replacement>*/\n      asyncWrite(afterWrite, stream, state, finished, cb);\n      /*</replacement>*/\n    } else {\n      afterWrite(stream, state, finished, cb);\n    }\n  }\n}\n\nfunction afterWrite(stream, state, finished, cb) {\n  if (!finished) onwriteDrain(stream, state);\n  state.pendingcb--;\n  cb();\n  finishMaybe(stream, state);\n}\n\n// Must force callback to be called on nextTick, so that we don't\n// emit 'drain' before the write() consumer gets the 'false' return\n// value, and has a chance to attach a 'drain' listener.\nfunction onwriteDrain(stream, state) {\n  if (state.length === 0 && state.needDrain) {\n    state.needDrain = false;\n    stream.emit('drain');\n  }\n}\n\n// if there's something in the buffer waiting, then process it\nfunction clearBuffer(stream, state) {\n  state.bufferProcessing = true;\n  var entry = state.bufferedRequest;\n\n  if (stream._writev && entry && entry.next) {\n    // Fast case, write everything using _writev()\n    var l = state.bufferedRequestCount;\n    var buffer = new Array(l);\n    var holder = state.corkedRequestsFree;\n    holder.entry = entry;\n\n    var count = 0;\n    var allBuffers = true;\n    while (entry) {\n      buffer[count] = entry;\n      if (!entry.isBuf) allBuffers = false;\n      entry = entry.next;\n      count += 1;\n    }\n    buffer.allBuffers = allBuffers;\n\n    doWrite(stream, state, true, state.length, buffer, '', holder.finish);\n\n    // doWrite is almost always async, defer these to save a bit of time\n    // as the hot path ends with doWrite\n    state.pendingcb++;\n    state.lastBufferedRequest = null;\n    if (holder.next) {\n      state.corkedRequestsFree = holder.next;\n      holder.next = null;\n    } else {\n      state.corkedRequestsFree = new CorkedRequest(state);\n    }\n    state.bufferedRequestCount = 0;\n  } else {\n    // Slow case, write chunks one-by-one\n    while (entry) {\n      var chunk = entry.chunk;\n      var encoding = entry.encoding;\n      var cb = entry.callback;\n      var len = state.objectMode ? 1 : chunk.length;\n\n      doWrite(stream, state, false, len, chunk, encoding, cb);\n      entry = entry.next;\n      state.bufferedRequestCount--;\n      // if we didn't call the onwrite immediately, then\n      // it means that we need to wait until it does.\n      // also, that means that the chunk and cb are currently\n      // being processed, so move the buffer counter past them.\n      if (state.writing) {\n        break;\n      }\n    }\n\n    if (entry === null) state.lastBufferedRequest = null;\n  }\n\n  state.bufferedRequest = entry;\n  state.bufferProcessing = false;\n}\n\nWritable.prototype._write = function (chunk, encoding, cb) {\n  cb(new Error('_write() is not implemented'));\n};\n\nWritable.prototype._writev = null;\n\nWritable.prototype.end = function (chunk, encoding, cb) {\n  var state = this._writableState;\n\n  if (typeof chunk === 'function') {\n    cb = chunk;\n    chunk = null;\n    encoding = null;\n  } else if (typeof encoding === 'function') {\n    cb = encoding;\n    encoding = null;\n  }\n\n  if (chunk !== null && chunk !== undefined) this.write(chunk, encoding);\n\n  // .end() fully uncorks\n  if (state.corked) {\n    state.corked = 1;\n    this.uncork();\n  }\n\n  // ignore unnecessary end() calls.\n  if (!state.ending && !state.finished) endWritable(this, state, cb);\n};\n\nfunction needFinish(state) {\n  return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;\n}\nfunction callFinal(stream, state) {\n  stream._final(function (err) {\n    state.pendingcb--;\n    if (err) {\n      stream.emit('error', err);\n    }\n    state.prefinished = true;\n    stream.emit('prefinish');\n    finishMaybe(stream, state);\n  });\n}\nfunction prefinish(stream, state) {\n  if (!state.prefinished && !state.finalCalled) {\n    if (typeof stream._final === 'function') {\n      state.pendingcb++;\n      state.finalCalled = true;\n      processNextTick(callFinal, stream, state);\n    } else {\n      state.prefinished = true;\n      stream.emit('prefinish');\n    }\n  }\n}\n\nfunction finishMaybe(stream, state) {\n  var need = needFinish(state);\n  if (need) {\n    prefinish(stream, state);\n    if (state.pendingcb === 0) {\n      state.finished = true;\n      stream.emit('finish');\n    }\n  }\n  return need;\n}\n\nfunction endWritable(stream, state, cb) {\n  state.ending = true;\n  finishMaybe(stream, state);\n  if (cb) {\n    if (state.finished) processNextTick(cb);else stream.once('finish', cb);\n  }\n  state.ended = true;\n  stream.writable = false;\n}\n\nfunction onCorkedFinish(corkReq, state, err) {\n  var entry = corkReq.entry;\n  corkReq.entry = null;\n  while (entry) {\n    var cb = entry.callback;\n    state.pendingcb--;\n    cb(err);\n    entry = entry.next;\n  }\n  if (state.corkedRequestsFree) {\n    state.corkedRequestsFree.next = corkReq;\n  } else {\n    state.corkedRequestsFree = corkReq;\n  }\n}\n\nObject.defineProperty(Writable.prototype, 'destroyed', {\n  get: function () {\n    if (this._writableState === undefined) {\n      return false;\n    }\n    return this._writableState.destroyed;\n  },\n  set: function (value) {\n    // we ignore the value if the stream\n    // has not been initialized yet\n    if (!this._writableState) {\n      return;\n    }\n\n    // backward compatibility, the user is explicitly\n    // managing destroyed\n    this._writableState.destroyed = value;\n  }\n});\n\nWritable.prototype.destroy = destroyImpl.destroy;\nWritable.prototype._undestroy = destroyImpl.undestroy;\nWritable.prototype._destroy = function (err, cb) {\n  this.end();\n  cb(err);\n};\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11), __webpack_require__(142).setImmediate, __webpack_require__(7)))\n\n/***/ }),\n/* 47 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar Buffer = __webpack_require__(33).Buffer;\n\nvar isEncoding = Buffer.isEncoding || function (encoding) {\n  encoding = '' + encoding;\n  switch (encoding && encoding.toLowerCase()) {\n    case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw':\n      return true;\n    default:\n      return false;\n  }\n};\n\nfunction _normalizeEncoding(enc) {\n  if (!enc) return 'utf8';\n  var retried;\n  while (true) {\n    switch (enc) {\n      case 'utf8':\n      case 'utf-8':\n        return 'utf8';\n      case 'ucs2':\n      case 'ucs-2':\n      case 'utf16le':\n      case 'utf-16le':\n        return 'utf16le';\n      case 'latin1':\n      case 'binary':\n        return 'latin1';\n      case 'base64':\n      case 'ascii':\n      case 'hex':\n        return enc;\n      default:\n        if (retried) return; // undefined\n        enc = ('' + enc).toLowerCase();\n        retried = true;\n    }\n  }\n};\n\n// Do not cache `Buffer.isEncoding` when checking encoding names as some\n// modules monkey-patch it to support additional encodings\nfunction normalizeEncoding(enc) {\n  var nenc = _normalizeEncoding(enc);\n  if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc);\n  return nenc || enc;\n}\n\n// StringDecoder provides an interface for efficiently splitting a series of\n// buffers into a series of JS strings without breaking apart multi-byte\n// characters.\nexports.StringDecoder = StringDecoder;\nfunction StringDecoder(encoding) {\n  this.encoding = normalizeEncoding(encoding);\n  var nb;\n  switch (this.encoding) {\n    case 'utf16le':\n      this.text = utf16Text;\n      this.end = utf16End;\n      nb = 4;\n      break;\n    case 'utf8':\n      this.fillLast = utf8FillLast;\n      nb = 4;\n      break;\n    case 'base64':\n      this.text = base64Text;\n      this.end = base64End;\n      nb = 3;\n      break;\n    default:\n      this.write = simpleWrite;\n      this.end = simpleEnd;\n      return;\n  }\n  this.lastNeed = 0;\n  this.lastTotal = 0;\n  this.lastChar = Buffer.allocUnsafe(nb);\n}\n\nStringDecoder.prototype.write = function (buf) {\n  if (buf.length === 0) return '';\n  var r;\n  var i;\n  if (this.lastNeed) {\n    r = this.fillLast(buf);\n    if (r === undefined) return '';\n    i = this.lastNeed;\n    this.lastNeed = 0;\n  } else {\n    i = 0;\n  }\n  if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i);\n  return r || '';\n};\n\nStringDecoder.prototype.end = utf8End;\n\n// Returns only complete characters in a Buffer\nStringDecoder.prototype.text = utf8Text;\n\n// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer\nStringDecoder.prototype.fillLast = function (buf) {\n  if (this.lastNeed <= buf.length) {\n    buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed);\n    return this.lastChar.toString(this.encoding, 0, this.lastTotal);\n  }\n  buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length);\n  this.lastNeed -= buf.length;\n};\n\n// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a\n// continuation byte.\nfunction utf8CheckByte(byte) {\n  if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4;\n  return -1;\n}\n\n// Checks at most 3 bytes at the end of a Buffer in order to detect an\n// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4)\n// needed to complete the UTF-8 character (if applicable) are returned.\nfunction utf8CheckIncomplete(self, buf, i) {\n  var j = buf.length - 1;\n  if (j < i) return 0;\n  var nb = utf8CheckByte(buf[j]);\n  if (nb >= 0) {\n    if (nb > 0) self.lastNeed = nb - 1;\n    return nb;\n  }\n  if (--j < i) return 0;\n  nb = utf8CheckByte(buf[j]);\n  if (nb >= 0) {\n    if (nb > 0) self.lastNeed = nb - 2;\n    return nb;\n  }\n  if (--j < i) return 0;\n  nb = utf8CheckByte(buf[j]);\n  if (nb >= 0) {\n    if (nb > 0) {\n      if (nb === 2) nb = 0;else self.lastNeed = nb - 3;\n    }\n    return nb;\n  }\n  return 0;\n}\n\n// Validates as many continuation bytes for a multi-byte UTF-8 character as\n// needed or are available. If we see a non-continuation byte where we expect\n// one, we \"replace\" the validated continuation bytes we've seen so far with\n// UTF-8 replacement characters ('\\ufffd'), to match v8's UTF-8 decoding\n// behavior. The continuation byte check is included three times in the case\n// where all of the continuation bytes for a character exist in the same buffer.\n// It is also done this way as a slight performance increase instead of using a\n// loop.\nfunction utf8CheckExtraBytes(self, buf, p) {\n  if ((buf[0] & 0xC0) !== 0x80) {\n    self.lastNeed = 0;\n    return '\\ufffd'.repeat(p);\n  }\n  if (self.lastNeed > 1 && buf.length > 1) {\n    if ((buf[1] & 0xC0) !== 0x80) {\n      self.lastNeed = 1;\n      return '\\ufffd'.repeat(p + 1);\n    }\n    if (self.lastNeed > 2 && buf.length > 2) {\n      if ((buf[2] & 0xC0) !== 0x80) {\n        self.lastNeed = 2;\n        return '\\ufffd'.repeat(p + 2);\n      }\n    }\n  }\n}\n\n// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer.\nfunction utf8FillLast(buf) {\n  var p = this.lastTotal - this.lastNeed;\n  var r = utf8CheckExtraBytes(this, buf, p);\n  if (r !== undefined) return r;\n  if (this.lastNeed <= buf.length) {\n    buf.copy(this.lastChar, p, 0, this.lastNeed);\n    return this.lastChar.toString(this.encoding, 0, this.lastTotal);\n  }\n  buf.copy(this.lastChar, p, 0, buf.length);\n  this.lastNeed -= buf.length;\n}\n\n// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a\n// partial character, the character's bytes are buffered until the required\n// number of bytes are available.\nfunction utf8Text(buf, i) {\n  var total = utf8CheckIncomplete(this, buf, i);\n  if (!this.lastNeed) return buf.toString('utf8', i);\n  this.lastTotal = total;\n  var end = buf.length - (total - this.lastNeed);\n  buf.copy(this.lastChar, 0, end);\n  return buf.toString('utf8', i, end);\n}\n\n// For UTF-8, a replacement character for each buffered byte of a (partial)\n// character needs to be added to the output.\nfunction utf8End(buf) {\n  var r = buf && buf.length ? this.write(buf) : '';\n  if (this.lastNeed) return r + '\\ufffd'.repeat(this.lastTotal - this.lastNeed);\n  return r;\n}\n\n// UTF-16LE typically needs two bytes per character, but even if we have an even\n// number of bytes available, we need to check if we end on a leading/high\n// surrogate. In that case, we need to wait for the next two bytes in order to\n// decode the last character properly.\nfunction utf16Text(buf, i) {\n  if ((buf.length - i) % 2 === 0) {\n    var r = buf.toString('utf16le', i);\n    if (r) {\n      var c = r.charCodeAt(r.length - 1);\n      if (c >= 0xD800 && c <= 0xDBFF) {\n        this.lastNeed = 2;\n        this.lastTotal = 4;\n        this.lastChar[0] = buf[buf.length - 2];\n        this.lastChar[1] = buf[buf.length - 1];\n        return r.slice(0, -1);\n      }\n    }\n    return r;\n  }\n  this.lastNeed = 1;\n  this.lastTotal = 2;\n  this.lastChar[0] = buf[buf.length - 1];\n  return buf.toString('utf16le', i, buf.length - 1);\n}\n\n// For UTF-16LE we do not explicitly append special replacement characters if we\n// end on a partial character, we simply let v8 handle that.\nfunction utf16End(buf) {\n  var r = buf && buf.length ? this.write(buf) : '';\n  if (this.lastNeed) {\n    var end = this.lastTotal - this.lastNeed;\n    return r + this.lastChar.toString('utf16le', 0, end);\n  }\n  return r;\n}\n\nfunction base64Text(buf, i) {\n  var n = (buf.length - i) % 3;\n  if (n === 0) return buf.toString('base64', i);\n  this.lastNeed = 3 - n;\n  this.lastTotal = 3;\n  if (n === 1) {\n    this.lastChar[0] = buf[buf.length - 1];\n  } else {\n    this.lastChar[0] = buf[buf.length - 2];\n    this.lastChar[1] = buf[buf.length - 1];\n  }\n  return buf.toString('base64', i, buf.length - n);\n}\n\nfunction base64End(buf) {\n  var r = buf && buf.length ? this.write(buf) : '';\n  if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed);\n  return r;\n}\n\n// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex)\nfunction simpleWrite(buf) {\n  return buf.toString(this.encoding);\n}\n\nfunction simpleEnd(buf) {\n  return buf && buf.length ? this.write(buf) : '';\n}\n\n/***/ }),\n/* 48 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(process) {\n\nvar Buffer = __webpack_require__(1).Buffer;\nvar Transform = __webpack_require__(15).Transform;\nvar binding = __webpack_require__(150);\nvar util = __webpack_require__(49);\nvar assert = __webpack_require__(88).ok;\nvar kMaxLength = __webpack_require__(1).kMaxLength;\nvar kRangeErrorMessage = 'Cannot create final Buffer. It would be larger ' + 'than 0x' + kMaxLength.toString(16) + ' bytes';\n\n// zlib doesn't provide these, so kludge them in following the same\n// const naming scheme zlib uses.\nbinding.Z_MIN_WINDOWBITS = 8;\nbinding.Z_MAX_WINDOWBITS = 15;\nbinding.Z_DEFAULT_WINDOWBITS = 15;\n\n// fewer than 64 bytes per chunk is stupid.\n// technically it could work with as few as 8, but even 64 bytes\n// is absurdly low.  Usually a MB or more is best.\nbinding.Z_MIN_CHUNK = 64;\nbinding.Z_MAX_CHUNK = Infinity;\nbinding.Z_DEFAULT_CHUNK = 16 * 1024;\n\nbinding.Z_MIN_MEMLEVEL = 1;\nbinding.Z_MAX_MEMLEVEL = 9;\nbinding.Z_DEFAULT_MEMLEVEL = 8;\n\nbinding.Z_MIN_LEVEL = -1;\nbinding.Z_MAX_LEVEL = 9;\nbinding.Z_DEFAULT_LEVEL = binding.Z_DEFAULT_COMPRESSION;\n\n// expose all the zlib constants\nvar bkeys = Object.keys(binding);\nfor (var bk = 0; bk < bkeys.length; bk++) {\n  var bkey = bkeys[bk];\n  if (bkey.match(/^Z/)) {\n    Object.defineProperty(exports, bkey, {\n      enumerable: true, value: binding[bkey], writable: false\n    });\n  }\n}\n\n// translation table for return codes.\nvar codes = {\n  Z_OK: binding.Z_OK,\n  Z_STREAM_END: binding.Z_STREAM_END,\n  Z_NEED_DICT: binding.Z_NEED_DICT,\n  Z_ERRNO: binding.Z_ERRNO,\n  Z_STREAM_ERROR: binding.Z_STREAM_ERROR,\n  Z_DATA_ERROR: binding.Z_DATA_ERROR,\n  Z_MEM_ERROR: binding.Z_MEM_ERROR,\n  Z_BUF_ERROR: binding.Z_BUF_ERROR,\n  Z_VERSION_ERROR: binding.Z_VERSION_ERROR\n};\n\nvar ckeys = Object.keys(codes);\nfor (var ck = 0; ck < ckeys.length; ck++) {\n  var ckey = ckeys[ck];\n  codes[codes[ckey]] = ckey;\n}\n\nObject.defineProperty(exports, 'codes', {\n  enumerable: true, value: Object.freeze(codes), writable: false\n});\n\nexports.Deflate = Deflate;\nexports.Inflate = Inflate;\nexports.Gzip = Gzip;\nexports.Gunzip = Gunzip;\nexports.DeflateRaw = DeflateRaw;\nexports.InflateRaw = InflateRaw;\nexports.Unzip = Unzip;\n\nexports.createDeflate = function (o) {\n  return new Deflate(o);\n};\n\nexports.createInflate = function (o) {\n  return new Inflate(o);\n};\n\nexports.createDeflateRaw = function (o) {\n  return new DeflateRaw(o);\n};\n\nexports.createInflateRaw = function (o) {\n  return new InflateRaw(o);\n};\n\nexports.createGzip = function (o) {\n  return new Gzip(o);\n};\n\nexports.createGunzip = function (o) {\n  return new Gunzip(o);\n};\n\nexports.createUnzip = function (o) {\n  return new Unzip(o);\n};\n\n// Convenience methods.\n// compress/decompress a string or buffer in one step.\nexports.deflate = function (buffer, opts, callback) {\n  if (typeof opts === 'function') {\n    callback = opts;\n    opts = {};\n  }\n  return zlibBuffer(new Deflate(opts), buffer, callback);\n};\n\nexports.deflateSync = function (buffer, opts) {\n  return zlibBufferSync(new Deflate(opts), buffer);\n};\n\nexports.gzip = function (buffer, opts, callback) {\n  if (typeof opts === 'function') {\n    callback = opts;\n    opts = {};\n  }\n  return zlibBuffer(new Gzip(opts), buffer, callback);\n};\n\nexports.gzipSync = function (buffer, opts) {\n  return zlibBufferSync(new Gzip(opts), buffer);\n};\n\nexports.deflateRaw = function (buffer, opts, callback) {\n  if (typeof opts === 'function') {\n    callback = opts;\n    opts = {};\n  }\n  return zlibBuffer(new DeflateRaw(opts), buffer, callback);\n};\n\nexports.deflateRawSync = function (buffer, opts) {\n  return zlibBufferSync(new DeflateRaw(opts), buffer);\n};\n\nexports.unzip = function (buffer, opts, callback) {\n  if (typeof opts === 'function') {\n    callback = opts;\n    opts = {};\n  }\n  return zlibBuffer(new Unzip(opts), buffer, callback);\n};\n\nexports.unzipSync = function (buffer, opts) {\n  return zlibBufferSync(new Unzip(opts), buffer);\n};\n\nexports.inflate = function (buffer, opts, callback) {\n  if (typeof opts === 'function') {\n    callback = opts;\n    opts = {};\n  }\n  return zlibBuffer(new Inflate(opts), buffer, callback);\n};\n\nexports.inflateSync = function (buffer, opts) {\n  return zlibBufferSync(new Inflate(opts), buffer);\n};\n\nexports.gunzip = function (buffer, opts, callback) {\n  if (typeof opts === 'function') {\n    callback = opts;\n    opts = {};\n  }\n  return zlibBuffer(new Gunzip(opts), buffer, callback);\n};\n\nexports.gunzipSync = function (buffer, opts) {\n  return zlibBufferSync(new Gunzip(opts), buffer);\n};\n\nexports.inflateRaw = function (buffer, opts, callback) {\n  if (typeof opts === 'function') {\n    callback = opts;\n    opts = {};\n  }\n  return zlibBuffer(new InflateRaw(opts), buffer, callback);\n};\n\nexports.inflateRawSync = function (buffer, opts) {\n  return zlibBufferSync(new InflateRaw(opts), buffer);\n};\n\nfunction zlibBuffer(engine, buffer, callback) {\n  var buffers = [];\n  var nread = 0;\n\n  engine.on('error', onError);\n  engine.on('end', onEnd);\n\n  engine.end(buffer);\n  flow();\n\n  function flow() {\n    var chunk;\n    while (null !== (chunk = engine.read())) {\n      buffers.push(chunk);\n      nread += chunk.length;\n    }\n    engine.once('readable', flow);\n  }\n\n  function onError(err) {\n    engine.removeListener('end', onEnd);\n    engine.removeListener('readable', flow);\n    callback(err);\n  }\n\n  function onEnd() {\n    var buf;\n    var err = null;\n\n    if (nread >= kMaxLength) {\n      err = new RangeError(kRangeErrorMessage);\n    } else {\n      buf = Buffer.concat(buffers, nread);\n    }\n\n    buffers = [];\n    engine.close();\n    callback(err, buf);\n  }\n}\n\nfunction zlibBufferSync(engine, buffer) {\n  if (typeof buffer === 'string') buffer = Buffer.from(buffer);\n\n  if (!Buffer.isBuffer(buffer)) throw new TypeError('Not a string or buffer');\n\n  var flushFlag = engine._finishFlushFlag;\n\n  return engine._processChunk(buffer, flushFlag);\n}\n\n// generic zlib\n// minimal 2-byte header\nfunction Deflate(opts) {\n  if (!(this instanceof Deflate)) return new Deflate(opts);\n  Zlib.call(this, opts, binding.DEFLATE);\n}\n\nfunction Inflate(opts) {\n  if (!(this instanceof Inflate)) return new Inflate(opts);\n  Zlib.call(this, opts, binding.INFLATE);\n}\n\n// gzip - bigger header, same deflate compression\nfunction Gzip(opts) {\n  if (!(this instanceof Gzip)) return new Gzip(opts);\n  Zlib.call(this, opts, binding.GZIP);\n}\n\nfunction Gunzip(opts) {\n  if (!(this instanceof Gunzip)) return new Gunzip(opts);\n  Zlib.call(this, opts, binding.GUNZIP);\n}\n\n// raw - no header\nfunction DeflateRaw(opts) {\n  if (!(this instanceof DeflateRaw)) return new DeflateRaw(opts);\n  Zlib.call(this, opts, binding.DEFLATERAW);\n}\n\nfunction InflateRaw(opts) {\n  if (!(this instanceof InflateRaw)) return new InflateRaw(opts);\n  Zlib.call(this, opts, binding.INFLATERAW);\n}\n\n// auto-detect header.\nfunction Unzip(opts) {\n  if (!(this instanceof Unzip)) return new Unzip(opts);\n  Zlib.call(this, opts, binding.UNZIP);\n}\n\nfunction isValidFlushFlag(flag) {\n  return flag === binding.Z_NO_FLUSH || flag === binding.Z_PARTIAL_FLUSH || flag === binding.Z_SYNC_FLUSH || flag === binding.Z_FULL_FLUSH || flag === binding.Z_FINISH || flag === binding.Z_BLOCK;\n}\n\n// the Zlib class they all inherit from\n// This thing manages the queue of requests, and returns\n// true or false if there is anything in the queue when\n// you call the .write() method.\n\nfunction Zlib(opts, mode) {\n  var _this = this;\n\n  this._opts = opts = opts || {};\n  this._chunkSize = opts.chunkSize || exports.Z_DEFAULT_CHUNK;\n\n  Transform.call(this, opts);\n\n  if (opts.flush && !isValidFlushFlag(opts.flush)) {\n    throw new Error('Invalid flush flag: ' + opts.flush);\n  }\n  if (opts.finishFlush && !isValidFlushFlag(opts.finishFlush)) {\n    throw new Error('Invalid flush flag: ' + opts.finishFlush);\n  }\n\n  this._flushFlag = opts.flush || binding.Z_NO_FLUSH;\n  this._finishFlushFlag = typeof opts.finishFlush !== 'undefined' ? opts.finishFlush : binding.Z_FINISH;\n\n  if (opts.chunkSize) {\n    if (opts.chunkSize < exports.Z_MIN_CHUNK || opts.chunkSize > exports.Z_MAX_CHUNK) {\n      throw new Error('Invalid chunk size: ' + opts.chunkSize);\n    }\n  }\n\n  if (opts.windowBits) {\n    if (opts.windowBits < exports.Z_MIN_WINDOWBITS || opts.windowBits > exports.Z_MAX_WINDOWBITS) {\n      throw new Error('Invalid windowBits: ' + opts.windowBits);\n    }\n  }\n\n  if (opts.level) {\n    if (opts.level < exports.Z_MIN_LEVEL || opts.level > exports.Z_MAX_LEVEL) {\n      throw new Error('Invalid compression level: ' + opts.level);\n    }\n  }\n\n  if (opts.memLevel) {\n    if (opts.memLevel < exports.Z_MIN_MEMLEVEL || opts.memLevel > exports.Z_MAX_MEMLEVEL) {\n      throw new Error('Invalid memLevel: ' + opts.memLevel);\n    }\n  }\n\n  if (opts.strategy) {\n    if (opts.strategy != exports.Z_FILTERED && opts.strategy != exports.Z_HUFFMAN_ONLY && opts.strategy != exports.Z_RLE && opts.strategy != exports.Z_FIXED && opts.strategy != exports.Z_DEFAULT_STRATEGY) {\n      throw new Error('Invalid strategy: ' + opts.strategy);\n    }\n  }\n\n  if (opts.dictionary) {\n    if (!Buffer.isBuffer(opts.dictionary)) {\n      throw new Error('Invalid dictionary: it should be a Buffer instance');\n    }\n  }\n\n  this._handle = new binding.Zlib(mode);\n\n  var self = this;\n  this._hadError = false;\n  this._handle.onerror = function (message, errno) {\n    // there is no way to cleanly recover.\n    // continuing only obscures problems.\n    _close(self);\n    self._hadError = true;\n\n    var error = new Error(message);\n    error.errno = errno;\n    error.code = exports.codes[errno];\n    self.emit('error', error);\n  };\n\n  var level = exports.Z_DEFAULT_COMPRESSION;\n  if (typeof opts.level === 'number') level = opts.level;\n\n  var strategy = exports.Z_DEFAULT_STRATEGY;\n  if (typeof opts.strategy === 'number') strategy = opts.strategy;\n\n  this._handle.init(opts.windowBits || exports.Z_DEFAULT_WINDOWBITS, level, opts.memLevel || exports.Z_DEFAULT_MEMLEVEL, strategy, opts.dictionary);\n\n  this._buffer = Buffer.allocUnsafe(this._chunkSize);\n  this._offset = 0;\n  this._level = level;\n  this._strategy = strategy;\n\n  this.once('end', this.close);\n\n  Object.defineProperty(this, '_closed', {\n    get: function () {\n      return !_this._handle;\n    },\n    configurable: true,\n    enumerable: true\n  });\n}\n\nutil.inherits(Zlib, Transform);\n\nZlib.prototype.params = function (level, strategy, callback) {\n  if (level < exports.Z_MIN_LEVEL || level > exports.Z_MAX_LEVEL) {\n    throw new RangeError('Invalid compression level: ' + level);\n  }\n  if (strategy != exports.Z_FILTERED && strategy != exports.Z_HUFFMAN_ONLY && strategy != exports.Z_RLE && strategy != exports.Z_FIXED && strategy != exports.Z_DEFAULT_STRATEGY) {\n    throw new TypeError('Invalid strategy: ' + strategy);\n  }\n\n  if (this._level !== level || this._strategy !== strategy) {\n    var self = this;\n    this.flush(binding.Z_SYNC_FLUSH, function () {\n      assert(self._handle, 'zlib binding closed');\n      self._handle.params(level, strategy);\n      if (!self._hadError) {\n        self._level = level;\n        self._strategy = strategy;\n        if (callback) callback();\n      }\n    });\n  } else {\n    process.nextTick(callback);\n  }\n};\n\nZlib.prototype.reset = function () {\n  assert(this._handle, 'zlib binding closed');\n  return this._handle.reset();\n};\n\n// This is the _flush function called by the transform class,\n// internally, when the last chunk has been written.\nZlib.prototype._flush = function (callback) {\n  this._transform(Buffer.alloc(0), '', callback);\n};\n\nZlib.prototype.flush = function (kind, callback) {\n  var _this2 = this;\n\n  var ws = this._writableState;\n\n  if (typeof kind === 'function' || kind === undefined && !callback) {\n    callback = kind;\n    kind = binding.Z_FULL_FLUSH;\n  }\n\n  if (ws.ended) {\n    if (callback) process.nextTick(callback);\n  } else if (ws.ending) {\n    if (callback) this.once('end', callback);\n  } else if (ws.needDrain) {\n    if (callback) {\n      this.once('drain', function () {\n        return _this2.flush(kind, callback);\n      });\n    }\n  } else {\n    this._flushFlag = kind;\n    this.write(Buffer.alloc(0), '', callback);\n  }\n};\n\nZlib.prototype.close = function (callback) {\n  _close(this, callback);\n  process.nextTick(emitCloseNT, this);\n};\n\nfunction _close(engine, callback) {\n  if (callback) process.nextTick(callback);\n\n  // Caller may invoke .close after a zlib error (which will null _handle).\n  if (!engine._handle) return;\n\n  engine._handle.close();\n  engine._handle = null;\n}\n\nfunction emitCloseNT(self) {\n  self.emit('close');\n}\n\nZlib.prototype._transform = function (chunk, encoding, cb) {\n  var flushFlag;\n  var ws = this._writableState;\n  var ending = ws.ending || ws.ended;\n  var last = ending && (!chunk || ws.length === chunk.length);\n\n  if (chunk !== null && !Buffer.isBuffer(chunk)) return cb(new Error('invalid input'));\n\n  if (!this._handle) return cb(new Error('zlib binding closed'));\n\n  // If it's the last chunk, or a final flush, we use the Z_FINISH flush flag\n  // (or whatever flag was provided using opts.finishFlush).\n  // If it's explicitly flushing at some other time, then we use\n  // Z_FULL_FLUSH. Otherwise, use Z_NO_FLUSH for maximum compression\n  // goodness.\n  if (last) flushFlag = this._finishFlushFlag;else {\n    flushFlag = this._flushFlag;\n    // once we've flushed the last of the queue, stop flushing and\n    // go back to the normal behavior.\n    if (chunk.length >= ws.length) {\n      this._flushFlag = this._opts.flush || binding.Z_NO_FLUSH;\n    }\n  }\n\n  this._processChunk(chunk, flushFlag, cb);\n};\n\nZlib.prototype._processChunk = function (chunk, flushFlag, cb) {\n  var availInBefore = chunk && chunk.length;\n  var availOutBefore = this._chunkSize - this._offset;\n  var inOff = 0;\n\n  var self = this;\n\n  var async = typeof cb === 'function';\n\n  if (!async) {\n    var buffers = [];\n    var nread = 0;\n\n    var error;\n    this.on('error', function (er) {\n      error = er;\n    });\n\n    assert(this._handle, 'zlib binding closed');\n    do {\n      var res = this._handle.writeSync(flushFlag, chunk, // in\n      inOff, // in_off\n      availInBefore, // in_len\n      this._buffer, // out\n      this._offset, //out_off\n      availOutBefore); // out_len\n    } while (!this._hadError && callback(res[0], res[1]));\n\n    if (this._hadError) {\n      throw error;\n    }\n\n    if (nread >= kMaxLength) {\n      _close(this);\n      throw new RangeError(kRangeErrorMessage);\n    }\n\n    var buf = Buffer.concat(buffers, nread);\n    _close(this);\n\n    return buf;\n  }\n\n  assert(this._handle, 'zlib binding closed');\n  var req = this._handle.write(flushFlag, chunk, // in\n  inOff, // in_off\n  availInBefore, // in_len\n  this._buffer, // out\n  this._offset, //out_off\n  availOutBefore); // out_len\n\n  req.buffer = chunk;\n  req.callback = callback;\n\n  function callback(availInAfter, availOutAfter) {\n    // When the callback is used in an async write, the callback's\n    // context is the `req` object that was created. The req object\n    // is === this._handle, and that's why it's important to null\n    // out the values after they are done being used. `this._handle`\n    // can stay in memory longer than the callback and buffer are needed.\n    if (this) {\n      this.buffer = null;\n      this.callback = null;\n    }\n\n    if (self._hadError) return;\n\n    var have = availOutBefore - availOutAfter;\n    assert(have >= 0, 'have should not go down');\n\n    if (have > 0) {\n      var out = self._buffer.slice(self._offset, self._offset + have);\n      self._offset += have;\n      // serve some output to the consumer.\n      if (async) {\n        self.push(out);\n      } else {\n        buffers.push(out);\n        nread += out.length;\n      }\n    }\n\n    // exhausted the output buffer, or used all the input create a new one.\n    if (availOutAfter === 0 || self._offset >= self._chunkSize) {\n      availOutBefore = self._chunkSize;\n      self._offset = 0;\n      self._buffer = Buffer.allocUnsafe(self._chunkSize);\n    }\n\n    if (availOutAfter === 0) {\n      // Not actually done.  Need to reprocess.\n      // Also, update the availInBefore to the availInAfter value,\n      // so that if we have to hit it a third (fourth, etc.) time,\n      // it'll have the correct byte counts.\n      inOff += availInBefore - availInAfter;\n      availInBefore = availInAfter;\n\n      if (!async) return true;\n\n      var newReq = self._handle.write(flushFlag, chunk, inOff, availInBefore, self._buffer, self._offset, self._chunkSize);\n      newReq.callback = callback; // this same function\n      newReq.buffer = chunk;\n      return;\n    }\n\n    if (!async) return false;\n\n    // finished with the chunk.\n    cb();\n  }\n};\n\nutil.inherits(Deflate, Zlib);\nutil.inherits(Inflate, Zlib);\nutil.inherits(Gzip, Zlib);\nutil.inherits(Gunzip, Zlib);\nutil.inherits(DeflateRaw, Zlib);\nutil.inherits(InflateRaw, Zlib);\nutil.inherits(Unzip, Zlib);\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11)))\n\n/***/ }),\n/* 49 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(global, process) {// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nvar formatRegExp = /%[sdj%]/g;\nexports.format = function(f) {\n  if (!isString(f)) {\n    var objects = [];\n    for (var i = 0; i < arguments.length; i++) {\n      objects.push(inspect(arguments[i]));\n    }\n    return objects.join(' ');\n  }\n\n  var i = 1;\n  var args = arguments;\n  var len = args.length;\n  var str = String(f).replace(formatRegExp, function(x) {\n    if (x === '%%') return '%';\n    if (i >= len) return x;\n    switch (x) {\n      case '%s': return String(args[i++]);\n      case '%d': return Number(args[i++]);\n      case '%j':\n        try {\n          return JSON.stringify(args[i++]);\n        } catch (_) {\n          return '[Circular]';\n        }\n      default:\n        return x;\n    }\n  });\n  for (var x = args[i]; i < len; x = args[++i]) {\n    if (isNull(x) || !isObject(x)) {\n      str += ' ' + x;\n    } else {\n      str += ' ' + inspect(x);\n    }\n  }\n  return str;\n};\n\n\n// Mark that a method should not be used.\n// Returns a modified function which warns once by default.\n// If --no-deprecation is set, then it is a no-op.\nexports.deprecate = function(fn, msg) {\n  // Allow for deprecating things in the process of starting up.\n  if (isUndefined(global.process)) {\n    return function() {\n      return exports.deprecate(fn, msg).apply(this, arguments);\n    };\n  }\n\n  if (process.noDeprecation === true) {\n    return fn;\n  }\n\n  var warned = false;\n  function deprecated() {\n    if (!warned) {\n      if (process.throwDeprecation) {\n        throw new Error(msg);\n      } else if (process.traceDeprecation) {\n        console.trace(msg);\n      } else {\n        console.error(msg);\n      }\n      warned = true;\n    }\n    return fn.apply(this, arguments);\n  }\n\n  return deprecated;\n};\n\n\nvar debugs = {};\nvar debugEnviron;\nexports.debuglog = function(set) {\n  if (isUndefined(debugEnviron))\n    debugEnviron = process.env.NODE_DEBUG || '';\n  set = set.toUpperCase();\n  if (!debugs[set]) {\n    if (new RegExp('\\\\b' + set + '\\\\b', 'i').test(debugEnviron)) {\n      var pid = process.pid;\n      debugs[set] = function() {\n        var msg = exports.format.apply(exports, arguments);\n        console.error('%s %d: %s', set, pid, msg);\n      };\n    } else {\n      debugs[set] = function() {};\n    }\n  }\n  return debugs[set];\n};\n\n\n/**\n * Echos the value of a value. Trys to print the value out\n * in the best way possible given the different types.\n *\n * @param {Object} obj The object to print out.\n * @param {Object} opts Optional options object that alters the output.\n */\n/* legacy: obj, showHidden, depth, colors*/\nfunction inspect(obj, opts) {\n  // default options\n  var ctx = {\n    seen: [],\n    stylize: stylizeNoColor\n  };\n  // legacy...\n  if (arguments.length >= 3) ctx.depth = arguments[2];\n  if (arguments.length >= 4) ctx.colors = arguments[3];\n  if (isBoolean(opts)) {\n    // legacy...\n    ctx.showHidden = opts;\n  } else if (opts) {\n    // got an \"options\" object\n    exports._extend(ctx, opts);\n  }\n  // set default options\n  if (isUndefined(ctx.showHidden)) ctx.showHidden = false;\n  if (isUndefined(ctx.depth)) ctx.depth = 2;\n  if (isUndefined(ctx.colors)) ctx.colors = false;\n  if (isUndefined(ctx.customInspect)) ctx.customInspect = true;\n  if (ctx.colors) ctx.stylize = stylizeWithColor;\n  return formatValue(ctx, obj, ctx.depth);\n}\nexports.inspect = inspect;\n\n\n// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics\ninspect.colors = {\n  'bold' : [1, 22],\n  'italic' : [3, 23],\n  'underline' : [4, 24],\n  'inverse' : [7, 27],\n  'white' : [37, 39],\n  'grey' : [90, 39],\n  'black' : [30, 39],\n  'blue' : [34, 39],\n  'cyan' : [36, 39],\n  'green' : [32, 39],\n  'magenta' : [35, 39],\n  'red' : [31, 39],\n  'yellow' : [33, 39]\n};\n\n// Don't use 'blue' not visible on cmd.exe\ninspect.styles = {\n  'special': 'cyan',\n  'number': 'yellow',\n  'boolean': 'yellow',\n  'undefined': 'grey',\n  'null': 'bold',\n  'string': 'green',\n  'date': 'magenta',\n  // \"name\": intentionally not styling\n  'regexp': 'red'\n};\n\n\nfunction stylizeWithColor(str, styleType) {\n  var style = inspect.styles[styleType];\n\n  if (style) {\n    return '\\u001b[' + inspect.colors[style][0] + 'm' + str +\n           '\\u001b[' + inspect.colors[style][1] + 'm';\n  } else {\n    return str;\n  }\n}\n\n\nfunction stylizeNoColor(str, styleType) {\n  return str;\n}\n\n\nfunction arrayToHash(array) {\n  var hash = {};\n\n  array.forEach(function(val, idx) {\n    hash[val] = true;\n  });\n\n  return hash;\n}\n\n\nfunction formatValue(ctx, value, recurseTimes) {\n  // Provide a hook for user-specified inspect functions.\n  // Check that value is an object with an inspect function on it\n  if (ctx.customInspect &&\n      value &&\n      isFunction(value.inspect) &&\n      // Filter out the util module, it's inspect function is special\n      value.inspect !== exports.inspect &&\n      // Also filter out any prototype objects using the circular check.\n      !(value.constructor && value.constructor.prototype === value)) {\n    var ret = value.inspect(recurseTimes, ctx);\n    if (!isString(ret)) {\n      ret = formatValue(ctx, ret, recurseTimes);\n    }\n    return ret;\n  }\n\n  // Primitive types cannot have properties\n  var primitive = formatPrimitive(ctx, value);\n  if (primitive) {\n    return primitive;\n  }\n\n  // Look up the keys of the object.\n  var keys = Object.keys(value);\n  var visibleKeys = arrayToHash(keys);\n\n  if (ctx.showHidden) {\n    keys = Object.getOwnPropertyNames(value);\n  }\n\n  // IE doesn't make error fields non-enumerable\n  // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx\n  if (isError(value)\n      && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {\n    return formatError(value);\n  }\n\n  // Some type of object without properties can be shortcutted.\n  if (keys.length === 0) {\n    if (isFunction(value)) {\n      var name = value.name ? ': ' + value.name : '';\n      return ctx.stylize('[Function' + name + ']', 'special');\n    }\n    if (isRegExp(value)) {\n      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');\n    }\n    if (isDate(value)) {\n      return ctx.stylize(Date.prototype.toString.call(value), 'date');\n    }\n    if (isError(value)) {\n      return formatError(value);\n    }\n  }\n\n  var base = '', array = false, braces = ['{', '}'];\n\n  // Make Array say that they are Array\n  if (isArray(value)) {\n    array = true;\n    braces = ['[', ']'];\n  }\n\n  // Make functions say that they are functions\n  if (isFunction(value)) {\n    var n = value.name ? ': ' + value.name : '';\n    base = ' [Function' + n + ']';\n  }\n\n  // Make RegExps say that they are RegExps\n  if (isRegExp(value)) {\n    base = ' ' + RegExp.prototype.toString.call(value);\n  }\n\n  // Make dates with properties first say the date\n  if (isDate(value)) {\n    base = ' ' + Date.prototype.toUTCString.call(value);\n  }\n\n  // Make error with message first say the error\n  if (isError(value)) {\n    base = ' ' + formatError(value);\n  }\n\n  if (keys.length === 0 && (!array || value.length == 0)) {\n    return braces[0] + base + braces[1];\n  }\n\n  if (recurseTimes < 0) {\n    if (isRegExp(value)) {\n      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');\n    } else {\n      return ctx.stylize('[Object]', 'special');\n    }\n  }\n\n  ctx.seen.push(value);\n\n  var output;\n  if (array) {\n    output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);\n  } else {\n    output = keys.map(function(key) {\n      return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);\n    });\n  }\n\n  ctx.seen.pop();\n\n  return reduceToSingleString(output, base, braces);\n}\n\n\nfunction formatPrimitive(ctx, value) {\n  if (isUndefined(value))\n    return ctx.stylize('undefined', 'undefined');\n  if (isString(value)) {\n    var simple = '\\'' + JSON.stringify(value).replace(/^\"|\"$/g, '')\n                                             .replace(/'/g, \"\\\\'\")\n                                             .replace(/\\\\\"/g, '\"') + '\\'';\n    return ctx.stylize(simple, 'string');\n  }\n  if (isNumber(value))\n    return ctx.stylize('' + value, 'number');\n  if (isBoolean(value))\n    return ctx.stylize('' + value, 'boolean');\n  // For some reason typeof null is \"object\", so special case here.\n  if (isNull(value))\n    return ctx.stylize('null', 'null');\n}\n\n\nfunction formatError(value) {\n  return '[' + Error.prototype.toString.call(value) + ']';\n}\n\n\nfunction formatArray(ctx, value, recurseTimes, visibleKeys, keys) {\n  var output = [];\n  for (var i = 0, l = value.length; i < l; ++i) {\n    if (hasOwnProperty(value, String(i))) {\n      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,\n          String(i), true));\n    } else {\n      output.push('');\n    }\n  }\n  keys.forEach(function(key) {\n    if (!key.match(/^\\d+$/)) {\n      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,\n          key, true));\n    }\n  });\n  return output;\n}\n\n\nfunction formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {\n  var name, str, desc;\n  desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };\n  if (desc.get) {\n    if (desc.set) {\n      str = ctx.stylize('[Getter/Setter]', 'special');\n    } else {\n      str = ctx.stylize('[Getter]', 'special');\n    }\n  } else {\n    if (desc.set) {\n      str = ctx.stylize('[Setter]', 'special');\n    }\n  }\n  if (!hasOwnProperty(visibleKeys, key)) {\n    name = '[' + key + ']';\n  }\n  if (!str) {\n    if (ctx.seen.indexOf(desc.value) < 0) {\n      if (isNull(recurseTimes)) {\n        str = formatValue(ctx, desc.value, null);\n      } else {\n        str = formatValue(ctx, desc.value, recurseTimes - 1);\n      }\n      if (str.indexOf('\\n') > -1) {\n        if (array) {\n          str = str.split('\\n').map(function(line) {\n            return '  ' + line;\n          }).join('\\n').substr(2);\n        } else {\n          str = '\\n' + str.split('\\n').map(function(line) {\n            return '   ' + line;\n          }).join('\\n');\n        }\n      }\n    } else {\n      str = ctx.stylize('[Circular]', 'special');\n    }\n  }\n  if (isUndefined(name)) {\n    if (array && key.match(/^\\d+$/)) {\n      return str;\n    }\n    name = JSON.stringify('' + key);\n    if (name.match(/^\"([a-zA-Z_][a-zA-Z_0-9]*)\"$/)) {\n      name = name.substr(1, name.length - 2);\n      name = ctx.stylize(name, 'name');\n    } else {\n      name = name.replace(/'/g, \"\\\\'\")\n                 .replace(/\\\\\"/g, '\"')\n                 .replace(/(^\"|\"$)/g, \"'\");\n      name = ctx.stylize(name, 'string');\n    }\n  }\n\n  return name + ': ' + str;\n}\n\n\nfunction reduceToSingleString(output, base, braces) {\n  var numLinesEst = 0;\n  var length = output.reduce(function(prev, cur) {\n    numLinesEst++;\n    if (cur.indexOf('\\n') >= 0) numLinesEst++;\n    return prev + cur.replace(/\\u001b\\[\\d\\d?m/g, '').length + 1;\n  }, 0);\n\n  if (length > 60) {\n    return braces[0] +\n           (base === '' ? '' : base + '\\n ') +\n           ' ' +\n           output.join(',\\n  ') +\n           ' ' +\n           braces[1];\n  }\n\n  return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];\n}\n\n\n// NOTE: These type checking functions intentionally don't use `instanceof`\n// because it is fragile and can be easily faked with `Object.create()`.\nfunction isArray(ar) {\n  return Array.isArray(ar);\n}\nexports.isArray = isArray;\n\nfunction isBoolean(arg) {\n  return typeof arg === 'boolean';\n}\nexports.isBoolean = isBoolean;\n\nfunction isNull(arg) {\n  return arg === null;\n}\nexports.isNull = isNull;\n\nfunction isNullOrUndefined(arg) {\n  return arg == null;\n}\nexports.isNullOrUndefined = isNullOrUndefined;\n\nfunction isNumber(arg) {\n  return typeof arg === 'number';\n}\nexports.isNumber = isNumber;\n\nfunction isString(arg) {\n  return typeof arg === 'string';\n}\nexports.isString = isString;\n\nfunction isSymbol(arg) {\n  return typeof arg === 'symbol';\n}\nexports.isSymbol = isSymbol;\n\nfunction isUndefined(arg) {\n  return arg === void 0;\n}\nexports.isUndefined = isUndefined;\n\nfunction isRegExp(re) {\n  return isObject(re) && objectToString(re) === '[object RegExp]';\n}\nexports.isRegExp = isRegExp;\n\nfunction isObject(arg) {\n  return typeof arg === 'object' && arg !== null;\n}\nexports.isObject = isObject;\n\nfunction isDate(d) {\n  return isObject(d) && objectToString(d) === '[object Date]';\n}\nexports.isDate = isDate;\n\nfunction isError(e) {\n  return isObject(e) &&\n      (objectToString(e) === '[object Error]' || e instanceof Error);\n}\nexports.isError = isError;\n\nfunction isFunction(arg) {\n  return typeof arg === 'function';\n}\nexports.isFunction = isFunction;\n\nfunction isPrimitive(arg) {\n  return arg === null ||\n         typeof arg === 'boolean' ||\n         typeof arg === 'number' ||\n         typeof arg === 'string' ||\n         typeof arg === 'symbol' ||  // ES6 symbol\n         typeof arg === 'undefined';\n}\nexports.isPrimitive = isPrimitive;\n\nexports.isBuffer = __webpack_require__(151);\n\nfunction objectToString(o) {\n  return Object.prototype.toString.call(o);\n}\n\n\nfunction pad(n) {\n  return n < 10 ? '0' + n.toString(10) : n.toString(10);\n}\n\n\nvar months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',\n              'Oct', 'Nov', 'Dec'];\n\n// 26 Feb 16:19:34\nfunction timestamp() {\n  var d = new Date();\n  var time = [pad(d.getHours()),\n              pad(d.getMinutes()),\n              pad(d.getSeconds())].join(':');\n  return [d.getDate(), months[d.getMonth()], time].join(' ');\n}\n\n\n// log is just a thin wrapper to console.log that prepends a timestamp\nexports.log = function() {\n  console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));\n};\n\n\n/**\n * Inherit the prototype methods from one constructor into another.\n *\n * The Function.prototype.inherits from lang.js rewritten as a standalone\n * function (not on Function.prototype). NOTE: If this file is to be loaded\n * during bootstrapping this function needs to be rewritten using some native\n * functions as prototype setup using normal JavaScript does not work as\n * expected during bootstrapping (see mirror.js in r114903).\n *\n * @param {function} ctor Constructor function which needs to inherit the\n *     prototype.\n * @param {function} superCtor Constructor function to inherit prototype from.\n */\nexports.inherits = __webpack_require__(152);\n\nexports._extend = function(origin, add) {\n  // Don't do anything if add isn't an object\n  if (!add || !isObject(add)) return origin;\n\n  var keys = Object.keys(add);\n  var i = keys.length;\n  while (i--) {\n    origin[keys[i]] = add[keys[i]];\n  }\n  return origin;\n};\n\nfunction hasOwnProperty(obj, prop) {\n  return Object.prototype.hasOwnProperty.call(obj, prop);\n}\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7), __webpack_require__(11)))\n\n/***/ }),\n/* 50 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6\n(function() {\n  var EmbeddedFont, PDFFont, StandardFont, fontkit;\n\n  fontkit = __webpack_require__(167);\n\n  PDFFont = (function() {\n    PDFFont.open = function(document, src, family, id) {\n      var font;\n      if (typeof src === 'string') {\n        if (StandardFont.isStandardFont(src)) {\n          return new StandardFont(document, src, id);\n        }\n        font = fontkit.openSync(src, family);\n      } else if (Buffer.isBuffer(src)) {\n        font = fontkit.create(src, family);\n      } else if (src instanceof Uint8Array) {\n        font = fontkit.create(new Buffer(src), family);\n      } else if (src instanceof ArrayBuffer) {\n        font = fontkit.create(new Buffer(new Uint8Array(src)), family);\n      }\n      if (font == null) {\n        throw new Error('Not a supported font format or standard PDF font.');\n      }\n      return new EmbeddedFont(document, font, id);\n    };\n\n    function PDFFont() {\n      throw new Error('Cannot construct a PDFFont directly.');\n    }\n\n    PDFFont.prototype.encode = function(text) {\n      throw new Error('Must be implemented by subclasses');\n    };\n\n    PDFFont.prototype.widthOfString = function(text) {\n      throw new Error('Must be implemented by subclasses');\n    };\n\n    PDFFont.prototype.ref = function() {\n      return this.dictionary != null ? this.dictionary : this.dictionary = this.document.ref();\n    };\n\n    PDFFont.prototype.finalize = function() {\n      if (this.embedded || (this.dictionary == null)) {\n        return;\n      }\n      this.embed();\n      return this.embedded = true;\n    };\n\n    PDFFont.prototype.embed = function() {\n      throw new Error('Must be implemented by subclasses');\n    };\n\n    PDFFont.prototype.lineHeight = function(size, includeGap) {\n      var gap;\n      if (includeGap == null) {\n        includeGap = false;\n      }\n      gap = includeGap ? this.lineGap : 0;\n      return (this.ascender + gap - this.descender) / 1000 * size;\n    };\n\n    return PDFFont;\n\n  })();\n\n  module.exports = PDFFont;\n\n  StandardFont = __webpack_require__(292);\n\n  EmbeddedFont = __webpack_require__(294);\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 51 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.7.1\n(function() {\n  var DecodeStream, iconv;\n\n  try {\n    iconv = __webpack_require__(52);\n  } catch (_error) {}\n\n  DecodeStream = (function() {\n    var key;\n\n    function DecodeStream(buffer) {\n      this.buffer = buffer;\n      this.pos = 0;\n      this.length = this.buffer.length;\n    }\n\n    DecodeStream.TYPES = {\n      UInt8: 1,\n      UInt16: 2,\n      UInt24: 3,\n      UInt32: 4,\n      Int8: 1,\n      Int16: 2,\n      Int24: 3,\n      Int32: 4,\n      Float: 4,\n      Double: 8\n    };\n\n    for (key in Buffer.prototype) {\n      if (key.slice(0, 4) === 'read') {\n        (function(key) {\n          var bytes;\n          bytes = DecodeStream.TYPES[key.replace(/read|[BL]E/g, '')];\n          return DecodeStream.prototype[key] = function() {\n            var ret;\n            ret = this.buffer[key](this.pos);\n            this.pos += bytes;\n            return ret;\n          };\n        })(key);\n      }\n    }\n\n    DecodeStream.prototype.readString = function(length, encoding) {\n      var buf, byte, i, _i, _ref;\n      if (encoding == null) {\n        encoding = 'ascii';\n      }\n      switch (encoding) {\n        case 'utf16le':\n        case 'ucs2':\n        case 'utf8':\n        case 'ascii':\n          return this.buffer.toString(encoding, this.pos, this.pos += length);\n        case 'utf16be':\n          buf = new Buffer(this.readBuffer(length));\n          for (i = _i = 0, _ref = buf.length - 1; _i < _ref; i = _i += 2) {\n            byte = buf[i];\n            buf[i] = buf[i + 1];\n            buf[i + 1] = byte;\n          }\n          return buf.toString('utf16le');\n        default:\n          buf = this.readBuffer(length);\n          if (iconv) {\n            try {\n              return iconv.decode(buf, encoding);\n            } catch (_error) {}\n          }\n          return buf;\n      }\n    };\n\n    DecodeStream.prototype.readBuffer = function(length) {\n      return this.buffer.slice(this.pos, this.pos += length);\n    };\n\n    DecodeStream.prototype.readUInt24BE = function() {\n      return (this.readUInt16BE() << 8) + this.readUInt8();\n    };\n\n    DecodeStream.prototype.readUInt24LE = function() {\n      return this.readUInt16LE() + (this.readUInt8() << 16);\n    };\n\n    DecodeStream.prototype.readInt24BE = function() {\n      return (this.readInt16BE() << 8) + this.readUInt8();\n    };\n\n    DecodeStream.prototype.readInt24LE = function() {\n      return this.readUInt16LE() + (this.readInt8() << 16);\n    };\n\n    return DecodeStream;\n\n  })();\n\n  module.exports = DecodeStream;\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 52 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(process) {\n\n// Some environments don't have global Buffer (e.g. React Native).\n// Solution would be installing npm modules \"buffer\" and \"stream\" explicitly.\nvar Buffer = __webpack_require__(1).Buffer;\n\nvar bomHandling = __webpack_require__(170),\n    iconv = module.exports;\n\n// All codecs and aliases are kept here, keyed by encoding name/alias.\n// They are lazy loaded in `iconv.getCodec` from `encodings/index.js`.\niconv.encodings = null;\n\n// Characters emitted in case of error.\niconv.defaultCharUnicode = '�';\niconv.defaultCharSingleByte = '?';\n\n// Public API.\niconv.encode = function encode(str, encoding, options) {\n    str = \"\" + (str || \"\"); // Ensure string.\n\n    var encoder = iconv.getEncoder(encoding, options);\n\n    var res = encoder.write(str);\n    var trail = encoder.end();\n    \n    return (trail && trail.length > 0) ? Buffer.concat([res, trail]) : res;\n}\n\niconv.decode = function decode(buf, encoding, options) {\n    if (typeof buf === 'string') {\n        if (!iconv.skipDecodeWarning) {\n            console.error('Iconv-lite warning: decode()-ing strings is deprecated. Refer to https://github.com/ashtuchkin/iconv-lite/wiki/Use-Buffers-when-decoding');\n            iconv.skipDecodeWarning = true;\n        }\n\n        buf = new Buffer(\"\" + (buf || \"\"), \"binary\"); // Ensure buffer.\n    }\n\n    var decoder = iconv.getDecoder(encoding, options);\n\n    var res = decoder.write(buf);\n    var trail = decoder.end();\n\n    return trail ? (res + trail) : res;\n}\n\niconv.encodingExists = function encodingExists(enc) {\n    try {\n        iconv.getCodec(enc);\n        return true;\n    } catch (e) {\n        return false;\n    }\n}\n\n// Legacy aliases to convert functions\niconv.toEncoding = iconv.encode;\niconv.fromEncoding = iconv.decode;\n\n// Search for a codec in iconv.encodings. Cache codec data in iconv._codecDataCache.\niconv._codecDataCache = {};\niconv.getCodec = function getCodec(encoding) {\n    if (!iconv.encodings)\n        iconv.encodings = __webpack_require__(171); // Lazy load all encoding definitions.\n    \n    // Canonicalize encoding name: strip all non-alphanumeric chars and appended year.\n    var enc = (''+encoding).toLowerCase().replace(/[^0-9a-z]|:\\d{4}$/g, \"\");\n\n    // Traverse iconv.encodings to find actual codec.\n    var codecOptions = {};\n    while (true) {\n        var codec = iconv._codecDataCache[enc];\n        if (codec)\n            return codec;\n\n        var codecDef = iconv.encodings[enc];\n\n        switch (typeof codecDef) {\n            case \"string\": // Direct alias to other encoding.\n                enc = codecDef;\n                break;\n\n            case \"object\": // Alias with options. Can be layered.\n                for (var key in codecDef)\n                    codecOptions[key] = codecDef[key];\n\n                if (!codecOptions.encodingName)\n                    codecOptions.encodingName = enc;\n                \n                enc = codecDef.type;\n                break;\n\n            case \"function\": // Codec itself.\n                if (!codecOptions.encodingName)\n                    codecOptions.encodingName = enc;\n\n                // The codec function must load all tables and return object with .encoder and .decoder methods.\n                // It'll be called only once (for each different options object).\n                codec = new codecDef(codecOptions, iconv);\n\n                iconv._codecDataCache[codecOptions.encodingName] = codec; // Save it to be reused later.\n                return codec;\n\n            default:\n                throw new Error(\"Encoding not recognized: '\" + encoding + \"' (searched as: '\"+enc+\"')\");\n        }\n    }\n}\n\niconv.getEncoder = function getEncoder(encoding, options) {\n    var codec = iconv.getCodec(encoding),\n        encoder = new codec.encoder(options, codec);\n\n    if (codec.bomAware && options && options.addBOM)\n        encoder = new bomHandling.PrependBOM(encoder, options);\n\n    return encoder;\n}\n\niconv.getDecoder = function getDecoder(encoding, options) {\n    var codec = iconv.getCodec(encoding),\n        decoder = new codec.decoder(options, codec);\n\n    if (codec.bomAware && !(options && options.stripBOM === false))\n        decoder = new bomHandling.StripBOM(decoder, options);\n\n    return decoder;\n}\n\n\n// Load extensions in Node. All of them are omitted in Browserify build via 'browser' field in package.json.\nvar nodeVer = typeof process !== 'undefined' && process.versions && process.versions.node;\nif (nodeVer) {\n\n    // Load streaming support in Node v0.10+\n    var nodeVerArr = nodeVer.split(\".\").map(Number);\n    if (nodeVerArr[0] > 0 || nodeVerArr[1] >= 10) {\n        __webpack_require__(185)(iconv);\n    }\n\n    // Load Node primitive extensions.\n    __webpack_require__(186)(iconv);\n}\n\nif (false) {\n    console.error(\"iconv-lite warning: javascript files use encoding different from utf-8. See https://github.com/ashtuchkin/iconv-lite/wiki/Javascript-source-file-encodings for more info.\");\n}\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11)))\n\n/***/ }),\n/* 53 */\n/***/ (function(module, exports) {\n\nmodule.exports = [[\"0\",\"\\u0000\",127,\"€\"],[\"8140\",\"丂丄丅丆丏丒丗丟丠両丣並丩丮丯丱丳丵丷丼乀乁乂乄乆乊乑乕乗乚乛乢乣乤乥乧乨乪\",5,\"乲乴\",9,\"乿\",6,\"亇亊\"],[\"8180\",\"亐亖亗亙亜亝亞亣亪亯亰亱亴亶亷亸亹亼亽亾仈仌仏仐仒仚仛仜仠仢仦仧仩仭仮仯仱仴仸仹仺仼仾伀伂\",6,\"伋伌伒\",4,\"伜伝伡伣伨伩伬伭伮伱伳伵伷伹伻伾\",4,\"佄佅佇\",5,\"佒佔佖佡佢佦佨佪佫佭佮佱佲併佷佸佹佺佽侀侁侂侅來侇侊侌侎侐侒侓侕侖侘侙侚侜侞侟価侢\"],[\"8240\",\"侤侫侭侰\",4,\"侶\",8,\"俀俁係俆俇俈俉俋俌俍俒\",4,\"俙俛俠俢俤俥俧俫俬俰俲俴俵俶俷俹俻俼俽俿\",11],[\"8280\",\"個倎倐們倓倕倖倗倛倝倞倠倢倣値倧倫倯\",10,\"倻倽倿偀偁偂偄偅偆偉偊偋偍偐\",4,\"偖偗偘偙偛偝\",7,\"偦\",5,\"偭\",8,\"偸偹偺偼偽傁傂傃傄傆傇傉傊傋傌傎\",20,\"傤傦傪傫傭\",4,\"傳\",6,\"傼\"],[\"8340\",\"傽\",17,\"僐\",5,\"僗僘僙僛\",10,\"僨僩僪僫僯僰僱僲僴僶\",4,\"僼\",9,\"儈\"],[\"8380\",\"儉儊儌\",5,\"儓\",13,\"儢\",28,\"兂兇兊兌兎兏児兒兓兗兘兙兛兝\",4,\"兣兤兦內兩兪兯兲兺兾兿冃冄円冇冊冋冎冏冐冑冓冔冘冚冝冞冟冡冣冦\",4,\"冭冮冴冸冹冺冾冿凁凂凃凅凈凊凍凎凐凒\",5],[\"8440\",\"凘凙凚凜凞凟凢凣凥\",5,\"凬凮凱凲凴凷凾刄刅刉刋刌刏刐刓刔刕刜刞刟刡刢刣別刦刧刪刬刯刱刲刴刵刼刾剄\",5,\"剋剎剏剒剓剕剗剘\"],[\"8480\",\"剙剚剛剝剟剠剢剣剤剦剨剫剬剭剮剰剱剳\",9,\"剾劀劃\",4,\"劉\",6,\"劑劒劔\",6,\"劜劤劥劦劧劮劯劰労\",9,\"勀勁勂勄勅勆勈勊勌勍勎勏勑勓勔動勗務\",5,\"勠勡勢勣勥\",10,\"勱\",7,\"勻勼勽匁匂匃匄匇匉匊匋匌匎\"],[\"8540\",\"匑匒匓匔匘匛匜匞匟匢匤匥匧匨匩匫匬匭匯\",9,\"匼匽區卂卄卆卋卌卍卐協単卙卛卝卥卨卪卬卭卲卶卹卻卼卽卾厀厁厃厇厈厊厎厏\"],[\"8580\",\"厐\",4,\"厖厗厙厛厜厞厠厡厤厧厪厫厬厭厯\",6,\"厷厸厹厺厼厽厾叀參\",4,\"収叏叐叒叓叕叚叜叝叞叡叢叧叴叺叾叿吀吂吅吇吋吔吘吙吚吜吢吤吥吪吰吳吶吷吺吽吿呁呂呄呅呇呉呌呍呎呏呑呚呝\",4,\"呣呥呧呩\",7,\"呴呹呺呾呿咁咃咅咇咈咉咊咍咑咓咗咘咜咞咟咠咡\"],[\"8640\",\"咢咥咮咰咲咵咶咷咹咺咼咾哃哅哊哋哖哘哛哠\",4,\"哫哬哯哰哱哴\",5,\"哻哾唀唂唃唄唅唈唊\",4,\"唒唓唕\",5,\"唜唝唞唟唡唥唦\"],[\"8680\",\"唨唩唫唭唲唴唵唶唸唹唺唻唽啀啂啅啇啈啋\",4,\"啑啒啓啔啗\",4,\"啝啞啟啠啢啣啨啩啫啯\",5,\"啹啺啽啿喅喆喌喍喎喐喒喓喕喖喗喚喛喞喠\",6,\"喨\",8,\"喲喴営喸喺喼喿\",4,\"嗆嗇嗈嗊嗋嗎嗏嗐嗕嗗\",4,\"嗞嗠嗢嗧嗩嗭嗮嗰嗱嗴嗶嗸\",4,\"嗿嘂嘃嘄嘅\"],[\"8740\",\"嘆嘇嘊嘋嘍嘐\",7,\"嘙嘚嘜嘝嘠嘡嘢嘥嘦嘨嘩嘪嘫嘮嘯嘰嘳嘵嘷嘸嘺嘼嘽嘾噀\",11,\"噏\",4,\"噕噖噚噛噝\",4],[\"8780\",\"噣噥噦噧噭噮噯噰噲噳噴噵噷噸噹噺噽\",7,\"嚇\",6,\"嚐嚑嚒嚔\",14,\"嚤\",10,\"嚰\",6,\"嚸嚹嚺嚻嚽\",12,\"囋\",8,\"囕囖囘囙囜団囥\",5,\"囬囮囯囲図囶囷囸囻囼圀圁圂圅圇國\",6],[\"8840\",\"園\",9,\"圝圞圠圡圢圤圥圦圧圫圱圲圴\",4,\"圼圽圿坁坃坄坅坆坈坉坋坒\",4,\"坘坙坢坣坥坧坬坮坰坱坲坴坵坸坹坺坽坾坿垀\"],[\"8880\",\"垁垇垈垉垊垍\",4,\"垔\",6,\"垜垝垞垟垥垨垪垬垯垰垱垳垵垶垷垹\",8,\"埄\",6,\"埌埍埐埑埓埖埗埛埜埞埡埢埣埥\",7,\"埮埰埱埲埳埵埶執埻埼埾埿堁堃堄堅堈堉堊堌堎堏堐堒堓堔堖堗堘堚堛堜堝堟堢堣堥\",4,\"堫\",4,\"報堲堳場堶\",7],[\"8940\",\"堾\",5,\"塅\",6,\"塎塏塐塒塓塕塖塗塙\",4,\"塟\",5,\"塦\",4,\"塭\",16,\"塿墂墄墆墇墈墊墋墌\"],[\"8980\",\"墍\",4,\"墔\",4,\"墛墜墝墠\",7,\"墪\",17,\"墽墾墿壀壂壃壄壆\",10,\"壒壓壔壖\",13,\"壥\",5,\"壭壯壱売壴壵壷壸壺\",7,\"夃夅夆夈\",4,\"夎夐夑夒夓夗夘夛夝夞夠夡夢夣夦夨夬夰夲夳夵夶夻\"],[\"8a40\",\"夽夾夿奀奃奅奆奊奌奍奐奒奓奙奛\",4,\"奡奣奤奦\",12,\"奵奷奺奻奼奾奿妀妅妉妋妌妎妏妐妑妔妕妘妚妛妜妝妟妠妡妢妦\"],[\"8a80\",\"妧妬妭妰妱妳\",5,\"妺妼妽妿\",6,\"姇姈姉姌姍姎姏姕姖姙姛姞\",4,\"姤姦姧姩姪姫姭\",11,\"姺姼姽姾娀娂娊娋娍娎娏娐娒娔娕娖娗娙娚娛娝娞娡娢娤娦娧娨娪\",6,\"娳娵娷\",4,\"娽娾娿婁\",4,\"婇婈婋\",9,\"婖婗婘婙婛\",5],[\"8b40\",\"婡婣婤婥婦婨婩婫\",8,\"婸婹婻婼婽婾媀\",17,\"媓\",6,\"媜\",13,\"媫媬\"],[\"8b80\",\"媭\",4,\"媴媶媷媹\",4,\"媿嫀嫃\",5,\"嫊嫋嫍\",4,\"嫓嫕嫗嫙嫚嫛嫝嫞嫟嫢嫤嫥嫧嫨嫪嫬\",4,\"嫲\",22,\"嬊\",11,\"嬘\",25,\"嬳嬵嬶嬸\",7,\"孁\",6],[\"8c40\",\"孈\",7,\"孒孖孞孠孡孧孨孫孭孮孯孲孴孶孷學孹孻孼孾孿宂宆宊宍宎宐宑宒宔宖実宧宨宩宬宭宮宯宱宲宷宺宻宼寀寁寃寈寉寊寋寍寎寏\"],[\"8c80\",\"寑寔\",8,\"寠寢寣實寧審\",4,\"寯寱\",6,\"寽対尀専尃尅將專尋尌對導尐尒尓尗尙尛尞尟尠尡尣尦尨尩尪尫尭尮尯尰尲尳尵尶尷屃屄屆屇屌屍屒屓屔屖屗屘屚屛屜屝屟屢層屧\",6,\"屰屲\",6,\"屻屼屽屾岀岃\",4,\"岉岊岋岎岏岒岓岕岝\",4,\"岤\",4],[\"8d40\",\"岪岮岯岰岲岴岶岹岺岻岼岾峀峂峃峅\",5,\"峌\",5,\"峓\",5,\"峚\",6,\"峢峣峧峩峫峬峮峯峱\",9,\"峼\",4],[\"8d80\",\"崁崄崅崈\",5,\"崏\",4,\"崕崗崘崙崚崜崝崟\",4,\"崥崨崪崫崬崯\",4,\"崵\",7,\"崿\",7,\"嵈嵉嵍\",10,\"嵙嵚嵜嵞\",10,\"嵪嵭嵮嵰嵱嵲嵳嵵\",12,\"嶃\",21,\"嶚嶛嶜嶞嶟嶠\"],[\"8e40\",\"嶡\",21,\"嶸\",12,\"巆\",6,\"巎\",12,\"巜巟巠巣巤巪巬巭\"],[\"8e80\",\"巰巵巶巸\",4,\"巿帀帄帇帉帊帋帍帎帒帓帗帞\",7,\"帨\",4,\"帯帰帲\",4,\"帹帺帾帿幀幁幃幆\",5,\"幍\",6,\"幖\",4,\"幜幝幟幠幣\",14,\"幵幷幹幾庁庂広庅庈庉庌庍庎庒庘庛庝庡庢庣庤庨\",4,\"庮\",4,\"庴庺庻庼庽庿\",6],[\"8f40\",\"廆廇廈廋\",5,\"廔廕廗廘廙廚廜\",11,\"廩廫\",8,\"廵廸廹廻廼廽弅弆弇弉弌弍弎弐弒弔弖弙弚弜弝弞弡弢弣弤\"],[\"8f80\",\"弨弫弬弮弰弲\",6,\"弻弽弾弿彁\",14,\"彑彔彙彚彛彜彞彟彠彣彥彧彨彫彮彯彲彴彵彶彸彺彽彾彿徃徆徍徎徏徑従徔徖徚徛徝從徟徠徢\",5,\"復徫徬徯\",5,\"徶徸徹徺徻徾\",4,\"忇忈忊忋忎忓忔忕忚忛応忞忟忢忣忥忦忨忩忬忯忰忲忳忴忶忷忹忺忼怇\"],[\"9040\",\"怈怉怋怌怐怑怓怗怘怚怞怟怢怣怤怬怭怮怰\",4,\"怶\",4,\"怽怾恀恄\",6,\"恌恎恏恑恓恔恖恗恘恛恜恞恟恠恡恥恦恮恱恲恴恵恷恾悀\"],[\"9080\",\"悁悂悅悆悇悈悊悋悎悏悐悑悓悕悗悘悙悜悞悡悢悤悥悧悩悪悮悰悳悵悶悷悹悺悽\",7,\"惇惈惉惌\",4,\"惒惓惔惖惗惙惛惞惡\",4,\"惪惱惲惵惷惸惻\",4,\"愂愃愄愅愇愊愋愌愐\",4,\"愖愗愘愙愛愜愝愞愡愢愥愨愩愪愬\",18,\"慀\",6],[\"9140\",\"慇慉態慍慏慐慒慓慔慖\",6,\"慞慟慠慡慣慤慥慦慩\",6,\"慱慲慳慴慶慸\",18,\"憌憍憏\",4,\"憕\"],[\"9180\",\"憖\",6,\"憞\",8,\"憪憫憭\",9,\"憸\",5,\"憿懀懁懃\",4,\"應懌\",4,\"懓懕\",16,\"懧\",13,\"懶\",8,\"戀\",5,\"戇戉戓戔戙戜戝戞戠戣戦戧戨戩戫戭戯戰戱戲戵戶戸\",4,\"扂扄扅扆扊\"],[\"9240\",\"扏扐払扖扗扙扚扜\",6,\"扤扥扨扱扲扴扵扷扸扺扻扽抁抂抃抅抆抇抈抋\",5,\"抔抙抜抝択抣抦抧抩抪抭抮抯抰抲抳抴抶抷抸抺抾拀拁\"],[\"9280\",\"拃拋拏拑拕拝拞拠拡拤拪拫拰拲拵拸拹拺拻挀挃挄挅挆挊挋挌挍挏挐挒挓挔挕挗挘挙挜挦挧挩挬挭挮挰挱挳\",5,\"挻挼挾挿捀捁捄捇捈捊捑捒捓捔捖\",7,\"捠捤捥捦捨捪捫捬捯捰捲捳捴捵捸捹捼捽捾捿掁掃掄掅掆掋掍掑掓掔掕掗掙\",6,\"採掤掦掫掯掱掲掵掶掹掻掽掿揀\"],[\"9340\",\"揁揂揃揅揇揈揊揋揌揑揓揔揕揗\",6,\"揟揢揤\",4,\"揫揬揮揯揰揱揳揵揷揹揺揻揼揾搃搄搆\",4,\"損搎搑搒搕\",5,\"搝搟搢搣搤\"],[\"9380\",\"搥搧搨搩搫搮\",5,\"搵\",4,\"搻搼搾摀摂摃摉摋\",6,\"摓摕摖摗摙\",4,\"摟\",7,\"摨摪摫摬摮\",9,\"摻\",6,\"撃撆撈\",8,\"撓撔撗撘撚撛撜撝撟\",4,\"撥撦撧撨撪撫撯撱撲撳撴撶撹撻撽撾撿擁擃擄擆\",6,\"擏擑擓擔擕擖擙據\"],[\"9440\",\"擛擜擝擟擠擡擣擥擧\",24,\"攁\",7,\"攊\",7,\"攓\",4,\"攙\",8],[\"9480\",\"攢攣攤攦\",4,\"攬攭攰攱攲攳攷攺攼攽敀\",4,\"敆敇敊敋敍敎敐敒敓敔敗敘敚敜敟敠敡敤敥敧敨敩敪敭敮敯敱敳敵敶數\",14,\"斈斉斊斍斎斏斒斔斕斖斘斚斝斞斠斢斣斦斨斪斬斮斱\",7,\"斺斻斾斿旀旂旇旈旉旊旍旐旑旓旔旕旘\",7,\"旡旣旤旪旫\"],[\"9540\",\"旲旳旴旵旸旹旻\",4,\"昁昄昅昇昈昉昋昍昐昑昒昖昗昘昚昛昜昞昡昢昣昤昦昩昪昫昬昮昰昲昳昷\",4,\"昽昿晀時晄\",6,\"晍晎晐晑晘\"],[\"9580\",\"晙晛晜晝晞晠晢晣晥晧晩\",4,\"晱晲晳晵晸晹晻晼晽晿暀暁暃暅暆暈暉暊暋暍暎暏暐暒暓暔暕暘\",4,\"暞\",8,\"暩\",4,\"暯\",4,\"暵暶暷暸暺暻暼暽暿\",25,\"曚曞\",7,\"曧曨曪\",5,\"曱曵曶書曺曻曽朁朂會\"],[\"9640\",\"朄朅朆朇朌朎朏朑朒朓朖朘朙朚朜朞朠\",5,\"朧朩朮朰朲朳朶朷朸朹朻朼朾朿杁杄杅杇杊杋杍杒杔杕杗\",4,\"杝杢杣杤杦杧杫杬杮東杴杶\"],[\"9680\",\"杸杹杺杻杽枀枂枃枅枆枈枊枌枍枎枏枑枒枓枔枖枙枛枟枠枡枤枦枩枬枮枱枲枴枹\",7,\"柂柅\",9,\"柕柖柗柛柟柡柣柤柦柧柨柪柫柭柮柲柵\",7,\"柾栁栂栃栄栆栍栐栒栔栕栘\",4,\"栞栟栠栢\",6,\"栫\",6,\"栴栵栶栺栻栿桇桋桍桏桒桖\",5],[\"9740\",\"桜桝桞桟桪桬\",7,\"桵桸\",8,\"梂梄梇\",7,\"梐梑梒梔梕梖梘\",9,\"梣梤梥梩梪梫梬梮梱梲梴梶梷梸\"],[\"9780\",\"梹\",6,\"棁棃\",5,\"棊棌棎棏棐棑棓棔棖棗棙棛\",4,\"棡棢棤\",9,\"棯棲棳棴棶棷棸棻棽棾棿椀椂椃椄椆\",4,\"椌椏椑椓\",11,\"椡椢椣椥\",7,\"椮椯椱椲椳椵椶椷椸椺椻椼椾楀楁楃\",16,\"楕楖楘楙楛楜楟\"],[\"9840\",\"楡楢楤楥楧楨楩楪楬業楯楰楲\",4,\"楺楻楽楾楿榁榃榅榊榋榌榎\",5,\"榖榗榙榚榝\",9,\"榩榪榬榮榯榰榲榳榵榶榸榹榺榼榽\"],[\"9880\",\"榾榿槀槂\",7,\"構槍槏槑槒槓槕\",5,\"槜槝槞槡\",11,\"槮槯槰槱槳\",9,\"槾樀\",9,\"樋\",11,\"標\",5,\"樠樢\",5,\"権樫樬樭樮樰樲樳樴樶\",6,\"樿\",4,\"橅橆橈\",7,\"橑\",6,\"橚\"],[\"9940\",\"橜\",4,\"橢橣橤橦\",10,\"橲\",6,\"橺橻橽橾橿檁檂檃檅\",8,\"檏檒\",4,\"檘\",7,\"檡\",5],[\"9980\",\"檧檨檪檭\",114,\"欥欦欨\",6],[\"9a40\",\"欯欰欱欳欴欵欶欸欻欼欽欿歀歁歂歄歅歈歊歋歍\",11,\"歚\",7,\"歨歩歫\",13,\"歺歽歾歿殀殅殈\"],[\"9a80\",\"殌殎殏殐殑殔殕殗殘殙殜\",4,\"殢\",7,\"殫\",7,\"殶殸\",6,\"毀毃毄毆\",4,\"毌毎毐毑毘毚毜\",4,\"毢\",7,\"毬毭毮毰毱毲毴毶毷毸毺毻毼毾\",6,\"氈\",4,\"氎氒気氜氝氞氠氣氥氫氬氭氱氳氶氷氹氺氻氼氾氿汃汄汅汈汋\",4,\"汑汒汓汖汘\"],[\"9b40\",\"汙汚汢汣汥汦汧汫\",4,\"汱汳汵汷汸決汻汼汿沀沄沇沊沋沍沎沑沒沕沖沗沘沚沜沝沞沠沢沨沬沯沰沴沵沶沷沺泀況泂泃泆泇泈泋泍泎泏泑泒泘\"],[\"9b80\",\"泙泚泜泝泟泤泦泧泩泬泭泲泴泹泿洀洂洃洅洆洈洉洊洍洏洐洑洓洔洕洖洘洜洝洟\",5,\"洦洨洩洬洭洯洰洴洶洷洸洺洿浀浂浄浉浌浐浕浖浗浘浛浝浟浡浢浤浥浧浨浫浬浭浰浱浲浳浵浶浹浺浻浽\",4,\"涃涄涆涇涊涋涍涏涐涒涖\",4,\"涜涢涥涬涭涰涱涳涴涶涷涹\",5,\"淁淂淃淈淉淊\"],[\"9c40\",\"淍淎淏淐淒淓淔淕淗淚淛淜淟淢淣淥淧淨淩淪淭淯淰淲淴淵淶淸淺淽\",7,\"渆渇済渉渋渏渒渓渕渘渙減渜渞渟渢渦渧渨渪測渮渰渱渳渵\"],[\"9c80\",\"渶渷渹渻\",7,\"湅\",7,\"湏湐湑湒湕湗湙湚湜湝湞湠\",10,\"湬湭湯\",14,\"満溁溂溄溇溈溊\",4,\"溑\",6,\"溙溚溛溝溞溠溡溣溤溦溨溩溫溬溭溮溰溳溵溸溹溼溾溿滀滃滄滅滆滈滉滊滌滍滎滐滒滖滘滙滛滜滝滣滧滪\",5],[\"9d40\",\"滰滱滲滳滵滶滷滸滺\",7,\"漃漄漅漇漈漊\",4,\"漐漑漒漖\",9,\"漡漢漣漥漦漧漨漬漮漰漲漴漵漷\",6,\"漿潀潁潂\"],[\"9d80\",\"潃潄潅潈潉潊潌潎\",9,\"潙潚潛潝潟潠潡潣潤潥潧\",5,\"潯潰潱潳潵潶潷潹潻潽\",6,\"澅澆澇澊澋澏\",12,\"澝澞澟澠澢\",4,\"澨\",10,\"澴澵澷澸澺\",5,\"濁濃\",5,\"濊\",6,\"濓\",10,\"濟濢濣濤濥\"],[\"9e40\",\"濦\",7,\"濰\",32,\"瀒\",7,\"瀜\",6,\"瀤\",6],[\"9e80\",\"瀫\",9,\"瀶瀷瀸瀺\",17,\"灍灎灐\",13,\"灟\",11,\"灮灱灲灳灴灷灹灺灻災炁炂炃炄炆炇炈炋炌炍炏炐炑炓炗炘炚炛炞\",12,\"炰炲炴炵炶為炾炿烄烅烆烇烉烋\",12,\"烚\"],[\"9f40\",\"烜烝烞烠烡烢烣烥烪烮烰\",6,\"烸烺烻烼烾\",10,\"焋\",4,\"焑焒焔焗焛\",10,\"焧\",7,\"焲焳焴\"],[\"9f80\",\"焵焷\",13,\"煆煇煈煉煋煍煏\",12,\"煝煟\",4,\"煥煩\",4,\"煯煰煱煴煵煶煷煹煻煼煾\",5,\"熅\",4,\"熋熌熍熎熐熑熒熓熕熖熗熚\",4,\"熡\",6,\"熩熪熫熭\",5,\"熴熶熷熸熺\",8,\"燄\",9,\"燏\",4],[\"a040\",\"燖\",9,\"燡燢燣燤燦燨\",5,\"燯\",9,\"燺\",11,\"爇\",19],[\"a080\",\"爛爜爞\",9,\"爩爫爭爮爯爲爳爴爺爼爾牀\",6,\"牉牊牋牎牏牐牑牓牔牕牗牘牚牜牞牠牣牤牥牨牪牫牬牭牰牱牳牴牶牷牸牻牼牽犂犃犅\",4,\"犌犎犐犑犓\",11,\"犠\",11,\"犮犱犲犳犵犺\",6,\"狅狆狇狉狊狋狌狏狑狓狔狕狖狘狚狛\"],[\"a1a1\",\"　、。·ˉˇ¨〃々—～‖…‘’“”〔〕〈\",7,\"〖〗【】±×÷∶∧∨∑∏∪∩∈∷√⊥∥∠⌒⊙∫∮≡≌≈∽∝≠≮≯≤≥∞∵∴♂♀°′″℃＄¤￠￡‰§№☆★○●◎◇◆□■△▲※→←↑↓〓\"],[\"a2a1\",\"ⅰ\",9],[\"a2b1\",\"⒈\",19,\"⑴\",19,\"①\",9],[\"a2e5\",\"㈠\",9],[\"a2f1\",\"Ⅰ\",11],[\"a3a1\",\"！＂＃￥％\",88,\"￣\"],[\"a4a1\",\"ぁ\",82],[\"a5a1\",\"ァ\",85],[\"a6a1\",\"Α\",16,\"Σ\",6],[\"a6c1\",\"α\",16,\"σ\",6],[\"a6e0\",\"︵︶︹︺︿﹀︽︾﹁﹂﹃﹄\"],[\"a6ee\",\"︻︼︷︸︱\"],[\"a6f4\",\"︳︴\"],[\"a7a1\",\"А\",5,\"ЁЖ\",25],[\"a7d1\",\"а\",5,\"ёж\",25],[\"a840\",\"ˊˋ˙–―‥‵℅℉↖↗↘↙∕∟∣≒≦≧⊿═\",35,\"▁\",6],[\"a880\",\"█\",7,\"▓▔▕▼▽◢◣◤◥☉⊕〒〝〞\"],[\"a8a1\",\"āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜüêɑ\"],[\"a8bd\",\"ńň\"],[\"a8c0\",\"ɡ\"],[\"a8c5\",\"ㄅ\",36],[\"a940\",\"〡\",8,\"㊣㎎㎏㎜㎝㎞㎡㏄㏎㏑㏒㏕︰￢￤\"],[\"a959\",\"℡㈱\"],[\"a95c\",\"‐\"],[\"a960\",\"ー゛゜ヽヾ〆ゝゞ﹉\",9,\"﹔﹕﹖﹗﹙\",8],[\"a980\",\"﹢\",4,\"﹨﹩﹪﹫\"],[\"a996\",\"〇\"],[\"a9a4\",\"─\",75],[\"aa40\",\"狜狝狟狢\",5,\"狪狫狵狶狹狽狾狿猀猂猄\",5,\"猋猌猍猏猐猑猒猔猘猙猚猟猠猣猤猦猧猨猭猯猰猲猳猵猶猺猻猼猽獀\",8],[\"aa80\",\"獉獊獋獌獎獏獑獓獔獕獖獘\",7,\"獡\",10,\"獮獰獱\"],[\"ab40\",\"獲\",11,\"獿\",4,\"玅玆玈玊玌玍玏玐玒玓玔玕玗玘玙玚玜玝玞玠玡玣\",5,\"玪玬玭玱玴玵玶玸玹玼玽玾玿珁珃\",4],[\"ab80\",\"珋珌珎珒\",6,\"珚珛珜珝珟珡珢珣珤珦珨珪珫珬珮珯珰珱珳\",4],[\"ac40\",\"珸\",10,\"琄琇琈琋琌琍琎琑\",8,\"琜\",5,\"琣琤琧琩琫琭琯琱琲琷\",4,\"琽琾琿瑀瑂\",11],[\"ac80\",\"瑎\",6,\"瑖瑘瑝瑠\",12,\"瑮瑯瑱\",4,\"瑸瑹瑺\"],[\"ad40\",\"瑻瑼瑽瑿璂璄璅璆璈璉璊璌璍璏璑\",10,\"璝璟\",7,\"璪\",15,\"璻\",12],[\"ad80\",\"瓈\",9,\"瓓\",8,\"瓝瓟瓡瓥瓧\",6,\"瓰瓱瓲\"],[\"ae40\",\"瓳瓵瓸\",6,\"甀甁甂甃甅\",7,\"甎甐甒甔甕甖甗甛甝甞甠\",4,\"甦甧甪甮甴甶甹甼甽甿畁畂畃畄畆畇畉畊畍畐畑畒畓畕畖畗畘\"],[\"ae80\",\"畝\",7,\"畧畨畩畫\",6,\"畳畵當畷畺\",4,\"疀疁疂疄疅疇\"],[\"af40\",\"疈疉疊疌疍疎疐疓疕疘疛疜疞疢疦\",4,\"疭疶疷疺疻疿痀痁痆痋痌痎痏痐痑痓痗痙痚痜痝痟痠痡痥痩痬痭痮痯痲痳痵痶痷痸痺痻痽痾瘂瘄瘆瘇\"],[\"af80\",\"瘈瘉瘋瘍瘎瘏瘑瘒瘓瘔瘖瘚瘜瘝瘞瘡瘣瘧瘨瘬瘮瘯瘱瘲瘶瘷瘹瘺瘻瘽癁療癄\"],[\"b040\",\"癅\",6,\"癎\",5,\"癕癗\",4,\"癝癟癠癡癢癤\",6,\"癬癭癮癰\",7,\"癹発發癿皀皁皃皅皉皊皌皍皏皐皒皔皕皗皘皚皛\"],[\"b080\",\"皜\",7,\"皥\",8,\"皯皰皳皵\",9,\"盀盁盃啊阿埃挨哎唉哀皑癌蔼矮艾碍爱隘鞍氨安俺按暗岸胺案肮昂盎凹敖熬翱袄傲奥懊澳芭捌扒叭吧笆八疤巴拔跋靶把耙坝霸罢爸白柏百摆佰败拜稗斑班搬扳般颁板版扮拌伴瓣半办绊邦帮梆榜膀绑棒磅蚌镑傍谤苞胞包褒剥\"],[\"b140\",\"盄盇盉盋盌盓盕盙盚盜盝盞盠\",4,\"盦\",7,\"盰盳盵盶盷盺盻盽盿眀眂眃眅眆眊県眎\",10,\"眛眜眝眞眡眣眤眥眧眪眫\"],[\"b180\",\"眬眮眰\",4,\"眹眻眽眾眿睂睄睅睆睈\",7,\"睒\",7,\"睜薄雹保堡饱宝抱报暴豹鲍爆杯碑悲卑北辈背贝钡倍狈备惫焙被奔苯本笨崩绷甭泵蹦迸逼鼻比鄙笔彼碧蓖蔽毕毙毖币庇痹闭敝弊必辟壁臂避陛鞭边编贬扁便变卞辨辩辫遍标彪膘表鳖憋别瘪彬斌濒滨宾摈兵冰柄丙秉饼炳\"],[\"b240\",\"睝睞睟睠睤睧睩睪睭\",11,\"睺睻睼瞁瞂瞃瞆\",5,\"瞏瞐瞓\",11,\"瞡瞣瞤瞦瞨瞫瞭瞮瞯瞱瞲瞴瞶\",4],[\"b280\",\"瞼瞾矀\",12,\"矎\",8,\"矘矙矚矝\",4,\"矤病并玻菠播拨钵波博勃搏铂箔伯帛舶脖膊渤泊驳捕卜哺补埠不布步簿部怖擦猜裁材才财睬踩采彩菜蔡餐参蚕残惭惨灿苍舱仓沧藏操糙槽曹草厕策侧册测层蹭插叉茬茶查碴搽察岔差诧拆柴豺搀掺蝉馋谗缠铲产阐颤昌猖\"],[\"b340\",\"矦矨矪矯矰矱矲矴矵矷矹矺矻矼砃\",5,\"砊砋砎砏砐砓砕砙砛砞砠砡砢砤砨砪砫砮砯砱砲砳砵砶砽砿硁硂硃硄硆硈硉硊硋硍硏硑硓硔硘硙硚\"],[\"b380\",\"硛硜硞\",11,\"硯\",7,\"硸硹硺硻硽\",6,\"场尝常长偿肠厂敞畅唱倡超抄钞朝嘲潮巢吵炒车扯撤掣彻澈郴臣辰尘晨忱沉陈趁衬撑称城橙成呈乘程惩澄诚承逞骋秤吃痴持匙池迟弛驰耻齿侈尺赤翅斥炽充冲虫崇宠抽酬畴踌稠愁筹仇绸瞅丑臭初出橱厨躇锄雏滁除楚\"],[\"b440\",\"碄碅碆碈碊碋碏碐碒碔碕碖碙碝碞碠碢碤碦碨\",7,\"碵碶碷碸確碻碼碽碿磀磂磃磄磆磇磈磌磍磎磏磑磒磓磖磗磘磚\",9],[\"b480\",\"磤磥磦磧磩磪磫磭\",4,\"磳磵磶磸磹磻\",5,\"礂礃礄礆\",6,\"础储矗搐触处揣川穿椽传船喘串疮窗幢床闯创吹炊捶锤垂春椿醇唇淳纯蠢戳绰疵茨磁雌辞慈瓷词此刺赐次聪葱囱匆从丛凑粗醋簇促蹿篡窜摧崔催脆瘁粹淬翠村存寸磋撮搓措挫错搭达答瘩打大呆歹傣戴带殆代贷袋待逮\"],[\"b540\",\"礍\",5,\"礔\",9,\"礟\",4,\"礥\",14,\"礵\",4,\"礽礿祂祃祄祅祇祊\",8,\"祔祕祘祙祡祣\"],[\"b580\",\"祤祦祩祪祫祬祮祰\",6,\"祹祻\",4,\"禂禃禆禇禈禉禋禌禍禎禐禑禒怠耽担丹单郸掸胆旦氮但惮淡诞弹蛋当挡党荡档刀捣蹈倒岛祷导到稻悼道盗德得的蹬灯登等瞪凳邓堤低滴迪敌笛狄涤翟嫡抵底地蒂第帝弟递缔颠掂滇碘点典靛垫电佃甸店惦奠淀殿碉叼雕凋刁掉吊钓调跌爹碟蝶迭谍叠\"],[\"b640\",\"禓\",6,\"禛\",11,\"禨\",10,\"禴\",4,\"禼禿秂秄秅秇秈秊秌秎秏秐秓秔秖秗秙\",5,\"秠秡秢秥秨秪\"],[\"b680\",\"秬秮秱\",6,\"秹秺秼秾秿稁稄稅稇稈稉稊稌稏\",4,\"稕稖稘稙稛稜丁盯叮钉顶鼎锭定订丢东冬董懂动栋侗恫冻洞兜抖斗陡豆逗痘都督毒犊独读堵睹赌杜镀肚度渡妒端短锻段断缎堆兑队对墩吨蹲敦顿囤钝盾遁掇哆多夺垛躲朵跺舵剁惰堕蛾峨鹅俄额讹娥恶厄扼遏鄂饿恩而儿耳尔饵洱二\"],[\"b740\",\"稝稟稡稢稤\",14,\"稴稵稶稸稺稾穀\",5,\"穇\",9,\"穒\",4,\"穘\",16],[\"b780\",\"穩\",6,\"穱穲穳穵穻穼穽穾窂窅窇窉窊窋窌窎窏窐窓窔窙窚窛窞窡窢贰发罚筏伐乏阀法珐藩帆番翻樊矾钒繁凡烦反返范贩犯饭泛坊芳方肪房防妨仿访纺放菲非啡飞肥匪诽吠肺废沸费芬酚吩氛分纷坟焚汾粉奋份忿愤粪丰封枫蜂峰锋风疯烽逢冯缝讽奉凤佛否夫敷肤孵扶拂辐幅氟符伏俘服\"],[\"b840\",\"窣窤窧窩窪窫窮\",4,\"窴\",10,\"竀\",10,\"竌\",9,\"竗竘竚竛竜竝竡竢竤竧\",5,\"竮竰竱竲竳\"],[\"b880\",\"竴\",4,\"竻竼竾笀笁笂笅笇笉笌笍笎笐笒笓笖笗笘笚笜笝笟笡笢笣笧笩笭浮涪福袱弗甫抚辅俯釜斧脯腑府腐赴副覆赋复傅付阜父腹负富讣附妇缚咐噶嘎该改概钙盖溉干甘杆柑竿肝赶感秆敢赣冈刚钢缸肛纲岗港杠篙皋高膏羔糕搞镐稿告哥歌搁戈鸽胳疙割革葛格蛤阁隔铬个各给根跟耕更庚羹\"],[\"b940\",\"笯笰笲笴笵笶笷笹笻笽笿\",5,\"筆筈筊筍筎筓筕筗筙筜筞筟筡筣\",10,\"筯筰筳筴筶筸筺筼筽筿箁箂箃箄箆\",6,\"箎箏\"],[\"b980\",\"箑箒箓箖箘箙箚箛箞箟箠箣箤箥箮箯箰箲箳箵箶箷箹\",7,\"篂篃範埂耿梗工攻功恭龚供躬公宫弓巩汞拱贡共钩勾沟苟狗垢构购够辜菇咕箍估沽孤姑鼓古蛊骨谷股故顾固雇刮瓜剐寡挂褂乖拐怪棺关官冠观管馆罐惯灌贯光广逛瑰规圭硅归龟闺轨鬼诡癸桂柜跪贵刽辊滚棍锅郭国果裹过哈\"],[\"ba40\",\"篅篈築篊篋篍篎篏篐篒篔\",4,\"篛篜篞篟篠篢篣篤篧篨篩篫篬篭篯篰篲\",4,\"篸篹篺篻篽篿\",7,\"簈簉簊簍簎簐\",5,\"簗簘簙\"],[\"ba80\",\"簚\",4,\"簠\",5,\"簨簩簫\",12,\"簹\",5,\"籂骸孩海氦亥害骇酣憨邯韩含涵寒函喊罕翰撼捍旱憾悍焊汗汉夯杭航壕嚎豪毫郝好耗号浩呵喝荷菏核禾和何合盒貉阂河涸赫褐鹤贺嘿黑痕很狠恨哼亨横衡恒轰哄烘虹鸿洪宏弘红喉侯猴吼厚候后呼乎忽瑚壶葫胡蝴狐糊湖\"],[\"bb40\",\"籃\",9,\"籎\",36,\"籵\",5,\"籾\",9],[\"bb80\",\"粈粊\",6,\"粓粔粖粙粚粛粠粡粣粦粧粨粩粫粬粭粯粰粴\",4,\"粺粻弧虎唬护互沪户花哗华猾滑画划化话槐徊怀淮坏欢环桓还缓换患唤痪豢焕涣宦幻荒慌黄磺蝗簧皇凰惶煌晃幌恍谎灰挥辉徽恢蛔回毁悔慧卉惠晦贿秽会烩汇讳诲绘荤昏婚魂浑混豁活伙火获或惑霍货祸击圾基机畸稽积箕\"],[\"bc40\",\"粿糀糂糃糄糆糉糋糎\",6,\"糘糚糛糝糞糡\",6,\"糩\",5,\"糰\",7,\"糹糺糼\",13,\"紋\",5],[\"bc80\",\"紑\",14,\"紡紣紤紥紦紨紩紪紬紭紮細\",6,\"肌饥迹激讥鸡姬绩缉吉极棘辑籍集及急疾汲即嫉级挤几脊己蓟技冀季伎祭剂悸济寄寂计记既忌际妓继纪嘉枷夹佳家加荚颊贾甲钾假稼价架驾嫁歼监坚尖笺间煎兼肩艰奸缄茧检柬碱硷拣捡简俭剪减荐槛鉴践贱见键箭件\"],[\"bd40\",\"紷\",54,\"絯\",7],[\"bd80\",\"絸\",32,\"健舰剑饯渐溅涧建僵姜将浆江疆蒋桨奖讲匠酱降蕉椒礁焦胶交郊浇骄娇嚼搅铰矫侥脚狡角饺缴绞剿教酵轿较叫窖揭接皆秸街阶截劫节桔杰捷睫竭洁结解姐戒藉芥界借介疥诫届巾筋斤金今津襟紧锦仅谨进靳晋禁近烬浸\"],[\"be40\",\"継\",12,\"綧\",6,\"綯\",42],[\"be80\",\"線\",32,\"尽劲荆兢茎睛晶鲸京惊精粳经井警景颈静境敬镜径痉靖竟竞净炯窘揪究纠玖韭久灸九酒厩救旧臼舅咎就疚鞠拘狙疽居驹菊局咀矩举沮聚拒据巨具距踞锯俱句惧炬剧捐鹃娟倦眷卷绢撅攫抉掘倔爵觉决诀绝均菌钧军君峻\"],[\"bf40\",\"緻\",62],[\"bf80\",\"縺縼\",4,\"繂\",4,\"繈\",21,\"俊竣浚郡骏喀咖卡咯开揩楷凯慨刊堪勘坎砍看康慷糠扛抗亢炕考拷烤靠坷苛柯棵磕颗科壳咳可渴克刻客课肯啃垦恳坑吭空恐孔控抠口扣寇枯哭窟苦酷库裤夸垮挎跨胯块筷侩快宽款匡筐狂框矿眶旷况亏盔岿窥葵奎魁傀\"],[\"c040\",\"繞\",35,\"纃\",23,\"纜纝纞\"],[\"c080\",\"纮纴纻纼绖绤绬绹缊缐缞缷缹缻\",6,\"罃罆\",9,\"罒罓馈愧溃坤昆捆困括扩廓阔垃拉喇蜡腊辣啦莱来赖蓝婪栏拦篮阑兰澜谰揽览懒缆烂滥琅榔狼廊郎朗浪捞劳牢老佬姥酪烙涝勒乐雷镭蕾磊累儡垒擂肋类泪棱楞冷厘梨犁黎篱狸离漓理李里鲤礼莉荔吏栗丽厉励砾历利傈例俐\"],[\"c140\",\"罖罙罛罜罝罞罠罣\",4,\"罫罬罭罯罰罳罵罶罷罸罺罻罼罽罿羀羂\",7,\"羋羍羏\",4,\"羕\",4,\"羛羜羠羢羣羥羦羨\",6,\"羱\"],[\"c180\",\"羳\",4,\"羺羻羾翀翂翃翄翆翇翈翉翋翍翏\",4,\"翖翗翙\",5,\"翢翣痢立粒沥隶力璃哩俩联莲连镰廉怜涟帘敛脸链恋炼练粮凉梁粱良两辆量晾亮谅撩聊僚疗燎寥辽潦了撂镣廖料列裂烈劣猎琳林磷霖临邻鳞淋凛赁吝拎玲菱零龄铃伶羚凌灵陵岭领另令溜琉榴硫馏留刘瘤流柳六龙聋咙笼窿\"],[\"c240\",\"翤翧翨翪翫翬翭翯翲翴\",6,\"翽翾翿耂耇耈耉耊耎耏耑耓耚耛耝耞耟耡耣耤耫\",5,\"耲耴耹耺耼耾聀聁聄聅聇聈聉聎聏聐聑聓聕聖聗\"],[\"c280\",\"聙聛\",13,\"聫\",5,\"聲\",11,\"隆垄拢陇楼娄搂篓漏陋芦卢颅庐炉掳卤虏鲁麓碌露路赂鹿潞禄录陆戮驴吕铝侣旅履屡缕虑氯律率滤绿峦挛孪滦卵乱掠略抡轮伦仑沦纶论萝螺罗逻锣箩骡裸落洛骆络妈麻玛码蚂马骂嘛吗埋买麦卖迈脉瞒馒蛮满蔓曼慢漫\"],[\"c340\",\"聾肁肂肅肈肊肍\",5,\"肔肕肗肙肞肣肦肧肨肬肰肳肵肶肸肹肻胅胇\",4,\"胏\",6,\"胘胟胠胢胣胦胮胵胷胹胻胾胿脀脁脃脄脅脇脈脋\"],[\"c380\",\"脌脕脗脙脛脜脝脟\",12,\"脭脮脰脳脴脵脷脹\",4,\"脿谩芒茫盲氓忙莽猫茅锚毛矛铆卯茂冒帽貌贸么玫枚梅酶霉煤没眉媒镁每美昧寐妹媚门闷们萌蒙檬盟锰猛梦孟眯醚靡糜迷谜弥米秘觅泌蜜密幂棉眠绵冕免勉娩缅面苗描瞄藐秒渺庙妙蔑灭民抿皿敏悯闽明螟鸣铭名命谬摸\"],[\"c440\",\"腀\",5,\"腇腉腍腎腏腒腖腗腘腛\",4,\"腡腢腣腤腦腨腪腫腬腯腲腳腵腶腷腸膁膃\",4,\"膉膋膌膍膎膐膒\",5,\"膙膚膞\",4,\"膤膥\"],[\"c480\",\"膧膩膫\",7,\"膴\",5,\"膼膽膾膿臄臅臇臈臉臋臍\",6,\"摹蘑模膜磨摩魔抹末莫墨默沫漠寞陌谋牟某拇牡亩姆母墓暮幕募慕木目睦牧穆拿哪呐钠那娜纳氖乃奶耐奈南男难囊挠脑恼闹淖呢馁内嫩能妮霓倪泥尼拟你匿腻逆溺蔫拈年碾撵捻念娘酿鸟尿捏聂孽啮镊镍涅您柠狞凝宁\"],[\"c540\",\"臔\",14,\"臤臥臦臨臩臫臮\",4,\"臵\",5,\"臽臿舃與\",4,\"舎舏舑舓舕\",5,\"舝舠舤舥舦舧舩舮舲舺舼舽舿\"],[\"c580\",\"艀艁艂艃艅艆艈艊艌艍艎艐\",7,\"艙艛艜艝艞艠\",7,\"艩拧泞牛扭钮纽脓浓农弄奴努怒女暖虐疟挪懦糯诺哦欧鸥殴藕呕偶沤啪趴爬帕怕琶拍排牌徘湃派攀潘盘磐盼畔判叛乓庞旁耪胖抛咆刨炮袍跑泡呸胚培裴赔陪配佩沛喷盆砰抨烹澎彭蓬棚硼篷膨朋鹏捧碰坯砒霹批披劈琵毗\"],[\"c640\",\"艪艫艬艭艱艵艶艷艸艻艼芀芁芃芅芆芇芉芌芐芓芔芕芖芚芛芞芠芢芣芧芲芵芶芺芻芼芿苀苂苃苅苆苉苐苖苙苚苝苢苧苨苩苪苬苭苮苰苲苳苵苶苸\"],[\"c680\",\"苺苼\",4,\"茊茋茍茐茒茓茖茘茙茝\",9,\"茩茪茮茰茲茷茻茽啤脾疲皮匹痞僻屁譬篇偏片骗飘漂瓢票撇瞥拼频贫品聘乒坪苹萍平凭瓶评屏坡泼颇婆破魄迫粕剖扑铺仆莆葡菩蒲埔朴圃普浦谱曝瀑期欺栖戚妻七凄漆柒沏其棋奇歧畦崎脐齐旗祈祁骑起岂乞企启契砌器气迄弃汽泣讫掐\"],[\"c740\",\"茾茿荁荂荄荅荈荊\",4,\"荓荕\",4,\"荝荢荰\",6,\"荹荺荾\",6,\"莇莈莊莋莌莍莏莐莑莔莕莖莗莙莚莝莟莡\",6,\"莬莭莮\"],[\"c780\",\"莯莵莻莾莿菂菃菄菆菈菉菋菍菎菐菑菒菓菕菗菙菚菛菞菢菣菤菦菧菨菫菬菭恰洽牵扦钎铅千迁签仟谦乾黔钱钳前潜遣浅谴堑嵌欠歉枪呛腔羌墙蔷强抢橇锹敲悄桥瞧乔侨巧鞘撬翘峭俏窍切茄且怯窃钦侵亲秦琴勤芹擒禽寝沁青轻氢倾卿清擎晴氰情顷请庆琼穷秋丘邱球求囚酋泅趋区蛆曲躯屈驱渠\"],[\"c840\",\"菮華菳\",4,\"菺菻菼菾菿萀萂萅萇萈萉萊萐萒\",5,\"萙萚萛萞\",5,\"萩\",7,\"萲\",5,\"萹萺萻萾\",7,\"葇葈葉\"],[\"c880\",\"葊\",6,\"葒\",4,\"葘葝葞葟葠葢葤\",4,\"葪葮葯葰葲葴葷葹葻葼取娶龋趣去圈颧权醛泉全痊拳犬券劝缺炔瘸却鹊榷确雀裙群然燃冉染瓤壤攘嚷让饶扰绕惹热壬仁人忍韧任认刃妊纫扔仍日戎茸蓉荣融熔溶容绒冗揉柔肉茹蠕儒孺如辱乳汝入褥软阮蕊瑞锐闰润若弱撒洒萨腮鳃塞赛三叁\"],[\"c940\",\"葽\",4,\"蒃蒄蒅蒆蒊蒍蒏\",7,\"蒘蒚蒛蒝蒞蒟蒠蒢\",12,\"蒰蒱蒳蒵蒶蒷蒻蒼蒾蓀蓂蓃蓅蓆蓇蓈蓋蓌蓎蓏蓒蓔蓕蓗\"],[\"c980\",\"蓘\",4,\"蓞蓡蓢蓤蓧\",4,\"蓭蓮蓯蓱\",10,\"蓽蓾蔀蔁蔂伞散桑嗓丧搔骚扫嫂瑟色涩森僧莎砂杀刹沙纱傻啥煞筛晒珊苫杉山删煽衫闪陕擅赡膳善汕扇缮墒伤商赏晌上尚裳梢捎稍烧芍勺韶少哨邵绍奢赊蛇舌舍赦摄射慑涉社设砷申呻伸身深娠绅神沈审婶甚肾慎渗声生甥牲升绳\"],[\"ca40\",\"蔃\",8,\"蔍蔎蔏蔐蔒蔔蔕蔖蔘蔙蔛蔜蔝蔞蔠蔢\",8,\"蔭\",9,\"蔾\",4,\"蕄蕅蕆蕇蕋\",10],[\"ca80\",\"蕗蕘蕚蕛蕜蕝蕟\",4,\"蕥蕦蕧蕩\",8,\"蕳蕵蕶蕷蕸蕼蕽蕿薀薁省盛剩胜圣师失狮施湿诗尸虱十石拾时什食蚀实识史矢使屎驶始式示士世柿事拭誓逝势是嗜噬适仕侍释饰氏市恃室视试收手首守寿授售受瘦兽蔬枢梳殊抒输叔舒淑疏书赎孰熟薯暑曙署蜀黍鼠属术述树束戍竖墅庶数漱\"],[\"cb40\",\"薂薃薆薈\",6,\"薐\",10,\"薝\",6,\"薥薦薧薩薫薬薭薱\",5,\"薸薺\",6,\"藂\",6,\"藊\",4,\"藑藒\"],[\"cb80\",\"藔藖\",5,\"藝\",6,\"藥藦藧藨藪\",14,\"恕刷耍摔衰甩帅栓拴霜双爽谁水睡税吮瞬顺舜说硕朔烁斯撕嘶思私司丝死肆寺嗣四伺似饲巳松耸怂颂送宋讼诵搜艘擞嗽苏酥俗素速粟僳塑溯宿诉肃酸蒜算虽隋随绥髓碎岁穗遂隧祟孙损笋蓑梭唆缩琐索锁所塌他它她塔\"],[\"cc40\",\"藹藺藼藽藾蘀\",4,\"蘆\",10,\"蘒蘓蘔蘕蘗\",15,\"蘨蘪\",13,\"蘹蘺蘻蘽蘾蘿虀\"],[\"cc80\",\"虁\",11,\"虒虓處\",4,\"虛虜虝號虠虡虣\",7,\"獭挞蹋踏胎苔抬台泰酞太态汰坍摊贪瘫滩坛檀痰潭谭谈坦毯袒碳探叹炭汤塘搪堂棠膛唐糖倘躺淌趟烫掏涛滔绦萄桃逃淘陶讨套特藤腾疼誊梯剔踢锑提题蹄啼体替嚏惕涕剃屉天添填田甜恬舔腆挑条迢眺跳贴铁帖厅听烃\"],[\"cd40\",\"虭虯虰虲\",6,\"蚃\",6,\"蚎\",4,\"蚔蚖\",5,\"蚞\",4,\"蚥蚦蚫蚭蚮蚲蚳蚷蚸蚹蚻\",4,\"蛁蛂蛃蛅蛈蛌蛍蛒蛓蛕蛖蛗蛚蛜\"],[\"cd80\",\"蛝蛠蛡蛢蛣蛥蛦蛧蛨蛪蛫蛬蛯蛵蛶蛷蛺蛻蛼蛽蛿蜁蜄蜅蜆蜋蜌蜎蜏蜐蜑蜔蜖汀廷停亭庭挺艇通桐酮瞳同铜彤童桶捅筒统痛偷投头透凸秃突图徒途涂屠土吐兔湍团推颓腿蜕褪退吞屯臀拖托脱鸵陀驮驼椭妥拓唾挖哇蛙洼娃瓦袜歪外豌弯湾玩顽丸烷完碗挽晚皖惋宛婉万腕汪王亡枉网往旺望忘妄威\"],[\"ce40\",\"蜙蜛蜝蜟蜠蜤蜦蜧蜨蜪蜫蜬蜭蜯蜰蜲蜳蜵蜶蜸蜹蜺蜼蜽蝀\",6,\"蝊蝋蝍蝏蝐蝑蝒蝔蝕蝖蝘蝚\",5,\"蝡蝢蝦\",7,\"蝯蝱蝲蝳蝵\"],[\"ce80\",\"蝷蝸蝹蝺蝿螀螁螄螆螇螉螊螌螎\",4,\"螔螕螖螘\",6,\"螠\",4,\"巍微危韦违桅围唯惟为潍维苇萎委伟伪尾纬未蔚味畏胃喂魏位渭谓尉慰卫瘟温蚊文闻纹吻稳紊问嗡翁瓮挝蜗涡窝我斡卧握沃巫呜钨乌污诬屋无芜梧吾吴毋武五捂午舞伍侮坞戊雾晤物勿务悟误昔熙析西硒矽晰嘻吸锡牺\"],[\"cf40\",\"螥螦螧螩螪螮螰螱螲螴螶螷螸螹螻螼螾螿蟁\",4,\"蟇蟈蟉蟌\",4,\"蟔\",6,\"蟜蟝蟞蟟蟡蟢蟣蟤蟦蟧蟨蟩蟫蟬蟭蟯\",9],[\"cf80\",\"蟺蟻蟼蟽蟿蠀蠁蠂蠄\",5,\"蠋\",7,\"蠔蠗蠘蠙蠚蠜\",4,\"蠣稀息希悉膝夕惜熄烯溪汐犀檄袭席习媳喜铣洗系隙戏细瞎虾匣霞辖暇峡侠狭下厦夏吓掀锨先仙鲜纤咸贤衔舷闲涎弦嫌显险现献县腺馅羡宪陷限线相厢镶香箱襄湘乡翔祥详想响享项巷橡像向象萧硝霄削哮嚣销消宵淆晓\"],[\"d040\",\"蠤\",13,\"蠳\",5,\"蠺蠻蠽蠾蠿衁衂衃衆\",5,\"衎\",5,\"衕衖衘衚\",6,\"衦衧衪衭衯衱衳衴衵衶衸衹衺\"],[\"d080\",\"衻衼袀袃袆袇袉袊袌袎袏袐袑袓袔袕袗\",4,\"袝\",4,\"袣袥\",5,\"小孝校肖啸笑效楔些歇蝎鞋协挟携邪斜胁谐写械卸蟹懈泄泻谢屑薪芯锌欣辛新忻心信衅星腥猩惺兴刑型形邢行醒幸杏性姓兄凶胸匈汹雄熊休修羞朽嗅锈秀袖绣墟戌需虚嘘须徐许蓄酗叙旭序畜恤絮婿绪续轩喧宣悬旋玄\"],[\"d140\",\"袬袮袯袰袲\",4,\"袸袹袺袻袽袾袿裀裃裄裇裈裊裋裌裍裏裐裑裓裖裗裚\",4,\"裠裡裦裧裩\",6,\"裲裵裶裷裺裻製裿褀褁褃\",5],[\"d180\",\"褉褋\",4,\"褑褔\",4,\"褜\",4,\"褢褣褤褦褧褨褩褬褭褮褯褱褲褳褵褷选癣眩绚靴薛学穴雪血勋熏循旬询寻驯巡殉汛训讯逊迅压押鸦鸭呀丫芽牙蚜崖衙涯雅哑亚讶焉咽阉烟淹盐严研蜒岩延言颜阎炎沿奄掩眼衍演艳堰燕厌砚雁唁彦焰宴谚验殃央鸯秧杨扬佯疡羊洋阳氧仰痒养样漾邀腰妖瑶\"],[\"d240\",\"褸\",8,\"襂襃襅\",24,\"襠\",5,\"襧\",19,\"襼\"],[\"d280\",\"襽襾覀覂覄覅覇\",26,\"摇尧遥窑谣姚咬舀药要耀椰噎耶爷野冶也页掖业叶曳腋夜液一壹医揖铱依伊衣颐夷遗移仪胰疑沂宜姨彝椅蚁倚已乙矣以艺抑易邑屹亿役臆逸肄疫亦裔意毅忆义益溢诣议谊译异翼翌绎茵荫因殷音阴姻吟银淫寅饮尹引隐\"],[\"d340\",\"覢\",30,\"觃觍觓觔觕觗觘觙觛觝觟觠觡觢觤觧觨觩觪觬觭觮觰觱觲觴\",6],[\"d380\",\"觻\",4,\"訁\",5,\"計\",21,\"印英樱婴鹰应缨莹萤营荧蝇迎赢盈影颖硬映哟拥佣臃痈庸雍踊蛹咏泳涌永恿勇用幽优悠忧尤由邮铀犹油游酉有友右佑釉诱又幼迂淤于盂榆虞愚舆余俞逾鱼愉渝渔隅予娱雨与屿禹宇语羽玉域芋郁吁遇喻峪御愈欲狱育誉\"],[\"d440\",\"訞\",31,\"訿\",8,\"詉\",21],[\"d480\",\"詟\",25,\"詺\",6,\"浴寓裕预豫驭鸳渊冤元垣袁原援辕园员圆猿源缘远苑愿怨院曰约越跃钥岳粤月悦阅耘云郧匀陨允运蕴酝晕韵孕匝砸杂栽哉灾宰载再在咱攒暂赞赃脏葬遭糟凿藻枣早澡蚤躁噪造皂灶燥责择则泽贼怎增憎曾赠扎喳渣札轧\"],[\"d540\",\"誁\",7,\"誋\",7,\"誔\",46],[\"d580\",\"諃\",32,\"铡闸眨栅榨咋乍炸诈摘斋宅窄债寨瞻毡詹粘沾盏斩辗崭展蘸栈占战站湛绽樟章彰漳张掌涨杖丈帐账仗胀瘴障招昭找沼赵照罩兆肇召遮折哲蛰辙者锗蔗这浙珍斟真甄砧臻贞针侦枕疹诊震振镇阵蒸挣睁征狰争怔整拯正政\"],[\"d640\",\"諤\",34,\"謈\",27],[\"d680\",\"謤謥謧\",30,\"帧症郑证芝枝支吱蜘知肢脂汁之织职直植殖执值侄址指止趾只旨纸志挚掷至致置帜峙制智秩稚质炙痔滞治窒中盅忠钟衷终种肿重仲众舟周州洲诌粥轴肘帚咒皱宙昼骤珠株蛛朱猪诸诛逐竹烛煮拄瞩嘱主著柱助蛀贮铸筑\"],[\"d740\",\"譆\",31,\"譧\",4,\"譭\",25],[\"d780\",\"讇\",24,\"讬讱讻诇诐诪谉谞住注祝驻抓爪拽专砖转撰赚篆桩庄装妆撞壮状椎锥追赘坠缀谆准捉拙卓桌琢茁酌啄着灼浊兹咨资姿滋淄孜紫仔籽滓子自渍字鬃棕踪宗综总纵邹走奏揍租足卒族祖诅阻组钻纂嘴醉最罪尊遵昨左佐柞做作坐座\"],[\"d840\",\"谸\",8,\"豂豃豄豅豈豊豋豍\",7,\"豖豗豘豙豛\",5,\"豣\",6,\"豬\",6,\"豴豵豶豷豻\",6,\"貃貄貆貇\"],[\"d880\",\"貈貋貍\",6,\"貕貖貗貙\",20,\"亍丌兀丐廿卅丕亘丞鬲孬噩丨禺丿匕乇夭爻卮氐囟胤馗毓睾鼗丶亟鼐乜乩亓芈孛啬嘏仄厍厝厣厥厮靥赝匚叵匦匮匾赜卦卣刂刈刎刭刳刿剀剌剞剡剜蒯剽劂劁劐劓冂罔亻仃仉仂仨仡仫仞伛仳伢佤仵伥伧伉伫佞佧攸佚佝\"],[\"d940\",\"貮\",62],[\"d980\",\"賭\",32,\"佟佗伲伽佶佴侑侉侃侏佾佻侪佼侬侔俦俨俪俅俚俣俜俑俟俸倩偌俳倬倏倮倭俾倜倌倥倨偾偃偕偈偎偬偻傥傧傩傺僖儆僭僬僦僮儇儋仝氽佘佥俎龠汆籴兮巽黉馘冁夔勹匍訇匐凫夙兕亠兖亳衮袤亵脔裒禀嬴蠃羸冫冱冽冼\"],[\"da40\",\"贎\",14,\"贠赑赒赗赟赥赨赩赪赬赮赯赱赲赸\",8,\"趂趃趆趇趈趉趌\",4,\"趒趓趕\",9,\"趠趡\"],[\"da80\",\"趢趤\",12,\"趲趶趷趹趻趽跀跁跂跅跇跈跉跊跍跐跒跓跔凇冖冢冥讠讦讧讪讴讵讷诂诃诋诏诎诒诓诔诖诘诙诜诟诠诤诨诩诮诰诳诶诹诼诿谀谂谄谇谌谏谑谒谔谕谖谙谛谘谝谟谠谡谥谧谪谫谮谯谲谳谵谶卩卺阝阢阡阱阪阽阼陂陉陔陟陧陬陲陴隈隍隗隰邗邛邝邙邬邡邴邳邶邺\"],[\"db40\",\"跕跘跙跜跠跡跢跥跦跧跩跭跮跰跱跲跴跶跼跾\",6,\"踆踇踈踋踍踎踐踑踒踓踕\",7,\"踠踡踤\",4,\"踫踭踰踲踳踴踶踷踸踻踼踾\"],[\"db80\",\"踿蹃蹅蹆蹌\",4,\"蹓\",5,\"蹚\",11,\"蹧蹨蹪蹫蹮蹱邸邰郏郅邾郐郄郇郓郦郢郜郗郛郫郯郾鄄鄢鄞鄣鄱鄯鄹酃酆刍奂劢劬劭劾哿勐勖勰叟燮矍廴凵凼鬯厶弁畚巯坌垩垡塾墼壅壑圩圬圪圳圹圮圯坜圻坂坩垅坫垆坼坻坨坭坶坳垭垤垌垲埏垧垴垓垠埕埘埚埙埒垸埴埯埸埤埝\"],[\"dc40\",\"蹳蹵蹷\",4,\"蹽蹾躀躂躃躄躆躈\",6,\"躑躒躓躕\",6,\"躝躟\",11,\"躭躮躰躱躳\",6,\"躻\",7],[\"dc80\",\"軃\",10,\"軏\",21,\"堋堍埽埭堀堞堙塄堠塥塬墁墉墚墀馨鼙懿艹艽艿芏芊芨芄芎芑芗芙芫芸芾芰苈苊苣芘芷芮苋苌苁芩芴芡芪芟苄苎芤苡茉苷苤茏茇苜苴苒苘茌苻苓茑茚茆茔茕苠苕茜荑荛荜茈莒茼茴茱莛荞茯荏荇荃荟荀茗荠茭茺茳荦荥\"],[\"dd40\",\"軥\",62],[\"dd80\",\"輤\",32,\"荨茛荩荬荪荭荮莰荸莳莴莠莪莓莜莅荼莶莩荽莸荻莘莞莨莺莼菁萁菥菘堇萘萋菝菽菖萜萸萑萆菔菟萏萃菸菹菪菅菀萦菰菡葜葑葚葙葳蒇蒈葺蒉葸萼葆葩葶蒌蒎萱葭蓁蓍蓐蓦蒽蓓蓊蒿蒺蓠蒡蒹蒴蒗蓥蓣蔌甍蔸蓰蔹蔟蔺\"],[\"de40\",\"轅\",32,\"轪辀辌辒辝辠辡辢辤辥辦辧辪辬辭辮辯農辳辴辵辷辸辺辻込辿迀迃迆\"],[\"de80\",\"迉\",4,\"迏迒迖迗迚迠迡迣迧迬迯迱迲迴迵迶迺迻迼迾迿逇逈逌逎逓逕逘蕖蔻蓿蓼蕙蕈蕨蕤蕞蕺瞢蕃蕲蕻薤薨薇薏蕹薮薜薅薹薷薰藓藁藜藿蘧蘅蘩蘖蘼廾弈夼奁耷奕奚奘匏尢尥尬尴扌扪抟抻拊拚拗拮挢拶挹捋捃掭揶捱捺掎掴捭掬掊捩掮掼揲揸揠揿揄揞揎摒揆掾摅摁搋搛搠搌搦搡摞撄摭撖\"],[\"df40\",\"這逜連逤逥逧\",5,\"逰\",4,\"逷逹逺逽逿遀遃遅遆遈\",4,\"過達違遖遙遚遜\",5,\"遤遦遧適遪遫遬遯\",4,\"遶\",6,\"遾邁\"],[\"df80\",\"還邅邆邇邉邊邌\",4,\"邒邔邖邘邚邜邞邟邠邤邥邧邨邩邫邭邲邷邼邽邿郀摺撷撸撙撺擀擐擗擤擢攉攥攮弋忒甙弑卟叱叽叩叨叻吒吖吆呋呒呓呔呖呃吡呗呙吣吲咂咔呷呱呤咚咛咄呶呦咝哐咭哂咴哒咧咦哓哔呲咣哕咻咿哌哙哚哜咩咪咤哝哏哞唛哧唠哽唔哳唢唣唏唑唧唪啧喏喵啉啭啁啕唿啐唼\"],[\"e040\",\"郂郃郆郈郉郋郌郍郒郔郕郖郘郙郚郞郟郠郣郤郥郩郪郬郮郰郱郲郳郵郶郷郹郺郻郼郿鄀鄁鄃鄅\",19,\"鄚鄛鄜\"],[\"e080\",\"鄝鄟鄠鄡鄤\",10,\"鄰鄲\",6,\"鄺\",8,\"酄唷啖啵啶啷唳唰啜喋嗒喃喱喹喈喁喟啾嗖喑啻嗟喽喾喔喙嗪嗷嗉嘟嗑嗫嗬嗔嗦嗝嗄嗯嗥嗲嗳嗌嗍嗨嗵嗤辔嘞嘈嘌嘁嘤嘣嗾嘀嘧嘭噘嘹噗嘬噍噢噙噜噌噔嚆噤噱噫噻噼嚅嚓嚯囔囗囝囡囵囫囹囿圄圊圉圜帏帙帔帑帱帻帼\"],[\"e140\",\"酅酇酈酑酓酔酕酖酘酙酛酜酟酠酦酧酨酫酭酳酺酻酼醀\",4,\"醆醈醊醎醏醓\",6,\"醜\",5,\"醤\",5,\"醫醬醰醱醲醳醶醷醸醹醻\"],[\"e180\",\"醼\",10,\"釈釋釐釒\",9,\"針\",8,\"帷幄幔幛幞幡岌屺岍岐岖岈岘岙岑岚岜岵岢岽岬岫岱岣峁岷峄峒峤峋峥崂崃崧崦崮崤崞崆崛嵘崾崴崽嵬嵛嵯嵝嵫嵋嵊嵩嵴嶂嶙嶝豳嶷巅彳彷徂徇徉後徕徙徜徨徭徵徼衢彡犭犰犴犷犸狃狁狎狍狒狨狯狩狲狴狷猁狳猃狺\"],[\"e240\",\"釦\",62],[\"e280\",\"鈥\",32,\"狻猗猓猡猊猞猝猕猢猹猥猬猸猱獐獍獗獠獬獯獾舛夥飧夤夂饣饧\",5,\"饴饷饽馀馄馇馊馍馐馑馓馔馕庀庑庋庖庥庠庹庵庾庳赓廒廑廛廨廪膺忄忉忖忏怃忮怄忡忤忾怅怆忪忭忸怙怵怦怛怏怍怩怫怊怿怡恸恹恻恺恂\"],[\"e340\",\"鉆\",45,\"鉵\",16],[\"e380\",\"銆\",7,\"銏\",24,\"恪恽悖悚悭悝悃悒悌悛惬悻悱惝惘惆惚悴愠愦愕愣惴愀愎愫慊慵憬憔憧憷懔懵忝隳闩闫闱闳闵闶闼闾阃阄阆阈阊阋阌阍阏阒阕阖阗阙阚丬爿戕氵汔汜汊沣沅沐沔沌汨汩汴汶沆沩泐泔沭泷泸泱泗沲泠泖泺泫泮沱泓泯泾\"],[\"e440\",\"銨\",5,\"銯\",24,\"鋉\",31],[\"e480\",\"鋩\",32,\"洹洧洌浃浈洇洄洙洎洫浍洮洵洚浏浒浔洳涑浯涞涠浞涓涔浜浠浼浣渚淇淅淞渎涿淠渑淦淝淙渖涫渌涮渫湮湎湫溲湟溆湓湔渲渥湄滟溱溘滠漭滢溥溧溽溻溷滗溴滏溏滂溟潢潆潇漤漕滹漯漶潋潴漪漉漩澉澍澌潸潲潼潺濑\"],[\"e540\",\"錊\",51,\"錿\",10],[\"e580\",\"鍊\",31,\"鍫濉澧澹澶濂濡濮濞濠濯瀚瀣瀛瀹瀵灏灞宀宄宕宓宥宸甯骞搴寤寮褰寰蹇謇辶迓迕迥迮迤迩迦迳迨逅逄逋逦逑逍逖逡逵逶逭逯遄遑遒遐遨遘遢遛暹遴遽邂邈邃邋彐彗彖彘尻咫屐屙孱屣屦羼弪弩弭艴弼鬻屮妁妃妍妩妪妣\"],[\"e640\",\"鍬\",34,\"鎐\",27],[\"e680\",\"鎬\",29,\"鏋鏌鏍妗姊妫妞妤姒妲妯姗妾娅娆姝娈姣姘姹娌娉娲娴娑娣娓婀婧婊婕娼婢婵胬媪媛婷婺媾嫫媲嫒嫔媸嫠嫣嫱嫖嫦嫘嫜嬉嬗嬖嬲嬷孀尕尜孚孥孳孑孓孢驵驷驸驺驿驽骀骁骅骈骊骐骒骓骖骘骛骜骝骟骠骢骣骥骧纟纡纣纥纨纩\"],[\"e740\",\"鏎\",7,\"鏗\",54],[\"e780\",\"鐎\",32,\"纭纰纾绀绁绂绉绋绌绐绔绗绛绠绡绨绫绮绯绱绲缍绶绺绻绾缁缂缃缇缈缋缌缏缑缒缗缙缜缛缟缡\",6,\"缪缫缬缭缯\",4,\"缵幺畿巛甾邕玎玑玮玢玟珏珂珑玷玳珀珉珈珥珙顼琊珩珧珞玺珲琏琪瑛琦琥琨琰琮琬\"],[\"e840\",\"鐯\",14,\"鐿\",43,\"鑬鑭鑮鑯\"],[\"e880\",\"鑰\",20,\"钑钖钘铇铏铓铔铚铦铻锜锠琛琚瑁瑜瑗瑕瑙瑷瑭瑾璜璎璀璁璇璋璞璨璩璐璧瓒璺韪韫韬杌杓杞杈杩枥枇杪杳枘枧杵枨枞枭枋杷杼柰栉柘栊柩枰栌柙枵柚枳柝栀柃枸柢栎柁柽栲栳桠桡桎桢桄桤梃栝桕桦桁桧桀栾桊桉栩梵梏桴桷梓桫棂楮棼椟椠棹\"],[\"e940\",\"锧锳锽镃镈镋镕镚镠镮镴镵長\",7,\"門\",42],[\"e980\",\"閫\",32,\"椤棰椋椁楗棣椐楱椹楠楂楝榄楫榀榘楸椴槌榇榈槎榉楦楣楹榛榧榻榫榭槔榱槁槊槟榕槠榍槿樯槭樗樘橥槲橄樾檠橐橛樵檎橹樽樨橘橼檑檐檩檗檫猷獒殁殂殇殄殒殓殍殚殛殡殪轫轭轱轲轳轵轶轸轷轹轺轼轾辁辂辄辇辋\"],[\"ea40\",\"闌\",27,\"闬闿阇阓阘阛阞阠阣\",6,\"阫阬阭阯阰阷阸阹阺阾陁陃陊陎陏陑陒陓陖陗\"],[\"ea80\",\"陘陙陚陜陝陞陠陣陥陦陫陭\",4,\"陳陸\",12,\"隇隉隊辍辎辏辘辚軎戋戗戛戟戢戡戥戤戬臧瓯瓴瓿甏甑甓攴旮旯旰昊昙杲昃昕昀炅曷昝昴昱昶昵耆晟晔晁晏晖晡晗晷暄暌暧暝暾曛曜曦曩贲贳贶贻贽赀赅赆赈赉赇赍赕赙觇觊觋觌觎觏觐觑牮犟牝牦牯牾牿犄犋犍犏犒挈挲掰\"],[\"eb40\",\"隌階隑隒隓隕隖隚際隝\",9,\"隨\",7,\"隱隲隴隵隷隸隺隻隿雂雃雈雊雋雐雑雓雔雖\",9,\"雡\",6,\"雫\"],[\"eb80\",\"雬雭雮雰雱雲雴雵雸雺電雼雽雿霂霃霅霊霋霌霐霑霒霔霕霗\",4,\"霝霟霠搿擘耄毪毳毽毵毹氅氇氆氍氕氘氙氚氡氩氤氪氲攵敕敫牍牒牖爰虢刖肟肜肓肼朊肽肱肫肭肴肷胧胨胩胪胛胂胄胙胍胗朐胝胫胱胴胭脍脎胲胼朕脒豚脶脞脬脘脲腈腌腓腴腙腚腱腠腩腼腽腭腧塍媵膈膂膑滕膣膪臌朦臊膻\"],[\"ec40\",\"霡\",8,\"霫霬霮霯霱霳\",4,\"霺霻霼霽霿\",18,\"靔靕靗靘靚靜靝靟靣靤靦靧靨靪\",7],[\"ec80\",\"靲靵靷\",4,\"靽\",7,\"鞆\",4,\"鞌鞎鞏鞐鞓鞕鞖鞗鞙\",4,\"臁膦欤欷欹歃歆歙飑飒飓飕飙飚殳彀毂觳斐齑斓於旆旄旃旌旎旒旖炀炜炖炝炻烀炷炫炱烨烊焐焓焖焯焱煳煜煨煅煲煊煸煺熘熳熵熨熠燠燔燧燹爝爨灬焘煦熹戾戽扃扈扉礻祀祆祉祛祜祓祚祢祗祠祯祧祺禅禊禚禧禳忑忐\"],[\"ed40\",\"鞞鞟鞡鞢鞤\",6,\"鞬鞮鞰鞱鞳鞵\",46],[\"ed80\",\"韤韥韨韮\",4,\"韴韷\",23,\"怼恝恚恧恁恙恣悫愆愍慝憩憝懋懑戆肀聿沓泶淼矶矸砀砉砗砘砑斫砭砜砝砹砺砻砟砼砥砬砣砩硎硭硖硗砦硐硇硌硪碛碓碚碇碜碡碣碲碹碥磔磙磉磬磲礅磴礓礤礞礴龛黹黻黼盱眄眍盹眇眈眚眢眙眭眦眵眸睐睑睇睃睚睨\"],[\"ee40\",\"頏\",62],[\"ee80\",\"顎\",32,\"睢睥睿瞍睽瞀瞌瞑瞟瞠瞰瞵瞽町畀畎畋畈畛畲畹疃罘罡罟詈罨罴罱罹羁罾盍盥蠲钅钆钇钋钊钌钍钏钐钔钗钕钚钛钜钣钤钫钪钭钬钯钰钲钴钶\",4,\"钼钽钿铄铈\",6,\"铐铑铒铕铖铗铙铘铛铞铟铠铢铤铥铧铨铪\"],[\"ef40\",\"顯\",5,\"颋颎颒颕颙颣風\",37,\"飏飐飔飖飗飛飜飝飠\",4],[\"ef80\",\"飥飦飩\",30,\"铩铫铮铯铳铴铵铷铹铼铽铿锃锂锆锇锉锊锍锎锏锒\",4,\"锘锛锝锞锟锢锪锫锩锬锱锲锴锶锷锸锼锾锿镂锵镄镅镆镉镌镎镏镒镓镔镖镗镘镙镛镞镟镝镡镢镤\",8,\"镯镱镲镳锺矧矬雉秕秭秣秫稆嵇稃稂稞稔\"],[\"f040\",\"餈\",4,\"餎餏餑\",28,\"餯\",26],[\"f080\",\"饊\",9,\"饖\",12,\"饤饦饳饸饹饻饾馂馃馉稹稷穑黏馥穰皈皎皓皙皤瓞瓠甬鸠鸢鸨\",4,\"鸲鸱鸶鸸鸷鸹鸺鸾鹁鹂鹄鹆鹇鹈鹉鹋鹌鹎鹑鹕鹗鹚鹛鹜鹞鹣鹦\",6,\"鹱鹭鹳疒疔疖疠疝疬疣疳疴疸痄疱疰痃痂痖痍痣痨痦痤痫痧瘃痱痼痿瘐瘀瘅瘌瘗瘊瘥瘘瘕瘙\"],[\"f140\",\"馌馎馚\",10,\"馦馧馩\",47],[\"f180\",\"駙\",32,\"瘛瘼瘢瘠癀瘭瘰瘿瘵癃瘾瘳癍癞癔癜癖癫癯翊竦穸穹窀窆窈窕窦窠窬窨窭窳衤衩衲衽衿袂袢裆袷袼裉裢裎裣裥裱褚裼裨裾裰褡褙褓褛褊褴褫褶襁襦襻疋胥皲皴矜耒耔耖耜耠耢耥耦耧耩耨耱耋耵聃聆聍聒聩聱覃顸颀颃\"],[\"f240\",\"駺\",62],[\"f280\",\"騹\",32,\"颉颌颍颏颔颚颛颞颟颡颢颥颦虍虔虬虮虿虺虼虻蚨蚍蚋蚬蚝蚧蚣蚪蚓蚩蚶蛄蚵蛎蚰蚺蚱蚯蛉蛏蚴蛩蛱蛲蛭蛳蛐蜓蛞蛴蛟蛘蛑蜃蜇蛸蜈蜊蜍蜉蜣蜻蜞蜥蜮蜚蜾蝈蜴蜱蜩蜷蜿螂蜢蝽蝾蝻蝠蝰蝌蝮螋蝓蝣蝼蝤蝙蝥螓螯螨蟒\"],[\"f340\",\"驚\",17,\"驲骃骉骍骎骔骕骙骦骩\",6,\"骲骳骴骵骹骻骽骾骿髃髄髆\",4,\"髍髎髏髐髒體髕髖髗髙髚髛髜\"],[\"f380\",\"髝髞髠髢髣髤髥髧髨髩髪髬髮髰\",8,\"髺髼\",6,\"鬄鬅鬆蟆螈螅螭螗螃螫蟥螬螵螳蟋蟓螽蟑蟀蟊蟛蟪蟠蟮蠖蠓蟾蠊蠛蠡蠹蠼缶罂罄罅舐竺竽笈笃笄笕笊笫笏筇笸笪笙笮笱笠笥笤笳笾笞筘筚筅筵筌筝筠筮筻筢筲筱箐箦箧箸箬箝箨箅箪箜箢箫箴篑篁篌篝篚篥篦篪簌篾篼簏簖簋\"],[\"f440\",\"鬇鬉\",5,\"鬐鬑鬒鬔\",10,\"鬠鬡鬢鬤\",10,\"鬰鬱鬳\",7,\"鬽鬾鬿魀魆魊魋魌魎魐魒魓魕\",5],[\"f480\",\"魛\",32,\"簟簪簦簸籁籀臾舁舂舄臬衄舡舢舣舭舯舨舫舸舻舳舴舾艄艉艋艏艚艟艨衾袅袈裘裟襞羝羟羧羯羰羲籼敉粑粝粜粞粢粲粼粽糁糇糌糍糈糅糗糨艮暨羿翎翕翥翡翦翩翮翳糸絷綦綮繇纛麸麴赳趄趔趑趱赧赭豇豉酊酐酎酏酤\"],[\"f540\",\"魼\",62],[\"f580\",\"鮻\",32,\"酢酡酰酩酯酽酾酲酴酹醌醅醐醍醑醢醣醪醭醮醯醵醴醺豕鹾趸跫踅蹙蹩趵趿趼趺跄跖跗跚跞跎跏跛跆跬跷跸跣跹跻跤踉跽踔踝踟踬踮踣踯踺蹀踹踵踽踱蹉蹁蹂蹑蹒蹊蹰蹶蹼蹯蹴躅躏躔躐躜躞豸貂貊貅貘貔斛觖觞觚觜\"],[\"f640\",\"鯜\",62],[\"f680\",\"鰛\",32,\"觥觫觯訾謦靓雩雳雯霆霁霈霏霎霪霭霰霾龀龃龅\",5,\"龌黾鼋鼍隹隼隽雎雒瞿雠銎銮鋈錾鍪鏊鎏鐾鑫鱿鲂鲅鲆鲇鲈稣鲋鲎鲐鲑鲒鲔鲕鲚鲛鲞\",5,\"鲥\",4,\"鲫鲭鲮鲰\",7,\"鲺鲻鲼鲽鳄鳅鳆鳇鳊鳋\"],[\"f740\",\"鰼\",62],[\"f780\",\"鱻鱽鱾鲀鲃鲄鲉鲊鲌鲏鲓鲖鲗鲘鲙鲝鲪鲬鲯鲹鲾\",4,\"鳈鳉鳑鳒鳚鳛鳠鳡鳌\",4,\"鳓鳔鳕鳗鳘鳙鳜鳝鳟鳢靼鞅鞑鞒鞔鞯鞫鞣鞲鞴骱骰骷鹘骶骺骼髁髀髅髂髋髌髑魅魃魇魉魈魍魑飨餍餮饕饔髟髡髦髯髫髻髭髹鬈鬏鬓鬟鬣麽麾縻麂麇麈麋麒鏖麝麟黛黜黝黠黟黢黩黧黥黪黯鼢鼬鼯鼹鼷鼽鼾齄\"],[\"f840\",\"鳣\",62],[\"f880\",\"鴢\",32],[\"f940\",\"鵃\",62],[\"f980\",\"鶂\",32],[\"fa40\",\"鶣\",62],[\"fa80\",\"鷢\",32],[\"fb40\",\"鸃\",27,\"鸤鸧鸮鸰鸴鸻鸼鹀鹍鹐鹒鹓鹔鹖鹙鹝鹟鹠鹡鹢鹥鹮鹯鹲鹴\",9,\"麀\"],[\"fb80\",\"麁麃麄麅麆麉麊麌\",5,\"麔\",8,\"麞麠\",5,\"麧麨麩麪\"],[\"fc40\",\"麫\",8,\"麵麶麷麹麺麼麿\",4,\"黅黆黇黈黊黋黌黐黒黓黕黖黗黙黚點黡黣黤黦黨黫黬黭黮黰\",8,\"黺黽黿\",6],[\"fc80\",\"鼆\",4,\"鼌鼏鼑鼒鼔鼕鼖鼘鼚\",5,\"鼡鼣\",8,\"鼭鼮鼰鼱\"],[\"fd40\",\"鼲\",4,\"鼸鼺鼼鼿\",4,\"齅\",10,\"齒\",38],[\"fd80\",\"齹\",5,\"龁龂龍\",11,\"龜龝龞龡\",4,\"郎凉秊裏隣\"],[\"fe40\",\"兀嗀﨎﨏﨑﨓﨔礼﨟蘒﨡﨣﨤﨧﨨﨩\"]]\n\n/***/ }),\n/* 54 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// fallback for non-array-like ES3 and non-enumerable old V8 strings\nvar cof = __webpack_require__(55);\n// eslint-disable-next-line no-prototype-builtins\nmodule.exports = Object('z').propertyIsEnumerable(0) ? Object : function (it) {\n  return cof(it) == 'String' ? it.split('') : Object(it);\n};\n\n\n/***/ }),\n/* 55 */\n/***/ (function(module, exports) {\n\nvar toString = {}.toString;\n\nmodule.exports = function (it) {\n  return toString.call(it).slice(8, -1);\n};\n\n\n/***/ }),\n/* 56 */\n/***/ (function(module, exports) {\n\n// 7.2.1 RequireObjectCoercible(argument)\nmodule.exports = function (it) {\n  if (it == undefined) throw TypeError(\"Can't call method on  \" + it);\n  return it;\n};\n\n\n/***/ }),\n/* 57 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar pIE = __webpack_require__(35);\nvar createDesc = __webpack_require__(27);\nvar toIObject = __webpack_require__(17);\nvar toPrimitive = __webpack_require__(58);\nvar has = __webpack_require__(18);\nvar IE8_DOM_DEFINE = __webpack_require__(95);\nvar gOPD = Object.getOwnPropertyDescriptor;\n\nexports.f = __webpack_require__(5) ? gOPD : function getOwnPropertyDescriptor(O, P) {\n  O = toIObject(O);\n  P = toPrimitive(P, true);\n  if (IE8_DOM_DEFINE) try {\n    return gOPD(O, P);\n  } catch (e) { /* empty */ }\n  if (has(O, P)) return createDesc(!pIE.f.call(O, P), O[P]);\n};\n\n\n/***/ }),\n/* 58 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 7.1.1 ToPrimitive(input [, PreferredType])\nvar isObject = __webpack_require__(9);\n// instead of the ES6 spec version, we didn't implement @@toPrimitive case\n// and the second argument - flag - preferred type is a string\nmodule.exports = function (it, S) {\n  if (!isObject(it)) return it;\n  var fn, val;\n  if (S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val;\n  if (typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it))) return val;\n  if (!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val;\n  throw TypeError(\"Can't convert object to primitive value\");\n};\n\n\n/***/ }),\n/* 59 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// most Object methods by ES6 should accept primitives\nvar $export = __webpack_require__(3);\nvar core = __webpack_require__(2);\nvar fails = __webpack_require__(19);\nmodule.exports = function (KEY, exec) {\n  var fn = (core.Object || {})[KEY] || Object[KEY];\n  var exp = {};\n  exp[KEY] = exec(fn);\n  $export($export.S + $export.F * fails(function () { fn(1); }), 'Object', exp);\n};\n\n\n/***/ }),\n/* 60 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(200), __esModule: true };\n\n/***/ }),\n/* 61 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar LIBRARY = __webpack_require__(62);\nvar $export = __webpack_require__(3);\nvar redefine = __webpack_require__(99);\nvar hide = __webpack_require__(13);\nvar has = __webpack_require__(18);\nvar Iterators = __webpack_require__(23);\nvar $iterCreate = __webpack_require__(203);\nvar setToStringTag = __webpack_require__(39);\nvar getPrototypeOf = __webpack_require__(206);\nvar ITERATOR = __webpack_require__(4)('iterator');\nvar BUGGY = !([].keys && 'next' in [].keys()); // Safari has buggy iterators w/o `next`\nvar FF_ITERATOR = '@@iterator';\nvar KEYS = 'keys';\nvar VALUES = 'values';\n\nvar returnThis = function () { return this; };\n\nmodule.exports = function (Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED) {\n  $iterCreate(Constructor, NAME, next);\n  var getMethod = function (kind) {\n    if (!BUGGY && kind in proto) return proto[kind];\n    switch (kind) {\n      case KEYS: return function keys() { return new Constructor(this, kind); };\n      case VALUES: return function values() { return new Constructor(this, kind); };\n    } return function entries() { return new Constructor(this, kind); };\n  };\n  var TAG = NAME + ' Iterator';\n  var DEF_VALUES = DEFAULT == VALUES;\n  var VALUES_BUG = false;\n  var proto = Base.prototype;\n  var $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT];\n  var $default = (!BUGGY && $native) || getMethod(DEFAULT);\n  var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined;\n  var $anyNative = NAME == 'Array' ? proto.entries || $native : $native;\n  var methods, key, IteratorPrototype;\n  // Fix native\n  if ($anyNative) {\n    IteratorPrototype = getPrototypeOf($anyNative.call(new Base()));\n    if (IteratorPrototype !== Object.prototype && IteratorPrototype.next) {\n      // Set @@toStringTag to native iterators\n      setToStringTag(IteratorPrototype, TAG, true);\n      // fix for some old engines\n      if (!LIBRARY && !has(IteratorPrototype, ITERATOR)) hide(IteratorPrototype, ITERATOR, returnThis);\n    }\n  }\n  // fix Array#{values, @@iterator}.name in V8 / FF\n  if (DEF_VALUES && $native && $native.name !== VALUES) {\n    VALUES_BUG = true;\n    $default = function values() { return $native.call(this); };\n  }\n  // Define iterator\n  if ((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])) {\n    hide(proto, ITERATOR, $default);\n  }\n  // Plug for library\n  Iterators[NAME] = $default;\n  Iterators[TAG] = returnThis;\n  if (DEFAULT) {\n    methods = {\n      values: DEF_VALUES ? $default : getMethod(VALUES),\n      keys: IS_SET ? $default : getMethod(KEYS),\n      entries: $entries\n    };\n    if (FORCED) for (key in methods) {\n      if (!(key in proto)) redefine(proto, key, methods[key]);\n    } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods);\n  }\n  return methods;\n};\n\n\n/***/ }),\n/* 62 */\n/***/ (function(module, exports) {\n\nmodule.exports = true;\n\n\n/***/ }),\n/* 63 */\n/***/ (function(module, exports) {\n\n// 7.1.4 ToInteger\nvar ceil = Math.ceil;\nvar floor = Math.floor;\nmodule.exports = function (it) {\n  return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it);\n};\n\n\n/***/ }),\n/* 64 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar shared = __webpack_require__(65)('keys');\nvar uid = __webpack_require__(38);\nmodule.exports = function (key) {\n  return shared[key] || (shared[key] = uid(key));\n};\n\n\n/***/ }),\n/* 65 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar global = __webpack_require__(10);\nvar SHARED = '__core-js_shared__';\nvar store = global[SHARED] || (global[SHARED] = {});\nmodule.exports = function (key) {\n  return store[key] || (store[key] = {});\n};\n\n\n/***/ }),\n/* 66 */\n/***/ (function(module, exports) {\n\n// IE 8- don't enum bug keys\nmodule.exports = (\n  'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf'\n).split(',');\n\n\n/***/ }),\n/* 67 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar classof = __webpack_require__(68);\nvar ITERATOR = __webpack_require__(4)('iterator');\nvar Iterators = __webpack_require__(23);\nmodule.exports = __webpack_require__(2).getIteratorMethod = function (it) {\n  if (it != undefined) return it[ITERATOR]\n    || it['@@iterator']\n    || Iterators[classof(it)];\n};\n\n\n/***/ }),\n/* 68 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// getting tag from 19.1.3.6 Object.prototype.toString()\nvar cof = __webpack_require__(55);\nvar TAG = __webpack_require__(4)('toStringTag');\n// ES3 wrong here\nvar ARG = cof(function () { return arguments; }()) == 'Arguments';\n\n// fallback for IE11 Script Access Denied error\nvar tryGet = function (it, key) {\n  try {\n    return it[key];\n  } catch (e) { /* empty */ }\n};\n\nmodule.exports = function (it) {\n  var O, T, B;\n  return it === undefined ? 'Undefined' : it === null ? 'Null'\n    // @@toStringTag case\n    : typeof (T = tryGet(O = Object(it), TAG)) == 'string' ? T\n    // builtinTag case\n    : ARG ? cof(O)\n    // ES3 arguments fallback\n    : (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B;\n};\n\n\n/***/ }),\n/* 69 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nvar _iterator = __webpack_require__(103);\n\nvar _iterator2 = _interopRequireDefault(_iterator);\n\nvar _symbol = __webpack_require__(216);\n\nvar _symbol2 = _interopRequireDefault(_symbol);\n\nvar _typeof = typeof _symbol2.default === \"function\" && typeof _iterator2.default === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof _symbol2.default === \"function\" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? \"symbol\" : typeof obj; };\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nexports.default = typeof _symbol2.default === \"function\" && _typeof(_iterator2.default) === \"symbol\" ? function (obj) {\n  return typeof obj === \"undefined\" ? \"undefined\" : _typeof(obj);\n} : function (obj) {\n  return obj && typeof _symbol2.default === \"function\" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? \"symbol\" : typeof obj === \"undefined\" ? \"undefined\" : _typeof(obj);\n};\n\n/***/ }),\n/* 70 */\n/***/ (function(module, exports, __webpack_require__) {\n\nexports.f = __webpack_require__(4);\n\n\n/***/ }),\n/* 71 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar global = __webpack_require__(10);\nvar core = __webpack_require__(2);\nvar LIBRARY = __webpack_require__(62);\nvar wksExt = __webpack_require__(70);\nvar defineProperty = __webpack_require__(6).f;\nmodule.exports = function (name) {\n  var $Symbol = core.Symbol || (core.Symbol = LIBRARY ? {} : global.Symbol || {});\n  if (name.charAt(0) != '_' && !(name in $Symbol)) defineProperty($Symbol, name, { value: wksExt.f(name) });\n};\n\n\n/***/ }),\n/* 72 */\n/***/ (function(module, exports) {\n\nexports.f = Object.getOwnPropertySymbols;\n\n\n/***/ }),\n/* 73 */\n/***/ (function(module, exports) {\n\n\n\n/***/ }),\n/* 74 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(223), __esModule: true };\n\n/***/ }),\n/* 75 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar isObject = __webpack_require__(9);\nmodule.exports = function (it, TYPE) {\n  if (!isObject(it) || it._t !== TYPE) throw TypeError('Incompatible receiver, ' + TYPE + ' required!');\n  return it;\n};\n\n\n/***/ }),\n/* 76 */\n/***/ (function(module, exports) {\n\nvar toString = {}.toString;\n\nmodule.exports = Array.isArray || function (arr) {\n  return toString.call(arr) == '[object Array]';\n};\n\n\n/***/ }),\n/* 77 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nfunction TraversalTracker() {\n\tthis.events = {};\n}\n\nTraversalTracker.prototype.startTracking = function (event, callback) {\n\tvar callbacks = this.events[event] || (this.events[event] = []);\n\n\tif (callbacks.indexOf(callback) < 0) {\n\t\tcallbacks.push(callback);\n\t}\n};\n\nTraversalTracker.prototype.stopTracking = function (event, callback) {\n\tvar callbacks = this.events[event];\n\n\tif (!callbacks) {\n\t\treturn;\n\t}\n\n\tvar index = callbacks.indexOf(callback);\n\tif (index >= 0) {\n\t\tcallbacks.splice(index, 1);\n\t}\n};\n\nTraversalTracker.prototype.emit = function (event) {\n\tvar args = Array.prototype.slice.call(arguments, 1);\n\tvar callbacks = this.events[event];\n\n\tif (!callbacks) {\n\t\treturn;\n\t}\n\n\tcallbacks.forEach(function (callback) {\n\t\tcallback.apply(this, args);\n\t});\n};\n\nTraversalTracker.prototype.auto = function (event, callback, innerFunction) {\n\tthis.startTracking(event, callback);\n\tinnerFunction();\n\tthis.stopTracking(event, callback);\n};\n\nmodule.exports = TraversalTracker;\n\n\n/***/ }),\n/* 78 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var AI, AL, BA, BK, CB, CI_BRK, CJ, CP_BRK, CR, DI_BRK, ID, IN_BRK, LF, LineBreaker, NL, NS, PR_BRK, SA, SG, SP, UnicodeTrie, WJ, XX, base64, characterClasses, classTrie, data, fs, pairTable, _ref, _ref1;\n\n  UnicodeTrie = __webpack_require__(43);\n\n  \n\n  base64 = __webpack_require__(131);\n\n  _ref = __webpack_require__(132), BK = _ref.BK, CR = _ref.CR, LF = _ref.LF, NL = _ref.NL, CB = _ref.CB, BA = _ref.BA, SP = _ref.SP, WJ = _ref.WJ, SP = _ref.SP, BK = _ref.BK, LF = _ref.LF, NL = _ref.NL, AI = _ref.AI, AL = _ref.AL, SA = _ref.SA, SG = _ref.SG, XX = _ref.XX, CJ = _ref.CJ, ID = _ref.ID, NS = _ref.NS, characterClasses = _ref.characterClasses;\n\n  _ref1 = __webpack_require__(133), DI_BRK = _ref1.DI_BRK, IN_BRK = _ref1.IN_BRK, CI_BRK = _ref1.CI_BRK, CP_BRK = _ref1.CP_BRK, PR_BRK = _ref1.PR_BRK, pairTable = _ref1.pairTable;\n\n  data = base64.toByteArray(\"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\");\n\n  classTrie = new UnicodeTrie(data);\n\n  LineBreaker = (function() {\n    var Break, mapClass, mapFirst;\n\n    function LineBreaker(string) {\n      this.string = string;\n      this.pos = 0;\n      this.lastPos = 0;\n      this.curClass = null;\n      this.nextClass = null;\n    }\n\n    LineBreaker.prototype.nextCodePoint = function() {\n      var code, next;\n      code = this.string.charCodeAt(this.pos++);\n      next = this.string.charCodeAt(this.pos);\n      if ((0xd800 <= code && code <= 0xdbff) && (0xdc00 <= next && next <= 0xdfff)) {\n        this.pos++;\n        return ((code - 0xd800) * 0x400) + (next - 0xdc00) + 0x10000;\n      }\n      return code;\n    };\n\n    mapClass = function(c) {\n      switch (c) {\n        case AI:\n          return AL;\n        case SA:\n        case SG:\n        case XX:\n          return AL;\n        case CJ:\n          return NS;\n        default:\n          return c;\n      }\n    };\n\n    mapFirst = function(c) {\n      switch (c) {\n        case LF:\n        case NL:\n          return BK;\n        case CB:\n          return BA;\n        case SP:\n          return WJ;\n        default:\n          return c;\n      }\n    };\n\n    LineBreaker.prototype.nextCharClass = function(first) {\n      if (first == null) {\n        first = false;\n      }\n      return mapClass(classTrie.get(this.nextCodePoint()));\n    };\n\n    Break = (function() {\n      function Break(position, required) {\n        this.position = position;\n        this.required = required != null ? required : false;\n      }\n\n      return Break;\n\n    })();\n\n    LineBreaker.prototype.nextBreak = function() {\n      var cur, lastClass, shouldBreak;\n      if (this.curClass == null) {\n        this.curClass = mapFirst(this.nextCharClass());\n      }\n      while (this.pos < this.string.length) {\n        this.lastPos = this.pos;\n        lastClass = this.nextClass;\n        this.nextClass = this.nextCharClass();\n        if (this.curClass === BK || (this.curClass === CR && this.nextClass !== LF)) {\n          this.curClass = mapFirst(mapClass(this.nextClass));\n          return new Break(this.lastPos, true);\n        }\n        cur = (function() {\n          switch (this.nextClass) {\n            case SP:\n              return this.curClass;\n            case BK:\n            case LF:\n            case NL:\n              return BK;\n            case CR:\n              return CR;\n            case CB:\n              return BA;\n          }\n        }).call(this);\n        if (cur != null) {\n          this.curClass = cur;\n          if (this.nextClass === CB) {\n            return new Break(this.lastPos);\n          }\n          continue;\n        }\n        shouldBreak = false;\n        switch (pairTable[this.curClass][this.nextClass]) {\n          case DI_BRK:\n            shouldBreak = true;\n            break;\n          case IN_BRK:\n            shouldBreak = lastClass === SP;\n            break;\n          case CI_BRK:\n            shouldBreak = lastClass === SP;\n            if (!shouldBreak) {\n              continue;\n            }\n            break;\n          case CP_BRK:\n            if (lastClass !== SP) {\n              continue;\n            }\n        }\n        this.curClass = this.nextClass;\n        if (shouldBreak) {\n          return new Break(this.lastPos);\n        }\n      }\n      if (this.pos >= this.string.length) {\n        if (this.lastPos < this.string.length) {\n          this.lastPos = this.string.length;\n          return new Break(this.string.length);\n        } else {\n          return null;\n        }\n      }\n    };\n\n    return LineBreaker;\n\n  })();\n\n  module.exports = LineBreaker;\n\n}).call(this);\n\n\n/***/ }),\n/* 79 */\n/***/ (function(module, exports) {\n\nvar TINF_OK = 0;\nvar TINF_DATA_ERROR = -3;\n\nfunction Tree() {\n  this.table = new Uint16Array(16);   /* table of code length counts */\n  this.trans = new Uint16Array(288);  /* code -> symbol translation table */\n}\n\nfunction Data(source, dest) {\n  this.source = source;\n  this.sourceIndex = 0;\n  this.tag = 0;\n  this.bitcount = 0;\n  \n  this.dest = dest;\n  this.destLen = 0;\n  \n  this.ltree = new Tree();  /* dynamic length/symbol tree */\n  this.dtree = new Tree();  /* dynamic distance tree */\n}\n\n/* --------------------------------------------------- *\n * -- uninitialized global data (static structures) -- *\n * --------------------------------------------------- */\n\nvar sltree = new Tree();\nvar sdtree = new Tree();\n\n/* extra bits and base tables for length codes */\nvar length_bits = new Uint8Array(30);\nvar length_base = new Uint16Array(30);\n\n/* extra bits and base tables for distance codes */\nvar dist_bits = new Uint8Array(30);\nvar dist_base = new Uint16Array(30);\n\n/* special ordering of code length codes */\nvar clcidx = new Uint8Array([\n  16, 17, 18, 0, 8, 7, 9, 6,\n  10, 5, 11, 4, 12, 3, 13, 2,\n  14, 1, 15\n]);\n\n/* used by tinf_decode_trees, avoids allocations every call */\nvar code_tree = new Tree();\nvar lengths = new Uint8Array(288 + 32);\n\n/* ----------------------- *\n * -- utility functions -- *\n * ----------------------- */\n\n/* build extra bits and base tables */\nfunction tinf_build_bits_base(bits, base, delta, first) {\n  var i, sum;\n\n  /* build bits table */\n  for (i = 0; i < delta; ++i) bits[i] = 0;\n  for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta | 0;\n\n  /* build base table */\n  for (sum = first, i = 0; i < 30; ++i) {\n    base[i] = sum;\n    sum += 1 << bits[i];\n  }\n}\n\n/* build the fixed huffman trees */\nfunction tinf_build_fixed_trees(lt, dt) {\n  var i;\n\n  /* build fixed length tree */\n  for (i = 0; i < 7; ++i) lt.table[i] = 0;\n\n  lt.table[7] = 24;\n  lt.table[8] = 152;\n  lt.table[9] = 112;\n\n  for (i = 0; i < 24; ++i) lt.trans[i] = 256 + i;\n  for (i = 0; i < 144; ++i) lt.trans[24 + i] = i;\n  for (i = 0; i < 8; ++i) lt.trans[24 + 144 + i] = 280 + i;\n  for (i = 0; i < 112; ++i) lt.trans[24 + 144 + 8 + i] = 144 + i;\n\n  /* build fixed distance tree */\n  for (i = 0; i < 5; ++i) dt.table[i] = 0;\n\n  dt.table[5] = 32;\n\n  for (i = 0; i < 32; ++i) dt.trans[i] = i;\n}\n\n/* given an array of code lengths, build a tree */\nvar offs = new Uint16Array(16);\n\nfunction tinf_build_tree(t, lengths, off, num) {\n  var i, sum;\n\n  /* clear code length count table */\n  for (i = 0; i < 16; ++i) t.table[i] = 0;\n\n  /* scan symbol lengths, and sum code length counts */\n  for (i = 0; i < num; ++i) t.table[lengths[off + i]]++;\n\n  t.table[0] = 0;\n\n  /* compute offset table for distribution sort */\n  for (sum = 0, i = 0; i < 16; ++i) {\n    offs[i] = sum;\n    sum += t.table[i];\n  }\n\n  /* create code->symbol translation table (symbols sorted by code) */\n  for (i = 0; i < num; ++i) {\n    if (lengths[off + i]) t.trans[offs[lengths[off + i]]++] = i;\n  }\n}\n\n/* ---------------------- *\n * -- decode functions -- *\n * ---------------------- */\n\n/* get one bit from source stream */\nfunction tinf_getbit(d) {\n  /* check if tag is empty */\n  if (!d.bitcount--) {\n    /* load next tag */\n    d.tag = d.source[d.sourceIndex++];\n    d.bitcount = 7;\n  }\n\n  /* shift bit out of tag */\n  var bit = d.tag & 1;\n  d.tag >>>= 1;\n\n  return bit;\n}\n\n/* read a num bit value from a stream and add base */\nfunction tinf_read_bits(d, num, base) {\n  if (!num)\n    return base;\n\n  while (d.bitcount < 24) {\n    d.tag |= d.source[d.sourceIndex++] << d.bitcount;\n    d.bitcount += 8;\n  }\n\n  var val = d.tag & (0xffff >>> (16 - num));\n  d.tag >>>= num;\n  d.bitcount -= num;\n  return val + base;\n}\n\n/* given a data stream and a tree, decode a symbol */\nfunction tinf_decode_symbol(d, t) {\n  while (d.bitcount < 24) {\n    d.tag |= d.source[d.sourceIndex++] << d.bitcount;\n    d.bitcount += 8;\n  }\n  \n  var sum = 0, cur = 0, len = 0;\n  var tag = d.tag;\n\n  /* get more bits while code value is above sum */\n  do {\n    cur = 2 * cur + (tag & 1);\n    tag >>>= 1;\n    ++len;\n\n    sum += t.table[len];\n    cur -= t.table[len];\n  } while (cur >= 0);\n  \n  d.tag = tag;\n  d.bitcount -= len;\n\n  return t.trans[sum + cur];\n}\n\n/* given a data stream, decode dynamic trees from it */\nfunction tinf_decode_trees(d, lt, dt) {\n  var hlit, hdist, hclen;\n  var i, num, length;\n\n  /* get 5 bits HLIT (257-286) */\n  hlit = tinf_read_bits(d, 5, 257);\n\n  /* get 5 bits HDIST (1-32) */\n  hdist = tinf_read_bits(d, 5, 1);\n\n  /* get 4 bits HCLEN (4-19) */\n  hclen = tinf_read_bits(d, 4, 4);\n\n  for (i = 0; i < 19; ++i) lengths[i] = 0;\n\n  /* read code lengths for code length alphabet */\n  for (i = 0; i < hclen; ++i) {\n    /* get 3 bits code length (0-7) */\n    var clen = tinf_read_bits(d, 3, 0);\n    lengths[clcidx[i]] = clen;\n  }\n\n  /* build code length tree */\n  tinf_build_tree(code_tree, lengths, 0, 19);\n\n  /* decode code lengths for the dynamic trees */\n  for (num = 0; num < hlit + hdist;) {\n    var sym = tinf_decode_symbol(d, code_tree);\n\n    switch (sym) {\n      case 16:\n        /* copy previous code length 3-6 times (read 2 bits) */\n        var prev = lengths[num - 1];\n        for (length = tinf_read_bits(d, 2, 3); length; --length) {\n          lengths[num++] = prev;\n        }\n        break;\n      case 17:\n        /* repeat code length 0 for 3-10 times (read 3 bits) */\n        for (length = tinf_read_bits(d, 3, 3); length; --length) {\n          lengths[num++] = 0;\n        }\n        break;\n      case 18:\n        /* repeat code length 0 for 11-138 times (read 7 bits) */\n        for (length = tinf_read_bits(d, 7, 11); length; --length) {\n          lengths[num++] = 0;\n        }\n        break;\n      default:\n        /* values 0-15 represent the actual code lengths */\n        lengths[num++] = sym;\n        break;\n    }\n  }\n\n  /* build dynamic trees */\n  tinf_build_tree(lt, lengths, 0, hlit);\n  tinf_build_tree(dt, lengths, hlit, hdist);\n}\n\n/* ----------------------------- *\n * -- block inflate functions -- *\n * ----------------------------- */\n\n/* given a stream and two trees, inflate a block of data */\nfunction tinf_inflate_block_data(d, lt, dt) {\n  while (1) {\n    var sym = tinf_decode_symbol(d, lt);\n\n    /* check for end of block */\n    if (sym === 256) {\n      return TINF_OK;\n    }\n\n    if (sym < 256) {\n      d.dest[d.destLen++] = sym;\n    } else {\n      var length, dist, offs;\n      var i;\n\n      sym -= 257;\n\n      /* possibly get more bits from length code */\n      length = tinf_read_bits(d, length_bits[sym], length_base[sym]);\n\n      dist = tinf_decode_symbol(d, dt);\n\n      /* possibly get more bits from distance code */\n      offs = d.destLen - tinf_read_bits(d, dist_bits[dist], dist_base[dist]);\n\n      /* copy match */\n      for (i = offs; i < offs + length; ++i) {\n        d.dest[d.destLen++] = d.dest[i];\n      }\n    }\n  }\n}\n\n/* inflate an uncompressed block of data */\nfunction tinf_inflate_uncompressed_block(d) {\n  var length, invlength;\n  var i;\n  \n  /* unread from bitbuffer */\n  while (d.bitcount > 8) {\n    d.sourceIndex--;\n    d.bitcount -= 8;\n  }\n\n  /* get length */\n  length = d.source[d.sourceIndex + 1];\n  length = 256 * length + d.source[d.sourceIndex];\n\n  /* get one's complement of length */\n  invlength = d.source[d.sourceIndex + 3];\n  invlength = 256 * invlength + d.source[d.sourceIndex + 2];\n\n  /* check length */\n  if (length !== (~invlength & 0x0000ffff))\n    return TINF_DATA_ERROR;\n\n  d.sourceIndex += 4;\n\n  /* copy block */\n  for (i = length; i; --i)\n    d.dest[d.destLen++] = d.source[d.sourceIndex++];\n\n  /* make sure we start next block on a byte boundary */\n  d.bitcount = 0;\n\n  return TINF_OK;\n}\n\n/* inflate stream from source to dest */\nfunction tinf_uncompress(source, dest) {\n  var d = new Data(source, dest);\n  var bfinal, btype, res;\n\n  do {\n    /* read final block flag */\n    bfinal = tinf_getbit(d);\n\n    /* read block type (2 bits) */\n    btype = tinf_read_bits(d, 2, 0);\n\n    /* decompress block */\n    switch (btype) {\n      case 0:\n        /* decompress uncompressed block */\n        res = tinf_inflate_uncompressed_block(d);\n        break;\n      case 1:\n        /* decompress block with fixed huffman trees */\n        res = tinf_inflate_block_data(d, sltree, sdtree);\n        break;\n      case 2:\n        /* decompress block with dynamic huffman trees */\n        tinf_decode_trees(d, d.ltree, d.dtree);\n        res = tinf_inflate_block_data(d, d.ltree, d.dtree);\n        break;\n      default:\n        res = TINF_DATA_ERROR;\n    }\n\n    if (res !== TINF_OK)\n      throw new Error('Data error');\n\n  } while (!bfinal);\n\n  if (d.destLen < d.dest.length) {\n    if (typeof d.dest.slice === 'function')\n      return d.dest.slice(0, d.destLen);\n    else\n      return d.dest.subarray(0, d.destLen);\n  }\n  \n  return d.dest;\n}\n\n/* -------------------- *\n * -- initialization -- *\n * -------------------- */\n\n/* build fixed huffman trees */\ntinf_build_fixed_trees(sltree, sdtree);\n\n/* build extra bits and base tables */\ntinf_build_bits_base(length_bits, length_base, 4, 3);\ntinf_build_bits_base(dist_bits, dist_base, 2, 1);\n\n/* fix a special case */\nlength_bits[28] = 0;\nlength_base[28] = 258;\n\nmodule.exports = tinf_uncompress;\n\n\n/***/ }),\n/* 80 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar isString = __webpack_require__(0).isString;\nvar isArray = __webpack_require__(0).isArray;\nvar isUndefined = __webpack_require__(0).isUndefined;\nvar isNull = __webpack_require__(0).isNull;\n\n/**\n * Creates an instance of StyleContextStack used for style inheritance and style overrides\n *\n * @constructor\n * @this {StyleContextStack}\n * @param {Object} named styles dictionary\n * @param {Object} optional default style definition\n */\nfunction StyleContextStack(styleDictionary, defaultStyle) {\n\tthis.defaultStyle = defaultStyle || {};\n\tthis.styleDictionary = styleDictionary;\n\tthis.styleOverrides = [];\n}\n\n/**\n * Creates cloned version of current stack\n * @return {StyleContextStack} current stack snapshot\n */\nStyleContextStack.prototype.clone = function () {\n\tvar stack = new StyleContextStack(this.styleDictionary, this.defaultStyle);\n\n\tthis.styleOverrides.forEach(function (item) {\n\t\tstack.styleOverrides.push(item);\n\t});\n\n\treturn stack;\n};\n\n/**\n * Pushes style-name or style-overrides-object onto the stack for future evaluation\n *\n * @param {String|Object} styleNameOrOverride style-name (referring to styleDictionary) or\n *                                            a new dictionary defining overriding properties\n */\nStyleContextStack.prototype.push = function (styleNameOrOverride) {\n\tthis.styleOverrides.push(styleNameOrOverride);\n};\n\n/**\n * Removes last style-name or style-overrides-object from the stack\n *\n * @param {Number} howMany - optional number of elements to be popped (if not specified,\n *                           one element will be removed from the stack)\n */\nStyleContextStack.prototype.pop = function (howMany) {\n\thowMany = howMany || 1;\n\n\twhile (howMany-- > 0) {\n\t\tthis.styleOverrides.pop();\n\t}\n};\n\n/**\n * Creates a set of named styles or/and a style-overrides-object based on the item,\n * pushes those elements onto the stack for future evaluation and returns the number\n * of elements pushed, so they can be easily poped then.\n *\n * @param {Object} item - an object with optional style property and/or style overrides\n * @return the number of items pushed onto the stack\n */\nStyleContextStack.prototype.autopush = function (item) {\n\tif (isString(item)) {\n\t\treturn 0;\n\t}\n\n\tvar styleNames = [];\n\n\tif (item.style) {\n\t\tif (isArray(item.style)) {\n\t\t\tstyleNames = item.style;\n\t\t} else {\n\t\t\tstyleNames = [item.style];\n\t\t}\n\t}\n\n\tfor (var i = 0, l = styleNames.length; i < l; i++) {\n\t\tthis.push(styleNames[i]);\n\t}\n\n\tvar styleProperties = [\n\t\t'font',\n\t\t'fontSize',\n\t\t'fontFeatures',\n\t\t'bold',\n\t\t'italics',\n\t\t'alignment',\n\t\t'color',\n\t\t'columnGap',\n\t\t'fillColor',\n\t\t'decoration',\n\t\t'decorationStyle',\n\t\t'decorationColor',\n\t\t'background',\n\t\t'lineHeight',\n\t\t'characterSpacing',\n\t\t'noWrap',\n\t\t'markerColor',\n\t\t'leadingIndent'\n\t\t\t//'tableCellPadding'\n\t\t\t// 'cellBorder',\n\t\t\t// 'headerCellBorder',\n\t\t\t// 'oddRowCellBorder',\n\t\t\t// 'evenRowCellBorder',\n\t\t\t// 'tableBorder'\n\t];\n\tvar styleOverrideObject = {};\n\tvar pushStyleOverrideObject = false;\n\n\tstyleProperties.forEach(function (key) {\n\t\tif (!isUndefined(item[key]) && !isNull(item[key])) {\n\t\t\tstyleOverrideObject[key] = item[key];\n\t\t\tpushStyleOverrideObject = true;\n\t\t}\n\t});\n\n\tif (pushStyleOverrideObject) {\n\t\tthis.push(styleOverrideObject);\n\t}\n\n\treturn styleNames.length + (pushStyleOverrideObject ? 1 : 0);\n};\n\n/**\n * Automatically pushes elements onto the stack, using autopush based on item,\n * executes callback and then pops elements back. Returns value returned by callback\n *\n * @param  {Object}   item - an object with optional style property and/or style overrides\n * @param  {Function} function to be called between autopush and pop\n * @return {Object} value returned by callback\n */\nStyleContextStack.prototype.auto = function (item, callback) {\n\tvar pushedItems = this.autopush(item);\n\tvar result = callback();\n\n\tif (pushedItems > 0) {\n\t\tthis.pop(pushedItems);\n\t}\n\n\treturn result;\n};\n\n/**\n * Evaluates stack and returns value of a named property\n *\n * @param {String} property - property name\n * @return property value or null if not found\n */\nStyleContextStack.prototype.getProperty = function (property) {\n\tif (this.styleOverrides) {\n\t\tfor (var i = this.styleOverrides.length - 1; i >= 0; i--) {\n\t\t\tvar item = this.styleOverrides[i];\n\n\t\t\tif (isString(item)) {\n\t\t\t\t// named-style-override\n\t\t\t\tvar style = this.styleDictionary[item];\n\t\t\t\tif (style && !isUndefined(style[property]) && !isNull(style[property])) {\n\t\t\t\t\treturn style[property];\n\t\t\t\t}\n\t\t\t} else if (!isUndefined(item[property]) && !isNull(item[property])) {\n\t\t\t\t// style-overrides-object\n\t\t\t\treturn item[property];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn this.defaultStyle && this.defaultStyle[property];\n};\n\nmodule.exports = StyleContextStack;\n\n\n/***/ }),\n/* 81 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar TraversalTracker = __webpack_require__(77);\nvar isString = __webpack_require__(0).isString;\n\n/**\n * Creates an instance of DocumentContext - a store for current x, y positions and available width/height.\n * It facilitates column divisions and vertical sync\n */\nfunction DocumentContext(pageSize, pageMargins) {\n\tthis.pages = [];\n\n\tthis.pageMargins = pageMargins;\n\n\tthis.x = pageMargins.left;\n\tthis.availableWidth = pageSize.width - pageMargins.left - pageMargins.right;\n\tthis.availableHeight = 0;\n\tthis.page = -1;\n\n\tthis.snapshots = [];\n\n\tthis.endingCell = null;\n\n\tthis.tracker = new TraversalTracker();\n\n\tthis.addPage(pageSize);\n\n\tthis.hasBackground = false;\n}\n\nDocumentContext.prototype.beginColumnGroup = function () {\n\tthis.snapshots.push({\n\t\tx: this.x,\n\t\ty: this.y,\n\t\tavailableHeight: this.availableHeight,\n\t\tavailableWidth: this.availableWidth,\n\t\tpage: this.page,\n\t\tbottomMost: {\n\t\t\tx: this.x,\n\t\t\ty: this.y,\n\t\t\tavailableHeight: this.availableHeight,\n\t\t\tavailableWidth: this.availableWidth,\n\t\t\tpage: this.page\n\t\t},\n\t\tendingCell: this.endingCell,\n\t\tlastColumnWidth: this.lastColumnWidth\n\t});\n\n\tthis.lastColumnWidth = 0;\n};\n\nDocumentContext.prototype.beginColumn = function (width, offset, endingCell) {\n\tvar saved = this.snapshots[this.snapshots.length - 1];\n\n\tthis.calculateBottomMost(saved);\n\n\tthis.endingCell = endingCell;\n\tthis.page = saved.page;\n\tthis.x = this.x + this.lastColumnWidth + (offset || 0);\n\tthis.y = saved.y;\n\tthis.availableWidth = width;\t//saved.availableWidth - offset;\n\tthis.availableHeight = saved.availableHeight;\n\n\tthis.lastColumnWidth = width;\n};\n\nDocumentContext.prototype.calculateBottomMost = function (destContext) {\n\tif (this.endingCell) {\n\t\tthis.saveContextInEndingCell(this.endingCell);\n\t\tthis.endingCell = null;\n\t} else {\n\t\tdestContext.bottomMost = bottomMostContext(this, destContext.bottomMost);\n\t}\n};\n\nDocumentContext.prototype.markEnding = function (endingCell) {\n\tthis.page = endingCell._columnEndingContext.page;\n\tthis.x = endingCell._columnEndingContext.x;\n\tthis.y = endingCell._columnEndingContext.y;\n\tthis.availableWidth = endingCell._columnEndingContext.availableWidth;\n\tthis.availableHeight = endingCell._columnEndingContext.availableHeight;\n\tthis.lastColumnWidth = endingCell._columnEndingContext.lastColumnWidth;\n};\n\nDocumentContext.prototype.saveContextInEndingCell = function (endingCell) {\n\tendingCell._columnEndingContext = {\n\t\tpage: this.page,\n\t\tx: this.x,\n\t\ty: this.y,\n\t\tavailableHeight: this.availableHeight,\n\t\tavailableWidth: this.availableWidth,\n\t\tlastColumnWidth: this.lastColumnWidth\n\t};\n};\n\nDocumentContext.prototype.completeColumnGroup = function (height) {\n\tvar saved = this.snapshots.pop();\n\n\tthis.calculateBottomMost(saved);\n\n\tthis.endingCell = null;\n\tthis.x = saved.x;\n\n\tvar y = saved.bottomMost.y;\n\tif (height) {\n\t\tif (saved.page === saved.bottomMost.page) {\n\t\t\tif ((saved.y + height) > y) {\n\t\t\t\ty = saved.y + height;\n\t\t\t}\n\t\t} else {\n\t\t\ty += height;\n\t\t}\n\t}\n\n\tthis.y = y;\n\tthis.page = saved.bottomMost.page;\n\tthis.availableWidth = saved.availableWidth;\n\tthis.availableHeight = saved.bottomMost.availableHeight;\n\tif (height) {\n\t\tthis.availableHeight -= (y - saved.bottomMost.y);\n\t}\n\tthis.lastColumnWidth = saved.lastColumnWidth;\n};\n\nDocumentContext.prototype.addMargin = function (left, right) {\n\tthis.x += left;\n\tthis.availableWidth -= left + (right || 0);\n};\n\nDocumentContext.prototype.moveDown = function (offset) {\n\tthis.y += offset;\n\tthis.availableHeight -= offset;\n\n\treturn this.availableHeight > 0;\n};\n\nDocumentContext.prototype.initializePage = function () {\n\tthis.y = this.pageMargins.top;\n\tthis.availableHeight = this.getCurrentPage().pageSize.height - this.pageMargins.top - this.pageMargins.bottom;\n\tthis.pageSnapshot().availableWidth = this.getCurrentPage().pageSize.width - this.pageMargins.left - this.pageMargins.right;\n};\n\nDocumentContext.prototype.pageSnapshot = function () {\n\tif (this.snapshots[0]) {\n\t\treturn this.snapshots[0];\n\t} else {\n\t\treturn this;\n\t}\n};\n\nDocumentContext.prototype.moveTo = function (x, y) {\n\tif (x !== undefined && x !== null) {\n\t\tthis.x = x;\n\t\tthis.availableWidth = this.getCurrentPage().pageSize.width - this.x - this.pageMargins.right;\n\t}\n\tif (y !== undefined && y !== null) {\n\t\tthis.y = y;\n\t\tthis.availableHeight = this.getCurrentPage().pageSize.height - this.y - this.pageMargins.bottom;\n\t}\n};\n\nDocumentContext.prototype.beginDetachedBlock = function () {\n\tthis.snapshots.push({\n\t\tx: this.x,\n\t\ty: this.y,\n\t\tavailableHeight: this.availableHeight,\n\t\tavailableWidth: this.availableWidth,\n\t\tpage: this.page,\n\t\tendingCell: this.endingCell,\n\t\tlastColumnWidth: this.lastColumnWidth\n\t});\n};\n\nDocumentContext.prototype.endDetachedBlock = function () {\n\tvar saved = this.snapshots.pop();\n\n\tthis.x = saved.x;\n\tthis.y = saved.y;\n\tthis.availableWidth = saved.availableWidth;\n\tthis.availableHeight = saved.availableHeight;\n\tthis.page = saved.page;\n\tthis.endingCell = saved.endingCell;\n\tthis.lastColumnWidth = saved.lastColumnWidth;\n};\n\nfunction pageOrientation(pageOrientationString, currentPageOrientation) {\n\tif (pageOrientationString === undefined) {\n\t\treturn currentPageOrientation;\n\t} else if (isString(pageOrientationString) && (pageOrientationString.toLowerCase() === 'landscape')) {\n\t\treturn 'landscape';\n\t} else {\n\t\treturn 'portrait';\n\t}\n}\n\nvar getPageSize = function (currentPage, newPageOrientation) {\n\n\tnewPageOrientation = pageOrientation(newPageOrientation, currentPage.pageSize.orientation);\n\n\tif (newPageOrientation !== currentPage.pageSize.orientation) {\n\t\treturn {\n\t\t\torientation: newPageOrientation,\n\t\t\twidth: currentPage.pageSize.height,\n\t\t\theight: currentPage.pageSize.width\n\t\t};\n\t} else {\n\t\treturn {\n\t\t\torientation: currentPage.pageSize.orientation,\n\t\t\twidth: currentPage.pageSize.width,\n\t\t\theight: currentPage.pageSize.height\n\t\t};\n\t}\n\n};\n\n\nDocumentContext.prototype.moveToNextPage = function (pageOrientation) {\n\tvar nextPageIndex = this.page + 1;\n\n\tvar prevPage = this.page;\n\tvar prevY = this.y;\n\n\tvar createNewPage = nextPageIndex >= this.pages.length;\n\tif (createNewPage) {\n\t\tvar currentAvailableWidth = this.availableWidth;\n\t\tvar currentPageOrientation = this.getCurrentPage().pageSize.orientation;\n\n\t\tvar pageSize = getPageSize(this.getCurrentPage(), pageOrientation);\n\t\tthis.addPage(pageSize);\n\n\t\tif (currentPageOrientation === pageSize.orientation) {\n\t\t\tthis.availableWidth = currentAvailableWidth;\n\t\t}\n\t} else {\n\t\tthis.page = nextPageIndex;\n\t\tthis.initializePage();\n\t}\n\n\treturn {\n\t\tnewPageCreated: createNewPage,\n\t\tprevPage: prevPage,\n\t\tprevY: prevY,\n\t\ty: this.y\n\t};\n};\n\n\nDocumentContext.prototype.addPage = function (pageSize) {\n\tvar page = {items: [], pageSize: pageSize};\n\tthis.pages.push(page);\n\tthis.page = this.pages.length - 1;\n\tthis.initializePage();\n\n\tthis.tracker.emit('pageAdded');\n\n\treturn page;\n};\n\nDocumentContext.prototype.getCurrentPage = function () {\n\tif (this.page < 0 || this.page >= this.pages.length) {\n\t\treturn null;\n\t}\n\n\treturn this.pages[this.page];\n};\n\nDocumentContext.prototype.getCurrentPosition = function () {\n\tvar pageSize = this.getCurrentPage().pageSize;\n\tvar innerHeight = pageSize.height - this.pageMargins.top - this.pageMargins.bottom;\n\tvar innerWidth = pageSize.width - this.pageMargins.left - this.pageMargins.right;\n\n\treturn {\n\t\tpageNumber: this.page + 1,\n\t\tpageOrientation: pageSize.orientation,\n\t\tpageInnerHeight: innerHeight,\n\t\tpageInnerWidth: innerWidth,\n\t\tleft: this.x,\n\t\ttop: this.y,\n\t\tverticalRatio: ((this.y - this.pageMargins.top) / innerHeight),\n\t\thorizontalRatio: ((this.x - this.pageMargins.left) / innerWidth)\n\t};\n};\n\nfunction bottomMostContext(c1, c2) {\n\tvar r;\n\n\tif (c1.page > c2.page) {\n\t\tr = c1;\n\t} else if (c2.page > c1.page) {\n\t\tr = c2;\n\t} else {\n\t\tr = (c1.y > c2.y) ? c1 : c2;\n\t}\n\n\treturn {\n\t\tpage: r.page,\n\t\tx: r.x,\n\t\ty: r.y,\n\t\tavailableHeight: r.availableHeight,\n\t\tavailableWidth: r.availableWidth\n\t};\n}\n\nmodule.exports = DocumentContext;\n\n\n/***/ }),\n/* 82 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n/**\n * Creates an instance of Line\n *\n * @constructor\n * @this {Line}\n * @param {Number} Maximum width this line can have\n */\nfunction Line(maxWidth) {\n\tthis.maxWidth = maxWidth;\n\tthis.leadingCut = 0;\n\tthis.trailingCut = 0;\n\tthis.inlineWidths = 0;\n\tthis.inlines = [];\n}\n\nLine.prototype.getAscenderHeight = function () {\n\tvar y = 0;\n\n\tthis.inlines.forEach(function (inline) {\n\t\ty = Math.max(y, inline.font.ascender / 1000 * inline.fontSize);\n\t});\n\treturn y;\n};\n\nLine.prototype.hasEnoughSpaceForInline = function (inline) {\n\tif (this.inlines.length === 0) {\n\t\treturn true;\n\t}\n\tif (this.newLineForced) {\n\t\treturn false;\n\t}\n\n\treturn this.inlineWidths + inline.width - this.leadingCut - (inline.trailingCut || 0) <= this.maxWidth;\n};\n\nLine.prototype.addInline = function (inline) {\n\tif (this.inlines.length === 0) {\n\t\tthis.leadingCut = inline.leadingCut || 0;\n\t}\n\tthis.trailingCut = inline.trailingCut || 0;\n\n\tinline.x = this.inlineWidths - this.leadingCut;\n\n\tthis.inlines.push(inline);\n\tthis.inlineWidths += inline.width;\n\n\tif (inline.lineEnd) {\n\t\tthis.newLineForced = true;\n\t}\n};\n\nLine.prototype.getWidth = function () {\n\treturn this.inlineWidths - this.leadingCut - this.trailingCut;\n};\n\n/**\n * Returns line height\n * @return {Number}\n */\nLine.prototype.getHeight = function () {\n\tvar max = 0;\n\n\tthis.inlines.forEach(function (item) {\n\t\tmax = Math.max(max, item.height || 0);\n\t});\n\n\treturn max;\n};\n\nmodule.exports = Line;\n\n\n/***/ }),\n/* 83 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(global, process) {// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n\n/*<replacement>*/\n\nvar processNextTick = __webpack_require__(32).nextTick;\n/*</replacement>*/\n\nmodule.exports = Readable;\n\n/*<replacement>*/\nvar isArray = __webpack_require__(76);\n/*</replacement>*/\n\n/*<replacement>*/\nvar Duplex;\n/*</replacement>*/\n\nReadable.ReadableState = ReadableState;\n\n/*<replacement>*/\nvar EE = __webpack_require__(31).EventEmitter;\n\nvar EElistenerCount = function (emitter, type) {\n  return emitter.listeners(type).length;\n};\n/*</replacement>*/\n\n/*<replacement>*/\nvar Stream = __webpack_require__(84);\n/*</replacement>*/\n\n/*<replacement>*/\n\nvar Buffer = __webpack_require__(33).Buffer;\nvar OurUint8Array = global.Uint8Array || function () {};\nfunction _uint8ArrayToBuffer(chunk) {\n  return Buffer.from(chunk);\n}\nfunction _isUint8Array(obj) {\n  return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;\n}\n\n/*</replacement>*/\n\n/*<replacement>*/\nvar util = __webpack_require__(25);\nutil.inherits = __webpack_require__(21);\n/*</replacement>*/\n\n/*<replacement>*/\nvar debugUtil = __webpack_require__(139);\nvar debug = void 0;\nif (debugUtil && debugUtil.debuglog) {\n  debug = debugUtil.debuglog('stream');\n} else {\n  debug = function () {};\n}\n/*</replacement>*/\n\nvar BufferList = __webpack_require__(140);\nvar destroyImpl = __webpack_require__(85);\nvar StringDecoder;\n\nutil.inherits(Readable, Stream);\n\nvar kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume'];\n\nfunction prependListener(emitter, event, fn) {\n  // Sadly this is not cacheable as some libraries bundle their own\n  // event emitter implementation with them.\n  if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn);\n\n  // This is a hack to make sure that our error handler is attached before any\n  // userland ones.  NEVER DO THIS. This is here only because this code needs\n  // to continue to work with older versions of Node.js that do not include\n  // the prependListener() method. The goal is to eventually remove this hack.\n  if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]];\n}\n\nfunction ReadableState(options, stream) {\n  Duplex = Duplex || __webpack_require__(16);\n\n  options = options || {};\n\n  // Duplex streams are both readable and writable, but share\n  // the same options object.\n  // However, some cases require setting options to different\n  // values for the readable and the writable sides of the duplex stream.\n  // These options can be provided separately as readableXXX and writableXXX.\n  var isDuplex = stream instanceof Duplex;\n\n  // object stream flag. Used to make read(n) ignore n and to\n  // make all the buffer merging and length checks go away\n  this.objectMode = !!options.objectMode;\n\n  if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode;\n\n  // the point at which it stops calling _read() to fill the buffer\n  // Note: 0 is a valid value, means \"don't call _read preemptively ever\"\n  var hwm = options.highWaterMark;\n  var readableHwm = options.readableHighWaterMark;\n  var defaultHwm = this.objectMode ? 16 : 16 * 1024;\n\n  if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (readableHwm || readableHwm === 0)) this.highWaterMark = readableHwm;else this.highWaterMark = defaultHwm;\n\n  // cast to ints.\n  this.highWaterMark = Math.floor(this.highWaterMark);\n\n  // A linked list is used to store data chunks instead of an array because the\n  // linked list can remove elements from the beginning faster than\n  // array.shift()\n  this.buffer = new BufferList();\n  this.length = 0;\n  this.pipes = null;\n  this.pipesCount = 0;\n  this.flowing = null;\n  this.ended = false;\n  this.endEmitted = false;\n  this.reading = false;\n\n  // a flag to be able to tell if the event 'readable'/'data' is emitted\n  // immediately, or on a later tick.  We set this to true at first, because\n  // any actions that shouldn't happen until \"later\" should generally also\n  // not happen before the first read call.\n  this.sync = true;\n\n  // whenever we return null, then we set a flag to say\n  // that we're awaiting a 'readable' event emission.\n  this.needReadable = false;\n  this.emittedReadable = false;\n  this.readableListening = false;\n  this.resumeScheduled = false;\n\n  // has it been destroyed\n  this.destroyed = false;\n\n  // Crypto is kind of old and crusty.  Historically, its default string\n  // encoding is 'binary' so we have to make this configurable.\n  // Everything else in the universe uses 'utf8', though.\n  this.defaultEncoding = options.defaultEncoding || 'utf8';\n\n  // the number of writers that are awaiting a drain event in .pipe()s\n  this.awaitDrain = 0;\n\n  // if true, a maybeReadMore has been scheduled\n  this.readingMore = false;\n\n  this.decoder = null;\n  this.encoding = null;\n  if (options.encoding) {\n    if (!StringDecoder) StringDecoder = __webpack_require__(47).StringDecoder;\n    this.decoder = new StringDecoder(options.encoding);\n    this.encoding = options.encoding;\n  }\n}\n\nfunction Readable(options) {\n  Duplex = Duplex || __webpack_require__(16);\n\n  if (!(this instanceof Readable)) return new Readable(options);\n\n  this._readableState = new ReadableState(options, this);\n\n  // legacy\n  this.readable = true;\n\n  if (options) {\n    if (typeof options.read === 'function') this._read = options.read;\n\n    if (typeof options.destroy === 'function') this._destroy = options.destroy;\n  }\n\n  Stream.call(this);\n}\n\nObject.defineProperty(Readable.prototype, 'destroyed', {\n  get: function () {\n    if (this._readableState === undefined) {\n      return false;\n    }\n    return this._readableState.destroyed;\n  },\n  set: function (value) {\n    // we ignore the value if the stream\n    // has not been initialized yet\n    if (!this._readableState) {\n      return;\n    }\n\n    // backward compatibility, the user is explicitly\n    // managing destroyed\n    this._readableState.destroyed = value;\n  }\n});\n\nReadable.prototype.destroy = destroyImpl.destroy;\nReadable.prototype._undestroy = destroyImpl.undestroy;\nReadable.prototype._destroy = function (err, cb) {\n  this.push(null);\n  cb(err);\n};\n\n// Manually shove something into the read() buffer.\n// This returns true if the highWaterMark has not been hit yet,\n// similar to how Writable.write() returns true if you should\n// write() some more.\nReadable.prototype.push = function (chunk, encoding) {\n  var state = this._readableState;\n  var skipChunkCheck;\n\n  if (!state.objectMode) {\n    if (typeof chunk === 'string') {\n      encoding = encoding || state.defaultEncoding;\n      if (encoding !== state.encoding) {\n        chunk = Buffer.from(chunk, encoding);\n        encoding = '';\n      }\n      skipChunkCheck = true;\n    }\n  } else {\n    skipChunkCheck = true;\n  }\n\n  return readableAddChunk(this, chunk, encoding, false, skipChunkCheck);\n};\n\n// Unshift should *always* be something directly out of read()\nReadable.prototype.unshift = function (chunk) {\n  return readableAddChunk(this, chunk, null, true, false);\n};\n\nfunction readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) {\n  var state = stream._readableState;\n  if (chunk === null) {\n    state.reading = false;\n    onEofChunk(stream, state);\n  } else {\n    var er;\n    if (!skipChunkCheck) er = chunkInvalid(state, chunk);\n    if (er) {\n      stream.emit('error', er);\n    } else if (state.objectMode || chunk && chunk.length > 0) {\n      if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) {\n        chunk = _uint8ArrayToBuffer(chunk);\n      }\n\n      if (addToFront) {\n        if (state.endEmitted) stream.emit('error', new Error('stream.unshift() after end event'));else addChunk(stream, state, chunk, true);\n      } else if (state.ended) {\n        stream.emit('error', new Error('stream.push() after EOF'));\n      } else {\n        state.reading = false;\n        if (state.decoder && !encoding) {\n          chunk = state.decoder.write(chunk);\n          if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state);\n        } else {\n          addChunk(stream, state, chunk, false);\n        }\n      }\n    } else if (!addToFront) {\n      state.reading = false;\n    }\n  }\n\n  return needMoreData(state);\n}\n\nfunction addChunk(stream, state, chunk, addToFront) {\n  if (state.flowing && state.length === 0 && !state.sync) {\n    stream.emit('data', chunk);\n    stream.read(0);\n  } else {\n    // update the buffer info.\n    state.length += state.objectMode ? 1 : chunk.length;\n    if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk);\n\n    if (state.needReadable) emitReadable(stream);\n  }\n  maybeReadMore(stream, state);\n}\n\nfunction chunkInvalid(state, chunk) {\n  var er;\n  if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {\n    er = new TypeError('Invalid non-string/buffer chunk');\n  }\n  return er;\n}\n\n// if it's past the high water mark, we can push in some more.\n// Also, if we have no data yet, we can stand some\n// more bytes.  This is to work around cases where hwm=0,\n// such as the repl.  Also, if the push() triggered a\n// readable event, and the user called read(largeNumber) such that\n// needReadable was set, then we ought to push more, so that another\n// 'readable' event will be triggered.\nfunction needMoreData(state) {\n  return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0);\n}\n\nReadable.prototype.isPaused = function () {\n  return this._readableState.flowing === false;\n};\n\n// backwards compatibility.\nReadable.prototype.setEncoding = function (enc) {\n  if (!StringDecoder) StringDecoder = __webpack_require__(47).StringDecoder;\n  this._readableState.decoder = new StringDecoder(enc);\n  this._readableState.encoding = enc;\n  return this;\n};\n\n// Don't raise the hwm > 8MB\nvar MAX_HWM = 0x800000;\nfunction computeNewHighWaterMark(n) {\n  if (n >= MAX_HWM) {\n    n = MAX_HWM;\n  } else {\n    // Get the next highest power of 2 to prevent increasing hwm excessively in\n    // tiny amounts\n    n--;\n    n |= n >>> 1;\n    n |= n >>> 2;\n    n |= n >>> 4;\n    n |= n >>> 8;\n    n |= n >>> 16;\n    n++;\n  }\n  return n;\n}\n\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction howMuchToRead(n, state) {\n  if (n <= 0 || state.length === 0 && state.ended) return 0;\n  if (state.objectMode) return 1;\n  if (n !== n) {\n    // Only flow one buffer at a time\n    if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length;\n  }\n  // If we're asking for more than the current hwm, then raise the hwm.\n  if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n);\n  if (n <= state.length) return n;\n  // Don't have enough\n  if (!state.ended) {\n    state.needReadable = true;\n    return 0;\n  }\n  return state.length;\n}\n\n// you can override either this method, or the async _read(n) below.\nReadable.prototype.read = function (n) {\n  debug('read', n);\n  n = parseInt(n, 10);\n  var state = this._readableState;\n  var nOrig = n;\n\n  if (n !== 0) state.emittedReadable = false;\n\n  // if we're doing read(0) to trigger a readable event, but we\n  // already have a bunch of data in the buffer, then just trigger\n  // the 'readable' event and move on.\n  if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) {\n    debug('read: emitReadable', state.length, state.ended);\n    if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this);\n    return null;\n  }\n\n  n = howMuchToRead(n, state);\n\n  // if we've ended, and we're now clear, then finish it up.\n  if (n === 0 && state.ended) {\n    if (state.length === 0) endReadable(this);\n    return null;\n  }\n\n  // All the actual chunk generation logic needs to be\n  // *below* the call to _read.  The reason is that in certain\n  // synthetic stream cases, such as passthrough streams, _read\n  // may be a completely synchronous operation which may change\n  // the state of the read buffer, providing enough data when\n  // before there was *not* enough.\n  //\n  // So, the steps are:\n  // 1. Figure out what the state of things will be after we do\n  // a read from the buffer.\n  //\n  // 2. If that resulting state will trigger a _read, then call _read.\n  // Note that this may be asynchronous, or synchronous.  Yes, it is\n  // deeply ugly to write APIs this way, but that still doesn't mean\n  // that the Readable class should behave improperly, as streams are\n  // designed to be sync/async agnostic.\n  // Take note if the _read call is sync or async (ie, if the read call\n  // has returned yet), so that we know whether or not it's safe to emit\n  // 'readable' etc.\n  //\n  // 3. Actually pull the requested chunks out of the buffer and return.\n\n  // if we need a readable event, then we need to do some reading.\n  var doRead = state.needReadable;\n  debug('need readable', doRead);\n\n  // if we currently have less than the highWaterMark, then also read some\n  if (state.length === 0 || state.length - n < state.highWaterMark) {\n    doRead = true;\n    debug('length less than watermark', doRead);\n  }\n\n  // however, if we've ended, then there's no point, and if we're already\n  // reading, then it's unnecessary.\n  if (state.ended || state.reading) {\n    doRead = false;\n    debug('reading or ended', doRead);\n  } else if (doRead) {\n    debug('do read');\n    state.reading = true;\n    state.sync = true;\n    // if the length is currently zero, then we *need* a readable event.\n    if (state.length === 0) state.needReadable = true;\n    // call internal read method\n    this._read(state.highWaterMark);\n    state.sync = false;\n    // If _read pushed data synchronously, then `reading` will be false,\n    // and we need to re-evaluate how much data we can return to the user.\n    if (!state.reading) n = howMuchToRead(nOrig, state);\n  }\n\n  var ret;\n  if (n > 0) ret = fromList(n, state);else ret = null;\n\n  if (ret === null) {\n    state.needReadable = true;\n    n = 0;\n  } else {\n    state.length -= n;\n  }\n\n  if (state.length === 0) {\n    // If we have nothing in the buffer, then we want to know\n    // as soon as we *do* get something into the buffer.\n    if (!state.ended) state.needReadable = true;\n\n    // If we tried to read() past the EOF, then emit end on the next tick.\n    if (nOrig !== n && state.ended) endReadable(this);\n  }\n\n  if (ret !== null) this.emit('data', ret);\n\n  return ret;\n};\n\nfunction onEofChunk(stream, state) {\n  if (state.ended) return;\n  if (state.decoder) {\n    var chunk = state.decoder.end();\n    if (chunk && chunk.length) {\n      state.buffer.push(chunk);\n      state.length += state.objectMode ? 1 : chunk.length;\n    }\n  }\n  state.ended = true;\n\n  // emit 'readable' now to make sure it gets picked up.\n  emitReadable(stream);\n}\n\n// Don't emit readable right away in sync mode, because this can trigger\n// another read() call => stack overflow.  This way, it might trigger\n// a nextTick recursion warning, but that's not so bad.\nfunction emitReadable(stream) {\n  var state = stream._readableState;\n  state.needReadable = false;\n  if (!state.emittedReadable) {\n    debug('emitReadable', state.flowing);\n    state.emittedReadable = true;\n    if (state.sync) processNextTick(emitReadable_, stream);else emitReadable_(stream);\n  }\n}\n\nfunction emitReadable_(stream) {\n  debug('emit readable');\n  stream.emit('readable');\n  flow(stream);\n}\n\n// at this point, the user has presumably seen the 'readable' event,\n// and called read() to consume some data.  that may have triggered\n// in turn another _read(n) call, in which case reading = true if\n// it's in progress.\n// However, if we're not ended, or reading, and the length < hwm,\n// then go ahead and try to read some more preemptively.\nfunction maybeReadMore(stream, state) {\n  if (!state.readingMore) {\n    state.readingMore = true;\n    processNextTick(maybeReadMore_, stream, state);\n  }\n}\n\nfunction maybeReadMore_(stream, state) {\n  var len = state.length;\n  while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) {\n    debug('maybeReadMore read 0');\n    stream.read(0);\n    if (len === state.length)\n      // didn't get any data, stop spinning.\n      break;else len = state.length;\n  }\n  state.readingMore = false;\n}\n\n// abstract method.  to be overridden in specific implementation classes.\n// call cb(er, data) where data is <= n in length.\n// for virtual (non-string, non-buffer) streams, \"length\" is somewhat\n// arbitrary, and perhaps not very meaningful.\nReadable.prototype._read = function (n) {\n  this.emit('error', new Error('_read() is not implemented'));\n};\n\nReadable.prototype.pipe = function (dest, pipeOpts) {\n  var src = this;\n  var state = this._readableState;\n\n  switch (state.pipesCount) {\n    case 0:\n      state.pipes = dest;\n      break;\n    case 1:\n      state.pipes = [state.pipes, dest];\n      break;\n    default:\n      state.pipes.push(dest);\n      break;\n  }\n  state.pipesCount += 1;\n  debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts);\n\n  var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr;\n\n  var endFn = doEnd ? onend : unpipe;\n  if (state.endEmitted) processNextTick(endFn);else src.once('end', endFn);\n\n  dest.on('unpipe', onunpipe);\n  function onunpipe(readable, unpipeInfo) {\n    debug('onunpipe');\n    if (readable === src) {\n      if (unpipeInfo && unpipeInfo.hasUnpiped === false) {\n        unpipeInfo.hasUnpiped = true;\n        cleanup();\n      }\n    }\n  }\n\n  function onend() {\n    debug('onend');\n    dest.end();\n  }\n\n  // when the dest drains, it reduces the awaitDrain counter\n  // on the source.  This would be more elegant with a .once()\n  // handler in flow(), but adding and removing repeatedly is\n  // too slow.\n  var ondrain = pipeOnDrain(src);\n  dest.on('drain', ondrain);\n\n  var cleanedUp = false;\n  function cleanup() {\n    debug('cleanup');\n    // cleanup event handlers once the pipe is broken\n    dest.removeListener('close', onclose);\n    dest.removeListener('finish', onfinish);\n    dest.removeListener('drain', ondrain);\n    dest.removeListener('error', onerror);\n    dest.removeListener('unpipe', onunpipe);\n    src.removeListener('end', onend);\n    src.removeListener('end', unpipe);\n    src.removeListener('data', ondata);\n\n    cleanedUp = true;\n\n    // if the reader is waiting for a drain event from this\n    // specific writer, then it would cause it to never start\n    // flowing again.\n    // So, if this is awaiting a drain, then we just call it now.\n    // If we don't know, then assume that we are waiting for one.\n    if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain();\n  }\n\n  // If the user pushes more data while we're writing to dest then we'll end up\n  // in ondata again. However, we only want to increase awaitDrain once because\n  // dest will only emit one 'drain' event for the multiple writes.\n  // => Introduce a guard on increasing awaitDrain.\n  var increasedAwaitDrain = false;\n  src.on('data', ondata);\n  function ondata(chunk) {\n    debug('ondata');\n    increasedAwaitDrain = false;\n    var ret = dest.write(chunk);\n    if (false === ret && !increasedAwaitDrain) {\n      // If the user unpiped during `dest.write()`, it is possible\n      // to get stuck in a permanently paused state if that write\n      // also returned false.\n      // => Check whether `dest` is still a piping destination.\n      if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) {\n        debug('false write response, pause', src._readableState.awaitDrain);\n        src._readableState.awaitDrain++;\n        increasedAwaitDrain = true;\n      }\n      src.pause();\n    }\n  }\n\n  // if the dest has an error, then stop piping into it.\n  // however, don't suppress the throwing behavior for this.\n  function onerror(er) {\n    debug('onerror', er);\n    unpipe();\n    dest.removeListener('error', onerror);\n    if (EElistenerCount(dest, 'error') === 0) dest.emit('error', er);\n  }\n\n  // Make sure our error handler is attached before userland ones.\n  prependListener(dest, 'error', onerror);\n\n  // Both close and finish should trigger unpipe, but only once.\n  function onclose() {\n    dest.removeListener('finish', onfinish);\n    unpipe();\n  }\n  dest.once('close', onclose);\n  function onfinish() {\n    debug('onfinish');\n    dest.removeListener('close', onclose);\n    unpipe();\n  }\n  dest.once('finish', onfinish);\n\n  function unpipe() {\n    debug('unpipe');\n    src.unpipe(dest);\n  }\n\n  // tell the dest that it's being piped to\n  dest.emit('pipe', src);\n\n  // start the flow if it hasn't been started already.\n  if (!state.flowing) {\n    debug('pipe resume');\n    src.resume();\n  }\n\n  return dest;\n};\n\nfunction pipeOnDrain(src) {\n  return function () {\n    var state = src._readableState;\n    debug('pipeOnDrain', state.awaitDrain);\n    if (state.awaitDrain) state.awaitDrain--;\n    if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) {\n      state.flowing = true;\n      flow(src);\n    }\n  };\n}\n\nReadable.prototype.unpipe = function (dest) {\n  var state = this._readableState;\n  var unpipeInfo = { hasUnpiped: false };\n\n  // if we're not piping anywhere, then do nothing.\n  if (state.pipesCount === 0) return this;\n\n  // just one destination.  most common case.\n  if (state.pipesCount === 1) {\n    // passed in one, but it's not the right one.\n    if (dest && dest !== state.pipes) return this;\n\n    if (!dest) dest = state.pipes;\n\n    // got a match.\n    state.pipes = null;\n    state.pipesCount = 0;\n    state.flowing = false;\n    if (dest) dest.emit('unpipe', this, unpipeInfo);\n    return this;\n  }\n\n  // slow case. multiple pipe destinations.\n\n  if (!dest) {\n    // remove all.\n    var dests = state.pipes;\n    var len = state.pipesCount;\n    state.pipes = null;\n    state.pipesCount = 0;\n    state.flowing = false;\n\n    for (var i = 0; i < len; i++) {\n      dests[i].emit('unpipe', this, unpipeInfo);\n    }return this;\n  }\n\n  // try to find the right one.\n  var index = indexOf(state.pipes, dest);\n  if (index === -1) return this;\n\n  state.pipes.splice(index, 1);\n  state.pipesCount -= 1;\n  if (state.pipesCount === 1) state.pipes = state.pipes[0];\n\n  dest.emit('unpipe', this, unpipeInfo);\n\n  return this;\n};\n\n// set up data events if they are asked for\n// Ensure readable listeners eventually get something\nReadable.prototype.on = function (ev, fn) {\n  var res = Stream.prototype.on.call(this, ev, fn);\n\n  if (ev === 'data') {\n    // Start flowing on next tick if stream isn't explicitly paused\n    if (this._readableState.flowing !== false) this.resume();\n  } else if (ev === 'readable') {\n    var state = this._readableState;\n    if (!state.endEmitted && !state.readableListening) {\n      state.readableListening = state.needReadable = true;\n      state.emittedReadable = false;\n      if (!state.reading) {\n        processNextTick(nReadingNextTick, this);\n      } else if (state.length) {\n        emitReadable(this);\n      }\n    }\n  }\n\n  return res;\n};\nReadable.prototype.addListener = Readable.prototype.on;\n\nfunction nReadingNextTick(self) {\n  debug('readable nexttick read 0');\n  self.read(0);\n}\n\n// pause() and resume() are remnants of the legacy readable stream API\n// If the user uses them, then switch into old mode.\nReadable.prototype.resume = function () {\n  var state = this._readableState;\n  if (!state.flowing) {\n    debug('resume');\n    state.flowing = true;\n    resume(this, state);\n  }\n  return this;\n};\n\nfunction resume(stream, state) {\n  if (!state.resumeScheduled) {\n    state.resumeScheduled = true;\n    processNextTick(resume_, stream, state);\n  }\n}\n\nfunction resume_(stream, state) {\n  if (!state.reading) {\n    debug('resume read 0');\n    stream.read(0);\n  }\n\n  state.resumeScheduled = false;\n  state.awaitDrain = 0;\n  stream.emit('resume');\n  flow(stream);\n  if (state.flowing && !state.reading) stream.read(0);\n}\n\nReadable.prototype.pause = function () {\n  debug('call pause flowing=%j', this._readableState.flowing);\n  if (false !== this._readableState.flowing) {\n    debug('pause');\n    this._readableState.flowing = false;\n    this.emit('pause');\n  }\n  return this;\n};\n\nfunction flow(stream) {\n  var state = stream._readableState;\n  debug('flow', state.flowing);\n  while (state.flowing && stream.read() !== null) {}\n}\n\n// wrap an old-style stream as the async data source.\n// This is *not* part of the readable stream interface.\n// It is an ugly unfortunate mess of history.\nReadable.prototype.wrap = function (stream) {\n  var _this = this;\n\n  var state = this._readableState;\n  var paused = false;\n\n  stream.on('end', function () {\n    debug('wrapped end');\n    if (state.decoder && !state.ended) {\n      var chunk = state.decoder.end();\n      if (chunk && chunk.length) _this.push(chunk);\n    }\n\n    _this.push(null);\n  });\n\n  stream.on('data', function (chunk) {\n    debug('wrapped data');\n    if (state.decoder) chunk = state.decoder.write(chunk);\n\n    // don't skip over falsy values in objectMode\n    if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return;\n\n    var ret = _this.push(chunk);\n    if (!ret) {\n      paused = true;\n      stream.pause();\n    }\n  });\n\n  // proxy all the other methods.\n  // important when wrapping filters and duplexes.\n  for (var i in stream) {\n    if (this[i] === undefined && typeof stream[i] === 'function') {\n      this[i] = function (method) {\n        return function () {\n          return stream[method].apply(stream, arguments);\n        };\n      }(i);\n    }\n  }\n\n  // proxy certain important events.\n  for (var n = 0; n < kProxyEvents.length; n++) {\n    stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n]));\n  }\n\n  // when we try to consume some more bytes, simply unpause the\n  // underlying stream.\n  this._read = function (n) {\n    debug('wrapped _read', n);\n    if (paused) {\n      paused = false;\n      stream.resume();\n    }\n  };\n\n  return this;\n};\n\n// exposed for testing purposes only.\nReadable._fromList = fromList;\n\n// Pluck off n bytes from an array of buffers.\n// Length is the combined lengths of all the buffers in the list.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction fromList(n, state) {\n  // nothing buffered\n  if (state.length === 0) return null;\n\n  var ret;\n  if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) {\n    // read it all, truncate the list\n    if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length);\n    state.buffer.clear();\n  } else {\n    // read part of list\n    ret = fromListPartial(n, state.buffer, state.decoder);\n  }\n\n  return ret;\n}\n\n// Extracts only enough buffered data to satisfy the amount requested.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction fromListPartial(n, list, hasStrings) {\n  var ret;\n  if (n < list.head.data.length) {\n    // slice is the same for buffers and strings\n    ret = list.head.data.slice(0, n);\n    list.head.data = list.head.data.slice(n);\n  } else if (n === list.head.data.length) {\n    // first chunk is a perfect match\n    ret = list.shift();\n  } else {\n    // result spans more than one buffer\n    ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list);\n  }\n  return ret;\n}\n\n// Copies a specified amount of characters from the list of buffered data\n// chunks.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction copyFromBufferString(n, list) {\n  var p = list.head;\n  var c = 1;\n  var ret = p.data;\n  n -= ret.length;\n  while (p = p.next) {\n    var str = p.data;\n    var nb = n > str.length ? str.length : n;\n    if (nb === str.length) ret += str;else ret += str.slice(0, n);\n    n -= nb;\n    if (n === 0) {\n      if (nb === str.length) {\n        ++c;\n        if (p.next) list.head = p.next;else list.head = list.tail = null;\n      } else {\n        list.head = p;\n        p.data = str.slice(nb);\n      }\n      break;\n    }\n    ++c;\n  }\n  list.length -= c;\n  return ret;\n}\n\n// Copies a specified amount of bytes from the list of buffered data chunks.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction copyFromBuffer(n, list) {\n  var ret = Buffer.allocUnsafe(n);\n  var p = list.head;\n  var c = 1;\n  p.data.copy(ret);\n  n -= p.data.length;\n  while (p = p.next) {\n    var buf = p.data;\n    var nb = n > buf.length ? buf.length : n;\n    buf.copy(ret, ret.length - n, 0, nb);\n    n -= nb;\n    if (n === 0) {\n      if (nb === buf.length) {\n        ++c;\n        if (p.next) list.head = p.next;else list.head = list.tail = null;\n      } else {\n        list.head = p;\n        p.data = buf.slice(nb);\n      }\n      break;\n    }\n    ++c;\n  }\n  list.length -= c;\n  return ret;\n}\n\nfunction endReadable(stream) {\n  var state = stream._readableState;\n\n  // If we get here before consuming all the bytes, then that is a\n  // bug in node.  Should never happen.\n  if (state.length > 0) throw new Error('\"endReadable()\" called on non-empty stream');\n\n  if (!state.endEmitted) {\n    state.ended = true;\n    processNextTick(endReadableNT, state, stream);\n  }\n}\n\nfunction endReadableNT(state, stream) {\n  // Check that we didn't get one last unshift.\n  if (!state.endEmitted && state.length === 0) {\n    state.endEmitted = true;\n    stream.readable = false;\n    stream.emit('end');\n  }\n}\n\nfunction forEach(xs, f) {\n  for (var i = 0, l = xs.length; i < l; i++) {\n    f(xs[i], i);\n  }\n}\n\nfunction indexOf(xs, x) {\n  for (var i = 0, l = xs.length; i < l; i++) {\n    if (xs[i] === x) return i;\n  }\n  return -1;\n}\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7), __webpack_require__(11)))\n\n/***/ }),\n/* 84 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(31).EventEmitter;\n\n\n/***/ }),\n/* 85 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n/*<replacement>*/\n\nvar processNextTick = __webpack_require__(32).nextTick;\n/*</replacement>*/\n\n// undocumented cb() API, needed for core, not for public API\nfunction destroy(err, cb) {\n  var _this = this;\n\n  var readableDestroyed = this._readableState && this._readableState.destroyed;\n  var writableDestroyed = this._writableState && this._writableState.destroyed;\n\n  if (readableDestroyed || writableDestroyed) {\n    if (cb) {\n      cb(err);\n    } else if (err && (!this._writableState || !this._writableState.errorEmitted)) {\n      processNextTick(emitErrorNT, this, err);\n    }\n    return this;\n  }\n\n  // we set destroyed to true before firing error callbacks in order\n  // to make it re-entrance safe in case destroy() is called within callbacks\n\n  if (this._readableState) {\n    this._readableState.destroyed = true;\n  }\n\n  // if this is a duplex stream mark the writable part as destroyed as well\n  if (this._writableState) {\n    this._writableState.destroyed = true;\n  }\n\n  this._destroy(err || null, function (err) {\n    if (!cb && err) {\n      processNextTick(emitErrorNT, _this, err);\n      if (_this._writableState) {\n        _this._writableState.errorEmitted = true;\n      }\n    } else if (cb) {\n      cb(err);\n    }\n  });\n\n  return this;\n}\n\nfunction undestroy() {\n  if (this._readableState) {\n    this._readableState.destroyed = false;\n    this._readableState.reading = false;\n    this._readableState.ended = false;\n    this._readableState.endEmitted = false;\n  }\n\n  if (this._writableState) {\n    this._writableState.destroyed = false;\n    this._writableState.ended = false;\n    this._writableState.ending = false;\n    this._writableState.finished = false;\n    this._writableState.errorEmitted = false;\n  }\n}\n\nfunction emitErrorNT(self, err) {\n  self.emit('error', err);\n}\n\nmodule.exports = {\n  destroy: destroy,\n  undestroy: undestroy\n};\n\n/***/ }),\n/* 86 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// a transform stream is a readable/writable stream where you do\n// something with the data.  Sometimes it's called a \"filter\",\n// but that's not a great name for it, since that implies a thing where\n// some bits pass through, and others are simply ignored.  (That would\n// be a valid example of a transform, of course.)\n//\n// While the output is causally related to the input, it's not a\n// necessarily symmetric or synchronous transformation.  For example,\n// a zlib stream might take multiple plain-text writes(), and then\n// emit a single compressed chunk some time in the future.\n//\n// Here's how this works:\n//\n// The Transform stream has all the aspects of the readable and writable\n// stream classes.  When you write(chunk), that calls _write(chunk,cb)\n// internally, and returns false if there's a lot of pending writes\n// buffered up.  When you call read(), that calls _read(n) until\n// there's enough pending readable data buffered up.\n//\n// In a transform stream, the written data is placed in a buffer.  When\n// _read(n) is called, it transforms the queued up data, calling the\n// buffered _write cb's as it consumes chunks.  If consuming a single\n// written chunk would result in multiple output chunks, then the first\n// outputted bit calls the readcb, and subsequent chunks just go into\n// the read buffer, and will cause it to emit 'readable' if necessary.\n//\n// This way, back-pressure is actually determined by the reading side,\n// since _read has to be called to start processing a new chunk.  However,\n// a pathological inflate type of transform can cause excessive buffering\n// here.  For example, imagine a stream where every byte of input is\n// interpreted as an integer from 0-255, and then results in that many\n// bytes of output.  Writing the 4 bytes {ff,ff,ff,ff} would result in\n// 1kb of data being output.  In this case, you could write a very small\n// amount of input, and end up with a very large amount of output.  In\n// such a pathological inflating mechanism, there'd be no way to tell\n// the system to stop doing the transform.  A single 4MB write could\n// cause the system to run out of memory.\n//\n// However, even in such a pathological case, only a single written chunk\n// would be consumed, and then the rest would wait (un-transformed) until\n// the results of the previous transformed chunk were consumed.\n\n\n\nmodule.exports = Transform;\n\nvar Duplex = __webpack_require__(16);\n\n/*<replacement>*/\nvar util = __webpack_require__(25);\nutil.inherits = __webpack_require__(21);\n/*</replacement>*/\n\nutil.inherits(Transform, Duplex);\n\nfunction afterTransform(er, data) {\n  var ts = this._transformState;\n  ts.transforming = false;\n\n  var cb = ts.writecb;\n\n  if (!cb) {\n    return this.emit('error', new Error('write callback called multiple times'));\n  }\n\n  ts.writechunk = null;\n  ts.writecb = null;\n\n  if (data != null) // single equals check for both `null` and `undefined`\n    this.push(data);\n\n  cb(er);\n\n  var rs = this._readableState;\n  rs.reading = false;\n  if (rs.needReadable || rs.length < rs.highWaterMark) {\n    this._read(rs.highWaterMark);\n  }\n}\n\nfunction Transform(options) {\n  if (!(this instanceof Transform)) return new Transform(options);\n\n  Duplex.call(this, options);\n\n  this._transformState = {\n    afterTransform: afterTransform.bind(this),\n    needTransform: false,\n    transforming: false,\n    writecb: null,\n    writechunk: null,\n    writeencoding: null\n  };\n\n  // start out asking for a readable event once data is transformed.\n  this._readableState.needReadable = true;\n\n  // we have implemented the _read method, and done the other things\n  // that Readable wants before the first _read call, so unset the\n  // sync guard flag.\n  this._readableState.sync = false;\n\n  if (options) {\n    if (typeof options.transform === 'function') this._transform = options.transform;\n\n    if (typeof options.flush === 'function') this._flush = options.flush;\n  }\n\n  // When the writable side finishes, then flush out anything remaining.\n  this.on('prefinish', prefinish);\n}\n\nfunction prefinish() {\n  var _this = this;\n\n  if (typeof this._flush === 'function') {\n    this._flush(function (er, data) {\n      done(_this, er, data);\n    });\n  } else {\n    done(this, null, null);\n  }\n}\n\nTransform.prototype.push = function (chunk, encoding) {\n  this._transformState.needTransform = false;\n  return Duplex.prototype.push.call(this, chunk, encoding);\n};\n\n// This is the part where you do stuff!\n// override this function in implementation classes.\n// 'chunk' is an input chunk.\n//\n// Call `push(newChunk)` to pass along transformed output\n// to the readable side.  You may call 'push' zero or more times.\n//\n// Call `cb(err)` when you are done with this chunk.  If you pass\n// an error, then that'll put the hurt on the whole operation.  If you\n// never call cb(), then you'll never get another chunk.\nTransform.prototype._transform = function (chunk, encoding, cb) {\n  throw new Error('_transform() is not implemented');\n};\n\nTransform.prototype._write = function (chunk, encoding, cb) {\n  var ts = this._transformState;\n  ts.writecb = cb;\n  ts.writechunk = chunk;\n  ts.writeencoding = encoding;\n  if (!ts.transforming) {\n    var rs = this._readableState;\n    if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark);\n  }\n};\n\n// Doesn't matter what the args are here.\n// _transform does all the work.\n// That we got here means that the readable side wants more data.\nTransform.prototype._read = function (n) {\n  var ts = this._transformState;\n\n  if (ts.writechunk !== null && ts.writecb && !ts.transforming) {\n    ts.transforming = true;\n    this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);\n  } else {\n    // mark that we need a transform, so that any data that comes in\n    // will get processed, now that we've asked for it.\n    ts.needTransform = true;\n  }\n};\n\nTransform.prototype._destroy = function (err, cb) {\n  var _this2 = this;\n\n  Duplex.prototype._destroy.call(this, err, function (err2) {\n    cb(err2);\n    _this2.emit('close');\n  });\n};\n\nfunction done(stream, er, data) {\n  if (er) return stream.emit('error', er);\n\n  if (data != null) // single equals check for both `null` and `undefined`\n    stream.push(data);\n\n  // if there's nothing in the write buffer, then that means\n  // that nothing more will ever be provided\n  if (stream._writableState.length) throw new Error('Calling transform done when ws.length != 0');\n\n  if (stream._transformState.transforming) throw new Error('Calling transform done when still transforming');\n\n  return stream.push(null);\n}\n\n/***/ }),\n/* 87 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6\n\n/*\nPDFReference - represents a reference to another object in the PDF object heirarchy\nBy Devon Govett\n */\n\n(function() {\n  var PDFObject, PDFReference, stream, zlib,\n    bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },\n    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n    hasProp = {}.hasOwnProperty;\n\n  zlib = __webpack_require__(48);\n\n  stream = __webpack_require__(15);\n\n  PDFReference = (function(superClass) {\n    extend(PDFReference, superClass);\n\n    function PDFReference(document, id, data) {\n      this.document = document;\n      this.id = id;\n      this.data = data != null ? data : {};\n      this.finalize = bind(this.finalize, this);\n      PDFReference.__super__.constructor.call(this, {\n        decodeStrings: false\n      });\n      this.gen = 0;\n      this.deflate = null;\n      this.compress = this.document.compress && !this.data.Filter;\n      this.uncompressedLength = 0;\n      this.chunks = [];\n    }\n\n    PDFReference.prototype.initDeflate = function() {\n      this.data.Filter = 'FlateDecode';\n      this.deflate = zlib.createDeflate();\n      this.deflate.on('data', (function(_this) {\n        return function(chunk) {\n          _this.chunks.push(chunk);\n          return _this.data.Length += chunk.length;\n        };\n      })(this));\n      return this.deflate.on('end', this.finalize);\n    };\n\n    PDFReference.prototype._write = function(chunk, encoding, callback) {\n      var base;\n      if (!Buffer.isBuffer(chunk)) {\n        chunk = new Buffer(chunk + '\\n', 'binary');\n      }\n      this.uncompressedLength += chunk.length;\n      if ((base = this.data).Length == null) {\n        base.Length = 0;\n      }\n      if (this.compress) {\n        if (!this.deflate) {\n          this.initDeflate();\n        }\n        this.deflate.write(chunk);\n      } else {\n        this.chunks.push(chunk);\n        this.data.Length += chunk.length;\n      }\n      return callback();\n    };\n\n    PDFReference.prototype.end = function(chunk) {\n      PDFReference.__super__.end.apply(this, arguments);\n      if (this.deflate) {\n        return this.deflate.end();\n      } else {\n        return this.finalize();\n      }\n    };\n\n    PDFReference.prototype.finalize = function() {\n      var chunk, i, len, ref;\n      this.offset = this.document._offset;\n      this.document._write(this.id + \" \" + this.gen + \" obj\");\n      this.document._write(PDFObject.convert(this.data));\n      if (this.chunks.length) {\n        this.document._write('stream');\n        ref = this.chunks;\n        for (i = 0, len = ref.length; i < len; i++) {\n          chunk = ref[i];\n          this.document._write(chunk);\n        }\n        this.chunks.length = 0;\n        this.document._write('\\nendstream');\n      }\n      this.document._write('endobj');\n      return this.document._refEnd(this);\n    };\n\n    PDFReference.prototype.toString = function() {\n      return this.id + \" \" + this.gen + \" R\";\n    };\n\n    return PDFReference;\n\n  })(stream.Writable);\n\n  module.exports = PDFReference;\n\n  PDFObject = __webpack_require__(26);\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 88 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(global) {\n\n// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js\n// original notice:\n\n/*!\n * The buffer module from node.js, for the browser.\n *\n * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>\n * @license  MIT\n */\nfunction compare(a, b) {\n  if (a === b) {\n    return 0;\n  }\n\n  var x = a.length;\n  var y = b.length;\n\n  for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n    if (a[i] !== b[i]) {\n      x = a[i];\n      y = b[i];\n      break;\n    }\n  }\n\n  if (x < y) {\n    return -1;\n  }\n  if (y < x) {\n    return 1;\n  }\n  return 0;\n}\nfunction isBuffer(b) {\n  if (global.Buffer && typeof global.Buffer.isBuffer === 'function') {\n    return global.Buffer.isBuffer(b);\n  }\n  return !!(b != null && b._isBuffer);\n}\n\n// based on node assert, original notice:\n\n// http://wiki.commonjs.org/wiki/Unit_Testing/1.0\n//\n// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!\n//\n// Originally from narwhal.js (http://narwhaljs.org)\n// Copyright (c) 2009 Thomas Robinson <280north.com>\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the 'Software'), to\n// deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n// sell copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nvar util = __webpack_require__(49);\nvar hasOwn = Object.prototype.hasOwnProperty;\nvar pSlice = Array.prototype.slice;\nvar functionsHaveNames = (function () {\n  return function foo() {}.name === 'foo';\n}());\nfunction pToString (obj) {\n  return Object.prototype.toString.call(obj);\n}\nfunction isView(arrbuf) {\n  if (isBuffer(arrbuf)) {\n    return false;\n  }\n  if (typeof global.ArrayBuffer !== 'function') {\n    return false;\n  }\n  if (typeof ArrayBuffer.isView === 'function') {\n    return ArrayBuffer.isView(arrbuf);\n  }\n  if (!arrbuf) {\n    return false;\n  }\n  if (arrbuf instanceof DataView) {\n    return true;\n  }\n  if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) {\n    return true;\n  }\n  return false;\n}\n// 1. The assert module provides functions that throw\n// AssertionError's when particular conditions are not met. The\n// assert module must conform to the following interface.\n\nvar assert = module.exports = ok;\n\n// 2. The AssertionError is defined in assert.\n// new assert.AssertionError({ message: message,\n//                             actual: actual,\n//                             expected: expected })\n\nvar regex = /\\s*function\\s+([^\\(\\s]*)\\s*/;\n// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js\nfunction getName(func) {\n  if (!util.isFunction(func)) {\n    return;\n  }\n  if (functionsHaveNames) {\n    return func.name;\n  }\n  var str = func.toString();\n  var match = str.match(regex);\n  return match && match[1];\n}\nassert.AssertionError = function AssertionError(options) {\n  this.name = 'AssertionError';\n  this.actual = options.actual;\n  this.expected = options.expected;\n  this.operator = options.operator;\n  if (options.message) {\n    this.message = options.message;\n    this.generatedMessage = false;\n  } else {\n    this.message = getMessage(this);\n    this.generatedMessage = true;\n  }\n  var stackStartFunction = options.stackStartFunction || fail;\n  if (Error.captureStackTrace) {\n    Error.captureStackTrace(this, stackStartFunction);\n  } else {\n    // non v8 browsers so we can have a stacktrace\n    var err = new Error();\n    if (err.stack) {\n      var out = err.stack;\n\n      // try to strip useless frames\n      var fn_name = getName(stackStartFunction);\n      var idx = out.indexOf('\\n' + fn_name);\n      if (idx >= 0) {\n        // once we have located the function frame\n        // we need to strip out everything before it (and its line)\n        var next_line = out.indexOf('\\n', idx + 1);\n        out = out.substring(next_line + 1);\n      }\n\n      this.stack = out;\n    }\n  }\n};\n\n// assert.AssertionError instanceof Error\nutil.inherits(assert.AssertionError, Error);\n\nfunction truncate(s, n) {\n  if (typeof s === 'string') {\n    return s.length < n ? s : s.slice(0, n);\n  } else {\n    return s;\n  }\n}\nfunction inspect(something) {\n  if (functionsHaveNames || !util.isFunction(something)) {\n    return util.inspect(something);\n  }\n  var rawname = getName(something);\n  var name = rawname ? ': ' + rawname : '';\n  return '[Function' +  name + ']';\n}\nfunction getMessage(self) {\n  return truncate(inspect(self.actual), 128) + ' ' +\n         self.operator + ' ' +\n         truncate(inspect(self.expected), 128);\n}\n\n// At present only the three keys mentioned above are used and\n// understood by the spec. Implementations or sub modules can pass\n// other keys to the AssertionError's constructor - they will be\n// ignored.\n\n// 3. All of the following functions must throw an AssertionError\n// when a corresponding condition is not met, with a message that\n// may be undefined if not provided.  All assertion methods provide\n// both the actual and expected values to the assertion error for\n// display purposes.\n\nfunction fail(actual, expected, message, operator, stackStartFunction) {\n  throw new assert.AssertionError({\n    message: message,\n    actual: actual,\n    expected: expected,\n    operator: operator,\n    stackStartFunction: stackStartFunction\n  });\n}\n\n// EXTENSION! allows for well behaved errors defined elsewhere.\nassert.fail = fail;\n\n// 4. Pure assertion tests whether a value is truthy, as determined\n// by !!guard.\n// assert.ok(guard, message_opt);\n// This statement is equivalent to assert.equal(true, !!guard,\n// message_opt);. To test strictly for the value true, use\n// assert.strictEqual(true, guard, message_opt);.\n\nfunction ok(value, message) {\n  if (!value) fail(value, true, message, '==', assert.ok);\n}\nassert.ok = ok;\n\n// 5. The equality assertion tests shallow, coercive equality with\n// ==.\n// assert.equal(actual, expected, message_opt);\n\nassert.equal = function equal(actual, expected, message) {\n  if (actual != expected) fail(actual, expected, message, '==', assert.equal);\n};\n\n// 6. The non-equality assertion tests for whether two objects are not equal\n// with != assert.notEqual(actual, expected, message_opt);\n\nassert.notEqual = function notEqual(actual, expected, message) {\n  if (actual == expected) {\n    fail(actual, expected, message, '!=', assert.notEqual);\n  }\n};\n\n// 7. The equivalence assertion tests a deep equality relation.\n// assert.deepEqual(actual, expected, message_opt);\n\nassert.deepEqual = function deepEqual(actual, expected, message) {\n  if (!_deepEqual(actual, expected, false)) {\n    fail(actual, expected, message, 'deepEqual', assert.deepEqual);\n  }\n};\n\nassert.deepStrictEqual = function deepStrictEqual(actual, expected, message) {\n  if (!_deepEqual(actual, expected, true)) {\n    fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual);\n  }\n};\n\nfunction _deepEqual(actual, expected, strict, memos) {\n  // 7.1. All identical values are equivalent, as determined by ===.\n  if (actual === expected) {\n    return true;\n  } else if (isBuffer(actual) && isBuffer(expected)) {\n    return compare(actual, expected) === 0;\n\n  // 7.2. If the expected value is a Date object, the actual value is\n  // equivalent if it is also a Date object that refers to the same time.\n  } else if (util.isDate(actual) && util.isDate(expected)) {\n    return actual.getTime() === expected.getTime();\n\n  // 7.3 If the expected value is a RegExp object, the actual value is\n  // equivalent if it is also a RegExp object with the same source and\n  // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).\n  } else if (util.isRegExp(actual) && util.isRegExp(expected)) {\n    return actual.source === expected.source &&\n           actual.global === expected.global &&\n           actual.multiline === expected.multiline &&\n           actual.lastIndex === expected.lastIndex &&\n           actual.ignoreCase === expected.ignoreCase;\n\n  // 7.4. Other pairs that do not both pass typeof value == 'object',\n  // equivalence is determined by ==.\n  } else if ((actual === null || typeof actual !== 'object') &&\n             (expected === null || typeof expected !== 'object')) {\n    return strict ? actual === expected : actual == expected;\n\n  // If both values are instances of typed arrays, wrap their underlying\n  // ArrayBuffers in a Buffer each to increase performance\n  // This optimization requires the arrays to have the same type as checked by\n  // Object.prototype.toString (aka pToString). Never perform binary\n  // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their\n  // bit patterns are not identical.\n  } else if (isView(actual) && isView(expected) &&\n             pToString(actual) === pToString(expected) &&\n             !(actual instanceof Float32Array ||\n               actual instanceof Float64Array)) {\n    return compare(new Uint8Array(actual.buffer),\n                   new Uint8Array(expected.buffer)) === 0;\n\n  // 7.5 For all other Object pairs, including Array objects, equivalence is\n  // determined by having the same number of owned properties (as verified\n  // with Object.prototype.hasOwnProperty.call), the same set of keys\n  // (although not necessarily the same order), equivalent values for every\n  // corresponding key, and an identical 'prototype' property. Note: this\n  // accounts for both named and indexed properties on Arrays.\n  } else if (isBuffer(actual) !== isBuffer(expected)) {\n    return false;\n  } else {\n    memos = memos || {actual: [], expected: []};\n\n    var actualIndex = memos.actual.indexOf(actual);\n    if (actualIndex !== -1) {\n      if (actualIndex === memos.expected.indexOf(expected)) {\n        return true;\n      }\n    }\n\n    memos.actual.push(actual);\n    memos.expected.push(expected);\n\n    return objEquiv(actual, expected, strict, memos);\n  }\n}\n\nfunction isArguments(object) {\n  return Object.prototype.toString.call(object) == '[object Arguments]';\n}\n\nfunction objEquiv(a, b, strict, actualVisitedObjects) {\n  if (a === null || a === undefined || b === null || b === undefined)\n    return false;\n  // if one is a primitive, the other must be same\n  if (util.isPrimitive(a) || util.isPrimitive(b))\n    return a === b;\n  if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b))\n    return false;\n  var aIsArgs = isArguments(a);\n  var bIsArgs = isArguments(b);\n  if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs))\n    return false;\n  if (aIsArgs) {\n    a = pSlice.call(a);\n    b = pSlice.call(b);\n    return _deepEqual(a, b, strict);\n  }\n  var ka = objectKeys(a);\n  var kb = objectKeys(b);\n  var key, i;\n  // having the same number of owned properties (keys incorporates\n  // hasOwnProperty)\n  if (ka.length !== kb.length)\n    return false;\n  //the same set of keys (although not necessarily the same order),\n  ka.sort();\n  kb.sort();\n  //~~~cheap key test\n  for (i = ka.length - 1; i >= 0; i--) {\n    if (ka[i] !== kb[i])\n      return false;\n  }\n  //equivalent values for every corresponding key, and\n  //~~~possibly expensive deep test\n  for (i = ka.length - 1; i >= 0; i--) {\n    key = ka[i];\n    if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects))\n      return false;\n  }\n  return true;\n}\n\n// 8. The non-equivalence assertion tests for any deep inequality.\n// assert.notDeepEqual(actual, expected, message_opt);\n\nassert.notDeepEqual = function notDeepEqual(actual, expected, message) {\n  if (_deepEqual(actual, expected, false)) {\n    fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);\n  }\n};\n\nassert.notDeepStrictEqual = notDeepStrictEqual;\nfunction notDeepStrictEqual(actual, expected, message) {\n  if (_deepEqual(actual, expected, true)) {\n    fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual);\n  }\n}\n\n\n// 9. The strict equality assertion tests strict equality, as determined by ===.\n// assert.strictEqual(actual, expected, message_opt);\n\nassert.strictEqual = function strictEqual(actual, expected, message) {\n  if (actual !== expected) {\n    fail(actual, expected, message, '===', assert.strictEqual);\n  }\n};\n\n// 10. The strict non-equality assertion tests for strict inequality, as\n// determined by !==.  assert.notStrictEqual(actual, expected, message_opt);\n\nassert.notStrictEqual = function notStrictEqual(actual, expected, message) {\n  if (actual === expected) {\n    fail(actual, expected, message, '!==', assert.notStrictEqual);\n  }\n};\n\nfunction expectedException(actual, expected) {\n  if (!actual || !expected) {\n    return false;\n  }\n\n  if (Object.prototype.toString.call(expected) == '[object RegExp]') {\n    return expected.test(actual);\n  }\n\n  try {\n    if (actual instanceof expected) {\n      return true;\n    }\n  } catch (e) {\n    // Ignore.  The instanceof check doesn't work for arrow functions.\n  }\n\n  if (Error.isPrototypeOf(expected)) {\n    return false;\n  }\n\n  return expected.call({}, actual) === true;\n}\n\nfunction _tryBlock(block) {\n  var error;\n  try {\n    block();\n  } catch (e) {\n    error = e;\n  }\n  return error;\n}\n\nfunction _throws(shouldThrow, block, expected, message) {\n  var actual;\n\n  if (typeof block !== 'function') {\n    throw new TypeError('\"block\" argument must be a function');\n  }\n\n  if (typeof expected === 'string') {\n    message = expected;\n    expected = null;\n  }\n\n  actual = _tryBlock(block);\n\n  message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +\n            (message ? ' ' + message : '.');\n\n  if (shouldThrow && !actual) {\n    fail(actual, expected, 'Missing expected exception' + message);\n  }\n\n  var userProvidedMessage = typeof message === 'string';\n  var isUnwantedException = !shouldThrow && util.isError(actual);\n  var isUnexpectedException = !shouldThrow && actual && !expected;\n\n  if ((isUnwantedException &&\n      userProvidedMessage &&\n      expectedException(actual, expected)) ||\n      isUnexpectedException) {\n    fail(actual, expected, 'Got unwanted exception' + message);\n  }\n\n  if ((shouldThrow && actual && expected &&\n      !expectedException(actual, expected)) || (!shouldThrow && actual)) {\n    throw actual;\n  }\n}\n\n// 11. Expected to throw an error:\n// assert.throws(block, Error_opt, message_opt);\n\nassert.throws = function(block, /*optional*/error, /*optional*/message) {\n  _throws(true, block, error, message);\n};\n\n// EXTENSION! This is annoying to write outside this module.\nassert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {\n  _throws(false, block, error, message);\n};\n\nassert.ifError = function(err) { if (err) throw err; };\n\nvar objectKeys = Object.keys || function (obj) {\n  var keys = [];\n  for (var key in obj) {\n    if (hasOwn.call(obj, key)) keys.push(key);\n  }\n  return keys;\n};\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))\n\n/***/ }),\n/* 89 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// Note: adler32 takes 12% for level 0 and 2% for level 6.\n// It isn't worth it to make additional optimizations as in original.\n// Small size is preferable.\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nfunction adler32(adler, buf, len, pos) {\n  var s1 = (adler & 0xffff) |0,\n      s2 = ((adler >>> 16) & 0xffff) |0,\n      n = 0;\n\n  while (len !== 0) {\n    // Set limit ~ twice less than 5552, to keep\n    // s2 in 31-bits, because we force signed ints.\n    // in other case %= will fail.\n    n = len > 2000 ? 2000 : len;\n    len -= n;\n\n    do {\n      s1 = (s1 + buf[pos++]) |0;\n      s2 = (s2 + s1) |0;\n    } while (--n);\n\n    s1 %= 65521;\n    s2 %= 65521;\n  }\n\n  return (s1 | (s2 << 16)) |0;\n}\n\n\nmodule.exports = adler32;\n\n\n/***/ }),\n/* 90 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// Note: we can't get significant speed boost here.\n// So write code to minimize size - no pregenerated tables\n// and array tools dependencies.\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\n// Use ordinary array, since untyped makes no boost here\nfunction makeTable() {\n  var c, table = [];\n\n  for (var n = 0; n < 256; n++) {\n    c = n;\n    for (var k = 0; k < 8; k++) {\n      c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));\n    }\n    table[n] = c;\n  }\n\n  return table;\n}\n\n// Create table on load. Just 255 signed longs. Not a problem.\nvar crcTable = makeTable();\n\n\nfunction crc32(crc, buf, len, pos) {\n  var t = crcTable,\n      end = pos + len;\n\n  crc ^= -1;\n\n  for (var i = pos; i < end; i++) {\n    crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];\n  }\n\n  return (crc ^ (-1)); // >>> 0;\n}\n\n\nmodule.exports = crc32;\n\n\n/***/ }),\n/* 91 */\n/***/ (function(module, exports) {\n\nmodule.exports = [[\"a140\",\"\",62],[\"a180\",\"\",32],[\"a240\",\"\",62],[\"a280\",\"\",32],[\"a2ab\",\"\",5],[\"a2e3\",\"€\"],[\"a2ef\",\"\"],[\"a2fd\",\"\"],[\"a340\",\"\",62],[\"a380\",\"\",31,\"　\"],[\"a440\",\"\",62],[\"a480\",\"\",32],[\"a4f4\",\"\",10],[\"a540\",\"\",62],[\"a580\",\"\",32],[\"a5f7\",\"\",7],[\"a640\",\"\",62],[\"a680\",\"\",32],[\"a6b9\",\"\",7],[\"a6d9\",\"\",6],[\"a6ec\",\"\"],[\"a6f3\",\"\"],[\"a6f6\",\"\",8],[\"a740\",\"\",62],[\"a780\",\"\",32],[\"a7c2\",\"\",14],[\"a7f2\",\"\",12],[\"a896\",\"\",10],[\"a8bc\",\"\"],[\"a8bf\",\"ǹ\"],[\"a8c1\",\"\"],[\"a8ea\",\"\",20],[\"a958\",\"\"],[\"a95b\",\"\"],[\"a95d\",\"\"],[\"a989\",\"〾⿰\",11],[\"a997\",\"\",12],[\"a9f0\",\"\",14],[\"aaa1\",\"\",93],[\"aba1\",\"\",93],[\"aca1\",\"\",93],[\"ada1\",\"\",93],[\"aea1\",\"\",93],[\"afa1\",\"\",93],[\"d7fa\",\"\",4],[\"f8a1\",\"\",93],[\"f9a1\",\"\",93],[\"faa1\",\"\",93],[\"fba1\",\"\",93],[\"fca1\",\"\",93],[\"fda1\",\"\",93],[\"fe50\",\"⺁⺄㑳㑇⺈⺋㖞㘚㘎⺌⺗㥮㤘㧏㧟㩳㧐㭎㱮㳠⺧⺪䁖䅟⺮䌷⺳⺶⺷䎱䎬⺻䏝䓖䙡䙌\"],[\"fe80\",\"䜣䜩䝼䞍⻊䥇䥺䥽䦂䦃䦅䦆䦟䦛䦷䦶䲣䲟䲠䲡䱷䲢䴓\",6,\"䶮\",93]]\n\n/***/ }),\n/* 92 */\n/***/ (function(module, exports) {\n\nmodule.exports = [[\"0\",\"\\u0000\",127],[\"a140\",\"　，、。．‧；：？！︰…‥﹐﹑﹒·﹔﹕﹖﹗｜–︱—︳╴︴﹏（）︵︶｛｝︷︸〔〕︹︺【】︻︼《》︽︾〈〉︿﹀「」﹁﹂『』﹃﹄﹙﹚\"],[\"a1a1\",\"﹛﹜﹝﹞‘’“”〝〞‵′＃＆＊※§〃○●△▲◎☆★◇◆□■▽▼㊣℅¯￣＿ˍ﹉﹊﹍﹎﹋﹌﹟﹠﹡＋－×÷±√＜＞＝≦≧≠∞≒≡﹢\",4,\"～∩∪⊥∠∟⊿㏒㏑∫∮∵∴♀♂⊕⊙↑↓←→↖↗↙↘∥∣／\"],[\"a240\",\"＼∕﹨＄￥〒￠￡％＠℃℉﹩﹪﹫㏕㎜㎝㎞㏎㎡㎎㎏㏄°兙兛兞兝兡兣嗧瓩糎▁\",7,\"▏▎▍▌▋▊▉┼┴┬┤├▔─│▕┌┐└┘╭\"],[\"a2a1\",\"╮╰╯═╞╪╡◢◣◥◤╱╲╳０\",9,\"Ⅰ\",9,\"〡\",8,\"十卄卅Ａ\",25,\"ａ\",21],[\"a340\",\"ｗｘｙｚΑ\",16,\"Σ\",6,\"α\",16,\"σ\",6,\"ㄅ\",10],[\"a3a1\",\"ㄐ\",25,\"˙ˉˊˇˋ\"],[\"a3e1\",\"€\"],[\"a440\",\"一乙丁七乃九了二人儿入八几刀刁力匕十卜又三下丈上丫丸凡久么也乞于亡兀刃勺千叉口土士夕大女子孑孓寸小尢尸山川工己已巳巾干廾弋弓才\"],[\"a4a1\",\"丑丐不中丰丹之尹予云井互五亢仁什仃仆仇仍今介仄元允內六兮公冗凶分切刈勻勾勿化匹午升卅卞厄友及反壬天夫太夭孔少尤尺屯巴幻廿弔引心戈戶手扎支文斗斤方日曰月木欠止歹毋比毛氏水火爪父爻片牙牛犬王丙\"],[\"a540\",\"世丕且丘主乍乏乎以付仔仕他仗代令仙仞充兄冉冊冬凹出凸刊加功包匆北匝仟半卉卡占卯卮去可古右召叮叩叨叼司叵叫另只史叱台句叭叻四囚外\"],[\"a5a1\",\"央失奴奶孕它尼巨巧左市布平幼弁弘弗必戊打扔扒扑斥旦朮本未末札正母民氐永汁汀氾犯玄玉瓜瓦甘生用甩田由甲申疋白皮皿目矛矢石示禾穴立丞丟乒乓乩亙交亦亥仿伉伙伊伕伍伐休伏仲件任仰仳份企伋光兇兆先全\"],[\"a640\",\"共再冰列刑划刎刖劣匈匡匠印危吉吏同吊吐吁吋各向名合吃后吆吒因回囝圳地在圭圬圯圩夙多夷夸妄奸妃好她如妁字存宇守宅安寺尖屹州帆并年\"],[\"a6a1\",\"式弛忙忖戎戌戍成扣扛托收早旨旬旭曲曳有朽朴朱朵次此死氖汝汗汙江池汐汕污汛汍汎灰牟牝百竹米糸缶羊羽老考而耒耳聿肉肋肌臣自至臼舌舛舟艮色艾虫血行衣西阡串亨位住佇佗佞伴佛何估佐佑伽伺伸佃佔似但佣\"],[\"a740\",\"作你伯低伶余佝佈佚兌克免兵冶冷別判利刪刨劫助努劬匣即卵吝吭吞吾否呎吧呆呃吳呈呂君吩告吹吻吸吮吵吶吠吼呀吱含吟听囪困囤囫坊坑址坍\"],[\"a7a1\",\"均坎圾坐坏圻壯夾妝妒妨妞妣妙妖妍妤妓妊妥孝孜孚孛完宋宏尬局屁尿尾岐岑岔岌巫希序庇床廷弄弟彤形彷役忘忌志忍忱快忸忪戒我抄抗抖技扶抉扭把扼找批扳抒扯折扮投抓抑抆改攻攸旱更束李杏材村杜杖杞杉杆杠\"],[\"a840\",\"杓杗步每求汞沙沁沈沉沅沛汪決沐汰沌汨沖沒汽沃汲汾汴沆汶沍沔沘沂灶灼災灸牢牡牠狄狂玖甬甫男甸皂盯矣私秀禿究系罕肖肓肝肘肛肚育良芒\"],[\"a8a1\",\"芋芍見角言谷豆豕貝赤走足身車辛辰迂迆迅迄巡邑邢邪邦那酉釆里防阮阱阪阬並乖乳事些亞享京佯依侍佳使佬供例來侃佰併侈佩佻侖佾侏侑佺兔兒兕兩具其典冽函刻券刷刺到刮制剁劾劻卒協卓卑卦卷卸卹取叔受味呵\"],[\"a940\",\"咖呸咕咀呻呷咄咒咆呼咐呱呶和咚呢周咋命咎固垃坷坪坩坡坦坤坼夜奉奇奈奄奔妾妻委妹妮姑姆姐姍始姓姊妯妳姒姅孟孤季宗定官宜宙宛尚屈居\"],[\"a9a1\",\"屆岷岡岸岩岫岱岳帘帚帖帕帛帑幸庚店府底庖延弦弧弩往征彿彼忝忠忽念忿怏怔怯怵怖怪怕怡性怩怫怛或戕房戾所承拉拌拄抿拂抹拒招披拓拔拋拈抨抽押拐拙拇拍抵拚抱拘拖拗拆抬拎放斧於旺昔易昌昆昂明昀昏昕昊\"],[\"aa40\",\"昇服朋杭枋枕東果杳杷枇枝林杯杰板枉松析杵枚枓杼杪杲欣武歧歿氓氛泣注泳沱泌泥河沽沾沼波沫法泓沸泄油況沮泗泅泱沿治泡泛泊沬泯泜泖泠\"],[\"aaa1\",\"炕炎炒炊炙爬爭爸版牧物狀狎狙狗狐玩玨玟玫玥甽疝疙疚的盂盲直知矽社祀祁秉秈空穹竺糾罔羌羋者肺肥肢肱股肫肩肴肪肯臥臾舍芳芝芙芭芽芟芹花芬芥芯芸芣芰芾芷虎虱初表軋迎返近邵邸邱邶采金長門阜陀阿阻附\"],[\"ab40\",\"陂隹雨青非亟亭亮信侵侯便俠俑俏保促侶俘俟俊俗侮俐俄係俚俎俞侷兗冒冑冠剎剃削前剌剋則勇勉勃勁匍南卻厚叛咬哀咨哎哉咸咦咳哇哂咽咪品\"],[\"aba1\",\"哄哈咯咫咱咻咩咧咿囿垂型垠垣垢城垮垓奕契奏奎奐姜姘姿姣姨娃姥姪姚姦威姻孩宣宦室客宥封屎屏屍屋峙峒巷帝帥帟幽庠度建弈弭彥很待徊律徇後徉怒思怠急怎怨恍恰恨恢恆恃恬恫恪恤扁拜挖按拼拭持拮拽指拱拷\"],[\"ac40\",\"拯括拾拴挑挂政故斫施既春昭映昧是星昨昱昤曷柿染柱柔某柬架枯柵柩柯柄柑枴柚查枸柏柞柳枰柙柢柝柒歪殃殆段毒毗氟泉洋洲洪流津洌洱洞洗\"],[\"aca1\",\"活洽派洶洛泵洹洧洸洩洮洵洎洫炫為炳炬炯炭炸炮炤爰牲牯牴狩狠狡玷珊玻玲珍珀玳甚甭畏界畎畋疫疤疥疢疣癸皆皇皈盈盆盃盅省盹相眉看盾盼眇矜砂研砌砍祆祉祈祇禹禺科秒秋穿突竿竽籽紂紅紀紉紇約紆缸美羿耄\"],[\"ad40\",\"耐耍耑耶胖胥胚胃胄背胡胛胎胞胤胝致舢苧范茅苣苛苦茄若茂茉苒苗英茁苜苔苑苞苓苟苯茆虐虹虻虺衍衫要觔計訂訃貞負赴赳趴軍軌述迦迢迪迥\"],[\"ada1\",\"迭迫迤迨郊郎郁郃酋酊重閂限陋陌降面革韋韭音頁風飛食首香乘亳倌倍倣俯倦倥俸倩倖倆值借倚倒們俺倀倔倨俱倡個候倘俳修倭倪俾倫倉兼冤冥冢凍凌准凋剖剜剔剛剝匪卿原厝叟哨唐唁唷哼哥哲唆哺唔哩哭員唉哮哪\"],[\"ae40\",\"哦唧唇哽唏圃圄埂埔埋埃堉夏套奘奚娑娘娜娟娛娓姬娠娣娩娥娌娉孫屘宰害家宴宮宵容宸射屑展屐峭峽峻峪峨峰島崁峴差席師庫庭座弱徒徑徐恙\"],[\"aea1\",\"恣恥恐恕恭恩息悄悟悚悍悔悌悅悖扇拳挈拿捎挾振捕捂捆捏捉挺捐挽挪挫挨捍捌效敉料旁旅時晉晏晃晒晌晅晁書朔朕朗校核案框桓根桂桔栩梳栗桌桑栽柴桐桀格桃株桅栓栘桁殊殉殷氣氧氨氦氤泰浪涕消涇浦浸海浙涓\"],[\"af40\",\"浬涉浮浚浴浩涌涊浹涅浥涔烊烘烤烙烈烏爹特狼狹狽狸狷玆班琉珮珠珪珞畔畝畜畚留疾病症疲疳疽疼疹痂疸皋皰益盍盎眩真眠眨矩砰砧砸砝破砷\"],[\"afa1\",\"砥砭砠砟砲祕祐祠祟祖神祝祗祚秤秣秧租秦秩秘窄窈站笆笑粉紡紗紋紊素索純紐紕級紜納紙紛缺罟羔翅翁耆耘耕耙耗耽耿胱脂胰脅胭胴脆胸胳脈能脊胼胯臭臬舀舐航舫舨般芻茫荒荔荊茸荐草茵茴荏茲茹茶茗荀茱茨荃\"],[\"b040\",\"虔蚊蚪蚓蚤蚩蚌蚣蚜衰衷袁袂衽衹記訐討訌訕訊託訓訖訏訑豈豺豹財貢起躬軒軔軏辱送逆迷退迺迴逃追逅迸邕郡郝郢酒配酌釘針釗釜釙閃院陣陡\"],[\"b0a1\",\"陛陝除陘陞隻飢馬骨高鬥鬲鬼乾偺偽停假偃偌做偉健偶偎偕偵側偷偏倏偯偭兜冕凰剪副勒務勘動匐匏匙匿區匾參曼商啪啦啄啞啡啃啊唱啖問啕唯啤唸售啜唬啣唳啁啗圈國圉域堅堊堆埠埤基堂堵執培夠奢娶婁婉婦婪婀\"],[\"b140\",\"娼婢婚婆婊孰寇寅寄寂宿密尉專將屠屜屝崇崆崎崛崖崢崑崩崔崙崤崧崗巢常帶帳帷康庸庶庵庾張強彗彬彩彫得徙從徘御徠徜恿患悉悠您惋悴惦悽\"],[\"b1a1\",\"情悻悵惜悼惘惕惆惟悸惚惇戚戛扈掠控捲掖探接捷捧掘措捱掩掉掃掛捫推掄授掙採掬排掏掀捻捩捨捺敝敖救教敗啟敏敘敕敔斜斛斬族旋旌旎晝晚晤晨晦晞曹勗望梁梯梢梓梵桿桶梱梧梗械梃棄梭梆梅梔條梨梟梡梂欲殺\"],[\"b240\",\"毫毬氫涎涼淳淙液淡淌淤添淺清淇淋涯淑涮淞淹涸混淵淅淒渚涵淚淫淘淪深淮淨淆淄涪淬涿淦烹焉焊烽烯爽牽犁猜猛猖猓猙率琅琊球理現琍瓠瓶\"],[\"b2a1\",\"瓷甜產略畦畢異疏痔痕疵痊痍皎盔盒盛眷眾眼眶眸眺硫硃硎祥票祭移窒窕笠笨笛第符笙笞笮粒粗粕絆絃統紮紹紼絀細紳組累終紲紱缽羞羚翌翎習耜聊聆脯脖脣脫脩脰脤舂舵舷舶船莎莞莘荸莢莖莽莫莒莊莓莉莠荷荻荼\"],[\"b340\",\"莆莧處彪蛇蛀蚶蛄蚵蛆蛋蚱蚯蛉術袞袈被袒袖袍袋覓規訪訝訣訥許設訟訛訢豉豚販責貫貨貪貧赧赦趾趺軛軟這逍通逗連速逝逐逕逞造透逢逖逛途\"],[\"b3a1\",\"部郭都酗野釵釦釣釧釭釩閉陪陵陳陸陰陴陶陷陬雀雪雩章竟頂頃魚鳥鹵鹿麥麻傢傍傅備傑傀傖傘傚最凱割剴創剩勞勝勛博厥啻喀喧啼喊喝喘喂喜喪喔喇喋喃喳單喟唾喲喚喻喬喱啾喉喫喙圍堯堪場堤堰報堡堝堠壹壺奠\"],[\"b440\",\"婷媚婿媒媛媧孳孱寒富寓寐尊尋就嵌嵐崴嵇巽幅帽幀幃幾廊廁廂廄弼彭復循徨惑惡悲悶惠愜愣惺愕惰惻惴慨惱愎惶愉愀愒戟扉掣掌描揀揩揉揆揍\"],[\"b4a1\",\"插揣提握揖揭揮捶援揪換摒揚揹敞敦敢散斑斐斯普晰晴晶景暑智晾晷曾替期朝棺棕棠棘棗椅棟棵森棧棹棒棲棣棋棍植椒椎棉棚楮棻款欺欽殘殖殼毯氮氯氬港游湔渡渲湧湊渠渥渣減湛湘渤湖湮渭渦湯渴湍渺測湃渝渾滋\"],[\"b540\",\"溉渙湎湣湄湲湩湟焙焚焦焰無然煮焜牌犄犀猶猥猴猩琺琪琳琢琥琵琶琴琯琛琦琨甥甦畫番痢痛痣痙痘痞痠登發皖皓皴盜睏短硝硬硯稍稈程稅稀窘\"],[\"b5a1\",\"窗窖童竣等策筆筐筒答筍筋筏筑粟粥絞結絨絕紫絮絲絡給絢絰絳善翔翕耋聒肅腕腔腋腑腎脹腆脾腌腓腴舒舜菩萃菸萍菠菅萋菁華菱菴著萊菰萌菌菽菲菊萸萎萄菜萇菔菟虛蛟蛙蛭蛔蛛蛤蛐蛞街裁裂袱覃視註詠評詞証詁\"],[\"b640\",\"詔詛詐詆訴診訶詖象貂貯貼貳貽賁費賀貴買貶貿貸越超趁跎距跋跚跑跌跛跆軻軸軼辜逮逵週逸進逶鄂郵鄉郾酣酥量鈔鈕鈣鈉鈞鈍鈐鈇鈑閔閏開閑\"],[\"b6a1\",\"間閒閎隊階隋陽隅隆隍陲隄雁雅雄集雇雯雲韌項順須飧飪飯飩飲飭馮馭黃黍黑亂傭債傲傳僅傾催傷傻傯僇剿剷剽募勦勤勢勣匯嗟嗨嗓嗦嗎嗜嗇嗑嗣嗤嗯嗚嗡嗅嗆嗥嗉園圓塞塑塘塗塚塔填塌塭塊塢塒塋奧嫁嫉嫌媾媽媼\"],[\"b740\",\"媳嫂媲嵩嵯幌幹廉廈弒彙徬微愚意慈感想愛惹愁愈慎慌慄慍愾愴愧愍愆愷戡戢搓搾搞搪搭搽搬搏搜搔損搶搖搗搆敬斟新暗暉暇暈暖暄暘暍會榔業\"],[\"b7a1\",\"楚楷楠楔極椰概楊楨楫楞楓楹榆楝楣楛歇歲毀殿毓毽溢溯滓溶滂源溝滇滅溥溘溼溺溫滑準溜滄滔溪溧溴煎煙煩煤煉照煜煬煦煌煥煞煆煨煖爺牒猷獅猿猾瑯瑚瑕瑟瑞瑁琿瑙瑛瑜當畸瘀痰瘁痲痱痺痿痴痳盞盟睛睫睦睞督\"],[\"b840\",\"睹睪睬睜睥睨睢矮碎碰碗碘碌碉硼碑碓硿祺祿禁萬禽稜稚稠稔稟稞窟窠筷節筠筮筧粱粳粵經絹綑綁綏絛置罩罪署義羨群聖聘肆肄腱腰腸腥腮腳腫\"],[\"b8a1\",\"腹腺腦舅艇蒂葷落萱葵葦葫葉葬葛萼萵葡董葩葭葆虞虜號蛹蜓蜈蜇蜀蛾蛻蜂蜃蜆蜊衙裟裔裙補裘裝裡裊裕裒覜解詫該詳試詩詰誇詼詣誠話誅詭詢詮詬詹詻訾詨豢貊貉賊資賈賄貲賃賂賅跡跟跨路跳跺跪跤跦躲較載軾輊\"],[\"b940\",\"辟農運遊道遂達逼違遐遇遏過遍遑逾遁鄒鄗酬酪酩釉鈷鉗鈸鈽鉀鈾鉛鉋鉤鉑鈴鉉鉍鉅鈹鈿鉚閘隘隔隕雍雋雉雊雷電雹零靖靴靶預頑頓頊頒頌飼飴\"],[\"b9a1\",\"飽飾馳馱馴髡鳩麂鼎鼓鼠僧僮僥僖僭僚僕像僑僱僎僩兢凳劃劂匱厭嗾嘀嘛嘗嗽嘔嘆嘉嘍嘎嗷嘖嘟嘈嘐嗶團圖塵塾境墓墊塹墅塽壽夥夢夤奪奩嫡嫦嫩嫗嫖嫘嫣孵寞寧寡寥實寨寢寤察對屢嶄嶇幛幣幕幗幔廓廖弊彆彰徹慇\"],[\"ba40\",\"愿態慷慢慣慟慚慘慵截撇摘摔撤摸摟摺摑摧搴摭摻敲斡旗旖暢暨暝榜榨榕槁榮槓構榛榷榻榫榴槐槍榭槌榦槃榣歉歌氳漳演滾漓滴漩漾漠漬漏漂漢\"],[\"baa1\",\"滿滯漆漱漸漲漣漕漫漯澈漪滬漁滲滌滷熔熙煽熊熄熒爾犒犖獄獐瑤瑣瑪瑰瑭甄疑瘧瘍瘋瘉瘓盡監瞄睽睿睡磁碟碧碳碩碣禎福禍種稱窪窩竭端管箕箋筵算箝箔箏箸箇箄粹粽精綻綰綜綽綾綠緊綴網綱綺綢綿綵綸維緒緇綬\"],[\"bb40\",\"罰翠翡翟聞聚肇腐膀膏膈膊腿膂臧臺與舔舞艋蓉蒿蓆蓄蒙蒞蒲蒜蓋蒸蓀蓓蒐蒼蓑蓊蜿蜜蜻蜢蜥蜴蜘蝕蜷蜩裳褂裴裹裸製裨褚裯誦誌語誣認誡誓誤\"],[\"bba1\",\"說誥誨誘誑誚誧豪貍貌賓賑賒赫趙趕跼輔輒輕輓辣遠遘遜遣遙遞遢遝遛鄙鄘鄞酵酸酷酴鉸銀銅銘銖鉻銓銜銨鉼銑閡閨閩閣閥閤隙障際雌雒需靼鞅韶頗領颯颱餃餅餌餉駁骯骰髦魁魂鳴鳶鳳麼鼻齊億儀僻僵價儂儈儉儅凜\"],[\"bc40\",\"劇劈劉劍劊勰厲嘮嘻嘹嘲嘿嘴嘩噓噎噗噴嘶嘯嘰墀墟增墳墜墮墩墦奭嬉嫻嬋嫵嬌嬈寮寬審寫層履嶝嶔幢幟幡廢廚廟廝廣廠彈影德徵慶慧慮慝慕憂\"],[\"bca1\",\"慼慰慫慾憧憐憫憎憬憚憤憔憮戮摩摯摹撞撲撈撐撰撥撓撕撩撒撮播撫撚撬撙撢撳敵敷數暮暫暴暱樣樟槨樁樞標槽模樓樊槳樂樅槭樑歐歎殤毅毆漿潼澄潑潦潔澆潭潛潸潮澎潺潰潤澗潘滕潯潠潟熟熬熱熨牖犛獎獗瑩璋璃\"],[\"bd40\",\"瑾璀畿瘠瘩瘟瘤瘦瘡瘢皚皺盤瞎瞇瞌瞑瞋磋磅確磊碾磕碼磐稿稼穀稽稷稻窯窮箭箱範箴篆篇篁箠篌糊締練緯緻緘緬緝編緣線緞緩綞緙緲緹罵罷羯\"],[\"bda1\",\"翩耦膛膜膝膠膚膘蔗蔽蔚蓮蔬蔭蔓蔑蔣蔡蔔蓬蔥蓿蔆螂蝴蝶蝠蝦蝸蝨蝙蝗蝌蝓衛衝褐複褒褓褕褊誼諒談諄誕請諸課諉諂調誰論諍誶誹諛豌豎豬賠賞賦賤賬賭賢賣賜質賡赭趟趣踫踐踝踢踏踩踟踡踞躺輝輛輟輩輦輪輜輞\"],[\"be40\",\"輥適遮遨遭遷鄰鄭鄧鄱醇醉醋醃鋅銻銷鋪銬鋤鋁銳銼鋒鋇鋰銲閭閱霄霆震霉靠鞍鞋鞏頡頫頜颳養餓餒餘駝駐駟駛駑駕駒駙骷髮髯鬧魅魄魷魯鴆鴉\"],[\"bea1\",\"鴃麩麾黎墨齒儒儘儔儐儕冀冪凝劑劓勳噙噫噹噩噤噸噪器噥噱噯噬噢噶壁墾壇壅奮嬝嬴學寰導彊憲憑憩憊懍憶憾懊懈戰擅擁擋撻撼據擄擇擂操撿擒擔撾整曆曉暹曄曇暸樽樸樺橙橫橘樹橄橢橡橋橇樵機橈歙歷氅濂澱澡\"],[\"bf40\",\"濃澤濁澧澳激澹澶澦澠澴熾燉燐燒燈燕熹燎燙燜燃燄獨璜璣璘璟璞瓢甌甍瘴瘸瘺盧盥瞠瞞瞟瞥磨磚磬磧禦積穎穆穌穋窺篙簑築篤篛篡篩篦糕糖縊\"],[\"bfa1\",\"縑縈縛縣縞縝縉縐罹羲翰翱翮耨膳膩膨臻興艘艙蕊蕙蕈蕨蕩蕃蕉蕭蕪蕞螃螟螞螢融衡褪褲褥褫褡親覦諦諺諫諱謀諜諧諮諾謁謂諷諭諳諶諼豫豭貓賴蹄踱踴蹂踹踵輻輯輸輳辨辦遵遴選遲遼遺鄴醒錠錶鋸錳錯錢鋼錫錄錚\"],[\"c040\",\"錐錦錡錕錮錙閻隧隨險雕霎霑霖霍霓霏靛靜靦鞘頰頸頻頷頭頹頤餐館餞餛餡餚駭駢駱骸骼髻髭鬨鮑鴕鴣鴦鴨鴒鴛默黔龍龜優償儡儲勵嚎嚀嚐嚅嚇\"],[\"c0a1\",\"嚏壕壓壑壎嬰嬪嬤孺尷屨嶼嶺嶽嶸幫彌徽應懂懇懦懋戲戴擎擊擘擠擰擦擬擱擢擭斂斃曙曖檀檔檄檢檜櫛檣橾檗檐檠歜殮毚氈濘濱濟濠濛濤濫濯澀濬濡濩濕濮濰燧營燮燦燥燭燬燴燠爵牆獰獲璩環璦璨癆療癌盪瞳瞪瞰瞬\"],[\"c140\",\"瞧瞭矯磷磺磴磯礁禧禪穗窿簇簍篾篷簌篠糠糜糞糢糟糙糝縮績繆縷縲繃縫總縱繅繁縴縹繈縵縿縯罄翳翼聱聲聰聯聳臆臃膺臂臀膿膽臉膾臨舉艱薪\"],[\"c1a1\",\"薄蕾薜薑薔薯薛薇薨薊虧蟀蟑螳蟒蟆螫螻螺蟈蟋褻褶襄褸褽覬謎謗謙講謊謠謝謄謐豁谿豳賺賽購賸賻趨蹉蹋蹈蹊轄輾轂轅輿避遽還邁邂邀鄹醣醞醜鍍鎂錨鍵鍊鍥鍋錘鍾鍬鍛鍰鍚鍔闊闋闌闈闆隱隸雖霜霞鞠韓顆颶餵騁\"],[\"c240\",\"駿鮮鮫鮪鮭鴻鴿麋黏點黜黝黛鼾齋叢嚕嚮壙壘嬸彝懣戳擴擲擾攆擺擻擷斷曜朦檳檬櫃檻檸櫂檮檯歟歸殯瀉瀋濾瀆濺瀑瀏燻燼燾燸獷獵璧璿甕癖癘\"],[\"c2a1\",\"癒瞽瞿瞻瞼礎禮穡穢穠竄竅簫簧簪簞簣簡糧織繕繞繚繡繒繙罈翹翻職聶臍臏舊藏薩藍藐藉薰薺薹薦蟯蟬蟲蟠覆覲觴謨謹謬謫豐贅蹙蹣蹦蹤蹟蹕軀轉轍邇邃邈醫醬釐鎔鎊鎖鎢鎳鎮鎬鎰鎘鎚鎗闔闖闐闕離雜雙雛雞霤鞣鞦\"],[\"c340\",\"鞭韹額顏題顎顓颺餾餿餽餮馥騎髁鬃鬆魏魎魍鯊鯉鯽鯈鯀鵑鵝鵠黠鼕鼬儳嚥壞壟壢寵龐廬懲懷懶懵攀攏曠曝櫥櫝櫚櫓瀛瀟瀨瀚瀝瀕瀘爆爍牘犢獸\"],[\"c3a1\",\"獺璽瓊瓣疇疆癟癡矇礙禱穫穩簾簿簸簽簷籀繫繭繹繩繪羅繳羶羹羸臘藩藝藪藕藤藥藷蟻蠅蠍蟹蟾襠襟襖襞譁譜識證譚譎譏譆譙贈贊蹼蹲躇蹶蹬蹺蹴轔轎辭邊邋醱醮鏡鏑鏟鏃鏈鏜鏝鏖鏢鏍鏘鏤鏗鏨關隴難霪霧靡韜韻類\"],[\"c440\",\"願顛颼饅饉騖騙鬍鯨鯧鯖鯛鶉鵡鵲鵪鵬麒麗麓麴勸嚨嚷嚶嚴嚼壤孀孃孽寶巉懸懺攘攔攙曦朧櫬瀾瀰瀲爐獻瓏癢癥礦礪礬礫竇競籌籃籍糯糰辮繽繼\"],[\"c4a1\",\"纂罌耀臚艦藻藹蘑藺蘆蘋蘇蘊蠔蠕襤覺觸議譬警譯譟譫贏贍躉躁躅躂醴釋鐘鐃鏽闡霰飄饒饑馨騫騰騷騵鰓鰍鹹麵黨鼯齟齣齡儷儸囁囀囂夔屬巍懼懾攝攜斕曩櫻欄櫺殲灌爛犧瓖瓔癩矓籐纏續羼蘗蘭蘚蠣蠢蠡蠟襪襬覽譴\"],[\"c540\",\"護譽贓躊躍躋轟辯醺鐮鐳鐵鐺鐸鐲鐫闢霸霹露響顧顥饗驅驃驀騾髏魔魑鰭鰥鶯鶴鷂鶸麝黯鼙齜齦齧儼儻囈囊囉孿巔巒彎懿攤權歡灑灘玀瓤疊癮癬\"],[\"c5a1\",\"禳籠籟聾聽臟襲襯觼讀贖贗躑躓轡酈鑄鑑鑒霽霾韃韁顫饕驕驍髒鬚鱉鰱鰾鰻鷓鷗鼴齬齪龔囌巖戀攣攫攪曬欐瓚竊籤籣籥纓纖纔臢蘸蘿蠱變邐邏鑣鑠鑤靨顯饜驚驛驗髓體髑鱔鱗鱖鷥麟黴囑壩攬灞癱癲矗罐羈蠶蠹衢讓讒\"],[\"c640\",\"讖艷贛釀鑪靂靈靄韆顰驟鬢魘鱟鷹鷺鹼鹽鼇齷齲廳欖灣籬籮蠻觀躡釁鑲鑰顱饞髖鬣黌灤矚讚鑷韉驢驥纜讜躪釅鑽鑾鑼鱷鱸黷豔鑿鸚爨驪鬱鸛鸞籲\"],[\"c940\",\"乂乜凵匚厂万丌乇亍囗兀屮彳丏冇与丮亓仂仉仈冘勼卬厹圠夃夬尐巿旡殳毌气爿丱丼仨仜仩仡仝仚刌匜卌圢圣夗夯宁宄尒尻屴屳帄庀庂忉戉扐氕\"],[\"c9a1\",\"氶汃氿氻犮犰玊禸肊阞伎优伬仵伔仱伀价伈伝伂伅伢伓伄仴伒冱刓刉刐劦匢匟卍厊吇囡囟圮圪圴夼妀奼妅奻奾奷奿孖尕尥屼屺屻屾巟幵庄异弚彴忕忔忏扜扞扤扡扦扢扙扠扚扥旯旮朾朹朸朻机朿朼朳氘汆汒汜汏汊汔汋\"],[\"ca40\",\"汌灱牞犴犵玎甪癿穵网艸艼芀艽艿虍襾邙邗邘邛邔阢阤阠阣佖伻佢佉体佤伾佧佒佟佁佘伭伳伿佡冏冹刜刞刡劭劮匉卣卲厎厏吰吷吪呔呅吙吜吥吘\"],[\"caa1\",\"吽呏呁吨吤呇囮囧囥坁坅坌坉坋坒夆奀妦妘妠妗妎妢妐妏妧妡宎宒尨尪岍岏岈岋岉岒岊岆岓岕巠帊帎庋庉庌庈庍弅弝彸彶忒忑忐忭忨忮忳忡忤忣忺忯忷忻怀忴戺抃抌抎抏抔抇扱扻扺扰抁抈扷扽扲扴攷旰旴旳旲旵杅杇\"],[\"cb40\",\"杙杕杌杈杝杍杚杋毐氙氚汸汧汫沄沋沏汱汯汩沚汭沇沕沜汦汳汥汻沎灴灺牣犿犽狃狆狁犺狅玕玗玓玔玒町甹疔疕皁礽耴肕肙肐肒肜芐芏芅芎芑芓\"],[\"cba1\",\"芊芃芄豸迉辿邟邡邥邞邧邠阰阨阯阭丳侘佼侅佽侀侇佶佴侉侄佷佌侗佪侚佹侁佸侐侜侔侞侒侂侕佫佮冞冼冾刵刲刳剆刱劼匊匋匼厒厔咇呿咁咑咂咈呫呺呾呥呬呴呦咍呯呡呠咘呣呧呤囷囹坯坲坭坫坱坰坶垀坵坻坳坴坢\"],[\"cc40\",\"坨坽夌奅妵妺姏姎妲姌姁妶妼姃姖妱妽姀姈妴姇孢孥宓宕屄屇岮岤岠岵岯岨岬岟岣岭岢岪岧岝岥岶岰岦帗帔帙弨弢弣弤彔徂彾彽忞忥怭怦怙怲怋\"],[\"cca1\",\"怴怊怗怳怚怞怬怢怍怐怮怓怑怌怉怜戔戽抭抴拑抾抪抶拊抮抳抯抻抩抰抸攽斨斻昉旼昄昒昈旻昃昋昍昅旽昑昐曶朊枅杬枎枒杶杻枘枆构杴枍枌杺枟枑枙枃杽极杸杹枔欥殀歾毞氝沓泬泫泮泙沶泔沭泧沷泐泂沺泃泆泭泲\"],[\"cd40\",\"泒泝沴沊沝沀泞泀洰泍泇沰泹泏泩泑炔炘炅炓炆炄炑炖炂炚炃牪狖狋狘狉狜狒狔狚狌狑玤玡玭玦玢玠玬玝瓝瓨甿畀甾疌疘皯盳盱盰盵矸矼矹矻矺\"],[\"cda1\",\"矷祂礿秅穸穻竻籵糽耵肏肮肣肸肵肭舠芠苀芫芚芘芛芵芧芮芼芞芺芴芨芡芩苂芤苃芶芢虰虯虭虮豖迒迋迓迍迖迕迗邲邴邯邳邰阹阽阼阺陃俍俅俓侲俉俋俁俔俜俙侻侳俛俇俖侺俀侹俬剄剉勀勂匽卼厗厖厙厘咺咡咭咥哏\"],[\"ce40\",\"哃茍咷咮哖咶哅哆咠呰咼咢咾呲哞咰垵垞垟垤垌垗垝垛垔垘垏垙垥垚垕壴复奓姡姞姮娀姱姝姺姽姼姶姤姲姷姛姩姳姵姠姾姴姭宨屌峐峘峌峗峋峛\"],[\"cea1\",\"峞峚峉峇峊峖峓峔峏峈峆峎峟峸巹帡帢帣帠帤庰庤庢庛庣庥弇弮彖徆怷怹恔恲恞恅恓恇恉恛恌恀恂恟怤恄恘恦恮扂扃拏挍挋拵挎挃拫拹挏挌拸拶挀挓挔拺挕拻拰敁敃斪斿昶昡昲昵昜昦昢昳昫昺昝昴昹昮朏朐柁柲柈枺\"],[\"cf40\",\"柜枻柸柘柀枷柅柫柤柟枵柍枳柷柶柮柣柂枹柎柧柰枲柼柆柭柌枮柦柛柺柉柊柃柪柋欨殂殄殶毖毘毠氠氡洨洴洭洟洼洿洒洊泚洳洄洙洺洚洑洀洝浂\"],[\"cfa1\",\"洁洘洷洃洏浀洇洠洬洈洢洉洐炷炟炾炱炰炡炴炵炩牁牉牊牬牰牳牮狊狤狨狫狟狪狦狣玅珌珂珈珅玹玶玵玴珫玿珇玾珃珆玸珋瓬瓮甮畇畈疧疪癹盄眈眃眄眅眊盷盻盺矧矨砆砑砒砅砐砏砎砉砃砓祊祌祋祅祄秕种秏秖秎窀\"],[\"d040\",\"穾竑笀笁籺籸籹籿粀粁紃紈紁罘羑羍羾耇耎耏耔耷胘胇胠胑胈胂胐胅胣胙胜胊胕胉胏胗胦胍臿舡芔苙苾苹茇苨茀苕茺苫苖苴苬苡苲苵茌苻苶苰苪\"],[\"d0a1\",\"苤苠苺苳苭虷虴虼虳衁衎衧衪衩觓訄訇赲迣迡迮迠郱邽邿郕郅邾郇郋郈釔釓陔陏陑陓陊陎倞倅倇倓倢倰倛俵俴倳倷倬俶俷倗倜倠倧倵倯倱倎党冔冓凊凄凅凈凎剡剚剒剞剟剕剢勍匎厞唦哢唗唒哧哳哤唚哿唄唈哫唑唅哱\"],[\"d140\",\"唊哻哷哸哠唎唃唋圁圂埌堲埕埒垺埆垽垼垸垶垿埇埐垹埁夎奊娙娖娭娮娕娏娗娊娞娳孬宧宭宬尃屖屔峬峿峮峱峷崀峹帩帨庨庮庪庬弳弰彧恝恚恧\"],[\"d1a1\",\"恁悢悈悀悒悁悝悃悕悛悗悇悜悎戙扆拲挐捖挬捄捅挶捃揤挹捋捊挼挩捁挴捘捔捙挭捇挳捚捑挸捗捀捈敊敆旆旃旄旂晊晟晇晑朒朓栟栚桉栲栳栻桋桏栖栱栜栵栫栭栯桎桄栴栝栒栔栦栨栮桍栺栥栠欬欯欭欱欴歭肂殈毦毤\"],[\"d240\",\"毨毣毢毧氥浺浣浤浶洍浡涒浘浢浭浯涑涍淯浿涆浞浧浠涗浰浼浟涂涘洯浨涋浾涀涄洖涃浻浽浵涐烜烓烑烝烋缹烢烗烒烞烠烔烍烅烆烇烚烎烡牂牸\"],[\"d2a1\",\"牷牶猀狺狴狾狶狳狻猁珓珙珥珖玼珧珣珩珜珒珛珔珝珚珗珘珨瓞瓟瓴瓵甡畛畟疰痁疻痄痀疿疶疺皊盉眝眛眐眓眒眣眑眕眙眚眢眧砣砬砢砵砯砨砮砫砡砩砳砪砱祔祛祏祜祓祒祑秫秬秠秮秭秪秜秞秝窆窉窅窋窌窊窇竘笐\"],[\"d340\",\"笄笓笅笏笈笊笎笉笒粄粑粊粌粈粍粅紞紝紑紎紘紖紓紟紒紏紌罜罡罞罠罝罛羖羒翃翂翀耖耾耹胺胲胹胵脁胻脀舁舯舥茳茭荄茙荑茥荖茿荁茦茜茢\"],[\"d3a1\",\"荂荎茛茪茈茼荍茖茤茠茷茯茩荇荅荌荓茞茬荋茧荈虓虒蚢蚨蚖蚍蚑蚞蚇蚗蚆蚋蚚蚅蚥蚙蚡蚧蚕蚘蚎蚝蚐蚔衃衄衭衵衶衲袀衱衿衯袃衾衴衼訒豇豗豻貤貣赶赸趵趷趶軑軓迾迵适迿迻逄迼迶郖郠郙郚郣郟郥郘郛郗郜郤酐\"],[\"d440\",\"酎酏釕釢釚陜陟隼飣髟鬯乿偰偪偡偞偠偓偋偝偲偈偍偁偛偊偢倕偅偟偩偫偣偤偆偀偮偳偗偑凐剫剭剬剮勖勓匭厜啵啶唼啍啐唴唪啑啢唶唵唰啒啅\"],[\"d4a1\",\"唌唲啥啎唹啈唭唻啀啋圊圇埻堔埢埶埜埴堀埭埽堈埸堋埳埏堇埮埣埲埥埬埡堎埼堐埧堁堌埱埩埰堍堄奜婠婘婕婧婞娸娵婭婐婟婥婬婓婤婗婃婝婒婄婛婈媎娾婍娹婌婰婩婇婑婖婂婜孲孮寁寀屙崞崋崝崚崠崌崨崍崦崥崏\"],[\"d540\",\"崰崒崣崟崮帾帴庱庴庹庲庳弶弸徛徖徟悊悐悆悾悰悺惓惔惏惤惙惝惈悱惛悷惊悿惃惍惀挲捥掊掂捽掽掞掭掝掗掫掎捯掇掐据掯捵掜捭掮捼掤挻掟\"],[\"d5a1\",\"捸掅掁掑掍捰敓旍晥晡晛晙晜晢朘桹梇梐梜桭桮梮梫楖桯梣梬梩桵桴梲梏桷梒桼桫桲梪梀桱桾梛梖梋梠梉梤桸桻梑梌梊桽欶欳欷欸殑殏殍殎殌氪淀涫涴涳湴涬淩淢涷淶淔渀淈淠淟淖涾淥淜淝淛淴淊涽淭淰涺淕淂淏淉\"],[\"d640\",\"淐淲淓淽淗淍淣涻烺焍烷焗烴焌烰焄烳焐烼烿焆焓焀烸烶焋焂焎牾牻牼牿猝猗猇猑猘猊猈狿猏猞玈珶珸珵琄琁珽琇琀珺珼珿琌琋珴琈畤畣痎痒痏\"],[\"d6a1\",\"痋痌痑痐皏皉盓眹眯眭眱眲眴眳眽眥眻眵硈硒硉硍硊硌砦硅硐祤祧祩祪祣祫祡离秺秸秶秷窏窔窐笵筇笴笥笰笢笤笳笘笪笝笱笫笭笯笲笸笚笣粔粘粖粣紵紽紸紶紺絅紬紩絁絇紾紿絊紻紨罣羕羜羝羛翊翋翍翐翑翇翏翉耟\"],[\"d740\",\"耞耛聇聃聈脘脥脙脛脭脟脬脞脡脕脧脝脢舑舸舳舺舴舲艴莐莣莨莍荺荳莤荴莏莁莕莙荵莔莩荽莃莌莝莛莪莋荾莥莯莈莗莰荿莦莇莮荶莚虙虖蚿蚷\"],[\"d7a1\",\"蛂蛁蛅蚺蚰蛈蚹蚳蚸蛌蚴蚻蚼蛃蚽蚾衒袉袕袨袢袪袚袑袡袟袘袧袙袛袗袤袬袌袓袎覂觖觙觕訰訧訬訞谹谻豜豝豽貥赽赻赹趼跂趹趿跁軘軞軝軜軗軠軡逤逋逑逜逌逡郯郪郰郴郲郳郔郫郬郩酖酘酚酓酕釬釴釱釳釸釤釹釪\"],[\"d840\",\"釫釷釨釮镺閆閈陼陭陫陱陯隿靪頄飥馗傛傕傔傞傋傣傃傌傎傝偨傜傒傂傇兟凔匒匑厤厧喑喨喥喭啷噅喢喓喈喏喵喁喣喒喤啽喌喦啿喕喡喎圌堩堷\"],[\"d8a1\",\"堙堞堧堣堨埵塈堥堜堛堳堿堶堮堹堸堭堬堻奡媯媔媟婺媢媞婸媦婼媥媬媕媮娷媄媊媗媃媋媩婻婽媌媜媏媓媝寪寍寋寔寑寊寎尌尰崷嵃嵫嵁嵋崿崵嵑嵎嵕崳崺嵒崽崱嵙嵂崹嵉崸崼崲崶嵀嵅幄幁彘徦徥徫惉悹惌惢惎惄愔\"],[\"d940\",\"惲愊愖愅惵愓惸惼惾惁愃愘愝愐惿愄愋扊掔掱掰揎揥揨揯揃撝揳揊揠揶揕揲揵摡揟掾揝揜揄揘揓揂揇揌揋揈揰揗揙攲敧敪敤敜敨敥斌斝斞斮旐旒\"],[\"d9a1\",\"晼晬晻暀晱晹晪晲朁椌棓椄棜椪棬棪棱椏棖棷棫棤棶椓椐棳棡椇棌椈楰梴椑棯棆椔棸棐棽棼棨椋椊椗棎棈棝棞棦棴棑椆棔棩椕椥棇欹欻欿欼殔殗殙殕殽毰毲毳氰淼湆湇渟湉溈渼渽湅湢渫渿湁湝湳渜渳湋湀湑渻渃渮湞\"],[\"da40\",\"湨湜湡渱渨湠湱湫渹渢渰湓湥渧湸湤湷湕湹湒湦渵渶湚焠焞焯烻焮焱焣焥焢焲焟焨焺焛牋牚犈犉犆犅犋猒猋猰猢猱猳猧猲猭猦猣猵猌琮琬琰琫琖\"],[\"daa1\",\"琚琡琭琱琤琣琝琩琠琲瓻甯畯畬痧痚痡痦痝痟痤痗皕皒盚睆睇睄睍睅睊睎睋睌矞矬硠硤硥硜硭硱硪确硰硩硨硞硢祴祳祲祰稂稊稃稌稄窙竦竤筊笻筄筈筌筎筀筘筅粢粞粨粡絘絯絣絓絖絧絪絏絭絜絫絒絔絩絑絟絎缾缿罥\"],[\"db40\",\"罦羢羠羡翗聑聏聐胾胔腃腊腒腏腇脽腍脺臦臮臷臸臹舄舼舽舿艵茻菏菹萣菀菨萒菧菤菼菶萐菆菈菫菣莿萁菝菥菘菿菡菋菎菖菵菉萉萏菞萑萆菂菳\"],[\"dba1\",\"菕菺菇菑菪萓菃菬菮菄菻菗菢萛菛菾蛘蛢蛦蛓蛣蛚蛪蛝蛫蛜蛬蛩蛗蛨蛑衈衖衕袺裗袹袸裀袾袶袼袷袽袲褁裉覕覘覗觝觚觛詎詍訹詙詀詗詘詄詅詒詈詑詊詌詏豟貁貀貺貾貰貹貵趄趀趉跘跓跍跇跖跜跏跕跙跈跗跅軯軷軺\"],[\"dc40\",\"軹軦軮軥軵軧軨軶軫軱軬軴軩逭逴逯鄆鄬鄄郿郼鄈郹郻鄁鄀鄇鄅鄃酡酤酟酢酠鈁鈊鈥鈃鈚鈦鈏鈌鈀鈒釿釽鈆鈄鈧鈂鈜鈤鈙鈗鈅鈖镻閍閌閐隇陾隈\"],[\"dca1\",\"隉隃隀雂雈雃雱雰靬靰靮頇颩飫鳦黹亃亄亶傽傿僆傮僄僊傴僈僂傰僁傺傱僋僉傶傸凗剺剸剻剼嗃嗛嗌嗐嗋嗊嗝嗀嗔嗄嗩喿嗒喍嗏嗕嗢嗖嗈嗲嗍嗙嗂圔塓塨塤塏塍塉塯塕塎塝塙塥塛堽塣塱壼嫇嫄嫋媺媸媱媵媰媿嫈媻嫆\"],[\"dd40\",\"媷嫀嫊媴媶嫍媹媐寖寘寙尟尳嵱嵣嵊嵥嵲嵬嵞嵨嵧嵢巰幏幎幊幍幋廅廌廆廋廇彀徯徭惷慉慊愫慅愶愲愮慆愯慏愩慀戠酨戣戥戤揅揱揫搐搒搉搠搤\"],[\"dda1\",\"搳摃搟搕搘搹搷搢搣搌搦搰搨摁搵搯搊搚摀搥搧搋揧搛搮搡搎敯斒旓暆暌暕暐暋暊暙暔晸朠楦楟椸楎楢楱椿楅楪椹楂楗楙楺楈楉椵楬椳椽楥棰楸椴楩楀楯楄楶楘楁楴楌椻楋椷楜楏楑椲楒椯楻椼歆歅歃歂歈歁殛嗀毻毼\"],[\"de40\",\"毹毷毸溛滖滈溏滀溟溓溔溠溱溹滆滒溽滁溞滉溷溰滍溦滏溲溾滃滜滘溙溒溎溍溤溡溿溳滐滊溗溮溣煇煔煒煣煠煁煝煢煲煸煪煡煂煘煃煋煰煟煐煓\"],[\"dea1\",\"煄煍煚牏犍犌犑犐犎猼獂猻猺獀獊獉瑄瑊瑋瑒瑑瑗瑀瑏瑐瑎瑂瑆瑍瑔瓡瓿瓾瓽甝畹畷榃痯瘏瘃痷痾痼痹痸瘐痻痶痭痵痽皙皵盝睕睟睠睒睖睚睩睧睔睙睭矠碇碚碔碏碄碕碅碆碡碃硹碙碀碖硻祼禂祽祹稑稘稙稒稗稕稢稓\"],[\"df40\",\"稛稐窣窢窞竫筦筤筭筴筩筲筥筳筱筰筡筸筶筣粲粴粯綈綆綀綍絿綅絺綎絻綃絼綌綔綄絽綒罭罫罧罨罬羦羥羧翛翜耡腤腠腷腜腩腛腢腲朡腞腶腧腯\"],[\"dfa1\",\"腄腡舝艉艄艀艂艅蓱萿葖葶葹蒏蒍葥葑葀蒆葧萰葍葽葚葙葴葳葝蔇葞萷萺萴葺葃葸萲葅萩菙葋萯葂萭葟葰萹葎葌葒葯蓅蒎萻葇萶萳葨葾葄萫葠葔葮葐蜋蜄蛷蜌蛺蛖蛵蝍蛸蜎蜉蜁蛶蜍蜅裖裋裍裎裞裛裚裌裐覅覛觟觥觤\"],[\"e040\",\"觡觠觢觜触詶誆詿詡訿詷誂誄詵誃誁詴詺谼豋豊豥豤豦貆貄貅賌赨赩趑趌趎趏趍趓趔趐趒跰跠跬跱跮跐跩跣跢跧跲跫跴輆軿輁輀輅輇輈輂輋遒逿\"],[\"e0a1\",\"遄遉逽鄐鄍鄏鄑鄖鄔鄋鄎酮酯鉈鉒鈰鈺鉦鈳鉥鉞銃鈮鉊鉆鉭鉬鉏鉠鉧鉯鈶鉡鉰鈱鉔鉣鉐鉲鉎鉓鉌鉖鈲閟閜閞閛隒隓隑隗雎雺雽雸雵靳靷靸靲頏頍頎颬飶飹馯馲馰馵骭骫魛鳪鳭鳧麀黽僦僔僗僨僳僛僪僝僤僓僬僰僯僣僠\"],[\"e140\",\"凘劀劁勩勫匰厬嘧嘕嘌嘒嗼嘏嘜嘁嘓嘂嗺嘝嘄嗿嗹墉塼墐墘墆墁塿塴墋塺墇墑墎塶墂墈塻墔墏壾奫嫜嫮嫥嫕嫪嫚嫭嫫嫳嫢嫠嫛嫬嫞嫝嫙嫨嫟孷寠\"],[\"e1a1\",\"寣屣嶂嶀嵽嶆嵺嶁嵷嶊嶉嶈嵾嵼嶍嵹嵿幘幙幓廘廑廗廎廜廕廙廒廔彄彃彯徶愬愨慁慞慱慳慒慓慲慬憀慴慔慺慛慥愻慪慡慖戩戧戫搫摍摛摝摴摶摲摳摽摵摦撦摎撂摞摜摋摓摠摐摿搿摬摫摙摥摷敳斠暡暠暟朅朄朢榱榶槉\"],[\"e240\",\"榠槎榖榰榬榼榑榙榎榧榍榩榾榯榿槄榽榤槔榹槊榚槏榳榓榪榡榞槙榗榐槂榵榥槆歊歍歋殞殟殠毃毄毾滎滵滱漃漥滸漷滻漮漉潎漙漚漧漘漻漒滭漊\"],[\"e2a1\",\"漶潳滹滮漭潀漰漼漵滫漇漎潃漅滽滶漹漜滼漺漟漍漞漈漡熇熐熉熀熅熂熏煻熆熁熗牄牓犗犕犓獃獍獑獌瑢瑳瑱瑵瑲瑧瑮甀甂甃畽疐瘖瘈瘌瘕瘑瘊瘔皸瞁睼瞅瞂睮瞀睯睾瞃碲碪碴碭碨硾碫碞碥碠碬碢碤禘禊禋禖禕禔禓\"],[\"e340\",\"禗禈禒禐稫穊稰稯稨稦窨窫窬竮箈箜箊箑箐箖箍箌箛箎箅箘劄箙箤箂粻粿粼粺綧綷緂綣綪緁緀緅綝緎緄緆緋緌綯綹綖綼綟綦綮綩綡緉罳翢翣翥翞\"],[\"e3a1\",\"耤聝聜膉膆膃膇膍膌膋舕蒗蒤蒡蒟蒺蓎蓂蒬蒮蒫蒹蒴蓁蓍蒪蒚蒱蓐蒝蒧蒻蒢蒔蓇蓌蒛蒩蒯蒨蓖蒘蒶蓏蒠蓗蓔蓒蓛蒰蒑虡蜳蜣蜨蝫蝀蜮蜞蜡蜙蜛蝃蜬蝁蜾蝆蜠蜲蜪蜭蜼蜒蜺蜱蜵蝂蜦蜧蜸蜤蜚蜰蜑裷裧裱裲裺裾裮裼裶裻\"],[\"e440\",\"裰裬裫覝覡覟覞觩觫觨誫誙誋誒誏誖谽豨豩賕賏賗趖踉踂跿踍跽踊踃踇踆踅跾踀踄輐輑輎輍鄣鄜鄠鄢鄟鄝鄚鄤鄡鄛酺酲酹酳銥銤鉶銛鉺銠銔銪銍\"],[\"e4a1\",\"銦銚銫鉹銗鉿銣鋮銎銂銕銢鉽銈銡銊銆銌銙銧鉾銇銩銝銋鈭隞隡雿靘靽靺靾鞃鞀鞂靻鞄鞁靿韎韍頖颭颮餂餀餇馝馜駃馹馻馺駂馽駇骱髣髧鬾鬿魠魡魟鳱鳲鳵麧僿儃儰僸儆儇僶僾儋儌僽儊劋劌勱勯噈噂噌嘵噁噊噉噆噘\"],[\"e540\",\"噚噀嘳嘽嘬嘾嘸嘪嘺圚墫墝墱墠墣墯墬墥墡壿嫿嫴嫽嫷嫶嬃嫸嬂嫹嬁嬇嬅嬏屧嶙嶗嶟嶒嶢嶓嶕嶠嶜嶡嶚嶞幩幝幠幜緳廛廞廡彉徲憋憃慹憱憰憢憉\"],[\"e5a1\",\"憛憓憯憭憟憒憪憡憍慦憳戭摮摰撖撠撅撗撜撏撋撊撌撣撟摨撱撘敶敺敹敻斲斳暵暰暩暲暷暪暯樀樆樗槥槸樕槱槤樠槿槬槢樛樝槾樧槲槮樔槷槧橀樈槦槻樍槼槫樉樄樘樥樏槶樦樇槴樖歑殥殣殢殦氁氀毿氂潁漦潾澇濆澒\"],[\"e640\",\"澍澉澌潢潏澅潚澖潶潬澂潕潲潒潐潗澔澓潝漀潡潫潽潧澐潓澋潩潿澕潣潷潪潻熲熯熛熰熠熚熩熵熝熥熞熤熡熪熜熧熳犘犚獘獒獞獟獠獝獛獡獚獙\"],[\"e6a1\",\"獢璇璉璊璆璁瑽璅璈瑼瑹甈甇畾瘥瘞瘙瘝瘜瘣瘚瘨瘛皜皝皞皛瞍瞏瞉瞈磍碻磏磌磑磎磔磈磃磄磉禚禡禠禜禢禛歶稹窲窴窳箷篋箾箬篎箯箹篊箵糅糈糌糋緷緛緪緧緗緡縃緺緦緶緱緰緮緟罶羬羰羭翭翫翪翬翦翨聤聧膣膟\"],[\"e740\",\"膞膕膢膙膗舖艏艓艒艐艎艑蔤蔻蔏蔀蔩蔎蔉蔍蔟蔊蔧蔜蓻蔫蓺蔈蔌蓴蔪蓲蔕蓷蓫蓳蓼蔒蓪蓩蔖蓾蔨蔝蔮蔂蓽蔞蓶蔱蔦蓧蓨蓰蓯蓹蔘蔠蔰蔋蔙蔯虢\"],[\"e7a1\",\"蝖蝣蝤蝷蟡蝳蝘蝔蝛蝒蝡蝚蝑蝞蝭蝪蝐蝎蝟蝝蝯蝬蝺蝮蝜蝥蝏蝻蝵蝢蝧蝩衚褅褌褔褋褗褘褙褆褖褑褎褉覢覤覣觭觰觬諏諆誸諓諑諔諕誻諗誾諀諅諘諃誺誽諙谾豍貏賥賟賙賨賚賝賧趠趜趡趛踠踣踥踤踮踕踛踖踑踙踦踧\"],[\"e840\",\"踔踒踘踓踜踗踚輬輤輘輚輠輣輖輗遳遰遯遧遫鄯鄫鄩鄪鄲鄦鄮醅醆醊醁醂醄醀鋐鋃鋄鋀鋙銶鋏鋱鋟鋘鋩鋗鋝鋌鋯鋂鋨鋊鋈鋎鋦鋍鋕鋉鋠鋞鋧鋑鋓\"],[\"e8a1\",\"銵鋡鋆銴镼閬閫閮閰隤隢雓霅霈霂靚鞊鞎鞈韐韏頞頝頦頩頨頠頛頧颲餈飺餑餔餖餗餕駜駍駏駓駔駎駉駖駘駋駗駌骳髬髫髳髲髱魆魃魧魴魱魦魶魵魰魨魤魬鳼鳺鳽鳿鳷鴇鴀鳹鳻鴈鴅鴄麃黓鼏鼐儜儓儗儚儑凞匴叡噰噠噮\"],[\"e940\",\"噳噦噣噭噲噞噷圜圛壈墽壉墿墺壂墼壆嬗嬙嬛嬡嬔嬓嬐嬖嬨嬚嬠嬞寯嶬嶱嶩嶧嶵嶰嶮嶪嶨嶲嶭嶯嶴幧幨幦幯廩廧廦廨廥彋徼憝憨憖懅憴懆懁懌憺\"],[\"e9a1\",\"憿憸憌擗擖擐擏擉撽撉擃擛擳擙攳敿敼斢曈暾曀曊曋曏暽暻暺曌朣樴橦橉橧樲橨樾橝橭橶橛橑樨橚樻樿橁橪橤橐橏橔橯橩橠樼橞橖橕橍橎橆歕歔歖殧殪殫毈毇氄氃氆澭濋澣濇澼濎濈潞濄澽澞濊澨瀄澥澮澺澬澪濏澿澸\"],[\"ea40\",\"澢濉澫濍澯澲澰燅燂熿熸燖燀燁燋燔燊燇燏熽燘熼燆燚燛犝犞獩獦獧獬獥獫獪瑿璚璠璔璒璕璡甋疀瘯瘭瘱瘽瘳瘼瘵瘲瘰皻盦瞚瞝瞡瞜瞛瞢瞣瞕瞙\"],[\"eaa1\",\"瞗磝磩磥磪磞磣磛磡磢磭磟磠禤穄穈穇窶窸窵窱窷篞篣篧篝篕篥篚篨篹篔篪篢篜篫篘篟糒糔糗糐糑縒縡縗縌縟縠縓縎縜縕縚縢縋縏縖縍縔縥縤罃罻罼罺羱翯耪耩聬膱膦膮膹膵膫膰膬膴膲膷膧臲艕艖艗蕖蕅蕫蕍蕓蕡蕘\"],[\"eb40\",\"蕀蕆蕤蕁蕢蕄蕑蕇蕣蔾蕛蕱蕎蕮蕵蕕蕧蕠薌蕦蕝蕔蕥蕬虣虥虤螛螏螗螓螒螈螁螖螘蝹螇螣螅螐螑螝螄螔螜螚螉褞褦褰褭褮褧褱褢褩褣褯褬褟觱諠\"],[\"eba1\",\"諢諲諴諵諝謔諤諟諰諈諞諡諨諿諯諻貑貒貐賵賮賱賰賳赬赮趥趧踳踾踸蹀蹅踶踼踽蹁踰踿躽輶輮輵輲輹輷輴遶遹遻邆郺鄳鄵鄶醓醐醑醍醏錧錞錈錟錆錏鍺錸錼錛錣錒錁鍆錭錎錍鋋錝鋺錥錓鋹鋷錴錂錤鋿錩錹錵錪錔錌\"],[\"ec40\",\"錋鋾錉錀鋻錖閼闍閾閹閺閶閿閵閽隩雔霋霒霐鞙鞗鞔韰韸頵頯頲餤餟餧餩馞駮駬駥駤駰駣駪駩駧骹骿骴骻髶髺髹髷鬳鮀鮅鮇魼魾魻鮂鮓鮒鮐魺鮕\"],[\"eca1\",\"魽鮈鴥鴗鴠鴞鴔鴩鴝鴘鴢鴐鴙鴟麈麆麇麮麭黕黖黺鼒鼽儦儥儢儤儠儩勴嚓嚌嚍嚆嚄嚃噾嚂噿嚁壖壔壏壒嬭嬥嬲嬣嬬嬧嬦嬯嬮孻寱寲嶷幬幪徾徻懃憵憼懧懠懥懤懨懞擯擩擣擫擤擨斁斀斶旚曒檍檖檁檥檉檟檛檡檞檇檓檎\"],[\"ed40\",\"檕檃檨檤檑橿檦檚檅檌檒歛殭氉濌澩濴濔濣濜濭濧濦濞濲濝濢濨燡燱燨燲燤燰燢獳獮獯璗璲璫璐璪璭璱璥璯甐甑甒甏疄癃癈癉癇皤盩瞵瞫瞲瞷瞶\"],[\"eda1\",\"瞴瞱瞨矰磳磽礂磻磼磲礅磹磾礄禫禨穜穛穖穘穔穚窾竀竁簅簏篲簀篿篻簎篴簋篳簂簉簃簁篸篽簆篰篱簐簊糨縭縼繂縳顈縸縪繉繀繇縩繌縰縻縶繄縺罅罿罾罽翴翲耬膻臄臌臊臅臇膼臩艛艚艜薃薀薏薧薕薠薋薣蕻薤薚薞\"],[\"ee40\",\"蕷蕼薉薡蕺蕸蕗薎薖薆薍薙薝薁薢薂薈薅蕹蕶薘薐薟虨螾螪螭蟅螰螬螹螵螼螮蟉蟃蟂蟌螷螯蟄蟊螴螶螿螸螽蟞螲褵褳褼褾襁襒褷襂覭覯覮觲觳謞\"],[\"eea1\",\"謘謖謑謅謋謢謏謒謕謇謍謈謆謜謓謚豏豰豲豱豯貕貔賹赯蹎蹍蹓蹐蹌蹇轃轀邅遾鄸醚醢醛醙醟醡醝醠鎡鎃鎯鍤鍖鍇鍼鍘鍜鍶鍉鍐鍑鍠鍭鎏鍌鍪鍹鍗鍕鍒鍏鍱鍷鍻鍡鍞鍣鍧鎀鍎鍙闇闀闉闃闅閷隮隰隬霠霟霘霝霙鞚鞡鞜\"],[\"ef40\",\"鞞鞝韕韔韱顁顄顊顉顅顃餥餫餬餪餳餲餯餭餱餰馘馣馡騂駺駴駷駹駸駶駻駽駾駼騃骾髾髽鬁髼魈鮚鮨鮞鮛鮦鮡鮥鮤鮆鮢鮠鮯鴳鵁鵧鴶鴮鴯鴱鴸鴰\"],[\"efa1\",\"鵅鵂鵃鴾鴷鵀鴽翵鴭麊麉麍麰黈黚黻黿鼤鼣鼢齔龠儱儭儮嚘嚜嚗嚚嚝嚙奰嬼屩屪巀幭幮懘懟懭懮懱懪懰懫懖懩擿攄擽擸攁攃擼斔旛曚曛曘櫅檹檽櫡櫆檺檶檷櫇檴檭歞毉氋瀇瀌瀍瀁瀅瀔瀎濿瀀濻瀦濼濷瀊爁燿燹爃燽獶\"],[\"f040\",\"璸瓀璵瓁璾璶璻瓂甔甓癜癤癙癐癓癗癚皦皽盬矂瞺磿礌礓礔礉礐礒礑禭禬穟簜簩簙簠簟簭簝簦簨簢簥簰繜繐繖繣繘繢繟繑繠繗繓羵羳翷翸聵臑臒\"],[\"f0a1\",\"臐艟艞薴藆藀藃藂薳薵薽藇藄薿藋藎藈藅薱薶藒蘤薸薷薾虩蟧蟦蟢蟛蟫蟪蟥蟟蟳蟤蟔蟜蟓蟭蟘蟣螤蟗蟙蠁蟴蟨蟝襓襋襏襌襆襐襑襉謪謧謣謳謰謵譇謯謼謾謱謥謷謦謶謮謤謻謽謺豂豵貙貘貗賾贄贂贀蹜蹢蹠蹗蹖蹞蹥蹧\"],[\"f140\",\"蹛蹚蹡蹝蹩蹔轆轇轈轋鄨鄺鄻鄾醨醥醧醯醪鎵鎌鎒鎷鎛鎝鎉鎧鎎鎪鎞鎦鎕鎈鎙鎟鎍鎱鎑鎲鎤鎨鎴鎣鎥闒闓闑隳雗雚巂雟雘雝霣霢霥鞬鞮鞨鞫鞤鞪\"],[\"f1a1\",\"鞢鞥韗韙韖韘韺顐顑顒颸饁餼餺騏騋騉騍騄騑騊騅騇騆髀髜鬈鬄鬅鬩鬵魊魌魋鯇鯆鯃鮿鯁鮵鮸鯓鮶鯄鮹鮽鵜鵓鵏鵊鵛鵋鵙鵖鵌鵗鵒鵔鵟鵘鵚麎麌黟鼁鼀鼖鼥鼫鼪鼩鼨齌齕儴儵劖勷厴嚫嚭嚦嚧嚪嚬壚壝壛夒嬽嬾嬿巃幰\"],[\"f240\",\"徿懻攇攐攍攉攌攎斄旞旝曞櫧櫠櫌櫑櫙櫋櫟櫜櫐櫫櫏櫍櫞歠殰氌瀙瀧瀠瀖瀫瀡瀢瀣瀩瀗瀤瀜瀪爌爊爇爂爅犥犦犤犣犡瓋瓅璷瓃甖癠矉矊矄矱礝礛\"],[\"f2a1\",\"礡礜礗礞禰穧穨簳簼簹簬簻糬糪繶繵繸繰繷繯繺繲繴繨罋罊羃羆羷翽翾聸臗臕艤艡艣藫藱藭藙藡藨藚藗藬藲藸藘藟藣藜藑藰藦藯藞藢蠀蟺蠃蟶蟷蠉蠌蠋蠆蟼蠈蟿蠊蠂襢襚襛襗襡襜襘襝襙覈覷覶觶譐譈譊譀譓譖譔譋譕\"],[\"f340\",\"譑譂譒譗豃豷豶貚贆贇贉趬趪趭趫蹭蹸蹳蹪蹯蹻軂轒轑轏轐轓辴酀鄿醰醭鏞鏇鏏鏂鏚鏐鏹鏬鏌鏙鎩鏦鏊鏔鏮鏣鏕鏄鏎鏀鏒鏧镽闚闛雡霩霫霬霨霦\"],[\"f3a1\",\"鞳鞷鞶韝韞韟顜顙顝顗颿颽颻颾饈饇饃馦馧騚騕騥騝騤騛騢騠騧騣騞騜騔髂鬋鬊鬎鬌鬷鯪鯫鯠鯞鯤鯦鯢鯰鯔鯗鯬鯜鯙鯥鯕鯡鯚鵷鶁鶊鶄鶈鵱鶀鵸鶆鶋鶌鵽鵫鵴鵵鵰鵩鶅鵳鵻鶂鵯鵹鵿鶇鵨麔麑黀黼鼭齀齁齍齖齗齘匷嚲\"],[\"f440\",\"嚵嚳壣孅巆巇廮廯忀忁懹攗攖攕攓旟曨曣曤櫳櫰櫪櫨櫹櫱櫮櫯瀼瀵瀯瀷瀴瀱灂瀸瀿瀺瀹灀瀻瀳灁爓爔犨獽獼璺皫皪皾盭矌矎矏矍矲礥礣礧礨礤礩\"],[\"f4a1\",\"禲穮穬穭竷籉籈籊籇籅糮繻繾纁纀羺翿聹臛臙舋艨艩蘢藿蘁藾蘛蘀藶蘄蘉蘅蘌藽蠙蠐蠑蠗蠓蠖襣襦覹觷譠譪譝譨譣譥譧譭趮躆躈躄轙轖轗轕轘轚邍酃酁醷醵醲醳鐋鐓鏻鐠鐏鐔鏾鐕鐐鐨鐙鐍鏵鐀鏷鐇鐎鐖鐒鏺鐉鏸鐊鏿\"],[\"f540\",\"鏼鐌鏶鐑鐆闞闠闟霮霯鞹鞻韽韾顠顢顣顟飁飂饐饎饙饌饋饓騲騴騱騬騪騶騩騮騸騭髇髊髆鬐鬒鬑鰋鰈鯷鰅鰒鯸鱀鰇鰎鰆鰗鰔鰉鶟鶙鶤鶝鶒鶘鶐鶛\"],[\"f5a1\",\"鶠鶔鶜鶪鶗鶡鶚鶢鶨鶞鶣鶿鶩鶖鶦鶧麙麛麚黥黤黧黦鼰鼮齛齠齞齝齙龑儺儹劘劗囃嚽嚾孈孇巋巏廱懽攛欂櫼欃櫸欀灃灄灊灈灉灅灆爝爚爙獾甗癪矐礭礱礯籔籓糲纊纇纈纋纆纍罍羻耰臝蘘蘪蘦蘟蘣蘜蘙蘧蘮蘡蘠蘩蘞蘥\"],[\"f640\",\"蠩蠝蠛蠠蠤蠜蠫衊襭襩襮襫觺譹譸譅譺譻贐贔趯躎躌轞轛轝酆酄酅醹鐿鐻鐶鐩鐽鐼鐰鐹鐪鐷鐬鑀鐱闥闤闣霵霺鞿韡顤飉飆飀饘饖騹騽驆驄驂驁騺\"],[\"f6a1\",\"騿髍鬕鬗鬘鬖鬺魒鰫鰝鰜鰬鰣鰨鰩鰤鰡鶷鶶鶼鷁鷇鷊鷏鶾鷅鷃鶻鶵鷎鶹鶺鶬鷈鶱鶭鷌鶳鷍鶲鹺麜黫黮黭鼛鼘鼚鼱齎齥齤龒亹囆囅囋奱孋孌巕巑廲攡攠攦攢欋欈欉氍灕灖灗灒爞爟犩獿瓘瓕瓙瓗癭皭礵禴穰穱籗籜籙籛籚\"],[\"f740\",\"糴糱纑罏羇臞艫蘴蘵蘳蘬蘲蘶蠬蠨蠦蠪蠥襱覿覾觻譾讄讂讆讅譿贕躕躔躚躒躐躖躗轠轢酇鑌鑐鑊鑋鑏鑇鑅鑈鑉鑆霿韣顪顩飋饔饛驎驓驔驌驏驈驊\"],[\"f7a1\",\"驉驒驐髐鬙鬫鬻魖魕鱆鱈鰿鱄鰹鰳鱁鰼鰷鰴鰲鰽鰶鷛鷒鷞鷚鷋鷐鷜鷑鷟鷩鷙鷘鷖鷵鷕鷝麶黰鼵鼳鼲齂齫龕龢儽劙壨壧奲孍巘蠯彏戁戃戄攩攥斖曫欑欒欏毊灛灚爢玂玁玃癰矔籧籦纕艬蘺虀蘹蘼蘱蘻蘾蠰蠲蠮蠳襶襴襳觾\"],[\"f840\",\"讌讎讋讈豅贙躘轤轣醼鑢鑕鑝鑗鑞韄韅頀驖驙鬞鬟鬠鱒鱘鱐鱊鱍鱋鱕鱙鱌鱎鷻鷷鷯鷣鷫鷸鷤鷶鷡鷮鷦鷲鷰鷢鷬鷴鷳鷨鷭黂黐黲黳鼆鼜鼸鼷鼶齃齏\"],[\"f8a1\",\"齱齰齮齯囓囍孎屭攭曭曮欓灟灡灝灠爣瓛瓥矕礸禷禶籪纗羉艭虃蠸蠷蠵衋讔讕躞躟躠躝醾醽釂鑫鑨鑩雥靆靃靇韇韥驞髕魙鱣鱧鱦鱢鱞鱠鸂鷾鸇鸃鸆鸅鸀鸁鸉鷿鷽鸄麠鼞齆齴齵齶囔攮斸欘欙欗欚灢爦犪矘矙礹籩籫糶纚\"],[\"f940\",\"纘纛纙臠臡虆虇虈襹襺襼襻觿讘讙躥躤躣鑮鑭鑯鑱鑳靉顲饟鱨鱮鱭鸋鸍鸐鸏鸒鸑麡黵鼉齇齸齻齺齹圞灦籯蠼趲躦釃鑴鑸鑶鑵驠鱴鱳鱱鱵鸔鸓黶鼊\"],[\"f9a1\",\"龤灨灥糷虪蠾蠽蠿讞貜躩軉靋顳顴飌饡馫驤驦驧鬤鸕鸗齈戇欞爧虌躨钂钀钁驩驨鬮鸙爩虋讟钃鱹麷癵驫鱺鸝灩灪麤齾齉龘碁銹裏墻恒粧嫺╔╦╗╠╬╣╚╩╝╒╤╕╞╪╡╘╧╛╓╥╖╟╫╢╙╨╜║═╭╮╰╯▓\"]]\n\n/***/ }),\n/* 93 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var ArrayT, NumberT, utils;\n\n  NumberT = __webpack_require__(22).Number;\n\n  utils = __webpack_require__(12);\n\n  ArrayT = (function() {\n    function ArrayT(type, length, lengthType) {\n      this.type = type;\n      this.length = length;\n      this.lengthType = lengthType != null ? lengthType : 'count';\n    }\n\n    ArrayT.prototype.decode = function(stream, parent) {\n      var ctx, i, length, pos, res, target, _i;\n      pos = stream.pos;\n      res = [];\n      ctx = parent;\n      if (this.length != null) {\n        length = utils.resolveLength(this.length, stream, parent);\n      }\n      if (this.length instanceof NumberT) {\n        Object.defineProperties(res, {\n          parent: {\n            value: parent\n          },\n          _startOffset: {\n            value: pos\n          },\n          _currentOffset: {\n            value: 0,\n            writable: true\n          },\n          _length: {\n            value: length\n          }\n        });\n        ctx = res;\n      }\n      if ((length == null) || this.lengthType === 'bytes') {\n        target = length != null ? stream.pos + length : (parent != null ? parent._length : void 0) ? parent._startOffset + parent._length : stream.length;\n        while (stream.pos < target) {\n          res.push(this.type.decode(stream, ctx));\n        }\n      } else {\n        for (i = _i = 0; _i < length; i = _i += 1) {\n          res.push(this.type.decode(stream, ctx));\n        }\n      }\n      return res;\n    };\n\n    ArrayT.prototype.size = function(array, ctx) {\n      var item, size, _i, _len;\n      if (!array) {\n        return this.type.size(null, ctx) * utils.resolveLength(this.length, null, ctx);\n      }\n      size = 0;\n      if (this.length instanceof NumberT) {\n        size += this.length.size();\n        ctx = {\n          parent: ctx\n        };\n      }\n      for (_i = 0, _len = array.length; _i < _len; _i++) {\n        item = array[_i];\n        size += this.type.size(item, ctx);\n      }\n      return size;\n    };\n\n    ArrayT.prototype.encode = function(stream, array, parent) {\n      var ctx, i, item, ptr, _i, _len;\n      ctx = parent;\n      if (this.length instanceof NumberT) {\n        ctx = {\n          pointers: [],\n          startOffset: stream.pos,\n          parent: parent\n        };\n        ctx.pointerOffset = stream.pos + this.size(array, ctx);\n        this.length.encode(stream, array.length);\n      }\n      for (_i = 0, _len = array.length; _i < _len; _i++) {\n        item = array[_i];\n        this.type.encode(stream, item, ctx);\n      }\n      if (this.length instanceof NumberT) {\n        i = 0;\n        while (i < ctx.pointers.length) {\n          ptr = ctx.pointers[i++];\n          ptr.type.encode(stream, ptr.val);\n        }\n      }\n    };\n\n    return ArrayT;\n\n  })();\n\n  module.exports = ArrayT;\n\n}).call(this);\n\n\n/***/ }),\n/* 94 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var Struct, utils;\n\n  utils = __webpack_require__(12);\n\n  Struct = (function() {\n    function Struct(fields) {\n      this.fields = fields != null ? fields : {};\n    }\n\n    Struct.prototype.decode = function(stream, parent, length) {\n      var res, _ref;\n      if (length == null) {\n        length = 0;\n      }\n      res = this._setup(stream, parent, length);\n      this._parseFields(stream, res, this.fields);\n      if ((_ref = this.process) != null) {\n        _ref.call(res, stream);\n      }\n      return res;\n    };\n\n    Struct.prototype._setup = function(stream, parent, length) {\n      var res;\n      res = {};\n      Object.defineProperties(res, {\n        parent: {\n          value: parent\n        },\n        _startOffset: {\n          value: stream.pos\n        },\n        _currentOffset: {\n          value: 0,\n          writable: true\n        },\n        _length: {\n          value: length\n        }\n      });\n      return res;\n    };\n\n    Struct.prototype._parseFields = function(stream, res, fields) {\n      var key, type, val;\n      for (key in fields) {\n        type = fields[key];\n        if (typeof type === 'function') {\n          val = type.call(res, res);\n        } else {\n          val = type.decode(stream, res);\n        }\n        if (val !== void 0) {\n          if (val instanceof utils.PropertyDescriptor) {\n            Object.defineProperty(res, key, val);\n          } else {\n            res[key] = val;\n          }\n        }\n        res._currentOffset = stream.pos - res._startOffset;\n      }\n    };\n\n    Struct.prototype.size = function(val, parent, includePointers) {\n      var ctx, key, size, type, _ref;\n      if (val == null) {\n        val = {};\n      }\n      if (includePointers == null) {\n        includePointers = true;\n      }\n      ctx = {\n        parent: parent,\n        val: val,\n        pointerSize: 0\n      };\n      size = 0;\n      _ref = this.fields;\n      for (key in _ref) {\n        type = _ref[key];\n        if (type.size != null) {\n          size += type.size(val[key], ctx);\n        }\n      }\n      if (includePointers) {\n        size += ctx.pointerSize;\n      }\n      return size;\n    };\n\n    Struct.prototype.encode = function(stream, val, parent) {\n      var ctx, i, key, ptr, type, _ref, _ref1;\n      if ((_ref = this.preEncode) != null) {\n        _ref.call(val, stream);\n      }\n      ctx = {\n        pointers: [],\n        startOffset: stream.pos,\n        parent: parent,\n        val: val,\n        pointerSize: 0\n      };\n      ctx.pointerOffset = stream.pos + this.size(val, ctx, false);\n      _ref1 = this.fields;\n      for (key in _ref1) {\n        type = _ref1[key];\n        if (type.encode != null) {\n          type.encode(stream, val[key], ctx);\n        }\n      }\n      i = 0;\n      while (i < ctx.pointers.length) {\n        ptr = ctx.pointers[i++];\n        ptr.type.encode(stream, ptr.val, ptr.parent);\n      }\n    };\n\n    return Struct;\n\n  })();\n\n  module.exports = Struct;\n\n}).call(this);\n\n\n/***/ }),\n/* 95 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = !__webpack_require__(5) && !__webpack_require__(19)(function () {\n  return Object.defineProperty(__webpack_require__(96)('div'), 'a', { get: function () { return 7; } }).a != 7;\n});\n\n\n/***/ }),\n/* 96 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar isObject = __webpack_require__(9);\nvar document = __webpack_require__(10).document;\n// typeof document.createElement is 'object' in old IE\nvar is = isObject(document) && isObject(document.createElement);\nmodule.exports = function (it) {\n  return is ? document.createElement(it) : {};\n};\n\n\n/***/ }),\n/* 97 */\n/***/ (function(module, exports) {\n\nmodule.exports = function (it) {\n  if (typeof it != 'function') throw TypeError(it + ' is not a function!');\n  return it;\n};\n\n\n/***/ }),\n/* 98 */\n/***/ (function(module, exports) {\n\nmodule.exports = function (done, value) {\n  return { value: value, done: !!done };\n};\n\n\n/***/ }),\n/* 99 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(13);\n\n\n/***/ }),\n/* 100 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar dP = __webpack_require__(6);\nvar anObject = __webpack_require__(14);\nvar getKeys = __webpack_require__(29);\n\nmodule.exports = __webpack_require__(5) ? Object.defineProperties : function defineProperties(O, Properties) {\n  anObject(O);\n  var keys = getKeys(Properties);\n  var length = keys.length;\n  var i = 0;\n  var P;\n  while (length > i) dP.f(O, P = keys[i++], Properties[P]);\n  return O;\n};\n\n\n/***/ }),\n/* 101 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar has = __webpack_require__(18);\nvar toIObject = __webpack_require__(17);\nvar arrayIndexOf = __webpack_require__(204)(false);\nvar IE_PROTO = __webpack_require__(64)('IE_PROTO');\n\nmodule.exports = function (object, names) {\n  var O = toIObject(object);\n  var i = 0;\n  var result = [];\n  var key;\n  for (key in O) if (key != IE_PROTO) has(O, key) && result.push(key);\n  // Don't enum bug & hidden keys\n  while (names.length > i) if (has(O, key = names[i++])) {\n    ~arrayIndexOf(result, key) || result.push(key);\n  }\n  return result;\n};\n\n\n/***/ }),\n/* 102 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar toInteger = __webpack_require__(63);\nvar max = Math.max;\nvar min = Math.min;\nmodule.exports = function (index, length) {\n  index = toInteger(index);\n  return index < 0 ? max(index + length, 0) : min(index, length);\n};\n\n\n/***/ }),\n/* 103 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(215), __esModule: true };\n\n/***/ }),\n/* 104 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 7.2.2 IsArray(argument)\nvar cof = __webpack_require__(55);\nmodule.exports = Array.isArray || function isArray(arg) {\n  return cof(arg) == 'Array';\n};\n\n\n/***/ }),\n/* 105 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.2.7 / 15.2.3.4 Object.getOwnPropertyNames(O)\nvar $keys = __webpack_require__(101);\nvar hiddenKeys = __webpack_require__(66).concat('length', 'prototype');\n\nexports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {\n  return $keys(O, hiddenKeys);\n};\n\n\n/***/ }),\n/* 106 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nexports.default = function (instance, Constructor) {\n  if (!(instance instanceof Constructor)) {\n    throw new TypeError(\"Cannot call a class as a function\");\n  }\n};\n\n/***/ }),\n/* 107 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nvar _defineProperty = __webpack_require__(74);\n\nvar _defineProperty2 = _interopRequireDefault(_defineProperty);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nexports.default = function () {\n  function defineProperties(target, props) {\n    for (var i = 0; i < props.length; i++) {\n      var descriptor = props[i];\n      descriptor.enumerable = descriptor.enumerable || false;\n      descriptor.configurable = true;\n      if (\"value\" in descriptor) descriptor.writable = true;\n      (0, _defineProperty2.default)(target, descriptor.key, descriptor);\n    }\n  }\n\n  return function (Constructor, protoProps, staticProps) {\n    if (protoProps) defineProperties(Constructor.prototype, protoProps);\n    if (staticProps) defineProperties(Constructor, staticProps);\n    return Constructor;\n  };\n}();\n\n/***/ }),\n/* 108 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar dP = __webpack_require__(6).f;\nvar create = __webpack_require__(36);\nvar redefineAll = __webpack_require__(109);\nvar ctx = __webpack_require__(20);\nvar anInstance = __webpack_require__(110);\nvar forOf = __webpack_require__(41);\nvar $iterDefine = __webpack_require__(61);\nvar step = __webpack_require__(98);\nvar setSpecies = __webpack_require__(228);\nvar DESCRIPTORS = __webpack_require__(5);\nvar fastKey = __webpack_require__(40).fastKey;\nvar validate = __webpack_require__(75);\nvar SIZE = DESCRIPTORS ? '_s' : 'size';\n\nvar getEntry = function (that, key) {\n  // fast case\n  var index = fastKey(key);\n  var entry;\n  if (index !== 'F') return that._i[index];\n  // frozen object case\n  for (entry = that._f; entry; entry = entry.n) {\n    if (entry.k == key) return entry;\n  }\n};\n\nmodule.exports = {\n  getConstructor: function (wrapper, NAME, IS_MAP, ADDER) {\n    var C = wrapper(function (that, iterable) {\n      anInstance(that, C, NAME, '_i');\n      that._t = NAME;         // collection type\n      that._i = create(null); // index\n      that._f = undefined;    // first entry\n      that._l = undefined;    // last entry\n      that[SIZE] = 0;         // size\n      if (iterable != undefined) forOf(iterable, IS_MAP, that[ADDER], that);\n    });\n    redefineAll(C.prototype, {\n      // 23.1.3.1 Map.prototype.clear()\n      // 23.2.3.2 Set.prototype.clear()\n      clear: function clear() {\n        for (var that = validate(this, NAME), data = that._i, entry = that._f; entry; entry = entry.n) {\n          entry.r = true;\n          if (entry.p) entry.p = entry.p.n = undefined;\n          delete data[entry.i];\n        }\n        that._f = that._l = undefined;\n        that[SIZE] = 0;\n      },\n      // 23.1.3.3 Map.prototype.delete(key)\n      // 23.2.3.4 Set.prototype.delete(value)\n      'delete': function (key) {\n        var that = validate(this, NAME);\n        var entry = getEntry(that, key);\n        if (entry) {\n          var next = entry.n;\n          var prev = entry.p;\n          delete that._i[entry.i];\n          entry.r = true;\n          if (prev) prev.n = next;\n          if (next) next.p = prev;\n          if (that._f == entry) that._f = next;\n          if (that._l == entry) that._l = prev;\n          that[SIZE]--;\n        } return !!entry;\n      },\n      // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)\n      // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)\n      forEach: function forEach(callbackfn /* , that = undefined */) {\n        validate(this, NAME);\n        var f = ctx(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);\n        var entry;\n        while (entry = entry ? entry.n : this._f) {\n          f(entry.v, entry.k, this);\n          // revert to the last existing entry\n          while (entry && entry.r) entry = entry.p;\n        }\n      },\n      // 23.1.3.7 Map.prototype.has(key)\n      // 23.2.3.7 Set.prototype.has(value)\n      has: function has(key) {\n        return !!getEntry(validate(this, NAME), key);\n      }\n    });\n    if (DESCRIPTORS) dP(C.prototype, 'size', {\n      get: function () {\n        return validate(this, NAME)[SIZE];\n      }\n    });\n    return C;\n  },\n  def: function (that, key, value) {\n    var entry = getEntry(that, key);\n    var prev, index;\n    // change existing entry\n    if (entry) {\n      entry.v = value;\n    // create new entry\n    } else {\n      that._l = entry = {\n        i: index = fastKey(key, true), // <- index\n        k: key,                        // <- key\n        v: value,                      // <- value\n        p: prev = that._l,             // <- previous entry\n        n: undefined,                  // <- next entry\n        r: false                       // <- removed\n      };\n      if (!that._f) that._f = entry;\n      if (prev) prev.n = entry;\n      that[SIZE]++;\n      // add to index\n      if (index !== 'F') that._i[index] = entry;\n    } return that;\n  },\n  getEntry: getEntry,\n  setStrong: function (C, NAME, IS_MAP) {\n    // add .keys, .values, .entries, [@@iterator]\n    // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11\n    $iterDefine(C, NAME, function (iterated, kind) {\n      this._t = validate(iterated, NAME); // target\n      this._k = kind;                     // kind\n      this._l = undefined;                // previous\n    }, function () {\n      var that = this;\n      var kind = that._k;\n      var entry = that._l;\n      // revert to the last existing entry\n      while (entry && entry.r) entry = entry.p;\n      // get next entry\n      if (!that._t || !(that._l = entry = entry ? entry.n : that._t._f)) {\n        // or finish the iteration\n        that._t = undefined;\n        return step(1);\n      }\n      // return step by kind\n      if (kind == 'keys') return step(0, entry.k);\n      if (kind == 'values') return step(0, entry.v);\n      return step(0, [entry.k, entry.v]);\n    }, IS_MAP ? 'entries' : 'values', !IS_MAP, true);\n\n    // add [@@species], 23.1.2.2, 23.2.2.2\n    setSpecies(NAME);\n  }\n};\n\n\n/***/ }),\n/* 109 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar hide = __webpack_require__(13);\nmodule.exports = function (target, src, safe) {\n  for (var key in src) {\n    if (safe && target[key]) target[key] = src[key];\n    else hide(target, key, src[key]);\n  } return target;\n};\n\n\n/***/ }),\n/* 110 */\n/***/ (function(module, exports) {\n\nmodule.exports = function (it, Constructor, name, forbiddenField) {\n  if (!(it instanceof Constructor) || (forbiddenField !== undefined && forbiddenField in it)) {\n    throw TypeError(name + ': incorrect invocation!');\n  } return it;\n};\n\n\n/***/ }),\n/* 111 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// call something on iterator step with safe closing on error\nvar anObject = __webpack_require__(14);\nmodule.exports = function (iterator, fn, value, entries) {\n  try {\n    return entries ? fn(anObject(value)[0], value[1]) : fn(value);\n  // 7.4.6 IteratorClose(iterator, completion)\n  } catch (e) {\n    var ret = iterator['return'];\n    if (ret !== undefined) anObject(ret.call(iterator));\n    throw e;\n  }\n};\n\n\n/***/ }),\n/* 112 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// check on default Array iterator\nvar Iterators = __webpack_require__(23);\nvar ITERATOR = __webpack_require__(4)('iterator');\nvar ArrayProto = Array.prototype;\n\nmodule.exports = function (it) {\n  return it !== undefined && (Iterators.Array === it || ArrayProto[ITERATOR] === it);\n};\n\n\n/***/ }),\n/* 113 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar global = __webpack_require__(10);\nvar $export = __webpack_require__(3);\nvar meta = __webpack_require__(40);\nvar fails = __webpack_require__(19);\nvar hide = __webpack_require__(13);\nvar redefineAll = __webpack_require__(109);\nvar forOf = __webpack_require__(41);\nvar anInstance = __webpack_require__(110);\nvar isObject = __webpack_require__(9);\nvar setToStringTag = __webpack_require__(39);\nvar dP = __webpack_require__(6).f;\nvar each = __webpack_require__(229)(0);\nvar DESCRIPTORS = __webpack_require__(5);\n\nmodule.exports = function (NAME, wrapper, methods, common, IS_MAP, IS_WEAK) {\n  var Base = global[NAME];\n  var C = Base;\n  var ADDER = IS_MAP ? 'set' : 'add';\n  var proto = C && C.prototype;\n  var O = {};\n  if (!DESCRIPTORS || typeof C != 'function' || !(IS_WEAK || proto.forEach && !fails(function () {\n    new C().entries().next();\n  }))) {\n    // create collection constructor\n    C = common.getConstructor(wrapper, NAME, IS_MAP, ADDER);\n    redefineAll(C.prototype, methods);\n    meta.NEED = true;\n  } else {\n    C = wrapper(function (target, iterable) {\n      anInstance(target, C, NAME, '_c');\n      target._c = new Base();\n      if (iterable != undefined) forOf(iterable, IS_MAP, target[ADDER], target);\n    });\n    each('add,clear,delete,forEach,get,has,set,keys,values,entries,toJSON'.split(','), function (KEY) {\n      var IS_ADDER = KEY == 'add' || KEY == 'set';\n      if (KEY in proto && !(IS_WEAK && KEY == 'clear')) hide(C.prototype, KEY, function (a, b) {\n        anInstance(this, C, KEY);\n        if (!IS_ADDER && IS_WEAK && !isObject(a)) return KEY == 'get' ? undefined : false;\n        var result = this._c[KEY](a === 0 ? 0 : a, b);\n        return IS_ADDER ? this : result;\n      });\n    });\n    IS_WEAK || dP(C.prototype, 'size', {\n      get: function () {\n        return this._c.size;\n      }\n    });\n  }\n\n  setToStringTag(C, NAME);\n\n  O[NAME] = C;\n  $export($export.G + $export.W + $export.F, O);\n\n  if (!IS_WEAK) common.setStrong(C, NAME, IS_MAP);\n\n  return C;\n};\n\n\n/***/ }),\n/* 114 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// https://github.com/DavidBruant/Map-Set.prototype.toJSON\nvar classof = __webpack_require__(68);\nvar from = __webpack_require__(233);\nmodule.exports = function (NAME) {\n  return function toJSON() {\n    if (classof(this) != NAME) throw TypeError(NAME + \"#toJSON isn't generic\");\n    return from(this);\n  };\n};\n\n\n/***/ }),\n/* 115 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n// https://tc39.github.io/proposal-setmap-offrom/\nvar $export = __webpack_require__(3);\n\nmodule.exports = function (COLLECTION) {\n  $export($export.S, COLLECTION, { of: function of() {\n    var length = arguments.length;\n    var A = new Array(length);\n    while (length--) A[length] = arguments[length];\n    return new this(A);\n  } });\n};\n\n\n/***/ }),\n/* 116 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n// https://tc39.github.io/proposal-setmap-offrom/\nvar $export = __webpack_require__(3);\nvar aFunction = __webpack_require__(97);\nvar ctx = __webpack_require__(20);\nvar forOf = __webpack_require__(41);\n\nmodule.exports = function (COLLECTION) {\n  $export($export.S, COLLECTION, { from: function from(source /* , mapFn, thisArg */) {\n    var mapFn = arguments[1];\n    var mapping, A, n, cb;\n    aFunction(this);\n    mapping = mapFn !== undefined;\n    if (mapping) aFunction(mapFn);\n    if (source == undefined) return new this();\n    A = [];\n    if (mapping) {\n      n = 0;\n      cb = ctx(mapFn, arguments[2], 2);\n      forOf(source, false, function (nextItem) {\n        A.push(cb(nextItem, n++));\n      });\n    } else {\n      forOf(source, false, A.push, A);\n    }\n    return new this(A);\n  } });\n};\n\n\n/***/ }),\n/* 117 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n*/\n\nvar BrotliInput = __webpack_require__(118).BrotliInput;\nvar BrotliOutput = __webpack_require__(118).BrotliOutput;\nvar BrotliBitReader = __webpack_require__(285);\nvar BrotliDictionary = __webpack_require__(119);\nvar HuffmanCode = __webpack_require__(120).HuffmanCode;\nvar BrotliBuildHuffmanTable = __webpack_require__(120).BrotliBuildHuffmanTable;\nvar Context = __webpack_require__(289);\nvar Prefix = __webpack_require__(290);\nvar Transform = __webpack_require__(291);\n\nvar kDefaultCodeLength = 8;\nvar kCodeLengthRepeatCode = 16;\nvar kNumLiteralCodes = 256;\nvar kNumInsertAndCopyCodes = 704;\nvar kNumBlockLengthCodes = 26;\nvar kLiteralContextBits = 6;\nvar kDistanceContextBits = 2;\n\nvar HUFFMAN_TABLE_BITS = 8;\nvar HUFFMAN_TABLE_MASK = 0xff;\n/* Maximum possible Huffman table size for an alphabet size of 704, max code\n * length 15 and root table bits 8. */\nvar HUFFMAN_MAX_TABLE_SIZE = 1080;\n\nvar CODE_LENGTH_CODES = 18;\nvar kCodeLengthCodeOrder = new Uint8Array([\n  1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n]);\n\nvar NUM_DISTANCE_SHORT_CODES = 16;\nvar kDistanceShortCodeIndexOffset = new Uint8Array([\n  3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2\n]);\n\nvar kDistanceShortCodeValueOffset = new Int8Array([\n  0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3\n]);\n\nvar kMaxHuffmanTableSize = new Uint16Array([\n  256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822,\n  854, 886, 920, 952, 984, 1016, 1048, 1080\n]);\n\nfunction DecodeWindowBits(br) {\n  var n;\n  if (br.readBits(1) === 0) {\n    return 16;\n  }\n  \n  n = br.readBits(3);\n  if (n > 0) {\n    return 17 + n;\n  }\n  \n  n = br.readBits(3);\n  if (n > 0) {\n    return 8 + n;\n  }\n  \n  return 17;\n}\n\n/* Decodes a number in the range [0..255], by reading 1 - 11 bits. */\nfunction DecodeVarLenUint8(br) {\n  if (br.readBits(1)) {\n    var nbits = br.readBits(3);\n    if (nbits === 0) {\n      return 1;\n    } else {\n      return br.readBits(nbits) + (1 << nbits);\n    }\n  }\n  return 0;\n}\n\nfunction MetaBlockLength() {\n  this.meta_block_length = 0;\n  this.input_end = 0;\n  this.is_uncompressed = 0;\n  this.is_metadata = false;\n}\n\nfunction DecodeMetaBlockLength(br) {\n  var out = new MetaBlockLength;  \n  var size_nibbles;\n  var size_bytes;\n  var i;\n  \n  out.input_end = br.readBits(1);\n  if (out.input_end && br.readBits(1)) {\n    return out;\n  }\n  \n  size_nibbles = br.readBits(2) + 4;\n  if (size_nibbles === 7) {\n    out.is_metadata = true;\n    \n    if (br.readBits(1) !== 0)\n      throw new Error('Invalid reserved bit');\n    \n    size_bytes = br.readBits(2);\n    if (size_bytes === 0)\n      return out;\n    \n    for (i = 0; i < size_bytes; i++) {\n      var next_byte = br.readBits(8);\n      if (i + 1 === size_bytes && size_bytes > 1 && next_byte === 0)\n        throw new Error('Invalid size byte');\n      \n      out.meta_block_length |= next_byte << (i * 8);\n    }\n  } else {\n    for (i = 0; i < size_nibbles; ++i) {\n      var next_nibble = br.readBits(4);\n      if (i + 1 === size_nibbles && size_nibbles > 4 && next_nibble === 0)\n        throw new Error('Invalid size nibble');\n      \n      out.meta_block_length |= next_nibble << (i * 4);\n    }\n  }\n  \n  ++out.meta_block_length;\n  \n  if (!out.input_end && !out.is_metadata) {\n    out.is_uncompressed = br.readBits(1);\n  }\n  \n  return out;\n}\n\n/* Decodes the next Huffman code from bit-stream. */\nfunction ReadSymbol(table, index, br) {\n  var start_index = index;\n  \n  var nbits;\n  br.fillBitWindow();\n  index += (br.val_ >>> br.bit_pos_) & HUFFMAN_TABLE_MASK;\n  nbits = table[index].bits - HUFFMAN_TABLE_BITS;\n  if (nbits > 0) {\n    br.bit_pos_ += HUFFMAN_TABLE_BITS;\n    index += table[index].value;\n    index += (br.val_ >>> br.bit_pos_) & ((1 << nbits) - 1);\n  }\n  br.bit_pos_ += table[index].bits;\n  return table[index].value;\n}\n\nfunction ReadHuffmanCodeLengths(code_length_code_lengths, num_symbols, code_lengths, br) {\n  var symbol = 0;\n  var prev_code_len = kDefaultCodeLength;\n  var repeat = 0;\n  var repeat_code_len = 0;\n  var space = 32768;\n  \n  var table = [];\n  for (var i = 0; i < 32; i++)\n    table.push(new HuffmanCode(0, 0));\n  \n  BrotliBuildHuffmanTable(table, 0, 5, code_length_code_lengths, CODE_LENGTH_CODES);\n\n  while (symbol < num_symbols && space > 0) {\n    var p = 0;\n    var code_len;\n    \n    br.readMoreInput();\n    br.fillBitWindow();\n    p += (br.val_ >>> br.bit_pos_) & 31;\n    br.bit_pos_ += table[p].bits;\n    code_len = table[p].value & 0xff;\n    if (code_len < kCodeLengthRepeatCode) {\n      repeat = 0;\n      code_lengths[symbol++] = code_len;\n      if (code_len !== 0) {\n        prev_code_len = code_len;\n        space -= 32768 >> code_len;\n      }\n    } else {\n      var extra_bits = code_len - 14;\n      var old_repeat;\n      var repeat_delta;\n      var new_len = 0;\n      if (code_len === kCodeLengthRepeatCode) {\n        new_len = prev_code_len;\n      }\n      if (repeat_code_len !== new_len) {\n        repeat = 0;\n        repeat_code_len = new_len;\n      }\n      old_repeat = repeat;\n      if (repeat > 0) {\n        repeat -= 2;\n        repeat <<= extra_bits;\n      }\n      repeat += br.readBits(extra_bits) + 3;\n      repeat_delta = repeat - old_repeat;\n      if (symbol + repeat_delta > num_symbols) {\n        throw new Error('[ReadHuffmanCodeLengths] symbol + repeat_delta > num_symbols');\n      }\n      \n      for (var x = 0; x < repeat_delta; x++)\n        code_lengths[symbol + x] = repeat_code_len;\n      \n      symbol += repeat_delta;\n      \n      if (repeat_code_len !== 0) {\n        space -= repeat_delta << (15 - repeat_code_len);\n      }\n    }\n  }\n  if (space !== 0) {\n    throw new Error(\"[ReadHuffmanCodeLengths] space = \" + space);\n  }\n  \n  for (; symbol < num_symbols; symbol++)\n    code_lengths[symbol] = 0;\n}\n\nfunction ReadHuffmanCode(alphabet_size, tables, table, br) {\n  var table_size = 0;\n  var simple_code_or_skip;\n  var code_lengths = new Uint8Array(alphabet_size);\n  \n  br.readMoreInput();\n  \n  /* simple_code_or_skip is used as follows:\n     1 for simple code;\n     0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */\n  simple_code_or_skip = br.readBits(2);\n  if (simple_code_or_skip === 1) {\n    /* Read symbols, codes & code lengths directly. */\n    var i;\n    var max_bits_counter = alphabet_size - 1;\n    var max_bits = 0;\n    var symbols = new Int32Array(4);\n    var num_symbols = br.readBits(2) + 1;\n    while (max_bits_counter) {\n      max_bits_counter >>= 1;\n      ++max_bits;\n    }\n\n    for (i = 0; i < num_symbols; ++i) {\n      symbols[i] = br.readBits(max_bits) % alphabet_size;\n      code_lengths[symbols[i]] = 2;\n    }\n    code_lengths[symbols[0]] = 1;\n    switch (num_symbols) {\n      case 1:\n        break;\n      case 3:\n        if ((symbols[0] === symbols[1]) ||\n            (symbols[0] === symbols[2]) ||\n            (symbols[1] === symbols[2])) {\n          throw new Error('[ReadHuffmanCode] invalid symbols');\n        }\n        break;\n      case 2:\n        if (symbols[0] === symbols[1]) {\n          throw new Error('[ReadHuffmanCode] invalid symbols');\n        }\n        \n        code_lengths[symbols[1]] = 1;\n        break;\n      case 4:\n        if ((symbols[0] === symbols[1]) ||\n            (symbols[0] === symbols[2]) ||\n            (symbols[0] === symbols[3]) ||\n            (symbols[1] === symbols[2]) ||\n            (symbols[1] === symbols[3]) ||\n            (symbols[2] === symbols[3])) {\n          throw new Error('[ReadHuffmanCode] invalid symbols');\n        }\n        \n        if (br.readBits(1)) {\n          code_lengths[symbols[2]] = 3;\n          code_lengths[symbols[3]] = 3;\n        } else {\n          code_lengths[symbols[0]] = 2;\n        }\n        break;\n    }\n  } else {  /* Decode Huffman-coded code lengths. */\n    var i;\n    var code_length_code_lengths = new Uint8Array(CODE_LENGTH_CODES);\n    var space = 32;\n    var num_codes = 0;\n    /* Static Huffman code for the code length code lengths */\n    var huff = [\n      new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(3, 2), \n      new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(4, 1),\n      new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(3, 2), \n      new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(4, 5)\n    ];\n    for (i = simple_code_or_skip; i < CODE_LENGTH_CODES && space > 0; ++i) {\n      var code_len_idx = kCodeLengthCodeOrder[i];\n      var p = 0;\n      var v;\n      br.fillBitWindow();\n      p += (br.val_ >>> br.bit_pos_) & 15;\n      br.bit_pos_ += huff[p].bits;\n      v = huff[p].value;\n      code_length_code_lengths[code_len_idx] = v;\n      if (v !== 0) {\n        space -= (32 >> v);\n        ++num_codes;\n      }\n    }\n    \n    if (!(num_codes === 1 || space === 0))\n      throw new Error('[ReadHuffmanCode] invalid num_codes or space');\n    \n    ReadHuffmanCodeLengths(code_length_code_lengths, alphabet_size, code_lengths, br);\n  }\n  \n  table_size = BrotliBuildHuffmanTable(tables, table, HUFFMAN_TABLE_BITS, code_lengths, alphabet_size);\n  \n  if (table_size === 0) {\n    throw new Error(\"[ReadHuffmanCode] BuildHuffmanTable failed: \");\n  }\n  \n  return table_size;\n}\n\nfunction ReadBlockLength(table, index, br) {\n  var code;\n  var nbits;\n  code = ReadSymbol(table, index, br);\n  nbits = Prefix.kBlockLengthPrefixCode[code].nbits;\n  return Prefix.kBlockLengthPrefixCode[code].offset + br.readBits(nbits);\n}\n\nfunction TranslateShortCodes(code, ringbuffer, index) {\n  var val;\n  if (code < NUM_DISTANCE_SHORT_CODES) {\n    index += kDistanceShortCodeIndexOffset[code];\n    index &= 3;\n    val = ringbuffer[index] + kDistanceShortCodeValueOffset[code];\n  } else {\n    val = code - NUM_DISTANCE_SHORT_CODES + 1;\n  }\n  return val;\n}\n\nfunction MoveToFront(v, index) {\n  var value = v[index];\n  var i = index;\n  for (; i; --i) v[i] = v[i - 1];\n  v[0] = value;\n}\n\nfunction InverseMoveToFrontTransform(v, v_len) {\n  var mtf = new Uint8Array(256);\n  var i;\n  for (i = 0; i < 256; ++i) {\n    mtf[i] = i;\n  }\n  for (i = 0; i < v_len; ++i) {\n    var index = v[i];\n    v[i] = mtf[index];\n    if (index) MoveToFront(mtf, index);\n  }\n}\n\n/* Contains a collection of huffman trees with the same alphabet size. */\nfunction HuffmanTreeGroup(alphabet_size, num_htrees) {\n  this.alphabet_size = alphabet_size;\n  this.num_htrees = num_htrees;\n  this.codes = new Array(num_htrees + num_htrees * kMaxHuffmanTableSize[(alphabet_size + 31) >>> 5]);  \n  this.htrees = new Uint32Array(num_htrees);\n}\n\nHuffmanTreeGroup.prototype.decode = function(br) {\n  var i;\n  var table_size;\n  var next = 0;\n  for (i = 0; i < this.num_htrees; ++i) {\n    this.htrees[i] = next;\n    table_size = ReadHuffmanCode(this.alphabet_size, this.codes, next, br);\n    next += table_size;\n  }\n};\n\nfunction DecodeContextMap(context_map_size, br) {\n  var out = { num_htrees: null, context_map: null };\n  var use_rle_for_zeros;\n  var max_run_length_prefix = 0;\n  var table;\n  var i;\n  \n  br.readMoreInput();\n  var num_htrees = out.num_htrees = DecodeVarLenUint8(br) + 1;\n\n  var context_map = out.context_map = new Uint8Array(context_map_size);\n  if (num_htrees <= 1) {\n    return out;\n  }\n\n  use_rle_for_zeros = br.readBits(1);\n  if (use_rle_for_zeros) {\n    max_run_length_prefix = br.readBits(4) + 1;\n  }\n  \n  table = [];\n  for (i = 0; i < HUFFMAN_MAX_TABLE_SIZE; i++) {\n    table[i] = new HuffmanCode(0, 0);\n  }\n  \n  ReadHuffmanCode(num_htrees + max_run_length_prefix, table, 0, br);\n  \n  for (i = 0; i < context_map_size;) {\n    var code;\n\n    br.readMoreInput();\n    code = ReadSymbol(table, 0, br);\n    if (code === 0) {\n      context_map[i] = 0;\n      ++i;\n    } else if (code <= max_run_length_prefix) {\n      var reps = 1 + (1 << code) + br.readBits(code);\n      while (--reps) {\n        if (i >= context_map_size) {\n          throw new Error(\"[DecodeContextMap] i >= context_map_size\");\n        }\n        context_map[i] = 0;\n        ++i;\n      }\n    } else {\n      context_map[i] = code - max_run_length_prefix;\n      ++i;\n    }\n  }\n  if (br.readBits(1)) {\n    InverseMoveToFrontTransform(context_map, context_map_size);\n  }\n  \n  return out;\n}\n\nfunction DecodeBlockType(max_block_type, trees, tree_type, block_types, ringbuffers, indexes, br) {\n  var ringbuffer = tree_type * 2;\n  var index = tree_type;\n  var type_code = ReadSymbol(trees, tree_type * HUFFMAN_MAX_TABLE_SIZE, br);\n  var block_type;\n  if (type_code === 0) {\n    block_type = ringbuffers[ringbuffer + (indexes[index] & 1)];\n  } else if (type_code === 1) {\n    block_type = ringbuffers[ringbuffer + ((indexes[index] - 1) & 1)] + 1;\n  } else {\n    block_type = type_code - 2;\n  }\n  if (block_type >= max_block_type) {\n    block_type -= max_block_type;\n  }\n  block_types[tree_type] = block_type;\n  ringbuffers[ringbuffer + (indexes[index] & 1)] = block_type;\n  ++indexes[index];\n}\n\nfunction CopyUncompressedBlockToOutput(output, len, pos, ringbuffer, ringbuffer_mask, br) {\n  var rb_size = ringbuffer_mask + 1;\n  var rb_pos = pos & ringbuffer_mask;\n  var br_pos = br.pos_ & BrotliBitReader.IBUF_MASK;\n  var nbytes;\n\n  /* For short lengths copy byte-by-byte */\n  if (len < 8 || br.bit_pos_ + (len << 3) < br.bit_end_pos_) {\n    while (len-- > 0) {\n      br.readMoreInput();\n      ringbuffer[rb_pos++] = br.readBits(8);\n      if (rb_pos === rb_size) {\n        output.write(ringbuffer, rb_size);\n        rb_pos = 0;\n      }\n    }\n    return;\n  }\n\n  if (br.bit_end_pos_ < 32) {\n    throw new Error('[CopyUncompressedBlockToOutput] br.bit_end_pos_ < 32');\n  }\n\n  /* Copy remaining 0-4 bytes from br.val_ to ringbuffer. */\n  while (br.bit_pos_ < 32) {\n    ringbuffer[rb_pos] = (br.val_ >>> br.bit_pos_);\n    br.bit_pos_ += 8;\n    ++rb_pos;\n    --len;\n  }\n\n  /* Copy remaining bytes from br.buf_ to ringbuffer. */\n  nbytes = (br.bit_end_pos_ - br.bit_pos_) >> 3;\n  if (br_pos + nbytes > BrotliBitReader.IBUF_MASK) {\n    var tail = BrotliBitReader.IBUF_MASK + 1 - br_pos;\n    for (var x = 0; x < tail; x++)\n      ringbuffer[rb_pos + x] = br.buf_[br_pos + x];\n    \n    nbytes -= tail;\n    rb_pos += tail;\n    len -= tail;\n    br_pos = 0;\n  }\n\n  for (var x = 0; x < nbytes; x++)\n    ringbuffer[rb_pos + x] = br.buf_[br_pos + x];\n  \n  rb_pos += nbytes;\n  len -= nbytes;\n\n  /* If we wrote past the logical end of the ringbuffer, copy the tail of the\n     ringbuffer to its beginning and flush the ringbuffer to the output. */\n  if (rb_pos >= rb_size) {\n    output.write(ringbuffer, rb_size);\n    rb_pos -= rb_size;    \n    for (var x = 0; x < rb_pos; x++)\n      ringbuffer[x] = ringbuffer[rb_size + x];\n  }\n\n  /* If we have more to copy than the remaining size of the ringbuffer, then we\n     first fill the ringbuffer from the input and then flush the ringbuffer to\n     the output */\n  while (rb_pos + len >= rb_size) {\n    nbytes = rb_size - rb_pos;\n    if (br.input_.read(ringbuffer, rb_pos, nbytes) < nbytes) {\n      throw new Error('[CopyUncompressedBlockToOutput] not enough bytes');\n    }\n    output.write(ringbuffer, rb_size);\n    len -= nbytes;\n    rb_pos = 0;\n  }\n\n  /* Copy straight from the input onto the ringbuffer. The ringbuffer will be\n     flushed to the output at a later time. */\n  if (br.input_.read(ringbuffer, rb_pos, len) < len) {\n    throw new Error('[CopyUncompressedBlockToOutput] not enough bytes');\n  }\n\n  /* Restore the state of the bit reader. */\n  br.reset();\n}\n\n/* Advances the bit reader position to the next byte boundary and verifies\n   that any skipped bits are set to zero. */\nfunction JumpToByteBoundary(br) {\n  var new_bit_pos = (br.bit_pos_ + 7) & ~7;\n  var pad_bits = br.readBits(new_bit_pos - br.bit_pos_);\n  return pad_bits == 0;\n}\n\nfunction BrotliDecompressedSize(buffer) {\n  var input = new BrotliInput(buffer);\n  var br = new BrotliBitReader(input);\n  DecodeWindowBits(br);\n  var out = DecodeMetaBlockLength(br);\n  return out.meta_block_length;\n}\n\nexports.BrotliDecompressedSize = BrotliDecompressedSize;\n\nfunction BrotliDecompressBuffer(buffer, output_size) {\n  var input = new BrotliInput(buffer);\n  \n  if (output_size == null) {\n    output_size = BrotliDecompressedSize(buffer);\n  }\n  \n  var output_buffer = new Uint8Array(output_size);\n  var output = new BrotliOutput(output_buffer);\n  \n  BrotliDecompress(input, output);\n  \n  if (output.pos < output.buffer.length) {\n    output.buffer = output.buffer.subarray(0, output.pos);\n  }\n  \n  return output.buffer;\n}\n\nexports.BrotliDecompressBuffer = BrotliDecompressBuffer;\n\nfunction BrotliDecompress(input, output) {\n  var i;\n  var pos = 0;\n  var input_end = 0;\n  var window_bits = 0;\n  var max_backward_distance;\n  var max_distance = 0;\n  var ringbuffer_size;\n  var ringbuffer_mask;\n  var ringbuffer;\n  var ringbuffer_end;\n  /* This ring buffer holds a few past copy distances that will be used by */\n  /* some special distance codes. */\n  var dist_rb = [ 16, 15, 11, 4 ];\n  var dist_rb_idx = 0;\n  /* The previous 2 bytes used for context. */\n  var prev_byte1 = 0;\n  var prev_byte2 = 0;\n  var hgroup = [new HuffmanTreeGroup(0, 0), new HuffmanTreeGroup(0, 0), new HuffmanTreeGroup(0, 0)];\n  var block_type_trees;\n  var block_len_trees;\n  var br;\n\n  /* We need the slack region for the following reasons:\n       - always doing two 8-byte copies for fast backward copying\n       - transforms\n       - flushing the input ringbuffer when decoding uncompressed blocks */\n  var kRingBufferWriteAheadSlack = 128 + BrotliBitReader.READ_SIZE;\n\n  br = new BrotliBitReader(input);\n\n  /* Decode window size. */\n  window_bits = DecodeWindowBits(br);\n  max_backward_distance = (1 << window_bits) - 16;\n\n  ringbuffer_size = 1 << window_bits;\n  ringbuffer_mask = ringbuffer_size - 1;\n  ringbuffer = new Uint8Array(ringbuffer_size + kRingBufferWriteAheadSlack + BrotliDictionary.maxDictionaryWordLength);\n  ringbuffer_end = ringbuffer_size;\n\n  block_type_trees = [];\n  block_len_trees = [];\n  for (var x = 0; x < 3 * HUFFMAN_MAX_TABLE_SIZE; x++) {\n    block_type_trees[x] = new HuffmanCode(0, 0);\n    block_len_trees[x] = new HuffmanCode(0, 0);\n  }\n\n  while (!input_end) {\n    var meta_block_remaining_len = 0;\n    var is_uncompressed;\n    var block_length = [ 1 << 28, 1 << 28, 1 << 28 ];\n    var block_type = [ 0 ];\n    var num_block_types = [ 1, 1, 1 ];\n    var block_type_rb = [ 0, 1, 0, 1, 0, 1 ];\n    var block_type_rb_index = [ 0 ];\n    var distance_postfix_bits;\n    var num_direct_distance_codes;\n    var distance_postfix_mask;\n    var num_distance_codes;\n    var context_map = null;\n    var context_modes = null;\n    var num_literal_htrees;\n    var dist_context_map = null;\n    var num_dist_htrees;\n    var context_offset = 0;\n    var context_map_slice = null;\n    var literal_htree_index = 0;\n    var dist_context_offset = 0;\n    var dist_context_map_slice = null;\n    var dist_htree_index = 0;\n    var context_lookup_offset1 = 0;\n    var context_lookup_offset2 = 0;\n    var context_mode;\n    var htree_command;\n\n    for (i = 0; i < 3; ++i) {\n      hgroup[i].codes = null;\n      hgroup[i].htrees = null;\n    }\n\n    br.readMoreInput();\n    \n    var _out = DecodeMetaBlockLength(br);\n    meta_block_remaining_len = _out.meta_block_length;\n    if (pos + meta_block_remaining_len > output.buffer.length) {\n      /* We need to grow the output buffer to fit the additional data. */\n      var tmp = new Uint8Array( pos + meta_block_remaining_len );\n      tmp.set( output.buffer );\n      output.buffer = tmp;\n    }    \n    input_end = _out.input_end;\n    is_uncompressed = _out.is_uncompressed;\n    \n    if (_out.is_metadata) {\n      JumpToByteBoundary(br);\n      \n      for (; meta_block_remaining_len > 0; --meta_block_remaining_len) {\n        br.readMoreInput();\n        /* Read one byte and ignore it. */\n        br.readBits(8);\n      }\n      \n      continue;\n    }\n    \n    if (meta_block_remaining_len === 0) {\n      continue;\n    }\n    \n    if (is_uncompressed) {\n      br.bit_pos_ = (br.bit_pos_ + 7) & ~7;\n      CopyUncompressedBlockToOutput(output, meta_block_remaining_len, pos,\n                                    ringbuffer, ringbuffer_mask, br);\n      pos += meta_block_remaining_len;\n      continue;\n    }\n    \n    for (i = 0; i < 3; ++i) {\n      num_block_types[i] = DecodeVarLenUint8(br) + 1;\n      if (num_block_types[i] >= 2) {\n        ReadHuffmanCode(num_block_types[i] + 2, block_type_trees, i * HUFFMAN_MAX_TABLE_SIZE, br);\n        ReadHuffmanCode(kNumBlockLengthCodes, block_len_trees, i * HUFFMAN_MAX_TABLE_SIZE, br);\n        block_length[i] = ReadBlockLength(block_len_trees, i * HUFFMAN_MAX_TABLE_SIZE, br);\n        block_type_rb_index[i] = 1;\n      }\n    }\n    \n    br.readMoreInput();\n    \n    distance_postfix_bits = br.readBits(2);\n    num_direct_distance_codes = NUM_DISTANCE_SHORT_CODES + (br.readBits(4) << distance_postfix_bits);\n    distance_postfix_mask = (1 << distance_postfix_bits) - 1;\n    num_distance_codes = (num_direct_distance_codes + (48 << distance_postfix_bits));\n    context_modes = new Uint8Array(num_block_types[0]);\n\n    for (i = 0; i < num_block_types[0]; ++i) {\n       br.readMoreInput();\n       context_modes[i] = (br.readBits(2) << 1);\n    }\n    \n    var _o1 = DecodeContextMap(num_block_types[0] << kLiteralContextBits, br);\n    num_literal_htrees = _o1.num_htrees;\n    context_map = _o1.context_map;\n    \n    var _o2 = DecodeContextMap(num_block_types[2] << kDistanceContextBits, br);\n    num_dist_htrees = _o2.num_htrees;\n    dist_context_map = _o2.context_map;\n    \n    hgroup[0] = new HuffmanTreeGroup(kNumLiteralCodes, num_literal_htrees);\n    hgroup[1] = new HuffmanTreeGroup(kNumInsertAndCopyCodes, num_block_types[1]);\n    hgroup[2] = new HuffmanTreeGroup(num_distance_codes, num_dist_htrees);\n\n    for (i = 0; i < 3; ++i) {\n      hgroup[i].decode(br);\n    }\n\n    context_map_slice = 0;\n    dist_context_map_slice = 0;\n    context_mode = context_modes[block_type[0]];\n    context_lookup_offset1 = Context.lookupOffsets[context_mode];\n    context_lookup_offset2 = Context.lookupOffsets[context_mode + 1];\n    htree_command = hgroup[1].htrees[0];\n\n    while (meta_block_remaining_len > 0) {\n      var cmd_code;\n      var range_idx;\n      var insert_code;\n      var copy_code;\n      var insert_length;\n      var copy_length;\n      var distance_code;\n      var distance;\n      var context;\n      var j;\n      var copy_dst;\n\n      br.readMoreInput();\n      \n      if (block_length[1] === 0) {\n        DecodeBlockType(num_block_types[1],\n                        block_type_trees, 1, block_type, block_type_rb,\n                        block_type_rb_index, br);\n        block_length[1] = ReadBlockLength(block_len_trees, HUFFMAN_MAX_TABLE_SIZE, br);\n        htree_command = hgroup[1].htrees[block_type[1]];\n      }\n      --block_length[1];\n      cmd_code = ReadSymbol(hgroup[1].codes, htree_command, br);\n      range_idx = cmd_code >> 6;\n      if (range_idx >= 2) {\n        range_idx -= 2;\n        distance_code = -1;\n      } else {\n        distance_code = 0;\n      }\n      insert_code = Prefix.kInsertRangeLut[range_idx] + ((cmd_code >> 3) & 7);\n      copy_code = Prefix.kCopyRangeLut[range_idx] + (cmd_code & 7);\n      insert_length = Prefix.kInsertLengthPrefixCode[insert_code].offset +\n          br.readBits(Prefix.kInsertLengthPrefixCode[insert_code].nbits);\n      copy_length = Prefix.kCopyLengthPrefixCode[copy_code].offset +\n          br.readBits(Prefix.kCopyLengthPrefixCode[copy_code].nbits);\n      prev_byte1 = ringbuffer[pos-1 & ringbuffer_mask];\n      prev_byte2 = ringbuffer[pos-2 & ringbuffer_mask];\n      for (j = 0; j < insert_length; ++j) {\n        br.readMoreInput();\n\n        if (block_length[0] === 0) {\n          DecodeBlockType(num_block_types[0],\n                          block_type_trees, 0, block_type, block_type_rb,\n                          block_type_rb_index, br);\n          block_length[0] = ReadBlockLength(block_len_trees, 0, br);\n          context_offset = block_type[0] << kLiteralContextBits;\n          context_map_slice = context_offset;\n          context_mode = context_modes[block_type[0]];\n          context_lookup_offset1 = Context.lookupOffsets[context_mode];\n          context_lookup_offset2 = Context.lookupOffsets[context_mode + 1];\n        }\n        context = (Context.lookup[context_lookup_offset1 + prev_byte1] |\n                   Context.lookup[context_lookup_offset2 + prev_byte2]);\n        literal_htree_index = context_map[context_map_slice + context];\n        --block_length[0];\n        prev_byte2 = prev_byte1;\n        prev_byte1 = ReadSymbol(hgroup[0].codes, hgroup[0].htrees[literal_htree_index], br);\n        ringbuffer[pos & ringbuffer_mask] = prev_byte1;\n        if ((pos & ringbuffer_mask) === ringbuffer_mask) {\n          output.write(ringbuffer, ringbuffer_size);\n        }\n        ++pos;\n      }\n      meta_block_remaining_len -= insert_length;\n      if (meta_block_remaining_len <= 0) break;\n\n      if (distance_code < 0) {\n        var context;\n        \n        br.readMoreInput();\n        if (block_length[2] === 0) {\n          DecodeBlockType(num_block_types[2],\n                          block_type_trees, 2, block_type, block_type_rb,\n                          block_type_rb_index, br);\n          block_length[2] = ReadBlockLength(block_len_trees, 2 * HUFFMAN_MAX_TABLE_SIZE, br);\n          dist_context_offset = block_type[2] << kDistanceContextBits;\n          dist_context_map_slice = dist_context_offset;\n        }\n        --block_length[2];\n        context = (copy_length > 4 ? 3 : copy_length - 2) & 0xff;\n        dist_htree_index = dist_context_map[dist_context_map_slice + context];\n        distance_code = ReadSymbol(hgroup[2].codes, hgroup[2].htrees[dist_htree_index], br);\n        if (distance_code >= num_direct_distance_codes) {\n          var nbits;\n          var postfix;\n          var offset;\n          distance_code -= num_direct_distance_codes;\n          postfix = distance_code & distance_postfix_mask;\n          distance_code >>= distance_postfix_bits;\n          nbits = (distance_code >> 1) + 1;\n          offset = ((2 + (distance_code & 1)) << nbits) - 4;\n          distance_code = num_direct_distance_codes +\n              ((offset + br.readBits(nbits)) <<\n               distance_postfix_bits) + postfix;\n        }\n      }\n\n      /* Convert the distance code to the actual distance by possibly looking */\n      /* up past distnaces from the ringbuffer. */\n      distance = TranslateShortCodes(distance_code, dist_rb, dist_rb_idx);\n      if (distance < 0) {\n        throw new Error('[BrotliDecompress] invalid distance');\n      }\n\n      if (pos < max_backward_distance &&\n          max_distance !== max_backward_distance) {\n        max_distance = pos;\n      } else {\n        max_distance = max_backward_distance;\n      }\n\n      copy_dst = pos & ringbuffer_mask;\n\n      if (distance > max_distance) {\n        if (copy_length >= BrotliDictionary.minDictionaryWordLength &&\n            copy_length <= BrotliDictionary.maxDictionaryWordLength) {\n          var offset = BrotliDictionary.offsetsByLength[copy_length];\n          var word_id = distance - max_distance - 1;\n          var shift = BrotliDictionary.sizeBitsByLength[copy_length];\n          var mask = (1 << shift) - 1;\n          var word_idx = word_id & mask;\n          var transform_idx = word_id >> shift;\n          offset += word_idx * copy_length;\n          if (transform_idx < Transform.kNumTransforms) {\n            var len = Transform.transformDictionaryWord(ringbuffer, copy_dst, offset, copy_length, transform_idx);\n            copy_dst += len;\n            pos += len;\n            meta_block_remaining_len -= len;\n            if (copy_dst >= ringbuffer_end) {\n              output.write(ringbuffer, ringbuffer_size);\n              \n              for (var _x = 0; _x < (copy_dst - ringbuffer_end); _x++)\n                ringbuffer[_x] = ringbuffer[ringbuffer_end + _x];\n            }\n          } else {\n            throw new Error(\"Invalid backward reference. pos: \" + pos + \" distance: \" + distance +\n              \" len: \" + copy_length + \" bytes left: \" + meta_block_remaining_len);\n          }\n        } else {\n          throw new Error(\"Invalid backward reference. pos: \" + pos + \" distance: \" + distance +\n            \" len: \" + copy_length + \" bytes left: \" + meta_block_remaining_len);\n        }\n      } else {\n        if (distance_code > 0) {\n          dist_rb[dist_rb_idx & 3] = distance;\n          ++dist_rb_idx;\n        }\n\n        if (copy_length > meta_block_remaining_len) {\n          throw new Error(\"Invalid backward reference. pos: \" + pos + \" distance: \" + distance +\n            \" len: \" + copy_length + \" bytes left: \" + meta_block_remaining_len);\n        }\n\n        for (j = 0; j < copy_length; ++j) {\n          ringbuffer[pos & ringbuffer_mask] = ringbuffer[(pos - distance) & ringbuffer_mask];\n          if ((pos & ringbuffer_mask) === ringbuffer_mask) {\n            output.write(ringbuffer, ringbuffer_size);\n          }\n          ++pos;\n          --meta_block_remaining_len;\n        }\n      }\n\n      /* When we get here, we must have inserted at least one literal and */\n      /* made a copy of at least length two, therefore accessing the last 2 */\n      /* bytes is valid. */\n      prev_byte1 = ringbuffer[(pos - 1) & ringbuffer_mask];\n      prev_byte2 = ringbuffer[(pos - 2) & ringbuffer_mask];\n    }\n\n    /* Protect pos from overflow, wrap it around at every GB of input data */\n    pos &= 0x3fffffff;\n  }\n\n  output.write(ringbuffer, pos & ringbuffer_mask);\n}\n\nexports.BrotliDecompress = BrotliDecompress;\n\nBrotliDictionary.init();\n\n\n/***/ }),\n/* 118 */\n/***/ (function(module, exports) {\n\nfunction BrotliInput(buffer) {\n  this.buffer = buffer;\n  this.pos = 0;\n}\n\nBrotliInput.prototype.read = function(buf, i, count) {\n  if (this.pos + count > this.buffer.length) {\n    count = this.buffer.length - this.pos;\n  }\n  \n  for (var p = 0; p < count; p++)\n    buf[i + p] = this.buffer[this.pos + p];\n  \n  this.pos += count;\n  return count;\n}\n\nexports.BrotliInput = BrotliInput;\n\nfunction BrotliOutput(buf) {\n  this.buffer = buf;\n  this.pos = 0;\n}\n\nBrotliOutput.prototype.write = function(buf, count) {\n  if (this.pos + count > this.buffer.length)\n    throw new Error('Output buffer is not large enough');\n  \n  this.buffer.set(buf.subarray(0, count), this.pos);\n  this.pos += count;\n  return count;\n};\n\nexports.BrotliOutput = BrotliOutput;\n\n\n/***/ }),\n/* 119 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n   Collection of static dictionary words.\n*/\n\nvar data = __webpack_require__(286);\nexports.init = function() {\n  exports.dictionary = data.init();\n};\n\nexports.offsetsByLength = new Uint32Array([\n     0,     0,     0,     0,     0,  4096,  9216, 21504, 35840, 44032,\n 53248, 63488, 74752, 87040, 93696, 100864, 104704, 106752, 108928, 113536,\n 115968, 118528, 119872, 121280, 122016,\n]);\n\nexports.sizeBitsByLength = new Uint8Array([\n  0,  0,  0,  0, 10, 10, 11, 11, 10, 10,\n 10, 10, 10,  9,  9,  8,  7,  7,  8,  7,\n  7,  6,  6,  5,  5,\n]);\n\nexports.minDictionaryWordLength = 4;\nexports.maxDictionaryWordLength = 24;\n\n\n/***/ }),\n/* 120 */\n/***/ (function(module, exports) {\n\nfunction HuffmanCode(bits, value) {\n  this.bits = bits;   /* number of bits used for this symbol */\n  this.value = value; /* symbol value or table offset */\n}\n\nexports.HuffmanCode = HuffmanCode;\n\nvar MAX_LENGTH = 15;\n\n/* Returns reverse(reverse(key, len) + 1, len), where reverse(key, len) is the\n   bit-wise reversal of the len least significant bits of key. */\nfunction GetNextKey(key, len) {\n  var step = 1 << (len - 1);\n  while (key & step) {\n    step >>= 1;\n  }\n  return (key & (step - 1)) + step;\n}\n\n/* Stores code in table[0], table[step], table[2*step], ..., table[end] */\n/* Assumes that end is an integer multiple of step */\nfunction ReplicateValue(table, i, step, end, code) {\n  do {\n    end -= step;\n    table[i + end] = new HuffmanCode(code.bits, code.value);\n  } while (end > 0);\n}\n\n/* Returns the table width of the next 2nd level table. count is the histogram\n   of bit lengths for the remaining symbols, len is the code length of the next\n   processed symbol */\nfunction NextTableBitSize(count, len, root_bits) {\n  var left = 1 << (len - root_bits);\n  while (len < MAX_LENGTH) {\n    left -= count[len];\n    if (left <= 0) break;\n    ++len;\n    left <<= 1;\n  }\n  return len - root_bits;\n}\n\nexports.BrotliBuildHuffmanTable = function(root_table, table, root_bits, code_lengths, code_lengths_size) {\n  var start_table = table;\n  var code;            /* current table entry */\n  var len;             /* current code length */\n  var symbol;          /* symbol index in original or sorted table */\n  var key;             /* reversed prefix code */\n  var step;            /* step size to replicate values in current table */\n  var low;             /* low bits for current root entry */\n  var mask;            /* mask for low bits */\n  var table_bits;      /* key length of current table */\n  var table_size;      /* size of current table */\n  var total_size;      /* sum of root table size and 2nd level table sizes */\n  var sorted;          /* symbols sorted by code length */\n  var count = new Int32Array(MAX_LENGTH + 1);  /* number of codes of each length */\n  var offset = new Int32Array(MAX_LENGTH + 1);  /* offsets in sorted table for each length */\n\n  sorted = new Int32Array(code_lengths_size);\n\n  /* build histogram of code lengths */\n  for (symbol = 0; symbol < code_lengths_size; symbol++) {\n    count[code_lengths[symbol]]++;\n  }\n\n  /* generate offsets into sorted symbol table by code length */\n  offset[1] = 0;\n  for (len = 1; len < MAX_LENGTH; len++) {\n    offset[len + 1] = offset[len] + count[len];\n  }\n\n  /* sort symbols by length, by symbol order within each length */\n  for (symbol = 0; symbol < code_lengths_size; symbol++) {\n    if (code_lengths[symbol] !== 0) {\n      sorted[offset[code_lengths[symbol]]++] = symbol;\n    }\n  }\n  \n  table_bits = root_bits;\n  table_size = 1 << table_bits;\n  total_size = table_size;\n\n  /* special case code with only one value */\n  if (offset[MAX_LENGTH] === 1) {\n    for (key = 0; key < total_size; ++key) {\n      root_table[table + key] = new HuffmanCode(0, sorted[0] & 0xffff);\n    }\n    \n    return total_size;\n  }\n\n  /* fill in root table */\n  key = 0;\n  symbol = 0;\n  for (len = 1, step = 2; len <= root_bits; ++len, step <<= 1) {\n    for (; count[len] > 0; --count[len]) {\n      code = new HuffmanCode(len & 0xff, sorted[symbol++] & 0xffff);\n      ReplicateValue(root_table, table + key, step, table_size, code);\n      key = GetNextKey(key, len);\n    }\n  }\n\n  /* fill in 2nd level tables and add pointers to root table */\n  mask = total_size - 1;\n  low = -1;\n  for (len = root_bits + 1, step = 2; len <= MAX_LENGTH; ++len, step <<= 1) {\n    for (; count[len] > 0; --count[len]) {\n      if ((key & mask) !== low) {\n        table += table_size;\n        table_bits = NextTableBitSize(count, len, root_bits);\n        table_size = 1 << table_bits;\n        total_size += table_size;\n        low = key & mask;\n        root_table[start_table + low] = new HuffmanCode((table_bits + root_bits) & 0xff, ((table - start_table) - low) & 0xffff);\n      }\n      code = new HuffmanCode((len - root_bits) & 0xff, sorted[symbol++] & 0xffff);\n      ReplicateValue(root_table, table + (key >> root_bits), step, table_size, code);\n      key = GetNextKey(key, len);\n    }\n  }\n  \n  return total_size;\n}\n\n\n/***/ }),\n/* 121 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6\n\n/*\nPDFImage - embeds images in PDF documents\nBy Devon Govett\n */\n\n(function() {\n  var Data, JPEG, PDFImage, PNG, fs;\n\n  fs = __webpack_require__(8);\n\n  Data = __webpack_require__(298);\n\n  JPEG = __webpack_require__(299);\n\n  PNG = __webpack_require__(300);\n\n  PDFImage = (function() {\n    function PDFImage() {}\n\n    PDFImage.open = function(src, label) {\n      var data, match;\n      if (Buffer.isBuffer(src)) {\n        data = src;\n      } else if (src instanceof ArrayBuffer) {\n        data = new Buffer(new Uint8Array(src));\n      } else {\n        if (match = /^data:.+;base64,(.*)$/.exec(src)) {\n          data = new Buffer(match[1], 'base64');\n        } else {\n          data = fs.readFileSync(src);\n          if (!data) {\n            return;\n          }\n        }\n      }\n      if (data[0] === 0xff && data[1] === 0xd8) {\n        return new JPEG(data, label);\n      } else if (data[0] === 0x89 && data.toString('ascii', 1, 4) === 'PNG') {\n        return new PNG(data, label);\n      } else {\n        throw new Error('Unknown image format.');\n      }\n    };\n\n    return PDFImage;\n\n  })();\n\n  module.exports = PDFImage;\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 122 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(global) {module.exports = global[\"pdfMake\"] = __webpack_require__(123);\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))\n\n/***/ }),\n/* 123 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(Buffer, global) {\n\nvar PdfPrinter = __webpack_require__(126);\nvar isFunction = __webpack_require__(0).isFunction;\nvar FileSaver = __webpack_require__(306);\nvar saveAs = FileSaver.saveAs;\n\nvar defaultClientFonts = {\n\tRoboto: {\n\t\tnormal: 'Roboto-Regular.ttf',\n\t\tbold: 'Roboto-Medium.ttf',\n\t\titalics: 'Roboto-Italic.ttf',\n\t\tbolditalics: 'Roboto-MediumItalic.ttf'\n\t}\n};\n\nfunction Document(docDefinition, tableLayouts, fonts, vfs) {\n\tthis.docDefinition = docDefinition;\n\tthis.tableLayouts = tableLayouts || null;\n\tthis.fonts = fonts || defaultClientFonts;\n\tthis.vfs = vfs;\n}\n\nfunction canCreatePdf() {\n\t// Ensure the browser provides the level of support needed\n\tif (!Object.keys) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nDocument.prototype._createDoc = function (options, callback) {\n\toptions = options || {};\n\tif (this.tableLayouts) {\n\t\toptions.tableLayouts = this.tableLayouts;\n\t}\n\n\tvar printer = new PdfPrinter(this.fonts);\n\t__webpack_require__(8).bindFS(this.vfs); // bind virtual file system to file system\n\n\tvar doc = printer.createPdfKitDocument(this.docDefinition, options);\n\tvar chunks = [];\n\tvar result;\n\n\tdoc.on('readable', function () {\n\t\tvar chunk;\n\t\twhile ((chunk = doc.read(9007199254740991)) !== null) {\n\t\t\tchunks.push(chunk);\n\t\t}\n\t});\n\tdoc.on('end', function () {\n\t\tresult = Buffer.concat(chunks);\n\t\tcallback(result, doc._pdfMakePages);\n\t});\n\tdoc.end();\n};\n\nDocument.prototype._getPages = function (options, cb) {\n\tif (!cb) {\n\t\tthrow '_getPages is an async method and needs a callback argument';\n\t}\n\tthis._createDoc(options, function (ignoreBuffer, pages) {\n\t\tcb(pages);\n\t});\n};\n\nDocument.prototype._bufferToBlob = function (buffer) {\n\tvar blob;\n\ttry {\n\t\tblob = new Blob([buffer], {type: 'application/pdf'});\n\t} catch (e) {\n\t\t// Old browser which can't handle it without making it an byte array (ie10)\n\t\tif (e.name === 'InvalidStateError') {\n\t\t\tvar byteArray = new Uint8Array(buffer);\n\t\t\tblob = new Blob([byteArray.buffer], {type: 'application/pdf'});\n\t\t}\n\t}\n\n\tif (!blob) {\n\t\tthrow 'Could not generate blob';\n\t}\n\n\treturn blob;\n};\n\nDocument.prototype._openWindow = function () {\n\t// we have to open the window immediately and store the reference\n\t// otherwise popup blockers will stop us\n\tvar win = window.open('', '_blank');\n\tif (win === null) {\n\t\tthrow 'Open PDF in new window blocked by browser';\n\t}\n\n\treturn win;\n};\n\nDocument.prototype._openPdf = function (options, win) {\n\tif (!win) {\n\t\twin = this._openWindow();\n\t}\n\ttry {\n\t\tthis.getBlob(function (result) {\n\t\t\tvar urlCreator = window.URL || window.webkitURL;\n\t\t\tvar pdfUrl = urlCreator.createObjectURL(result);\n\t\t\twin.location.href = pdfUrl;\n\t\t}, options);\n\t} catch (e) {\n\t\twin.close();\n\t\tthrow e;\n\t}\n};\n\nDocument.prototype.open = function (options, win) {\n\toptions = options || {};\n\toptions.autoPrint = false;\n\twin = win || null;\n\n\tthis._openPdf(options, win);\n};\n\n\nDocument.prototype.print = function (options, win) {\n\toptions = options || {};\n\toptions.autoPrint = true;\n\twin = win || null;\n\n\tthis._openPdf(options, win);\n};\n\nDocument.prototype.download = function (defaultFileName, cb, options) {\n\tif (isFunction(defaultFileName)) {\n\t\tcb = defaultFileName;\n\t\tdefaultFileName = null;\n\t}\n\n\tdefaultFileName = defaultFileName || 'file.pdf';\n\tthis.getBlob(function (result) {\n\t\tsaveAs(result, defaultFileName);\n\n\t\tif (isFunction(cb)) {\n\t\t\tcb();\n\t\t}\n\t}, options);\n};\n\nDocument.prototype.getBase64 = function (cb, options) {\n\tif (!cb) {\n\t\tthrow 'getBase64 is an async method and needs a callback argument';\n\t}\n\tthis.getBuffer(function (buffer) {\n\t\tcb(buffer.toString('base64'));\n\t}, options);\n};\n\nDocument.prototype.getDataUrl = function (cb, options) {\n\tif (!cb) {\n\t\tthrow 'getDataUrl is an async method and needs a callback argument';\n\t}\n\tthis.getBuffer(function (buffer) {\n\t\tcb('data:application/pdf;base64,' + buffer.toString('base64'));\n\t}, options);\n};\n\nDocument.prototype.getBlob = function (cb, options) {\n\tif (!cb) {\n\t\tthrow 'getBlob is an async method and needs a callback argument';\n\t}\n\tvar that = this;\n\tthis.getBuffer(function (result) {\n\t\tvar blob = that._bufferToBlob(result);\n\t\tcb(blob);\n\t}, options);\n};\n\nDocument.prototype.getBuffer = function (cb, options) {\n\tif (!cb) {\n\t\tthrow 'getBuffer is an async method and needs a callback argument';\n\t}\n\tthis._createDoc(options, function (buffer) {\n\t\tcb(buffer);\n\t});\n};\n\nmodule.exports = {\n\tcreatePdf: function (docDefinition) {\n\t\tif (!canCreatePdf()) {\n\t\t\tthrow 'Your browser does not provide the level of support needed';\n\t\t}\n\t\treturn new Document(docDefinition, global.pdfMake.tableLayouts, global.pdfMake.fonts, global.pdfMake.vfs);\n\t}\n};\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer, __webpack_require__(7)))\n\n/***/ }),\n/* 124 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.byteLength = byteLength\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nvar code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\nfor (var i = 0, len = code.length; i < len; ++i) {\n  lookup[i] = code[i]\n  revLookup[code.charCodeAt(i)] = i\n}\n\n// Support decoding URL-safe base64 strings, as Node.js does.\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\nrevLookup['-'.charCodeAt(0)] = 62\nrevLookup['_'.charCodeAt(0)] = 63\n\nfunction placeHoldersCount (b64) {\n  var len = b64.length\n  if (len % 4 > 0) {\n    throw new Error('Invalid string. Length must be a multiple of 4')\n  }\n\n  // the number of equal signs (place holders)\n  // if there are two placeholders, than the two characters before it\n  // represent one byte\n  // if there is only one, then the three characters before it represent 2 bytes\n  // this is just a cheap hack to not do indexOf twice\n  return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0\n}\n\nfunction byteLength (b64) {\n  // base64 is 4/3 + up to two characters of the original data\n  return (b64.length * 3 / 4) - placeHoldersCount(b64)\n}\n\nfunction toByteArray (b64) {\n  var i, l, tmp, placeHolders, arr\n  var len = b64.length\n  placeHolders = placeHoldersCount(b64)\n\n  arr = new Arr((len * 3 / 4) - placeHolders)\n\n  // if there are placeholders, only get up to the last complete 4 chars\n  l = placeHolders > 0 ? len - 4 : len\n\n  var L = 0\n\n  for (i = 0; i < l; i += 4) {\n    tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]\n    arr[L++] = (tmp >> 16) & 0xFF\n    arr[L++] = (tmp >> 8) & 0xFF\n    arr[L++] = tmp & 0xFF\n  }\n\n  if (placeHolders === 2) {\n    tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)\n    arr[L++] = tmp & 0xFF\n  } else if (placeHolders === 1) {\n    tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)\n    arr[L++] = (tmp >> 8) & 0xFF\n    arr[L++] = tmp & 0xFF\n  }\n\n  return arr\n}\n\nfunction tripletToBase64 (num) {\n  return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n  var tmp\n  var output = []\n  for (var i = start; i < end; i += 3) {\n    tmp = ((uint8[i] << 16) & 0xFF0000) + ((uint8[i + 1] << 8) & 0xFF00) + (uint8[i + 2] & 0xFF)\n    output.push(tripletToBase64(tmp))\n  }\n  return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n  var tmp\n  var len = uint8.length\n  var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n  var output = ''\n  var parts = []\n  var maxChunkLength = 16383 // must be multiple of 3\n\n  // go through the array every three bytes, we'll deal with trailing stuff later\n  for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n    parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n  }\n\n  // pad the end with zeros, but make sure to not forget the extra bytes\n  if (extraBytes === 1) {\n    tmp = uint8[len - 1]\n    output += lookup[tmp >> 2]\n    output += lookup[(tmp << 4) & 0x3F]\n    output += '=='\n  } else if (extraBytes === 2) {\n    tmp = (uint8[len - 2] << 8) + (uint8[len - 1])\n    output += lookup[tmp >> 10]\n    output += lookup[(tmp >> 4) & 0x3F]\n    output += lookup[(tmp << 2) & 0x3F]\n    output += '='\n  }\n\n  parts.push(output)\n\n  return parts.join('')\n}\n\n\n/***/ }),\n/* 125 */\n/***/ (function(module, exports) {\n\nexports.read = function (buffer, offset, isLE, mLen, nBytes) {\n  var e, m\n  var eLen = nBytes * 8 - mLen - 1\n  var eMax = (1 << eLen) - 1\n  var eBias = eMax >> 1\n  var nBits = -7\n  var i = isLE ? (nBytes - 1) : 0\n  var d = isLE ? -1 : 1\n  var s = buffer[offset + i]\n\n  i += d\n\n  e = s & ((1 << (-nBits)) - 1)\n  s >>= (-nBits)\n  nBits += eLen\n  for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n  m = e & ((1 << (-nBits)) - 1)\n  e >>= (-nBits)\n  nBits += mLen\n  for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n  if (e === 0) {\n    e = 1 - eBias\n  } else if (e === eMax) {\n    return m ? NaN : ((s ? -1 : 1) * Infinity)\n  } else {\n    m = m + Math.pow(2, mLen)\n    e = e - eBias\n  }\n  return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n  var e, m, c\n  var eLen = nBytes * 8 - mLen - 1\n  var eMax = (1 << eLen) - 1\n  var eBias = eMax >> 1\n  var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n  var i = isLE ? 0 : (nBytes - 1)\n  var d = isLE ? 1 : -1\n  var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n  value = Math.abs(value)\n\n  if (isNaN(value) || value === Infinity) {\n    m = isNaN(value) ? 1 : 0\n    e = eMax\n  } else {\n    e = Math.floor(Math.log(value) / Math.LN2)\n    if (value * (c = Math.pow(2, -e)) < 1) {\n      e--\n      c *= 2\n    }\n    if (e + eBias >= 1) {\n      value += rt / c\n    } else {\n      value += rt * Math.pow(2, 1 - eBias)\n    }\n    if (value * c >= 2) {\n      e++\n      c /= 2\n    }\n\n    if (e + eBias >= eMax) {\n      m = 0\n      e = eMax\n    } else if (e + eBias >= 1) {\n      m = (value * c - 1) * Math.pow(2, mLen)\n      e = e + eBias\n    } else {\n      m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n      e = 0\n    }\n  }\n\n  for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n  e = (e << mLen) | m\n  eLen += mLen\n  for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n  buffer[offset + i - d] |= s * 128\n}\n\n\n/***/ }),\n/* 126 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/*eslint no-unused-vars: [\"error\", {\"args\": \"none\"}]*/\n\n\nvar FontProvider = __webpack_require__(127);\nvar LayoutBuilder = __webpack_require__(128);\nvar PdfKit = __webpack_require__(138);\nvar sizes = __webpack_require__(303);\nvar ImageMeasure = __webpack_require__(304);\nvar textDecorator = __webpack_require__(305);\nvar TextTools = __webpack_require__(42);\nvar isFunction = __webpack_require__(0).isFunction;\nvar isString = __webpack_require__(0).isString;\nvar isNumber = __webpack_require__(0).isNumber;\nvar isBoolean = __webpack_require__(0).isBoolean;\nvar isArray = __webpack_require__(0).isArray;\n\n////////////////////////////////////////\n// PdfPrinter\n\n/**\n * @class Creates an instance of a PdfPrinter which turns document definition into a pdf\n *\n * @param {Object} fontDescriptors font definition dictionary\n *\n * @example\n * var fontDescriptors = {\n *\tRoboto: {\n *\t\tnormal: 'fonts/Roboto-Regular.ttf',\n *\t\tbold: 'fonts/Roboto-Medium.ttf',\n *\t\titalics: 'fonts/Roboto-Italic.ttf',\n *\t\tbolditalics: 'fonts/Roboto-MediumItalic.ttf'\n *\t}\n * };\n *\n * var printer = new PdfPrinter(fontDescriptors);\n */\nfunction PdfPrinter(fontDescriptors) {\n\tthis.fontDescriptors = fontDescriptors;\n}\n\n/**\n * Executes layout engine for the specified document and renders it into a pdfkit document\n * ready to be saved.\n *\n * @param {Object} docDefinition document definition\n * @param {Object} docDefinition.content an array describing the pdf structure (for more information take a look at the examples in the /examples folder)\n * @param {Object} [docDefinition.defaultStyle] default (implicit) style definition\n * @param {Object} [docDefinition.styles] dictionary defining all styles which can be used in the document\n * @param {Object} [docDefinition.pageSize] page size (pdfkit units, A4 dimensions by default)\n * @param {Number} docDefinition.pageSize.width width\n * @param {Number} docDefinition.pageSize.height height\n * @param {Object} [docDefinition.pageMargins] page margins (pdfkit units)\n * @param {Number} docDefinition.maxPagesNumber maximum number of pages to render\n *\n * @example\n *\n * var docDefinition = {\n * \tinfo: {\n *\t\ttitle: 'awesome Document',\n *\t\tauthor: 'john doe',\n *\t\tsubject: 'subject of document',\n *\t\tkeywords: 'keywords for document',\n * \t},\n *\tcontent: [\n *\t\t'First paragraph',\n *\t\t'Second paragraph, this time a little bit longer',\n *\t\t{ text: 'Third paragraph, slightly bigger font size', fontSize: 20 },\n *\t\t{ text: 'Another paragraph using a named style', style: 'header' },\n *\t\t{ text: ['playing with ', 'inlines' ] },\n *\t\t{ text: ['and ', { text: 'restyling ', bold: true }, 'them'] },\n *\t],\n *\tstyles: {\n *\t\theader: { fontSize: 30, bold: true }\n *\t}\n * }\n *\n * var pdfKitDoc = printer.createPdfKitDocument(docDefinition);\n *\n * pdfKitDoc.pipe(fs.createWriteStream('sample.pdf'));\n * pdfKitDoc.end();\n *\n * @return {Object} a pdfKit document object which can be saved or encode to data-url\n */\nPdfPrinter.prototype.createPdfKitDocument = function (docDefinition, options) {\n\toptions = options || {};\n\n\tvar pageSize = fixPageSize(docDefinition.pageSize, docDefinition.pageOrientation);\n\tvar compressPdf = isBoolean(docDefinition.compress) ? docDefinition.compress : true;\n\n\tthis.pdfKitDoc = new PdfKit({size: [pageSize.width, pageSize.height], autoFirstPage: false, compress: compressPdf});\n\tsetMetadata(docDefinition, this.pdfKitDoc);\n\n\tthis.fontProvider = new FontProvider(this.fontDescriptors, this.pdfKitDoc);\n\n\tdocDefinition.images = docDefinition.images || {};\n\n\tvar builder = new LayoutBuilder(pageSize, fixPageMargins(docDefinition.pageMargins || 40), new ImageMeasure(this.pdfKitDoc, docDefinition.images));\n\n\tregisterDefaultTableLayouts(builder);\n\tif (options.tableLayouts) {\n\t\tbuilder.registerTableLayouts(options.tableLayouts);\n\t}\n\n\tvar pages = builder.layoutDocument(docDefinition.content, this.fontProvider, docDefinition.styles || {}, docDefinition.defaultStyle || {fontSize: 12, font: 'Roboto'}, docDefinition.background, docDefinition.header, docDefinition.footer, docDefinition.images, docDefinition.watermark, docDefinition.pageBreakBefore);\n\tvar maxNumberPages = docDefinition.maxPagesNumber || -1;\n\tif (isNumber(maxNumberPages) && maxNumberPages > -1) {\n\t\tpages = pages.slice(0, maxNumberPages);\n\t}\n\n\t// if pageSize.height is set to Infinity, calculate the actual height of the page that\n\t// was laid out using the height of each of the items in the page.\n\tif (pageSize.height === Infinity) {\n\t\tvar pageHeight = calculatePageHeight(pages, docDefinition.pageMargins);\n\t\tthis.pdfKitDoc.options.size = [pageSize.width, pageHeight];\n\t}\n\n\trenderPages(pages, this.fontProvider, this.pdfKitDoc, options.progressCallback);\n\n\tif (options.autoPrint) {\n\t\tvar printActionRef = this.pdfKitDoc.ref({\n\t\t\tType: 'Action',\n\t\t\tS: 'Named',\n\t\t\tN: 'Print'\n\t\t});\n\t\tthis.pdfKitDoc._root.data.OpenAction = printActionRef;\n\t\tprintActionRef.end();\n\t}\n\treturn this.pdfKitDoc;\n};\n\nfunction setMetadata(docDefinition, pdfKitDoc) {\n\t// PDF standard has these properties reserved: Title, Author, Subject, Keywords,\n\t// Creator, Producer, CreationDate, ModDate, Trapped.\n\t// To keep the pdfmake api consistent, the info field are defined lowercase.\n\t// Custom properties don't contain a space.\n\tfunction standardizePropertyKey(key) {\n\t\tvar standardProperties = ['Title', 'Author', 'Subject', 'Keywords',\n\t\t\t'Creator', 'Producer', 'CreationDate', 'ModDate', 'Trapped'];\n\t\tvar standardizedKey = key.charAt(0).toUpperCase() + key.slice(1);\n\t\tif (standardProperties.indexOf(standardizedKey) !== -1) {\n\t\t\treturn standardizedKey;\n\t\t}\n\n\t\treturn key.replace(/\\s+/g, '');\n\t}\n\n\tpdfKitDoc.info.Producer = 'pdfmake';\n\tpdfKitDoc.info.Creator = 'pdfmake';\n\n\tif (docDefinition.info) {\n\t\tfor (var key in docDefinition.info) {\n\t\t\tvar value = docDefinition.info[key];\n\t\t\tif (value) {\n\t\t\t\tkey = standardizePropertyKey(key);\n\t\t\t\tpdfKitDoc.info[key] = value;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction calculatePageHeight(pages, margins) {\n\tfunction getItemHeight(item) {\n\t\tif (isFunction(item.item.getHeight)) {\n\t\t\treturn item.item.getHeight();\n\t\t} else if (item.item._height) {\n\t\t\treturn item.item._height;\n\t\t} else {\n\t\t\t// TODO: add support for next item types\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tvar fixedMargins = fixPageMargins(margins || 40);\n\tvar height = fixedMargins.top + fixedMargins.bottom;\n\tpages.forEach(function (page) {\n\t\tpage.items.forEach(function (item) {\n\t\t\theight += getItemHeight(item);\n\t\t});\n\t});\n\treturn height;\n}\n\nfunction fixPageSize(pageSize, pageOrientation) {\n\tfunction isNeedSwapPageSizes(pageOrientation) {\n\t\tif (isString(pageOrientation)) {\n\t\t\tpageOrientation = pageOrientation.toLowerCase();\n\t\t\treturn ((pageOrientation === 'portrait') && (size.width > size.height)) ||\n\t\t\t\t((pageOrientation === 'landscape') && (size.width < size.height));\n\t\t}\n\t\treturn false;\n\t}\n\n\t// if pageSize.height is set to auto, set the height to infinity so there are no page breaks.\n\tif (pageSize && pageSize.height === 'auto') {\n\t\tpageSize.height = Infinity;\n\t}\n\n\tvar size = pageSize2widthAndHeight(pageSize || 'A4');\n\tif (isNeedSwapPageSizes(pageOrientation)) { // swap page sizes\n\t\tsize = {width: size.height, height: size.width};\n\t}\n\tsize.orientation = size.width > size.height ? 'landscape' : 'portrait';\n\treturn size;\n}\n\nfunction fixPageMargins(margin) {\n\tif (!margin) {\n\t\treturn null;\n\t}\n\n\tif (isNumber(margin)) {\n\t\tmargin = {left: margin, right: margin, top: margin, bottom: margin};\n\t} else if (isArray(margin)) {\n\t\tif (margin.length === 2) {\n\t\t\tmargin = {left: margin[0], top: margin[1], right: margin[0], bottom: margin[1]};\n\t\t} else if (margin.length === 4) {\n\t\t\tmargin = {left: margin[0], top: margin[1], right: margin[2], bottom: margin[3]};\n\t\t} else {\n\t\t\tthrow 'Invalid pageMargins definition';\n\t\t}\n\t}\n\n\treturn margin;\n}\n\nfunction registerDefaultTableLayouts(layoutBuilder) {\n\tlayoutBuilder.registerTableLayouts({\n\t\tnoBorders: {\n\t\t\thLineWidth: function (i) {\n\t\t\t\treturn 0;\n\t\t\t},\n\t\t\tvLineWidth: function (i) {\n\t\t\t\treturn 0;\n\t\t\t},\n\t\t\tpaddingLeft: function (i) {\n\t\t\t\treturn i && 4 || 0;\n\t\t\t},\n\t\t\tpaddingRight: function (i, node) {\n\t\t\t\treturn (i < node.table.widths.length - 1) ? 4 : 0;\n\t\t\t}\n\t\t},\n\t\theaderLineOnly: {\n\t\t\thLineWidth: function (i, node) {\n\t\t\t\tif (i === 0 || i === node.table.body.length) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\treturn (i === node.table.headerRows) ? 2 : 0;\n\t\t\t},\n\t\t\tvLineWidth: function (i) {\n\t\t\t\treturn 0;\n\t\t\t},\n\t\t\tpaddingLeft: function (i) {\n\t\t\t\treturn i === 0 ? 0 : 8;\n\t\t\t},\n\t\t\tpaddingRight: function (i, node) {\n\t\t\t\treturn (i === node.table.widths.length - 1) ? 0 : 8;\n\t\t\t}\n\t\t},\n\t\tlightHorizontalLines: {\n\t\t\thLineWidth: function (i, node) {\n\t\t\t\tif (i === 0 || i === node.table.body.length) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\treturn (i === node.table.headerRows) ? 2 : 1;\n\t\t\t},\n\t\t\tvLineWidth: function (i) {\n\t\t\t\treturn 0;\n\t\t\t},\n\t\t\thLineColor: function (i) {\n\t\t\t\treturn i === 1 ? 'black' : '#aaa';\n\t\t\t},\n\t\t\tpaddingLeft: function (i) {\n\t\t\t\treturn i === 0 ? 0 : 8;\n\t\t\t},\n\t\t\tpaddingRight: function (i, node) {\n\t\t\t\treturn (i === node.table.widths.length - 1) ? 0 : 8;\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction pageSize2widthAndHeight(pageSize) {\n\tif (isString(pageSize)) {\n\t\tvar size = sizes[pageSize.toUpperCase()];\n\t\tif (!size) {\n\t\t\tthrow 'Page size ' + pageSize + ' not recognized';\n\t\t}\n\t\treturn {width: size[0], height: size[1]};\n\t}\n\n\treturn pageSize;\n}\n\nfunction updatePageOrientationInOptions(currentPage, pdfKitDoc) {\n\tvar previousPageOrientation = pdfKitDoc.options.size[0] > pdfKitDoc.options.size[1] ? 'landscape' : 'portrait';\n\n\tif (currentPage.pageSize.orientation !== previousPageOrientation) {\n\t\tvar width = pdfKitDoc.options.size[0];\n\t\tvar height = pdfKitDoc.options.size[1];\n\t\tpdfKitDoc.options.size = [height, width];\n\t}\n}\n\nfunction renderPages(pages, fontProvider, pdfKitDoc, progressCallback) {\n\tpdfKitDoc._pdfMakePages = pages;\n\tpdfKitDoc.addPage();\n\n\tvar totalItems = 0;\n\tif (progressCallback) {\n\t\tpages.forEach(function (page) {\n\t\t\ttotalItems += page.items.length;\n\t\t});\n\t}\n\n\tvar renderedItems = 0;\n\tprogressCallback = progressCallback || function () {};\n\n\tfor (var i = 0; i < pages.length; i++) {\n\t\tif (i > 0) {\n\t\t\tupdatePageOrientationInOptions(pages[i], pdfKitDoc);\n\t\t\tpdfKitDoc.addPage(pdfKitDoc.options);\n\t\t}\n\n\t\tvar page = pages[i];\n\t\tfor (var ii = 0, il = page.items.length; ii < il; ii++) {\n\t\t\tvar item = page.items[ii];\n\t\t\tswitch (item.type) {\n\t\t\t\tcase 'vector':\n\t\t\t\t\trenderVector(item.item, pdfKitDoc);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'line':\n\t\t\t\t\trenderLine(item.item, item.item.x, item.item.y, pdfKitDoc);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'image':\n\t\t\t\t\trenderImage(item.item, item.item.x, item.item.y, pdfKitDoc);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'beginClip':\n\t\t\t\t\tbeginClip(item.item, pdfKitDoc);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'endClip':\n\t\t\t\t\tendClip(pdfKitDoc);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\trenderedItems++;\n\t\t\tprogressCallback(renderedItems / totalItems);\n\t\t}\n\t\tif (page.watermark) {\n\t\t\trenderWatermark(page, pdfKitDoc);\n\t\t}\n\t}\n}\n\nfunction renderLine(line, x, y, pdfKitDoc) {\n\tif (line._pageNodeRef) {\n\t\tvar newWidth;\n\t\tvar diffWidth;\n\t\tvar textTools = new TextTools(null);\n\t\tvar pageNumber = line._pageNodeRef.positions[0].pageNumber.toString();\n\n\t\tline.inlines[0].text = pageNumber;\n\t\tline.inlines[0].linkToPage = pageNumber;\n\t\tnewWidth = textTools.widthOfString(line.inlines[0].text, line.inlines[0].font, line.inlines[0].fontSize, line.inlines[0].characterSpacing, line.inlines[0].fontFeatures);\n\t\tdiffWidth = line.inlines[0].width - newWidth;\n\t\tline.inlines[0].width = newWidth;\n\n\t\tswitch (line.inlines[0].alignment) {\n\t\t\tcase 'right':\n\t\t\t\tline.inlines[0].x += diffWidth;\n\t\t\t\tbreak;\n\t\t\tcase 'center':\n\t\t\t\tline.inlines[0].x += diffWidth / 2;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tx = x || 0;\n\ty = y || 0;\n\n\tvar lineHeight = line.getHeight();\n\tvar ascenderHeight = line.getAscenderHeight();\n\tvar descent = lineHeight - ascenderHeight;\n\n\ttextDecorator.drawBackground(line, x, y, pdfKitDoc);\n\n\t//TODO: line.optimizeInlines();\n\tfor (var i = 0, l = line.inlines.length; i < l; i++) {\n\t\tvar inline = line.inlines[i];\n\t\tvar shiftToBaseline = lineHeight - ((inline.font.ascender / 1000) * inline.fontSize) - descent;\n\t\tvar options = {\n\t\t\tlineBreak: false,\n\t\t\ttextWidth: inline.width,\n\t\t\tcharacterSpacing: inline.characterSpacing,\n\t\t\twordCount: 1,\n\t\t\tlink: inline.link\n\t\t};\n\n\t\tif (inline.fontFeatures) {\n\t\t\toptions.features = inline.fontFeatures;\n\t\t}\n\n\t\tpdfKitDoc.fill(inline.color || 'black');\n\n\t\tpdfKitDoc._font = inline.font;\n\t\tpdfKitDoc.fontSize(inline.fontSize);\n\t\tpdfKitDoc.text(inline.text, x + inline.x, y + shiftToBaseline, options);\n\n\t\tif (inline.linkToPage) {\n\t\t\tvar _ref = pdfKitDoc.ref({Type: 'Action', S: 'GoTo', D: [inline.linkToPage, 0, 0]}).end();\n\t\t\tpdfKitDoc.annotate(x + inline.x, y + shiftToBaseline, inline.width, inline.height, {Subtype: 'Link', Dest: [inline.linkToPage - 1, 'XYZ', null, null, null]});\n\t\t}\n\n\t}\n\n\ttextDecorator.drawDecorations(line, x, y, pdfKitDoc);\n}\n\nfunction renderWatermark(page, pdfKitDoc) {\n\tvar watermark = page.watermark;\n\n\tpdfKitDoc.fill(watermark.color);\n\tpdfKitDoc.opacity(watermark.opacity);\n\n\tpdfKitDoc.save();\n\n\tvar angle = Math.atan2(pdfKitDoc.page.height, pdfKitDoc.page.width) * -180 / Math.PI;\n\tpdfKitDoc.rotate(angle, {origin: [pdfKitDoc.page.width / 2, pdfKitDoc.page.height / 2]});\n\n\tvar x = pdfKitDoc.page.width / 2 - watermark.size.size.width / 2;\n\tvar y = pdfKitDoc.page.height / 2 - watermark.size.size.height / 4;\n\n\tpdfKitDoc._font = watermark.font;\n\tpdfKitDoc.fontSize(watermark.size.fontSize);\n\tpdfKitDoc.text(watermark.text, x, y, {lineBreak: false});\n\n\tpdfKitDoc.restore();\n}\n\nfunction renderVector(vector, pdfKitDoc) {\n\t//TODO: pdf optimization (there's no need to write all properties everytime)\n\tpdfKitDoc.lineWidth(vector.lineWidth || 1);\n\tif (vector.dash) {\n\t\tpdfKitDoc.dash(vector.dash.length, {space: vector.dash.space || vector.dash.length, phase: vector.dash.phase || 0});\n\t} else {\n\t\tpdfKitDoc.undash();\n\t}\n\tpdfKitDoc.lineJoin(vector.lineJoin || 'miter');\n\tpdfKitDoc.lineCap(vector.lineCap || 'butt');\n\n\t//TODO: clipping\n\n\tswitch (vector.type) {\n\t\tcase 'ellipse':\n\t\t\tpdfKitDoc.ellipse(vector.x, vector.y, vector.r1, vector.r2);\n\t\t\tbreak;\n\t\tcase 'rect':\n\t\t\tif (vector.r) {\n\t\t\t\tpdfKitDoc.roundedRect(vector.x, vector.y, vector.w, vector.h, vector.r);\n\t\t\t} else {\n\t\t\t\tpdfKitDoc.rect(vector.x, vector.y, vector.w, vector.h);\n\t\t\t}\n\n\t\t\tif (vector.linearGradient) {\n\t\t\t\tvar gradient = pdfKitDoc.linearGradient(vector.x, vector.y, vector.x + vector.w, vector.y);\n\t\t\t\tvar step = 1 / (vector.linearGradient.length - 1);\n\n\t\t\t\tfor (var i = 0; i < vector.linearGradient.length; i++) {\n\t\t\t\t\tgradient.stop(i * step, vector.linearGradient[i]);\n\t\t\t\t}\n\n\t\t\t\tvector.color = gradient;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'line':\n\t\t\tpdfKitDoc.moveTo(vector.x1, vector.y1);\n\t\t\tpdfKitDoc.lineTo(vector.x2, vector.y2);\n\t\t\tbreak;\n\t\tcase 'polyline':\n\t\t\tif (vector.points.length === 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tpdfKitDoc.moveTo(vector.points[0].x, vector.points[0].y);\n\t\t\tfor (var i = 1, l = vector.points.length; i < l; i++) {\n\t\t\t\tpdfKitDoc.lineTo(vector.points[i].x, vector.points[i].y);\n\t\t\t}\n\n\t\t\tif (vector.points.length > 1) {\n\t\t\t\tvar p1 = vector.points[0];\n\t\t\t\tvar pn = vector.points[vector.points.length - 1];\n\n\t\t\t\tif (vector.closePath || p1.x === pn.x && p1.y === pn.y) {\n\t\t\t\t\tpdfKitDoc.closePath();\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'path':\n\t\t\tpdfKitDoc.path(vector.d);\n\t\t\tbreak;\n\t}\n\n\tif (vector.color && vector.lineColor) {\n\t\tpdfKitDoc.fillColor(vector.color, vector.fillOpacity || 1);\n\t\tpdfKitDoc.strokeColor(vector.lineColor, vector.strokeOpacity || 1);\n\t\tpdfKitDoc.fillAndStroke();\n\t} else if (vector.color) {\n\t\tpdfKitDoc.fillColor(vector.color, vector.fillOpacity || 1);\n\t\tpdfKitDoc.fill();\n\t} else {\n\t\tpdfKitDoc.strokeColor(vector.lineColor || 'black', vector.strokeOpacity || 1);\n\t\tpdfKitDoc.stroke();\n\t}\n}\n\nfunction renderImage(image, x, y, pdfKitDoc) {\n\tpdfKitDoc.image(image.image, image.x, image.y, {width: image._width, height: image._height});\n\tif (image.link) {\n\t\tpdfKitDoc.link(image.x, image.y, image._width, image._height, image.link);\n\t}\n}\n\nfunction beginClip(rect, pdfKitDoc) {\n\tpdfKitDoc.save();\n\tpdfKitDoc.addContent('' + rect.x + ' ' + rect.y + ' ' + rect.width + ' ' + rect.height + ' re');\n\tpdfKitDoc.clip();\n}\n\nfunction endClip(pdfKitDoc) {\n\tpdfKitDoc.restore();\n}\n\nmodule.exports = PdfPrinter;\n\n\n/***/ }),\n/* 127 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar isArray = __webpack_require__(0).isArray;\n\nfunction typeName(bold, italics) {\n\tvar type = 'normal';\n\tif (bold && italics) {\n\t\ttype = 'bolditalics';\n\t} else if (bold) {\n\t\ttype = 'bold';\n\t} else if (italics) {\n\t\ttype = 'italics';\n\t}\n\treturn type;\n}\n\nfunction FontProvider(fontDescriptors, pdfKitDoc) {\n\tthis.fonts = {};\n\tthis.pdfKitDoc = pdfKitDoc;\n\tthis.fontCache = {};\n\n\tfor (var font in fontDescriptors) {\n\t\tif (fontDescriptors.hasOwnProperty(font)) {\n\t\t\tvar fontDef = fontDescriptors[font];\n\n\t\t\tthis.fonts[font] = {\n\t\t\t\tnormal: fontDef.normal,\n\t\t\t\tbold: fontDef.bold,\n\t\t\t\titalics: fontDef.italics,\n\t\t\t\tbolditalics: fontDef.bolditalics\n\t\t\t};\n\t\t}\n\t}\n}\n\nFontProvider.prototype.provideFont = function (familyName, bold, italics) {\n\tvar type = typeName(bold, italics);\n\tif (!this.fonts[familyName] || !this.fonts[familyName][type]) {\n\t\tthrow new Error('Font \\'' + familyName + '\\' in style \\'' + type + '\\' is not defined in the font section of the document definition.');\n\t}\n\n\tthis.fontCache[familyName] = this.fontCache[familyName] || {};\n\n\tif (!this.fontCache[familyName][type]) {\n\t\tvar def = this.fonts[familyName][type];\n\t\tif (!isArray(def)) {\n\t\t\tdef = [def];\n\t\t}\n\t\tthis.fontCache[familyName][type] = this.pdfKitDoc.font.apply(this.pdfKitDoc, def)._font;\n\t}\n\n\treturn this.fontCache[familyName][type];\n};\n\nmodule.exports = FontProvider;\n\n\n/***/ }),\n/* 128 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar TraversalTracker = __webpack_require__(77);\nvar DocPreprocessor = __webpack_require__(129);\nvar DocMeasure = __webpack_require__(130);\nvar DocumentContext = __webpack_require__(81);\nvar PageElementWriter = __webpack_require__(135);\nvar ColumnCalculator = __webpack_require__(44);\nvar TableProcessor = __webpack_require__(137);\nvar Line = __webpack_require__(82);\nvar isString = __webpack_require__(0).isString;\nvar isArray = __webpack_require__(0).isArray;\nvar pack = __webpack_require__(0).pack;\nvar offsetVector = __webpack_require__(0).offsetVector;\nvar fontStringify = __webpack_require__(0).fontStringify;\nvar isFunction = __webpack_require__(0).isFunction;\nvar TextTools = __webpack_require__(42);\nvar StyleContextStack = __webpack_require__(80);\n\nfunction addAll(target, otherArray) {\n\totherArray.forEach(function (item) {\n\t\ttarget.push(item);\n\t});\n}\n\n/**\n * Creates an instance of LayoutBuilder - layout engine which turns document-definition-object\n * into a set of pages, lines, inlines and vectors ready to be rendered into a PDF\n *\n * @param {Object} pageSize - an object defining page width and height\n * @param {Object} pageMargins - an object defining top, left, right and bottom margins\n */\nfunction LayoutBuilder(pageSize, pageMargins, imageMeasure) {\n\tthis.pageSize = pageSize;\n\tthis.pageMargins = pageMargins;\n\tthis.tracker = new TraversalTracker();\n\tthis.imageMeasure = imageMeasure;\n\tthis.tableLayouts = {};\n}\n\nLayoutBuilder.prototype.registerTableLayouts = function (tableLayouts) {\n\tthis.tableLayouts = pack(this.tableLayouts, tableLayouts);\n};\n\n/**\n * Executes layout engine on document-definition-object and creates an array of pages\n * containing positioned Blocks, Lines and inlines\n *\n * @param {Object} docStructure document-definition-object\n * @param {Object} fontProvider font provider\n * @param {Object} styleDictionary dictionary with style definitions\n * @param {Object} defaultStyle default style definition\n * @return {Array} an array of pages\n */\nLayoutBuilder.prototype.layoutDocument = function (docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark, pageBreakBeforeFct) {\n\n\tfunction addPageBreaksIfNecessary(linearNodeList, pages) {\n\n\t\tif (!isFunction(pageBreakBeforeFct)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlinearNodeList = linearNodeList.filter(function (node) {\n\t\t\treturn node.positions.length > 0;\n\t\t});\n\n\t\tlinearNodeList.forEach(function (node) {\n\t\t\tvar nodeInfo = {};\n\t\t\t[\n\t\t\t\t'id', 'text', 'ul', 'ol', 'table', 'image', 'qr', 'canvas', 'columns',\n\t\t\t\t'headlineLevel', 'style', 'pageBreak', 'pageOrientation',\n\t\t\t\t'width', 'height'\n\t\t\t].forEach(function (key) {\n\t\t\t\tif (node[key] !== undefined) {\n\t\t\t\t\tnodeInfo[key] = node[key];\n\t\t\t\t}\n\t\t\t});\n\t\t\tnodeInfo.startPosition = node.positions[0];\n\t\t\tnodeInfo.pageNumbers = node.positions.map(function (node) {\n\t\t\t\treturn node.pageNumber;\n\t\t\t}).filter(function (element, position, array) {\n\t\t\t\treturn array.indexOf(element) === position;\n\t\t\t});\n\t\t\tnodeInfo.pages = pages.length;\n\t\t\tnodeInfo.stack = isArray(node.stack);\n\n\t\t\tnode.nodeInfo = nodeInfo;\n\t\t});\n\n\t\treturn linearNodeList.some(function (node, index, followingNodeList) {\n\t\t\tif (node.pageBreak !== 'before' && !node.pageBreakCalculated) {\n\t\t\t\tnode.pageBreakCalculated = true;\n\t\t\t\tvar pageNumber = node.nodeInfo.pageNumbers[0];\n\n\t\t\t\tvar followingNodesOnPage = followingNodeList.slice(index + 1).filter(function (node0) {\n\t\t\t\t\treturn node0.nodeInfo.pageNumbers.indexOf(pageNumber) > -1;\n\t\t\t\t});\n\n\t\t\t\tvar nodesOnNextPage = followingNodeList.slice(index + 1).filter(function (node0) {\n\t\t\t\t\treturn node0.nodeInfo.pageNumbers.indexOf(pageNumber + 1) > -1;\n\t\t\t\t});\n\n\t\t\t\tvar previousNodesOnPage = followingNodeList.slice(0, index).filter(function (node0) {\n\t\t\t\t\treturn node0.nodeInfo.pageNumbers.indexOf(pageNumber) > -1;\n\t\t\t\t});\n\n\t\t\t\tif (\n\t\t\t\t\tpageBreakBeforeFct(\n\t\t\t\t\t\tnode.nodeInfo,\n\t\t\t\t\t\tfollowingNodesOnPage.map(function (node) {\n\t\t\t\t\t\t\treturn node.nodeInfo;\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tnodesOnNextPage.map(function (node) {\n\t\t\t\t\t\t\treturn node.nodeInfo;\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tpreviousNodesOnPage.map(function (node) {\n\t\t\t\t\t\t\treturn node.nodeInfo;\n\t\t\t\t\t\t}))) {\n\t\t\t\t\tnode.pageBreak = 'before';\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tthis.docPreprocessor = new DocPreprocessor();\n\tthis.docMeasure = new DocMeasure(fontProvider, styleDictionary, defaultStyle, this.imageMeasure, this.tableLayouts, images);\n\n\n\tfunction resetXYs(result) {\n\t\tresult.linearNodeList.forEach(function (node) {\n\t\t\tnode.resetXY();\n\t\t});\n\t}\n\n\tvar result = this.tryLayoutDocument(docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark);\n\twhile (addPageBreaksIfNecessary(result.linearNodeList, result.pages)) {\n\t\tresetXYs(result);\n\t\tresult = this.tryLayoutDocument(docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark);\n\t}\n\n\treturn result.pages;\n};\n\nLayoutBuilder.prototype.tryLayoutDocument = function (docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark, pageBreakBeforeFct) {\n\n\tthis.linearNodeList = [];\n\tdocStructure = this.docPreprocessor.preprocessDocument(docStructure);\n\tdocStructure = this.docMeasure.measureDocument(docStructure);\n\n\tthis.writer = new PageElementWriter(\n\t\tnew DocumentContext(this.pageSize, this.pageMargins), this.tracker);\n\n\tvar _this = this;\n\tthis.writer.context().tracker.startTracking('pageAdded', function () {\n\t\t_this.addBackground(background);\n\t});\n\n\tthis.addBackground(background);\n\tthis.processNode(docStructure);\n\tthis.addHeadersAndFooters(header, footer);\n\tif (watermark != null) {\n\t\tthis.addWatermark(watermark, fontProvider, defaultStyle);\n\t}\n\n\treturn {pages: this.writer.context().pages, linearNodeList: this.linearNodeList};\n};\n\n\nLayoutBuilder.prototype.addBackground = function (background) {\n\tvar backgroundGetter = isFunction(background) ? background : function () {\n\t\treturn background;\n\t};\n\n\tvar pageBackground = backgroundGetter(this.writer.context().page + 1);\n\n\tif (pageBackground) {\n\t\tvar pageSize = this.writer.context().getCurrentPage().pageSize;\n\t\tthis.writer.beginUnbreakableBlock(pageSize.width, pageSize.height);\n\t\tpageBackground = this.docPreprocessor.preprocessDocument(pageBackground);\n\t\tthis.processNode(this.docMeasure.measureDocument(pageBackground));\n\t\tthis.writer.commitUnbreakableBlock(0, 0);\n\t\tthis.writer.context().hasBackground = true;\n\t}\n};\n\nLayoutBuilder.prototype.addStaticRepeatable = function (headerOrFooter, sizeFunction) {\n\tthis.addDynamicRepeatable(function () {\n\t\treturn JSON.parse(JSON.stringify(headerOrFooter)); // copy to new object\n\t}, sizeFunction);\n};\n\nLayoutBuilder.prototype.addDynamicRepeatable = function (nodeGetter, sizeFunction) {\n\tvar pages = this.writer.context().pages;\n\n\tfor (var pageIndex = 0, l = pages.length; pageIndex < l; pageIndex++) {\n\t\tthis.writer.context().page = pageIndex;\n\n\t\tvar node = nodeGetter(pageIndex + 1, l, this.writer.context().pages[pageIndex].pageSize);\n\n\t\tif (node) {\n\t\t\tvar sizes = sizeFunction(this.writer.context().getCurrentPage().pageSize, this.pageMargins);\n\t\t\tthis.writer.beginUnbreakableBlock(sizes.width, sizes.height);\n\t\t\tnode = this.docPreprocessor.preprocessDocument(node);\n\t\t\tthis.processNode(this.docMeasure.measureDocument(node));\n\t\t\tthis.writer.commitUnbreakableBlock(sizes.x, sizes.y);\n\t\t}\n\t}\n};\n\nLayoutBuilder.prototype.addHeadersAndFooters = function (header, footer) {\n\tvar headerSizeFct = function (pageSize, pageMargins) {\n\t\treturn {\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t\twidth: pageSize.width,\n\t\t\theight: pageMargins.top\n\t\t};\n\t};\n\n\tvar footerSizeFct = function (pageSize, pageMargins) {\n\t\treturn {\n\t\t\tx: 0,\n\t\t\ty: pageSize.height - pageMargins.bottom,\n\t\t\twidth: pageSize.width,\n\t\t\theight: pageMargins.bottom\n\t\t};\n\t};\n\n\tif (isFunction(header)) {\n\t\tthis.addDynamicRepeatable(header, headerSizeFct);\n\t} else if (header) {\n\t\tthis.addStaticRepeatable(header, headerSizeFct);\n\t}\n\n\tif (isFunction(footer)) {\n\t\tthis.addDynamicRepeatable(footer, footerSizeFct);\n\t} else if (footer) {\n\t\tthis.addStaticRepeatable(footer, footerSizeFct);\n\t}\n};\n\nLayoutBuilder.prototype.addWatermark = function (watermark, fontProvider, defaultStyle) {\n\tif (isString(watermark)) {\n\t\twatermark = {'text': watermark};\n\t}\n\n\tif (!watermark.text) { // empty watermark text\n\t\treturn;\n\t}\n\n\twatermark.font = watermark.font || defaultStyle.font || 'Roboto';\n\twatermark.color = watermark.color || 'black';\n\twatermark.opacity = watermark.opacity || 0.6;\n\twatermark.bold = watermark.bold || false;\n\twatermark.italics = watermark.italics || false;\n\n\tvar watermarkObject = {\n\t\ttext: watermark.text,\n\t\tfont: fontProvider.provideFont(watermark.font, watermark.bold, watermark.italics),\n\t\tsize: getSize(this.pageSize, watermark, fontProvider),\n\t\tcolor: watermark.color,\n\t\topacity: watermark.opacity\n\t};\n\n\tvar pages = this.writer.context().pages;\n\tfor (var i = 0, l = pages.length; i < l; i++) {\n\t\tpages[i].watermark = watermarkObject;\n\t}\n\n\tfunction getSize(pageSize, watermark, fontProvider) {\n\t\tvar width = pageSize.width;\n\t\tvar height = pageSize.height;\n\t\tvar targetWidth = Math.sqrt(width * width + height * height) * 0.8; /* page diagonal * sample factor */\n\t\tvar textTools = new TextTools(fontProvider);\n\t\tvar styleContextStack = new StyleContextStack(null, {font: watermark.font, bold: watermark.bold, italics: watermark.italics});\n\t\tvar size;\n\n\t\t/**\n\t\t * Binary search the best font size.\n\t\t * Initial bounds [0, 1000]\n\t\t * Break when range < 1\n\t\t */\n\t\tvar a = 0;\n\t\tvar b = 1000;\n\t\tvar c = (a + b) / 2;\n\t\twhile (Math.abs(a - b) > 1) {\n\t\t\tstyleContextStack.push({\n\t\t\t\tfontSize: c\n\t\t\t});\n\t\t\tsize = textTools.sizeOfString(watermark.text, styleContextStack);\n\t\t\tif (size.width > targetWidth) {\n\t\t\t\tb = c;\n\t\t\t\tc = (a + b) / 2;\n\t\t\t} else if (size.width < targetWidth) {\n\t\t\t\ta = c;\n\t\t\t\tc = (a + b) / 2;\n\t\t\t}\n\t\t\tstyleContextStack.pop();\n\t\t}\n\t\t/*\n\t\t End binary search\n\t\t */\n\t\treturn {size: size, fontSize: c};\n\t}\n};\n\nfunction decorateNode(node) {\n\tvar x = node.x, y = node.y;\n\tnode.positions = [];\n\n\tif (isArray(node.canvas)) {\n\t\tnode.canvas.forEach(function (vector) {\n\t\t\tvar x = vector.x, y = vector.y, x1 = vector.x1, y1 = vector.y1, x2 = vector.x2, y2 = vector.y2;\n\t\t\tvector.resetXY = function () {\n\t\t\t\tvector.x = x;\n\t\t\t\tvector.y = y;\n\t\t\t\tvector.x1 = x1;\n\t\t\t\tvector.y1 = y1;\n\t\t\t\tvector.x2 = x2;\n\t\t\t\tvector.y2 = y2;\n\t\t\t};\n\t\t});\n\t}\n\n\tnode.resetXY = function () {\n\t\tnode.x = x;\n\t\tnode.y = y;\n\t\tif (isArray(node.canvas)) {\n\t\t\tnode.canvas.forEach(function (vector) {\n\t\t\t\tvector.resetXY();\n\t\t\t});\n\t\t}\n\t};\n}\n\nLayoutBuilder.prototype.processNode = function (node) {\n\tvar self = this;\n\n\tthis.linearNodeList.push(node);\n\tdecorateNode(node);\n\n\tapplyMargins(function () {\n\t\tvar unbreakable = node.unbreakable;\n\t\tif (unbreakable) {\n\t\t\tself.writer.beginUnbreakableBlock();\n\t\t}\n\n\t\tvar absPosition = node.absolutePosition;\n\t\tif (absPosition) {\n\t\t\tself.writer.context().beginDetachedBlock();\n\t\t\tself.writer.context().moveTo(absPosition.x || 0, absPosition.y || 0);\n\t\t}\n\n\t\tvar relPosition = node.relativePosition;\n\t\tif (relPosition) {\n\t\t\tself.writer.context().beginDetachedBlock();\n\t\t\tself.writer.context().moveTo((relPosition.x || 0) + self.writer.context().x, (relPosition.y || 0) + self.writer.context().y);\n\t\t}\n\n\t\tif (node.stack) {\n\t\t\tself.processVerticalContainer(node);\n\t\t} else if (node.columns) {\n\t\t\tself.processColumns(node);\n\t\t} else if (node.ul) {\n\t\t\tself.processList(false, node);\n\t\t} else if (node.ol) {\n\t\t\tself.processList(true, node);\n\t\t} else if (node.table) {\n\t\t\tself.processTable(node);\n\t\t} else if (node.text !== undefined) {\n\t\t\tself.processLeaf(node);\n\t\t} else if (node.toc) {\n\t\t\tself.processToc(node);\n\t\t} else if (node.image) {\n\t\t\tself.processImage(node);\n\t\t} else if (node.canvas) {\n\t\t\tself.processCanvas(node);\n\t\t} else if (node.qr) {\n\t\t\tself.processQr(node);\n\t\t} else if (!node._span) {\n\t\t\tthrow 'Unrecognized document structure: ' + JSON.stringify(node, fontStringify);\n\t\t}\n\n\t\tif (absPosition || relPosition) {\n\t\t\tself.writer.context().endDetachedBlock();\n\t\t}\n\n\t\tif (unbreakable) {\n\t\t\tself.writer.commitUnbreakableBlock();\n\t\t}\n\t});\n\n\tfunction applyMargins(callback) {\n\t\tvar margin = node._margin;\n\n\t\tif (node.pageBreak === 'before') {\n\t\t\tself.writer.moveToNextPage(node.pageOrientation);\n\t\t}\n\n\t\tif (margin) {\n\t\t\tself.writer.context().moveDown(margin[1]);\n\t\t\tself.writer.context().addMargin(margin[0], margin[2]);\n\t\t}\n\n\t\tcallback();\n\n\t\tif (margin) {\n\t\t\tself.writer.context().addMargin(-margin[0], -margin[2]);\n\t\t\tself.writer.context().moveDown(margin[3]);\n\t\t}\n\n\t\tif (node.pageBreak === 'after') {\n\t\t\tself.writer.moveToNextPage(node.pageOrientation);\n\t\t}\n\t}\n};\n\n// vertical container\nLayoutBuilder.prototype.processVerticalContainer = function (node) {\n\tvar self = this;\n\tnode.stack.forEach(function (item) {\n\t\tself.processNode(item);\n\t\taddAll(node.positions, item.positions);\n\n\t\t//TODO: paragraph gap\n\t});\n};\n\n// columns\nLayoutBuilder.prototype.processColumns = function (columnNode) {\n\tvar columns = columnNode.columns;\n\tvar availableWidth = this.writer.context().availableWidth;\n\tvar gaps = gapArray(columnNode._gap);\n\n\tif (gaps) {\n\t\tavailableWidth -= (gaps.length - 1) * columnNode._gap;\n\t}\n\n\tColumnCalculator.buildColumnWidths(columns, availableWidth);\n\tvar result = this.processRow(columns, columns, gaps);\n\taddAll(columnNode.positions, result.positions);\n\n\n\tfunction gapArray(gap) {\n\t\tif (!gap) {\n\t\t\treturn null;\n\t\t}\n\n\t\tvar gaps = [];\n\t\tgaps.push(0);\n\n\t\tfor (var i = columns.length - 1; i > 0; i--) {\n\t\t\tgaps.push(gap);\n\t\t}\n\n\t\treturn gaps;\n\t}\n};\n\nLayoutBuilder.prototype.processRow = function (columns, widths, gaps, tableBody, tableRow, height) {\n\tvar self = this;\n\tvar pageBreaks = [], positions = [];\n\n\tthis.tracker.auto('pageChanged', storePageBreakData, function () {\n\t\twidths = widths || columns;\n\n\t\tself.writer.context().beginColumnGroup();\n\n\t\tfor (var i = 0, l = columns.length; i < l; i++) {\n\t\t\tvar column = columns[i];\n\t\t\tvar width = widths[i]._calcWidth;\n\t\t\tvar leftOffset = colLeftOffset(i);\n\n\t\t\tif (column.colSpan && column.colSpan > 1) {\n\t\t\t\tfor (var j = 1; j < column.colSpan; j++) {\n\t\t\t\t\twidth += widths[++i]._calcWidth + gaps[i];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tself.writer.context().beginColumn(width, leftOffset, getEndingCell(column, i));\n\t\t\tif (!column._span) {\n\t\t\t\tself.processNode(column);\n\t\t\t\taddAll(positions, column.positions);\n\t\t\t} else if (column._columnEndingContext) {\n\t\t\t\t// row-span ending\n\t\t\t\tself.writer.context().markEnding(column);\n\t\t\t}\n\t\t}\n\n\t\tself.writer.context().completeColumnGroup(height);\n\t});\n\n\treturn {pageBreaks: pageBreaks, positions: positions};\n\n\tfunction storePageBreakData(data) {\n\t\tvar pageDesc;\n\n\t\tfor (var i = 0, l = pageBreaks.length; i < l; i++) {\n\t\t\tvar desc = pageBreaks[i];\n\t\t\tif (desc.prevPage === data.prevPage) {\n\t\t\t\tpageDesc = desc;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!pageDesc) {\n\t\t\tpageDesc = data;\n\t\t\tpageBreaks.push(pageDesc);\n\t\t}\n\t\tpageDesc.prevY = Math.max(pageDesc.prevY, data.prevY);\n\t\tpageDesc.y = Math.min(pageDesc.y, data.y);\n\t}\n\n\tfunction colLeftOffset(i) {\n\t\tif (gaps && gaps.length > i) {\n\t\t\treturn gaps[i];\n\t\t}\n\t\treturn 0;\n\t}\n\n\tfunction getEndingCell(column, columnIndex) {\n\t\tif (column.rowSpan && column.rowSpan > 1) {\n\t\t\tvar endingRow = tableRow + column.rowSpan - 1;\n\t\t\tif (endingRow >= tableBody.length) {\n\t\t\t\tthrow 'Row span for column ' + columnIndex + ' (with indexes starting from 0) exceeded row count';\n\t\t\t}\n\t\t\treturn tableBody[endingRow][columnIndex];\n\t\t}\n\n\t\treturn null;\n\t}\n};\n\n// lists\nLayoutBuilder.prototype.processList = function (orderedList, node) {\n\tvar self = this,\n\t\titems = orderedList ? node.ol : node.ul,\n\t\tgapSize = node._gapSize;\n\n\tthis.writer.context().addMargin(gapSize.width);\n\n\tvar nextMarker;\n\tthis.tracker.auto('lineAdded', addMarkerToFirstLeaf, function () {\n\t\titems.forEach(function (item) {\n\t\t\tnextMarker = item.listMarker;\n\t\t\tself.processNode(item);\n\t\t\taddAll(node.positions, item.positions);\n\t\t});\n\t});\n\n\tthis.writer.context().addMargin(-gapSize.width);\n\n\tfunction addMarkerToFirstLeaf(line) {\n\t\t// I'm not very happy with the way list processing is implemented\n\t\t// (both code and algorithm should be rethinked)\n\t\tif (nextMarker) {\n\t\t\tvar marker = nextMarker;\n\t\t\tnextMarker = null;\n\n\t\t\tif (marker.canvas) {\n\t\t\t\tvar vector = marker.canvas[0];\n\n\t\t\t\toffsetVector(vector, -marker._minWidth, 0);\n\t\t\t\tself.writer.addVector(vector);\n\t\t\t} else if (marker._inlines) {\n\t\t\t\tvar markerLine = new Line(self.pageSize.width);\n\t\t\t\tmarkerLine.addInline(marker._inlines[0]);\n\t\t\t\tmarkerLine.x = -marker._minWidth;\n\t\t\t\tmarkerLine.y = line.getAscenderHeight() - markerLine.getAscenderHeight();\n\t\t\t\tself.writer.addLine(markerLine, true);\n\t\t\t}\n\t\t}\n\t}\n};\n\n// tables\nLayoutBuilder.prototype.processTable = function (tableNode) {\n\tvar processor = new TableProcessor(tableNode);\n\n\tprocessor.beginTable(this.writer);\n\n\tvar rowHeights = tableNode.table.heights;\n\tfor (var i = 0, l = tableNode.table.body.length; i < l; i++) {\n\t\tprocessor.beginRow(i, this.writer);\n\n\t\tvar height;\n\t\tif (isFunction(rowHeights)) {\n\t\t\theight = rowHeights(i);\n\t\t} else if (isArray(rowHeights)) {\n\t\t\theight = rowHeights[i];\n\t\t} else {\n\t\t\theight = rowHeights;\n\t\t}\n\n\t\tif (height === 'auto') {\n\t\t\theight = undefined;\n\t\t}\n\n\t\tvar result = this.processRow(tableNode.table.body[i], tableNode.table.widths, tableNode._offsets.offsets, tableNode.table.body, i, height);\n\t\taddAll(tableNode.positions, result.positions);\n\n\t\tprocessor.endRow(i, this.writer, result.pageBreaks);\n\t}\n\n\tprocessor.endTable(this.writer);\n};\n\n// leafs (texts)\nLayoutBuilder.prototype.processLeaf = function (node) {\n\tvar line = this.buildNextLine(node);\n\tvar currentHeight = (line) ? line.getHeight() : 0;\n\tvar maxHeight = node.maxHeight || -1;\n\n\tif (node._tocItemRef) {\n\t\tline._pageNodeRef = node._tocItemRef;\n\t}\n\n\tif (node._pageRef) {\n\t\tline._pageNodeRef = node._pageRef._nodeRef;\n\t}\n\n\twhile (line && (maxHeight === -1 || currentHeight < maxHeight)) {\n\t\tvar positions = this.writer.addLine(line);\n\t\tnode.positions.push(positions);\n\t\tline = this.buildNextLine(node);\n\t\tif (line) {\n\t\t\tcurrentHeight += line.getHeight();\n\t\t}\n\t}\n};\n\nLayoutBuilder.prototype.processToc = function (node) {\n\tif (node.toc.title) {\n\t\tthis.processNode(node.toc.title);\n\t}\n\tthis.processNode(node.toc._table);\n};\n\nLayoutBuilder.prototype.buildNextLine = function (textNode) {\n\n\tfunction cloneInline(inline) {\n\t\tvar newInline = inline.constructor();\n\t\tfor (var key in inline) {\n\t\t\tnewInline[key] = inline[key];\n\t\t}\n\t\treturn newInline;\n\t}\n\n\tif (!textNode._inlines || textNode._inlines.length === 0) {\n\t\treturn null;\n\t}\n\n\tvar line = new Line(this.writer.context().availableWidth);\n\tvar textTools = new TextTools(null);\n\n\twhile (textNode._inlines && textNode._inlines.length > 0 && line.hasEnoughSpaceForInline(textNode._inlines[0])) {\n\t\tvar inline = textNode._inlines.shift();\n\n\t\tif (!inline.noWrap && inline.text.length > 1 && inline.width > line.maxWidth) {\n\t\t\tvar widthPerChar = inline.width / inline.text.length;\n\t\t\tvar maxChars = Math.floor(line.maxWidth / widthPerChar);\n\t\t\tif (maxChars < 1) {\n\t\t\t\tmaxChars = 1;\n\t\t\t}\n\t\t\tif (maxChars < inline.text.length) {\n\t\t\t\tvar newInline = cloneInline(inline);\n\n\t\t\t\tnewInline.text = inline.text.substr(maxChars);\n\t\t\t\tinline.text = inline.text.substr(0, maxChars);\n\n\t\t\t\tnewInline.width = textTools.widthOfString(newInline.text, newInline.font, newInline.fontSize, newInline.characterSpacing, newInline.fontFeatures);\n\t\t\t\tinline.width = textTools.widthOfString(inline.text, inline.font, inline.fontSize, inline.characterSpacing, inline.fontFeatures);\n\n\t\t\t\ttextNode._inlines.unshift(newInline);\n\t\t\t}\n\t\t}\n\n\t\tline.addInline(inline);\n\t}\n\n\tline.lastLineInParagraph = textNode._inlines.length === 0;\n\n\treturn line;\n};\n\n// images\nLayoutBuilder.prototype.processImage = function (node) {\n\tvar position = this.writer.addImage(node);\n\tnode.positions.push(position);\n};\n\nLayoutBuilder.prototype.processCanvas = function (node) {\n\tvar height = node._minHeight;\n\n\tif (node.absolutePosition === undefined && this.writer.context().availableHeight < height) {\n\t\t// TODO: support for canvas larger than a page\n\t\t// TODO: support for other overflow methods\n\n\t\tthis.writer.moveToNextPage();\n\t}\n\n\tthis.writer.alignCanvas(node);\n\n\tnode.canvas.forEach(function (vector) {\n\t\tvar position = this.writer.addVector(vector);\n\t\tnode.positions.push(position);\n\t}, this);\n\n\tthis.writer.context().moveDown(height);\n};\n\nLayoutBuilder.prototype.processQr = function (node) {\n\tvar position = this.writer.addQr(node);\n\tnode.positions.push(position);\n};\n\nmodule.exports = LayoutBuilder;\n\n\n/***/ }),\n/* 129 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(Buffer) {\n\nvar isString = __webpack_require__(0).isString;\nvar isNumber = __webpack_require__(0).isNumber;\nvar isBoolean = __webpack_require__(0).isBoolean;\nvar isArray = __webpack_require__(0).isArray;\nvar isUndefined = __webpack_require__(0).isUndefined;\nvar fontStringify = __webpack_require__(0).fontStringify;\n\nfunction DocPreprocessor() {\n\n}\n\nDocPreprocessor.prototype.preprocessDocument = function (docStructure) {\n\tthis.tocs = [];\n\tthis.nodeReferences = [];\n\treturn this.preprocessNode(docStructure);\n};\n\nDocPreprocessor.prototype.preprocessNode = function (node) {\n\t// expand shortcuts and casting values\n\tif (isArray(node)) {\n\t\tnode = {stack: node};\n\t} else if (isString(node)) {\n\t\tnode = {text: node};\n\t} else if (isNumber(node) || isBoolean(node)) {\n\t\tnode = {text: node.toString()};\n\t} else if (node === null) {\n\t\tnode = {text: ''};\n\t} else if (Object.keys(node).length === 0) { // empty object\n\t\tnode = {text: ''};\n\t}\n\n\tif (node.columns) {\n\t\treturn this.preprocessColumns(node);\n\t} else if (node.stack) {\n\t\treturn this.preprocessVerticalContainer(node);\n\t} else if (node.ul) {\n\t\treturn this.preprocessList(node);\n\t} else if (node.ol) {\n\t\treturn this.preprocessList(node);\n\t} else if (node.table) {\n\t\treturn this.preprocessTable(node);\n\t} else if (node.text !== undefined) {\n\t\treturn this.preprocessText(node);\n\t} else if (node.toc) {\n\t\treturn this.preprocessToc(node);\n\t} else if (node.image) {\n\t\treturn this.preprocessImage(node);\n\t} else if (node.canvas) {\n\t\treturn this.preprocessCanvas(node);\n\t} else if (node.qr) {\n\t\treturn this.preprocessQr(node);\n\t} else if (node.pageReference || node.textReference) {\n\t\treturn this.preprocessText(node);\n\t} else {\n\t\tthrow 'Unrecognized document structure: ' + JSON.stringify(node, fontStringify);\n\t}\n};\n\nDocPreprocessor.prototype.preprocessColumns = function (node) {\n\tvar columns = node.columns;\n\n\tfor (var i = 0, l = columns.length; i < l; i++) {\n\t\tcolumns[i] = this.preprocessNode(columns[i]);\n\t}\n\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessVerticalContainer = function (node) {\n\tvar items = node.stack;\n\n\tfor (var i = 0, l = items.length; i < l; i++) {\n\t\titems[i] = this.preprocessNode(items[i]);\n\t}\n\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessList = function (node) {\n\tvar items = node.ul || node.ol;\n\n\tfor (var i = 0, l = items.length; i < l; i++) {\n\t\titems[i] = this.preprocessNode(items[i]);\n\t}\n\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessTable = function (node) {\n\tvar col, row, cols, rows;\n\n\tfor (col = 0, cols = node.table.body[0].length; col < cols; col++) {\n\t\tfor (row = 0, rows = node.table.body.length; row < rows; row++) {\n\t\t\tvar rowData = node.table.body[row];\n\t\t\tvar data = rowData[col];\n\t\t\tif (data !== undefined) {\n\t\t\t\tif (data === null) { // transform to object\n\t\t\t\t\tdata = '';\n\t\t\t\t}\n\t\t\t\tif (!data._span) {\n\t\t\t\t\trowData[col] = this.preprocessNode(data);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessText = function (node) {\n\tif (node.tocItem) {\n\t\tif (!isArray(node.tocItem)) {\n\t\t\tnode.tocItem = [node.tocItem];\n\t\t}\n\n\t\tfor (var i = 0, l = node.tocItem.length; i < l; i++) {\n\t\t\tif (!isString(node.tocItem[i])) {\n\t\t\t\tnode.tocItem[i] = '_default_';\n\t\t\t}\n\n\t\t\tvar tocItemId = node.tocItem[i];\n\n\t\t\tif (!this.tocs[tocItemId]) {\n\t\t\t\tthis.tocs[tocItemId] = {toc: {_items: [], _pseudo: true}};\n\t\t\t}\n\n\t\t\tthis.tocs[tocItemId].toc._items.push(node);\n\t\t}\n\t}\n\n\tif (node.id) {\n\t\tif (this.nodeReferences[node.id]) {\n\t\t\tif (!this.nodeReferences[node.id]._pseudo) {\n\t\t\t\tthrow \"Node id '\" + node.id + \"' already exists\";\n\t\t\t}\n\n\t\t\tthis.nodeReferences[node.id]._nodeRef = node;\n\t\t\tthis.nodeReferences[node.id]._pseudo = false;\n\t\t} else {\n\t\t\tthis.nodeReferences[node.id] = {_nodeRef: node};\n\t\t}\n\t}\n\n\tif (node.pageReference) {\n\t\tif (!this.nodeReferences[node.pageReference]) {\n\t\t\tthis.nodeReferences[node.pageReference] = {_nodeRef: {}, _pseudo: true};\n\t\t}\n\t\tnode.text = '00000';\n\t\tnode._pageRef = this.nodeReferences[node.pageReference];\n\t}\n\n\tif (node.textReference) {\n\t\tif (!this.nodeReferences[node.textReference]) {\n\t\t\tthis.nodeReferences[node.textReference] = {_nodeRef: {}, _pseudo: true};\n\t\t}\n\n\t\tnode.text = '';\n\t\tnode._textRef = this.nodeReferences[node.textReference];\n\t}\n\n\tif (node.text && node.text.text) {\n\t\tnode.text = [this.preprocessNode(node.text)];\n\t}\n\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessToc = function (node) {\n\tif (!node.toc.id) {\n\t\tnode.toc.id = '_default_';\n\t}\n\n\tnode.toc.title = node.toc.title ? this.preprocessNode(node.toc.title) : null;\n\tnode.toc._items = [];\n\n\tif (this.tocs[node.toc.id]) {\n\t\tif (!this.tocs[node.toc.id].toc._pseudo) {\n\t\t\tthrow \"TOC '\" + node.toc.id + \"' already exists\";\n\t\t}\n\n\t\tnode.toc._items = this.tocs[node.toc.id].toc._items;\n\t}\n\n\tthis.tocs[node.toc.id] = node;\n\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessImage = function (node) {\n\tif (!isUndefined(node.image.type) && !isUndefined(node.image.data) && (node.image.type === 'Buffer') && isArray(node.image.data)) {\n\t\tnode.image = Buffer.from(node.image.data);\n\t}\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessCanvas = function (node) {\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessQr = function (node) {\n\treturn node;\n};\n\nmodule.exports = DocPreprocessor;\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 130 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/*eslint no-unused-vars: [\"error\", {\"args\": \"none\"}]*/\n\n\n\nvar TextTools = __webpack_require__(42);\nvar StyleContextStack = __webpack_require__(80);\nvar ColumnCalculator = __webpack_require__(44);\nvar isString = __webpack_require__(0).isString;\nvar isNumber = __webpack_require__(0).isNumber;\nvar isObject = __webpack_require__(0).isObject;\nvar isArray = __webpack_require__(0).isArray;\nvar fontStringify = __webpack_require__(0).fontStringify;\nvar pack = __webpack_require__(0).pack;\nvar qrEncoder = __webpack_require__(134);\n\n/**\n * @private\n */\nfunction DocMeasure(fontProvider, styleDictionary, defaultStyle, imageMeasure, tableLayouts, images) {\n\tthis.textTools = new TextTools(fontProvider);\n\tthis.styleStack = new StyleContextStack(styleDictionary, defaultStyle);\n\tthis.imageMeasure = imageMeasure;\n\tthis.tableLayouts = tableLayouts;\n\tthis.images = images;\n\tthis.autoImageIndex = 1;\n}\n\n/**\n * Measures all nodes and sets min/max-width properties required for the second\n * layout-pass.\n * @param  {Object} docStructure document-definition-object\n * @return {Object}              document-measurement-object\n */\nDocMeasure.prototype.measureDocument = function (docStructure) {\n\treturn this.measureNode(docStructure);\n};\n\nDocMeasure.prototype.measureNode = function (node) {\n\n\tvar self = this;\n\n\treturn this.styleStack.auto(node, function () {\n\t\t// TODO: refactor + rethink whether this is the proper way to handle margins\n\t\tnode._margin = getNodeMargin(node);\n\n\t\tif (node.columns) {\n\t\t\treturn extendMargins(self.measureColumns(node));\n\t\t} else if (node.stack) {\n\t\t\treturn extendMargins(self.measureVerticalContainer(node));\n\t\t} else if (node.ul) {\n\t\t\treturn extendMargins(self.measureUnorderedList(node));\n\t\t} else if (node.ol) {\n\t\t\treturn extendMargins(self.measureOrderedList(node));\n\t\t} else if (node.table) {\n\t\t\treturn extendMargins(self.measureTable(node));\n\t\t} else if (node.text !== undefined) {\n\t\t\treturn extendMargins(self.measureLeaf(node));\n\t\t} else if (node.toc) {\n\t\t\treturn extendMargins(self.measureToc(node));\n\t\t} else if (node.image) {\n\t\t\treturn extendMargins(self.measureImage(node));\n\t\t} else if (node.canvas) {\n\t\t\treturn extendMargins(self.measureCanvas(node));\n\t\t} else if (node.qr) {\n\t\t\treturn extendMargins(self.measureQr(node));\n\t\t} else {\n\t\t\tthrow 'Unrecognized document structure: ' + JSON.stringify(node, fontStringify);\n\t\t}\n\t});\n\n\tfunction extendMargins(node) {\n\t\tvar margin = node._margin;\n\n\t\tif (margin) {\n\t\t\tnode._minWidth += margin[0] + margin[2];\n\t\t\tnode._maxWidth += margin[0] + margin[2];\n\t\t}\n\n\t\treturn node;\n\t}\n\n\tfunction getNodeMargin() {\n\n\t\tfunction processSingleMargins(node, currentMargin) {\n\t\t\tif (node.marginLeft || node.marginTop || node.marginRight || node.marginBottom) {\n\t\t\t\treturn [\n\t\t\t\t\tnode.marginLeft || currentMargin[0] || 0,\n\t\t\t\t\tnode.marginTop || currentMargin[1] || 0,\n\t\t\t\t\tnode.marginRight || currentMargin[2] || 0,\n\t\t\t\t\tnode.marginBottom || currentMargin[3] || 0\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn currentMargin;\n\t\t}\n\n\t\tfunction flattenStyleArray(styleArray) {\n\t\t\tvar flattenedStyles = {};\n\t\t\tfor (var i = styleArray.length - 1; i >= 0; i--) {\n\t\t\t\tvar styleName = styleArray[i];\n\t\t\t\tvar style = self.styleStack.styleDictionary[styleName];\n\t\t\t\tfor (var key in style) {\n\t\t\t\t\tif (style.hasOwnProperty(key)) {\n\t\t\t\t\t\tflattenedStyles[key] = style[key];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn flattenedStyles;\n\t\t}\n\n\t\tfunction convertMargin(margin) {\n\t\t\tif (isNumber(margin)) {\n\t\t\t\tmargin = [margin, margin, margin, margin];\n\t\t\t} else if (isArray(margin)) {\n\t\t\t\tif (margin.length === 2) {\n\t\t\t\t\tmargin = [margin[0], margin[1], margin[0], margin[1]];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn margin;\n\t\t}\n\n\t\tvar margin = [undefined, undefined, undefined, undefined];\n\n\t\tif (node.style) {\n\t\t\tvar styleArray = isArray(node.style) ? node.style : [node.style];\n\t\t\tvar flattenedStyleArray = flattenStyleArray(styleArray);\n\n\t\t\tif (flattenedStyleArray) {\n\t\t\t\tmargin = processSingleMargins(flattenedStyleArray, margin);\n\t\t\t}\n\n\t\t\tif (flattenedStyleArray.margin) {\n\t\t\t\tmargin = convertMargin(flattenedStyleArray.margin);\n\t\t\t}\n\t\t}\n\n\t\tmargin = processSingleMargins(node, margin);\n\n\t\tif (node.margin) {\n\t\t\tmargin = convertMargin(node.margin);\n\t\t}\n\n\t\tif (margin[0] === undefined && margin[1] === undefined && margin[2] === undefined && margin[3] === undefined) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\treturn margin;\n\t\t}\n\t}\n};\n\nDocMeasure.prototype.convertIfBase64Image = function (node) {\n\tif (/^data:image\\/(jpeg|jpg|png);base64,/.test(node.image)) {\n\t\tvar label = '$$pdfmake$$' + this.autoImageIndex++;\n\t\tthis.images[label] = node.image;\n\t\tnode.image = label;\n\t}\n};\n\nDocMeasure.prototype.measureImage = function (node) {\n\tif (this.images) {\n\t\tthis.convertIfBase64Image(node);\n\t}\n\n\tvar imageSize = this.imageMeasure.measureImage(node.image);\n\n\tif (node.fit) {\n\t\tvar factor = (imageSize.width / imageSize.height > node.fit[0] / node.fit[1]) ? node.fit[0] / imageSize.width : node.fit[1] / imageSize.height;\n\t\tnode._width = node._minWidth = node._maxWidth = imageSize.width * factor;\n\t\tnode._height = imageSize.height * factor;\n\t} else {\n\t\tnode._width = node._minWidth = node._maxWidth = node.width || imageSize.width;\n\t\tnode._height = node.height || (imageSize.height * node._width / imageSize.width);\n\n\t\tif (isNumber(node.maxWidth) && node.maxWidth < node._width) {\n\t\t\tnode._width = node._minWidth = node._maxWidth = node.maxWidth;\n\t\t\tnode._height = node._width * imageSize.height / imageSize.width;\n\t\t}\n\n\t\tif (isNumber(node.maxHeight) && node.maxHeight < node._height) {\n\t\t\tnode._height = node.maxHeight;\n\t\t\tnode._width = node._minWidth = node._maxWidth = node._height * imageSize.width / imageSize.height;\n\t\t}\n\n\t\tif (isNumber(node.minWidth) && node.minWidth > node._width) {\n\t\t\tnode._width = node._minWidth = node._maxWidth = node.minWidth;\n\t\t\tnode._height = node._width * imageSize.height / imageSize.width;\n\t\t}\n\n\t\tif (isNumber(node.minHeight) && node.minHeight > node._height) {\n\t\t\tnode._height = node.minHeight;\n\t\t\tnode._width = node._minWidth = node._maxWidth = node._height * imageSize.width / imageSize.height;\n\t\t}\n\t}\n\n\tnode._alignment = this.styleStack.getProperty('alignment');\n\treturn node;\n};\n\nDocMeasure.prototype.measureLeaf = function (node) {\n\n\tif (node._textRef && node._textRef._nodeRef.text) {\n\t\tnode.text = node._textRef._nodeRef.text;\n\t}\n\n\t// Make sure style properties of the node itself are considered when building inlines.\n\t// We could also just pass [node] to buildInlines, but that fails for bullet points.\n\tvar styleStack = this.styleStack.clone();\n\tstyleStack.push(node);\n\n\tvar data = this.textTools.buildInlines(node.text, styleStack);\n\n\tnode._inlines = data.items;\n\tnode._minWidth = data.minWidth;\n\tnode._maxWidth = data.maxWidth;\n\n\treturn node;\n};\n\nDocMeasure.prototype.measureToc = function (node) {\n\tif (node.toc.title) {\n\t\tnode.toc.title = this.measureNode(node.toc.title);\n\t}\n\n\tvar body = [];\n\tvar textStyle = node.toc.textStyle || {};\n\tvar numberStyle = node.toc.numberStyle || textStyle;\n\tvar textMargin = node.toc.textMargin || [0, 0, 0, 0];\n\tfor (var i = 0, l = node.toc._items.length; i < l; i++) {\n\t\tvar item = node.toc._items[i];\n\t\tvar lineStyle = node.toc._items[i].tocStyle || textStyle;\n\t\tvar lineMargin = node.toc._items[i].tocMargin || textMargin;\n\t\tbody.push([\n\t\t\t{text: item.text, alignment: 'left', style: lineStyle, margin: lineMargin},\n\t\t\t{text: '00000', alignment: 'right', _tocItemRef: item, style: numberStyle, margin: [0, lineMargin[1], 0, lineMargin[3]]}\n\t\t]);\n\t}\n\n\n\tnode.toc._table = {\n\t\ttable: {\n\t\t\tdontBreakRows: true,\n\t\t\twidths: ['*', 'auto'],\n\t\t\tbody: body\n\t\t},\n\t\tlayout: 'noBorders'\n\t};\n\n\tnode.toc._table = this.measureNode(node.toc._table);\n\n\treturn node;\n};\n\nDocMeasure.prototype.measureVerticalContainer = function (node) {\n\tvar items = node.stack;\n\n\tnode._minWidth = 0;\n\tnode._maxWidth = 0;\n\n\tfor (var i = 0, l = items.length; i < l; i++) {\n\t\titems[i] = this.measureNode(items[i]);\n\n\t\tnode._minWidth = Math.max(node._minWidth, items[i]._minWidth);\n\t\tnode._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth);\n\t}\n\n\treturn node;\n};\n\nDocMeasure.prototype.gapSizeForList = function () {\n\treturn this.textTools.sizeOfString('9. ', this.styleStack);\n};\n\nDocMeasure.prototype.buildUnorderedMarker = function (styleStack, gapSize, type) {\n\tfunction buildDisc(gapSize, color) {\n\t\t// TODO: ascender-based calculations\n\t\tvar radius = gapSize.fontSize / 6;\n\t\treturn {\n\t\t\tcanvas: [{\n\t\t\t\t\tx: radius,\n\t\t\t\t\ty: (gapSize.height / gapSize.lineHeight) + gapSize.descender - gapSize.fontSize / 3,\n\t\t\t\t\tr1: radius,\n\t\t\t\t\tr2: radius,\n\t\t\t\t\ttype: 'ellipse',\n\t\t\t\t\tcolor: color\n\t\t\t\t}]\n\t\t};\n\t}\n\n\tfunction buildSquare(gapSize, color) {\n\t\t// TODO: ascender-based calculations\n\t\tvar size = gapSize.fontSize / 3;\n\t\treturn {\n\t\t\tcanvas: [{\n\t\t\t\t\tx: 0,\n\t\t\t\t\ty: (gapSize.height / gapSize.lineHeight) + gapSize.descender - (gapSize.fontSize / 3) - (size / 2),\n\t\t\t\t\th: size,\n\t\t\t\t\tw: size,\n\t\t\t\t\ttype: 'rect',\n\t\t\t\t\tcolor: color\n\t\t\t\t}]\n\t\t};\n\t}\n\n\tfunction buildCircle(gapSize, color) {\n\t\t// TODO: ascender-based calculations\n\t\tvar radius = gapSize.fontSize / 6;\n\t\treturn {\n\t\t\tcanvas: [{\n\t\t\t\t\tx: radius,\n\t\t\t\t\ty: (gapSize.height / gapSize.lineHeight) + gapSize.descender - gapSize.fontSize / 3,\n\t\t\t\t\tr1: radius,\n\t\t\t\t\tr2: radius,\n\t\t\t\t\ttype: 'ellipse',\n\t\t\t\t\tlineColor: color\n\t\t\t\t}]\n\t\t};\n\t}\n\n\tvar marker;\n\tvar color = styleStack.getProperty('markerColor') || styleStack.getProperty('color') || 'black';\n\n\tswitch (type) {\n\t\tcase 'circle':\n\t\t\tmarker = buildCircle(gapSize, color);\n\t\t\tbreak;\n\n\t\tcase 'square':\n\t\t\tmarker = buildSquare(gapSize, color);\n\t\t\tbreak;\n\n\t\tcase 'none':\n\t\t\tmarker = {};\n\t\t\tbreak;\n\n\t\tcase 'disc':\n\t\tdefault:\n\t\t\tmarker = buildDisc(gapSize, color);\n\t\t\tbreak;\n\t}\n\n\tmarker._minWidth = marker._maxWidth = gapSize.width;\n\tmarker._minHeight = marker._maxHeight = gapSize.height;\n\n\treturn marker;\n};\n\nDocMeasure.prototype.buildOrderedMarker = function (counter, styleStack, type, separator) {\n\tfunction prepareAlpha(counter) {\n\t\tfunction toAlpha(num) {\n\t\t\treturn (num >= 26 ? toAlpha((num / 26 >> 0) - 1) : '') + 'abcdefghijklmnopqrstuvwxyz'[num % 26 >> 0];\n\t\t}\n\n\t\tif (counter < 1) {\n\t\t\treturn counter.toString();\n\t\t}\n\n\t\treturn toAlpha(counter - 1);\n\t}\n\n\tfunction prepareRoman(counter) {\n\t\tif (counter < 1 || counter > 4999) {\n\t\t\treturn counter.toString();\n\t\t}\n\t\tvar num = counter;\n\t\tvar lookup = {M: 1000, CM: 900, D: 500, CD: 400, C: 100, XC: 90, L: 50, XL: 40, X: 10, IX: 9, V: 5, IV: 4, I: 1}, roman = '', i;\n\t\tfor (i in lookup) {\n\t\t\twhile (num >= lookup[i]) {\n\t\t\t\troman += i;\n\t\t\t\tnum -= lookup[i];\n\t\t\t}\n\t\t}\n\t\treturn roman;\n\t}\n\n\tfunction prepareDecimal(counter) {\n\t\treturn counter.toString();\n\t}\n\n\tvar counterText;\n\tswitch (type) {\n\t\tcase 'none':\n\t\t\tcounterText = null;\n\t\t\tbreak;\n\n\t\tcase 'upper-alpha':\n\t\t\tcounterText = prepareAlpha(counter).toUpperCase();\n\t\t\tbreak;\n\n\t\tcase 'lower-alpha':\n\t\t\tcounterText = prepareAlpha(counter);\n\t\t\tbreak;\n\n\t\tcase 'upper-roman':\n\t\t\tcounterText = prepareRoman(counter);\n\t\t\tbreak;\n\n\t\tcase 'lower-roman':\n\t\t\tcounterText = prepareRoman(counter).toLowerCase();\n\t\t\tbreak;\n\n\t\tcase 'decimal':\n\t\tdefault:\n\t\t\tcounterText = prepareDecimal(counter);\n\t\t\tbreak;\n\t}\n\n\tif (counterText === null) {\n\t\treturn {};\n\t}\n\n\tif (separator) {\n\t\tif (isArray(separator)) {\n\t\t\tif (separator[0]) {\n\t\t\t\tcounterText = separator[0] + counterText;\n\t\t\t}\n\n\t\t\tif (separator[1]) {\n\t\t\t\tcounterText += separator[1];\n\t\t\t}\n\t\t\tcounterText += ' ';\n\t\t} else {\n\t\t\tcounterText += separator + ' ';\n\t\t}\n\t}\n\n\tvar textArray = {text: counterText};\n\tvar markerColor = styleStack.getProperty('markerColor');\n\tif (markerColor) {\n\t\ttextArray.color = markerColor;\n\t}\n\n\treturn {_inlines: this.textTools.buildInlines(textArray, styleStack).items};\n};\n\nDocMeasure.prototype.measureUnorderedList = function (node) {\n\tvar style = this.styleStack.clone();\n\tvar items = node.ul;\n\tnode.type = node.type || 'disc';\n\tnode._gapSize = this.gapSizeForList();\n\tnode._minWidth = 0;\n\tnode._maxWidth = 0;\n\n\tfor (var i = 0, l = items.length; i < l; i++) {\n\t\tvar item = items[i] = this.measureNode(items[i]);\n\n\t\tif (!item.ol && !item.ul) {\n\t\t\titem.listMarker = this.buildUnorderedMarker(style, node._gapSize, item.listType || node.type);\n\t\t}\n\n\t\tnode._minWidth = Math.max(node._minWidth, items[i]._minWidth + node._gapSize.width);\n\t\tnode._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth + node._gapSize.width);\n\t}\n\n\treturn node;\n};\n\nDocMeasure.prototype.measureOrderedList = function (node) {\n\tvar style = this.styleStack.clone();\n\tvar items = node.ol;\n\tnode.type = node.type || 'decimal';\n\tnode.separator = node.separator || '.';\n\tnode.reversed = node.reversed || false;\n\tif (!node.start) {\n\t\tnode.start = node.reversed ? items.length : 1;\n\t}\n\tnode._gapSize = this.gapSizeForList();\n\tnode._minWidth = 0;\n\tnode._maxWidth = 0;\n\n\tvar counter = node.start;\n\tfor (var i = 0, l = items.length; i < l; i++) {\n\t\tvar item = items[i] = this.measureNode(items[i]);\n\n\t\tif (!item.ol && !item.ul) {\n\t\t\titem.listMarker = this.buildOrderedMarker(item.counter || counter, style, item.listType || node.type, node.separator);\n\t\t\tif (item.listMarker._inlines) {\n\t\t\t\tnode._gapSize.width = Math.max(node._gapSize.width, item.listMarker._inlines[0].width);\n\t\t\t}\n\t\t}  // TODO: else - nested lists numbering\n\n\t\tnode._minWidth = Math.max(node._minWidth, items[i]._minWidth);\n\t\tnode._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth);\n\n\t\tif (node.reversed) {\n\t\t\tcounter--;\n\t\t} else {\n\t\t\tcounter++;\n\t\t}\n\t}\n\n\tnode._minWidth += node._gapSize.width;\n\tnode._maxWidth += node._gapSize.width;\n\n\tfor (var i = 0, l = items.length; i < l; i++) {\n\t\tvar item = items[i];\n\t\tif (!item.ol && !item.ul) {\n\t\t\titem.listMarker._minWidth = item.listMarker._maxWidth = node._gapSize.width;\n\t\t}\n\t}\n\n\treturn node;\n};\n\nDocMeasure.prototype.measureColumns = function (node) {\n\tvar columns = node.columns;\n\tnode._gap = this.styleStack.getProperty('columnGap') || 0;\n\n\tfor (var i = 0, l = columns.length; i < l; i++) {\n\t\tcolumns[i] = this.measureNode(columns[i]);\n\t}\n\n\tvar measures = ColumnCalculator.measureMinMax(columns);\n\n\tvar numGaps = (columns.length > 0) ? (columns.length - 1) : 0;\n\tnode._minWidth = measures.min + node._gap * numGaps;\n\tnode._maxWidth = measures.max + node._gap * numGaps;\n\n\treturn node;\n};\n\nDocMeasure.prototype.measureTable = function (node) {\n\textendTableWidths(node);\n\tnode._layout = getLayout(this.tableLayouts);\n\tnode._offsets = getOffsets(node._layout);\n\n\tvar colSpans = [];\n\tvar col, row, cols, rows;\n\n\tfor (col = 0, cols = node.table.body[0].length; col < cols; col++) {\n\t\tvar c = node.table.widths[col];\n\t\tc._minWidth = 0;\n\t\tc._maxWidth = 0;\n\n\t\tfor (row = 0, rows = node.table.body.length; row < rows; row++) {\n\t\t\tvar rowData = node.table.body[row];\n\t\t\tvar data = rowData[col];\n\t\t\tif (data === undefined) {\n\t\t\t\tconsole.error('Malformed table row ', rowData, 'in node ', node);\n\t\t\t\tthrow 'Malformed table row, a cell is undefined.';\n\t\t\t}\n\t\t\tif (data === null) { // transform to object\n\t\t\t\tdata = '';\n\t\t\t}\n\n\t\t\tif (!data._span) {\n\t\t\t\tdata = rowData[col] = this.styleStack.auto(data, measureCb(this, data));\n\n\t\t\t\tif (data.colSpan && data.colSpan > 1) {\n\t\t\t\t\tmarkSpans(rowData, col, data.colSpan);\n\t\t\t\t\tcolSpans.push({col: col, span: data.colSpan, minWidth: data._minWidth, maxWidth: data._maxWidth});\n\t\t\t\t} else {\n\t\t\t\t\tc._minWidth = Math.max(c._minWidth, data._minWidth);\n\t\t\t\t\tc._maxWidth = Math.max(c._maxWidth, data._maxWidth);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (data.rowSpan && data.rowSpan > 1) {\n\t\t\t\tmarkVSpans(node.table, row, col, data.rowSpan);\n\t\t\t}\n\t\t}\n\t}\n\n\textendWidthsForColSpans();\n\n\tvar measures = ColumnCalculator.measureMinMax(node.table.widths);\n\n\tnode._minWidth = measures.min + node._offsets.total;\n\tnode._maxWidth = measures.max + node._offsets.total;\n\n\treturn node;\n\n\tfunction measureCb(_this, data) {\n\t\treturn function () {\n\t\t\tif (isObject(data)) {\n\t\t\t\tdata.fillColor = _this.styleStack.getProperty('fillColor');\n\t\t\t}\n\t\t\treturn _this.measureNode(data);\n\t\t};\n\t}\n\n\tfunction getLayout(tableLayouts) {\n\t\tvar layout = node.layout;\n\n\t\tif (isString(layout)) {\n\t\t\tlayout = tableLayouts[layout];\n\t\t}\n\n\t\tvar defaultLayout = {\n\t\t\thLineWidth: function (i, node) {\n\t\t\t\treturn 1;\n\t\t\t},\n\t\t\tvLineWidth: function (i, node) {\n\t\t\t\treturn 1;\n\t\t\t},\n\t\t\thLineColor: function (i, node) {\n\t\t\t\treturn 'black';\n\t\t\t},\n\t\t\tvLineColor: function (i, node) {\n\t\t\t\treturn 'black';\n\t\t\t},\n\t\t\tpaddingLeft: function (i, node) {\n\t\t\t\treturn 4;\n\t\t\t},\n\t\t\tpaddingRight: function (i, node) {\n\t\t\t\treturn 4;\n\t\t\t},\n\t\t\tpaddingTop: function (i, node) {\n\t\t\t\treturn 2;\n\t\t\t},\n\t\t\tpaddingBottom: function (i, node) {\n\t\t\t\treturn 2;\n\t\t\t},\n\t\t\tfillColor: function (i, node) {\n\t\t\t\treturn null;\n\t\t\t},\n\t\t\tdefaultBorder: true\n\t\t};\n\n\t\treturn pack(defaultLayout, layout);\n\t}\n\n\tfunction getOffsets(layout) {\n\t\tvar offsets = [];\n\t\tvar totalOffset = 0;\n\t\tvar prevRightPadding = 0;\n\n\t\tfor (var i = 0, l = node.table.widths.length; i < l; i++) {\n\t\t\tvar lOffset = prevRightPadding + layout.vLineWidth(i, node) + layout.paddingLeft(i, node);\n\t\t\toffsets.push(lOffset);\n\t\t\ttotalOffset += lOffset;\n\t\t\tprevRightPadding = layout.paddingRight(i, node);\n\t\t}\n\n\t\ttotalOffset += prevRightPadding + layout.vLineWidth(node.table.widths.length, node);\n\n\t\treturn {\n\t\t\ttotal: totalOffset,\n\t\t\toffsets: offsets\n\t\t};\n\t}\n\n\tfunction extendWidthsForColSpans() {\n\t\tvar q, j;\n\n\t\tfor (var i = 0, l = colSpans.length; i < l; i++) {\n\t\t\tvar span = colSpans[i];\n\n\t\t\tvar currentMinMax = getMinMax(span.col, span.span, node._offsets);\n\t\t\tvar minDifference = span.minWidth - currentMinMax.minWidth;\n\t\t\tvar maxDifference = span.maxWidth - currentMinMax.maxWidth;\n\n\t\t\tif (minDifference > 0) {\n\t\t\t\tq = minDifference / span.span;\n\n\t\t\t\tfor (j = 0; j < span.span; j++) {\n\t\t\t\t\tnode.table.widths[span.col + j]._minWidth += q;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (maxDifference > 0) {\n\t\t\t\tq = maxDifference / span.span;\n\n\t\t\t\tfor (j = 0; j < span.span; j++) {\n\t\t\t\t\tnode.table.widths[span.col + j]._maxWidth += q;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction getMinMax(col, span, offsets) {\n\t\tvar result = {minWidth: 0, maxWidth: 0};\n\n\t\tfor (var i = 0; i < span; i++) {\n\t\t\tresult.minWidth += node.table.widths[col + i]._minWidth + (i ? offsets.offsets[col + i] : 0);\n\t\t\tresult.maxWidth += node.table.widths[col + i]._maxWidth + (i ? offsets.offsets[col + i] : 0);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tfunction markSpans(rowData, col, span) {\n\t\tfor (var i = 1; i < span; i++) {\n\t\t\trowData[col + i] = {\n\t\t\t\t_span: true,\n\t\t\t\t_minWidth: 0,\n\t\t\t\t_maxWidth: 0,\n\t\t\t\trowSpan: rowData[col].rowSpan\n\t\t\t};\n\t\t}\n\t}\n\n\tfunction markVSpans(table, row, col, span) {\n\t\tfor (var i = 1; i < span; i++) {\n\t\t\ttable.body[row + i][col] = {\n\t\t\t\t_span: true,\n\t\t\t\t_minWidth: 0,\n\t\t\t\t_maxWidth: 0,\n\t\t\t\tfillColor: table.body[row][col].fillColor\n\t\t\t};\n\t\t}\n\t}\n\n\tfunction extendTableWidths(node) {\n\t\tif (!node.table.widths) {\n\t\t\tnode.table.widths = 'auto';\n\t\t}\n\n\t\tif (isString(node.table.widths)) {\n\t\t\tnode.table.widths = [node.table.widths];\n\n\t\t\twhile (node.table.widths.length < node.table.body[0].length) {\n\t\t\t\tnode.table.widths.push(node.table.widths[node.table.widths.length - 1]);\n\t\t\t}\n\t\t}\n\n\t\tfor (var i = 0, l = node.table.widths.length; i < l; i++) {\n\t\t\tvar w = node.table.widths[i];\n\t\t\tif (isNumber(w) || isString(w)) {\n\t\t\t\tnode.table.widths[i] = {width: w};\n\t\t\t}\n\t\t}\n\t}\n};\n\nDocMeasure.prototype.measureCanvas = function (node) {\n\tvar w = 0, h = 0;\n\n\tfor (var i = 0, l = node.canvas.length; i < l; i++) {\n\t\tvar vector = node.canvas[i];\n\n\t\tswitch (vector.type) {\n\t\t\tcase 'ellipse':\n\t\t\t\tw = Math.max(w, vector.x + vector.r1);\n\t\t\t\th = Math.max(h, vector.y + vector.r2);\n\t\t\t\tbreak;\n\t\t\tcase 'rect':\n\t\t\t\tw = Math.max(w, vector.x + vector.w);\n\t\t\t\th = Math.max(h, vector.y + vector.h);\n\t\t\t\tbreak;\n\t\t\tcase 'line':\n\t\t\t\tw = Math.max(w, vector.x1, vector.x2);\n\t\t\t\th = Math.max(h, vector.y1, vector.y2);\n\t\t\t\tbreak;\n\t\t\tcase 'polyline':\n\t\t\t\tfor (var i2 = 0, l2 = vector.points.length; i2 < l2; i2++) {\n\t\t\t\t\tw = Math.max(w, vector.points[i2].x);\n\t\t\t\t\th = Math.max(h, vector.points[i2].y);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tnode._minWidth = node._maxWidth = w;\n\tnode._minHeight = node._maxHeight = h;\n\tnode._alignment = this.styleStack.getProperty('alignment');\n\n\treturn node;\n};\n\nDocMeasure.prototype.measureQr = function (node) {\n\tnode = qrEncoder.measure(node);\n\tnode._alignment = this.styleStack.getProperty('alignment');\n\treturn node;\n};\n\nmodule.exports = DocMeasure;\n\n\n/***/ }),\n/* 131 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n;(function (exports) {\n\t'use strict';\n\n  var Arr = (typeof Uint8Array !== 'undefined')\n    ? Uint8Array\n    : Array\n\n\tvar PLUS   = '+'.charCodeAt(0)\n\tvar SLASH  = '/'.charCodeAt(0)\n\tvar NUMBER = '0'.charCodeAt(0)\n\tvar LOWER  = 'a'.charCodeAt(0)\n\tvar UPPER  = 'A'.charCodeAt(0)\n\tvar PLUS_URL_SAFE = '-'.charCodeAt(0)\n\tvar SLASH_URL_SAFE = '_'.charCodeAt(0)\n\n\tfunction decode (elt) {\n\t\tvar code = elt.charCodeAt(0)\n\t\tif (code === PLUS ||\n\t\t    code === PLUS_URL_SAFE)\n\t\t\treturn 62 // '+'\n\t\tif (code === SLASH ||\n\t\t    code === SLASH_URL_SAFE)\n\t\t\treturn 63 // '/'\n\t\tif (code < NUMBER)\n\t\t\treturn -1 //no match\n\t\tif (code < NUMBER + 10)\n\t\t\treturn code - NUMBER + 26 + 26\n\t\tif (code < UPPER + 26)\n\t\t\treturn code - UPPER\n\t\tif (code < LOWER + 26)\n\t\t\treturn code - LOWER + 26\n\t}\n\n\tfunction b64ToByteArray (b64) {\n\t\tvar i, j, l, tmp, placeHolders, arr\n\n\t\tif (b64.length % 4 > 0) {\n\t\t\tthrow new Error('Invalid string. Length must be a multiple of 4')\n\t\t}\n\n\t\t// the number of equal signs (place holders)\n\t\t// if there are two placeholders, than the two characters before it\n\t\t// represent one byte\n\t\t// if there is only one, then the three characters before it represent 2 bytes\n\t\t// this is just a cheap hack to not do indexOf twice\n\t\tvar len = b64.length\n\t\tplaceHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0\n\n\t\t// base64 is 4/3 + up to two characters of the original data\n\t\tarr = new Arr(b64.length * 3 / 4 - placeHolders)\n\n\t\t// if there are placeholders, only get up to the last complete 4 chars\n\t\tl = placeHolders > 0 ? b64.length - 4 : b64.length\n\n\t\tvar L = 0\n\n\t\tfunction push (v) {\n\t\t\tarr[L++] = v\n\t\t}\n\n\t\tfor (i = 0, j = 0; i < l; i += 4, j += 3) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))\n\t\t\tpush((tmp & 0xFF0000) >> 16)\n\t\t\tpush((tmp & 0xFF00) >> 8)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\tif (placeHolders === 2) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)\n\t\t\tpush(tmp & 0xFF)\n\t\t} else if (placeHolders === 1) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)\n\t\t\tpush((tmp >> 8) & 0xFF)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\treturn arr\n\t}\n\n\tfunction uint8ToBase64 (uint8) {\n\t\tvar i,\n\t\t\textraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes\n\t\t\toutput = \"\",\n\t\t\ttemp, length\n\n\t\tfunction encode (num) {\n\t\t\treturn lookup.charAt(num)\n\t\t}\n\n\t\tfunction tripletToBase64 (num) {\n\t\t\treturn encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)\n\t\t}\n\n\t\t// go through the array every three bytes, we'll deal with trailing stuff later\n\t\tfor (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {\n\t\t\ttemp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n\t\t\toutput += tripletToBase64(temp)\n\t\t}\n\n\t\t// pad the end with zeros, but make sure to not forget the extra bytes\n\t\tswitch (extraBytes) {\n\t\t\tcase 1:\n\t\t\t\ttemp = uint8[uint8.length - 1]\n\t\t\t\toutput += encode(temp >> 2)\n\t\t\t\toutput += encode((temp << 4) & 0x3F)\n\t\t\t\toutput += '=='\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\ttemp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])\n\t\t\t\toutput += encode(temp >> 10)\n\t\t\t\toutput += encode((temp >> 4) & 0x3F)\n\t\t\t\toutput += encode((temp << 2) & 0x3F)\n\t\t\t\toutput += '='\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn output\n\t}\n\n\texports.toByteArray = b64ToByteArray\n\texports.fromByteArray = uint8ToBase64\n}( false ? (this.base64js = {}) : exports))\n\n\n/***/ }),\n/* 132 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var AI, AL, B2, BA, BB, BK, CB, CJ, CL, CM, CP, CR, EX, GL, H2, H3, HL, HY, ID, IN, IS, JL, JT, JV, LF, NL, NS, NU, OP, PO, PR, QU, RI, SA, SG, SP, SY, WJ, XX, ZW;\n\n  exports.OP = OP = 0;\n\n  exports.CL = CL = 1;\n\n  exports.CP = CP = 2;\n\n  exports.QU = QU = 3;\n\n  exports.GL = GL = 4;\n\n  exports.NS = NS = 5;\n\n  exports.EX = EX = 6;\n\n  exports.SY = SY = 7;\n\n  exports.IS = IS = 8;\n\n  exports.PR = PR = 9;\n\n  exports.PO = PO = 10;\n\n  exports.NU = NU = 11;\n\n  exports.AL = AL = 12;\n\n  exports.HL = HL = 13;\n\n  exports.ID = ID = 14;\n\n  exports.IN = IN = 15;\n\n  exports.HY = HY = 16;\n\n  exports.BA = BA = 17;\n\n  exports.BB = BB = 18;\n\n  exports.B2 = B2 = 19;\n\n  exports.ZW = ZW = 20;\n\n  exports.CM = CM = 21;\n\n  exports.WJ = WJ = 22;\n\n  exports.H2 = H2 = 23;\n\n  exports.H3 = H3 = 24;\n\n  exports.JL = JL = 25;\n\n  exports.JV = JV = 26;\n\n  exports.JT = JT = 27;\n\n  exports.RI = RI = 28;\n\n  exports.AI = AI = 29;\n\n  exports.BK = BK = 30;\n\n  exports.CB = CB = 31;\n\n  exports.CJ = CJ = 32;\n\n  exports.CR = CR = 33;\n\n  exports.LF = LF = 34;\n\n  exports.NL = NL = 35;\n\n  exports.SA = SA = 36;\n\n  exports.SG = SG = 37;\n\n  exports.SP = SP = 38;\n\n  exports.XX = XX = 39;\n\n}).call(this);\n\n\n/***/ }),\n/* 133 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var CI_BRK, CP_BRK, DI_BRK, IN_BRK, PR_BRK;\n\n  exports.DI_BRK = DI_BRK = 0;\n\n  exports.IN_BRK = IN_BRK = 1;\n\n  exports.CI_BRK = CI_BRK = 2;\n\n  exports.CP_BRK = CP_BRK = 3;\n\n  exports.PR_BRK = PR_BRK = 4;\n\n  exports.pairTable = [[PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, CP_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, DI_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, DI_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, PR_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK]];\n\n}).call(this);\n\n\n/***/ }),\n/* 134 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/*eslint no-unused-vars: [\"error\", {\"args\": \"none\"}]*/\n/*eslint no-redeclare: \"off\"*/\n\n\n/* qr.js -- QR code generator in Javascript (revision 2011-01-19)\n * Written by Kang Seonghoon <public+qrjs@mearie.org>.\n *\n * This source code is in the public domain; if your jurisdiction does not\n * recognize the public domain the terms of Creative Commons CC0 license\n * apply. In the other words, you can always do what you want.\n */\n\n\n// per-version information (cf. JIS X 0510:2004 pp. 30--36, 71)\n//\n// [0]: the degree of generator polynomial by ECC levels\n// [1]: # of code blocks by ECC levels\n// [2]: left-top positions of alignment patterns\n//\n// the number in this table (in particular, [0]) does not exactly match with\n// the numbers in the specficiation. see augumenteccs below for the reason.\nvar VERSIONS = [\n\tnull,\n\t[[10, 7, 17, 13], [1, 1, 1, 1], []],\n\t[[16, 10, 28, 22], [1, 1, 1, 1], [4, 16]],\n\t[[26, 15, 22, 18], [1, 1, 2, 2], [4, 20]],\n\t[[18, 20, 16, 26], [2, 1, 4, 2], [4, 24]],\n\t[[24, 26, 22, 18], [2, 1, 4, 4], [4, 28]],\n\t[[16, 18, 28, 24], [4, 2, 4, 4], [4, 32]],\n\t[[18, 20, 26, 18], [4, 2, 5, 6], [4, 20, 36]],\n\t[[22, 24, 26, 22], [4, 2, 6, 6], [4, 22, 40]],\n\t[[22, 30, 24, 20], [5, 2, 8, 8], [4, 24, 44]],\n\t[[26, 18, 28, 24], [5, 4, 8, 8], [4, 26, 48]],\n\t[[30, 20, 24, 28], [5, 4, 11, 8], [4, 28, 52]],\n\t[[22, 24, 28, 26], [8, 4, 11, 10], [4, 30, 56]],\n\t[[22, 26, 22, 24], [9, 4, 16, 12], [4, 32, 60]],\n\t[[24, 30, 24, 20], [9, 4, 16, 16], [4, 24, 44, 64]],\n\t[[24, 22, 24, 30], [10, 6, 18, 12], [4, 24, 46, 68]],\n\t[[28, 24, 30, 24], [10, 6, 16, 17], [4, 24, 48, 72]],\n\t[[28, 28, 28, 28], [11, 6, 19, 16], [4, 28, 52, 76]],\n\t[[26, 30, 28, 28], [13, 6, 21, 18], [4, 28, 54, 80]],\n\t[[26, 28, 26, 26], [14, 7, 25, 21], [4, 28, 56, 84]],\n\t[[26, 28, 28, 30], [16, 8, 25, 20], [4, 32, 60, 88]],\n\t[[26, 28, 30, 28], [17, 8, 25, 23], [4, 26, 48, 70, 92]],\n\t[[28, 28, 24, 30], [17, 9, 34, 23], [4, 24, 48, 72, 96]],\n\t[[28, 30, 30, 30], [18, 9, 30, 25], [4, 28, 52, 76, 100]],\n\t[[28, 30, 30, 30], [20, 10, 32, 27], [4, 26, 52, 78, 104]],\n\t[[28, 26, 30, 30], [21, 12, 35, 29], [4, 30, 56, 82, 108]],\n\t[[28, 28, 30, 28], [23, 12, 37, 34], [4, 28, 56, 84, 112]],\n\t[[28, 30, 30, 30], [25, 12, 40, 34], [4, 32, 60, 88, 116]],\n\t[[28, 30, 30, 30], [26, 13, 42, 35], [4, 24, 48, 72, 96, 120]],\n\t[[28, 30, 30, 30], [28, 14, 45, 38], [4, 28, 52, 76, 100, 124]],\n\t[[28, 30, 30, 30], [29, 15, 48, 40], [4, 24, 50, 76, 102, 128]],\n\t[[28, 30, 30, 30], [31, 16, 51, 43], [4, 28, 54, 80, 106, 132]],\n\t[[28, 30, 30, 30], [33, 17, 54, 45], [4, 32, 58, 84, 110, 136]],\n\t[[28, 30, 30, 30], [35, 18, 57, 48], [4, 28, 56, 84, 112, 140]],\n\t[[28, 30, 30, 30], [37, 19, 60, 51], [4, 32, 60, 88, 116, 144]],\n\t[[28, 30, 30, 30], [38, 19, 63, 53], [4, 28, 52, 76, 100, 124, 148]],\n\t[[28, 30, 30, 30], [40, 20, 66, 56], [4, 22, 48, 74, 100, 126, 152]],\n\t[[28, 30, 30, 30], [43, 21, 70, 59], [4, 26, 52, 78, 104, 130, 156]],\n\t[[28, 30, 30, 30], [45, 22, 74, 62], [4, 30, 56, 82, 108, 134, 160]],\n\t[[28, 30, 30, 30], [47, 24, 77, 65], [4, 24, 52, 80, 108, 136, 164]],\n\t[[28, 30, 30, 30], [49, 25, 81, 68], [4, 28, 56, 84, 112, 140, 168]]];\n\n// mode constants (cf. Table 2 in JIS X 0510:2004 p. 16)\nvar MODE_TERMINATOR = 0;\nvar MODE_NUMERIC = 1, MODE_ALPHANUMERIC = 2, MODE_OCTET = 4, MODE_KANJI = 8;\n\n// validation regexps\nvar NUMERIC_REGEXP = /^\\d*$/;\nvar ALPHANUMERIC_REGEXP = /^[A-Za-z0-9 $%*+\\-./:]*$/;\nvar ALPHANUMERIC_OUT_REGEXP = /^[A-Z0-9 $%*+\\-./:]*$/;\n\n// ECC levels (cf. Table 22 in JIS X 0510:2004 p. 45)\nvar ECCLEVEL_L = 1, ECCLEVEL_M = 0, ECCLEVEL_Q = 3, ECCLEVEL_H = 2;\n\n// GF(2^8)-to-integer mapping with a reducing polynomial x^8+x^4+x^3+x^2+1\n// invariant: GF256_MAP[GF256_INVMAP[i]] == i for all i in [1,256)\nvar GF256_MAP = [], GF256_INVMAP = [-1];\nfor (var i = 0, v = 1; i < 255; ++i) {\n\tGF256_MAP.push(v);\n\tGF256_INVMAP[v] = i;\n\tv = (v * 2) ^ (v >= 128 ? 0x11d : 0);\n}\n\n// generator polynomials up to degree 30\n// (should match with polynomials in JIS X 0510:2004 Appendix A)\n//\n// generator polynomial of degree K is product of (x-\\alpha^0), (x-\\alpha^1),\n// ..., (x-\\alpha^(K-1)). by convention, we omit the K-th coefficient (always 1)\n// from the result; also other coefficients are written in terms of the exponent\n// to \\alpha to avoid the redundant calculation. (see also calculateecc below.)\nvar GF256_GENPOLY = [[]];\nfor (var i = 0; i < 30; ++i) {\n\tvar prevpoly = GF256_GENPOLY[i], poly = [];\n\tfor (var j = 0; j <= i; ++j) {\n\t\tvar a = (j < i ? GF256_MAP[prevpoly[j]] : 0);\n\t\tvar b = GF256_MAP[(i + (prevpoly[j - 1] || 0)) % 255];\n\t\tpoly.push(GF256_INVMAP[a ^ b]);\n\t}\n\tGF256_GENPOLY.push(poly);\n}\n\n// alphanumeric character mapping (cf. Table 5 in JIS X 0510:2004 p. 19)\nvar ALPHANUMERIC_MAP = {};\nfor (var i = 0; i < 45; ++i) {\n\tALPHANUMERIC_MAP['0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'.charAt(i)] = i;\n}\n\n// mask functions in terms of row # and column #\n// (cf. Table 20 in JIS X 0510:2004 p. 42)\n/*jshint unused: false */\nvar MASKFUNCS = [\n\tfunction (i, j) {\n\t\treturn (i + j) % 2 === 0;\n\t},\n\tfunction (i, j) {\n\t\treturn i % 2 === 0;\n\t},\n\tfunction (i, j) {\n\t\treturn j % 3 === 0;\n\t},\n\tfunction (i, j) {\n\t\treturn (i + j) % 3 === 0;\n\t},\n\tfunction (i, j) {\n\t\treturn (((i / 2) | 0) + ((j / 3) | 0)) % 2 === 0;\n\t},\n\tfunction (i, j) {\n\t\treturn (i * j) % 2 + (i * j) % 3 === 0;\n\t},\n\tfunction (i, j) {\n\t\treturn ((i * j) % 2 + (i * j) % 3) % 2 === 0;\n\t},\n\tfunction (i, j) {\n\t\treturn ((i + j) % 2 + (i * j) % 3) % 2 === 0;\n\t}];\n\n// returns true when the version information has to be embeded.\nvar needsverinfo = function (ver) {\n\treturn ver > 6;\n};\n\n// returns the size of entire QR code for given version.\nvar getsizebyver = function (ver) {\n\treturn 4 * ver + 17;\n};\n\n// returns the number of bits available for code words in this version.\nvar nfullbits = function (ver) {\n\t/*\n\t * |<--------------- n --------------->|\n\t * |        |<----- n-17 ---->|        |\n\t * +-------+                ///+-------+ ----\n\t * |       |                ///|       |    ^\n\t * |  9x9  |       @@@@@    ///|  9x8  |    |\n\t * |       | # # # @5x5@ # # # |       |    |\n\t * +-------+       @@@@@       +-------+    |\n\t *       #                               ---|\n\t *                                        ^ |\n\t *       #                                |\n\t *     @@@@@       @@@@@       @@@@@      | n\n\t *     @5x5@       @5x5@       @5x5@   n-17\n\t *     @@@@@       @@@@@       @@@@@      | |\n\t *       #                                | |\n\t * //////                                 v |\n\t * //////#                               ---|\n\t * +-------+       @@@@@       @@@@@        |\n\t * |       |       @5x5@       @5x5@        |\n\t * |  8x9  |       @@@@@       @@@@@        |\n\t * |       |                                v\n\t * +-------+                             ----\n\t *\n\t * when the entire code has n^2 modules and there are m^2-3 alignment\n\t * patterns, we have:\n\t * - 225 (= 9x9 + 9x8 + 8x9) modules for finder patterns and\n\t *   format information;\n\t * - 2n-34 (= 2(n-17)) modules for timing patterns;\n\t * - 36 (= 3x6 + 6x3) modules for version information, if any;\n\t * - 25m^2-75 (= (m^2-3)(5x5)) modules for alignment patterns\n\t *   if any, but 10m-20 (= 2(m-2)x5) of them overlaps with\n\t *   timing patterns.\n\t */\n\tvar v = VERSIONS[ver];\n\tvar nbits = 16 * ver * ver + 128 * ver + 64; // finder, timing and format info.\n\tif (needsverinfo(ver))\n\t\tnbits -= 36; // version information\n\tif (v[2].length) { // alignment patterns\n\t\tnbits -= 25 * v[2].length * v[2].length - 10 * v[2].length - 55;\n\t}\n\treturn nbits;\n};\n\n// returns the number of bits available for data portions (i.e. excludes ECC\n// bits but includes mode and length bits) in this version and ECC level.\nvar ndatabits = function (ver, ecclevel) {\n\tvar nbits = nfullbits(ver) & ~7; // no sub-octet code words\n\tvar v = VERSIONS[ver];\n\tnbits -= 8 * v[0][ecclevel] * v[1][ecclevel]; // ecc bits\n\treturn nbits;\n};\n\n// returns the number of bits required for the length of data.\n// (cf. Table 3 in JIS X 0510:2004 p. 16)\nvar ndatalenbits = function (ver, mode) {\n\tswitch (mode) {\n\t\tcase MODE_NUMERIC:\n\t\t\treturn (ver < 10 ? 10 : ver < 27 ? 12 : 14);\n\t\tcase MODE_ALPHANUMERIC:\n\t\t\treturn (ver < 10 ? 9 : ver < 27 ? 11 : 13);\n\t\tcase MODE_OCTET:\n\t\t\treturn (ver < 10 ? 8 : 16);\n\t\tcase MODE_KANJI:\n\t\t\treturn (ver < 10 ? 8 : ver < 27 ? 10 : 12);\n\t}\n};\n\n// returns the maximum length of data possible in given configuration.\nvar getmaxdatalen = function (ver, mode, ecclevel) {\n\tvar nbits = ndatabits(ver, ecclevel) - 4 - ndatalenbits(ver, mode); // 4 for mode bits\n\tswitch (mode) {\n\t\tcase MODE_NUMERIC:\n\t\t\treturn ((nbits / 10) | 0) * 3 + (nbits % 10 < 4 ? 0 : nbits % 10 < 7 ? 1 : 2);\n\t\tcase MODE_ALPHANUMERIC:\n\t\t\treturn ((nbits / 11) | 0) * 2 + (nbits % 11 < 6 ? 0 : 1);\n\t\tcase MODE_OCTET:\n\t\t\treturn (nbits / 8) | 0;\n\t\tcase MODE_KANJI:\n\t\t\treturn (nbits / 13) | 0;\n\t}\n};\n\n// checks if the given data can be encoded in given mode, and returns\n// the converted data for the further processing if possible. otherwise\n// returns null.\n//\n// this function does not check the length of data; it is a duty of\n// encode function below (as it depends on the version and ECC level too).\nvar validatedata = function (mode, data) {\n\tswitch (mode) {\n\t\tcase MODE_NUMERIC:\n\t\t\tif (!data.match(NUMERIC_REGEXP))\n\t\t\t\treturn null;\n\t\t\treturn data;\n\n\t\tcase MODE_ALPHANUMERIC:\n\t\t\tif (!data.match(ALPHANUMERIC_REGEXP))\n\t\t\t\treturn null;\n\t\t\treturn data.toUpperCase();\n\n\t\tcase MODE_OCTET:\n\t\t\tif (typeof data === 'string') { // encode as utf-8 string\n\t\t\t\tvar newdata = [];\n\t\t\t\tfor (var i = 0; i < data.length; ++i) {\n\t\t\t\t\tvar ch = data.charCodeAt(i);\n\t\t\t\t\tif (ch < 0x80) {\n\t\t\t\t\t\tnewdata.push(ch);\n\t\t\t\t\t} else if (ch < 0x800) {\n\t\t\t\t\t\tnewdata.push(0xc0 | (ch >> 6),\n\t\t\t\t\t\t\t0x80 | (ch & 0x3f));\n\t\t\t\t\t} else if (ch < 0x10000) {\n\t\t\t\t\t\tnewdata.push(0xe0 | (ch >> 12),\n\t\t\t\t\t\t\t0x80 | ((ch >> 6) & 0x3f),\n\t\t\t\t\t\t\t0x80 | (ch & 0x3f));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnewdata.push(0xf0 | (ch >> 18),\n\t\t\t\t\t\t\t0x80 | ((ch >> 12) & 0x3f),\n\t\t\t\t\t\t\t0x80 | ((ch >> 6) & 0x3f),\n\t\t\t\t\t\t\t0x80 | (ch & 0x3f));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn newdata;\n\t\t\t} else {\n\t\t\t\treturn data;\n\t\t\t}\n\t}\n};\n\n// returns the code words (sans ECC bits) for given data and configurations.\n// requires data to be preprocessed by validatedata. no length check is\n// performed, and everything has to be checked before calling this function.\nvar encode = function (ver, mode, data, maxbuflen) {\n\tvar buf = [];\n\tvar bits = 0, remaining = 8;\n\tvar datalen = data.length;\n\n\t// this function is intentionally no-op when n=0.\n\tvar pack = function (x, n) {\n\t\tif (n >= remaining) {\n\t\t\tbuf.push(bits | (x >> (n -= remaining)));\n\t\t\twhile (n >= 8)\n\t\t\t\tbuf.push((x >> (n -= 8)) & 255);\n\t\t\tbits = 0;\n\t\t\tremaining = 8;\n\t\t}\n\t\tif (n > 0)\n\t\t\tbits |= (x & ((1 << n) - 1)) << (remaining -= n);\n\t};\n\n\tvar nlenbits = ndatalenbits(ver, mode);\n\tpack(mode, 4);\n\tpack(datalen, nlenbits);\n\n\tswitch (mode) {\n\t\tcase MODE_NUMERIC:\n\t\t\tfor (var i = 2; i < datalen; i += 3) {\n\t\t\t\tpack(parseInt(data.substring(i - 2, i + 1), 10), 10);\n\t\t\t}\n\t\t\tpack(parseInt(data.substring(i - 2), 10), [0, 4, 7][datalen % 3]);\n\t\t\tbreak;\n\n\t\tcase MODE_ALPHANUMERIC:\n\t\t\tfor (var i = 1; i < datalen; i += 2) {\n\t\t\t\tpack(ALPHANUMERIC_MAP[data.charAt(i - 1)] * 45 +\n\t\t\t\t\tALPHANUMERIC_MAP[data.charAt(i)], 11);\n\t\t\t}\n\t\t\tif (datalen % 2 == 1) {\n\t\t\t\tpack(ALPHANUMERIC_MAP[data.charAt(i - 1)], 6);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase MODE_OCTET:\n\t\t\tfor (var i = 0; i < datalen; ++i) {\n\t\t\t\tpack(data[i], 8);\n\t\t\t}\n\t\t\tbreak;\n\t}\n\n\t// final bits. it is possible that adding terminator causes the buffer\n\t// to overflow, but then the buffer truncated to the maximum size will\n\t// be valid as the truncated terminator mode bits and padding is\n\t// identical in appearance (cf. JIS X 0510:2004 sec 8.4.8).\n\tpack(MODE_TERMINATOR, 4);\n\tif (remaining < 8)\n\t\tbuf.push(bits);\n\n\t// the padding to fill up the remaining space. we should not add any\n\t// words when the overflow already occurred.\n\twhile (buf.length + 1 < maxbuflen)\n\t\tbuf.push(0xec, 0x11);\n\tif (buf.length < maxbuflen)\n\t\tbuf.push(0xec);\n\treturn buf;\n};\n\n// calculates ECC code words for given code words and generator polynomial.\n//\n// this is quite similar to CRC calculation as both Reed-Solomon and CRC use\n// the certain kind of cyclic codes, which is effectively the division of\n// zero-augumented polynomial by the generator polynomial. the only difference\n// is that Reed-Solomon uses GF(2^8), instead of CRC's GF(2), and Reed-Solomon\n// uses the different generator polynomial than CRC's.\nvar calculateecc = function (poly, genpoly) {\n\tvar modulus = poly.slice(0);\n\tvar polylen = poly.length, genpolylen = genpoly.length;\n\tfor (var i = 0; i < genpolylen; ++i)\n\t\tmodulus.push(0);\n\tfor (var i = 0; i < polylen; ) {\n\t\tvar quotient = GF256_INVMAP[modulus[i++]];\n\t\tif (quotient >= 0) {\n\t\t\tfor (var j = 0; j < genpolylen; ++j) {\n\t\t\t\tmodulus[i + j] ^= GF256_MAP[(quotient + genpoly[j]) % 255];\n\t\t\t}\n\t\t}\n\t}\n\treturn modulus.slice(polylen);\n};\n\n// auguments ECC code words to given code words. the resulting words are\n// ready to be encoded in the matrix.\n//\n// the much of actual augumenting procedure follows JIS X 0510:2004 sec 8.7.\n// the code is simplified using the fact that the size of each code & ECC\n// blocks is almost same; for example, when we have 4 blocks and 46 data words\n// the number of code words in those blocks are 11, 11, 12, 12 respectively.\nvar augumenteccs = function (poly, nblocks, genpoly) {\n\tvar subsizes = [];\n\tvar subsize = (poly.length / nblocks) | 0, subsize0 = 0;\n\tvar pivot = nblocks - poly.length % nblocks;\n\tfor (var i = 0; i < pivot; ++i) {\n\t\tsubsizes.push(subsize0);\n\t\tsubsize0 += subsize;\n\t}\n\tfor (var i = pivot; i < nblocks; ++i) {\n\t\tsubsizes.push(subsize0);\n\t\tsubsize0 += subsize + 1;\n\t}\n\tsubsizes.push(subsize0);\n\n\tvar eccs = [];\n\tfor (var i = 0; i < nblocks; ++i) {\n\t\teccs.push(calculateecc(poly.slice(subsizes[i], subsizes[i + 1]), genpoly));\n\t}\n\n\tvar result = [];\n\tvar nitemsperblock = (poly.length / nblocks) | 0;\n\tfor (var i = 0; i < nitemsperblock; ++i) {\n\t\tfor (var j = 0; j < nblocks; ++j) {\n\t\t\tresult.push(poly[subsizes[j] + i]);\n\t\t}\n\t}\n\tfor (var j = pivot; j < nblocks; ++j) {\n\t\tresult.push(poly[subsizes[j + 1] - 1]);\n\t}\n\tfor (var i = 0; i < genpoly.length; ++i) {\n\t\tfor (var j = 0; j < nblocks; ++j) {\n\t\t\tresult.push(eccs[j][i]);\n\t\t}\n\t}\n\treturn result;\n};\n\n// auguments BCH(p+q,q) code to the polynomial over GF(2), given the proper\n// genpoly. the both input and output are in binary numbers, and unlike\n// calculateecc genpoly should include the 1 bit for the highest degree.\n//\n// actual polynomials used for this procedure are as follows:\n// - p=10, q=5, genpoly=x^10+x^8+x^5+x^4+x^2+x+1 (JIS X 0510:2004 Appendix C)\n// - p=18, q=6, genpoly=x^12+x^11+x^10+x^9+x^8+x^5+x^2+1 (ibid. Appendix D)\nvar augumentbch = function (poly, p, genpoly, q) {\n\tvar modulus = poly << q;\n\tfor (var i = p - 1; i >= 0; --i) {\n\t\tif ((modulus >> (q + i)) & 1)\n\t\t\tmodulus ^= genpoly << i;\n\t}\n\treturn (poly << q) | modulus;\n};\n\n// creates the base matrix for given version. it returns two matrices, one of\n// them is the actual one and the another represents the \"reserved\" portion\n// (e.g. finder and timing patterns) of the matrix.\n//\n// some entries in the matrix may be undefined, rather than 0 or 1. this is\n// intentional (no initialization needed!), and putdata below will fill\n// the remaining ones.\nvar makebasematrix = function (ver) {\n\tvar v = VERSIONS[ver], n = getsizebyver(ver);\n\tvar matrix = [], reserved = [];\n\tfor (var i = 0; i < n; ++i) {\n\t\tmatrix.push([]);\n\t\treserved.push([]);\n\t}\n\n\tvar blit = function (y, x, h, w, bits) {\n\t\tfor (var i = 0; i < h; ++i) {\n\t\t\tfor (var j = 0; j < w; ++j) {\n\t\t\t\tmatrix[y + i][x + j] = (bits[i] >> j) & 1;\n\t\t\t\treserved[y + i][x + j] = 1;\n\t\t\t}\n\t\t}\n\t};\n\n\t// finder patterns and a part of timing patterns\n\t// will also mark the format information area (not yet written) as reserved.\n\tblit(0, 0, 9, 9, [0x7f, 0x41, 0x5d, 0x5d, 0x5d, 0x41, 0x17f, 0x00, 0x40]);\n\tblit(n - 8, 0, 8, 9, [0x100, 0x7f, 0x41, 0x5d, 0x5d, 0x5d, 0x41, 0x7f]);\n\tblit(0, n - 8, 9, 8, [0xfe, 0x82, 0xba, 0xba, 0xba, 0x82, 0xfe, 0x00, 0x00]);\n\n\t// the rest of timing patterns\n\tfor (var i = 9; i < n - 8; ++i) {\n\t\tmatrix[6][i] = matrix[i][6] = ~i & 1;\n\t\treserved[6][i] = reserved[i][6] = 1;\n\t}\n\n\t// alignment patterns\n\tvar aligns = v[2], m = aligns.length;\n\tfor (var i = 0; i < m; ++i) {\n\t\tvar minj = (i === 0 || i === m - 1 ? 1 : 0), maxj = (i === 0 ? m - 1 : m);\n\t\tfor (var j = minj; j < maxj; ++j) {\n\t\t\tblit(aligns[i], aligns[j], 5, 5, [0x1f, 0x11, 0x15, 0x11, 0x1f]);\n\t\t}\n\t}\n\n\t// version information\n\tif (needsverinfo(ver)) {\n\t\tvar code = augumentbch(ver, 6, 0x1f25, 12);\n\t\tvar k = 0;\n\t\tfor (var i = 0; i < 6; ++i) {\n\t\t\tfor (var j = 0; j < 3; ++j) {\n\t\t\t\tmatrix[i][(n - 11) + j] = matrix[(n - 11) + j][i] = (code >> k++) & 1;\n\t\t\t\treserved[i][(n - 11) + j] = reserved[(n - 11) + j][i] = 1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {matrix: matrix, reserved: reserved};\n};\n\n// fills the data portion (i.e. unmarked in reserved) of the matrix with given\n// code words. the size of code words should be no more than available bits,\n// and remaining bits are padded to 0 (cf. JIS X 0510:2004 sec 8.7.3).\nvar putdata = function (matrix, reserved, buf) {\n\tvar n = matrix.length;\n\tvar k = 0, dir = -1;\n\tfor (var i = n - 1; i >= 0; i -= 2) {\n\t\tif (i == 6)\n\t\t\t--i; // skip the entire timing pattern column\n\t\tvar jj = (dir < 0 ? n - 1 : 0);\n\t\tfor (var j = 0; j < n; ++j) {\n\t\t\tfor (var ii = i; ii > i - 2; --ii) {\n\t\t\t\tif (!reserved[jj][ii]) {\n\t\t\t\t\t// may overflow, but (undefined >> x)\n\t\t\t\t\t// is 0 so it will auto-pad to zero.\n\t\t\t\t\tmatrix[jj][ii] = (buf[k >> 3] >> (~k & 7)) & 1;\n\t\t\t\t\t++k;\n\t\t\t\t}\n\t\t\t}\n\t\t\tjj += dir;\n\t\t}\n\t\tdir = -dir;\n\t}\n\treturn matrix;\n};\n\n// XOR-masks the data portion of the matrix. repeating the call with the same\n// arguments will revert the prior call (convenient in the matrix evaluation).\nvar maskdata = function (matrix, reserved, mask) {\n\tvar maskf = MASKFUNCS[mask];\n\tvar n = matrix.length;\n\tfor (var i = 0; i < n; ++i) {\n\t\tfor (var j = 0; j < n; ++j) {\n\t\t\tif (!reserved[i][j])\n\t\t\t\tmatrix[i][j] ^= maskf(i, j);\n\t\t}\n\t}\n\treturn matrix;\n};\n\n// puts the format information.\nvar putformatinfo = function (matrix, reserved, ecclevel, mask) {\n\tvar n = matrix.length;\n\tvar code = augumentbch((ecclevel << 3) | mask, 5, 0x537, 10) ^ 0x5412;\n\tfor (var i = 0; i < 15; ++i) {\n\t\tvar r = [0, 1, 2, 3, 4, 5, 7, 8, n - 7, n - 6, n - 5, n - 4, n - 3, n - 2, n - 1][i];\n\t\tvar c = [n - 1, n - 2, n - 3, n - 4, n - 5, n - 6, n - 7, n - 8, 7, 5, 4, 3, 2, 1, 0][i];\n\t\tmatrix[r][8] = matrix[8][c] = (code >> i) & 1;\n\t\t// we don't have to mark those bits reserved; always done\n\t\t// in makebasematrix above.\n\t}\n\treturn matrix;\n};\n\n// evaluates the resulting matrix and returns the score (lower is better).\n// (cf. JIS X 0510:2004 sec 8.8.2)\n//\n// the evaluation procedure tries to avoid the problematic patterns naturally\n// occuring from the original matrix. for example, it penaltizes the patterns\n// which just look like the finder pattern which will confuse the decoder.\n// we choose the mask which results in the lowest score among 8 possible ones.\n//\n// note: zxing seems to use the same procedure and in many cases its choice\n// agrees to ours, but sometimes it does not. practically it doesn't matter.\nvar evaluatematrix = function (matrix) {\n\t// N1+(k-5) points for each consecutive row of k same-colored modules,\n\t// where k >= 5. no overlapping row counts.\n\tvar PENALTY_CONSECUTIVE = 3;\n\t// N2 points for each 2x2 block of same-colored modules.\n\t// overlapping block does count.\n\tvar PENALTY_TWOBYTWO = 3;\n\t// N3 points for each pattern with >4W:1B:1W:3B:1W:1B or\n\t// 1B:1W:3B:1W:1B:>4W, or their multiples (e.g. highly unlikely,\n\t// but 13W:3B:3W:9B:3W:3B counts).\n\tvar PENALTY_FINDERLIKE = 40;\n\t// N4*k points for every (5*k)% deviation from 50% black density.\n\t// i.e. k=1 for 55~60% and 40~45%, k=2 for 60~65% and 35~40%, etc.\n\tvar PENALTY_DENSITY = 10;\n\n\tvar evaluategroup = function (groups) { // assumes [W,B,W,B,W,...,B,W]\n\t\tvar score = 0;\n\t\tfor (var i = 0; i < groups.length; ++i) {\n\t\t\tif (groups[i] >= 5)\n\t\t\t\tscore += PENALTY_CONSECUTIVE + (groups[i] - 5);\n\t\t}\n\t\tfor (var i = 5; i < groups.length; i += 2) {\n\t\t\tvar p = groups[i];\n\t\t\tif (groups[i - 1] == p && groups[i - 2] == 3 * p && groups[i - 3] == p &&\n\t\t\t\tgroups[i - 4] == p && (groups[i - 5] >= 4 * p || groups[i + 1] >= 4 * p)) {\n\t\t\t\t// this part differs from zxing...\n\t\t\t\tscore += PENALTY_FINDERLIKE;\n\t\t\t}\n\t\t}\n\t\treturn score;\n\t};\n\n\tvar n = matrix.length;\n\tvar score = 0, nblacks = 0;\n\tfor (var i = 0; i < n; ++i) {\n\t\tvar row = matrix[i];\n\t\tvar groups;\n\n\t\t// evaluate the current row\n\t\tgroups = [0]; // the first empty group of white\n\t\tfor (var j = 0; j < n; ) {\n\t\t\tvar k;\n\t\t\tfor (k = 0; j < n && row[j]; ++k)\n\t\t\t\t++j;\n\t\t\tgroups.push(k);\n\t\t\tfor (k = 0; j < n && !row[j]; ++k)\n\t\t\t\t++j;\n\t\t\tgroups.push(k);\n\t\t}\n\t\tscore += evaluategroup(groups);\n\n\t\t// evaluate the current column\n\t\tgroups = [0];\n\t\tfor (var j = 0; j < n; ) {\n\t\t\tvar k;\n\t\t\tfor (k = 0; j < n && matrix[j][i]; ++k)\n\t\t\t\t++j;\n\t\t\tgroups.push(k);\n\t\t\tfor (k = 0; j < n && !matrix[j][i]; ++k)\n\t\t\t\t++j;\n\t\t\tgroups.push(k);\n\t\t}\n\t\tscore += evaluategroup(groups);\n\n\t\t// check the 2x2 box and calculate the density\n\t\tvar nextrow = matrix[i + 1] || [];\n\t\tnblacks += row[0];\n\t\tfor (var j = 1; j < n; ++j) {\n\t\t\tvar p = row[j];\n\t\t\tnblacks += p;\n\t\t\t// at least comparison with next row should be strict...\n\t\t\tif (row[j - 1] == p && nextrow[j] === p && nextrow[j - 1] === p) {\n\t\t\t\tscore += PENALTY_TWOBYTWO;\n\t\t\t}\n\t\t}\n\t}\n\n\tscore += PENALTY_DENSITY * ((Math.abs(nblacks / n / n - 0.5) / 0.05) | 0);\n\treturn score;\n};\n\n// returns the fully encoded QR code matrix which contains given data.\n// it also chooses the best mask automatically when mask is -1.\nvar generate = function (data, ver, mode, ecclevel, mask) {\n\tvar v = VERSIONS[ver];\n\tvar buf = encode(ver, mode, data, ndatabits(ver, ecclevel) >> 3);\n\tbuf = augumenteccs(buf, v[1][ecclevel], GF256_GENPOLY[v[0][ecclevel]]);\n\n\tvar result = makebasematrix(ver);\n\tvar matrix = result.matrix, reserved = result.reserved;\n\tputdata(matrix, reserved, buf);\n\n\tif (mask < 0) {\n\t\t// find the best mask\n\t\tmaskdata(matrix, reserved, 0);\n\t\tputformatinfo(matrix, reserved, ecclevel, 0);\n\t\tvar bestmask = 0, bestscore = evaluatematrix(matrix);\n\t\tmaskdata(matrix, reserved, 0);\n\t\tfor (mask = 1; mask < 8; ++mask) {\n\t\t\tmaskdata(matrix, reserved, mask);\n\t\t\tputformatinfo(matrix, reserved, ecclevel, mask);\n\t\t\tvar score = evaluatematrix(matrix);\n\t\t\tif (bestscore > score) {\n\t\t\t\tbestscore = score;\n\t\t\t\tbestmask = mask;\n\t\t\t}\n\t\t\tmaskdata(matrix, reserved, mask);\n\t\t}\n\t\tmask = bestmask;\n\t}\n\n\tmaskdata(matrix, reserved, mask);\n\tputformatinfo(matrix, reserved, ecclevel, mask);\n\treturn matrix;\n};\n\n// the public interface is trivial; the options available are as follows:\n//\n// - version: an integer in [1,40]. when omitted (or -1) the smallest possible\n//   version is chosen.\n// - mode: one of 'numeric', 'alphanumeric', 'octet'. when omitted the smallest\n//   possible mode is chosen.\n// - eccLevel: one of 'L', 'M', 'Q', 'H'. defaults to 'L'.\n// - mask: an integer in [0,7]. when omitted (or -1) the best mask is chosen.\n//\n\nfunction generateFrame(data, options) {\n\tvar MODES = {'numeric': MODE_NUMERIC, 'alphanumeric': MODE_ALPHANUMERIC,\n\t\t'octet': MODE_OCTET};\n\tvar ECCLEVELS = {'L': ECCLEVEL_L, 'M': ECCLEVEL_M, 'Q': ECCLEVEL_Q,\n\t\t'H': ECCLEVEL_H};\n\n\toptions = options || {};\n\tvar ver = options.version || -1;\n\tvar ecclevel = ECCLEVELS[(options.eccLevel || 'L').toUpperCase()];\n\tvar mode = options.mode ? MODES[options.mode.toLowerCase()] : -1;\n\tvar mask = 'mask' in options ? options.mask : -1;\n\n\tif (mode < 0) {\n\t\tif (typeof data === 'string') {\n\t\t\tif (data.match(NUMERIC_REGEXP)) {\n\t\t\t\tmode = MODE_NUMERIC;\n\t\t\t} else if (data.match(ALPHANUMERIC_OUT_REGEXP)) {\n\t\t\t\t// while encode supports case-insensitive encoding, we restrict the data to be uppercased when auto-selecting the mode.\n\t\t\t\tmode = MODE_ALPHANUMERIC;\n\t\t\t} else {\n\t\t\t\tmode = MODE_OCTET;\n\t\t\t}\n\t\t} else {\n\t\t\tmode = MODE_OCTET;\n\t\t}\n\t} else if (!(mode == MODE_NUMERIC || mode == MODE_ALPHANUMERIC ||\n\t\tmode == MODE_OCTET)) {\n\t\tthrow 'invalid or unsupported mode';\n\t}\n\n\tdata = validatedata(mode, data);\n\tif (data === null)\n\t\tthrow 'invalid data format';\n\n\tif (ecclevel < 0 || ecclevel > 3)\n\t\tthrow 'invalid ECC level';\n\n\tif (ver < 0) {\n\t\tfor (ver = 1; ver <= 40; ++ver) {\n\t\t\tif (data.length <= getmaxdatalen(ver, mode, ecclevel))\n\t\t\t\tbreak;\n\t\t}\n\t\tif (ver > 40)\n\t\t\tthrow 'too large data for the Qr format';\n\t} else if (ver < 1 || ver > 40) {\n\t\tthrow 'invalid Qr version! should be between 1 and 40';\n\t}\n\n\tif (mask != -1 && (mask < 0 || mask > 8))\n\t\tthrow 'invalid mask';\n\t//console.log('version:', ver, 'mode:', mode, 'ECC:', ecclevel, 'mask:', mask )\n\treturn generate(data, ver, mode, ecclevel, mask);\n}\n\n\n// options\n// - modulesize: a number. this is a size of each modules in pixels, and\n//   defaults to 5px.\n// - margin: a number. this is a size of margin in *modules*, and defaults to\n//   4 (white modules). the specficiation mandates the margin no less than 4\n//   modules, so it is better not to alter this value unless you know what\n//   you're doing.\nfunction buildCanvas(data, options) {\n\n\tvar canvas = [];\n\tvar background = options.background || '#fff';\n\tvar foreground = options.foreground || '#000';\n\t//var margin = options.margin || 4;\n\tvar matrix = generateFrame(data, options);\n\tvar n = matrix.length;\n\tvar modSize = Math.floor(options.fit ? options.fit / n : 5);\n\tvar size = n * modSize;\n\n\tcanvas.push({\n\t\ttype: 'rect',\n\t\tx: 0, y: 0, w: size, h: size, lineWidth: 0, color: background\n\t});\n\n\tfor (var i = 0; i < n; ++i) {\n\t\tfor (var j = 0; j < n; ++j) {\n\t\t\tif (matrix[i][j]) {\n\t\t\t\tcanvas.push({\n\t\t\t\t\ttype: 'rect',\n\t\t\t\t\tx: modSize * j,\n\t\t\t\t\ty: modSize * i,\n\t\t\t\t\tw: modSize,\n\t\t\t\t\th: modSize,\n\t\t\t\t\tlineWidth: 0,\n\t\t\t\t\tcolor: foreground\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tcanvas: canvas,\n\t\tsize: size\n\t};\n\n}\n\nfunction measure(node) {\n\tvar cd = buildCanvas(node.qr, node);\n\tnode._canvas = cd.canvas;\n\tnode._width = node._height = node._minWidth = node._maxWidth = node._minHeight = node._maxHeight = cd.size;\n\treturn node;\n}\n\nmodule.exports = {\n\tmeasure: measure\n};\n\n/***/ }),\n/* 135 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar ElementWriter = __webpack_require__(136);\n\n/**\n * Creates an instance of PageElementWriter - an extended ElementWriter\n * which can handle:\n * - page-breaks (it adds new pages when there's not enough space left),\n * - repeatable fragments (like table-headers, which are repeated everytime\n *                         a page-break occurs)\n * - transactions (used for unbreakable-blocks when we want to make sure\n *                 whole block will be rendered on the same page)\n */\nfunction PageElementWriter(context, tracker) {\n\tthis.transactionLevel = 0;\n\tthis.repeatables = [];\n\tthis.tracker = tracker;\n\tthis.writer = new ElementWriter(context, tracker);\n}\n\nfunction fitOnPage(self, addFct) {\n\tvar position = addFct(self);\n\tif (!position) {\n\t\tself.moveToNextPage();\n\t\tposition = addFct(self);\n\t}\n\treturn position;\n}\n\nPageElementWriter.prototype.addLine = function (line, dontUpdateContextPosition, index) {\n\treturn fitOnPage(this, function (self) {\n\t\treturn self.writer.addLine(line, dontUpdateContextPosition, index);\n\t});\n};\n\nPageElementWriter.prototype.addImage = function (image, index) {\n\treturn fitOnPage(this, function (self) {\n\t\treturn self.writer.addImage(image, index);\n\t});\n};\n\nPageElementWriter.prototype.addQr = function (qr, index) {\n\treturn fitOnPage(this, function (self) {\n\t\treturn self.writer.addQr(qr, index);\n\t});\n};\n\nPageElementWriter.prototype.addVector = function (vector, ignoreContextX, ignoreContextY, index) {\n\treturn this.writer.addVector(vector, ignoreContextX, ignoreContextY, index);\n};\n\nPageElementWriter.prototype.beginClip = function (width, height) {\n\treturn this.writer.beginClip(width, height);\n};\n\nPageElementWriter.prototype.endClip = function () {\n\treturn this.writer.endClip();\n};\n\nPageElementWriter.prototype.alignCanvas = function (node) {\n\tthis.writer.alignCanvas(node);\n};\n\nPageElementWriter.prototype.addFragment = function (fragment, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition) {\n\tif (!this.writer.addFragment(fragment, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition)) {\n\t\tthis.moveToNextPage();\n\t\tthis.writer.addFragment(fragment, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition);\n\t}\n};\n\nPageElementWriter.prototype.moveToNextPage = function (pageOrientation) {\n\n\tvar nextPage = this.writer.context.moveToNextPage(pageOrientation);\n\n\tif (nextPage.newPageCreated) {\n\t\tthis.repeatables.forEach(function (rep) {\n\t\t\tthis.writer.addFragment(rep, true);\n\t\t}, this);\n\t} else {\n\t\tthis.repeatables.forEach(function (rep) {\n\t\t\tthis.writer.context.moveDown(rep.height);\n\t\t}, this);\n\t}\n\n\tthis.writer.tracker.emit('pageChanged', {\n\t\tprevPage: nextPage.prevPage,\n\t\tprevY: nextPage.prevY,\n\t\ty: nextPage.y\n\t});\n};\n\nPageElementWriter.prototype.beginUnbreakableBlock = function (width, height) {\n\tif (this.transactionLevel++ === 0) {\n\t\tthis.originalX = this.writer.context.x;\n\t\tthis.writer.pushContext(width, height);\n\t}\n};\n\nPageElementWriter.prototype.commitUnbreakableBlock = function (forcedX, forcedY) {\n\tif (--this.transactionLevel === 0) {\n\t\tvar unbreakableContext = this.writer.context;\n\t\tthis.writer.popContext();\n\n\t\tvar nbPages = unbreakableContext.pages.length;\n\t\tif (nbPages > 0) {\n\t\t\t// no support for multi-page unbreakableBlocks\n\t\t\tvar fragment = unbreakableContext.pages[0];\n\t\t\tfragment.xOffset = forcedX;\n\t\t\tfragment.yOffset = forcedY;\n\n\t\t\t//TODO: vectors can influence height in some situations\n\t\t\tif (nbPages > 1) {\n\t\t\t\t// on out-of-context blocs (headers, footers, background) height should be the whole DocumentContext height\n\t\t\t\tif (forcedX !== undefined || forcedY !== undefined) {\n\t\t\t\t\tfragment.height = unbreakableContext.getCurrentPage().pageSize.height - unbreakableContext.pageMargins.top - unbreakableContext.pageMargins.bottom;\n\t\t\t\t} else {\n\t\t\t\t\tfragment.height = this.writer.context.getCurrentPage().pageSize.height - this.writer.context.pageMargins.top - this.writer.context.pageMargins.bottom;\n\t\t\t\t\tfor (var i = 0, l = this.repeatables.length; i < l; i++) {\n\t\t\t\t\t\tfragment.height -= this.repeatables[i].height;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfragment.height = unbreakableContext.y;\n\t\t\t}\n\n\t\t\tif (forcedX !== undefined || forcedY !== undefined) {\n\t\t\t\tthis.writer.addFragment(fragment, true, true, true);\n\t\t\t} else {\n\t\t\t\tthis.addFragment(fragment);\n\t\t\t}\n\t\t}\n\t}\n};\n\nPageElementWriter.prototype.currentBlockToRepeatable = function () {\n\tvar unbreakableContext = this.writer.context;\n\tvar rep = {items: []};\n\n\tunbreakableContext.pages[0].items.forEach(function (item) {\n\t\trep.items.push(item);\n\t});\n\n\trep.xOffset = this.originalX;\n\n\t//TODO: vectors can influence height in some situations\n\trep.height = unbreakableContext.y;\n\n\treturn rep;\n};\n\nPageElementWriter.prototype.pushToRepeatables = function (rep) {\n\tthis.repeatables.push(rep);\n};\n\nPageElementWriter.prototype.popFromRepeatables = function () {\n\tthis.repeatables.pop();\n};\n\nPageElementWriter.prototype.context = function () {\n\treturn this.writer.context;\n};\n\nmodule.exports = PageElementWriter;\n\n\n/***/ }),\n/* 136 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar Line = __webpack_require__(82);\nvar isNumber = __webpack_require__(0).isNumber;\nvar pack = __webpack_require__(0).pack;\nvar offsetVector = __webpack_require__(0).offsetVector;\nvar DocumentContext = __webpack_require__(81);\n\n/**\n * Creates an instance of ElementWriter - a line/vector writer, which adds\n * elements to current page and sets their positions based on the context\n */\nfunction ElementWriter(context, tracker) {\n\tthis.context = context;\n\tthis.contextStack = [];\n\tthis.tracker = tracker;\n}\n\nfunction addPageItem(page, item, index) {\n\tif (index === null || index === undefined || index < 0 || index > page.items.length) {\n\t\tpage.items.push(item);\n\t} else {\n\t\tpage.items.splice(index, 0, item);\n\t}\n}\n\nElementWriter.prototype.addLine = function (line, dontUpdateContextPosition, index) {\n\tvar height = line.getHeight();\n\tvar context = this.context;\n\tvar page = context.getCurrentPage(),\n\t\tposition = this.getCurrentPositionOnPage();\n\n\tif (context.availableHeight < height || !page) {\n\t\treturn false;\n\t}\n\n\tline.x = context.x + (line.x || 0);\n\tline.y = context.y + (line.y || 0);\n\n\tthis.alignLine(line);\n\n\taddPageItem(page, {\n\t\ttype: 'line',\n\t\titem: line\n\t}, index);\n\tthis.tracker.emit('lineAdded', line);\n\n\tif (!dontUpdateContextPosition) {\n\t\tcontext.moveDown(height);\n\t}\n\n\treturn position;\n};\n\nElementWriter.prototype.alignLine = function (line) {\n\tvar width = this.context.availableWidth;\n\tvar lineWidth = line.getWidth();\n\n\tvar alignment = line.inlines && line.inlines.length > 0 && line.inlines[0].alignment;\n\n\tvar offset = 0;\n\tswitch (alignment) {\n\t\tcase 'right':\n\t\t\toffset = width - lineWidth;\n\t\t\tbreak;\n\t\tcase 'center':\n\t\t\toffset = (width - lineWidth) / 2;\n\t\t\tbreak;\n\t}\n\n\tif (offset) {\n\t\tline.x = (line.x || 0) + offset;\n\t}\n\n\tif (alignment === 'justify' &&\n\t\t!line.newLineForced &&\n\t\t!line.lastLineInParagraph &&\n\t\tline.inlines.length > 1) {\n\t\tvar additionalSpacing = (width - lineWidth) / (line.inlines.length - 1);\n\n\t\tfor (var i = 1, l = line.inlines.length; i < l; i++) {\n\t\t\toffset = i * additionalSpacing;\n\n\t\t\tline.inlines[i].x += offset;\n\t\t\tline.inlines[i].justifyShift = additionalSpacing;\n\t\t}\n\t}\n};\n\nElementWriter.prototype.addImage = function (image, index) {\n\tvar context = this.context;\n\tvar page = context.getCurrentPage(),\n\t\tposition = this.getCurrentPositionOnPage();\n\n\tif (!page || (image.absolutePosition === undefined && context.availableHeight < image._height && page.items.length > 0)) {\n\t\treturn false;\n\t}\n\n\tif (image._x === undefined) {\n\t\timage._x = image.x || 0;\n\t}\n\n\timage.x = context.x + image._x;\n\timage.y = context.y;\n\n\tthis.alignImage(image);\n\n\taddPageItem(page, {\n\t\ttype: 'image',\n\t\titem: image\n\t}, index);\n\n\tcontext.moveDown(image._height);\n\n\treturn position;\n};\n\nElementWriter.prototype.addQr = function (qr, index) {\n\tvar context = this.context;\n\tvar page = context.getCurrentPage(),\n\t\tposition = this.getCurrentPositionOnPage();\n\n\tif (!page || (qr.absolutePosition === undefined && context.availableHeight < qr._height)) {\n\t\treturn false;\n\t}\n\n\tif (qr._x === undefined) {\n\t\tqr._x = qr.x || 0;\n\t}\n\n\tqr.x = context.x + qr._x;\n\tqr.y = context.y;\n\n\tthis.alignImage(qr);\n\n\tfor (var i = 0, l = qr._canvas.length; i < l; i++) {\n\t\tvar vector = qr._canvas[i];\n\t\tvector.x += qr.x;\n\t\tvector.y += qr.y;\n\t\tthis.addVector(vector, true, true, index);\n\t}\n\n\tcontext.moveDown(qr._height);\n\n\treturn position;\n};\n\nElementWriter.prototype.alignImage = function (image) {\n\tvar width = this.context.availableWidth;\n\tvar imageWidth = image._minWidth;\n\tvar offset = 0;\n\tswitch (image._alignment) {\n\t\tcase 'right':\n\t\t\toffset = width - imageWidth;\n\t\t\tbreak;\n\t\tcase 'center':\n\t\t\toffset = (width - imageWidth) / 2;\n\t\t\tbreak;\n\t}\n\n\tif (offset) {\n\t\timage.x = (image.x || 0) + offset;\n\t}\n};\n\nElementWriter.prototype.alignCanvas = function (node) {\n\tvar width = this.context.availableWidth;\n\tvar canvasWidth = node._minWidth;\n\tvar offset = 0;\n\tswitch (node._alignment) {\n\t\tcase 'right':\n\t\t\toffset = width - canvasWidth;\n\t\t\tbreak;\n\t\tcase 'center':\n\t\t\toffset = (width - canvasWidth) / 2;\n\t\t\tbreak;\n\t}\n\tif (offset) {\n\t\tnode.canvas.forEach(function (vector) {\n\t\t\toffsetVector(vector, offset, 0);\n\t\t});\n\t}\n};\n\nElementWriter.prototype.addVector = function (vector, ignoreContextX, ignoreContextY, index) {\n\tvar context = this.context;\n\tvar page = context.getCurrentPage(),\n\t\tposition = this.getCurrentPositionOnPage();\n\n\tif (page) {\n\t\toffsetVector(vector, ignoreContextX ? 0 : context.x, ignoreContextY ? 0 : context.y);\n\t\taddPageItem(page, {\n\t\t\ttype: 'vector',\n\t\t\titem: vector\n\t\t}, index);\n\t\treturn position;\n\t}\n};\n\nElementWriter.prototype.beginClip = function (width, height) {\n\tvar ctx = this.context;\n\tvar page = ctx.getCurrentPage();\n\tpage.items.push({\n\t\ttype: 'beginClip',\n\t\titem: {x: ctx.x, y: ctx.y, width: width, height: height}\n\t});\n\treturn true;\n};\n\nElementWriter.prototype.endClip = function () {\n\tvar ctx = this.context;\n\tvar page = ctx.getCurrentPage();\n\tpage.items.push({\n\t\ttype: 'endClip'\n\t});\n\treturn true;\n};\n\nfunction cloneLine(line) {\n\tvar result = new Line(line.maxWidth);\n\n\tfor (var key in line) {\n\t\tif (line.hasOwnProperty(key)) {\n\t\t\tresult[key] = line[key];\n\t\t}\n\t}\n\n\treturn result;\n}\n\nElementWriter.prototype.addFragment = function (block, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition) {\n\tvar ctx = this.context;\n\tvar page = ctx.getCurrentPage();\n\n\tif (!useBlockXOffset && block.height > ctx.availableHeight) {\n\t\treturn false;\n\t}\n\n\tblock.items.forEach(function (item) {\n\t\tswitch (item.type) {\n\t\t\tcase 'line':\n\t\t\t\tvar l = cloneLine(item.item);\n\n\t\t\t\tl.x = (l.x || 0) + (useBlockXOffset ? (block.xOffset || 0) : ctx.x);\n\t\t\t\tl.y = (l.y || 0) + (useBlockYOffset ? (block.yOffset || 0) : ctx.y);\n\n\t\t\t\tpage.items.push({\n\t\t\t\t\ttype: 'line',\n\t\t\t\t\titem: l\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase 'vector':\n\t\t\t\tvar v = pack(item.item);\n\n\t\t\t\toffsetVector(v, useBlockXOffset ? (block.xOffset || 0) : ctx.x, useBlockYOffset ? (block.yOffset || 0) : ctx.y);\n\t\t\t\tpage.items.push({\n\t\t\t\t\ttype: 'vector',\n\t\t\t\t\titem: v\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase 'image':\n\t\t\t\tvar img = pack(item.item);\n\n\t\t\t\timg.x = (img.x || 0) + (useBlockXOffset ? (block.xOffset || 0) : ctx.x);\n\t\t\t\timg.y = (img.y || 0) + (useBlockYOffset ? (block.yOffset || 0) : ctx.y);\n\n\t\t\t\tpage.items.push({\n\t\t\t\t\ttype: 'image',\n\t\t\t\t\titem: img\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t}\n\t});\n\n\tif (!dontUpdateContextPosition) {\n\t\tctx.moveDown(block.height);\n\t}\n\n\treturn true;\n};\n\n/**\n * Pushes the provided context onto the stack or creates a new one\n *\n * pushContext(context) - pushes the provided context and makes it current\n * pushContext(width, height) - creates and pushes a new context with the specified width and height\n * pushContext() - creates a new context for unbreakable blocks (with current availableWidth and full-page-height)\n */\nElementWriter.prototype.pushContext = function (contextOrWidth, height) {\n\tif (contextOrWidth === undefined) {\n\t\theight = this.context.getCurrentPage().height - this.context.pageMargins.top - this.context.pageMargins.bottom;\n\t\tcontextOrWidth = this.context.availableWidth;\n\t}\n\n\tif (isNumber(contextOrWidth)) {\n\t\tcontextOrWidth = new DocumentContext({width: contextOrWidth, height: height}, {left: 0, right: 0, top: 0, bottom: 0});\n\t}\n\n\tthis.contextStack.push(this.context);\n\tthis.context = contextOrWidth;\n};\n\nElementWriter.prototype.popContext = function () {\n\tthis.context = this.contextStack.pop();\n};\n\nElementWriter.prototype.getCurrentPositionOnPage = function () {\n\treturn (this.contextStack[0] || this.context).getCurrentPosition();\n};\n\n\nmodule.exports = ElementWriter;\n\n\n/***/ }),\n/* 137 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar ColumnCalculator = __webpack_require__(44);\nvar isFunction = __webpack_require__(0).isFunction;\n\nfunction TableProcessor(tableNode) {\n\tthis.tableNode = tableNode;\n}\n\nTableProcessor.prototype.beginTable = function (writer) {\n\tvar tableNode;\n\tvar availableWidth;\n\tvar self = this;\n\n\ttableNode = this.tableNode;\n\tthis.offsets = tableNode._offsets;\n\tthis.layout = tableNode._layout;\n\n\tavailableWidth = writer.context().availableWidth - this.offsets.total;\n\tColumnCalculator.buildColumnWidths(tableNode.table.widths, availableWidth);\n\n\tthis.tableWidth = tableNode._offsets.total + getTableInnerContentWidth();\n\tthis.rowSpanData = prepareRowSpanData();\n\tthis.cleanUpRepeatables = false;\n\n\tthis.headerRows = tableNode.table.headerRows || 0;\n\tthis.rowsWithoutPageBreak = this.headerRows + (tableNode.table.keepWithHeaderRows || 0);\n\tthis.dontBreakRows = tableNode.table.dontBreakRows || false;\n\n\tif (this.rowsWithoutPageBreak) {\n\t\twriter.beginUnbreakableBlock();\n\t}\n\n\t// update the border properties of all cells before drawing any lines\n\tprepareCellBorders(this.tableNode.table.body);\n\n\tthis.drawHorizontalLine(0, writer);\n\n\tfunction getTableInnerContentWidth() {\n\t\tvar width = 0;\n\n\t\ttableNode.table.widths.forEach(function (w) {\n\t\t\twidth += w._calcWidth;\n\t\t});\n\n\t\treturn width;\n\t}\n\n\tfunction prepareRowSpanData() {\n\t\tvar rsd = [];\n\t\tvar x = 0;\n\t\tvar lastWidth = 0;\n\n\t\trsd.push({left: 0, rowSpan: 0});\n\n\t\tfor (var i = 0, l = self.tableNode.table.body[0].length; i < l; i++) {\n\t\t\tvar paddings = self.layout.paddingLeft(i, self.tableNode) + self.layout.paddingRight(i, self.tableNode);\n\t\t\tvar lBorder = self.layout.vLineWidth(i, self.tableNode);\n\t\t\tlastWidth = paddings + lBorder + self.tableNode.table.widths[i]._calcWidth;\n\t\t\trsd[rsd.length - 1].width = lastWidth;\n\t\t\tx += lastWidth;\n\t\t\trsd.push({left: x, rowSpan: 0, width: 0});\n\t\t}\n\n\t\treturn rsd;\n\t}\n\n\t// Iterate through all cells. If the current cell is the start of a\n\t// rowSpan/colSpan, update the border property of the cells on its\n\t// bottom/right accordingly. This is needed since each iteration of the\n\t// line-drawing loops draws lines for a single cell, not for an entire\n\t// rowSpan/colSpan.\n\tfunction prepareCellBorders(body) {\n\t\tfor (var rowIndex = 0; rowIndex < body.length; rowIndex++) {\n\t\t\tvar row = body[rowIndex];\n\n\t\t\tfor (var colIndex = 0; colIndex < row.length; colIndex++) {\n\t\t\t\tvar cell = row[colIndex];\n\n\t\t\t\tif (cell.border) {\n\t\t\t\t\tvar rowSpan = cell.rowSpan || 1;\n\t\t\t\t\tvar colSpan = cell.colSpan || 1;\n\n\t\t\t\t\tfor (var rowOffset = 0; rowOffset < rowSpan; rowOffset++) {\n\t\t\t\t\t\t// set left border\n\t\t\t\t\t\tif (cell.border[0] !== undefined && rowOffset > 0) {\n\t\t\t\t\t\t\tsetBorder(rowIndex + rowOffset, colIndex, 0, cell.border[0]);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// set right border\n\t\t\t\t\t\tif (cell.border[2] !== undefined) {\n\t\t\t\t\t\t\tsetBorder(rowIndex + rowOffset, colIndex + colSpan - 1, 2, cell.border[2]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (var colOffset = 0; colOffset < colSpan; colOffset++) {\n\t\t\t\t\t\t// set top border\n\t\t\t\t\t\tif (cell.border[1] !== undefined && colOffset > 0) {\n\t\t\t\t\t\t\tsetBorder(rowIndex, colIndex + colOffset, 1, cell.border[1]);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// set bottom border\n\t\t\t\t\t\tif (cell.border[3] !== undefined) {\n\t\t\t\t\t\t\tsetBorder(rowIndex + rowSpan - 1, colIndex + colOffset, 3, cell.border[3]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// helper function to set the border for a given cell\n\t\tfunction setBorder(rowIndex, colIndex, borderIndex, borderValue) {\n\t\t\tvar cell = body[rowIndex][colIndex];\n\t\t\tcell.border = cell.border || {};\n\t\t\tcell.border[borderIndex] = borderValue;\n\t\t}\n\t}\n};\n\nTableProcessor.prototype.onRowBreak = function (rowIndex, writer) {\n\tvar self = this;\n\treturn function () {\n\t\tvar offset = self.rowPaddingTop + (!self.headerRows ? self.topLineWidth : 0);\n\t\twriter.context().availableHeight -= self.reservedAtBottom;\n\t\twriter.context().moveDown(offset);\n\t};\n};\n\nTableProcessor.prototype.beginRow = function (rowIndex, writer) {\n\tthis.topLineWidth = this.layout.hLineWidth(rowIndex, this.tableNode);\n\tthis.rowPaddingTop = this.layout.paddingTop(rowIndex, this.tableNode);\n\tthis.bottomLineWidth = this.layout.hLineWidth(rowIndex + 1, this.tableNode);\n\tthis.rowPaddingBottom = this.layout.paddingBottom(rowIndex, this.tableNode);\n\n\tthis.rowCallback = this.onRowBreak(rowIndex, writer);\n\twriter.tracker.startTracking('pageChanged', this.rowCallback);\n\tif (this.dontBreakRows) {\n\t\twriter.beginUnbreakableBlock();\n\t}\n\tthis.rowTopY = writer.context().y;\n\tthis.reservedAtBottom = this.bottomLineWidth + this.rowPaddingBottom;\n\n\twriter.context().availableHeight -= this.reservedAtBottom;\n\n\twriter.context().moveDown(this.rowPaddingTop);\n};\n\nTableProcessor.prototype.drawHorizontalLine = function (lineIndex, writer, overrideY) {\n\tvar lineWidth = this.layout.hLineWidth(lineIndex, this.tableNode);\n\tif (lineWidth) {\n\t\tvar offset = lineWidth / 2;\n\t\tvar currentLine = null;\n\t\tvar body = this.tableNode.table.body;\n\n\t\tfor (var i = 0, l = this.rowSpanData.length; i < l; i++) {\n\t\t\tvar data = this.rowSpanData[i];\n\t\t\tvar shouldDrawLine = !data.rowSpan;\n\n\t\t\t// draw only if the current cell requires a top border or the cell in the\n\t\t\t// row above requires a bottom border\n\t\t\tif (shouldDrawLine && i < l - 1) {\n\t\t\t\tvar topBorder = false, bottomBorder = false;\n\n\t\t\t\t// the current cell\n\t\t\t\tif (lineIndex < body.length) {\n\t\t\t\t\tvar cell = body[lineIndex][i];\n\t\t\t\t\ttopBorder = cell.border ? cell.border[1] : this.layout.defaultBorder;\n\t\t\t\t}\n\n\t\t\t\t// the cell in the row above\n\t\t\t\tif (lineIndex > 0) {\n\t\t\t\t\tvar cellAbove = body[lineIndex - 1][i];\n\t\t\t\t\tbottomBorder = cellAbove.border ? cellAbove.border[3] : this.layout.defaultBorder;\n\t\t\t\t}\n\n\t\t\t\tshouldDrawLine = topBorder || bottomBorder;\n\t\t\t}\n\n\t\t\tif (!currentLine && shouldDrawLine) {\n\t\t\t\tcurrentLine = {left: data.left, width: 0};\n\t\t\t}\n\n\t\t\tif (shouldDrawLine) {\n\t\t\t\tcurrentLine.width += (data.width || 0);\n\t\t\t}\n\n\t\t\tvar y = (overrideY || 0) + offset;\n\n\t\t\tif (!shouldDrawLine || i === l - 1) {\n\t\t\t\tif (currentLine && currentLine.width) {\n\t\t\t\t\twriter.addVector({\n\t\t\t\t\t\ttype: 'line',\n\t\t\t\t\t\tx1: currentLine.left,\n\t\t\t\t\t\tx2: currentLine.left + currentLine.width,\n\t\t\t\t\t\ty1: y,\n\t\t\t\t\t\ty2: y,\n\t\t\t\t\t\tlineWidth: lineWidth,\n\t\t\t\t\t\tlineColor: isFunction(this.layout.hLineColor) ? this.layout.hLineColor(lineIndex, this.tableNode) : this.layout.hLineColor\n\t\t\t\t\t}, false, overrideY);\n\t\t\t\t\tcurrentLine = null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\twriter.context().moveDown(lineWidth);\n\t}\n};\n\nTableProcessor.prototype.drawVerticalLine = function (x, y0, y1, vLineIndex, writer) {\n\tvar width = this.layout.vLineWidth(vLineIndex, this.tableNode);\n\tif (width === 0) {\n\t\treturn;\n\t}\n\twriter.addVector({\n\t\ttype: 'line',\n\t\tx1: x + width / 2,\n\t\tx2: x + width / 2,\n\t\ty1: y0,\n\t\ty2: y1,\n\t\tlineWidth: width,\n\t\tlineColor: isFunction(this.layout.vLineColor) ? this.layout.vLineColor(vLineIndex, this.tableNode) : this.layout.vLineColor\n\t}, false, true);\n};\n\nTableProcessor.prototype.endTable = function (writer) {\n\tif (this.cleanUpRepeatables) {\n\t\twriter.popFromRepeatables();\n\t\tthis.headerRepeatableHeight = null;\n\t}\n};\n\nTableProcessor.prototype.endRow = function (rowIndex, writer, pageBreaks) {\n\tvar l, i;\n\tvar self = this;\n\twriter.tracker.stopTracking('pageChanged', this.rowCallback);\n\twriter.context().moveDown(this.layout.paddingBottom(rowIndex, this.tableNode));\n\twriter.context().availableHeight += this.reservedAtBottom;\n\n\tvar endingPage = writer.context().page;\n\tvar endingY = writer.context().y;\n\n\tvar xs = getLineXs();\n\n\tvar ys = [];\n\n\tvar hasBreaks = pageBreaks && pageBreaks.length > 0;\n\tvar body = this.tableNode.table.body;\n\n\tys.push({\n\t\ty0: this.rowTopY,\n\t\tpage: hasBreaks ? pageBreaks[0].prevPage : endingPage\n\t});\n\n\tif (hasBreaks) {\n\t\tfor (i = 0, l = pageBreaks.length; i < l; i++) {\n\t\t\tvar pageBreak = pageBreaks[i];\n\t\t\tys[ys.length - 1].y1 = pageBreak.prevY;\n\n\t\t\tys.push({y0: pageBreak.y, page: pageBreak.prevPage + 1});\n\n\t\t\tif (this.headerRepeatableHeight) {\n\t\t\t\tys[ys.length - 1].y0 += this.headerRepeatableHeight;\n\t\t\t}\n\t\t}\n\t}\n\n\tys[ys.length - 1].y1 = endingY;\n\n\tvar skipOrphanePadding = (ys[0].y1 - ys[0].y0 === this.rowPaddingTop);\n\tfor (var yi = (skipOrphanePadding ? 1 : 0), yl = ys.length; yi < yl; yi++) {\n\t\tvar willBreak = yi < ys.length - 1;\n\t\tvar rowBreakWithoutHeader = (yi > 0 && !this.headerRows);\n\t\tvar hzLineOffset = rowBreakWithoutHeader ? 0 : this.topLineWidth;\n\t\tvar y1 = ys[yi].y0;\n\t\tvar y2 = ys[yi].y1;\n\n\t\tif (willBreak) {\n\t\t\ty2 = y2 + this.rowPaddingBottom;\n\t\t}\n\n\t\tif (writer.context().page != ys[yi].page) {\n\t\t\twriter.context().page = ys[yi].page;\n\n\t\t\t//TODO: buggy, availableHeight should be updated on every pageChanged event\n\t\t\t// TableProcessor should be pageChanged listener, instead of processRow\n\t\t\tthis.reservedAtBottom = 0;\n\t\t}\n\n\t\tfor (i = 0, l = xs.length; i < l; i++) {\n\t\t\tvar leftBorder = false, rightBorder = false;\n\t\t\tvar colIndex = xs[i].index;\n\n\t\t\t// the current cell\n\t\t\tif (colIndex < body[rowIndex].length) {\n\t\t\t\tvar cell = body[rowIndex][colIndex];\n\t\t\t\tleftBorder = cell.border ? cell.border[0] : this.layout.defaultBorder;\n\t\t\t}\n\n\t\t\t// the cell from before column\n\t\t\tif (colIndex > 0) {\n\t\t\t\tvar cell = body[rowIndex][colIndex - 1];\n\t\t\t\trightBorder = cell.border ? cell.border[2] : this.layout.defaultBorder;\n\t\t\t}\n\n\t\t\tif (leftBorder || rightBorder) {\n\t\t\t\tthis.drawVerticalLine(xs[i].x, y1 - hzLineOffset, y2 + this.bottomLineWidth, xs[i].index, writer);\n\t\t\t}\n\n\t\t\tif (i < l - 1) {\n\t\t\t\tvar fillColor = body[rowIndex][colIndex].fillColor;\n\t\t\t\tif (!fillColor) {\n\t\t\t\t\tfillColor = isFunction(this.layout.fillColor) ? this.layout.fillColor(rowIndex, this.tableNode, colIndex) : this.layout.fillColor;\n\t\t\t\t}\n\t\t\t\tif (fillColor) {\n\t\t\t\t\tvar wBorder = (leftBorder || rightBorder) ? this.layout.vLineWidth(colIndex, this.tableNode) : 0;\n\t\t\t\t\tvar xf = xs[i].x + wBorder;\n\t\t\t\t\tvar yf = this.dontBreakRows ? y1 : y1 - hzLineOffset;\n\t\t\t\t\twriter.addVector({\n\t\t\t\t\t\ttype: 'rect',\n\t\t\t\t\t\tx: xf,\n\t\t\t\t\t\ty: yf,\n\t\t\t\t\t\tw: xs[i + 1].x - xf,\n\t\t\t\t\t\th: y2 + this.bottomLineWidth - yf,\n\t\t\t\t\t\tlineWidth: 0,\n\t\t\t\t\t\tcolor: fillColor\n\t\t\t\t\t}, false, true, writer.context().hasBackground ? 1 : 0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (willBreak && this.layout.hLineWhenBroken !== false) {\n\t\t\tthis.drawHorizontalLine(rowIndex + 1, writer, y2);\n\t\t}\n\t\tif (rowBreakWithoutHeader && this.layout.hLineWhenBroken !== false) {\n\t\t\tthis.drawHorizontalLine(rowIndex, writer, y1);\n\t\t}\n\t}\n\n\twriter.context().page = endingPage;\n\twriter.context().y = endingY;\n\n\tvar row = this.tableNode.table.body[rowIndex];\n\tfor (i = 0, l = row.length; i < l; i++) {\n\t\tif (row[i].rowSpan) {\n\t\t\tthis.rowSpanData[i].rowSpan = row[i].rowSpan;\n\n\t\t\t// fix colSpans\n\t\t\tif (row[i].colSpan && row[i].colSpan > 1) {\n\t\t\t\tfor (var j = 1; j < row[i].rowSpan; j++) {\n\t\t\t\t\tthis.tableNode.table.body[rowIndex + j][i]._colSpan = row[i].colSpan;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.rowSpanData[i].rowSpan > 0) {\n\t\t\tthis.rowSpanData[i].rowSpan--;\n\t\t}\n\t}\n\n\tthis.drawHorizontalLine(rowIndex + 1, writer);\n\n\tif (this.headerRows && rowIndex === this.headerRows - 1) {\n\t\tthis.headerRepeatable = writer.currentBlockToRepeatable();\n\t}\n\n\tif (this.dontBreakRows) {\n\t\twriter.tracker.auto('pageChanged',\n\t\t\tfunction () {\n\t\t\t\tif (!self.headerRows && self.layout.hLineWhenBroken !== false) {\n\t\t\t\t\tself.drawHorizontalLine(rowIndex, writer);\n\t\t\t\t}\n\t\t\t},\n\t\t\tfunction () {\n\t\t\t\twriter.commitUnbreakableBlock();\n\t\t\t}\n\t\t);\n\t}\n\n\tif (this.headerRepeatable && (rowIndex === (this.rowsWithoutPageBreak - 1) || rowIndex === this.tableNode.table.body.length - 1)) {\n\t\tthis.headerRepeatableHeight = this.headerRepeatable.height;\n\t\twriter.commitUnbreakableBlock();\n\t\twriter.pushToRepeatables(this.headerRepeatable);\n\t\tthis.cleanUpRepeatables = true;\n\t\tthis.headerRepeatable = null;\n\t}\n\n\tfunction getLineXs() {\n\t\tvar result = [];\n\t\tvar cols = 0;\n\n\t\tfor (var i = 0, l = self.tableNode.table.body[rowIndex].length; i < l; i++) {\n\t\t\tif (!cols) {\n\t\t\t\tresult.push({x: self.rowSpanData[i].left, index: i});\n\n\t\t\t\tvar item = self.tableNode.table.body[rowIndex][i];\n\t\t\t\tcols = (item._colSpan || item.colSpan || 0);\n\t\t\t}\n\t\t\tif (cols > 0) {\n\t\t\t\tcols--;\n\t\t\t}\n\t\t}\n\n\t\tresult.push({x: self.rowSpanData[self.rowSpanData.length - 1].left, index: self.rowSpanData.length - 1});\n\n\t\treturn result;\n\t}\n};\n\nmodule.exports = TableProcessor;\n\n\n/***/ }),\n/* 138 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6\n\n/*\nPDFDocument - represents an entire PDF document\nBy Devon Govett\n */\n\n(function() {\n  var PDFDocument, PDFObject, PDFPage, PDFReference, fs, stream,\n    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n    hasProp = {}.hasOwnProperty;\n\n  stream = __webpack_require__(15);\n\n  fs = __webpack_require__(8);\n\n  PDFObject = __webpack_require__(26);\n\n  PDFReference = __webpack_require__(87);\n\n  PDFPage = __webpack_require__(161);\n\n  PDFDocument = (function(superClass) {\n    var mixin;\n\n    extend(PDFDocument, superClass);\n\n    function PDFDocument(options1) {\n      var key, ref1, ref2, val;\n      this.options = options1 != null ? options1 : {};\n      PDFDocument.__super__.constructor.apply(this, arguments);\n      this.version = 1.3;\n      this.compress = (ref1 = this.options.compress) != null ? ref1 : true;\n      this._pageBuffer = [];\n      this._pageBufferStart = 0;\n      this._offsets = [];\n      this._waiting = 0;\n      this._ended = false;\n      this._offset = 0;\n      this._root = this.ref({\n        Type: 'Catalog',\n        Pages: this.ref({\n          Type: 'Pages',\n          Count: 0,\n          Kids: []\n        })\n      });\n      this.page = null;\n      this.initColor();\n      this.initVector();\n      this.initFonts();\n      this.initText();\n      this.initImages();\n      this.info = {\n        Producer: 'PDFKit',\n        Creator: 'PDFKit',\n        CreationDate: new Date()\n      };\n      if (this.options.info) {\n        ref2 = this.options.info;\n        for (key in ref2) {\n          val = ref2[key];\n          this.info[key] = val;\n        }\n      }\n      this._write(\"%PDF-\" + this.version);\n      this._write(\"%\\xFF\\xFF\\xFF\\xFF\");\n      if (this.options.autoFirstPage !== false) {\n        this.addPage();\n      }\n    }\n\n    mixin = function(methods) {\n      var method, name, results;\n      results = [];\n      for (name in methods) {\n        method = methods[name];\n        results.push(PDFDocument.prototype[name] = method);\n      }\n      return results;\n    };\n\n    mixin(__webpack_require__(162));\n\n    mixin(__webpack_require__(164));\n\n    mixin(__webpack_require__(166));\n\n    mixin(__webpack_require__(295));\n\n    mixin(__webpack_require__(297));\n\n    mixin(__webpack_require__(302));\n\n    PDFDocument.prototype.addPage = function(options) {\n      var pages;\n      if (options == null) {\n        options = this.options;\n      }\n      if (!this.options.bufferPages) {\n        this.flushPages();\n      }\n      this.page = new PDFPage(this, options);\n      this._pageBuffer.push(this.page);\n      pages = this._root.data.Pages.data;\n      pages.Kids.push(this.page.dictionary);\n      pages.Count++;\n      this.x = this.page.margins.left;\n      this.y = this.page.margins.top;\n      this._ctm = [1, 0, 0, 1, 0, 0];\n      this.transform(1, 0, 0, -1, 0, this.page.height);\n      this.emit('pageAdded');\n      return this;\n    };\n\n    PDFDocument.prototype.bufferedPageRange = function() {\n      return {\n        start: this._pageBufferStart,\n        count: this._pageBuffer.length\n      };\n    };\n\n    PDFDocument.prototype.switchToPage = function(n) {\n      var page;\n      if (!(page = this._pageBuffer[n - this._pageBufferStart])) {\n        throw new Error(\"switchToPage(\" + n + \") out of bounds, current buffer covers pages \" + this._pageBufferStart + \" to \" + (this._pageBufferStart + this._pageBuffer.length - 1));\n      }\n      return this.page = page;\n    };\n\n    PDFDocument.prototype.flushPages = function() {\n      var i, len, page, pages;\n      pages = this._pageBuffer;\n      this._pageBuffer = [];\n      this._pageBufferStart += pages.length;\n      for (i = 0, len = pages.length; i < len; i++) {\n        page = pages[i];\n        page.end();\n      }\n    };\n\n    PDFDocument.prototype.ref = function(data) {\n      var ref;\n      ref = new PDFReference(this, this._offsets.length + 1, data);\n      this._offsets.push(null);\n      this._waiting++;\n      return ref;\n    };\n\n    PDFDocument.prototype._read = function() {};\n\n    PDFDocument.prototype._write = function(data) {\n      if (!Buffer.isBuffer(data)) {\n        data = new Buffer(data + '\\n', 'binary');\n      }\n      this.push(data);\n      return this._offset += data.length;\n    };\n\n    PDFDocument.prototype.addContent = function(data) {\n      this.page.write(data);\n      return this;\n    };\n\n    PDFDocument.prototype._refEnd = function(ref) {\n      this._offsets[ref.id - 1] = ref.offset;\n      if (--this._waiting === 0 && this._ended) {\n        this._finalize();\n        return this._ended = false;\n      }\n    };\n\n    PDFDocument.prototype.write = function(filename, fn) {\n      var err;\n      err = new Error('PDFDocument#write is deprecated, and will be removed in a future version of PDFKit. Please pipe the document into a Node stream.');\n      console.warn(err.stack);\n      this.pipe(fs.createWriteStream(filename));\n      this.end();\n      return this.once('end', fn);\n    };\n\n    PDFDocument.prototype.output = function(fn) {\n      throw new Error('PDFDocument#output is deprecated, and has been removed from PDFKit. Please pipe the document into a Node stream.');\n    };\n\n    PDFDocument.prototype.end = function() {\n      var font, key, name, ref1, ref2, val;\n      this.flushPages();\n      this._info = this.ref();\n      ref1 = this.info;\n      for (key in ref1) {\n        val = ref1[key];\n        if (typeof val === 'string') {\n          val = new String(val);\n        }\n        this._info.data[key] = val;\n      }\n      this._info.end();\n      ref2 = this._fontFamilies;\n      for (name in ref2) {\n        font = ref2[name];\n        font.finalize();\n      }\n      this._root.end();\n      this._root.data.Pages.end();\n      if (this._waiting === 0) {\n        return this._finalize();\n      } else {\n        return this._ended = true;\n      }\n    };\n\n    PDFDocument.prototype._finalize = function(fn) {\n      var i, len, offset, ref1, xRefOffset;\n      xRefOffset = this._offset;\n      this._write(\"xref\");\n      this._write(\"0 \" + (this._offsets.length + 1));\n      this._write(\"0000000000 65535 f \");\n      ref1 = this._offsets;\n      for (i = 0, len = ref1.length; i < len; i++) {\n        offset = ref1[i];\n        offset = ('0000000000' + offset).slice(-10);\n        this._write(offset + ' 00000 n ');\n      }\n      this._write('trailer');\n      this._write(PDFObject.convert({\n        Size: this._offsets.length + 1,\n        Root: this._root,\n        Info: this._info\n      }));\n      this._write('startxref');\n      this._write(\"\" + xRefOffset);\n      this._write('%%EOF');\n      return this.push(null);\n    };\n\n    PDFDocument.prototype.toString = function() {\n      return \"[object PDFDocument]\";\n    };\n\n    return PDFDocument;\n\n  })(stream.Readable);\n\n  module.exports = PDFDocument;\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 139 */\n/***/ (function(module, exports) {\n\n/* (ignored) */\n\n/***/ }),\n/* 140 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar Buffer = __webpack_require__(33).Buffer;\nvar util = __webpack_require__(141);\n\nfunction copyBuffer(src, target, offset) {\n  src.copy(target, offset);\n}\n\nmodule.exports = function () {\n  function BufferList() {\n    _classCallCheck(this, BufferList);\n\n    this.head = null;\n    this.tail = null;\n    this.length = 0;\n  }\n\n  BufferList.prototype.push = function push(v) {\n    var entry = { data: v, next: null };\n    if (this.length > 0) this.tail.next = entry;else this.head = entry;\n    this.tail = entry;\n    ++this.length;\n  };\n\n  BufferList.prototype.unshift = function unshift(v) {\n    var entry = { data: v, next: this.head };\n    if (this.length === 0) this.tail = entry;\n    this.head = entry;\n    ++this.length;\n  };\n\n  BufferList.prototype.shift = function shift() {\n    if (this.length === 0) return;\n    var ret = this.head.data;\n    if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next;\n    --this.length;\n    return ret;\n  };\n\n  BufferList.prototype.clear = function clear() {\n    this.head = this.tail = null;\n    this.length = 0;\n  };\n\n  BufferList.prototype.join = function join(s) {\n    if (this.length === 0) return '';\n    var p = this.head;\n    var ret = '' + p.data;\n    while (p = p.next) {\n      ret += s + p.data;\n    }return ret;\n  };\n\n  BufferList.prototype.concat = function concat(n) {\n    if (this.length === 0) return Buffer.alloc(0);\n    if (this.length === 1) return this.head.data;\n    var ret = Buffer.allocUnsafe(n >>> 0);\n    var p = this.head;\n    var i = 0;\n    while (p) {\n      copyBuffer(p.data, ret, i);\n      i += p.data.length;\n      p = p.next;\n    }\n    return ret;\n  };\n\n  return BufferList;\n}();\n\nif (util && util.inspect && util.inspect.custom) {\n  module.exports.prototype[util.inspect.custom] = function () {\n    var obj = util.inspect({ length: this.length });\n    return this.constructor.name + ' ' + obj;\n  };\n}\n\n/***/ }),\n/* 141 */\n/***/ (function(module, exports) {\n\n/* (ignored) */\n\n/***/ }),\n/* 142 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(global) {var apply = Function.prototype.apply;\n\n// DOM APIs, for completeness\n\nexports.setTimeout = function() {\n  return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout);\n};\nexports.setInterval = function() {\n  return new Timeout(apply.call(setInterval, window, arguments), clearInterval);\n};\nexports.clearTimeout =\nexports.clearInterval = function(timeout) {\n  if (timeout) {\n    timeout.close();\n  }\n};\n\nfunction Timeout(id, clearFn) {\n  this._id = id;\n  this._clearFn = clearFn;\n}\nTimeout.prototype.unref = Timeout.prototype.ref = function() {};\nTimeout.prototype.close = function() {\n  this._clearFn.call(window, this._id);\n};\n\n// Does not start the time, just sets up the members needed.\nexports.enroll = function(item, msecs) {\n  clearTimeout(item._idleTimeoutId);\n  item._idleTimeout = msecs;\n};\n\nexports.unenroll = function(item) {\n  clearTimeout(item._idleTimeoutId);\n  item._idleTimeout = -1;\n};\n\nexports._unrefActive = exports.active = function(item) {\n  clearTimeout(item._idleTimeoutId);\n\n  var msecs = item._idleTimeout;\n  if (msecs >= 0) {\n    item._idleTimeoutId = setTimeout(function onTimeout() {\n      if (item._onTimeout)\n        item._onTimeout();\n    }, msecs);\n  }\n};\n\n// setimmediate attaches itself to the global object\n__webpack_require__(143);\n// On some exotic environments, it's not clear which object `setimmeidate` was\n// able to install onto.  Search each possibility in the same order as the\n// `setimmediate` library.\nexports.setImmediate = (typeof self !== \"undefined\" && self.setImmediate) ||\n                       (typeof global !== \"undefined\" && global.setImmediate) ||\n                       (this && this.setImmediate);\nexports.clearImmediate = (typeof self !== \"undefined\" && self.clearImmediate) ||\n                         (typeof global !== \"undefined\" && global.clearImmediate) ||\n                         (this && this.clearImmediate);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))\n\n/***/ }),\n/* 143 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(global, process) {(function (global, undefined) {\n    \"use strict\";\n\n    if (global.setImmediate) {\n        return;\n    }\n\n    var nextHandle = 1; // Spec says greater than zero\n    var tasksByHandle = {};\n    var currentlyRunningATask = false;\n    var doc = global.document;\n    var registerImmediate;\n\n    function setImmediate(callback) {\n      // Callback can either be a function or a string\n      if (typeof callback !== \"function\") {\n        callback = new Function(\"\" + callback);\n      }\n      // Copy function arguments\n      var args = new Array(arguments.length - 1);\n      for (var i = 0; i < args.length; i++) {\n          args[i] = arguments[i + 1];\n      }\n      // Store and register the task\n      var task = { callback: callback, args: args };\n      tasksByHandle[nextHandle] = task;\n      registerImmediate(nextHandle);\n      return nextHandle++;\n    }\n\n    function clearImmediate(handle) {\n        delete tasksByHandle[handle];\n    }\n\n    function run(task) {\n        var callback = task.callback;\n        var args = task.args;\n        switch (args.length) {\n        case 0:\n            callback();\n            break;\n        case 1:\n            callback(args[0]);\n            break;\n        case 2:\n            callback(args[0], args[1]);\n            break;\n        case 3:\n            callback(args[0], args[1], args[2]);\n            break;\n        default:\n            callback.apply(undefined, args);\n            break;\n        }\n    }\n\n    function runIfPresent(handle) {\n        // From the spec: \"Wait until any invocations of this algorithm started before this one have completed.\"\n        // So if we're currently running a task, we'll need to delay this invocation.\n        if (currentlyRunningATask) {\n            // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a\n            // \"too much recursion\" error.\n            setTimeout(runIfPresent, 0, handle);\n        } else {\n            var task = tasksByHandle[handle];\n            if (task) {\n                currentlyRunningATask = true;\n                try {\n                    run(task);\n                } finally {\n                    clearImmediate(handle);\n                    currentlyRunningATask = false;\n                }\n            }\n        }\n    }\n\n    function installNextTickImplementation() {\n        registerImmediate = function(handle) {\n            process.nextTick(function () { runIfPresent(handle); });\n        };\n    }\n\n    function canUsePostMessage() {\n        // The test against `importScripts` prevents this implementation from being installed inside a web worker,\n        // where `global.postMessage` means something completely different and can't be used for this purpose.\n        if (global.postMessage && !global.importScripts) {\n            var postMessageIsAsynchronous = true;\n            var oldOnMessage = global.onmessage;\n            global.onmessage = function() {\n                postMessageIsAsynchronous = false;\n            };\n            global.postMessage(\"\", \"*\");\n            global.onmessage = oldOnMessage;\n            return postMessageIsAsynchronous;\n        }\n    }\n\n    function installPostMessageImplementation() {\n        // Installs an event handler on `global` for the `message` event: see\n        // * https://developer.mozilla.org/en/DOM/window.postMessage\n        // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages\n\n        var messagePrefix = \"setImmediate$\" + Math.random() + \"$\";\n        var onGlobalMessage = function(event) {\n            if (event.source === global &&\n                typeof event.data === \"string\" &&\n                event.data.indexOf(messagePrefix) === 0) {\n                runIfPresent(+event.data.slice(messagePrefix.length));\n            }\n        };\n\n        if (global.addEventListener) {\n            global.addEventListener(\"message\", onGlobalMessage, false);\n        } else {\n            global.attachEvent(\"onmessage\", onGlobalMessage);\n        }\n\n        registerImmediate = function(handle) {\n            global.postMessage(messagePrefix + handle, \"*\");\n        };\n    }\n\n    function installMessageChannelImplementation() {\n        var channel = new MessageChannel();\n        channel.port1.onmessage = function(event) {\n            var handle = event.data;\n            runIfPresent(handle);\n        };\n\n        registerImmediate = function(handle) {\n            channel.port2.postMessage(handle);\n        };\n    }\n\n    function installReadyStateChangeImplementation() {\n        var html = doc.documentElement;\n        registerImmediate = function(handle) {\n            // Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted\n            // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.\n            var script = doc.createElement(\"script\");\n            script.onreadystatechange = function () {\n                runIfPresent(handle);\n                script.onreadystatechange = null;\n                html.removeChild(script);\n                script = null;\n            };\n            html.appendChild(script);\n        };\n    }\n\n    function installSetTimeoutImplementation() {\n        registerImmediate = function(handle) {\n            setTimeout(runIfPresent, 0, handle);\n        };\n    }\n\n    // If supported, we should attach to the prototype of global, since that is where setTimeout et al. live.\n    var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global);\n    attachTo = attachTo && attachTo.setTimeout ? attachTo : global;\n\n    // Don't get fooled by e.g. browserify environments.\n    if ({}.toString.call(global.process) === \"[object process]\") {\n        // For Node.js before 0.9\n        installNextTickImplementation();\n\n    } else if (canUsePostMessage()) {\n        // For non-IE10 modern browsers\n        installPostMessageImplementation();\n\n    } else if (global.MessageChannel) {\n        // For web workers, where supported\n        installMessageChannelImplementation();\n\n    } else if (doc && \"onreadystatechange\" in doc.createElement(\"script\")) {\n        // For IE 6–8\n        installReadyStateChangeImplementation();\n\n    } else {\n        // For older browsers\n        installSetTimeoutImplementation();\n    }\n\n    attachTo.setImmediate = setImmediate;\n    attachTo.clearImmediate = clearImmediate;\n}(typeof self === \"undefined\" ? typeof global === \"undefined\" ? this : global : self));\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7), __webpack_require__(11)))\n\n/***/ }),\n/* 144 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(global) {\n/**\n * Module exports.\n */\n\nmodule.exports = deprecate;\n\n/**\n * Mark that a method should not be used.\n * Returns a modified function which warns once by default.\n *\n * If `localStorage.noDeprecation = true` is set, then it is a no-op.\n *\n * If `localStorage.throwDeprecation = true` is set, then deprecated functions\n * will throw an Error when invoked.\n *\n * If `localStorage.traceDeprecation = true` is set, then deprecated functions\n * will invoke `console.trace()` instead of `console.error()`.\n *\n * @param {Function} fn - the function to deprecate\n * @param {String} msg - the string to print to the console when `fn` is invoked\n * @returns {Function} a new \"deprecated\" version of `fn`\n * @api public\n */\n\nfunction deprecate (fn, msg) {\n  if (config('noDeprecation')) {\n    return fn;\n  }\n\n  var warned = false;\n  function deprecated() {\n    if (!warned) {\n      if (config('throwDeprecation')) {\n        throw new Error(msg);\n      } else if (config('traceDeprecation')) {\n        console.trace(msg);\n      } else {\n        console.warn(msg);\n      }\n      warned = true;\n    }\n    return fn.apply(this, arguments);\n  }\n\n  return deprecated;\n}\n\n/**\n * Checks `localStorage` for boolean values for the given `name`.\n *\n * @param {String} name\n * @returns {Boolean}\n * @api private\n */\n\nfunction config (name) {\n  // accessing global.localStorage can trigger a DOMException in sandboxed iframes\n  try {\n    if (!global.localStorage) return false;\n  } catch (_) {\n    return false;\n  }\n  var val = global.localStorage[name];\n  if (null == val) return false;\n  return String(val).toLowerCase() === 'true';\n}\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))\n\n/***/ }),\n/* 145 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// a passthrough stream.\n// basically just the most minimal sort of Transform stream.\n// Every written chunk gets output as-is.\n\n\n\nmodule.exports = PassThrough;\n\nvar Transform = __webpack_require__(86);\n\n/*<replacement>*/\nvar util = __webpack_require__(25);\nutil.inherits = __webpack_require__(21);\n/*</replacement>*/\n\nutil.inherits(PassThrough, Transform);\n\nfunction PassThrough(options) {\n  if (!(this instanceof PassThrough)) return new PassThrough(options);\n\n  Transform.call(this, options);\n}\n\nPassThrough.prototype._transform = function (chunk, encoding, cb) {\n  cb(null, chunk);\n};\n\n/***/ }),\n/* 146 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(46);\n\n\n/***/ }),\n/* 147 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(16);\n\n\n/***/ }),\n/* 148 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(45).Transform\n\n\n/***/ }),\n/* 149 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(45).PassThrough\n\n\n/***/ }),\n/* 150 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(Buffer, process) {\n/* eslint camelcase: \"off\" */\n\nvar assert = __webpack_require__(88);\n\nvar Zstream = __webpack_require__(153);\nvar zlib_deflate = __webpack_require__(154);\nvar zlib_inflate = __webpack_require__(157);\nvar constants = __webpack_require__(160);\n\nfor (var key in constants) {\n  exports[key] = constants[key];\n}\n\n// zlib modes\nexports.NONE = 0;\nexports.DEFLATE = 1;\nexports.INFLATE = 2;\nexports.GZIP = 3;\nexports.GUNZIP = 4;\nexports.DEFLATERAW = 5;\nexports.INFLATERAW = 6;\nexports.UNZIP = 7;\n\nvar GZIP_HEADER_ID1 = 0x1f;\nvar GZIP_HEADER_ID2 = 0x8b;\n\n/**\n * Emulate Node's zlib C++ layer for use by the JS layer in index.js\n */\nfunction Zlib(mode) {\n  if (typeof mode !== 'number' || mode < exports.DEFLATE || mode > exports.UNZIP) {\n    throw new TypeError('Bad argument');\n  }\n\n  this.dictionary = null;\n  this.err = 0;\n  this.flush = 0;\n  this.init_done = false;\n  this.level = 0;\n  this.memLevel = 0;\n  this.mode = mode;\n  this.strategy = 0;\n  this.windowBits = 0;\n  this.write_in_progress = false;\n  this.pending_close = false;\n  this.gzip_id_bytes_read = 0;\n}\n\nZlib.prototype.close = function () {\n  if (this.write_in_progress) {\n    this.pending_close = true;\n    return;\n  }\n\n  this.pending_close = false;\n\n  assert(this.init_done, 'close before init');\n  assert(this.mode <= exports.UNZIP);\n\n  if (this.mode === exports.DEFLATE || this.mode === exports.GZIP || this.mode === exports.DEFLATERAW) {\n    zlib_deflate.deflateEnd(this.strm);\n  } else if (this.mode === exports.INFLATE || this.mode === exports.GUNZIP || this.mode === exports.INFLATERAW || this.mode === exports.UNZIP) {\n    zlib_inflate.inflateEnd(this.strm);\n  }\n\n  this.mode = exports.NONE;\n\n  this.dictionary = null;\n};\n\nZlib.prototype.write = function (flush, input, in_off, in_len, out, out_off, out_len) {\n  return this._write(true, flush, input, in_off, in_len, out, out_off, out_len);\n};\n\nZlib.prototype.writeSync = function (flush, input, in_off, in_len, out, out_off, out_len) {\n  return this._write(false, flush, input, in_off, in_len, out, out_off, out_len);\n};\n\nZlib.prototype._write = function (async, flush, input, in_off, in_len, out, out_off, out_len) {\n  assert.equal(arguments.length, 8);\n\n  assert(this.init_done, 'write before init');\n  assert(this.mode !== exports.NONE, 'already finalized');\n  assert.equal(false, this.write_in_progress, 'write already in progress');\n  assert.equal(false, this.pending_close, 'close is pending');\n\n  this.write_in_progress = true;\n\n  assert.equal(false, flush === undefined, 'must provide flush value');\n\n  this.write_in_progress = true;\n\n  if (flush !== exports.Z_NO_FLUSH && flush !== exports.Z_PARTIAL_FLUSH && flush !== exports.Z_SYNC_FLUSH && flush !== exports.Z_FULL_FLUSH && flush !== exports.Z_FINISH && flush !== exports.Z_BLOCK) {\n    throw new Error('Invalid flush value');\n  }\n\n  if (input == null) {\n    input = Buffer.alloc(0);\n    in_len = 0;\n    in_off = 0;\n  }\n\n  this.strm.avail_in = in_len;\n  this.strm.input = input;\n  this.strm.next_in = in_off;\n  this.strm.avail_out = out_len;\n  this.strm.output = out;\n  this.strm.next_out = out_off;\n  this.flush = flush;\n\n  if (!async) {\n    // sync version\n    this._process();\n\n    if (this._checkError()) {\n      return this._afterSync();\n    }\n    return;\n  }\n\n  // async version\n  var self = this;\n  process.nextTick(function () {\n    self._process();\n    self._after();\n  });\n\n  return this;\n};\n\nZlib.prototype._afterSync = function () {\n  var avail_out = this.strm.avail_out;\n  var avail_in = this.strm.avail_in;\n\n  this.write_in_progress = false;\n\n  return [avail_in, avail_out];\n};\n\nZlib.prototype._process = function () {\n  var next_expected_header_byte = null;\n\n  // If the avail_out is left at 0, then it means that it ran out\n  // of room.  If there was avail_out left over, then it means\n  // that all of the input was consumed.\n  switch (this.mode) {\n    case exports.DEFLATE:\n    case exports.GZIP:\n    case exports.DEFLATERAW:\n      this.err = zlib_deflate.deflate(this.strm, this.flush);\n      break;\n    case exports.UNZIP:\n      if (this.strm.avail_in > 0) {\n        next_expected_header_byte = this.strm.next_in;\n      }\n\n      switch (this.gzip_id_bytes_read) {\n        case 0:\n          if (next_expected_header_byte === null) {\n            break;\n          }\n\n          if (this.strm.input[next_expected_header_byte] === GZIP_HEADER_ID1) {\n            this.gzip_id_bytes_read = 1;\n            next_expected_header_byte++;\n\n            if (this.strm.avail_in === 1) {\n              // The only available byte was already read.\n              break;\n            }\n          } else {\n            this.mode = exports.INFLATE;\n            break;\n          }\n\n        // fallthrough\n        case 1:\n          if (next_expected_header_byte === null) {\n            break;\n          }\n\n          if (this.strm.input[next_expected_header_byte] === GZIP_HEADER_ID2) {\n            this.gzip_id_bytes_read = 2;\n            this.mode = exports.GUNZIP;\n          } else {\n            // There is no actual difference between INFLATE and INFLATERAW\n            // (after initialization).\n            this.mode = exports.INFLATE;\n          }\n\n          break;\n        default:\n          throw new Error('invalid number of gzip magic number bytes read');\n      }\n\n    // fallthrough\n    case exports.INFLATE:\n    case exports.GUNZIP:\n    case exports.INFLATERAW:\n      this.err = zlib_inflate.inflate(this.strm, this.flush\n\n      // If data was encoded with dictionary\n      );if (this.err === exports.Z_NEED_DICT && this.dictionary) {\n        // Load it\n        this.err = zlib_inflate.inflateSetDictionary(this.strm, this.dictionary);\n        if (this.err === exports.Z_OK) {\n          // And try to decode again\n          this.err = zlib_inflate.inflate(this.strm, this.flush);\n        } else if (this.err === exports.Z_DATA_ERROR) {\n          // Both inflateSetDictionary() and inflate() return Z_DATA_ERROR.\n          // Make it possible for After() to tell a bad dictionary from bad\n          // input.\n          this.err = exports.Z_NEED_DICT;\n        }\n      }\n      while (this.strm.avail_in > 0 && this.mode === exports.GUNZIP && this.err === exports.Z_STREAM_END && this.strm.next_in[0] !== 0x00) {\n        // Bytes remain in input buffer. Perhaps this is another compressed\n        // member in the same archive, or just trailing garbage.\n        // Trailing zero bytes are okay, though, since they are frequently\n        // used for padding.\n\n        this.reset();\n        this.err = zlib_inflate.inflate(this.strm, this.flush);\n      }\n      break;\n    default:\n      throw new Error('Unknown mode ' + this.mode);\n  }\n};\n\nZlib.prototype._checkError = function () {\n  // Acceptable error states depend on the type of zlib stream.\n  switch (this.err) {\n    case exports.Z_OK:\n    case exports.Z_BUF_ERROR:\n      if (this.strm.avail_out !== 0 && this.flush === exports.Z_FINISH) {\n        this._error('unexpected end of file');\n        return false;\n      }\n      break;\n    case exports.Z_STREAM_END:\n      // normal statuses, not fatal\n      break;\n    case exports.Z_NEED_DICT:\n      if (this.dictionary == null) {\n        this._error('Missing dictionary');\n      } else {\n        this._error('Bad dictionary');\n      }\n      return false;\n    default:\n      // something else.\n      this._error('Zlib error');\n      return false;\n  }\n\n  return true;\n};\n\nZlib.prototype._after = function () {\n  if (!this._checkError()) {\n    return;\n  }\n\n  var avail_out = this.strm.avail_out;\n  var avail_in = this.strm.avail_in;\n\n  this.write_in_progress = false;\n\n  // call the write() cb\n  this.callback(avail_in, avail_out);\n\n  if (this.pending_close) {\n    this.close();\n  }\n};\n\nZlib.prototype._error = function (message) {\n  if (this.strm.msg) {\n    message = this.strm.msg;\n  }\n  this.onerror(message, this.err\n\n  // no hope of rescue.\n  );this.write_in_progress = false;\n  if (this.pending_close) {\n    this.close();\n  }\n};\n\nZlib.prototype.init = function (windowBits, level, memLevel, strategy, dictionary) {\n  assert(arguments.length === 4 || arguments.length === 5, 'init(windowBits, level, memLevel, strategy, [dictionary])');\n\n  assert(windowBits >= 8 && windowBits <= 15, 'invalid windowBits');\n  assert(level >= -1 && level <= 9, 'invalid compression level');\n\n  assert(memLevel >= 1 && memLevel <= 9, 'invalid memlevel');\n\n  assert(strategy === exports.Z_FILTERED || strategy === exports.Z_HUFFMAN_ONLY || strategy === exports.Z_RLE || strategy === exports.Z_FIXED || strategy === exports.Z_DEFAULT_STRATEGY, 'invalid strategy');\n\n  this._init(level, windowBits, memLevel, strategy, dictionary);\n  this._setDictionary();\n};\n\nZlib.prototype.params = function () {\n  throw new Error('deflateParams Not supported');\n};\n\nZlib.prototype.reset = function () {\n  this._reset();\n  this._setDictionary();\n};\n\nZlib.prototype._init = function (level, windowBits, memLevel, strategy, dictionary) {\n  this.level = level;\n  this.windowBits = windowBits;\n  this.memLevel = memLevel;\n  this.strategy = strategy;\n\n  this.flush = exports.Z_NO_FLUSH;\n\n  this.err = exports.Z_OK;\n\n  if (this.mode === exports.GZIP || this.mode === exports.GUNZIP) {\n    this.windowBits += 16;\n  }\n\n  if (this.mode === exports.UNZIP) {\n    this.windowBits += 32;\n  }\n\n  if (this.mode === exports.DEFLATERAW || this.mode === exports.INFLATERAW) {\n    this.windowBits = -1 * this.windowBits;\n  }\n\n  this.strm = new Zstream();\n\n  switch (this.mode) {\n    case exports.DEFLATE:\n    case exports.GZIP:\n    case exports.DEFLATERAW:\n      this.err = zlib_deflate.deflateInit2(this.strm, this.level, exports.Z_DEFLATED, this.windowBits, this.memLevel, this.strategy);\n      break;\n    case exports.INFLATE:\n    case exports.GUNZIP:\n    case exports.INFLATERAW:\n    case exports.UNZIP:\n      this.err = zlib_inflate.inflateInit2(this.strm, this.windowBits);\n      break;\n    default:\n      throw new Error('Unknown mode ' + this.mode);\n  }\n\n  if (this.err !== exports.Z_OK) {\n    this._error('Init error');\n  }\n\n  this.dictionary = dictionary;\n\n  this.write_in_progress = false;\n  this.init_done = true;\n};\n\nZlib.prototype._setDictionary = function () {\n  if (this.dictionary == null) {\n    return;\n  }\n\n  this.err = exports.Z_OK;\n\n  switch (this.mode) {\n    case exports.DEFLATE:\n    case exports.DEFLATERAW:\n      this.err = zlib_deflate.deflateSetDictionary(this.strm, this.dictionary);\n      break;\n    default:\n      break;\n  }\n\n  if (this.err !== exports.Z_OK) {\n    this._error('Failed to set dictionary');\n  }\n};\n\nZlib.prototype._reset = function () {\n  this.err = exports.Z_OK;\n\n  switch (this.mode) {\n    case exports.DEFLATE:\n    case exports.DEFLATERAW:\n    case exports.GZIP:\n      this.err = zlib_deflate.deflateReset(this.strm);\n      break;\n    case exports.INFLATE:\n    case exports.INFLATERAW:\n    case exports.GUNZIP:\n      this.err = zlib_inflate.inflateReset(this.strm);\n      break;\n    default:\n      break;\n  }\n\n  if (this.err !== exports.Z_OK) {\n    this._error('Failed to reset stream');\n  }\n};\n\nexports.Zlib = Zlib;\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer, __webpack_require__(11)))\n\n/***/ }),\n/* 151 */\n/***/ (function(module, exports) {\n\nmodule.exports = function isBuffer(arg) {\n  return arg && typeof arg === 'object'\n    && typeof arg.copy === 'function'\n    && typeof arg.fill === 'function'\n    && typeof arg.readUInt8 === 'function';\n}\n\n/***/ }),\n/* 152 */\n/***/ (function(module, exports) {\n\nif (typeof Object.create === 'function') {\n  // implementation from standard node.js 'util' module\n  module.exports = function inherits(ctor, superCtor) {\n    ctor.super_ = superCtor\n    ctor.prototype = Object.create(superCtor.prototype, {\n      constructor: {\n        value: ctor,\n        enumerable: false,\n        writable: true,\n        configurable: true\n      }\n    });\n  };\n} else {\n  // old school shim for old browsers\n  module.exports = function inherits(ctor, superCtor) {\n    ctor.super_ = superCtor\n    var TempCtor = function () {}\n    TempCtor.prototype = superCtor.prototype\n    ctor.prototype = new TempCtor()\n    ctor.prototype.constructor = ctor\n  }\n}\n\n\n/***/ }),\n/* 153 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nfunction ZStream() {\n  /* next input byte */\n  this.input = null; // JS specific, because we have no pointers\n  this.next_in = 0;\n  /* number of bytes available at input */\n  this.avail_in = 0;\n  /* total number of input bytes read so far */\n  this.total_in = 0;\n  /* next output byte should be put there */\n  this.output = null; // JS specific, because we have no pointers\n  this.next_out = 0;\n  /* remaining free space at output */\n  this.avail_out = 0;\n  /* total number of bytes output so far */\n  this.total_out = 0;\n  /* last error message, NULL if no error */\n  this.msg = ''/*Z_NULL*/;\n  /* not visible by applications */\n  this.state = null;\n  /* best guess about the data type: binary or text */\n  this.data_type = 2/*Z_UNKNOWN*/;\n  /* adler32 value of the uncompressed data */\n  this.adler = 0;\n}\n\nmodule.exports = ZStream;\n\n\n/***/ }),\n/* 154 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nvar utils   = __webpack_require__(34);\nvar trees   = __webpack_require__(155);\nvar adler32 = __webpack_require__(89);\nvar crc32   = __webpack_require__(90);\nvar msg     = __webpack_require__(156);\n\n/* Public constants ==========================================================*/\n/* ===========================================================================*/\n\n\n/* Allowed flush values; see deflate() and inflate() below for details */\nvar Z_NO_FLUSH      = 0;\nvar Z_PARTIAL_FLUSH = 1;\n//var Z_SYNC_FLUSH    = 2;\nvar Z_FULL_FLUSH    = 3;\nvar Z_FINISH        = 4;\nvar Z_BLOCK         = 5;\n//var Z_TREES         = 6;\n\n\n/* Return codes for the compression/decompression functions. Negative values\n * are errors, positive values are used for special but normal events.\n */\nvar Z_OK            = 0;\nvar Z_STREAM_END    = 1;\n//var Z_NEED_DICT     = 2;\n//var Z_ERRNO         = -1;\nvar Z_STREAM_ERROR  = -2;\nvar Z_DATA_ERROR    = -3;\n//var Z_MEM_ERROR     = -4;\nvar Z_BUF_ERROR     = -5;\n//var Z_VERSION_ERROR = -6;\n\n\n/* compression levels */\n//var Z_NO_COMPRESSION      = 0;\n//var Z_BEST_SPEED          = 1;\n//var Z_BEST_COMPRESSION    = 9;\nvar Z_DEFAULT_COMPRESSION = -1;\n\n\nvar Z_FILTERED            = 1;\nvar Z_HUFFMAN_ONLY        = 2;\nvar Z_RLE                 = 3;\nvar Z_FIXED               = 4;\nvar Z_DEFAULT_STRATEGY    = 0;\n\n/* Possible values of the data_type field (though see inflate()) */\n//var Z_BINARY              = 0;\n//var Z_TEXT                = 1;\n//var Z_ASCII               = 1; // = Z_TEXT\nvar Z_UNKNOWN             = 2;\n\n\n/* The deflate compression method */\nvar Z_DEFLATED  = 8;\n\n/*============================================================================*/\n\n\nvar MAX_MEM_LEVEL = 9;\n/* Maximum value for memLevel in deflateInit2 */\nvar MAX_WBITS = 15;\n/* 32K LZ77 window */\nvar DEF_MEM_LEVEL = 8;\n\n\nvar LENGTH_CODES  = 29;\n/* number of length codes, not counting the special END_BLOCK code */\nvar LITERALS      = 256;\n/* number of literal bytes 0..255 */\nvar L_CODES       = LITERALS + 1 + LENGTH_CODES;\n/* number of Literal or Length codes, including the END_BLOCK code */\nvar D_CODES       = 30;\n/* number of distance codes */\nvar BL_CODES      = 19;\n/* number of codes used to transfer the bit lengths */\nvar HEAP_SIZE     = 2 * L_CODES + 1;\n/* maximum heap size */\nvar MAX_BITS  = 15;\n/* All codes must not exceed MAX_BITS bits */\n\nvar MIN_MATCH = 3;\nvar MAX_MATCH = 258;\nvar MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);\n\nvar PRESET_DICT = 0x20;\n\nvar INIT_STATE = 42;\nvar EXTRA_STATE = 69;\nvar NAME_STATE = 73;\nvar COMMENT_STATE = 91;\nvar HCRC_STATE = 103;\nvar BUSY_STATE = 113;\nvar FINISH_STATE = 666;\n\nvar BS_NEED_MORE      = 1; /* block not completed, need more input or more output */\nvar BS_BLOCK_DONE     = 2; /* block flush performed */\nvar BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */\nvar BS_FINISH_DONE    = 4; /* finish done, accept no more input or output */\n\nvar OS_CODE = 0x03; // Unix :) . Don't detect, use this default.\n\nfunction err(strm, errorCode) {\n  strm.msg = msg[errorCode];\n  return errorCode;\n}\n\nfunction rank(f) {\n  return ((f) << 1) - ((f) > 4 ? 9 : 0);\n}\n\nfunction zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }\n\n\n/* =========================================================================\n * Flush as much pending output as possible. All deflate() output goes\n * through this function so some applications may wish to modify it\n * to avoid allocating a large strm->output buffer and copying into it.\n * (See also read_buf()).\n */\nfunction flush_pending(strm) {\n  var s = strm.state;\n\n  //_tr_flush_bits(s);\n  var len = s.pending;\n  if (len > strm.avail_out) {\n    len = strm.avail_out;\n  }\n  if (len === 0) { return; }\n\n  utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out);\n  strm.next_out += len;\n  s.pending_out += len;\n  strm.total_out += len;\n  strm.avail_out -= len;\n  s.pending -= len;\n  if (s.pending === 0) {\n    s.pending_out = 0;\n  }\n}\n\n\nfunction flush_block_only(s, last) {\n  trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);\n  s.block_start = s.strstart;\n  flush_pending(s.strm);\n}\n\n\nfunction put_byte(s, b) {\n  s.pending_buf[s.pending++] = b;\n}\n\n\n/* =========================================================================\n * Put a short in the pending buffer. The 16-bit value is put in MSB order.\n * IN assertion: the stream state is correct and there is enough room in\n * pending_buf.\n */\nfunction putShortMSB(s, b) {\n//  put_byte(s, (Byte)(b >> 8));\n//  put_byte(s, (Byte)(b & 0xff));\n  s.pending_buf[s.pending++] = (b >>> 8) & 0xff;\n  s.pending_buf[s.pending++] = b & 0xff;\n}\n\n\n/* ===========================================================================\n * Read a new buffer from the current input stream, update the adler32\n * and total number of bytes read.  All deflate() input goes through\n * this function so some applications may wish to modify it to avoid\n * allocating a large strm->input buffer and copying from it.\n * (See also flush_pending()).\n */\nfunction read_buf(strm, buf, start, size) {\n  var len = strm.avail_in;\n\n  if (len > size) { len = size; }\n  if (len === 0) { return 0; }\n\n  strm.avail_in -= len;\n\n  // zmemcpy(buf, strm->next_in, len);\n  utils.arraySet(buf, strm.input, strm.next_in, len, start);\n  if (strm.state.wrap === 1) {\n    strm.adler = adler32(strm.adler, buf, len, start);\n  }\n\n  else if (strm.state.wrap === 2) {\n    strm.adler = crc32(strm.adler, buf, len, start);\n  }\n\n  strm.next_in += len;\n  strm.total_in += len;\n\n  return len;\n}\n\n\n/* ===========================================================================\n * Set match_start to the longest match starting at the given string and\n * return its length. Matches shorter or equal to prev_length are discarded,\n * in which case the result is equal to prev_length and match_start is\n * garbage.\n * IN assertions: cur_match is the head of the hash chain for the current\n *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1\n * OUT assertion: the match length is not greater than s->lookahead.\n */\nfunction longest_match(s, cur_match) {\n  var chain_length = s.max_chain_length;      /* max hash chain length */\n  var scan = s.strstart; /* current string */\n  var match;                       /* matched string */\n  var len;                           /* length of current match */\n  var best_len = s.prev_length;              /* best match length so far */\n  var nice_match = s.nice_match;             /* stop if match long enough */\n  var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?\n      s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;\n\n  var _win = s.window; // shortcut\n\n  var wmask = s.w_mask;\n  var prev  = s.prev;\n\n  /* Stop when cur_match becomes <= limit. To simplify the code,\n   * we prevent matches with the string of window index 0.\n   */\n\n  var strend = s.strstart + MAX_MATCH;\n  var scan_end1  = _win[scan + best_len - 1];\n  var scan_end   = _win[scan + best_len];\n\n  /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.\n   * It is easy to get rid of this optimization if necessary.\n   */\n  // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, \"Code too clever\");\n\n  /* Do not waste too much time if we already have a good match: */\n  if (s.prev_length >= s.good_match) {\n    chain_length >>= 2;\n  }\n  /* Do not look for matches beyond the end of the input. This is necessary\n   * to make deflate deterministic.\n   */\n  if (nice_match > s.lookahead) { nice_match = s.lookahead; }\n\n  // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, \"need lookahead\");\n\n  do {\n    // Assert(cur_match < s->strstart, \"no future\");\n    match = cur_match;\n\n    /* Skip to next match if the match length cannot increase\n     * or if the match length is less than 2.  Note that the checks below\n     * for insufficient lookahead only occur occasionally for performance\n     * reasons.  Therefore uninitialized memory will be accessed, and\n     * conditional jumps will be made that depend on those values.\n     * However the length of the match is limited to the lookahead, so\n     * the output of deflate is not affected by the uninitialized values.\n     */\n\n    if (_win[match + best_len]     !== scan_end  ||\n        _win[match + best_len - 1] !== scan_end1 ||\n        _win[match]                !== _win[scan] ||\n        _win[++match]              !== _win[scan + 1]) {\n      continue;\n    }\n\n    /* The check at best_len-1 can be removed because it will be made\n     * again later. (This heuristic is not always a win.)\n     * It is not necessary to compare scan[2] and match[2] since they\n     * are always equal when the other bytes match, given that\n     * the hash keys are equal and that HASH_BITS >= 8.\n     */\n    scan += 2;\n    match++;\n    // Assert(*scan == *match, \"match[2]?\");\n\n    /* We check for insufficient lookahead only every 8th comparison;\n     * the 256th check will be made at strstart+258.\n     */\n    do {\n      /*jshint noempty:false*/\n    } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             scan < strend);\n\n    // Assert(scan <= s->window+(unsigned)(s->window_size-1), \"wild scan\");\n\n    len = MAX_MATCH - (strend - scan);\n    scan = strend - MAX_MATCH;\n\n    if (len > best_len) {\n      s.match_start = cur_match;\n      best_len = len;\n      if (len >= nice_match) {\n        break;\n      }\n      scan_end1  = _win[scan + best_len - 1];\n      scan_end   = _win[scan + best_len];\n    }\n  } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);\n\n  if (best_len <= s.lookahead) {\n    return best_len;\n  }\n  return s.lookahead;\n}\n\n\n/* ===========================================================================\n * Fill the window when the lookahead becomes insufficient.\n * Updates strstart and lookahead.\n *\n * IN assertion: lookahead < MIN_LOOKAHEAD\n * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD\n *    At least one byte has been read, or avail_in == 0; reads are\n *    performed for at least two bytes (required for the zip translate_eol\n *    option -- not supported here).\n */\nfunction fill_window(s) {\n  var _w_size = s.w_size;\n  var p, n, m, more, str;\n\n  //Assert(s->lookahead < MIN_LOOKAHEAD, \"already enough lookahead\");\n\n  do {\n    more = s.window_size - s.lookahead - s.strstart;\n\n    // JS ints have 32 bit, block below not needed\n    /* Deal with !@#$% 64K limit: */\n    //if (sizeof(int) <= 2) {\n    //    if (more == 0 && s->strstart == 0 && s->lookahead == 0) {\n    //        more = wsize;\n    //\n    //  } else if (more == (unsigned)(-1)) {\n    //        /* Very unlikely, but possible on 16 bit machine if\n    //         * strstart == 0 && lookahead == 1 (input done a byte at time)\n    //         */\n    //        more--;\n    //    }\n    //}\n\n\n    /* If the window is almost full and there is insufficient lookahead,\n     * move the upper half to the lower one to make room in the upper half.\n     */\n    if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {\n\n      utils.arraySet(s.window, s.window, _w_size, _w_size, 0);\n      s.match_start -= _w_size;\n      s.strstart -= _w_size;\n      /* we now have strstart >= MAX_DIST */\n      s.block_start -= _w_size;\n\n      /* Slide the hash table (could be avoided with 32 bit values\n       at the expense of memory usage). We slide even when level == 0\n       to keep the hash table consistent if we switch back to level > 0\n       later. (Using level 0 permanently is not an optimal usage of\n       zlib, so we don't care about this pathological case.)\n       */\n\n      n = s.hash_size;\n      p = n;\n      do {\n        m = s.head[--p];\n        s.head[p] = (m >= _w_size ? m - _w_size : 0);\n      } while (--n);\n\n      n = _w_size;\n      p = n;\n      do {\n        m = s.prev[--p];\n        s.prev[p] = (m >= _w_size ? m - _w_size : 0);\n        /* If n is not on any hash chain, prev[n] is garbage but\n         * its value will never be used.\n         */\n      } while (--n);\n\n      more += _w_size;\n    }\n    if (s.strm.avail_in === 0) {\n      break;\n    }\n\n    /* If there was no sliding:\n     *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&\n     *    more == window_size - lookahead - strstart\n     * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)\n     * => more >= window_size - 2*WSIZE + 2\n     * In the BIG_MEM or MMAP case (not yet supported),\n     *   window_size == input_size + MIN_LOOKAHEAD  &&\n     *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.\n     * Otherwise, window_size == 2*WSIZE so more >= 2.\n     * If there was sliding, more >= WSIZE. So in all cases, more >= 2.\n     */\n    //Assert(more >= 2, \"more < 2\");\n    n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);\n    s.lookahead += n;\n\n    /* Initialize the hash value now that we have some input: */\n    if (s.lookahead + s.insert >= MIN_MATCH) {\n      str = s.strstart - s.insert;\n      s.ins_h = s.window[str];\n\n      /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */\n      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask;\n//#if MIN_MATCH != 3\n//        Call update_hash() MIN_MATCH-3 more times\n//#endif\n      while (s.insert) {\n        /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */\n        s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask;\n\n        s.prev[str & s.w_mask] = s.head[s.ins_h];\n        s.head[s.ins_h] = str;\n        str++;\n        s.insert--;\n        if (s.lookahead + s.insert < MIN_MATCH) {\n          break;\n        }\n      }\n    }\n    /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,\n     * but this is not important since only literal bytes will be emitted.\n     */\n\n  } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);\n\n  /* If the WIN_INIT bytes after the end of the current data have never been\n   * written, then zero those bytes in order to avoid memory check reports of\n   * the use of uninitialized (or uninitialised as Julian writes) bytes by\n   * the longest match routines.  Update the high water mark for the next\n   * time through here.  WIN_INIT is set to MAX_MATCH since the longest match\n   * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.\n   */\n//  if (s.high_water < s.window_size) {\n//    var curr = s.strstart + s.lookahead;\n//    var init = 0;\n//\n//    if (s.high_water < curr) {\n//      /* Previous high water mark below current data -- zero WIN_INIT\n//       * bytes or up to end of window, whichever is less.\n//       */\n//      init = s.window_size - curr;\n//      if (init > WIN_INIT)\n//        init = WIN_INIT;\n//      zmemzero(s->window + curr, (unsigned)init);\n//      s->high_water = curr + init;\n//    }\n//    else if (s->high_water < (ulg)curr + WIN_INIT) {\n//      /* High water mark at or above current data, but below current data\n//       * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up\n//       * to end of window, whichever is less.\n//       */\n//      init = (ulg)curr + WIN_INIT - s->high_water;\n//      if (init > s->window_size - s->high_water)\n//        init = s->window_size - s->high_water;\n//      zmemzero(s->window + s->high_water, (unsigned)init);\n//      s->high_water += init;\n//    }\n//  }\n//\n//  Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,\n//    \"not enough room for search\");\n}\n\n/* ===========================================================================\n * Copy without compression as much as possible from the input stream, return\n * the current block state.\n * This function does not insert new strings in the dictionary since\n * uncompressible data is probably not useful. This function is used\n * only for the level=0 compression option.\n * NOTE: this function should be optimized to avoid extra copying from\n * window to pending_buf.\n */\nfunction deflate_stored(s, flush) {\n  /* Stored blocks are limited to 0xffff bytes, pending_buf is limited\n   * to pending_buf_size, and each stored block has a 5 byte header:\n   */\n  var max_block_size = 0xffff;\n\n  if (max_block_size > s.pending_buf_size - 5) {\n    max_block_size = s.pending_buf_size - 5;\n  }\n\n  /* Copy as much as possible from input to output: */\n  for (;;) {\n    /* Fill the window as much as possible: */\n    if (s.lookahead <= 1) {\n\n      //Assert(s->strstart < s->w_size+MAX_DIST(s) ||\n      //  s->block_start >= (long)s->w_size, \"slide too late\");\n//      if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) ||\n//        s.block_start >= s.w_size)) {\n//        throw  new Error(\"slide too late\");\n//      }\n\n      fill_window(s);\n      if (s.lookahead === 0 && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n\n      if (s.lookahead === 0) {\n        break;\n      }\n      /* flush the current block */\n    }\n    //Assert(s->block_start >= 0L, \"block gone\");\n//    if (s.block_start < 0) throw new Error(\"block gone\");\n\n    s.strstart += s.lookahead;\n    s.lookahead = 0;\n\n    /* Emit a stored block if pending_buf will be full: */\n    var max_start = s.block_start + max_block_size;\n\n    if (s.strstart === 0 || s.strstart >= max_start) {\n      /* strstart == 0 is possible when wraparound on 16-bit machine */\n      s.lookahead = s.strstart - max_start;\n      s.strstart = max_start;\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n\n\n    }\n    /* Flush if we may have to slide, otherwise block_start may become\n     * negative and the data will be gone:\n     */\n    if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n\n  s.insert = 0;\n\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n\n  if (s.strstart > s.block_start) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n\n  return BS_NEED_MORE;\n}\n\n/* ===========================================================================\n * Compress as much as possible from the input stream, return the current\n * block state.\n * This function does not perform lazy evaluation of matches and inserts\n * new strings in the dictionary only for unmatched strings or for short\n * matches. It is used only for the fast compression options.\n */\nfunction deflate_fast(s, flush) {\n  var hash_head;        /* head of the hash chain */\n  var bflush;           /* set if current block must be flushed */\n\n  for (;;) {\n    /* Make sure that we always have enough lookahead, except\n     * at the end of the input file. We need MAX_MATCH bytes\n     * for the next match, plus MIN_MATCH bytes to insert the\n     * string following the next match.\n     */\n    if (s.lookahead < MIN_LOOKAHEAD) {\n      fill_window(s);\n      if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n      if (s.lookahead === 0) {\n        break; /* flush the current block */\n      }\n    }\n\n    /* Insert the string window[strstart .. strstart+2] in the\n     * dictionary, and set hash_head to the head of the hash chain:\n     */\n    hash_head = 0/*NIL*/;\n    if (s.lookahead >= MIN_MATCH) {\n      /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n      hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n      s.head[s.ins_h] = s.strstart;\n      /***/\n    }\n\n    /* Find the longest match, discarding those <= prev_length.\n     * At this point we have always match_length < MIN_MATCH\n     */\n    if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {\n      /* To simplify the code, we prevent matches with the string\n       * of window index 0 (in particular we have to avoid a match\n       * of the string with itself at the start of the input file).\n       */\n      s.match_length = longest_match(s, hash_head);\n      /* longest_match() sets match_start */\n    }\n    if (s.match_length >= MIN_MATCH) {\n      // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only\n\n      /*** _tr_tally_dist(s, s.strstart - s.match_start,\n                     s.match_length - MIN_MATCH, bflush); ***/\n      bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);\n\n      s.lookahead -= s.match_length;\n\n      /* Insert new strings in the hash table only if the match length\n       * is not too large. This saves time but degrades compression.\n       */\n      if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) {\n        s.match_length--; /* string at strstart already in table */\n        do {\n          s.strstart++;\n          /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n          s.head[s.ins_h] = s.strstart;\n          /***/\n          /* strstart never exceeds WSIZE-MAX_MATCH, so there are\n           * always MIN_MATCH bytes ahead.\n           */\n        } while (--s.match_length !== 0);\n        s.strstart++;\n      } else\n      {\n        s.strstart += s.match_length;\n        s.match_length = 0;\n        s.ins_h = s.window[s.strstart];\n        /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */\n        s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask;\n\n//#if MIN_MATCH != 3\n//                Call UPDATE_HASH() MIN_MATCH-3 more times\n//#endif\n        /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not\n         * matter since it will be recomputed at next deflate call.\n         */\n      }\n    } else {\n      /* No match, output a literal byte */\n      //Tracevv((stderr,\"%c\", s.window[s.strstart]));\n      /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/\n      bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n\n      s.lookahead--;\n      s.strstart++;\n    }\n    if (bflush) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n  s.insert = ((s.strstart < (MIN_MATCH - 1)) ? s.strstart : MIN_MATCH - 1);\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n  return BS_BLOCK_DONE;\n}\n\n/* ===========================================================================\n * Same as above, but achieves better compression. We use a lazy\n * evaluation for matches: a match is finally adopted only if there is\n * no better match at the next window position.\n */\nfunction deflate_slow(s, flush) {\n  var hash_head;          /* head of hash chain */\n  var bflush;              /* set if current block must be flushed */\n\n  var max_insert;\n\n  /* Process the input block. */\n  for (;;) {\n    /* Make sure that we always have enough lookahead, except\n     * at the end of the input file. We need MAX_MATCH bytes\n     * for the next match, plus MIN_MATCH bytes to insert the\n     * string following the next match.\n     */\n    if (s.lookahead < MIN_LOOKAHEAD) {\n      fill_window(s);\n      if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n      if (s.lookahead === 0) { break; } /* flush the current block */\n    }\n\n    /* Insert the string window[strstart .. strstart+2] in the\n     * dictionary, and set hash_head to the head of the hash chain:\n     */\n    hash_head = 0/*NIL*/;\n    if (s.lookahead >= MIN_MATCH) {\n      /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n      hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n      s.head[s.ins_h] = s.strstart;\n      /***/\n    }\n\n    /* Find the longest match, discarding those <= prev_length.\n     */\n    s.prev_length = s.match_length;\n    s.prev_match = s.match_start;\n    s.match_length = MIN_MATCH - 1;\n\n    if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&\n        s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {\n      /* To simplify the code, we prevent matches with the string\n       * of window index 0 (in particular we have to avoid a match\n       * of the string with itself at the start of the input file).\n       */\n      s.match_length = longest_match(s, hash_head);\n      /* longest_match() sets match_start */\n\n      if (s.match_length <= 5 &&\n         (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {\n\n        /* If prev_match is also MIN_MATCH, match_start is garbage\n         * but we will ignore the current match anyway.\n         */\n        s.match_length = MIN_MATCH - 1;\n      }\n    }\n    /* If there was a match at the previous step and the current\n     * match is not better, output the previous match:\n     */\n    if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {\n      max_insert = s.strstart + s.lookahead - MIN_MATCH;\n      /* Do not insert strings in hash table beyond this. */\n\n      //check_match(s, s.strstart-1, s.prev_match, s.prev_length);\n\n      /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,\n                     s.prev_length - MIN_MATCH, bflush);***/\n      bflush = trees._tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH);\n      /* Insert in hash table all strings up to the end of the match.\n       * strstart-1 and strstart are already inserted. If there is not\n       * enough lookahead, the last two strings are not inserted in\n       * the hash table.\n       */\n      s.lookahead -= s.prev_length - 1;\n      s.prev_length -= 2;\n      do {\n        if (++s.strstart <= max_insert) {\n          /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n          s.head[s.ins_h] = s.strstart;\n          /***/\n        }\n      } while (--s.prev_length !== 0);\n      s.match_available = 0;\n      s.match_length = MIN_MATCH - 1;\n      s.strstart++;\n\n      if (bflush) {\n        /*** FLUSH_BLOCK(s, 0); ***/\n        flush_block_only(s, false);\n        if (s.strm.avail_out === 0) {\n          return BS_NEED_MORE;\n        }\n        /***/\n      }\n\n    } else if (s.match_available) {\n      /* If there was no match at the previous position, output a\n       * single literal. If there was a match but the current match\n       * is longer, truncate the previous match to a single literal.\n       */\n      //Tracevv((stderr,\"%c\", s->window[s->strstart-1]));\n      /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/\n      bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]);\n\n      if (bflush) {\n        /*** FLUSH_BLOCK_ONLY(s, 0) ***/\n        flush_block_only(s, false);\n        /***/\n      }\n      s.strstart++;\n      s.lookahead--;\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n    } else {\n      /* There is no previous match to compare with, wait for\n       * the next step to decide.\n       */\n      s.match_available = 1;\n      s.strstart++;\n      s.lookahead--;\n    }\n  }\n  //Assert (flush != Z_NO_FLUSH, \"no flush?\");\n  if (s.match_available) {\n    //Tracevv((stderr,\"%c\", s->window[s->strstart-1]));\n    /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/\n    bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]);\n\n    s.match_available = 0;\n  }\n  s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1;\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n\n  return BS_BLOCK_DONE;\n}\n\n\n/* ===========================================================================\n * For Z_RLE, simply look for runs of bytes, generate matches only of distance\n * one.  Do not maintain a hash table.  (It will be regenerated if this run of\n * deflate switches away from Z_RLE.)\n */\nfunction deflate_rle(s, flush) {\n  var bflush;            /* set if current block must be flushed */\n  var prev;              /* byte at distance one to match */\n  var scan, strend;      /* scan goes up to strend for length of run */\n\n  var _win = s.window;\n\n  for (;;) {\n    /* Make sure that we always have enough lookahead, except\n     * at the end of the input file. We need MAX_MATCH bytes\n     * for the longest run, plus one for the unrolled loop.\n     */\n    if (s.lookahead <= MAX_MATCH) {\n      fill_window(s);\n      if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n      if (s.lookahead === 0) { break; } /* flush the current block */\n    }\n\n    /* See how many times the previous byte repeats */\n    s.match_length = 0;\n    if (s.lookahead >= MIN_MATCH && s.strstart > 0) {\n      scan = s.strstart - 1;\n      prev = _win[scan];\n      if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {\n        strend = s.strstart + MAX_MATCH;\n        do {\n          /*jshint noempty:false*/\n        } while (prev === _win[++scan] && prev === _win[++scan] &&\n                 prev === _win[++scan] && prev === _win[++scan] &&\n                 prev === _win[++scan] && prev === _win[++scan] &&\n                 prev === _win[++scan] && prev === _win[++scan] &&\n                 scan < strend);\n        s.match_length = MAX_MATCH - (strend - scan);\n        if (s.match_length > s.lookahead) {\n          s.match_length = s.lookahead;\n        }\n      }\n      //Assert(scan <= s->window+(uInt)(s->window_size-1), \"wild scan\");\n    }\n\n    /* Emit match if have run of MIN_MATCH or longer, else emit literal */\n    if (s.match_length >= MIN_MATCH) {\n      //check_match(s, s.strstart, s.strstart - 1, s.match_length);\n\n      /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/\n      bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH);\n\n      s.lookahead -= s.match_length;\n      s.strstart += s.match_length;\n      s.match_length = 0;\n    } else {\n      /* No match, output a literal byte */\n      //Tracevv((stderr,\"%c\", s->window[s->strstart]));\n      /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/\n      bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n\n      s.lookahead--;\n      s.strstart++;\n    }\n    if (bflush) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n  s.insert = 0;\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n  return BS_BLOCK_DONE;\n}\n\n/* ===========================================================================\n * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.\n * (It will be regenerated if this run of deflate switches away from Huffman.)\n */\nfunction deflate_huff(s, flush) {\n  var bflush;             /* set if current block must be flushed */\n\n  for (;;) {\n    /* Make sure that we have a literal to write. */\n    if (s.lookahead === 0) {\n      fill_window(s);\n      if (s.lookahead === 0) {\n        if (flush === Z_NO_FLUSH) {\n          return BS_NEED_MORE;\n        }\n        break;      /* flush the current block */\n      }\n    }\n\n    /* Output a literal byte */\n    s.match_length = 0;\n    //Tracevv((stderr,\"%c\", s->window[s->strstart]));\n    /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/\n    bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n    s.lookahead--;\n    s.strstart++;\n    if (bflush) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n  s.insert = 0;\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n  return BS_BLOCK_DONE;\n}\n\n/* Values for max_lazy_match, good_match and max_chain_length, depending on\n * the desired pack level (0..9). The values given below have been tuned to\n * exclude worst case performance for pathological files. Better values may be\n * found for specific files.\n */\nfunction Config(good_length, max_lazy, nice_length, max_chain, func) {\n  this.good_length = good_length;\n  this.max_lazy = max_lazy;\n  this.nice_length = nice_length;\n  this.max_chain = max_chain;\n  this.func = func;\n}\n\nvar configuration_table;\n\nconfiguration_table = [\n  /*      good lazy nice chain */\n  new Config(0, 0, 0, 0, deflate_stored),          /* 0 store only */\n  new Config(4, 4, 8, 4, deflate_fast),            /* 1 max speed, no lazy matches */\n  new Config(4, 5, 16, 8, deflate_fast),           /* 2 */\n  new Config(4, 6, 32, 32, deflate_fast),          /* 3 */\n\n  new Config(4, 4, 16, 16, deflate_slow),          /* 4 lazy matches */\n  new Config(8, 16, 32, 32, deflate_slow),         /* 5 */\n  new Config(8, 16, 128, 128, deflate_slow),       /* 6 */\n  new Config(8, 32, 128, 256, deflate_slow),       /* 7 */\n  new Config(32, 128, 258, 1024, deflate_slow),    /* 8 */\n  new Config(32, 258, 258, 4096, deflate_slow)     /* 9 max compression */\n];\n\n\n/* ===========================================================================\n * Initialize the \"longest match\" routines for a new zlib stream\n */\nfunction lm_init(s) {\n  s.window_size = 2 * s.w_size;\n\n  /*** CLEAR_HASH(s); ***/\n  zero(s.head); // Fill with NIL (= 0);\n\n  /* Set the default configuration parameters:\n   */\n  s.max_lazy_match = configuration_table[s.level].max_lazy;\n  s.good_match = configuration_table[s.level].good_length;\n  s.nice_match = configuration_table[s.level].nice_length;\n  s.max_chain_length = configuration_table[s.level].max_chain;\n\n  s.strstart = 0;\n  s.block_start = 0;\n  s.lookahead = 0;\n  s.insert = 0;\n  s.match_length = s.prev_length = MIN_MATCH - 1;\n  s.match_available = 0;\n  s.ins_h = 0;\n}\n\n\nfunction DeflateState() {\n  this.strm = null;            /* pointer back to this zlib stream */\n  this.status = 0;            /* as the name implies */\n  this.pending_buf = null;      /* output still pending */\n  this.pending_buf_size = 0;  /* size of pending_buf */\n  this.pending_out = 0;       /* next pending byte to output to the stream */\n  this.pending = 0;           /* nb of bytes in the pending buffer */\n  this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */\n  this.gzhead = null;         /* gzip header information to write */\n  this.gzindex = 0;           /* where in extra, name, or comment */\n  this.method = Z_DEFLATED; /* can only be DEFLATED */\n  this.last_flush = -1;   /* value of flush param for previous deflate call */\n\n  this.w_size = 0;  /* LZ77 window size (32K by default) */\n  this.w_bits = 0;  /* log2(w_size)  (8..16) */\n  this.w_mask = 0;  /* w_size - 1 */\n\n  this.window = null;\n  /* Sliding window. Input bytes are read into the second half of the window,\n   * and move to the first half later to keep a dictionary of at least wSize\n   * bytes. With this organization, matches are limited to a distance of\n   * wSize-MAX_MATCH bytes, but this ensures that IO is always\n   * performed with a length multiple of the block size.\n   */\n\n  this.window_size = 0;\n  /* Actual size of window: 2*wSize, except when the user input buffer\n   * is directly used as sliding window.\n   */\n\n  this.prev = null;\n  /* Link to older string with same hash index. To limit the size of this\n   * array to 64K, this link is maintained only for the last 32K strings.\n   * An index in this array is thus a window index modulo 32K.\n   */\n\n  this.head = null;   /* Heads of the hash chains or NIL. */\n\n  this.ins_h = 0;       /* hash index of string to be inserted */\n  this.hash_size = 0;   /* number of elements in hash table */\n  this.hash_bits = 0;   /* log2(hash_size) */\n  this.hash_mask = 0;   /* hash_size-1 */\n\n  this.hash_shift = 0;\n  /* Number of bits by which ins_h must be shifted at each input\n   * step. It must be such that after MIN_MATCH steps, the oldest\n   * byte no longer takes part in the hash key, that is:\n   *   hash_shift * MIN_MATCH >= hash_bits\n   */\n\n  this.block_start = 0;\n  /* Window position at the beginning of the current output block. Gets\n   * negative when the window is moved backwards.\n   */\n\n  this.match_length = 0;      /* length of best match */\n  this.prev_match = 0;        /* previous match */\n  this.match_available = 0;   /* set if previous match exists */\n  this.strstart = 0;          /* start of string to insert */\n  this.match_start = 0;       /* start of matching string */\n  this.lookahead = 0;         /* number of valid bytes ahead in window */\n\n  this.prev_length = 0;\n  /* Length of the best match at previous step. Matches not greater than this\n   * are discarded. This is used in the lazy match evaluation.\n   */\n\n  this.max_chain_length = 0;\n  /* To speed up deflation, hash chains are never searched beyond this\n   * length.  A higher limit improves compression ratio but degrades the\n   * speed.\n   */\n\n  this.max_lazy_match = 0;\n  /* Attempt to find a better match only when the current match is strictly\n   * smaller than this value. This mechanism is used only for compression\n   * levels >= 4.\n   */\n  // That's alias to max_lazy_match, don't use directly\n  //this.max_insert_length = 0;\n  /* Insert new strings in the hash table only if the match length is not\n   * greater than this length. This saves time but degrades compression.\n   * max_insert_length is used only for compression levels <= 3.\n   */\n\n  this.level = 0;     /* compression level (1..9) */\n  this.strategy = 0;  /* favor or force Huffman coding*/\n\n  this.good_match = 0;\n  /* Use a faster search when the previous match is longer than this */\n\n  this.nice_match = 0; /* Stop searching when current match exceeds this */\n\n              /* used by trees.c: */\n\n  /* Didn't use ct_data typedef below to suppress compiler warning */\n\n  // struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */\n  // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */\n  // struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */\n\n  // Use flat array of DOUBLE size, with interleaved fata,\n  // because JS does not support effective\n  this.dyn_ltree  = new utils.Buf16(HEAP_SIZE * 2);\n  this.dyn_dtree  = new utils.Buf16((2 * D_CODES + 1) * 2);\n  this.bl_tree    = new utils.Buf16((2 * BL_CODES + 1) * 2);\n  zero(this.dyn_ltree);\n  zero(this.dyn_dtree);\n  zero(this.bl_tree);\n\n  this.l_desc   = null;         /* desc. for literal tree */\n  this.d_desc   = null;         /* desc. for distance tree */\n  this.bl_desc  = null;         /* desc. for bit length tree */\n\n  //ush bl_count[MAX_BITS+1];\n  this.bl_count = new utils.Buf16(MAX_BITS + 1);\n  /* number of codes at each bit length for an optimal tree */\n\n  //int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */\n  this.heap = new utils.Buf16(2 * L_CODES + 1);  /* heap used to build the Huffman trees */\n  zero(this.heap);\n\n  this.heap_len = 0;               /* number of elements in the heap */\n  this.heap_max = 0;               /* element of largest frequency */\n  /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.\n   * The same heap array is used to build all trees.\n   */\n\n  this.depth = new utils.Buf16(2 * L_CODES + 1); //uch depth[2*L_CODES+1];\n  zero(this.depth);\n  /* Depth of each subtree used as tie breaker for trees of equal frequency\n   */\n\n  this.l_buf = 0;          /* buffer index for literals or lengths */\n\n  this.lit_bufsize = 0;\n  /* Size of match buffer for literals/lengths.  There are 4 reasons for\n   * limiting lit_bufsize to 64K:\n   *   - frequencies can be kept in 16 bit counters\n   *   - if compression is not successful for the first block, all input\n   *     data is still in the window so we can still emit a stored block even\n   *     when input comes from standard input.  (This can also be done for\n   *     all blocks if lit_bufsize is not greater than 32K.)\n   *   - if compression is not successful for a file smaller than 64K, we can\n   *     even emit a stored file instead of a stored block (saving 5 bytes).\n   *     This is applicable only for zip (not gzip or zlib).\n   *   - creating new Huffman trees less frequently may not provide fast\n   *     adaptation to changes in the input data statistics. (Take for\n   *     example a binary file with poorly compressible code followed by\n   *     a highly compressible string table.) Smaller buffer sizes give\n   *     fast adaptation but have of course the overhead of transmitting\n   *     trees more frequently.\n   *   - I can't count above 4\n   */\n\n  this.last_lit = 0;      /* running index in l_buf */\n\n  this.d_buf = 0;\n  /* Buffer index for distances. To simplify the code, d_buf and l_buf have\n   * the same number of elements. To use different lengths, an extra flag\n   * array would be necessary.\n   */\n\n  this.opt_len = 0;       /* bit length of current block with optimal trees */\n  this.static_len = 0;    /* bit length of current block with static trees */\n  this.matches = 0;       /* number of string matches in current block */\n  this.insert = 0;        /* bytes at end of window left to insert */\n\n\n  this.bi_buf = 0;\n  /* Output buffer. bits are inserted starting at the bottom (least\n   * significant bits).\n   */\n  this.bi_valid = 0;\n  /* Number of valid bits in bi_buf.  All bits above the last valid bit\n   * are always zero.\n   */\n\n  // Used for window memory init. We safely ignore it for JS. That makes\n  // sense only for pointers and memory check tools.\n  //this.high_water = 0;\n  /* High water mark offset in window for initialized bytes -- bytes above\n   * this are set to zero in order to avoid memory check warnings when\n   * longest match routines access bytes past the input.  This is then\n   * updated to the new high water mark.\n   */\n}\n\n\nfunction deflateResetKeep(strm) {\n  var s;\n\n  if (!strm || !strm.state) {\n    return err(strm, Z_STREAM_ERROR);\n  }\n\n  strm.total_in = strm.total_out = 0;\n  strm.data_type = Z_UNKNOWN;\n\n  s = strm.state;\n  s.pending = 0;\n  s.pending_out = 0;\n\n  if (s.wrap < 0) {\n    s.wrap = -s.wrap;\n    /* was made negative by deflate(..., Z_FINISH); */\n  }\n  s.status = (s.wrap ? INIT_STATE : BUSY_STATE);\n  strm.adler = (s.wrap === 2) ?\n    0  // crc32(0, Z_NULL, 0)\n  :\n    1; // adler32(0, Z_NULL, 0)\n  s.last_flush = Z_NO_FLUSH;\n  trees._tr_init(s);\n  return Z_OK;\n}\n\n\nfunction deflateReset(strm) {\n  var ret = deflateResetKeep(strm);\n  if (ret === Z_OK) {\n    lm_init(strm.state);\n  }\n  return ret;\n}\n\n\nfunction deflateSetHeader(strm, head) {\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; }\n  strm.state.gzhead = head;\n  return Z_OK;\n}\n\n\nfunction deflateInit2(strm, level, method, windowBits, memLevel, strategy) {\n  if (!strm) { // === Z_NULL\n    return Z_STREAM_ERROR;\n  }\n  var wrap = 1;\n\n  if (level === Z_DEFAULT_COMPRESSION) {\n    level = 6;\n  }\n\n  if (windowBits < 0) { /* suppress zlib wrapper */\n    wrap = 0;\n    windowBits = -windowBits;\n  }\n\n  else if (windowBits > 15) {\n    wrap = 2;           /* write gzip wrapper instead */\n    windowBits -= 16;\n  }\n\n\n  if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED ||\n    windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||\n    strategy < 0 || strategy > Z_FIXED) {\n    return err(strm, Z_STREAM_ERROR);\n  }\n\n\n  if (windowBits === 8) {\n    windowBits = 9;\n  }\n  /* until 256-byte window bug fixed */\n\n  var s = new DeflateState();\n\n  strm.state = s;\n  s.strm = strm;\n\n  s.wrap = wrap;\n  s.gzhead = null;\n  s.w_bits = windowBits;\n  s.w_size = 1 << s.w_bits;\n  s.w_mask = s.w_size - 1;\n\n  s.hash_bits = memLevel + 7;\n  s.hash_size = 1 << s.hash_bits;\n  s.hash_mask = s.hash_size - 1;\n  s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);\n\n  s.window = new utils.Buf8(s.w_size * 2);\n  s.head = new utils.Buf16(s.hash_size);\n  s.prev = new utils.Buf16(s.w_size);\n\n  // Don't need mem init magic for JS.\n  //s.high_water = 0;  /* nothing written to s->window yet */\n\n  s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */\n\n  s.pending_buf_size = s.lit_bufsize * 4;\n\n  //overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);\n  //s->pending_buf = (uchf *) overlay;\n  s.pending_buf = new utils.Buf8(s.pending_buf_size);\n\n  // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`)\n  //s->d_buf = overlay + s->lit_bufsize/sizeof(ush);\n  s.d_buf = 1 * s.lit_bufsize;\n\n  //s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;\n  s.l_buf = (1 + 2) * s.lit_bufsize;\n\n  s.level = level;\n  s.strategy = strategy;\n  s.method = method;\n\n  return deflateReset(strm);\n}\n\nfunction deflateInit(strm, level) {\n  return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);\n}\n\n\nfunction deflate(strm, flush) {\n  var old_flush, s;\n  var beg, val; // for gzip header write only\n\n  if (!strm || !strm.state ||\n    flush > Z_BLOCK || flush < 0) {\n    return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR;\n  }\n\n  s = strm.state;\n\n  if (!strm.output ||\n      (!strm.input && strm.avail_in !== 0) ||\n      (s.status === FINISH_STATE && flush !== Z_FINISH)) {\n    return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR);\n  }\n\n  s.strm = strm; /* just in case */\n  old_flush = s.last_flush;\n  s.last_flush = flush;\n\n  /* Write the header */\n  if (s.status === INIT_STATE) {\n\n    if (s.wrap === 2) { // GZIP header\n      strm.adler = 0;  //crc32(0L, Z_NULL, 0);\n      put_byte(s, 31);\n      put_byte(s, 139);\n      put_byte(s, 8);\n      if (!s.gzhead) { // s->gzhead == Z_NULL\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, s.level === 9 ? 2 :\n                    (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?\n                     4 : 0));\n        put_byte(s, OS_CODE);\n        s.status = BUSY_STATE;\n      }\n      else {\n        put_byte(s, (s.gzhead.text ? 1 : 0) +\n                    (s.gzhead.hcrc ? 2 : 0) +\n                    (!s.gzhead.extra ? 0 : 4) +\n                    (!s.gzhead.name ? 0 : 8) +\n                    (!s.gzhead.comment ? 0 : 16)\n                );\n        put_byte(s, s.gzhead.time & 0xff);\n        put_byte(s, (s.gzhead.time >> 8) & 0xff);\n        put_byte(s, (s.gzhead.time >> 16) & 0xff);\n        put_byte(s, (s.gzhead.time >> 24) & 0xff);\n        put_byte(s, s.level === 9 ? 2 :\n                    (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?\n                     4 : 0));\n        put_byte(s, s.gzhead.os & 0xff);\n        if (s.gzhead.extra && s.gzhead.extra.length) {\n          put_byte(s, s.gzhead.extra.length & 0xff);\n          put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);\n        }\n        if (s.gzhead.hcrc) {\n          strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0);\n        }\n        s.gzindex = 0;\n        s.status = EXTRA_STATE;\n      }\n    }\n    else // DEFLATE header\n    {\n      var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8;\n      var level_flags = -1;\n\n      if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {\n        level_flags = 0;\n      } else if (s.level < 6) {\n        level_flags = 1;\n      } else if (s.level === 6) {\n        level_flags = 2;\n      } else {\n        level_flags = 3;\n      }\n      header |= (level_flags << 6);\n      if (s.strstart !== 0) { header |= PRESET_DICT; }\n      header += 31 - (header % 31);\n\n      s.status = BUSY_STATE;\n      putShortMSB(s, header);\n\n      /* Save the adler32 of the preset dictionary: */\n      if (s.strstart !== 0) {\n        putShortMSB(s, strm.adler >>> 16);\n        putShortMSB(s, strm.adler & 0xffff);\n      }\n      strm.adler = 1; // adler32(0L, Z_NULL, 0);\n    }\n  }\n\n//#ifdef GZIP\n  if (s.status === EXTRA_STATE) {\n    if (s.gzhead.extra/* != Z_NULL*/) {\n      beg = s.pending;  /* start of bytes to update crc */\n\n      while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {\n        if (s.pending === s.pending_buf_size) {\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          flush_pending(strm);\n          beg = s.pending;\n          if (s.pending === s.pending_buf_size) {\n            break;\n          }\n        }\n        put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);\n        s.gzindex++;\n      }\n      if (s.gzhead.hcrc && s.pending > beg) {\n        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n      }\n      if (s.gzindex === s.gzhead.extra.length) {\n        s.gzindex = 0;\n        s.status = NAME_STATE;\n      }\n    }\n    else {\n      s.status = NAME_STATE;\n    }\n  }\n  if (s.status === NAME_STATE) {\n    if (s.gzhead.name/* != Z_NULL*/) {\n      beg = s.pending;  /* start of bytes to update crc */\n      //int val;\n\n      do {\n        if (s.pending === s.pending_buf_size) {\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          flush_pending(strm);\n          beg = s.pending;\n          if (s.pending === s.pending_buf_size) {\n            val = 1;\n            break;\n          }\n        }\n        // JS specific: little magic to add zero terminator to end of string\n        if (s.gzindex < s.gzhead.name.length) {\n          val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;\n        } else {\n          val = 0;\n        }\n        put_byte(s, val);\n      } while (val !== 0);\n\n      if (s.gzhead.hcrc && s.pending > beg) {\n        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n      }\n      if (val === 0) {\n        s.gzindex = 0;\n        s.status = COMMENT_STATE;\n      }\n    }\n    else {\n      s.status = COMMENT_STATE;\n    }\n  }\n  if (s.status === COMMENT_STATE) {\n    if (s.gzhead.comment/* != Z_NULL*/) {\n      beg = s.pending;  /* start of bytes to update crc */\n      //int val;\n\n      do {\n        if (s.pending === s.pending_buf_size) {\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          flush_pending(strm);\n          beg = s.pending;\n          if (s.pending === s.pending_buf_size) {\n            val = 1;\n            break;\n          }\n        }\n        // JS specific: little magic to add zero terminator to end of string\n        if (s.gzindex < s.gzhead.comment.length) {\n          val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;\n        } else {\n          val = 0;\n        }\n        put_byte(s, val);\n      } while (val !== 0);\n\n      if (s.gzhead.hcrc && s.pending > beg) {\n        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n      }\n      if (val === 0) {\n        s.status = HCRC_STATE;\n      }\n    }\n    else {\n      s.status = HCRC_STATE;\n    }\n  }\n  if (s.status === HCRC_STATE) {\n    if (s.gzhead.hcrc) {\n      if (s.pending + 2 > s.pending_buf_size) {\n        flush_pending(strm);\n      }\n      if (s.pending + 2 <= s.pending_buf_size) {\n        put_byte(s, strm.adler & 0xff);\n        put_byte(s, (strm.adler >> 8) & 0xff);\n        strm.adler = 0; //crc32(0L, Z_NULL, 0);\n        s.status = BUSY_STATE;\n      }\n    }\n    else {\n      s.status = BUSY_STATE;\n    }\n  }\n//#endif\n\n  /* Flush as much pending output as possible */\n  if (s.pending !== 0) {\n    flush_pending(strm);\n    if (strm.avail_out === 0) {\n      /* Since avail_out is 0, deflate will be called again with\n       * more output space, but possibly with both pending and\n       * avail_in equal to zero. There won't be anything to do,\n       * but this is not an error situation so make sure we\n       * return OK instead of BUF_ERROR at next call of deflate:\n       */\n      s.last_flush = -1;\n      return Z_OK;\n    }\n\n    /* Make sure there is something to do and avoid duplicate consecutive\n     * flushes. For repeated and useless calls with Z_FINISH, we keep\n     * returning Z_STREAM_END instead of Z_BUF_ERROR.\n     */\n  } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&\n    flush !== Z_FINISH) {\n    return err(strm, Z_BUF_ERROR);\n  }\n\n  /* User must not provide more input after the first FINISH: */\n  if (s.status === FINISH_STATE && strm.avail_in !== 0) {\n    return err(strm, Z_BUF_ERROR);\n  }\n\n  /* Start a new block or continue the current one.\n   */\n  if (strm.avail_in !== 0 || s.lookahead !== 0 ||\n    (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) {\n    var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) :\n      (s.strategy === Z_RLE ? deflate_rle(s, flush) :\n        configuration_table[s.level].func(s, flush));\n\n    if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {\n      s.status = FINISH_STATE;\n    }\n    if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {\n      if (strm.avail_out === 0) {\n        s.last_flush = -1;\n        /* avoid BUF_ERROR next call, see above */\n      }\n      return Z_OK;\n      /* If flush != Z_NO_FLUSH && avail_out == 0, the next call\n       * of deflate should use the same flush parameter to make sure\n       * that the flush is complete. So we don't have to output an\n       * empty block here, this will be done at next call. This also\n       * ensures that for a very small output buffer, we emit at most\n       * one empty block.\n       */\n    }\n    if (bstate === BS_BLOCK_DONE) {\n      if (flush === Z_PARTIAL_FLUSH) {\n        trees._tr_align(s);\n      }\n      else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */\n\n        trees._tr_stored_block(s, 0, 0, false);\n        /* For a full flush, this empty block will be recognized\n         * as a special marker by inflate_sync().\n         */\n        if (flush === Z_FULL_FLUSH) {\n          /*** CLEAR_HASH(s); ***/             /* forget history */\n          zero(s.head); // Fill with NIL (= 0);\n\n          if (s.lookahead === 0) {\n            s.strstart = 0;\n            s.block_start = 0;\n            s.insert = 0;\n          }\n        }\n      }\n      flush_pending(strm);\n      if (strm.avail_out === 0) {\n        s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */\n        return Z_OK;\n      }\n    }\n  }\n  //Assert(strm->avail_out > 0, \"bug2\");\n  //if (strm.avail_out <= 0) { throw new Error(\"bug2\");}\n\n  if (flush !== Z_FINISH) { return Z_OK; }\n  if (s.wrap <= 0) { return Z_STREAM_END; }\n\n  /* Write the trailer */\n  if (s.wrap === 2) {\n    put_byte(s, strm.adler & 0xff);\n    put_byte(s, (strm.adler >> 8) & 0xff);\n    put_byte(s, (strm.adler >> 16) & 0xff);\n    put_byte(s, (strm.adler >> 24) & 0xff);\n    put_byte(s, strm.total_in & 0xff);\n    put_byte(s, (strm.total_in >> 8) & 0xff);\n    put_byte(s, (strm.total_in >> 16) & 0xff);\n    put_byte(s, (strm.total_in >> 24) & 0xff);\n  }\n  else\n  {\n    putShortMSB(s, strm.adler >>> 16);\n    putShortMSB(s, strm.adler & 0xffff);\n  }\n\n  flush_pending(strm);\n  /* If avail_out is zero, the application will call deflate again\n   * to flush the rest.\n   */\n  if (s.wrap > 0) { s.wrap = -s.wrap; }\n  /* write the trailer only once! */\n  return s.pending !== 0 ? Z_OK : Z_STREAM_END;\n}\n\nfunction deflateEnd(strm) {\n  var status;\n\n  if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {\n    return Z_STREAM_ERROR;\n  }\n\n  status = strm.state.status;\n  if (status !== INIT_STATE &&\n    status !== EXTRA_STATE &&\n    status !== NAME_STATE &&\n    status !== COMMENT_STATE &&\n    status !== HCRC_STATE &&\n    status !== BUSY_STATE &&\n    status !== FINISH_STATE\n  ) {\n    return err(strm, Z_STREAM_ERROR);\n  }\n\n  strm.state = null;\n\n  return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK;\n}\n\n\n/* =========================================================================\n * Initializes the compression dictionary from the given byte\n * sequence without producing any compressed output.\n */\nfunction deflateSetDictionary(strm, dictionary) {\n  var dictLength = dictionary.length;\n\n  var s;\n  var str, n;\n  var wrap;\n  var avail;\n  var next;\n  var input;\n  var tmpDict;\n\n  if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {\n    return Z_STREAM_ERROR;\n  }\n\n  s = strm.state;\n  wrap = s.wrap;\n\n  if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) {\n    return Z_STREAM_ERROR;\n  }\n\n  /* when using zlib wrappers, compute Adler-32 for provided dictionary */\n  if (wrap === 1) {\n    /* adler32(strm->adler, dictionary, dictLength); */\n    strm.adler = adler32(strm.adler, dictionary, dictLength, 0);\n  }\n\n  s.wrap = 0;   /* avoid computing Adler-32 in read_buf */\n\n  /* if dictionary would fill window, just replace the history */\n  if (dictLength >= s.w_size) {\n    if (wrap === 0) {            /* already empty otherwise */\n      /*** CLEAR_HASH(s); ***/\n      zero(s.head); // Fill with NIL (= 0);\n      s.strstart = 0;\n      s.block_start = 0;\n      s.insert = 0;\n    }\n    /* use the tail */\n    // dictionary = dictionary.slice(dictLength - s.w_size);\n    tmpDict = new utils.Buf8(s.w_size);\n    utils.arraySet(tmpDict, dictionary, dictLength - s.w_size, s.w_size, 0);\n    dictionary = tmpDict;\n    dictLength = s.w_size;\n  }\n  /* insert dictionary into window and hash */\n  avail = strm.avail_in;\n  next = strm.next_in;\n  input = strm.input;\n  strm.avail_in = dictLength;\n  strm.next_in = 0;\n  strm.input = dictionary;\n  fill_window(s);\n  while (s.lookahead >= MIN_MATCH) {\n    str = s.strstart;\n    n = s.lookahead - (MIN_MATCH - 1);\n    do {\n      /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */\n      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask;\n\n      s.prev[str & s.w_mask] = s.head[s.ins_h];\n\n      s.head[s.ins_h] = str;\n      str++;\n    } while (--n);\n    s.strstart = str;\n    s.lookahead = MIN_MATCH - 1;\n    fill_window(s);\n  }\n  s.strstart += s.lookahead;\n  s.block_start = s.strstart;\n  s.insert = s.lookahead;\n  s.lookahead = 0;\n  s.match_length = s.prev_length = MIN_MATCH - 1;\n  s.match_available = 0;\n  strm.next_in = next;\n  strm.input = input;\n  strm.avail_in = avail;\n  s.wrap = wrap;\n  return Z_OK;\n}\n\n\nexports.deflateInit = deflateInit;\nexports.deflateInit2 = deflateInit2;\nexports.deflateReset = deflateReset;\nexports.deflateResetKeep = deflateResetKeep;\nexports.deflateSetHeader = deflateSetHeader;\nexports.deflate = deflate;\nexports.deflateEnd = deflateEnd;\nexports.deflateSetDictionary = deflateSetDictionary;\nexports.deflateInfo = 'pako deflate (from Nodeca project)';\n\n/* Not implemented\nexports.deflateBound = deflateBound;\nexports.deflateCopy = deflateCopy;\nexports.deflateParams = deflateParams;\nexports.deflatePending = deflatePending;\nexports.deflatePrime = deflatePrime;\nexports.deflateTune = deflateTune;\n*/\n\n\n/***/ }),\n/* 155 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nvar utils = __webpack_require__(34);\n\n/* Public constants ==========================================================*/\n/* ===========================================================================*/\n\n\n//var Z_FILTERED          = 1;\n//var Z_HUFFMAN_ONLY      = 2;\n//var Z_RLE               = 3;\nvar Z_FIXED               = 4;\n//var Z_DEFAULT_STRATEGY  = 0;\n\n/* Possible values of the data_type field (though see inflate()) */\nvar Z_BINARY              = 0;\nvar Z_TEXT                = 1;\n//var Z_ASCII             = 1; // = Z_TEXT\nvar Z_UNKNOWN             = 2;\n\n/*============================================================================*/\n\n\nfunction zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }\n\n// From zutil.h\n\nvar STORED_BLOCK = 0;\nvar STATIC_TREES = 1;\nvar DYN_TREES    = 2;\n/* The three kinds of block type */\n\nvar MIN_MATCH    = 3;\nvar MAX_MATCH    = 258;\n/* The minimum and maximum match lengths */\n\n// From deflate.h\n/* ===========================================================================\n * Internal compression state.\n */\n\nvar LENGTH_CODES  = 29;\n/* number of length codes, not counting the special END_BLOCK code */\n\nvar LITERALS      = 256;\n/* number of literal bytes 0..255 */\n\nvar L_CODES       = LITERALS + 1 + LENGTH_CODES;\n/* number of Literal or Length codes, including the END_BLOCK code */\n\nvar D_CODES       = 30;\n/* number of distance codes */\n\nvar BL_CODES      = 19;\n/* number of codes used to transfer the bit lengths */\n\nvar HEAP_SIZE     = 2 * L_CODES + 1;\n/* maximum heap size */\n\nvar MAX_BITS      = 15;\n/* All codes must not exceed MAX_BITS bits */\n\nvar Buf_size      = 16;\n/* size of bit buffer in bi_buf */\n\n\n/* ===========================================================================\n * Constants\n */\n\nvar MAX_BL_BITS = 7;\n/* Bit length codes must not exceed MAX_BL_BITS bits */\n\nvar END_BLOCK   = 256;\n/* end of block literal code */\n\nvar REP_3_6     = 16;\n/* repeat previous bit length 3-6 times (2 bits of repeat count) */\n\nvar REPZ_3_10   = 17;\n/* repeat a zero length 3-10 times  (3 bits of repeat count) */\n\nvar REPZ_11_138 = 18;\n/* repeat a zero length 11-138 times  (7 bits of repeat count) */\n\n/* eslint-disable comma-spacing,array-bracket-spacing */\nvar extra_lbits =   /* extra bits for each length code */\n  [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0];\n\nvar extra_dbits =   /* extra bits for each distance code */\n  [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];\n\nvar extra_blbits =  /* extra bits for each bit length code */\n  [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];\n\nvar bl_order =\n  [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];\n/* eslint-enable comma-spacing,array-bracket-spacing */\n\n/* The lengths of the bit length codes are sent in order of decreasing\n * probability, to avoid transmitting the lengths for unused bit length codes.\n */\n\n/* ===========================================================================\n * Local data. These are initialized only once.\n */\n\n// We pre-fill arrays with 0 to avoid uninitialized gaps\n\nvar DIST_CODE_LEN = 512; /* see definition of array dist_code below */\n\n// !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1\nvar static_ltree  = new Array((L_CODES + 2) * 2);\nzero(static_ltree);\n/* The static literal tree. Since the bit lengths are imposed, there is no\n * need for the L_CODES extra codes used during heap construction. However\n * The codes 286 and 287 are needed to build a canonical tree (see _tr_init\n * below).\n */\n\nvar static_dtree  = new Array(D_CODES * 2);\nzero(static_dtree);\n/* The static distance tree. (Actually a trivial tree since all codes use\n * 5 bits.)\n */\n\nvar _dist_code    = new Array(DIST_CODE_LEN);\nzero(_dist_code);\n/* Distance codes. The first 256 values correspond to the distances\n * 3 .. 258, the last 256 values correspond to the top 8 bits of\n * the 15 bit distances.\n */\n\nvar _length_code  = new Array(MAX_MATCH - MIN_MATCH + 1);\nzero(_length_code);\n/* length code for each normalized match length (0 == MIN_MATCH) */\n\nvar base_length   = new Array(LENGTH_CODES);\nzero(base_length);\n/* First normalized length for each code (0 = MIN_MATCH) */\n\nvar base_dist     = new Array(D_CODES);\nzero(base_dist);\n/* First normalized distance for each code (0 = distance of 1) */\n\n\nfunction StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) {\n\n  this.static_tree  = static_tree;  /* static tree or NULL */\n  this.extra_bits   = extra_bits;   /* extra bits for each code or NULL */\n  this.extra_base   = extra_base;   /* base index for extra_bits */\n  this.elems        = elems;        /* max number of elements in the tree */\n  this.max_length   = max_length;   /* max bit length for the codes */\n\n  // show if `static_tree` has data or dummy - needed for monomorphic objects\n  this.has_stree    = static_tree && static_tree.length;\n}\n\n\nvar static_l_desc;\nvar static_d_desc;\nvar static_bl_desc;\n\n\nfunction TreeDesc(dyn_tree, stat_desc) {\n  this.dyn_tree = dyn_tree;     /* the dynamic tree */\n  this.max_code = 0;            /* largest code with non zero frequency */\n  this.stat_desc = stat_desc;   /* the corresponding static tree */\n}\n\n\n\nfunction d_code(dist) {\n  return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];\n}\n\n\n/* ===========================================================================\n * Output a short LSB first on the stream.\n * IN assertion: there is enough room in pendingBuf.\n */\nfunction put_short(s, w) {\n//    put_byte(s, (uch)((w) & 0xff));\n//    put_byte(s, (uch)((ush)(w) >> 8));\n  s.pending_buf[s.pending++] = (w) & 0xff;\n  s.pending_buf[s.pending++] = (w >>> 8) & 0xff;\n}\n\n\n/* ===========================================================================\n * Send a value on a given number of bits.\n * IN assertion: length <= 16 and value fits in length bits.\n */\nfunction send_bits(s, value, length) {\n  if (s.bi_valid > (Buf_size - length)) {\n    s.bi_buf |= (value << s.bi_valid) & 0xffff;\n    put_short(s, s.bi_buf);\n    s.bi_buf = value >> (Buf_size - s.bi_valid);\n    s.bi_valid += length - Buf_size;\n  } else {\n    s.bi_buf |= (value << s.bi_valid) & 0xffff;\n    s.bi_valid += length;\n  }\n}\n\n\nfunction send_code(s, c, tree) {\n  send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/);\n}\n\n\n/* ===========================================================================\n * Reverse the first len bits of a code, using straightforward code (a faster\n * method would use a table)\n * IN assertion: 1 <= len <= 15\n */\nfunction bi_reverse(code, len) {\n  var res = 0;\n  do {\n    res |= code & 1;\n    code >>>= 1;\n    res <<= 1;\n  } while (--len > 0);\n  return res >>> 1;\n}\n\n\n/* ===========================================================================\n * Flush the bit buffer, keeping at most 7 bits in it.\n */\nfunction bi_flush(s) {\n  if (s.bi_valid === 16) {\n    put_short(s, s.bi_buf);\n    s.bi_buf = 0;\n    s.bi_valid = 0;\n\n  } else if (s.bi_valid >= 8) {\n    s.pending_buf[s.pending++] = s.bi_buf & 0xff;\n    s.bi_buf >>= 8;\n    s.bi_valid -= 8;\n  }\n}\n\n\n/* ===========================================================================\n * Compute the optimal bit lengths for a tree and update the total bit length\n * for the current block.\n * IN assertion: the fields freq and dad are set, heap[heap_max] and\n *    above are the tree nodes sorted by increasing frequency.\n * OUT assertions: the field len is set to the optimal bit length, the\n *     array bl_count contains the frequencies for each bit length.\n *     The length opt_len is updated; static_len is also updated if stree is\n *     not null.\n */\nfunction gen_bitlen(s, desc)\n//    deflate_state *s;\n//    tree_desc *desc;    /* the tree descriptor */\n{\n  var tree            = desc.dyn_tree;\n  var max_code        = desc.max_code;\n  var stree           = desc.stat_desc.static_tree;\n  var has_stree       = desc.stat_desc.has_stree;\n  var extra           = desc.stat_desc.extra_bits;\n  var base            = desc.stat_desc.extra_base;\n  var max_length      = desc.stat_desc.max_length;\n  var h;              /* heap index */\n  var n, m;           /* iterate over the tree elements */\n  var bits;           /* bit length */\n  var xbits;          /* extra bits */\n  var f;              /* frequency */\n  var overflow = 0;   /* number of elements with bit length too large */\n\n  for (bits = 0; bits <= MAX_BITS; bits++) {\n    s.bl_count[bits] = 0;\n  }\n\n  /* In a first pass, compute the optimal bit lengths (which may\n   * overflow in the case of the bit length tree).\n   */\n  tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */\n\n  for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {\n    n = s.heap[h];\n    bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;\n    if (bits > max_length) {\n      bits = max_length;\n      overflow++;\n    }\n    tree[n * 2 + 1]/*.Len*/ = bits;\n    /* We overwrite tree[n].Dad which is no longer needed */\n\n    if (n > max_code) { continue; } /* not a leaf node */\n\n    s.bl_count[bits]++;\n    xbits = 0;\n    if (n >= base) {\n      xbits = extra[n - base];\n    }\n    f = tree[n * 2]/*.Freq*/;\n    s.opt_len += f * (bits + xbits);\n    if (has_stree) {\n      s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits);\n    }\n  }\n  if (overflow === 0) { return; }\n\n  // Trace((stderr,\"\\nbit length overflow\\n\"));\n  /* This happens for example on obj2 and pic of the Calgary corpus */\n\n  /* Find the first bit length which could increase: */\n  do {\n    bits = max_length - 1;\n    while (s.bl_count[bits] === 0) { bits--; }\n    s.bl_count[bits]--;      /* move one leaf down the tree */\n    s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */\n    s.bl_count[max_length]--;\n    /* The brother of the overflow item also moves one step up,\n     * but this does not affect bl_count[max_length]\n     */\n    overflow -= 2;\n  } while (overflow > 0);\n\n  /* Now recompute all bit lengths, scanning in increasing frequency.\n   * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all\n   * lengths instead of fixing only the wrong ones. This idea is taken\n   * from 'ar' written by Haruhiko Okumura.)\n   */\n  for (bits = max_length; bits !== 0; bits--) {\n    n = s.bl_count[bits];\n    while (n !== 0) {\n      m = s.heap[--h];\n      if (m > max_code) { continue; }\n      if (tree[m * 2 + 1]/*.Len*/ !== bits) {\n        // Trace((stderr,\"code %d bits %d->%d\\n\", m, tree[m].Len, bits));\n        s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/;\n        tree[m * 2 + 1]/*.Len*/ = bits;\n      }\n      n--;\n    }\n  }\n}\n\n\n/* ===========================================================================\n * Generate the codes for a given tree and bit counts (which need not be\n * optimal).\n * IN assertion: the array bl_count contains the bit length statistics for\n * the given tree and the field len is set for all tree elements.\n * OUT assertion: the field code is set for all tree elements of non\n *     zero code length.\n */\nfunction gen_codes(tree, max_code, bl_count)\n//    ct_data *tree;             /* the tree to decorate */\n//    int max_code;              /* largest code with non zero frequency */\n//    ushf *bl_count;            /* number of codes at each bit length */\n{\n  var next_code = new Array(MAX_BITS + 1); /* next code value for each bit length */\n  var code = 0;              /* running code value */\n  var bits;                  /* bit index */\n  var n;                     /* code index */\n\n  /* The distribution counts are first used to generate the code values\n   * without bit reversal.\n   */\n  for (bits = 1; bits <= MAX_BITS; bits++) {\n    next_code[bits] = code = (code + bl_count[bits - 1]) << 1;\n  }\n  /* Check that the bit counts in bl_count are consistent. The last code\n   * must be all ones.\n   */\n  //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,\n  //        \"inconsistent bit counts\");\n  //Tracev((stderr,\"\\ngen_codes: max_code %d \", max_code));\n\n  for (n = 0;  n <= max_code; n++) {\n    var len = tree[n * 2 + 1]/*.Len*/;\n    if (len === 0) { continue; }\n    /* Now reverse the bits */\n    tree[n * 2]/*.Code*/ = bi_reverse(next_code[len]++, len);\n\n    //Tracecv(tree != static_ltree, (stderr,\"\\nn %3d %c l %2d c %4x (%x) \",\n    //     n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));\n  }\n}\n\n\n/* ===========================================================================\n * Initialize the various 'constant' tables.\n */\nfunction tr_static_init() {\n  var n;        /* iterates over tree elements */\n  var bits;     /* bit counter */\n  var length;   /* length value */\n  var code;     /* code value */\n  var dist;     /* distance index */\n  var bl_count = new Array(MAX_BITS + 1);\n  /* number of codes at each bit length for an optimal tree */\n\n  // do check in _tr_init()\n  //if (static_init_done) return;\n\n  /* For some embedded targets, global variables are not initialized: */\n/*#ifdef NO_INIT_GLOBAL_POINTERS\n  static_l_desc.static_tree = static_ltree;\n  static_l_desc.extra_bits = extra_lbits;\n  static_d_desc.static_tree = static_dtree;\n  static_d_desc.extra_bits = extra_dbits;\n  static_bl_desc.extra_bits = extra_blbits;\n#endif*/\n\n  /* Initialize the mapping length (0..255) -> length code (0..28) */\n  length = 0;\n  for (code = 0; code < LENGTH_CODES - 1; code++) {\n    base_length[code] = length;\n    for (n = 0; n < (1 << extra_lbits[code]); n++) {\n      _length_code[length++] = code;\n    }\n  }\n  //Assert (length == 256, \"tr_static_init: length != 256\");\n  /* Note that the length 255 (match length 258) can be represented\n   * in two different ways: code 284 + 5 bits or code 285, so we\n   * overwrite length_code[255] to use the best encoding:\n   */\n  _length_code[length - 1] = code;\n\n  /* Initialize the mapping dist (0..32K) -> dist code (0..29) */\n  dist = 0;\n  for (code = 0; code < 16; code++) {\n    base_dist[code] = dist;\n    for (n = 0; n < (1 << extra_dbits[code]); n++) {\n      _dist_code[dist++] = code;\n    }\n  }\n  //Assert (dist == 256, \"tr_static_init: dist != 256\");\n  dist >>= 7; /* from now on, all distances are divided by 128 */\n  for (; code < D_CODES; code++) {\n    base_dist[code] = dist << 7;\n    for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {\n      _dist_code[256 + dist++] = code;\n    }\n  }\n  //Assert (dist == 256, \"tr_static_init: 256+dist != 512\");\n\n  /* Construct the codes of the static literal tree */\n  for (bits = 0; bits <= MAX_BITS; bits++) {\n    bl_count[bits] = 0;\n  }\n\n  n = 0;\n  while (n <= 143) {\n    static_ltree[n * 2 + 1]/*.Len*/ = 8;\n    n++;\n    bl_count[8]++;\n  }\n  while (n <= 255) {\n    static_ltree[n * 2 + 1]/*.Len*/ = 9;\n    n++;\n    bl_count[9]++;\n  }\n  while (n <= 279) {\n    static_ltree[n * 2 + 1]/*.Len*/ = 7;\n    n++;\n    bl_count[7]++;\n  }\n  while (n <= 287) {\n    static_ltree[n * 2 + 1]/*.Len*/ = 8;\n    n++;\n    bl_count[8]++;\n  }\n  /* Codes 286 and 287 do not exist, but we must include them in the\n   * tree construction to get a canonical Huffman tree (longest code\n   * all ones)\n   */\n  gen_codes(static_ltree, L_CODES + 1, bl_count);\n\n  /* The static distance tree is trivial: */\n  for (n = 0; n < D_CODES; n++) {\n    static_dtree[n * 2 + 1]/*.Len*/ = 5;\n    static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5);\n  }\n\n  // Now data ready and we can init static trees\n  static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);\n  static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS);\n  static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0,         BL_CODES, MAX_BL_BITS);\n\n  //static_init_done = true;\n}\n\n\n/* ===========================================================================\n * Initialize a new block.\n */\nfunction init_block(s) {\n  var n; /* iterates over tree elements */\n\n  /* Initialize the trees. */\n  for (n = 0; n < L_CODES;  n++) { s.dyn_ltree[n * 2]/*.Freq*/ = 0; }\n  for (n = 0; n < D_CODES;  n++) { s.dyn_dtree[n * 2]/*.Freq*/ = 0; }\n  for (n = 0; n < BL_CODES; n++) { s.bl_tree[n * 2]/*.Freq*/ = 0; }\n\n  s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1;\n  s.opt_len = s.static_len = 0;\n  s.last_lit = s.matches = 0;\n}\n\n\n/* ===========================================================================\n * Flush the bit buffer and align the output on a byte boundary\n */\nfunction bi_windup(s)\n{\n  if (s.bi_valid > 8) {\n    put_short(s, s.bi_buf);\n  } else if (s.bi_valid > 0) {\n    //put_byte(s, (Byte)s->bi_buf);\n    s.pending_buf[s.pending++] = s.bi_buf;\n  }\n  s.bi_buf = 0;\n  s.bi_valid = 0;\n}\n\n/* ===========================================================================\n * Copy a stored block, storing first the length and its\n * one's complement if requested.\n */\nfunction copy_block(s, buf, len, header)\n//DeflateState *s;\n//charf    *buf;    /* the input data */\n//unsigned len;     /* its length */\n//int      header;  /* true if block header must be written */\n{\n  bi_windup(s);        /* align on byte boundary */\n\n  if (header) {\n    put_short(s, len);\n    put_short(s, ~len);\n  }\n//  while (len--) {\n//    put_byte(s, *buf++);\n//  }\n  utils.arraySet(s.pending_buf, s.window, buf, len, s.pending);\n  s.pending += len;\n}\n\n/* ===========================================================================\n * Compares to subtrees, using the tree depth as tie breaker when\n * the subtrees have equal frequency. This minimizes the worst case length.\n */\nfunction smaller(tree, n, m, depth) {\n  var _n2 = n * 2;\n  var _m2 = m * 2;\n  return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||\n         (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m]));\n}\n\n/* ===========================================================================\n * Restore the heap property by moving down the tree starting at node k,\n * exchanging a node with the smallest of its two sons if necessary, stopping\n * when the heap property is re-established (each father smaller than its\n * two sons).\n */\nfunction pqdownheap(s, tree, k)\n//    deflate_state *s;\n//    ct_data *tree;  /* the tree to restore */\n//    int k;               /* node to move down */\n{\n  var v = s.heap[k];\n  var j = k << 1;  /* left son of k */\n  while (j <= s.heap_len) {\n    /* Set j to the smallest of the two sons: */\n    if (j < s.heap_len &&\n      smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) {\n      j++;\n    }\n    /* Exit if v is smaller than both sons */\n    if (smaller(tree, v, s.heap[j], s.depth)) { break; }\n\n    /* Exchange v with the smallest son */\n    s.heap[k] = s.heap[j];\n    k = j;\n\n    /* And continue down the tree, setting j to the left son of k */\n    j <<= 1;\n  }\n  s.heap[k] = v;\n}\n\n\n// inlined manually\n// var SMALLEST = 1;\n\n/* ===========================================================================\n * Send the block data compressed using the given Huffman trees\n */\nfunction compress_block(s, ltree, dtree)\n//    deflate_state *s;\n//    const ct_data *ltree; /* literal tree */\n//    const ct_data *dtree; /* distance tree */\n{\n  var dist;           /* distance of matched string */\n  var lc;             /* match length or unmatched char (if dist == 0) */\n  var lx = 0;         /* running index in l_buf */\n  var code;           /* the code to send */\n  var extra;          /* number of extra bits to send */\n\n  if (s.last_lit !== 0) {\n    do {\n      dist = (s.pending_buf[s.d_buf + lx * 2] << 8) | (s.pending_buf[s.d_buf + lx * 2 + 1]);\n      lc = s.pending_buf[s.l_buf + lx];\n      lx++;\n\n      if (dist === 0) {\n        send_code(s, lc, ltree); /* send a literal byte */\n        //Tracecv(isgraph(lc), (stderr,\" '%c' \", lc));\n      } else {\n        /* Here, lc is the match length - MIN_MATCH */\n        code = _length_code[lc];\n        send_code(s, code + LITERALS + 1, ltree); /* send the length code */\n        extra = extra_lbits[code];\n        if (extra !== 0) {\n          lc -= base_length[code];\n          send_bits(s, lc, extra);       /* send the extra length bits */\n        }\n        dist--; /* dist is now the match distance - 1 */\n        code = d_code(dist);\n        //Assert (code < D_CODES, \"bad d_code\");\n\n        send_code(s, code, dtree);       /* send the distance code */\n        extra = extra_dbits[code];\n        if (extra !== 0) {\n          dist -= base_dist[code];\n          send_bits(s, dist, extra);   /* send the extra distance bits */\n        }\n      } /* literal or match pair ? */\n\n      /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */\n      //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,\n      //       \"pendingBuf overflow\");\n\n    } while (lx < s.last_lit);\n  }\n\n  send_code(s, END_BLOCK, ltree);\n}\n\n\n/* ===========================================================================\n * Construct one Huffman tree and assigns the code bit strings and lengths.\n * Update the total bit length for the current block.\n * IN assertion: the field freq is set for all tree elements.\n * OUT assertions: the fields len and code are set to the optimal bit length\n *     and corresponding code. The length opt_len is updated; static_len is\n *     also updated if stree is not null. The field max_code is set.\n */\nfunction build_tree(s, desc)\n//    deflate_state *s;\n//    tree_desc *desc; /* the tree descriptor */\n{\n  var tree     = desc.dyn_tree;\n  var stree    = desc.stat_desc.static_tree;\n  var has_stree = desc.stat_desc.has_stree;\n  var elems    = desc.stat_desc.elems;\n  var n, m;          /* iterate over heap elements */\n  var max_code = -1; /* largest code with non zero frequency */\n  var node;          /* new node being created */\n\n  /* Construct the initial heap, with least frequent element in\n   * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].\n   * heap[0] is not used.\n   */\n  s.heap_len = 0;\n  s.heap_max = HEAP_SIZE;\n\n  for (n = 0; n < elems; n++) {\n    if (tree[n * 2]/*.Freq*/ !== 0) {\n      s.heap[++s.heap_len] = max_code = n;\n      s.depth[n] = 0;\n\n    } else {\n      tree[n * 2 + 1]/*.Len*/ = 0;\n    }\n  }\n\n  /* The pkzip format requires that at least one distance code exists,\n   * and that at least one bit should be sent even if there is only one\n   * possible code. So to avoid special checks later on we force at least\n   * two codes of non zero frequency.\n   */\n  while (s.heap_len < 2) {\n    node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);\n    tree[node * 2]/*.Freq*/ = 1;\n    s.depth[node] = 0;\n    s.opt_len--;\n\n    if (has_stree) {\n      s.static_len -= stree[node * 2 + 1]/*.Len*/;\n    }\n    /* node is 0 or 1 so it does not have extra bits */\n  }\n  desc.max_code = max_code;\n\n  /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,\n   * establish sub-heaps of increasing lengths:\n   */\n  for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); }\n\n  /* Construct the Huffman tree by repeatedly combining the least two\n   * frequent nodes.\n   */\n  node = elems;              /* next internal node of the tree */\n  do {\n    //pqremove(s, tree, n);  /* n = node of least frequency */\n    /*** pqremove ***/\n    n = s.heap[1/*SMALLEST*/];\n    s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];\n    pqdownheap(s, tree, 1/*SMALLEST*/);\n    /***/\n\n    m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */\n\n    s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */\n    s.heap[--s.heap_max] = m;\n\n    /* Create a new node father of n and m */\n    tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;\n    s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;\n    tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node;\n\n    /* and insert the new node in the heap */\n    s.heap[1/*SMALLEST*/] = node++;\n    pqdownheap(s, tree, 1/*SMALLEST*/);\n\n  } while (s.heap_len >= 2);\n\n  s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];\n\n  /* At this point, the fields freq and dad are set. We can now\n   * generate the bit lengths.\n   */\n  gen_bitlen(s, desc);\n\n  /* The field len is now set, we can generate the bit codes */\n  gen_codes(tree, max_code, s.bl_count);\n}\n\n\n/* ===========================================================================\n * Scan a literal or distance tree to determine the frequencies of the codes\n * in the bit length tree.\n */\nfunction scan_tree(s, tree, max_code)\n//    deflate_state *s;\n//    ct_data *tree;   /* the tree to be scanned */\n//    int max_code;    /* and its largest code of non zero frequency */\n{\n  var n;                     /* iterates over all tree elements */\n  var prevlen = -1;          /* last emitted length */\n  var curlen;                /* length of current code */\n\n  var nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */\n\n  var count = 0;             /* repeat count of the current code */\n  var max_count = 7;         /* max repeat count */\n  var min_count = 4;         /* min repeat count */\n\n  if (nextlen === 0) {\n    max_count = 138;\n    min_count = 3;\n  }\n  tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */\n\n  for (n = 0; n <= max_code; n++) {\n    curlen = nextlen;\n    nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;\n\n    if (++count < max_count && curlen === nextlen) {\n      continue;\n\n    } else if (count < min_count) {\n      s.bl_tree[curlen * 2]/*.Freq*/ += count;\n\n    } else if (curlen !== 0) {\n\n      if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; }\n      s.bl_tree[REP_3_6 * 2]/*.Freq*/++;\n\n    } else if (count <= 10) {\n      s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++;\n\n    } else {\n      s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++;\n    }\n\n    count = 0;\n    prevlen = curlen;\n\n    if (nextlen === 0) {\n      max_count = 138;\n      min_count = 3;\n\n    } else if (curlen === nextlen) {\n      max_count = 6;\n      min_count = 3;\n\n    } else {\n      max_count = 7;\n      min_count = 4;\n    }\n  }\n}\n\n\n/* ===========================================================================\n * Send a literal or distance tree in compressed form, using the codes in\n * bl_tree.\n */\nfunction send_tree(s, tree, max_code)\n//    deflate_state *s;\n//    ct_data *tree; /* the tree to be scanned */\n//    int max_code;       /* and its largest code of non zero frequency */\n{\n  var n;                     /* iterates over all tree elements */\n  var prevlen = -1;          /* last emitted length */\n  var curlen;                /* length of current code */\n\n  var nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */\n\n  var count = 0;             /* repeat count of the current code */\n  var max_count = 7;         /* max repeat count */\n  var min_count = 4;         /* min repeat count */\n\n  /* tree[max_code+1].Len = -1; */  /* guard already set */\n  if (nextlen === 0) {\n    max_count = 138;\n    min_count = 3;\n  }\n\n  for (n = 0; n <= max_code; n++) {\n    curlen = nextlen;\n    nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;\n\n    if (++count < max_count && curlen === nextlen) {\n      continue;\n\n    } else if (count < min_count) {\n      do { send_code(s, curlen, s.bl_tree); } while (--count !== 0);\n\n    } else if (curlen !== 0) {\n      if (curlen !== prevlen) {\n        send_code(s, curlen, s.bl_tree);\n        count--;\n      }\n      //Assert(count >= 3 && count <= 6, \" 3_6?\");\n      send_code(s, REP_3_6, s.bl_tree);\n      send_bits(s, count - 3, 2);\n\n    } else if (count <= 10) {\n      send_code(s, REPZ_3_10, s.bl_tree);\n      send_bits(s, count - 3, 3);\n\n    } else {\n      send_code(s, REPZ_11_138, s.bl_tree);\n      send_bits(s, count - 11, 7);\n    }\n\n    count = 0;\n    prevlen = curlen;\n    if (nextlen === 0) {\n      max_count = 138;\n      min_count = 3;\n\n    } else if (curlen === nextlen) {\n      max_count = 6;\n      min_count = 3;\n\n    } else {\n      max_count = 7;\n      min_count = 4;\n    }\n  }\n}\n\n\n/* ===========================================================================\n * Construct the Huffman tree for the bit lengths and return the index in\n * bl_order of the last bit length code to send.\n */\nfunction build_bl_tree(s) {\n  var max_blindex;  /* index of last bit length code of non zero freq */\n\n  /* Determine the bit length frequencies for literal and distance trees */\n  scan_tree(s, s.dyn_ltree, s.l_desc.max_code);\n  scan_tree(s, s.dyn_dtree, s.d_desc.max_code);\n\n  /* Build the bit length tree: */\n  build_tree(s, s.bl_desc);\n  /* opt_len now includes the length of the tree representations, except\n   * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.\n   */\n\n  /* Determine the number of bit length codes to send. The pkzip format\n   * requires that at least 4 bit length codes be sent. (appnote.txt says\n   * 3 but the actual value used is 4.)\n   */\n  for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {\n    if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) {\n      break;\n    }\n  }\n  /* Update opt_len to include the bit length tree and counts */\n  s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;\n  //Tracev((stderr, \"\\ndyn trees: dyn %ld, stat %ld\",\n  //        s->opt_len, s->static_len));\n\n  return max_blindex;\n}\n\n\n/* ===========================================================================\n * Send the header for a block using dynamic Huffman trees: the counts, the\n * lengths of the bit length codes, the literal tree and the distance tree.\n * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.\n */\nfunction send_all_trees(s, lcodes, dcodes, blcodes)\n//    deflate_state *s;\n//    int lcodes, dcodes, blcodes; /* number of codes for each tree */\n{\n  var rank;                    /* index in bl_order */\n\n  //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, \"not enough codes\");\n  //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,\n  //        \"too many codes\");\n  //Tracev((stderr, \"\\nbl counts: \"));\n  send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */\n  send_bits(s, dcodes - 1,   5);\n  send_bits(s, blcodes - 4,  4); /* not -3 as stated in appnote.txt */\n  for (rank = 0; rank < blcodes; rank++) {\n    //Tracev((stderr, \"\\nbl code %2d \", bl_order[rank]));\n    send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3);\n  }\n  //Tracev((stderr, \"\\nbl tree: sent %ld\", s->bits_sent));\n\n  send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */\n  //Tracev((stderr, \"\\nlit tree: sent %ld\", s->bits_sent));\n\n  send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */\n  //Tracev((stderr, \"\\ndist tree: sent %ld\", s->bits_sent));\n}\n\n\n/* ===========================================================================\n * Check if the data type is TEXT or BINARY, using the following algorithm:\n * - TEXT if the two conditions below are satisfied:\n *    a) There are no non-portable control characters belonging to the\n *       \"black list\" (0..6, 14..25, 28..31).\n *    b) There is at least one printable character belonging to the\n *       \"white list\" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).\n * - BINARY otherwise.\n * - The following partially-portable control characters form a\n *   \"gray list\" that is ignored in this detection algorithm:\n *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).\n * IN assertion: the fields Freq of dyn_ltree are set.\n */\nfunction detect_data_type(s) {\n  /* black_mask is the bit mask of black-listed bytes\n   * set bits 0..6, 14..25, and 28..31\n   * 0xf3ffc07f = binary 11110011111111111100000001111111\n   */\n  var black_mask = 0xf3ffc07f;\n  var n;\n\n  /* Check for non-textual (\"black-listed\") bytes. */\n  for (n = 0; n <= 31; n++, black_mask >>>= 1) {\n    if ((black_mask & 1) && (s.dyn_ltree[n * 2]/*.Freq*/ !== 0)) {\n      return Z_BINARY;\n    }\n  }\n\n  /* Check for textual (\"white-listed\") bytes. */\n  if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||\n      s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {\n    return Z_TEXT;\n  }\n  for (n = 32; n < LITERALS; n++) {\n    if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {\n      return Z_TEXT;\n    }\n  }\n\n  /* There are no \"black-listed\" or \"white-listed\" bytes:\n   * this stream either is empty or has tolerated (\"gray-listed\") bytes only.\n   */\n  return Z_BINARY;\n}\n\n\nvar static_init_done = false;\n\n/* ===========================================================================\n * Initialize the tree data structures for a new zlib stream.\n */\nfunction _tr_init(s)\n{\n\n  if (!static_init_done) {\n    tr_static_init();\n    static_init_done = true;\n  }\n\n  s.l_desc  = new TreeDesc(s.dyn_ltree, static_l_desc);\n  s.d_desc  = new TreeDesc(s.dyn_dtree, static_d_desc);\n  s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);\n\n  s.bi_buf = 0;\n  s.bi_valid = 0;\n\n  /* Initialize the first block of the first file: */\n  init_block(s);\n}\n\n\n/* ===========================================================================\n * Send a stored block\n */\nfunction _tr_stored_block(s, buf, stored_len, last)\n//DeflateState *s;\n//charf *buf;       /* input block */\n//ulg stored_len;   /* length of input block */\n//int last;         /* one if this is the last block for a file */\n{\n  send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3);    /* send block type */\n  copy_block(s, buf, stored_len, true); /* with header */\n}\n\n\n/* ===========================================================================\n * Send one empty static block to give enough lookahead for inflate.\n * This takes 10 bits, of which 7 may remain in the bit buffer.\n */\nfunction _tr_align(s) {\n  send_bits(s, STATIC_TREES << 1, 3);\n  send_code(s, END_BLOCK, static_ltree);\n  bi_flush(s);\n}\n\n\n/* ===========================================================================\n * Determine the best encoding for the current block: dynamic trees, static\n * trees or store, and output the encoded block to the zip file.\n */\nfunction _tr_flush_block(s, buf, stored_len, last)\n//DeflateState *s;\n//charf *buf;       /* input block, or NULL if too old */\n//ulg stored_len;   /* length of input block */\n//int last;         /* one if this is the last block for a file */\n{\n  var opt_lenb, static_lenb;  /* opt_len and static_len in bytes */\n  var max_blindex = 0;        /* index of last bit length code of non zero freq */\n\n  /* Build the Huffman trees unless a stored block is forced */\n  if (s.level > 0) {\n\n    /* Check if the file is binary or text */\n    if (s.strm.data_type === Z_UNKNOWN) {\n      s.strm.data_type = detect_data_type(s);\n    }\n\n    /* Construct the literal and distance trees */\n    build_tree(s, s.l_desc);\n    // Tracev((stderr, \"\\nlit data: dyn %ld, stat %ld\", s->opt_len,\n    //        s->static_len));\n\n    build_tree(s, s.d_desc);\n    // Tracev((stderr, \"\\ndist data: dyn %ld, stat %ld\", s->opt_len,\n    //        s->static_len));\n    /* At this point, opt_len and static_len are the total bit lengths of\n     * the compressed block data, excluding the tree representations.\n     */\n\n    /* Build the bit length tree for the above two trees, and get the index\n     * in bl_order of the last bit length code to send.\n     */\n    max_blindex = build_bl_tree(s);\n\n    /* Determine the best encoding. Compute the block lengths in bytes. */\n    opt_lenb = (s.opt_len + 3 + 7) >>> 3;\n    static_lenb = (s.static_len + 3 + 7) >>> 3;\n\n    // Tracev((stderr, \"\\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u \",\n    //        opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,\n    //        s->last_lit));\n\n    if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; }\n\n  } else {\n    // Assert(buf != (char*)0, \"lost buf\");\n    opt_lenb = static_lenb = stored_len + 5; /* force a stored block */\n  }\n\n  if ((stored_len + 4 <= opt_lenb) && (buf !== -1)) {\n    /* 4: two words for the lengths */\n\n    /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.\n     * Otherwise we can't have processed more than WSIZE input bytes since\n     * the last block flush, because compression would have been\n     * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to\n     * transform a block into a stored block.\n     */\n    _tr_stored_block(s, buf, stored_len, last);\n\n  } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) {\n\n    send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3);\n    compress_block(s, static_ltree, static_dtree);\n\n  } else {\n    send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3);\n    send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1);\n    compress_block(s, s.dyn_ltree, s.dyn_dtree);\n  }\n  // Assert (s->compressed_len == s->bits_sent, \"bad compressed size\");\n  /* The above check is made mod 2^32, for files larger than 512 MB\n   * and uLong implemented on 32 bits.\n   */\n  init_block(s);\n\n  if (last) {\n    bi_windup(s);\n  }\n  // Tracev((stderr,\"\\ncomprlen %lu(%lu) \", s->compressed_len>>3,\n  //       s->compressed_len-7*last));\n}\n\n/* ===========================================================================\n * Save the match info and tally the frequency counts. Return true if\n * the current block must be flushed.\n */\nfunction _tr_tally(s, dist, lc)\n//    deflate_state *s;\n//    unsigned dist;  /* distance of matched string */\n//    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */\n{\n  //var out_length, in_length, dcode;\n\n  s.pending_buf[s.d_buf + s.last_lit * 2]     = (dist >>> 8) & 0xff;\n  s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff;\n\n  s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff;\n  s.last_lit++;\n\n  if (dist === 0) {\n    /* lc is the unmatched char */\n    s.dyn_ltree[lc * 2]/*.Freq*/++;\n  } else {\n    s.matches++;\n    /* Here, lc is the match length - MIN_MATCH */\n    dist--;             /* dist = match distance - 1 */\n    //Assert((ush)dist < (ush)MAX_DIST(s) &&\n    //       (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&\n    //       (ush)d_code(dist) < (ush)D_CODES,  \"_tr_tally: bad match\");\n\n    s.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]/*.Freq*/++;\n    s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;\n  }\n\n// (!) This block is disabled in zlib defaults,\n// don't enable it for binary compatibility\n\n//#ifdef TRUNCATE_BLOCK\n//  /* Try to guess if it is profitable to stop the current block here */\n//  if ((s.last_lit & 0x1fff) === 0 && s.level > 2) {\n//    /* Compute an upper bound for the compressed length */\n//    out_length = s.last_lit*8;\n//    in_length = s.strstart - s.block_start;\n//\n//    for (dcode = 0; dcode < D_CODES; dcode++) {\n//      out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]);\n//    }\n//    out_length >>>= 3;\n//    //Tracev((stderr,\"\\nlast_lit %u, in %ld, out ~%ld(%ld%%) \",\n//    //       s->last_lit, in_length, out_length,\n//    //       100L - out_length*100L/in_length));\n//    if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) {\n//      return true;\n//    }\n//  }\n//#endif\n\n  return (s.last_lit === s.lit_bufsize - 1);\n  /* We avoid equality with lit_bufsize because of wraparound at 64K\n   * on 16 bit machines and because stored blocks are restricted to\n   * 64K-1 bytes.\n   */\n}\n\nexports._tr_init  = _tr_init;\nexports._tr_stored_block = _tr_stored_block;\nexports._tr_flush_block  = _tr_flush_block;\nexports._tr_tally = _tr_tally;\nexports._tr_align = _tr_align;\n\n\n/***/ }),\n/* 156 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nmodule.exports = {\n  2:      'need dictionary',     /* Z_NEED_DICT       2  */\n  1:      'stream end',          /* Z_STREAM_END      1  */\n  0:      '',                    /* Z_OK              0  */\n  '-1':   'file error',          /* Z_ERRNO         (-1) */\n  '-2':   'stream error',        /* Z_STREAM_ERROR  (-2) */\n  '-3':   'data error',          /* Z_DATA_ERROR    (-3) */\n  '-4':   'insufficient memory', /* Z_MEM_ERROR     (-4) */\n  '-5':   'buffer error',        /* Z_BUF_ERROR     (-5) */\n  '-6':   'incompatible version' /* Z_VERSION_ERROR (-6) */\n};\n\n\n/***/ }),\n/* 157 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nvar utils         = __webpack_require__(34);\nvar adler32       = __webpack_require__(89);\nvar crc32         = __webpack_require__(90);\nvar inflate_fast  = __webpack_require__(158);\nvar inflate_table = __webpack_require__(159);\n\nvar CODES = 0;\nvar LENS = 1;\nvar DISTS = 2;\n\n/* Public constants ==========================================================*/\n/* ===========================================================================*/\n\n\n/* Allowed flush values; see deflate() and inflate() below for details */\n//var Z_NO_FLUSH      = 0;\n//var Z_PARTIAL_FLUSH = 1;\n//var Z_SYNC_FLUSH    = 2;\n//var Z_FULL_FLUSH    = 3;\nvar Z_FINISH        = 4;\nvar Z_BLOCK         = 5;\nvar Z_TREES         = 6;\n\n\n/* Return codes for the compression/decompression functions. Negative values\n * are errors, positive values are used for special but normal events.\n */\nvar Z_OK            = 0;\nvar Z_STREAM_END    = 1;\nvar Z_NEED_DICT     = 2;\n//var Z_ERRNO         = -1;\nvar Z_STREAM_ERROR  = -2;\nvar Z_DATA_ERROR    = -3;\nvar Z_MEM_ERROR     = -4;\nvar Z_BUF_ERROR     = -5;\n//var Z_VERSION_ERROR = -6;\n\n/* The deflate compression method */\nvar Z_DEFLATED  = 8;\n\n\n/* STATES ====================================================================*/\n/* ===========================================================================*/\n\n\nvar    HEAD = 1;       /* i: waiting for magic header */\nvar    FLAGS = 2;      /* i: waiting for method and flags (gzip) */\nvar    TIME = 3;       /* i: waiting for modification time (gzip) */\nvar    OS = 4;         /* i: waiting for extra flags and operating system (gzip) */\nvar    EXLEN = 5;      /* i: waiting for extra length (gzip) */\nvar    EXTRA = 6;      /* i: waiting for extra bytes (gzip) */\nvar    NAME = 7;       /* i: waiting for end of file name (gzip) */\nvar    COMMENT = 8;    /* i: waiting for end of comment (gzip) */\nvar    HCRC = 9;       /* i: waiting for header crc (gzip) */\nvar    DICTID = 10;    /* i: waiting for dictionary check value */\nvar    DICT = 11;      /* waiting for inflateSetDictionary() call */\nvar        TYPE = 12;      /* i: waiting for type bits, including last-flag bit */\nvar        TYPEDO = 13;    /* i: same, but skip check to exit inflate on new block */\nvar        STORED = 14;    /* i: waiting for stored size (length and complement) */\nvar        COPY_ = 15;     /* i/o: same as COPY below, but only first time in */\nvar        COPY = 16;      /* i/o: waiting for input or output to copy stored block */\nvar        TABLE = 17;     /* i: waiting for dynamic block table lengths */\nvar        LENLENS = 18;   /* i: waiting for code length code lengths */\nvar        CODELENS = 19;  /* i: waiting for length/lit and distance code lengths */\nvar            LEN_ = 20;      /* i: same as LEN below, but only first time in */\nvar            LEN = 21;       /* i: waiting for length/lit/eob code */\nvar            LENEXT = 22;    /* i: waiting for length extra bits */\nvar            DIST = 23;      /* i: waiting for distance code */\nvar            DISTEXT = 24;   /* i: waiting for distance extra bits */\nvar            MATCH = 25;     /* o: waiting for output space to copy string */\nvar            LIT = 26;       /* o: waiting for output space to write literal */\nvar    CHECK = 27;     /* i: waiting for 32-bit check value */\nvar    LENGTH = 28;    /* i: waiting for 32-bit length (gzip) */\nvar    DONE = 29;      /* finished check, done -- remain here until reset */\nvar    BAD = 30;       /* got a data error -- remain here until reset */\nvar    MEM = 31;       /* got an inflate() memory error -- remain here until reset */\nvar    SYNC = 32;      /* looking for synchronization bytes to restart inflate() */\n\n/* ===========================================================================*/\n\n\n\nvar ENOUGH_LENS = 852;\nvar ENOUGH_DISTS = 592;\n//var ENOUGH =  (ENOUGH_LENS+ENOUGH_DISTS);\n\nvar MAX_WBITS = 15;\n/* 32K LZ77 window */\nvar DEF_WBITS = MAX_WBITS;\n\n\nfunction zswap32(q) {\n  return  (((q >>> 24) & 0xff) +\n          ((q >>> 8) & 0xff00) +\n          ((q & 0xff00) << 8) +\n          ((q & 0xff) << 24));\n}\n\n\nfunction InflateState() {\n  this.mode = 0;             /* current inflate mode */\n  this.last = false;          /* true if processing last block */\n  this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */\n  this.havedict = false;      /* true if dictionary provided */\n  this.flags = 0;             /* gzip header method and flags (0 if zlib) */\n  this.dmax = 0;              /* zlib header max distance (INFLATE_STRICT) */\n  this.check = 0;             /* protected copy of check value */\n  this.total = 0;             /* protected copy of output count */\n  // TODO: may be {}\n  this.head = null;           /* where to save gzip header information */\n\n  /* sliding window */\n  this.wbits = 0;             /* log base 2 of requested window size */\n  this.wsize = 0;             /* window size or zero if not using window */\n  this.whave = 0;             /* valid bytes in the window */\n  this.wnext = 0;             /* window write index */\n  this.window = null;         /* allocated sliding window, if needed */\n\n  /* bit accumulator */\n  this.hold = 0;              /* input bit accumulator */\n  this.bits = 0;              /* number of bits in \"in\" */\n\n  /* for string and stored block copying */\n  this.length = 0;            /* literal or length of data to copy */\n  this.offset = 0;            /* distance back to copy string from */\n\n  /* for table and code decoding */\n  this.extra = 0;             /* extra bits needed */\n\n  /* fixed and dynamic code tables */\n  this.lencode = null;          /* starting table for length/literal codes */\n  this.distcode = null;         /* starting table for distance codes */\n  this.lenbits = 0;           /* index bits for lencode */\n  this.distbits = 0;          /* index bits for distcode */\n\n  /* dynamic table building */\n  this.ncode = 0;             /* number of code length code lengths */\n  this.nlen = 0;              /* number of length code lengths */\n  this.ndist = 0;             /* number of distance code lengths */\n  this.have = 0;              /* number of code lengths in lens[] */\n  this.next = null;              /* next available space in codes[] */\n\n  this.lens = new utils.Buf16(320); /* temporary storage for code lengths */\n  this.work = new utils.Buf16(288); /* work area for code table building */\n\n  /*\n   because we don't have pointers in js, we use lencode and distcode directly\n   as buffers so we don't need codes\n  */\n  //this.codes = new utils.Buf32(ENOUGH);       /* space for code tables */\n  this.lendyn = null;              /* dynamic table for length/literal codes (JS specific) */\n  this.distdyn = null;             /* dynamic table for distance codes (JS specific) */\n  this.sane = 0;                   /* if false, allow invalid distance too far */\n  this.back = 0;                   /* bits back of last unprocessed length/lit */\n  this.was = 0;                    /* initial length of match */\n}\n\nfunction inflateResetKeep(strm) {\n  var state;\n\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n  strm.total_in = strm.total_out = state.total = 0;\n  strm.msg = ''; /*Z_NULL*/\n  if (state.wrap) {       /* to support ill-conceived Java test suite */\n    strm.adler = state.wrap & 1;\n  }\n  state.mode = HEAD;\n  state.last = 0;\n  state.havedict = 0;\n  state.dmax = 32768;\n  state.head = null/*Z_NULL*/;\n  state.hold = 0;\n  state.bits = 0;\n  //state.lencode = state.distcode = state.next = state.codes;\n  state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS);\n  state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS);\n\n  state.sane = 1;\n  state.back = -1;\n  //Tracev((stderr, \"inflate: reset\\n\"));\n  return Z_OK;\n}\n\nfunction inflateReset(strm) {\n  var state;\n\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n  state.wsize = 0;\n  state.whave = 0;\n  state.wnext = 0;\n  return inflateResetKeep(strm);\n\n}\n\nfunction inflateReset2(strm, windowBits) {\n  var wrap;\n  var state;\n\n  /* get the state */\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n\n  /* extract wrap request from windowBits parameter */\n  if (windowBits < 0) {\n    wrap = 0;\n    windowBits = -windowBits;\n  }\n  else {\n    wrap = (windowBits >> 4) + 1;\n    if (windowBits < 48) {\n      windowBits &= 15;\n    }\n  }\n\n  /* set number of window bits, free window if different */\n  if (windowBits && (windowBits < 8 || windowBits > 15)) {\n    return Z_STREAM_ERROR;\n  }\n  if (state.window !== null && state.wbits !== windowBits) {\n    state.window = null;\n  }\n\n  /* update state and reset the rest of it */\n  state.wrap = wrap;\n  state.wbits = windowBits;\n  return inflateReset(strm);\n}\n\nfunction inflateInit2(strm, windowBits) {\n  var ret;\n  var state;\n\n  if (!strm) { return Z_STREAM_ERROR; }\n  //strm.msg = Z_NULL;                 /* in case we return an error */\n\n  state = new InflateState();\n\n  //if (state === Z_NULL) return Z_MEM_ERROR;\n  //Tracev((stderr, \"inflate: allocated\\n\"));\n  strm.state = state;\n  state.window = null/*Z_NULL*/;\n  ret = inflateReset2(strm, windowBits);\n  if (ret !== Z_OK) {\n    strm.state = null/*Z_NULL*/;\n  }\n  return ret;\n}\n\nfunction inflateInit(strm) {\n  return inflateInit2(strm, DEF_WBITS);\n}\n\n\n/*\n Return state with length and distance decoding tables and index sizes set to\n fixed code decoding.  Normally this returns fixed tables from inffixed.h.\n If BUILDFIXED is defined, then instead this routine builds the tables the\n first time it's called, and returns those tables the first time and\n thereafter.  This reduces the size of the code by about 2K bytes, in\n exchange for a little execution time.  However, BUILDFIXED should not be\n used for threaded applications, since the rewriting of the tables and virgin\n may not be thread-safe.\n */\nvar virgin = true;\n\nvar lenfix, distfix; // We have no pointers in JS, so keep tables separate\n\nfunction fixedtables(state) {\n  /* build fixed huffman tables if first call (may not be thread safe) */\n  if (virgin) {\n    var sym;\n\n    lenfix = new utils.Buf32(512);\n    distfix = new utils.Buf32(32);\n\n    /* literal/length table */\n    sym = 0;\n    while (sym < 144) { state.lens[sym++] = 8; }\n    while (sym < 256) { state.lens[sym++] = 9; }\n    while (sym < 280) { state.lens[sym++] = 7; }\n    while (sym < 288) { state.lens[sym++] = 8; }\n\n    inflate_table(LENS,  state.lens, 0, 288, lenfix,   0, state.work, { bits: 9 });\n\n    /* distance table */\n    sym = 0;\n    while (sym < 32) { state.lens[sym++] = 5; }\n\n    inflate_table(DISTS, state.lens, 0, 32,   distfix, 0, state.work, { bits: 5 });\n\n    /* do this just once */\n    virgin = false;\n  }\n\n  state.lencode = lenfix;\n  state.lenbits = 9;\n  state.distcode = distfix;\n  state.distbits = 5;\n}\n\n\n/*\n Update the window with the last wsize (normally 32K) bytes written before\n returning.  If window does not exist yet, create it.  This is only called\n when a window is already in use, or when output has been written during this\n inflate call, but the end of the deflate stream has not been reached yet.\n It is also called to create a window for dictionary data when a dictionary\n is loaded.\n\n Providing output buffers larger than 32K to inflate() should provide a speed\n advantage, since only the last 32K of output is copied to the sliding window\n upon return from inflate(), and since all distances after the first 32K of\n output will fall in the output data, making match copies simpler and faster.\n The advantage may be dependent on the size of the processor's data caches.\n */\nfunction updatewindow(strm, src, end, copy) {\n  var dist;\n  var state = strm.state;\n\n  /* if it hasn't been done already, allocate space for the window */\n  if (state.window === null) {\n    state.wsize = 1 << state.wbits;\n    state.wnext = 0;\n    state.whave = 0;\n\n    state.window = new utils.Buf8(state.wsize);\n  }\n\n  /* copy state->wsize or less output bytes into the circular window */\n  if (copy >= state.wsize) {\n    utils.arraySet(state.window, src, end - state.wsize, state.wsize, 0);\n    state.wnext = 0;\n    state.whave = state.wsize;\n  }\n  else {\n    dist = state.wsize - state.wnext;\n    if (dist > copy) {\n      dist = copy;\n    }\n    //zmemcpy(state->window + state->wnext, end - copy, dist);\n    utils.arraySet(state.window, src, end - copy, dist, state.wnext);\n    copy -= dist;\n    if (copy) {\n      //zmemcpy(state->window, end - copy, copy);\n      utils.arraySet(state.window, src, end - copy, copy, 0);\n      state.wnext = copy;\n      state.whave = state.wsize;\n    }\n    else {\n      state.wnext += dist;\n      if (state.wnext === state.wsize) { state.wnext = 0; }\n      if (state.whave < state.wsize) { state.whave += dist; }\n    }\n  }\n  return 0;\n}\n\nfunction inflate(strm, flush) {\n  var state;\n  var input, output;          // input/output buffers\n  var next;                   /* next input INDEX */\n  var put;                    /* next output INDEX */\n  var have, left;             /* available input and output */\n  var hold;                   /* bit buffer */\n  var bits;                   /* bits in bit buffer */\n  var _in, _out;              /* save starting available input and output */\n  var copy;                   /* number of stored or match bytes to copy */\n  var from;                   /* where to copy match bytes from */\n  var from_source;\n  var here = 0;               /* current decoding table entry */\n  var here_bits, here_op, here_val; // paked \"here\" denormalized (JS specific)\n  //var last;                   /* parent table entry */\n  var last_bits, last_op, last_val; // paked \"last\" denormalized (JS specific)\n  var len;                    /* length to copy for repeats, bits to drop */\n  var ret;                    /* return code */\n  var hbuf = new utils.Buf8(4);    /* buffer for gzip header crc calculation */\n  var opts;\n\n  var n; // temporary var for NEED_BITS\n\n  var order = /* permutation of code lengths */\n    [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];\n\n\n  if (!strm || !strm.state || !strm.output ||\n      (!strm.input && strm.avail_in !== 0)) {\n    return Z_STREAM_ERROR;\n  }\n\n  state = strm.state;\n  if (state.mode === TYPE) { state.mode = TYPEDO; }    /* skip check */\n\n\n  //--- LOAD() ---\n  put = strm.next_out;\n  output = strm.output;\n  left = strm.avail_out;\n  next = strm.next_in;\n  input = strm.input;\n  have = strm.avail_in;\n  hold = state.hold;\n  bits = state.bits;\n  //---\n\n  _in = have;\n  _out = left;\n  ret = Z_OK;\n\n  inf_leave: // goto emulation\n  for (;;) {\n    switch (state.mode) {\n      case HEAD:\n        if (state.wrap === 0) {\n          state.mode = TYPEDO;\n          break;\n        }\n        //=== NEEDBITS(16);\n        while (bits < 16) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        if ((state.wrap & 2) && hold === 0x8b1f) {  /* gzip header */\n          state.check = 0/*crc32(0L, Z_NULL, 0)*/;\n          //=== CRC2(state.check, hold);\n          hbuf[0] = hold & 0xff;\n          hbuf[1] = (hold >>> 8) & 0xff;\n          state.check = crc32(state.check, hbuf, 2, 0);\n          //===//\n\n          //=== INITBITS();\n          hold = 0;\n          bits = 0;\n          //===//\n          state.mode = FLAGS;\n          break;\n        }\n        state.flags = 0;           /* expect zlib header */\n        if (state.head) {\n          state.head.done = false;\n        }\n        if (!(state.wrap & 1) ||   /* check if zlib header allowed */\n          (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {\n          strm.msg = 'incorrect header check';\n          state.mode = BAD;\n          break;\n        }\n        if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {\n          strm.msg = 'unknown compression method';\n          state.mode = BAD;\n          break;\n        }\n        //--- DROPBITS(4) ---//\n        hold >>>= 4;\n        bits -= 4;\n        //---//\n        len = (hold & 0x0f)/*BITS(4)*/ + 8;\n        if (state.wbits === 0) {\n          state.wbits = len;\n        }\n        else if (len > state.wbits) {\n          strm.msg = 'invalid window size';\n          state.mode = BAD;\n          break;\n        }\n        state.dmax = 1 << len;\n        //Tracev((stderr, \"inflate:   zlib header ok\\n\"));\n        strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;\n        state.mode = hold & 0x200 ? DICTID : TYPE;\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        break;\n      case FLAGS:\n        //=== NEEDBITS(16); */\n        while (bits < 16) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        state.flags = hold;\n        if ((state.flags & 0xff) !== Z_DEFLATED) {\n          strm.msg = 'unknown compression method';\n          state.mode = BAD;\n          break;\n        }\n        if (state.flags & 0xe000) {\n          strm.msg = 'unknown header flags set';\n          state.mode = BAD;\n          break;\n        }\n        if (state.head) {\n          state.head.text = ((hold >> 8) & 1);\n        }\n        if (state.flags & 0x0200) {\n          //=== CRC2(state.check, hold);\n          hbuf[0] = hold & 0xff;\n          hbuf[1] = (hold >>> 8) & 0xff;\n          state.check = crc32(state.check, hbuf, 2, 0);\n          //===//\n        }\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        state.mode = TIME;\n        /* falls through */\n      case TIME:\n        //=== NEEDBITS(32); */\n        while (bits < 32) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        if (state.head) {\n          state.head.time = hold;\n        }\n        if (state.flags & 0x0200) {\n          //=== CRC4(state.check, hold)\n          hbuf[0] = hold & 0xff;\n          hbuf[1] = (hold >>> 8) & 0xff;\n          hbuf[2] = (hold >>> 16) & 0xff;\n          hbuf[3] = (hold >>> 24) & 0xff;\n          state.check = crc32(state.check, hbuf, 4, 0);\n          //===\n        }\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        state.mode = OS;\n        /* falls through */\n      case OS:\n        //=== NEEDBITS(16); */\n        while (bits < 16) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        if (state.head) {\n          state.head.xflags = (hold & 0xff);\n          state.head.os = (hold >> 8);\n        }\n        if (state.flags & 0x0200) {\n          //=== CRC2(state.check, hold);\n          hbuf[0] = hold & 0xff;\n          hbuf[1] = (hold >>> 8) & 0xff;\n          state.check = crc32(state.check, hbuf, 2, 0);\n          //===//\n        }\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        state.mode = EXLEN;\n        /* falls through */\n      case EXLEN:\n        if (state.flags & 0x0400) {\n          //=== NEEDBITS(16); */\n          while (bits < 16) {\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n          }\n          //===//\n          state.length = hold;\n          if (state.head) {\n            state.head.extra_len = hold;\n          }\n          if (state.flags & 0x0200) {\n            //=== CRC2(state.check, hold);\n            hbuf[0] = hold & 0xff;\n            hbuf[1] = (hold >>> 8) & 0xff;\n            state.check = crc32(state.check, hbuf, 2, 0);\n            //===//\n          }\n          //=== INITBITS();\n          hold = 0;\n          bits = 0;\n          //===//\n        }\n        else if (state.head) {\n          state.head.extra = null/*Z_NULL*/;\n        }\n        state.mode = EXTRA;\n        /* falls through */\n      case EXTRA:\n        if (state.flags & 0x0400) {\n          copy = state.length;\n          if (copy > have) { copy = have; }\n          if (copy) {\n            if (state.head) {\n              len = state.head.extra_len - state.length;\n              if (!state.head.extra) {\n                // Use untyped array for more convenient processing later\n                state.head.extra = new Array(state.head.extra_len);\n              }\n              utils.arraySet(\n                state.head.extra,\n                input,\n                next,\n                // extra field is limited to 65536 bytes\n                // - no need for additional size check\n                copy,\n                /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/\n                len\n              );\n              //zmemcpy(state.head.extra + len, next,\n              //        len + copy > state.head.extra_max ?\n              //        state.head.extra_max - len : copy);\n            }\n            if (state.flags & 0x0200) {\n              state.check = crc32(state.check, input, copy, next);\n            }\n            have -= copy;\n            next += copy;\n            state.length -= copy;\n          }\n          if (state.length) { break inf_leave; }\n        }\n        state.length = 0;\n        state.mode = NAME;\n        /* falls through */\n      case NAME:\n        if (state.flags & 0x0800) {\n          if (have === 0) { break inf_leave; }\n          copy = 0;\n          do {\n            // TODO: 2 or 1 bytes?\n            len = input[next + copy++];\n            /* use constant limit because in js we should not preallocate memory */\n            if (state.head && len &&\n                (state.length < 65536 /*state.head.name_max*/)) {\n              state.head.name += String.fromCharCode(len);\n            }\n          } while (len && copy < have);\n\n          if (state.flags & 0x0200) {\n            state.check = crc32(state.check, input, copy, next);\n          }\n          have -= copy;\n          next += copy;\n          if (len) { break inf_leave; }\n        }\n        else if (state.head) {\n          state.head.name = null;\n        }\n        state.length = 0;\n        state.mode = COMMENT;\n        /* falls through */\n      case COMMENT:\n        if (state.flags & 0x1000) {\n          if (have === 0) { break inf_leave; }\n          copy = 0;\n          do {\n            len = input[next + copy++];\n            /* use constant limit because in js we should not preallocate memory */\n            if (state.head && len &&\n                (state.length < 65536 /*state.head.comm_max*/)) {\n              state.head.comment += String.fromCharCode(len);\n            }\n          } while (len && copy < have);\n          if (state.flags & 0x0200) {\n            state.check = crc32(state.check, input, copy, next);\n          }\n          have -= copy;\n          next += copy;\n          if (len) { break inf_leave; }\n        }\n        else if (state.head) {\n          state.head.comment = null;\n        }\n        state.mode = HCRC;\n        /* falls through */\n      case HCRC:\n        if (state.flags & 0x0200) {\n          //=== NEEDBITS(16); */\n          while (bits < 16) {\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n          }\n          //===//\n          if (hold !== (state.check & 0xffff)) {\n            strm.msg = 'header crc mismatch';\n            state.mode = BAD;\n            break;\n          }\n          //=== INITBITS();\n          hold = 0;\n          bits = 0;\n          //===//\n        }\n        if (state.head) {\n          state.head.hcrc = ((state.flags >> 9) & 1);\n          state.head.done = true;\n        }\n        strm.adler = state.check = 0;\n        state.mode = TYPE;\n        break;\n      case DICTID:\n        //=== NEEDBITS(32); */\n        while (bits < 32) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        strm.adler = state.check = zswap32(hold);\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        state.mode = DICT;\n        /* falls through */\n      case DICT:\n        if (state.havedict === 0) {\n          //--- RESTORE() ---\n          strm.next_out = put;\n          strm.avail_out = left;\n          strm.next_in = next;\n          strm.avail_in = have;\n          state.hold = hold;\n          state.bits = bits;\n          //---\n          return Z_NEED_DICT;\n        }\n        strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;\n        state.mode = TYPE;\n        /* falls through */\n      case TYPE:\n        if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }\n        /* falls through */\n      case TYPEDO:\n        if (state.last) {\n          //--- BYTEBITS() ---//\n          hold >>>= bits & 7;\n          bits -= bits & 7;\n          //---//\n          state.mode = CHECK;\n          break;\n        }\n        //=== NEEDBITS(3); */\n        while (bits < 3) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        state.last = (hold & 0x01)/*BITS(1)*/;\n        //--- DROPBITS(1) ---//\n        hold >>>= 1;\n        bits -= 1;\n        //---//\n\n        switch ((hold & 0x03)/*BITS(2)*/) {\n          case 0:                             /* stored block */\n            //Tracev((stderr, \"inflate:     stored block%s\\n\",\n            //        state.last ? \" (last)\" : \"\"));\n            state.mode = STORED;\n            break;\n          case 1:                             /* fixed block */\n            fixedtables(state);\n            //Tracev((stderr, \"inflate:     fixed codes block%s\\n\",\n            //        state.last ? \" (last)\" : \"\"));\n            state.mode = LEN_;             /* decode codes */\n            if (flush === Z_TREES) {\n              //--- DROPBITS(2) ---//\n              hold >>>= 2;\n              bits -= 2;\n              //---//\n              break inf_leave;\n            }\n            break;\n          case 2:                             /* dynamic block */\n            //Tracev((stderr, \"inflate:     dynamic codes block%s\\n\",\n            //        state.last ? \" (last)\" : \"\"));\n            state.mode = TABLE;\n            break;\n          case 3:\n            strm.msg = 'invalid block type';\n            state.mode = BAD;\n        }\n        //--- DROPBITS(2) ---//\n        hold >>>= 2;\n        bits -= 2;\n        //---//\n        break;\n      case STORED:\n        //--- BYTEBITS() ---// /* go to byte boundary */\n        hold >>>= bits & 7;\n        bits -= bits & 7;\n        //---//\n        //=== NEEDBITS(32); */\n        while (bits < 32) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {\n          strm.msg = 'invalid stored block lengths';\n          state.mode = BAD;\n          break;\n        }\n        state.length = hold & 0xffff;\n        //Tracev((stderr, \"inflate:       stored length %u\\n\",\n        //        state.length));\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        state.mode = COPY_;\n        if (flush === Z_TREES) { break inf_leave; }\n        /* falls through */\n      case COPY_:\n        state.mode = COPY;\n        /* falls through */\n      case COPY:\n        copy = state.length;\n        if (copy) {\n          if (copy > have) { copy = have; }\n          if (copy > left) { copy = left; }\n          if (copy === 0) { break inf_leave; }\n          //--- zmemcpy(put, next, copy); ---\n          utils.arraySet(output, input, next, copy, put);\n          //---//\n          have -= copy;\n          next += copy;\n          left -= copy;\n          put += copy;\n          state.length -= copy;\n          break;\n        }\n        //Tracev((stderr, \"inflate:       stored end\\n\"));\n        state.mode = TYPE;\n        break;\n      case TABLE:\n        //=== NEEDBITS(14); */\n        while (bits < 14) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;\n        //--- DROPBITS(5) ---//\n        hold >>>= 5;\n        bits -= 5;\n        //---//\n        state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;\n        //--- DROPBITS(5) ---//\n        hold >>>= 5;\n        bits -= 5;\n        //---//\n        state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;\n        //--- DROPBITS(4) ---//\n        hold >>>= 4;\n        bits -= 4;\n        //---//\n//#ifndef PKZIP_BUG_WORKAROUND\n        if (state.nlen > 286 || state.ndist > 30) {\n          strm.msg = 'too many length or distance symbols';\n          state.mode = BAD;\n          break;\n        }\n//#endif\n        //Tracev((stderr, \"inflate:       table sizes ok\\n\"));\n        state.have = 0;\n        state.mode = LENLENS;\n        /* falls through */\n      case LENLENS:\n        while (state.have < state.ncode) {\n          //=== NEEDBITS(3);\n          while (bits < 3) {\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n          }\n          //===//\n          state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);\n          //--- DROPBITS(3) ---//\n          hold >>>= 3;\n          bits -= 3;\n          //---//\n        }\n        while (state.have < 19) {\n          state.lens[order[state.have++]] = 0;\n        }\n        // We have separate tables & no pointers. 2 commented lines below not needed.\n        //state.next = state.codes;\n        //state.lencode = state.next;\n        // Switch to use dynamic table\n        state.lencode = state.lendyn;\n        state.lenbits = 7;\n\n        opts = { bits: state.lenbits };\n        ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);\n        state.lenbits = opts.bits;\n\n        if (ret) {\n          strm.msg = 'invalid code lengths set';\n          state.mode = BAD;\n          break;\n        }\n        //Tracev((stderr, \"inflate:       code lengths ok\\n\"));\n        state.have = 0;\n        state.mode = CODELENS;\n        /* falls through */\n      case CODELENS:\n        while (state.have < state.nlen + state.ndist) {\n          for (;;) {\n            here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/\n            here_bits = here >>> 24;\n            here_op = (here >>> 16) & 0xff;\n            here_val = here & 0xffff;\n\n            if ((here_bits) <= bits) { break; }\n            //--- PULLBYTE() ---//\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n            //---//\n          }\n          if (here_val < 16) {\n            //--- DROPBITS(here.bits) ---//\n            hold >>>= here_bits;\n            bits -= here_bits;\n            //---//\n            state.lens[state.have++] = here_val;\n          }\n          else {\n            if (here_val === 16) {\n              //=== NEEDBITS(here.bits + 2);\n              n = here_bits + 2;\n              while (bits < n) {\n                if (have === 0) { break inf_leave; }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              //===//\n              //--- DROPBITS(here.bits) ---//\n              hold >>>= here_bits;\n              bits -= here_bits;\n              //---//\n              if (state.have === 0) {\n                strm.msg = 'invalid bit length repeat';\n                state.mode = BAD;\n                break;\n              }\n              len = state.lens[state.have - 1];\n              copy = 3 + (hold & 0x03);//BITS(2);\n              //--- DROPBITS(2) ---//\n              hold >>>= 2;\n              bits -= 2;\n              //---//\n            }\n            else if (here_val === 17) {\n              //=== NEEDBITS(here.bits + 3);\n              n = here_bits + 3;\n              while (bits < n) {\n                if (have === 0) { break inf_leave; }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              //===//\n              //--- DROPBITS(here.bits) ---//\n              hold >>>= here_bits;\n              bits -= here_bits;\n              //---//\n              len = 0;\n              copy = 3 + (hold & 0x07);//BITS(3);\n              //--- DROPBITS(3) ---//\n              hold >>>= 3;\n              bits -= 3;\n              //---//\n            }\n            else {\n              //=== NEEDBITS(here.bits + 7);\n              n = here_bits + 7;\n              while (bits < n) {\n                if (have === 0) { break inf_leave; }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              //===//\n              //--- DROPBITS(here.bits) ---//\n              hold >>>= here_bits;\n              bits -= here_bits;\n              //---//\n              len = 0;\n              copy = 11 + (hold & 0x7f);//BITS(7);\n              //--- DROPBITS(7) ---//\n              hold >>>= 7;\n              bits -= 7;\n              //---//\n            }\n            if (state.have + copy > state.nlen + state.ndist) {\n              strm.msg = 'invalid bit length repeat';\n              state.mode = BAD;\n              break;\n            }\n            while (copy--) {\n              state.lens[state.have++] = len;\n            }\n          }\n        }\n\n        /* handle error breaks in while */\n        if (state.mode === BAD) { break; }\n\n        /* check for end-of-block code (better have one) */\n        if (state.lens[256] === 0) {\n          strm.msg = 'invalid code -- missing end-of-block';\n          state.mode = BAD;\n          break;\n        }\n\n        /* build code tables -- note: do not change the lenbits or distbits\n           values here (9 and 6) without reading the comments in inftrees.h\n           concerning the ENOUGH constants, which depend on those values */\n        state.lenbits = 9;\n\n        opts = { bits: state.lenbits };\n        ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);\n        // We have separate tables & no pointers. 2 commented lines below not needed.\n        // state.next_index = opts.table_index;\n        state.lenbits = opts.bits;\n        // state.lencode = state.next;\n\n        if (ret) {\n          strm.msg = 'invalid literal/lengths set';\n          state.mode = BAD;\n          break;\n        }\n\n        state.distbits = 6;\n        //state.distcode.copy(state.codes);\n        // Switch to use dynamic table\n        state.distcode = state.distdyn;\n        opts = { bits: state.distbits };\n        ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);\n        // We have separate tables & no pointers. 2 commented lines below not needed.\n        // state.next_index = opts.table_index;\n        state.distbits = opts.bits;\n        // state.distcode = state.next;\n\n        if (ret) {\n          strm.msg = 'invalid distances set';\n          state.mode = BAD;\n          break;\n        }\n        //Tracev((stderr, 'inflate:       codes ok\\n'));\n        state.mode = LEN_;\n        if (flush === Z_TREES) { break inf_leave; }\n        /* falls through */\n      case LEN_:\n        state.mode = LEN;\n        /* falls through */\n      case LEN:\n        if (have >= 6 && left >= 258) {\n          //--- RESTORE() ---\n          strm.next_out = put;\n          strm.avail_out = left;\n          strm.next_in = next;\n          strm.avail_in = have;\n          state.hold = hold;\n          state.bits = bits;\n          //---\n          inflate_fast(strm, _out);\n          //--- LOAD() ---\n          put = strm.next_out;\n          output = strm.output;\n          left = strm.avail_out;\n          next = strm.next_in;\n          input = strm.input;\n          have = strm.avail_in;\n          hold = state.hold;\n          bits = state.bits;\n          //---\n\n          if (state.mode === TYPE) {\n            state.back = -1;\n          }\n          break;\n        }\n        state.back = 0;\n        for (;;) {\n          here = state.lencode[hold & ((1 << state.lenbits) - 1)];  /*BITS(state.lenbits)*/\n          here_bits = here >>> 24;\n          here_op = (here >>> 16) & 0xff;\n          here_val = here & 0xffff;\n\n          if (here_bits <= bits) { break; }\n          //--- PULLBYTE() ---//\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n          //---//\n        }\n        if (here_op && (here_op & 0xf0) === 0) {\n          last_bits = here_bits;\n          last_op = here_op;\n          last_val = here_val;\n          for (;;) {\n            here = state.lencode[last_val +\n                    ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];\n            here_bits = here >>> 24;\n            here_op = (here >>> 16) & 0xff;\n            here_val = here & 0xffff;\n\n            if ((last_bits + here_bits) <= bits) { break; }\n            //--- PULLBYTE() ---//\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n            //---//\n          }\n          //--- DROPBITS(last.bits) ---//\n          hold >>>= last_bits;\n          bits -= last_bits;\n          //---//\n          state.back += last_bits;\n        }\n        //--- DROPBITS(here.bits) ---//\n        hold >>>= here_bits;\n        bits -= here_bits;\n        //---//\n        state.back += here_bits;\n        state.length = here_val;\n        if (here_op === 0) {\n          //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?\n          //        \"inflate:         literal '%c'\\n\" :\n          //        \"inflate:         literal 0x%02x\\n\", here.val));\n          state.mode = LIT;\n          break;\n        }\n        if (here_op & 32) {\n          //Tracevv((stderr, \"inflate:         end of block\\n\"));\n          state.back = -1;\n          state.mode = TYPE;\n          break;\n        }\n        if (here_op & 64) {\n          strm.msg = 'invalid literal/length code';\n          state.mode = BAD;\n          break;\n        }\n        state.extra = here_op & 15;\n        state.mode = LENEXT;\n        /* falls through */\n      case LENEXT:\n        if (state.extra) {\n          //=== NEEDBITS(state.extra);\n          n = state.extra;\n          while (bits < n) {\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n          }\n          //===//\n          state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;\n          //--- DROPBITS(state.extra) ---//\n          hold >>>= state.extra;\n          bits -= state.extra;\n          //---//\n          state.back += state.extra;\n        }\n        //Tracevv((stderr, \"inflate:         length %u\\n\", state.length));\n        state.was = state.length;\n        state.mode = DIST;\n        /* falls through */\n      case DIST:\n        for (;;) {\n          here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/\n          here_bits = here >>> 24;\n          here_op = (here >>> 16) & 0xff;\n          here_val = here & 0xffff;\n\n          if ((here_bits) <= bits) { break; }\n          //--- PULLBYTE() ---//\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n          //---//\n        }\n        if ((here_op & 0xf0) === 0) {\n          last_bits = here_bits;\n          last_op = here_op;\n          last_val = here_val;\n          for (;;) {\n            here = state.distcode[last_val +\n                    ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];\n            here_bits = here >>> 24;\n            here_op = (here >>> 16) & 0xff;\n            here_val = here & 0xffff;\n\n            if ((last_bits + here_bits) <= bits) { break; }\n            //--- PULLBYTE() ---//\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n            //---//\n          }\n          //--- DROPBITS(last.bits) ---//\n          hold >>>= last_bits;\n          bits -= last_bits;\n          //---//\n          state.back += last_bits;\n        }\n        //--- DROPBITS(here.bits) ---//\n        hold >>>= here_bits;\n        bits -= here_bits;\n        //---//\n        state.back += here_bits;\n        if (here_op & 64) {\n          strm.msg = 'invalid distance code';\n          state.mode = BAD;\n          break;\n        }\n        state.offset = here_val;\n        state.extra = (here_op) & 15;\n        state.mode = DISTEXT;\n        /* falls through */\n      case DISTEXT:\n        if (state.extra) {\n          //=== NEEDBITS(state.extra);\n          n = state.extra;\n          while (bits < n) {\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n          }\n          //===//\n          state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;\n          //--- DROPBITS(state.extra) ---//\n          hold >>>= state.extra;\n          bits -= state.extra;\n          //---//\n          state.back += state.extra;\n        }\n//#ifdef INFLATE_STRICT\n        if (state.offset > state.dmax) {\n          strm.msg = 'invalid distance too far back';\n          state.mode = BAD;\n          break;\n        }\n//#endif\n        //Tracevv((stderr, \"inflate:         distance %u\\n\", state.offset));\n        state.mode = MATCH;\n        /* falls through */\n      case MATCH:\n        if (left === 0) { break inf_leave; }\n        copy = _out - left;\n        if (state.offset > copy) {         /* copy from window */\n          copy = state.offset - copy;\n          if (copy > state.whave) {\n            if (state.sane) {\n              strm.msg = 'invalid distance too far back';\n              state.mode = BAD;\n              break;\n            }\n// (!) This block is disabled in zlib defaults,\n// don't enable it for binary compatibility\n//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR\n//          Trace((stderr, \"inflate.c too far\\n\"));\n//          copy -= state.whave;\n//          if (copy > state.length) { copy = state.length; }\n//          if (copy > left) { copy = left; }\n//          left -= copy;\n//          state.length -= copy;\n//          do {\n//            output[put++] = 0;\n//          } while (--copy);\n//          if (state.length === 0) { state.mode = LEN; }\n//          break;\n//#endif\n          }\n          if (copy > state.wnext) {\n            copy -= state.wnext;\n            from = state.wsize - copy;\n          }\n          else {\n            from = state.wnext - copy;\n          }\n          if (copy > state.length) { copy = state.length; }\n          from_source = state.window;\n        }\n        else {                              /* copy from output */\n          from_source = output;\n          from = put - state.offset;\n          copy = state.length;\n        }\n        if (copy > left) { copy = left; }\n        left -= copy;\n        state.length -= copy;\n        do {\n          output[put++] = from_source[from++];\n        } while (--copy);\n        if (state.length === 0) { state.mode = LEN; }\n        break;\n      case LIT:\n        if (left === 0) { break inf_leave; }\n        output[put++] = state.length;\n        left--;\n        state.mode = LEN;\n        break;\n      case CHECK:\n        if (state.wrap) {\n          //=== NEEDBITS(32);\n          while (bits < 32) {\n            if (have === 0) { break inf_leave; }\n            have--;\n            // Use '|' instead of '+' to make sure that result is signed\n            hold |= input[next++] << bits;\n            bits += 8;\n          }\n          //===//\n          _out -= left;\n          strm.total_out += _out;\n          state.total += _out;\n          if (_out) {\n            strm.adler = state.check =\n                /*UPDATE(state.check, put - _out, _out);*/\n                (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out));\n\n          }\n          _out = left;\n          // NB: crc32 stored as signed 32-bit int, zswap32 returns signed too\n          if ((state.flags ? hold : zswap32(hold)) !== state.check) {\n            strm.msg = 'incorrect data check';\n            state.mode = BAD;\n            break;\n          }\n          //=== INITBITS();\n          hold = 0;\n          bits = 0;\n          //===//\n          //Tracev((stderr, \"inflate:   check matches trailer\\n\"));\n        }\n        state.mode = LENGTH;\n        /* falls through */\n      case LENGTH:\n        if (state.wrap && state.flags) {\n          //=== NEEDBITS(32);\n          while (bits < 32) {\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n          }\n          //===//\n          if (hold !== (state.total & 0xffffffff)) {\n            strm.msg = 'incorrect length check';\n            state.mode = BAD;\n            break;\n          }\n          //=== INITBITS();\n          hold = 0;\n          bits = 0;\n          //===//\n          //Tracev((stderr, \"inflate:   length matches trailer\\n\"));\n        }\n        state.mode = DONE;\n        /* falls through */\n      case DONE:\n        ret = Z_STREAM_END;\n        break inf_leave;\n      case BAD:\n        ret = Z_DATA_ERROR;\n        break inf_leave;\n      case MEM:\n        return Z_MEM_ERROR;\n      case SYNC:\n        /* falls through */\n      default:\n        return Z_STREAM_ERROR;\n    }\n  }\n\n  // inf_leave <- here is real place for \"goto inf_leave\", emulated via \"break inf_leave\"\n\n  /*\n     Return from inflate(), updating the total counts and the check value.\n     If there was no progress during the inflate() call, return a buffer\n     error.  Call updatewindow() to create and/or update the window state.\n     Note: a memory error from inflate() is non-recoverable.\n   */\n\n  //--- RESTORE() ---\n  strm.next_out = put;\n  strm.avail_out = left;\n  strm.next_in = next;\n  strm.avail_in = have;\n  state.hold = hold;\n  state.bits = bits;\n  //---\n\n  if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&\n                      (state.mode < CHECK || flush !== Z_FINISH))) {\n    if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {\n      state.mode = MEM;\n      return Z_MEM_ERROR;\n    }\n  }\n  _in -= strm.avail_in;\n  _out -= strm.avail_out;\n  strm.total_in += _in;\n  strm.total_out += _out;\n  state.total += _out;\n  if (state.wrap && _out) {\n    strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/\n      (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out));\n  }\n  strm.data_type = state.bits + (state.last ? 64 : 0) +\n                    (state.mode === TYPE ? 128 : 0) +\n                    (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);\n  if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) {\n    ret = Z_BUF_ERROR;\n  }\n  return ret;\n}\n\nfunction inflateEnd(strm) {\n\n  if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {\n    return Z_STREAM_ERROR;\n  }\n\n  var state = strm.state;\n  if (state.window) {\n    state.window = null;\n  }\n  strm.state = null;\n  return Z_OK;\n}\n\nfunction inflateGetHeader(strm, head) {\n  var state;\n\n  /* check state */\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n  if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; }\n\n  /* save header structure */\n  state.head = head;\n  head.done = false;\n  return Z_OK;\n}\n\nfunction inflateSetDictionary(strm, dictionary) {\n  var dictLength = dictionary.length;\n\n  var state;\n  var dictid;\n  var ret;\n\n  /* check state */\n  if (!strm /* == Z_NULL */ || !strm.state /* == Z_NULL */) { return Z_STREAM_ERROR; }\n  state = strm.state;\n\n  if (state.wrap !== 0 && state.mode !== DICT) {\n    return Z_STREAM_ERROR;\n  }\n\n  /* check for correct dictionary identifier */\n  if (state.mode === DICT) {\n    dictid = 1; /* adler32(0, null, 0)*/\n    /* dictid = adler32(dictid, dictionary, dictLength); */\n    dictid = adler32(dictid, dictionary, dictLength, 0);\n    if (dictid !== state.check) {\n      return Z_DATA_ERROR;\n    }\n  }\n  /* copy dictionary to window using updatewindow(), which will amend the\n   existing dictionary if appropriate */\n  ret = updatewindow(strm, dictionary, dictLength, dictLength);\n  if (ret) {\n    state.mode = MEM;\n    return Z_MEM_ERROR;\n  }\n  state.havedict = 1;\n  // Tracev((stderr, \"inflate:   dictionary set\\n\"));\n  return Z_OK;\n}\n\nexports.inflateReset = inflateReset;\nexports.inflateReset2 = inflateReset2;\nexports.inflateResetKeep = inflateResetKeep;\nexports.inflateInit = inflateInit;\nexports.inflateInit2 = inflateInit2;\nexports.inflate = inflate;\nexports.inflateEnd = inflateEnd;\nexports.inflateGetHeader = inflateGetHeader;\nexports.inflateSetDictionary = inflateSetDictionary;\nexports.inflateInfo = 'pako inflate (from Nodeca project)';\n\n/* Not implemented\nexports.inflateCopy = inflateCopy;\nexports.inflateGetDictionary = inflateGetDictionary;\nexports.inflateMark = inflateMark;\nexports.inflatePrime = inflatePrime;\nexports.inflateSync = inflateSync;\nexports.inflateSyncPoint = inflateSyncPoint;\nexports.inflateUndermine = inflateUndermine;\n*/\n\n\n/***/ }),\n/* 158 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\n// See state defs from inflate.js\nvar BAD = 30;       /* got a data error -- remain here until reset */\nvar TYPE = 12;      /* i: waiting for type bits, including last-flag bit */\n\n/*\n   Decode literal, length, and distance codes and write out the resulting\n   literal and match bytes until either not enough input or output is\n   available, an end-of-block is encountered, or a data error is encountered.\n   When large enough input and output buffers are supplied to inflate(), for\n   example, a 16K input buffer and a 64K output buffer, more than 95% of the\n   inflate execution time is spent in this routine.\n\n   Entry assumptions:\n\n        state.mode === LEN\n        strm.avail_in >= 6\n        strm.avail_out >= 258\n        start >= strm.avail_out\n        state.bits < 8\n\n   On return, state.mode is one of:\n\n        LEN -- ran out of enough output space or enough available input\n        TYPE -- reached end of block code, inflate() to interpret next block\n        BAD -- error in block data\n\n   Notes:\n\n    - The maximum input bits used by a length/distance pair is 15 bits for the\n      length code, 5 bits for the length extra, 15 bits for the distance code,\n      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.\n      Therefore if strm.avail_in >= 6, then there is enough input to avoid\n      checking for available input while decoding.\n\n    - The maximum bytes that a single length/distance pair can output is 258\n      bytes, which is the maximum length that can be coded.  inflate_fast()\n      requires strm.avail_out >= 258 for each loop to avoid checking for\n      output space.\n */\nmodule.exports = function inflate_fast(strm, start) {\n  var state;\n  var _in;                    /* local strm.input */\n  var last;                   /* have enough input while in < last */\n  var _out;                   /* local strm.output */\n  var beg;                    /* inflate()'s initial strm.output */\n  var end;                    /* while out < end, enough space available */\n//#ifdef INFLATE_STRICT\n  var dmax;                   /* maximum distance from zlib header */\n//#endif\n  var wsize;                  /* window size or zero if not using window */\n  var whave;                  /* valid bytes in the window */\n  var wnext;                  /* window write index */\n  // Use `s_window` instead `window`, avoid conflict with instrumentation tools\n  var s_window;               /* allocated sliding window, if wsize != 0 */\n  var hold;                   /* local strm.hold */\n  var bits;                   /* local strm.bits */\n  var lcode;                  /* local strm.lencode */\n  var dcode;                  /* local strm.distcode */\n  var lmask;                  /* mask for first level of length codes */\n  var dmask;                  /* mask for first level of distance codes */\n  var here;                   /* retrieved table entry */\n  var op;                     /* code bits, operation, extra bits, or */\n                              /*  window position, window bytes to copy */\n  var len;                    /* match length, unused bytes */\n  var dist;                   /* match distance */\n  var from;                   /* where to copy match from */\n  var from_source;\n\n\n  var input, output; // JS specific, because we have no pointers\n\n  /* copy state to local variables */\n  state = strm.state;\n  //here = state.here;\n  _in = strm.next_in;\n  input = strm.input;\n  last = _in + (strm.avail_in - 5);\n  _out = strm.next_out;\n  output = strm.output;\n  beg = _out - (start - strm.avail_out);\n  end = _out + (strm.avail_out - 257);\n//#ifdef INFLATE_STRICT\n  dmax = state.dmax;\n//#endif\n  wsize = state.wsize;\n  whave = state.whave;\n  wnext = state.wnext;\n  s_window = state.window;\n  hold = state.hold;\n  bits = state.bits;\n  lcode = state.lencode;\n  dcode = state.distcode;\n  lmask = (1 << state.lenbits) - 1;\n  dmask = (1 << state.distbits) - 1;\n\n\n  /* decode literals and length/distances until end-of-block or not enough\n     input data or output space */\n\n  top:\n  do {\n    if (bits < 15) {\n      hold += input[_in++] << bits;\n      bits += 8;\n      hold += input[_in++] << bits;\n      bits += 8;\n    }\n\n    here = lcode[hold & lmask];\n\n    dolen:\n    for (;;) { // Goto emulation\n      op = here >>> 24/*here.bits*/;\n      hold >>>= op;\n      bits -= op;\n      op = (here >>> 16) & 0xff/*here.op*/;\n      if (op === 0) {                          /* literal */\n        //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?\n        //        \"inflate:         literal '%c'\\n\" :\n        //        \"inflate:         literal 0x%02x\\n\", here.val));\n        output[_out++] = here & 0xffff/*here.val*/;\n      }\n      else if (op & 16) {                     /* length base */\n        len = here & 0xffff/*here.val*/;\n        op &= 15;                           /* number of extra bits */\n        if (op) {\n          if (bits < op) {\n            hold += input[_in++] << bits;\n            bits += 8;\n          }\n          len += hold & ((1 << op) - 1);\n          hold >>>= op;\n          bits -= op;\n        }\n        //Tracevv((stderr, \"inflate:         length %u\\n\", len));\n        if (bits < 15) {\n          hold += input[_in++] << bits;\n          bits += 8;\n          hold += input[_in++] << bits;\n          bits += 8;\n        }\n        here = dcode[hold & dmask];\n\n        dodist:\n        for (;;) { // goto emulation\n          op = here >>> 24/*here.bits*/;\n          hold >>>= op;\n          bits -= op;\n          op = (here >>> 16) & 0xff/*here.op*/;\n\n          if (op & 16) {                      /* distance base */\n            dist = here & 0xffff/*here.val*/;\n            op &= 15;                       /* number of extra bits */\n            if (bits < op) {\n              hold += input[_in++] << bits;\n              bits += 8;\n              if (bits < op) {\n                hold += input[_in++] << bits;\n                bits += 8;\n              }\n            }\n            dist += hold & ((1 << op) - 1);\n//#ifdef INFLATE_STRICT\n            if (dist > dmax) {\n              strm.msg = 'invalid distance too far back';\n              state.mode = BAD;\n              break top;\n            }\n//#endif\n            hold >>>= op;\n            bits -= op;\n            //Tracevv((stderr, \"inflate:         distance %u\\n\", dist));\n            op = _out - beg;                /* max distance in output */\n            if (dist > op) {                /* see if copy from window */\n              op = dist - op;               /* distance back in window */\n              if (op > whave) {\n                if (state.sane) {\n                  strm.msg = 'invalid distance too far back';\n                  state.mode = BAD;\n                  break top;\n                }\n\n// (!) This block is disabled in zlib defaults,\n// don't enable it for binary compatibility\n//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR\n//                if (len <= op - whave) {\n//                  do {\n//                    output[_out++] = 0;\n//                  } while (--len);\n//                  continue top;\n//                }\n//                len -= op - whave;\n//                do {\n//                  output[_out++] = 0;\n//                } while (--op > whave);\n//                if (op === 0) {\n//                  from = _out - dist;\n//                  do {\n//                    output[_out++] = output[from++];\n//                  } while (--len);\n//                  continue top;\n//                }\n//#endif\n              }\n              from = 0; // window index\n              from_source = s_window;\n              if (wnext === 0) {           /* very common case */\n                from += wsize - op;\n                if (op < len) {         /* some from window */\n                  len -= op;\n                  do {\n                    output[_out++] = s_window[from++];\n                  } while (--op);\n                  from = _out - dist;  /* rest from output */\n                  from_source = output;\n                }\n              }\n              else if (wnext < op) {      /* wrap around window */\n                from += wsize + wnext - op;\n                op -= wnext;\n                if (op < len) {         /* some from end of window */\n                  len -= op;\n                  do {\n                    output[_out++] = s_window[from++];\n                  } while (--op);\n                  from = 0;\n                  if (wnext < len) {  /* some from start of window */\n                    op = wnext;\n                    len -= op;\n                    do {\n                      output[_out++] = s_window[from++];\n                    } while (--op);\n                    from = _out - dist;      /* rest from output */\n                    from_source = output;\n                  }\n                }\n              }\n              else {                      /* contiguous in window */\n                from += wnext - op;\n                if (op < len) {         /* some from window */\n                  len -= op;\n                  do {\n                    output[_out++] = s_window[from++];\n                  } while (--op);\n                  from = _out - dist;  /* rest from output */\n                  from_source = output;\n                }\n              }\n              while (len > 2) {\n                output[_out++] = from_source[from++];\n                output[_out++] = from_source[from++];\n                output[_out++] = from_source[from++];\n                len -= 3;\n              }\n              if (len) {\n                output[_out++] = from_source[from++];\n                if (len > 1) {\n                  output[_out++] = from_source[from++];\n                }\n              }\n            }\n            else {\n              from = _out - dist;          /* copy direct from output */\n              do {                        /* minimum length is three */\n                output[_out++] = output[from++];\n                output[_out++] = output[from++];\n                output[_out++] = output[from++];\n                len -= 3;\n              } while (len > 2);\n              if (len) {\n                output[_out++] = output[from++];\n                if (len > 1) {\n                  output[_out++] = output[from++];\n                }\n              }\n            }\n          }\n          else if ((op & 64) === 0) {          /* 2nd level distance code */\n            here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];\n            continue dodist;\n          }\n          else {\n            strm.msg = 'invalid distance code';\n            state.mode = BAD;\n            break top;\n          }\n\n          break; // need to emulate goto via \"continue\"\n        }\n      }\n      else if ((op & 64) === 0) {              /* 2nd level length code */\n        here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];\n        continue dolen;\n      }\n      else if (op & 32) {                     /* end-of-block */\n        //Tracevv((stderr, \"inflate:         end of block\\n\"));\n        state.mode = TYPE;\n        break top;\n      }\n      else {\n        strm.msg = 'invalid literal/length code';\n        state.mode = BAD;\n        break top;\n      }\n\n      break; // need to emulate goto via \"continue\"\n    }\n  } while (_in < last && _out < end);\n\n  /* return unused bytes (on entry, bits < 8, so in won't go too far back) */\n  len = bits >> 3;\n  _in -= len;\n  bits -= len << 3;\n  hold &= (1 << bits) - 1;\n\n  /* update state and return */\n  strm.next_in = _in;\n  strm.next_out = _out;\n  strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));\n  strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));\n  state.hold = hold;\n  state.bits = bits;\n  return;\n};\n\n\n/***/ }),\n/* 159 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nvar utils = __webpack_require__(34);\n\nvar MAXBITS = 15;\nvar ENOUGH_LENS = 852;\nvar ENOUGH_DISTS = 592;\n//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);\n\nvar CODES = 0;\nvar LENS = 1;\nvar DISTS = 2;\n\nvar lbase = [ /* Length codes 257..285 base */\n  3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,\n  35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0\n];\n\nvar lext = [ /* Length codes 257..285 extra */\n  16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,\n  19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78\n];\n\nvar dbase = [ /* Distance codes 0..29 base */\n  1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,\n  257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,\n  8193, 12289, 16385, 24577, 0, 0\n];\n\nvar dext = [ /* Distance codes 0..29 extra */\n  16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,\n  23, 23, 24, 24, 25, 25, 26, 26, 27, 27,\n  28, 28, 29, 29, 64, 64\n];\n\nmodule.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts)\n{\n  var bits = opts.bits;\n      //here = opts.here; /* table entry for duplication */\n\n  var len = 0;               /* a code's length in bits */\n  var sym = 0;               /* index of code symbols */\n  var min = 0, max = 0;          /* minimum and maximum code lengths */\n  var root = 0;              /* number of index bits for root table */\n  var curr = 0;              /* number of index bits for current table */\n  var drop = 0;              /* code bits to drop for sub-table */\n  var left = 0;                   /* number of prefix codes available */\n  var used = 0;              /* code entries in table used */\n  var huff = 0;              /* Huffman code */\n  var incr;              /* for incrementing code, index */\n  var fill;              /* index for replicating entries */\n  var low;               /* low bits for current root entry */\n  var mask;              /* mask for low root bits */\n  var next;             /* next available space in table */\n  var base = null;     /* base value table to use */\n  var base_index = 0;\n//  var shoextra;    /* extra bits table to use */\n  var end;                    /* use base and extra for symbol > end */\n  var count = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1];    /* number of codes of each length */\n  var offs = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1];     /* offsets in table for each length */\n  var extra = null;\n  var extra_index = 0;\n\n  var here_bits, here_op, here_val;\n\n  /*\n   Process a set of code lengths to create a canonical Huffman code.  The\n   code lengths are lens[0..codes-1].  Each length corresponds to the\n   symbols 0..codes-1.  The Huffman code is generated by first sorting the\n   symbols by length from short to long, and retaining the symbol order\n   for codes with equal lengths.  Then the code starts with all zero bits\n   for the first code of the shortest length, and the codes are integer\n   increments for the same length, and zeros are appended as the length\n   increases.  For the deflate format, these bits are stored backwards\n   from their more natural integer increment ordering, and so when the\n   decoding tables are built in the large loop below, the integer codes\n   are incremented backwards.\n\n   This routine assumes, but does not check, that all of the entries in\n   lens[] are in the range 0..MAXBITS.  The caller must assure this.\n   1..MAXBITS is interpreted as that code length.  zero means that that\n   symbol does not occur in this code.\n\n   The codes are sorted by computing a count of codes for each length,\n   creating from that a table of starting indices for each length in the\n   sorted table, and then entering the symbols in order in the sorted\n   table.  The sorted table is work[], with that space being provided by\n   the caller.\n\n   The length counts are used for other purposes as well, i.e. finding\n   the minimum and maximum length codes, determining if there are any\n   codes at all, checking for a valid set of lengths, and looking ahead\n   at length counts to determine sub-table sizes when building the\n   decoding tables.\n   */\n\n  /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */\n  for (len = 0; len <= MAXBITS; len++) {\n    count[len] = 0;\n  }\n  for (sym = 0; sym < codes; sym++) {\n    count[lens[lens_index + sym]]++;\n  }\n\n  /* bound code lengths, force root to be within code lengths */\n  root = bits;\n  for (max = MAXBITS; max >= 1; max--) {\n    if (count[max] !== 0) { break; }\n  }\n  if (root > max) {\n    root = max;\n  }\n  if (max === 0) {                     /* no symbols to code at all */\n    //table.op[opts.table_index] = 64;  //here.op = (var char)64;    /* invalid code marker */\n    //table.bits[opts.table_index] = 1;   //here.bits = (var char)1;\n    //table.val[opts.table_index++] = 0;   //here.val = (var short)0;\n    table[table_index++] = (1 << 24) | (64 << 16) | 0;\n\n\n    //table.op[opts.table_index] = 64;\n    //table.bits[opts.table_index] = 1;\n    //table.val[opts.table_index++] = 0;\n    table[table_index++] = (1 << 24) | (64 << 16) | 0;\n\n    opts.bits = 1;\n    return 0;     /* no symbols, but wait for decoding to report error */\n  }\n  for (min = 1; min < max; min++) {\n    if (count[min] !== 0) { break; }\n  }\n  if (root < min) {\n    root = min;\n  }\n\n  /* check for an over-subscribed or incomplete set of lengths */\n  left = 1;\n  for (len = 1; len <= MAXBITS; len++) {\n    left <<= 1;\n    left -= count[len];\n    if (left < 0) {\n      return -1;\n    }        /* over-subscribed */\n  }\n  if (left > 0 && (type === CODES || max !== 1)) {\n    return -1;                      /* incomplete set */\n  }\n\n  /* generate offsets into symbol table for each length for sorting */\n  offs[1] = 0;\n  for (len = 1; len < MAXBITS; len++) {\n    offs[len + 1] = offs[len] + count[len];\n  }\n\n  /* sort symbols by length, by symbol order within each length */\n  for (sym = 0; sym < codes; sym++) {\n    if (lens[lens_index + sym] !== 0) {\n      work[offs[lens[lens_index + sym]]++] = sym;\n    }\n  }\n\n  /*\n   Create and fill in decoding tables.  In this loop, the table being\n   filled is at next and has curr index bits.  The code being used is huff\n   with length len.  That code is converted to an index by dropping drop\n   bits off of the bottom.  For codes where len is less than drop + curr,\n   those top drop + curr - len bits are incremented through all values to\n   fill the table with replicated entries.\n\n   root is the number of index bits for the root table.  When len exceeds\n   root, sub-tables are created pointed to by the root entry with an index\n   of the low root bits of huff.  This is saved in low to check for when a\n   new sub-table should be started.  drop is zero when the root table is\n   being filled, and drop is root when sub-tables are being filled.\n\n   When a new sub-table is needed, it is necessary to look ahead in the\n   code lengths to determine what size sub-table is needed.  The length\n   counts are used for this, and so count[] is decremented as codes are\n   entered in the tables.\n\n   used keeps track of how many table entries have been allocated from the\n   provided *table space.  It is checked for LENS and DIST tables against\n   the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in\n   the initial root table size constants.  See the comments in inftrees.h\n   for more information.\n\n   sym increments through all symbols, and the loop terminates when\n   all codes of length max, i.e. all codes, have been processed.  This\n   routine permits incomplete codes, so another loop after this one fills\n   in the rest of the decoding tables with invalid code markers.\n   */\n\n  /* set up for code type */\n  // poor man optimization - use if-else instead of switch,\n  // to avoid deopts in old v8\n  if (type === CODES) {\n    base = extra = work;    /* dummy value--not used */\n    end = 19;\n\n  } else if (type === LENS) {\n    base = lbase;\n    base_index -= 257;\n    extra = lext;\n    extra_index -= 257;\n    end = 256;\n\n  } else {                    /* DISTS */\n    base = dbase;\n    extra = dext;\n    end = -1;\n  }\n\n  /* initialize opts for loop */\n  huff = 0;                   /* starting code */\n  sym = 0;                    /* starting code symbol */\n  len = min;                  /* starting code length */\n  next = table_index;              /* current table to fill in */\n  curr = root;                /* current table index bits */\n  drop = 0;                   /* current bits to drop from code for index */\n  low = -1;                   /* trigger new sub-table when len > root */\n  used = 1 << root;          /* use root table entries */\n  mask = used - 1;            /* mask for comparing low */\n\n  /* check available table space */\n  if ((type === LENS && used > ENOUGH_LENS) ||\n    (type === DISTS && used > ENOUGH_DISTS)) {\n    return 1;\n  }\n\n  /* process all codes and make table entries */\n  for (;;) {\n    /* create table entry */\n    here_bits = len - drop;\n    if (work[sym] < end) {\n      here_op = 0;\n      here_val = work[sym];\n    }\n    else if (work[sym] > end) {\n      here_op = extra[extra_index + work[sym]];\n      here_val = base[base_index + work[sym]];\n    }\n    else {\n      here_op = 32 + 64;         /* end of block */\n      here_val = 0;\n    }\n\n    /* replicate for those indices with low len bits equal to huff */\n    incr = 1 << (len - drop);\n    fill = 1 << curr;\n    min = fill;                 /* save offset to next table */\n    do {\n      fill -= incr;\n      table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;\n    } while (fill !== 0);\n\n    /* backwards increment the len-bit code huff */\n    incr = 1 << (len - 1);\n    while (huff & incr) {\n      incr >>= 1;\n    }\n    if (incr !== 0) {\n      huff &= incr - 1;\n      huff += incr;\n    } else {\n      huff = 0;\n    }\n\n    /* go to next symbol, update count, len */\n    sym++;\n    if (--count[len] === 0) {\n      if (len === max) { break; }\n      len = lens[lens_index + work[sym]];\n    }\n\n    /* create new sub-table if needed */\n    if (len > root && (huff & mask) !== low) {\n      /* if first time, transition to sub-tables */\n      if (drop === 0) {\n        drop = root;\n      }\n\n      /* increment past last table */\n      next += min;            /* here min is 1 << curr */\n\n      /* determine length of next table */\n      curr = len - drop;\n      left = 1 << curr;\n      while (curr + drop < max) {\n        left -= count[curr + drop];\n        if (left <= 0) { break; }\n        curr++;\n        left <<= 1;\n      }\n\n      /* check for enough space */\n      used += 1 << curr;\n      if ((type === LENS && used > ENOUGH_LENS) ||\n        (type === DISTS && used > ENOUGH_DISTS)) {\n        return 1;\n      }\n\n      /* point entry in root table to sub-table */\n      low = huff & mask;\n      /*table.op[low] = curr;\n      table.bits[low] = root;\n      table.val[low] = next - opts.table_index;*/\n      table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;\n    }\n  }\n\n  /* fill in remaining table entry if code is incomplete (guaranteed to have\n   at most one remaining entry, since if the code is incomplete, the\n   maximum code length that was allowed to get this far is one bit) */\n  if (huff !== 0) {\n    //table.op[next + huff] = 64;            /* invalid code marker */\n    //table.bits[next + huff] = len - drop;\n    //table.val[next + huff] = 0;\n    table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;\n  }\n\n  /* set return parameters */\n  //opts.table_index += used;\n  opts.bits = root;\n  return 0;\n};\n\n\n/***/ }),\n/* 160 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nmodule.exports = {\n\n  /* Allowed flush values; see deflate() and inflate() below for details */\n  Z_NO_FLUSH:         0,\n  Z_PARTIAL_FLUSH:    1,\n  Z_SYNC_FLUSH:       2,\n  Z_FULL_FLUSH:       3,\n  Z_FINISH:           4,\n  Z_BLOCK:            5,\n  Z_TREES:            6,\n\n  /* Return codes for the compression/decompression functions. Negative values\n  * are errors, positive values are used for special but normal events.\n  */\n  Z_OK:               0,\n  Z_STREAM_END:       1,\n  Z_NEED_DICT:        2,\n  Z_ERRNO:           -1,\n  Z_STREAM_ERROR:    -2,\n  Z_DATA_ERROR:      -3,\n  //Z_MEM_ERROR:     -4,\n  Z_BUF_ERROR:       -5,\n  //Z_VERSION_ERROR: -6,\n\n  /* compression levels */\n  Z_NO_COMPRESSION:         0,\n  Z_BEST_SPEED:             1,\n  Z_BEST_COMPRESSION:       9,\n  Z_DEFAULT_COMPRESSION:   -1,\n\n\n  Z_FILTERED:               1,\n  Z_HUFFMAN_ONLY:           2,\n  Z_RLE:                    3,\n  Z_FIXED:                  4,\n  Z_DEFAULT_STRATEGY:       0,\n\n  /* Possible values of the data_type field (though see inflate()) */\n  Z_BINARY:                 0,\n  Z_TEXT:                   1,\n  //Z_ASCII:                1, // = Z_TEXT (deprecated)\n  Z_UNKNOWN:                2,\n\n  /* The deflate compression method */\n  Z_DEFLATED:               8\n  //Z_NULL:                 null // Use -1 or null inline, depending on var type\n};\n\n\n/***/ }),\n/* 161 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.12.6\n\n/*\nPDFPage - represents a single page in the PDF document\nBy Devon Govett\n */\n\n(function() {\n  var PDFPage;\n\n  PDFPage = (function() {\n    var DEFAULT_MARGINS, SIZES;\n\n    function PDFPage(document, options) {\n      var dimensions;\n      this.document = document;\n      if (options == null) {\n        options = {};\n      }\n      this.size = options.size || 'letter';\n      this.layout = options.layout || 'portrait';\n      if (typeof options.margin === 'number') {\n        this.margins = {\n          top: options.margin,\n          left: options.margin,\n          bottom: options.margin,\n          right: options.margin\n        };\n      } else {\n        this.margins = options.margins || DEFAULT_MARGINS;\n      }\n      dimensions = Array.isArray(this.size) ? this.size : SIZES[this.size.toUpperCase()];\n      this.width = dimensions[this.layout === 'portrait' ? 0 : 1];\n      this.height = dimensions[this.layout === 'portrait' ? 1 : 0];\n      this.content = this.document.ref();\n      this.resources = this.document.ref({\n        ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI']\n      });\n      Object.defineProperties(this, {\n        fonts: {\n          get: (function(_this) {\n            return function() {\n              var base;\n              return (base = _this.resources.data).Font != null ? base.Font : base.Font = {};\n            };\n          })(this)\n        },\n        xobjects: {\n          get: (function(_this) {\n            return function() {\n              var base;\n              return (base = _this.resources.data).XObject != null ? base.XObject : base.XObject = {};\n            };\n          })(this)\n        },\n        ext_gstates: {\n          get: (function(_this) {\n            return function() {\n              var base;\n              return (base = _this.resources.data).ExtGState != null ? base.ExtGState : base.ExtGState = {};\n            };\n          })(this)\n        },\n        patterns: {\n          get: (function(_this) {\n            return function() {\n              var base;\n              return (base = _this.resources.data).Pattern != null ? base.Pattern : base.Pattern = {};\n            };\n          })(this)\n        },\n        annotations: {\n          get: (function(_this) {\n            return function() {\n              var base;\n              return (base = _this.dictionary.data).Annots != null ? base.Annots : base.Annots = [];\n            };\n          })(this)\n        }\n      });\n      this.dictionary = this.document.ref({\n        Type: 'Page',\n        Parent: this.document._root.data.Pages,\n        MediaBox: [0, 0, this.width, this.height],\n        Contents: this.content,\n        Resources: this.resources\n      });\n    }\n\n    PDFPage.prototype.maxY = function() {\n      return this.height - this.margins.bottom;\n    };\n\n    PDFPage.prototype.write = function(chunk) {\n      return this.content.write(chunk);\n    };\n\n    PDFPage.prototype.end = function() {\n      this.dictionary.end();\n      this.resources.end();\n      return this.content.end();\n    };\n\n    DEFAULT_MARGINS = {\n      top: 72,\n      left: 72,\n      bottom: 72,\n      right: 72\n    };\n\n    SIZES = {\n      '4A0': [4767.87, 6740.79],\n      '2A0': [3370.39, 4767.87],\n      A0: [2383.94, 3370.39],\n      A1: [1683.78, 2383.94],\n      A2: [1190.55, 1683.78],\n      A3: [841.89, 1190.55],\n      A4: [595.28, 841.89],\n      A5: [419.53, 595.28],\n      A6: [297.64, 419.53],\n      A7: [209.76, 297.64],\n      A8: [147.40, 209.76],\n      A9: [104.88, 147.40],\n      A10: [73.70, 104.88],\n      B0: [2834.65, 4008.19],\n      B1: [2004.09, 2834.65],\n      B2: [1417.32, 2004.09],\n      B3: [1000.63, 1417.32],\n      B4: [708.66, 1000.63],\n      B5: [498.90, 708.66],\n      B6: [354.33, 498.90],\n      B7: [249.45, 354.33],\n      B8: [175.75, 249.45],\n      B9: [124.72, 175.75],\n      B10: [87.87, 124.72],\n      C0: [2599.37, 3676.54],\n      C1: [1836.85, 2599.37],\n      C2: [1298.27, 1836.85],\n      C3: [918.43, 1298.27],\n      C4: [649.13, 918.43],\n      C5: [459.21, 649.13],\n      C6: [323.15, 459.21],\n      C7: [229.61, 323.15],\n      C8: [161.57, 229.61],\n      C9: [113.39, 161.57],\n      C10: [79.37, 113.39],\n      RA0: [2437.80, 3458.27],\n      RA1: [1729.13, 2437.80],\n      RA2: [1218.90, 1729.13],\n      RA3: [864.57, 1218.90],\n      RA4: [609.45, 864.57],\n      SRA0: [2551.18, 3628.35],\n      SRA1: [1814.17, 2551.18],\n      SRA2: [1275.59, 1814.17],\n      SRA3: [907.09, 1275.59],\n      SRA4: [637.80, 907.09],\n      EXECUTIVE: [521.86, 756.00],\n      FOLIO: [612.00, 936.00],\n      LEGAL: [612.00, 1008.00],\n      LETTER: [612.00, 792.00],\n      TABLOID: [792.00, 1224.00]\n    };\n\n    return PDFPage;\n\n  })();\n\n  module.exports = PDFPage;\n\n}).call(this);\n\n\n/***/ }),\n/* 162 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var PDFGradient, PDFLinearGradient, PDFRadialGradient, namedColors, ref;\n\n  ref = __webpack_require__(163), PDFGradient = ref.PDFGradient, PDFLinearGradient = ref.PDFLinearGradient, PDFRadialGradient = ref.PDFRadialGradient;\n\n  module.exports = {\n    initColor: function() {\n      this._opacityRegistry = {};\n      this._opacityCount = 0;\n      return this._gradCount = 0;\n    },\n    _normalizeColor: function(color) {\n      var hex, part;\n      if (color instanceof PDFGradient) {\n        return color;\n      }\n      if (typeof color === 'string') {\n        if (color.charAt(0) === '#') {\n          if (color.length === 4) {\n            color = color.replace(/#([0-9A-F])([0-9A-F])([0-9A-F])/i, \"#$1$1$2$2$3$3\");\n          }\n          hex = parseInt(color.slice(1), 16);\n          color = [hex >> 16, hex >> 8 & 0xff, hex & 0xff];\n        } else if (namedColors[color]) {\n          color = namedColors[color];\n        }\n      }\n      if (Array.isArray(color)) {\n        if (color.length === 3) {\n          color = (function() {\n            var i, len, results;\n            results = [];\n            for (i = 0, len = color.length; i < len; i++) {\n              part = color[i];\n              results.push(part / 255);\n            }\n            return results;\n          })();\n        } else if (color.length === 4) {\n          color = (function() {\n            var i, len, results;\n            results = [];\n            for (i = 0, len = color.length; i < len; i++) {\n              part = color[i];\n              results.push(part / 100);\n            }\n            return results;\n          })();\n        }\n        return color;\n      }\n      return null;\n    },\n    _setColor: function(color, stroke) {\n      var op, space;\n      color = this._normalizeColor(color);\n      if (!color) {\n        return false;\n      }\n      op = stroke ? 'SCN' : 'scn';\n      if (color instanceof PDFGradient) {\n        this._setColorSpace('Pattern', stroke);\n        color.apply(op);\n      } else {\n        space = color.length === 4 ? 'DeviceCMYK' : 'DeviceRGB';\n        this._setColorSpace(space, stroke);\n        color = color.join(' ');\n        this.addContent(color + \" \" + op);\n      }\n      return true;\n    },\n    _setColorSpace: function(space, stroke) {\n      var op;\n      op = stroke ? 'CS' : 'cs';\n      return this.addContent(\"/\" + space + \" \" + op);\n    },\n    fillColor: function(color, opacity) {\n      var set;\n      set = this._setColor(color, false);\n      if (set) {\n        this.fillOpacity(opacity);\n      }\n      this._fillColor = [color, opacity];\n      return this;\n    },\n    strokeColor: function(color, opacity) {\n      var set;\n      set = this._setColor(color, true);\n      if (set) {\n        this.strokeOpacity(opacity);\n      }\n      return this;\n    },\n    opacity: function(opacity) {\n      this._doOpacity(opacity, opacity);\n      return this;\n    },\n    fillOpacity: function(opacity) {\n      this._doOpacity(opacity, null);\n      return this;\n    },\n    strokeOpacity: function(opacity) {\n      this._doOpacity(null, opacity);\n      return this;\n    },\n    _doOpacity: function(fillOpacity, strokeOpacity) {\n      var dictionary, id, key, name, ref1;\n      if (!((fillOpacity != null) || (strokeOpacity != null))) {\n        return;\n      }\n      if (fillOpacity != null) {\n        fillOpacity = Math.max(0, Math.min(1, fillOpacity));\n      }\n      if (strokeOpacity != null) {\n        strokeOpacity = Math.max(0, Math.min(1, strokeOpacity));\n      }\n      key = fillOpacity + \"_\" + strokeOpacity;\n      if (this._opacityRegistry[key]) {\n        ref1 = this._opacityRegistry[key], dictionary = ref1[0], name = ref1[1];\n      } else {\n        dictionary = {\n          Type: 'ExtGState'\n        };\n        if (fillOpacity != null) {\n          dictionary.ca = fillOpacity;\n        }\n        if (strokeOpacity != null) {\n          dictionary.CA = strokeOpacity;\n        }\n        dictionary = this.ref(dictionary);\n        dictionary.end();\n        id = ++this._opacityCount;\n        name = \"Gs\" + id;\n        this._opacityRegistry[key] = [dictionary, name];\n      }\n      this.page.ext_gstates[name] = dictionary;\n      return this.addContent(\"/\" + name + \" gs\");\n    },\n    linearGradient: function(x1, y1, x2, y2) {\n      return new PDFLinearGradient(this, x1, y1, x2, y2);\n    },\n    radialGradient: function(x1, y1, r1, x2, y2, r2) {\n      return new PDFRadialGradient(this, x1, y1, r1, x2, y2, r2);\n    }\n  };\n\n  namedColors = {\n    aliceblue: [240, 248, 255],\n    antiquewhite: [250, 235, 215],\n    aqua: [0, 255, 255],\n    aquamarine: [127, 255, 212],\n    azure: [240, 255, 255],\n    beige: [245, 245, 220],\n    bisque: [255, 228, 196],\n    black: [0, 0, 0],\n    blanchedalmond: [255, 235, 205],\n    blue: [0, 0, 255],\n    blueviolet: [138, 43, 226],\n    brown: [165, 42, 42],\n    burlywood: [222, 184, 135],\n    cadetblue: [95, 158, 160],\n    chartreuse: [127, 255, 0],\n    chocolate: [210, 105, 30],\n    coral: [255, 127, 80],\n    cornflowerblue: [100, 149, 237],\n    cornsilk: [255, 248, 220],\n    crimson: [220, 20, 60],\n    cyan: [0, 255, 255],\n    darkblue: [0, 0, 139],\n    darkcyan: [0, 139, 139],\n    darkgoldenrod: [184, 134, 11],\n    darkgray: [169, 169, 169],\n    darkgreen: [0, 100, 0],\n    darkgrey: [169, 169, 169],\n    darkkhaki: [189, 183, 107],\n    darkmagenta: [139, 0, 139],\n    darkolivegreen: [85, 107, 47],\n    darkorange: [255, 140, 0],\n    darkorchid: [153, 50, 204],\n    darkred: [139, 0, 0],\n    darksalmon: [233, 150, 122],\n    darkseagreen: [143, 188, 143],\n    darkslateblue: [72, 61, 139],\n    darkslategray: [47, 79, 79],\n    darkslategrey: [47, 79, 79],\n    darkturquoise: [0, 206, 209],\n    darkviolet: [148, 0, 211],\n    deeppink: [255, 20, 147],\n    deepskyblue: [0, 191, 255],\n    dimgray: [105, 105, 105],\n    dimgrey: [105, 105, 105],\n    dodgerblue: [30, 144, 255],\n    firebrick: [178, 34, 34],\n    floralwhite: [255, 250, 240],\n    forestgreen: [34, 139, 34],\n    fuchsia: [255, 0, 255],\n    gainsboro: [220, 220, 220],\n    ghostwhite: [248, 248, 255],\n    gold: [255, 215, 0],\n    goldenrod: [218, 165, 32],\n    gray: [128, 128, 128],\n    grey: [128, 128, 128],\n    green: [0, 128, 0],\n    greenyellow: [173, 255, 47],\n    honeydew: [240, 255, 240],\n    hotpink: [255, 105, 180],\n    indianred: [205, 92, 92],\n    indigo: [75, 0, 130],\n    ivory: [255, 255, 240],\n    khaki: [240, 230, 140],\n    lavender: [230, 230, 250],\n    lavenderblush: [255, 240, 245],\n    lawngreen: [124, 252, 0],\n    lemonchiffon: [255, 250, 205],\n    lightblue: [173, 216, 230],\n    lightcoral: [240, 128, 128],\n    lightcyan: [224, 255, 255],\n    lightgoldenrodyellow: [250, 250, 210],\n    lightgray: [211, 211, 211],\n    lightgreen: [144, 238, 144],\n    lightgrey: [211, 211, 211],\n    lightpink: [255, 182, 193],\n    lightsalmon: [255, 160, 122],\n    lightseagreen: [32, 178, 170],\n    lightskyblue: [135, 206, 250],\n    lightslategray: [119, 136, 153],\n    lightslategrey: [119, 136, 153],\n    lightsteelblue: [176, 196, 222],\n    lightyellow: [255, 255, 224],\n    lime: [0, 255, 0],\n    limegreen: [50, 205, 50],\n    linen: [250, 240, 230],\n    magenta: [255, 0, 255],\n    maroon: [128, 0, 0],\n    mediumaquamarine: [102, 205, 170],\n    mediumblue: [0, 0, 205],\n    mediumorchid: [186, 85, 211],\n    mediumpurple: [147, 112, 219],\n    mediumseagreen: [60, 179, 113],\n    mediumslateblue: [123, 104, 238],\n    mediumspringgreen: [0, 250, 154],\n    mediumturquoise: [72, 209, 204],\n    mediumvioletred: [199, 21, 133],\n    midnightblue: [25, 25, 112],\n    mintcream: [245, 255, 250],\n    mistyrose: [255, 228, 225],\n    moccasin: [255, 228, 181],\n    navajowhite: [255, 222, 173],\n    navy: [0, 0, 128],\n    oldlace: [253, 245, 230],\n    olive: [128, 128, 0],\n    olivedrab: [107, 142, 35],\n    orange: [255, 165, 0],\n    orangered: [255, 69, 0],\n    orchid: [218, 112, 214],\n    palegoldenrod: [238, 232, 170],\n    palegreen: [152, 251, 152],\n    paleturquoise: [175, 238, 238],\n    palevioletred: [219, 112, 147],\n    papayawhip: [255, 239, 213],\n    peachpuff: [255, 218, 185],\n    peru: [205, 133, 63],\n    pink: [255, 192, 203],\n    plum: [221, 160, 221],\n    powderblue: [176, 224, 230],\n    purple: [128, 0, 128],\n    red: [255, 0, 0],\n    rosybrown: [188, 143, 143],\n    royalblue: [65, 105, 225],\n    saddlebrown: [139, 69, 19],\n    salmon: [250, 128, 114],\n    sandybrown: [244, 164, 96],\n    seagreen: [46, 139, 87],\n    seashell: [255, 245, 238],\n    sienna: [160, 82, 45],\n    silver: [192, 192, 192],\n    skyblue: [135, 206, 235],\n    slateblue: [106, 90, 205],\n    slategray: [112, 128, 144],\n    slategrey: [112, 128, 144],\n    snow: [255, 250, 250],\n    springgreen: [0, 255, 127],\n    steelblue: [70, 130, 180],\n    tan: [210, 180, 140],\n    teal: [0, 128, 128],\n    thistle: [216, 191, 216],\n    tomato: [255, 99, 71],\n    turquoise: [64, 224, 208],\n    violet: [238, 130, 238],\n    wheat: [245, 222, 179],\n    white: [255, 255, 255],\n    whitesmoke: [245, 245, 245],\n    yellow: [255, 255, 0],\n    yellowgreen: [154, 205, 50]\n  };\n\n}).call(this);\n\n\n/***/ }),\n/* 163 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var PDFGradient, PDFLinearGradient, PDFRadialGradient,\n    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n    hasProp = {}.hasOwnProperty;\n\n  PDFGradient = (function() {\n    function PDFGradient(doc) {\n      this.doc = doc;\n      this.stops = [];\n      this.embedded = false;\n      this.transform = [1, 0, 0, 1, 0, 0];\n      this._colorSpace = 'DeviceRGB';\n    }\n\n    PDFGradient.prototype.stop = function(pos, color, opacity) {\n      if (opacity == null) {\n        opacity = 1;\n      }\n      opacity = Math.max(0, Math.min(1, opacity));\n      this.stops.push([pos, this.doc._normalizeColor(color), opacity]);\n      return this;\n    };\n\n    PDFGradient.prototype.setTransform = function(m11, m12, m21, m22, dx, dy) {\n      this.transform = [m11, m12, m21, m22, dx, dy];\n      return this;\n    };\n\n    PDFGradient.prototype.embed = function(m) {\n      var bounds, encode, fn, form, grad, gstate, i, j, k, last, len, opacityPattern, pageBBox, pattern, ref, ref1, shader, stop, stops, v;\n      if (this.stops.length === 0) {\n        return;\n      }\n      this.embedded = true;\n      this.matrix = m;\n      last = this.stops[this.stops.length - 1];\n      if (last[0] < 1) {\n        this.stops.push([1, last[1], last[2]]);\n      }\n      bounds = [];\n      encode = [];\n      stops = [];\n      for (i = j = 0, ref = this.stops.length - 1; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {\n        encode.push(0, 1);\n        if (i + 2 !== this.stops.length) {\n          bounds.push(this.stops[i + 1][0]);\n        }\n        fn = this.doc.ref({\n          FunctionType: 2,\n          Domain: [0, 1],\n          C0: this.stops[i + 0][1],\n          C1: this.stops[i + 1][1],\n          N: 1\n        });\n        stops.push(fn);\n        fn.end();\n      }\n      if (stops.length === 1) {\n        fn = stops[0];\n      } else {\n        fn = this.doc.ref({\n          FunctionType: 3,\n          Domain: [0, 1],\n          Functions: stops,\n          Bounds: bounds,\n          Encode: encode\n        });\n        fn.end();\n      }\n      this.id = 'Sh' + (++this.doc._gradCount);\n      shader = this.shader(fn);\n      shader.end();\n      pattern = this.doc.ref({\n        Type: 'Pattern',\n        PatternType: 2,\n        Shading: shader,\n        Matrix: (function() {\n          var k, len, ref1, results;\n          ref1 = this.matrix;\n          results = [];\n          for (k = 0, len = ref1.length; k < len; k++) {\n            v = ref1[k];\n            results.push(+v.toFixed(5));\n          }\n          return results;\n        }).call(this)\n      });\n      pattern.end();\n      if (this.stops.some(function(stop) {\n        return stop[2] < 1;\n      })) {\n        grad = this.opacityGradient();\n        grad._colorSpace = 'DeviceGray';\n        ref1 = this.stops;\n        for (k = 0, len = ref1.length; k < len; k++) {\n          stop = ref1[k];\n          grad.stop(stop[0], [stop[2]]);\n        }\n        grad = grad.embed(this.matrix);\n        pageBBox = [0, 0, this.doc.page.width, this.doc.page.height];\n        form = this.doc.ref({\n          Type: 'XObject',\n          Subtype: 'Form',\n          FormType: 1,\n          BBox: pageBBox,\n          Group: {\n            Type: 'Group',\n            S: 'Transparency',\n            CS: 'DeviceGray'\n          },\n          Resources: {\n            ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'],\n            Pattern: {\n              Sh1: grad\n            }\n          }\n        });\n        form.write(\"/Pattern cs /Sh1 scn\");\n        form.end((pageBBox.join(\" \")) + \" re f\");\n        gstate = this.doc.ref({\n          Type: 'ExtGState',\n          SMask: {\n            Type: 'Mask',\n            S: 'Luminosity',\n            G: form\n          }\n        });\n        gstate.end();\n        opacityPattern = this.doc.ref({\n          Type: 'Pattern',\n          PatternType: 1,\n          PaintType: 1,\n          TilingType: 2,\n          BBox: pageBBox,\n          XStep: pageBBox[2],\n          YStep: pageBBox[3],\n          Resources: {\n            ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'],\n            Pattern: {\n              Sh1: pattern\n            },\n            ExtGState: {\n              Gs1: gstate\n            }\n          }\n        });\n        opacityPattern.write(\"/Gs1 gs /Pattern cs /Sh1 scn\");\n        opacityPattern.end((pageBBox.join(\" \")) + \" re f\");\n        this.doc.page.patterns[this.id] = opacityPattern;\n      } else {\n        this.doc.page.patterns[this.id] = pattern;\n      }\n      return pattern;\n    };\n\n    PDFGradient.prototype.apply = function(op) {\n      var dx, dy, m, m0, m1, m11, m12, m2, m21, m22, m3, m4, m5, ref, ref1;\n      ref = this.doc._ctm.slice(), m0 = ref[0], m1 = ref[1], m2 = ref[2], m3 = ref[3], m4 = ref[4], m5 = ref[5];\n      ref1 = this.transform, m11 = ref1[0], m12 = ref1[1], m21 = ref1[2], m22 = ref1[3], dx = ref1[4], dy = ref1[5];\n      m = [m0 * m11 + m2 * m12, m1 * m11 + m3 * m12, m0 * m21 + m2 * m22, m1 * m21 + m3 * m22, m0 * dx + m2 * dy + m4, m1 * dx + m3 * dy + m5];\n      if (!(this.embedded && m.join(\" \") === this.matrix.join(\" \"))) {\n        this.embed(m);\n      }\n      return this.doc.addContent(\"/\" + this.id + \" \" + op);\n    };\n\n    return PDFGradient;\n\n  })();\n\n  PDFLinearGradient = (function(superClass) {\n    extend(PDFLinearGradient, superClass);\n\n    function PDFLinearGradient(doc, x1, y1, x2, y2) {\n      this.doc = doc;\n      this.x1 = x1;\n      this.y1 = y1;\n      this.x2 = x2;\n      this.y2 = y2;\n      PDFLinearGradient.__super__.constructor.apply(this, arguments);\n    }\n\n    PDFLinearGradient.prototype.shader = function(fn) {\n      return this.doc.ref({\n        ShadingType: 2,\n        ColorSpace: this._colorSpace,\n        Coords: [this.x1, this.y1, this.x2, this.y2],\n        Function: fn,\n        Extend: [true, true]\n      });\n    };\n\n    PDFLinearGradient.prototype.opacityGradient = function() {\n      return new PDFLinearGradient(this.doc, this.x1, this.y1, this.x2, this.y2);\n    };\n\n    return PDFLinearGradient;\n\n  })(PDFGradient);\n\n  PDFRadialGradient = (function(superClass) {\n    extend(PDFRadialGradient, superClass);\n\n    function PDFRadialGradient(doc, x1, y1, r1, x2, y2, r2) {\n      this.doc = doc;\n      this.x1 = x1;\n      this.y1 = y1;\n      this.r1 = r1;\n      this.x2 = x2;\n      this.y2 = y2;\n      this.r2 = r2;\n      PDFRadialGradient.__super__.constructor.apply(this, arguments);\n    }\n\n    PDFRadialGradient.prototype.shader = function(fn) {\n      return this.doc.ref({\n        ShadingType: 3,\n        ColorSpace: this._colorSpace,\n        Coords: [this.x1, this.y1, this.r1, this.x2, this.y2, this.r2],\n        Function: fn,\n        Extend: [true, true]\n      });\n    };\n\n    PDFRadialGradient.prototype.opacityGradient = function() {\n      return new PDFRadialGradient(this.doc, this.x1, this.y1, this.r1, this.x2, this.y2, this.r2);\n    };\n\n    return PDFRadialGradient;\n\n  })(PDFGradient);\n\n  module.exports = {\n    PDFGradient: PDFGradient,\n    PDFLinearGradient: PDFLinearGradient,\n    PDFRadialGradient: PDFRadialGradient\n  };\n\n}).call(this);\n\n\n/***/ }),\n/* 164 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var KAPPA, SVGPath, number,\n    slice = [].slice;\n\n  SVGPath = __webpack_require__(165);\n\n  number = __webpack_require__(26).number;\n\n  KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0);\n\n  module.exports = {\n    initVector: function() {\n      this._ctm = [1, 0, 0, 1, 0, 0];\n      return this._ctmStack = [];\n    },\n    save: function() {\n      this._ctmStack.push(this._ctm.slice());\n      return this.addContent('q');\n    },\n    restore: function() {\n      this._ctm = this._ctmStack.pop() || [1, 0, 0, 1, 0, 0];\n      return this.addContent('Q');\n    },\n    closePath: function() {\n      return this.addContent('h');\n    },\n    lineWidth: function(w) {\n      return this.addContent((number(w)) + \" w\");\n    },\n    _CAP_STYLES: {\n      BUTT: 0,\n      ROUND: 1,\n      SQUARE: 2\n    },\n    lineCap: function(c) {\n      if (typeof c === 'string') {\n        c = this._CAP_STYLES[c.toUpperCase()];\n      }\n      return this.addContent(c + \" J\");\n    },\n    _JOIN_STYLES: {\n      MITER: 0,\n      ROUND: 1,\n      BEVEL: 2\n    },\n    lineJoin: function(j) {\n      if (typeof j === 'string') {\n        j = this._JOIN_STYLES[j.toUpperCase()];\n      }\n      return this.addContent(j + \" j\");\n    },\n    miterLimit: function(m) {\n      return this.addContent((number(m)) + \" M\");\n    },\n    dash: function(length, options) {\n      var phase, ref, space, v;\n      if (options == null) {\n        options = {};\n      }\n      if (length == null) {\n        return this;\n      }\n      if (Array.isArray(length)) {\n        length = ((function() {\n          var i, len, results;\n          results = [];\n          for (i = 0, len = length.length; i < len; i++) {\n            v = length[i];\n            results.push(number(v));\n          }\n          return results;\n        })()).join(' ');\n        phase = options.phase || 0;\n        return this.addContent(\"[\" + length + \"] \" + (number(phase)) + \" d\");\n      } else {\n        space = (ref = options.space) != null ? ref : length;\n        phase = options.phase || 0;\n        return this.addContent(\"[\" + (number(length)) + \" \" + (number(space)) + \"] \" + (number(phase)) + \" d\");\n      }\n    },\n    undash: function() {\n      return this.addContent(\"[] 0 d\");\n    },\n    moveTo: function(x, y) {\n      return this.addContent((number(x)) + \" \" + (number(y)) + \" m\");\n    },\n    lineTo: function(x, y) {\n      return this.addContent((number(x)) + \" \" + (number(y)) + \" l\");\n    },\n    bezierCurveTo: function(cp1x, cp1y, cp2x, cp2y, x, y) {\n      return this.addContent((number(cp1x)) + \" \" + (number(cp1y)) + \" \" + (number(cp2x)) + \" \" + (number(cp2y)) + \" \" + (number(x)) + \" \" + (number(y)) + \" c\");\n    },\n    quadraticCurveTo: function(cpx, cpy, x, y) {\n      return this.addContent((number(cpx)) + \" \" + (number(cpy)) + \" \" + (number(x)) + \" \" + (number(y)) + \" v\");\n    },\n    rect: function(x, y, w, h) {\n      return this.addContent((number(x)) + \" \" + (number(y)) + \" \" + (number(w)) + \" \" + (number(h)) + \" re\");\n    },\n    roundedRect: function(x, y, w, h, r) {\n      var c;\n      if (r == null) {\n        r = 0;\n      }\n      r = Math.min(r, 0.5 * w, 0.5 * h);\n      c = r * (1.0 - KAPPA);\n      this.moveTo(x + r, y);\n      this.lineTo(x + w - r, y);\n      this.bezierCurveTo(x + w - c, y, x + w, y + c, x + w, y + r);\n      this.lineTo(x + w, y + h - r);\n      this.bezierCurveTo(x + w, y + h - c, x + w - c, y + h, x + w - r, y + h);\n      this.lineTo(x + r, y + h);\n      this.bezierCurveTo(x + c, y + h, x, y + h - c, x, y + h - r);\n      this.lineTo(x, y + r);\n      this.bezierCurveTo(x, y + c, x + c, y, x + r, y);\n      return this.closePath();\n    },\n    ellipse: function(x, y, r1, r2) {\n      var ox, oy, xe, xm, ye, ym;\n      if (r2 == null) {\n        r2 = r1;\n      }\n      x -= r1;\n      y -= r2;\n      ox = r1 * KAPPA;\n      oy = r2 * KAPPA;\n      xe = x + r1 * 2;\n      ye = y + r2 * 2;\n      xm = x + r1;\n      ym = y + r2;\n      this.moveTo(x, ym);\n      this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);\n      this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);\n      this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);\n      this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);\n      return this.closePath();\n    },\n    circle: function(x, y, radius) {\n      return this.ellipse(x, y, radius);\n    },\n    arc: function(x, y, radius, startAngle, endAngle, anticlockwise) {\n      var HALF_PI, TWO_PI, ax, ay, cp1x, cp1y, cp2x, cp2y, curAng, deltaAng, deltaCx, deltaCy, dir, handleLen, i, numSegs, ref, segAng, segIdx;\n      if (anticlockwise == null) {\n        anticlockwise = false;\n      }\n      TWO_PI = 2.0 * Math.PI;\n      HALF_PI = 0.5 * Math.PI;\n      deltaAng = endAngle - startAngle;\n      if (Math.abs(deltaAng) > TWO_PI) {\n        deltaAng = TWO_PI;\n      } else if (deltaAng !== 0 && anticlockwise !== (deltaAng < 0)) {\n        dir = anticlockwise ? -1 : 1;\n        deltaAng = dir * TWO_PI + deltaAng;\n      }\n      numSegs = Math.ceil(Math.abs(deltaAng) / HALF_PI);\n      segAng = deltaAng / numSegs;\n      handleLen = (segAng / HALF_PI) * KAPPA * radius;\n      curAng = startAngle;\n      deltaCx = -Math.sin(curAng) * handleLen;\n      deltaCy = Math.cos(curAng) * handleLen;\n      ax = x + Math.cos(curAng) * radius;\n      ay = y + Math.sin(curAng) * radius;\n      this.moveTo(ax, ay);\n      for (segIdx = i = 0, ref = numSegs; 0 <= ref ? i < ref : i > ref; segIdx = 0 <= ref ? ++i : --i) {\n        cp1x = ax + deltaCx;\n        cp1y = ay + deltaCy;\n        curAng += segAng;\n        ax = x + Math.cos(curAng) * radius;\n        ay = y + Math.sin(curAng) * radius;\n        deltaCx = -Math.sin(curAng) * handleLen;\n        deltaCy = Math.cos(curAng) * handleLen;\n        cp2x = ax - deltaCx;\n        cp2y = ay - deltaCy;\n        this.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, ax, ay);\n      }\n      return this;\n    },\n    polygon: function() {\n      var i, len, point, points;\n      points = 1 <= arguments.length ? slice.call(arguments, 0) : [];\n      this.moveTo.apply(this, points.shift());\n      for (i = 0, len = points.length; i < len; i++) {\n        point = points[i];\n        this.lineTo.apply(this, point);\n      }\n      return this.closePath();\n    },\n    path: function(path) {\n      SVGPath.apply(this, path);\n      return this;\n    },\n    _windingRule: function(rule) {\n      if (/even-?odd/.test(rule)) {\n        return '*';\n      }\n      return '';\n    },\n    fill: function(color, rule) {\n      if (/(even-?odd)|(non-?zero)/.test(color)) {\n        rule = color;\n        color = null;\n      }\n      if (color) {\n        this.fillColor(color);\n      }\n      return this.addContent('f' + this._windingRule(rule));\n    },\n    stroke: function(color) {\n      if (color) {\n        this.strokeColor(color);\n      }\n      return this.addContent('S');\n    },\n    fillAndStroke: function(fillColor, strokeColor, rule) {\n      var isFillRule;\n      if (strokeColor == null) {\n        strokeColor = fillColor;\n      }\n      isFillRule = /(even-?odd)|(non-?zero)/;\n      if (isFillRule.test(fillColor)) {\n        rule = fillColor;\n        fillColor = null;\n      }\n      if (isFillRule.test(strokeColor)) {\n        rule = strokeColor;\n        strokeColor = fillColor;\n      }\n      if (fillColor) {\n        this.fillColor(fillColor);\n        this.strokeColor(strokeColor);\n      }\n      return this.addContent('B' + this._windingRule(rule));\n    },\n    clip: function(rule) {\n      return this.addContent('W' + this._windingRule(rule) + ' n');\n    },\n    transform: function(m11, m12, m21, m22, dx, dy) {\n      var m, m0, m1, m2, m3, m4, m5, v, values;\n      m = this._ctm;\n      m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3], m4 = m[4], m5 = m[5];\n      m[0] = m0 * m11 + m2 * m12;\n      m[1] = m1 * m11 + m3 * m12;\n      m[2] = m0 * m21 + m2 * m22;\n      m[3] = m1 * m21 + m3 * m22;\n      m[4] = m0 * dx + m2 * dy + m4;\n      m[5] = m1 * dx + m3 * dy + m5;\n      values = ((function() {\n        var i, len, ref, results;\n        ref = [m11, m12, m21, m22, dx, dy];\n        results = [];\n        for (i = 0, len = ref.length; i < len; i++) {\n          v = ref[i];\n          results.push(number(v));\n        }\n        return results;\n      })()).join(' ');\n      return this.addContent(values + \" cm\");\n    },\n    translate: function(x, y) {\n      return this.transform(1, 0, 0, 1, x, y);\n    },\n    rotate: function(angle, options) {\n      var cos, rad, ref, sin, x, x1, y, y1;\n      if (options == null) {\n        options = {};\n      }\n      rad = angle * Math.PI / 180;\n      cos = Math.cos(rad);\n      sin = Math.sin(rad);\n      x = y = 0;\n      if (options.origin != null) {\n        ref = options.origin, x = ref[0], y = ref[1];\n        x1 = x * cos - y * sin;\n        y1 = x * sin + y * cos;\n        x -= x1;\n        y -= y1;\n      }\n      return this.transform(cos, sin, -sin, cos, x, y);\n    },\n    scale: function(xFactor, yFactor, options) {\n      var ref, x, y;\n      if (yFactor == null) {\n        yFactor = xFactor;\n      }\n      if (options == null) {\n        options = {};\n      }\n      if (typeof yFactor === \"object\") {\n        options = yFactor;\n        yFactor = xFactor;\n      }\n      x = y = 0;\n      if (options.origin != null) {\n        ref = options.origin, x = ref[0], y = ref[1];\n        x -= xFactor * x;\n        y -= yFactor * y;\n      }\n      return this.transform(xFactor, 0, 0, yFactor, x, y);\n    }\n  };\n\n}).call(this);\n\n\n/***/ }),\n/* 165 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var SVGPath;\n\n  SVGPath = (function() {\n    var apply, arcToSegments, cx, cy, parameters, parse, px, py, runners, segmentToBezier, solveArc, sx, sy;\n\n    function SVGPath() {}\n\n    SVGPath.apply = function(doc, path) {\n      var commands;\n      commands = parse(path);\n      return apply(commands, doc);\n    };\n\n    parameters = {\n      A: 7,\n      a: 7,\n      C: 6,\n      c: 6,\n      H: 1,\n      h: 1,\n      L: 2,\n      l: 2,\n      M: 2,\n      m: 2,\n      Q: 4,\n      q: 4,\n      S: 4,\n      s: 4,\n      T: 2,\n      t: 2,\n      V: 1,\n      v: 1,\n      Z: 0,\n      z: 0\n    };\n\n    parse = function(path) {\n      var args, c, cmd, curArg, foundDecimal, j, len, params, ret;\n      ret = [];\n      args = [];\n      curArg = \"\";\n      foundDecimal = false;\n      params = 0;\n      for (j = 0, len = path.length; j < len; j++) {\n        c = path[j];\n        if (parameters[c] != null) {\n          params = parameters[c];\n          if (cmd) {\n            if (curArg.length > 0) {\n              args[args.length] = +curArg;\n            }\n            ret[ret.length] = {\n              cmd: cmd,\n              args: args\n            };\n            args = [];\n            curArg = \"\";\n            foundDecimal = false;\n          }\n          cmd = c;\n        } else if ((c === \" \" || c === \",\") || (c === \"-\" && curArg.length > 0 && curArg[curArg.length - 1] !== 'e') || (c === \".\" && foundDecimal)) {\n          if (curArg.length === 0) {\n            continue;\n          }\n          if (args.length === params) {\n            ret[ret.length] = {\n              cmd: cmd,\n              args: args\n            };\n            args = [+curArg];\n            if (cmd === \"M\") {\n              cmd = \"L\";\n            }\n            if (cmd === \"m\") {\n              cmd = \"l\";\n            }\n          } else {\n            args[args.length] = +curArg;\n          }\n          foundDecimal = c === \".\";\n          curArg = c === '-' || c === '.' ? c : '';\n        } else {\n          curArg += c;\n          if (c === '.') {\n            foundDecimal = true;\n          }\n        }\n      }\n      if (curArg.length > 0) {\n        if (args.length === params) {\n          ret[ret.length] = {\n            cmd: cmd,\n            args: args\n          };\n          args = [+curArg];\n          if (cmd === \"M\") {\n            cmd = \"L\";\n          }\n          if (cmd === \"m\") {\n            cmd = \"l\";\n          }\n        } else {\n          args[args.length] = +curArg;\n        }\n      }\n      ret[ret.length] = {\n        cmd: cmd,\n        args: args\n      };\n      return ret;\n    };\n\n    cx = cy = px = py = sx = sy = 0;\n\n    apply = function(commands, doc) {\n      var c, i, j, len, name;\n      cx = cy = px = py = sx = sy = 0;\n      for (i = j = 0, len = commands.length; j < len; i = ++j) {\n        c = commands[i];\n        if (typeof runners[name = c.cmd] === \"function\") {\n          runners[name](doc, c.args);\n        }\n      }\n      return cx = cy = px = py = 0;\n    };\n\n    runners = {\n      M: function(doc, a) {\n        cx = a[0];\n        cy = a[1];\n        px = py = null;\n        sx = cx;\n        sy = cy;\n        return doc.moveTo(cx, cy);\n      },\n      m: function(doc, a) {\n        cx += a[0];\n        cy += a[1];\n        px = py = null;\n        sx = cx;\n        sy = cy;\n        return doc.moveTo(cx, cy);\n      },\n      C: function(doc, a) {\n        cx = a[4];\n        cy = a[5];\n        px = a[2];\n        py = a[3];\n        return doc.bezierCurveTo.apply(doc, a);\n      },\n      c: function(doc, a) {\n        doc.bezierCurveTo(a[0] + cx, a[1] + cy, a[2] + cx, a[3] + cy, a[4] + cx, a[5] + cy);\n        px = cx + a[2];\n        py = cy + a[3];\n        cx += a[4];\n        return cy += a[5];\n      },\n      S: function(doc, a) {\n        if (px === null) {\n          px = cx;\n          py = cy;\n        }\n        doc.bezierCurveTo(cx - (px - cx), cy - (py - cy), a[0], a[1], a[2], a[3]);\n        px = a[0];\n        py = a[1];\n        cx = a[2];\n        return cy = a[3];\n      },\n      s: function(doc, a) {\n        if (px === null) {\n          px = cx;\n          py = cy;\n        }\n        doc.bezierCurveTo(cx - (px - cx), cy - (py - cy), cx + a[0], cy + a[1], cx + a[2], cy + a[3]);\n        px = cx + a[0];\n        py = cy + a[1];\n        cx += a[2];\n        return cy += a[3];\n      },\n      Q: function(doc, a) {\n        px = a[0];\n        py = a[1];\n        cx = a[2];\n        cy = a[3];\n        return doc.quadraticCurveTo(a[0], a[1], cx, cy);\n      },\n      q: function(doc, a) {\n        doc.quadraticCurveTo(a[0] + cx, a[1] + cy, a[2] + cx, a[3] + cy);\n        px = cx + a[0];\n        py = cy + a[1];\n        cx += a[2];\n        return cy += a[3];\n      },\n      T: function(doc, a) {\n        if (px === null) {\n          px = cx;\n          py = cy;\n        } else {\n          px = cx - (px - cx);\n          py = cy - (py - cy);\n        }\n        doc.quadraticCurveTo(px, py, a[0], a[1]);\n        px = cx - (px - cx);\n        py = cy - (py - cy);\n        cx = a[0];\n        return cy = a[1];\n      },\n      t: function(doc, a) {\n        if (px === null) {\n          px = cx;\n          py = cy;\n        } else {\n          px = cx - (px - cx);\n          py = cy - (py - cy);\n        }\n        doc.quadraticCurveTo(px, py, cx + a[0], cy + a[1]);\n        cx += a[0];\n        return cy += a[1];\n      },\n      A: function(doc, a) {\n        solveArc(doc, cx, cy, a);\n        cx = a[5];\n        return cy = a[6];\n      },\n      a: function(doc, a) {\n        a[5] += cx;\n        a[6] += cy;\n        solveArc(doc, cx, cy, a);\n        cx = a[5];\n        return cy = a[6];\n      },\n      L: function(doc, a) {\n        cx = a[0];\n        cy = a[1];\n        px = py = null;\n        return doc.lineTo(cx, cy);\n      },\n      l: function(doc, a) {\n        cx += a[0];\n        cy += a[1];\n        px = py = null;\n        return doc.lineTo(cx, cy);\n      },\n      H: function(doc, a) {\n        cx = a[0];\n        px = py = null;\n        return doc.lineTo(cx, cy);\n      },\n      h: function(doc, a) {\n        cx += a[0];\n        px = py = null;\n        return doc.lineTo(cx, cy);\n      },\n      V: function(doc, a) {\n        cy = a[0];\n        px = py = null;\n        return doc.lineTo(cx, cy);\n      },\n      v: function(doc, a) {\n        cy += a[0];\n        px = py = null;\n        return doc.lineTo(cx, cy);\n      },\n      Z: function(doc) {\n        doc.closePath();\n        cx = sx;\n        return cy = sy;\n      },\n      z: function(doc) {\n        doc.closePath();\n        cx = sx;\n        return cy = sy;\n      }\n    };\n\n    solveArc = function(doc, x, y, coords) {\n      var bez, ex, ey, j, large, len, results, rot, rx, ry, seg, segs, sweep;\n      rx = coords[0], ry = coords[1], rot = coords[2], large = coords[3], sweep = coords[4], ex = coords[5], ey = coords[6];\n      segs = arcToSegments(ex, ey, rx, ry, large, sweep, rot, x, y);\n      results = [];\n      for (j = 0, len = segs.length; j < len; j++) {\n        seg = segs[j];\n        bez = segmentToBezier.apply(null, seg);\n        results.push(doc.bezierCurveTo.apply(doc, bez));\n      }\n      return results;\n    };\n\n    arcToSegments = function(x, y, rx, ry, large, sweep, rotateX, ox, oy) {\n      var a00, a01, a10, a11, cos_th, d, i, j, pl, ref, result, segments, sfactor, sfactor_sq, sin_th, th, th0, th1, th2, th3, th_arc, x0, x1, xc, y0, y1, yc;\n      th = rotateX * (Math.PI / 180);\n      sin_th = Math.sin(th);\n      cos_th = Math.cos(th);\n      rx = Math.abs(rx);\n      ry = Math.abs(ry);\n      px = cos_th * (ox - x) * 0.5 + sin_th * (oy - y) * 0.5;\n      py = cos_th * (oy - y) * 0.5 - sin_th * (ox - x) * 0.5;\n      pl = (px * px) / (rx * rx) + (py * py) / (ry * ry);\n      if (pl > 1) {\n        pl = Math.sqrt(pl);\n        rx *= pl;\n        ry *= pl;\n      }\n      a00 = cos_th / rx;\n      a01 = sin_th / rx;\n      a10 = (-sin_th) / ry;\n      a11 = cos_th / ry;\n      x0 = a00 * ox + a01 * oy;\n      y0 = a10 * ox + a11 * oy;\n      x1 = a00 * x + a01 * y;\n      y1 = a10 * x + a11 * y;\n      d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);\n      sfactor_sq = 1 / d - 0.25;\n      if (sfactor_sq < 0) {\n        sfactor_sq = 0;\n      }\n      sfactor = Math.sqrt(sfactor_sq);\n      if (sweep === large) {\n        sfactor = -sfactor;\n      }\n      xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);\n      yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);\n      th0 = Math.atan2(y0 - yc, x0 - xc);\n      th1 = Math.atan2(y1 - yc, x1 - xc);\n      th_arc = th1 - th0;\n      if (th_arc < 0 && sweep === 1) {\n        th_arc += 2 * Math.PI;\n      } else if (th_arc > 0 && sweep === 0) {\n        th_arc -= 2 * Math.PI;\n      }\n      segments = Math.ceil(Math.abs(th_arc / (Math.PI * 0.5 + 0.001)));\n      result = [];\n      for (i = j = 0, ref = segments; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {\n        th2 = th0 + i * th_arc / segments;\n        th3 = th0 + (i + 1) * th_arc / segments;\n        result[i] = [xc, yc, th2, th3, rx, ry, sin_th, cos_th];\n      }\n      return result;\n    };\n\n    segmentToBezier = function(cx, cy, th0, th1, rx, ry, sin_th, cos_th) {\n      var a00, a01, a10, a11, t, th_half, x1, x2, x3, y1, y2, y3;\n      a00 = cos_th * rx;\n      a01 = -sin_th * ry;\n      a10 = sin_th * rx;\n      a11 = cos_th * ry;\n      th_half = 0.5 * (th1 - th0);\n      t = (8 / 3) * Math.sin(th_half * 0.5) * Math.sin(th_half * 0.5) / Math.sin(th_half);\n      x1 = cx + Math.cos(th0) - t * Math.sin(th0);\n      y1 = cy + Math.sin(th0) + t * Math.cos(th0);\n      x3 = cx + Math.cos(th1);\n      y3 = cy + Math.sin(th1);\n      x2 = x3 + t * Math.sin(th1);\n      y2 = y3 - t * Math.cos(th1);\n      return [a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, a00 * x3 + a01 * y3, a10 * x3 + a11 * y3];\n    };\n\n    return SVGPath;\n\n  })();\n\n  module.exports = SVGPath;\n\n}).call(this);\n\n\n/***/ }),\n/* 166 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var PDFFont;\n\n  PDFFont = __webpack_require__(50);\n\n  module.exports = {\n    initFonts: function() {\n      this._fontFamilies = {};\n      this._fontCount = 0;\n      this._fontSize = 12;\n      this._font = null;\n      this._registeredFonts = {};\n      \n    },\n    font: function(src, family, size) {\n      var cacheKey, font, id, ref;\n      if (typeof family === 'number') {\n        size = family;\n        family = null;\n      }\n      if (typeof src === 'string' && this._registeredFonts[src]) {\n        cacheKey = src;\n        ref = this._registeredFonts[src], src = ref.src, family = ref.family;\n      } else {\n        cacheKey = family || src;\n        if (typeof cacheKey !== 'string') {\n          cacheKey = null;\n        }\n      }\n      if (size != null) {\n        this.fontSize(size);\n      }\n      if (font = this._fontFamilies[cacheKey]) {\n        this._font = font;\n        return this;\n      }\n      id = 'F' + (++this._fontCount);\n      this._font = PDFFont.open(this, src, family, id);\n      if (font = this._fontFamilies[this._font.name]) {\n        this._font = font;\n        return this;\n      }\n      if (cacheKey) {\n        this._fontFamilies[cacheKey] = this._font;\n      }\n      if (this._font.name) {\n        this._fontFamilies[this._font.name] = this._font;\n      }\n      return this;\n    },\n    fontSize: function(_fontSize) {\n      this._fontSize = _fontSize;\n      return this;\n    },\n    currentLineHeight: function(includeGap) {\n      if (includeGap == null) {\n        includeGap = false;\n      }\n      return this._font.lineHeight(this._fontSize, includeGap);\n    },\n    registerFont: function(name, src, family) {\n      this._registeredFonts[name] = {\n        src: src,\n        family: family\n      };\n      return this;\n    }\n  };\n\n}).call(this);\n\n\n/***/ }),\n/* 167 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(Buffer, process) {\n\nfunction _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }\n\nvar r = _interopDefault(__webpack_require__(168));\nvar _Object$getOwnPropertyDescriptor = _interopDefault(__webpack_require__(197));\nvar _getIterator = _interopDefault(__webpack_require__(60));\nvar _Object$freeze = _interopDefault(__webpack_require__(209));\nvar _Object$keys = _interopDefault(__webpack_require__(212));\nvar _typeof = _interopDefault(__webpack_require__(69));\nvar _Object$defineProperty = _interopDefault(__webpack_require__(74));\nvar _classCallCheck = _interopDefault(__webpack_require__(106));\nvar _createClass = _interopDefault(__webpack_require__(107));\nvar _Map = _interopDefault(__webpack_require__(225));\nvar _possibleConstructorReturn = _interopDefault(__webpack_require__(236));\nvar _inherits = _interopDefault(__webpack_require__(237));\nvar restructure_src_utils = __webpack_require__(12);\nvar _Object$defineProperties = _interopDefault(__webpack_require__(245));\nvar isEqual = _interopDefault(__webpack_require__(248));\nvar _Object$assign = _interopDefault(__webpack_require__(251));\nvar _String$fromCodePoint = _interopDefault(__webpack_require__(255));\nvar _Array$from = _interopDefault(__webpack_require__(258));\nvar _Set = _interopDefault(__webpack_require__(263));\nvar unicode = _interopDefault(__webpack_require__(269));\nvar UnicodeTrie = _interopDefault(__webpack_require__(43));\nvar StateMachine = _interopDefault(__webpack_require__(271));\nvar _Number$EPSILON = _interopDefault(__webpack_require__(280));\nvar cloneDeep = _interopDefault(__webpack_require__(283));\nvar inflate = _interopDefault(__webpack_require__(79));\nvar brotli = _interopDefault(__webpack_require__(284));\n\n\n\nvar fontkit = {};\nfontkit.logErrors = false;\n\nvar formats = [];\nfontkit.registerFormat = function (format) {\n  formats.push(format);\n};\n\nfontkit.openSync = function (filename, postscriptName) {\n  var buffer = __webpack_require__(8).readFileSync(filename);\n  return fontkit.create(buffer, postscriptName);\n};\n\nfontkit.open = function (filename, postscriptName, callback) {\n  if (typeof postscriptName === 'function') {\n    callback = postscriptName;\n    postscriptName = null;\n  }\n\n  __webpack_require__(8).readFile(filename, function (err, buffer) {\n    if (err) {\n      return callback(err);\n    }\n\n    try {\n      var font = fontkit.create(buffer, postscriptName);\n    } catch (e) {\n      return callback(e);\n    }\n\n    return callback(null, font);\n  });\n\n  return;\n};\n\nfontkit.create = function (buffer, postscriptName) {\n  for (var i = 0; i < formats.length; i++) {\n    var format = formats[i];\n    if (format.probe(buffer)) {\n      var font = new format(new r.DecodeStream(buffer));\n      if (postscriptName) {\n        return font.getFont(postscriptName);\n      }\n\n      return font;\n    }\n  }\n\n  throw new Error('Unknown font format');\n};\n\n/**\n * This decorator caches the results of a getter or method such that\n * the results are lazily computed once, and then cached.\n * @private\n */\nfunction cache(target, key, descriptor) {\n  if (descriptor.get) {\n    var get = descriptor.get;\n    descriptor.get = function () {\n      var value = get.call(this);\n      _Object$defineProperty(this, key, { value: value });\n      return value;\n    };\n  } else if (typeof descriptor.value === 'function') {\n    var fn = descriptor.value;\n\n    return {\n      get: function get() {\n        var cache = new _Map();\n        function memoized() {\n          for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {\n            args[_key] = arguments[_key];\n          }\n\n          var key = args.length > 0 ? args[0] : 'value';\n          if (cache.has(key)) {\n            return cache.get(key);\n          }\n\n          var result = fn.apply(this, args);\n          cache.set(key, result);\n          return result;\n        };\n\n        _Object$defineProperty(this, key, { value: memoized });\n        return memoized;\n      }\n    };\n  }\n}\n\nvar SubHeader = new r.Struct({\n  firstCode: r.uint16,\n  entryCount: r.uint16,\n  idDelta: r.int16,\n  idRangeOffset: r.uint16\n});\n\nvar CmapGroup = new r.Struct({\n  startCharCode: r.uint32,\n  endCharCode: r.uint32,\n  glyphID: r.uint32\n});\n\nvar UnicodeValueRange = new r.Struct({\n  startUnicodeValue: r.uint24,\n  additionalCount: r.uint8\n});\n\nvar UVSMapping = new r.Struct({\n  unicodeValue: r.uint24,\n  glyphID: r.uint16\n});\n\nvar DefaultUVS = new r.Array(UnicodeValueRange, r.uint32);\nvar NonDefaultUVS = new r.Array(UVSMapping, r.uint32);\n\nvar VarSelectorRecord = new r.Struct({\n  varSelector: r.uint24,\n  defaultUVS: new r.Pointer(r.uint32, DefaultUVS, { type: 'parent' }),\n  nonDefaultUVS: new r.Pointer(r.uint32, NonDefaultUVS, { type: 'parent' })\n});\n\nvar CmapSubtable = new r.VersionedStruct(r.uint16, {\n  0: { // Byte encoding\n    length: r.uint16, // Total table length in bytes (set to 262 for format 0)\n    language: r.uint16, // Language code for this encoding subtable, or zero if language-independent\n    codeMap: new r.LazyArray(r.uint8, 256)\n  },\n\n  2: { // High-byte mapping (CJK)\n    length: r.uint16,\n    language: r.uint16,\n    subHeaderKeys: new r.Array(r.uint16, 256),\n    subHeaderCount: function subHeaderCount(t) {\n      return Math.max.apply(Math, t.subHeaderKeys);\n    },\n    subHeaders: new r.LazyArray(SubHeader, 'subHeaderCount'),\n    glyphIndexArray: new r.LazyArray(r.uint16, 'subHeaderCount')\n  },\n\n  4: { // Segment mapping to delta values\n    length: r.uint16, // Total table length in bytes\n    language: r.uint16, // Language code\n    segCountX2: r.uint16,\n    segCount: function segCount(t) {\n      return t.segCountX2 >> 1;\n    },\n    searchRange: r.uint16,\n    entrySelector: r.uint16,\n    rangeShift: r.uint16,\n    endCode: new r.LazyArray(r.uint16, 'segCount'),\n    reservedPad: new r.Reserved(r.uint16), // This value should be zero\n    startCode: new r.LazyArray(r.uint16, 'segCount'),\n    idDelta: new r.LazyArray(r.int16, 'segCount'),\n    idRangeOffset: new r.LazyArray(r.uint16, 'segCount'),\n    glyphIndexArray: new r.LazyArray(r.uint16, function (t) {\n      return (t.length - t._currentOffset) / 2;\n    })\n  },\n\n  6: { // Trimmed table\n    length: r.uint16,\n    language: r.uint16,\n    firstCode: r.uint16,\n    entryCount: r.uint16,\n    glyphIndices: new r.LazyArray(r.uint16, 'entryCount')\n  },\n\n  8: { // mixed 16-bit and 32-bit coverage\n    reserved: new r.Reserved(r.uint16),\n    length: r.uint32,\n    language: r.uint16,\n    is32: new r.LazyArray(r.uint8, 8192),\n    nGroups: r.uint32,\n    groups: new r.LazyArray(CmapGroup, 'nGroups')\n  },\n\n  10: { // Trimmed Array\n    reserved: new r.Reserved(r.uint16),\n    length: r.uint32,\n    language: r.uint32,\n    firstCode: r.uint32,\n    entryCount: r.uint32,\n    glyphIndices: new r.LazyArray(r.uint16, 'numChars')\n  },\n\n  12: { // Segmented coverage\n    reserved: new r.Reserved(r.uint16),\n    length: r.uint32,\n    language: r.uint32,\n    nGroups: r.uint32,\n    groups: new r.LazyArray(CmapGroup, 'nGroups')\n  },\n\n  13: { // Many-to-one range mappings (same as 12 except for group.startGlyphID)\n    reserved: new r.Reserved(r.uint16),\n    length: r.uint32,\n    language: r.uint32,\n    nGroups: r.uint32,\n    groups: new r.LazyArray(CmapGroup, 'nGroups')\n  },\n\n  14: { // Unicode Variation Sequences\n    length: r.uint32,\n    numRecords: r.uint32,\n    varSelectors: new r.LazyArray(VarSelectorRecord, 'numRecords')\n  }\n});\n\nvar CmapEntry = new r.Struct({\n  platformID: r.uint16, // Platform identifier\n  encodingID: r.uint16, // Platform-specific encoding identifier\n  table: new r.Pointer(r.uint32, CmapSubtable, { type: 'parent', lazy: true })\n});\n\n// character to glyph mapping\nvar cmap = new r.Struct({\n  version: r.uint16,\n  numSubtables: r.uint16,\n  tables: new r.Array(CmapEntry, 'numSubtables')\n});\n\n// font header\nvar head = new r.Struct({\n  version: r.int32, // 0x00010000 (version 1.0)\n  revision: r.int32, // set by font manufacturer\n  checkSumAdjustment: r.uint32,\n  magicNumber: r.uint32, // set to 0x5F0F3CF5\n  flags: r.uint16,\n  unitsPerEm: r.uint16, // range from 64 to 16384\n  created: new r.Array(r.int32, 2),\n  modified: new r.Array(r.int32, 2),\n  xMin: r.int16, // for all glyph bounding boxes\n  yMin: r.int16, // for all glyph bounding boxes\n  xMax: r.int16, // for all glyph bounding boxes\n  yMax: r.int16, // for all glyph bounding boxes\n  macStyle: new r.Bitfield(r.uint16, ['bold', 'italic', 'underline', 'outline', 'shadow', 'condensed', 'extended']),\n  lowestRecPPEM: r.uint16, // smallest readable size in pixels\n  fontDirectionHint: r.int16,\n  indexToLocFormat: r.int16, // 0 for short offsets, 1 for long\n  glyphDataFormat: r.int16 // 0 for current format\n});\n\n// horizontal header\nvar hhea = new r.Struct({\n  version: r.int32,\n  ascent: r.int16, // Distance from baseline of highest ascender\n  descent: r.int16, // Distance from baseline of lowest descender\n  lineGap: r.int16, // Typographic line gap\n  advanceWidthMax: r.uint16, // Maximum advance width value in 'hmtx' table\n  minLeftSideBearing: r.int16, // Maximum advance width value in 'hmtx' table\n  minRightSideBearing: r.int16, // Minimum right sidebearing value\n  xMaxExtent: r.int16,\n  caretSlopeRise: r.int16, // Used to calculate the slope of the cursor (rise/run); 1 for vertical\n  caretSlopeRun: r.int16, // 0 for vertical\n  caretOffset: r.int16, // Set to 0 for non-slanted fonts\n  reserved: new r.Reserved(r.int16, 4),\n  metricDataFormat: r.int16, // 0 for current format\n  numberOfMetrics: r.uint16 // Number of advance widths in 'hmtx' table\n});\n\nvar HmtxEntry = new r.Struct({\n  advance: r.uint16,\n  bearing: r.int16\n});\n\nvar hmtx = new r.Struct({\n  metrics: new r.LazyArray(HmtxEntry, function (t) {\n    return t.parent.hhea.numberOfMetrics;\n  }),\n  bearings: new r.LazyArray(r.int16, function (t) {\n    return t.parent.maxp.numGlyphs - t.parent.hhea.numberOfMetrics;\n  })\n});\n\n// maxiumum profile\nvar maxp = new r.Struct({\n  version: r.int32,\n  numGlyphs: r.uint16, // The number of glyphs in the font\n  maxPoints: r.uint16, // Maximum points in a non-composite glyph\n  maxContours: r.uint16, // Maximum contours in a non-composite glyph\n  maxComponentPoints: r.uint16, // Maximum points in a composite glyph\n  maxComponentContours: r.uint16, // Maximum contours in a composite glyph\n  maxZones: r.uint16, // 1 if instructions do not use the twilight zone, 2 otherwise\n  maxTwilightPoints: r.uint16, // Maximum points used in Z0\n  maxStorage: r.uint16, // Number of Storage Area locations\n  maxFunctionDefs: r.uint16, // Number of FDEFs\n  maxInstructionDefs: r.uint16, // Number of IDEFs\n  maxStackElements: r.uint16, // Maximum stack depth\n  maxSizeOfInstructions: r.uint16, // Maximum byte count for glyph instructions\n  maxComponentElements: r.uint16, // Maximum number of components referenced at “top level” for any composite glyph\n  maxComponentDepth: r.uint16 // Maximum levels of recursion; 1 for simple components\n});\n\n/**\n * Gets an encoding name from platform, encoding, and language ids.\n * Returned encoding names can be used in iconv-lite to decode text.\n */\nfunction getEncoding(platformID, encodingID) {\n  var languageID = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n\n  if (platformID === 1 && MAC_LANGUAGE_ENCODINGS[languageID]) {\n    return MAC_LANGUAGE_ENCODINGS[languageID];\n  }\n\n  return ENCODINGS[platformID][encodingID];\n}\n\n// Map of platform ids to encoding ids.\nvar ENCODINGS = [\n// unicode\n['utf16be', 'utf16be', 'utf16be', 'utf16be', 'utf16be', 'utf16be'],\n\n// macintosh\n// Mappings available at http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/\n// 0\tRoman                 17\tMalayalam\n// 1\tJapanese\t            18\tSinhalese\n// 2\tTraditional Chinese\t  19\tBurmese\n// 3\tKorean\t              20\tKhmer\n// 4\tArabic\t              21\tThai\n// 5\tHebrew\t              22\tLaotian\n// 6\tGreek\t                23\tGeorgian\n// 7\tRussian\t              24\tArmenian\n// 8\tRSymbol\t              25\tSimplified Chinese\n// 9\tDevanagari\t          26\tTibetan\n// 10\tGurmukhi\t            27\tMongolian\n// 11\tGujarati\t            28\tGeez\n// 12\tOriya\t                29\tSlavic\n// 13\tBengali\t              30\tVietnamese\n// 14\tTamil\t                31\tSindhi\n// 15\tTelugu\t              32\t(Uninterpreted)\n// 16\tKannada\n['macroman', 'shift-jis', 'big5', 'euc-kr', 'iso-8859-6', 'iso-8859-8', 'macgreek', 'maccyrillic', 'symbol', 'Devanagari', 'Gurmukhi', 'Gujarati', 'Oriya', 'Bengali', 'Tamil', 'Telugu', 'Kannada', 'Malayalam', 'Sinhalese', 'Burmese', 'Khmer', 'macthai', 'Laotian', 'Georgian', 'Armenian', 'gb-2312-80', 'Tibetan', 'Mongolian', 'Geez', 'maccenteuro', 'Vietnamese', 'Sindhi'],\n\n// ISO (deprecated)\n['ascii'],\n\n// windows\n// Docs here: http://msdn.microsoft.com/en-us/library/system.text.encoding(v=vs.110).aspx\n['symbol', 'utf16be', 'shift-jis', 'gb18030', 'big5', 'wansung', 'johab', null, null, null, 'utf16be']];\n\n// Overrides for Mac scripts by language id.\n// See http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/Readme.txt\nvar MAC_LANGUAGE_ENCODINGS = {\n  15: 'maciceland',\n  17: 'macturkish',\n  18: 'maccroatian',\n  24: 'maccenteuro',\n  25: 'maccenteuro',\n  26: 'maccenteuro',\n  27: 'maccenteuro',\n  28: 'maccenteuro',\n  30: 'maciceland',\n  37: 'macromania',\n  38: 'maccenteuro',\n  39: 'maccenteuro',\n  40: 'maccenteuro',\n  143: 'macinuit', // Unsupported by iconv-lite\n  146: 'macgaelic' // Unsupported by iconv-lite\n};\n\n// Map of platform ids to BCP-47 language codes.\nvar LANGUAGES = [\n// unicode\n[], { // macintosh\n  0: 'en', 30: 'fo', 60: 'ks', 90: 'rw',\n  1: 'fr', 31: 'fa', 61: 'ku', 91: 'rn',\n  2: 'de', 32: 'ru', 62: 'sd', 92: 'ny',\n  3: 'it', 33: 'zh', 63: 'bo', 93: 'mg',\n  4: 'nl', 34: 'nl-BE', 64: 'ne', 94: 'eo',\n  5: 'sv', 35: 'ga', 65: 'sa', 128: 'cy',\n  6: 'es', 36: 'sq', 66: 'mr', 129: 'eu',\n  7: 'da', 37: 'ro', 67: 'bn', 130: 'ca',\n  8: 'pt', 38: 'cz', 68: 'as', 131: 'la',\n  9: 'no', 39: 'sk', 69: 'gu', 132: 'qu',\n  10: 'he', 40: 'si', 70: 'pa', 133: 'gn',\n  11: 'ja', 41: 'yi', 71: 'or', 134: 'ay',\n  12: 'ar', 42: 'sr', 72: 'ml', 135: 'tt',\n  13: 'fi', 43: 'mk', 73: 'kn', 136: 'ug',\n  14: 'el', 44: 'bg', 74: 'ta', 137: 'dz',\n  15: 'is', 45: 'uk', 75: 'te', 138: 'jv',\n  16: 'mt', 46: 'be', 76: 'si', 139: 'su',\n  17: 'tr', 47: 'uz', 77: 'my', 140: 'gl',\n  18: 'hr', 48: 'kk', 78: 'km', 141: 'af',\n  19: 'zh-Hant', 49: 'az-Cyrl', 79: 'lo', 142: 'br',\n  20: 'ur', 50: 'az-Arab', 80: 'vi', 143: 'iu',\n  21: 'hi', 51: 'hy', 81: 'id', 144: 'gd',\n  22: 'th', 52: 'ka', 82: 'tl', 145: 'gv',\n  23: 'ko', 53: 'mo', 83: 'ms', 146: 'ga',\n  24: 'lt', 54: 'ky', 84: 'ms-Arab', 147: 'to',\n  25: 'pl', 55: 'tg', 85: 'am', 148: 'el-polyton',\n  26: 'hu', 56: 'tk', 86: 'ti', 149: 'kl',\n  27: 'es', 57: 'mn-CN', 87: 'om', 150: 'az',\n  28: 'lv', 58: 'mn', 88: 'so', 151: 'nn',\n  29: 'se', 59: 'ps', 89: 'sw'\n},\n\n// ISO (deprecated)\n[], { // windows                                        \n  0x0436: 'af', 0x4009: 'en-IN', 0x0487: 'rw', 0x0432: 'tn',\n  0x041C: 'sq', 0x1809: 'en-IE', 0x0441: 'sw', 0x045B: 'si',\n  0x0484: 'gsw', 0x2009: 'en-JM', 0x0457: 'kok', 0x041B: 'sk',\n  0x045E: 'am', 0x4409: 'en-MY', 0x0412: 'ko', 0x0424: 'sl',\n  0x1401: 'ar-DZ', 0x1409: 'en-NZ', 0x0440: 'ky', 0x2C0A: 'es-AR',\n  0x3C01: 'ar-BH', 0x3409: 'en-PH', 0x0454: 'lo', 0x400A: 'es-BO',\n  0x0C01: 'ar', 0x4809: 'en-SG', 0x0426: 'lv', 0x340A: 'es-CL',\n  0x0801: 'ar-IQ', 0x1C09: 'en-ZA', 0x0427: 'lt', 0x240A: 'es-CO',\n  0x2C01: 'ar-JO', 0x2C09: 'en-TT', 0x082E: 'dsb', 0x140A: 'es-CR',\n  0x3401: 'ar-KW', 0x0809: 'en-GB', 0x046E: 'lb', 0x1C0A: 'es-DO',\n  0x3001: 'ar-LB', 0x0409: 'en', 0x042F: 'mk', 0x300A: 'es-EC',\n  0x1001: 'ar-LY', 0x3009: 'en-ZW', 0x083E: 'ms-BN', 0x440A: 'es-SV',\n  0x1801: 'ary', 0x0425: 'et', 0x043E: 'ms', 0x100A: 'es-GT',\n  0x2001: 'ar-OM', 0x0438: 'fo', 0x044C: 'ml', 0x480A: 'es-HN',\n  0x4001: 'ar-QA', 0x0464: 'fil', 0x043A: 'mt', 0x080A: 'es-MX',\n  0x0401: 'ar-SA', 0x040B: 'fi', 0x0481: 'mi', 0x4C0A: 'es-NI',\n  0x2801: 'ar-SY', 0x080C: 'fr-BE', 0x047A: 'arn', 0x180A: 'es-PA',\n  0x1C01: 'aeb', 0x0C0C: 'fr-CA', 0x044E: 'mr', 0x3C0A: 'es-PY',\n  0x3801: 'ar-AE', 0x040C: 'fr', 0x047C: 'moh', 0x280A: 'es-PE',\n  0x2401: 'ar-YE', 0x140C: 'fr-LU', 0x0450: 'mn', 0x500A: 'es-PR',\n  0x042B: 'hy', 0x180C: 'fr-MC', 0x0850: 'mn-CN', 0x0C0A: 'es',\n  0x044D: 'as', 0x100C: 'fr-CH', 0x0461: 'ne', 0x040A: 'es',\n  0x082C: 'az-Cyrl', 0x0462: 'fy', 0x0414: 'nb', 0x540A: 'es-US',\n  0x042C: 'az', 0x0456: 'gl', 0x0814: 'nn', 0x380A: 'es-UY',\n  0x046D: 'ba', 0x0437: 'ka', 0x0482: 'oc', 0x200A: 'es-VE',\n  0x042D: 'eu', 0x0C07: 'de-AT', 0x0448: 'or', 0x081D: 'sv-FI',\n  0x0423: 'be', 0x0407: 'de', 0x0463: 'ps', 0x041D: 'sv',\n  0x0845: 'bn', 0x1407: 'de-LI', 0x0415: 'pl', 0x045A: 'syr',\n  0x0445: 'bn-IN', 0x1007: 'de-LU', 0x0416: 'pt', 0x0428: 'tg',\n  0x201A: 'bs-Cyrl', 0x0807: 'de-CH', 0x0816: 'pt-PT', 0x085F: 'tzm',\n  0x141A: 'bs', 0x0408: 'el', 0x0446: 'pa', 0x0449: 'ta',\n  0x047E: 'br', 0x046F: 'kl', 0x046B: 'qu-BO', 0x0444: 'tt',\n  0x0402: 'bg', 0x0447: 'gu', 0x086B: 'qu-EC', 0x044A: 'te',\n  0x0403: 'ca', 0x0468: 'ha', 0x0C6B: 'qu', 0x041E: 'th',\n  0x0C04: 'zh-HK', 0x040D: 'he', 0x0418: 'ro', 0x0451: 'bo',\n  0x1404: 'zh-MO', 0x0439: 'hi', 0x0417: 'rm', 0x041F: 'tr',\n  0x0804: 'zh', 0x040E: 'hu', 0x0419: 'ru', 0x0442: 'tk',\n  0x1004: 'zh-SG', 0x040F: 'is', 0x243B: 'smn', 0x0480: 'ug',\n  0x0404: 'zh-TW', 0x0470: 'ig', 0x103B: 'smj-NO', 0x0422: 'uk',\n  0x0483: 'co', 0x0421: 'id', 0x143B: 'smj', 0x042E: 'hsb',\n  0x041A: 'hr', 0x045D: 'iu', 0x0C3B: 'se-FI', 0x0420: 'ur',\n  0x101A: 'hr-BA', 0x085D: 'iu-Latn', 0x043B: 'se', 0x0843: 'uz-Cyrl',\n  0x0405: 'cs', 0x083C: 'ga', 0x083B: 'se-SE', 0x0443: 'uz',\n  0x0406: 'da', 0x0434: 'xh', 0x203B: 'sms', 0x042A: 'vi',\n  0x048C: 'prs', 0x0435: 'zu', 0x183B: 'sma-NO', 0x0452: 'cy',\n  0x0465: 'dv', 0x0410: 'it', 0x1C3B: 'sms', 0x0488: 'wo',\n  0x0813: 'nl-BE', 0x0810: 'it-CH', 0x044F: 'sa', 0x0485: 'sah',\n  0x0413: 'nl', 0x0411: 'ja', 0x1C1A: 'sr-Cyrl-BA', 0x0478: 'ii',\n  0x0C09: 'en-AU', 0x044B: 'kn', 0x0C1A: 'sr', 0x046A: 'yo',\n  0x2809: 'en-BZ', 0x043F: 'kk', 0x181A: 'sr-Latn-BA',\n  0x1009: 'en-CA', 0x0453: 'km', 0x081A: 'sr-Latn',\n  0x2409: 'en-029', 0x0486: 'quc', 0x046C: 'nso'\n}];\n\nvar NameRecord = new r.Struct({\n  platformID: r.uint16,\n  encodingID: r.uint16,\n  languageID: r.uint16,\n  nameID: r.uint16,\n  length: r.uint16,\n  string: new r.Pointer(r.uint16, new r.String('length', function (t) {\n    return getEncoding(t.platformID, t.encodingID, t.languageID);\n  }), { type: 'parent', relativeTo: 'parent.stringOffset', allowNull: false })\n});\n\nvar LangTagRecord = new r.Struct({\n  length: r.uint16,\n  tag: new r.Pointer(r.uint16, new r.String('length', 'utf16be'), { type: 'parent', relativeTo: 'stringOffset' })\n});\n\nvar NameTable = new r.VersionedStruct(r.uint16, {\n  0: {\n    count: r.uint16,\n    stringOffset: r.uint16,\n    records: new r.Array(NameRecord, 'count')\n  },\n  1: {\n    count: r.uint16,\n    stringOffset: r.uint16,\n    records: new r.Array(NameRecord, 'count'),\n    langTagCount: r.uint16,\n    langTags: new r.Array(LangTagRecord, 'langTagCount')\n  }\n});\n\nvar NAMES = ['copyright', 'fontFamily', 'fontSubfamily', 'uniqueSubfamily', 'fullName', 'version', 'postscriptName', // Note: A font may have only one PostScript name and that name must be ASCII.\n'trademark', 'manufacturer', 'designer', 'description', 'vendorURL', 'designerURL', 'license', 'licenseURL', null, // reserved\n'preferredFamily', 'preferredSubfamily', 'compatibleFull', 'sampleText', 'postscriptCIDFontName', 'wwsFamilyName', 'wwsSubfamilyName'];\n\nNameTable.process = function (stream) {\n  var records = {};\n  for (var _iterator = this.records, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n    var _ref;\n\n    if (_isArray) {\n      if (_i >= _iterator.length) break;\n      _ref = _iterator[_i++];\n    } else {\n      _i = _iterator.next();\n      if (_i.done) break;\n      _ref = _i.value;\n    }\n\n    var record = _ref;\n\n    // find out what language this is for\n    var language = LANGUAGES[record.platformID][record.languageID];\n\n    if (language == null && this.langTags != null && record.languageID >= 0x8000) {\n      language = this.langTags[record.languageID - 0x8000].tag;\n    }\n\n    if (language == null) {\n      language = record.platformID + '-' + record.languageID;\n    }\n\n    // if the nameID is >= 256, it is a font feature record (AAT)\n    var key = record.nameID >= 256 ? 'fontFeatures' : NAMES[record.nameID] || record.nameID;\n    if (records[key] == null) {\n      records[key] = {};\n    }\n\n    var obj = records[key];\n    if (record.nameID >= 256) {\n      obj = obj[record.nameID] || (obj[record.nameID] = {});\n    }\n\n    if (typeof record.string === 'string' || typeof obj[language] !== 'string') {\n      obj[language] = record.string;\n    }\n  }\n\n  this.records = records;\n};\n\nNameTable.preEncode = function () {\n  if (Array.isArray(this.records)) return;\n  this.version = 0;\n\n  var records = [];\n  for (var key in this.records) {\n    var val = this.records[key];\n    if (key === 'fontFeatures') continue;\n\n    records.push({\n      platformID: 3,\n      encodingID: 1,\n      languageID: 0x409,\n      nameID: NAMES.indexOf(key),\n      length: Buffer.byteLength(val.en, 'utf16le'),\n      string: val.en\n    });\n\n    if (key === 'postscriptName') {\n      records.push({\n        platformID: 1,\n        encodingID: 0,\n        languageID: 0,\n        nameID: NAMES.indexOf(key),\n        length: val.en.length,\n        string: val.en\n      });\n    }\n  }\n\n  this.records = records;\n  this.count = records.length;\n  this.stringOffset = NameTable.size(this, null, false);\n};\n\nvar OS2 = new r.VersionedStruct(r.uint16, {\n  header: {\n    xAvgCharWidth: r.int16, // average weighted advance width of lower case letters and space\n    usWeightClass: r.uint16, // visual weight of stroke in glyphs\n    usWidthClass: r.uint16, // relative change from the normal aspect ratio (width to height ratio)\n    fsType: new r.Bitfield(r.uint16, [// Indicates font embedding licensing rights\n    null, 'noEmbedding', 'viewOnly', 'editable', null, null, null, null, 'noSubsetting', 'bitmapOnly']),\n    ySubscriptXSize: r.int16, // recommended horizontal size in pixels for subscripts\n    ySubscriptYSize: r.int16, // recommended vertical size in pixels for subscripts\n    ySubscriptXOffset: r.int16, // recommended horizontal offset for subscripts\n    ySubscriptYOffset: r.int16, // recommended vertical offset form the baseline for subscripts\n    ySuperscriptXSize: r.int16, // recommended horizontal size in pixels for superscripts\n    ySuperscriptYSize: r.int16, // recommended vertical size in pixels for superscripts\n    ySuperscriptXOffset: r.int16, // recommended horizontal offset for superscripts\n    ySuperscriptYOffset: r.int16, // recommended vertical offset from the baseline for superscripts\n    yStrikeoutSize: r.int16, // width of the strikeout stroke\n    yStrikeoutPosition: r.int16, // position of the strikeout stroke relative to the baseline\n    sFamilyClass: r.int16, // classification of font-family design\n    panose: new r.Array(r.uint8, 10), // describe the visual characteristics of a given typeface\n    ulCharRange: new r.Array(r.uint32, 4),\n    vendorID: new r.String(4), // four character identifier for the font vendor\n    fsSelection: new r.Bitfield(r.uint16, [// bit field containing information about the font\n    'italic', 'underscore', 'negative', 'outlined', 'strikeout', 'bold', 'regular', 'useTypoMetrics', 'wws', 'oblique']),\n    usFirstCharIndex: r.uint16, // The minimum Unicode index in this font\n    usLastCharIndex: r.uint16 // The maximum Unicode index in this font\n  },\n\n  // The Apple version of this table ends here, but the Microsoft one continues on...\n  0: {},\n\n  1: {\n    typoAscender: r.int16,\n    typoDescender: r.int16,\n    typoLineGap: r.int16,\n    winAscent: r.uint16,\n    winDescent: r.uint16,\n    codePageRange: new r.Array(r.uint32, 2)\n  },\n\n  2: {\n    // these should be common with version 1 somehow\n    typoAscender: r.int16,\n    typoDescender: r.int16,\n    typoLineGap: r.int16,\n    winAscent: r.uint16,\n    winDescent: r.uint16,\n    codePageRange: new r.Array(r.uint32, 2),\n\n    xHeight: r.int16,\n    capHeight: r.int16,\n    defaultChar: r.uint16,\n    breakChar: r.uint16,\n    maxContent: r.uint16\n  },\n\n  5: {\n    typoAscender: r.int16,\n    typoDescender: r.int16,\n    typoLineGap: r.int16,\n    winAscent: r.uint16,\n    winDescent: r.uint16,\n    codePageRange: new r.Array(r.uint32, 2),\n\n    xHeight: r.int16,\n    capHeight: r.int16,\n    defaultChar: r.uint16,\n    breakChar: r.uint16,\n    maxContent: r.uint16,\n\n    usLowerOpticalPointSize: r.uint16,\n    usUpperOpticalPointSize: r.uint16\n  }\n});\n\nvar versions = OS2.versions;\nversions[3] = versions[4] = versions[2];\n\n// PostScript information\nvar post = new r.VersionedStruct(r.fixed32, {\n  header: { // these fields exist at the top of all versions\n    italicAngle: r.fixed32, // Italic angle in counter-clockwise degrees from the vertical.\n    underlinePosition: r.int16, // Suggested distance of the top of the underline from the baseline\n    underlineThickness: r.int16, // Suggested values for the underline thickness\n    isFixedPitch: r.uint32, // Whether the font is monospaced\n    minMemType42: r.uint32, // Minimum memory usage when a TrueType font is downloaded as a Type 42 font\n    maxMemType42: r.uint32, // Maximum memory usage when a TrueType font is downloaded as a Type 42 font\n    minMemType1: r.uint32, // Minimum memory usage when a TrueType font is downloaded as a Type 1 font\n    maxMemType1: r.uint32 // Maximum memory usage when a TrueType font is downloaded as a Type 1 font\n  },\n\n  1: {}, // version 1 has no additional fields\n\n  2: {\n    numberOfGlyphs: r.uint16,\n    glyphNameIndex: new r.Array(r.uint16, 'numberOfGlyphs'),\n    names: new r.Array(new r.String(r.uint8))\n  },\n\n  2.5: {\n    numberOfGlyphs: r.uint16,\n    offsets: new r.Array(r.uint8, 'numberOfGlyphs')\n  },\n\n  3: {}, // version 3 has no additional fields\n\n  4: {\n    map: new r.Array(r.uint32, function (t) {\n      return t.parent.maxp.numGlyphs;\n    })\n  }\n});\n\n// An array of predefined values accessible by instructions\nvar cvt = new r.Struct({\n  controlValues: new r.Array(r.int16)\n});\n\n// A list of instructions that are executed once when a font is first used.\n// These instructions are known as the font program. The main use of this table\n// is for the definition of functions that are used in many different glyph programs.\nvar fpgm = new r.Struct({\n  instructions: new r.Array(r.uint8)\n});\n\nvar loca = new r.VersionedStruct('head.indexToLocFormat', {\n  0: {\n    offsets: new r.Array(r.uint16)\n  },\n  1: {\n    offsets: new r.Array(r.uint32)\n  }\n});\n\nloca.process = function () {\n  if (this.version === 0) {\n    for (var i = 0; i < this.offsets.length; i++) {\n      this.offsets[i] <<= 1;\n    }\n  }\n};\n\nloca.preEncode = function () {\n  if (this.version != null) return;\n\n  // assume this.offsets is a sorted array\n  this.version = this.offsets[this.offsets.length - 1] > 0xffff ? 1 : 0;\n\n  if (this.version === 0) {\n    for (var i = 0; i < this.offsets.length; i++) {\n      this.offsets[i] >>>= 1;\n    }\n  }\n};\n\n// Set of instructions executed whenever the point size or font transformation change\nvar prep = new r.Struct({\n  controlValueProgram: new r.Array(r.uint8)\n});\n\n// only used for encoding\nvar glyf = new r.Array(new r.Buffer());\n\nvar CFFIndex = function () {\n  function CFFIndex(type) {\n    _classCallCheck(this, CFFIndex);\n\n    this.type = type;\n  }\n\n  CFFIndex.prototype.getCFFVersion = function getCFFVersion(ctx) {\n    while (ctx && !ctx.hdrSize) {\n      ctx = ctx.parent;\n    }\n\n    return ctx ? ctx.version : -1;\n  };\n\n  CFFIndex.prototype.decode = function decode(stream, parent) {\n    var version = this.getCFFVersion(parent);\n    var count = version >= 2 ? stream.readUInt32BE() : stream.readUInt16BE();\n\n    if (count === 0) {\n      return [];\n    }\n\n    var offSize = stream.readUInt8();\n    var offsetType = void 0;\n    if (offSize === 1) {\n      offsetType = r.uint8;\n    } else if (offSize === 2) {\n      offsetType = r.uint16;\n    } else if (offSize === 3) {\n      offsetType = r.uint24;\n    } else if (offSize === 4) {\n      offsetType = r.uint32;\n    } else {\n      throw new Error(\"Bad offset size in CFFIndex: \" + offSize + \" \" + stream.pos);\n    }\n\n    var ret = [];\n    var startPos = stream.pos + (count + 1) * offSize - 1;\n\n    var start = offsetType.decode(stream);\n    for (var i = 0; i < count; i++) {\n      var end = offsetType.decode(stream);\n\n      if (this.type != null) {\n        var pos = stream.pos;\n        stream.pos = startPos + start;\n\n        parent.length = end - start;\n        ret.push(this.type.decode(stream, parent));\n        stream.pos = pos;\n      } else {\n        ret.push({\n          offset: startPos + start,\n          length: end - start\n        });\n      }\n\n      start = end;\n    }\n\n    stream.pos = startPos + start;\n    return ret;\n  };\n\n  CFFIndex.prototype.size = function size(arr, parent) {\n    var size = 2;\n    if (arr.length === 0) {\n      return size;\n    }\n\n    var type = this.type || new r.Buffer();\n\n    // find maximum offset to detminine offset type\n    var offset = 1;\n    for (var i = 0; i < arr.length; i++) {\n      var item = arr[i];\n      offset += type.size(item, parent);\n    }\n\n    var offsetType = void 0;\n    if (offset <= 0xff) {\n      offsetType = r.uint8;\n    } else if (offset <= 0xffff) {\n      offsetType = r.uint16;\n    } else if (offset <= 0xffffff) {\n      offsetType = r.uint24;\n    } else if (offset <= 0xffffffff) {\n      offsetType = r.uint32;\n    } else {\n      throw new Error(\"Bad offset in CFFIndex\");\n    }\n\n    size += 1 + offsetType.size() * (arr.length + 1);\n    size += offset - 1;\n\n    return size;\n  };\n\n  CFFIndex.prototype.encode = function encode(stream, arr, parent) {\n    stream.writeUInt16BE(arr.length);\n    if (arr.length === 0) {\n      return;\n    }\n\n    var type = this.type || new r.Buffer();\n\n    // find maximum offset to detminine offset type\n    var sizes = [];\n    var offset = 1;\n    for (var _iterator = arr, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var item = _ref;\n\n      var s = type.size(item, parent);\n      sizes.push(s);\n      offset += s;\n    }\n\n    var offsetType = void 0;\n    if (offset <= 0xff) {\n      offsetType = r.uint8;\n    } else if (offset <= 0xffff) {\n      offsetType = r.uint16;\n    } else if (offset <= 0xffffff) {\n      offsetType = r.uint24;\n    } else if (offset <= 0xffffffff) {\n      offsetType = r.uint32;\n    } else {\n      throw new Error(\"Bad offset in CFFIndex\");\n    }\n\n    // write offset size\n    stream.writeUInt8(offsetType.size());\n\n    // write elements\n    offset = 1;\n    offsetType.encode(stream, offset);\n\n    for (var _iterator2 = sizes, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n      var _ref2;\n\n      if (_isArray2) {\n        if (_i2 >= _iterator2.length) break;\n        _ref2 = _iterator2[_i2++];\n      } else {\n        _i2 = _iterator2.next();\n        if (_i2.done) break;\n        _ref2 = _i2.value;\n      }\n\n      var size = _ref2;\n\n      offset += size;\n      offsetType.encode(stream, offset);\n    }\n\n    for (var _iterator3 = arr, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n      var _ref3;\n\n      if (_isArray3) {\n        if (_i3 >= _iterator3.length) break;\n        _ref3 = _iterator3[_i3++];\n      } else {\n        _i3 = _iterator3.next();\n        if (_i3.done) break;\n        _ref3 = _i3.value;\n      }\n\n      var _item = _ref3;\n\n      type.encode(stream, _item, parent);\n    }\n\n    return;\n  };\n\n  return CFFIndex;\n}();\n\nvar FLOAT_EOF = 0xf;\nvar FLOAT_LOOKUP = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'E', 'E-', null, '-'];\n\nvar FLOAT_ENCODE_LOOKUP = {\n  '.': 10,\n  'E': 11,\n  'E-': 12,\n  '-': 14\n};\n\nvar CFFOperand = function () {\n  function CFFOperand() {\n    _classCallCheck(this, CFFOperand);\n  }\n\n  CFFOperand.decode = function decode(stream, value) {\n    if (32 <= value && value <= 246) {\n      return value - 139;\n    }\n\n    if (247 <= value && value <= 250) {\n      return (value - 247) * 256 + stream.readUInt8() + 108;\n    }\n\n    if (251 <= value && value <= 254) {\n      return -(value - 251) * 256 - stream.readUInt8() - 108;\n    }\n\n    if (value === 28) {\n      return stream.readInt16BE();\n    }\n\n    if (value === 29) {\n      return stream.readInt32BE();\n    }\n\n    if (value === 30) {\n      var str = '';\n      while (true) {\n        var b = stream.readUInt8();\n\n        var n1 = b >> 4;\n        if (n1 === FLOAT_EOF) {\n          break;\n        }\n        str += FLOAT_LOOKUP[n1];\n\n        var n2 = b & 15;\n        if (n2 === FLOAT_EOF) {\n          break;\n        }\n        str += FLOAT_LOOKUP[n2];\n      }\n\n      return parseFloat(str);\n    }\n\n    return null;\n  };\n\n  CFFOperand.size = function size(value) {\n    // if the value needs to be forced to the largest size (32 bit)\n    // e.g. for unknown pointers, set to 32768\n    if (value.forceLarge) {\n      value = 32768;\n    }\n\n    if ((value | 0) !== value) {\n      // floating point\n      var str = '' + value;\n      return 1 + Math.ceil((str.length + 1) / 2);\n    } else if (-107 <= value && value <= 107) {\n      return 1;\n    } else if (108 <= value && value <= 1131 || -1131 <= value && value <= -108) {\n      return 2;\n    } else if (-32768 <= value && value <= 32767) {\n      return 3;\n    } else {\n      return 5;\n    }\n  };\n\n  CFFOperand.encode = function encode(stream, value) {\n    // if the value needs to be forced to the largest size (32 bit)\n    // e.g. for unknown pointers, save the old value and set to 32768\n    var val = Number(value);\n\n    if (value.forceLarge) {\n      stream.writeUInt8(29);\n      return stream.writeInt32BE(val);\n    } else if ((val | 0) !== val) {\n      // floating point\n      stream.writeUInt8(30);\n\n      var str = '' + val;\n      for (var i = 0; i < str.length; i += 2) {\n        var c1 = str[i];\n        var n1 = FLOAT_ENCODE_LOOKUP[c1] || +c1;\n\n        if (i === str.length - 1) {\n          var n2 = FLOAT_EOF;\n        } else {\n          var c2 = str[i + 1];\n          var n2 = FLOAT_ENCODE_LOOKUP[c2] || +c2;\n        }\n\n        stream.writeUInt8(n1 << 4 | n2 & 15);\n      }\n\n      if (n2 !== FLOAT_EOF) {\n        return stream.writeUInt8(FLOAT_EOF << 4);\n      }\n    } else if (-107 <= val && val <= 107) {\n      return stream.writeUInt8(val + 139);\n    } else if (108 <= val && val <= 1131) {\n      val -= 108;\n      stream.writeUInt8((val >> 8) + 247);\n      return stream.writeUInt8(val & 0xff);\n    } else if (-1131 <= val && val <= -108) {\n      val = -val - 108;\n      stream.writeUInt8((val >> 8) + 251);\n      return stream.writeUInt8(val & 0xff);\n    } else if (-32768 <= val && val <= 32767) {\n      stream.writeUInt8(28);\n      return stream.writeInt16BE(val);\n    } else {\n      stream.writeUInt8(29);\n      return stream.writeInt32BE(val);\n    }\n  };\n\n  return CFFOperand;\n}();\n\nvar CFFDict = function () {\n  function CFFDict() {\n    var ops = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n\n    _classCallCheck(this, CFFDict);\n\n    this.ops = ops;\n    this.fields = {};\n    for (var _iterator = ops, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var field = _ref;\n\n      var key = Array.isArray(field[0]) ? field[0][0] << 8 | field[0][1] : field[0];\n      this.fields[key] = field;\n    }\n  }\n\n  CFFDict.prototype.decodeOperands = function decodeOperands(type, stream, ret, operands) {\n    var _this = this;\n\n    if (Array.isArray(type)) {\n      return operands.map(function (op, i) {\n        return _this.decodeOperands(type[i], stream, ret, [op]);\n      });\n    } else if (type.decode != null) {\n      return type.decode(stream, ret, operands);\n    } else {\n      switch (type) {\n        case 'number':\n        case 'offset':\n        case 'sid':\n          return operands[0];\n        case 'boolean':\n          return !!operands[0];\n        default:\n          return operands;\n      }\n    }\n  };\n\n  CFFDict.prototype.encodeOperands = function encodeOperands(type, stream, ctx, operands) {\n    var _this2 = this;\n\n    if (Array.isArray(type)) {\n      return operands.map(function (op, i) {\n        return _this2.encodeOperands(type[i], stream, ctx, op)[0];\n      });\n    } else if (type.encode != null) {\n      return type.encode(stream, operands, ctx);\n    } else if (typeof operands === 'number') {\n      return [operands];\n    } else if (typeof operands === 'boolean') {\n      return [+operands];\n    } else if (Array.isArray(operands)) {\n      return operands;\n    } else {\n      return [operands];\n    }\n  };\n\n  CFFDict.prototype.decode = function decode(stream, parent) {\n    var end = stream.pos + parent.length;\n    var ret = {};\n    var operands = [];\n\n    // define hidden properties\n    _Object$defineProperties(ret, {\n      parent: { value: parent },\n      _startOffset: { value: stream.pos }\n    });\n\n    // fill in defaults\n    for (var key in this.fields) {\n      var field = this.fields[key];\n      ret[field[1]] = field[3];\n    }\n\n    while (stream.pos < end) {\n      var b = stream.readUInt8();\n      if (b < 28) {\n        if (b === 12) {\n          b = b << 8 | stream.readUInt8();\n        }\n\n        var _field = this.fields[b];\n        if (!_field) {\n          throw new Error('Unknown operator ' + b);\n        }\n\n        var val = this.decodeOperands(_field[2], stream, ret, operands);\n        if (val != null) {\n          if (val instanceof restructure_src_utils.PropertyDescriptor) {\n            _Object$defineProperty(ret, _field[1], val);\n          } else {\n            ret[_field[1]] = val;\n          }\n        }\n\n        operands = [];\n      } else {\n        operands.push(CFFOperand.decode(stream, b));\n      }\n    }\n\n    return ret;\n  };\n\n  CFFDict.prototype.size = function size(dict, parent) {\n    var includePointers = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n\n    var ctx = {\n      parent: parent,\n      val: dict,\n      pointerSize: 0,\n      startOffset: parent.startOffset || 0\n    };\n\n    var len = 0;\n\n    for (var k in this.fields) {\n      var field = this.fields[k];\n      var val = dict[field[1]];\n      if (val == null || isEqual(val, field[3])) {\n        continue;\n      }\n\n      var operands = this.encodeOperands(field[2], null, ctx, val);\n      for (var _iterator2 = operands, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n        var _ref2;\n\n        if (_isArray2) {\n          if (_i2 >= _iterator2.length) break;\n          _ref2 = _iterator2[_i2++];\n        } else {\n          _i2 = _iterator2.next();\n          if (_i2.done) break;\n          _ref2 = _i2.value;\n        }\n\n        var op = _ref2;\n\n        len += CFFOperand.size(op);\n      }\n\n      var key = Array.isArray(field[0]) ? field[0] : [field[0]];\n      len += key.length;\n    }\n\n    if (includePointers) {\n      len += ctx.pointerSize;\n    }\n\n    return len;\n  };\n\n  CFFDict.prototype.encode = function encode(stream, dict, parent) {\n    var ctx = {\n      pointers: [],\n      startOffset: stream.pos,\n      parent: parent,\n      val: dict,\n      pointerSize: 0\n    };\n\n    ctx.pointerOffset = stream.pos + this.size(dict, ctx, false);\n\n    for (var _iterator3 = this.ops, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n      var _ref3;\n\n      if (_isArray3) {\n        if (_i3 >= _iterator3.length) break;\n        _ref3 = _iterator3[_i3++];\n      } else {\n        _i3 = _iterator3.next();\n        if (_i3.done) break;\n        _ref3 = _i3.value;\n      }\n\n      var field = _ref3;\n\n      var val = dict[field[1]];\n      if (val == null || isEqual(val, field[3])) {\n        continue;\n      }\n\n      var operands = this.encodeOperands(field[2], stream, ctx, val);\n      for (var _iterator4 = operands, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _getIterator(_iterator4);;) {\n        var _ref4;\n\n        if (_isArray4) {\n          if (_i4 >= _iterator4.length) break;\n          _ref4 = _iterator4[_i4++];\n        } else {\n          _i4 = _iterator4.next();\n          if (_i4.done) break;\n          _ref4 = _i4.value;\n        }\n\n        var op = _ref4;\n\n        CFFOperand.encode(stream, op);\n      }\n\n      var key = Array.isArray(field[0]) ? field[0] : [field[0]];\n      for (var _iterator5 = key, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _getIterator(_iterator5);;) {\n        var _ref5;\n\n        if (_isArray5) {\n          if (_i5 >= _iterator5.length) break;\n          _ref5 = _iterator5[_i5++];\n        } else {\n          _i5 = _iterator5.next();\n          if (_i5.done) break;\n          _ref5 = _i5.value;\n        }\n\n        var _op = _ref5;\n\n        stream.writeUInt8(_op);\n      }\n    }\n\n    var i = 0;\n    while (i < ctx.pointers.length) {\n      var ptr = ctx.pointers[i++];\n      ptr.type.encode(stream, ptr.val, ptr.parent);\n    }\n\n    return;\n  };\n\n  return CFFDict;\n}();\n\nvar CFFPointer = function (_r$Pointer) {\n  _inherits(CFFPointer, _r$Pointer);\n\n  function CFFPointer(type) {\n    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n    _classCallCheck(this, CFFPointer);\n\n    if (options.type == null) {\n      options.type = 'global';\n    }\n\n    return _possibleConstructorReturn(this, _r$Pointer.call(this, null, type, options));\n  }\n\n  CFFPointer.prototype.decode = function decode(stream, parent, operands) {\n    this.offsetType = {\n      decode: function decode() {\n        return operands[0];\n      }\n    };\n\n    return _r$Pointer.prototype.decode.call(this, stream, parent, operands);\n  };\n\n  CFFPointer.prototype.encode = function encode(stream, value, ctx) {\n    if (!stream) {\n      // compute the size (so ctx.pointerSize is correct)\n      this.offsetType = {\n        size: function size() {\n          return 0;\n        }\n      };\n\n      this.size(value, ctx);\n      return [new Ptr(0)];\n    }\n\n    var ptr = null;\n    this.offsetType = {\n      encode: function encode(stream, val) {\n        return ptr = val;\n      }\n    };\n\n    _r$Pointer.prototype.encode.call(this, stream, value, ctx);\n    return [new Ptr(ptr)];\n  };\n\n  return CFFPointer;\n}(r.Pointer);\n\nvar Ptr = function () {\n  function Ptr(val) {\n    _classCallCheck(this, Ptr);\n\n    this.val = val;\n    this.forceLarge = true;\n  }\n\n  Ptr.prototype.valueOf = function valueOf() {\n    return this.val;\n  };\n\n  return Ptr;\n}();\n\nvar CFFBlendOp = function () {\n  function CFFBlendOp() {\n    _classCallCheck(this, CFFBlendOp);\n  }\n\n  CFFBlendOp.decode = function decode(stream, parent, operands) {\n    var numBlends = operands.pop();\n\n    // TODO: actually blend. For now just consume the deltas\n    // since we don't use any of the values anyway.\n    while (operands.length > numBlends) {\n      operands.pop();\n    }\n  };\n\n  return CFFBlendOp;\n}();\n\nvar CFFPrivateDict = new CFFDict([\n// key       name                    type                                          default\n[6, 'BlueValues', 'delta', null], [7, 'OtherBlues', 'delta', null], [8, 'FamilyBlues', 'delta', null], [9, 'FamilyOtherBlues', 'delta', null], [[12, 9], 'BlueScale', 'number', 0.039625], [[12, 10], 'BlueShift', 'number', 7], [[12, 11], 'BlueFuzz', 'number', 1], [10, 'StdHW', 'number', null], [11, 'StdVW', 'number', null], [[12, 12], 'StemSnapH', 'delta', null], [[12, 13], 'StemSnapV', 'delta', null], [[12, 14], 'ForceBold', 'boolean', false], [[12, 17], 'LanguageGroup', 'number', 0], [[12, 18], 'ExpansionFactor', 'number', 0.06], [[12, 19], 'initialRandomSeed', 'number', 0], [20, 'defaultWidthX', 'number', 0], [21, 'nominalWidthX', 'number', 0], [22, 'vsindex', 'number', 0], [23, 'blend', CFFBlendOp, null], [19, 'Subrs', new CFFPointer(new CFFIndex(), { type: 'local' }), null]]);\n\n// Automatically generated from Appendix A of the CFF specification; do\n// not edit. Length should be 391.\nvar standardStrings = [\".notdef\", \"space\", \"exclam\", \"quotedbl\", \"numbersign\", \"dollar\", \"percent\", \"ampersand\", \"quoteright\", \"parenleft\", \"parenright\", \"asterisk\", \"plus\", \"comma\", \"hyphen\", \"period\", \"slash\", \"zero\", \"one\", \"two\", \"three\", \"four\", \"five\", \"six\", \"seven\", \"eight\", \"nine\", \"colon\", \"semicolon\", \"less\", \"equal\", \"greater\", \"question\", \"at\", \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\", \"J\", \"K\", \"L\", \"M\", \"N\", \"O\", \"P\", \"Q\", \"R\", \"S\", \"T\", \"U\", \"V\", \"W\", \"X\", \"Y\", \"Z\", \"bracketleft\", \"backslash\", \"bracketright\", \"asciicircum\", \"underscore\", \"quoteleft\", \"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\", \"i\", \"j\", \"k\", \"l\", \"m\", \"n\", \"o\", \"p\", \"q\", \"r\", \"s\", \"t\", \"u\", \"v\", \"w\", \"x\", \"y\", \"z\", \"braceleft\", \"bar\", \"braceright\", \"asciitilde\", \"exclamdown\", \"cent\", \"sterling\", \"fraction\", \"yen\", \"florin\", \"section\", \"currency\", \"quotesingle\", \"quotedblleft\", \"guillemotleft\", \"guilsinglleft\", \"guilsinglright\", \"fi\", \"fl\", \"endash\", \"dagger\", \"daggerdbl\", \"periodcentered\", \"paragraph\", \"bullet\", \"quotesinglbase\", \"quotedblbase\", \"quotedblright\", \"guillemotright\", \"ellipsis\", \"perthousand\", \"questiondown\", \"grave\", \"acute\", \"circumflex\", \"tilde\", \"macron\", \"breve\", \"dotaccent\", \"dieresis\", \"ring\", \"cedilla\", \"hungarumlaut\", \"ogonek\", \"caron\", \"emdash\", \"AE\", \"ordfeminine\", \"Lslash\", \"Oslash\", \"OE\", \"ordmasculine\", \"ae\", \"dotlessi\", \"lslash\", \"oslash\", \"oe\", \"germandbls\", \"onesuperior\", \"logicalnot\", \"mu\", \"trademark\", \"Eth\", \"onehalf\", \"plusminus\", \"Thorn\", \"onequarter\", \"divide\", \"brokenbar\", \"degree\", \"thorn\", \"threequarters\", \"twosuperior\", \"registered\", \"minus\", \"eth\", \"multiply\", \"threesuperior\", \"copyright\", \"Aacute\", \"Acircumflex\", \"Adieresis\", \"Agrave\", \"Aring\", \"Atilde\", \"Ccedilla\", \"Eacute\", \"Ecircumflex\", \"Edieresis\", \"Egrave\", \"Iacute\", \"Icircumflex\", \"Idieresis\", \"Igrave\", \"Ntilde\", \"Oacute\", \"Ocircumflex\", \"Odieresis\", \"Ograve\", \"Otilde\", \"Scaron\", \"Uacute\", \"Ucircumflex\", \"Udieresis\", \"Ugrave\", \"Yacute\", \"Ydieresis\", \"Zcaron\", \"aacute\", \"acircumflex\", \"adieresis\", \"agrave\", \"aring\", \"atilde\", \"ccedilla\", \"eacute\", \"ecircumflex\", \"edieresis\", \"egrave\", \"iacute\", \"icircumflex\", \"idieresis\", \"igrave\", \"ntilde\", \"oacute\", \"ocircumflex\", \"odieresis\", \"ograve\", \"otilde\", \"scaron\", \"uacute\", \"ucircumflex\", \"udieresis\", \"ugrave\", \"yacute\", \"ydieresis\", \"zcaron\", \"exclamsmall\", \"Hungarumlautsmall\", \"dollaroldstyle\", \"dollarsuperior\", \"ampersandsmall\", \"Acutesmall\", \"parenleftsuperior\", \"parenrightsuperior\", \"twodotenleader\", \"onedotenleader\", \"zerooldstyle\", \"oneoldstyle\", \"twooldstyle\", \"threeoldstyle\", \"fouroldstyle\", \"fiveoldstyle\", \"sixoldstyle\", \"sevenoldstyle\", \"eightoldstyle\", \"nineoldstyle\", \"commasuperior\", \"threequartersemdash\", \"periodsuperior\", \"questionsmall\", \"asuperior\", \"bsuperior\", \"centsuperior\", \"dsuperior\", \"esuperior\", \"isuperior\", \"lsuperior\", \"msuperior\", \"nsuperior\", \"osuperior\", \"rsuperior\", \"ssuperior\", \"tsuperior\", \"ff\", \"ffi\", \"ffl\", \"parenleftinferior\", \"parenrightinferior\", \"Circumflexsmall\", \"hyphensuperior\", \"Gravesmall\", \"Asmall\", \"Bsmall\", \"Csmall\", \"Dsmall\", \"Esmall\", \"Fsmall\", \"Gsmall\", \"Hsmall\", \"Ismall\", \"Jsmall\", \"Ksmall\", \"Lsmall\", \"Msmall\", \"Nsmall\", \"Osmall\", \"Psmall\", \"Qsmall\", \"Rsmall\", \"Ssmall\", \"Tsmall\", \"Usmall\", \"Vsmall\", \"Wsmall\", \"Xsmall\", \"Ysmall\", \"Zsmall\", \"colonmonetary\", \"onefitted\", \"rupiah\", \"Tildesmall\", \"exclamdownsmall\", \"centoldstyle\", \"Lslashsmall\", \"Scaronsmall\", \"Zcaronsmall\", \"Dieresissmall\", \"Brevesmall\", \"Caronsmall\", \"Dotaccentsmall\", \"Macronsmall\", \"figuredash\", \"hypheninferior\", \"Ogoneksmall\", \"Ringsmall\", \"Cedillasmall\", \"questiondownsmall\", \"oneeighth\", \"threeeighths\", \"fiveeighths\", \"seveneighths\", \"onethird\", \"twothirds\", \"zerosuperior\", \"foursuperior\", \"fivesuperior\", \"sixsuperior\", \"sevensuperior\", \"eightsuperior\", \"ninesuperior\", \"zeroinferior\", \"oneinferior\", \"twoinferior\", \"threeinferior\", \"fourinferior\", \"fiveinferior\", \"sixinferior\", \"seveninferior\", \"eightinferior\", \"nineinferior\", \"centinferior\", \"dollarinferior\", \"periodinferior\", \"commainferior\", \"Agravesmall\", \"Aacutesmall\", \"Acircumflexsmall\", \"Atildesmall\", \"Adieresissmall\", \"Aringsmall\", \"AEsmall\", \"Ccedillasmall\", \"Egravesmall\", \"Eacutesmall\", \"Ecircumflexsmall\", \"Edieresissmall\", \"Igravesmall\", \"Iacutesmall\", \"Icircumflexsmall\", \"Idieresissmall\", \"Ethsmall\", \"Ntildesmall\", \"Ogravesmall\", \"Oacutesmall\", \"Ocircumflexsmall\", \"Otildesmall\", \"Odieresissmall\", \"OEsmall\", \"Oslashsmall\", \"Ugravesmall\", \"Uacutesmall\", \"Ucircumflexsmall\", \"Udieresissmall\", \"Yacutesmall\", \"Thornsmall\", \"Ydieresissmall\", \"001.000\", \"001.001\", \"001.002\", \"001.003\", \"Black\", \"Bold\", \"Book\", \"Light\", \"Medium\", \"Regular\", \"Roman\", \"Semibold\"];\n\nvar StandardEncoding = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', 'daggerdbl', 'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla', '', 'hungarumlaut', 'ogonek', 'caron', 'emdash', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '', '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae', '', '', '', 'dotlessi', '', '', 'lslash', 'oslash', 'oe', 'germandbls'];\n\nvar ExpertEncoding = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', '', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior', '', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '', 'figuredash', 'hypheninferior', '', '', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters', 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', '', '', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall'];\n\nvar ISOAdobeCharset = ['.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl', 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', 'yacute', 'ydieresis', 'zcaron'];\n\nvar ExpertCharset = ['.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 'onequarter', 'onehalf', 'threequarters', 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall'];\n\nvar ExpertSubsetCharset = ['.notdef', 'space', 'dollaroldstyle', 'dollarsuperior', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted', 'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter', 'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior'];\n\n//########################\n// Scripts and Languages #\n//########################\n\nvar LangSysTable = new r.Struct({\n  reserved: new r.Reserved(r.uint16),\n  reqFeatureIndex: r.uint16,\n  featureCount: r.uint16,\n  featureIndexes: new r.Array(r.uint16, 'featureCount')\n});\n\nvar LangSysRecord = new r.Struct({\n  tag: new r.String(4),\n  langSys: new r.Pointer(r.uint16, LangSysTable, { type: 'parent' })\n});\n\nvar Script = new r.Struct({\n  defaultLangSys: new r.Pointer(r.uint16, LangSysTable),\n  count: r.uint16,\n  langSysRecords: new r.Array(LangSysRecord, 'count')\n});\n\nvar ScriptRecord = new r.Struct({\n  tag: new r.String(4),\n  script: new r.Pointer(r.uint16, Script, { type: 'parent' })\n});\n\nvar ScriptList = new r.Array(ScriptRecord, r.uint16);\n\n//#######################\n// Features and Lookups #\n//#######################\n\nvar Feature = new r.Struct({\n  featureParams: r.uint16, // pointer\n  lookupCount: r.uint16,\n  lookupListIndexes: new r.Array(r.uint16, 'lookupCount')\n});\n\nvar FeatureRecord = new r.Struct({\n  tag: new r.String(4),\n  feature: new r.Pointer(r.uint16, Feature, { type: 'parent' })\n});\n\nvar FeatureList = new r.Array(FeatureRecord, r.uint16);\n\nvar LookupFlags = new r.Struct({\n  markAttachmentType: r.uint8,\n  flags: new r.Bitfield(r.uint8, ['rightToLeft', 'ignoreBaseGlyphs', 'ignoreLigatures', 'ignoreMarks', 'useMarkFilteringSet'])\n});\n\nfunction LookupList(SubTable) {\n  var Lookup = new r.Struct({\n    lookupType: r.uint16,\n    flags: LookupFlags,\n    subTableCount: r.uint16,\n    subTables: new r.Array(new r.Pointer(r.uint16, SubTable), 'subTableCount'),\n    markFilteringSet: new r.Optional(r.uint16, function (t) {\n      return t.flags.flags.useMarkFilteringSet;\n    })\n  });\n\n  return new r.LazyArray(new r.Pointer(r.uint16, Lookup), r.uint16);\n}\n\n//#################\n// Coverage Table #\n//#################\n\nvar RangeRecord = new r.Struct({\n  start: r.uint16,\n  end: r.uint16,\n  startCoverageIndex: r.uint16\n});\n\nvar Coverage = new r.VersionedStruct(r.uint16, {\n  1: {\n    glyphCount: r.uint16,\n    glyphs: new r.Array(r.uint16, 'glyphCount')\n  },\n  2: {\n    rangeCount: r.uint16,\n    rangeRecords: new r.Array(RangeRecord, 'rangeCount')\n  }\n});\n\n//#########################\n// Class Definition Table #\n//#########################\n\nvar ClassRangeRecord = new r.Struct({\n  start: r.uint16,\n  end: r.uint16,\n  class: r.uint16\n});\n\nvar ClassDef = new r.VersionedStruct(r.uint16, {\n  1: { // Class array\n    startGlyph: r.uint16,\n    glyphCount: r.uint16,\n    classValueArray: new r.Array(r.uint16, 'glyphCount')\n  },\n  2: { // Class ranges\n    classRangeCount: r.uint16,\n    classRangeRecord: new r.Array(ClassRangeRecord, 'classRangeCount')\n  }\n});\n\n//###############\n// Device Table #\n//###############\n\nvar Device = new r.Struct({\n  a: r.uint16, // startSize for hinting Device, outerIndex for VariationIndex\n  b: r.uint16, // endSize for Device, innerIndex for VariationIndex\n  deltaFormat: r.uint16\n});\n\n//#############################################\n// Contextual Substitution/Positioning Tables #\n//#############################################\n\nvar LookupRecord = new r.Struct({\n  sequenceIndex: r.uint16,\n  lookupListIndex: r.uint16\n});\n\nvar Rule = new r.Struct({\n  glyphCount: r.uint16,\n  lookupCount: r.uint16,\n  input: new r.Array(r.uint16, function (t) {\n    return t.glyphCount - 1;\n  }),\n  lookupRecords: new r.Array(LookupRecord, 'lookupCount')\n});\n\nvar RuleSet = new r.Array(new r.Pointer(r.uint16, Rule), r.uint16);\n\nvar ClassRule = new r.Struct({\n  glyphCount: r.uint16,\n  lookupCount: r.uint16,\n  classes: new r.Array(r.uint16, function (t) {\n    return t.glyphCount - 1;\n  }),\n  lookupRecords: new r.Array(LookupRecord, 'lookupCount')\n});\n\nvar ClassSet = new r.Array(new r.Pointer(r.uint16, ClassRule), r.uint16);\n\nvar Context = new r.VersionedStruct(r.uint16, {\n  1: { // Simple context\n    coverage: new r.Pointer(r.uint16, Coverage),\n    ruleSetCount: r.uint16,\n    ruleSets: new r.Array(new r.Pointer(r.uint16, RuleSet), 'ruleSetCount')\n  },\n  2: { // Class-based context\n    coverage: new r.Pointer(r.uint16, Coverage),\n    classDef: new r.Pointer(r.uint16, ClassDef),\n    classSetCnt: r.uint16,\n    classSet: new r.Array(new r.Pointer(r.uint16, ClassSet), 'classSetCnt')\n  },\n  3: {\n    glyphCount: r.uint16,\n    lookupCount: r.uint16,\n    coverages: new r.Array(new r.Pointer(r.uint16, Coverage), 'glyphCount'),\n    lookupRecords: new r.Array(LookupRecord, 'lookupCount')\n  }\n});\n\n//######################################################\n// Chaining Contextual Substitution/Positioning Tables #\n//######################################################\n\nvar ChainRule = new r.Struct({\n  backtrackGlyphCount: r.uint16,\n  backtrack: new r.Array(r.uint16, 'backtrackGlyphCount'),\n  inputGlyphCount: r.uint16,\n  input: new r.Array(r.uint16, function (t) {\n    return t.inputGlyphCount - 1;\n  }),\n  lookaheadGlyphCount: r.uint16,\n  lookahead: new r.Array(r.uint16, 'lookaheadGlyphCount'),\n  lookupCount: r.uint16,\n  lookupRecords: new r.Array(LookupRecord, 'lookupCount')\n});\n\nvar ChainRuleSet = new r.Array(new r.Pointer(r.uint16, ChainRule), r.uint16);\n\nvar ChainingContext = new r.VersionedStruct(r.uint16, {\n  1: { // Simple context glyph substitution\n    coverage: new r.Pointer(r.uint16, Coverage),\n    chainCount: r.uint16,\n    chainRuleSets: new r.Array(new r.Pointer(r.uint16, ChainRuleSet), 'chainCount')\n  },\n\n  2: { // Class-based chaining context\n    coverage: new r.Pointer(r.uint16, Coverage),\n    backtrackClassDef: new r.Pointer(r.uint16, ClassDef),\n    inputClassDef: new r.Pointer(r.uint16, ClassDef),\n    lookaheadClassDef: new r.Pointer(r.uint16, ClassDef),\n    chainCount: r.uint16,\n    chainClassSet: new r.Array(new r.Pointer(r.uint16, ChainRuleSet), 'chainCount')\n  },\n\n  3: { // Coverage-based chaining context\n    backtrackGlyphCount: r.uint16,\n    backtrackCoverage: new r.Array(new r.Pointer(r.uint16, Coverage), 'backtrackGlyphCount'),\n    inputGlyphCount: r.uint16,\n    inputCoverage: new r.Array(new r.Pointer(r.uint16, Coverage), 'inputGlyphCount'),\n    lookaheadGlyphCount: r.uint16,\n    lookaheadCoverage: new r.Array(new r.Pointer(r.uint16, Coverage), 'lookaheadGlyphCount'),\n    lookupCount: r.uint16,\n    lookupRecords: new r.Array(LookupRecord, 'lookupCount')\n  }\n});\n\nvar _;\n\n/*******************\n * Variation Store *\n *******************/\n\nvar F2DOT14 = new r.Fixed(16, 'BE', 14);\nvar RegionAxisCoordinates = new r.Struct({\n  startCoord: F2DOT14,\n  peakCoord: F2DOT14,\n  endCoord: F2DOT14\n});\n\nvar VariationRegionList = new r.Struct({\n  axisCount: r.uint16,\n  regionCount: r.uint16,\n  variationRegions: new r.Array(new r.Array(RegionAxisCoordinates, 'axisCount'), 'regionCount')\n});\n\nvar DeltaSet = new r.Struct({\n  shortDeltas: new r.Array(r.int16, function (t) {\n    return t.parent.shortDeltaCount;\n  }),\n  regionDeltas: new r.Array(r.int8, function (t) {\n    return t.parent.regionIndexCount - t.parent.shortDeltaCount;\n  }),\n  deltas: function deltas(t) {\n    return t.shortDeltas.concat(t.regionDeltas);\n  }\n});\n\nvar ItemVariationData = new r.Struct({\n  itemCount: r.uint16,\n  shortDeltaCount: r.uint16,\n  regionIndexCount: r.uint16,\n  regionIndexes: new r.Array(r.uint16, 'regionIndexCount'),\n  deltaSets: new r.Array(DeltaSet, 'itemCount')\n});\n\nvar ItemVariationStore = new r.Struct({\n  format: r.uint16,\n  variationRegionList: new r.Pointer(r.uint32, VariationRegionList),\n  variationDataCount: r.uint16,\n  itemVariationData: new r.Array(new r.Pointer(r.uint32, ItemVariationData), 'variationDataCount')\n});\n\n/**********************\n * Feature Variations *\n **********************/\n\nvar ConditionTable = new r.VersionedStruct(r.uint16, {\n  1: (_ = {\n    axisIndex: r.uint16\n  }, _['axisIndex'] = r.uint16, _.filterRangeMinValue = F2DOT14, _.filterRangeMaxValue = F2DOT14, _)\n});\n\nvar ConditionSet = new r.Struct({\n  conditionCount: r.uint16,\n  conditionTable: new r.Array(new r.Pointer(r.uint32, ConditionTable), 'conditionCount')\n});\n\nvar FeatureTableSubstitutionRecord = new r.Struct({\n  featureIndex: r.uint16,\n  alternateFeatureTable: new r.Pointer(r.uint32, Feature, { type: 'parent' })\n});\n\nvar FeatureTableSubstitution = new r.Struct({\n  version: r.fixed32,\n  substitutionCount: r.uint16,\n  substitutions: new r.Array(FeatureTableSubstitutionRecord, 'substitutionCount')\n});\n\nvar FeatureVariationRecord = new r.Struct({\n  conditionSet: new r.Pointer(r.uint32, ConditionSet, { type: 'parent' }),\n  featureTableSubstitution: new r.Pointer(r.uint32, FeatureTableSubstitution, { type: 'parent' })\n});\n\nvar FeatureVariations = new r.Struct({\n  majorVersion: r.uint16,\n  minorVersion: r.uint16,\n  featureVariationRecordCount: r.uint32,\n  featureVariationRecords: new r.Array(FeatureVariationRecord, 'featureVariationRecordCount')\n});\n\n// Checks if an operand is an index of a predefined value,\n// otherwise delegates to the provided type.\n\nvar PredefinedOp = function () {\n  function PredefinedOp(predefinedOps, type) {\n    _classCallCheck(this, PredefinedOp);\n\n    this.predefinedOps = predefinedOps;\n    this.type = type;\n  }\n\n  PredefinedOp.prototype.decode = function decode(stream, parent, operands) {\n    if (this.predefinedOps[operands[0]]) {\n      return this.predefinedOps[operands[0]];\n    }\n\n    return this.type.decode(stream, parent, operands);\n  };\n\n  PredefinedOp.prototype.size = function size(value, ctx) {\n    return this.type.size(value, ctx);\n  };\n\n  PredefinedOp.prototype.encode = function encode(stream, value, ctx) {\n    var index = this.predefinedOps.indexOf(value);\n    if (index !== -1) {\n      return index;\n    }\n\n    return this.type.encode(stream, value, ctx);\n  };\n\n  return PredefinedOp;\n}();\n\nvar CFFEncodingVersion = function (_r$Number) {\n  _inherits(CFFEncodingVersion, _r$Number);\n\n  function CFFEncodingVersion() {\n    _classCallCheck(this, CFFEncodingVersion);\n\n    return _possibleConstructorReturn(this, _r$Number.call(this, 'UInt8'));\n  }\n\n  CFFEncodingVersion.prototype.decode = function decode(stream) {\n    return r.uint8.decode(stream) & 0x7f;\n  };\n\n  return CFFEncodingVersion;\n}(r.Number);\n\nvar Range1 = new r.Struct({\n  first: r.uint16,\n  nLeft: r.uint8\n});\n\nvar Range2 = new r.Struct({\n  first: r.uint16,\n  nLeft: r.uint16\n});\n\nvar CFFCustomEncoding = new r.VersionedStruct(new CFFEncodingVersion(), {\n  0: {\n    nCodes: r.uint8,\n    codes: new r.Array(r.uint8, 'nCodes')\n  },\n\n  1: {\n    nRanges: r.uint8,\n    ranges: new r.Array(Range1, 'nRanges')\n  }\n\n  // TODO: supplement?\n});\n\nvar CFFEncoding = new PredefinedOp([StandardEncoding, ExpertEncoding], new CFFPointer(CFFCustomEncoding, { lazy: true }));\n\n// Decodes an array of ranges until the total\n// length is equal to the provided length.\n\nvar RangeArray = function (_r$Array) {\n  _inherits(RangeArray, _r$Array);\n\n  function RangeArray() {\n    _classCallCheck(this, RangeArray);\n\n    return _possibleConstructorReturn(this, _r$Array.apply(this, arguments));\n  }\n\n  RangeArray.prototype.decode = function decode(stream, parent) {\n    var length = restructure_src_utils.resolveLength(this.length, stream, parent);\n    var count = 0;\n    var res = [];\n    while (count < length) {\n      var range = this.type.decode(stream, parent);\n      range.offset = count;\n      count += range.nLeft + 1;\n      res.push(range);\n    }\n\n    return res;\n  };\n\n  return RangeArray;\n}(r.Array);\n\nvar CFFCustomCharset = new r.VersionedStruct(r.uint8, {\n  0: {\n    glyphs: new r.Array(r.uint16, function (t) {\n      return t.parent.CharStrings.length - 1;\n    })\n  },\n\n  1: {\n    ranges: new RangeArray(Range1, function (t) {\n      return t.parent.CharStrings.length - 1;\n    })\n  },\n\n  2: {\n    ranges: new RangeArray(Range2, function (t) {\n      return t.parent.CharStrings.length - 1;\n    })\n  }\n});\n\nvar CFFCharset = new PredefinedOp([ISOAdobeCharset, ExpertCharset, ExpertSubsetCharset], new CFFPointer(CFFCustomCharset, { lazy: true }));\n\nvar FDRange3 = new r.Struct({\n  first: r.uint16,\n  fd: r.uint8\n});\n\nvar FDRange4 = new r.Struct({\n  first: r.uint32,\n  fd: r.uint16\n});\n\nvar FDSelect = new r.VersionedStruct(r.uint8, {\n  0: {\n    fds: new r.Array(r.uint8, function (t) {\n      return t.parent.CharStrings.length;\n    })\n  },\n\n  3: {\n    nRanges: r.uint16,\n    ranges: new r.Array(FDRange3, 'nRanges'),\n    sentinel: r.uint16\n  },\n\n  4: {\n    nRanges: r.uint32,\n    ranges: new r.Array(FDRange4, 'nRanges'),\n    sentinel: r.uint32\n  }\n});\n\nvar ptr = new CFFPointer(CFFPrivateDict);\n\nvar CFFPrivateOp = function () {\n  function CFFPrivateOp() {\n    _classCallCheck(this, CFFPrivateOp);\n  }\n\n  CFFPrivateOp.prototype.decode = function decode(stream, parent, operands) {\n    parent.length = operands[0];\n    return ptr.decode(stream, parent, [operands[1]]);\n  };\n\n  CFFPrivateOp.prototype.size = function size(dict, ctx) {\n    return [CFFPrivateDict.size(dict, ctx, false), ptr.size(dict, ctx)[0]];\n  };\n\n  CFFPrivateOp.prototype.encode = function encode(stream, dict, ctx) {\n    return [CFFPrivateDict.size(dict, ctx, false), ptr.encode(stream, dict, ctx)[0]];\n  };\n\n  return CFFPrivateOp;\n}();\n\nvar FontDict = new CFFDict([\n// key       name                   type(s)                                 default\n[18, 'Private', new CFFPrivateOp(), null], [[12, 38], 'FontName', 'sid', null]]);\n\nvar CFFTopDict = new CFFDict([\n// key       name                   type(s)                                 default\n[[12, 30], 'ROS', ['sid', 'sid', 'number'], null], [0, 'version', 'sid', null], [1, 'Notice', 'sid', null], [[12, 0], 'Copyright', 'sid', null], [2, 'FullName', 'sid', null], [3, 'FamilyName', 'sid', null], [4, 'Weight', 'sid', null], [[12, 1], 'isFixedPitch', 'boolean', false], [[12, 2], 'ItalicAngle', 'number', 0], [[12, 3], 'UnderlinePosition', 'number', -100], [[12, 4], 'UnderlineThickness', 'number', 50], [[12, 5], 'PaintType', 'number', 0], [[12, 6], 'CharstringType', 'number', 2], [[12, 7], 'FontMatrix', 'array', [0.001, 0, 0, 0.001, 0, 0]], [13, 'UniqueID', 'number', null], [5, 'FontBBox', 'array', [0, 0, 0, 0]], [[12, 8], 'StrokeWidth', 'number', 0], [14, 'XUID', 'array', null], [15, 'charset', CFFCharset, ISOAdobeCharset], [16, 'Encoding', CFFEncoding, StandardEncoding], [17, 'CharStrings', new CFFPointer(new CFFIndex()), null], [18, 'Private', new CFFPrivateOp(), null], [[12, 20], 'SyntheticBase', 'number', null], [[12, 21], 'PostScript', 'sid', null], [[12, 22], 'BaseFontName', 'sid', null], [[12, 23], 'BaseFontBlend', 'delta', null],\n\n// CID font specific\n[[12, 31], 'CIDFontVersion', 'number', 0], [[12, 32], 'CIDFontRevision', 'number', 0], [[12, 33], 'CIDFontType', 'number', 0], [[12, 34], 'CIDCount', 'number', 8720], [[12, 35], 'UIDBase', 'number', null], [[12, 37], 'FDSelect', new CFFPointer(FDSelect), null], [[12, 36], 'FDArray', new CFFPointer(new CFFIndex(FontDict)), null], [[12, 38], 'FontName', 'sid', null]]);\n\nvar VariationStore = new r.Struct({\n  length: r.uint16,\n  itemVariationStore: ItemVariationStore\n});\n\nvar CFF2TopDict = new CFFDict([[[12, 7], 'FontMatrix', 'array', [0.001, 0, 0, 0.001, 0, 0]], [17, 'CharStrings', new CFFPointer(new CFFIndex()), null], [[12, 37], 'FDSelect', new CFFPointer(FDSelect), null], [[12, 36], 'FDArray', new CFFPointer(new CFFIndex(FontDict)), null], [24, 'vstore', new CFFPointer(VariationStore), null], [25, 'maxstack', 'number', 193]]);\n\nvar CFFTop = new r.VersionedStruct(r.fixed16, {\n  1: {\n    hdrSize: r.uint8,\n    offSize: r.uint8,\n    nameIndex: new CFFIndex(new r.String('length')),\n    topDictIndex: new CFFIndex(CFFTopDict),\n    stringIndex: new CFFIndex(new r.String('length')),\n    globalSubrIndex: new CFFIndex()\n  },\n\n  2: {\n    hdrSize: r.uint8,\n    length: r.uint16,\n    topDict: CFF2TopDict,\n    globalSubrIndex: new CFFIndex()\n  }\n});\n\nvar CFFFont = function () {\n  function CFFFont(stream) {\n    _classCallCheck(this, CFFFont);\n\n    this.stream = stream;\n    this.decode();\n  }\n\n  CFFFont.decode = function decode(stream) {\n    return new CFFFont(stream);\n  };\n\n  CFFFont.prototype.decode = function decode() {\n    var start = this.stream.pos;\n    var top = CFFTop.decode(this.stream);\n    for (var key in top) {\n      var val = top[key];\n      this[key] = val;\n    }\n\n    if (this.version < 2) {\n      if (this.topDictIndex.length !== 1) {\n        throw new Error(\"Only a single font is allowed in CFF\");\n      }\n\n      this.topDict = this.topDictIndex[0];\n    }\n\n    this.isCIDFont = this.topDict.ROS != null;\n    return this;\n  };\n\n  CFFFont.prototype.string = function string(sid) {\n    if (this.version >= 2) {\n      return null;\n    }\n\n    if (sid < standardStrings.length) {\n      return standardStrings[sid];\n    }\n\n    return this.stringIndex[sid - standardStrings.length];\n  };\n\n  CFFFont.prototype.getCharString = function getCharString(glyph) {\n    this.stream.pos = this.topDict.CharStrings[glyph].offset;\n    return this.stream.readBuffer(this.topDict.CharStrings[glyph].length);\n  };\n\n  CFFFont.prototype.getGlyphName = function getGlyphName(gid) {\n    // CFF2 glyph names are in the post table.\n    if (this.version >= 2) {\n      return null;\n    }\n\n    // CID-keyed fonts don't have glyph names\n    if (this.isCIDFont) {\n      return null;\n    }\n\n    var charset = this.topDict.charset;\n\n    if (Array.isArray(charset)) {\n      return charset[gid];\n    }\n\n    if (gid === 0) {\n      return '.notdef';\n    }\n\n    gid -= 1;\n\n    switch (charset.version) {\n      case 0:\n        return this.string(charset.glyphs[gid]);\n\n      case 1:\n      case 2:\n        for (var i = 0; i < charset.ranges.length; i++) {\n          var range = charset.ranges[i];\n          if (range.offset <= gid && gid <= range.offset + range.nLeft) {\n            return this.string(range.first + (gid - range.offset));\n          }\n        }\n        break;\n    }\n\n    return null;\n  };\n\n  CFFFont.prototype.fdForGlyph = function fdForGlyph(gid) {\n    if (!this.topDict.FDSelect) {\n      return null;\n    }\n\n    switch (this.topDict.FDSelect.version) {\n      case 0:\n        return this.topDict.FDSelect.fds[gid];\n\n      case 3:\n      case 4:\n        var ranges = this.topDict.FDSelect.ranges;\n\n        var low = 0;\n        var high = ranges.length - 1;\n\n        while (low <= high) {\n          var mid = low + high >> 1;\n\n          if (gid < ranges[mid].first) {\n            high = mid - 1;\n          } else if (mid < high && gid > ranges[mid + 1].first) {\n            low = mid + 1;\n          } else {\n            return ranges[mid].fd;\n          }\n        }\n      default:\n        throw new Error('Unknown FDSelect version: ' + this.topDict.FDSelect.version);\n    }\n  };\n\n  CFFFont.prototype.privateDictForGlyph = function privateDictForGlyph(gid) {\n    if (this.topDict.FDSelect) {\n      var fd = this.fdForGlyph(gid);\n      if (this.topDict.FDArray[fd]) {\n        return this.topDict.FDArray[fd].Private;\n      }\n\n      return null;\n    }\n\n    if (this.version < 2) {\n      return this.topDict.Private;\n    }\n\n    return this.topDict.FDArray[0].Private;\n  };\n\n  _createClass(CFFFont, [{\n    key: 'postscriptName',\n    get: function get() {\n      if (this.version < 2) {\n        return this.nameIndex[0];\n      }\n\n      return null;\n    }\n  }, {\n    key: 'fullName',\n    get: function get() {\n      return this.string(this.topDict.FullName);\n    }\n  }, {\n    key: 'familyName',\n    get: function get() {\n      return this.string(this.topDict.FamilyName);\n    }\n  }]);\n\n  return CFFFont;\n}();\n\nvar VerticalOrigin = new r.Struct({\n  glyphIndex: r.uint16,\n  vertOriginY: r.int16\n});\n\nvar VORG = new r.Struct({\n  majorVersion: r.uint16,\n  minorVersion: r.uint16,\n  defaultVertOriginY: r.int16,\n  numVertOriginYMetrics: r.uint16,\n  metrics: new r.Array(VerticalOrigin, 'numVertOriginYMetrics')\n});\n\nvar BigMetrics = new r.Struct({\n  height: r.uint8,\n  width: r.uint8,\n  horiBearingX: r.int8,\n  horiBearingY: r.int8,\n  horiAdvance: r.uint8,\n  vertBearingX: r.int8,\n  vertBearingY: r.int8,\n  vertAdvance: r.uint8\n});\n\nvar SmallMetrics = new r.Struct({\n  height: r.uint8,\n  width: r.uint8,\n  bearingX: r.int8,\n  bearingY: r.int8,\n  advance: r.uint8\n});\n\nvar EBDTComponent = new r.Struct({\n  glyph: r.uint16,\n  xOffset: r.int8,\n  yOffset: r.int8\n});\n\nvar ByteAligned = function ByteAligned() {\n  _classCallCheck(this, ByteAligned);\n};\n\nvar BitAligned = function BitAligned() {\n  _classCallCheck(this, BitAligned);\n};\n\nvar glyph = new r.VersionedStruct('version', {\n  1: {\n    metrics: SmallMetrics,\n    data: ByteAligned\n  },\n\n  2: {\n    metrics: SmallMetrics,\n    data: BitAligned\n  },\n\n  // format 3 is deprecated\n  // format 4 is not supported by Microsoft\n\n  5: {\n    data: BitAligned\n  },\n\n  6: {\n    metrics: BigMetrics,\n    data: ByteAligned\n  },\n\n  7: {\n    metrics: BigMetrics,\n    data: BitAligned\n  },\n\n  8: {\n    metrics: SmallMetrics,\n    pad: new r.Reserved(r.uint8),\n    numComponents: r.uint16,\n    components: new r.Array(EBDTComponent, 'numComponents')\n  },\n\n  9: {\n    metrics: BigMetrics,\n    pad: new r.Reserved(r.uint8),\n    numComponents: r.uint16,\n    components: new r.Array(EBDTComponent, 'numComponents')\n  },\n\n  17: {\n    metrics: SmallMetrics,\n    dataLen: r.uint32,\n    data: new r.Buffer('dataLen')\n  },\n\n  18: {\n    metrics: BigMetrics,\n    dataLen: r.uint32,\n    data: new r.Buffer('dataLen')\n  },\n\n  19: {\n    dataLen: r.uint32,\n    data: new r.Buffer('dataLen')\n  }\n});\n\nvar SBitLineMetrics = new r.Struct({\n  ascender: r.int8,\n  descender: r.int8,\n  widthMax: r.uint8,\n  caretSlopeNumerator: r.int8,\n  caretSlopeDenominator: r.int8,\n  caretOffset: r.int8,\n  minOriginSB: r.int8,\n  minAdvanceSB: r.int8,\n  maxBeforeBL: r.int8,\n  minAfterBL: r.int8,\n  pad: new r.Reserved(r.int8, 2)\n});\n\nvar CodeOffsetPair = new r.Struct({\n  glyphCode: r.uint16,\n  offset: r.uint16\n});\n\nvar IndexSubtable = new r.VersionedStruct(r.uint16, {\n  header: {\n    imageFormat: r.uint16,\n    imageDataOffset: r.uint32\n  },\n\n  1: {\n    offsetArray: new r.Array(r.uint32, function (t) {\n      return t.parent.lastGlyphIndex - t.parent.firstGlyphIndex + 1;\n    })\n  },\n\n  2: {\n    imageSize: r.uint32,\n    bigMetrics: BigMetrics\n  },\n\n  3: {\n    offsetArray: new r.Array(r.uint16, function (t) {\n      return t.parent.lastGlyphIndex - t.parent.firstGlyphIndex + 1;\n    })\n  },\n\n  4: {\n    numGlyphs: r.uint32,\n    glyphArray: new r.Array(CodeOffsetPair, function (t) {\n      return t.numGlyphs + 1;\n    })\n  },\n\n  5: {\n    imageSize: r.uint32,\n    bigMetrics: BigMetrics,\n    numGlyphs: r.uint32,\n    glyphCodeArray: new r.Array(r.uint16, 'numGlyphs')\n  }\n});\n\nvar IndexSubtableArray = new r.Struct({\n  firstGlyphIndex: r.uint16,\n  lastGlyphIndex: r.uint16,\n  subtable: new r.Pointer(r.uint32, IndexSubtable)\n});\n\nvar BitmapSizeTable = new r.Struct({\n  indexSubTableArray: new r.Pointer(r.uint32, new r.Array(IndexSubtableArray, 1), { type: 'parent' }),\n  indexTablesSize: r.uint32,\n  numberOfIndexSubTables: r.uint32,\n  colorRef: r.uint32,\n  hori: SBitLineMetrics,\n  vert: SBitLineMetrics,\n  startGlyphIndex: r.uint16,\n  endGlyphIndex: r.uint16,\n  ppemX: r.uint8,\n  ppemY: r.uint8,\n  bitDepth: r.uint8,\n  flags: new r.Bitfield(r.uint8, ['horizontal', 'vertical'])\n});\n\nvar EBLC = new r.Struct({\n  version: r.uint32, // 0x00020000\n  numSizes: r.uint32,\n  sizes: new r.Array(BitmapSizeTable, 'numSizes')\n});\n\nvar ImageTable = new r.Struct({\n  ppem: r.uint16,\n  resolution: r.uint16,\n  imageOffsets: new r.Array(new r.Pointer(r.uint32, 'void'), function (t) {\n    return t.parent.parent.maxp.numGlyphs + 1;\n  })\n});\n\n// This is the Apple sbix table, used by the \"Apple Color Emoji\" font.\n// It includes several image tables with images for each bitmap glyph\n// of several different sizes.\nvar sbix = new r.Struct({\n  version: r.uint16,\n  flags: new r.Bitfield(r.uint16, ['renderOutlines']),\n  numImgTables: r.uint32,\n  imageTables: new r.Array(new r.Pointer(r.uint32, ImageTable), 'numImgTables')\n});\n\nvar LayerRecord = new r.Struct({\n  gid: r.uint16, // Glyph ID of layer glyph (must be in z-order from bottom to top).\n  paletteIndex: r.uint16 // Index value to use in the appropriate palette. This value must\n}); // be less than numPaletteEntries in the CPAL table, except for\n// the special case noted below. Each palette entry is 16 bits.\n// A palette index of 0xFFFF is a special case indicating that\n// the text foreground color should be used.\n\nvar BaseGlyphRecord = new r.Struct({\n  gid: r.uint16, // Glyph ID of reference glyph. This glyph is for reference only\n  // and is not rendered for color.\n  firstLayerIndex: r.uint16, // Index (from beginning of the Layer Records) to the layer record.\n  // There will be numLayers consecutive entries for this base glyph.\n  numLayers: r.uint16\n});\n\nvar COLR = new r.Struct({\n  version: r.uint16,\n  numBaseGlyphRecords: r.uint16,\n  baseGlyphRecord: new r.Pointer(r.uint32, new r.Array(BaseGlyphRecord, 'numBaseGlyphRecords')),\n  layerRecords: new r.Pointer(r.uint32, new r.Array(LayerRecord, 'numLayerRecords'), { lazy: true }),\n  numLayerRecords: r.uint16\n});\n\nvar ColorRecord = new r.Struct({\n  blue: r.uint8,\n  green: r.uint8,\n  red: r.uint8,\n  alpha: r.uint8\n});\n\nvar CPAL = new r.VersionedStruct(r.uint16, {\n  header: {\n    numPaletteEntries: r.uint16,\n    numPalettes: r.uint16,\n    numColorRecords: r.uint16,\n    colorRecords: new r.Pointer(r.uint32, new r.Array(ColorRecord, 'numColorRecords')),\n    colorRecordIndices: new r.Array(r.uint16, 'numPalettes')\n  },\n  0: {},\n  1: {\n    offsetPaletteTypeArray: new r.Pointer(r.uint32, new r.Array(r.uint32, 'numPalettes')),\n    offsetPaletteLabelArray: new r.Pointer(r.uint32, new r.Array(r.uint16, 'numPalettes')),\n    offsetPaletteEntryLabelArray: new r.Pointer(r.uint32, new r.Array(r.uint16, 'numPaletteEntries'))\n  }\n});\n\nvar BaseCoord = new r.VersionedStruct(r.uint16, {\n  1: { // Design units only\n    coordinate: r.int16 // X or Y value, in design units\n  },\n\n  2: { // Design units plus contour point\n    coordinate: r.int16, // X or Y value, in design units\n    referenceGlyph: r.uint16, // GlyphID of control glyph\n    baseCoordPoint: r.uint16 // Index of contour point on the referenceGlyph\n  },\n\n  3: { // Design units plus Device table\n    coordinate: r.int16, // X or Y value, in design units\n    deviceTable: new r.Pointer(r.uint16, Device) // Device table for X or Y value\n  }\n});\n\nvar BaseValues = new r.Struct({\n  defaultIndex: r.uint16, // Index of default baseline for this script-same index in the BaseTagList\n  baseCoordCount: r.uint16,\n  baseCoords: new r.Array(new r.Pointer(r.uint16, BaseCoord), 'baseCoordCount')\n});\n\nvar FeatMinMaxRecord = new r.Struct({\n  tag: new r.String(4), // 4-byte feature identification tag-must match FeatureTag in FeatureList\n  minCoord: new r.Pointer(r.uint16, BaseCoord, { type: 'parent' }), // May be NULL\n  maxCoord: new r.Pointer(r.uint16, BaseCoord, { type: 'parent' }) // May be NULL\n});\n\nvar MinMax = new r.Struct({\n  minCoord: new r.Pointer(r.uint16, BaseCoord), // May be NULL\n  maxCoord: new r.Pointer(r.uint16, BaseCoord), // May be NULL\n  featMinMaxCount: r.uint16, // May be 0\n  featMinMaxRecords: new r.Array(FeatMinMaxRecord, 'featMinMaxCount') // In alphabetical order\n});\n\nvar BaseLangSysRecord = new r.Struct({\n  tag: new r.String(4), // 4-byte language system identification tag\n  minMax: new r.Pointer(r.uint16, MinMax, { type: 'parent' })\n});\n\nvar BaseScript = new r.Struct({\n  baseValues: new r.Pointer(r.uint16, BaseValues), // May be NULL\n  defaultMinMax: new r.Pointer(r.uint16, MinMax), // May be NULL\n  baseLangSysCount: r.uint16, // May be 0\n  baseLangSysRecords: new r.Array(BaseLangSysRecord, 'baseLangSysCount') // in alphabetical order by BaseLangSysTag\n});\n\nvar BaseScriptRecord = new r.Struct({\n  tag: new r.String(4), // 4-byte script identification tag\n  script: new r.Pointer(r.uint16, BaseScript, { type: 'parent' })\n});\n\nvar BaseScriptList = new r.Array(BaseScriptRecord, r.uint16);\n\n// Array of 4-byte baseline identification tags-must be in alphabetical order\nvar BaseTagList = new r.Array(new r.String(4), r.uint16);\n\nvar Axis = new r.Struct({\n  baseTagList: new r.Pointer(r.uint16, BaseTagList), // May be NULL\n  baseScriptList: new r.Pointer(r.uint16, BaseScriptList)\n});\n\nvar BASE = new r.VersionedStruct(r.uint32, {\n  header: {\n    horizAxis: new r.Pointer(r.uint16, Axis), // May be NULL\n    vertAxis: new r.Pointer(r.uint16, Axis) // May be NULL\n  },\n\n  0x00010000: {},\n  0x00010001: {\n    itemVariationStore: new r.Pointer(r.uint32, ItemVariationStore)\n  }\n});\n\nvar AttachPoint = new r.Array(r.uint16, r.uint16);\nvar AttachList = new r.Struct({\n  coverage: new r.Pointer(r.uint16, Coverage),\n  glyphCount: r.uint16,\n  attachPoints: new r.Array(new r.Pointer(r.uint16, AttachPoint), 'glyphCount')\n});\n\nvar CaretValue = new r.VersionedStruct(r.uint16, {\n  1: { // Design units only\n    coordinate: r.int16\n  },\n\n  2: { // Contour point\n    caretValuePoint: r.uint16\n  },\n\n  3: { // Design units plus Device table\n    coordinate: r.int16,\n    deviceTable: new r.Pointer(r.uint16, Device)\n  }\n});\n\nvar LigGlyph = new r.Array(new r.Pointer(r.uint16, CaretValue), r.uint16);\n\nvar LigCaretList = new r.Struct({\n  coverage: new r.Pointer(r.uint16, Coverage),\n  ligGlyphCount: r.uint16,\n  ligGlyphs: new r.Array(new r.Pointer(r.uint16, LigGlyph), 'ligGlyphCount')\n});\n\nvar MarkGlyphSetsDef = new r.Struct({\n  markSetTableFormat: r.uint16,\n  markSetCount: r.uint16,\n  coverage: new r.Array(new r.Pointer(r.uint32, Coverage), 'markSetCount')\n});\n\nvar GDEF = new r.VersionedStruct(r.uint32, {\n  header: {\n    glyphClassDef: new r.Pointer(r.uint16, ClassDef),\n    attachList: new r.Pointer(r.uint16, AttachList),\n    ligCaretList: new r.Pointer(r.uint16, LigCaretList),\n    markAttachClassDef: new r.Pointer(r.uint16, ClassDef)\n  },\n\n  0x00010000: {},\n  0x00010002: {\n    markGlyphSetsDef: new r.Pointer(r.uint16, MarkGlyphSetsDef)\n  },\n  0x00010003: {\n    markGlyphSetsDef: new r.Pointer(r.uint16, MarkGlyphSetsDef),\n    itemVariationStore: new r.Pointer(r.uint32, ItemVariationStore)\n  }\n});\n\nvar ValueFormat = new r.Bitfield(r.uint16, ['xPlacement', 'yPlacement', 'xAdvance', 'yAdvance', 'xPlaDevice', 'yPlaDevice', 'xAdvDevice', 'yAdvDevice']);\n\nvar types = {\n  xPlacement: r.int16,\n  yPlacement: r.int16,\n  xAdvance: r.int16,\n  yAdvance: r.int16,\n  xPlaDevice: new r.Pointer(r.uint16, Device, { type: 'global', relativeTo: 'rel' }),\n  yPlaDevice: new r.Pointer(r.uint16, Device, { type: 'global', relativeTo: 'rel' }),\n  xAdvDevice: new r.Pointer(r.uint16, Device, { type: 'global', relativeTo: 'rel' }),\n  yAdvDevice: new r.Pointer(r.uint16, Device, { type: 'global', relativeTo: 'rel' })\n};\n\nvar ValueRecord = function () {\n  function ValueRecord() {\n    var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'valueFormat';\n\n    _classCallCheck(this, ValueRecord);\n\n    this.key = key;\n  }\n\n  ValueRecord.prototype.buildStruct = function buildStruct(parent) {\n    var struct = parent;\n    while (!struct[this.key] && struct.parent) {\n      struct = struct.parent;\n    }\n\n    if (!struct[this.key]) return;\n\n    var fields = {};\n    fields.rel = function () {\n      return struct._startOffset;\n    };\n\n    var format = struct[this.key];\n    for (var key in format) {\n      if (format[key]) {\n        fields[key] = types[key];\n      }\n    }\n\n    return new r.Struct(fields);\n  };\n\n  ValueRecord.prototype.size = function size(val, ctx) {\n    return this.buildStruct(ctx).size(val, ctx);\n  };\n\n  ValueRecord.prototype.decode = function decode(stream, parent) {\n    var res = this.buildStruct(parent).decode(stream, parent);\n    delete res.rel;\n    return res;\n  };\n\n  return ValueRecord;\n}();\n\nvar PairValueRecord = new r.Struct({\n  secondGlyph: r.uint16,\n  value1: new ValueRecord('valueFormat1'),\n  value2: new ValueRecord('valueFormat2')\n});\n\nvar PairSet = new r.Array(PairValueRecord, r.uint16);\n\nvar Class2Record = new r.Struct({\n  value1: new ValueRecord('valueFormat1'),\n  value2: new ValueRecord('valueFormat2')\n});\n\nvar Anchor = new r.VersionedStruct(r.uint16, {\n  1: { // Design units only\n    xCoordinate: r.int16,\n    yCoordinate: r.int16\n  },\n\n  2: { // Design units plus contour point\n    xCoordinate: r.int16,\n    yCoordinate: r.int16,\n    anchorPoint: r.uint16\n  },\n\n  3: { // Design units plus Device tables\n    xCoordinate: r.int16,\n    yCoordinate: r.int16,\n    xDeviceTable: new r.Pointer(r.uint16, Device),\n    yDeviceTable: new r.Pointer(r.uint16, Device)\n  }\n});\n\nvar EntryExitRecord = new r.Struct({\n  entryAnchor: new r.Pointer(r.uint16, Anchor, { type: 'parent' }),\n  exitAnchor: new r.Pointer(r.uint16, Anchor, { type: 'parent' })\n});\n\nvar MarkRecord = new r.Struct({\n  class: r.uint16,\n  markAnchor: new r.Pointer(r.uint16, Anchor, { type: 'parent' })\n});\n\nvar MarkArray = new r.Array(MarkRecord, r.uint16);\n\nvar BaseRecord = new r.Array(new r.Pointer(r.uint16, Anchor), function (t) {\n  return t.parent.classCount;\n});\nvar BaseArray = new r.Array(BaseRecord, r.uint16);\n\nvar ComponentRecord = new r.Array(new r.Pointer(r.uint16, Anchor), function (t) {\n  return t.parent.parent.classCount;\n});\nvar LigatureAttach = new r.Array(ComponentRecord, r.uint16);\nvar LigatureArray = new r.Array(new r.Pointer(r.uint16, LigatureAttach), r.uint16);\n\nvar GPOSLookup = new r.VersionedStruct('lookupType', {\n  1: new r.VersionedStruct(r.uint16, { // Single Adjustment\n    1: { // Single positioning value\n      coverage: new r.Pointer(r.uint16, Coverage),\n      valueFormat: ValueFormat,\n      value: new ValueRecord()\n    },\n    2: {\n      coverage: new r.Pointer(r.uint16, Coverage),\n      valueFormat: ValueFormat,\n      valueCount: r.uint16,\n      values: new r.LazyArray(new ValueRecord(), 'valueCount')\n    }\n  }),\n\n  2: new r.VersionedStruct(r.uint16, { // Pair Adjustment Positioning\n    1: { // Adjustments for glyph pairs\n      coverage: new r.Pointer(r.uint16, Coverage),\n      valueFormat1: ValueFormat,\n      valueFormat2: ValueFormat,\n      pairSetCount: r.uint16,\n      pairSets: new r.LazyArray(new r.Pointer(r.uint16, PairSet), 'pairSetCount')\n    },\n\n    2: { // Class pair adjustment\n      coverage: new r.Pointer(r.uint16, Coverage),\n      valueFormat1: ValueFormat,\n      valueFormat2: ValueFormat,\n      classDef1: new r.Pointer(r.uint16, ClassDef),\n      classDef2: new r.Pointer(r.uint16, ClassDef),\n      class1Count: r.uint16,\n      class2Count: r.uint16,\n      classRecords: new r.LazyArray(new r.LazyArray(Class2Record, 'class2Count'), 'class1Count')\n    }\n  }),\n\n  3: { // Cursive Attachment Positioning\n    format: r.uint16,\n    coverage: new r.Pointer(r.uint16, Coverage),\n    entryExitCount: r.uint16,\n    entryExitRecords: new r.Array(EntryExitRecord, 'entryExitCount')\n  },\n\n  4: { // MarkToBase Attachment Positioning\n    format: r.uint16,\n    markCoverage: new r.Pointer(r.uint16, Coverage),\n    baseCoverage: new r.Pointer(r.uint16, Coverage),\n    classCount: r.uint16,\n    markArray: new r.Pointer(r.uint16, MarkArray),\n    baseArray: new r.Pointer(r.uint16, BaseArray)\n  },\n\n  5: { // MarkToLigature Attachment Positioning\n    format: r.uint16,\n    markCoverage: new r.Pointer(r.uint16, Coverage),\n    ligatureCoverage: new r.Pointer(r.uint16, Coverage),\n    classCount: r.uint16,\n    markArray: new r.Pointer(r.uint16, MarkArray),\n    ligatureArray: new r.Pointer(r.uint16, LigatureArray)\n  },\n\n  6: { // MarkToMark Attachment Positioning\n    format: r.uint16,\n    mark1Coverage: new r.Pointer(r.uint16, Coverage),\n    mark2Coverage: new r.Pointer(r.uint16, Coverage),\n    classCount: r.uint16,\n    mark1Array: new r.Pointer(r.uint16, MarkArray),\n    mark2Array: new r.Pointer(r.uint16, BaseArray)\n  },\n\n  7: Context, // Contextual positioning\n  8: ChainingContext, // Chaining contextual positioning\n\n  9: { // Extension Positioning\n    posFormat: r.uint16,\n    lookupType: r.uint16, // cannot also be 9\n    extension: new r.Pointer(r.uint32, GPOSLookup)\n  }\n});\n\n// Fix circular reference\nGPOSLookup.versions[9].extension.type = GPOSLookup;\n\nvar GPOS = new r.VersionedStruct(r.uint32, {\n  header: {\n    scriptList: new r.Pointer(r.uint16, ScriptList),\n    featureList: new r.Pointer(r.uint16, FeatureList),\n    lookupList: new r.Pointer(r.uint16, new LookupList(GPOSLookup))\n  },\n\n  0x00010000: {},\n  0x00010001: {\n    featureVariations: new r.Pointer(r.uint32, FeatureVariations)\n  }\n});\n\nvar Sequence = new r.Array(r.uint16, r.uint16);\nvar AlternateSet = Sequence;\n\nvar Ligature = new r.Struct({\n  glyph: r.uint16,\n  compCount: r.uint16,\n  components: new r.Array(r.uint16, function (t) {\n    return t.compCount - 1;\n  })\n});\n\nvar LigatureSet = new r.Array(new r.Pointer(r.uint16, Ligature), r.uint16);\n\nvar GSUBLookup = new r.VersionedStruct('lookupType', {\n  1: new r.VersionedStruct(r.uint16, { // Single Substitution\n    1: {\n      coverage: new r.Pointer(r.uint16, Coverage),\n      deltaGlyphID: r.int16\n    },\n    2: {\n      coverage: new r.Pointer(r.uint16, Coverage),\n      glyphCount: r.uint16,\n      substitute: new r.LazyArray(r.uint16, 'glyphCount')\n    }\n  }),\n\n  2: { // Multiple Substitution\n    substFormat: r.uint16,\n    coverage: new r.Pointer(r.uint16, Coverage),\n    count: r.uint16,\n    sequences: new r.LazyArray(new r.Pointer(r.uint16, Sequence), 'count')\n  },\n\n  3: { // Alternate Substitution\n    substFormat: r.uint16,\n    coverage: new r.Pointer(r.uint16, Coverage),\n    count: r.uint16,\n    alternateSet: new r.LazyArray(new r.Pointer(r.uint16, AlternateSet), 'count')\n  },\n\n  4: { // Ligature Substitution\n    substFormat: r.uint16,\n    coverage: new r.Pointer(r.uint16, Coverage),\n    count: r.uint16,\n    ligatureSets: new r.LazyArray(new r.Pointer(r.uint16, LigatureSet), 'count')\n  },\n\n  5: Context, // Contextual Substitution\n  6: ChainingContext, // Chaining Contextual Substitution\n\n  7: { // Extension Substitution\n    substFormat: r.uint16,\n    lookupType: r.uint16, // cannot also be 7\n    extension: new r.Pointer(r.uint32, GSUBLookup)\n  },\n\n  8: { // Reverse Chaining Contextual Single Substitution\n    substFormat: r.uint16,\n    coverage: new r.Pointer(r.uint16, Coverage),\n    backtrackCoverage: new r.Array(new r.Pointer(r.uint16, Coverage), 'backtrackGlyphCount'),\n    lookaheadGlyphCount: r.uint16,\n    lookaheadCoverage: new r.Array(new r.Pointer(r.uint16, Coverage), 'lookaheadGlyphCount'),\n    glyphCount: r.uint16,\n    substitutes: new r.Array(r.uint16, 'glyphCount')\n  }\n});\n\n// Fix circular reference\nGSUBLookup.versions[7].extension.type = GSUBLookup;\n\nvar GSUB = new r.VersionedStruct(r.uint32, {\n  header: {\n    scriptList: new r.Pointer(r.uint16, ScriptList),\n    featureList: new r.Pointer(r.uint16, FeatureList),\n    lookupList: new r.Pointer(r.uint16, new LookupList(GSUBLookup))\n  },\n\n  0x00010000: {},\n  0x00010001: {\n    featureVariations: new r.Pointer(r.uint32, FeatureVariations)\n  }\n});\n\nvar JstfGSUBModList = new r.Array(r.uint16, r.uint16);\n\nvar JstfPriority = new r.Struct({\n  shrinkageEnableGSUB: new r.Pointer(r.uint16, JstfGSUBModList),\n  shrinkageDisableGSUB: new r.Pointer(r.uint16, JstfGSUBModList),\n  shrinkageEnableGPOS: new r.Pointer(r.uint16, JstfGSUBModList),\n  shrinkageDisableGPOS: new r.Pointer(r.uint16, JstfGSUBModList),\n  shrinkageJstfMax: new r.Pointer(r.uint16, new LookupList(GPOSLookup)),\n  extensionEnableGSUB: new r.Pointer(r.uint16, JstfGSUBModList),\n  extensionDisableGSUB: new r.Pointer(r.uint16, JstfGSUBModList),\n  extensionEnableGPOS: new r.Pointer(r.uint16, JstfGSUBModList),\n  extensionDisableGPOS: new r.Pointer(r.uint16, JstfGSUBModList),\n  extensionJstfMax: new r.Pointer(r.uint16, new LookupList(GPOSLookup))\n});\n\nvar JstfLangSys = new r.Array(new r.Pointer(r.uint16, JstfPriority), r.uint16);\n\nvar JstfLangSysRecord = new r.Struct({\n  tag: new r.String(4),\n  jstfLangSys: new r.Pointer(r.uint16, JstfLangSys)\n});\n\nvar JstfScript = new r.Struct({\n  extenderGlyphs: new r.Pointer(r.uint16, new r.Array(r.uint16, r.uint16)), // array of glyphs to extend line length\n  defaultLangSys: new r.Pointer(r.uint16, JstfLangSys),\n  langSysCount: r.uint16,\n  langSysRecords: new r.Array(JstfLangSysRecord, 'langSysCount')\n});\n\nvar JstfScriptRecord = new r.Struct({\n  tag: new r.String(4),\n  script: new r.Pointer(r.uint16, JstfScript, { type: 'parent' })\n});\n\nvar JSTF = new r.Struct({\n  version: r.uint32, // should be 0x00010000\n  scriptCount: r.uint16,\n  scriptList: new r.Array(JstfScriptRecord, 'scriptCount')\n});\n\n// TODO: add this to restructure\n\nvar VariableSizeNumber = function () {\n  function VariableSizeNumber(size) {\n    _classCallCheck(this, VariableSizeNumber);\n\n    this._size = size;\n  }\n\n  VariableSizeNumber.prototype.decode = function decode(stream, parent) {\n    switch (this.size(0, parent)) {\n      case 1:\n        return stream.readUInt8();\n      case 2:\n        return stream.readUInt16BE();\n      case 3:\n        return stream.readUInt24BE();\n      case 4:\n        return stream.readUInt32BE();\n    }\n  };\n\n  VariableSizeNumber.prototype.size = function size(val, parent) {\n    return restructure_src_utils.resolveLength(this._size, null, parent);\n  };\n\n  return VariableSizeNumber;\n}();\n\nvar MapDataEntry = new r.Struct({\n  entry: new VariableSizeNumber(function (t) {\n    return ((t.parent.entryFormat & 0x0030) >> 4) + 1;\n  }),\n  outerIndex: function outerIndex(t) {\n    return t.entry >> (t.parent.entryFormat & 0x000F) + 1;\n  },\n  innerIndex: function innerIndex(t) {\n    return t.entry & (1 << (t.parent.entryFormat & 0x000F) + 1) - 1;\n  }\n});\n\nvar DeltaSetIndexMap = new r.Struct({\n  entryFormat: r.uint16,\n  mapCount: r.uint16,\n  mapData: new r.Array(MapDataEntry, 'mapCount')\n});\n\nvar HVAR = new r.Struct({\n  majorVersion: r.uint16,\n  minorVersion: r.uint16,\n  itemVariationStore: new r.Pointer(r.uint32, ItemVariationStore),\n  advanceWidthMapping: new r.Pointer(r.uint32, DeltaSetIndexMap),\n  LSBMapping: new r.Pointer(r.uint32, DeltaSetIndexMap),\n  RSBMapping: new r.Pointer(r.uint32, DeltaSetIndexMap)\n});\n\nvar Signature = new r.Struct({\n  format: r.uint32,\n  length: r.uint32,\n  offset: r.uint32\n});\n\nvar SignatureBlock = new r.Struct({\n  reserved: new r.Reserved(r.uint16, 2),\n  cbSignature: r.uint32, // Length (in bytes) of the PKCS#7 packet in pbSignature\n  signature: new r.Buffer('cbSignature')\n});\n\nvar DSIG = new r.Struct({\n  ulVersion: r.uint32, // Version number of the DSIG table (0x00000001)\n  usNumSigs: r.uint16, // Number of signatures in the table\n  usFlag: r.uint16, // Permission flags\n  signatures: new r.Array(Signature, 'usNumSigs'),\n  signatureBlocks: new r.Array(SignatureBlock, 'usNumSigs')\n});\n\nvar GaspRange = new r.Struct({\n  rangeMaxPPEM: r.uint16, // Upper limit of range, in ppem\n  rangeGaspBehavior: new r.Bitfield(r.uint16, [// Flags describing desired rasterizer behavior\n  'grayscale', 'gridfit', 'symmetricSmoothing', 'symmetricGridfit' // only in version 1, for ClearType\n  ])\n});\n\nvar gasp = new r.Struct({\n  version: r.uint16, // set to 0\n  numRanges: r.uint16,\n  gaspRanges: new r.Array(GaspRange, 'numRanges') // Sorted by ppem\n});\n\nvar DeviceRecord = new r.Struct({\n  pixelSize: r.uint8,\n  maximumWidth: r.uint8,\n  widths: new r.Array(r.uint8, function (t) {\n    return t.parent.parent.maxp.numGlyphs;\n  })\n});\n\n// The Horizontal Device Metrics table stores integer advance widths scaled to particular pixel sizes\nvar hdmx = new r.Struct({\n  version: r.uint16,\n  numRecords: r.int16,\n  sizeDeviceRecord: r.int32,\n  records: new r.Array(DeviceRecord, 'numRecords')\n});\n\nvar KernPair = new r.Struct({\n  left: r.uint16,\n  right: r.uint16,\n  value: r.int16\n});\n\nvar ClassTable = new r.Struct({\n  firstGlyph: r.uint16,\n  nGlyphs: r.uint16,\n  offsets: new r.Array(r.uint16, 'nGlyphs'),\n  max: function max(t) {\n    return t.offsets.length && Math.max.apply(Math, t.offsets);\n  }\n});\n\nvar Kern2Array = new r.Struct({\n  off: function off(t) {\n    return t._startOffset - t.parent.parent._startOffset;\n  },\n  len: function len(t) {\n    return ((t.parent.leftTable.max - t.off) / t.parent.rowWidth + 1) * (t.parent.rowWidth / 2);\n  },\n  values: new r.LazyArray(r.int16, 'len')\n});\n\nvar KernSubtable = new r.VersionedStruct('format', {\n  0: {\n    nPairs: r.uint16,\n    searchRange: r.uint16,\n    entrySelector: r.uint16,\n    rangeShift: r.uint16,\n    pairs: new r.Array(KernPair, 'nPairs')\n  },\n\n  2: {\n    rowWidth: r.uint16,\n    leftTable: new r.Pointer(r.uint16, ClassTable, { type: 'parent' }),\n    rightTable: new r.Pointer(r.uint16, ClassTable, { type: 'parent' }),\n    array: new r.Pointer(r.uint16, Kern2Array, { type: 'parent' })\n  },\n\n  3: {\n    glyphCount: r.uint16,\n    kernValueCount: r.uint8,\n    leftClassCount: r.uint8,\n    rightClassCount: r.uint8,\n    flags: r.uint8,\n    kernValue: new r.Array(r.int16, 'kernValueCount'),\n    leftClass: new r.Array(r.uint8, 'glyphCount'),\n    rightClass: new r.Array(r.uint8, 'glyphCount'),\n    kernIndex: new r.Array(r.uint8, function (t) {\n      return t.leftClassCount * t.rightClassCount;\n    })\n  }\n});\n\nvar KernTable = new r.VersionedStruct('version', {\n  0: { // Microsoft uses this format\n    subVersion: r.uint16, // Microsoft has an extra sub-table version number\n    length: r.uint16, // Length of the subtable, in bytes\n    format: r.uint8, // Format of subtable\n    coverage: new r.Bitfield(r.uint8, ['horizontal', // 1 if table has horizontal data, 0 if vertical\n    'minimum', // If set to 1, the table has minimum values. If set to 0, the table has kerning values.\n    'crossStream', // If set to 1, kerning is perpendicular to the flow of the text\n    'override' // If set to 1 the value in this table replaces the accumulated value\n    ]),\n    subtable: KernSubtable,\n    padding: new r.Reserved(r.uint8, function (t) {\n      return t.length - t._currentOffset;\n    })\n  },\n  1: { // Apple uses this format\n    length: r.uint32,\n    coverage: new r.Bitfield(r.uint8, [null, null, null, null, null, 'variation', // Set if table has variation kerning values\n    'crossStream', // Set if table has cross-stream kerning values\n    'vertical' // Set if table has vertical kerning values\n    ]),\n    format: r.uint8,\n    tupleIndex: r.uint16,\n    subtable: KernSubtable,\n    padding: new r.Reserved(r.uint8, function (t) {\n      return t.length - t._currentOffset;\n    })\n  }\n});\n\nvar kern = new r.VersionedStruct(r.uint16, {\n  0: { // Microsoft Version\n    nTables: r.uint16,\n    tables: new r.Array(KernTable, 'nTables')\n  },\n\n  1: { // Apple Version\n    reserved: new r.Reserved(r.uint16), // the other half of the version number\n    nTables: r.uint32,\n    tables: new r.Array(KernTable, 'nTables')\n  }\n});\n\n// Linear Threshold table\n// Records the ppem for each glyph at which the scaling becomes linear again,\n// despite instructions effecting the advance width\nvar LTSH = new r.Struct({\n  version: r.uint16,\n  numGlyphs: r.uint16,\n  yPels: new r.Array(r.uint8, 'numGlyphs')\n});\n\n// PCL 5 Table\n// NOTE: The PCLT table is strongly discouraged for OpenType fonts with TrueType outlines\nvar PCLT = new r.Struct({\n  version: r.uint16,\n  fontNumber: r.uint32,\n  pitch: r.uint16,\n  xHeight: r.uint16,\n  style: r.uint16,\n  typeFamily: r.uint16,\n  capHeight: r.uint16,\n  symbolSet: r.uint16,\n  typeface: new r.String(16),\n  characterComplement: new r.String(8),\n  fileName: new r.String(6),\n  strokeWeight: new r.String(1),\n  widthType: new r.String(1),\n  serifStyle: r.uint8,\n  reserved: new r.Reserved(r.uint8)\n});\n\n// VDMX tables contain ascender/descender overrides for certain (usually small)\n// sizes. This is needed in order to match font metrics on Windows.\n\nvar Ratio = new r.Struct({\n  bCharSet: r.uint8, // Character set\n  xRatio: r.uint8, // Value to use for x-Ratio\n  yStartRatio: r.uint8, // Starting y-Ratio value\n  yEndRatio: r.uint8 // Ending y-Ratio value\n});\n\nvar vTable = new r.Struct({\n  yPelHeight: r.uint16, // yPelHeight to which values apply\n  yMax: r.int16, // Maximum value (in pels) for this yPelHeight\n  yMin: r.int16 // Minimum value (in pels) for this yPelHeight\n});\n\nvar VdmxGroup = new r.Struct({\n  recs: r.uint16, // Number of height records in this group\n  startsz: r.uint8, // Starting yPelHeight\n  endsz: r.uint8, // Ending yPelHeight\n  entries: new r.Array(vTable, 'recs') // The VDMX records\n});\n\nvar VDMX = new r.Struct({\n  version: r.uint16, // Version number (0 or 1)\n  numRecs: r.uint16, // Number of VDMX groups present\n  numRatios: r.uint16, // Number of aspect ratio groupings\n  ratioRanges: new r.Array(Ratio, 'numRatios'), // Ratio ranges\n  offsets: new r.Array(r.uint16, 'numRatios'), // Offset to the VDMX group for this ratio range\n  groups: new r.Array(VdmxGroup, 'numRecs') // The actual VDMX groupings\n});\n\n// Vertical Header Table\nvar vhea = new r.Struct({\n  version: r.uint16, // Version number of the Vertical Header Table\n  ascent: r.int16, // The vertical typographic ascender for this font\n  descent: r.int16, // The vertical typographic descender for this font\n  lineGap: r.int16, // The vertical typographic line gap for this font\n  advanceHeightMax: r.int16, // The maximum advance height measurement found in the font\n  minTopSideBearing: r.int16, // The minimum top side bearing measurement found in the font\n  minBottomSideBearing: r.int16, // The minimum bottom side bearing measurement found in the font\n  yMaxExtent: r.int16,\n  caretSlopeRise: r.int16, // Caret slope (rise/run)\n  caretSlopeRun: r.int16,\n  caretOffset: r.int16, // Set value equal to 0 for nonslanted fonts\n  reserved: new r.Reserved(r.int16, 4),\n  metricDataFormat: r.int16, // Set to 0\n  numberOfMetrics: r.uint16 // Number of advance heights in the Vertical Metrics table\n});\n\nvar VmtxEntry = new r.Struct({\n  advance: r.uint16, // The advance height of the glyph\n  bearing: r.int16 // The top sidebearing of the glyph\n});\n\n// Vertical Metrics Table\nvar vmtx = new r.Struct({\n  metrics: new r.LazyArray(VmtxEntry, function (t) {\n    return t.parent.vhea.numberOfMetrics;\n  }),\n  bearings: new r.LazyArray(r.int16, function (t) {\n    return t.parent.maxp.numGlyphs - t.parent.vhea.numberOfMetrics;\n  })\n});\n\nvar shortFrac = new r.Fixed(16, 'BE', 14);\n\nvar Correspondence = new r.Struct({\n  fromCoord: shortFrac,\n  toCoord: shortFrac\n});\n\nvar Segment = new r.Struct({\n  pairCount: r.uint16,\n  correspondence: new r.Array(Correspondence, 'pairCount')\n});\n\nvar avar = new r.Struct({\n  version: r.fixed32,\n  axisCount: r.uint32,\n  segment: new r.Array(Segment, 'axisCount')\n});\n\nvar UnboundedArrayAccessor = function () {\n  function UnboundedArrayAccessor(type, stream, parent) {\n    _classCallCheck(this, UnboundedArrayAccessor);\n\n    this.type = type;\n    this.stream = stream;\n    this.parent = parent;\n    this.base = this.stream.pos;\n    this._items = [];\n  }\n\n  UnboundedArrayAccessor.prototype.getItem = function getItem(index) {\n    if (this._items[index] == null) {\n      var pos = this.stream.pos;\n      this.stream.pos = this.base + this.type.size(null, this.parent) * index;\n      this._items[index] = this.type.decode(this.stream, this.parent);\n      this.stream.pos = pos;\n    }\n\n    return this._items[index];\n  };\n\n  UnboundedArrayAccessor.prototype.inspect = function inspect() {\n    return '[UnboundedArray ' + this.type.constructor.name + ']';\n  };\n\n  return UnboundedArrayAccessor;\n}();\n\nvar UnboundedArray = function (_r$Array) {\n  _inherits(UnboundedArray, _r$Array);\n\n  function UnboundedArray(type) {\n    _classCallCheck(this, UnboundedArray);\n\n    return _possibleConstructorReturn(this, _r$Array.call(this, type, 0));\n  }\n\n  UnboundedArray.prototype.decode = function decode(stream, parent) {\n    return new UnboundedArrayAccessor(this.type, stream, parent);\n  };\n\n  return UnboundedArray;\n}(r.Array);\n\nvar LookupTable = function LookupTable() {\n  var ValueType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : r.uint16;\n\n  // Helper class that makes internal structures invisible to pointers\n  var Shadow = function () {\n    function Shadow(type) {\n      _classCallCheck(this, Shadow);\n\n      this.type = type;\n    }\n\n    Shadow.prototype.decode = function decode(stream, ctx) {\n      ctx = ctx.parent.parent;\n      return this.type.decode(stream, ctx);\n    };\n\n    Shadow.prototype.size = function size(val, ctx) {\n      ctx = ctx.parent.parent;\n      return this.type.size(val, ctx);\n    };\n\n    Shadow.prototype.encode = function encode(stream, val, ctx) {\n      ctx = ctx.parent.parent;\n      return this.type.encode(stream, val, ctx);\n    };\n\n    return Shadow;\n  }();\n\n  ValueType = new Shadow(ValueType);\n\n  var BinarySearchHeader = new r.Struct({\n    unitSize: r.uint16,\n    nUnits: r.uint16,\n    searchRange: r.uint16,\n    entrySelector: r.uint16,\n    rangeShift: r.uint16\n  });\n\n  var LookupSegmentSingle = new r.Struct({\n    lastGlyph: r.uint16,\n    firstGlyph: r.uint16,\n    value: ValueType\n  });\n\n  var LookupSegmentArray = new r.Struct({\n    lastGlyph: r.uint16,\n    firstGlyph: r.uint16,\n    values: new r.Pointer(r.uint16, new r.Array(ValueType, function (t) {\n      return t.lastGlyph - t.firstGlyph + 1;\n    }), { type: 'parent' })\n  });\n\n  var LookupSingle = new r.Struct({\n    glyph: r.uint16,\n    value: ValueType\n  });\n\n  return new r.VersionedStruct(r.uint16, {\n    0: {\n      values: new UnboundedArray(ValueType) // length == number of glyphs maybe?\n    },\n    2: {\n      binarySearchHeader: BinarySearchHeader,\n      segments: new r.Array(LookupSegmentSingle, function (t) {\n        return t.binarySearchHeader.nUnits;\n      })\n    },\n    4: {\n      binarySearchHeader: BinarySearchHeader,\n      segments: new r.Array(LookupSegmentArray, function (t) {\n        return t.binarySearchHeader.nUnits;\n      })\n    },\n    6: {\n      binarySearchHeader: BinarySearchHeader,\n      segments: new r.Array(LookupSingle, function (t) {\n        return t.binarySearchHeader.nUnits;\n      })\n    },\n    8: {\n      firstGlyph: r.uint16,\n      count: r.uint16,\n      values: new r.Array(ValueType, 'count')\n    }\n  });\n};\n\nfunction StateTable() {\n  var entryData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n  var lookupType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : r.uint16;\n\n  var entry = _Object$assign({\n    newState: r.uint16,\n    flags: r.uint16\n  }, entryData);\n\n  var Entry = new r.Struct(entry);\n  var StateArray = new UnboundedArray(new r.Array(r.uint16, function (t) {\n    return t.nClasses;\n  }));\n\n  var StateHeader = new r.Struct({\n    nClasses: r.uint32,\n    classTable: new r.Pointer(r.uint32, new LookupTable(lookupType)),\n    stateArray: new r.Pointer(r.uint32, StateArray),\n    entryTable: new r.Pointer(r.uint32, new UnboundedArray(Entry))\n  });\n\n  return StateHeader;\n}\n\n// This is the old version of the StateTable structure\nfunction StateTable1() {\n  var entryData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n  var lookupType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : r.uint16;\n\n  var ClassLookupTable = new r.Struct({\n    version: function version() {\n      return 8;\n    },\n    // simulate LookupTable\n    firstGlyph: r.uint16,\n    values: new r.Array(r.uint8, r.uint16)\n  });\n\n  var entry = _Object$assign({\n    newStateOffset: r.uint16,\n    // convert offset to stateArray index\n    newState: function newState(t) {\n      return (t.newStateOffset - (t.parent.stateArray.base - t.parent._startOffset)) / t.parent.nClasses;\n    },\n    flags: r.uint16\n  }, entryData);\n\n  var Entry = new r.Struct(entry);\n  var StateArray = new UnboundedArray(new r.Array(r.uint8, function (t) {\n    return t.nClasses;\n  }));\n\n  var StateHeader1 = new r.Struct({\n    nClasses: r.uint16,\n    classTable: new r.Pointer(r.uint16, ClassLookupTable),\n    stateArray: new r.Pointer(r.uint16, StateArray),\n    entryTable: new r.Pointer(r.uint16, new UnboundedArray(Entry))\n  });\n\n  return StateHeader1;\n}\n\nvar BslnSubtable = new r.VersionedStruct('format', {\n  0: { // Distance-based, no mapping\n    deltas: new r.Array(r.int16, 32)\n  },\n\n  1: { // Distance-based, with mapping\n    deltas: new r.Array(r.int16, 32),\n    mappingData: new LookupTable(r.uint16)\n  },\n\n  2: { // Control point-based, no mapping\n    standardGlyph: r.uint16,\n    controlPoints: new r.Array(r.uint16, 32)\n  },\n\n  3: { // Control point-based, with mapping\n    standardGlyph: r.uint16,\n    controlPoints: new r.Array(r.uint16, 32),\n    mappingData: new LookupTable(r.uint16)\n  }\n});\n\nvar bsln = new r.Struct({\n  version: r.fixed32,\n  format: r.uint16,\n  defaultBaseline: r.uint16,\n  subtable: BslnSubtable\n});\n\nvar Setting = new r.Struct({\n  setting: r.uint16,\n  nameIndex: r.int16,\n  name: function name(t) {\n    return t.parent.parent.parent.name.records.fontFeatures[t.nameIndex];\n  }\n});\n\nvar FeatureName = new r.Struct({\n  feature: r.uint16,\n  nSettings: r.uint16,\n  settingTable: new r.Pointer(r.uint32, new r.Array(Setting, 'nSettings'), { type: 'parent' }),\n  featureFlags: new r.Bitfield(r.uint8, [null, null, null, null, null, null, 'hasDefault', 'exclusive']),\n  defaultSetting: r.uint8,\n  nameIndex: r.int16,\n  name: function name(t) {\n    return t.parent.parent.name.records.fontFeatures[t.nameIndex];\n  }\n});\n\nvar feat = new r.Struct({\n  version: r.fixed32,\n  featureNameCount: r.uint16,\n  reserved1: new r.Reserved(r.uint16),\n  reserved2: new r.Reserved(r.uint32),\n  featureNames: new r.Array(FeatureName, 'featureNameCount')\n});\n\nvar Axis$1 = new r.Struct({\n  axisTag: new r.String(4),\n  minValue: r.fixed32,\n  defaultValue: r.fixed32,\n  maxValue: r.fixed32,\n  flags: r.uint16,\n  nameID: r.uint16,\n  name: function name(t) {\n    return t.parent.parent.name.records.fontFeatures[t.nameID];\n  }\n});\n\nvar Instance = new r.Struct({\n  nameID: r.uint16,\n  name: function name(t) {\n    return t.parent.parent.name.records.fontFeatures[t.nameID];\n  },\n  flags: r.uint16,\n  coord: new r.Array(r.fixed32, function (t) {\n    return t.parent.axisCount;\n  }),\n  postscriptNameID: new r.Optional(r.uint16, function (t) {\n    return t.parent.instanceSize - t._currentOffset > 0;\n  })\n});\n\nvar fvar = new r.Struct({\n  version: r.fixed32,\n  offsetToData: r.uint16,\n  countSizePairs: r.uint16,\n  axisCount: r.uint16,\n  axisSize: r.uint16,\n  instanceCount: r.uint16,\n  instanceSize: r.uint16,\n  axis: new r.Array(Axis$1, 'axisCount'),\n  instance: new r.Array(Instance, 'instanceCount')\n});\n\nvar shortFrac$1 = new r.Fixed(16, 'BE', 14);\n\nvar Offset = function () {\n  function Offset() {\n    _classCallCheck(this, Offset);\n  }\n\n  Offset.decode = function decode(stream, parent) {\n    // In short format, offsets are multiplied by 2.\n    // This doesn't seem to be documented by Apple, but it\n    // is implemented this way in Freetype.\n    return parent.flags ? stream.readUInt32BE() : stream.readUInt16BE() * 2;\n  };\n\n  return Offset;\n}();\n\nvar gvar = new r.Struct({\n  version: r.uint16,\n  reserved: new r.Reserved(r.uint16),\n  axisCount: r.uint16,\n  globalCoordCount: r.uint16,\n  globalCoords: new r.Pointer(r.uint32, new r.Array(new r.Array(shortFrac$1, 'axisCount'), 'globalCoordCount')),\n  glyphCount: r.uint16,\n  flags: r.uint16,\n  offsetToData: r.uint32,\n  offsets: new r.Array(new r.Pointer(Offset, 'void', { relativeTo: 'offsetToData', allowNull: false }), function (t) {\n    return t.glyphCount + 1;\n  })\n});\n\nvar ClassTable$1 = new r.Struct({\n  length: r.uint16,\n  coverage: r.uint16,\n  subFeatureFlags: r.uint32,\n  stateTable: new StateTable1()\n});\n\nvar WidthDeltaRecord = new r.Struct({\n  justClass: r.uint32,\n  beforeGrowLimit: r.fixed32,\n  beforeShrinkLimit: r.fixed32,\n  afterGrowLimit: r.fixed32,\n  afterShrinkLimit: r.fixed32,\n  growFlags: r.uint16,\n  shrinkFlags: r.uint16\n});\n\nvar WidthDeltaCluster = new r.Array(WidthDeltaRecord, r.uint32);\n\nvar ActionData = new r.VersionedStruct('actionType', {\n  0: { // Decomposition action\n    lowerLimit: r.fixed32,\n    upperLimit: r.fixed32,\n    order: r.uint16,\n    glyphs: new r.Array(r.uint16, r.uint16)\n  },\n\n  1: { // Unconditional add glyph action\n    addGlyph: r.uint16\n  },\n\n  2: { // Conditional add glyph action\n    substThreshold: r.fixed32,\n    addGlyph: r.uint16,\n    substGlyph: r.uint16\n  },\n\n  3: {}, // Stretch glyph action (no data, not supported by CoreText)\n\n  4: { // Ductile glyph action (not supported by CoreText)\n    variationAxis: r.uint32,\n    minimumLimit: r.fixed32,\n    noStretchValue: r.fixed32,\n    maximumLimit: r.fixed32\n  },\n\n  5: { // Repeated add glyph action\n    flags: r.uint16,\n    glyph: r.uint16\n  }\n});\n\nvar Action = new r.Struct({\n  actionClass: r.uint16,\n  actionType: r.uint16,\n  actionLength: r.uint32,\n  actionData: ActionData,\n  padding: new r.Reserved(r.uint8, function (t) {\n    return t.actionLength - t._currentOffset;\n  })\n});\n\nvar PostcompensationAction = new r.Array(Action, r.uint32);\nvar PostCompensationTable = new r.Struct({\n  lookupTable: new LookupTable(new r.Pointer(r.uint16, PostcompensationAction))\n});\n\nvar JustificationTable = new r.Struct({\n  classTable: new r.Pointer(r.uint16, ClassTable$1, { type: 'parent' }),\n  wdcOffset: r.uint16,\n  postCompensationTable: new r.Pointer(r.uint16, PostCompensationTable, { type: 'parent' }),\n  widthDeltaClusters: new LookupTable(new r.Pointer(r.uint16, WidthDeltaCluster, { type: 'parent', relativeTo: 'wdcOffset' }))\n});\n\nvar just = new r.Struct({\n  version: r.uint32,\n  format: r.uint16,\n  horizontal: new r.Pointer(r.uint16, JustificationTable),\n  vertical: new r.Pointer(r.uint16, JustificationTable)\n});\n\nvar LigatureData = {\n  action: r.uint16\n};\n\nvar ContextualData = {\n  markIndex: r.uint16,\n  currentIndex: r.uint16\n};\n\nvar InsertionData = {\n  currentInsertIndex: r.uint16,\n  markedInsertIndex: r.uint16\n};\n\nvar SubstitutionTable = new r.Struct({\n  items: new UnboundedArray(new r.Pointer(r.uint32, new LookupTable()))\n});\n\nvar SubtableData = new r.VersionedStruct('type', {\n  0: { // Indic Rearrangement Subtable\n    stateTable: new StateTable()\n  },\n\n  1: { // Contextual Glyph Substitution Subtable\n    stateTable: new StateTable(ContextualData),\n    substitutionTable: new r.Pointer(r.uint32, SubstitutionTable)\n  },\n\n  2: { // Ligature subtable\n    stateTable: new StateTable(LigatureData),\n    ligatureActions: new r.Pointer(r.uint32, new UnboundedArray(r.uint32)),\n    components: new r.Pointer(r.uint32, new UnboundedArray(r.uint16)),\n    ligatureList: new r.Pointer(r.uint32, new UnboundedArray(r.uint16))\n  },\n\n  4: { // Non-contextual Glyph Substitution Subtable\n    lookupTable: new LookupTable()\n  },\n\n  5: { // Glyph Insertion Subtable\n    stateTable: new StateTable(InsertionData),\n    insertionActions: new r.Pointer(r.uint32, new UnboundedArray(r.uint16))\n  }\n});\n\nvar Subtable = new r.Struct({\n  length: r.uint32,\n  coverage: r.uint24,\n  type: r.uint8,\n  subFeatureFlags: r.uint32,\n  table: SubtableData,\n  padding: new r.Reserved(r.uint8, function (t) {\n    return t.length - t._currentOffset;\n  })\n});\n\nvar FeatureEntry = new r.Struct({\n  featureType: r.uint16,\n  featureSetting: r.uint16,\n  enableFlags: r.uint32,\n  disableFlags: r.uint32\n});\n\nvar MorxChain = new r.Struct({\n  defaultFlags: r.uint32,\n  chainLength: r.uint32,\n  nFeatureEntries: r.uint32,\n  nSubtables: r.uint32,\n  features: new r.Array(FeatureEntry, 'nFeatureEntries'),\n  subtables: new r.Array(Subtable, 'nSubtables')\n});\n\nvar morx = new r.Struct({\n  version: r.uint16,\n  unused: new r.Reserved(r.uint16),\n  nChains: r.uint32,\n  chains: new r.Array(MorxChain, 'nChains')\n});\n\nvar OpticalBounds = new r.Struct({\n  left: r.int16,\n  top: r.int16,\n  right: r.int16,\n  bottom: r.int16\n});\n\nvar opbd = new r.Struct({\n  version: r.fixed32,\n  format: r.uint16,\n  lookupTable: new LookupTable(OpticalBounds)\n});\n\nvar tables = {};\n// Required Tables\ntables.cmap = cmap;\ntables.head = head;\ntables.hhea = hhea;\ntables.hmtx = hmtx;\ntables.maxp = maxp;\ntables.name = NameTable;\ntables['OS/2'] = OS2;\ntables.post = post;\n\n// TrueType Outlines\ntables.fpgm = fpgm;\ntables.loca = loca;\ntables.prep = prep;\ntables['cvt '] = cvt;\ntables.glyf = glyf;\n\n// PostScript Outlines\ntables['CFF '] = CFFFont;\ntables['CFF2'] = CFFFont;\ntables.VORG = VORG;\n\n// Bitmap Glyphs\ntables.EBLC = EBLC;\ntables.CBLC = tables.EBLC;\ntables.sbix = sbix;\ntables.COLR = COLR;\ntables.CPAL = CPAL;\n\n// Advanced OpenType Tables\ntables.BASE = BASE;\ntables.GDEF = GDEF;\ntables.GPOS = GPOS;\ntables.GSUB = GSUB;\ntables.JSTF = JSTF;\n\n// OpenType variations tables\ntables.HVAR = HVAR;\n\n// Other OpenType Tables\ntables.DSIG = DSIG;\ntables.gasp = gasp;\ntables.hdmx = hdmx;\ntables.kern = kern;\ntables.LTSH = LTSH;\ntables.PCLT = PCLT;\ntables.VDMX = VDMX;\ntables.vhea = vhea;\ntables.vmtx = vmtx;\n\n// Apple Advanced Typography Tables\ntables.avar = avar;\ntables.bsln = bsln;\ntables.feat = feat;\ntables.fvar = fvar;\ntables.gvar = gvar;\ntables.just = just;\ntables.morx = morx;\ntables.opbd = opbd;\n\nvar TableEntry = new r.Struct({\n  tag: new r.String(4),\n  checkSum: r.uint32,\n  offset: new r.Pointer(r.uint32, 'void', { type: 'global' }),\n  length: r.uint32\n});\n\nvar Directory = new r.Struct({\n  tag: new r.String(4),\n  numTables: r.uint16,\n  searchRange: r.uint16,\n  entrySelector: r.uint16,\n  rangeShift: r.uint16,\n  tables: new r.Array(TableEntry, 'numTables')\n});\n\nDirectory.process = function () {\n  var tables = {};\n  for (var _iterator = this.tables, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n    var _ref;\n\n    if (_isArray) {\n      if (_i >= _iterator.length) break;\n      _ref = _iterator[_i++];\n    } else {\n      _i = _iterator.next();\n      if (_i.done) break;\n      _ref = _i.value;\n    }\n\n    var table = _ref;\n\n    tables[table.tag] = table;\n  }\n\n  this.tables = tables;\n};\n\nDirectory.preEncode = function (stream) {\n  var tables$$ = [];\n  for (var tag in this.tables) {\n    var table = this.tables[tag];\n    if (table) {\n      tables$$.push({\n        tag: tag,\n        checkSum: 0,\n        offset: new r.VoidPointer(tables[tag], table),\n        length: tables[tag].size(table)\n      });\n    }\n  }\n\n  this.tag = 'true';\n  this.numTables = tables$$.length;\n  this.tables = tables$$;\n\n  this.searchRange = Math.floor(Math.log(this.numTables) / Math.LN2) * 16;\n  this.entrySelector = Math.floor(this.searchRange / Math.LN2);\n  this.rangeShift = this.numTables * 16 - this.searchRange;\n};\n\nfunction binarySearch(arr, cmp) {\n  var min = 0;\n  var max = arr.length - 1;\n  while (min <= max) {\n    var mid = min + max >> 1;\n    var res = cmp(arr[mid]);\n\n    if (res < 0) {\n      max = mid - 1;\n    } else if (res > 0) {\n      min = mid + 1;\n    } else {\n      return mid;\n    }\n  }\n\n  return -1;\n}\n\nfunction range(index, end) {\n  var range = [];\n  while (index < end) {\n    range.push(index++);\n  }\n  return range;\n}\n\nvar _class$1;\nfunction _applyDecoratedDescriptor$1(target, property, decorators, descriptor, context) {\n  var desc = {};\n  Object['ke' + 'ys'](descriptor).forEach(function (key) {\n    desc[key] = descriptor[key];\n  });\n  desc.enumerable = !!desc.enumerable;\n  desc.configurable = !!desc.configurable;\n\n  if ('value' in desc || desc.initializer) {\n    desc.writable = true;\n  }\n\n  desc = decorators.slice().reverse().reduce(function (desc, decorator) {\n    return decorator(target, property, desc) || desc;\n  }, desc);\n\n  if (context && desc.initializer !== void 0) {\n    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;\n    desc.initializer = undefined;\n  }\n\n  if (desc.initializer === void 0) {\n    Object['define' + 'Property'](target, property, desc);\n    desc = null;\n  }\n\n  return desc;\n}\n\n// iconv-lite is an optional dependency.\ntry {\n  var iconv = __webpack_require__(52);\n} catch (err) {}\n\nvar CmapProcessor = (_class$1 = function () {\n  function CmapProcessor(cmapTable) {\n    _classCallCheck(this, CmapProcessor);\n\n    // Attempt to find a Unicode cmap first\n    this.encoding = null;\n    this.cmap = this.findSubtable(cmapTable, [\n    // 32-bit subtables\n    [3, 10], [0, 6], [0, 4],\n\n    // 16-bit subtables\n    [3, 1], [0, 3], [0, 2], [0, 1], [0, 0]]);\n\n    // If not unicode cmap was found, and iconv-lite is installed,\n    // take the first table with a supported encoding.\n    if (!this.cmap && iconv) {\n      for (var _iterator = cmapTable.tables, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n        var _ref;\n\n        if (_isArray) {\n          if (_i >= _iterator.length) break;\n          _ref = _iterator[_i++];\n        } else {\n          _i = _iterator.next();\n          if (_i.done) break;\n          _ref = _i.value;\n        }\n\n        var cmap = _ref;\n\n        var encoding = getEncoding(cmap.platformID, cmap.encodingID, cmap.table.language - 1);\n        if (iconv.encodingExists(encoding)) {\n          this.cmap = cmap.table;\n          this.encoding = encoding;\n        }\n      }\n    }\n\n    if (!this.cmap) {\n      throw new Error(\"Could not find a supported cmap table\");\n    }\n\n    this.uvs = this.findSubtable(cmapTable, [[0, 5]]);\n    if (this.uvs && this.uvs.version !== 14) {\n      this.uvs = null;\n    }\n  }\n\n  CmapProcessor.prototype.findSubtable = function findSubtable(cmapTable, pairs) {\n    for (var _iterator2 = pairs, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n      var _ref2;\n\n      if (_isArray2) {\n        if (_i2 >= _iterator2.length) break;\n        _ref2 = _iterator2[_i2++];\n      } else {\n        _i2 = _iterator2.next();\n        if (_i2.done) break;\n        _ref2 = _i2.value;\n      }\n\n      var _ref3 = _ref2,\n          platformID = _ref3[0],\n          encodingID = _ref3[1];\n\n      for (var _iterator3 = cmapTable.tables, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n        var _ref4;\n\n        if (_isArray3) {\n          if (_i3 >= _iterator3.length) break;\n          _ref4 = _iterator3[_i3++];\n        } else {\n          _i3 = _iterator3.next();\n          if (_i3.done) break;\n          _ref4 = _i3.value;\n        }\n\n        var cmap = _ref4;\n\n        if (cmap.platformID === platformID && cmap.encodingID === encodingID) {\n          return cmap.table;\n        }\n      }\n    }\n\n    return null;\n  };\n\n  CmapProcessor.prototype.lookup = function lookup(codepoint, variationSelector) {\n    // If there is no Unicode cmap in this font, we need to re-encode\n    // the codepoint in the encoding that the cmap supports.\n    if (this.encoding) {\n      var buf = iconv.encode(_String$fromCodePoint(codepoint), this.encoding);\n      codepoint = 0;\n      for (var i = 0; i < buf.length; i++) {\n        codepoint = codepoint << 8 | buf[i];\n      }\n\n      // Otherwise, try to get a Unicode variation selector for this codepoint if one is provided.\n    } else if (variationSelector) {\n      var gid = this.getVariationSelector(codepoint, variationSelector);\n      if (gid) {\n        return gid;\n      }\n    }\n\n    var cmap = this.cmap;\n    switch (cmap.version) {\n      case 0:\n        return cmap.codeMap.get(codepoint) || 0;\n\n      case 4:\n        {\n          var min = 0;\n          var max = cmap.segCount - 1;\n          while (min <= max) {\n            var mid = min + max >> 1;\n\n            if (codepoint < cmap.startCode.get(mid)) {\n              max = mid - 1;\n            } else if (codepoint > cmap.endCode.get(mid)) {\n              min = mid + 1;\n            } else {\n              var rangeOffset = cmap.idRangeOffset.get(mid);\n              var _gid = void 0;\n\n              if (rangeOffset === 0) {\n                _gid = codepoint + cmap.idDelta.get(mid);\n              } else {\n                var index = rangeOffset / 2 + (codepoint - cmap.startCode.get(mid)) - (cmap.segCount - mid);\n                _gid = cmap.glyphIndexArray.get(index) || 0;\n                if (_gid !== 0) {\n                  _gid += cmap.idDelta.get(mid);\n                }\n              }\n\n              return _gid & 0xffff;\n            }\n          }\n\n          return 0;\n        }\n\n      case 8:\n        throw new Error('TODO: cmap format 8');\n\n      case 6:\n      case 10:\n        return cmap.glyphIndices.get(codepoint - cmap.firstCode) || 0;\n\n      case 12:\n      case 13:\n        {\n          var _min = 0;\n          var _max = cmap.nGroups - 1;\n          while (_min <= _max) {\n            var _mid = _min + _max >> 1;\n            var group = cmap.groups.get(_mid);\n\n            if (codepoint < group.startCharCode) {\n              _max = _mid - 1;\n            } else if (codepoint > group.endCharCode) {\n              _min = _mid + 1;\n            } else {\n              if (cmap.version === 12) {\n                return group.glyphID + (codepoint - group.startCharCode);\n              } else {\n                return group.glyphID;\n              }\n            }\n          }\n\n          return 0;\n        }\n\n      case 14:\n        throw new Error('TODO: cmap format 14');\n\n      default:\n        throw new Error('Unknown cmap format ' + cmap.version);\n    }\n  };\n\n  CmapProcessor.prototype.getVariationSelector = function getVariationSelector(codepoint, variationSelector) {\n    if (!this.uvs) {\n      return 0;\n    }\n\n    var selectors = this.uvs.varSelectors.toArray();\n    var i = binarySearch(selectors, function (x) {\n      return variationSelector - x.varSelector;\n    });\n    var sel = selectors[i];\n\n    if (i !== -1 && sel.defaultUVS) {\n      i = binarySearch(sel.defaultUVS, function (x) {\n        return codepoint < x.startUnicodeValue ? -1 : codepoint > x.startUnicodeValue + x.additionalCount ? +1 : 0;\n      });\n    }\n\n    if (i !== -1 && sel.nonDefaultUVS) {\n      i = binarySearch(sel.nonDefaultUVS, function (x) {\n        return codepoint - x.unicodeValue;\n      });\n      if (i !== -1) {\n        return sel.nonDefaultUVS[i].glyphID;\n      }\n    }\n\n    return 0;\n  };\n\n  CmapProcessor.prototype.getCharacterSet = function getCharacterSet() {\n    var cmap = this.cmap;\n    switch (cmap.version) {\n      case 0:\n        return range(0, cmap.codeMap.length);\n\n      case 4:\n        {\n          var res = [];\n          var endCodes = cmap.endCode.toArray();\n          for (var i = 0; i < endCodes.length; i++) {\n            var tail = endCodes[i] + 1;\n            var start = cmap.startCode.get(i);\n            res.push.apply(res, range(start, tail));\n          }\n\n          return res;\n        }\n\n      case 8:\n        throw new Error('TODO: cmap format 8');\n\n      case 6:\n      case 10:\n        return range(cmap.firstCode, cmap.firstCode + cmap.glyphIndices.length);\n\n      case 12:\n      case 13:\n        {\n          var _res = [];\n          for (var _iterator4 = cmap.groups.toArray(), _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _getIterator(_iterator4);;) {\n            var _ref5;\n\n            if (_isArray4) {\n              if (_i4 >= _iterator4.length) break;\n              _ref5 = _iterator4[_i4++];\n            } else {\n              _i4 = _iterator4.next();\n              if (_i4.done) break;\n              _ref5 = _i4.value;\n            }\n\n            var group = _ref5;\n\n            _res.push.apply(_res, range(group.startCharCode, group.endCharCode + 1));\n          }\n\n          return _res;\n        }\n\n      case 14:\n        throw new Error('TODO: cmap format 14');\n\n      default:\n        throw new Error('Unknown cmap format ' + cmap.version);\n    }\n  };\n\n  CmapProcessor.prototype.codePointsForGlyph = function codePointsForGlyph(gid) {\n    var cmap = this.cmap;\n    switch (cmap.version) {\n      case 0:\n        {\n          var res = [];\n          for (var i = 0; i < 256; i++) {\n            if (cmap.codeMap.get(i) === gid) {\n              res.push(i);\n            }\n          }\n\n          return res;\n        }\n\n      case 4:\n        {\n          var _res2 = [];\n          for (var _i5 = 0; _i5 < cmap.segCount; _i5++) {\n            var end = cmap.endCode.get(_i5);\n            var start = cmap.startCode.get(_i5);\n            var rangeOffset = cmap.idRangeOffset.get(_i5);\n            var delta = cmap.idDelta.get(_i5);\n\n            for (var c = start; c <= end; c++) {\n              var g = 0;\n              if (rangeOffset === 0) {\n                g = c + delta;\n              } else {\n                var index = rangeOffset / 2 + (c - start) - (cmap.segCount - _i5);\n                g = cmap.glyphIndexArray.get(index) || 0;\n                if (g !== 0) {\n                  g += delta;\n                }\n              }\n\n              if (g === gid) {\n                _res2.push(c);\n              }\n            }\n          }\n\n          return _res2;\n        }\n\n      case 12:\n        {\n          var _res3 = [];\n          for (var _iterator5 = cmap.groups.toArray(), _isArray5 = Array.isArray(_iterator5), _i6 = 0, _iterator5 = _isArray5 ? _iterator5 : _getIterator(_iterator5);;) {\n            var _ref6;\n\n            if (_isArray5) {\n              if (_i6 >= _iterator5.length) break;\n              _ref6 = _iterator5[_i6++];\n            } else {\n              _i6 = _iterator5.next();\n              if (_i6.done) break;\n              _ref6 = _i6.value;\n            }\n\n            var group = _ref6;\n\n            if (gid >= group.glyphID && gid <= group.glyphID + (group.endCharCode - group.startCharCode)) {\n              _res3.push(group.startCharCode + (gid - group.glyphID));\n            }\n          }\n\n          return _res3;\n        }\n\n      case 13:\n        {\n          var _res4 = [];\n          for (var _iterator6 = cmap.groups.toArray(), _isArray6 = Array.isArray(_iterator6), _i7 = 0, _iterator6 = _isArray6 ? _iterator6 : _getIterator(_iterator6);;) {\n            var _ref7;\n\n            if (_isArray6) {\n              if (_i7 >= _iterator6.length) break;\n              _ref7 = _iterator6[_i7++];\n            } else {\n              _i7 = _iterator6.next();\n              if (_i7.done) break;\n              _ref7 = _i7.value;\n            }\n\n            var _group = _ref7;\n\n            if (gid === _group.glyphID) {\n              _res4.push.apply(_res4, range(_group.startCharCode, _group.endCharCode + 1));\n            }\n          }\n\n          return _res4;\n        }\n\n      default:\n        throw new Error('Unknown cmap format ' + cmap.version);\n    }\n  };\n\n  return CmapProcessor;\n}(), (_applyDecoratedDescriptor$1(_class$1.prototype, 'getCharacterSet', [cache], _Object$getOwnPropertyDescriptor(_class$1.prototype, 'getCharacterSet'), _class$1.prototype), _applyDecoratedDescriptor$1(_class$1.prototype, 'codePointsForGlyph', [cache], _Object$getOwnPropertyDescriptor(_class$1.prototype, 'codePointsForGlyph'), _class$1.prototype)), _class$1);\n\nvar KernProcessor = function () {\n  function KernProcessor(font) {\n    _classCallCheck(this, KernProcessor);\n\n    this.kern = font.kern;\n  }\n\n  KernProcessor.prototype.process = function process(glyphs, positions) {\n    for (var glyphIndex = 0; glyphIndex < glyphs.length - 1; glyphIndex++) {\n      var left = glyphs[glyphIndex].id;\n      var right = glyphs[glyphIndex + 1].id;\n      positions[glyphIndex].xAdvance += this.getKerning(left, right);\n    }\n  };\n\n  KernProcessor.prototype.getKerning = function getKerning(left, right) {\n    var res = 0;\n\n    for (var _iterator = this.kern.tables, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var table = _ref;\n\n      if (table.coverage.crossStream) {\n        continue;\n      }\n\n      switch (table.version) {\n        case 0:\n          if (!table.coverage.horizontal) {\n            continue;\n          }\n\n          break;\n        case 1:\n          if (table.coverage.vertical || table.coverage.variation) {\n            continue;\n          }\n\n          break;\n        default:\n          throw new Error('Unsupported kerning table version ' + table.version);\n      }\n\n      var val = 0;\n      var s = table.subtable;\n      switch (table.format) {\n        case 0:\n          var pairIdx = binarySearch(s.pairs, function (pair) {\n            return left - pair.left || right - pair.right;\n          });\n\n          if (pairIdx >= 0) {\n            val = s.pairs[pairIdx].value;\n          }\n\n          break;\n\n        case 2:\n          var leftOffset = 0,\n              rightOffset = 0;\n          if (left >= s.leftTable.firstGlyph && left < s.leftTable.firstGlyph + s.leftTable.nGlyphs) {\n            leftOffset = s.leftTable.offsets[left - s.leftTable.firstGlyph];\n          } else {\n            leftOffset = s.array.off;\n          }\n\n          if (right >= s.rightTable.firstGlyph && right < s.rightTable.firstGlyph + s.rightTable.nGlyphs) {\n            rightOffset = s.rightTable.offsets[right - s.rightTable.firstGlyph];\n          }\n\n          var index = (leftOffset + rightOffset - s.array.off) / 2;\n          val = s.array.values.get(index);\n          break;\n\n        case 3:\n          if (left >= s.glyphCount || right >= s.glyphCount) {\n            return 0;\n          }\n\n          val = s.kernValue[s.kernIndex[s.leftClass[left] * s.rightClassCount + s.rightClass[right]]];\n          break;\n\n        default:\n          throw new Error('Unsupported kerning sub-table format ' + table.format);\n      }\n\n      // Microsoft supports the override flag, which resets the result\n      // Otherwise, the sum of the results from all subtables is returned\n      if (table.coverage.override) {\n        res = val;\n      } else {\n        res += val;\n      }\n    }\n\n    return res;\n  };\n\n  return KernProcessor;\n}();\n\n/**\n * This class is used when GPOS does not define 'mark' or 'mkmk' features\n * for positioning marks relative to base glyphs. It uses the unicode\n * combining class property to position marks.\n *\n * Based on code from Harfbuzz, thanks!\n * https://github.com/behdad/harfbuzz/blob/master/src/hb-ot-shape-fallback.cc\n */\n\nvar UnicodeLayoutEngine = function () {\n  function UnicodeLayoutEngine(font) {\n    _classCallCheck(this, UnicodeLayoutEngine);\n\n    this.font = font;\n  }\n\n  UnicodeLayoutEngine.prototype.positionGlyphs = function positionGlyphs(glyphs, positions) {\n    // find each base + mark cluster, and position the marks relative to the base\n    var clusterStart = 0;\n    var clusterEnd = 0;\n    for (var index = 0; index < glyphs.length; index++) {\n      var glyph = glyphs[index];\n      if (glyph.isMark) {\n        // TODO: handle ligatures\n        clusterEnd = index;\n      } else {\n        if (clusterStart !== clusterEnd) {\n          this.positionCluster(glyphs, positions, clusterStart, clusterEnd);\n        }\n\n        clusterStart = clusterEnd = index;\n      }\n    }\n\n    if (clusterStart !== clusterEnd) {\n      this.positionCluster(glyphs, positions, clusterStart, clusterEnd);\n    }\n\n    return positions;\n  };\n\n  UnicodeLayoutEngine.prototype.positionCluster = function positionCluster(glyphs, positions, clusterStart, clusterEnd) {\n    var base = glyphs[clusterStart];\n    var baseBox = base.cbox.copy();\n\n    // adjust bounding box for ligature glyphs\n    if (base.codePoints.length > 1) {\n      // LTR. TODO: RTL support.\n      baseBox.minX += (base.codePoints.length - 1) * baseBox.width / base.codePoints.length;\n    }\n\n    var xOffset = -positions[clusterStart].xAdvance;\n    var yOffset = 0;\n    var yGap = this.font.unitsPerEm / 16;\n\n    // position each of the mark glyphs relative to the base glyph\n    for (var index = clusterStart + 1; index <= clusterEnd; index++) {\n      var mark = glyphs[index];\n      var markBox = mark.cbox;\n      var position = positions[index];\n\n      var combiningClass = this.getCombiningClass(mark.codePoints[0]);\n\n      if (combiningClass !== 'Not_Reordered') {\n        position.xOffset = position.yOffset = 0;\n\n        // x positioning\n        switch (combiningClass) {\n          case 'Double_Above':\n          case 'Double_Below':\n            // LTR. TODO: RTL support.\n            position.xOffset += baseBox.minX - markBox.width / 2 - markBox.minX;\n            break;\n\n          case 'Attached_Below_Left':\n          case 'Below_Left':\n          case 'Above_Left':\n            // left align\n            position.xOffset += baseBox.minX - markBox.minX;\n            break;\n\n          case 'Attached_Above_Right':\n          case 'Below_Right':\n          case 'Above_Right':\n            // right align\n            position.xOffset += baseBox.maxX - markBox.width - markBox.minX;\n            break;\n\n          default:\n            // Attached_Below, Attached_Above, Below, Above, other\n            // center align\n            position.xOffset += baseBox.minX + (baseBox.width - markBox.width) / 2 - markBox.minX;\n        }\n\n        // y positioning\n        switch (combiningClass) {\n          case 'Double_Below':\n          case 'Below_Left':\n          case 'Below':\n          case 'Below_Right':\n          case 'Attached_Below_Left':\n          case 'Attached_Below':\n            // add a small gap between the glyphs if they are not attached\n            if (combiningClass === 'Attached_Below_Left' || combiningClass === 'Attached_Below') {\n              baseBox.minY += yGap;\n            }\n\n            position.yOffset = -baseBox.minY - markBox.maxY;\n            baseBox.minY += markBox.height;\n            break;\n\n          case 'Double_Above':\n          case 'Above_Left':\n          case 'Above':\n          case 'Above_Right':\n          case 'Attached_Above':\n          case 'Attached_Above_Right':\n            // add a small gap between the glyphs if they are not attached\n            if (combiningClass === 'Attached_Above' || combiningClass === 'Attached_Above_Right') {\n              baseBox.maxY += yGap;\n            }\n\n            position.yOffset = baseBox.maxY - markBox.minY;\n            baseBox.maxY += markBox.height;\n            break;\n        }\n\n        position.xAdvance = position.yAdvance = 0;\n        position.xOffset += xOffset;\n        position.yOffset += yOffset;\n      } else {\n        xOffset -= position.xAdvance;\n        yOffset -= position.yAdvance;\n      }\n    }\n\n    return;\n  };\n\n  UnicodeLayoutEngine.prototype.getCombiningClass = function getCombiningClass(codePoint) {\n    var combiningClass = unicode.getCombiningClass(codePoint);\n\n    // Thai / Lao need some per-character work\n    if ((codePoint & ~0xff) === 0x0e00) {\n      if (combiningClass === 'Not_Reordered') {\n        switch (codePoint) {\n          case 0x0e31:\n          case 0x0e34:\n          case 0x0e35:\n          case 0x0e36:\n          case 0x0e37:\n          case 0x0e47:\n          case 0x0e4c:\n          case 0x0e3d:\n          case 0x0e4e:\n            return 'Above_Right';\n\n          case 0x0eb1:\n          case 0x0eb4:\n          case 0x0eb5:\n          case 0x0eb6:\n          case 0x0eb7:\n          case 0x0ebb:\n          case 0x0ecc:\n          case 0x0ecd:\n            return 'Above';\n\n          case 0x0ebc:\n            return 'Below';\n        }\n      } else if (codePoint === 0x0e3a) {\n        // virama\n        return 'Below_Right';\n      }\n    }\n\n    switch (combiningClass) {\n      // Hebrew\n\n      case 'CCC10': // sheva\n      case 'CCC11': // hataf segol\n      case 'CCC12': // hataf patah\n      case 'CCC13': // hataf qamats\n      case 'CCC14': // hiriq\n      case 'CCC15': // tsere\n      case 'CCC16': // segol\n      case 'CCC17': // patah\n      case 'CCC18': // qamats\n      case 'CCC20': // qubuts\n      case 'CCC22':\n        // meteg\n        return 'Below';\n\n      case 'CCC23':\n        // rafe\n        return 'Attached_Above';\n\n      case 'CCC24':\n        // shin dot\n        return 'Above_Right';\n\n      case 'CCC25': // sin dot\n      case 'CCC19':\n        // holam\n        return 'Above_Left';\n\n      case 'CCC26':\n        // point varika\n        return 'Above';\n\n      case 'CCC21':\n        // dagesh\n        break;\n\n      // Arabic and Syriac\n\n      case 'CCC27': // fathatan\n      case 'CCC28': // dammatan\n      case 'CCC30': // fatha\n      case 'CCC31': // damma\n      case 'CCC33': // shadda\n      case 'CCC34': // sukun\n      case 'CCC35': // superscript alef\n      case 'CCC36':\n        // superscript alaph\n        return 'Above';\n\n      case 'CCC29': // kasratan\n      case 'CCC32':\n        // kasra\n        return 'Below';\n\n      // Thai\n\n      case 'CCC103':\n        // sara u / sara uu\n        return 'Below_Right';\n\n      case 'CCC107':\n        // mai\n        return 'Above_Right';\n\n      // Lao\n\n      case 'CCC118':\n        // sign u / sign uu\n        return 'Below';\n\n      case 'CCC122':\n        // mai\n        return 'Above';\n\n      // Tibetan\n\n      case 'CCC129': // sign aa\n      case 'CCC132':\n        // sign u\n        return 'Below';\n\n      case 'CCC130':\n        // sign i\n        return 'Above';\n    }\n\n    return combiningClass;\n  };\n\n  return UnicodeLayoutEngine;\n}();\n\n/**\n * Represents a glyph bounding box\n */\nvar BBox = function () {\n  function BBox() {\n    var minX = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Infinity;\n    var minY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Infinity;\n    var maxX = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : -Infinity;\n    var maxY = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : -Infinity;\n\n    _classCallCheck(this, BBox);\n\n    /**\n     * The minimum X position in the bounding box\n     * @type {number}\n     */\n    this.minX = minX;\n\n    /**\n     * The minimum Y position in the bounding box\n     * @type {number}\n     */\n    this.minY = minY;\n\n    /**\n     * The maxmimum X position in the bounding box\n     * @type {number}\n     */\n    this.maxX = maxX;\n\n    /**\n     * The maxmimum Y position in the bounding box\n     * @type {number}\n     */\n    this.maxY = maxY;\n  }\n\n  /**\n   * The width of the bounding box\n   * @type {number}\n   */\n\n\n  BBox.prototype.addPoint = function addPoint(x, y) {\n    if (Math.abs(x) !== Infinity) {\n      if (x < this.minX) {\n        this.minX = x;\n      }\n\n      if (x > this.maxX) {\n        this.maxX = x;\n      }\n    }\n\n    if (Math.abs(y) !== Infinity) {\n      if (y < this.minY) {\n        this.minY = y;\n      }\n\n      if (y > this.maxY) {\n        this.maxY = y;\n      }\n    }\n  };\n\n  BBox.prototype.copy = function copy() {\n    return new BBox(this.minX, this.minY, this.maxX, this.maxY);\n  };\n\n  _createClass(BBox, [{\n    key: \"width\",\n    get: function get() {\n      return this.maxX - this.minX;\n    }\n\n    /**\n     * The height of the bounding box\n     * @type {number}\n     */\n\n  }, {\n    key: \"height\",\n    get: function get() {\n      return this.maxY - this.minY;\n    }\n  }]);\n\n  return BBox;\n}();\n\n// This maps the Unicode Script property to an OpenType script tag\n// Data from http://www.microsoft.com/typography/otspec/scripttags.htm\n// and http://www.unicode.org/Public/UNIDATA/PropertyValueAliases.txt.\nvar UNICODE_SCRIPTS = {\n  Caucasian_Albanian: 'aghb',\n  Arabic: 'arab',\n  Imperial_Aramaic: 'armi',\n  Armenian: 'armn',\n  Avestan: 'avst',\n  Balinese: 'bali',\n  Bamum: 'bamu',\n  Bassa_Vah: 'bass',\n  Batak: 'batk',\n  Bengali: ['bng2', 'beng'],\n  Bopomofo: 'bopo',\n  Brahmi: 'brah',\n  Braille: 'brai',\n  Buginese: 'bugi',\n  Buhid: 'buhd',\n  Chakma: 'cakm',\n  Canadian_Aboriginal: 'cans',\n  Carian: 'cari',\n  Cham: 'cham',\n  Cherokee: 'cher',\n  Coptic: 'copt',\n  Cypriot: 'cprt',\n  Cyrillic: 'cyrl',\n  Devanagari: ['dev2', 'deva'],\n  Deseret: 'dsrt',\n  Duployan: 'dupl',\n  Egyptian_Hieroglyphs: 'egyp',\n  Elbasan: 'elba',\n  Ethiopic: 'ethi',\n  Georgian: 'geor',\n  Glagolitic: 'glag',\n  Gothic: 'goth',\n  Grantha: 'gran',\n  Greek: 'grek',\n  Gujarati: ['gjr2', 'gujr'],\n  Gurmukhi: ['gur2', 'guru'],\n  Hangul: 'hang',\n  Han: 'hani',\n  Hanunoo: 'hano',\n  Hebrew: 'hebr',\n  Hiragana: 'hira',\n  Pahawh_Hmong: 'hmng',\n  Katakana_Or_Hiragana: 'hrkt',\n  Old_Italic: 'ital',\n  Javanese: 'java',\n  Kayah_Li: 'kali',\n  Katakana: 'kana',\n  Kharoshthi: 'khar',\n  Khmer: 'khmr',\n  Khojki: 'khoj',\n  Kannada: ['knd2', 'knda'],\n  Kaithi: 'kthi',\n  Tai_Tham: 'lana',\n  Lao: 'lao ',\n  Latin: 'latn',\n  Lepcha: 'lepc',\n  Limbu: 'limb',\n  Linear_A: 'lina',\n  Linear_B: 'linb',\n  Lisu: 'lisu',\n  Lycian: 'lyci',\n  Lydian: 'lydi',\n  Mahajani: 'mahj',\n  Mandaic: 'mand',\n  Manichaean: 'mani',\n  Mende_Kikakui: 'mend',\n  Meroitic_Cursive: 'merc',\n  Meroitic_Hieroglyphs: 'mero',\n  Malayalam: ['mlm2', 'mlym'],\n  Modi: 'modi',\n  Mongolian: 'mong',\n  Mro: 'mroo',\n  Meetei_Mayek: 'mtei',\n  Myanmar: ['mym2', 'mymr'],\n  Old_North_Arabian: 'narb',\n  Nabataean: 'nbat',\n  Nko: 'nko ',\n  Ogham: 'ogam',\n  Ol_Chiki: 'olck',\n  Old_Turkic: 'orkh',\n  Oriya: ['ory2', 'orya'],\n  Osmanya: 'osma',\n  Palmyrene: 'palm',\n  Pau_Cin_Hau: 'pauc',\n  Old_Permic: 'perm',\n  Phags_Pa: 'phag',\n  Inscriptional_Pahlavi: 'phli',\n  Psalter_Pahlavi: 'phlp',\n  Phoenician: 'phnx',\n  Miao: 'plrd',\n  Inscriptional_Parthian: 'prti',\n  Rejang: 'rjng',\n  Runic: 'runr',\n  Samaritan: 'samr',\n  Old_South_Arabian: 'sarb',\n  Saurashtra: 'saur',\n  Shavian: 'shaw',\n  Sharada: 'shrd',\n  Siddham: 'sidd',\n  Khudawadi: 'sind',\n  Sinhala: 'sinh',\n  Sora_Sompeng: 'sora',\n  Sundanese: 'sund',\n  Syloti_Nagri: 'sylo',\n  Syriac: 'syrc',\n  Tagbanwa: 'tagb',\n  Takri: 'takr',\n  Tai_Le: 'tale',\n  New_Tai_Lue: 'talu',\n  Tamil: ['tml2', 'taml'],\n  Tai_Viet: 'tavt',\n  Telugu: ['tel2', 'telu'],\n  Tifinagh: 'tfng',\n  Tagalog: 'tglg',\n  Thaana: 'thaa',\n  Thai: 'thai',\n  Tibetan: 'tibt',\n  Tirhuta: 'tirh',\n  Ugaritic: 'ugar',\n  Vai: 'vai ',\n  Warang_Citi: 'wara',\n  Old_Persian: 'xpeo',\n  Cuneiform: 'xsux',\n  Yi: 'yi  ',\n  Inherited: 'zinh',\n  Common: 'zyyy',\n  Unknown: 'zzzz'\n};\n\nvar OPENTYPE_SCRIPTS = {};\nfor (var script in UNICODE_SCRIPTS) {\n  var tag = UNICODE_SCRIPTS[script];\n  if (Array.isArray(tag)) {\n    for (var _iterator = tag, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var t = _ref;\n\n      OPENTYPE_SCRIPTS[t] = script;\n    }\n  } else {\n    OPENTYPE_SCRIPTS[tag] = script;\n  }\n}\n\nfunction fromOpenType(tag) {\n  return OPENTYPE_SCRIPTS[tag];\n}\n\nfunction forString(string) {\n  var len = string.length;\n  var idx = 0;\n  while (idx < len) {\n    var code = string.charCodeAt(idx++);\n\n    // Check if this is a high surrogate\n    if (0xd800 <= code && code <= 0xdbff && idx < len) {\n      var next = string.charCodeAt(idx);\n\n      // Check if this is a low surrogate\n      if (0xdc00 <= next && next <= 0xdfff) {\n        idx++;\n        code = ((code & 0x3FF) << 10) + (next & 0x3FF) + 0x10000;\n      }\n    }\n\n    var _script = unicode.getScript(code);\n    if (_script !== 'Common' && _script !== 'Inherited' && _script !== 'Unknown') {\n      return UNICODE_SCRIPTS[_script];\n    }\n  }\n\n  return UNICODE_SCRIPTS.Unknown;\n}\n\nfunction forCodePoints(codePoints) {\n  for (var i = 0; i < codePoints.length; i++) {\n    var codePoint = codePoints[i];\n    var _script2 = unicode.getScript(codePoint);\n    if (_script2 !== 'Common' && _script2 !== 'Inherited' && _script2 !== 'Unknown') {\n      return UNICODE_SCRIPTS[_script2];\n    }\n  }\n\n  return UNICODE_SCRIPTS.Unknown;\n}\n\n// The scripts in this map are written from right to left\nvar RTL = {\n  arab: true, // Arabic\n  hebr: true, // Hebrew\n  syrc: true, // Syriac\n  thaa: true, // Thaana\n  cprt: true, // Cypriot Syllabary\n  khar: true, // Kharosthi\n  phnx: true, // Phoenician\n  'nko ': true, // N'Ko\n  lydi: true, // Lydian\n  avst: true, // Avestan\n  armi: true, // Imperial Aramaic\n  phli: true, // Inscriptional Pahlavi\n  prti: true, // Inscriptional Parthian\n  sarb: true, // Old South Arabian\n  orkh: true, // Old Turkic, Orkhon Runic\n  samr: true, // Samaritan\n  mand: true, // Mandaic, Mandaean\n  merc: true, // Meroitic Cursive\n  mero: true, // Meroitic Hieroglyphs\n\n  // Unicode 7.0 (not listed on http://www.microsoft.com/typography/otspec/scripttags.htm)\n  mani: true, // Manichaean\n  mend: true, // Mende Kikakui\n  nbat: true, // Nabataean\n  narb: true, // Old North Arabian\n  palm: true, // Palmyrene\n  phlp: true // Psalter Pahlavi\n};\n\nfunction direction(script) {\n  if (RTL[script]) {\n    return 'rtl';\n  }\n\n  return 'ltr';\n}\n\n/**\n * Represents a run of Glyph and GlyphPosition objects.\n * Returned by the font layout method.\n */\n\nvar GlyphRun = function () {\n  function GlyphRun(glyphs, features, script, language, direction$$) {\n    _classCallCheck(this, GlyphRun);\n\n    /**\n     * An array of Glyph objects in the run\n     * @type {Glyph[]}\n     */\n    this.glyphs = glyphs;\n\n    /**\n     * An array of GlyphPosition objects for each glyph in the run\n     * @type {GlyphPosition[]}\n     */\n    this.positions = null;\n\n    /**\n     * The script that was requested for shaping. This was either passed in or detected automatically.\n     * @type {string}\n     */\n    this.script = script;\n\n    /**\n     * The language requested for shaping, as passed in. If `null`, the default language for the\n     * script was used.\n     * @type {string}\n     */\n    this.language = language || null;\n\n    /**\n     * The direction requested for shaping, as passed in (either ltr or rtl).\n     * If `null`, the default direction of the script is used.\n     * @type {string}\n     */\n    this.direction = direction$$ || direction(script);\n\n    /**\n     * The features requested during shaping. This is a combination of user\n     * specified features and features chosen by the shaper.\n     * @type {object}\n     */\n    this.features = {};\n\n    // Convert features to an object\n    if (Array.isArray(features)) {\n      for (var _iterator = features, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n        var _ref;\n\n        if (_isArray) {\n          if (_i >= _iterator.length) break;\n          _ref = _iterator[_i++];\n        } else {\n          _i = _iterator.next();\n          if (_i.done) break;\n          _ref = _i.value;\n        }\n\n        var tag = _ref;\n\n        this.features[tag] = true;\n      }\n    } else if ((typeof features === 'undefined' ? 'undefined' : _typeof(features)) === 'object') {\n      this.features = features;\n    }\n  }\n\n  /**\n   * The total advance width of the run.\n   * @type {number}\n   */\n\n\n  _createClass(GlyphRun, [{\n    key: 'advanceWidth',\n    get: function get() {\n      var width = 0;\n      for (var _iterator2 = this.positions, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n        var _ref2;\n\n        if (_isArray2) {\n          if (_i2 >= _iterator2.length) break;\n          _ref2 = _iterator2[_i2++];\n        } else {\n          _i2 = _iterator2.next();\n          if (_i2.done) break;\n          _ref2 = _i2.value;\n        }\n\n        var position = _ref2;\n\n        width += position.xAdvance;\n      }\n\n      return width;\n    }\n\n    /**\n     * The total advance height of the run.\n     * @type {number}\n     */\n\n  }, {\n    key: 'advanceHeight',\n    get: function get() {\n      var height = 0;\n      for (var _iterator3 = this.positions, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n        var _ref3;\n\n        if (_isArray3) {\n          if (_i3 >= _iterator3.length) break;\n          _ref3 = _iterator3[_i3++];\n        } else {\n          _i3 = _iterator3.next();\n          if (_i3.done) break;\n          _ref3 = _i3.value;\n        }\n\n        var position = _ref3;\n\n        height += position.yAdvance;\n      }\n\n      return height;\n    }\n\n    /**\n     * The bounding box containing all glyphs in the run.\n     * @type {BBox}\n     */\n\n  }, {\n    key: 'bbox',\n    get: function get() {\n      var bbox = new BBox();\n\n      var x = 0;\n      var y = 0;\n      for (var index = 0; index < this.glyphs.length; index++) {\n        var glyph = this.glyphs[index];\n        var p = this.positions[index];\n        var b = glyph.bbox;\n\n        bbox.addPoint(b.minX + x + p.xOffset, b.minY + y + p.yOffset);\n        bbox.addPoint(b.maxX + x + p.xOffset, b.maxY + y + p.yOffset);\n\n        x += p.xAdvance;\n        y += p.yAdvance;\n      }\n\n      return bbox;\n    }\n  }]);\n\n  return GlyphRun;\n}();\n\n/**\n * Represents positioning information for a glyph in a GlyphRun.\n */\nvar GlyphPosition = function GlyphPosition() {\n  var xAdvance = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;\n  var yAdvance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n  var xOffset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n  var yOffset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;\n\n  _classCallCheck(this, GlyphPosition);\n\n  /**\n   * The amount to move the virtual pen in the X direction after rendering this glyph.\n   * @type {number}\n   */\n  this.xAdvance = xAdvance;\n\n  /**\n   * The amount to move the virtual pen in the Y direction after rendering this glyph.\n   * @type {number}\n   */\n  this.yAdvance = yAdvance;\n\n  /**\n   * The offset from the pen position in the X direction at which to render this glyph.\n   * @type {number}\n   */\n  this.xOffset = xOffset;\n\n  /**\n   * The offset from the pen position in the Y direction at which to render this glyph.\n   * @type {number}\n   */\n  this.yOffset = yOffset;\n};\n\n// see https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html\n// and /System/Library/Frameworks/CoreText.framework/Versions/A/Headers/SFNTLayoutTypes.h on a Mac\nvar features = {\n  allTypographicFeatures: {\n    code: 0,\n    exclusive: false,\n    allTypeFeatures: 0\n  },\n  ligatures: {\n    code: 1,\n    exclusive: false,\n    requiredLigatures: 0,\n    commonLigatures: 2,\n    rareLigatures: 4,\n    // logos: 6\n    rebusPictures: 8,\n    diphthongLigatures: 10,\n    squaredLigatures: 12,\n    abbrevSquaredLigatures: 14,\n    symbolLigatures: 16,\n    contextualLigatures: 18,\n    historicalLigatures: 20\n  },\n  cursiveConnection: {\n    code: 2,\n    exclusive: true,\n    unconnected: 0,\n    partiallyConnected: 1,\n    cursive: 2\n  },\n  letterCase: {\n    code: 3,\n    exclusive: true\n  },\n  // upperAndLowerCase: 0          # deprecated\n  // allCaps: 1                    # deprecated\n  // allLowerCase: 2               # deprecated\n  // smallCaps: 3                  # deprecated\n  // initialCaps: 4                # deprecated\n  // initialCapsAndSmallCaps: 5    # deprecated\n  verticalSubstitution: {\n    code: 4,\n    exclusive: false,\n    substituteVerticalForms: 0\n  },\n  linguisticRearrangement: {\n    code: 5,\n    exclusive: false,\n    linguisticRearrangement: 0\n  },\n  numberSpacing: {\n    code: 6,\n    exclusive: true,\n    monospacedNumbers: 0,\n    proportionalNumbers: 1,\n    thirdWidthNumbers: 2,\n    quarterWidthNumbers: 3\n  },\n  smartSwash: {\n    code: 8,\n    exclusive: false,\n    wordInitialSwashes: 0,\n    wordFinalSwashes: 2,\n    // lineInitialSwashes: 4\n    // lineFinalSwashes: 6\n    nonFinalSwashes: 8\n  },\n  diacritics: {\n    code: 9,\n    exclusive: true,\n    showDiacritics: 0,\n    hideDiacritics: 1,\n    decomposeDiacritics: 2\n  },\n  verticalPosition: {\n    code: 10,\n    exclusive: true,\n    normalPosition: 0,\n    superiors: 1,\n    inferiors: 2,\n    ordinals: 3,\n    scientificInferiors: 4\n  },\n  fractions: {\n    code: 11,\n    exclusive: true,\n    noFractions: 0,\n    verticalFractions: 1,\n    diagonalFractions: 2\n  },\n  overlappingCharacters: {\n    code: 13,\n    exclusive: false,\n    preventOverlap: 0\n  },\n  typographicExtras: {\n    code: 14,\n    exclusive: false,\n    // hyphensToEmDash: 0\n    // hyphenToEnDash: 2\n    slashedZero: 4\n  },\n  // formInterrobang: 6\n  // smartQuotes: 8\n  // periodsToEllipsis: 10\n  mathematicalExtras: {\n    code: 15,\n    exclusive: false,\n    // hyphenToMinus: 0\n    // asteristoMultiply: 2\n    // slashToDivide: 4\n    // inequalityLigatures: 6\n    // exponents: 8\n    mathematicalGreek: 10\n  },\n  ornamentSets: {\n    code: 16,\n    exclusive: true,\n    noOrnaments: 0,\n    dingbats: 1,\n    piCharacters: 2,\n    fleurons: 3,\n    decorativeBorders: 4,\n    internationalSymbols: 5,\n    mathSymbols: 6\n  },\n  characterAlternatives: {\n    code: 17,\n    exclusive: true,\n    noAlternates: 0\n  },\n  // user defined options\n  designComplexity: {\n    code: 18,\n    exclusive: true,\n    designLevel1: 0,\n    designLevel2: 1,\n    designLevel3: 2,\n    designLevel4: 3,\n    designLevel5: 4\n  },\n  styleOptions: {\n    code: 19,\n    exclusive: true,\n    noStyleOptions: 0,\n    displayText: 1,\n    engravedText: 2,\n    illuminatedCaps: 3,\n    titlingCaps: 4,\n    tallCaps: 5\n  },\n  characterShape: {\n    code: 20,\n    exclusive: true,\n    traditionalCharacters: 0,\n    simplifiedCharacters: 1,\n    JIS1978Characters: 2,\n    JIS1983Characters: 3,\n    JIS1990Characters: 4,\n    traditionalAltOne: 5,\n    traditionalAltTwo: 6,\n    traditionalAltThree: 7,\n    traditionalAltFour: 8,\n    traditionalAltFive: 9,\n    expertCharacters: 10,\n    JIS2004Characters: 11,\n    hojoCharacters: 12,\n    NLCCharacters: 13,\n    traditionalNamesCharacters: 14\n  },\n  numberCase: {\n    code: 21,\n    exclusive: true,\n    lowerCaseNumbers: 0,\n    upperCaseNumbers: 1\n  },\n  textSpacing: {\n    code: 22,\n    exclusive: true,\n    proportionalText: 0,\n    monospacedText: 1,\n    halfWidthText: 2,\n    thirdWidthText: 3,\n    quarterWidthText: 4,\n    altProportionalText: 5,\n    altHalfWidthText: 6\n  },\n  transliteration: {\n    code: 23,\n    exclusive: true,\n    noTransliteration: 0\n  },\n  // hanjaToHangul: 1\n  // hiraganaToKatakana: 2\n  // katakanaToHiragana: 3\n  // kanaToRomanization: 4\n  // romanizationToHiragana: 5\n  // romanizationToKatakana: 6\n  // hanjaToHangulAltOne: 7\n  // hanjaToHangulAltTwo: 8\n  // hanjaToHangulAltThree: 9\n  annotation: {\n    code: 24,\n    exclusive: true,\n    noAnnotation: 0,\n    boxAnnotation: 1,\n    roundedBoxAnnotation: 2,\n    circleAnnotation: 3,\n    invertedCircleAnnotation: 4,\n    parenthesisAnnotation: 5,\n    periodAnnotation: 6,\n    romanNumeralAnnotation: 7,\n    diamondAnnotation: 8,\n    invertedBoxAnnotation: 9,\n    invertedRoundedBoxAnnotation: 10\n  },\n  kanaSpacing: {\n    code: 25,\n    exclusive: true,\n    fullWidthKana: 0,\n    proportionalKana: 1\n  },\n  ideographicSpacing: {\n    code: 26,\n    exclusive: true,\n    fullWidthIdeographs: 0,\n    proportionalIdeographs: 1,\n    halfWidthIdeographs: 2\n  },\n  unicodeDecomposition: {\n    code: 27,\n    exclusive: false,\n    canonicalComposition: 0,\n    compatibilityComposition: 2,\n    transcodingComposition: 4\n  },\n  rubyKana: {\n    code: 28,\n    exclusive: false,\n    // noRubyKana: 0     # deprecated - use rubyKanaOff instead\n    // rubyKana: 1     # deprecated - use rubyKanaOn instead\n    rubyKana: 2\n  },\n  CJKSymbolAlternatives: {\n    code: 29,\n    exclusive: true,\n    noCJKSymbolAlternatives: 0,\n    CJKSymbolAltOne: 1,\n    CJKSymbolAltTwo: 2,\n    CJKSymbolAltThree: 3,\n    CJKSymbolAltFour: 4,\n    CJKSymbolAltFive: 5\n  },\n  ideographicAlternatives: {\n    code: 30,\n    exclusive: true,\n    noIdeographicAlternatives: 0,\n    ideographicAltOne: 1,\n    ideographicAltTwo: 2,\n    ideographicAltThree: 3,\n    ideographicAltFour: 4,\n    ideographicAltFive: 5\n  },\n  CJKVerticalRomanPlacement: {\n    code: 31,\n    exclusive: true,\n    CJKVerticalRomanCentered: 0,\n    CJKVerticalRomanHBaseline: 1\n  },\n  italicCJKRoman: {\n    code: 32,\n    exclusive: false,\n    // noCJKItalicRoman: 0     # deprecated - use CJKItalicRomanOff instead\n    // CJKItalicRoman: 1     # deprecated - use CJKItalicRomanOn instead\n    CJKItalicRoman: 2\n  },\n  caseSensitiveLayout: {\n    code: 33,\n    exclusive: false,\n    caseSensitiveLayout: 0,\n    caseSensitiveSpacing: 2\n  },\n  alternateKana: {\n    code: 34,\n    exclusive: false,\n    alternateHorizKana: 0,\n    alternateVertKana: 2\n  },\n  stylisticAlternatives: {\n    code: 35,\n    exclusive: false,\n    noStylisticAlternates: 0,\n    stylisticAltOne: 2,\n    stylisticAltTwo: 4,\n    stylisticAltThree: 6,\n    stylisticAltFour: 8,\n    stylisticAltFive: 10,\n    stylisticAltSix: 12,\n    stylisticAltSeven: 14,\n    stylisticAltEight: 16,\n    stylisticAltNine: 18,\n    stylisticAltTen: 20,\n    stylisticAltEleven: 22,\n    stylisticAltTwelve: 24,\n    stylisticAltThirteen: 26,\n    stylisticAltFourteen: 28,\n    stylisticAltFifteen: 30,\n    stylisticAltSixteen: 32,\n    stylisticAltSeventeen: 34,\n    stylisticAltEighteen: 36,\n    stylisticAltNineteen: 38,\n    stylisticAltTwenty: 40\n  },\n  contextualAlternates: {\n    code: 36,\n    exclusive: false,\n    contextualAlternates: 0,\n    swashAlternates: 2,\n    contextualSwashAlternates: 4\n  },\n  lowerCase: {\n    code: 37,\n    exclusive: true,\n    defaultLowerCase: 0,\n    lowerCaseSmallCaps: 1,\n    lowerCasePetiteCaps: 2\n  },\n  upperCase: {\n    code: 38,\n    exclusive: true,\n    defaultUpperCase: 0,\n    upperCaseSmallCaps: 1,\n    upperCasePetiteCaps: 2\n  },\n  languageTag: { // indices into ltag table\n    code: 39,\n    exclusive: true\n  },\n  CJKRomanSpacing: {\n    code: 103,\n    exclusive: true,\n    halfWidthCJKRoman: 0,\n    proportionalCJKRoman: 1,\n    defaultCJKRoman: 2,\n    fullWidthCJKRoman: 3\n  }\n};\n\nvar feature = function feature(name, selector) {\n  return [features[name].code, features[name][selector]];\n};\n\nvar OTMapping = {\n  rlig: feature('ligatures', 'requiredLigatures'),\n  clig: feature('ligatures', 'contextualLigatures'),\n  dlig: feature('ligatures', 'rareLigatures'),\n  hlig: feature('ligatures', 'historicalLigatures'),\n  liga: feature('ligatures', 'commonLigatures'),\n  hist: feature('ligatures', 'historicalLigatures'), // ??\n\n  smcp: feature('lowerCase', 'lowerCaseSmallCaps'),\n  pcap: feature('lowerCase', 'lowerCasePetiteCaps'),\n\n  frac: feature('fractions', 'diagonalFractions'),\n  dnom: feature('fractions', 'diagonalFractions'), // ??\n  numr: feature('fractions', 'diagonalFractions'), // ??\n  afrc: feature('fractions', 'verticalFractions'),\n  // aalt\n  // abvf, abvm, abvs, akhn, blwf, blwm, blws, cfar, cjct, cpsp, falt, isol, jalt, ljmo, mset?\n  // ltra, ltrm, nukt, pref, pres, pstf, psts, rand, rkrf, rphf, rtla, rtlm, size, tjmo, tnum?\n  // unic, vatu, vhal, vjmo, vpal, vrt2\n  // dist -> trak table?\n  // kern, vkrn -> kern table\n  // lfbd + opbd + rtbd -> opbd table?\n  // mark, mkmk -> acnt table?\n  // locl -> languageTag + ltag table\n\n  case: feature('caseSensitiveLayout', 'caseSensitiveLayout'), // also caseSensitiveSpacing\n  ccmp: feature('unicodeDecomposition', 'canonicalComposition'), // compatibilityComposition?\n  cpct: feature('CJKVerticalRomanPlacement', 'CJKVerticalRomanCentered'), // guess..., probably not given below\n  valt: feature('CJKVerticalRomanPlacement', 'CJKVerticalRomanCentered'),\n  swsh: feature('contextualAlternates', 'swashAlternates'),\n  cswh: feature('contextualAlternates', 'contextualSwashAlternates'),\n  curs: feature('cursiveConnection', 'cursive'), // ??\n  c2pc: feature('upperCase', 'upperCasePetiteCaps'),\n  c2sc: feature('upperCase', 'upperCaseSmallCaps'),\n\n  init: feature('smartSwash', 'wordInitialSwashes'), // ??\n  fin2: feature('smartSwash', 'wordFinalSwashes'), // ??\n  medi: feature('smartSwash', 'nonFinalSwashes'), // ??\n  med2: feature('smartSwash', 'nonFinalSwashes'), // ??\n  fin3: feature('smartSwash', 'wordFinalSwashes'), // ??\n  fina: feature('smartSwash', 'wordFinalSwashes'), // ??\n\n  pkna: feature('kanaSpacing', 'proportionalKana'),\n  half: feature('textSpacing', 'halfWidthText'), // also HalfWidthCJKRoman, HalfWidthIdeographs?\n  halt: feature('textSpacing', 'altHalfWidthText'),\n\n  hkna: feature('alternateKana', 'alternateHorizKana'),\n  vkna: feature('alternateKana', 'alternateVertKana'),\n  // hngl: feature 'transliteration', 'hanjaToHangulSelector' # deprecated\n\n  ital: feature('italicCJKRoman', 'CJKItalicRoman'),\n  lnum: feature('numberCase', 'upperCaseNumbers'),\n  onum: feature('numberCase', 'lowerCaseNumbers'),\n  mgrk: feature('mathematicalExtras', 'mathematicalGreek'),\n\n  // nalt: not enough info. what type of annotation?\n  // ornm: ditto, which ornament style?\n\n  calt: feature('contextualAlternates', 'contextualAlternates'), // or more?\n  vrt2: feature('verticalSubstitution', 'substituteVerticalForms'), // oh... below?\n  vert: feature('verticalSubstitution', 'substituteVerticalForms'),\n  tnum: feature('numberSpacing', 'monospacedNumbers'),\n  pnum: feature('numberSpacing', 'proportionalNumbers'),\n  sups: feature('verticalPosition', 'superiors'),\n  subs: feature('verticalPosition', 'inferiors'),\n  ordn: feature('verticalPosition', 'ordinals'),\n  pwid: feature('textSpacing', 'proportionalText'),\n  hwid: feature('textSpacing', 'halfWidthText'),\n  qwid: feature('textSpacing', 'quarterWidthText'), // also QuarterWidthNumbers?\n  twid: feature('textSpacing', 'thirdWidthText'), // also ThirdWidthNumbers?\n  fwid: feature('textSpacing', 'proportionalText'), //??\n  palt: feature('textSpacing', 'altProportionalText'),\n  trad: feature('characterShape', 'traditionalCharacters'),\n  smpl: feature('characterShape', 'simplifiedCharacters'),\n  jp78: feature('characterShape', 'JIS1978Characters'),\n  jp83: feature('characterShape', 'JIS1983Characters'),\n  jp90: feature('characterShape', 'JIS1990Characters'),\n  jp04: feature('characterShape', 'JIS2004Characters'),\n  expt: feature('characterShape', 'expertCharacters'),\n  hojo: feature('characterShape', 'hojoCharacters'),\n  nlck: feature('characterShape', 'NLCCharacters'),\n  tnam: feature('characterShape', 'traditionalNamesCharacters'),\n  ruby: feature('rubyKana', 'rubyKana'),\n  titl: feature('styleOptions', 'titlingCaps'),\n  zero: feature('typographicExtras', 'slashedZero'),\n\n  ss01: feature('stylisticAlternatives', 'stylisticAltOne'),\n  ss02: feature('stylisticAlternatives', 'stylisticAltTwo'),\n  ss03: feature('stylisticAlternatives', 'stylisticAltThree'),\n  ss04: feature('stylisticAlternatives', 'stylisticAltFour'),\n  ss05: feature('stylisticAlternatives', 'stylisticAltFive'),\n  ss06: feature('stylisticAlternatives', 'stylisticAltSix'),\n  ss07: feature('stylisticAlternatives', 'stylisticAltSeven'),\n  ss08: feature('stylisticAlternatives', 'stylisticAltEight'),\n  ss09: feature('stylisticAlternatives', 'stylisticAltNine'),\n  ss10: feature('stylisticAlternatives', 'stylisticAltTen'),\n  ss11: feature('stylisticAlternatives', 'stylisticAltEleven'),\n  ss12: feature('stylisticAlternatives', 'stylisticAltTwelve'),\n  ss13: feature('stylisticAlternatives', 'stylisticAltThirteen'),\n  ss14: feature('stylisticAlternatives', 'stylisticAltFourteen'),\n  ss15: feature('stylisticAlternatives', 'stylisticAltFifteen'),\n  ss16: feature('stylisticAlternatives', 'stylisticAltSixteen'),\n  ss17: feature('stylisticAlternatives', 'stylisticAltSeventeen'),\n  ss18: feature('stylisticAlternatives', 'stylisticAltEighteen'),\n  ss19: feature('stylisticAlternatives', 'stylisticAltNineteen'),\n  ss20: feature('stylisticAlternatives', 'stylisticAltTwenty')\n};\n\n// salt: feature 'stylisticAlternatives', 'stylisticAltOne' # hmm, which one to choose\n\n// Add cv01-cv99 features\nfor (var i = 1; i <= 99; i++) {\n  OTMapping['cv' + ('00' + i).slice(-2)] = [features.characterAlternatives.code, i];\n}\n\n// create inverse mapping\nvar AATMapping = {};\nfor (var ot in OTMapping) {\n  var aat = OTMapping[ot];\n  if (AATMapping[aat[0]] == null) {\n    AATMapping[aat[0]] = {};\n  }\n\n  AATMapping[aat[0]][aat[1]] = ot;\n}\n\n// Maps an array of OpenType features to AAT features\n// in the form of {featureType:{featureSetting:true}}\nfunction mapOTToAAT(features) {\n  var res = {};\n  for (var k in features) {\n    var r = void 0;\n    if (r = OTMapping[k]) {\n      if (res[r[0]] == null) {\n        res[r[0]] = {};\n      }\n\n      res[r[0]][r[1]] = features[k];\n    }\n  }\n\n  return res;\n}\n\n// Maps strings in a [featureType, featureSetting]\n// to their equivalent number codes\nfunction mapFeatureStrings(f) {\n  var type = f[0],\n      setting = f[1];\n\n  if (isNaN(type)) {\n    var typeCode = features[type] && features[type].code;\n  } else {\n    var typeCode = type;\n  }\n\n  if (isNaN(setting)) {\n    var settingCode = features[type] && features[type][setting];\n  } else {\n    var settingCode = setting;\n  }\n\n  return [typeCode, settingCode];\n}\n\n// Maps AAT features to an array of OpenType features\n// Supports both arrays in the form of [[featureType, featureSetting]]\n// and objects in the form of {featureType:{featureSetting:true}}\n// featureTypes and featureSettings can be either strings or number codes\nfunction mapAATToOT(features) {\n  var res = {};\n  if (Array.isArray(features)) {\n    for (var k = 0; k < features.length; k++) {\n      var r = void 0;\n      var f = mapFeatureStrings(features[k]);\n      if (r = AATMapping[f[0]] && AATMapping[f[0]][f[1]]) {\n        res[r] = true;\n      }\n    }\n  } else if ((typeof features === 'undefined' ? 'undefined' : _typeof(features)) === 'object') {\n    for (var type in features) {\n      var _feature = features[type];\n      for (var setting in _feature) {\n        var _r = void 0;\n        var _f = mapFeatureStrings([type, setting]);\n        if (_feature[setting] && (_r = AATMapping[_f[0]] && AATMapping[_f[0]][_f[1]])) {\n          res[_r] = true;\n        }\n      }\n    }\n  }\n\n  return _Object$keys(res);\n}\n\nvar _class$3;\nfunction _applyDecoratedDescriptor$3(target, property, decorators, descriptor, context) {\n  var desc = {};\n  Object['ke' + 'ys'](descriptor).forEach(function (key) {\n    desc[key] = descriptor[key];\n  });\n  desc.enumerable = !!desc.enumerable;\n  desc.configurable = !!desc.configurable;\n\n  if ('value' in desc || desc.initializer) {\n    desc.writable = true;\n  }\n\n  desc = decorators.slice().reverse().reduce(function (desc, decorator) {\n    return decorator(target, property, desc) || desc;\n  }, desc);\n\n  if (context && desc.initializer !== void 0) {\n    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;\n    desc.initializer = undefined;\n  }\n\n  if (desc.initializer === void 0) {\n    Object['define' + 'Property'](target, property, desc);\n    desc = null;\n  }\n\n  return desc;\n}\n\nvar AATLookupTable = (_class$3 = function () {\n  function AATLookupTable(table) {\n    _classCallCheck(this, AATLookupTable);\n\n    this.table = table;\n  }\n\n  AATLookupTable.prototype.lookup = function lookup(glyph) {\n    switch (this.table.version) {\n      case 0:\n        // simple array format\n        return this.table.values.getItem(glyph);\n\n      case 2: // segment format\n      case 4:\n        {\n          var min = 0;\n          var max = this.table.binarySearchHeader.nUnits - 1;\n\n          while (min <= max) {\n            var mid = min + max >> 1;\n            var seg = this.table.segments[mid];\n\n            // special end of search value\n            if (seg.firstGlyph === 0xffff) {\n              return null;\n            }\n\n            if (glyph < seg.firstGlyph) {\n              max = mid - 1;\n            } else if (glyph > seg.lastGlyph) {\n              min = mid + 1;\n            } else {\n              if (this.table.version === 2) {\n                return seg.value;\n              } else {\n                return seg.values[glyph - seg.firstGlyph];\n              }\n            }\n          }\n\n          return null;\n        }\n\n      case 6:\n        {\n          // lookup single\n          var _min = 0;\n          var _max = this.table.binarySearchHeader.nUnits - 1;\n\n          while (_min <= _max) {\n            var mid = _min + _max >> 1;\n            var seg = this.table.segments[mid];\n\n            // special end of search value\n            if (seg.glyph === 0xffff) {\n              return null;\n            }\n\n            if (glyph < seg.glyph) {\n              _max = mid - 1;\n            } else if (glyph > seg.glyph) {\n              _min = mid + 1;\n            } else {\n              return seg.value;\n            }\n          }\n\n          return null;\n        }\n\n      case 8:\n        // lookup trimmed\n        return this.table.values[glyph - this.table.firstGlyph];\n\n      default:\n        throw new Error('Unknown lookup table format: ' + this.table.version);\n    }\n  };\n\n  AATLookupTable.prototype.glyphsForValue = function glyphsForValue(classValue) {\n    var res = [];\n\n    switch (this.table.version) {\n      case 2: // segment format\n      case 4:\n        {\n          for (var _iterator = this.table.segments, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n            var _ref;\n\n            if (_isArray) {\n              if (_i >= _iterator.length) break;\n              _ref = _iterator[_i++];\n            } else {\n              _i = _iterator.next();\n              if (_i.done) break;\n              _ref = _i.value;\n            }\n\n            var segment = _ref;\n\n            if (this.table.version === 2 && segment.value === classValue) {\n              res.push.apply(res, range(segment.firstGlyph, segment.lastGlyph + 1));\n            } else {\n              for (var index = 0; index < segment.values.length; index++) {\n                if (segment.values[index] === classValue) {\n                  res.push(segment.firstGlyph + index);\n                }\n              }\n            }\n          }\n\n          break;\n        }\n\n      case 6:\n        {\n          // lookup single\n          for (var _iterator2 = this.table.segments, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n            var _ref2;\n\n            if (_isArray2) {\n              if (_i2 >= _iterator2.length) break;\n              _ref2 = _iterator2[_i2++];\n            } else {\n              _i2 = _iterator2.next();\n              if (_i2.done) break;\n              _ref2 = _i2.value;\n            }\n\n            var _segment = _ref2;\n\n            if (_segment.value === classValue) {\n              res.push(_segment.glyph);\n            }\n          }\n\n          break;\n        }\n\n      case 8:\n        {\n          // lookup trimmed\n          for (var i = 0; i < this.table.values.length; i++) {\n            if (this.table.values[i] === classValue) {\n              res.push(this.table.firstGlyph + i);\n            }\n          }\n\n          break;\n        }\n\n      default:\n        throw new Error('Unknown lookup table format: ' + this.table.version);\n    }\n\n    return res;\n  };\n\n  return AATLookupTable;\n}(), (_applyDecoratedDescriptor$3(_class$3.prototype, 'glyphsForValue', [cache], _Object$getOwnPropertyDescriptor(_class$3.prototype, 'glyphsForValue'), _class$3.prototype)), _class$3);\n\nvar START_OF_TEXT_STATE = 0;\nvar END_OF_TEXT_CLASS = 0;\nvar OUT_OF_BOUNDS_CLASS = 1;\nvar DELETED_GLYPH_CLASS = 2;\nvar DONT_ADVANCE = 0x4000;\n\nvar AATStateMachine = function () {\n  function AATStateMachine(stateTable) {\n    _classCallCheck(this, AATStateMachine);\n\n    this.stateTable = stateTable;\n    this.lookupTable = new AATLookupTable(stateTable.classTable);\n  }\n\n  AATStateMachine.prototype.process = function process(glyphs, reverse, processEntry) {\n    var currentState = START_OF_TEXT_STATE; // START_OF_LINE_STATE is used for kashida glyph insertions sometimes I think?\n    var index = reverse ? glyphs.length - 1 : 0;\n    var dir = reverse ? -1 : 1;\n\n    while (dir === 1 && index <= glyphs.length || dir === -1 && index >= -1) {\n      var glyph = null;\n      var classCode = OUT_OF_BOUNDS_CLASS;\n      var shouldAdvance = true;\n\n      if (index === glyphs.length || index === -1) {\n        classCode = END_OF_TEXT_CLASS;\n      } else {\n        glyph = glyphs[index];\n        if (glyph.id === 0xffff) {\n          // deleted glyph\n          classCode = DELETED_GLYPH_CLASS;\n        } else {\n          classCode = this.lookupTable.lookup(glyph.id);\n          if (classCode == null) {\n            classCode = OUT_OF_BOUNDS_CLASS;\n          }\n        }\n      }\n\n      var row = this.stateTable.stateArray.getItem(currentState);\n      var entryIndex = row[classCode];\n      var entry = this.stateTable.entryTable.getItem(entryIndex);\n\n      if (classCode !== END_OF_TEXT_CLASS && classCode !== DELETED_GLYPH_CLASS) {\n        processEntry(glyph, entry, index);\n        shouldAdvance = !(entry.flags & DONT_ADVANCE);\n      }\n\n      currentState = entry.newState;\n      if (shouldAdvance) {\n        index += dir;\n      }\n    }\n\n    return glyphs;\n  };\n\n  /**\n   * Performs a depth-first traversal of the glyph strings\n   * represented by the state machine.\n   */\n\n\n  AATStateMachine.prototype.traverse = function traverse(opts) {\n    var state = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n    var visited = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : new _Set();\n\n    if (visited.has(state)) {\n      return;\n    }\n\n    visited.add(state);\n\n    var _stateTable = this.stateTable,\n        nClasses = _stateTable.nClasses,\n        stateArray = _stateTable.stateArray,\n        entryTable = _stateTable.entryTable;\n\n    var row = stateArray.getItem(state);\n\n    // Skip predefined classes\n    for (var classCode = 4; classCode < nClasses; classCode++) {\n      var entryIndex = row[classCode];\n      var entry = entryTable.getItem(entryIndex);\n\n      // Try all glyphs in the class\n      for (var _iterator = this.lookupTable.glyphsForValue(classCode), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n        var _ref;\n\n        if (_isArray) {\n          if (_i >= _iterator.length) break;\n          _ref = _iterator[_i++];\n        } else {\n          _i = _iterator.next();\n          if (_i.done) break;\n          _ref = _i.value;\n        }\n\n        var glyph = _ref;\n\n        if (opts.enter) {\n          opts.enter(glyph, entry);\n        }\n\n        if (entry.newState !== 0) {\n          this.traverse(opts, entry.newState, visited);\n        }\n\n        if (opts.exit) {\n          opts.exit(glyph, entry);\n        }\n      }\n    }\n  };\n\n  return AATStateMachine;\n}();\n\nvar _class$2;\nfunction _applyDecoratedDescriptor$2(target, property, decorators, descriptor, context) {\n  var desc = {};\n  Object['ke' + 'ys'](descriptor).forEach(function (key) {\n    desc[key] = descriptor[key];\n  });\n  desc.enumerable = !!desc.enumerable;\n  desc.configurable = !!desc.configurable;\n\n  if ('value' in desc || desc.initializer) {\n    desc.writable = true;\n  }\n\n  desc = decorators.slice().reverse().reduce(function (desc, decorator) {\n    return decorator(target, property, desc) || desc;\n  }, desc);\n\n  if (context && desc.initializer !== void 0) {\n    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;\n    desc.initializer = undefined;\n  }\n\n  if (desc.initializer === void 0) {\n    Object['define' + 'Property'](target, property, desc);\n    desc = null;\n  }\n\n  return desc;\n}\n\n// indic replacement flags\nvar MARK_FIRST = 0x8000;\nvar MARK_LAST = 0x2000;\nvar VERB = 0x000F;\n\n// contextual substitution and glyph insertion flag\nvar SET_MARK = 0x8000;\n\n// ligature entry flags\nvar SET_COMPONENT = 0x8000;\nvar PERFORM_ACTION = 0x2000;\n\n// ligature action masks\nvar LAST_MASK = 0x80000000;\nvar STORE_MASK = 0x40000000;\nvar OFFSET_MASK = 0x3FFFFFFF;\n\nvar REVERSE_DIRECTION = 0x400000;\nvar CURRENT_INSERT_BEFORE = 0x0800;\nvar MARKED_INSERT_BEFORE = 0x0400;\nvar CURRENT_INSERT_COUNT = 0x03E0;\nvar MARKED_INSERT_COUNT = 0x001F;\n\nvar AATMorxProcessor = (_class$2 = function () {\n  function AATMorxProcessor(font) {\n    _classCallCheck(this, AATMorxProcessor);\n\n    this.processIndicRearragement = this.processIndicRearragement.bind(this);\n    this.processContextualSubstitution = this.processContextualSubstitution.bind(this);\n    this.processLigature = this.processLigature.bind(this);\n    this.processNoncontextualSubstitutions = this.processNoncontextualSubstitutions.bind(this);\n    this.processGlyphInsertion = this.processGlyphInsertion.bind(this);\n    this.font = font;\n    this.morx = font.morx;\n    this.inputCache = null;\n  }\n\n  // Processes an array of glyphs and applies the specified features\n  // Features should be in the form of {featureType:{featureSetting:true}}\n\n\n  AATMorxProcessor.prototype.process = function process(glyphs) {\n    var features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n    for (var _iterator = this.morx.chains, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var chain = _ref;\n\n      var flags = chain.defaultFlags;\n\n      // enable/disable the requested features\n      for (var _iterator2 = chain.features, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n        var _ref2;\n\n        if (_isArray2) {\n          if (_i2 >= _iterator2.length) break;\n          _ref2 = _iterator2[_i2++];\n        } else {\n          _i2 = _iterator2.next();\n          if (_i2.done) break;\n          _ref2 = _i2.value;\n        }\n\n        var feature = _ref2;\n\n        var f = void 0;\n        if ((f = features[feature.featureType]) && f[feature.featureSetting]) {\n          flags &= feature.disableFlags;\n          flags |= feature.enableFlags;\n        }\n      }\n\n      for (var _iterator3 = chain.subtables, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n        var _ref3;\n\n        if (_isArray3) {\n          if (_i3 >= _iterator3.length) break;\n          _ref3 = _iterator3[_i3++];\n        } else {\n          _i3 = _iterator3.next();\n          if (_i3.done) break;\n          _ref3 = _i3.value;\n        }\n\n        var subtable = _ref3;\n\n        if (subtable.subFeatureFlags & flags) {\n          this.processSubtable(subtable, glyphs);\n        }\n      }\n    }\n\n    // remove deleted glyphs\n    var index = glyphs.length - 1;\n    while (index >= 0) {\n      if (glyphs[index].id === 0xffff) {\n        glyphs.splice(index, 1);\n      }\n\n      index--;\n    }\n\n    return glyphs;\n  };\n\n  AATMorxProcessor.prototype.processSubtable = function processSubtable(subtable, glyphs) {\n    this.subtable = subtable;\n    this.glyphs = glyphs;\n    if (this.subtable.type === 4) {\n      this.processNoncontextualSubstitutions(this.subtable, this.glyphs);\n      return;\n    }\n\n    this.ligatureStack = [];\n    this.markedGlyph = null;\n    this.firstGlyph = null;\n    this.lastGlyph = null;\n    this.markedIndex = null;\n\n    var stateMachine = this.getStateMachine(subtable);\n    var process = this.getProcessor();\n\n    var reverse = !!(this.subtable.coverage & REVERSE_DIRECTION);\n    return stateMachine.process(this.glyphs, reverse, process);\n  };\n\n  AATMorxProcessor.prototype.getStateMachine = function getStateMachine(subtable) {\n    return new AATStateMachine(subtable.table.stateTable);\n  };\n\n  AATMorxProcessor.prototype.getProcessor = function getProcessor() {\n    switch (this.subtable.type) {\n      case 0:\n        return this.processIndicRearragement;\n      case 1:\n        return this.processContextualSubstitution;\n      case 2:\n        return this.processLigature;\n      case 4:\n        return this.processNoncontextualSubstitutions;\n      case 5:\n        return this.processGlyphInsertion;\n      default:\n        throw new Error('Invalid morx subtable type: ' + this.subtable.type);\n    }\n  };\n\n  AATMorxProcessor.prototype.processIndicRearragement = function processIndicRearragement(glyph, entry, index) {\n    if (entry.flags & MARK_FIRST) {\n      this.firstGlyph = index;\n    }\n\n    if (entry.flags & MARK_LAST) {\n      this.lastGlyph = index;\n    }\n\n    reorderGlyphs(this.glyphs, entry.flags & VERB, this.firstGlyph, this.lastGlyph);\n  };\n\n  AATMorxProcessor.prototype.processContextualSubstitution = function processContextualSubstitution(glyph, entry, index) {\n    var subsitutions = this.subtable.table.substitutionTable.items;\n    if (entry.markIndex !== 0xffff) {\n      var lookup = subsitutions.getItem(entry.markIndex);\n      var lookupTable = new AATLookupTable(lookup);\n      glyph = this.glyphs[this.markedGlyph];\n      var gid = lookupTable.lookup(glyph.id);\n      if (gid) {\n        this.glyphs[this.markedGlyph] = this.font.getGlyph(gid, glyph.codePoints);\n      }\n    }\n\n    if (entry.currentIndex !== 0xffff) {\n      var _lookup = subsitutions.getItem(entry.currentIndex);\n      var _lookupTable = new AATLookupTable(_lookup);\n      glyph = this.glyphs[index];\n      var gid = _lookupTable.lookup(glyph.id);\n      if (gid) {\n        this.glyphs[index] = this.font.getGlyph(gid, glyph.codePoints);\n      }\n    }\n\n    if (entry.flags & SET_MARK) {\n      this.markedGlyph = index;\n    }\n  };\n\n  AATMorxProcessor.prototype.processLigature = function processLigature(glyph, entry, index) {\n    if (entry.flags & SET_COMPONENT) {\n      this.ligatureStack.push(index);\n    }\n\n    if (entry.flags & PERFORM_ACTION) {\n      var _ligatureStack;\n\n      var actions = this.subtable.table.ligatureActions;\n      var components = this.subtable.table.components;\n      var ligatureList = this.subtable.table.ligatureList;\n\n      var actionIndex = entry.action;\n      var last = false;\n      var ligatureIndex = 0;\n      var codePoints = [];\n      var ligatureGlyphs = [];\n\n      while (!last) {\n        var _codePoints;\n\n        var componentGlyph = this.ligatureStack.pop();\n        (_codePoints = codePoints).unshift.apply(_codePoints, this.glyphs[componentGlyph].codePoints);\n\n        var action = actions.getItem(actionIndex++);\n        last = !!(action & LAST_MASK);\n        var store = !!(action & STORE_MASK);\n        var offset = (action & OFFSET_MASK) << 2 >> 2; // sign extend 30 to 32 bits\n        offset += this.glyphs[componentGlyph].id;\n\n        var component = components.getItem(offset);\n        ligatureIndex += component;\n\n        if (last || store) {\n          var ligatureEntry = ligatureList.getItem(ligatureIndex);\n          this.glyphs[componentGlyph] = this.font.getGlyph(ligatureEntry, codePoints);\n          ligatureGlyphs.push(componentGlyph);\n          ligatureIndex = 0;\n          codePoints = [];\n        } else {\n          this.glyphs[componentGlyph] = this.font.getGlyph(0xffff);\n        }\n      }\n\n      // Put ligature glyph indexes back on the stack\n      (_ligatureStack = this.ligatureStack).push.apply(_ligatureStack, ligatureGlyphs);\n    }\n  };\n\n  AATMorxProcessor.prototype.processNoncontextualSubstitutions = function processNoncontextualSubstitutions(subtable, glyphs, index) {\n    var lookupTable = new AATLookupTable(subtable.table.lookupTable);\n\n    for (index = 0; index < glyphs.length; index++) {\n      var glyph = glyphs[index];\n      if (glyph.id !== 0xffff) {\n        var gid = lookupTable.lookup(glyph.id);\n        if (gid) {\n          // 0 means do nothing\n          glyphs[index] = this.font.getGlyph(gid, glyph.codePoints);\n        }\n      }\n    }\n  };\n\n  AATMorxProcessor.prototype._insertGlyphs = function _insertGlyphs(glyphIndex, insertionActionIndex, count, isBefore) {\n    var _glyphs;\n\n    var insertions = [];\n    while (count--) {\n      var gid = this.subtable.table.insertionActions.getItem(insertionActionIndex++);\n      insertions.push(this.font.getGlyph(gid));\n    }\n\n    if (!isBefore) {\n      glyphIndex++;\n    }\n\n    (_glyphs = this.glyphs).splice.apply(_glyphs, [glyphIndex, 0].concat(insertions));\n  };\n\n  AATMorxProcessor.prototype.processGlyphInsertion = function processGlyphInsertion(glyph, entry, index) {\n    if (entry.flags & SET_MARK) {\n      this.markedIndex = index;\n    }\n\n    if (entry.markedInsertIndex !== 0xffff) {\n      var count = (entry.flags & MARKED_INSERT_COUNT) >>> 5;\n      var isBefore = !!(entry.flags & MARKED_INSERT_BEFORE);\n      this._insertGlyphs(this.markedIndex, entry.markedInsertIndex, count, isBefore);\n    }\n\n    if (entry.currentInsertIndex !== 0xffff) {\n      var _count = (entry.flags & CURRENT_INSERT_COUNT) >>> 5;\n      var _isBefore = !!(entry.flags & CURRENT_INSERT_BEFORE);\n      this._insertGlyphs(index, entry.currentInsertIndex, _count, _isBefore);\n    }\n  };\n\n  AATMorxProcessor.prototype.getSupportedFeatures = function getSupportedFeatures() {\n    var features = [];\n    for (var _iterator4 = this.morx.chains, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _getIterator(_iterator4);;) {\n      var _ref4;\n\n      if (_isArray4) {\n        if (_i4 >= _iterator4.length) break;\n        _ref4 = _iterator4[_i4++];\n      } else {\n        _i4 = _iterator4.next();\n        if (_i4.done) break;\n        _ref4 = _i4.value;\n      }\n\n      var chain = _ref4;\n\n      for (var _iterator5 = chain.features, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _getIterator(_iterator5);;) {\n        var _ref5;\n\n        if (_isArray5) {\n          if (_i5 >= _iterator5.length) break;\n          _ref5 = _iterator5[_i5++];\n        } else {\n          _i5 = _iterator5.next();\n          if (_i5.done) break;\n          _ref5 = _i5.value;\n        }\n\n        var feature = _ref5;\n\n        features.push([feature.featureType, feature.featureSetting]);\n      }\n    }\n\n    return features;\n  };\n\n  AATMorxProcessor.prototype.generateInputs = function generateInputs(gid) {\n    if (!this.inputCache) {\n      this.generateInputCache();\n    }\n\n    return this.inputCache[gid] || [];\n  };\n\n  AATMorxProcessor.prototype.generateInputCache = function generateInputCache() {\n    this.inputCache = {};\n\n    for (var _iterator6 = this.morx.chains, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _getIterator(_iterator6);;) {\n      var _ref6;\n\n      if (_isArray6) {\n        if (_i6 >= _iterator6.length) break;\n        _ref6 = _iterator6[_i6++];\n      } else {\n        _i6 = _iterator6.next();\n        if (_i6.done) break;\n        _ref6 = _i6.value;\n      }\n\n      var chain = _ref6;\n\n      var flags = chain.defaultFlags;\n\n      for (var _iterator7 = chain.subtables, _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _getIterator(_iterator7);;) {\n        var _ref7;\n\n        if (_isArray7) {\n          if (_i7 >= _iterator7.length) break;\n          _ref7 = _iterator7[_i7++];\n        } else {\n          _i7 = _iterator7.next();\n          if (_i7.done) break;\n          _ref7 = _i7.value;\n        }\n\n        var subtable = _ref7;\n\n        if (subtable.subFeatureFlags & flags) {\n          this.generateInputsForSubtable(subtable);\n        }\n      }\n    }\n  };\n\n  AATMorxProcessor.prototype.generateInputsForSubtable = function generateInputsForSubtable(subtable) {\n    var _this = this;\n\n    // Currently, only supporting ligature subtables.\n    if (subtable.type !== 2) {\n      return;\n    }\n\n    var reverse = !!(subtable.coverage & REVERSE_DIRECTION);\n    if (reverse) {\n      throw new Error('Reverse subtable, not supported.');\n    }\n\n    this.subtable = subtable;\n    this.ligatureStack = [];\n\n    var stateMachine = this.getStateMachine(subtable);\n    var process = this.getProcessor();\n\n    var input = [];\n    var stack = [];\n    this.glyphs = [];\n\n    stateMachine.traverse({\n      enter: function enter(glyph, entry) {\n        var glyphs = _this.glyphs;\n        stack.push({\n          glyphs: glyphs.slice(),\n          ligatureStack: _this.ligatureStack.slice()\n        });\n\n        // Add glyph to input and glyphs to process.\n        var g = _this.font.getGlyph(glyph);\n        input.push(g);\n        glyphs.push(input[input.length - 1]);\n\n        // Process ligature substitution\n        process(glyphs[glyphs.length - 1], entry, glyphs.length - 1);\n\n        // Add input to result if only one matching (non-deleted) glyph remains.\n        var count = 0;\n        var found = 0;\n        for (var i = 0; i < glyphs.length && count <= 1; i++) {\n          if (glyphs[i].id !== 0xffff) {\n            count++;\n            found = glyphs[i].id;\n          }\n        }\n\n        if (count === 1) {\n          var result = input.map(function (g) {\n            return g.id;\n          });\n          var _cache = _this.inputCache[found];\n          if (_cache) {\n            _cache.push(result);\n          } else {\n            _this.inputCache[found] = [result];\n          }\n        }\n      },\n\n      exit: function exit() {\n        var _stack$pop = stack.pop();\n\n        _this.glyphs = _stack$pop.glyphs;\n        _this.ligatureStack = _stack$pop.ligatureStack;\n\n        input.pop();\n      }\n    });\n  };\n\n  return AATMorxProcessor;\n}(), (_applyDecoratedDescriptor$2(_class$2.prototype, 'getStateMachine', [cache], _Object$getOwnPropertyDescriptor(_class$2.prototype, 'getStateMachine'), _class$2.prototype)), _class$2);\n\nfunction swap(glyphs, rangeA, rangeB) {\n  var reverseA = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n  var reverseB = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;\n\n  var end = glyphs.splice(rangeB[0] - (rangeB[1] - 1), rangeB[1]);\n  if (reverseB) {\n    end.reverse();\n  }\n\n  var start = glyphs.splice.apply(glyphs, [rangeA[0], rangeA[1]].concat(end));\n  if (reverseA) {\n    start.reverse();\n  }\n\n  glyphs.splice.apply(glyphs, [rangeB[0] - (rangeA[1] - 1), 0].concat(start));\n  return glyphs;\n}\n\nfunction reorderGlyphs(glyphs, verb, firstGlyph, lastGlyph) {\n  var length = lastGlyph - firstGlyph + 1;\n  switch (verb) {\n    case 0:\n      // no change\n      return glyphs;\n\n    case 1:\n      // Ax => xA\n      return swap(glyphs, [firstGlyph, 1], [lastGlyph, 0]);\n\n    case 2:\n      // xD => Dx\n      return swap(glyphs, [firstGlyph, 0], [lastGlyph, 1]);\n\n    case 3:\n      // AxD => DxA\n      return swap(glyphs, [firstGlyph, 1], [lastGlyph, 1]);\n\n    case 4:\n      // ABx => xAB\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 0]);\n\n    case 5:\n      // ABx => xBA\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 0], true, false);\n\n    case 6:\n      // xCD => CDx\n      return swap(glyphs, [firstGlyph, 0], [lastGlyph, 2]);\n\n    case 7:\n      // xCD => DCx\n      return swap(glyphs, [firstGlyph, 0], [lastGlyph, 2], false, true);\n\n    case 8:\n      // AxCD => CDxA\n      return swap(glyphs, [firstGlyph, 1], [lastGlyph, 2]);\n\n    case 9:\n      // AxCD => DCxA\n      return swap(glyphs, [firstGlyph, 1], [lastGlyph, 2], false, true);\n\n    case 10:\n      // ABxD => DxAB\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 1]);\n\n    case 11:\n      // ABxD => DxBA\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 1], true, false);\n\n    case 12:\n      // ABxCD => CDxAB\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2]);\n\n    case 13:\n      // ABxCD => CDxBA\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2], true, false);\n\n    case 14:\n      // ABxCD => DCxAB\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2], false, true);\n\n    case 15:\n      // ABxCD => DCxBA\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2], true, true);\n\n    default:\n      throw new Error('Unknown verb: ' + verb);\n  }\n}\n\nvar AATLayoutEngine = function () {\n  function AATLayoutEngine(font) {\n    _classCallCheck(this, AATLayoutEngine);\n\n    this.font = font;\n    this.morxProcessor = new AATMorxProcessor(font);\n    this.fallbackPosition = false;\n  }\n\n  AATLayoutEngine.prototype.substitute = function substitute(glyphRun) {\n    // AAT expects the glyphs to be in visual order prior to morx processing,\n    // so reverse the glyphs if the script is right-to-left.\n    if (glyphRun.direction === 'rtl') {\n      glyphRun.glyphs.reverse();\n    }\n\n    this.morxProcessor.process(glyphRun.glyphs, mapOTToAAT(glyphRun.features));\n  };\n\n  AATLayoutEngine.prototype.getAvailableFeatures = function getAvailableFeatures(script, language) {\n    return mapAATToOT(this.morxProcessor.getSupportedFeatures());\n  };\n\n  AATLayoutEngine.prototype.stringsForGlyph = function stringsForGlyph(gid) {\n    var glyphStrings = this.morxProcessor.generateInputs(gid);\n    var result = new _Set();\n\n    for (var _iterator = glyphStrings, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var glyphs = _ref;\n\n      this._addStrings(glyphs, 0, result, '');\n    }\n\n    return result;\n  };\n\n  AATLayoutEngine.prototype._addStrings = function _addStrings(glyphs, index, strings, string) {\n    var codePoints = this.font._cmapProcessor.codePointsForGlyph(glyphs[index]);\n\n    for (var _iterator2 = codePoints, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n      var _ref2;\n\n      if (_isArray2) {\n        if (_i2 >= _iterator2.length) break;\n        _ref2 = _iterator2[_i2++];\n      } else {\n        _i2 = _iterator2.next();\n        if (_i2.done) break;\n        _ref2 = _i2.value;\n      }\n\n      var codePoint = _ref2;\n\n      var s = string + _String$fromCodePoint(codePoint);\n      if (index < glyphs.length - 1) {\n        this._addStrings(glyphs, index + 1, strings, s);\n      } else {\n        strings.add(s);\n      }\n    }\n  };\n\n  return AATLayoutEngine;\n}();\n\n/**\n * ShapingPlans are used by the OpenType shapers to store which\n * features should by applied, and in what order to apply them.\n * The features are applied in groups called stages. A feature\n * can be applied globally to all glyphs, or locally to only\n * specific glyphs.\n *\n * @private\n */\n\nvar ShapingPlan = function () {\n  function ShapingPlan(font, script, direction) {\n    _classCallCheck(this, ShapingPlan);\n\n    this.font = font;\n    this.script = script;\n    this.direction = direction;\n    this.stages = [];\n    this.globalFeatures = {};\n    this.allFeatures = {};\n  }\n\n  /**\n   * Adds the given features to the last stage.\n   * Ignores features that have already been applied.\n   */\n\n\n  ShapingPlan.prototype._addFeatures = function _addFeatures(features, global) {\n    var stageIndex = this.stages.length - 1;\n    var stage = this.stages[stageIndex];\n    for (var _iterator = features, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var feature = _ref;\n\n      if (this.allFeatures[feature] == null) {\n        stage.push(feature);\n        this.allFeatures[feature] = stageIndex;\n\n        if (global) {\n          this.globalFeatures[feature] = true;\n        }\n      }\n    }\n  };\n\n  /**\n   * Add features to the last stage\n   */\n\n\n  ShapingPlan.prototype.add = function add(arg) {\n    var global = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n\n    if (this.stages.length === 0) {\n      this.stages.push([]);\n    }\n\n    if (typeof arg === 'string') {\n      arg = [arg];\n    }\n\n    if (Array.isArray(arg)) {\n      this._addFeatures(arg, global);\n    } else if ((typeof arg === 'undefined' ? 'undefined' : _typeof(arg)) === 'object') {\n      this._addFeatures(arg.global || [], true);\n      this._addFeatures(arg.local || [], false);\n    } else {\n      throw new Error(\"Unsupported argument to ShapingPlan#add\");\n    }\n  };\n\n  /**\n   * Add a new stage\n   */\n\n\n  ShapingPlan.prototype.addStage = function addStage(arg, global) {\n    if (typeof arg === 'function') {\n      this.stages.push(arg, []);\n    } else {\n      this.stages.push([]);\n      this.add(arg, global);\n    }\n  };\n\n  ShapingPlan.prototype.setFeatureOverrides = function setFeatureOverrides(features) {\n    if (Array.isArray(features)) {\n      this.add(features);\n    } else if ((typeof features === 'undefined' ? 'undefined' : _typeof(features)) === 'object') {\n      for (var tag in features) {\n        if (features[tag]) {\n          this.add(tag);\n        } else if (this.allFeatures[tag] != null) {\n          var stage = this.stages[this.allFeatures[tag]];\n          stage.splice(stage.indexOf(tag), 1);\n          delete this.allFeatures[tag];\n          delete this.globalFeatures[tag];\n        }\n      }\n    }\n  };\n\n  /**\n   * Assigns the global features to the given glyphs\n   */\n\n\n  ShapingPlan.prototype.assignGlobalFeatures = function assignGlobalFeatures(glyphs) {\n    for (var _iterator2 = glyphs, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n      var _ref2;\n\n      if (_isArray2) {\n        if (_i2 >= _iterator2.length) break;\n        _ref2 = _iterator2[_i2++];\n      } else {\n        _i2 = _iterator2.next();\n        if (_i2.done) break;\n        _ref2 = _i2.value;\n      }\n\n      var glyph = _ref2;\n\n      for (var feature in this.globalFeatures) {\n        glyph.features[feature] = true;\n      }\n    }\n  };\n\n  /**\n   * Executes the planned stages using the given OTProcessor\n   */\n\n\n  ShapingPlan.prototype.process = function process(processor, glyphs, positions) {\n    for (var _iterator3 = this.stages, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n      var _ref3;\n\n      if (_isArray3) {\n        if (_i3 >= _iterator3.length) break;\n        _ref3 = _iterator3[_i3++];\n      } else {\n        _i3 = _iterator3.next();\n        if (_i3.done) break;\n        _ref3 = _i3.value;\n      }\n\n      var stage = _ref3;\n\n      if (typeof stage === 'function') {\n        if (!positions) {\n          stage(this.font, glyphs, this);\n        }\n      } else if (stage.length > 0) {\n        processor.applyFeatures(stage, glyphs, positions);\n      }\n    }\n  };\n\n  return ShapingPlan;\n}();\n\nvar _class$4;\nvar _temp;\nvar VARIATION_FEATURES = ['rvrn'];\nvar COMMON_FEATURES = ['ccmp', 'locl', 'rlig', 'mark', 'mkmk'];\nvar FRACTIONAL_FEATURES = ['frac', 'numr', 'dnom'];\nvar HORIZONTAL_FEATURES = ['calt', 'clig', 'liga', 'rclt', 'curs', 'kern'];\nvar DIRECTIONAL_FEATURES = {\n  ltr: ['ltra', 'ltrm'],\n  rtl: ['rtla', 'rtlm']\n};\n\nvar DefaultShaper = (_temp = _class$4 = function () {\n  function DefaultShaper() {\n    _classCallCheck(this, DefaultShaper);\n  }\n\n  DefaultShaper.plan = function plan(_plan, glyphs, features) {\n    // Plan the features we want to apply\n    this.planPreprocessing(_plan);\n    this.planFeatures(_plan);\n    this.planPostprocessing(_plan, features);\n\n    // Assign the global features to all the glyphs\n    _plan.assignGlobalFeatures(glyphs);\n\n    // Assign local features to glyphs\n    this.assignFeatures(_plan, glyphs);\n  };\n\n  DefaultShaper.planPreprocessing = function planPreprocessing(plan) {\n    plan.add({\n      global: [].concat(VARIATION_FEATURES, DIRECTIONAL_FEATURES[plan.direction]),\n      local: FRACTIONAL_FEATURES\n    });\n  };\n\n  DefaultShaper.planFeatures = function planFeatures(plan) {\n    // Do nothing by default. Let subclasses override this.\n  };\n\n  DefaultShaper.planPostprocessing = function planPostprocessing(plan, userFeatures) {\n    plan.add([].concat(COMMON_FEATURES, HORIZONTAL_FEATURES));\n    plan.setFeatureOverrides(userFeatures);\n  };\n\n  DefaultShaper.assignFeatures = function assignFeatures(plan, glyphs) {\n    // Enable contextual fractions\n    for (var i = 0; i < glyphs.length; i++) {\n      var glyph = glyphs[i];\n      if (glyph.codePoints[0] === 0x2044) {\n        // fraction slash\n        var start = i;\n        var end = i + 1;\n\n        // Apply numerator\n        while (start > 0 && unicode.isDigit(glyphs[start - 1].codePoints[0])) {\n          glyphs[start - 1].features.numr = true;\n          glyphs[start - 1].features.frac = true;\n          start--;\n        }\n\n        // Apply denominator\n        while (end < glyphs.length && unicode.isDigit(glyphs[end].codePoints[0])) {\n          glyphs[end].features.dnom = true;\n          glyphs[end].features.frac = true;\n          end++;\n        }\n\n        // Apply fraction slash\n        glyph.features.frac = true;\n        i = end - 1;\n      }\n    }\n  };\n\n  return DefaultShaper;\n}(), _class$4.zeroMarkWidths = 'AFTER_GPOS', _temp);\n\nvar trie = new UnicodeTrie(Buffer(\"AAEQAAAAAAAAADGgAZUBav7t2CtPA0EUBeDZB00pin9AJZIEgyUEj0QhweDAgQOJxCBRBElQSBwSicLgkOAwnNKZ5GaY2c7uzj4o5yZfZrrbefbuIx2nSq3CGmzAWH/+K+UO7MIe7MMhHMMpnMMFXMIVXIt2t3CnP088iPqjqNN8e4Ij7Rle4LUH82rLm6i/92A+RERERERERERNmfz/89GDeRARERERzbN8ceps2Iwt9H0C9/AJ6yOlDkbTczcot5VSm8Pm1vcFWfb7+BKOLTuOd2UlTX4wGP85Eg953lWPFbnuN7PkjtLmalOWbNenkHOSa7T3KmR9MVTZ2zZkVj1kHa68MueVKH0R4zqQ44WEXLM8VjcWHP0PtKLfPzQnMtGn3W4QYf6qxFxceVI394r2xnV+1rih0fV1Vzf3fO1n3evL5J78ruvZ5ptX2Rwy92Tfb1wlEqut3U+sZ3HXOeJ7/zDrbyuP6+Zz0fqa6Nv3vhY7Yu1xWnGevmsvsUpTT/RYIe8waUH/rvHMWKFzLfN8L+rTfp645mfX7ftlnfDtYxN59w0=\",\"base64\"));\nvar FEATURES = ['isol', 'fina', 'fin2', 'fin3', 'medi', 'med2', 'init'];\n\nvar ShapingClasses = {\n  Non_Joining: 0,\n  Left_Joining: 1,\n  Right_Joining: 2,\n  Dual_Joining: 3,\n  Join_Causing: 3,\n  ALAPH: 4,\n  'DALATH RISH': 5,\n  Transparent: 6\n};\n\nvar ISOL = 'isol';\nvar FINA = 'fina';\nvar FIN2 = 'fin2';\nvar FIN3 = 'fin3';\nvar MEDI = 'medi';\nvar MED2 = 'med2';\nvar INIT = 'init';\nvar NONE = null;\n\n// Each entry is [prevAction, curAction, nextState]\nvar STATE_TABLE = [\n//   Non_Joining,        Left_Joining,       Right_Joining,     Dual_Joining,           ALAPH,            DALATH RISH\n// State 0: prev was U,  not willing to join.\n[[NONE, NONE, 0], [NONE, ISOL, 2], [NONE, ISOL, 1], [NONE, ISOL, 2], [NONE, ISOL, 1], [NONE, ISOL, 6]],\n\n// State 1: prev was R or ISOL/ALAPH,  not willing to join.\n[[NONE, NONE, 0], [NONE, ISOL, 2], [NONE, ISOL, 1], [NONE, ISOL, 2], [NONE, FIN2, 5], [NONE, ISOL, 6]],\n\n// State 2: prev was D/L in ISOL form,  willing to join.\n[[NONE, NONE, 0], [NONE, ISOL, 2], [INIT, FINA, 1], [INIT, FINA, 3], [INIT, FINA, 4], [INIT, FINA, 6]],\n\n// State 3: prev was D in FINA form,  willing to join.\n[[NONE, NONE, 0], [NONE, ISOL, 2], [MEDI, FINA, 1], [MEDI, FINA, 3], [MEDI, FINA, 4], [MEDI, FINA, 6]],\n\n// State 4: prev was FINA ALAPH,  not willing to join.\n[[NONE, NONE, 0], [NONE, ISOL, 2], [MED2, ISOL, 1], [MED2, ISOL, 2], [MED2, FIN2, 5], [MED2, ISOL, 6]],\n\n// State 5: prev was FIN2/FIN3 ALAPH,  not willing to join.\n[[NONE, NONE, 0], [NONE, ISOL, 2], [ISOL, ISOL, 1], [ISOL, ISOL, 2], [ISOL, FIN2, 5], [ISOL, ISOL, 6]],\n\n// State 6: prev was DALATH/RISH,  not willing to join.\n[[NONE, NONE, 0], [NONE, ISOL, 2], [NONE, ISOL, 1], [NONE, ISOL, 2], [NONE, FIN3, 5], [NONE, ISOL, 6]]];\n\n/**\n * This is a shaper for Arabic, and other cursive scripts.\n * It uses data from ArabicShaping.txt in the Unicode database,\n * compiled to a UnicodeTrie by generate-data.coffee.\n *\n * The shaping state machine was ported from Harfbuzz.\n * https://github.com/behdad/harfbuzz/blob/master/src/hb-ot-shape-complex-arabic.cc\n */\n\nvar ArabicShaper = function (_DefaultShaper) {\n  _inherits(ArabicShaper, _DefaultShaper);\n\n  function ArabicShaper() {\n    _classCallCheck(this, ArabicShaper);\n\n    return _possibleConstructorReturn(this, _DefaultShaper.apply(this, arguments));\n  }\n\n  ArabicShaper.planFeatures = function planFeatures(plan) {\n    plan.add(['ccmp', 'locl']);\n    for (var i = 0; i < FEATURES.length; i++) {\n      var feature = FEATURES[i];\n      plan.addStage(feature, false);\n    }\n\n    plan.addStage('mset');\n  };\n\n  ArabicShaper.assignFeatures = function assignFeatures(plan, glyphs) {\n    _DefaultShaper.assignFeatures.call(this, plan, glyphs);\n\n    var prev = -1;\n    var state = 0;\n    var actions = [];\n\n    // Apply the state machine to map glyphs to features\n    for (var i = 0; i < glyphs.length; i++) {\n      var curAction = void 0,\n          prevAction = void 0;\n      var glyph = glyphs[i];\n      var type = getShapingClass(glyph.codePoints[0]);\n      if (type === ShapingClasses.Transparent) {\n        actions[i] = NONE;\n        continue;\n      }\n\n      var _STATE_TABLE$state$ty = STATE_TABLE[state][type];\n      prevAction = _STATE_TABLE$state$ty[0];\n      curAction = _STATE_TABLE$state$ty[1];\n      state = _STATE_TABLE$state$ty[2];\n\n\n      if (prevAction !== NONE && prev !== -1) {\n        actions[prev] = prevAction;\n      }\n\n      actions[i] = curAction;\n      prev = i;\n    }\n\n    // Apply the chosen features to their respective glyphs\n    for (var index = 0; index < glyphs.length; index++) {\n      var feature = void 0;\n      var glyph = glyphs[index];\n      if (feature = actions[index]) {\n        glyph.features[feature] = true;\n      }\n    }\n  };\n\n  return ArabicShaper;\n}(DefaultShaper);\n\nfunction getShapingClass(codePoint) {\n  var res = trie.get(codePoint);\n  if (res) {\n    return res - 1;\n  }\n\n  var category = unicode.getCategory(codePoint);\n  if (category === 'Mn' || category === 'Me' || category === 'Cf') {\n    return ShapingClasses.Transparent;\n  }\n\n  return ShapingClasses.Non_Joining;\n}\n\nvar GlyphIterator = function () {\n  function GlyphIterator(glyphs, options) {\n    _classCallCheck(this, GlyphIterator);\n\n    this.glyphs = glyphs;\n    this.reset(options);\n  }\n\n  GlyphIterator.prototype.reset = function reset() {\n    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n    var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n\n    this.options = options;\n    this.flags = options.flags || {};\n    this.markAttachmentType = options.markAttachmentType || 0;\n    this.index = index;\n  };\n\n  GlyphIterator.prototype.shouldIgnore = function shouldIgnore(glyph) {\n    return this.flags.ignoreMarks && glyph.isMark || this.flags.ignoreBaseGlyphs && glyph.isBase || this.flags.ignoreLigatures && glyph.isLigature || this.markAttachmentType && glyph.isMark && glyph.markAttachmentType !== this.markAttachmentType;\n  };\n\n  GlyphIterator.prototype.move = function move(dir) {\n    this.index += dir;\n    while (0 <= this.index && this.index < this.glyphs.length && this.shouldIgnore(this.glyphs[this.index])) {\n      this.index += dir;\n    }\n\n    if (0 > this.index || this.index >= this.glyphs.length) {\n      return null;\n    }\n\n    return this.glyphs[this.index];\n  };\n\n  GlyphIterator.prototype.next = function next() {\n    return this.move(+1);\n  };\n\n  GlyphIterator.prototype.prev = function prev() {\n    return this.move(-1);\n  };\n\n  GlyphIterator.prototype.peek = function peek() {\n    var count = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;\n\n    var idx = this.index;\n    var res = this.increment(count);\n    this.index = idx;\n    return res;\n  };\n\n  GlyphIterator.prototype.peekIndex = function peekIndex() {\n    var count = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;\n\n    var idx = this.index;\n    this.increment(count);\n    var res = this.index;\n    this.index = idx;\n    return res;\n  };\n\n  GlyphIterator.prototype.increment = function increment() {\n    var count = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;\n\n    var dir = count < 0 ? -1 : 1;\n    count = Math.abs(count);\n    while (count--) {\n      this.move(dir);\n    }\n\n    return this.glyphs[this.index];\n  };\n\n  _createClass(GlyphIterator, [{\n    key: \"cur\",\n    get: function get() {\n      return this.glyphs[this.index] || null;\n    }\n  }]);\n\n  return GlyphIterator;\n}();\n\nvar DEFAULT_SCRIPTS = ['DFLT', 'dflt', 'latn'];\n\nvar OTProcessor = function () {\n  function OTProcessor(font, table) {\n    _classCallCheck(this, OTProcessor);\n\n    this.font = font;\n    this.table = table;\n\n    this.script = null;\n    this.scriptTag = null;\n\n    this.language = null;\n    this.languageTag = null;\n\n    this.features = {};\n    this.lookups = {};\n\n    // Setup variation substitutions\n    this.variationsIndex = font._variationProcessor ? this.findVariationsIndex(font._variationProcessor.normalizedCoords) : -1;\n\n    // initialize to default script + language\n    this.selectScript();\n\n    // current context (set by applyFeatures)\n    this.glyphs = [];\n    this.positions = []; // only used by GPOS\n    this.ligatureID = 1;\n    this.currentFeature = null;\n  }\n\n  OTProcessor.prototype.findScript = function findScript(script) {\n    if (this.table.scriptList == null) {\n      return null;\n    }\n\n    if (!Array.isArray(script)) {\n      script = [script];\n    }\n\n    for (var _iterator = script, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var s = _ref;\n\n      for (var _iterator2 = this.table.scriptList, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n        var _ref2;\n\n        if (_isArray2) {\n          if (_i2 >= _iterator2.length) break;\n          _ref2 = _iterator2[_i2++];\n        } else {\n          _i2 = _iterator2.next();\n          if (_i2.done) break;\n          _ref2 = _i2.value;\n        }\n\n        var entry = _ref2;\n\n        if (entry.tag === s) {\n          return entry;\n        }\n      }\n    }\n\n    return null;\n  };\n\n  OTProcessor.prototype.selectScript = function selectScript(script, language, direction$$) {\n    var changed = false;\n    var entry = void 0;\n    if (!this.script || script !== this.scriptTag) {\n      entry = this.findScript(script);\n      if (!entry) {\n        entry = this.findScript(DEFAULT_SCRIPTS);\n      }\n\n      if (!entry) {\n        return this.scriptTag;\n      }\n\n      this.scriptTag = entry.tag;\n      this.script = entry.script;\n      this.language = null;\n      this.languageTag = null;\n      changed = true;\n    }\n\n    if (!direction$$ || direction$$ !== this.direction) {\n      this.direction = direction$$ || direction(script);\n    }\n\n    if (language && language.length < 4) {\n      language += ' '.repeat(4 - language.length);\n    }\n\n    if (!language || language !== this.languageTag) {\n      this.language = null;\n\n      for (var _iterator3 = this.script.langSysRecords, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n        var _ref3;\n\n        if (_isArray3) {\n          if (_i3 >= _iterator3.length) break;\n          _ref3 = _iterator3[_i3++];\n        } else {\n          _i3 = _iterator3.next();\n          if (_i3.done) break;\n          _ref3 = _i3.value;\n        }\n\n        var lang = _ref3;\n\n        if (lang.tag === language) {\n          this.language = lang.langSys;\n          this.languageTag = lang.tag;\n          break;\n        }\n      }\n\n      if (!this.language) {\n        this.language = this.script.defaultLangSys;\n        this.languageTag = null;\n      }\n\n      changed = true;\n    }\n\n    // Build a feature lookup table\n    if (changed) {\n      this.features = {};\n      if (this.language) {\n        for (var _iterator4 = this.language.featureIndexes, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _getIterator(_iterator4);;) {\n          var _ref4;\n\n          if (_isArray4) {\n            if (_i4 >= _iterator4.length) break;\n            _ref4 = _iterator4[_i4++];\n          } else {\n            _i4 = _iterator4.next();\n            if (_i4.done) break;\n            _ref4 = _i4.value;\n          }\n\n          var featureIndex = _ref4;\n\n          var record = this.table.featureList[featureIndex];\n          var substituteFeature = this.substituteFeatureForVariations(featureIndex);\n          this.features[record.tag] = substituteFeature || record.feature;\n        }\n      }\n    }\n\n    return this.scriptTag;\n  };\n\n  OTProcessor.prototype.lookupsForFeatures = function lookupsForFeatures() {\n    var userFeatures = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n    var exclude = arguments[1];\n\n    var lookups = [];\n    for (var _iterator5 = userFeatures, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _getIterator(_iterator5);;) {\n      var _ref5;\n\n      if (_isArray5) {\n        if (_i5 >= _iterator5.length) break;\n        _ref5 = _iterator5[_i5++];\n      } else {\n        _i5 = _iterator5.next();\n        if (_i5.done) break;\n        _ref5 = _i5.value;\n      }\n\n      var tag = _ref5;\n\n      var feature = this.features[tag];\n      if (!feature) {\n        continue;\n      }\n\n      for (var _iterator6 = feature.lookupListIndexes, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _getIterator(_iterator6);;) {\n        var _ref6;\n\n        if (_isArray6) {\n          if (_i6 >= _iterator6.length) break;\n          _ref6 = _iterator6[_i6++];\n        } else {\n          _i6 = _iterator6.next();\n          if (_i6.done) break;\n          _ref6 = _i6.value;\n        }\n\n        var lookupIndex = _ref6;\n\n        if (exclude && exclude.indexOf(lookupIndex) !== -1) {\n          continue;\n        }\n\n        lookups.push({\n          feature: tag,\n          index: lookupIndex,\n          lookup: this.table.lookupList.get(lookupIndex)\n        });\n      }\n    }\n\n    lookups.sort(function (a, b) {\n      return a.index - b.index;\n    });\n    return lookups;\n  };\n\n  OTProcessor.prototype.substituteFeatureForVariations = function substituteFeatureForVariations(featureIndex) {\n    if (this.variationsIndex === -1) {\n      return null;\n    }\n\n    var record = this.table.featureVariations.featureVariationRecords[this.variationsIndex];\n    var substitutions = record.featureTableSubstitution.substitutions;\n    for (var _iterator7 = substitutions, _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _getIterator(_iterator7);;) {\n      var _ref7;\n\n      if (_isArray7) {\n        if (_i7 >= _iterator7.length) break;\n        _ref7 = _iterator7[_i7++];\n      } else {\n        _i7 = _iterator7.next();\n        if (_i7.done) break;\n        _ref7 = _i7.value;\n      }\n\n      var substitution = _ref7;\n\n      if (substitution.featureIndex === featureIndex) {\n        return substitution.alternateFeatureTable;\n      }\n    }\n\n    return null;\n  };\n\n  OTProcessor.prototype.findVariationsIndex = function findVariationsIndex(coords) {\n    var variations = this.table.featureVariations;\n    if (!variations) {\n      return -1;\n    }\n\n    var records = variations.featureVariationRecords;\n    for (var i = 0; i < records.length; i++) {\n      var conditions = records[i].conditionSet.conditionTable;\n      if (this.variationConditionsMatch(conditions, coords)) {\n        return i;\n      }\n    }\n\n    return -1;\n  };\n\n  OTProcessor.prototype.variationConditionsMatch = function variationConditionsMatch(conditions, coords) {\n    return conditions.every(function (condition) {\n      var coord = condition.axisIndex < coords.length ? coords[condition.axisIndex] : 0;\n      return condition.filterRangeMinValue <= coord && coord <= condition.filterRangeMaxValue;\n    });\n  };\n\n  OTProcessor.prototype.applyFeatures = function applyFeatures(userFeatures, glyphs, advances) {\n    var lookups = this.lookupsForFeatures(userFeatures);\n    this.applyLookups(lookups, glyphs, advances);\n  };\n\n  OTProcessor.prototype.applyLookups = function applyLookups(lookups, glyphs, positions) {\n    this.glyphs = glyphs;\n    this.positions = positions;\n    this.glyphIterator = new GlyphIterator(glyphs);\n\n    for (var _iterator8 = lookups, _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _getIterator(_iterator8);;) {\n      var _ref8;\n\n      if (_isArray8) {\n        if (_i8 >= _iterator8.length) break;\n        _ref8 = _iterator8[_i8++];\n      } else {\n        _i8 = _iterator8.next();\n        if (_i8.done) break;\n        _ref8 = _i8.value;\n      }\n\n      var _ref9 = _ref8,\n          feature = _ref9.feature,\n          lookup = _ref9.lookup;\n\n      this.currentFeature = feature;\n      this.glyphIterator.reset(lookup.flags);\n\n      while (this.glyphIterator.index < glyphs.length) {\n        if (!(feature in this.glyphIterator.cur.features)) {\n          this.glyphIterator.next();\n          continue;\n        }\n\n        for (var _iterator9 = lookup.subTables, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _getIterator(_iterator9);;) {\n          var _ref10;\n\n          if (_isArray9) {\n            if (_i9 >= _iterator9.length) break;\n            _ref10 = _iterator9[_i9++];\n          } else {\n            _i9 = _iterator9.next();\n            if (_i9.done) break;\n            _ref10 = _i9.value;\n          }\n\n          var table = _ref10;\n\n          var res = this.applyLookup(lookup.lookupType, table);\n          if (res) {\n            break;\n          }\n        }\n\n        this.glyphIterator.next();\n      }\n    }\n  };\n\n  OTProcessor.prototype.applyLookup = function applyLookup(lookup, table) {\n    throw new Error(\"applyLookup must be implemented by subclasses\");\n  };\n\n  OTProcessor.prototype.applyLookupList = function applyLookupList(lookupRecords) {\n    var options = this.glyphIterator.options;\n    var glyphIndex = this.glyphIterator.index;\n\n    for (var _iterator10 = lookupRecords, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _getIterator(_iterator10);;) {\n      var _ref11;\n\n      if (_isArray10) {\n        if (_i10 >= _iterator10.length) break;\n        _ref11 = _iterator10[_i10++];\n      } else {\n        _i10 = _iterator10.next();\n        if (_i10.done) break;\n        _ref11 = _i10.value;\n      }\n\n      var lookupRecord = _ref11;\n\n      // Reset flags and find glyph index for this lookup record\n      this.glyphIterator.reset(options, glyphIndex);\n      this.glyphIterator.increment(lookupRecord.sequenceIndex);\n\n      // Get the lookup and setup flags for subtables\n      var lookup = this.table.lookupList.get(lookupRecord.lookupListIndex);\n      this.glyphIterator.reset(lookup.flags, this.glyphIterator.index);\n\n      // Apply lookup subtables until one matches\n      for (var _iterator11 = lookup.subTables, _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _getIterator(_iterator11);;) {\n        var _ref12;\n\n        if (_isArray11) {\n          if (_i11 >= _iterator11.length) break;\n          _ref12 = _iterator11[_i11++];\n        } else {\n          _i11 = _iterator11.next();\n          if (_i11.done) break;\n          _ref12 = _i11.value;\n        }\n\n        var table = _ref12;\n\n        if (this.applyLookup(lookup.lookupType, table)) {\n          break;\n        }\n      }\n    }\n\n    this.glyphIterator.reset(options, glyphIndex);\n    return true;\n  };\n\n  OTProcessor.prototype.coverageIndex = function coverageIndex(coverage, glyph) {\n    if (glyph == null) {\n      glyph = this.glyphIterator.cur.id;\n    }\n\n    switch (coverage.version) {\n      case 1:\n        return coverage.glyphs.indexOf(glyph);\n\n      case 2:\n        for (var _iterator12 = coverage.rangeRecords, _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _getIterator(_iterator12);;) {\n          var _ref13;\n\n          if (_isArray12) {\n            if (_i12 >= _iterator12.length) break;\n            _ref13 = _iterator12[_i12++];\n          } else {\n            _i12 = _iterator12.next();\n            if (_i12.done) break;\n            _ref13 = _i12.value;\n          }\n\n          var range = _ref13;\n\n          if (range.start <= glyph && glyph <= range.end) {\n            return range.startCoverageIndex + glyph - range.start;\n          }\n        }\n\n        break;\n    }\n\n    return -1;\n  };\n\n  OTProcessor.prototype.match = function match(sequenceIndex, sequence, fn, matched) {\n    var pos = this.glyphIterator.index;\n    var glyph = this.glyphIterator.increment(sequenceIndex);\n    var idx = 0;\n\n    while (idx < sequence.length && glyph && fn(sequence[idx], glyph)) {\n      if (matched) {\n        matched.push(this.glyphIterator.index);\n      }\n\n      idx++;\n      glyph = this.glyphIterator.next();\n    }\n\n    this.glyphIterator.index = pos;\n    if (idx < sequence.length) {\n      return false;\n    }\n\n    return matched || true;\n  };\n\n  OTProcessor.prototype.sequenceMatches = function sequenceMatches(sequenceIndex, sequence) {\n    return this.match(sequenceIndex, sequence, function (component, glyph) {\n      return component === glyph.id;\n    });\n  };\n\n  OTProcessor.prototype.sequenceMatchIndices = function sequenceMatchIndices(sequenceIndex, sequence) {\n    var _this = this;\n\n    return this.match(sequenceIndex, sequence, function (component, glyph) {\n      // If the current feature doesn't apply to this glyph,\n      if (!(_this.currentFeature in glyph.features)) {\n        return false;\n      }\n\n      return component === glyph.id;\n    }, []);\n  };\n\n  OTProcessor.prototype.coverageSequenceMatches = function coverageSequenceMatches(sequenceIndex, sequence) {\n    var _this2 = this;\n\n    return this.match(sequenceIndex, sequence, function (coverage, glyph) {\n      return _this2.coverageIndex(coverage, glyph.id) >= 0;\n    });\n  };\n\n  OTProcessor.prototype.getClassID = function getClassID(glyph, classDef) {\n    switch (classDef.version) {\n      case 1:\n        // Class array\n        var i = glyph - classDef.startGlyph;\n        if (i >= 0 && i < classDef.classValueArray.length) {\n          return classDef.classValueArray[i];\n        }\n\n        break;\n\n      case 2:\n        for (var _iterator13 = classDef.classRangeRecord, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _getIterator(_iterator13);;) {\n          var _ref14;\n\n          if (_isArray13) {\n            if (_i13 >= _iterator13.length) break;\n            _ref14 = _iterator13[_i13++];\n          } else {\n            _i13 = _iterator13.next();\n            if (_i13.done) break;\n            _ref14 = _i13.value;\n          }\n\n          var range = _ref14;\n\n          if (range.start <= glyph && glyph <= range.end) {\n            return range.class;\n          }\n        }\n\n        break;\n    }\n\n    return 0;\n  };\n\n  OTProcessor.prototype.classSequenceMatches = function classSequenceMatches(sequenceIndex, sequence, classDef) {\n    var _this3 = this;\n\n    return this.match(sequenceIndex, sequence, function (classID, glyph) {\n      return classID === _this3.getClassID(glyph.id, classDef);\n    });\n  };\n\n  OTProcessor.prototype.applyContext = function applyContext(table) {\n    switch (table.version) {\n      case 1:\n        var index = this.coverageIndex(table.coverage);\n        if (index === -1) {\n          return false;\n        }\n\n        var set = table.ruleSets[index];\n        for (var _iterator14 = set, _isArray14 = Array.isArray(_iterator14), _i14 = 0, _iterator14 = _isArray14 ? _iterator14 : _getIterator(_iterator14);;) {\n          var _ref15;\n\n          if (_isArray14) {\n            if (_i14 >= _iterator14.length) break;\n            _ref15 = _iterator14[_i14++];\n          } else {\n            _i14 = _iterator14.next();\n            if (_i14.done) break;\n            _ref15 = _i14.value;\n          }\n\n          var rule = _ref15;\n\n          if (this.sequenceMatches(1, rule.input)) {\n            return this.applyLookupList(rule.lookupRecords);\n          }\n        }\n\n        break;\n\n      case 2:\n        if (this.coverageIndex(table.coverage) === -1) {\n          return false;\n        }\n\n        index = this.getClassID(this.glyphIterator.cur.id, table.classDef);\n        if (index === -1) {\n          return false;\n        }\n\n        set = table.classSet[index];\n        for (var _iterator15 = set, _isArray15 = Array.isArray(_iterator15), _i15 = 0, _iterator15 = _isArray15 ? _iterator15 : _getIterator(_iterator15);;) {\n          var _ref16;\n\n          if (_isArray15) {\n            if (_i15 >= _iterator15.length) break;\n            _ref16 = _iterator15[_i15++];\n          } else {\n            _i15 = _iterator15.next();\n            if (_i15.done) break;\n            _ref16 = _i15.value;\n          }\n\n          var _rule = _ref16;\n\n          if (this.classSequenceMatches(1, _rule.classes, table.classDef)) {\n            return this.applyLookupList(_rule.lookupRecords);\n          }\n        }\n\n        break;\n\n      case 3:\n        if (this.coverageSequenceMatches(0, table.coverages)) {\n          return this.applyLookupList(table.lookupRecords);\n        }\n\n        break;\n    }\n\n    return false;\n  };\n\n  OTProcessor.prototype.applyChainingContext = function applyChainingContext(table) {\n    switch (table.version) {\n      case 1:\n        var index = this.coverageIndex(table.coverage);\n        if (index === -1) {\n          return false;\n        }\n\n        var set = table.chainRuleSets[index];\n        for (var _iterator16 = set, _isArray16 = Array.isArray(_iterator16), _i16 = 0, _iterator16 = _isArray16 ? _iterator16 : _getIterator(_iterator16);;) {\n          var _ref17;\n\n          if (_isArray16) {\n            if (_i16 >= _iterator16.length) break;\n            _ref17 = _iterator16[_i16++];\n          } else {\n            _i16 = _iterator16.next();\n            if (_i16.done) break;\n            _ref17 = _i16.value;\n          }\n\n          var rule = _ref17;\n\n          if (this.sequenceMatches(-rule.backtrack.length, rule.backtrack) && this.sequenceMatches(1, rule.input) && this.sequenceMatches(1 + rule.input.length, rule.lookahead)) {\n            return this.applyLookupList(rule.lookupRecords);\n          }\n        }\n\n        break;\n\n      case 2:\n        if (this.coverageIndex(table.coverage) === -1) {\n          return false;\n        }\n\n        index = this.getClassID(this.glyphIterator.cur.id, table.inputClassDef);\n        var rules = table.chainClassSet[index];\n        if (!rules) {\n          return false;\n        }\n\n        for (var _iterator17 = rules, _isArray17 = Array.isArray(_iterator17), _i17 = 0, _iterator17 = _isArray17 ? _iterator17 : _getIterator(_iterator17);;) {\n          var _ref18;\n\n          if (_isArray17) {\n            if (_i17 >= _iterator17.length) break;\n            _ref18 = _iterator17[_i17++];\n          } else {\n            _i17 = _iterator17.next();\n            if (_i17.done) break;\n            _ref18 = _i17.value;\n          }\n\n          var _rule2 = _ref18;\n\n          if (this.classSequenceMatches(-_rule2.backtrack.length, _rule2.backtrack, table.backtrackClassDef) && this.classSequenceMatches(1, _rule2.input, table.inputClassDef) && this.classSequenceMatches(1 + _rule2.input.length, _rule2.lookahead, table.lookaheadClassDef)) {\n            return this.applyLookupList(_rule2.lookupRecords);\n          }\n        }\n\n        break;\n\n      case 3:\n        if (this.coverageSequenceMatches(-table.backtrackGlyphCount, table.backtrackCoverage) && this.coverageSequenceMatches(0, table.inputCoverage) && this.coverageSequenceMatches(table.inputGlyphCount, table.lookaheadCoverage)) {\n          return this.applyLookupList(table.lookupRecords);\n        }\n\n        break;\n    }\n\n    return false;\n  };\n\n  return OTProcessor;\n}();\n\nvar GlyphInfo = function () {\n  function GlyphInfo(font, id) {\n    var codePoints = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];\n    var features = arguments[3];\n\n    _classCallCheck(this, GlyphInfo);\n\n    this._font = font;\n    this.codePoints = codePoints;\n    this.id = id;\n\n    this.features = {};\n    if (Array.isArray(features)) {\n      for (var i = 0; i < features.length; i++) {\n        var feature = features[i];\n        this.features[feature] = true;\n      }\n    } else if ((typeof features === 'undefined' ? 'undefined' : _typeof(features)) === 'object') {\n      _Object$assign(this.features, features);\n    }\n\n    this.ligatureID = null;\n    this.ligatureComponent = null;\n    this.isLigated = false;\n    this.cursiveAttachment = null;\n    this.markAttachment = null;\n    this.shaperInfo = null;\n    this.substituted = false;\n    this.isMultiplied = false;\n  }\n\n  GlyphInfo.prototype.copy = function copy() {\n    return new GlyphInfo(this._font, this.id, this.codePoints, this.features);\n  };\n\n  _createClass(GlyphInfo, [{\n    key: 'id',\n    get: function get() {\n      return this._id;\n    },\n    set: function set(id) {\n      this._id = id;\n      this.substituted = true;\n\n      var GDEF = this._font.GDEF;\n      if (GDEF && GDEF.glyphClassDef) {\n        // TODO: clean this up\n        var classID = OTProcessor.prototype.getClassID(id, GDEF.glyphClassDef);\n        this.isBase = classID === 1;\n        this.isLigature = classID === 2;\n        this.isMark = classID === 3;\n        this.markAttachmentType = GDEF.markAttachClassDef ? OTProcessor.prototype.getClassID(id, GDEF.markAttachClassDef) : 0;\n      } else {\n        this.isMark = this.codePoints.every(unicode.isMark);\n        this.isBase = !this.isMark;\n        this.isLigature = this.codePoints.length > 1;\n        this.markAttachmentType = 0;\n      }\n    }\n  }]);\n\n  return GlyphInfo;\n}();\n\nvar _class$5;\nvar _temp$1;\n/**\n * This is a shaper for the Hangul script, used by the Korean language.\n * It does the following:\n *   - decompose if unsupported by the font:\n *     <LV>   -> <L,V>\n *     <LVT>  -> <L,V,T>\n *     <LV,T> -> <L,V,T>\n *\n *   - compose if supported by the font:\n *     <L,V>   -> <LV>\n *     <L,V,T> -> <LVT>\n *     <LV,T>  -> <LVT>\n *\n *   - reorder tone marks (S is any valid syllable):\n *     <S, M> -> <M, S>\n *\n *   - apply ljmo, vjmo, and tjmo OpenType features to decomposed Jamo sequences.\n *\n * This logic is based on the following documents:\n *   - http://www.microsoft.com/typography/OpenTypeDev/hangul/intro.htm\n *   - http://ktug.org/~nomos/harfbuzz-hangul/hangulshaper.pdf\n */\nvar HangulShaper = (_temp$1 = _class$5 = function (_DefaultShaper) {\n  _inherits(HangulShaper, _DefaultShaper);\n\n  function HangulShaper() {\n    _classCallCheck(this, HangulShaper);\n\n    return _possibleConstructorReturn(this, _DefaultShaper.apply(this, arguments));\n  }\n\n  HangulShaper.planFeatures = function planFeatures(plan) {\n    plan.add(['ljmo', 'vjmo', 'tjmo'], false);\n  };\n\n  HangulShaper.assignFeatures = function assignFeatures(plan, glyphs) {\n    var state = 0;\n    var i = 0;\n    while (i < glyphs.length) {\n      var action = void 0;\n      var glyph = glyphs[i];\n      var code = glyph.codePoints[0];\n      var type = getType(code);\n\n      var _STATE_TABLE$state$ty = STATE_TABLE$1[state][type];\n      action = _STATE_TABLE$state$ty[0];\n      state = _STATE_TABLE$state$ty[1];\n\n\n      switch (action) {\n        case DECOMPOSE:\n          // Decompose the composed syllable if it is not supported by the font.\n          if (!plan.font.hasGlyphForCodePoint(code)) {\n            i = decompose(glyphs, i, plan.font);\n          }\n          break;\n\n        case COMPOSE:\n          // Found a decomposed syllable. Try to compose if supported by the font.\n          i = compose(glyphs, i, plan.font);\n          break;\n\n        case TONE_MARK:\n          // Got a valid syllable, followed by a tone mark. Move the tone mark to the beginning of the syllable.\n          reorderToneMark(glyphs, i, plan.font);\n          break;\n\n        case INVALID:\n          // Tone mark has no valid syllable to attach to, so insert a dotted circle\n          i = insertDottedCircle(glyphs, i, plan.font);\n          break;\n      }\n\n      i++;\n    }\n  };\n\n  return HangulShaper;\n}(DefaultShaper), _class$5.zeroMarkWidths = 'NONE', _temp$1);\nvar HANGUL_BASE = 0xac00;\nvar HANGUL_END = 0xd7a4;\nvar HANGUL_COUNT = HANGUL_END - HANGUL_BASE + 1;\nvar L_BASE = 0x1100; // lead\nvar V_BASE = 0x1161; // vowel\nvar T_BASE = 0x11a7; // trail\nvar L_COUNT = 19;\nvar V_COUNT = 21;\nvar T_COUNT = 28;\nvar L_END = L_BASE + L_COUNT - 1;\nvar V_END = V_BASE + V_COUNT - 1;\nvar T_END = T_BASE + T_COUNT - 1;\nvar DOTTED_CIRCLE = 0x25cc;\n\nvar isL = function isL(code) {\n  return 0x1100 <= code && code <= 0x115f || 0xa960 <= code && code <= 0xa97c;\n};\nvar isV = function isV(code) {\n  return 0x1160 <= code && code <= 0x11a7 || 0xd7b0 <= code && code <= 0xd7c6;\n};\nvar isT = function isT(code) {\n  return 0x11a8 <= code && code <= 0x11ff || 0xd7cb <= code && code <= 0xd7fb;\n};\nvar isTone = function isTone(code) {\n  return 0x302e <= code && code <= 0x302f;\n};\nvar isLVT = function isLVT(code) {\n  return HANGUL_BASE <= code && code <= HANGUL_END;\n};\nvar isLV = function isLV(code) {\n  return code - HANGUL_BASE < HANGUL_COUNT && (code - HANGUL_BASE) % T_COUNT === 0;\n};\nvar isCombiningL = function isCombiningL(code) {\n  return L_BASE <= code && code <= L_END;\n};\nvar isCombiningV = function isCombiningV(code) {\n  return V_BASE <= code && code <= V_END;\n};\nvar isCombiningT = function isCombiningT(code) {\n  return T_BASE + 1 && 1 <= code && code <= T_END;\n};\n\n// Character categories\nvar X = 0; // Other character\nvar L = 1; // Leading consonant\nvar V = 2; // Medial vowel\nvar T = 3; // Trailing consonant\nvar LV = 4; // Composed <LV> syllable\nvar LVT = 5; // Composed <LVT> syllable\nvar M = 6; // Tone mark\n\n// This function classifies a character using the above categories.\nfunction getType(code) {\n  if (isL(code)) {\n    return L;\n  }\n  if (isV(code)) {\n    return V;\n  }\n  if (isT(code)) {\n    return T;\n  }\n  if (isLV(code)) {\n    return LV;\n  }\n  if (isLVT(code)) {\n    return LVT;\n  }\n  if (isTone(code)) {\n    return M;\n  }\n  return X;\n}\n\n// State machine actions\nvar NO_ACTION = 0;\nvar DECOMPOSE = 1;\nvar COMPOSE = 2;\nvar TONE_MARK = 4;\nvar INVALID = 5;\n\n// Build a state machine that accepts valid syllables, and applies actions along the way.\n// The logic this is implementing is documented at the top of the file.\nvar STATE_TABLE$1 = [\n//       X                 L                 V                T                  LV                LVT               M\n// State 0: start state\n[[NO_ACTION, 0], [NO_ACTION, 1], [NO_ACTION, 0], [NO_ACTION, 0], [DECOMPOSE, 2], [DECOMPOSE, 3], [INVALID, 0]],\n\n// State 1: <L>\n[[NO_ACTION, 0], [NO_ACTION, 1], [COMPOSE, 2], [NO_ACTION, 0], [DECOMPOSE, 2], [DECOMPOSE, 3], [INVALID, 0]],\n\n// State 2: <L,V> or <LV>\n[[NO_ACTION, 0], [NO_ACTION, 1], [NO_ACTION, 0], [COMPOSE, 3], [DECOMPOSE, 2], [DECOMPOSE, 3], [TONE_MARK, 0]],\n\n// State 3: <L,V,T> or <LVT>\n[[NO_ACTION, 0], [NO_ACTION, 1], [NO_ACTION, 0], [NO_ACTION, 0], [DECOMPOSE, 2], [DECOMPOSE, 3], [TONE_MARK, 0]]];\n\nfunction getGlyph(font, code, features) {\n  return new GlyphInfo(font, font.glyphForCodePoint(code).id, [code], features);\n}\n\nfunction decompose(glyphs, i, font) {\n  var glyph = glyphs[i];\n  var code = glyph.codePoints[0];\n\n  var s = code - HANGUL_BASE;\n  var t = T_BASE + s % T_COUNT;\n  s = s / T_COUNT | 0;\n  var l = L_BASE + s / V_COUNT | 0;\n  var v = V_BASE + s % V_COUNT;\n\n  // Don't decompose if all of the components are not available\n  if (!font.hasGlyphForCodePoint(l) || !font.hasGlyphForCodePoint(v) || t !== T_BASE && !font.hasGlyphForCodePoint(t)) {\n    return i;\n  }\n\n  // Replace the current glyph with decomposed L, V, and T glyphs,\n  // and apply the proper OpenType features to each component.\n  var ljmo = getGlyph(font, l, glyph.features);\n  ljmo.features.ljmo = true;\n\n  var vjmo = getGlyph(font, v, glyph.features);\n  vjmo.features.vjmo = true;\n\n  var insert = [ljmo, vjmo];\n\n  if (t > T_BASE) {\n    var tjmo = getGlyph(font, t, glyph.features);\n    tjmo.features.tjmo = true;\n    insert.push(tjmo);\n  }\n\n  glyphs.splice.apply(glyphs, [i, 1].concat(insert));\n  return i + insert.length - 1;\n}\n\nfunction compose(glyphs, i, font) {\n  var glyph = glyphs[i];\n  var code = glyphs[i].codePoints[0];\n  var type = getType(code);\n\n  var prev = glyphs[i - 1].codePoints[0];\n  var prevType = getType(prev);\n\n  // Figure out what type of syllable we're dealing with\n  var lv = void 0,\n      ljmo = void 0,\n      vjmo = void 0,\n      tjmo = void 0;\n  if (prevType === LV && type === T) {\n    // <LV,T>\n    lv = prev;\n    tjmo = glyph;\n  } else {\n    if (type === V) {\n      // <L,V>\n      ljmo = glyphs[i - 1];\n      vjmo = glyph;\n    } else {\n      // <L,V,T>\n      ljmo = glyphs[i - 2];\n      vjmo = glyphs[i - 1];\n      tjmo = glyph;\n    }\n\n    var l = ljmo.codePoints[0];\n    var v = vjmo.codePoints[0];\n\n    // Make sure L and V are combining characters\n    if (isCombiningL(l) && isCombiningV(v)) {\n      lv = HANGUL_BASE + ((l - L_BASE) * V_COUNT + (v - V_BASE)) * T_COUNT;\n    }\n  }\n\n  var t = tjmo && tjmo.codePoints[0] || T_BASE;\n  if (lv != null && (t === T_BASE || isCombiningT(t))) {\n    var s = lv + (t - T_BASE);\n\n    // Replace with a composed glyph if supported by the font,\n    // otherwise apply the proper OpenType features to each component.\n    if (font.hasGlyphForCodePoint(s)) {\n      var del = prevType === V ? 3 : 2;\n      glyphs.splice(i - del + 1, del, getGlyph(font, s, glyph.features));\n      return i - del + 1;\n    }\n  }\n\n  // Didn't compose (either a non-combining component or unsupported by font).\n  if (ljmo) {\n    ljmo.features.ljmo = true;\n  }\n  if (vjmo) {\n    vjmo.features.vjmo = true;\n  }\n  if (tjmo) {\n    tjmo.features.tjmo = true;\n  }\n\n  if (prevType === LV) {\n    // Sequence was originally <L,V>, which got combined earlier.\n    // Either the T was non-combining, or the LVT glyph wasn't supported.\n    // Decompose the glyph again and apply OT features.\n    decompose(glyphs, i - 1, font);\n    return i + 1;\n  }\n\n  return i;\n}\n\nfunction getLength(code) {\n  switch (getType(code)) {\n    case LV:\n    case LVT:\n      return 1;\n    case V:\n      return 2;\n    case T:\n      return 3;\n  }\n}\n\nfunction reorderToneMark(glyphs, i, font) {\n  var glyph = glyphs[i];\n  var code = glyphs[i].codePoints[0];\n\n  // Move tone mark to the beginning of the previous syllable, unless it is zero width\n  if (font.glyphForCodePoint(code).advanceWidth === 0) {\n    return;\n  }\n\n  var prev = glyphs[i - 1].codePoints[0];\n  var len = getLength(prev);\n\n  glyphs.splice(i, 1);\n  return glyphs.splice(i - len, 0, glyph);\n}\n\nfunction insertDottedCircle(glyphs, i, font) {\n  var glyph = glyphs[i];\n  var code = glyphs[i].codePoints[0];\n\n  if (font.hasGlyphForCodePoint(DOTTED_CIRCLE)) {\n    var dottedCircle = getGlyph(font, DOTTED_CIRCLE, glyph.features);\n\n    // If the tone mark is zero width, insert the dotted circle before, otherwise after\n    var idx = font.glyphForCodePoint(code).advanceWidth === 0 ? i : i + 1;\n    glyphs.splice(idx, 0, dottedCircle);\n    i++;\n  }\n\n  return i;\n}\n\nvar stateTable = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 11, 12, 13, 14, 15, 16, 17], [0, 0, 0, 18, 19, 20, 21, 22, 23, 0, 24, 0, 0, 25, 26, 0, 0, 27, 0], [0, 0, 0, 28, 29, 30, 31, 32, 33, 0, 34, 0, 0, 35, 36, 0, 0, 37, 0], [0, 0, 0, 38, 5, 7, 7, 8, 9, 0, 10, 0, 0, 0, 13, 0, 0, 16, 0], [0, 39, 0, 0, 0, 40, 41, 0, 9, 0, 10, 0, 0, 0, 42, 0, 39, 0, 0], [0, 0, 0, 0, 43, 44, 44, 8, 9, 0, 0, 0, 0, 12, 43, 0, 0, 0, 0], [0, 0, 0, 0, 43, 44, 44, 8, 9, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0], [0, 0, 0, 45, 46, 47, 48, 49, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 50, 0, 0, 51, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 53, 54, 55, 56, 57, 58, 0, 59, 0, 0, 60, 61, 0, 0, 62, 0], [0, 0, 0, 4, 5, 7, 7, 8, 9, 0, 10, 0, 0, 0, 13, 0, 0, 16, 0], [0, 63, 64, 0, 0, 40, 41, 0, 9, 0, 10, 0, 0, 0, 42, 0, 63, 0, 0], [0, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 11, 12, 13, 0, 2, 16, 0], [0, 0, 0, 18, 65, 20, 21, 22, 23, 0, 24, 0, 0, 25, 26, 0, 0, 27, 0], [0, 0, 0, 0, 66, 67, 67, 8, 9, 0, 10, 0, 0, 0, 68, 0, 0, 0, 0], [0, 0, 0, 69, 0, 70, 70, 0, 71, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 73, 19, 74, 74, 22, 23, 0, 24, 0, 0, 0, 26, 0, 0, 27, 0], [0, 75, 0, 0, 0, 76, 77, 0, 23, 0, 24, 0, 0, 0, 78, 0, 75, 0, 0], [0, 0, 0, 0, 79, 80, 80, 22, 23, 0, 0, 0, 0, 25, 79, 0, 0, 0, 0], [0, 0, 0, 18, 19, 20, 74, 22, 23, 0, 24, 0, 0, 25, 26, 0, 0, 27, 0], [0, 0, 0, 81, 82, 83, 84, 85, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 86, 0, 0, 87, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 18, 19, 74, 74, 22, 23, 0, 24, 0, 0, 0, 26, 0, 0, 27, 0], [0, 89, 90, 0, 0, 76, 77, 0, 23, 0, 24, 0, 0, 0, 78, 0, 89, 0, 0], [0, 0, 0, 0, 91, 92, 92, 22, 23, 0, 24, 0, 0, 0, 93, 0, 0, 0, 0], [0, 0, 0, 94, 29, 95, 31, 32, 33, 0, 34, 0, 0, 0, 36, 0, 0, 37, 0], [0, 96, 0, 0, 0, 97, 98, 0, 33, 0, 34, 0, 0, 0, 99, 0, 96, 0, 0], [0, 0, 0, 0, 100, 101, 101, 32, 33, 0, 0, 0, 0, 35, 100, 0, 0, 0, 0], [0, 0, 0, 0, 100, 101, 101, 32, 33, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0], [0, 0, 0, 102, 103, 104, 105, 106, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 107, 0, 0, 108, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 28, 29, 95, 31, 32, 33, 0, 34, 0, 0, 0, 36, 0, 0, 37, 0], [0, 110, 111, 0, 0, 97, 98, 0, 33, 0, 34, 0, 0, 0, 99, 0, 110, 0, 0], [0, 0, 0, 0, 112, 113, 113, 32, 33, 0, 34, 0, 0, 0, 114, 0, 0, 0, 0], [0, 0, 0, 0, 5, 7, 7, 8, 9, 0, 10, 0, 0, 0, 13, 0, 0, 16, 0], [0, 0, 0, 115, 116, 117, 118, 8, 9, 0, 10, 0, 0, 119, 120, 0, 0, 16, 0], [0, 0, 0, 0, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 39, 0, 122, 0, 123, 123, 8, 9, 0, 10, 0, 0, 0, 42, 0, 39, 0, 0], [0, 124, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 0], [0, 39, 0, 0, 0, 121, 125, 0, 9, 0, 10, 0, 0, 0, 42, 0, 39, 0, 0], [0, 0, 0, 0, 0, 126, 126, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 46, 47, 48, 49, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 47, 47, 49, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 127, 127, 49, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 128, 127, 127, 49, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 129, 130, 131, 132, 133, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 135, 54, 56, 56, 57, 58, 0, 59, 0, 0, 0, 61, 0, 0, 62, 0], [0, 136, 0, 0, 0, 137, 138, 0, 58, 0, 59, 0, 0, 0, 139, 0, 136, 0, 0], [0, 0, 0, 0, 140, 141, 141, 57, 58, 0, 0, 0, 0, 60, 140, 0, 0, 0, 0], [0, 0, 0, 0, 140, 141, 141, 57, 58, 0, 0, 0, 0, 0, 140, 0, 0, 0, 0], [0, 0, 0, 142, 143, 144, 145, 146, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 147, 0, 0, 148, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 149, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 53, 54, 56, 56, 57, 58, 0, 59, 0, 0, 0, 61, 0, 0, 62, 0], [0, 150, 151, 0, 0, 137, 138, 0, 58, 0, 59, 0, 0, 0, 139, 0, 150, 0, 0], [0, 0, 0, 0, 152, 153, 153, 57, 58, 0, 59, 0, 0, 0, 154, 0, 0, 0, 0], [0, 0, 0, 155, 116, 156, 157, 8, 9, 0, 10, 0, 0, 158, 120, 0, 0, 16, 0], [0, 0, 0, 0, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0], [0, 75, 3, 4, 5, 159, 160, 8, 161, 0, 162, 0, 11, 12, 163, 0, 75, 16, 0], [0, 0, 0, 0, 0, 40, 164, 0, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 165, 44, 44, 8, 9, 0, 0, 0, 0, 0, 165, 0, 0, 0, 0], [0, 124, 64, 0, 0, 40, 164, 0, 9, 0, 10, 0, 0, 0, 42, 0, 124, 0, 0], [0, 0, 0, 0, 0, 70, 70, 0, 71, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 166, 0, 0, 167, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 19, 74, 74, 22, 23, 0, 24, 0, 0, 0, 26, 0, 0, 27, 0], [0, 0, 0, 0, 79, 80, 80, 22, 23, 0, 0, 0, 0, 0, 79, 0, 0, 0, 0], [0, 0, 0, 169, 170, 171, 172, 22, 23, 0, 24, 0, 0, 173, 174, 0, 0, 27, 0], [0, 0, 0, 0, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 75, 0, 176, 0, 177, 177, 22, 23, 0, 24, 0, 0, 0, 78, 0, 75, 0, 0], [0, 178, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 0, 0], [0, 75, 0, 0, 0, 175, 179, 0, 23, 0, 24, 0, 0, 0, 78, 0, 75, 0, 0], [0, 0, 0, 0, 0, 180, 180, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 82, 83, 84, 85, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 83, 83, 85, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 181, 181, 85, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 182, 181, 181, 85, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 183, 184, 185, 186, 187, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 188, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 189, 170, 190, 191, 22, 23, 0, 24, 0, 0, 192, 174, 0, 0, 27, 0], [0, 0, 0, 0, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 76, 193, 0, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 194, 80, 80, 22, 23, 0, 0, 0, 0, 0, 194, 0, 0, 0, 0], [0, 178, 90, 0, 0, 76, 193, 0, 23, 0, 24, 0, 0, 0, 78, 0, 178, 0, 0], [0, 0, 0, 0, 29, 95, 31, 32, 33, 0, 34, 0, 0, 0, 36, 0, 0, 37, 0], [0, 0, 0, 0, 100, 101, 101, 32, 33, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0], [0, 0, 0, 195, 196, 197, 198, 32, 33, 0, 34, 0, 0, 199, 200, 0, 0, 37, 0], [0, 0, 0, 0, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 96, 0, 202, 0, 203, 203, 32, 33, 0, 34, 0, 0, 0, 99, 0, 96, 0, 0], [0, 204, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 204, 0, 0], [0, 96, 0, 0, 0, 201, 205, 0, 33, 0, 34, 0, 0, 0, 99, 0, 96, 0, 0], [0, 0, 0, 0, 0, 206, 206, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 103, 104, 105, 106, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 104, 104, 106, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 207, 207, 106, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 208, 207, 207, 106, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 209, 210, 211, 212, 213, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 107, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 215, 196, 216, 217, 32, 33, 0, 34, 0, 0, 218, 200, 0, 0, 37, 0], [0, 0, 0, 0, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 97, 219, 0, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 220, 101, 101, 32, 33, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0], [0, 204, 111, 0, 0, 97, 219, 0, 33, 0, 34, 0, 0, 0, 99, 0, 204, 0, 0], [0, 0, 0, 221, 116, 222, 222, 8, 9, 0, 10, 0, 0, 0, 120, 0, 0, 16, 0], [0, 223, 0, 0, 0, 40, 224, 0, 9, 0, 10, 0, 0, 0, 42, 0, 223, 0, 0], [0, 0, 0, 0, 225, 44, 44, 8, 9, 0, 0, 0, 0, 119, 225, 0, 0, 0, 0], [0, 0, 0, 115, 116, 117, 222, 8, 9, 0, 10, 0, 0, 119, 120, 0, 0, 16, 0], [0, 0, 0, 115, 116, 222, 222, 8, 9, 0, 10, 0, 0, 0, 120, 0, 0, 16, 0], [0, 226, 64, 0, 0, 40, 224, 0, 9, 0, 10, 0, 0, 0, 42, 0, 226, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 39, 0, 0, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 39, 0, 0], [0, 0, 0, 0, 0, 44, 44, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 227, 0, 228, 229, 0, 9, 0, 10, 0, 0, 230, 0, 0, 0, 0, 0], [0, 39, 0, 122, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 39, 0, 0], [0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 231, 231, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 130, 131, 132, 133, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 131, 131, 133, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 233, 233, 133, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 234, 233, 233, 133, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 235, 236, 237, 238, 239, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 54, 56, 56, 57, 58, 0, 59, 0, 0, 0, 61, 0, 0, 62, 0], [0, 0, 0, 240, 241, 242, 243, 57, 58, 0, 59, 0, 0, 244, 245, 0, 0, 62, 0], [0, 0, 0, 0, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 136, 0, 247, 0, 248, 248, 57, 58, 0, 59, 0, 0, 0, 139, 0, 136, 0, 0], [0, 249, 151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 0, 0], [0, 136, 0, 0, 0, 246, 250, 0, 58, 0, 59, 0, 0, 0, 139, 0, 136, 0, 0], [0, 0, 0, 0, 0, 251, 251, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 143, 144, 145, 146, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 144, 144, 146, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 252, 252, 146, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 253, 252, 252, 146, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 254, 255, 256, 257, 258, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 147, 0, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 260, 241, 261, 262, 57, 58, 0, 59, 0, 0, 263, 245, 0, 0, 62, 0], [0, 0, 0, 0, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 137, 264, 0, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 265, 141, 141, 57, 58, 0, 0, 0, 0, 0, 265, 0, 0, 0, 0], [0, 249, 151, 0, 0, 137, 264, 0, 58, 0, 59, 0, 0, 0, 139, 0, 249, 0, 0], [0, 0, 0, 221, 116, 222, 222, 8, 9, 0, 10, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 225, 44, 44, 8, 9, 0, 0, 0, 0, 158, 225, 0, 0, 0, 0], [0, 0, 0, 155, 116, 156, 222, 8, 9, 0, 10, 0, 0, 158, 120, 0, 0, 16, 0], [0, 0, 0, 155, 116, 222, 222, 8, 9, 0, 10, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 43, 266, 266, 8, 161, 0, 24, 0, 0, 12, 267, 0, 0, 0, 0], [0, 75, 0, 176, 43, 268, 268, 269, 161, 0, 24, 0, 0, 0, 267, 0, 75, 0, 0], [0, 0, 0, 0, 0, 270, 0, 0, 271, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0], [0, 273, 274, 0, 0, 40, 41, 0, 9, 0, 10, 0, 0, 0, 42, 0, 273, 0, 0], [0, 0, 0, 40, 0, 123, 123, 8, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 121, 275, 0, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 276, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 277, 170, 278, 278, 22, 23, 0, 24, 0, 0, 0, 174, 0, 0, 27, 0], [0, 279, 0, 0, 0, 76, 280, 0, 23, 0, 24, 0, 0, 0, 78, 0, 279, 0, 0], [0, 0, 0, 0, 281, 80, 80, 22, 23, 0, 0, 0, 0, 173, 281, 0, 0, 0, 0], [0, 0, 0, 169, 170, 171, 278, 22, 23, 0, 24, 0, 0, 173, 174, 0, 0, 27, 0], [0, 0, 0, 169, 170, 278, 278, 22, 23, 0, 24, 0, 0, 0, 174, 0, 0, 27, 0], [0, 282, 90, 0, 0, 76, 280, 0, 23, 0, 24, 0, 0, 0, 78, 0, 282, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 75, 0, 0, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 75, 0, 0], [0, 0, 0, 0, 0, 80, 80, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 283, 0, 284, 285, 0, 23, 0, 24, 0, 0, 286, 0, 0, 0, 0, 0], [0, 75, 0, 176, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 75, 0, 0], [0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 287, 287, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 184, 185, 186, 187, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 185, 185, 187, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 289, 289, 187, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 290, 289, 289, 187, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 291, 292, 293, 294, 295, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 277, 170, 278, 278, 22, 23, 0, 24, 0, 0, 0, 174, 0, 0, 27, 0], [0, 0, 0, 0, 281, 80, 80, 22, 23, 0, 0, 0, 0, 192, 281, 0, 0, 0, 0], [0, 0, 0, 189, 170, 190, 278, 22, 23, 0, 24, 0, 0, 192, 174, 0, 0, 27, 0], [0, 0, 0, 189, 170, 278, 278, 22, 23, 0, 24, 0, 0, 0, 174, 0, 0, 27, 0], [0, 0, 0, 76, 0, 177, 177, 22, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 175, 296, 0, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 297, 196, 298, 298, 32, 33, 0, 34, 0, 0, 0, 200, 0, 0, 37, 0], [0, 299, 0, 0, 0, 97, 300, 0, 33, 0, 34, 0, 0, 0, 99, 0, 299, 0, 0], [0, 0, 0, 0, 301, 101, 101, 32, 33, 0, 0, 0, 0, 199, 301, 0, 0, 0, 0], [0, 0, 0, 195, 196, 197, 298, 32, 33, 0, 34, 0, 0, 199, 200, 0, 0, 37, 0], [0, 0, 0, 195, 196, 298, 298, 32, 33, 0, 34, 0, 0, 0, 200, 0, 0, 37, 0], [0, 302, 111, 0, 0, 97, 300, 0, 33, 0, 34, 0, 0, 0, 99, 0, 302, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 96, 0, 0, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 96, 0, 0], [0, 0, 0, 0, 0, 101, 101, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 303, 0, 304, 305, 0, 33, 0, 34, 0, 0, 306, 0, 0, 0, 0, 0], [0, 96, 0, 202, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 96, 0, 0], [0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 307, 307, 106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 210, 211, 212, 213, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 211, 211, 213, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 309, 309, 213, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 310, 309, 309, 213, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 311, 312, 313, 314, 315, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 297, 196, 298, 298, 32, 33, 0, 34, 0, 0, 0, 200, 0, 0, 37, 0], [0, 0, 0, 0, 301, 101, 101, 32, 33, 0, 0, 0, 0, 218, 301, 0, 0, 0, 0], [0, 0, 0, 215, 196, 216, 298, 32, 33, 0, 34, 0, 0, 218, 200, 0, 0, 37, 0], [0, 0, 0, 215, 196, 298, 298, 32, 33, 0, 34, 0, 0, 0, 200, 0, 0, 37, 0], [0, 0, 0, 97, 0, 203, 203, 32, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 201, 316, 0, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 116, 222, 222, 8, 9, 0, 10, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 225, 44, 44, 8, 9, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0], [0, 0, 0, 317, 318, 319, 320, 8, 9, 0, 10, 0, 0, 321, 322, 0, 0, 16, 0], [0, 223, 0, 323, 0, 123, 123, 8, 9, 0, 10, 0, 0, 0, 42, 0, 223, 0, 0], [0, 223, 0, 0, 0, 121, 324, 0, 9, 0, 10, 0, 0, 0, 42, 0, 223, 0, 0], [0, 0, 0, 325, 318, 326, 327, 8, 9, 0, 10, 0, 0, 328, 322, 0, 0, 16, 0], [0, 0, 0, 64, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 230, 0, 0, 0, 0, 0], [0, 0, 0, 227, 0, 228, 121, 0, 9, 0, 10, 0, 0, 230, 0, 0, 0, 0, 0], [0, 0, 0, 227, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0], [0, 0, 0, 0, 0, 329, 329, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 236, 237, 238, 239, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 237, 237, 239, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 331, 331, 239, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 332, 331, 331, 239, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 333, 40, 121, 334, 0, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 335, 241, 336, 336, 57, 58, 0, 59, 0, 0, 0, 245, 0, 0, 62, 0], [0, 337, 0, 0, 0, 137, 338, 0, 58, 0, 59, 0, 0, 0, 139, 0, 337, 0, 0], [0, 0, 0, 0, 339, 141, 141, 57, 58, 0, 0, 0, 0, 244, 339, 0, 0, 0, 0], [0, 0, 0, 240, 241, 242, 336, 57, 58, 0, 59, 0, 0, 244, 245, 0, 0, 62, 0], [0, 0, 0, 240, 241, 336, 336, 57, 58, 0, 59, 0, 0, 0, 245, 0, 0, 62, 0], [0, 340, 151, 0, 0, 137, 338, 0, 58, 0, 59, 0, 0, 0, 139, 0, 340, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 136, 0, 0, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 136, 0, 0], [0, 0, 0, 0, 0, 141, 141, 57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 341, 0, 342, 343, 0, 58, 0, 59, 0, 0, 344, 0, 0, 0, 0, 0], [0, 136, 0, 247, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 136, 0, 0], [0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 345, 345, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 255, 256, 257, 258, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 256, 256, 258, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 347, 347, 258, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 348, 347, 347, 258, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 349, 350, 351, 352, 353, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 335, 241, 336, 336, 57, 58, 0, 59, 0, 0, 0, 245, 0, 0, 62, 0], [0, 0, 0, 0, 339, 141, 141, 57, 58, 0, 0, 0, 0, 263, 339, 0, 0, 0, 0], [0, 0, 0, 260, 241, 261, 336, 57, 58, 0, 59, 0, 0, 263, 245, 0, 0, 62, 0], [0, 0, 0, 260, 241, 336, 336, 57, 58, 0, 59, 0, 0, 0, 245, 0, 0, 62, 0], [0, 0, 0, 137, 0, 248, 248, 57, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 246, 354, 0, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 126, 126, 8, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 355, 90, 0, 0, 121, 125, 0, 9, 0, 10, 0, 0, 0, 42, 0, 355, 0, 0], [0, 0, 0, 0, 0, 356, 356, 269, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 357, 358, 359, 360, 361, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 270, 0, 0, 0, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 363, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 364, 116, 365, 366, 8, 161, 0, 162, 0, 0, 367, 120, 0, 0, 16, 0], [0, 0, 0, 0, 0, 368, 368, 0, 161, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 40, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 170, 278, 278, 22, 23, 0, 24, 0, 0, 0, 174, 0, 0, 27, 0], [0, 0, 0, 0, 281, 80, 80, 22, 23, 0, 0, 0, 0, 0, 281, 0, 0, 0, 0], [0, 0, 0, 369, 370, 371, 372, 22, 23, 0, 24, 0, 0, 373, 374, 0, 0, 27, 0], [0, 279, 0, 375, 0, 177, 177, 22, 23, 0, 24, 0, 0, 0, 78, 0, 279, 0, 0], [0, 279, 0, 0, 0, 175, 376, 0, 23, 0, 24, 0, 0, 0, 78, 0, 279, 0, 0], [0, 0, 0, 377, 370, 378, 379, 22, 23, 0, 24, 0, 0, 380, 374, 0, 0, 27, 0], [0, 0, 0, 90, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 286, 0, 0, 0, 0, 0], [0, 0, 0, 283, 0, 284, 175, 0, 23, 0, 24, 0, 0, 286, 0, 0, 0, 0, 0], [0, 0, 0, 283, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 0, 0], [0, 0, 0, 0, 0, 381, 381, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 382, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 292, 293, 294, 295, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 293, 293, 295, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 383, 383, 295, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 384, 383, 383, 295, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 385, 76, 175, 386, 0, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 76, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 196, 298, 298, 32, 33, 0, 34, 0, 0, 0, 200, 0, 0, 37, 0], [0, 0, 0, 0, 301, 101, 101, 32, 33, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0], [0, 0, 0, 387, 388, 389, 390, 32, 33, 0, 34, 0, 0, 391, 392, 0, 0, 37, 0], [0, 299, 0, 393, 0, 203, 203, 32, 33, 0, 34, 0, 0, 0, 99, 0, 299, 0, 0], [0, 299, 0, 0, 0, 201, 394, 0, 33, 0, 34, 0, 0, 0, 99, 0, 299, 0, 0], [0, 0, 0, 395, 388, 396, 397, 32, 33, 0, 34, 0, 0, 398, 392, 0, 0, 37, 0], [0, 0, 0, 111, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 306, 0, 0, 0, 0, 0], [0, 0, 0, 303, 0, 304, 201, 0, 33, 0, 34, 0, 0, 306, 0, 0, 0, 0, 0], [0, 0, 0, 303, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, 0], [0, 0, 0, 0, 0, 399, 399, 213, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 312, 313, 314, 315, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 313, 313, 315, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 401, 401, 315, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 402, 401, 401, 315, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 403, 97, 201, 404, 0, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 97, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 405, 318, 406, 406, 8, 9, 0, 10, 0, 0, 0, 322, 0, 0, 16, 0], [0, 407, 0, 0, 0, 40, 408, 0, 9, 0, 10, 0, 0, 0, 42, 0, 407, 0, 0], [0, 0, 0, 0, 409, 44, 44, 8, 9, 0, 0, 0, 0, 321, 409, 0, 0, 0, 0], [0, 0, 0, 317, 318, 319, 406, 8, 9, 0, 10, 0, 0, 321, 322, 0, 0, 16, 0], [0, 0, 0, 317, 318, 406, 406, 8, 9, 0, 10, 0, 0, 0, 322, 0, 0, 16, 0], [0, 410, 64, 0, 0, 40, 408, 0, 9, 0, 10, 0, 0, 0, 42, 0, 410, 0, 0], [0, 223, 0, 0, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 223, 0, 0], [0, 223, 0, 323, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 223, 0, 0], [0, 0, 0, 405, 318, 406, 406, 8, 9, 0, 10, 0, 0, 0, 322, 0, 0, 16, 0], [0, 0, 0, 0, 409, 44, 44, 8, 9, 0, 0, 0, 0, 328, 409, 0, 0, 0, 0], [0, 0, 0, 325, 318, 326, 406, 8, 9, 0, 10, 0, 0, 328, 322, 0, 0, 16, 0], [0, 0, 0, 325, 318, 406, 406, 8, 9, 0, 10, 0, 0, 0, 322, 0, 0, 16, 0], [0, 0, 0, 0, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0], [0, 0, 0, 0, 0, 411, 411, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 412, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 40, 121, 334, 0, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 413, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 241, 336, 336, 57, 58, 0, 59, 0, 0, 0, 245, 0, 0, 62, 0], [0, 0, 0, 0, 339, 141, 141, 57, 58, 0, 0, 0, 0, 0, 339, 0, 0, 0, 0], [0, 0, 0, 414, 415, 416, 417, 57, 58, 0, 59, 0, 0, 418, 419, 0, 0, 62, 0], [0, 337, 0, 420, 0, 248, 248, 57, 58, 0, 59, 0, 0, 0, 139, 0, 337, 0, 0], [0, 337, 0, 0, 0, 246, 421, 0, 58, 0, 59, 0, 0, 0, 139, 0, 337, 0, 0], [0, 0, 0, 422, 415, 423, 424, 57, 58, 0, 59, 0, 0, 425, 419, 0, 0, 62, 0], [0, 0, 0, 151, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0], [0, 0, 0, 341, 0, 342, 246, 0, 58, 0, 59, 0, 0, 344, 0, 0, 0, 0, 0], [0, 0, 0, 341, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143, 0, 0], [0, 0, 0, 0, 0, 426, 426, 258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 350, 351, 352, 353, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 351, 351, 353, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 428, 428, 353, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 429, 428, 428, 353, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 430, 137, 246, 431, 0, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 137, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 432, 116, 433, 434, 8, 161, 0, 162, 0, 0, 435, 120, 0, 0, 16, 0], [0, 0, 0, 0, 0, 180, 180, 269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 358, 359, 360, 361, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 359, 359, 361, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 436, 436, 361, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 437, 436, 436, 361, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 438, 439, 440, 441, 442, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 443, 274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 443, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 444, 116, 445, 445, 8, 161, 0, 162, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 225, 44, 44, 8, 161, 0, 0, 0, 0, 367, 225, 0, 0, 0, 0], [0, 0, 0, 364, 116, 365, 445, 8, 161, 0, 162, 0, 0, 367, 120, 0, 0, 16, 0], [0, 0, 0, 364, 116, 445, 445, 8, 161, 0, 162, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 0, 0, 0, 0, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 446, 370, 447, 447, 22, 23, 0, 24, 0, 0, 0, 374, 0, 0, 27, 0], [0, 448, 0, 0, 0, 76, 449, 0, 23, 0, 24, 0, 0, 0, 78, 0, 448, 0, 0], [0, 0, 0, 0, 450, 80, 80, 22, 23, 0, 0, 0, 0, 373, 450, 0, 0, 0, 0], [0, 0, 0, 369, 370, 371, 447, 22, 23, 0, 24, 0, 0, 373, 374, 0, 0, 27, 0], [0, 0, 0, 369, 370, 447, 447, 22, 23, 0, 24, 0, 0, 0, 374, 0, 0, 27, 0], [0, 451, 90, 0, 0, 76, 449, 0, 23, 0, 24, 0, 0, 0, 78, 0, 451, 0, 0], [0, 279, 0, 0, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 279, 0, 0], [0, 279, 0, 375, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 279, 0, 0], [0, 0, 0, 446, 370, 447, 447, 22, 23, 0, 24, 0, 0, 0, 374, 0, 0, 27, 0], [0, 0, 0, 0, 450, 80, 80, 22, 23, 0, 0, 0, 0, 380, 450, 0, 0, 0, 0], [0, 0, 0, 377, 370, 378, 447, 22, 23, 0, 24, 0, 0, 380, 374, 0, 0, 27, 0], [0, 0, 0, 377, 370, 447, 447, 22, 23, 0, 24, 0, 0, 0, 374, 0, 0, 27, 0], [0, 0, 0, 0, 0, 0, 0, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 184, 0, 0], [0, 0, 0, 0, 0, 452, 452, 295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 453, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 76, 175, 386, 0, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 454, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 455, 388, 456, 456, 32, 33, 0, 34, 0, 0, 0, 392, 0, 0, 37, 0], [0, 457, 0, 0, 0, 97, 458, 0, 33, 0, 34, 0, 0, 0, 99, 0, 457, 0, 0], [0, 0, 0, 0, 459, 101, 101, 32, 33, 0, 0, 0, 0, 391, 459, 0, 0, 0, 0], [0, 0, 0, 387, 388, 389, 456, 32, 33, 0, 34, 0, 0, 391, 392, 0, 0, 37, 0], [0, 0, 0, 387, 388, 456, 456, 32, 33, 0, 34, 0, 0, 0, 392, 0, 0, 37, 0], [0, 460, 111, 0, 0, 97, 458, 0, 33, 0, 34, 0, 0, 0, 99, 0, 460, 0, 0], [0, 299, 0, 0, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 299, 0, 0], [0, 299, 0, 393, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 299, 0, 0], [0, 0, 0, 455, 388, 456, 456, 32, 33, 0, 34, 0, 0, 0, 392, 0, 0, 37, 0], [0, 0, 0, 0, 459, 101, 101, 32, 33, 0, 0, 0, 0, 398, 459, 0, 0, 0, 0], [0, 0, 0, 395, 388, 396, 456, 32, 33, 0, 34, 0, 0, 398, 392, 0, 0, 37, 0], [0, 0, 0, 395, 388, 456, 456, 32, 33, 0, 34, 0, 0, 0, 392, 0, 0, 37, 0], [0, 0, 0, 0, 0, 0, 0, 213, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 210, 0, 0], [0, 0, 0, 0, 0, 461, 461, 315, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 462, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 97, 201, 404, 0, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 463, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 318, 406, 406, 8, 9, 0, 10, 0, 0, 0, 322, 0, 0, 16, 0], [0, 0, 0, 0, 409, 44, 44, 8, 9, 0, 0, 0, 0, 0, 409, 0, 0, 0, 0], [0, 0, 0, 464, 465, 466, 467, 8, 9, 0, 10, 0, 0, 468, 469, 0, 0, 16, 0], [0, 407, 0, 470, 0, 123, 123, 8, 9, 0, 10, 0, 0, 0, 42, 0, 407, 0, 0], [0, 407, 0, 0, 0, 121, 471, 0, 9, 0, 10, 0, 0, 0, 42, 0, 407, 0, 0], [0, 0, 0, 472, 465, 473, 474, 8, 9, 0, 10, 0, 0, 475, 469, 0, 0, 16, 0], [0, 0, 0, 0, 0, 0, 0, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 236, 0, 0], [0, 0, 0, 0, 0, 0, 476, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 477, 415, 478, 478, 57, 58, 0, 59, 0, 0, 0, 419, 0, 0, 62, 0], [0, 479, 0, 0, 0, 137, 480, 0, 58, 0, 59, 0, 0, 0, 139, 0, 479, 0, 0], [0, 0, 0, 0, 481, 141, 141, 57, 58, 0, 0, 0, 0, 418, 481, 0, 0, 0, 0], [0, 0, 0, 414, 415, 416, 478, 57, 58, 0, 59, 0, 0, 418, 419, 0, 0, 62, 0], [0, 0, 0, 414, 415, 478, 478, 57, 58, 0, 59, 0, 0, 0, 419, 0, 0, 62, 0], [0, 482, 151, 0, 0, 137, 480, 0, 58, 0, 59, 0, 0, 0, 139, 0, 482, 0, 0], [0, 337, 0, 0, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 337, 0, 0], [0, 337, 0, 420, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 337, 0, 0], [0, 0, 0, 477, 415, 478, 478, 57, 58, 0, 59, 0, 0, 0, 419, 0, 0, 62, 0], [0, 0, 0, 0, 481, 141, 141, 57, 58, 0, 0, 0, 0, 425, 481, 0, 0, 0, 0], [0, 0, 0, 422, 415, 423, 478, 57, 58, 0, 59, 0, 0, 425, 419, 0, 0, 62, 0], [0, 0, 0, 422, 415, 478, 478, 57, 58, 0, 59, 0, 0, 0, 419, 0, 0, 62, 0], [0, 0, 0, 0, 0, 0, 0, 258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0], [0, 0, 0, 0, 0, 483, 483, 353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 484, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 137, 246, 431, 0, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 485, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 444, 116, 445, 445, 8, 161, 0, 162, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 225, 44, 44, 8, 161, 0, 0, 0, 0, 435, 225, 0, 0, 0, 0], [0, 0, 0, 432, 116, 433, 445, 8, 161, 0, 162, 0, 0, 435, 120, 0, 0, 16, 0], [0, 0, 0, 432, 116, 445, 445, 8, 161, 0, 162, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 0, 486, 486, 361, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 439, 440, 441, 442, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 440, 440, 442, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 488, 488, 442, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 489, 488, 488, 442, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 490, 491, 492, 493, 494, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 495, 0, 496, 497, 0, 161, 0, 162, 0, 0, 498, 0, 0, 0, 0, 0], [0, 0, 0, 0, 116, 445, 445, 8, 161, 0, 162, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 225, 44, 44, 8, 161, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0], [0, 0, 0, 0, 370, 447, 447, 22, 23, 0, 24, 0, 0, 0, 374, 0, 0, 27, 0], [0, 0, 0, 0, 450, 80, 80, 22, 23, 0, 0, 0, 0, 0, 450, 0, 0, 0, 0], [0, 0, 0, 499, 500, 501, 502, 22, 23, 0, 24, 0, 0, 503, 504, 0, 0, 27, 0], [0, 448, 0, 505, 0, 177, 177, 22, 23, 0, 24, 0, 0, 0, 78, 0, 448, 0, 0], [0, 448, 0, 0, 0, 175, 506, 0, 23, 0, 24, 0, 0, 0, 78, 0, 448, 0, 0], [0, 0, 0, 507, 500, 508, 509, 22, 23, 0, 24, 0, 0, 510, 504, 0, 0, 27, 0], [0, 0, 0, 0, 0, 0, 0, 295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 292, 0, 0], [0, 0, 0, 0, 0, 0, 511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 388, 456, 456, 32, 33, 0, 34, 0, 0, 0, 392, 0, 0, 37, 0], [0, 0, 0, 0, 459, 101, 101, 32, 33, 0, 0, 0, 0, 0, 459, 0, 0, 0, 0], [0, 0, 0, 512, 513, 514, 515, 32, 33, 0, 34, 0, 0, 516, 517, 0, 0, 37, 0], [0, 457, 0, 518, 0, 203, 203, 32, 33, 0, 34, 0, 0, 0, 99, 0, 457, 0, 0], [0, 457, 0, 0, 0, 201, 519, 0, 33, 0, 34, 0, 0, 0, 99, 0, 457, 0, 0], [0, 0, 0, 520, 513, 521, 522, 32, 33, 0, 34, 0, 0, 523, 517, 0, 0, 37, 0], [0, 0, 0, 0, 0, 0, 0, 315, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 312, 0, 0], [0, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 525, 465, 526, 526, 8, 9, 0, 10, 0, 0, 0, 469, 0, 0, 16, 0], [0, 527, 0, 0, 0, 40, 528, 0, 9, 0, 10, 0, 0, 0, 42, 0, 527, 0, 0], [0, 0, 0, 0, 529, 44, 44, 8, 9, 0, 0, 0, 0, 468, 529, 0, 0, 0, 0], [0, 0, 0, 464, 465, 466, 526, 8, 9, 0, 10, 0, 0, 468, 469, 0, 0, 16, 0], [0, 0, 0, 464, 465, 526, 526, 8, 9, 0, 10, 0, 0, 0, 469, 0, 0, 16, 0], [0, 530, 64, 0, 0, 40, 528, 0, 9, 0, 10, 0, 0, 0, 42, 0, 530, 0, 0], [0, 407, 0, 0, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 407, 0, 0], [0, 407, 0, 470, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 407, 0, 0], [0, 0, 0, 525, 465, 526, 526, 8, 9, 0, 10, 0, 0, 0, 469, 0, 0, 16, 0], [0, 0, 0, 0, 529, 44, 44, 8, 9, 0, 0, 0, 0, 475, 529, 0, 0, 0, 0], [0, 0, 0, 472, 465, 473, 526, 8, 9, 0, 10, 0, 0, 475, 469, 0, 0, 16, 0], [0, 0, 0, 472, 465, 526, 526, 8, 9, 0, 10, 0, 0, 0, 469, 0, 0, 16, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0], [0, 0, 0, 0, 415, 478, 478, 57, 58, 0, 59, 0, 0, 0, 419, 0, 0, 62, 0], [0, 0, 0, 0, 481, 141, 141, 57, 58, 0, 0, 0, 0, 0, 481, 0, 0, 0, 0], [0, 0, 0, 531, 532, 533, 534, 57, 58, 0, 59, 0, 0, 535, 536, 0, 0, 62, 0], [0, 479, 0, 537, 0, 248, 248, 57, 58, 0, 59, 0, 0, 0, 139, 0, 479, 0, 0], [0, 479, 0, 0, 0, 246, 538, 0, 58, 0, 59, 0, 0, 0, 139, 0, 479, 0, 0], [0, 0, 0, 539, 532, 540, 541, 57, 58, 0, 59, 0, 0, 542, 536, 0, 0, 62, 0], [0, 0, 0, 0, 0, 0, 0, 353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 350, 0, 0], [0, 0, 0, 0, 0, 0, 543, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 361, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 358, 0, 0], [0, 0, 0, 0, 0, 544, 544, 442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 545, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 491, 492, 493, 494, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 492, 492, 494, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 546, 546, 494, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 547, 546, 546, 494, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 548, 549, 368, 550, 0, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 274, 0, 368, 368, 0, 161, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 161, 0, 0, 0, 0, 498, 0, 0, 0, 0, 0], [0, 0, 0, 495, 0, 496, 368, 0, 161, 0, 162, 0, 0, 498, 0, 0, 0, 0, 0], [0, 0, 0, 495, 0, 368, 368, 0, 161, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 551, 500, 552, 552, 22, 23, 0, 24, 0, 0, 0, 504, 0, 0, 27, 0], [0, 553, 0, 0, 0, 76, 554, 0, 23, 0, 24, 0, 0, 0, 78, 0, 553, 0, 0], [0, 0, 0, 0, 555, 80, 80, 22, 23, 0, 0, 0, 0, 503, 555, 0, 0, 0, 0], [0, 0, 0, 499, 500, 501, 552, 22, 23, 0, 24, 0, 0, 503, 504, 0, 0, 27, 0], [0, 0, 0, 499, 500, 552, 552, 22, 23, 0, 24, 0, 0, 0, 504, 0, 0, 27, 0], [0, 556, 90, 0, 0, 76, 554, 0, 23, 0, 24, 0, 0, 0, 78, 0, 556, 0, 0], [0, 448, 0, 0, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 448, 0, 0], [0, 448, 0, 505, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 448, 0, 0], [0, 0, 0, 551, 500, 552, 552, 22, 23, 0, 24, 0, 0, 0, 504, 0, 0, 27, 0], [0, 0, 0, 0, 555, 80, 80, 22, 23, 0, 0, 0, 0, 510, 555, 0, 0, 0, 0], [0, 0, 0, 507, 500, 508, 552, 22, 23, 0, 24, 0, 0, 510, 504, 0, 0, 27, 0], [0, 0, 0, 507, 500, 552, 552, 22, 23, 0, 24, 0, 0, 0, 504, 0, 0, 27, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 0, 0], [0, 0, 0, 557, 513, 558, 558, 32, 33, 0, 34, 0, 0, 0, 517, 0, 0, 37, 0], [0, 559, 0, 0, 0, 97, 560, 0, 33, 0, 34, 0, 0, 0, 99, 0, 559, 0, 0], [0, 0, 0, 0, 561, 101, 101, 32, 33, 0, 0, 0, 0, 516, 561, 0, 0, 0, 0], [0, 0, 0, 512, 513, 514, 558, 32, 33, 0, 34, 0, 0, 516, 517, 0, 0, 37, 0], [0, 0, 0, 512, 513, 558, 558, 32, 33, 0, 34, 0, 0, 0, 517, 0, 0, 37, 0], [0, 562, 111, 0, 0, 97, 560, 0, 33, 0, 34, 0, 0, 0, 99, 0, 562, 0, 0], [0, 457, 0, 0, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 457, 0, 0], [0, 457, 0, 518, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 457, 0, 0], [0, 0, 0, 557, 513, 558, 558, 32, 33, 0, 34, 0, 0, 0, 517, 0, 0, 37, 0], [0, 0, 0, 0, 561, 101, 101, 32, 33, 0, 0, 0, 0, 523, 561, 0, 0, 0, 0], [0, 0, 0, 520, 513, 521, 558, 32, 33, 0, 34, 0, 0, 523, 517, 0, 0, 37, 0], [0, 0, 0, 520, 513, 558, 558, 32, 33, 0, 34, 0, 0, 0, 517, 0, 0, 37, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 0, 0], [0, 0, 0, 0, 465, 526, 526, 8, 9, 0, 10, 0, 0, 0, 469, 0, 0, 16, 0], [0, 0, 0, 0, 529, 44, 44, 8, 9, 0, 0, 0, 0, 0, 529, 0, 0, 0, 0], [0, 0, 0, 563, 66, 564, 565, 8, 9, 0, 10, 0, 0, 566, 68, 0, 0, 16, 0], [0, 527, 0, 567, 0, 123, 123, 8, 9, 0, 10, 0, 0, 0, 42, 0, 527, 0, 0], [0, 527, 0, 0, 0, 121, 568, 0, 9, 0, 10, 0, 0, 0, 42, 0, 527, 0, 0], [0, 0, 0, 569, 66, 570, 571, 8, 9, 0, 10, 0, 0, 572, 68, 0, 0, 16, 0], [0, 0, 0, 573, 532, 574, 574, 57, 58, 0, 59, 0, 0, 0, 536, 0, 0, 62, 0], [0, 575, 0, 0, 0, 137, 576, 0, 58, 0, 59, 0, 0, 0, 139, 0, 575, 0, 0], [0, 0, 0, 0, 577, 141, 141, 57, 58, 0, 0, 0, 0, 535, 577, 0, 0, 0, 0], [0, 0, 0, 531, 532, 533, 574, 57, 58, 0, 59, 0, 0, 535, 536, 0, 0, 62, 0], [0, 0, 0, 531, 532, 574, 574, 57, 58, 0, 59, 0, 0, 0, 536, 0, 0, 62, 0], [0, 578, 151, 0, 0, 137, 576, 0, 58, 0, 59, 0, 0, 0, 139, 0, 578, 0, 0], [0, 479, 0, 0, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 479, 0, 0], [0, 479, 0, 537, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 479, 0, 0], [0, 0, 0, 573, 532, 574, 574, 57, 58, 0, 59, 0, 0, 0, 536, 0, 0, 62, 0], [0, 0, 0, 0, 577, 141, 141, 57, 58, 0, 0, 0, 0, 542, 577, 0, 0, 0, 0], [0, 0, 0, 539, 532, 540, 574, 57, 58, 0, 59, 0, 0, 542, 536, 0, 0, 62, 0], [0, 0, 0, 539, 532, 574, 574, 57, 58, 0, 59, 0, 0, 0, 536, 0, 0, 62, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 137, 0, 0], [0, 0, 0, 0, 0, 0, 0, 442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 439, 0, 0], [0, 0, 0, 0, 0, 579, 579, 494, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 549, 368, 550, 0, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 368, 368, 0, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 581, 0, 0, 0, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 500, 552, 552, 22, 23, 0, 24, 0, 0, 0, 504, 0, 0, 27, 0], [0, 0, 0, 0, 555, 80, 80, 22, 23, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0], [0, 0, 0, 582, 91, 583, 584, 22, 23, 0, 24, 0, 0, 585, 93, 0, 0, 27, 0], [0, 553, 0, 586, 0, 177, 177, 22, 23, 0, 24, 0, 0, 0, 78, 0, 553, 0, 0], [0, 553, 0, 0, 0, 175, 587, 0, 23, 0, 24, 0, 0, 0, 78, 0, 553, 0, 0], [0, 0, 0, 588, 91, 589, 590, 22, 23, 0, 24, 0, 0, 591, 93, 0, 0, 27, 0], [0, 0, 0, 0, 513, 558, 558, 32, 33, 0, 34, 0, 0, 0, 517, 0, 0, 37, 0], [0, 0, 0, 0, 561, 101, 101, 32, 33, 0, 0, 0, 0, 0, 561, 0, 0, 0, 0], [0, 0, 0, 592, 112, 593, 594, 32, 33, 0, 34, 0, 0, 595, 114, 0, 0, 37, 0], [0, 559, 0, 596, 0, 203, 203, 32, 33, 0, 34, 0, 0, 0, 99, 0, 559, 0, 0], [0, 559, 0, 0, 0, 201, 597, 0, 33, 0, 34, 0, 0, 0, 99, 0, 559, 0, 0], [0, 0, 0, 598, 112, 599, 600, 32, 33, 0, 34, 0, 0, 601, 114, 0, 0, 37, 0], [0, 0, 0, 602, 66, 67, 67, 8, 9, 0, 10, 0, 0, 0, 68, 0, 0, 16, 0], [0, 0, 0, 0, 165, 44, 44, 8, 9, 0, 0, 0, 0, 566, 165, 0, 0, 0, 0], [0, 0, 0, 563, 66, 564, 67, 8, 9, 0, 10, 0, 0, 566, 68, 0, 0, 16, 0], [0, 0, 0, 563, 66, 67, 67, 8, 9, 0, 10, 0, 0, 0, 68, 0, 0, 16, 0], [0, 527, 0, 0, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 527, 0, 0], [0, 527, 0, 567, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 527, 0, 0], [0, 0, 0, 602, 66, 67, 67, 8, 9, 0, 10, 0, 0, 0, 68, 0, 0, 16, 0], [0, 0, 0, 0, 165, 44, 44, 8, 9, 0, 0, 0, 0, 572, 165, 0, 0, 0, 0], [0, 0, 0, 569, 66, 570, 67, 8, 9, 0, 10, 0, 0, 572, 68, 0, 0, 16, 0], [0, 0, 0, 569, 66, 67, 67, 8, 9, 0, 10, 0, 0, 0, 68, 0, 0, 16, 0], [0, 0, 0, 0, 532, 574, 574, 57, 58, 0, 59, 0, 0, 0, 536, 0, 0, 62, 0], [0, 0, 0, 0, 577, 141, 141, 57, 58, 0, 0, 0, 0, 0, 577, 0, 0, 0, 0], [0, 0, 0, 603, 152, 604, 605, 57, 58, 0, 59, 0, 0, 606, 154, 0, 0, 62, 0], [0, 575, 0, 607, 0, 248, 248, 57, 58, 0, 59, 0, 0, 0, 139, 0, 575, 0, 0], [0, 575, 0, 0, 0, 246, 608, 0, 58, 0, 59, 0, 0, 0, 139, 0, 575, 0, 0], [0, 0, 0, 609, 152, 610, 611, 57, 58, 0, 59, 0, 0, 612, 154, 0, 0, 62, 0], [0, 0, 0, 0, 0, 0, 0, 494, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 491, 0, 0], [0, 0, 0, 0, 0, 0, 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 614, 91, 92, 92, 22, 23, 0, 24, 0, 0, 0, 93, 0, 0, 27, 0], [0, 0, 0, 0, 194, 80, 80, 22, 23, 0, 0, 0, 0, 585, 194, 0, 0, 0, 0], [0, 0, 0, 582, 91, 583, 92, 22, 23, 0, 24, 0, 0, 585, 93, 0, 0, 27, 0], [0, 0, 0, 582, 91, 92, 92, 22, 23, 0, 24, 0, 0, 0, 93, 0, 0, 27, 0], [0, 553, 0, 0, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 553, 0, 0], [0, 553, 0, 586, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 553, 0, 0], [0, 0, 0, 614, 91, 92, 92, 22, 23, 0, 24, 0, 0, 0, 93, 0, 0, 27, 0], [0, 0, 0, 0, 194, 80, 80, 22, 23, 0, 0, 0, 0, 591, 194, 0, 0, 0, 0], [0, 0, 0, 588, 91, 589, 92, 22, 23, 0, 24, 0, 0, 591, 93, 0, 0, 27, 0], [0, 0, 0, 588, 91, 92, 92, 22, 23, 0, 24, 0, 0, 0, 93, 0, 0, 27, 0], [0, 0, 0, 615, 112, 113, 113, 32, 33, 0, 34, 0, 0, 0, 114, 0, 0, 37, 0], [0, 0, 0, 0, 220, 101, 101, 32, 33, 0, 0, 0, 0, 595, 220, 0, 0, 0, 0], [0, 0, 0, 592, 112, 593, 113, 32, 33, 0, 34, 0, 0, 595, 114, 0, 0, 37, 0], [0, 0, 0, 592, 112, 113, 113, 32, 33, 0, 34, 0, 0, 0, 114, 0, 0, 37, 0], [0, 559, 0, 0, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 559, 0, 0], [0, 559, 0, 596, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 559, 0, 0], [0, 0, 0, 615, 112, 113, 113, 32, 33, 0, 34, 0, 0, 0, 114, 0, 0, 37, 0], [0, 0, 0, 0, 220, 101, 101, 32, 33, 0, 0, 0, 0, 601, 220, 0, 0, 0, 0], [0, 0, 0, 598, 112, 599, 113, 32, 33, 0, 34, 0, 0, 601, 114, 0, 0, 37, 0], [0, 0, 0, 598, 112, 113, 113, 32, 33, 0, 34, 0, 0, 0, 114, 0, 0, 37, 0], [0, 0, 0, 0, 66, 67, 67, 8, 9, 0, 10, 0, 0, 0, 68, 0, 0, 16, 0], [0, 0, 0, 616, 152, 153, 153, 57, 58, 0, 59, 0, 0, 0, 154, 0, 0, 62, 0], [0, 0, 0, 0, 265, 141, 141, 57, 58, 0, 0, 0, 0, 606, 265, 0, 0, 0, 0], [0, 0, 0, 603, 152, 604, 153, 57, 58, 0, 59, 0, 0, 606, 154, 0, 0, 62, 0], [0, 0, 0, 603, 152, 153, 153, 57, 58, 0, 59, 0, 0, 0, 154, 0, 0, 62, 0], [0, 575, 0, 0, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 575, 0, 0], [0, 575, 0, 607, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 575, 0, 0], [0, 0, 0, 616, 152, 153, 153, 57, 58, 0, 59, 0, 0, 0, 154, 0, 0, 62, 0], [0, 0, 0, 0, 265, 141, 141, 57, 58, 0, 0, 0, 0, 612, 265, 0, 0, 0, 0], [0, 0, 0, 609, 152, 610, 153, 57, 58, 0, 59, 0, 0, 612, 154, 0, 0, 62, 0], [0, 0, 0, 609, 152, 153, 153, 57, 58, 0, 59, 0, 0, 0, 154, 0, 0, 62, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 549, 0, 0], [0, 0, 0, 0, 91, 92, 92, 22, 23, 0, 24, 0, 0, 0, 93, 0, 0, 27, 0], [0, 0, 0, 0, 112, 113, 113, 32, 33, 0, 34, 0, 0, 0, 114, 0, 0, 37, 0], [0, 0, 0, 0, 152, 153, 153, 57, 58, 0, 59, 0, 0, 0, 154, 0, 0, 62, 0]];\nvar accepting = [false, true, true, true, true, true, false, false, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, false, true, false, true, true, false, false, true, true, true, true, true, true, false, false, true, true, true, true, true, true, true, true, true, true, false, true, true, false, true, true, true, false, true, true, true, false, true, false, true, true, false, false, true, true, true, true, true, true, true, false, true, true, false, true, true, true, false, true, false, true, true, false, false, true, true, true, true, true, true, true, false, true, true, true, false, true, true, true, false, true, false, true, true, false, false, false, true, true, false, false, true, true, true, true, true, true, false, true, false, true, true, false, false, true, true, true, true, true, true, true, false, true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, false, true, false, true, true, false, false, false, true, true, false, false, true, true, true, false, true, true, true, true, true, true, false, true, true, true, false, true, false, true, true, false, false, false, true, true, false, false, true, true, true, false, true, true, true, true, true, false, true, true, true, true, true, false, true, true, false, false, false, false, true, true, false, false, true, true, true, false, true, true, true, false, true, false, true, true, false, false, false, true, true, false, false, true, true, true, false, true, true, true, true, false, true, false, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, false, true, true, false, false, false, false, true, true, false, false, true, true, true, false, true, true, true, true, true, false, true, true, false, false, false, false, true, true, false, false, true, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false, false, false, true, false, true, false, true, true, true, true, true, false, true, true, false, false, false, false, true, true, false, false, true, true, true, false, true, true, false, false, true, false, true, true, false, true, true, false, true, true, false, true, true, true, true, true, true, false, true, true, false, false, false, false, true, false, true, true, false, true, true, true, true, true, true, false, true, true, false, false, false, false, true, false, true, false, true, true, true, true, false, false, false, true, true, false, true, true, true, true, true, true, false, true, true, false, false, false, false, true, false, true, false, true, true, false, false, true, true, false, false, true, true, true, false, true, false, true, true, true, true, false, false, false, true, false, true, true, true, true, false, false, false, true, true, false, true, true, true, true, true, true, false, true, true, false, true, false, true, true, true, true, false, false, false, false, false, false, false, true, true, false, false, true, true, false, true, true, true, true, false, true, true, true, true, true, true, false, true, true, false, true, true, false, true, true, true, true, true, true, false, true, true, false, true, false, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false, false, false, false, true, true, false, true, false, true, true, true, true, true, false, true, true, true, true, true, false, true, true, true, true, true, false, true, true, true, false, true, true, true, true, false, false, false, true, false, true, true, true, true, true, false, true, true, true, false, true, true, true, true, true, false, true, true, true, true, false, true, true, true, true, true, false, true, true, false, true, true, true];\nvar tags = [[], [\"broken_cluster\"], [\"consonant_syllable\"], [\"vowel_syllable\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"standalone_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"consonant_syllable\"], [\"broken_cluster\"], [\"symbol_cluster\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"symbol_cluster\"], [], [\"symbol_cluster\"], [\"symbol_cluster\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"symbol_cluster\"], [\"symbol_cluster\"], [\"symbol_cluster\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [\"broken_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"broken_cluster\"], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"broken_cluster\"], [\"symbol_cluster\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [], [], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [], [], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [], [], [\"broken_cluster\"], [], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [], [], [], [\"consonant_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [], [], [], [\"vowel_syllable\"], [], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [], [], [\"standalone_cluster\"], [], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [], [], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [], [], [], [], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [], [], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"broken_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"consonant_syllable\"], [\"vowel_syllable\"], [\"standalone_cluster\"]];\nvar indicMachine = {\n\tstateTable: stateTable,\n\taccepting: accepting,\n\ttags: tags\n};\n\nvar categories = [\"O\", \"IND\", \"S\", \"GB\", \"B\", \"FM\", \"CGJ\", \"VMAbv\", \"VMPst\", \"VAbv\", \"VPst\", \"CMBlw\", \"VPre\", \"VBlw\", \"H\", \"VMBlw\", \"CMAbv\", \"MBlw\", \"CS\", \"R\", \"SUB\", \"MPst\", \"MPre\", \"FAbv\", \"FPst\", \"FBlw\", \"SMAbv\", \"SMBlw\", \"VMPre\", \"ZWNJ\", \"ZWJ\", \"WJ\", \"VS\", \"N\", \"HN\", \"MAbv\"];\nvar decompositions$1 = { \"2507\": [2503, 2494], \"2508\": [2503, 2519], \"2888\": [2887, 2902], \"2891\": [2887, 2878], \"2892\": [2887, 2903], \"3018\": [3014, 3006], \"3019\": [3015, 3006], \"3020\": [3014, 3031], \"3144\": [3142, 3158], \"3264\": [3263, 3285], \"3271\": [3270, 3285], \"3272\": [3270, 3286], \"3274\": [3270, 3266], \"3275\": [3270, 3266, 3285], \"3402\": [3398, 3390], \"3403\": [3399, 3390], \"3404\": [3398, 3415], \"3546\": [3545, 3530], \"3548\": [3545, 3535], \"3549\": [3545, 3535, 3530], \"3550\": [3545, 3551], \"3635\": [3661, 3634], \"3763\": [3789, 3762], \"3955\": [3953, 3954], \"3957\": [3953, 3956], \"3958\": [4018, 3968], \"3959\": [4018, 3953, 3968], \"3960\": [4019, 3968], \"3961\": [4019, 3953, 3968], \"3969\": [3953, 3968], \"6971\": [6970, 6965], \"6973\": [6972, 6965], \"6976\": [6974, 6965], \"6977\": [6975, 6965], \"6979\": [6978, 6965], \"69934\": [69937, 69927], \"69935\": [69938, 69927], \"70475\": [70471, 70462], \"70476\": [70471, 70487], \"70843\": [70841, 70842], \"70844\": [70841, 70832], \"70846\": [70841, 70845], \"71098\": [71096, 71087], \"71099\": [71097, 71087] };\nvar stateTable$1 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2, 2, 3, 4, 4, 5, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 17, 18, 11, 19, 20, 21, 22, 0, 0, 23, 0, 0, 2, 0, 24, 0, 25], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 0, 0, 0, 0, 27, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 0, 0, 41, 35, 42, 43, 44, 45, 0, 0, 46, 0, 0, 0, 39, 0, 0, 47], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 0, 0, 12, 0, 14, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 9, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 16, 0, 0, 18, 11, 19, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 25], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 0, 11, 12, 0, 14, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 9, 0, 0, 12, 0, 14, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 0, 7, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 18, 11, 19, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 25], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 0, 11, 12, 0, 14, 0, 0, 0, 0, 0, 11, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 4, 4, 5, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 18, 11, 19, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 25], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 48, 11, 12, 13, 14, 48, 16, 0, 0, 18, 11, 19, 20, 21, 22, 0, 0, 23, 0, 0, 0, 49, 0, 0, 25], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 0, 11, 12, 0, 14, 0, 16, 0, 0, 0, 11, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 25], [0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 0, 11, 12, 0, 14, 0, 16, 0, 0, 0, 11, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 0, 0, 36, 0, 38, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 0, 33, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 34, 35, 36, 37, 38, 0, 40, 0, 0, 41, 35, 42, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 47], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 0, 35, 36, 0, 38, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 0, 33, 0, 0, 36, 0, 38, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 0, 31, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 0, 0, 41, 35, 42, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 47], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 0, 35, 36, 0, 38, 0, 0, 0, 0, 0, 35, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 52, 35, 36, 37, 38, 52, 40, 0, 0, 41, 35, 42, 43, 44, 45, 0, 0, 46, 0, 0, 0, 53, 0, 0, 47], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 0, 35, 36, 0, 38, 0, 40, 0, 0, 0, 35, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 47], [0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 0, 35, 36, 0, 38, 0, 40, 0, 0, 0, 35, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 48, 11, 12, 13, 14, 0, 16, 0, 0, 18, 11, 19, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 25], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 48, 11, 12, 13, 14, 48, 16, 0, 0, 18, 11, 19, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 25], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 52, 35, 36, 37, 38, 0, 40, 0, 0, 41, 35, 42, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 47], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 52, 35, 36, 37, 38, 52, 40, 0, 0, 41, 35, 42, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 47], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0]];\nvar accepting$1 = [false, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true];\nvar tags$1 = [[], [\"broken_cluster\"], [\"independent_cluster\"], [\"symbol_cluster\"], [\"standard_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"numeral_cluster\"], [\"broken_cluster\"], [\"independent_cluster\"], [\"symbol_cluster\"], [\"symbol_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"virama_terminated_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"numeral_cluster\"], [\"number_joiner_terminated_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"numeral_cluster\"]];\nvar useData = {\n\tcategories: categories,\n\tdecompositions: decompositions$1,\n\tstateTable: stateTable$1,\n\taccepting: accepting$1,\n\ttags: tags$1\n};\n\n// Cateories used in the OpenType spec:\n// https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx\nvar CATEGORIES = {\n  X: 1 << 0,\n  C: 1 << 1,\n  V: 1 << 2,\n  N: 1 << 3,\n  H: 1 << 4,\n  ZWNJ: 1 << 5,\n  ZWJ: 1 << 6,\n  M: 1 << 7,\n  SM: 1 << 8,\n  VD: 1 << 9,\n  A: 1 << 10,\n  Placeholder: 1 << 11,\n  Dotted_Circle: 1 << 12,\n  RS: 1 << 13, // Register Shifter, used in Khmer OT spec.\n  Coeng: 1 << 14, // Khmer-style Virama.\n  Repha: 1 << 15, // Atomically-encoded logical or visual repha.\n  Ra: 1 << 16,\n  CM: 1 << 17, // Consonant-Medial.\n  Symbol: 1 << 18 // Avagraha, etc that take marks (SM,A,VD).\n};\n\n// Visual positions in a syllable from left to right.\nvar POSITIONS = {\n  Start: 1 << 0,\n\n  Ra_To_Become_Reph: 1 << 1,\n  Pre_M: 1 << 2,\n  Pre_C: 1 << 3,\n\n  Base_C: 1 << 4,\n  After_Main: 1 << 5,\n\n  Above_C: 1 << 6,\n\n  Before_Sub: 1 << 7,\n  Below_C: 1 << 8,\n  After_Sub: 1 << 9,\n\n  Before_Post: 1 << 10,\n  Post_C: 1 << 11,\n  After_Post: 1 << 12,\n\n  Final_C: 1 << 13,\n  SMVD: 1 << 14,\n\n  End: 1 << 15\n};\n\nvar CONSONANT_FLAGS = CATEGORIES.C | CATEGORIES.Ra | CATEGORIES.CM | CATEGORIES.V | CATEGORIES.Placeholder | CATEGORIES.Dotted_Circle;\nvar JOINER_FLAGS = CATEGORIES.ZWJ | CATEGORIES.ZWNJ;\nvar HALANT_OR_COENG_FLAGS = CATEGORIES.H | CATEGORIES.Coeng;\n\nvar INDIC_CONFIGS = {\n  Default: {\n    hasOldSpec: false,\n    virama: 0,\n    basePos: 'Last',\n    rephPos: POSITIONS.Before_Post,\n    rephMode: 'Implicit',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  Devanagari: {\n    hasOldSpec: true,\n    virama: 0x094D,\n    basePos: 'Last',\n    rephPos: POSITIONS.Before_Post,\n    rephMode: 'Implicit',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  Bengali: {\n    hasOldSpec: true,\n    virama: 0x09CD,\n    basePos: 'Last',\n    rephPos: POSITIONS.After_Sub,\n    rephMode: 'Implicit',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  Gurmukhi: {\n    hasOldSpec: true,\n    virama: 0x0A4D,\n    basePos: 'Last',\n    rephPos: POSITIONS.Before_Sub,\n    rephMode: 'Implicit',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  Gujarati: {\n    hasOldSpec: true,\n    virama: 0x0ACD,\n    basePos: 'Last',\n    rephPos: POSITIONS.Before_Post,\n    rephMode: 'Implicit',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  Oriya: {\n    hasOldSpec: true,\n    virama: 0x0B4D,\n    basePos: 'Last',\n    rephPos: POSITIONS.After_Main,\n    rephMode: 'Implicit',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  Tamil: {\n    hasOldSpec: true,\n    virama: 0x0BCD,\n    basePos: 'Last',\n    rephPos: POSITIONS.After_Post,\n    rephMode: 'Implicit',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  Telugu: {\n    hasOldSpec: true,\n    virama: 0x0C4D,\n    basePos: 'Last',\n    rephPos: POSITIONS.After_Post,\n    rephMode: 'Explicit',\n    blwfMode: 'Post_Only'\n  },\n\n  Kannada: {\n    hasOldSpec: true,\n    virama: 0x0CCD,\n    basePos: 'Last',\n    rephPos: POSITIONS.After_Post,\n    rephMode: 'Implicit',\n    blwfMode: 'Post_Only'\n  },\n\n  Malayalam: {\n    hasOldSpec: true,\n    virama: 0x0D4D,\n    basePos: 'Last',\n    rephPos: POSITIONS.After_Main,\n    rephMode: 'Log_Repha',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  // Handled by UniversalShaper\n  // Sinhala: {\n  //   hasOldSpec: false,\n  //   virama: 0x0DCA,\n  //   basePos: 'Last_Sinhala',\n  //   rephPos: POSITIONS.After_Main,\n  //   rephMode: 'Explicit',\n  //   blwfMode: 'Pre_And_Post'\n  // },\n\n  Khmer: {\n    hasOldSpec: false,\n    virama: 0x17D2,\n    basePos: 'First',\n    rephPos: POSITIONS.Ra_To_Become_Reph,\n    rephMode: 'Vis_Repha',\n    blwfMode: 'Pre_And_Post'\n  }\n};\n\n// Additional decompositions that aren't in Unicode\nvar INDIC_DECOMPOSITIONS = {\n  // Khmer\n  0x17BE: [0x17C1, 0x17BE],\n  0x17BF: [0x17C1, 0x17BF],\n  0x17C0: [0x17C1, 0x17C0],\n  0x17C4: [0x17C1, 0x17C4],\n  0x17C5: [0x17C1, 0x17C5]\n};\n\nvar _class$6;\nvar _temp$2;\nvar decompositions = useData.decompositions;\n\nvar trie$1 = new UnicodeTrie(Buffer(\"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\",\"base64\"));\nvar stateMachine = new StateMachine(indicMachine);\n\n/**\n * The IndicShaper supports indic scripts e.g. Devanagari, Kannada, etc.\n * Based on code from Harfbuzz: https://github.com/behdad/harfbuzz/blob/master/src/hb-ot-shape-complex-indic.cc\n */\nvar IndicShaper = (_temp$2 = _class$6 = function (_DefaultShaper) {\n  _inherits(IndicShaper, _DefaultShaper);\n\n  function IndicShaper() {\n    _classCallCheck(this, IndicShaper);\n\n    return _possibleConstructorReturn(this, _DefaultShaper.apply(this, arguments));\n  }\n\n  IndicShaper.planFeatures = function planFeatures(plan) {\n    plan.addStage(setupSyllables);\n\n    plan.addStage(['locl', 'ccmp']);\n\n    plan.addStage(initialReordering);\n\n    plan.addStage('nukt');\n    plan.addStage('akhn');\n    plan.addStage('rphf', false);\n    plan.addStage('rkrf');\n    plan.addStage('pref', false);\n    plan.addStage('blwf', false);\n    plan.addStage('abvf', false);\n    plan.addStage('half', false);\n    plan.addStage('pstf', false);\n    plan.addStage('vatu');\n    plan.addStage('cjct');\n    plan.addStage('cfar', false);\n\n    plan.addStage(finalReordering);\n\n    plan.addStage({\n      local: ['init'],\n      global: ['pres', 'abvs', 'blws', 'psts', 'haln', 'dist', 'abvm', 'blwm', 'calt', 'clig']\n    });\n\n    // Setup the indic config for the selected script\n    plan.unicodeScript = fromOpenType(plan.script);\n    plan.indicConfig = INDIC_CONFIGS[plan.unicodeScript] || INDIC_CONFIGS.Default;\n    plan.isOldSpec = plan.indicConfig.hasOldSpec && plan.script[plan.script.length - 1] !== '2';\n\n    // TODO: turn off kern (Khmer) and liga features.\n  };\n\n  IndicShaper.assignFeatures = function assignFeatures(plan, glyphs) {\n    var _loop = function _loop(i) {\n      var codepoint = glyphs[i].codePoints[0];\n      var d = INDIC_DECOMPOSITIONS[codepoint] || decompositions[codepoint];\n      if (d) {\n        var decomposed = d.map(function (c) {\n          var g = plan.font.glyphForCodePoint(c);\n          return new GlyphInfo(plan.font, g.id, [c], glyphs[i].features);\n        });\n\n        glyphs.splice.apply(glyphs, [i, 1].concat(decomposed));\n      }\n    };\n\n    // Decompose split matras\n    // TODO: do this in a more general unicode normalizer\n    for (var i = glyphs.length - 1; i >= 0; i--) {\n      _loop(i);\n    }\n  };\n\n  return IndicShaper;\n}(DefaultShaper), _class$6.zeroMarkWidths = 'NONE', _temp$2);\nfunction indicCategory(glyph) {\n  return trie$1.get(glyph.codePoints[0]) >> 8;\n}\n\nfunction indicPosition(glyph) {\n  return 1 << (trie$1.get(glyph.codePoints[0]) & 0xff);\n}\n\nvar IndicInfo = function IndicInfo(category, position, syllableType, syllable) {\n  _classCallCheck(this, IndicInfo);\n\n  this.category = category;\n  this.position = position;\n  this.syllableType = syllableType;\n  this.syllable = syllable;\n};\n\nfunction setupSyllables(font, glyphs) {\n  var syllable = 0;\n  var last = 0;\n  for (var _iterator = stateMachine.match(glyphs.map(indicCategory)), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n    var _ref;\n\n    if (_isArray) {\n      if (_i >= _iterator.length) break;\n      _ref = _iterator[_i++];\n    } else {\n      _i = _iterator.next();\n      if (_i.done) break;\n      _ref = _i.value;\n    }\n\n    var _ref2 = _ref,\n        start = _ref2[0],\n        end = _ref2[1],\n        tags = _ref2[2];\n\n    if (start > last) {\n      ++syllable;\n      for (var _i2 = last; _i2 < start; _i2++) {\n        glyphs[_i2].shaperInfo = new IndicInfo(CATEGORIES.X, POSITIONS.End, 'non_indic_cluster', syllable);\n      }\n    }\n\n    ++syllable;\n\n    // Create shaper info\n    for (var _i3 = start; _i3 <= end; _i3++) {\n      glyphs[_i3].shaperInfo = new IndicInfo(1 << indicCategory(glyphs[_i3]), indicPosition(glyphs[_i3]), tags[0], syllable);\n    }\n\n    last = end + 1;\n  }\n\n  if (last < glyphs.length) {\n    ++syllable;\n    for (var i = last; i < glyphs.length; i++) {\n      glyphs[i].shaperInfo = new IndicInfo(CATEGORIES.X, POSITIONS.End, 'non_indic_cluster', syllable);\n    }\n  }\n}\n\nfunction isConsonant(glyph) {\n  return glyph.shaperInfo.category & CONSONANT_FLAGS;\n}\n\nfunction isJoiner(glyph) {\n  return glyph.shaperInfo.category & JOINER_FLAGS;\n}\n\nfunction isHalantOrCoeng(glyph) {\n  return glyph.shaperInfo.category & HALANT_OR_COENG_FLAGS;\n}\n\nfunction wouldSubstitute(glyphs, feature) {\n  for (var _iterator2 = glyphs, _isArray2 = Array.isArray(_iterator2), _i4 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n    var _glyph$features;\n\n    var _ref3;\n\n    if (_isArray2) {\n      if (_i4 >= _iterator2.length) break;\n      _ref3 = _iterator2[_i4++];\n    } else {\n      _i4 = _iterator2.next();\n      if (_i4.done) break;\n      _ref3 = _i4.value;\n    }\n\n    var glyph = _ref3;\n\n    glyph.features = (_glyph$features = {}, _glyph$features[feature] = true, _glyph$features);\n  }\n\n  var GSUB = glyphs[0]._font._layoutEngine.engine.GSUBProcessor;\n  GSUB.applyFeatures([feature], glyphs);\n\n  return glyphs.length === 1;\n}\n\nfunction consonantPosition(font, consonant, virama) {\n  var glyphs = [virama, consonant, virama];\n  if (wouldSubstitute(glyphs.slice(0, 2), 'blwf') || wouldSubstitute(glyphs.slice(1, 3), 'blwf')) {\n    return POSITIONS.Below_C;\n  } else if (wouldSubstitute(glyphs.slice(0, 2), 'pstf') || wouldSubstitute(glyphs.slice(1, 3), 'pstf')) {\n    return POSITIONS.Post_C;\n  } else if (wouldSubstitute(glyphs.slice(0, 2), 'pref') || wouldSubstitute(glyphs.slice(1, 3), 'pref')) {\n    return POSITIONS.Post_C;\n  }\n\n  return POSITIONS.Base_C;\n}\n\nfunction initialReordering(font, glyphs, plan) {\n  var indicConfig = plan.indicConfig;\n  var features = font._layoutEngine.engine.GSUBProcessor.features;\n\n  var dottedCircle = font.glyphForCodePoint(0x25cc).id;\n  var virama = font.glyphForCodePoint(indicConfig.virama).id;\n  if (virama) {\n    var info = new GlyphInfo(font, virama, [indicConfig.virama]);\n    for (var i = 0; i < glyphs.length; i++) {\n      if (glyphs[i].shaperInfo.position === POSITIONS.Base_C) {\n        glyphs[i].shaperInfo.position = consonantPosition(font, glyphs[i].copy(), info);\n      }\n    }\n  }\n\n  for (var start = 0, end = nextSyllable(glyphs, 0); start < glyphs.length; start = end, end = nextSyllable(glyphs, start)) {\n    var _glyphs$start$shaperI = glyphs[start].shaperInfo,\n        category = _glyphs$start$shaperI.category,\n        syllableType = _glyphs$start$shaperI.syllableType;\n\n\n    if (syllableType === 'symbol_cluster' || syllableType === 'non_indic_cluster') {\n      continue;\n    }\n\n    if (syllableType === 'broken_cluster' && dottedCircle) {\n      var g = new GlyphInfo(font, dottedCircle, [0x25cc]);\n      g.shaperInfo = new IndicInfo(1 << indicCategory(g), indicPosition(g), glyphs[start].shaperInfo.syllableType, glyphs[start].shaperInfo.syllable);\n\n      // Insert after possible Repha.\n      var _i5 = start;\n      while (_i5 < end && glyphs[_i5].shaperInfo.category === CATEGORIES.Repha) {\n        _i5++;\n      }\n\n      glyphs.splice(_i5++, 0, g);\n      end++;\n    }\n\n    // 1. Find base consonant:\n    //\n    // The shaping engine finds the base consonant of the syllable, using the\n    // following algorithm: starting from the end of the syllable, move backwards\n    // until a consonant is found that does not have a below-base or post-base\n    // form (post-base forms have to follow below-base forms), or that is not a\n    // pre-base reordering Ra, or arrive at the first consonant. The consonant\n    // stopped at will be the base.\n\n    var base = end;\n    var limit = start;\n    var hasReph = false;\n\n    // If the syllable starts with Ra + Halant (in a script that has Reph)\n    // and has more than one consonant, Ra is excluded from candidates for\n    // base consonants.\n    if (indicConfig.rephPos !== POSITIONS.Ra_To_Become_Reph && features.rphf && start + 3 <= end && (indicConfig.rephMode === 'Implicit' && !isJoiner(glyphs[start + 2]) || indicConfig.rephMode === 'Explicit' && glyphs[start + 2].shaperInfo.category === CATEGORIES.ZWJ)) {\n      // See if it matches the 'rphf' feature.\n      var _g = [glyphs[start].copy(), glyphs[start + 1].copy(), glyphs[start + 2].copy()];\n      if (wouldSubstitute(_g.slice(0, 2), 'rphf') || indicConfig.rephMode === 'Explicit' && wouldSubstitute(_g, 'rphf')) {\n        limit += 2;\n        while (limit < end && isJoiner(glyphs[limit])) {\n          limit++;\n        }\n        base = start;\n        hasReph = true;\n      }\n    } else if (indicConfig.rephMode === 'Log_Repha' && glyphs[start].shaperInfo.category === CATEGORIES.Repha) {\n      limit++;\n      while (limit < end && isJoiner(glyphs[limit])) {\n        limit++;\n      }\n      base = start;\n      hasReph = true;\n    }\n\n    switch (indicConfig.basePos) {\n      case 'Last':\n        {\n          // starting from the end of the syllable, move backwards\n          var _i6 = end;\n          var seenBelow = false;\n\n          do {\n            var _info = glyphs[--_i6].shaperInfo;\n\n            // until a consonant is found\n            if (isConsonant(glyphs[_i6])) {\n              // that does not have a below-base or post-base form\n              // (post-base forms have to follow below-base forms),\n              if (_info.position !== POSITIONS.Below_C && (_info.position !== POSITIONS.Post_C || seenBelow)) {\n                base = _i6;\n                break;\n              }\n\n              // or that is not a pre-base reordering Ra,\n              //\n              // IMPLEMENTATION NOTES:\n              //\n              // Our pre-base reordering Ra's are marked POS_POST_C, so will be skipped\n              // by the logic above already.\n              //\n\n              // or arrive at the first consonant. The consonant stopped at will\n              // be the base.\n              if (_info.position === POSITIONS.Below_C) {\n                seenBelow = true;\n              }\n\n              base = _i6;\n            } else if (start < _i6 && _info.category === CATEGORIES.ZWJ && glyphs[_i6 - 1].shaperInfo.category === CATEGORIES.H) {\n              // A ZWJ after a Halant stops the base search, and requests an explicit\n              // half form.\n              // A ZWJ before a Halant, requests a subjoined form instead, and hence\n              // search continues.  This is particularly important for Bengali\n              // sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya.\n              break;\n            }\n          } while (_i6 > limit);\n          break;\n        }\n\n      case 'First':\n        {\n          // The first consonant is always the base.\n          base = start;\n\n          // Mark all subsequent consonants as below.\n          for (var _i7 = base + 1; _i7 < end; _i7++) {\n            if (isConsonant(glyphs[_i7])) {\n              glyphs[_i7].shaperInfo.position = POSITIONS.Below_C;\n            }\n          }\n        }\n    }\n\n    // If the syllable starts with Ra + Halant (in a script that has Reph)\n    // and has more than one consonant, Ra is excluded from candidates for\n    // base consonants.\n    //\n    //  Only do this for unforced Reph. (ie. not for Ra,H,ZWJ)\n    if (hasReph && base === start && limit - base <= 2) {\n      hasReph = false;\n    }\n\n    // 2. Decompose and reorder Matras:\n    //\n    // Each matra and any syllable modifier sign in the cluster are moved to the\n    // appropriate position relative to the consonant(s) in the cluster. The\n    // shaping engine decomposes two- or three-part matras into their constituent\n    // parts before any repositioning. Matra characters are classified by which\n    // consonant in a conjunct they have affinity for and are reordered to the\n    // following positions:\n    //\n    //   o Before first half form in the syllable\n    //   o After subjoined consonants\n    //   o After post-form consonant\n    //   o After main consonant (for above marks)\n    //\n    // IMPLEMENTATION NOTES:\n    //\n    // The normalize() routine has already decomposed matras for us, so we don't\n    // need to worry about that.\n\n    // 3.  Reorder marks to canonical order:\n    //\n    // Adjacent nukta and halant or nukta and vedic sign are always repositioned\n    // if necessary, so that the nukta is first.\n    //\n    // IMPLEMENTATION NOTES:\n    //\n    // We don't need to do this: the normalize() routine already did this for us.\n\n    // Reorder characters\n\n    for (var _i8 = start; _i8 < base; _i8++) {\n      var _info2 = glyphs[_i8].shaperInfo;\n      _info2.position = Math.min(POSITIONS.Pre_C, _info2.position);\n    }\n\n    if (base < end) {\n      glyphs[base].shaperInfo.position = POSITIONS.Base_C;\n    }\n\n    // Mark final consonants.  A final consonant is one appearing after a matra,\n    // like in Khmer.\n    for (var _i9 = base + 1; _i9 < end; _i9++) {\n      if (glyphs[_i9].shaperInfo.category === CATEGORIES.M) {\n        for (var j = _i9 + 1; j < end; j++) {\n          if (isConsonant(glyphs[j])) {\n            glyphs[j].shaperInfo.position = POSITIONS.Final_C;\n            break;\n          }\n        }\n        break;\n      }\n    }\n\n    // Handle beginning Ra\n    if (hasReph) {\n      glyphs[start].shaperInfo.position = POSITIONS.Ra_To_Become_Reph;\n    }\n\n    // For old-style Indic script tags, move the first post-base Halant after\n    // last consonant.\n    //\n    // Reports suggest that in some scripts Uniscribe does this only if there\n    // is *not* a Halant after last consonant already (eg. Kannada), while it\n    // does it unconditionally in other scripts (eg. Malayalam).  We don't\n    // currently know about other scripts, so we single out Malayalam for now.\n    //\n    // Kannada test case:\n    // U+0C9A,U+0CCD,U+0C9A,U+0CCD\n    // With some versions of Lohit Kannada.\n    // https://bugs.freedesktop.org/show_bug.cgi?id=59118\n    //\n    // Malayalam test case:\n    // U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D\n    // With lohit-ttf-20121122/Lohit-Malayalam.ttf\n    if (plan.isOldSpec) {\n      var disallowDoubleHalants = plan.unicodeScript !== 'Malayalam';\n      for (var _i10 = base + 1; _i10 < end; _i10++) {\n        if (glyphs[_i10].shaperInfo.category === CATEGORIES.H) {\n          var _j = void 0;\n          for (_j = end - 1; _j > _i10; _j--) {\n            if (isConsonant(glyphs[_j]) || disallowDoubleHalants && glyphs[_j].shaperInfo.category === CATEGORIES.H) {\n              break;\n            }\n          }\n\n          if (glyphs[_j].shaperInfo.category !== CATEGORIES.H && _j > _i10) {\n            // Move Halant to after last consonant.\n            var t = glyphs[_i10];\n            glyphs.splice.apply(glyphs, [_i10, 0].concat(glyphs.splice(_i10 + 1, _j - _i10)));\n            glyphs[_j] = t;\n          }\n\n          break;\n        }\n      }\n    }\n\n    // Attach misc marks to previous char to move with them.\n    var lastPos = POSITIONS.Start;\n    for (var _i11 = start; _i11 < end; _i11++) {\n      var _info3 = glyphs[_i11].shaperInfo;\n      if (_info3.category & (JOINER_FLAGS | CATEGORIES.N | CATEGORIES.RS | CATEGORIES.CM | HALANT_OR_COENG_FLAGS & _info3.category)) {\n        _info3.position = lastPos;\n        if (_info3.category === CATEGORIES.H && _info3.position === POSITIONS.Pre_M) {\n          // Uniscribe doesn't move the Halant with Left Matra.\n          // TEST: U+092B,U+093F,U+094DE\n          // We follow.  This is important for the Sinhala\n          // U+0DDA split matra since it decomposes to U+0DD9,U+0DCA\n          // where U+0DD9 is a left matra and U+0DCA is the virama.\n          // We don't want to move the virama with the left matra.\n          // TEST: U+0D9A,U+0DDA\n          for (var _j2 = _i11; _j2 > start; _j2--) {\n            if (glyphs[_j2 - 1].shaperInfo.position !== POSITIONS.Pre_M) {\n              _info3.position = glyphs[_j2 - 1].shaperInfo.position;\n              break;\n            }\n          }\n        }\n      } else if (_info3.position !== POSITIONS.SMVD) {\n        lastPos = _info3.position;\n      }\n    }\n\n    // For post-base consonants let them own anything before them\n    // since the last consonant or matra.\n    var last = base;\n    for (var _i12 = base + 1; _i12 < end; _i12++) {\n      if (isConsonant(glyphs[_i12])) {\n        for (var _j3 = last + 1; _j3 < _i12; _j3++) {\n          if (glyphs[_j3].shaperInfo.position < POSITIONS.SMVD) {\n            glyphs[_j3].shaperInfo.position = glyphs[_i12].shaperInfo.position;\n          }\n        }\n        last = _i12;\n      } else if (glyphs[_i12].shaperInfo.category === CATEGORIES.M) {\n        last = _i12;\n      }\n    }\n\n    var arr = glyphs.slice(start, end);\n    arr.sort(function (a, b) {\n      return a.shaperInfo.position - b.shaperInfo.position;\n    });\n    glyphs.splice.apply(glyphs, [start, arr.length].concat(arr));\n\n    // Find base again\n    for (var _i13 = start; _i13 < end; _i13++) {\n      if (glyphs[_i13].shaperInfo.position === POSITIONS.Base_C) {\n        base = _i13;\n        break;\n      }\n    }\n\n    // Setup features now\n\n    // Reph\n    for (var _i14 = start; _i14 < end && glyphs[_i14].shaperInfo.position === POSITIONS.Ra_To_Become_Reph; _i14++) {\n      glyphs[_i14].features.rphf = true;\n    }\n\n    // Pre-base\n    var blwf = !plan.isOldSpec && indicConfig.blwfMode === 'Pre_And_Post';\n    for (var _i15 = start; _i15 < base; _i15++) {\n      glyphs[_i15].features.half = true;\n      if (blwf) {\n        glyphs[_i15].features.blwf = true;\n      }\n    }\n\n    // Post-base\n    for (var _i16 = base + 1; _i16 < end; _i16++) {\n      glyphs[_i16].features.abvf = true;\n      glyphs[_i16].features.pstf = true;\n      glyphs[_i16].features.blwf = true;\n    }\n\n    if (plan.isOldSpec && plan.unicodeScript === 'Devanagari') {\n      // Old-spec eye-lash Ra needs special handling.  From the\n      // spec:\n      //\n      // \"The feature 'below-base form' is applied to consonants\n      // having below-base forms and following the base consonant.\n      // The exception is vattu, which may appear below half forms\n      // as well as below the base glyph. The feature 'below-base\n      // form' will be applied to all such occurrences of Ra as well.\"\n      //\n      // Test case: U+0924,U+094D,U+0930,U+094d,U+0915\n      // with Sanskrit 2003 font.\n      //\n      // However, note that Ra,Halant,ZWJ is the correct way to\n      // request eyelash form of Ra, so we wouldbn't inhibit it\n      // in that sequence.\n      //\n      // Test case: U+0924,U+094D,U+0930,U+094d,U+200D,U+0915\n      for (var _i17 = start; _i17 + 1 < base; _i17++) {\n        if (glyphs[_i17].shaperInfo.category === CATEGORIES.Ra && glyphs[_i17 + 1].shaperInfo.category === CATEGORIES.H && (_i17 + 1 === base || glyphs[_i17 + 2].shaperInfo.category === CATEGORIES.ZWJ)) {\n          glyphs[_i17].features.blwf = true;\n          glyphs[_i17 + 1].features.blwf = true;\n        }\n      }\n    }\n\n    var prefLen = 2;\n    if (features.pref && base + prefLen < end) {\n      // Find a Halant,Ra sequence and mark it for pre-base reordering processing.\n      for (var _i18 = base + 1; _i18 + prefLen - 1 < end; _i18++) {\n        var _g2 = [glyphs[_i18].copy(), glyphs[_i18 + 1].copy()];\n        if (wouldSubstitute(_g2, 'pref')) {\n          for (var _j4 = 0; _j4 < prefLen; _j4++) {\n            glyphs[_i18++].features.pref = true;\n          }\n\n          // Mark the subsequent stuff with 'cfar'.  Used in Khmer.\n          // Read the feature spec.\n          // This allows distinguishing the following cases with MS Khmer fonts:\n          // U+1784,U+17D2,U+179A,U+17D2,U+1782\n          // U+1784,U+17D2,U+1782,U+17D2,U+179A\n          if (features.cfar) {\n            for (; _i18 < end; _i18++) {\n              glyphs[_i18].features.cfar = true;\n            }\n          }\n\n          break;\n        }\n      }\n    }\n\n    // Apply ZWJ/ZWNJ effects\n    for (var _i19 = start + 1; _i19 < end; _i19++) {\n      if (isJoiner(glyphs[_i19])) {\n        var nonJoiner = glyphs[_i19].shaperInfo.category === CATEGORIES.ZWNJ;\n        var _j5 = _i19;\n\n        do {\n          _j5--;\n\n          // ZWJ/ZWNJ should disable CJCT.  They do that by simply\n          // being there, since we don't skip them for the CJCT\n          // feature (ie. F_MANUAL_ZWJ)\n\n          // A ZWNJ disables HALF.\n          if (nonJoiner) {\n            delete glyphs[_j5].features.half;\n          }\n        } while (_j5 > start && !isConsonant(glyphs[_j5]));\n      }\n    }\n  }\n}\n\nfunction finalReordering(font, glyphs, plan) {\n  var indicConfig = plan.indicConfig;\n  var features = font._layoutEngine.engine.GSUBProcessor.features;\n\n  for (var start = 0, end = nextSyllable(glyphs, 0); start < glyphs.length; start = end, end = nextSyllable(glyphs, start)) {\n    // 4. Final reordering:\n    //\n    // After the localized forms and basic shaping forms GSUB features have been\n    // applied (see below), the shaping engine performs some final glyph\n    // reordering before applying all the remaining font features to the entire\n    // cluster.\n\n    var tryPref = !!features.pref;\n\n    // Find base again\n    var base = start;\n    for (; base < end; base++) {\n      if (glyphs[base].shaperInfo.position >= POSITIONS.Base_C) {\n        if (tryPref && base + 1 < end) {\n          for (var i = base + 1; i < end; i++) {\n            if (glyphs[i].features.pref) {\n              if (!(glyphs[i].substituted && glyphs[i].isLigated && !glyphs[i].isMultiplied)) {\n                // Ok, this was a 'pref' candidate but didn't form any.\n                // Base is around here...\n                base = i;\n                while (base < end && isHalantOrCoeng(glyphs[base])) {\n                  base++;\n                }\n                glyphs[base].shaperInfo.position = POSITIONS.BASE_C;\n                tryPref = false;\n              }\n              break;\n            }\n          }\n        }\n\n        // For Malayalam, skip over unformed below- (but NOT post-) forms.\n        if (plan.unicodeScript === 'Malayalam') {\n          for (var _i20 = base + 1; _i20 < end; _i20++) {\n            while (_i20 < end && isJoiner(glyphs[_i20])) {\n              _i20++;\n            }\n\n            if (_i20 === end || !isHalantOrCoeng(glyphs[_i20])) {\n              break;\n            }\n\n            _i20++; // Skip halant.\n            while (_i20 < end && isJoiner(glyphs[_i20])) {\n              _i20++;\n            }\n\n            if (_i20 < end && isConsonant(glyphs[_i20]) && glyphs[_i20].shaperInfo.position === POSITIONS.Below_C) {\n              base = _i20;\n              glyphs[base].shaperInfo.position = POSITIONS.Base_C;\n            }\n          }\n        }\n\n        if (start < base && glyphs[base].shaperInfo.position > POSITIONS.Base_C) {\n          base--;\n        }\n        break;\n      }\n    }\n\n    if (base === end && start < base && glyphs[base - 1].shaperInfo.category === CATEGORIES.ZWJ) {\n      base--;\n    }\n\n    if (base < end) {\n      while (start < base && glyphs[base].shaperInfo.category & (CATEGORIES.N | HALANT_OR_COENG_FLAGS)) {\n        base--;\n      }\n    }\n\n    // o Reorder matras:\n    //\n    // If a pre-base matra character had been reordered before applying basic\n    // features, the glyph can be moved closer to the main consonant based on\n    // whether half-forms had been formed. Actual position for the matra is\n    // defined as “after last standalone halant glyph, after initial matra\n    // position and before the main consonant”. If ZWJ or ZWNJ follow this\n    // halant, position is moved after it.\n    //\n\n    if (start + 1 < end && start < base) {\n      // Otherwise there can't be any pre-base matra characters.\n      // If we lost track of base, alas, position before last thingy.\n      var newPos = base === end ? base - 2 : base - 1;\n\n      // Malayalam / Tamil do not have \"half\" forms or explicit virama forms.\n      // The glyphs formed by 'half' are Chillus or ligated explicit viramas.\n      // We want to position matra after them.\n      if (plan.unicodeScript !== 'Malayalam' && plan.unicodeScript !== 'Tamil') {\n        while (newPos > start && !(glyphs[newPos].shaperInfo.category & (CATEGORIES.M | HALANT_OR_COENG_FLAGS))) {\n          newPos--;\n        }\n\n        // If we found no Halant we are done.\n        // Otherwise only proceed if the Halant does\n        // not belong to the Matra itself!\n        if (isHalantOrCoeng(glyphs[newPos]) && glyphs[newPos].shaperInfo.position !== POSITIONS.Pre_M) {\n          // If ZWJ or ZWNJ follow this halant, position is moved after it.\n          if (newPos + 1 < end && isJoiner(glyphs[newPos + 1])) {\n            newPos++;\n          }\n        } else {\n          newPos = start; // No move.\n        }\n      }\n\n      if (start < newPos && glyphs[newPos].shaperInfo.position !== POSITIONS.Pre_M) {\n        // Now go see if there's actually any matras...\n        for (var _i21 = newPos; _i21 > start; _i21--) {\n          if (glyphs[_i21 - 1].shaperInfo.position === POSITIONS.Pre_M) {\n            var oldPos = _i21 - 1;\n            if (oldPos < base && base <= newPos) {\n              // Shouldn't actually happen.\n              base--;\n            }\n\n            var tmp = glyphs[oldPos];\n            glyphs.splice.apply(glyphs, [oldPos, 0].concat(glyphs.splice(oldPos + 1, newPos - oldPos)));\n            glyphs[newPos] = tmp;\n\n            newPos--;\n          }\n        }\n      }\n    }\n\n    // o Reorder reph:\n    //\n    // Reph’s original position is always at the beginning of the syllable,\n    // (i.e. it is not reordered at the character reordering stage). However,\n    // it will be reordered according to the basic-forms shaping results.\n    // Possible positions for reph, depending on the script, are; after main,\n    // before post-base consonant forms, and after post-base consonant forms.\n\n    // Two cases:\n    //\n    // - If repha is encoded as a sequence of characters (Ra,H or Ra,H,ZWJ), then\n    //   we should only move it if the sequence ligated to the repha form.\n    //\n    // - If repha is encoded separately and in the logical position, we should only\n    //   move it if it did NOT ligate.  If it ligated, it's probably the font trying\n    //   to make it work without the reordering.\n    if (start + 1 < end && glyphs[start].shaperInfo.position === POSITIONS.Ra_To_Become_Reph && glyphs[start].shaperInfo.category === CATEGORIES.Repha !== (glyphs[start].isLigated && !glyphs[start].isMultiplied)) {\n      var newRephPos = void 0;\n      var rephPos = indicConfig.rephPos;\n      var found = false;\n\n      // 1. If reph should be positioned after post-base consonant forms,\n      //    proceed to step 5.\n      if (rephPos !== POSITIONS.After_Post) {\n        //  2. If the reph repositioning class is not after post-base: target\n        //     position is after the first explicit halant glyph between the\n        //     first post-reph consonant and last main consonant. If ZWJ or ZWNJ\n        //     are following this halant, position is moved after it. If such\n        //     position is found, this is the target position. Otherwise,\n        //     proceed to the next step.\n        //\n        //     Note: in old-implementation fonts, where classifications were\n        //     fixed in shaping engine, there was no case where reph position\n        //     will be found on this step.\n        newRephPos = start + 1;\n        while (newRephPos < base && !isHalantOrCoeng(glyphs[newRephPos])) {\n          newRephPos++;\n        }\n\n        if (newRephPos < base && isHalantOrCoeng(glyphs[newRephPos])) {\n          // ->If ZWJ or ZWNJ are following this halant, position is moved after it.\n          if (newRephPos + 1 < base && isJoiner(glyphs[newRephPos + 1])) {\n            newRephPos++;\n          }\n\n          found = true;\n        }\n\n        // 3. If reph should be repositioned after the main consonant: find the\n        //    first consonant not ligated with main, or find the first\n        //    consonant that is not a potential pre-base reordering Ra.\n        if (!found && rephPos === POSITIONS.After_Main) {\n          newRephPos = base;\n          while (newRephPos + 1 < end && glyphs[newRephPos + 1].shaperInfo.position <= POSITIONS.After_Main) {\n            newRephPos++;\n          }\n\n          found = newRephPos < end;\n        }\n\n        // 4. If reph should be positioned before post-base consonant, find\n        //    first post-base classified consonant not ligated with main. If no\n        //    consonant is found, the target position should be before the\n        //    first matra, syllable modifier sign or vedic sign.\n        //\n        // This is our take on what step 4 is trying to say (and failing, BADLY).\n        if (!found && rephPos === POSITIONS.After_Sub) {\n          newRephPos = base;\n          while (newRephPos + 1 < end && !(glyphs[newRephPos + 1].shaperInfo.position & (POSITIONS.Post_C | POSITIONS.After_Post | POSITIONS.SMVD))) {\n            newRephPos++;\n          }\n\n          found = newRephPos < end;\n        }\n      }\n\n      //  5. If no consonant is found in steps 3 or 4, move reph to a position\n      //     immediately before the first post-base matra, syllable modifier\n      //     sign or vedic sign that has a reordering class after the intended\n      //     reph position. For example, if the reordering position for reph\n      //     is post-main, it will skip above-base matras that also have a\n      //     post-main position.\n      if (!found) {\n        // Copied from step 2.\n        newRephPos = start + 1;\n        while (newRephPos < base && !isHalantOrCoeng(glyphs[newRephPos])) {\n          newRephPos++;\n        }\n\n        if (newRephPos < base && isHalantOrCoeng(glyphs[newRephPos])) {\n          // ->If ZWJ or ZWNJ are following this halant, position is moved after it.\n          if (newRephPos + 1 < base && isJoiner(glyphs[newRephPos + 1])) {\n            newRephPos++;\n          }\n\n          found = true;\n        }\n      }\n\n      // 6. Otherwise, reorder reph to the end of the syllable.\n      if (!found) {\n        newRephPos = end - 1;\n        while (newRephPos > start && glyphs[newRephPos].shaperInfo.position === POSITIONS.SMVD) {\n          newRephPos--;\n        }\n\n        // If the Reph is to be ending up after a Matra,Halant sequence,\n        // position it before that Halant so it can interact with the Matra.\n        // However, if it's a plain Consonant,Halant we shouldn't do that.\n        // Uniscribe doesn't do this.\n        // TEST: U+0930,U+094D,U+0915,U+094B,U+094D\n        if (isHalantOrCoeng(glyphs[newRephPos])) {\n          for (var _i22 = base + 1; _i22 < newRephPos; _i22++) {\n            if (glyphs[_i22].shaperInfo.category === CATEGORIES.M) {\n              newRephPos--;\n            }\n          }\n        }\n      }\n\n      var reph = glyphs[start];\n      glyphs.splice.apply(glyphs, [start, 0].concat(glyphs.splice(start + 1, newRephPos - start)));\n      glyphs[newRephPos] = reph;\n\n      if (start < base && base <= newRephPos) {\n        base--;\n      }\n    }\n\n    // o Reorder pre-base reordering consonants:\n    //\n    // If a pre-base reordering consonant is found, reorder it according to\n    // the following rules:\n    if (tryPref && base + 1 < end) {\n      for (var _i23 = base + 1; _i23 < end; _i23++) {\n        if (glyphs[_i23].features.pref) {\n          // 1. Only reorder a glyph produced by substitution during application\n          //    of the <pref> feature. (Note that a font may shape a Ra consonant with\n          //    the feature generally but block it in certain contexts.)\n\n          // Note: We just check that something got substituted.  We don't check that\n          // the <pref> feature actually did it...\n          //\n          // Reorder pref only if it ligated.\n          if (glyphs[_i23].isLigated && !glyphs[_i23].isMultiplied) {\n            // 2. Try to find a target position the same way as for pre-base matra.\n            //    If it is found, reorder pre-base consonant glyph.\n            //\n            // 3. If position is not found, reorder immediately before main\n            //    consonant.\n            var _newPos = base;\n\n            // Malayalam / Tamil do not have \"half\" forms or explicit virama forms.\n            // The glyphs formed by 'half' are Chillus or ligated explicit viramas.\n            // We want to position matra after them.\n            if (plan.unicodeScript !== 'Malayalam' && plan.unicodeScript !== 'Tamil') {\n              while (_newPos > start && !(glyphs[_newPos - 1].shaperInfo.category & (CATEGORIES.M | HALANT_OR_COENG_FLAGS))) {\n                _newPos--;\n              }\n\n              // In Khmer coeng model, a H,Ra can go *after* matras.  If it goes after a\n              // split matra, it should be reordered to *before* the left part of such matra.\n              if (_newPos > start && glyphs[_newPos - 1].shaperInfo.category === CATEGORIES.M) {\n                var _oldPos2 = _i23;\n                for (var j = base + 1; j < _oldPos2; j++) {\n                  if (glyphs[j].shaperInfo.category === CATEGORIES.M) {\n                    _newPos--;\n                    break;\n                  }\n                }\n              }\n            }\n\n            if (_newPos > start && isHalantOrCoeng(glyphs[_newPos - 1])) {\n              // -> If ZWJ or ZWNJ follow this halant, position is moved after it.\n              if (_newPos < end && isJoiner(glyphs[_newPos])) {\n                _newPos++;\n              }\n            }\n\n            var _oldPos = _i23;\n            var _tmp = glyphs[_oldPos];\n            glyphs.splice.apply(glyphs, [_newPos + 1, 0].concat(glyphs.splice(_newPos, _oldPos - _newPos)));\n            glyphs[_newPos] = _tmp;\n\n            if (_newPos <= base && base < _oldPos) {\n              base++;\n            }\n          }\n\n          break;\n        }\n      }\n    }\n\n    // Apply 'init' to the Left Matra if it's a word start.\n    if (glyphs[start].shaperInfo.position === POSITIONS.Pre_M && (!start || !/Cf|Mn/.test(unicode.getCategory(glyphs[start - 1].codePoints[0])))) {\n      glyphs[start].features.init = true;\n    }\n  }\n}\n\nfunction nextSyllable(glyphs, start) {\n  if (start >= glyphs.length) return start;\n  var syllable = glyphs[start].shaperInfo.syllable;\n  while (++start < glyphs.length && glyphs[start].shaperInfo.syllable === syllable) {}\n  return start;\n}\n\nvar _class$7;\nvar _temp$3;\nvar categories$1 = useData.categories;\nvar decompositions$2 = useData.decompositions;\nvar trie$2 = new UnicodeTrie(Buffer(\"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\",\"base64\"));\nvar stateMachine$1 = new StateMachine(useData);\n\n/**\n * This shaper is an implementation of the Universal Shaping Engine, which\n * uses Unicode data to shape a number of scripts without a dedicated shaping engine.\n * See https://www.microsoft.com/typography/OpenTypeDev/USE/intro.htm.\n */\nvar UniversalShaper = (_temp$3 = _class$7 = function (_DefaultShaper) {\n  _inherits(UniversalShaper, _DefaultShaper);\n\n  function UniversalShaper() {\n    _classCallCheck(this, UniversalShaper);\n\n    return _possibleConstructorReturn(this, _DefaultShaper.apply(this, arguments));\n  }\n\n  UniversalShaper.planFeatures = function planFeatures(plan) {\n    plan.addStage(setupSyllables$1);\n\n    // Default glyph pre-processing group\n    plan.addStage(['locl', 'ccmp', 'nukt', 'akhn']);\n\n    // Reordering group\n    plan.addStage(clearSubstitutionFlags);\n    plan.addStage(['rphf'], false);\n    plan.addStage(recordRphf);\n    plan.addStage(clearSubstitutionFlags);\n    plan.addStage(['pref']);\n    plan.addStage(recordPref);\n\n    // Orthographic unit shaping group\n    plan.addStage(['rkrf', 'abvf', 'blwf', 'half', 'pstf', 'vatu', 'cjct']);\n    plan.addStage(reorder);\n\n    // Topographical features\n    // Scripts that need this are handled by the Arabic shaper, not implemented here for now.\n    // plan.addStage(['isol', 'init', 'medi', 'fina', 'med2', 'fin2', 'fin3'], false);\n\n    // Standard topographic presentation and positional feature application\n    plan.addStage(['abvs', 'blws', 'pres', 'psts', 'dist', 'abvm', 'blwm']);\n  };\n\n  UniversalShaper.assignFeatures = function assignFeatures(plan, glyphs) {\n    var _loop = function _loop(i) {\n      var codepoint = glyphs[i].codePoints[0];\n      if (decompositions$2[codepoint]) {\n        var decomposed = decompositions$2[codepoint].map(function (c) {\n          var g = plan.font.glyphForCodePoint(c);\n          return new GlyphInfo(plan.font, g.id, [c], glyphs[i].features);\n        });\n\n        glyphs.splice.apply(glyphs, [i, 1].concat(decomposed));\n      }\n    };\n\n    // Decompose split vowels\n    // TODO: do this in a more general unicode normalizer\n    for (var i = glyphs.length - 1; i >= 0; i--) {\n      _loop(i);\n    }\n  };\n\n  return UniversalShaper;\n}(DefaultShaper), _class$7.zeroMarkWidths = 'BEFORE_GPOS', _temp$3);\nfunction useCategory(glyph) {\n  return trie$2.get(glyph.codePoints[0]);\n}\n\nvar USEInfo = function USEInfo(category, syllableType, syllable) {\n  _classCallCheck(this, USEInfo);\n\n  this.category = category;\n  this.syllableType = syllableType;\n  this.syllable = syllable;\n};\n\nfunction setupSyllables$1(font, glyphs) {\n  var syllable = 0;\n  for (var _iterator = stateMachine$1.match(glyphs.map(useCategory)), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n    var _ref;\n\n    if (_isArray) {\n      if (_i >= _iterator.length) break;\n      _ref = _iterator[_i++];\n    } else {\n      _i = _iterator.next();\n      if (_i.done) break;\n      _ref = _i.value;\n    }\n\n    var _ref2 = _ref,\n        start = _ref2[0],\n        end = _ref2[1],\n        tags = _ref2[2];\n\n    ++syllable;\n\n    // Create shaper info\n    for (var i = start; i <= end; i++) {\n      glyphs[i].shaperInfo = new USEInfo(categories$1[useCategory(glyphs[i])], tags[0], syllable);\n    }\n\n    // Assign rphf feature\n    var limit = glyphs[start].shaperInfo.category === 'R' ? 1 : Math.min(3, end - start);\n    for (var _i2 = start; _i2 < start + limit; _i2++) {\n      glyphs[_i2].features.rphf = true;\n    }\n  }\n}\n\nfunction clearSubstitutionFlags(font, glyphs) {\n  for (var _iterator2 = glyphs, _isArray2 = Array.isArray(_iterator2), _i3 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n    var _ref3;\n\n    if (_isArray2) {\n      if (_i3 >= _iterator2.length) break;\n      _ref3 = _iterator2[_i3++];\n    } else {\n      _i3 = _iterator2.next();\n      if (_i3.done) break;\n      _ref3 = _i3.value;\n    }\n\n    var glyph = _ref3;\n\n    glyph.substituted = false;\n  }\n}\n\nfunction recordRphf(font, glyphs) {\n  for (var _iterator3 = glyphs, _isArray3 = Array.isArray(_iterator3), _i4 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n    var _ref4;\n\n    if (_isArray3) {\n      if (_i4 >= _iterator3.length) break;\n      _ref4 = _iterator3[_i4++];\n    } else {\n      _i4 = _iterator3.next();\n      if (_i4.done) break;\n      _ref4 = _i4.value;\n    }\n\n    var glyph = _ref4;\n\n    if (glyph.substituted && glyph.features.rphf) {\n      // Mark a substituted repha.\n      glyph.shaperInfo.category = 'R';\n    }\n  }\n}\n\nfunction recordPref(font, glyphs) {\n  for (var _iterator4 = glyphs, _isArray4 = Array.isArray(_iterator4), _i5 = 0, _iterator4 = _isArray4 ? _iterator4 : _getIterator(_iterator4);;) {\n    var _ref5;\n\n    if (_isArray4) {\n      if (_i5 >= _iterator4.length) break;\n      _ref5 = _iterator4[_i5++];\n    } else {\n      _i5 = _iterator4.next();\n      if (_i5.done) break;\n      _ref5 = _i5.value;\n    }\n\n    var glyph = _ref5;\n\n    if (glyph.substituted) {\n      // Mark a substituted pref as VPre, as they behave the same way.\n      glyph.shaperInfo.category = 'VPre';\n    }\n  }\n}\n\nfunction reorder(font, glyphs) {\n  var dottedCircle = font.glyphForCodePoint(0x25cc).id;\n\n  for (var start = 0, end = nextSyllable$1(glyphs, 0); start < glyphs.length; start = end, end = nextSyllable$1(glyphs, start)) {\n    var i = void 0,\n        j = void 0;\n    var info = glyphs[start].shaperInfo;\n    var type = info.syllableType;\n\n    // Only a few syllable types need reordering.\n    if (type !== 'virama_terminated_cluster' && type !== 'standard_cluster' && type !== 'broken_cluster') {\n      continue;\n    }\n\n    // Insert a dotted circle glyph in broken clusters.\n    if (type === 'broken_cluster' && dottedCircle) {\n      var g = new GlyphInfo(font, dottedCircle, [0x25cc]);\n      g.shaperInfo = info;\n\n      // Insert after possible Repha.\n      for (i = start; i < end && glyphs[i].shaperInfo.category === 'R'; i++) {}\n      glyphs.splice(++i, 0, g);\n      end++;\n    }\n\n    // Move things forward.\n    if (info.category === 'R' && end - start > 1) {\n      // Got a repha. Reorder it to after first base, before first halant.\n      for (i = start + 1; i < end; i++) {\n        info = glyphs[i].shaperInfo;\n        if (isBase(info) || isHalant(glyphs[i])) {\n          // If we hit a halant, move before it; otherwise it's a base: move to it's\n          // place, and shift things in between backward.\n          if (isHalant(glyphs[i])) {\n            i--;\n          }\n\n          glyphs.splice.apply(glyphs, [start, 0].concat(glyphs.splice(start + 1, i - start), [glyphs[i]]));\n          break;\n        }\n      }\n    }\n\n    // Move things back.\n    for (i = start, j = end; i < end; i++) {\n      info = glyphs[i].shaperInfo;\n      if (isBase(info) || isHalant(glyphs[i])) {\n        // If we hit a halant, move after it; otherwise it's a base: move to it's\n        // place, and shift things in between backward.\n        j = isHalant(glyphs[i]) ? i + 1 : i;\n      } else if ((info.category === 'VPre' || info.category === 'VMPre') && j < i) {\n        glyphs.splice.apply(glyphs, [j, 1, glyphs[i]].concat(glyphs.splice(j, i - j)));\n      }\n    }\n  }\n}\n\nfunction nextSyllable$1(glyphs, start) {\n  if (start >= glyphs.length) return start;\n  var syllable = glyphs[start].shaperInfo.syllable;\n  while (++start < glyphs.length && glyphs[start].shaperInfo.syllable === syllable) {}\n  return start;\n}\n\nfunction isHalant(glyph) {\n  return glyph.shaperInfo.category === 'H' && !glyph.isLigated;\n}\n\nfunction isBase(info) {\n  return info.category === 'B' || info.category === 'GB';\n}\n\nvar SHAPERS = {\n  arab: ArabicShaper, // Arabic\n  mong: ArabicShaper, // Mongolian\n  syrc: ArabicShaper, // Syriac\n  'nko ': ArabicShaper, // N'Ko\n  phag: ArabicShaper, // Phags Pa\n  mand: ArabicShaper, // Mandaic\n  mani: ArabicShaper, // Manichaean\n  phlp: ArabicShaper, // Psalter Pahlavi\n\n  hang: HangulShaper, // Hangul\n\n  bng2: IndicShaper, // Bengali\n  beng: IndicShaper, // Bengali\n  dev2: IndicShaper, // Devanagari\n  deva: IndicShaper, // Devanagari\n  gjr2: IndicShaper, // Gujarati\n  gujr: IndicShaper, // Gujarati\n  guru: IndicShaper, // Gurmukhi\n  gur2: IndicShaper, // Gurmukhi\n  knda: IndicShaper, // Kannada\n  knd2: IndicShaper, // Kannada\n  mlm2: IndicShaper, // Malayalam\n  mlym: IndicShaper, // Malayalam\n  ory2: IndicShaper, // Oriya\n  orya: IndicShaper, // Oriya\n  taml: IndicShaper, // Tamil\n  tml2: IndicShaper, // Tamil\n  telu: IndicShaper, // Telugu\n  tel2: IndicShaper, // Telugu\n  khmr: IndicShaper, // Khmer\n\n  bali: UniversalShaper, // Balinese\n  batk: UniversalShaper, // Batak\n  brah: UniversalShaper, // Brahmi\n  bugi: UniversalShaper, // Buginese\n  buhd: UniversalShaper, // Buhid\n  cakm: UniversalShaper, // Chakma\n  cham: UniversalShaper, // Cham\n  dupl: UniversalShaper, // Duployan\n  egyp: UniversalShaper, // Egyptian Hieroglyphs\n  gran: UniversalShaper, // Grantha\n  hano: UniversalShaper, // Hanunoo\n  java: UniversalShaper, // Javanese\n  kthi: UniversalShaper, // Kaithi\n  kali: UniversalShaper, // Kayah Li\n  khar: UniversalShaper, // Kharoshthi\n  khoj: UniversalShaper, // Khojki\n  sind: UniversalShaper, // Khudawadi\n  lepc: UniversalShaper, // Lepcha\n  limb: UniversalShaper, // Limbu\n  mahj: UniversalShaper, // Mahajani\n  // mand: UniversalShaper, // Mandaic\n  // mani: UniversalShaper, // Manichaean\n  mtei: UniversalShaper, // Meitei Mayek\n  modi: UniversalShaper, // Modi\n  // mong: UniversalShaper, // Mongolian\n  // 'nko ': UniversalShaper, // N’Ko\n  hmng: UniversalShaper, // Pahawh Hmong\n  // phag: UniversalShaper, // Phags-pa\n  // phlp: UniversalShaper, // Psalter Pahlavi\n  rjng: UniversalShaper, // Rejang\n  saur: UniversalShaper, // Saurashtra\n  shrd: UniversalShaper, // Sharada\n  sidd: UniversalShaper, // Siddham\n  sinh: UniversalShaper, // Sinhala\n  sund: UniversalShaper, // Sundanese\n  sylo: UniversalShaper, // Syloti Nagri\n  tglg: UniversalShaper, // Tagalog\n  tagb: UniversalShaper, // Tagbanwa\n  tale: UniversalShaper, // Tai Le\n  lana: UniversalShaper, // Tai Tham\n  tavt: UniversalShaper, // Tai Viet\n  takr: UniversalShaper, // Takri\n  tibt: UniversalShaper, // Tibetan\n  tfng: UniversalShaper, // Tifinagh\n  tirh: UniversalShaper, // Tirhuta\n\n  latn: DefaultShaper, // Latin\n  DFLT: DefaultShaper // Default\n};\n\nfunction choose(script) {\n  if (!Array.isArray(script)) {\n    script = [script];\n  }\n\n  for (var _iterator = script, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n    var _ref;\n\n    if (_isArray) {\n      if (_i >= _iterator.length) break;\n      _ref = _iterator[_i++];\n    } else {\n      _i = _iterator.next();\n      if (_i.done) break;\n      _ref = _i.value;\n    }\n\n    var s = _ref;\n\n    var shaper = SHAPERS[s];\n    if (shaper) {\n      return shaper;\n    }\n  }\n\n  return DefaultShaper;\n}\n\nvar GSUBProcessor = function (_OTProcessor) {\n  _inherits(GSUBProcessor, _OTProcessor);\n\n  function GSUBProcessor() {\n    _classCallCheck(this, GSUBProcessor);\n\n    return _possibleConstructorReturn(this, _OTProcessor.apply(this, arguments));\n  }\n\n  GSUBProcessor.prototype.applyLookup = function applyLookup(lookupType, table) {\n    var _this2 = this;\n\n    switch (lookupType) {\n      case 1:\n        {\n          // Single Substitution\n          var index = this.coverageIndex(table.coverage);\n          if (index === -1) {\n            return false;\n          }\n\n          var glyph = this.glyphIterator.cur;\n          switch (table.version) {\n            case 1:\n              glyph.id = glyph.id + table.deltaGlyphID & 0xffff;\n              break;\n\n            case 2:\n              glyph.id = table.substitute.get(index);\n              break;\n          }\n\n          return true;\n        }\n\n      case 2:\n        {\n          // Multiple Substitution\n          var _index = this.coverageIndex(table.coverage);\n          if (_index !== -1) {\n            var _glyphs;\n\n            var sequence = table.sequences.get(_index);\n            this.glyphIterator.cur.id = sequence[0];\n            this.glyphIterator.cur.ligatureComponent = 0;\n\n            var features = this.glyphIterator.cur.features;\n            var curGlyph = this.glyphIterator.cur;\n            var replacement = sequence.slice(1).map(function (gid, i) {\n              var glyph = new GlyphInfo(_this2.font, gid, undefined, features);\n              glyph.shaperInfo = curGlyph.shaperInfo;\n              glyph.isLigated = curGlyph.isLigated;\n              glyph.ligatureComponent = i + 1;\n              glyph.substituted = true;\n              glyph.isMultiplied = true;\n              return glyph;\n            });\n\n            (_glyphs = this.glyphs).splice.apply(_glyphs, [this.glyphIterator.index + 1, 0].concat(replacement));\n            return true;\n          }\n\n          return false;\n        }\n\n      case 3:\n        {\n          // Alternate Substitution\n          var _index2 = this.coverageIndex(table.coverage);\n          if (_index2 !== -1) {\n            var USER_INDEX = 0; // TODO\n            this.glyphIterator.cur.id = table.alternateSet.get(_index2)[USER_INDEX];\n            return true;\n          }\n\n          return false;\n        }\n\n      case 4:\n        {\n          // Ligature Substitution\n          var _index3 = this.coverageIndex(table.coverage);\n          if (_index3 === -1) {\n            return false;\n          }\n\n          for (var _iterator = table.ligatureSets.get(_index3), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n            var _ref;\n\n            if (_isArray) {\n              if (_i >= _iterator.length) break;\n              _ref = _iterator[_i++];\n            } else {\n              _i = _iterator.next();\n              if (_i.done) break;\n              _ref = _i.value;\n            }\n\n            var ligature = _ref;\n\n            var matched = this.sequenceMatchIndices(1, ligature.components);\n            if (!matched) {\n              continue;\n            }\n\n            var _curGlyph = this.glyphIterator.cur;\n\n            // Concatenate all of the characters the new ligature will represent\n            var characters = _curGlyph.codePoints.slice();\n            for (var _iterator2 = matched, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n              var _ref2;\n\n              if (_isArray2) {\n                if (_i2 >= _iterator2.length) break;\n                _ref2 = _iterator2[_i2++];\n              } else {\n                _i2 = _iterator2.next();\n                if (_i2.done) break;\n                _ref2 = _i2.value;\n              }\n\n              var _index4 = _ref2;\n\n              characters.push.apply(characters, this.glyphs[_index4].codePoints);\n            }\n\n            // Create the replacement ligature glyph\n            var ligatureGlyph = new GlyphInfo(this.font, ligature.glyph, characters, _curGlyph.features);\n            ligatureGlyph.shaperInfo = _curGlyph.shaperInfo;\n            ligatureGlyph.isLigated = true;\n            ligatureGlyph.substituted = true;\n\n            // From Harfbuzz:\n            // - If it *is* a mark ligature, we don't allocate a new ligature id, and leave\n            //   the ligature to keep its old ligature id.  This will allow it to attach to\n            //   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,\n            //   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a\n            //   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature\n            //   later, we don't want them to lose their ligature id/component, otherwise\n            //   GPOS will fail to correctly position the mark ligature on top of the\n            //   LAM,LAM,HEH ligature. See https://bugzilla.gnome.org/show_bug.cgi?id=676343\n            //\n            // - If a ligature is formed of components that some of which are also ligatures\n            //   themselves, and those ligature components had marks attached to *their*\n            //   components, we have to attach the marks to the new ligature component\n            //   positions!  Now *that*'s tricky!  And these marks may be following the\n            //   last component of the whole sequence, so we should loop forward looking\n            //   for them and update them.\n            //\n            //   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a\n            //   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature\n            //   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature\n            //   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to\n            //   the new ligature with a component value of 2.\n            //\n            //   This in fact happened to a font...  See https://bugzilla.gnome.org/show_bug.cgi?id=437633\n            var isMarkLigature = _curGlyph.isMark;\n            for (var i = 0; i < matched.length && isMarkLigature; i++) {\n              isMarkLigature = this.glyphs[matched[i]].isMark;\n            }\n\n            ligatureGlyph.ligatureID = isMarkLigature ? null : this.ligatureID++;\n\n            var lastLigID = _curGlyph.ligatureID;\n            var lastNumComps = _curGlyph.codePoints.length;\n            var curComps = lastNumComps;\n            var idx = this.glyphIterator.index + 1;\n\n            // Set ligatureID and ligatureComponent on glyphs that were skipped in the matched sequence.\n            // This allows GPOS to attach marks to the correct ligature components.\n            for (var _iterator3 = matched, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n              var _ref3;\n\n              if (_isArray3) {\n                if (_i3 >= _iterator3.length) break;\n                _ref3 = _iterator3[_i3++];\n              } else {\n                _i3 = _iterator3.next();\n                if (_i3.done) break;\n                _ref3 = _i3.value;\n              }\n\n              var matchIndex = _ref3;\n\n              // Don't assign new ligature components for mark ligatures (see above)\n              if (isMarkLigature) {\n                idx = matchIndex;\n              } else {\n                while (idx < matchIndex) {\n                  var ligatureComponent = curComps - lastNumComps + Math.min(this.glyphs[idx].ligatureComponent || 1, lastNumComps);\n                  this.glyphs[idx].ligatureID = ligatureGlyph.ligatureID;\n                  this.glyphs[idx].ligatureComponent = ligatureComponent;\n                  idx++;\n                }\n              }\n\n              lastLigID = this.glyphs[idx].ligatureID;\n              lastNumComps = this.glyphs[idx].codePoints.length;\n              curComps += lastNumComps;\n              idx++; // skip base glyph\n            }\n\n            // Adjust ligature components for any marks following\n            if (lastLigID && !isMarkLigature) {\n              for (var _i4 = idx; _i4 < this.glyphs.length; _i4++) {\n                if (this.glyphs[_i4].ligatureID === lastLigID) {\n                  var ligatureComponent = curComps - lastNumComps + Math.min(this.glyphs[_i4].ligatureComponent || 1, lastNumComps);\n                  this.glyphs[_i4].ligatureComponent = ligatureComponent;\n                } else {\n                  break;\n                }\n              }\n            }\n\n            // Delete the matched glyphs, and replace the current glyph with the ligature glyph\n            for (var _i5 = matched.length - 1; _i5 >= 0; _i5--) {\n              this.glyphs.splice(matched[_i5], 1);\n            }\n\n            this.glyphs[this.glyphIterator.index] = ligatureGlyph;\n            return true;\n          }\n\n          return false;\n        }\n\n      case 5:\n        // Contextual Substitution\n        return this.applyContext(table);\n\n      case 6:\n        // Chaining Contextual Substitution\n        return this.applyChainingContext(table);\n\n      case 7:\n        // Extension Substitution\n        return this.applyLookup(table.lookupType, table.extension);\n\n      default:\n        throw new Error('GSUB lookupType ' + lookupType + ' is not supported');\n    }\n  };\n\n  return GSUBProcessor;\n}(OTProcessor);\n\nvar GPOSProcessor = function (_OTProcessor) {\n  _inherits(GPOSProcessor, _OTProcessor);\n\n  function GPOSProcessor() {\n    _classCallCheck(this, GPOSProcessor);\n\n    return _possibleConstructorReturn(this, _OTProcessor.apply(this, arguments));\n  }\n\n  GPOSProcessor.prototype.applyPositionValue = function applyPositionValue(sequenceIndex, value) {\n    var position = this.positions[this.glyphIterator.peekIndex(sequenceIndex)];\n    if (value.xAdvance != null) {\n      position.xAdvance += value.xAdvance;\n    }\n\n    if (value.yAdvance != null) {\n      position.yAdvance += value.yAdvance;\n    }\n\n    if (value.xPlacement != null) {\n      position.xOffset += value.xPlacement;\n    }\n\n    if (value.yPlacement != null) {\n      position.yOffset += value.yPlacement;\n    }\n\n    // Adjustments for font variations\n    var variationProcessor = this.font._variationProcessor;\n    var variationStore = this.font.GDEF && this.font.GDEF.itemVariationStore;\n    if (variationProcessor && variationStore) {\n      if (value.xPlaDevice) {\n        position.xOffset += variationProcessor.getDelta(variationStore, value.xPlaDevice.a, value.xPlaDevice.b);\n      }\n\n      if (value.yPlaDevice) {\n        position.yOffset += variationProcessor.getDelta(variationStore, value.yPlaDevice.a, value.yPlaDevice.b);\n      }\n\n      if (value.xAdvDevice) {\n        position.xAdvance += variationProcessor.getDelta(variationStore, value.xAdvDevice.a, value.xAdvDevice.b);\n      }\n\n      if (value.yAdvDevice) {\n        position.yAdvance += variationProcessor.getDelta(variationStore, value.yAdvDevice.a, value.yAdvDevice.b);\n      }\n    }\n\n    // TODO: device tables\n  };\n\n  GPOSProcessor.prototype.applyLookup = function applyLookup(lookupType, table) {\n    switch (lookupType) {\n      case 1:\n        {\n          // Single positioning value\n          var index = this.coverageIndex(table.coverage);\n          if (index === -1) {\n            return false;\n          }\n\n          switch (table.version) {\n            case 1:\n              this.applyPositionValue(0, table.value);\n              break;\n\n            case 2:\n              this.applyPositionValue(0, table.values.get(index));\n              break;\n          }\n\n          return true;\n        }\n\n      case 2:\n        {\n          // Pair Adjustment Positioning\n          var nextGlyph = this.glyphIterator.peek();\n          if (!nextGlyph) {\n            return false;\n          }\n\n          var _index = this.coverageIndex(table.coverage);\n          if (_index === -1) {\n            return false;\n          }\n\n          switch (table.version) {\n            case 1:\n              // Adjustments for glyph pairs\n              var set = table.pairSets.get(_index);\n\n              for (var _iterator = set, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n                var _ref;\n\n                if (_isArray) {\n                  if (_i >= _iterator.length) break;\n                  _ref = _iterator[_i++];\n                } else {\n                  _i = _iterator.next();\n                  if (_i.done) break;\n                  _ref = _i.value;\n                }\n\n                var _pair = _ref;\n\n                if (_pair.secondGlyph === nextGlyph.id) {\n                  this.applyPositionValue(0, _pair.value1);\n                  this.applyPositionValue(1, _pair.value2);\n                  return true;\n                }\n              }\n\n              return false;\n\n            case 2:\n              // Class pair adjustment\n              var class1 = this.getClassID(this.glyphIterator.cur.id, table.classDef1);\n              var class2 = this.getClassID(nextGlyph.id, table.classDef2);\n              if (class1 === -1 || class2 === -1) {\n                return false;\n              }\n\n              var pair = table.classRecords.get(class1).get(class2);\n              this.applyPositionValue(0, pair.value1);\n              this.applyPositionValue(1, pair.value2);\n              return true;\n          }\n        }\n\n      case 3:\n        {\n          // Cursive Attachment Positioning\n          var nextIndex = this.glyphIterator.peekIndex();\n          var _nextGlyph = this.glyphs[nextIndex];\n          if (!_nextGlyph) {\n            return false;\n          }\n\n          var curRecord = table.entryExitRecords[this.coverageIndex(table.coverage)];\n          if (!curRecord || !curRecord.exitAnchor) {\n            return false;\n          }\n\n          var nextRecord = table.entryExitRecords[this.coverageIndex(table.coverage, _nextGlyph.id)];\n          if (!nextRecord || !nextRecord.entryAnchor) {\n            return false;\n          }\n\n          var entry = this.getAnchor(nextRecord.entryAnchor);\n          var exit = this.getAnchor(curRecord.exitAnchor);\n\n          var cur = this.positions[this.glyphIterator.index];\n          var next = this.positions[nextIndex];\n\n          switch (this.direction) {\n            case 'ltr':\n              cur.xAdvance = exit.x + cur.xOffset;\n\n              var d = entry.x + next.xOffset;\n              next.xAdvance -= d;\n              next.xOffset -= d;\n              break;\n\n            case 'rtl':\n              d = exit.x + cur.xOffset;\n              cur.xAdvance -= d;\n              cur.xOffset -= d;\n              next.xAdvance = entry.x + next.xOffset;\n              break;\n          }\n\n          if (this.glyphIterator.flags.rightToLeft) {\n            this.glyphIterator.cur.cursiveAttachment = nextIndex;\n            cur.yOffset = entry.y - exit.y;\n          } else {\n            _nextGlyph.cursiveAttachment = this.glyphIterator.index;\n            cur.yOffset = exit.y - entry.y;\n          }\n\n          return true;\n        }\n\n      case 4:\n        {\n          // Mark to base positioning\n          var markIndex = this.coverageIndex(table.markCoverage);\n          if (markIndex === -1) {\n            return false;\n          }\n\n          // search backward for a base glyph\n          var baseGlyphIndex = this.glyphIterator.index;\n          while (--baseGlyphIndex >= 0 && (this.glyphs[baseGlyphIndex].isMark || this.glyphs[baseGlyphIndex].ligatureComponent > 0)) {}\n\n          if (baseGlyphIndex < 0) {\n            return false;\n          }\n\n          var baseIndex = this.coverageIndex(table.baseCoverage, this.glyphs[baseGlyphIndex].id);\n          if (baseIndex === -1) {\n            return false;\n          }\n\n          var markRecord = table.markArray[markIndex];\n          var baseAnchor = table.baseArray[baseIndex][markRecord.class];\n          this.applyAnchor(markRecord, baseAnchor, baseGlyphIndex);\n          return true;\n        }\n\n      case 5:\n        {\n          // Mark to ligature positioning\n          var _markIndex = this.coverageIndex(table.markCoverage);\n          if (_markIndex === -1) {\n            return false;\n          }\n\n          // search backward for a base glyph\n          var _baseGlyphIndex = this.glyphIterator.index;\n          while (--_baseGlyphIndex >= 0 && this.glyphs[_baseGlyphIndex].isMark) {}\n\n          if (_baseGlyphIndex < 0) {\n            return false;\n          }\n\n          var ligIndex = this.coverageIndex(table.ligatureCoverage, this.glyphs[_baseGlyphIndex].id);\n          if (ligIndex === -1) {\n            return false;\n          }\n\n          var ligAttach = table.ligatureArray[ligIndex];\n          var markGlyph = this.glyphIterator.cur;\n          var ligGlyph = this.glyphs[_baseGlyphIndex];\n          var compIndex = ligGlyph.ligatureID && ligGlyph.ligatureID === markGlyph.ligatureID && markGlyph.ligatureComponent > 0 ? Math.min(markGlyph.ligatureComponent, ligGlyph.codePoints.length) - 1 : ligGlyph.codePoints.length - 1;\n\n          var _markRecord = table.markArray[_markIndex];\n          var _baseAnchor = ligAttach[compIndex][_markRecord.class];\n          this.applyAnchor(_markRecord, _baseAnchor, _baseGlyphIndex);\n          return true;\n        }\n\n      case 6:\n        {\n          // Mark to mark positioning\n          var mark1Index = this.coverageIndex(table.mark1Coverage);\n          if (mark1Index === -1) {\n            return false;\n          }\n\n          // get the previous mark to attach to\n          var prevIndex = this.glyphIterator.peekIndex(-1);\n          var prev = this.glyphs[prevIndex];\n          if (!prev || !prev.isMark) {\n            return false;\n          }\n\n          var _cur = this.glyphIterator.cur;\n\n          // The following logic was borrowed from Harfbuzz\n          var good = false;\n          if (_cur.ligatureID === prev.ligatureID) {\n            if (!_cur.ligatureID) {\n              // Marks belonging to the same base\n              good = true;\n            } else if (_cur.ligatureComponent === prev.ligatureComponent) {\n              // Marks belonging to the same ligature component\n              good = true;\n            }\n          } else {\n            // If ligature ids don't match, it may be the case that one of the marks\n            // itself is a ligature, in which case match.\n            if (_cur.ligatureID && !_cur.ligatureComponent || prev.ligatureID && !prev.ligatureComponent) {\n              good = true;\n            }\n          }\n\n          if (!good) {\n            return false;\n          }\n\n          var mark2Index = this.coverageIndex(table.mark2Coverage, prev.id);\n          if (mark2Index === -1) {\n            return false;\n          }\n\n          var _markRecord2 = table.mark1Array[mark1Index];\n          var _baseAnchor2 = table.mark2Array[mark2Index][_markRecord2.class];\n          this.applyAnchor(_markRecord2, _baseAnchor2, prevIndex);\n          return true;\n        }\n\n      case 7:\n        // Contextual positioning\n        return this.applyContext(table);\n\n      case 8:\n        // Chaining contextual positioning\n        return this.applyChainingContext(table);\n\n      case 9:\n        // Extension positioning\n        return this.applyLookup(table.lookupType, table.extension);\n\n      default:\n        throw new Error('Unsupported GPOS table: ' + lookupType);\n    }\n  };\n\n  GPOSProcessor.prototype.applyAnchor = function applyAnchor(markRecord, baseAnchor, baseGlyphIndex) {\n    var baseCoords = this.getAnchor(baseAnchor);\n    var markCoords = this.getAnchor(markRecord.markAnchor);\n\n    var basePos = this.positions[baseGlyphIndex];\n    var markPos = this.positions[this.glyphIterator.index];\n\n    markPos.xOffset = baseCoords.x - markCoords.x;\n    markPos.yOffset = baseCoords.y - markCoords.y;\n    this.glyphIterator.cur.markAttachment = baseGlyphIndex;\n  };\n\n  GPOSProcessor.prototype.getAnchor = function getAnchor(anchor) {\n    // TODO: contour point, device tables\n    var x = anchor.xCoordinate;\n    var y = anchor.yCoordinate;\n\n    // Adjustments for font variations\n    var variationProcessor = this.font._variationProcessor;\n    var variationStore = this.font.GDEF && this.font.GDEF.itemVariationStore;\n    if (variationProcessor && variationStore) {\n      if (anchor.xDeviceTable) {\n        x += variationProcessor.getDelta(variationStore, anchor.xDeviceTable.a, anchor.xDeviceTable.b);\n      }\n\n      if (anchor.yDeviceTable) {\n        y += variationProcessor.getDelta(variationStore, anchor.yDeviceTable.a, anchor.yDeviceTable.b);\n      }\n    }\n\n    return { x: x, y: y };\n  };\n\n  GPOSProcessor.prototype.applyFeatures = function applyFeatures(userFeatures, glyphs, advances) {\n    _OTProcessor.prototype.applyFeatures.call(this, userFeatures, glyphs, advances);\n\n    for (var i = 0; i < this.glyphs.length; i++) {\n      this.fixCursiveAttachment(i);\n    }\n\n    this.fixMarkAttachment();\n  };\n\n  GPOSProcessor.prototype.fixCursiveAttachment = function fixCursiveAttachment(i) {\n    var glyph = this.glyphs[i];\n    if (glyph.cursiveAttachment != null) {\n      var j = glyph.cursiveAttachment;\n\n      glyph.cursiveAttachment = null;\n      this.fixCursiveAttachment(j);\n\n      this.positions[i].yOffset += this.positions[j].yOffset;\n    }\n  };\n\n  GPOSProcessor.prototype.fixMarkAttachment = function fixMarkAttachment() {\n    for (var i = 0; i < this.glyphs.length; i++) {\n      var glyph = this.glyphs[i];\n      if (glyph.markAttachment != null) {\n        var j = glyph.markAttachment;\n\n        this.positions[i].xOffset += this.positions[j].xOffset;\n        this.positions[i].yOffset += this.positions[j].yOffset;\n\n        if (this.direction === 'ltr') {\n          for (var k = j; k < i; k++) {\n            this.positions[i].xOffset -= this.positions[k].xAdvance;\n            this.positions[i].yOffset -= this.positions[k].yAdvance;\n          }\n        } else {\n          for (var _k = j + 1; _k < i + 1; _k++) {\n            this.positions[i].xOffset += this.positions[_k].xAdvance;\n            this.positions[i].yOffset += this.positions[_k].yAdvance;\n          }\n        }\n      }\n    }\n  };\n\n  return GPOSProcessor;\n}(OTProcessor);\n\nvar OTLayoutEngine = function () {\n  function OTLayoutEngine(font) {\n    _classCallCheck(this, OTLayoutEngine);\n\n    this.font = font;\n    this.glyphInfos = null;\n    this.plan = null;\n    this.GSUBProcessor = null;\n    this.GPOSProcessor = null;\n    this.fallbackPosition = true;\n\n    if (font.GSUB) {\n      this.GSUBProcessor = new GSUBProcessor(font, font.GSUB);\n    }\n\n    if (font.GPOS) {\n      this.GPOSProcessor = new GPOSProcessor(font, font.GPOS);\n    }\n  }\n\n  OTLayoutEngine.prototype.setup = function setup(glyphRun) {\n    var _this = this;\n\n    // Map glyphs to GlyphInfo objects so data can be passed between\n    // GSUB and GPOS without mutating the real (shared) Glyph objects.\n    this.glyphInfos = glyphRun.glyphs.map(function (glyph) {\n      return new GlyphInfo(_this.font, glyph.id, [].concat(glyph.codePoints));\n    });\n\n    // Select a script based on what is available in GSUB/GPOS.\n    var script = null;\n    if (this.GPOSProcessor) {\n      script = this.GPOSProcessor.selectScript(glyphRun.script, glyphRun.language, glyphRun.direction);\n    }\n\n    if (this.GSUBProcessor) {\n      script = this.GSUBProcessor.selectScript(glyphRun.script, glyphRun.language, glyphRun.direction);\n    }\n\n    // Choose a shaper based on the script, and setup a shaping plan.\n    // This determines which features to apply to which glyphs.\n    this.shaper = choose(script);\n    this.plan = new ShapingPlan(this.font, script, glyphRun.direction);\n    this.shaper.plan(this.plan, this.glyphInfos, glyphRun.features);\n\n    // Assign chosen features to output glyph run\n    for (var key in this.plan.allFeatures) {\n      glyphRun.features[key] = true;\n    }\n  };\n\n  OTLayoutEngine.prototype.substitute = function substitute(glyphRun) {\n    var _this2 = this;\n\n    if (this.GSUBProcessor) {\n      this.plan.process(this.GSUBProcessor, this.glyphInfos);\n\n      // Map glyph infos back to normal Glyph objects\n      glyphRun.glyphs = this.glyphInfos.map(function (glyphInfo) {\n        return _this2.font.getGlyph(glyphInfo.id, glyphInfo.codePoints);\n      });\n    }\n  };\n\n  OTLayoutEngine.prototype.position = function position(glyphRun) {\n    if (this.shaper.zeroMarkWidths === 'BEFORE_GPOS') {\n      this.zeroMarkAdvances(glyphRun.positions);\n    }\n\n    if (this.GPOSProcessor) {\n      this.plan.process(this.GPOSProcessor, this.glyphInfos, glyphRun.positions);\n    }\n\n    if (this.shaper.zeroMarkWidths === 'AFTER_GPOS') {\n      this.zeroMarkAdvances(glyphRun.positions);\n    }\n\n    // Reverse the glyphs and positions if the script is right-to-left\n    if (glyphRun.direction === 'rtl') {\n      glyphRun.glyphs.reverse();\n      glyphRun.positions.reverse();\n    }\n\n    return this.GPOSProcessor && this.GPOSProcessor.features;\n  };\n\n  OTLayoutEngine.prototype.zeroMarkAdvances = function zeroMarkAdvances(positions) {\n    for (var i = 0; i < this.glyphInfos.length; i++) {\n      if (this.glyphInfos[i].isMark) {\n        positions[i].xAdvance = 0;\n        positions[i].yAdvance = 0;\n      }\n    }\n  };\n\n  OTLayoutEngine.prototype.cleanup = function cleanup() {\n    this.glyphInfos = null;\n    this.plan = null;\n    this.shaper = null;\n  };\n\n  OTLayoutEngine.prototype.getAvailableFeatures = function getAvailableFeatures(script, language) {\n    var features = [];\n\n    if (this.GSUBProcessor) {\n      this.GSUBProcessor.selectScript(script, language);\n      features.push.apply(features, _Object$keys(this.GSUBProcessor.features));\n    }\n\n    if (this.GPOSProcessor) {\n      this.GPOSProcessor.selectScript(script, language);\n      features.push.apply(features, _Object$keys(this.GPOSProcessor.features));\n    }\n\n    return features;\n  };\n\n  return OTLayoutEngine;\n}();\n\nvar LayoutEngine = function () {\n  function LayoutEngine(font) {\n    _classCallCheck(this, LayoutEngine);\n\n    this.font = font;\n    this.unicodeLayoutEngine = null;\n    this.kernProcessor = null;\n\n    // Choose an advanced layout engine. We try the AAT morx table first since more\n    // scripts are currently supported because the shaping logic is built into the font.\n    if (this.font.morx) {\n      this.engine = new AATLayoutEngine(this.font);\n    } else if (this.font.GSUB || this.font.GPOS) {\n      this.engine = new OTLayoutEngine(this.font);\n    }\n  }\n\n  LayoutEngine.prototype.layout = function layout(string, features, script, language, direction) {\n    // Make the features parameter optional\n    if (typeof features === 'string') {\n      direction = language;\n      language = script;\n      script = features;\n      features = [];\n    }\n\n    // Map string to glyphs if needed\n    if (typeof string === 'string') {\n      // Attempt to detect the script from the string if not provided.\n      if (script == null) {\n        script = forString(string);\n      }\n\n      var glyphs = this.font.glyphsForString(string);\n    } else {\n      // Attempt to detect the script from the glyph code points if not provided.\n      if (script == null) {\n        var codePoints = [];\n        for (var _iterator = string, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n          var _ref;\n\n          if (_isArray) {\n            if (_i >= _iterator.length) break;\n            _ref = _iterator[_i++];\n          } else {\n            _i = _iterator.next();\n            if (_i.done) break;\n            _ref = _i.value;\n          }\n\n          var glyph = _ref;\n\n          codePoints.push.apply(codePoints, glyph.codePoints);\n        }\n\n        script = forCodePoints(codePoints);\n      }\n\n      var glyphs = string;\n    }\n\n    var glyphRun = new GlyphRun(glyphs, features, script, language, direction);\n\n    // Return early if there are no glyphs\n    if (glyphs.length === 0) {\n      glyphRun.positions = [];\n      return glyphRun;\n    }\n\n    // Setup the advanced layout engine\n    if (this.engine && this.engine.setup) {\n      this.engine.setup(glyphRun);\n    }\n\n    // Substitute and position the glyphs\n    this.substitute(glyphRun);\n    this.position(glyphRun);\n\n    this.hideDefaultIgnorables(glyphRun.glyphs, glyphRun.positions);\n\n    // Let the layout engine clean up any state it might have\n    if (this.engine && this.engine.cleanup) {\n      this.engine.cleanup();\n    }\n\n    return glyphRun;\n  };\n\n  LayoutEngine.prototype.substitute = function substitute(glyphRun) {\n    // Call the advanced layout engine to make substitutions\n    if (this.engine && this.engine.substitute) {\n      this.engine.substitute(glyphRun);\n    }\n  };\n\n  LayoutEngine.prototype.position = function position(glyphRun) {\n    // Get initial glyph positions\n    glyphRun.positions = glyphRun.glyphs.map(function (glyph) {\n      return new GlyphPosition(glyph.advanceWidth);\n    });\n    var positioned = null;\n\n    // Call the advanced layout engine. Returns the features applied.\n    if (this.engine && this.engine.position) {\n      positioned = this.engine.position(glyphRun);\n    }\n\n    // if there is no GPOS table, use unicode properties to position marks.\n    if (!positioned && (!this.engine || this.engine.fallbackPosition)) {\n      if (!this.unicodeLayoutEngine) {\n        this.unicodeLayoutEngine = new UnicodeLayoutEngine(this.font);\n      }\n\n      this.unicodeLayoutEngine.positionGlyphs(glyphRun.glyphs, glyphRun.positions);\n    }\n\n    // if kerning is not supported by GPOS, do kerning with the TrueType/AAT kern table\n    if ((!positioned || !positioned.kern) && glyphRun.features.kern !== false && this.font.kern) {\n      if (!this.kernProcessor) {\n        this.kernProcessor = new KernProcessor(this.font);\n      }\n\n      this.kernProcessor.process(glyphRun.glyphs, glyphRun.positions);\n      glyphRun.features.kern = true;\n    }\n  };\n\n  LayoutEngine.prototype.hideDefaultIgnorables = function hideDefaultIgnorables(glyphs, positions) {\n    var space = this.font.glyphForCodePoint(0x20);\n    for (var i = 0; i < glyphs.length; i++) {\n      if (this.isDefaultIgnorable(glyphs[i].codePoints[0])) {\n        glyphs[i] = space;\n        positions[i].xAdvance = 0;\n        positions[i].yAdvance = 0;\n      }\n    }\n  };\n\n  LayoutEngine.prototype.isDefaultIgnorable = function isDefaultIgnorable(ch) {\n    // From DerivedCoreProperties.txt in the Unicode database,\n    // minus U+115F, U+1160, U+3164 and U+FFA0, which is what\n    // Harfbuzz and Uniscribe do.\n    var plane = ch >> 16;\n    if (plane === 0) {\n      // BMP\n      switch (ch >> 8) {\n        case 0x00:\n          return ch === 0x00AD;\n        case 0x03:\n          return ch === 0x034F;\n        case 0x06:\n          return ch === 0x061C;\n        case 0x17:\n          return 0x17B4 <= ch && ch <= 0x17B5;\n        case 0x18:\n          return 0x180B <= ch && ch <= 0x180E;\n        case 0x20:\n          return 0x200B <= ch && ch <= 0x200F || 0x202A <= ch && ch <= 0x202E || 0x2060 <= ch && ch <= 0x206F;\n        case 0xFE:\n          return 0xFE00 <= ch && ch <= 0xFE0F || ch === 0xFEFF;\n        case 0xFF:\n          return 0xFFF0 <= ch && ch <= 0xFFF8;\n        default:\n          return false;\n      }\n    } else {\n      // Other planes\n      switch (plane) {\n        case 0x01:\n          return 0x1BCA0 <= ch && ch <= 0x1BCA3 || 0x1D173 <= ch && ch <= 0x1D17A;\n        case 0x0E:\n          return 0xE0000 <= ch && ch <= 0xE0FFF;\n        default:\n          return false;\n      }\n    }\n  };\n\n  LayoutEngine.prototype.getAvailableFeatures = function getAvailableFeatures(script, language) {\n    var features = [];\n\n    if (this.engine) {\n      features.push.apply(features, this.engine.getAvailableFeatures(script, language));\n    }\n\n    if (this.font.kern && features.indexOf('kern') === -1) {\n      features.push('kern');\n    }\n\n    return features;\n  };\n\n  LayoutEngine.prototype.stringsForGlyph = function stringsForGlyph(gid) {\n    var result = new _Set();\n\n    var codePoints = this.font._cmapProcessor.codePointsForGlyph(gid);\n    for (var _iterator2 = codePoints, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n      var _ref2;\n\n      if (_isArray2) {\n        if (_i2 >= _iterator2.length) break;\n        _ref2 = _iterator2[_i2++];\n      } else {\n        _i2 = _iterator2.next();\n        if (_i2.done) break;\n        _ref2 = _i2.value;\n      }\n\n      var codePoint = _ref2;\n\n      result.add(_String$fromCodePoint(codePoint));\n    }\n\n    if (this.engine && this.engine.stringsForGlyph) {\n      for (var _iterator3 = this.engine.stringsForGlyph(gid), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n        var _ref3;\n\n        if (_isArray3) {\n          if (_i3 >= _iterator3.length) break;\n          _ref3 = _iterator3[_i3++];\n        } else {\n          _i3 = _iterator3.next();\n          if (_i3.done) break;\n          _ref3 = _i3.value;\n        }\n\n        var string = _ref3;\n\n        result.add(string);\n      }\n    }\n\n    return _Array$from(result);\n  };\n\n  return LayoutEngine;\n}();\n\nvar SVG_COMMANDS = {\n  moveTo: 'M',\n  lineTo: 'L',\n  quadraticCurveTo: 'Q',\n  bezierCurveTo: 'C',\n  closePath: 'Z'\n};\n\n/**\n * Path objects are returned by glyphs and represent the actual\n * vector outlines for each glyph in the font. Paths can be converted\n * to SVG path data strings, or to functions that can be applied to\n * render the path to a graphics context.\n */\n\nvar Path = function () {\n  function Path() {\n    _classCallCheck(this, Path);\n\n    this.commands = [];\n    this._bbox = null;\n    this._cbox = null;\n  }\n\n  /**\n   * Compiles the path to a JavaScript function that can be applied with\n   * a graphics context in order to render the path.\n   * @return {string}\n   */\n\n\n  Path.prototype.toFunction = function toFunction() {\n    var cmds = this.commands.map(function (c) {\n      return '  ctx.' + c.command + '(' + c.args.join(', ') + ');';\n    });\n    return new Function('ctx', cmds.join('\\n'));\n  };\n\n  /**\n   * Converts the path to an SVG path data string\n   * @return {string}\n   */\n\n\n  Path.prototype.toSVG = function toSVG() {\n    var cmds = this.commands.map(function (c) {\n      var args = c.args.map(function (arg) {\n        return Math.round(arg * 100) / 100;\n      });\n      return '' + SVG_COMMANDS[c.command] + args.join(' ');\n    });\n\n    return cmds.join('');\n  };\n\n  /**\n   * Gets the \"control box\" of a path.\n   * This is like the bounding box, but it includes all points including\n   * control points of bezier segments and is much faster to compute than\n   * the real bounding box.\n   * @type {BBox}\n   */\n\n\n  /**\n   * Applies a mapping function to each point in the path.\n   * @param {function} fn\n   * @return {Path}\n   */\n  Path.prototype.mapPoints = function mapPoints(fn) {\n    var path = new Path();\n\n    for (var _iterator = this.commands, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var c = _ref;\n\n      var args = [];\n      for (var _i2 = 0; _i2 < c.args.length; _i2 += 2) {\n        var _fn = fn(c.args[_i2], c.args[_i2 + 1]),\n            x = _fn[0],\n            y = _fn[1];\n\n        args.push(x, y);\n      }\n\n      path[c.command].apply(path, args);\n    }\n\n    return path;\n  };\n\n  /**\n   * Transforms the path by the given matrix.\n   */\n\n\n  Path.prototype.transform = function transform(m0, m1, m2, m3, m4, m5) {\n    return this.mapPoints(function (x, y) {\n      x = m0 * x + m2 * y + m4;\n      y = m1 * x + m3 * y + m5;\n      return [x, y];\n    });\n  };\n\n  /**\n   * Translates the path by the given offset.\n   */\n\n\n  Path.prototype.translate = function translate(x, y) {\n    return this.transform(1, 0, 0, 1, x, y);\n  };\n\n  /**\n   * Rotates the path by the given angle (in radians).\n   */\n\n\n  Path.prototype.rotate = function rotate(angle) {\n    var cos = Math.cos(angle);\n    var sin = Math.sin(angle);\n    return this.transform(cos, sin, -sin, cos, 0, 0);\n  };\n\n  /**\n   * Scales the path.\n   */\n\n\n  Path.prototype.scale = function scale(scaleX) {\n    var scaleY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : scaleX;\n\n    return this.transform(scaleX, 0, 0, scaleY, 0, 0);\n  };\n\n  _createClass(Path, [{\n    key: 'cbox',\n    get: function get() {\n      if (!this._cbox) {\n        var cbox = new BBox();\n        for (var _iterator2 = this.commands, _isArray2 = Array.isArray(_iterator2), _i3 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n          var _ref2;\n\n          if (_isArray2) {\n            if (_i3 >= _iterator2.length) break;\n            _ref2 = _iterator2[_i3++];\n          } else {\n            _i3 = _iterator2.next();\n            if (_i3.done) break;\n            _ref2 = _i3.value;\n          }\n\n          var command = _ref2;\n\n          for (var _i4 = 0; _i4 < command.args.length; _i4 += 2) {\n            cbox.addPoint(command.args[_i4], command.args[_i4 + 1]);\n          }\n        }\n\n        this._cbox = _Object$freeze(cbox);\n      }\n\n      return this._cbox;\n    }\n\n    /**\n     * Gets the exact bounding box of the path by evaluating curve segments.\n     * Slower to compute than the control box, but more accurate.\n     * @type {BBox}\n     */\n\n  }, {\n    key: 'bbox',\n    get: function get() {\n      if (this._bbox) {\n        return this._bbox;\n      }\n\n      var bbox = new BBox();\n      var cx = 0,\n          cy = 0;\n\n      var f = function f(t) {\n        return Math.pow(1 - t, 3) * p0[i] + 3 * Math.pow(1 - t, 2) * t * p1[i] + 3 * (1 - t) * Math.pow(t, 2) * p2[i] + Math.pow(t, 3) * p3[i];\n      };\n\n      for (var _iterator3 = this.commands, _isArray3 = Array.isArray(_iterator3), _i5 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n        var _ref3;\n\n        if (_isArray3) {\n          if (_i5 >= _iterator3.length) break;\n          _ref3 = _iterator3[_i5++];\n        } else {\n          _i5 = _iterator3.next();\n          if (_i5.done) break;\n          _ref3 = _i5.value;\n        }\n\n        var c = _ref3;\n\n        switch (c.command) {\n          case 'moveTo':\n          case 'lineTo':\n            var _c$args = c.args,\n                x = _c$args[0],\n                y = _c$args[1];\n\n            bbox.addPoint(x, y);\n            cx = x;\n            cy = y;\n            break;\n\n          case 'quadraticCurveTo':\n          case 'bezierCurveTo':\n            if (c.command === 'quadraticCurveTo') {\n              // http://fontforge.org/bezier.html\n              var _c$args2 = c.args,\n                  qp1x = _c$args2[0],\n                  qp1y = _c$args2[1],\n                  p3x = _c$args2[2],\n                  p3y = _c$args2[3];\n\n              var cp1x = cx + 2 / 3 * (qp1x - cx); // CP1 = QP0 + 2/3 * (QP1-QP0)\n              var cp1y = cy + 2 / 3 * (qp1y - cy);\n              var cp2x = p3x + 2 / 3 * (qp1x - p3x); // CP2 = QP2 + 2/3 * (QP1-QP2)\n              var cp2y = p3y + 2 / 3 * (qp1y - p3y);\n            } else {\n              var _c$args3 = c.args,\n                  cp1x = _c$args3[0],\n                  cp1y = _c$args3[1],\n                  cp2x = _c$args3[2],\n                  cp2y = _c$args3[3],\n                  p3x = _c$args3[4],\n                  p3y = _c$args3[5];\n            }\n\n            // http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html\n            bbox.addPoint(p3x, p3y);\n\n            var p0 = [cx, cy];\n            var p1 = [cp1x, cp1y];\n            var p2 = [cp2x, cp2y];\n            var p3 = [p3x, p3y];\n\n            for (var i = 0; i <= 1; i++) {\n              var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i];\n              var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i];\n              c = 3 * p1[i] - 3 * p0[i];\n\n              if (a === 0) {\n                if (b === 0) {\n                  continue;\n                }\n\n                var t = -c / b;\n                if (0 < t && t < 1) {\n                  if (i === 0) {\n                    bbox.addPoint(f(t), bbox.maxY);\n                  } else if (i === 1) {\n                    bbox.addPoint(bbox.maxX, f(t));\n                  }\n                }\n\n                continue;\n              }\n\n              var b2ac = Math.pow(b, 2) - 4 * c * a;\n              if (b2ac < 0) {\n                continue;\n              }\n\n              var t1 = (-b + Math.sqrt(b2ac)) / (2 * a);\n              if (0 < t1 && t1 < 1) {\n                if (i === 0) {\n                  bbox.addPoint(f(t1), bbox.maxY);\n                } else if (i === 1) {\n                  bbox.addPoint(bbox.maxX, f(t1));\n                }\n              }\n\n              var t2 = (-b - Math.sqrt(b2ac)) / (2 * a);\n              if (0 < t2 && t2 < 1) {\n                if (i === 0) {\n                  bbox.addPoint(f(t2), bbox.maxY);\n                } else if (i === 1) {\n                  bbox.addPoint(bbox.maxX, f(t2));\n                }\n              }\n            }\n\n            cx = p3x;\n            cy = p3y;\n            break;\n        }\n      }\n\n      return this._bbox = _Object$freeze(bbox);\n    }\n  }]);\n\n  return Path;\n}();\n\nvar _arr = ['moveTo', 'lineTo', 'quadraticCurveTo', 'bezierCurveTo', 'closePath'];\n\nvar _loop = function _loop() {\n  var command = _arr[_i6];\n  Path.prototype[command] = function () {\n    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {\n      args[_key] = arguments[_key];\n    }\n\n    this._bbox = this._cbox = null;\n    this.commands.push({\n      command: command,\n      args: args\n    });\n\n    return this;\n  };\n};\n\nfor (var _i6 = 0; _i6 < _arr.length; _i6++) {\n  _loop();\n}\n\nvar StandardNames = ['.notdef', '.null', 'nonmarkingreturn', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', 'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis', 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis', 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute', 'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave', 'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section', 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', 'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus', 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff', 'summation', 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis', 'nonbreakingspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash', 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction', 'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered', 'quotesinglbase', 'quotedblbase', 'perthousand', 'Acircumflex', 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple', 'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'Lslash', 'lslash', 'Scaron', 'scaron', 'Zcaron', 'zcaron', 'brokenbar', 'Eth', 'eth', 'Yacute', 'yacute', 'Thorn', 'thorn', 'minus', 'multiply', 'onesuperior', 'twosuperior', 'threesuperior', 'onehalf', 'onequarter', 'threequarters', 'franc', 'Gbreve', 'gbreve', 'Idotaccent', 'Scedilla', 'scedilla', 'Cacute', 'cacute', 'Ccaron', 'ccaron', 'dcroat'];\n\nvar _class$8;\nfunction _applyDecoratedDescriptor$4(target, property, decorators, descriptor, context) {\n  var desc = {};\n  Object['ke' + 'ys'](descriptor).forEach(function (key) {\n    desc[key] = descriptor[key];\n  });\n  desc.enumerable = !!desc.enumerable;\n  desc.configurable = !!desc.configurable;\n\n  if ('value' in desc || desc.initializer) {\n    desc.writable = true;\n  }\n\n  desc = decorators.slice().reverse().reduce(function (desc, decorator) {\n    return decorator(target, property, desc) || desc;\n  }, desc);\n\n  if (context && desc.initializer !== void 0) {\n    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;\n    desc.initializer = undefined;\n  }\n\n  if (desc.initializer === void 0) {\n    Object['define' + 'Property'](target, property, desc);\n    desc = null;\n  }\n\n  return desc;\n}\n\n/**\n * Glyph objects represent a glyph in the font. They have various properties for accessing metrics and\n * the actual vector path the glyph represents, and methods for rendering the glyph to a graphics context.\n *\n * You do not create glyph objects directly. They are created by various methods on the font object.\n * There are several subclasses of the base Glyph class internally that may be returned depending\n * on the font format, but they all inherit from this class.\n */\nvar Glyph = (_class$8 = function () {\n  function Glyph(id, codePoints, font) {\n    _classCallCheck(this, Glyph);\n\n    /**\n     * The glyph id in the font\n     * @type {number}\n     */\n    this.id = id;\n\n    /**\n     * An array of unicode code points that are represented by this glyph.\n     * There can be multiple code points in the case of ligatures and other glyphs\n     * that represent multiple visual characters.\n     * @type {number[]}\n     */\n    this.codePoints = codePoints;\n    this._font = font;\n\n    // TODO: get this info from GDEF if available\n    this.isMark = this.codePoints.every(unicode.isMark);\n    this.isLigature = this.codePoints.length > 1;\n  }\n\n  Glyph.prototype._getPath = function _getPath() {\n    return new Path();\n  };\n\n  Glyph.prototype._getCBox = function _getCBox() {\n    return this.path.cbox;\n  };\n\n  Glyph.prototype._getBBox = function _getBBox() {\n    return this.path.bbox;\n  };\n\n  Glyph.prototype._getTableMetrics = function _getTableMetrics(table) {\n    if (this.id < table.metrics.length) {\n      return table.metrics.get(this.id);\n    }\n\n    var metric = table.metrics.get(table.metrics.length - 1);\n    var res = {\n      advance: metric ? metric.advance : 0,\n      bearing: table.bearings.get(this.id - table.metrics.length) || 0\n    };\n\n    return res;\n  };\n\n  Glyph.prototype._getMetrics = function _getMetrics(cbox) {\n    if (this._metrics) {\n      return this._metrics;\n    }\n\n    var _getTableMetrics2 = this._getTableMetrics(this._font.hmtx),\n        advanceWidth = _getTableMetrics2.advance,\n        leftBearing = _getTableMetrics2.bearing;\n\n    // For vertical metrics, use vmtx if available, or fall back to global data from OS/2 or hhea\n\n\n    if (this._font.vmtx) {\n      var _getTableMetrics3 = this._getTableMetrics(this._font.vmtx),\n          advanceHeight = _getTableMetrics3.advance,\n          topBearing = _getTableMetrics3.bearing;\n    } else {\n      var os2 = void 0;\n      if (typeof cbox === 'undefined' || cbox === null) {\n        cbox = this.cbox;\n      }\n\n      if ((os2 = this._font['OS/2']) && os2.version > 0) {\n        var advanceHeight = Math.abs(os2.typoAscender - os2.typoDescender);\n        var topBearing = os2.typoAscender - cbox.maxY;\n      } else {\n        var hhea = this._font.hhea;\n\n        var advanceHeight = Math.abs(hhea.ascent - hhea.descent);\n        var topBearing = hhea.ascent - cbox.maxY;\n      }\n    }\n\n    if (this._font._variationProcessor && this._font.HVAR) {\n      advanceWidth += this._font._variationProcessor.getAdvanceAdjustment(this.id, this._font.HVAR);\n    }\n\n    return this._metrics = { advanceWidth: advanceWidth, advanceHeight: advanceHeight, leftBearing: leftBearing, topBearing: topBearing };\n  };\n\n  /**\n   * The glyph’s control box.\n   * This is often the same as the bounding box, but is faster to compute.\n   * Because of the way bezier curves are defined, some of the control points\n   * can be outside of the bounding box. Where `bbox` takes this into account,\n   * `cbox` does not. Thus, cbox is less accurate, but faster to compute.\n   * See [here](http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-2)\n   * for a more detailed description.\n   *\n   * @type {BBox}\n   */\n\n\n  /**\n   * Returns a path scaled to the given font size.\n   * @param {number} size\n   * @return {Path}\n   */\n  Glyph.prototype.getScaledPath = function getScaledPath(size) {\n    var scale = 1 / this._font.unitsPerEm * size;\n    return this.path.scale(scale);\n  };\n\n  /**\n   * The glyph's advance width.\n   * @type {number}\n   */\n\n\n  Glyph.prototype._getName = function _getName() {\n    var post = this._font.post;\n\n    if (!post) {\n      return null;\n    }\n\n    switch (post.version) {\n      case 1:\n        return StandardNames[this.id];\n\n      case 2:\n        var id = post.glyphNameIndex[this.id];\n        if (id < StandardNames.length) {\n          return StandardNames[id];\n        }\n\n        return post.names[id - StandardNames.length];\n\n      case 2.5:\n        return StandardNames[this.id + post.offsets[this.id]];\n\n      case 4:\n        return String.fromCharCode(post.map[this.id]);\n    }\n  };\n\n  /**\n   * The glyph's name\n   * @type {string}\n   */\n\n\n  /**\n   * Renders the glyph to the given graphics context, at the specified font size.\n   * @param {CanvasRenderingContext2d} ctx\n   * @param {number} size\n   */\n  Glyph.prototype.render = function render(ctx, size) {\n    ctx.save();\n\n    var scale = 1 / this._font.head.unitsPerEm * size;\n    ctx.scale(scale, scale);\n\n    var fn = this.path.toFunction();\n    fn(ctx);\n    ctx.fill();\n\n    ctx.restore();\n  };\n\n  _createClass(Glyph, [{\n    key: 'cbox',\n    get: function get() {\n      return this._getCBox();\n    }\n\n    /**\n     * The glyph’s bounding box, i.e. the rectangle that encloses the\n     * glyph outline as tightly as possible.\n     * @type {BBox}\n     */\n\n  }, {\n    key: 'bbox',\n    get: function get() {\n      return this._getBBox();\n    }\n\n    /**\n     * A vector Path object representing the glyph outline.\n     * @type {Path}\n     */\n\n  }, {\n    key: 'path',\n    get: function get() {\n      // Cache the path so we only decode it once\n      // Decoding is actually performed by subclasses\n      return this._getPath();\n    }\n  }, {\n    key: 'advanceWidth',\n    get: function get() {\n      return this._getMetrics().advanceWidth;\n    }\n\n    /**\n     * The glyph's advance height.\n     * @type {number}\n     */\n\n  }, {\n    key: 'advanceHeight',\n    get: function get() {\n      return this._getMetrics().advanceHeight;\n    }\n  }, {\n    key: 'ligatureCaretPositions',\n    get: function get() {}\n  }, {\n    key: 'name',\n    get: function get() {\n      return this._getName();\n    }\n  }]);\n\n  return Glyph;\n}(), (_applyDecoratedDescriptor$4(_class$8.prototype, 'cbox', [cache], _Object$getOwnPropertyDescriptor(_class$8.prototype, 'cbox'), _class$8.prototype), _applyDecoratedDescriptor$4(_class$8.prototype, 'bbox', [cache], _Object$getOwnPropertyDescriptor(_class$8.prototype, 'bbox'), _class$8.prototype), _applyDecoratedDescriptor$4(_class$8.prototype, 'path', [cache], _Object$getOwnPropertyDescriptor(_class$8.prototype, 'path'), _class$8.prototype), _applyDecoratedDescriptor$4(_class$8.prototype, 'advanceWidth', [cache], _Object$getOwnPropertyDescriptor(_class$8.prototype, 'advanceWidth'), _class$8.prototype), _applyDecoratedDescriptor$4(_class$8.prototype, 'advanceHeight', [cache], _Object$getOwnPropertyDescriptor(_class$8.prototype, 'advanceHeight'), _class$8.prototype), _applyDecoratedDescriptor$4(_class$8.prototype, 'name', [cache], _Object$getOwnPropertyDescriptor(_class$8.prototype, 'name'), _class$8.prototype)), _class$8);\n\n// The header for both simple and composite glyphs\nvar GlyfHeader = new r.Struct({\n  numberOfContours: r.int16, // if negative, this is a composite glyph\n  xMin: r.int16,\n  yMin: r.int16,\n  xMax: r.int16,\n  yMax: r.int16\n});\n\n// Flags for simple glyphs\nvar ON_CURVE = 1 << 0;\nvar X_SHORT_VECTOR = 1 << 1;\nvar Y_SHORT_VECTOR = 1 << 2;\nvar REPEAT = 1 << 3;\nvar SAME_X = 1 << 4;\nvar SAME_Y = 1 << 5;\n\n// Flags for composite glyphs\nvar ARG_1_AND_2_ARE_WORDS = 1 << 0;\nvar WE_HAVE_A_SCALE = 1 << 3;\nvar MORE_COMPONENTS = 1 << 5;\nvar WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;\nvar WE_HAVE_A_TWO_BY_TWO = 1 << 7;\nvar WE_HAVE_INSTRUCTIONS = 1 << 8;\n// Represents a point in a simple glyph\nvar Point = function () {\n  function Point(onCurve, endContour) {\n    var x = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n    var y = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;\n\n    _classCallCheck(this, Point);\n\n    this.onCurve = onCurve;\n    this.endContour = endContour;\n    this.x = x;\n    this.y = y;\n  }\n\n  Point.prototype.copy = function copy() {\n    return new Point(this.onCurve, this.endContour, this.x, this.y);\n  };\n\n  return Point;\n}();\n\n// Represents a component in a composite glyph\n\nvar Component = function Component(glyphID, dx, dy) {\n  _classCallCheck(this, Component);\n\n  this.glyphID = glyphID;\n  this.dx = dx;\n  this.dy = dy;\n  this.pos = 0;\n  this.scaleX = this.scaleY = 1;\n  this.scale01 = this.scale10 = 0;\n};\n\n/**\n * Represents a TrueType glyph.\n */\n\n\nvar TTFGlyph = function (_Glyph) {\n  _inherits(TTFGlyph, _Glyph);\n\n  function TTFGlyph() {\n    _classCallCheck(this, TTFGlyph);\n\n    return _possibleConstructorReturn(this, _Glyph.apply(this, arguments));\n  }\n\n  // Parses just the glyph header and returns the bounding box\n  TTFGlyph.prototype._getCBox = function _getCBox(internal) {\n    // We need to decode the glyph if variation processing is requested,\n    // so it's easier just to recompute the path's cbox after decoding.\n    if (this._font._variationProcessor && !internal) {\n      return this.path.cbox;\n    }\n\n    var stream = this._font._getTableStream('glyf');\n    stream.pos += this._font.loca.offsets[this.id];\n    var glyph = GlyfHeader.decode(stream);\n\n    var cbox = new BBox(glyph.xMin, glyph.yMin, glyph.xMax, glyph.yMax);\n    return _Object$freeze(cbox);\n  };\n\n  // Parses a single glyph coordinate\n\n\n  TTFGlyph.prototype._parseGlyphCoord = function _parseGlyphCoord(stream, prev, short, same) {\n    if (short) {\n      var val = stream.readUInt8();\n      if (!same) {\n        val = -val;\n      }\n\n      val += prev;\n    } else {\n      if (same) {\n        var val = prev;\n      } else {\n        var val = prev + stream.readInt16BE();\n      }\n    }\n\n    return val;\n  };\n\n  // Decodes the glyph data into points for simple glyphs,\n  // or components for composite glyphs\n\n\n  TTFGlyph.prototype._decode = function _decode() {\n    var glyfPos = this._font.loca.offsets[this.id];\n    var nextPos = this._font.loca.offsets[this.id + 1];\n\n    // Nothing to do if there is no data for this glyph\n    if (glyfPos === nextPos) {\n      return null;\n    }\n\n    var stream = this._font._getTableStream('glyf');\n    stream.pos += glyfPos;\n    var startPos = stream.pos;\n\n    var glyph = GlyfHeader.decode(stream);\n\n    if (glyph.numberOfContours > 0) {\n      this._decodeSimple(glyph, stream);\n    } else if (glyph.numberOfContours < 0) {\n      this._decodeComposite(glyph, stream, startPos);\n    }\n\n    return glyph;\n  };\n\n  TTFGlyph.prototype._decodeSimple = function _decodeSimple(glyph, stream) {\n    // this is a simple glyph\n    glyph.points = [];\n\n    var endPtsOfContours = new r.Array(r.uint16, glyph.numberOfContours).decode(stream);\n    glyph.instructions = new r.Array(r.uint8, r.uint16).decode(stream);\n\n    var flags = [];\n    var numCoords = endPtsOfContours[endPtsOfContours.length - 1] + 1;\n\n    while (flags.length < numCoords) {\n      var flag = stream.readUInt8();\n      flags.push(flag);\n\n      // check for repeat flag\n      if (flag & REPEAT) {\n        var count = stream.readUInt8();\n        for (var j = 0; j < count; j++) {\n          flags.push(flag);\n        }\n      }\n    }\n\n    for (var i = 0; i < flags.length; i++) {\n      var flag = flags[i];\n      var point = new Point(!!(flag & ON_CURVE), endPtsOfContours.indexOf(i) >= 0, 0, 0);\n      glyph.points.push(point);\n    }\n\n    var px = 0;\n    for (var i = 0; i < flags.length; i++) {\n      var flag = flags[i];\n      glyph.points[i].x = px = this._parseGlyphCoord(stream, px, flag & X_SHORT_VECTOR, flag & SAME_X);\n    }\n\n    var py = 0;\n    for (var i = 0; i < flags.length; i++) {\n      var flag = flags[i];\n      glyph.points[i].y = py = this._parseGlyphCoord(stream, py, flag & Y_SHORT_VECTOR, flag & SAME_Y);\n    }\n\n    if (this._font._variationProcessor) {\n      var points = glyph.points.slice();\n      points.push.apply(points, this._getPhantomPoints(glyph));\n\n      this._font._variationProcessor.transformPoints(this.id, points);\n      glyph.phantomPoints = points.slice(-4);\n    }\n\n    return;\n  };\n\n  TTFGlyph.prototype._decodeComposite = function _decodeComposite(glyph, stream) {\n    var offset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n\n    // this is a composite glyph\n    glyph.components = [];\n    var haveInstructions = false;\n    var flags = MORE_COMPONENTS;\n\n    while (flags & MORE_COMPONENTS) {\n      flags = stream.readUInt16BE();\n      var gPos = stream.pos - offset;\n      var glyphID = stream.readUInt16BE();\n      if (!haveInstructions) {\n        haveInstructions = (flags & WE_HAVE_INSTRUCTIONS) !== 0;\n      }\n\n      if (flags & ARG_1_AND_2_ARE_WORDS) {\n        var dx = stream.readInt16BE();\n        var dy = stream.readInt16BE();\n      } else {\n        var dx = stream.readInt8();\n        var dy = stream.readInt8();\n      }\n\n      var component = new Component(glyphID, dx, dy);\n      component.pos = gPos;\n\n      if (flags & WE_HAVE_A_SCALE) {\n        // fixed number with 14 bits of fraction\n        component.scaleX = component.scaleY = (stream.readUInt8() << 24 | stream.readUInt8() << 16) / 1073741824;\n      } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {\n        component.scaleX = (stream.readUInt8() << 24 | stream.readUInt8() << 16) / 1073741824;\n        component.scaleY = (stream.readUInt8() << 24 | stream.readUInt8() << 16) / 1073741824;\n      } else if (flags & WE_HAVE_A_TWO_BY_TWO) {\n        component.scaleX = (stream.readUInt8() << 24 | stream.readUInt8() << 16) / 1073741824;\n        component.scale01 = (stream.readUInt8() << 24 | stream.readUInt8() << 16) / 1073741824;\n        component.scale10 = (stream.readUInt8() << 24 | stream.readUInt8() << 16) / 1073741824;\n        component.scaleY = (stream.readUInt8() << 24 | stream.readUInt8() << 16) / 1073741824;\n      }\n\n      glyph.components.push(component);\n    }\n\n    if (this._font._variationProcessor) {\n      var points = [];\n      for (var j = 0; j < glyph.components.length; j++) {\n        var component = glyph.components[j];\n        points.push(new Point(true, true, component.dx, component.dy));\n      }\n\n      points.push.apply(points, this._getPhantomPoints(glyph));\n\n      this._font._variationProcessor.transformPoints(this.id, points);\n      glyph.phantomPoints = points.splice(-4, 4);\n\n      for (var i = 0; i < points.length; i++) {\n        var point = points[i];\n        glyph.components[i].dx = point.x;\n        glyph.components[i].dy = point.y;\n      }\n    }\n\n    return haveInstructions;\n  };\n\n  TTFGlyph.prototype._getPhantomPoints = function _getPhantomPoints(glyph) {\n    var cbox = this._getCBox(true);\n    if (this._metrics == null) {\n      this._metrics = Glyph.prototype._getMetrics.call(this, cbox);\n    }\n\n    var _metrics = this._metrics,\n        advanceWidth = _metrics.advanceWidth,\n        advanceHeight = _metrics.advanceHeight,\n        leftBearing = _metrics.leftBearing,\n        topBearing = _metrics.topBearing;\n\n\n    return [new Point(false, true, glyph.xMin - leftBearing, 0), new Point(false, true, glyph.xMin - leftBearing + advanceWidth, 0), new Point(false, true, 0, glyph.yMax + topBearing), new Point(false, true, 0, glyph.yMax + topBearing + advanceHeight)];\n  };\n\n  // Decodes font data, resolves composite glyphs, and returns an array of contours\n\n\n  TTFGlyph.prototype._getContours = function _getContours() {\n    var glyph = this._decode();\n    if (!glyph) {\n      return [];\n    }\n\n    var points = [];\n\n    if (glyph.numberOfContours < 0) {\n      // resolve composite glyphs\n      for (var _iterator = glyph.components, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n        var _ref;\n\n        if (_isArray) {\n          if (_i >= _iterator.length) break;\n          _ref = _iterator[_i++];\n        } else {\n          _i = _iterator.next();\n          if (_i.done) break;\n          _ref = _i.value;\n        }\n\n        var component = _ref;\n\n        var _contours = this._font.getGlyph(component.glyphID)._getContours();\n        for (var i = 0; i < _contours.length; i++) {\n          var contour = _contours[i];\n          for (var j = 0; j < contour.length; j++) {\n            var _point = contour[j];\n            var x = _point.x * component.scaleX + _point.y * component.scale01 + component.dx;\n            var y = _point.y * component.scaleY + _point.x * component.scale10 + component.dy;\n            points.push(new Point(_point.onCurve, _point.endContour, x, y));\n          }\n        }\n      }\n    } else {\n      points = glyph.points || [];\n    }\n\n    // Recompute and cache metrics if we performed variation processing, and don't have an HVAR table\n    if (glyph.phantomPoints && !this._font.directory.tables.HVAR) {\n      this._metrics.advanceWidth = glyph.phantomPoints[1].x - glyph.phantomPoints[0].x;\n      this._metrics.advanceHeight = glyph.phantomPoints[3].y - glyph.phantomPoints[2].y;\n      this._metrics.leftBearing = glyph.xMin - glyph.phantomPoints[0].x;\n      this._metrics.topBearing = glyph.phantomPoints[2].y - glyph.yMax;\n    }\n\n    var contours = [];\n    var cur = [];\n    for (var k = 0; k < points.length; k++) {\n      var point = points[k];\n      cur.push(point);\n      if (point.endContour) {\n        contours.push(cur);\n        cur = [];\n      }\n    }\n\n    return contours;\n  };\n\n  TTFGlyph.prototype._getMetrics = function _getMetrics() {\n    if (this._metrics) {\n      return this._metrics;\n    }\n\n    var cbox = this._getCBox(true);\n    _Glyph.prototype._getMetrics.call(this, cbox);\n\n    if (this._font._variationProcessor && !this._font.HVAR) {\n      // No HVAR table, decode the glyph. This triggers recomputation of metrics.\n      this.path;\n    }\n\n    return this._metrics;\n  };\n\n  // Converts contours to a Path object that can be rendered\n\n\n  TTFGlyph.prototype._getPath = function _getPath() {\n    var contours = this._getContours();\n    var path = new Path();\n\n    for (var i = 0; i < contours.length; i++) {\n      var contour = contours[i];\n      var firstPt = contour[0];\n      var lastPt = contour[contour.length - 1];\n      var start = 0;\n\n      if (firstPt.onCurve) {\n        // The first point will be consumed by the moveTo command, so skip in the loop\n        var curvePt = null;\n        start = 1;\n      } else {\n        if (lastPt.onCurve) {\n          // Start at the last point if the first point is off curve and the last point is on curve\n          firstPt = lastPt;\n        } else {\n          // Start at the middle if both the first and last points are off curve\n          firstPt = new Point(false, false, (firstPt.x + lastPt.x) / 2, (firstPt.y + lastPt.y) / 2);\n        }\n\n        var curvePt = firstPt;\n      }\n\n      path.moveTo(firstPt.x, firstPt.y);\n\n      for (var j = start; j < contour.length; j++) {\n        var pt = contour[j];\n        var prevPt = j === 0 ? firstPt : contour[j - 1];\n\n        if (prevPt.onCurve && pt.onCurve) {\n          path.lineTo(pt.x, pt.y);\n        } else if (prevPt.onCurve && !pt.onCurve) {\n          var curvePt = pt;\n        } else if (!prevPt.onCurve && !pt.onCurve) {\n          var midX = (prevPt.x + pt.x) / 2;\n          var midY = (prevPt.y + pt.y) / 2;\n          path.quadraticCurveTo(prevPt.x, prevPt.y, midX, midY);\n          var curvePt = pt;\n        } else if (!prevPt.onCurve && pt.onCurve) {\n          path.quadraticCurveTo(curvePt.x, curvePt.y, pt.x, pt.y);\n          var curvePt = null;\n        } else {\n          throw new Error(\"Unknown TTF path state\");\n        }\n      }\n\n      // Connect the first and last points\n      if (curvePt) {\n        path.quadraticCurveTo(curvePt.x, curvePt.y, firstPt.x, firstPt.y);\n      }\n\n      path.closePath();\n    }\n\n    return path;\n  };\n\n  return TTFGlyph;\n}(Glyph);\n\n/**\n * Represents an OpenType PostScript glyph, in the Compact Font Format.\n */\n\nvar CFFGlyph = function (_Glyph) {\n  _inherits(CFFGlyph, _Glyph);\n\n  function CFFGlyph() {\n    _classCallCheck(this, CFFGlyph);\n\n    return _possibleConstructorReturn(this, _Glyph.apply(this, arguments));\n  }\n\n  CFFGlyph.prototype._getName = function _getName() {\n    if (this._font.CFF2) {\n      return _Glyph.prototype._getName.call(this);\n    }\n\n    return this._font['CFF '].getGlyphName(this.id);\n  };\n\n  CFFGlyph.prototype.bias = function bias(s) {\n    if (s.length < 1240) {\n      return 107;\n    } else if (s.length < 33900) {\n      return 1131;\n    } else {\n      return 32768;\n    }\n  };\n\n  CFFGlyph.prototype._getPath = function _getPath() {\n    var stream = this._font.stream;\n    var pos = stream.pos;\n\n\n    var cff = this._font.CFF2 || this._font['CFF '];\n    var str = cff.topDict.CharStrings[this.id];\n    var end = str.offset + str.length;\n    stream.pos = str.offset;\n\n    var path = new Path();\n    var stack = [];\n    var trans = [];\n\n    var width = null;\n    var nStems = 0;\n    var x = 0,\n        y = 0;\n    var usedGsubrs = void 0;\n    var usedSubrs = void 0;\n    var open = false;\n\n    this._usedGsubrs = usedGsubrs = {};\n    this._usedSubrs = usedSubrs = {};\n\n    var gsubrs = cff.globalSubrIndex || [];\n    var gsubrsBias = this.bias(gsubrs);\n\n    var privateDict = cff.privateDictForGlyph(this.id);\n    var subrs = privateDict.Subrs || [];\n    var subrsBias = this.bias(subrs);\n\n    var vstore = cff.topDict.vstore && cff.topDict.vstore.itemVariationStore;\n    var vsindex = privateDict.vsindex;\n    var variationProcessor = this._font._variationProcessor;\n\n    function checkWidth() {\n      if (width == null) {\n        width = stack.shift() + privateDict.nominalWidthX;\n      }\n    }\n\n    function parseStems() {\n      if (stack.length % 2 !== 0) {\n        checkWidth();\n      }\n\n      nStems += stack.length >> 1;\n      return stack.length = 0;\n    }\n\n    function moveTo(x, y) {\n      if (open) {\n        path.closePath();\n      }\n\n      path.moveTo(x, y);\n      open = true;\n    }\n\n    var parse = function parse() {\n      while (stream.pos < end) {\n        var op = stream.readUInt8();\n        if (op < 32) {\n          switch (op) {\n            case 1: // hstem\n            case 3: // vstem\n            case 18: // hstemhm\n            case 23:\n              // vstemhm\n              parseStems();\n              break;\n\n            case 4:\n              // vmoveto\n              if (stack.length > 1) {\n                checkWidth();\n              }\n\n              y += stack.shift();\n              moveTo(x, y);\n              break;\n\n            case 5:\n              // rlineto\n              while (stack.length >= 2) {\n                x += stack.shift();\n                y += stack.shift();\n                path.lineTo(x, y);\n              }\n              break;\n\n            case 6: // hlineto\n            case 7:\n              // vlineto\n              var phase = op === 6;\n              while (stack.length >= 1) {\n                if (phase) {\n                  x += stack.shift();\n                } else {\n                  y += stack.shift();\n                }\n\n                path.lineTo(x, y);\n                phase = !phase;\n              }\n              break;\n\n            case 8:\n              // rrcurveto\n              while (stack.length > 0) {\n                var c1x = x + stack.shift();\n                var c1y = y + stack.shift();\n                var c2x = c1x + stack.shift();\n                var c2y = c1y + stack.shift();\n                x = c2x + stack.shift();\n                y = c2y + stack.shift();\n                path.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n              }\n              break;\n\n            case 10:\n              // callsubr\n              var index = stack.pop() + subrsBias;\n              var subr = subrs[index];\n              if (subr) {\n                usedSubrs[index] = true;\n                var p = stream.pos;\n                var e = end;\n                stream.pos = subr.offset;\n                end = subr.offset + subr.length;\n                parse();\n                stream.pos = p;\n                end = e;\n              }\n              break;\n\n            case 11:\n              // return\n              if (cff.version >= 2) {\n                break;\n              }\n              return;\n\n            case 14:\n              // endchar\n              if (cff.version >= 2) {\n                break;\n              }\n\n              if (stack.length > 0) {\n                checkWidth();\n              }\n\n              if (open) {\n                path.closePath();\n                open = false;\n              }\n              break;\n\n            case 15:\n              {\n                // vsindex\n                if (cff.version < 2) {\n                  throw new Error('vsindex operator not supported in CFF v1');\n                }\n\n                vsindex = stack.pop();\n                break;\n              }\n\n            case 16:\n              {\n                // blend\n                if (cff.version < 2) {\n                  throw new Error('blend operator not supported in CFF v1');\n                }\n\n                if (!variationProcessor) {\n                  throw new Error('blend operator in non-variation font');\n                }\n\n                var blendVector = variationProcessor.getBlendVector(vstore, vsindex);\n                var numBlends = stack.pop();\n                var numOperands = numBlends * blendVector.length;\n                var delta = stack.length - numOperands;\n                var base = delta - numBlends;\n\n                for (var i = 0; i < numBlends; i++) {\n                  var sum = stack[base + i];\n                  for (var j = 0; j < blendVector.length; j++) {\n                    sum += blendVector[j] * stack[delta++];\n                  }\n\n                  stack[base + i] = sum;\n                }\n\n                while (numOperands--) {\n                  stack.pop();\n                }\n\n                break;\n              }\n\n            case 19: // hintmask\n            case 20:\n              // cntrmask\n              parseStems();\n              stream.pos += nStems + 7 >> 3;\n              break;\n\n            case 21:\n              // rmoveto\n              if (stack.length > 2) {\n                checkWidth();\n              }\n\n              x += stack.shift();\n              y += stack.shift();\n              moveTo(x, y);\n              break;\n\n            case 22:\n              // hmoveto\n              if (stack.length > 1) {\n                checkWidth();\n              }\n\n              x += stack.shift();\n              moveTo(x, y);\n              break;\n\n            case 24:\n              // rcurveline\n              while (stack.length >= 8) {\n                var c1x = x + stack.shift();\n                var c1y = y + stack.shift();\n                var c2x = c1x + stack.shift();\n                var c2y = c1y + stack.shift();\n                x = c2x + stack.shift();\n                y = c2y + stack.shift();\n                path.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n              }\n\n              x += stack.shift();\n              y += stack.shift();\n              path.lineTo(x, y);\n              break;\n\n            case 25:\n              // rlinecurve\n              while (stack.length >= 8) {\n                x += stack.shift();\n                y += stack.shift();\n                path.lineTo(x, y);\n              }\n\n              var c1x = x + stack.shift();\n              var c1y = y + stack.shift();\n              var c2x = c1x + stack.shift();\n              var c2y = c1y + stack.shift();\n              x = c2x + stack.shift();\n              y = c2y + stack.shift();\n              path.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n              break;\n\n            case 26:\n              // vvcurveto\n              if (stack.length % 2) {\n                x += stack.shift();\n              }\n\n              while (stack.length >= 4) {\n                c1x = x;\n                c1y = y + stack.shift();\n                c2x = c1x + stack.shift();\n                c2y = c1y + stack.shift();\n                x = c2x;\n                y = c2y + stack.shift();\n                path.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n              }\n              break;\n\n            case 27:\n              // hhcurveto\n              if (stack.length % 2) {\n                y += stack.shift();\n              }\n\n              while (stack.length >= 4) {\n                c1x = x + stack.shift();\n                c1y = y;\n                c2x = c1x + stack.shift();\n                c2y = c1y + stack.shift();\n                x = c2x + stack.shift();\n                y = c2y;\n                path.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n              }\n              break;\n\n            case 28:\n              // shortint\n              stack.push(stream.readInt16BE());\n              break;\n\n            case 29:\n              // callgsubr\n              index = stack.pop() + gsubrsBias;\n              subr = gsubrs[index];\n              if (subr) {\n                usedGsubrs[index] = true;\n                var p = stream.pos;\n                var e = end;\n                stream.pos = subr.offset;\n                end = subr.offset + subr.length;\n                parse();\n                stream.pos = p;\n                end = e;\n              }\n              break;\n\n            case 30: // vhcurveto\n            case 31:\n              // hvcurveto\n              phase = op === 31;\n              while (stack.length >= 4) {\n                if (phase) {\n                  c1x = x + stack.shift();\n                  c1y = y;\n                  c2x = c1x + stack.shift();\n                  c2y = c1y + stack.shift();\n                  y = c2y + stack.shift();\n                  x = c2x + (stack.length === 1 ? stack.shift() : 0);\n                } else {\n                  c1x = x;\n                  c1y = y + stack.shift();\n                  c2x = c1x + stack.shift();\n                  c2y = c1y + stack.shift();\n                  x = c2x + stack.shift();\n                  y = c2y + (stack.length === 1 ? stack.shift() : 0);\n                }\n\n                path.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n                phase = !phase;\n              }\n              break;\n\n            case 12:\n              op = stream.readUInt8();\n              switch (op) {\n                case 3:\n                  // and\n                  var a = stack.pop();\n                  var b = stack.pop();\n                  stack.push(a && b ? 1 : 0);\n                  break;\n\n                case 4:\n                  // or\n                  a = stack.pop();\n                  b = stack.pop();\n                  stack.push(a || b ? 1 : 0);\n                  break;\n\n                case 5:\n                  // not\n                  a = stack.pop();\n                  stack.push(a ? 0 : 1);\n                  break;\n\n                case 9:\n                  // abs\n                  a = stack.pop();\n                  stack.push(Math.abs(a));\n                  break;\n\n                case 10:\n                  // add\n                  a = stack.pop();\n                  b = stack.pop();\n                  stack.push(a + b);\n                  break;\n\n                case 11:\n                  // sub\n                  a = stack.pop();\n                  b = stack.pop();\n                  stack.push(a - b);\n                  break;\n\n                case 12:\n                  // div\n                  a = stack.pop();\n                  b = stack.pop();\n                  stack.push(a / b);\n                  break;\n\n                case 14:\n                  // neg\n                  a = stack.pop();\n                  stack.push(-a);\n                  break;\n\n                case 15:\n                  // eq\n                  a = stack.pop();\n                  b = stack.pop();\n                  stack.push(a === b ? 1 : 0);\n                  break;\n\n                case 18:\n                  // drop\n                  stack.pop();\n                  break;\n\n                case 20:\n                  // put\n                  var val = stack.pop();\n                  var idx = stack.pop();\n                  trans[idx] = val;\n                  break;\n\n                case 21:\n                  // get\n                  idx = stack.pop();\n                  stack.push(trans[idx] || 0);\n                  break;\n\n                case 22:\n                  // ifelse\n                  var s1 = stack.pop();\n                  var s2 = stack.pop();\n                  var v1 = stack.pop();\n                  var v2 = stack.pop();\n                  stack.push(v1 <= v2 ? s1 : s2);\n                  break;\n\n                case 23:\n                  // random\n                  stack.push(Math.random());\n                  break;\n\n                case 24:\n                  // mul\n                  a = stack.pop();\n                  b = stack.pop();\n                  stack.push(a * b);\n                  break;\n\n                case 26:\n                  // sqrt\n                  a = stack.pop();\n                  stack.push(Math.sqrt(a));\n                  break;\n\n                case 27:\n                  // dup\n                  a = stack.pop();\n                  stack.push(a, a);\n                  break;\n\n                case 28:\n                  // exch\n                  a = stack.pop();\n                  b = stack.pop();\n                  stack.push(b, a);\n                  break;\n\n                case 29:\n                  // index\n                  idx = stack.pop();\n                  if (idx < 0) {\n                    idx = 0;\n                  } else if (idx > stack.length - 1) {\n                    idx = stack.length - 1;\n                  }\n\n                  stack.push(stack[idx]);\n                  break;\n\n                case 30:\n                  // roll\n                  var n = stack.pop();\n                  var _j = stack.pop();\n\n                  if (_j >= 0) {\n                    while (_j > 0) {\n                      var t = stack[n - 1];\n                      for (var _i = n - 2; _i >= 0; _i--) {\n                        stack[_i + 1] = stack[_i];\n                      }\n\n                      stack[0] = t;\n                      _j--;\n                    }\n                  } else {\n                    while (_j < 0) {\n                      var t = stack[0];\n                      for (var _i2 = 0; _i2 <= n; _i2++) {\n                        stack[_i2] = stack[_i2 + 1];\n                      }\n\n                      stack[n - 1] = t;\n                      _j++;\n                    }\n                  }\n                  break;\n\n                case 34:\n                  // hflex\n                  c1x = x + stack.shift();\n                  c1y = y;\n                  c2x = c1x + stack.shift();\n                  c2y = c1y + stack.shift();\n                  var c3x = c2x + stack.shift();\n                  var c3y = c2y;\n                  var c4x = c3x + stack.shift();\n                  var c4y = c3y;\n                  var c5x = c4x + stack.shift();\n                  var c5y = c4y;\n                  var c6x = c5x + stack.shift();\n                  var c6y = c5y;\n                  x = c6x;\n                  y = c6y;\n\n                  path.bezierCurveTo(c1x, c1y, c2x, c2y, c3x, c3y);\n                  path.bezierCurveTo(c4x, c4y, c5x, c5y, c6x, c6y);\n                  break;\n\n                case 35:\n                  // flex\n                  var pts = [];\n\n                  for (var _i3 = 0; _i3 <= 5; _i3++) {\n                    x += stack.shift();\n                    y += stack.shift();\n                    pts.push(x, y);\n                  }\n\n                  path.bezierCurveTo.apply(path, pts.slice(0, 6));\n                  path.bezierCurveTo.apply(path, pts.slice(6));\n                  stack.shift(); // fd\n                  break;\n\n                case 36:\n                  // hflex1\n                  c1x = x + stack.shift();\n                  c1y = y + stack.shift();\n                  c2x = c1x + stack.shift();\n                  c2y = c1y + stack.shift();\n                  c3x = c2x + stack.shift();\n                  c3y = c2y;\n                  c4x = c3x + stack.shift();\n                  c4y = c3y;\n                  c5x = c4x + stack.shift();\n                  c5y = c4y + stack.shift();\n                  c6x = c5x + stack.shift();\n                  c6y = c5y;\n                  x = c6x;\n                  y = c6y;\n\n                  path.bezierCurveTo(c1x, c1y, c2x, c2y, c3x, c3y);\n                  path.bezierCurveTo(c4x, c4y, c5x, c5y, c6x, c6y);\n                  break;\n\n                case 37:\n                  // flex1\n                  var startx = x;\n                  var starty = y;\n\n                  pts = [];\n                  for (var _i4 = 0; _i4 <= 4; _i4++) {\n                    x += stack.shift();\n                    y += stack.shift();\n                    pts.push(x, y);\n                  }\n\n                  if (Math.abs(x - startx) > Math.abs(y - starty)) {\n                    // horizontal\n                    x += stack.shift();\n                    y = starty;\n                  } else {\n                    x = startx;\n                    y += stack.shift();\n                  }\n\n                  pts.push(x, y);\n                  path.bezierCurveTo.apply(path, pts.slice(0, 6));\n                  path.bezierCurveTo.apply(path, pts.slice(6));\n                  break;\n\n                default:\n                  throw new Error('Unknown op: 12 ' + op);\n              }\n              break;\n\n            default:\n              throw new Error('Unknown op: ' + op);\n          }\n        } else if (op < 247) {\n          stack.push(op - 139);\n        } else if (op < 251) {\n          var b1 = stream.readUInt8();\n          stack.push((op - 247) * 256 + b1 + 108);\n        } else if (op < 255) {\n          var b1 = stream.readUInt8();\n          stack.push(-(op - 251) * 256 - b1 - 108);\n        } else {\n          stack.push(stream.readInt32BE() / 65536);\n        }\n      }\n    };\n\n    parse();\n\n    if (open) {\n      path.closePath();\n    }\n\n    return path;\n  };\n\n  return CFFGlyph;\n}(Glyph);\n\nvar SBIXImage = new r.Struct({\n  originX: r.uint16,\n  originY: r.uint16,\n  type: new r.String(4),\n  data: new r.Buffer(function (t) {\n    return t.parent.buflen - t._currentOffset;\n  })\n});\n\n/**\n * Represents a color (e.g. emoji) glyph in Apple's SBIX format.\n */\n\nvar SBIXGlyph = function (_TTFGlyph) {\n  _inherits(SBIXGlyph, _TTFGlyph);\n\n  function SBIXGlyph() {\n    _classCallCheck(this, SBIXGlyph);\n\n    return _possibleConstructorReturn(this, _TTFGlyph.apply(this, arguments));\n  }\n\n  /**\n   * Returns an object representing a glyph image at the given point size.\n   * The object has a data property with a Buffer containing the actual image data,\n   * along with the image type, and origin.\n   *\n   * @param {number} size\n   * @return {object}\n   */\n  SBIXGlyph.prototype.getImageForSize = function getImageForSize(size) {\n    for (var i = 0; i < this._font.sbix.imageTables.length; i++) {\n      var table = this._font.sbix.imageTables[i];\n      if (table.ppem >= size) {\n        break;\n      }\n    }\n\n    var offsets = table.imageOffsets;\n    var start = offsets[this.id];\n    var end = offsets[this.id + 1];\n\n    if (start === end) {\n      return null;\n    }\n\n    this._font.stream.pos = start;\n    return SBIXImage.decode(this._font.stream, { buflen: end - start });\n  };\n\n  SBIXGlyph.prototype.render = function render(ctx, size) {\n    var img = this.getImageForSize(size);\n    if (img != null) {\n      var scale = size / this._font.unitsPerEm;\n      ctx.image(img.data, { height: size, x: img.originX, y: (this.bbox.minY - img.originY) * scale });\n    }\n\n    if (this._font.sbix.flags.renderOutlines) {\n      _TTFGlyph.prototype.render.call(this, ctx, size);\n    }\n  };\n\n  return SBIXGlyph;\n}(TTFGlyph);\n\nvar COLRLayer = function COLRLayer(glyph, color) {\n  _classCallCheck(this, COLRLayer);\n\n  this.glyph = glyph;\n  this.color = color;\n};\n\n/**\n * Represents a color (e.g. emoji) glyph in Microsoft's COLR format.\n * Each glyph in this format contain a list of colored layers, each\n * of which  is another vector glyph.\n */\n\n\nvar COLRGlyph = function (_Glyph) {\n  _inherits(COLRGlyph, _Glyph);\n\n  function COLRGlyph() {\n    _classCallCheck(this, COLRGlyph);\n\n    return _possibleConstructorReturn(this, _Glyph.apply(this, arguments));\n  }\n\n  COLRGlyph.prototype._getBBox = function _getBBox() {\n    var bbox = new BBox();\n    for (var i = 0; i < this.layers.length; i++) {\n      var layer = this.layers[i];\n      var b = layer.glyph.bbox;\n      bbox.addPoint(b.minX, b.minY);\n      bbox.addPoint(b.maxX, b.maxY);\n    }\n\n    return bbox;\n  };\n\n  /**\n   * Returns an array of objects containing the glyph and color for\n   * each layer in the composite color glyph.\n   * @type {object[]}\n   */\n\n\n  COLRGlyph.prototype.render = function render(ctx, size) {\n    for (var _iterator = this.layers, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var _ref2 = _ref,\n          glyph = _ref2.glyph,\n          color = _ref2.color;\n\n      ctx.fillColor([color.red, color.green, color.blue], color.alpha / 255 * 100);\n      glyph.render(ctx, size);\n    }\n\n    return;\n  };\n\n  _createClass(COLRGlyph, [{\n    key: 'layers',\n    get: function get() {\n      var cpal = this._font.CPAL;\n      var colr = this._font.COLR;\n      var low = 0;\n      var high = colr.baseGlyphRecord.length - 1;\n\n      while (low <= high) {\n        var mid = low + high >> 1;\n        var rec = colr.baseGlyphRecord[mid];\n\n        if (this.id < rec.gid) {\n          high = mid - 1;\n        } else if (this.id > rec.gid) {\n          low = mid + 1;\n        } else {\n          var baseLayer = rec;\n          break;\n        }\n      }\n\n      // if base glyph not found in COLR table,\n      // default to normal glyph from glyf or CFF\n      if (baseLayer == null) {\n        var g = this._font._getBaseGlyph(this.id);\n        var color = {\n          red: 0,\n          green: 0,\n          blue: 0,\n          alpha: 255\n        };\n\n        return [new COLRLayer(g, color)];\n      }\n\n      // otherwise, return an array of all the layers\n      var layers = [];\n      for (var i = baseLayer.firstLayerIndex; i < baseLayer.firstLayerIndex + baseLayer.numLayers; i++) {\n        var rec = colr.layerRecords[i];\n        var color = cpal.colorRecords[rec.paletteIndex];\n        var g = this._font._getBaseGlyph(rec.gid);\n        layers.push(new COLRLayer(g, color));\n      }\n\n      return layers;\n    }\n  }]);\n\n  return COLRGlyph;\n}(Glyph);\n\nvar TUPLES_SHARE_POINT_NUMBERS = 0x8000;\nvar TUPLE_COUNT_MASK = 0x0fff;\nvar EMBEDDED_TUPLE_COORD = 0x8000;\nvar INTERMEDIATE_TUPLE = 0x4000;\nvar PRIVATE_POINT_NUMBERS = 0x2000;\nvar TUPLE_INDEX_MASK = 0x0fff;\nvar POINTS_ARE_WORDS = 0x80;\nvar POINT_RUN_COUNT_MASK = 0x7f;\nvar DELTAS_ARE_ZERO = 0x80;\nvar DELTAS_ARE_WORDS = 0x40;\nvar DELTA_RUN_COUNT_MASK = 0x3f;\n\n/**\n * This class is transforms TrueType glyphs according to the data from\n * the Apple Advanced Typography variation tables (fvar, gvar, and avar).\n * These tables allow infinite adjustments to glyph weight, width, slant,\n * and optical size without the designer needing to specify every exact style.\n *\n * Apple's documentation for these tables is not great, so thanks to the\n * Freetype project for figuring much of this out.\n *\n * @private\n */\n\nvar GlyphVariationProcessor = function () {\n  function GlyphVariationProcessor(font, coords) {\n    _classCallCheck(this, GlyphVariationProcessor);\n\n    this.font = font;\n    this.normalizedCoords = this.normalizeCoords(coords);\n    this.blendVectors = new _Map();\n  }\n\n  GlyphVariationProcessor.prototype.normalizeCoords = function normalizeCoords(coords) {\n    // the default mapping is linear along each axis, in two segments:\n    // from the minValue to defaultValue, and from defaultValue to maxValue.\n    var normalized = [];\n    for (var i = 0; i < this.font.fvar.axis.length; i++) {\n      var axis = this.font.fvar.axis[i];\n      if (coords[i] < axis.defaultValue) {\n        normalized.push((coords[i] - axis.defaultValue + _Number$EPSILON) / (axis.defaultValue - axis.minValue + _Number$EPSILON));\n      } else {\n        normalized.push((coords[i] - axis.defaultValue + _Number$EPSILON) / (axis.maxValue - axis.defaultValue + _Number$EPSILON));\n      }\n    }\n\n    // if there is an avar table, the normalized value is calculated\n    // by interpolating between the two nearest mapped values.\n    if (this.font.avar) {\n      for (var i = 0; i < this.font.avar.segment.length; i++) {\n        var segment = this.font.avar.segment[i];\n        for (var j = 0; j < segment.correspondence.length; j++) {\n          var pair = segment.correspondence[j];\n          if (j >= 1 && normalized[i] < pair.fromCoord) {\n            var prev = segment.correspondence[j - 1];\n            normalized[i] = ((normalized[i] - prev.fromCoord) * (pair.toCoord - prev.toCoord) + _Number$EPSILON) / (pair.fromCoord - prev.fromCoord + _Number$EPSILON) + prev.toCoord;\n\n            break;\n          }\n        }\n      }\n    }\n\n    return normalized;\n  };\n\n  GlyphVariationProcessor.prototype.transformPoints = function transformPoints(gid, glyphPoints) {\n    if (!this.font.fvar || !this.font.gvar) {\n      return;\n    }\n\n    var gvar = this.font.gvar;\n\n    if (gid >= gvar.glyphCount) {\n      return;\n    }\n\n    var offset = gvar.offsets[gid];\n    if (offset === gvar.offsets[gid + 1]) {\n      return;\n    }\n\n    // Read the gvar data for this glyph\n    var stream = this.font.stream;\n\n    stream.pos = offset;\n    if (stream.pos >= stream.length) {\n      return;\n    }\n\n    var tupleCount = stream.readUInt16BE();\n    var offsetToData = offset + stream.readUInt16BE();\n\n    if (tupleCount & TUPLES_SHARE_POINT_NUMBERS) {\n      var here = stream.pos;\n      stream.pos = offsetToData;\n      var sharedPoints = this.decodePoints();\n      offsetToData = stream.pos;\n      stream.pos = here;\n    }\n\n    var origPoints = glyphPoints.map(function (pt) {\n      return pt.copy();\n    });\n\n    tupleCount &= TUPLE_COUNT_MASK;\n    for (var i = 0; i < tupleCount; i++) {\n      var tupleDataSize = stream.readUInt16BE();\n      var tupleIndex = stream.readUInt16BE();\n\n      if (tupleIndex & EMBEDDED_TUPLE_COORD) {\n        var tupleCoords = [];\n        for (var a = 0; a < gvar.axisCount; a++) {\n          tupleCoords.push(stream.readInt16BE() / 16384);\n        }\n      } else {\n        if ((tupleIndex & TUPLE_INDEX_MASK) >= gvar.globalCoordCount) {\n          throw new Error('Invalid gvar table');\n        }\n\n        var tupleCoords = gvar.globalCoords[tupleIndex & TUPLE_INDEX_MASK];\n      }\n\n      if (tupleIndex & INTERMEDIATE_TUPLE) {\n        var startCoords = [];\n        for (var _a = 0; _a < gvar.axisCount; _a++) {\n          startCoords.push(stream.readInt16BE() / 16384);\n        }\n\n        var endCoords = [];\n        for (var _a2 = 0; _a2 < gvar.axisCount; _a2++) {\n          endCoords.push(stream.readInt16BE() / 16384);\n        }\n      }\n\n      // Get the factor at which to apply this tuple\n      var factor = this.tupleFactor(tupleIndex, tupleCoords, startCoords, endCoords);\n      if (factor === 0) {\n        offsetToData += tupleDataSize;\n        continue;\n      }\n\n      var here = stream.pos;\n      stream.pos = offsetToData;\n\n      if (tupleIndex & PRIVATE_POINT_NUMBERS) {\n        var points = this.decodePoints();\n      } else {\n        var points = sharedPoints;\n      }\n\n      // points.length = 0 means there are deltas for all points\n      var nPoints = points.length === 0 ? glyphPoints.length : points.length;\n      var xDeltas = this.decodeDeltas(nPoints);\n      var yDeltas = this.decodeDeltas(nPoints);\n\n      if (points.length === 0) {\n        // all points\n        for (var _i = 0; _i < glyphPoints.length; _i++) {\n          var point = glyphPoints[_i];\n          point.x += Math.round(xDeltas[_i] * factor);\n          point.y += Math.round(yDeltas[_i] * factor);\n        }\n      } else {\n        var outPoints = origPoints.map(function (pt) {\n          return pt.copy();\n        });\n        var hasDelta = glyphPoints.map(function () {\n          return false;\n        });\n\n        for (var _i2 = 0; _i2 < points.length; _i2++) {\n          var idx = points[_i2];\n          if (idx < glyphPoints.length) {\n            var _point = outPoints[idx];\n            hasDelta[idx] = true;\n\n            _point.x += Math.round(xDeltas[_i2] * factor);\n            _point.y += Math.round(yDeltas[_i2] * factor);\n          }\n        }\n\n        this.interpolateMissingDeltas(outPoints, origPoints, hasDelta);\n\n        for (var _i3 = 0; _i3 < glyphPoints.length; _i3++) {\n          var deltaX = outPoints[_i3].x - origPoints[_i3].x;\n          var deltaY = outPoints[_i3].y - origPoints[_i3].y;\n\n          glyphPoints[_i3].x += deltaX;\n          glyphPoints[_i3].y += deltaY;\n        }\n      }\n\n      offsetToData += tupleDataSize;\n      stream.pos = here;\n    }\n  };\n\n  GlyphVariationProcessor.prototype.decodePoints = function decodePoints() {\n    var stream = this.font.stream;\n    var count = stream.readUInt8();\n\n    if (count & POINTS_ARE_WORDS) {\n      count = (count & POINT_RUN_COUNT_MASK) << 8 | stream.readUInt8();\n    }\n\n    var points = new Uint16Array(count);\n    var i = 0;\n    var point = 0;\n    while (i < count) {\n      var run = stream.readUInt8();\n      var runCount = (run & POINT_RUN_COUNT_MASK) + 1;\n      var fn = run & POINTS_ARE_WORDS ? stream.readUInt16 : stream.readUInt8;\n\n      for (var j = 0; j < runCount && i < count; j++) {\n        point += fn.call(stream);\n        points[i++] = point;\n      }\n    }\n\n    return points;\n  };\n\n  GlyphVariationProcessor.prototype.decodeDeltas = function decodeDeltas(count) {\n    var stream = this.font.stream;\n    var i = 0;\n    var deltas = new Int16Array(count);\n\n    while (i < count) {\n      var run = stream.readUInt8();\n      var runCount = (run & DELTA_RUN_COUNT_MASK) + 1;\n\n      if (run & DELTAS_ARE_ZERO) {\n        i += runCount;\n      } else {\n        var fn = run & DELTAS_ARE_WORDS ? stream.readInt16BE : stream.readInt8;\n        for (var j = 0; j < runCount && i < count; j++) {\n          deltas[i++] = fn.call(stream);\n        }\n      }\n    }\n\n    return deltas;\n  };\n\n  GlyphVariationProcessor.prototype.tupleFactor = function tupleFactor(tupleIndex, tupleCoords, startCoords, endCoords) {\n    var normalized = this.normalizedCoords;\n    var gvar = this.font.gvar;\n\n    var factor = 1;\n\n    for (var i = 0; i < gvar.axisCount; i++) {\n      if (tupleCoords[i] === 0) {\n        continue;\n      }\n\n      if (normalized[i] === 0) {\n        return 0;\n      }\n\n      if ((tupleIndex & INTERMEDIATE_TUPLE) === 0) {\n        if (normalized[i] < Math.min(0, tupleCoords[i]) || normalized[i] > Math.max(0, tupleCoords[i])) {\n          return 0;\n        }\n\n        factor = (factor * normalized[i] + _Number$EPSILON) / (tupleCoords[i] + _Number$EPSILON);\n      } else {\n        if (normalized[i] < startCoords[i] || normalized[i] > endCoords[i]) {\n          return 0;\n        } else if (normalized[i] < tupleCoords[i]) {\n          factor = factor * (normalized[i] - startCoords[i] + _Number$EPSILON) / (tupleCoords[i] - startCoords[i] + _Number$EPSILON);\n        } else {\n          factor = factor * (endCoords[i] - normalized[i] + _Number$EPSILON) / (endCoords[i] - tupleCoords[i] + _Number$EPSILON);\n        }\n      }\n    }\n\n    return factor;\n  };\n\n  // Interpolates points without delta values.\n  // Needed for the Ø and Q glyphs in Skia.\n  // Algorithm from Freetype.\n\n\n  GlyphVariationProcessor.prototype.interpolateMissingDeltas = function interpolateMissingDeltas(points, inPoints, hasDelta) {\n    if (points.length === 0) {\n      return;\n    }\n\n    var point = 0;\n    while (point < points.length) {\n      var firstPoint = point;\n\n      // find the end point of the contour\n      var endPoint = point;\n      var pt = points[endPoint];\n      while (!pt.endContour) {\n        pt = points[++endPoint];\n      }\n\n      // find the first point that has a delta\n      while (point <= endPoint && !hasDelta[point]) {\n        point++;\n      }\n\n      if (point > endPoint) {\n        continue;\n      }\n\n      var firstDelta = point;\n      var curDelta = point;\n      point++;\n\n      while (point <= endPoint) {\n        // find the next point with a delta, and interpolate intermediate points\n        if (hasDelta[point]) {\n          this.deltaInterpolate(curDelta + 1, point - 1, curDelta, point, inPoints, points);\n          curDelta = point;\n        }\n\n        point++;\n      }\n\n      // shift contour if we only have a single delta\n      if (curDelta === firstDelta) {\n        this.deltaShift(firstPoint, endPoint, curDelta, inPoints, points);\n      } else {\n        // otherwise, handle the remaining points at the end and beginning of the contour\n        this.deltaInterpolate(curDelta + 1, endPoint, curDelta, firstDelta, inPoints, points);\n\n        if (firstDelta > 0) {\n          this.deltaInterpolate(firstPoint, firstDelta - 1, curDelta, firstDelta, inPoints, points);\n        }\n      }\n\n      point = endPoint + 1;\n    }\n  };\n\n  GlyphVariationProcessor.prototype.deltaInterpolate = function deltaInterpolate(p1, p2, ref1, ref2, inPoints, outPoints) {\n    if (p1 > p2) {\n      return;\n    }\n\n    var iterable = ['x', 'y'];\n    for (var i = 0; i < iterable.length; i++) {\n      var k = iterable[i];\n      if (inPoints[ref1][k] > inPoints[ref2][k]) {\n        var p = ref1;\n        ref1 = ref2;\n        ref2 = p;\n      }\n\n      var in1 = inPoints[ref1][k];\n      var in2 = inPoints[ref2][k];\n      var out1 = outPoints[ref1][k];\n      var out2 = outPoints[ref2][k];\n\n      // If the reference points have the same coordinate but different\n      // delta, inferred delta is zero.  Otherwise interpolate.\n      if (in1 !== in2 || out1 === out2) {\n        var scale = in1 === in2 ? 0 : (out2 - out1) / (in2 - in1);\n\n        for (var _p = p1; _p <= p2; _p++) {\n          var out = inPoints[_p][k];\n\n          if (out <= in1) {\n            out += out1 - in1;\n          } else if (out >= in2) {\n            out += out2 - in2;\n          } else {\n            out = out1 + (out - in1) * scale;\n          }\n\n          outPoints[_p][k] = out;\n        }\n      }\n    }\n  };\n\n  GlyphVariationProcessor.prototype.deltaShift = function deltaShift(p1, p2, ref, inPoints, outPoints) {\n    var deltaX = outPoints[ref].x - inPoints[ref].x;\n    var deltaY = outPoints[ref].y - inPoints[ref].y;\n\n    if (deltaX === 0 && deltaY === 0) {\n      return;\n    }\n\n    for (var p = p1; p <= p2; p++) {\n      if (p !== ref) {\n        outPoints[p].x += deltaX;\n        outPoints[p].y += deltaY;\n      }\n    }\n  };\n\n  GlyphVariationProcessor.prototype.getAdvanceAdjustment = function getAdvanceAdjustment(gid, table) {\n    var outerIndex = void 0,\n        innerIndex = void 0;\n\n    if (table.advanceWidthMapping) {\n      var idx = gid;\n      if (idx >= table.advanceWidthMapping.mapCount) {\n        idx = table.advanceWidthMapping.mapCount - 1;\n      }\n\n      var entryFormat = table.advanceWidthMapping.entryFormat;\n      var _table$advanceWidthMa = table.advanceWidthMapping.mapData[idx];\n      outerIndex = _table$advanceWidthMa.outerIndex;\n      innerIndex = _table$advanceWidthMa.innerIndex;\n    } else {\n      outerIndex = 0;\n      innerIndex = gid;\n    }\n\n    return this.getDelta(table.itemVariationStore, outerIndex, innerIndex);\n  };\n\n  // See pseudo code from `Font Variations Overview'\n  // in the OpenType specification.\n\n\n  GlyphVariationProcessor.prototype.getDelta = function getDelta(itemStore, outerIndex, innerIndex) {\n    if (outerIndex >= itemStore.itemVariationData.length) {\n      return 0;\n    }\n\n    var varData = itemStore.itemVariationData[outerIndex];\n    if (innerIndex >= varData.deltaSets.length) {\n      return 0;\n    }\n\n    var deltaSet = varData.deltaSets[innerIndex];\n    var blendVector = this.getBlendVector(itemStore, outerIndex);\n    var netAdjustment = 0;\n\n    for (var master = 0; master < varData.regionIndexCount; master++) {\n      netAdjustment += deltaSet.deltas[master] * blendVector[master];\n    }\n\n    return netAdjustment;\n  };\n\n  GlyphVariationProcessor.prototype.getBlendVector = function getBlendVector(itemStore, outerIndex) {\n    var varData = itemStore.itemVariationData[outerIndex];\n    if (this.blendVectors.has(varData)) {\n      return this.blendVectors.get(varData);\n    }\n\n    var normalizedCoords = this.normalizedCoords;\n    var blendVector = [];\n\n    // outer loop steps through master designs to be blended\n    for (var master = 0; master < varData.regionIndexCount; master++) {\n      var scalar = 1;\n      var regionIndex = varData.regionIndexes[master];\n      var axes = itemStore.variationRegionList.variationRegions[regionIndex];\n\n      // inner loop steps through axes in this region\n      for (var j = 0; j < axes.length; j++) {\n        var axis = axes[j];\n        var axisScalar = void 0;\n\n        // compute the scalar contribution of this axis\n        // ignore invalid ranges\n        if (axis.startCoord > axis.peakCoord || axis.peakCoord > axis.endCoord) {\n          axisScalar = 1;\n        } else if (axis.startCoord < 0 && axis.endCoord > 0 && axis.peakCoord !== 0) {\n          axisScalar = 1;\n\n          // peak of 0 means ignore this axis\n        } else if (axis.peakCoord === 0) {\n          axisScalar = 1;\n\n          // ignore this region if coords are out of range\n        } else if (normalizedCoords[j] < axis.startCoord || normalizedCoords[j] > axis.endCoord) {\n          axisScalar = 0;\n\n          // calculate a proportional factor\n        } else {\n          if (normalizedCoords[j] === axis.peakCoord) {\n            axisScalar = 1;\n          } else if (normalizedCoords[j] < axis.peakCoord) {\n            axisScalar = (normalizedCoords[j] - axis.startCoord + _Number$EPSILON) / (axis.peakCoord - axis.startCoord + _Number$EPSILON);\n          } else {\n            axisScalar = (axis.endCoord - normalizedCoords[j] + _Number$EPSILON) / (axis.endCoord - axis.peakCoord + _Number$EPSILON);\n          }\n        }\n\n        // take product of all the axis scalars\n        scalar *= axisScalar;\n      }\n\n      blendVector[master] = scalar;\n    }\n\n    this.blendVectors.set(varData, blendVector);\n    return blendVector;\n  };\n\n  return GlyphVariationProcessor;\n}();\n\nvar Subset = function () {\n  function Subset(font) {\n    _classCallCheck(this, Subset);\n\n    this.font = font;\n    this.glyphs = [];\n    this.mapping = {};\n\n    // always include the missing glyph\n    this.includeGlyph(0);\n  }\n\n  Subset.prototype.includeGlyph = function includeGlyph(glyph) {\n    if ((typeof glyph === 'undefined' ? 'undefined' : _typeof(glyph)) === 'object') {\n      glyph = glyph.id;\n    }\n\n    if (this.mapping[glyph] == null) {\n      this.glyphs.push(glyph);\n      this.mapping[glyph] = this.glyphs.length - 1;\n    }\n\n    return this.mapping[glyph];\n  };\n\n  Subset.prototype.encodeStream = function encodeStream() {\n    var _this = this;\n\n    var s = new r.EncodeStream();\n\n    process.nextTick(function () {\n      _this.encode(s);\n      return s.end();\n    });\n\n    return s;\n  };\n\n  return Subset;\n}();\n\n// Flags for simple glyphs\nvar ON_CURVE$1 = 1 << 0;\nvar X_SHORT_VECTOR$1 = 1 << 1;\nvar Y_SHORT_VECTOR$1 = 1 << 2;\nvar REPEAT$1 = 1 << 3;\nvar SAME_X$1 = 1 << 4;\nvar SAME_Y$1 = 1 << 5;\n\nvar Point$1 = function () {\n  function Point() {\n    _classCallCheck(this, Point);\n  }\n\n  Point.size = function size(val) {\n    return val >= 0 && val <= 255 ? 1 : 2;\n  };\n\n  Point.encode = function encode(stream, value) {\n    if (value >= 0 && value <= 255) {\n      stream.writeUInt8(value);\n    } else {\n      stream.writeInt16BE(value);\n    }\n  };\n\n  return Point;\n}();\n\nvar Glyf = new r.Struct({\n  numberOfContours: r.int16, // if negative, this is a composite glyph\n  xMin: r.int16,\n  yMin: r.int16,\n  xMax: r.int16,\n  yMax: r.int16,\n  endPtsOfContours: new r.Array(r.uint16, 'numberOfContours'),\n  instructions: new r.Array(r.uint8, r.uint16),\n  flags: new r.Array(r.uint8, 0),\n  xPoints: new r.Array(Point$1, 0),\n  yPoints: new r.Array(Point$1, 0)\n});\n\n/**\n * Encodes TrueType glyph outlines\n */\n\nvar TTFGlyphEncoder = function () {\n  function TTFGlyphEncoder() {\n    _classCallCheck(this, TTFGlyphEncoder);\n  }\n\n  TTFGlyphEncoder.prototype.encodeSimple = function encodeSimple(path) {\n    var instructions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n\n    var endPtsOfContours = [];\n    var xPoints = [];\n    var yPoints = [];\n    var flags = [];\n    var same = 0;\n    var lastX = 0,\n        lastY = 0,\n        lastFlag = 0;\n    var pointCount = 0;\n\n    for (var i = 0; i < path.commands.length; i++) {\n      var c = path.commands[i];\n\n      for (var j = 0; j < c.args.length; j += 2) {\n        var x = c.args[j];\n        var y = c.args[j + 1];\n        var flag = 0;\n\n        // If the ending point of a quadratic curve is the midpoint\n        // between the control point and the control point of the next\n        // quadratic curve, we can omit the ending point.\n        if (c.command === 'quadraticCurveTo' && j === 2) {\n          var next = path.commands[i + 1];\n          if (next && next.command === 'quadraticCurveTo') {\n            var midX = (lastX + next.args[0]) / 2;\n            var midY = (lastY + next.args[1]) / 2;\n\n            if (x === midX && y === midY) {\n              continue;\n            }\n          }\n        }\n\n        // All points except control points are on curve.\n        if (!(c.command === 'quadraticCurveTo' && j === 0)) {\n          flag |= ON_CURVE$1;\n        }\n\n        flag = this._encodePoint(x, lastX, xPoints, flag, X_SHORT_VECTOR$1, SAME_X$1);\n        flag = this._encodePoint(y, lastY, yPoints, flag, Y_SHORT_VECTOR$1, SAME_Y$1);\n\n        if (flag === lastFlag && same < 255) {\n          flags[flags.length - 1] |= REPEAT$1;\n          same++;\n        } else {\n          if (same > 0) {\n            flags.push(same);\n            same = 0;\n          }\n\n          flags.push(flag);\n          lastFlag = flag;\n        }\n\n        lastX = x;\n        lastY = y;\n        pointCount++;\n      }\n\n      if (c.command === 'closePath') {\n        endPtsOfContours.push(pointCount - 1);\n      }\n    }\n\n    // Close the path if the last command didn't already\n    if (path.commands.length > 1 && path.commands[path.commands.length - 1].command !== 'closePath') {\n      endPtsOfContours.push(pointCount - 1);\n    }\n\n    var bbox = path.bbox;\n    var glyf = {\n      numberOfContours: endPtsOfContours.length,\n      xMin: bbox.minX,\n      yMin: bbox.minY,\n      xMax: bbox.maxX,\n      yMax: bbox.maxY,\n      endPtsOfContours: endPtsOfContours,\n      instructions: instructions,\n      flags: flags,\n      xPoints: xPoints,\n      yPoints: yPoints\n    };\n\n    var size = Glyf.size(glyf);\n    var tail = 4 - size % 4;\n\n    var stream = new r.EncodeStream(size + tail);\n    Glyf.encode(stream, glyf);\n\n    // Align to 4-byte length\n    if (tail !== 0) {\n      stream.fill(0, tail);\n    }\n\n    return stream.buffer;\n  };\n\n  TTFGlyphEncoder.prototype._encodePoint = function _encodePoint(value, last, points, flag, shortFlag, sameFlag) {\n    var diff = value - last;\n\n    if (value === last) {\n      flag |= sameFlag;\n    } else {\n      if (-255 <= diff && diff <= 255) {\n        flag |= shortFlag;\n        if (diff < 0) {\n          diff = -diff;\n        } else {\n          flag |= sameFlag;\n        }\n      }\n\n      points.push(diff);\n    }\n\n    return flag;\n  };\n\n  return TTFGlyphEncoder;\n}();\n\nvar TTFSubset = function (_Subset) {\n  _inherits(TTFSubset, _Subset);\n\n  function TTFSubset(font) {\n    _classCallCheck(this, TTFSubset);\n\n    var _this = _possibleConstructorReturn(this, _Subset.call(this, font));\n\n    _this.glyphEncoder = new TTFGlyphEncoder();\n    return _this;\n  }\n\n  TTFSubset.prototype._addGlyph = function _addGlyph(gid) {\n    var glyph = this.font.getGlyph(gid);\n    var glyf = glyph._decode();\n\n    // get the offset to the glyph from the loca table\n    var curOffset = this.font.loca.offsets[gid];\n    var nextOffset = this.font.loca.offsets[gid + 1];\n\n    var stream = this.font._getTableStream('glyf');\n    stream.pos += curOffset;\n\n    var buffer = stream.readBuffer(nextOffset - curOffset);\n\n    // if it is a compound glyph, include its components\n    if (glyf && glyf.numberOfContours < 0) {\n      buffer = new Buffer(buffer);\n      for (var _iterator = glyf.components, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n        var _ref;\n\n        if (_isArray) {\n          if (_i >= _iterator.length) break;\n          _ref = _iterator[_i++];\n        } else {\n          _i = _iterator.next();\n          if (_i.done) break;\n          _ref = _i.value;\n        }\n\n        var component = _ref;\n\n        gid = this.includeGlyph(component.glyphID);\n        buffer.writeUInt16BE(gid, component.pos);\n      }\n    } else if (glyf && this.font._variationProcessor) {\n      // If this is a TrueType variation glyph, re-encode the path\n      buffer = this.glyphEncoder.encodeSimple(glyph.path, glyf.instructions);\n    }\n\n    this.glyf.push(buffer);\n    this.loca.offsets.push(this.offset);\n\n    this.hmtx.metrics.push({\n      advance: glyph.advanceWidth,\n      bearing: glyph._getMetrics().leftBearing\n    });\n\n    this.offset += buffer.length;\n    return this.glyf.length - 1;\n  };\n\n  TTFSubset.prototype.encode = function encode(stream) {\n    // tables required by PDF spec:\n    //   head, hhea, loca, maxp, cvt , prep, glyf, hmtx, fpgm\n    //\n    // additional tables required for standalone fonts:\n    //   name, cmap, OS/2, post\n\n    this.glyf = [];\n    this.offset = 0;\n    this.loca = {\n      offsets: []\n    };\n\n    this.hmtx = {\n      metrics: [],\n      bearings: []\n    };\n\n    // include all the glyphs\n    // not using a for loop because we need to support adding more\n    // glyphs to the array as we go, and CoffeeScript caches the length.\n    var i = 0;\n    while (i < this.glyphs.length) {\n      this._addGlyph(this.glyphs[i++]);\n    }\n\n    var maxp = cloneDeep(this.font.maxp);\n    maxp.numGlyphs = this.glyf.length;\n\n    this.loca.offsets.push(this.offset);\n    tables.loca.preEncode.call(this.loca);\n\n    var head = cloneDeep(this.font.head);\n    head.indexToLocFormat = this.loca.version;\n\n    var hhea = cloneDeep(this.font.hhea);\n    hhea.numberOfMetrics = this.hmtx.metrics.length;\n\n    // map = []\n    // for index in [0...256]\n    //     if index < @numGlyphs\n    //         map[index] = index\n    //     else\n    //         map[index] = 0\n    //\n    // cmapTable =\n    //     version: 0\n    //     length: 262\n    //     language: 0\n    //     codeMap: map\n    //\n    // cmap =\n    //     version: 0\n    //     numSubtables: 1\n    //     tables: [\n    //         platformID: 1\n    //         encodingID: 0\n    //         table: cmapTable\n    //     ]\n\n    // TODO: subset prep, cvt, fpgm?\n    Directory.encode(stream, {\n      tables: {\n        head: head,\n        hhea: hhea,\n        loca: this.loca,\n        maxp: maxp,\n        'cvt ': this.font['cvt '],\n        prep: this.font.prep,\n        glyf: this.glyf,\n        hmtx: this.hmtx,\n        fpgm: this.font.fpgm\n\n        // name: clone @font.name\n        // 'OS/2': clone @font['OS/2']\n        // post: clone @font.post\n        // cmap: cmap\n      }\n    });\n  };\n\n  return TTFSubset;\n}(Subset);\n\nvar CFFSubset = function (_Subset) {\n  _inherits(CFFSubset, _Subset);\n\n  function CFFSubset(font) {\n    _classCallCheck(this, CFFSubset);\n\n    var _this = _possibleConstructorReturn(this, _Subset.call(this, font));\n\n    _this.cff = _this.font['CFF '];\n    if (!_this.cff) {\n      throw new Error('Not a CFF Font');\n    }\n    return _this;\n  }\n\n  CFFSubset.prototype.subsetCharstrings = function subsetCharstrings() {\n    this.charstrings = [];\n    var gsubrs = {};\n\n    for (var _iterator = this.glyphs, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var gid = _ref;\n\n      this.charstrings.push(this.cff.getCharString(gid));\n\n      var glyph = this.font.getGlyph(gid);\n      var path = glyph.path; // this causes the glyph to be parsed\n\n      for (var subr in glyph._usedGsubrs) {\n        gsubrs[subr] = true;\n      }\n    }\n\n    this.gsubrs = this.subsetSubrs(this.cff.globalSubrIndex, gsubrs);\n  };\n\n  CFFSubset.prototype.subsetSubrs = function subsetSubrs(subrs, used) {\n    var res = [];\n    for (var i = 0; i < subrs.length; i++) {\n      var subr = subrs[i];\n      if (used[i]) {\n        this.cff.stream.pos = subr.offset;\n        res.push(this.cff.stream.readBuffer(subr.length));\n      } else {\n        res.push(new Buffer([11])); // return\n      }\n    }\n\n    return res;\n  };\n\n  CFFSubset.prototype.subsetFontdict = function subsetFontdict(topDict) {\n    topDict.FDArray = [];\n    topDict.FDSelect = {\n      version: 0,\n      fds: []\n    };\n\n    var used_fds = {};\n    var used_subrs = [];\n    for (var _iterator2 = this.glyphs, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n      var _ref2;\n\n      if (_isArray2) {\n        if (_i2 >= _iterator2.length) break;\n        _ref2 = _iterator2[_i2++];\n      } else {\n        _i2 = _iterator2.next();\n        if (_i2.done) break;\n        _ref2 = _i2.value;\n      }\n\n      var gid = _ref2;\n\n      var fd = this.cff.fdForGlyph(gid);\n      if (fd == null) {\n        continue;\n      }\n\n      if (!used_fds[fd]) {\n        topDict.FDArray.push(_Object$assign({}, this.cff.topDict.FDArray[fd]));\n        used_subrs.push({});\n      }\n\n      used_fds[fd] = true;\n      topDict.FDSelect.fds.push(topDict.FDArray.length - 1);\n\n      var glyph = this.font.getGlyph(gid);\n      var path = glyph.path; // this causes the glyph to be parsed\n      for (var subr in glyph._usedSubrs) {\n        used_subrs[used_subrs.length - 1][subr] = true;\n      }\n    }\n\n    for (var i = 0; i < topDict.FDArray.length; i++) {\n      var dict = topDict.FDArray[i];\n      delete dict.FontName;\n      if (dict.Private && dict.Private.Subrs) {\n        dict.Private = _Object$assign({}, dict.Private);\n        dict.Private.Subrs = this.subsetSubrs(dict.Private.Subrs, used_subrs[i]);\n      }\n    }\n\n    return;\n  };\n\n  CFFSubset.prototype.createCIDFontdict = function createCIDFontdict(topDict) {\n    var used_subrs = {};\n    for (var _iterator3 = this.glyphs, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n      var _ref3;\n\n      if (_isArray3) {\n        if (_i3 >= _iterator3.length) break;\n        _ref3 = _iterator3[_i3++];\n      } else {\n        _i3 = _iterator3.next();\n        if (_i3.done) break;\n        _ref3 = _i3.value;\n      }\n\n      var gid = _ref3;\n\n      var glyph = this.font.getGlyph(gid);\n      var path = glyph.path; // this causes the glyph to be parsed\n\n      for (var subr in glyph._usedSubrs) {\n        used_subrs[subr] = true;\n      }\n    }\n\n    var privateDict = _Object$assign({}, this.cff.topDict.Private);\n    privateDict.Subrs = this.subsetSubrs(this.cff.topDict.Private.Subrs, used_subrs);\n\n    topDict.FDArray = [{ Private: privateDict }];\n    return topDict.FDSelect = {\n      version: 3,\n      nRanges: 1,\n      ranges: [{ first: 0, fd: 0 }],\n      sentinel: this.charstrings.length\n    };\n  };\n\n  CFFSubset.prototype.addString = function addString(string) {\n    if (!string) {\n      return null;\n    }\n\n    if (!this.strings) {\n      this.strings = [];\n    }\n\n    this.strings.push(string);\n    return standardStrings.length + this.strings.length - 1;\n  };\n\n  CFFSubset.prototype.encode = function encode(stream) {\n    this.subsetCharstrings();\n\n    var charset = {\n      version: this.charstrings.length > 255 ? 2 : 1,\n      ranges: [{ first: 1, nLeft: this.charstrings.length - 2 }]\n    };\n\n    var topDict = _Object$assign({}, this.cff.topDict);\n    topDict.Private = null;\n    topDict.charset = charset;\n    topDict.Encoding = null;\n    topDict.CharStrings = this.charstrings;\n\n    var _arr = ['version', 'Notice', 'Copyright', 'FullName', 'FamilyName', 'Weight', 'PostScript', 'BaseFontName', 'FontName'];\n    for (var _i4 = 0; _i4 < _arr.length; _i4++) {\n      var key = _arr[_i4];\n      topDict[key] = this.addString(this.cff.string(topDict[key]));\n    }\n\n    topDict.ROS = [this.addString('Adobe'), this.addString('Identity'), 0];\n    topDict.CIDCount = this.charstrings.length;\n\n    if (this.cff.isCIDFont) {\n      this.subsetFontdict(topDict);\n    } else {\n      this.createCIDFontdict(topDict);\n    }\n\n    var top = {\n      version: 1,\n      hdrSize: this.cff.hdrSize,\n      offSize: this.cff.length,\n      header: this.cff.header,\n      nameIndex: [this.cff.postscriptName],\n      topDictIndex: [topDict],\n      stringIndex: this.strings,\n      globalSubrIndex: this.gsubrs\n    };\n\n    CFFTop.encode(stream, top);\n  };\n\n  return CFFSubset;\n}(Subset);\n\nvar _class;\nfunction _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {\n  var desc = {};\n  Object['ke' + 'ys'](descriptor).forEach(function (key) {\n    desc[key] = descriptor[key];\n  });\n  desc.enumerable = !!desc.enumerable;\n  desc.configurable = !!desc.configurable;\n\n  if ('value' in desc || desc.initializer) {\n    desc.writable = true;\n  }\n\n  desc = decorators.slice().reverse().reduce(function (desc, decorator) {\n    return decorator(target, property, desc) || desc;\n  }, desc);\n\n  if (context && desc.initializer !== void 0) {\n    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;\n    desc.initializer = undefined;\n  }\n\n  if (desc.initializer === void 0) {\n    Object['define' + 'Property'](target, property, desc);\n    desc = null;\n  }\n\n  return desc;\n}\n\n/**\n * This is the base class for all SFNT-based font formats in fontkit.\n * It supports TrueType, and PostScript glyphs, and several color glyph formats.\n */\nvar TTFFont = (_class = function () {\n  TTFFont.probe = function probe(buffer) {\n    var format = buffer.toString('ascii', 0, 4);\n    return format === 'true' || format === 'OTTO' || format === String.fromCharCode(0, 1, 0, 0);\n  };\n\n  function TTFFont(stream) {\n    var variationCoords = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n\n    _classCallCheck(this, TTFFont);\n\n    this.stream = stream;\n    this.variationCoords = variationCoords;\n\n    this._directoryPos = this.stream.pos;\n    this._tables = {};\n    this._glyphs = {};\n    this._decodeDirectory();\n\n    // define properties for each table to lazily parse\n    for (var tag in this.directory.tables) {\n      var table = this.directory.tables[tag];\n      if (tables[tag] && table.length > 0) {\n        _Object$defineProperty(this, tag, {\n          get: this._getTable.bind(this, table)\n        });\n      }\n    }\n  }\n\n  TTFFont.prototype._getTable = function _getTable(table) {\n    if (!(table.tag in this._tables)) {\n      try {\n        this._tables[table.tag] = this._decodeTable(table);\n      } catch (e) {\n        if (fontkit.logErrors) {\n          console.error('Error decoding table ' + table.tag);\n          console.error(e.stack);\n        }\n      }\n    }\n\n    return this._tables[table.tag];\n  };\n\n  TTFFont.prototype._getTableStream = function _getTableStream(tag) {\n    var table = this.directory.tables[tag];\n    if (table) {\n      this.stream.pos = table.offset;\n      return this.stream;\n    }\n\n    return null;\n  };\n\n  TTFFont.prototype._decodeDirectory = function _decodeDirectory() {\n    return this.directory = Directory.decode(this.stream, { _startOffset: 0 });\n  };\n\n  TTFFont.prototype._decodeTable = function _decodeTable(table) {\n    var pos = this.stream.pos;\n\n    var stream = this._getTableStream(table.tag);\n    var result = tables[table.tag].decode(stream, this, table.length);\n\n    this.stream.pos = pos;\n    return result;\n  };\n\n  /**\n   * The unique PostScript name for this font\n   * @type {string}\n   */\n\n\n  /**\n   * Gets a string from the font's `name` table\n   * `lang` is a BCP-47 language code.\n   * @return {string}\n   */\n  TTFFont.prototype.getName = function getName(key) {\n    var lang = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'en';\n\n    var record = this.name.records[key];\n    if (record) {\n      return record[lang];\n    }\n\n    return null;\n  };\n\n  /**\n   * The font's full name, e.g. \"Helvetica Bold\"\n   * @type {string}\n   */\n\n\n  /**\n   * Returns whether there is glyph in the font for the given unicode code point.\n   *\n   * @param {number} codePoint\n   * @return {boolean}\n   */\n  TTFFont.prototype.hasGlyphForCodePoint = function hasGlyphForCodePoint(codePoint) {\n    return !!this._cmapProcessor.lookup(codePoint);\n  };\n\n  /**\n   * Maps a single unicode code point to a Glyph object.\n   * Does not perform any advanced substitutions (there is no context to do so).\n   *\n   * @param {number} codePoint\n   * @return {Glyph}\n   */\n\n\n  TTFFont.prototype.glyphForCodePoint = function glyphForCodePoint(codePoint) {\n    return this.getGlyph(this._cmapProcessor.lookup(codePoint), [codePoint]);\n  };\n\n  /**\n   * Returns an array of Glyph objects for the given string.\n   * This is only a one-to-one mapping from characters to glyphs.\n   * For most uses, you should use font.layout (described below), which\n   * provides a much more advanced mapping supporting AAT and OpenType shaping.\n   *\n   * @param {string} string\n   * @return {Glyph[]}\n   */\n\n\n  TTFFont.prototype.glyphsForString = function glyphsForString(string) {\n    var glyphs = [];\n    var len = string.length;\n    var idx = 0;\n    var last = -1;\n    var state = -1;\n\n    while (idx <= len) {\n      var code = 0;\n      var nextState = 0;\n\n      if (idx < len) {\n        // Decode the next codepoint from UTF 16\n        code = string.charCodeAt(idx++);\n        if (0xd800 <= code && code <= 0xdbff && idx < len) {\n          var next = string.charCodeAt(idx);\n          if (0xdc00 <= next && next <= 0xdfff) {\n            idx++;\n            code = ((code & 0x3ff) << 10) + (next & 0x3ff) + 0x10000;\n          }\n        }\n\n        // Compute the next state: 1 if the next codepoint is a variation selector, 0 otherwise.\n        nextState = 0xfe00 <= code && code <= 0xfe0f || 0xe0100 <= code && code <= 0xe01ef ? 1 : 0;\n      } else {\n        idx++;\n      }\n\n      if (state === 0 && nextState === 1) {\n        // Variation selector following normal codepoint.\n        glyphs.push(this.getGlyph(this._cmapProcessor.lookup(last, code), [last, code]));\n      } else if (state === 0 && nextState === 0) {\n        // Normal codepoint following normal codepoint.\n        glyphs.push(this.glyphForCodePoint(last));\n      }\n\n      last = code;\n      state = nextState;\n    }\n\n    return glyphs;\n  };\n\n  /**\n   * Returns a GlyphRun object, which includes an array of Glyphs and GlyphPositions for the given string.\n   *\n   * @param {string} string\n   * @param {string[]} [userFeatures]\n   * @param {string} [script]\n   * @param {string} [language]\n   * @param {string} [direction]\n   * @return {GlyphRun}\n   */\n  TTFFont.prototype.layout = function layout(string, userFeatures, script, language, direction) {\n    return this._layoutEngine.layout(string, userFeatures, script, language, direction);\n  };\n\n  /**\n   * Returns an array of strings that map to the given glyph id.\n   * @param {number} gid - glyph id\n   */\n\n\n  TTFFont.prototype.stringsForGlyph = function stringsForGlyph(gid) {\n    return this._layoutEngine.stringsForGlyph(gid);\n  };\n\n  /**\n   * An array of all [OpenType feature tags](https://www.microsoft.com/typography/otspec/featuretags.htm)\n   * (or mapped AAT tags) supported by the font.\n   * The features parameter is an array of OpenType feature tags to be applied in addition to the default set.\n   * If this is an AAT font, the OpenType feature tags are mapped to AAT features.\n   *\n   * @type {string[]}\n   */\n\n\n  TTFFont.prototype.getAvailableFeatures = function getAvailableFeatures(script, language) {\n    return this._layoutEngine.getAvailableFeatures(script, language);\n  };\n\n  TTFFont.prototype._getBaseGlyph = function _getBaseGlyph(glyph) {\n    var characters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n\n    if (!this._glyphs[glyph]) {\n      if (this.directory.tables.glyf) {\n        this._glyphs[glyph] = new TTFGlyph(glyph, characters, this);\n      } else if (this.directory.tables['CFF '] || this.directory.tables.CFF2) {\n        this._glyphs[glyph] = new CFFGlyph(glyph, characters, this);\n      }\n    }\n\n    return this._glyphs[glyph] || null;\n  };\n\n  /**\n   * Returns a glyph object for the given glyph id.\n   * You can pass the array of code points this glyph represents for\n   * your use later, and it will be stored in the glyph object.\n   *\n   * @param {number} glyph\n   * @param {number[]} characters\n   * @return {Glyph}\n   */\n\n\n  TTFFont.prototype.getGlyph = function getGlyph(glyph) {\n    var characters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n\n    if (!this._glyphs[glyph]) {\n      if (this.directory.tables.sbix) {\n        this._glyphs[glyph] = new SBIXGlyph(glyph, characters, this);\n      } else if (this.directory.tables.COLR && this.directory.tables.CPAL) {\n        this._glyphs[glyph] = new COLRGlyph(glyph, characters, this);\n      } else {\n        this._getBaseGlyph(glyph, characters);\n      }\n    }\n\n    return this._glyphs[glyph] || null;\n  };\n\n  /**\n   * Returns a Subset for this font.\n   * @return {Subset}\n   */\n\n\n  TTFFont.prototype.createSubset = function createSubset() {\n    if (this.directory.tables['CFF ']) {\n      return new CFFSubset(this);\n    }\n\n    return new TTFSubset(this);\n  };\n\n  /**\n   * Returns an object describing the available variation axes\n   * that this font supports. Keys are setting tags, and values\n   * contain the axis name, range, and default value.\n   *\n   * @type {object}\n   */\n\n\n  /**\n   * Returns a new font with the given variation settings applied.\n   * Settings can either be an instance name, or an object containing\n   * variation tags as specified by the `variationAxes` property.\n   *\n   * @param {object} settings\n   * @return {TTFFont}\n   */\n  TTFFont.prototype.getVariation = function getVariation(settings) {\n    if (!(this.directory.tables.fvar && (this.directory.tables.gvar && this.directory.tables.glyf || this.directory.tables.CFF2))) {\n      throw new Error('Variations require a font with the fvar, gvar and glyf, or CFF2 tables.');\n    }\n\n    if (typeof settings === 'string') {\n      settings = this.namedVariations[settings];\n    }\n\n    if ((typeof settings === 'undefined' ? 'undefined' : _typeof(settings)) !== 'object') {\n      throw new Error('Variation settings must be either a variation name or settings object.');\n    }\n\n    // normalize the coordinates\n    var coords = this.fvar.axis.map(function (axis, i) {\n      var axisTag = axis.axisTag.trim();\n      if (axisTag in settings) {\n        return Math.max(axis.minValue, Math.min(axis.maxValue, settings[axisTag]));\n      } else {\n        return axis.defaultValue;\n      }\n    });\n\n    var stream = new r.DecodeStream(this.stream.buffer);\n    stream.pos = this._directoryPos;\n\n    var font = new TTFFont(stream, coords);\n    font._tables = this._tables;\n\n    return font;\n  };\n\n  // Standardized format plugin API\n  TTFFont.prototype.getFont = function getFont(name) {\n    return this.getVariation(name);\n  };\n\n  _createClass(TTFFont, [{\n    key: 'postscriptName',\n    get: function get() {\n      var name = this.name.records.postscriptName;\n      if (name) {\n        var lang = _Object$keys(name)[0];\n        return name[lang];\n      }\n\n      return null;\n    }\n  }, {\n    key: 'fullName',\n    get: function get() {\n      return this.getName('fullName');\n    }\n\n    /**\n     * The font's family name, e.g. \"Helvetica\"\n     * @type {string}\n     */\n\n  }, {\n    key: 'familyName',\n    get: function get() {\n      return this.getName('fontFamily');\n    }\n\n    /**\n     * The font's sub-family, e.g. \"Bold\".\n     * @type {string}\n     */\n\n  }, {\n    key: 'subfamilyName',\n    get: function get() {\n      return this.getName('fontSubfamily');\n    }\n\n    /**\n     * The font's copyright information\n     * @type {string}\n     */\n\n  }, {\n    key: 'copyright',\n    get: function get() {\n      return this.getName('copyright');\n    }\n\n    /**\n     * The font's version number\n     * @type {string}\n     */\n\n  }, {\n    key: 'version',\n    get: function get() {\n      return this.getName('version');\n    }\n\n    /**\n     * The font’s [ascender](https://en.wikipedia.org/wiki/Ascender_(typography))\n     * @type {number}\n     */\n\n  }, {\n    key: 'ascent',\n    get: function get() {\n      return this.hhea.ascent;\n    }\n\n    /**\n     * The font’s [descender](https://en.wikipedia.org/wiki/Descender)\n     * @type {number}\n     */\n\n  }, {\n    key: 'descent',\n    get: function get() {\n      return this.hhea.descent;\n    }\n\n    /**\n     * The amount of space that should be included between lines\n     * @type {number}\n     */\n\n  }, {\n    key: 'lineGap',\n    get: function get() {\n      return this.hhea.lineGap;\n    }\n\n    /**\n     * The offset from the normal underline position that should be used\n     * @type {number}\n     */\n\n  }, {\n    key: 'underlinePosition',\n    get: function get() {\n      return this.post.underlinePosition;\n    }\n\n    /**\n     * The weight of the underline that should be used\n     * @type {number}\n     */\n\n  }, {\n    key: 'underlineThickness',\n    get: function get() {\n      return this.post.underlineThickness;\n    }\n\n    /**\n     * If this is an italic font, the angle the cursor should be drawn at to match the font design\n     * @type {number}\n     */\n\n  }, {\n    key: 'italicAngle',\n    get: function get() {\n      return this.post.italicAngle;\n    }\n\n    /**\n     * The height of capital letters above the baseline.\n     * See [here](https://en.wikipedia.org/wiki/Cap_height) for more details.\n     * @type {number}\n     */\n\n  }, {\n    key: 'capHeight',\n    get: function get() {\n      var os2 = this['OS/2'];\n      return os2 ? os2.capHeight : this.ascent;\n    }\n\n    /**\n     * The height of lower case letters in the font.\n     * See [here](https://en.wikipedia.org/wiki/X-height) for more details.\n     * @type {number}\n     */\n\n  }, {\n    key: 'xHeight',\n    get: function get() {\n      var os2 = this['OS/2'];\n      return os2 ? os2.xHeight : 0;\n    }\n\n    /**\n     * The number of glyphs in the font.\n     * @type {number}\n     */\n\n  }, {\n    key: 'numGlyphs',\n    get: function get() {\n      return this.maxp.numGlyphs;\n    }\n\n    /**\n     * The size of the font’s internal coordinate grid\n     * @type {number}\n     */\n\n  }, {\n    key: 'unitsPerEm',\n    get: function get() {\n      return this.head.unitsPerEm;\n    }\n\n    /**\n     * The font’s bounding box, i.e. the box that encloses all glyphs in the font.\n     * @type {BBox}\n     */\n\n  }, {\n    key: 'bbox',\n    get: function get() {\n      return _Object$freeze(new BBox(this.head.xMin, this.head.yMin, this.head.xMax, this.head.yMax));\n    }\n  }, {\n    key: '_cmapProcessor',\n    get: function get() {\n      return new CmapProcessor(this.cmap);\n    }\n\n    /**\n     * An array of all of the unicode code points supported by the font.\n     * @type {number[]}\n     */\n\n  }, {\n    key: 'characterSet',\n    get: function get() {\n      return this._cmapProcessor.getCharacterSet();\n    }\n  }, {\n    key: '_layoutEngine',\n    get: function get() {\n      return new LayoutEngine(this);\n    }\n  }, {\n    key: 'availableFeatures',\n    get: function get() {\n      return this._layoutEngine.getAvailableFeatures();\n    }\n  }, {\n    key: 'variationAxes',\n    get: function get() {\n      var res = {};\n      if (!this.fvar) {\n        return res;\n      }\n\n      for (var _iterator = this.fvar.axis, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n        var _ref;\n\n        if (_isArray) {\n          if (_i >= _iterator.length) break;\n          _ref = _iterator[_i++];\n        } else {\n          _i = _iterator.next();\n          if (_i.done) break;\n          _ref = _i.value;\n        }\n\n        var axis = _ref;\n\n        res[axis.axisTag.trim()] = {\n          name: axis.name.en,\n          min: axis.minValue,\n          default: axis.defaultValue,\n          max: axis.maxValue\n        };\n      }\n\n      return res;\n    }\n\n    /**\n     * Returns an object describing the named variation instances\n     * that the font designer has specified. Keys are variation names\n     * and values are the variation settings for this instance.\n     *\n     * @type {object}\n     */\n\n  }, {\n    key: 'namedVariations',\n    get: function get() {\n      var res = {};\n      if (!this.fvar) {\n        return res;\n      }\n\n      for (var _iterator2 = this.fvar.instance, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n        var _ref2;\n\n        if (_isArray2) {\n          if (_i2 >= _iterator2.length) break;\n          _ref2 = _iterator2[_i2++];\n        } else {\n          _i2 = _iterator2.next();\n          if (_i2.done) break;\n          _ref2 = _i2.value;\n        }\n\n        var instance = _ref2;\n\n        var settings = {};\n        for (var i = 0; i < this.fvar.axis.length; i++) {\n          var axis = this.fvar.axis[i];\n          settings[axis.axisTag.trim()] = instance.coord[i];\n        }\n\n        res[instance.name.en] = settings;\n      }\n\n      return res;\n    }\n  }, {\n    key: '_variationProcessor',\n    get: function get() {\n      if (!this.fvar) {\n        return null;\n      }\n\n      var variationCoords = this.variationCoords;\n\n      // Ignore if no variation coords and not CFF2\n      if (!variationCoords && !this.CFF2) {\n        return null;\n      }\n\n      if (!variationCoords) {\n        variationCoords = this.fvar.axis.map(function (axis) {\n          return axis.defaultValue;\n        });\n      }\n\n      return new GlyphVariationProcessor(this, variationCoords);\n    }\n  }]);\n\n  return TTFFont;\n}(), (_applyDecoratedDescriptor(_class.prototype, 'bbox', [cache], _Object$getOwnPropertyDescriptor(_class.prototype, 'bbox'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, '_cmapProcessor', [cache], _Object$getOwnPropertyDescriptor(_class.prototype, '_cmapProcessor'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'characterSet', [cache], _Object$getOwnPropertyDescriptor(_class.prototype, 'characterSet'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, '_layoutEngine', [cache], _Object$getOwnPropertyDescriptor(_class.prototype, '_layoutEngine'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'variationAxes', [cache], _Object$getOwnPropertyDescriptor(_class.prototype, 'variationAxes'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'namedVariations', [cache], _Object$getOwnPropertyDescriptor(_class.prototype, 'namedVariations'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, '_variationProcessor', [cache], _Object$getOwnPropertyDescriptor(_class.prototype, '_variationProcessor'), _class.prototype)), _class);\n\nvar WOFFDirectoryEntry = new r.Struct({\n  tag: new r.String(4),\n  offset: new r.Pointer(r.uint32, 'void', { type: 'global' }),\n  compLength: r.uint32,\n  length: r.uint32,\n  origChecksum: r.uint32\n});\n\nvar WOFFDirectory = new r.Struct({\n  tag: new r.String(4), // should be 'wOFF'\n  flavor: r.uint32,\n  length: r.uint32,\n  numTables: r.uint16,\n  reserved: new r.Reserved(r.uint16),\n  totalSfntSize: r.uint32,\n  majorVersion: r.uint16,\n  minorVersion: r.uint16,\n  metaOffset: r.uint32,\n  metaLength: r.uint32,\n  metaOrigLength: r.uint32,\n  privOffset: r.uint32,\n  privLength: r.uint32,\n  tables: new r.Array(WOFFDirectoryEntry, 'numTables')\n});\n\nWOFFDirectory.process = function () {\n  var tables = {};\n  for (var _iterator = this.tables, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n    var _ref;\n\n    if (_isArray) {\n      if (_i >= _iterator.length) break;\n      _ref = _iterator[_i++];\n    } else {\n      _i = _iterator.next();\n      if (_i.done) break;\n      _ref = _i.value;\n    }\n\n    var table = _ref;\n\n    tables[table.tag] = table;\n  }\n\n  this.tables = tables;\n};\n\nvar WOFFFont = function (_TTFFont) {\n  _inherits(WOFFFont, _TTFFont);\n\n  function WOFFFont() {\n    _classCallCheck(this, WOFFFont);\n\n    return _possibleConstructorReturn(this, _TTFFont.apply(this, arguments));\n  }\n\n  WOFFFont.probe = function probe(buffer) {\n    return buffer.toString('ascii', 0, 4) === 'wOFF';\n  };\n\n  WOFFFont.prototype._decodeDirectory = function _decodeDirectory() {\n    this.directory = WOFFDirectory.decode(this.stream, { _startOffset: 0 });\n  };\n\n  WOFFFont.prototype._getTableStream = function _getTableStream(tag) {\n    var table = this.directory.tables[tag];\n    if (table) {\n      this.stream.pos = table.offset;\n\n      if (table.compLength < table.length) {\n        this.stream.pos += 2; // skip deflate header\n        var outBuffer = new Buffer(table.length);\n        var buf = inflate(this.stream.readBuffer(table.compLength - 2), outBuffer);\n        return new r.DecodeStream(buf);\n      } else {\n        return this.stream;\n      }\n    }\n\n    return null;\n  };\n\n  return WOFFFont;\n}(TTFFont);\n\n/**\n * Represents a TrueType glyph in the WOFF2 format, which compresses glyphs differently.\n */\n\nvar WOFF2Glyph = function (_TTFGlyph) {\n  _inherits(WOFF2Glyph, _TTFGlyph);\n\n  function WOFF2Glyph() {\n    _classCallCheck(this, WOFF2Glyph);\n\n    return _possibleConstructorReturn(this, _TTFGlyph.apply(this, arguments));\n  }\n\n  WOFF2Glyph.prototype._decode = function _decode() {\n    // We have to decode in advance (in WOFF2Font), so just return the pre-decoded data.\n    return this._font._transformedGlyphs[this.id];\n  };\n\n  WOFF2Glyph.prototype._getCBox = function _getCBox() {\n    return this.path.bbox;\n  };\n\n  return WOFF2Glyph;\n}(TTFGlyph);\n\nvar Base128 = {\n  decode: function decode(stream) {\n    var result = 0;\n    var iterable = [0, 1, 2, 3, 4];\n    for (var j = 0; j < iterable.length; j++) {\n      var i = iterable[j];\n      var code = stream.readUInt8();\n\n      // If any of the top seven bits are set then we're about to overflow.\n      if (result & 0xe0000000) {\n        throw new Error('Overflow');\n      }\n\n      result = result << 7 | code & 0x7f;\n      if ((code & 0x80) === 0) {\n        return result;\n      }\n    }\n\n    throw new Error('Bad base 128 number');\n  }\n};\n\nvar knownTags = ['cmap', 'head', 'hhea', 'hmtx', 'maxp', 'name', 'OS/2', 'post', 'cvt ', 'fpgm', 'glyf', 'loca', 'prep', 'CFF ', 'VORG', 'EBDT', 'EBLC', 'gasp', 'hdmx', 'kern', 'LTSH', 'PCLT', 'VDMX', 'vhea', 'vmtx', 'BASE', 'GDEF', 'GPOS', 'GSUB', 'EBSC', 'JSTF', 'MATH', 'CBDT', 'CBLC', 'COLR', 'CPAL', 'SVG ', 'sbix', 'acnt', 'avar', 'bdat', 'bloc', 'bsln', 'cvar', 'fdsc', 'feat', 'fmtx', 'fvar', 'gvar', 'hsty', 'just', 'lcar', 'mort', 'morx', 'opbd', 'prop', 'trak', 'Zapf', 'Silf', 'Glat', 'Gloc', 'Feat', 'Sill'];\n\nvar WOFF2DirectoryEntry = new r.Struct({\n  flags: r.uint8,\n  customTag: new r.Optional(new r.String(4), function (t) {\n    return (t.flags & 0x3f) === 0x3f;\n  }),\n  tag: function tag(t) {\n    return t.customTag || knownTags[t.flags & 0x3f];\n  }, // || (() => { throw new Error(`Bad tag: ${flags & 0x3f}`); })(); },\n  length: Base128,\n  transformVersion: function transformVersion(t) {\n    return t.flags >>> 6 & 0x03;\n  },\n  transformed: function transformed(t) {\n    return t.tag === 'glyf' || t.tag === 'loca' ? t.transformVersion === 0 : t.transformVersion !== 0;\n  },\n  transformLength: new r.Optional(Base128, function (t) {\n    return t.transformed;\n  })\n});\n\nvar WOFF2Directory = new r.Struct({\n  tag: new r.String(4), // should be 'wOF2'\n  flavor: r.uint32,\n  length: r.uint32,\n  numTables: r.uint16,\n  reserved: new r.Reserved(r.uint16),\n  totalSfntSize: r.uint32,\n  totalCompressedSize: r.uint32,\n  majorVersion: r.uint16,\n  minorVersion: r.uint16,\n  metaOffset: r.uint32,\n  metaLength: r.uint32,\n  metaOrigLength: r.uint32,\n  privOffset: r.uint32,\n  privLength: r.uint32,\n  tables: new r.Array(WOFF2DirectoryEntry, 'numTables')\n});\n\nWOFF2Directory.process = function () {\n  var tables = {};\n  for (var i = 0; i < this.tables.length; i++) {\n    var table = this.tables[i];\n    tables[table.tag] = table;\n  }\n\n  return this.tables = tables;\n};\n\n/**\n * Subclass of TTFFont that represents a TTF/OTF font compressed by WOFF2\n * See spec here: http://www.w3.org/TR/WOFF2/\n */\n\nvar WOFF2Font = function (_TTFFont) {\n  _inherits(WOFF2Font, _TTFFont);\n\n  function WOFF2Font() {\n    _classCallCheck(this, WOFF2Font);\n\n    return _possibleConstructorReturn(this, _TTFFont.apply(this, arguments));\n  }\n\n  WOFF2Font.probe = function probe(buffer) {\n    return buffer.toString('ascii', 0, 4) === 'wOF2';\n  };\n\n  WOFF2Font.prototype._decodeDirectory = function _decodeDirectory() {\n    this.directory = WOFF2Directory.decode(this.stream);\n    this._dataPos = this.stream.pos;\n  };\n\n  WOFF2Font.prototype._decompress = function _decompress() {\n    // decompress data and setup table offsets if we haven't already\n    if (!this._decompressed) {\n      this.stream.pos = this._dataPos;\n      var buffer = this.stream.readBuffer(this.directory.totalCompressedSize);\n\n      var decompressedSize = 0;\n      for (var tag in this.directory.tables) {\n        var entry = this.directory.tables[tag];\n        entry.offset = decompressedSize;\n        decompressedSize += entry.transformLength != null ? entry.transformLength : entry.length;\n      }\n\n      var decompressed = brotli(buffer, decompressedSize);\n      if (!decompressed) {\n        throw new Error('Error decoding compressed data in WOFF2');\n      }\n\n      this.stream = new r.DecodeStream(new Buffer(decompressed));\n      this._decompressed = true;\n    }\n  };\n\n  WOFF2Font.prototype._decodeTable = function _decodeTable(table) {\n    this._decompress();\n    return _TTFFont.prototype._decodeTable.call(this, table);\n  };\n\n  // Override this method to get a glyph and return our\n  // custom subclass if there is a glyf table.\n\n\n  WOFF2Font.prototype._getBaseGlyph = function _getBaseGlyph(glyph) {\n    var characters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n\n    if (!this._glyphs[glyph]) {\n      if (this.directory.tables.glyf && this.directory.tables.glyf.transformed) {\n        if (!this._transformedGlyphs) {\n          this._transformGlyfTable();\n        }\n        return this._glyphs[glyph] = new WOFF2Glyph(glyph, characters, this);\n      } else {\n        return _TTFFont.prototype._getBaseGlyph.call(this, glyph, characters);\n      }\n    }\n  };\n\n  WOFF2Font.prototype._transformGlyfTable = function _transformGlyfTable() {\n    this._decompress();\n    this.stream.pos = this.directory.tables.glyf.offset;\n    var table = GlyfTable.decode(this.stream);\n    var glyphs = [];\n\n    for (var index = 0; index < table.numGlyphs; index++) {\n      var glyph = {};\n      var nContours = table.nContours.readInt16BE();\n      glyph.numberOfContours = nContours;\n\n      if (nContours > 0) {\n        // simple glyph\n        var nPoints = [];\n        var totalPoints = 0;\n\n        for (var i = 0; i < nContours; i++) {\n          var _r = read255UInt16(table.nPoints);\n          totalPoints += _r;\n          nPoints.push(totalPoints);\n        }\n\n        glyph.points = decodeTriplet(table.flags, table.glyphs, totalPoints);\n        for (var _i = 0; _i < nContours; _i++) {\n          glyph.points[nPoints[_i] - 1].endContour = true;\n        }\n\n        var instructionSize = read255UInt16(table.glyphs);\n      } else if (nContours < 0) {\n        // composite glyph\n        var haveInstructions = TTFGlyph.prototype._decodeComposite.call({ _font: this }, glyph, table.composites);\n        if (haveInstructions) {\n          var instructionSize = read255UInt16(table.glyphs);\n        }\n      }\n\n      glyphs.push(glyph);\n    }\n\n    this._transformedGlyphs = glyphs;\n  };\n\n  return WOFF2Font;\n}(TTFFont);\n\nvar Substream = function () {\n  function Substream(length) {\n    _classCallCheck(this, Substream);\n\n    this.length = length;\n    this._buf = new r.Buffer(length);\n  }\n\n  Substream.prototype.decode = function decode(stream, parent) {\n    return new r.DecodeStream(this._buf.decode(stream, parent));\n  };\n\n  return Substream;\n}();\n\n// This struct represents the entire glyf table\n\n\nvar GlyfTable = new r.Struct({\n  version: r.uint32,\n  numGlyphs: r.uint16,\n  indexFormat: r.uint16,\n  nContourStreamSize: r.uint32,\n  nPointsStreamSize: r.uint32,\n  flagStreamSize: r.uint32,\n  glyphStreamSize: r.uint32,\n  compositeStreamSize: r.uint32,\n  bboxStreamSize: r.uint32,\n  instructionStreamSize: r.uint32,\n  nContours: new Substream('nContourStreamSize'),\n  nPoints: new Substream('nPointsStreamSize'),\n  flags: new Substream('flagStreamSize'),\n  glyphs: new Substream('glyphStreamSize'),\n  composites: new Substream('compositeStreamSize'),\n  bboxes: new Substream('bboxStreamSize'),\n  instructions: new Substream('instructionStreamSize')\n});\n\nvar WORD_CODE = 253;\nvar ONE_MORE_BYTE_CODE2 = 254;\nvar ONE_MORE_BYTE_CODE1 = 255;\nvar LOWEST_U_CODE = 253;\n\nfunction read255UInt16(stream) {\n  var code = stream.readUInt8();\n\n  if (code === WORD_CODE) {\n    return stream.readUInt16BE();\n  }\n\n  if (code === ONE_MORE_BYTE_CODE1) {\n    return stream.readUInt8() + LOWEST_U_CODE;\n  }\n\n  if (code === ONE_MORE_BYTE_CODE2) {\n    return stream.readUInt8() + LOWEST_U_CODE * 2;\n  }\n\n  return code;\n}\n\nfunction withSign(flag, baseval) {\n  return flag & 1 ? baseval : -baseval;\n}\n\nfunction decodeTriplet(flags, glyphs, nPoints) {\n  var y = void 0;\n  var x = y = 0;\n  var res = [];\n\n  for (var i = 0; i < nPoints; i++) {\n    var dx = 0,\n        dy = 0;\n    var flag = flags.readUInt8();\n    var onCurve = !(flag >> 7);\n    flag &= 0x7f;\n\n    if (flag < 10) {\n      dx = 0;\n      dy = withSign(flag, ((flag & 14) << 7) + glyphs.readUInt8());\n    } else if (flag < 20) {\n      dx = withSign(flag, ((flag - 10 & 14) << 7) + glyphs.readUInt8());\n      dy = 0;\n    } else if (flag < 84) {\n      var b0 = flag - 20;\n      var b1 = glyphs.readUInt8();\n      dx = withSign(flag, 1 + (b0 & 0x30) + (b1 >> 4));\n      dy = withSign(flag >> 1, 1 + ((b0 & 0x0c) << 2) + (b1 & 0x0f));\n    } else if (flag < 120) {\n      var b0 = flag - 84;\n      dx = withSign(flag, 1 + (b0 / 12 << 8) + glyphs.readUInt8());\n      dy = withSign(flag >> 1, 1 + (b0 % 12 >> 2 << 8) + glyphs.readUInt8());\n    } else if (flag < 124) {\n      var b1 = glyphs.readUInt8();\n      var b2 = glyphs.readUInt8();\n      dx = withSign(flag, (b1 << 4) + (b2 >> 4));\n      dy = withSign(flag >> 1, ((b2 & 0x0f) << 8) + glyphs.readUInt8());\n    } else {\n      dx = withSign(flag, glyphs.readUInt16BE());\n      dy = withSign(flag >> 1, glyphs.readUInt16BE());\n    }\n\n    x += dx;\n    y += dy;\n    res.push(new Point(onCurve, false, x, y));\n  }\n\n  return res;\n}\n\nvar TTCHeader = new r.VersionedStruct(r.uint32, {\n  0x00010000: {\n    numFonts: r.uint32,\n    offsets: new r.Array(r.uint32, 'numFonts')\n  },\n  0x00020000: {\n    numFonts: r.uint32,\n    offsets: new r.Array(r.uint32, 'numFonts'),\n    dsigTag: r.uint32,\n    dsigLength: r.uint32,\n    dsigOffset: r.uint32\n  }\n});\n\nvar TrueTypeCollection = function () {\n  TrueTypeCollection.probe = function probe(buffer) {\n    return buffer.toString('ascii', 0, 4) === 'ttcf';\n  };\n\n  function TrueTypeCollection(stream) {\n    _classCallCheck(this, TrueTypeCollection);\n\n    this.stream = stream;\n    if (stream.readString(4) !== 'ttcf') {\n      throw new Error('Not a TrueType collection');\n    }\n\n    this.header = TTCHeader.decode(stream);\n  }\n\n  TrueTypeCollection.prototype.getFont = function getFont(name) {\n    for (var _iterator = this.header.offsets, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var offset = _ref;\n\n      var stream = new r.DecodeStream(this.stream.buffer);\n      stream.pos = offset;\n      var font = new TTFFont(stream);\n      if (font.postscriptName === name) {\n        return font;\n      }\n    }\n\n    return null;\n  };\n\n  _createClass(TrueTypeCollection, [{\n    key: 'fonts',\n    get: function get() {\n      var fonts = [];\n      for (var _iterator2 = this.header.offsets, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n        var _ref2;\n\n        if (_isArray2) {\n          if (_i2 >= _iterator2.length) break;\n          _ref2 = _iterator2[_i2++];\n        } else {\n          _i2 = _iterator2.next();\n          if (_i2.done) break;\n          _ref2 = _i2.value;\n        }\n\n        var offset = _ref2;\n\n        var stream = new r.DecodeStream(this.stream.buffer);\n        stream.pos = offset;\n        fonts.push(new TTFFont(stream));\n      }\n\n      return fonts;\n    }\n  }]);\n\n  return TrueTypeCollection;\n}();\n\nvar DFontName = new r.String(r.uint8);\nvar DFontData = new r.Struct({\n  len: r.uint32,\n  buf: new r.Buffer('len')\n});\n\nvar Ref = new r.Struct({\n  id: r.uint16,\n  nameOffset: r.int16,\n  attr: r.uint8,\n  dataOffset: r.uint24,\n  handle: r.uint32\n});\n\nvar Type = new r.Struct({\n  name: new r.String(4),\n  maxTypeIndex: r.uint16,\n  refList: new r.Pointer(r.uint16, new r.Array(Ref, function (t) {\n    return t.maxTypeIndex + 1;\n  }), { type: 'parent' })\n});\n\nvar TypeList = new r.Struct({\n  length: r.uint16,\n  types: new r.Array(Type, function (t) {\n    return t.length + 1;\n  })\n});\n\nvar DFontMap = new r.Struct({\n  reserved: new r.Reserved(r.uint8, 24),\n  typeList: new r.Pointer(r.uint16, TypeList),\n  nameListOffset: new r.Pointer(r.uint16, 'void')\n});\n\nvar DFontHeader = new r.Struct({\n  dataOffset: r.uint32,\n  map: new r.Pointer(r.uint32, DFontMap),\n  dataLength: r.uint32,\n  mapLength: r.uint32\n});\n\nvar DFont = function () {\n  DFont.probe = function probe(buffer) {\n    var stream = new r.DecodeStream(buffer);\n\n    try {\n      var header = DFontHeader.decode(stream);\n    } catch (e) {\n      return false;\n    }\n\n    for (var _iterator = header.map.typeList.types, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var type = _ref;\n\n      if (type.name === 'sfnt') {\n        return true;\n      }\n    }\n\n    return false;\n  };\n\n  function DFont(stream) {\n    _classCallCheck(this, DFont);\n\n    this.stream = stream;\n    this.header = DFontHeader.decode(this.stream);\n\n    for (var _iterator2 = this.header.map.typeList.types, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n      var _ref2;\n\n      if (_isArray2) {\n        if (_i2 >= _iterator2.length) break;\n        _ref2 = _iterator2[_i2++];\n      } else {\n        _i2 = _iterator2.next();\n        if (_i2.done) break;\n        _ref2 = _i2.value;\n      }\n\n      var type = _ref2;\n\n      for (var _iterator3 = type.refList, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n        var _ref3;\n\n        if (_isArray3) {\n          if (_i3 >= _iterator3.length) break;\n          _ref3 = _iterator3[_i3++];\n        } else {\n          _i3 = _iterator3.next();\n          if (_i3.done) break;\n          _ref3 = _i3.value;\n        }\n\n        var ref = _ref3;\n\n        if (ref.nameOffset >= 0) {\n          this.stream.pos = ref.nameOffset + this.header.map.nameListOffset;\n          ref.name = DFontName.decode(this.stream);\n        } else {\n          ref.name = null;\n        }\n      }\n\n      if (type.name === 'sfnt') {\n        this.sfnt = type;\n      }\n    }\n  }\n\n  DFont.prototype.getFont = function getFont(name) {\n    if (!this.sfnt) {\n      return null;\n    }\n\n    for (var _iterator4 = this.sfnt.refList, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _getIterator(_iterator4);;) {\n      var _ref4;\n\n      if (_isArray4) {\n        if (_i4 >= _iterator4.length) break;\n        _ref4 = _iterator4[_i4++];\n      } else {\n        _i4 = _iterator4.next();\n        if (_i4.done) break;\n        _ref4 = _i4.value;\n      }\n\n      var ref = _ref4;\n\n      var pos = this.header.dataOffset + ref.dataOffset + 4;\n      var stream = new r.DecodeStream(this.stream.buffer.slice(pos));\n      var font = new TTFFont(stream);\n      if (font.postscriptName === name) {\n        return font;\n      }\n    }\n\n    return null;\n  };\n\n  _createClass(DFont, [{\n    key: 'fonts',\n    get: function get() {\n      var fonts = [];\n      for (var _iterator5 = this.sfnt.refList, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _getIterator(_iterator5);;) {\n        var _ref5;\n\n        if (_isArray5) {\n          if (_i5 >= _iterator5.length) break;\n          _ref5 = _iterator5[_i5++];\n        } else {\n          _i5 = _iterator5.next();\n          if (_i5.done) break;\n          _ref5 = _i5.value;\n        }\n\n        var ref = _ref5;\n\n        var pos = this.header.dataOffset + ref.dataOffset + 4;\n        var stream = new r.DecodeStream(this.stream.buffer.slice(pos));\n        fonts.push(new TTFFont(stream));\n      }\n\n      return fonts;\n    }\n  }]);\n\n  return DFont;\n}();\n\n// Register font formats\nfontkit.registerFormat(TTFFont);\nfontkit.registerFormat(WOFFFont);\nfontkit.registerFormat(WOFF2Font);\nfontkit.registerFormat(TrueTypeCollection);\nfontkit.registerFormat(DFont);\n\nmodule.exports = fontkit;\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer, __webpack_require__(11)))\n\n/***/ }),\n/* 168 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var key, val, _ref, _ref1;\n\n  exports.EncodeStream = __webpack_require__(169);\n\n  exports.DecodeStream = __webpack_require__(51);\n\n  exports.Array = __webpack_require__(93);\n\n  exports.LazyArray = __webpack_require__(187);\n\n  exports.Bitfield = __webpack_require__(188);\n\n  exports.Boolean = __webpack_require__(189);\n\n  exports.Buffer = __webpack_require__(190);\n\n  exports.Enum = __webpack_require__(191);\n\n  exports.Optional = __webpack_require__(192);\n\n  exports.Reserved = __webpack_require__(193);\n\n  exports.String = __webpack_require__(194);\n\n  exports.Struct = __webpack_require__(94);\n\n  exports.VersionedStruct = __webpack_require__(195);\n\n  _ref = __webpack_require__(22);\n  for (key in _ref) {\n    val = _ref[key];\n    exports[key] = val;\n  }\n\n  _ref1 = __webpack_require__(196);\n  for (key in _ref1) {\n    val = _ref1[key];\n    exports[key] = val;\n  }\n\n}).call(this);\n\n\n/***/ }),\n/* 169 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.7.1\n(function() {\n  var DecodeStream, EncodeStream, iconv, stream,\n    __hasProp = {}.hasOwnProperty,\n    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n  stream = __webpack_require__(15);\n\n  DecodeStream = __webpack_require__(51);\n\n  try {\n    iconv = __webpack_require__(52);\n  } catch (_error) {}\n\n  EncodeStream = (function(_super) {\n    var key;\n\n    __extends(EncodeStream, _super);\n\n    function EncodeStream(bufferSize) {\n      if (bufferSize == null) {\n        bufferSize = 65536;\n      }\n      EncodeStream.__super__.constructor.apply(this, arguments);\n      this.buffer = new Buffer(bufferSize);\n      this.bufferOffset = 0;\n      this.pos = 0;\n    }\n\n    for (key in Buffer.prototype) {\n      if (key.slice(0, 5) === 'write') {\n        (function(key) {\n          var bytes;\n          bytes = +DecodeStream.TYPES[key.replace(/write|[BL]E/g, '')];\n          return EncodeStream.prototype[key] = function(value) {\n            this.ensure(bytes);\n            this.buffer[key](value, this.bufferOffset);\n            this.bufferOffset += bytes;\n            return this.pos += bytes;\n          };\n        })(key);\n      }\n    }\n\n    EncodeStream.prototype._read = function() {};\n\n    EncodeStream.prototype.ensure = function(bytes) {\n      if (this.bufferOffset + bytes > this.buffer.length) {\n        return this.flush();\n      }\n    };\n\n    EncodeStream.prototype.flush = function() {\n      if (this.bufferOffset > 0) {\n        this.push(new Buffer(this.buffer.slice(0, this.bufferOffset)));\n        return this.bufferOffset = 0;\n      }\n    };\n\n    EncodeStream.prototype.writeBuffer = function(buffer) {\n      this.flush();\n      this.push(buffer);\n      return this.pos += buffer.length;\n    };\n\n    EncodeStream.prototype.writeString = function(string, encoding) {\n      var buf, byte, i, _i, _ref;\n      if (encoding == null) {\n        encoding = 'ascii';\n      }\n      switch (encoding) {\n        case 'utf16le':\n        case 'ucs2':\n        case 'utf8':\n        case 'ascii':\n          return this.writeBuffer(new Buffer(string, encoding));\n        case 'utf16be':\n          buf = new Buffer(string, 'utf16le');\n          for (i = _i = 0, _ref = buf.length - 1; _i < _ref; i = _i += 2) {\n            byte = buf[i];\n            buf[i] = buf[i + 1];\n            buf[i + 1] = byte;\n          }\n          return this.writeBuffer(buf);\n        default:\n          if (iconv) {\n            return this.writeBuffer(iconv.encode(string, encoding));\n          } else {\n            throw new Error('Install iconv-lite to enable additional string encodings.');\n          }\n      }\n    };\n\n    EncodeStream.prototype.writeUInt24BE = function(val) {\n      this.ensure(3);\n      this.buffer[this.bufferOffset++] = val >>> 16 & 0xff;\n      this.buffer[this.bufferOffset++] = val >>> 8 & 0xff;\n      this.buffer[this.bufferOffset++] = val & 0xff;\n      return this.pos += 3;\n    };\n\n    EncodeStream.prototype.writeUInt24LE = function(val) {\n      this.ensure(3);\n      this.buffer[this.bufferOffset++] = val & 0xff;\n      this.buffer[this.bufferOffset++] = val >>> 8 & 0xff;\n      this.buffer[this.bufferOffset++] = val >>> 16 & 0xff;\n      return this.pos += 3;\n    };\n\n    EncodeStream.prototype.writeInt24BE = function(val) {\n      if (val >= 0) {\n        return this.writeUInt24BE(val);\n      } else {\n        return this.writeUInt24BE(val + 0xffffff + 1);\n      }\n    };\n\n    EncodeStream.prototype.writeInt24LE = function(val) {\n      if (val >= 0) {\n        return this.writeUInt24LE(val);\n      } else {\n        return this.writeUInt24LE(val + 0xffffff + 1);\n      }\n    };\n\n    EncodeStream.prototype.fill = function(val, length) {\n      var buf;\n      if (length < this.buffer.length) {\n        this.ensure(length);\n        this.buffer.fill(val, this.bufferOffset, this.bufferOffset + length);\n        this.bufferOffset += length;\n        return this.pos += length;\n      } else {\n        buf = new Buffer(length);\n        buf.fill(val);\n        return this.writeBuffer(buf);\n      }\n    };\n\n    EncodeStream.prototype.end = function() {\n      this.flush();\n      return this.push(null);\n    };\n\n    return EncodeStream;\n\n  })(stream.Readable);\n\n  module.exports = EncodeStream;\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 170 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar BOMChar = '\\uFEFF';\n\nexports.PrependBOM = PrependBOMWrapper\nfunction PrependBOMWrapper(encoder, options) {\n    this.encoder = encoder;\n    this.addBOM = true;\n}\n\nPrependBOMWrapper.prototype.write = function(str) {\n    if (this.addBOM) {\n        str = BOMChar + str;\n        this.addBOM = false;\n    }\n\n    return this.encoder.write(str);\n}\n\nPrependBOMWrapper.prototype.end = function() {\n    return this.encoder.end();\n}\n\n\n//------------------------------------------------------------------------------\n\nexports.StripBOM = StripBOMWrapper;\nfunction StripBOMWrapper(decoder, options) {\n    this.decoder = decoder;\n    this.pass = false;\n    this.options = options || {};\n}\n\nStripBOMWrapper.prototype.write = function(buf) {\n    var res = this.decoder.write(buf);\n    if (this.pass || !res)\n        return res;\n\n    if (res[0] === BOMChar) {\n        res = res.slice(1);\n        if (typeof this.options.stripBOM === 'function')\n            this.options.stripBOM();\n    }\n\n    this.pass = true;\n    return res;\n}\n\nStripBOMWrapper.prototype.end = function() {\n    return this.decoder.end();\n}\n\n\n\n/***/ }),\n/* 171 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// Update this array if you add/rename/remove files in this directory.\n// We support Browserify by skipping automatic module discovery and requiring modules directly.\nvar modules = [\n    __webpack_require__(172),\n    __webpack_require__(173),\n    __webpack_require__(174),\n    __webpack_require__(175),\n    __webpack_require__(176),\n    __webpack_require__(177),\n    __webpack_require__(178),\n    __webpack_require__(179),\n];\n\n// Put all encoding/alias/codec definitions to single object and export it. \nfor (var i = 0; i < modules.length; i++) {\n    var module = modules[i];\n    for (var enc in module)\n        if (Object.prototype.hasOwnProperty.call(module, enc))\n            exports[enc] = module[enc];\n}\n\n\n/***/ }),\n/* 172 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar Buffer = __webpack_require__(1).Buffer;\n\n// Export Node.js internal encodings.\n\nmodule.exports = {\n    // Encodings\n    utf8:   { type: \"_internal\", bomAware: true},\n    cesu8:  { type: \"_internal\", bomAware: true},\n    unicode11utf8: \"utf8\",\n\n    ucs2:   { type: \"_internal\", bomAware: true},\n    utf16le: \"ucs2\",\n\n    binary: { type: \"_internal\" },\n    base64: { type: \"_internal\" },\n    hex:    { type: \"_internal\" },\n\n    // Codec.\n    _internal: InternalCodec,\n};\n\n//------------------------------------------------------------------------------\n\nfunction InternalCodec(codecOptions, iconv) {\n    this.enc = codecOptions.encodingName;\n    this.bomAware = codecOptions.bomAware;\n\n    if (this.enc === \"base64\")\n        this.encoder = InternalEncoderBase64;\n    else if (this.enc === \"cesu8\") {\n        this.enc = \"utf8\"; // Use utf8 for decoding.\n        this.encoder = InternalEncoderCesu8;\n\n        // Add decoder for versions of Node not supporting CESU-8\n        if (new Buffer('eda0bdedb2a9', 'hex').toString() !== '💩') {\n            this.decoder = InternalDecoderCesu8;\n            this.defaultCharUnicode = iconv.defaultCharUnicode;\n        }\n    }\n}\n\nInternalCodec.prototype.encoder = InternalEncoder;\nInternalCodec.prototype.decoder = InternalDecoder;\n\n//------------------------------------------------------------------------------\n\n// We use node.js internal decoder. Its signature is the same as ours.\nvar StringDecoder = __webpack_require__(47).StringDecoder;\n\nif (!StringDecoder.prototype.end) // Node v0.8 doesn't have this method.\n    StringDecoder.prototype.end = function() {};\n\n\nfunction InternalDecoder(options, codec) {\n    StringDecoder.call(this, codec.enc);\n}\n\nInternalDecoder.prototype = StringDecoder.prototype;\n\n\n//------------------------------------------------------------------------------\n// Encoder is mostly trivial\n\nfunction InternalEncoder(options, codec) {\n    this.enc = codec.enc;\n}\n\nInternalEncoder.prototype.write = function(str) {\n    return new Buffer(str, this.enc);\n}\n\nInternalEncoder.prototype.end = function() {\n}\n\n\n//------------------------------------------------------------------------------\n// Except base64 encoder, which must keep its state.\n\nfunction InternalEncoderBase64(options, codec) {\n    this.prevStr = '';\n}\n\nInternalEncoderBase64.prototype.write = function(str) {\n    str = this.prevStr + str;\n    var completeQuads = str.length - (str.length % 4);\n    this.prevStr = str.slice(completeQuads);\n    str = str.slice(0, completeQuads);\n\n    return new Buffer(str, \"base64\");\n}\n\nInternalEncoderBase64.prototype.end = function() {\n    return new Buffer(this.prevStr, \"base64\");\n}\n\n\n//------------------------------------------------------------------------------\n// CESU-8 encoder is also special.\n\nfunction InternalEncoderCesu8(options, codec) {\n}\n\nInternalEncoderCesu8.prototype.write = function(str) {\n    var buf = new Buffer(str.length * 3), bufIdx = 0;\n    for (var i = 0; i < str.length; i++) {\n        var charCode = str.charCodeAt(i);\n        // Naive implementation, but it works because CESU-8 is especially easy\n        // to convert from UTF-16 (which all JS strings are encoded in).\n        if (charCode < 0x80)\n            buf[bufIdx++] = charCode;\n        else if (charCode < 0x800) {\n            buf[bufIdx++] = 0xC0 + (charCode >>> 6);\n            buf[bufIdx++] = 0x80 + (charCode & 0x3f);\n        }\n        else { // charCode will always be < 0x10000 in javascript.\n            buf[bufIdx++] = 0xE0 + (charCode >>> 12);\n            buf[bufIdx++] = 0x80 + ((charCode >>> 6) & 0x3f);\n            buf[bufIdx++] = 0x80 + (charCode & 0x3f);\n        }\n    }\n    return buf.slice(0, bufIdx);\n}\n\nInternalEncoderCesu8.prototype.end = function() {\n}\n\n//------------------------------------------------------------------------------\n// CESU-8 decoder is not implemented in Node v4.0+\n\nfunction InternalDecoderCesu8(options, codec) {\n    this.acc = 0;\n    this.contBytes = 0;\n    this.accBytes = 0;\n    this.defaultCharUnicode = codec.defaultCharUnicode;\n}\n\nInternalDecoderCesu8.prototype.write = function(buf) {\n    var acc = this.acc, contBytes = this.contBytes, accBytes = this.accBytes, \n        res = '';\n    for (var i = 0; i < buf.length; i++) {\n        var curByte = buf[i];\n        if ((curByte & 0xC0) !== 0x80) { // Leading byte\n            if (contBytes > 0) { // Previous code is invalid\n                res += this.defaultCharUnicode;\n                contBytes = 0;\n            }\n\n            if (curByte < 0x80) { // Single-byte code\n                res += String.fromCharCode(curByte);\n            } else if (curByte < 0xE0) { // Two-byte code\n                acc = curByte & 0x1F;\n                contBytes = 1; accBytes = 1;\n            } else if (curByte < 0xF0) { // Three-byte code\n                acc = curByte & 0x0F;\n                contBytes = 2; accBytes = 1;\n            } else { // Four or more are not supported for CESU-8.\n                res += this.defaultCharUnicode;\n            }\n        } else { // Continuation byte\n            if (contBytes > 0) { // We're waiting for it.\n                acc = (acc << 6) | (curByte & 0x3f);\n                contBytes--; accBytes++;\n                if (contBytes === 0) {\n                    // Check for overlong encoding, but support Modified UTF-8 (encoding NULL as C0 80)\n                    if (accBytes === 2 && acc < 0x80 && acc > 0)\n                        res += this.defaultCharUnicode;\n                    else if (accBytes === 3 && acc < 0x800)\n                        res += this.defaultCharUnicode;\n                    else\n                        // Actually add character.\n                        res += String.fromCharCode(acc);\n                }\n            } else { // Unexpected continuation byte\n                res += this.defaultCharUnicode;\n            }\n        }\n    }\n    this.acc = acc; this.contBytes = contBytes; this.accBytes = accBytes;\n    return res;\n}\n\nInternalDecoderCesu8.prototype.end = function() {\n    var res = 0;\n    if (this.contBytes > 0)\n        res += this.defaultCharUnicode;\n    return res;\n}\n\n\n/***/ }),\n/* 173 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar Buffer = __webpack_require__(1).Buffer;\n\n// Note: UTF16-LE (or UCS2) codec is Node.js native. See encodings/internal.js\n\n// == UTF16-BE codec. ==========================================================\n\nexports.utf16be = Utf16BECodec;\nfunction Utf16BECodec() {\n}\n\nUtf16BECodec.prototype.encoder = Utf16BEEncoder;\nUtf16BECodec.prototype.decoder = Utf16BEDecoder;\nUtf16BECodec.prototype.bomAware = true;\n\n\n// -- Encoding\n\nfunction Utf16BEEncoder() {\n}\n\nUtf16BEEncoder.prototype.write = function(str) {\n    var buf = new Buffer(str, 'ucs2');\n    for (var i = 0; i < buf.length; i += 2) {\n        var tmp = buf[i]; buf[i] = buf[i+1]; buf[i+1] = tmp;\n    }\n    return buf;\n}\n\nUtf16BEEncoder.prototype.end = function() {\n}\n\n\n// -- Decoding\n\nfunction Utf16BEDecoder() {\n    this.overflowByte = -1;\n}\n\nUtf16BEDecoder.prototype.write = function(buf) {\n    if (buf.length == 0)\n        return '';\n\n    var buf2 = new Buffer(buf.length + 1),\n        i = 0, j = 0;\n\n    if (this.overflowByte !== -1) {\n        buf2[0] = buf[0];\n        buf2[1] = this.overflowByte;\n        i = 1; j = 2;\n    }\n\n    for (; i < buf.length-1; i += 2, j+= 2) {\n        buf2[j] = buf[i+1];\n        buf2[j+1] = buf[i];\n    }\n\n    this.overflowByte = (i == buf.length-1) ? buf[buf.length-1] : -1;\n\n    return buf2.slice(0, j).toString('ucs2');\n}\n\nUtf16BEDecoder.prototype.end = function() {\n}\n\n\n// == UTF-16 codec =============================================================\n// Decoder chooses automatically from UTF-16LE and UTF-16BE using BOM and space-based heuristic.\n// Defaults to UTF-16LE, as it's prevalent and default in Node.\n// http://en.wikipedia.org/wiki/UTF-16 and http://encoding.spec.whatwg.org/#utf-16le\n// Decoder default can be changed: iconv.decode(buf, 'utf16', {defaultEncoding: 'utf-16be'});\n\n// Encoder uses UTF-16LE and prepends BOM (which can be overridden with addBOM: false).\n\nexports.utf16 = Utf16Codec;\nfunction Utf16Codec(codecOptions, iconv) {\n    this.iconv = iconv;\n}\n\nUtf16Codec.prototype.encoder = Utf16Encoder;\nUtf16Codec.prototype.decoder = Utf16Decoder;\n\n\n// -- Encoding (pass-through)\n\nfunction Utf16Encoder(options, codec) {\n    options = options || {};\n    if (options.addBOM === undefined)\n        options.addBOM = true;\n    this.encoder = codec.iconv.getEncoder('utf-16le', options);\n}\n\nUtf16Encoder.prototype.write = function(str) {\n    return this.encoder.write(str);\n}\n\nUtf16Encoder.prototype.end = function() {\n    return this.encoder.end();\n}\n\n\n// -- Decoding\n\nfunction Utf16Decoder(options, codec) {\n    this.decoder = null;\n    this.initialBytes = [];\n    this.initialBytesLen = 0;\n\n    this.options = options || {};\n    this.iconv = codec.iconv;\n}\n\nUtf16Decoder.prototype.write = function(buf) {\n    if (!this.decoder) {\n        // Codec is not chosen yet. Accumulate initial bytes.\n        this.initialBytes.push(buf);\n        this.initialBytesLen += buf.length;\n        \n        if (this.initialBytesLen < 16) // We need more bytes to use space heuristic (see below)\n            return '';\n\n        // We have enough bytes -> detect endianness.\n        var buf = Buffer.concat(this.initialBytes),\n            encoding = detectEncoding(buf, this.options.defaultEncoding);\n        this.decoder = this.iconv.getDecoder(encoding, this.options);\n        this.initialBytes.length = this.initialBytesLen = 0;\n    }\n\n    return this.decoder.write(buf);\n}\n\nUtf16Decoder.prototype.end = function() {\n    if (!this.decoder) {\n        var buf = Buffer.concat(this.initialBytes),\n            encoding = detectEncoding(buf, this.options.defaultEncoding);\n        this.decoder = this.iconv.getDecoder(encoding, this.options);\n\n        var res = this.decoder.write(buf),\n            trail = this.decoder.end();\n\n        return trail ? (res + trail) : res;\n    }\n    return this.decoder.end();\n}\n\nfunction detectEncoding(buf, defaultEncoding) {\n    var enc = defaultEncoding || 'utf-16le';\n\n    if (buf.length >= 2) {\n        // Check BOM.\n        if (buf[0] == 0xFE && buf[1] == 0xFF) // UTF-16BE BOM\n            enc = 'utf-16be';\n        else if (buf[0] == 0xFF && buf[1] == 0xFE) // UTF-16LE BOM\n            enc = 'utf-16le';\n        else {\n            // No BOM found. Try to deduce encoding from initial content.\n            // Most of the time, the content has ASCII chars (U+00**), but the opposite (U+**00) is uncommon.\n            // So, we count ASCII as if it was LE or BE, and decide from that.\n            var asciiCharsLE = 0, asciiCharsBE = 0, // Counts of chars in both positions\n                _len = Math.min(buf.length - (buf.length % 2), 64); // Len is always even.\n\n            for (var i = 0; i < _len; i += 2) {\n                if (buf[i] === 0 && buf[i+1] !== 0) asciiCharsBE++;\n                if (buf[i] !== 0 && buf[i+1] === 0) asciiCharsLE++;\n            }\n\n            if (asciiCharsBE > asciiCharsLE)\n                enc = 'utf-16be';\n            else if (asciiCharsBE < asciiCharsLE)\n                enc = 'utf-16le';\n        }\n    }\n\n    return enc;\n}\n\n\n\n\n/***/ }),\n/* 174 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar Buffer = __webpack_require__(1).Buffer;\n\n// UTF-7 codec, according to https://tools.ietf.org/html/rfc2152\n// See also below a UTF-7-IMAP codec, according to http://tools.ietf.org/html/rfc3501#section-5.1.3\n\nexports.utf7 = Utf7Codec;\nexports.unicode11utf7 = 'utf7'; // Alias UNICODE-1-1-UTF-7\nfunction Utf7Codec(codecOptions, iconv) {\n    this.iconv = iconv;\n};\n\nUtf7Codec.prototype.encoder = Utf7Encoder;\nUtf7Codec.prototype.decoder = Utf7Decoder;\nUtf7Codec.prototype.bomAware = true;\n\n\n// -- Encoding\n\nvar nonDirectChars = /[^A-Za-z0-9'\\(\\),-\\.\\/:\\? \\n\\r\\t]+/g;\n\nfunction Utf7Encoder(options, codec) {\n    this.iconv = codec.iconv;\n}\n\nUtf7Encoder.prototype.write = function(str) {\n    // Naive implementation.\n    // Non-direct chars are encoded as \"+<base64>-\"; single \"+\" char is encoded as \"+-\".\n    return new Buffer(str.replace(nonDirectChars, function(chunk) {\n        return \"+\" + (chunk === '+' ? '' : \n            this.iconv.encode(chunk, 'utf16-be').toString('base64').replace(/=+$/, '')) \n            + \"-\";\n    }.bind(this)));\n}\n\nUtf7Encoder.prototype.end = function() {\n}\n\n\n// -- Decoding\n\nfunction Utf7Decoder(options, codec) {\n    this.iconv = codec.iconv;\n    this.inBase64 = false;\n    this.base64Accum = '';\n}\n\nvar base64Regex = /[A-Za-z0-9\\/+]/;\nvar base64Chars = [];\nfor (var i = 0; i < 256; i++)\n    base64Chars[i] = base64Regex.test(String.fromCharCode(i));\n\nvar plusChar = '+'.charCodeAt(0), \n    minusChar = '-'.charCodeAt(0),\n    andChar = '&'.charCodeAt(0);\n\nUtf7Decoder.prototype.write = function(buf) {\n    var res = \"\", lastI = 0,\n        inBase64 = this.inBase64,\n        base64Accum = this.base64Accum;\n\n    // The decoder is more involved as we must handle chunks in stream.\n\n    for (var i = 0; i < buf.length; i++) {\n        if (!inBase64) { // We're in direct mode.\n            // Write direct chars until '+'\n            if (buf[i] == plusChar) {\n                res += this.iconv.decode(buf.slice(lastI, i), \"ascii\"); // Write direct chars.\n                lastI = i+1;\n                inBase64 = true;\n            }\n        } else { // We decode base64.\n            if (!base64Chars[buf[i]]) { // Base64 ended.\n                if (i == lastI && buf[i] == minusChar) {// \"+-\" -> \"+\"\n                    res += \"+\";\n                } else {\n                    var b64str = base64Accum + buf.slice(lastI, i).toString();\n                    res += this.iconv.decode(new Buffer(b64str, 'base64'), \"utf16-be\");\n                }\n\n                if (buf[i] != minusChar) // Minus is absorbed after base64.\n                    i--;\n\n                lastI = i+1;\n                inBase64 = false;\n                base64Accum = '';\n            }\n        }\n    }\n\n    if (!inBase64) {\n        res += this.iconv.decode(buf.slice(lastI), \"ascii\"); // Write direct chars.\n    } else {\n        var b64str = base64Accum + buf.slice(lastI).toString();\n\n        var canBeDecoded = b64str.length - (b64str.length % 8); // Minimal chunk: 2 quads -> 2x3 bytes -> 3 chars.\n        base64Accum = b64str.slice(canBeDecoded); // The rest will be decoded in future.\n        b64str = b64str.slice(0, canBeDecoded);\n\n        res += this.iconv.decode(new Buffer(b64str, 'base64'), \"utf16-be\");\n    }\n\n    this.inBase64 = inBase64;\n    this.base64Accum = base64Accum;\n\n    return res;\n}\n\nUtf7Decoder.prototype.end = function() {\n    var res = \"\";\n    if (this.inBase64 && this.base64Accum.length > 0)\n        res = this.iconv.decode(new Buffer(this.base64Accum, 'base64'), \"utf16-be\");\n\n    this.inBase64 = false;\n    this.base64Accum = '';\n    return res;\n}\n\n\n// UTF-7-IMAP codec.\n// RFC3501 Sec. 5.1.3 Modified UTF-7 (http://tools.ietf.org/html/rfc3501#section-5.1.3)\n// Differences:\n//  * Base64 part is started by \"&\" instead of \"+\"\n//  * Direct characters are 0x20-0x7E, except \"&\" (0x26)\n//  * In Base64, \",\" is used instead of \"/\"\n//  * Base64 must not be used to represent direct characters.\n//  * No implicit shift back from Base64 (should always end with '-')\n//  * String must end in non-shifted position.\n//  * \"-&\" while in base64 is not allowed.\n\n\nexports.utf7imap = Utf7IMAPCodec;\nfunction Utf7IMAPCodec(codecOptions, iconv) {\n    this.iconv = iconv;\n};\n\nUtf7IMAPCodec.prototype.encoder = Utf7IMAPEncoder;\nUtf7IMAPCodec.prototype.decoder = Utf7IMAPDecoder;\nUtf7IMAPCodec.prototype.bomAware = true;\n\n\n// -- Encoding\n\nfunction Utf7IMAPEncoder(options, codec) {\n    this.iconv = codec.iconv;\n    this.inBase64 = false;\n    this.base64Accum = new Buffer(6);\n    this.base64AccumIdx = 0;\n}\n\nUtf7IMAPEncoder.prototype.write = function(str) {\n    var inBase64 = this.inBase64,\n        base64Accum = this.base64Accum,\n        base64AccumIdx = this.base64AccumIdx,\n        buf = new Buffer(str.length*5 + 10), bufIdx = 0;\n\n    for (var i = 0; i < str.length; i++) {\n        var uChar = str.charCodeAt(i);\n        if (0x20 <= uChar && uChar <= 0x7E) { // Direct character or '&'.\n            if (inBase64) {\n                if (base64AccumIdx > 0) {\n                    bufIdx += buf.write(base64Accum.slice(0, base64AccumIdx).toString('base64').replace(/\\//g, ',').replace(/=+$/, ''), bufIdx);\n                    base64AccumIdx = 0;\n                }\n\n                buf[bufIdx++] = minusChar; // Write '-', then go to direct mode.\n                inBase64 = false;\n            }\n\n            if (!inBase64) {\n                buf[bufIdx++] = uChar; // Write direct character\n\n                if (uChar === andChar)  // Ampersand -> '&-'\n                    buf[bufIdx++] = minusChar;\n            }\n\n        } else { // Non-direct character\n            if (!inBase64) {\n                buf[bufIdx++] = andChar; // Write '&', then go to base64 mode.\n                inBase64 = true;\n            }\n            if (inBase64) {\n                base64Accum[base64AccumIdx++] = uChar >> 8;\n                base64Accum[base64AccumIdx++] = uChar & 0xFF;\n\n                if (base64AccumIdx == base64Accum.length) {\n                    bufIdx += buf.write(base64Accum.toString('base64').replace(/\\//g, ','), bufIdx);\n                    base64AccumIdx = 0;\n                }\n            }\n        }\n    }\n\n    this.inBase64 = inBase64;\n    this.base64AccumIdx = base64AccumIdx;\n\n    return buf.slice(0, bufIdx);\n}\n\nUtf7IMAPEncoder.prototype.end = function() {\n    var buf = new Buffer(10), bufIdx = 0;\n    if (this.inBase64) {\n        if (this.base64AccumIdx > 0) {\n            bufIdx += buf.write(this.base64Accum.slice(0, this.base64AccumIdx).toString('base64').replace(/\\//g, ',').replace(/=+$/, ''), bufIdx);\n            this.base64AccumIdx = 0;\n        }\n\n        buf[bufIdx++] = minusChar; // Write '-', then go to direct mode.\n        this.inBase64 = false;\n    }\n\n    return buf.slice(0, bufIdx);\n}\n\n\n// -- Decoding\n\nfunction Utf7IMAPDecoder(options, codec) {\n    this.iconv = codec.iconv;\n    this.inBase64 = false;\n    this.base64Accum = '';\n}\n\nvar base64IMAPChars = base64Chars.slice();\nbase64IMAPChars[','.charCodeAt(0)] = true;\n\nUtf7IMAPDecoder.prototype.write = function(buf) {\n    var res = \"\", lastI = 0,\n        inBase64 = this.inBase64,\n        base64Accum = this.base64Accum;\n\n    // The decoder is more involved as we must handle chunks in stream.\n    // It is forgiving, closer to standard UTF-7 (for example, '-' is optional at the end).\n\n    for (var i = 0; i < buf.length; i++) {\n        if (!inBase64) { // We're in direct mode.\n            // Write direct chars until '&'\n            if (buf[i] == andChar) {\n                res += this.iconv.decode(buf.slice(lastI, i), \"ascii\"); // Write direct chars.\n                lastI = i+1;\n                inBase64 = true;\n            }\n        } else { // We decode base64.\n            if (!base64IMAPChars[buf[i]]) { // Base64 ended.\n                if (i == lastI && buf[i] == minusChar) { // \"&-\" -> \"&\"\n                    res += \"&\";\n                } else {\n                    var b64str = base64Accum + buf.slice(lastI, i).toString().replace(/,/g, '/');\n                    res += this.iconv.decode(new Buffer(b64str, 'base64'), \"utf16-be\");\n                }\n\n                if (buf[i] != minusChar) // Minus may be absorbed after base64.\n                    i--;\n\n                lastI = i+1;\n                inBase64 = false;\n                base64Accum = '';\n            }\n        }\n    }\n\n    if (!inBase64) {\n        res += this.iconv.decode(buf.slice(lastI), \"ascii\"); // Write direct chars.\n    } else {\n        var b64str = base64Accum + buf.slice(lastI).toString().replace(/,/g, '/');\n\n        var canBeDecoded = b64str.length - (b64str.length % 8); // Minimal chunk: 2 quads -> 2x3 bytes -> 3 chars.\n        base64Accum = b64str.slice(canBeDecoded); // The rest will be decoded in future.\n        b64str = b64str.slice(0, canBeDecoded);\n\n        res += this.iconv.decode(new Buffer(b64str, 'base64'), \"utf16-be\");\n    }\n\n    this.inBase64 = inBase64;\n    this.base64Accum = base64Accum;\n\n    return res;\n}\n\nUtf7IMAPDecoder.prototype.end = function() {\n    var res = \"\";\n    if (this.inBase64 && this.base64Accum.length > 0)\n        res = this.iconv.decode(new Buffer(this.base64Accum, 'base64'), \"utf16-be\");\n\n    this.inBase64 = false;\n    this.base64Accum = '';\n    return res;\n}\n\n\n\n\n/***/ }),\n/* 175 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar Buffer = __webpack_require__(1).Buffer;\n\n// Single-byte codec. Needs a 'chars' string parameter that contains 256 or 128 chars that\n// correspond to encoded bytes (if 128 - then lower half is ASCII). \n\nexports._sbcs = SBCSCodec;\nfunction SBCSCodec(codecOptions, iconv) {\n    if (!codecOptions)\n        throw new Error(\"SBCS codec is called without the data.\")\n    \n    // Prepare char buffer for decoding.\n    if (!codecOptions.chars || (codecOptions.chars.length !== 128 && codecOptions.chars.length !== 256))\n        throw new Error(\"Encoding '\"+codecOptions.type+\"' has incorrect 'chars' (must be of len 128 or 256)\");\n    \n    if (codecOptions.chars.length === 128) {\n        var asciiString = \"\";\n        for (var i = 0; i < 128; i++)\n            asciiString += String.fromCharCode(i);\n        codecOptions.chars = asciiString + codecOptions.chars;\n    }\n\n    this.decodeBuf = new Buffer(codecOptions.chars, 'ucs2');\n    \n    // Encoding buffer.\n    var encodeBuf = new Buffer(65536);\n    encodeBuf.fill(iconv.defaultCharSingleByte.charCodeAt(0));\n\n    for (var i = 0; i < codecOptions.chars.length; i++)\n        encodeBuf[codecOptions.chars.charCodeAt(i)] = i;\n\n    this.encodeBuf = encodeBuf;\n}\n\nSBCSCodec.prototype.encoder = SBCSEncoder;\nSBCSCodec.prototype.decoder = SBCSDecoder;\n\n\nfunction SBCSEncoder(options, codec) {\n    this.encodeBuf = codec.encodeBuf;\n}\n\nSBCSEncoder.prototype.write = function(str) {\n    var buf = new Buffer(str.length);\n    for (var i = 0; i < str.length; i++)\n        buf[i] = this.encodeBuf[str.charCodeAt(i)];\n    \n    return buf;\n}\n\nSBCSEncoder.prototype.end = function() {\n}\n\n\nfunction SBCSDecoder(options, codec) {\n    this.decodeBuf = codec.decodeBuf;\n}\n\nSBCSDecoder.prototype.write = function(buf) {\n    // Strings are immutable in JS -> we use ucs2 buffer to speed up computations.\n    var decodeBuf = this.decodeBuf;\n    var newBuf = new Buffer(buf.length*2);\n    var idx1 = 0, idx2 = 0;\n    for (var i = 0; i < buf.length; i++) {\n        idx1 = buf[i]*2; idx2 = i*2;\n        newBuf[idx2] = decodeBuf[idx1];\n        newBuf[idx2+1] = decodeBuf[idx1+1];\n    }\n    return newBuf.toString('ucs2');\n}\n\nSBCSDecoder.prototype.end = function() {\n}\n\n\n/***/ }),\n/* 176 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// Manually added data to be used by sbcs codec in addition to generated one.\n\nmodule.exports = {\n    // Not supported by iconv, not sure why.\n    \"10029\": \"maccenteuro\",\n    \"maccenteuro\": {\n        \"type\": \"_sbcs\",\n        \"chars\": \"ÄĀāÉĄÖÜáąČäčĆćéŹźĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅņŃ¬√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ\"\n    },\n\n    \"808\": \"cp808\",\n    \"ibm808\": \"cp808\",\n    \"cp808\": {\n        \"type\": \"_sbcs\",\n        \"chars\": \"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёЄєЇїЎў°∙·√№€■ \"\n    },\n\n    // Aliases of generated encodings.\n    \"ascii8bit\": \"ascii\",\n    \"usascii\": \"ascii\",\n    \"ansix34\": \"ascii\",\n    \"ansix341968\": \"ascii\",\n    \"ansix341986\": \"ascii\",\n    \"csascii\": \"ascii\",\n    \"cp367\": \"ascii\",\n    \"ibm367\": \"ascii\",\n    \"isoir6\": \"ascii\",\n    \"iso646us\": \"ascii\",\n    \"iso646irv\": \"ascii\",\n    \"us\": \"ascii\",\n\n    \"latin1\": \"iso88591\",\n    \"latin2\": \"iso88592\",\n    \"latin3\": \"iso88593\",\n    \"latin4\": \"iso88594\",\n    \"latin5\": \"iso88599\",\n    \"latin6\": \"iso885910\",\n    \"latin7\": \"iso885913\",\n    \"latin8\": \"iso885914\",\n    \"latin9\": \"iso885915\",\n    \"latin10\": \"iso885916\",\n\n    \"csisolatin1\": \"iso88591\",\n    \"csisolatin2\": \"iso88592\",\n    \"csisolatin3\": \"iso88593\",\n    \"csisolatin4\": \"iso88594\",\n    \"csisolatincyrillic\": \"iso88595\",\n    \"csisolatinarabic\": \"iso88596\",\n    \"csisolatingreek\" : \"iso88597\",\n    \"csisolatinhebrew\": \"iso88598\",\n    \"csisolatin5\": \"iso88599\",\n    \"csisolatin6\": \"iso885910\",\n\n    \"l1\": \"iso88591\",\n    \"l2\": \"iso88592\",\n    \"l3\": \"iso88593\",\n    \"l4\": \"iso88594\",\n    \"l5\": \"iso88599\",\n    \"l6\": \"iso885910\",\n    \"l7\": \"iso885913\",\n    \"l8\": \"iso885914\",\n    \"l9\": \"iso885915\",\n    \"l10\": \"iso885916\",\n\n    \"isoir14\": \"iso646jp\",\n    \"isoir57\": \"iso646cn\",\n    \"isoir100\": \"iso88591\",\n    \"isoir101\": \"iso88592\",\n    \"isoir109\": \"iso88593\",\n    \"isoir110\": \"iso88594\",\n    \"isoir144\": \"iso88595\",\n    \"isoir127\": \"iso88596\",\n    \"isoir126\": \"iso88597\",\n    \"isoir138\": \"iso88598\",\n    \"isoir148\": \"iso88599\",\n    \"isoir157\": \"iso885910\",\n    \"isoir166\": \"tis620\",\n    \"isoir179\": \"iso885913\",\n    \"isoir199\": \"iso885914\",\n    \"isoir203\": \"iso885915\",\n    \"isoir226\": \"iso885916\",\n\n    \"cp819\": \"iso88591\",\n    \"ibm819\": \"iso88591\",\n\n    \"cyrillic\": \"iso88595\",\n\n    \"arabic\": \"iso88596\",\n    \"arabic8\": \"iso88596\",\n    \"ecma114\": \"iso88596\",\n    \"asmo708\": \"iso88596\",\n\n    \"greek\" : \"iso88597\",\n    \"greek8\" : \"iso88597\",\n    \"ecma118\" : \"iso88597\",\n    \"elot928\" : \"iso88597\",\n\n    \"hebrew\": \"iso88598\",\n    \"hebrew8\": \"iso88598\",\n\n    \"turkish\": \"iso88599\",\n    \"turkish8\": \"iso88599\",\n\n    \"thai\": \"iso885911\",\n    \"thai8\": \"iso885911\",\n\n    \"celtic\": \"iso885914\",\n    \"celtic8\": \"iso885914\",\n    \"isoceltic\": \"iso885914\",\n\n    \"tis6200\": \"tis620\",\n    \"tis62025291\": \"tis620\",\n    \"tis62025330\": \"tis620\",\n\n    \"10000\": \"macroman\",\n    \"10006\": \"macgreek\",\n    \"10007\": \"maccyrillic\",\n    \"10079\": \"maciceland\",\n    \"10081\": \"macturkish\",\n\n    \"cspc8codepage437\": \"cp437\",\n    \"cspc775baltic\": \"cp775\",\n    \"cspc850multilingual\": \"cp850\",\n    \"cspcp852\": \"cp852\",\n    \"cspc862latinhebrew\": \"cp862\",\n    \"cpgr\": \"cp869\",\n\n    \"msee\": \"cp1250\",\n    \"mscyrl\": \"cp1251\",\n    \"msansi\": \"cp1252\",\n    \"msgreek\": \"cp1253\",\n    \"msturk\": \"cp1254\",\n    \"mshebr\": \"cp1255\",\n    \"msarab\": \"cp1256\",\n    \"winbaltrim\": \"cp1257\",\n\n    \"cp20866\": \"koi8r\",\n    \"20866\": \"koi8r\",\n    \"ibm878\": \"koi8r\",\n    \"cskoi8r\": \"koi8r\",\n\n    \"cp21866\": \"koi8u\",\n    \"21866\": \"koi8u\",\n    \"ibm1168\": \"koi8u\",\n\n    \"strk10482002\": \"rk1048\",\n\n    \"tcvn5712\": \"tcvn\",\n    \"tcvn57121\": \"tcvn\",\n\n    \"gb198880\": \"iso646cn\",\n    \"cn\": \"iso646cn\",\n\n    \"csiso14jisc6220ro\": \"iso646jp\",\n    \"jisc62201969ro\": \"iso646jp\",\n    \"jp\": \"iso646jp\",\n\n    \"cshproman8\": \"hproman8\",\n    \"r8\": \"hproman8\",\n    \"roman8\": \"hproman8\",\n    \"xroman8\": \"hproman8\",\n    \"ibm1051\": \"hproman8\",\n\n    \"mac\": \"macintosh\",\n    \"csmacintosh\": \"macintosh\",\n};\n\n\n\n/***/ }),\n/* 177 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// Generated data for sbcs codec. Don't edit manually. Regenerate using generation/gen-sbcs.js script.\nmodule.exports = {\n  \"437\": \"cp437\",\n  \"737\": \"cp737\",\n  \"775\": \"cp775\",\n  \"850\": \"cp850\",\n  \"852\": \"cp852\",\n  \"855\": \"cp855\",\n  \"856\": \"cp856\",\n  \"857\": \"cp857\",\n  \"858\": \"cp858\",\n  \"860\": \"cp860\",\n  \"861\": \"cp861\",\n  \"862\": \"cp862\",\n  \"863\": \"cp863\",\n  \"864\": \"cp864\",\n  \"865\": \"cp865\",\n  \"866\": \"cp866\",\n  \"869\": \"cp869\",\n  \"874\": \"windows874\",\n  \"922\": \"cp922\",\n  \"1046\": \"cp1046\",\n  \"1124\": \"cp1124\",\n  \"1125\": \"cp1125\",\n  \"1129\": \"cp1129\",\n  \"1133\": \"cp1133\",\n  \"1161\": \"cp1161\",\n  \"1162\": \"cp1162\",\n  \"1163\": \"cp1163\",\n  \"1250\": \"windows1250\",\n  \"1251\": \"windows1251\",\n  \"1252\": \"windows1252\",\n  \"1253\": \"windows1253\",\n  \"1254\": \"windows1254\",\n  \"1255\": \"windows1255\",\n  \"1256\": \"windows1256\",\n  \"1257\": \"windows1257\",\n  \"1258\": \"windows1258\",\n  \"28591\": \"iso88591\",\n  \"28592\": \"iso88592\",\n  \"28593\": \"iso88593\",\n  \"28594\": \"iso88594\",\n  \"28595\": \"iso88595\",\n  \"28596\": \"iso88596\",\n  \"28597\": \"iso88597\",\n  \"28598\": \"iso88598\",\n  \"28599\": \"iso88599\",\n  \"28600\": \"iso885910\",\n  \"28601\": \"iso885911\",\n  \"28603\": \"iso885913\",\n  \"28604\": \"iso885914\",\n  \"28605\": \"iso885915\",\n  \"28606\": \"iso885916\",\n  \"windows874\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€����…�����������‘’“”•–—�������� กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����\"\n  },\n  \"win874\": \"windows874\",\n  \"cp874\": \"windows874\",\n  \"windows1250\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€�‚�„…†‡�‰Š‹ŚŤŽŹ�‘’“”•–—�™š›śťžź ˇ˘Ł¤Ą¦§¨©Ş«¬­®Ż°±˛ł´µ¶·¸ąş»Ľ˝ľżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙\"\n  },\n  \"win1250\": \"windows1250\",\n  \"cp1250\": \"windows1250\",\n  \"windows1251\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ЂЃ‚ѓ„…†‡€‰Љ‹ЊЌЋЏђ‘’“”•–—�™љ›њќћџ ЎўЈ¤Ґ¦§Ё©Є«¬­®Ї°±Ііґµ¶·ё№є»јЅѕїАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя\"\n  },\n  \"win1251\": \"windows1251\",\n  \"cp1251\": \"windows1251\",\n  \"windows1252\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€�‚ƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"\n  },\n  \"win1252\": \"windows1252\",\n  \"cp1252\": \"windows1252\",\n  \"windows1253\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€�‚ƒ„…†‡�‰�‹�����‘’“”•–—�™�›���� ΅Ά£¤¥¦§¨©�«¬­®―°±²³΄µ¶·ΈΉΊ»Ό½ΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ�ΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ�\"\n  },\n  \"win1253\": \"windows1253\",\n  \"cp1253\": \"windows1253\",\n  \"windows1254\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€�‚ƒ„…†‡ˆ‰Š‹Œ����‘’“”•–—˜™š›œ��Ÿ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖ×ØÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ\"\n  },\n  \"win1254\": \"windows1254\",\n  \"cp1254\": \"windows1254\",\n  \"windows1255\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€�‚ƒ„…†‡ˆ‰�‹�����‘’“”•–—˜™�›���� ¡¢£₪¥¦§¨©×«¬­®¯°±²³´µ¶·¸¹÷»¼½¾¿ְֱֲֳִֵֶַָֹֺֻּֽ־ֿ׀ׁׂ׃װױײ׳״�������אבגדהוזחטיךכלםמןנסעףפץצקרשת��‎‏�\"\n  },\n  \"win1255\": \"windows1255\",\n  \"cp1255\": \"windows1255\",\n  \"windows1256\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€پ‚ƒ„…†‡ˆ‰ٹ‹Œچژڈگ‘’“”•–—ک™ڑ›œ‌‍ں ،¢£¤¥¦§¨©ھ«¬­®¯°±²³´µ¶·¸¹؛»¼½¾؟ہءآأؤإئابةتثجحخدذرزسشصض×طظعغـفقكàلâمنهوçèéêëىيîïًٌٍَôُِ÷ّùْûü‎‏ے\"\n  },\n  \"win1256\": \"windows1256\",\n  \"cp1256\": \"windows1256\",\n  \"windows1257\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€�‚�„…†‡�‰�‹�¨ˇ¸�‘’“”•–—�™�›�¯˛� �¢£¤�¦§Ø©Ŗ«¬­®Æ°±²³´µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżž˙\"\n  },\n  \"win1257\": \"windows1257\",\n  \"cp1257\": \"windows1257\",\n  \"windows1258\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€�‚ƒ„…†‡ˆ‰�‹Œ����‘’“”•–—˜™�›œ��Ÿ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂĂÄÅÆÇÈÉÊË̀ÍÎÏĐÑ̉ÓÔƠÖ×ØÙÚÛÜỮßàáâăäåæçèéêë́íîïđṇ̃óôơö÷øùúûüư₫ÿ\"\n  },\n  \"win1258\": \"windows1258\",\n  \"cp1258\": \"windows1258\",\n  \"iso88591\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"\n  },\n  \"cp28591\": \"iso88591\",\n  \"iso88592\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" Ą˘Ł¤ĽŚ§¨ŠŞŤŹ­ŽŻ°ą˛ł´ľśˇ¸šşťź˝žżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙\"\n  },\n  \"cp28592\": \"iso88592\",\n  \"iso88593\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" Ħ˘£¤�Ĥ§¨İŞĞĴ­�Ż°ħ²³´µĥ·¸ışğĵ½�żÀÁÂ�ÄĊĈÇÈÉÊËÌÍÎÏ�ÑÒÓÔĠÖ×ĜÙÚÛÜŬŜßàáâ�äċĉçèéêëìíîï�ñòóôġö÷ĝùúûüŭŝ˙\"\n  },\n  \"cp28593\": \"iso88593\",\n  \"iso88594\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ĄĸŖ¤ĨĻ§¨ŠĒĢŦ­Ž¯°ą˛ŗ´ĩļˇ¸šēģŧŊžŋĀÁÂÃÄÅÆĮČÉĘËĖÍÎĪĐŅŌĶÔÕÖ×ØŲÚÛÜŨŪßāáâãäåæįčéęëėíîīđņōķôõö÷øųúûüũū˙\"\n  },\n  \"cp28594\": \"iso88594\",\n  \"iso88595\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ЁЂЃЄЅІЇЈЉЊЋЌ­ЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя№ёђѓєѕіїјљњћќ§ўџ\"\n  },\n  \"cp28595\": \"iso88595\",\n  \"iso88596\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ���¤�������،­�������������؛���؟�ءآأؤإئابةتثجحخدذرزسشصضطظعغ�����ـفقكلمنهوىيًٌٍَُِّْ�������������\"\n  },\n  \"cp28596\": \"iso88596\",\n  \"iso88597\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ‘’£€₯¦§¨©ͺ«¬­�―°±²³΄΅Ά·ΈΉΊ»Ό½ΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ�ΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ�\"\n  },\n  \"cp28597\": \"iso88597\",\n  \"iso88598\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" �¢£¤¥¦§¨©×«¬­®¯°±²³´µ¶·¸¹÷»¼½¾��������������������������������‗אבגדהוזחטיךכלםמןנסעףפץצקרשת��‎‏�\"\n  },\n  \"cp28598\": \"iso88598\",\n  \"iso88599\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖ×ØÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ\"\n  },\n  \"cp28599\": \"iso88599\",\n  \"iso885910\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ĄĒĢĪĨĶ§ĻĐŠŦŽ­ŪŊ°ąēģīĩķ·ļđšŧž―ūŋĀÁÂÃÄÅÆĮČÉĘËĖÍÎÏÐŅŌÓÔÕÖŨØŲÚÛÜÝÞßāáâãäåæįčéęëėíîïðņōóôõöũøųúûüýþĸ\"\n  },\n  \"cp28600\": \"iso885910\",\n  \"iso885911\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����\"\n  },\n  \"cp28601\": \"iso885911\",\n  \"iso885913\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ”¢£¤„¦§Ø©Ŗ«¬­®Æ°±²³“µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżž’\"\n  },\n  \"cp28603\": \"iso885913\",\n  \"iso885914\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" Ḃḃ£ĊċḊ§Ẁ©ẂḋỲ­®ŸḞḟĠġṀṁ¶ṖẁṗẃṠỳẄẅṡÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏŴÑÒÓÔÕÖṪØÙÚÛÜÝŶßàáâãäåæçèéêëìíîïŵñòóôõöṫøùúûüýŷÿ\"\n  },\n  \"cp28604\": \"iso885914\",\n  \"iso885915\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ¡¢£€¥Š§š©ª«¬­®¯°±²³Žµ¶·ž¹º»ŒœŸ¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"\n  },\n  \"cp28605\": \"iso885915\",\n  \"iso885916\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ĄąŁ€„Š§š©Ș«Ź­źŻ°±ČłŽ”¶·žčș»ŒœŸżÀÁÂĂÄĆÆÇÈÉÊËÌÍÎÏĐŃÒÓÔŐÖŚŰÙÚÛÜĘȚßàáâăäćæçèéêëìíîïđńòóôőöśűùúûüęțÿ\"\n  },\n  \"cp28606\": \"iso885916\",\n  \"cp437\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñÑªº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ \"\n  },\n  \"ibm437\": \"cp437\",\n  \"csibm437\": \"cp437\",\n  \"cp737\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρσςτυφχψ░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀ωάέήϊίόύϋώΆΈΉΊΌΎΏ±≥≤ΪΫ÷≈°∙·√ⁿ²■ \"\n  },\n  \"ibm737\": \"cp737\",\n  \"csibm737\": \"cp737\",\n  \"cp775\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ĆüéāäģåćłēŖŗīŹÄÅÉæÆōöĢ¢ŚśÖÜø£Ø×¤ĀĪóŻżź”¦©®¬½¼Ł«»░▒▓│┤ĄČĘĖ╣║╗╝ĮŠ┐└┴┬├─┼ŲŪ╚╔╩╦╠═╬Žąčęėįšųūž┘┌█▄▌▐▀ÓßŌŃõÕµńĶķĻļņĒŅ’­±“¾¶§÷„°∙·¹³²■ \"\n  },\n  \"ibm775\": \"cp775\",\n  \"csibm775\": \"cp775\",\n  \"cp850\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø×ƒáíóúñÑªº¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ðÐÊËÈıÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµþÞÚÛÙýÝ¯´­±‗¾¶§÷¸°¨·¹³²■ \"\n  },\n  \"ibm850\": \"cp850\",\n  \"csibm850\": \"cp850\",\n  \"cp852\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâäůćçłëŐőîŹÄĆÉĹĺôöĽľŚśÖÜŤťŁ×čáíóúĄąŽžĘę¬źČş«»░▒▓│┤ÁÂĚŞ╣║╗╝Żż┐└┴┬├─┼Ăă╚╔╩╦╠═╬¤đĐĎËďŇÍÎě┘┌█▄ŢŮ▀ÓßÔŃńňŠšŔÚŕŰýÝţ´­˝˛ˇ˘§÷¸°¨˙űŘř■ \"\n  },\n  \"ibm852\": \"cp852\",\n  \"csibm852\": \"cp852\",\n  \"cp855\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ђЂѓЃёЁєЄѕЅіІїЇјЈљЉњЊћЋќЌўЎџЏюЮъЪаАбБцЦдДеЕфФгГ«»░▒▓│┤хХиИ╣║╗╝йЙ┐└┴┬├─┼кК╚╔╩╦╠═╬¤лЛмМнНоОп┘┌█▄Пя▀ЯрРсСтТуУжЖвВьЬ№­ыЫзЗшШэЭщЩчЧ§■ \"\n  },\n  \"ibm855\": \"cp855\",\n  \"csibm855\": \"cp855\",\n  \"cp856\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"אבגדהוזחטיךכלםמןנסעףפץצקרשת�£�×����������®¬½¼�«»░▒▓│┤���©╣║╗╝¢¥┐└┴┬├─┼��╚╔╩╦╠═╬¤���������┘┌█▄¦�▀������µ�������¯´­±‗¾¶§÷¸°¨·¹³²■ \"\n  },\n  \"ibm856\": \"cp856\",\n  \"csibm856\": \"cp856\",\n  \"cp857\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâäàåçêëèïîıÄÅÉæÆôöòûùİÖÜø£ØŞşáíóúñÑĞğ¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ºªÊËÈ�ÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµ�×ÚÛÙìÿ¯´­±�¾¶§÷¸°¨·¹³²■ \"\n  },\n  \"ibm857\": \"cp857\",\n  \"csibm857\": \"cp857\",\n  \"cp858\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø×ƒáíóúñÑªº¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ðÐÊËÈ€ÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµþÞÚÛÙýÝ¯´­±‗¾¶§÷¸°¨·¹³²■ \"\n  },\n  \"ibm858\": \"cp858\",\n  \"csibm858\": \"cp858\",\n  \"cp860\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâãàÁçêÊèÍÔìÃÂÉÀÈôõòÚùÌÕÜ¢£Ù₧ÓáíóúñÑªº¿Ò¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ \"\n  },\n  \"ibm860\": \"cp860\",\n  \"csibm860\": \"cp860\",\n  \"cp861\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâäàåçêëèÐðÞÄÅÉæÆôöþûÝýÖÜø£Ø₧ƒáíóúÁÍÓÚ¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ \"\n  },\n  \"ibm861\": \"cp861\",\n  \"csibm861\": \"cp861\",\n  \"cp862\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"אבגדהוזחטיךכלםמןנסעףפץצקרשת¢£¥₧ƒáíóúñÑªº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ \"\n  },\n  \"ibm862\": \"cp862\",\n  \"csibm862\": \"cp862\",\n  \"cp863\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâÂà¶çêëèïî‗À§ÉÈÊôËÏûù¤ÔÜ¢£ÙÛƒ¦´óú¨¸³¯Î⌐¬½¼¾«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ \"\n  },\n  \"ibm863\": \"cp863\",\n  \"csibm863\": \"cp863\",\n  \"cp864\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f !\\\"#$٪&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~°·∙√▒─│┼┤┬├┴┐┌└┘β∞φ±½¼≈«»ﻷﻸ��ﻻﻼ� ­ﺂ£¤ﺄ��ﺎﺏﺕﺙ،ﺝﺡﺥ٠١٢٣٤٥٦٧٨٩ﻑ؛ﺱﺵﺹ؟¢ﺀﺁﺃﺅﻊﺋﺍﺑﺓﺗﺛﺟﺣﺧﺩﺫﺭﺯﺳﺷﺻﺿﻁﻅﻋﻏ¦¬÷×ﻉـﻓﻗﻛﻟﻣﻧﻫﻭﻯﻳﺽﻌﻎﻍﻡﹽّﻥﻩﻬﻰﻲﻐﻕﻵﻶﻝﻙﻱ■�\"\n  },\n  \"ibm864\": \"cp864\",\n  \"csibm864\": \"cp864\",\n  \"cp865\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø₧ƒáíóúñÑªº¿⌐¬½¼¡«¤░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ \"\n  },\n  \"ibm865\": \"cp865\",\n  \"csibm865\": \"cp865\",\n  \"cp866\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёЄєЇїЎў°∙·√№¤■ \"\n  },\n  \"ibm866\": \"cp866\",\n  \"csibm866\": \"cp866\",\n  \"cp869\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"������Ά�·¬¦‘’Έ―ΉΊΪΌ��ΎΫ©Ώ²³ά£έήίϊΐόύΑΒΓΔΕΖΗ½ΘΙ«»░▒▓│┤ΚΛΜΝ╣║╗╝ΞΟ┐└┴┬├─┼ΠΡ╚╔╩╦╠═╬ΣΤΥΦΧΨΩαβγ┘┌█▄δε▀ζηθικλμνξοπρσςτ΄­±υφχ§ψ΅°¨ωϋΰώ■ \"\n  },\n  \"ibm869\": \"cp869\",\n  \"csibm869\": \"cp869\",\n  \"cp922\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ¡¢£¤¥¦§¨©ª«¬­®‾°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏŠÑÒÓÔÕÖ×ØÙÚÛÜÝŽßàáâãäåæçèéêëìíîïšñòóôõö÷øùúûüýžÿ\"\n  },\n  \"ibm922\": \"cp922\",\n  \"csibm922\": \"cp922\",\n  \"cp1046\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ﺈ×÷ﹱ■│─┐┌└┘ﹹﹻﹽﹿﹷﺊﻰﻳﻲﻎﻏﻐﻶﻸﻺﻼ ¤ﺋﺑﺗﺛﺟﺣ،­ﺧﺳ٠١٢٣٤٥٦٧٨٩ﺷ؛ﺻﺿﻊ؟ﻋءآأؤإئابةتثجحخدذرزسشصضطﻇعغﻌﺂﺄﺎﻓـفقكلمنهوىيًٌٍَُِّْﻗﻛﻟﻵﻷﻹﻻﻣﻧﻬﻩ�\"\n  },\n  \"ibm1046\": \"cp1046\",\n  \"csibm1046\": \"cp1046\",\n  \"cp1124\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ЁЂҐЄЅІЇЈЉЊЋЌ­ЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя№ёђґєѕіїјљњћќ§ўџ\"\n  },\n  \"ibm1124\": \"cp1124\",\n  \"csibm1124\": \"cp1124\",\n  \"cp1125\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёҐґЄєІіЇї·√№¤■ \"\n  },\n  \"ibm1125\": \"cp1125\",\n  \"csibm1125\": \"cp1125\",\n  \"cp1129\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ¡¢£¤¥¦§œ©ª«¬­®¯°±²³Ÿµ¶·Œ¹º»¼½¾¿ÀÁÂĂÄÅÆÇÈÉÊË̀ÍÎÏĐÑ̉ÓÔƠÖ×ØÙÚÛÜỮßàáâăäåæçèéêë́íîïđṇ̃óôơö÷øùúûüư₫ÿ\"\n  },\n  \"ibm1129\": \"cp1129\",\n  \"csibm1129\": \"cp1129\",\n  \"cp1133\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ກຂຄງຈສຊຍດຕຖທນບປຜຝພຟມຢຣລວຫອຮ���ຯະາຳິີຶືຸູຼັົຽ���ເແໂໃໄ່້໊໋໌ໍໆ�ໜໝ₭����������������໐໑໒໓໔໕໖໗໘໙��¢¬¦�\"\n  },\n  \"ibm1133\": \"cp1133\",\n  \"csibm1133\": \"cp1133\",\n  \"cp1161\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"��������������������������������่กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู้๊๋€฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛¢¬¦ \"\n  },\n  \"ibm1161\": \"cp1161\",\n  \"csibm1161\": \"cp1161\",\n  \"cp1162\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€…‘’“”•–— กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����\"\n  },\n  \"ibm1162\": \"cp1162\",\n  \"csibm1162\": \"cp1162\",\n  \"cp1163\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ¡¢£€¥¦§œ©ª«¬­®¯°±²³Ÿµ¶·Œ¹º»¼½¾¿ÀÁÂĂÄÅÆÇÈÉÊË̀ÍÎÏĐÑ̉ÓÔƠÖ×ØÙÚÛÜỮßàáâăäåæçèéêë́íîïđṇ̃óôơö÷øùúûüư₫ÿ\"\n  },\n  \"ibm1163\": \"cp1163\",\n  \"csibm1163\": \"cp1163\",\n  \"maccroatian\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®Š™´¨≠ŽØ∞±≤≥∆µ∂∑∏š∫ªºΩžø¿¡¬√ƒ≈Ć«Č… ÀÃÕŒœĐ—“”‘’÷◊�©⁄¤‹›Æ»–·‚„‰ÂćÁčÈÍÎÏÌÓÔđÒÚÛÙıˆ˜¯πË˚¸Êæˇ\"\n  },\n  \"maccyrillic\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°¢£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµ∂ЈЄєЇїЉљЊњјЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю¤\"\n  },\n  \"macgreek\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"Ä¹²É³ÖÜ΅àâä΄¨çéèêë£™îï•½‰ôö¦­ùûü†ΓΔΘΛΞΠß®©ΣΪ§≠°·Α±≤≥¥ΒΕΖΗΙΚΜΦΫΨΩάΝ¬ΟΡ≈Τ«»… ΥΧΆΈœ–―“”‘’÷ΉΊΌΎέήίόΏύαβψδεφγηιξκλμνοπώρστθωςχυζϊϋΐΰ�\"\n  },\n  \"maciceland\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûüÝ°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤ÐðÞþý·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ\"\n  },\n  \"macroman\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤‹›ﬁﬂ‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ\"\n  },\n  \"macromania\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ĂŞ∞±≤≥¥µ∂∑∏π∫ªºΩăş¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤‹›Ţţ‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ\"\n  },\n  \"macthai\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"«»…“”�•‘’� กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู﻿​–—฿เแโใไๅๆ็่้๊๋์ํ™๏๐๑๒๓๔๕๖๗๘๙®©����\"\n  },\n  \"macturkish\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸĞğİıŞş‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙ�ˆ˜¯˘˙˚¸˝˛ˇ\"\n  },\n  \"macukraine\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°Ґ£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµґЈЄєЇїЉљЊњјЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю¤\"\n  },\n  \"koi8r\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ё╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡Ё╢╣╤╥╦╧╨╩╪╫╬©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ\"\n  },\n  \"koi8u\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ёє╔ії╗╘╙╚╛ґ╝╞╟╠╡ЁЄ╣ІЇ╦╧╨╩╪Ґ╬©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ\"\n  },\n  \"koi8ru\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ёє╔ії╗╘╙╚╛ґў╞╟╠╡ЁЄ╣ІЇ╦╧╨╩╪ҐЎ©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ\"\n  },\n  \"koi8t\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"қғ‚Ғ„…†‡�‰ҳ‹ҲҷҶ�Қ‘’“”•–—�™�›�����ӯӮё¤ӣ¦§���«¬­®�°±²Ё�Ӣ¶·�№�»���©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ\"\n  },\n  \"armscii8\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" �և։)(»«—.՝,-֊…՜՛՞ԱաԲբԳգԴդԵեԶզԷէԸըԹթԺժԻիԼլԽխԾծԿկՀհՁձՂղՃճՄմՅյՆնՇշՈոՉչՊպՋջՌռՍսՎվՏտՐրՑցՒւՓփՔքՕօՖֆ՚�\"\n  },\n  \"rk1048\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ЂЃ‚ѓ„…†‡€‰Љ‹ЊҚҺЏђ‘’“”•–—�™љ›њқһџ ҰұӘ¤Ө¦§Ё©Ғ«¬­®Ү°±Ііөµ¶·ё№ғ»әҢңүАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя\"\n  },\n  \"tcvn\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"\\u0000ÚỤ\\u0003ỪỬỮ\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010ỨỰỲỶỸÝỴ\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÀẢÃÁẠẶẬÈẺẼÉẸỆÌỈĨÍỊÒỎÕÓỌỘỜỞỠỚỢÙỦŨ ĂÂÊÔƠƯĐăâêôơưđẶ̀̀̉̃́àảãáạẲằẳẵắẴẮẦẨẪẤỀặầẩẫấậèỂẻẽéẹềểễếệìỉỄẾỒĩíịòỔỏõóọồổỗốộờởỡớợùỖủũúụừửữứựỳỷỹýỵỐ\"\n  },\n  \"georgianacademy\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"‚ƒ„…†‡ˆ‰Š‹Œ‘’“”•–—˜™š›œŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿აბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰჱჲჳჴჵჶçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"\n  },\n  \"georgianps\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"‚ƒ„…†‡ˆ‰Š‹Œ‘’“”•–—˜™š›œŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿აბგდევზჱთიკლმნჲოპჟრსტჳუფქღყშჩცძწჭხჴჯჰჵæçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"\n  },\n  \"pt154\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ҖҒӮғ„…ҶҮҲүҠӢҢҚҺҸҗ‘’“”•–—ҳҷҡӣңқһҹ ЎўЈӨҘҰ§Ё©Ә«¬ӯ®Ҝ°ұІіҙө¶·ё№ә»јҪҫҝАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя\"\n  },\n  \"viscii\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"\\u0000\\u0001Ẳ\\u0003\\u0004ẴẪ\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013Ỷ\\u0015\\u0016\\u0017\\u0018Ỹ\\u001a\\u001b\\u001c\\u001dỴ\\u001f !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ẠẮẰẶẤẦẨẬẼẸẾỀỂỄỆỐỒỔỖỘỢỚỜỞỊỎỌỈỦŨỤỲÕắằặấầẩậẽẹếềểễệốồổỗỠƠộờởịỰỨỪỬơớƯÀÁÂÃẢĂẳẵÈÉÊẺÌÍĨỳĐứÒÓÔạỷừửÙÚỹỵÝỡưàáâãảăữẫèéêẻìíĩỉđựòóôõỏọụùúũủýợỮ\"\n  },\n  \"iso646cn\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f !\\\"#¥%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}‾��������������������������������������������������������������������������������������������������������������������������������\"\n  },\n  \"iso646jp\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[¥]^_`abcdefghijklmnopqrstuvwxyz{|}‾��������������������������������������������������������������������������������������������������������������������������������\"\n  },\n  \"hproman8\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ÀÂÈÊËÎÏ´ˋˆ¨˜ÙÛ₤¯Ýý°ÇçÑñ¡¿¤£¥§ƒ¢âêôûáéóúàèòùäëöüÅîØÆåíøæÄìÖÜÉïßÔÁÃãÐðÍÌÓÒÕõŠšÚŸÿÞþ·µ¶¾—¼½ªº«■»±�\"\n  },\n  \"macintosh\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤‹›ﬁﬂ‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ\"\n  },\n  \"ascii\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"��������������������������������������������������������������������������������������������������������������������������������\"\n  },\n  \"tis620\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"���������������������������������กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����\"\n  }\n}\n\n/***/ }),\n/* 178 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar Buffer = __webpack_require__(1).Buffer;\n\n// Multibyte codec. In this scheme, a character is represented by 1 or more bytes.\n// Our codec supports UTF-16 surrogates, extensions for GB18030 and unicode sequences.\n// To save memory and loading time, we read table files only when requested.\n\nexports._dbcs = DBCSCodec;\n\nvar UNASSIGNED = -1,\n    GB18030_CODE = -2,\n    SEQ_START  = -10,\n    NODE_START = -1000,\n    UNASSIGNED_NODE = new Array(0x100),\n    DEF_CHAR = -1;\n\nfor (var i = 0; i < 0x100; i++)\n    UNASSIGNED_NODE[i] = UNASSIGNED;\n\n\n// Class DBCSCodec reads and initializes mapping tables.\nfunction DBCSCodec(codecOptions, iconv) {\n    this.encodingName = codecOptions.encodingName;\n    if (!codecOptions)\n        throw new Error(\"DBCS codec is called without the data.\")\n    if (!codecOptions.table)\n        throw new Error(\"Encoding '\" + this.encodingName + \"' has no data.\");\n\n    // Load tables.\n    var mappingTable = codecOptions.table();\n\n\n    // Decode tables: MBCS -> Unicode.\n\n    // decodeTables is a trie, encoded as an array of arrays of integers. Internal arrays are trie nodes and all have len = 256.\n    // Trie root is decodeTables[0].\n    // Values: >=  0 -> unicode character code. can be > 0xFFFF\n    //         == UNASSIGNED -> unknown/unassigned sequence.\n    //         == GB18030_CODE -> this is the end of a GB18030 4-byte sequence.\n    //         <= NODE_START -> index of the next node in our trie to process next byte.\n    //         <= SEQ_START  -> index of the start of a character code sequence, in decodeTableSeq.\n    this.decodeTables = [];\n    this.decodeTables[0] = UNASSIGNED_NODE.slice(0); // Create root node.\n\n    // Sometimes a MBCS char corresponds to a sequence of unicode chars. We store them as arrays of integers here. \n    this.decodeTableSeq = [];\n\n    // Actual mapping tables consist of chunks. Use them to fill up decode tables.\n    for (var i = 0; i < mappingTable.length; i++)\n        this._addDecodeChunk(mappingTable[i]);\n\n    this.defaultCharUnicode = iconv.defaultCharUnicode;\n\n    \n    // Encode tables: Unicode -> DBCS.\n\n    // `encodeTable` is array mapping from unicode char to encoded char. All its values are integers for performance.\n    // Because it can be sparse, it is represented as array of buckets by 256 chars each. Bucket can be null.\n    // Values: >=  0 -> it is a normal char. Write the value (if <=256 then 1 byte, if <=65536 then 2 bytes, etc.).\n    //         == UNASSIGNED -> no conversion found. Output a default char.\n    //         <= SEQ_START  -> it's an index in encodeTableSeq, see below. The character starts a sequence.\n    this.encodeTable = [];\n    \n    // `encodeTableSeq` is used when a sequence of unicode characters is encoded as a single code. We use a tree of\n    // objects where keys correspond to characters in sequence and leafs are the encoded dbcs values. A special DEF_CHAR key\n    // means end of sequence (needed when one sequence is a strict subsequence of another).\n    // Objects are kept separately from encodeTable to increase performance.\n    this.encodeTableSeq = [];\n\n    // Some chars can be decoded, but need not be encoded.\n    var skipEncodeChars = {};\n    if (codecOptions.encodeSkipVals)\n        for (var i = 0; i < codecOptions.encodeSkipVals.length; i++) {\n            var val = codecOptions.encodeSkipVals[i];\n            if (typeof val === 'number')\n                skipEncodeChars[val] = true;\n            else\n                for (var j = val.from; j <= val.to; j++)\n                    skipEncodeChars[j] = true;\n        }\n        \n    // Use decode trie to recursively fill out encode tables.\n    this._fillEncodeTable(0, 0, skipEncodeChars);\n\n    // Add more encoding pairs when needed.\n    if (codecOptions.encodeAdd) {\n        for (var uChar in codecOptions.encodeAdd)\n            if (Object.prototype.hasOwnProperty.call(codecOptions.encodeAdd, uChar))\n                this._setEncodeChar(uChar.charCodeAt(0), codecOptions.encodeAdd[uChar]);\n    }\n\n    this.defCharSB  = this.encodeTable[0][iconv.defaultCharSingleByte.charCodeAt(0)];\n    if (this.defCharSB === UNASSIGNED) this.defCharSB = this.encodeTable[0]['?'];\n    if (this.defCharSB === UNASSIGNED) this.defCharSB = \"?\".charCodeAt(0);\n\n\n    // Load & create GB18030 tables when needed.\n    if (typeof codecOptions.gb18030 === 'function') {\n        this.gb18030 = codecOptions.gb18030(); // Load GB18030 ranges.\n\n        // Add GB18030 decode tables.\n        var thirdByteNodeIdx = this.decodeTables.length;\n        var thirdByteNode = this.decodeTables[thirdByteNodeIdx] = UNASSIGNED_NODE.slice(0);\n\n        var fourthByteNodeIdx = this.decodeTables.length;\n        var fourthByteNode = this.decodeTables[fourthByteNodeIdx] = UNASSIGNED_NODE.slice(0);\n\n        for (var i = 0x81; i <= 0xFE; i++) {\n            var secondByteNodeIdx = NODE_START - this.decodeTables[0][i];\n            var secondByteNode = this.decodeTables[secondByteNodeIdx];\n            for (var j = 0x30; j <= 0x39; j++)\n                secondByteNode[j] = NODE_START - thirdByteNodeIdx;\n        }\n        for (var i = 0x81; i <= 0xFE; i++)\n            thirdByteNode[i] = NODE_START - fourthByteNodeIdx;\n        for (var i = 0x30; i <= 0x39; i++)\n            fourthByteNode[i] = GB18030_CODE\n    }        \n}\n\nDBCSCodec.prototype.encoder = DBCSEncoder;\nDBCSCodec.prototype.decoder = DBCSDecoder;\n\n// Decoder helpers\nDBCSCodec.prototype._getDecodeTrieNode = function(addr) {\n    var bytes = [];\n    for (; addr > 0; addr >>= 8)\n        bytes.push(addr & 0xFF);\n    if (bytes.length == 0)\n        bytes.push(0);\n\n    var node = this.decodeTables[0];\n    for (var i = bytes.length-1; i > 0; i--) { // Traverse nodes deeper into the trie.\n        var val = node[bytes[i]];\n\n        if (val == UNASSIGNED) { // Create new node.\n            node[bytes[i]] = NODE_START - this.decodeTables.length;\n            this.decodeTables.push(node = UNASSIGNED_NODE.slice(0));\n        }\n        else if (val <= NODE_START) { // Existing node.\n            node = this.decodeTables[NODE_START - val];\n        }\n        else\n            throw new Error(\"Overwrite byte in \" + this.encodingName + \", addr: \" + addr.toString(16));\n    }\n    return node;\n}\n\n\nDBCSCodec.prototype._addDecodeChunk = function(chunk) {\n    // First element of chunk is the hex mbcs code where we start.\n    var curAddr = parseInt(chunk[0], 16);\n\n    // Choose the decoding node where we'll write our chars.\n    var writeTable = this._getDecodeTrieNode(curAddr);\n    curAddr = curAddr & 0xFF;\n\n    // Write all other elements of the chunk to the table.\n    for (var k = 1; k < chunk.length; k++) {\n        var part = chunk[k];\n        if (typeof part === \"string\") { // String, write as-is.\n            for (var l = 0; l < part.length;) {\n                var code = part.charCodeAt(l++);\n                if (0xD800 <= code && code < 0xDC00) { // Decode surrogate\n                    var codeTrail = part.charCodeAt(l++);\n                    if (0xDC00 <= codeTrail && codeTrail < 0xE000)\n                        writeTable[curAddr++] = 0x10000 + (code - 0xD800) * 0x400 + (codeTrail - 0xDC00);\n                    else\n                        throw new Error(\"Incorrect surrogate pair in \"  + this.encodingName + \" at chunk \" + chunk[0]);\n                }\n                else if (0x0FF0 < code && code <= 0x0FFF) { // Character sequence (our own encoding used)\n                    var len = 0xFFF - code + 2;\n                    var seq = [];\n                    for (var m = 0; m < len; m++)\n                        seq.push(part.charCodeAt(l++)); // Simple variation: don't support surrogates or subsequences in seq.\n\n                    writeTable[curAddr++] = SEQ_START - this.decodeTableSeq.length;\n                    this.decodeTableSeq.push(seq);\n                }\n                else\n                    writeTable[curAddr++] = code; // Basic char\n            }\n        } \n        else if (typeof part === \"number\") { // Integer, meaning increasing sequence starting with prev character.\n            var charCode = writeTable[curAddr - 1] + 1;\n            for (var l = 0; l < part; l++)\n                writeTable[curAddr++] = charCode++;\n        }\n        else\n            throw new Error(\"Incorrect type '\" + typeof part + \"' given in \"  + this.encodingName + \" at chunk \" + chunk[0]);\n    }\n    if (curAddr > 0xFF)\n        throw new Error(\"Incorrect chunk in \"  + this.encodingName + \" at addr \" + chunk[0] + \": too long\" + curAddr);\n}\n\n// Encoder helpers\nDBCSCodec.prototype._getEncodeBucket = function(uCode) {\n    var high = uCode >> 8; // This could be > 0xFF because of astral characters.\n    if (this.encodeTable[high] === undefined)\n        this.encodeTable[high] = UNASSIGNED_NODE.slice(0); // Create bucket on demand.\n    return this.encodeTable[high];\n}\n\nDBCSCodec.prototype._setEncodeChar = function(uCode, dbcsCode) {\n    var bucket = this._getEncodeBucket(uCode);\n    var low = uCode & 0xFF;\n    if (bucket[low] <= SEQ_START)\n        this.encodeTableSeq[SEQ_START-bucket[low]][DEF_CHAR] = dbcsCode; // There's already a sequence, set a single-char subsequence of it.\n    else if (bucket[low] == UNASSIGNED)\n        bucket[low] = dbcsCode;\n}\n\nDBCSCodec.prototype._setEncodeSequence = function(seq, dbcsCode) {\n    \n    // Get the root of character tree according to first character of the sequence.\n    var uCode = seq[0];\n    var bucket = this._getEncodeBucket(uCode);\n    var low = uCode & 0xFF;\n\n    var node;\n    if (bucket[low] <= SEQ_START) {\n        // There's already a sequence with  - use it.\n        node = this.encodeTableSeq[SEQ_START-bucket[low]];\n    }\n    else {\n        // There was no sequence object - allocate a new one.\n        node = {};\n        if (bucket[low] !== UNASSIGNED) node[DEF_CHAR] = bucket[low]; // If a char was set before - make it a single-char subsequence.\n        bucket[low] = SEQ_START - this.encodeTableSeq.length;\n        this.encodeTableSeq.push(node);\n    }\n\n    // Traverse the character tree, allocating new nodes as needed.\n    for (var j = 1; j < seq.length-1; j++) {\n        var oldVal = node[uCode];\n        if (typeof oldVal === 'object')\n            node = oldVal;\n        else {\n            node = node[uCode] = {}\n            if (oldVal !== undefined)\n                node[DEF_CHAR] = oldVal\n        }\n    }\n\n    // Set the leaf to given dbcsCode.\n    uCode = seq[seq.length-1];\n    node[uCode] = dbcsCode;\n}\n\nDBCSCodec.prototype._fillEncodeTable = function(nodeIdx, prefix, skipEncodeChars) {\n    var node = this.decodeTables[nodeIdx];\n    for (var i = 0; i < 0x100; i++) {\n        var uCode = node[i];\n        var mbCode = prefix + i;\n        if (skipEncodeChars[mbCode])\n            continue;\n\n        if (uCode >= 0)\n            this._setEncodeChar(uCode, mbCode);\n        else if (uCode <= NODE_START)\n            this._fillEncodeTable(NODE_START - uCode, mbCode << 8, skipEncodeChars);\n        else if (uCode <= SEQ_START)\n            this._setEncodeSequence(this.decodeTableSeq[SEQ_START - uCode], mbCode);\n    }\n}\n\n\n\n// == Encoder ==================================================================\n\nfunction DBCSEncoder(options, codec) {\n    // Encoder state\n    this.leadSurrogate = -1;\n    this.seqObj = undefined;\n    \n    // Static data\n    this.encodeTable = codec.encodeTable;\n    this.encodeTableSeq = codec.encodeTableSeq;\n    this.defaultCharSingleByte = codec.defCharSB;\n    this.gb18030 = codec.gb18030;\n}\n\nDBCSEncoder.prototype.write = function(str) {\n    var newBuf = new Buffer(str.length * (this.gb18030 ? 4 : 3)), \n        leadSurrogate = this.leadSurrogate,\n        seqObj = this.seqObj, nextChar = -1,\n        i = 0, j = 0;\n\n    while (true) {\n        // 0. Get next character.\n        if (nextChar === -1) {\n            if (i == str.length) break;\n            var uCode = str.charCodeAt(i++);\n        }\n        else {\n            var uCode = nextChar;\n            nextChar = -1;    \n        }\n\n        // 1. Handle surrogates.\n        if (0xD800 <= uCode && uCode < 0xE000) { // Char is one of surrogates.\n            if (uCode < 0xDC00) { // We've got lead surrogate.\n                if (leadSurrogate === -1) {\n                    leadSurrogate = uCode;\n                    continue;\n                } else {\n                    leadSurrogate = uCode;\n                    // Double lead surrogate found.\n                    uCode = UNASSIGNED;\n                }\n            } else { // We've got trail surrogate.\n                if (leadSurrogate !== -1) {\n                    uCode = 0x10000 + (leadSurrogate - 0xD800) * 0x400 + (uCode - 0xDC00);\n                    leadSurrogate = -1;\n                } else {\n                    // Incomplete surrogate pair - only trail surrogate found.\n                    uCode = UNASSIGNED;\n                }\n                \n            }\n        }\n        else if (leadSurrogate !== -1) {\n            // Incomplete surrogate pair - only lead surrogate found.\n            nextChar = uCode; uCode = UNASSIGNED; // Write an error, then current char.\n            leadSurrogate = -1;\n        }\n\n        // 2. Convert uCode character.\n        var dbcsCode = UNASSIGNED;\n        if (seqObj !== undefined && uCode != UNASSIGNED) { // We are in the middle of the sequence\n            var resCode = seqObj[uCode];\n            if (typeof resCode === 'object') { // Sequence continues.\n                seqObj = resCode;\n                continue;\n\n            } else if (typeof resCode == 'number') { // Sequence finished. Write it.\n                dbcsCode = resCode;\n\n            } else if (resCode == undefined) { // Current character is not part of the sequence.\n\n                // Try default character for this sequence\n                resCode = seqObj[DEF_CHAR];\n                if (resCode !== undefined) {\n                    dbcsCode = resCode; // Found. Write it.\n                    nextChar = uCode; // Current character will be written too in the next iteration.\n\n                } else {\n                    // TODO: What if we have no default? (resCode == undefined)\n                    // Then, we should write first char of the sequence as-is and try the rest recursively.\n                    // Didn't do it for now because no encoding has this situation yet.\n                    // Currently, just skip the sequence and write current char.\n                }\n            }\n            seqObj = undefined;\n        }\n        else if (uCode >= 0) {  // Regular character\n            var subtable = this.encodeTable[uCode >> 8];\n            if (subtable !== undefined)\n                dbcsCode = subtable[uCode & 0xFF];\n            \n            if (dbcsCode <= SEQ_START) { // Sequence start\n                seqObj = this.encodeTableSeq[SEQ_START-dbcsCode];\n                continue;\n            }\n\n            if (dbcsCode == UNASSIGNED && this.gb18030) {\n                // Use GB18030 algorithm to find character(s) to write.\n                var idx = findIdx(this.gb18030.uChars, uCode);\n                if (idx != -1) {\n                    var dbcsCode = this.gb18030.gbChars[idx] + (uCode - this.gb18030.uChars[idx]);\n                    newBuf[j++] = 0x81 + Math.floor(dbcsCode / 12600); dbcsCode = dbcsCode % 12600;\n                    newBuf[j++] = 0x30 + Math.floor(dbcsCode / 1260); dbcsCode = dbcsCode % 1260;\n                    newBuf[j++] = 0x81 + Math.floor(dbcsCode / 10); dbcsCode = dbcsCode % 10;\n                    newBuf[j++] = 0x30 + dbcsCode;\n                    continue;\n                }\n            }\n        }\n\n        // 3. Write dbcsCode character.\n        if (dbcsCode === UNASSIGNED)\n            dbcsCode = this.defaultCharSingleByte;\n        \n        if (dbcsCode < 0x100) {\n            newBuf[j++] = dbcsCode;\n        }\n        else if (dbcsCode < 0x10000) {\n            newBuf[j++] = dbcsCode >> 8;   // high byte\n            newBuf[j++] = dbcsCode & 0xFF; // low byte\n        }\n        else {\n            newBuf[j++] = dbcsCode >> 16;\n            newBuf[j++] = (dbcsCode >> 8) & 0xFF;\n            newBuf[j++] = dbcsCode & 0xFF;\n        }\n    }\n\n    this.seqObj = seqObj;\n    this.leadSurrogate = leadSurrogate;\n    return newBuf.slice(0, j);\n}\n\nDBCSEncoder.prototype.end = function() {\n    if (this.leadSurrogate === -1 && this.seqObj === undefined)\n        return; // All clean. Most often case.\n\n    var newBuf = new Buffer(10), j = 0;\n\n    if (this.seqObj) { // We're in the sequence.\n        var dbcsCode = this.seqObj[DEF_CHAR];\n        if (dbcsCode !== undefined) { // Write beginning of the sequence.\n            if (dbcsCode < 0x100) {\n                newBuf[j++] = dbcsCode;\n            }\n            else {\n                newBuf[j++] = dbcsCode >> 8;   // high byte\n                newBuf[j++] = dbcsCode & 0xFF; // low byte\n            }\n        } else {\n            // See todo above.\n        }\n        this.seqObj = undefined;\n    }\n\n    if (this.leadSurrogate !== -1) {\n        // Incomplete surrogate pair - only lead surrogate found.\n        newBuf[j++] = this.defaultCharSingleByte;\n        this.leadSurrogate = -1;\n    }\n    \n    return newBuf.slice(0, j);\n}\n\n// Export for testing\nDBCSEncoder.prototype.findIdx = findIdx;\n\n\n// == Decoder ==================================================================\n\nfunction DBCSDecoder(options, codec) {\n    // Decoder state\n    this.nodeIdx = 0;\n    this.prevBuf = new Buffer(0);\n\n    // Static data\n    this.decodeTables = codec.decodeTables;\n    this.decodeTableSeq = codec.decodeTableSeq;\n    this.defaultCharUnicode = codec.defaultCharUnicode;\n    this.gb18030 = codec.gb18030;\n}\n\nDBCSDecoder.prototype.write = function(buf) {\n    var newBuf = new Buffer(buf.length*2),\n        nodeIdx = this.nodeIdx, \n        prevBuf = this.prevBuf, prevBufOffset = this.prevBuf.length,\n        seqStart = -this.prevBuf.length, // idx of the start of current parsed sequence.\n        uCode;\n\n    if (prevBufOffset > 0) // Make prev buf overlap a little to make it easier to slice later.\n        prevBuf = Buffer.concat([prevBuf, buf.slice(0, 10)]);\n    \n    for (var i = 0, j = 0; i < buf.length; i++) {\n        var curByte = (i >= 0) ? buf[i] : prevBuf[i + prevBufOffset];\n\n        // Lookup in current trie node.\n        var uCode = this.decodeTables[nodeIdx][curByte];\n\n        if (uCode >= 0) { \n            // Normal character, just use it.\n        }\n        else if (uCode === UNASSIGNED) { // Unknown char.\n            // TODO: Callback with seq.\n            //var curSeq = (seqStart >= 0) ? buf.slice(seqStart, i+1) : prevBuf.slice(seqStart + prevBufOffset, i+1 + prevBufOffset);\n            i = seqStart; // Try to parse again, after skipping first byte of the sequence ('i' will be incremented by 'for' cycle).\n            uCode = this.defaultCharUnicode.charCodeAt(0);\n        }\n        else if (uCode === GB18030_CODE) {\n            var curSeq = (seqStart >= 0) ? buf.slice(seqStart, i+1) : prevBuf.slice(seqStart + prevBufOffset, i+1 + prevBufOffset);\n            var ptr = (curSeq[0]-0x81)*12600 + (curSeq[1]-0x30)*1260 + (curSeq[2]-0x81)*10 + (curSeq[3]-0x30);\n            var idx = findIdx(this.gb18030.gbChars, ptr);\n            uCode = this.gb18030.uChars[idx] + ptr - this.gb18030.gbChars[idx];\n        }\n        else if (uCode <= NODE_START) { // Go to next trie node.\n            nodeIdx = NODE_START - uCode;\n            continue;\n        }\n        else if (uCode <= SEQ_START) { // Output a sequence of chars.\n            var seq = this.decodeTableSeq[SEQ_START - uCode];\n            for (var k = 0; k < seq.length - 1; k++) {\n                uCode = seq[k];\n                newBuf[j++] = uCode & 0xFF;\n                newBuf[j++] = uCode >> 8;\n            }\n            uCode = seq[seq.length-1];\n        }\n        else\n            throw new Error(\"iconv-lite internal error: invalid decoding table value \" + uCode + \" at \" + nodeIdx + \"/\" + curByte);\n\n        // Write the character to buffer, handling higher planes using surrogate pair.\n        if (uCode > 0xFFFF) { \n            uCode -= 0x10000;\n            var uCodeLead = 0xD800 + Math.floor(uCode / 0x400);\n            newBuf[j++] = uCodeLead & 0xFF;\n            newBuf[j++] = uCodeLead >> 8;\n\n            uCode = 0xDC00 + uCode % 0x400;\n        }\n        newBuf[j++] = uCode & 0xFF;\n        newBuf[j++] = uCode >> 8;\n\n        // Reset trie node.\n        nodeIdx = 0; seqStart = i+1;\n    }\n\n    this.nodeIdx = nodeIdx;\n    this.prevBuf = (seqStart >= 0) ? buf.slice(seqStart) : prevBuf.slice(seqStart + prevBufOffset);\n    return newBuf.slice(0, j).toString('ucs2');\n}\n\nDBCSDecoder.prototype.end = function() {\n    var ret = '';\n\n    // Try to parse all remaining chars.\n    while (this.prevBuf.length > 0) {\n        // Skip 1 character in the buffer.\n        ret += this.defaultCharUnicode;\n        var buf = this.prevBuf.slice(1);\n\n        // Parse remaining as usual.\n        this.prevBuf = new Buffer(0);\n        this.nodeIdx = 0;\n        if (buf.length > 0)\n            ret += this.write(buf);\n    }\n\n    this.nodeIdx = 0;\n    return ret;\n}\n\n// Binary search for GB18030. Returns largest i such that table[i] <= val.\nfunction findIdx(table, val) {\n    if (table[0] > val)\n        return -1;\n\n    var l = 0, r = table.length;\n    while (l < r-1) { // always table[l] <= val < table[r]\n        var mid = l + Math.floor((r-l+1)/2);\n        if (table[mid] <= val)\n            l = mid;\n        else\n            r = mid;\n    }\n    return l;\n}\n\n\n\n/***/ }),\n/* 179 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// Description of supported double byte encodings and aliases.\n// Tables are not require()-d until they are needed to speed up library load.\n// require()-s are direct to support Browserify.\n\nmodule.exports = {\n    \n    // == Japanese/ShiftJIS ====================================================\n    // All japanese encodings are based on JIS X set of standards:\n    // JIS X 0201 - Single-byte encoding of ASCII + ¥ + Kana chars at 0xA1-0xDF.\n    // JIS X 0208 - Main set of 6879 characters, placed in 94x94 plane, to be encoded by 2 bytes. \n    //              Has several variations in 1978, 1983, 1990 and 1997.\n    // JIS X 0212 - Supplementary plane of 6067 chars in 94x94 plane. 1990. Effectively dead.\n    // JIS X 0213 - Extension and modern replacement of 0208 and 0212. Total chars: 11233.\n    //              2 planes, first is superset of 0208, second - revised 0212.\n    //              Introduced in 2000, revised 2004. Some characters are in Unicode Plane 2 (0x2xxxx)\n\n    // Byte encodings are:\n    //  * Shift_JIS: Compatible with 0201, uses not defined chars in top half as lead bytes for double-byte\n    //               encoding of 0208. Lead byte ranges: 0x81-0x9F, 0xE0-0xEF; Trail byte ranges: 0x40-0x7E, 0x80-0x9E, 0x9F-0xFC.\n    //               Windows CP932 is a superset of Shift_JIS. Some companies added more chars, notably KDDI.\n    //  * EUC-JP:    Up to 3 bytes per character. Used mostly on *nixes.\n    //               0x00-0x7F       - lower part of 0201\n    //               0x8E, 0xA1-0xDF - upper part of 0201\n    //               (0xA1-0xFE)x2   - 0208 plane (94x94).\n    //               0x8F, (0xA1-0xFE)x2 - 0212 plane (94x94).\n    //  * JIS X 208: 7-bit, direct encoding of 0208. Byte ranges: 0x21-0x7E (94 values). Uncommon.\n    //               Used as-is in ISO2022 family.\n    //  * ISO2022-JP: Stateful encoding, with escape sequences to switch between ASCII, \n    //                0201-1976 Roman, 0208-1978, 0208-1983.\n    //  * ISO2022-JP-1: Adds esc seq for 0212-1990.\n    //  * ISO2022-JP-2: Adds esc seq for GB2313-1980, KSX1001-1992, ISO8859-1, ISO8859-7.\n    //  * ISO2022-JP-3: Adds esc seq for 0201-1976 Kana set, 0213-2000 Planes 1, 2.\n    //  * ISO2022-JP-2004: Adds 0213-2004 Plane 1.\n    //\n    // After JIS X 0213 appeared, Shift_JIS-2004, EUC-JISX0213 and ISO2022-JP-2004 followed, with just changing the planes.\n    //\n    // Overall, it seems that it's a mess :( http://www8.plala.or.jp/tkubota1/unicode-symbols-map2.html\n\n    'shiftjis': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(180) },\n        encodeAdd: {'\\u00a5': 0x5C, '\\u203E': 0x7E},\n        encodeSkipVals: [{from: 0xED40, to: 0xF940}],\n    },\n    'csshiftjis': 'shiftjis',\n    'mskanji': 'shiftjis',\n    'sjis': 'shiftjis',\n    'windows31j': 'shiftjis',\n    'ms31j': 'shiftjis',\n    'xsjis': 'shiftjis',\n    'windows932': 'shiftjis',\n    'ms932': 'shiftjis',\n    '932': 'shiftjis',\n    'cp932': 'shiftjis',\n\n    'eucjp': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(181) },\n        encodeAdd: {'\\u00a5': 0x5C, '\\u203E': 0x7E},\n    },\n\n    // TODO: KDDI extension to Shift_JIS\n    // TODO: IBM CCSID 942 = CP932, but F0-F9 custom chars and other char changes.\n    // TODO: IBM CCSID 943 = Shift_JIS = CP932 with original Shift_JIS lower 128 chars.\n\n\n    // == Chinese/GBK ==========================================================\n    // http://en.wikipedia.org/wiki/GBK\n    // We mostly implement W3C recommendation: https://www.w3.org/TR/encoding/#gbk-encoder\n\n    // Oldest GB2312 (1981, ~7600 chars) is a subset of CP936\n    'gb2312': 'cp936',\n    'gb231280': 'cp936',\n    'gb23121980': 'cp936',\n    'csgb2312': 'cp936',\n    'csiso58gb231280': 'cp936',\n    'euccn': 'cp936',\n\n    // Microsoft's CP936 is a subset and approximation of GBK.\n    'windows936': 'cp936',\n    'ms936': 'cp936',\n    '936': 'cp936',\n    'cp936': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(53) },\n    },\n\n    // GBK (~22000 chars) is an extension of CP936 that added user-mapped chars and some other.\n    'gbk': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(53).concat(__webpack_require__(91)) },\n    },\n    'xgbk': 'gbk',\n    'isoir58': 'gbk',\n\n    // GB18030 is an algorithmic extension of GBK.\n    // Main source: https://www.w3.org/TR/encoding/#gbk-encoder\n    // http://icu-project.org/docs/papers/gb18030.html\n    // http://source.icu-project.org/repos/icu/data/trunk/charset/data/xml/gb-18030-2000.xml\n    // http://www.khngai.com/chinese/charmap/tblgbk.php?page=0\n    'gb18030': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(53).concat(__webpack_require__(91)) },\n        gb18030: function() { return __webpack_require__(182) },\n        encodeSkipVals: [0x80],\n        encodeAdd: {'€': 0xA2E3},\n    },\n\n    'chinese': 'gb18030',\n\n\n    // == Korean ===============================================================\n    // EUC-KR, KS_C_5601 and KS X 1001 are exactly the same.\n    'windows949': 'cp949',\n    'ms949': 'cp949',\n    '949': 'cp949',\n    'cp949': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(183) },\n    },\n\n    'cseuckr': 'cp949',\n    'csksc56011987': 'cp949',\n    'euckr': 'cp949',\n    'isoir149': 'cp949',\n    'korean': 'cp949',\n    'ksc56011987': 'cp949',\n    'ksc56011989': 'cp949',\n    'ksc5601': 'cp949',\n\n\n    // == Big5/Taiwan/Hong Kong ================================================\n    // There are lots of tables for Big5 and cp950. Please see the following links for history:\n    // http://moztw.org/docs/big5/  http://www.haible.de/bruno/charsets/conversion-tables/Big5.html\n    // Variations, in roughly number of defined chars:\n    //  * Windows CP 950: Microsoft variant of Big5. Canonical: http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP950.TXT\n    //  * Windows CP 951: Microsoft variant of Big5-HKSCS-2001. Seems to be never public. http://me.abelcheung.org/articles/research/what-is-cp951/\n    //  * Big5-2003 (Taiwan standard) almost superset of cp950.\n    //  * Unicode-at-on (UAO) / Mozilla 1.8. Falling out of use on the Web. Not supported by other browsers.\n    //  * Big5-HKSCS (-2001, -2004, -2008). Hong Kong standard. \n    //    many unicode code points moved from PUA to Supplementary plane (U+2XXXX) over the years.\n    //    Plus, it has 4 combining sequences.\n    //    Seems that Mozilla refused to support it for 10 yrs. https://bugzilla.mozilla.org/show_bug.cgi?id=162431 https://bugzilla.mozilla.org/show_bug.cgi?id=310299\n    //    because big5-hkscs is the only encoding to include astral characters in non-algorithmic way.\n    //    Implementations are not consistent within browsers; sometimes labeled as just big5.\n    //    MS Internet Explorer switches from big5 to big5-hkscs when a patch applied.\n    //    Great discussion & recap of what's going on https://bugzilla.mozilla.org/show_bug.cgi?id=912470#c31\n    //    In the encoder, it might make sense to support encoding old PUA mappings to Big5 bytes seq-s.\n    //    Official spec: http://www.ogcio.gov.hk/en/business/tech_promotion/ccli/terms/doc/2003cmp_2008.txt\n    //                   http://www.ogcio.gov.hk/tc/business/tech_promotion/ccli/terms/doc/hkscs-2008-big5-iso.txt\n    // \n    // Current understanding of how to deal with Big5(-HKSCS) is in the Encoding Standard, http://encoding.spec.whatwg.org/#big5-encoder\n    // Unicode mapping (http://www.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/OTHER/BIG5.TXT) is said to be wrong.\n\n    'windows950': 'cp950',\n    'ms950': 'cp950',\n    '950': 'cp950',\n    'cp950': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(92) },\n    },\n\n    // Big5 has many variations and is an extension of cp950. We use Encoding Standard's as a consensus.\n    'big5': 'big5hkscs',\n    'big5hkscs': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(92).concat(__webpack_require__(184)) },\n        encodeSkipVals: [0xa2cc],\n    },\n\n    'cnbig5': 'big5hkscs',\n    'csbig5': 'big5hkscs',\n    'xxbig5': 'big5hkscs',\n};\n\n\n/***/ }),\n/* 180 */\n/***/ (function(module, exports) {\n\nmodule.exports = [[\"0\",\"\\u0000\",128],[\"a1\",\"｡\",62],[\"8140\",\"　、。，．・：；？！゛゜´｀¨＾￣＿ヽヾゝゞ〃仝々〆〇ー―‐／＼～∥｜…‥‘’“”（）〔〕［］｛｝〈\",9,\"＋－±×\"],[\"8180\",\"÷＝≠＜＞≦≧∞∴♂♀°′″℃￥＄￠￡％＃＆＊＠§☆★○●◎◇◆□■△▲▽▼※〒→←↑↓〓\"],[\"81b8\",\"∈∋⊆⊇⊂⊃∪∩\"],[\"81c8\",\"∧∨￢⇒⇔∀∃\"],[\"81da\",\"∠⊥⌒∂∇≡≒≪≫√∽∝∵∫∬\"],[\"81f0\",\"Å‰♯♭♪†‡¶\"],[\"81fc\",\"◯\"],[\"824f\",\"０\",9],[\"8260\",\"Ａ\",25],[\"8281\",\"ａ\",25],[\"829f\",\"ぁ\",82],[\"8340\",\"ァ\",62],[\"8380\",\"ム\",22],[\"839f\",\"Α\",16,\"Σ\",6],[\"83bf\",\"α\",16,\"σ\",6],[\"8440\",\"А\",5,\"ЁЖ\",25],[\"8470\",\"а\",5,\"ёж\",7],[\"8480\",\"о\",17],[\"849f\",\"─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂\"],[\"8740\",\"①\",19,\"Ⅰ\",9],[\"875f\",\"㍉㌔㌢㍍㌘㌧㌃㌶㍑㍗㌍㌦㌣㌫㍊㌻㎜㎝㎞㎎㎏㏄㎡\"],[\"877e\",\"㍻\"],[\"8780\",\"〝〟№㏍℡㊤\",4,\"㈱㈲㈹㍾㍽㍼≒≡∫∮∑√⊥∠∟⊿∵∩∪\"],[\"889f\",\"亜唖娃阿哀愛挨姶逢葵茜穐悪握渥旭葦芦鯵梓圧斡扱宛姐虻飴絢綾鮎或粟袷安庵按暗案闇鞍杏以伊位依偉囲夷委威尉惟意慰易椅為畏異移維緯胃萎衣謂違遺医井亥域育郁磯一壱溢逸稲茨芋鰯允印咽員因姻引飲淫胤蔭\"],[\"8940\",\"院陰隠韻吋右宇烏羽迂雨卯鵜窺丑碓臼渦嘘唄欝蔚鰻姥厩浦瓜閏噂云運雲荏餌叡営嬰影映曳栄永泳洩瑛盈穎頴英衛詠鋭液疫益駅悦謁越閲榎厭円\"],[\"8980\",\"園堰奄宴延怨掩援沿演炎焔煙燕猿縁艶苑薗遠鉛鴛塩於汚甥凹央奥往応押旺横欧殴王翁襖鴬鴎黄岡沖荻億屋憶臆桶牡乙俺卸恩温穏音下化仮何伽価佳加可嘉夏嫁家寡科暇果架歌河火珂禍禾稼箇花苛茄荷華菓蝦課嘩貨迦過霞蚊俄峨我牙画臥芽蛾賀雅餓駕介会解回塊壊廻快怪悔恢懐戒拐改\"],[\"8a40\",\"魁晦械海灰界皆絵芥蟹開階貝凱劾外咳害崖慨概涯碍蓋街該鎧骸浬馨蛙垣柿蛎鈎劃嚇各廓拡撹格核殻獲確穫覚角赫較郭閣隔革学岳楽額顎掛笠樫\"],[\"8a80\",\"橿梶鰍潟割喝恰括活渇滑葛褐轄且鰹叶椛樺鞄株兜竃蒲釜鎌噛鴨栢茅萱粥刈苅瓦乾侃冠寒刊勘勧巻喚堪姦完官寛干幹患感慣憾換敢柑桓棺款歓汗漢澗潅環甘監看竿管簡緩缶翰肝艦莞観諌貫還鑑間閑関陥韓館舘丸含岸巌玩癌眼岩翫贋雁頑顔願企伎危喜器基奇嬉寄岐希幾忌揮机旗既期棋棄\"],[\"8b40\",\"機帰毅気汽畿祈季稀紀徽規記貴起軌輝飢騎鬼亀偽儀妓宜戯技擬欺犠疑祇義蟻誼議掬菊鞠吉吃喫桔橘詰砧杵黍却客脚虐逆丘久仇休及吸宮弓急救\"],[\"8b80\",\"朽求汲泣灸球究窮笈級糾給旧牛去居巨拒拠挙渠虚許距鋸漁禦魚亨享京供侠僑兇競共凶協匡卿叫喬境峡強彊怯恐恭挟教橋況狂狭矯胸脅興蕎郷鏡響饗驚仰凝尭暁業局曲極玉桐粁僅勤均巾錦斤欣欽琴禁禽筋緊芹菌衿襟謹近金吟銀九倶句区狗玖矩苦躯駆駈駒具愚虞喰空偶寓遇隅串櫛釧屑屈\"],[\"8c40\",\"掘窟沓靴轡窪熊隈粂栗繰桑鍬勲君薫訓群軍郡卦袈祁係傾刑兄啓圭珪型契形径恵慶慧憩掲携敬景桂渓畦稽系経継繋罫茎荊蛍計詣警軽頚鶏芸迎鯨\"],[\"8c80\",\"劇戟撃激隙桁傑欠決潔穴結血訣月件倹倦健兼券剣喧圏堅嫌建憲懸拳捲検権牽犬献研硯絹県肩見謙賢軒遣鍵険顕験鹸元原厳幻弦減源玄現絃舷言諺限乎個古呼固姑孤己庫弧戸故枯湖狐糊袴股胡菰虎誇跨鈷雇顧鼓五互伍午呉吾娯後御悟梧檎瑚碁語誤護醐乞鯉交佼侯候倖光公功効勾厚口向\"],[\"8d40\",\"后喉坑垢好孔孝宏工巧巷幸広庚康弘恒慌抗拘控攻昂晃更杭校梗構江洪浩港溝甲皇硬稿糠紅紘絞綱耕考肯肱腔膏航荒行衡講貢購郊酵鉱砿鋼閤降\"],[\"8d80\",\"項香高鴻剛劫号合壕拷濠豪轟麹克刻告国穀酷鵠黒獄漉腰甑忽惚骨狛込此頃今困坤墾婚恨懇昏昆根梱混痕紺艮魂些佐叉唆嵯左差査沙瑳砂詐鎖裟坐座挫債催再最哉塞妻宰彩才採栽歳済災采犀砕砦祭斎細菜裁載際剤在材罪財冴坂阪堺榊肴咲崎埼碕鷺作削咋搾昨朔柵窄策索錯桜鮭笹匙冊刷\"],[\"8e40\",\"察拶撮擦札殺薩雑皐鯖捌錆鮫皿晒三傘参山惨撒散桟燦珊産算纂蚕讃賛酸餐斬暫残仕仔伺使刺司史嗣四士始姉姿子屍市師志思指支孜斯施旨枝止\"],[\"8e80\",\"死氏獅祉私糸紙紫肢脂至視詞詩試誌諮資賜雌飼歯事似侍児字寺慈持時次滋治爾璽痔磁示而耳自蒔辞汐鹿式識鴫竺軸宍雫七叱執失嫉室悉湿漆疾質実蔀篠偲柴芝屡蕊縞舎写射捨赦斜煮社紗者謝車遮蛇邪借勺尺杓灼爵酌釈錫若寂弱惹主取守手朱殊狩珠種腫趣酒首儒受呪寿授樹綬需囚収周\"],[\"8f40\",\"宗就州修愁拾洲秀秋終繍習臭舟蒐衆襲讐蹴輯週酋酬集醜什住充十従戎柔汁渋獣縦重銃叔夙宿淑祝縮粛塾熟出術述俊峻春瞬竣舜駿准循旬楯殉淳\"],[\"8f80\",\"準潤盾純巡遵醇順処初所暑曙渚庶緒署書薯藷諸助叙女序徐恕鋤除傷償勝匠升召哨商唱嘗奨妾娼宵将小少尚庄床廠彰承抄招掌捷昇昌昭晶松梢樟樵沼消渉湘焼焦照症省硝礁祥称章笑粧紹肖菖蒋蕉衝裳訟証詔詳象賞醤鉦鍾鐘障鞘上丈丞乗冗剰城場壌嬢常情擾条杖浄状畳穣蒸譲醸錠嘱埴飾\"],[\"9040\",\"拭植殖燭織職色触食蝕辱尻伸信侵唇娠寝審心慎振新晋森榛浸深申疹真神秦紳臣芯薪親診身辛進針震人仁刃塵壬尋甚尽腎訊迅陣靭笥諏須酢図厨\"],[\"9080\",\"逗吹垂帥推水炊睡粋翠衰遂酔錐錘随瑞髄崇嵩数枢趨雛据杉椙菅頗雀裾澄摺寸世瀬畝是凄制勢姓征性成政整星晴棲栖正清牲生盛精聖声製西誠誓請逝醒青静斉税脆隻席惜戚斥昔析石積籍績脊責赤跡蹟碩切拙接摂折設窃節説雪絶舌蝉仙先千占宣専尖川戦扇撰栓栴泉浅洗染潜煎煽旋穿箭線\"],[\"9140\",\"繊羨腺舛船薦詮賎践選遷銭銑閃鮮前善漸然全禅繕膳糎噌塑岨措曾曽楚狙疏疎礎祖租粗素組蘇訴阻遡鼠僧創双叢倉喪壮奏爽宋層匝惣想捜掃挿掻\"],[\"9180\",\"操早曹巣槍槽漕燥争痩相窓糟総綜聡草荘葬蒼藻装走送遭鎗霜騒像増憎臓蔵贈造促側則即息捉束測足速俗属賊族続卒袖其揃存孫尊損村遜他多太汰詑唾堕妥惰打柁舵楕陀駄騨体堆対耐岱帯待怠態戴替泰滞胎腿苔袋貸退逮隊黛鯛代台大第醍題鷹滝瀧卓啄宅托択拓沢濯琢託鐸濁諾茸凧蛸只\"],[\"9240\",\"叩但達辰奪脱巽竪辿棚谷狸鱈樽誰丹単嘆坦担探旦歎淡湛炭短端箪綻耽胆蛋誕鍛団壇弾断暖檀段男談値知地弛恥智池痴稚置致蜘遅馳築畜竹筑蓄\"],[\"9280\",\"逐秩窒茶嫡着中仲宙忠抽昼柱注虫衷註酎鋳駐樗瀦猪苧著貯丁兆凋喋寵帖帳庁弔張彫徴懲挑暢朝潮牒町眺聴脹腸蝶調諜超跳銚長頂鳥勅捗直朕沈珍賃鎮陳津墜椎槌追鎚痛通塚栂掴槻佃漬柘辻蔦綴鍔椿潰坪壷嬬紬爪吊釣鶴亭低停偵剃貞呈堤定帝底庭廷弟悌抵挺提梯汀碇禎程締艇訂諦蹄逓\"],[\"9340\",\"邸鄭釘鼎泥摘擢敵滴的笛適鏑溺哲徹撤轍迭鉄典填天展店添纏甜貼転顛点伝殿澱田電兎吐堵塗妬屠徒斗杜渡登菟賭途都鍍砥砺努度土奴怒倒党冬\"],[\"9380\",\"凍刀唐塔塘套宕島嶋悼投搭東桃梼棟盗淘湯涛灯燈当痘祷等答筒糖統到董蕩藤討謄豆踏逃透鐙陶頭騰闘働動同堂導憧撞洞瞳童胴萄道銅峠鴇匿得徳涜特督禿篤毒独読栃橡凸突椴届鳶苫寅酉瀞噸屯惇敦沌豚遁頓呑曇鈍奈那内乍凪薙謎灘捺鍋楢馴縄畷南楠軟難汝二尼弐迩匂賑肉虹廿日乳入\"],[\"9440\",\"如尿韮任妊忍認濡禰祢寧葱猫熱年念捻撚燃粘乃廼之埜嚢悩濃納能脳膿農覗蚤巴把播覇杷波派琶破婆罵芭馬俳廃拝排敗杯盃牌背肺輩配倍培媒梅\"],[\"9480\",\"楳煤狽買売賠陪這蝿秤矧萩伯剥博拍柏泊白箔粕舶薄迫曝漠爆縛莫駁麦函箱硲箸肇筈櫨幡肌畑畠八鉢溌発醗髪伐罰抜筏閥鳩噺塙蛤隼伴判半反叛帆搬斑板氾汎版犯班畔繁般藩販範釆煩頒飯挽晩番盤磐蕃蛮匪卑否妃庇彼悲扉批披斐比泌疲皮碑秘緋罷肥被誹費避非飛樋簸備尾微枇毘琵眉美\"],[\"9540\",\"鼻柊稗匹疋髭彦膝菱肘弼必畢筆逼桧姫媛紐百謬俵彪標氷漂瓢票表評豹廟描病秒苗錨鋲蒜蛭鰭品彬斌浜瀕貧賓頻敏瓶不付埠夫婦富冨布府怖扶敷\"],[\"9580\",\"斧普浮父符腐膚芙譜負賦赴阜附侮撫武舞葡蕪部封楓風葺蕗伏副復幅服福腹複覆淵弗払沸仏物鮒分吻噴墳憤扮焚奮粉糞紛雰文聞丙併兵塀幣平弊柄並蔽閉陛米頁僻壁癖碧別瞥蔑箆偏変片篇編辺返遍便勉娩弁鞭保舗鋪圃捕歩甫補輔穂募墓慕戊暮母簿菩倣俸包呆報奉宝峰峯崩庖抱捧放方朋\"],[\"9640\",\"法泡烹砲縫胞芳萌蓬蜂褒訪豊邦鋒飽鳳鵬乏亡傍剖坊妨帽忘忙房暴望某棒冒紡肪膨謀貌貿鉾防吠頬北僕卜墨撲朴牧睦穆釦勃没殆堀幌奔本翻凡盆\"],[\"9680\",\"摩磨魔麻埋妹昧枚毎哩槙幕膜枕鮪柾鱒桝亦俣又抹末沫迄侭繭麿万慢満漫蔓味未魅巳箕岬密蜜湊蓑稔脈妙粍民眠務夢無牟矛霧鵡椋婿娘冥名命明盟迷銘鳴姪牝滅免棉綿緬面麺摸模茂妄孟毛猛盲網耗蒙儲木黙目杢勿餅尤戻籾貰問悶紋門匁也冶夜爺耶野弥矢厄役約薬訳躍靖柳薮鑓愉愈油癒\"],[\"9740\",\"諭輸唯佑優勇友宥幽悠憂揖有柚湧涌猶猷由祐裕誘遊邑郵雄融夕予余与誉輿預傭幼妖容庸揚揺擁曜楊様洋溶熔用窯羊耀葉蓉要謡踊遥陽養慾抑欲\"],[\"9780\",\"沃浴翌翼淀羅螺裸来莱頼雷洛絡落酪乱卵嵐欄濫藍蘭覧利吏履李梨理璃痢裏裡里離陸律率立葎掠略劉流溜琉留硫粒隆竜龍侶慮旅虜了亮僚両凌寮料梁涼猟療瞭稜糧良諒遼量陵領力緑倫厘林淋燐琳臨輪隣鱗麟瑠塁涙累類令伶例冷励嶺怜玲礼苓鈴隷零霊麗齢暦歴列劣烈裂廉恋憐漣煉簾練聯\"],[\"9840\",\"蓮連錬呂魯櫓炉賂路露労婁廊弄朗楼榔浪漏牢狼篭老聾蝋郎六麓禄肋録論倭和話歪賄脇惑枠鷲亙亘鰐詫藁蕨椀湾碗腕\"],[\"989f\",\"弌丐丕个丱丶丼丿乂乖乘亂亅豫亊舒弍于亞亟亠亢亰亳亶从仍仄仆仂仗仞仭仟价伉佚估佛佝佗佇佶侈侏侘佻佩佰侑佯來侖儘俔俟俎俘俛俑俚俐俤俥倚倨倔倪倥倅伜俶倡倩倬俾俯們倆偃假會偕偐偈做偖偬偸傀傚傅傴傲\"],[\"9940\",\"僉僊傳僂僖僞僥僭僣僮價僵儉儁儂儖儕儔儚儡儺儷儼儻儿兀兒兌兔兢竸兩兪兮冀冂囘册冉冏冑冓冕冖冤冦冢冩冪冫决冱冲冰况冽凅凉凛几處凩凭\"],[\"9980\",\"凰凵凾刄刋刔刎刧刪刮刳刹剏剄剋剌剞剔剪剴剩剳剿剽劍劔劒剱劈劑辨辧劬劭劼劵勁勍勗勞勣勦飭勠勳勵勸勹匆匈甸匍匐匏匕匚匣匯匱匳匸區卆卅丗卉卍凖卞卩卮夘卻卷厂厖厠厦厥厮厰厶參簒雙叟曼燮叮叨叭叺吁吽呀听吭吼吮吶吩吝呎咏呵咎呟呱呷呰咒呻咀呶咄咐咆哇咢咸咥咬哄哈咨\"],[\"9a40\",\"咫哂咤咾咼哘哥哦唏唔哽哮哭哺哢唹啀啣啌售啜啅啖啗唸唳啝喙喀咯喊喟啻啾喘喞單啼喃喩喇喨嗚嗅嗟嗄嗜嗤嗔嘔嗷嘖嗾嗽嘛嗹噎噐營嘴嘶嘲嘸\"],[\"9a80\",\"噫噤嘯噬噪嚆嚀嚊嚠嚔嚏嚥嚮嚶嚴囂嚼囁囃囀囈囎囑囓囗囮囹圀囿圄圉圈國圍圓團圖嗇圜圦圷圸坎圻址坏坩埀垈坡坿垉垓垠垳垤垪垰埃埆埔埒埓堊埖埣堋堙堝塲堡塢塋塰毀塒堽塹墅墹墟墫墺壞墻墸墮壅壓壑壗壙壘壥壜壤壟壯壺壹壻壼壽夂夊夐夛梦夥夬夭夲夸夾竒奕奐奎奚奘奢奠奧奬奩\"],[\"9b40\",\"奸妁妝佞侫妣妲姆姨姜妍姙姚娥娟娑娜娉娚婀婬婉娵娶婢婪媚媼媾嫋嫂媽嫣嫗嫦嫩嫖嫺嫻嬌嬋嬖嬲嫐嬪嬶嬾孃孅孀孑孕孚孛孥孩孰孳孵學斈孺宀\"],[\"9b80\",\"它宦宸寃寇寉寔寐寤實寢寞寥寫寰寶寳尅將專對尓尠尢尨尸尹屁屆屎屓屐屏孱屬屮乢屶屹岌岑岔妛岫岻岶岼岷峅岾峇峙峩峽峺峭嶌峪崋崕崗嵜崟崛崑崔崢崚崙崘嵌嵒嵎嵋嵬嵳嵶嶇嶄嶂嶢嶝嶬嶮嶽嶐嶷嶼巉巍巓巒巖巛巫已巵帋帚帙帑帛帶帷幄幃幀幎幗幔幟幢幤幇幵并幺麼广庠廁廂廈廐廏\"],[\"9c40\",\"廖廣廝廚廛廢廡廨廩廬廱廳廰廴廸廾弃弉彝彜弋弑弖弩弭弸彁彈彌彎弯彑彖彗彙彡彭彳彷徃徂彿徊很徑徇從徙徘徠徨徭徼忖忻忤忸忱忝悳忿怡恠\"],[\"9c80\",\"怙怐怩怎怱怛怕怫怦怏怺恚恁恪恷恟恊恆恍恣恃恤恂恬恫恙悁悍惧悃悚悄悛悖悗悒悧悋惡悸惠惓悴忰悽惆悵惘慍愕愆惶惷愀惴惺愃愡惻惱愍愎慇愾愨愧慊愿愼愬愴愽慂慄慳慷慘慙慚慫慴慯慥慱慟慝慓慵憙憖憇憬憔憚憊憑憫憮懌懊應懷懈懃懆憺懋罹懍懦懣懶懺懴懿懽懼懾戀戈戉戍戌戔戛\"],[\"9d40\",\"戞戡截戮戰戲戳扁扎扞扣扛扠扨扼抂抉找抒抓抖拔抃抔拗拑抻拏拿拆擔拈拜拌拊拂拇抛拉挌拮拱挧挂挈拯拵捐挾捍搜捏掖掎掀掫捶掣掏掉掟掵捫\"],[\"9d80\",\"捩掾揩揀揆揣揉插揶揄搖搴搆搓搦搶攝搗搨搏摧摯摶摎攪撕撓撥撩撈撼據擒擅擇撻擘擂擱擧舉擠擡抬擣擯攬擶擴擲擺攀擽攘攜攅攤攣攫攴攵攷收攸畋效敖敕敍敘敞敝敲數斂斃變斛斟斫斷旃旆旁旄旌旒旛旙无旡旱杲昊昃旻杳昵昶昴昜晏晄晉晁晞晝晤晧晨晟晢晰暃暈暎暉暄暘暝曁暹曉暾暼\"],[\"9e40\",\"曄暸曖曚曠昿曦曩曰曵曷朏朖朞朦朧霸朮朿朶杁朸朷杆杞杠杙杣杤枉杰枩杼杪枌枋枦枡枅枷柯枴柬枳柩枸柤柞柝柢柮枹柎柆柧檜栞框栩桀桍栲桎\"],[\"9e80\",\"梳栫桙档桷桿梟梏梭梔條梛梃檮梹桴梵梠梺椏梍桾椁棊椈棘椢椦棡椌棍棔棧棕椶椒椄棗棣椥棹棠棯椨椪椚椣椡棆楹楷楜楸楫楔楾楮椹楴椽楙椰楡楞楝榁楪榲榮槐榿槁槓榾槎寨槊槝榻槃榧樮榑榠榜榕榴槞槨樂樛槿權槹槲槧樅榱樞槭樔槫樊樒櫁樣樓橄樌橲樶橸橇橢橙橦橈樸樢檐檍檠檄檢檣\"],[\"9f40\",\"檗蘗檻櫃櫂檸檳檬櫞櫑櫟檪櫚櫪櫻欅蘖櫺欒欖鬱欟欸欷盜欹飮歇歃歉歐歙歔歛歟歡歸歹歿殀殄殃殍殘殕殞殤殪殫殯殲殱殳殷殼毆毋毓毟毬毫毳毯\"],[\"9f80\",\"麾氈氓气氛氤氣汞汕汢汪沂沍沚沁沛汾汨汳沒沐泄泱泓沽泗泅泝沮沱沾沺泛泯泙泪洟衍洶洫洽洸洙洵洳洒洌浣涓浤浚浹浙涎涕濤涅淹渕渊涵淇淦涸淆淬淞淌淨淒淅淺淙淤淕淪淮渭湮渮渙湲湟渾渣湫渫湶湍渟湃渺湎渤滿渝游溂溪溘滉溷滓溽溯滄溲滔滕溏溥滂溟潁漑灌滬滸滾漿滲漱滯漲滌\"],[\"e040\",\"漾漓滷澆潺潸澁澀潯潛濳潭澂潼潘澎澑濂潦澳澣澡澤澹濆澪濟濕濬濔濘濱濮濛瀉瀋濺瀑瀁瀏濾瀛瀚潴瀝瀘瀟瀰瀾瀲灑灣炙炒炯烱炬炸炳炮烟烋烝\"],[\"e080\",\"烙焉烽焜焙煥煕熈煦煢煌煖煬熏燻熄熕熨熬燗熹熾燒燉燔燎燠燬燧燵燼燹燿爍爐爛爨爭爬爰爲爻爼爿牀牆牋牘牴牾犂犁犇犒犖犢犧犹犲狃狆狄狎狒狢狠狡狹狷倏猗猊猜猖猝猴猯猩猥猾獎獏默獗獪獨獰獸獵獻獺珈玳珎玻珀珥珮珞璢琅瑯琥珸琲琺瑕琿瑟瑙瑁瑜瑩瑰瑣瑪瑶瑾璋璞璧瓊瓏瓔珱\"],[\"e140\",\"瓠瓣瓧瓩瓮瓲瓰瓱瓸瓷甄甃甅甌甎甍甕甓甞甦甬甼畄畍畊畉畛畆畚畩畤畧畫畭畸當疆疇畴疊疉疂疔疚疝疥疣痂疳痃疵疽疸疼疱痍痊痒痙痣痞痾痿\"],[\"e180\",\"痼瘁痰痺痲痳瘋瘍瘉瘟瘧瘠瘡瘢瘤瘴瘰瘻癇癈癆癜癘癡癢癨癩癪癧癬癰癲癶癸發皀皃皈皋皎皖皓皙皚皰皴皸皹皺盂盍盖盒盞盡盥盧盪蘯盻眈眇眄眩眤眞眥眦眛眷眸睇睚睨睫睛睥睿睾睹瞎瞋瞑瞠瞞瞰瞶瞹瞿瞼瞽瞻矇矍矗矚矜矣矮矼砌砒礦砠礪硅碎硴碆硼碚碌碣碵碪碯磑磆磋磔碾碼磅磊磬\"],[\"e240\",\"磧磚磽磴礇礒礑礙礬礫祀祠祗祟祚祕祓祺祿禊禝禧齋禪禮禳禹禺秉秕秧秬秡秣稈稍稘稙稠稟禀稱稻稾稷穃穗穉穡穢穩龝穰穹穽窈窗窕窘窖窩竈窰\"],[\"e280\",\"窶竅竄窿邃竇竊竍竏竕竓站竚竝竡竢竦竭竰笂笏笊笆笳笘笙笞笵笨笶筐筺笄筍笋筌筅筵筥筴筧筰筱筬筮箝箘箟箍箜箚箋箒箏筝箙篋篁篌篏箴篆篝篩簑簔篦篥籠簀簇簓篳篷簗簍篶簣簧簪簟簷簫簽籌籃籔籏籀籐籘籟籤籖籥籬籵粃粐粤粭粢粫粡粨粳粲粱粮粹粽糀糅糂糘糒糜糢鬻糯糲糴糶糺紆\"],[\"e340\",\"紂紜紕紊絅絋紮紲紿紵絆絳絖絎絲絨絮絏絣經綉絛綏絽綛綺綮綣綵緇綽綫總綢綯緜綸綟綰緘緝緤緞緻緲緡縅縊縣縡縒縱縟縉縋縢繆繦縻縵縹繃縷\"],[\"e380\",\"縲縺繧繝繖繞繙繚繹繪繩繼繻纃緕繽辮繿纈纉續纒纐纓纔纖纎纛纜缸缺罅罌罍罎罐网罕罔罘罟罠罨罩罧罸羂羆羃羈羇羌羔羞羝羚羣羯羲羹羮羶羸譱翅翆翊翕翔翡翦翩翳翹飜耆耄耋耒耘耙耜耡耨耿耻聊聆聒聘聚聟聢聨聳聲聰聶聹聽聿肄肆肅肛肓肚肭冐肬胛胥胙胝胄胚胖脉胯胱脛脩脣脯腋\"],[\"e440\",\"隋腆脾腓腑胼腱腮腥腦腴膃膈膊膀膂膠膕膤膣腟膓膩膰膵膾膸膽臀臂膺臉臍臑臙臘臈臚臟臠臧臺臻臾舁舂舅與舊舍舐舖舩舫舸舳艀艙艘艝艚艟艤\"],[\"e480\",\"艢艨艪艫舮艱艷艸艾芍芒芫芟芻芬苡苣苟苒苴苳苺莓范苻苹苞茆苜茉苙茵茴茖茲茱荀茹荐荅茯茫茗茘莅莚莪莟莢莖茣莎莇莊荼莵荳荵莠莉莨菴萓菫菎菽萃菘萋菁菷萇菠菲萍萢萠莽萸蔆菻葭萪萼蕚蒄葷葫蒭葮蒂葩葆萬葯葹萵蓊葢蒹蒿蒟蓙蓍蒻蓚蓐蓁蓆蓖蒡蔡蓿蓴蔗蔘蔬蔟蔕蔔蓼蕀蕣蕘蕈\"],[\"e540\",\"蕁蘂蕋蕕薀薤薈薑薊薨蕭薔薛藪薇薜蕷蕾薐藉薺藏薹藐藕藝藥藜藹蘊蘓蘋藾藺蘆蘢蘚蘰蘿虍乕虔號虧虱蚓蚣蚩蚪蚋蚌蚶蚯蛄蛆蚰蛉蠣蚫蛔蛞蛩蛬\"],[\"e580\",\"蛟蛛蛯蜒蜆蜈蜀蜃蛻蜑蜉蜍蛹蜊蜴蜿蜷蜻蜥蜩蜚蝠蝟蝸蝌蝎蝴蝗蝨蝮蝙蝓蝣蝪蠅螢螟螂螯蟋螽蟀蟐雖螫蟄螳蟇蟆螻蟯蟲蟠蠏蠍蟾蟶蟷蠎蟒蠑蠖蠕蠢蠡蠱蠶蠹蠧蠻衄衂衒衙衞衢衫袁衾袞衵衽袵衲袂袗袒袮袙袢袍袤袰袿袱裃裄裔裘裙裝裹褂裼裴裨裲褄褌褊褓襃褞褥褪褫襁襄褻褶褸襌褝襠襞\"],[\"e640\",\"襦襤襭襪襯襴襷襾覃覈覊覓覘覡覩覦覬覯覲覺覽覿觀觚觜觝觧觴觸訃訖訐訌訛訝訥訶詁詛詒詆詈詼詭詬詢誅誂誄誨誡誑誥誦誚誣諄諍諂諚諫諳諧\"],[\"e680\",\"諤諱謔諠諢諷諞諛謌謇謚諡謖謐謗謠謳鞫謦謫謾謨譁譌譏譎證譖譛譚譫譟譬譯譴譽讀讌讎讒讓讖讙讚谺豁谿豈豌豎豐豕豢豬豸豺貂貉貅貊貍貎貔豼貘戝貭貪貽貲貳貮貶賈賁賤賣賚賽賺賻贄贅贊贇贏贍贐齎贓賍贔贖赧赭赱赳趁趙跂趾趺跏跚跖跌跛跋跪跫跟跣跼踈踉跿踝踞踐踟蹂踵踰踴蹊\"],[\"e740\",\"蹇蹉蹌蹐蹈蹙蹤蹠踪蹣蹕蹶蹲蹼躁躇躅躄躋躊躓躑躔躙躪躡躬躰軆躱躾軅軈軋軛軣軼軻軫軾輊輅輕輒輙輓輜輟輛輌輦輳輻輹轅轂輾轌轉轆轎轗轜\"],[\"e780\",\"轢轣轤辜辟辣辭辯辷迚迥迢迪迯邇迴逅迹迺逑逕逡逍逞逖逋逧逶逵逹迸遏遐遑遒逎遉逾遖遘遞遨遯遶隨遲邂遽邁邀邊邉邏邨邯邱邵郢郤扈郛鄂鄒鄙鄲鄰酊酖酘酣酥酩酳酲醋醉醂醢醫醯醪醵醴醺釀釁釉釋釐釖釟釡釛釼釵釶鈞釿鈔鈬鈕鈑鉞鉗鉅鉉鉤鉈銕鈿鉋鉐銜銖銓銛鉚鋏銹銷鋩錏鋺鍄錮\"],[\"e840\",\"錙錢錚錣錺錵錻鍜鍠鍼鍮鍖鎰鎬鎭鎔鎹鏖鏗鏨鏥鏘鏃鏝鏐鏈鏤鐚鐔鐓鐃鐇鐐鐶鐫鐵鐡鐺鑁鑒鑄鑛鑠鑢鑞鑪鈩鑰鑵鑷鑽鑚鑼鑾钁鑿閂閇閊閔閖閘閙\"],[\"e880\",\"閠閨閧閭閼閻閹閾闊濶闃闍闌闕闔闖關闡闥闢阡阨阮阯陂陌陏陋陷陜陞陝陟陦陲陬隍隘隕隗險隧隱隲隰隴隶隸隹雎雋雉雍襍雜霍雕雹霄霆霈霓霎霑霏霖霙霤霪霰霹霽霾靄靆靈靂靉靜靠靤靦靨勒靫靱靹鞅靼鞁靺鞆鞋鞏鞐鞜鞨鞦鞣鞳鞴韃韆韈韋韜韭齏韲竟韶韵頏頌頸頤頡頷頽顆顏顋顫顯顰\"],[\"e940\",\"顱顴顳颪颯颱颶飄飃飆飩飫餃餉餒餔餘餡餝餞餤餠餬餮餽餾饂饉饅饐饋饑饒饌饕馗馘馥馭馮馼駟駛駝駘駑駭駮駱駲駻駸騁騏騅駢騙騫騷驅驂驀驃\"],[\"e980\",\"騾驕驍驛驗驟驢驥驤驩驫驪骭骰骼髀髏髑髓體髞髟髢髣髦髯髫髮髴髱髷髻鬆鬘鬚鬟鬢鬣鬥鬧鬨鬩鬪鬮鬯鬲魄魃魏魍魎魑魘魴鮓鮃鮑鮖鮗鮟鮠鮨鮴鯀鯊鮹鯆鯏鯑鯒鯣鯢鯤鯔鯡鰺鯲鯱鯰鰕鰔鰉鰓鰌鰆鰈鰒鰊鰄鰮鰛鰥鰤鰡鰰鱇鰲鱆鰾鱚鱠鱧鱶鱸鳧鳬鳰鴉鴈鳫鴃鴆鴪鴦鶯鴣鴟鵄鴕鴒鵁鴿鴾鵆鵈\"],[\"ea40\",\"鵝鵞鵤鵑鵐鵙鵲鶉鶇鶫鵯鵺鶚鶤鶩鶲鷄鷁鶻鶸鶺鷆鷏鷂鷙鷓鷸鷦鷭鷯鷽鸚鸛鸞鹵鹹鹽麁麈麋麌麒麕麑麝麥麩麸麪麭靡黌黎黏黐黔黜點黝黠黥黨黯\"],[\"ea80\",\"黴黶黷黹黻黼黽鼇鼈皷鼕鼡鼬鼾齊齒齔齣齟齠齡齦齧齬齪齷齲齶龕龜龠堯槇遙瑤凜熙\"],[\"ed40\",\"纊褜鍈銈蓜俉炻昱棈鋹曻彅丨仡仼伀伃伹佖侒侊侚侔俍偀倢俿倞偆偰偂傔僴僘兊兤冝冾凬刕劜劦勀勛匀匇匤卲厓厲叝﨎咜咊咩哿喆坙坥垬埈埇﨏\"],[\"ed80\",\"塚增墲夋奓奛奝奣妤妺孖寀甯寘寬尞岦岺峵崧嵓﨑嵂嵭嶸嶹巐弡弴彧德忞恝悅悊惞惕愠惲愑愷愰憘戓抦揵摠撝擎敎昀昕昻昉昮昞昤晥晗晙晴晳暙暠暲暿曺朎朗杦枻桒柀栁桄棏﨓楨﨔榘槢樰橫橆橳橾櫢櫤毖氿汜沆汯泚洄涇浯涖涬淏淸淲淼渹湜渧渼溿澈澵濵瀅瀇瀨炅炫焏焄煜煆煇凞燁燾犱\"],[\"ee40\",\"犾猤猪獷玽珉珖珣珒琇珵琦琪琩琮瑢璉璟甁畯皂皜皞皛皦益睆劯砡硎硤硺礰礼神祥禔福禛竑竧靖竫箞精絈絜綷綠緖繒罇羡羽茁荢荿菇菶葈蒴蕓蕙\"],[\"ee80\",\"蕫﨟薰蘒﨡蠇裵訒訷詹誧誾諟諸諶譓譿賰賴贒赶﨣軏﨤逸遧郞都鄕鄧釚釗釞釭釮釤釥鈆鈐鈊鈺鉀鈼鉎鉙鉑鈹鉧銧鉷鉸鋧鋗鋙鋐﨧鋕鋠鋓錥錡鋻﨨錞鋿錝錂鍰鍗鎤鏆鏞鏸鐱鑅鑈閒隆﨩隝隯霳霻靃靍靏靑靕顗顥飯飼餧館馞驎髙髜魵魲鮏鮱鮻鰀鵰鵫鶴鸙黑\"],[\"eeef\",\"ⅰ\",9,\"￢￤＇＂\"],[\"f040\",\"\",62],[\"f080\",\"\",124],[\"f140\",\"\",62],[\"f180\",\"\",124],[\"f240\",\"\",62],[\"f280\",\"\",124],[\"f340\",\"\",62],[\"f380\",\"\",124],[\"f440\",\"\",62],[\"f480\",\"\",124],[\"f540\",\"\",62],[\"f580\",\"\",124],[\"f640\",\"\",62],[\"f680\",\"\",124],[\"f740\",\"\",62],[\"f780\",\"\",124],[\"f840\",\"\",62],[\"f880\",\"\",124],[\"f940\",\"\"],[\"fa40\",\"ⅰ\",9,\"Ⅰ\",9,\"￢￤＇＂㈱№℡∵纊褜鍈銈蓜俉炻昱棈鋹曻彅丨仡仼伀伃伹佖侒侊侚侔俍偀倢俿倞偆偰偂傔僴僘兊\"],[\"fa80\",\"兤冝冾凬刕劜劦勀勛匀匇匤卲厓厲叝﨎咜咊咩哿喆坙坥垬埈埇﨏塚增墲夋奓奛奝奣妤妺孖寀甯寘寬尞岦岺峵崧嵓﨑嵂嵭嶸嶹巐弡弴彧德忞恝悅悊惞惕愠惲愑愷愰憘戓抦揵摠撝擎敎昀昕昻昉昮昞昤晥晗晙晴晳暙暠暲暿曺朎朗杦枻桒柀栁桄棏﨓楨﨔榘槢樰橫橆橳橾櫢櫤毖氿汜沆汯泚洄涇浯\"],[\"fb40\",\"涖涬淏淸淲淼渹湜渧渼溿澈澵濵瀅瀇瀨炅炫焏焄煜煆煇凞燁燾犱犾猤猪獷玽珉珖珣珒琇珵琦琪琩琮瑢璉璟甁畯皂皜皞皛皦益睆劯砡硎硤硺礰礼神\"],[\"fb80\",\"祥禔福禛竑竧靖竫箞精絈絜綷綠緖繒罇羡羽茁荢荿菇菶葈蒴蕓蕙蕫﨟薰蘒﨡蠇裵訒訷詹誧誾諟諸諶譓譿賰賴贒赶﨣軏﨤逸遧郞都鄕鄧釚釗釞釭釮釤釥鈆鈐鈊鈺鉀鈼鉎鉙鉑鈹鉧銧鉷鉸鋧鋗鋙鋐﨧鋕鋠鋓錥錡鋻﨨錞鋿錝錂鍰鍗鎤鏆鏞鏸鐱鑅鑈閒隆﨩隝隯霳霻靃靍靏靑靕顗顥飯飼餧館馞驎髙\"],[\"fc40\",\"髜魵魲鮏鮱鮻鰀鵰鵫鶴鸙黑\"]]\n\n/***/ }),\n/* 181 */\n/***/ (function(module, exports) {\n\nmodule.exports = [[\"0\",\"\\u0000\",127],[\"8ea1\",\"｡\",62],[\"a1a1\",\"　、。，．・：；？！゛゜´｀¨＾￣＿ヽヾゝゞ〃仝々〆〇ー―‐／＼～∥｜…‥‘’“”（）〔〕［］｛｝〈\",9,\"＋－±×÷＝≠＜＞≦≧∞∴♂♀°′″℃￥＄￠￡％＃＆＊＠§☆★○●◎◇\"],[\"a2a1\",\"◆□■△▲▽▼※〒→←↑↓〓\"],[\"a2ba\",\"∈∋⊆⊇⊂⊃∪∩\"],[\"a2ca\",\"∧∨￢⇒⇔∀∃\"],[\"a2dc\",\"∠⊥⌒∂∇≡≒≪≫√∽∝∵∫∬\"],[\"a2f2\",\"Å‰♯♭♪†‡¶\"],[\"a2fe\",\"◯\"],[\"a3b0\",\"０\",9],[\"a3c1\",\"Ａ\",25],[\"a3e1\",\"ａ\",25],[\"a4a1\",\"ぁ\",82],[\"a5a1\",\"ァ\",85],[\"a6a1\",\"Α\",16,\"Σ\",6],[\"a6c1\",\"α\",16,\"σ\",6],[\"a7a1\",\"А\",5,\"ЁЖ\",25],[\"a7d1\",\"а\",5,\"ёж\",25],[\"a8a1\",\"─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂\"],[\"ada1\",\"①\",19,\"Ⅰ\",9],[\"adc0\",\"㍉㌔㌢㍍㌘㌧㌃㌶㍑㍗㌍㌦㌣㌫㍊㌻㎜㎝㎞㎎㎏㏄㎡\"],[\"addf\",\"㍻〝〟№㏍℡㊤\",4,\"㈱㈲㈹㍾㍽㍼≒≡∫∮∑√⊥∠∟⊿∵∩∪\"],[\"b0a1\",\"亜唖娃阿哀愛挨姶逢葵茜穐悪握渥旭葦芦鯵梓圧斡扱宛姐虻飴絢綾鮎或粟袷安庵按暗案闇鞍杏以伊位依偉囲夷委威尉惟意慰易椅為畏異移維緯胃萎衣謂違遺医井亥域育郁磯一壱溢逸稲茨芋鰯允印咽員因姻引飲淫胤蔭\"],[\"b1a1\",\"院陰隠韻吋右宇烏羽迂雨卯鵜窺丑碓臼渦嘘唄欝蔚鰻姥厩浦瓜閏噂云運雲荏餌叡営嬰影映曳栄永泳洩瑛盈穎頴英衛詠鋭液疫益駅悦謁越閲榎厭円園堰奄宴延怨掩援沿演炎焔煙燕猿縁艶苑薗遠鉛鴛塩於汚甥凹央奥往応\"],[\"b2a1\",\"押旺横欧殴王翁襖鴬鴎黄岡沖荻億屋憶臆桶牡乙俺卸恩温穏音下化仮何伽価佳加可嘉夏嫁家寡科暇果架歌河火珂禍禾稼箇花苛茄荷華菓蝦課嘩貨迦過霞蚊俄峨我牙画臥芽蛾賀雅餓駕介会解回塊壊廻快怪悔恢懐戒拐改\"],[\"b3a1\",\"魁晦械海灰界皆絵芥蟹開階貝凱劾外咳害崖慨概涯碍蓋街該鎧骸浬馨蛙垣柿蛎鈎劃嚇各廓拡撹格核殻獲確穫覚角赫較郭閣隔革学岳楽額顎掛笠樫橿梶鰍潟割喝恰括活渇滑葛褐轄且鰹叶椛樺鞄株兜竃蒲釜鎌噛鴨栢茅萱\"],[\"b4a1\",\"粥刈苅瓦乾侃冠寒刊勘勧巻喚堪姦完官寛干幹患感慣憾換敢柑桓棺款歓汗漢澗潅環甘監看竿管簡緩缶翰肝艦莞観諌貫還鑑間閑関陥韓館舘丸含岸巌玩癌眼岩翫贋雁頑顔願企伎危喜器基奇嬉寄岐希幾忌揮机旗既期棋棄\"],[\"b5a1\",\"機帰毅気汽畿祈季稀紀徽規記貴起軌輝飢騎鬼亀偽儀妓宜戯技擬欺犠疑祇義蟻誼議掬菊鞠吉吃喫桔橘詰砧杵黍却客脚虐逆丘久仇休及吸宮弓急救朽求汲泣灸球究窮笈級糾給旧牛去居巨拒拠挙渠虚許距鋸漁禦魚亨享京\"],[\"b6a1\",\"供侠僑兇競共凶協匡卿叫喬境峡強彊怯恐恭挟教橋況狂狭矯胸脅興蕎郷鏡響饗驚仰凝尭暁業局曲極玉桐粁僅勤均巾錦斤欣欽琴禁禽筋緊芹菌衿襟謹近金吟銀九倶句区狗玖矩苦躯駆駈駒具愚虞喰空偶寓遇隅串櫛釧屑屈\"],[\"b7a1\",\"掘窟沓靴轡窪熊隈粂栗繰桑鍬勲君薫訓群軍郡卦袈祁係傾刑兄啓圭珪型契形径恵慶慧憩掲携敬景桂渓畦稽系経継繋罫茎荊蛍計詣警軽頚鶏芸迎鯨劇戟撃激隙桁傑欠決潔穴結血訣月件倹倦健兼券剣喧圏堅嫌建憲懸拳捲\"],[\"b8a1\",\"検権牽犬献研硯絹県肩見謙賢軒遣鍵険顕験鹸元原厳幻弦減源玄現絃舷言諺限乎個古呼固姑孤己庫弧戸故枯湖狐糊袴股胡菰虎誇跨鈷雇顧鼓五互伍午呉吾娯後御悟梧檎瑚碁語誤護醐乞鯉交佼侯候倖光公功効勾厚口向\"],[\"b9a1\",\"后喉坑垢好孔孝宏工巧巷幸広庚康弘恒慌抗拘控攻昂晃更杭校梗構江洪浩港溝甲皇硬稿糠紅紘絞綱耕考肯肱腔膏航荒行衡講貢購郊酵鉱砿鋼閤降項香高鴻剛劫号合壕拷濠豪轟麹克刻告国穀酷鵠黒獄漉腰甑忽惚骨狛込\"],[\"baa1\",\"此頃今困坤墾婚恨懇昏昆根梱混痕紺艮魂些佐叉唆嵯左差査沙瑳砂詐鎖裟坐座挫債催再最哉塞妻宰彩才採栽歳済災采犀砕砦祭斎細菜裁載際剤在材罪財冴坂阪堺榊肴咲崎埼碕鷺作削咋搾昨朔柵窄策索錯桜鮭笹匙冊刷\"],[\"bba1\",\"察拶撮擦札殺薩雑皐鯖捌錆鮫皿晒三傘参山惨撒散桟燦珊産算纂蚕讃賛酸餐斬暫残仕仔伺使刺司史嗣四士始姉姿子屍市師志思指支孜斯施旨枝止死氏獅祉私糸紙紫肢脂至視詞詩試誌諮資賜雌飼歯事似侍児字寺慈持時\"],[\"bca1\",\"次滋治爾璽痔磁示而耳自蒔辞汐鹿式識鴫竺軸宍雫七叱執失嫉室悉湿漆疾質実蔀篠偲柴芝屡蕊縞舎写射捨赦斜煮社紗者謝車遮蛇邪借勺尺杓灼爵酌釈錫若寂弱惹主取守手朱殊狩珠種腫趣酒首儒受呪寿授樹綬需囚収周\"],[\"bda1\",\"宗就州修愁拾洲秀秋終繍習臭舟蒐衆襲讐蹴輯週酋酬集醜什住充十従戎柔汁渋獣縦重銃叔夙宿淑祝縮粛塾熟出術述俊峻春瞬竣舜駿准循旬楯殉淳準潤盾純巡遵醇順処初所暑曙渚庶緒署書薯藷諸助叙女序徐恕鋤除傷償\"],[\"bea1\",\"勝匠升召哨商唱嘗奨妾娼宵将小少尚庄床廠彰承抄招掌捷昇昌昭晶松梢樟樵沼消渉湘焼焦照症省硝礁祥称章笑粧紹肖菖蒋蕉衝裳訟証詔詳象賞醤鉦鍾鐘障鞘上丈丞乗冗剰城場壌嬢常情擾条杖浄状畳穣蒸譲醸錠嘱埴飾\"],[\"bfa1\",\"拭植殖燭織職色触食蝕辱尻伸信侵唇娠寝審心慎振新晋森榛浸深申疹真神秦紳臣芯薪親診身辛進針震人仁刃塵壬尋甚尽腎訊迅陣靭笥諏須酢図厨逗吹垂帥推水炊睡粋翠衰遂酔錐錘随瑞髄崇嵩数枢趨雛据杉椙菅頗雀裾\"],[\"c0a1\",\"澄摺寸世瀬畝是凄制勢姓征性成政整星晴棲栖正清牲生盛精聖声製西誠誓請逝醒青静斉税脆隻席惜戚斥昔析石積籍績脊責赤跡蹟碩切拙接摂折設窃節説雪絶舌蝉仙先千占宣専尖川戦扇撰栓栴泉浅洗染潜煎煽旋穿箭線\"],[\"c1a1\",\"繊羨腺舛船薦詮賎践選遷銭銑閃鮮前善漸然全禅繕膳糎噌塑岨措曾曽楚狙疏疎礎祖租粗素組蘇訴阻遡鼠僧創双叢倉喪壮奏爽宋層匝惣想捜掃挿掻操早曹巣槍槽漕燥争痩相窓糟総綜聡草荘葬蒼藻装走送遭鎗霜騒像増憎\"],[\"c2a1\",\"臓蔵贈造促側則即息捉束測足速俗属賊族続卒袖其揃存孫尊損村遜他多太汰詑唾堕妥惰打柁舵楕陀駄騨体堆対耐岱帯待怠態戴替泰滞胎腿苔袋貸退逮隊黛鯛代台大第醍題鷹滝瀧卓啄宅托択拓沢濯琢託鐸濁諾茸凧蛸只\"],[\"c3a1\",\"叩但達辰奪脱巽竪辿棚谷狸鱈樽誰丹単嘆坦担探旦歎淡湛炭短端箪綻耽胆蛋誕鍛団壇弾断暖檀段男談値知地弛恥智池痴稚置致蜘遅馳築畜竹筑蓄逐秩窒茶嫡着中仲宙忠抽昼柱注虫衷註酎鋳駐樗瀦猪苧著貯丁兆凋喋寵\"],[\"c4a1\",\"帖帳庁弔張彫徴懲挑暢朝潮牒町眺聴脹腸蝶調諜超跳銚長頂鳥勅捗直朕沈珍賃鎮陳津墜椎槌追鎚痛通塚栂掴槻佃漬柘辻蔦綴鍔椿潰坪壷嬬紬爪吊釣鶴亭低停偵剃貞呈堤定帝底庭廷弟悌抵挺提梯汀碇禎程締艇訂諦蹄逓\"],[\"c5a1\",\"邸鄭釘鼎泥摘擢敵滴的笛適鏑溺哲徹撤轍迭鉄典填天展店添纏甜貼転顛点伝殿澱田電兎吐堵塗妬屠徒斗杜渡登菟賭途都鍍砥砺努度土奴怒倒党冬凍刀唐塔塘套宕島嶋悼投搭東桃梼棟盗淘湯涛灯燈当痘祷等答筒糖統到\"],[\"c6a1\",\"董蕩藤討謄豆踏逃透鐙陶頭騰闘働動同堂導憧撞洞瞳童胴萄道銅峠鴇匿得徳涜特督禿篤毒独読栃橡凸突椴届鳶苫寅酉瀞噸屯惇敦沌豚遁頓呑曇鈍奈那内乍凪薙謎灘捺鍋楢馴縄畷南楠軟難汝二尼弐迩匂賑肉虹廿日乳入\"],[\"c7a1\",\"如尿韮任妊忍認濡禰祢寧葱猫熱年念捻撚燃粘乃廼之埜嚢悩濃納能脳膿農覗蚤巴把播覇杷波派琶破婆罵芭馬俳廃拝排敗杯盃牌背肺輩配倍培媒梅楳煤狽買売賠陪這蝿秤矧萩伯剥博拍柏泊白箔粕舶薄迫曝漠爆縛莫駁麦\"],[\"c8a1\",\"函箱硲箸肇筈櫨幡肌畑畠八鉢溌発醗髪伐罰抜筏閥鳩噺塙蛤隼伴判半反叛帆搬斑板氾汎版犯班畔繁般藩販範釆煩頒飯挽晩番盤磐蕃蛮匪卑否妃庇彼悲扉批披斐比泌疲皮碑秘緋罷肥被誹費避非飛樋簸備尾微枇毘琵眉美\"],[\"c9a1\",\"鼻柊稗匹疋髭彦膝菱肘弼必畢筆逼桧姫媛紐百謬俵彪標氷漂瓢票表評豹廟描病秒苗錨鋲蒜蛭鰭品彬斌浜瀕貧賓頻敏瓶不付埠夫婦富冨布府怖扶敷斧普浮父符腐膚芙譜負賦赴阜附侮撫武舞葡蕪部封楓風葺蕗伏副復幅服\"],[\"caa1\",\"福腹複覆淵弗払沸仏物鮒分吻噴墳憤扮焚奮粉糞紛雰文聞丙併兵塀幣平弊柄並蔽閉陛米頁僻壁癖碧別瞥蔑箆偏変片篇編辺返遍便勉娩弁鞭保舗鋪圃捕歩甫補輔穂募墓慕戊暮母簿菩倣俸包呆報奉宝峰峯崩庖抱捧放方朋\"],[\"cba1\",\"法泡烹砲縫胞芳萌蓬蜂褒訪豊邦鋒飽鳳鵬乏亡傍剖坊妨帽忘忙房暴望某棒冒紡肪膨謀貌貿鉾防吠頬北僕卜墨撲朴牧睦穆釦勃没殆堀幌奔本翻凡盆摩磨魔麻埋妹昧枚毎哩槙幕膜枕鮪柾鱒桝亦俣又抹末沫迄侭繭麿万慢満\"],[\"cca1\",\"漫蔓味未魅巳箕岬密蜜湊蓑稔脈妙粍民眠務夢無牟矛霧鵡椋婿娘冥名命明盟迷銘鳴姪牝滅免棉綿緬面麺摸模茂妄孟毛猛盲網耗蒙儲木黙目杢勿餅尤戻籾貰問悶紋門匁也冶夜爺耶野弥矢厄役約薬訳躍靖柳薮鑓愉愈油癒\"],[\"cda1\",\"諭輸唯佑優勇友宥幽悠憂揖有柚湧涌猶猷由祐裕誘遊邑郵雄融夕予余与誉輿預傭幼妖容庸揚揺擁曜楊様洋溶熔用窯羊耀葉蓉要謡踊遥陽養慾抑欲沃浴翌翼淀羅螺裸来莱頼雷洛絡落酪乱卵嵐欄濫藍蘭覧利吏履李梨理璃\"],[\"cea1\",\"痢裏裡里離陸律率立葎掠略劉流溜琉留硫粒隆竜龍侶慮旅虜了亮僚両凌寮料梁涼猟療瞭稜糧良諒遼量陵領力緑倫厘林淋燐琳臨輪隣鱗麟瑠塁涙累類令伶例冷励嶺怜玲礼苓鈴隷零霊麗齢暦歴列劣烈裂廉恋憐漣煉簾練聯\"],[\"cfa1\",\"蓮連錬呂魯櫓炉賂路露労婁廊弄朗楼榔浪漏牢狼篭老聾蝋郎六麓禄肋録論倭和話歪賄脇惑枠鷲亙亘鰐詫藁蕨椀湾碗腕\"],[\"d0a1\",\"弌丐丕个丱丶丼丿乂乖乘亂亅豫亊舒弍于亞亟亠亢亰亳亶从仍仄仆仂仗仞仭仟价伉佚估佛佝佗佇佶侈侏侘佻佩佰侑佯來侖儘俔俟俎俘俛俑俚俐俤俥倚倨倔倪倥倅伜俶倡倩倬俾俯們倆偃假會偕偐偈做偖偬偸傀傚傅傴傲\"],[\"d1a1\",\"僉僊傳僂僖僞僥僭僣僮價僵儉儁儂儖儕儔儚儡儺儷儼儻儿兀兒兌兔兢竸兩兪兮冀冂囘册冉冏冑冓冕冖冤冦冢冩冪冫决冱冲冰况冽凅凉凛几處凩凭凰凵凾刄刋刔刎刧刪刮刳刹剏剄剋剌剞剔剪剴剩剳剿剽劍劔劒剱劈劑辨\"],[\"d2a1\",\"辧劬劭劼劵勁勍勗勞勣勦飭勠勳勵勸勹匆匈甸匍匐匏匕匚匣匯匱匳匸區卆卅丗卉卍凖卞卩卮夘卻卷厂厖厠厦厥厮厰厶參簒雙叟曼燮叮叨叭叺吁吽呀听吭吼吮吶吩吝呎咏呵咎呟呱呷呰咒呻咀呶咄咐咆哇咢咸咥咬哄哈咨\"],[\"d3a1\",\"咫哂咤咾咼哘哥哦唏唔哽哮哭哺哢唹啀啣啌售啜啅啖啗唸唳啝喙喀咯喊喟啻啾喘喞單啼喃喩喇喨嗚嗅嗟嗄嗜嗤嗔嘔嗷嘖嗾嗽嘛嗹噎噐營嘴嘶嘲嘸噫噤嘯噬噪嚆嚀嚊嚠嚔嚏嚥嚮嚶嚴囂嚼囁囃囀囈囎囑囓囗囮囹圀囿圄圉\"],[\"d4a1\",\"圈國圍圓團圖嗇圜圦圷圸坎圻址坏坩埀垈坡坿垉垓垠垳垤垪垰埃埆埔埒埓堊埖埣堋堙堝塲堡塢塋塰毀塒堽塹墅墹墟墫墺壞墻墸墮壅壓壑壗壙壘壥壜壤壟壯壺壹壻壼壽夂夊夐夛梦夥夬夭夲夸夾竒奕奐奎奚奘奢奠奧奬奩\"],[\"d5a1\",\"奸妁妝佞侫妣妲姆姨姜妍姙姚娥娟娑娜娉娚婀婬婉娵娶婢婪媚媼媾嫋嫂媽嫣嫗嫦嫩嫖嫺嫻嬌嬋嬖嬲嫐嬪嬶嬾孃孅孀孑孕孚孛孥孩孰孳孵學斈孺宀它宦宸寃寇寉寔寐寤實寢寞寥寫寰寶寳尅將專對尓尠尢尨尸尹屁屆屎屓\"],[\"d6a1\",\"屐屏孱屬屮乢屶屹岌岑岔妛岫岻岶岼岷峅岾峇峙峩峽峺峭嶌峪崋崕崗嵜崟崛崑崔崢崚崙崘嵌嵒嵎嵋嵬嵳嵶嶇嶄嶂嶢嶝嶬嶮嶽嶐嶷嶼巉巍巓巒巖巛巫已巵帋帚帙帑帛帶帷幄幃幀幎幗幔幟幢幤幇幵并幺麼广庠廁廂廈廐廏\"],[\"d7a1\",\"廖廣廝廚廛廢廡廨廩廬廱廳廰廴廸廾弃弉彝彜弋弑弖弩弭弸彁彈彌彎弯彑彖彗彙彡彭彳彷徃徂彿徊很徑徇從徙徘徠徨徭徼忖忻忤忸忱忝悳忿怡恠怙怐怩怎怱怛怕怫怦怏怺恚恁恪恷恟恊恆恍恣恃恤恂恬恫恙悁悍惧悃悚\"],[\"d8a1\",\"悄悛悖悗悒悧悋惡悸惠惓悴忰悽惆悵惘慍愕愆惶惷愀惴惺愃愡惻惱愍愎慇愾愨愧慊愿愼愬愴愽慂慄慳慷慘慙慚慫慴慯慥慱慟慝慓慵憙憖憇憬憔憚憊憑憫憮懌懊應懷懈懃懆憺懋罹懍懦懣懶懺懴懿懽懼懾戀戈戉戍戌戔戛\"],[\"d9a1\",\"戞戡截戮戰戲戳扁扎扞扣扛扠扨扼抂抉找抒抓抖拔抃抔拗拑抻拏拿拆擔拈拜拌拊拂拇抛拉挌拮拱挧挂挈拯拵捐挾捍搜捏掖掎掀掫捶掣掏掉掟掵捫捩掾揩揀揆揣揉插揶揄搖搴搆搓搦搶攝搗搨搏摧摯摶摎攪撕撓撥撩撈撼\"],[\"daa1\",\"據擒擅擇撻擘擂擱擧舉擠擡抬擣擯攬擶擴擲擺攀擽攘攜攅攤攣攫攴攵攷收攸畋效敖敕敍敘敞敝敲數斂斃變斛斟斫斷旃旆旁旄旌旒旛旙无旡旱杲昊昃旻杳昵昶昴昜晏晄晉晁晞晝晤晧晨晟晢晰暃暈暎暉暄暘暝曁暹曉暾暼\"],[\"dba1\",\"曄暸曖曚曠昿曦曩曰曵曷朏朖朞朦朧霸朮朿朶杁朸朷杆杞杠杙杣杤枉杰枩杼杪枌枋枦枡枅枷柯枴柬枳柩枸柤柞柝柢柮枹柎柆柧檜栞框栩桀桍栲桎梳栫桙档桷桿梟梏梭梔條梛梃檮梹桴梵梠梺椏梍桾椁棊椈棘椢椦棡椌棍\"],[\"dca1\",\"棔棧棕椶椒椄棗棣椥棹棠棯椨椪椚椣椡棆楹楷楜楸楫楔楾楮椹楴椽楙椰楡楞楝榁楪榲榮槐榿槁槓榾槎寨槊槝榻槃榧樮榑榠榜榕榴槞槨樂樛槿權槹槲槧樅榱樞槭樔槫樊樒櫁樣樓橄樌橲樶橸橇橢橙橦橈樸樢檐檍檠檄檢檣\"],[\"dda1\",\"檗蘗檻櫃櫂檸檳檬櫞櫑櫟檪櫚櫪櫻欅蘖櫺欒欖鬱欟欸欷盜欹飮歇歃歉歐歙歔歛歟歡歸歹歿殀殄殃殍殘殕殞殤殪殫殯殲殱殳殷殼毆毋毓毟毬毫毳毯麾氈氓气氛氤氣汞汕汢汪沂沍沚沁沛汾汨汳沒沐泄泱泓沽泗泅泝沮沱沾\"],[\"dea1\",\"沺泛泯泙泪洟衍洶洫洽洸洙洵洳洒洌浣涓浤浚浹浙涎涕濤涅淹渕渊涵淇淦涸淆淬淞淌淨淒淅淺淙淤淕淪淮渭湮渮渙湲湟渾渣湫渫湶湍渟湃渺湎渤滿渝游溂溪溘滉溷滓溽溯滄溲滔滕溏溥滂溟潁漑灌滬滸滾漿滲漱滯漲滌\"],[\"dfa1\",\"漾漓滷澆潺潸澁澀潯潛濳潭澂潼潘澎澑濂潦澳澣澡澤澹濆澪濟濕濬濔濘濱濮濛瀉瀋濺瀑瀁瀏濾瀛瀚潴瀝瀘瀟瀰瀾瀲灑灣炙炒炯烱炬炸炳炮烟烋烝烙焉烽焜焙煥煕熈煦煢煌煖煬熏燻熄熕熨熬燗熹熾燒燉燔燎燠燬燧燵燼\"],[\"e0a1\",\"燹燿爍爐爛爨爭爬爰爲爻爼爿牀牆牋牘牴牾犂犁犇犒犖犢犧犹犲狃狆狄狎狒狢狠狡狹狷倏猗猊猜猖猝猴猯猩猥猾獎獏默獗獪獨獰獸獵獻獺珈玳珎玻珀珥珮珞璢琅瑯琥珸琲琺瑕琿瑟瑙瑁瑜瑩瑰瑣瑪瑶瑾璋璞璧瓊瓏瓔珱\"],[\"e1a1\",\"瓠瓣瓧瓩瓮瓲瓰瓱瓸瓷甄甃甅甌甎甍甕甓甞甦甬甼畄畍畊畉畛畆畚畩畤畧畫畭畸當疆疇畴疊疉疂疔疚疝疥疣痂疳痃疵疽疸疼疱痍痊痒痙痣痞痾痿痼瘁痰痺痲痳瘋瘍瘉瘟瘧瘠瘡瘢瘤瘴瘰瘻癇癈癆癜癘癡癢癨癩癪癧癬癰\"],[\"e2a1\",\"癲癶癸發皀皃皈皋皎皖皓皙皚皰皴皸皹皺盂盍盖盒盞盡盥盧盪蘯盻眈眇眄眩眤眞眥眦眛眷眸睇睚睨睫睛睥睿睾睹瞎瞋瞑瞠瞞瞰瞶瞹瞿瞼瞽瞻矇矍矗矚矜矣矮矼砌砒礦砠礪硅碎硴碆硼碚碌碣碵碪碯磑磆磋磔碾碼磅磊磬\"],[\"e3a1\",\"磧磚磽磴礇礒礑礙礬礫祀祠祗祟祚祕祓祺祿禊禝禧齋禪禮禳禹禺秉秕秧秬秡秣稈稍稘稙稠稟禀稱稻稾稷穃穗穉穡穢穩龝穰穹穽窈窗窕窘窖窩竈窰窶竅竄窿邃竇竊竍竏竕竓站竚竝竡竢竦竭竰笂笏笊笆笳笘笙笞笵笨笶筐\"],[\"e4a1\",\"筺笄筍笋筌筅筵筥筴筧筰筱筬筮箝箘箟箍箜箚箋箒箏筝箙篋篁篌篏箴篆篝篩簑簔篦篥籠簀簇簓篳篷簗簍篶簣簧簪簟簷簫簽籌籃籔籏籀籐籘籟籤籖籥籬籵粃粐粤粭粢粫粡粨粳粲粱粮粹粽糀糅糂糘糒糜糢鬻糯糲糴糶糺紆\"],[\"e5a1\",\"紂紜紕紊絅絋紮紲紿紵絆絳絖絎絲絨絮絏絣經綉絛綏絽綛綺綮綣綵緇綽綫總綢綯緜綸綟綰緘緝緤緞緻緲緡縅縊縣縡縒縱縟縉縋縢繆繦縻縵縹繃縷縲縺繧繝繖繞繙繚繹繪繩繼繻纃緕繽辮繿纈纉續纒纐纓纔纖纎纛纜缸缺\"],[\"e6a1\",\"罅罌罍罎罐网罕罔罘罟罠罨罩罧罸羂羆羃羈羇羌羔羞羝羚羣羯羲羹羮羶羸譱翅翆翊翕翔翡翦翩翳翹飜耆耄耋耒耘耙耜耡耨耿耻聊聆聒聘聚聟聢聨聳聲聰聶聹聽聿肄肆肅肛肓肚肭冐肬胛胥胙胝胄胚胖脉胯胱脛脩脣脯腋\"],[\"e7a1\",\"隋腆脾腓腑胼腱腮腥腦腴膃膈膊膀膂膠膕膤膣腟膓膩膰膵膾膸膽臀臂膺臉臍臑臙臘臈臚臟臠臧臺臻臾舁舂舅與舊舍舐舖舩舫舸舳艀艙艘艝艚艟艤艢艨艪艫舮艱艷艸艾芍芒芫芟芻芬苡苣苟苒苴苳苺莓范苻苹苞茆苜茉苙\"],[\"e8a1\",\"茵茴茖茲茱荀茹荐荅茯茫茗茘莅莚莪莟莢莖茣莎莇莊荼莵荳荵莠莉莨菴萓菫菎菽萃菘萋菁菷萇菠菲萍萢萠莽萸蔆菻葭萪萼蕚蒄葷葫蒭葮蒂葩葆萬葯葹萵蓊葢蒹蒿蒟蓙蓍蒻蓚蓐蓁蓆蓖蒡蔡蓿蓴蔗蔘蔬蔟蔕蔔蓼蕀蕣蕘蕈\"],[\"e9a1\",\"蕁蘂蕋蕕薀薤薈薑薊薨蕭薔薛藪薇薜蕷蕾薐藉薺藏薹藐藕藝藥藜藹蘊蘓蘋藾藺蘆蘢蘚蘰蘿虍乕虔號虧虱蚓蚣蚩蚪蚋蚌蚶蚯蛄蛆蚰蛉蠣蚫蛔蛞蛩蛬蛟蛛蛯蜒蜆蜈蜀蜃蛻蜑蜉蜍蛹蜊蜴蜿蜷蜻蜥蜩蜚蝠蝟蝸蝌蝎蝴蝗蝨蝮蝙\"],[\"eaa1\",\"蝓蝣蝪蠅螢螟螂螯蟋螽蟀蟐雖螫蟄螳蟇蟆螻蟯蟲蟠蠏蠍蟾蟶蟷蠎蟒蠑蠖蠕蠢蠡蠱蠶蠹蠧蠻衄衂衒衙衞衢衫袁衾袞衵衽袵衲袂袗袒袮袙袢袍袤袰袿袱裃裄裔裘裙裝裹褂裼裴裨裲褄褌褊褓襃褞褥褪褫襁襄褻褶褸襌褝襠襞\"],[\"eba1\",\"襦襤襭襪襯襴襷襾覃覈覊覓覘覡覩覦覬覯覲覺覽覿觀觚觜觝觧觴觸訃訖訐訌訛訝訥訶詁詛詒詆詈詼詭詬詢誅誂誄誨誡誑誥誦誚誣諄諍諂諚諫諳諧諤諱謔諠諢諷諞諛謌謇謚諡謖謐謗謠謳鞫謦謫謾謨譁譌譏譎證譖譛譚譫\"],[\"eca1\",\"譟譬譯譴譽讀讌讎讒讓讖讙讚谺豁谿豈豌豎豐豕豢豬豸豺貂貉貅貊貍貎貔豼貘戝貭貪貽貲貳貮貶賈賁賤賣賚賽賺賻贄贅贊贇贏贍贐齎贓賍贔贖赧赭赱赳趁趙跂趾趺跏跚跖跌跛跋跪跫跟跣跼踈踉跿踝踞踐踟蹂踵踰踴蹊\"],[\"eda1\",\"蹇蹉蹌蹐蹈蹙蹤蹠踪蹣蹕蹶蹲蹼躁躇躅躄躋躊躓躑躔躙躪躡躬躰軆躱躾軅軈軋軛軣軼軻軫軾輊輅輕輒輙輓輜輟輛輌輦輳輻輹轅轂輾轌轉轆轎轗轜轢轣轤辜辟辣辭辯辷迚迥迢迪迯邇迴逅迹迺逑逕逡逍逞逖逋逧逶逵逹迸\"],[\"eea1\",\"遏遐遑遒逎遉逾遖遘遞遨遯遶隨遲邂遽邁邀邊邉邏邨邯邱邵郢郤扈郛鄂鄒鄙鄲鄰酊酖酘酣酥酩酳酲醋醉醂醢醫醯醪醵醴醺釀釁釉釋釐釖釟釡釛釼釵釶鈞釿鈔鈬鈕鈑鉞鉗鉅鉉鉤鉈銕鈿鉋鉐銜銖銓銛鉚鋏銹銷鋩錏鋺鍄錮\"],[\"efa1\",\"錙錢錚錣錺錵錻鍜鍠鍼鍮鍖鎰鎬鎭鎔鎹鏖鏗鏨鏥鏘鏃鏝鏐鏈鏤鐚鐔鐓鐃鐇鐐鐶鐫鐵鐡鐺鑁鑒鑄鑛鑠鑢鑞鑪鈩鑰鑵鑷鑽鑚鑼鑾钁鑿閂閇閊閔閖閘閙閠閨閧閭閼閻閹閾闊濶闃闍闌闕闔闖關闡闥闢阡阨阮阯陂陌陏陋陷陜陞\"],[\"f0a1\",\"陝陟陦陲陬隍隘隕隗險隧隱隲隰隴隶隸隹雎雋雉雍襍雜霍雕雹霄霆霈霓霎霑霏霖霙霤霪霰霹霽霾靄靆靈靂靉靜靠靤靦靨勒靫靱靹鞅靼鞁靺鞆鞋鞏鞐鞜鞨鞦鞣鞳鞴韃韆韈韋韜韭齏韲竟韶韵頏頌頸頤頡頷頽顆顏顋顫顯顰\"],[\"f1a1\",\"顱顴顳颪颯颱颶飄飃飆飩飫餃餉餒餔餘餡餝餞餤餠餬餮餽餾饂饉饅饐饋饑饒饌饕馗馘馥馭馮馼駟駛駝駘駑駭駮駱駲駻駸騁騏騅駢騙騫騷驅驂驀驃騾驕驍驛驗驟驢驥驤驩驫驪骭骰骼髀髏髑髓體髞髟髢髣髦髯髫髮髴髱髷\"],[\"f2a1\",\"髻鬆鬘鬚鬟鬢鬣鬥鬧鬨鬩鬪鬮鬯鬲魄魃魏魍魎魑魘魴鮓鮃鮑鮖鮗鮟鮠鮨鮴鯀鯊鮹鯆鯏鯑鯒鯣鯢鯤鯔鯡鰺鯲鯱鯰鰕鰔鰉鰓鰌鰆鰈鰒鰊鰄鰮鰛鰥鰤鰡鰰鱇鰲鱆鰾鱚鱠鱧鱶鱸鳧鳬鳰鴉鴈鳫鴃鴆鴪鴦鶯鴣鴟鵄鴕鴒鵁鴿鴾鵆鵈\"],[\"f3a1\",\"鵝鵞鵤鵑鵐鵙鵲鶉鶇鶫鵯鵺鶚鶤鶩鶲鷄鷁鶻鶸鶺鷆鷏鷂鷙鷓鷸鷦鷭鷯鷽鸚鸛鸞鹵鹹鹽麁麈麋麌麒麕麑麝麥麩麸麪麭靡黌黎黏黐黔黜點黝黠黥黨黯黴黶黷黹黻黼黽鼇鼈皷鼕鼡鼬鼾齊齒齔齣齟齠齡齦齧齬齪齷齲齶龕龜龠\"],[\"f4a1\",\"堯槇遙瑤凜熙\"],[\"f9a1\",\"纊褜鍈銈蓜俉炻昱棈鋹曻彅丨仡仼伀伃伹佖侒侊侚侔俍偀倢俿倞偆偰偂傔僴僘兊兤冝冾凬刕劜劦勀勛匀匇匤卲厓厲叝﨎咜咊咩哿喆坙坥垬埈埇﨏塚增墲夋奓奛奝奣妤妺孖寀甯寘寬尞岦岺峵崧嵓﨑嵂嵭嶸嶹巐弡弴彧德\"],[\"faa1\",\"忞恝悅悊惞惕愠惲愑愷愰憘戓抦揵摠撝擎敎昀昕昻昉昮昞昤晥晗晙晴晳暙暠暲暿曺朎朗杦枻桒柀栁桄棏﨓楨﨔榘槢樰橫橆橳橾櫢櫤毖氿汜沆汯泚洄涇浯涖涬淏淸淲淼渹湜渧渼溿澈澵濵瀅瀇瀨炅炫焏焄煜煆煇凞燁燾犱\"],[\"fba1\",\"犾猤猪獷玽珉珖珣珒琇珵琦琪琩琮瑢璉璟甁畯皂皜皞皛皦益睆劯砡硎硤硺礰礼神祥禔福禛竑竧靖竫箞精絈絜綷綠緖繒罇羡羽茁荢荿菇菶葈蒴蕓蕙蕫﨟薰蘒﨡蠇裵訒訷詹誧誾諟諸諶譓譿賰賴贒赶﨣軏﨤逸遧郞都鄕鄧釚\"],[\"fca1\",\"釗釞釭釮釤釥鈆鈐鈊鈺鉀鈼鉎鉙鉑鈹鉧銧鉷鉸鋧鋗鋙鋐﨧鋕鋠鋓錥錡鋻﨨錞鋿錝錂鍰鍗鎤鏆鏞鏸鐱鑅鑈閒隆﨩隝隯霳霻靃靍靏靑靕顗顥飯飼餧館馞驎髙髜魵魲鮏鮱鮻鰀鵰鵫鶴鸙黑\"],[\"fcf1\",\"ⅰ\",9,\"￢￤＇＂\"],[\"8fa2af\",\"˘ˇ¸˙˝¯˛˚～΄΅\"],[\"8fa2c2\",\"¡¦¿\"],[\"8fa2eb\",\"ºª©®™¤№\"],[\"8fa6e1\",\"ΆΈΉΊΪ\"],[\"8fa6e7\",\"Ό\"],[\"8fa6e9\",\"ΎΫ\"],[\"8fa6ec\",\"Ώ\"],[\"8fa6f1\",\"άέήίϊΐόςύϋΰώ\"],[\"8fa7c2\",\"Ђ\",10,\"ЎЏ\"],[\"8fa7f2\",\"ђ\",10,\"ўџ\"],[\"8fa9a1\",\"ÆĐ\"],[\"8fa9a4\",\"Ħ\"],[\"8fa9a6\",\"Ĳ\"],[\"8fa9a8\",\"ŁĿ\"],[\"8fa9ab\",\"ŊØŒ\"],[\"8fa9af\",\"ŦÞ\"],[\"8fa9c1\",\"æđðħıĳĸłŀŉŋøœßŧþ\"],[\"8faaa1\",\"ÁÀÄÂĂǍĀĄÅÃĆĈČÇĊĎÉÈËÊĚĖĒĘ\"],[\"8faaba\",\"ĜĞĢĠĤÍÌÏÎǏİĪĮĨĴĶĹĽĻŃŇŅÑÓÒÖÔǑŐŌÕŔŘŖŚŜŠŞŤŢÚÙÜÛŬǓŰŪŲŮŨǗǛǙǕŴÝŸŶŹŽŻ\"],[\"8faba1\",\"áàäâăǎāąåãćĉčçċďéèëêěėēęǵĝğ\"],[\"8fabbd\",\"ġĥíìïîǐ\"],[\"8fabc5\",\"īįĩĵķĺľļńňņñóòöôǒőōõŕřŗśŝšşťţúùüûŭǔűūųůũǘǜǚǖŵýÿŷźžż\"],[\"8fb0a1\",\"丂丄丅丌丒丟丣两丨丫丮丯丰丵乀乁乄乇乑乚乜乣乨乩乴乵乹乿亍亖亗亝亯亹仃仐仚仛仠仡仢仨仯仱仳仵份仾仿伀伂伃伈伋伌伒伕伖众伙伮伱你伳伵伷伹伻伾佀佂佈佉佋佌佒佔佖佘佟佣佪佬佮佱佷佸佹佺佽佾侁侂侄\"],[\"8fb1a1\",\"侅侉侊侌侎侐侒侓侔侗侙侚侞侟侲侷侹侻侼侽侾俀俁俅俆俈俉俋俌俍俏俒俜俠俢俰俲俼俽俿倀倁倄倇倊倌倎倐倓倗倘倛倜倝倞倢倧倮倰倲倳倵偀偁偂偅偆偊偌偎偑偒偓偗偙偟偠偢偣偦偧偪偭偰偱倻傁傃傄傆傊傎傏傐\"],[\"8fb2a1\",\"傒傓傔傖傛傜傞\",4,\"傪傯傰傹傺傽僀僃僄僇僌僎僐僓僔僘僜僝僟僢僤僦僨僩僯僱僶僺僾儃儆儇儈儋儌儍儎僲儐儗儙儛儜儝儞儣儧儨儬儭儯儱儳儴儵儸儹兂兊兏兓兕兗兘兟兤兦兾冃冄冋冎冘冝冡冣冭冸冺冼冾冿凂\"],[\"8fb3a1\",\"凈减凑凒凓凕凘凞凢凥凮凲凳凴凷刁刂刅划刓刕刖刘刢刨刱刲刵刼剅剉剕剗剘剚剜剟剠剡剦剮剷剸剹劀劂劅劊劌劓劕劖劗劘劚劜劤劥劦劧劯劰劶劷劸劺劻劽勀勄勆勈勌勏勑勔勖勛勜勡勥勨勩勪勬勰勱勴勶勷匀匃匊匋\"],[\"8fb4a1\",\"匌匑匓匘匛匜匞匟匥匧匨匩匫匬匭匰匲匵匼匽匾卂卌卋卙卛卡卣卥卬卭卲卹卾厃厇厈厎厓厔厙厝厡厤厪厫厯厲厴厵厷厸厺厽叀叅叏叒叓叕叚叝叞叠另叧叵吂吓吚吡吧吨吪启吱吴吵呃呄呇呍呏呞呢呤呦呧呩呫呭呮呴呿\"],[\"8fb5a1\",\"咁咃咅咈咉咍咑咕咖咜咟咡咦咧咩咪咭咮咱咷咹咺咻咿哆哊响哎哠哪哬哯哶哼哾哿唀唁唅唈唉唌唍唎唕唪唫唲唵唶唻唼唽啁啇啉啊啍啐啑啘啚啛啞啠啡啤啦啿喁喂喆喈喎喏喑喒喓喔喗喣喤喭喲喿嗁嗃嗆嗉嗋嗌嗎嗑嗒\"],[\"8fb6a1\",\"嗓嗗嗘嗛嗞嗢嗩嗶嗿嘅嘈嘊嘍\",5,\"嘙嘬嘰嘳嘵嘷嘹嘻嘼嘽嘿噀噁噃噄噆噉噋噍噏噔噞噠噡噢噣噦噩噭噯噱噲噵嚄嚅嚈嚋嚌嚕嚙嚚嚝嚞嚟嚦嚧嚨嚩嚫嚬嚭嚱嚳嚷嚾囅囉囊囋囏囐囌囍囙囜囝囟囡囤\",4,\"囱囫园\"],[\"8fb7a1\",\"囶囷圁圂圇圊圌圑圕圚圛圝圠圢圣圤圥圩圪圬圮圯圳圴圽圾圿坅坆坌坍坒坢坥坧坨坫坭\",4,\"坳坴坵坷坹坺坻坼坾垁垃垌垔垗垙垚垜垝垞垟垡垕垧垨垩垬垸垽埇埈埌埏埕埝埞埤埦埧埩埭埰埵埶埸埽埾埿堃堄堈堉埡\"],[\"8fb8a1\",\"堌堍堛堞堟堠堦堧堭堲堹堿塉塌塍塏塐塕塟塡塤塧塨塸塼塿墀墁墇墈墉墊墌墍墏墐墔墖墝墠墡墢墦墩墱墲壄墼壂壈壍壎壐壒壔壖壚壝壡壢壩壳夅夆夋夌夒夓夔虁夝夡夣夤夨夯夰夳夵夶夿奃奆奒奓奙奛奝奞奟奡奣奫奭\"],[\"8fb9a1\",\"奯奲奵奶她奻奼妋妌妎妒妕妗妟妤妧妭妮妯妰妳妷妺妼姁姃姄姈姊姍姒姝姞姟姣姤姧姮姯姱姲姴姷娀娄娌娍娎娒娓娞娣娤娧娨娪娭娰婄婅婇婈婌婐婕婞婣婥婧婭婷婺婻婾媋媐媓媖媙媜媞媟媠媢媧媬媱媲媳媵媸媺媻媿\"],[\"8fbaa1\",\"嫄嫆嫈嫏嫚嫜嫠嫥嫪嫮嫵嫶嫽嬀嬁嬈嬗嬴嬙嬛嬝嬡嬥嬭嬸孁孋孌孒孖孞孨孮孯孼孽孾孿宁宄宆宊宎宐宑宓宔宖宨宩宬宭宯宱宲宷宺宼寀寁寍寏寖\",4,\"寠寯寱寴寽尌尗尞尟尣尦尩尫尬尮尰尲尵尶屙屚屜屢屣屧屨屩\"],[\"8fbba1\",\"屭屰屴屵屺屻屼屽岇岈岊岏岒岝岟岠岢岣岦岪岲岴岵岺峉峋峒峝峗峮峱峲峴崁崆崍崒崫崣崤崦崧崱崴崹崽崿嵂嵃嵆嵈嵕嵑嵙嵊嵟嵠嵡嵢嵤嵪嵭嵰嵹嵺嵾嵿嶁嶃嶈嶊嶒嶓嶔嶕嶙嶛嶟嶠嶧嶫嶰嶴嶸嶹巃巇巋巐巎巘巙巠巤\"],[\"8fbca1\",\"巩巸巹帀帇帍帒帔帕帘帟帠帮帨帲帵帾幋幐幉幑幖幘幛幜幞幨幪\",4,\"幰庀庋庎庢庤庥庨庪庬庱庳庽庾庿廆廌廋廎廑廒廔廕廜廞廥廫异弆弇弈弎弙弜弝弡弢弣弤弨弫弬弮弰弴弶弻弽弿彀彄彅彇彍彐彔彘彛彠彣彤彧\"],[\"8fbda1\",\"彯彲彴彵彸彺彽彾徉徍徏徖徜徝徢徧徫徤徬徯徰徱徸忄忇忈忉忋忐\",4,\"忞忡忢忨忩忪忬忭忮忯忲忳忶忺忼怇怊怍怓怔怗怘怚怟怤怭怳怵恀恇恈恉恌恑恔恖恗恝恡恧恱恾恿悂悆悈悊悎悑悓悕悘悝悞悢悤悥您悰悱悷\"],[\"8fbea1\",\"悻悾惂惄惈惉惊惋惎惏惔惕惙惛惝惞惢惥惲惵惸惼惽愂愇愊愌愐\",4,\"愖愗愙愜愞愢愪愫愰愱愵愶愷愹慁慅慆慉慞慠慬慲慸慻慼慿憀憁憃憄憋憍憒憓憗憘憜憝憟憠憥憨憪憭憸憹憼懀懁懂懎懏懕懜懝懞懟懡懢懧懩懥\"],[\"8fbfa1\",\"懬懭懯戁戃戄戇戓戕戜戠戢戣戧戩戫戹戽扂扃扄扆扌扐扑扒扔扖扚扜扤扭扯扳扺扽抍抎抏抐抦抨抳抶抷抺抾抿拄拎拕拖拚拪拲拴拼拽挃挄挊挋挍挐挓挖挘挩挪挭挵挶挹挼捁捂捃捄捆捊捋捎捒捓捔捘捛捥捦捬捭捱捴捵\"],[\"8fc0a1\",\"捸捼捽捿掂掄掇掊掐掔掕掙掚掞掤掦掭掮掯掽揁揅揈揎揑揓揔揕揜揠揥揪揬揲揳揵揸揹搉搊搐搒搔搘搞搠搢搤搥搩搪搯搰搵搽搿摋摏摑摒摓摔摚摛摜摝摟摠摡摣摭摳摴摻摽撅撇撏撐撑撘撙撛撝撟撡撣撦撨撬撳撽撾撿\"],[\"8fc1a1\",\"擄擉擊擋擌擎擐擑擕擗擤擥擩擪擭擰擵擷擻擿攁攄攈攉攊攏攓攔攖攙攛攞攟攢攦攩攮攱攺攼攽敃敇敉敐敒敔敟敠敧敫敺敽斁斅斊斒斕斘斝斠斣斦斮斲斳斴斿旂旈旉旎旐旔旖旘旟旰旲旴旵旹旾旿昀昄昈昉昍昑昒昕昖昝\"],[\"8fc2a1\",\"昞昡昢昣昤昦昩昪昫昬昮昰昱昳昹昷晀晅晆晊晌晑晎晗晘晙晛晜晠晡曻晪晫晬晾晳晵晿晷晸晹晻暀晼暋暌暍暐暒暙暚暛暜暟暠暤暭暱暲暵暻暿曀曂曃曈曌曎曏曔曛曟曨曫曬曮曺朅朇朎朓朙朜朠朢朳朾杅杇杈杌杔杕杝\"],[\"8fc3a1\",\"杦杬杮杴杶杻极构枎枏枑枓枖枘枙枛枰枱枲枵枻枼枽柹柀柂柃柅柈柉柒柗柙柜柡柦柰柲柶柷桒栔栙栝栟栨栧栬栭栯栰栱栳栻栿桄桅桊桌桕桗桘桛桫桮\",4,\"桵桹桺桻桼梂梄梆梈梖梘梚梜梡梣梥梩梪梮梲梻棅棈棌棏\"],[\"8fc4a1\",\"棐棑棓棖棙棜棝棥棨棪棫棬棭棰棱棵棶棻棼棽椆椉椊椐椑椓椖椗椱椳椵椸椻楂楅楉楎楗楛楣楤楥楦楨楩楬楰楱楲楺楻楿榀榍榒榖榘榡榥榦榨榫榭榯榷榸榺榼槅槈槑槖槗槢槥槮槯槱槳槵槾樀樁樃樏樑樕樚樝樠樤樨樰樲\"],[\"8fc5a1\",\"樴樷樻樾樿橅橆橉橊橎橐橑橒橕橖橛橤橧橪橱橳橾檁檃檆檇檉檋檑檛檝檞檟檥檫檯檰檱檴檽檾檿櫆櫉櫈櫌櫐櫔櫕櫖櫜櫝櫤櫧櫬櫰櫱櫲櫼櫽欂欃欆欇欉欏欐欑欗欛欞欤欨欫欬欯欵欶欻欿歆歊歍歒歖歘歝歠歧歫歮歰歵歽\"],[\"8fc6a1\",\"歾殂殅殗殛殟殠殢殣殨殩殬殭殮殰殸殹殽殾毃毄毉毌毖毚毡毣毦毧毮毱毷毹毿氂氄氅氉氍氎氐氒氙氟氦氧氨氬氮氳氵氶氺氻氿汊汋汍汏汒汔汙汛汜汫汭汯汴汶汸汹汻沅沆沇沉沔沕沗沘沜沟沰沲沴泂泆泍泏泐泑泒泔泖\"],[\"8fc7a1\",\"泚泜泠泧泩泫泬泮泲泴洄洇洊洎洏洑洓洚洦洧洨汧洮洯洱洹洼洿浗浞浟浡浥浧浯浰浼涂涇涑涒涔涖涗涘涪涬涴涷涹涽涿淄淈淊淎淏淖淛淝淟淠淢淥淩淯淰淴淶淼渀渄渞渢渧渲渶渹渻渼湄湅湈湉湋湏湑湒湓湔湗湜湝湞\"],[\"8fc8a1\",\"湢湣湨湳湻湽溍溓溙溠溧溭溮溱溳溻溿滀滁滃滇滈滊滍滎滏滫滭滮滹滻滽漄漈漊漌漍漖漘漚漛漦漩漪漯漰漳漶漻漼漭潏潑潒潓潗潙潚潝潞潡潢潨潬潽潾澃澇澈澋澌澍澐澒澓澔澖澚澟澠澥澦澧澨澮澯澰澵澶澼濅濇濈濊\"],[\"8fc9a1\",\"濚濞濨濩濰濵濹濼濽瀀瀅瀆瀇瀍瀗瀠瀣瀯瀴瀷瀹瀼灃灄灈灉灊灋灔灕灝灞灎灤灥灬灮灵灶灾炁炅炆炔\",4,\"炛炤炫炰炱炴炷烊烑烓烔烕烖烘烜烤烺焃\",4,\"焋焌焏焞焠焫焭焯焰焱焸煁煅煆煇煊煋煐煒煗煚煜煞煠\"],[\"8fcaa1\",\"煨煹熀熅熇熌熒熚熛熠熢熯熰熲熳熺熿燀燁燄燋燌燓燖燙燚燜燸燾爀爇爈爉爓爗爚爝爟爤爫爯爴爸爹牁牂牃牅牎牏牐牓牕牖牚牜牞牠牣牨牫牮牯牱牷牸牻牼牿犄犉犍犎犓犛犨犭犮犱犴犾狁狇狉狌狕狖狘狟狥狳狴狺狻\"],[\"8fcba1\",\"狾猂猄猅猇猋猍猒猓猘猙猞猢猤猧猨猬猱猲猵猺猻猽獃獍獐獒獖獘獝獞獟獠獦獧獩獫獬獮獯獱獷獹獼玀玁玃玅玆玎玐玓玕玗玘玜玞玟玠玢玥玦玪玫玭玵玷玹玼玽玿珅珆珉珋珌珏珒珓珖珙珝珡珣珦珧珩珴珵珷珹珺珻珽\"],[\"8fcca1\",\"珿琀琁琄琇琊琑琚琛琤琦琨\",9,\"琹瑀瑃瑄瑆瑇瑋瑍瑑瑒瑗瑝瑢瑦瑧瑨瑫瑭瑮瑱瑲璀璁璅璆璇璉璏璐璑璒璘璙璚璜璟璠璡璣璦璨璩璪璫璮璯璱璲璵璹璻璿瓈瓉瓌瓐瓓瓘瓚瓛瓞瓟瓤瓨瓪瓫瓯瓴瓺瓻瓼瓿甆\"],[\"8fcda1\",\"甒甖甗甠甡甤甧甩甪甯甶甹甽甾甿畀畃畇畈畎畐畒畗畞畟畡畯畱畹\",5,\"疁疅疐疒疓疕疙疜疢疤疴疺疿痀痁痄痆痌痎痏痗痜痟痠痡痤痧痬痮痯痱痹瘀瘂瘃瘄瘇瘈瘊瘌瘏瘒瘓瘕瘖瘙瘛瘜瘝瘞瘣瘥瘦瘩瘭瘲瘳瘵瘸瘹\"],[\"8fcea1\",\"瘺瘼癊癀癁癃癄癅癉癋癕癙癟癤癥癭癮癯癱癴皁皅皌皍皕皛皜皝皟皠皢\",6,\"皪皭皽盁盅盉盋盌盎盔盙盠盦盨盬盰盱盶盹盼眀眆眊眎眒眔眕眗眙眚眜眢眨眭眮眯眴眵眶眹眽眾睂睅睆睊睍睎睏睒睖睗睜睞睟睠睢\"],[\"8fcfa1\",\"睤睧睪睬睰睲睳睴睺睽瞀瞄瞌瞍瞔瞕瞖瞚瞟瞢瞧瞪瞮瞯瞱瞵瞾矃矉矑矒矕矙矞矟矠矤矦矪矬矰矱矴矸矻砅砆砉砍砎砑砝砡砢砣砭砮砰砵砷硃硄硇硈硌硎硒硜硞硠硡硣硤硨硪确硺硾碊碏碔碘碡碝碞碟碤碨碬碭碰碱碲碳\"],[\"8fd0a1\",\"碻碽碿磇磈磉磌磎磒磓磕磖磤磛磟磠磡磦磪磲磳礀磶磷磺磻磿礆礌礐礚礜礞礟礠礥礧礩礭礱礴礵礻礽礿祄祅祆祊祋祏祑祔祘祛祜祧祩祫祲祹祻祼祾禋禌禑禓禔禕禖禘禛禜禡禨禩禫禯禱禴禸离秂秄秇秈秊秏秔秖秚秝秞\"],[\"8fd1a1\",\"秠秢秥秪秫秭秱秸秼稂稃稇稉稊稌稑稕稛稞稡稧稫稭稯稰稴稵稸稹稺穄穅穇穈穌穕穖穙穜穝穟穠穥穧穪穭穵穸穾窀窂窅窆窊窋窐窑窔窞窠窣窬窳窵窹窻窼竆竉竌竎竑竛竨竩竫竬竱竴竻竽竾笇笔笟笣笧笩笪笫笭笮笯笰\"],[\"8fd2a1\",\"笱笴笽笿筀筁筇筎筕筠筤筦筩筪筭筯筲筳筷箄箉箎箐箑箖箛箞箠箥箬箯箰箲箵箶箺箻箼箽篂篅篈篊篔篖篗篙篚篛篨篪篲篴篵篸篹篺篼篾簁簂簃簄簆簉簋簌簎簏簙簛簠簥簦簨簬簱簳簴簶簹簺籆籊籕籑籒籓籙\",5],[\"8fd3a1\",\"籡籣籧籩籭籮籰籲籹籼籽粆粇粏粔粞粠粦粰粶粷粺粻粼粿糄糇糈糉糍糏糓糔糕糗糙糚糝糦糩糫糵紃紇紈紉紏紑紒紓紖紝紞紣紦紪紭紱紼紽紾絀絁絇絈絍絑絓絗絙絚絜絝絥絧絪絰絸絺絻絿綁綂綃綅綆綈綋綌綍綑綖綗綝\"],[\"8fd4a1\",\"綞綦綧綪綳綶綷綹緂\",4,\"緌緍緎緗緙縀緢緥緦緪緫緭緱緵緶緹緺縈縐縑縕縗縜縝縠縧縨縬縭縯縳縶縿繄繅繇繎繐繒繘繟繡繢繥繫繮繯繳繸繾纁纆纇纊纍纑纕纘纚纝纞缼缻缽缾缿罃罄罇罏罒罓罛罜罝罡罣罤罥罦罭\"],[\"8fd5a1\",\"罱罽罾罿羀羋羍羏羐羑羖羗羜羡羢羦羪羭羴羼羿翀翃翈翎翏翛翟翣翥翨翬翮翯翲翺翽翾翿耇耈耊耍耎耏耑耓耔耖耝耞耟耠耤耦耬耮耰耴耵耷耹耺耼耾聀聄聠聤聦聭聱聵肁肈肎肜肞肦肧肫肸肹胈胍胏胒胔胕胗胘胠胭胮\"],[\"8fd6a1\",\"胰胲胳胶胹胺胾脃脋脖脗脘脜脞脠脤脧脬脰脵脺脼腅腇腊腌腒腗腠腡腧腨腩腭腯腷膁膐膄膅膆膋膎膖膘膛膞膢膮膲膴膻臋臃臅臊臎臏臕臗臛臝臞臡臤臫臬臰臱臲臵臶臸臹臽臿舀舃舏舓舔舙舚舝舡舢舨舲舴舺艃艄艅艆\"],[\"8fd7a1\",\"艋艎艏艑艖艜艠艣艧艭艴艻艽艿芀芁芃芄芇芉芊芎芑芔芖芘芚芛芠芡芣芤芧芨芩芪芮芰芲芴芷芺芼芾芿苆苐苕苚苠苢苤苨苪苭苯苶苷苽苾茀茁茇茈茊茋荔茛茝茞茟茡茢茬茭茮茰茳茷茺茼茽荂荃荄荇荍荎荑荕荖荗荰荸\"],[\"8fd8a1\",\"荽荿莀莂莄莆莍莒莔莕莘莙莛莜莝莦莧莩莬莾莿菀菇菉菏菐菑菔菝荓菨菪菶菸菹菼萁萆萊萏萑萕萙莭萯萹葅葇葈葊葍葏葑葒葖葘葙葚葜葠葤葥葧葪葰葳葴葶葸葼葽蒁蒅蒒蒓蒕蒞蒦蒨蒩蒪蒯蒱蒴蒺蒽蒾蓀蓂蓇蓈蓌蓏蓓\"],[\"8fd9a1\",\"蓜蓧蓪蓯蓰蓱蓲蓷蔲蓺蓻蓽蔂蔃蔇蔌蔎蔐蔜蔞蔢蔣蔤蔥蔧蔪蔫蔯蔳蔴蔶蔿蕆蕏\",4,\"蕖蕙蕜\",6,\"蕤蕫蕯蕹蕺蕻蕽蕿薁薅薆薉薋薌薏薓薘薝薟薠薢薥薧薴薶薷薸薼薽薾薿藂藇藊藋藎薭藘藚藟藠藦藨藭藳藶藼\"],[\"8fdaa1\",\"藿蘀蘄蘅蘍蘎蘐蘑蘒蘘蘙蘛蘞蘡蘧蘩蘶蘸蘺蘼蘽虀虂虆虒虓虖虗虘虙虝虠\",4,\"虩虬虯虵虶虷虺蚍蚑蚖蚘蚚蚜蚡蚦蚧蚨蚭蚱蚳蚴蚵蚷蚸蚹蚿蛀蛁蛃蛅蛑蛒蛕蛗蛚蛜蛠蛣蛥蛧蚈蛺蛼蛽蜄蜅蜇蜋蜎蜏蜐蜓蜔蜙蜞蜟蜡蜣\"],[\"8fdba1\",\"蜨蜮蜯蜱蜲蜹蜺蜼蜽蜾蝀蝃蝅蝍蝘蝝蝡蝤蝥蝯蝱蝲蝻螃\",6,\"螋螌螐螓螕螗螘螙螞螠螣螧螬螭螮螱螵螾螿蟁蟈蟉蟊蟎蟕蟖蟙蟚蟜蟟蟢蟣蟤蟪蟫蟭蟱蟳蟸蟺蟿蠁蠃蠆蠉蠊蠋蠐蠙蠒蠓蠔蠘蠚蠛蠜蠞蠟蠨蠭蠮蠰蠲蠵\"],[\"8fdca1\",\"蠺蠼衁衃衅衈衉衊衋衎衑衕衖衘衚衜衟衠衤衩衱衹衻袀袘袚袛袜袟袠袨袪袺袽袾裀裊\",4,\"裑裒裓裛裞裧裯裰裱裵裷褁褆褍褎褏褕褖褘褙褚褜褠褦褧褨褰褱褲褵褹褺褾襀襂襅襆襉襏襒襗襚襛襜襡襢襣襫襮襰襳襵襺\"],[\"8fdda1\",\"襻襼襽覉覍覐覔覕覛覜覟覠覥覰覴覵覶覷覼觔\",4,\"觥觩觫觭觱觳觶觹觽觿訄訅訇訏訑訒訔訕訞訠訢訤訦訫訬訯訵訷訽訾詀詃詅詇詉詍詎詓詖詗詘詜詝詡詥詧詵詶詷詹詺詻詾詿誀誃誆誋誏誐誒誖誗誙誟誧誩誮誯誳\"],[\"8fdea1\",\"誶誷誻誾諃諆諈諉諊諑諓諔諕諗諝諟諬諰諴諵諶諼諿謅謆謋謑謜謞謟謊謭謰謷謼譂\",4,\"譈譒譓譔譙譍譞譣譭譶譸譹譼譾讁讄讅讋讍讏讔讕讜讞讟谸谹谽谾豅豇豉豋豏豑豓豔豗豘豛豝豙豣豤豦豨豩豭豳豵豶豻豾貆\"],[\"8fdfa1\",\"貇貋貐貒貓貙貛貜貤貹貺賅賆賉賋賏賖賕賙賝賡賨賬賯賰賲賵賷賸賾賿贁贃贉贒贗贛赥赩赬赮赿趂趄趈趍趐趑趕趞趟趠趦趫趬趯趲趵趷趹趻跀跅跆跇跈跊跎跑跔跕跗跙跤跥跧跬跰趼跱跲跴跽踁踄踅踆踋踑踔踖踠踡踢\"],[\"8fe0a1\",\"踣踦踧踱踳踶踷踸踹踽蹀蹁蹋蹍蹎蹏蹔蹛蹜蹝蹞蹡蹢蹩蹬蹭蹯蹰蹱蹹蹺蹻躂躃躉躐躒躕躚躛躝躞躢躧躩躭躮躳躵躺躻軀軁軃軄軇軏軑軔軜軨軮軰軱軷軹軺軭輀輂輇輈輏輐輖輗輘輞輠輡輣輥輧輨輬輭輮輴輵輶輷輺轀轁\"],[\"8fe1a1\",\"轃轇轏轑\",4,\"轘轝轞轥辝辠辡辤辥辦辵辶辸达迀迁迆迊迋迍运迒迓迕迠迣迤迨迮迱迵迶迻迾适逄逈逌逘逛逨逩逯逪逬逭逳逴逷逿遃遄遌遛遝遢遦遧遬遰遴遹邅邈邋邌邎邐邕邗邘邙邛邠邡邢邥邰邲邳邴邶邽郌邾郃\"],[\"8fe2a1\",\"郄郅郇郈郕郗郘郙郜郝郟郥郒郶郫郯郰郴郾郿鄀鄄鄅鄆鄈鄍鄐鄔鄖鄗鄘鄚鄜鄞鄠鄥鄢鄣鄧鄩鄮鄯鄱鄴鄶鄷鄹鄺鄼鄽酃酇酈酏酓酗酙酚酛酡酤酧酭酴酹酺酻醁醃醅醆醊醎醑醓醔醕醘醞醡醦醨醬醭醮醰醱醲醳醶醻醼醽醿\"],[\"8fe3a1\",\"釂釃釅釓釔釗釙釚釞釤釥釩釪釬\",5,\"釷釹釻釽鈀鈁鈄鈅鈆鈇鈉鈊鈌鈐鈒鈓鈖鈘鈜鈝鈣鈤鈥鈦鈨鈮鈯鈰鈳鈵鈶鈸鈹鈺鈼鈾鉀鉂鉃鉆鉇鉊鉍鉎鉏鉑鉘鉙鉜鉝鉠鉡鉥鉧鉨鉩鉮鉯鉰鉵\",4,\"鉻鉼鉽鉿銈銉銊銍銎銒銗\"],[\"8fe4a1\",\"銙銟銠銤銥銧銨銫銯銲銶銸銺銻銼銽銿\",4,\"鋅鋆鋇鋈鋋鋌鋍鋎鋐鋓鋕鋗鋘鋙鋜鋝鋟鋠鋡鋣鋥鋧鋨鋬鋮鋰鋹鋻鋿錀錂錈錍錑錔錕錜錝錞錟錡錤錥錧錩錪錳錴錶錷鍇鍈鍉鍐鍑鍒鍕鍗鍘鍚鍞鍤鍥鍧鍩鍪鍭鍯鍰鍱鍳鍴鍶\"],[\"8fe5a1\",\"鍺鍽鍿鎀鎁鎂鎈鎊鎋鎍鎏鎒鎕鎘鎛鎞鎡鎣鎤鎦鎨鎫鎴鎵鎶鎺鎩鏁鏄鏅鏆鏇鏉\",4,\"鏓鏙鏜鏞鏟鏢鏦鏧鏹鏷鏸鏺鏻鏽鐁鐂鐄鐈鐉鐍鐎鐏鐕鐖鐗鐟鐮鐯鐱鐲鐳鐴鐻鐿鐽鑃鑅鑈鑊鑌鑕鑙鑜鑟鑡鑣鑨鑫鑭鑮鑯鑱鑲钄钃镸镹\"],[\"8fe6a1\",\"镾閄閈閌閍閎閝閞閟閡閦閩閫閬閴閶閺閽閿闆闈闉闋闐闑闒闓闙闚闝闞闟闠闤闦阝阞阢阤阥阦阬阱阳阷阸阹阺阼阽陁陒陔陖陗陘陡陮陴陻陼陾陿隁隂隃隄隉隑隖隚隝隟隤隥隦隩隮隯隳隺雊雒嶲雘雚雝雞雟雩雯雱雺霂\"],[\"8fe7a1\",\"霃霅霉霚霛霝霡霢霣霨霱霳靁靃靊靎靏靕靗靘靚靛靣靧靪靮靳靶靷靸靻靽靿鞀鞉鞕鞖鞗鞙鞚鞞鞟鞢鞬鞮鞱鞲鞵鞶鞸鞹鞺鞼鞾鞿韁韄韅韇韉韊韌韍韎韐韑韔韗韘韙韝韞韠韛韡韤韯韱韴韷韸韺頇頊頙頍頎頔頖頜頞頠頣頦\"],[\"8fe8a1\",\"頫頮頯頰頲頳頵頥頾顄顇顊顑顒顓顖顗顙顚顢顣顥顦顪顬颫颭颮颰颴颷颸颺颻颿飂飅飈飌飡飣飥飦飧飪飳飶餂餇餈餑餕餖餗餚餛餜餟餢餦餧餫餱\",4,\"餹餺餻餼饀饁饆饇饈饍饎饔饘饙饛饜饞饟饠馛馝馟馦馰馱馲馵\"],[\"8fe9a1\",\"馹馺馽馿駃駉駓駔駙駚駜駞駧駪駫駬駰駴駵駹駽駾騂騃騄騋騌騐騑騖騞騠騢騣騤騧騭騮騳騵騶騸驇驁驄驊驋驌驎驑驔驖驝骪骬骮骯骲骴骵骶骹骻骾骿髁髃髆髈髎髐髒髕髖髗髛髜髠髤髥髧髩髬髲髳髵髹髺髽髿\",4],[\"8feaa1\",\"鬄鬅鬈鬉鬋鬌鬍鬎鬐鬒鬖鬙鬛鬜鬠鬦鬫鬭鬳鬴鬵鬷鬹鬺鬽魈魋魌魕魖魗魛魞魡魣魥魦魨魪\",4,\"魳魵魷魸魹魿鮀鮄鮅鮆鮇鮉鮊鮋鮍鮏鮐鮔鮚鮝鮞鮦鮧鮩鮬鮰鮱鮲鮷鮸鮻鮼鮾鮿鯁鯇鯈鯎鯐鯗鯘鯝鯟鯥鯧鯪鯫鯯鯳鯷鯸\"],[\"8feba1\",\"鯹鯺鯽鯿鰀鰂鰋鰏鰑鰖鰘鰙鰚鰜鰞鰢鰣鰦\",4,\"鰱鰵鰶鰷鰽鱁鱃鱄鱅鱉鱊鱎鱏鱐鱓鱔鱖鱘鱛鱝鱞鱟鱣鱩鱪鱜鱫鱨鱮鱰鱲鱵鱷鱻鳦鳲鳷鳹鴋鴂鴑鴗鴘鴜鴝鴞鴯鴰鴲鴳鴴鴺鴼鵅鴽鵂鵃鵇鵊鵓鵔鵟鵣鵢鵥鵩鵪鵫鵰鵶鵷鵻\"],[\"8feca1\",\"鵼鵾鶃鶄鶆鶊鶍鶎鶒鶓鶕鶖鶗鶘鶡鶪鶬鶮鶱鶵鶹鶼鶿鷃鷇鷉鷊鷔鷕鷖鷗鷚鷞鷟鷠鷥鷧鷩鷫鷮鷰鷳鷴鷾鸊鸂鸇鸎鸐鸑鸒鸕鸖鸙鸜鸝鹺鹻鹼麀麂麃麄麅麇麎麏麖麘麛麞麤麨麬麮麯麰麳麴麵黆黈黋黕黟黤黧黬黭黮黰黱黲黵\"],[\"8feda1\",\"黸黿鼂鼃鼉鼏鼐鼑鼒鼔鼖鼗鼙鼚鼛鼟鼢鼦鼪鼫鼯鼱鼲鼴鼷鼹鼺鼼鼽鼿齁齃\",4,\"齓齕齖齗齘齚齝齞齨齩齭\",4,\"齳齵齺齽龏龐龑龒龔龖龗龞龡龢龣龥\"]]\n\n/***/ }),\n/* 182 */\n/***/ (function(module, exports) {\n\nmodule.exports = {\"uChars\":[128,165,169,178,184,216,226,235,238,244,248,251,253,258,276,284,300,325,329,334,364,463,465,467,469,471,473,475,477,506,594,610,712,716,730,930,938,962,970,1026,1104,1106,8209,8215,8218,8222,8231,8241,8244,8246,8252,8365,8452,8454,8458,8471,8482,8556,8570,8596,8602,8713,8720,8722,8726,8731,8737,8740,8742,8748,8751,8760,8766,8777,8781,8787,8802,8808,8816,8854,8858,8870,8896,8979,9322,9372,9548,9588,9616,9622,9634,9652,9662,9672,9676,9680,9702,9735,9738,9793,9795,11906,11909,11913,11917,11928,11944,11947,11951,11956,11960,11964,11979,12284,12292,12312,12319,12330,12351,12436,12447,12535,12543,12586,12842,12850,12964,13200,13215,13218,13253,13263,13267,13270,13384,13428,13727,13839,13851,14617,14703,14801,14816,14964,15183,15471,15585,16471,16736,17208,17325,17330,17374,17623,17997,18018,18212,18218,18301,18318,18760,18811,18814,18820,18823,18844,18848,18872,19576,19620,19738,19887,40870,59244,59336,59367,59413,59417,59423,59431,59437,59443,59452,59460,59478,59493,63789,63866,63894,63976,63986,64016,64018,64021,64025,64034,64037,64042,65074,65093,65107,65112,65127,65132,65375,65510,65536],\"gbChars\":[0,36,38,45,50,81,89,95,96,100,103,104,105,109,126,133,148,172,175,179,208,306,307,308,309,310,311,312,313,341,428,443,544,545,558,741,742,749,750,805,819,820,7922,7924,7925,7927,7934,7943,7944,7945,7950,8062,8148,8149,8152,8164,8174,8236,8240,8262,8264,8374,8380,8381,8384,8388,8390,8392,8393,8394,8396,8401,8406,8416,8419,8424,8437,8439,8445,8482,8485,8496,8521,8603,8936,8946,9046,9050,9063,9066,9076,9092,9100,9108,9111,9113,9131,9162,9164,9218,9219,11329,11331,11334,11336,11346,11361,11363,11366,11370,11372,11375,11389,11682,11686,11687,11692,11694,11714,11716,11723,11725,11730,11736,11982,11989,12102,12336,12348,12350,12384,12393,12395,12397,12510,12553,12851,12962,12973,13738,13823,13919,13933,14080,14298,14585,14698,15583,15847,16318,16434,16438,16481,16729,17102,17122,17315,17320,17402,17418,17859,17909,17911,17915,17916,17936,17939,17961,18664,18703,18814,18962,19043,33469,33470,33471,33484,33485,33490,33497,33501,33505,33513,33520,33536,33550,37845,37921,37948,38029,38038,38064,38065,38066,38069,38075,38076,38078,39108,39109,39113,39114,39115,39116,39265,39394,189000]}\n\n/***/ }),\n/* 183 */\n/***/ (function(module, exports) {\n\nmodule.exports = [[\"0\",\"\\u0000\",127],[\"8141\",\"갂갃갅갆갋\",4,\"갘갞갟갡갢갣갥\",6,\"갮갲갳갴\"],[\"8161\",\"갵갶갷갺갻갽갾갿걁\",9,\"걌걎\",5,\"걕\"],[\"8181\",\"걖걗걙걚걛걝\",18,\"걲걳걵걶걹걻\",4,\"겂겇겈겍겎겏겑겒겓겕\",6,\"겞겢\",5,\"겫겭겮겱\",6,\"겺겾겿곀곂곃곅곆곇곉곊곋곍\",7,\"곖곘\",7,\"곢곣곥곦곩곫곭곮곲곴곷\",4,\"곾곿괁괂괃괅괇\",4,\"괎괐괒괓\"],[\"8241\",\"괔괕괖괗괙괚괛괝괞괟괡\",7,\"괪괫괮\",5],[\"8261\",\"괶괷괹괺괻괽\",6,\"굆굈굊\",5,\"굑굒굓굕굖굗\"],[\"8281\",\"굙\",7,\"굢굤\",7,\"굮굯굱굲굷굸굹굺굾궀궃\",4,\"궊궋궍궎궏궑\",10,\"궞\",5,\"궥\",17,\"궸\",7,\"귂귃귅귆귇귉\",6,\"귒귔\",7,\"귝귞귟귡귢귣귥\",18],[\"8341\",\"귺귻귽귾긂\",5,\"긊긌긎\",5,\"긕\",7],[\"8361\",\"긝\",18,\"긲긳긵긶긹긻긼\"],[\"8381\",\"긽긾긿깂깄깇깈깉깋깏깑깒깓깕깗\",4,\"깞깢깣깤깦깧깪깫깭깮깯깱\",6,\"깺깾\",5,\"꺆\",5,\"꺍\",46,\"꺿껁껂껃껅\",6,\"껎껒\",5,\"껚껛껝\",8],[\"8441\",\"껦껧껩껪껬껮\",5,\"껵껶껷껹껺껻껽\",8],[\"8461\",\"꼆꼉꼊꼋꼌꼎꼏꼑\",18],[\"8481\",\"꼤\",7,\"꼮꼯꼱꼳꼵\",6,\"꼾꽀꽄꽅꽆꽇꽊\",5,\"꽑\",10,\"꽞\",5,\"꽦\",18,\"꽺\",5,\"꾁꾂꾃꾅꾆꾇꾉\",6,\"꾒꾓꾔꾖\",5,\"꾝\",26,\"꾺꾻꾽꾾\"],[\"8541\",\"꾿꿁\",5,\"꿊꿌꿏\",4,\"꿕\",6,\"꿝\",4],[\"8561\",\"꿢\",5,\"꿪\",5,\"꿲꿳꿵꿶꿷꿹\",6,\"뀂뀃\"],[\"8581\",\"뀅\",6,\"뀍뀎뀏뀑뀒뀓뀕\",6,\"뀞\",9,\"뀩\",26,\"끆끇끉끋끍끏끐끑끒끖끘끚끛끜끞\",29,\"끾끿낁낂낃낅\",6,\"낎낐낒\",5,\"낛낝낞낣낤\"],[\"8641\",\"낥낦낧낪낰낲낶낷낹낺낻낽\",6,\"냆냊\",5,\"냒\"],[\"8661\",\"냓냕냖냗냙\",6,\"냡냢냣냤냦\",10],[\"8681\",\"냱\",22,\"넊넍넎넏넑넔넕넖넗넚넞\",4,\"넦넧넩넪넫넭\",6,\"넶넺\",5,\"녂녃녅녆녇녉\",6,\"녒녓녖녗녙녚녛녝녞녟녡\",22,\"녺녻녽녾녿놁놃\",4,\"놊놌놎놏놐놑놕놖놗놙놚놛놝\"],[\"8741\",\"놞\",9,\"놩\",15],[\"8761\",\"놹\",18,\"뇍뇎뇏뇑뇒뇓뇕\"],[\"8781\",\"뇖\",5,\"뇞뇠\",7,\"뇪뇫뇭뇮뇯뇱\",7,\"뇺뇼뇾\",5,\"눆눇눉눊눍\",6,\"눖눘눚\",5,\"눡\",18,\"눵\",6,\"눽\",26,\"뉙뉚뉛뉝뉞뉟뉡\",6,\"뉪\",4],[\"8841\",\"뉯\",4,\"뉶\",5,\"뉽\",6,\"늆늇늈늊\",4],[\"8861\",\"늏늒늓늕늖늗늛\",4,\"늢늤늧늨늩늫늭늮늯늱늲늳늵늶늷\"],[\"8881\",\"늸\",15,\"닊닋닍닎닏닑닓\",4,\"닚닜닞닟닠닡닣닧닩닪닰닱닲닶닼닽닾댂댃댅댆댇댉\",6,\"댒댖\",5,\"댝\",54,\"덗덙덚덝덠덡덢덣\"],[\"8941\",\"덦덨덪덬덭덯덲덳덵덶덷덹\",6,\"뎂뎆\",5,\"뎍\"],[\"8961\",\"뎎뎏뎑뎒뎓뎕\",10,\"뎢\",5,\"뎩뎪뎫뎭\"],[\"8981\",\"뎮\",21,\"돆돇돉돊돍돏돑돒돓돖돘돚돜돞돟돡돢돣돥돦돧돩\",18,\"돽\",18,\"됑\",6,\"됙됚됛됝됞됟됡\",6,\"됪됬\",7,\"됵\",15],[\"8a41\",\"둅\",10,\"둒둓둕둖둗둙\",6,\"둢둤둦\"],[\"8a61\",\"둧\",4,\"둭\",18,\"뒁뒂\"],[\"8a81\",\"뒃\",4,\"뒉\",19,\"뒞\",5,\"뒥뒦뒧뒩뒪뒫뒭\",7,\"뒶뒸뒺\",5,\"듁듂듃듅듆듇듉\",6,\"듑듒듓듔듖\",5,\"듞듟듡듢듥듧\",4,\"듮듰듲\",5,\"듹\",26,\"딖딗딙딚딝\"],[\"8b41\",\"딞\",5,\"딦딫\",4,\"딲딳딵딶딷딹\",6,\"땂땆\"],[\"8b61\",\"땇땈땉땊땎땏땑땒땓땕\",6,\"땞땢\",8],[\"8b81\",\"땫\",52,\"떢떣떥떦떧떩떬떭떮떯떲떶\",4,\"떾떿뗁뗂뗃뗅\",6,\"뗎뗒\",5,\"뗙\",18,\"뗭\",18],[\"8c41\",\"똀\",15,\"똒똓똕똖똗똙\",4],[\"8c61\",\"똞\",6,\"똦\",5,\"똭\",6,\"똵\",5],[\"8c81\",\"똻\",12,\"뙉\",26,\"뙥뙦뙧뙩\",50,\"뚞뚟뚡뚢뚣뚥\",5,\"뚭뚮뚯뚰뚲\",16],[\"8d41\",\"뛃\",16,\"뛕\",8],[\"8d61\",\"뛞\",17,\"뛱뛲뛳뛵뛶뛷뛹뛺\"],[\"8d81\",\"뛻\",4,\"뜂뜃뜄뜆\",33,\"뜪뜫뜭뜮뜱\",6,\"뜺뜼\",7,\"띅띆띇띉띊띋띍\",6,\"띖\",9,\"띡띢띣띥띦띧띩\",6,\"띲띴띶\",5,\"띾띿랁랂랃랅\",6,\"랎랓랔랕랚랛랝랞\"],[\"8e41\",\"랟랡\",6,\"랪랮\",5,\"랶랷랹\",8],[\"8e61\",\"럂\",4,\"럈럊\",19],[\"8e81\",\"럞\",13,\"럮럯럱럲럳럵\",6,\"럾렂\",4,\"렊렋렍렎렏렑\",6,\"렚렜렞\",5,\"렦렧렩렪렫렭\",6,\"렶렺\",5,\"롁롂롃롅\",11,\"롒롔\",7,\"롞롟롡롢롣롥\",6,\"롮롰롲\",5,\"롹롺롻롽\",7],[\"8f41\",\"뢅\",7,\"뢎\",17],[\"8f61\",\"뢠\",7,\"뢩\",6,\"뢱뢲뢳뢵뢶뢷뢹\",4],[\"8f81\",\"뢾뢿룂룄룆\",5,\"룍룎룏룑룒룓룕\",7,\"룞룠룢\",5,\"룪룫룭룮룯룱\",6,\"룺룼룾\",5,\"뤅\",18,\"뤙\",6,\"뤡\",26,\"뤾뤿륁륂륃륅\",6,\"륍륎륐륒\",5],[\"9041\",\"륚륛륝륞륟륡\",6,\"륪륬륮\",5,\"륶륷륹륺륻륽\"],[\"9061\",\"륾\",5,\"릆릈릋릌릏\",15],[\"9081\",\"릟\",12,\"릮릯릱릲릳릵\",6,\"릾맀맂\",5,\"맊맋맍맓\",4,\"맚맜맟맠맢맦맧맩맪맫맭\",6,\"맶맻\",4,\"먂\",5,\"먉\",11,\"먖\",33,\"먺먻먽먾먿멁멃멄멅멆\"],[\"9141\",\"멇멊멌멏멐멑멒멖멗멙멚멛멝\",6,\"멦멪\",5],[\"9161\",\"멲멳멵멶멷멹\",9,\"몆몈몉몊몋몍\",5],[\"9181\",\"몓\",20,\"몪몭몮몯몱몳\",4,\"몺몼몾\",5,\"뫅뫆뫇뫉\",14,\"뫚\",33,\"뫽뫾뫿묁묂묃묅\",7,\"묎묐묒\",5,\"묙묚묛묝묞묟묡\",6],[\"9241\",\"묨묪묬\",7,\"묷묹묺묿\",4,\"뭆뭈뭊뭋뭌뭎뭑뭒\"],[\"9261\",\"뭓뭕뭖뭗뭙\",7,\"뭢뭤\",7,\"뭭\",4],[\"9281\",\"뭲\",21,\"뮉뮊뮋뮍뮎뮏뮑\",18,\"뮥뮦뮧뮩뮪뮫뮭\",6,\"뮵뮶뮸\",7,\"믁믂믃믅믆믇믉\",6,\"믑믒믔\",35,\"믺믻믽믾밁\"],[\"9341\",\"밃\",4,\"밊밎밐밒밓밙밚밠밡밢밣밦밨밪밫밬밮밯밲밳밵\"],[\"9361\",\"밶밷밹\",6,\"뱂뱆뱇뱈뱊뱋뱎뱏뱑\",8],[\"9381\",\"뱚뱛뱜뱞\",37,\"벆벇벉벊벍벏\",4,\"벖벘벛\",4,\"벢벣벥벦벩\",6,\"벲벶\",5,\"벾벿볁볂볃볅\",7,\"볎볒볓볔볖볗볙볚볛볝\",22,\"볷볹볺볻볽\"],[\"9441\",\"볾\",5,\"봆봈봊\",5,\"봑봒봓봕\",8],[\"9461\",\"봞\",5,\"봥\",6,\"봭\",12],[\"9481\",\"봺\",5,\"뵁\",6,\"뵊뵋뵍뵎뵏뵑\",6,\"뵚\",9,\"뵥뵦뵧뵩\",22,\"붂붃붅붆붋\",4,\"붒붔붖붗붘붛붝\",6,\"붥\",10,\"붱\",6,\"붹\",24],[\"9541\",\"뷒뷓뷖뷗뷙뷚뷛뷝\",11,\"뷪\",5,\"뷱\"],[\"9561\",\"뷲뷳뷵뷶뷷뷹\",6,\"븁븂븄븆\",5,\"븎븏븑븒븓\"],[\"9581\",\"븕\",6,\"븞븠\",35,\"빆빇빉빊빋빍빏\",4,\"빖빘빜빝빞빟빢빣빥빦빧빩빫\",4,\"빲빶\",4,\"빾빿뺁뺂뺃뺅\",6,\"뺎뺒\",5,\"뺚\",13,\"뺩\",14],[\"9641\",\"뺸\",23,\"뻒뻓\"],[\"9661\",\"뻕뻖뻙\",6,\"뻡뻢뻦\",5,\"뻭\",8],[\"9681\",\"뻶\",10,\"뼂\",5,\"뼊\",13,\"뼚뼞\",33,\"뽂뽃뽅뽆뽇뽉\",6,\"뽒뽓뽔뽖\",44],[\"9741\",\"뾃\",16,\"뾕\",8],[\"9761\",\"뾞\",17,\"뾱\",7],[\"9781\",\"뾹\",11,\"뿆\",5,\"뿎뿏뿑뿒뿓뿕\",6,\"뿝뿞뿠뿢\",89,\"쀽쀾쀿\"],[\"9841\",\"쁀\",16,\"쁒\",5,\"쁙쁚쁛\"],[\"9861\",\"쁝쁞쁟쁡\",6,\"쁪\",15],[\"9881\",\"쁺\",21,\"삒삓삕삖삗삙\",6,\"삢삤삦\",5,\"삮삱삲삷\",4,\"삾샂샃샄샆샇샊샋샍샎샏샑\",6,\"샚샞\",5,\"샦샧샩샪샫샭\",6,\"샶샸샺\",5,\"섁섂섃섅섆섇섉\",6,\"섑섒섓섔섖\",5,\"섡섢섥섨섩섪섫섮\"],[\"9941\",\"섲섳섴섵섷섺섻섽섾섿셁\",6,\"셊셎\",5,\"셖셗\"],[\"9961\",\"셙셚셛셝\",6,\"셦셪\",5,\"셱셲셳셵셶셷셹셺셻\"],[\"9981\",\"셼\",8,\"솆\",5,\"솏솑솒솓솕솗\",4,\"솞솠솢솣솤솦솧솪솫솭솮솯솱\",11,\"솾\",5,\"쇅쇆쇇쇉쇊쇋쇍\",6,\"쇕쇖쇙\",6,\"쇡쇢쇣쇥쇦쇧쇩\",6,\"쇲쇴\",7,\"쇾쇿숁숂숃숅\",6,\"숎숐숒\",5,\"숚숛숝숞숡숢숣\"],[\"9a41\",\"숤숥숦숧숪숬숮숰숳숵\",16],[\"9a61\",\"쉆쉇쉉\",6,\"쉒쉓쉕쉖쉗쉙\",6,\"쉡쉢쉣쉤쉦\"],[\"9a81\",\"쉧\",4,\"쉮쉯쉱쉲쉳쉵\",6,\"쉾슀슂\",5,\"슊\",5,\"슑\",6,\"슙슚슜슞\",5,\"슦슧슩슪슫슮\",5,\"슶슸슺\",33,\"싞싟싡싢싥\",5,\"싮싰싲싳싴싵싷싺싽싾싿쌁\",6,\"쌊쌋쌎쌏\"],[\"9b41\",\"쌐쌑쌒쌖쌗쌙쌚쌛쌝\",6,\"쌦쌧쌪\",8],[\"9b61\",\"쌳\",17,\"썆\",7],[\"9b81\",\"썎\",25,\"썪썫썭썮썯썱썳\",4,\"썺썻썾\",5,\"쎅쎆쎇쎉쎊쎋쎍\",50,\"쏁\",22,\"쏚\"],[\"9c41\",\"쏛쏝쏞쏡쏣\",4,\"쏪쏫쏬쏮\",5,\"쏶쏷쏹\",5],[\"9c61\",\"쏿\",8,\"쐉\",6,\"쐑\",9],[\"9c81\",\"쐛\",8,\"쐥\",6,\"쐭쐮쐯쐱쐲쐳쐵\",6,\"쐾\",9,\"쑉\",26,\"쑦쑧쑩쑪쑫쑭\",6,\"쑶쑷쑸쑺\",5,\"쒁\",18,\"쒕\",6,\"쒝\",12],[\"9d41\",\"쒪\",13,\"쒹쒺쒻쒽\",8],[\"9d61\",\"쓆\",25],[\"9d81\",\"쓠\",8,\"쓪\",5,\"쓲쓳쓵쓶쓷쓹쓻쓼쓽쓾씂\",9,\"씍씎씏씑씒씓씕\",6,\"씝\",10,\"씪씫씭씮씯씱\",6,\"씺씼씾\",5,\"앆앇앋앏앐앑앒앖앚앛앜앟앢앣앥앦앧앩\",6,\"앲앶\",5,\"앾앿얁얂얃얅얆얈얉얊얋얎얐얒얓얔\"],[\"9e41\",\"얖얙얚얛얝얞얟얡\",7,\"얪\",9,\"얶\"],[\"9e61\",\"얷얺얿\",4,\"엋엍엏엒엓엕엖엗엙\",6,\"엢엤엦엧\"],[\"9e81\",\"엨엩엪엫엯엱엲엳엵엸엹엺엻옂옃옄옉옊옋옍옎옏옑\",6,\"옚옝\",6,\"옦옧옩옪옫옯옱옲옶옸옺옼옽옾옿왂왃왅왆왇왉\",6,\"왒왖\",5,\"왞왟왡\",10,\"왭왮왰왲\",5,\"왺왻왽왾왿욁\",6,\"욊욌욎\",5,\"욖욗욙욚욛욝\",6,\"욦\"],[\"9f41\",\"욨욪\",5,\"욲욳욵욶욷욻\",4,\"웂웄웆\",5,\"웎\"],[\"9f61\",\"웏웑웒웓웕\",6,\"웞웟웢\",5,\"웪웫웭웮웯웱웲\"],[\"9f81\",\"웳\",4,\"웺웻웼웾\",5,\"윆윇윉윊윋윍\",6,\"윖윘윚\",5,\"윢윣윥윦윧윩\",6,\"윲윴윶윸윹윺윻윾윿읁읂읃읅\",4,\"읋읎읐읙읚읛읝읞읟읡\",6,\"읩읪읬\",7,\"읶읷읹읺읻읿잀잁잂잆잋잌잍잏잒잓잕잙잛\",4,\"잢잧\",4,\"잮잯잱잲잳잵잶잷\"],[\"a041\",\"잸잹잺잻잾쟂\",5,\"쟊쟋쟍쟏쟑\",6,\"쟙쟚쟛쟜\"],[\"a061\",\"쟞\",5,\"쟥쟦쟧쟩쟪쟫쟭\",13],[\"a081\",\"쟻\",4,\"젂젃젅젆젇젉젋\",4,\"젒젔젗\",4,\"젞젟젡젢젣젥\",6,\"젮젰젲\",5,\"젹젺젻젽젾젿졁\",6,\"졊졋졎\",5,\"졕\",26,\"졲졳졵졶졷졹졻\",4,\"좂좄좈좉좊좎\",5,\"좕\",7,\"좞좠좢좣좤\"],[\"a141\",\"좥좦좧좩\",18,\"좾좿죀죁\"],[\"a161\",\"죂죃죅죆죇죉죊죋죍\",6,\"죖죘죚\",5,\"죢죣죥\"],[\"a181\",\"죦\",14,\"죶\",5,\"죾죿줁줂줃줇\",4,\"줎　、。·‥…¨〃­―∥＼∼‘’“”〔〕〈\",9,\"±×÷≠≤≥∞∴°′″℃Å￠￡￥♂♀∠⊥⌒∂∇≡≒§※☆★○●◎◇◆□■△▲▽▼→←↑↓↔〓≪≫√∽∝∵∫∬∈∋⊆⊇⊂⊃∪∩∧∨￢\"],[\"a241\",\"줐줒\",5,\"줙\",18],[\"a261\",\"줭\",6,\"줵\",18],[\"a281\",\"쥈\",7,\"쥒쥓쥕쥖쥗쥙\",6,\"쥢쥤\",7,\"쥭쥮쥯⇒⇔∀∃´～ˇ˘˝˚˙¸˛¡¿ː∮∑∏¤℉‰◁◀▷▶♤♠♡♥♧♣⊙◈▣◐◑▒▤▥▨▧▦▩♨☏☎☜☞¶†‡↕↗↙↖↘♭♩♪♬㉿㈜№㏇™㏂㏘℡€®\"],[\"a341\",\"쥱쥲쥳쥵\",6,\"쥽\",10,\"즊즋즍즎즏\"],[\"a361\",\"즑\",6,\"즚즜즞\",16],[\"a381\",\"즯\",16,\"짂짃짅짆짉짋\",4,\"짒짔짗짘짛！\",58,\"￦］\",32,\"￣\"],[\"a441\",\"짞짟짡짣짥짦짨짩짪짫짮짲\",5,\"짺짻짽짾짿쨁쨂쨃쨄\"],[\"a461\",\"쨅쨆쨇쨊쨎\",5,\"쨕쨖쨗쨙\",12],[\"a481\",\"쨦쨧쨨쨪\",28,\"ㄱ\",93],[\"a541\",\"쩇\",4,\"쩎쩏쩑쩒쩓쩕\",6,\"쩞쩢\",5,\"쩩쩪\"],[\"a561\",\"쩫\",17,\"쩾\",5,\"쪅쪆\"],[\"a581\",\"쪇\",16,\"쪙\",14,\"ⅰ\",9],[\"a5b0\",\"Ⅰ\",9],[\"a5c1\",\"Α\",16,\"Σ\",6],[\"a5e1\",\"α\",16,\"σ\",6],[\"a641\",\"쪨\",19,\"쪾쪿쫁쫂쫃쫅\"],[\"a661\",\"쫆\",5,\"쫎쫐쫒쫔쫕쫖쫗쫚\",5,\"쫡\",6],[\"a681\",\"쫨쫩쫪쫫쫭\",6,\"쫵\",18,\"쬉쬊─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂┒┑┚┙┖┕┎┍┞┟┡┢┦┧┩┪┭┮┱┲┵┶┹┺┽┾╀╁╃\",7],[\"a741\",\"쬋\",4,\"쬑쬒쬓쬕쬖쬗쬙\",6,\"쬢\",7],[\"a761\",\"쬪\",22,\"쭂쭃쭄\"],[\"a781\",\"쭅쭆쭇쭊쭋쭍쭎쭏쭑\",6,\"쭚쭛쭜쭞\",5,\"쭥\",7,\"㎕㎖㎗ℓ㎘㏄㎣㎤㎥㎦㎙\",9,\"㏊㎍㎎㎏㏏㎈㎉㏈㎧㎨㎰\",9,\"㎀\",4,\"㎺\",5,\"㎐\",4,\"Ω㏀㏁㎊㎋㎌㏖㏅㎭㎮㎯㏛㎩㎪㎫㎬㏝㏐㏓㏃㏉㏜㏆\"],[\"a841\",\"쭭\",10,\"쭺\",14],[\"a861\",\"쮉\",18,\"쮝\",6],[\"a881\",\"쮤\",19,\"쮹\",11,\"ÆÐªĦ\"],[\"a8a6\",\"Ĳ\"],[\"a8a8\",\"ĿŁØŒºÞŦŊ\"],[\"a8b1\",\"㉠\",27,\"ⓐ\",25,\"①\",14,\"½⅓⅔¼¾⅛⅜⅝⅞\"],[\"a941\",\"쯅\",14,\"쯕\",10],[\"a961\",\"쯠쯡쯢쯣쯥쯦쯨쯪\",18],[\"a981\",\"쯽\",14,\"찎찏찑찒찓찕\",6,\"찞찟찠찣찤æđðħıĳĸŀłøœßþŧŋŉ㈀\",27,\"⒜\",25,\"⑴\",14,\"¹²³⁴ⁿ₁₂₃₄\"],[\"aa41\",\"찥찦찪찫찭찯찱\",6,\"찺찿\",4,\"챆챇챉챊챋챍챎\"],[\"aa61\",\"챏\",4,\"챖챚\",5,\"챡챢챣챥챧챩\",6,\"챱챲\"],[\"aa81\",\"챳챴챶\",29,\"ぁ\",82],[\"ab41\",\"첔첕첖첗첚첛첝첞첟첡\",6,\"첪첮\",5,\"첶첷첹\"],[\"ab61\",\"첺첻첽\",6,\"쳆쳈쳊\",5,\"쳑쳒쳓쳕\",5],[\"ab81\",\"쳛\",8,\"쳥\",6,\"쳭쳮쳯쳱\",12,\"ァ\",85],[\"ac41\",\"쳾쳿촀촂\",5,\"촊촋촍촎촏촑\",6,\"촚촜촞촟촠\"],[\"ac61\",\"촡촢촣촥촦촧촩촪촫촭\",11,\"촺\",4],[\"ac81\",\"촿\",28,\"쵝쵞쵟А\",5,\"ЁЖ\",25],[\"acd1\",\"а\",5,\"ёж\",25],[\"ad41\",\"쵡쵢쵣쵥\",6,\"쵮쵰쵲\",5,\"쵹\",7],[\"ad61\",\"춁\",6,\"춉\",10,\"춖춗춙춚춛춝춞춟\"],[\"ad81\",\"춠춡춢춣춦춨춪\",5,\"춱\",18,\"췅\"],[\"ae41\",\"췆\",5,\"췍췎췏췑\",16],[\"ae61\",\"췢\",5,\"췩췪췫췭췮췯췱\",6,\"췺췼췾\",4],[\"ae81\",\"츃츅츆츇츉츊츋츍\",6,\"츕츖츗츘츚\",5,\"츢츣츥츦츧츩츪츫\"],[\"af41\",\"츬츭츮츯츲츴츶\",19],[\"af61\",\"칊\",13,\"칚칛칝칞칢\",5,\"칪칬\"],[\"af81\",\"칮\",5,\"칶칷칹칺칻칽\",6,\"캆캈캊\",5,\"캒캓캕캖캗캙\"],[\"b041\",\"캚\",5,\"캢캦\",5,\"캮\",12],[\"b061\",\"캻\",5,\"컂\",19],[\"b081\",\"컖\",13,\"컦컧컩컪컭\",6,\"컶컺\",5,\"가각간갇갈갉갊감\",7,\"같\",4,\"갠갤갬갭갯갰갱갸갹갼걀걋걍걔걘걜거걱건걷걸걺검겁것겄겅겆겉겊겋게겐겔겜겝겟겠겡겨격겪견겯결겸겹겻겼경곁계곈곌곕곗고곡곤곧골곪곬곯곰곱곳공곶과곽관괄괆\"],[\"b141\",\"켂켃켅켆켇켉\",6,\"켒켔켖\",5,\"켝켞켟켡켢켣\"],[\"b161\",\"켥\",6,\"켮켲\",5,\"켹\",11],[\"b181\",\"콅\",14,\"콖콗콙콚콛콝\",6,\"콦콨콪콫콬괌괍괏광괘괜괠괩괬괭괴괵괸괼굄굅굇굉교굔굘굡굣구국군굳굴굵굶굻굼굽굿궁궂궈궉권궐궜궝궤궷귀귁귄귈귐귑귓규균귤그극근귿글긁금급긋긍긔기긱긴긷길긺김깁깃깅깆깊까깍깎깐깔깖깜깝깟깠깡깥깨깩깬깰깸\"],[\"b241\",\"콭콮콯콲콳콵콶콷콹\",6,\"쾁쾂쾃쾄쾆\",5,\"쾍\"],[\"b261\",\"쾎\",18,\"쾢\",5,\"쾩\"],[\"b281\",\"쾪\",5,\"쾱\",18,\"쿅\",6,\"깹깻깼깽꺄꺅꺌꺼꺽꺾껀껄껌껍껏껐껑께껙껜껨껫껭껴껸껼꼇꼈꼍꼐꼬꼭꼰꼲꼴꼼꼽꼿꽁꽂꽃꽈꽉꽐꽜꽝꽤꽥꽹꾀꾄꾈꾐꾑꾕꾜꾸꾹꾼꿀꿇꿈꿉꿋꿍꿎꿔꿜꿨꿩꿰꿱꿴꿸뀀뀁뀄뀌뀐뀔뀜뀝뀨끄끅끈끊끌끎끓끔끕끗끙\"],[\"b341\",\"쿌\",19,\"쿢쿣쿥쿦쿧쿩\"],[\"b361\",\"쿪\",5,\"쿲쿴쿶\",5,\"쿽쿾쿿퀁퀂퀃퀅\",5],[\"b381\",\"퀋\",5,\"퀒\",5,\"퀙\",19,\"끝끼끽낀낄낌낍낏낑나낙낚난낟날낡낢남납낫\",4,\"낱낳내낵낸낼냄냅냇냈냉냐냑냔냘냠냥너넉넋넌널넒넓넘넙넛넜넝넣네넥넨넬넴넵넷넸넹녀녁년녈념녑녔녕녘녜녠노녹논놀놂놈놉놋농높놓놔놘놜놨뇌뇐뇔뇜뇝\"],[\"b441\",\"퀮\",5,\"퀶퀷퀹퀺퀻퀽\",6,\"큆큈큊\",5],[\"b461\",\"큑큒큓큕큖큗큙\",6,\"큡\",10,\"큮큯\"],[\"b481\",\"큱큲큳큵\",6,\"큾큿킀킂\",18,\"뇟뇨뇩뇬뇰뇹뇻뇽누눅눈눋눌눔눕눗눙눠눴눼뉘뉜뉠뉨뉩뉴뉵뉼늄늅늉느늑는늘늙늚늠늡늣능늦늪늬늰늴니닉닌닐닒님닙닛닝닢다닥닦단닫\",4,\"닳담답닷\",4,\"닿대댁댄댈댐댑댓댔댕댜더덕덖던덛덜덞덟덤덥\"],[\"b541\",\"킕\",14,\"킦킧킩킪킫킭\",5],[\"b561\",\"킳킶킸킺\",5,\"탂탃탅탆탇탊\",5,\"탒탖\",4],[\"b581\",\"탛탞탟탡탢탣탥\",6,\"탮탲\",5,\"탹\",11,\"덧덩덫덮데덱덴델뎀뎁뎃뎄뎅뎌뎐뎔뎠뎡뎨뎬도독돈돋돌돎돐돔돕돗동돛돝돠돤돨돼됐되된될됨됩됫됴두둑둔둘둠둡둣둥둬뒀뒈뒝뒤뒨뒬뒵뒷뒹듀듄듈듐듕드득든듣들듦듬듭듯등듸디딕딘딛딜딤딥딧딨딩딪따딱딴딸\"],[\"b641\",\"턅\",7,\"턎\",17],[\"b661\",\"턠\",15,\"턲턳턵턶턷턹턻턼턽턾\"],[\"b681\",\"턿텂텆\",5,\"텎텏텑텒텓텕\",6,\"텞텠텢\",5,\"텩텪텫텭땀땁땃땄땅땋때땍땐땔땜땝땟땠땡떠떡떤떨떪떫떰떱떳떴떵떻떼떽뗀뗄뗌뗍뗏뗐뗑뗘뗬또똑똔똘똥똬똴뙈뙤뙨뚜뚝뚠뚤뚫뚬뚱뛔뛰뛴뛸뜀뜁뜅뜨뜩뜬뜯뜰뜸뜹뜻띄띈띌띔띕띠띤띨띰띱띳띵라락란랄람랍랏랐랑랒랖랗\"],[\"b741\",\"텮\",13,\"텽\",6,\"톅톆톇톉톊\"],[\"b761\",\"톋\",20,\"톢톣톥톦톧\"],[\"b781\",\"톩\",6,\"톲톴톶톷톸톹톻톽톾톿퇁\",14,\"래랙랜랠램랩랫랬랭랴략랸럇량러럭런럴럼럽럿렀렁렇레렉렌렐렘렙렛렝려력련렬렴렵렷렸령례롄롑롓로록론롤롬롭롯롱롸롼뢍뢨뢰뢴뢸룀룁룃룅료룐룔룝룟룡루룩룬룰룸룹룻룽뤄뤘뤠뤼뤽륀륄륌륏륑류륙륜률륨륩\"],[\"b841\",\"퇐\",7,\"퇙\",17],[\"b861\",\"퇫\",8,\"퇵퇶퇷퇹\",13],[\"b881\",\"툈툊\",5,\"툑\",24,\"륫륭르륵른를름릅릇릉릊릍릎리릭린릴림립릿링마막만많\",4,\"맘맙맛망맞맡맣매맥맨맬맴맵맷맸맹맺먀먁먈먕머먹먼멀멂멈멉멋멍멎멓메멕멘멜멤멥멧멨멩며멱면멸몃몄명몇몌모목몫몬몰몲몸몹못몽뫄뫈뫘뫙뫼\"],[\"b941\",\"툪툫툮툯툱툲툳툵\",6,\"툾퉀퉂\",5,\"퉉퉊퉋퉌\"],[\"b961\",\"퉍\",14,\"퉝\",6,\"퉥퉦퉧퉨\"],[\"b981\",\"퉩\",22,\"튂튃튅튆튇튉튊튋튌묀묄묍묏묑묘묜묠묩묫무묵묶문묻물묽묾뭄뭅뭇뭉뭍뭏뭐뭔뭘뭡뭣뭬뮈뮌뮐뮤뮨뮬뮴뮷므믄믈믐믓미믹민믿밀밂밈밉밋밌밍및밑바\",4,\"받\",4,\"밤밥밧방밭배백밴밸뱀뱁뱃뱄뱅뱉뱌뱍뱐뱝버벅번벋벌벎범법벗\"],[\"ba41\",\"튍튎튏튒튓튔튖\",5,\"튝튞튟튡튢튣튥\",6,\"튭\"],[\"ba61\",\"튮튯튰튲\",5,\"튺튻튽튾틁틃\",4,\"틊틌\",5],[\"ba81\",\"틒틓틕틖틗틙틚틛틝\",6,\"틦\",9,\"틲틳틵틶틷틹틺벙벚베벡벤벧벨벰벱벳벴벵벼벽변별볍볏볐병볕볘볜보복볶본볼봄봅봇봉봐봔봤봬뵀뵈뵉뵌뵐뵘뵙뵤뵨부북분붇불붉붊붐붑붓붕붙붚붜붤붰붸뷔뷕뷘뷜뷩뷰뷴뷸븀븃븅브븍븐블븜븝븟비빅빈빌빎빔빕빗빙빚빛빠빡빤\"],[\"bb41\",\"틻\",4,\"팂팄팆\",5,\"팏팑팒팓팕팗\",4,\"팞팢팣\"],[\"bb61\",\"팤팦팧팪팫팭팮팯팱\",6,\"팺팾\",5,\"퍆퍇퍈퍉\"],[\"bb81\",\"퍊\",31,\"빨빪빰빱빳빴빵빻빼빽뺀뺄뺌뺍뺏뺐뺑뺘뺙뺨뻐뻑뻔뻗뻘뻠뻣뻤뻥뻬뼁뼈뼉뼘뼙뼛뼜뼝뽀뽁뽄뽈뽐뽑뽕뾔뾰뿅뿌뿍뿐뿔뿜뿟뿡쀼쁑쁘쁜쁠쁨쁩삐삑삔삘삠삡삣삥사삭삯산삳살삵삶삼삽삿샀상샅새색샌샐샘샙샛샜생샤\"],[\"bc41\",\"퍪\",17,\"퍾퍿펁펂펃펅펆펇\"],[\"bc61\",\"펈펉펊펋펎펒\",5,\"펚펛펝펞펟펡\",6,\"펪펬펮\"],[\"bc81\",\"펯\",4,\"펵펶펷펹펺펻펽\",6,\"폆폇폊\",5,\"폑\",5,\"샥샨샬샴샵샷샹섀섄섈섐섕서\",4,\"섣설섦섧섬섭섯섰성섶세섹센셀셈셉셋셌셍셔셕션셜셤셥셧셨셩셰셴셸솅소속솎손솔솖솜솝솟송솥솨솩솬솰솽쇄쇈쇌쇔쇗쇘쇠쇤쇨쇰쇱쇳쇼쇽숀숄숌숍숏숑수숙순숟술숨숩숫숭\"],[\"bd41\",\"폗폙\",7,\"폢폤\",7,\"폮폯폱폲폳폵폶폷\"],[\"bd61\",\"폸폹폺폻폾퐀퐂\",5,\"퐉\",13],[\"bd81\",\"퐗\",5,\"퐞\",25,\"숯숱숲숴쉈쉐쉑쉔쉘쉠쉥쉬쉭쉰쉴쉼쉽쉿슁슈슉슐슘슛슝스슥슨슬슭슴습슷승시식신싣실싫심십싯싱싶싸싹싻싼쌀쌈쌉쌌쌍쌓쌔쌕쌘쌜쌤쌥쌨쌩썅써썩썬썰썲썸썹썼썽쎄쎈쎌쏀쏘쏙쏜쏟쏠쏢쏨쏩쏭쏴쏵쏸쐈쐐쐤쐬쐰\"],[\"be41\",\"퐸\",7,\"푁푂푃푅\",14],[\"be61\",\"푔\",7,\"푝푞푟푡푢푣푥\",7,\"푮푰푱푲\"],[\"be81\",\"푳\",4,\"푺푻푽푾풁풃\",4,\"풊풌풎\",5,\"풕\",8,\"쐴쐼쐽쑈쑤쑥쑨쑬쑴쑵쑹쒀쒔쒜쒸쒼쓩쓰쓱쓴쓸쓺쓿씀씁씌씐씔씜씨씩씬씰씸씹씻씽아악안앉않알앍앎앓암압앗았앙앝앞애액앤앨앰앱앳앴앵야약얀얄얇얌얍얏양얕얗얘얜얠얩어억언얹얻얼얽얾엄\",6,\"엌엎\"],[\"bf41\",\"풞\",10,\"풪\",14],[\"bf61\",\"풹\",18,\"퓍퓎퓏퓑퓒퓓퓕\"],[\"bf81\",\"퓖\",5,\"퓝퓞퓠\",7,\"퓩퓪퓫퓭퓮퓯퓱\",6,\"퓹퓺퓼에엑엔엘엠엡엣엥여역엮연열엶엷염\",5,\"옅옆옇예옌옐옘옙옛옜오옥온올옭옮옰옳옴옵옷옹옻와왁완왈왐왑왓왔왕왜왝왠왬왯왱외왹왼욀욈욉욋욍요욕욘욜욤욥욧용우욱운울욹욺움웁웃웅워웍원월웜웝웠웡웨\"],[\"c041\",\"퓾\",5,\"픅픆픇픉픊픋픍\",6,\"픖픘\",5],[\"c061\",\"픞\",25],[\"c081\",\"픸픹픺픻픾픿핁핂핃핅\",6,\"핎핐핒\",5,\"핚핛핝핞핟핡핢핣웩웬웰웸웹웽위윅윈윌윔윕윗윙유육윤율윰윱윳융윷으윽은을읊음읍읏응\",7,\"읜읠읨읫이익인일읽읾잃임입잇있잉잊잎자작잔잖잗잘잚잠잡잣잤장잦재잭잰잴잼잽잿쟀쟁쟈쟉쟌쟎쟐쟘쟝쟤쟨쟬저적전절젊\"],[\"c141\",\"핤핦핧핪핬핮\",5,\"핶핷핹핺핻핽\",6,\"햆햊햋\"],[\"c161\",\"햌햍햎햏햑\",19,\"햦햧\"],[\"c181\",\"햨\",31,\"점접젓정젖제젝젠젤젬젭젯젱져젼졀졈졉졌졍졔조족존졸졺좀좁좃종좆좇좋좌좍좔좝좟좡좨좼좽죄죈죌죔죕죗죙죠죡죤죵주죽준줄줅줆줌줍줏중줘줬줴쥐쥑쥔쥘쥠쥡쥣쥬쥰쥴쥼즈즉즌즐즘즙즛증지직진짇질짊짐집짓\"],[\"c241\",\"헊헋헍헎헏헑헓\",4,\"헚헜헞\",5,\"헦헧헩헪헫헭헮\"],[\"c261\",\"헯\",4,\"헶헸헺\",5,\"혂혃혅혆혇혉\",6,\"혒\"],[\"c281\",\"혖\",5,\"혝혞혟혡혢혣혥\",7,\"혮\",9,\"혺혻징짖짙짚짜짝짠짢짤짧짬짭짯짰짱째짹짼쨀쨈쨉쨋쨌쨍쨔쨘쨩쩌쩍쩐쩔쩜쩝쩟쩠쩡쩨쩽쪄쪘쪼쪽쫀쫄쫌쫍쫏쫑쫓쫘쫙쫠쫬쫴쬈쬐쬔쬘쬠쬡쭁쭈쭉쭌쭐쭘쭙쭝쭤쭸쭹쮜쮸쯔쯤쯧쯩찌찍찐찔찜찝찡찢찧차착찬찮찰참찹찻\"],[\"c341\",\"혽혾혿홁홂홃홄홆홇홊홌홎홏홐홒홓홖홗홙홚홛홝\",4],[\"c361\",\"홢\",4,\"홨홪\",5,\"홲홳홵\",11],[\"c381\",\"횁횂횄횆\",5,\"횎횏횑횒횓횕\",7,\"횞횠횢\",5,\"횩횪찼창찾채책챈챌챔챕챗챘챙챠챤챦챨챰챵처척천철첨첩첫첬청체첵첸첼쳄쳅쳇쳉쳐쳔쳤쳬쳰촁초촉촌촐촘촙촛총촤촨촬촹최쵠쵤쵬쵭쵯쵱쵸춈추축춘출춤춥춧충춰췄췌췐취췬췰췸췹췻췽츄츈츌츔츙츠측츤츨츰츱츳층\"],[\"c441\",\"횫횭횮횯횱\",7,\"횺횼\",7,\"훆훇훉훊훋\"],[\"c461\",\"훍훎훏훐훒훓훕훖훘훚\",5,\"훡훢훣훥훦훧훩\",4],[\"c481\",\"훮훯훱훲훳훴훶\",5,\"훾훿휁휂휃휅\",11,\"휒휓휔치칙친칟칠칡침칩칫칭카칵칸칼캄캅캇캉캐캑캔캘캠캡캣캤캥캬캭컁커컥컨컫컬컴컵컷컸컹케켁켄켈켐켑켓켕켜켠켤켬켭켯켰켱켸코콕콘콜콤콥콧콩콰콱콴콸쾀쾅쾌쾡쾨쾰쿄쿠쿡쿤쿨쿰쿱쿳쿵쿼퀀퀄퀑퀘퀭퀴퀵퀸퀼\"],[\"c541\",\"휕휖휗휚휛휝휞휟휡\",6,\"휪휬휮\",5,\"휶휷휹\"],[\"c561\",\"휺휻휽\",6,\"흅흆흈흊\",5,\"흒흓흕흚\",4],[\"c581\",\"흟흢흤흦흧흨흪흫흭흮흯흱흲흳흵\",6,\"흾흿힀힂\",5,\"힊힋큄큅큇큉큐큔큘큠크큭큰클큼큽킁키킥킨킬킴킵킷킹타탁탄탈탉탐탑탓탔탕태택탠탤탬탭탯탰탱탸턍터턱턴털턺텀텁텃텄텅테텍텐텔템텝텟텡텨텬텼톄톈토톡톤톨톰톱톳통톺톼퇀퇘퇴퇸툇툉툐투툭툰툴툼툽툿퉁퉈퉜\"],[\"c641\",\"힍힎힏힑\",6,\"힚힜힞\",5],[\"c6a1\",\"퉤튀튁튄튈튐튑튕튜튠튤튬튱트특튼튿틀틂틈틉틋틔틘틜틤틥티틱틴틸팀팁팃팅파팍팎판팔팖팜팝팟팠팡팥패팩팬팰팸팹팻팼팽퍄퍅퍼퍽펀펄펌펍펏펐펑페펙펜펠펨펩펫펭펴편펼폄폅폈평폐폘폡폣포폭폰폴폼폽폿퐁\"],[\"c7a1\",\"퐈퐝푀푄표푠푤푭푯푸푹푼푿풀풂품풉풋풍풔풩퓌퓐퓔퓜퓟퓨퓬퓰퓸퓻퓽프픈플픔픕픗피픽핀필핌핍핏핑하학한할핥함합핫항해핵핸핼햄햅햇했행햐향허헉헌헐헒험헙헛헝헤헥헨헬헴헵헷헹혀혁현혈혐협혓혔형혜혠\"],[\"c8a1\",\"혤혭호혹혼홀홅홈홉홋홍홑화확환활홧황홰홱홴횃횅회획횐횔횝횟횡효횬횰횹횻후훅훈훌훑훔훗훙훠훤훨훰훵훼훽휀휄휑휘휙휜휠휨휩휫휭휴휵휸휼흄흇흉흐흑흔흖흗흘흙흠흡흣흥흩희흰흴흼흽힁히힉힌힐힘힙힛힝\"],[\"caa1\",\"伽佳假價加可呵哥嘉嫁家暇架枷柯歌珂痂稼苛茄街袈訶賈跏軻迦駕刻却各恪慤殼珏脚覺角閣侃刊墾奸姦干幹懇揀杆柬桿澗癎看磵稈竿簡肝艮艱諫間乫喝曷渴碣竭葛褐蝎鞨勘坎堪嵌感憾戡敢柑橄減甘疳監瞰紺邯鑑鑒龕\"],[\"cba1\",\"匣岬甲胛鉀閘剛堈姜岡崗康强彊慷江畺疆糠絳綱羌腔舡薑襁講鋼降鱇介价個凱塏愷愾慨改槪漑疥皆盖箇芥蓋豈鎧開喀客坑更粳羹醵倨去居巨拒据據擧渠炬祛距踞車遽鉅鋸乾件健巾建愆楗腱虔蹇鍵騫乞傑杰桀儉劍劒檢\"],[\"cca1\",\"瞼鈐黔劫怯迲偈憩揭擊格檄激膈覡隔堅牽犬甄絹繭肩見譴遣鵑抉決潔結缺訣兼慊箝謙鉗鎌京俓倞傾儆勁勍卿坰境庚徑慶憬擎敬景暻更梗涇炅烱璟璥瓊痙硬磬竟競絅經耕耿脛莖警輕逕鏡頃頸驚鯨係啓堺契季屆悸戒桂械\"],[\"cda1\",\"棨溪界癸磎稽系繫繼計誡谿階鷄古叩告呱固姑孤尻庫拷攷故敲暠枯槁沽痼皐睾稿羔考股膏苦苽菰藁蠱袴誥賈辜錮雇顧高鼓哭斛曲梏穀谷鵠困坤崑昆梱棍滾琨袞鯤汨滑骨供公共功孔工恐恭拱控攻珙空蚣貢鞏串寡戈果瓜\"],[\"cea1\",\"科菓誇課跨過鍋顆廓槨藿郭串冠官寬慣棺款灌琯瓘管罐菅觀貫關館刮恝括适侊光匡壙廣曠洸炚狂珖筐胱鑛卦掛罫乖傀塊壞怪愧拐槐魁宏紘肱轟交僑咬喬嬌嶠巧攪敎校橋狡皎矯絞翹膠蕎蛟較轎郊餃驕鮫丘久九仇俱具勾\"],[\"cfa1\",\"區口句咎嘔坵垢寇嶇廐懼拘救枸柩構歐毆毬求溝灸狗玖球瞿矩究絿耉臼舅舊苟衢謳購軀逑邱鉤銶駒驅鳩鷗龜國局菊鞠鞫麴君窘群裙軍郡堀屈掘窟宮弓穹窮芎躬倦券勸卷圈拳捲權淃眷厥獗蕨蹶闕机櫃潰詭軌饋句晷歸貴\"],[\"d0a1\",\"鬼龜叫圭奎揆槻珪硅窺竅糾葵規赳逵閨勻均畇筠菌鈞龜橘克剋劇戟棘極隙僅劤勤懃斤根槿瑾筋芹菫覲謹近饉契今妗擒昑檎琴禁禽芩衾衿襟金錦伋及急扱汲級給亘兢矜肯企伎其冀嗜器圻基埼夔奇妓寄岐崎己幾忌技旗旣\"],[\"d1a1\",\"朞期杞棋棄機欺氣汽沂淇玘琦琪璂璣畸畿碁磯祁祇祈祺箕紀綺羈耆耭肌記譏豈起錡錤飢饑騎騏驥麒緊佶吉拮桔金喫儺喇奈娜懦懶拏拿癩\",5,\"那樂\",4,\"諾酪駱亂卵暖欄煖爛蘭難鸞捏捺南嵐枏楠湳濫男藍襤拉\"],[\"d2a1\",\"納臘蠟衲囊娘廊\",4,\"乃來內奈柰耐冷女年撚秊念恬拈捻寧寗努勞奴弩怒擄櫓爐瑙盧\",5,\"駑魯\",10,\"濃籠聾膿農惱牢磊腦賂雷尿壘\",7,\"嫩訥杻紐勒\",5,\"能菱陵尼泥匿溺多茶\"],[\"d3a1\",\"丹亶但單團壇彖斷旦檀段湍短端簞緞蛋袒鄲鍛撻澾獺疸達啖坍憺擔曇淡湛潭澹痰聃膽蕁覃談譚錟沓畓答踏遝唐堂塘幢戇撞棠當糖螳黨代垈坮大對岱帶待戴擡玳臺袋貸隊黛宅德悳倒刀到圖堵塗導屠島嶋度徒悼挑掉搗桃\"],[\"d4a1\",\"棹櫂淘渡滔濤燾盜睹禱稻萄覩賭跳蹈逃途道都鍍陶韜毒瀆牘犢獨督禿篤纛讀墩惇敦旽暾沌焞燉豚頓乭突仝冬凍動同憧東桐棟洞潼疼瞳童胴董銅兜斗杜枓痘竇荳讀豆逗頭屯臀芚遁遯鈍得嶝橙燈登等藤謄鄧騰喇懶拏癩羅\"],[\"d5a1\",\"蘿螺裸邏樂洛烙珞絡落諾酪駱丹亂卵欄欒瀾爛蘭鸞剌辣嵐擥攬欖濫籃纜藍襤覽拉臘蠟廊朗浪狼琅瑯螂郞來崍徠萊冷掠略亮倆兩凉梁樑粮粱糧良諒輛量侶儷勵呂廬慮戾旅櫚濾礪藜蠣閭驢驪麗黎力曆歷瀝礫轢靂憐戀攣漣\"],[\"d6a1\",\"煉璉練聯蓮輦連鍊冽列劣洌烈裂廉斂殮濂簾獵令伶囹寧岺嶺怜玲笭羚翎聆逞鈴零靈領齡例澧禮醴隷勞怒撈擄櫓潞瀘爐盧老蘆虜路輅露魯鷺鹵碌祿綠菉錄鹿麓論壟弄朧瀧瓏籠聾儡瀨牢磊賂賚賴雷了僚寮廖料燎療瞭聊蓼\"],[\"d7a1\",\"遼鬧龍壘婁屢樓淚漏瘻累縷蔞褸鏤陋劉旒柳榴流溜瀏琉瑠留瘤硫謬類六戮陸侖倫崙淪綸輪律慄栗率隆勒肋凜凌楞稜綾菱陵俚利厘吏唎履悧李梨浬犁狸理璃異痢籬罹羸莉裏裡里釐離鯉吝潾燐璘藺躪隣鱗麟林淋琳臨霖砬\"],[\"d8a1\",\"立笠粒摩瑪痲碼磨馬魔麻寞幕漠膜莫邈万卍娩巒彎慢挽晩曼滿漫灣瞞萬蔓蠻輓饅鰻唜抹末沫茉襪靺亡妄忘忙望網罔芒茫莽輞邙埋妹媒寐昧枚梅每煤罵買賣邁魅脈貊陌驀麥孟氓猛盲盟萌冪覓免冕勉棉沔眄眠綿緬面麵滅\"],[\"d9a1\",\"蔑冥名命明暝椧溟皿瞑茗蓂螟酩銘鳴袂侮冒募姆帽慕摸摹暮某模母毛牟牡瑁眸矛耗芼茅謀謨貌木沐牧目睦穆鶩歿沒夢朦蒙卯墓妙廟描昴杳渺猫竗苗錨務巫憮懋戊拇撫无楙武毋無珷畝繆舞茂蕪誣貿霧鵡墨默們刎吻問文\"],[\"daa1\",\"汶紊紋聞蚊門雯勿沕物味媚尾嵋彌微未梶楣渼湄眉米美薇謎迷靡黴岷悶愍憫敏旻旼民泯玟珉緡閔密蜜謐剝博拍搏撲朴樸泊珀璞箔粕縛膊舶薄迫雹駁伴半反叛拌搬攀斑槃泮潘班畔瘢盤盼磐磻礬絆般蟠返頒飯勃拔撥渤潑\"],[\"dba1\",\"發跋醱鉢髮魃倣傍坊妨尨幇彷房放方旁昉枋榜滂磅紡肪膀舫芳蒡蚌訪謗邦防龐倍俳北培徘拜排杯湃焙盃背胚裴裵褙賠輩配陪伯佰帛柏栢白百魄幡樊煩燔番磻繁蕃藩飜伐筏罰閥凡帆梵氾汎泛犯範范法琺僻劈壁擘檗璧癖\"],[\"dca1\",\"碧蘗闢霹便卞弁變辨辯邊別瞥鱉鼈丙倂兵屛幷昞昺柄棅炳甁病秉竝輧餠騈保堡報寶普步洑湺潽珤甫菩補褓譜輔伏僕匐卜宓復服福腹茯蔔複覆輹輻馥鰒本乶俸奉封峯峰捧棒烽熢琫縫蓬蜂逢鋒鳳不付俯傅剖副否咐埠夫婦\"],[\"dda1\",\"孚孵富府復扶敷斧浮溥父符簿缶腐腑膚艀芙莩訃負賦賻赴趺部釜阜附駙鳧北分吩噴墳奔奮忿憤扮昐汾焚盆粉糞紛芬賁雰不佛弗彿拂崩朋棚硼繃鵬丕備匕匪卑妃婢庇悲憊扉批斐枇榧比毖毗毘沸泌琵痺砒碑秕秘粃緋翡肥\"],[\"dea1\",\"脾臂菲蜚裨誹譬費鄙非飛鼻嚬嬪彬斌檳殯浜濱瀕牝玭貧賓頻憑氷聘騁乍事些仕伺似使俟僿史司唆嗣四士奢娑寫寺射巳師徙思捨斜斯柶査梭死沙泗渣瀉獅砂社祀祠私篩紗絲肆舍莎蓑蛇裟詐詞謝賜赦辭邪飼駟麝削數朔索\"],[\"dfa1\",\"傘刪山散汕珊産疝算蒜酸霰乷撒殺煞薩三參杉森渗芟蔘衫揷澁鈒颯上傷像償商喪嘗孀尙峠常床庠廂想桑橡湘爽牀狀相祥箱翔裳觴詳象賞霜塞璽賽嗇塞穡索色牲生甥省笙墅壻嶼序庶徐恕抒捿敍暑曙書栖棲犀瑞筮絮緖署\"],[\"e0a1\",\"胥舒薯西誓逝鋤黍鼠夕奭席惜昔晳析汐淅潟石碩蓆釋錫仙僊先善嬋宣扇敾旋渲煽琁瑄璇璿癬禪線繕羨腺膳船蘚蟬詵跣選銑鐥饍鮮卨屑楔泄洩渫舌薛褻設說雪齧剡暹殲纖蟾贍閃陝攝涉燮葉城姓宬性惺成星晟猩珹盛省筬\"],[\"e1a1\",\"聖聲腥誠醒世勢歲洗稅笹細說貰召嘯塑宵小少巢所掃搔昭梳沼消溯瀟炤燒甦疏疎瘙笑篠簫素紹蔬蕭蘇訴逍遡邵銷韶騷俗屬束涑粟續謖贖速孫巽損蓀遜飡率宋悚松淞訟誦送頌刷殺灑碎鎖衰釗修受嗽囚垂壽嫂守岫峀帥愁\"],[\"e2a1\",\"戍手授搜收數樹殊水洙漱燧狩獸琇璲瘦睡秀穗竪粹綏綬繡羞脩茱蒐蓚藪袖誰讐輸遂邃酬銖銹隋隧隨雖需須首髓鬚叔塾夙孰宿淑潚熟琡璹肅菽巡徇循恂旬栒楯橓殉洵淳珣盾瞬筍純脣舜荀蓴蕣詢諄醇錞順馴戌術述鉥崇崧\"],[\"e3a1\",\"嵩瑟膝蝨濕拾習褶襲丞乘僧勝升承昇繩蠅陞侍匙嘶始媤尸屎屍市弑恃施是時枾柴猜矢示翅蒔蓍視試詩諡豕豺埴寔式息拭植殖湜熄篒蝕識軾食飾伸侁信呻娠宸愼新晨燼申神紳腎臣莘薪藎蜃訊身辛辰迅失室實悉審尋心沁\"],[\"e4a1\",\"沈深瀋甚芯諶什十拾雙氏亞俄兒啞娥峨我牙芽莪蛾衙訝阿雅餓鴉鵝堊岳嶽幄惡愕握樂渥鄂鍔顎鰐齷安岸按晏案眼雁鞍顔鮟斡謁軋閼唵岩巖庵暗癌菴闇壓押狎鴨仰央怏昻殃秧鴦厓哀埃崖愛曖涯碍艾隘靄厄扼掖液縊腋額\"],[\"e5a1\",\"櫻罌鶯鸚也倻冶夜惹揶椰爺耶若野弱掠略約若葯蒻藥躍亮佯兩凉壤孃恙揚攘敭暘梁楊樣洋瀁煬痒瘍禳穰糧羊良襄諒讓釀陽量養圄御於漁瘀禦語馭魚齬億憶抑檍臆偃堰彦焉言諺孼蘖俺儼嚴奄掩淹嶪業円予余勵呂女如廬\"],[\"e6a1\",\"旅歟汝濾璵礖礪與艅茹輿轝閭餘驪麗黎亦力域役易曆歷疫繹譯轢逆驛嚥堧姸娟宴年延憐戀捐挻撚椽沇沿涎涓淵演漣烟然煙煉燃燕璉硏硯秊筵緣練縯聯衍軟輦蓮連鉛鍊鳶列劣咽悅涅烈熱裂說閱厭廉念捻染殮炎焰琰艶苒\"],[\"e7a1\",\"簾閻髥鹽曄獵燁葉令囹塋寧嶺嶸影怜映暎楹榮永泳渶潁濚瀛瀯煐營獰玲瑛瑩瓔盈穎纓羚聆英詠迎鈴鍈零霙靈領乂倪例刈叡曳汭濊猊睿穢芮藝蘂禮裔詣譽豫醴銳隸霓預五伍俉傲午吾吳嗚塢墺奧娛寤悟惡懊敖旿晤梧汚澳\"],[\"e8a1\",\"烏熬獒筽蜈誤鰲鼇屋沃獄玉鈺溫瑥瘟穩縕蘊兀壅擁瓮甕癰翁邕雍饔渦瓦窩窪臥蛙蝸訛婉完宛梡椀浣玩琓琬碗緩翫脘腕莞豌阮頑曰往旺枉汪王倭娃歪矮外嵬巍猥畏了僚僥凹堯夭妖姚寥寮尿嶢拗搖撓擾料曜樂橈燎燿瑤療\"],[\"e9a1\",\"窈窯繇繞耀腰蓼蟯要謠遙遼邀饒慾欲浴縟褥辱俑傭冗勇埇墉容庸慂榕涌湧溶熔瑢用甬聳茸蓉踊鎔鏞龍于佑偶優又友右宇寓尤愚憂旴牛玗瑀盂祐禑禹紆羽芋藕虞迂遇郵釪隅雨雩勖彧旭昱栯煜稶郁頊云暈橒殞澐熉耘芸蕓\"],[\"eaa1\",\"運隕雲韻蔚鬱亐熊雄元原員圓園垣媛嫄寃怨愿援沅洹湲源爰猿瑗苑袁轅遠阮院願鴛月越鉞位偉僞危圍委威尉慰暐渭爲瑋緯胃萎葦蔿蝟衛褘謂違韋魏乳侑儒兪劉唯喩孺宥幼幽庾悠惟愈愉揄攸有杻柔柚柳楡楢油洧流游溜\"],[\"eba1\",\"濡猶猷琉瑜由留癒硫紐維臾萸裕誘諛諭踰蹂遊逾遺酉釉鍮類六堉戮毓肉育陸倫允奫尹崙淪潤玧胤贇輪鈗閏律慄栗率聿戎瀜絨融隆垠恩慇殷誾銀隱乙吟淫蔭陰音飮揖泣邑凝應膺鷹依倚儀宜意懿擬椅毅疑矣義艤薏蟻衣誼\"],[\"eca1\",\"議醫二以伊利吏夷姨履已弛彛怡易李梨泥爾珥理異痍痢移罹而耳肄苡荑裏裡貽貳邇里離飴餌匿溺瀷益翊翌翼謚人仁刃印吝咽因姻寅引忍湮燐璘絪茵藺蚓認隣靭靷鱗麟一佚佾壹日溢逸鎰馹任壬妊姙恁林淋稔臨荏賃入卄\"],[\"eda1\",\"立笠粒仍剩孕芿仔刺咨姉姿子字孜恣慈滋炙煮玆瓷疵磁紫者自茨蔗藉諮資雌作勺嚼斫昨灼炸爵綽芍酌雀鵲孱棧殘潺盞岑暫潛箴簪蠶雜丈仗匠場墻壯奬將帳庄張掌暲杖樟檣欌漿牆狀獐璋章粧腸臟臧莊葬蔣薔藏裝贓醬長\"],[\"eea1\",\"障再哉在宰才材栽梓渽滓災縡裁財載齋齎爭箏諍錚佇低儲咀姐底抵杵楮樗沮渚狙猪疽箸紵苧菹著藷詛貯躇這邸雎齟勣吊嫡寂摘敵滴狄炙的積笛籍績翟荻謫賊赤跡蹟迪迹適鏑佃佺傳全典前剪塡塼奠專展廛悛戰栓殿氈澱\"],[\"efa1\",\"煎琠田甸畑癲筌箋箭篆纏詮輾轉鈿銓錢鐫電顚顫餞切截折浙癤竊節絶占岾店漸点粘霑鮎點接摺蝶丁井亭停偵呈姃定幀庭廷征情挺政整旌晶晸柾楨檉正汀淀淨渟湞瀞炡玎珽町睛碇禎程穽精綎艇訂諪貞鄭酊釘鉦鋌錠霆靖\"],[\"f0a1\",\"靜頂鼎制劑啼堤帝弟悌提梯濟祭第臍薺製諸蹄醍除際霽題齊俎兆凋助嘲弔彫措操早晁曺曹朝條棗槽漕潮照燥爪璪眺祖祚租稠窕粗糟組繰肇藻蚤詔調趙躁造遭釣阻雕鳥族簇足鏃存尊卒拙猝倧宗從悰慫棕淙琮種終綜縱腫\"],[\"f1a1\",\"踪踵鍾鐘佐坐左座挫罪主住侏做姝胄呪周嗾奏宙州廚晝朱柱株注洲湊澍炷珠疇籌紂紬綢舟蛛註誅走躊輳週酎酒鑄駐竹粥俊儁准埈寯峻晙樽浚準濬焌畯竣蠢逡遵雋駿茁中仲衆重卽櫛楫汁葺增憎曾拯烝甑症繒蒸證贈之只\"],[\"f2a1\",\"咫地址志持指摯支旨智枝枳止池沚漬知砥祉祗紙肢脂至芝芷蜘誌識贄趾遲直稙稷織職唇嗔塵振搢晉晋桭榛殄津溱珍瑨璡畛疹盡眞瞋秦縉縝臻蔯袗診賑軫辰進鎭陣陳震侄叱姪嫉帙桎瓆疾秩窒膣蛭質跌迭斟朕什執潗緝輯\"],[\"f3a1\",\"鏶集徵懲澄且侘借叉嗟嵯差次此磋箚茶蹉車遮捉搾着窄錯鑿齪撰澯燦璨瓚竄簒纂粲纘讚贊鑽餐饌刹察擦札紮僭參塹慘慙懺斬站讒讖倉倡創唱娼廠彰愴敞昌昶暢槍滄漲猖瘡窓脹艙菖蒼債埰寀寨彩採砦綵菜蔡采釵冊柵策\"],[\"f4a1\",\"責凄妻悽處倜刺剔尺慽戚拓擲斥滌瘠脊蹠陟隻仟千喘天川擅泉淺玔穿舛薦賤踐遷釧闡阡韆凸哲喆徹撤澈綴輟轍鐵僉尖沾添甛瞻簽籤詹諂堞妾帖捷牒疊睫諜貼輒廳晴淸聽菁請靑鯖切剃替涕滯締諦逮遞體初剿哨憔抄招梢\"],[\"f5a1\",\"椒楚樵炒焦硝礁礎秒稍肖艸苕草蕉貂超酢醋醮促囑燭矗蜀觸寸忖村邨叢塚寵悤憁摠總聰蔥銃撮催崔最墜抽推椎楸樞湫皺秋芻萩諏趨追鄒酋醜錐錘鎚雛騶鰍丑畜祝竺筑築縮蓄蹙蹴軸逐春椿瑃出朮黜充忠沖蟲衝衷悴膵萃\"],[\"f6a1\",\"贅取吹嘴娶就炊翠聚脆臭趣醉驟鷲側仄厠惻測層侈値嗤峙幟恥梔治淄熾痔痴癡稚穉緇緻置致蚩輜雉馳齒則勅飭親七柒漆侵寢枕沈浸琛砧針鍼蟄秤稱快他咤唾墮妥惰打拖朶楕舵陀馱駝倬卓啄坼度托拓擢晫柝濁濯琢琸託\"],[\"f7a1\",\"鐸呑嘆坦彈憚歎灘炭綻誕奪脫探眈耽貪塔搭榻宕帑湯糖蕩兌台太怠態殆汰泰笞胎苔跆邰颱宅擇澤撑攄兎吐土討慟桶洞痛筒統通堆槌腿褪退頹偸套妬投透鬪慝特闖坡婆巴把播擺杷波派爬琶破罷芭跛頗判坂板版瓣販辦鈑\"],[\"f8a1\",\"阪八叭捌佩唄悖敗沛浿牌狽稗覇貝彭澎烹膨愎便偏扁片篇編翩遍鞭騙貶坪平枰萍評吠嬖幣廢弊斃肺蔽閉陛佈包匍匏咆哺圃布怖抛抱捕暴泡浦疱砲胞脯苞葡蒲袍褒逋鋪飽鮑幅暴曝瀑爆輻俵剽彪慓杓標漂瓢票表豹飇飄驃\"],[\"f9a1\",\"品稟楓諷豊風馮彼披疲皮被避陂匹弼必泌珌畢疋筆苾馝乏逼下何厦夏廈昰河瑕荷蝦賀遐霞鰕壑學虐謔鶴寒恨悍旱汗漢澣瀚罕翰閑閒限韓割轄函含咸啣喊檻涵緘艦銜陷鹹合哈盒蛤閤闔陜亢伉姮嫦巷恒抗杭桁沆港缸肛航\"],[\"faa1\",\"行降項亥偕咳垓奚孩害懈楷海瀣蟹解該諧邂駭骸劾核倖幸杏荇行享向嚮珦鄕響餉饗香噓墟虛許憲櫶獻軒歇險驗奕爀赫革俔峴弦懸晛泫炫玄玹現眩睍絃絢縣舷衒見賢鉉顯孑穴血頁嫌俠協夾峽挾浹狹脅脇莢鋏頰亨兄刑型\"],[\"fba1\",\"形泂滎瀅灐炯熒珩瑩荊螢衡逈邢鎣馨兮彗惠慧暳蕙蹊醯鞋乎互呼壕壺好岵弧戶扈昊晧毫浩淏湖滸澔濠濩灝狐琥瑚瓠皓祜糊縞胡芦葫蒿虎號蝴護豪鎬頀顥惑或酷婚昏混渾琿魂忽惚笏哄弘汞泓洪烘紅虹訌鴻化和嬅樺火畵\"],[\"fca1\",\"禍禾花華話譁貨靴廓擴攫確碻穫丸喚奐宦幻患換歡晥桓渙煥環紈還驩鰥活滑猾豁闊凰幌徨恍惶愰慌晃晄榥況湟滉潢煌璜皇篁簧荒蝗遑隍黃匯回廻徊恢悔懷晦會檜淮澮灰獪繪膾茴蛔誨賄劃獲宖橫鐄哮嚆孝效斅曉梟涍淆\"],[\"fda1\",\"爻肴酵驍侯候厚后吼喉嗅帿後朽煦珝逅勛勳塤壎焄熏燻薰訓暈薨喧暄煊萱卉喙毁彙徽揮暉煇諱輝麾休携烋畦虧恤譎鷸兇凶匈洶胸黑昕欣炘痕吃屹紇訖欠欽歆吸恰洽翕興僖凞喜噫囍姬嬉希憙憘戱晞曦熙熹熺犧禧稀羲詰\"]]\n\n/***/ }),\n/* 184 */\n/***/ (function(module, exports) {\n\nmodule.exports = [[\"8740\",\"䏰䰲䘃䖦䕸𧉧䵷䖳𧲱䳢𧳅㮕䜶䝄䱇䱀𤊿𣘗𧍒𦺋𧃒䱗𪍑䝏䗚䲅𧱬䴇䪤䚡𦬣爥𥩔𡩣𣸆𣽡晍囻\"],[\"8767\",\"綕夝𨮹㷴霴𧯯寛𡵞媤㘥𩺰嫑宷峼杮薓𩥅瑡璝㡵𡵓𣚞𦀡㻬\"],[\"87a1\",\"𥣞㫵竼龗𤅡𨤍𣇪𠪊𣉞䌊蒄龖鐯䤰蘓墖靊鈘秐稲晠権袝瑌篅枂稬剏遆㓦珄𥶹瓆鿇垳䤯呌䄱𣚎堘穲𧭥讏䚮𦺈䆁𥶙箮𢒼鿈𢓁𢓉𢓌鿉蔄𣖻䂴鿊䓡𪷿拁灮鿋\"],[\"8840\",\"㇀\",4,\"𠄌㇅𠃑𠃍㇆㇇𠃋𡿨㇈𠃊㇉㇊㇋㇌𠄎㇍㇎ĀÁǍÀĒÉĚÈŌÓǑÒ࿿Ê̄Ế࿿Ê̌ỀÊāáǎàɑēéěèīíǐìōóǒòūúǔùǖǘǚ\"],[\"88a1\",\"ǜü࿿ê̄ế࿿ê̌ềêɡ⏚⏛\"],[\"8940\",\"𪎩𡅅\"],[\"8943\",\"攊\"],[\"8946\",\"丽滝鵎釟\"],[\"894c\",\"𧜵撑会伨侨兖兴农凤务动医华发变团声处备夲头学实実岚庆总斉柾栄桥济炼电纤纬纺织经统缆缷艺苏药视设询车轧轮\"],[\"89a1\",\"琑糼緍楆竉刧\"],[\"89ab\",\"醌碸酞肼\"],[\"89b0\",\"贋胶𠧧\"],[\"89b5\",\"肟黇䳍鷉鸌䰾𩷶𧀎鸊𪄳㗁\"],[\"89c1\",\"溚舾甙\"],[\"89c5\",\"䤑马骏龙禇𨑬𡷊𠗐𢫦两亁亀亇亿仫伷㑌侽㹈倃傈㑽㒓㒥円夅凛凼刅争剹劐匧㗇厩㕑厰㕓参吣㕭㕲㚁咓咣咴咹哐哯唘唣唨㖘唿㖥㖿嗗㗅\"],[\"8a40\",\"𧶄唥\"],[\"8a43\",\"𠱂𠴕𥄫喐𢳆㧬𠍁蹆𤶸𩓥䁓𨂾睺𢰸㨴䟕𨅝𦧲𤷪擝𠵼𠾴𠳕𡃴撍蹾𠺖𠰋𠽤𢲩𨉖𤓓\"],[\"8a64\",\"𠵆𩩍𨃩䟴𤺧𢳂骲㩧𩗴㿭㔆𥋇𩟔𧣈𢵄鵮頕\"],[\"8a76\",\"䏙𦂥撴哣𢵌𢯊𡁷㧻𡁯\"],[\"8aa1\",\"𦛚𦜖𧦠擪𥁒𠱃蹨𢆡𨭌𠜱\"],[\"8aac\",\"䠋𠆩㿺塳𢶍\"],[\"8ab2\",\"𤗈𠓼𦂗𠽌𠶖啹䂻䎺\"],[\"8abb\",\"䪴𢩦𡂝膪飵𠶜捹㧾𢝵跀嚡摼㹃\"],[\"8ac9\",\"𪘁𠸉𢫏𢳉\"],[\"8ace\",\"𡃈𣧂㦒㨆𨊛㕸𥹉𢃇噒𠼱𢲲𩜠㒼氽𤸻\"],[\"8adf\",\"𧕴𢺋𢈈𪙛𨳍𠹺𠰴𦠜羓𡃏𢠃𢤹㗻𥇣𠺌𠾍𠺪㾓𠼰𠵇𡅏𠹌\"],[\"8af6\",\"𠺫𠮩𠵈𡃀𡄽㿹𢚖搲𠾭\"],[\"8b40\",\"𣏴𧘹𢯎𠵾𠵿𢱑𢱕㨘𠺘𡃇𠼮𪘲𦭐𨳒𨶙𨳊閪哌苄喹\"],[\"8b55\",\"𩻃鰦骶𧝞𢷮煀腭胬尜𦕲脴㞗卟𨂽醶𠻺𠸏𠹷𠻻㗝𤷫㘉𠳖嚯𢞵𡃉𠸐𠹸𡁸𡅈𨈇𡑕𠹹𤹐𢶤婔𡀝𡀞𡃵𡃶垜𠸑\"],[\"8ba1\",\"𧚔𨋍𠾵𠹻𥅾㜃𠾶𡆀𥋘𪊽𤧚𡠺𤅷𨉼墙剨㘚𥜽箲孨䠀䬬鼧䧧鰟鮍𥭴𣄽嗻㗲嚉丨夂𡯁屮靑𠂆乛亻㔾尣彑忄㣺扌攵歺氵氺灬爫丬犭𤣩罒礻糹罓𦉪㓁\"],[\"8bde\",\"𦍋耂肀𦘒𦥑卝衤见𧢲讠贝钅镸长门𨸏韦页风飞饣𩠐鱼鸟黄歯龜丷𠂇阝户钢\"],[\"8c40\",\"倻淾𩱳龦㷉袏𤅎灷峵䬠𥇍㕙𥴰愢𨨲辧釶熑朙玺𣊁𪄇㲋𡦀䬐磤琂冮𨜏䀉橣𪊺䈣蘏𠩯稪𩥇𨫪靕灍匤𢁾鏴盙𨧣龧矝亣俰傼丯众龨吴綋墒壐𡶶庒庙忂𢜒斋\"],[\"8ca1\",\"𣏹椙橃𣱣泿\"],[\"8ca7\",\"爀𤔅玌㻛𤨓嬕璹讃𥲤𥚕窓篬糃繬苸薗龩袐龪躹龫迏蕟駠鈡龬𨶹𡐿䁱䊢娚\"],[\"8cc9\",\"顨杫䉶圽\"],[\"8cce\",\"藖𤥻芿𧄍䲁𦵴嵻𦬕𦾾龭龮宖龯曧繛湗秊㶈䓃𣉖𢞖䎚䔶\"],[\"8ce6\",\"峕𣬚諹屸㴒𣕑嵸龲煗䕘𤃬𡸣䱷㥸㑊𠆤𦱁諌侴𠈹妿腬顖𩣺弻\"],[\"8d40\",\"𠮟\"],[\"8d42\",\"𢇁𨥭䄂䚻𩁹㼇龳𪆵䃸㟖䛷𦱆䅼𨚲𧏿䕭㣔𥒚䕡䔛䶉䱻䵶䗪㿈𤬏㙡䓞䒽䇭崾嵈嵖㷼㠏嶤嶹㠠㠸幂庽弥徃㤈㤔㤿㥍惗愽峥㦉憷憹懏㦸戬抐拥挘㧸嚱\"],[\"8da1\",\"㨃揢揻搇摚㩋擀崕嘡龟㪗斆㪽旿晓㫲暒㬢朖㭂枤栀㭘桊梄㭲㭱㭻椉楃牜楤榟榅㮼槖㯝橥橴橱檂㯬檙㯲檫檵櫔櫶殁毁毪汵沪㳋洂洆洦涁㳯涤涱渕渘温溆𨧀溻滢滚齿滨滩漤漴㵆𣽁澁澾㵪㵵熷岙㶊瀬㶑灐灔灯灿炉𠌥䏁㗱𠻘\"],[\"8e40\",\"𣻗垾𦻓焾𥟠㙎榢𨯩孴穉𥣡𩓙穥穽𥦬窻窰竂竃燑𦒍䇊竚竝竪䇯咲𥰁笋筕笩𥌎𥳾箢筯莜𥮴𦱿篐萡箒箸𥴠㶭𥱥蒒篺簆簵𥳁籄粃𤢂粦晽𤕸糉糇糦籴糳糵糎\"],[\"8ea1\",\"繧䔝𦹄絝𦻖璍綉綫焵綳緒𤁗𦀩緤㴓緵𡟹緥𨍭縝𦄡𦅚繮纒䌫鑬縧罀罁罇礶𦋐駡羗𦍑羣𡙡𠁨䕜𣝦䔃𨌺翺𦒉者耈耝耨耯𪂇𦳃耻耼聡𢜔䦉𦘦𣷣𦛨朥肧𨩈脇脚墰𢛶汿𦒘𤾸擧𡒊舘𡡞橓𤩥𤪕䑺舩𠬍𦩒𣵾俹𡓽蓢荢𦬊𤦧𣔰𡝳𣷸芪椛芳䇛\"],[\"8f40\",\"蕋苐茚𠸖𡞴㛁𣅽𣕚艻苢茘𣺋𦶣𦬅𦮗𣗎㶿茝嗬莅䔋𦶥莬菁菓㑾𦻔橗蕚㒖𦹂𢻯葘𥯤葱㷓䓤檧葊𣲵祘蒨𦮖𦹷𦹃蓞萏莑䒠蒓蓤𥲑䉀𥳀䕃蔴嫲𦺙䔧蕳䔖枿蘖\"],[\"8fa1\",\"𨘥𨘻藁𧂈蘂𡖂𧃍䕫䕪蘨㙈𡢢号𧎚虾蝱𪃸蟮𢰧螱蟚蠏噡虬桖䘏衅衆𧗠𣶹𧗤衞袜䙛袴袵揁装睷𧜏覇覊覦覩覧覼𨨥觧𧤤𧪽誜瞓釾誐𧩙竩𧬺𣾏䜓𧬸煼謌謟𥐰𥕥謿譌譍誩𤩺讐讛誯𡛟䘕衏貛𧵔𧶏貫㜥𧵓賖𧶘𧶽贒贃𡤐賛灜贑𤳉㻐起\"],[\"9040\",\"趩𨀂𡀔𤦊㭼𨆼𧄌竧躭躶軃鋔輙輭𨍥𨐒辥錃𪊟𠩐辳䤪𨧞𨔽𣶻廸𣉢迹𪀔𨚼𨔁𢌥㦀𦻗逷𨔼𧪾遡𨕬𨘋邨𨜓郄𨛦邮都酧㫰醩釄粬𨤳𡺉鈎沟鉁鉢𥖹銹𨫆𣲛𨬌𥗛\"],[\"90a1\",\"𠴱錬鍫𨫡𨯫炏嫃𨫢𨫥䥥鉄𨯬𨰹𨯿鍳鑛躼閅閦鐦閠濶䊹𢙺𨛘𡉼𣸮䧟氜陻隖䅬隣𦻕懚隶磵𨫠隽双䦡𦲸𠉴𦐐𩂯𩃥𤫑𡤕𣌊霱虂霶䨏䔽䖅𤫩灵孁霛靜𩇕靗孊𩇫靟鐥僐𣂷𣂼鞉鞟鞱鞾韀韒韠𥑬韮琜𩐳響韵𩐝𧥺䫑頴頳顋顦㬎𧅵㵑𠘰𤅜\"],[\"9140\",\"𥜆飊颷飈飇䫿𦴧𡛓喰飡飦飬鍸餹𤨩䭲𩡗𩤅駵騌騻騐驘𥜥㛄𩂱𩯕髠髢𩬅髴䰎鬔鬭𨘀倴鬴𦦨㣃𣁽魐魀𩴾婅𡡣鮎𤉋鰂鯿鰌𩹨鷔𩾷𪆒𪆫𪃡𪄣𪇟鵾鶃𪄴鸎梈\"],[\"91a1\",\"鷄𢅛𪆓𪈠𡤻𪈳鴹𪂹𪊴麐麕麞麢䴴麪麯𤍤黁㭠㧥㴝伲㞾𨰫鼂鼈䮖鐤𦶢鼗鼖鼹嚟嚊齅馸𩂋韲葿齢齩竜龎爖䮾𤥵𤦻煷𤧸𤍈𤩑玞𨯚𡣺禟𨥾𨸶鍩鏳𨩄鋬鎁鏋𨥬𤒹爗㻫睲穃烐𤑳𤏸煾𡟯炣𡢾𣖙㻇𡢅𥐯𡟸㜢𡛻𡠹㛡𡝴𡣑𥽋㜣𡛀坛𤨥𡏾𡊨\"],[\"9240\",\"𡏆𡒶蔃𣚦蔃葕𤦔𧅥𣸱𥕜𣻻𧁒䓴𣛮𩦝𦼦柹㜳㰕㷧塬𡤢栐䁗𣜿𤃡𤂋𤄏𦰡哋嚞𦚱嚒𠿟𠮨𠸍鏆𨬓鎜仸儫㠙𤐶亼𠑥𠍿佋侊𥙑婨𠆫𠏋㦙𠌊𠐔㐵伩𠋀𨺳𠉵諚𠈌亘\"],[\"92a1\",\"働儍侢伃𤨎𣺊佂倮偬傁俌俥偘僼兙兛兝兞湶𣖕𣸹𣺿浲𡢄𣺉冨凃𠗠䓝𠒣𠒒𠒑赺𨪜𠜎剙劤𠡳勡鍮䙺熌𤎌𠰠𤦬𡃤槑𠸝瑹㻞璙琔瑖玘䮎𤪼𤂍叐㖄爏𤃉喴𠍅响𠯆圝鉝雴鍦埝垍坿㘾壋媙𨩆𡛺𡝯𡜐娬妸銏婾嫏娒𥥆𡧳𡡡𤊕㛵洅瑃娡𥺃\"],[\"9340\",\"媁𨯗𠐓鏠璌𡌃焅䥲鐈𨧻鎽㞠尞岞幞幈𡦖𡥼𣫮廍孏𡤃𡤄㜁𡢠㛝𡛾㛓脪𨩇𡶺𣑲𨦨弌弎𡤧𡞫婫𡜻孄蘔𧗽衠恾𢡠𢘫忛㺸𢖯𢖾𩂈𦽳懀𠀾𠁆𢘛憙憘恵𢲛𢴇𤛔𩅍\"],[\"93a1\",\"摱𤙥𢭪㨩𢬢𣑐𩣪𢹸挷𪑛撶挱揑𤧣𢵧护𢲡搻敫楲㯴𣂎𣊭𤦉𣊫唍𣋠𡣙𩐿曎𣊉𣆳㫠䆐𥖄𨬢𥖏𡛼𥕛𥐥磮𣄃𡠪𣈴㑤𣈏𣆂𤋉暎𦴤晫䮓昰𧡰𡷫晣𣋒𣋡昞𥡲㣑𣠺𣞼㮙𣞢𣏾瓐㮖枏𤘪梶栞㯄檾㡣𣟕𤒇樳橒櫉欅𡤒攑梘橌㯗橺歗𣿀𣲚鎠鋲𨯪𨫋\"],[\"9440\",\"銉𨀞𨧜鑧涥漋𤧬浧𣽿㶏渄𤀼娽渊塇洤硂焻𤌚𤉶烱牐犇犔𤞏𤜥兹𤪤𠗫瑺𣻸𣙟𤩊𤤗𥿡㼆㺱𤫟𨰣𣼵悧㻳瓌琼鎇琷䒟𦷪䕑疃㽣𤳙𤴆㽘畕癳𪗆㬙瑨𨫌𤦫𤦎㫻\"],[\"94a1\",\"㷍𤩎㻿𤧅𤣳釺圲鍂𨫣𡡤僟𥈡𥇧睸𣈲眎眏睻𤚗𣞁㩞𤣰琸璛㺿𤪺𤫇䃈𤪖𦆮錇𥖁砞碍碈磒珐祙𧝁𥛣䄎禛蒖禥樭𣻺稺秴䅮𡛦䄲鈵秱𠵌𤦌𠊙𣶺𡝮㖗啫㕰㚪𠇔𠰍竢婙𢛵𥪯𥪜娍𠉛磰娪𥯆竾䇹籝籭䈑𥮳𥺼𥺦糍𤧹𡞰粎籼粮檲緜縇緓罎𦉡\"],[\"9540\",\"𦅜𧭈綗𥺂䉪𦭵𠤖柖𠁎𣗏埄𦐒𦏸𤥢翝笧𠠬𥫩𥵃笌𥸎駦虅驣樜𣐿㧢𤧷𦖭騟𦖠蒀𧄧𦳑䓪脷䐂胆脉腂𦞴飃𦩂艢艥𦩑葓𦶧蘐𧈛媆䅿𡡀嬫𡢡嫤𡣘蚠蜨𣶏蠭𧐢娂\"],[\"95a1\",\"衮佅袇袿裦襥襍𥚃襔𧞅𧞄𨯵𨯙𨮜𨧹㺭蒣䛵䛏㟲訽訜𩑈彍鈫𤊄旔焩烄𡡅鵭貟賩𧷜妚矃姰䍮㛔踪躧𤰉輰轊䋴汘澻𢌡䢛潹溋𡟚鯩㚵𤤯邻邗啱䤆醻鐄𨩋䁢𨫼鐧𨰝𨰻蓥訫閙閧閗閖𨴴瑅㻂𤣿𤩂𤏪㻧𣈥随𨻧𨹦𨹥㻌𤧭𤩸𣿮琒瑫㻼靁𩂰\"],[\"9640\",\"桇䨝𩂓𥟟靝鍨𨦉𨰦𨬯𦎾銺嬑譩䤼珹𤈛鞛靱餸𠼦巁𨯅𤪲頟𩓚鋶𩗗釥䓀𨭐𤩧𨭤飜𨩅㼀鈪䤥萔餻饍𧬆㷽馛䭯馪驜𨭥𥣈檏騡嫾騯𩣱䮐𩥈馼䮽䮗鍽塲𡌂堢𤦸\"],[\"96a1\",\"𡓨硄𢜟𣶸棅㵽鑘㤧慐𢞁𢥫愇鱏鱓鱻鰵鰐魿鯏𩸭鮟𪇵𪃾鴡䲮𤄄鸘䲰鴌𪆴𪃭𪃳𩤯鶥蒽𦸒𦿟𦮂藼䔳𦶤𦺄𦷰萠藮𦸀𣟗𦁤秢𣖜𣙀䤭𤧞㵢鏛銾鍈𠊿碹鉷鑍俤㑀遤𥕝砽硔碶硋𡝗𣇉𤥁㚚佲濚濙瀞瀞吔𤆵垻壳垊鴖埗焴㒯𤆬燫𦱀𤾗嬨𡞵𨩉\"],[\"9740\",\"愌嫎娋䊼𤒈㜬䭻𨧼鎻鎸𡣖𠼝葲𦳀𡐓𤋺𢰦𤏁妔𣶷𦝁綨𦅛𦂤𤦹𤦋𨧺鋥珢㻩璴𨭣𡢟㻡𤪳櫘珳珻㻖𤨾𤪔𡟙𤩦𠎧𡐤𤧥瑈𤤖炥𤥶銄珦鍟𠓾錱𨫎𨨖鎆𨯧𥗕䤵𨪂煫\"],[\"97a1\",\"𤥃𠳿嚤𠘚𠯫𠲸唂秄𡟺緾𡛂𤩐𡡒䔮鐁㜊𨫀𤦭妰𡢿𡢃𧒄媡㛢𣵛㚰鉟婹𨪁𡡢鍴㳍𠪴䪖㦊僴㵩㵌𡎜煵䋻𨈘渏𩃤䓫浗𧹏灧沯㳖𣿭𣸭渂漌㵯𠏵畑㚼㓈䚀㻚䡱姄鉮䤾轁𨰜𦯀堒埈㛖𡑒烾𤍢𤩱𢿣𡊰𢎽梹楧𡎘𣓥𧯴𣛟𨪃𣟖𣏺𤲟樚𣚭𦲷萾䓟䓎\"],[\"9840\",\"𦴦𦵑𦲂𦿞漗𧄉茽𡜺菭𦲀𧁓𡟛妉媂𡞳婡婱𡤅𤇼㜭姯𡜼㛇熎鎐暚𤊥婮娫𤊓樫𣻹𧜶𤑛𤋊焝𤉙𨧡侰𦴨峂𤓎𧹍𤎽樌𤉖𡌄炦焳𤏩㶥泟勇𤩏繥姫崯㷳彜𤩝𡟟綤萦\"],[\"98a1\",\"咅𣫺𣌀𠈔坾𠣕𠘙㿥𡾞𪊶瀃𩅛嵰玏糓𨩙𩐠俈翧狍猐𧫴猸猹𥛶獁獈㺩𧬘遬燵𤣲珡臶㻊県㻑沢国琙琞琟㻢㻰㻴㻺瓓㼎㽓畂畭畲疍㽼痈痜㿀癍㿗癴㿜発𤽜熈嘣覀塩䀝睃䀹条䁅㗛瞘䁪䁯属瞾矋売砘点砜䂨砹硇硑硦葈𥔵礳栃礲䄃\"],[\"9940\",\"䄉禑禙辻稆込䅧窑䆲窼艹䇄竏竛䇏両筢筬筻簒簛䉠䉺类粜䊌粸䊔糭输烀𠳏総緔緐緽羮羴犟䎗耠耥笹耮耱联㷌垴炠肷胩䏭脌猪脎脒畠脔䐁㬹腖腙腚\"],[\"99a1\",\"䐓堺腼膄䐥膓䐭膥埯臁臤艔䒏芦艶苊苘苿䒰荗险榊萅烵葤惣蒈䔄蒾蓡蓸蔐蔸蕒䔻蕯蕰藠䕷虲蚒蚲蛯际螋䘆䘗袮裿褤襇覑𧥧訩訸誔誴豑賔賲贜䞘塟跃䟭仮踺嗘坔蹱嗵躰䠷軎転軤軭軲辷迁迊迌逳駄䢭飠鈓䤞鈨鉘鉫銱銮銿\"],[\"9a40\",\"鋣鋫鋳鋴鋽鍃鎄鎭䥅䥑麿鐗匁鐝鐭鐾䥪鑔鑹锭関䦧间阳䧥枠䨤靀䨵鞲韂噔䫤惨颹䬙飱塄餎餙冴餜餷饂饝饢䭰駅䮝騼鬏窃魩鮁鯝鯱鯴䱭鰠㝯𡯂鵉鰺\"],[\"9aa1\",\"黾噐鶓鶽鷀鷼银辶鹻麬麱麽黆铜黢黱黸竈齄𠂔𠊷𠎠椚铃妬𠓗塀铁㞹𠗕𠘕𠙶𡚺块煳𠫂𠫍𠮿呪吆𠯋咞𠯻𠰻𠱓𠱥𠱼惧𠲍噺𠲵𠳝𠳭𠵯𠶲𠷈楕鰯螥𠸄𠸎𠻗𠾐𠼭𠹳尠𠾼帋𡁜𡁏𡁶朞𡁻𡂈𡂖㙇𡂿𡃓𡄯𡄻卤蒭𡋣𡍵𡌶讁𡕷𡘙𡟃𡟇乸炻𡠭𡥪\"],[\"9b40\",\"𡨭𡩅𡰪𡱰𡲬𡻈拃𡻕𡼕熘桕𢁅槩㛈𢉼𢏗𢏺𢜪𢡱𢥏苽𢥧𢦓𢫕覥𢫨辠𢬎鞸𢬿顇骽𢱌\"],[\"9b62\",\"𢲈𢲷𥯨𢴈𢴒𢶷𢶕𢹂𢽴𢿌𣀳𣁦𣌟𣏞徱晈暿𧩹𣕧𣗳爁𤦺矗𣘚𣜖纇𠍆墵朎\"],[\"9ba1\",\"椘𣪧𧙗𥿢𣸑𣺹𧗾𢂚䣐䪸𤄙𨪚𤋮𤌍𤀻𤌴𤎖𤩅𠗊凒𠘑妟𡺨㮾𣳿𤐄𤓖垈𤙴㦛𤜯𨗨𩧉㝢𢇃譞𨭎駖𤠒𤣻𤨕爉𤫀𠱸奥𤺥𤾆𠝹軚𥀬劏圿煱𥊙𥐙𣽊𤪧喼𥑆𥑮𦭒釔㑳𥔿𧘲𥕞䜘𥕢𥕦𥟇𤤿𥡝偦㓻𣏌惞𥤃䝼𨥈𥪮𥮉𥰆𡶐垡煑澶𦄂𧰒遖𦆲𤾚譢𦐂𦑊\"],[\"9c40\",\"嵛𦯷輶𦒄𡤜諪𤧶𦒈𣿯𦔒䯀𦖿𦚵𢜛鑥𥟡憕娧晉侻嚹𤔡𦛼乪𤤴陖涏𦲽㘘襷𦞙𦡮𦐑𦡞營𦣇筂𩃀𠨑𦤦鄄𦤹穅鷰𦧺騦𦨭㙟𦑩𠀡禃𦨴𦭛崬𣔙菏𦮝䛐𦲤画补𦶮墶\"],[\"9ca1\",\"㜜𢖍𧁋𧇍㱔𧊀𧊅銁𢅺𧊋錰𧋦𤧐氹钟𧑐𠻸蠧裵𢤦𨑳𡞱溸𤨪𡠠㦤㚹尐秣䔿暶𩲭𩢤襃𧟌𧡘囖䃟𡘊㦡𣜯𨃨𡏅熭荦𧧝𩆨婧䲷𧂯𨦫𧧽𧨊𧬋𧵦𤅺筃祾𨀉澵𪋟樃𨌘厢𦸇鎿栶靝𨅯𨀣𦦵𡏭𣈯𨁈嶅𨰰𨂃圕頣𨥉嶫𤦈斾槕叒𤪥𣾁㰑朶𨂐𨃴𨄮𡾡𨅏\"],[\"9d40\",\"𨆉𨆯𨈚𨌆𨌯𨎊㗊𨑨𨚪䣺揦𨥖砈鉕𨦸䏲𨧧䏟𨧨𨭆𨯔姸𨰉輋𨿅𩃬筑𩄐𩄼㷷𩅞𤫊运犏嚋𩓧𩗩𩖰𩖸𩜲𩣑𩥉𩥪𩧃𩨨𩬎𩵚𩶛纟𩻸𩼣䲤镇𪊓熢𪋿䶑递𪗋䶜𠲜达嗁\"],[\"9da1\",\"辺𢒰边𤪓䔉繿潖檱仪㓤𨬬𧢝㜺躀𡟵𨀤𨭬𨮙𧨾𦚯㷫𧙕𣲷𥘵𥥖亚𥺁𦉘嚿𠹭踎孭𣺈𤲞揞拐𡟶𡡻攰嘭𥱊吚𥌑㷆𩶘䱽嘢嘞罉𥻘奵𣵀蝰东𠿪𠵉𣚺脗鵞贘瘻鱅癎瞹鍅吲腈苷嘥脲萘肽嗪祢噃吖𠺝㗎嘅嗱曱𨋢㘭甴嗰喺咗啲𠱁𠲖廐𥅈𠹶𢱢\"],[\"9e40\",\"𠺢麫絚嗞𡁵抝靭咔賍燶酶揼掹揾啩𢭃鱲𢺳冚㓟𠶧冧呍唞唓癦踭𦢊疱肶蠄螆裇膶萜𡃁䓬猄𤜆宐茋𦢓噻𢛴𧴯𤆣𧵳𦻐𧊶酰𡇙鈈𣳼𪚩𠺬𠻹牦𡲢䝎𤿂𧿹𠿫䃺\"],[\"9ea1\",\"鱝攟𢶠䣳𤟠𩵼𠿬𠸊恢𧖣𠿭\"],[\"9ead\",\"𦁈𡆇熣纎鵐业丄㕷嬍沲卧㚬㧜卽㚥𤘘墚𤭮舭呋垪𥪕𠥹\"],[\"9ec5\",\"㩒𢑥獴𩺬䴉鯭𣳾𩼰䱛𤾩𩖞𩿞葜𣶶𧊲𦞳𣜠挮紥𣻷𣸬㨪逈勌㹴㙺䗩𠒎癀嫰𠺶硺𧼮墧䂿噼鮋嵴癔𪐴麅䳡痹㟻愙𣃚𤏲\"],[\"9ef5\",\"噝𡊩垧𤥣𩸆刴𧂮㖭汊鵼\"],[\"9f40\",\"籖鬹埞𡝬屓擓𩓐𦌵𧅤蚭𠴨𦴢𤫢𠵱\"],[\"9f4f\",\"凾𡼏嶎霃𡷑麁遌笟鬂峑箣扨挵髿篏鬪籾鬮籂粆鰕篼鬉鼗鰛𤤾齚啳寃俽麘俲剠㸆勑坧偖妷帒韈鶫轜呩鞴饀鞺匬愰\"],[\"9fa1\",\"椬叚鰊鴂䰻陁榀傦畆𡝭駚剳\"],[\"9fae\",\"酙隁酜\"],[\"9fb2\",\"酑𨺗捿𦴣櫊嘑醎畺抅𠏼獏籰𥰡𣳽\"],[\"9fc1\",\"𤤙盖鮝个𠳔莾衂\"],[\"9fc9\",\"届槀僭坺刟巵从氱𠇲伹咜哚劚趂㗾弌㗳\"],[\"9fdb\",\"歒酼龥鮗頮颴骺麨麄煺笔\"],[\"9fe7\",\"毺蠘罸\"],[\"9feb\",\"嘠𪙊蹷齓\"],[\"9ff0\",\"跔蹏鸜踁抂𨍽踨蹵竓𤩷稾磘泪詧瘇\"],[\"a040\",\"𨩚鼦泎蟖痃𪊲硓咢贌狢獱謭猂瓱賫𤪻蘯徺袠䒷\"],[\"a055\",\"𡠻𦸅\"],[\"a058\",\"詾𢔛\"],[\"a05b\",\"惽癧髗鵄鍮鮏蟵\"],[\"a063\",\"蠏賷猬霡鮰㗖犲䰇籑饊𦅙慙䰄麖慽\"],[\"a073\",\"坟慯抦戹拎㩜懢厪𣏵捤栂㗒\"],[\"a0a1\",\"嵗𨯂迚𨸹\"],[\"a0a6\",\"僙𡵆礆匲阸𠼻䁥\"],[\"a0ae\",\"矾\"],[\"a0b0\",\"糂𥼚糚稭聦聣絍甅瓲覔舚朌聢𧒆聛瓰脃眤覉𦟌畓𦻑螩蟎臈螌詉貭譃眫瓸蓚㘵榲趦\"],[\"a0d4\",\"覩瑨涹蟁𤀑瓧㷛煶悤憜㳑煢恷\"],[\"a0e2\",\"罱𨬭牐惩䭾删㰘𣳇𥻗𧙖𥔱𡥄𡋾𩤃𦷜𧂭峁𦆭𨨏𣙷𠃮𦡆𤼎䕢嬟𦍌齐麦𦉫\"],[\"a3c0\",\"␀\",31,\"␡\"],[\"c6a1\",\"①\",9,\"⑴\",9,\"ⅰ\",9,\"丶丿亅亠冂冖冫勹匸卩厶夊宀巛⼳广廴彐彡攴无疒癶辵隶¨ˆヽヾゝゞ〃仝々〆〇ー［］✽ぁ\",23],[\"c740\",\"す\",58,\"ァアィイ\"],[\"c7a1\",\"ゥ\",81,\"А\",5,\"ЁЖ\",4],[\"c840\",\"Л\",26,\"ёж\",25,\"⇧↸↹㇏𠃌乚𠂊刂䒑\"],[\"c8a1\",\"龰冈龱𧘇\"],[\"c8cd\",\"￢￤＇＂㈱№℡゛゜⺀⺄⺆⺇⺈⺊⺌⺍⺕⺜⺝⺥⺧⺪⺬⺮⺶⺼⺾⻆⻊⻌⻍⻏⻖⻗⻞⻣\"],[\"c8f5\",\"ʃɐɛɔɵœøŋʊɪ\"],[\"f9fe\",\"￭\"],[\"fa40\",\"𠕇鋛𠗟𣿅蕌䊵珯况㙉𤥂𨧤鍄𡧛苮𣳈砼杄拟𤤳𨦪𠊠𦮳𡌅侫𢓭倈𦴩𧪄𣘀𤪱𢔓倩𠍾徤𠎀𠍇滛𠐟偽儁㑺儎顬㝃萖𤦤𠒇兠𣎴兪𠯿𢃼𠋥𢔰𠖎𣈳𡦃宂蝽𠖳𣲙冲冸\"],[\"faa1\",\"鴴凉减凑㳜凓𤪦决凢卂凭菍椾𣜭彻刋刦刼劵剗劔効勅簕蕂勠蘍𦬓包𨫞啉滙𣾀𠥔𣿬匳卄𠯢泋𡜦栛珕恊㺪㣌𡛨燝䒢卭却𨚫卾卿𡖖𡘓矦厓𨪛厠厫厮玧𥝲㽙玜叁叅汉义埾叙㪫𠮏叠𣿫𢶣叶𠱷吓灹唫晗浛呭𦭓𠵴啝咏咤䞦𡜍𠻝㶴𠵍\"],[\"fb40\",\"𨦼𢚘啇䳭启琗喆喩嘅𡣗𤀺䕒𤐵暳𡂴嘷曍𣊊暤暭噍噏磱囱鞇叾圀囯园𨭦㘣𡉏坆𤆥汮炋坂㚱𦱾埦𡐖堃𡑔𤍣堦𤯵塜墪㕡壠壜𡈼壻寿坃𪅐𤉸鏓㖡够梦㛃湙\"],[\"fba1\",\"𡘾娤啓𡚒蔅姉𠵎𦲁𦴪𡟜姙𡟻𡞲𦶦浱𡠨𡛕姹𦹅媫婣㛦𤦩婷㜈媖瑥嫓𦾡𢕔㶅𡤑㜲𡚸広勐孶斈孼𧨎䀄䡝𠈄寕慠𡨴𥧌𠖥寳宝䴐尅𡭄尓珎尔𡲥𦬨屉䣝岅峩峯嶋𡷹𡸷崐崘嵆𡺤岺巗苼㠭𤤁𢁉𢅳芇㠶㯂帮檊幵幺𤒼𠳓厦亷廐厨𡝱帉廴𨒂\"],[\"fc40\",\"廹廻㢠廼栾鐛弍𠇁弢㫞䢮𡌺强𦢈𢏐彘𢑱彣鞽𦹮彲鍀𨨶徧嶶㵟𥉐𡽪𧃸𢙨釖𠊞𨨩怱暅𡡷㥣㷇㘹垐𢞴祱㹀悞悤悳𤦂𤦏𧩓璤僡媠慤萤慂慈𦻒憁凴𠙖憇宪𣾷\"],[\"fca1\",\"𢡟懓𨮝𩥝懐㤲𢦀𢣁怣慜攞掋𠄘担𡝰拕𢸍捬𤧟㨗搸揸𡎎𡟼撐澊𢸶頔𤂌𥜝擡擥鑻㩦携㩗敍漖𤨨𤨣斅敭敟𣁾斵𤥀䬷旑䃘𡠩无旣忟𣐀昘𣇷𣇸晄𣆤𣆥晋𠹵晧𥇦晳晴𡸽𣈱𨗴𣇈𥌓矅𢣷馤朂𤎜𤨡㬫槺𣟂杞杧杢𤇍𩃭柗䓩栢湐鈼栁𣏦𦶠桝\"],[\"fd40\",\"𣑯槡樋𨫟楳棃𣗍椁椀㴲㨁𣘼㮀枬楡𨩊䋼椶榘㮡𠏉荣傐槹𣙙𢄪橅𣜃檝㯳枱櫈𩆜㰍欝𠤣惞欵歴𢟍溵𣫛𠎵𡥘㝀吡𣭚毡𣻼毜氷𢒋𤣱𦭑汚舦汹𣶼䓅𣶽𤆤𤤌𤤀\"],[\"fda1\",\"𣳉㛥㳫𠴲鮃𣇹𢒑羏样𦴥𦶡𦷫涖浜湼漄𤥿𤂅𦹲蔳𦽴凇沜渝萮𨬡港𣸯瑓𣾂秌湏媑𣁋濸㜍澝𣸰滺𡒗𤀽䕕鏰潄潜㵎潴𩅰㴻澟𤅄濓𤂑𤅕𤀹𣿰𣾴𤄿凟𤅖𤅗𤅀𦇝灋灾炧炁烌烕烖烟䄄㷨熴熖𤉷焫煅媈煊煮岜𤍥煏鍢𤋁焬𤑚𤨧𤨢熺𨯨炽爎\"],[\"fe40\",\"鑂爕夑鑃爤鍁𥘅爮牀𤥴梽牕牗㹕𣁄栍漽犂猪猫𤠣𨠫䣭𨠄猨献珏玪𠰺𦨮珉瑉𤇢𡛧𤨤昣㛅𤦷𤦍𤧻珷琕椃𤨦琹𠗃㻗瑜𢢭瑠𨺲瑇珤瑶莹瑬㜰瑴鏱樬璂䥓𤪌\"],[\"fea1\",\"𤅟𤩹𨮏孆𨰃𡢞瓈𡦈甎瓩甞𨻙𡩋寗𨺬鎅畍畊畧畮𤾂㼄𤴓疎瑝疞疴瘂瘬癑癏癯癶𦏵皐臯㟸𦤑𦤎皡皥皷盌𦾟葢𥂝𥅽𡸜眞眦着撯𥈠睘𣊬瞯𨥤𨥨𡛁矴砉𡍶𤨒棊碯磇磓隥礮𥗠磗礴碱𧘌辸袄𨬫𦂃𢘜禆褀椂禀𥡗禝𧬹礼禩渪𧄦㺨秆𩄍秔\"]]\n\n/***/ }),\n/* 185 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar Buffer = __webpack_require__(1).Buffer,\n    Transform = __webpack_require__(15).Transform;\n\n\n// == Exports ==================================================================\nmodule.exports = function(iconv) {\n    \n    // Additional Public API.\n    iconv.encodeStream = function encodeStream(encoding, options) {\n        return new IconvLiteEncoderStream(iconv.getEncoder(encoding, options), options);\n    }\n\n    iconv.decodeStream = function decodeStream(encoding, options) {\n        return new IconvLiteDecoderStream(iconv.getDecoder(encoding, options), options);\n    }\n\n    iconv.supportsStreams = true;\n\n\n    // Not published yet.\n    iconv.IconvLiteEncoderStream = IconvLiteEncoderStream;\n    iconv.IconvLiteDecoderStream = IconvLiteDecoderStream;\n    iconv._collect = IconvLiteDecoderStream.prototype.collect;\n};\n\n\n// == Encoder stream =======================================================\nfunction IconvLiteEncoderStream(conv, options) {\n    this.conv = conv;\n    options = options || {};\n    options.decodeStrings = false; // We accept only strings, so we don't need to decode them.\n    Transform.call(this, options);\n}\n\nIconvLiteEncoderStream.prototype = Object.create(Transform.prototype, {\n    constructor: { value: IconvLiteEncoderStream }\n});\n\nIconvLiteEncoderStream.prototype._transform = function(chunk, encoding, done) {\n    if (typeof chunk != 'string')\n        return done(new Error(\"Iconv encoding stream needs strings as its input.\"));\n    try {\n        var res = this.conv.write(chunk);\n        if (res && res.length) this.push(res);\n        done();\n    }\n    catch (e) {\n        done(e);\n    }\n}\n\nIconvLiteEncoderStream.prototype._flush = function(done) {\n    try {\n        var res = this.conv.end();\n        if (res && res.length) this.push(res);\n        done();\n    }\n    catch (e) {\n        done(e);\n    }\n}\n\nIconvLiteEncoderStream.prototype.collect = function(cb) {\n    var chunks = [];\n    this.on('error', cb);\n    this.on('data', function(chunk) { chunks.push(chunk); });\n    this.on('end', function() {\n        cb(null, Buffer.concat(chunks));\n    });\n    return this;\n}\n\n\n// == Decoder stream =======================================================\nfunction IconvLiteDecoderStream(conv, options) {\n    this.conv = conv;\n    options = options || {};\n    options.encoding = this.encoding = 'utf8'; // We output strings.\n    Transform.call(this, options);\n}\n\nIconvLiteDecoderStream.prototype = Object.create(Transform.prototype, {\n    constructor: { value: IconvLiteDecoderStream }\n});\n\nIconvLiteDecoderStream.prototype._transform = function(chunk, encoding, done) {\n    if (!Buffer.isBuffer(chunk))\n        return done(new Error(\"Iconv decoding stream needs buffers as its input.\"));\n    try {\n        var res = this.conv.write(chunk);\n        if (res && res.length) this.push(res, this.encoding);\n        done();\n    }\n    catch (e) {\n        done(e);\n    }\n}\n\nIconvLiteDecoderStream.prototype._flush = function(done) {\n    try {\n        var res = this.conv.end();\n        if (res && res.length) this.push(res, this.encoding);                \n        done();\n    }\n    catch (e) {\n        done(e);\n    }\n}\n\nIconvLiteDecoderStream.prototype.collect = function(cb) {\n    var res = '';\n    this.on('error', cb);\n    this.on('data', function(chunk) { res += chunk; });\n    this.on('end', function() {\n        cb(null, res);\n    });\n    return this;\n}\n\n\n\n/***/ }),\n/* 186 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar Buffer = __webpack_require__(1).Buffer;\n\n// == Extend Node primitives to use iconv-lite =================================\n\nmodule.exports = function (iconv) {\n    var original = undefined; // Place to keep original methods.\n\n    // Node authors rewrote Buffer internals to make it compatible with\n    // Uint8Array and we cannot patch key functions since then.\n    iconv.supportsNodeEncodingsExtension = !(new Buffer(0) instanceof Uint8Array);\n\n    iconv.extendNodeEncodings = function extendNodeEncodings() {\n        if (original) return;\n        original = {};\n\n        if (!iconv.supportsNodeEncodingsExtension) {\n            console.error(\"ACTION NEEDED: require('iconv-lite').extendNodeEncodings() is not supported in your version of Node\");\n            console.error(\"See more info at https://github.com/ashtuchkin/iconv-lite/wiki/Node-v4-compatibility\");\n            return;\n        }\n\n        var nodeNativeEncodings = {\n            'hex': true, 'utf8': true, 'utf-8': true, 'ascii': true, 'binary': true, \n            'base64': true, 'ucs2': true, 'ucs-2': true, 'utf16le': true, 'utf-16le': true,\n        };\n\n        Buffer.isNativeEncoding = function(enc) {\n            return enc && nodeNativeEncodings[enc.toLowerCase()];\n        }\n\n        // -- SlowBuffer -----------------------------------------------------------\n        var SlowBuffer = __webpack_require__(1).SlowBuffer;\n\n        original.SlowBufferToString = SlowBuffer.prototype.toString;\n        SlowBuffer.prototype.toString = function(encoding, start, end) {\n            encoding = String(encoding || 'utf8').toLowerCase();\n\n            // Use native conversion when possible\n            if (Buffer.isNativeEncoding(encoding))\n                return original.SlowBufferToString.call(this, encoding, start, end);\n\n            // Otherwise, use our decoding method.\n            if (typeof start == 'undefined') start = 0;\n            if (typeof end == 'undefined') end = this.length;\n            return iconv.decode(this.slice(start, end), encoding);\n        }\n\n        original.SlowBufferWrite = SlowBuffer.prototype.write;\n        SlowBuffer.prototype.write = function(string, offset, length, encoding) {\n            // Support both (string, offset, length, encoding)\n            // and the legacy (string, encoding, offset, length)\n            if (isFinite(offset)) {\n                if (!isFinite(length)) {\n                    encoding = length;\n                    length = undefined;\n                }\n            } else {  // legacy\n                var swap = encoding;\n                encoding = offset;\n                offset = length;\n                length = swap;\n            }\n\n            offset = +offset || 0;\n            var remaining = this.length - offset;\n            if (!length) {\n                length = remaining;\n            } else {\n                length = +length;\n                if (length > remaining) {\n                    length = remaining;\n                }\n            }\n            encoding = String(encoding || 'utf8').toLowerCase();\n\n            // Use native conversion when possible\n            if (Buffer.isNativeEncoding(encoding))\n                return original.SlowBufferWrite.call(this, string, offset, length, encoding);\n\n            if (string.length > 0 && (length < 0 || offset < 0))\n                throw new RangeError('attempt to write beyond buffer bounds');\n\n            // Otherwise, use our encoding method.\n            var buf = iconv.encode(string, encoding);\n            if (buf.length < length) length = buf.length;\n            buf.copy(this, offset, 0, length);\n            return length;\n        }\n\n        // -- Buffer ---------------------------------------------------------------\n\n        original.BufferIsEncoding = Buffer.isEncoding;\n        Buffer.isEncoding = function(encoding) {\n            return Buffer.isNativeEncoding(encoding) || iconv.encodingExists(encoding);\n        }\n\n        original.BufferByteLength = Buffer.byteLength;\n        Buffer.byteLength = SlowBuffer.byteLength = function(str, encoding) {\n            encoding = String(encoding || 'utf8').toLowerCase();\n\n            // Use native conversion when possible\n            if (Buffer.isNativeEncoding(encoding))\n                return original.BufferByteLength.call(this, str, encoding);\n\n            // Slow, I know, but we don't have a better way yet.\n            return iconv.encode(str, encoding).length;\n        }\n\n        original.BufferToString = Buffer.prototype.toString;\n        Buffer.prototype.toString = function(encoding, start, end) {\n            encoding = String(encoding || 'utf8').toLowerCase();\n\n            // Use native conversion when possible\n            if (Buffer.isNativeEncoding(encoding))\n                return original.BufferToString.call(this, encoding, start, end);\n\n            // Otherwise, use our decoding method.\n            if (typeof start == 'undefined') start = 0;\n            if (typeof end == 'undefined') end = this.length;\n            return iconv.decode(this.slice(start, end), encoding);\n        }\n\n        original.BufferWrite = Buffer.prototype.write;\n        Buffer.prototype.write = function(string, offset, length, encoding) {\n            var _offset = offset, _length = length, _encoding = encoding;\n            // Support both (string, offset, length, encoding)\n            // and the legacy (string, encoding, offset, length)\n            if (isFinite(offset)) {\n                if (!isFinite(length)) {\n                    encoding = length;\n                    length = undefined;\n                }\n            } else {  // legacy\n                var swap = encoding;\n                encoding = offset;\n                offset = length;\n                length = swap;\n            }\n\n            encoding = String(encoding || 'utf8').toLowerCase();\n\n            // Use native conversion when possible\n            if (Buffer.isNativeEncoding(encoding))\n                return original.BufferWrite.call(this, string, _offset, _length, _encoding);\n\n            offset = +offset || 0;\n            var remaining = this.length - offset;\n            if (!length) {\n                length = remaining;\n            } else {\n                length = +length;\n                if (length > remaining) {\n                    length = remaining;\n                }\n            }\n\n            if (string.length > 0 && (length < 0 || offset < 0))\n                throw new RangeError('attempt to write beyond buffer bounds');\n\n            // Otherwise, use our encoding method.\n            var buf = iconv.encode(string, encoding);\n            if (buf.length < length) length = buf.length;\n            buf.copy(this, offset, 0, length);\n            return length;\n\n            // TODO: Set _charsWritten.\n        }\n\n\n        // -- Readable -------------------------------------------------------------\n        if (iconv.supportsStreams) {\n            var Readable = __webpack_require__(15).Readable;\n\n            original.ReadableSetEncoding = Readable.prototype.setEncoding;\n            Readable.prototype.setEncoding = function setEncoding(enc, options) {\n                // Use our own decoder, it has the same interface.\n                // We cannot use original function as it doesn't handle BOM-s.\n                this._readableState.decoder = iconv.getDecoder(enc, options);\n                this._readableState.encoding = enc;\n            }\n\n            Readable.prototype.collect = iconv._collect;\n        }\n    }\n\n    // Remove iconv-lite Node primitive extensions.\n    iconv.undoExtendNodeEncodings = function undoExtendNodeEncodings() {\n        if (!iconv.supportsNodeEncodingsExtension)\n            return;\n        if (!original)\n            throw new Error(\"require('iconv-lite').undoExtendNodeEncodings(): Nothing to undo; extendNodeEncodings() is not called.\")\n\n        delete Buffer.isNativeEncoding;\n\n        var SlowBuffer = __webpack_require__(1).SlowBuffer;\n\n        SlowBuffer.prototype.toString = original.SlowBufferToString;\n        SlowBuffer.prototype.write = original.SlowBufferWrite;\n\n        Buffer.isEncoding = original.BufferIsEncoding;\n        Buffer.byteLength = original.BufferByteLength;\n        Buffer.prototype.toString = original.BufferToString;\n        Buffer.prototype.write = original.BufferWrite;\n\n        if (iconv.supportsStreams) {\n            var Readable = __webpack_require__(15).Readable;\n\n            Readable.prototype.setEncoding = original.ReadableSetEncoding;\n            delete Readable.prototype.collect;\n        }\n\n        original = undefined;\n    }\n}\n\n\n/***/ }),\n/* 187 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var ArrayT, LazyArray, LazyArrayT, NumberT, inspect, utils,\n    __hasProp = {}.hasOwnProperty,\n    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n  ArrayT = __webpack_require__(93);\n\n  NumberT = __webpack_require__(22).Number;\n\n  utils = __webpack_require__(12);\n\n  inspect = __webpack_require__(49).inspect;\n\n  LazyArrayT = (function(_super) {\n    __extends(LazyArrayT, _super);\n\n    function LazyArrayT() {\n      return LazyArrayT.__super__.constructor.apply(this, arguments);\n    }\n\n    LazyArrayT.prototype.decode = function(stream, parent) {\n      var length, pos, res;\n      pos = stream.pos;\n      length = utils.resolveLength(this.length, stream, parent);\n      if (this.length instanceof NumberT) {\n        parent = {\n          parent: parent,\n          _startOffset: pos,\n          _currentOffset: 0,\n          _length: length\n        };\n      }\n      res = new LazyArray(this.type, length, stream, parent);\n      stream.pos += length * this.type.size(null, parent);\n      return res;\n    };\n\n    LazyArrayT.prototype.size = function(val, ctx) {\n      if (val instanceof LazyArray) {\n        val = val.toArray();\n      }\n      return LazyArrayT.__super__.size.call(this, val, ctx);\n    };\n\n    LazyArrayT.prototype.encode = function(stream, val, ctx) {\n      if (val instanceof LazyArray) {\n        val = val.toArray();\n      }\n      return LazyArrayT.__super__.encode.call(this, stream, val, ctx);\n    };\n\n    return LazyArrayT;\n\n  })(ArrayT);\n\n  LazyArray = (function() {\n    function LazyArray(type, length, stream, ctx) {\n      this.type = type;\n      this.length = length;\n      this.stream = stream;\n      this.ctx = ctx;\n      this.base = this.stream.pos;\n      this.items = [];\n    }\n\n    LazyArray.prototype.get = function(index) {\n      var pos;\n      if (index < 0 || index >= this.length) {\n        return void 0;\n      }\n      if (this.items[index] == null) {\n        pos = this.stream.pos;\n        this.stream.pos = this.base + this.type.size(null, this.ctx) * index;\n        this.items[index] = this.type.decode(this.stream, this.ctx);\n        this.stream.pos = pos;\n      }\n      return this.items[index];\n    };\n\n    LazyArray.prototype.toArray = function() {\n      var i, _i, _ref, _results;\n      _results = [];\n      for (i = _i = 0, _ref = this.length; _i < _ref; i = _i += 1) {\n        _results.push(this.get(i));\n      }\n      return _results;\n    };\n\n    LazyArray.prototype.inspect = function() {\n      return inspect(this.toArray());\n    };\n\n    return LazyArray;\n\n  })();\n\n  module.exports = LazyArrayT;\n\n}).call(this);\n\n\n/***/ }),\n/* 188 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var Bitfield;\n\n  Bitfield = (function() {\n    function Bitfield(type, flags) {\n      this.type = type;\n      this.flags = flags != null ? flags : [];\n    }\n\n    Bitfield.prototype.decode = function(stream) {\n      var flag, i, res, val, _i, _len, _ref;\n      val = this.type.decode(stream);\n      res = {};\n      _ref = this.flags;\n      for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {\n        flag = _ref[i];\n        if (flag != null) {\n          res[flag] = !!(val & (1 << i));\n        }\n      }\n      return res;\n    };\n\n    Bitfield.prototype.size = function() {\n      return this.type.size();\n    };\n\n    Bitfield.prototype.encode = function(stream, keys) {\n      var flag, i, val, _i, _len, _ref;\n      val = 0;\n      _ref = this.flags;\n      for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {\n        flag = _ref[i];\n        if (flag != null) {\n          if (keys[flag]) {\n            val |= 1 << i;\n          }\n        }\n      }\n      return this.type.encode(stream, val);\n    };\n\n    return Bitfield;\n\n  })();\n\n  module.exports = Bitfield;\n\n}).call(this);\n\n\n/***/ }),\n/* 189 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var BooleanT;\n\n  BooleanT = (function() {\n    function BooleanT(type) {\n      this.type = type;\n    }\n\n    BooleanT.prototype.decode = function(stream, parent) {\n      return !!this.type.decode(stream, parent);\n    };\n\n    BooleanT.prototype.size = function(val, parent) {\n      return this.type.size(val, parent);\n    };\n\n    BooleanT.prototype.encode = function(stream, val, parent) {\n      return this.type.encode(stream, +val, parent);\n    };\n\n    return BooleanT;\n\n  })();\n\n  module.exports = BooleanT;\n\n}).call(this);\n\n\n/***/ }),\n/* 190 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var BufferT, NumberT, utils;\n\n  utils = __webpack_require__(12);\n\n  NumberT = __webpack_require__(22).Number;\n\n  BufferT = (function() {\n    function BufferT(length) {\n      this.length = length;\n    }\n\n    BufferT.prototype.decode = function(stream, parent) {\n      var length;\n      length = utils.resolveLength(this.length, stream, parent);\n      return stream.readBuffer(length);\n    };\n\n    BufferT.prototype.size = function(val, parent) {\n      if (!val) {\n        return utils.resolveLength(this.length, null, parent);\n      }\n      return val.length;\n    };\n\n    BufferT.prototype.encode = function(stream, buf, parent) {\n      if (this.length instanceof NumberT) {\n        this.length.encode(stream, buf.length);\n      }\n      return stream.writeBuffer(buf);\n    };\n\n    return BufferT;\n\n  })();\n\n  module.exports = BufferT;\n\n}).call(this);\n\n\n/***/ }),\n/* 191 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var Enum;\n\n  Enum = (function() {\n    function Enum(type, options) {\n      this.type = type;\n      this.options = options != null ? options : [];\n    }\n\n    Enum.prototype.decode = function(stream) {\n      var index;\n      index = this.type.decode(stream);\n      return this.options[index] || index;\n    };\n\n    Enum.prototype.size = function() {\n      return this.type.size();\n    };\n\n    Enum.prototype.encode = function(stream, val) {\n      var index;\n      index = this.options.indexOf(val);\n      if (index === -1) {\n        throw new Error(\"Unknown option in enum: \" + val);\n      }\n      return this.type.encode(stream, index);\n    };\n\n    return Enum;\n\n  })();\n\n  module.exports = Enum;\n\n}).call(this);\n\n\n/***/ }),\n/* 192 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var Optional;\n\n  Optional = (function() {\n    function Optional(type, condition) {\n      this.type = type;\n      this.condition = condition != null ? condition : true;\n    }\n\n    Optional.prototype.decode = function(stream, parent) {\n      var condition;\n      condition = this.condition;\n      if (typeof condition === 'function') {\n        condition = condition.call(parent, parent);\n      }\n      if (condition) {\n        return this.type.decode(stream, parent);\n      }\n    };\n\n    Optional.prototype.size = function(val, parent) {\n      var condition;\n      condition = this.condition;\n      if (typeof condition === 'function') {\n        condition = condition.call(parent, parent);\n      }\n      if (condition) {\n        return this.type.size(val, parent);\n      } else {\n        return 0;\n      }\n    };\n\n    Optional.prototype.encode = function(stream, val, parent) {\n      var condition;\n      condition = this.condition;\n      if (typeof condition === 'function') {\n        condition = condition.call(parent, parent);\n      }\n      if (condition) {\n        return this.type.encode(stream, val, parent);\n      }\n    };\n\n    return Optional;\n\n  })();\n\n  module.exports = Optional;\n\n}).call(this);\n\n\n/***/ }),\n/* 193 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var Reserved, utils;\n\n  utils = __webpack_require__(12);\n\n  Reserved = (function() {\n    function Reserved(type, count) {\n      this.type = type;\n      this.count = count != null ? count : 1;\n    }\n\n    Reserved.prototype.decode = function(stream, parent) {\n      stream.pos += this.size(null, parent);\n      return void 0;\n    };\n\n    Reserved.prototype.size = function(data, parent) {\n      var count;\n      count = utils.resolveLength(this.count, null, parent);\n      return this.type.size() * count;\n    };\n\n    Reserved.prototype.encode = function(stream, val, parent) {\n      return stream.fill(0, this.size(val, parent));\n    };\n\n    return Reserved;\n\n  })();\n\n  module.exports = Reserved;\n\n}).call(this);\n\n\n/***/ }),\n/* 194 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.7.1\n(function() {\n  var NumberT, StringT, utils;\n\n  NumberT = __webpack_require__(22).Number;\n\n  utils = __webpack_require__(12);\n\n  StringT = (function() {\n    function StringT(length, encoding) {\n      this.length = length;\n      this.encoding = encoding != null ? encoding : 'ascii';\n    }\n\n    StringT.prototype.decode = function(stream, parent) {\n      var buffer, encoding, length, pos, string;\n      length = (function() {\n        if (this.length != null) {\n          return utils.resolveLength(this.length, stream, parent);\n        } else {\n          buffer = stream.buffer, length = stream.length, pos = stream.pos;\n          while (pos < length && buffer[pos] !== 0x00) {\n            ++pos;\n          }\n          return pos - stream.pos;\n        }\n      }).call(this);\n      encoding = this.encoding;\n      if (typeof encoding === 'function') {\n        encoding = encoding.call(parent, parent) || 'ascii';\n      }\n      string = stream.readString(length, encoding);\n      if ((this.length == null) && stream.pos < stream.length) {\n        stream.pos++;\n      }\n      return string;\n    };\n\n    StringT.prototype.size = function(val, parent) {\n      var encoding, size;\n      if (!val) {\n        return utils.resolveLength(this.length, null, parent);\n      }\n      encoding = this.encoding;\n      if (typeof encoding === 'function') {\n        encoding = encoding.call(parent != null ? parent.val : void 0, parent != null ? parent.val : void 0) || 'ascii';\n      }\n      if (encoding === 'utf16be') {\n        encoding = 'utf16le';\n      }\n      size = Buffer.byteLength(val, encoding);\n      if (this.length instanceof NumberT) {\n        size += this.length.size();\n      }\n      if (this.length == null) {\n        size++;\n      }\n      return size;\n    };\n\n    StringT.prototype.encode = function(stream, val, parent) {\n      var encoding;\n      encoding = this.encoding;\n      if (typeof encoding === 'function') {\n        encoding = encoding.call(parent != null ? parent.val : void 0, parent != null ? parent.val : void 0) || 'ascii';\n      }\n      if (this.length instanceof NumberT) {\n        this.length.encode(stream, Buffer.byteLength(val, encoding));\n      }\n      stream.writeString(val, encoding);\n      if (this.length == null) {\n        return stream.writeUInt8(0x00);\n      }\n    };\n\n    return StringT;\n\n  })();\n\n  module.exports = StringT;\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 195 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var Struct, VersionedStruct,\n    __hasProp = {}.hasOwnProperty,\n    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n  Struct = __webpack_require__(94);\n\n  VersionedStruct = (function(_super) {\n    __extends(VersionedStruct, _super);\n\n    function VersionedStruct(type, versions) {\n      this.type = type;\n      this.versions = versions != null ? versions : {};\n      if (typeof this.type === 'string') {\n        this.versionGetter = new Function('parent', \"return parent.\" + this.type);\n        this.versionSetter = new Function('parent', 'version', \"return parent.\" + this.type + \" = version\");\n      }\n    }\n\n    VersionedStruct.prototype.decode = function(stream, parent, length) {\n      var fields, res, _ref;\n      if (length == null) {\n        length = 0;\n      }\n      res = this._setup(stream, parent, length);\n      if (typeof this.type === 'string') {\n        res.version = this.versionGetter(parent);\n      } else {\n        res.version = this.type.decode(stream);\n      }\n      if (this.versions.header) {\n        this._parseFields(stream, res, this.versions.header);\n      }\n      fields = this.versions[res.version];\n      if (fields == null) {\n        throw new Error(\"Unknown version \" + res.version);\n      }\n      if (fields instanceof VersionedStruct) {\n        return fields.decode(stream, parent);\n      }\n      this._parseFields(stream, res, fields);\n      if ((_ref = this.process) != null) {\n        _ref.call(res, stream);\n      }\n      return res;\n    };\n\n    VersionedStruct.prototype.size = function(val, parent, includePointers) {\n      var ctx, fields, key, size, type, _ref;\n      if (includePointers == null) {\n        includePointers = true;\n      }\n      if (!val) {\n        throw new Error('Not a fixed size');\n      }\n      ctx = {\n        parent: parent,\n        val: val,\n        pointerSize: 0\n      };\n      size = 0;\n      if (typeof this.type !== 'string') {\n        size += this.type.size(val.version, ctx);\n      }\n      if (this.versions.header) {\n        _ref = this.versions.header;\n        for (key in _ref) {\n          type = _ref[key];\n          if (type.size != null) {\n            size += type.size(val[key], ctx);\n          }\n        }\n      }\n      fields = this.versions[val.version];\n      if (fields == null) {\n        throw new Error(\"Unknown version \" + val.version);\n      }\n      for (key in fields) {\n        type = fields[key];\n        if (type.size != null) {\n          size += type.size(val[key], ctx);\n        }\n      }\n      if (includePointers) {\n        size += ctx.pointerSize;\n      }\n      return size;\n    };\n\n    VersionedStruct.prototype.encode = function(stream, val, parent) {\n      var ctx, fields, i, key, ptr, type, _ref, _ref1;\n      if ((_ref = this.preEncode) != null) {\n        _ref.call(val, stream);\n      }\n      ctx = {\n        pointers: [],\n        startOffset: stream.pos,\n        parent: parent,\n        val: val,\n        pointerSize: 0\n      };\n      ctx.pointerOffset = stream.pos + this.size(val, ctx, false);\n      if (typeof this.type !== 'string') {\n        this.type.encode(stream, val.version);\n      }\n      if (this.versions.header) {\n        _ref1 = this.versions.header;\n        for (key in _ref1) {\n          type = _ref1[key];\n          if (type.encode != null) {\n            type.encode(stream, val[key], ctx);\n          }\n        }\n      }\n      fields = this.versions[val.version];\n      for (key in fields) {\n        type = fields[key];\n        if (type.encode != null) {\n          type.encode(stream, val[key], ctx);\n        }\n      }\n      i = 0;\n      while (i < ctx.pointers.length) {\n        ptr = ctx.pointers[i++];\n        ptr.type.encode(stream, ptr.val, ptr.parent);\n      }\n    };\n\n    return VersionedStruct;\n\n  })(Struct);\n\n  module.exports = VersionedStruct;\n\n}).call(this);\n\n\n/***/ }),\n/* 196 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var Pointer, VoidPointer, utils;\n\n  utils = __webpack_require__(12);\n\n  Pointer = (function() {\n    function Pointer(offsetType, type, options) {\n      var _base, _base1, _base2, _base3;\n      this.offsetType = offsetType;\n      this.type = type;\n      this.options = options != null ? options : {};\n      if (this.type === 'void') {\n        this.type = null;\n      }\n      if ((_base = this.options).type == null) {\n        _base.type = 'local';\n      }\n      if ((_base1 = this.options).allowNull == null) {\n        _base1.allowNull = true;\n      }\n      if ((_base2 = this.options).nullValue == null) {\n        _base2.nullValue = 0;\n      }\n      if ((_base3 = this.options).lazy == null) {\n        _base3.lazy = false;\n      }\n      if (this.options.relativeTo) {\n        this.relativeToGetter = new Function('ctx', \"return ctx.\" + this.options.relativeTo);\n      }\n    }\n\n    Pointer.prototype.decode = function(stream, ctx) {\n      var c, decodeValue, offset, ptr, relative, val;\n      offset = this.offsetType.decode(stream, ctx);\n      if (offset === this.options.nullValue && this.options.allowNull) {\n        return null;\n      }\n      relative = (function() {\n        switch (this.options.type) {\n          case 'local':\n            return ctx._startOffset;\n          case 'immediate':\n            return stream.pos - this.offsetType.size();\n          case 'parent':\n            return ctx.parent._startOffset;\n          default:\n            c = ctx;\n            while (c.parent) {\n              c = c.parent;\n            }\n            return c._startOffset || 0;\n        }\n      }).call(this);\n      if (this.options.relativeTo) {\n        relative += this.relativeToGetter(ctx);\n      }\n      ptr = offset + relative;\n      if (this.type != null) {\n        val = null;\n        decodeValue = (function(_this) {\n          return function() {\n            var pos;\n            if (val != null) {\n              return val;\n            }\n            pos = stream.pos;\n            stream.pos = ptr;\n            val = _this.type.decode(stream, ctx);\n            stream.pos = pos;\n            return val;\n          };\n        })(this);\n        if (this.options.lazy) {\n          return new utils.PropertyDescriptor({\n            get: decodeValue\n          });\n        }\n        return decodeValue();\n      } else {\n        return ptr;\n      }\n    };\n\n    Pointer.prototype.size = function(val, ctx) {\n      var parent, type;\n      parent = ctx;\n      switch (this.options.type) {\n        case 'local':\n        case 'immediate':\n          break;\n        case 'parent':\n          ctx = ctx.parent;\n          break;\n        default:\n          while (ctx.parent) {\n            ctx = ctx.parent;\n          }\n      }\n      type = this.type;\n      if (type == null) {\n        if (!(val instanceof VoidPointer)) {\n          throw new Error(\"Must be a VoidPointer\");\n        }\n        type = val.type;\n        val = val.value;\n      }\n      if (val && ctx) {\n        ctx.pointerSize += type.size(val, parent);\n      }\n      return this.offsetType.size();\n    };\n\n    Pointer.prototype.encode = function(stream, val, ctx) {\n      var parent, relative, type;\n      parent = ctx;\n      if (val == null) {\n        this.offsetType.encode(stream, this.options.nullValue);\n        return;\n      }\n      switch (this.options.type) {\n        case 'local':\n          relative = ctx.startOffset;\n          break;\n        case 'immediate':\n          relative = stream.pos + this.offsetType.size(val, parent);\n          break;\n        case 'parent':\n          ctx = ctx.parent;\n          relative = ctx.startOffset;\n          break;\n        default:\n          relative = 0;\n          while (ctx.parent) {\n            ctx = ctx.parent;\n          }\n      }\n      if (this.options.relativeTo) {\n        relative += this.relativeToGetter(parent.val);\n      }\n      this.offsetType.encode(stream, ctx.pointerOffset - relative);\n      type = this.type;\n      if (type == null) {\n        if (!(val instanceof VoidPointer)) {\n          throw new Error(\"Must be a VoidPointer\");\n        }\n        type = val.type;\n        val = val.value;\n      }\n      ctx.pointers.push({\n        type: type,\n        val: val,\n        parent: parent\n      });\n      return ctx.pointerOffset += type.size(val, parent);\n    };\n\n    return Pointer;\n\n  })();\n\n  VoidPointer = (function() {\n    function VoidPointer(type, value) {\n      this.type = type;\n      this.value = value;\n    }\n\n    return VoidPointer;\n\n  })();\n\n  exports.Pointer = Pointer;\n\n  exports.VoidPointer = VoidPointer;\n\n}).call(this);\n\n\n/***/ }),\n/* 197 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(198), __esModule: true };\n\n/***/ }),\n/* 198 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(199);\nvar $Object = __webpack_require__(2).Object;\nmodule.exports = function getOwnPropertyDescriptor(it, key) {\n  return $Object.getOwnPropertyDescriptor(it, key);\n};\n\n\n/***/ }),\n/* 199 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.2.6 Object.getOwnPropertyDescriptor(O, P)\nvar toIObject = __webpack_require__(17);\nvar $getOwnPropertyDescriptor = __webpack_require__(57).f;\n\n__webpack_require__(59)('getOwnPropertyDescriptor', function () {\n  return function getOwnPropertyDescriptor(it, key) {\n    return $getOwnPropertyDescriptor(toIObject(it), key);\n  };\n});\n\n\n/***/ }),\n/* 200 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(28);\n__webpack_require__(24);\nmodule.exports = __webpack_require__(208);\n\n\n/***/ }),\n/* 201 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar addToUnscopables = __webpack_require__(202);\nvar step = __webpack_require__(98);\nvar Iterators = __webpack_require__(23);\nvar toIObject = __webpack_require__(17);\n\n// 22.1.3.4 Array.prototype.entries()\n// 22.1.3.13 Array.prototype.keys()\n// 22.1.3.29 Array.prototype.values()\n// 22.1.3.30 Array.prototype[@@iterator]()\nmodule.exports = __webpack_require__(61)(Array, 'Array', function (iterated, kind) {\n  this._t = toIObject(iterated); // target\n  this._i = 0;                   // next index\n  this._k = kind;                // kind\n// 22.1.5.2.1 %ArrayIteratorPrototype%.next()\n}, function () {\n  var O = this._t;\n  var kind = this._k;\n  var index = this._i++;\n  if (!O || index >= O.length) {\n    this._t = undefined;\n    return step(1);\n  }\n  if (kind == 'keys') return step(0, index);\n  if (kind == 'values') return step(0, O[index]);\n  return step(0, [index, O[index]]);\n}, 'values');\n\n// argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7)\nIterators.Arguments = Iterators.Array;\n\naddToUnscopables('keys');\naddToUnscopables('values');\naddToUnscopables('entries');\n\n\n/***/ }),\n/* 202 */\n/***/ (function(module, exports) {\n\nmodule.exports = function () { /* empty */ };\n\n\n/***/ }),\n/* 203 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar create = __webpack_require__(36);\nvar descriptor = __webpack_require__(27);\nvar setToStringTag = __webpack_require__(39);\nvar IteratorPrototype = {};\n\n// 25.1.2.1.1 %IteratorPrototype%[@@iterator]()\n__webpack_require__(13)(IteratorPrototype, __webpack_require__(4)('iterator'), function () { return this; });\n\nmodule.exports = function (Constructor, NAME, next) {\n  Constructor.prototype = create(IteratorPrototype, { next: descriptor(1, next) });\n  setToStringTag(Constructor, NAME + ' Iterator');\n};\n\n\n/***/ }),\n/* 204 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// false -> Array#indexOf\n// true  -> Array#includes\nvar toIObject = __webpack_require__(17);\nvar toLength = __webpack_require__(37);\nvar toAbsoluteIndex = __webpack_require__(102);\nmodule.exports = function (IS_INCLUDES) {\n  return function ($this, el, fromIndex) {\n    var O = toIObject($this);\n    var length = toLength(O.length);\n    var index = toAbsoluteIndex(fromIndex, length);\n    var value;\n    // Array#includes uses SameValueZero equality algorithm\n    // eslint-disable-next-line no-self-compare\n    if (IS_INCLUDES && el != el) while (length > index) {\n      value = O[index++];\n      // eslint-disable-next-line no-self-compare\n      if (value != value) return true;\n    // Array#indexOf ignores holes, Array#includes - not\n    } else for (;length > index; index++) if (IS_INCLUDES || index in O) {\n      if (O[index] === el) return IS_INCLUDES || index || 0;\n    } return !IS_INCLUDES && -1;\n  };\n};\n\n\n/***/ }),\n/* 205 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar document = __webpack_require__(10).document;\nmodule.exports = document && document.documentElement;\n\n\n/***/ }),\n/* 206 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O)\nvar has = __webpack_require__(18);\nvar toObject = __webpack_require__(30);\nvar IE_PROTO = __webpack_require__(64)('IE_PROTO');\nvar ObjectProto = Object.prototype;\n\nmodule.exports = Object.getPrototypeOf || function (O) {\n  O = toObject(O);\n  if (has(O, IE_PROTO)) return O[IE_PROTO];\n  if (typeof O.constructor == 'function' && O instanceof O.constructor) {\n    return O.constructor.prototype;\n  } return O instanceof Object ? ObjectProto : null;\n};\n\n\n/***/ }),\n/* 207 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar toInteger = __webpack_require__(63);\nvar defined = __webpack_require__(56);\n// true  -> String#at\n// false -> String#codePointAt\nmodule.exports = function (TO_STRING) {\n  return function (that, pos) {\n    var s = String(defined(that));\n    var i = toInteger(pos);\n    var l = s.length;\n    var a, b;\n    if (i < 0 || i >= l) return TO_STRING ? '' : undefined;\n    a = s.charCodeAt(i);\n    return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff\n      ? TO_STRING ? s.charAt(i) : a\n      : TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000;\n  };\n};\n\n\n/***/ }),\n/* 208 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar anObject = __webpack_require__(14);\nvar get = __webpack_require__(67);\nmodule.exports = __webpack_require__(2).getIterator = function (it) {\n  var iterFn = get(it);\n  if (typeof iterFn != 'function') throw TypeError(it + ' is not iterable!');\n  return anObject(iterFn.call(it));\n};\n\n\n/***/ }),\n/* 209 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(210), __esModule: true };\n\n/***/ }),\n/* 210 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(211);\nmodule.exports = __webpack_require__(2).Object.freeze;\n\n\n/***/ }),\n/* 211 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.2.5 Object.freeze(O)\nvar isObject = __webpack_require__(9);\nvar meta = __webpack_require__(40).onFreeze;\n\n__webpack_require__(59)('freeze', function ($freeze) {\n  return function freeze(it) {\n    return $freeze && isObject(it) ? $freeze(meta(it)) : it;\n  };\n});\n\n\n/***/ }),\n/* 212 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(213), __esModule: true };\n\n/***/ }),\n/* 213 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(214);\nmodule.exports = __webpack_require__(2).Object.keys;\n\n\n/***/ }),\n/* 214 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.2.14 Object.keys(O)\nvar toObject = __webpack_require__(30);\nvar $keys = __webpack_require__(29);\n\n__webpack_require__(59)('keys', function () {\n  return function keys(it) {\n    return $keys(toObject(it));\n  };\n});\n\n\n/***/ }),\n/* 215 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(24);\n__webpack_require__(28);\nmodule.exports = __webpack_require__(70).f('iterator');\n\n\n/***/ }),\n/* 216 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(217), __esModule: true };\n\n/***/ }),\n/* 217 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(218);\n__webpack_require__(73);\n__webpack_require__(221);\n__webpack_require__(222);\nmodule.exports = __webpack_require__(2).Symbol;\n\n\n/***/ }),\n/* 218 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n// ECMAScript 6 symbols shim\nvar global = __webpack_require__(10);\nvar has = __webpack_require__(18);\nvar DESCRIPTORS = __webpack_require__(5);\nvar $export = __webpack_require__(3);\nvar redefine = __webpack_require__(99);\nvar META = __webpack_require__(40).KEY;\nvar $fails = __webpack_require__(19);\nvar shared = __webpack_require__(65);\nvar setToStringTag = __webpack_require__(39);\nvar uid = __webpack_require__(38);\nvar wks = __webpack_require__(4);\nvar wksExt = __webpack_require__(70);\nvar wksDefine = __webpack_require__(71);\nvar enumKeys = __webpack_require__(219);\nvar isArray = __webpack_require__(104);\nvar anObject = __webpack_require__(14);\nvar isObject = __webpack_require__(9);\nvar toIObject = __webpack_require__(17);\nvar toPrimitive = __webpack_require__(58);\nvar createDesc = __webpack_require__(27);\nvar _create = __webpack_require__(36);\nvar gOPNExt = __webpack_require__(220);\nvar $GOPD = __webpack_require__(57);\nvar $DP = __webpack_require__(6);\nvar $keys = __webpack_require__(29);\nvar gOPD = $GOPD.f;\nvar dP = $DP.f;\nvar gOPN = gOPNExt.f;\nvar $Symbol = global.Symbol;\nvar $JSON = global.JSON;\nvar _stringify = $JSON && $JSON.stringify;\nvar PROTOTYPE = 'prototype';\nvar HIDDEN = wks('_hidden');\nvar TO_PRIMITIVE = wks('toPrimitive');\nvar isEnum = {}.propertyIsEnumerable;\nvar SymbolRegistry = shared('symbol-registry');\nvar AllSymbols = shared('symbols');\nvar OPSymbols = shared('op-symbols');\nvar ObjectProto = Object[PROTOTYPE];\nvar USE_NATIVE = typeof $Symbol == 'function';\nvar QObject = global.QObject;\n// Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173\nvar setter = !QObject || !QObject[PROTOTYPE] || !QObject[PROTOTYPE].findChild;\n\n// fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687\nvar setSymbolDesc = DESCRIPTORS && $fails(function () {\n  return _create(dP({}, 'a', {\n    get: function () { return dP(this, 'a', { value: 7 }).a; }\n  })).a != 7;\n}) ? function (it, key, D) {\n  var protoDesc = gOPD(ObjectProto, key);\n  if (protoDesc) delete ObjectProto[key];\n  dP(it, key, D);\n  if (protoDesc && it !== ObjectProto) dP(ObjectProto, key, protoDesc);\n} : dP;\n\nvar wrap = function (tag) {\n  var sym = AllSymbols[tag] = _create($Symbol[PROTOTYPE]);\n  sym._k = tag;\n  return sym;\n};\n\nvar isSymbol = USE_NATIVE && typeof $Symbol.iterator == 'symbol' ? function (it) {\n  return typeof it == 'symbol';\n} : function (it) {\n  return it instanceof $Symbol;\n};\n\nvar $defineProperty = function defineProperty(it, key, D) {\n  if (it === ObjectProto) $defineProperty(OPSymbols, key, D);\n  anObject(it);\n  key = toPrimitive(key, true);\n  anObject(D);\n  if (has(AllSymbols, key)) {\n    if (!D.enumerable) {\n      if (!has(it, HIDDEN)) dP(it, HIDDEN, createDesc(1, {}));\n      it[HIDDEN][key] = true;\n    } else {\n      if (has(it, HIDDEN) && it[HIDDEN][key]) it[HIDDEN][key] = false;\n      D = _create(D, { enumerable: createDesc(0, false) });\n    } return setSymbolDesc(it, key, D);\n  } return dP(it, key, D);\n};\nvar $defineProperties = function defineProperties(it, P) {\n  anObject(it);\n  var keys = enumKeys(P = toIObject(P));\n  var i = 0;\n  var l = keys.length;\n  var key;\n  while (l > i) $defineProperty(it, key = keys[i++], P[key]);\n  return it;\n};\nvar $create = function create(it, P) {\n  return P === undefined ? _create(it) : $defineProperties(_create(it), P);\n};\nvar $propertyIsEnumerable = function propertyIsEnumerable(key) {\n  var E = isEnum.call(this, key = toPrimitive(key, true));\n  if (this === ObjectProto && has(AllSymbols, key) && !has(OPSymbols, key)) return false;\n  return E || !has(this, key) || !has(AllSymbols, key) || has(this, HIDDEN) && this[HIDDEN][key] ? E : true;\n};\nvar $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(it, key) {\n  it = toIObject(it);\n  key = toPrimitive(key, true);\n  if (it === ObjectProto && has(AllSymbols, key) && !has(OPSymbols, key)) return;\n  var D = gOPD(it, key);\n  if (D && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key])) D.enumerable = true;\n  return D;\n};\nvar $getOwnPropertyNames = function getOwnPropertyNames(it) {\n  var names = gOPN(toIObject(it));\n  var result = [];\n  var i = 0;\n  var key;\n  while (names.length > i) {\n    if (!has(AllSymbols, key = names[i++]) && key != HIDDEN && key != META) result.push(key);\n  } return result;\n};\nvar $getOwnPropertySymbols = function getOwnPropertySymbols(it) {\n  var IS_OP = it === ObjectProto;\n  var names = gOPN(IS_OP ? OPSymbols : toIObject(it));\n  var result = [];\n  var i = 0;\n  var key;\n  while (names.length > i) {\n    if (has(AllSymbols, key = names[i++]) && (IS_OP ? has(ObjectProto, key) : true)) result.push(AllSymbols[key]);\n  } return result;\n};\n\n// 19.4.1.1 Symbol([description])\nif (!USE_NATIVE) {\n  $Symbol = function Symbol() {\n    if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor!');\n    var tag = uid(arguments.length > 0 ? arguments[0] : undefined);\n    var $set = function (value) {\n      if (this === ObjectProto) $set.call(OPSymbols, value);\n      if (has(this, HIDDEN) && has(this[HIDDEN], tag)) this[HIDDEN][tag] = false;\n      setSymbolDesc(this, tag, createDesc(1, value));\n    };\n    if (DESCRIPTORS && setter) setSymbolDesc(ObjectProto, tag, { configurable: true, set: $set });\n    return wrap(tag);\n  };\n  redefine($Symbol[PROTOTYPE], 'toString', function toString() {\n    return this._k;\n  });\n\n  $GOPD.f = $getOwnPropertyDescriptor;\n  $DP.f = $defineProperty;\n  __webpack_require__(105).f = gOPNExt.f = $getOwnPropertyNames;\n  __webpack_require__(35).f = $propertyIsEnumerable;\n  __webpack_require__(72).f = $getOwnPropertySymbols;\n\n  if (DESCRIPTORS && !__webpack_require__(62)) {\n    redefine(ObjectProto, 'propertyIsEnumerable', $propertyIsEnumerable, true);\n  }\n\n  wksExt.f = function (name) {\n    return wrap(wks(name));\n  };\n}\n\n$export($export.G + $export.W + $export.F * !USE_NATIVE, { Symbol: $Symbol });\n\nfor (var es6Symbols = (\n  // 19.4.2.2, 19.4.2.3, 19.4.2.4, 19.4.2.6, 19.4.2.8, 19.4.2.9, 19.4.2.10, 19.4.2.11, 19.4.2.12, 19.4.2.13, 19.4.2.14\n  'hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables'\n).split(','), j = 0; es6Symbols.length > j;)wks(es6Symbols[j++]);\n\nfor (var wellKnownSymbols = $keys(wks.store), k = 0; wellKnownSymbols.length > k;) wksDefine(wellKnownSymbols[k++]);\n\n$export($export.S + $export.F * !USE_NATIVE, 'Symbol', {\n  // 19.4.2.1 Symbol.for(key)\n  'for': function (key) {\n    return has(SymbolRegistry, key += '')\n      ? SymbolRegistry[key]\n      : SymbolRegistry[key] = $Symbol(key);\n  },\n  // 19.4.2.5 Symbol.keyFor(sym)\n  keyFor: function keyFor(sym) {\n    if (!isSymbol(sym)) throw TypeError(sym + ' is not a symbol!');\n    for (var key in SymbolRegistry) if (SymbolRegistry[key] === sym) return key;\n  },\n  useSetter: function () { setter = true; },\n  useSimple: function () { setter = false; }\n});\n\n$export($export.S + $export.F * !USE_NATIVE, 'Object', {\n  // 19.1.2.2 Object.create(O [, Properties])\n  create: $create,\n  // 19.1.2.4 Object.defineProperty(O, P, Attributes)\n  defineProperty: $defineProperty,\n  // 19.1.2.3 Object.defineProperties(O, Properties)\n  defineProperties: $defineProperties,\n  // 19.1.2.6 Object.getOwnPropertyDescriptor(O, P)\n  getOwnPropertyDescriptor: $getOwnPropertyDescriptor,\n  // 19.1.2.7 Object.getOwnPropertyNames(O)\n  getOwnPropertyNames: $getOwnPropertyNames,\n  // 19.1.2.8 Object.getOwnPropertySymbols(O)\n  getOwnPropertySymbols: $getOwnPropertySymbols\n});\n\n// 24.3.2 JSON.stringify(value [, replacer [, space]])\n$JSON && $export($export.S + $export.F * (!USE_NATIVE || $fails(function () {\n  var S = $Symbol();\n  // MS Edge converts symbol values to JSON as {}\n  // WebKit converts symbol values to JSON as null\n  // V8 throws on boxed symbols\n  return _stringify([S]) != '[null]' || _stringify({ a: S }) != '{}' || _stringify(Object(S)) != '{}';\n})), 'JSON', {\n  stringify: function stringify(it) {\n    var args = [it];\n    var i = 1;\n    var replacer, $replacer;\n    while (arguments.length > i) args.push(arguments[i++]);\n    $replacer = replacer = args[1];\n    if (!isObject(replacer) && it === undefined || isSymbol(it)) return; // IE8 returns string on undefined\n    if (!isArray(replacer)) replacer = function (key, value) {\n      if (typeof $replacer == 'function') value = $replacer.call(this, key, value);\n      if (!isSymbol(value)) return value;\n    };\n    args[1] = replacer;\n    return _stringify.apply($JSON, args);\n  }\n});\n\n// 19.4.3.4 Symbol.prototype[@@toPrimitive](hint)\n$Symbol[PROTOTYPE][TO_PRIMITIVE] || __webpack_require__(13)($Symbol[PROTOTYPE], TO_PRIMITIVE, $Symbol[PROTOTYPE].valueOf);\n// 19.4.3.5 Symbol.prototype[@@toStringTag]\nsetToStringTag($Symbol, 'Symbol');\n// 20.2.1.9 Math[@@toStringTag]\nsetToStringTag(Math, 'Math', true);\n// 24.3.3 JSON[@@toStringTag]\nsetToStringTag(global.JSON, 'JSON', true);\n\n\n/***/ }),\n/* 219 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// all enumerable object keys, includes symbols\nvar getKeys = __webpack_require__(29);\nvar gOPS = __webpack_require__(72);\nvar pIE = __webpack_require__(35);\nmodule.exports = function (it) {\n  var result = getKeys(it);\n  var getSymbols = gOPS.f;\n  if (getSymbols) {\n    var symbols = getSymbols(it);\n    var isEnum = pIE.f;\n    var i = 0;\n    var key;\n    while (symbols.length > i) if (isEnum.call(it, key = symbols[i++])) result.push(key);\n  } return result;\n};\n\n\n/***/ }),\n/* 220 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window\nvar toIObject = __webpack_require__(17);\nvar gOPN = __webpack_require__(105).f;\nvar toString = {}.toString;\n\nvar windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames\n  ? Object.getOwnPropertyNames(window) : [];\n\nvar getWindowNames = function (it) {\n  try {\n    return gOPN(it);\n  } catch (e) {\n    return windowNames.slice();\n  }\n};\n\nmodule.exports.f = function getOwnPropertyNames(it) {\n  return windowNames && toString.call(it) == '[object Window]' ? getWindowNames(it) : gOPN(toIObject(it));\n};\n\n\n/***/ }),\n/* 221 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(71)('asyncIterator');\n\n\n/***/ }),\n/* 222 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(71)('observable');\n\n\n/***/ }),\n/* 223 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(224);\nvar $Object = __webpack_require__(2).Object;\nmodule.exports = function defineProperty(it, key, desc) {\n  return $Object.defineProperty(it, key, desc);\n};\n\n\n/***/ }),\n/* 224 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar $export = __webpack_require__(3);\n// 19.1.2.4 / 15.2.3.6 Object.defineProperty(O, P, Attributes)\n$export($export.S + $export.F * !__webpack_require__(5), 'Object', { defineProperty: __webpack_require__(6).f });\n\n\n/***/ }),\n/* 225 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(226), __esModule: true };\n\n/***/ }),\n/* 226 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(73);\n__webpack_require__(24);\n__webpack_require__(28);\n__webpack_require__(227);\n__webpack_require__(232);\n__webpack_require__(234);\n__webpack_require__(235);\nmodule.exports = __webpack_require__(2).Map;\n\n\n/***/ }),\n/* 227 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar strong = __webpack_require__(108);\nvar validate = __webpack_require__(75);\nvar MAP = 'Map';\n\n// 23.1 Map Objects\nmodule.exports = __webpack_require__(113)(MAP, function (get) {\n  return function Map() { return get(this, arguments.length > 0 ? arguments[0] : undefined); };\n}, {\n  // 23.1.3.6 Map.prototype.get(key)\n  get: function get(key) {\n    var entry = strong.getEntry(validate(this, MAP), key);\n    return entry && entry.v;\n  },\n  // 23.1.3.9 Map.prototype.set(key, value)\n  set: function set(key, value) {\n    return strong.def(validate(this, MAP), key === 0 ? 0 : key, value);\n  }\n}, strong, true);\n\n\n/***/ }),\n/* 228 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar global = __webpack_require__(10);\nvar core = __webpack_require__(2);\nvar dP = __webpack_require__(6);\nvar DESCRIPTORS = __webpack_require__(5);\nvar SPECIES = __webpack_require__(4)('species');\n\nmodule.exports = function (KEY) {\n  var C = typeof core[KEY] == 'function' ? core[KEY] : global[KEY];\n  if (DESCRIPTORS && C && !C[SPECIES]) dP.f(C, SPECIES, {\n    configurable: true,\n    get: function () { return this; }\n  });\n};\n\n\n/***/ }),\n/* 229 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 0 -> Array#forEach\n// 1 -> Array#map\n// 2 -> Array#filter\n// 3 -> Array#some\n// 4 -> Array#every\n// 5 -> Array#find\n// 6 -> Array#findIndex\nvar ctx = __webpack_require__(20);\nvar IObject = __webpack_require__(54);\nvar toObject = __webpack_require__(30);\nvar toLength = __webpack_require__(37);\nvar asc = __webpack_require__(230);\nmodule.exports = function (TYPE, $create) {\n  var IS_MAP = TYPE == 1;\n  var IS_FILTER = TYPE == 2;\n  var IS_SOME = TYPE == 3;\n  var IS_EVERY = TYPE == 4;\n  var IS_FIND_INDEX = TYPE == 6;\n  var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;\n  var create = $create || asc;\n  return function ($this, callbackfn, that) {\n    var O = toObject($this);\n    var self = IObject(O);\n    var f = ctx(callbackfn, that, 3);\n    var length = toLength(self.length);\n    var index = 0;\n    var result = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined;\n    var val, res;\n    for (;length > index; index++) if (NO_HOLES || index in self) {\n      val = self[index];\n      res = f(val, index, O);\n      if (TYPE) {\n        if (IS_MAP) result[index] = res;   // map\n        else if (res) switch (TYPE) {\n          case 3: return true;             // some\n          case 5: return val;              // find\n          case 6: return index;            // findIndex\n          case 2: result.push(val);        // filter\n        } else if (IS_EVERY) return false; // every\n      }\n    }\n    return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : result;\n  };\n};\n\n\n/***/ }),\n/* 230 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 9.4.2.3 ArraySpeciesCreate(originalArray, length)\nvar speciesConstructor = __webpack_require__(231);\n\nmodule.exports = function (original, length) {\n  return new (speciesConstructor(original))(length);\n};\n\n\n/***/ }),\n/* 231 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar isObject = __webpack_require__(9);\nvar isArray = __webpack_require__(104);\nvar SPECIES = __webpack_require__(4)('species');\n\nmodule.exports = function (original) {\n  var C;\n  if (isArray(original)) {\n    C = original.constructor;\n    // cross-realm fallback\n    if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined;\n    if (isObject(C)) {\n      C = C[SPECIES];\n      if (C === null) C = undefined;\n    }\n  } return C === undefined ? Array : C;\n};\n\n\n/***/ }),\n/* 232 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// https://github.com/DavidBruant/Map-Set.prototype.toJSON\nvar $export = __webpack_require__(3);\n\n$export($export.P + $export.R, 'Map', { toJSON: __webpack_require__(114)('Map') });\n\n\n/***/ }),\n/* 233 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar forOf = __webpack_require__(41);\n\nmodule.exports = function (iter, ITERATOR) {\n  var result = [];\n  forOf(iter, false, result.push, result, ITERATOR);\n  return result;\n};\n\n\n/***/ }),\n/* 234 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// https://tc39.github.io/proposal-setmap-offrom/#sec-map.of\n__webpack_require__(115)('Map');\n\n\n/***/ }),\n/* 235 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// https://tc39.github.io/proposal-setmap-offrom/#sec-map.from\n__webpack_require__(116)('Map');\n\n\n/***/ }),\n/* 236 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nvar _typeof2 = __webpack_require__(69);\n\nvar _typeof3 = _interopRequireDefault(_typeof2);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nexports.default = function (self, call) {\n  if (!self) {\n    throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n  }\n\n  return call && ((typeof call === \"undefined\" ? \"undefined\" : (0, _typeof3.default)(call)) === \"object\" || typeof call === \"function\") ? call : self;\n};\n\n/***/ }),\n/* 237 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nvar _setPrototypeOf = __webpack_require__(238);\n\nvar _setPrototypeOf2 = _interopRequireDefault(_setPrototypeOf);\n\nvar _create = __webpack_require__(242);\n\nvar _create2 = _interopRequireDefault(_create);\n\nvar _typeof2 = __webpack_require__(69);\n\nvar _typeof3 = _interopRequireDefault(_typeof2);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nexports.default = function (subClass, superClass) {\n  if (typeof superClass !== \"function\" && superClass !== null) {\n    throw new TypeError(\"Super expression must either be null or a function, not \" + (typeof superClass === \"undefined\" ? \"undefined\" : (0, _typeof3.default)(superClass)));\n  }\n\n  subClass.prototype = (0, _create2.default)(superClass && superClass.prototype, {\n    constructor: {\n      value: subClass,\n      enumerable: false,\n      writable: true,\n      configurable: true\n    }\n  });\n  if (superClass) _setPrototypeOf2.default ? (0, _setPrototypeOf2.default)(subClass, superClass) : subClass.__proto__ = superClass;\n};\n\n/***/ }),\n/* 238 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(239), __esModule: true };\n\n/***/ }),\n/* 239 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(240);\nmodule.exports = __webpack_require__(2).Object.setPrototypeOf;\n\n\n/***/ }),\n/* 240 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.3.19 Object.setPrototypeOf(O, proto)\nvar $export = __webpack_require__(3);\n$export($export.S, 'Object', { setPrototypeOf: __webpack_require__(241).set });\n\n\n/***/ }),\n/* 241 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Works with __proto__ only. Old v8 can't work with null proto objects.\n/* eslint-disable no-proto */\nvar isObject = __webpack_require__(9);\nvar anObject = __webpack_require__(14);\nvar check = function (O, proto) {\n  anObject(O);\n  if (!isObject(proto) && proto !== null) throw TypeError(proto + \": can't set as prototype!\");\n};\nmodule.exports = {\n  set: Object.setPrototypeOf || ('__proto__' in {} ? // eslint-disable-line\n    function (test, buggy, set) {\n      try {\n        set = __webpack_require__(20)(Function.call, __webpack_require__(57).f(Object.prototype, '__proto__').set, 2);\n        set(test, []);\n        buggy = !(test instanceof Array);\n      } catch (e) { buggy = true; }\n      return function setPrototypeOf(O, proto) {\n        check(O, proto);\n        if (buggy) O.__proto__ = proto;\n        else set(O, proto);\n        return O;\n      };\n    }({}, false) : undefined),\n  check: check\n};\n\n\n/***/ }),\n/* 242 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(243), __esModule: true };\n\n/***/ }),\n/* 243 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(244);\nvar $Object = __webpack_require__(2).Object;\nmodule.exports = function create(P, D) {\n  return $Object.create(P, D);\n};\n\n\n/***/ }),\n/* 244 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar $export = __webpack_require__(3);\n// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])\n$export($export.S, 'Object', { create: __webpack_require__(36) });\n\n\n/***/ }),\n/* 245 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(246), __esModule: true };\n\n/***/ }),\n/* 246 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(247);\nvar $Object = __webpack_require__(2).Object;\nmodule.exports = function defineProperties(T, D) {\n  return $Object.defineProperties(T, D);\n};\n\n\n/***/ }),\n/* 247 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar $export = __webpack_require__(3);\n// 19.1.2.3 / 15.2.3.7 Object.defineProperties(O, Properties)\n$export($export.S + $export.F * !__webpack_require__(5), 'Object', { defineProperties: __webpack_require__(100) });\n\n\n/***/ }),\n/* 248 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar pSlice = Array.prototype.slice;\nvar objectKeys = __webpack_require__(249);\nvar isArguments = __webpack_require__(250);\n\nvar deepEqual = module.exports = function (actual, expected, opts) {\n  if (!opts) opts = {};\n  // 7.1. All identical values are equivalent, as determined by ===.\n  if (actual === expected) {\n    return true;\n\n  } else if (actual instanceof Date && expected instanceof Date) {\n    return actual.getTime() === expected.getTime();\n\n  // 7.3. Other pairs that do not both pass typeof value == 'object',\n  // equivalence is determined by ==.\n  } else if (!actual || !expected || typeof actual != 'object' && typeof expected != 'object') {\n    return opts.strict ? actual === expected : actual == expected;\n\n  // 7.4. For all other Object pairs, including Array objects, equivalence is\n  // determined by having the same number of owned properties (as verified\n  // with Object.prototype.hasOwnProperty.call), the same set of keys\n  // (although not necessarily the same order), equivalent values for every\n  // corresponding key, and an identical 'prototype' property. Note: this\n  // accounts for both named and indexed properties on Arrays.\n  } else {\n    return objEquiv(actual, expected, opts);\n  }\n}\n\nfunction isUndefinedOrNull(value) {\n  return value === null || value === undefined;\n}\n\nfunction isBuffer (x) {\n  if (!x || typeof x !== 'object' || typeof x.length !== 'number') return false;\n  if (typeof x.copy !== 'function' || typeof x.slice !== 'function') {\n    return false;\n  }\n  if (x.length > 0 && typeof x[0] !== 'number') return false;\n  return true;\n}\n\nfunction objEquiv(a, b, opts) {\n  var i, key;\n  if (isUndefinedOrNull(a) || isUndefinedOrNull(b))\n    return false;\n  // an identical 'prototype' property.\n  if (a.prototype !== b.prototype) return false;\n  //~~~I've managed to break Object.keys through screwy arguments passing.\n  //   Converting to array solves the problem.\n  if (isArguments(a)) {\n    if (!isArguments(b)) {\n      return false;\n    }\n    a = pSlice.call(a);\n    b = pSlice.call(b);\n    return deepEqual(a, b, opts);\n  }\n  if (isBuffer(a)) {\n    if (!isBuffer(b)) {\n      return false;\n    }\n    if (a.length !== b.length) return false;\n    for (i = 0; i < a.length; i++) {\n      if (a[i] !== b[i]) return false;\n    }\n    return true;\n  }\n  try {\n    var ka = objectKeys(a),\n        kb = objectKeys(b);\n  } catch (e) {//happens when one is a string literal and the other isn't\n    return false;\n  }\n  // having the same number of owned properties (keys incorporates\n  // hasOwnProperty)\n  if (ka.length != kb.length)\n    return false;\n  //the same set of keys (although not necessarily the same order),\n  ka.sort();\n  kb.sort();\n  //~~~cheap key test\n  for (i = ka.length - 1; i >= 0; i--) {\n    if (ka[i] != kb[i])\n      return false;\n  }\n  //equivalent values for every corresponding key, and\n  //~~~possibly expensive deep test\n  for (i = ka.length - 1; i >= 0; i--) {\n    key = ka[i];\n    if (!deepEqual(a[key], b[key], opts)) return false;\n  }\n  return typeof a === typeof b;\n}\n\n\n/***/ }),\n/* 249 */\n/***/ (function(module, exports) {\n\nexports = module.exports = typeof Object.keys === 'function'\n  ? Object.keys : shim;\n\nexports.shim = shim;\nfunction shim (obj) {\n  var keys = [];\n  for (var key in obj) keys.push(key);\n  return keys;\n}\n\n\n/***/ }),\n/* 250 */\n/***/ (function(module, exports) {\n\nvar supportsArgumentsClass = (function(){\n  return Object.prototype.toString.call(arguments)\n})() == '[object Arguments]';\n\nexports = module.exports = supportsArgumentsClass ? supported : unsupported;\n\nexports.supported = supported;\nfunction supported(object) {\n  return Object.prototype.toString.call(object) == '[object Arguments]';\n};\n\nexports.unsupported = unsupported;\nfunction unsupported(object){\n  return object &&\n    typeof object == 'object' &&\n    typeof object.length == 'number' &&\n    Object.prototype.hasOwnProperty.call(object, 'callee') &&\n    !Object.prototype.propertyIsEnumerable.call(object, 'callee') ||\n    false;\n};\n\n\n/***/ }),\n/* 251 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(252), __esModule: true };\n\n/***/ }),\n/* 252 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(253);\nmodule.exports = __webpack_require__(2).Object.assign;\n\n\n/***/ }),\n/* 253 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.3.1 Object.assign(target, source)\nvar $export = __webpack_require__(3);\n\n$export($export.S + $export.F, 'Object', { assign: __webpack_require__(254) });\n\n\n/***/ }),\n/* 254 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n// 19.1.2.1 Object.assign(target, source, ...)\nvar getKeys = __webpack_require__(29);\nvar gOPS = __webpack_require__(72);\nvar pIE = __webpack_require__(35);\nvar toObject = __webpack_require__(30);\nvar IObject = __webpack_require__(54);\nvar $assign = Object.assign;\n\n// should work with symbols and should have deterministic property order (V8 bug)\nmodule.exports = !$assign || __webpack_require__(19)(function () {\n  var A = {};\n  var B = {};\n  // eslint-disable-next-line no-undef\n  var S = Symbol();\n  var K = 'abcdefghijklmnopqrst';\n  A[S] = 7;\n  K.split('').forEach(function (k) { B[k] = k; });\n  return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join('') != K;\n}) ? function assign(target, source) { // eslint-disable-line no-unused-vars\n  var T = toObject(target);\n  var aLen = arguments.length;\n  var index = 1;\n  var getSymbols = gOPS.f;\n  var isEnum = pIE.f;\n  while (aLen > index) {\n    var S = IObject(arguments[index++]);\n    var keys = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S);\n    var length = keys.length;\n    var j = 0;\n    var key;\n    while (length > j) if (isEnum.call(S, key = keys[j++])) T[key] = S[key];\n  } return T;\n} : $assign;\n\n\n/***/ }),\n/* 255 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(256), __esModule: true };\n\n/***/ }),\n/* 256 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(257);\nmodule.exports = __webpack_require__(2).String.fromCodePoint;\n\n\n/***/ }),\n/* 257 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar $export = __webpack_require__(3);\nvar toAbsoluteIndex = __webpack_require__(102);\nvar fromCharCode = String.fromCharCode;\nvar $fromCodePoint = String.fromCodePoint;\n\n// length should be 1, old FF problem\n$export($export.S + $export.F * (!!$fromCodePoint && $fromCodePoint.length != 1), 'String', {\n  // 21.1.2.2 String.fromCodePoint(...codePoints)\n  fromCodePoint: function fromCodePoint(x) { // eslint-disable-line no-unused-vars\n    var res = [];\n    var aLen = arguments.length;\n    var i = 0;\n    var code;\n    while (aLen > i) {\n      code = +arguments[i++];\n      if (toAbsoluteIndex(code, 0x10ffff) !== code) throw RangeError(code + ' is not a valid code point');\n      res.push(code < 0x10000\n        ? fromCharCode(code)\n        : fromCharCode(((code -= 0x10000) >> 10) + 0xd800, code % 0x400 + 0xdc00)\n      );\n    } return res.join('');\n  }\n});\n\n\n/***/ }),\n/* 258 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(259), __esModule: true };\n\n/***/ }),\n/* 259 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(24);\n__webpack_require__(260);\nmodule.exports = __webpack_require__(2).Array.from;\n\n\n/***/ }),\n/* 260 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar ctx = __webpack_require__(20);\nvar $export = __webpack_require__(3);\nvar toObject = __webpack_require__(30);\nvar call = __webpack_require__(111);\nvar isArrayIter = __webpack_require__(112);\nvar toLength = __webpack_require__(37);\nvar createProperty = __webpack_require__(261);\nvar getIterFn = __webpack_require__(67);\n\n$export($export.S + $export.F * !__webpack_require__(262)(function (iter) { Array.from(iter); }), 'Array', {\n  // 22.1.2.1 Array.from(arrayLike, mapfn = undefined, thisArg = undefined)\n  from: function from(arrayLike /* , mapfn = undefined, thisArg = undefined */) {\n    var O = toObject(arrayLike);\n    var C = typeof this == 'function' ? this : Array;\n    var aLen = arguments.length;\n    var mapfn = aLen > 1 ? arguments[1] : undefined;\n    var mapping = mapfn !== undefined;\n    var index = 0;\n    var iterFn = getIterFn(O);\n    var length, result, step, iterator;\n    if (mapping) mapfn = ctx(mapfn, aLen > 2 ? arguments[2] : undefined, 2);\n    // if object isn't iterable or it's array with default iterator - use simple case\n    if (iterFn != undefined && !(C == Array && isArrayIter(iterFn))) {\n      for (iterator = iterFn.call(O), result = new C(); !(step = iterator.next()).done; index++) {\n        createProperty(result, index, mapping ? call(iterator, mapfn, [step.value, index], true) : step.value);\n      }\n    } else {\n      length = toLength(O.length);\n      for (result = new C(length); length > index; index++) {\n        createProperty(result, index, mapping ? mapfn(O[index], index) : O[index]);\n      }\n    }\n    result.length = index;\n    return result;\n  }\n});\n\n\n/***/ }),\n/* 261 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar $defineProperty = __webpack_require__(6);\nvar createDesc = __webpack_require__(27);\n\nmodule.exports = function (object, index, value) {\n  if (index in object) $defineProperty.f(object, index, createDesc(0, value));\n  else object[index] = value;\n};\n\n\n/***/ }),\n/* 262 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar ITERATOR = __webpack_require__(4)('iterator');\nvar SAFE_CLOSING = false;\n\ntry {\n  var riter = [7][ITERATOR]();\n  riter['return'] = function () { SAFE_CLOSING = true; };\n  // eslint-disable-next-line no-throw-literal\n  Array.from(riter, function () { throw 2; });\n} catch (e) { /* empty */ }\n\nmodule.exports = function (exec, skipClosing) {\n  if (!skipClosing && !SAFE_CLOSING) return false;\n  var safe = false;\n  try {\n    var arr = [7];\n    var iter = arr[ITERATOR]();\n    iter.next = function () { return { done: safe = true }; };\n    arr[ITERATOR] = function () { return iter; };\n    exec(arr);\n  } catch (e) { /* empty */ }\n  return safe;\n};\n\n\n/***/ }),\n/* 263 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(264), __esModule: true };\n\n/***/ }),\n/* 264 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(73);\n__webpack_require__(24);\n__webpack_require__(28);\n__webpack_require__(265);\n__webpack_require__(266);\n__webpack_require__(267);\n__webpack_require__(268);\nmodule.exports = __webpack_require__(2).Set;\n\n\n/***/ }),\n/* 265 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar strong = __webpack_require__(108);\nvar validate = __webpack_require__(75);\nvar SET = 'Set';\n\n// 23.2 Set Objects\nmodule.exports = __webpack_require__(113)(SET, function (get) {\n  return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); };\n}, {\n  // 23.2.3.1 Set.prototype.add(value)\n  add: function add(value) {\n    return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value);\n  }\n}, strong);\n\n\n/***/ }),\n/* 266 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// https://github.com/DavidBruant/Map-Set.prototype.toJSON\nvar $export = __webpack_require__(3);\n\n$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__(114)('Set') });\n\n\n/***/ }),\n/* 267 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of\n__webpack_require__(115)('Set');\n\n\n/***/ }),\n/* 268 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from\n__webpack_require__(116)('Set');\n\n\n/***/ }),\n/* 269 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.9.1\nvar CATEGORY_BITS, CATEGORY_MASK, CATEGORY_SHIFT, COMBINING_BITS, COMBINING_MASK, COMBINING_SHIFT, EAW_BITS, EAW_MASK, EAW_SHIFT, NUMBER_BITS, NUMBER_MASK, SCRIPT_BITS, SCRIPT_MASK, SCRIPT_SHIFT, UnicodeTrie, bits, data, fs, log2, trie;\n\nUnicodeTrie = __webpack_require__(43);\n\ndata = __webpack_require__(270);\n\n\n\ntrie = new UnicodeTrie(Buffer(\"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\",\"base64\"));\n\nlog2 = Math.log2 || function(n) {\n  return Math.log(n) / Math.LN2;\n};\n\nbits = function(n) {\n  return (log2(n) + 1) | 0;\n};\n\nCATEGORY_BITS = bits(data.categories.length - 1);\n\nCOMBINING_BITS = bits(data.combiningClasses.length - 1);\n\nSCRIPT_BITS = bits(data.scripts.length - 1);\n\nEAW_BITS = bits(data.eaw.length - 1);\n\nNUMBER_BITS = 10;\n\nCATEGORY_SHIFT = COMBINING_BITS + SCRIPT_BITS + EAW_BITS + NUMBER_BITS;\n\nCOMBINING_SHIFT = SCRIPT_BITS + EAW_BITS + NUMBER_BITS;\n\nSCRIPT_SHIFT = EAW_BITS + NUMBER_BITS;\n\nEAW_SHIFT = NUMBER_BITS;\n\nCATEGORY_MASK = (1 << CATEGORY_BITS) - 1;\n\nCOMBINING_MASK = (1 << COMBINING_BITS) - 1;\n\nSCRIPT_MASK = (1 << SCRIPT_BITS) - 1;\n\nEAW_MASK = (1 << EAW_BITS) - 1;\n\nNUMBER_MASK = (1 << NUMBER_BITS) - 1;\n\nexports.getCategory = function(codePoint) {\n  var val;\n  val = trie.get(codePoint);\n  return data.categories[(val >> CATEGORY_SHIFT) & CATEGORY_MASK];\n};\n\nexports.getCombiningClass = function(codePoint) {\n  var val;\n  val = trie.get(codePoint);\n  return data.combiningClasses[(val >> COMBINING_SHIFT) & COMBINING_MASK];\n};\n\nexports.getScript = function(codePoint) {\n  var val;\n  val = trie.get(codePoint);\n  return data.scripts[(val >> SCRIPT_SHIFT) & SCRIPT_MASK];\n};\n\nexports.getEastAsianWidth = function(codePoint) {\n  var val;\n  val = trie.get(codePoint);\n  return data.eaw[(val >> EAW_SHIFT) & EAW_MASK];\n};\n\nexports.getNumericValue = function(codePoint) {\n  var denominator, exp, num, numerator, val;\n  val = trie.get(codePoint);\n  num = val & NUMBER_MASK;\n  if (num === 0) {\n    return null;\n  } else if (num <= 50) {\n    return num - 1;\n  } else if (num < 0x1e0) {\n    numerator = (num >> 4) - 12;\n    denominator = (num & 0xf) + 1;\n    return numerator / denominator;\n  } else if (num < 0x300) {\n    val = (num >> 5) - 14;\n    exp = (num & 0x1f) + 2;\n    while (exp > 0) {\n      val *= 10;\n      exp--;\n    }\n    return val;\n  } else {\n    val = (num >> 2) - 0xbf;\n    exp = (num & 3) + 1;\n    while (exp > 0) {\n      val *= 60;\n      exp--;\n    }\n    return val;\n  }\n};\n\nexports.isAlphabetic = function(codePoint) {\n  var ref;\n  return (ref = exports.getCategory(codePoint)) === 'Lu' || ref === 'Ll' || ref === 'Lt' || ref === 'Lm' || ref === 'Lo' || ref === 'Nl';\n};\n\nexports.isDigit = function(codePoint) {\n  return exports.getCategory(codePoint) === 'Nd';\n};\n\nexports.isPunctuation = function(codePoint) {\n  var ref;\n  return (ref = exports.getCategory(codePoint)) === 'Pc' || ref === 'Pd' || ref === 'Pe' || ref === 'Pf' || ref === 'Pi' || ref === 'Po' || ref === 'Ps';\n};\n\nexports.isLowerCase = function(codePoint) {\n  return exports.getCategory(codePoint) === 'Ll';\n};\n\nexports.isUpperCase = function(codePoint) {\n  return exports.getCategory(codePoint) === 'Lu';\n};\n\nexports.isTitleCase = function(codePoint) {\n  return exports.getCategory(codePoint) === 'Lt';\n};\n\nexports.isWhiteSpace = function(codePoint) {\n  var ref;\n  return (ref = exports.getCategory(codePoint)) === 'Zs' || ref === 'Zl' || ref === 'Zp';\n};\n\nexports.isBaseForm = function(codePoint) {\n  var ref;\n  return (ref = exports.getCategory(codePoint)) === 'Nd' || ref === 'No' || ref === 'Nl' || ref === 'Lu' || ref === 'Ll' || ref === 'Lt' || ref === 'Lm' || ref === 'Lo' || ref === 'Me' || ref === 'Mc';\n};\n\nexports.isMark = function(codePoint) {\n  var ref;\n  return (ref = exports.getCategory(codePoint)) === 'Mn' || ref === 'Me' || ref === 'Mc';\n};\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 270 */\n/***/ (function(module, exports) {\n\nmodule.exports = {\"categories\":[\"Cc\",\"Zs\",\"Po\",\"Sc\",\"Ps\",\"Pe\",\"Sm\",\"Pd\",\"Nd\",\"Lu\",\"Sk\",\"Pc\",\"Ll\",\"So\",\"Lo\",\"Pi\",\"Cf\",\"No\",\"Pf\",\"Lt\",\"Lm\",\"Mn\",\"Me\",\"Mc\",\"Nl\",\"Zl\",\"Zp\",\"Cs\",\"Co\"],\"combiningClasses\":[\"Not_Reordered\",\"Above\",\"Above_Right\",\"Below\",\"Attached_Above_Right\",\"Attached_Below\",\"Overlay\",\"Iota_Subscript\",\"Double_Below\",\"Double_Above\",\"Below_Right\",\"Above_Left\",\"CCC10\",\"CCC11\",\"CCC12\",\"CCC13\",\"CCC14\",\"CCC15\",\"CCC16\",\"CCC17\",\"CCC18\",\"CCC19\",\"CCC20\",\"CCC21\",\"CCC22\",\"CCC23\",\"CCC24\",\"CCC25\",\"CCC30\",\"CCC31\",\"CCC32\",\"CCC27\",\"CCC28\",\"CCC29\",\"CCC33\",\"CCC34\",\"CCC35\",\"CCC36\",\"Nukta\",\"Virama\",\"CCC84\",\"CCC91\",\"CCC103\",\"CCC107\",\"CCC118\",\"CCC122\",\"CCC129\",\"CCC130\",\"CCC132\",\"Attached_Above\",\"Below_Left\",\"Left\",\"Kana_Voicing\",\"CCC26\",\"Right\"],\"scripts\":[\"Common\",\"Latin\",\"Bopomofo\",\"Inherited\",\"Greek\",\"Coptic\",\"Cyrillic\",\"Armenian\",\"Hebrew\",\"Arabic\",\"Syriac\",\"Thaana\",\"Nko\",\"Samaritan\",\"Mandaic\",\"Devanagari\",\"Bengali\",\"Gurmukhi\",\"Gujarati\",\"Oriya\",\"Tamil\",\"Telugu\",\"Kannada\",\"Malayalam\",\"Sinhala\",\"Thai\",\"Lao\",\"Tibetan\",\"Myanmar\",\"Georgian\",\"Hangul\",\"Ethiopic\",\"Cherokee\",\"Canadian_Aboriginal\",\"Ogham\",\"Runic\",\"Tagalog\",\"Hanunoo\",\"Buhid\",\"Tagbanwa\",\"Khmer\",\"Mongolian\",\"Limbu\",\"Tai_Le\",\"New_Tai_Lue\",\"Buginese\",\"Tai_Tham\",\"Balinese\",\"Sundanese\",\"Batak\",\"Lepcha\",\"Ol_Chiki\",\"Braille\",\"Glagolitic\",\"Tifinagh\",\"Han\",\"Hiragana\",\"Katakana\",\"Yi\",\"Lisu\",\"Vai\",\"Bamum\",\"Syloti_Nagri\",\"Phags_Pa\",\"Saurashtra\",\"Kayah_Li\",\"Rejang\",\"Javanese\",\"Cham\",\"Tai_Viet\",\"Meetei_Mayek\",\"null\",\"Linear_B\",\"Lycian\",\"Carian\",\"Old_Italic\",\"Gothic\",\"Old_Permic\",\"Ugaritic\",\"Old_Persian\",\"Deseret\",\"Shavian\",\"Osmanya\",\"Elbasan\",\"Caucasian_Albanian\",\"Linear_A\",\"Cypriot\",\"Imperial_Aramaic\",\"Palmyrene\",\"Nabataean\",\"Hatran\",\"Phoenician\",\"Lydian\",\"Meroitic_Hieroglyphs\",\"Meroitic_Cursive\",\"Kharoshthi\",\"Old_South_Arabian\",\"Old_North_Arabian\",\"Manichaean\",\"Avestan\",\"Inscriptional_Parthian\",\"Inscriptional_Pahlavi\",\"Psalter_Pahlavi\",\"Old_Turkic\",\"Old_Hungarian\",\"Brahmi\",\"Kaithi\",\"Sora_Sompeng\",\"Chakma\",\"Mahajani\",\"Sharada\",\"Khojki\",\"Multani\",\"Khudawadi\",\"Grantha\",\"Tirhuta\",\"Siddham\",\"Modi\",\"Takri\",\"Ahom\",\"Warang_Citi\",\"Pau_Cin_Hau\",\"Cuneiform\",\"Egyptian_Hieroglyphs\",\"Anatolian_Hieroglyphs\",\"Mro\",\"Bassa_Vah\",\"Pahawh_Hmong\",\"Miao\",\"Duployan\",\"SignWriting\",\"Mende_Kikakui\"],\"eaw\":[\"N\",\"Na\",\"A\",\"W\",\"H\",\"F\"]}\n\n/***/ }),\n/* 271 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nfunction _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }\n\nvar _slicedToArray = _interopDefault(__webpack_require__(272));\nvar _getIterator = _interopDefault(__webpack_require__(60));\nvar _defineProperty = _interopDefault(__webpack_require__(276));\nvar _regeneratorRuntime = _interopDefault(__webpack_require__(277));\nvar _Symbol$iterator = _interopDefault(__webpack_require__(103));\nvar _classCallCheck = _interopDefault(__webpack_require__(106));\nvar _createClass = _interopDefault(__webpack_require__(107));\n\nvar INITIAL_STATE = 1;\nvar FAIL_STATE = 0;\n\n/**\n * A StateMachine represents a deterministic finite automaton.\n * It can perform matches over a sequence of values, similar to a regular expression.\n */\n\nvar StateMachine = function () {\n  function StateMachine(dfa) {\n    _classCallCheck(this, StateMachine);\n\n    this.stateTable = dfa.stateTable;\n    this.accepting = dfa.accepting;\n    this.tags = dfa.tags;\n  }\n\n  /**\n   * Returns an iterable object that yields pattern matches over the input sequence.\n   * Matches are of the form [startIndex, endIndex, tags].\n   */\n\n\n  _createClass(StateMachine, [{\n    key: 'match',\n    value: function match(str) {\n      var self = this;\n      return _defineProperty({}, _Symbol$iterator, _regeneratorRuntime.mark(function _callee() {\n        var state, startRun, lastAccepting, lastState, p, c;\n        return _regeneratorRuntime.wrap(function _callee$(_context) {\n          while (1) {\n            switch (_context.prev = _context.next) {\n              case 0:\n                state = INITIAL_STATE;\n                startRun = null;\n                lastAccepting = null;\n                lastState = null;\n                p = 0;\n\n              case 5:\n                if (!(p < str.length)) {\n                  _context.next = 21;\n                  break;\n                }\n\n                c = str[p];\n\n\n                lastState = state;\n                state = self.stateTable[state][c];\n\n                if (!(state === FAIL_STATE)) {\n                  _context.next = 15;\n                  break;\n                }\n\n                if (!(startRun != null && lastAccepting != null && lastAccepting >= startRun)) {\n                  _context.next = 13;\n                  break;\n                }\n\n                _context.next = 13;\n                return [startRun, lastAccepting, self.tags[lastState]];\n\n              case 13:\n\n                // reset the state as if we started over from the initial state\n                state = self.stateTable[INITIAL_STATE][c];\n                startRun = null;\n\n              case 15:\n\n                // start a run if not in the failure state\n                if (state !== FAIL_STATE && startRun == null) {\n                  startRun = p;\n                }\n\n                // if accepting, mark the potential match end\n                if (self.accepting[state]) {\n                  lastAccepting = p;\n                }\n\n                // reset the state to the initial state if we get into the failure state\n                if (state === FAIL_STATE) {\n                  state = INITIAL_STATE;\n                }\n\n              case 18:\n                p++;\n                _context.next = 5;\n                break;\n\n              case 21:\n                if (!(startRun != null && lastAccepting != null && lastAccepting >= startRun)) {\n                  _context.next = 24;\n                  break;\n                }\n\n                _context.next = 24;\n                return [startRun, lastAccepting, self.tags[state]];\n\n              case 24:\n              case 'end':\n                return _context.stop();\n            }\n          }\n        }, _callee, this);\n      }));\n    }\n\n    /**\n     * For each match over the input sequence, action functions matching\n     * the tag definitions in the input pattern are called with the startIndex,\n     * endIndex, and sub-match sequence.\n     */\n\n  }, {\n    key: 'apply',\n    value: function apply(str, actions) {\n      var _iteratorNormalCompletion = true;\n      var _didIteratorError = false;\n      var _iteratorError = undefined;\n\n      try {\n        for (var _iterator = _getIterator(this.match(str)), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {\n          var _step$value = _slicedToArray(_step.value, 3);\n\n          var start = _step$value[0];\n          var end = _step$value[1];\n          var tags = _step$value[2];\n          var _iteratorNormalCompletion2 = true;\n          var _didIteratorError2 = false;\n          var _iteratorError2 = undefined;\n\n          try {\n            for (var _iterator2 = _getIterator(tags), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {\n              var tag = _step2.value;\n\n              if (typeof actions[tag] === 'function') {\n                actions[tag](start, end, str.slice(start, end + 1));\n              }\n            }\n          } catch (err) {\n            _didIteratorError2 = true;\n            _iteratorError2 = err;\n          } finally {\n            try {\n              if (!_iteratorNormalCompletion2 && _iterator2.return) {\n                _iterator2.return();\n              }\n            } finally {\n              if (_didIteratorError2) {\n                throw _iteratorError2;\n              }\n            }\n          }\n        }\n      } catch (err) {\n        _didIteratorError = true;\n        _iteratorError = err;\n      } finally {\n        try {\n          if (!_iteratorNormalCompletion && _iterator.return) {\n            _iterator.return();\n          }\n        } finally {\n          if (_didIteratorError) {\n            throw _iteratorError;\n          }\n        }\n      }\n    }\n  }]);\n\n  return StateMachine;\n}();\n\nmodule.exports = StateMachine;\n\n\n/***/ }),\n/* 272 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nvar _isIterable2 = __webpack_require__(273);\n\nvar _isIterable3 = _interopRequireDefault(_isIterable2);\n\nvar _getIterator2 = __webpack_require__(60);\n\nvar _getIterator3 = _interopRequireDefault(_getIterator2);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nexports.default = function () {\n  function sliceIterator(arr, i) {\n    var _arr = [];\n    var _n = true;\n    var _d = false;\n    var _e = undefined;\n\n    try {\n      for (var _i = (0, _getIterator3.default)(arr), _s; !(_n = (_s = _i.next()).done); _n = true) {\n        _arr.push(_s.value);\n\n        if (i && _arr.length === i) break;\n      }\n    } catch (err) {\n      _d = true;\n      _e = err;\n    } finally {\n      try {\n        if (!_n && _i[\"return\"]) _i[\"return\"]();\n      } finally {\n        if (_d) throw _e;\n      }\n    }\n\n    return _arr;\n  }\n\n  return function (arr, i) {\n    if (Array.isArray(arr)) {\n      return arr;\n    } else if ((0, _isIterable3.default)(Object(arr))) {\n      return sliceIterator(arr, i);\n    } else {\n      throw new TypeError(\"Invalid attempt to destructure non-iterable instance\");\n    }\n  };\n}();\n\n/***/ }),\n/* 273 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(274), __esModule: true };\n\n/***/ }),\n/* 274 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(28);\n__webpack_require__(24);\nmodule.exports = __webpack_require__(275);\n\n\n/***/ }),\n/* 275 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar classof = __webpack_require__(68);\nvar ITERATOR = __webpack_require__(4)('iterator');\nvar Iterators = __webpack_require__(23);\nmodule.exports = __webpack_require__(2).isIterable = function (it) {\n  var O = Object(it);\n  return O[ITERATOR] !== undefined\n    || '@@iterator' in O\n    // eslint-disable-next-line no-prototype-builtins\n    || Iterators.hasOwnProperty(classof(O));\n};\n\n\n/***/ }),\n/* 276 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nvar _defineProperty = __webpack_require__(74);\n\nvar _defineProperty2 = _interopRequireDefault(_defineProperty);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nexports.default = function (obj, key, value) {\n  if (key in obj) {\n    (0, _defineProperty2.default)(obj, key, {\n      value: value,\n      enumerable: true,\n      configurable: true,\n      writable: true\n    });\n  } else {\n    obj[key] = value;\n  }\n\n  return obj;\n};\n\n/***/ }),\n/* 277 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(278);\n\n\n/***/ }),\n/* 278 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n * Copyright (c) 2014-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n// This method of obtaining a reference to the global object needs to be\n// kept identical to the way it is obtained in runtime.js\nvar g = (function() { return this })() || Function(\"return this\")();\n\n// Use `getOwnPropertyNames` because not all browsers support calling\n// `hasOwnProperty` on the global `self` object in a worker. See #183.\nvar hadRuntime = g.regeneratorRuntime &&\n  Object.getOwnPropertyNames(g).indexOf(\"regeneratorRuntime\") >= 0;\n\n// Save the old regeneratorRuntime in case it needs to be restored later.\nvar oldRuntime = hadRuntime && g.regeneratorRuntime;\n\n// Force reevalutation of runtime.js.\ng.regeneratorRuntime = undefined;\n\nmodule.exports = __webpack_require__(279);\n\nif (hadRuntime) {\n  // Restore the original runtime.\n  g.regeneratorRuntime = oldRuntime;\n} else {\n  // Remove the global property added by runtime.js.\n  try {\n    delete g.regeneratorRuntime;\n  } catch(e) {\n    g.regeneratorRuntime = undefined;\n  }\n}\n\n\n/***/ }),\n/* 279 */\n/***/ (function(module, exports) {\n\n/**\n * Copyright (c) 2014-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n!(function(global) {\n  \"use strict\";\n\n  var Op = Object.prototype;\n  var hasOwn = Op.hasOwnProperty;\n  var undefined; // More compressible than void 0.\n  var $Symbol = typeof Symbol === \"function\" ? Symbol : {};\n  var iteratorSymbol = $Symbol.iterator || \"@@iterator\";\n  var asyncIteratorSymbol = $Symbol.asyncIterator || \"@@asyncIterator\";\n  var toStringTagSymbol = $Symbol.toStringTag || \"@@toStringTag\";\n\n  var inModule = typeof module === \"object\";\n  var runtime = global.regeneratorRuntime;\n  if (runtime) {\n    if (inModule) {\n      // If regeneratorRuntime is defined globally and we're in a module,\n      // make the exports object identical to regeneratorRuntime.\n      module.exports = runtime;\n    }\n    // Don't bother evaluating the rest of this file if the runtime was\n    // already defined globally.\n    return;\n  }\n\n  // Define the runtime globally (as expected by generated code) as either\n  // module.exports (if we're in a module) or a new, empty object.\n  runtime = global.regeneratorRuntime = inModule ? module.exports : {};\n\n  function wrap(innerFn, outerFn, self, tryLocsList) {\n    // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.\n    var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;\n    var generator = Object.create(protoGenerator.prototype);\n    var context = new Context(tryLocsList || []);\n\n    // The ._invoke method unifies the implementations of the .next,\n    // .throw, and .return methods.\n    generator._invoke = makeInvokeMethod(innerFn, self, context);\n\n    return generator;\n  }\n  runtime.wrap = wrap;\n\n  // Try/catch helper to minimize deoptimizations. Returns a completion\n  // record like context.tryEntries[i].completion. This interface could\n  // have been (and was previously) designed to take a closure to be\n  // invoked without arguments, but in all the cases we care about we\n  // already have an existing method we want to call, so there's no need\n  // to create a new function object. We can even get away with assuming\n  // the method takes exactly one argument, since that happens to be true\n  // in every case, so we don't have to touch the arguments object. The\n  // only additional allocation required is the completion record, which\n  // has a stable shape and so hopefully should be cheap to allocate.\n  function tryCatch(fn, obj, arg) {\n    try {\n      return { type: \"normal\", arg: fn.call(obj, arg) };\n    } catch (err) {\n      return { type: \"throw\", arg: err };\n    }\n  }\n\n  var GenStateSuspendedStart = \"suspendedStart\";\n  var GenStateSuspendedYield = \"suspendedYield\";\n  var GenStateExecuting = \"executing\";\n  var GenStateCompleted = \"completed\";\n\n  // Returning this object from the innerFn has the same effect as\n  // breaking out of the dispatch switch statement.\n  var ContinueSentinel = {};\n\n  // Dummy constructor functions that we use as the .constructor and\n  // .constructor.prototype properties for functions that return Generator\n  // objects. For full spec compliance, you may wish to configure your\n  // minifier not to mangle the names of these two functions.\n  function Generator() {}\n  function GeneratorFunction() {}\n  function GeneratorFunctionPrototype() {}\n\n  // This is a polyfill for %IteratorPrototype% for environments that\n  // don't natively support it.\n  var IteratorPrototype = {};\n  IteratorPrototype[iteratorSymbol] = function () {\n    return this;\n  };\n\n  var getProto = Object.getPrototypeOf;\n  var NativeIteratorPrototype = getProto && getProto(getProto(values([])));\n  if (NativeIteratorPrototype &&\n      NativeIteratorPrototype !== Op &&\n      hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {\n    // This environment has a native %IteratorPrototype%; use it instead\n    // of the polyfill.\n    IteratorPrototype = NativeIteratorPrototype;\n  }\n\n  var Gp = GeneratorFunctionPrototype.prototype =\n    Generator.prototype = Object.create(IteratorPrototype);\n  GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;\n  GeneratorFunctionPrototype.constructor = GeneratorFunction;\n  GeneratorFunctionPrototype[toStringTagSymbol] =\n    GeneratorFunction.displayName = \"GeneratorFunction\";\n\n  // Helper for defining the .next, .throw, and .return methods of the\n  // Iterator interface in terms of a single ._invoke method.\n  function defineIteratorMethods(prototype) {\n    [\"next\", \"throw\", \"return\"].forEach(function(method) {\n      prototype[method] = function(arg) {\n        return this._invoke(method, arg);\n      };\n    });\n  }\n\n  runtime.isGeneratorFunction = function(genFun) {\n    var ctor = typeof genFun === \"function\" && genFun.constructor;\n    return ctor\n      ? ctor === GeneratorFunction ||\n        // For the native GeneratorFunction constructor, the best we can\n        // do is to check its .name property.\n        (ctor.displayName || ctor.name) === \"GeneratorFunction\"\n      : false;\n  };\n\n  runtime.mark = function(genFun) {\n    if (Object.setPrototypeOf) {\n      Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);\n    } else {\n      genFun.__proto__ = GeneratorFunctionPrototype;\n      if (!(toStringTagSymbol in genFun)) {\n        genFun[toStringTagSymbol] = \"GeneratorFunction\";\n      }\n    }\n    genFun.prototype = Object.create(Gp);\n    return genFun;\n  };\n\n  // Within the body of any async function, `await x` is transformed to\n  // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test\n  // `hasOwn.call(value, \"__await\")` to determine if the yielded value is\n  // meant to be awaited.\n  runtime.awrap = function(arg) {\n    return { __await: arg };\n  };\n\n  function AsyncIterator(generator) {\n    function invoke(method, arg, resolve, reject) {\n      var record = tryCatch(generator[method], generator, arg);\n      if (record.type === \"throw\") {\n        reject(record.arg);\n      } else {\n        var result = record.arg;\n        var value = result.value;\n        if (value &&\n            typeof value === \"object\" &&\n            hasOwn.call(value, \"__await\")) {\n          return Promise.resolve(value.__await).then(function(value) {\n            invoke(\"next\", value, resolve, reject);\n          }, function(err) {\n            invoke(\"throw\", err, resolve, reject);\n          });\n        }\n\n        return Promise.resolve(value).then(function(unwrapped) {\n          // When a yielded Promise is resolved, its final value becomes\n          // the .value of the Promise<{value,done}> result for the\n          // current iteration. If the Promise is rejected, however, the\n          // result for this iteration will be rejected with the same\n          // reason. Note that rejections of yielded Promises are not\n          // thrown back into the generator function, as is the case\n          // when an awaited Promise is rejected. This difference in\n          // behavior between yield and await is important, because it\n          // allows the consumer to decide what to do with the yielded\n          // rejection (swallow it and continue, manually .throw it back\n          // into the generator, abandon iteration, whatever). With\n          // await, by contrast, there is no opportunity to examine the\n          // rejection reason outside the generator function, so the\n          // only option is to throw it from the await expression, and\n          // let the generator function handle the exception.\n          result.value = unwrapped;\n          resolve(result);\n        }, reject);\n      }\n    }\n\n    var previousPromise;\n\n    function enqueue(method, arg) {\n      function callInvokeWithMethodAndArg() {\n        return new Promise(function(resolve, reject) {\n          invoke(method, arg, resolve, reject);\n        });\n      }\n\n      return previousPromise =\n        // If enqueue has been called before, then we want to wait until\n        // all previous Promises have been resolved before calling invoke,\n        // so that results are always delivered in the correct order. If\n        // enqueue has not been called before, then it is important to\n        // call invoke immediately, without waiting on a callback to fire,\n        // so that the async generator function has the opportunity to do\n        // any necessary setup in a predictable way. This predictability\n        // is why the Promise constructor synchronously invokes its\n        // executor callback, and why async functions synchronously\n        // execute code before the first await. Since we implement simple\n        // async functions in terms of async generators, it is especially\n        // important to get this right, even though it requires care.\n        previousPromise ? previousPromise.then(\n          callInvokeWithMethodAndArg,\n          // Avoid propagating failures to Promises returned by later\n          // invocations of the iterator.\n          callInvokeWithMethodAndArg\n        ) : callInvokeWithMethodAndArg();\n    }\n\n    // Define the unified helper method that is used to implement .next,\n    // .throw, and .return (see defineIteratorMethods).\n    this._invoke = enqueue;\n  }\n\n  defineIteratorMethods(AsyncIterator.prototype);\n  AsyncIterator.prototype[asyncIteratorSymbol] = function () {\n    return this;\n  };\n  runtime.AsyncIterator = AsyncIterator;\n\n  // Note that simple async functions are implemented on top of\n  // AsyncIterator objects; they just return a Promise for the value of\n  // the final result produced by the iterator.\n  runtime.async = function(innerFn, outerFn, self, tryLocsList) {\n    var iter = new AsyncIterator(\n      wrap(innerFn, outerFn, self, tryLocsList)\n    );\n\n    return runtime.isGeneratorFunction(outerFn)\n      ? iter // If outerFn is a generator, return the full iterator.\n      : iter.next().then(function(result) {\n          return result.done ? result.value : iter.next();\n        });\n  };\n\n  function makeInvokeMethod(innerFn, self, context) {\n    var state = GenStateSuspendedStart;\n\n    return function invoke(method, arg) {\n      if (state === GenStateExecuting) {\n        throw new Error(\"Generator is already running\");\n      }\n\n      if (state === GenStateCompleted) {\n        if (method === \"throw\") {\n          throw arg;\n        }\n\n        // Be forgiving, per 25.3.3.3.3 of the spec:\n        // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume\n        return doneResult();\n      }\n\n      context.method = method;\n      context.arg = arg;\n\n      while (true) {\n        var delegate = context.delegate;\n        if (delegate) {\n          var delegateResult = maybeInvokeDelegate(delegate, context);\n          if (delegateResult) {\n            if (delegateResult === ContinueSentinel) continue;\n            return delegateResult;\n          }\n        }\n\n        if (context.method === \"next\") {\n          // Setting context._sent for legacy support of Babel's\n          // function.sent implementation.\n          context.sent = context._sent = context.arg;\n\n        } else if (context.method === \"throw\") {\n          if (state === GenStateSuspendedStart) {\n            state = GenStateCompleted;\n            throw context.arg;\n          }\n\n          context.dispatchException(context.arg);\n\n        } else if (context.method === \"return\") {\n          context.abrupt(\"return\", context.arg);\n        }\n\n        state = GenStateExecuting;\n\n        var record = tryCatch(innerFn, self, context);\n        if (record.type === \"normal\") {\n          // If an exception is thrown from innerFn, we leave state ===\n          // GenStateExecuting and loop back for another invocation.\n          state = context.done\n            ? GenStateCompleted\n            : GenStateSuspendedYield;\n\n          if (record.arg === ContinueSentinel) {\n            continue;\n          }\n\n          return {\n            value: record.arg,\n            done: context.done\n          };\n\n        } else if (record.type === \"throw\") {\n          state = GenStateCompleted;\n          // Dispatch the exception by looping back around to the\n          // context.dispatchException(context.arg) call above.\n          context.method = \"throw\";\n          context.arg = record.arg;\n        }\n      }\n    };\n  }\n\n  // Call delegate.iterator[context.method](context.arg) and handle the\n  // result, either by returning a { value, done } result from the\n  // delegate iterator, or by modifying context.method and context.arg,\n  // setting context.delegate to null, and returning the ContinueSentinel.\n  function maybeInvokeDelegate(delegate, context) {\n    var method = delegate.iterator[context.method];\n    if (method === undefined) {\n      // A .throw or .return when the delegate iterator has no .throw\n      // method always terminates the yield* loop.\n      context.delegate = null;\n\n      if (context.method === \"throw\") {\n        if (delegate.iterator.return) {\n          // If the delegate iterator has a return method, give it a\n          // chance to clean up.\n          context.method = \"return\";\n          context.arg = undefined;\n          maybeInvokeDelegate(delegate, context);\n\n          if (context.method === \"throw\") {\n            // If maybeInvokeDelegate(context) changed context.method from\n            // \"return\" to \"throw\", let that override the TypeError below.\n            return ContinueSentinel;\n          }\n        }\n\n        context.method = \"throw\";\n        context.arg = new TypeError(\n          \"The iterator does not provide a 'throw' method\");\n      }\n\n      return ContinueSentinel;\n    }\n\n    var record = tryCatch(method, delegate.iterator, context.arg);\n\n    if (record.type === \"throw\") {\n      context.method = \"throw\";\n      context.arg = record.arg;\n      context.delegate = null;\n      return ContinueSentinel;\n    }\n\n    var info = record.arg;\n\n    if (! info) {\n      context.method = \"throw\";\n      context.arg = new TypeError(\"iterator result is not an object\");\n      context.delegate = null;\n      return ContinueSentinel;\n    }\n\n    if (info.done) {\n      // Assign the result of the finished delegate to the temporary\n      // variable specified by delegate.resultName (see delegateYield).\n      context[delegate.resultName] = info.value;\n\n      // Resume execution at the desired location (see delegateYield).\n      context.next = delegate.nextLoc;\n\n      // If context.method was \"throw\" but the delegate handled the\n      // exception, let the outer generator proceed normally. If\n      // context.method was \"next\", forget context.arg since it has been\n      // \"consumed\" by the delegate iterator. If context.method was\n      // \"return\", allow the original .return call to continue in the\n      // outer generator.\n      if (context.method !== \"return\") {\n        context.method = \"next\";\n        context.arg = undefined;\n      }\n\n    } else {\n      // Re-yield the result returned by the delegate method.\n      return info;\n    }\n\n    // The delegate iterator is finished, so forget it and continue with\n    // the outer generator.\n    context.delegate = null;\n    return ContinueSentinel;\n  }\n\n  // Define Generator.prototype.{next,throw,return} in terms of the\n  // unified ._invoke helper method.\n  defineIteratorMethods(Gp);\n\n  Gp[toStringTagSymbol] = \"Generator\";\n\n  // A Generator should always return itself as the iterator object when the\n  // @@iterator function is called on it. Some browsers' implementations of the\n  // iterator prototype chain incorrectly implement this, causing the Generator\n  // object to not be returned from this call. This ensures that doesn't happen.\n  // See https://github.com/facebook/regenerator/issues/274 for more details.\n  Gp[iteratorSymbol] = function() {\n    return this;\n  };\n\n  Gp.toString = function() {\n    return \"[object Generator]\";\n  };\n\n  function pushTryEntry(locs) {\n    var entry = { tryLoc: locs[0] };\n\n    if (1 in locs) {\n      entry.catchLoc = locs[1];\n    }\n\n    if (2 in locs) {\n      entry.finallyLoc = locs[2];\n      entry.afterLoc = locs[3];\n    }\n\n    this.tryEntries.push(entry);\n  }\n\n  function resetTryEntry(entry) {\n    var record = entry.completion || {};\n    record.type = \"normal\";\n    delete record.arg;\n    entry.completion = record;\n  }\n\n  function Context(tryLocsList) {\n    // The root entry object (effectively a try statement without a catch\n    // or a finally block) gives us a place to store values thrown from\n    // locations where there is no enclosing try statement.\n    this.tryEntries = [{ tryLoc: \"root\" }];\n    tryLocsList.forEach(pushTryEntry, this);\n    this.reset(true);\n  }\n\n  runtime.keys = function(object) {\n    var keys = [];\n    for (var key in object) {\n      keys.push(key);\n    }\n    keys.reverse();\n\n    // Rather than returning an object with a next method, we keep\n    // things simple and return the next function itself.\n    return function next() {\n      while (keys.length) {\n        var key = keys.pop();\n        if (key in object) {\n          next.value = key;\n          next.done = false;\n          return next;\n        }\n      }\n\n      // To avoid creating an additional object, we just hang the .value\n      // and .done properties off the next function object itself. This\n      // also ensures that the minifier will not anonymize the function.\n      next.done = true;\n      return next;\n    };\n  };\n\n  function values(iterable) {\n    if (iterable) {\n      var iteratorMethod = iterable[iteratorSymbol];\n      if (iteratorMethod) {\n        return iteratorMethod.call(iterable);\n      }\n\n      if (typeof iterable.next === \"function\") {\n        return iterable;\n      }\n\n      if (!isNaN(iterable.length)) {\n        var i = -1, next = function next() {\n          while (++i < iterable.length) {\n            if (hasOwn.call(iterable, i)) {\n              next.value = iterable[i];\n              next.done = false;\n              return next;\n            }\n          }\n\n          next.value = undefined;\n          next.done = true;\n\n          return next;\n        };\n\n        return next.next = next;\n      }\n    }\n\n    // Return an iterator with no values.\n    return { next: doneResult };\n  }\n  runtime.values = values;\n\n  function doneResult() {\n    return { value: undefined, done: true };\n  }\n\n  Context.prototype = {\n    constructor: Context,\n\n    reset: function(skipTempReset) {\n      this.prev = 0;\n      this.next = 0;\n      // Resetting context._sent for legacy support of Babel's\n      // function.sent implementation.\n      this.sent = this._sent = undefined;\n      this.done = false;\n      this.delegate = null;\n\n      this.method = \"next\";\n      this.arg = undefined;\n\n      this.tryEntries.forEach(resetTryEntry);\n\n      if (!skipTempReset) {\n        for (var name in this) {\n          // Not sure about the optimal order of these conditions:\n          if (name.charAt(0) === \"t\" &&\n              hasOwn.call(this, name) &&\n              !isNaN(+name.slice(1))) {\n            this[name] = undefined;\n          }\n        }\n      }\n    },\n\n    stop: function() {\n      this.done = true;\n\n      var rootEntry = this.tryEntries[0];\n      var rootRecord = rootEntry.completion;\n      if (rootRecord.type === \"throw\") {\n        throw rootRecord.arg;\n      }\n\n      return this.rval;\n    },\n\n    dispatchException: function(exception) {\n      if (this.done) {\n        throw exception;\n      }\n\n      var context = this;\n      function handle(loc, caught) {\n        record.type = \"throw\";\n        record.arg = exception;\n        context.next = loc;\n\n        if (caught) {\n          // If the dispatched exception was caught by a catch block,\n          // then let that catch block handle the exception normally.\n          context.method = \"next\";\n          context.arg = undefined;\n        }\n\n        return !! caught;\n      }\n\n      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n        var entry = this.tryEntries[i];\n        var record = entry.completion;\n\n        if (entry.tryLoc === \"root\") {\n          // Exception thrown outside of any try block that could handle\n          // it, so set the completion value of the entire function to\n          // throw the exception.\n          return handle(\"end\");\n        }\n\n        if (entry.tryLoc <= this.prev) {\n          var hasCatch = hasOwn.call(entry, \"catchLoc\");\n          var hasFinally = hasOwn.call(entry, \"finallyLoc\");\n\n          if (hasCatch && hasFinally) {\n            if (this.prev < entry.catchLoc) {\n              return handle(entry.catchLoc, true);\n            } else if (this.prev < entry.finallyLoc) {\n              return handle(entry.finallyLoc);\n            }\n\n          } else if (hasCatch) {\n            if (this.prev < entry.catchLoc) {\n              return handle(entry.catchLoc, true);\n            }\n\n          } else if (hasFinally) {\n            if (this.prev < entry.finallyLoc) {\n              return handle(entry.finallyLoc);\n            }\n\n          } else {\n            throw new Error(\"try statement without catch or finally\");\n          }\n        }\n      }\n    },\n\n    abrupt: function(type, arg) {\n      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n        var entry = this.tryEntries[i];\n        if (entry.tryLoc <= this.prev &&\n            hasOwn.call(entry, \"finallyLoc\") &&\n            this.prev < entry.finallyLoc) {\n          var finallyEntry = entry;\n          break;\n        }\n      }\n\n      if (finallyEntry &&\n          (type === \"break\" ||\n           type === \"continue\") &&\n          finallyEntry.tryLoc <= arg &&\n          arg <= finallyEntry.finallyLoc) {\n        // Ignore the finally entry if control is not jumping to a\n        // location outside the try/catch block.\n        finallyEntry = null;\n      }\n\n      var record = finallyEntry ? finallyEntry.completion : {};\n      record.type = type;\n      record.arg = arg;\n\n      if (finallyEntry) {\n        this.method = \"next\";\n        this.next = finallyEntry.finallyLoc;\n        return ContinueSentinel;\n      }\n\n      return this.complete(record);\n    },\n\n    complete: function(record, afterLoc) {\n      if (record.type === \"throw\") {\n        throw record.arg;\n      }\n\n      if (record.type === \"break\" ||\n          record.type === \"continue\") {\n        this.next = record.arg;\n      } else if (record.type === \"return\") {\n        this.rval = this.arg = record.arg;\n        this.method = \"return\";\n        this.next = \"end\";\n      } else if (record.type === \"normal\" && afterLoc) {\n        this.next = afterLoc;\n      }\n\n      return ContinueSentinel;\n    },\n\n    finish: function(finallyLoc) {\n      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n        var entry = this.tryEntries[i];\n        if (entry.finallyLoc === finallyLoc) {\n          this.complete(entry.completion, entry.afterLoc);\n          resetTryEntry(entry);\n          return ContinueSentinel;\n        }\n      }\n    },\n\n    \"catch\": function(tryLoc) {\n      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n        var entry = this.tryEntries[i];\n        if (entry.tryLoc === tryLoc) {\n          var record = entry.completion;\n          if (record.type === \"throw\") {\n            var thrown = record.arg;\n            resetTryEntry(entry);\n          }\n          return thrown;\n        }\n      }\n\n      // The context.catch method must only be called with a location\n      // argument that corresponds to a known catch block.\n      throw new Error(\"illegal catch attempt\");\n    },\n\n    delegateYield: function(iterable, resultName, nextLoc) {\n      this.delegate = {\n        iterator: values(iterable),\n        resultName: resultName,\n        nextLoc: nextLoc\n      };\n\n      if (this.method === \"next\") {\n        // Deliberately forget the last sent value so that we don't\n        // accidentally pass it on to the delegate.\n        this.arg = undefined;\n      }\n\n      return ContinueSentinel;\n    }\n  };\n})(\n  // In sloppy mode, unbound `this` refers to the global object, fallback to\n  // Function constructor if we're in global strict mode. That is sadly a form\n  // of indirect eval which violates Content Security Policy.\n  (function() { return this })() || Function(\"return this\")()\n);\n\n\n/***/ }),\n/* 280 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(281), __esModule: true };\n\n/***/ }),\n/* 281 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(282);\nmodule.exports = Math.pow(2, -52);\n\n\n/***/ }),\n/* 282 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 20.1.2.1 Number.EPSILON\nvar $export = __webpack_require__(3);\n\n$export($export.S, 'Number', { EPSILON: Math.pow(2, -52) });\n\n\n/***/ }),\n/* 283 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {var clone = (function() {\n'use strict';\n\n/**\n * Clones (copies) an Object using deep copying.\n *\n * This function supports circular references by default, but if you are certain\n * there are no circular references in your object, you can save some CPU time\n * by calling clone(obj, false).\n *\n * Caution: if `circular` is false and `parent` contains circular references,\n * your program may enter an infinite loop and crash.\n *\n * @param `parent` - the object to be cloned\n * @param `circular` - set to true if the object to be cloned may contain\n *    circular references. (optional - true by default)\n * @param `depth` - set to a number if the object is only to be cloned to\n *    a particular depth. (optional - defaults to Infinity)\n * @param `prototype` - sets the prototype to be used when cloning an object.\n *    (optional - defaults to parent prototype).\n*/\nfunction clone(parent, circular, depth, prototype) {\n  var filter;\n  if (typeof circular === 'object') {\n    depth = circular.depth;\n    prototype = circular.prototype;\n    filter = circular.filter;\n    circular = circular.circular\n  }\n  // maintain two arrays for circular references, where corresponding parents\n  // and children have the same index\n  var allParents = [];\n  var allChildren = [];\n\n  var useBuffer = typeof Buffer != 'undefined';\n\n  if (typeof circular == 'undefined')\n    circular = true;\n\n  if (typeof depth == 'undefined')\n    depth = Infinity;\n\n  // recurse this function so we don't reset allParents and allChildren\n  function _clone(parent, depth) {\n    // cloning null always returns null\n    if (parent === null)\n      return null;\n\n    if (depth == 0)\n      return parent;\n\n    var child;\n    var proto;\n    if (typeof parent != 'object') {\n      return parent;\n    }\n\n    if (clone.__isArray(parent)) {\n      child = [];\n    } else if (clone.__isRegExp(parent)) {\n      child = new RegExp(parent.source, __getRegExpFlags(parent));\n      if (parent.lastIndex) child.lastIndex = parent.lastIndex;\n    } else if (clone.__isDate(parent)) {\n      child = new Date(parent.getTime());\n    } else if (useBuffer && Buffer.isBuffer(parent)) {\n      child = new Buffer(parent.length);\n      parent.copy(child);\n      return child;\n    } else {\n      if (typeof prototype == 'undefined') {\n        proto = Object.getPrototypeOf(parent);\n        child = Object.create(proto);\n      }\n      else {\n        child = Object.create(prototype);\n        proto = prototype;\n      }\n    }\n\n    if (circular) {\n      var index = allParents.indexOf(parent);\n\n      if (index != -1) {\n        return allChildren[index];\n      }\n      allParents.push(parent);\n      allChildren.push(child);\n    }\n\n    for (var i in parent) {\n      var attrs;\n      if (proto) {\n        attrs = Object.getOwnPropertyDescriptor(proto, i);\n      }\n\n      if (attrs && attrs.set == null) {\n        continue;\n      }\n      child[i] = _clone(parent[i], depth - 1);\n    }\n\n    return child;\n  }\n\n  return _clone(parent, depth);\n}\n\n/**\n * Simple flat clone using prototype, accepts only objects, usefull for property\n * override on FLAT configuration object (no nested props).\n *\n * USE WITH CAUTION! This may not behave as you wish if you do not know how this\n * works.\n */\nclone.clonePrototype = function clonePrototype(parent) {\n  if (parent === null)\n    return null;\n\n  var c = function () {};\n  c.prototype = parent;\n  return new c();\n};\n\n// private utility functions\n\nfunction __objToStr(o) {\n  return Object.prototype.toString.call(o);\n};\nclone.__objToStr = __objToStr;\n\nfunction __isDate(o) {\n  return typeof o === 'object' && __objToStr(o) === '[object Date]';\n};\nclone.__isDate = __isDate;\n\nfunction __isArray(o) {\n  return typeof o === 'object' && __objToStr(o) === '[object Array]';\n};\nclone.__isArray = __isArray;\n\nfunction __isRegExp(o) {\n  return typeof o === 'object' && __objToStr(o) === '[object RegExp]';\n};\nclone.__isRegExp = __isRegExp;\n\nfunction __getRegExpFlags(re) {\n  var flags = '';\n  if (re.global) flags += 'g';\n  if (re.ignoreCase) flags += 'i';\n  if (re.multiline) flags += 'm';\n  return flags;\n};\nclone.__getRegExpFlags = __getRegExpFlags;\n\nreturn clone;\n})();\n\nif (typeof module === 'object' && module.exports) {\n  module.exports = clone;\n}\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 284 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(117).BrotliDecompressBuffer;\n\n\n/***/ }),\n/* 285 */\n/***/ (function(module, exports) {\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n   Bit reading helpers\n*/\n\nvar BROTLI_READ_SIZE = 4096;\nvar BROTLI_IBUF_SIZE =  (2 * BROTLI_READ_SIZE + 32);\nvar BROTLI_IBUF_MASK =  (2 * BROTLI_READ_SIZE - 1);\n\nvar kBitMask = new Uint32Array([\n  0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767,\n  65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215\n]);\n\n/* Input byte buffer, consist of a ringbuffer and a \"slack\" region where */\n/* bytes from the start of the ringbuffer are copied. */\nfunction BrotliBitReader(input) {\n  this.buf_ = new Uint8Array(BROTLI_IBUF_SIZE);\n  this.input_ = input;    /* input callback */\n  \n  this.reset();\n}\n\nBrotliBitReader.READ_SIZE = BROTLI_READ_SIZE;\nBrotliBitReader.IBUF_MASK = BROTLI_IBUF_MASK;\n\nBrotliBitReader.prototype.reset = function() {\n  this.buf_ptr_ = 0;      /* next input will write here */\n  this.val_ = 0;          /* pre-fetched bits */\n  this.pos_ = 0;          /* byte position in stream */\n  this.bit_pos_ = 0;      /* current bit-reading position in val_ */\n  this.bit_end_pos_ = 0;  /* bit-reading end position from LSB of val_ */\n  this.eos_ = 0;          /* input stream is finished */\n  \n  this.readMoreInput();\n  for (var i = 0; i < 4; i++) {\n    this.val_ |= this.buf_[this.pos_] << (8 * i);\n    ++this.pos_;\n  }\n  \n  return this.bit_end_pos_ > 0;\n};\n\n/* Fills up the input ringbuffer by calling the input callback.\n\n   Does nothing if there are at least 32 bytes present after current position.\n\n   Returns 0 if either:\n    - the input callback returned an error, or\n    - there is no more input and the position is past the end of the stream.\n\n   After encountering the end of the input stream, 32 additional zero bytes are\n   copied to the ringbuffer, therefore it is safe to call this function after\n   every 32 bytes of input is read.\n*/\nBrotliBitReader.prototype.readMoreInput = function() {\n  if (this.bit_end_pos_ > 256) {\n    return;\n  } else if (this.eos_) {\n    if (this.bit_pos_ > this.bit_end_pos_)\n      throw new Error('Unexpected end of input ' + this.bit_pos_ + ' ' + this.bit_end_pos_);\n  } else {\n    var dst = this.buf_ptr_;\n    var bytes_read = this.input_.read(this.buf_, dst, BROTLI_READ_SIZE);\n    if (bytes_read < 0) {\n      throw new Error('Unexpected end of input');\n    }\n    \n    if (bytes_read < BROTLI_READ_SIZE) {\n      this.eos_ = 1;\n      /* Store 32 bytes of zero after the stream end. */\n      for (var p = 0; p < 32; p++)\n        this.buf_[dst + bytes_read + p] = 0;\n    }\n    \n    if (dst === 0) {\n      /* Copy the head of the ringbuffer to the slack region. */\n      for (var p = 0; p < 32; p++)\n        this.buf_[(BROTLI_READ_SIZE << 1) + p] = this.buf_[p];\n\n      this.buf_ptr_ = BROTLI_READ_SIZE;\n    } else {\n      this.buf_ptr_ = 0;\n    }\n    \n    this.bit_end_pos_ += bytes_read << 3;\n  }\n};\n\n/* Guarantees that there are at least 24 bits in the buffer. */\nBrotliBitReader.prototype.fillBitWindow = function() {    \n  while (this.bit_pos_ >= 8) {\n    this.val_ >>>= 8;\n    this.val_ |= this.buf_[this.pos_ & BROTLI_IBUF_MASK] << 24;\n    ++this.pos_;\n    this.bit_pos_ = this.bit_pos_ - 8 >>> 0;\n    this.bit_end_pos_ = this.bit_end_pos_ - 8 >>> 0;\n  }\n};\n\n/* Reads the specified number of bits from Read Buffer. */\nBrotliBitReader.prototype.readBits = function(n_bits) {\n  if (32 - this.bit_pos_ < n_bits) {\n    this.fillBitWindow();\n  }\n  \n  var val = ((this.val_ >>> this.bit_pos_) & kBitMask[n_bits]);\n  this.bit_pos_ += n_bits;\n  return val;\n};\n\nmodule.exports = BrotliBitReader;\n\n\n/***/ }),\n/* 286 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar base64 = __webpack_require__(287);\nvar fs = __webpack_require__(8);\n\n/**\n * The normal dictionary-data.js is quite large, which makes it \n * unsuitable for browser usage. In order to make it smaller, \n * we read dictionary.bin, which is a compressed version of\n * the dictionary, and on initial load, Brotli decompresses \n * it's own dictionary. 😜\n */\nexports.init = function() {\n  var BrotliDecompressBuffer = __webpack_require__(117).BrotliDecompressBuffer;\n  var compressed = base64.toByteArray(__webpack_require__(288));\n  return BrotliDecompressBuffer(compressed);\n};\n\n\n/***/ }),\n/* 287 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.byteLength = byteLength\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nvar code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\nfor (var i = 0, len = code.length; i < len; ++i) {\n  lookup[i] = code[i]\n  revLookup[code.charCodeAt(i)] = i\n}\n\n// Support decoding URL-safe base64 strings, as Node.js does.\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\nrevLookup['-'.charCodeAt(0)] = 62\nrevLookup['_'.charCodeAt(0)] = 63\n\nfunction placeHoldersCount (b64) {\n  var len = b64.length\n  if (len % 4 > 0) {\n    throw new Error('Invalid string. Length must be a multiple of 4')\n  }\n\n  // the number of equal signs (place holders)\n  // if there are two placeholders, than the two characters before it\n  // represent one byte\n  // if there is only one, then the three characters before it represent 2 bytes\n  // this is just a cheap hack to not do indexOf twice\n  return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0\n}\n\nfunction byteLength (b64) {\n  // base64 is 4/3 + up to two characters of the original data\n  return (b64.length * 3 / 4) - placeHoldersCount(b64)\n}\n\nfunction toByteArray (b64) {\n  var i, l, tmp, placeHolders, arr\n  var len = b64.length\n  placeHolders = placeHoldersCount(b64)\n\n  arr = new Arr((len * 3 / 4) - placeHolders)\n\n  // if there are placeholders, only get up to the last complete 4 chars\n  l = placeHolders > 0 ? len - 4 : len\n\n  var L = 0\n\n  for (i = 0; i < l; i += 4) {\n    tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]\n    arr[L++] = (tmp >> 16) & 0xFF\n    arr[L++] = (tmp >> 8) & 0xFF\n    arr[L++] = tmp & 0xFF\n  }\n\n  if (placeHolders === 2) {\n    tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)\n    arr[L++] = tmp & 0xFF\n  } else if (placeHolders === 1) {\n    tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)\n    arr[L++] = (tmp >> 8) & 0xFF\n    arr[L++] = tmp & 0xFF\n  }\n\n  return arr\n}\n\nfunction tripletToBase64 (num) {\n  return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n  var tmp\n  var output = []\n  for (var i = start; i < end; i += 3) {\n    tmp = ((uint8[i] << 16) & 0xFF0000) + ((uint8[i + 1] << 8) & 0xFF00) + (uint8[i + 2] & 0xFF)\n    output.push(tripletToBase64(tmp))\n  }\n  return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n  var tmp\n  var len = uint8.length\n  var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n  var output = ''\n  var parts = []\n  var maxChunkLength = 16383 // must be multiple of 3\n\n  // go through the array every three bytes, we'll deal with trailing stuff later\n  for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n    parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n  }\n\n  // pad the end with zeros, but make sure to not forget the extra bytes\n  if (extraBytes === 1) {\n    tmp = uint8[len - 1]\n    output += lookup[tmp >> 2]\n    output += lookup[(tmp << 4) & 0x3F]\n    output += '=='\n  } else if (extraBytes === 2) {\n    tmp = (uint8[len - 2] << 8) + (uint8[len - 1])\n    output += lookup[tmp >> 10]\n    output += lookup[(tmp >> 4) & 0x3F]\n    output += lookup[(tmp << 2) & 0x3F]\n    output += '='\n  }\n\n  parts.push(output)\n\n  return parts.join('')\n}\n\n\n/***/ }),\n/* 288 */\n/***/ (function(module, exports) {\n\nmodule.exports=\"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\";\n\n\n/***/ }),\n/* 289 */\n/***/ (function(module, exports) {\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n   Lookup table to map the previous two bytes to a context id.\n\n   There are four different context modeling modes defined here:\n     CONTEXT_LSB6: context id is the least significant 6 bits of the last byte,\n     CONTEXT_MSB6: context id is the most significant 6 bits of the last byte,\n     CONTEXT_UTF8: second-order context model tuned for UTF8-encoded text,\n     CONTEXT_SIGNED: second-order context model tuned for signed integers.\n\n   The context id for the UTF8 context model is calculated as follows. If p1\n   and p2 are the previous two bytes, we calcualte the context as\n\n     context = kContextLookup[p1] | kContextLookup[p2 + 256].\n\n   If the previous two bytes are ASCII characters (i.e. < 128), this will be\n   equivalent to\n\n     context = 4 * context1(p1) + context2(p2),\n\n   where context1 is based on the previous byte in the following way:\n\n     0  : non-ASCII control\n     1  : \\t, \\n, \\r\n     2  : space\n     3  : other punctuation\n     4  : \" '\n     5  : %\n     6  : ( < [ {\n     7  : ) > ] }\n     8  : , ; :\n     9  : .\n     10 : =\n     11 : number\n     12 : upper-case vowel\n     13 : upper-case consonant\n     14 : lower-case vowel\n     15 : lower-case consonant\n\n   and context2 is based on the second last byte:\n\n     0 : control, space\n     1 : punctuation\n     2 : upper-case letter, number\n     3 : lower-case letter\n\n   If the last byte is ASCII, and the second last byte is not (in a valid UTF8\n   stream it will be a continuation byte, value between 128 and 191), the\n   context is the same as if the second last byte was an ASCII control or space.\n\n   If the last byte is a UTF8 lead byte (value >= 192), then the next byte will\n   be a continuation byte and the context id is 2 or 3 depending on the LSB of\n   the last byte and to a lesser extent on the second last byte if it is ASCII.\n\n   If the last byte is a UTF8 continuation byte, the second last byte can be:\n     - continuation byte: the next byte is probably ASCII or lead byte (assuming\n       4-byte UTF8 characters are rare) and the context id is 0 or 1.\n     - lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1\n     - lead byte (208 - 255): next byte is continuation byte, context is 2 or 3\n\n   The possible value combinations of the previous two bytes, the range of\n   context ids and the type of the next byte is summarized in the table below:\n\n   |--------\\-----------------------------------------------------------------|\n   |         \\                         Last byte                              |\n   | Second   \\---------------------------------------------------------------|\n   | last byte \\    ASCII            |   cont. byte        |   lead byte      |\n   |            \\   (0-127)          |   (128-191)         |   (192-)         |\n   |=============|===================|=====================|==================|\n   |  ASCII      | next: ASCII/lead  |  not valid          |  next: cont.     |\n   |  (0-127)    | context: 4 - 63   |                     |  context: 2 - 3  |\n   |-------------|-------------------|---------------------|------------------|\n   |  cont. byte | next: ASCII/lead  |  next: ASCII/lead   |  next: cont.     |\n   |  (128-191)  | context: 4 - 63   |  context: 0 - 1     |  context: 2 - 3  |\n   |-------------|-------------------|---------------------|------------------|\n   |  lead byte  | not valid         |  next: ASCII/lead   |  not valid       |\n   |  (192-207)  |                   |  context: 0 - 1     |                  |\n   |-------------|-------------------|---------------------|------------------|\n   |  lead byte  | not valid         |  next: cont.        |  not valid       |\n   |  (208-)     |                   |  context: 2 - 3     |                  |\n   |-------------|-------------------|---------------------|------------------|\n\n   The context id for the signed context mode is calculated as:\n\n     context = (kContextLookup[512 + p1] << 3) | kContextLookup[512 + p2].\n\n   For any context modeling modes, the context ids can be calculated by |-ing\n   together two lookups from one table using context model dependent offsets:\n\n     context = kContextLookup[offset1 + p1] | kContextLookup[offset2 + p2].\n\n   where offset1 and offset2 are dependent on the context mode.\n*/\n\nvar CONTEXT_LSB6         = 0;\nvar CONTEXT_MSB6         = 1;\nvar CONTEXT_UTF8         = 2;\nvar CONTEXT_SIGNED       = 3;\n\n/* Common context lookup table for all context modes. */\nexports.lookup = new Uint8Array([\n  /* CONTEXT_UTF8, last byte. */\n  /* ASCII range. */\n   0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  4,  0,  0,  4,  0,  0,\n   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,\n   8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,\n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,\n  12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,\n  52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,\n  12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,\n  60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12,  0,\n  /* UTF8 continuation byte range. */\n  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,\n  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,\n  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,\n  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,\n  /* UTF8 lead byte range. */\n  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,\n  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,\n  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,\n  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,\n  /* CONTEXT_UTF8 second last byte. */\n  /* ASCII range. */\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,\n  1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,\n  1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0,\n  /* UTF8 continuation byte range. */\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  /* UTF8 lead byte range. */\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n  /* CONTEXT_SIGNED, second last byte. */\n  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,\n  /* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */\n   0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,\n  16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,\n  16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,\n  16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,\n  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,\n  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,\n  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,\n  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,\n  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,\n  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,\n  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,\n  48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56,\n  /* CONTEXT_LSB6, last byte. */\n   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,\n  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,\n  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\n   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,\n  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,\n  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\n   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,\n  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,\n  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\n   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,\n  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,\n  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\n  /* CONTEXT_MSB6, last byte. */\n   0,  0,  0,  0,  1,  1,  1,  1,  2,  2,  2,  2,  3,  3,  3,  3,\n   4,  4,  4,  4,  5,  5,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,\n   8,  8,  8,  8,  9,  9,  9,  9, 10, 10, 10, 10, 11, 11, 11, 11,\n  12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,\n  16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,\n  20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,\n  24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,\n  28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,\n  32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,\n  36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,\n  40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,\n  44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,\n  48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,\n  52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,\n  56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,\n  60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,\n  /* CONTEXT_{M,L}SB6, second last byte, */\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n]);\n\nexports.lookupOffsets = new Uint16Array([\n  /* CONTEXT_LSB6 */\n  1024, 1536,\n  /* CONTEXT_MSB6 */\n  1280, 1536,\n  /* CONTEXT_UTF8 */\n  0, 256,\n  /* CONTEXT_SIGNED */\n  768, 512,\n]);\n\n\n/***/ }),\n/* 290 */\n/***/ (function(module, exports) {\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n   Lookup tables to map prefix codes to value ranges. This is used during\n   decoding of the block lengths, literal insertion lengths and copy lengths.\n*/\n\n/* Represents the range of values belonging to a prefix code: */\n/* [offset, offset + 2^nbits) */\nfunction PrefixCodeRange(offset, nbits) {\n  this.offset = offset;\n  this.nbits = nbits;\n}\n\nexports.kBlockLengthPrefixCode = [\n  new PrefixCodeRange(1, 2), new PrefixCodeRange(5, 2), new PrefixCodeRange(9, 2), new PrefixCodeRange(13, 2),\n  new PrefixCodeRange(17, 3), new PrefixCodeRange(25, 3), new PrefixCodeRange(33, 3), new PrefixCodeRange(41, 3),\n  new PrefixCodeRange(49, 4), new PrefixCodeRange(65, 4), new PrefixCodeRange(81, 4), new PrefixCodeRange(97, 4),\n  new PrefixCodeRange(113, 5), new PrefixCodeRange(145, 5), new PrefixCodeRange(177, 5), new PrefixCodeRange(209, 5),\n  new PrefixCodeRange(241, 6), new PrefixCodeRange(305, 6), new PrefixCodeRange(369, 7), new PrefixCodeRange(497, 8),\n  new PrefixCodeRange(753, 9), new PrefixCodeRange(1265, 10), new PrefixCodeRange(2289, 11), new PrefixCodeRange(4337, 12),\n  new PrefixCodeRange(8433, 13), new PrefixCodeRange(16625, 24)\n];\n\nexports.kInsertLengthPrefixCode = [\n  new PrefixCodeRange(0, 0), new PrefixCodeRange(1, 0), new PrefixCodeRange(2, 0), new PrefixCodeRange(3, 0),\n  new PrefixCodeRange(4, 0), new PrefixCodeRange(5, 0), new PrefixCodeRange(6, 1), new PrefixCodeRange(8, 1),\n  new PrefixCodeRange(10, 2), new PrefixCodeRange(14, 2), new PrefixCodeRange(18, 3), new PrefixCodeRange(26, 3),\n  new PrefixCodeRange(34, 4), new PrefixCodeRange(50, 4), new PrefixCodeRange(66, 5), new PrefixCodeRange(98, 5),\n  new PrefixCodeRange(130, 6), new PrefixCodeRange(194, 7), new PrefixCodeRange(322, 8), new PrefixCodeRange(578, 9),\n  new PrefixCodeRange(1090, 10), new PrefixCodeRange(2114, 12), new PrefixCodeRange(6210, 14), new PrefixCodeRange(22594, 24),\n];\n\nexports.kCopyLengthPrefixCode = [\n  new PrefixCodeRange(2, 0), new PrefixCodeRange(3, 0), new PrefixCodeRange(4, 0), new PrefixCodeRange(5, 0),\n  new PrefixCodeRange(6, 0), new PrefixCodeRange(7, 0), new PrefixCodeRange(8, 0), new PrefixCodeRange(9, 0),\n  new PrefixCodeRange(10, 1), new PrefixCodeRange(12, 1), new PrefixCodeRange(14, 2), new PrefixCodeRange(18, 2),\n  new PrefixCodeRange(22, 3), new PrefixCodeRange(30, 3), new PrefixCodeRange(38, 4), new PrefixCodeRange(54, 4),\n  new PrefixCodeRange(70, 5), new PrefixCodeRange(102, 5), new PrefixCodeRange(134, 6), new PrefixCodeRange(198, 7),\n  new PrefixCodeRange(326, 8), new PrefixCodeRange(582, 9), new PrefixCodeRange(1094, 10), new PrefixCodeRange(2118, 24),\n];\n\nexports.kInsertRangeLut = [\n  0, 0, 8, 8, 0, 16, 8, 16, 16,\n];\n\nexports.kCopyRangeLut = [\n  0, 8, 0, 8, 16, 0, 16, 8, 16,\n];\n\n\n/***/ }),\n/* 291 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n   Transformations on dictionary words.\n*/\n\nvar BrotliDictionary = __webpack_require__(119);\n\nvar kIdentity       = 0;\nvar kOmitLast1      = 1;\nvar kOmitLast2      = 2;\nvar kOmitLast3      = 3;\nvar kOmitLast4      = 4;\nvar kOmitLast5      = 5;\nvar kOmitLast6      = 6;\nvar kOmitLast7      = 7;\nvar kOmitLast8      = 8;\nvar kOmitLast9      = 9;\nvar kUppercaseFirst = 10;\nvar kUppercaseAll   = 11;\nvar kOmitFirst1     = 12;\nvar kOmitFirst2     = 13;\nvar kOmitFirst3     = 14;\nvar kOmitFirst4     = 15;\nvar kOmitFirst5     = 16;\nvar kOmitFirst6     = 17;\nvar kOmitFirst7     = 18;\nvar kOmitFirst8     = 19;\nvar kOmitFirst9     = 20;\n\nfunction Transform(prefix, transform, suffix) {\n  this.prefix = new Uint8Array(prefix.length);\n  this.transform = transform;\n  this.suffix = new Uint8Array(suffix.length);\n  \n  for (var i = 0; i < prefix.length; i++)\n    this.prefix[i] = prefix.charCodeAt(i);\n  \n  for (var i = 0; i < suffix.length; i++)\n    this.suffix[i] = suffix.charCodeAt(i);\n}\n\nvar kTransforms = [\n     new Transform(         \"\", kIdentity,       \"\"           ),\n     new Transform(         \"\", kIdentity,       \" \"          ),\n     new Transform(        \" \", kIdentity,       \" \"          ),\n     new Transform(         \"\", kOmitFirst1,     \"\"           ),\n     new Transform(         \"\", kUppercaseFirst, \" \"          ),\n     new Transform(         \"\", kIdentity,       \" the \"      ),\n     new Transform(        \" \", kIdentity,       \"\"           ),\n     new Transform(       \"s \", kIdentity,       \" \"          ),\n     new Transform(         \"\", kIdentity,       \" of \"       ),\n     new Transform(         \"\", kUppercaseFirst, \"\"           ),\n     new Transform(         \"\", kIdentity,       \" and \"      ),\n     new Transform(         \"\", kOmitFirst2,     \"\"           ),\n     new Transform(         \"\", kOmitLast1,      \"\"           ),\n     new Transform(       \", \", kIdentity,       \" \"          ),\n     new Transform(         \"\", kIdentity,       \", \"         ),\n     new Transform(        \" \", kUppercaseFirst, \" \"          ),\n     new Transform(         \"\", kIdentity,       \" in \"       ),\n     new Transform(         \"\", kIdentity,       \" to \"       ),\n     new Transform(       \"e \", kIdentity,       \" \"          ),\n     new Transform(         \"\", kIdentity,       \"\\\"\"         ),\n     new Transform(         \"\", kIdentity,       \".\"          ),\n     new Transform(         \"\", kIdentity,       \"\\\">\"        ),\n     new Transform(         \"\", kIdentity,       \"\\n\"         ),\n     new Transform(         \"\", kOmitLast3,      \"\"           ),\n     new Transform(         \"\", kIdentity,       \"]\"          ),\n     new Transform(         \"\", kIdentity,       \" for \"      ),\n     new Transform(         \"\", kOmitFirst3,     \"\"           ),\n     new Transform(         \"\", kOmitLast2,      \"\"           ),\n     new Transform(         \"\", kIdentity,       \" a \"        ),\n     new Transform(         \"\", kIdentity,       \" that \"     ),\n     new Transform(        \" \", kUppercaseFirst, \"\"           ),\n     new Transform(         \"\", kIdentity,       \". \"         ),\n     new Transform(        \".\", kIdentity,       \"\"           ),\n     new Transform(        \" \", kIdentity,       \", \"         ),\n     new Transform(         \"\", kOmitFirst4,     \"\"           ),\n     new Transform(         \"\", kIdentity,       \" with \"     ),\n     new Transform(         \"\", kIdentity,       \"'\"          ),\n     new Transform(         \"\", kIdentity,       \" from \"     ),\n     new Transform(         \"\", kIdentity,       \" by \"       ),\n     new Transform(         \"\", kOmitFirst5,     \"\"           ),\n     new Transform(         \"\", kOmitFirst6,     \"\"           ),\n     new Transform(    \" the \", kIdentity,       \"\"           ),\n     new Transform(         \"\", kOmitLast4,      \"\"           ),\n     new Transform(         \"\", kIdentity,       \". The \"     ),\n     new Transform(         \"\", kUppercaseAll,   \"\"           ),\n     new Transform(         \"\", kIdentity,       \" on \"       ),\n     new Transform(         \"\", kIdentity,       \" as \"       ),\n     new Transform(         \"\", kIdentity,       \" is \"       ),\n     new Transform(         \"\", kOmitLast7,      \"\"           ),\n     new Transform(         \"\", kOmitLast1,      \"ing \"       ),\n     new Transform(         \"\", kIdentity,       \"\\n\\t\"       ),\n     new Transform(         \"\", kIdentity,       \":\"          ),\n     new Transform(        \" \", kIdentity,       \". \"         ),\n     new Transform(         \"\", kIdentity,       \"ed \"        ),\n     new Transform(         \"\", kOmitFirst9,     \"\"           ),\n     new Transform(         \"\", kOmitFirst7,     \"\"           ),\n     new Transform(         \"\", kOmitLast6,      \"\"           ),\n     new Transform(         \"\", kIdentity,       \"(\"          ),\n     new Transform(         \"\", kUppercaseFirst, \", \"         ),\n     new Transform(         \"\", kOmitLast8,      \"\"           ),\n     new Transform(         \"\", kIdentity,       \" at \"       ),\n     new Transform(         \"\", kIdentity,       \"ly \"        ),\n     new Transform(    \" the \", kIdentity,       \" of \"       ),\n     new Transform(         \"\", kOmitLast5,      \"\"           ),\n     new Transform(         \"\", kOmitLast9,      \"\"           ),\n     new Transform(        \" \", kUppercaseFirst, \", \"         ),\n     new Transform(         \"\", kUppercaseFirst, \"\\\"\"         ),\n     new Transform(        \".\", kIdentity,       \"(\"          ),\n     new Transform(         \"\", kUppercaseAll,   \" \"          ),\n     new Transform(         \"\", kUppercaseFirst, \"\\\">\"        ),\n     new Transform(         \"\", kIdentity,       \"=\\\"\"        ),\n     new Transform(        \" \", kIdentity,       \".\"          ),\n     new Transform(    \".com/\", kIdentity,       \"\"           ),\n     new Transform(    \" the \", kIdentity,       \" of the \"   ),\n     new Transform(         \"\", kUppercaseFirst, \"'\"          ),\n     new Transform(         \"\", kIdentity,       \". This \"    ),\n     new Transform(         \"\", kIdentity,       \",\"          ),\n     new Transform(        \".\", kIdentity,       \" \"          ),\n     new Transform(         \"\", kUppercaseFirst, \"(\"          ),\n     new Transform(         \"\", kUppercaseFirst, \".\"          ),\n     new Transform(         \"\", kIdentity,       \" not \"      ),\n     new Transform(        \" \", kIdentity,       \"=\\\"\"        ),\n     new Transform(         \"\", kIdentity,       \"er \"        ),\n     new Transform(        \" \", kUppercaseAll,   \" \"          ),\n     new Transform(         \"\", kIdentity,       \"al \"        ),\n     new Transform(        \" \", kUppercaseAll,   \"\"           ),\n     new Transform(         \"\", kIdentity,       \"='\"         ),\n     new Transform(         \"\", kUppercaseAll,   \"\\\"\"         ),\n     new Transform(         \"\", kUppercaseFirst, \". \"         ),\n     new Transform(        \" \", kIdentity,       \"(\"          ),\n     new Transform(         \"\", kIdentity,       \"ful \"       ),\n     new Transform(        \" \", kUppercaseFirst, \". \"         ),\n     new Transform(         \"\", kIdentity,       \"ive \"       ),\n     new Transform(         \"\", kIdentity,       \"less \"      ),\n     new Transform(         \"\", kUppercaseAll,   \"'\"          ),\n     new Transform(         \"\", kIdentity,       \"est \"       ),\n     new Transform(        \" \", kUppercaseFirst, \".\"          ),\n     new Transform(         \"\", kUppercaseAll,   \"\\\">\"        ),\n     new Transform(        \" \", kIdentity,       \"='\"         ),\n     new Transform(         \"\", kUppercaseFirst, \",\"          ),\n     new Transform(         \"\", kIdentity,       \"ize \"       ),\n     new Transform(         \"\", kUppercaseAll,   \".\"          ),\n     new Transform( \"\\xc2\\xa0\", kIdentity,       \"\"           ),\n     new Transform(        \" \", kIdentity,       \",\"          ),\n     new Transform(         \"\", kUppercaseFirst, \"=\\\"\"        ),\n     new Transform(         \"\", kUppercaseAll,   \"=\\\"\"        ),\n     new Transform(         \"\", kIdentity,       \"ous \"       ),\n     new Transform(         \"\", kUppercaseAll,   \", \"         ),\n     new Transform(         \"\", kUppercaseFirst, \"='\"         ),\n     new Transform(        \" \", kUppercaseFirst, \",\"          ),\n     new Transform(        \" \", kUppercaseAll,   \"=\\\"\"        ),\n     new Transform(        \" \", kUppercaseAll,   \", \"         ),\n     new Transform(         \"\", kUppercaseAll,   \",\"          ),\n     new Transform(         \"\", kUppercaseAll,   \"(\"          ),\n     new Transform(         \"\", kUppercaseAll,   \". \"         ),\n     new Transform(        \" \", kUppercaseAll,   \".\"          ),\n     new Transform(         \"\", kUppercaseAll,   \"='\"         ),\n     new Transform(        \" \", kUppercaseAll,   \". \"         ),\n     new Transform(        \" \", kUppercaseFirst, \"=\\\"\"        ),\n     new Transform(        \" \", kUppercaseAll,   \"='\"         ),\n     new Transform(        \" \", kUppercaseFirst, \"='\"         )\n];\n\nexports.kTransforms = kTransforms;\nexports.kNumTransforms = kTransforms.length;\n\nfunction ToUpperCase(p, i) {\n  if (p[i] < 0xc0) {\n    if (p[i] >= 97 && p[i] <= 122) {\n      p[i] ^= 32;\n    }\n    return 1;\n  }\n  \n  /* An overly simplified uppercasing model for utf-8. */\n  if (p[i] < 0xe0) {\n    p[i + 1] ^= 32;\n    return 2;\n  }\n  \n  /* An arbitrary transform for three byte characters. */\n  p[i + 2] ^= 5;\n  return 3;\n}\n\nexports.transformDictionaryWord = function(dst, idx, word, len, transform) {\n  var prefix = kTransforms[transform].prefix;\n  var suffix = kTransforms[transform].suffix;\n  var t = kTransforms[transform].transform;\n  var skip = t < kOmitFirst1 ? 0 : t - (kOmitFirst1 - 1);\n  var i = 0;\n  var start_idx = idx;\n  var uppercase;\n  \n  if (skip > len) {\n    skip = len;\n  }\n  \n  var prefix_pos = 0;\n  while (prefix_pos < prefix.length) {\n    dst[idx++] = prefix[prefix_pos++];\n  }\n  \n  word += skip;\n  len -= skip;\n  \n  if (t <= kOmitLast9) {\n    len -= t;\n  }\n  \n  for (i = 0; i < len; i++) {\n    dst[idx++] = BrotliDictionary.dictionary[word + i];\n  }\n  \n  uppercase = idx - len;\n  \n  if (t === kUppercaseFirst) {\n    ToUpperCase(dst, uppercase);\n  } else if (t === kUppercaseAll) {\n    while (len > 0) {\n      var step = ToUpperCase(dst, uppercase);\n      uppercase += step;\n      len -= step;\n    }\n  }\n  \n  var suffix_pos = 0;\n  while (suffix_pos < suffix.length) {\n    dst[idx++] = suffix[suffix_pos++];\n  }\n  \n  return idx - start_idx;\n}\n\n\n/***/ }),\n/* 292 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(__dirname) {// Generated by CoffeeScript 1.12.6\n(function() {\n  var AFMFont, PDFFont, StandardFont, fs,\n    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n    hasProp = {}.hasOwnProperty;\n\n  AFMFont = __webpack_require__(293);\n\n  PDFFont = __webpack_require__(50);\n\n  fs = __webpack_require__(8);\n\n  StandardFont = (function(superClass) {\n    var STANDARD_FONTS;\n\n    extend(StandardFont, superClass);\n\n    function StandardFont(document, name1, id) {\n      var ref;\n      this.document = document;\n      this.name = name1;\n      this.id = id;\n      this.font = new AFMFont(STANDARD_FONTS[this.name]());\n      ref = this.font, this.ascender = ref.ascender, this.descender = ref.descender, this.bbox = ref.bbox, this.lineGap = ref.lineGap;\n    }\n\n    StandardFont.prototype.embed = function() {\n      this.dictionary.data = {\n        Type: 'Font',\n        BaseFont: this.name,\n        Subtype: 'Type1',\n        Encoding: 'WinAnsiEncoding'\n      };\n      return this.dictionary.end();\n    };\n\n    StandardFont.prototype.encode = function(text) {\n      var advances, encoded, glyph, glyphs, i, j, len, positions;\n      encoded = this.font.encodeText(text);\n      glyphs = this.font.glyphsForString('' + text);\n      advances = this.font.advancesForGlyphs(glyphs);\n      positions = [];\n      for (i = j = 0, len = glyphs.length; j < len; i = ++j) {\n        glyph = glyphs[i];\n        positions.push({\n          xAdvance: advances[i],\n          yAdvance: 0,\n          xOffset: 0,\n          yOffset: 0,\n          advanceWidth: this.font.widthOfGlyph(glyph)\n        });\n      }\n      return [encoded, positions];\n    };\n\n    StandardFont.prototype.widthOfString = function(string, size) {\n      var advance, advances, glyphs, j, len, scale, width;\n      glyphs = this.font.glyphsForString('' + string);\n      advances = this.font.advancesForGlyphs(glyphs);\n      width = 0;\n      for (j = 0, len = advances.length; j < len; j++) {\n        advance = advances[j];\n        width += advance;\n      }\n      scale = size / 1000;\n      return width * scale;\n    };\n\n    StandardFont.isStandardFont = function(name) {\n      return name in STANDARD_FONTS;\n    };\n\n    STANDARD_FONTS = {\n      \"Courier\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Courier.afm\", 'utf8');\n      },\n      \"Courier-Bold\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Courier-Bold.afm\", 'utf8');\n      },\n      \"Courier-Oblique\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Courier-Oblique.afm\", 'utf8');\n      },\n      \"Courier-BoldOblique\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Courier-BoldOblique.afm\", 'utf8');\n      },\n      \"Helvetica\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Helvetica.afm\", 'utf8');\n      },\n      \"Helvetica-Bold\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Helvetica-Bold.afm\", 'utf8');\n      },\n      \"Helvetica-Oblique\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Helvetica-Oblique.afm\", 'utf8');\n      },\n      \"Helvetica-BoldOblique\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Helvetica-BoldOblique.afm\", 'utf8');\n      },\n      \"Times-Roman\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Times-Roman.afm\", 'utf8');\n      },\n      \"Times-Bold\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Times-Bold.afm\", 'utf8');\n      },\n      \"Times-Italic\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Times-Italic.afm\", 'utf8');\n      },\n      \"Times-BoldItalic\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Times-BoldItalic.afm\", 'utf8');\n      },\n      \"Symbol\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Symbol.afm\", 'utf8');\n      },\n      \"ZapfDingbats\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/ZapfDingbats.afm\", 'utf8');\n      }\n    };\n\n    return StandardFont;\n\n  })(PDFFont);\n\n  module.exports = StandardFont;\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, \"/\"))\n\n/***/ }),\n/* 293 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var AFMFont, fs;\n\n  fs = __webpack_require__(8);\n\n  AFMFont = (function() {\n    var WIN_ANSI_MAP, characters;\n\n    AFMFont.open = function(filename) {\n      return new AFMFont(fs.readFileSync(filename, 'utf8'));\n    };\n\n    function AFMFont(contents) {\n      var e, i;\n      this.contents = contents;\n      this.attributes = {};\n      this.glyphWidths = {};\n      this.boundingBoxes = {};\n      this.kernPairs = {};\n      this.parse();\n      this.charWidths = (function() {\n        var j, results;\n        results = [];\n        for (i = j = 0; j <= 255; i = ++j) {\n          results.push(this.glyphWidths[characters[i]]);\n        }\n        return results;\n      }).call(this);\n      this.bbox = (function() {\n        var j, len, ref, results;\n        ref = this.attributes['FontBBox'].split(/\\s+/);\n        results = [];\n        for (j = 0, len = ref.length; j < len; j++) {\n          e = ref[j];\n          results.push(+e);\n        }\n        return results;\n      }).call(this);\n      this.ascender = +(this.attributes['Ascender'] || 0);\n      this.descender = +(this.attributes['Descender'] || 0);\n      this.lineGap = (this.bbox[3] - this.bbox[1]) - (this.ascender - this.descender);\n    }\n\n    AFMFont.prototype.parse = function() {\n      var a, j, key, len, line, match, name, ref, section, value;\n      section = '';\n      ref = this.contents.split('\\n');\n      for (j = 0, len = ref.length; j < len; j++) {\n        line = ref[j];\n        if (match = line.match(/^Start(\\w+)/)) {\n          section = match[1];\n          continue;\n        } else if (match = line.match(/^End(\\w+)/)) {\n          section = '';\n          continue;\n        }\n        switch (section) {\n          case 'FontMetrics':\n            match = line.match(/(^\\w+)\\s+(.*)/);\n            key = match[1];\n            value = match[2];\n            if (a = this.attributes[key]) {\n              if (!Array.isArray(a)) {\n                a = this.attributes[key] = [a];\n              }\n              a.push(value);\n            } else {\n              this.attributes[key] = value;\n            }\n            break;\n          case 'CharMetrics':\n            if (!/^CH?\\s/.test(line)) {\n              continue;\n            }\n            name = line.match(/\\bN\\s+(\\.?\\w+)\\s*;/)[1];\n            this.glyphWidths[name] = +line.match(/\\bWX\\s+(\\d+)\\s*;/)[1];\n            break;\n          case 'KernPairs':\n            match = line.match(/^KPX\\s+(\\.?\\w+)\\s+(\\.?\\w+)\\s+(-?\\d+)/);\n            if (match) {\n              this.kernPairs[match[1] + '\\0' + match[2]] = parseInt(match[3]);\n            }\n        }\n      }\n    };\n\n    WIN_ANSI_MAP = {\n      402: 131,\n      8211: 150,\n      8212: 151,\n      8216: 145,\n      8217: 146,\n      8218: 130,\n      8220: 147,\n      8221: 148,\n      8222: 132,\n      8224: 134,\n      8225: 135,\n      8226: 149,\n      8230: 133,\n      8364: 128,\n      8240: 137,\n      8249: 139,\n      8250: 155,\n      710: 136,\n      8482: 153,\n      338: 140,\n      339: 156,\n      732: 152,\n      352: 138,\n      353: 154,\n      376: 159,\n      381: 142,\n      382: 158\n    };\n\n    AFMFont.prototype.encodeText = function(text) {\n      var char, i, j, ref, res;\n      res = [];\n      for (i = j = 0, ref = text.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {\n        char = text.charCodeAt(i);\n        char = WIN_ANSI_MAP[char] || char;\n        res.push(char.toString(16));\n      }\n      return res;\n    };\n\n    AFMFont.prototype.glyphsForString = function(string) {\n      var charCode, glyphs, i, j, ref;\n      glyphs = [];\n      for (i = j = 0, ref = string.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {\n        charCode = string.charCodeAt(i);\n        glyphs.push(this.characterToGlyph(charCode));\n      }\n      return glyphs;\n    };\n\n    AFMFont.prototype.characterToGlyph = function(character) {\n      return characters[WIN_ANSI_MAP[character] || character] || '.notdef';\n    };\n\n    AFMFont.prototype.widthOfGlyph = function(glyph) {\n      return this.glyphWidths[glyph] || 0;\n    };\n\n    AFMFont.prototype.getKernPair = function(left, right) {\n      return this.kernPairs[left + '\\0' + right] || 0;\n    };\n\n    AFMFont.prototype.advancesForGlyphs = function(glyphs) {\n      var advances, index, j, left, len, right;\n      advances = [];\n      for (index = j = 0, len = glyphs.length; j < len; index = ++j) {\n        left = glyphs[index];\n        right = glyphs[index + 1];\n        advances.push(this.widthOfGlyph(left) + this.getKernPair(left, right));\n      }\n      return advances;\n    };\n\n    characters = '.notdef       .notdef        .notdef        .notdef\\n.notdef       .notdef        .notdef        .notdef\\n.notdef       .notdef        .notdef        .notdef\\n.notdef       .notdef        .notdef        .notdef\\n.notdef       .notdef        .notdef        .notdef\\n.notdef       .notdef        .notdef        .notdef\\n.notdef       .notdef        .notdef        .notdef\\n.notdef       .notdef        .notdef        .notdef\\n\\nspace         exclam         quotedbl       numbersign\\ndollar        percent        ampersand      quotesingle\\nparenleft     parenright     asterisk       plus\\ncomma         hyphen         period         slash\\nzero          one            two            three\\nfour          five           six            seven\\neight         nine           colon          semicolon\\nless          equal          greater        question\\n\\nat            A              B              C\\nD             E              F              G\\nH             I              J              K\\nL             M              N              O\\nP             Q              R              S\\nT             U              V              W\\nX             Y              Z              bracketleft\\nbackslash     bracketright   asciicircum    underscore\\n\\ngrave         a              b              c\\nd             e              f              g\\nh             i              j              k\\nl             m              n              o\\np             q              r              s\\nt             u              v              w\\nx             y              z              braceleft\\nbar           braceright     asciitilde     .notdef\\n\\nEuro          .notdef        quotesinglbase florin\\nquotedblbase  ellipsis       dagger         daggerdbl\\ncircumflex    perthousand    Scaron         guilsinglleft\\nOE            .notdef        Zcaron         .notdef\\n.notdef       quoteleft      quoteright     quotedblleft\\nquotedblright bullet         endash         emdash\\ntilde         trademark      scaron         guilsinglright\\noe            .notdef        zcaron         ydieresis\\n\\nspace         exclamdown     cent           sterling\\ncurrency      yen            brokenbar      section\\ndieresis      copyright      ordfeminine    guillemotleft\\nlogicalnot    hyphen         registered     macron\\ndegree        plusminus      twosuperior    threesuperior\\nacute         mu             paragraph      periodcentered\\ncedilla       onesuperior    ordmasculine   guillemotright\\nonequarter    onehalf        threequarters  questiondown\\n\\nAgrave        Aacute         Acircumflex    Atilde\\nAdieresis     Aring          AE             Ccedilla\\nEgrave        Eacute         Ecircumflex    Edieresis\\nIgrave        Iacute         Icircumflex    Idieresis\\nEth           Ntilde         Ograve         Oacute\\nOcircumflex   Otilde         Odieresis      multiply\\nOslash        Ugrave         Uacute         Ucircumflex\\nUdieresis     Yacute         Thorn          germandbls\\n\\nagrave        aacute         acircumflex    atilde\\nadieresis     aring          ae             ccedilla\\negrave        eacute         ecircumflex    edieresis\\nigrave        iacute         icircumflex    idieresis\\neth           ntilde         ograve         oacute\\nocircumflex   otilde         odieresis      divide\\noslash        ugrave         uacute         ucircumflex\\nudieresis     yacute         thorn          ydieresis'.split(/\\s+/);\n\n    return AFMFont;\n\n  })();\n\n  module.exports = AFMFont;\n\n}).call(this);\n\n\n/***/ }),\n/* 294 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var EmbeddedFont, PDFFont, PDFObject,\n    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n    hasProp = {}.hasOwnProperty,\n    slice = [].slice;\n\n  PDFFont = __webpack_require__(50);\n\n  PDFObject = __webpack_require__(26);\n\n  EmbeddedFont = (function(superClass) {\n    var toHex;\n\n    extend(EmbeddedFont, superClass);\n\n    function EmbeddedFont(document, font, id) {\n      this.document = document;\n      this.font = font;\n      this.id = id;\n      this.subset = this.font.createSubset();\n      this.unicode = [[0]];\n      this.widths = [this.font.getGlyph(0).advanceWidth];\n      this.name = this.font.postscriptName;\n      this.scale = 1000 / this.font.unitsPerEm;\n      this.ascender = this.font.ascent * this.scale;\n      this.descender = this.font.descent * this.scale;\n      this.lineGap = this.font.lineGap * this.scale;\n      this.bbox = this.font.bbox;\n      this.layoutCache = Object.create(null);\n    }\n\n    EmbeddedFont.prototype.layoutRun = function(text, features) {\n      var i, j, key, len, position, ref, run;\n      run = this.font.layout(text, features);\n      ref = run.positions;\n      for (i = j = 0, len = ref.length; j < len; i = ++j) {\n        position = ref[i];\n        for (key in position) {\n          position[key] *= this.scale;\n        }\n        position.advanceWidth = run.glyphs[i].advanceWidth * this.scale;\n      }\n      return run;\n    };\n\n    EmbeddedFont.prototype.layoutCached = function(text) {\n      var cached, run;\n      if (cached = this.layoutCache[text]) {\n        return cached;\n      }\n      run = this.layoutRun(text);\n      this.layoutCache[text] = run;\n      return run;\n    };\n\n    EmbeddedFont.prototype.layout = function(text, features, onlyWidth) {\n      var advanceWidth, glyphs, index, last, positions, ref, run;\n      if (onlyWidth == null) {\n        onlyWidth = false;\n      }\n      if (features) {\n        return this.layoutRun(text, features);\n      }\n      glyphs = onlyWidth ? null : [];\n      positions = onlyWidth ? null : [];\n      advanceWidth = 0;\n      last = 0;\n      index = 0;\n      while (index <= text.length) {\n        if ((index === text.length && last < index) || ((ref = text.charAt(index)) === ' ' || ref === '\\t')) {\n          run = this.layoutCached(text.slice(last, ++index));\n          if (!onlyWidth) {\n            glyphs.push.apply(glyphs, run.glyphs);\n            positions.push.apply(positions, run.positions);\n          }\n          advanceWidth += run.advanceWidth;\n          last = index;\n        } else {\n          index++;\n        }\n      }\n      return {\n        glyphs: glyphs,\n        positions: positions,\n        advanceWidth: advanceWidth\n      };\n    };\n\n    EmbeddedFont.prototype.encode = function(text, features) {\n      var base, base1, gid, glyph, glyphs, i, j, len, positions, ref, res;\n      ref = this.layout(text, features), glyphs = ref.glyphs, positions = ref.positions;\n      res = [];\n      for (i = j = 0, len = glyphs.length; j < len; i = ++j) {\n        glyph = glyphs[i];\n        gid = this.subset.includeGlyph(glyph.id);\n        res.push(('0000' + gid.toString(16)).slice(-4));\n        if ((base = this.widths)[gid] == null) {\n          base[gid] = glyph.advanceWidth * this.scale;\n        }\n        if ((base1 = this.unicode)[gid] == null) {\n          base1[gid] = glyph.codePoints;\n        }\n      }\n      return [res, positions];\n    };\n\n    EmbeddedFont.prototype.widthOfString = function(string, size, features) {\n      var scale, width;\n      width = this.layout(string, features, true).advanceWidth;\n      scale = size / 1000;\n      return width * scale;\n    };\n\n    EmbeddedFont.prototype.embed = function() {\n      var bbox, descendantFont, descriptor, familyClass, flags, fontFile, i, isCFF, name, ref, tag;\n      isCFF = this.subset.cff != null;\n      fontFile = this.document.ref();\n      if (isCFF) {\n        fontFile.data.Subtype = 'CIDFontType0C';\n      }\n      this.subset.encodeStream().pipe(fontFile);\n      familyClass = (((ref = this.font['OS/2']) != null ? ref.sFamilyClass : void 0) || 0) >> 8;\n      flags = 0;\n      if (this.font.post.isFixedPitch) {\n        flags |= 1 << 0;\n      }\n      if ((1 <= familyClass && familyClass <= 7)) {\n        flags |= 1 << 1;\n      }\n      flags |= 1 << 2;\n      if (familyClass === 10) {\n        flags |= 1 << 3;\n      }\n      if (this.font.head.macStyle.italic) {\n        flags |= 1 << 6;\n      }\n      tag = ((function() {\n        var j, results;\n        results = [];\n        for (i = j = 0; j < 6; i = ++j) {\n          results.push(String.fromCharCode(Math.random() * 26 + 65));\n        }\n        return results;\n      })()).join('');\n      name = tag + '+' + this.font.postscriptName;\n      bbox = this.font.bbox;\n      descriptor = this.document.ref({\n        Type: 'FontDescriptor',\n        FontName: name,\n        Flags: flags,\n        FontBBox: [bbox.minX * this.scale, bbox.minY * this.scale, bbox.maxX * this.scale, bbox.maxY * this.scale],\n        ItalicAngle: this.font.italicAngle,\n        Ascent: this.ascender,\n        Descent: this.descender,\n        CapHeight: (this.font.capHeight || this.font.ascent) * this.scale,\n        XHeight: (this.font.xHeight || 0) * this.scale,\n        StemV: 0\n      });\n      if (isCFF) {\n        descriptor.data.FontFile3 = fontFile;\n      } else {\n        descriptor.data.FontFile2 = fontFile;\n      }\n      descriptor.end();\n      descendantFont = this.document.ref({\n        Type: 'Font',\n        Subtype: isCFF ? 'CIDFontType0' : 'CIDFontType2',\n        BaseFont: name,\n        CIDSystemInfo: {\n          Registry: new String('Adobe'),\n          Ordering: new String('Identity'),\n          Supplement: 0\n        },\n        FontDescriptor: descriptor,\n        W: [0, this.widths]\n      });\n      descendantFont.end();\n      this.dictionary.data = {\n        Type: 'Font',\n        Subtype: 'Type0',\n        BaseFont: name,\n        Encoding: 'Identity-H',\n        DescendantFonts: [descendantFont],\n        ToUnicode: this.toUnicodeCmap()\n      };\n      return this.dictionary.end();\n    };\n\n    toHex = function() {\n      var code, codePoints, codes;\n      codePoints = 1 <= arguments.length ? slice.call(arguments, 0) : [];\n      codes = (function() {\n        var j, len, results;\n        results = [];\n        for (j = 0, len = codePoints.length; j < len; j++) {\n          code = codePoints[j];\n          results.push(('0000' + code.toString(16)).slice(-4));\n        }\n        return results;\n      })();\n      return codes.join('');\n    };\n\n    EmbeddedFont.prototype.toUnicodeCmap = function() {\n      var cmap, codePoints, encoded, entries, j, k, len, len1, ref, value;\n      cmap = this.document.ref();\n      entries = [];\n      ref = this.unicode;\n      for (j = 0, len = ref.length; j < len; j++) {\n        codePoints = ref[j];\n        encoded = [];\n        for (k = 0, len1 = codePoints.length; k < len1; k++) {\n          value = codePoints[k];\n          if (value > 0xffff) {\n            value -= 0x10000;\n            encoded.push(toHex(value >>> 10 & 0x3ff | 0xd800));\n            value = 0xdc00 | value & 0x3ff;\n          }\n          encoded.push(toHex(value));\n        }\n        entries.push(\"<\" + (encoded.join(' ')) + \">\");\n      }\n      cmap.end(\"/CIDInit /ProcSet findresource begin\\n12 dict begin\\nbegincmap\\n/CIDSystemInfo <<\\n  /Registry (Adobe)\\n  /Ordering (UCS)\\n  /Supplement 0\\n>> def\\n/CMapName /Adobe-Identity-UCS def\\n/CMapType 2 def\\n1 begincodespacerange\\n<0000><ffff>\\nendcodespacerange\\n1 beginbfrange\\n<0000> <\" + (toHex(entries.length - 1)) + \"> [\" + (entries.join(' ')) + \"]\\nendbfrange\\nendcmap\\nCMapName currentdict /CMap defineresource pop\\nend\\nend\");\n      return cmap;\n    };\n\n    return EmbeddedFont;\n\n  })(PDFFont);\n\n  module.exports = EmbeddedFont;\n\n}).call(this);\n\n\n/***/ }),\n/* 295 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var LineWrapper, number;\n\n  LineWrapper = __webpack_require__(296);\n\n  number = __webpack_require__(26).number;\n\n  module.exports = {\n    initText: function() {\n      this.x = 0;\n      this.y = 0;\n      return this._lineGap = 0;\n    },\n    lineGap: function(_lineGap) {\n      this._lineGap = _lineGap;\n      return this;\n    },\n    moveDown: function(lines) {\n      if (lines == null) {\n        lines = 1;\n      }\n      this.y += this.currentLineHeight(true) * lines + this._lineGap;\n      return this;\n    },\n    moveUp: function(lines) {\n      if (lines == null) {\n        lines = 1;\n      }\n      this.y -= this.currentLineHeight(true) * lines + this._lineGap;\n      return this;\n    },\n    _text: function(text, x, y, options, lineCallback) {\n      var j, len, line, ref, wrapper;\n      options = this._initOptions(x, y, options);\n      text = text == null ? '' : '' + text;\n      if (options.wordSpacing) {\n        text = text.replace(/\\s{2,}/g, ' ');\n      }\n      if (options.width) {\n        wrapper = this._wrapper;\n        if (!wrapper) {\n          wrapper = new LineWrapper(this, options);\n          wrapper.on('line', lineCallback);\n        }\n        this._wrapper = options.continued ? wrapper : null;\n        this._textOptions = options.continued ? options : null;\n        wrapper.wrap(text, options);\n      } else {\n        ref = text.split('\\n');\n        for (j = 0, len = ref.length; j < len; j++) {\n          line = ref[j];\n          lineCallback(line, options);\n        }\n      }\n      return this;\n    },\n    text: function(text, x, y, options) {\n      return this._text(text, x, y, options, this._line.bind(this));\n    },\n    widthOfString: function(string, options) {\n      if (options == null) {\n        options = {};\n      }\n      return this._font.widthOfString(string, this._fontSize, options.features) + (options.characterSpacing || 0) * (string.length - 1);\n    },\n    heightOfString: function(text, options) {\n      var height, lineGap, ref, x, y;\n      if (options == null) {\n        options = {};\n      }\n      ref = this, x = ref.x, y = ref.y;\n      options = this._initOptions(options);\n      options.height = 2e308;\n      lineGap = options.lineGap || this._lineGap || 0;\n      this._text(text, this.x, this.y, options, (function(_this) {\n        return function(line, options) {\n          return _this.y += _this.currentLineHeight(true) + lineGap;\n        };\n      })(this));\n      height = this.y - y;\n      this.x = x;\n      this.y = y;\n      return height;\n    },\n    list: function(list, x, y, options, wrapper) {\n      var flatten, i, indent, itemIndent, items, level, levels, midLine, r;\n      options = this._initOptions(x, y, options);\n      midLine = Math.round((this._font.ascender / 1000 * this._fontSize) / 2);\n      r = options.bulletRadius || Math.round((this._font.ascender / 1000 * this._fontSize) / 3);\n      indent = options.textIndent || r * 5;\n      itemIndent = options.bulletIndent || r * 8;\n      level = 1;\n      items = [];\n      levels = [];\n      flatten = function(list) {\n        var i, item, j, len, results;\n        results = [];\n        for (i = j = 0, len = list.length; j < len; i = ++j) {\n          item = list[i];\n          if (Array.isArray(item)) {\n            level++;\n            flatten(item);\n            results.push(level--);\n          } else {\n            items.push(item);\n            results.push(levels.push(level));\n          }\n        }\n        return results;\n      };\n      flatten(list);\n      wrapper = new LineWrapper(this, options);\n      wrapper.on('line', this._line.bind(this));\n      level = 1;\n      i = 0;\n      wrapper.on('firstLine', (function(_this) {\n        return function() {\n          var diff, l;\n          if ((l = levels[i++]) !== level) {\n            diff = itemIndent * (l - level);\n            _this.x += diff;\n            wrapper.lineWidth -= diff;\n            level = l;\n          }\n          _this.circle(_this.x - indent + r, _this.y + midLine, r);\n          return _this.fill();\n        };\n      })(this));\n      wrapper.on('sectionStart', (function(_this) {\n        return function() {\n          var pos;\n          pos = indent + itemIndent * (level - 1);\n          _this.x += pos;\n          return wrapper.lineWidth -= pos;\n        };\n      })(this));\n      wrapper.on('sectionEnd', (function(_this) {\n        return function() {\n          var pos;\n          pos = indent + itemIndent * (level - 1);\n          _this.x -= pos;\n          return wrapper.lineWidth += pos;\n        };\n      })(this));\n      wrapper.wrap(items.join('\\n'), options);\n      return this;\n    },\n    _initOptions: function(x, y, options) {\n      var key, ref, val;\n      if (x == null) {\n        x = {};\n      }\n      if (options == null) {\n        options = {};\n      }\n      if (typeof x === 'object') {\n        options = x;\n        x = null;\n      }\n      options = (function() {\n        var k, opts, v;\n        opts = {};\n        for (k in options) {\n          v = options[k];\n          opts[k] = v;\n        }\n        return opts;\n      })();\n      if (this._textOptions) {\n        ref = this._textOptions;\n        for (key in ref) {\n          val = ref[key];\n          if (key !== 'continued') {\n            if (options[key] == null) {\n              options[key] = val;\n            }\n          }\n        }\n      }\n      if (x != null) {\n        this.x = x;\n      }\n      if (y != null) {\n        this.y = y;\n      }\n      if (options.lineBreak !== false) {\n        if (options.width == null) {\n          options.width = this.page.width - this.x - this.page.margins.right;\n        }\n      }\n      options.columns || (options.columns = 0);\n      if (options.columnGap == null) {\n        options.columnGap = 18;\n      }\n      return options;\n    },\n    _line: function(text, options, wrapper) {\n      var lineGap;\n      if (options == null) {\n        options = {};\n      }\n      this._fragment(text, this.x, this.y, options);\n      lineGap = options.lineGap || this._lineGap || 0;\n      if (!wrapper) {\n        return this.x += this.widthOfString(text);\n      } else {\n        return this.y += this.currentLineHeight(true) + lineGap;\n      }\n    },\n    _fragment: function(text, x, y, options) {\n      var addSegment, align, base, characterSpacing, commands, d, encoded, encodedWord, flush, hadOffset, i, j, key, last, len, len1, lineWidth, lineY, m, mode, name, pos, positions, positionsWord, ref, ref1, ref2, renderedWidth, scale, space, spaceWidth, textWidth, val, word, wordSpacing, words;\n      text = ('' + text).replace(/\\n/g, '');\n      if (text.length === 0) {\n        return;\n      }\n      align = options.align || 'left';\n      wordSpacing = options.wordSpacing || 0;\n      characterSpacing = options.characterSpacing || 0;\n      if (options.width) {\n        switch (align) {\n          case 'right':\n            textWidth = this.widthOfString(text.replace(/\\s+$/, ''), options);\n            x += options.lineWidth - textWidth;\n            break;\n          case 'center':\n            x += options.lineWidth / 2 - options.textWidth / 2;\n            break;\n          case 'justify':\n            words = text.trim().split(/\\s+/);\n            textWidth = this.widthOfString(text.replace(/\\s+/g, ''), options);\n            spaceWidth = this.widthOfString(' ') + characterSpacing;\n            wordSpacing = Math.max(0, (options.lineWidth - textWidth) / Math.max(1, words.length - 1) - spaceWidth);\n        }\n      }\n      renderedWidth = options.textWidth + (wordSpacing * (options.wordCount - 1)) + (characterSpacing * (text.length - 1));\n      if (options.link) {\n        this.link(x, y, renderedWidth, this.currentLineHeight(), options.link);\n      }\n      if (options.underline || options.strike) {\n        this.save();\n        if (!options.stroke) {\n          this.strokeColor.apply(this, this._fillColor);\n        }\n        lineWidth = this._fontSize < 10 ? 0.5 : Math.floor(this._fontSize / 10);\n        this.lineWidth(lineWidth);\n        d = options.underline ? 1 : 2;\n        lineY = y + this.currentLineHeight() / d;\n        if (options.underline) {\n          lineY -= lineWidth;\n        }\n        this.moveTo(x, lineY);\n        this.lineTo(x + renderedWidth, lineY);\n        this.stroke();\n        this.restore();\n      }\n      this.save();\n      this.transform(1, 0, 0, -1, 0, this.page.height);\n      y = this.page.height - y - (this._font.ascender / 1000 * this._fontSize);\n      if ((base = this.page.fonts)[name = this._font.id] == null) {\n        base[name] = this._font.ref();\n      }\n      this.addContent(\"BT\");\n      this.addContent(\"1 0 0 1 \" + (number(x)) + \" \" + (number(y)) + \" Tm\");\n      this.addContent(\"/\" + this._font.id + \" \" + (number(this._fontSize)) + \" Tf\");\n      mode = options.fill && options.stroke ? 2 : options.stroke ? 1 : 0;\n      if (mode) {\n        this.addContent(mode + \" Tr\");\n      }\n      if (characterSpacing) {\n        this.addContent((number(characterSpacing)) + \" Tc\");\n      }\n      if (wordSpacing) {\n        words = text.trim().split(/\\s+/);\n        wordSpacing += this.widthOfString(' ') + characterSpacing;\n        wordSpacing *= 1000 / this._fontSize;\n        encoded = [];\n        positions = [];\n        for (j = 0, len = words.length; j < len; j++) {\n          word = words[j];\n          ref = this._font.encode(word, options.features), encodedWord = ref[0], positionsWord = ref[1];\n          encoded.push.apply(encoded, encodedWord);\n          positions.push.apply(positions, positionsWord);\n          space = {};\n          ref1 = positions[positions.length - 1];\n          for (key in ref1) {\n            val = ref1[key];\n            space[key] = val;\n          }\n          space.xAdvance += wordSpacing;\n          positions[positions.length - 1] = space;\n        }\n      } else {\n        ref2 = this._font.encode(text, options.features), encoded = ref2[0], positions = ref2[1];\n      }\n      scale = this._fontSize / 1000;\n      commands = [];\n      last = 0;\n      hadOffset = false;\n      addSegment = (function(_this) {\n        return function(cur) {\n          var advance, hex;\n          if (last < cur) {\n            hex = encoded.slice(last, cur).join('');\n            advance = positions[cur - 1].xAdvance - positions[cur - 1].advanceWidth;\n            commands.push(\"<\" + hex + \"> \" + (number(-advance)));\n          }\n          return last = cur;\n        };\n      })(this);\n      flush = (function(_this) {\n        return function(i) {\n          addSegment(i);\n          if (commands.length > 0) {\n            _this.addContent(\"[\" + (commands.join(' ')) + \"] TJ\");\n            return commands.length = 0;\n          }\n        };\n      })(this);\n      for (i = m = 0, len1 = positions.length; m < len1; i = ++m) {\n        pos = positions[i];\n        if (pos.xOffset || pos.yOffset) {\n          flush(i);\n          this.addContent(\"1 0 0 1 \" + (number(x + pos.xOffset * scale)) + \" \" + (number(y + pos.yOffset * scale)) + \" Tm\");\n          flush(i + 1);\n          hadOffset = true;\n        } else {\n          if (hadOffset) {\n            this.addContent(\"1 0 0 1 \" + (number(x)) + \" \" + (number(y)) + \" Tm\");\n            hadOffset = false;\n          }\n          if (pos.xAdvance - pos.advanceWidth !== 0) {\n            addSegment(i + 1);\n          }\n        }\n        x += pos.xAdvance * scale;\n      }\n      flush(i);\n      this.addContent(\"ET\");\n      return this.restore();\n    }\n  };\n\n}).call(this);\n\n\n/***/ }),\n/* 296 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var EventEmitter, LineBreaker, LineWrapper,\n    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n    hasProp = {}.hasOwnProperty;\n\n  EventEmitter = __webpack_require__(31).EventEmitter;\n\n  LineBreaker = __webpack_require__(78);\n\n  LineWrapper = (function(superClass) {\n    extend(LineWrapper, superClass);\n\n    function LineWrapper(document, options) {\n      var ref;\n      this.document = document;\n      this.indent = options.indent || 0;\n      this.characterSpacing = options.characterSpacing || 0;\n      this.wordSpacing = options.wordSpacing === 0;\n      this.columns = options.columns || 1;\n      this.columnGap = (ref = options.columnGap) != null ? ref : 18;\n      this.lineWidth = (options.width - (this.columnGap * (this.columns - 1))) / this.columns;\n      this.spaceLeft = this.lineWidth;\n      this.startX = this.document.x;\n      this.startY = this.document.y;\n      this.column = 1;\n      this.ellipsis = options.ellipsis;\n      this.continuedX = 0;\n      this.features = options.features;\n      if (options.height != null) {\n        this.height = options.height;\n        this.maxY = this.startY + options.height;\n      } else {\n        this.maxY = this.document.page.maxY();\n      }\n      this.on('firstLine', (function(_this) {\n        return function(options) {\n          var indent;\n          indent = _this.continuedX || _this.indent;\n          _this.document.x += indent;\n          _this.lineWidth -= indent;\n          return _this.once('line', function() {\n            _this.document.x -= indent;\n            _this.lineWidth += indent;\n            if (options.continued && !_this.continuedX) {\n              _this.continuedX = _this.indent;\n            }\n            if (!options.continued) {\n              return _this.continuedX = 0;\n            }\n          });\n        };\n      })(this));\n      this.on('lastLine', (function(_this) {\n        return function(options) {\n          var align;\n          align = options.align;\n          if (align === 'justify') {\n            options.align = 'left';\n          }\n          _this.lastLine = true;\n          return _this.once('line', function() {\n            _this.document.y += options.paragraphGap || 0;\n            options.align = align;\n            return _this.lastLine = false;\n          });\n        };\n      })(this));\n    }\n\n    LineWrapper.prototype.wordWidth = function(word) {\n      return this.document.widthOfString(word, this) + this.characterSpacing + this.wordSpacing;\n    };\n\n    LineWrapper.prototype.eachWord = function(text, fn) {\n      var bk, breaker, fbk, l, last, lbk, shouldContinue, w, word, wordWidths;\n      breaker = new LineBreaker(text);\n      last = null;\n      wordWidths = Object.create(null);\n      while (bk = breaker.nextBreak()) {\n        word = text.slice((last != null ? last.position : void 0) || 0, bk.position);\n        w = wordWidths[word] != null ? wordWidths[word] : wordWidths[word] = this.wordWidth(word);\n        if (w > this.lineWidth + this.continuedX) {\n          lbk = last;\n          fbk = {};\n          while (word.length) {\n            l = word.length;\n            while (w > this.spaceLeft) {\n              w = this.wordWidth(word.slice(0, --l));\n            }\n            fbk.required = l < word.length;\n            shouldContinue = fn(word.slice(0, l), w, fbk, lbk);\n            lbk = {\n              required: false\n            };\n            word = word.slice(l);\n            w = this.wordWidth(word);\n            if (shouldContinue === false) {\n              break;\n            }\n          }\n        } else {\n          shouldContinue = fn(word, w, bk, last);\n        }\n        if (shouldContinue === false) {\n          break;\n        }\n        last = bk;\n      }\n    };\n\n    LineWrapper.prototype.wrap = function(text, options) {\n      var buffer, emitLine, lc, nextY, textWidth, wc, y;\n      if (options.indent != null) {\n        this.indent = options.indent;\n      }\n      if (options.characterSpacing != null) {\n        this.characterSpacing = options.characterSpacing;\n      }\n      if (options.wordSpacing != null) {\n        this.wordSpacing = options.wordSpacing;\n      }\n      if (options.ellipsis != null) {\n        this.ellipsis = options.ellipsis;\n      }\n      nextY = this.document.y + this.document.currentLineHeight(true);\n      if (this.document.y > this.maxY || nextY > this.maxY) {\n        this.nextSection();\n      }\n      buffer = '';\n      textWidth = 0;\n      wc = 0;\n      lc = 0;\n      y = this.document.y;\n      emitLine = (function(_this) {\n        return function() {\n          options.textWidth = textWidth + _this.wordSpacing * (wc - 1);\n          options.wordCount = wc;\n          options.lineWidth = _this.lineWidth;\n          y = _this.document.y;\n          _this.emit('line', buffer, options, _this);\n          return lc++;\n        };\n      })(this);\n      this.emit('sectionStart', options, this);\n      this.eachWord(text, (function(_this) {\n        return function(word, w, bk, last) {\n          var lh, shouldContinue;\n          if ((last == null) || last.required) {\n            _this.emit('firstLine', options, _this);\n            _this.spaceLeft = _this.lineWidth;\n          }\n          if (w <= _this.spaceLeft) {\n            buffer += word;\n            textWidth += w;\n            wc++;\n          }\n          if (bk.required || w > _this.spaceLeft) {\n            if (bk.required) {\n              _this.emit('lastLine', options, _this);\n            }\n            lh = _this.document.currentLineHeight(true);\n            if ((_this.height != null) && _this.ellipsis && _this.document.y + lh * 2 > _this.maxY && _this.column >= _this.columns) {\n              if (_this.ellipsis === true) {\n                _this.ellipsis = '…';\n              }\n              buffer = buffer.replace(/\\s+$/, '');\n              textWidth = _this.wordWidth(buffer + _this.ellipsis);\n              while (textWidth > _this.lineWidth) {\n                buffer = buffer.slice(0, -1).replace(/\\s+$/, '');\n                textWidth = _this.wordWidth(buffer + _this.ellipsis);\n              }\n              buffer = buffer + _this.ellipsis;\n            }\n            if (bk.required && w > _this.spaceLeft) {\n              buffer = word;\n              textWidth = w;\n              wc = 1;\n            }\n            emitLine();\n            if (_this.document.y + lh > _this.maxY) {\n              shouldContinue = _this.nextSection();\n              if (!shouldContinue) {\n                wc = 0;\n                buffer = '';\n                return false;\n              }\n            }\n            if (bk.required) {\n              _this.spaceLeft = _this.lineWidth;\n              buffer = '';\n              textWidth = 0;\n              return wc = 0;\n            } else {\n              _this.spaceLeft = _this.lineWidth - w;\n              buffer = word;\n              textWidth = w;\n              return wc = 1;\n            }\n          } else {\n            return _this.spaceLeft -= w;\n          }\n        };\n      })(this));\n      if (wc > 0) {\n        this.emit('lastLine', options, this);\n        emitLine();\n      }\n      this.emit('sectionEnd', options, this);\n      if (options.continued === true) {\n        if (lc > 1) {\n          this.continuedX = 0;\n        }\n        this.continuedX += options.textWidth;\n        return this.document.y = y;\n      } else {\n        return this.document.x = this.startX;\n      }\n    };\n\n    LineWrapper.prototype.nextSection = function(options) {\n      var ref;\n      this.emit('sectionEnd', options, this);\n      if (++this.column > this.columns) {\n        if (this.height != null) {\n          return false;\n        }\n        this.document.addPage();\n        this.column = 1;\n        this.startY = this.document.page.margins.top;\n        this.maxY = this.document.page.maxY();\n        this.document.x = this.startX;\n        if (this.document._fillColor) {\n          (ref = this.document).fillColor.apply(ref, this.document._fillColor);\n        }\n        this.emit('pageBreak', options, this);\n      } else {\n        this.document.x += this.lineWidth + this.columnGap;\n        this.document.y = this.startY;\n        this.emit('columnBreak', options, this);\n      }\n      this.emit('sectionStart', options, this);\n      return true;\n    };\n\n    return LineWrapper;\n\n  })(EventEmitter);\n\n  module.exports = LineWrapper;\n\n}).call(this);\n\n\n/***/ }),\n/* 297 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var PDFImage;\n\n  PDFImage = __webpack_require__(121);\n\n  module.exports = {\n    initImages: function() {\n      this._imageRegistry = {};\n      return this._imageCount = 0;\n    },\n    image: function(src, x, y, options) {\n      var base, bh, bp, bw, h, hp, image, ip, name, ref, ref1, ref2, ref3, w, wp;\n      if (options == null) {\n        options = {};\n      }\n      if (typeof x === 'object') {\n        options = x;\n        x = null;\n      }\n      x = (ref = x != null ? x : options.x) != null ? ref : this.x;\n      y = (ref1 = y != null ? y : options.y) != null ? ref1 : this.y;\n      if (typeof src === 'string') {\n        image = this._imageRegistry[src];\n      }\n      if (!image) {\n        if (src.width && src.height) {\n          image = src;\n        } else {\n          image = this.openImage(src);\n        }\n      }\n      if (!image.obj) {\n        image.embed(this);\n      }\n      if ((base = this.page.xobjects)[name = image.label] == null) {\n        base[name] = image.obj;\n      }\n      w = options.width || image.width;\n      h = options.height || image.height;\n      if (options.width && !options.height) {\n        wp = w / image.width;\n        w = image.width * wp;\n        h = image.height * wp;\n      } else if (options.height && !options.width) {\n        hp = h / image.height;\n        w = image.width * hp;\n        h = image.height * hp;\n      } else if (options.scale) {\n        w = image.width * options.scale;\n        h = image.height * options.scale;\n      } else if (options.fit) {\n        ref2 = options.fit, bw = ref2[0], bh = ref2[1];\n        bp = bw / bh;\n        ip = image.width / image.height;\n        if (ip > bp) {\n          w = bw;\n          h = bw / ip;\n        } else {\n          h = bh;\n          w = bh * ip;\n        }\n      } else if (options.cover) {\n        ref3 = options.cover, bw = ref3[0], bh = ref3[1];\n        bp = bw / bh;\n        ip = image.width / image.height;\n        if (ip > bp) {\n          h = bh;\n          w = bh * ip;\n        } else {\n          w = bw;\n          h = bw / ip;\n        }\n      }\n      if (options.fit || options.cover) {\n        if (options.align === 'center') {\n          x = x + bw / 2 - w / 2;\n        } else if (options.align === 'right') {\n          x = x + bw - w;\n        }\n        if (options.valign === 'center') {\n          y = y + bh / 2 - h / 2;\n        } else if (options.valign === 'bottom') {\n          y = y + bh - h;\n        }\n      }\n      if (this.y === y) {\n        this.y += h;\n      }\n      this.save();\n      this.transform(w, 0, 0, -h, x, y + h);\n      this.addContent(\"/\" + image.label + \" Do\");\n      this.restore();\n      return this;\n    },\n    openImage: function(src) {\n      var image;\n      if (typeof src === 'string') {\n        image = this._imageRegistry[src];\n      }\n      if (!image) {\n        image = PDFImage.open(src, 'I' + (++this._imageCount));\n        if (typeof src === 'string') {\n          this._imageRegistry[src] = image;\n        }\n      }\n      return image;\n    }\n  };\n\n}).call(this);\n\n\n/***/ }),\n/* 298 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var Data;\n\n  Data = (function() {\n    function Data(data) {\n      this.data = data != null ? data : [];\n      this.pos = 0;\n      this.length = this.data.length;\n    }\n\n    Data.prototype.readByte = function() {\n      return this.data[this.pos++];\n    };\n\n    Data.prototype.writeByte = function(byte) {\n      return this.data[this.pos++] = byte;\n    };\n\n    Data.prototype.byteAt = function(index) {\n      return this.data[index];\n    };\n\n    Data.prototype.readBool = function() {\n      return !!this.readByte();\n    };\n\n    Data.prototype.writeBool = function(val) {\n      return this.writeByte(val ? 1 : 0);\n    };\n\n    Data.prototype.readUInt32 = function() {\n      var b1, b2, b3, b4;\n      b1 = this.readByte() * 0x1000000;\n      b2 = this.readByte() << 16;\n      b3 = this.readByte() << 8;\n      b4 = this.readByte();\n      return b1 + b2 + b3 + b4;\n    };\n\n    Data.prototype.writeUInt32 = function(val) {\n      this.writeByte((val >>> 24) & 0xff);\n      this.writeByte((val >> 16) & 0xff);\n      this.writeByte((val >> 8) & 0xff);\n      return this.writeByte(val & 0xff);\n    };\n\n    Data.prototype.readInt32 = function() {\n      var int;\n      int = this.readUInt32();\n      if (int >= 0x80000000) {\n        return int - 0x100000000;\n      } else {\n        return int;\n      }\n    };\n\n    Data.prototype.writeInt32 = function(val) {\n      if (val < 0) {\n        val += 0x100000000;\n      }\n      return this.writeUInt32(val);\n    };\n\n    Data.prototype.readUInt16 = function() {\n      var b1, b2;\n      b1 = this.readByte() << 8;\n      b2 = this.readByte();\n      return b1 | b2;\n    };\n\n    Data.prototype.writeUInt16 = function(val) {\n      this.writeByte((val >> 8) & 0xff);\n      return this.writeByte(val & 0xff);\n    };\n\n    Data.prototype.readInt16 = function() {\n      var int;\n      int = this.readUInt16();\n      if (int >= 0x8000) {\n        return int - 0x10000;\n      } else {\n        return int;\n      }\n    };\n\n    Data.prototype.writeInt16 = function(val) {\n      if (val < 0) {\n        val += 0x10000;\n      }\n      return this.writeUInt16(val);\n    };\n\n    Data.prototype.readString = function(length) {\n      var i, j, ref, ret;\n      ret = [];\n      for (i = j = 0, ref = length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {\n        ret[i] = String.fromCharCode(this.readByte());\n      }\n      return ret.join('');\n    };\n\n    Data.prototype.writeString = function(val) {\n      var i, j, ref, results;\n      results = [];\n      for (i = j = 0, ref = val.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {\n        results.push(this.writeByte(val.charCodeAt(i)));\n      }\n      return results;\n    };\n\n    Data.prototype.stringAt = function(pos, length) {\n      this.pos = pos;\n      return this.readString(length);\n    };\n\n    Data.prototype.readShort = function() {\n      return this.readInt16();\n    };\n\n    Data.prototype.writeShort = function(val) {\n      return this.writeInt16(val);\n    };\n\n    Data.prototype.readLongLong = function() {\n      var b1, b2, b3, b4, b5, b6, b7, b8;\n      b1 = this.readByte();\n      b2 = this.readByte();\n      b3 = this.readByte();\n      b4 = this.readByte();\n      b5 = this.readByte();\n      b6 = this.readByte();\n      b7 = this.readByte();\n      b8 = this.readByte();\n      if (b1 & 0x80) {\n        return ((b1 ^ 0xff) * 0x100000000000000 + (b2 ^ 0xff) * 0x1000000000000 + (b3 ^ 0xff) * 0x10000000000 + (b4 ^ 0xff) * 0x100000000 + (b5 ^ 0xff) * 0x1000000 + (b6 ^ 0xff) * 0x10000 + (b7 ^ 0xff) * 0x100 + (b8 ^ 0xff) + 1) * -1;\n      }\n      return b1 * 0x100000000000000 + b2 * 0x1000000000000 + b3 * 0x10000000000 + b4 * 0x100000000 + b5 * 0x1000000 + b6 * 0x10000 + b7 * 0x100 + b8;\n    };\n\n    Data.prototype.writeLongLong = function(val) {\n      var high, low;\n      high = Math.floor(val / 0x100000000);\n      low = val & 0xffffffff;\n      this.writeByte((high >> 24) & 0xff);\n      this.writeByte((high >> 16) & 0xff);\n      this.writeByte((high >> 8) & 0xff);\n      this.writeByte(high & 0xff);\n      this.writeByte((low >> 24) & 0xff);\n      this.writeByte((low >> 16) & 0xff);\n      this.writeByte((low >> 8) & 0xff);\n      return this.writeByte(low & 0xff);\n    };\n\n    Data.prototype.readInt = function() {\n      return this.readInt32();\n    };\n\n    Data.prototype.writeInt = function(val) {\n      return this.writeInt32(val);\n    };\n\n    Data.prototype.slice = function(start, end) {\n      return this.data.slice(start, end);\n    };\n\n    Data.prototype.read = function(bytes) {\n      var buf, i, j, ref;\n      buf = [];\n      for (i = j = 0, ref = bytes; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {\n        buf.push(this.readByte());\n      }\n      return buf;\n    };\n\n    Data.prototype.write = function(bytes) {\n      var byte, j, len, results;\n      results = [];\n      for (j = 0, len = bytes.length; j < len; j++) {\n        byte = bytes[j];\n        results.push(this.writeByte(byte));\n      }\n      return results;\n    };\n\n    return Data;\n\n  })();\n\n  module.exports = Data;\n\n}).call(this);\n\n\n/***/ }),\n/* 299 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var JPEG, fs,\n    indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };\n\n  fs = __webpack_require__(8);\n\n  JPEG = (function() {\n    var MARKERS;\n\n    MARKERS = [0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC5, 0xFFC6, 0xFFC7, 0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF];\n\n    function JPEG(data, label) {\n      var channels, marker, pos;\n      this.data = data;\n      this.label = label;\n      if (this.data.readUInt16BE(0) !== 0xFFD8) {\n        throw \"SOI not found in JPEG\";\n      }\n      pos = 2;\n      while (pos < this.data.length) {\n        marker = this.data.readUInt16BE(pos);\n        pos += 2;\n        if (indexOf.call(MARKERS, marker) >= 0) {\n          break;\n        }\n        pos += this.data.readUInt16BE(pos);\n      }\n      if (indexOf.call(MARKERS, marker) < 0) {\n        throw \"Invalid JPEG.\";\n      }\n      pos += 2;\n      this.bits = this.data[pos++];\n      this.height = this.data.readUInt16BE(pos);\n      pos += 2;\n      this.width = this.data.readUInt16BE(pos);\n      pos += 2;\n      channels = this.data[pos++];\n      this.colorSpace = (function() {\n        switch (channels) {\n          case 1:\n            return 'DeviceGray';\n          case 3:\n            return 'DeviceRGB';\n          case 4:\n            return 'DeviceCMYK';\n        }\n      })();\n      this.obj = null;\n    }\n\n    JPEG.prototype.embed = function(document) {\n      if (this.obj) {\n        return;\n      }\n      this.obj = document.ref({\n        Type: 'XObject',\n        Subtype: 'Image',\n        BitsPerComponent: this.bits,\n        Width: this.width,\n        Height: this.height,\n        ColorSpace: this.colorSpace,\n        Filter: 'DCTDecode'\n      });\n      if (this.colorSpace === 'DeviceCMYK') {\n        this.obj.data['Decode'] = [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0];\n      }\n      this.obj.end(this.data);\n      return this.data = null;\n    };\n\n    return JPEG;\n\n  })();\n\n  module.exports = JPEG;\n\n}).call(this);\n\n\n/***/ }),\n/* 300 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6\n(function() {\n  var PNG, PNGImage, zlib;\n\n  zlib = __webpack_require__(48);\n\n  PNG = __webpack_require__(301);\n\n  PNGImage = (function() {\n    function PNGImage(data, label) {\n      this.label = label;\n      this.image = new PNG(data);\n      this.width = this.image.width;\n      this.height = this.image.height;\n      this.imgData = this.image.imgData;\n      this.obj = null;\n    }\n\n    PNGImage.prototype.embed = function(document) {\n      var k, len1, mask, palette, params, rgb, val, x;\n      this.document = document;\n      if (this.obj) {\n        return;\n      }\n      this.obj = this.document.ref({\n        Type: 'XObject',\n        Subtype: 'Image',\n        BitsPerComponent: this.image.bits,\n        Width: this.width,\n        Height: this.height,\n        Filter: 'FlateDecode'\n      });\n      if (!this.image.hasAlphaChannel) {\n        params = this.document.ref({\n          Predictor: 15,\n          Colors: this.image.colors,\n          BitsPerComponent: this.image.bits,\n          Columns: this.width\n        });\n        this.obj.data['DecodeParms'] = params;\n        params.end();\n      }\n      if (this.image.palette.length === 0) {\n        this.obj.data['ColorSpace'] = this.image.colorSpace;\n      } else {\n        palette = this.document.ref();\n        palette.end(new Buffer(this.image.palette));\n        this.obj.data['ColorSpace'] = ['Indexed', 'DeviceRGB', (this.image.palette.length / 3) - 1, palette];\n      }\n      if (this.image.transparency.grayscale) {\n        val = this.image.transparency.greyscale;\n        return this.obj.data['Mask'] = [val, val];\n      } else if (this.image.transparency.rgb) {\n        rgb = this.image.transparency.rgb;\n        mask = [];\n        for (k = 0, len1 = rgb.length; k < len1; k++) {\n          x = rgb[k];\n          mask.push(x, x);\n        }\n        return this.obj.data['Mask'] = mask;\n      } else if (this.image.transparency.indexed) {\n        return this.loadIndexedAlphaChannel();\n      } else if (this.image.hasAlphaChannel) {\n        return this.splitAlphaChannel();\n      } else {\n        return this.finalize();\n      }\n    };\n\n    PNGImage.prototype.finalize = function() {\n      var sMask;\n      if (this.alphaChannel) {\n        sMask = this.document.ref({\n          Type: 'XObject',\n          Subtype: 'Image',\n          Height: this.height,\n          Width: this.width,\n          BitsPerComponent: 8,\n          Filter: 'FlateDecode',\n          ColorSpace: 'DeviceGray',\n          Decode: [0, 1]\n        });\n        sMask.end(this.alphaChannel);\n        this.obj.data['SMask'] = sMask;\n      }\n      this.obj.end(this.imgData);\n      this.image = null;\n      return this.imgData = null;\n    };\n\n    PNGImage.prototype.splitAlphaChannel = function() {\n      return this.image.decodePixels((function(_this) {\n        return function(pixels) {\n          var a, alphaChannel, colorByteSize, done, i, imgData, len, p, pixelCount;\n          colorByteSize = _this.image.colors * _this.image.bits / 8;\n          pixelCount = _this.width * _this.height;\n          imgData = new Buffer(pixelCount * colorByteSize);\n          alphaChannel = new Buffer(pixelCount);\n          i = p = a = 0;\n          len = pixels.length;\n          while (i < len) {\n            imgData[p++] = pixels[i++];\n            imgData[p++] = pixels[i++];\n            imgData[p++] = pixels[i++];\n            alphaChannel[a++] = pixels[i++];\n          }\n          done = 0;\n          zlib.deflate(imgData, function(err, imgData1) {\n            _this.imgData = imgData1;\n            if (err) {\n              throw err;\n            }\n            if (++done === 2) {\n              return _this.finalize();\n            }\n          });\n          return zlib.deflate(alphaChannel, function(err, alphaChannel1) {\n            _this.alphaChannel = alphaChannel1;\n            if (err) {\n              throw err;\n            }\n            if (++done === 2) {\n              return _this.finalize();\n            }\n          });\n        };\n      })(this));\n    };\n\n    PNGImage.prototype.loadIndexedAlphaChannel = function(fn) {\n      var transparency;\n      transparency = this.image.transparency.indexed;\n      return this.image.decodePixels((function(_this) {\n        return function(pixels) {\n          var alphaChannel, i, j, k, ref;\n          alphaChannel = new Buffer(_this.width * _this.height);\n          i = 0;\n          for (j = k = 0, ref = pixels.length; k < ref; j = k += 1) {\n            alphaChannel[i++] = transparency[pixels[j]];\n          }\n          return zlib.deflate(alphaChannel, function(err, alphaChannel1) {\n            _this.alphaChannel = alphaChannel1;\n            if (err) {\n              throw err;\n            }\n            return _this.finalize();\n          });\n        };\n      })(this));\n    };\n\n    return PNGImage;\n\n  })();\n\n  module.exports = PNGImage;\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 301 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.4.0\n\n/*\n# MIT LICENSE\n# Copyright (c) 2011 Devon Govett\n# \n# Permission is hereby granted, free of charge, to any person obtaining a copy of this \n# software and associated documentation files (the \"Software\"), to deal in the Software \n# without restriction, including without limitation the rights to use, copy, modify, merge, \n# publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons \n# to whom the Software is furnished to do so, subject to the following conditions:\n# \n# The above copyright notice and this permission notice shall be included in all copies or \n# substantial portions of the Software.\n# \n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING \n# BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \n# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \n# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n\n(function() {\n  var PNG, fs, zlib;\n\n  fs = __webpack_require__(8);\n\n  zlib = __webpack_require__(48);\n\n  module.exports = PNG = (function() {\n\n    PNG.decode = function(path, fn) {\n      return fs.readFile(path, function(err, file) {\n        var png;\n        png = new PNG(file);\n        return png.decode(function(pixels) {\n          return fn(pixels);\n        });\n      });\n    };\n\n    PNG.load = function(path) {\n      var file;\n      file = fs.readFileSync(path);\n      return new PNG(file);\n    };\n\n    function PNG(data) {\n      var chunkSize, colors, i, index, key, section, short, text, _i, _j, _ref;\n      this.data = data;\n      this.pos = 8;\n      this.palette = [];\n      this.imgData = [];\n      this.transparency = {};\n      this.text = {};\n      while (true) {\n        chunkSize = this.readUInt32();\n        section = ((function() {\n          var _i, _results;\n          _results = [];\n          for (i = _i = 0; _i < 4; i = ++_i) {\n            _results.push(String.fromCharCode(this.data[this.pos++]));\n          }\n          return _results;\n        }).call(this)).join('');\n        switch (section) {\n          case 'IHDR':\n            this.width = this.readUInt32();\n            this.height = this.readUInt32();\n            this.bits = this.data[this.pos++];\n            this.colorType = this.data[this.pos++];\n            this.compressionMethod = this.data[this.pos++];\n            this.filterMethod = this.data[this.pos++];\n            this.interlaceMethod = this.data[this.pos++];\n            break;\n          case 'PLTE':\n            this.palette = this.read(chunkSize);\n            break;\n          case 'IDAT':\n            for (i = _i = 0; _i < chunkSize; i = _i += 1) {\n              this.imgData.push(this.data[this.pos++]);\n            }\n            break;\n          case 'tRNS':\n            this.transparency = {};\n            switch (this.colorType) {\n              case 3:\n                this.transparency.indexed = this.read(chunkSize);\n                short = 255 - this.transparency.indexed.length;\n                if (short > 0) {\n                  for (i = _j = 0; 0 <= short ? _j < short : _j > short; i = 0 <= short ? ++_j : --_j) {\n                    this.transparency.indexed.push(255);\n                  }\n                }\n                break;\n              case 0:\n                this.transparency.grayscale = this.read(chunkSize)[0];\n                break;\n              case 2:\n                this.transparency.rgb = this.read(chunkSize);\n            }\n            break;\n          case 'tEXt':\n            text = this.read(chunkSize);\n            index = text.indexOf(0);\n            key = String.fromCharCode.apply(String, text.slice(0, index));\n            this.text[key] = String.fromCharCode.apply(String, text.slice(index + 1));\n            break;\n          case 'IEND':\n            this.colors = (function() {\n              switch (this.colorType) {\n                case 0:\n                case 3:\n                case 4:\n                  return 1;\n                case 2:\n                case 6:\n                  return 3;\n              }\n            }).call(this);\n            this.hasAlphaChannel = (_ref = this.colorType) === 4 || _ref === 6;\n            colors = this.colors + (this.hasAlphaChannel ? 1 : 0);\n            this.pixelBitlength = this.bits * colors;\n            this.colorSpace = (function() {\n              switch (this.colors) {\n                case 1:\n                  return 'DeviceGray';\n                case 3:\n                  return 'DeviceRGB';\n              }\n            }).call(this);\n            this.imgData = new Buffer(this.imgData);\n            return;\n          default:\n            this.pos += chunkSize;\n        }\n        this.pos += 4;\n        if (this.pos > this.data.length) {\n          throw new Error(\"Incomplete or corrupt PNG file\");\n        }\n      }\n      return;\n    }\n\n    PNG.prototype.read = function(bytes) {\n      var i, _i, _results;\n      _results = [];\n      for (i = _i = 0; 0 <= bytes ? _i < bytes : _i > bytes; i = 0 <= bytes ? ++_i : --_i) {\n        _results.push(this.data[this.pos++]);\n      }\n      return _results;\n    };\n\n    PNG.prototype.readUInt32 = function() {\n      var b1, b2, b3, b4;\n      b1 = this.data[this.pos++] << 24;\n      b2 = this.data[this.pos++] << 16;\n      b3 = this.data[this.pos++] << 8;\n      b4 = this.data[this.pos++];\n      return b1 | b2 | b3 | b4;\n    };\n\n    PNG.prototype.readUInt16 = function() {\n      var b1, b2;\n      b1 = this.data[this.pos++] << 8;\n      b2 = this.data[this.pos++];\n      return b1 | b2;\n    };\n\n    PNG.prototype.decodePixels = function(fn) {\n      var _this = this;\n      return zlib.inflate(this.imgData, function(err, data) {\n        var byte, c, col, i, left, length, p, pa, paeth, pb, pc, pixelBytes, pixels, pos, row, scanlineLength, upper, upperLeft, _i, _j, _k, _l, _m;\n        if (err) {\n          throw err;\n        }\n        pixelBytes = _this.pixelBitlength / 8;\n        scanlineLength = pixelBytes * _this.width;\n        pixels = new Buffer(scanlineLength * _this.height);\n        length = data.length;\n        row = 0;\n        pos = 0;\n        c = 0;\n        while (pos < length) {\n          switch (data[pos++]) {\n            case 0:\n              for (i = _i = 0; _i < scanlineLength; i = _i += 1) {\n                pixels[c++] = data[pos++];\n              }\n              break;\n            case 1:\n              for (i = _j = 0; _j < scanlineLength; i = _j += 1) {\n                byte = data[pos++];\n                left = i < pixelBytes ? 0 : pixels[c - pixelBytes];\n                pixels[c++] = (byte + left) % 256;\n              }\n              break;\n            case 2:\n              for (i = _k = 0; _k < scanlineLength; i = _k += 1) {\n                byte = data[pos++];\n                col = (i - (i % pixelBytes)) / pixelBytes;\n                upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];\n                pixels[c++] = (upper + byte) % 256;\n              }\n              break;\n            case 3:\n              for (i = _l = 0; _l < scanlineLength; i = _l += 1) {\n                byte = data[pos++];\n                col = (i - (i % pixelBytes)) / pixelBytes;\n                left = i < pixelBytes ? 0 : pixels[c - pixelBytes];\n                upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];\n                pixels[c++] = (byte + Math.floor((left + upper) / 2)) % 256;\n              }\n              break;\n            case 4:\n              for (i = _m = 0; _m < scanlineLength; i = _m += 1) {\n                byte = data[pos++];\n                col = (i - (i % pixelBytes)) / pixelBytes;\n                left = i < pixelBytes ? 0 : pixels[c - pixelBytes];\n                if (row === 0) {\n                  upper = upperLeft = 0;\n                } else {\n                  upper = pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];\n                  upperLeft = col && pixels[(row - 1) * scanlineLength + (col - 1) * pixelBytes + (i % pixelBytes)];\n                }\n                p = left + upper - upperLeft;\n                pa = Math.abs(p - left);\n                pb = Math.abs(p - upper);\n                pc = Math.abs(p - upperLeft);\n                if (pa <= pb && pa <= pc) {\n                  paeth = left;\n                } else if (pb <= pc) {\n                  paeth = upper;\n                } else {\n                  paeth = upperLeft;\n                }\n                pixels[c++] = (byte + paeth) % 256;\n              }\n              break;\n            default:\n              throw new Error(\"Invalid filter algorithm: \" + data[pos - 1]);\n          }\n          row++;\n        }\n        return fn(pixels);\n      });\n    };\n\n    PNG.prototype.decodePalette = function() {\n      var c, i, length, palette, pos, ret, transparency, _i, _ref, _ref1;\n      palette = this.palette;\n      transparency = this.transparency.indexed || [];\n      ret = new Buffer(transparency.length + palette.length);\n      pos = 0;\n      length = palette.length;\n      c = 0;\n      for (i = _i = 0, _ref = palette.length; _i < _ref; i = _i += 3) {\n        ret[pos++] = palette[i];\n        ret[pos++] = palette[i + 1];\n        ret[pos++] = palette[i + 2];\n        ret[pos++] = (_ref1 = transparency[c++]) != null ? _ref1 : 255;\n      }\n      return ret;\n    };\n\n    PNG.prototype.copyToImageData = function(imageData, pixels) {\n      var alpha, colors, data, i, input, j, k, length, palette, v, _ref;\n      colors = this.colors;\n      palette = null;\n      alpha = this.hasAlphaChannel;\n      if (this.palette.length) {\n        palette = (_ref = this._decodedPalette) != null ? _ref : this._decodedPalette = this.decodePalette();\n        colors = 4;\n        alpha = true;\n      }\n      data = (imageData != null ? imageData.data : void 0) || imageData;\n      length = data.length;\n      input = palette || pixels;\n      i = j = 0;\n      if (colors === 1) {\n        while (i < length) {\n          k = palette ? pixels[i / 4] * 4 : j;\n          v = input[k++];\n          data[i++] = v;\n          data[i++] = v;\n          data[i++] = v;\n          data[i++] = alpha ? input[k++] : 255;\n          j = k;\n        }\n      } else {\n        while (i < length) {\n          k = palette ? pixels[i / 4] * 4 : j;\n          data[i++] = input[k++];\n          data[i++] = input[k++];\n          data[i++] = input[k++];\n          data[i++] = alpha ? input[k++] : 255;\n          j = k;\n        }\n      }\n    };\n\n    PNG.prototype.decode = function(fn) {\n      var ret,\n        _this = this;\n      ret = new Buffer(this.width * this.height * 4);\n      return this.decodePixels(function(pixels) {\n        _this.copyToImageData(ret, pixels);\n        return fn(ret);\n      });\n    };\n\n    return PNG;\n\n  })();\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 302 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  module.exports = {\n    annotate: function(x, y, w, h, options) {\n      var key, ref, val;\n      options.Type = 'Annot';\n      options.Rect = this._convertRect(x, y, w, h);\n      options.Border = [0, 0, 0];\n      if (options.Subtype !== 'Link') {\n        if (options.C == null) {\n          options.C = this._normalizeColor(options.color || [0, 0, 0]);\n        }\n      }\n      delete options.color;\n      if (typeof options.Dest === 'string') {\n        options.Dest = new String(options.Dest);\n      }\n      for (key in options) {\n        val = options[key];\n        options[key[0].toUpperCase() + key.slice(1)] = val;\n      }\n      ref = this.ref(options);\n      this.page.annotations.push(ref);\n      ref.end();\n      return this;\n    },\n    note: function(x, y, w, h, contents, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'Text';\n      options.Contents = new String(contents);\n      options.Name = 'Comment';\n      if (options.color == null) {\n        options.color = [243, 223, 92];\n      }\n      return this.annotate(x, y, w, h, options);\n    },\n    link: function(x, y, w, h, url, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'Link';\n      options.A = this.ref({\n        S: 'URI',\n        URI: new String(url)\n      });\n      options.A.end();\n      return this.annotate(x, y, w, h, options);\n    },\n    _markup: function(x, y, w, h, options) {\n      var ref1, x1, x2, y1, y2;\n      if (options == null) {\n        options = {};\n      }\n      ref1 = this._convertRect(x, y, w, h), x1 = ref1[0], y1 = ref1[1], x2 = ref1[2], y2 = ref1[3];\n      options.QuadPoints = [x1, y2, x2, y2, x1, y1, x2, y1];\n      options.Contents = new String;\n      return this.annotate(x, y, w, h, options);\n    },\n    highlight: function(x, y, w, h, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'Highlight';\n      if (options.color == null) {\n        options.color = [241, 238, 148];\n      }\n      return this._markup(x, y, w, h, options);\n    },\n    underline: function(x, y, w, h, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'Underline';\n      return this._markup(x, y, w, h, options);\n    },\n    strike: function(x, y, w, h, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'StrikeOut';\n      return this._markup(x, y, w, h, options);\n    },\n    lineAnnotation: function(x1, y1, x2, y2, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'Line';\n      options.Contents = new String;\n      options.L = [x1, this.page.height - y1, x2, this.page.height - y2];\n      return this.annotate(x1, y1, x2, y2, options);\n    },\n    rectAnnotation: function(x, y, w, h, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'Square';\n      options.Contents = new String;\n      return this.annotate(x, y, w, h, options);\n    },\n    ellipseAnnotation: function(x, y, w, h, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'Circle';\n      options.Contents = new String;\n      return this.annotate(x, y, w, h, options);\n    },\n    textAnnotation: function(x, y, w, h, text, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'FreeText';\n      options.Contents = new String(text);\n      options.DA = new String;\n      return this.annotate(x, y, w, h, options);\n    },\n    _convertRect: function(x1, y1, w, h) {\n      var m0, m1, m2, m3, m4, m5, ref1, x2, y2;\n      y2 = y1;\n      y1 += h;\n      x2 = x1 + w;\n      ref1 = this._ctm, m0 = ref1[0], m1 = ref1[1], m2 = ref1[2], m3 = ref1[3], m4 = ref1[4], m5 = ref1[5];\n      x1 = m0 * x1 + m2 * y1 + m4;\n      y1 = m1 * x1 + m3 * y1 + m5;\n      x2 = m0 * x2 + m2 * y2 + m4;\n      y2 = m1 * x2 + m3 * y2 + m5;\n      return [x1, y1, x2, y2];\n    }\n  };\n\n}).call(this);\n\n\n/***/ }),\n/* 303 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nmodule.exports = {\n\t'4A0': [4767.87, 6740.79],\n\t'2A0': [3370.39, 4767.87],\n\tA0: [2383.94, 3370.39],\n\tA1: [1683.78, 2383.94],\n\tA2: [1190.55, 1683.78],\n\tA3: [841.89, 1190.55],\n\tA4: [595.28, 841.89],\n\tA5: [419.53, 595.28],\n\tA6: [297.64, 419.53],\n\tA7: [209.76, 297.64],\n\tA8: [147.40, 209.76],\n\tA9: [104.88, 147.40],\n\tA10: [73.70, 104.88],\n\tB0: [2834.65, 4008.19],\n\tB1: [2004.09, 2834.65],\n\tB2: [1417.32, 2004.09],\n\tB3: [1000.63, 1417.32],\n\tB4: [708.66, 1000.63],\n\tB5: [498.90, 708.66],\n\tB6: [354.33, 498.90],\n\tB7: [249.45, 354.33],\n\tB8: [175.75, 249.45],\n\tB9: [124.72, 175.75],\n\tB10: [87.87, 124.72],\n\tC0: [2599.37, 3676.54],\n\tC1: [1836.85, 2599.37],\n\tC2: [1298.27, 1836.85],\n\tC3: [918.43, 1298.27],\n\tC4: [649.13, 918.43],\n\tC5: [459.21, 649.13],\n\tC6: [323.15, 459.21],\n\tC7: [229.61, 323.15],\n\tC8: [161.57, 229.61],\n\tC9: [113.39, 161.57],\n\tC10: [79.37, 113.39],\n\tRA0: [2437.80, 3458.27],\n\tRA1: [1729.13, 2437.80],\n\tRA2: [1218.90, 1729.13],\n\tRA3: [864.57, 1218.90],\n\tRA4: [609.45, 864.57],\n\tSRA0: [2551.18, 3628.35],\n\tSRA1: [1814.17, 2551.18],\n\tSRA2: [1275.59, 1814.17],\n\tSRA3: [907.09, 1275.59],\n\tSRA4: [637.80, 907.09],\n\tEXECUTIVE: [521.86, 756.00],\n\tFOLIO: [612.00, 936.00],\n\tLEGAL: [612.00, 1008.00],\n\tLETTER: [612.00, 792.00],\n\tTABLOID: [792.00, 1224.00]\n};\n\n\n/***/ }),\n/* 304 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(Buffer) {\n\nvar PDFImage = __webpack_require__(121);\n\nfunction ImageMeasure(pdfKitDoc, imageDictionary) {\n\tthis.pdfKitDoc = pdfKitDoc;\n\tthis.imageDictionary = imageDictionary || {};\n}\n\nImageMeasure.prototype.measureImage = function (src) {\n\tvar image, label;\n\tvar that = this;\n\n\tif (!this.pdfKitDoc._imageRegistry[src]) {\n\t\tlabel = 'I' + (++this.pdfKitDoc._imageCount);\n\t\ttry {\n\t\t\timage = PDFImage.open(realImageSrc(src), label);\n\t\t} catch (error) {\n\t\t\timage = null;\n\t\t}\n\t\tif (image === null || image === undefined) {\n\t\t\tthrow 'invalid image, images dictionary should contain dataURL entries (or local file paths in node.js)';\n\t\t}\n\t\timage.embed(this.pdfKitDoc);\n\t\tthis.pdfKitDoc._imageRegistry[src] = image;\n\t} else {\n\t\timage = this.pdfKitDoc._imageRegistry[src];\n\t}\n\n\treturn {width: image.width, height: image.height};\n\n\tfunction realImageSrc(src) {\n\t\tvar img = that.imageDictionary[src];\n\n\t\tif (!img) {\n\t\t\treturn src;\n\t\t}\n\n\t\tvar index = img.indexOf('base64,');\n\t\tif (index < 0) {\n\t\t\treturn that.imageDictionary[src];\n\t\t}\n\n\t\treturn Buffer.from(img.substring(index + 7), 'base64');\n\t}\n};\n\nmodule.exports = ImageMeasure;\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 305 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar isArray = __webpack_require__(0).isArray;\n\nfunction groupDecorations(line) {\n\tvar groups = [], currentGroup = null;\n\tfor (var i = 0, l = line.inlines.length; i < l; i++) {\n\t\tvar inline = line.inlines[i];\n\t\tvar decoration = inline.decoration;\n\t\tif (!decoration) {\n\t\t\tcurrentGroup = null;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!isArray(decoration)) {\n\t\t\tdecoration = [decoration];\n\t\t}\n\t\tvar color = inline.decorationColor || inline.color || 'black';\n\t\tvar style = inline.decorationStyle || 'solid';\n\t\tfor (var ii = 0, ll = decoration.length; ii < ll; ii++) {\n\t\t\tvar decorationItem = decoration[ii];\n\t\t\tif (!currentGroup || decorationItem !== currentGroup.decoration ||\n\t\t\t\tstyle !== currentGroup.decorationStyle || color !== currentGroup.decorationColor ||\n\t\t\t\tdecorationItem === 'lineThrough') {\n\n\t\t\t\tcurrentGroup = {\n\t\t\t\t\tline: line,\n\t\t\t\t\tdecoration: decorationItem,\n\t\t\t\t\tdecorationColor: color,\n\t\t\t\t\tdecorationStyle: style,\n\t\t\t\t\tinlines: [inline]\n\t\t\t\t};\n\t\t\t\tgroups.push(currentGroup);\n\t\t\t} else {\n\t\t\t\tcurrentGroup.inlines.push(inline);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn groups;\n}\n\nfunction drawDecoration(group, x, y, pdfKitDoc) {\n\tfunction maxInline() {\n\t\tvar max = 0;\n\t\tfor (var i = 0, l = group.inlines.length; i < l; i++) {\n\t\t\tvar inline = group.inlines[i];\n\t\t\tmax = inline.fontSize > max ? i : max;\n\t\t}\n\t\treturn group.inlines[max];\n\t}\n\tfunction width() {\n\t\tvar sum = 0;\n\t\tfor (var i = 0, l = group.inlines.length; i < l; i++) {\n\t\t\tsum += group.inlines[i].width;\n\t\t}\n\t\treturn sum;\n\t}\n\tvar firstInline = group.inlines[0],\n\t\tbiggerInline = maxInline(),\n\t\ttotalWidth = width(),\n\t\tlineAscent = group.line.getAscenderHeight(),\n\t\tascent = biggerInline.font.ascender / 1000 * biggerInline.fontSize,\n\t\theight = biggerInline.height,\n\t\tdescent = height - ascent;\n\n\tvar lw = 0.5 + Math.floor(Math.max(biggerInline.fontSize - 8, 0) / 2) * 0.12;\n\n\tswitch (group.decoration) {\n\t\tcase 'underline':\n\t\t\ty += lineAscent + descent * 0.45;\n\t\t\tbreak;\n\t\tcase 'overline':\n\t\t\ty += lineAscent - (ascent * 0.85);\n\t\t\tbreak;\n\t\tcase 'lineThrough':\n\t\t\ty += lineAscent - (ascent * 0.25);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tthrow 'Unkown decoration : ' + group.decoration;\n\t}\n\tpdfKitDoc.save();\n\n\tif (group.decorationStyle === 'double') {\n\t\tvar gap = Math.max(0.5, lw * 2);\n\t\tpdfKitDoc.fillColor(group.decorationColor)\n\t\t\t.rect(x + firstInline.x, y - lw / 2, totalWidth, lw / 2).fill()\n\t\t\t.rect(x + firstInline.x, y + gap - lw / 2, totalWidth, lw / 2).fill();\n\t} else if (group.decorationStyle === 'dashed') {\n\t\tvar nbDashes = Math.ceil(totalWidth / (3.96 + 2.84));\n\t\tvar rdx = x + firstInline.x;\n\t\tpdfKitDoc.rect(rdx, y, totalWidth, lw).clip();\n\t\tpdfKitDoc.fillColor(group.decorationColor);\n\t\tfor (var i = 0; i < nbDashes; i++) {\n\t\t\tpdfKitDoc.rect(rdx, y - lw / 2, 3.96, lw).fill();\n\t\t\trdx += 3.96 + 2.84;\n\t\t}\n\t} else if (group.decorationStyle === 'dotted') {\n\t\tvar nbDots = Math.ceil(totalWidth / (lw * 3));\n\t\tvar rx = x + firstInline.x;\n\t\tpdfKitDoc.rect(rx, y, totalWidth, lw).clip();\n\t\tpdfKitDoc.fillColor(group.decorationColor);\n\t\tfor (var ii = 0; ii < nbDots; ii++) {\n\t\t\tpdfKitDoc.rect(rx, y - lw / 2, lw, lw).fill();\n\t\t\trx += (lw * 3);\n\t\t}\n\t} else if (group.decorationStyle === 'wavy') {\n\t\tvar sh = 0.7, sv = 1;\n\t\tvar nbWaves = Math.ceil(totalWidth / (sh * 2)) + 1;\n\t\tvar rwx = x + firstInline.x - 1;\n\t\tpdfKitDoc.rect(x + firstInline.x, y - sv, totalWidth, y + sv).clip();\n\t\tpdfKitDoc.lineWidth(0.24);\n\t\tpdfKitDoc.moveTo(rwx, y);\n\t\tfor (var iii = 0; iii < nbWaves; iii++) {\n\t\t\tpdfKitDoc.bezierCurveTo(rwx + sh, y - sv, rwx + sh * 2, y - sv, rwx + sh * 3, y)\n\t\t\t\t.bezierCurveTo(rwx + sh * 4, y + sv, rwx + sh * 5, y + sv, rwx + sh * 6, y);\n\t\t\trwx += sh * 6;\n\t\t}\n\t\tpdfKitDoc.stroke(group.decorationColor);\n\t} else {\n\t\tpdfKitDoc.fillColor(group.decorationColor)\n\t\t\t.rect(x + firstInline.x, y - lw / 2, totalWidth, lw)\n\t\t\t.fill();\n\t}\n\tpdfKitDoc.restore();\n}\n\nfunction drawDecorations(line, x, y, pdfKitDoc) {\n\tvar groups = groupDecorations(line);\n\tfor (var i = 0, l = groups.length; i < l; i++) {\n\t\tdrawDecoration(groups[i], x, y, pdfKitDoc);\n\t}\n}\n\nfunction drawBackground(line, x, y, pdfKitDoc) {\n\tvar height = line.getHeight();\n\tfor (var i = 0, l = line.inlines.length; i < l; i++) {\n\t\tvar inline = line.inlines[i];\n\t\tif (!inline.background) {\n\t\t\tcontinue;\n\t\t}\n\t\tvar justifyShift = (inline.justifyShift || 0);\n\t\tpdfKitDoc.fillColor(inline.background)\n\t\t\t.rect(x + inline.x - justifyShift, y, inline.width + justifyShift, height)\n\t\t\t.fill();\n\t}\n}\n\nmodule.exports = {\n\tdrawBackground: drawBackground,\n\tdrawDecorations: drawDecorations\n};\n\n/***/ }),\n/* 306 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar __WEBPACK_AMD_DEFINE_RESULT__;/* FileSaver.js\n * A saveAs() FileSaver implementation.\n * 1.3.2\n * 2016-06-16 18:25:19\n *\n * By Eli Grey, http://eligrey.com\n * License: MIT\n *   See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md\n */\n\n/*global self */\n/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */\n\n/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */\n\nvar saveAs = saveAs || (function(view) {\n\t\"use strict\";\n\t// IE <10 is explicitly unsupported\n\tif (typeof view === \"undefined\" || typeof navigator !== \"undefined\" && /MSIE [1-9]\\./.test(navigator.userAgent)) {\n\t\treturn;\n\t}\n\tvar\n\t\t  doc = view.document\n\t\t  // only get URL when necessary in case Blob.js hasn't overridden it yet\n\t\t, get_URL = function() {\n\t\t\treturn view.URL || view.webkitURL || view;\n\t\t}\n\t\t, save_link = doc ? doc.createElementNS(\"http://www.w3.org/1999/xhtml\", \"a\") : []\n\t\t, can_use_save_link = \"download\" in save_link\n\t\t, click = function(node) {\n\t\t\tvar event = new MouseEvent(\"click\");\n\t\t\tnode.dispatchEvent(event);\n\t\t}\n\t\t, is_safari = /constructor/i.test(view.HTMLElement) || view.safari\n\t\t, is_chrome_ios =/CriOS\\/[\\d]+/.test(navigator.userAgent)\n\t\t, throw_outside = function(ex) {\n\t\t\t(view.setImmediate || view.setTimeout)(function() {\n\t\t\t\tthrow ex;\n\t\t\t}, 0);\n\t\t}\n\t\t, force_saveable_type = \"application/octet-stream\"\n\t\t// the Blob API is fundamentally broken as there is no \"downloadfinished\" event to subscribe to\n\t\t, arbitrary_revoke_timeout = 1000 * 40 // in ms\n\t\t, revoke = function(file) {\n\t\t\tvar revoker = function() {\n\t\t\t\tif (typeof file === \"string\") { // file is an object URL\n\t\t\t\t\tget_URL().revokeObjectURL(file);\n\t\t\t\t} else { // file is a File\n\t\t\t\t\tfile.remove();\n\t\t\t\t}\n\t\t\t};\n\t\t\tsetTimeout(revoker, arbitrary_revoke_timeout);\n\t\t}\n\t\t, dispatch = function(filesaver, event_types, event) {\n\t\t\tevent_types = [].concat(event_types);\n\t\t\tvar i = event_types.length;\n\t\t\twhile (i--) {\n\t\t\t\tvar listener = filesaver[\"on\" + event_types[i]];\n\t\t\t\tif (typeof listener === \"function\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tlistener.call(filesaver, event || filesaver);\n\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\tthrow_outside(ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t, auto_bom = function(blob) {\n\t\t\t// prepend BOM for UTF-8 XML and text/* types (including HTML)\n\t\t\t// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF\n\t\t\tif (/^\\s*(?:text\\/\\S*|application\\/xml|\\S*\\/\\S*\\+xml)\\s*;.*charset\\s*=\\s*utf-8/i.test(blob.type)) {\n\t\t\t\treturn new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});\n\t\t\t}\n\t\t\treturn blob;\n\t\t}\n\t\t, FileSaver = function(blob, name, no_auto_bom) {\n\t\t\tif (!no_auto_bom) {\n\t\t\t\tblob = auto_bom(blob);\n\t\t\t}\n\t\t\t// First try a.download, then web filesystem, then object URLs\n\t\t\tvar\n\t\t\t\t  filesaver = this\n\t\t\t\t, type = blob.type\n\t\t\t\t, force = type === force_saveable_type\n\t\t\t\t, object_url\n\t\t\t\t, dispatch_all = function() {\n\t\t\t\t\tdispatch(filesaver, \"writestart progress write writeend\".split(\" \"));\n\t\t\t\t}\n\t\t\t\t// on any filesys errors revert to saving with object URLs\n\t\t\t\t, fs_error = function() {\n\t\t\t\t\tif ((is_chrome_ios || (force && is_safari)) && view.FileReader) {\n\t\t\t\t\t\t// Safari doesn't allow downloading of blob urls\n\t\t\t\t\t\tvar reader = new FileReader();\n\t\t\t\t\t\treader.onloadend = function() {\n\t\t\t\t\t\t\tvar url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');\n\t\t\t\t\t\t\tvar popup = view.open(url, '_blank');\n\t\t\t\t\t\t\tif(!popup) view.location.href = url;\n\t\t\t\t\t\t\turl=undefined; // release reference before dispatching\n\t\t\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t\t\t\tdispatch_all();\n\t\t\t\t\t\t};\n\t\t\t\t\t\treader.readAsDataURL(blob);\n\t\t\t\t\t\tfilesaver.readyState = filesaver.INIT;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// don't create more object URLs than needed\n\t\t\t\t\tif (!object_url) {\n\t\t\t\t\t\tobject_url = get_URL().createObjectURL(blob);\n\t\t\t\t\t}\n\t\t\t\t\tif (force) {\n\t\t\t\t\t\tview.location.href = object_url;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar opened = view.open(object_url, \"_blank\");\n\t\t\t\t\t\tif (!opened) {\n\t\t\t\t\t\t\t// Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html\n\t\t\t\t\t\t\tview.location.href = object_url;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t\tdispatch_all();\n\t\t\t\t\trevoke(object_url);\n\t\t\t\t}\n\t\t\t;\n\t\t\tfilesaver.readyState = filesaver.INIT;\n\n\t\t\tif (can_use_save_link) {\n\t\t\t\tobject_url = get_URL().createObjectURL(blob);\n\t\t\t\tsetTimeout(function() {\n\t\t\t\t\tsave_link.href = object_url;\n\t\t\t\t\tsave_link.download = name;\n\t\t\t\t\tclick(save_link);\n\t\t\t\t\tdispatch_all();\n\t\t\t\t\trevoke(object_url);\n\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfs_error();\n\t\t}\n\t\t, FS_proto = FileSaver.prototype\n\t\t, saveAs = function(blob, name, no_auto_bom) {\n\t\t\treturn new FileSaver(blob, name || blob.name || \"download\", no_auto_bom);\n\t\t}\n\t;\n\t// IE 10+ (native saveAs)\n\tif (typeof navigator !== \"undefined\" && navigator.msSaveOrOpenBlob) {\n\t\treturn function(blob, name, no_auto_bom) {\n\t\t\tname = name || blob.name || \"download\";\n\n\t\t\tif (!no_auto_bom) {\n\t\t\t\tblob = auto_bom(blob);\n\t\t\t}\n\t\t\treturn navigator.msSaveOrOpenBlob(blob, name);\n\t\t};\n\t}\n\n\tFS_proto.abort = function(){};\n\tFS_proto.readyState = FS_proto.INIT = 0;\n\tFS_proto.WRITING = 1;\n\tFS_proto.DONE = 2;\n\n\tFS_proto.error =\n\tFS_proto.onwritestart =\n\tFS_proto.onprogress =\n\tFS_proto.onwrite =\n\tFS_proto.onabort =\n\tFS_proto.onerror =\n\tFS_proto.onwriteend =\n\t\tnull;\n\n\treturn saveAs;\n}(\n\t   typeof self !== \"undefined\" && self\n\t|| typeof window !== \"undefined\" && window\n\t|| this.content\n));\n// `self` is undefined in Firefox for Android content script context\n// while `this` is nsIContentFrameMessageManager\n// with an attribute `content` that corresponds to the window\n\nif (typeof module !== \"undefined\" && module.exports) {\n  module.exports.saveAs = saveAs;\n} else if ((\"function\" !== \"undefined\" && __webpack_require__(307) !== null) && (__webpack_require__(308) !== null)) {\n  !(__WEBPACK_AMD_DEFINE_RESULT__ = (function() {\n    return saveAs;\n  }).call(exports, __webpack_require__, exports, module),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n}\n\n\n/***/ }),\n/* 307 */\n/***/ (function(module, exports) {\n\nmodule.exports = function() {\n\tthrow new Error(\"define cannot be used indirect\");\n};\n\n\n/***/ }),\n/* 308 */\n/***/ (function(module, exports) {\n\n/* WEBPACK VAR INJECTION */(function(__webpack_amd_options__) {/* globals __webpack_amd_options__ */\nmodule.exports = __webpack_amd_options__;\n\n/* WEBPACK VAR INJECTION */}.call(exports, {}))\n\n/***/ })\n/******/ ]);\n});\n\nthis.pdfMake = this.pdfMake || {}; this.pdfMake.vfs = {\n  \"Roboto-Italic.ttf\": \"AAEAAAASAQAABAAgR0RFRtRX1FkAAgp8AAACREdQT1NKcuCzAAIMwAAAUiRHU1VCw4aZEQACXuQAABfoT1MvMqCnsO0AAAGoAAAAYGNtYXBAbb9DAAAafAAABoBjdnQgJEEG5QAAI5QAAABMZnBnbWf0XKsAACD8AAABvGdhc3AACAATAAIKcAAAAAxnbHlmoLsktAAALagAAdn2aGRteCEe/AUAABWQAAAE7GhlYWT4gasAAAABLAAAADZoaGVhDKYSegAAAWQAAAAkaG10eHJO1ygAAAIIAAATiGxvY2EXM5zBAAAj4AAACcZtYXhwBxICWwAAAYgAAAAgbmFtZTlLZFAAAgegAAACrnBvc3T/YQBkAAIKUAAAACBwcmVwdKCP7AAAIrgAAADbAAEAAAACAAAcadIiXw889QAbCAAAAAAAxPARLgAAAADQ206M+jj91QlMCHMAAgAJAAIAAAAAAAAAAQAAB2z+DAAACRb6OP52CUwIAAGzAAAAAAAAAAAAAAAABOIAAQAABOIAkAAWAFYABQABAAAAAAAOAAACAAFzAAYAAQADBAsBkAAFAAAFmgUzAAABHwWaBTMAAAPRAGYCAAAAAgAAAAAAAAAAAOAACv9QACF/AAAAIQAAAABHT09HAAEAAP/9BgD+AABmB5oCACAAAZ8AAAAABDoFsAAgACAAAgOWAGQACgAAAAoAAAH2AAAB9gAAAgkAQwKFAMgE0QBSBGYASgW5ALsE3QA6AWQAqgKxAG0Cvf+PA2IAawRwAEwBkP+PAi4AGQIVADUDPf+PBGYAaARmAPkEZgAXBGYANARmAAUEZgByBGYAcARmAJ0EZgBBBGYAlAHrACsBrv+bA/wAQQRMAHAEGAA6A7QApQcCAEQFGv+vBN8AOwUXAHQFIQA7BHMAOwRUADsFUwB5BZIAOwImAEkEUgAKBOcAOwQ3ADsG0AA7BZIAOwVgAHcE7wA7BWAAbwTRADoEpQAnBKsAqAUSAGcE+gCkBuwAwwTn/9QEswCoBK//6wIZ//8DOQC/Ahn/egNIAE8Div+BAnAAzwRDADMEZQAfBBoARgRqAEsEJgBFArwAdARlAAQEUAAfAewALwHk/xQD+QAgAewALwbXAB4EUgAfBHcARQRl/9cEcwBJAqoAHwQKAC4CkwBDBFEAWwPMAG4F3wCAA+P/xAO2/6UD4//tAqoAOAHuACECqv+MBVEAaQHu//EESABSBIz/8wWSABIEvQBTAeb/9wTM/90DSADbBiMAYgOCAMMDrgBZBFYAgQYkAGEDmADjAvAA6AQvACUC4gBcAuIAbgJ5ANUEb//lA9UAewIQAKUB9v/IAuIA3wORAMADrQAPBbkAuQYPALQGEwCeA7b/0wdL/4QELQAoBWAAIASgADgEpwAeBpcAEwSWAFwEeABEBG8AOQSD/+AFeQA1AfUALgRbAC0EOAAiAiIAIwVqADUEbwAkB3AAVAcWAEcB9wAzBWcAUQKu/0kFXgBnBHkAQgVvAGcE1wBaAf7/CQQhAD4DsQEXA3wBJgOZAOMDWgEHAewBDgKiAQECI/+vA7MA3QLvAMICUv/pAAr9agAK/esACv0LAAr99QAK/NsB6vy7AgcBIQP2APMCEQClBFsAQwWD/7EFUQBpBSD/xAR4AAwFkwBEBHj/2gWZAFQFaACGBTMACgRsAEgEo//wA+0AhARvAEMEOQApBA8AggRvACQEdQBzAo0AhQRW/7cD2AA/BKkAYARv/9wENgBOBG8ASgQWAIcERQBnBYIAQQV5AE8GbgBmBIcAUQQrAGcGIgBmBdsAoQVFAHgIWf/MCGwAQwZaALQFkgBCBO4ANAXg/4sHFf+sBKUAJQWSAEMFiP/KBOoAkwYHAFsFtgBBBVoAzgdXAEIHjgBCBe0AiQbAAEUE6AA2BUUAdAb6AEkE+//oBFQARgR5ADADSwAtBLn/jQX7/6UD+wAhBIUALwQ7AC8Ehv/IBcsAMASEAC8EhQAvA8QAYAWqAEwEowAvBEIAewZQAC8GdQAkBNsAVgYQADAEQQAwBDYANAZfADAETP+/BFAAHwQ2AE4Gn//DBrkALwRwAB8EhQAvBtwAbwYGAE8EPwAuBv4ASQXUACwEt/+6BC//ogbfAFoF5wBOBqcAJgW+ACkIyQBIB58ALgQN/84Dx//KBVEAaQRyAEIE7QCtA+4AhAVRAGoEbwBEBtUAdAX/AFIG3ABvBgYATwUUAGYEMABNBOEAQAAK/OgACv0LAAr+FwAK/jsACvo4AAr6TwQ/AC4E/gA6BHD/1wRLADUDfwAkBMAAQwPwACQE7AA2BGYALQZkALsFYwB0B50AOgWSACQH/ABCBskAJAXKAHEEuABfBv8ArAU9AFcFTwDEBFIAmAVQAOwGCgCKBKMABwTsADUEQwAtBZAAQwRvACQFZwBRBI4APASO//wEnf/4Azr/6QTaADEGawAyBrkATAYvAK0FDQBoBDIArwPyAKAHj//fBk3/2gfIADsGeAAjBNoAagQHAEwFiwCaBQMAfQVFAGoDEgDyA/8AAAf0AAAD/wAAB/QAAAKuAAACBAAAAVwAAARmAAACKQAAAZ8AAADVAAAACgAAAi0AGQItABkFIgCnBhkAmQOU/18BlwCuAZcAiQGV/5gBlwDUAsgAtgLPAJUCtv+UBFEAdwR2//YCpwCgA7EAOQU7ADkA+QAaB3kAlwJeAF8CXgACA5H/7wLiAGEDUAB+BIz/8wYuAAoGaAA5CD8AOgc0ACIGBgAfBGYAUQW3AEMEDABJBFwACgUp//IFMP/lBcQAzAO7AEsIBQA1BOUA6gT6AIIGAQC1BqwAkgalAI8GQwC+BHYATQVtACQElf+sBHkAqwSqAEEIBQBNAgb/GgRpADEETABwA/z/1AQZABkD8wBBAkQAeAKFAHAB/v/jBNcAdARWAFgEcgB0BqoAdAaqAHQE0gB0BnIAKQAKAAAH/v+rCDUAXAQKAGIEhQBBAff/DwGP/70DkgETA4wBEgONARED4ADNA/kAzgPfACID2wDSA5IBEQH4APwEbP+lBDkAHQRkAEcEZwAdA9IAHQO4AB0EkgBMBMcAHQHjACoDvP/2BD0AHQOiAB0F3gAdBMcAHQShAEoERQAdBKEARQQzAB0ECgARBBAAbQRkAEUETwB6BfAAlQQ9/7YEFQB0BA3/3ALiAB0C4gBrAuL/6QLi//sC4v/wAuIAFgLiAB4C4gAvAuIACwLiADYDhACTAqoBCwQk/5oEqABLBS0AQwUHAEQD/gAlBR8ARAP6ACUECgASBB0ABgQlADQDnQAdBE//sAShAEoET/+wA3j/0wSzAB0D2//VBUgAUQT6AH4E1gAMBVIAbARkAEcHE//EByEAHQVUAG0EsgAdBEIAHwUH/4kF5/+vBCgAEQTQAB8ENwAeBKb/xAQJAFgFCgAdBFIAWgYqAB0GgwAdBQAAUAXNAB8ENwAfBGMAIAZOAB0Ebv/fA/z/+gYh/68EYQAeBOwAHgUZAGkFoABQBEcAdASO/7YGOgBsBFIAWgRSAB0FoQAvBK8AQQQoABEEoQBKBB3//wPPAB4H7gAdBJH/3QRlAB8EHABDBHoARwRzACQDaACpBHT/1wSDAEYEJgBFBGUANQVhAIEFjACEBXIARAW9AIUFwACFA8IAuwRpADkDnQAdBEH/gQS0/9MC4gCQAuIAYQLiAIkC4gCRAuIAogLiAH4C4gCpBFP/1QQYACsGewBJBJ8APwTkAGQCAP8JAf//CQH2AC4B9v96AfYALgH2//EEOQAdAfYAAAIuABkFPwAvBT8ALwRuAD0EqwCoApP/9AUa/68FGv+vBRr/rwUa/68FGv+vBRr/rwUa/68FFwB0BHMAOwRzADsEcwA7BHMAOwImAEkCJgBJAiYASQImAEkFkgA7BWAAdwVgAHcFYAB3BWAAdwVgAHcFEgBnBRIAZwUSAGcFEgBnBLMAqARDADMEQwAzBEMAMwRDADMEQwAzBEMAMwRDADMEGgBGBCYARQQmAEUEJgBFBCYARQH1AC4B9QAuAfUALgH1AC4EUgAfBHcARQR3AEUEdwBFBHcARQR3AEUEUQBbBFEAWwRRAFsEUQBbA7b/pQO2/6UFGv+vBEMAMwUa/68EQwAzBRr/rwRDADMFFwB0BBoARgUXAHQEGgBGBRcAdAQaAEYFFwB0BBoARgUhADsFAABLBHMAOwQmAEUEcwA7BCYARQRzADsEJgBFBHMAOwQmAEUEcwA7BCYARQVTAHkEZQAEBVMAeQRlAAQFUwB5BGUABAVTAHkEZQAEBZIAOwRQAB8CJgBJAfUAEQImAEkB9QAaAiYASQH1AC4CJv+OAez/cAImAEkGeABJA9AALwRSAAoB/v8JBOcAOwP5ACAENwA7AewALwQ3ADsB7P+jBDcAOwKCAC8ENwA7AsgALwWSADsEUgAfBZIAOwRSAB8FkgA7BFIAHwRSAB8FYAB3BHcARQVgAHcEdwBFBWAAdwR3AEUE0QA6AqoAHwTRADoCqv+fBNEAOgKqAB8EpQAnBAoALgSlACcECgAuBKUAJwQKAC4EpQAnBAoALgSlACcECgAuBKsAqAKTAEMEqwCoApMAQwSrAKgCuwBDBRIAZwRRAFsFEgBnBFEAWwUSAGcEUQBbBRIAZwRRAFsFEgBnBFEAWwUSAGcEUQBbBuwAwwXfAIAEswCoA7b/pQSzAKgEr//rA+P/7QSv/+sD4//tBK//6wPj/+0HS/+EBpcAEwVgACAEbwA5BGf/sARn/7AEEABtBGz/pQRs/6UEbP+lBGz/pQRs/6UEbP+lBGz/pQRkAEcD0gAdA9IAHQPSAB0D0gAdAeMAKgHjACoB4wAqAeMAKgTHAB0EoQBKBKEASgShAEoEoQBKBKEASgRkAEUEZABFBGQARQRkAEUEFQB0BGz/pQRs/6UEbP+lBGQARwRkAEcEZABHBGQARwRnAB0D0gAdA9IAHQPSAB0D0gAdA9IAHQSSAEwEkgBMBJIATASSAEwExwAdAeMADwHjABgB4wAqAeP/egHjACoDvP/2BD0AHQOiAB0DogAdA6IAHQOiAB0ExwAdBMcAHQTHAB0EoQBKBKEASgShAEoEMwAdBDMAHQQzAB0ECgARBAoAEQQKABEECgARBBAAbQQQAG0EEABtBGQARQRkAEUEZABFBGQARQRkAEUEZABFBfAAlQQVAHQEFQB0BA3/3AQN/9wEDf/cBRr/rwTXAGMF9gBxAooAdwV0AGoFF//uBUcAHgKNACAFGv+vBN8AOwRzADsEr//rBZIAOwImAEkE5wA7BtAAOwWSADsFYAB3BO8AOwSrAKgEswCoBOf/1AImAEkEswCoBGwASAQ5ACkEbwAkAo0AhQRFAGcEWwAtBHcARQRv/+UDzABuA+P/xAKNAGcERQBnBHcARQRFAGcGbgBmBHMAOwRbAEMEpQAnAiYASQImAEkEUgAKBQcARATnADsE6gCTBRr/rwTfADsEWwBDBHMAOwWSAEMG0AA7BZIAOwVgAHcFkwBEBO8AOwUXAHQEqwCoBOf/1ARDADMEJgBFBIUALwR3AEUEZf/XBBoARgO2/6UD4//EBCYARQNLAC0ECgAuAewALwH1AC4B5P8UBDsALwO2/6UG7ADDBd8AgAbsAMMF3wCABuwAwwXfAIAEswCoA7b/pQFkAKoChQDIBBIAQwH+/wkBlwCJBtAAOwbXAB4FGv+vBEMAMwRzADsFkgBDBCYARQSFAC8FaACGBXkATwTtAK0D7gCECC0ARQkWAHcEpQAlA/sAIQUXAHQEGgBGBLMAqAPtAIQCJgBJBxX/rAX7/6UCJgBJBRr/rwRDADMFGv+vBEMAMwdL/4QGlwATBHMAOwQmAEUFZwBRBCEAPgQhAD4HFf+sBfv/pQSlACUD+wAhBZIAQwSFAC8FkgBDBIUALwVgAHcEdwBFBVEAaQRyAEIFUQBpBHIAQgVFAHQENgA0BOoAkwO2/6UE6gCTA7b/pQTqAJMDtv+lBVoAzgRCAHsGwABFBhAAMATn/9QD4//EBGoASwWI/8oEhv/IBRr/rwRDADMFGv+vBEMAMwUa/68EQwAzBRr/rwRDADMFGv+vBEMAMwUa/68EQwAzBRr/rwRDADMFGv+vBEMAMwUa/68EQwAzBRr/rwRDADMFGv+vBEMAMwUa/68EQwAzBHMAOwQmAEUEcwA7BCYARQRzADsEJgBFBHMAOwQmAEUEcwA7BCYARQRzADsEJgBFBHMAOwQmAEUEcwA7BCYARQImAEkB9QAuAiYADgHs//EFYAB3BHcARQVgAHcEdwBFBWAAdwR3AEUFYAB3BHcARQVgAHcEdwBFBWAAdwR3AEUFYAB3BHcARQVeAGcEeQBCBV4AZwR5AEIFXgBnBHkAQgVeAGcEeQBCBV4AZwR5AEIFEgBnBFEAWwUSAGcEUQBbBW8AZwTXAFoFbwBnBNcAWgVvAGcE1wBaBW8AZwTXAFoFbwBnBNcAWgSzAKgDtv+lBLMAqAO2/6UEswCoA7b/pQSIAEsEiAAABQcARAQ7AC8FkgA7BIQALwSrAKgDxABgBOf/1APj/8QFWgDOBEIAewVaAM4EQgB7BFsAQwNLAC0HFf+sBfv/pQYKAIoEowAHBFAAHwToACsE6AArBFsAEANL/+YFGwBYBBIAOQWSAEMEhQAvBZIAOwSEAC8G0AA7BcsAMAWI/8oEhv/IBLMAqAPtAF0E5//UA+P/xAQ5ACkEVP/XBhkAmQRmABcEZgA0BGYABQRmAHIEegCUBI4AfAVTAHkEZQAEBZIAOwRSAB8FGv+vBEMAMwRzADsEJgBFAib/3wH1/40FYAB3BHcARQTRADoCqgAfBRIAZwRRAFsEj/+yBN8AOwRlAB8FIQA7BGoASwUhADsEagBLBZIAOwRQAB8E5wA7A/kAIATnADsD+QAgBDcAOwHs//IG0AA7BtcAHgWSADsEUgAfBO8AOwRl/9cE0QA6Aqr/7gSlACcECgAuBKsAqAKTAEME+gCkA8wAbgT6AKQDzABuBuwAwwXfAIAEr//rA+P/7QWm/wwEbP+lBA7/4QUD//0CHwABBKsAHQRR/5sE4AAWBGz/pQQ5AB0D0gAdBA3/3ATHAB0B4wAqBD0AHQXeAB0EoQBKBEUAHQQQAG0EFQB0BD3/tgHjACoEFQB0A9IAHQOdAB0ECgARAeMAKgHjACoDvP/2BD0AHQQJAFgEbP+lBDkAHQOdAB0D0gAdBNAAHwXeAB0ExwAdBKEASgSzAB0ERQAdBGQARwQQAG0EPf+2BCgAEQTHAB0EZABIBBUAdAWhAC8E0AAfBAkAWAVIAFEFGv+vBEMAMwRzADsEJgBFAAAAAQAABOQJCgQAAAICAgMFBQYFAgMDBAUCAgIEBQUFBQUFBQUFBQICBAUFBAgGBQYGBQUGBgIFBgUIBgYGBgUFBQYGCAYFBQIEAgQEAwUFBQUFAwUFAgIEAggFBQUFAwUDBQQHBAQEAwIDBgIFBQYFAgUEBwQEBQcEAwUDAwMFBAICAwQEBgcHBAgFBgUFBwUFBQUGAgUFAgYFCAgCBgMGBQYFAgUEBAQEAgMCBAMDAAAAAAACAgQCBQYGBgUGBQYGBgUFBAUFBQUFAwUEBQUFBQUFBgYHBQUHBwYJCQcGBgcIBQYGBgcGBggJBwgGBggGBQUEBQcEBQUFBwUFBAYFBQcHBQcFBQcFBQUHCAUFCAcFCAcFBQgHBwYKCQUEBgUGBAYFCAcIBwYFBQAAAAAAAAUGBQUEBQQGBQcGCQYJCAcFCAYGBQYHBQYFBgUGBQUFBAUHCAcGBQQJBwkHBQUGBgYDBQkFCQMCAgUCAgEAAgIGBwQCAgICAwMDBQUDBAYBCAMDBAMEBQcHCQgHBQYFBQYGBgQJBgYHCAcHBQYFBQUJAgUFBAUEAwMCBQUFCAgFBwAJCQUFAgIEBAQEBAQEBAIFBQUFBAQFBQIEBQQHBQUFBQUFBQUFBwUFBQMDAwMDAwMDAwMEAwUFBgYEBgQFBQUEBQUFBAUEBgYFBgUICAYFBQYHBQUFBQUGBQcHBgcFBQcFBAcFBgYGBQUHBQUGBQUFBQQJBQUFBQUEBQUFBQYGBgYGBAUEBQUDAwMDAwMDBQUHBQYCAgICAgIFAgIGBgUFAwYGBgYGBgYGBQUFBQICAgIGBgYGBgYGBgYGBQUFBQUFBQUFBQUFBQICAgIFBQUFBQUFBQUFBAQGBQYFBgUGBQYFBgUGBQYGBQUFBQUFBQUFBQYFBgUGBQYFBgUCAgICAgICAgIHBAUCBgQFAgUCBQMFAwYFBgUGBQUGBQYFBgUFAwUDBQMFBQUFBQUFBQUFBQMFAwUDBgUGBQYFBgUGBQYFCAcFBAUFBAUEBQQIBwYFBQUFBQUF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c3dzd3N/c4dzkXObc7Jz0XPvdA50LnQ6dEZ0d3S4dR11QnVOdV51cnZGdmJ2f3aSdqZ273d6eBx4qXi1eXh503pZewR7ZnvpfEd8uH1dfcl+W368fyR/Pn9Yf3J/jH//gCeAYYB9gLKBO4GBgfiCOYJHglWCjoKbgsKC24Lng0qDo4Q3hMKFQ4YXhheHlIfxiCKIgIiviMWJKIl6ibqKLIqFisWLCItIi2KLqIwejHqMx40TjU+Nto4EjiKOWI6cjsSPFo9Uj7OQA5BhkLWRI5FPkYuRvpISkleSi5LIkxuTRpOVlAaUSJSolQiVNZW+liCWN5aBlz6XuZgtmHyYwpkEmUyZzJo4mq+a2psQm4ibuZwHnDqcepzunVCdu54enoyfA597n9KgDaBpoMGhN6G8ofqiS6KUotijE6Nbo5uj5aRApEyknaURpZyl+aZIptCnM6eYp/iooqiuqQGpTamiqeuqZarSqzerq6xHrM6tb63irk+uqK8Tr5yvpLAQsH6w6bFysdWyQLKSsvSzWrOFs9q0BLRdtKG0tbTJtNu077UBtRi1LLWOtba2RLa0tw23FbcdtyW3MLc4t0S3sLewt7i4KLiYuPq5QLmoub+51rntugS6HLovuju6R7peunC6h7qaurG6w7rauu27BLsbuy27RLtbu267hbuXu667wbvTu+q7/LwSvCO8NrxJvFW8Ybx4vIq8oLyzvMm82rzxvQm9Gr0xvUO9Wb1qvX29lL2mvby9z73hvfO+Cr4gvje+Sb62v2S/dr+Iv5q/q7+9v8+/4b/ywATAEMAiwDPARcBXwGnAe8DvwX3Bj8GgwbLBw8HVwefB+cILwhfCKcI7wk/CYcJzwoXCl8KpwrvCxsLRwuPC78L7ww3DH8MrwzfDScNbw2fDc8OIw5TDoMOsw77D0MPcw+jD+sQLxBfEKcQ6xEzEXsRxxITElsSoxLTEwMTSxOPE9cUHxRnFKsU2xULFTsVaxWzFfcWJxZXFocWtxb/Fy8Xdxe7GAMYRxiPGNcZIxlvGbsaBxuLHUcdjx3XHh8eYx6vHvcfPx+HH88gFyBbILchEyFvIcsiVyLjIyMjfyPHJB8kYySvJPslKyVbJbcl/yZDJosm4ycnJ28nuygDKF8opyjvKTcpgynfKicqayq3Kv8rQyuLLSctby2zLfsuQy6HLssvDy9XMT8xg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AdMAAAEHAKEBFwAeAAkAsAcvsBPcMDEA////3AAABA4GIAImAdMAAAEGAJ5VHwAJALAHL7AO3DAxAP///68AAASLBj8CJgAlAAAABgCtBAD//wBjAAAFFQY/ACYAKWQAAAcArf9CAAD//wBxAAAF2wZBACYALGQAAAcArf9QAAL//wB3AAACZQZAACYALWQAAAcArf9WAAH//wBq/+cFIQY/ACYAMxQAAAcArf9JAAD////uAAAFlgY/ACYAPWQAAAcArf7NAAD//wAeAAAE7gY/ACYAuRQAAAcArf9MAAD//wAg//QDGwZ0AiYAwgAAAQcArv8t/+wAHACwAEVYsA4vG7EOGD5ZsBvcsBHQsBsQsCTQMDH///+vAAAEiwWwAgYAJQAA//8AOwAABKAFsAIGACYAAP//ADsAAASxBbACBgApAAD////rAAAEzgWwAgYAPgAA//8AOwAABXcFsAIGACwAAP//AEkAAAIBBbACBgAtAAD//wA7AAAFUAWwAgYALwAA//8AOwAABrcFsAIGADEAAP//ADsAAAV3BbACBgAyAAD//wB3/+cFDQXIAgYAMwAA//8AOwAABPMFsAIGADQAAP//AKgAAAUJBbACBgA4AAD//wCoAAAFMgWwAgYAPQAA////1AAABSsFsAIGADwAAP//AEkAAAMKBwkCJgAtAAABBwBq/7gBQgAMALACL7AZ3LAE0DAx//8AqAAABTIG/QImAD0AAAEHAGoA/QE2AAwAsAEvsB7csAnQMDH//wBI/+cEMgY6AiYAugAAAQcArQFo//sACQCwFS+wKNwwMQD//wAp/+cD5QY5AiYAvgAAAQcArQEh//oACQCwGi+wK9wwMQD//wAk/mED8wY6AiYAwAAAAQcArQE7//sACQCwAy+wFdwwMQD//wCF//QCZQYlAiYAwgAAAQYArSTmAAkAsAAvsBHcMDEA//8AZ//lBAoGdAImAMoAAAEGAK4c7AASALALL7Ar3LAW0LArELAa0DAx//8ALQAABFcEOgIGAI0AAP//AEX/6AQfBFICBgBTAAD////l/mAEJQQ6AgYAdgAA//8AbgAAA+0EOgIGAFoAAP///8QAAAP0BDoCBgBcAAD//wBn//QC3gWzAiYAwgAAAQYAaozsAAwAsAAvsCTcsA/QMDH//wBn/+UD+gWzAiYAygAAAQYAanvs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3LAi0DAx//8Ak//mBUAG+gImAN0AAAEHAHAA7AFKAAkAsAEvsBHcMDEA////pf5FA+wFuAImAF0AAAEGAHAvCAAJALABL7AQ3DAxAP//AJP/5gVABwkCJgDdAAABBwBqARsBQgAMALABL7Am3LAR0DAx////pf5FA+wFxwImAF0AAAEGAGpeAAAMALABL7Al3LAQ0DAx//8Ak//mBUAHQQImAN0AAAEHAKUBXQFCABYAsABFWLABLxuxARw+WbAT3LAX0DAx////pf5FBF4F/wImAF0AAAEHAKUAoAAAABYAsABFWLABLxuxARg+WbAS3LAW0DAx//8AzgAABUQHCQImAOAAAAEHAGoBRAFCABYAsABFWLASLxuxEhw+WbAo3LAc0DAx//8AewAABAAFswImAPgAAAEGAGpp7AAMALAIL7Ao3LAT0DAx//8ARQAABpYHCQAmAOUPAAAnAC0ElQAAAQcAagIIAUIAFgCwAEVYsAovG7EKHD5ZsCHcsC3QMDH//wAwAAAFqQWzACYA/QAAACcAjAQKAAABBwBqAWr/7AAWALAARViwCi8bsQoYPlmwIdywLdAwMf///9T+RQUrBbACJgA8AAAABwGvA5UAAP///8T+RQP0BDoCJgBcAAAABwGvAqoAAP//AEv/6AR1BgACBgBIAAD////K/kUFZQWwAiYA3AAAAAcBrwQkAAD////I/kUESgQ6AiYA8QAAAAcBrwM7AAD///+v/p8EiwWwAiYAJQAAAAcArATcAAD//wAz/p8DzwRRAiYARQAAAAcArAQpAAD///+vAAAEiwe5AiYAJQAAAQcAqgUBAUYACQCwBC+wGNwwMQD//wAz/+gDzwaDAiYARQAAAQcAqgRzABAACQCwGC+wOdwwMQD///+vAAAF7QfDAiYAJQAAAQcBtwDyAS4AFgCwAEVYsAUvG7EFHD5ZsA7csBTQMDH//wAz/+gFXwaOAiYARQAAAQYBt2T5ABYAsABFWLAYLxuxGBg+WbAv3LA10DAx////rwAABIsHvwImACUAAAEHAbYA+AE9ABYAsABFWLAFLxuxBRw+WbAM3LAT0DAx//8AM//oA/0GiQImAEUAAAEGAbZqBwAWALAARViwGC8bsRgYPlmwL9ywNNAwMf///68AAAVsB+oCJgAlAAABBwG1APMBGwAWALAARViwBS8bsQUc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ALAARViwBC8bsQQcPlmwDNywENAwMf//ADP/6APPBesCJgBFAAABBwCrA/L//QAWALAARViwGC8bsRgYPlmwLdywMdAwMf//ADsAAASxBywCJgApAAABBwCrBE4BPgAWALAARViwBi8bsQYcPlmwDdywEdAwMf//AEX/6gPgBesCJgBJAAABBwCrA9f//QAWALAARViwCC8bsQgYPlmwIdywJdAwMf///98AAAKKBywCJgAtAAABBwCrAwQBPgAWALAARViwAi8bsQIcPlmwBdywCdAwMf///40AAAI4BekCJgCMAAABBwCrArL/+wAWALAARViwAi8bsQIYPlmwBdywCdAwMf//AHf/5wUNByICJgAzAAABBwCrBKEBNAAWALAARViwCi8bsQocPlmwJNywKNAwMf//AEX/6AQfBesCJgBTAAABBwCrA+D//QAWALAARViwAC8bsQAYPlmwJNywKNAwMf//ADoAAATCByACJgA2AAABBwCrBEMBMgAWALAARViwBC8bsQQcPlmwGdywHdAwMf//AB8AAALUBesCJgBWAAABBwCrA0n//QAWALAARViwCi8bsQoYPlmwEtywDdAwMf//AGf/5wUgByACJgA5AAABBwCrBHsBMgAWALAARViwCi8bsQocPlmwFNywGNAwMf//AFv/6AQeBesCJgBZAAABBwCrA+T//QAWALAARViwBy8bsQcYPlmwFdywGdAwMf///7IAAAU8Bj8AJgDPZAAABwCt/pEAAP//ADv+qQSgBbACJgAmAAAABwCsBJgACv//AB/+lgP+BgACJgBGAAAABwCsBIb/9///ADv+qQTVBbACJgAoAAAABwCsBJcACv//AEv+nwR1BgACJgBIAAAABwCsBJkAAP//ADv+CQTVBbACJgAoAAAABwGiAR/+qv//AEv9/wR1BgACJgBIAAAABwGiASH+oP//ADv+qQV3BbACJgAsAAAABwCsBPoACv//AB/+qQPjBgACJgBMAAAABwCsBH8ACv//ADsAAAVQBy4CJgAvAAABBwB1AbABMAATALAARViwBS8bsQUcPlmwDtwwMQD//wAgAAAEIgc/AiYATwAAAQcAdQF9AUEACQCwBS+wD9wwMQD//wA7/vgFUAWwAiYALwAAAAcArATSAFn//wAg/uUEGgYAAiYATwAAAAcArARQAEb//wA7/qkDsQWwAiYAMAAAAAcArASdAAr////y/qkB7gYAAiYAUAAAAAcArAM3AAr//wA7/qkGtwWwAiYAMQAAAAcArAWnAAr//wAe/qkGagRSAiYAUQAAAAcArAWrAAr//wA7/qkFdwWwAiYAMgAAAAcArAT+AAr//wAf/qkD4wRSAiYAUgAAAAcArARmAAr//wA7AAAE8wdAAiYANAAAAQcAdQG0AUIAEwCwAEVYsAMvG7EDHD5ZsBbcMDEA////1/5gBDYF9QImAFQAAAEHAHUBkf/3ABMAsABFWLANLxuxDRg+WbAh3DAxAP//ADr+qQTCBbACJgA2AAAABwCsBJUACv///+7+qQLUBFQCJgBWAAAABwCsAzMACv//ACf+nwSjBccCJgA3AAAABwCsBKQAAP//AC7+lwO2BFACJgBXAAAABwCsBG3/+P//AKj+nwUJBbACJgA4AAAABwCsBJYAAP//AEP+nwKUBUACJgBYAAAABwCsA/oAAP//AKQAAAVhBy0CJgA6AAABBwCkAOEBRgATALAARViwAS8bsQEcPlmwCtwwMQD//wBuAAAD7QXiAiYAWgAAAQYApBv7ABMAsABFWLABLxuxARg+WbAK3DAxAP//AKT+qQVhBbACJgA6AAAABwCsBMoACv//AG7+qQPtBDoCJgBaAAAABwCsBDgACv//AMP+qQdBBbACJgA7AAAABwCsBc0ACv//AID+qQX+BDoCJgBbAAAABwCsBSwACv///+v+qQTOBbACJgA+AAAABwCsBJgACv///+3+qQPOBDoCJgBeAAAABwCsBEIACv///wz/5wVTBdYAJgAzRgAABwFa/hoAAP///6UAAAPjBRwCJgG6AAAABwCt/6v+3f///+EAAAQrBR8AJgG+PAAABwCt/sD+4P////0AAATWBRwAJgHBPAAABwCt/tz+3f//AAEAAAHmBR4AJgHCPAAABwCt/uD+3///AB3/6gRYBRwAJgHICgAABwCt/vz+3f///5sAAAShBRwAJgHSPAAABwCt/nr+3f//ABYAAAR0BRsAJgHzCgAABwCt/xT+3P///6UAAAPjBI0CBgG6AAD//wAdAAAD5wSNAgYBuwAA//8AHQAAA+8EjQIGAb4AAP///9wAAAQOBI0CBgHTAAD//wAdAAAEmgSNAgYBwQAA//8AKgAAAaoEjQIGAcIAAP//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DAAGiA7uDu4MRg6gCiIO7g7uD5oKigaSDGYMRgrYCqwNUg8QCl4L4gsQDBYGmA22DbYNtgwgCxAKUAxMDbAMTAsQBqYN5gtwD5oLcAasBrIGvAbCBsgMTAbOBtgNtgb+BxQHKgcwB0YHTAdSB4QHigeQDcANwAe+Du4H4AgCDVIIMA7uDu4LJg7uDu4IRg3ADcAIeAiCCIwIpg1ICLgNsAjSCOgLEAkyCUwJaAloCxAJYgloCWgJaAtwDCAK2AxMCxAN5g1IDqAOoA1ICtIK0grSCtIK0gmKCbAJugnECeIJ9AoGChgK/g+aD5oPmg+aDGYLcAtwC3ALcAtwC3ALcAr+DAAMAAwADAAO7g7uDu4O7g7uD5oPmg+aD5oPmgxGDEYMRgxGDxAL4gviC+IL4gviC+IL4gwWDBYMFgwWDbYMIAwgDCAMIAwgDEwMTAtwC+ILcAviC3AL4gr+Cv4K/gr+D5oMAAwWDAAMFgwADBYMAAwWDAAMFg7uDbYO7g7uDu4O7g7uDEYOoAoiCiIKIgoiDu4Ntg7uDbYO7g22DbYPmgwgD5oMIA+aDCAKUApQClAMZgxmDGYMRgxGDEYMRgxGDEYKrA8QDEwPEApeCl4KXgtwDAAO7g7uD5oPEAtwCoAMAApeDu4O7g6gDu4O7g+aCooMZg8QDVIO7g8QDbYMIAxMDCAMAA3mDu4O7gxGDqAOoAsmC3AKgA3mDAAO7g7uD5oKigr+DGYNUgviDBYMIAsQDEwNsAwWDUgMTAqsCqwKrA8QDEwK0grSCtIO7g22C3AL4gwADBYK2AxMCv4PEAxMDu4NUg2wDu4LcAviC3AL4gwADBYMFgwWDVINsA+aDCAMIAsQCyYMTAsmDEwLJgxMDVINsAtwC+ILcAviC3AL4gtwC+ILcAviC3AL4gtwC+ILcAviC3AL4gtwC+ILcAviC3AL4gwADBYMAAwWDAAMFgwADBYMAAwWDAAMFgwADBYMAAwWDu4O7g+aDCAPmgwgD5oMIA+aDCAPmgwgD5oMIA+aDCAMIAxGDEYPEAxMDxAMTA8QDEwOoA7uDGYNUg2wDeYNSA1SDbANtg3ADeYOoA7uDu4PEA+aAAIAhwAGAAYAAAALAAsAAQATABMAAgAlACoAAwAsADUACQA4AD4AEwBFAEYAGgBJAEoAHABMAEwAHgBRAFQAHwBWAFYAIwBaAFoAJABcAF0AJQCKAIoAJwCcAJwAKACwALQAKQC2ALgALgC6ALoAMQC8AL0AMgC/AMAANADCAMQANgDGAMsAOQDRANEAPwDTAN0AQADfAN8ASwDhAOMATADlAOcATwDpAO0AUgDwAPAAVwD1APcAWAD6APsAWwD9AP8AXQEDAQQAYAEJAQkAYgEMAQwAYwEXARkAZAErAS0AZwEwATAAagEyATIAawFJAUkAbAFsAW0AbQFvAXEAbwG6AboAcgG9Ab0AcwHEAcUAdAHIAcgAdgHKAcsAdwHNAc0AeQIoAigAegIqAisAewJHAkgAfQJKAkoAfwJMAm0AgAJvAnIAogJ3AnwApgKBAokArAKLAosAtQKNAo0AtgKPAo8AtwKRApEAuAKTApwAuQKlAqcAwwKpAqkAxgKrAqsAxwKtAq0AyAKvAq8AyQKyArIAygK0ArQAywK2ArYAzAK4ArgAzQK6AroAzgK8ArwAzwK+AsoA0ALMAswA3QLOAs4A3gLQAtAA3wLbAtsA4ALdAt0A4QLfAt8A4gLhAuEA4wLjAuMA5ALlAuUA5QLnAucA5gLpAukA5wLrAusA6ALtAu0A6QLvAvIA6gL0AvQA7gL2AvYA7wNTA1gA8ANbA2oA9gNtA20BBgNxA3EBBwNzA3MBCAN3A3cBCQN6A3sBCgN9A4YBDAOIA4oBFgOMA5EBGQOTA5QBHwOWA5kBIQOfA6ABJQOiA6IBJwOkA6QBKAOmA6kBKQOsA7EBLQOzA7MBMwO3A7gBNAO9A70BNgO/A8gBNwPLA8wBQQPOA9EBQwPYA9kBRwPdA90BSQPfA+UBSgPqA+sBUQPvBBcBUwQZBBkBfAQbBCgBfQQwBDABiwQzBDMBjAQ1BDUBjQRBBEYBjgRJBEkBlARLBEsBlQRNBE0BlgRPBFABlwRVBFgBmQRbBFsBnQRdBF4BngRgBGABoARkBGQBoQRmBGYBogRqBGoBowSqBKoBpAABABP/IAACAFb/5gG6/8AAAQG6AA4AAwANABQAQQASAGEAEwABAPX/9QABAMMADQACALf/wgDDABAAAQDD/+IAAQDG//IAAQDDAA4AAgDJ/+0A9f/AAAkAvv/mAMH/6wDC/+kAxP/wAMX/5wDJ/+MAy//OAMz/1ADN/9sABQDB/+wAwwAPAMX/6gDJ/8QAy//nAAUASv/pAMH/7gDD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Aor/6wKM/+sCjv/rApD/6wKS/+sClP/rApb/6wKY/+sCmv/rApz/6wKe/+sCoP/rAqL/6wKk/+sCsv74Asb/6wLI/+sCyv/rAtsAFALdABQC3wAUAuL/6gLk/+oC5v/qAuj/6gLq/+oC7P/qAvD/6ANT/1YDW/9WA2v/6wNv/+oDcf/rA3P/6AN2/+oDd//rA3j/6gN//vgDg/9WA44AFAOQ/94Dkf/rA5P/6wOV/+sDlv/oA5j/6wOf/+gDp//oA6//VgOw/94Ds//rA7j/6AO5/+sDvv/rA8D/6APF/1YDxv/eA8f/VgPI/94DzP/rA87/6wPP/+sD2f/rA9v/6wPd/+sD4f/oA+P/6APl/+gD7P/rA+//VgPw/94D8f9WA/L/3gPz/1YD9P/eA/X/VgP2/94D9/9WA/j/3gP5/1YD+v/eA/v/VgP8/94D/f9WA/7/3gP//1YEAP/eBAH/VgQC/94EA/9WBAT/3gQF/1YEBv/eBAj/6wQK/+sEDP/rBA7/6wQQ/+sEEv/rBBT/6wQW/+sEHP/rBB7/6wQg/+sEIv/rBCT/6wQm/+sEKP/rBCr/6wQs/+sELv/rBDD/6wQy/+sENP/qBDb/6gQ4/+oEOv/qBDz/6gQ+/+oEQP/qBEL/6ARE/+gERv/oBE0AFAAfADj/1QA6/+QAO//sAD3/3QDR/9UA1f/VARj/5AEy/9UBOv/VAmb/3QLb/9UC3f/VAt//1QLt/+wC7//dAvH/3QNY/90DZ//dA2r/3QOO/9UDoP/sA6L/7AOk/+wDpv/dA7f/5AO//90EQf/dBEP/3QRF/90ETf/VBGr/3QAaADj/sAA6/+0APf/QANH/sADV/7ABGP/tATL/sAE6/7ACZv/QAtv/sALd/7AC3/+wAu//0ALx/9ADWP/QA2f/0ANq/9ADjv+wA6b/0AO3/+0Dv//QBEH/0ARD/9AERf/QBE3/sARq/9AAEAAu/+4AOf/uAmL/7gJj/+4CZP/uAmX/7gKy/+4C4f/uAuP/7gLl/+4C5//uAun/7gLr/+4Df//uBDP/7gQ1/+4ARwAGABAACwAQAEf/6ABI/+gASf/oAEv/6ABV/+gAk//oAJj/6AC6/+gAx//oAMj/6AD2/+gBAv/oAR3/6AEh/+gBOf/oAUv/6AFM/+gBVv/oAWwAEAFtABABbwAQAXAAEAFxABACbv/o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/90AWv/hAF3/4QCT/9wAmP/cAJr/3QC6/9wAvP/hAMD/8wDH/9wAyP/cAMr/3QDr//MA7//zAPD/8wDy//MA8//zAPT/8wD2/9wA9//zAPn/8wD6//MA/f/zAP//8wEC/9wBBP/zARf/1gEZ/+EBHf/cASH/3AE1//MBOf/cAUT/8wFJ//MBS//cAUz/3AFW/9wCbv/cAm//3AJw/9wCcf/cAnL/3AJ3//MCeP/WAnn/1gJ6/9YCe//WAnz/1gJ9/90Cfv/dAn//3QKA/90Cgf/hAoL/4QKK/9wCjP/cAo7/3AKQ/9wCkv/cApT/3AKW/9wCmP/cApr/3AKc/9wCnv/cAqD/3AKi/9wCpP/cAr//8wLB//MCw//zAsT/8wLG/9YCyP/WAsr/1gLi/90C5P/dAub/3QLo/90C6v/dAuz/3QLw/+EDa//cA23/8wNv/90Dcf/WA3P/4QN2/90Dd//WA3j/3QOR/9wDkv/zA5P/1gOU//MDlf/cA5b/4QOY/9wDmf/zA57/8wOf/+EDp//hA67/8wOz/9wDtP/zA7j/4QO5/9wDvv/cA8D/4QPM/9wDzv/cA8//3APV//MD1//zA9n/1gPb/9wD3f/WA+H/4QPj/+ED5f/hA+n/8wPs/9wECP/cBAr/3AQM/9wEDv/cBBD/3AQS/9wEFP/cBBb/3AQc/9YEHv/WBCD/1gQi/9YEJP/WBCb/1gQo/9YEKv/cBCz/3AQu/9wEMP/WBDL/3AQ0/90ENv/dBDj/3QQ6/90EPP/dBD7/3QRA/90EQv/hBET/4QRG/+EESv/zBEz/8wRW//MEY//zBGX/8wRn//MAcQAG/9oAC//aAEf/8ABI//AASf/wAEv/8ABV//AAWf/vAFr/3ABd/9wAk//wAJj/8ACa/+8Auv/wALz/3ADH//AAyP/wAMr/7wD2//ABAv/wARn/3AEd//ABIf/wATn/8AFL//ABTP/wAVb/8AFs/9oBbf/aAW//2gFw/9oBcf/aAm7/8AJv//ACcP/wAnH/8AJy//ACff/vAn7/7wJ//+8CgP/vAoH/3AKC/9wCiv/wAoz/8AKO//ACkP/wApL/8AKU//AClv/wApj/8AKa//ACnP/wAp7/8AKg//ACov/wAqT/8ALi/+8C5P/vAub/7wLo/+8C6v/vAuz/7wLw/9wDa//wA2//7wNz/9wDdv/v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//UA1f/xANn/9ADc//UA3f/zARj/9AEy//EBOv/xAVH/9QJm//AC2//xAt3/8QLf//EC7//wAvH/8ANY//ADZ//wA2j/9ANq//ADgv/zA47/8QOP//QDpv/wA7f/9AO///ADwv/0A9D/9APg//MD4v/zA+T/8wPq//QD7f/1BEH/8ARD//AERf/wBE3/8QRP//QEV//0BGj/9QRq//AAWQAlAA8AOP/mADr/5gA8AA4APf/mALEADwCzAA8A0f/mANMADgDV/+YA2QAOANwADgDdAAsA4P/lAPEADwD4/+gBAwAPAQwADwEY/+YBMv/mATr/5gFRAA4CTAAPAk0ADwJOAA8CTwAPAlAADwJRAA8CUgAPAmb/5gKDAA8ChQAPAocADwLb/+YC3f/mAt//5gLv/+YC8f/mA1MADwNY/+YDWwAPA2f/5gNoAA4Dav/mA4IACwODAA8Djv/mA48ADgOm/+YDrwAPA7f/5gO//+YDwgAOA8UADwPHAA8D0AAOA+AACwPiAAsD5AALA+b/5QPn/+gD6gAOA+0ADgPuAA8D7wAPA/EADwPzAA8D9QAPA/cADwP5AA8D+wAPA/0ADwP/AA8EAQAPBAMADwQFAA8EQf/mBEP/5gRF/+YETf/mBE8ADgRR/+UEUv/oBFP/5QRU/+gEVwAOBGgADgRpAA8Eav/mAC4AOP/jADz/5QA9/+QA0f/jANP/5QDV/+MA2f/lANz/5QDd/+kA8f/qAQP/6gEy/+MBOv/jAVH/5QJm/+QC2//jAt3/4wLf/+MC7//kAvH/5ANY/+QDZ//kA2j/5QNq/+QDgv/pA47/4wOP/+UDpv/kA7//5APC/+UD0P/lA+D/6QPi/+kD5P/pA+r/5QPt/+UD7v/qBEH/5ARD/+QERf/kBE3/4wRP/+UEV//lBGj/5QRp/+oEav/kACEAOP/iADz/5ADR/+IA0//kANX/4gDZ/+QA3P/kAN3/6QDx/+sBA//rATL/4gE6/+IBUf/kAtv/4gLd/+IC3//iA2j/5AOC/+kDjv/iA4//5APC/+QD0P/kA+D/6QPi/+kD5P/pA+r/5APt/+QD7v/rBE3/4gRP/+QEV//kBGj/5ARp/+sAFwA4/+sAPf/zANH/6wDV/+sBMv/rATr/6wJm//MC2//rAt3/6wLf/+sC7//zAvH/8wNY//MDZ//zA2r/8wOO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ABgEJwQnAAMEKAQoABgEMAQwABgEMwQzAAwENQQ1AAwEQQRBAA8EQgRCABkEQwRDAA8ERAREABkERQRFAA8ERgRGABkESQRJAAkESwRLAAIETQRNAAYETwRPAA4EUARQABsEVQRVAAcEVgRWAAgEVwRXAA4EWARYABsEWwRbABcEXQRdAB8EXgReAAcEYARgAAkEZARkAAIEZgRmAAIEagRqAA8EqgSqAAMAAgFtAAYABgAHAAsACwAHABAAEAATABEAEQAXABIAEgATACUAJQARACcAJwAFACsAKwAFAC4ALgAcADMAMwAFADUANQAFADcANwAZADgAOAAKADkAOQAGADoAOgANADsAOwAJADwAPAASAD0APQAOAD4APgAUAEUARQAaAEcASQAVAEsASwAVAFEAUgAYAFMAUwAIAFQAVAAYAFUAVQAVAFcAVwAbAFkAWQALAFoAWgACAFwAXAAWAF0AXQACAF4AXgAMAIMAgwAFAJIAkgAFAJMAkwAVAJcAlwAFAJgAmAAVAJoAmgALALEAsQARALIAsgAFALMAswARALoAugAVALwAvAACAMAAwAAYAMcAyAAVAMoAygALANEA0QAKANIA0gAFANMA0wABANUA1QAKANkA2QASANwA3AABAN0A3QAQAOAA4AAPAOsA6wAYAO0A7QAWAO8A8AAYAPEA8QAEAPIA9AAYAPYA9gAVAPcA9wAYAPgA+AADAPkA+gAYAP0A/QAYAP8A/wAYAQIBAgAVAQMBAwAEAQQBBAAYAQcBBwAFAQwBDAARARYBFgAFARcBFwAIARgBGAANARkBGQACARoBGgAFARwBHAAFAR0BHQAVAR4BHgAFASABIAAFASEBIQAVATIBMgAKATUBNQAYATgBOAAFATkBOQAVAToBOgAKAUQBRAAYAUkBSQAYAUsBTAAVAVEBUQABAVUBVQAFAVYBVgAVAWkBagAXAWwBbQAHAW4BbgATAW8BcQAHAXIBcgATAXYBdwATAigCKQAFAisCLAAFAkYCRgAXAkwCUgARAlMCUwAFAl0CYQAFAmICZQAGAmYCZgAOAmcCbQAaAm4CcgAVAncCdwAYAngCfAAIAn0CgAALAoECggACAoMCgwARAoQChAAaAoUChQARAoYChgAaAocChwARAogCiAAaAokCiQAFAooCigAVAosCiwAFAowCjAAVAo0CjQAFAo4CjgAVAo8CjwAFApACkAAVApICkgAVApQClAAVApYClgAVApgCmAAVApoCmgAVApwCnAAVAp0CnQAFAp4CngAVAp8CnwAFAqACoAAVAqECoQAFAqICogAVAqMCowAFAqQCpAAVArICsgAcAr8CvwAYAsECwQAYAsMCxAAYAsUCxQAFAsYCxgAIAscCxwAFAsgCyAAIAskCyQAFAsoCygAIAtEC0QAZAtIC0gAbAtMC0wAZAtQC1AAbAtUC1QAZAtYC1gAbAtcC1wAZAtgC2AAbAtkC2QAZAtoC2gAbAtsC2wAKAt0C3QAKAt8C3wAKAuEC4QAGAuIC4gALAuMC4wAGAuQC5AALAuUC5QAGAuYC5gALAucC5wAGAugC6AALAukC6QAGAuoC6gALAusC6wAGAuwC7AALAu0C7QAJAu8C7wAOAvAC8AACAvEC8QAOAvIC8gAUAvMC8wAMAvQC9AAUAvUC9QAMAvYC9gAUAvcC9wAMAvoC+gAFA1MDUwARA1cDVwAFA1gDWAAOA1sDWwARA14DXgAUA2QDZAAFA2cDZwAOA2gDaAASA2oDagAOA2sDawAVA20DbQAYA28DbwALA3EDcQAIA3MDcwACA3YDdgALA3cDdwAIA3gDeAALA38DfwAcA4IDggAQA4MDgwARA4oDigAFA40DjQAFA44DjgAKA48DjwASA5ADkAAaA5EDkQAVA5IDkgAYA5MDkwAIA5QDlAAYA5UDlQAVA5YDlgACA5cDlwAWA5gDmAAVA5kDmQAYA5oDmgAbA54DngAYA58DnwACA6ADoAAJA6IDogAJA6QDpAAJA6YDpgAOA6cDpwACA6gDqQAHA6wDrAAHA64DrgAYA68DrwARA7ADsAAaA7MDswAVA7QDtAAYA7cDtwANA7gDuAACA7kDuQAVA7oDugAFA70DvQAFA74DvgAVA78DvwAOA8ADwAACA8IDwgASA8MDwwAWA8UDxQARA8YDxgAaA8cDxwARA8gDyAAaA8wDzAAVA84DzwAVA9AD0AASA9ED0QAWA9UD1QAYA9cD1wAYA9gD2AAFA9kD2QAIA9oD2gAFA9sD2wAVA9wD3AAFA90D3QAIA+AD4AAQA+ED4QACA+ID4gAQA+MD4wACA+QD5AAQA+UD5QACA+YD5gAPA+cD5wADA+kD6QAYA+oD6gASA+sD6wAWA+wD7AAVA+0D7QABA+4D7gAEA+8D7wARA/AD8AAaA/ED8QARA/ID8gAaA/MD8wARA/QD9AAaA/UD9QARA/YD9gAaA/cD9wARA/gD+AAaA/kD+QARA/oD+gAaA/sD+wARA/wD/AAaA/0D/QARA/4D/gAaA/8D/wARBAAEAAAaBAEEAQARBAIEAgAaBAMEAwARBAQEBAAaBAUEBQARBAYEBgAaBAgECAAVBAoECgAVBAwEDAAVBA4EDgAVBBAEEAAVBBIEEgAVBBQEFAAVBBYEFgAVBBsEGwAFBBwEHAAIBB0EHQAFBB4EHgAIBB8EHwAFBCAEIAAIBCEEIQAFBCIEIgAIBCMEIwAFBCQEJAAIBCUEJQAFBCYEJgAIBCcEJwAFBCgEKAAIBCkEKQAFBCoEKgAVBCsEKwAFBCwELAAVBC0ELQAFBC4ELgAVBC8ELwAFBDAEMAAIBDEEMQAFBDIEMgAVBDMEMwAGBDQENAALBDUENQAGBDYENgALBDgEOAALBDoEOgALBDwEPAALBD4EPgALBEAEQAALBEEEQQAOBEIEQgACBEMEQwAOBEQERAACBEUERQAOBEYERgACBEoESgAYBEwETAAYBE0ETQAKBE8ETwASBFAEUAAWBFEEUQAPBFIEUgADBFMEUwAPBFQEVAADBFYEVgAYBFcEVwASBFgEWAAWBGMEYwAYBGUEZQAYBGcEZwAYBGgEaAABBGkEaQAEBGoEagAOBHAEcAAXBKoEqgAFAAEAAAAKAgYG8AAEREZMVAAaY3lybABIZ3JlawB2bGF0bgCkAAQAAAAA//8AEgAAAAoAFAAeACgANABBAEsAVQBfAGkAcwB9AIcAkQCbAKUArwAEAAAAAP//ABIAAQALABUAHwApADUAQgBMAFYAYABqAHQAfgCIAJIAnACmALAABAAAAAD//wASAAIADAAWACAAKgA2AEMATQBXAGEAawB1AH8AiQCTAJ0ApwCxACgABkFaRSAAVENSVCAAfk1PTCAAqE5BViAA1FJPTSABAFRVUiABLAAA//8AEwADAA0AFwAhACsAMgA3AEQATgBYAGIAbAB2AIAAigCUAJ4AqACyAAD//wASAAQADgAYACIALAA4AEUATwBZAGMAbQB3AIEAiwCVAJ8AqQCzAAD//wASAAUADwAZACMALQA5AEYAUABaAGQAbgB4AIIAjACWAKAAqgC0AAD//wATAAYAEAAaACQALgA6AD4ARwBRAFsAZQBvAHkAgwCNAJcAoQCrALUAAP//ABMABwARABsAJQAvADsAPwBIAFIAXABmAHAAegCEAI4AmACiAKwAtgAA//8AEwAIABIAHAAmADAAPABAAEkAUwBdAGcAcQB7AIUAjwCZAKMArQC3AAD//wATAAkAEwAdACcAMQAzAD0ASgBUAF4AaAByAHwAhgCQAJoApACuALgAuWMyc2MEWGMyc2MEWGMyc2MEWGMyc2MEWGMyc2MEWGMyc2MEWGMyc2MEWGMyc2MEWGMyc2MEWGMyc2MEWGNjbXAEXmNjbXAEXmNjbXAEXmNjbXAEXmNjbXAEXmNjbXAEXmNjbXAEXmNjbXAEXmNjbXAEXmNjbXAEXmRsaWcEZmRsaWcEZmRsaWcEZmRsaWcEZmRsaWcEZmRsaWcEZmRsaWcEZmRsaWcEZmRsaWcEZmRsaWcEZmRub20EbGRub20EbGRub20EbGRub20EbGRub20EbGRub20EbGRub20EbGRub20EbGRub20EbGRub20EbGZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmxpZ2EEfGxpZ2EEhGxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxvY2wEkGxvY2wElmxvY2wEnG51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqHBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5AAAAAEAAAAAAAIAAgADAAAAAQAHAAAAAQAYAAAAAwAVABYAFwAAAAIACAAJAAAAAQAJAAAAAQAUAAAAAQAEAAAAAQAGAAAAAQAFAAAAAQAZAAAAAQARAAAAAQATAAAAAQABAAAAAQAKAAAAAQALAAAAAQAMAAAAAQANAAAAAQAOAAAAAQAPAAAAAQAQAAAAAQASABsAOAPGBrQHYA3wDfAOBg4oDl4OhA6yDsYO2g7uDwAPGg9cD3oPmA/KD/wQLhBCEHoQbBB6EKYAAQAAAAEACAACAcQA3wHnAboBuwG8Ab0BvgG/AcABwQHCAcMBxAHFAcYBxwHIAckBygHLAcwBzQHOAc8B0AHRAdIB0wHoAekCRAI7AeoB6wHsAe0B7gHvAfAB8QHyAfMB9AH1AfYB9wH4AfkB+gH7AfwB/QH+AgACAQTdAgICAwIEAgUCBgIHAggCCQIKAgsCLwIPAhACEQIUAhUCFgIXAhgCGQIbAhwCHgIdAvwC/QL+Av8DAAMBAwIDAwMEAwUDBgMHAwgDCQMKAwsDDAMNAw4DDwMQAxEDEgMTAxQDFQMWAxcDGAMZAxoDGwMcAx0DHgMfAyADIQMiAyMDJAMlAyYDJwMoAykDKgMrAywDLQMuAy8DMAMxAzIDMwM0AzUDNgM3AzgDOQM6AzsDPAM9Az4DPwNAA0EDQgNDA0QDRgNFA0cDSANJA0oDSwNMA00DTgNPA1ADUQNSBKsErAStBK4ErwSwBLEEsgSzBLQEtQS2BLcEuAS5BLoEuwS8BL0EvgS/BMAEwQTCBMMExATFBMYB/wTHBMgEyQTKBMsEzATNBM4EzwTQBNEE0gTTBNQE1QTWBNgE2QTbAhoE3AIOBNcCEwINBNoCDAISAAEA3wAIACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgBlAGcAhQCSALAAsQCyALMAtAC1ALYAtwC4ALkA0QDSANMA1ADVANYA1wDYANkA2gDbANwA3QDeAN8A4ADhAOIA4wDkAOUA5gDnAOgBLAEwATIBOAE6ATwBPgE/AUUBRgF/AYUBigGNAkcCSAJKAkwCTQJOAk8CUAJRAlICUwJUAlUCVgJXAlgCWQJaAlsCXAJdAl4CXwJgAmECYgJjAmQCZQJmAoMChQKHAokCiwKNAo8CkQKTApUClwKZApsCnQKfAqECowKlAqcCqQKrAq0CrwKyArQCtgK4AroCvAK+AsACwgLFAscCyQLLAs0CzwLRAtMC1QLZAtsC3QLfAuEC4wLlAucC6QLrAu0C7wLxAvIC9AL2A1MDVANVA1YDVwNYA1kDWwNcA10DXgNfA2ADYQNiA2QDZQNmA2cDaANpA2oDegN7A3wDfQN+A38DgAOBA4IDgwOEA4UDhgOHA4gDiQOKA4sDjAONA44DjwO7A70DvwPUA9oD4ARJBEsETwRXBFkEXgRqAAEAAAABAAgAAgF0ALcBugG7AbwBvQG+Ab8BwAHBAcIBwwHEAcUBxgHHAcgByQHKAcsBzAHNAc4BzwHQAdEB0gHTAv0DMAI7AfoEygTLAfsB/AH9Af4B/wIABM4EzwTRBNQE3QICAgMCBAIFAgYCBwIIAgkCCgILAfQB9QH2AfcB+AH5Ai8CDwIQAhECFAIVAhcCGQL+Av8DAAMBAwIDAwMEAwUDBgMHAwgDCQMKAwsDDAMNAw4DDwMQAxEDEgMTAxQDFQMWAxcDGAMZA08DGgMbAxwDHQMeAx8DIAMhAyIDIwMkAyUDJgMnAygDKQMqAysDLAMtAy4DLwMxAzIDMwM0AzUDNgM3AzgDOQM6AzsDPAM9Az4DPwNAA0EDQgNDA0QDRgNFA0cDSANJA0oDSwNMA00DTgNQA1EDUgTJBMwEzQTQBNIE0wIBBNUEwQTCBMMExATFBMYExwTIBNYE2ATZAhgE2wIaBNwC/AIOBNcCEwINBNoCFgIMAhIAAQC3AEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0AXgCHAIwAkwDpAOoA6wDsAO0A7gDvAPAA8QDyAPMA9AD1APYA9wD4APkA+gD7APwA/QD+AP8BAAEBAQIBAwEEAQUBBgEtATEBMwE5ATsBPQFAAUcCSwJnAmgCaQJqAmsCbAJtAm4CbwJwAnECcgJzAnQCdQJ2AncCeAJ5AnoCewJ8An0CfgJ/AoACgQKCAoQChgKIAooCjAKOApACkgKUApYCmAKaApwCngKgAqICpAKmAqgCqgKsAq4CswK1ArcCuQK7Ar0CvwLBAsMCxgLIAsoCzALOAtAC0gLUAtYC2gLcAt4C4ALiAuQC5gLoAuoC7ALuAvAC8wL1AvcDkAORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwO8A74DwAPOA9UD2wPhBEcESgRMBFAEWARaBFsEXwRrAAYAAAAGABIAKgBCAFoAcgCKAAMAAAABABIAAQCQAAEAAAAaAAEAAQBNAAMAAAABABIAAQB4AAEAAAAaAAEAAQBOAAMAAAABABIAAQBgAAEAAAAaAAEAAQKuAAMAAAABABIAAQBIAAEAAAAaAAEAAQObAAMAAAABABIAAQAwAAEAAAAaAAEAAQOdAAMAAAABABIAAQAYAAEAAAAaAAEAAQQaAAIAAQCnAKsAAAAEAAAAAQAIAAEGHgA2AHIApACuALgAygD8AQ4BGAFKAWQBfgGQAboB7AH2AhgCMgJEAnYCiAKiAswC3gMQAxoDJAM2A2gDcgN8A4YDoAO6A8wD9gQoBDIEVARuBIAEsgTEBN4FCAUaBSQFLgU4BUIFbAWWBcAF6gYUAAYADgAUABoAIAAmACwCTAACAKcCTQACAKgCTwACAKkD8QACAKoEewACAKsD7wACAKwAAQAEBIgAAgCsAAEABAKJAAIAqAACAAYADASKAAIArASMAAIBogAGAA4AFAAaACAAJgAsAlQAAgCnAlUAAgCoBAsAAgCpBAkAAgCqBH0AAgCrBAcAAgCsAAIABgAMBHcAAgCoAqMAAgGiAAEABASOAAIArAAGAA4AFAAaACAAJgAsAlgAAgCnAlkAAgCoAqcAAgCpBBcAAgCqBH8AAgCrBBkAAgCsAAMACAAOABQEkAACAKgEkgACAKwCtAACAaIAAwAIAA4AFAK2AAIAqASUAAIArAK4AAIBogACAAYADAOtAAIAqASWAAIArAAFAAwAEgAYAB4AJAR5AAIApwK+AAIAqAJcAAIAqQSYAAIArALAAAIBogAGAA4AFAAaACAAJgAsAl0AAgCnAl4AAgCoAmAAAgCpBB0AAgCqBIEAAgCrBBsAAgCsAAEABASaAAIAqAAEAAoAEAAWABwCywACAKgEgwACAKsEnAACAKwCzQACAaIAAwAIAA4AFALRAAIAqASeAAIArALXAAIBogACAAYADASgAAIArALbAAIBogAGAA4AFAAaACAAJgAsAmIAAgCnAmMAAgCoAuEAAgCpBDUAAgCqBIUAAgCrBDMAAgCsAAIABgAMBKIAAgCpBKQAAgCsAAMACAAOABQDoAACAKcDogACAKgEpgACAKwABQAMABIAGAAeACQDpgACAKcCZgACAKgERQACAKkEQwACAKoEQQACAKwAAgAGAAwC8gACAKgEqAACAKwABgAOABQAGgAgACYALAJnAAIApwJoAAIAqAJqAAIAqQPyAAIAqgR8AAIAqwPwAAIArAABAAQEiQACAKwAAQAEAooAAgCoAAIABgAMBIsAAgCsBI0AAgGiAAYADgAUABoAIAAmACwCbwACAKcCcAACAKgEDAACAKkECgACAKoEfgACAKsECAACAKwAAQAEBHgAAgCoAAEABASPAAIArAABAAQEGgACAKwAAwAIAA4AFASRAAIAqASTAAIArAK1AAIBogADAAgADgAUArcAAgCoBJUAAgCsArkAAgGiAAIABgAMA64AAgCoBJcAAgCsAAUADAASABgAHgAkBHoAAgCnAr8AAgCoAncAAgCpBJkAAgCsAsEAAgGiAAYADgAUABoAIAAmACwCeAACAKcCeQACAKgCewACAKkEHgACAKoEggACAKsEHAACAKwAAQAEBJsAAgCoAAQACgAQABYAHALMAAIAqASEAAIAqwSdAAIArALOAAIBogADAAgADgAUAtIAAgCoBJ8AAgCsAtgAAgGiAAIABgAMBKEAAgCsAtwAAgGiAAYADgAUABoAIAAmACwCfQACAKcCfgACAKgC4gACAKkENgACAKoEhgACAKsENAACAKwAAgAGAAwEowACAKkEpQACAKwAAwAIAA4AFAOhAAIApwOjAAIAqASnAAIArAAFAAwAEgAYAB4AJAOnAAIApwKBAAIAqARGAAIAqQREAAIAqgRCAAIArAACAAYADALzAAIAqASpAAIArAABAAQC+AACAKgAAQAEAvoAAgCoAAEABAL5AAIAqAABAAQC+wACAKgABQAMABIAGAAeACQCcwACAKcCdAACAKgCqAACAKkEGAACAKoEgAACAKsABQAMABIAGAAeACQEKwACAKcEKQACAKgELwACAKkELQACAKoEMQACAKwABQAMABIAGAAeACQELAACAKcEKgACAKgEMAACAKkELgACAKoEMgACAKwABQAMABIAGAAeACQEOQACAKcENwACAKgEPQACAKkEOwACAKoEPwACAKwABQAMABIAGAAeACQEOgACAKcEOAACAKgEPgACAKkEPAACAKoEQAACAKwAAQAEBIcAAgCoAAIAEQAlACkAAAArAC0ABQAvADQACAA2ADsADgA9AD4AFABFAEkAFgBLAE0AGwBPAFQAHgBWAFsAJABdAF4AKgCBAIEALACDAIMALQCGAIYALgCJAIkALwCMAIwAMACXAJoAMQDPAM8ANQABAAAAAQAIAAEABgACAAEAAgLVAtYAAQAAAAEACAACAA4ABATeBN8E4AThAAEABAKHAogCmQKaAAQAAAABAAgAAQAmAAIACgAcAAIABgAMAaMAAgBKAagAAgBYAAEABAGpAAIAWAABAAIASgBXAAQAAAABAAgAAQBEAAIACgAUAAEABAGkAAIATQABAAQBpgACAE0ABAAAAAEACAABAB4AAgAKABQAAQAEAaUAAgBQAAEABAGnAAIAUAABAAIASgGjAAEAAAABAAgAAQAGAZUAAQABAEsAAQAAAAEACAABAAYBJwABAAEAugABAAAAAQAIAAEABgGsAAEAAQA2AAEAAAABAAgAAgAcAAIB4wHkAAEAAAABAAgAAgAKAAIB5QHmAAEAAgAvAE8AAQAAAAEACAACAB4ADAIoAioCKQIrAiwCHwIgAiECIgGuAiQCJQABAAwAJwAoACsAMwA1AEYARwBIAEsAUwBUAFUAAQAAAAEACAACAAwAAwImAicCJwABAAMASQBLAiIAAQAAAAEACAACAGYACAI9Ai0CLgIwAjECOQI6AjwAAQAAAAEACAACABYACAAbABUAFgAXABgAGQAdABQAAQAIAa0CIwRxBHIEcwR0BHUEdgABAAAAAQAIAAIAFgAIBHYCIwRxBHIEcwR0Aa0EdQABAAgAFAAVABYAFwAYABkAGwAdAAEAAAABAAgAAgAWAAgAFQAWABcAGAAZABsAHQAUAAEACAItAi4CMAIxAjkCOgI8Aj0AAQAAAAEACAABAAYBaQABAAEAEwAGAAAAAQAIAAMAAQASAAEAUgAAAAEAAAAaAAIAAgF8AXwAAAHUAd0AAQABAAAAAQAIAAEAKAHAAAEAAAABAAgAAgAaAAoCMgB6AHMAdAIzAjQCNQI2AjcCOAACAAEAFAAdAAAAAQAAAAEACAACACYAEAHUAdUB1gHXAdgB2QHaAdsB3AHdAkACPgJBAkICPwJDAAEAEAAUABUAFgAXABgAGQAaABsAHAAdAE0ATgKuA5sDnQQa\",\n  \"Roboto-Medium.ttf\": \"AAEAAAARAQAABAAQR1BPU32qcYwAAgioAABZDEdTVUJMnCjgAAJhtAAAGWhPUy8yoQuxtgAAAZgAAABgY21hcEAmSHIAABpsAAASyGN2dCAElytKAAAvvAAAAFZmcGdte/lhqwAALTQAAAG8Z2FzcAAIABMAAgicAAAADGdseWaunmLpAAA53AABy8xoZG14PT88IAAAFYAAAATsaGVhZPh7qwgAAAEcAAAANmhoZWEK7wqbAAABVAAAACRobXR4JPNE9QAAAfgAABOIbG9jYd3eZq0AADAUAAAJxm1heHAHEgL1AAABeAAAACBuYW1lPWNvTAACBagAAALUcG9zdP9tAGQAAgh8AAAAIHByZXAbsfg2AAAu8AAAAMwAAQAAAAIAABFApG1fDzz1ABsIAAAAAADE8BEuAAAAANDbTpT6JP3VCVwIcwAAAAkAAgAAAAAAAAABAAAHbP4MAAAJa/ok/kEJXAABAAAAAAAAAAAAAAAAAAAE4gABAAAE4gCPABYATgAFAAEAAAAAAA4AAAIAAhYABgABAAMElQH0AAUAAAWaBTMAAAEfBZoFMwAAA9EAZgIAAAACAAAAAAAAAAAA4AAK/1AAIX8AAAAhAAAAAEdPT0cAQAAA//0GAP4AAGYHmgIAIAABnwAAAAAEOgWwACAAIAACA4wAZAAAAAAAAAAAAf4AAAH+AAACJQCPApgAZQTiAGAEjABkBeAAYwUdAFYBWgBSAsoAgALSACgDiQAbBHUARAHCABwCoABHAjwAhwMqAAIEjABpBIwAqASMAFEEjABPBIwANASMAIEEjAB1BIwARQSMAGgEjABdAh8AggHnAC4EEQA/BHoAkQQqAIAD5AA8BygAWwVTABIFDACUBTkAZgU6AJQEhgCUBGUAlAVyAGoFrwCUAkIAowRxAC0FCwCUBFQAlAcBAJQFrgCUBYYAZgUdAJQFhgBgBP4AlATUAEoE2wAtBTcAfQUtABIHCgAwBRAAKQTgAAcE0QBQAjEAhANYABQCMQAMA2sANQOcAAMClAAxBFQAWgSBAHwEMABPBIQATwRLAFMC1gAtBIkAUgRxAHkCCwB9AgH/tQQtAH0CCwCMBvYAfARzAHkEjgBPBIEAfASLAE8C0AB8BCEASwKpAAgEcgB3A/UAFgXyACEEBgAfA+UADAQGAFICrwA4AgIArgKvABsFUQB1Ah4AhgR9AGQEtQBeBZ0AXQTgABkB/ACIBPgAWgOFAF0GRABXA5EAjQPiAFcEbQB/BkQAVwPbAIcDCgB/BEoAXwL2ADwC9gA3ApsAcAS7AJID7QBFAkIAjgIQAG0C9gCAA6cAdwPiAF0F0ABZBisAUAZXAGcD5ABCB4X/9gREAE0FhABpBMoAlATnAIgGwQBIBKcAZwSRAEMEiABPBJcAggWwAB8CGgCPBJgAjgRkACICTwAhBZMAkASIAH4HtABkBzoAWwIMAIsFiABRAtD/5AWKAFgEngBPBaQAfQTyAHcCJv+1BDwAWQPmAJQDsAByA9wAhwN8AHUCCwCBArIAeAJNACkD2AB6Ax8ASQJsAIIAAPyOAAD9XgAA/HMAAP0+AAD8DAAA/RwCXQDGBDwAZwJCAI4EdQCbBb8AGQV6AFsFOAAgBJAAbAWxAJsEkABHBe8ASgWqAEQFWwBrBIQAVgTGAJYEDgAgBIgAVARgAGAEGgBhBIgAfgShAHMCqgCpBGoAFgQTAGQE8wAtBIgAgAQ3AFIEkABSBC0APwRgAIAF0ABEBckATwaUAGYEswB2BHv/4QZxADMF/gAiBVkAaAiIAC0IjwCbBlsAMQWqAJIFCACQBgYAJAeiABYE1gBJBagAlAWpAC0FCgA5Bl8ATwX5AJIFiQCOB5sAmAf5AJgGGgAYBvkAmwUHAJAFUABrB1QAoAT3ACAEfQBbBI8AjwNaAIUE9gAnBnYAHgQWAE0EmACGBG4AjwSaACEGAwCPBJcAhgSYAIYD9QAjBdMAVATTAIYEZgBfBo4AhgbsAH4FFwAfBm8AjwRoAI8EPABRBoQAkQRwACcEcf/bBDwAVAbRAB4G5ACGBIn/7gSYAIYHSQCIBk8AcARn/+AHKACYBgEAhgUMABwEYAAKB0IArAY2AJ0G7QCABeYAggkyAKMH+QCPBCAAKAPwADMFegBfBIgATwUaABAEDgAgBXoAXwSIAE8HRQCIBkQAdAdJAIgGTwBwBRoAZgRKAFwE/wBtAAD8ZgAA/HMAAP17AAD9pQAA+iQAAPpNBGf/4AUTAJQEhgB8BGoAjwOhAH4EtwCbBCAAfgUsAJAEqwCOBpUANAWkAD0H0ACUBaoAfghHAJsG9QB+BioAZwT/AGEHMQAtBXAAJgV0AIAEcwB0BYcAhQYkABYEw//LBSEAkAR4AI4FrwCbBIgAfgWIAFEEpgBbBKYAXQTHADQDUwAtBQcAUgbxAGgG3QBeBlMAPAUoAC8EewBIBD4AdAe+AEIGnQBAB/0AlAaeAHcFBABdBCwAVQWqACEFHQBEBVUAgQMsAGcEFAAACCkAAAQUAAAIKQAAArkAAAIKAAABXAAABH8AAAIwAAABogAAANEAAAAAAAACoQBHAqEARwUpAJ0GMACBA50ABAHAAGMBvAAzAc4AMgGoAEoDFABsAxsAQAMIADIEXQBABJkAXALLAIgD+gCKBaYAigFsAEcHpwBKAnIAbAJpAFQDnAAtAvYANQNcAGkEtQBfBnAAIQa4AJgIkwCUB4gANQaMAHwEjABeBfUAIQQ0ACgEogAhBV4ATwV9ACgF5ABwA+IATAguAJAFCQBtBRQAlgY1AFkG3QBUBtEAWwaiAFgEkQBiBZYApgTZAEAEgwCeBLIAOwhFAF4CLf+vBI4AZQR6AJEEEQA8BCoAgAQMACQCWwChApgAYwHxAEUFGwAtBKgAGAS8AC0HIwAtByMALQURAC0GtwBLAAAAAAgwAFkINQBcBDMAOgSTAE8CEP+wAbMAXAOhAHUDoQB1A6EAdQQLAHUECwB1BAv/TAQLAHoDoQB1AgUAlASeAAkEYAB2BIAATwR6AHYD4AB2A8UAdgSmAFQE3gB2AfwAhQPVACQEWwB2A7kAdgYGAHYE3QB2BMAATwRtAHYEwABMBFwAdgQ0AD4EOwAkBIQAZwR7AAkGBwAoBF4AFQQ8AAUEKgBBAvYASwL2AIAC9gA8AvYANwL2ADUC9gBPAvYATQL2ADYC9gBLAvYARgO5AJACsgCWBDsACgS7AFYFRACbBSgAmwQwAIEFOQCbBC0AgQQ0AD4EZgA4BE0ADgO5AHYEewAJBMAATwR7AAkDmABCBNgAdgQZAEQFnQBQBVQAUATkAF8FkQAkBIAATwdUACQHVwB2BZcAJATXAHYEcQB2BVkAJwY6ABoERgBCBOQAdgRcAHYEywAkBEYAHwVdAHYEjABBBoQAdgcKAHYFWgAKBiAAdgRnAHYEgAA8BpIAdgSIAEMEIgAKBpIAGgSdAHYFGgB2BW4AJAXwAE8EWgAFBMQAFQaVACQEjABBBIwAdgX+AAoE0gBPBEYAQgTAAE8EZgA4A/cARgg2AHYE6wAoBIgAfAQ9AFAEmABPA6QAWwShAEwElAB8BJ8ATwRLAFMEiQBRBXoAawWiAGsFhgCbBeAAawXiAGsEGwCXBIIAbgO5AHYEVwAPBL4ANQL2AEsC9gA1AvYATwL2AE0C9gA2AvYASwL2AEYEawBmBC4AQwaYAE8EtABzBOsAYgIm/7UCJv+1AhsAjwIb//sCGwCPBGAAdgH+AAACoABHBVj/9wVY//cEj//UBNsALQKp/+gFUwASBVMAEgVTABIFUwASBVMAEgVTABIFUwASBTkAZgSGAJQEhgCUBIYAlASGAJQCQv/IAkIAowJC/8sCQv+/Ba4AlAWGAGYFhgBmBYYAZgWGAGYFhgBmBTcAfQU3AH0FNwB9BTcAfQTgAAcEVABaBFQAWgRUAFoEVABaBFQAWgRUAFoEVABaBDAATwRLAFMESwBTBEsAUwRLAFMCGv+0AhoAjwIa/7cCGv+rBHMAeQSOAE8EjgBPBI4ATwSOAE8EjgBPBHIAdwRyAHcEcgB3BHIAdwPlAAwD5QAMBVMAEgRUAFoFUwASBFQAWgVTABIEVABaBTkAZgQwAE8FOQBmBDAATwU5AGYEMABPBTkAZgQwAE8FOgCUBRoATwSGAJQESwBTBIYAlARLAFMEhgCUBEsAUwSGAJQESwBTBIYAlARLAFMFcgBqBIkAUgVyAGoEiQBSBXIAagSJAFIFcgBqBIkAUgWvAJQEcQB5AkL/swIa/58CQv+5Ahr/pQJC/98CGv/LAkIAFwILAAACQgCdBrMAowQMAH0EcQAtAib/tQULAJQELQB9BFQAlAILAIoEVACUAgsAVQRUAJQCoQCMBFQAlALnAIwFrgCUBHMAeQWuAJQEcwB5Ba4AlARzAHkEc/+lBYYAZgSOAE8FhgBmBI4ATwWGAGYEjgBPBP4AlALQAHwE/gCUAtAATwT+AJQC0AA4BNQASgQhAEsE1ABKBCEASwTUAEoEIQBLBNQASgQhAEsE1ABKBCEASwTbAC0CqQAIBNsALQKpAAgE2wAtAtEACAU3AH0EcgB3BTcAfQRyAHcFNwB9BHIAdwU3AH0EcgB3BTcAfQRyAHcFNwB9BHIAdwcKADAF8gAhBOAABwPlAAwE4AAHBNEAUAQGAFIE0QBQBAYAUgTRAFAEBgBSB4X/9gbBAEgFhABpBIgATwR6/6YEev+mBDsAJASeAAkEngAJBJ4ACQSeAAkEngAJBJ4ACQSeAAkEgABPA+AAdgPgAHYD4AB2A+AAdgH8/6YB/ACDAfz/qQH8/50E3QB2BMAATwTAAE8EwABPBMAATwTAAE8EhABnBIQAZwSEAGcEhABnBDwABQSeAAkEngAJBJ4ACQSAAE8EgABPBIAATwSAAE8EegBqA+AAdgPgAHYD4AB2A+AAdgPgAHYEpgBUBKYAVASmAFQEpgBUBN4AdgH8/5EB/P+XAfz/vQH8ABUB/AB8A9UAJARbAHYDuQB2A7kAdgO5AHYDuQB2BN0AdgTdAHYE3QB2BMAATwTAAE8EwABPBFwAdgRcAHYEXAB2BDQAPgQ0AD4ENAA+BDQAPgQ7ACQEOwAkBDsAJASEAGcEhABnBIQAZwSEAGcEhABnBIQAZwYHACgEPAAFBDwABQQqAEEEKgBBBCoAQQVTABIE6v9KBhP/UwKm/1YFmv+nBUT+4QVv/7ICqv+HBVMAEgUMAJQEhgCUBNEAUAWvAJQCQgCjBQsAlAcBAJQFrgCUBYYAZgUdAJQE2wAtBOAABwUQACkCQv+/BOAABwSEAFYEYABgBIgAfgKqAKkEYACABJgAjgSOAE8EuwCSA/UAFgQGAB8Cqv/MBGAAgASOAE8EYACABpQAZgSGAJQEdQCbBNQASgJCAKMCQv+/BHEALQUoAJsFCwCUBQoAOQVTABIFDACUBHUAmwSGAJQFqACUBwEAlAWvAJQFhgBmBbEAmwUdAJQFOQBmBNsALQUQACkEVABaBEsAUwSYAIYEjgBPBIEAfAQwAE8D5QAMBAYAHwRLAFMDWgCFBCEASwILAH0CGv+rAgH/tQRuAI8D5QAMBwoAMAXyACEHCgAwBfIAIQcKADAF8gAhBOAABwPlAAwBWgBSApgAZQRKAI8CJv+xAbwAMwcBAJQG9gB8BVMAEgRUAFoEhgCUBagAlARLAFMEmACGBaoARAXJAE8FGgAQBA7/8QhzAE8JawBmBNYASQQWAE0FOQBmBDAATwTgAAcEDgAgAkIAoweiABYGdgAeAkIAowVTABIEVABaBVMAEgRUAFoHhf/2BsEASASGAJQESwBTBYgAUQQ8AFkEPABZB6IAFgZ2AB4E1gBJBBYATQWoAJQEmACGBagAlASYAIYFhgBmBI4ATwV6AF8EiABPBXoAXwSIAE8FUABrBDwAUQUKADkD5QAMBQoAOQPlAAwFCgA5A+UADAWJAI4EZgBfBvkAmwZvAI8FEAApBAYAHwSEAE8FqQAtBJoAIQVTABIEVABaBVMAEgRUAFoFUwASBFQAWgVTABAEVP+aBVMAEgRUAFoFUwASBFQAWgVTABIEVABaBVMAEgRUAFoFUwASBFQAWgVTABIEVABaBVMAEgRUAFoFUwASBFQAWgSGAJQESwBTBIYAlARLAFMEhgCUBEsAUwSGAJQESwBTBIb/1QRL/44EhgCUBEsAUwSGAJQESwBTBIYAlARLAFMCQgCjAhoAjwJCAJQCCwB4BYYAZgSOAE8FhgBmBI4ATwWGAGYEjgBPBYYAJwSO/6MFhgBmBI4ATwWGAGYEjgBPBYYAZgSOAE8FigBYBJ4ATwWKAFgEngBPBYoAWASeAE8FigBYBJ4ATwWKAFgEngBPBTcAfQRyAHcFNwB9BHIAdwWkAH0E8gB3BaQAfQTyAHcFpAB9BPIAdwWkAH0E8gB3BaQAfQTyAHcE4AAHA+UADATgAAcD5QAMBOAABwPlAAwEogBPBKIATwUoAJsEbgCPBa8AlASXAIYE2wAtA/UAIwUQACkEBgAfBYkAjgRmAF8FiQCOBGYAXwR1AJsDWgCFB6IAFgZ2AB4GJAAWBMP/ywRxAHkFB//QBQf/0AR1//ADWv/iBTz/4wRE/64FqACUBJgAhgWvAJQElwCGBwEAlAYDAI8FqQAtBJoAIQTgAAcEDgAgBRAAKQQGAB8EYABgBGUAAgYwAIEEjABRBIwATwSMADQEjACBBKAAXQS0AH0FcgBqBIkAUgWuAJQEcwB5BVMAEgRUAA0EhgBIBEsAAQJC/vYCGv7iBYYAZgSOABYE/gAyAtD/bgU3AHEEcgAPBN/+rAUMAJQEgQB8BToAlASEAE8FOgCUBIQATwWvAJQEcQB5BQsAlAQtAH0FCwCUBC0AfQRUAJQCCwB4BwEAlAb2AHwFrgCUBHMAeQUdAJQEgQB8BP4AlALQAHIE1ABKBCEASwTbAC0CqQAIBS0AEgP1ABYFLQASA/UAFgcKADAF8gAhBNEAUAQGAFIFzP4cBJ4ACQQc/yoFGv83Ajj/OQTK/5MEeP7oBO7/pASeAAkEYAB2A+AAdgQqAEEE3gB2AfwAhQRbAHYGBgB2BMAATwRtAHYEOwAkBDwABQReABUB/P+dBDwABQPgAHYDuQB2BDQAPgH8AIUB/P+dA9UAJARbAHYERgAfBJ4ACQRgAHYDuQB2A+AAdgTkAHYGBgB2BN4AdgTAAE8E2AB2BG0AdgSAAE8EOwAkBF4AFQRGAEIE3gB2BIAATwQ8AAUF/gAKBOQAdgRGAB8FnQBQBVMAEgRUAFoEhgCUBEsAUwIaAHgAAAABAAAE5AkLBAAAAgICAwYFBwYCAwMEBQIDAwQFBQUFBQUFBQUFAgIFBQUECAYGBgYFBQYGAwUGBQgGBgYGBgUFBgYIBgUFAgQCBAQDBQUFBQUDBQUCAgUCCAUFBQUDBQMFBAcFBAUDAgMGAgUFBgUCBgQHBAQFBwQDBQMDAwUEAwIDBAQHBwcECAUGBQYIBQUFBQYCBQUDBgUJCAIGAwYFBgYCBQQEBAQCAwMEBAMAAAAAAAADBQMFBgYGBQYFBwYGBQUFBQUFBQUDBQUGBQUFBQUHBwcFBQcHBgoKBwYGBwkFBgYGBwcGCQkHCAYGCAYFBQQGBwUFBQUHBQUEBwUFBwgGBwUFBwUFBQgIBQUIBwUIBwYFCAcIBwoJBQQGBQYFBgUIBwgHBgUGAAAAAAAABQYFBQQFBQYFBwYJBgkIBwYIBgYFBgcFBgUGBQYFBQUEBggIBwYFBQkHCQcGBQYGBgQFCQUJAwICBQICAQADAwYHBAICAgIDBAMFBQMEBgIJAwMEAwQFBwgKCAcFBwUFBgYHBAkGBgcICAcFBgUFBQkCBQUFBQUDAwIGBQUICAYIAAkJBQUCAgQEBAUFBQUEAgUFBQUEBAUFAgQFBAcFBQUFBQUFBQUHBQUFAwMDAwMDAwMDAwQDBQUGBgUGBQUFBQQFBQUEBQUGBgYGBQgIBgUFBgcFBgUFBQYFBwgGBwUFBwUFBwUGBgcFBQcFBQcFBQUFBAkGBQUFBAUFBQUFBgYGBwcFBQQFBQMDAwMDAwMFBQcFBgICAgICBQIDBgYFBQMGBgYGBgYGBgUFBQUDAwMDBgYGBgYGBgYGBgUFBQUFBQUFBQUFBQUCAgICBQUFBQUFBQUFBQQEBgUGBQYFBgUGBQYFBgUGBgUFBQUFBQUFBQUGBQYFBgUGBQYFAwIDAgMCAwIDCAUFAgYFBQIFAgUDBQMGBQYFBgUFBgUGBQYFBgMGAwYDBQUFBQUFBQUFBQUDBQMFAwYFBgUGBQYFBgUGBQgHBQQFBQUFBQUFCAgGBQUFBQUFBQUFBQUFBAQEBAICAgIFBQUF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AAADfwAABBsAAAQbAAAA3AAABBwAAAQiAAADhwAABCMAAAQkAAAA3QAABCUAAAQlAAADjgAABCYAAAQvAAAA3wAABDAAAAQwAAADjwAABDEAAAQ0AAAA6QAABDUAAAQ1AAADkAAABDYAAAQ4AAAA7QAABDkAAAQ5AAADkQAABDoAAAQ9AAAA8AAABD4AAAQ+AAADkgAABD8AAAQ/AAAA9AAABEAAAARBAAADkwAABEIAAARCAAAA9QAABEMAAARDAAADlQAABEQAAAREAAAA9gAABEUAAARFAAADlgAABEYAAARPAAAA9wAABFAAAARQAAADsgAABFEAAARRAAADlwAABFIAAARSAAABAQAABFMAAARTAAADmAAABFQAAARUAAABAgAABFUAAARYAAADmQAABFkAAARbAAABAwAABFwAAARcAAADnQAABF0AAARdAAADswAABF4AAAReAAADngAABF8AAARhAAABBgAABGIAAARiAAAEXAAABGMAAARvAAABCQAABHAAAARxAAADtAAABHIAAAR1AAABFgAABHYAAAR3AAADtgAABHgAAAR4AAADuQAABHkAAAR5AAADuAAABHoAAASGAAABGgAABIgAAASJAAABJwAABIoAAASLAAAEYQAABIwAAASMAAAEWwAABI0AAASRAAABKQAABJIAAASTAAAEXQAABJQAAASVAAABLgAABJYAAASXAAAEVgAABJgAAASZAAADugAABJoAAASbAAAESAAABJwAAASdAAABMAAABJ4AAASfAAAEXwAABKAAAAShAAABMgAABKIAAASjAAAESgAABKQAAASpAAABNAAABKoAAASrAAADvAAABKwAAAStAAAETAAABK4AAASvAAADvgAABLAAAASxAAAEaQAABLIAAASzAAAETgAABLQAAAS1AAABOgAABLYAAAS3AAAEUAAABLgAAAS6AAABPAAABLsAAAS7AAAEWgAABLwAAAS9AAABPwAABL4AAAS/AAAEWAAABMAAAATCAAADwAAABMMAAATEAAABQQAABMUAAATGAAAEZwAABMcAAATIAAABQwAABMkAAATKAAAEYwAABMsAAATMAAAEUgAABM0AAATOAAAEZQAABM8AAATXAAADwwAABNgAAATYAAABRQAABNkAAATZAAADzQAABNoAAATaAAADzAAABNsAAATfAAADzgAABOAAAAThAAABRgAABOIAAAT1AAAD0wAABPYAAAT3AAAEVAAABPgAAAT5AAAD5wAABPoAAAT7AAABSAAABPwAAAT9AAAD6QAABP4AAAT/AAAEawAABQAAAAUAAAABSgAABQEAAAUBAAAD6wAABQIAAAUQAAABSwAABREAAAURAAAEbQAABRIAAAUTAAAD7AAAHgAAAB4BAAADrgAAHj4AAB4/AAADrAAAHoAAAB6FAAADnwAAHqAAAB7xAAAD7gAAHvIAAB7zAAADpQAAHvQAAB75AAAEQAAAH00AAB9NAAAEqQAAIAAAACALAAABWwAAIBAAACARAAABZwAAIBMAACAUAAABaQAAIBUAACAVAAAEbwAAIBcAACAeAAABawAAICAAACAiAAABcwAAICUAACAnAAABdgAAIDAAACAwAAABeQAAIDIAACAzAAADpwAAIDkAACA6AAABegAAIDwAACA8AAADqQAAIEQAACBEAAABfAAAIHQAACB0AAABfQAAIH8AACB/AAABfgAAIKMAACCjAAAEbgAAIKQAACCkAAABfwAAIKYAACCqAAABgAAAIKsAACCrAAAERwAAIKwAACCsAAABhQAAILEAACCxAAABhgAAILkAACC6AAABhwAAILwAACC9AAABiQAAIQUAACEFAAABiwAAIRMAACETAAABjAAAIRYAACEWAAABjQAAISIAACEiAAABjgAAISYAACEmAAAAuQAAIS4AACEuAAABjwAAIVsAACFeAAABkAAAIgIAACICAAABlAAAIgYAACIGAAAAsQAAIg8AACIPAAABlQAAIhEAACISAAABlgAAIhoAACIaAAABmAAAIh4AACIeAAABmQAAIisAACIrAAABmgAAIkgAACJIAAABmwAAImAAACJgAAABnAAAImQAACJlAAABnQAAJcoAACXKAAABnwAA7gEAAO4CAAABoAAA9sMAAPbDAAABogAA+wEAAPsEAAABpAAA/v8AAP7/AAABqgAA//wAAP/9AAABq7AALEuwCVBYsQEBjlm4Af+FsIQdsQkDX14tsAEsICBFaUSwAWAtsAIssAEqIS2wAywgRrADJUZSWCNZIIogiklkiiBGIGhhZLAEJUYgaGFkUlgjZYpZLyCwAFNYaSCwAFRYIbBAWRtpILAAVFghsEBlWVk6LbAELCBGsAQlRlJYI4pZIEYgamFksAQlRiBqYWRSWCOKWS/9LbAFLEsgsAMmUFhRWLCARBuwQERZGyEhIEWwwFBYsMBEGyFZWS2wBiwgIEVpRLABYCAgRX1pGESwAWAtsAcssAYqLbAILEsgsAMmU1iwQBuwAFmKiiCwAyZTWCMhsICKihuKI1kgsAMmU1gjIbDAioobiiNZILADJlNYIyG4AQCKihuKI1kgsAMmU1gjIbgBQIqKG4ojWSCwAyZTWLADJUW4AYBQWCMhuAGAIyEbsAMlRSMhIyFZGyFZRC2wCSxLU1hFRBshIVktsAossClFLbALLLAqRS2wDCyxJwGIIIpTWLlAAAQAY7gIAIhUWLkAKQPocFkbsCNTWLAgiLgQAFRYuQApA+hwWVlZLbANLLBAiLggAFpYsSoARBu5ACoD6ERZLbAMK7AAKwCyAQ0CKwGyDgECKwG3DjowJRsQAAgrALcBOC4kGhEACCu3Ak5AMiMVAAgrtwNIOy4hFAAIK7cETkAyIxUACCu3BTAoHxYOAAgrtwZjUT8tGwAIK7cHQDQkGhEACCu3CFtKOikZAAgrtwmDZE46IwAIK7cKd2JMNiEACCu3C5F3XDojAAgrtwx2YEs2HQAIK7cNLCQcFAwACCsAsg8NByuwACBFfWkYRLKwEwFzslATAXSygBMBdLJwEwF1sg8fAXOybx8BdQAqAMwAkQCeAJEA7AByALIAfQBWAF8ATgBgAQQAxAAAABT+YAAUApsAEP85AA3+lwASAyEACwQ6ABQEjQAQBbAAFAYYABUGwAAQAlsAEgcEAAUAAAAAAAAAAABgAGAAYABgAGAAmgDEAUABvwJYAvQDDgM6A2kDnAPBA+MD+QQgBDcEiwS5BQoFfQXBBicGjwa8BzoHpAewB7wH2wgCCCEIhwkzCXMJ3QowCnkKuQrvC04LiwumC9kMIAxEDJ0M2Q0zDX4N3g43DqUOzw8NDz4PjQ/YEAkQQRBlEHwQoRDIEOMRBBGDEeMSNxKUEwgTURPLFAsURRSQFNcU8hVdFaYV9BZYFrgW9RdjF64X9BgkGHIYuxj8GTQZdxmOGc8aExpQGrIbFRt2G9kb+ByTHMQdZR3jHe8eDB68HtIfER9UH6cgGSA5IIogtiDWIQshOSGDIY8hqSHDId0iRiKqIugjYyO0JCAk3iVWJasmHSZ8Jtom9SdBJ4onxygeKHko/SmZKckqLCqSKv8rYyu3LBEsQiylLNwtBC0MLTstXi2WLcIuBS46Ln4uni6+Lscu9S8nL0MvXC+hL6kvzy/8MHUwozDjMRExTTHCMhwyhTL4M2gzmzQPNI005zUwNaM10DYoNpg26TdCN5839Tg5OHg45Dk2OZY6DjpeOtM7NDujPBg8jDzdPRk9cT3NPjk+uD7xPzo/gD/sQCJAY0CgQOlBQkGmQfJCaELnQ0FDqUQTRDlEjkT7RXlFskYDRkpGlEbqRxhHREfOSARIRkiDSMdJG0l9ScdKOEqwSwlLgUvvTGNM0003TXNN0k4xTphPHU+eT+tQOVClURJRhFH1Un5TBlOkVDdUpVUPVVNVmVYEVmtXK1fjWFxY21kwWYNZuFnUWgdaHVozWwRbclvaXDFcoFzMXPVdSl2VXetePV6NXuJfQV+PX+1gQ2DSYVxhomHlYjdihmLJYzhjt2QXZGxkymUlZYxl7mZIZldmZ2a2Zx5npWgXaIBo5mlKabVqH2qDavBrS2uda+9sQGy2bOFs4WzhbOFs4WzhbOFs4WzhbOFs4WzhbOFs6WzxbPttBW0gbUNtZW2FbaRtsG28be5uLG6NbrFuvW7NbuZvtG/Qb+xv/3ATcFpw3HF+cgpyFnLmc0tzyXR+dOR1XnW2diR2wXcid7h4Fnh4eJJ4rHjGeOB5S3lxeal5v3nzeoV6x3tGe4V7lHuje9x773wYfDF8PXygfPV9jn4Yfo9/SH9IgPiBYYGOgguCPIJSgsGDG4Nog9mEL4R1hLyFCoUthWuF74ZEhoyGzIcCh2CHuofViACIQ4hniLmI8olGiY+J6opCiquK1YsOiz+LiYvSjAOMO4yDjKyM/o1xjbOOEo5ujpuPH49/j5WP6JCWkP+RYpGrkfGSM5J0kuqTU5PJk/OUKJSblM6VGJVKlY2V+5ZMlq+XDJeFl/iYiJjYmReZbJnCmj2au5r3m0+bmJvbnBScVZyNnMudIZ0tnXmd755+ntGfE5+Un/mgX6DBoVChXKGtofmiR6KIovejXKO6pDCkwqVHpd6mU6aypwWnZadtp7moHqiBqPKpbanAqiKqbarJqyqrVKurq9esLqx2rIqsnqywrMSs1qztrQGtX62FrgKuZq64rsCuyK7Qrtuu469Jr0mvUa/BsDGwkrDUsTexTrFlsXyxjrGmsbmxxbHRseix/7IWsi6yRbJcsnOyi7KdsrSyy7LisvmzEbMoszqzUbNps4Czl7Ops7+z1bPstAS0ELQctDO0RbRbtHK0iLSetLW0zbTetPW1B7UdtS61RrVdtW+1hbWcta61xbXcte22BLYbtoW3J7c5t0u3Yrd4t4+3pre4t8m327fruAK4E7gquEC4V7huuNu5crmJuZq5sbnHud659LoLuiK6LrpAule6abqAupK6qbrAute67rr5uwS7G7snuzO7Srthu227ebuQu6e7s7u/u9S76bv1vAG8GLwqvDa8QrxZvGq8f7yWvKe8vrzVvO29Bb0XvSm9Nb1BvVO9ZL12vYi9n721vcG9zb3ZveW9974IvhS+IL4svji+T75bvnK+iL6avrC+x77evvG/BL8cvy+/jb/vwAbAHcA0wErAYsB5wJDAp8C+wNDA4cD4wQrBIcE4wWjBmMGowb/B1sHswf3CFcItwjnCRcJcwnPCicKgwrfCzcLkwvzDDsMlwzfDTcNew3bDjcOkw7rD0sPpw//EFsR9xI/EpcS8xM3E3sT0xQrFIcWOxaTFusXRxejF9MYKxhzGM8ZKxlXGa8aCxo7GpMawxsXG0cboxvTHC8ccxzPHRsdYx2THdceHx53Hqce6x8bH3Mfox/7ID8gmyDnITMityMTI2sjxyQjJH8k1yUDJTMlYyWTJcMl8yYjJo8mrybPJu8nDycvJ08nbyePJ68nzyfvKA8oLyhPKK8pDylXKZ8p5yorKpMqsyrTKvMrEyszK5Mr7yw3LH8sxy0nLYMvOy9bL7sv2y/7MFcwszDTMPMxEzEzMY8xrzHPMe8yDzIvMk8ybzKPMq8yzzMrM0szazS7NNs0+zVXNbM10zXzNlM2czbPNyc3gzffODs4lzjjOS85iznPOh86mzrLOxM7MzuPO9c8Bzw3PJM87z1LPac9xz3nPkc+pz7XPwc/Nz9nP5c/xz/nQAdAJ0CDQN9A/0FbQbdCF0JzQpNCs0MPQ2dDx0PnRENEo0UDRWNFv0YbRnNG00czR5NH80gTSDNIk0jvSU9Jq0nzSjdKl0rzS1NLs0wTTG9M301PTX9Nr03PTf9OL05fTo9O108fT4NPy1AvUHdQw1ELUVdRn1HfUhtSZ1KvUvtTQ1OPU9dUI1RrVKtU61UbVUtVk1XbViNWZ1bLVxNXd1e/WAtYU1ifWOdZJ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CRCwBtCwBi+wAdCwAS8wMf//AI//8gPIBbAAJgAFAAAABwAFAiUAAP///7H+SwJzBd8CJgCbAAABBwCe/z//3gAJALAAL7AR3DAxAP//ADMEAAFlBgACBgFtAAD//wCUAAAGagc2AiYAMQAAAQcAdQKQATYAEwCwAEVYsAIvG7ECHz5ZsBHcMDEA//8AfAAABnkGAAImAFEAAAEHAHUCoAAAAAkAsAMvsCDcMDEA//8AEv5tBUIFsAImACUAAAAHAKYBegAD//8AWv5xA/sETgImAEUAAAAHAKYArQAH//8AlAAABEwHPQImACkAAAEHAEQA6AE9ABMAsABFWLAGLxuxBh8+WbAN3DAxAP//AJQAAAUNBz0CJgDbAAABBwBEAUoBPQATALAARViwCC8bsQgfPlmwC9wwMQD//wBT/+wECwYAAiYASQAAAQcARAChAAAAEwCwAEVYsAgvG7EIGz5ZsB/cMDEA//8AhgAABBIF8wImAO8AAAEHAEQAxP/zABMAsABFWLAILxuxCBs+WbAL3DAxAP//AEQAAAVcBbACBgC4AAD//wBP/iIFfgQ6AgYAzAAA//8AEAAABPMG/AImARgAAAEHAKsESQEOABYAsABFWLAPLxuxDx8+WbAR3LAV0DAx////8QAABBgF0AImARkAAAEHAKsD5f/iABYAsABFWLARLxuxERs+WbAT3LAX0DAx//8AT/5LCGQETgAmAFMAAAAHAF0EjgAA//8AZv5LCVwFxAAmADMAAAAHAF0FhgAA//8ASf46BH8FwwImANoAAAAHAbABkv+g//8ATf47A8QETQImAO4AAAAHAbABOf+h//8AZv4+BOsFxAImACcAAAAHAbAB1v+k//8AT/4+A/UETgImAEcAAAAHAbABSv+k//8ABwAABNYFsAIGAD0AAP//ACD+XwP1BDoCBgC8AAD//wCjAAABnwWwAgYALQAA//8AFgAAB5sHIwImANkAAAEHAKACHQE9ABMAsABFWLANLxuxDR8+WbAZ3DAxAP//AB4AAAZcBdkCJgDtAAABBwCgAYf/8wATALAARViwDS8bsQ0bPlmwGdwwMQD//wCjAAABnwWwAgYALQAA//8AEgAABUIHHAImACUAAAEHAKAA9gE2ABMAsABFWLAELxuxBB8+WbAO3DAxAP//AFr/7AP7BeYCJgBFAAABBwCg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ALAARViwBy8bsQcfPlmxDwn0sBXQMDEA//8AU//sBMgGfAImAEkAAAEGAbc97AAMALAIL7Ag3LAl0DAx////1QAABEwHtQImACkAAAEHAbYAiQEyABcAsABFWLAGLxuxBh8+WbEPCfSwFNAwMQD///+O/+wECwZ5AiYASQAAAQYBtkL2AAwAsAgvsB7csCXQMDH//wCUAAAEkgflAiYAKQAAAQcBtQCIARoADACwBi+wDNywE9AwMf//AFP/7ARLBqkCJgBJAAABBgG1Qd4ADACwCC+wHtywJdAwMf//AJQAAARMB90CJgApAAABBwG0AIkBDAAMALAGL7AM3LAT0DAx//8AU//sBAsGoQImAEkAAAEGAbRC0AAMALAIL7Ae3LAl0DAx//8AlP6eBEwHPgImACkAAAAnAJ0AiAE9AAcArATLAAr//wBT/pQECwYBAiYASQAAACYAnUEAAAcArASPAAD//wCjAAACEQfCAiYALQAAAQcAqgN4AUMACQCwAi+wBNwwMQD//wCPAAAB/QZ+AiYAjAAAAQcAqgNk//8ACQCwAi+wBNwwMQD//wCU/poBpwWwAiYALQAAAAcArAN4AAb//wB4/p4BkAXVAiYATQAAAAcArANcAAr//wBm/pQFHgXEAiYAMwAAAAcArAUdAAD//wBP/pIEPQROAiYAUwAAAAcArASd//7//wBm/+wFHge7AiYAMwAAAQcAqgUcATwACQCwFC+wH9wwMQD//wBP/+wEPQaFAiYAUwAAAQcAqgSYAAYACQCwBC+wG9wwMQD//wBm/+wFYQexAiYAMwAAAQcBtwDWASEADACwFC+wIdywJtAwMf//AE//7ATdBnwCJgBTAAABBgG3UuwADACwBC+wHdywItAwMf//ACf/7AUeB64CJgAzAAABBwG2ANsBKwAMALAUL7Af3LAm0DAx////o//sBD0GeQImAFMAAAEGAbZX9gAMALAEL7Ab3LAi0DAx//8AZv/sBR4H3gImADMAAAEHAbUA2gETAAwAsBQvsB/csCbQMDH//wBP/+wEYAapAiYAUwAAAQYBtVbeAAwAsAQvsBvcsCLQMDH//wBm/+wFHgfWAiYAMwAAAQcBtADbAQUADACwFC+wH9ywJtAwMf//AE//7AQ9BqECJgBTAAABBgG0V9AADACwBC+wG9ywItAwMf//AGb+lAUe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GzIcqB5aIBg63iFOIuA5MiUuOt463jb2Ot463iX4J5I5oChwKTIpwCoeKvg5KCuCOZAsTCx2Ldw23DBiMKAx0jOQNtwyVDLaMwQzWjOQN0A3+DakOCQztjbcOco5KDqMOow5KDaeM+A2njaeNp41UjV4NYI1jDWqNbw1zjXgNso7ijuKO4o7ijg+N0A3QDdAN0A3QDdAN0A2yjfYN9g32DfYOt463jreOt463juKO4o7ijuKO4o4HjgeOB44HjsAN7Y3tje2N7Y3tje2N7Y37jfuN+437jmWN/g3+Df4N/g3+DgkOCQ3QDe2N0A3tjdAN7Y2yjbKNso2yjuKN9g37jfYN+432DfuN9g37jfYN+463jmWOt463jreOt463jgeOow16jXqNeo16jreOZY63jmWOt45ljmWO4o3+DuKN/g7ijf4Nhg2GDYYOD44Pjg+OB44HjgeOB44HjgeNng7ADgkOwA2KjYqNio3QDfYOt463juKOwA3QDZMN9g2KjreOt46jDreOt47ijZWOD47ADkyOt47ADmWN/g4JDf4N9g5yjreOt44HjqMOow29jdANkw5yjfYOt463juKNlY2yjg+OTI3tjfuN/g23DgkOZA37jkoOCQ2eDZ4Nng7ADgkNp42njaeOt45ljdAN7Y32DfuNqQ4JDbKOwA4JDreOTI5kDreN0A3tjdAN7Y32DfuN+437jkyOZA7ijf4N/g23Db2OCQ29jgkNvY4JDkyOZA3QDe2N0A3tjdAN7Y3QDe2N0A3tjdAN7Y3QDe2N0A3tjdAN7Y3QDe2N0A3tjdAN7Y32DfuN9g37jfYN+432DfuN9g37jfYN+432DfuN9g37jreOt47ijf4O4o3+DuKN/g7ijf4O4o3+DuKN/g7ijf4N/g4HjgeOwA4JDsAOCQ7ADgkOow63jg+OTI5kDnKOSg5MjmQOZY5oDnKOow63jreOwA7igACAIsABAAEAAAABgAGAAEACwAMAAIAEwATAAQAJQAqAAUALAA2AAsAOAA/ABYARQBGAB4ASQBKACAATABMACIATwBPACMAUQBUACQAVgBWACgAWABYACkAWgBdACoAXwBfAC4AigCKAC8AnACcADAAsAC0ADEAtgC4ADYAugC6ADkAvAC8ADoAvwDAADsAwgDCAD0AxADEAD4AxgDNAD8A0QDRAEcA0wDdAEgA3wDfAFMA4QDjAFQA5QDuAFcA8ADwAGEA9QD3AGIA+gD7AGUA/QD/AGcBAgEEAGoBCQEJAG0BDAEMAG4BFwEZAG8BIQEhAHIBKwEtAHMBMAEwAHYBMgEyAHcBSQFJAHgBbAFtAHkBbwFxAHsBugG6AH4BvQG9AH8BxAHFAIAByAHIAIIBygHLAIMBzQHNAIUCKAIoAIYCKgIrAIcCRgJHAIkCSQJJAIsCSwJsAIwCbgJxAK4CdgJ7ALICgAKIALgCigKKAMECjAKMAMICjgKOAMMCkAKQAMQCkgKbAMUCpAKmAM8CqAKoANICqgKqANMCrAKsANQCrgKuANUCsQKxANYCswKzANcCtQK1ANgCtwK3ANkCuQK5ANoCuwK7ANsCvQLJANwCywLLAOkCzQLNAOoCzwLPAOsC2gLaAOwC3ALcAO0C3gLeAO4C4ALgAO8C4gLiAPAC5ALkAPEC5gLmAPIC6ALoAPMC6gLqAPQC7ALsAPUC7gLxAPYC8wLzAPoC9QL1APsDUgNXAPwDWgNpAQIDbANsARIDcANwARMDcgNyARQDdgN2ARUDeQN6ARYDfAOFARgDhwOJASIDiwOQASUDkgOTASsDlQOYAS0DngOfATEDoQOhATMDowOjATQDpQOoATUDqwOwATkDsgOyAT8DtgO3AUADvAO8AUIDvgPHAUMDygPLAU0DzQPQAU8D1wPYAVMD3APcAVUD3gPkAVYD6QPqAV0D7gQWAV8EGAQYAYgEGgQnAYkELwQvAZcEMgQyAZgENAQ0AZkEQARFAZoESARIAaAESgRKAaEETARMAaIETgRPAaMEVARXAaUEWgRaAakEXARdAaoEXwRfAawEYwRjAa0EZQRlAa4EaQRpAa8EqQSpAbAACgA4/8QA0f/EANX/xAEy/8QBOv/EAtr/xALc/8QC3v/EA43/xARM/8QAFQA6ABQAOwAmAD0AFgEYABQCZQAWAuwAJgLuABYC8AAWA1cAFgNmABYDaQAWA58AJgOhACYDowAmA6UAFgO2ABQDvgAWBEAAFgRCABYERAAWBGkAFgABABP/CADOABD+7gAS/u4AJf9AAC7/MAA4ABQARf/eAEf/6wBI/+sASf/rAEv/6wBT/+sAVf/rAFb/5gBZ/+oAWv/oAF3/6ACT/+sAmP/rAJr/6gCx/0AAs/9AALr/6wC8/+gAx//rAMj/6wDK/+oA0QAUANUAFAD2/+sBAv/rAQz/QAEX/+sBGf/oAR3/6wEh/+sBMgAUATn/6wE6ABQBS//rAUz/6wFW/+sBbv7uAXL+7gF2/u4Bd/7uAbr/wAJL/0ACTP9AAk3/QAJO/0ACT/9AAlD/QAJR/0ACZv/eAmf/3gJo/94Caf/eAmr/3gJr/94CbP/eAm3/6wJu/+sCb//rAnD/6wJx/+sCd//rAnj/6wJ5/+sCev/rAnv/6wJ8/+oCff/qAn7/6gJ//+oCgP/oAoH/6AKC/0ACg//eAoT/QAKF/94Chv9AAof/3gKJ/+sCi//rAo3/6wKP/+sCkf/rApP/6wKV/+sCl//rApn/6wKb/+sCnf/rAp//6wKh/+sCo//rArH/MALF/+sCx//rAsn/6wLaABQC3AAUAt4AFALh/+oC4//qAuX/6gLn/+oC6f/qAuv/6gLv/+gDUv9AA1r/QANq/+sDbv/qA3D/6wNy/+gDdf/qA3b/6wN3/+oDfv8wA4L/QAONABQDj//eA5D/6wOS/+sDlP/rA5X/6AOX/+sDnv/oA6b/6AOu/0ADr//eA7L/6wO3/+gDuP/rA73/6wO//+gDxP9AA8X/3gPG/0ADx//eA8v/6wPN/+sDzv/rA9j/6wPa/+sD3P/rA+D/6APi/+gD5P/oA+v/6wPu/0AD7//eA/D/QAPx/94D8v9AA/P/3gP0/0AD9f/eA/b/QAP3/94D+P9AA/n/3gP6/0AD+//eA/z/QAP9/94D/v9AA///3gQA/0AEAf/eBAL/QAQD/94EBP9ABAX/3gQH/+sECf/rBAv/6wQN/+sED//rBBH/6wQT/+sEFf/rBBv/6wQd/+sEH//rBCH/6wQj/+sEJf/rBCf/6wQp/+sEK//rBC3/6wQv/+sEMf/rBDP/6gQ1/+oEN//qBDn/6gQ7/+oEPf/qBD//6gRB/+gEQ//oBEX/6ARMABQAIAA4/98AOv/kADv/7AA9/90A0f/fANX/3wEY/+QBMv/fATr/3wG6AA4CZf/dAtr/3wLc/98C3v/fAuz/7ALu/90C8P/dA1f/3QNm/90Daf/dA43/3wOf/+wDof/sA6P/7AOl/90Dtv/kA77/3QRA/90EQv/dBET/3QRM/98Eaf/dABoAOP/OADr/7QA9/9AA0f/OANX/zgEY/+0BMv/OATr/zgJl/9AC2v/OAtz/zgLe/84C7v/QAvD/0ANX/9ADZv/QA2n/0AON/84Dpf/QA7b/7QO+/9AEQP/QBEL/0ARE/9AETP/OBGn/0AAQAC7/7gA5/+4CYf/uAmL/7gJj/+4CZP/uArH/7gLg/+4C4v/uAuT/7gLm/+4C6P/uAur/7gN+/+4EMv/uBDT/7gBKAAYAEAALABAADQAUAEEAEgBH/+gASP/oAEn/6ABL/+gAVf/oAGEAEwCT/+gAmP/oALr/6ADH/+gAyP/oAPb/6AEC/+gBHf/oASH/6AE5/+gBS//oAUz/6AFW/+gBbAAQAW0AEAFvABABcAAQAXEAEAJt/+gCbv/oAm//6AJw/+gCcf/oAon/6AKL/+gCjf/oAo//6AKR/+gCk//oApX/6AKX/+gCmf/oApv/6AKd/+gCn//oAqH/6AKj/+gDav/oA5D/6AOU/+gDl//oA6cAEAOoABADqwAQA7L/6AO4/+gDvf/oA8v/6APN/+gDzv/oA9r/6APr/+gEB//oBAn/6AQL/+gEDf/oBA//6AQR/+gEE//oBBX/6AQp/+gEK//oBC3/6AQx/+gAAgD1/9YBbf+YAD0AR//sAEj/7ABJ/+wAS//sAFX/7ACT/+wAmP/sALr/7ADH/+wAyP/sAPb/7AEC/+wBHf/sASH/7AE5/+wBS//sAUz/7AFW/+wCbf/sAm7/7AJv/+wCcP/sAnH/7AKJ/+wCi//sAo3/7AKP/+wCkf/sApP/7AKV/+wCl//sApn/7AKb/+wCnf/sAp//7AKh/+wCo//sA2r/7AOQ/+wDlP/sA5f/7AOy/+wDuP/sA73/7APL/+wDzf/sA87/7APa/+wD6//sBAf/7AQJ/+wEC//sBA3/7AQP/+wEEf/sBBP/7AQV/+wEKf/sBCv/7AQt/+wEMf/sABgAU//iARf/4gFtABgCd//iAnj/4gJ5/+ICev/iAnv/4gLF/+ICx//iAsn/4gNw/+IDdv/iA5L/4gPY/+ID3P/iBBv/4gQd/+IEH//iBCH/4gQj/+IEJf/iBCf/4gQv/+IABgAQ/4QAEv+EAW7/hAFy/4QBdv+EAXf/hAAQAC7/7AA5/+wCYf/sAmL/7AJj/+wCZP/sArH/7ALg/+wC4v/sAuT/7ALm/+wC6P/sAur/7AN+/+wEMv/sBDT/7AAeAAb/8gAL//IAWv/zAF3/8wC8//MA9f/1ARn/8wFs//IBbf/yAW//8gFw//IBcf/yAoD/8wKB//MC7//zA3L/8wOV//MDnv/zA6b/8wOn//IDqP/yA6v/8gO3//MDv//zA+D/8wPi//MD5P/zBEH/8wRD//MERf/zAD4AJ//zACv/8wAz//MANf/zAIP/8wCS//MAl//zALL/8wDDAA0A0v/zAQf/8wEW//MBGv/zARz/8wEe//MBIP/zATj/8wFV//MCKP/zAin/8wIr//MCLP/zAlL/8wJc//MCXf/zAl7/8wJf//MCYP/zAoj/8wKK//MCjP/zAo7/8wKc//MCnv/zAqD/8wKi//MCxP/zAsb/8wLI//MC+f/zA1b/8wNj//MDif/zA4z/8wO5//MDvP/zA9f/8wPZ//MD2//zBBr/8wQc//MEHv/zBCD/8wQi//MEJP/zBCb/8wQo//MEKv/zBCz/8wQu//MEMP/zBKn/8wA/ACf/5gAr/+YAM//mADX/5gCD/+YAkv/mAJf/5gCy/+YAt//CAMMAEADS/+YBB//mARb/5gEa/+YBHP/mAR7/5gEg/+YBOP/mAVX/5gIo/+YCKf/mAiv/5gIs/+YCUv/mAlz/5gJd/+YCXv/mAl//5gJg/+YCiP/mAor/5gKM/+YCjv/mApz/5gKe/+YCoP/mAqL/5gLE/+YCxv/mAsj/5gL5/+YDVv/mA2P/5gOJ/+YDjP/mA7n/5gO8/+YD1//mA9n/5gPb/+YEGv/mBBz/5gQe/+YEIP/mBCL/5gQk/+YEJv/mBCj/5gQq/+YELP/mBC7/5gQw/+YEqf/mADcAJf/kADz/0gA9/9MAsf/kALP/5ADD/+IA2f/SAQz/5AJL/+QCTP/kAk3/5AJO/+QCT//kAlD/5AJR/+QCZf/TAoL/5AKE/+QChv/kAu7/0wLw/9MDUv/kA1f/0wNa/+QDZv/TA2f/0gNp/9MDgv/kA47/0gOl/9MDrv/kA77/0wPB/9IDxP/kA8b/5APP/9ID6f/SA+7/5APw/+QD8v/kA/T/5AP2/+QD+P/kA/r/5AP8/+QD/v/kBAD/5AQC/+QEBP/kBED/0wRC/9MERP/TBE7/0gRW/9IEaf/TACcAEP9GABL/RgAl/80Asf/NALP/zQDG//IBDP/NAW7/RgFy/0YBdv9GAXf/RgJL/80CTP/NAk3/zQJO/80CT//NAlD/zQJR/80Cgv/NAoT/zQKG/80DUv/NA1r/zQOC/80Drv/NA8T/zQPG/80D7v/NA/D/zQPy/80D9P/NA/b/zQP4/80D+v/NA/z/zQP+/80EAP/NBAL/zQQE/80AAQDDAA4ArwBH/9wASP/cAEn/3ABL/9wAUf/BAFL/wQBT/9YAVP/BAFX/3ABZ/90AWv/hAF3/4QCT/9wAmP/cAJr/3QC6/9wAvP/hAL7/5gDA/8EAwf/rAML/6QDE//AAxf/nAMf/3ADI/9wAyf/jAMr/3QDL/84AzP/UAM3/2wDr/8EA7//BAPD/wQDy/8EA8//BAPT/wQD2/9wA9//BAPn/wQD6/8EA/f/BAP//wQEC/9wBBP/BARf/1gEZ/+EBHf/cASH/3AE1/8EBOf/cAUT/wQFJ/8EBS//cAUz/3AFW/9wCbf/cAm7/3AJv/9wCcP/cAnH/3AJ2/8ECd//WAnj/1gJ5/9YCev/WAnv/1gJ8/90Cff/dAn7/3QJ//90CgP/hAoH/4QKJ/9wCi//cAo3/3AKP/9wCkf/cApP/3AKV/9wCl//cApn/3AKb/9wCnf/cAp//3AKh/9wCo//cAr7/wQLA/8ECwv/BAsP/wQLF/9YCx//WAsn/1gLh/90C4//dAuX/3QLn/90C6f/dAuv/3QLv/+EDav/cA2z/wQNu/90DcP/WA3L/4QN1/90Ddv/WA3f/3QOQ/9wDkf/BA5L/1gOT/8EDlP/cA5X/4QOX/9wDmP/BA53/wQOe/+EDpv/hA63/wQOy/9wDs//BA7f/4QO4/9wDvf/cA7//4QPL/9wDzf/cA87/3APU/8ED1v/BA9j/1gPa/9wD3P/WA+D/4QPi/+ED5P/hA+j/wQPr/9wEB//cBAn/3AQL/9wEDf/cBA//3AQR/9wEE//cBBX/3AQb/9YEHf/WBB//1gQh/9YEI//WBCX/1gQn/9YEKf/cBCv/3AQt/9wEL//WBDH/3AQz/90ENf/dBDf/3QQ5/90EO//dBD3/3QQ//90EQf/hBEP/4QRF/+EESf/BBEv/wQRV/8EEYv/BBGT/wQRm/8EAdgAG/9oAC//aAEf/8ABI//AASf/wAEv/8ABV//AAWf/vAFr/3ABd/9wAk//wAJj/8ACa/+8Auv/wALz/3ADB/+wAwwAPAMX/6gDH//AAyP/wAMn/zgDK/+8Ay//nAPb/8AEC//ABGf/cAR3/8AEh//ABOf/wAUv/8AFM//ABVv/wAWz/2gFt/9oBb//aAXD/2gFx/9oCbf/wAm7/8AJv//ACcP/wAnH/8AJ8/+8Cff/vAn7/7wJ//+8CgP/cAoH/3AKJ//ACi//wAo3/8AKP//ACkf/wApP/8AKV//ACl//wApn/8AKb//ACnf/wAp//8AKh//ACo//wAuH/7wLj/+8C5f/vAuf/7wLp/+8C6//vAu//3ANq//ADbv/vA3L/3AN1/+8Dd//vA5D/8AOU//ADlf/cA5f/8AOe/9wDpv/cA6f/2gOo/9oDq//aA7L/8AO3/9wDuP/wA73/8AO//9wDy//wA83/8APO//AD2v/wA+D/3APi/9wD5P/cA+v/8AQH//AECf/wBAv/8AQN//AED//wBBH/8AQT//AEFf/wBCn/8AQr//AELf/wBDH/8AQz/+8ENf/vBDf/7wQ5/+8EO//vBD3/7wQ//+8EQf/cBEP/3ARF/9wARAAQAAwAEgAMAEf/5wBI/+cASf/nAEv/5wBV/+cAk//nAJj/5wC6/+cAwwAPAMf/5wDI/+cA9v/nAQL/5wEd/+cBIf/nATn/5wFL/+cBTP/nAVb/5wFuAAwBcgAMAXYADAF3AAwCbf/nAm7/5wJv/+cCcP/nAnH/5wKJ/+cCi//nAo3/5wKP/+cCkf/nApP/5wKV/+cCl//nApn/5wKb/+cCnf/nAp//5wKh/+cCo//nA2r/5wOQ/+cDlP/nA5f/5wOy/+cDuP/nA73/5wPL/+cDzf/nA87/5wPa/+cD6//nBAf/5wQJ/+cEC//nBA3/5wQP/+cEEf/nBBP/5wQV/+cEKf/nBCv/5wQt/+cEMf/nAAYAyf/qAOz/7gD1/9UA/f/tATP/7AFY/+wAAQD1/8AAAQDJACAAfgAGAAwACwAMAEf/6ABI/+gASf/oAEoADABL/+gAU//qAFX/6ABaAAsAXQALAJP/6ACY/+gAuv/oALwACwDD/5AAxQALAMf/6ADI/+gAyQAMAPb/6AEC/+gBF//qARkACwEd/+gBIf/oATn/6AFL/+gBTP/oAVb/6AFsAAwBbQAMAW8ADAFwAAwBcQAMAbr/vwG8/+4BwP/sAcj/7QHK/+wBzP/1Ac0ADgHPAA0B0gANAm3/6AJu/+gCb//oAnD/6AJx/+gCd//qAnj/6gJ5/+oCev/qAnv/6gKAAAsCgQALAon/6AKL/+gCjf/oAo//6AKR/+gCk//oApX/6AKX/+gCmf/oApv/6AKd/+gCn//oAqH/6AKj/+gCxf/qAsf/6gLJ/+oC7wALA2r/6ANw/+oDcgALA3b/6gOQ/+gDkv/qA5T/6AOVAAsDl//oA54ACwOmAAsDpwAMA6gADAOrAAwDsv/oA7cACwO4/+gDvf/oA78ACwPL/+gDzf/oA87/6APY/+oD2v/oA9z/6gPgAAsD4gALA+QACwPr/+gEB//oBAn/6AQL/+gEDf/oBA//6AQR/+gEE//oBBX/6AQb/+oEHf/qBB//6gQh/+oEI//qBCX/6gQn/+oEKf/oBCv/6AQt/+gEL//qBDH/6ARBAAsEQwALBEUACwABAPX/4gANAFz/7QBe/+0A7f/tAPX/wALy/+0C9P/tAvb/7QOW/+0Dwv/tA9D/7QPq/+0ET//tBFf/7QAMAFz/8gBe//IA7f/yAvL/8gL0//IC9v/yA5b/8gPC//ID0P/yA+r/8gRP//IEV//yAB8AWv/0AFz/8gBd//QAXv/zALz/9ADt//IBGf/0AoD/9AKB//QC7//0AvL/8wL0//MC9v/zA3L/9AOV//QDlv/yA57/9AOm//QDt//0A7//9APC//ID0P/yA+D/9APi//QD5P/0A+r/8gRB//QEQ//0BEX/9ARP//IEV//yAF0ABv/KAAv/ygA4/9IAOv/UADz/9AA9/9MAWv/mAFz/7wBd/+YAvP/mANH/0gDV/9IA2f/0AN3/7QDg/+EA5f/UAO3/7wD1/8kA/f/RAQj/5QEY/9QBGf/mAR//4wEy/9IBM//EATr/0gE8/+EBTf/UAU7/9QFP/+cBV/9kAVj/yQFs/8oBbf/KAW//ygFw/8oBcf/KAmX/0wKA/+YCgf/mAtr/0gLc/9IC3v/SAu7/0wLv/+YC8P/TA1f/0wNm/9MDZ//0A2n/0wNy/+YDgf/tA43/0gOO//QDlf/mA5b/7wOe/+YDpf/TA6b/5gOn/8oDqP/KA6v/ygO2/9QDt//mA77/0wO//+YDwf/0A8L/7wPP//QD0P/vA9//7QPg/+YD4f/tA+L/5gPj/+0D5P/mA+X/4QPp//QD6v/vBED/0wRB/+YEQv/TBEP/5gRE/9MERf/mBEz/0gRO//QET//vBFD/4QRS/+EEVv/0BFf/7wRp/9MAbAAG/8AAC//AADj/nQA6/8cAPP/wAD3/qwBR/9IAUv/SAFT/0gDA/9IA0f+dANP/9QDV/50A2f/wANz/9QDd/+oA4P/lAOX/wQDr/9IA7//SAPD/0gDy/9IA8//SAPT/0gD1/80A9//SAPn/0gD6/9IA/f/SAP//0gEE/9IBGP/HATL/nQEz/8wBNf/SATr/nQE8/+UBP//fAUT/0gFJ/9IBTf/OAU//6gFR//UBV/+eAVj/zgFs/8ABbf/AAW//wAFw/8ABcf/AAmX/qwJ2/9ICvv/SAsD/0gLC/9ICw//SAtr/nQLc/50C3v+dAu7/qwLw/6sDV/+rA2b/qwNn//ADaf+rA2z/0gOB/+oDjf+dA47/8AOR/9IDk//SA5j/0gOd/9IDpf+rA6f/wAOo/8ADq//AA63/0gOz/9IDtv/HA77/qwPB//ADz//wA9T/0gPW/9ID3//qA+H/6gPj/+oD5f/lA+j/0gPp//AD7P/1BED/qwRC/6sERP+rBEn/0gRL/9IETP+dBE7/8ARQ/+UEUv/lBFX/0gRW//AEYv/SBGT/0gRm/9IEZ//1BGn/qwBvAAb/sQAL/7EAOP+eADr/xQA8//IAPf+oAFH/zwBS/88AVP/PAFz/7wDA/88A0f+eANX/ngDZ//IA3f/sAOD/4QDl/8IA6//PAO3/7wDv/88A8P/PAPL/zwDz/88A9P/PAPX/xgD3/88A+f/PAPr/zwD9/88A///PAQT/zwEY/8UBMv+eATP/wAE1/88BOv+eATz/4QE//98BRP/PAUn/zwFN/80BT//oAVf/nwFY/8YBbP+xAW3/sQFv/7EBcP+xAXH/sQJl/6gCdv/PAr7/zwLA/88Cwv/PAsP/zwLa/54C3P+eAt7/ngLu/6gC8P+oA1f/qANm/6gDZ//yA2n/qANs/88Dgf/sA43/ngOO//IDkf/PA5P/zwOW/+8DmP/PA53/zwOl/6gDp/+xA6j/sQOr/7EDrf/PA7P/zwO2/8UDvv+oA8H/8gPC/+8Dz//yA9D/7wPU/88D1v/PA9//7APh/+wD4//sA+X/4QPo/88D6f/yA+r/7wRA/6gEQv+oBET/qARJ/88ES//PBEz/ngRO//IET//vBFD/4QRS/+EEVf/PBFb/8gRX/+8EYv/PBGT/zwRm/88Eaf+oAE0AOP++AFH/4QBS/+EAVP/hAFr/7wBd/+8AvP/vAMD/4QDR/74A1f++AOX/yQDr/+EA7//hAPD/4QDy/+EA8//hAPT/4QD1/98A9//hAPn/4QD6/+EA/f/hAP//4QEE/+EBCP/tARn/7wEf/+sBMv++ATP/3wE1/+EBOv++AT//6QFE/+EBSf/hAU7/9QFY/+ACdv/hAoD/7wKB/+8Cvv/hAsD/4QLC/+ECw//hAtr/vgLc/74C3v++Au//7wNs/+EDcv/vA43/vgOR/+EDk//hA5X/7wOY/+EDnf/hA57/7wOm/+8Drf/hA7P/4QO3/+8Dv//vA9T/4QPW/+ED4P/vA+L/7wPk/+8D6P/hBEH/7wRD/+8ERf/vBEn/4QRL/+EETP++BFX/4QRi/+EEZP/hBGb/4QBkADj/5gA6/+cAPP/yAD3/5wBR/9YAUv/WAFT/1gBc//EAwP/WANH/5gDV/+YA2f/yAN3/7gDg/+gA5f/mAOv/1gDt//EA7//WAPD/1gDy/9YA8//WAPT/1gD1/9AA9//WAPn/1gD6/9YA/f/WAP//1gEE/9YBGP/nATL/5gEz/84BNf/WATr/5gE8/+gBRP/WAUn/1gFN/+cBT//tAVf/5gFY/9ACZf/nAnb/1gK+/9YCwP/WAsL/1gLD/9YC2v/mAtz/5gLe/+YC7v/nAvD/5wNX/+cDZv/nA2f/8gNp/+cDbP/WA4H/7gON/+YDjv/yA5H/1gOT/9YDlv/xA5j/1gOd/9YDpf/nA63/1gOz/9YDtv/nA77/5wPB//IDwv/xA8//8gPQ//ED1P/WA9b/1gPf/+4D4f/uA+P/7gPl/+gD6P/WA+n/8gPq//EEQP/nBEL/5wRE/+cESf/WBEv/1gRM/+YETv/yBE//8QRQ/+gEUv/oBFX/1gRW//IEV//xBGL/1gRk/9YEZv/WBGn/5wCTACUAEAAn/+gAK//oADP/6AA1/+gAOP/gADr/4AA9/98Ag//oAJL/6ACX/+gAsQAQALL/6ACzABAA0f/gANL/6ADTABAA1f/gANgAFADcABAA4P/hAOX/4ADsABMA8QAQAPj/4AEDABABB//oAQwAEAEW/+gBGP/gARr/6AEc/+gBHv/oASD/6AEy/+ABOP/oATr/4AE8/+EBPf/gAUD/4QFF/+kBTf/fAU//3gFRABABVf/oAVf/3wFZ//ICKP/oAin/6AIr/+gCLP/oAksAEAJMABACTQAQAk4AEAJPABACUAAQAlEAEAJS/+gCXP/oAl3/6AJe/+gCX//oAmD/6AJl/98CggAQAoQAEAKGABACiP/oAor/6AKM/+gCjv/oApz/6AKe/+gCoP/oAqL/6ALE/+gCxv/oAsj/6ALa/+AC3P/gAt7/4ALu/98C8P/fAvn/6ANSABADVv/oA1f/3wNaABADY//oA2b/3wNp/98DggAQA4n/6AOM/+gDjf/gA6X/3wOuABADtv/gA7n/6AO8/+gDvv/fA8QAEAPGABAD1//oA9n/6APb/+gD5f/hA+b/4APsABAD7QAQA+4AEAPwABAD8gAQA/QAEAP2ABAD+AAQA/oAEAP8ABAD/gAQBAAAEAQCABAEBAAQBBr/6AQc/+gEHv/oBCD/6AQi/+gEJP/oBCb/6AQo/+gEKv/oBCz/6AQu/+gEMP/oBED/3wRC/98ERP/fBEz/4ARQ/+EEUf/gBFL/4QRT/+AEZwAQBGgAEARp/98Eqf/oADIAG//yADj/8QA6//QAPP/0AD3/8ADR//EA0//1ANX/8QDZ//QA3P/1AN3/8wDl//EBGP/0ATL/8QE6//EBTf/yAU//8gFR//UBV//yAmX/8ALa//EC3P/xAt7/8QLu//AC8P/wA1f/8ANm//ADZ//0A2n/8AOB//MDjf/xA47/9AOl//ADtv/0A77/8APB//QDz//0A9//8wPh//MD4//zA+n/9APs//UEQP/wBEL/8ARE//AETP/xBE7/9ARW//QEZ//1BGn/8ABmACUADwA4/+YAOv/mADwADgA9/+YAsQAPALMADwDR/+YA0wAOANX/5gDYABMA2QAOANwADgDdAAsA4P/lAOX/5gDm//QA7AASAPEADwD1/+cA+P/oAP3/5wEDAA8BDAAPARj/5gEy/+YBM//nATr/5gE8/+UBPf/oAU3/5gFP/+YBUQAOAVf/5gFY/+cCSwAPAkwADwJNAA8CTgAPAk8ADwJQAA8CUQAPAmX/5gKCAA8ChAAPAoYADwLa/+YC3P/mAt7/5gLu/+YC8P/mA1IADwNX/+YDWgAPA2b/5gNnAA4Daf/mA4EACwOCAA8Djf/mA44ADgOl/+YDrgAPA7b/5gO+/+YDwQAOA8QADwPGAA8DzwAOA98ACwPhAAsD4wALA+X/5QPm/+gD6QAOA+wADgPtAA8D7gAPA/AADwPyAA8D9AAPA/YADwP4AA8D+gAPA/wADwP+AA8EAAAPBAIADwQEAA8EQP/mBEL/5gRE/+YETP/mBE4ADgRQ/+UEUf/oBFL/5QRT/+gEVgAOBGcADgRoAA8Eaf/mADcABv+/AAv/vwA4/58AOv/JAD3/rQDR/58A1f+fAN3/7ADg/+YA5f/EAPX/zQD9/9UBGP/JATL/nwEz/8wBOv+fATz/5gE//98BTf/RAU//7AFX/6EBWP/PAWz/vwFt/78Bb/+/AXD/vwFx/78CZf+tAtr/nwLc/58C3v+fAu7/rQLw/60DV/+tA2b/rQNp/60Dgf/sA43/nwOl/60Dp/+/A6j/vwOr/78Dtv/JA77/rQPf/+wD4f/sA+P/7APl/+YEQP+tBEL/rQRE/60ETP+fBFD/5gRS/+YEaf+tADAAOP/jADz/5QA9/+QA0f/jANP/5QDV/+MA2P/iANn/5QDc/+UA3f/pAPH/6gED/+oBMv/jATr/4wFR/+UBV//kAmX/5ALa/+MC3P/jAt7/4wLu/+QC8P/kA1f/5ANm/+QDZ//lA2n/5AOB/+kDjf/jA47/5QOl/+QDvv/kA8H/5QPP/+UD3//pA+H/6QPj/+kD6f/lA+z/5QPt/+oEQP/kBEL/5ARE/+QETP/jBE7/5QRW/+UEZ//lBGj/6gRp/+QAIwA4/+IAPP/kANH/4gDT/+QA1f/iANj/4QDZ/+QA3P/kAN3/6QDs/+QA8f/rAQP/6wEy/+IBOv/iAVH/5ALa/+IC3P/iAt7/4gNn/+QDgf/pA43/4gOO/+QDwf/kA8//5APf/+kD4f/pA+P/6QPp/+QD7P/kA+3/6wRM/+IETv/kBFb/5ARn/+QEaP/rABcAOP/rAD3/8wDR/+sA1f/rATL/6wE6/+sCZf/zAtr/6wLc/+sC3v/rAu7/8wLw//MDV//zA2b/8wNp//MDjf/rA6X/8wO+//MEQP/zBEL/8wRE//METP/rBGn/8wA2AFH/7wBS/+8AVP/vAFz/8ADA/+8A6//vAOz/7gDt//AA7//vAPD/7wDy/+8A8//vAPT/7wD1/+4A9//vAPn/7wD6/+8A/f/vAP//7wEE/+8BCP/0AR//8QEz/+8BNf/vAUT/7wFJ/+8BWP/vAnb/7wK+/+8CwP/vAsL/7wLD/+8DbP/vA5H/7wOT/+8Dlv/wA5j/7wOd/+8Drf/vA7P/7wPC//AD0P/wA9T/7wPW/+8D6P/vA+r/8ARJ/+8ES//vBE//8ARV/+8EV//wBGL/7wRk/+8EZv/vACIABv/yAAv/8gBa//UAXf/1ALz/9QD1//QA/f/0AQj/9QEZ//UBM//1AVj/9QFs//IBbf/yAW//8gFw//IBcf/yAoD/9QKB//UC7//1A3L/9QOV//UDnv/1A6b/9QOn//IDqP/yA6v/8gO3//UDv//1A+D/9QPi//UD5P/1BEH/9QRD//UERf/1ADIAUf/uAFL/7gBU/+4AwP/uAOv/7gDsABQA7//uAPD/7gDy/+4A8//uAPT/7gD1/+0A9//uAPj/7QD5/+4A+v/uAPv/0AD9/+4A///uAQT/7gEz/+0BNf/uAT3/7QFE/+4BSf/uAVj/7QJ2/+4Cvv/uAsD/7gLC/+4Cw//uA2z/7gOR/+4Dk//uA5j/7gOd/+4Drf/uA7P/7gPU/+4D1v/uA+b/7QPo/+4ESf/uBEv/7gRR/+0EU//tBFX/7gRi/+4EZP/uBGb/7gAKAAb/9QAL//UBbP/1AW3/9QFv//UBcP/1AXH/9QOn//UDqP/1A6v/9QBZAEf/8ABI//AASf/wAEv/8ABT/8cAVf/wAJP/8ACY//AAuv/wAMf/8ADI//AA9v/wAQL/8AEX/8cBG//rAR3/8AEh//ABOf/wAUv/8AFM//ABVv/wAbz/6wHA/+kByP/rAcr/6wJt//ACbv/wAm//8AJw//ACcf/wAnf/xwJ4/8cCef/HAnr/xwJ7/8cCif/wAov/8AKN//ACj//wApH/8AKT//AClf/wApf/8AKZ//ACm//wAp3/8AKf//ACof/wAqP/8ALF/8cCx//HAsn/xwNq//ADcP/HA3b/xwOQ//ADkv/HA5T/8AOX//ADsv/wA7j/8AO9//ADy//wA83/8APO//AD2P/HA9r/8APc/8cD6//wBAf/8AQJ//AEC//wBA3/8AQP//AEEf/wBBP/8AQV//AEG//HBB3/xwQf/8cEIf/HBCP/xwQl/8cEJ//HBCn/8AQr//AELf/wBC//xwQx//AAoQAGAA0ACwANAEX/8ABH/8AASP/AAEn/wABKAA0AS//AAFP/4gBV/8AAWgALAF0ACwCT/8AAmP/AALr/wAC8AAsAxv/WAMf/wADI/8AAy//VAOz/yADx/9cA9v/AAQL/wAED/9cBF//iARkACwEb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AD4AEgBFAEcAGQBJAEkAHABMAEwAHQBRAFQAHgBWAFYAIgBaAFoAIwBcAF4AJACKAIoAJwCwALMAKAC8ALwALADAAMAALQDGAMYALgDTANQALwDWANYAMQDZANkAMgDbAN0AMwDfAN8ANgDhAOEANwDjAOMAOADlAOUAOQDrAOsAOgDtAO0AOwD2APYAPAD7APsAPQD9AP4APgEDAQQAQAEJAQkAQgEMAQwAQwEXARkARAErAS0ARwEwATAASgEyATIASwFJAUkATAFsAXIATQF2AXcAVAIoAigAVgIqAisAVwJGAkcAWQJJAkkAWwJLAnEAXAJ2AnsAgwKAApAAiQKSApsAmgKkAqYApAKoAqgApwKqAqoAqAKsAqwAqQKuAq4AqgKxArEAqwKzArMArAK1ArUArQK3ArcArgK5ArkArwK7ArsAsAK9AskAsQLLAssAvgLNAs0AvwLPAs8AwALaAtoAwQLcAtwAwgLeAt4AwwLgAuAAxALiAuIAxQLkAuQAxgLmAuYAxwLoAugAyALqAuoAyQLsAuwAygLuAvYAywNSA1cA1ANaA2kA2gNsA2wA6gNwA3AA6wNyA3IA7AN2A3YA7QN5A3oA7gN8A4UA8AOHA4kA+gOLA5AA/QOSA5gBAwOeA58BCgOhA6EBDAOjA6MBDQOlA6gBDgOrA7ABEgOyA7IBGAO2A7cBGQO8A8cBGwPKA8sBJwPNA9ABKQPXA9gBLQPcA9wBLwPeA+QBMAPpA+oBNwPuBBYBOQQYBBgBYgQaBCcBYwQvBC8BcQQyBDIBcgQ0BDQBcwRABEUBdARIBEgBegRKBEoBewRMBEwBfAROBE8BfQRUBFcBfwRaBFoBgwRcBF0BhARfBF8BhgRjBGMBhwRlBGUBiARpBGkBiQSpBKkBigACAU4AEAAQAAEAEgASAAEAJQAlAAIAJgAmAAMAJwAnAAQAKAAoAAUAKQApAAYALAAtAAcALgAuAAgALwAvAAkAMAAwAAoAMQAyAAcAMwAzAAUANAA0AAsAOAA4AAwAOQA5AAgAOgA6AA0AOwA7AA4APAA8AA8APQA9ABAAPgA+ABEARQBFABIARgBGABMARwBHABQASQBJABUATABMABYAUQBSABYAUwBTABcAVABUABMAVgBWABgAWgBaABkAXABcABoAXQBdABkAXgBeABsAigCKABMAsACwABwAsQCxAAIAsgCyAAUAswCzAAIAvAC8ABkAwADAABYAxgDGABMA0wDUAB0A1gDWAAcA2QDZAA8A2wDcAAcA3QDdAB4A3wDfAAcA4QDhAAcA4wDjAB0A5QDlAB0A6wDrAB8A7QDtABoA9gD2ABMA+wD7ACAA/QD9ACAA/gD+ABMBAwEEACABCQEJACABDAEMAAIBFwEXABcBGAEYAA0BGQEZABkBKwErABMBLAEsABwBLQEtAB8BMAEwAAkBMgEyAAkBSQFJAB8BbgFuAAEBcgFyAAEBdgF3AAECKAIoAAQCKgIrAAUCRgJHAAUCSQJJAAwCSwJRAAICUgJSAAQCUwJWAAYCVwJbAAcCXAJgAAUCYQJkAAgCZQJlABACZgJsABICbQJtABQCbgJxABUCdgJ2ABYCdwJ7ABcCgAKBABkCggKCAAICgwKDABIChAKEAAIChQKFABIChgKGAAIChwKHABICiAKIAAQCiQKJABQCigKKAAQCiwKLABQCjAKMAAQCjQKNABQCjgKOAAQCjwKPABQCkAKQAAUCkgKSAAYCkwKTABUClAKUAAYClQKVABUClgKWAAYClwKXABUCmAKYAAYCmQKZABUCmgKaAAYCmwKbABUCpAKkAAcCpQKlABYCpgKmAAcCqAKoAAcCqgKqAAcCrAKsAAcCrgKuAAcCsQKxAAgCswKzAAkCtQK1AAoCtwK3AAoCuQK5AAoCuwK7AAoCvQK9AAcCvgK+ABYCvwK/AAcCwALAABYCwQLBAAcCwgLDABYCxALEAAUCxQLFABcCxgLGAAUCxwLHABcCyALIAAUCyQLJABcCywLLABgCzQLNABgCzwLPABgC2gLaAAwC3ALcAAwC3gLeAAwC4ALgAAgC4gLiAAgC5ALkAAgC5gLmAAgC6ALoAAgC6gLqAAgC7ALsAA4C7gLuABAC7wLvABkC8ALwABAC8QLxABEC8gLyABsC8wLzABEC9AL0ABsC9QL1ABEC9gL2ABsDUgNSAAIDUwNTAAYDVANVAAcDVgNWAAUDVwNXABADWgNaAAIDWwNbAAMDXANcAAYDXQNdABEDXgNfAAcDYANgAAkDYQNiAAcDYwNjAAUDZANkAAsDZQNlAAwDZgNmABADZwNnAA8DaANoAAcDaQNpABADbANsABYDcANwABcDcgNyABkDdgN2ABcDeQN5AAYDegN6ABwDfAN9AAcDfgN+AAgDfwOAAAkDgQOBAB4DggOCAAIDgwODAAMDhAOEABwDhQOFAAYDhwOIAAcDiQOJAAUDiwOLAAsDjAOMAAQDjQONAAwDjgOOAA8DjwOPABIDkAOQABUDkgOSABcDkwOTABMDlAOUABQDlQOVABkDlgOWABoDlwOXABUDmAOYAB8DngOeABkDnwOfAA4DoQOhAA4DowOjAA4DpQOlABADpgOmABkDrAOsAAcDrQOtABYDrgOuAAIDrwOvABIDsAOwAAYDsgOyABUDtgO2AA0DtwO3ABkDvAO8AAQDvQO9ABQDvgO+ABADvwO/ABkDwAPAAAcDwQPBAA8DwgPCABoDwwPDAAcDxAPEAAIDxQPFABIDxgPGAAIDxwPHABIDygPKAAYDywPLABUDzQPOABUDzwPPAA8D0APQABoD1wPXAAUD2APYABcD3APcABcD3gPeABMD3wPfAB4D4APgABkD4QPhAB4D4gPiABkD4wPjAB4D5APkABkD6QPpAA8D6gPqABoD7gPuAAID7wPvABID8APwAAID8QPxABID8gPyAAID8wPzABID9AP0AAID9QP1ABID9gP2AAID9wP3ABID+AP4AAID+QP5ABID+gP6AAID+wP7ABID/AP8AAID/QP9ABID/gP+AAID/wP/ABIEAAQAAAIEAQQBABIEAgQCAAIEAwQDABIEBAQEAAIEBQQFABIEBgQGAAYEBwQHABUECAQIAAYECQQJABUECgQKAAYECwQLABUEDAQMAAYEDQQNABUEDgQOAAYEDwQPABUEEAQQAAYEEQQRABUEEgQSAAYEEwQTABUEFAQUAAYEFQQVABUEFgQWAAcEGAQYAAcEGgQaAAUEGwQbABcEHAQcAAUEHQQdABcEHgQeAAUEHwQfABcEIAQgAAUEIQQhABcEIgQiAAUEIwQjABcEJAQkAAUEJQQlABcEJgQmAAUEJwQnABcELwQvABcEMgQyAAgENAQ0AAgEQARAABAEQQRBABkEQgRCABAEQwRDABkERAREABAERQRFABkESARIAAkESgRKAAcETARMAAwETgROAA8ETwRPABoEVARUABwEVQRVAB8EVgRWAA8EVwRXABoEWgRaABYEXARcAB0EXQRdABwEXwRfAAkEYwRjAAcEZQRlAAcEaQRpABAEqQSpAAUAAgFtAAYABgABAAsACwABABAAEAAWABEAEQAZABIAEgAWACUAJQACACcAJwAIACsAKwAIAC4ALgAaADMAMwAIADUANQAIADcANwAbADgAOAAJADkAOQAKADoAOgALADsAOwAMADwAPAAXAD0APQANAD4APgAYAEUARQADAEcASQAEAEsASwAEAFEAUgAFAFMAUwAGAFQAVAAFAFUAVQAEAFcAVwAHAFkAWQAOAFoAWgAPAFwAXAAcAF0AXQAPAF4AXgAQAIMAgwAIAJIAkgAIAJMAkwAEAJcAlwAIAJgAmAAEAJoAmgAOALEAsQACALIAsgAIALMAswACALoAugAEALwAvAAPAMAAwAAFAMcAyAAEAMoAygAOANEA0QAJANIA0gAIANMA0wARANUA1QAJANkA2QAXANwA3AARAN0A3QAVAOAA4AASAOsA6wAFAO0A7QAcAO8A8AAFAPEA8QATAPIA9AAFAPYA9gAEAPcA9wAFAPgA+AAUAPkA+gAFAP0A/QAFAP8A/wAFAQIBAgAEAQMBAwATAQQBBAAFAQcBBwAIAQwBDAACARYBFgAIARcBFwAGARgBGAALARkBGQAPARoBGgAIARwBHAAIAR0BHQAEAR4BHgAIASABIAAIASEBIQAEATIBMgAJATUBNQAFATgBOAAIATkBOQAEAToBOgAJAUQBRAAFAUkBSQAFAUsBTAAEAVEBUQARAVUBVQAIAVYBVgAEAWkBagAZAWwBbQABAW4BbgAWAW8BcQABAXIBcgAWAXYBdwAWAigCKQAIAisCLAAIAkUCRQAZAksCUQACAlICUgAIAlwCYAAIAmECZAAKAmUCZQANAmYCbAADAm0CcQAEAnYCdgAFAncCewAGAnwCfwAOAoACgQAPAoICggACAoMCgwADAoQChAACAoUChQADAoYChgACAocChwADAogCiAAIAokCiQAEAooCigAIAosCiwAEAowCjAAIAo0CjQAEAo4CjgAIAo8CjwAEApECkQAEApMCkwAEApUClQAEApcClwAEApkCmQAEApsCmwAEApwCnAAIAp0CnQAEAp4CngAIAp8CnwAEAqACoAAIAqECoQAEAqICogAIAqMCowAEArECsQAaAr4CvgAFAsACwAAFAsICwwAFAsQCxAAIAsUCxQAGAsYCxgAIAscCxwAGAsgCyAAIAskCyQAGAtAC0AAbAtEC0QAH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ALgAuWMyc2MEWGMyc2MEXmMyc2MEZGMyc2MEamMyc2MEamMyc2MEamMyc2MEamMyc2MEamMyc2MEamMyc2MEamNjbXAEcGNjbXAEcGNjbXAEcGNjbXAEcGNjbXAEcGNjbXAEcGNjbXAEcGNjbXAEcGNjbXAEcGNjbXAEcGRsaWcEeGRsaWcEfmRsaWcEhGRsaWcEimRsaWcEimRsaWcEimRsaWcEimRsaWcEimRsaWcEimRsaWcEimRub20EkGRub20ElmRub20EnGRub20EomRub20EomRub20EomRub20EomRub20EomRub20EomRub20EomZyYWMEqGZyYWMEqGZyYWMEqGZyYWMEqGZyYWMEqGZyYWMEqGZyYWMEqGZyYWMEqGZyYWMEqGZyYWMEqGxpZ2EEsmxpZ2EEumxudW0EwGxudW0ExmxudW0EzGxudW0E0mxudW0E0mxudW0E0mxudW0E0mxudW0E0mxudW0E0mxudW0E0mxvY2wE2GxvY2wE3mxvY2wE5G51bXIE6m51bXIE8G51bXIE9m51bXIE/G51bXIE/G51bXIE/G51bXIE/G51bXIE/G51bXIE/G51bXIE/G9udW0FAm9udW0FCG9udW0FDm9udW0FFG9udW0FFG9udW0FFG9udW0FFG9udW0FFG9udW0FFG9udW0FFHBudW0FGnBudW0FIHBudW0FJnBudW0FLHBudW0FLHBudW0FLHBudW0FLHBudW0FLHBudW0FLHBudW0FLHNtY3AFMnNtY3AFOHNtY3AFPnNtY3AFRHNtY3AFRHNtY3AFRHNtY3AFRHNtY3AFRHNtY3AFRHNtY3AFRHNzMDEFSnNzMDEFUHNzMDEFVnNzMDEFXHNzMDEFXHNzMDEFXHNzMDEFXHNzMDEFXHNzMDEFXHNzMDEFXHNzMDIFYnNzMDIFaHNzMDIFbnNzMDIFdHNzMDIFdHNzMDIFdHNzMDIFdHNzMDIFdHNzMDIFdHNzMDIFdHNzMDMFenNzMDMFgHNzMDMFhnNzMDMFjHNzMDMFjHNzMDMFjHNzMDMFjHNzMDMFjHNzMDMFjHNzMDMFjHNzMDQFknNzMDQFmHNzMDQFnnNzMDQFpHNzMDQFpHNzMDQFpHNzMDQFpHNzMDQFpHNzMDQFpHNzMDQFpHNzMDUFqnNzMDUFsHNzMDUFtnNzMDUFvHNzMDUFvHNzMDUFvHNzMDUFvHNzMDUFvHNzMDUFvHNzMDUFvHNzMDYFwnNzMDYFyHNzMDYFznNzMDYF1HNzMDYF1HNzMDYF1HNzMDYF1HNzMDYF1HNzMDYF1HNzMDYF1HNzMDcF2nNzMDcF4HNzMDcF5nNzMDcF7HNzMDcF7HNzMDcF7HNzMDcF7HNzMDcF7HNzMDcF7HNzMDcF7HRudW0F8nRudW0F+HRudW0F/nRudW0GBHRudW0GBHRudW0GBHRudW0GBHRudW0GBHRudW0GBHRudW0GBAAAAAEAAQAAAAEAAwAAAAEAAgAAAAEAAAAAAAIACAAJAAAAAQAOAAAAAQAQAAAAAQAPAAAAAQANAAAAAQBDAAAAAQBFAAAAAQBEAAAAAQBCAAAAAwA/AEAAQQAAAAIAEQASAAAAAQASAAAAAQA8AAAAAQA+AAAAAQA9AAAAAQA7AAAAAQAKAAAAAQAMAAAAAQALAAAAAQBHAAAAAQBJAAAAAQBIAAAAAQBGAAAAAQAwAAAAAQAyAAAAAQAxAAAAAQAvAAAAAQA4AAAAAQA6AAAAAQA5AAAAAQA3AAAAAQAFAAAAAQAHAAAAAQAGAAAAAQAEAAAAAQAUAAAAAQAWAAAAAQAVAAAAAQATAAAAAQAYAAAAAQAaAAAAAQAZAAAAAQAXAAAAAQAcAAAAAQAeAAAAAQAdAAAAAQAbAAAAAQAgAAAAAQAiAAAAAQAhAAAAAQAfAAAAAQAkAAAAAQAmAAAAAQAlAAAAAQAjAAAAAQAoAAAAAQAqAAAAAQApAAAAAQAnAAAAAQAsAAAAAQAuAAAAAQAtAAAAAQArAAAAAQA0AAAAAQA2AAAAAQA1AAAAAQAzAEsAmACYAJgAmAQmBCYEJgQmBxQHwA5QDlAOZg6IDogOiA6IDr4O5A8SDxIPEg8SDyYPJg8mDyYPOg86DzoPOg9OD04PTg9OD2APYA9gD2APeg96D3oPeg+8D7wPvA+8D9oP2g/aD9oP+A/4D/gP+BAqECoQKhAqEFwQXBBcEFwQjhCiENoQzBDMEMwQzBDaENoQ2hDaEQYAAQAAAAEACAACAcQA3wHnAboBuwG8Ab0BvgG/AcABwQHCAcMBxAHFAcYBxwHIAckBygHLAcwBzQHOAc8B0AHRAdIB0wHoAekCQwI7AeoB6wHsAe0B7gHvAfAB8QHyAfMB9AH1AfYB9wH4AfkB+gH7AfwB/QH+AgACAQTcAgICAwIEAgUCBgIHAggCCQIKAgsCLwIPAhACEQIUAhUCFgIXAhgCGQIbAhwCHgIdAvsC/AL9Av4C/wMAAwEDAgMDAwQDBQMGAwcDCAMJAwoDCwMMAw0DDgMPAxADEQMSAxMDFAMVAxYDFwMYAxkDGgMbAxwDHQMeAx8DIAMhAyIDIwMkAyUDJgMnAygDKQMqAysDLAMtAy4DLwMwAzEDMgMzAzQDNQM2AzcDOAM5AzoDOwM8Az0DPgM/A0ADQQNCA0MDRQNEA0YDRwNIA0kDSgNLA0wDTQNOA08DUANRBKoEqwSsBK0ErgSvBLAEsQSyBLMEtAS1BLYEtwS4BLkEugS7BLwEvQS+BL8EwATBBMIEwwTEBMUB/wTGBMcEyATJBMoEywTMBM0EzgTPBNAE0QTSBNME1ATVBNcE2ATaAhoE2wIOBNYCEwINBNkCDAISAAEA3wAIACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgBlAGcAhQCSALAAsQCyALMAtAC1ALYAtwC4ALkA0QDSANMA1ADVANYA1wDYANkA2gDbANwA3QDeAN8A4ADhAOIA4wDkAOUA5gDnAOgBLAEwATIBOAE6ATwBPgE/AUUBRgF/AYUBigGNAkYCRwJJAksCTAJNAk4CTwJQAlECUgJTAlQCVQJWAlcCWAJZAloCWwJcAl0CXgJfAmACYQJiAmMCZAJlAoIChAKGAogCigKMAo4CkAKSApQClgKYApoCnAKeAqACogKkAqYCqAKqAqwCrgKxArMCtQK3ArkCuwK9Ar8CwQLEAsYCyALKAswCzgLQAtIC1ALYAtoC3ALeAuAC4gLkAuYC6ALqAuwC7gLwAvEC8wL1A1IDUwNUA1UDVgNXA1gDWgNbA1wDXQNeA18DYANhA2MDZANlA2YDZwNoA2kDeQN6A3sDfAN9A34DfwOAA4EDggODA4QDhQOGA4cDiAOJA4oDiwOMA40DjgO6A7wDvgPTA9kD3wRIBEoETgRWBFgEXQRpAAEAAAABAAgAAgF0ALcBugG7AbwBvQG+Ab8BwAHBAcIBwwHEAcUBxgHHAcgByQHKAcsBzAHNAc4BzwHQAdEB0gHTAvwDLwI7AfoEyQTKAfsB/AH9Af4B/wIABM0EzgTQBNME3AICAgMCBAIFAgYCBwIIAgkCCgILAfQB9QH2AfcB+AH5Ai8CDwIQAhECFAIVAhcCGQL9Av4C/wMAAwEDAgMDAwQDBQMGAwcDCAMJAwoDCwMMAw0DDgMPAxADEQMSAxMDFAMVAxYDFwMYA04DGQMaAxsDHAMdAx4DHwMgAyEDIgMjAyQDJQMmAycDKAMpAyoDKwMsAy0DLgMwAzEDMgMzAzQDNQM2AzcDOAM5AzoDOwM8Az0DPgM/A0ADQQNCA0MDRQNEA0YDRwNIA0kDSgNLA0wDTQNPA1ADUQTIBMsEzATPBNEE0gIBBNQEwATBBMIEwwTEBMUExgTHBNUE1wTYAhgE2gIaBNsC+wIOBNYCEwINBNkCFgIMAhIAAQC3AEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0AXgCHAIwAkwDpAOoA6wDsAO0A7gDvAPAA8QDyAPMA9AD1APYA9wD4APkA+gD7APwA/QD+AP8BAAEBAQIBAwEEAQUBBgEtATEBMwE5ATsBPQFAAUcCSgJmAmcCaAJpAmoCawJsAm0CbgJvAnACcQJyAnMCdAJ1AnYCdwJ4AnkCegJ7AnwCfQJ+An8CgAKBAoMChQKHAokCiwKNAo8CkQKTApUClwKZApsCnQKfAqECowKlAqcCqQKrAq0CsgK0ArYCuAK6ArwCvgLAAsICxQLHAskCywLNAs8C0QLTAtUC2QLbAt0C3wLhAuMC5QLnAukC6wLtAu8C8gL0AvYDjwOQA5EDkgOTA5QDlQOWA5cDmAOZA5oDmwOcA50DngO7A70DvwPNA9QD2gPgBEYESQRLBE8EVwRZBFoEXgRqAAYAAAAGABIAKgBCAFoAcgCKAAMAAAABABIAAQCQAAEAAABKAAEAAQBNAAMAAAABABIAAQB4AAEAAABKAAEAAQBOAAMAAAABABIAAQBgAAEAAABKAAEAAQKtAAMAAAABABIAAQBIAAEAAABKAAEAAQOaAAMAAAABABIAAQAwAAEAAABKAAEAAQOcAAMAAAABABIAAQAYAAEAAABKAAEAAQQZAAIAAQCnAKsAAAAEAAAAAQAIAAEGHgA2AHIApACuALgAygD8AQ4BGAFKAWQBfgGQAboB7AH2AhgCMgJEAnYCiAKiAswC3gMQAxoDJAM2A2gDcgN8A4YDoAO6A8wD9gQoBDIEVARuBIAEsgTEBN4FCAUaBSQFLgU4BUIFbAWWBcAF6gYUAAYADgAUABoAIAAmACwCSwACAKcCTAACAKgCTgACAKkD8AACAKoEegACAKsD7gACAKwAAQAEBIcAAgCsAAEABAKIAAIAqAACAAYADASJAAIArASLAAIBogAGAA4AFAAaACAAJgAsAlMAAgCnAlQAAgCoBAoAAgCpBAgAAgCqBHwAAgCrBAYAAgCsAAIABgAMBHYAAgCoAqIAAgGiAAEABASNAAIArAAGAA4AFAAaACAAJgAsAlcAAgCnAlgAAgCoAqYAAgCpBBYAAgCqBH4AAgCrBBgAAgCsAAMACAAOABQEjwACAKgEkQACAKwCswACAaIAAwAIAA4AFAK1AAIAqASTAAIArAK3AAIBogACAAYADAOsAAIAqASVAAIArAAFAAwAEgAYAB4AJAR4AAIApwK9AAIAqAJbAAIAqQSXAAIArAK/AAIBogAGAA4AFAAaACAAJgAsAlwAAgCnAl0AAgCoAl8AAgCpBBwAAgCqBIAAAgCrBBoAAgCsAAEABASZAAIAqAAEAAoAEAAWABwCygACAKgEggACAKsEmwACAKwCzAACAaIAAwAIAA4AFALQAAIAqASdAAIArALWAAIBogACAAYADASfAAIArALaAAIBogAGAA4AFAAaACAAJgAsAmEAAgCnAmIAAgCoAuAAAgCpBDQAAgCqBIQAAgCrBDIAAgCsAAIABgAMBKEAAgCpBKMAAgCsAAMACAAOABQDnwACAKcDoQACAKgEpQACAKwABQAMABIAGAAeACQDpQACAKcCZQACAKgERAACAKkEQgACAKoEQAACAKwAAgAGAAwC8QACAKgEpwACAKwABgAOABQAGgAgACYALAJmAAIApwJnAAIAqAJpAAIAqQPxAAIAqgR7AAIAqwPvAAIArAABAAQEiAACAKwAAQAEAokAAgCoAAIABgAMBIoAAgCsBIwAAgGiAAYADgAUABoAIAAmACwCbgACAKcCbwACAKgECwACAKkECQACAKoEfQACAKsEBwACAKwAAQAEBHcAAgCoAAEABASOAAIArAABAAQEGQACAKwAAwAIAA4AFASQAAIAqASSAAIArAK0AAIBogADAAgADgAUArYAAgCoBJQAAgCsArgAAgGiAAIABgAMA60AAgCoBJYAAgCsAAUADAASABgAHgAkBHkAAgCnAr4AAgCoAnYAAgCpBJgAAgCsAsAAAgGiAAYADgAUABoAIAAmACwCdwACAKcCeAACAKgCegACAKkEHQACAKoEgQACAKsEGwACAKwAAQAEBJoAAgCoAAQACgAQABYAHALLAAIAqASDAAIAqwScAAIArALNAAIBogADAAgADgAUAtEAAgCoBJ4AAgCsAtcAAgGiAAIABgAMBKAAAgCsAtsAAgGiAAYADgAUABoAIAAmACwCfAACAKcCfQACAKgC4QACAKkENQACAKoEhQACAKsEMwACAKwAAgAGAAwEogACAKkEpAACAKwAAwAIAA4AFAOgAAIApwOiAAIAqASmAAIArAAFAAwAEgAYAB4AJAOmAAIApwKAAAIAqARFAAIAqQRDAAIAqgRBAAIArAACAAYADALyAAIAqASoAAIArAABAAQC9wACAKgAAQAEAvkAAgCoAAEABAL4AAIAqAABAAQC+gACAKgABQAMABIAGAAeACQCcgACAKcCcwACAKgCpwACAKkEFwACAKoEfwACAKsABQAMABIAGAAeACQEKgACAKcEKAACAKgELgACAKkELAACAKoEMAACAKwABQAMABIAGAAeACQEKwACAKcEKQACAKgELwACAKkELQACAKoEMQACAKwABQAMABIAGAAeACQEOAACAKcENgACAKgEPAACAKkEOgACAKoEPgACAKwABQAMABIAGAAeACQEOQACAKcENwACAKgEPQACAKkEOwACAKoEPwACAKwAAQAEBIYAAgCoAAIAEQAlACkAAAArAC0ABQAvADQACAA2ADsADgA9AD4AFABFAEkAFgBLAE0AGwBPAFQAHgBWAFsAJABdAF4AKgCBAIEALACDAIMALQCGAIYALgCJAIkALwCMAIwAMACXAJoAMQDPAM8ANQABAAAAAQAIAAEABgACAAEAAgLUAtUAAQAAAAEACAACAA4ABATdBN4E3wTgAAEABAKGAocCmAKZAAQAAAABAAgAAQAmAAIACgAcAAIABgAMAaMAAgBKAagAAgBYAAEABAGpAAIAWAABAAIASgBXAAQAAAABAAgAAQBEAAIACgAUAAEABAGkAAIATQABAAQBpgACAE0ABAAAAAEACAABAB4AAgAKABQAAQAEAaUAAgBQAAEABAGnAAIAUAABAAIASgGjAAEAAAABAAgAAQAGAZUAAQABAEsAAQAAAAEACAABAAYBJwABAAEAugABAAAAAQAIAAEABgGsAAEAAQA2AAEAAAABAAgAAgAcAAIB4wHkAAEAAAABAAgAAgAKAAIB5QHmAAEAAgAvAE8AAQAAAAEACAACAB4ADAIoAioCKQIrAiwCHwIgAiEBrgIjAiQCJQABAAwAJwAoACsAMwA1AEYARwBIAEsAUwBUAFUAAQAAAAEACAACAAwAAwImAicCJwABAAMASQBLAa4AAQAAAAEACAACAGYACAI9Ai0CLgIwAjECOQI6AjwAAQAAAAEACAACABYACAAbABUAFgAXABgAGQAdABQAAQAIAa0CIgRwBHEEcgRzBHQEdQABAAAAAQAIAAIAFgAIBHUCIgRwBHEEcgRzAa0EdAABAAgAFAAVABYAFwAYABkAGwAdAAEAAAABAAgAAgAWAAgAFQAWABcAGAAZABsAHQAUAAEACAItAi4CMAIxAjkCOgI8Aj0AAQAAAAEACAABAAYBaQABAAEAEwAGAAAAAQAIAAMAAQASAAEAUgAAAAEAAABKAAIAAgF8AXwAAAHUAd0AAQABAAAAAQAIAAEAKAHAAAEAAAABAAgAAgAaAAoCMgB6AHMAdAIzAjQCNQI2AjcCOAACAAEAFAAdAAAAAQAAAAEACAACACYAEAHUAdUB1gHXAdgB2QHaAdsB3AHdAkACPgJBAkICPwThAAEAEAAUABUAFgAXABgAGQAaABsAHAAdAE0ATgKtA5oDnAQZ\",\n  \"Roboto-MediumItalic.ttf\": \"AAEAAAARAQAABAAQR1BPUyEcbY8AAhQcAABZakdTVULEnLdcAAJtiAAAGXxPUy8yoQuw+wAAAZgAAABgY21hcNhuDxIAABpsAAAGXGN2dCAElytKAAAjUAAAAFZmcGdte/lhqwAAIMgAAAG8Z2FzcAAIABMAAhQQAAAADGdseWZgubUGAAAtcAAB42poZG14LxpP7wAAFYAAAATsaGVhZPi2qwsAAAEcAAAANmhoZWEM2xKRAAABVAAAACRobXR4rRqYNAAAAfgAABOIbG9jYSKZqcwAACOoAAAJxm1heHAHEgLZAAABeAAAACBuYW1lRuRz4wACENwAAAMUcG9zdP9hAGQAAhPwAAAAIHByZXAbsfg2AAAihAAAAMwAAQAAAAIAALDh6v1fDzz1ABsIAAAAAADE8BEuAAAAANDbTpf6Qf3VCXgIcwACAAkAAgAAAAAAAAABAAAHbP4MAAAJN/pB/mwJeAgAAbMAAAAAAAAAAAAAAAAE4gABAAAE4gCPABYAVgAFAAEAAAAAAA4AAAIAAfIABgABAAMEGQH0AAUAAAWaBTMAAAEfBZoFMwAAA9EAZgIAAAACAAAAAAAAAAAA4AAK/1AAIX8AAAAhAAAAAEdPT0cAAQAA//0GAP4AAGYHmgIAIAABnwAAAAAEOgWwACAAIAACA5YAZAAKAAAACgAAAfkAAAH5AAACHwA3Ao4AoQTHADsEcwBCBb0AtQUAAC0BWgCQAr8AaALG/5QDeABnBF0APQG//4kClgA2AjUAMAMc/38EcwBgBHMA7wRzAAsEcwAmBHMACQRzAFoEcwBjBHMAhgRzADsEcwCOAhkAKwHi/5oD/AAyBGIAYgQUAC8D0ACVBvsAMgU0/6QE7wAnBRsAZQUcACcEbQAnBE0AJwVSAGsFjQAnAjsANQRZAAME7gAnBD0AJwbVACcFjAAnBWYAawUAACcFZgBkBOIAJwS5ACQEwACcBRkAWwUPAJsG3gC3BPP/wwTFAKEEtv/lAir/7wNIAKwCKv96A1sARAOK/3kCigDKBD0AIgRoABAEGgA4BGsAOwQ0ADsCygBfBHD/9wRZAA0CBQAfAfz/DAQXABECBQAfBssAEARbAA0EdQA5BGj/xwRyADsCxAAQBAsAHAKfADsEWgBKA+EAZAXOAHcD8f+5A9H/tQPx/+cCpAAwAf0AIAKk/5kFMgBbAfkAAAIY/+YEZQBMBJv/9gV8AAgExQBQAff/7ATc/9wDdADRBh4AXgOAAL4DzgBJBFUAgAKWADYGHgBeA8cA7wL9AOQEMwAbAukAVgLpAGcCkQDIBKH/3QPZAH0COwCeAgr/0wLpAOEDlQC+A84AAgWtALkGBgCxBjAAlgPQ/9IFNP+kBTT/pAU0/6QFNP+kBTT/pAU0/6QHVf+HBRsAZQRtACcEbQAnBG0AJwRtACcCOwA1AjsANQI7ADUCOwA1BTr//wWMACcFZgBrBWYAawVmAGsFZgBrBWYAawQtACMFZAAVBRkAWwUZAFsFGQBbBRkAWwTFAKEErwAnBMsAGwQ9ACIEPQAiBD0AIgQ9ACIEPQAiBD0AIgaXAA8EGgA4BDQAOwQ0ADsENAA7BDQAOwIUACICFAAiAhQAIgIUACIEjQBGBFsADQR1ADkEdQA5BHUAOQR1ADkEdQA5BHgAPQRvACoEWgBKBFoASgRaAEoEWgBKA9H/tQR+/80D0f+1BTT/pAQ9ACIFNP+kBD0AIgU0/6QEPQAiBRsAZQQaADgFGwBlBBoAOAUbAGUEGgA4BRsAZQQaADgFHAAnBQEAOwU6//8EiQA7BG0AJwQ0ADsEbQAnBDQAOwRtACcENAA7BG0AJwQ0ADwEbQAnBDQAOwVSAGsEcP/3BVIAawRw//cFUgBrBHD/9wVSAGsEcP/3BY0AJwRZAA0FjgAuBHcAKwI7ADUCFAAUAjsANQIUAB8COwA1AhQAIgI7/44CBf92AjsANQIUACIGlAA1BAEAHwRZAAMCIP8PBO4AJwQXABEEfwAhBD0AJwIFAB8EPQAnAgX/ogQ9ACcCmwAfBD0AJwLhAB8ETAAhAkcAHwWMACcEWwANBYwAJwRbAA0FjAAnBFsADQRbAA0FcgAjBG8AEQVmAGsEdQA5BWYAawR1ADkFZgBrBHUAOQeDAFAHDQBCBOIAJwLEABAE4gAnAsT/nATiACcCxAAQBLkAJAQLABwEuQAkBAsAHAS5ACQECwAcBLkAJAQLABwEwACcAp8AOwTAAJwCxwA7BMAAnAKf/+IFGQBbBFoASgUZAFsEWgBKBRkAWwRaAEoFGQBbBFoASgUZAFsEWgBKBRkAWwRaAEoG3gC3Bc4AdwTFAKED0f+1BMUAoQS2/+UD8f/nBLb/5QPx/+cEtv/lA/H/5wIGAB4FaABOAsT/SgVpAFsEhQA2BYMAWwTWAEoCIP8PBVIAawRw//cFjAAnBFsADQU0/6QEPQAiB1X/hwaXAA8FZAAVBG8AKgU0/6QEPQAiBG0AJwQ0ADsCO//JAhT/fgVmAGsEdQA5BOIAJwLEAAcFGQBbBFoASgS5ACQECwAcBMAAnAKfADsCIP8PBCUANgG5AIoD0gECA54BDQPIAO8DawD+AgUBAgKnAPoCRf+oA8QA3gMRAKwCY//uAAr9VAAK/dcACvz2AAr91gAK/L8ACvygAlUBLgQlAOgFNP+kAjsAngTR/74F8f/GAp//ygV6ABgFKf9YBVAAHQKgAAsFNP+kBO8AJwRdAC4Fnf+qBG0AJwS2/+UFjQAnBVoAXgI7ADUE7gAnBRr/sgbVACcFjAAnBHcAAAVmAGsFjwAuBQAAJwR3/9wEwACcBMUAoQXLAFIE8//DBYkAdQU8AAkCOwA1BMUAoQRrAD4ESAAoBG8AEQKgAG4ESABXBGsAPgSr/+UD+QB3BG8AOARIACgEBQBmBG8AEQSHAGwCoABuBH8AIQRS/6gEof/dA+EAZAP+AD4EdQA5BNcAXQRv/8sEIQA7BHcAOAQXAG4ESABXBa0AMgPx/7kFpwA/BmsAVAKgAEwESABXBHUAOQRIAFcGawBUBJkAUARjAG0Ex/8kBkoAVwRtACcEbQAnBdoAkQRdAC4FOgBnBLkAJAI7ADUCOwA1BFkAAwhQ/8oIVwAuBjQAoATuACcFhwAnBO0AmwWJACUFNP+kBOsAIwTvACcEXQAuBeL/hARtACcHcf+lBLsAHgWHACcFhwAnBQoALgWI/8oG1QAnBY0AJwVmAGsFjwAuBQAAJwUbAGUEwACcBO0AmwY4AFYE8//DBdUAJQVoAMUHawArB8YAKwX1AIkGzQAuBOoAIwUxAE8HJgAyBNv/sAQ9ACIEZQBDBHYAIgNKABgE2v+FBDQAOwZO/60EAQAWBH8AGQR/ABkEVgAiBIH/vwXfACIEfgAZBHUAOQR/ABkEaP/HBBoAOAPhAFMD0f+1BbAAPQPx/7kEuAAZBE4AcAZmABkGwQASBPoATwZIACIEUAAiBCUAIwZcACQEWP+2BDQAOwQ0ADsEWQANA0oAGAQlADsECwAcAgUAHwIUACIB/P8MBqf/vQa5ABkEcAANBFYAIgR/ABkD0f+1BH8AGQcbAGAGKQBEBOoAIwRPACEG+wArBd0AGQTv/64ESP+cBxQAPgYQADAGwgAUBcMAFgj1ADUHxgAiBAr/qgPc/7UFiQB1BacAPwVaAGIEbwA2BP0AqAP5AHcE/QCoA/kAdwk3AGsIRgA5BVoAZgRvADgHFwBiBh4ASwcbAGAGKQBEBP0AVgQzAEUE4wA4AAr85gAK/Q4ACv4rAAr+PAAK+kEACvpvBYcAJwR/ABkE6gAjBE8AIQT2ACcEbf/HBFIAIgOPABEEXf/8A0r/ywSdAC4ECgARB3H/pQZO/60EuwAeBAEAFgUKAC4EVgAiBQ4AIwSRACEFHgA3BC4AGQZsAKQFgwBsBY0AJwR+ABkHngAnBYkAEQgRAC4GygARBgUAZQTjAEsFGwBlBBoAOATAAJwD4QBTBMUAoQP5AHcExQChA/kAVATz/8MD8f+5BwQAnQVQAFYFaADFBE4AcAVUALkEWwCFBWcA5wRZAA0F/wBiBKj/9AX/AGIEqP/0AjsANQdx/6UGTv+tBQQAIwRgACEFiP/KBIH/vwWNAC4EbwARBY0AJwR+ABkFaADFBE4AcAbVACcF3wAiAjsANQU0/6QEPQAiBTT/pAQ9ACIHVf+HBpcADwRtACcENAA7BWgASAQlADYFaABIBCUANgdx/6UGTv+tBLsAHgQBABYEjAAvBIz/8AWHACcEfwAZBYcAJwR/ABkFZgBrBHUAOQVaAGIEbwA2BVoAYgRvADYFMQBPBCUAIwTtAJsD0f+1BO0AmwPR/7UE7QCbA9H/tQVoAMUETgBwBF0ALgNKABgGzQAuBkgAIgSsADMDQwAJBPP/wwPx/7kE8//DA/H/uQTqADAEawA7BsYARQayAEcGLACqBQoAYQRjAJIEJwCMB43/3gZ0/94HygAnBnUACwTnAEwEFgA9BYkAkAUAAHMFNgBWBEgAKAWI/8oEgf+/BTT/pAQ9ACIE7wAnBGgAEAUcACcEawA7BRwAJwRrADsFjQAnBFkADQTuACcEFwARBO4AJwQXABEEPQAnAgX/5AbVACcGywAQBtUAJwbLABAFjAAnBFsADQUAACcEaP/HBOIAJwLE/94EuQAkBAsAHATAAJwCnwA7BQ8AmwPhAGQFDwCbA+EAZAbeALcFzgB3Bt4AtwXOAHcG3gC3Bc4AdwbeALcFzgB3BLb/5QPx/+cFNP+kBD0AIgU0/6QEPQAiBTT/pAQ9ACIFNP+kBD0AIgU0/6QEPQAiBTT/pAQ9ACIFNP+kBD0AIgU0/6QEPQAiBTT/pAQ9ACIFNP+kBD0AIgU0/6QEPQAiBTT/pAQ9ACIEbQAnBDQAOwRtACcENAA7BG0AJwQ0ADsEbQAnBDQAOwRtACcENAA7BG0AJwQ0ADsEbQAnBDQAOwRtACcENAA7AjsANQIUACICO///AgX/5AVmAGsEdQA5BWYAawR1ADkFZgBrBHUAOQVmAGsEdQA5BWYAawR1ADkFZgBrBHUAOQVmAGsEdQA5BWkAWwSFADYFaQBbBIUANgVpAFsEhQA2BWkAWwSFADYFaQBbBIUANgUZAFsEWgBKBRkAWwRaAEoFgwBbBNYASgWDAFsE1gBKBYMAWwTWAEoFgwBbBNYASgWDAFsE1gBKBMUAoQPR/7UExQChA9H/tQTFAKED0f+1BMUAoQPR/7UFrP6zAx4A7AP/AAAH9AAAA/8AAAf0AAACrgAAAgQAAAFcAAAEZgAAAikAAAGfAAAA1QAAAAoAAAKXADYClwA2BQsAnAYKAIIGCgCCA4v/TgG9AK4BuQCKAcr/pAGlAM0DBgC3Aw0AlwL7/6EERQBpBID/+wLAAJ4D5QAzBYUAMwFrADYHdgCdAVoAkAKOAKECaQBdAmD/+QQ+ADcDiv/hAukAYwNMAG4ETf/DBJv/9gZJAA0GjgArCFsAJwdYACoGZAAQBIn/9ARzAE4F0QBCBB4AOwSIABAFP//kBV3/5gXBAMIDzgAxB/kAIwTsAO0E9wB9Bg8AtgayAIIGpwCIBnkAtQR4AEUFdQAfBL7/pwRqAJwEmAA0CA8ASQIm/xcEdQAwBGIAYgP8/9UEFAAXA/cAOgJTAGkCjgBmAez/zwT+AF8EjgBLBKIAXwb2AF8G9gBfBPQAXwaNABcACgAAB/v/qQg1AFwDhv/XBGP/pwSmADoEY/+nA6YACgQ2AC0ETgARBB4ADgQXABQFGwAuBBoAFAUKAC4FJgAuBKEAOwQl/4cCpwEGBL0ACgLpADMC6QAIAukAIwLpABYC6QAKAun/8QLp//QC6f/jAukAbQLpABcEBP/ZBXwAQwU1AHAEyAAAA6YAkwXjAIwEYwBwBGsAOQQlAGIEHgAOBEUACgSmADcEVQAKBKYAOgTCAAoF4gAKA6YACgREAAoDwv/yAfcAGATDAAoEjAA/A7IACgPMAAoEYgAKBGcAOQRIAAoEhf+bAf8A6wOPAQQD9gDcA/YAEwP2ANgD9gDXA48BBAOPAQUDjwEEBEb/pAQlAG0EZwA5BXAAYgQdAFUEegAqAgr/BwGw/7IEFP/WByb/wQcpAAoFdgBiBLwACgRZAAsFOv+DBhT/qQQvAAwEyAALBEUACgSw/8EELwByBT4ACgRzAF0GXAAKBt4ACgU7AEoF+wALBE8ACwRnABMGagAKBG//0gQM//UGav+pBIQACgT9AAoFTgBiBcwAQARDAG0Eqf+kBmwAYgRzAF0EcwAKBdoANwS3ADQELwAMBKYAOgROAAQD4wAeCAEACgTP/9kEbwAQBCYANwR/ADsDkgCkBIcANAR7/8cEhgA7BDQAOwRwADAFWgBvBYEAcQVmAC4FvQByBb8AcgQFAKsEaQAfA6YACgRA/38EpP/RAukAigLpAGQC6QB9AukAiQLpAJYC6QB7AukApgRT/9QEGAAnBm8AOgSaAEcEzwBOAiD/DwIg/w8CFQAiAhX/fQIVACIESAAKBGL/lwRi/5cEJQBiBIX/mwSF/5sEhf+bBIX/mwSF/5sEhf+bBIX/mwRnADkDzAAKA8wACgPMAAoDzAAKAfcAGAH3ABgB9wAYAfcAGATCAAoEpgA6BKYAOgSmADoEpgA6BKYAOgRrADkEmwB0BIcAjgRzAFoEcwAJBHMAJgRzAAsEawA5BGsAOQRrADkEJQBtBIX/mwSF/5sEhf+bBGcAOQRnADkEZwA5BGcAOQRiAAoDzAAKA8wACgPMAAoDzAAKA8wACgSMAD8EjAA/BIwAPwSMAD8EwwAKAfcADQH3ABgB9wAYAff/igH3ABgDwv/yBEQACgOmAAoDpgAKA6YACgOmAAoEwgAKBMIACgTCAAoEpgA6BKYAOgSmADoERQAKBEUACgRFAAoEHgAOBB4ADgQeAA4EHgAOBCUAYgQlAGIEJQBiBGsAOQRrADkEawA5BGsAOQRrADkEawA6BeMAjAQlAG0EJQBtBBT/1gQU/9YEFP/WBIX/mwQI/20E//94AjP/ewSw/9IEYf8sBNL/4gSF/5sESAAKA8wACgQU/9YEwwAKAfcAGAREAAoF4gAKBKYAOgRVAAoEJQBiBCUAbQRG/6QB9wAYBCUAbQPMAAoDpgAKBB4ADgH3ABgB9wAYA8L/8gREAAoELwByBIX/mwRIAAoDpgAKA8wACgTIAAsF4gAKBMMACgSmADoEvQAKBFUACgRnADkEJQBiBEb/pAQvAA0EwwAKBGcAOgQlAG0F2gA3BMgACwQvAHIFfABDBTT/pAQ9ACIEbQAnBDQAOwIU/+QAAAABAAAE5AkKBAAAAgICAwUFBgYCAwMEBQIDAgQFBQUFBQUFBQUFAgIEBQUECAYGBgYFBQYGAwUGBQgGBgYGBgUFBgYIBgUFAgQCBAQDBQUFBQUDBQUCAgUCCAUFBQUDBQMFBAcEBAQDAgMGAgIFBQYFAgUEBwQEBQMHBAMFAwMDBQQDAgMEBAYHBwQGBgYGBgYIBgUFBQUDAwMDBgYGBgYGBgUGBgYGBgUFBQUFBQUFBQcFBQUFBQICAgIFBQUFBQUFBQUFBQUFBAUEBgUGBQYFBgUGBQYFBgUGBgYFBQUFBQUFBQUFBQYFBgUGBQYFBgUGBQMCAwIDAgMCAwIHBQUCBgUFBQIFAgUDBQMFAwYFBgUGBQUGBQYFBgUGBQgIBgMGAwYDBQUFBQUFBQUFAwUDBQMGBQYFBgUGBQYFBgUIBwUEBQUEBQQFBAIGAwYFBgUCBgUGBQYFCAcGBQYFBQUDAgYFBgMGBQUFBQMCBQIEBAQEAgMDBAMDAAAAAAAAAwUGAwUHAwYGBgMGBgUGBQUGBgMGBggGBQYGBgUFBQcGBgYDBQUFBQMFBQUEBQUFBQUDBQUFBAQFBQUFBQUFBgQGBwMFBQUHBQUFBwUFBwUGBQMDBQkJBwYGBgYGBgYFBwUIBQYGBgYIBgYGBgYFBgcGBwYICQcIBgYIBQUFBQQFBQcFBQUFBQcFBQUFBQQEBgQFBQcIBgcFBQcFBQUFBAUFAgICBwgFBQUEBQgHBgUIBwYFCAcIBgoJBQQGBgYFBgQGBAoJBgUIBwgHBgUGAAAAAAAABgUGBQYFBQQFBAUFCAcFBQYFBgUGBQcGBgUJBgkIBwYGBQUEBQQFBAYECAYGBQYFBgUHBQcFAwgHBgUGBQYFBgUGBQgHAwYFBgUIBwUFBgUGBQgHBQUFBQYFBgUGBQYFBgUGBQYEBgQGBAYFBQQIBwUEBgQGBAYFCAgHBgUFCQcJBwYFBgYGBQYFBgUGBQYFBgUGBQYFBgUFAggICAgGBQYFBgMFBQUDBgQGBAgHCAcIBwgHBQQGBQYFBgUGBQYFBgUGBQYF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RvpHAkcKRzFHXkdmR25HdkgASAhIEEg9SEVITUiPSJdIx0jPSQ1JFUkdSZtJo0oDSnJKhUqYSqpKvErOSt9K9Et+S/lMLUytTT5Nm03qTnFOok6qTwVPDU8VT4xPlE/sUE9Qt1EnUW9RulIqUjJSlFMPUyJTNFNGU1hTalPqVERUUFTPVOZU+VVhVXhV91ZtVnVWiFaQVw5XhVfgV/dYDlggWF9YZ1jDWMtY01ksWTRZoVopWmRadlp+Wspa0lraWuJa6lryWvpbAltHW8JbylwCXElciVzVXTBdmF3pXmle9V9VX11f22BcYINg3GDkYVNh6WIkYjZiiGLRYxxjdWN9Y61jtWQLZDhkQGTgZOhlIGVoZahl8GZLZrFnAGdzZ/5oXWh0aIZpBWkcaYVpjWmVaahpsGopaqBrCmshazhrSWuIa/lsZWzSbUBty25YbqVu9G9hb9BwSHC6cUxx3HJ5cyhzMHM4c7V0JXRpdK50xnTedOp09nVqddh2s3eIeBh4qHkFeV95k3mweel6AHoXevJ7YXt8e5d8BHxzfM99S317faV95n4ofoR+037ffut+938Dfw9/G391f8yALICKgNyBM4E/gUuBmIHpgk+CqYNUg++D+4QHhBOEH4QnhC+Ee4TLhNeE44UshXKFfoWKheGGMYZ2hn6HAIeNh5mHpYeth7+H0YgziI6ImoimiQmJZ4lziX+Ji4mXiaOJr4m3icmJ24nuigGKCYoRiiOKNIqniq+KworUiueK+osNix+Lhovni/6MFIwnjDqMTYxfjGeMb4yCjJSMp4y5jMuM3IzvjQGNFI0sjT+NUY1djWmNhY2hjbCNwI3MjdiOMo6JjtyO5I9Oj+eQY5DakU2Ru5Iukp2TEJOCk+OUOpSTlOqVb5V3lYOVj5WblaeVs5W/lcuV15Xjle+V+5YHlhmWK5Y3lkOWT5ZblnKWhJaQlpyWqJa0lsaW2JbklvCW/JcIlxSXIJcyl0OXT5dbl3KXiZegl7eXypfdl+mX9ZgBmA2YGZglmDeYSZhhmHiYkJinmL+Y1pjumQWZIJk6mVKZaZl8mY6ZoZmzmcaZ2Jnzmg6aGpommjiaSppcmm2ahZqcmrSay5rjmvqbEpspm0SbXptwm4Kbjpuam6abspvEm9ab7pwFnB2cNJxMnGOce5ySnK2cx5zenPWdDJ0jnTqdUZ1o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A/wDXgAA////pP5sBK4FsAImACUAAAAHAXABbwAD//8AIv5wA9wEUAImAEUAAAAHAXAAqQAH//8AJ/6bBLwFsAImACYAAAAHAXYElwAK//8AEP6IBA8GAAImAEYAAAAHAXYEpf/3//8AJ/6bBOAFsAImACgAAAAHAXYEcwAK//8AO/6RBIgGAAImAEgAAAAHAXYEkAAA//8AJ/35BOAFsAImACgAAAAHA6sBAf6S//8AO/35BIgGAAImAEgAAAAHA6sBHv6S//8AJ/6bBYcFsAImACwAAAAHAXYFAAAK//8ADf6bA/kGAAImAEwAAAAHAXYEfwAK//8AJwAABXEHNgImAC8AAAEHAHcBpQE2AAkAsAQvsA/cMDEA//8AEQAABHUHPQImAE8AAAEHAHcBowE9AAkAsAQvsA/cMDEA//8AJ/7cBXEFsAImAC8AAAAHAXYE0QBL//8AEf7HBEoGAAImAE8AAAAHAXYEYAA2//8AJ/6bA8MFsAImADAAAAAHAXYElwAK////5P6bAhcGAAImAFAAAAAHAXYDRAAK//8AJwAABs4HNgImADEAAAEHAHcCvgE2ABMAsABFWLACLxuxAh8+WbAR3DAxAP//ABAAAAZoBgACJgBRAAABBwB3ApgAAAAJALADL7Ak3DAxAP//ACf+mwbOBbACJgAxAAAABwF2BasACv//ABD+mwZoBFICJgBRAAAABwF2Ba4ACv//ACf+lwWGBbACJgAyAAAABwF2BQIABv//AA3+mwP6BFICJgBSAAAABwF2BGwACv//ACcAAAUEB0ICJgA0AAABBwB3AasBQgAJALADL7AW3DAxAP///8f+YARtBfcCJgBUAAABBwB3AZv/9wAJALANL7Ah3DAxAP//ACf+mwTYBbACJgA2AAAABwF2BJgACv///97+mwLvBFMCJgBWAAAABwF2Az4ACv//ACT+kQS7BccCJgA3AAAABwF2BLAAAP//ABz+iAPEBFACJgBXAAAABwF2BGL/9///AJz+lAUiBbACJgA4AAAABwF2BJ8AA///ADv+kQKuBUECJgBYAAAABwF2A/UAAP//AJsAAAWBBzcCJgA6AAABBwFuAN0BQwAJALABL7AR3DAxAP//AGQAAAQNBewCJgBaAAABBgFuFvgACQCwAS+wEdwwMQD//wCb/psFgQWwAiYAOgAAAAcBdgTV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AesB7AHtAe4B7wHwAfEB8gJSAlQCWAJaAlwCXgJiAmQCagJsAnACcgJ0AnYCegJ8An4CgAKaAqICpAKqArADhwOOA5MDlgACAAAAAgAKO9oAAQNsAAQAAAGxBtI6+jr6BvwHUjfeI2I7mDuqOHYHWDiWOJY43jTeDqg4ljiWO6omhAqSCxQ1MDjeNI43uDdKOOQPYgt+OFQ2GjiMC8AM6gz0N643rji4NhoO1g3qOW4OTDeoOW4OZjfeN9433jfeN9433juYOHY4djh2OHY4ljiWOJY4ljuqOJY7qjuqO6o7qjuqON443jjeON445DhUOFQ4VDhUOFQ4VDiMOIw4jDiMN644uDi4OLg4uDi4OW42GjluN944VDfeOFQ33jhUO5g7mDuYO5g7qjuqOHY4jDh2OIw4djiMOHY4jDh2OIw4ljeuOJY4ljiWOJY4ljjeNN4OqA6oDqgOqDiWN644ljeuOJY3rjeuO6o4uDuqOLg7qji4DtYO1g7WNTA1MDUwON443jjeON443jjeN7g45DluOOQPYg9iD2I33jhUNTAO6Dr6N944djiWOJY7qjjkN94jYjZ+N944dg9iOJY7qjiWNN433jiWOJYPhDuqJoQQfjUwOOQRfDdKElo4ljjkN64S+DluEv43rhW8OW4Xlji4GKgYwhjIGM4ayBrOGwQbNji4OHY4dhu0Nn44ljiWON4dKh7cIJo03jY0OJY33iHQI2I2fiNsOHY3SiW6OJY03jiWOJY4ljuqJoQ7mDUwNjQ3SjiWOJYmpihAND4pHingKm44VCrMK6Y3QCwwOIw3qCz6LSQ4uDYaLoo5bjYaN6gxEDFOMoA0aDYaMwI4jDiMN0AziDOyNAg5bjQ+NGg33ji4NI45bjSOOW40tDYaNn43QDZ+N0o3qDTeNN403jTeOJY7mDUwOOQ5bjjkN0o3qDeuOJY3SjeoOJY4ljiWN944VDfeOFQ4djiMOIw4jDdKN6g7qji4OLg2GjY0OW42NDluNjQ5bjZ+N0A3QDdKN6g33jhUOJY3rje4N7g3uDfeOFQ33jhUN944VDfeOFQ33jhUN944VDfeOFQ33jhUN944VDfeOFQ33jhUN944VDh2OIw4djiMOHY4jDh2OIw4djiMOHY4jDh2OIw4djiMOJY4ljuqOLg7qji4O6o4uDuqOLg7qji4O6o4uDuqOLg4uDjeON445DluOOQ5bjjkOW445DluO6o6+jmIOvo6+jr6Ovo6+jsAOwo7HDsuO0A7XjtoO3I7mDuqO6oAAQGxAAQABgALAAwAEwAlACYAJwAoACkAKgAsAC0ALgAvADAAMQAyADMANAA1ADYAOAA5ADoAOwA8AD0APgA/AEUARgBJAEoATABPAFEAUgBTAFQAVgBYAFoAWwBcAF0AXwCDAIQAhQCGAIcAiACKAIsAjACNAI4AjwCQAJEAkgCTAJQAlQCWAJcAmACZAJwAnQCeAJ8AoACjAKQApQCmAKcAqACrAKwArQCuALQAtQC2ALcAuAC5AMAAwQDCAMMAxADFAMYAxwDIAMkAywDNAM8A0QDTANUA1gDXANgA2QDaANsA3ADdAN4A5wDoAOsA7QDvAPEA8wD3APkA/AD+AQABAgEGAQcBCAEJAQoBCwEMAQ8BEAERARIBEwEUARgBGgEcASUBJwEpASsBLQEvATEBMwE1ATcBOQE6ATsBPAE+AUABTgFPAWIBZQFmAXkBewF8AX0BfgF/AYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZIBkwGUAZUBlgGXAZgBmgGbAZ4BoQGjAaYBpwGpAa0BrgGvAbEBsgGzAbQBtQG2AbgBuQG8AcMBxAHFAcYByQHKAcsBzAHNAc4BzwHRAdIB0wHUAdUB1gHXAdgB2QHaAdsB3QHeAd8B4AHhAeMB5AHlAeYB6AHpAesB7AHtAe8B8AHxAfIB8wH0AfUB9gH3AfgB+QH6Af0CAQIDAgUCBgIHAggCCQIMAg0CDwIQAhECEwIUAhYCFwIcAh0CIQIlAiYCKQI2AjcCOAI5AjoCRAJRAlICUwJUAlgCWQJcAl4CYAJiAmQCbAJuAnACcQJyAnQCdQJ9AoICgwKEAosCjwKRApICkwKUApUCmAKZApsCnQKeAp8CqAKpAq0CrwKwArECsgKzArQCtQK4ArkCvQK+Ar8C1gLXAuYC5wL4AvoC/AMCAwMDBAMFAwYDBwMIAwkDCgMLAwwDDQMOAw8DEAMRAxIDEwMUAxUDFgMXAxgDGQMaAxsDHAMdAx4DHwMgAyEDIgMjAyQDJQMmAycDKAMpAyoDLAMuAy8DMAMxAzIDMwM0AzUDNgM3AzgDOQM6AzsDQwNGA0gDVANVA1YDVwNYA1kDWgNbA1wDcANxA3MDdAN1A34DfwPZA9sD3APeA+ED4gPpA+wEMQQzBDQACgA4/8QBJf/EASf/xAFi/8QBxf/EAc7/xAHl/8QCYv/EAm7/xAJ2/8QAFQA6ABQAOwAmAD0AFgCgABYBNwAmATkAFgE7ABYBfwAWAZUAFgGbABYCNwAUAjkAFAJwABYCcgAWAvgAJgL6ACYC/AAmA1QAFgNWABYDWAAWA1oAFgABABP/CADOABD+7gAS/u4AJf9AAC7/MAA4ABQARf/eAEf/6wBI/+sASf/rAEv/6wBT/+sAVf/rAFb/5gBZ/+oAWv/oAF3/6ACD/0AAhP9AAIX/QACG/0AAh/9AAIj/QACj/94ApP/eAKX/3gCm/94Ap//eAKj/3gCq/+sAq//rAKz/6wCt/+sArv/rALX/6wC2/+sAt//rALj/6wC5/+sAvP/qAL3/6gC+/+oAv//qAMD/6ADC/+gAw/9AAMT/3gDF/0AAxv/eAMf/QADI/94Ayv/rAMz/6wDO/+sA0P/rANL/6wDW/+sA2P/rANr/6wDc/+sA3v/rAOD/6wDi/+sA5P/rAOb/6wD3/zABEP/rARL/6wEU/+sBFv/rASUAFAEnABQBLP/qAS7/6gEw/+oBMv/qATT/6gE2/+oBOv/oAUb/6wFI/+oBTv9AAU//3gFiABQBef9AAYL/QAGF/0ABjP9AAZz/6wGg/+oBof/rAaP/6AGt/+gBr//rAbL/6wGz/+sBtf/qAbv/6gG8/+sBvf/qAcUAFAHL/zABzgAUAdP/QAHlABQB8//eAfj/6wIB/+sCBP/rAgb/6AIH/+sCE//rAhT/6wIX/+sCIf/oAin/QAI2/+sCOP/oAjr/6AI8/+sCQP/rAkT/6wJiABQCa//rAm3/6wJuABQCcf/oAnYAFAKS/0ACk//eApT/QAKV/94Cmf/rApv/6wKd/+sCqf/rAqv/6wKt/+sCsf/oArP/6AK1/+gCw//rAsT/6wLF/+sCz//rAtb/QALX/94DAv9AAwP/3gME/0ADBf/eAwb/QAMH/94DCP9AAwn/3gMK/0ADC//eAwz/QAMN/94DDv9AAw//3gMQ/0ADEf/eAxL/QAMT/94DFP9AAxX/3gMW/0ADF//eAxj/QAMZ/94DG//rAx3/6wMf/+sDIf/rAyP/6wMl/+sDJ//rAyn/6wMv/+sDMf/rAzP/6wM1/+sDN//rAzn/6wM7/+sDPf/rAz//6wNB/+sDQ//rA0X/6wNH/+oDSf/qA0v/6gNN/+oDT//qA1H/6gNT/+oDVf/oA1f/6ANZ/+gDW//oA3L+7gN2/u4Dev7uA3v+7gPs/8AAIAA4/98AOv/kADv/7AA9/90AoP/dASX/3wEn/98BN//sATn/3QE7/90BYv/fAX//3QGV/90Bm//dAcX/3wHO/98B5f/fAjf/5AI5/+QCYv/fAm7/3wJw/90Ccv/dAnb/3wL4/+wC+v/sAvz/7ANU/90DVv/dA1j/3QNa/90D7AAOABoAOP/OADr/7QA9/9AAoP/QASX/zgEn/84BOf/QATv/0AFi/84Bf//QAZX/0AGb/9ABxf/OAc7/zgHl/84CN//tAjn/7QJi/84Cbv/OAnD/0AJy/9ACdv/OA1T/0ANW/9ADWP/QA1r/0AAQAC7/7gA5/+4AnP/uAJ3/7gCe/+4An//uAPf/7gEr/+4BLf/uAS//7gEx/+4BM//uATX/7gHL/+4DRv/uA0j/7gBKAAYAEAALABAADQAUAEEAEgBH/+gASP/oAEn/6ABL/+gAVf/oAGEAEwCq/+gAq//oAKz/6ACt/+gArv/oAMr/6ADM/+gAzv/oAND/6ADS/+gA1v/oANj/6ADa/+gA3P/oAN7/6ADg/+gA4v/oAOT/6ADm/+gBFv/oAUb/6AFmABABnP/oAaH/6AGy/+gBs//oAfj/6AIE/+gCB//oAhP/6AIU/+gCF//oAjz/6AJA/+gCRP/oAmv/6AJt/+gCmf/oApv/6AKd/+gCq//oAsP/6ALE/+gCxf/oAs//6AMb/+gDHf/oAx//6AMh/+gDI//oAyX/6AMn/+gDKf/oAz3/6AM//+gDQf/oA0X/6ANwABADcQAQA3MAEAN0ABADdQAQA34AEAN/ABAAAgIF/9YDcf+YAD0AR//sAEj/7ABJ/+wAS//sAFX/7ACq/+wAq//sAKz/7ACt/+wArv/sAMr/7ADM/+wAzv/sAND/7ADS/+wA1v/sANj/7ADa/+wA3P/sAN7/7ADg/+wA4v/sAOT/7ADm/+wBFv/sAUb/7AGc/+wBof/sAbL/7AGz/+wB+P/sAgT/7AIH/+wCE//sAhT/7AIX/+wCPP/sAkD/7AJE/+wCa//sAm3/7AKZ/+wCm//sAp3/7AKr/+wCw//sAsT/7ALF/+wCz//sAxv/7AMd/+wDH//sAyH/7AMj/+wDJf/sAyf/7AMp/+wDPf/sAz//7ANB/+wDRf/sABgAU//iALX/4gC2/+IAt//iALj/4gC5/+IBEP/iARL/4gEU/+IBr//iAbz/4gIB/+ICNv/iAqn/4gKt/+IDL//iAzH/4gMz/+IDNf/iAzf/4gM5/+IDO//iA0P/4gNxABgABgAQ/4QAEv+EA3L/hAN2/4QDev+EA3v/hAAQAC7/7AA5/+wAnP/sAJ3/7ACe/+wAn//sAPf/7AEr/+wBLf/sAS//7AEx/+wBM//sATX/7AHL/+wDRv/sA0j/7AALAFv/zAPW/9cD1/+4A9j/7gPZ/70D3P/yA97/8gPm//ED6v/zA+wAEwP3/7cABABKABQAWAAyAFsAEQNxABAAHgAG//IAC//yAFr/8wBd//MAwP/zAML/8wE6//MBZv/yAaP/8wGt//MCBf/1Agb/8wIh//MCOP/zAjr/8wJx//MCsf/zArP/8wK1//MDVf/zA1f/8wNZ//MDW//zA3D/8gNx//IDc//yA3T/8gN1//IDfv/yA3//8gAIAFv/5QGW/8sBuP/kA9z/7APe/+wD5v/rA+r/7QPsAA0APgAn//MAK//zADP/8wA1//MAiv/zAJX/8wCW//MAl//zAJj/8wCZ//MAm//zAMn/8wDL//MAzf/zAM//8wDf//MA4f/zAOP/8wDl//MBD//zARH/8wET//MBFf/zAUX/8wFS//MBfv/zAYn/8wGQ//MBqwANAcf/8wHh//MB5P/zAiP/8wI1//MCO//zAj3/8wI///MCQf/zAkP/8wJq//MCbP/zAqj/8wKq//MCrP/zAs7/8wMu//MDMP/zAzL/8wM0//MDNv/zAzj/8wM6//MDPP/zAz7/8wNA//MDQv/zA0T/8wNc//MEMf/zBDL/8wQ0//MENf/zAD8AJ//mACv/5gAz/+YANf/mAIr/5gCV/+YAlv/mAJf/5gCY/+YAmf/mAJv/5gDJ/+YAy//mAM3/5gDP/+YA3//mAOH/5gDj/+YA5f/mAQ//5gER/+YBE//mARX/5gFF/+YBUv/mAX7/5gGJ/+YBkP/mAZb/wgGrABABx//mAeH/5gHk/+YCI//mAjX/5gI7/+YCPf/mAj//5gJB/+YCQ//mAmr/5gJs/+YCqP/mAqr/5gKs/+YCzv/mAy7/5gMw/+YDMv/mAzT/5gM2/+YDOP/mAzr/5gM8/+YDPv/mA0D/5gNC/+YDRP/mA1z/5gQx/+YEMv/mBDT/5gQ1/+YANwAl/+QAPP/SAD3/0wCD/+QAhP/kAIX/5ACG/+QAh//kAIj/5ACg/9MAw//kAMX/5ADH/+QBOf/TATv/0wFO/+QBef/kAX//0wGC/+QBhf/kAYz/5AGV/9MBl//SAZv/0wGr/+IB0//kAdn/0gHo/9ICKf/kAlj/0gJw/9MCcv/TAnT/0gKD/9ICkv/kApT/5AKe/9ICvv/SAtb/5AMC/+QDBP/kAwb/5AMI/+QDCv/kAwz/5AMO/+QDEP/kAxL/5AMU/+QDFv/kAxj/5ANU/9MDVv/TA1j/0wNa/9MAJwAQ/0YAEv9GACX/zQCD/80AhP/NAIX/zQCG/80Ah//NAIj/zQDD/80Axf/NAMf/zQFO/80Bef/NAYL/zQGF/80BjP/NAbH/8gHT/80CKf/NApL/zQKU/80C1v/NAwL/zQME/80DBv/NAwj/zQMK/80DDP/NAw7/zQMQ/80DEv/NAxT/zQMW/80DGP/NA3L/RgN2/0YDev9GA3v/RgABAasADgCvAEf/3ABI/9wASf/cAEv/3ABR/8EAUv/BAFP/1gBU/8EAVf/cAFn/3QBa/+EAXf/hAKr/3ACr/9wArP/cAK3/3ACu/9wAtP/BALX/1gC2/9YAt//WALj/1gC5/9YAvP/dAL3/3QC+/90Av//dAMD/4QDC/+EAyv/cAMz/3ADO/9wA0P/cANL/3ADW/9wA2P/cANr/3ADc/9wA3v/cAOD/3ADi/9wA5P/cAOb/3AEH/8EBCf/BAQv/wQEM/8EBEP/WARL/1gEU/9YBFv/cASz/3QEu/90BMP/dATL/3QE0/90BNv/dATr/4QFG/9wBSP/dAZz/3AGe/8EBoP/dAaH/3AGj/+EBpf/mAaf/wQGo/+sBqf/pAa3/4QGu//ABr//WAbD/5wGy/9wBs//cAbT/4wG1/90Btv/OAbj/1AG5/9sBu//dAbz/1gG9/90B9v/BAfj/3AH7/8EB/P/BAf3/wQH//8ECAP/BAgH/1gIC/8ECA//BAgT/3AIG/+ECB//cAgn/wQIL/8ECDP/BAg//wQIR/8ECE//cAhT/3AIW/8ECF//cAh3/wQIf/8ECIP/BAiH/4QI2/9YCOP/hAjr/4QI8/9wCQP/cAkT/3AJN/8ECXf/BAmX/wQJn/8ECa//cAm3/3AJx/+ECiv/BAoz/wQKQ/8ECmf/cApv/3AKd/9wCpf/BAqf/wQKp/9YCq//cAq3/1gKx/+ECs//hArX/4QK5/8ECu//BAr3/wQLD/9wCxP/cAsX/3ALP/9wC5//BAxv/3AMd/9wDH//cAyH/3AMj/9wDJf/cAyf/3AMp/9wDL//WAzH/1gMz/9YDNf/WAzf/1gM5/9YDO//WAz3/3AM//9wDQf/cA0P/1gNF/9wDR//dA0n/3QNL/90DTf/dA0//3QNR/90DU//dA1X/4QNX/+EDWf/hA1v/4QB2AAb/2gAL/9oAR//wAEj/8ABJ//AAS//wAFX/8ABZ/+8AWv/cAF3/3ACq//AAq//wAKz/8ACt//AArv/wALz/7wC9/+8Avv/vAL//7wDA/9wAwv/cAMr/8ADM//AAzv/wAND/8ADS//AA1v/wANj/8ADa//AA3P/wAN7/8ADg//AA4v/wAOT/8ADm//ABFv/wASz/7wEu/+8BMP/vATL/7wE0/+8BNv/vATr/3AFG//ABSP/vAWb/2gGc//ABoP/vAaH/8AGj/9wBqP/sAasADwGt/9wBsP/qAbL/8AGz//ABtP/OAbX/7wG2/+cBu//vAb3/7wH4//ACBP/wAgb/3AIH//ACE//wAhT/8AIX//ACIf/cAjj/3AI6/9wCPP/wAkD/8AJE//ACa//wAm3/8AJx/9wCmf/wApv/8AKd//ACq//wArH/3AKz/9wCtf/cAsP/8ALE//ACxf/wAs//8AMb//ADHf/wAx//8AMh//ADI//wAyX/8AMn//ADKf/wAz3/8AM///ADQf/wA0X/8ANH/+8DSf/vA0v/7wNN/+8DT//vA1H/7wNT/+8DVf/cA1f/3ANZ/9wDW//cA3D/2gNx/9oDc//aA3T/2gN1/9oDfv/aA3//2gBEABAADAASAAwAR//nAEj/5wBJ/+cAS//nAFX/5wCq/+cAq//nAKz/5wCt/+cArv/nAMr/5wDM/+cAzv/nAND/5wDS/+cA1v/nANj/5wDa/+cA3P/nAN7/5wDg/+cA4v/nAOT/5wDm/+cBFv/nAUb/5wGc/+cBof/nAasADwGy/+cBs//nAfj/5wIE/+cCB//nAhP/5wIU/+cCF//nAjz/5wJA/+cCRP/nAmv/5wJt/+cCmf/nApv/5wKd/+cCq//nAsP/5wLE/+cCxf/nAs//5wMb/+cDHf/nAx//5wMh/+cDI//nAyX/5wMn/+cDKf/nAz3/5wM//+cDQf/nA0X/5wNyAAwDdgAMA3oADAN7AAwABgG0/+oB9//uAgX/1QIP/+0CY//sAtH/7AABAgX/wAABAbQAIAB+AAYADAALAAwAR//oAEj/6ABJ/+gASgAMAEv/6ABT/+oAVf/oAFoACwBdAAsAqv/oAKv/6ACs/+gArf/oAK7/6AC1/+oAtv/qALf/6gC4/+oAuf/qAMAACwDCAAsAyv/oAMz/6ADO/+gA0P/oANL/6ADW/+gA2P/oANr/6ADc/+gA3v/oAOD/6ADi/+gA5P/oAOb/6AEQ/+oBEv/qART/6gEW/+gBOgALAUb/6AFmAAwBnP/oAaH/6AGjAAsBq/+QAa0ACwGv/+oBsAALAbL/6AGz/+gBtAAMAbz/6gH4/+gCAf/qAgT/6AIGAAsCB//oAhP/6AIU/+gCF//oAiEACwI2/+oCOAALAjoACwI8/+gCQP/oAkT/6AJr/+gCbf/oAnEACwKZ/+gCm//oAp3/6AKp/+oCq//oAq3/6gKxAAsCswALArUACwLD/+gCxP/oAsX/6ALP/+gDG//oAx3/6AMf/+gDIf/oAyP/6AMl/+gDJ//oAyn/6AMv/+oDMf/qAzP/6gM1/+oDN//qAzn/6gM7/+oDPf/oAz//6ANB/+gDQ//qA0X/6ANVAAsDVwALA1kACwNbAAsDcAAMA3EADANzAAwDdAAMA3UADAN+AAwDfwAMA9cADQPZAA4D2v/1A9z/7APe/+0D5v/sA+r/7gPs/78D9wANAAECBf/iAA0AXP/tAF7/7QE9/+0BP//tAUH/7QH5/+0CBf/AAgj/7QJZ/+0Cdf/tAoT/7QKf/+0Cv//tAAwAXP/yAF7/8gE9//IBP//yAUH/8gH5//ICCP/yAln/8gJ1//IChP/yAp//8gK///IAHwBa//QAXP/yAF3/9ABe//MAwP/0AML/9AE6//QBPf/zAT//8wFB//MBo//0Aa3/9AH5//ICBv/0Agj/8gIh//QCOP/0Ajr/9AJZ//ICcf/0AnX/8gKE//ICn//yArH/9AKz//QCtf/0Ar//8gNV//QDV//0A1n/9ANb//QAXQAG/8oAC//KADj/0gA6/9QAPP/0AD3/0wBa/+YAXP/vAF3/5gCg/9MAwP/mAML/5gEl/9IBJ//SATn/0wE6/+YBO//TAWL/0gFm/8oBf//TAZX/0wGX//QBm//TAaP/5gGt/+YBxf/SAc7/0gHR/+0B2f/0AeX/0gHm/+0B6P/0Aer/4QHv/9QB+f/vAgX/yQIG/+YCCP/vAg//0QIh/+YCJP/lAjf/1AI4/+YCOf/UAjr/5gJC/+MCWP/0Aln/7wJi/9ICY//EAm7/0gJw/9MCcf/mAnL/0wJ0//QCdf/vAnb/0gJ4/+ECev/hAoP/9AKE/+8Cjf/hAp7/9AKf/+8CsP/tArH/5gKy/+0Cs//mArT/7QK1/+YCtv/hAr7/9AK//+8Cxv/UAsf/9QLI/+cC0P9kAtH/yQNU/9MDVf/mA1b/0wNX/+YDWP/TA1n/5gNa/9MDW//mA3D/ygNx/8oDc//KA3T/ygN1/8oDfv/KA3//ygBsAAb/wAAL/8AAOP+dADr/xwA8//AAPf+rAFH/0gBS/9IAVP/SAKD/qwC0/9IBB//SAQn/0gEL/9IBDP/SASX/nQEn/50BOf+rATv/qwFi/50BZv/AAX//qwGV/6sBl//wAZv/qwGe/9IBp//SAcX/nQHM//UBzv+dAdH/6gHZ//AB3v/1AeX/nQHm/+oB6P/wAer/5QHv/8EB9v/SAfv/0gH8/9IB/f/SAf//0gIA/9ICAv/SAgP/0gIF/80CCf/SAgv/0gIM/9ICD//SAhH/0gIW/9ICHf/SAh//0gIg/9ICN//HAjn/xwJN/9ICWP/wAl3/0gJi/50CY//MAmX/0gJn/9ICbv+dAnD/qwJy/6sCdP/wAnb/nQJ4/+UCev/lAn7/3wKD//ACh//1Aor/0gKM/9ICjf/lApD/0gKe//ACpf/SAqf/0gKw/+oCsv/qArT/6gK2/+UCuf/SArv/0gK9/9ICvv/wAsb/zgLI/+oCyv/1AtD/ngLR/84C1P/1Auf/0gNU/6sDVv+rA1j/qwNa/6sDcP/AA3H/wANz/8ADdP/AA3X/wAN+/8ADf//AAG8ABv+xAAv/sQA4/54AOv/FADz/8gA9/6gAUf/PAFL/zwBU/88AXP/vAKD/qAC0/88BB//PAQn/zwEL/88BDP/PASX/ngEn/54BOf+oATv/qAFi/54BZv+xAX//qAGV/6gBl//yAZv/qAGe/88Bp//PAcX/ngHO/54B0f/sAdn/8gHl/54B5v/sAej/8gHq/+EB7//CAfb/zwH5/+8B+//PAfz/zwH9/88B///PAgD/zwIC/88CA//PAgX/xgII/+8CCf/PAgv/zwIM/88CD//PAhH/zwIW/88CHf/PAh//zwIg/88CN//FAjn/xQJN/88CWP/yAln/7wJd/88CYv+eAmP/wAJl/88CZ//PAm7/ngJw/6gCcv+oAnT/8gJ1/+8Cdv+eAnj/4QJ6/+ECfv/fAoP/8gKE/+8Civ/PAoz/zwKN/+ECkP/PAp7/8gKf/+8Cpf/PAqf/zwKw/+wCsv/sArT/7AK2/+ECuf/PArv/zwK9/88Cvv/yAr//7wLG/80CyP/oAtD/nwLR/8YC5//PA1T/qANW/6gDWP+oA1r/qANw/7EDcf+xA3P/sQN0/7EDdf+xA37/sQN//7EATQA4/74AUf/hAFL/4QBU/+EAWv/vAF3/7wC0/+EAwP/vAML/7wEH/+EBCf/hAQv/4QEM/+EBJf++ASf/vgE6/+8BYv++AZ7/4QGj/+8Bp//hAa3/7wHF/74Bzv++AeX/vgHv/8kB9v/hAfv/4QH8/+EB/f/hAf//4QIA/+ECAv/hAgP/4QIF/98CBv/vAgn/4QIL/+ECDP/hAg//4QIR/+ECFv/hAh3/4QIf/+ECIP/hAiH/7wIk/+0COP/vAjr/7wJC/+sCTf/hAl3/4QJi/74CY//fAmX/4QJn/+ECbv++AnH/7wJ2/74Cfv/pAor/4QKM/+ECkP/hAqX/4QKn/+ECsf/vArP/7wK1/+8Cuf/hArv/4QK9/+ECx//1AtH/4ALn/+EDVf/vA1f/7wNZ/+8DW//vAGQAOP/mADr/5wA8//IAPf/nAFH/1gBS/9YAVP/WAFz/8QCg/+cAtP/WAQf/1gEJ/9YBC//WAQz/1gEl/+YBJ//mATn/5wE7/+cBYv/mAX//5wGV/+cBl//yAZv/5wGe/9YBp//WAcX/5gHO/+YB0f/uAdn/8gHl/+YB5v/uAej/8gHq/+gB7//mAfb/1gH5//EB+//WAfz/1gH9/9YB///WAgD/1gIC/9YCA//WAgX/0AII//ECCf/WAgv/1gIM/9YCD//WAhH/1gIW/9YCHf/WAh//1gIg/9YCN//nAjn/5wJN/9YCWP/yAln/8QJd/9YCYv/mAmP/zgJl/9YCZ//WAm7/5gJw/+cCcv/nAnT/8gJ1//ECdv/mAnj/6AJ6/+gCg//yAoT/8QKK/9YCjP/WAo3/6AKQ/9YCnv/yAp//8QKl/9YCp//WArD/7gKy/+4CtP/uArb/6AK5/9YCu//WAr3/1gK+//ICv//xAsb/5wLI/+0C0P/mAtH/0ALn/9YDVP/nA1b/5wNY/+cDWv/nAAICLQALAtD/5gCTACUAEAAn/+gAK//oADP/6AA1/+gAOP/gADr/4AA9/98AgwAQAIQAEACFABAAhgAQAIcAEACIABAAiv/oAJX/6ACW/+gAl//oAJj/6ACZ/+gAm//oAKD/3wDDABAAxQAQAMcAEADJ/+gAy//oAM3/6ADP/+gA3//oAOH/6ADj/+gA5f/oAQ//6AER/+gBE//oARX/6AEl/+ABJ//gATn/3wE7/98BRf/oAU4AEAFS/+gBYv/gAXkAEAF+/+gBf//fAYIAEAGFABABif/oAYwAEAGQ/+gBlf/fAZv/3wHF/+ABx//oAcwAEAHO/+AB0wAQAdcAFAHeABAB4f/oAeT/6AHl/+AB6v/hAe//4AH3ABMB/gAQAgr/4AIcABACI//oAikAEAI1/+gCN//gAjn/4AI7/+gCPf/oAj//6AJB/+gCQ//oAmL/4AJq/+gCbP/oAm7/4AJw/98Ccv/fAnb/4AJ4/+ECef/gAnr/4QJ7/+ACf//hAocAEAKIABACjf/hAo7/4AKSABAClAAQApr/6QKo/+gCqv/oAqz/6AK2/+ECt//gAsb/3wLI/94CygAQAs7/6ALQ/98C0v/yAtQAEALVABAC1gAQAwIAEAMEABADBgAQAwgAEAMKABADDAAQAw4AEAMQABADEgAQAxQAEAMWABADGAAQAy7/6AMw/+gDMv/oAzT/6AM2/+gDOP/oAzr/6AM8/+gDPv/oA0D/6ANC/+gDRP/oA1T/3wNW/98DWP/fA1r/3wNc/+gEMf/oBDL/6AQ0/+gENf/oADIAG//yADj/8QA6//QAPP/0AD3/8ACg//ABJf/xASf/8QE5//ABO//wAWL/8QF///ABlf/wAZf/9AGb//ABxf/xAcz/9QHO//EB0f/zAdn/9AHe//UB5f/xAeb/8wHo//QB7//xAjf/9AI5//QCWP/0AmL/8QJu//ECcP/wAnL/8AJ0//QCdv/xAoP/9AKH//UCnv/0ArD/8wKy//MCtP/zAr7/9ALG//ICyP/yAsr/9QLQ//IC1P/1A1T/8ANW//ADWP/wA1r/8AAIAFgADgCJ/tcBq/+YAbH/xwHX/xIB9/9SAsL/zwPs/4AAZgAlAA8AOP/mADr/5gA8AA4APf/mAIMADwCEAA8AhQAPAIYADwCHAA8AiAAPAKD/5gDDAA8AxQAPAMcADwEl/+YBJ//mATn/5gE7/+YBTgAPAWL/5gF5AA8Bf//mAYIADwGFAA8BjAAPAZX/5gGXAA4Bm//mAcX/5gHMAA4Bzv/mAdEACwHTAA8B1wATAdkADgHeAA4B5f/mAeYACwHoAA4B6v/lAe//5gHw//QB9wASAf4ADwIF/+cCCv/oAg//5wIcAA8CKQAPAjf/5gI5/+YCWAAOAmL/5gJj/+cCbv/mAnD/5gJy/+YCdAAOAnb/5gJ4/+UCef/oAnr/5QJ7/+gCgwAOAocADgKIAA8Cjf/lAo7/6AKSAA8ClAAPAp4ADgKwAAsCsgALArQACwK2/+UCt//oAr4ADgLG/+YCyP/mAsoADgLQ/+YC0f/nAtQADgLVAA8C1gAPAwIADwMEAA8DBgAPAwgADwMKAA8DDAAPAw4ADwMQAA8DEgAPAxQADwMWAA8DGAAPA1T/5gNW/+YDWP/mA1r/5gA3AAb/vwAL/78AOP+fADr/yQA9/60AoP+tASX/nwEn/58BOf+tATv/rQFi/58BZv+/AX//rQGV/60Bm/+tAcX/nwHO/58B0f/sAeX/nwHm/+wB6v/mAe//xAIF/80CD//VAjf/yQI5/8kCYv+fAmP/zAJu/58CcP+tAnL/rQJ2/58CeP/mAnr/5gJ+/98Cjf/mArD/7AKy/+wCtP/sArb/5gLG/9ECyP/sAtD/oQLR/88DVP+tA1b/rQNY/60DWv+tA3D/vwNx/78Dc/+/A3T/vwN1/78Dfv+/A3//vwAwADj/4wA8/+UAPf/kAKD/5AEl/+MBJ//jATn/5AE7/+QBYv/jAX//5AGV/+QBl//lAZv/5AHF/+MBzP/lAc7/4wHR/+kB1//iAdn/5QHe/+UB5f/jAeb/6QHo/+UB/v/qAhz/6gJY/+UCYv/jAm7/4wJw/+QCcv/kAnT/5QJ2/+MCg//lAof/5QKI/+oCnv/lArD/6QKy/+kCtP/pAr7/5QLK/+UC0P/kAtT/5QLV/+oDVP/kA1b/5ANY/+QDWv/kACMAOP/iADz/5AEl/+IBJ//iAWL/4gGX/+QBxf/iAcz/5AHO/+IB0f/pAdf/4QHZ/+QB3v/kAeX/4gHm/+kB6P/kAff/5AH+/+sCHP/rAlj/5AJi/+ICbv/iAnT/5AJ2/+ICg//kAof/5AKI/+sCnv/kArD/6QKy/+kCtP/pAr7/5ALK/+QC1P/kAtX/6wAXADj/6wA9//MAoP/zASX/6wEn/+sBOf/zATv/8wFi/+sBf//zAZX/8wGb//MBxf/rAc7/6wHl/+sCYv/rAm7/6wJw//MCcv/zAnb/6wNU//MDVv/zA1j/8wNa//MANgBR/+8AUv/vAFT/7wBc//AAtP/vAQf/7wEJ/+8BC//vAQz/7wGe/+8Bp//vAfb/7wH3/+4B+f/wAfv/7wH8/+8B/f/vAf//7wIA/+8CAv/vAgP/7wIF/+4CCP/wAgn/7wIL/+8CDP/vAg//7wIR/+8CFv/vAh3/7wIf/+8CIP/vAiT/9AJC//ECTf/vAln/8AJd/+8CY//vAmX/7wJn/+8Cdf/wAoT/8AKK/+8CjP/vApD/7wKf//ACpf/vAqf/7wK5/+8Cu//vAr3/7wK///AC0f/vAuf/7wAiAAb/8gAL//IAWv/1AF3/9QDA//UAwv/1ATr/9QFm//IBo//1Aa3/9QIF//QCBv/1Ag//9AIh//UCJP/1Ajj/9QI6//UCY//1AnH/9QKx//UCs//1ArX/9QLR//UDVf/1A1f/9QNZ//UDW//1A3D/8gNx//IDc//yA3T/8gN1//IDfv/yA3//8gAyAFH/7gBS/+4AVP/uALT/7gEH/+4BCf/uAQv/7gEM/+4Bnv/uAaf/7gH2/+4B9wAUAfv/7gH8/+4B/f/uAf//7gIA/+4CAv/uAgP/7gIF/+0CCf/uAgr/7QIL/+4CDP/uAg3/0AIP/+4CEf/uAhb/7gId/+4CH//uAiD/7gJN/+4CXf/uAmP/7QJl/+4CZ//uAnn/7QJ7/+0Civ/uAoz/7gKO/+0CkP/uAqX/7gKn/+4Ct//tArn/7gK7/+4Cvf/uAtH/7QLn/+4ACgAG//UAC//1AWb/9QNw//UDcf/1A3P/9QN0//UDdf/1A37/9QN///UAWQBH//AASP/wAEn/8ABL//AAU//HAFX/8ACq//AAq//wAKz/8ACt//AArv/wALX/xwC2/8cAt//HALj/xwC5/8cAyv/wAMz/8ADO//AA0P/wANL/8ADW//AA2P/wANr/8ADc//AA3v/wAOD/8ADi//AA5P/wAOb/8AEQ/8cBEv/HART/xwEW//ABRv/wAZz/8AGh//ABr//HAbL/8AGz//ABvP/HAfj/8AIB/8cCBP/wAgf/8AIT//ACFP/wAhf/8AI2/8cCPP/wAj7/6wJA//ACRP/wAmv/8AJt//ACmf/wApv/8AKd//ACqf/HAqv/8AKt/8cCw//wAsT/8ALF//ACz//wAxv/8AMd//ADH//wAyH/8AMj//ADJf/wAyf/8AMp//ADL//HAzH/xwMz/8cDNf/HAzf/xwM5/8cDO//HAz3/8AM///ADQf/wA0P/xwNF//AD3P/rA97/6wPm/+kD6v/rAKEABgANAAsADQBF//AAR//AAEj/wABJ/8AASgANAEv/wABT/+IAVf/AAFoACwBdAAsAo//wAKT/8ACl//AApv/wAKf/8ACo//AAqv/AAKv/wACs/8AArf/AAK7/wAC1/+IAtv/iALf/4gC4/+IAuf/iAMAACwDCAAsAxP/wAMb/8ADI//AAyv/AAMz/wADO/8AA0P/AANL/wADW/8AA2P/AANr/wADc/8AA3v/AAOD/wADi/8AA5P/AAOb/wAEQ/+IBEv/iART/4gEW/8ABOgALAUb/wAFP//ABZgANAZz/wAGh/8ABowALAa0ACwGv/+IBsf/WAbL/wAGz/8ABtv/VAbz/4gHz//AB9//IAfj/wAH+/9cCAf/iAgT/wAIGAAsCB//AAhP/wAIU/8ACF//AAhz/1wIhAAsCNv/iAjgACwI6AAsCPP/AAj7/7AJA/8ACQgAMAkT/wAJr/8ACbf/AAnEACwKI/9cCk//wApX/8AKZ/8ACm//AAp3/wAKp/+ICq//AAq3/4gKxAAsCswALArUACwLD/8ACxP/AAsX/wALHAAsCyQALAs//wALV/9cC1//wAwP/8AMF//ADB//wAwn/8AML//ADDf/wAw//8AMR//ADE//wAxX/8AMX//ADGf/wAxv/wAMd/8ADH//AAyH/wAMj/8ADJf/AAyf/wAMp/8ADL//iAzH/4gMz/+IDNf/iAzf/4gM5/+IDO//iAz3/wAM//8ADQf/AA0P/4gNF/8ADVQALA1cACwNZAAsDWwALA3AADQNxAA0DcwANA3QADQN1AA0DfgANA38ADQPXAA0D2QAOA9r/9QPc/+wD3v/tA+b/7APq/+4D7P+/A/cADQAPAfcAFAH+ABACBf/wAgr/8AIP//ACEgAWAhwAEAJj/+YCef/wAnv/3AKIABACjv/wArf/8ALR//AC1QAQAEwAR//uAEj/7gBJ/+4AS//uAFX/7gCq/+4Aq//uAKz/7gCt/+4Arv/uAMr/7gDM/+4Azv/uAND/7gDS/+4A1v/uANj/7gDa/+4A3P/uAN7/7gDg/+4A4v/uAOT/7gDm/+4BFv/uAUb/7gGc/+4Bof/uAbL/7gGz/+4B9wASAfj/7gH+AA4CBP/uAgX/4wIH/+4CCv/jAg3/uAIP/+MCE//uAhT/7gIX/+4CHAAOAjz/7gJA/+4CRP/uAmP/ugJr/+4Cbf/uAnn/4wJ7/9kCiAAOAo7/4wKZ/+4Cm//uAp3/7gKr/+4Ct//jAsP/7gLE/+4Cxf/uAs//7gLR/+MC1QAOAxv/7gMd/+4DH//uAyH/7gMj/+4DJf/uAyf/7gMp/+4DPf/uAz//7gNB/+4DRf/uACAAWv/AAF3/wADA/8AAwv/AATr/wAGj/8ABrf/AAgX/gAIG/8ACCv/uAg//8AIh/8ACJP/bAjj/wAI6/8ACQv/cAmP/RwJx/8ACef/uAnv/7gKO/+4Csf/AArP/wAK1/8ACt//uAscABwLJ//QC0f9/A1X/wANX/8ADWf/AA1v/wAAhAFr/9ABc//AAXf/0AMD/9ADC//QBOv/0AaP/9AGt//QB9//vAfn/8AH+//MCBv/0Agj/8AIP/+4CHP/zAiH/9AI4//QCOv/0Aln/8AJx//QCdf/wAoT/8AKI//MCn//wArH/9AKz//QCtf/0Ar//8ALV//MDVf/0A1f/9ANZ//QDW//0AAoABv/WAAv/1gFm/9YDcP/WA3H/1gNz/9YDdP/WA3X/1gN+/9YDf//WABUAXP/gAfn/4AIF/3YCCP/gAgr/wgIP/9MCJP/ZAkL/2wJZ/+ACY/8eAnX/4AJ5/8ICe//tAoT/4AKO/8ICn//gArf/wgK//+ACx//wAsn/8gLR/1YADQIF/2QCCv/SAg//2QIk/9kCQv/bAmP/HgJ5/9ICe//tAo7/0gK3/9ICx//wAsn/8gLR/1YACgHv/8MCBf/PAg//1AJj/84Cev/nAn7/3wLG/9ECyP/sAtD/oALR/9EACQIF/2oCD//GAiT/2QJC/9sCY/8eAnv/7QLH//ACyf/yAtH/VgAJAA0AFABBABEAVv/iAGEAEwPc/9kD3v/ZA+b/2QPq/9kD7P+0AAoABv/XAAv/1wFm/9cDcP/XA3H/1wNz/9cDdP/XA3X/1wN+/9cDf//XABQAW//BAZb/xQG0/7QB9P/XAgX/uQIP/+kCJP+yAj7/0gJC/8gCY/+gAnv/xQKa/+QCx//MAsn/zALR/8sC0v/vA9z/5wPe/+cD5v/mA+r/6AA6AAT/xABW/78AW//RAG7/bAB+/24Aif9DAKn/rAC7/6EBlv+4AaX/fgGp/3sBsP+bAbH/eQG0/7IBtv9+Abj/fQG5/3wB1/+vAe8ADwH0/+QB9f+gAff/dAH6/4ACBf+yAg7/fQIP/7ICEP+AAhL/eQIVACgCIv99AiT/fwI+/2YCQv/aAlH/gQJT/5gCX/99AmP/swJp/6ACe/98An7/mgJ//2wCmv/mAsL/awLH/5ICyf+tAs3/ewLQAA8C0f+RAtL/8gPW//ED2f/xA9r/vAPc/7kD3v+5A+b/uQPq/7kD7P+vA/b/7QAGAbT/6gH3/+4CBf/WAg//7QJj/+wC0f/sABIB1/+uAe8AEgH1/+AB9/+tAfr/1gIO/98CEv/SAiL/4AI+/84CUf/dAlP/4gJf/+ACaf/gAnv/6QJ//9oCwv+9As3/3wLQABEAMABW/34AW/+dAG7+8QB+/vQAif6rAKn/XgC7/0sBlv9yAaX/DwGp/woBsP9BAbH/BwG0/2gBtv8PAbj/DgG5/wwB1/9jAe8ABQH0/70B9f9JAff+/gH6/xMCBf9oAg7/DgIP/2gCEP8TAhL/BwIVADACIv8OAiT/EQI+/ucCQv+sAlH/FQJT/zwCX/8OAmP/agJp/0kCe/8MAn7/PwJ//vECmv/AAsL+7wLH/zECyf9fAs3/CgLQAAUC0f8wAtL/1QACAff/aAI+/+4AFwGW/9QBqP/tAasAEQG0/+ABtv/nAbj/5QG5/+4B1wASAfT/6QIF/9cCY//XAnv/0wJ+/9YCf//FApr/5wLGAA0CyAAMAtH/1gLS//ID3P/pA97/5wPm/+cD6v/pAAECPv/xAAICBf/WA3H/iAAJAA0ADwBBAAwAVv/rAGEADgPc/+cD3v/nA+b/5wPq/+kD7P/LAB0AI/+vAFj/7wBb/98BR//u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AX4BfgAFAX8BfwAQAYIBggACAYMBgwADAYQBhAAcAYUBhQACAYYBhgAGAYcBhwARAYgBiAAHAYkBiQAFAYoBigAHAYsBiwAJAYwBjAACAY0BjgAHAZABkAAFAZIBkgALAZQBlAAMAZUBlQAQAZcBlwAPAZoBmgAHAZsBmwAQAZ4BngAWAaMBowAZAacBpwAWAa0BrQAZAa8BrwAXAbEBsQATAbwBvAAXAcMBxAAGAcYBxgAcAckBygAHAcsBywAIAcwBzQAdAc8BzwAJAdEB0QAeAdIB0gAHAdMB0wACAdUB1QADAdYB1gAcAdgB2AAGAdkB2QAPAdsB2wAHAd0B3QAJAd4B4AAHAeEB4QAFAeMB4wALAeQB5AAEAeUB5QAMAeYB5gAeAegB6AAPAekB6QAHAesB6wAHAe0B7QAdAe8B7wAdAfMB8wASAfYB9gAfAfgB+AAVAfkB+QAaAgECAQAXAgMCAwATAgQCBAAUAgYCBgAZAgcCBwATAggCCAAaAg0CDQAgAg8CDwAgAhACEAATAhMCFAAVAhYCFgAfAhwCHQAgAiECIQAZAiUCJQAdAiYCJgAgAikCKQACAjYCNgAXAjcCNwANAjgCOAAZAjkCOQANAjoCOgAZAlECUQATAlICUgAcAlMCUwAfAlQCVAAcAlgCWAAPAlkCWQAaAlwCXAAJAl4CXgAJAmACYAAJAmICYgAJAmQCZAAHAmwCbAAEAm0CbQAUAm4CbgAMAnACcAAQAnECcQAZAnICcgAQAnQCdAAPAnUCdQAaAn0CfQAWAoICggAHAoMCgwAPAoQChAAaAosCiwAHAo8CjwAHApECkQAHApICkgACApMCkwASApQClAACApUClQASApgCmAAGApkCmQAVApsCmwAVAp0CnQAVAp4CngAPAp8CnwAaAqgCqAAFAqkCqQAXAq0CrQAXAq8CrwATArACsAAeArECsQAZArICsgAeArMCswAZArQCtAAeArUCtQAZArgCuAAcArkCuQAfAr0CvQAfAr4CvgAPAr8CvwAaAtYC1gACAtcC1wASAuYC5gAHAucC5wAWAvgC+AAOAvoC+gAOAvwC/AAOAwIDAgACAwMDAwASAwQDBAACAwUDBQASAwYDBgACAwcDBwASAwgDCAACAwkDCQASAwoDCgACAwsDCwASAwwDDAACAw0DDQASAw4DDgACAw8DDwASAxADEAACAxEDEQASAxIDEgACAxMDEwASAxQDFAACAxUDFQASAxYDFgACAxcDFwASAxgDGAACAxkDGQASAxoDGgAGAxsDGwAVAxwDHAAGAx0DHQAVAx4DHgAGAx8DHwAVAyADIAAGAyEDIQAVAyIDIgAGAyMDIwAVAyQDJAAGAyUDJQAVAyYDJgAGAycDJwAVAygDKAAGAykDKQAVAyoDKgAHAywDLAAHAy4DLgAFAy8DLwAXAzADMAAFAzEDMQAXAzIDMgAFAzMDMwAXAzQDNAAFAzUDNQAXAzYDNgAFAzcDNwAXAzgDOAAFAzkDOQAXAzoDOgAFAzsDOwAXA0MDQwAXA0YDRgAIA0gDSAAIA1QDVAAQA1UDVQAZA1YDVgAQA1cDVwAZA1gDWAAQA1kDWQAZA1oDWgAQA1sDWwAZA1wDXAAFA3IDcgABA3YDdgABA3oDewABBDEEMQAEBDMENAAFAAEABgQwAAEAAAAAAAAAAAABAAAAAAAAAAAAFgAZABYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAgAAAAAAAAACAAAAAAAGgAAAAAAAAAAAAgAAAAIAAAAGwAJAAoACwAMABcADQAYAAAAAAAAAAAAAAAAAAMAAAAEAAQABAAAAAQAAAAAAAAAAAAAAAUABQAGAAUABAAAAAcAAAAOAA8AAAAcAA8AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAIAAgACAAIAAgAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgACAAIAAgAAAAIAAoACgAKAAoADQAAAAAAAwADAAMAAwADAAMAAAAEAAQABAAEAAQAAAAAAAAAAAAAAAUABgAGAAYABgAGAAAAAAAOAA4ADgAOAA8AAAAPAAIAAwACAAMAAgADAAgABAAIAAQACAAEAAgABAAAAAQAAAAAAAAABAAAAAQAAAAEAAAABAAAAAQACAAEAAgABAAIAAQACAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAABQAAAAUABQAAAAAACAAGAAgABgAIAAYACAAEAAAAAAAAAAAAAAAAABsABwAbAAcAGwAHABsABwAJAAAACQAAAAAAAAAKAA4ACgAOAAoADgAKAA4ACgAOAAoADgAMAAAADQAPAA0AGAAQABgAEAAYABAAAAAAAAAACAAEAAAADgAAAAAAAAAAAAAAAgADAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGwAHAAkAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAACAANAAAAAAACAAAAAAACAAAAGAAAAAgAAAAAAAIAAAAAAAAACAAAAAAAAAAAAA0AAAAXAAAAAAAAAA0ABAAAAAUAAAAOAAQAAAAPAAAAAAAAAAUAAAAAAAAAAAAAAA8AAAAGAAAAAAAEAAQAAAAOAAAAAAAAAAAAAAAOAAYADgAAAAAAAAAAAAAAAAAAAAkAAAAIAAAAAAAAABoAEQAAAAkAAAAAABUAAAACAAAAAAAAAAAAAAAXAAAAAAAAAAAAEQAAAAAACAAAAAAACAAJABUAAAAXAAAAEgAAAAAAAAAAAAAAAAAAAAAAAwAAAAAABQAAAAQAHAAAAAUABQAFABMABQAFAAYABQAFAAQAAAAPAAQAHAAFABQABQAFAAAAAAAFAAAABQAAAAQABAAAAAUABAAHAAAAAAAAABMABQAAAAUABQAPAAAACAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAGAAsADwALAA8ACAAEAAgAAAAIAAQACAAAAAgABAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAABcAHAAAAAAAAAAFAAAAAAAAAAAACQAAAAAABQAAAAUAAAAAAAgABAAIAAQACQAAAA0ADwANAAAAFwAcAAkAAAASABQAAAAAAAAAAAAAAAAAAAAAAAAAFwAcAAAAAAARABMAAAAFAAAABQASABQAAAAFAAAAAgADAAIAAwAAAAAAAAAEAAAABAAAAAQAFwAcAAAAAAAAAAAAAAAFAAAABQAIAAYACAAEAAgABgAAAAAAFQAPABUADwAVAA8AEgAUAAAABQAAAAUAAAAFABcAHAAAAAAAAAAEAAQABAAAAAAAAAAAABEAAAAAAAAACAAEAAAAAAAAAAAAEQATAAIAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAwAAAAMAAAAAAAAAAAAAAACAAMAAgADAAIAAwACAAMAAgADAAIAAwACAAMAAgADAAIAAwACAAMAAgADAAIAAwAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAAAAAAAAACAAGAAgABgAIAAYACAAGAAgABgAIAAYACAAGAAgABAAIAAQACAAEAAgABgAIAAQACgAOAAoADgAAAA4AAAAOAAAADgAAAA4AAAAOAA0ADwANAA8ADQAPAA0ADwAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkAGQAZAAAAAQABABYAAQABAAEAFgAAAAAAAAAWABYAAAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgAAAAIAAgAAAABAAAACgIGCBAABERGTFQAGmN5cmwASGdyZWsAdmxhdG4ApAAEAAAAAP//ABIAAAAKABQAHgAoADQAQQBLAFUAXwBpAHMAfQCHAJEAmwClAK8ABAAAAAD//wASAAEACwAVAB8AKQA1AEIATABWAGAAagB0AH4AiACSAJwApgCwAAQAAAAA//8AEgACAAwAFgAgACoANgBDAE0AVwBhAGsAdQB/AIkAkwCdAKcAsQAoAAZBWkUgAFRDUlQgAH5NT0wgAKhOQVYgANRST00gAQBUVVIgASwAAP//ABMAAwANABcAIQArADIANwBEAE4AWABiAGwAdgCAAIoAlACeAKgAsgAA//8AEgAEAA4AGAAiACwAOABFAE8AWQBjAG0AdwCBAIsAlQCfAKkAswAA//8AEgAFAA8AGQAjAC0AOQBGAFAAWgBkAG4AeACCAIwAlgCgAKoAtAAA//8AEwAGABAAGgAkAC4AOgA+AEcAUQBbAGUAbwB5AIMAjQCXAKEAqwC1AAD//wATAAcAEQAbACUALwA7AD8ASABSAFwAZgBwAHoAhACOAJgAogCsALYAAP//ABMACAASABwAJgAwADwAQABJAFMAXQBnAHEAewCFAI8AmQCjAK0AtwAA//8AEwAJABMAHQAnADEAMwA9AEoAVABeAGgAcgB8AIYAkACaAKQArgC4ALljMnNjBFhjMnNjBF5jMnNjBGRjMnNjBGpjMnNjBGpjMnNjBGpjMnNjBGpjMnNjBGpjMnNjBGpjMnNjBGpjY21wBHBjY21wBHBjY21wBHBjY21wBHBjY21wBHBjY21wBHBjY21wBHBjY21wBHBjY21wBHBjY21wBHBkbGlnBHhkbGlnBH5kbGlnBIRkbGlnBIpkbGlnBIpkbGlnBIpkbGlnBIpkbGlnBIpkbGlnBIpkbGlnBIpkbm9tBJBkbm9tBJZkbm9tBJxkbm9tBKJkbm9tBKJkbm9tBKJkbm9tBKJkbm9tBKJkbm9tBKJkbm9tBKJmcmFjBKhmcmFjBKhmcmFjBKhmcmFjBKhmcmFjBKhmcmFjBKhmcmFjBKhmcmFjBKhmcmFjBKhmcmFjBKhsaWdhBLJsaWdhBLpsbnVtBMBsbnVtBMZsbnVtBMxsbnVtBNJsbnVtBNJsbnVtBNJsbnVtBNJsbnVtBNJsbnVtBNJsbnVtBNJsb2NsBNhsb2NsBN5sb2NsBORudW1yBOpudW1yBPBudW1yBPZudW1yBPxudW1yBPxudW1yBPxudW1yBPxudW1yBPxudW1yBPxudW1yBPxvbnVtBQJvbnVtBQhvbnVtBQ5vbnVtBRRvbnVtBRRvbnVtBRRvbnVtBRRvbnVtBRRvbnVtBRRvbnVtBRRwbnVtBRpwbnVtBSBwbnVtBSZwbnVtBSxwbnVtBSxwbnVtBSxwbnVtBSxwbnVtBSxwbnVtBSxwbnVtBSxzbWNwBTJzbWNwBThzbWNwBT5zbWNwBURzbWNwBURzbWNwBURzbWNwBURzbWNwBURzbWNwBURzbWNwBURzczAxBUpzczAxBVBzczAxBVZzczAxBVxzczAxBVxzczAxBVxzczAxBVxzczAxBVxzczAxBVxzczAxBVxzczAyBWJzczAyBWhzczAyBW5zczAyBXRzczAyBXRzczAyBXRzczAyBXRzczAyBXRzczAyBXRzczAyBXRzczAzBXpzczAzBYBzczAzBYZzczAzBYxzczAzBYxzczAzBYxzczAzBYxzczAzBYxzczAzBYxzczAzBYxzczA0BZJzczA0BZhzczA0BZ5zczA0BaRzczA0BaRzczA0BaRzczA0BaRzczA0BaRzczA0BaRzczA0BaRzczA1BapzczA1BbBzczA1BbZzczA1BbxzczA1BbxzczA1BbxzczA1BbxzczA1BbxzczA1BbxzczA1BbxzczA2BcJzczA2BchzczA2Bc5zczA2BdRzczA2BdRzczA2BdRzczA2BdRzczA2BdRzczA2BdRzczA2BdRzczA3BdpzczA3BeBzczA3BeZzczA3BexzczA3BexzczA3BexzczA3BexzczA3BexzczA3BexzczA3Bex0bnVtBfJ0bnVtBfh0bnVtBf50bnVtBgR0bnVtBgR0bnVtBgR0bnVtBgR0bnVtBgR0bnVtBgR0bnVtBgQAAAABAAEAAAABAAMAAAABAAIAAAABAAAAAAACAAgACQAAAAEADgAAAAEAEAAAAAEADwAAAAEADQAAAAEAQwAAAAEARQAAAAEARAAAAAEAQgAAAAMAPwBAAEEAAAACABEAEgAAAAEAEgAAAAEAPAAAAAEAPgAAAAEAPQAAAAEAOwAAAAEACgAAAAEADAAAAAEACwAAAAEARwAAAAEASQAAAAEASAAAAAEARgAAAAEAMAAAAAEAMgAAAAEAMQAAAAEALwAAAAEAOAAAAAEAOgAAAAEAOQAAAAEANwAAAAEABQAAAAEABwAAAAEABgAAAAEABAAAAAEAFAAAAAEAFgAAAAEAFQAAAAEAEwAAAAEAGAAAAAEAGgAAAAEAGQAAAAEAFwAAAAEAHAAAAAEAHgAAAAEAHQAAAAEAGwAAAAEAIAAAAAEAIgAAAAEAIQAAAAEAHwAAAAEAJAAAAAEAJgAAAAEAJQAAAAEAIwAAAAEAKAAAAAEAKgAAAAEAKQAAAAEAJwAAAAEALAAAAAEALgAAAAEALQAAAAEAKwAAAAEANAAAAAEANgAAAAEANQAAAAEAMwBLAJgAmACYAJgEJgQmBCYEJgcUB8AOUA5QDmYOiA6IDogOiA6+DuQPEg8SDxIPEg8mDyYPJg8mDzoPOg86DzoPTg9OD04PTg9gD2APYA9gD3oPeg96D3oPvA+8D7wPvA/aD9oP2g/aD/gP+A/4D/gQKhAqECoQKhBcEFwQXBBcEI4QohDuEMwQzBDMEMwQ7hDuEO4Q7hEaAAEAAAABAAgAAgHEAN8DvQPsA+sD6gPpA+gD5wPmA+UD5APjA+ID4QPgA98D3gPdA9wD2wPaA9kD2APXA9YD9gP3BKkDvAO7BFAEUQRSBFMEVARVBFcEWARZBFoEWwRcBF0EXgRfBE4EYARhBGIEYwRkBGUEZgRtBG4EbwRwBEwEcQRyBHMEdAR1BHYEdwR4BE0EeQR6BHsEfAR9BH4EfwSABIEEggSDBIQEhQSGBIcEiASJBIoEiwSMBI0EjgSPBJAEkQSSBJMERASUBJUElgSXBJgEmQSaBJ0EnARPBJ4EnwSgBKEEogSjBKQEpQSmBKcEqAP+BFYEmwSqBKsErAStBK4ErwSwBLEEsgO6A7kEswS0BLUDuAS2BLcDtwS4A7YEuQPGBLoD0QS7BLwD0gS9A9MD1AS+BL8EwAP5BMED+ATCBMMExATFA/8EAAQBBMYExwQCBMgEAwTJBMoEBATLBAUEBgQHBMwECAQJBM0EzgTPBNAE0QTSBNMECgTcBNQECwQMBA0EDgQPBBAEEQQSBBMEFAQ4BBUEFgTVBBcEGAQZBNYEGgTXBNgEGwQcBB0EHgQfBCAE2QQhBCIE2gQjBNsEJAQlBCcEJgABAN8ACAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4AZgBoAIMAhACFAIYAhwCIAIoAiwCMAI0AjgCPAJAAkQCSAJMAlACVAJYAlwCYAJkAnACdAJ4AnwCgAKIAwwDFAMcAyQDLAM0AzwDRANMA1QDXANkA2wDdAN8A4QDjAOUA5wDrAO0A7wDxAPMA9wD5APwA/gEAAQIBBgEIAQoBDwERARMBFQEXARkBGwEdAR8BIQEjASUBJwEpASsBLQEvATEBMwE1ATcBOQE7ATwBPgFAAU4BYgF5AXsBfAF9AX4BfwGAAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY8BkAGRAZIBkwGUAZUBlgGXAZgBmQGaAZsBxAHFAcYBxwHIAckBygHLAcwBzQHOAc8B0QHSAdMB1AHVAdYB1wHYAdkB2gHbAdwB3QHeAd8B4AHhAeIB4wHkAeUB5gHnAegB6QHqAesB7AHtAe4B7wHwAfEB8gJSAlQCWAJaAlwCXgJiAmQCagJsAnACcgJ0AnYCegJ8An4CgAKaAqICpAKqArADhwOOA5MDlgABAAAAAQAIAAIBdAC3A+wD6wPqA+kD6APnA+YD5QPkA+MD4gPhA+AD3wPeA90D3APbA9oD2QPYA9cD1gP2A/cEqQRQBFEEUgRTBFQEVQRXBFgEWQRaBFsEXARdBF4EXwROBGAEYQRiBGMEZARlBGYEbQRuBG8EcASmBHEEcgRzBHQEdQR2BHcEeARNBHkEegR7BHwEfQR+BH8EgASBBIIEgwSEBIUEhgSHBIgEiQSKBIsEjASNBI4EjwSQBJEEkgSTBEQElASVBJYElwSYBJkEmgSdBJwETwSeBJ8EoAShBKIEowSkBKUEpwSoA/4EVgSbBMgEAwTJBMoEBATLBAUEBgQHBMwECAQJBM0EzgTPBNAE0QTSBNMECgTcBNQECwQMBA0EDgQPBBAEEQQSBBMEFATAA/kEwQP4BMIEwwTEBMUD/wQABAEExgTHBAIEOAQVBBYE1QQXBBgEGQTWBBoE1wTYBBsEHAQdBB4EHwQgBNkEIQQiBNoEIwTbAAEAtwBFAEYARwBIAEkASgBLAEwATQBOAE8AUABRAFIAUwBUAFUAVgBXAFgAWQBaAFsAXABdAF4AowCkAKUApgCnAKgAqgCrAKwArQCuAK8AsACxALIAswC0ALUAtgC3ALgAuQC8AL0AvgC/AMAAwgDEAMYAyADKAMwAzgDQANIA1ADWANgA2gDcAN4A4ADiAOQA5gDoAOwA7gDwAPIA9AD4APoA/QD/AQEBAwEHAQkBCwEQARIBFAEWARgBGgEcAR4BIAEiASQBJgEoASoBLAEuATABMgE0ATYBOAE6AT0BPwFBAU8BYwHzAfQB9QH2AfcB+AH5AfoB+wH8Af0B/gH/AgACAQICAgMCBAIFAgYCBwIIAgkCCgILAgwCDQIOAg8CEAIRAhICFAIVAhYCFwIYAhkCGgIbAhwCHQIeAh8CIQIiAlMCVQJZAlsCXQJfAmMCZQJrAm0CcQJzAnUCdwJ7An0CfwKBApsCowKlAqsCsQAGAAAABgASACoAQgBaAHIAigADAAAAAQASAAEAkAABAAAASgABAAEATQADAAAAAQASAAEAeAABAAAASgABAAEATgADAAAAAQASAAEAYAABAAAASgABAAEA8gADAAAAAQASAAEASAABAAAASgABAAECGQADAAAAAQASAAEAMAABAAAASgABAAECGwADAAAAAQASAAEAGAABAAAASgABAAEDLQACAAEBcQF1AAAABAAAAAEACAABBh4ANgByAKQArgC4AMoA/AEOARgBSgFkAX4BkAG6AewB9gIYAjICRAJ2AogCogLMAt4DEAMaAyQDNgNoA3IDfAOGA6ADugPMA/YEKAQyBFQEbgSABLIExATeBQgFGgUkBS4FOAVCBWwFlgXABeoGFAAGAA4AFAAaACAAJgAsAIMAAgFxAIQAAgFyAIYAAgFzAwQAAgF0AVQAAgF1AwIAAgF2AAEABALYAAIBdgABAAQAyQACAXIAAgAGAAwC2gACAXYC3AACA6sABgAOABQAGgAgACYALACLAAIBcQCMAAIBcgMeAAIBcwMcAAIBdAFWAAIBdQMaAAIBdgACAAYADAFKAAIBcgDlAAIDqwABAAQC3gACAXYABgAOABQAGgAgACYALACPAAIBcQCQAAIBcgDrAAIBcwMqAAIBdAFYAAIBdQMsAAIBdgADAAgADgAUAuAAAgFyAuIAAgF2APkAAgOrAAMACAAOABQA/AACAXIC5AACAXYA/gACA6sAAgAGAAwC5gACAXIC6AACAXYABQAMABIAGAAeACQBTAACAXEBBgACAXIAlAACAXMC6gACAXYBCAACA6sABgAOABQAGgAgACYALACVAAIBcQCWAAIBcgCYAAIBcwMwAAIBdAFaAAIBdQMuAAIBdgABAAQC7AACAXIABAAKABAAFgAcARcAAgFyAVwAAgF1Au4AAgF2ARkAAgOrAAMACAAOABQBHQACAXIC8AACAXYBYAACA6sAAgAGAAwC8gACAXYBYgACA6sABgAOABQAGgAgACYALACcAAIBcQCdAAIBcgErAAIBcwNIAAIBdAFeAAIBdQNGAAIBdgACAAYADAL0AAIBcwL2AAIBdgADAAgADgAUAvgAAgFxAvoAAgFyAv4AAgF2AAUADAASABgAHgAkA1QAAgFxAKAAAgFyA1oAAgFzA1gAAgF0A1YAAgF2AAIABgAMATwAAgFyAwAAAgF2AAYADgAUABoAIAAmACwAowACAXEApAACAXIApgACAXMDBQACAXQBVQACAXUDAwACAXYAAQAEAtkAAgF2AAEABADKAAIBcgACAAYADALbAAIBdgLdAAIDqwAGAA4AFAAaACAAJgAsAKsAAgFxAKwAAgFyAx8AAgFzAx0AAgF0AVcAAgF1AxsAAgF2AAEABAFLAAIBcgABAAQC3wACAXYAAQAEAy0AAgF2AAMACAAOABQC4QACAXIC4wACAXYA+gACA6sAAwAIAA4AFAD9AAIBcgLlAAIBdgD/AAIDqwACAAYADALnAAIBcgLpAAIBdgAFAAwAEgAYAB4AJAFNAAIBcQEHAAIBcgC0AAIBcwLrAAIBdgEJAAIDqwAGAA4AFAAaACAAJgAsALUAAgFxALYAAgFyALgAAgFzAzEAAgF0AVsAAgF1Ay8AAgF2AAEABALtAAIBcgAEAAoAEAAWABwBGAACAXIBXQACAXUC7wACAXYBGgACA6sAAwAIAA4AFAEeAAIBcgLxAAIBdgFhAAIDqwACAAYADALzAAIBdgFjAAIDqwAGAA4AFAAaACAAJgAsALwAAgFxAL0AAgFyASwAAgFzA0kAAgF0AV8AAgF1A0cAAgF2AAIABgAMAvUAAgFzAvcAAgF2AAMACAAOABQC+QACAXEC+wACAXIC/wACAXYABQAMABIAGAAeACQDVQACAXEAwAACAXIDWwACAXMDWQACAXQDVwACAXYAAgAGAAwBPQACAXIDAQACAXYAAQAEAVAAAgFyAAEABAFSAAIBcgABAAQBUQACAXIAAQAEAVMAAgFyAAUADAASABgAHgAkAK8AAgFxALAAAgFyAOwAAgFzAysAAgF0AVkAAgF1AAUADAASABgAHgAkAz4AAgFxAzwAAgFyA0IAAgFzA0AAAgF0A0QAAgF2AAUADAASABgAHgAkAz8AAgFxAz0AAgFyA0MAAgFzA0EAAgF0A0UAAgF2AAUADAASABgAHgAkA0wAAgFxA0oAAgFyA1AAAgFzA04AAgF0A1IAAgF2AAUADAASABgAHgAkA00AAgFxA0sAAgFyA1EAAgFzA08AAgF0A1MAAgF2AAEABAHBAAIBcgACABEAJQApAAAAKwAtAAUALwA0AAgANgA7AA4APQA+ABQARQBJABYASwBNABsATwBUAB4AVgBbACQAXQBeACoAiQCJACwAmwCbAC0AqQCpAC4AuwC7AC8A9AD0ADABRQFIADEBwAHAADUAAQAAAAEACAABAAYAPwABAAIBIQEiAAEAAAABAAgAAgAOAAQE3QTeBN8E4AABAAQAxwDIANsA3AAEAAAAAQAIAAEAJgACAAoAHAACAAYADAOsAAIASgOxAAIAWAABAAQDsgACAFgAAQACAEoAVwAEAAAAAQAIAAEARAACAAoAFAABAAQDrQACAE0AAQAEA68AAgBNAAQAAAABAAgAAQAeAAIACgAUAAEABAOuAAIAUAABAAQDsAACAFAAAQACAEoDrAABAAAAAQAIAAEABgN5AAEAAQBLAAEAAAABAAgAAQAGAiIAAQABAaEAAQAAAAEACAABAAYDjAABAAEANgABAAAAAQAIAAIAHAACA8EDwAABAAAAAQAIAAIACgACA78DvgABAAIALwBPAAEAAAABAAgAAgAeAAwEMQQzBDIENAQ1BCgEKQQqA/sELAQtBC4AAQAMACcAKAArADMANQBGAEcASABLAFMAVABVAAEAAAABAAgAAgAMAAMELwQwBDAAAQADAEkASwP7AAEAAAABAAgAAgBmAAgERgQ2BDcEOQQ6BEIEQwRFAAEAAAABAAgAAgAWAAgAGwAVABQAHQAZABgAFwAWAAEACAP6BCsEZwRoBGkEagRrBGwAAQAAAAEACAACABYACARnBCsEbARrBGoEaQP6BGgAAQAIABQAFQAWABcAGAAZABsAHQABAAAAAQAIAAIAFgAIABUAFgAXABgAGQAbAB0AFAABAAgENgQ3BDkEOgRCBEMERQRGAAEAAAABAAgAAQAGA3AAAQABABMABgAAAAEACAADAAEAEgABAGYAAAABAAAASgACAAIDgwODAAADxwPQAAEAAQAAAAEACAACADwACgPQA88DzgPNA8wDywPKA8kDyAPHAAEAAAABAAgAAgAaAAoEOwB8AHUAdgQ8BD0EPgQ/BEAEQQACAAEAFAAdAAAAAQAAAAEACAACACYAEAPQA88DzgPNA8wDywPKA8kDyAPHBEkERwRKBEsESAThAAEAEAAUABUAFgAXABgAGQAaABsAHAAdAE0ATgDyAhkCGwMt\",\n  \"Roboto-Regular.ttf\": \"AAEAAAASAQAABAAgR0RFRtRX1FkAAg/sAAACREdQT1NKcuCzAAISMAAAUiRHU1VCw4aZEQACZFQAABfoT1MvMqCnsaYAAAGoAAAAYGNtYXBAmkl2AAAafAAAEshjdnQgJEEG5QAAL9wAAABMZnBnbWf0XKsAAC1EAAABvGdhc3AACAATAAIP4AAAAAxnbHlmHN2bBQAAOfAAAdM2aGRteDc4ERcAABWQAAAE7GhlYWT4RqsOAAABLAAAADZoaGVhCroKggAAAWQAAAAkaG10eOiEiIgAAAIIAAATiGxvY2HgyGepAAAwKAAACcZtYXhwBxIC+QAAAYgAAAAgbmFtZTVTY1kAAg0oAAACmHBvc3T/bQBkAAIPwAAAACBwcmVwdKCP7AAALwAAAADbAAEAAAACAACEKlnoXw889QAbCAAAAAAAxPARLgAAAADQ206a+hv91QkwCHMAAAAJAAIAAAAAAAAAAQAAB2z+DAAACUn6G/5KCTAAAQAAAAAAAAAAAAAAAAAABOIAAQAABOIAjwAWAFQABQABAAAAAAAOAAACAAIUAAYAAQADBIUBkAAFAAAFmgUzAAABHwWaBTMAAAPRAGYCAAAAAgAAAAAAAAAAAOAACv9QACF/AAAAIQAAAABHT09HAEAAAP/9BgD+AABmB5oCACAAAZ8AAAAABDoFsAAgACAAAgOMAGQAAAAAAAAAAAH7AAAB+wAAAg8AoAKPAIgE7QB3BH4AbgXcAGkE+QBlAWUAZwK8AIUCyAAmA3IAHASJAE4BkgAdAjUAJQIbAJADTAASBH4AcwR+AKoEfgBdBH4AXgR+ADUEfgCaBH4AhAR+AE0EfgBwBH4AZAHwAIYBsQApBBEASARkAJgELgCGA8cASwcvAGoFOAAcBPsAqQU1AHcFPwCpBIwAqQRsAKkFcwB6BbQAqQItALcEagA1BQQAqQROAKkG/ACpBbQAqQWAAHYFDACpBYAAbQTtAKgEvwBQBMYAMQUwAIwFFwAcBxkAPQUEADkEzgAPBMoAVgIfAJIDSAAoAh8ACQNYAEADnAAEAnkAOQRaAG0EfQCMBDAAXASDAF8EPQBdAscAPAR9AGAEaACMAfEAjQHp/78EDgCNAfEAnAcDAIsEagCMBJAAWwR9AIwEjABfArUAjAQgAF8CnQAJBGkAiAPgACEGAwArA/cAKQPJABYD9wBYArUAQAHzAK8CtQATBXEAgwHzAIsEYABpBKYAWwW0AGkE2AAfAesAkwToAFoDWABmBkkAWwOTAJMDwQBmBG4AfwZKAFoDqgB4Av0AggRGAGEC7wBCAu8APgKCAHsEiACaA+kAQwIWAJMB+wB0Au8AegOjAHoDwABmBdwAVQY1AFAGOQBvA8kARAd6//IERABZBYAAdgS6AKYEwgCLBsEATgSwAH4EkQBHBIgAWwScAJUFmgAdAfoAmwRzAJoETwAiAikAIgWLAKIEiACRB6EAaAdEAGEB/ACgBYcAXQK5/+QFfgBlBJIAWwWQAIwE8wCIAgP/tAQ3AGIDxACpA40AjAOrAHgDagCBAfEAjQKtAHkCKgAyA8YAewL8AF4CWgB+AAD8pwAA/W8AAPyLAAD9XgAA/CcB7/04Ag0AtwQLAHECFwCTBHMAsQWkAB8FcQBnBT4AMgSRAHgFtQCyBJEARQW7AE0FiQBaBVIAcQSFAGQEvQCgBAIALgSIAGAEUABjBCUAbQSIAJEEjgB6ApcAwwRuACUD7ABlBMQAKQSIAJEETQBlBIgAYAQsAFEEXQCPBaMAVwWaAF8GlwB6BKEAeQRC/9oGSABKBf8AKgVkAHsIkQAxCKQAsQaCAD4FtACwBQsAogYEADIHQwAbBL8AUAW0ALEFqQAvBQcATQYsAFMF2QCvBXoAlgeHALAHwACwBhIAEAbrALIFBQCjBWQAkwcnALcFGABZBGwAYQSSAJ0DWwCaBNQALgYgABUEEABYBJ4AnARSAJwEoAAsBe8AnQSdAJwEngCcA9gAKAXNAGQEvQCcBFkAZwZ4AJwGngCRBPcAHgY2AJ0EWACdBE0AZAaHAJ0EZAAvBGj/6ARNAGcGyQAnBuQAnASJ//0EngCcBwgAnAYrAIEEVv/cBysAtwX4AJkE0gAoBEYADwcLAMkGCwC8BtEAkwXhAJYJBAC2B9EAmwQjAFAD2wBMBXEAZwSLAFsFCgAWBAMALgVxAGcEiABbBwEAnAYkAH4HCACcBisAgQUyAHUERwBkBP0AdAAA/GcAAPxxAAD9ZgAA/aQAAPobAAD6LARW/9wFGwCoBIkAjARjAKIDkACRBNsAsQQFAJEFCQCjBH4AmgaMAEQFgwA+B88AqAW0AJEIMQCwBvQAkQXuAHEE0wBtBywANAVcAB8FbwCWBGoAgwVwAIoGLwA/BL3/3gUJAKMEWgCaBbIAsQSIAJEFhwBdBKgAaASoAGkEtwA6A0kAOwT2AFcGlABZBuQAZAZWADYFKwAxBEkAUgQHAHkHwQBEBnUAPwf7AKkGoQCQBPYAdgQdAGUFrQAjBSAARgVkAJYDIABvBBQAAAgpAAAEFAAACCkAAAK5AAACCgAAAVwAAAR/AAACMAAAAaIAAADRAAAAAAAAAjQAJQI0ACUFQACiBj8AkAOmAA0BmQBgAZkAMAGXACQBmQBPAtQAaALbADwCwQAkBGkARgSPAFcCsgCKA8QAlAVaAJQA9gAmB6oARAJmAGwCZgBZA6MAOwLvADYDYAB6BKYAWwZVAB8GkACnCHYAqAdjADkGKwCMBH4AXwXaAB8EIgAqBHQAIAVIAF0FTwAfBecAegPOAGgIOgCiBQEAZwUXAJgGJgBUBtcAZAbPAGMGagBZBI8AagWOAKkErwBFBJIAqATFAD8IOgBiAgz/sASCAGUEZACYBBEAPgQvAIUECAArAkwAtQKPAG4CAwBcBPMAPARuAB8EiwA8BtQAPAbUADwE7gA8BpsAXwAAAAAIMwBbCDUAXAQgADsEngBaAfz/tgGRAGcDpACDA54AgQOfAIED9ABpBA4AaQPz/14D7wBuA6QAgQH9AJ8EhQATBFAAigR8AGAEgACKA+YAigPLAIoErABjBOMAigHoAJcDzwArBFQAigO0AIoGAgCKBOMAigS7AGAEXACKBLsAWQRKAIoEIABDBCYAKAR8AHQEZwAUBhUAMQRUACYEKwANBCMARwLvAFAC7wB6Au8AQgLvAD4C7wA2Au8AWwLvAFYC7wA6Au8ATwLvAEkDlgCPArUAngQ6AB4EwwBkBUwAsQUkALIEEwCSBT0AsgQPAJIEIABDBDMAMAQ8ABYDrwCKBGcAFAS7AGAEZwAUA4kAPgTOAIoD7wA/BWcAYAUXAGAE8gB1BXIAJgR8AGAHQQAnB08AigV0ACgEzQCKBFkAigUkAC4GCwAfBD8ARwTsAIoETgCLBMEAJwQfACIFKACKBGoAPQZRAIoGrACKBR0ACAXxAIoETgCKBHsASwZ2AIoEhwBQBBEACwZHAB8EeQCLBQkAiwU3ACMFwgBgBF8ADQSoACYGYQAmBGoAPQRqAIoFwwACBMoAXgQ/AEcEuwBgBDMAMAPjAEIIIgCKBKsAKAR9AIwEMgBcBJMAWwSMAFsDeQBXBI0AjAScAFsEPQBdBH0AYAWBAH4FrgB+BZMAsgXgAH4F4wB+A9UAoASCAIMDrwCKBFgADwTPAD4C7wBQAu8ANgLvAFsC7wBWAu8AOgLvAE8C7wBJBGsAZQQuAEoGpABgBLkAggUAAHgCBv+0AgT/tAH7AJsB+//6AfsAmwH7AIYEUACKAfsAAAI1ACUFXQAlBV0AJQSGAAAExgAxAp3/9AU4ABwFOAAcBTgAHAU4ABwFOAAcBTgAHAU4ABwFNQB3BIwAqQSMAKkEjACpBIwAqQIt/+ACLQCwAi3/6QIt/9YFtACpBYAAdgWAAHYFgAB2BYAAdgWAAHYFMACMBTAAjAUwAIwFMACMBM4ADwRaAG0EWgBtBFoAbQRaAG0EWgBtBFoAbQRaAG0EMABcBD0AXQQ9AF0EPQBdBD0AXQH6/8YB+gCWAfr/zwH6/7wEagCMBJAAWwSQAFsEkABbBJAAWwSQAFsEaQCIBGkAiARpAIgEaQCIA8kAFgPJABYFOAAcBFoAbQU4ABwEWgBtBTgAHARaAG0FNQB3BDAAXAU1AHcEMABcBTUAdwQwAFwFNQB3BDAAXAU/AKkFGQBfBIwAqQQ9AF0EjACpBD0AXQSMAKkEPQBdBIwAqQQ9AF0EjACpBD0AXQVzAHoEfQBgBXMAegR9AGAFcwB6BH0AYAVzAHoEfQBgBbQAqQRoAIwCLf+3Afr/nQIt/7YB+v+cAi3/7AH6/9ICLQAYAfH/+wItAKoGlwC3A9oAjQRqADUCA/+0BQQAqQQOAI0ETgChAfEAkwROAKkB8QBXBE4AqQKHAJwETgCpAs0AnAW0AKkEagCMBbQAqQRqAIwFtACpBGoAjARq/7wFgAB2BJAAWwWAAHYEkABbBYAAdgSQAFsE7QCoArUAjATtAKgCtQBTBO0AqAK1AGMEvwBQBCAAXwS/AFAEIABfBL8AUAQgAF8EvwBQBCAAXwS/AFAEIABfBMYAMQKdAAkExgAxAp0ACQTGADECxQAJBTAAjARpAIgFMACMBGkAiAUwAIwEaQCIBTAAjARpAIgFMACMBGkAiAUwAIwEaQCIBxkAPQYDACsEzgAPA8kAFgTOAA8EygBWA/cAWATKAFYD9wBYBMoAVgP3AFgHev/yBsEATgWAAHYEiABbBID/vgSA/74EJgAoBIUAEwSFABMEhQATBIUAEwSFABMEhQATBIUAEwR8AGAD5gCKA+YAigPmAIoD5gCKAej/vgHoAI4B6P/HAej/tATjAIoEuwBgBLsAYAS7AGAEuwBgBLsAYAR8AHQEfAB0BHwAdAR8AHQEKwANBIUAEwSFABMEhQATBHwAYAR8AGAEfABgBHwAYASAAIoD5gCKA+YAigPmAIoD5gCKA+YAigSsAGMErABjBKwAYwSsAGME4wCKAej/lQHo/5QB6P/KAegABgHoAIkDzwArBFQAigO0AIIDtACKA7QAigO0AIoE4wCKBOMAigTjAIoEuwBgBLsAYAS7AGAESgCKBEoAigRKAIoEIABDBCAAQwQgAEMEIABDBCYAKAQmACgEJgAoBHwAdAR8AHQEfAB0BHwAdAR8AHQEfAB0BhUAMQQrAA0EKwANBCMARwQjAEcEIwBHBTgAHATw//AGGP/+ApEABAWU//oFMv94BWb//QKX/5sFOAAcBPsAqQSMAKkEygBWBbQAqQItALcFBACpBvwAqQW0AKkFgAB2BQwAqQTGADEEzgAPBQQAOQIt/9YEzgAPBIUAZARQAGMEiACRApcAwwRdAI8EcwCaBJAAWwSIAJoD4AAhA/cAKQKX/+YEXQCPBJAAWwRdAI8GlwB6BIwAqQRzALEEvwBQAi0AtwIt/9YEagA1BSQAsgUEAKkFBwBNBTgAHAT7AKkEcwCxBIwAqQW0ALEG/ACpBbQAqQWAAHYFtQCyBQwAqQU1AHcExgAxBQQAOQRaAG0EPQBdBJ4AnASQAFsEfQCMBDAAXAPJABYD9wApBD0AXQNbAJoEIABfAfEAjQH6/7wB6f+/BFIAnAPJABYHGQA9BgMAKwcZAD0GAwArBxkAPQYDACsEzgAPA8kAFgFlAGcCjwCIBB4AoAID/7QBmQAwBvwAqQcDAIsFOAAcBFoAbQSMAKkFtACxBD0AXQSeAJwFiQBaBZoAXwUKABYEA//7CFkAWwlJAHYEvwBQBBAAWAU1AHcEMABcBM4ADwQCAC4CLQC3B0MAGwYgABUCLQC3BTgAHARaAG0FOAAcBFoAbQd6//IGwQBOBIwAqQQ9AF0FhwBdBDcAYgQ3AGIHQwAbBiAAFQS/AFAEEABYBbQAsQSeAJwFtACxBJ4AnAWAAHYEkABbBXEAZwSLAFsFcQBnBIsAWwVkAJMETQBkBQcATQPJABYFBwBNA8kAFgUHAE0DyQAWBXoAlgRZAGcG6wCyBjYAnQUEADkD9wApBIMAXwWpAC8EoAAsBTgAHARaAG0FOAAcBFoAbQU4ABwEWgBtBTgAHARa/8oFOAAcBFoAbQU4ABwEWgBtBTgAHARaAG0FOAAcBFoAbQU4ABwEWgBtBTgAHARaAG0FOAAcBFoAbQU4ABwEWgBtBIwAqQQ9AF0EjACpBD0AXQSMAKkEPQBdBIwAqQQ9AF0EjP/wBD3/ugSMAKkEPQBdBIwAqQQ9AF0EjACpBD0AXQItALcB+gCbAi0AowHxAIUFgAB2BJAAWwWAAHYEkABbBYAAdgSQAFsFgABHBJD/xAWAAHYEkABbBYAAdgSQAFsFgAB2BJAAWwV+AGUEkgBbBX4AZQSSAFsFfgBlBJIAWwV+AGUEkgBbBX4AZQSSAFsFMACMBGkAiAUwAIwEaQCIBZAAjATzAIgFkACMBPMAiAWQAIwE8wCIBZAAjATzAIgFkACMBPMAiATOAA8DyQAWBM4ADwPJABYEzgAPA8kAFgShAF8EoQBfBSQAsgRSAJwFtACpBJ0AnATGADED2AAoBQQAOQP3ACkFegCWBFkAZwV6AJYEWQBnBHMAsQNbAJoHQwAbBiAAFQYvAD8Evf/eBGgAjAUF/9QFBf/UBHMAAwNb//wFOAALBCf/0wW0ALEEngCcBbQAqQSdAJwG/ACpBe8AnQWpAC8EoAAsBM4ADwQCAC4FBAA5A/cAKQRQAGMEbAASBj8AkAR+AF0EfgBeBH4ANQR+AJoEkgBkBKYAhwVzAHoEfQBgBbQAqQRqAIwFOAAcBFoAOQSMAF8EPQApAi3/CgH6/vAFgAB2BJAAMwTtAFUCtf+LBTAAjARpACsEpv86BPsAqQR9AIwFPwCpBIMAXwU/AKkEgwBfBbQAqQRoAIwFBACpBA4AjQUEAKkEDgCNBE4AqQHxAIYG/ACpBwMAiwW0AKkEagCMBQwAqQR9AIwE7QCoArUAggS/AFAEIABfBMYAMQKdAAkFFwAcA+AAIQUXABwD4AAhBxkAPQYDACsEygBWA/cAWAXG/ngEhQATBCL/nwUf/7wCJP/ABMX/3wRn/1cE/P/4BIUAEwRQAIoD5gCKBCMARwTjAIoB6ACXBFQAigYCAIoEuwBgBFwAigQmACgEKwANBFQAJgHo/7QEKwANA+YAigOvAIoEIABDAegAlwHo/7QDzwArBFQAigQfACIEhQATBFAAigOvAIoD5gCKBOwAigYCAIoE4wCKBLsAYATOAIoEXACKBHwAYAQmACgEVAAmBD8ARwTjAIoEfABgBCsADQXDAAIE7ACKBB8AIgVnAGAFOAAcBFoAbQSMAKkEPQBdAAAAAQAABOQJCgQAAAICAgMGBQcGAgMDBAUCAgIEBQUFBQUFBQUFBQICBQUFBAgGBgYGBQUGBgIFBgUIBgYGBgYFBQYGCAYFBQIEAgQEAwUFBQUFAwUFAgIFAggFBQUFAwUDBQQHBAQEAwIDBgIFBQYFAgYEBwQEBQcEAwUDAwMFBAICAwQEBwcHBAgFBgUFCAUFBQUGAgUFAgYFCQgCBgMGBQYGAgUEBAQEAgMCBAMDAAAAAAACAgUCBQYGBgUGBQYGBgUFBQUFBQUFAwUEBQUFBQUFBgYHBQUHBwYKCgcGBgcIBQYGBgcHBggJBwgGBggGBQUEBQcFBQUFBwUFBAcFBQcHBgcFBQcFBQUICAUFCAcFCAcFBQgHCAcKCQUEBgUGBQYFCAcIBwYFBgAAAAAAAAUGBQUEBQUGBQcGCQYJCAcFCAYGBQYHBQYFBgUGBQUFBAYHCAcGBQUJBwkHBgUGBgYEBQkFCQMCAgUCAgEAAgIGBwQCAgICAwMDBQUDBAYBCQMDBAMEBQcHCggHBQcFBQYGBwQJBgYHCAgHBQYFBQUJAgUFBQUFAwMCBgUFCAgGBwAJCQUFAgIEBAQEBQQEBAIFBQUFBAQFBgIEBQQHBgUFBQUFBQUFBwUFBQMDAwMDAwMDAwMEAwUFBgYFBgUFBQUEBQUFBAUEBgYGBgUICAYFBQYHBQYFBQUGBQcIBgcFBQcFBQcFBgYGBQUHBQUGBQUFBQQJBQUFBQUEBQUFBQYGBgcHBAUEBQUDAwMDAwMDBQUHBQYCAgICAgIFAgIGBgUFAwYGBgYGBgYGBQUFBQICAgIGBgYGBgYGBgYGBQUFBQUFBQUFBQUFBQICAgIFBQUFBQUFBQUFBAQGBQYFBgUGBQYFBgUGBQYGBQUFBQUFBQUFBQYFBgUGBQYFBgUCAgICAgICAgIHBAUCBgUFAgUCBQMFAwYFBgUGBQUGBQYFBgUGAwYDBgMFBQUFBQUFBQUFBQMFAwUDBgUGBQYFBgUGBQYFCAcFBAUFBAUEBQQICAYFBQUFBQUF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sRCxUrG2sc2x5LH7shKyK7JEslCyXLJzsoqyobK6stGy6LL/sxizL7NGs12zdLOLs6Szu7PSs+m0ArQZtDC0R7RdtHO0jLSltLG0vbTUtOu1AbUatTC1RrVdtXa1jLWjtbq10LXmtf+2FrYttkO2XLZztou2ora4ts+25rdJt9+39rgNuCS4OrhRuGi4f7iVuKy43bj0uQq5Ibk4uU+5ZrnOulK6abp/upa6rLrDutq68bsIuxS7K7tCu1S7a7uCu5m7sLvHu9676bv0vAu8F7wjvDq8UbxdvGm8gLyXvKO8r7zEvPm9Bb0RvSi9P71LvVe9br2EvZS9q73Bvdi9774IviG+OL5Pvlu+Z75+vpS+q77Cvtm+7777vwe/E78fvza/TL9Yv2S/cL98v5O/n7+2v8y/47/5wBDAJ8BAwFnAcsCLwOjBTsFlwXzBk8GpwcLB2cHwwgfCHsI1wkvCYsJ5wpDCp8LKwvLDBcMcwzPDScNfw3jDkcOdw6nDwMPXw+3EBcQbxDHESMRhxHjEj8SmxL3E1MTtxQTFG8UxxUrFYcV3xY7F8cYIxh7GNcZMxmLGeMaOxqXHDsckxzrHUcdox3THi8eix7nH0Mfbx/HICMgUyCrINshLyFfIbsh6yJHIqMi/yNjI78j7yRHJKMk+yUrJYMlsyYLJjsmkybrJ0cnqygPKX8p2yozKpMq7ytLK6Mrzyv/LC8sXyyPLL8s7y1fLX8tny2/Ld8t/y4fLj8uXy5/Lp8uvy7fLv8vHy+DL+cwQzCfMPsxUzG/Md8x/zIfMj8yXzK/Mx8zezPXNDM0lzTzNp82vzcjN0M3Yze/OBs4OzhbOHs4mzj3ORc5NzlXOXc5lzm3Odc59zoXOjc6kzqzOtM8Hzw/PF88wz0fPT89Xz3DPeM+Pz6XPvM/Tz+rQAdAa0DPQStBh0GnQcdB90JTQnNCz0MrQ1tDi0PnRENEn0T7RRtFO0WfRgNGM0ZjRpNGw0bzRyNHQ0djR4NH30g7SFtIt0kTSW9J00nzShNKb0rLSy9LT0uzTBdMe0zfTT9Nm03zTldOu08fT4NPo0/DUCdQi1DvUU9Rq1IDUmdSx1MrU49T81RTVMdVO1VrVZtVu1XrVhtWS1Z7VtdXM1eXV/dYW1i7WR9Zf1njWkNar1sXW3tb31xDXKddC11vXdNeN16jXw9fP19vX8tgJ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AAUAJABIAAEA3gAIACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgBlAGcAkgCwALEAsgCzALQAtQC2ALcAuAC5ANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoASwBMAEyATgBOgE8AT4BPwFFAUYBfwGFAYoBjQJHAkgCSgJMAk0CTgJPAlACUQJSAlMCVAJVAlYCVwJYAlkCWgJbAlwCXQJeAl8CYAJhAmICYwJkAmUCZgKDAoUChwKJAosCjQKPApECkwKVApcCmQKbAp0CnwKhAqMCpQKnAqkCqwKtAq8CsgK0ArYCuAK6ArwCvgLAAsICxQLHAskCywLNAs8C0QLTAtUC2QLbAt0C3wLhAuMC5QLnAukC6wLtAu8C8QLyAvQC9gNTA1QDVQNWA1cDWANZA1sDXANdA14DXwNgA2EDYgNkA2UDZgNnA2gDaQNqA3oDewN8A30DfgN/A4ADgQOCA4MDhAOFA4YDhwOIA4kDigOLA4wDjQOOA48DuwO9A78D1APaA+AESQRLBE8EVwRZBF4EagACAAAABAAOD84V8jViAAEDVAAEAAABpQrSCtIGggtwCoAK/g+aDAAGiA7uDu4MRg6gCiIO7g7uD5oKigaSDGYMRgrYCqwNUg8QCl4L4gsQDBYGmA22DbYNtgwgCxAKUAxMDbAMTAsQBqYN5gtwD5oLcAasBrIGvAbCBsgMTAbOBtgNtgb+BxQHKgcwB0YHTAdSB4QHigeQDcANwAe+Du4H4AgCDVIIMA7uDu4LJg7uDu4IRg3ADcAIeAiCCIwIpg1ICLgNsAjSCOgLEAkyCUwJaAloCxAJYgloCWgJaAtwDCAK2AxMCxAN5g1IDqAOoA1ICtIK0grSCtIK0gmKCbAJugnECeIJ9AoGChgK/g+aD5oPmg+aDGYLcAtwC3ALcAtwC3ALcAr+DAAMAAwADAAO7g7uDu4O7g7uD5oPmg+aD5oPmgxGDEYMRgxGDxAL4gviC+IL4gviC+IL4gwWDBYMFgwWDbYMIAwgDCAMIAwgDEwMTAtwC+ILcAviC3AL4gr+Cv4K/gr+D5oMAAwWDAAMFgwADBYMAAwWDAAMFg7uDbYO7g7uDu4O7g7uDEYOoAoiCiIKIgoiDu4Ntg7uDbYO7g22DbYPmgwgD5oMIA+aDCAKUApQClAMZgxmDGYMRgxGDEYMRgxGDEYKrA8QDEwPEApeCl4KXgtwDAAO7g7uD5oPEAtwCoAMAApeDu4O7g6gDu4O7g+aCooMZg8QDVIO7g8QDbYMIAxMDCAMAA3mDu4O7gxGDqAOoAsmC3AKgA3mDAAO7g7uD5oKigr+DGYNUgviDBYMIAsQDEwNsAwWDUgMTAqsCqwKrA8QDEwK0grSCtIO7g22C3AL4gwADBYK2AxMCv4PEAxMDu4NUg2wDu4LcAviC3AL4gwADBYMFgwWDVINsA+aDCAMIAsQCyYMTAsmDEwLJgxMDVINsAtwC+ILcAviC3AL4gtwC+ILcAviC3AL4gtwC+ILcAviC3AL4gtwC+ILcAviC3AL4gwADBYMAAwWDAAMFgwADBYMAAwWDAAMFgwADBYMAAwWDu4O7g+aDCAPmgwgD5oMIA+aDCAPmgwgD5oMIA+aDCAMIAxGDEYPEAxMDxAMTA8QDEwOoA7uDGYNUg2wDeYNSA1SDbANtg3ADeYOoA7uDu4PEA+aAAIAhwAGAAYAAAALAAsAAQATABMAAgAlACoAAwAsADUACQA4AD4AEwBFAEYAGgBJAEoAHABMAEwAHgBRAFQAHwBWAFYAIwBaAFoAJABcAF0AJQCKAIoAJwCcAJwAKACwALQAKQC2ALgALgC6ALoAMQC8AL0AMgC/AMAANADCAMQANgDGAMsAOQDRANEAPwDTAN0AQADfAN8ASwDhAOMATADlAOcATwDpAO0AUgDwAPAAVwD1APcAWAD6APsAWwD9AP8AXQEDAQQAYAEJAQkAYgEMAQwAYwEXARkAZAErAS0AZwEwATAAagEyATIAawFJAUkAbAFsAW0AbQFvAXEAbwG6AboAcgG9Ab0AcwHEAcUAdAHIAcgAdgHKAcsAdwHNAc0AeQIoAigAegIqAisAewJHAkgAfQJKAkoAfwJMAm0AgAJvAnIAogJ3AnwApgKBAokArAKLAosAtQKNAo0AtgKPAo8AtwKRApEAuAKTApwAuQKlAqcAwwKpAqkAxgKrAqsAxwKtAq0AyAKvAq8AyQKyArIAygK0ArQAywK2ArYAzAK4ArgAzQK6AroAzgK8ArwAzwK+AsoA0ALMAswA3QLOAs4A3gLQAtAA3wLbAtsA4ALdAt0A4QLfAt8A4gLh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BB7/6wQg/+sEIv/rBCT/6wQm/+sEKP/rBCr/6wQs/+sELv/rBDD/6wQy/+sENP/qBDb/6gQ4/+oEOv/qBDz/6gQ+/+oEQP/qBEL/6ARE/+gERv/oBE0AFAAfADj/1QA6/+QAO//sAD3/3QDR/9UA1f/VARj/5AEy/9UBOv/VAmb/3QLb/9UC3f/VAt//1QLt/+wC7//dAvH/3QNY/90DZ//dA2r/3QOO/9UDoP/sA6L/7AOk/+wDpv/dA7f/5AO//90EQf/dBEP/3QRF/90ETf/VBGr/3QAaADj/sAA6/+0APf/QANH/sADV/7ABGP/tATL/sAE6/7ACZv/QAtv/sALd/7AC3/+wAu//0ALx/9ADWP/QA2f/0ANq/9ADjv+wA6b/0AO3/+0Dv//QBEH/0ARD/9AERf/QBE3/sARq/9AAEAAu/+4AOf/uAmL/7gJj/+4CZP/uAmX/7gKy/+4C4f/uAuP/7gLl/+4C5//uAun/7gLr/+4Df//uBDP/7gQ1/+4ARwAGABAACwAQAEf/6ABI/+gASf/oAEv/6ABV/+gAk//oAJj/6AC6/+gAx//oAMj/6AD2/+gBAv/oAR3/6AEh/+gBOf/oAUv/6AFM/+gBVv/oAWwAEAFtABABbwAQAXAAEAFxABACbv/oAm//6AJw/+gCcf/oAnL/6AKK/+gCjP/oAo7/6AKQ/+gCkv/oApT/6AKW/+gCmP/oApr/6AKc/+gCnv/oAqD/6AKi/+gCpP/oA2v/6AOR/+gDlf/oA5j/6AOoABADqQAQA6wAEAOz/+gDuf/oA77/6APM/+gDzv/oA8//6APb/+gD7P/oBAj/6AQK/+gEDP/oBA7/6AQQ/+gEEv/oBBT/6AQW/+gEKv/oBCz/6AQu/+gEMv/oAAEAVgAEAAAAJgCmAZwB+gIUAlYCzAPCBLgFkgYsCMYKjAteDFQOGg5MDn4O/BDiEVgSKhRMFQIWaBciF6gYBhjIGT4ewBlQGqIc4B0CHhgelh7AHuoAAQAmAE8AWABbAF8AnAC0ALYAtwC4AL8AwgDDAMQAyQDLAMwAzQDRANUA1wDYANoA4gDmAOcA6ADpAOoA7ADuAPAA9QD3APoA/wECASEBbQA9AEf/7ABI/+wASf/sAEv/7ABV/+wAk//sAJj/7AC6/+wAx//sAMj/7AD2/+wBAv/sAR3/7AEh/+wBOf/sAUv/7AFM/+wBVv/sAm7/7AJv/+wCcP/sAnH/7AJy/+wCiv/sAoz/7AKO/+wCkP/sApL/7AKU/+wClv/sApj/7AKa/+wCnP/sAp7/7AKg/+wCov/sAqT/7ANr/+wDkf/sA5X/7AOY/+wDs//sA7n/7AO+/+wDzP/sA87/7APP/+wD2//sA+z/7AQI/+wECv/sBAz/7AQO/+wEEP/sBBL/7AQU/+wEFv/sBCr/7AQs/+wELv/sBDL/7AAXAFP/7AEX/+wCeP/sAnn/7AJ6/+wCe//sAnz/7ALG/+wCyP/sAsr/7ANx/+wDd//sA5P/7APZ/+wD3f/sBBz/7AQe/+wEIP/sBCL/7AQk/+wEJv/sBCj/7AQw/+wABgAQ/4QAEv+EAW7/hAFy/4QBdv+EAXf/hAAQAC7/7AA5/+wCYv/sAmP/7AJk/+wCZf/sArL/7ALh/+wC4//sAuX/7ALn/+wC6f/sAuv/7AN//+wEM//sBDX/7AAdAAb/8gAL//IAWv/zAF3/8wC8//MBGf/zAWz/8gFt//IBb//yAXD/8gFx//ICgf/zAoL/8wLw//MDc//zA5b/8wOf//MDp//zA6j/8gOp//IDrP/yA7j/8wPA//MD4f/zA+P/8wPl//MEQv/zBET/8wRG//MAPQAn//MAK//zADP/8wA1//MAg//zAJL/8wCX//MAsv/zANL/8wEH//MBFv/zARr/8wEc//MBHv/zASD/8wE4//MBVf/zAij/8wIp//MCK//zAiz/8wJT//MCXf/zAl7/8wJf//MCYP/zAmH/8wKJ//MCi//zAo3/8wKP//MCnf/zAp//8wKh//MCo//zAsX/8wLH//MCyf/zAvr/8wNX//MDZP/zA4r/8wON//MDuv/zA73/8wPY//MD2v/zA9z/8wQb//MEHf/zBB//8wQh//MEI//zBCX/8wQn//MEKf/zBCv/8wQt//MEL//zBDH/8wSq//MAPQAn/+YAK//mADP/5gA1/+YAg//mAJL/5gCX/+YAsv/mANL/5gEH/+YBFv/mARr/5gEc/+YBHv/mASD/5gE4/+YBVf/mAij/5gIp/+YCK//mAiz/5gJT/+YCXf/mAl7/5gJf/+YCYP/mAmH/5gKJ/+YCi//mAo3/5gKP/+YCnf/mAp//5gKh/+YCo//mAsX/5gLH/+YCyf/mAvr/5gNX/+YDZP/mA4r/5gON/+YDuv/mA73/5gPY/+YD2v/mA9z/5gQb/+YEHf/mBB//5gQh/+YEI//mBCX/5gQn/+YEKf/mBCv/5gQt/+YEL//mBDH/5gSq/+YANgAl/+QAPP/SAD3/0wCx/+QAs//kANn/0gEM/+QCTP/kAk3/5AJO/+QCT//kAlD/5AJR/+QCUv/kAmb/0wKD/+QChf/kAof/5ALv/9MC8f/TA1P/5ANY/9MDW//kA2f/0wNo/9IDav/TA4P/5AOP/9IDpv/TA6//5AO//9MDwv/SA8X/5APH/+QD0P/SA+r/0gPv/+QD8f/kA/P/5AP1/+QD9//kA/n/5AP7/+QD/f/kA///5AQB/+QEA//kBAX/5ARB/9MEQ//TBEX/0wRP/9IEV//SBGr/0wAmABD/HgAS/x4AJf/NALH/zQCz/80BDP/NAW7/HgFy/x4Bdv8eAXf/HgJM/80CTf/NAk7/zQJP/80CUP/NAlH/zQJS/80Cg//NAoX/zQKH/80DU//NA1v/zQOD/80Dr//NA8X/zQPH/80D7//NA/H/zQPz/80D9f/NA/f/zQP5/80D+//NA/3/zQP//80EAf/NBAP/zQQF/80ApgBH/9wASP/cAEn/3ABL/9wAUf/zAFL/8wBT/9YAVP/zAFX/3ABZ/90AWv/hAF3/4QCT/9wAmP/cAJr/3QC6/9wAvP/hAMD/8wDH/9wAyP/cAMr/3QDr//MA7//zAPD/8wDy//MA8//zAPT/8wD2/9wA9//zAPn/8wD6//MA/f/zAP//8wEC/9wBBP/zARf/1gEZ/+EBHf/cASH/3AE1//MBOf/cAUT/8wFJ//MBS//cAUz/3AFW/9wCbv/cAm//3AJw/9wCcf/cAnL/3AJ3//MCeP/WAnn/1gJ6/9YCe//WAnz/1gJ9/90Cfv/dAn//3QKA/90Cgf/hAoL/4QKK/9wCjP/cAo7/3AKQ/9wCkv/cApT/3AKW/9wCmP/cApr/3AKc/9wCnv/cAqD/3AKi/9wCpP/cAr//8wLB//MCw//zAsT/8wLG/9YCyP/WAsr/1gLi/90C5P/dAub/3QLo/90C6v/dAuz/3QLw/+EDa//cA23/8wNv/90Dcf/WA3P/4QN2/90Dd//WA3j/3QOR/9wDkv/zA5P/1gOU//MDlf/cA5b/4QOY/9wDmf/zA57/8wOf/+EDp//hA67/8wOz/9wDtP/zA7j/4QO5/9wDvv/cA8D/4QPM/9wDzv/cA8//3APV//MD1//zA9n/1gPb/9wD3f/WA+H/4QPj/+ED5f/hA+n/8wPs/9wECP/cBAr/3AQM/9wEDv/cBBD/3AQS/9wEFP/cBBb/3AQc/9YEHv/WBCD/1gQi/9YEJP/WBCb/1gQo/9YEKv/cBCz/3AQu/9wEMP/WBDL/3AQ0/90ENv/dBDj/3QQ6/90EPP/dBD7/3QRA/90EQv/hBET/4QRG/+EESv/zBEz/8wRW//MEY//zBGX/8wRn//MAcQAG/9oAC//aAEf/8ABI//AASf/wAEv/8ABV//AAWf/vAFr/3ABd/9wAk//wAJj/8ACa/+8Auv/wALz/3ADH//AAyP/wAMr/7wD2//ABAv/wARn/3AEd//ABIf/wATn/8AFL//ABTP/wAVb/8AFs/9oBbf/aAW//2gFw/9oBcf/aAm7/8AJv//ACcP/wAnH/8AJy//ACff/vAn7/7wJ//+8CgP/vAoH/3AKC/9wCiv/wAoz/8AKO//ACkP/wApL/8AKU//AClv/wApj/8AKa//ACnP/wAp7/8AKg//ACov/wAqT/8ALi/+8C5P/vAub/7wLo/+8C6v/vAuz/7wLw/9wDa//wA2//7wNz/9wDdv/vA3j/7wOR//ADlf/wA5b/3AOY//ADn//cA6f/3AOo/9oDqf/aA6z/2gOz//ADuP/cA7n/8AO+//ADwP/cA8z/8APO//ADz//wA9v/8APh/9wD4//cA+X/3APs//AECP/wBAr/8AQM//AEDv/wBBD/8AQS//AEFP/wBBb/8AQq//AELP/wBC7/8AQy//AENP/vBDb/7wQ4/+8EOv/vBDz/7wQ+/+8EQP/vBEL/3ARE/9wERv/cADQABv+gAAv/oABZ//EAWv/FAF3/xQCa//EAvP/FAMr/8QEZ/8UBbP+gAW3/oAFv/6ABcP+gAXH/oAJ9//ECfv/xAn//8QKA//ECgf/FAoL/xQLi//EC5P/xAub/8QLo//EC6v/xAuz/8QLw/8UDb//xA3P/xQN2//EDeP/xA5b/xQOf/8UDp//FA6j/oAOp/6ADrP+gA7j/xQPA/8UD4f/FA+P/xQPl/8UENP/xBDb/8QQ4//EEOv/xBDz/8QQ+//EEQP/xBEL/xQRE/8UERv/FAD0AR//nAEj/5wBJ/+cAS//nAFX/5wCT/+cAmP/nALr/5wDH/+cAyP/nAPb/5wEC/+cBHf/nASH/5wE5/+cBS//nAUz/5wFW/+cCbv/nAm//5wJw/+cCcf/nAnL/5wKK/+cCjP/nAo7/5wKQ/+cCkv/nApT/5wKW/+cCmP/nApr/5wKc/+cCnv/nAqD/5wKi/+cCpP/nA2v/5wOR/+cDlf/nA5j/5wOz/+cDuf/nA77/5wPM/+cDzv/nA8//5wPb/+cD7P/nBAj/5wQK/+cEDP/nBA7/5wQQ/+cEEv/nBBT/5wQW/+cEKv/nBCz/5wQu/+cEMv/nAHEABgAMAAsADABH/+gASP/oAEn/6ABL/+gAU//qAFX/6ABaAAsAXQALAJP/6ACY/+gAuv/oALwACwDH/+gAyP/oAPb/6AEC/+gBF//qARkACwEd/+gBIf/oATn/6AFL/+gBTP/oAVb/6AFsAAwBbQAMAW8ADAFwAAwBcQAMAm7/6AJv/+gCcP/oAnH/6AJy/+gCeP/qAnn/6gJ6/+oCe//qAnz/6gKBAAsCggALAor/6AKM/+gCjv/oApD/6AKS/+gClP/oApb/6AKY/+gCmv/oApz/6AKe/+gCoP/oAqL/6AKk/+gCxv/qAsj/6gLK/+oC8AALA2v/6ANx/+oDcwALA3f/6gOR/+gDk//qA5X/6AOWAAsDmP/oA58ACwOnAAsDqAAMA6kADAOsAAwDs//oA7gACwO5/+gDvv/oA8AACwPM/+gDzv/oA8//6APZ/+oD2//oA93/6gPhAAsD4wALA+UACwPs/+gECP/oBAr/6AQM/+gEDv/oBBD/6AQS/+gEFP/oBBb/6AQc/+oEHv/qBCD/6gQi/+oEJP/qBCb/6gQo/+oEKv/oBCz/6AQu/+gEMP/qBDL/6ARCAAsERAALBEYACwAMAFz/7QBe/+0A7f/tAvP/7QL1/+0C9//tA5f/7QPD/+0D0f/tA+v/7QRQ/+0EWP/tAAwAXP/yAF7/8gDt//IC8//yAvX/8gL3//IDl//yA8P/8gPR//ID6//yBFD/8gRY//IAHwBa//QAXP/yAF3/9ABe//MAvP/0AO3/8gEZ//QCgf/0AoL/9ALw//QC8//zAvX/8wL3//MDc//0A5b/9AOX//IDn//0A6f/9AO4//QDwP/0A8P/8gPR//ID4f/0A+P/9APl//QD6//yBEL/9ARE//QERv/0BFD/8gRY//IAeQAG/8oAC//KADj/0gA6/9QAPP/0AD3/0wBR/9EAUv/RAFT/0QBa/+YAXP/vAF3/5gC8/+YAwP/RANH/0gDV/9IA2f/0AN3/7QDg/+EA6//RAO3/7wDv/9EA8P/RAPL/0QDz/9EA9P/RAPf/0QD5/9EA+v/RAP3/0QD//9EBBP/RARj/1AEZ/+YBMv/SATX/0QE6/9IBRP/RAUn/0QFs/8oBbf/KAW//ygFw/8oBcf/KAmb/0wJ3/9ECgf/mAoL/5gK//9ECwf/RAsP/0QLE/9EC2//SAt3/0gLf/9IC7//TAvD/5gLx/9MDWP/TA2f/0wNo//QDav/TA23/0QNz/+YDgv/tA47/0gOP//QDkv/RA5T/0QOW/+YDl//vA5n/0QOe/9EDn//mA6b/0wOn/+YDqP/KA6n/ygOs/8oDrv/RA7T/0QO3/9QDuP/mA7//0wPA/+YDwv/0A8P/7wPQ//QD0f/vA9X/0QPX/9ED4P/tA+H/5gPi/+0D4//mA+T/7QPl/+YD5v/hA+n/0QPq//QD6//vBEH/0wRC/+YEQ//TBET/5gRF/9MERv/mBEr/0QRM/9EETf/SBE//9ARQ/+8EUf/hBFP/4QRW/9EEV//0BFj/7wRj/9EEZf/RBGf/0QRq/9MAHQA4/74AWv/vAF3/7wC8/+8A0f++ANX/vgEZ/+8BMv++ATr/vgKB/+8Cgv/vAtv/vgLd/74C3/++AvD/7wNz/+8Djv++A5b/7wOf/+8Dp//vA7j/7wPA/+8D4f/vA+P/7wPl/+8EQv/vBET/7wRG/+8ETf++ADQAOP/mADr/5wA8//IAPf/nAFz/8QDR/+YA1f/mANn/8gDd/+4A4P/oAO3/8QEY/+cBMv/mATr/5gJm/+cC2//mAt3/5gLf/+YC7//nAvH/5wNY/+cDZ//nA2j/8gNq/+cDgv/uA47/5gOP//IDl//xA6b/5wO3/+cDv//nA8L/8gPD//ED0P/yA9H/8QPg/+4D4v/uA+T/7gPm/+gD6v/yA+v/8QRB/+cEQ//nBEX/5wRN/+YET//yBFD/8QRR/+gEU//oBFf/8gRY//EEav/nAIgAJQAQACf/6AAr/+gAM//oADX/6AA4/+AAOv/gAD3/3wCD/+gAkv/oAJf/6ACxABAAsv/oALMAEADR/+AA0v/oANMAEADV/+AA3AAQAOD/4QDxABAA+P/gAQMAEAEH/+gBDAAQARb/6AEY/+ABGv/oARz/6AEe/+gBIP/oATL/4AE4/+gBOv/gAVEAEAFV/+gCKP/oAin/6AIr/+gCLP/oAkwAEAJNABACTgAQAk8AEAJQABACUQAQAlIAEAJT/+gCXf/oAl7/6AJf/+gCYP/oAmH/6AJm/98CgwAQAoUAEAKHABACif/oAov/6AKN/+gCj//oAp3/6AKf/+gCof/oAqP/6ALF/+gCx//oAsn/6ALb/+AC3f/gAt//4ALv/98C8f/fAvr/6ANTABADV//oA1j/3wNbABADZP/oA2f/3wNq/98DgwAQA4r/6AON/+gDjv/gA6b/3wOvABADt//gA7r/6AO9/+gDv//fA8UAEAPHABAD2P/oA9r/6APc/+gD5v/hA+f/4APtABAD7gAQA+8AEAPxABAD8wAQA/UAEAP3ABAD+QAQA/sAEAP9ABAD/wAQBAEAEAQDABAEBQAQBBv/6AQd/+gEH//oBCH/6AQj/+gEJf/oBCf/6AQp/+gEK//oBC3/6AQv/+gEMf/oBEH/3wRD/98ERf/fBE3/4ARR/+EEUv/gBFP/4QRU/+AEaAAQBGkAEARq/98Eqv/oAC0AOP/xADr/9AA8//QAPf/wANH/8QDT//UA1f/xANn/9ADc//UA3f/zARj/9AEy//EBOv/xAVH/9QJm//AC2//xAt3/8QLf//EC7//wAvH/8ANY//ADZ//wA2j/9ANq//ADgv/zA47/8QOP//QDpv/wA7f/9AO///ADwv/0A9D/9APg//MD4v/zA+T/8wPq//QD7f/1BEH/8ARD//AERf/wBE3/8QRP//QEV//0BGj/9QRq//AAWQAlAA8AOP/mADr/5gA8AA4APf/mALEADwCzAA8A0f/mANMADgDV/+YA2QAOANwADgDdAAsA4P/lAPEADwD4/+gBAwAPAQwADwEY/+YBMv/mATr/5gFRAA4CTAAPAk0ADwJOAA8CTwAPAlAADwJRAA8CUgAPAmb/5gKDAA8ChQAPAocADwLb/+YC3f/mAt//5gLv/+YC8f/mA1MADwNY/+YDWwAPA2f/5gNoAA4Dav/mA4IACwODAA8Djv/mA48ADgOm/+YDrwAPA7f/5gO//+YDwgAOA8UADwPHAA8D0AAOA+AACwPiAAsD5AALA+b/5QPn/+gD6gAO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ABADogOiABADpAOkABADpgOmAA8DpwOnABkDqAOpAB0DrAOsAB0DrQOtAAIDrgOuABcDsAOwABMDsQOxAAUDswOzABYDtwO3AA0DuAO4ABkDvQO9AAQDvgO+ABQDvwO/AA8DwAPAABkDwQPBAAIDwgPCAA4DwwPDABsDxAPEAAIDxgPGABMDyAPIABMDywPLAAUDzAPMABYDzgPPABYD0APQAA4D0QPRABsD2APYAAMD2QPZABgD3QPdABgD3wPfABUD4APgABID4QPhABkD4gPiABID4wPjABkD5APkABID5QPlABkD6gPqAA4D6wPrABsD8APwABMD8gPyABMD9AP0ABMD9gP2ABMD+AP4ABMD+gP6ABMD/AP8ABMD/gP+ABMEAAQAABMEAgQCABMEBAQEABMEBgQGABMEBwQHAAUECAQIABYECQQJAAUECgQKABYECwQLAAUEDAQMABYEDQQNAAUEDgQOABYEDwQPAAUEEAQQABYEEQQRAAUEEgQSABYEEwQTAAUEFAQUABYEFQQVAAUEFgQWABYEFwQXAAIEGQQZAAIEGwQbAAMEHAQcABgEHQQdAAMEHgQeABgEHwQfAAMEIAQgABgEIQQhAAMEIgQiABgEIwQjAAMEJAQkABgEJQQlAAMEJgQmABgEJwQnAAMEKAQoABgEMAQwABgEMwQzAAwENQQ1AAwEQQRBAA8EQgRCABkEQwRDAA8ERAREABkERQRFAA8ERgRGABkESQRJAAkESwRLAAIETQRNAAYETwRPAA4EUARQABsEVQRVAAcEVgRWAAgEVwRXAA4EWARYABsEWwRbABcEXQRdAB8EXgReAAcEYARgAAkEZARkAAIEZgRmAAIEagRqAA8EqgSqAAMAAgFtAAYABgAHAAsACwAHABAAEAATABEAEQAXABIAEgATACUAJQARACcAJwAFACsAKwAFAC4ALgAcADMAMwAFADUANQAFADcANwAZADgAOAAKADkAOQAGADoAOgANADsAOwAJADwAPAASAD0APQAOAD4APgAUAEUARQAaAEcASQAVAEsASwAVAFEAUgAYAFMAUwAIAFQAVAAYAFUAVQAVAFcAVwAbAFkAWQALAFoAWgACAFwAXAAWAF0AXQACAF4AXgAMAIMAgwAFAJIAkgAFAJMAkwAVAJcAlwAFAJgAmAAVAJoAmgALALEAsQAR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b20EbGRub20EbGRub20EbGZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmxpZ2EEfGxpZ2EEhGxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxvY2wEkGxvY2wElmxvY2wEnG51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqHBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5AAAAAEAAAAAAAIAAgADAAAAAQAHAAAAAQAYAAAAAwAVABYAFwAAAAIACAAJAAAAAQAJAAAAAQAUAAAAAQAEAAAAAQAGAAAAAQAFAAAAAQAZAAAAAQARAAAAAQATAAAAAQABAAAAAQAKAAAAAQALAAAAAQAMAAAAAQANAAAAAQAOAAAAAQAPAAAAAQAQAAAAAQASABsAOAPGBrQHYA3wDfAOBg4oDl4OhA6yDsYO2g7uDwAPGg9cD3oPmA/KD/wQLhBCEHoQbBB6EKYAAQAAAAEACAACAcQA3wHnAboBuwG8Ab0BvgG/AcABwQHCAcMBxAHFAcYBxwHIAckBygHLAcwBzQHOAc8B0AHRAdIB0wHoAekCRAI7AeoB6wHsAe0B7gHvAfAB8QHyAfMB9AH1AfYB9wH4AfkB+gH7AfwB/QH+AgACAQTdAgICAwIEAgUCBgIHAggCCQIKAgsCLwIPAhACEQIUAhUCFgIXAhgCGQIbAhwCHgIdAvwC/QL+Av8DAAMBAwIDAwMEAwUDBgMHAwgDCQMKAwsDDAMNAw4DDwMQAxEDEgMTAxQDFQMWAxcDGAMZAxoDGwMcAx0DHgMfAyADIQMiAyMDJAMlAyYDJwMoAykDKgMrAywDLQMuAy8DMAMxAzIDMwM0AzUDNgM3AzgDOQM6AzsDPAM9Az4DPwNAA0EDQgNDA0QDRgNFA0cDSANJA0oDSwNMA00DTgNPA1ADUQNSBKsErAStBK4ErwSwBLEEsgSzBLQEtQS2BLcEuAS5BLoEuwS8BL0EvgS/BMAEwQTCBMMExATFBMYB/wTHBMgEyQTKBMsEzATNBM4EzwTQBNEE0gTTBNQE1QTWBNgE2QTbAhoE3AIOBNcCEwINBNoCDAISAAEA3wAIACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgBlAGcAhQCSALAAsQCyALMAtAC1ALYAtwC4ALkA0QDSANMA1ADVANYA1wDYANkA2gDbANwA3QDeAN8A4ADhAOIA4wDkAOUA5gDnAOgBLAEwATIBOAE6ATwBPgE/AUUBRgF/AYUBigGNAkcCSAJKAkwCTQJOAk8CUAJRAlICUwJUAlUCVgJXAlgCWQJaAlsCXAJdAl4CXwJgAmECYgJjAmQCZQJmAoMChQKHAokCiwKNAo8CkQKTApUClwKZApsCnQKfAqECowKlAqcCqQKrAq0CrwKyArQCtgK4AroCvAK+AsACwgLFAscCyQLLAs0CzwLRAtMC1QLZAtsC3QLfAuEC4wLlAucC6QLrAu0C7wLxAvIC9AL2A1MDVANVA1YDVwNYA1kDWwNcA10DXgNfA2ADYQNiA2QDZQNmA2cDaANpA2oDegN7A3wDfQN+A38DgAOBA4IDgwOEA4UDhgOHA4gDiQOKA4sDjAONA44DjwO7A70DvwPUA9oD4ARJBEsETwRXBFkEXgRqAAEAAAABAAgAAgF0ALcBugG7AbwBvQG+Ab8BwAHBAcIBwwHEAcUBxgHHAcgByQHKAcsBzAHNAc4BzwHQAdEB0gHTAv0DMAI7AfoEygTLAfsB/AH9Af4B/wIABM4EzwTRBNQE3QICAgMCBAIFAgYCBwIIAgkCCgILAfQB9QH2AfcB+AH5Ai8CDwIQAhECFAIVAhcCGQL+Av8DAAMBAwIDAwMEAwUDBgMHAwgDCQMKAwsDDAMNAw4DDwMQAxEDEgMTAxQDFQMWAxcDGAMZA08DGgMbAxwDHQMeAx8DIAMhAyIDIwMkAyUDJgMnAygDKQMqAysDLAMtAy4DLwMxAzIDMwM0AzUDNgM3AzgDOQM6AzsDPAM9Az4DPwNAA0EDQgNDA0QDRgNFA0cDSANJA0oDSwNMA00DTgNQA1EDUgTJBMwEzQTQBNIE0wIBBNUEwQTCBMMExATFBMYExwTIBNYE2ATZAhgE2wIaBNwC/AIOBNcCEwINBNoCFgIMAhIAAQC3AEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0AXgCHAIwAkwDpAOoA6wDsAO0A7gDvAPAA8QDyAPMA9AD1APYA9wD4APkA+gD7APwA/QD+AP8BAAEBAQIBAwEEAQUBBgEtATEBMwE5ATsBPQFAAUcCSwJnAmgCaQJqAmsCbAJtAm4CbwJwAnECcgJzAnQCdQJ2AncCeAJ5AnoCewJ8An0CfgJ/AoACgQKCAoQChgKIAooCjAKOApACkgKUApYCmAKaApwCngKgAqICpAKmAqgCqgKsAq4CswK1ArcCuQK7Ar0CvwLBAsMCxgLIAsoCzALOAtAC0gLUAtYC2gLcAt4C4ALiAuQC5gLoAuoC7ALuAvAC8wL1AvcDkAORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwO8A74DwAPOA9UD2wPhBEcESgRMBFAEWARaBFsEXwRrAAYAAAAGABIAKgBCAFoAcgCKAAMAAAABABIAAQCQAAEAAAAaAAEAAQBNAAMAAAABABIAAQB4AAEAAAAaAAEAAQBOAAMAAAABABIAAQBgAAEAAAAaAAEAAQKuAAMAAAABABIAAQBIAAEAAAAaAAEAAQObAAMAAAABABIAAQAwAAEAAAAaAAEAAQOdAAMAAAABABIAAQAYAAEAAAAaAAEAAQQaAAIAAQCnAKsAAAAEAAAAAQAIAAEGHgA2AHIApACuALgAygD8AQ4BGAFKAWQBfgGQAboB7AH2AhgCMgJEAnYCiAKiAswC3gMQAxoDJAM2A2gDcgN8A4YDoAO6A8wD9gQoBDIEVARuBIAEsgTEBN4FCAUaBSQFLgU4BUIFbAWWBcAF6gYUAAYADgAUABoAIAAmACwCTAACAKcCTQACAKgCTwACAKkD8QACAKoEewACAKsD7wACAKwAAQAEBIgAAgCsAAEABAKJAAIAqAACAAYADASKAAIArASMAAIBogAGAA4AFAAaACAAJgAsAlQAAgCnAlUAAgCoBAsAAgCpBAkAAgCqBH0AAgCrBAcAAgCsAAIABgAMBHcAAgCoAqMAAgGiAAEABASOAAIArAAGAA4AFAAaACAAJgAsAlgAAgCnAlkAAgCoAqcAAgCpBBcAAgCqBH8AAgCrBBkAAgCsAAMACAAOABQEkAACAKgEkgACAKwCtAACAaIAAwAIAA4AFAK2AAIAqASUAAIArAK4AAIBogACAAYADAOtAAIAqASWAAIArAAFAAwAEgAYAB4AJAR5AAIApwK+AAIAqAJcAAIAqQSYAAIArALAAAIBogAGAA4AFAAaACAAJgAsAl0AAgCnAl4AAgCoAmAAAgCpBB0AAgCqBIEAAgCrBBsAAgCsAAEABASaAAIAqAAEAAoAEAAWABwCywACAKgEgwACAKsEnAACAKwCzQACAaIAAwAIAA4AFALRAAIAqASeAAIArALXAAIBogACAAYADASgAAIArALbAAIBogAGAA4AFAAaACAAJgAsAmIAAgCnAmMAAgCoAuEAAgCpBDUAAgCqBIUAAgCrBDMAAgCsAAIABgAMBKIAAgCpBKQAAgCsAAMACAAOABQDoAACAKcDogACAKgEpgACAKwABQAMABIAGAAeACQDpgACAKcCZgACAKgERQACAKkEQwACAKoEQQACAKwAAgAGAAwC8gACAKgEqAACAKwABgAOABQAGgAgACYALAJnAAIApwJoAAIAqAJqAAIAqQPyAAIAqgR8AAIAqwPwAAIArAABAAQEiQACAKwAAQAEAooAAgCoAAIABgAMBIsAAgCsBI0AAgGiAAYADgAUABoAIAAmACwCbwACAKcCcAACAKgEDAACAKkECgACAKoEfgACAKsECAACAKwAAQAEBHgAAgCoAAEABASPAAIArAABAAQEGgACAKwAAwAIAA4AFASRAAIAqASTAAIArAK1AAIBogADAAgADgAUArcAAgCoBJUAAgCsArkAAgGiAAIABgAMA64AAgCoBJcAAgCsAAUADAASABgAHgAkBHoAAgCnAr8AAgCoAncAAgCpBJkAAgCsAsEAAgGiAAYADgAUABoAIAAmACwCeAACAKcCeQACAKgCewACAKkEHgACAKoEggACAKsEHAACAKwAAQAEBJsAAgCoAAQACgAQABYAHALMAAIAqASEAAIAqwSdAAIArALOAAIBogADAAgADgAUAtIAAgCoBJ8AAgCsAtgAAgGiAAIABgAMBKEAAgCsAtwAAgGiAAYADgAUABoAIAAmACwCfQACAKcCfgACAKgC4gACAKkENgACAKoEhgACAKsENAACAKwAAgAGAAwEowACAKkEpQACAKwAAwAIAA4AFAOhAAIApwOjAAIAqASnAAIArAAFAAwAEgAYAB4AJAOnAAIApwKBAAIAqARGAAIAqQREAAIAqgRCAAIArAACAAYADALzAAIAqASpAAIArAABAAQC+AACAKgAAQAEAvoAAgCoAAEABAL5AAIAqAABAAQC+wACAKgABQAMABIAGAAeACQCcwACAKcCdAACAKgCqAACAKkEGAACAKoEgAACAKsABQAMABIAGAAeACQEKwACAKcEKQACAKgELwACAKkELQACAKoEMQACAKwABQAMABIAGAAeACQELAACAKcEKgACAKgEMAACAKkELgACAKoEMgACAKwABQAMABIAGAAeACQEOQACAKcENwACAKgEPQACAKkEOwACAKoEPwACAKwABQAMABIAGAAeACQEOgACAKcEOAACAKgEPgACAKkEPAACAKoEQAACAKwAAQAEBIcAAgCoAAIAEQAlACkAAAArAC0ABQAvADQACAA2ADsADgA9AD4AFABFAEkAFgBLAE0AGwBPAFQAHgBWAFsAJABdAF4AKgCBAIEALACDAIMALQCGAIYALgCJAIkALwCMAIwAMACXAJoAMQDPAM8ANQABAAAAAQAIAAEABgACAAEAAgLVAtYAAQAAAAEACAACAA4ABATeBN8E4AThAAEABAKHAogCmQKaAAQAAAABAAgAAQAmAAIACgAcAAIABgAMAaMAAgBKAagAAgBYAAEABAGpAAIAWAABAAIASgBXAAQAAAABAAgAAQBEAAIACgAUAAEABAGkAAIATQABAAQBpgACAE0ABAAAAAEACAABAB4AAgAKABQAAQAEAaUAAgBQAAEABAGnAAIAUAABAAIASgGjAAEAAAABAAgAAQAGAZUAAQABAEsAAQAAAAEACAABAAYBJwABAAEAugABAAAAAQAIAAEABgGsAAEAAQA2AAEAAAABAAgAAgAcAAIB4wHkAAEAAAABAAgAAgAKAAIB5QHmAAEAAgAvAE8AAQAAAAEACAACAB4ADAIoAioCKQIrAiwCHwIgAiECIgGuAiQCJQABAAwAJwAoACsAMwA1AEYARwBIAEsAUwBUAFUAAQAAAAEACAACAAwAAwImAicCJwABAAMASQBLAiIAAQAAAAEACAACAGYACAI9Ai0CLgIwAjECOQI6AjwAAQAAAAEACAACABYACAAbABUAFgAXABgAGQAdABQAAQAIAa0CIwRxBHIEcwR0BHUEdgABAAAAAQAIAAIAFgAIBHYCIwRxBHIEcwR0Aa0EdQABAAgAFAAVABYAFwAYABkAGwAdAAEAAAABAAgAAgAWAAgAFQAWABcAGAAZABsAHQAUAAEACAItAi4CMAIxAjkCOgI8Aj0AAQAAAAEACAABAAYBaQABAAEAEwAGAAAAAQAIAAMAAQASAAEAUgAAAAEAAAAaAAIAAgF8AXwAAAHUAd0AAQABAAAAAQAIAAEAKAHAAAEAAAABAAgAAgAaAAoCMgB6AHMAdAIzAjQCNQI2AjcCOAACAAEAFAAdAAAAAQAAAAEACAACACYAEAHUAdUB1gHXAdgB2QHaAdsB3AHdAkACPgJBAkICPwJDAAEAEAAUABUAFgAXABgAGQAaABsAHAAdAE0ATgKuA5sDnQQa\"\n};\n\n/*! DataTables 1.10.18\n * ©2008-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     DataTables\n * @description Paginate, search and order HTML tables\n * @version     1.10.18\n * @file        jquery.dataTables.js\n * @author      SpryMedia Ltd\n * @contact     www.datatables.net\n * @copyright   Copyright 2008-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n/*jslint evil: true, undef: true, browser: true */\n/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/\n\n(function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\t// CommonJS environments without a window global must pass a\n\t\t\t\t// root. This will give an error otherwise\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ ) {\n\t\t\t\t$ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window\n\t\t\t\t\trequire('jquery') :\n\t\t\t\t\trequire('jquery')( root );\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}\n(function( $, window, document, undefined ) {\n\t\"use strict\";\n\n\t/**\n\t * DataTables is a plug-in for the jQuery Javascript library. It is a highly\n\t * flexible tool, based upon the foundations of progressive enhancement,\n\t * which will add advanced interaction controls to any HTML table. For a\n\t * full list of features please refer to\n\t * [DataTables.net](href=\"http://datatables.net).\n\t *\n\t * Note that the `DataTable` object is not a global variable but is aliased\n\t * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may\n\t * be  accessed.\n\t *\n\t *  @class\n\t *  @param {object} [init={}] Configuration object for DataTables. Options\n\t *    are defined by {@link DataTable.defaults}\n\t *  @requires jQuery 1.7+\n\t *\n\t *  @example\n\t *    // Basic initialisation\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable();\n\t *    } );\n\t *\n\t *  @example\n\t *    // Initialisation with configuration options - in this case, disable\n\t *    // pagination and sorting.\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable( {\n\t *        \"paginate\": false,\n\t *        \"sort\": false\n\t *      } );\n\t *    } );\n\t */\n\tvar DataTable = function ( options )\n\t{\n\t\t/**\n\t\t * Perform a jQuery selector action on the table's TR elements (from the tbody) and\n\t\t * return the resulting jQuery object.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter\n\t\t *    criterion (\"applied\") or all TR elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {object} jQuery object, filtered by the given selector.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Highlight every second row\n\t\t *      oTable.$('tr:odd').css('backgroundColor', 'blue');\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to rows with 'Webkit' in them, add a background colour and then\n\t\t *      // remove the filter, thus highlighting the 'Webkit' rows only.\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      oTable.$('tr', {\"search\": \"applied\"}).css('backgroundColor', 'blue');\n\t\t *      oTable.fnFilter('');\n\t\t *    } );\n\t\t */\n\t\tthis.$ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).$( sSelector, oOpts );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Almost identical to $ in operation, but in this case returns the data for the matched\n\t\t * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes\n\t\t * rather than any descendants, so the data can be obtained for the row/cell. If matching\n\t\t * rows are found, the data returned is the original data array/object that was used to\n\t\t * create the row (or a generated array if from a DOM source).\n\t\t *\n\t\t * This method is often useful in-combination with $ where both functions are given the\n\t\t * same parameters and the array indexes will match identically.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select elements that meet the current filter\n\t\t *    criterion (\"applied\") or all elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the data in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {array} Data for the matched elements. If any elements, as a result of the\n\t\t *    selector, were not TR, TD or TH elements in the DataTable, they will have a null\n\t\t *    entry in the array.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the data from the first row in the table\n\t\t *      var data = oTable._('tr:first');\n\t\t *\n\t\t *      // Do something useful with the data\n\t\t *      alert( \"First cell is: \"+data[0] );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to 'Webkit' and get all data for\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      var data = oTable._('tr', {\"search\": \"applied\"});\n\t\t *\n\t\t *      // Do something with the data\n\t\t *      alert( data.length+\" rows matched the search\" );\n\t\t *    } );\n\t\t */\n\t\tthis._ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).rows( sSelector, oOpts ).data();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Create a DataTables Api instance, with the currently selected tables for\n\t\t * the Api's context.\n\t\t * @param {boolean} [traditional=false] Set the API instance's context to be\n\t\t *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was\n\t\t *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),\n\t\t *   or if all tables captured in the jQuery object should be used.\n\t\t * @return {DataTables.Api}\n\t\t */\n\t\tthis.api = function ( traditional )\n\t\t{\n\t\t\treturn traditional ?\n\t\t\t\tnew _Api(\n\t\t\t\t\t_fnSettingsFromNode( this[ _ext.iApiIndex ] )\n\t\t\t\t) :\n\t\t\t\tnew _Api( this );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Add a single new row or multiple rows of data to the table. Please note\n\t\t * that this is suitable for client-side processing only - if you are using\n\t\t * server-side processing (i.e. \"bServerSide\": true), then to add data, you\n\t\t * must add it to the data source, i.e. the server-side, through an Ajax call.\n\t\t *  @param {array|object} data The data to be added to the table. This can be:\n\t\t *    <ul>\n\t\t *      <li>1D array of data - add a single row with the data provided</li>\n\t\t *      <li>2D array of arrays - add multiple rows in a single call</li>\n\t\t *      <li>object - data object when using <i>mData</i></li>\n\t\t *      <li>array of objects - multiple data objects when using <i>mData</i></li>\n\t\t *    </ul>\n\t\t *  @param {bool} [redraw=true] redraw the table or not\n\t\t *  @returns {array} An array of integers, representing the list of indexes in\n\t\t *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to\n\t\t *    the table.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Global var for counter\n\t\t *    var giCount = 2;\n\t\t *\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example').dataTable();\n\t\t *    } );\n\t\t *\n\t\t *    function fnClickAddRow() {\n\t\t *      $('#example').dataTable().fnAddData( [\n\t\t *        giCount+\".1\",\n\t\t *        giCount+\".2\",\n\t\t *        giCount+\".3\",\n\t\t *        giCount+\".4\" ]\n\t\t *      );\n\t\t *\n\t\t *      giCount++;\n\t\t *    }\n\t\t */\n\t\tthis.fnAddData = function( data, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\t/* Check if we want to add multiple rows or not */\n\t\t\tvar rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?\n\t\t\t\tapi.rows.add( data ) :\n\t\t\t\tapi.row.add( data );\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn rows.flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will make DataTables recalculate the column sizes, based on the data\n\t\t * contained in the table and the sizes applied to the columns (in the DOM, CSS or\n\t\t * through the sWidth parameter). This can be useful when the width of the table's\n\t\t * parent element changes (for example a window resize).\n\t\t *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable( {\n\t\t *        \"sScrollY\": \"200px\",\n\t\t *        \"bPaginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      $(window).on('resize', function () {\n\t\t *        oTable.fnAdjustColumnSizing();\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnAdjustColumnSizing = function ( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).columns.adjust();\n\t\t\tvar settings = api.settings()[0];\n\t\t\tvar scroll = settings.oScroll;\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw( false );\n\t\t\t}\n\t\t\telse if ( scroll.sX !== \"\" || scroll.sY !== \"\" ) {\n\t\t\t\t/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */\n\t\t\t\t_fnScrollDraw( settings );\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Quickly and simply clear a table\n\t\t *  @param {bool} [bRedraw=true] redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)\n\t\t *      oTable.fnClearTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClearTable = function( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).clear();\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * The exact opposite of 'opening' a row, this function will close any rows which\n\t\t * are currently 'open'.\n\t\t *  @param {node} nTr the table row to 'close'\n\t\t *  @returns {int} 0 on success, or 1 if failed (can't find the row)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClose = function( nTr )\n\t\t{\n\t\t\tthis.api( true ).row( nTr ).child.hide();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Remove a row for the table\n\t\t *  @param {mixed} target The index of the row from aoData to be deleted, or\n\t\t *    the TR element you want to delete\n\t\t *  @param {function|null} [callBack] Callback function\n\t\t *  @param {bool} [redraw=true] Redraw the table or not\n\t\t *  @returns {array} The row that was deleted\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately remove the first row\n\t\t *      oTable.fnDeleteRow( 0 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnDeleteRow = function( target, callback, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar rows = api.rows( target );\n\t\t\tvar settings = rows.settings()[0];\n\t\t\tvar data = settings.aoData[ rows[0][0] ];\n\t\t\n\t\t\trows.remove();\n\t\t\n\t\t\tif ( callback ) {\n\t\t\t\tcallback.call( this, settings, data );\n\t\t\t}\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn data;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Restore the table to it's original state in the DOM by removing all of DataTables\n\t\t * enhancements, alterations to the DOM structure of the table and event listeners.\n\t\t *  @param {boolean} [remove=false] Completely remove the table from the DOM\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      // This example is fairly pointless in reality, but shows how fnDestroy can be used\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnDestroy();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDestroy = function ( remove )\n\t\t{\n\t\t\tthis.api( true ).destroy( remove );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Redraw the table\n\t\t *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)\n\t\t *      oTable.fnDraw();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDraw = function( complete )\n\t\t{\n\t\t\t// Note that this isn't an exact match to the old call to _fnDraw - it takes\n\t\t\t// into account the new data, but can hold position.\n\t\t\tthis.api( true ).draw( complete );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Filter the input based on data\n\t\t *  @param {string} sInput String to filter the table on\n\t\t *  @param {int|null} [iColumn] Column to limit filtering to\n\t\t *  @param {bool} [bRegex=false] Treat as regular expression or not\n\t\t *  @param {bool} [bSmart=true] Perform smart filtering or not\n\t\t *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)\n\t\t *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sometime later - filter...\n\t\t *      oTable.fnFilter( 'test string' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === null || iColumn === undefined ) {\n\t\t\t\tapi.search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\n\t\t\tapi.draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the data for the whole table, an individual row or an individual cell based on the\n\t\t * provided parameters.\n\t\t *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as\n\t\t *    a TR node then the data source for the whole row will be returned. If given as a\n\t\t *    TD/TH cell node then iCol will be automatically calculated and the data for the\n\t\t *    cell returned. If given as an integer, then this is treated as the aoData internal\n\t\t *    data index for the row (see fnGetPosition) and the data for that row used.\n\t\t *  @param {int} [col] Optional column index that you want the data of.\n\t\t *  @returns {array|object|string} If mRow is undefined, then the data for all rows is\n\t\t *    returned. If mRow is defined, just data for that row, and is iCol is\n\t\t *    defined, only data for the designated cell is returned.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Row data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('tr').click( function () {\n\t\t *        var data = oTable.fnGetData( this );\n\t\t *        // ... do something with the array / object of data for the row\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Individual cell data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('td').click( function () {\n\t\t *        var sData = oTable.fnGetData( this );\n\t\t *        alert( 'The cell clicked on had the value of '+sData );\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetData = function( src, col )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( src !== undefined ) {\n\t\t\t\tvar type = src.nodeName ? src.nodeName.toLowerCase() : '';\n\t\t\n\t\t\t\treturn col !== undefined || type == 'td' || type == 'th' ?\n\t\t\t\t\tapi.cell( src, col ).data() :\n\t\t\t\t\tapi.row( src ).data() || null;\n\t\t\t}\n\t\t\n\t\t\treturn api.data().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get an array of the TR nodes that are used in the table's body. Note that you will\n\t\t * typically want to use the '$' API method in preference to this as it is more\n\t\t * flexible.\n\t\t *  @param {int} [iRow] Optional row index for the TR element you want\n\t\t *  @returns {array|node} If iRow is undefined, returns an array of all TR elements\n\t\t *    in the table's body, or iRow is defined, just the TR element requested.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the nodes from the table\n\t\t *      var nNodes = oTable.fnGetNodes( );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetNodes = function( iRow )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\treturn iRow !== undefined ?\n\t\t\t\tapi.row( iRow ).node() :\n\t\t\t\tapi.rows().nodes().flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the array indexes of a particular cell from it's DOM element\n\t\t * and column index including hidden columns\n\t\t *  @param {node} node this can either be a TR, TD or TH in the table's body\n\t\t *  @returns {int} If nNode is given as a TR, then a single index is returned, or\n\t\t *    if given as a cell, an array of [row index, column index (visible),\n\t\t *    column index (all)] is given.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example tbody td').click( function () {\n\t\t *        // Get the position of the current data from the node\n\t\t *        var aPos = oTable.fnGetPosition( this );\n\t\t *\n\t\t *        // Get the data array for this row\n\t\t *        var aData = oTable.fnGetData( aPos[0] );\n\t\t *\n\t\t *        // Update the data array and return the value\n\t\t *        aData[ aPos[1] ] = 'clicked';\n\t\t *        this.innerHTML = 'clicked';\n\t\t *      } );\n\t\t *\n\t\t *      // Init DataTables\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetPosition = function( node )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar nodeName = node.nodeName.toUpperCase();\n\t\t\n\t\t\tif ( nodeName == 'TR' ) {\n\t\t\t\treturn api.row( node ).index();\n\t\t\t}\n\t\t\telse if ( nodeName == 'TD' || nodeName == 'TH' ) {\n\t\t\t\tvar cell = api.cell( node ).index();\n\t\t\n\t\t\t\treturn [\n\t\t\t\t\tcell.row,\n\t\t\t\t\tcell.columnVisible,\n\t\t\t\t\tcell.column\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Check to see if a row is 'open' or not.\n\t\t *  @param {node} nTr the table row to check\n\t\t *  @returns {boolean} true if the row is currently open, false otherwise\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnIsOpen = function( nTr )\n\t\t{\n\t\t\treturn this.api( true ).row( nTr ).child.isShown();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will place a new row directly after a row which is currently\n\t\t * on display on the page, with the HTML contents that is passed into the\n\t\t * function. This can be used, for example, to ask for confirmation that a\n\t\t * particular record should be deleted.\n\t\t *  @param {node} nTr The table row to 'open'\n\t\t *  @param {string|node|jQuery} mHtml The HTML to put into the row\n\t\t *  @param {string} sClass Class to give the new TD cell\n\t\t *  @returns {node} The row opened. Note that if the table row passed in as the\n\t\t *    first parameter, is not found in the table, this method will silently\n\t\t *    return.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnOpen = function( nTr, mHtml, sClass )\n\t\t{\n\t\t\treturn this.api( true )\n\t\t\t\t.row( nTr )\n\t\t\t\t.child( mHtml, sClass )\n\t\t\t\t.show()\n\t\t\t\t.child()[0];\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Change the pagination - provides the internal logic for pagination in a simple API\n\t\t * function. With this function you can have a DataTables table go to the next,\n\t\t * previous, first or last pages.\n\t\t *  @param {string|int} mAction Paging action to take: \"first\", \"previous\", \"next\" or \"last\"\n\t\t *    or page number to jump to (integer), note that page 0 is the first page.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnPageChange( 'next' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnPageChange = function ( mAction, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).page( mAction );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw(false);\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Show a particular column\n\t\t *  @param {int} iCol The column whose display should be changed\n\t\t *  @param {bool} bShow Show (true) or hide (false) the column\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Hide the second column after initialisation\n\t\t *      oTable.fnSetColumnVis( 1, false );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSetColumnVis = function ( iCol, bShow, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).column( iCol ).visible( bShow );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.columns.adjust().draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the settings for a particular table for external manipulation\n\t\t *  @returns {object} DataTables settings object. See\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      var oSettings = oTable.fnSettings();\n\t\t *\n\t\t *      // Show an example parameter from the settings\n\t\t *      alert( oSettings._iDisplayStart );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSettings = function()\n\t\t{\n\t\t\treturn _fnSettingsFromNode( this[_ext.iApiIndex] );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Sort the table by a particular column\n\t\t *  @param {int} iCol the data index to sort on. Note that this will not match the\n\t\t *    'display index' if you have hidden data entries\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort immediately with columns 0 and 1\n\t\t *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSort = function( aaSort )\n\t\t{\n\t\t\tthis.api( true ).order( aaSort ).draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Attach a sort listener to an element for a given column\n\t\t *  @param {node} nNode the element to attach the sort listener to\n\t\t *  @param {int} iColumn the column that a click on this node will sort on\n\t\t *  @param {function} [fnCallback] callback function when sort is run\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort on column 1, when 'sorter' is clicked on\n\t\t *      oTable.fnSortListener( document.getElementById('sorter'), 1 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSortListener = function( nNode, iColumn, fnCallback )\n\t\t{\n\t\t\tthis.api( true ).order.listener( nNode, iColumn, fnCallback );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Update a table cell or row - this method will accept either a single value to\n\t\t * update the cell with, an array of values with one element for each column or\n\t\t * an object in the same format as the original data source. The function is\n\t\t * self-referencing in order to make the multi column updates easier.\n\t\t *  @param {object|array|string} mData Data to update the cell/row with\n\t\t *  @param {node|int} mRow TR element you want to update or the aoData index\n\t\t *  @param {int} [iColumn] The column to update, give as null or undefined to\n\t\t *    update a whole row.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @param {bool} [bAction=true] Perform pre-draw actions or not\n\t\t *  @returns {int} 0 on success, 1 on error\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell\n\t\t *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row\n\t\t *    } );\n\t\t */\n\t\tthis.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === undefined || iColumn === null ) {\n\t\t\t\tapi.row( mRow ).data( mData );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.cell( mRow, iColumn ).data( mData );\n\t\t\t}\n\t\t\n\t\t\tif ( bAction === undefined || bAction ) {\n\t\t\t\tapi.columns.adjust();\n\t\t\t}\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Provide a common method for plug-ins to check the version of DataTables being used, in order\n\t\t * to ensure compatibility.\n\t\t *  @param {string} sVersion Version string to check for, in the format \"X.Y.Z\". Note that the\n\t\t *    formats \"X\" and \"X.Y\" are also acceptable.\n\t\t *  @returns {boolean} true if this version of DataTables is greater or equal to the required\n\t\t *    version, or false if this version of DataTales is not suitable\n\t\t *  @method\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      alert( oTable.fnVersionCheck( '1.9.0' ) );\n\t\t *    } );\n\t\t */\n\t\tthis.fnVersionCheck = _ext.fnVersionCheck;\n\t\t\n\n\t\tvar _that = this;\n\t\tvar emptyInit = options === undefined;\n\t\tvar len = this.length;\n\n\t\tif ( emptyInit ) {\n\t\t\toptions = {};\n\t\t}\n\n\t\tthis.oApi = this.internal = _ext.internal;\n\n\t\t// Extend with old style plug-in API methods\n\t\tfor ( var fn in DataTable.ext.internal ) {\n\t\t\tif ( fn ) {\n\t\t\t\tthis[fn] = _fnExternApiFunc(fn);\n\t\t\t}\n\t\t}\n\n\t\tthis.each(function() {\n\t\t\t// For each initialisation we want to give it a clean initialisation\n\t\t\t// object that can be bashed around\n\t\t\tvar o = {};\n\t\t\tvar oInit = len > 1 ? // optimisation for single table case\n\t\t\t\t_fnExtend( o, options, true ) :\n\t\t\t\toptions;\n\n\t\t\t/*global oInit,_that,emptyInit*/\n\t\t\tvar i=0, iLen, j, jLen, k, kLen;\n\t\t\tvar sId = this.getAttribute( 'id' );\n\t\t\tvar bInitHandedOff = false;\n\t\t\tvar defaults = DataTable.defaults;\n\t\t\tvar $this = $(this);\n\t\t\t\n\t\t\t\n\t\t\t/* Sanity check */\n\t\t\tif ( this.nodeName.toLowerCase() != 'table' )\n\t\t\t{\n\t\t\t\t_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t/* Backwards compatibility for the defaults */\n\t\t\t_fnCompatOpts( defaults );\n\t\t\t_fnCompatCols( defaults.column );\n\t\t\t\n\t\t\t/* Convert the camel-case defaults to Hungarian */\n\t\t\t_fnCamelToHungarian( defaults, defaults, true );\n\t\t\t_fnCamelToHungarian( defaults.column, defaults.column, true );\n\t\t\t\n\t\t\t/* Setting up the initialisation object */\n\t\t\t_fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/* Check to see if we are re-initialising a table */\n\t\t\tvar allSettings = DataTable.settings;\n\t\t\tfor ( i=0, iLen=allSettings.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tvar s = allSettings[i];\n\t\t\t\n\t\t\t\t/* Base check on table node */\n\t\t\t\tif (\n\t\t\t\t\ts.nTable == this ||\n\t\t\t\t\t(s.nTHead && s.nTHead.parentNode == this) ||\n\t\t\t\t\t(s.nTFoot && s.nTFoot.parentNode == this)\n\t\t\t\t) {\n\t\t\t\t\tvar bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;\n\t\t\t\t\tvar bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;\n\t\t\t\n\t\t\t\t\tif ( emptyInit || bRetrieve )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn s.oInstance;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( bDestroy )\n\t\t\t\t\t{\n\t\t\t\t\t\ts.oInstance.fnDestroy();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* If the element we are initialising has the same ID as a table which was previously\n\t\t\t\t * initialised, but the table nodes don't match (from before) then we destroy the old\n\t\t\t\t * instance by simply deleting it. This is under the assumption that the table has been\n\t\t\t\t * destroyed by other methods. Anyone using non-id selectors will need to do this manually\n\t\t\t\t */\n\t\t\t\tif ( s.sTableId == this.id )\n\t\t\t\t{\n\t\t\t\t\tallSettings.splice( i, 1 );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Ensure the table has an ID - required for accessibility */\n\t\t\tif ( sId === null || sId === \"\" )\n\t\t\t{\n\t\t\t\tsId = \"DataTables_Table_\"+(DataTable.ext._unique++);\n\t\t\t\tthis.id = sId;\n\t\t\t}\n\t\t\t\n\t\t\t/* Create the settings object for this table and set some of the default parameters */\n\t\t\tvar oSettings = $.extend( true, {}, DataTable.models.oSettings, {\n\t\t\t\t\"sDestroyWidth\": $this[0].style.width,\n\t\t\t\t\"sInstance\":     sId,\n\t\t\t\t\"sTableId\":      sId\n\t\t\t} );\n\t\t\toSettings.nTable = this;\n\t\t\toSettings.oApi   = _that.internal;\n\t\t\toSettings.oInit  = oInit;\n\t\t\t\n\t\t\tallSettings.push( oSettings );\n\t\t\t\n\t\t\t// Need to add the instance after the instance after the settings object has been added\n\t\t\t// to the settings array, so we can self reference the table instance if more than one\n\t\t\toSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();\n\t\t\t\n\t\t\t// Backwards compatibility, before we apply all the defaults\n\t\t\t_fnCompatOpts( oInit );\n\t\t\t_fnLanguageCompat( oInit.oLanguage );\n\t\t\t\n\t\t\t// If the length menu is given, but the init display length is not, use the length menu\n\t\t\tif ( oInit.aLengthMenu && ! oInit.iDisplayLength )\n\t\t\t{\n\t\t\t\toInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?\n\t\t\t\t\toInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];\n\t\t\t}\n\t\t\t\n\t\t\t// Apply the defaults and init options to make a single init object will all\n\t\t\t// options defined from defaults and instance options.\n\t\t\toInit = _fnExtend( $.extend( true, {}, defaults ), oInit );\n\t\t\t\n\t\t\t\n\t\t\t// Map the initialisation options onto the settings object\n\t\t\t_fnMap( oSettings.oFeatures, oInit, [\n\t\t\t\t\"bPaginate\",\n\t\t\t\t\"bLengthChange\",\n\t\t\t\t\"bFilter\",\n\t\t\t\t\"bSort\",\n\t\t\t\t\"bSortMulti\",\n\t\t\t\t\"bInfo\",\n\t\t\t\t\"bProcessing\",\n\t\t\t\t\"bAutoWidth\",\n\t\t\t\t\"bSortClasses\",\n\t\t\t\t\"bServerSide\",\n\t\t\t\t\"bDeferRender\"\n\t\t\t] );\n\t\t\t_fnMap( oSettings, oInit, [\n\t\t\t\t\"asStripeClasses\",\n\t\t\t\t\"ajax\",\n\t\t\t\t\"fnServerData\",\n\t\t\t\t\"fnFormatNumber\",\n\t\t\t\t\"sServerMethod\",\n\t\t\t\t\"aaSorting\",\n\t\t\t\t\"aaSortingFixed\",\n\t\t\t\t\"aLengthMenu\",\n\t\t\t\t\"sPaginationType\",\n\t\t\t\t\"sAjaxSource\",\n\t\t\t\t\"sAjaxDataProp\",\n\t\t\t\t\"iStateDuration\",\n\t\t\t\t\"sDom\",\n\t\t\t\t\"bSortCellsTop\",\n\t\t\t\t\"iTabIndex\",\n\t\t\t\t\"fnStateLoadCallback\",\n\t\t\t\t\"fnStateSaveCallback\",\n\t\t\t\t\"renderer\",\n\t\t\t\t\"searchDelay\",\n\t\t\t\t\"rowId\",\n\t\t\t\t[ \"iCookieDuration\", \"iStateDuration\" ], // backwards compat\n\t\t\t\t[ \"oSearch\", \"oPreviousSearch\" ],\n\t\t\t\t[ \"aoSearchCols\", \"aoPreSearchCols\" ],\n\t\t\t\t[ \"iDisplayLength\", \"_iDisplayLength\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oScroll, oInit, [\n\t\t\t\t[ \"sScrollX\", \"sX\" ],\n\t\t\t\t[ \"sScrollXInner\", \"sXInner\" ],\n\t\t\t\t[ \"sScrollY\", \"sY\" ],\n\t\t\t\t[ \"bScrollCollapse\", \"bCollapse\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oLanguage, oInit, \"fnInfoCallback\" );\n\t\t\t\n\t\t\t/* Callback functions which are array driven */\n\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );\n\t\t\t\n\t\t\toSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );\n\t\t\t\n\t\t\t/* Browser support detection */\n\t\t\t_fnBrowserDetect( oSettings );\n\t\t\t\n\t\t\tvar oClasses = oSettings.oClasses;\n\t\t\t\n\t\t\t$.extend( oClasses, DataTable.ext.classes, oInit.oClasses );\n\t\t\t$this.addClass( oClasses.sTable );\n\t\t\t\n\t\t\t\n\t\t\tif ( oSettings.iInitDisplayStart === undefined )\n\t\t\t{\n\t\t\t\t/* Display start point, taking into account the save saving */\n\t\t\t\toSettings.iInitDisplayStart = oInit.iDisplayStart;\n\t\t\t\toSettings._iDisplayStart = oInit.iDisplayStart;\n\t\t\t}\n\t\t\t\n\t\t\tif ( oInit.iDeferLoading !== null )\n\t\t\t{\n\t\t\t\toSettings.bDeferLoading = true;\n\t\t\t\tvar tmp = $.isArray( oInit.iDeferLoading );\n\t\t\t\toSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;\n\t\t\t\toSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;\n\t\t\t}\n\t\t\t\n\t\t\t/* Language definitions */\n\t\t\tvar oLanguage = oSettings.oLanguage;\n\t\t\t$.extend( true, oLanguage, oInit.oLanguage );\n\t\t\t\n\t\t\tif ( oLanguage.sUrl )\n\t\t\t{\n\t\t\t\t/* Get the language definitions from a file - because this Ajax call makes the language\n\t\t\t\t * get async to the remainder of this function we use bInitHandedOff to indicate that\n\t\t\t\t * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor\n\t\t\t\t */\n\t\t\t\t$.ajax( {\n\t\t\t\t\tdataType: 'json',\n\t\t\t\t\turl: oLanguage.sUrl,\n\t\t\t\t\tsuccess: function ( json ) {\n\t\t\t\t\t\t_fnLanguageCompat( json );\n\t\t\t\t\t\t_fnCamelToHungarian( defaults.oLanguage, json );\n\t\t\t\t\t\t$.extend( true, oLanguage, json );\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t},\n\t\t\t\t\terror: function () {\n\t\t\t\t\t\t// Error occurred loading language file, continue on as best we can\n\t\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\tbInitHandedOff = true;\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Stripes\n\t\t\t */\n\t\t\tif ( oInit.asStripeClasses === null )\n\t\t\t{\n\t\t\t\toSettings.asStripeClasses =[\n\t\t\t\t\toClasses.sStripeOdd,\n\t\t\t\t\toClasses.sStripeEven\n\t\t\t\t];\n\t\t\t}\n\t\t\t\n\t\t\t/* Remove row stripe classes if they are already on the table row */\n\t\t\tvar stripeClasses = oSettings.asStripeClasses;\n\t\t\tvar rowOne = $this.children('tbody').find('tr').eq(0);\n\t\t\tif ( $.inArray( true, $.map( stripeClasses, function(el, i) {\n\t\t\t\treturn rowOne.hasClass(el);\n\t\t\t} ) ) !== -1 ) {\n\t\t\t\t$('tbody tr', this).removeClass( stripeClasses.join(' ') );\n\t\t\t\toSettings.asDestroyStripes = stripeClasses.slice();\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Columns\n\t\t\t * See if we should load columns automatically or use defined ones\n\t\t\t */\n\t\t\tvar anThs = [];\n\t\t\tvar aoColumnsInit;\n\t\t\tvar nThead = this.getElementsByTagName('thead');\n\t\t\tif ( nThead.length !== 0 )\n\t\t\t{\n\t\t\t\t_fnDetectHeader( oSettings.aoHeader, nThead[0] );\n\t\t\t\tanThs = _fnGetUniqueThs( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* If not given a column array, generate one with nulls */\n\t\t\tif ( oInit.aoColumns === null )\n\t\t\t{\n\t\t\t\taoColumnsInit = [];\n\t\t\t\tfor ( i=0, iLen=anThs.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\taoColumnsInit.push( null );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taoColumnsInit = oInit.aoColumns;\n\t\t\t}\n\t\t\t\n\t\t\t/* Add the columns */\n\t\t\tfor ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t_fnAddColumn( oSettings, anThs ? anThs[i] : null );\n\t\t\t}\n\t\t\t\n\t\t\t/* Apply the column definitions */\n\t\t\t_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {\n\t\t\t\t_fnColumnOptions( oSettings, iCol, oDef );\n\t\t\t} );\n\t\t\t\n\t\t\t/* HTML5 attribute detection - build an mData object automatically if the\n\t\t\t * attributes are found\n\t\t\t */\n\t\t\tif ( rowOne.length ) {\n\t\t\t\tvar a = function ( cell, name ) {\n\t\t\t\t\treturn cell.getAttribute( 'data-'+name ) !== null ? name : null;\n\t\t\t\t};\n\t\t\t\n\t\t\t\t$( rowOne[0] ).children('th, td').each( function (i, cell) {\n\t\t\t\t\tvar col = oSettings.aoColumns[i];\n\t\t\t\n\t\t\t\t\tif ( col.mData === i ) {\n\t\t\t\t\t\tvar sort = a( cell, 'sort' ) || a( cell, 'order' );\n\t\t\t\t\t\tvar filter = a( cell, 'filter' ) || a( cell, 'search' );\n\t\t\t\n\t\t\t\t\t\tif ( sort !== null || filter !== null ) {\n\t\t\t\t\t\t\tcol.mData = {\n\t\t\t\t\t\t\t\t_:      i+'.display',\n\t\t\t\t\t\t\t\tsort:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\ttype:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\tfilter: filter !== null ? i+'.@data-'+filter : undefined\n\t\t\t\t\t\t\t};\n\t\t\t\n\t\t\t\t\t\t\t_fnColumnOptions( oSettings, i );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\t\n\t\t\tvar features = oSettings.oFeatures;\n\t\t\tvar loadedInit = function () {\n\t\t\t\t/*\n\t\t\t\t * Sorting\n\t\t\t\t * @todo For modularisation (1.11) this needs to do into a sort start up handler\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// If aaSorting is not defined, then we use the first indicator in asSorting\n\t\t\t\t// in case that has been altered, so the default sort reflects that option\n\t\t\t\tif ( oInit.aaSorting === undefined ) {\n\t\t\t\t\tvar sorting = oSettings.aaSorting;\n\t\t\t\t\tfor ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {\n\t\t\t\t\t\tsorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Do a first pass on the sorting classes (allows any size changes to be taken into\n\t\t\t\t * account, and also will apply sorting disabled classes if disabled\n\t\t\t\t */\n\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\n\t\t\t\tif ( features.bSort ) {\n\t\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\t\tif ( oSettings.bSorted ) {\n\t\t\t\t\t\t\tvar aSort = _fnSortFlatten( oSettings );\n\t\t\t\t\t\t\tvar sortedColumns = {};\n\t\t\t\n\t\t\t\t\t\t\t$.each( aSort, function (i, val) {\n\t\t\t\t\t\t\t\tsortedColumns[ val.src ] = val.dir;\n\t\t\t\t\t\t\t} );\n\t\t\t\n\t\t\t\t\t\t\t_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );\n\t\t\t\t\t\t\t_fnSortAria( oSettings );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\tif ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {\n\t\t\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\t\t}\n\t\t\t\t}, 'sc' );\n\t\t\t\n\t\t\t\n\t\t\t\t/*\n\t\t\t\t * Final init\n\t\t\t\t * Cache the header, body and footer as required, creating them if needed\n\t\t\t\t */\n\t\t\t\n\t\t\t\t// Work around for Webkit bug 83867 - store the caption-side before removing from doc\n\t\t\t\tvar captions = $this.children('caption').each( function () {\n\t\t\t\t\tthis._captionSide = $(this).css('caption-side');\n\t\t\t\t} );\n\t\t\t\n\t\t\t\tvar thead = $this.children('thead');\n\t\t\t\tif ( thead.length === 0 ) {\n\t\t\t\t\tthead = $('<thead/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTHead = thead[0];\n\t\t\t\n\t\t\t\tvar tbody = $this.children('tbody');\n\t\t\t\tif ( tbody.length === 0 ) {\n\t\t\t\t\ttbody = $('<tbody/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\toSettings.nTBody = tbody[0];\n\t\t\t\n\t\t\t\tvar tfoot = $this.children('tfoot');\n\t\t\t\tif ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== \"\" || oSettings.oScroll.sY !== \"\") ) {\n\t\t\t\t\t// If we are a scrolling table, and no footer has been given, then we need to create\n\t\t\t\t\t// a tfoot element for the caption element to be appended to\n\t\t\t\t\ttfoot = $('<tfoot/>').appendTo($this);\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( tfoot.length === 0 || tfoot.children().length === 0 ) {\n\t\t\t\t\t$this.addClass( oClasses.sNoFooter );\n\t\t\t\t}\n\t\t\t\telse if ( tfoot.length > 0 ) {\n\t\t\t\t\toSettings.nTFoot = tfoot[0];\n\t\t\t\t\t_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Check if there is data passing into the constructor */\n\t\t\t\tif ( oInit.aaData ) {\n\t\t\t\t\tfor ( i=0 ; i<oInit.aaData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( oSettings, oInit.aaData[ i ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {\n\t\t\t\t\t/* Grab the data from the page - only do this when deferred loading or no Ajax\n\t\t\t\t\t * source since there is no point in reading the DOM data if we are then going\n\t\t\t\t\t * to replace it with Ajax data\n\t\t\t\t\t */\n\t\t\t\t\t_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* Copy the data index array */\n\t\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\n\t\t\t\t/* Initialisation complete - table can be drawn */\n\t\t\t\toSettings.bInitialised = true;\n\t\t\t\n\t\t\t\t/* Check if we need to initialise the table (it might not have been handed off to the\n\t\t\t\t * language processor)\n\t\t\t\t */\n\t\t\t\tif ( bInitHandedOff === false ) {\n\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t}\n\t\t\t};\n\t\t\t\n\t\t\t/* Must be done after everything which can be overridden by the state saving! */\n\t\t\tif ( oInit.bStateSave )\n\t\t\t{\n\t\t\t\tfeatures.bStateSave = true;\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );\n\t\t\t\t_fnLoadState( oSettings, oInit, loadedInit );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadedInit();\n\t\t\t}\n\t\t\t\n\t\t} );\n\t\t_that = null;\n\t\treturn this;\n\t};\n\n\t\n\t/*\n\t * It is useful to have variables which are scoped locally so only the\n\t * DataTables functions can access them and they don't leak into global space.\n\t * At the same time these functions are often useful over multiple files in the\n\t * core and API, so we list, or at least document, all variables which are used\n\t * by DataTables as private variables here. This also ensures that there is no\n\t * clashing of variable names and that they can easily referenced for reuse.\n\t */\n\t\n\t\n\t// Defined else where\n\t//  _selector_run\n\t//  _selector_opts\n\t//  _selector_first\n\t//  _selector_row_indexes\n\t\n\tvar _ext; // DataTable.ext\n\tvar _Api; // DataTable.Api\n\tvar _api_register; // DataTable.Api.register\n\tvar _api_registerPlural; // DataTable.Api.registerPlural\n\t\n\tvar _re_dic = {};\n\tvar _re_new_lines = /[\\r\\n]/g;\n\tvar _re_html = /<.*?>/g;\n\t\n\t// This is not strict ISO8601 - Date.parse() is quite lax, although\n\t// implementations differ between browsers.\n\tvar _re_date = /^\\d{2,4}[\\.\\/\\-]\\d{1,2}[\\.\\/\\-]\\d{1,2}([T ]{1}\\d{1,2}[:\\.]\\d{2}([\\.:]\\d{2})?)?$/;\n\t\n\t// Escape regular expression special characters\n\tvar _re_escape_regex = new RegExp( '(\\\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\\\', '$', '^', '-' ].join('|\\\\') + ')', 'g' );\n\t\n\t// http://en.wikipedia.org/wiki/Foreign_exchange_market\n\t// - \\u20BD - Russian ruble.\n\t// - \\u20a9 - South Korean Won\n\t// - \\u20BA - Turkish Lira\n\t// - \\u20B9 - Indian Rupee\n\t// - R - Brazil (R$) and South Africa\n\t// - fr - Swiss Franc\n\t// - kr - Swedish krona, Norwegian krone and Danish krone\n\t// - \\u2009 is thin space and \\u202F is narrow no-break space, both used in many\n\t// - Ƀ - Bitcoin\n\t// - Ξ - Ethereum\n\t//   standards as thousands separators.\n\tvar _re_formatted_numeric = /[',$£€¥%\\u2009\\u202F\\u20BD\\u20a9\\u20BArfkɃΞ]/gi;\n\t\n\t\n\tvar _empty = function ( d ) {\n\t\treturn !d || d === true || d === '-' ? true : false;\n\t};\n\t\n\t\n\tvar _intVal = function ( s ) {\n\t\tvar integer = parseInt( s, 10 );\n\t\treturn !isNaN(integer) && isFinite(s) ? integer : null;\n\t};\n\t\n\t// Convert from a formatted number with characters other than `.` as the\n\t// decimal place, to a Javascript number\n\tvar _numToDecimal = function ( num, decimalPoint ) {\n\t\t// Cache created regular expressions for speed as this function is called often\n\t\tif ( ! _re_dic[ decimalPoint ] ) {\n\t\t\t_re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );\n\t\t}\n\t\treturn typeof num === 'string' && decimalPoint !== '.' ?\n\t\t\tnum.replace( /\\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :\n\t\t\tnum;\n\t};\n\t\n\t\n\tvar _isNumber = function ( d, decimalPoint, formatted ) {\n\t\tvar strType = typeof d === 'string';\n\t\n\t\t// If empty return immediately so there must be a number if it is a\n\t\t// formatted string (this stops the string \"k\", or \"kr\", etc being detected\n\t\t// as a formatted number for currency\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tif ( decimalPoint && strType ) {\n\t\t\td = _numToDecimal( d, decimalPoint );\n\t\t}\n\t\n\t\tif ( formatted && strType ) {\n\t\t\td = d.replace( _re_formatted_numeric, '' );\n\t\t}\n\t\n\t\treturn !isNaN( parseFloat(d) ) && isFinite( d );\n\t};\n\t\n\t\n\t// A string without HTML in it can be considered to be HTML still\n\tvar _isHtml = function ( d ) {\n\t\treturn _empty( d ) || typeof d === 'string';\n\t};\n\t\n\t\n\tvar _htmlNumeric = function ( d, decimalPoint, formatted ) {\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tvar html = _isHtml( d );\n\t\treturn ! html ?\n\t\t\tnull :\n\t\t\t_isNumber( _stripHtml( d ), decimalPoint, formatted ) ?\n\t\t\t\ttrue :\n\t\t\t\tnull;\n\t};\n\t\n\t\n\tvar _pluck = function ( a, prop, prop2 ) {\n\t\tvar out = [];\n\t\tvar i=0, ien=a.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] && a[i][ prop ] ) {\n\t\t\t\t\tout.push( a[i][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] ) {\n\t\t\t\t\tout.push( a[i][ prop ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t// Basically the same as _pluck, but rather than looping over `a` we use `order`\n\t// as the indexes to pick from `a`\n\tvar _pluck_order = function ( a, order, prop, prop2 )\n\t{\n\t\tvar out = [];\n\t\tvar i=0, ien=order.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[ order[i] ][ prop ] ) {\n\t\t\t\t\tout.push( a[ order[i] ][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tout.push( a[ order[i] ][ prop ] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _range = function ( len, start )\n\t{\n\t\tvar out = [];\n\t\tvar end;\n\t\n\t\tif ( start === undefined ) {\n\t\t\tstart = 0;\n\t\t\tend = len;\n\t\t}\n\t\telse {\n\t\t\tend = start;\n\t\t\tstart = len;\n\t\t}\n\t\n\t\tfor ( var i=start ; i<end ; i++ ) {\n\t\t\tout.push( i );\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _removeEmpty = function ( a )\n\t{\n\t\tvar out = [];\n\t\n\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\tif ( a[i] ) { // careful - will remove all falsy values!\n\t\t\t\tout.push( a[i] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _stripHtml = function ( d ) {\n\t\treturn d.replace( _re_html, '' );\n\t};\n\t\n\t\n\t/**\n\t * Determine if all values in the array are unique. This means we can short\n\t * cut the _unique method at the cost of a single loop. A sorted array is used\n\t * to easily check the values.\n\t *\n\t * @param  {array} src Source array\n\t * @return {boolean} true if all unique, false otherwise\n\t * @ignore\n\t */\n\tvar _areAllUnique = function ( src ) {\n\t\tif ( src.length < 2 ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tvar sorted = src.slice().sort();\n\t\tvar last = sorted[0];\n\t\n\t\tfor ( var i=1, ien=sorted.length ; i<ien ; i++ ) {\n\t\t\tif ( sorted[i] === last ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\n\t\t\tlast = sorted[i];\n\t\t}\n\t\n\t\treturn true;\n\t};\n\t\n\t\n\t/**\n\t * Find the unique elements in a source array.\n\t *\n\t * @param  {array} src Source array\n\t * @return {array} Array of unique items\n\t * @ignore\n\t */\n\tvar _unique = function ( src )\n\t{\n\t\tif ( _areAllUnique( src ) ) {\n\t\t\treturn src.slice();\n\t\t}\n\t\n\t\t// A faster unique method is to use object keys to identify used values,\n\t\t// but this doesn't work with arrays or objects, which we must also\n\t\t// consider. See jsperf.com/compare-array-unique-versions/4 for more\n\t\t// information.\n\t\tvar\n\t\t\tout = [],\n\t\t\tval,\n\t\t\ti, ien=src.length,\n\t\t\tj, k=0;\n\t\n\t\tagain: for ( i=0 ; i<ien ; i++ ) {\n\t\t\tval = src[i];\n\t\n\t\t\tfor ( j=0 ; j<k ; j++ ) {\n\t\t\t\tif ( out[j] === val ) {\n\t\t\t\t\tcontinue again;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tout.push( val );\n\t\t\tk++;\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t/**\n\t * DataTables utility methods\n\t * \n\t * This namespace provides helper methods that DataTables uses internally to\n\t * create a DataTable, but which are not exclusively used only for DataTables.\n\t * These methods can be used by extension authors to save the duplication of\n\t * code.\n\t *\n\t *  @namespace\n\t */\n\tDataTable.util = {\n\t\t/**\n\t\t * Throttle the calls to a function. Arguments and context are maintained\n\t\t * for the throttled function.\n\t\t *\n\t\t * @param {function} fn Function to be called\n\t\t * @param {integer} freq Call frequency in mS\n\t\t * @return {function} Wrapped function\n\t\t */\n\t\tthrottle: function ( fn, freq ) {\n\t\t\tvar\n\t\t\t\tfrequency = freq !== undefined ? freq : 200,\n\t\t\t\tlast,\n\t\t\t\ttimer;\n\t\n\t\t\treturn function () {\n\t\t\t\tvar\n\t\t\t\t\tthat = this,\n\t\t\t\t\tnow  = +new Date(),\n\t\t\t\t\targs = arguments;\n\t\n\t\t\t\tif ( last && now < last + frequency ) {\n\t\t\t\t\tclearTimeout( timer );\n\t\n\t\t\t\t\ttimer = setTimeout( function () {\n\t\t\t\t\t\tlast = undefined;\n\t\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t\t}, frequency );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlast = now;\n\t\t\t\t\tfn.apply( that, args );\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Escape a string such that it can be used in a regular expression\n\t\t *\n\t\t *  @param {string} val string to escape\n\t\t *  @returns {string} escaped string\n\t\t */\n\t\tescapeRegex: function ( val ) {\n\t\t\treturn val.replace( _re_escape_regex, '\\\\$1' );\n\t\t}\n\t};\n\t\n\t\n\t\n\t/**\n\t * Create a mapping object that allows camel case parameters to be looked up\n\t * for their Hungarian counterparts. The mapping is stored in a private\n\t * parameter called `_hungarianMap` which can be accessed on the source object.\n\t *  @param {object} o\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnHungarianMap ( o )\n\t{\n\t\tvar\n\t\t\thungarian = 'a aa ai ao as b fn i m o s ',\n\t\t\tmatch,\n\t\t\tnewKey,\n\t\t\tmap = {};\n\t\n\t\t$.each( o, function (key, val) {\n\t\t\tmatch = key.match(/^([^A-Z]+?)([A-Z])/);\n\t\n\t\t\tif ( match && hungarian.indexOf(match[1]+' ') !== -1 )\n\t\t\t{\n\t\t\t\tnewKey = key.replace( match[0], match[2].toLowerCase() );\n\t\t\t\tmap[ newKey ] = key;\n\t\n\t\t\t\tif ( match[1] === 'o' )\n\t\t\t\t{\n\t\t\t\t\t_fnHungarianMap( o[key] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t\n\t\to._hungarianMap = map;\n\t}\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian, based on a Hungarian map\n\t * created by _fnHungarianMap.\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCamelToHungarian ( src, user, force )\n\t{\n\t\tif ( ! src._hungarianMap ) {\n\t\t\t_fnHungarianMap( src );\n\t\t}\n\t\n\t\tvar hungarianKey;\n\t\n\t\t$.each( user, function (key, val) {\n\t\t\thungarianKey = src._hungarianMap[ key ];\n\t\n\t\t\tif ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )\n\t\t\t{\n\t\t\t\t// For objects, we need to buzz down into the object to copy parameters\n\t\t\t\tif ( hungarianKey.charAt(0) === 'o' )\n\t\t\t\t{\n\t\t\t\t\t// Copy the camelCase options over to the hungarian\n\t\t\t\t\tif ( ! user[ hungarianKey ] ) {\n\t\t\t\t\t\tuser[ hungarianKey ] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, user[hungarianKey], user[key] );\n\t\n\t\t\t\t\t_fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tuser[hungarianKey] = user[ key ];\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Language compatibility - when certain options are given, and others aren't, we\n\t * need to duplicate the values over, in order to provide backwards compatibility\n\t * with older language files.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLanguageCompat( lang )\n\t{\n\t\t// Note the use of the Hungarian notation for the parameters in this method as\n\t\t// this is called after the mapping of camelCase to Hungarian\n\t\tvar defaults = DataTable.defaults.oLanguage;\n\t\n\t\t// Default mapping\n\t\tvar defaultDecimal = defaults.sDecimal;\n\t\tif ( defaultDecimal ) {\n\t\t\t_addNumericSort( defaultDecimal );\n\t\t}\n\t\n\t\tif ( lang ) {\n\t\t\tvar zeroRecords = lang.sZeroRecords;\n\t\n\t\t\t// Backwards compatibility - if there is no sEmptyTable given, then use the same as\n\t\t\t// sZeroRecords - assuming that is given.\n\t\t\tif ( ! lang.sEmptyTable && zeroRecords &&\n\t\t\t\tdefaults.sEmptyTable === \"No data available in table\" )\n\t\t\t{\n\t\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );\n\t\t\t}\n\t\n\t\t\t// Likewise with loading records\n\t\t\tif ( ! lang.sLoadingRecords && zeroRecords &&\n\t\t\t\tdefaults.sLoadingRecords === \"Loading...\" )\n\t\t\t{\n\t\t\t\t_fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );\n\t\t\t}\n\t\n\t\t\t// Old parameter name of the thousands separator mapped onto the new\n\t\t\tif ( lang.sInfoThousands ) {\n\t\t\t\tlang.sThousands = lang.sInfoThousands;\n\t\t\t}\n\t\n\t\t\tvar decimal = lang.sDecimal;\n\t\t\tif ( decimal && defaultDecimal !== decimal ) {\n\t\t\t\t_addNumericSort( decimal );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Map one parameter onto another\n\t *  @param {object} o Object to map\n\t *  @param {*} knew The new parameter name\n\t *  @param {*} old The old parameter name\n\t */\n\tvar _fnCompatMap = function ( o, knew, old ) {\n\t\tif ( o[ knew ] !== undefined ) {\n\t\t\to[ old ] = o[ knew ];\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for the main DT options. Note that the new\n\t * options are mapped onto the old parameters, so this is an external interface\n\t * change only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatOpts ( init )\n\t{\n\t\t_fnCompatMap( init, 'ordering',      'bSort' );\n\t\t_fnCompatMap( init, 'orderMulti',    'bSortMulti' );\n\t\t_fnCompatMap( init, 'orderClasses',  'bSortClasses' );\n\t\t_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );\n\t\t_fnCompatMap( init, 'order',         'aaSorting' );\n\t\t_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );\n\t\t_fnCompatMap( init, 'paging',        'bPaginate' );\n\t\t_fnCompatMap( init, 'pagingType',    'sPaginationType' );\n\t\t_fnCompatMap( init, 'pageLength',    'iDisplayLength' );\n\t\t_fnCompatMap( init, 'searching',     'bFilter' );\n\t\n\t\t// Boolean initialisation of x-scrolling\n\t\tif ( typeof init.sScrollX === 'boolean' ) {\n\t\t\tinit.sScrollX = init.sScrollX ? '100%' : '';\n\t\t}\n\t\tif ( typeof init.scrollX === 'boolean' ) {\n\t\t\tinit.scrollX = init.scrollX ? '100%' : '';\n\t\t}\n\t\n\t\t// Column search objects are in an array, so it needs to be converted\n\t\t// element by element\n\t\tvar searchCols = init.aoSearchCols;\n\t\n\t\tif ( searchCols ) {\n\t\t\tfor ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {\n\t\t\t\tif ( searchCols[i] ) {\n\t\t\t\t\t_fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for column options. Note that the new options\n\t * are mapped onto the old parameters, so this is an external interface change\n\t * only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatCols ( init )\n\t{\n\t\t_fnCompatMap( init, 'orderable',     'bSortable' );\n\t\t_fnCompatMap( init, 'orderData',     'aDataSort' );\n\t\t_fnCompatMap( init, 'orderSequence', 'asSorting' );\n\t\t_fnCompatMap( init, 'orderDataType', 'sortDataType' );\n\t\n\t\t// orderData can be given as an integer\n\t\tvar dataSort = init.aDataSort;\n\t\tif ( typeof dataSort === 'number' && ! $.isArray( dataSort ) ) {\n\t\t\tinit.aDataSort = [ dataSort ];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Browser feature detection for capabilities, quirks\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBrowserDetect( settings )\n\t{\n\t\t// We don't need to do this every time DataTables is constructed, the values\n\t\t// calculated are specific to the browser and OS configuration which we\n\t\t// don't expect to change between initialisations\n\t\tif ( ! DataTable.__browser ) {\n\t\t\tvar browser = {};\n\t\t\tDataTable.__browser = browser;\n\t\n\t\t\t// Scrolling feature / quirks detection\n\t\t\tvar n = $('<div/>')\n\t\t\t\t.css( {\n\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: $(window).scrollLeft()*-1, // allow for scrolling\n\t\t\t\t\theight: 1,\n\t\t\t\t\twidth: 1,\n\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t} )\n\t\t\t\t.append(\n\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\ttop: 1,\n\t\t\t\t\t\t\tleft: 1,\n\t\t\t\t\t\t\twidth: 100,\n\t\t\t\t\t\t\toverflow: 'scroll'\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$('<div/>')\n\t\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t\t\t\theight: 10\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t.appendTo( 'body' );\n\t\n\t\t\tvar outer = n.children();\n\t\t\tvar inner = outer.children();\n\t\n\t\t\t// Numbers below, in order, are:\n\t\t\t// inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth\n\t\t\t//\n\t\t\t// IE6 XP:                           100 100 100  83\n\t\t\t// IE7 Vista:                        100 100 100  83\n\t\t\t// IE 8+ Windows:                     83  83 100  83\n\t\t\t// Evergreen Windows:                 83  83 100  83\n\t\t\t// Evergreen Mac with scrollbars:     85  85 100  85\n\t\t\t// Evergreen Mac without scrollbars: 100 100 100 100\n\t\n\t\t\t// Get scrollbar width\n\t\t\tbrowser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;\n\t\n\t\t\t// IE6/7 will oversize a width 100% element inside a scrolling element, to\n\t\t\t// include the width of the scrollbar, while other browsers ensure the inner\n\t\t\t// element is contained without forcing scrolling\n\t\t\tbrowser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;\n\t\n\t\t\t// In rtl text layout, some browsers (most, but not all) will place the\n\t\t\t// scrollbar on the left, rather than the right.\n\t\t\tbrowser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;\n\t\n\t\t\t// IE8- don't provide height and width for getBoundingClientRect\n\t\t\tbrowser.bBounding = n[0].getBoundingClientRect().width ? true : false;\n\t\n\t\t\tn.remove();\n\t\t}\n\t\n\t\t$.extend( settings.oBrowser, DataTable.__browser );\n\t\tsettings.oScroll.iBarWidth = DataTable.__browser.barWidth;\n\t}\n\t\n\t\n\t/**\n\t * Array.prototype reduce[Right] method, used for browsers which don't support\n\t * JS 1.6. Done this way to reduce code size, since we iterate either way\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReduce ( that, fn, init, start, end, inc )\n\t{\n\t\tvar\n\t\t\ti = start,\n\t\t\tvalue,\n\t\t\tisSet = false;\n\t\n\t\tif ( init !== undefined ) {\n\t\t\tvalue = init;\n\t\t\tisSet = true;\n\t\t}\n\t\n\t\twhile ( i !== end ) {\n\t\t\tif ( ! that.hasOwnProperty(i) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\tvalue = isSet ?\n\t\t\t\tfn( value, that[i], i, that ) :\n\t\t\t\tthat[i];\n\t\n\t\t\tisSet = true;\n\t\t\ti += inc;\n\t\t}\n\t\n\t\treturn value;\n\t}\n\t\n\t/**\n\t * Add a column to the list used for the table with default values\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nTh The th element for this column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddColumn( oSettings, nTh )\n\t{\n\t\t// Add column to aoColumns array\n\t\tvar oDefaults = DataTable.defaults.column;\n\t\tvar iCol = oSettings.aoColumns.length;\n\t\tvar oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {\n\t\t\t\"nTh\": nTh ? nTh : document.createElement('th'),\n\t\t\t\"sTitle\":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',\n\t\t\t\"aDataSort\": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],\n\t\t\t\"mData\": oDefaults.mData ? oDefaults.mData : iCol,\n\t\t\tidx: iCol\n\t\t} );\n\t\toSettings.aoColumns.push( oCol );\n\t\n\t\t// Add search object for column specific search. Note that the `searchCols[ iCol ]`\n\t\t// passed into extend can be undefined. This allows the user to give a default\n\t\t// with only some of the parameters defined, and also not give a default\n\t\tvar searchCols = oSettings.aoPreSearchCols;\n\t\tsearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );\n\t\n\t\t// Use the default column options function to initialise classes etc\n\t\t_fnColumnOptions( oSettings, iCol, $(nTh).data() );\n\t}\n\t\n\t\n\t/**\n\t * Apply options for a column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iCol column index to consider\n\t *  @param {object} oOptions object with sType, bVisible and bSearchable etc\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnOptions( oSettings, iCol, oOptions )\n\t{\n\t\tvar oCol = oSettings.aoColumns[ iCol ];\n\t\tvar oClasses = oSettings.oClasses;\n\t\tvar th = $(oCol.nTh);\n\t\n\t\t// Try to get width information from the DOM. We can't get it from CSS\n\t\t// as we'd need to parse the CSS stylesheet. `width` option can override\n\t\tif ( ! oCol.sWidthOrig ) {\n\t\t\t// Width attribute\n\t\t\toCol.sWidthOrig = th.attr('width') || null;\n\t\n\t\t\t// Style attribute\n\t\t\tvar t = (th.attr('style') || '').match(/width:\\s*(\\d+[pxem%]+)/);\n\t\t\tif ( t ) {\n\t\t\t\toCol.sWidthOrig = t[1];\n\t\t\t}\n\t\t}\n\t\n\t\t/* User specified column options */\n\t\tif ( oOptions !== undefined && oOptions !== null )\n\t\t{\n\t\t\t// Backwards compatibility\n\t\t\t_fnCompatCols( oOptions );\n\t\n\t\t\t// Map camel case parameters to their Hungarian counterparts\n\t\t\t_fnCamelToHungarian( DataTable.defaults.column, oOptions );\n\t\n\t\t\t/* Backwards compatibility for mDataProp */\n\t\t\tif ( oOptions.mDataProp !== undefined && !oOptions.mData )\n\t\t\t{\n\t\t\t\toOptions.mData = oOptions.mDataProp;\n\t\t\t}\n\t\n\t\t\tif ( oOptions.sType )\n\t\t\t{\n\t\t\t\toCol._sManualType = oOptions.sType;\n\t\t\t}\n\t\n\t\t\t// `class` is a reserved word in Javascript, so we need to provide\n\t\t\t// the ability to use a valid name for the camel case input\n\t\t\tif ( oOptions.className && ! oOptions.sClass )\n\t\t\t{\n\t\t\t\toOptions.sClass = oOptions.className;\n\t\t\t}\n\t\t\tif ( oOptions.sClass ) {\n\t\t\t\tth.addClass( oOptions.sClass );\n\t\t\t}\n\t\n\t\t\t$.extend( oCol, oOptions );\n\t\t\t_fnMap( oCol, oOptions, \"sWidth\", \"sWidthOrig\" );\n\t\n\t\t\t/* iDataSort to be applied (backwards compatibility), but aDataSort will take\n\t\t\t * priority if defined\n\t\t\t */\n\t\t\tif ( oOptions.iDataSort !== undefined )\n\t\t\t{\n\t\t\t\toCol.aDataSort = [ oOptions.iDataSort ];\n\t\t\t}\n\t\t\t_fnMap( oCol, oOptions, \"aDataSort\" );\n\t\t}\n\t\n\t\t/* Cache the data get and set functions for speed */\n\t\tvar mDataSrc = oCol.mData;\n\t\tvar mData = _fnGetObjectDataFn( mDataSrc );\n\t\tvar mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;\n\t\n\t\tvar attrTest = function( src ) {\n\t\t\treturn typeof src === 'string' && src.indexOf('@') !== -1;\n\t\t};\n\t\toCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (\n\t\t\tattrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)\n\t\t);\n\t\toCol._setter = null;\n\t\n\t\toCol.fnGetData = function (rowData, type, meta) {\n\t\t\tvar innerData = mData( rowData, type, undefined, meta );\n\t\n\t\t\treturn mRender && type ?\n\t\t\t\tmRender( innerData, type, rowData, meta ) :\n\t\t\t\tinnerData;\n\t\t};\n\t\toCol.fnSetData = function ( rowData, val, meta ) {\n\t\t\treturn _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );\n\t\t};\n\t\n\t\t// Indicate if DataTables should read DOM data as an object or array\n\t\t// Used in _fnGetRowElements\n\t\tif ( typeof mDataSrc !== 'number' ) {\n\t\t\toSettings._rowReadObject = true;\n\t\t}\n\t\n\t\t/* Feature sorting overrides column specific when off */\n\t\tif ( !oSettings.oFeatures.bSort )\n\t\t{\n\t\t\toCol.bSortable = false;\n\t\t\tth.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called\n\t\t}\n\t\n\t\t/* Check that the class assignment is correct for sorting */\n\t\tvar bAsc = $.inArray('asc', oCol.asSorting) !== -1;\n\t\tvar bDesc = $.inArray('desc', oCol.asSorting) !== -1;\n\t\tif ( !oCol.bSortable || (!bAsc && !bDesc) )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableNone;\n\t\t\toCol.sSortingClassJUI = \"\";\n\t\t}\n\t\telse if ( bAsc && !bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableAsc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;\n\t\t}\n\t\telse if ( !bAsc && bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableDesc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;\n\t\t}\n\t\telse\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortable;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUI;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Adjust the table column widths for new data. Note: you would probably want to\n\t * do a redraw after calling this function!\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAdjustColumnSizing ( settings )\n\t{\n\t\t/* Not interested in doing column width calculation if auto-width is disabled */\n\t\tif ( settings.oFeatures.bAutoWidth !== false )\n\t\t{\n\t\t\tvar columns = settings.aoColumns;\n\t\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t\tfor ( var i=0 , iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tcolumns[i].nTh.style.width = columns[i].sWidth;\n\t\t\t}\n\t\t}\n\t\n\t\tvar scroll = settings.oScroll;\n\t\tif ( scroll.sY !== '' || scroll.sX !== '')\n\t\t{\n\t\t\t_fnScrollDraw( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'column-sizing', [settings] );\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of a visible column to the index in the data array (take account\n\t * of hidden columns)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iMatch Visible column index to lookup\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisibleToColumnIndex( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\n\t\treturn typeof aiVis[iMatch] === 'number' ?\n\t\t\taiVis[iMatch] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of an index in the data array and convert it to the visible\n\t *   column index (take account of hidden columns)\n\t *  @param {int} iMatch Column index to lookup\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnIndexToVisible( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\tvar iPos = $.inArray( iMatch, aiVis );\n\t\n\t\treturn iPos !== -1 ? iPos : null;\n\t}\n\t\n\t\n\t/**\n\t * Get the number of visible columns\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the number of visible columns\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisbleColumns( oSettings )\n\t{\n\t\tvar vis = 0;\n\t\n\t\t// No reduce in IE8, use a loop for now\n\t\t$.each( oSettings.aoColumns, function ( i, col ) {\n\t\t\tif ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {\n\t\t\t\tvis++;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn vis;\n\t}\n\t\n\t\n\t/**\n\t * Get an array of column indexes that match a given property\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sParam Parameter in aoColumns to look for - typically\n\t *    bVisible or bSearchable\n\t *  @returns {array} Array of indexes with matched properties\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetColumns( oSettings, sParam )\n\t{\n\t\tvar a = [];\n\t\n\t\t$.map( oSettings.aoColumns, function(val, i) {\n\t\t\tif ( val[sParam] ) {\n\t\t\t\ta.push( i );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn a;\n\t}\n\t\n\t\n\t/**\n\t * Calculate the 'type' of a column\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnTypes ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar data = settings.aoData;\n\t\tvar types = DataTable.ext.type.detect;\n\t\tvar i, ien, j, jen, k, ken;\n\t\tvar col, cell, detectedType, cache;\n\t\n\t\t// For each column, spin over the \n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcol = columns[i];\n\t\t\tcache = [];\n\t\n\t\t\tif ( ! col.sType && col._sManualType ) {\n\t\t\t\tcol.sType = col._sManualType;\n\t\t\t}\n\t\t\telse if ( ! col.sType ) {\n\t\t\t\tfor ( j=0, jen=types.length ; j<jen ; j++ ) {\n\t\t\t\t\tfor ( k=0, ken=data.length ; k<ken ; k++ ) {\n\t\t\t\t\t\t// Use a cache array so we only need to get the type data\n\t\t\t\t\t\t// from the formatter once (when using multiple detectors)\n\t\t\t\t\t\tif ( cache[k] === undefined ) {\n\t\t\t\t\t\t\tcache[k] = _fnGetCellData( settings, k, i, 'type' );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tdetectedType = types[j]( cache[k], settings );\n\t\n\t\t\t\t\t\t// If null, then this type can't apply to this column, so\n\t\t\t\t\t\t// rather than testing all cells, break out. There is an\n\t\t\t\t\t\t// exception for the last type which is `html`. We need to\n\t\t\t\t\t\t// scan all rows since it is possible to mix string and HTML\n\t\t\t\t\t\t// types\n\t\t\t\t\t\tif ( ! detectedType && j !== types.length-1 ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Only a single match is needed for html type since it is\n\t\t\t\t\t\t// bottom of the pile and very similar to string\n\t\t\t\t\t\tif ( detectedType === 'html' ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Type is valid for all data points in the column - use this\n\t\t\t\t\t// type\n\t\t\t\t\tif ( detectedType ) {\n\t\t\t\t\t\tcol.sType = detectedType;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Fall back - if no type was detected, always use string\n\t\t\t\tif ( ! col.sType ) {\n\t\t\t\t\tcol.sType = 'string';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Take the column definitions and static columns arrays and calculate how\n\t * they relate to column indexes. The callback function will then apply the\n\t * definition found for a column to a suitable configuration object.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aoColDefs The aoColumnDefs array that is to be applied\n\t *  @param {array} aoCols The aoColumns array that defines columns individually\n\t *  @param {function} fn Callback function - takes two parameters, the calculated\n\t *    column index and the definition for that column.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, def;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Column definitions with aTargets\n\t\tif ( aoColDefs )\n\t\t{\n\t\t\t/* Loop over the definitions array - loop in reverse so first instance has priority */\n\t\t\tfor ( i=aoColDefs.length-1 ; i>=0 ; i-- )\n\t\t\t{\n\t\t\t\tdef = aoColDefs[i];\n\t\n\t\t\t\t/* Each definition can target multiple columns, as it is an array */\n\t\t\t\tvar aTargets = def.targets !== undefined ?\n\t\t\t\t\tdef.targets :\n\t\t\t\t\tdef.aTargets;\n\t\n\t\t\t\tif ( ! $.isArray( aTargets ) )\n\t\t\t\t{\n\t\t\t\t\taTargets = [ aTargets ];\n\t\t\t\t}\n\t\n\t\t\t\tfor ( j=0, jLen=aTargets.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Add columns that we don't yet know about */\n\t\t\t\t\t\twhile( columns.length <= aTargets[j] )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_fnAddColumn( oSettings );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t/* Integer, basic index */\n\t\t\t\t\t\tfn( aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Negative integer, right to left column counting */\n\t\t\t\t\t\tfn( columns.length+aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'string' )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Class name matching on TH element */\n\t\t\t\t\t\tfor ( k=0, kLen=columns.length ; k<kLen ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( aTargets[j] == \"_all\" ||\n\t\t\t\t\t\t\t     $(columns[k].nTh).hasClass( aTargets[j] ) )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfn( k, def );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// Statically defined columns array\n\t\tif ( aoCols )\n\t\t{\n\t\t\tfor ( i=0, iLen=aoCols.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfn( i, aoCols[i] );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * Add a data array to the table, creating DOM node etc. This is the parallel to\n\t * _fnGatherData, but for adding rows from a Javascript source, rather than a\n\t * DOM source.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aData data array to be added\n\t *  @param {node} [nTr] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddData ( oSettings, aDataIn, nTr, anTds )\n\t{\n\t\t/* Create the object for storing information about this new row */\n\t\tvar iRow = oSettings.aoData.length;\n\t\tvar oData = $.extend( true, {}, DataTable.models.oRow, {\n\t\t\tsrc: nTr ? 'dom' : 'data',\n\t\t\tidx: iRow\n\t\t} );\n\t\n\t\toData._aData = aDataIn;\n\t\toSettings.aoData.push( oData );\n\t\n\t\t/* Create the cells */\n\t\tvar nTd, sThisType;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\t// Invalidate the column types as the new data needs to be revalidated\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tcolumns[i].sType = null;\n\t\t}\n\t\n\t\t/* Add to the display array */\n\t\toSettings.aiDisplayMaster.push( iRow );\n\t\n\t\tvar id = oSettings.rowIdFn( aDataIn );\n\t\tif ( id !== undefined ) {\n\t\t\toSettings.aIds[ id ] = oData;\n\t\t}\n\t\n\t\t/* Create the DOM information, or register it if already present */\n\t\tif ( nTr || ! oSettings.oFeatures.bDeferRender )\n\t\t{\n\t\t\t_fnCreateTr( oSettings, iRow, nTr, anTds );\n\t\t}\n\t\n\t\treturn iRow;\n\t}\n\t\n\t\n\t/**\n\t * Add one or more TR elements to the table. Generally we'd expect to\n\t * use this for reading data from a DOM sourced table, but it could be\n\t * used for an TR element. Note that if a TR is given, it is used (i.e.\n\t * it is not cloned).\n\t *  @param {object} settings dataTables settings object\n\t *  @param {array|node|jQuery} trs The TR element(s) to add to the table\n\t *  @returns {array} Array of indexes for the added rows\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddTr( settings, trs )\n\t{\n\t\tvar row;\n\t\n\t\t// Allow an individual node to be passed in\n\t\tif ( ! (trs instanceof $) ) {\n\t\t\ttrs = $(trs);\n\t\t}\n\t\n\t\treturn trs.map( function (i, el) {\n\t\t\trow = _fnGetRowElements( settings, el );\n\t\t\treturn _fnAddData( settings, row.data, el, row.cells );\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Take a TR element and convert it to an index in aoData\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} n the TR element to find\n\t *  @returns {int} index if the node is found, null if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToDataIndex( oSettings, n )\n\t{\n\t\treturn (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;\n\t}\n\t\n\t\n\t/**\n\t * Take a TD element and convert it into a column data index (not the visible index)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow The row number the TD/TH can be found in\n\t *  @param {node} n The TD/TH element to find\n\t *  @returns {int} index if the node is found, -1 if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToColumnIndex( oSettings, iRow, n )\n\t{\n\t\treturn $.inArray( n, oSettings.aoData[ iRow ].anCells );\n\t}\n\t\n\t\n\t/**\n\t * Get the data for a given cell from the internal cache, taking into account data mapping\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {string} type data get type ('display', 'type' 'filter' 'sort')\n\t *  @returns {*} Cell data\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetCellData( settings, rowIdx, colIdx, type )\n\t{\n\t\tvar draw           = settings.iDraw;\n\t\tvar col            = settings.aoColumns[colIdx];\n\t\tvar rowData        = settings.aoData[rowIdx]._aData;\n\t\tvar defaultContent = col.sDefaultContent;\n\t\tvar cellData       = col.fnGetData( rowData, type, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t} );\n\t\n\t\tif ( cellData === undefined ) {\n\t\t\tif ( settings.iDrawError != draw && defaultContent === null ) {\n\t\t\t\t_fnLog( settings, 0, \"Requested unknown parameter \"+\n\t\t\t\t\t(typeof col.mData=='function' ? '{function}' : \"'\"+col.mData+\"'\")+\n\t\t\t\t\t\" for row \"+rowIdx+\", column \"+colIdx, 4 );\n\t\t\t\tsettings.iDrawError = draw;\n\t\t\t}\n\t\t\treturn defaultContent;\n\t\t}\n\t\n\t\t// When the data source is null and a specific data type is requested (i.e.\n\t\t// not the original data), we can use default column data\n\t\tif ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {\n\t\t\tcellData = defaultContent;\n\t\t}\n\t\telse if ( typeof cellData === 'function' ) {\n\t\t\t// If the data source is a function, then we run it and use the return,\n\t\t\t// executing in the scope of the data object (for instances)\n\t\t\treturn cellData.call( rowData );\n\t\t}\n\t\n\t\tif ( cellData === null && type == 'display' ) {\n\t\t\treturn '';\n\t\t}\n\t\treturn cellData;\n\t}\n\t\n\t\n\t/**\n\t * Set the value for a specific cell, into the internal data cache\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} rowIdx aoData row id\n\t *  @param {int} colIdx Column index\n\t *  @param {*} val Value to set\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetCellData( settings, rowIdx, colIdx, val )\n\t{\n\t\tvar col     = settings.aoColumns[colIdx];\n\t\tvar rowData = settings.aoData[rowIdx]._aData;\n\t\n\t\tcol.fnSetData( rowData, val, {\n\t\t\tsettings: settings,\n\t\t\trow:      rowIdx,\n\t\t\tcol:      colIdx\n\t\t}  );\n\t}\n\t\n\t\n\t// Private variable that is used to match action syntax in the data property object\n\tvar __reArray = /\\[.*?\\]$/;\n\tvar __reFn = /\\(\\)$/;\n\t\n\t/**\n\t * Split string on periods, taking into account escaped periods\n\t * @param  {string} str String to split\n\t * @return {array} Split string\n\t */\n\tfunction _fnSplitObjNotation( str )\n\t{\n\t\treturn $.map( str.match(/(\\\\.|[^\\.])+/g) || [''], function ( s ) {\n\t\t\treturn s.replace(/\\\\\\./g, '.');\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to get data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data get function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Build an object of get functions, and wrap them in a single call */\n\t\t\tvar o = {};\n\t\t\t$.each( mSource, function (key, val) {\n\t\t\t\tif ( val ) {\n\t\t\t\t\to[key] = _fnGetObjectDataFn( val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\tvar t = o[type] || o._;\n\t\t\t\treturn t !== undefined ?\n\t\t\t\t\tt(data, type, row, meta) :\n\t\t\t\t\tdata;\n\t\t\t};\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Give an empty string for rendering / sorting etc */\n\t\t\treturn function (data) { // type, row and meta also passed, but not used\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, type, row, meta) {\n\t\t\t\treturn mSource( data, type, row, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* If there is a . in the source string then the data source is in a\n\t\t\t * nested object so we loop over the data for each level to get the next\n\t\t\t * level down. On each loop we test for undefined, and if found immediately\n\t\t\t * return. This allows entire objects to be missing and sDefaultContent to\n\t\t\t * be used if defined, rather than throwing an error\n\t\t\t */\n\t\t\tvar fetchData = function (data, type, src) {\n\t\t\t\tvar arrayNotation, funcNotation, out, innerSrc;\n\t\n\t\t\t\tif ( src !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tvar a = _fnSplitObjNotation( src );\n\t\n\t\t\t\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check if we are dealing with special notation\n\t\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Array notation\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\n\t\t\t\t\t\t\t// Condition allows simply [] to be passed in\n\t\t\t\t\t\t\tif ( a[i] !== \"\" ) {\n\t\t\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tout = [];\n\t\n\t\t\t\t\t\t\t// Get the remainder of the nested object to get\n\t\t\t\t\t\t\ta.splice( 0, i+1 );\n\t\t\t\t\t\t\tinnerSrc = a.join('.');\n\t\n\t\t\t\t\t\t\t// Traverse each entry in the array getting the properties requested\n\t\t\t\t\t\t\tif ( $.isArray( data ) ) {\n\t\t\t\t\t\t\t\tfor ( var j=0, jLen=data.length ; j<jLen ; j++ ) {\n\t\t\t\t\t\t\t\t\tout.push( fetchData( data[j], type, innerSrc ) );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\t// If a string is given in between the array notation indicators, that\n\t\t\t\t\t\t\t// is used to join the strings together, otherwise an array is returned\n\t\t\t\t\t\t\tvar join = arrayNotation[0].substring(1, arrayNotation[0].length-1);\n\t\t\t\t\t\t\tdata = (join===\"\") ? out : out.join(join);\n\t\n\t\t\t\t\t\t\t// The inner call to fetchData has already traversed through the remainder\n\t\t\t\t\t\t\t// of the source requested, so we exit from the loop\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Function call\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\t\tdata = data[ a[i] ]();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( data === null || data[ a[i] ] === undefined )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn data;\n\t\t\t};\n\t\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn fetchData( data, type, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, type) { // row and meta also passed, but not used\n\t\t\t\treturn data[mSource];\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to set data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data set function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Unlike get, only the underscore (global) option is used for for\n\t\t\t * setting data since we don't know the type here. This is why an object\n\t\t\t * option is not documented for `mData` (which is read/write), but it is\n\t\t\t * for `mRender` which is read only.\n\t\t\t */\n\t\t\treturn _fnSetObjectDataFn( mSource._ );\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Nothing to do when the data source is null */\n\t\t\treturn function () {};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, val, meta) {\n\t\t\t\tmSource( data, 'set', val, meta );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* Like the get, we need to get data from a nested object */\n\t\t\tvar setData = function (data, val, src) {\n\t\t\t\tvar a = _fnSplitObjNotation( src ), b;\n\t\t\t\tvar aLast = a[a.length-1];\n\t\t\t\tvar arrayNotation, funcNotation, o, innerSrc;\n\t\n\t\t\t\tfor ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\t// Check if we are dealing with an array notation request\n\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\t\t\t\t\tdata[ a[i] ] = [];\n\t\n\t\t\t\t\t\t// Get the remainder of the nested object to set so we can recurse\n\t\t\t\t\t\tb = a.slice();\n\t\t\t\t\t\tb.splice( 0, i+1 );\n\t\t\t\t\t\tinnerSrc = b.join('.');\n\t\n\t\t\t\t\t\t// Traverse each entry in the array setting the properties requested\n\t\t\t\t\t\tif ( $.isArray( val ) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor ( var j=0, jLen=val.length ; j<jLen ; j++ )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\to = {};\n\t\t\t\t\t\t\t\tsetData( o, val[j], innerSrc );\n\t\t\t\t\t\t\t\tdata[ a[i] ].push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We've been asked to save data to an array, but it\n\t\t\t\t\t\t\t// isn't array data to be saved. Best that can be done\n\t\t\t\t\t\t\t// is to just save the value.\n\t\t\t\t\t\t\tdata[ a[i] ] = val;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// The inner call to setData has already traversed through the remainder\n\t\t\t\t\t\t// of the source and has set the data, thus we can exit here\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Function call\n\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\tdata = data[ a[i] ]( val );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If the nested object doesn't currently exist - since we are\n\t\t\t\t\t// trying to set the value - create it\n\t\t\t\t\tif ( data[ a[i] ] === null || data[ a[i] ] === undefined )\n\t\t\t\t\t{\n\t\t\t\t\t\tdata[ a[i] ] = {};\n\t\t\t\t\t}\n\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t}\n\t\n\t\t\t\t// Last item in the input - i.e, the actual set\n\t\t\t\tif ( aLast.match(__reFn ) )\n\t\t\t\t{\n\t\t\t\t\t// Function call\n\t\t\t\t\tdata = data[ aLast.replace(__reFn, '') ]( val );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// If array notation is used, we just want to strip it and use the property name\n\t\t\t\t\t// and assign the value. If it isn't used, then we get the result we want anyway\n\t\t\t\t\tdata[ aLast.replace(__reArray, '') ] = val;\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\treturn setData( data, val, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, val) { // meta is also passed in, but not used\n\t\t\t\tdata[mSource] = val;\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return an array with the full table data\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns array {array} aData Master data array\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetDataMaster ( settings )\n\t{\n\t\treturn _pluck( settings.aoData, '_aData' );\n\t}\n\t\n\t\n\t/**\n\t * Nuke the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnClearTable( settings )\n\t{\n\t\tsettings.aoData.length = 0;\n\t\tsettings.aiDisplayMaster.length = 0;\n\t\tsettings.aiDisplay.length = 0;\n\t\tsettings.aIds = {};\n\t}\n\t\n\t\n\t /**\n\t * Take an array of integers (index array) and remove a target integer (value - not\n\t * the key!)\n\t *  @param {array} a Index array to target\n\t *  @param {int} iTarget value to find\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDeleteIndex( a, iTarget, splice )\n\t{\n\t\tvar iTargetIndex = -1;\n\t\n\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( a[i] == iTarget )\n\t\t\t{\n\t\t\t\tiTargetIndex = i;\n\t\t\t}\n\t\t\telse if ( a[i] > iTarget )\n\t\t\t{\n\t\t\t\ta[i]--;\n\t\t\t}\n\t\t}\n\t\n\t\tif ( iTargetIndex != -1 && splice === undefined )\n\t\t{\n\t\t\ta.splice( iTargetIndex, 1 );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Mark cached data as invalid such that a re-read of the data will occur when\n\t * the cached data is next requested. Also update from the data source object.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {int}    rowIdx   Row index to invalidate\n\t * @param {string} [src]    Source to invalidate from: undefined, 'auto', 'dom'\n\t *     or 'data'\n\t * @param {int}    [colIdx] Column index to invalidate. If undefined the whole\n\t *     row will be invalidated\n\t * @memberof DataTable#oApi\n\t *\n\t * @todo For the modularisation of v1.11 this will need to become a callback, so\n\t *   the sort and filter methods can subscribe to it. That will required\n\t *   initialisation options for sorting, which is why it is not already baked in\n\t */\n\tfunction _fnInvalidate( settings, rowIdx, src, colIdx )\n\t{\n\t\tvar row = settings.aoData[ rowIdx ];\n\t\tvar i, ien;\n\t\tvar cellWrite = function ( cell, col ) {\n\t\t\t// This is very frustrating, but in IE if you just write directly\n\t\t\t// to innerHTML, and elements that are overwritten are GC'ed,\n\t\t\t// even if there is a reference to them elsewhere\n\t\t\twhile ( cell.childNodes.length ) {\n\t\t\t\tcell.removeChild( cell.firstChild );\n\t\t\t}\n\t\n\t\t\tcell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );\n\t\t};\n\t\n\t\t// Are we reading last data from DOM or the data object?\n\t\tif ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {\n\t\t\t// Read the data from the DOM\n\t\t\trow._aData = _fnGetRowElements(\n\t\t\t\t\tsettings, row, colIdx, colIdx === undefined ? undefined : row._aData\n\t\t\t\t)\n\t\t\t\t.data;\n\t\t}\n\t\telse {\n\t\t\t// Reading from data object, update the DOM\n\t\t\tvar cells = row.anCells;\n\t\n\t\t\tif ( cells ) {\n\t\t\t\tif ( colIdx !== undefined ) {\n\t\t\t\t\tcellWrite( cells[colIdx], colIdx );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tcellWrite( cells[i], i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// For both row and cell invalidation, the cached data for sorting and\n\t\t// filtering is nulled out\n\t\trow._aSortData = null;\n\t\trow._aFilterData = null;\n\t\n\t\t// Invalidate the type for a specific column (if given) or all columns since\n\t\t// the data might have changed\n\t\tvar cols = settings.aoColumns;\n\t\tif ( colIdx !== undefined ) {\n\t\t\tcols[ colIdx ].sType = null;\n\t\t}\n\t\telse {\n\t\t\tfor ( i=0, ien=cols.length ; i<ien ; i++ ) {\n\t\t\t\tcols[i].sType = null;\n\t\t\t}\n\t\n\t\t\t// Update DataTables special `DT_*` attributes for the row\n\t\t\t_fnRowAttributes( settings, row );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a data source object from an HTML row, reading the contents of the\n\t * cells that are in the row.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {node|object} TR element from which to read data or existing row\n\t *   object from which to re-read the data from the cells\n\t * @param {int} [colIdx] Optional column index\n\t * @param {array|object} [d] Data source object. If `colIdx` is given then this\n\t *   parameter should also be given and will be used to write the data into.\n\t *   Only the column in question will be written\n\t * @returns {object} Object with two parameters: `data` the data read, in\n\t *   document order, and `cells` and array of nodes (they can be useful to the\n\t *   caller, so rather than needing a second traversal to get them, just return\n\t *   them from here).\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetRowElements( settings, row, colIdx, d )\n\t{\n\t\tvar\n\t\t\ttds = [],\n\t\t\ttd = row.firstChild,\n\t\t\tname, col, o, i=0, contents,\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tobjectRead = settings._rowReadObject;\n\t\n\t\t// Allow the data object to be passed in, or construct\n\t\td = d !== undefined ?\n\t\t\td :\n\t\t\tobjectRead ?\n\t\t\t\t{} :\n\t\t\t\t[];\n\t\n\t\tvar attr = function ( str, td  ) {\n\t\t\tif ( typeof str === 'string' ) {\n\t\t\t\tvar idx = str.indexOf('@');\n\t\n\t\t\t\tif ( idx !== -1 ) {\n\t\t\t\t\tvar attr = str.substring( idx+1 );\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( str );\n\t\t\t\t\tsetter( d, td.getAttribute( attr ) );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\n\t\t// Read data from a cell and store into the data object\n\t\tvar cellProcess = function ( cell ) {\n\t\t\tif ( colIdx === undefined || colIdx === i ) {\n\t\t\t\tcol = columns[i];\n\t\t\t\tcontents = $.trim(cell.innerHTML);\n\t\n\t\t\t\tif ( col && col._bAttrSrc ) {\n\t\t\t\t\tvar setter = _fnSetObjectDataFn( col.mData._ );\n\t\t\t\t\tsetter( d, contents );\n\t\n\t\t\t\t\tattr( col.mData.sort, cell );\n\t\t\t\t\tattr( col.mData.type, cell );\n\t\t\t\t\tattr( col.mData.filter, cell );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Depending on the `data` option for the columns the data can\n\t\t\t\t\t// be read to either an object or an array.\n\t\t\t\t\tif ( objectRead ) {\n\t\t\t\t\t\tif ( ! col._setter ) {\n\t\t\t\t\t\t\t// Cache the setter function\n\t\t\t\t\t\t\tcol._setter = _fnSetObjectDataFn( col.mData );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcol._setter( d, contents );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\td[i] = contents;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t};\n\t\n\t\tif ( td ) {\n\t\t\t// `tr` element was passed in\n\t\t\twhile ( td ) {\n\t\t\t\tname = td.nodeName.toUpperCase();\n\t\n\t\t\t\tif ( name == \"TD\" || name == \"TH\" ) {\n\t\t\t\t\tcellProcess( td );\n\t\t\t\t\ttds.push( td );\n\t\t\t\t}\n\t\n\t\t\t\ttd = td.nextSibling;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Existing row object passed in\n\t\t\ttds = row.anCells;\n\t\n\t\t\tfor ( var j=0, jen=tds.length ; j<jen ; j++ ) {\n\t\t\t\tcellProcess( tds[j] );\n\t\t\t}\n\t\t}\n\t\n\t\t// Read the ID from the DOM if present\n\t\tvar rowNode = row.firstChild ? row : row.nTr;\n\t\n\t\tif ( rowNode ) {\n\t\t\tvar id = rowNode.getAttribute( 'id' );\n\t\n\t\t\tif ( id ) {\n\t\t\t\t_fnSetObjectDataFn( settings.rowId )( d, id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn {\n\t\t\tdata: d,\n\t\t\tcells: tds\n\t\t};\n\t}\n\t/**\n\t * Create a new TR element (and it's TD children) for a row\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow Row to consider\n\t *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCreateTr ( oSettings, iRow, nTrIn, anTds )\n\t{\n\t\tvar\n\t\t\trow = oSettings.aoData[iRow],\n\t\t\trowData = row._aData,\n\t\t\tcells = [],\n\t\t\tnTr, nTd, oCol,\n\t\t\ti, iLen;\n\t\n\t\tif ( row.nTr === null )\n\t\t{\n\t\t\tnTr = nTrIn || document.createElement('tr');\n\t\n\t\t\trow.nTr = nTr;\n\t\t\trow.anCells = cells;\n\t\n\t\t\t/* Use a private property on the node to allow reserve mapping from the node\n\t\t\t * to the aoData array for fast look up\n\t\t\t */\n\t\t\tnTr._DT_RowIndex = iRow;\n\t\n\t\t\t/* Special parameters can be given by the data source to be used on the row */\n\t\t\t_fnRowAttributes( oSettings, row );\n\t\n\t\t\t/* Process each column */\n\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toCol = oSettings.aoColumns[i];\n\t\n\t\t\t\tnTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );\n\t\t\t\tnTd._DT_CellIndex = {\n\t\t\t\t\trow: iRow,\n\t\t\t\t\tcolumn: i\n\t\t\t\t};\n\t\t\t\t\n\t\t\t\tcells.push( nTd );\n\t\n\t\t\t\t// Need to create the HTML if new, or if a rendering function is defined\n\t\t\t\tif ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&\n\t\t\t\t\t (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')\n\t\t\t\t) {\n\t\t\t\t\tnTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );\n\t\t\t\t}\n\t\n\t\t\t\t/* Add user defined class */\n\t\t\t\tif ( oCol.sClass )\n\t\t\t\t{\n\t\t\t\t\tnTd.className += ' '+oCol.sClass;\n\t\t\t\t}\n\t\n\t\t\t\t// Visibility - add or remove as required\n\t\t\t\tif ( oCol.bVisible && ! nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTr.appendChild( nTd );\n\t\t\t\t}\n\t\t\t\telse if ( ! oCol.bVisible && nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTd.parentNode.removeChild( nTd );\n\t\t\t\t}\n\t\n\t\t\t\tif ( oCol.fnCreatedCell )\n\t\t\t\t{\n\t\t\t\t\toCol.fnCreatedCell.call( oSettings.oInstance,\n\t\t\t\t\t\tnTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] );\n\t\t}\n\t\n\t\t// Remove once webkit bug 131819 and Chromium bug 365619 have been resolved\n\t\t// and deployed\n\t\trow.nTr.setAttribute( 'role', 'row' );\n\t}\n\t\n\t\n\t/**\n\t * Add attributes to a row based on the special `DT_*` parameters in a data\n\t * source object.\n\t *  @param {object} settings DataTables settings object\n\t *  @param {object} DataTables row object for the row to be modified\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnRowAttributes( settings, row )\n\t{\n\t\tvar tr = row.nTr;\n\t\tvar data = row._aData;\n\t\n\t\tif ( tr ) {\n\t\t\tvar id = settings.rowIdFn( data );\n\t\n\t\t\tif ( id ) {\n\t\t\t\ttr.id = id;\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowClass ) {\n\t\t\t\t// Remove any classes added by DT_RowClass before\n\t\t\t\tvar a = data.DT_RowClass.split(' ');\n\t\t\t\trow.__rowc = row.__rowc ?\n\t\t\t\t\t_unique( row.__rowc.concat( a ) ) :\n\t\t\t\t\ta;\n\t\n\t\t\t\t$(tr)\n\t\t\t\t\t.removeClass( row.__rowc.join(' ') )\n\t\t\t\t\t.addClass( data.DT_RowClass );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowAttr ) {\n\t\t\t\t$(tr).attr( data.DT_RowAttr );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowData ) {\n\t\t\t\t$(tr).data( data.DT_RowData );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Create the HTML header for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBuildHead( oSettings )\n\t{\n\t\tvar i, ien, cell, row, column;\n\t\tvar thead = oSettings.nTHead;\n\t\tvar tfoot = oSettings.nTFoot;\n\t\tvar createHeader = $('th, td', thead).length === 0;\n\t\tvar classes = oSettings.oClasses;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\tif ( createHeader ) {\n\t\t\trow = $('<tr/>').appendTo( thead );\n\t\t}\n\t\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcell = $( column.nTh ).addClass( column.sClass );\n\t\n\t\t\tif ( createHeader ) {\n\t\t\t\tcell.appendTo( row );\n\t\t\t}\n\t\n\t\t\t// 1.11 move into sorting\n\t\t\tif ( oSettings.oFeatures.bSort ) {\n\t\t\t\tcell.addClass( column.sSortingClass );\n\t\n\t\t\t\tif ( column.bSortable !== false ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.attr( 'tabindex', oSettings.iTabIndex )\n\t\t\t\t\t\t.attr( 'aria-controls', oSettings.sTableId );\n\t\n\t\t\t\t\t_fnSortAttachListener( oSettings, column.nTh, i );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( column.sTitle != cell[0].innerHTML ) {\n\t\t\t\tcell.html( column.sTitle );\n\t\t\t}\n\t\n\t\t\t_fnRenderer( oSettings, 'header' )(\n\t\t\t\toSettings, cell, column, classes\n\t\t\t);\n\t\t}\n\t\n\t\tif ( createHeader ) {\n\t\t\t_fnDetectHeader( oSettings.aoHeader, thead );\n\t\t}\n\t\t\n\t\t/* ARIA role for the rows */\n\t \t$(thead).find('>tr').attr('role', 'row');\n\t\n\t\t/* Deal with the footer - add classes if required */\n\t\t$(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );\n\t\t$(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );\n\t\n\t\t// Cache the footer cells. Note that we only take the cells from the first\n\t\t// row in the footer. If there is more than one row the user wants to\n\t\t// interact with, they need to use the table().foot() method. Note also this\n\t\t// allows cells to be used for multiple columns using colspan\n\t\tif ( tfoot !== null ) {\n\t\t\tvar cells = oSettings.aoFooter[0];\n\t\n\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tcolumn = columns[i];\n\t\t\t\tcolumn.nTf = cells[i].cell;\n\t\n\t\t\t\tif ( column.sClass ) {\n\t\t\t\t\t$(column.nTf).addClass( column.sClass );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the header (or footer) element based on the column visibility states. The\n\t * methodology here is to use the layout array from _fnDetectHeader, modified for\n\t * the instantaneous column visibility, to construct the new layout. The grid is\n\t * traversed over cell at a time in a rows x columns grid fashion, although each\n\t * cell insert can cover multiple elements in the grid - which is tracks using the\n\t * aApplied array. Cell inserts in the grid will only occur where there isn't\n\t * already a cell in that position.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param array {objects} aoSource Layout array from _fnDetectHeader\n\t *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDrawHead( oSettings, aoSource, bIncludeHidden )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, n, nLocalTr;\n\t\tvar aoLocal = [];\n\t\tvar aApplied = [];\n\t\tvar iColumns = oSettings.aoColumns.length;\n\t\tvar iRowspan, iColspan;\n\t\n\t\tif ( ! aoSource )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif (  bIncludeHidden === undefined )\n\t\t{\n\t\t\tbIncludeHidden = false;\n\t\t}\n\t\n\t\t/* Make a copy of the master layout array, but without the visible columns in it */\n\t\tfor ( i=0, iLen=aoSource.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taoLocal[i] = aoSource[i].slice();\n\t\t\taoLocal[i].nTr = aoSource[i].nTr;\n\t\n\t\t\t/* Remove any columns which are currently hidden */\n\t\t\tfor ( j=iColumns-1 ; j>=0 ; j-- )\n\t\t\t{\n\t\t\t\tif ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )\n\t\t\t\t{\n\t\t\t\t\taoLocal[i].splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Prep the applied array - it needs an element for each row */\n\t\t\taApplied.push( [] );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnLocalTr = aoLocal[i].nTr;\n\t\n\t\t\t/* All cells are going to be replaced, so empty out the row */\n\t\t\tif ( nLocalTr )\n\t\t\t{\n\t\t\t\twhile( (n = nLocalTr.firstChild) )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.removeChild( n );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tfor ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tiRowspan = 1;\n\t\t\t\tiColspan = 1;\n\t\n\t\t\t\t/* Check to see if there is already a cell (row/colspan) covering our target\n\t\t\t\t * insert point. If there is, then there is nothing to do.\n\t\t\t\t */\n\t\t\t\tif ( aApplied[i][j] === undefined )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.appendChild( aoLocal[i][j].cell );\n\t\t\t\t\taApplied[i][j] = 1;\n\t\n\t\t\t\t\t/* Expand the cell to cover as many rows as needed */\n\t\t\t\t\twhile ( aoLocal[i+iRowspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\taApplied[i+iRowspan][j] = 1;\n\t\t\t\t\t\tiRowspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Expand the cell to cover as many columns as needed */\n\t\t\t\t\twhile ( aoLocal[i][j+iColspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Must update the applied array over the rows for the columns */\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taApplied[i+k][j+iColspan] = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiColspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Do the actual expansion in the DOM */\n\t\t\t\t\t$(aoLocal[i][j].cell)\n\t\t\t\t\t\t.attr('rowspan', iRowspan)\n\t\t\t\t\t\t.attr('colspan', iColspan);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Insert the required TR nodes into the table for display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDraw( oSettings )\n\t{\n\t\t/* Provide a pre-callback function which can be used to cancel the draw is false is returned */\n\t\tvar aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );\n\t\tif ( $.inArray( false, aPreDraw ) !== -1 )\n\t\t{\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar i, iLen, n;\n\t\tvar anRows = [];\n\t\tvar iRowCount = 0;\n\t\tvar asStripeClasses = oSettings.asStripeClasses;\n\t\tvar iStripes = asStripeClasses.length;\n\t\tvar iOpenRows = oSettings.aoOpenRows.length;\n\t\tvar oLang = oSettings.oLanguage;\n\t\tvar iInitDisplayStart = oSettings.iInitDisplayStart;\n\t\tvar bServerSide = _fnDataSource( oSettings ) == 'ssp';\n\t\tvar aiDisplay = oSettings.aiDisplay;\n\t\n\t\toSettings.bDrawing = true;\n\t\n\t\t/* Check and see if we have an initial draw position from state saving */\n\t\tif ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )\n\t\t{\n\t\t\toSettings._iDisplayStart = bServerSide ?\n\t\t\t\tiInitDisplayStart :\n\t\t\t\tiInitDisplayStart >= oSettings.fnRecordsDisplay() ?\n\t\t\t\t\t0 :\n\t\t\t\t\tiInitDisplayStart;\n\t\n\t\t\toSettings.iInitDisplayStart = -1;\n\t\t}\n\t\n\t\tvar iDisplayStart = oSettings._iDisplayStart;\n\t\tvar iDisplayEnd = oSettings.fnDisplayEnd();\n\t\n\t\t/* Server-side processing draw intercept */\n\t\tif ( oSettings.bDeferLoading )\n\t\t{\n\t\t\toSettings.bDeferLoading = false;\n\t\t\toSettings.iDraw++;\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t}\n\t\telse if ( !bServerSide )\n\t\t{\n\t\t\toSettings.iDraw++;\n\t\t}\n\t\telse if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( aiDisplay.length !== 0 )\n\t\t{\n\t\t\tvar iStart = bServerSide ? 0 : iDisplayStart;\n\t\t\tvar iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;\n\t\n\t\t\tfor ( var j=iStart ; j<iEnd ; j++ )\n\t\t\t{\n\t\t\t\tvar iDataIndex = aiDisplay[j];\n\t\t\t\tvar aoData = oSettings.aoData[ iDataIndex ];\n\t\t\t\tif ( aoData.nTr === null )\n\t\t\t\t{\n\t\t\t\t\t_fnCreateTr( oSettings, iDataIndex );\n\t\t\t\t}\n\t\n\t\t\t\tvar nRow = aoData.nTr;\n\t\n\t\t\t\t/* Remove the old striping classes and then add the new one */\n\t\t\t\tif ( iStripes !== 0 )\n\t\t\t\t{\n\t\t\t\t\tvar sStripe = asStripeClasses[ iRowCount % iStripes ];\n\t\t\t\t\tif ( aoData._sRowStripe != sStripe )\n\t\t\t\t\t{\n\t\t\t\t\t\t$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );\n\t\t\t\t\t\taoData._sRowStripe = sStripe;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Row callback functions - might want to manipulate the row\n\t\t\t\t// iRowCount and j are not currently documented. Are they at all\n\t\t\t\t// useful?\n\t\t\t\t_fnCallbackFire( oSettings, 'aoRowCallback', null,\n\t\t\t\t\t[nRow, aoData._aData, iRowCount, j, iDataIndex] );\n\t\n\t\t\t\tanRows.push( nRow );\n\t\t\t\tiRowCount++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Table is empty - create a row with an empty message in it */\n\t\t\tvar sZero = oLang.sZeroRecords;\n\t\t\tif ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )\n\t\t\t{\n\t\t\t\tsZero = oLang.sLoadingRecords;\n\t\t\t}\n\t\t\telse if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )\n\t\t\t{\n\t\t\t\tsZero = oLang.sEmptyTable;\n\t\t\t}\n\t\n\t\t\tanRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )\n\t\t\t\t.append( $('<td />', {\n\t\t\t\t\t'valign':  'top',\n\t\t\t\t\t'colSpan': _fnVisbleColumns( oSettings ),\n\t\t\t\t\t'class':   oSettings.oClasses.sRowEmpty\n\t\t\t\t} ).html( sZero ) )[0];\n\t\t}\n\t\n\t\t/* Header and footer callbacks */\n\t\t_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\t_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\tvar body = $(oSettings.nTBody);\n\t\n\t\tbody.children().detach();\n\t\tbody.append( $(anRows) );\n\t\n\t\t/* Call all required callback functions for the end of a draw */\n\t\t_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );\n\t\n\t\t/* Draw is complete, sorting and filtering must be as well */\n\t\toSettings.bSorted = false;\n\t\toSettings.bFiltered = false;\n\t\toSettings.bDrawing = false;\n\t}\n\t\n\t\n\t/**\n\t * Redraw the table - taking account of the various features which are enabled\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {boolean} [holdPosition] Keep the current paging position. By default\n\t *    the paging is reset to the first page\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReDraw( settings, holdPosition )\n\t{\n\t\tvar\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tsort     = features.bSort,\n\t\t\tfilter   = features.bFilter;\n\t\n\t\tif ( sort ) {\n\t\t\t_fnSort( settings );\n\t\t}\n\t\n\t\tif ( filter ) {\n\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch );\n\t\t}\n\t\telse {\n\t\t\t// No filtering, so we want to just use the display master\n\t\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\t}\n\t\n\t\tif ( holdPosition !== true ) {\n\t\t\tsettings._iDisplayStart = 0;\n\t\t}\n\t\n\t\t// Let any modules know about the draw hold position state (used by\n\t\t// scrolling internally)\n\t\tsettings._drawHold = holdPosition;\n\t\n\t\t_fnDraw( settings );\n\t\n\t\tsettings._drawHold = false;\n\t}\n\t\n\t\n\t/**\n\t * Add the options to the page HTML for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddOptionsHtml ( oSettings )\n\t{\n\t\tvar classes = oSettings.oClasses;\n\t\tvar table = $(oSettings.nTable);\n\t\tvar holding = $('<div/>').insertBefore( table ); // Holding element for speed\n\t\tvar features = oSettings.oFeatures;\n\t\n\t\t// All DataTables are wrapped in a div\n\t\tvar insert = $('<div/>', {\n\t\t\tid:      oSettings.sTableId+'_wrapper',\n\t\t\t'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)\n\t\t} );\n\t\n\t\toSettings.nHolding = holding[0];\n\t\toSettings.nTableWrapper = insert[0];\n\t\toSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;\n\t\n\t\t/* Loop over the user set positioning and place the elements as needed */\n\t\tvar aDom = oSettings.sDom.split('');\n\t\tvar featureNode, cOption, nNewNode, cNext, sAttr, j;\n\t\tfor ( var i=0 ; i<aDom.length ; i++ )\n\t\t{\n\t\t\tfeatureNode = null;\n\t\t\tcOption = aDom[i];\n\t\n\t\t\tif ( cOption == '<' )\n\t\t\t{\n\t\t\t\t/* New container div */\n\t\t\t\tnNewNode = $('<div/>')[0];\n\t\n\t\t\t\t/* Check to see if we should append an id and/or a class name to the container */\n\t\t\t\tcNext = aDom[i+1];\n\t\t\t\tif ( cNext == \"'\" || cNext == '\"' )\n\t\t\t\t{\n\t\t\t\t\tsAttr = \"\";\n\t\t\t\t\tj = 2;\n\t\t\t\t\twhile ( aDom[i+j] != cNext )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr += aDom[i+j];\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Replace jQuery UI constants @todo depreciated */\n\t\t\t\t\tif ( sAttr == \"H\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIHeader;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr == \"F\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = classes.sJUIFooter;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* The attribute can be in the format of \"#id.class\", \"#id\" or \"class\" This logic\n\t\t\t\t\t * breaks the string into parts and applies them as needed\n\t\t\t\t\t */\n\t\t\t\t\tif ( sAttr.indexOf('.') != -1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar aSplit = sAttr.split('.');\n\t\t\t\t\t\tnNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);\n\t\t\t\t\t\tnNewNode.className = aSplit[1];\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr.charAt(0) == \"#\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.id = sAttr.substr(1, sAttr.length-1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.className = sAttr;\n\t\t\t\t\t}\n\t\n\t\t\t\t\ti += j; /* Move along the position array */\n\t\t\t\t}\n\t\n\t\t\t\tinsert.append( nNewNode );\n\t\t\t\tinsert = $(nNewNode);\n\t\t\t}\n\t\t\telse if ( cOption == '>' )\n\t\t\t{\n\t\t\t\t/* End container div */\n\t\t\t\tinsert = insert.parent();\n\t\t\t}\n\t\t\t// @todo Move options into their own plugins?\n\t\t\telse if ( cOption == 'l' && features.bPaginate && features.bLengthChange )\n\t\t\t{\n\t\t\t\t/* Length */\n\t\t\t\tfeatureNode = _fnFeatureHtmlLength( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'f' && features.bFilter )\n\t\t\t{\n\t\t\t\t/* Filter */\n\t\t\t\tfeatureNode = _fnFeatureHtmlFilter( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'r' && features.bProcessing )\n\t\t\t{\n\t\t\t\t/* pRocessing */\n\t\t\t\tfeatureNode = _fnFeatureHtmlProcessing( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 't' )\n\t\t\t{\n\t\t\t\t/* Table */\n\t\t\t\tfeatureNode = _fnFeatureHtmlTable( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption ==  'i' && features.bInfo )\n\t\t\t{\n\t\t\t\t/* Info */\n\t\t\t\tfeatureNode = _fnFeatureHtmlInfo( oSettings );\n\t\t\t}\n\t\t\telse if ( cOption == 'p' && features.bPaginate )\n\t\t\t{\n\t\t\t\t/* Pagination */\n\t\t\t\tfeatureNode = _fnFeatureHtmlPaginate( oSettings );\n\t\t\t}\n\t\t\telse if ( DataTable.ext.feature.length !== 0 )\n\t\t\t{\n\t\t\t\t/* Plug-in features */\n\t\t\t\tvar aoFeatures = DataTable.ext.feature;\n\t\t\t\tfor ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )\n\t\t\t\t{\n\t\t\t\t\tif ( cOption == aoFeatures[k].cFeature )\n\t\t\t\t\t{\n\t\t\t\t\t\tfeatureNode = aoFeatures[k].fnInit( oSettings );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Add to the 2D features array */\n\t\t\tif ( featureNode )\n\t\t\t{\n\t\t\t\tvar aanFeatures = oSettings.aanFeatures;\n\t\n\t\t\t\tif ( ! aanFeatures[cOption] )\n\t\t\t\t{\n\t\t\t\t\taanFeatures[cOption] = [];\n\t\t\t\t}\n\t\n\t\t\t\taanFeatures[cOption].push( featureNode );\n\t\t\t\tinsert.append( featureNode );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Built our DOM structure - replace the holding div with what we want */\n\t\tholding.replaceWith( insert );\n\t\toSettings.nHolding = null;\n\t}\n\t\n\t\n\t/**\n\t * Use the DOM source to create up an array of header cells. The idea here is to\n\t * create a layout grid (array) of rows x columns, which contains a reference\n\t * to the cell that that point in the grid (regardless of col/rowspan), such that\n\t * any column / row could be removed and the new grid constructed\n\t *  @param array {object} aLayout Array to store the calculated layout in\n\t *  @param {node} nThead The header/footer element for the table\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDetectHeader ( aLayout, nThead )\n\t{\n\t\tvar nTrs = $(nThead).children('tr');\n\t\tvar nTr, nCell;\n\t\tvar i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;\n\t\tvar bUnique;\n\t\tvar fnShiftCol = function ( a, i, j ) {\n\t\t\tvar k = a[i];\n\t                while ( k[j] ) {\n\t\t\t\tj++;\n\t\t\t}\n\t\t\treturn j;\n\t\t};\n\t\n\t\taLayout.splice( 0, aLayout.length );\n\t\n\t\t/* We know how many rows there are in the layout - so prep it */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taLayout.push( [] );\n\t\t}\n\t\n\t\t/* Calculate a layout array */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnTr = nTrs[i];\n\t\t\tiColumn = 0;\n\t\n\t\t\t/* For every cell in the row... */\n\t\t\tnCell = nTr.firstChild;\n\t\t\twhile ( nCell ) {\n\t\t\t\tif ( nCell.nodeName.toUpperCase() == \"TD\" ||\n\t\t\t\t     nCell.nodeName.toUpperCase() == \"TH\" )\n\t\t\t\t{\n\t\t\t\t\t/* Get the col and rowspan attributes from the DOM and sanitise them */\n\t\t\t\t\tiColspan = nCell.getAttribute('colspan') * 1;\n\t\t\t\t\tiRowspan = nCell.getAttribute('rowspan') * 1;\n\t\t\t\t\tiColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;\n\t\t\t\t\tiRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;\n\t\n\t\t\t\t\t/* There might be colspan cells already in this row, so shift our target\n\t\t\t\t\t * accordingly\n\t\t\t\t\t */\n\t\t\t\t\tiColShifted = fnShiftCol( aLayout, i, iColumn );\n\t\n\t\t\t\t\t/* Cache calculation for unique columns */\n\t\t\t\t\tbUnique = iColspan === 1 ? true : false;\n\t\n\t\t\t\t\t/* If there is col / rowspan, copy the information into the layout grid */\n\t\t\t\t\tfor ( l=0 ; l<iColspan ; l++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taLayout[i+k][iColShifted+l] = {\n\t\t\t\t\t\t\t\t\"cell\": nCell,\n\t\t\t\t\t\t\t\t\"unique\": bUnique\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\taLayout[i+k].nTr = nTr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnCell = nCell.nextSibling;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Get an array of unique th elements, one for each column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nHeader automatically detect the layout from this node - optional\n\t *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional\n\t *  @returns array {node} aReturn list of unique th's\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetUniqueThs ( oSettings, nHeader, aLayout )\n\t{\n\t\tvar aReturn = [];\n\t\tif ( !aLayout )\n\t\t{\n\t\t\taLayout = oSettings.aoHeader;\n\t\t\tif ( nHeader )\n\t\t\t{\n\t\t\t\taLayout = [];\n\t\t\t\t_fnDetectHeader( aLayout, nHeader );\n\t\t\t}\n\t\t}\n\t\n\t\tfor ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfor ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tif ( aLayout[i][j].unique &&\n\t\t\t\t\t (!aReturn[j] || !oSettings.bSortCellsTop) )\n\t\t\t\t{\n\t\t\t\t\taReturn[j] = aLayout[i][j].cell;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn aReturn;\n\t}\n\t\n\t/**\n\t * Create an Ajax call based on the table's settings, taking into account that\n\t * parameters can have multiple forms, and backwards compatibility.\n\t *\n\t * @param {object} oSettings dataTables settings object\n\t * @param {array} data Data to send to the server, required by\n\t *     DataTables - may be augmented by developer callbacks\n\t * @param {function} fn Callback function to run when data is obtained\n\t */\n\tfunction _fnBuildAjax( oSettings, data, fn )\n\t{\n\t\t// Compatibility with 1.9-, allow fnServerData and event to manipulate\n\t\t_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );\n\t\n\t\t// Convert to object based for 1.10+ if using the old array scheme which can\n\t\t// come from server-side processing or serverParams\n\t\tif ( data && $.isArray(data) ) {\n\t\t\tvar tmp = {};\n\t\t\tvar rbracket = /(.*?)\\[\\]$/;\n\t\n\t\t\t$.each( data, function (key, val) {\n\t\t\t\tvar match = val.name.match(rbracket);\n\t\n\t\t\t\tif ( match ) {\n\t\t\t\t\t// Support for arrays\n\t\t\t\t\tvar name = match[0];\n\t\n\t\t\t\t\tif ( ! tmp[ name ] ) {\n\t\t\t\t\t\ttmp[ name ] = [];\n\t\t\t\t\t}\n\t\t\t\t\ttmp[ name ].push( val.value );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttmp[val.name] = val.value;\n\t\t\t\t}\n\t\t\t} );\n\t\t\tdata = tmp;\n\t\t}\n\t\n\t\tvar ajaxData;\n\t\tvar ajax = oSettings.ajax;\n\t\tvar instance = oSettings.oInstance;\n\t\tvar callback = function ( json ) {\n\t\t\t_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );\n\t\t\tfn( json );\n\t\t};\n\t\n\t\tif ( $.isPlainObject( ajax ) && ajax.data )\n\t\t{\n\t\t\tajaxData = ajax.data;\n\t\n\t\t\tvar newData = typeof ajaxData === 'function' ?\n\t\t\t\tajaxData( data, oSettings ) :  // fn can manipulate data or return\n\t\t\t\tajaxData;                      // an object object or array to merge\n\t\n\t\t\t// If the function returned something, use that alone\n\t\t\tdata = typeof ajaxData === 'function' && newData ?\n\t\t\t\tnewData :\n\t\t\t\t$.extend( true, data, newData );\n\t\n\t\t\t// Remove the data property as we've resolved it already and don't want\n\t\t\t// jQuery to do it again (it is restored at the end of the function)\n\t\t\tdelete ajax.data;\n\t\t}\n\t\n\t\tvar baseAjax = {\n\t\t\t\"data\": data,\n\t\t\t\"success\": function (json) {\n\t\t\t\tvar error = json.error || json.sError;\n\t\t\t\tif ( error ) {\n\t\t\t\t\t_fnLog( oSettings, 0, error );\n\t\t\t\t}\n\t\n\t\t\t\toSettings.json = json;\n\t\t\t\tcallback( json );\n\t\t\t},\n\t\t\t\"dataType\": \"json\",\n\t\t\t\"cache\": false,\n\t\t\t\"type\": oSettings.sServerMethod,\n\t\t\t\"error\": function (xhr, error, thrown) {\n\t\t\t\tvar ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );\n\t\n\t\t\t\tif ( $.inArray( true, ret ) === -1 ) {\n\t\t\t\t\tif ( error == \"parsererror\" ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Invalid JSON response', 1 );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( xhr.readyState === 4 ) {\n\t\t\t\t\t\t_fnLog( oSettings, 0, 'Ajax error', 7 );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\t}\n\t\t};\n\t\n\t\t// Store the data submitted for the API\n\t\toSettings.oAjaxData = data;\n\t\n\t\t// Allow plug-ins and external processes to modify the data\n\t\t_fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );\n\t\n\t\tif ( oSettings.fnServerData )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.fnServerData.call( instance,\n\t\t\t\toSettings.sAjaxSource,\n\t\t\t\t$.map( data, function (val, key) { // Need to convert back to 1.9 trad format\n\t\t\t\t\treturn { name: key, value: val };\n\t\t\t\t} ),\n\t\t\t\tcallback,\n\t\t\t\toSettings\n\t\t\t);\n\t\t}\n\t\telse if ( oSettings.sAjaxSource || typeof ajax === 'string' )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, {\n\t\t\t\turl: ajax || oSettings.sAjaxSource\n\t\t\t} ) );\n\t\t}\n\t\telse if ( typeof ajax === 'function' )\n\t\t{\n\t\t\t// Is a function - let the caller define what needs to be done\n\t\t\toSettings.jqXHR = ajax.call( instance, data, callback, oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Object to extend the base settings\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );\n\t\n\t\t\t// Restore for next time around\n\t\t\tajax.data = ajaxData;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Update the table using an Ajax call\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {boolean} Block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdate( settings )\n\t{\n\t\tif ( settings.bAjaxDataGet ) {\n\t\t\tsettings.iDraw++;\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t_fnBuildAjax(\n\t\t\t\tsettings,\n\t\t\t\t_fnAjaxParameters( settings ),\n\t\t\t\tfunction(json) {\n\t\t\t\t\t_fnAjaxUpdateDraw( settings, json );\n\t\t\t\t}\n\t\t\t);\n\t\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\t\n\t/**\n\t * Build up the parameters in an object needed for a server-side processing\n\t * request. Note that this is basically done twice, is different ways - a modern\n\t * method which is used by default in DataTables 1.10 which uses objects and\n\t * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if\n\t * the sAjaxSource option is used in the initialisation, or the legacyAjax\n\t * option is set.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {bool} block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxParameters( settings )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tcolumnCount = columns.length,\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tpreSearch = settings.oPreviousSearch,\n\t\t\tpreColSearch = settings.aoPreSearchCols,\n\t\t\ti, data = [], dataProp, column, columnSearch,\n\t\t\tsort = _fnSortFlatten( settings ),\n\t\t\tdisplayStart = settings._iDisplayStart,\n\t\t\tdisplayLength = features.bPaginate !== false ?\n\t\t\t\tsettings._iDisplayLength :\n\t\t\t\t-1;\n\t\n\t\tvar param = function ( name, value ) {\n\t\t\tdata.push( { 'name': name, 'value': value } );\n\t\t};\n\t\n\t\t// DataTables 1.9- compatible method\n\t\tparam( 'sEcho',          settings.iDraw );\n\t\tparam( 'iColumns',       columnCount );\n\t\tparam( 'sColumns',       _pluck( columns, 'sName' ).join(',') );\n\t\tparam( 'iDisplayStart',  displayStart );\n\t\tparam( 'iDisplayLength', displayLength );\n\t\n\t\t// DataTables 1.10+ method\n\t\tvar d = {\n\t\t\tdraw:    settings.iDraw,\n\t\t\tcolumns: [],\n\t\t\torder:   [],\n\t\t\tstart:   displayStart,\n\t\t\tlength:  displayLength,\n\t\t\tsearch:  {\n\t\t\t\tvalue: preSearch.sSearch,\n\t\t\t\tregex: preSearch.bRegex\n\t\t\t}\n\t\t};\n\t\n\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcolumnSearch = preColSearch[i];\n\t\t\tdataProp = typeof column.mData==\"function\" ? 'function' : column.mData ;\n\t\n\t\t\td.columns.push( {\n\t\t\t\tdata:       dataProp,\n\t\t\t\tname:       column.sName,\n\t\t\t\tsearchable: column.bSearchable,\n\t\t\t\torderable:  column.bSortable,\n\t\t\t\tsearch:     {\n\t\t\t\t\tvalue: columnSearch.sSearch,\n\t\t\t\t\tregex: columnSearch.bRegex\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\tparam( \"mDataProp_\"+i, dataProp );\n\t\n\t\t\tif ( features.bFilter ) {\n\t\t\t\tparam( 'sSearch_'+i,     columnSearch.sSearch );\n\t\t\t\tparam( 'bRegex_'+i,      columnSearch.bRegex );\n\t\t\t\tparam( 'bSearchable_'+i, column.bSearchable );\n\t\t\t}\n\t\n\t\t\tif ( features.bSort ) {\n\t\t\t\tparam( 'bSortable_'+i, column.bSortable );\n\t\t\t}\n\t\t}\n\t\n\t\tif ( features.bFilter ) {\n\t\t\tparam( 'sSearch', preSearch.sSearch );\n\t\t\tparam( 'bRegex', preSearch.bRegex );\n\t\t}\n\t\n\t\tif ( features.bSort ) {\n\t\t\t$.each( sort, function ( i, val ) {\n\t\t\t\td.order.push( { column: val.col, dir: val.dir } );\n\t\n\t\t\t\tparam( 'iSortCol_'+i, val.col );\n\t\t\t\tparam( 'sSortDir_'+i, val.dir );\n\t\t\t} );\n\t\n\t\t\tparam( 'iSortingCols', sort.length );\n\t\t}\n\t\n\t\t// If the legacy.ajax parameter is null, then we automatically decide which\n\t\t// form to use, based on sAjaxSource\n\t\tvar legacy = DataTable.ext.legacy.ajax;\n\t\tif ( legacy === null ) {\n\t\t\treturn settings.sAjaxSource ? data : d;\n\t\t}\n\t\n\t\t// Otherwise, if legacy has been specified then we use that to decide on the\n\t\t// form\n\t\treturn legacy ? data : d;\n\t}\n\t\n\t\n\t/**\n\t * Data the data from the server (nuking the old) and redraw the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} json json data return from the server.\n\t *  @param {string} json.sEcho Tracking flag for DataTables to match requests\n\t *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering\n\t *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering\n\t *  @param {array} json.aaData The data to display on this page\n\t *  @param {string} [json.sColumns] Column ordering (sName, comma separated)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdateDraw ( settings, json )\n\t{\n\t\t// v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.\n\t\t// Support both\n\t\tvar compat = function ( old, modern ) {\n\t\t\treturn json[old] !== undefined ? json[old] : json[modern];\n\t\t};\n\t\n\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\tvar draw            = compat( 'sEcho',                'draw' );\n\t\tvar recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );\n\t\tvar recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );\n\t\n\t\tif ( draw ) {\n\t\t\t// Protect against out of sequence returns\n\t\t\tif ( draw*1 < settings.iDraw ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettings.iDraw = draw * 1;\n\t\t}\n\t\n\t\t_fnClearTable( settings );\n\t\tsettings._iRecordsTotal   = parseInt(recordsTotal, 10);\n\t\tsettings._iRecordsDisplay = parseInt(recordsFiltered, 10);\n\t\n\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t_fnAddData( settings, data[i] );\n\t\t}\n\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\n\t\tsettings.bAjaxDataGet = false;\n\t\t_fnDraw( settings );\n\t\n\t\tif ( ! settings._bInitComplete ) {\n\t\t\t_fnInitComplete( settings, json );\n\t\t}\n\t\n\t\tsettings.bAjaxDataGet = true;\n\t\t_fnProcessingDisplay( settings, false );\n\t}\n\t\n\t\n\t/**\n\t * Get the data from the JSON data source to use for drawing a table. Using\n\t * `_fnGetObjectDataFn` allows the data to be sourced from a property of the\n\t * source object, or from a processing function.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param  {object} json Data source object / array from the server\n\t *  @return {array} Array of data to use\n\t */\n\tfunction _fnAjaxDataSrc ( oSettings, json )\n\t{\n\t\tvar dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?\n\t\t\toSettings.ajax.dataSrc :\n\t\t\toSettings.sAjaxDataProp; // Compatibility with 1.9-.\n\t\n\t\t// Compatibility with 1.9-. In order to read from aaData, check if the\n\t\t// default has been changed, if not, check for aaData\n\t\tif ( dataSrc === 'data' ) {\n\t\t\treturn json.aaData || json[dataSrc];\n\t\t}\n\t\n\t\treturn dataSrc !== \"\" ?\n\t\t\t_fnGetObjectDataFn( dataSrc )( json ) :\n\t\t\tjson;\n\t}\n\t\n\t/**\n\t * Generate the node required for filtering text\n\t *  @returns {node} Filter control element\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlFilter ( settings )\n\t{\n\t\tvar classes = settings.oClasses;\n\t\tvar tableId = settings.sTableId;\n\t\tvar language = settings.oLanguage;\n\t\tvar previousSearch = settings.oPreviousSearch;\n\t\tvar features = settings.aanFeatures;\n\t\tvar input = '<input type=\"search\" class=\"'+classes.sFilterInput+'\"/>';\n\t\n\t\tvar str = language.sSearch;\n\t\tstr = str.match(/_INPUT_/) ?\n\t\t\tstr.replace('_INPUT_', input) :\n\t\t\tstr+input;\n\t\n\t\tvar filter = $('<div/>', {\n\t\t\t\t'id': ! features.f ? tableId+'_filter' : null,\n\t\t\t\t'class': classes.sFilter\n\t\t\t} )\n\t\t\t.append( $('<label/>' ).append( str ) );\n\t\n\t\tvar searchFn = function() {\n\t\t\t/* Update all other filter input elements for the new display */\n\t\t\tvar n = features.f;\n\t\t\tvar val = !this.value ? \"\" : this.value; // mental IE8 fix :-(\n\t\n\t\t\t/* Now do the filter */\n\t\t\tif ( val != previousSearch.sSearch ) {\n\t\t\t\t_fnFilterComplete( settings, {\n\t\t\t\t\t\"sSearch\": val,\n\t\t\t\t\t\"bRegex\": previousSearch.bRegex,\n\t\t\t\t\t\"bSmart\": previousSearch.bSmart ,\n\t\t\t\t\t\"bCaseInsensitive\": previousSearch.bCaseInsensitive\n\t\t\t\t} );\n\t\n\t\t\t\t// Need to redraw, without resorting\n\t\t\t\tsettings._iDisplayStart = 0;\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t};\n\t\n\t\tvar searchDelay = settings.searchDelay !== null ?\n\t\t\tsettings.searchDelay :\n\t\t\t_fnDataSource( settings ) === 'ssp' ?\n\t\t\t\t400 :\n\t\t\t\t0;\n\t\n\t\tvar jqFilter = $('input', filter)\n\t\t\t.val( previousSearch.sSearch )\n\t\t\t.attr( 'placeholder', language.sSearchPlaceholder )\n\t\t\t.on(\n\t\t\t\t'keyup.DT search.DT input.DT paste.DT cut.DT',\n\t\t\t\tsearchDelay ?\n\t\t\t\t\t_fnThrottle( searchFn, searchDelay ) :\n\t\t\t\t\tsearchFn\n\t\t\t)\n\t\t\t.on( 'keypress.DT', function(e) {\n\t\t\t\t/* Prevent form submission */\n\t\t\t\tif ( e.keyCode == 13 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.attr('aria-controls', tableId);\n\t\n\t\t// Update the input elements whenever the table is filtered\n\t\t$(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame...\n\t\t\t\ttry {\n\t\t\t\t\tif ( jqFilter[0] !== document.activeElement ) {\n\t\t\t\t\t\tjqFilter.val( previousSearch.sSearch );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch ( e ) {}\n\t\t\t}\n\t\t} );\n\t\n\t\treturn filter[0];\n\t}\n\t\n\t\n\t/**\n\t * Filter the table using both the global filter and column based filtering\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oSearch search information\n\t *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterComplete ( oSettings, oInput, iForce )\n\t{\n\t\tvar oPrevSearch = oSettings.oPreviousSearch;\n\t\tvar aoPrevSearch = oSettings.aoPreSearchCols;\n\t\tvar fnSaveFilter = function ( oFilter ) {\n\t\t\t/* Save the filtering values */\n\t\t\toPrevSearch.sSearch = oFilter.sSearch;\n\t\t\toPrevSearch.bRegex = oFilter.bRegex;\n\t\t\toPrevSearch.bSmart = oFilter.bSmart;\n\t\t\toPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;\n\t\t};\n\t\tvar fnRegex = function ( o ) {\n\t\t\t// Backwards compatibility with the bEscapeRegex option\n\t\t\treturn o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;\n\t\t};\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo As per sort - can this be moved into an event handler?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\t/* In server-side processing all filtering is done by the server, so no point hanging around here */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' )\n\t\t{\n\t\t\t/* Global filter */\n\t\t\t_fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );\n\t\t\tfnSaveFilter( oInput );\n\t\n\t\t\t/* Now do the individual column filter */\n\t\t\tfor ( var i=0 ; i<aoPrevSearch.length ; i++ )\n\t\t\t{\n\t\t\t\t_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),\n\t\t\t\t\taoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );\n\t\t\t}\n\t\n\t\t\t/* Custom filtering */\n\t\t\t_fnFilterCustom( oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfnSaveFilter( oInput );\n\t\t}\n\t\n\t\t/* Tell the draw function we have been filtering */\n\t\toSettings.bFiltered = true;\n\t\t_fnCallbackFire( oSettings, null, 'search', [oSettings] );\n\t}\n\t\n\t\n\t/**\n\t * Apply custom filtering functions\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCustom( settings )\n\t{\n\t\tvar filters = DataTable.ext.search;\n\t\tvar displayRows = settings.aiDisplay;\n\t\tvar row, rowIdx;\n\t\n\t\tfor ( var i=0, ien=filters.length ; i<ien ; i++ ) {\n\t\t\tvar rows = [];\n\t\n\t\t\t// Loop over each row and see if it should be included\n\t\t\tfor ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {\n\t\t\t\trowIdx = displayRows[ j ];\n\t\t\t\trow = settings.aoData[ rowIdx ];\n\t\n\t\t\t\tif ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {\n\t\t\t\t\trows.push( rowIdx );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// So the array reference doesn't break set the results into the\n\t\t\t// existing array\n\t\t\tdisplayRows.length = 0;\n\t\t\t$.merge( displayRows, rows );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Filter the table on a per-column basis\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sInput string to filter on\n\t *  @param {int} iColumn column to filter\n\t *  @param {bool} bRegex treat search string as a regular expression or not\n\t *  @param {bool} bSmart use smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )\n\t{\n\t\tif ( searchStr === '' ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar data;\n\t\tvar out = [];\n\t\tvar display = settings.aiDisplay;\n\t\tvar rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );\n\t\n\t\tfor ( var i=0 ; i<display.length ; i++ ) {\n\t\t\tdata = settings.aoData[ display[i] ]._aFilterData[ colIdx ];\n\t\n\t\t\tif ( rpSearch.test( data ) ) {\n\t\t\t\tout.push( display[i] );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aiDisplay = out;\n\t}\n\t\n\t\n\t/**\n\t * Filter the data table based on user input and draw the table\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} input string to filter on\n\t *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)\n\t *  @param {bool} regex treat as a regular expression or not\n\t *  @param {bool} smart perform smart filtering or not\n\t *  @param {bool} caseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilter( settings, input, force, regex, smart, caseInsensitive )\n\t{\n\t\tvar rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );\n\t\tvar prevSearch = settings.oPreviousSearch.sSearch;\n\t\tvar displayMaster = settings.aiDisplayMaster;\n\t\tvar display, invalidated, i;\n\t\tvar filtered = [];\n\t\n\t\t// Need to take account of custom filtering functions - always filter\n\t\tif ( DataTable.ext.search.length !== 0 ) {\n\t\t\tforce = true;\n\t\t}\n\t\n\t\t// Check if any of the rows were invalidated\n\t\tinvalidated = _fnFilterData( settings );\n\t\n\t\t// If the input is blank - we just want the full data set\n\t\tif ( input.length <= 0 ) {\n\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t}\n\t\telse {\n\t\t\t// New search - start from the master array\n\t\t\tif ( invalidated ||\n\t\t\t\t force ||\n\t\t\t\t prevSearch.length > input.length ||\n\t\t\t\t input.indexOf(prevSearch) !== 0 ||\n\t\t\t\t settings.bSorted // On resort, the display master needs to be\n\t\t\t\t                  // re-filtered since indexes will have changed\n\t\t\t) {\n\t\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t\t}\n\t\n\t\t\t// Search the display array\n\t\t\tdisplay = settings.aiDisplay;\n\t\n\t\t\tfor ( i=0 ; i<display.length ; i++ ) {\n\t\t\t\tif ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {\n\t\t\t\t\tfiltered.push( display[i] );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tsettings.aiDisplay = filtered;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a regular expression object suitable for searching a table\n\t *  @param {string} sSearch string to search for\n\t *  @param {bool} bRegex treat as a regular expression or not\n\t *  @param {bool} bSmart perform smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insensitive matching or not\n\t *  @returns {RegExp} constructed object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCreateSearch( search, regex, smart, caseInsensitive )\n\t{\n\t\tsearch = regex ?\n\t\t\tsearch :\n\t\t\t_fnEscapeRegex( search );\n\t\t\n\t\tif ( smart ) {\n\t\t\t/* For smart filtering we want to allow the search to work regardless of\n\t\t\t * word order. We also want double quoted text to be preserved, so word\n\t\t\t * order is important - a la google. So this is what we want to\n\t\t\t * generate:\n\t\t\t * \n\t\t\t * ^(?=.*?\\bone\\b)(?=.*?\\btwo three\\b)(?=.*?\\bfour\\b).*$\n\t\t\t */\n\t\t\tvar a = $.map( search.match( /\"[^\"]+\"|[^ ]+/g ) || [''], function ( word ) {\n\t\t\t\tif ( word.charAt(0) === '\"' ) {\n\t\t\t\t\tvar m = word.match( /^\"(.*)\"$/ );\n\t\t\t\t\tword = m ? m[1] : word;\n\t\t\t\t}\n\t\n\t\t\t\treturn word.replace('\"', '');\n\t\t\t} );\n\t\n\t\t\tsearch = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';\n\t\t}\n\t\n\t\treturn new RegExp( search, caseInsensitive ? 'i' : '' );\n\t}\n\t\n\t\n\t/**\n\t * Escape a string such that it can be used in a regular expression\n\t *  @param {string} sVal string to escape\n\t *  @returns {string} escaped string\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnEscapeRegex = DataTable.util.escapeRegex;\n\t\n\tvar __filter_div = $('<div>')[0];\n\tvar __filter_div_textContent = __filter_div.textContent !== undefined;\n\t\n\t// Update the filtering data for each row if needed (by invalidation or first run)\n\tfunction _fnFilterData ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar column;\n\t\tvar i, j, ien, jen, filterData, cellData, row;\n\t\tvar fomatters = DataTable.ext.type.search;\n\t\tvar wasInvalidated = false;\n\t\n\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aFilterData ) {\n\t\t\t\tfilterData = [];\n\t\n\t\t\t\tfor ( j=0, jen=columns.length ; j<jen ; j++ ) {\n\t\t\t\t\tcolumn = columns[j];\n\t\n\t\t\t\t\tif ( column.bSearchable ) {\n\t\t\t\t\t\tcellData = _fnGetCellData( settings, i, j, 'filter' );\n\t\n\t\t\t\t\t\tif ( fomatters[ column.sType ] ) {\n\t\t\t\t\t\t\tcellData = fomatters[ column.sType ]( cellData );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// Search in DataTables 1.10 is string based. In 1.11 this\n\t\t\t\t\t\t// should be altered to also allow strict type checking.\n\t\t\t\t\t\tif ( cellData === null ) {\n\t\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( typeof cellData !== 'string' && cellData.toString ) {\n\t\t\t\t\t\t\tcellData = cellData.toString();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If it looks like there is an HTML entity in the string,\n\t\t\t\t\t// attempt to decode it so sorting works as expected. Note that\n\t\t\t\t\t// we could use a single line of jQuery to do this, but the DOM\n\t\t\t\t\t// method used here is much faster http://jsperf.com/html-decode\n\t\t\t\t\tif ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {\n\t\t\t\t\t\t__filter_div.innerHTML = cellData;\n\t\t\t\t\t\tcellData = __filter_div_textContent ?\n\t\t\t\t\t\t\t__filter_div.textContent :\n\t\t\t\t\t\t\t__filter_div.innerText;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tif ( cellData.replace ) {\n\t\t\t\t\t\tcellData = cellData.replace(/[\\r\\n]/g, '');\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfilterData.push( cellData );\n\t\t\t\t}\n\t\n\t\t\t\trow._aFilterData = filterData;\n\t\t\t\trow._sFilterRow = filterData.join('  ');\n\t\t\t\twasInvalidated = true;\n\t\t\t}\n\t\t}\n\t\n\t\treturn wasInvalidated;\n\t}\n\t\n\t\n\t/**\n\t * Convert from the internal Hungarian notation to camelCase for external\n\t * interaction\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToCamel ( obj )\n\t{\n\t\treturn {\n\t\t\tsearch:          obj.sSearch,\n\t\t\tsmart:           obj.bSmart,\n\t\t\tregex:           obj.bRegex,\n\t\t\tcaseInsensitive: obj.bCaseInsensitive\n\t\t};\n\t}\n\t\n\t\n\t\n\t/**\n\t * Convert from camelCase notation to the internal Hungarian. We could use the\n\t * Hungarian convert function here, but this is cleaner\n\t *  @param {object} obj Object to convert\n\t *  @returns {object} Inverted object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSearchToHung ( obj )\n\t{\n\t\treturn {\n\t\t\tsSearch:          obj.search,\n\t\t\tbSmart:           obj.smart,\n\t\t\tbRegex:           obj.regex,\n\t\t\tbCaseInsensitive: obj.caseInsensitive\n\t\t};\n\t}\n\t\n\t/**\n\t * Generate the node required for the info display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Information element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlInfo ( settings )\n\t{\n\t\tvar\n\t\t\ttid = settings.sTableId,\n\t\t\tnodes = settings.aanFeatures.i,\n\t\t\tn = $('<div/>', {\n\t\t\t\t'class': settings.oClasses.sInfo,\n\t\t\t\t'id': ! nodes ? tid+'_info' : null\n\t\t\t} );\n\t\n\t\tif ( ! nodes ) {\n\t\t\t// Update display on each draw\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": _fnUpdateInfo,\n\t\t\t\t\"sName\": \"information\"\n\t\t\t} );\n\t\n\t\t\tn\n\t\t\t\t.attr( 'role', 'status' )\n\t\t\t\t.attr( 'aria-live', 'polite' );\n\t\n\t\t\t// Table is described by our info div\n\t\t\t$(settings.nTable).attr( 'aria-describedby', tid+'_info' );\n\t\t}\n\t\n\t\treturn n[0];\n\t}\n\t\n\t\n\t/**\n\t * Update the information elements in the display\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnUpdateInfo ( settings )\n\t{\n\t\t/* Show information about the table */\n\t\tvar nodes = settings.aanFeatures.i;\n\t\tif ( nodes.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\tlang  = settings.oLanguage,\n\t\t\tstart = settings._iDisplayStart+1,\n\t\t\tend   = settings.fnDisplayEnd(),\n\t\t\tmax   = settings.fnRecordsTotal(),\n\t\t\ttotal = settings.fnRecordsDisplay(),\n\t\t\tout   = total ?\n\t\t\t\tlang.sInfo :\n\t\t\t\tlang.sInfoEmpty;\n\t\n\t\tif ( total !== max ) {\n\t\t\t/* Record set after filtering */\n\t\t\tout += ' ' + lang.sInfoFiltered;\n\t\t}\n\t\n\t\t// Convert the macros\n\t\tout += lang.sInfoPostFix;\n\t\tout = _fnInfoMacros( settings, out );\n\t\n\t\tvar callback = lang.fnInfoCallback;\n\t\tif ( callback !== null ) {\n\t\t\tout = callback.call( settings.oInstance,\n\t\t\t\tsettings, start, end, max, total, out\n\t\t\t);\n\t\t}\n\t\n\t\t$(nodes).html( out );\n\t}\n\t\n\t\n\tfunction _fnInfoMacros ( settings, str )\n\t{\n\t\t// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only\n\t\t// internally\n\t\tvar\n\t\t\tformatter  = settings.fnFormatNumber,\n\t\t\tstart      = settings._iDisplayStart+1,\n\t\t\tlen        = settings._iDisplayLength,\n\t\t\tvis        = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn str.\n\t\t\treplace(/_START_/g, formatter.call( settings, start ) ).\n\t\t\treplace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).\n\t\t\treplace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).\n\t\t\treplace(/_TOTAL_/g, formatter.call( settings, vis ) ).\n\t\t\treplace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).\n\t\t\treplace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );\n\t}\n\t\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitialise ( settings )\n\t{\n\t\tvar i, iLen, iAjaxStart=settings.iInitDisplayStart;\n\t\tvar columns = settings.aoColumns, column;\n\t\tvar features = settings.oFeatures;\n\t\tvar deferLoading = settings.bDeferLoading; // value modified by the draw\n\t\n\t\t/* Ensure that the table data is fully initialised */\n\t\tif ( ! settings.bInitialised ) {\n\t\t\tsetTimeout( function(){ _fnInitialise( settings ); }, 200 );\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Show the display HTML options */\n\t\t_fnAddOptionsHtml( settings );\n\t\n\t\t/* Build and draw the header / footer for the table */\n\t\t_fnBuildHead( settings );\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t/* Okay to show that something is going on now */\n\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t/* Calculate sizes for columns */\n\t\tif ( features.bAutoWidth ) {\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\n\t\t\tif ( column.sWidth ) {\n\t\t\t\tcolumn.nTh.style.width = _fnStringToCss( column.sWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'preInit', [settings] );\n\t\n\t\t// If there is default sorting required - let's do it. The sort function\n\t\t// will do the drawing for us. Otherwise we draw the table regardless of the\n\t\t// Ajax source - this allows the table to look initialised for Ajax sourcing\n\t\t// data (show 'loading' message possibly)\n\t\t_fnReDraw( settings );\n\t\n\t\t// Server-side processing init complete is done by _fnAjaxUpdateDraw\n\t\tvar dataSrc = _fnDataSource( settings );\n\t\tif ( dataSrc != 'ssp' || deferLoading ) {\n\t\t\t// if there is an ajax source load the data\n\t\t\tif ( dataSrc == 'ajax' ) {\n\t\t\t\t_fnBuildAjax( settings, [], function(json) {\n\t\t\t\t\tvar aData = _fnAjaxDataSrc( settings, json );\n\t\n\t\t\t\t\t// Got the data - add it to the table\n\t\t\t\t\tfor ( i=0 ; i<aData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( settings, aData[i] );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Reset the init display for cookie saving. We've already done\n\t\t\t\t\t// a filter, and therefore cleared it before. So we need to make\n\t\t\t\t\t// it appear 'fresh'\n\t\t\t\t\tsettings.iInitDisplayStart = iAjaxStart;\n\t\n\t\t\t\t\t_fnReDraw( settings );\n\t\n\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t_fnInitComplete( settings, json );\n\t\t\t\t}, settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t_fnInitComplete( settings );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} [json] JSON from the server that completed the table, if using Ajax source\n\t *    with client-side processing (optional)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitComplete ( settings, json )\n\t{\n\t\tsettings._bInitComplete = true;\n\t\n\t\t// When data was added after the initialisation (data or Ajax) we need to\n\t\t// calculate the column sizing\n\t\tif ( json || settings.oInit.aaData ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'plugin-init', [settings, json] );\n\t\t_fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );\n\t}\n\t\n\t\n\tfunction _fnLengthChange ( settings, val )\n\t{\n\t\tvar len = parseInt( val, 10 );\n\t\tsettings._iDisplayLength = len;\n\t\n\t\t_fnLengthOverflow( settings );\n\t\n\t\t// Fire length change event\n\t\t_fnCallbackFire( settings, null, 'length', [settings, len] );\n\t}\n\t\n\t\n\t/**\n\t * Generate the node required for user display length changing\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Display length feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlLength ( settings )\n\t{\n\t\tvar\n\t\t\tclasses  = settings.oClasses,\n\t\t\ttableId  = settings.sTableId,\n\t\t\tmenu     = settings.aLengthMenu,\n\t\t\td2       = $.isArray( menu[0] ),\n\t\t\tlengths  = d2 ? menu[0] : menu,\n\t\t\tlanguage = d2 ? menu[1] : menu;\n\t\n\t\tvar select = $('<select/>', {\n\t\t\t'name':          tableId+'_length',\n\t\t\t'aria-controls': tableId,\n\t\t\t'class':         classes.sLengthSelect\n\t\t} );\n\t\n\t\tfor ( var i=0, ien=lengths.length ; i<ien ; i++ ) {\n\t\t\tselect[0][ i ] = new Option(\n\t\t\t\ttypeof language[i] === 'number' ?\n\t\t\t\t\tsettings.fnFormatNumber( language[i] ) :\n\t\t\t\t\tlanguage[i],\n\t\t\t\tlengths[i]\n\t\t\t);\n\t\t}\n\t\n\t\tvar div = $('<div><label/></div>').addClass( classes.sLength );\n\t\tif ( ! settings.aanFeatures.l ) {\n\t\t\tdiv[0].id = tableId+'_length';\n\t\t}\n\t\n\t\tdiv.children().append(\n\t\t\tsettings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )\n\t\t);\n\t\n\t\t// Can't use `select` variable as user might provide their own and the\n\t\t// reference is broken by the use of outerHTML\n\t\t$('select', div)\n\t\t\t.val( settings._iDisplayLength )\n\t\t\t.on( 'change.DT', function(e) {\n\t\t\t\t_fnLengthChange( settings, $(this).val() );\n\t\t\t\t_fnDraw( settings );\n\t\t\t} );\n\t\n\t\t// Update node value whenever anything changes the table's length\n\t\t$(settings.nTable).on( 'length.dt.DT', function (e, s, len) {\n\t\t\tif ( settings === s ) {\n\t\t\t\t$('select', div).val( len );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn div[0];\n\t}\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Note that most of the paging logic is done in\n\t * DataTable.ext.pager\n\t */\n\t\n\t/**\n\t * Generate the node required for default pagination\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Pagination feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlPaginate ( settings )\n\t{\n\t\tvar\n\t\t\ttype   = settings.sPaginationType,\n\t\t\tplugin = DataTable.ext.pager[ type ],\n\t\t\tmodern = typeof plugin === 'function',\n\t\t\tredraw = function( settings ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t},\n\t\t\tnode = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],\n\t\t\tfeatures = settings.aanFeatures;\n\t\n\t\tif ( ! modern ) {\n\t\t\tplugin.fnInit( settings, node, redraw );\n\t\t}\n\t\n\t\t/* Add a draw callback for the pagination on first instance, to update the paging display */\n\t\tif ( ! features.p )\n\t\t{\n\t\t\tnode.id = settings.sTableId+'_paginate';\n\t\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": function( settings ) {\n\t\t\t\t\tif ( modern ) {\n\t\t\t\t\t\tvar\n\t\t\t\t\t\t\tstart      = settings._iDisplayStart,\n\t\t\t\t\t\t\tlen        = settings._iDisplayLength,\n\t\t\t\t\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\t\t\t\t\tall        = len === -1,\n\t\t\t\t\t\t\tpage = all ? 0 : Math.ceil( start / len ),\n\t\t\t\t\t\t\tpages = all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\t\t\t\tbuttons = plugin(page, pages),\n\t\t\t\t\t\t\ti, ien;\n\t\n\t\t\t\t\t\tfor ( i=0, ien=features.p.length ; i<ien ; i++ ) {\n\t\t\t\t\t\t\t_fnRenderer( settings, 'pageButton' )(\n\t\t\t\t\t\t\t\tsettings, features.p[i], i, buttons, page, pages\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tplugin.fnUpdate( settings, redraw );\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"sName\": \"pagination\"\n\t\t\t} );\n\t\t}\n\t\n\t\treturn node;\n\t}\n\t\n\t\n\t/**\n\t * Alter the display settings to change the page\n\t *  @param {object} settings DataTables settings object\n\t *  @param {string|int} action Paging action to take: \"first\", \"previous\",\n\t *    \"next\" or \"last\" or page number to jump to (integer)\n\t *  @param [bool] redraw Automatically draw the update or not\n\t *  @returns {bool} true page has changed, false - no change\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnPageChange ( settings, action, redraw )\n\t{\n\t\tvar\n\t\t\tstart     = settings._iDisplayStart,\n\t\t\tlen       = settings._iDisplayLength,\n\t\t\trecords   = settings.fnRecordsDisplay();\n\t\n\t\tif ( records === 0 || len === -1 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( typeof action === \"number\" )\n\t\t{\n\t\t\tstart = action * len;\n\t\n\t\t\tif ( start > records )\n\t\t\t{\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"first\" )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( action == \"previous\" )\n\t\t{\n\t\t\tstart = len >= 0 ?\n\t\t\t\tstart - len :\n\t\t\t\t0;\n\t\n\t\t\tif ( start < 0 )\n\t\t\t{\n\t\t\t  start = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"next\" )\n\t\t{\n\t\t\tif ( start + len < records )\n\t\t\t{\n\t\t\t\tstart += len;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"last\" )\n\t\t{\n\t\t\tstart = Math.floor( (records-1) / len) * len;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_fnLog( settings, 0, \"Unknown paging action: \"+action, 5 );\n\t\t}\n\t\n\t\tvar changed = settings._iDisplayStart !== start;\n\t\tsettings._iDisplayStart = start;\n\t\n\t\tif ( changed ) {\n\t\t\t_fnCallbackFire( settings, null, 'page', [settings] );\n\t\n\t\t\tif ( redraw ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t}\n\t\n\t\treturn changed;\n\t}\n\t\n\t\n\t\n\t/**\n\t * Generate the node required for the processing node\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Processing element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlProcessing ( settings )\n\t{\n\t\treturn $('<div/>', {\n\t\t\t\t'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,\n\t\t\t\t'class': settings.oClasses.sProcessing\n\t\t\t} )\n\t\t\t.html( settings.oLanguage.sProcessing )\n\t\t\t.insertBefore( settings.nTable )[0];\n\t}\n\t\n\t\n\t/**\n\t * Display or hide the processing indicator\n\t *  @param {object} settings dataTables settings object\n\t *  @param {bool} show Show the processing indicator (true) or not (false)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnProcessingDisplay ( settings, show )\n\t{\n\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t$(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'processing', [settings, show] );\n\t}\n\t\n\t/**\n\t * Add any control elements for the table - specifically scrolling\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Node to add to the DOM\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlTable ( settings )\n\t{\n\t\tvar table = $(settings.nTable);\n\t\n\t\t// Add the ARIA grid role to the table\n\t\ttable.attr( 'role', 'grid' );\n\t\n\t\t// Scrolling from here on in\n\t\tvar scroll = settings.oScroll;\n\t\n\t\tif ( scroll.sX === '' && scroll.sY === '' ) {\n\t\t\treturn settings.nTable;\n\t\t}\n\t\n\t\tvar scrollX = scroll.sX;\n\t\tvar scrollY = scroll.sY;\n\t\tvar classes = settings.oClasses;\n\t\tvar caption = table.children('caption');\n\t\tvar captionSide = caption.length ? caption[0]._captionSide : null;\n\t\tvar headerClone = $( table[0].cloneNode(false) );\n\t\tvar footerClone = $( table[0].cloneNode(false) );\n\t\tvar footer = table.children('tfoot');\n\t\tvar _div = '<div/>';\n\t\tvar size = function ( s ) {\n\t\t\treturn !s ? null : _fnStringToCss( s );\n\t\t};\n\t\n\t\tif ( ! footer.length ) {\n\t\t\tfooter = null;\n\t\t}\n\t\n\t\t/*\n\t\t * The HTML structure that we want to generate in this function is:\n\t\t *  div - scroller\n\t\t *    div - scroll head\n\t\t *      div - scroll head inner\n\t\t *        table - scroll head table\n\t\t *          thead - thead\n\t\t *    div - scroll body\n\t\t *      table - table (master table)\n\t\t *        thead - thead clone for sizing\n\t\t *        tbody - tbody\n\t\t *    div - scroll foot\n\t\t *      div - scroll foot inner\n\t\t *        table - scroll foot table\n\t\t *          tfoot - tfoot\n\t\t */\n\t\tvar scroller = $( _div, { 'class': classes.sScrollWrapper } )\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollHead } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollHeadInner } )\n\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t'box-sizing': 'content-box',\n\t\t\t\t\t\t\t\twidth: scroll.sXInner || '100%'\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\theaderClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'top' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('thead')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t)\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollBody } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\toverflow: 'auto',\n\t\t\t\t\t\twidth: size( scrollX )\n\t\t\t\t\t} )\n\t\t\t\t\t.append( table )\n\t\t\t);\n\t\n\t\tif ( footer ) {\n\t\t\tscroller.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollFoot } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollFootInner } )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\tfooterClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append( captionSide === 'bottom' ? caption : null )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('tfoot')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\n\t\tvar children = scroller.children();\n\t\tvar scrollHead = children[0];\n\t\tvar scrollBody = children[1];\n\t\tvar scrollFoot = footer ? children[2] : null;\n\t\n\t\t// When the body is scrolled, then we also want to scroll the headers\n\t\tif ( scrollX ) {\n\t\t\t$(scrollBody).on( 'scroll.DT', function (e) {\n\t\t\t\tvar scrollLeft = this.scrollLeft;\n\t\n\t\t\t\tscrollHead.scrollLeft = scrollLeft;\n\t\n\t\t\t\tif ( footer ) {\n\t\t\t\t\tscrollFoot.scrollLeft = scrollLeft;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\n\t\t$(scrollBody).css(\n\t\t\tscrollY && scroll.bCollapse ? 'max-height' : 'height', \n\t\t\tscrollY\n\t\t);\n\t\n\t\tsettings.nScrollHead = scrollHead;\n\t\tsettings.nScrollBody = scrollBody;\n\t\tsettings.nScrollFoot = scrollFoot;\n\t\n\t\t// On redraw - align columns\n\t\tsettings.aoDrawCallback.push( {\n\t\t\t\"fn\": _fnScrollDraw,\n\t\t\t\"sName\": \"scrolling\"\n\t\t} );\n\t\n\t\treturn scroller[0];\n\t}\n\t\n\t\n\t\n\t/**\n\t * Update the header, footer and body tables for resizing - i.e. column\n\t * alignment.\n\t *\n\t * Welcome to the most horrible function DataTables. The process that this\n\t * function follows is basically:\n\t *   1. Re-create the table inside the scrolling div\n\t *   2. Take live measurements from the DOM\n\t *   3. Apply the measurements to align the columns\n\t *   4. Clean up\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnScrollDraw ( settings )\n\t{\n\t\t// Given that this is such a monster function, a lot of variables are use\n\t\t// to try and keep the minimised size as small as possible\n\t\tvar\n\t\t\tscroll         = settings.oScroll,\n\t\t\tscrollX        = scroll.sX,\n\t\t\tscrollXInner   = scroll.sXInner,\n\t\t\tscrollY        = scroll.sY,\n\t\t\tbarWidth       = scroll.iBarWidth,\n\t\t\tdivHeader      = $(settings.nScrollHead),\n\t\t\tdivHeaderStyle = divHeader[0].style,\n\t\t\tdivHeaderInner = divHeader.children('div'),\n\t\t\tdivHeaderInnerStyle = divHeaderInner[0].style,\n\t\t\tdivHeaderTable = divHeaderInner.children('table'),\n\t\t\tdivBodyEl      = settings.nScrollBody,\n\t\t\tdivBody        = $(divBodyEl),\n\t\t\tdivBodyStyle   = divBodyEl.style,\n\t\t\tdivFooter      = $(settings.nScrollFoot),\n\t\t\tdivFooterInner = divFooter.children('div'),\n\t\t\tdivFooterTable = divFooterInner.children('table'),\n\t\t\theader         = $(settings.nTHead),\n\t\t\ttable          = $(settings.nTable),\n\t\t\ttableEl        = table[0],\n\t\t\ttableStyle     = tableEl.style,\n\t\t\tfooter         = settings.nTFoot ? $(settings.nTFoot) : null,\n\t\t\tbrowser        = settings.oBrowser,\n\t\t\tie67           = browser.bScrollOversize,\n\t\t\tdtHeaderCells  = _pluck( settings.aoColumns, 'nTh' ),\n\t\t\theaderTrgEls, footerTrgEls,\n\t\t\theaderSrcEls, footerSrcEls,\n\t\t\theaderCopy, footerCopy,\n\t\t\theaderWidths=[], footerWidths=[],\n\t\t\theaderContent=[], footerContent=[],\n\t\t\tidx, correction, sanityWidth,\n\t\t\tzeroOut = function(nSizer) {\n\t\t\t\tvar style = nSizer.style;\n\t\t\t\tstyle.paddingTop = \"0\";\n\t\t\t\tstyle.paddingBottom = \"0\";\n\t\t\t\tstyle.borderTopWidth = \"0\";\n\t\t\t\tstyle.borderBottomWidth = \"0\";\n\t\t\t\tstyle.height = 0;\n\t\t\t};\n\t\n\t\t// If the scrollbar visibility has changed from the last draw, we need to\n\t\t// adjust the column sizes as the table width will have changed to account\n\t\t// for the scrollbar\n\t\tvar scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;\n\t\t\n\t\tif ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t\treturn; // adjust column sizing will call this function again\n\t\t}\n\t\telse {\n\t\t\tsettings.scrollBarVis = scrollBarVis;\n\t\t}\n\t\n\t\t/*\n\t\t * 1. Re-create the table inside the scrolling div\n\t\t */\n\t\n\t\t// Remove the old minimised thead and tfoot elements in the inner table\n\t\ttable.children('thead, tfoot').remove();\n\t\n\t\tif ( footer ) {\n\t\t\tfooterCopy = footer.clone().prependTo( table );\n\t\t\tfooterTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized\n\t\t\tfooterSrcEls = footerCopy.find('tr');\n\t\t}\n\t\n\t\t// Clone the current header and footer elements and then place it into the inner table\n\t\theaderCopy = header.clone().prependTo( table );\n\t\theaderTrgEls = header.find('tr'); // original header is in its own table\n\t\theaderSrcEls = headerCopy.find('tr');\n\t\theaderCopy.find('th, td').removeAttr('tabindex');\n\t\n\t\n\t\t/*\n\t\t * 2. Take live measurements from the DOM - do not alter the DOM itself!\n\t\t */\n\t\n\t\t// Remove old sizing and apply the calculated column widths\n\t\t// Get the unique column headers in the newly created (cloned) header. We want to apply the\n\t\t// calculated sizes to this header\n\t\tif ( ! scrollX )\n\t\t{\n\t\t\tdivBodyStyle.width = '100%';\n\t\t\tdivHeader[0].style.width = '100%';\n\t\t}\n\t\n\t\t$.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {\n\t\t\tidx = _fnVisibleToColumnIndex( settings, i );\n\t\t\tel.style.width = settings.aoColumns[idx].sWidth;\n\t\t} );\n\t\n\t\tif ( footer ) {\n\t\t\t_fnApplyToChildren( function(n) {\n\t\t\t\tn.style.width = \"\";\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Size the table as a whole\n\t\tsanityWidth = table.outerWidth();\n\t\tif ( scrollX === \"\" ) {\n\t\t\t// No x scrolling\n\t\t\ttableStyle.width = \"100%\";\n\t\n\t\t\t// IE7 will make the width of the table when 100% include the scrollbar\n\t\t\t// - which is shouldn't. When there is a scrollbar we need to take this\n\t\t\t// into account.\n\t\t\tif ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);\n\t\t\t}\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\telse if ( scrollXInner !== \"\" ) {\n\t\t\t// legacy x scroll inner has been given - use it\n\t\t\ttableStyle.width = _fnStringToCss(scrollXInner);\n\t\n\t\t\t// Recalculate the sanity width\n\t\t\tsanityWidth = table.outerWidth();\n\t\t}\n\t\n\t\t// Hidden header should have zero height, so remove padding and borders. Then\n\t\t// set the width based on the real headers\n\t\n\t\t// Apply all styles in one pass\n\t\t_fnApplyToChildren( zeroOut, headerSrcEls );\n\t\n\t\t// Read all widths in next pass\n\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\theaderContent.push( nSizer.innerHTML );\n\t\t\theaderWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t}, headerSrcEls );\n\t\n\t\t// Apply all widths in final pass\n\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t// Only apply widths to the DataTables detected header cells - this\n\t\t\t// prevents complex headers from having contradictory sizes applied\n\t\t\tif ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {\n\t\t\t\tnToSize.style.width = headerWidths[i];\n\t\t\t}\n\t\t}, headerTrgEls );\n\t\n\t\t$(headerSrcEls).height(0);\n\t\n\t\t/* Same again with the footer if we have one */\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( zeroOut, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\t\tfooterContent.push( nSizer.innerHTML );\n\t\t\t\tfooterWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t\t}, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t\tnToSize.style.width = footerWidths[i];\n\t\t\t}, footerTrgEls );\n\t\n\t\t\t$(footerSrcEls).height(0);\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 3. Apply the measurements\n\t\t */\n\t\n\t\t// \"Hide\" the header and footer that we used for the sizing. We need to keep\n\t\t// the content of the cell so that the width applied to the header and body\n\t\t// both match, but we want to hide it completely. We want to also fix their\n\t\t// width to what they currently are\n\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\">'+headerContent[i]+'</div>';\n\t\t\tnSizer.childNodes[0].style.height = \"0\";\n\t\t\tnSizer.childNodes[0].style.overflow = \"hidden\";\n\t\t\tnSizer.style.width = headerWidths[i];\n\t\t}, headerSrcEls );\n\t\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\t\tnSizer.innerHTML = '<div class=\"dataTables_sizing\">'+footerContent[i]+'</div>';\n\t\t\t\tnSizer.childNodes[0].style.height = \"0\";\n\t\t\t\tnSizer.childNodes[0].style.overflow = \"hidden\";\n\t\t\t\tnSizer.style.width = footerWidths[i];\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Sanity check that the table is of a sensible width. If not then we are going to get\n\t\t// misalignment - try to prevent this by not allowing the table to shrink below its min width\n\t\tif ( table.outerWidth() < sanityWidth )\n\t\t{\n\t\t\t// The min width depends upon if we have a vertical scrollbar visible or not */\n\t\t\tcorrection = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")) ?\n\t\t\t\t\tsanityWidth+barWidth :\n\t\t\t\t\tsanityWidth;\n\t\n\t\t\t// IE6/7 are a law unto themselves...\n\t\t\tif ( ie67 && (divBodyEl.scrollHeight >\n\t\t\t\tdivBodyEl.offsetHeight || divBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( correction-barWidth );\n\t\t\t}\n\t\n\t\t\t// And give the user a warning that we've stopped the table getting too small\n\t\t\tif ( scrollX === \"\" || scrollXInner !== \"\" ) {\n\t\t\t\t_fnLog( settings, 1, 'Possible column misalignment', 6 );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcorrection = '100%';\n\t\t}\n\t\n\t\t// Apply to the container elements\n\t\tdivBodyStyle.width = _fnStringToCss( correction );\n\t\tdivHeaderStyle.width = _fnStringToCss( correction );\n\t\n\t\tif ( footer ) {\n\t\t\tsettings.nScrollFoot.style.width = _fnStringToCss( correction );\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 4. Clean up\n\t\t */\n\t\tif ( ! scrollY ) {\n\t\t\t/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting\n\t\t\t * the scrollbar height from the visible display, rather than adding it on. We need to\n\t\t\t * set the height in order to sort this. Don't want to do it in any other browsers.\n\t\t\t */\n\t\t\tif ( ie67 ) {\n\t\t\t\tdivBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Finally set the width's of the header and footer tables */\n\t\tvar iOuterWidth = table.outerWidth();\n\t\tdivHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\tdivHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );\n\t\n\t\t// Figure out if there are scrollbar present - if so then we need a the header and footer to\n\t\t// provide a bit more space to allow \"overflow\" scrolling (i.e. past the scrollbar)\n\t\tvar bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == \"scroll\";\n\t\tvar padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );\n\t\tdivHeaderInnerStyle[ padding ] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\n\t\tif ( footer ) {\n\t\t\tdivFooterTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style[padding] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\t}\n\t\n\t\t// Correct DOM ordering for colgroup - comes before the thead\n\t\ttable.children('colgroup').insertBefore( table.children('thead') );\n\t\n\t\t/* Adjust the position of the header in case we loose the y-scrollbar */\n\t\tdivBody.scroll();\n\t\n\t\t// If sorting or filtering has occurred, jump the scrolling back to the top\n\t\t// only if we aren't holding the position\n\t\tif ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {\n\t\t\tdivBodyEl.scrollTop = 0;\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Apply a given function to the display child nodes of an element array (typically\n\t * TD children of TR rows\n\t *  @param {function} fn Method to apply to the objects\n\t *  @param array {nodes} an1 List of elements to look through for display children\n\t *  @param array {nodes} an2 Another list (identical structure to the first) - optional\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyToChildren( fn, an1, an2 )\n\t{\n\t\tvar index=0, i=0, iLen=an1.length;\n\t\tvar nNode1, nNode2;\n\t\n\t\twhile ( i < iLen ) {\n\t\t\tnNode1 = an1[i].firstChild;\n\t\t\tnNode2 = an2 ? an2[i].firstChild : null;\n\t\n\t\t\twhile ( nNode1 ) {\n\t\t\t\tif ( nNode1.nodeType === 1 ) {\n\t\t\t\t\tif ( an2 ) {\n\t\t\t\t\t\tfn( nNode1, nNode2, index );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfn( nNode1, index );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\n\t\t\t\tnNode1 = nNode1.nextSibling;\n\t\t\t\tnNode2 = an2 ? nNode2.nextSibling : null;\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t}\n\t}\n\t\n\t\n\t\n\tvar __re_html_remove = /<.*?>/g;\n\t\n\t\n\t/**\n\t * Calculate the width of columns for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCalculateColumnWidths ( oSettings )\n\t{\n\t\tvar\n\t\t\ttable = oSettings.nTable,\n\t\t\tcolumns = oSettings.aoColumns,\n\t\t\tscroll = oSettings.oScroll,\n\t\t\tscrollY = scroll.sY,\n\t\t\tscrollX = scroll.sX,\n\t\t\tscrollXInner = scroll.sXInner,\n\t\t\tcolumnCount = columns.length,\n\t\t\tvisibleColumns = _fnGetColumns( oSettings, 'bVisible' ),\n\t\t\theaderCells = $('th', oSettings.nTHead),\n\t\t\ttableWidthAttr = table.getAttribute('width'), // from DOM element\n\t\t\ttableContainer = table.parentNode,\n\t\t\tuserInputs = false,\n\t\t\ti, column, columnIdx, width, outerWidth,\n\t\t\tbrowser = oSettings.oBrowser,\n\t\t\tie67 = browser.bScrollOversize;\n\t\n\t\tvar styleWidth = table.style.width;\n\t\tif ( styleWidth && styleWidth.indexOf('%') !== -1 ) {\n\t\t\ttableWidthAttr = styleWidth;\n\t\t}\n\t\n\t\t/* Convert any user input sizes into pixel sizes */\n\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\tif ( column.sWidth !== null ) {\n\t\t\t\tcolumn.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );\n\t\n\t\t\t\tuserInputs = true;\n\t\t\t}\n\t\t}\n\t\n\t\t/* If the number of columns in the DOM equals the number that we have to\n\t\t * process in DataTables, then we can use the offsets that are created by\n\t\t * the web- browser. No custom sizes can be set in order for this to happen,\n\t\t * nor scrolling used\n\t\t */\n\t\tif ( ie67 || ! userInputs && ! scrollX && ! scrollY &&\n\t\t     columnCount == _fnVisbleColumns( oSettings ) &&\n\t\t     columnCount == headerCells.length\n\t\t) {\n\t\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\t\tvar colIdx = _fnVisibleToColumnIndex( oSettings, i );\n\t\n\t\t\t\tif ( colIdx !== null ) {\n\t\t\t\t\tcolumns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise construct a single row, worst case, table with the widest\n\t\t\t// node in the data, assign any user defined widths, then insert it into\n\t\t\t// the DOM and allow the browser to do all the hard work of calculating\n\t\t\t// table widths\n\t\t\tvar tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table\n\t\t\t\t.css( 'visibility', 'hidden' )\n\t\t\t\t.removeAttr( 'id' );\n\t\n\t\t\t// Clean up the table body\n\t\t\ttmpTable.find('tbody tr').remove();\n\t\t\tvar tr = $('<tr/>').appendTo( tmpTable.find('tbody') );\n\t\n\t\t\t// Clone the table header and footer - we can't use the header / footer\n\t\t\t// from the cloned table, since if scrolling is active, the table's\n\t\t\t// real header and footer are contained in different table tags\n\t\t\ttmpTable.find('thead, tfoot').remove();\n\t\t\ttmpTable\n\t\t\t\t.append( $(oSettings.nTHead).clone() )\n\t\t\t\t.append( $(oSettings.nTFoot).clone() );\n\t\n\t\t\t// Remove any assigned widths from the footer (from scrolling)\n\t\t\ttmpTable.find('tfoot th, tfoot td').css('width', '');\n\t\n\t\t\t// Apply custom sizing to the cloned header\n\t\t\theaderCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );\n\t\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\t\theaderCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?\n\t\t\t\t\t_fnStringToCss( column.sWidthOrig ) :\n\t\t\t\t\t'';\n\t\n\t\t\t\t// For scrollX we need to force the column width otherwise the\n\t\t\t\t// browser will collapse it. If this width is smaller than the\n\t\t\t\t// width the column requires, then it will have no effect\n\t\t\t\tif ( column.sWidthOrig && scrollX ) {\n\t\t\t\t\t$( headerCells[i] ).append( $('<div/>').css( {\n\t\t\t\t\t\twidth: column.sWidthOrig,\n\t\t\t\t\t\tmargin: 0,\n\t\t\t\t\t\tpadding: 0,\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\theight: 1\n\t\t\t\t\t} ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Find the widest cell for each column and put it into the table\n\t\t\tif ( oSettings.aoData.length ) {\n\t\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\t\tcolumnIdx = visibleColumns[i];\n\t\t\t\t\tcolumn = columns[ columnIdx ];\n\t\n\t\t\t\t\t$( _fnGetWidestNode( oSettings, columnIdx ) )\n\t\t\t\t\t\t.clone( false )\n\t\t\t\t\t\t.append( column.sContentPadding )\n\t\t\t\t\t\t.appendTo( tr );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Tidy the temporary table - remove name attributes so there aren't\n\t\t\t// duplicated in the dom (radio elements for example)\n\t\t\t$('[name]', tmpTable).removeAttr('name');\n\t\n\t\t\t// Table has been built, attach to the document so we can work with it.\n\t\t\t// A holding element is used, positioned at the top of the container\n\t\t\t// with minimal height, so it has no effect on if the container scrolls\n\t\t\t// or not. Otherwise it might trigger scrolling when it actually isn't\n\t\t\t// needed\n\t\t\tvar holder = $('<div/>').css( scrollX || scrollY ?\n\t\t\t\t\t{\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\theight: 1,\n\t\t\t\t\t\tright: 0,\n\t\t\t\t\t\toverflow: 'hidden'\n\t\t\t\t\t} :\n\t\t\t\t\t{}\n\t\t\t\t)\n\t\t\t\t.append( tmpTable )\n\t\t\t\t.appendTo( tableContainer );\n\t\n\t\t\t// When scrolling (X or Y) we want to set the width of the table as \n\t\t\t// appropriate. However, when not scrolling leave the table width as it\n\t\t\t// is. This results in slightly different, but I think correct behaviour\n\t\t\tif ( scrollX && scrollXInner ) {\n\t\t\t\ttmpTable.width( scrollXInner );\n\t\t\t}\n\t\t\telse if ( scrollX ) {\n\t\t\t\ttmpTable.css( 'width', 'auto' );\n\t\t\t\ttmpTable.removeAttr('width');\n\t\n\t\t\t\t// If there is no width attribute or style, then allow the table to\n\t\t\t\t// collapse\n\t\t\t\tif ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {\n\t\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( scrollY ) {\n\t\t\t\ttmpTable.width( tableContainer.clientWidth );\n\t\t\t}\n\t\t\telse if ( tableWidthAttr ) {\n\t\t\t\ttmpTable.width( tableWidthAttr );\n\t\t\t}\n\t\n\t\t\t// Get the width of each column in the constructed table - we need to\n\t\t\t// know the inner width (so it can be assigned to the other table's\n\t\t\t// cells) and the outer width so we can calculate the full width of the\n\t\t\t// table. This is safe since DataTables requires a unique cell for each\n\t\t\t// column, but if ever a header can span multiple columns, this will\n\t\t\t// need to be modified.\n\t\t\tvar total = 0;\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tvar cell = $(headerCells[i]);\n\t\t\t\tvar border = cell.outerWidth() - cell.width();\n\t\n\t\t\t\t// Use getBounding... where possible (not IE8-) because it can give\n\t\t\t\t// sub-pixel accuracy, which we then want to round up!\n\t\t\t\tvar bounding = browser.bBounding ?\n\t\t\t\t\tMath.ceil( headerCells[i].getBoundingClientRect().width ) :\n\t\t\t\t\tcell.outerWidth();\n\t\n\t\t\t\t// Total is tracked to remove any sub-pixel errors as the outerWidth\n\t\t\t\t// of the table might not equal the total given here (IE!).\n\t\t\t\ttotal += bounding;\n\t\n\t\t\t\t// Width for each column to use\n\t\t\t\tcolumns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );\n\t\t\t}\n\t\n\t\t\ttable.style.width = _fnStringToCss( total );\n\t\n\t\t\t// Finished with the table - ditch it\n\t\t\tholder.remove();\n\t\t}\n\t\n\t\t// If there is a width attr, we want to attach an event listener which\n\t\t// allows the table sizing to automatically adjust when the window is\n\t\t// resized. Use the width attr rather than CSS, since we can't know if the\n\t\t// CSS is a relative value or absolute - DOM read is always px.\n\t\tif ( tableWidthAttr ) {\n\t\t\ttable.style.width = _fnStringToCss( tableWidthAttr );\n\t\t}\n\t\n\t\tif ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {\n\t\t\tvar bindResize = function () {\n\t\t\t\t$(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {\n\t\t\t\t\t_fnAdjustColumnSizing( oSettings );\n\t\t\t\t} ) );\n\t\t\t};\n\t\n\t\t\t// IE6/7 will crash if we bind a resize event handler on page load.\n\t\t\t// To be removed in 1.11 which drops IE6/7 support\n\t\t\tif ( ie67 ) {\n\t\t\t\tsetTimeout( bindResize, 1000 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbindResize();\n\t\t\t}\n\t\n\t\t\toSettings._reszEvt = true;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Throttle the calls to a function. Arguments and context are maintained for\n\t * the throttled function\n\t *  @param {function} fn Function to be called\n\t *  @param {int} [freq=200] call frequency in mS\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#oApi\n\t */\n\tvar _fnThrottle = DataTable.util.throttle;\n\t\n\t\n\t/**\n\t * Convert a CSS unit width to pixels (e.g. 2em)\n\t *  @param {string} width width to be converted\n\t *  @param {node} parent parent to get the with for (required for relative widths) - optional\n\t *  @returns {int} width in pixels\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnConvertToWidth ( width, parent )\n\t{\n\t\tif ( ! width ) {\n\t\t\treturn 0;\n\t\t}\n\t\n\t\tvar n = $('<div/>')\n\t\t\t.css( 'width', _fnStringToCss( width ) )\n\t\t\t.appendTo( parent || document.body );\n\t\n\t\tvar val = n[0].offsetWidth;\n\t\tn.remove();\n\t\n\t\treturn val;\n\t}\n\t\n\t\n\t/**\n\t * Get the widest node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {node} widest table node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetWidestNode( settings, colIdx )\n\t{\n\t\tvar idx = _fnGetMaxLenString( settings, colIdx );\n\t\tif ( idx < 0 ) {\n\t\t\treturn null;\n\t\t}\n\t\n\t\tvar data = settings.aoData[ idx ];\n\t\treturn ! data.nTr ? // Might not have been created when deferred rendering\n\t\t\t$('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :\n\t\t\tdata.anCells[ colIdx ];\n\t}\n\t\n\t\n\t/**\n\t * Get the maximum strlen for each data column\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {string} max string length for each column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetMaxLenString( settings, colIdx )\n\t{\n\t\tvar s, max=-1, maxIdx = -1;\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\ts = _fnGetCellData( settings, i, colIdx, 'display' )+'';\n\t\t\ts = s.replace( __re_html_remove, '' );\n\t\t\ts = s.replace( /&nbsp;/g, ' ' );\n\t\n\t\t\tif ( s.length > max ) {\n\t\t\t\tmax = s.length;\n\t\t\t\tmaxIdx = i;\n\t\t\t}\n\t\t}\n\t\n\t\treturn maxIdx;\n\t}\n\t\n\t\n\t/**\n\t * Append a CSS unit (only if required) to a string\n\t *  @param {string} value to css-ify\n\t *  @returns {string} value with css unit\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnStringToCss( s )\n\t{\n\t\tif ( s === null ) {\n\t\t\treturn '0px';\n\t\t}\n\t\n\t\tif ( typeof s == 'number' ) {\n\t\t\treturn s < 0 ?\n\t\t\t\t'0px' :\n\t\t\t\ts+'px';\n\t\t}\n\t\n\t\t// Check it has a unit character already\n\t\treturn s.match(/\\d$/) ?\n\t\t\ts+'px' :\n\t\t\ts;\n\t}\n\t\n\t\n\t\n\tfunction _fnSortFlatten ( settings )\n\t{\n\t\tvar\n\t\t\ti, iLen, k, kLen,\n\t\t\taSort = [],\n\t\t\taiOrig = [],\n\t\t\taoColumns = settings.aoColumns,\n\t\t\taDataSort, iCol, sType, srcCol,\n\t\t\tfixed = settings.aaSortingFixed,\n\t\t\tfixedObj = $.isPlainObject( fixed ),\n\t\t\tnestedSort = [],\n\t\t\tadd = function ( a ) {\n\t\t\t\tif ( a.length && ! $.isArray( a[0] ) ) {\n\t\t\t\t\t// 1D array\n\t\t\t\t\tnestedSort.push( a );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// 2D array\n\t\t\t\t\t$.merge( nestedSort, a );\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t// Build the sort array, with pre-fix and post-fix options if they have been\n\t\t// specified\n\t\tif ( $.isArray( fixed ) ) {\n\t\t\tadd( fixed );\n\t\t}\n\t\n\t\tif ( fixedObj && fixed.pre ) {\n\t\t\tadd( fixed.pre );\n\t\t}\n\t\n\t\tadd( settings.aaSorting );\n\t\n\t\tif (fixedObj && fixed.post ) {\n\t\t\tadd( fixed.post );\n\t\t}\n\t\n\t\tfor ( i=0 ; i<nestedSort.length ; i++ )\n\t\t{\n\t\t\tsrcCol = nestedSort[i][0];\n\t\t\taDataSort = aoColumns[ srcCol ].aDataSort;\n\t\n\t\t\tfor ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )\n\t\t\t{\n\t\t\t\tiCol = aDataSort[k];\n\t\t\t\tsType = aoColumns[ iCol ].sType || 'string';\n\t\n\t\t\t\tif ( nestedSort[i]._idx === undefined ) {\n\t\t\t\t\tnestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );\n\t\t\t\t}\n\t\n\t\t\t\taSort.push( {\n\t\t\t\t\tsrc:       srcCol,\n\t\t\t\t\tcol:       iCol,\n\t\t\t\t\tdir:       nestedSort[i][1],\n\t\t\t\t\tindex:     nestedSort[i]._idx,\n\t\t\t\t\ttype:      sType,\n\t\t\t\t\tformatter: DataTable.ext.type.order[ sType+\"-pre\" ]\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\treturn aSort;\n\t}\n\t\n\t/**\n\t * Change the order of the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t *  @todo This really needs split up!\n\t */\n\tfunction _fnSort ( oSettings )\n\t{\n\t\tvar\n\t\t\ti, ien, iLen, j, jLen, k, kLen,\n\t\t\tsDataType, nTh,\n\t\t\taiOrig = [],\n\t\t\toExtSort = DataTable.ext.type.order,\n\t\t\taoData = oSettings.aoData,\n\t\t\taoColumns = oSettings.aoColumns,\n\t\t\taDataSort, data, iCol, sType, oSort,\n\t\t\tformatters = 0,\n\t\t\tsortCol,\n\t\t\tdisplayMaster = oSettings.aiDisplayMaster,\n\t\t\taSort;\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo Can this be moved into a 'data-ready' handler which is called when\n\t\t//   data is going to be used in the table?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\taSort = _fnSortFlatten( oSettings );\n\t\n\t\tfor ( i=0, ien=aSort.length ; i<ien ; i++ ) {\n\t\t\tsortCol = aSort[i];\n\t\n\t\t\t// Track if we can use the fast sort algorithm\n\t\t\tif ( sortCol.formatter ) {\n\t\t\t\tformatters++;\n\t\t\t}\n\t\n\t\t\t// Load the data needed for the sort, for each cell\n\t\t\t_fnSortData( oSettings, sortCol.col );\n\t\t}\n\t\n\t\t/* No sorting required if server-side or no sorting array */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )\n\t\t{\n\t\t\t// Create a value - key array of the current row positions such that we can use their\n\t\t\t// current position during the sort, if values match, in order to perform stable sorting\n\t\t\tfor ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {\n\t\t\t\taiOrig[ displayMaster[i] ] = i;\n\t\t\t}\n\t\n\t\t\t/* Do the sort - here we want multi-column sorting based on a given data source (column)\n\t\t\t * and sorting function (from oSort) in a certain direction. It's reasonably complex to\n\t\t\t * follow on it's own, but this is what we want (example two column sorting):\n\t\t\t *  fnLocalSorting = function(a,b){\n\t\t\t *    var iTest;\n\t\t\t *    iTest = oSort['string-asc']('data11', 'data12');\n\t\t\t *      if (iTest !== 0)\n\t\t\t *        return iTest;\n\t\t\t *    iTest = oSort['numeric-desc']('data21', 'data22');\n\t\t\t *    if (iTest !== 0)\n\t\t\t *      return iTest;\n\t\t\t *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );\n\t\t\t *  }\n\t\t\t * Basically we have a test for each sorting column, if the data in that column is equal,\n\t\t\t * test the next column. If all columns match, then we use a numeric sort on the row\n\t\t\t * positions in the original data array to provide a stable sort.\n\t\t\t *\n\t\t\t * Note - I know it seems excessive to have two sorting methods, but the first is around\n\t\t\t * 15% faster, so the second is only maintained for backwards compatibility with sorting\n\t\t\t * methods which do not have a pre-sort formatting function.\n\t\t\t */\n\t\t\tif ( formatters === aSort.length ) {\n\t\t\t\t// All sort types have formatting functions\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, test, sort,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\ttest = x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn sort.dir === 'asc' ? test : -test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Depreciated - remove in 1.11 (providing a plug-in option)\n\t\t\t\t// Not all sort types have formatting methods, so we have to call their sorting\n\t\t\t\t// methods.\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, l, test, sort, fn,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\tfn = oExtSort[ sort.type+\"-\"+sort.dir ] || oExtSort[ \"string-\"+sort.dir ];\n\t\t\t\t\t\ttest = fn( x, y );\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Tell the draw function that we have sorted the data */\n\t\toSettings.bSorted = true;\n\t}\n\t\n\t\n\tfunction _fnSortAria ( settings )\n\t{\n\t\tvar label;\n\t\tvar nextSort;\n\t\tvar columns = settings.aoColumns;\n\t\tvar aSort = _fnSortFlatten( settings );\n\t\tvar oAria = settings.oLanguage.oAria;\n\t\n\t\t// ARIA attributes - need to loop all columns, to update all (removing old\n\t\t// attributes as needed)\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar col = columns[i];\n\t\t\tvar asSorting = col.asSorting;\n\t\t\tvar sTitle = col.sTitle.replace( /<.*?>/g, \"\" );\n\t\t\tvar th = col.nTh;\n\t\n\t\t\t// IE7 is throwing an error when setting these properties with jQuery's\n\t\t\t// attr() and removeAttr() methods...\n\t\t\tth.removeAttribute('aria-sort');\n\t\n\t\t\t/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */\n\t\t\tif ( col.bSortable ) {\n\t\t\t\tif ( aSort.length > 0 && aSort[0].col == i ) {\n\t\t\t\t\tth.setAttribute('aria-sort', aSort[0].dir==\"asc\" ? \"ascending\" : \"descending\" );\n\t\t\t\t\tnextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tnextSort = asSorting[0];\n\t\t\t\t}\n\t\n\t\t\t\tlabel = sTitle + ( nextSort === \"asc\" ?\n\t\t\t\t\toAria.sSortAscending :\n\t\t\t\t\toAria.sSortDescending\n\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlabel = sTitle;\n\t\t\t}\n\t\n\t\t\tth.setAttribute('aria-label', label);\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Function to run on user sort request\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {boolean} [append=false] Append the requested sort to the existing\n\t *    sort if true (i.e. multi-column sort)\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortListener ( settings, colIdx, append, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\tvar sorting = settings.aaSorting;\n\t\tvar asSorting = col.asSorting;\n\t\tvar nextSortIdx;\n\t\tvar next = function ( a, overflow ) {\n\t\t\tvar idx = a._idx;\n\t\t\tif ( idx === undefined ) {\n\t\t\t\tidx = $.inArray( a[1], asSorting );\n\t\t\t}\n\t\n\t\t\treturn idx+1 < asSorting.length ?\n\t\t\t\tidx+1 :\n\t\t\t\toverflow ?\n\t\t\t\t\tnull :\n\t\t\t\t\t0;\n\t\t};\n\t\n\t\t// Convert to 2D array if needed\n\t\tif ( typeof sorting[0] === 'number' ) {\n\t\t\tsorting = settings.aaSorting = [ sorting ];\n\t\t}\n\t\n\t\t// If appending the sort then we are multi-column sorting\n\t\tif ( append && settings.oFeatures.bSortMulti ) {\n\t\t\t// Are we already doing some kind of sort on this column?\n\t\t\tvar sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );\n\t\n\t\t\tif ( sortIdx !== -1 ) {\n\t\t\t\t// Yes, modify the sort\n\t\t\t\tnextSortIdx = next( sorting[sortIdx], true );\n\t\n\t\t\t\tif ( nextSortIdx === null && sorting.length === 1 ) {\n\t\t\t\t\tnextSortIdx = 0; // can't remove sorting completely\n\t\t\t\t}\n\t\n\t\t\t\tif ( nextSortIdx === null ) {\n\t\t\t\t\tsorting.splice( sortIdx, 1 );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tsorting[sortIdx][1] = asSorting[ nextSortIdx ];\n\t\t\t\t\tsorting[sortIdx]._idx = nextSortIdx;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// No sort on this column yet\n\t\t\t\tsorting.push( [ colIdx, asSorting[0], 0 ] );\n\t\t\t\tsorting[sorting.length-1]._idx = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( sorting.length && sorting[0][0] == colIdx ) {\n\t\t\t// Single column - already sorting on this column, modify the sort\n\t\t\tnextSortIdx = next( sorting[0] );\n\t\n\t\t\tsorting.length = 1;\n\t\t\tsorting[0][1] = asSorting[ nextSortIdx ];\n\t\t\tsorting[0]._idx = nextSortIdx;\n\t\t}\n\t\telse {\n\t\t\t// Single column - sort only on this column\n\t\t\tsorting.length = 0;\n\t\t\tsorting.push( [ colIdx, asSorting[0] ] );\n\t\t\tsorting[0]._idx = 0;\n\t\t}\n\t\n\t\t// Run the sort by calling a full redraw\n\t\t_fnReDraw( settings );\n\t\n\t\t// callback used for async user interaction\n\t\tif ( typeof callback == 'function' ) {\n\t\t\tcallback( settings );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Attach a sort handler (click) to a node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortAttachListener ( settings, attachTo, colIdx, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\n\t\t_fnBindAction( attachTo, {}, function (e) {\n\t\t\t/* If the column is not sortable - don't to anything */\n\t\t\tif ( col.bSortable === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If processing is enabled use a timeout to allow the processing\n\t\t\t// display to be shown - otherwise to it synchronously\n\t\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t\tsetTimeout( function() {\n\t\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\n\t\t\t\t\t// In server-side processing, the draw callback will remove the\n\t\t\t\t\t// processing display\n\t\t\t\t\tif ( _fnDataSource( settings ) !== 'ssp' ) {\n\t\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t}\n\t\t\t\t}, 0 );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Set the sorting classes on table's body, Note: it is safe to call this function\n\t * when bSort and bSortClasses are false\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortingClasses( settings )\n\t{\n\t\tvar oldSort = settings.aLastSort;\n\t\tvar sortClass = settings.oClasses.sSortColumn;\n\t\tvar sort = _fnSortFlatten( settings );\n\t\tvar features = settings.oFeatures;\n\t\tvar i, ien, colIdx;\n\t\n\t\tif ( features.bSort && features.bSortClasses ) {\n\t\t\t// Remove old sorting classes\n\t\t\tfor ( i=0, ien=oldSort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = oldSort[i].src;\n\t\n\t\t\t\t// Remove column sorting\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.removeClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\n\t\t\t// Add new column sorting\n\t\t\tfor ( i=0, ien=sort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = sort[i].src;\n\t\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.addClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aLastSort = sort;\n\t}\n\t\n\t\n\t// Get the data to sort a column, be it from cache, fresh (populating the\n\t// cache), or from a sort formatter\n\tfunction _fnSortData( settings, idx )\n\t{\n\t\t// Custom sorting function - provided by the sort data type\n\t\tvar column = settings.aoColumns[ idx ];\n\t\tvar customSort = DataTable.ext.order[ column.sSortDataType ];\n\t\tvar customData;\n\t\n\t\tif ( customSort ) {\n\t\t\tcustomData = customSort.call( settings.oInstance, settings, idx,\n\t\t\t\t_fnColumnIndexToVisible( settings, idx )\n\t\t\t);\n\t\t}\n\t\n\t\t// Use / populate cache\n\t\tvar row, cellData;\n\t\tvar formatter = DataTable.ext.type.order[ column.sType+\"-pre\" ];\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aSortData ) {\n\t\t\t\trow._aSortData = [];\n\t\t\t}\n\t\n\t\t\tif ( ! row._aSortData[idx] || customSort ) {\n\t\t\t\tcellData = customSort ?\n\t\t\t\t\tcustomData[i] : // If there was a custom sort function, use data from there\n\t\t\t\t\t_fnGetCellData( settings, i, idx, 'sort' );\n\t\n\t\t\t\trow._aSortData[ idx ] = formatter ?\n\t\t\t\t\tformatter( cellData ) :\n\t\t\t\t\tcellData;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Save the state of a table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSaveState ( settings )\n\t{\n\t\tif ( !settings.oFeatures.bStateSave || settings.bDestroying )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Store the interesting variables */\n\t\tvar state = {\n\t\t\ttime:    +new Date(),\n\t\t\tstart:   settings._iDisplayStart,\n\t\t\tlength:  settings._iDisplayLength,\n\t\t\torder:   $.extend( true, [], settings.aaSorting ),\n\t\t\tsearch:  _fnSearchToCamel( settings.oPreviousSearch ),\n\t\t\tcolumns: $.map( settings.aoColumns, function ( col, i ) {\n\t\t\t\treturn {\n\t\t\t\t\tvisible: col.bVisible,\n\t\t\t\t\tsearch: _fnSearchToCamel( settings.aoPreSearchCols[i] )\n\t\t\t\t};\n\t\t\t} )\n\t\t};\n\t\n\t\t_fnCallbackFire( settings, \"aoStateSaveParams\", 'stateSaveParams', [settings, state] );\n\t\n\t\tsettings.oSavedState = state;\n\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, state );\n\t}\n\t\n\t\n\t/**\n\t * Attempt to load a saved table state\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oInit DataTables init object so we can override settings\n\t *  @param {function} callback Callback to execute when the state has been loaded\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLoadState ( settings, oInit, callback )\n\t{\n\t\tvar i, ien;\n\t\tvar columns = settings.aoColumns;\n\t\tvar loaded = function ( s ) {\n\t\t\tif ( ! s || ! s.time ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Allow custom and plug-in manipulation functions to alter the saved data set and\n\t\t\t// cancelling of loading by returning false\n\t\t\tvar abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );\n\t\t\tif ( $.inArray( false, abStateLoad ) !== -1 ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Reject old data\n\t\t\tvar duration = settings.iStateDuration;\n\t\t\tif ( duration > 0 && s.time < +new Date() - (duration*1000) ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Number of columns have changed - all bets are off, no restore of settings\n\t\t\tif ( s.columns && columns.length !== s.columns.length ) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// Store the saved state so it might be accessed at any time\n\t\t\tsettings.oLoadedState = $.extend( true, {}, s );\n\t\n\t\t\t// Restore key features - todo - for 1.11 this needs to be done by\n\t\t\t// subscribed events\n\t\t\tif ( s.start !== undefined ) {\n\t\t\t\tsettings._iDisplayStart    = s.start;\n\t\t\t\tsettings.iInitDisplayStart = s.start;\n\t\t\t}\n\t\t\tif ( s.length !== undefined ) {\n\t\t\t\tsettings._iDisplayLength   = s.length;\n\t\t\t}\n\t\n\t\t\t// Order\n\t\t\tif ( s.order !== undefined ) {\n\t\t\t\tsettings.aaSorting = [];\n\t\t\t\t$.each( s.order, function ( i, col ) {\n\t\t\t\t\tsettings.aaSorting.push( col[0] >= columns.length ?\n\t\t\t\t\t\t[ 0, col[1] ] :\n\t\t\t\t\t\tcol\n\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Search\n\t\t\tif ( s.search !== undefined ) {\n\t\t\t\t$.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );\n\t\t\t}\n\t\n\t\t\t// Columns\n\t\t\t//\n\t\t\tif ( s.columns ) {\n\t\t\t\tfor ( i=0, ien=s.columns.length ; i<ien ; i++ ) {\n\t\t\t\t\tvar col = s.columns[i];\n\t\n\t\t\t\t\t// Visibility\n\t\t\t\t\tif ( col.visible !== undefined ) {\n\t\t\t\t\t\tcolumns[i].bVisible = col.visible;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Search\n\t\t\t\t\tif ( col.search !== undefined ) {\n\t\t\t\t\t\t$.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );\n\t\t\tcallback();\n\t\t}\n\t\n\t\tif ( ! settings.oFeatures.bStateSave ) {\n\t\t\tcallback();\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );\n\t\n\t\tif ( state !== undefined ) {\n\t\t\tloaded( state );\n\t\t}\n\t\t// otherwise, wait for the loaded callback to be executed\n\t}\n\t\n\t\n\t/**\n\t * Return the settings object for a particular table\n\t *  @param {node} table table we are using as a dataTable\n\t *  @returns {object} Settings object - or null if not found\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSettingsFromNode ( table )\n\t{\n\t\tvar settings = DataTable.settings;\n\t\tvar idx = $.inArray( table, _pluck( settings, 'nTable' ) );\n\t\n\t\treturn idx !== -1 ?\n\t\t\tsettings[ idx ] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Log an error message\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} level log error messages, or display them to the user\n\t *  @param {string} msg error message\n\t *  @param {int} tn Technical note id to get more information about the error.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLog( settings, level, msg, tn )\n\t{\n\t\tmsg = 'DataTables warning: '+\n\t\t\t(settings ? 'table id='+settings.sTableId+' - ' : '')+msg;\n\t\n\t\tif ( tn ) {\n\t\t\tmsg += '. For more information about this error, please see '+\n\t\t\t'http://datatables.net/tn/'+tn;\n\t\t}\n\t\n\t\tif ( ! level  ) {\n\t\t\t// Backwards compatibility pre 1.10\n\t\t\tvar ext = DataTable.ext;\n\t\t\tvar type = ext.sErrMode || ext.errMode;\n\t\n\t\t\tif ( settings ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );\n\t\t\t}\n\t\n\t\t\tif ( type == 'alert' ) {\n\t\t\t\talert( msg );\n\t\t\t}\n\t\t\telse if ( type == 'throw' ) {\n\t\t\t\tthrow new Error(msg);\n\t\t\t}\n\t\t\telse if ( typeof type == 'function' ) {\n\t\t\t\ttype( settings, tn, msg );\n\t\t\t}\n\t\t}\n\t\telse if ( window.console && console.log ) {\n\t\t\tconsole.log( msg );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * See if a property is defined on one object, if so assign it to the other object\n\t *  @param {object} ret target object\n\t *  @param {object} src source object\n\t *  @param {string} name property\n\t *  @param {string} [mappedName] name to map too - optional, name used if not given\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnMap( ret, src, name, mappedName )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\t$.each( name, function (i, val) {\n\t\t\t\tif ( $.isArray( val ) ) {\n\t\t\t\t\t_fnMap( ret, src, val[0], val[1] );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_fnMap( ret, src, val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( mappedName === undefined ) {\n\t\t\tmappedName = name;\n\t\t}\n\t\n\t\tif ( src[name] !== undefined ) {\n\t\t\tret[mappedName] = src[name];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Extend objects - very similar to jQuery.extend, but deep copy objects, and\n\t * shallow copy arrays. The reason we need to do this, is that we don't want to\n\t * deep copy array init values (such as aaSorting) since the dev wouldn't be\n\t * able to override them, but we do want to deep copy arrays.\n\t *  @param {object} out Object to extend\n\t *  @param {object} extender Object from which the properties will be applied to\n\t *      out\n\t *  @param {boolean} breakRefs If true, then arrays will be sliced to take an\n\t *      independent copy with the exception of the `data` or `aaData` parameters\n\t *      if they are present. This is so you can pass in a collection to\n\t *      DataTables and have that used as your data source without breaking the\n\t *      references\n\t *  @returns {object} out Reference, just for convenience - out === the return.\n\t *  @memberof DataTable#oApi\n\t *  @todo This doesn't take account of arrays inside the deep copied objects.\n\t */\n\tfunction _fnExtend( out, extender, breakRefs )\n\t{\n\t\tvar val;\n\t\n\t\tfor ( var prop in extender ) {\n\t\t\tif ( extender.hasOwnProperty(prop) ) {\n\t\t\t\tval = extender[prop];\n\t\n\t\t\t\tif ( $.isPlainObject( val ) ) {\n\t\t\t\t\tif ( ! $.isPlainObject( out[prop] ) ) {\n\t\t\t\t\t\tout[prop] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, out[prop], val );\n\t\t\t\t}\n\t\t\t\telse if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {\n\t\t\t\t\tout[prop] = val.slice();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tout[prop] = val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t}\n\t\n\t\n\t/**\n\t * Bind an event handers to allow a click or return key to activate the callback.\n\t * This is good for accessibility since a return on the keyboard will have the\n\t * same effect as a click, if the element has focus.\n\t *  @param {element} n Element to bind the action to\n\t *  @param {object} oData Data object to pass to the triggered function\n\t *  @param {function} fn Callback function for when the event is triggered\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBindAction( n, oData, fn )\n\t{\n\t\t$(n)\n\t\t\t.on( 'click.DT', oData, function (e) {\n\t\t\t\t\t$(n).blur(); // Remove focus outline for mouse users\n\t\t\t\t\tfn(e);\n\t\t\t\t} )\n\t\t\t.on( 'keypress.DT', oData, function (e){\n\t\t\t\t\tif ( e.which === 13 ) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tfn(e);\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t.on( 'selectstart.DT', function () {\n\t\t\t\t\t/* Take the brutal approach to cancelling text selection */\n\t\t\t\t\treturn false;\n\t\t\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Register a callback function. Easily allows a callback function to be added to\n\t * an array store of callback functions that can then all be called together.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sStore Name of the array storage for the callbacks in oSettings\n\t *  @param {function} fn Function to be called back\n\t *  @param {string} sName Identifying name for the callback (i.e. a label)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackReg( oSettings, sStore, fn, sName )\n\t{\n\t\tif ( fn )\n\t\t{\n\t\t\toSettings[sStore].push( {\n\t\t\t\t\"fn\": fn,\n\t\t\t\t\"sName\": sName\n\t\t\t} );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Fire callback functions and trigger events. Note that the loop over the\n\t * callback array store is done backwards! Further note that you do not want to\n\t * fire off triggers in time sensitive applications (for example cell creation)\n\t * as its slow.\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} callbackArr Name of the array storage for the callbacks in\n\t *      oSettings\n\t *  @param {string} eventName Name of the jQuery custom event to trigger. If\n\t *      null no trigger is fired\n\t *  @param {array} args Array of arguments to pass to the callback function /\n\t *      trigger\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackFire( settings, callbackArr, eventName, args )\n\t{\n\t\tvar ret = [];\n\t\n\t\tif ( callbackArr ) {\n\t\t\tret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {\n\t\t\t\treturn val.fn.apply( settings.oInstance, args );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( eventName !== null ) {\n\t\t\tvar e = $.Event( eventName+'.dt' );\n\t\n\t\t\t$(settings.nTable).trigger( e, args );\n\t\n\t\t\tret.push( e.result );\n\t\t}\n\t\n\t\treturn ret;\n\t}\n\t\n\t\n\tfunction _fnLengthOverflow ( settings )\n\t{\n\t\tvar\n\t\t\tstart = settings._iDisplayStart,\n\t\t\tend = settings.fnDisplayEnd(),\n\t\t\tlen = settings._iDisplayLength;\n\t\n\t\t/* If we have space to show extra rows (backing up from the end point - then do so */\n\t\tif ( start >= end )\n\t\t{\n\t\t\tstart = end - len;\n\t\t}\n\t\n\t\t// Keep the start record on the current page\n\t\tstart -= (start % len);\n\t\n\t\tif ( len === -1 || start < 0 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\n\t\tsettings._iDisplayStart = start;\n\t}\n\t\n\t\n\tfunction _fnRenderer( settings, type )\n\t{\n\t\tvar renderer = settings.renderer;\n\t\tvar host = DataTable.ext.renderer[type];\n\t\n\t\tif ( $.isPlainObject( renderer ) && renderer[type] ) {\n\t\t\t// Specific renderer for this type. If available use it, otherwise use\n\t\t\t// the default.\n\t\t\treturn host[renderer[type]] || host._;\n\t\t}\n\t\telse if ( typeof renderer === 'string' ) {\n\t\t\t// Common renderer - if there is one available for this type use it,\n\t\t\t// otherwise use the default\n\t\t\treturn host[renderer] || host._;\n\t\t}\n\t\n\t\t// Use the default\n\t\treturn host._;\n\t}\n\t\n\t\n\t/**\n\t * Detect the data source being used for the table. Used to simplify the code\n\t * a little (ajax) and to make it compress a little smaller.\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {string} Data source\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDataSource ( settings )\n\t{\n\t\tif ( settings.oFeatures.bServerSide ) {\n\t\t\treturn 'ssp';\n\t\t}\n\t\telse if ( settings.ajax || settings.sAjaxSource ) {\n\t\t\treturn 'ajax';\n\t\t}\n\t\treturn 'dom';\n\t}\n\t\n\n\t\n\t\n\t/**\n\t * Computed structure of the DataTables API, defined by the options passed to\n\t * `DataTable.Api.register()` when building the API.\n\t *\n\t * The structure is built in order to speed creation and extension of the Api\n\t * objects since the extensions are effectively pre-parsed.\n\t *\n\t * The array is an array of objects with the following structure, where this\n\t * base array represents the Api prototype base:\n\t *\n\t *     [\n\t *       {\n\t *         name:      'data'                -- string   - Property name\n\t *         val:       function () {},       -- function - Api method (or undefined if just an object\n\t *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t *       },\n\t *       {\n\t *         name:     'row'\n\t *         val:       {},\n\t *         methodExt: [ ... ],\n\t *         propExt:   [\n\t *           {\n\t *             name:      'data'\n\t *             val:       function () {},\n\t *             methodExt: [ ... ],\n\t *             propExt:   [ ... ]\n\t *           },\n\t *           ...\n\t *         ]\n\t *       }\n\t *     ]\n\t *\n\t * @type {Array}\n\t * @ignore\n\t */\n\tvar __apiStruct = [];\n\t\n\t\n\t/**\n\t * `Array.prototype` reference.\n\t *\n\t * @type object\n\t * @ignore\n\t */\n\tvar __arrayProto = Array.prototype;\n\t\n\t\n\t/**\n\t * Abstraction for `context` parameter of the `Api` constructor to allow it to\n\t * take several different forms for ease of use.\n\t *\n\t * Each of the input parameter types will be converted to a DataTables settings\n\t * object where possible.\n\t *\n\t * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one\n\t *   of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t *   * `DataTables.Api` - API instance\n\t * @return {array|null} Matching DataTables settings objects. `null` or\n\t *   `undefined` is returned if no matching DataTable is found.\n\t * @ignore\n\t */\n\tvar _toSettings = function ( mixed )\n\t{\n\t\tvar idx, jq;\n\t\tvar settings = DataTable.settings;\n\t\tvar tables = $.map( settings, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\tif ( ! mixed ) {\n\t\t\treturn [];\n\t\t}\n\t\telse if ( mixed.nTable && mixed.oApi ) {\n\t\t\t// DataTables settings object\n\t\t\treturn [ mixed ];\n\t\t}\n\t\telse if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {\n\t\t\t// Table node\n\t\t\tidx = $.inArray( mixed, tables );\n\t\t\treturn idx !== -1 ? [ settings[idx] ] : null;\n\t\t}\n\t\telse if ( mixed && typeof mixed.settings === 'function' ) {\n\t\t\treturn mixed.settings().toArray();\n\t\t}\n\t\telse if ( typeof mixed === 'string' ) {\n\t\t\t// jQuery selector\n\t\t\tjq = $(mixed);\n\t\t}\n\t\telse if ( mixed instanceof $ ) {\n\t\t\t// jQuery object (also DataTables instance)\n\t\t\tjq = mixed;\n\t\t}\n\t\n\t\tif ( jq ) {\n\t\t\treturn jq.map( function(i) {\n\t\t\t\tidx = $.inArray( this, tables );\n\t\t\t\treturn idx !== -1 ? settings[idx] : null;\n\t\t\t} ).toArray();\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * DataTables API class - used to control and interface with  one or more\n\t * DataTables enhanced tables.\n\t *\n\t * The API class is heavily based on jQuery, presenting a chainable interface\n\t * that you can use to interact with tables. Each instance of the API class has\n\t * a \"context\" - i.e. the tables that it will operate on. This could be a single\n\t * table, all tables on a page or a sub-set thereof.\n\t *\n\t * Additionally the API is designed to allow you to easily work with the data in\n\t * the tables, retrieving and manipulating it as required. This is done by\n\t * presenting the API class as an array like interface. The contents of the\n\t * array depend upon the actions requested by each method (for example\n\t * `rows().nodes()` will return an array of nodes, while `rows().data()` will\n\t * return an array of objects or arrays depending upon your table's\n\t * configuration). The API object has a number of array like methods (`push`,\n\t * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,\n\t * `unique` etc) to assist your working with the data held in a table.\n\t *\n\t * Most methods (those which return an Api instance) are chainable, which means\n\t * the return from a method call also has all of the methods available that the\n\t * top level object had. For example, these two calls are equivalent:\n\t *\n\t *     // Not chained\n\t *     api.row.add( {...} );\n\t *     api.draw();\n\t *\n\t *     // Chained\n\t *     api.row.add( {...} ).draw();\n\t *\n\t * @class DataTable.Api\n\t * @param {array|object|string|jQuery} context DataTable identifier. This is\n\t *   used to define which DataTables enhanced tables this API will operate on.\n\t *   Can be one of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t * @param {array} [data] Data to initialise the Api instance with.\n\t *\n\t * @example\n\t *   // Direct initialisation during DataTables construction\n\t *   var api = $('#example').DataTable();\n\t *\n\t * @example\n\t *   // Initialisation using a DataTables jQuery object\n\t *   var api = $('#example').dataTable().api();\n\t *\n\t * @example\n\t *   // Initialisation as a constructor\n\t *   var api = new $.fn.DataTable.Api( 'table.dataTable' );\n\t */\n\t_Api = function ( context, data )\n\t{\n\t\tif ( ! (this instanceof _Api) ) {\n\t\t\treturn new _Api( context, data );\n\t\t}\n\t\n\t\tvar settings = [];\n\t\tvar ctxSettings = function ( o ) {\n\t\t\tvar a = _toSettings( o );\n\t\t\tif ( a ) {\n\t\t\t\tsettings = settings.concat( a );\n\t\t\t}\n\t\t};\n\t\n\t\tif ( $.isArray( context ) ) {\n\t\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tctxSettings( context[i] );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tctxSettings( context );\n\t\t}\n\t\n\t\t// Remove duplicates\n\t\tthis.context = _unique( settings );\n\t\n\t\t// Initial data\n\t\tif ( data ) {\n\t\t\t$.merge( this, data );\n\t\t}\n\t\n\t\t// selector\n\t\tthis.selector = {\n\t\t\trows: null,\n\t\t\tcols: null,\n\t\t\topts: null\n\t\t};\n\t\n\t\t_Api.extend( this, this, __apiStruct );\n\t};\n\t\n\tDataTable.Api = _Api;\n\t\n\t// Don't destroy the existing prototype, just extend it. Required for jQuery 2's\n\t// isPlainObject.\n\t$.extend( _Api.prototype, {\n\t\tany: function ()\n\t\t{\n\t\t\treturn this.count() !== 0;\n\t\t},\n\t\n\t\n\t\tconcat:  __arrayProto.concat,\n\t\n\t\n\t\tcontext: [], // array of table settings objects\n\t\n\t\n\t\tcount: function ()\n\t\t{\n\t\t\treturn this.flatten().length;\n\t\t},\n\t\n\t\n\t\teach: function ( fn )\n\t\t{\n\t\t\tfor ( var i=0, ien=this.length ; i<ien; i++ ) {\n\t\t\t\tfn.call( this, this[i], i, this );\n\t\t\t}\n\t\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\teq: function ( idx )\n\t\t{\n\t\t\tvar ctx = this.context;\n\t\n\t\t\treturn ctx.length > idx ?\n\t\t\t\tnew _Api( ctx[idx], this[idx] ) :\n\t\t\t\tnull;\n\t\t},\n\t\n\t\n\t\tfilter: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.filter ) {\n\t\t\t\ta = __arrayProto.filter.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( fn.call( this, this[i], i, this ) ) {\n\t\t\t\t\t\ta.push( this[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tflatten: function ()\n\t\t{\n\t\t\tvar a = [];\n\t\t\treturn new _Api( this.context, a.concat.apply( a, this.toArray() ) );\n\t\t},\n\t\n\t\n\t\tjoin:    __arrayProto.join,\n\t\n\t\n\t\tindexOf: __arrayProto.indexOf || function (obj, start)\n\t\t{\n\t\t\tfor ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {\n\t\t\t\tif ( this[i] === obj ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn -1;\n\t\t},\n\t\n\t\titerator: function ( flatten, type, fn, alwaysNew ) {\n\t\t\tvar\n\t\t\t\ta = [], ret,\n\t\t\t\ti, ien, j, jen,\n\t\t\t\tcontext = this.context,\n\t\t\t\trows, items, item,\n\t\t\t\tselector = this.selector;\n\t\n\t\t\t// Argument shifting\n\t\t\tif ( typeof flatten === 'string' ) {\n\t\t\t\talwaysNew = fn;\n\t\t\t\tfn = type;\n\t\t\t\ttype = flatten;\n\t\t\t\tflatten = false;\n\t\t\t}\n\t\n\t\t\tfor ( i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tvar apiInst = new _Api( context[i] );\n\t\n\t\t\t\tif ( type === 'table' ) {\n\t\t\t\t\tret = fn.call( apiInst, context[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'columns' || type === 'rows' ) {\n\t\t\t\t\t// this has same length as context - one entry for each table\n\t\t\t\t\tret = fn.call( apiInst, context[i], this[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {\n\t\t\t\t\t// columns and rows share the same structure.\n\t\t\t\t\t// 'this' is an array of column indexes for each context\n\t\t\t\t\titems = this[i];\n\t\n\t\t\t\t\tif ( type === 'column-rows' ) {\n\t\t\t\t\t\trows = _selector_row_indexes( context[i], selector.opts );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfor ( j=0, jen=items.length ; j<jen ; j++ ) {\n\t\t\t\t\t\titem = items[j];\n\t\n\t\t\t\t\t\tif ( type === 'cell' ) {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item.row, item.column, i, j );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tret = fn.call( apiInst, context[i], item, i, j, rows );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( a.length || alwaysNew ) {\n\t\t\t\tvar api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );\n\t\t\t\tvar apiSelector = api.selector;\n\t\t\t\tapiSelector.rows = selector.rows;\n\t\t\t\tapiSelector.cols = selector.cols;\n\t\t\t\tapiSelector.opts = selector.opts;\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\tlastIndexOf: __arrayProto.lastIndexOf || function (obj, start)\n\t\t{\n\t\t\t// Bit cheeky...\n\t\t\treturn this.indexOf.apply( this.toArray.reverse(), arguments );\n\t\t},\n\t\n\t\n\t\tlength:  0,\n\t\n\t\n\t\tmap: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.map ) {\n\t\t\t\ta = __arrayProto.map.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\ta.push( fn.call( this, this[i], i ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tpluck: function ( prop )\n\t\t{\n\t\t\treturn this.map( function ( el ) {\n\t\t\t\treturn el[ prop ];\n\t\t\t} );\n\t\t},\n\t\n\t\tpop:     __arrayProto.pop,\n\t\n\t\n\t\tpush:    __arrayProto.push,\n\t\n\t\n\t\t// Does not return an API instance\n\t\treduce: __arrayProto.reduce || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, 0, this.length, 1 );\n\t\t},\n\t\n\t\n\t\treduceRight: __arrayProto.reduceRight || function ( fn, init )\n\t\t{\n\t\t\treturn _fnReduce( this, fn, init, this.length-1, -1, -1 );\n\t\t},\n\t\n\t\n\t\treverse: __arrayProto.reverse,\n\t\n\t\n\t\t// Object with rows, columns and opts\n\t\tselector: null,\n\t\n\t\n\t\tshift:   __arrayProto.shift,\n\t\n\t\n\t\tslice: function () {\n\t\t\treturn new _Api( this.context, this );\n\t\t},\n\t\n\t\n\t\tsort:    __arrayProto.sort, // ? name - order?\n\t\n\t\n\t\tsplice:  __arrayProto.splice,\n\t\n\t\n\t\ttoArray: function ()\n\t\t{\n\t\t\treturn __arrayProto.slice.call( this );\n\t\t},\n\t\n\t\n\t\tto$: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\ttoJQuery: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\tunique: function ()\n\t\t{\n\t\t\treturn new _Api( this.context, _unique(this) );\n\t\t},\n\t\n\t\n\t\tunshift: __arrayProto.unshift\n\t} );\n\t\n\t\n\t_Api.extend = function ( scope, obj, ext )\n\t{\n\t\t// Only extend API instances and static properties of the API\n\t\tif ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\tj, jen,\n\t\t\tstruct, inner,\n\t\t\tmethodScoping = function ( scope, fn, struc ) {\n\t\t\t\treturn function () {\n\t\t\t\t\tvar ret = fn.apply( scope, arguments );\n\t\n\t\t\t\t\t// Method extension\n\t\t\t\t\t_Api.extend( ret, ret, struc.methodExt );\n\t\t\t\t\treturn ret;\n\t\t\t\t};\n\t\t\t};\n\t\n\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\tstruct = ext[i];\n\t\n\t\t\t// Value\n\t\t\tobj[ struct.name ] = typeof struct.val === 'function' ?\n\t\t\t\tmethodScoping( scope, struct.val, struct ) :\n\t\t\t\t$.isPlainObject( struct.val ) ?\n\t\t\t\t\t{} :\n\t\t\t\t\tstruct.val;\n\t\n\t\t\tobj[ struct.name ].__dt_wrapper = true;\n\t\n\t\t\t// Property extension\n\t\t\t_Api.extend( scope, obj[ struct.name ], struct.propExt );\n\t\t}\n\t};\n\t\n\t\n\t// @todo - Is there need for an augment function?\n\t// _Api.augment = function ( inst, name )\n\t// {\n\t// \t// Find src object in the structure from the name\n\t// \tvar parts = name.split('.');\n\t\n\t// \t_Api.extend( inst, obj );\n\t// };\n\t\n\t\n\t//     [\n\t//       {\n\t//         name:      'data'                -- string   - Property name\n\t//         val:       function () {},       -- function - Api method (or undefined if just an object\n\t//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t//       },\n\t//       {\n\t//         name:     'row'\n\t//         val:       {},\n\t//         methodExt: [ ... ],\n\t//         propExt:   [\n\t//           {\n\t//             name:      'data'\n\t//             val:       function () {},\n\t//             methodExt: [ ... ],\n\t//             propExt:   [ ... ]\n\t//           },\n\t//           ...\n\t//         ]\n\t//       }\n\t//     ]\n\t\n\t_Api.register = _api_register = function ( name, val )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\tfor ( var j=0, jen=name.length ; j<jen ; j++ ) {\n\t\t\t\t_Api.register( name[j], val );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\their = name.split('.'),\n\t\t\tstruct = __apiStruct,\n\t\t\tkey, method;\n\t\n\t\tvar find = function ( src, name ) {\n\t\t\tfor ( var i=0, ien=src.length ; i<ien ; i++ ) {\n\t\t\t\tif ( src[i].name === name ) {\n\t\t\t\t\treturn src[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\n\t\tfor ( i=0, ien=heir.length ; i<ien ; i++ ) {\n\t\t\tmethod = heir[i].indexOf('()') !== -1;\n\t\t\tkey = method ?\n\t\t\t\their[i].replace('()', '') :\n\t\t\t\their[i];\n\t\n\t\t\tvar src = find( struct, key );\n\t\t\tif ( ! src ) {\n\t\t\t\tsrc = {\n\t\t\t\t\tname:      key,\n\t\t\t\t\tval:       {},\n\t\t\t\t\tmethodExt: [],\n\t\t\t\t\tpropExt:   []\n\t\t\t\t};\n\t\t\t\tstruct.push( src );\n\t\t\t}\n\t\n\t\t\tif ( i === ien-1 ) {\n\t\t\t\tsrc.val = val;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstruct = method ?\n\t\t\t\t\tsrc.methodExt :\n\t\t\t\t\tsrc.propExt;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\t_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {\n\t\t_Api.register( pluralName, val );\n\t\n\t\t_Api.register( singularName, function () {\n\t\t\tvar ret = val.apply( this, arguments );\n\t\n\t\t\tif ( ret === this ) {\n\t\t\t\t// Returned item is the API instance that was passed in, return it\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\telse if ( ret instanceof _Api ) {\n\t\t\t\t// New API instance returned, want the value from the first item\n\t\t\t\t// in the returned array for the singular result.\n\t\t\t\treturn ret.length ?\n\t\t\t\t\t$.isArray( ret[0] ) ?\n\t\t\t\t\t\tnew _Api( ret.context, ret[0] ) : // Array results are 'enhanced'\n\t\t\t\t\t\tret[0] :\n\t\t\t\t\tundefined;\n\t\t\t}\n\t\n\t\t\t// Non-API return - just fire it back\n\t\t\treturn ret;\n\t\t} );\n\t};\n\t\n\t\n\t/**\n\t * Selector for HTML tables. Apply the given selector to the give array of\n\t * DataTables settings objects.\n\t *\n\t * @param {string|integer} [selector] jQuery selector string or integer\n\t * @param  {array} Array of DataTables settings objects to be filtered\n\t * @return {array}\n\t * @ignore\n\t */\n\tvar __table_selector = function ( selector, a )\n\t{\n\t\t// Integer is used to pick out a table by index\n\t\tif ( typeof selector === 'number' ) {\n\t\t\treturn [ a[ selector ] ];\n\t\t}\n\t\n\t\t// Perform a jQuery selector on the table nodes\n\t\tvar nodes = $.map( a, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\treturn $(nodes)\n\t\t\t.filter( selector )\n\t\t\t.map( function (i) {\n\t\t\t\t// Need to translate back from the table node to the settings\n\t\t\t\tvar idx = $.inArray( this, nodes );\n\t\t\t\treturn a[ idx ];\n\t\t\t} )\n\t\t\t.toArray();\n\t};\n\t\n\t\n\t\n\t/**\n\t * Context selector for the API's context (i.e. the tables the API instance\n\t * refers to.\n\t *\n\t * @name    DataTable.Api#tables\n\t * @param {string|integer} [selector] Selector to pick which tables the iterator\n\t *   should operate on. If not given, all tables in the current context are\n\t *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to\n\t *   select multiple tables or as an integer to select a single table.\n\t * @returns {DataTable.Api} Returns a new API instance if a selector is given.\n\t */\n\t_api_register( 'tables()', function ( selector ) {\n\t\t// A new instance is created if there was a selector specified\n\t\treturn selector ?\n\t\t\tnew _Api( __table_selector( selector, this.context ) ) :\n\t\t\tthis;\n\t} );\n\t\n\t\n\t_api_register( 'table()', function ( selector ) {\n\t\tvar tables = this.tables( selector );\n\t\tvar ctx = tables.context;\n\t\n\t\t// Truncate to the first matched table\n\t\treturn ctx.length ?\n\t\t\tnew _Api( ctx[0] ) :\n\t\t\ttables;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().nodes()', 'table().node()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTable;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().body()', 'table().body()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTBody;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().header()', 'table().header()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTHead;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().footer()', 'table().footer()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTFoot;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().containers()', 'table().container()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTableWrapper;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Redraw the tables in the current context.\n\t */\n\t_api_register( 'draw()', function ( paging ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( paging === 'page' ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif ( typeof paging === 'string' ) {\n\t\t\t\t\tpaging = paging === 'full-hold' ?\n\t\t\t\t\t\tfalse :\n\t\t\t\t\t\ttrue;\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, paging===false );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get the current page index.\n\t *\n\t * @return {integer} Current page index (zero based)\n\t *//**\n\t * Set the current page.\n\t *\n\t * Note that if you attempt to show a page which does not exist, DataTables will\n\t * not throw an error, but rather reset the paging.\n\t *\n\t * @param {integer|string} action The paging action to take. This can be one of:\n\t *  * `integer` - The page index to jump to\n\t *  * `string` - An action to take:\n\t *    * `first` - Jump to first page.\n\t *    * `next` - Jump to the next page\n\t *    * `previous` - Jump to previous page\n\t *    * `last` - Jump to the last page.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page()', function ( action ) {\n\t\tif ( action === undefined ) {\n\t\t\treturn this.page.info().page; // not an expensive call\n\t\t}\n\t\n\t\t// else, have an action to take on all tables\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnPageChange( settings, action );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Paging information for the first table in the current context.\n\t *\n\t * If you require paging information for another table, use the `table()` method\n\t * with a suitable selector.\n\t *\n\t * @return {object} Object with the following properties set:\n\t *  * `page` - Current page index (zero based - i.e. the first page is `0`)\n\t *  * `pages` - Total number of pages\n\t *  * `start` - Display index for the first record shown on the current page\n\t *  * `end` - Display index for the last record shown on the current page\n\t *  * `length` - Display length (number of records). Note that generally `start\n\t *    + length = end`, but this is not always true, for example if there are\n\t *    only 2 records to show on the final page, with a length of 10.\n\t *  * `recordsTotal` - Full data set length\n\t *  * `recordsDisplay` - Data set length once the current filtering criterion\n\t *    are applied.\n\t */\n\t_api_register( 'page.info()', function ( action ) {\n\t\tif ( this.context.length === 0 ) {\n\t\t\treturn undefined;\n\t\t}\n\t\n\t\tvar\n\t\t\tsettings   = this.context[0],\n\t\t\tstart      = settings._iDisplayStart,\n\t\t\tlen        = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,\n\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn {\n\t\t\t\"page\":           all ? 0 : Math.floor( start / len ),\n\t\t\t\"pages\":          all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\"start\":          start,\n\t\t\t\"end\":            settings.fnDisplayEnd(),\n\t\t\t\"length\":         len,\n\t\t\t\"recordsTotal\":   settings.fnRecordsTotal(),\n\t\t\t\"recordsDisplay\": visRecords,\n\t\t\t\"serverSide\":     _fnDataSource( settings ) === 'ssp'\n\t\t};\n\t} );\n\t\n\t\n\t/**\n\t * Get the current page length.\n\t *\n\t * @return {integer} Current page length. Note `-1` indicates that all records\n\t *   are to be shown.\n\t *//**\n\t * Set the current page length.\n\t *\n\t * @param {integer} Page length to set. Use `-1` to show all records.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page.len()', function ( len ) {\n\t\t// Note that we can't call this function 'length()' because `length`\n\t\t// is a Javascript property of functions which defines how many arguments\n\t\t// the function expects.\n\t\tif ( len === undefined ) {\n\t\t\treturn this.context.length !== 0 ?\n\t\t\t\tthis.context[0]._iDisplayLength :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// else, set the page length\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnLengthChange( settings, len );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\tvar __reload = function ( settings, holdPosition, callback ) {\n\t\t// Use the draw event to trigger a callback\n\t\tif ( callback ) {\n\t\t\tvar api = new _Api( settings );\n\t\n\t\t\tapi.one( 'draw', function () {\n\t\t\t\tcallback( api.ajax.json() );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t_fnReDraw( settings, holdPosition );\n\t\t}\n\t\telse {\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t// Cancel an existing request\n\t\t\tvar xhr = settings.jqXHR;\n\t\t\tif ( xhr && xhr.readyState !== 4 ) {\n\t\t\t\txhr.abort();\n\t\t\t}\n\t\n\t\t\t// Trigger xhr\n\t\t\t_fnBuildAjax( settings, [], function( json ) {\n\t\t\t\t_fnClearTable( settings );\n\t\n\t\t\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\t_fnAddData( settings, data[i] );\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, holdPosition );\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Get the JSON response from the last Ajax request that DataTables made to the\n\t * server. Note that this returns the JSON from the first table in the current\n\t * context.\n\t *\n\t * @return {object} JSON received from the server.\n\t */\n\t_api_register( 'ajax.json()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].json;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Get the data submitted in the last Ajax request\n\t */\n\t_api_register( 'ajax.params()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].oAjaxData;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Reload tables from the Ajax data source. Note that this function will\n\t * automatically re-draw the table when the remote data has been loaded.\n\t *\n\t * @param {boolean} [reset=true] Reset (default) or hold the current paging\n\t *   position. A full re-sort and re-filter is performed when this method is\n\t *   called, which is why the pagination reset is the default action.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.reload()', function ( callback, resetPaging ) {\n\t\treturn this.iterator( 'table', function (settings) {\n\t\t\t__reload( settings, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Get the current Ajax URL. Note that this returns the URL from the first\n\t * table in the current context.\n\t *\n\t * @return {string} Current Ajax source URL\n\t *//**\n\t * Set the Ajax URL. Note that this will set the URL for all tables in the\n\t * current context.\n\t *\n\t * @param {string} url URL to set.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url()', function ( url ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( url === undefined ) {\n\t\t\t// get\n\t\t\tif ( ctx.length === 0 ) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tctx = ctx[0];\n\t\n\t\t\treturn ctx.ajax ?\n\t\t\t\t$.isPlainObject( ctx.ajax ) ?\n\t\t\t\t\tctx.ajax.url :\n\t\t\t\t\tctx.ajax :\n\t\t\t\tctx.sAjaxSource;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( $.isPlainObject( settings.ajax ) ) {\n\t\t\t\tsettings.ajax.url = url;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsettings.ajax = url;\n\t\t\t}\n\t\t\t// No need to consider sAjaxSource here since DataTables gives priority\n\t\t\t// to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any\n\t\t\t// value of `sAjaxSource` redundant.\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Load data from the newly set Ajax URL. Note that this method is only\n\t * available when `ajax.url()` is used to set a URL. Additionally, this method\n\t * has the same effect as calling `ajax.reload()` but is provided for\n\t * convenience when setting a new URL. Like `ajax.reload()` it will\n\t * automatically redraw the table once the remote data has been loaded.\n\t *\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {\n\t\t// Same as a reload, but makes sense to present it for easy access after a\n\t\t// url change\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\t__reload( ctx, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t\n\tvar _selector_run = function ( type, selector, selectFn, settings, opts )\n\t{\n\t\tvar\n\t\t\tout = [], res,\n\t\t\ta, i, ien, j, jen,\n\t\t\tselectorType = typeof selector;\n\t\n\t\t// Can't just check for isArray here, as an API or jQuery instance might be\n\t\t// given with their array like look\n\t\tif ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {\n\t\t\tselector = [ selector ];\n\t\t}\n\t\n\t\tfor ( i=0, ien=selector.length ; i<ien ; i++ ) {\n\t\t\t// Only split on simple strings - complex expressions will be jQuery selectors\n\t\t\ta = selector[i] && selector[i].split && ! selector[i].match(/[\\[\\(:]/) ?\n\t\t\t\tselector[i].split(',') :\n\t\t\t\t[ selector[i] ];\n\t\n\t\t\tfor ( j=0, jen=a.length ; j<jen ; j++ ) {\n\t\t\t\tres = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );\n\t\n\t\t\t\tif ( res && res.length ) {\n\t\t\t\t\tout = out.concat( res );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\t// selector extensions\n\t\tvar ext = _ext.selector[ type ];\n\t\tif ( ext.length ) {\n\t\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\t\tout = ext[i]( settings, opts, out );\n\t\t\t}\n\t\t}\n\t\n\t\treturn _unique( out );\n\t};\n\t\n\t\n\tvar _selector_opts = function ( opts )\n\t{\n\t\tif ( ! opts ) {\n\t\t\topts = {};\n\t\t}\n\t\n\t\t// Backwards compatibility for 1.9- which used the terminology filter rather\n\t\t// than search\n\t\tif ( opts.filter && opts.search === undefined ) {\n\t\t\topts.search = opts.filter;\n\t\t}\n\t\n\t\treturn $.extend( {\n\t\t\tsearch: 'none',\n\t\t\torder: 'current',\n\t\t\tpage: 'all'\n\t\t}, opts );\n\t};\n\t\n\t\n\tvar _selector_first = function ( inst )\n\t{\n\t\t// Reduce the API instance to the first item found\n\t\tfor ( var i=0, ien=inst.length ; i<ien ; i++ ) {\n\t\t\tif ( inst[i].length > 0 ) {\n\t\t\t\t// Assign the first element to the first item in the instance\n\t\t\t\t// and truncate the instance and context\n\t\t\t\tinst[0] = inst[i];\n\t\t\t\tinst[0].length = 1;\n\t\t\t\tinst.length = 1;\n\t\t\t\tinst.context = [ inst.context[i] ];\n\t\n\t\t\t\treturn inst;\n\t\t\t}\n\t\t}\n\t\n\t\t// Not found - return an empty instance\n\t\tinst.length = 0;\n\t\treturn inst;\n\t};\n\t\n\t\n\tvar _selector_row_indexes = function ( settings, opts )\n\t{\n\t\tvar\n\t\t\ti, ien, tmp, a=[],\n\t\t\tdisplayFiltered = settings.aiDisplay,\n\t\t\tdisplayMaster = settings.aiDisplayMaster;\n\t\n\t\tvar\n\t\t\tsearch = opts.search,  // none, applied, removed\n\t\t\torder  = opts.order,   // applied, current, index (original - compatibility with 1.9)\n\t\t\tpage   = opts.page;    // all, current\n\t\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t// In server-side processing mode, most options are irrelevant since\n\t\t\t// rows not shown don't exist and the index order is the applied order\n\t\t\t// Removed is a special case - for consistency just return an empty\n\t\t\t// array\n\t\t\treturn search === 'removed' ?\n\t\t\t\t[] :\n\t\t\t\t_range( 0, displayMaster.length );\n\t\t}\n\t\telse if ( page == 'current' ) {\n\t\t\t// Current page implies that order=current and fitler=applied, since it is\n\t\t\t// fairly senseless otherwise, regardless of what order and search actually\n\t\t\t// are\n\t\t\tfor ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {\n\t\t\t\ta.push( displayFiltered[i] );\n\t\t\t}\n\t\t}\n\t\telse if ( order == 'current' || order == 'applied' ) {\n\t\t\tif ( search == 'none') {\n\t\t\t\ta = displayMaster.slice();\n\t\t\t}\n\t\t\telse if ( search == 'applied' ) {\n\t\t\t\ta = displayFiltered.slice();\n\t\t\t}\n\t\t\telse if ( search == 'removed' ) {\n\t\t\t\t// O(n+m) solution by creating a hash map\n\t\t\t\tvar displayFilteredMap = {};\n\t\n\t\t\t\tfor ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) {\n\t\t\t\t\tdisplayFilteredMap[displayFiltered[i]] = null;\n\t\t\t\t}\n\t\n\t\t\t\ta = $.map( displayMaster, function (el) {\n\t\t\t\t\treturn ! displayFilteredMap.hasOwnProperty(el) ?\n\t\t\t\t\t\tel :\n\t\t\t\t\t\tnull;\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\telse if ( order == 'index' || order == 'original' ) {\n\t\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tif ( search == 'none' ) {\n\t\t\t\t\ta.push( i );\n\t\t\t\t}\n\t\t\t\telse { // applied | removed\n\t\t\t\t\ttmp = $.inArray( i, displayFiltered );\n\t\n\t\t\t\t\tif ((tmp === -1 && search == 'removed') ||\n\t\t\t\t\t\t(tmp >= 0   && search == 'applied') )\n\t\t\t\t\t{\n\t\t\t\t\t\ta.push( i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn a;\n\t};\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Rows\n\t *\n\t * {}          - no selector - use all available rows\n\t * {integer}   - row aoData index\n\t * {node}      - TR node\n\t * {string}    - jQuery selector to apply to the TR elements\n\t * {array}     - jQuery array of nodes, or simply an array of TR nodes\n\t *\n\t */\n\tvar __row_selector = function ( settings, selector, opts )\n\t{\n\t\tvar rows;\n\t\tvar run = function ( sel ) {\n\t\t\tvar selInt = _intVal( sel );\n\t\t\tvar i, ien;\n\t\t\tvar aoData = settings.aoData;\n\t\n\t\t\t// Short cut - selector is a number and no options provided (default is\n\t\t\t// all records, so no need to check if the index is in there, since it\n\t\t\t// must be - dev error if the index doesn't exist).\n\t\t\tif ( selInt !== null && ! opts ) {\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\n\t\t\tif ( ! rows ) {\n\t\t\t\trows = _selector_row_indexes( settings, opts );\n\t\t\t}\n\t\n\t\t\tif ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {\n\t\t\t\t// Selector - integer\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\t\telse if ( sel === null || sel === undefined || sel === '' ) {\n\t\t\t\t// Selector - none\n\t\t\t\treturn rows;\n\t\t\t}\n\t\n\t\t\t// Selector - function\n\t\t\tif ( typeof sel === 'function' ) {\n\t\t\t\treturn $.map( rows, function (idx) {\n\t\t\t\t\tvar row = aoData[ idx ];\n\t\t\t\t\treturn sel( idx, row._aData, row.nTr ) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// Selector - node\n\t\t\tif ( sel.nodeName ) {\n\t\t\t\tvar rowIdx = sel._DT_RowIndex;  // Property added by DT for fast lookup\n\t\t\t\tvar cellIdx = sel._DT_CellIndex;\n\t\n\t\t\t\tif ( rowIdx !== undefined ) {\n\t\t\t\t\t// Make sure that the row is actually still present in the table\n\t\t\t\t\treturn aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?\n\t\t\t\t\t\t[ rowIdx ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t\telse if ( cellIdx ) {\n\t\t\t\t\treturn aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel ?\n\t\t\t\t\t\t[ cellIdx.row ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tvar host = $(sel).closest('*[data-dt-row]');\n\t\t\t\t\treturn host.length ?\n\t\t\t\t\t\t[ host.data('dt-row') ] :\n\t\t\t\t\t\t[];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// ID selector. Want to always be able to select rows by id, regardless\n\t\t\t// of if the tr element has been created or not, so can't rely upon\n\t\t\t// jQuery here - hence a custom implementation. This does not match\n\t\t\t// Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,\n\t\t\t// but to select it using a CSS selector engine (like Sizzle or\n\t\t\t// querySelect) it would need to need to be escaped for some characters.\n\t\t\t// DataTables simplifies this for row selectors since you can select\n\t\t\t// only a row. A # indicates an id any anything that follows is the id -\n\t\t\t// unescaped.\n\t\t\tif ( typeof sel === 'string' && sel.charAt(0) === '#' ) {\n\t\t\t\t// get row index from id\n\t\t\t\tvar rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];\n\t\t\t\tif ( rowObj !== undefined ) {\n\t\t\t\t\treturn [ rowObj.idx ];\n\t\t\t\t}\n\t\n\t\t\t\t// need to fall through to jQuery in case there is DOM id that\n\t\t\t\t// matches\n\t\t\t}\n\t\t\t\n\t\t\t// Get nodes in the order from the `rows` array with null values removed\n\t\t\tvar nodes = _removeEmpty(\n\t\t\t\t_pluck_order( settings.aoData, rows, 'nTr' )\n\t\t\t);\n\t\n\t\t\t// Selector - jQuery selector string, array of nodes or jQuery object/\n\t\t\t// As jQuery's .filter() allows jQuery objects to be passed in filter,\n\t\t\t// it also allows arrays, so this will cope with all three options\n\t\t\treturn $(nodes)\n\t\t\t\t.filter( sel )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn this._DT_RowIndex;\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\t};\n\t\n\t\treturn _selector_run( 'row', selector, run, settings, opts );\n\t};\n\t\n\t\n\t_api_register( 'rows()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __row_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in __row_selector?\n\t\tinst.selector.rows = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_register( 'rows().nodes()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn settings.aoData[ row ].nTr || undefined;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'rows().data()', function () {\n\t\treturn this.iterator( true, 'rows', function ( settings, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, '_aData' );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\tvar r = settings.aoData[ row ];\n\t\t\treturn type === 'search' ? r._aFilterData : r._aSortData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\t_fnInvalidate( settings, row, src );\n\t\t} );\n\t} );\n\t\n\t_api_registerPlural( 'rows().indexes()', 'row().index()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn row;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {\n\t\tvar a = [];\n\t\tvar context = this.context;\n\t\n\t\t// `iterator` will drop undefined values, but in this case we want them\n\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\tfor ( var j=0, jen=this[i].length ; j<jen ; j++ ) {\n\t\t\t\tvar id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );\n\t\t\t\ta.push( (hash === true ? '#' : '' )+ id );\n\t\t\t}\n\t\t}\n\t\n\t\treturn new _Api( context, a );\n\t} );\n\t\n\t_api_registerPlural( 'rows().remove()', 'row().remove()', function () {\n\t\tvar that = this;\n\t\n\t\tthis.iterator( 'row', function ( settings, row, thatIdx ) {\n\t\t\tvar data = settings.aoData;\n\t\t\tvar rowData = data[ row ];\n\t\t\tvar i, ien, j, jen;\n\t\t\tvar loopRow, loopCells;\n\t\n\t\t\tdata.splice( row, 1 );\n\t\n\t\t\t// Update the cached indexes\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\tloopRow = data[i];\n\t\t\t\tloopCells = loopRow.anCells;\n\t\n\t\t\t\t// Rows\n\t\t\t\tif ( loopRow.nTr !== null ) {\n\t\t\t\t\tloopRow.nTr._DT_RowIndex = i;\n\t\t\t\t}\n\t\n\t\t\t\t// Cells\n\t\t\t\tif ( loopCells !== null ) {\n\t\t\t\t\tfor ( j=0, jen=loopCells.length ; j<jen ; j++ ) {\n\t\t\t\t\t\tloopCells[j]._DT_CellIndex.row = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Delete from the display arrays\n\t\t\t_fnDeleteIndex( settings.aiDisplayMaster, row );\n\t\t\t_fnDeleteIndex( settings.aiDisplay, row );\n\t\t\t_fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes\n\t\n\t\t\t// For server-side processing tables - subtract the deleted row from the count\n\t\t\tif ( settings._iRecordsDisplay > 0 ) {\n\t\t\t\tsettings._iRecordsDisplay--;\n\t\t\t}\n\t\n\t\t\t// Check for an 'overflow' they case for displaying the table\n\t\t\t_fnLengthOverflow( settings );\n\t\n\t\t\t// Remove the row's ID reference if there is one\n\t\t\tvar id = settings.rowIdFn( rowData._aData );\n\t\t\tif ( id !== undefined ) {\n\t\t\t\tdelete settings.aIds[ id ];\n\t\t\t}\n\t\t} );\n\t\n\t\tthis.iterator( 'table', function ( settings ) {\n\t\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tsettings.aoData[i].idx = i;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'rows.add()', function ( rows ) {\n\t\tvar newRows = this.iterator( 'table', function ( settings ) {\n\t\t\t\tvar row, i, ien;\n\t\t\t\tvar out = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\t\t\tout.push( _fnAddTr( settings, row )[0] );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tout.push( _fnAddData( settings, row ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn out;\n\t\t\t}, 1 );\n\t\n\t\t// Return an Api.rows() extended instance, so rows().nodes() etc can be used\n\t\tvar modRows = this.rows( -1 );\n\t\tmodRows.pop();\n\t\t$.merge( modRows, newRows );\n\t\n\t\treturn modRows;\n\t} );\n\t\n\t\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( 'row()', function ( selector, opts ) {\n\t\treturn _selector_first( this.rows( selector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'row().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._aData :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\tvar row = ctx[0].aoData[ this[0] ];\n\t\trow._aData = data;\n\t\n\t\t// If the DOM has an id, and the data source is an array\n\t\tif ( $.isArray( data ) && row.nTr.id ) {\n\t\t\t_fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );\n\t\t}\n\t\n\t\t// Automatically invalidate\n\t\t_fnInvalidate( ctx[0], this[0], 'data' );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'row().node()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\treturn ctx.length && this.length ?\n\t\t\tctx[0].aoData[ this[0] ].nTr || null :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'row.add()', function ( row ) {\n\t\t// Allow a jQuery object to be passed in - only a single row is added from\n\t\t// it though - the first element in the set\n\t\tif ( row instanceof $ && row.length ) {\n\t\t\trow = row[0];\n\t\t}\n\t\n\t\tvar rows = this.iterator( 'table', function ( settings ) {\n\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\treturn _fnAddTr( settings, row )[0];\n\t\t\t}\n\t\t\treturn _fnAddData( settings, row );\n\t\t} );\n\t\n\t\t// Return an Api.rows() extended instance, with the newly added row selected\n\t\treturn this.row( rows[0] );\n\t} );\n\t\n\t\n\t\n\tvar __details_add = function ( ctx, row, data, klass )\n\t{\n\t\t// Convert to array of TR elements\n\t\tvar rows = [];\n\t\tvar addRow = function ( r, k ) {\n\t\t\t// Recursion to allow for arrays of jQuery objects\n\t\t\tif ( $.isArray( r ) || r instanceof $ ) {\n\t\t\t\tfor ( var i=0, ien=r.length ; i<ien ; i++ ) {\n\t\t\t\t\taddRow( r[i], k );\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t// If we get a TR element, then just add it directly - up to the dev\n\t\t\t// to add the correct number of columns etc\n\t\t\tif ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {\n\t\t\t\trows.push( r );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Otherwise create a row with a wrapper\n\t\t\t\tvar created = $('<tr><td/></tr>').addClass( k );\n\t\t\t\t$('td', created)\n\t\t\t\t\t.addClass( k )\n\t\t\t\t\t.html( r )\n\t\t\t\t\t[0].colSpan = _fnVisbleColumns( ctx );\n\t\n\t\t\t\trows.push( created[0] );\n\t\t\t}\n\t\t};\n\t\n\t\taddRow( data, klass );\n\t\n\t\tif ( row._details ) {\n\t\t\trow._details.detach();\n\t\t}\n\t\n\t\trow._details = $(rows);\n\t\n\t\t// If the children were already shown, that state should be retained\n\t\tif ( row._detailsShow ) {\n\t\t\trow._details.insertAfter( row.nTr );\n\t\t}\n\t};\n\t\n\t\n\tvar __details_remove = function ( api, idx )\n\t{\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length ) {\n\t\t\tvar row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];\n\t\n\t\t\tif ( row && row._details ) {\n\t\t\t\trow._details.remove();\n\t\n\t\t\t\trow._detailsShow = undefined;\n\t\t\t\trow._details = undefined;\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_display = function ( api, show ) {\n\t\tvar ctx = api.context;\n\t\n\t\tif ( ctx.length && api.length ) {\n\t\t\tvar row = ctx[0].aoData[ api[0] ];\n\t\n\t\t\tif ( row._details ) {\n\t\t\t\trow._detailsShow = show;\n\t\n\t\t\t\tif ( show ) {\n\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\trow._details.detach();\n\t\t\t\t}\n\t\n\t\t\t\t__details_events( ctx[0] );\n\t\t\t}\n\t\t}\n\t};\n\t\n\t\n\tvar __details_events = function ( settings )\n\t{\n\t\tvar api = new _Api( settings );\n\t\tvar namespace = '.dt.DT_details';\n\t\tvar drawEvent = 'draw'+namespace;\n\t\tvar colvisEvent = 'column-visibility'+namespace;\n\t\tvar destroyEvent = 'destroy'+namespace;\n\t\tvar data = settings.aoData;\n\t\n\t\tapi.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );\n\t\n\t\tif ( _pluck( data, '_details' ).length > 0 ) {\n\t\t\t// On each draw, insert the required elements into the document\n\t\t\tapi.on( drawEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tapi.rows( {page:'current'} ).eq(0).each( function (idx) {\n\t\t\t\t\t// Internal data grab\n\t\t\t\t\tvar row = data[ idx ];\n\t\n\t\t\t\t\tif ( row._detailsShow ) {\n\t\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\n\t\t\t// Column visibility change - update the colspan\n\t\t\tapi.on( colvisEvent, function ( e, ctx, idx, vis ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t// Update the colspan for the details rows (note, only if it already has\n\t\t\t\t// a colspan)\n\t\t\t\tvar row, visible = _fnVisbleColumns( ctx );\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = data[i];\n\t\n\t\t\t\t\tif ( row._details ) {\n\t\t\t\t\t\trow._details.children('td[colspan]').attr('colspan', visible );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\t// Table destroyed - nuke any child rows\n\t\t\tapi.on( destroyEvent, function ( e, ctx ) {\n\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( data[i]._details ) {\n\t\t\t\t\t\t__details_remove( api, i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t// Strings for the method names to help minification\n\tvar _emp = '';\n\tvar _child_obj = _emp+'row().child';\n\tvar _child_mth = _child_obj+'()';\n\t\n\t// data can be:\n\t//  tr\n\t//  string\n\t//  jQuery or array of any of the above\n\t_api_register( _child_mth, function ( data, klass ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._details :\n\t\t\t\tundefined;\n\t\t}\n\t\telse if ( data === true ) {\n\t\t\t// show\n\t\t\tthis.child.show();\n\t\t}\n\t\telse if ( data === false ) {\n\t\t\t// remove\n\t\t\t__details_remove( this );\n\t\t}\n\t\telse if ( ctx.length && this.length ) {\n\t\t\t// set\n\t\t\t__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );\n\t\t}\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.show()',\n\t\t_child_mth+'.show()' // only when `child()` was called with parameters (without\n\t], function ( show ) {   // it returns an object and this method is not executed)\n\t\t__details_display( this, true );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.hide()',\n\t\t_child_mth+'.hide()' // only when `child()` was called with parameters (without\n\t], function () {         // it returns an object and this method is not executed)\n\t\t__details_display( this, false );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t_child_obj+'.remove()',\n\t\t_child_mth+'.remove()' // only when `child()` was called with parameters (without\n\t], function () {           // it returns an object and this method is not executed)\n\t\t__details_remove( this );\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( _child_obj+'.isShown()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length && this.length ) {\n\t\t\t// _detailsShown as false or undefined will fall through to return false\n\t\t\treturn ctx[0].aoData[ this[0] ]._detailsShow || false;\n\t\t}\n\t\treturn false;\n\t} );\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Columns\n\t *\n\t * {integer}           - column index (>=0 count from left, <0 count from right)\n\t * \"{integer}:visIdx\"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)\n\t * \"{integer}:visible\" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)\n\t * \"{string}:name\"     - column name\n\t * \"{string}\"          - jQuery selector on column header nodes\n\t *\n\t */\n\t\n\t// can be an array of these items, comma separated list, or an array of comma\n\t// separated lists\n\t\n\tvar __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;\n\t\n\t\n\t// r1 and r2 are redundant - but it means that the parameters match for the\n\t// iterator callback in columns().data()\n\tvar __columnData = function ( settings, column, r1, r2, rows ) {\n\t\tvar a = [];\n\t\tfor ( var row=0, ien=rows.length ; row<ien ; row++ ) {\n\t\t\ta.push( _fnGetCellData( settings, rows[row], column ) );\n\t\t}\n\t\treturn a;\n\t};\n\t\n\t\n\tvar __column_selector = function ( settings, selector, opts )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tnames = _pluck( columns, 'sName' ),\n\t\t\tnodes = _pluck( columns, 'nTh' );\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar selInt = _intVal( s );\n\t\n\t\t\t// Selector - all\n\t\t\tif ( s === '' ) {\n\t\t\t\treturn _range( columns.length );\n\t\t\t}\n\t\n\t\t\t// Selector - index\n\t\t\tif ( selInt !== null ) {\n\t\t\t\treturn [ selInt >= 0 ?\n\t\t\t\t\tselInt : // Count from left\n\t\t\t\t\tcolumns.length + selInt // Count from right (+ because its a negative value)\n\t\t\t\t];\n\t\t\t}\n\t\n\t\t\t// Selector = function\n\t\t\tif ( typeof s === 'function' ) {\n\t\t\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\n\t\t\t\treturn $.map( columns, function (col, idx) {\n\t\t\t\t\treturn s(\n\t\t\t\t\t\t\tidx,\n\t\t\t\t\t\t\t__columnData( settings, idx, 0, 0, rows ),\n\t\t\t\t\t\t\tnodes[ idx ]\n\t\t\t\t\t\t) ? idx : null;\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t// jQuery or string selector\n\t\t\tvar match = typeof s === 'string' ?\n\t\t\t\ts.match( __re_column_selector ) :\n\t\t\t\t'';\n\t\n\t\t\tif ( match ) {\n\t\t\t\tswitch( match[2] ) {\n\t\t\t\t\tcase 'visIdx':\n\t\t\t\t\tcase 'visible':\n\t\t\t\t\t\tvar idx = parseInt( match[1], 10 );\n\t\t\t\t\t\t// Visible index given, convert to column index\n\t\t\t\t\t\tif ( idx < 0 ) {\n\t\t\t\t\t\t\t// Counting from the right\n\t\t\t\t\t\t\tvar visColumns = $.map( columns, function (col,i) {\n\t\t\t\t\t\t\t\treturn col.bVisible ? i : null;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\treturn [ visColumns[ visColumns.length + idx ] ];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Counting from the left\n\t\t\t\t\t\treturn [ _fnVisibleToColumnIndex( settings, idx ) ];\n\t\n\t\t\t\t\tcase 'name':\n\t\t\t\t\t\t// match by name. `names` is column index complete and in order\n\t\t\t\t\t\treturn $.map( names, function (name, i) {\n\t\t\t\t\t\t\treturn name === match[1] ? i : null;\n\t\t\t\t\t\t} );\n\t\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Cell in the table body\n\t\t\tif ( s.nodeName && s._DT_CellIndex ) {\n\t\t\t\treturn [ s._DT_CellIndex.column ];\n\t\t\t}\n\t\n\t\t\t// jQuery selector on the TH elements for the columns\n\t\t\tvar jqResult = $( nodes )\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn $.inArray( this, nodes ); // `nodes` is column index complete and in order\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise a node which might have a `dt-column` data attribute, or be\n\t\t\t// a child or such an element\n\t\t\tvar host = $(s).closest('*[data-dt-column]');\n\t\t\treturn host.length ?\n\t\t\t\t[ host.data('dt-column') ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'column', selector, run, settings, opts );\n\t};\n\t\n\t\n\tvar __setColumnVis = function ( settings, column, vis ) {\n\t\tvar\n\t\t\tcols = settings.aoColumns,\n\t\t\tcol  = cols[ column ],\n\t\t\tdata = settings.aoData,\n\t\t\trow, cells, i, ien, tr;\n\t\n\t\t// Get\n\t\tif ( vis === undefined ) {\n\t\t\treturn col.bVisible;\n\t\t}\n\t\n\t\t// Set\n\t\t// No change\n\t\tif ( col.bVisible === vis ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( vis ) {\n\t\t\t// Insert column\n\t\t\t// Need to decide if we should use appendChild or insertBefore\n\t\t\tvar insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );\n\t\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\ttr = data[i].nTr;\n\t\t\t\tcells = data[i].anCells;\n\t\n\t\t\t\tif ( tr ) {\n\t\t\t\t\t// insertBefore can act like appendChild if 2nd arg is null\n\t\t\t\t\ttr.insertBefore( cells[ column ], cells[ insertBefore ] || null );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Remove column\n\t\t\t$( _pluck( settings.aoData, 'anCells', column ) ).detach();\n\t\t}\n\t\n\t\t// Common actions\n\t\tcol.bVisible = vis;\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t// Update colspan for no records display. Child rows and extensions will use their own\n\t\t// listeners to do this - only need to update the empty table item here\n\t\tif ( ! settings.aiDisplay.length ) {\n\t\t\t$(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));\n\t\t}\n\t\n\t\t_fnSaveState( settings );\n\t};\n\t\n\t\n\t_api_register( 'columns()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __column_selector( settings, selector, opts );\n\t\t}, 1 );\n\t\n\t\t// Want argument shifting here and in _row_selector?\n\t\tinst.selector.cols = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t_api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTh;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTf;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().data()', 'column().data()', function () {\n\t\treturn this.iterator( 'column-rows', __columnData, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].mData;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows,\n\t\t\t\ttype === 'search' ? '_aFilterData' : '_aSortData', column\n\t\t\t);\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, 'anCells', column ) ;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {\n\t\tvar ret = this.iterator( 'column', function ( settings, column ) {\n\t\t\tif ( vis === undefined ) {\n\t\t\t\treturn settings.aoColumns[ column ].bVisible;\n\t\t\t} // else\n\t\t\t__setColumnVis( settings, column, vis );\n\t\t} );\n\t\n\t\t// Group the column visibility changes\n\t\tif ( vis !== undefined ) {\n\t\t\t// Second loop once the first is done for events\n\t\t\tthis.iterator( 'column', function ( settings, column ) {\n\t\t\t\t_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );\n\t\t\t} );\n\t\n\t\t\tif ( calc === undefined || calc ) {\n\t\t\t\tthis.columns.adjust();\n\t\t\t}\n\t\t}\n\t\n\t\treturn ret;\n\t} );\n\t\n\t_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn type === 'visible' ?\n\t\t\t\t_fnColumnIndexToVisible( settings, column ) :\n\t\t\t\tcolumn;\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'columns.adjust()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}, 1 );\n\t} );\n\t\n\t_api_register( 'column.index()', function ( type, idx ) {\n\t\tif ( this.context.length !== 0 ) {\n\t\t\tvar ctx = this.context[0];\n\t\n\t\t\tif ( type === 'fromVisible' || type === 'toData' ) {\n\t\t\t\treturn _fnVisibleToColumnIndex( ctx, idx );\n\t\t\t}\n\t\t\telse if ( type === 'fromData' || type === 'toVisible' ) {\n\t\t\t\treturn _fnColumnIndexToVisible( ctx, idx );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t_api_register( 'column()', function ( selector, opts ) {\n\t\treturn _selector_first( this.columns( selector, opts ) );\n\t} );\n\t\n\t\n\t\n\tvar __cell_selector = function ( settings, selector, opts )\n\t{\n\t\tvar data = settings.aoData;\n\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\tvar cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );\n\t\tvar allCells = $( [].concat.apply([], cells) );\n\t\tvar row;\n\t\tvar columns = settings.aoColumns.length;\n\t\tvar a, i, ien, j, o, host;\n\t\n\t\tvar run = function ( s ) {\n\t\t\tvar fnSelector = typeof s === 'function';\n\t\n\t\t\tif ( s === null || s === undefined || fnSelector ) {\n\t\t\t\t// All cells and function selectors\n\t\t\t\ta = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tfor ( j=0 ; j<columns ; j++ ) {\n\t\t\t\t\t\to = {\n\t\t\t\t\t\t\trow: row,\n\t\t\t\t\t\t\tcolumn: j\n\t\t\t\t\t\t};\n\t\n\t\t\t\t\t\tif ( fnSelector ) {\n\t\t\t\t\t\t\t// Selector - function\n\t\t\t\t\t\t\thost = data[ row ];\n\t\n\t\t\t\t\t\t\tif ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {\n\t\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Selector - all\n\t\t\t\t\t\t\ta.push( o );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn a;\n\t\t\t}\n\t\t\t\n\t\t\t// Selector - index\n\t\t\tif ( $.isPlainObject( s ) ) {\n\t\t\t\t// Valid cell index and its in the array of selectable rows\n\t\t\t\treturn s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ?\n\t\t\t\t\t[s] :\n\t\t\t\t\t[];\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery filtered cells\n\t\t\tvar jqResult = allCells\n\t\t\t\t.filter( s )\n\t\t\t\t.map( function (i, el) {\n\t\t\t\t\treturn { // use a new object, in case someone changes the values\n\t\t\t\t\t\trow:    el._DT_CellIndex.row,\n\t\t\t\t\t\tcolumn: el._DT_CellIndex.column\n\t \t\t\t\t};\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\n\t\t\tif ( jqResult.length || ! s.nodeName ) {\n\t\t\t\treturn jqResult;\n\t\t\t}\n\t\n\t\t\t// Otherwise the selector is a node, and there is one last option - the\n\t\t\t// element might be a child of an element which has dt-row and dt-column\n\t\t\t// data attributes\n\t\t\thost = $(s).closest('*[data-dt-row]');\n\t\t\treturn host.length ?\n\t\t\t\t[ {\n\t\t\t\t\trow: host.data('dt-row'),\n\t\t\t\t\tcolumn: host.data('dt-column')\n\t\t\t\t} ] :\n\t\t\t\t[];\n\t\t};\n\t\n\t\treturn _selector_run( 'cell', selector, run, settings, opts );\n\t};\n\t\n\t\n\t\n\t\n\t_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {\n\t\t// Argument shifting\n\t\tif ( $.isPlainObject( rowSelector ) ) {\n\t\t\t// Indexes\n\t\t\tif ( rowSelector.row === undefined ) {\n\t\t\t\t// Selector options in first parameter\n\t\t\t\topts = rowSelector;\n\t\t\t\trowSelector = null;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Cell index objects in first parameter\n\t\t\t\topts = columnSelector;\n\t\t\t\tcolumnSelector = null;\n\t\t\t}\n\t\t}\n\t\tif ( $.isPlainObject( columnSelector ) ) {\n\t\t\topts = columnSelector;\n\t\t\tcolumnSelector = null;\n\t\t}\n\t\n\t\t// Cell selector\n\t\tif ( columnSelector === null || columnSelector === undefined ) {\n\t\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t\treturn __cell_selector( settings, rowSelector, _selector_opts( opts ) );\n\t\t\t} );\n\t\t}\n\t\n\t\t// Row + column selector\n\t\tvar columns = this.columns( columnSelector );\n\t\tvar rows = this.rows( rowSelector );\n\t\tvar a, i, ien, j, jen;\n\t\n\t\tthis.iterator( 'table', function ( settings, idx ) {\n\t\t\ta = [];\n\t\n\t\t\tfor ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {\n\t\t\t\tfor ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {\n\t\t\t\t\ta.push( {\n\t\t\t\t\t\trow:    rows[idx][i],\n\t\t\t\t\t\tcolumn: columns[idx][j]\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}, 1 );\n\t\n\t    // Now pass through the cell selector for options\n\t    var cells = this.cells( a, opts );\n\t\n\t\t$.extend( cells.selector, {\n\t\t\tcols: columnSelector,\n\t\t\trows: rowSelector,\n\t\t\topts: opts\n\t\t} );\n\t\n\t\treturn cells;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\tvar data = settings.aoData[ row ];\n\t\n\t\t\treturn data && data.anCells ?\n\t\t\t\tdata.anCells[ column ] :\n\t\t\t\tundefined;\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_register( 'cells().data()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {\n\t\ttype = type === 'search' ? '_aFilterData' : '_aSortData';\n\t\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn settings.aoData[ row ][ type ][ column ];\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column, type );\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn {\n\t\t\t\trow: row,\n\t\t\t\tcolumn: column,\n\t\t\t\tcolumnVisible: _fnColumnIndexToVisible( settings, column )\n\t\t\t};\n\t\t}, 1 );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\t_fnInvalidate( settings, row, src, column );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {\n\t\treturn _selector_first( this.cells( rowSelector, columnSelector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'cell().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\tvar cell = this[0];\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && cell.length ?\n\t\t\t\t_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\t_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );\n\t\t_fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get current ordering (sorting) that has been applied to the table.\n\t *\n\t * @returns {array} 2D array containing the sorting information for the first\n\t *   table in the current context. Each element in the parent array represents\n\t *   a column being sorted upon (i.e. multi-sorting with two columns would have\n\t *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is\n\t *   the column index that the sorting condition applies to, the second is the\n\t *   direction of the sort (`desc` or `asc`) and, optionally, the third is the\n\t *   index of the sorting order from the `column.sorting` initialisation array.\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {integer} order Column index to sort upon.\n\t * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 1D array of sorting information to be applied.\n\t * @param {array} [...] Optional additional sorting conditions\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 2D array of sorting information to be applied.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order()', function ( order, dir ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( order === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].aaSorting :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\tif ( typeof order === 'number' ) {\n\t\t\t// Simple column / direction passed in\n\t\t\torder = [ [ order, dir ] ];\n\t\t}\n\t\telse if ( order.length && ! $.isArray( order[0] ) ) {\n\t\t\t// Arguments passed in (list of 1D arrays)\n\t\t\torder = Array.prototype.slice.call( arguments );\n\t\t}\n\t\t// otherwise a 2D array was passed in\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSorting = order.slice();\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Attach a sort listener to an element for a given column\n\t *\n\t * @param {node|jQuery|string} node Identifier for the element(s) to attach the\n\t *   listener to. This can take the form of a single DOM node, a jQuery\n\t *   collection of nodes or a jQuery selector which will identify the node(s).\n\t * @param {integer} column the column that a click on this node will sort on\n\t * @param {function} [callback] callback function when sort is run\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order.listener()', function ( node, column, callback ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSortAttachListener( settings, node, column, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'order.fixed()', function ( set ) {\n\t\tif ( ! set ) {\n\t\t\tvar ctx = this.context;\n\t\t\tvar fixed = ctx.length ?\n\t\t\t\tctx[0].aaSortingFixed :\n\t\t\t\tundefined;\n\t\n\t\t\treturn $.isArray( fixed ) ?\n\t\t\t\t{ pre: fixed } :\n\t\t\t\tfixed;\n\t\t}\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSortingFixed = $.extend( true, {}, set );\n\t\t} );\n\t} );\n\t\n\t\n\t// Order by the selected column(s)\n\t_api_register( [\n\t\t'columns().order()',\n\t\t'column().order()'\n\t], function ( dir ) {\n\t\tvar that = this;\n\t\n\t\treturn this.iterator( 'table', function ( settings, i ) {\n\t\t\tvar sort = [];\n\t\n\t\t\t$.each( that[i], function (j, col) {\n\t\t\t\tsort.push( [ col, dir ] );\n\t\t\t} );\n\t\n\t\t\tsettings.aaSorting = sort;\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'search()', function ( input, regex, smart, caseInsen ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( input === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].oPreviousSearch.sSearch :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t_fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {\n\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t} ), 1 );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural(\n\t\t'columns().search()',\n\t\t'column().search()',\n\t\tfunction ( input, regex, smart, caseInsen ) {\n\t\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\t\tvar preSearch = settings.aoPreSearchCols;\n\t\n\t\t\t\tif ( input === undefined ) {\n\t\t\t\t\t// get\n\t\t\t\t\treturn preSearch[ column ].sSearch;\n\t\t\t\t}\n\t\n\t\t\t\t// set\n\t\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\n\t\t\t\t$.extend( preSearch[ column ], {\n\t\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t\t} );\n\t\n\t\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch, 1 );\n\t\t\t} );\n\t\t}\n\t);\n\t\n\t/*\n\t * State API methods\n\t */\n\t\n\t_api_register( 'state()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oSavedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t// Save an empty object\n\t\t\tsettings.fnStateSaveCallback.call( settings.oInstance, settings, {} );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'state.loaded()', function () {\n\t\treturn this.context.length ?\n\t\t\tthis.context[0].oLoadedState :\n\t\t\tnull;\n\t} );\n\t\n\t\n\t_api_register( 'state.save()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSaveState( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Provide a common method for plug-ins to check the version of DataTables being\n\t * used, in order to ensure compatibility.\n\t *\n\t *  @param {string} version Version string to check for, in the format \"X.Y.Z\".\n\t *    Note that the formats \"X\" and \"X.Y\" are also acceptable.\n\t *  @returns {boolean} true if this version of DataTables is greater or equal to\n\t *    the required version, or false if this version of DataTales is not\n\t *    suitable\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );\n\t */\n\tDataTable.versionCheck = DataTable.fnVersionCheck = function( version )\n\t{\n\t\tvar aThis = DataTable.version.split('.');\n\t\tvar aThat = version.split('.');\n\t\tvar iThis, iThat;\n\t\n\t\tfor ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {\n\t\t\tiThis = parseInt( aThis[i], 10 ) || 0;\n\t\t\tiThat = parseInt( aThat[i], 10 ) || 0;\n\t\n\t\t\t// Parts are the same, keep comparing\n\t\t\tif (iThis === iThat) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\t// Parts are different, return immediately\n\t\t\treturn iThis > iThat;\n\t\t}\n\t\n\t\treturn true;\n\t};\n\t\n\t\n\t/**\n\t * Check if a `<table>` node is a DataTable table already or not.\n\t *\n\t *  @param {node|jquery|string} table Table node, jQuery object or jQuery\n\t *      selector for the table to test. Note that if more than more than one\n\t *      table is passed on, only the first will be checked\n\t *  @returns {boolean} true the table given is a DataTable, or false otherwise\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {\n\t *      $('#example').dataTable();\n\t *    }\n\t */\n\tDataTable.isDataTable = DataTable.fnIsDataTable = function ( table )\n\t{\n\t\tvar t = $(table).get(0);\n\t\tvar is = false;\n\t\n\t\tif ( table instanceof DataTable.Api ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\t$.each( DataTable.settings, function (i, o) {\n\t\t\tvar head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;\n\t\t\tvar foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;\n\t\n\t\t\tif ( o.nTable === t || head === t || foot === t ) {\n\t\t\t\tis = true;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn is;\n\t};\n\t\n\t\n\t/**\n\t * Get all DataTable tables that have been initialised - optionally you can\n\t * select to get only currently visible tables.\n\t *\n\t *  @param {boolean} [visible=false] Flag to indicate if you want all (default)\n\t *    or visible tables only.\n\t *  @returns {array} Array of `table` nodes (not DataTable instances) which are\n\t *    DataTables\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    $.each( $.fn.dataTable.tables(true), function () {\n\t *      $(table).DataTable().columns.adjust();\n\t *    } );\n\t */\n\tDataTable.tables = DataTable.fnTables = function ( visible )\n\t{\n\t\tvar api = false;\n\t\n\t\tif ( $.isPlainObject( visible ) ) {\n\t\t\tapi = visible.api;\n\t\t\tvisible = visible.visible;\n\t\t}\n\t\n\t\tvar a = $.map( DataTable.settings, function (o) {\n\t\t\tif ( !visible || (visible && $(o.nTable).is(':visible')) ) {\n\t\t\t\treturn o.nTable;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn api ?\n\t\t\tnew _Api( a ) :\n\t\t\ta;\n\t};\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian notation. This is made public\n\t * for the extensions to provide the same ability as DataTables core to accept\n\t * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase\n\t * parameters.\n\t *\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t */\n\tDataTable.camelToHungarian = _fnCamelToHungarian;\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( '$()', function ( selector, opts ) {\n\t\tvar\n\t\t\trows   = this.rows( opts ).nodes(), // Get all rows\n\t\t\tjqRows = $(rows);\n\t\n\t\treturn $( [].concat(\n\t\t\tjqRows.filter( selector ).toArray(),\n\t\t\tjqRows.find( selector ).toArray()\n\t\t) );\n\t} );\n\t\n\t\n\t// jQuery functions to operate on the tables\n\t$.each( [ 'on', 'one', 'off' ], function (i, key) {\n\t\t_api_register( key+'()', function ( /* event, handler */ ) {\n\t\t\tvar args = Array.prototype.slice.call(arguments);\n\t\n\t\t\t// Add the `dt` namespace automatically if it isn't already present\n\t\t\targs[0] = $.map( args[0].split( /\\s/ ), function ( e ) {\n\t\t\t\treturn ! e.match(/\\.dt\\b/) ?\n\t\t\t\t\te+'.dt' :\n\t\t\t\t\te;\n\t\t\t\t} ).join( ' ' );\n\t\n\t\t\tvar inst = $( this.tables().nodes() );\n\t\t\tinst[key].apply( inst, args );\n\t\t\treturn this;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnClearTable( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'settings()', function () {\n\t\treturn new _Api( this.context, this.context );\n\t} );\n\t\n\t\n\t_api_register( 'init()', function () {\n\t\tvar ctx = this.context;\n\t\treturn ctx.length ? ctx[0].oInit : null;\n\t} );\n\t\n\t\n\t_api_register( 'data()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\treturn _pluck( settings.aoData, '_aData' );\n\t\t} ).flatten();\n\t} );\n\t\n\t\n\t_api_register( 'destroy()', function ( remove ) {\n\t\tremove = remove || false;\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tvar orig      = settings.nTableWrapper.parentNode;\n\t\t\tvar classes   = settings.oClasses;\n\t\t\tvar table     = settings.nTable;\n\t\t\tvar tbody     = settings.nTBody;\n\t\t\tvar thead     = settings.nTHead;\n\t\t\tvar tfoot     = settings.nTFoot;\n\t\t\tvar jqTable   = $(table);\n\t\t\tvar jqTbody   = $(tbody);\n\t\t\tvar jqWrapper = $(settings.nTableWrapper);\n\t\t\tvar rows      = $.map( settings.aoData, function (r) { return r.nTr; } );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Flag to note that the table is currently being destroyed - no action\n\t\t\t// should be taken\n\t\t\tsettings.bDestroying = true;\n\t\n\t\t\t// Fire off the destroy callbacks for plug-ins etc\n\t\t\t_fnCallbackFire( settings, \"aoDestroyCallback\", \"destroy\", [settings] );\n\t\n\t\t\t// If not being removed from the document, make all columns visible\n\t\t\tif ( ! remove ) {\n\t\t\t\tnew _Api( settings ).columns().visible( true );\n\t\t\t}\n\t\n\t\t\t// Blitz all `DT` namespaced events (these are internal events, the\n\t\t\t// lowercase, `dt` events are user subscribed and they are responsible\n\t\t\t// for removing them\n\t\t\tjqWrapper.off('.DT').find(':not(tbody *)').off('.DT');\n\t\t\t$(window).off('.DT-'+settings.sInstance);\n\t\n\t\t\t// When scrolling we had to break the table up - restore it\n\t\t\tif ( table != thead.parentNode ) {\n\t\t\t\tjqTable.children('thead').detach();\n\t\t\t\tjqTable.append( thead );\n\t\t\t}\n\t\n\t\t\tif ( tfoot && table != tfoot.parentNode ) {\n\t\t\t\tjqTable.children('tfoot').detach();\n\t\t\t\tjqTable.append( tfoot );\n\t\t\t}\n\t\n\t\t\tsettings.aaSorting = [];\n\t\t\tsettings.aaSortingFixed = [];\n\t\t\t_fnSortingClasses( settings );\n\t\n\t\t\t$( rows ).removeClass( settings.asStripeClasses.join(' ') );\n\t\n\t\t\t$('th, td', thead).removeClass( classes.sSortable+' '+\n\t\t\t\tclasses.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone\n\t\t\t);\n\t\n\t\t\t// Add the TR elements back into the table in their original order\n\t\t\tjqTbody.children().detach();\n\t\t\tjqTbody.append( rows );\n\t\n\t\t\t// Remove the DataTables generated nodes, events and classes\n\t\t\tvar removedMethod = remove ? 'remove' : 'detach';\n\t\t\tjqTable[ removedMethod ]();\n\t\t\tjqWrapper[ removedMethod ]();\n\t\n\t\t\t// If we need to reattach the table to the document\n\t\t\tif ( ! remove && orig ) {\n\t\t\t\t// insertBefore acts like appendChild if !arg[1]\n\t\t\t\torig.insertBefore( table, settings.nTableReinsertBefore );\n\t\n\t\t\t\t// Restore the width of the original table - was read from the style property,\n\t\t\t\t// so we can restore directly to that\n\t\t\t\tjqTable\n\t\t\t\t\t.css( 'width', settings.sDestroyWidth )\n\t\t\t\t\t.removeClass( classes.sTable );\n\t\n\t\t\t\t// If the were originally stripe classes - then we add them back here.\n\t\t\t\t// Note this is not fool proof (for example if not all rows had stripe\n\t\t\t\t// classes - but it's a good effort without getting carried away\n\t\t\t\tien = settings.asDestroyStripes.length;\n\t\n\t\t\t\tif ( ien ) {\n\t\t\t\t\tjqTbody.children().each( function (i) {\n\t\t\t\t\t\t$(this).addClass( settings.asDestroyStripes[i % ien] );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Remove the settings object from the settings array */\n\t\t\tvar idx = $.inArray( settings, DataTable.settings );\n\t\t\tif ( idx !== -1 ) {\n\t\t\t\tDataTable.settings.splice( idx, 1 );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\t\n\t// Add the `every()` method for rows, columns and cells in a compact form\n\t$.each( [ 'column', 'row', 'cell' ], function ( i, type ) {\n\t\t_api_register( type+'s().every()', function ( fn ) {\n\t\t\tvar opts = this.selector.opts;\n\t\t\tvar api = this;\n\t\n\t\t\treturn this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {\n\t\t\t\t// Rows and columns:\n\t\t\t\t//  arg1 - index\n\t\t\t\t//  arg2 - table counter\n\t\t\t\t//  arg3 - loop counter\n\t\t\t\t//  arg4 - undefined\n\t\t\t\t// Cells:\n\t\t\t\t//  arg1 - row index\n\t\t\t\t//  arg2 - column index\n\t\t\t\t//  arg3 - table counter\n\t\t\t\t//  arg4 - loop counter\n\t\t\t\tfn.call(\n\t\t\t\t\tapi[ type ](\n\t\t\t\t\t\targ1,\n\t\t\t\t\t\ttype==='cell' ? arg2 : opts,\n\t\t\t\t\t\ttype==='cell' ? opts : undefined\n\t\t\t\t\t),\n\t\t\t\t\targ1, arg2, arg3, arg4\n\t\t\t\t);\n\t\t\t} );\n\t\t} );\n\t} );\n\t\n\t\n\t// i18n method for extensions to be able to use the language object from the\n\t// DataTable\n\t_api_register( 'i18n()', function ( token, def, plural ) {\n\t\tvar ctx = this.context[0];\n\t\tvar resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );\n\t\n\t\tif ( resolved === undefined ) {\n\t\t\tresolved = def;\n\t\t}\n\t\n\t\tif ( plural !== undefined && $.isPlainObject( resolved ) ) {\n\t\t\tresolved = resolved[ plural ] !== undefined ?\n\t\t\t\tresolved[ plural ] :\n\t\t\t\tresolved._;\n\t\t}\n\t\n\t\treturn resolved.replace( '%d', plural ); // nb: plural might be undefined,\n\t} );\n\n\t/**\n\t * Version string for plug-ins to check compatibility. Allowed format is\n\t * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used\n\t * only for non-release builds. See http://semver.org/ for more information.\n\t *  @member\n\t *  @type string\n\t *  @default Version number\n\t */\n\tDataTable.version = \"1.10.18\";\n\n\t/**\n\t * Private data store, containing all of the settings objects that are\n\t * created for the tables on a given page.\n\t *\n\t * Note that the `DataTable.settings` object is aliased to\n\t * `jQuery.fn.dataTableExt` through which it may be accessed and\n\t * manipulated, or `jQuery.fn.dataTable.settings`.\n\t *  @member\n\t *  @type array\n\t *  @default []\n\t *  @private\n\t */\n\tDataTable.settings = [];\n\n\t/**\n\t * Object models container, for the various models that DataTables has\n\t * available to it. These models define the objects that are used to hold\n\t * the active state and configuration of the table.\n\t *  @namespace\n\t */\n\tDataTable.models = {};\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * search information for the global filter and individual column filters.\n\t *  @namespace\n\t */\n\tDataTable.models.oSearch = {\n\t\t/**\n\t\t * Flag to indicate if the filtering should be case insensitive or not\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bCaseInsensitive\": true,\n\t\n\t\t/**\n\t\t * Applied search term\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sSearch\": \"\",\n\t\n\t\t/**\n\t\t * Flag to indicate if the search term should be interpreted as a\n\t\t * regular expression (true) or not (false) and therefore and special\n\t\t * regex characters escaped.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bRegex\": false,\n\t\n\t\t/**\n\t\t * Flag to indicate if DataTables is to use its smart filtering or not.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bSmart\": true\n\t};\n\t\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * each individual row. This is the object format used for the settings\n\t * aoData array.\n\t *  @namespace\n\t */\n\tDataTable.models.oRow = {\n\t\t/**\n\t\t * TR element for the row\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTr\": null,\n\t\n\t\t/**\n\t\t * Array of TD elements for each row. This is null until the row has been\n\t\t * created.\n\t\t *  @type array nodes\n\t\t *  @default []\n\t\t */\n\t\t\"anCells\": null,\n\t\n\t\t/**\n\t\t * Data object from the original data source for the row. This is either\n\t\t * an array if using the traditional form of DataTables, or an object if\n\t\t * using mData options. The exact type will depend on the passed in\n\t\t * data from the data source, or will be an array if using DOM a data\n\t\t * source.\n\t\t *  @type array|object\n\t\t *  @default []\n\t\t */\n\t\t\"_aData\": [],\n\t\n\t\t/**\n\t\t * Sorting data cache - this array is ostensibly the same length as the\n\t\t * number of columns (although each index is generated only as it is\n\t\t * needed), and holds the data that is used for sorting each column in the\n\t\t * row. We do this cache generation at the start of the sort in order that\n\t\t * the formatting of the sort data need be done only once for each cell\n\t\t * per sort. This array should not be read from or written to by anything\n\t\t * other than the master sorting methods.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aSortData\": null,\n\t\n\t\t/**\n\t\t * Per cell filtering data cache. As per the sort data cache, used to\n\t\t * increase the performance of the filtering in DataTables\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aFilterData\": null,\n\t\n\t\t/**\n\t\t * Filtering data cache. This is the same as the cell filtering cache, but\n\t\t * in this case a string rather than an array. This is easily computed with\n\t\t * a join on `_aFilterData`, but is provided as a cache so the join isn't\n\t\t * needed on every search (memory traded for performance)\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sFilterRow\": null,\n\t\n\t\t/**\n\t\t * Cache of the class name that DataTables has applied to the row, so we\n\t\t * can quickly look at this variable rather than needing to do a DOM check\n\t\t * on className for the nTr property.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *  @private\n\t\t */\n\t\t\"_sRowStripe\": \"\",\n\t\n\t\t/**\n\t\t * Denote if the original data source was from the DOM, or the data source\n\t\t * object. This is used for invalidating data, so DataTables can\n\t\t * automatically read data from the original source, unless uninstructed\n\t\t * otherwise.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"src\": null,\n\t\n\t\t/**\n\t\t * Index in the aoData array. This saves an indexOf lookup when we have the\n\t\t * object, but want to know the index\n\t\t *  @type integer\n\t\t *  @default -1\n\t\t *  @private\n\t\t */\n\t\t\"idx\": -1\n\t};\n\t\n\t\n\t/**\n\t * Template object for the column information object in DataTables. This object\n\t * is held in the settings aoColumns array and contains all the information that\n\t * DataTables needs about each individual column.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults.column}\n\t * but this one is the internal data store for DataTables's cache of columns.\n\t * It should NOT be manipulated outside of DataTables. Any configuration should\n\t * be done through the initialisation options.\n\t *  @namespace\n\t */\n\tDataTable.models.oColumn = {\n\t\t/**\n\t\t * Column index. This could be worked out on-the-fly with $.inArray, but it\n\t\t * is faster to just hold it as a variable\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"idx\": null,\n\t\n\t\t/**\n\t\t * A list of the columns that sorting should occur on when this column\n\t\t * is sorted. That this property is an array allows multi-column sorting\n\t\t * to be defined for a column (for example first name / last name columns\n\t\t * would benefit from this). The values are integers pointing to the\n\t\t * columns to be sorted on (typically it will be a single integer pointing\n\t\t * at itself, but that doesn't need to be the case).\n\t\t *  @type array\n\t\t */\n\t\t\"aDataSort\": null,\n\t\n\t\t/**\n\t\t * Define the sorting directions that are applied to the column, in sequence\n\t\t * as the column is repeatedly sorted upon - i.e. the first value is used\n\t\t * as the sorting direction when the column if first sorted (clicked on).\n\t\t * Sort it again (click again) and it will move on to the next index.\n\t\t * Repeat until loop.\n\t\t *  @type array\n\t\t */\n\t\t\"asSorting\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is searchable, and thus should be included\n\t\t * in the filtering or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSearchable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is sortable or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is currently visible in the table or not\n\t\t *  @type boolean\n\t\t */\n\t\t\"bVisible\": null,\n\t\n\t\t/**\n\t\t * Store for manual type assignment using the `column.type` option. This\n\t\t * is held in store so we can manipulate the column's `sType` property.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sManualType\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if HTML5 data attributes should be used as the data\n\t\t * source for filtering or sorting. True is either are.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @private\n\t\t */\n\t\t\"_bAttrSrc\": false,\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} nTd The TD node that has been created\n\t\t *  @param {*} sData The Data for the cell\n\t\t *  @param {array|object} oData The data for the whole row\n\t\t *  @param {int} iRow The row index for the aoData data store\n\t\t *  @default null\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\t/**\n\t\t * Function to get data from a cell in a column. You should <b>never</b>\n\t\t * access data directly through _aData internally in DataTables - always use\n\t\t * the method attached to this property. It allows mData to function as\n\t\t * required. This function is automatically assigned by the column\n\t\t * initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {string} sSpecific The specific data type you want to get -\n\t\t *    'display', 'type' 'filter' 'sort'\n\t\t *  @returns {*} The data for the cell from the given row's data\n\t\t *  @default null\n\t\t */\n\t\t\"fnGetData\": null,\n\t\n\t\t/**\n\t\t * Function to set data for a cell in the column. You should <b>never</b>\n\t\t * set the data directly to _aData internally in DataTables - always use\n\t\t * this method. It allows mData to function as required. This function\n\t\t * is automatically assigned by the column initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {*} sValue Value to set\n\t\t *  @default null\n\t\t */\n\t\t\"fnSetData\": null,\n\t\n\t\t/**\n\t\t * Property to read the value for the cells in the column from the data\n\t\t * source array / object. If null, then the default content is used, if a\n\t\t * function is given then the return from the function is used.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\t/**\n\t\t * Partner property to mData which is used (only when defined) to get\n\t\t * the data - i.e. it is basically the same as mData, but without the\n\t\t * 'set' option, and also the data fed to it is the result from mData.\n\t\t * This is the rendering method to match the data method of mData.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\t/**\n\t\t * Unique header TH/TD element for this column - this is what the sorting\n\t\t * listener is attached to (if sorting is enabled.)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTh\": null,\n\t\n\t\t/**\n\t\t * Unique footer TH/TD element for this column (if there is one). Not used\n\t\t * in DataTables as such, but can be used for plug-ins to reference the\n\t\t * footer for each column.\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTf\": null,\n\t\n\t\t/**\n\t\t * The class to apply to all TD elements in the table's TBODY for the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sClass\": null,\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t *  @type string\n\t\t */\n\t\t\"sContentPadding\": null,\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because mData\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\t/**\n\t\t * Name for the column, allowing reference to the column by name as well as\n\t\t * by index (needs a lookup to work by name).\n\t\t *  @type string\n\t\t */\n\t\t\"sName\": null,\n\t\n\t\t/**\n\t\t * Custom sorting data type - defines which of the available plug-ins in\n\t\t * afnSortData the custom sorting will use - if any is defined.\n\t\t *  @type string\n\t\t *  @default std\n\t\t */\n\t\t\"sSortDataType\": 'std',\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClass\": null,\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column -\n\t\t * when jQuery UI theming is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClassJUI\": null,\n\t\n\t\t/**\n\t\t * Title of the column - what is seen in the TH element (nTh).\n\t\t *  @type string\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\t/**\n\t\t * Column sorting and filtering type\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\t/**\n\t\t * Width of the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidth\": null,\n\t\n\t\t/**\n\t\t * Width of the column when it was first \"encountered\"\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidthOrig\": null\n\t};\n\t\n\t\n\t/*\n\t * Developer note: The properties of the object below are given in Hungarian\n\t * notation, that was used as the interface for DataTables prior to v1.10, however\n\t * from v1.10 onwards the primary interface is camel case. In order to avoid\n\t * breaking backwards compatibility utterly with this change, the Hungarian\n\t * version is still, internally the primary interface, but is is not documented\n\t * - hence the @name tags in each doc comment. This allows a Javascript function\n\t * to create a map from Hungarian notation to camel case (going the other direction\n\t * would require each property to be listed, which would at around 3K to the size\n\t * of DataTables, while this method is about a 0.5K hit.\n\t *\n\t * Ultimately this does pave the way for Hungarian notation to be dropped\n\t * completely, but that is a massive amount of work and will break current\n\t * installs (therefore is on-hold until v2).\n\t */\n\t\n\t/**\n\t * Initialisation options that can be given to DataTables at initialisation\n\t * time.\n\t *  @namespace\n\t */\n\tDataTable.defaults = {\n\t\t/**\n\t\t * An array of data to use for the table, passed in at initialisation which\n\t\t * will be used in preference to any data which is already in the DOM. This is\n\t\t * particularly useful for constructing tables purely in Javascript, for\n\t\t * example with a custom Ajax call.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.data\n\t\t *\n\t\t *  @example\n\t\t *    // Using a 2D array data source\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],\n\t\t *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\" },\n\t\t *          { \"title\": \"Browser\" },\n\t\t *          { \"title\": \"Platform\" },\n\t\t *          { \"title\": \"Version\" },\n\t\t *          { \"title\": \"Grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using an array of objects as a data source (`data`)\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 4.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  4,\n\t\t *            \"grade\":    \"X\"\n\t\t *          },\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 5.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  5,\n\t\t *            \"grade\":    \"C\"\n\t\t *          }\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\",   \"data\": \"engine\" },\n\t\t *          { \"title\": \"Browser\",  \"data\": \"browser\" },\n\t\t *          { \"title\": \"Platform\", \"data\": \"platform\" },\n\t\t *          { \"title\": \"Version\",  \"data\": \"version\" },\n\t\t *          { \"title\": \"Grade\",    \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaData\": null,\n\t\n\t\n\t\t/**\n\t\t * If ordering is enabled, then DataTables will perform a first pass sort on\n\t\t * initialisation. You can define which column(s) the sort is performed\n\t\t * upon, and the sorting direction, with this variable. The `sorting` array\n\t\t * should contain an array for each column to be sorted initially containing\n\t\t * the column's index and a direction string ('asc' or 'desc').\n\t\t *  @type array\n\t\t *  @default [[0,'asc']]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.order\n\t\t *\n\t\t *  @example\n\t\t *    // Sort by 3rd column first, and then 4th column\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": [[2,'asc'], [3,'desc']]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *    // No initial sorting\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": []\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaSorting\": [[0,'asc']],\n\t\n\t\n\t\t/**\n\t\t * This parameter is basically identical to the `sorting` parameter, but\n\t\t * cannot be overridden by user interaction with the table. What this means\n\t\t * is that you could have a column (visible or hidden) which the sorting\n\t\t * will always be forced on first - any sorting after that (from the user)\n\t\t * will then be performed as required. This can be useful for grouping rows\n\t\t * together.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.orderFixed\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderFixed\": [[0,'asc']]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\n\t\t/**\n\t\t * DataTables can be instructed to load data to display in the table from a\n\t\t * Ajax source. This option defines how that Ajax call is made and where to.\n\t\t *\n\t\t * The `ajax` property has three different modes of operation, depending on\n\t\t * how it is defined. These are:\n\t\t *\n\t\t * * `string` - Set the URL from where the data should be loaded from.\n\t\t * * `object` - Define properties for `jQuery.ajax`.\n\t\t * * `function` - Custom data get function\n\t\t *\n\t\t * `string`\n\t\t * --------\n\t\t *\n\t\t * As a string, the `ajax` property simply defines the URL from which\n\t\t * DataTables will load data.\n\t\t *\n\t\t * `object`\n\t\t * --------\n\t\t *\n\t\t * As an object, the parameters in the object are passed to\n\t\t * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control\n\t\t * of the Ajax request. DataTables has a number of default parameters which\n\t\t * you can override using this option. Please refer to the jQuery\n\t\t * documentation for a full description of the options available, although\n\t\t * the following parameters provide additional options in DataTables or\n\t\t * require special consideration:\n\t\t *\n\t\t * * `data` - As with jQuery, `data` can be provided as an object, but it\n\t\t *   can also be used as a function to manipulate the data DataTables sends\n\t\t *   to the server. The function takes a single parameter, an object of\n\t\t *   parameters with the values that DataTables has readied for sending. An\n\t\t *   object may be returned which will be merged into the DataTables\n\t\t *   defaults, or you can add the items to the object that was passed in and\n\t\t *   not return anything from the function. This supersedes `fnServerParams`\n\t\t *   from DataTables 1.9-.\n\t\t *\n\t\t * * `dataSrc` - By default DataTables will look for the property `data` (or\n\t\t *   `aaData` for compatibility with DataTables 1.9-) when obtaining data\n\t\t *   from an Ajax source or for server-side processing - this parameter\n\t\t *   allows that property to be changed. You can use Javascript dotted\n\t\t *   object notation to get a data source for multiple levels of nesting, or\n\t\t *   it my be used as a function. As a function it takes a single parameter,\n\t\t *   the JSON returned from the server, which can be manipulated as\n\t\t *   required, with the returned value being that used by DataTables as the\n\t\t *   data source for the table. This supersedes `sAjaxDataProp` from\n\t\t *   DataTables 1.9-.\n\t\t *\n\t\t * * `success` - Should not be overridden it is used internally in\n\t\t *   DataTables. To manipulate / transform the data returned by the server\n\t\t *   use `ajax.dataSrc`, or use `ajax` as a function (see below).\n\t\t *\n\t\t * `function`\n\t\t * ----------\n\t\t *\n\t\t * As a function, making the Ajax call is left up to yourself allowing\n\t\t * complete control of the Ajax request. Indeed, if desired, a method other\n\t\t * than Ajax could be used to obtain the required data, such as Web storage\n\t\t * or an AIR database.\n\t\t *\n\t\t * The function is given four parameters and no return is required. The\n\t\t * parameters are:\n\t\t *\n\t\t * 1. _object_ - Data to send to the server\n\t\t * 2. _function_ - Callback function that must be executed when the required\n\t\t *    data has been obtained. That data should be passed into the callback\n\t\t *    as the only parameter\n\t\t * 3. _object_ - DataTables settings object for the table\n\t\t *\n\t\t * Note that this supersedes `fnServerData` from DataTables 1.9-.\n\t\t *\n\t\t *  @type string|object|function\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.ajax\n\t\t *  @since 1.10.0\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax.\n\t\t *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": \"data.json\"\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to change\n\t\t *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"tableData\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to read data\n\t\t *   // from a plain array rather than an array in an object\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Manipulate the data returned from the server - add a link to data\n\t\t *   // (note this can, should, be done using `render` for the column - this\n\t\t *   // is just a simple example of how the data can be manipulated).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": function ( json ) {\n\t\t *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {\n\t\t *           json[i][0] = '<a href=\"/message/'+json[i][0]+'>View message</a>';\n\t\t *         }\n\t\t *         return json;\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Add data to the request\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"data\": function ( d ) {\n\t\t *         return {\n\t\t *           \"extra_search\": $('#extra').val()\n\t\t *         };\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Send request as POST\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"type\": \"POST\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get the data from localStorage (could interface with a form for\n\t\t *   // adding, editing and removing rows).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": function (data, callback, settings) {\n\t\t *       callback(\n\t\t *         JSON.parse( localStorage.getItem('dataTablesData') )\n\t\t *       );\n\t\t *     }\n\t\t *   } );\n\t\t */\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to readily specify the entries in the length drop\n\t\t * down menu that DataTables shows when pagination is enabled. It can be\n\t\t * either a 1D array of options which will be used for both the displayed\n\t\t * option and the value, or a 2D array which will use the array in the first\n\t\t * position as the value, and the array in the second position as the\n\t\t * displayed options (useful for language strings such as 'All').\n\t\t *\n\t\t * Note that the `pageLength` property will be automatically set to the\n\t\t * first value given in this array, unless `pageLength` is also provided.\n\t\t *  @type array\n\t\t *  @default [ 10, 25, 50, 100 ]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.lengthMenu\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthMenu\": [[10, 25, 50, -1], [10, 25, 50, \"All\"]]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aLengthMenu\": [ 10, 25, 50, 100 ],\n\t\n\t\n\t\t/**\n\t\t * The `columns` option in the initialisation parameter allows you to define\n\t\t * details about the way individual columns behave. For a full list of\n\t\t * column options that can be set, please see\n\t\t * {@link DataTable.defaults.column}. Note that if you use `columns` to\n\t\t * define your columns, you must have an entry in the array for every single\n\t\t * column that you have in your table (these can be null if you don't which\n\t\t * to specify any options).\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.column\n\t\t */\n\t\t\"aoColumns\": null,\n\t\n\t\t/**\n\t\t * Very similar to `columns`, `columnDefs` allows you to target a specific\n\t\t * column, multiple columns, or all columns, using the `targets` property of\n\t\t * each object in the array. This allows great flexibility when creating\n\t\t * tables, as the `columnDefs` arrays can be of any length, targeting the\n\t\t * columns you specifically want. `columnDefs` may use any of the column\n\t\t * options available: {@link DataTable.defaults.column}, but it _must_\n\t\t * have `targets` defined in each object in the array. Values in the `targets`\n\t\t * array may be:\n\t\t *   <ul>\n\t\t *     <li>a string - class name will be matched on the TH for the column</li>\n\t\t *     <li>0 or a positive integer - column index counting from the left</li>\n\t\t *     <li>a negative integer - column index counting from the right</li>\n\t\t *     <li>the string \"_all\" - all columns (i.e. assign a default)</li>\n\t\t *   </ul>\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.columnDefs\n\t\t */\n\t\t\"aoColumnDefs\": null,\n\t\n\t\n\t\t/**\n\t\t * Basically the same as `search`, this parameter defines the individual column\n\t\t * filtering state at initialisation time. The array must be of the same size\n\t\t * as the number of columns, and each element be an object with the parameters\n\t\t * `search` and `escapeRegex` (the latter is optional). 'null' is also\n\t\t * accepted and the default will be used.\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.searchCols\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchCols\": [\n\t\t *          null,\n\t\t *          { \"search\": \"My filter\" },\n\t\t *          null,\n\t\t *          { \"search\": \"^[0-9]\", \"escapeRegex\": false }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aoSearchCols\": [],\n\t\n\t\n\t\t/**\n\t\t * An array of CSS classes that should be applied to displayed rows. This\n\t\t * array may be of any length, and DataTables will apply each class\n\t\t * sequentially, looping when required.\n\t\t *  @type array\n\t\t *  @default null <i>Will take the values determined by the `oClasses.stripe*`\n\t\t *    options</i>\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.stripeClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stripeClasses\": [ 'strip1', 'strip2', 'strip3' ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable automatic column width calculation. This can be disabled\n\t\t * as an optimisation (it takes some time to calculate the widths) if the\n\t\t * tables widths are passed in using `columns`.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.autoWidth\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"autoWidth\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bAutoWidth\": true,\n\t\n\t\n\t\t/**\n\t\t * Deferred rendering can provide DataTables with a huge speed boost when you\n\t\t * are using an Ajax or JS data source for the table. This option, when set to\n\t\t * true, will cause DataTables to defer the creation of the table elements for\n\t\t * each row until they are needed for a draw - saving a significant amount of\n\t\t * time.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.deferRender\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajax\": \"sources/arrays.txt\",\n\t\t *        \"deferRender\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDeferRender\": false,\n\t\n\t\n\t\t/**\n\t\t * Replace a DataTable which matches the given selector and replace it with\n\t\t * one which has the properties of the new initialisation object passed. If no\n\t\t * table matches the selector, then the new DataTable will be constructed as\n\t\t * per normal.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.destroy\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"srollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      // Some time later....\n\t\t *      $('#example').dataTable( {\n\t\t *        \"filter\": false,\n\t\t *        \"destroy\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDestroy\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering of data. Filtering in DataTables is \"smart\" in\n\t\t * that it allows the end user to input multiple words (space separated) and\n\t\t * will match a row containing those words, even if not in the order that was\n\t\t * specified (this allow matching across multiple columns). Note that if you\n\t\t * wish to use filtering in DataTables this must remain 'true' - to remove the\n\t\t * default filtering input box and retain filtering abilities, please use\n\t\t * {@link DataTable.defaults.dom}.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.searching\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searching\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bFilter\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the table information display. This shows information\n\t\t * about the data that is currently visible on the page, including information\n\t\t * about filtered data if that action is being performed.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.info\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"info\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bInfo\": true,\n\t\n\t\n\t\t/**\n\t\t * Allows the end user to select the size of a formatted page from a select\n\t\t * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.lengthChange\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthChange\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bLengthChange\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable pagination.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.paging\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"paging\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bPaginate\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of a 'processing' indicator when the table is\n\t\t * being processed (e.g. a sort). This is particularly useful for tables with\n\t\t * large amounts of data where it can take a noticeable amount of time to sort\n\t\t * the entries.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.processing\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"processing\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bProcessing\": false,\n\t\n\t\n\t\t/**\n\t\t * Retrieve the DataTables object for the given selector. Note that if the\n\t\t * table has already been initialised, this parameter will cause DataTables\n\t\t * to simply return the object that has already been set up - it will not take\n\t\t * account of any changes you might have made to the initialisation object\n\t\t * passed to DataTables (setting this parameter to true is an acknowledgement\n\t\t * that you understand this). `destroy` can be used to reinitialise a table if\n\t\t * you need.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.retrieve\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      initTable();\n\t\t *      tableActions();\n\t\t *    } );\n\t\t *\n\t\t *    function initTable ()\n\t\t *    {\n\t\t *      return $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false,\n\t\t *        \"retrieve\": true\n\t\t *      } );\n\t\t *    }\n\t\t *\n\t\t *    function tableActions ()\n\t\t *    {\n\t\t *      var table = initTable();\n\t\t *      // perform API operations with oTable\n\t\t *    }\n\t\t */\n\t\t\"bRetrieve\": false,\n\t\n\t\n\t\t/**\n\t\t * When vertical (y) scrolling is enabled, DataTables will force the height of\n\t\t * the table's viewport to the given height at all times (useful for layout).\n\t\t * However, this can look odd when filtering data down to a small data set,\n\t\t * and the footer is left \"floating\" further down. This parameter (when\n\t\t * enabled) will cause DataTables to collapse the table's viewport down when\n\t\t * the result set will fit within the given Y height.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollCollapse\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200\",\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bScrollCollapse\": false,\n\t\n\t\n\t\t/**\n\t\t * Configure DataTables to use server-side processing. Note that the\n\t\t * `ajax` parameter must also be given in order to give DataTables a\n\t\t * source to obtain the required data for each draw.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverSide\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"xhr.php\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bServerSide\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable sorting of columns. Sorting of individual columns can be\n\t\t * disabled by the `sortable` option for each column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.ordering\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ordering\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSort\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or display DataTables' ability to sort multiple columns at the\n\t\t * same time (activated by shift-click by the user).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderMulti\n\t\t *\n\t\t *  @example\n\t\t *    // Disable multiple column sorting ability\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderMulti\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortMulti\": true,\n\t\n\t\n\t\t/**\n\t\t * Allows control over whether DataTables should use the top (true) unique\n\t\t * cell that is found for a single column, or the bottom (false - default).\n\t\t * This is useful when using complex headers.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderCellsTop\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderCellsTop\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortCellsTop\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the addition of the classes `sorting\\_1`, `sorting\\_2` and\n\t\t * `sorting\\_3` to the columns which are currently being sorted on. This is\n\t\t * presented as a feature switch as it can increase processing time (while\n\t\t * classes are removed and added) so for large data sets you might want to\n\t\t * turn this off.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.orderClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderClasses\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortClasses\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable state saving. When enabled HTML5 `localStorage` will be\n\t\t * used to save table display information such as pagination information,\n\t\t * display length, filtering and sorting. As such when the end user reloads\n\t\t * the page the display display will match what thy had previously set up.\n\t\t *\n\t\t * Due to the use of `localStorage` the default state saving is not supported\n\t\t * in IE6 or 7. If state saving is required in those browsers, use\n\t\t * `stateSaveCallback` to provide a storage solution such as cookies.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.stateSave\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bStateSave\": false,\n\t\n\t\n\t\t/**\n\t\t * This function is called when a TR element is created (and all TD child\n\t\t * elements have been inserted), or registered if using a DOM source, allowing\n\t\t * manipulation of the TR element (adding classes etc).\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} dataIndex The index of this row in the internal aoData array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.createdRow\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"createdRow\": function( row, data, dataIndex ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" )\n\t\t *          {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedRow\": null,\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify any aspect you want about the created DOM.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.drawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"drawCallback\": function( settings ) {\n\t\t *          alert( 'DataTables has redrawn the table' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Identical to fnHeaderCallback() but for the table footer this function\n\t\t * allows you to modify the table footer on every 'draw' event.\n\t\t *  @type function\n\t\t *  @param {node} foot \"TR\" element for the footer\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.footerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"footerCallback\": function( tfoot, data, start, end, display ) {\n\t\t *          tfoot.getElementsByTagName('th')[0].innerHTML = \"Starting index is \"+start;\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnFooterCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * When rendering large numbers in the information element for the table\n\t\t * (i.e. \"Showing 1 to 10 of 57 entries\") DataTables will render large numbers\n\t\t * to have a comma separator for the 'thousands' units (e.g. 1 million is\n\t\t * rendered as \"1,000,000\") to help readability for the end user. This\n\t\t * function will override the default method DataTables uses.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {int} toFormat number to be formatted\n\t\t *  @returns {string} formatted string for DataTables to show the number\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.formatNumber\n\t\t *\n\t\t *  @example\n\t\t *    // Format a number using a single quote for the separator (note that\n\t\t *    // this can also be done with the language.thousands option)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"formatNumber\": function ( toFormat ) {\n\t\t *          return toFormat.toString().replace(\n\t\t *            /\\B(?=(\\d{3})+(?!\\d))/g, \"'\"\n\t\t *          );\n\t\t *        };\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnFormatNumber\": function ( toFormat ) {\n\t\t\treturn toFormat.toString().replace(\n\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g,\n\t\t\t\tthis.oLanguage.sThousands\n\t\t\t);\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify the header row. This can be used to calculate and\n\t\t * display useful information about the table.\n\t\t *  @type function\n\t\t *  @param {node} head \"TR\" element for the header\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.headerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"fheaderCallback\": function( head, data, start, end, display ) {\n\t\t *          head.getElementsByTagName('th')[0].innerHTML = \"Displaying \"+(end-start)+\" records\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnHeaderCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * The information element can be used to convey information about the current\n\t\t * state of the table. Although the internationalisation options presented by\n\t\t * DataTables are quite capable of dealing with most customisations, there may\n\t\t * be times where you wish to customise the string further. This callback\n\t\t * allows you to do exactly that.\n\t\t *  @type function\n\t\t *  @param {object} oSettings DataTables settings object\n\t\t *  @param {int} start Starting position in data for the draw\n\t\t *  @param {int} end End position in data for the draw\n\t\t *  @param {int} max Total number of rows in the table (regardless of\n\t\t *    filtering)\n\t\t *  @param {int} total Total number of rows in the data set, after filtering\n\t\t *  @param {string} pre The string that DataTables has formatted using it's\n\t\t *    own rules\n\t\t *  @returns {string} The string to be displayed in the information element.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.infoCallback\n\t\t *\n\t\t *  @example\n\t\t *    $('#example').dataTable( {\n\t\t *      \"infoCallback\": function( settings, start, end, max, total, pre ) {\n\t\t *        return start +\" to \"+ end;\n\t\t *      }\n\t\t *    } );\n\t\t */\n\t\t\"fnInfoCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Called when the table has been initialised. Normally DataTables will\n\t\t * initialise sequentially and there will be no need for this function,\n\t\t * however, this does not hold true when using external language information\n\t\t * since that is obtained using an async XHR call.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} json The JSON object request from the server - only\n\t\t *    present if client-side Ajax sourced data is used\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.initComplete\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"initComplete\": function(settings, json) {\n\t\t *          alert( 'DataTables has finished its initialisation.' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnInitComplete\": null,\n\t\n\t\n\t\t/**\n\t\t * Called at the very start of each table draw and can be used to cancel the\n\t\t * draw by returning false, any other return (including undefined) results in\n\t\t * the full draw occurring).\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @returns {boolean} False will cancel the draw, anything else (including no\n\t\t *    return) will allow it to complete.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.preDrawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"preDrawCallback\": function( settings ) {\n\t\t *          if ( $('#test').val() == 1 ) {\n\t\t *            return false;\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnPreDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * This function allows you to 'post process' each row after it have been\n\t\t * generated for each table draw, but before it is rendered on screen. This\n\t\t * function might be used for setting the row class name etc.\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} displayIndex The display index for the current table draw\n\t\t *  @param {int} displayIndexFull The index of the data in the full list of\n\t\t *    rows (after filtering)\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.rowCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"rowCallback\": function( row, data, displayIndex, displayIndexFull ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" ) {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnRowCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * This parameter allows you to override the default function which obtains\n\t\t * the data from the server so something more suitable for your application.\n\t\t * For example you could use POST data, or pull information from a Gears or\n\t\t * AIR database.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {string} source HTTP source to obtain the data from (`ajax`)\n\t\t *  @param {array} data A key/value pair object containing the data to send\n\t\t *    to the server\n\t\t *  @param {function} callback to be called on completion of the data get\n\t\t *    process that will draw the data on the page.\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverData\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t *  It is often useful to send extra data to the server when making an Ajax\n\t\t * request - for example custom filtering information, and this callback\n\t\t * function makes it trivial to send extra information to the server. The\n\t\t * passed in parameter is the data set that has been constructed by\n\t\t * DataTables, and you can add to this or modify it as you require.\n\t\t *  @type function\n\t\t *  @param {array} data Data array (array of objects which are name/value\n\t\t *    pairs) that has been constructed by DataTables and will be sent to the\n\t\t *    server. In the case of Ajax sourced data with server-side processing\n\t\t *    this will be an empty array, for server-side processing there will be a\n\t\t *    significant number of parameters!\n\t\t *  @returns {undefined} Ensure that you modify the data array passed in,\n\t\t *    as this is passed by reference.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverParams\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Load the table state. With this function you can define from where, and how, the\n\t\t * state of a table is loaded. By default DataTables will load from `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} callback Callback that can be executed when done. It\n\t\t *    should be passed the loaded state object.\n\t\t *  @return {object} The DataTables state object to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadCallback\": function (settings, callback) {\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_load\",\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"success\": function (json) {\n\t\t *              callback( json );\n\t\t *            }\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadCallback\": function ( settings ) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(\n\t\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(\n\t\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the saved state prior to loading that state.\n\t\t * This callback is called when the table is loading state from the stored data, but\n\t\t * prior to the settings object being modified by the saved state. Note that for\n\t\t * plug-in authors, you should use the `stateLoadParams` event to load parameters for\n\t\t * a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that is to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never loaded\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Disallow state loading by returning false\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          return false;\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Callback that is called when the state has been loaded from the state saving method\n\t\t * and the DataTables settings object has been modified as a result of the loaded state.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that was loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoaded\n\t\t *\n\t\t *  @example\n\t\t *    // Show an alert with the filtering value that was saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoaded\": function (settings, data) {\n\t\t *          alert( 'Saved filter was: '+data.oSearch.sSearch );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoaded\": null,\n\t\n\t\n\t\t/**\n\t\t * Save the table state. This function allows you to define where and how the state\n\t\t * information for the table is stored By default DataTables will use `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveCallback\": function (settings, data) {\n\t\t *          // Send an Ajax request to the server with the state object\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_save\",\n\t\t *            \"data\": data,\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"method\": \"POST\"\n\t\t *            \"success\": function () {}\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveCallback\": function ( settings, data ) {\n\t\t\ttry {\n\t\t\t\t(settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(\n\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+location.pathname,\n\t\t\t\t\tJSON.stringify( data )\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the state to be saved. Called when the table\n\t\t * has changed state a new state save is required. This method allows modification of\n\t\t * the state saving object prior to actually doing the save, including addition or\n\t\t * other state properties or modification. Note that for plug-in authors, you should\n\t\t * use the `stateSaveParams` event to save parameters for a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Duration for which the saved state information is considered valid. After this period\n\t\t * has elapsed the state will be returned to the default.\n\t\t * Value is given in seconds.\n\t\t *  @type int\n\t\t *  @default 7200 <i>(2 hours)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.stateDuration\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateDuration\": 60*60*24; // 1 day\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iStateDuration\": 7200,\n\t\n\t\n\t\t/**\n\t\t * When enabled DataTables will not make a request to the server for the first\n\t\t * page draw - rather it will use the data already on the page (no sorting etc\n\t\t * will be applied to it), thus saving on an XHR at load time. `deferLoading`\n\t\t * is used to indicate that deferred loading is required, but it is also used\n\t\t * to tell DataTables how many records there are in the full table (allowing\n\t\t * the information element and pagination to be displayed correctly). In the case\n\t\t * where a filtering is applied to the table on initial load, this can be\n\t\t * indicated by giving the parameter as an array, where the first element is\n\t\t * the number of records available after filtering and the second element is the\n\t\t * number of records without filtering (allowing the table information element\n\t\t * to be shown correctly).\n\t\t *  @type int | array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.deferLoading\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records available in the table, no filtering applied\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": 57\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records after filtering, 100 without filtering (an initial filter applied)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": [ 57, 100 ],\n\t\t *        \"search\": {\n\t\t *          \"search\": \"my_filter\"\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iDeferLoading\": null,\n\t\n\t\n\t\t/**\n\t\t * Number of rows to display on a single page when using pagination. If\n\t\t * feature enabled (`lengthChange`) then the end user will be able to override\n\t\t * this to a custom setting using a pop-up menu.\n\t\t *  @type int\n\t\t *  @default 10\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pageLength\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pageLength\": 50\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayLength\": 10,\n\t\n\t\n\t\t/**\n\t\t * Define the starting point for data display when using DataTables with\n\t\t * pagination. Note that this parameter is the number of records, rather than\n\t\t * the page number, so if you have 10 records per page and want to start on\n\t\t * the third page, it should be \"20\".\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.displayStart\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"displayStart\": 20\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayStart\": 0,\n\t\n\t\n\t\t/**\n\t\t * By default DataTables allows keyboard navigation of the table (sorting, paging,\n\t\t * and filtering) by adding a `tabindex` attribute to the required elements. This\n\t\t * allows you to tab through the controls and press the enter key to activate them.\n\t\t * The tabindex is default 0, meaning that the tab follows the flow of the document.\n\t\t * You can overrule this using this parameter if you wish. Use a value of -1 to\n\t\t * disable built-in keyboard navigation.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.tabIndex\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"tabIndex\": 1\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\n\t\t/**\n\t\t * Classes that DataTables assigns to the various components and features\n\t\t * that it adds to the HTML table. This allows classes to be configured\n\t\t * during initialisation in addition to through the static\n\t\t * {@link DataTable.ext.oStdClasses} object).\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.classes\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\n\t\t/**\n\t\t * All strings that DataTables uses in the user interface that it creates\n\t\t * are defined in this object, allowing you to modified them individually or\n\t\t * completely replace them all as required.\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.language\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Strings that are used for WAI-ARIA labels and controls only (these are not\n\t\t\t * actually visible on the page, but will be read by screenreaders, and thus\n\t\t\t * must be internationalised as well).\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.aria\n\t\t\t */\n\t\t\t\"oAria\": {\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted ascending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortAscending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortAscending\": \" - click/return to sort ascending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortAscending\": \": activate to sort column ascending\",\n\t\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted descending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortDescending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortDescending\": \" - click/return to sort descending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortDescending\": \": activate to sort column descending\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * Pagination string used by DataTables for the built-in pagination\n\t\t\t * control types.\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.paginate\n\t\t\t */\n\t\t\t\"oPaginate\": {\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the first page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default First\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.first\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"first\": \"First page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sFirst\": \"First\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the last page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Last\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.last\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"last\": \"Last page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sLast\": \"Last\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'next' pagination button (to take the user to the\n\t\t\t\t * next page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Next\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.next\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"next\": \"Next page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sNext\": \"Next\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'previous' pagination button (to take the user to\n\t\t\t\t * the previous page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Previous\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.previous\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"previous\": \"Previous page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sPrevious\": \"Previous\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * This string is shown in preference to `zeroRecords` when the table is\n\t\t\t * empty of data (regardless of filtering). Note that this is an optional\n\t\t\t * parameter - if it is not given, the value of `zeroRecords` will be used\n\t\t\t * instead (either the default or given value).\n\t\t\t *  @type string\n\t\t\t *  @default No data available in table\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.emptyTable\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"emptyTable\": \"No data available in table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sEmptyTable\": \"No data available in table\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This string gives information to the end user about the information\n\t\t\t * that is current on display on the page. The following tokens can be\n\t\t\t * used in the string and will be dynamically replaced as the table\n\t\t\t * display updates. This tokens can be placed anywhere in the string, or\n\t\t\t * removed as needed by the language requires:\n\t\t\t *\n\t\t\t * * `\\_START\\_` - Display index of the first record on the current page\n\t\t\t * * `\\_END\\_` - Display index of the last record on the current page\n\t\t\t * * `\\_TOTAL\\_` - Number of records in the table after filtering\n\t\t\t * * `\\_MAX\\_` - Number of records in the table without filtering\n\t\t\t * * `\\_PAGE\\_` - Current page number\n\t\t\t * * `\\_PAGES\\_` - Total number of pages of data in the table\n\t\t\t *\n\t\t\t *  @type string\n\t\t\t *  @default Showing _START_ to _END_ of _TOTAL_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.info\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"info\": \"Showing page _PAGE_ of _PAGES_\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfo\": \"Showing _START_ to _END_ of _TOTAL_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Display information string for when the table is empty. Typically the\n\t\t\t * format of this string should match `info`.\n\t\t\t *  @type string\n\t\t\t *  @default Showing 0 to 0 of 0 entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoEmpty\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoEmpty\": \"No entries to show\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoEmpty\": \"Showing 0 to 0 of 0 entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When a user filters the information in a table, this string is appended\n\t\t\t * to the information (`info`) to give an idea of how strong the filtering\n\t\t\t * is. The variable _MAX_ is dynamically updated.\n\t\t\t *  @type string\n\t\t\t *  @default (filtered from _MAX_ total entries)\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoFiltered\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoFiltered\": \" - filtering from _MAX_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoFiltered\": \"(filtered from _MAX_ total entries)\",\n\t\n\t\n\t\t\t/**\n\t\t\t * If can be useful to append extra information to the info string at times,\n\t\t\t * and this variable does exactly that. This information will be appended to\n\t\t\t * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are\n\t\t\t * being used) at all times.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoPostFix\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoPostFix\": \"All records shown are derived from real information.\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoPostFix\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This decimal place operator is a little different from the other\n\t\t\t * language options since DataTables doesn't output floating point\n\t\t\t * numbers, so it won't ever use this for display of a number. Rather,\n\t\t\t * what this parameter does is modify the sort methods of the table so\n\t\t\t * that numbers which are in a format which has a character other than\n\t\t\t * a period (`.`) as a decimal place will be sorted numerically.\n\t\t\t *\n\t\t\t * Note that numbers with different decimal places cannot be shown in\n\t\t\t * the same table and still be sortable, the table must be consistent.\n\t\t\t * However, multiple different tables on the page can use different\n\t\t\t * decimal place characters.\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.decimal\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"decimal\": \",\"\n\t\t\t *          \"thousands\": \".\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sDecimal\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * DataTables has a build in number formatter (`formatNumber`) which is\n\t\t\t * used to format large numbers that are used in the table information.\n\t\t\t * By default a comma is used, but this can be trivially changed to any\n\t\t\t * character you wish with this parameter.\n\t\t\t *  @type string\n\t\t\t *  @default ,\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.thousands\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"thousands\": \"'\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sThousands\": \",\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Detail the action that will be taken when the drop down menu for the\n\t\t\t * pagination length option is changed. The '_MENU_' variable is replaced\n\t\t\t * with a default select list of 10, 25, 50 and 100, and can be replaced\n\t\t\t * with a custom select box if required.\n\t\t\t *  @type string\n\t\t\t *  @default Show _MENU_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.lengthMenu\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language change only\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": \"Display _MENU_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language and options change\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": 'Display <select>'+\n\t\t\t *            '<option value=\"10\">10</option>'+\n\t\t\t *            '<option value=\"20\">20</option>'+\n\t\t\t *            '<option value=\"30\">30</option>'+\n\t\t\t *            '<option value=\"40\">40</option>'+\n\t\t\t *            '<option value=\"50\">50</option>'+\n\t\t\t *            '<option value=\"-1\">All</option>'+\n\t\t\t *            '</select> records'\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLengthMenu\": \"Show _MENU_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When using Ajax sourced data and during the first draw when DataTables is\n\t\t\t * gathering the data, this message is shown in an empty row in the table to\n\t\t\t * indicate to the end user the the data is being loaded. Note that this\n\t\t\t * parameter is not used when loading data by server-side processing, just\n\t\t\t * Ajax sourced data with client-side processing.\n\t\t\t *  @type string\n\t\t\t *  @default Loading...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.loadingRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"loadingRecords\": \"Please wait - loading...\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLoadingRecords\": \"Loading...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text which is displayed when the table is processing a user action\n\t\t\t * (usually a sort command or similar).\n\t\t\t *  @type string\n\t\t\t *  @default Processing...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.processing\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"processing\": \"DataTables is currently busy\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sProcessing\": \"Processing...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Details the actions that will be taken when the user types into the\n\t\t\t * filtering input text box. The variable \"_INPUT_\", if used in the string,\n\t\t\t * is replaced with the HTML text box for the filtering input allowing\n\t\t\t * control over where it appears in the string. If \"_INPUT_\" is not given\n\t\t\t * then the input box is appended to the string automatically.\n\t\t\t *  @type string\n\t\t\t *  @default Search:\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.search\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Input text box will be appended at the end automatically\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Filter records:\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Specify where the filter should appear\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Apply filter _INPUT_ to table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sSearch\": \"Search:\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Assign a `placeholder` attribute to the search `input` element\n\t\t\t *  @type string\n\t\t\t *  @default \n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.searchPlaceholder\n\t\t\t */\n\t\t\t\"sSearchPlaceholder\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * All of the language information can be stored in a file on the\n\t\t\t * server-side, which DataTables will look up if this parameter is passed.\n\t\t\t * It must store the URL of the language file, which is in a JSON format,\n\t\t\t * and the object has the same properties as the oLanguage object in the\n\t\t\t * initialiser object (i.e. the above parameters). Please refer to one of\n\t\t\t * the example language files to see how this works in action.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string - i.e. disabled</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.url\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"url\": \"http://www.sprymedia.co.uk/dataTables/lang.txt\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sUrl\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text shown inside the table records when the is no information to be\n\t\t\t * displayed after filtering. `emptyTable` is shown when there is simply no\n\t\t\t * information in the table at all (regardless of filtering).\n\t\t\t *  @type string\n\t\t\t *  @default No matching records found\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.zeroRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"zeroRecords\": \"No records to display\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sZeroRecords\": \"No matching records found\"\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to have define the global filtering state at\n\t\t * initialisation time. As an object the `search` parameter must be\n\t\t * defined, but all other parameters are optional. When `regex` is true,\n\t\t * the search string will be treated as a regular expression, when false\n\t\t * (default) it will be treated as a straight string. When `smart`\n\t\t * DataTables will use it's smart filtering methods (to word match at\n\t\t * any point in the data), when false this will not be done.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.search\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"search\": {\"search\": \"Initial search\"}\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"oSearch\": $.extend( {}, DataTable.models.oSearch ),\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * By default DataTables will look for the property `data` (or `aaData` for\n\t\t * compatibility with DataTables 1.9-) when obtaining data from an Ajax\n\t\t * source or for server-side processing - this parameter allows that\n\t\t * property to be changed. You can use Javascript dotted object notation to\n\t\t * get a data source for multiple levels of nesting.\n\t\t *  @type string\n\t\t *  @default data\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxDataProp\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxDataProp\": \"data\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * You can instruct DataTables to load data from an external\n\t\t * source using this parameter (use aData if you want to pass data in you\n\t\t * already have). Simply provide a url a JSON object can be obtained from.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxSource\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\n\t\t/**\n\t\t * This initialisation variable allows you to specify exactly where in the\n\t\t * DOM you want DataTables to inject the various controls it adds to the page\n\t\t * (for example you might want the pagination controls at the top of the\n\t\t * table). DIV elements (with or without a custom class) can also be added to\n\t\t * aid styling. The follow syntax is used:\n\t\t *   <ul>\n\t\t *     <li>The following options are allowed:\n\t\t *       <ul>\n\t\t *         <li>'l' - Length changing</li>\n\t\t *         <li>'f' - Filtering input</li>\n\t\t *         <li>'t' - The table!</li>\n\t\t *         <li>'i' - Information</li>\n\t\t *         <li>'p' - Pagination</li>\n\t\t *         <li>'r' - pRocessing</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following constants are allowed:\n\t\t *       <ul>\n\t\t *         <li>'H' - jQueryUI theme \"header\" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>\n\t\t *         <li>'F' - jQueryUI theme \"footer\" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following syntax is expected:\n\t\t *       <ul>\n\t\t *         <li>'&lt;' and '&gt;' - div elements</li>\n\t\t *         <li>'&lt;\"class\" and '&gt;' - div with a class</li>\n\t\t *         <li>'&lt;\"#id\" and '&gt;' - div with an ID</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>Examples:\n\t\t *       <ul>\n\t\t *         <li>'&lt;\"wrapper\"flipt&gt;'</li>\n\t\t *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *   </ul>\n\t\t *  @type string\n\t\t *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>\n\t\t *    <\"H\"lfr>t<\"F\"ip> <i>(when `jQueryUI` is true)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.dom\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"dom\": '&lt;\"top\"i&gt;rt&lt;\"bottom\"flp&gt;&lt;\"clear\"&gt;'\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDom\": \"lfrtip\",\n\t\n\t\n\t\t/**\n\t\t * Search delay option. This will throttle full table searches that use the\n\t\t * DataTables provided search input element (it does not effect calls to\n\t\t * `dt-api search()`, providing a delay before the search is made.\n\t\t *  @type integer\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.searchDelay\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchDelay\": 200\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\n\t\t/**\n\t\t * DataTables features six different built-in options for the buttons to\n\t\t * display for pagination control:\n\t\t *\n\t\t * * `numbers` - Page number buttons only\n\t\t * * `simple` - 'Previous' and 'Next' buttons only\n\t\t * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers\n\t\t * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons\n\t\t * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers\n\t\t * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers\n\t\t *  \n\t\t * Further methods can be added using {@link DataTable.ext.oPagination}.\n\t\t *  @type string\n\t\t *  @default simple_numbers\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pagingType\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pagingType\": \"full_numbers\"\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"sPaginationType\": \"simple_numbers\",\n\t\n\t\n\t\t/**\n\t\t * Enable horizontal scrolling. When a table is too wide to fit into a\n\t\t * certain layout, or you have a large number of columns in the table, you\n\t\t * can enable x-scrolling to show the table in a viewport, which can be\n\t\t * scrolled. This property can be `true` which will allow the table to\n\t\t * scroll horizontally when needed, or any CSS unit, or a number (in which\n\t\t * case it will be treated as a pixel measurement). Setting as simply `true`\n\t\t * is recommended.\n\t\t *  @type boolean|string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollX\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": true,\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollX\": \"\",\n\t\n\t\n\t\t/**\n\t\t * This property can be used to force a DataTable to use more width than it\n\t\t * might otherwise do when x-scrolling is enabled. For example if you have a\n\t\t * table which requires to be well spaced, this parameter is useful for\n\t\t * \"over-sizing\" the table, and thus forcing scrolling. This property can by\n\t\t * any CSS unit, or a number (in which case it will be treated as a pixel\n\t\t * measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollXInner\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": \"100%\",\n\t\t *        \"scrollXInner\": \"110%\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollXInner\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Enable vertical scrolling. Vertical scrolling will constrain the DataTable\n\t\t * to the given height, and enable scrolling for any data which overflows the\n\t\t * current viewport. This can be used as an alternative to paging to display\n\t\t * a lot of data in a small area (although paging and scrolling can both be\n\t\t * enabled at the same time). This property can be any CSS unit, or a number\n\t\t * (in which case it will be treated as a pixel measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollY\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollY\": \"\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * Set the HTTP method that is used to make the Ajax call for server-side\n\t\t * processing or Ajax sourced data.\n\t\t *  @type string\n\t\t *  @default GET\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverMethod\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sServerMethod\": \"GET\",\n\t\n\t\n\t\t/**\n\t\t * DataTables makes use of renderers when displaying HTML elements for\n\t\t * a table. These renderers can be added or modified by plug-ins to\n\t\t * generate suitable mark-up for a site. For example the Bootstrap\n\t\t * integration plug-in for DataTables uses a paging button renderer to\n\t\t * display pagination buttons in the mark-up required by Bootstrap.\n\t\t *\n\t\t * For further information about the renderers available see\n\t\t * DataTable.ext.renderer\n\t\t *  @type string|object\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.renderer\n\t\t *\n\t\t */\n\t\t\"renderer\": null,\n\t\n\t\n\t\t/**\n\t\t * Set the data property name that DataTables should use to get a row's id\n\t\t * to set as the `id` property in the node.\n\t\t *  @type string\n\t\t *  @default DT_RowId\n\t\t *\n\t\t *  @name DataTable.defaults.rowId\n\t\t */\n\t\t\"rowId\": \"DT_RowId\"\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults );\n\t\n\t\n\t\n\t/*\n\t * Developer note - See note in model.defaults.js about the use of Hungarian\n\t * notation and camel case.\n\t */\n\t\n\t/**\n\t * Column options that can be given to DataTables at initialisation time.\n\t *  @namespace\n\t */\n\tDataTable.defaults.column = {\n\t\t/**\n\t\t * Define which column(s) an order will occur on for this column. This\n\t\t * allows a column's ordering to take multiple columns into account when\n\t\t * doing a sort or use the data from a different column. For example first\n\t\t * name / last name columns make sense to do a multi-column sort over the\n\t\t * two columns.\n\t\t *  @type array|int\n\t\t *  @default null <i>Takes the value of the column index automatically</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderData\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderData\": [ 0, 1 ], \"targets\": [ 0 ] },\n\t\t *          { \"orderData\": [ 1, 0 ], \"targets\": [ 1 ] },\n\t\t *          { \"orderData\": 2, \"targets\": [ 2 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderData\": [ 0, 1 ] },\n\t\t *          { \"orderData\": [ 1, 0 ] },\n\t\t *          { \"orderData\": 2 },\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aDataSort\": null,\n\t\t\"iDataSort\": -1,\n\t\n\t\n\t\t/**\n\t\t * You can control the default ordering direction, and even alter the\n\t\t * behaviour of the sort handler (i.e. only allow ascending ordering etc)\n\t\t * using this parameter.\n\t\t *  @type array\n\t\t *  @default [ 'asc', 'desc' ]\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderSequence\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderSequence\": [ \"asc\" ], \"targets\": [ 1 ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ], \"targets\": [ 2 ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ], \"targets\": [ 3 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          { \"orderSequence\": [ \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ] },\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"asSorting\": [ 'asc', 'desc' ],\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering on the data in this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.searchable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"searchable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"searchable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSearchable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable ordering on this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.visible\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"visible\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"visible\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bVisible\": true,\n\t\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} td The TD node that has been created\n\t\t *  @param {*} cellData The Data for the cell\n\t\t *  @param {array|object} rowData The data for the whole row\n\t\t *  @param {int} row The row index for the aoData data store\n\t\t *  @param {int} col The column index for aoColumns\n\t\t *\n\t\t *  @name DataTable.defaults.column.createdCell\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [3],\n\t\t *          \"createdCell\": function (td, cellData, rowData, row, col) {\n\t\t *            if ( cellData == \"1.7\" ) {\n\t\t *              $(td).css('color', 'blue')\n\t\t *            }\n\t\t *          }\n\t\t *        } ]\n\t\t *      });\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter has been replaced by `data` in DataTables to ensure naming\n\t\t * consistency. `dataProp` can still be used, as there is backwards\n\t\t * compatibility in DataTables for this option, but it is strongly\n\t\t * recommended that you use `data` in preference to `dataProp`.\n\t\t *  @name DataTable.defaults.column.dataProp\n\t\t */\n\t\n\t\n\t\t/**\n\t\t * This property can be used to read data from any data source property,\n\t\t * including deeply nested objects / properties. `data` can be given in a\n\t\t * number of different ways which effect its behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object. Note that\n\t\t *      function notation is recommended for use in `render` rather than\n\t\t *      `data` as it is much simpler to use as a renderer.\n\t\t * * `null` - use the original data source for the row rather than plucking\n\t\t *   data directly from it. This action has effects on two other\n\t\t *   initialisation options:\n\t\t *    * `defaultContent` - When null is given as the `data` option and\n\t\t *      `defaultContent` is specified for the column, the value defined by\n\t\t *      `defaultContent` will be used for the cell.\n\t\t *    * `render` - When null is used for the `data` option and the `render`\n\t\t *      option is specified for the column, the whole data source for the\n\t\t *      row is used for the renderer.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * `{array|object}` The data source for the row\n\t\t *      * `{string}` The type call data requested - this will be 'set' when\n\t\t *        setting data or 'filter', 'display', 'type', 'sort' or undefined\n\t\t *        when gathering data. Note that when `undefined` is given for the\n\t\t *        type DataTables expects to get the raw data for the object back<\n\t\t *      * `{*}` Data to set when the second parameter is 'set'.\n\t\t *    * Return:\n\t\t *      * The return value from the function is not required when 'set' is\n\t\t *        the type of call, but otherwise the return is what will be used\n\t\t *        for the data requested.\n\t\t *\n\t\t * Note that `data` is a getter and setter option. If you just require\n\t\t * formatting of data for output, you will likely want to use `render` which\n\t\t * is simply a getter and thus simpler to use.\n\t\t *\n\t\t * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The\n\t\t * name change reflects the flexibility of this property and is consistent\n\t\t * with the naming of mRender. If 'mDataProp' is given, then it will still\n\t\t * be used by DataTables, as it automatically maps the old name to the new\n\t\t * if required.\n\t\t *\n\t\t *  @type string|int|function|null\n\t\t *  @default null <i>Use automatically calculated column index</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.data\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Read table data from objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {value},\n\t\t *    //      \"version\": {value},\n\t\t *    //      \"grade\": {value}\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/objects.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform\" },\n\t\t *          { \"data\": \"version\" },\n\t\t *          { \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Read information from deeply nested objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {\n\t\t *    //         \"inner\": {value}\n\t\t *    //      },\n\t\t *    //      \"details\": [\n\t\t *    //         {value}, {value}\n\t\t *    //      ]\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform.inner\" },\n\t\t *          { \"data\": \"details.0\" },\n\t\t *          { \"data\": \"details.1\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `data` as a function to provide different information for\n\t\t *    // sorting, filtering and display. In this case, currency (price)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": function ( source, type, val ) {\n\t\t *            if (type === 'set') {\n\t\t *              source.price = val;\n\t\t *              // Store the computed dislay and filter values for efficiency\n\t\t *              source.price_display = val==\"\" ? \"\" : \"$\"+numberFormat(val);\n\t\t *              source.price_filter  = val==\"\" ? \"\" : \"$\"+numberFormat(val)+\" \"+val;\n\t\t *              return;\n\t\t *            }\n\t\t *            else if (type === 'display') {\n\t\t *              return source.price_display;\n\t\t *            }\n\t\t *            else if (type === 'filter') {\n\t\t *              return source.price_filter;\n\t\t *            }\n\t\t *            // 'sort', 'type' and undefined all just use the integer\n\t\t *            return source.price;\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using default content\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null,\n\t\t *          \"defaultContent\": \"Click to edit\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using array notation - outputting a list from an array\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"name[, ]\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\n\t\t/**\n\t\t * This property is the rendering partner to `data` and it is suggested that\n\t\t * when you want to manipulate data for display (including filtering,\n\t\t * sorting etc) without altering the underlying data for the table, use this\n\t\t * property. `render` can be considered to be the the read only companion to\n\t\t * `data` which is read / write (then as such more complex). Like `data`\n\t\t * this option can be given in a number of different ways to effect its\n\t\t * behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object.\n\t\t * * `object` - use different data for the different data types requested by\n\t\t *   DataTables ('filter', 'display', 'type' or 'sort'). The property names\n\t\t *   of the object is the data type the property refers to and the value can\n\t\t *   defined using an integer, string or function using the same rules as\n\t\t *   `render` normally does. Note that an `_` option _must_ be specified.\n\t\t *   This is the default value to use if you haven't specified a value for\n\t\t *   the data type requested by DataTables.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * {array|object} The data source for the row (based on `data`)\n\t\t *      * {string} The type call data requested - this will be 'filter',\n\t\t *        'display', 'type' or 'sort'.\n\t\t *      * {array|object} The full data source for the row (not based on\n\t\t *        `data`)\n\t\t *    * Return:\n\t\t *      * The return value from the function is what will be used for the\n\t\t *        data requested.\n\t\t *\n\t\t *  @type string|int|function|object|null\n\t\t *  @default null Use the data source value.\n\t\t *\n\t\t *  @name DataTable.defaults.column.render\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Create a comma separated list from an array of objects\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          {\n\t\t *            \"data\": \"platform\",\n\t\t *            \"render\": \"[, ].name\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Execute a function to obtain data\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": \"browserName()\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // As an object, extracting different data for the different types\n\t\t *    // This would be used with a data source such as:\n\t\t *    //   { \"phone\": 5552368, \"phone_filter\": \"5552368 555-2368\", \"phone_display\": \"555-2368\" }\n\t\t *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`\n\t\t *    // (which has both forms) is used for filtering for if a user inputs either format, while\n\t\t *    // the formatted phone number is the one that is shown in the table.\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": {\n\t\t *            \"_\": \"phone\",\n\t\t *            \"filter\": \"phone_filter\",\n\t\t *            \"display\": \"phone_display\"\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Use as a function to create a link from the data source\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"download_link\",\n\t\t *          \"render\": function ( data, type, full ) {\n\t\t *            return '<a href=\"'+data+'\">Download</a>';\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\n\t\t/**\n\t\t * Change the cell type created for the column - either TD cells or TH cells. This\n\t\t * can be useful as TH cells have semantic meaning in the table body, allowing them\n\t\t * to act as a header for a row (you may wish to add scope='row' to the TH elements).\n\t\t *  @type string\n\t\t *  @default td\n\t\t *\n\t\t *  @name DataTable.defaults.column.cellType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Make the first column use TH cells\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"cellType\": \"th\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sCellType\": \"td\",\n\t\n\t\n\t\t/**\n\t\t * Class to give to each cell in this column.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.class\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"class\": \"my_class\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"class\": \"my_class\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sClass\": \"\",\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t * Generally you shouldn't need this!\n\t\t *  @type string\n\t\t *  @default <i>Empty string<i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.contentPadding\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"contentPadding\": \"mmm\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sContentPadding\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because `data`\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.column.defaultContent\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\",\n\t\t *            \"targets\": [ -1 ]\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter is only used in DataTables' server-side processing. It can\n\t\t * be exceptionally useful to know what columns are being displayed on the\n\t\t * client side, and to map these to database fields. When defined, the names\n\t\t * also allow DataTables to reorder information from the server if it comes\n\t\t * back in an unexpected order (i.e. if you switch your columns around on the\n\t\t * client-side, your server-side code does not also need updating).\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.name\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"name\": \"engine\", \"targets\": [ 0 ] },\n\t\t *          { \"name\": \"browser\", \"targets\": [ 1 ] },\n\t\t *          { \"name\": \"platform\", \"targets\": [ 2 ] },\n\t\t *          { \"name\": \"version\", \"targets\": [ 3 ] },\n\t\t *          { \"name\": \"grade\", \"targets\": [ 4 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"name\": \"engine\" },\n\t\t *          { \"name\": \"browser\" },\n\t\t *          { \"name\": \"platform\" },\n\t\t *          { \"name\": \"version\" },\n\t\t *          { \"name\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sName\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Defines a data source type for the ordering which can be used to read\n\t\t * real-time information from the table (updating the internally cached\n\t\t * version) prior to ordering. This allows ordering to occur on user\n\t\t * editable elements such as form inputs.\n\t\t *  @type string\n\t\t *  @default std\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderDataType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderDataType\": \"dom-text\", \"targets\": [ 2, 3 ] },\n\t\t *          { \"type\": \"numeric\", \"targets\": [ 3 ] },\n\t\t *          { \"orderDataType\": \"dom-select\", \"targets\": [ 4 ] },\n\t\t *          { \"orderDataType\": \"dom-checkbox\", \"targets\": [ 5 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          { \"orderDataType\": \"dom-text\" },\n\t\t *          { \"orderDataType\": \"dom-text\", \"type\": \"numeric\" },\n\t\t *          { \"orderDataType\": \"dom-select\" },\n\t\t *          { \"orderDataType\": \"dom-checkbox\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sSortDataType\": \"std\",\n\t\n\t\n\t\t/**\n\t\t * The title of this column.\n\t\t *  @type string\n\t\t *  @default null <i>Derived from the 'TH' value for this column in the\n\t\t *    original HTML table.</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.title\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"title\": \"My column title\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"My column title\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\n\t\t/**\n\t\t * The type allows you to specify how the data for this column will be\n\t\t * ordered. Four types (string, numeric, date and html (which will strip\n\t\t * HTML tags before ordering)) are currently available. Note that only date\n\t\t * formats understood by Javascript's Date() object will be accepted as type\n\t\t * date. For example: \"Mar 26, 2008 5:03 PM\". May take the values: 'string',\n\t\t * 'numeric', 'date' or 'html' (by default). Further types can be adding\n\t\t * through plug-ins.\n\t\t *  @type string\n\t\t *  @default null <i>Auto-detected from raw data</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.type\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"type\": \"html\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"type\": \"html\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\n\t\t/**\n\t\t * Defining the width of the column, this parameter may take any CSS value\n\t\t * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not\n\t\t * been given a specific width through this interface ensuring that the table\n\t\t * remains readable.\n\t\t *  @type string\n\t\t *  @default null <i>Automatic</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.width\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"width\": \"20%\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"width\": \"20%\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sWidth\": null\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults.column );\n\t\n\t\n\t\n\t/**\n\t * DataTables settings object - this holds all the information needed for a\n\t * given table, including configuration, data and current application of the\n\t * table options. DataTables does not have a single instance for each DataTable\n\t * with the settings attached to that instance, but rather instances of the\n\t * DataTable \"class\" are created on-the-fly as needed (typically by a\n\t * $().dataTable() call) and the settings object is then applied to that\n\t * instance.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults} but this\n\t * one is the internal data store for DataTables's cache of columns. It should\n\t * NOT be manipulated outside of DataTables. Any configuration should be done\n\t * through the initialisation options.\n\t *  @namespace\n\t *  @todo Really should attach the settings object to individual instances so we\n\t *    don't need to create new instances on each $().dataTable() call (if the\n\t *    table already exists). It would also save passing oSettings around and\n\t *    into every single function. However, this is a very significant\n\t *    architecture change for DataTables and will almost certainly break\n\t *    backwards compatibility with older installations. This is something that\n\t *    will be done in 2.0.\n\t */\n\tDataTable.models.oSettings = {\n\t\t/**\n\t\t * Primary features of DataTables and their enablement state.\n\t\t *  @namespace\n\t\t */\n\t\t\"oFeatures\": {\n\t\n\t\t\t/**\n\t\t\t * Flag to say if DataTables should automatically try to calculate the\n\t\t\t * optimum table and columns widths (true) or not (false).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bAutoWidth\": null,\n\t\n\t\t\t/**\n\t\t\t * Delay the creation of TR and TD elements until they are actually\n\t\t\t * needed by a driven page draw. This can give a significant speed\n\t\t\t * increase for Ajax source and Javascript source data, but makes no\n\t\t\t * difference at all fro DOM and server-side processing tables.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bDeferRender\": null,\n\t\n\t\t\t/**\n\t\t\t * Enable filtering on the table or not. Note that if this is disabled\n\t\t\t * then there is no filtering at all on the table, including fnFilter.\n\t\t\t * To just remove the filtering input use sDom and remove the 'f' option.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bFilter\": null,\n\t\n\t\t\t/**\n\t\t\t * Table information element (the 'Showing x of y records' div) enable\n\t\t\t * flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bInfo\": null,\n\t\n\t\t\t/**\n\t\t\t * Present a user control allowing the end user to change the page size\n\t\t\t * when pagination is enabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bLengthChange\": null,\n\t\n\t\t\t/**\n\t\t\t * Pagination enabled or not. Note that if this is disabled then length\n\t\t\t * changing must also be disabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bPaginate\": null,\n\t\n\t\t\t/**\n\t\t\t * Processing indicator enable flag whenever DataTables is enacting a\n\t\t\t * user request - typically an Ajax request for server-side processing.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bProcessing\": null,\n\t\n\t\t\t/**\n\t\t\t * Server-side processing enabled flag - when enabled DataTables will\n\t\t\t * get all data from the server for every draw - there is no filtering,\n\t\t\t * sorting or paging done on the client-side.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bServerSide\": null,\n\t\n\t\t\t/**\n\t\t\t * Sorting enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSort\": null,\n\t\n\t\t\t/**\n\t\t\t * Multi-column sorting\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortMulti\": null,\n\t\n\t\t\t/**\n\t\t\t * Apply a class to the columns which are being sorted to provide a\n\t\t\t * visual highlight or not. This can slow things down when enabled since\n\t\t\t * there is a lot of DOM interaction.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortClasses\": null,\n\t\n\t\t\t/**\n\t\t\t * State saving enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bStateSave\": null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Scrolling settings for a table.\n\t\t *  @namespace\n\t\t */\n\t\t\"oScroll\": {\n\t\t\t/**\n\t\t\t * When the table is shorter in height than sScrollY, collapse the\n\t\t\t * table container down to the height of the table (when true).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bCollapse\": null,\n\t\n\t\t\t/**\n\t\t\t * Width of the scrollbar for the web-browser's platform. Calculated\n\t\t\t * during table initialisation.\n\t\t\t *  @type int\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"iBarWidth\": 0,\n\t\n\t\t\t/**\n\t\t\t * Viewport width for horizontal scrolling. Horizontal scrolling is\n\t\t\t * disabled if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sX\": null,\n\t\n\t\t\t/**\n\t\t\t * Width to expand the table to when using x-scrolling. Typically you\n\t\t\t * should not need to use this.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t *  @deprecated\n\t\t\t */\n\t\t\t\"sXInner\": null,\n\t\n\t\t\t/**\n\t\t\t * Viewport height for vertical scrolling. Vertical scrolling is disabled\n\t\t\t * if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sY\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Language information for the table.\n\t\t *  @namespace\n\t\t *  @extends DataTable.defaults.oLanguage\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Information callback function. See\n\t\t\t * {@link DataTable.defaults.fnInfoCallback}\n\t\t\t *  @type function\n\t\t\t *  @default null\n\t\t\t */\n\t\t\t\"fnInfoCallback\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Browser support parameters\n\t\t *  @namespace\n\t\t */\n\t\t\"oBrowser\": {\n\t\t\t/**\n\t\t\t * Indicate if the browser incorrectly calculates width:100% inside a\n\t\t\t * scrolling element (IE6/7)\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollOversize\": false,\n\t\n\t\t\t/**\n\t\t\t * Determine if the vertical scrollbar is on the right or left of the\n\t\t\t * scrolling container - needed for rtl language layout, although not\n\t\t\t * all browsers move the scrollbar (Safari).\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollbarLeft\": false,\n\t\n\t\t\t/**\n\t\t\t * Flag for if `getBoundingClientRect` is fully supported or not\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bBounding\": false,\n\t\n\t\t\t/**\n\t\t\t * Browser scrollbar width\n\t\t\t *  @type integer\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"barWidth\": 0\n\t\t},\n\t\n\t\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * Array referencing the nodes which are used for the features. The\n\t\t * parameters of this object match what is allowed by sDom - i.e.\n\t\t *   <ul>\n\t\t *     <li>'l' - Length changing</li>\n\t\t *     <li>'f' - Filtering input</li>\n\t\t *     <li>'t' - The table!</li>\n\t\t *     <li>'i' - Information</li>\n\t\t *     <li>'p' - Pagination</li>\n\t\t *     <li>'r' - pRocessing</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aanFeatures\": [],\n\t\n\t\t/**\n\t\t * Store data information - see {@link DataTable.models.oRow} for detailed\n\t\t * information.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoData\": [],\n\t\n\t\t/**\n\t\t * Array of indexes which are in the current display (after filtering etc)\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplay\": [],\n\t\n\t\t/**\n\t\t * Array of indexes for display - no filtering\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplayMaster\": [],\n\t\n\t\t/**\n\t\t * Map of row ids to data indexes\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"aIds\": {},\n\t\n\t\t/**\n\t\t * Store information about each column that is in use\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoColumns\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's header\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeader\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's footer\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooter\": [],\n\t\n\t\t/**\n\t\t * Store the applied global search information in case we want to force a\n\t\t * research or compare the old search to a new one.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t */\n\t\t\"oPreviousSearch\": {},\n\t\n\t\t/**\n\t\t * Store the applied search for each column - see\n\t\t * {@link DataTable.models.oSearch} for the format that is used for the\n\t\t * filtering information for each column.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreSearchCols\": [],\n\t\n\t\t/**\n\t\t * Sorting that is applied to the table. Note that the inner arrays are\n\t\t * used in the following manner:\n\t\t * <ul>\n\t\t *   <li>Index 0 - column number</li>\n\t\t *   <li>Index 1 - current sorting direction</li>\n\t\t * </ul>\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @todo These inner arrays should really be objects\n\t\t */\n\t\t\"aaSorting\": null,\n\t\n\t\t/**\n\t\t * Sorting that is always applied to the table (i.e. prefixed in front of\n\t\t * aaSorting).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\t/**\n\t\t * Classes to use for the striping of a table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its striping classes as well\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asDestroyStripes\": [],\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its width\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"sDestroyWidth\": 0,\n\t\n\t\t/**\n\t\t * Callback functions array for every time a row is inserted (i.e. on a draw).\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for the header on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeaderCallback\": [],\n\t\n\t\t/**\n\t\t * Callback function for the footer on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooterCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for draw callback functions\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for row created function\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCreatedCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for just before the table is redrawn. A return of\n\t\t * false will be used to cancel the draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for when the table has been initialised.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoInitComplete\": [],\n\t\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings to be stored for state saving, prior to\n\t\t * saving state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSaveParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings that have been stored for state saving\n\t\t * prior to using the stored values to restore the state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoadParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for operating on the settings object once the saved state has been\n\t\t * loaded\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoaded\": [],\n\t\n\t\t/**\n\t\t * Cache the table ID for quick access\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sTableId\": \"\",\n\t\n\t\t/**\n\t\t * The TABLE node for the main table\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTable\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the thead element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTHead\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tfoot element - if it exists\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTFoot\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tbody element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTBody\": null,\n\t\n\t\t/**\n\t\t * Cache the wrapper node (contains all DataTables controlled elements)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTableWrapper\": null,\n\t\n\t\t/**\n\t\t * Indicate if when using server-side processing the loading of data\n\t\t * should be deferred until the second draw.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDeferLoading\": false,\n\t\n\t\t/**\n\t\t * Indicate if all required information has been read in\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bInitialised\": false,\n\t\n\t\t/**\n\t\t * Information about open rows. Each object in the array has the parameters\n\t\t * 'nTr' and 'nParent'\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoOpenRows\": [],\n\t\n\t\t/**\n\t\t * Dictate the positioning of DataTables' control elements - see\n\t\t * {@link DataTable.model.oInit.sDom}.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDom\": null,\n\t\n\t\t/**\n\t\t * Search delay (in mS)\n\t\t *  @type integer\n\t\t *  @default null\n\t\t */\n\t\t\"searchDelay\": null,\n\t\n\t\t/**\n\t\t * Which type of pagination should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default two_button\n\t\t */\n\t\t\"sPaginationType\": \"two_button\",\n\t\n\t\t/**\n\t\t * The state duration (for `stateSave`) in seconds.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iStateDuration\": 0,\n\t\n\t\t/**\n\t\t * Array of callback functions for state saving. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the JSON string to save that has been thus far created. Returns\n\t\t *       a JSON string to be inserted into a json object\n\t\t *       (i.e. '\"param\": [ 0, 1, 2]')</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSave\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for state loading. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the object stored. May return false to cancel state loading</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoad\": [],\n\t\n\t\t/**\n\t\t * State that was saved. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oSavedState\": null,\n\t\n\t\t/**\n\t\t * State that was loaded. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oLoadedState\": null,\n\t\n\t\t/**\n\t\t * Source url for AJAX data for the table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\t/**\n\t\t * Property from a given object from which to read the table data from. This\n\t\t * can be an empty string (when not server-side processing), in which case\n\t\t * it is  assumed an an array is given directly.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sAjaxDataProp\": null,\n\t\n\t\t/**\n\t\t * Note if draw should be blocked while getting data\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bAjaxDataGet\": true,\n\t\n\t\t/**\n\t\t * The last jQuery XHR object that was used for server-side data gathering.\n\t\t * This can be used for working with the XHR information in one of the\n\t\t * callbacks\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"jqXHR\": null,\n\t\n\t\t/**\n\t\t * JSON returned from the server in the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"json\": undefined,\n\t\n\t\t/**\n\t\t * Data submitted as part of the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"oAjaxData\": undefined,\n\t\n\t\t/**\n\t\t * Function to get the server-side data.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\t/**\n\t\t * Functions which are called prior to sending an Ajax request so extra\n\t\t * parameters can easily be sent to the server\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoServerParams\": [],\n\t\n\t\t/**\n\t\t * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if\n\t\t * required).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sServerMethod\": null,\n\t\n\t\t/**\n\t\t * Format numbers for display.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnFormatNumber\": null,\n\t\n\t\t/**\n\t\t * List of options that can be used for the user selectable length menu.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLengthMenu\": null,\n\t\n\t\t/**\n\t\t * Counter for the draws that the table does. Also used as a tracker for\n\t\t * server-side processing\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iDraw\": 0,\n\t\n\t\t/**\n\t\t * Indicate if a redraw is being done - useful for Ajax\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDrawing\": false,\n\t\n\t\t/**\n\t\t * Draw index (iDraw) of the last error when parsing the returned data\n\t\t *  @type int\n\t\t *  @default -1\n\t\t */\n\t\t\"iDrawError\": -1,\n\t\n\t\t/**\n\t\t * Paging display length\n\t\t *  @type int\n\t\t *  @default 10\n\t\t */\n\t\t\"_iDisplayLength\": 10,\n\t\n\t\t/**\n\t\t * Paging start point - aiDisplay index\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"_iDisplayStart\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the result set\n\t\t * (i.e. before filtering), Use fnRecordsTotal rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsTotal\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the current display set\n\t\t * (i.e. after filtering). Use fnRecordsDisplay rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type boolean\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsDisplay\": 0,\n\t\n\t\t/**\n\t\t * The classes to use for the table\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if filtering has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bFiltered\": false,\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if sorting has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bSorted\": false,\n\t\n\t\t/**\n\t\t * Indicate that if multiple rows are in the header and there is more than\n\t\t * one unique cell per column, if the top one (true) or bottom one (false)\n\t\t * should be used for sorting / title by DataTables.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortCellsTop\": null,\n\t\n\t\t/**\n\t\t * Initialisation object that is used for the table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInit\": null,\n\t\n\t\t/**\n\t\t * Destroy callback functions - for plug-ins to attach themselves to the\n\t\t * destroy so they can clean up markup and events.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDestroyCallback\": [],\n\t\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, before filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsTotal\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsTotal * 1 :\n\t\t\t\tthis.aiDisplayMaster.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, after filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsDisplay\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsDisplay * 1 :\n\t\t\t\tthis.aiDisplay.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the display end point - aiDisplay index\n\t\t *  @type function\n\t\t */\n\t\t\"fnDisplayEnd\": function ()\n\t\t{\n\t\t\tvar\n\t\t\t\tlen      = this._iDisplayLength,\n\t\t\t\tstart    = this._iDisplayStart,\n\t\t\t\tcalc     = start + len,\n\t\t\t\trecords  = this.aiDisplay.length,\n\t\t\t\tfeatures = this.oFeatures,\n\t\t\t\tpaginate = features.bPaginate;\n\t\n\t\t\tif ( features.bServerSide ) {\n\t\t\t\treturn paginate === false || len === -1 ?\n\t\t\t\t\tstart + records :\n\t\t\t\t\tMath.min( start+len, this._iRecordsDisplay );\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn ! paginate || calc>records || len===-1 ?\n\t\t\t\t\trecords :\n\t\t\t\t\tcalc;\n\t\t\t}\n\t\t},\n\t\n\t\t/**\n\t\t * The DataTables object for this table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInstance\": null,\n\t\n\t\t/**\n\t\t * Unique identifier for each instance of the DataTables object. If there\n\t\t * is an ID on the table node, then it takes that value, otherwise an\n\t\t * incrementing internal counter is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sInstance\": null,\n\t\n\t\t/**\n\t\t * tabindex attribute value that is added to DataTables control elements, allowing\n\t\t * keyboard navigation of the table and its controls.\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollHead\": null,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollFoot\": null,\n\t\n\t\t/**\n\t\t * Last applied sort\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLastSort\": [],\n\t\n\t\t/**\n\t\t * Stored plug-in instances\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oPlugins\": {},\n\t\n\t\t/**\n\t\t * Function used to get a row's id from the row's data\n\t\t *  @type function\n\t\t *  @default null\n\t\t */\n\t\t\"rowIdFn\": null,\n\t\n\t\t/**\n\t\t * Data location where to store a row's id\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"rowId\": null\n\t};\n\n\t/**\n\t * Extension object for DataTables that is used to provide all extension\n\t * options.\n\t *\n\t * Note that the `DataTable.ext` object is available through\n\t * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is\n\t * also aliased to `jQuery.fn.dataTableExt` for historic reasons.\n\t *  @namespace\n\t *  @extends DataTable.models.ext\n\t */\n\t\n\t\n\t/**\n\t * DataTables extensions\n\t * \n\t * This namespace acts as a collection area for plug-ins that can be used to\n\t * extend DataTables capabilities. Indeed many of the build in methods\n\t * use this method to provide their own capabilities (sorting methods for\n\t * example).\n\t *\n\t * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy\n\t * reasons\n\t *\n\t *  @namespace\n\t */\n\tDataTable.ext = _ext = {\n\t\t/**\n\t\t * Buttons. For use with the Buttons extension for DataTables. This is\n\t\t * defined here so other extensions can define buttons regardless of load\n\t\t * order. It is _not_ used by DataTables core.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tbuttons: {},\n\t\n\t\n\t\t/**\n\t\t * Element class names\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tclasses: {},\n\t\n\t\n\t\t/**\n\t\t * DataTables build type (expanded by the download builder)\n\t\t *\n\t\t *  @type string\n\t\t */\n\t\tbuild:\"zf/jq-3.3.1/jszip-2.5.0/pdfmake-0.1.36/dt-1.10.18/af-2.3.3/b-1.5.6/b-colvis-1.5.6/b-flash-1.5.6/b-html5-1.5.6/b-print-1.5.6/cr-1.5.0/fc-3.2.5/fh-3.1.4/kt-2.5.0/r-2.2.2/rg-1.1.0/rr-1.2.4/sc-2.0.0/sl-1.3.0\",\n\t\n\t\n\t\t/**\n\t\t * Error reporting.\n\t\t * \n\t\t * How should DataTables report an error. Can take the value 'alert',\n\t\t * 'throw', 'none' or a function.\n\t\t *\n\t\t *  @type string|function\n\t\t *  @default alert\n\t\t */\n\t\terrMode: \"alert\",\n\t\n\t\n\t\t/**\n\t\t * Feature plug-ins.\n\t\t * \n\t\t * This is an array of objects which describe the feature plug-ins that are\n\t\t * available to DataTables. These feature plug-ins are then available for\n\t\t * use through the `dom` initialisation option.\n\t\t * \n\t\t * Each feature plug-in is described by an object which must have the\n\t\t * following properties:\n\t\t * \n\t\t * * `fnInit` - function that is used to initialise the plug-in,\n\t\t * * `cFeature` - a character so the feature can be enabled by the `dom`\n\t\t *   instillation option. This is case sensitive.\n\t\t *\n\t\t * The `fnInit` function has the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *\n\t\t * And the following return is expected:\n\t\t * \n\t\t * * {node|null} The element which contains your feature. Note that the\n\t\t *   return may also be void if your plug-in does not require to inject any\n\t\t *   DOM elements into DataTables control (`dom`) - for example this might\n\t\t *   be useful when developing a plug-in which allows table control via\n\t\t *   keyboard entry\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    $.fn.dataTable.ext.features.push( {\n\t\t *      \"fnInit\": function( oSettings ) {\n\t\t *        return new TableTools( { \"oDTSettings\": oSettings } );\n\t\t *      },\n\t\t *      \"cFeature\": \"T\"\n\t\t *    } );\n\t\t */\n\t\tfeature: [],\n\t\n\t\n\t\t/**\n\t\t * Row searching.\n\t\t * \n\t\t * This method of searching is complimentary to the default type based\n\t\t * searching, and a lot more comprehensive as it allows you complete control\n\t\t * over the searching logic. Each element in this array is a function\n\t\t * (parameters described below) that is called for every row in the table,\n\t\t * and your logic decides if it should be included in the searching data set\n\t\t * or not.\n\t\t *\n\t\t * Searching functions have the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{array|object}` Data for the row to be processed (same as the\n\t\t *    original format that was passed in as the data source, or an array\n\t\t *    from a DOM data source\n\t\t * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which\n\t\t *    can be useful to retrieve the `TR` element if you need DOM interaction.\n\t\t *\n\t\t * And the following return is expected:\n\t\t *\n\t\t * * {boolean} Include the row in the searched result set (true) or not\n\t\t *   (false)\n\t\t *\n\t\t * Note that as with the main search ability in DataTables, technically this\n\t\t * is \"filtering\", since it is subtractive. However, for consistency in\n\t\t * naming we call it searching here.\n\t\t *\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @example\n\t\t *    // The following example shows custom search being applied to the\n\t\t *    // fourth column (i.e. the data[3] index) based on two input values\n\t\t *    // from the end-user, matching the data in a certain range.\n\t\t *    $.fn.dataTable.ext.search.push(\n\t\t *      function( settings, data, dataIndex ) {\n\t\t *        var min = document.getElementById('min').value * 1;\n\t\t *        var max = document.getElementById('max').value * 1;\n\t\t *        var version = data[3] == \"-\" ? 0 : data[3]*1;\n\t\t *\n\t\t *        if ( min == \"\" && max == \"\" ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min == \"\" && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && \"\" == max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        return false;\n\t\t *      }\n\t\t *    );\n\t\t */\n\t\tsearch: [],\n\t\n\t\n\t\t/**\n\t\t * Selector extensions\n\t\t *\n\t\t * The `selector` option can be used to extend the options available for the\n\t\t * selector modifier options (`selector-modifier` object data type) that\n\t\t * each of the three built in selector types offer (row, column and cell +\n\t\t * their plural counterparts). For example the Select extension uses this\n\t\t * mechanism to provide an option to select only rows, columns and cells\n\t\t * that have been marked as selected by the end user (`{selected: true}`),\n\t\t * which can be used in conjunction with the existing built in selector\n\t\t * options.\n\t\t *\n\t\t * Each property is an array to which functions can be pushed. The functions\n\t\t * take three attributes:\n\t\t *\n\t\t * * Settings object for the host table\n\t\t * * Options object (`selector-modifier` object type)\n\t\t * * Array of selected item indexes\n\t\t *\n\t\t * The return is an array of the resulting item indexes after the custom\n\t\t * selector has been applied.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tselector: {\n\t\t\tcell: [],\n\t\t\tcolumn: [],\n\t\t\trow: []\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Internal functions, exposed for used in plug-ins.\n\t\t * \n\t\t * Please note that you should not need to use the internal methods for\n\t\t * anything other than a plug-in (and even then, try to avoid if possible).\n\t\t * The internal function may change between releases.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tinternal: {},\n\t\n\t\n\t\t/**\n\t\t * Legacy configuration options. Enable and disable legacy options that\n\t\t * are available in DataTables.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tlegacy: {\n\t\t\t/**\n\t\t\t * Enable / disable DataTables 1.9 compatible server-side processing\n\t\t\t * requests\n\t\t\t *\n\t\t\t *  @type boolean\n\t\t\t *  @default null\n\t\t\t */\n\t\t\tajax: null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Pagination plug-in methods.\n\t\t * \n\t\t * Each entry in this object is a function and defines which buttons should\n\t\t * be shown by the pagination rendering method that is used for the table:\n\t\t * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the\n\t\t * buttons are displayed in the document, while the functions here tell it\n\t\t * what buttons to display. This is done by returning an array of button\n\t\t * descriptions (what each button will do).\n\t\t *\n\t\t * Pagination types (the four built in options and any additional plug-in\n\t\t * options defined here) can be used through the `paginationType`\n\t\t * initialisation parameter.\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{int} page` The current page index\n\t\t * 2. `{int} pages` The number of pages in the table\n\t\t *\n\t\t * Each function is expected to return an array where each element of the\n\t\t * array can be one of:\n\t\t *\n\t\t * * `first` - Jump to first page when activated\n\t\t * * `last` - Jump to last page when activated\n\t\t * * `previous` - Show previous page when activated\n\t\t * * `next` - Show next page when activated\n\t\t * * `{int}` - Show page of the index given\n\t\t * * `{array}` - A nested array containing the above elements to add a\n\t\t *   containing 'DIV' element (might be useful for styling).\n\t\t *\n\t\t * Note that DataTables v1.9- used this object slightly differently whereby\n\t\t * an object with two functions would be defined for each plug-in. That\n\t\t * ability is still supported by DataTables 1.10+ to provide backwards\n\t\t * compatibility, but this option of use is now decremented and no longer\n\t\t * documented in DataTables 1.10+.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t *\n\t\t *  @example\n\t\t *    // Show previous, next and current page buttons only\n\t\t *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {\n\t\t *      return [ 'previous', page, 'next' ];\n\t\t *    };\n\t\t */\n\t\tpager: {},\n\t\n\t\n\t\trenderer: {\n\t\t\tpageButton: {},\n\t\t\theader: {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Ordering plug-ins - custom data source\n\t\t * \n\t\t * The extension options for ordering of data available here is complimentary\n\t\t * to the default type based ordering that DataTables typically uses. It\n\t\t * allows much greater control over the the data that is being used to\n\t\t * order a column, but is necessarily therefore more complex.\n\t\t * \n\t\t * This type of ordering is useful if you want to do ordering based on data\n\t\t * live from the DOM (for example the contents of an 'input' element) rather\n\t\t * than just the static string that DataTables knows of.\n\t\t * \n\t\t * The way these plug-ins work is that you create an array of the values you\n\t\t * wish to be ordering for the column in question and then return that\n\t\t * array. The data in the array much be in the index order of the rows in\n\t\t * the table (not the currently ordering order!). Which order data gathering\n\t\t * function is run here depends on the `dt-init columns.orderDataType`\n\t\t * parameter that is used for the column (if any).\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{int}` Target column index\n\t\t *\n\t\t * Each function is expected to return an array:\n\t\t *\n\t\t * * `{array}` Data for the column to be ordering upon\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    // Ordering using `input` node values\n\t\t *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )\n\t\t *    {\n\t\t *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {\n\t\t *        return $('input', td).val();\n\t\t *      } );\n\t\t *    }\n\t\t */\n\t\torder: {},\n\t\n\t\n\t\t/**\n\t\t * Type based plug-ins.\n\t\t *\n\t\t * Each column in DataTables has a type assigned to it, either by automatic\n\t\t * detection or by direct assignment using the `type` option for the column.\n\t\t * The type of a column will effect how it is ordering and search (plug-ins\n\t\t * can also make use of the column type if required).\n\t\t *\n\t\t * @namespace\n\t\t */\n\t\ttype: {\n\t\t\t/**\n\t\t\t * Type detection functions.\n\t\t\t *\n\t\t\t * The functions defined in this object are used to automatically detect\n\t\t\t * a column's type, making initialisation of DataTables super easy, even\n\t\t\t * when complex data is in the table.\n\t\t\t *\n\t\t\t * The functions defined take two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be analysed\n\t\t     *  2. `{settings}` DataTables settings object. This can be used to\n\t\t     *     perform context specific type detection - for example detection\n\t\t     *     based on language settings such as using a comma for a decimal\n\t\t     *     place. Generally speaking the options from the settings will not\n\t\t     *     be required\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Data type detected, or null if unknown (and thus\n\t\t\t *   pass it on to the other type detection functions.\n\t\t\t *\n\t\t\t *  @type array\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Currency type detection plug-in:\n\t\t\t *    $.fn.dataTable.ext.type.detect.push(\n\t\t\t *      function ( data, settings ) {\n\t\t\t *        // Check the numeric part\n\t\t\t *        if ( ! data.substring(1).match(/[0-9]/) ) {\n\t\t\t *          return null;\n\t\t\t *        }\n\t\t\t *\n\t\t\t *        // Check prefixed by currency\n\t\t\t *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {\n\t\t\t *          return 'currency';\n\t\t\t *        }\n\t\t\t *        return null;\n\t\t\t *      }\n\t\t\t *    );\n\t\t\t */\n\t\t\tdetect: [],\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based search formatting.\n\t\t\t *\n\t\t\t * The type based searching functions can be used to pre-format the\n\t\t\t * data to be search on. For example, it can be used to strip HTML\n\t\t\t * tags or to de-format telephone numbers for numeric only searching.\n\t\t\t *\n\t\t\t * Note that is a search is not defined for a column of a given type,\n\t\t\t * no search formatting will be performed.\n\t\t\t * \n\t\t\t * Pre-processing of searching data plug-ins - When you assign the sType\n\t\t\t * for a column (or have it automatically detected for you by DataTables\n\t\t\t * or a type detection plug-in), you will typically be using this for\n\t\t\t * custom sorting, but it can also be used to provide custom searching\n\t\t\t * by allowing you to pre-processing the data and returning the data in\n\t\t\t * the format that should be searched upon. This is done by adding\n\t\t\t * functions this object with a parameter name which matches the sType\n\t\t\t * for that target column. This is the corollary of <i>afnSortData</i>\n\t\t\t * for searching data.\n\t\t\t *\n\t\t\t * The functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for searching\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Formatted string that will be used for the searching.\n\t\t\t *\n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {\n\t\t\t *      return d.replace(/\\n/g,\" \").replace( /<.*?>/g, \"\" );\n\t\t\t *    }\n\t\t\t */\n\t\t\tsearch: {},\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based ordering.\n\t\t\t *\n\t\t\t * The column type tells DataTables what ordering to apply to the table\n\t\t\t * when a column is sorted upon. The order for each type that is defined,\n\t\t\t * is defined by the functions available in this object.\n\t\t\t *\n\t\t\t * Each ordering option can be described by three properties added to\n\t\t\t * this object:\n\t\t\t *\n\t\t\t * * `{type}-pre` - Pre-formatting function\n\t\t\t * * `{type}-asc` - Ascending order function\n\t\t\t * * `{type}-desc` - Descending order function\n\t\t\t *\n\t\t\t * All three can be used together, only `{type}-pre` or only\n\t\t\t * `{type}-asc` and `{type}-desc` together. It is generally recommended\n\t\t\t * that only `{type}-pre` is used, as this provides the optimal\n\t\t\t * implementation in terms of speed, although the others are provided\n\t\t\t * for compatibility with existing Javascript sort functions.\n\t\t\t *\n\t\t\t * `{type}-pre`: Functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for ordering\n\t\t\t *\n\t\t\t * And return:\n\t\t\t *\n\t\t\t * * `{*}` Data to be sorted upon\n\t\t\t *\n\t\t\t * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort\n\t\t\t * functions, taking two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data to compare to the second parameter\n\t\t     *  2. `{*}` Data to compare to the first parameter\n\t\t\t *\n\t\t\t * And returning:\n\t\t\t *\n\t\t\t * * `{*}` Ordering match: <0 if first parameter should be sorted lower\n\t\t\t *   than the second parameter, ===0 if the two parameters are equal and\n\t\t\t *   >0 if the first parameter should be sorted height than the second\n\t\t\t *   parameter.\n\t\t\t * \n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Numeric ordering of formatted numbers with a pre-formatter\n\t\t\t *    $.extend( $.fn.dataTable.ext.type.order, {\n\t\t\t *      \"string-pre\": function(x) {\n\t\t\t *        a = (a === \"-\" || a === \"\") ? 0 : a.replace( /[^\\d\\-\\.]/g, \"\" );\n\t\t\t *        return parseFloat( a );\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Case-sensitive string ordering, with no pre-formatting method\n\t\t\t *    $.extend( $.fn.dataTable.ext.order, {\n\t\t\t *      \"string-case-asc\": function(x,y) {\n\t\t\t *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t\t *      },\n\t\t\t *      \"string-case-desc\": function(x,y) {\n\t\t\t *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t */\n\t\t\torder: {}\n\t\t},\n\t\n\t\t/**\n\t\t * Unique DataTables instance counter\n\t\t *\n\t\t * @type int\n\t\t * @private\n\t\t */\n\t\t_unique: 0,\n\t\n\t\n\t\t//\n\t\t// Depreciated\n\t\t// The following properties are retained for backwards compatiblity only.\n\t\t// The should not be used in new projects and will be removed in a future\n\t\t// version\n\t\t//\n\t\n\t\t/**\n\t\t * Version check function.\n\t\t *  @type function\n\t\t *  @depreciated Since 1.10\n\t\t */\n\t\tfnVersionCheck: DataTable.fnVersionCheck,\n\t\n\t\n\t\t/**\n\t\t * Index for what 'this' index API functions should use\n\t\t *  @type int\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tiApiIndex: 0,\n\t\n\t\n\t\t/**\n\t\t * jQuery UI class container\n\t\t *  @type object\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\toJUIClasses: {},\n\t\n\t\n\t\t/**\n\t\t * Software version\n\t\t *  @type string\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tsVersion: DataTable.version\n\t};\n\t\n\t\n\t//\n\t// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts\n\t//\n\t$.extend( _ext, {\n\t\tafnFiltering: _ext.search,\n\t\taTypes:       _ext.type.detect,\n\t\tofnSearch:    _ext.type.search,\n\t\toSort:        _ext.type.order,\n\t\tafnSortData:  _ext.order,\n\t\taoFeatures:   _ext.feature,\n\t\toApi:         _ext.internal,\n\t\toStdClasses:  _ext.classes,\n\t\toPagination:  _ext.pager\n\t} );\n\t\n\t\n\t$.extend( DataTable.ext.classes, {\n\t\t\"sTable\": \"dataTable\",\n\t\t\"sNoFooter\": \"no-footer\",\n\t\n\t\t/* Paging buttons */\n\t\t\"sPageButton\": \"paginate_button\",\n\t\t\"sPageButtonActive\": \"current\",\n\t\t\"sPageButtonDisabled\": \"disabled\",\n\t\n\t\t/* Striping classes */\n\t\t\"sStripeOdd\": \"odd\",\n\t\t\"sStripeEven\": \"even\",\n\t\n\t\t/* Empty row */\n\t\t\"sRowEmpty\": \"dataTables_empty\",\n\t\n\t\t/* Features */\n\t\t\"sWrapper\": \"dataTables_wrapper\",\n\t\t\"sFilter\": \"dataTables_filter\",\n\t\t\"sInfo\": \"dataTables_info\",\n\t\t\"sPaging\": \"dataTables_paginate paging_\", /* Note that the type is postfixed */\n\t\t\"sLength\": \"dataTables_length\",\n\t\t\"sProcessing\": \"dataTables_processing\",\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\": \"sorting_asc\",\n\t\t\"sSortDesc\": \"sorting_desc\",\n\t\t\"sSortable\": \"sorting\", /* Sortable in both directions */\n\t\t\"sSortableAsc\": \"sorting_asc_disabled\",\n\t\t\"sSortableDesc\": \"sorting_desc_disabled\",\n\t\t\"sSortableNone\": \"sorting_disabled\",\n\t\t\"sSortColumn\": \"sorting_\", /* Note that an int is postfixed for the sorting order */\n\t\n\t\t/* Filtering */\n\t\t\"sFilterInput\": \"\",\n\t\n\t\t/* Page length */\n\t\t\"sLengthSelect\": \"\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollWrapper\": \"dataTables_scroll\",\n\t\t\"sScrollHead\": \"dataTables_scrollHead\",\n\t\t\"sScrollHeadInner\": \"dataTables_scrollHeadInner\",\n\t\t\"sScrollBody\": \"dataTables_scrollBody\",\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot\",\n\t\t\"sScrollFootInner\": \"dataTables_scrollFootInner\",\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\": \"\",\n\t\t\"sFooterTH\": \"\",\n\t\n\t\t// Deprecated\n\t\t\"sSortJUIAsc\": \"\",\n\t\t\"sSortJUIDesc\": \"\",\n\t\t\"sSortJUI\": \"\",\n\t\t\"sSortJUIAscAllowed\": \"\",\n\t\t\"sSortJUIDescAllowed\": \"\",\n\t\t\"sSortJUIWrapper\": \"\",\n\t\t\"sSortIcon\": \"\",\n\t\t\"sJUIHeader\": \"\",\n\t\t\"sJUIFooter\": \"\"\n\t} );\n\t\n\t\n\tvar extPagination = DataTable.ext.pager;\n\t\n\tfunction _numbers ( page, pages ) {\n\t\tvar\n\t\t\tnumbers = [],\n\t\t\tbuttons = extPagination.numbers_length,\n\t\t\thalf = Math.floor( buttons / 2 ),\n\t\t\ti = 1;\n\t\n\t\tif ( pages <= buttons ) {\n\t\t\tnumbers = _range( 0, pages );\n\t\t}\n\t\telse if ( page <= half ) {\n\t\t\tnumbers = _range( 0, buttons-2 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t}\n\t\telse if ( page >= pages - 1 - half ) {\n\t\t\tnumbers = _range( pages-(buttons-2), pages );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\telse {\n\t\t\tnumbers = _range( page-half+2, page+half-1 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' );\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\n\t\tnumbers.DT_el = 'span';\n\t\treturn numbers;\n\t}\n\t\n\t\n\t$.extend( extPagination, {\n\t\tsimple: function ( page, pages ) {\n\t\t\treturn [ 'previous', 'next' ];\n\t\t},\n\t\n\t\tfull: function ( page, pages ) {\n\t\t\treturn [  'first', 'previous', 'next', 'last' ];\n\t\t},\n\t\n\t\tnumbers: function ( page, pages ) {\n\t\t\treturn [ _numbers(page, pages) ];\n\t\t},\n\t\n\t\tsimple_numbers: function ( page, pages ) {\n\t\t\treturn [ 'previous', _numbers(page, pages), 'next' ];\n\t\t},\n\t\n\t\tfull_numbers: function ( page, pages ) {\n\t\t\treturn [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];\n\t\t},\n\t\t\n\t\tfirst_last_numbers: function (page, pages) {\n\t \t\treturn ['first', _numbers(page, pages), 'last'];\n\t \t},\n\t\n\t\t// For testing and plug-ins to use\n\t\t_numbers: _numbers,\n\t\n\t\t// Number of number buttons (including ellipsis) to show. _Must be odd!_\n\t\tnumbers_length: 7\n\t} );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\tpageButton: {\n\t\t\t_: function ( settings, host, idx, buttons, page, pages ) {\n\t\t\t\tvar classes = settings.oClasses;\n\t\t\t\tvar lang = settings.oLanguage.oPaginate;\n\t\t\t\tvar aria = settings.oLanguage.oAria.paginate || {};\n\t\t\t\tvar btnDisplay, btnClass, counter=0;\n\t\n\t\t\t\tvar attach = function( container, buttons ) {\n\t\t\t\t\tvar i, ien, node, button;\n\t\t\t\t\tvar clickHandler = function ( e ) {\n\t\t\t\t\t\t_fnPageChange( settings, e.data.action, true );\n\t\t\t\t\t};\n\t\n\t\t\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tbutton = buttons[i];\n\t\n\t\t\t\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\t\t\t\tvar inner = $( '<'+(button.DT_el || 'div')+'/>' )\n\t\t\t\t\t\t\t\t.appendTo( container );\n\t\t\t\t\t\t\tattach( inner, button );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tbtnDisplay = null;\n\t\t\t\t\t\t\tbtnClass = '';\n\t\n\t\t\t\t\t\t\tswitch ( button ) {\n\t\t\t\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\t\t\t\tcontainer.append('<span class=\"ellipsis\">&#x2026;</span>');\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'first':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'next':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'last':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t\t\t\tclasses.sPageButtonActive : '';\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\tif ( btnDisplay !== null ) {\n\t\t\t\t\t\t\t\tnode = $('<a>', {\n\t\t\t\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t\t\t\t'data-dt-idx': counter,\n\t\t\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t\t\t\t.appendTo( container );\n\t\n\t\t\t\t\t\t\t\t_fnBindAction(\n\t\t\t\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t\t\t\t);\n\t\n\t\t\t\t\t\t\t\tcounter++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\n\t\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t\t// inside an iframe or frame. Try / catch the error. Not good for\n\t\t\t\t// accessibility, but neither are frames.\n\t\t\t\tvar activeEl;\n\t\n\t\t\t\ttry {\n\t\t\t\t\t// Because this approach is destroying and recreating the paging\n\t\t\t\t\t// elements, focus is lost on the select button which is bad for\n\t\t\t\t\t// accessibility. So we want to restore focus once the draw has\n\t\t\t\t\t// completed\n\t\t\t\t\tactiveEl = $(host).find(document.activeElement).data('dt-idx');\n\t\t\t\t}\n\t\t\t\tcatch (e) {}\n\t\n\t\t\t\tattach( $(host).empty(), buttons );\n\t\n\t\t\t\tif ( activeEl !== undefined ) {\n\t\t\t\t\t$(host).find( '[data-dt-idx='+activeEl+']' ).focus();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t\n\t\n\t// Built in type detection. See model.ext.aTypes for information about\n\t// what is required from this methods.\n\t$.extend( DataTable.ext.type.detect, [\n\t\t// Plain numbers - first since V8 detects some plain numbers as dates\n\t\t// e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal ) ? 'num'+decimal : null;\n\t\t},\n\t\n\t\t// Dates (only those recognised by the browser's Date.parse)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\t// V8 tries _very_ hard to make a string passed into `Date.parse()`\n\t\t\t// valid, so we need to use a regex to restrict date formats. Use a\n\t\t\t// plug-in for anything other than ISO8601 style strings\n\t\t\tif ( d && !(d instanceof Date) && ! _re_date.test(d) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tvar parsed = Date.parse(d);\n\t\t\treturn (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;\n\t\t},\n\t\n\t\t// Formatted numbers\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;\n\t\t},\n\t\n\t\t// HTML numeric, formatted\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\tvar decimal = settings.oLanguage.sDecimal;\n\t\t\treturn _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;\n\t\t},\n\t\n\t\t// HTML (this is strict checking - there must be html)\n\t\tfunction ( d, settings )\n\t\t{\n\t\t\treturn _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?\n\t\t\t\t'html' : null;\n\t\t}\n\t] );\n\t\n\t\n\t\n\t// Filter formatting functions. See model.ext.ofnSearch for information about\n\t// what is required from these methods.\n\t// \n\t// Note that additional search methods are added for the html numbers and\n\t// html formatted numbers by `_addNumericSort()` when we know what the decimal\n\t// place is\n\t\n\t\n\t$.extend( DataTable.ext.type.search, {\n\t\thtml: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata\n\t\t\t\t\t\t.replace( _re_new_lines, \" \" )\n\t\t\t\t\t\t.replace( _re_html, \"\" ) :\n\t\t\t\t\t'';\n\t\t},\n\t\n\t\tstring: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\tdata :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata.replace( _re_new_lines, \" \" ) :\n\t\t\t\t\tdata;\n\t\t}\n\t} );\n\t\n\t\n\t\n\tvar __numericReplace = function ( d, decimalPlace, re1, re2 ) {\n\t\tif ( d !== 0 && (!d || d === '-') ) {\n\t\t\treturn -Infinity;\n\t\t}\n\t\n\t\t// If a decimal place other than `.` is used, it needs to be given to the\n\t\t// function so we can detect it and replace with a `.` which is the only\n\t\t// decimal place Javascript recognises - it is not locale aware.\n\t\tif ( decimalPlace ) {\n\t\t\td = _numToDecimal( d, decimalPlace );\n\t\t}\n\t\n\t\tif ( d.replace ) {\n\t\t\tif ( re1 ) {\n\t\t\t\td = d.replace( re1, '' );\n\t\t\t}\n\t\n\t\t\tif ( re2 ) {\n\t\t\t\td = d.replace( re2, '' );\n\t\t\t}\n\t\t}\n\t\n\t\treturn d * 1;\n\t};\n\t\n\t\n\t// Add the numeric 'deformatting' functions for sorting and search. This is done\n\t// in a function to provide an easy ability for the language options to add\n\t// additional methods if a non-period decimal place is used.\n\tfunction _addNumericSort ( decimalPlace ) {\n\t\t$.each(\n\t\t\t{\n\t\t\t\t// Plain numbers\n\t\t\t\t\"num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace );\n\t\t\t\t},\n\t\n\t\t\t\t// Formatted numbers\n\t\t\t\t\"num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_formatted_numeric );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric\n\t\t\t\t\"html-num\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html );\n\t\t\t\t},\n\t\n\t\t\t\t// HTML numeric, formatted\n\t\t\t\t\"html-num-fmt\": function ( d ) {\n\t\t\t\t\treturn __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );\n\t\t\t\t}\n\t\t\t},\n\t\t\tfunction ( key, fn ) {\n\t\t\t\t// Add the ordering method\n\t\t\t\t_ext.type.order[ key+decimalPlace+'-pre' ] = fn;\n\t\n\t\t\t\t// For HTML types add a search formatter that will strip the HTML\n\t\t\t\tif ( key.match(/^html\\-/) ) {\n\t\t\t\t\t_ext.type.search[ key+decimalPlace ] = _ext.type.search.html;\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\t\n\t\n\t// Default sort methods\n\t$.extend( _ext.type.order, {\n\t\t// Dates\n\t\t\"date-pre\": function ( d ) {\n\t\t\tvar ts = Date.parse( d );\n\t\t\treturn isNaN(ts) ? -Infinity : ts;\n\t\t},\n\t\n\t\t// html\n\t\t\"html-pre\": function ( a ) {\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ta.replace ?\n\t\t\t\t\ta.replace( /<.*?>/g, \"\" ).toLowerCase() :\n\t\t\t\t\ta+'';\n\t\t},\n\t\n\t\t// string\n\t\t\"string-pre\": function ( a ) {\n\t\t\t// This is a little complex, but faster than always calling toString,\n\t\t\t// http://jsperf.com/tostring-v-check\n\t\t\treturn _empty(a) ?\n\t\t\t\t'' :\n\t\t\t\ttypeof a === 'string' ?\n\t\t\t\t\ta.toLowerCase() :\n\t\t\t\t\t! a.toString ?\n\t\t\t\t\t\t'' :\n\t\t\t\t\t\ta.toString();\n\t\t},\n\t\n\t\t// string-asc and -desc are retained only for compatibility with the old\n\t\t// sort methods\n\t\t\"string-asc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t},\n\t\n\t\t\"string-desc\": function ( x, y ) {\n\t\t\treturn ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t}\n\t} );\n\t\n\t\n\t// Numeric sorting types - order doesn't matter here\n\t_addNumericSort( '' );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\theader: {\n\t\t\t_: function ( settings, cell, column, classes ) {\n\t\t\t\t// No additional mark-up required\n\t\t\t\t// Attach a sort listener to update on sort - note that using the\n\t\t\t\t// `DT` namespace will allow the event to be removed automatically\n\t\t\t\t// on destroy, while the `dt` namespaced event is the one we are\n\t\t\t\t// listening for\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) { // need to check this this is the host\n\t\t\t\t\t\treturn;               // table, not a nested one\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tcolumn.sSortingClass +' '+\n\t\t\t\t\t\t\tclasses.sSortAsc +' '+\n\t\t\t\t\t\t\tclasses.sSortDesc\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t},\n\t\n\t\t\tjqueryui: function ( settings, cell, column, classes ) {\n\t\t\t\t$('<div/>')\n\t\t\t\t\t.addClass( classes.sSortJUIWrapper )\n\t\t\t\t\t.append( cell.contents() )\n\t\t\t\t\t.append( $('<span/>')\n\t\t\t\t\t\t.addClass( classes.sSortIcon+' '+column.sSortingClassJUI )\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo( cell );\n\t\n\t\t\t\t// Attach a sort listener to update on sort\n\t\t\t\t$(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {\n\t\t\t\t\tif ( settings !== ctx ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar colIdx = column.idx;\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.find( 'span.'+classes.sSortIcon )\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tclasses.sSortJUIAsc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDesc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUI +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIAscAllowed +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDescAllowed\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ colIdx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortJUIAsc : columns[ colIdx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortJUIDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClassJUI\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t/*\n\t * Public helper functions. These aren't used internally by DataTables, or\n\t * called by any of the options passed into DataTables, but they can be used\n\t * externally by developers working with DataTables. They are helper functions\n\t * to make working with DataTables a little bit easier.\n\t */\n\t\n\tvar __htmlEscapeEntities = function ( d ) {\n\t\treturn typeof d === 'string' ?\n\t\t\td.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;') :\n\t\t\td;\n\t};\n\t\n\t/**\n\t * Helpers for `columns.render`.\n\t *\n\t * The options defined here can be used with the `columns.render` initialisation\n\t * option to provide a display renderer. The following functions are defined:\n\t *\n\t * * `number` - Will format numeric data (defined by `columns.data`) for\n\t *   display, retaining the original unformatted data for sorting and filtering.\n\t *   It takes 5 parameters:\n\t *   * `string` - Thousands grouping separator\n\t *   * `string` - Decimal point indicator\n\t *   * `integer` - Number of decimal points to show\n\t *   * `string` (optional) - Prefix.\n\t *   * `string` (optional) - Postfix (/suffix).\n\t * * `text` - Escape HTML to help prevent XSS attacks. It has no optional\n\t *   parameters.\n\t *\n\t * @example\n\t *   // Column definition using the number renderer\n\t *   {\n\t *     data: \"salary\",\n\t *     render: $.fn.dataTable.render.number( '\\'', '.', 0, '$' )\n\t *   }\n\t *\n\t * @namespace\n\t */\n\tDataTable.render = {\n\t\tnumber: function ( thousands, decimal, precision, prefix, postfix ) {\n\t\t\treturn {\n\t\t\t\tdisplay: function ( d ) {\n\t\t\t\t\tif ( typeof d !== 'number' && typeof d !== 'string' ) {\n\t\t\t\t\t\treturn d;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tvar negative = d < 0 ? '-' : '';\n\t\t\t\t\tvar flo = parseFloat( d );\n\t\n\t\t\t\t\t// If NaN then there isn't much formatting that we can do - just\n\t\t\t\t\t// return immediately, escaping any HTML (this was supposed to\n\t\t\t\t\t// be a number after all)\n\t\t\t\t\tif ( isNaN( flo ) ) {\n\t\t\t\t\t\treturn __htmlEscapeEntities( d );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tflo = flo.toFixed( precision );\n\t\t\t\t\td = Math.abs( flo );\n\t\n\t\t\t\t\tvar intPart = parseInt( d, 10 );\n\t\t\t\t\tvar floatPart = precision ?\n\t\t\t\t\t\tdecimal+(d - intPart).toFixed( precision ).substring( 2 ):\n\t\t\t\t\t\t'';\n\t\n\t\t\t\t\treturn negative + (prefix||'') +\n\t\t\t\t\t\tintPart.toString().replace(\n\t\t\t\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g, thousands\n\t\t\t\t\t\t) +\n\t\t\t\t\t\tfloatPart +\n\t\t\t\t\t\t(postfix||'');\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\n\t\ttext: function () {\n\t\t\treturn {\n\t\t\t\tdisplay: __htmlEscapeEntities\n\t\t\t};\n\t\t}\n\t};\n\t\n\t\n\t/*\n\t * This is really a good bit rubbish this method of exposing the internal methods\n\t * publicly... - To be fixed in 2.0 using methods on the prototype\n\t */\n\t\n\t\n\t/**\n\t * Create a wrapper function for exporting an internal functions to an external API.\n\t *  @param {string} fn API function name\n\t *  @returns {function} wrapped function\n\t *  @memberof DataTable#internal\n\t */\n\tfunction _fnExternApiFunc (fn)\n\t{\n\t\treturn function() {\n\t\t\tvar args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(\n\t\t\t\tArray.prototype.slice.call(arguments)\n\t\t\t);\n\t\t\treturn DataTable.ext.internal[fn].apply( this, args );\n\t\t};\n\t}\n\t\n\t\n\t/**\n\t * Reference to internal functions for use by plug-in developers. Note that\n\t * these methods are references to internal functions and are considered to be\n\t * private. If you use these methods, be aware that they are liable to change\n\t * between versions.\n\t *  @namespace\n\t */\n\t$.extend( DataTable.ext.internal, {\n\t\t_fnExternApiFunc: _fnExternApiFunc,\n\t\t_fnBuildAjax: _fnBuildAjax,\n\t\t_fnAjaxUpdate: _fnAjaxUpdate,\n\t\t_fnAjaxParameters: _fnAjaxParameters,\n\t\t_fnAjaxUpdateDraw: _fnAjaxUpdateDraw,\n\t\t_fnAjaxDataSrc: _fnAjaxDataSrc,\n\t\t_fnAddColumn: _fnAddColumn,\n\t\t_fnColumnOptions: _fnColumnOptions,\n\t\t_fnAdjustColumnSizing: _fnAdjustColumnSizing,\n\t\t_fnVisibleToColumnIndex: _fnVisibleToColumnIndex,\n\t\t_fnColumnIndexToVisible: _fnColumnIndexToVisible,\n\t\t_fnVisbleColumns: _fnVisbleColumns,\n\t\t_fnGetColumns: _fnGetColumns,\n\t\t_fnColumnTypes: _fnColumnTypes,\n\t\t_fnApplyColumnDefs: _fnApplyColumnDefs,\n\t\t_fnHungarianMap: _fnHungarianMap,\n\t\t_fnCamelToHungarian: _fnCamelToHungarian,\n\t\t_fnLanguageCompat: _fnLanguageCompat,\n\t\t_fnBrowserDetect: _fnBrowserDetect,\n\t\t_fnAddData: _fnAddData,\n\t\t_fnAddTr: _fnAddTr,\n\t\t_fnNodeToDataIndex: _fnNodeToDataIndex,\n\t\t_fnNodeToColumnIndex: _fnNodeToColumnIndex,\n\t\t_fnGetCellData: _fnGetCellData,\n\t\t_fnSetCellData: _fnSetCellData,\n\t\t_fnSplitObjNotation: _fnSplitObjNotation,\n\t\t_fnGetObjectDataFn: _fnGetObjectDataFn,\n\t\t_fnSetObjectDataFn: _fnSetObjectDataFn,\n\t\t_fnGetDataMaster: _fnGetDataMaster,\n\t\t_fnClearTable: _fnClearTable,\n\t\t_fnDeleteIndex: _fnDeleteIndex,\n\t\t_fnInvalidate: _fnInvalidate,\n\t\t_fnGetRowElements: _fnGetRowElements,\n\t\t_fnCreateTr: _fnCreateTr,\n\t\t_fnBuildHead: _fnBuildHead,\n\t\t_fnDrawHead: _fnDrawHead,\n\t\t_fnDraw: _fnDraw,\n\t\t_fnReDraw: _fnReDraw,\n\t\t_fnAddOptionsHtml: _fnAddOptionsHtml,\n\t\t_fnDetectHeader: _fnDetectHeader,\n\t\t_fnGetUniqueThs: _fnGetUniqueThs,\n\t\t_fnFeatureHtmlFilter: _fnFeatureHtmlFilter,\n\t\t_fnFilterComplete: _fnFilterComplete,\n\t\t_fnFilterCustom: _fnFilterCustom,\n\t\t_fnFilterColumn: _fnFilterColumn,\n\t\t_fnFilter: _fnFilter,\n\t\t_fnFilterCreateSearch: _fnFilterCreateSearch,\n\t\t_fnEscapeRegex: _fnEscapeRegex,\n\t\t_fnFilterData: _fnFilterData,\n\t\t_fnFeatureHtmlInfo: _fnFeatureHtmlInfo,\n\t\t_fnUpdateInfo: _fnUpdateInfo,\n\t\t_fnInfoMacros: _fnInfoMacros,\n\t\t_fnInitialise: _fnInitialise,\n\t\t_fnInitComplete: _fnInitComplete,\n\t\t_fnLengthChange: _fnLengthChange,\n\t\t_fnFeatureHtmlLength: _fnFeatureHtmlLength,\n\t\t_fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,\n\t\t_fnPageChange: _fnPageChange,\n\t\t_fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,\n\t\t_fnProcessingDisplay: _fnProcessingDisplay,\n\t\t_fnFeatureHtmlTable: _fnFeatureHtmlTable,\n\t\t_fnScrollDraw: _fnScrollDraw,\n\t\t_fnApplyToChildren: _fnApplyToChildren,\n\t\t_fnCalculateColumnWidths: _fnCalculateColumnWidths,\n\t\t_fnThrottle: _fnThrottle,\n\t\t_fnConvertToWidth: _fnConvertToWidth,\n\t\t_fnGetWidestNode: _fnGetWidestNode,\n\t\t_fnGetMaxLenString: _fnGetMaxLenString,\n\t\t_fnStringToCss: _fnStringToCss,\n\t\t_fnSortFlatten: _fnSortFlatten,\n\t\t_fnSort: _fnSort,\n\t\t_fnSortAria: _fnSortAria,\n\t\t_fnSortListener: _fnSortListener,\n\t\t_fnSortAttachListener: _fnSortAttachListener,\n\t\t_fnSortingClasses: _fnSortingClasses,\n\t\t_fnSortData: _fnSortData,\n\t\t_fnSaveState: _fnSaveState,\n\t\t_fnLoadState: _fnLoadState,\n\t\t_fnSettingsFromNode: _fnSettingsFromNode,\n\t\t_fnLog: _fnLog,\n\t\t_fnMap: _fnMap,\n\t\t_fnBindAction: _fnBindAction,\n\t\t_fnCallbackReg: _fnCallbackReg,\n\t\t_fnCallbackFire: _fnCallbackFire,\n\t\t_fnLengthOverflow: _fnLengthOverflow,\n\t\t_fnRenderer: _fnRenderer,\n\t\t_fnDataSource: _fnDataSource,\n\t\t_fnRowAttributes: _fnRowAttributes,\n\t\t_fnExtend: _fnExtend,\n\t\t_fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant\n\t\t                                // in 1.10, so this dead-end function is\n\t\t                                // added to prevent errors\n\t} );\n\t\n\n\t// jQuery access\n\t$.fn.dataTable = DataTable;\n\n\t// Provide access to the host jQuery object (circular reference)\n\tDataTable.$ = $;\n\n\t// Legacy aliases\n\t$.fn.dataTableSettings = DataTable.settings;\n\t$.fn.dataTableExt = DataTable.ext;\n\n\t// With a capital `D` we return a DataTables API instance rather than a\n\t// jQuery object\n\t$.fn.DataTable = function ( opts ) {\n\t\treturn $(this).dataTable( opts ).api();\n\t};\n\n\t// All properties that are available to $.fn.dataTable should also be\n\t// available on $.fn.DataTable\n\t$.each( DataTable, function ( prop, val ) {\n\t\t$.fn.DataTable[ prop ] = val;\n\t} );\n\n\n\t// Information about events fired by DataTables - for documentation.\n\t/**\n\t * Draw event, fired whenever the table is redrawn on the page, at the same\n\t * point as fnDrawCallback. This may be useful for binding events or\n\t * performing calculations when the table is altered at all.\n\t *  @name DataTable#draw.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Search event, fired when the searching applied to the table (using the\n\t * built-in global search, or column filters) is altered.\n\t *  @name DataTable#search.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page change event, fired when the paging of the table is altered.\n\t *  @name DataTable#page.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Order event, fired when the ordering applied to the table is altered.\n\t *  @name DataTable#order.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * DataTables initialisation complete event, fired when the table is fully\n\t * drawn, including Ajax data loaded, if Ajax data is required.\n\t *  @name DataTable#init.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The JSON object request from the server - only\n\t *    present if client-side Ajax sourced data is used</li></ol>\n\t */\n\n\t/**\n\t * State save event, fired when the table has changed state a new state save\n\t * is required. This event allows modification of the state saving object\n\t * prior to actually doing the save, including addition or other state\n\t * properties (for plug-ins) or modification of a DataTables core property.\n\t *  @name DataTable#stateSaveParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The state information to be saved\n\t */\n\n\t/**\n\t * State load event, fired when the table is loading state from the stored\n\t * data, but prior to the settings object being modified by the saved state\n\t * - allowing modification of the saved state is required or loading of\n\t * state for a plug-in.\n\t *  @name DataTable#stateLoadParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * State loaded event, fired when state has been loaded from stored data and\n\t * the settings object has been modified by the loaded data.\n\t *  @name DataTable#stateLoaded.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * Processing event, fired when DataTables is doing some kind of processing\n\t * (be it, order, searcg or anything else). It can be used to indicate to\n\t * the end user that there is something happening, or that something has\n\t * finished.\n\t *  @name DataTable#processing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {boolean} bShow Flag for if DataTables is doing processing or not\n\t */\n\n\t/**\n\t * Ajax (XHR) event, fired whenever an Ajax request is completed from a\n\t * request to made to the server for new data. This event is called before\n\t * DataTables processed the returned data, so it can also be used to pre-\n\t * process the data returned from the server, if needed.\n\t *\n\t * Note that this trigger is called in `fnServerData`, if you override\n\t * `fnServerData` and which to use this event, you need to trigger it in you\n\t * success function.\n\t *  @name DataTable#xhr.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {object} json JSON returned from the server\n\t *\n\t *  @example\n\t *     // Use a custom property returned from the server in another DOM element\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       $('#status').html( json.status );\n\t *     } );\n\t *\n\t *  @example\n\t *     // Pre-process the data returned from the server\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {\n\t *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;\n\t *       }\n\t *       // Note no return - manipulate the data directly in the JSON object.\n\t *     } );\n\t */\n\n\t/**\n\t * Destroy event, fired when the DataTable is destroyed by calling fnDestroy\n\t * or passing the bDestroy:true parameter in the initialisation object. This\n\t * can be used to remove bound events, added DOM nodes, etc.\n\t *  @name DataTable#destroy.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page length change event, fired when number of records to show on each\n\t * page (the length) is changed.\n\t *  @name DataTable#length.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {integer} len New length\n\t */\n\n\t/**\n\t * Column sizing has changed.\n\t *  @name DataTable#column-sizing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Column visibility has changed.\n\t *  @name DataTable#column-visibility.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {int} column Column index\n\t *  @param {bool} vis `false` if column now hidden, or `true` if visible\n\t */\n\n\treturn $.fn.dataTable;\n}));\n\n\n/*! DataTables Foundation integration\n * ©2011-2015 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * DataTables integration for Foundation. This requires Foundation 5 and\n * DataTables 1.10 or newer.\n *\n * This file sets the defaults and adds options to DataTables to style its\n * controls using Foundation. See http://datatables.net/manual/styling/foundation\n * for further information.\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n// Detect Foundation 5 / 6 as they have different element and class requirements\nvar meta = $('<meta class=\"foundation-mq\"/>').appendTo('head');\nDataTable.ext.foundationVersion = meta.css('font-family').match(/small|medium|large/) ? 6 : 5;\nmeta.remove();\n\n\n$.extend( DataTable.ext.classes, {\n\tsWrapper:    \"dataTables_wrapper dt-foundation\",\n\tsProcessing: \"dataTables_processing panel callout\"\n} );\n\n\n/* Set the defaults for DataTables initialisation */\n$.extend( true, DataTable.defaults, {\n\tdom:\n\t\t\"<'row grid-x'<'small-6 columns cell'l><'small-6 columns cell'f>r>\"+\n\t\t\"t\"+\n\t\t\"<'row grid-x'<'small-6 columns cell'i><'small-6 columns cell'p>>\",\n\trenderer: 'foundation'\n} );\n\n\n/* Page button renderer */\nDataTable.ext.renderer.pageButton.foundation = function ( settings, host, idx, buttons, page, pages ) {\n\tvar api = new DataTable.Api( settings );\n\tvar classes = settings.oClasses;\n\tvar lang = settings.oLanguage.oPaginate;\n\tvar aria = settings.oLanguage.oAria.paginate || {};\n\tvar btnDisplay, btnClass;\n\tvar tag;\n\tvar v5 = DataTable.ext.foundationVersion === 5;\n\n\tvar attach = function( container, buttons ) {\n\t\tvar i, ien, node, button;\n\t\tvar clickHandler = function ( e ) {\n\t\t\te.preventDefault();\n\t\t\tif ( !$(e.currentTarget).hasClass('unavailable') && api.page() != e.data.action ) {\n\t\t\t\tapi.page( e.data.action ).draw( 'page' );\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\tattach( container, button );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbtnDisplay = '';\n\t\t\t\tbtnClass = '';\n\t\t\t\ttag = null;\n\n\t\t\t\tswitch ( button ) {\n\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\tbtnDisplay = '&#x2026;';\n\t\t\t\t\t\tbtnClass = 'unavailable disabled';\n\t\t\t\t\t\ttag = null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'first':\n\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page > 0 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page > 0 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'next':\n\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page < pages-1 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'last':\n\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t'' : ' unavailable disabled');\n\t\t\t\t\t\ttag = page < pages-1 ? 'a' : null;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t'current' : '';\n\t\t\t\t\t\ttag = page === button ?\n\t\t\t\t\t\t\tnull : 'a';\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( v5 ) {\n\t\t\t\t\ttag = 'a';\n\t\t\t\t}\n\n\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\tnode = $('<li>', {\n\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t'aria-label': aria[ button ],\n\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.append( tag ?\n\t\t\t\t\t\t\t$('<'+tag+'/>', {'href': '#'} ).html( btnDisplay ) :\n\t\t\t\t\t\t\tbtnDisplay\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\tsettings.oApi._fnBindAction(\n\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\tattach(\n\t\t$(host).empty().html('<ul class=\"pagination\"/>').children('ul'),\n\t\tbuttons\n\t);\n};\n\n\nreturn DataTable;\n}));\n\n\n/*! AutoFill 2.3.3\n * ©2008-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     AutoFill\n * @description Add Excel like click and drag auto-fill options to DataTables\n * @version     2.3.3\n * @file        dataTables.autoFill.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2010-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar _instance = 0;\n\n/** \n * AutoFill provides Excel like auto-fill features for a DataTable\n *\n * @class AutoFill\n * @constructor\n * @param {object} oTD DataTables settings object\n * @param {object} oConfig Configuration object for AutoFill\n */\nvar AutoFill = function( dt, opts )\n{\n\tif ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {\n\t\tthrow( \"Warning: AutoFill requires DataTables 1.10.8 or greater\");\n\t}\n\n\t// User and defaults configuration object\n\tthis.c = $.extend( true, {},\n\t\tDataTable.defaults.autoFill,\n\t\tAutoFill.defaults,\n\t\topts\n\t);\n\n\t/**\n\t * @namespace Settings object which contains customisable information for AutoFill instance\n\t */\n\tthis.s = {\n\t\t/** @type {DataTable.Api} DataTables' API instance */\n\t\tdt: new DataTable.Api( dt ),\n\n\t\t/** @type {String} Unique namespace for events attached to the document */\n\t\tnamespace: '.autoFill'+(_instance++),\n\n\t\t/** @type {Object} Cached dimension information for use in the mouse move event handler */\n\t\tscroll: {},\n\n\t\t/** @type {integer} Interval object used for smooth scrolling */\n\t\tscrollInterval: null,\n\n\t\thandle: {\n\t\t\theight: 0,\n\t\t\twidth: 0\n\t\t},\n\n\t\t/**\n\t\t * Enabled setting\n\t\t * @type {Boolean}\n\t\t */\n\t\tenabled: false\n\t};\n\n\n\t/**\n\t * @namespace Common and useful DOM elements for the class instance\n\t */\n\tthis.dom = {\n\t\t/** @type {jQuery} AutoFill handle */\n\t\thandle: $('<div class=\"dt-autofill-handle\"/>'),\n\n\t\t/**\n\t\t * @type {Object} Selected cells outline - Need to use 4 elements,\n\t\t *   otherwise the mouse over if you back into the selected rectangle\n\t\t *   will be over that element, rather than the cells!\n\t\t */\n\t\tselect: {\n\t\t\ttop:    $('<div class=\"dt-autofill-select top\"/>'),\n\t\t\tright:  $('<div class=\"dt-autofill-select right\"/>'),\n\t\t\tbottom: $('<div class=\"dt-autofill-select bottom\"/>'),\n\t\t\tleft:   $('<div class=\"dt-autofill-select left\"/>')\n\t\t},\n\n\t\t/** @type {jQuery} Fill type chooser background */\n\t\tbackground: $('<div class=\"dt-autofill-background\"/>'),\n\n\t\t/** @type {jQuery} Fill type chooser */\n\t\tlist: $('<div class=\"dt-autofill-list\">'+this.s.dt.i18n('autoFill.info', '')+'<ul/></div>'),\n\n\t\t/** @type {jQuery} DataTables scrolling container */\n\t\tdtScroll: null,\n\n\t\t/** @type {jQuery} Offset parent element */\n\t\toffsetParent: null\n\t};\n\n\n\t/* Constructor logic */\n\tthis._constructor();\n};\n\n\n\n$.extend( AutoFill.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Public methods (exposed via the DataTables API below)\n\t */\n\tenabled: function ()\n\t{\n\t\treturn this.s.enabled;\n\t},\n\n\n\tenable: function ( flag )\n\t{\n\t\tvar that = this;\n\n\t\tif ( flag === false ) {\n\t\t\treturn this.disable();\n\t\t}\n\n\t\tthis.s.enabled = true;\n\n\t\tthis._focusListener();\n\n\t\tthis.dom.handle.on( 'mousedown', function (e) {\n\t\t\tthat._mousedown( e );\n\t\t\treturn false;\n\t\t} );\n\n\t\treturn this;\n\t},\n\n\tdisable: function ()\n\t{\n\t\tthis.s.enabled = false;\n\n\t\tthis._focusListenerRemove();\n\n\t\treturn this;\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\n\t/**\n\t * Initialise the RowReorder instance\n\t *\n\t * @private\n\t */\n\t_constructor: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar dtScroll = $('div.dataTables_scrollBody', this.s.dt.table().container());\n\n\t\t// Make the instance accessible to the API\n\t\tdt.settings()[0].autoFill = this;\n\n\t\tif ( dtScroll.length ) {\n\t\t\tthis.dom.dtScroll = dtScroll;\n\n\t\t\t// Need to scroll container to be the offset parent\n\t\t\tif ( dtScroll.css('position') === 'static' ) {\n\t\t\t\tdtScroll.css( 'position', 'relative' );\n\t\t\t}\n\t\t}\n\n\t\tif ( this.c.enable !== false ) {\n\t\t\tthis.enable();\n\t\t}\n\n\t\tdt.on( 'destroy.autoFill', function () {\n\t\t\tthat._focusListenerRemove();\n\t\t} );\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\n\t/**\n\t * Display the AutoFill drag handle by appending it to a table cell. This\n\t * is the opposite of the _detach method.\n\t *\n\t * @param  {node} node TD/TH cell to insert the handle into\n\t * @private\n\t */\n\t_attach: function ( node )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar idx = dt.cell( node ).index();\n\t\tvar handle = this.dom.handle;\n\t\tvar handleDim = this.s.handle;\n\n\t\tif ( ! idx || dt.columns( this.c.columns ).indexes().indexOf( idx.column ) === -1 ) {\n\t\t\tthis._detach();\n\t\t\treturn;\n\t\t}\n\n\t\tif ( ! this.dom.offsetParent ) {\n\t\t\t// We attach to the table's offset parent\n\t\t\tthis.dom.offsetParent = $( dt.table().node() ).offsetParent();\n\t\t}\n\n\t\tif ( ! handleDim.height || ! handleDim.width ) {\n\t\t\t// Append to document so we can get its size. Not expecting it to\n\t\t\t// change during the life time of the page\n\t\t\thandle.appendTo( 'body' );\n\t\t\thandleDim.height = handle.outerHeight();\n\t\t\thandleDim.width = handle.outerWidth();\n\t\t}\n\n\t\t// Might need to go through multiple offset parents\n\t\tvar offset = this._getPosition( node, this.dom.offsetParent );\n\n\t\tthis.dom.attachedTo = node;\n\t\thandle\n\t\t\t.css( {\n\t\t\t\ttop: offset.top + node.offsetHeight - handleDim.height,\n\t\t\t\tleft: offset.left + node.offsetWidth - handleDim.width\n\t\t\t} )\n\t\t\t.appendTo( this.dom.offsetParent );\n\t},\n\n\n\t/**\n\t * Determine can the fill type should be. This can be automatic, or ask the\n\t * end user.\n\t *\n\t * @param {array} cells Information about the selected cells from the key\n\t *     up function\n\t * @private\n\t */\n\t_actionSelector: function ( cells )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar actions = AutoFill.actions;\n\t\tvar available = [];\n\n\t\t// \"Ask\" each plug-in if it wants to handle this data\n\t\t$.each( actions, function ( key, action ) {\n\t\t\tif ( action.available( dt, cells ) ) {\n\t\t\t\tavailable.push( key );\n\t\t\t}\n\t\t} );\n\n\t\tif ( available.length === 1 && this.c.alwaysAsk === false ) {\n\t\t\t// Only one action available - enact it immediately\n\t\t\tvar result = actions[ available[0] ].execute( dt, cells );\n\t\t\tthis._update( result, cells );\n\t\t}\n\t\telse {\n\t\t\t// Multiple actions available - ask the end user what they want to do\n\t\t\tvar list = this.dom.list.children('ul').empty();\n\n\t\t\t// Add a cancel option\n\t\t\tavailable.push( 'cancel' );\n\n\t\t\t$.each( available, function ( i, name ) {\n\t\t\t\tlist.append( $('<li/>')\n\t\t\t\t\t.append(\n\t\t\t\t\t\t'<div class=\"dt-autofill-question\">'+\n\t\t\t\t\t\t\tactions[ name ].option( dt, cells )+\n\t\t\t\t\t\t'<div>'\n\t\t\t\t\t)\n\t\t\t\t\t.append( $('<div class=\"dt-autofill-button\">' )\n\t\t\t\t\t\t.append( $('<button class=\"'+AutoFill.classes.btn+'\">'+dt.i18n('autoFill.button', '&gt;')+'</button>')\n\t\t\t\t\t\t\t.on( 'click', function () {\n\t\t\t\t\t\t\t\tvar result = actions[ name ].execute(\n\t\t\t\t\t\t\t\t\tdt, cells, $(this).closest('li')\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tthat._update( result, cells );\n\n\t\t\t\t\t\t\t\tthat.dom.background.remove();\n\t\t\t\t\t\t\t\tthat.dom.list.remove();\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} );\n\n\t\t\tthis.dom.background.appendTo( 'body' );\n\t\t\tthis.dom.list.appendTo( 'body' );\n\n\t\t\tthis.dom.list.css( 'margin-top', this.dom.list.outerHeight()/2 * -1 );\n\t\t}\n\t},\n\n\n\t/**\n\t * Remove the AutoFill handle from the document\n\t *\n\t * @private\n\t */\n\t_detach: function ()\n\t{\n\t\tthis.dom.attachedTo = null;\n\t\tthis.dom.handle.detach();\n\t},\n\n\n\t/**\n\t * Draw the selection outline by calculating the range between the start\n\t * and end cells, then placing the highlighting elements to draw a rectangle\n\t *\n\t * @param  {node}   target End cell\n\t * @param  {object} e      Originating event\n\t * @private\n\t */\n\t_drawSelection: function ( target, e )\n\t{\n\t\t// Calculate boundary for start cell to this one\n\t\tvar dt = this.s.dt;\n\t\tvar start = this.s.start;\n\t\tvar startCell = $(this.dom.start);\n\t\tvar end = {\n\t\t\trow: this.c.vertical ?\n\t\t\t\tdt.rows( { page: 'current' } ).nodes().indexOf( target.parentNode ) :\n\t\t\t\tstart.row,\n\t\t\tcolumn: this.c.horizontal ?\n\t\t\t\t$(target).index() :\n\t\t\t\tstart.column\n\t\t};\n\t\tvar colIndx = dt.column.index( 'toData', end.column );\n\t\tvar endRow =  dt.row( ':eq('+end.row+')', { page: 'current' } ); // Workaround for M581\n\t\tvar endCell = $( dt.cell( endRow.index(), colIndx ).node() );\n\n\t\t// Be sure that is a DataTables controlled cell\n\t\tif ( ! dt.cell( endCell ).any() ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// if target is not in the columns available - do nothing\n\t\tif ( dt.columns( this.c.columns ).indexes().indexOf( colIndx ) === -1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.s.end = end;\n\n\t\tvar top, bottom, left, right, height, width;\n\n\t\ttop    = start.row    < end.row    ? startCell : endCell;\n\t\tbottom = start.row    < end.row    ? endCell   : startCell;\n\t\tleft   = start.column < end.column ? startCell : endCell;\n\t\tright  = start.column < end.column ? endCell   : startCell;\n\n\t\ttop    = this._getPosition( top.get(0) ).top;\n\t\tleft   = this._getPosition( left.get(0) ).left;\n\t\theight = this._getPosition( bottom.get(0) ).top + bottom.outerHeight() - top;\n\t\twidth  = this._getPosition( right.get(0) ).left + right.outerWidth() - left;\n\n\t\tvar select = this.dom.select;\n\t\tselect.top.css( {\n\t\t\ttop: top,\n\t\t\tleft: left,\n\t\t\twidth: width\n\t\t} );\n\n\t\tselect.left.css( {\n\t\t\ttop: top,\n\t\t\tleft: left,\n\t\t\theight: height\n\t\t} );\n\n\t\tselect.bottom.css( {\n\t\t\ttop: top + height,\n\t\t\tleft: left,\n\t\t\twidth: width\n\t\t} );\n\n\t\tselect.right.css( {\n\t\t\ttop: top,\n\t\t\tleft: left + width,\n\t\t\theight: height\n\t\t} );\n\t},\n\n\n\t/**\n\t * Use the Editor API to perform an update based on the new data for the\n\t * cells\n\t *\n\t * @param {array} cells Information about the selected cells from the key\n\t *     up function\n\t * @private\n\t */\n\t_editor: function ( cells )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar editor = this.c.editor;\n\n\t\tif ( ! editor ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Build the object structure for Editor's multi-row editing\n\t\tvar idValues = {};\n\t\tvar nodes = [];\n\t\tvar fields = editor.fields();\n\n\t\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\tfor ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {\n\t\t\t\tvar cell = cells[i][j];\n\n\t\t\t\t// Determine the field name for the cell being edited\n\t\t\t\tvar col = dt.settings()[0].aoColumns[ cell.index.column ];\n\t\t\t\tvar fieldName = col.editField;\n\n\t\t\t\tif ( fieldName === undefined ) {\n\t\t\t\t\tvar dataSrc = col.mData;\n\n\t\t\t\t\t// dataSrc is the `field.data` property, but we need to set\n\t\t\t\t\t// using the field name, so we need to translate from the\n\t\t\t\t\t// data to the name\n\t\t\t\t\tfor ( var k=0, ken=fields.length ; k<ken ; k++ ) {\n\t\t\t\t\t\tvar field = editor.field( fields[k] );\n\n\t\t\t\t\t\tif ( field.dataSrc() === dataSrc ) {\n\t\t\t\t\t\t\tfieldName = field.name();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( ! fieldName ) {\n\t\t\t\t\tthrow 'Could not automatically determine field data. '+\n\t\t\t\t\t\t'Please see https://datatables.net/tn/11';\n\t\t\t\t}\n\n\t\t\t\tif ( ! idValues[ fieldName ] ) {\n\t\t\t\t\tidValues[ fieldName ] = {};\n\t\t\t\t}\n\n\t\t\t\tvar id = dt.row( cell.index.row ).id();\n\t\t\t\tidValues[ fieldName ][ id ] = cell.set;\n\n\t\t\t\t// Keep a list of cells so we can activate the bubble editing\n\t\t\t\t// with them\n\t\t\t\tnodes.push( cell.index );\n\t\t\t}\n\t\t}\n\n\t\t// Perform the edit using bubble editing as it allows us to specify\n\t\t// the cells to be edited, rather than using full rows\n\t\teditor\n\t\t\t.bubble( nodes, false )\n\t\t\t.multiSet( idValues )\n\t\t\t.submit();\n\t},\n\n\n\t/**\n\t * Emit an event on the DataTable for listeners\n\t *\n\t * @param  {string} name Event name\n\t * @param  {array} args Event arguments\n\t * @private\n\t */\n\t_emitEvent: function ( name, args )\n\t{\n\t\tthis.s.dt.iterator( 'table', function ( ctx, i ) {\n\t\t\t$(ctx.nTable).triggerHandler( name+'.dt', args );\n\t\t} );\n\t},\n\n\n\t/**\n\t * Attach suitable listeners (based on the configuration) that will attach\n\t * and detach the AutoFill handle in the document.\n\t *\n\t * @private\n\t */\n\t_focusListener: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar namespace = this.s.namespace;\n\t\tvar focus = this.c.focus !== null ?\n\t\t\tthis.c.focus :\n\t\t\tdt.init().keys || dt.settings()[0].keytable ?\n\t\t\t\t'focus' :\n\t\t\t\t'hover';\n\n\t\t// All event listeners attached here are removed in the `destroy`\n\t\t// callback in the constructor\n\t\tif ( focus === 'focus' ) {\n\t\t\tdt\n\t\t\t\t.on( 'key-focus.autoFill', function ( e, dt, cell ) {\n\t\t\t\t\tthat._attach( cell.node() );\n\t\t\t\t} )\n\t\t\t\t.on( 'key-blur.autoFill', function ( e, dt, cell ) {\n\t\t\t\t\tthat._detach();\n\t\t\t\t} );\n\t\t}\n\t\telse if ( focus === 'click' ) {\n\t\t\t$(dt.table().body()).on( 'click'+namespace, 'td, th', function (e) {\n\t\t\t\tthat._attach( this );\n\t\t\t} );\n\n\t\t\t$(document.body).on( 'click'+namespace, function (e) {\n\t\t\t\tif ( ! $(e.target).parents().filter( dt.table().body() ).length ) {\n\t\t\t\t\tthat._detach();\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\telse {\n\t\t\t$(dt.table().body())\n\t\t\t\t.on( 'mouseenter'+namespace, 'td, th', function (e) {\n\t\t\t\t\tthat._attach( this );\n\t\t\t\t} )\n\t\t\t\t.on( 'mouseleave'+namespace, function (e) {\n\t\t\t\t\tif ( $(e.relatedTarget).hasClass('dt-autofill-handle') ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tthat._detach();\n\t\t\t\t} );\n\t\t}\n\t},\n\n\n\t_focusListenerRemove: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\n\t\tdt.off( '.autoFill' );\n\t\t$(dt.table().body()).off( this.s.namespace );\n\t\t$(document.body).off( this.s.namespace );\n\t},\n\n\n\t/**\n\t * Get the position of a node, relative to another, including any scrolling\n\t * offsets.\n\t * @param  {Node}   node         Node to get the position of\n\t * @param  {jQuery} targetParent Node to use as the parent\n\t * @return {object}              Offset calculation\n\t * @private\n\t */\n\t_getPosition: function ( node, targetParent )\n\t{\n\t\tvar\n\t\t\tcurrNode = node,\n\t\t\tcurrOffsetParent,\n\t\t\ttop = 0,\n\t\t\tleft = 0;\n\n\t\tif ( ! targetParent ) {\n\t\t\ttargetParent = $( $( this.s.dt.table().node() )[0].offsetParent );\n\t\t}\n\n\t\tdo {\n\t\t\t// Don't use jQuery().position() the behaviour changes between 1.x and 3.x for\n\t\t\t// tables\n\t\t\tvar positionTop = currNode.offsetTop;\n\t\t\tvar positionLeft = currNode.offsetLeft;\n\n\t\t\t// jQuery doesn't give a `table` as the offset parent oddly, so use DOM directly\n\t\t\tcurrOffsetParent = $( currNode.offsetParent );\n\n\t\t\ttop += positionTop + currOffsetParent.scrollTop();\n\t\t\tleft += positionLeft + currOffsetParent.scrollLeft();\n\n\t\t\ttop += parseInt( currOffsetParent.css('margin-top') ) * 1;\n\t\t\ttop += parseInt( currOffsetParent.css('border-top-width') ) * 1;\n\n\t\t\t// Emergency fall back. Shouldn't happen, but just in case!\n\t\t\tif ( currNode.nodeName.toLowerCase() === 'body' ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcurrNode = currOffsetParent.get(0); // for next loop\n\t\t}\n\t\twhile ( currOffsetParent.get(0) !== targetParent.get(0) )\n\n\t\treturn {\n\t\t\ttop: top,\n\t\t\tleft: left\n\t\t};\n\t},\n\n\n\t/**\n\t * Start mouse drag - selects the start cell\n\t *\n\t * @param  {object} e Mouse down event\n\t * @private\n\t */\n\t_mousedown: function ( e )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\n\t\tthis.dom.start = this.dom.attachedTo;\n\t\tthis.s.start = {\n\t\t\trow: dt.rows( { page: 'current' } ).nodes().indexOf( $(this.dom.start).parent()[0] ),\n\t\t\tcolumn: $(this.dom.start).index()\n\t\t};\n\n\t\t$(document.body)\n\t\t\t.on( 'mousemove.autoFill', function (e) {\n\t\t\t\tthat._mousemove( e );\n\t\t\t} )\n\t\t\t.on( 'mouseup.autoFill', function (e) {\n\t\t\t\tthat._mouseup( e );\n\t\t\t} );\n\n\t\tvar select = this.dom.select;\n\t\tvar offsetParent = $( dt.table().node() ).offsetParent();\n\t\tselect.top.appendTo( offsetParent );\n\t\tselect.left.appendTo( offsetParent );\n\t\tselect.right.appendTo( offsetParent );\n\t\tselect.bottom.appendTo( offsetParent );\n\n\t\tthis._drawSelection( this.dom.start, e );\n\n\t\tthis.dom.handle.css( 'display', 'none' );\n\n\t\t// Cache scrolling information so mouse move doesn't need to read.\n\t\t// This assumes that the window and DT scroller will not change size\n\t\t// during an AutoFill drag, which I think is a fair assumption\n\t\tvar scrollWrapper = this.dom.dtScroll;\n\t\tthis.s.scroll = {\n\t\t\twindowHeight: $(window).height(),\n\t\t\twindowWidth:  $(window).width(),\n\t\t\tdtTop:        scrollWrapper ? scrollWrapper.offset().top : null,\n\t\t\tdtLeft:       scrollWrapper ? scrollWrapper.offset().left : null,\n\t\t\tdtHeight:     scrollWrapper ? scrollWrapper.outerHeight() : null,\n\t\t\tdtWidth:      scrollWrapper ? scrollWrapper.outerWidth() : null\n\t\t};\n\t},\n\n\n\t/**\n\t * Mouse drag - selects the end cell and update the selection display for\n\t * the end user\n\t *\n\t * @param  {object} e Mouse move event\n\t * @private\n\t */\n\t_mousemove: function ( e )\n\t{\t\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar name = e.target.nodeName.toLowerCase();\n\t\tif ( name !== 'td' && name !== 'th' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._drawSelection( e.target, e );\n\t\tthis._shiftScroll( e );\n\t},\n\n\n\t/**\n\t * End mouse drag - perform the update actions\n\t *\n\t * @param  {object} e Mouse up event\n\t * @private\n\t */\n\t_mouseup: function ( e )\n\t{\n\t\t$(document.body).off( '.autoFill' );\n\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar select = this.dom.select;\n\t\tselect.top.remove();\n\t\tselect.left.remove();\n\t\tselect.right.remove();\n\t\tselect.bottom.remove();\n\n\t\tthis.dom.handle.css( 'display', 'block' );\n\n\t\t// Display complete - now do something useful with the selection!\n\t\tvar start = this.s.start;\n\t\tvar end = this.s.end;\n\n\t\t// Haven't selected multiple cells, so nothing to do\n\t\tif ( start.row === end.row && start.column === end.column ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar startDt = dt.cell( ':eq('+start.row+')', start.column+':visible', {page:'current'} );\n\n\t\t// If Editor is active inside this cell (inline editing) we need to wait for Editor to\n\t\t// submit and then we can loop back and trigger the fill.\n\t\tif ( $('div.DTE', startDt.node()).length ) {\n\t\t\tvar editor = dt.editor();\n\n\t\t\teditor\n\t\t\t\t.on( 'submitSuccess.dtaf close.dtaf', function () {\n\t\t\t\t\teditor.off( '.dtaf');\n\n\t\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t\tthat._mouseup( e );\n\t\t\t\t\t}, 100 );\n\t\t\t\t} )\n\t\t\t\t.on( 'submitComplete.dtaf preSubmitCancelled.dtaf close.dtaf', function () {\n\t\t\t\t\teditor.off( '.dtaf');\n\t\t\t\t} );\n\n\t\t\t// Make the current input submit\n\t\t\teditor.submit();\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Build a matrix representation of the selected rows\n\t\tvar rows       = this._range( start.row, end.row );\n\t\tvar columns    = this._range( start.column, end.column );\n\t\tvar selected   = [];\n\t\tvar dtSettings = dt.settings()[0];\n\t\tvar dtColumns  = dtSettings.aoColumns;\n\n\t\t// Can't use Array.prototype.map as IE8 doesn't support it\n\t\t// Can't use $.map as jQuery flattens 2D arrays\n\t\t// Need to use a good old fashioned for loop\n\t\tfor ( var rowIdx=0 ; rowIdx<rows.length ; rowIdx++ ) {\n\t\t\tselected.push(\n\t\t\t\t$.map( columns, function (column) {\n\t\t\t\t\tvar row = dt.row( ':eq('+rows[rowIdx]+')', {page:'current'} ); // Workaround for M581\n\t\t\t\t\tvar cell = dt.cell( row.index(), column+':visible' );\n\t\t\t\t\tvar data = cell.data();\n\t\t\t\t\tvar cellIndex = cell.index();\n\t\t\t\t\tvar editField = dtColumns[ cellIndex.column ].editField;\n\n\t\t\t\t\tif ( editField !== undefined ) {\n\t\t\t\t\t\tdata = dtSettings.oApi._fnGetObjectDataFn( editField )( dt.row( cellIndex.row ).data() );\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcell:  cell,\n\t\t\t\t\t\tdata:  data,\n\t\t\t\t\t\tlabel: cell.data(),\n\t\t\t\t\t\tindex: cellIndex\n\t\t\t\t\t};\n\t\t\t\t} )\n\t\t\t);\n\t\t}\n\n\t\tthis._actionSelector( selected );\n\t\t\n\t\t// Stop shiftScroll\n\t\tclearInterval( this.s.scrollInterval );\n\t\tthis.s.scrollInterval = null;\n\t},\n\n\n\t/**\n\t * Create an array with a range of numbers defined by the start and end\n\t * parameters passed in (inclusive!).\n\t * \n\t * @param  {integer} start Start\n\t * @param  {integer} end   End\n\t * @private\n\t */\n\t_range: function ( start, end )\n\t{\n\t\tvar out = [];\n\t\tvar i;\n\n\t\tif ( start <= end ) {\n\t\t\tfor ( i=start ; i<=end ; i++ ) {\n\t\t\t\tout.push( i );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( i=start ; i>=end ; i-- ) {\n\t\t\t\tout.push( i );\n\t\t\t}\n\t\t}\n\n\t\treturn out;\n\t},\n\n\n\t/**\n\t * Move the window and DataTables scrolling during a drag to scroll new\n\t * content into view. This is done by proximity to the edge of the scrolling\n\t * container of the mouse - for example near the top edge of the window\n\t * should scroll up. This is a little complicated as there are two elements\n\t * that can be scrolled - the window and the DataTables scrolling view port\n\t * (if scrollX and / or scrollY is enabled).\n\t *\n\t * @param  {object} e Mouse move event object\n\t * @private\n\t */\n\t_shiftScroll: function ( e )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar scroll = this.s.scroll;\n\t\tvar runInterval = false;\n\t\tvar scrollSpeed = 5;\n\t\tvar buffer = 65;\n\t\tvar\n\t\t\twindowY = e.pageY - document.body.scrollTop,\n\t\t\twindowX = e.pageX - document.body.scrollLeft,\n\t\t\twindowVert, windowHoriz,\n\t\t\tdtVert, dtHoriz;\n\n\t\t// Window calculations - based on the mouse position in the window,\n\t\t// regardless of scrolling\n\t\tif ( windowY < buffer ) {\n\t\t\twindowVert = scrollSpeed * -1;\n\t\t}\n\t\telse if ( windowY > scroll.windowHeight - buffer ) {\n\t\t\twindowVert = scrollSpeed;\n\t\t}\n\n\t\tif ( windowX < buffer ) {\n\t\t\twindowHoriz = scrollSpeed * -1;\n\t\t}\n\t\telse if ( windowX > scroll.windowWidth - buffer ) {\n\t\t\twindowHoriz = scrollSpeed;\n\t\t}\n\n\t\t// DataTables scrolling calculations - based on the table's position in\n\t\t// the document and the mouse position on the page\n\t\tif ( scroll.dtTop !== null && e.pageY < scroll.dtTop + buffer ) {\n\t\t\tdtVert = scrollSpeed * -1;\n\t\t}\n\t\telse if ( scroll.dtTop !== null && e.pageY > scroll.dtTop + scroll.dtHeight - buffer ) {\n\t\t\tdtVert = scrollSpeed;\n\t\t}\n\n\t\tif ( scroll.dtLeft !== null && e.pageX < scroll.dtLeft + buffer ) {\n\t\t\tdtHoriz = scrollSpeed * -1;\n\t\t}\n\t\telse if ( scroll.dtLeft !== null && e.pageX > scroll.dtLeft + scroll.dtWidth - buffer ) {\n\t\t\tdtHoriz = scrollSpeed;\n\t\t}\n\n\t\t// This is where it gets interesting. We want to continue scrolling\n\t\t// without requiring a mouse move, so we need an interval to be\n\t\t// triggered. The interval should continue until it is no longer needed,\n\t\t// but it must also use the latest scroll commands (for example consider\n\t\t// that the mouse might move from scrolling up to scrolling left, all\n\t\t// with the same interval running. We use the `scroll` object to \"pass\"\n\t\t// this information to the interval. Can't use local variables as they\n\t\t// wouldn't be the ones that are used by an already existing interval!\n\t\tif ( windowVert || windowHoriz || dtVert || dtHoriz ) {\n\t\t\tscroll.windowVert = windowVert;\n\t\t\tscroll.windowHoriz = windowHoriz;\n\t\t\tscroll.dtVert = dtVert;\n\t\t\tscroll.dtHoriz = dtHoriz;\n\t\t\trunInterval = true;\n\t\t}\n\t\telse if ( this.s.scrollInterval ) {\n\t\t\t// Don't need to scroll - remove any existing timer\n\t\t\tclearInterval( this.s.scrollInterval );\n\t\t\tthis.s.scrollInterval = null;\n\t\t}\n\n\t\t// If we need to run the interval to scroll and there is no existing\n\t\t// interval (if there is an existing one, it will continue to run)\n\t\tif ( ! this.s.scrollInterval && runInterval ) {\n\t\t\tthis.s.scrollInterval = setInterval( function () {\n\t\t\t\t// Don't need to worry about setting scroll <0 or beyond the\n\t\t\t\t// scroll bound as the browser will just reject that.\n\t\t\t\tif ( scroll.windowVert ) {\n\t\t\t\t\tdocument.body.scrollTop += scroll.windowVert;\n\t\t\t\t}\n\t\t\t\tif ( scroll.windowHoriz ) {\n\t\t\t\t\tdocument.body.scrollLeft += scroll.windowHoriz;\n\t\t\t\t}\n\n\t\t\t\t// DataTables scrolling\n\t\t\t\tif ( scroll.dtVert || scroll.dtHoriz ) {\n\t\t\t\t\tvar scroller = that.dom.dtScroll[0];\n\n\t\t\t\t\tif ( scroll.dtVert ) {\n\t\t\t\t\t\tscroller.scrollTop += scroll.dtVert;\n\t\t\t\t\t}\n\t\t\t\t\tif ( scroll.dtHoriz ) {\n\t\t\t\t\t\tscroller.scrollLeft += scroll.dtHoriz;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, 20 );\n\t\t}\n\t},\n\n\n\t/**\n\t * Update the DataTable after the user has selected what they want to do\n\t *\n\t * @param  {false|undefined} result Return from the `execute` method - can\n\t *   be false internally to do nothing. This is not documented for plug-ins\n\t *   and is used only by the cancel option.\n\t * @param {array} cells Information about the selected cells from the key\n\t *     up function, argumented with the set values\n\t * @private\n\t */\n\t_update: function ( result, cells )\n\t{\n\t\t// Do nothing on `false` return from an execute function\n\t\tif ( result === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar dt = this.s.dt;\n\t\tvar cell;\n\t\tvar columns = dt.columns( this.c.columns ).indexes();\n\n\t\t// Potentially allow modifications to the cells matrix\n\t\tthis._emitEvent( 'preAutoFill', [ dt, cells ] );\n\n\t\tthis._editor( cells );\n\n\t\t// Automatic updates are not performed if `update` is null and the\n\t\t// `editor` parameter is passed in - the reason being that Editor will\n\t\t// update the data once submitted\n\t\tvar update = this.c.update !== null ?\n\t\t\tthis.c.update :\n\t\t\tthis.c.editor ?\n\t\t\t\tfalse :\n\t\t\t\ttrue;\n\n\t\tif ( update ) {\n\t\t\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tfor ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {\n\t\t\t\t\tcell = cells[i][j];\n\n\t\t\t\t\tif ( columns.indexOf(cell.index.column) !== -1 ) {\n\t\t\t\t\t\tcell.cell.data( cell.set );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdt.draw(false);\n\t\t}\n\n\t\tthis._emitEvent( 'autoFill', [ dt, cells ] );\n\t}\n} );\n\n\n/**\n * AutoFill actions. The options here determine how AutoFill will fill the data\n * in the table when the user has selected a range of cells. Please see the\n * documentation on the DataTables site for full details on how to create plug-\n * ins.\n *\n * @type {Object}\n */\nAutoFill.actions = {\n\tincrement: {\n\t\tavailable: function ( dt, cells ) {\n\t\t\tvar d = cells[0][0].label;\n\n\t\t\t// is numeric test based on jQuery's old `isNumeric` function\n\t\t\treturn !isNaN( d - parseFloat( d ) );\n\t\t},\n\n\t\toption: function ( dt, cells ) {\n\t\t\treturn dt.i18n(\n\t\t\t\t'autoFill.increment',\n\t\t\t\t'Increment / decrement each cell by: <input type=\"number\" value=\"1\">'\n\t\t\t);\n\t\t},\n\n\t\texecute: function ( dt, cells, node ) {\n\t\t\tvar value = cells[0][0].data * 1;\n\t\t\tvar increment = $('input', node).val() * 1;\n\n\t\t\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tfor ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {\n\t\t\t\t\tcells[i][j].set = value;\n\n\t\t\t\t\tvalue += increment;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tfill: {\n\t\tavailable: function ( dt, cells ) {\n\t\t\treturn true;\n\t\t},\n\n\t\toption: function ( dt, cells ) {\n\t\t\treturn dt.i18n('autoFill.fill', 'Fill all cells with <i>'+cells[0][0].label+'</i>' );\n\t\t},\n\n\t\texecute: function ( dt, cells, node ) {\n\t\t\tvar value = cells[0][0].data;\n\n\t\t\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tfor ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {\n\t\t\t\t\tcells[i][j].set = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tfillHorizontal: {\n\t\tavailable: function ( dt, cells ) {\n\t\t\treturn cells.length > 1 && cells[0].length > 1;\n\t\t},\n\n\t\toption: function ( dt, cells ) {\n\t\t\treturn dt.i18n('autoFill.fillHorizontal', 'Fill cells horizontally' );\n\t\t},\n\n\t\texecute: function ( dt, cells, node ) {\n\t\t\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tfor ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {\n\t\t\t\t\tcells[i][j].set = cells[i][0].data;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tfillVertical: {\n\t\tavailable: function ( dt, cells ) {\n\t\t\treturn cells.length > 1 && cells[0].length > 1;\n\t\t},\n\n\t\toption: function ( dt, cells ) {\n\t\t\treturn dt.i18n('autoFill.fillVertical', 'Fill cells vertically' );\n\t\t},\n\n\t\texecute: function ( dt, cells, node ) {\n\t\t\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tfor ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {\n\t\t\t\t\tcells[i][j].set = cells[0][j].data;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Special type that does not make itself available, but is added\n\t// automatically by AutoFill if a multi-choice list is shown. This allows\n\t// sensible code reuse\n\tcancel: {\n\t\tavailable: function () {\n\t\t\treturn false;\n\t\t},\n\n\t\toption: function ( dt ) {\n\t\t\treturn dt.i18n('autoFill.cancel', 'Cancel' );\n\t\t},\n\n\t\texecute: function () {\n\t\t\treturn false;\n\t\t}\n\t}\n};\n\n\n/**\n * AutoFill version\n * \n * @static\n * @type      String\n */\nAutoFill.version = '2.3.3';\n\n\n/**\n * AutoFill defaults\n * \n * @namespace\n */\nAutoFill.defaults = {\n\t/** @type {Boolean} Ask user what they want to do, even for a single option */\n\talwaysAsk: false,\n\n\t/** @type {string|null} What will trigger a focus */\n\tfocus: null, // focus, click, hover\n\n\t/** @type {column-selector} Columns to provide auto fill for */\n\tcolumns: '', // all\n\n\t/** @type {Boolean} Enable AutoFill on load */\n\tenable: true,\n\n\t/** @type {boolean|null} Update the cells after a drag */\n\tupdate: null, // false is editor given, true otherwise\n\n\t/** @type {DataTable.Editor} Editor instance for automatic submission */\n\teditor: null,\n\n\t/** @type {boolean} Enable vertical fill */\n\tvertical: true,\n\n\t/** @type {boolean} Enable horizontal fill */\n\thorizontal: true\n};\n\n\n/**\n * Classes used by AutoFill that are configurable\n * \n * @namespace\n */\nAutoFill.classes = {\n\t/** @type {String} Class used by the selection button */\n\tbtn: 'btn'\n};\n\n\n/*\n * API\n */\nvar Api = $.fn.dataTable.Api;\n\n// Doesn't do anything - Not documented\nApi.register( 'autoFill()', function () {\n\treturn this;\n} );\n\nApi.register( 'autoFill().enabled()', function () {\n\tvar ctx = this.context[0];\n\n\treturn ctx.autoFill ?\n\t\tctx.autoFill.enabled() :\n\t\tfalse;\n} );\n\nApi.register( 'autoFill().enable()', function ( flag ) {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx.autoFill ) {\n\t\t\tctx.autoFill.enable( flag );\n\t\t}\n\t} );\n} );\n\nApi.register( 'autoFill().disable()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx.autoFill ) {\n\t\t\tctx.autoFill.disable();\n\t\t}\n\t} );\n} );\n\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'preInit.dt.autofill', function (e, settings, json) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.autoFill;\n\tvar defaults = DataTable.defaults.autoFill;\n\n\tif ( init || defaults ) {\n\t\tvar opts = $.extend( {}, init, defaults );\n\n\t\tif ( init !== false ) {\n\t\t\tnew AutoFill( settings, opts  );\n\t\t}\n\t}\n} );\n\n\n// Alias for access\nDataTable.AutoFill = AutoFill;\nDataTable.AutoFill = AutoFill;\n\n\nreturn AutoFill;\n}));\n\n\n/*! Foundation integration for DataTables' AutoFill\n * ©2015 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-zf', 'datatables.net-autofill'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-zf')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.AutoFill ) {\n\t\t\t\trequire('datatables.net-autofill')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nDataTable.AutoFill.classes.btn = 'button tiny';\n\n\nreturn DataTable;\n}));\n\n/*! Buttons for DataTables 1.5.6\n * ©2016-2019 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n// Used for namespacing events added to the document by each instance, so they\n// can be removed on destroy\nvar _instCounter = 0;\n\n// Button namespacing counter for namespacing events on individual buttons\nvar _buttonCounter = 0;\n\nvar _dtButtons = DataTable.ext.buttons;\n\n/**\n * [Buttons description]\n * @param {[type]}\n * @param {[type]}\n */\nvar Buttons = function( dt, config )\n{\n\t// If not created with a `new` keyword then we return a wrapper function that\n\t// will take the settings object for a DT. This allows easy use of new instances\n\t// with the `layout` option - e.g. `topLeft: $.fn.dataTable.Buttons( ... )`.\n\tif ( !(this instanceof Buttons) ) {\n\t\treturn function (settings) {\n\t\t\treturn new Buttons( settings, dt ).container();\n\t\t};\n\t}\n\n\t// If there is no config set it to an empty object\n\tif ( typeof( config ) === 'undefined' ) {\n\t\tconfig = {};\t\n\t}\n\t\n\t// Allow a boolean true for defaults\n\tif ( config === true ) {\n\t\tconfig = {};\n\t}\n\n\t// For easy configuration of buttons an array can be given\n\tif ( $.isArray( config ) ) {\n\t\tconfig = { buttons: config };\n\t}\n\n\tthis.c = $.extend( true, {}, Buttons.defaults, config );\n\n\t// Don't want a deep copy for the buttons\n\tif ( config.buttons ) {\n\t\tthis.c.buttons = config.buttons;\n\t}\n\n\tthis.s = {\n\t\tdt: new DataTable.Api( dt ),\n\t\tbuttons: [],\n\t\tlistenKeys: '',\n\t\tnamespace: 'dtb'+(_instCounter++)\n\t};\n\n\tthis.dom = {\n\t\tcontainer: $('<'+this.c.dom.container.tag+'/>')\n\t\t\t.addClass( this.c.dom.container.className )\n\t};\n\n\tthis._constructor();\n};\n\n\n$.extend( Buttons.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Public methods\n\t */\n\n\t/**\n\t * Get the action of a button\n\t * @param  {int|string} Button index\n\t * @return {function}\n\t *//**\n\t * Set the action of a button\n\t * @param  {node} node Button element\n\t * @param  {function} action Function to set\n\t * @return {Buttons} Self for chaining\n\t */\n\taction: function ( node, action )\n\t{\n\t\tvar button = this._nodeToButton( node );\n\n\t\tif ( action === undefined ) {\n\t\t\treturn button.conf.action;\n\t\t}\n\n\t\tbutton.conf.action = action;\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Add an active class to the button to make to look active or get current\n\t * active state.\n\t * @param  {node} node Button element\n\t * @param  {boolean} [flag] Enable / disable flag\n\t * @return {Buttons} Self for chaining or boolean for getter\n\t */\n\tactive: function ( node, flag ) {\n\t\tvar button = this._nodeToButton( node );\n\t\tvar klass = this.c.dom.button.active;\n\t\tvar jqNode = $(button.node);\n\n\t\tif ( flag === undefined ) {\n\t\t\treturn jqNode.hasClass( klass );\n\t\t}\n\n\t\tjqNode.toggleClass( klass, flag === undefined ? true : flag );\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Add a new button\n\t * @param {object} config Button configuration object, base string name or function\n\t * @param {int|string} [idx] Button index for where to insert the button\n\t * @return {Buttons} Self for chaining\n\t */\n\tadd: function ( config, idx )\n\t{\n\t\tvar buttons = this.s.buttons;\n\n\t\tif ( typeof idx === 'string' ) {\n\t\t\tvar split = idx.split('-');\n\t\t\tvar base = this.s;\n\n\t\t\tfor ( var i=0, ien=split.length-1 ; i<ien ; i++ ) {\n\t\t\t\tbase = base.buttons[ split[i]*1 ];\n\t\t\t}\n\n\t\t\tbuttons = base.buttons;\n\t\t\tidx = split[ split.length-1 ]*1;\n\t\t}\n\n\t\tthis._expandButton( buttons, config, false, idx );\n\t\tthis._draw();\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Get the container node for the buttons\n\t * @return {jQuery} Buttons node\n\t */\n\tcontainer: function ()\n\t{\n\t\treturn this.dom.container;\n\t},\n\n\t/**\n\t * Disable a button\n\t * @param  {node} node Button node\n\t * @return {Buttons} Self for chaining\n\t */\n\tdisable: function ( node ) {\n\t\tvar button = this._nodeToButton( node );\n\n\t\t$(button.node).addClass( this.c.dom.button.disabled );\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Destroy the instance, cleaning up event handlers and removing DOM\n\t * elements\n\t * @return {Buttons} Self for chaining\n\t */\n\tdestroy: function ()\n\t{\n\t\t// Key event listener\n\t\t$('body').off( 'keyup.'+this.s.namespace );\n\n\t\t// Individual button destroy (so they can remove their own events if\n\t\t// needed). Take a copy as the array is modified by `remove`\n\t\tvar buttons = this.s.buttons.slice();\n\t\tvar i, ien;\n\t\t\n\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tthis.remove( buttons[i].node );\n\t\t}\n\n\t\t// Container\n\t\tthis.dom.container.remove();\n\n\t\t// Remove from the settings object collection\n\t\tvar buttonInsts = this.s.dt.settings()[0];\n\n\t\tfor ( i=0, ien=buttonInsts.length ; i<ien ; i++ ) {\n\t\t\tif ( buttonInsts.inst === this ) {\n\t\t\t\tbuttonInsts.splice( i, 1 );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Enable / disable a button\n\t * @param  {node} node Button node\n\t * @param  {boolean} [flag=true] Enable / disable flag\n\t * @return {Buttons} Self for chaining\n\t */\n\tenable: function ( node, flag )\n\t{\n\t\tif ( flag === false ) {\n\t\t\treturn this.disable( node );\n\t\t}\n\n\t\tvar button = this._nodeToButton( node );\n\t\t$(button.node).removeClass( this.c.dom.button.disabled );\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Get the instance name for the button set selector\n\t * @return {string} Instance name\n\t */\n\tname: function ()\n\t{\n\t\treturn this.c.name;\n\t},\n\n\t/**\n\t * Get a button's node of the buttons container if no button is given\n\t * @param  {node} [node] Button node\n\t * @return {jQuery} Button element, or container\n\t */\n\tnode: function ( node )\n\t{\n\t\tif ( ! node ) {\n\t\t\treturn this.dom.container;\n\t\t}\n\n\t\tvar button = this._nodeToButton( node );\n\t\treturn $(button.node);\n\t},\n\n\t/**\n\t * Set / get a processing class on the selected button\n\t * @param  {boolean} flag true to add, false to remove, undefined to get\n\t * @return {boolean|Buttons} Getter value or this if a setter.\n\t */\n\tprocessing: function ( node, flag )\n\t{\n\t\tvar button = this._nodeToButton( node );\n\n\t\tif ( flag === undefined ) {\n\t\t\treturn $(button.node).hasClass( 'processing' );\n\t\t}\n\n\t\t$(button.node).toggleClass( 'processing', flag );\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Remove a button.\n\t * @param  {node} node Button node\n\t * @return {Buttons} Self for chaining\n\t */\n\tremove: function ( node )\n\t{\n\t\tvar button = this._nodeToButton( node );\n\t\tvar host = this._nodeToHost( node );\n\t\tvar dt = this.s.dt;\n\n\t\t// Remove any child buttons first\n\t\tif ( button.buttons.length ) {\n\t\t\tfor ( var i=button.buttons.length-1 ; i>=0 ; i-- ) {\n\t\t\t\tthis.remove( button.buttons[i].node );\n\t\t\t}\n\t\t}\n\n\t\t// Allow the button to remove event handlers, etc\n\t\tif ( button.conf.destroy ) {\n\t\t\tbutton.conf.destroy.call( dt.button(node), dt, $(node), button.conf );\n\t\t}\n\n\t\tthis._removeKey( button.conf );\n\n\t\t$(button.node).remove();\n\n\t\tvar idx = $.inArray( button, host );\n\t\thost.splice( idx, 1 );\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Get the text for a button\n\t * @param  {int|string} node Button index\n\t * @return {string} Button text\n\t *//**\n\t * Set the text for a button\n\t * @param  {int|string|function} node Button index\n\t * @param  {string} label Text\n\t * @return {Buttons} Self for chaining\n\t */\n\ttext: function ( node, label )\n\t{\n\t\tvar button = this._nodeToButton( node );\n\t\tvar buttonLiner = this.c.dom.collection.buttonLiner;\n\t\tvar linerTag = button.inCollection && buttonLiner && buttonLiner.tag ?\n\t\t\tbuttonLiner.tag :\n\t\t\tthis.c.dom.buttonLiner.tag;\n\t\tvar dt = this.s.dt;\n\t\tvar jqNode = $(button.node);\n\t\tvar text = function ( opt ) {\n\t\t\treturn typeof opt === 'function' ?\n\t\t\t\topt( dt, jqNode, button.conf ) :\n\t\t\t\topt;\n\t\t};\n\n\t\tif ( label === undefined ) {\n\t\t\treturn text( button.conf.text );\n\t\t}\n\n\t\tbutton.conf.text = label;\n\n\t\tif ( linerTag ) {\n\t\t\tjqNode.children( linerTag ).html( text(label) );\n\t\t}\n\t\telse {\n\t\t\tjqNode.html( text(label) );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\n\t/**\n\t * Buttons constructor\n\t * @private\n\t */\n\t_constructor: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar dtSettings = dt.settings()[0];\n\t\tvar buttons =  this.c.buttons;\n\n\t\tif ( ! dtSettings._buttons ) {\n\t\t\tdtSettings._buttons = [];\n\t\t}\n\n\t\tdtSettings._buttons.push( {\n\t\t\tinst: this,\n\t\t\tname: this.c.name\n\t\t} );\n\n\t\tfor ( var i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tthis.add( buttons[i] );\n\t\t}\n\n\t\tdt.on( 'destroy', function ( e, settings ) {\n\t\t\tif ( settings === dtSettings ) {\n\t\t\t\tthat.destroy();\n\t\t\t}\n\t\t} );\n\n\t\t// Global key event binding to listen for button keys\n\t\t$('body').on( 'keyup.'+this.s.namespace, function ( e ) {\n\t\t\tif ( ! document.activeElement || document.activeElement === document.body ) {\n\t\t\t\t// SUse a string of characters for fast lookup of if we need to\n\t\t\t\t// handle this\n\t\t\t\tvar character = String.fromCharCode(e.keyCode).toLowerCase();\n\n\t\t\t\tif ( that.s.listenKeys.toLowerCase().indexOf( character ) !== -1 ) {\n\t\t\t\t\tthat._keypress( character, e );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\n\t/**\n\t * Add a new button to the key press listener\n\t * @param {object} conf Resolved button configuration object\n\t * @private\n\t */\n\t_addKey: function ( conf )\n\t{\n\t\tif ( conf.key ) {\n\t\t\tthis.s.listenKeys += $.isPlainObject( conf.key ) ?\n\t\t\t\tconf.key.key :\n\t\t\t\tconf.key;\n\t\t}\n\t},\n\n\t/**\n\t * Insert the buttons into the container. Call without parameters!\n\t * @param  {node} [container] Recursive only - Insert point\n\t * @param  {array} [buttons] Recursive only - Buttons array\n\t * @private\n\t */\n\t_draw: function ( container, buttons )\n\t{\n\t\tif ( ! container ) {\n\t\t\tcontainer = this.dom.container;\n\t\t\tbuttons = this.s.buttons;\n\t\t}\n\n\t\tcontainer.children().detach();\n\n\t\tfor ( var i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tcontainer.append( buttons[i].inserter );\n\t\t\tcontainer.append( ' ' );\n\n\t\t\tif ( buttons[i].buttons && buttons[i].buttons.length ) {\n\t\t\t\tthis._draw( buttons[i].collection, buttons[i].buttons );\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * Create buttons from an array of buttons\n\t * @param  {array} attachTo Buttons array to attach to\n\t * @param  {object} button Button definition\n\t * @param  {boolean} inCollection true if the button is in a collection\n\t * @private\n\t */\n\t_expandButton: function ( attachTo, button, inCollection, attachPoint )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar buttonCounter = 0;\n\t\tvar buttons = ! $.isArray( button ) ?\n\t\t\t[ button ] :\n\t\t\tbutton;\n\n\t\tfor ( var i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tvar conf = this._resolveExtends( buttons[i] );\n\n\t\t\tif ( ! conf ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If the configuration is an array, then expand the buttons at this\n\t\t\t// point\n\t\t\tif ( $.isArray( conf ) ) {\n\t\t\t\tthis._expandButton( attachTo, conf, inCollection, attachPoint );\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tvar built = this._buildButton( conf, inCollection );\n\t\t\tif ( ! built ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ( attachPoint !== undefined ) {\n\t\t\t\tattachTo.splice( attachPoint, 0, built );\n\t\t\t\tattachPoint++;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tattachTo.push( built );\n\t\t\t}\n\n\t\t\tif ( built.conf.buttons ) {\n\t\t\t\tvar collectionDom = this.c.dom.collection;\n\t\t\t\tbuilt.collection = $('<'+collectionDom.tag+'/>')\n\t\t\t\t\t.addClass( collectionDom.className )\n\t\t\t\t\t.attr( 'role', 'menu' ) ;\n\t\t\t\tbuilt.conf._collection = built.collection;\n\n\t\t\t\tthis._expandButton( built.buttons, built.conf.buttons, true, attachPoint );\n\t\t\t}\n\n\t\t\t// init call is made here, rather than buildButton as it needs to\n\t\t\t// be selectable, and for that it needs to be in the buttons array\n\t\t\tif ( conf.init ) {\n\t\t\t\tconf.init.call( dt.button( built.node ), dt, $(built.node), conf );\n\t\t\t}\n\n\t\t\tbuttonCounter++;\n\t\t}\n\t},\n\n\t/**\n\t * Create an individual button\n\t * @param  {object} config            Resolved button configuration\n\t * @param  {boolean} inCollection `true` if a collection button\n\t * @return {jQuery} Created button node (jQuery)\n\t * @private\n\t */\n\t_buildButton: function ( config, inCollection )\n\t{\n\t\tvar buttonDom = this.c.dom.button;\n\t\tvar linerDom = this.c.dom.buttonLiner;\n\t\tvar collectionDom = this.c.dom.collection;\n\t\tvar dt = this.s.dt;\n\t\tvar text = function ( opt ) {\n\t\t\treturn typeof opt === 'function' ?\n\t\t\t\topt( dt, button, config ) :\n\t\t\t\topt;\n\t\t};\n\n\t\tif ( inCollection && collectionDom.button ) {\n\t\t\tbuttonDom = collectionDom.button;\n\t\t}\n\n\t\tif ( inCollection && collectionDom.buttonLiner ) {\n\t\t\tlinerDom = collectionDom.buttonLiner;\n\t\t}\n\n\t\t// Make sure that the button is available based on whatever requirements\n\t\t// it has. For example, Flash buttons require Flash\n\t\tif ( config.available && ! config.available( dt, config ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tvar action = function ( e, dt, button, config ) {\n\t\t\tconfig.action.call( dt.button( button ), e, dt, button, config );\n\n\t\t\t$(dt.table().node()).triggerHandler( 'buttons-action.dt', [\n\t\t\t\tdt.button( button ), dt, button, config \n\t\t\t] );\n\t\t};\n\n\t\tvar tag = config.tag || buttonDom.tag;\n\t\tvar clickBlurs = config.clickBlurs === undefined ? true : config.clickBlurs\n\t\tvar button = $('<'+tag+'/>')\n\t\t\t.addClass( buttonDom.className )\n\t\t\t.attr( 'tabindex', this.s.dt.settings()[0].iTabIndex )\n\t\t\t.attr( 'aria-controls', this.s.dt.table().node().id )\n\t\t\t.on( 'click.dtb', function (e) {\n\t\t\t\te.preventDefault();\n\n\t\t\t\tif ( ! button.hasClass( buttonDom.disabled ) && config.action ) {\n\t\t\t\t\taction( e, dt, button, config );\n\t\t\t\t}\n\t\t\t\tif( clickBlurs ) {\n\t\t\t\t\tbutton.blur();\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'keyup.dtb', function (e) {\n\t\t\t\tif ( e.keyCode === 13 ) {\n\t\t\t\t\tif ( ! button.hasClass( buttonDom.disabled ) && config.action ) {\n\t\t\t\t\t\taction( e, dt, button, config );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\n\t\t// Make `a` tags act like a link\n\t\tif ( tag.toLowerCase() === 'a' ) {\n\t\t\tbutton.attr( 'href', '#' );\n\t\t}\n\n\t\t// Button tags should have `type=button` so they don't have any default behaviour\n\t\tif ( tag.toLowerCase() === 'button' ) {\n\t\t\tbutton.attr( 'type', 'button' );\n\t\t}\n\n\t\tif ( linerDom.tag ) {\n\t\t\tvar liner = $('<'+linerDom.tag+'/>')\n\t\t\t\t.html( text( config.text ) )\n\t\t\t\t.addClass( linerDom.className );\n\n\t\t\tif ( linerDom.tag.toLowerCase() === 'a' ) {\n\t\t\t\tliner.attr( 'href', '#' );\n\t\t\t}\n\n\t\t\tbutton.append( liner );\n\t\t}\n\t\telse {\n\t\t\tbutton.html( text( config.text ) );\n\t\t}\n\n\t\tif ( config.enabled === false ) {\n\t\t\tbutton.addClass( buttonDom.disabled );\n\t\t}\n\n\t\tif ( config.className ) {\n\t\t\tbutton.addClass( config.className );\n\t\t}\n\n\t\tif ( config.titleAttr ) {\n\t\t\tbutton.attr( 'title', text( config.titleAttr ) );\n\t\t}\n\n\t\tif ( config.attr ) {\n\t\t\tbutton.attr( config.attr );\n\t\t}\n\n\t\tif ( ! config.namespace ) {\n\t\t\tconfig.namespace = '.dt-button-'+(_buttonCounter++);\n\t\t}\n\n\t\tvar buttonContainer = this.c.dom.buttonContainer;\n\t\tvar inserter;\n\t\tif ( buttonContainer && buttonContainer.tag ) {\n\t\t\tinserter = $('<'+buttonContainer.tag+'/>')\n\t\t\t\t.addClass( buttonContainer.className )\n\t\t\t\t.append( button );\n\t\t}\n\t\telse {\n\t\t\tinserter = button;\n\t\t}\n\n\t\tthis._addKey( config );\n\n\t\t// Style integration callback for DOM manipulation\n\t\t// Note that this is _not_ documented. It is currently\n\t\t// for style integration only\n\t\tif( this.c.buttonCreated ) {\n\t\t\tinserter = this.c.buttonCreated( config, inserter );\n\t\t}\n\n\t\treturn {\n\t\t\tconf:         config,\n\t\t\tnode:         button.get(0),\n\t\t\tinserter:     inserter,\n\t\t\tbuttons:      [],\n\t\t\tinCollection: inCollection,\n\t\t\tcollection:   null\n\t\t};\n\t},\n\n\t/**\n\t * Get the button object from a node (recursive)\n\t * @param  {node} node Button node\n\t * @param  {array} [buttons] Button array, uses base if not defined\n\t * @return {object} Button object\n\t * @private\n\t */\n\t_nodeToButton: function ( node, buttons )\n\t{\n\t\tif ( ! buttons ) {\n\t\t\tbuttons = this.s.buttons;\n\t\t}\n\n\t\tfor ( var i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tif ( buttons[i].node === node ) {\n\t\t\t\treturn buttons[i];\n\t\t\t}\n\n\t\t\tif ( buttons[i].buttons.length ) {\n\t\t\t\tvar ret = this._nodeToButton( node, buttons[i].buttons );\n\n\t\t\t\tif ( ret ) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * Get container array for a button from a button node (recursive)\n\t * @param  {node} node Button node\n\t * @param  {array} [buttons] Button array, uses base if not defined\n\t * @return {array} Button's host array\n\t * @private\n\t */\n\t_nodeToHost: function ( node, buttons )\n\t{\n\t\tif ( ! buttons ) {\n\t\t\tbuttons = this.s.buttons;\n\t\t}\n\n\t\tfor ( var i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tif ( buttons[i].node === node ) {\n\t\t\t\treturn buttons;\n\t\t\t}\n\n\t\t\tif ( buttons[i].buttons.length ) {\n\t\t\t\tvar ret = this._nodeToHost( node, buttons[i].buttons );\n\n\t\t\t\tif ( ret ) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * Handle a key press - determine if any button's key configured matches\n\t * what was typed and trigger the action if so.\n\t * @param  {string} character The character pressed\n\t * @param  {object} e Key event that triggered this call\n\t * @private\n\t */\n\t_keypress: function ( character, e )\n\t{\n\t\t// Check if this button press already activated on another instance of Buttons\n\t\tif ( e._buttonsHandled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar run = function ( conf, node ) {\n\t\t\tif ( ! conf.key ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( conf.key === character ) {\n\t\t\t\te._buttonsHandled = true;\n\t\t\t\t$(node).click();\n\t\t\t}\n\t\t\telse if ( $.isPlainObject( conf.key ) ) {\n\t\t\t\tif ( conf.key.key !== character ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( conf.key.shiftKey && ! e.shiftKey ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( conf.key.altKey && ! e.altKey ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( conf.key.ctrlKey && ! e.ctrlKey ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( conf.key.metaKey && ! e.metaKey ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Made it this far - it is good\n\t\t\t\te._buttonsHandled = true;\n\t\t\t\t$(node).click();\n\t\t\t}\n\t\t};\n\n\t\tvar recurse = function ( a ) {\n\t\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\t\trun( a[i].conf, a[i].node );\n\n\t\t\t\tif ( a[i].buttons.length ) {\n\t\t\t\t\trecurse( a[i].buttons );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\trecurse( this.s.buttons );\n\t},\n\n\t/**\n\t * Remove a key from the key listener for this instance (to be used when a\n\t * button is removed)\n\t * @param  {object} conf Button configuration\n\t * @private\n\t */\n\t_removeKey: function ( conf )\n\t{\n\t\tif ( conf.key ) {\n\t\t\tvar character = $.isPlainObject( conf.key ) ?\n\t\t\t\tconf.key.key :\n\t\t\t\tconf.key;\n\n\t\t\t// Remove only one character, as multiple buttons could have the\n\t\t\t// same listening key\n\t\t\tvar a = this.s.listenKeys.split('');\n\t\t\tvar idx = $.inArray( character, a );\n\t\t\ta.splice( idx, 1 );\n\t\t\tthis.s.listenKeys = a.join('');\n\t\t}\n\t},\n\n\t/**\n\t * Resolve a button configuration\n\t * @param  {string|function|object} conf Button config to resolve\n\t * @return {object} Button configuration\n\t * @private\n\t */\n\t_resolveExtends: function ( conf )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar i, ien;\n\t\tvar toConfObject = function ( base ) {\n\t\t\tvar loop = 0;\n\n\t\t\t// Loop until we have resolved to a button configuration, or an\n\t\t\t// array of button configurations (which will be iterated\n\t\t\t// separately)\n\t\t\twhile ( ! $.isPlainObject(base) && ! $.isArray(base) ) {\n\t\t\t\tif ( base === undefined ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( typeof base === 'function' ) {\n\t\t\t\t\tbase = base( dt, conf );\n\n\t\t\t\t\tif ( ! base ) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( typeof base === 'string' ) {\n\t\t\t\t\tif ( ! _dtButtons[ base ] ) {\n\t\t\t\t\t\tthrow 'Unknown button type: '+base;\n\t\t\t\t\t}\n\n\t\t\t\t\tbase = _dtButtons[ base ];\n\t\t\t\t}\n\n\t\t\t\tloop++;\n\t\t\t\tif ( loop > 30 ) {\n\t\t\t\t\t// Protect against misconfiguration killing the browser\n\t\t\t\t\tthrow 'Buttons: Too many iterations';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn $.isArray( base ) ?\n\t\t\t\tbase :\n\t\t\t\t$.extend( {}, base );\n\t\t};\n\n\t\tconf = toConfObject( conf );\n\n\t\twhile ( conf && conf.extend ) {\n\t\t\t// Use `toConfObject` in case the button definition being extended\n\t\t\t// is itself a string or a function\n\t\t\tif ( ! _dtButtons[ conf.extend ] ) {\n\t\t\t\tthrow 'Cannot extend unknown button type: '+conf.extend;\n\t\t\t}\n\n\t\t\tvar objArray = toConfObject( _dtButtons[ conf.extend ] );\n\t\t\tif ( $.isArray( objArray ) ) {\n\t\t\t\treturn objArray;\n\t\t\t}\n\t\t\telse if ( ! objArray ) {\n\t\t\t\t// This is a little brutal as it might be possible to have a\n\t\t\t\t// valid button without the extend, but if there is no extend\n\t\t\t\t// then the host button would be acting in an undefined state\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Stash the current class name\n\t\t\tvar originalClassName = objArray.className;\n\n\t\t\tconf = $.extend( {}, objArray, conf );\n\n\t\t\t// The extend will have overwritten the original class name if the\n\t\t\t// `conf` object also assigned a class, but we want to concatenate\n\t\t\t// them so they are list that is combined from all extended buttons\n\t\t\tif ( originalClassName && conf.className !== originalClassName ) {\n\t\t\t\tconf.className = originalClassName+' '+conf.className;\n\t\t\t}\n\n\t\t\t// Buttons to be added to a collection  -gives the ability to define\n\t\t\t// if buttons should be added to the start or end of a collection\n\t\t\tvar postfixButtons = conf.postfixButtons;\n\t\t\tif ( postfixButtons ) {\n\t\t\t\tif ( ! conf.buttons ) {\n\t\t\t\t\tconf.buttons = [];\n\t\t\t\t}\n\n\t\t\t\tfor ( i=0, ien=postfixButtons.length ; i<ien ; i++ ) {\n\t\t\t\t\tconf.buttons.push( postfixButtons[i] );\n\t\t\t\t}\n\n\t\t\t\tconf.postfixButtons = null;\n\t\t\t}\n\n\t\t\tvar prefixButtons = conf.prefixButtons;\n\t\t\tif ( prefixButtons ) {\n\t\t\t\tif ( ! conf.buttons ) {\n\t\t\t\t\tconf.buttons = [];\n\t\t\t\t}\n\n\t\t\t\tfor ( i=0, ien=prefixButtons.length ; i<ien ; i++ ) {\n\t\t\t\t\tconf.buttons.splice( i, 0, prefixButtons[i] );\n\t\t\t\t}\n\n\t\t\t\tconf.prefixButtons = null;\n\t\t\t}\n\n\t\t\t// Although we want the `conf` object to overwrite almost all of\n\t\t\t// the properties of the object being extended, the `extend`\n\t\t\t// property should come from the object being extended\n\t\t\tconf.extend = objArray.extend;\n\t\t}\n\n\t\treturn conf;\n\t}\n} );\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Statics\n */\n\n/**\n * Show / hide a background layer behind a collection\n * @param  {boolean} Flag to indicate if the background should be shown or\n *   hidden \n * @param  {string} Class to assign to the background\n * @static\n */\nButtons.background = function ( show, className, fade, insertPoint ) {\n\tif ( fade === undefined ) {\n\t\tfade = 400;\n\t}\n\tif ( ! insertPoint ) {\n\t\tinsertPoint = document.body;\n\t}\n\n\tif ( show ) {\n\t\t$('<div/>')\n\t\t\t.addClass( className )\n\t\t\t.css( 'display', 'none' )\n\t\t\t.insertAfter( insertPoint )\n\t\t\t.stop()\n\t\t\t.fadeIn( fade );\n\t}\n\telse {\n\t\t$('div.'+className)\n\t\t\t.stop()\n\t\t\t.fadeOut( fade, function () {\n\t\t\t\t$(this)\n\t\t\t\t\t.removeClass( className )\n\t\t\t\t\t.remove();\n\t\t\t} );\n\t}\n};\n\n/**\n * Instance selector - select Buttons instances based on an instance selector\n * value from the buttons assigned to a DataTable. This is only useful if\n * multiple instances are attached to a DataTable.\n * @param  {string|int|array} Instance selector - see `instance-selector`\n *   documentation on the DataTables site\n * @param  {array} Button instance array that was attached to the DataTables\n *   settings object\n * @return {array} Buttons instances\n * @static\n */\nButtons.instanceSelector = function ( group, buttons )\n{\n\tif ( ! group ) {\n\t\treturn $.map( buttons, function ( v ) {\n\t\t\treturn v.inst;\n\t\t} );\n\t}\n\n\tvar ret = [];\n\tvar names = $.map( buttons, function ( v ) {\n\t\treturn v.name;\n\t} );\n\n\t// Flatten the group selector into an array of single options\n\tvar process = function ( input ) {\n\t\tif ( $.isArray( input ) ) {\n\t\t\tfor ( var i=0, ien=input.length ; i<ien ; i++ ) {\n\t\t\t\tprocess( input[i] );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif ( typeof input === 'string' ) {\n\t\t\tif ( input.indexOf( ',' ) !== -1 ) {\n\t\t\t\t// String selector, list of names\n\t\t\t\tprocess( input.split(',') );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// String selector individual name\n\t\t\t\tvar idx = $.inArray( $.trim(input), names );\n\n\t\t\t\tif ( idx !== -1 ) {\n\t\t\t\t\tret.push( buttons[ idx ].inst );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if ( typeof input === 'number' ) {\n\t\t\t// Index selector\n\t\t\tret.push( buttons[ input ].inst );\n\t\t}\n\t};\n\t\n\tprocess( group );\n\n\treturn ret;\n};\n\n/**\n * Button selector - select one or more buttons from a selector input so some\n * operation can be performed on them.\n * @param  {array} Button instances array that the selector should operate on\n * @param  {string|int|node|jQuery|array} Button selector - see\n *   `button-selector` documentation on the DataTables site\n * @return {array} Array of objects containing `inst` and `idx` properties of\n *   the selected buttons so you know which instance each button belongs to.\n * @static\n */\nButtons.buttonSelector = function ( insts, selector )\n{\n\tvar ret = [];\n\tvar nodeBuilder = function ( a, buttons, baseIdx ) {\n\t\tvar button;\n\t\tvar idx;\n\n\t\tfor ( var i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\tbutton = buttons[i];\n\n\t\t\tif ( button ) {\n\t\t\t\tidx = baseIdx !== undefined ?\n\t\t\t\t\tbaseIdx+i :\n\t\t\t\t\ti+'';\n\n\t\t\t\ta.push( {\n\t\t\t\t\tnode: button.node,\n\t\t\t\t\tname: button.conf.name,\n\t\t\t\t\tidx:  idx\n\t\t\t\t} );\n\n\t\t\t\tif ( button.buttons ) {\n\t\t\t\t\tnodeBuilder( a, button.buttons, idx+'-' );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\tvar run = function ( selector, inst ) {\n\t\tvar i, ien;\n\t\tvar buttons = [];\n\t\tnodeBuilder( buttons, inst.s.buttons );\n\n\t\tvar nodes = $.map( buttons, function (v) {\n\t\t\treturn v.node;\n\t\t} );\n\n\t\tif ( $.isArray( selector ) || selector instanceof $ ) {\n\t\t\tfor ( i=0, ien=selector.length ; i<ien ; i++ ) {\n\t\t\t\trun( selector[i], inst );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif ( selector === null || selector === undefined || selector === '*' ) {\n\t\t\t// Select all\n\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\tret.push( {\n\t\t\t\t\tinst: inst,\n\t\t\t\t\tnode: buttons[i].node\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\telse if ( typeof selector === 'number' ) {\n\t\t\t// Main button index selector\n\t\t\tret.push( {\n\t\t\t\tinst: inst,\n\t\t\t\tnode: inst.s.buttons[ selector ].node\n\t\t\t} );\n\t\t}\n\t\telse if ( typeof selector === 'string' ) {\n\t\t\tif ( selector.indexOf( ',' ) !== -1 ) {\n\t\t\t\t// Split\n\t\t\t\tvar a = selector.split(',');\n\n\t\t\t\tfor ( i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\t\t\trun( $.trim(a[i]), inst );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( selector.match( /^\\d+(\\-\\d+)*$/ ) ) {\n\t\t\t\t// Sub-button index selector\n\t\t\t\tvar indexes = $.map( buttons, function (v) {\n\t\t\t\t\treturn v.idx;\n\t\t\t\t} );\n\n\t\t\t\tret.push( {\n\t\t\t\t\tinst: inst,\n\t\t\t\t\tnode: buttons[ $.inArray( selector, indexes ) ].node\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse if ( selector.indexOf( ':name' ) !== -1 ) {\n\t\t\t\t// Button name selector\n\t\t\t\tvar name = selector.replace( ':name', '' );\n\n\t\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( buttons[i].name === name ) {\n\t\t\t\t\t\tret.push( {\n\t\t\t\t\t\t\tinst: inst,\n\t\t\t\t\t\t\tnode: buttons[i].node\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// jQuery selector on the nodes\n\t\t\t\t$( nodes ).filter( selector ).each( function () {\n\t\t\t\t\tret.push( {\n\t\t\t\t\t\tinst: inst,\n\t\t\t\t\t\tnode: this\n\t\t\t\t\t} );\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\telse if ( typeof selector === 'object' && selector.nodeName ) {\n\t\t\t// Node selector\n\t\t\tvar idx = $.inArray( selector, nodes );\n\n\t\t\tif ( idx !== -1 ) {\n\t\t\t\tret.push( {\n\t\t\t\t\tinst: inst,\n\t\t\t\t\tnode: nodes[ idx ]\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t};\n\n\n\tfor ( var i=0, ien=insts.length ; i<ien ; i++ ) {\n\t\tvar inst = insts[i];\n\n\t\trun( selector, inst );\n\t}\n\n\treturn ret;\n};\n\n\n/**\n * Buttons defaults. For full documentation, please refer to the docs/option\n * directory or the DataTables site.\n * @type {Object}\n * @static\n */\nButtons.defaults = {\n\tbuttons: [ 'copy', 'excel', 'csv', 'pdf', 'print' ],\n\tname: 'main',\n\ttabIndex: 0,\n\tdom: {\n\t\tcontainer: {\n\t\t\ttag: 'div',\n\t\t\tclassName: 'dt-buttons'\n\t\t},\n\t\tcollection: {\n\t\t\ttag: 'div',\n\t\t\tclassName: 'dt-button-collection'\n\t\t},\n\t\tbutton: {\n\t\t\t// Flash buttons will not work with `<button>` in IE - it has to be `<a>`\n\t\t\ttag: 'ActiveXObject' in window ?\n\t\t\t\t'a' :\n\t\t\t\t'button',\n\t\t\tclassName: 'dt-button',\n\t\t\tactive: 'active',\n\t\t\tdisabled: 'disabled'\n\t\t},\n\t\tbuttonLiner: {\n\t\t\ttag: 'span',\n\t\t\tclassName: ''\n\t\t}\n\t}\n};\n\n/**\n * Version information\n * @type {string}\n * @static\n */\nButtons.version = '1.5.6';\n\n\n$.extend( _dtButtons, {\n\tcollection: {\n\t\ttext: function ( dt ) {\n\t\t\treturn dt.i18n( 'buttons.collection', 'Collection' );\n\t\t},\n\t\tclassName: 'buttons-collection',\n\t\tinit: function ( dt, button, config ) {\n\t\t\tbutton.attr( 'aria-expanded', false );\n\t\t},\n\t\taction: function ( e, dt, button, config ) {\n\t\t\tvar close = function () {\n\t\t\t\tdt.buttons( '[aria-haspopup=\"true\"][aria-expanded=\"true\"]' ).nodes().each( function() {\n\t\t\t\t\tvar collection = $(this).siblings('.dt-button-collection');\n\n\t\t\t\t\tif ( collection.length ) {\n\t\t\t\t\t\tcollection.stop().fadeOut( config.fade, function () {\n\t\t\t\t\t\t\tcollection.detach();\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\n\t\t\t\t\t$(this).attr( 'aria-expanded', 'false' );\n\t\t\t\t});\n\n\t\t\t\t$('div.dt-button-background').off( 'click.dtb-collection' );\n\t\t\t\tButtons.background( false, config.backgroundClassName, config.fade, insertPoint );\n\n\t\t\t\t$('body').off( '.dtb-collection' );\n\t\t\t\tdt.off( 'buttons-action.b-internal' );\n\t\t\t};\n\n\t\t\tvar wasExpanded = button.attr( 'aria-expanded' ) === 'true';\n\n\t\t\tclose();\n\n\t\t\tif (!wasExpanded) {\n\t\t\t\tvar host = button;\n\t\t\t\tvar collectionParent = $(button).parents('div.dt-button-collection');\n\t\t\t\tvar hostPosition = host.position();\n\t\t\t\tvar tableContainer = $( dt.table().container() );\n\t\t\t\tvar multiLevel = false;\n\t\t\t\tvar insertPoint = host;\n\n\t\t\t\tbutton.attr( 'aria-expanded', 'true' );\n\n\t\t\t\t// Remove any old collection\n\t\t\t\tif ( collectionParent.length ) {\n\t\t\t\t\tmultiLevel = $('.dt-button-collection').position();\n\t\t\t\t\tinsertPoint = collectionParent;\n\t\t\t\t\t$('body').trigger( 'click.dtb-collection' );\n\t\t\t\t}\n\n\t\t\t\tif ( insertPoint.parents('body')[0] !== document.body ) {\n\t\t\t\t\tinsertPoint = document.body.lastChild;\n\t\t\t\t}\n\n\t\t\t\tconfig._collection.find('.dt-button-collection-title').remove();\n\t\t\t\tconfig._collection.prepend('<div class=\"dt-button-collection-title\">'+config.collectionTitle+'</div>');\n\n\t\t\t\tconfig._collection\n\t\t\t\t\t.addClass( config.collectionLayout )\n\t\t\t\t\t.css( 'display', 'none' )\n\t\t\t\t\t.insertAfter( insertPoint )\n\t\t\t\t\t.stop()\n\t\t\t\t\t.fadeIn( config.fade );\n\n\t\t\t\tvar position = config._collection.css( 'position' );\n\n\t\t\t\tif ( multiLevel && position === 'absolute' ) {\n\t\t\t\t\tconfig._collection.css( {\n\t\t\t\t\t\ttop: multiLevel.top,\n\t\t\t\t\t\tleft: multiLevel.left\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\telse if ( position === 'absolute' ) {\n\t\t\t\t\tconfig._collection.css( {\n\t\t\t\t\t\ttop: hostPosition.top + host.outerHeight(),\n\t\t\t\t\t\tleft: hostPosition.left\n\t\t\t\t\t} );\n\n\t\t\t\t\t// calculate overflow when positioned beneath\n\t\t\t\t\tvar tableBottom = tableContainer.offset().top + tableContainer.height();\n\t\t\t\t\tvar listBottom = hostPosition.top + host.outerHeight() + config._collection.outerHeight();\n\t\t\t\t\tvar bottomOverflow = listBottom - tableBottom;\n\n\t\t\t\t\t// calculate overflow when positioned above\n\t\t\t\t\tvar listTop = hostPosition.top - config._collection.outerHeight();\n\t\t\t\t\tvar tableTop = tableContainer.offset().top;\n\t\t\t\t\tvar topOverflow = tableTop - listTop;\n\n\t\t\t\t\t// if bottom overflow is larger, move to the top because it fits better, or if dropup is requested\n\t\t\t\t\tif (bottomOverflow > topOverflow || config.dropup) {\n\t\t\t\t\t\tconfig._collection.css( 'top', hostPosition.top - config._collection.outerHeight() - 5);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Right alignment is enabled on a class, e.g. bootstrap:\n\t\t\t\t\t// $.fn.dataTable.Buttons.defaults.dom.collection.className += \" dropdown-menu-right\"; \n\t\t\t\t\tif ( config._collection.hasClass( config.rightAlignClassName ) ) {\n\t\t\t\t\t\tconfig._collection.css( 'left', hostPosition.left + host.outerWidth() - config._collection.outerWidth() );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Right alignment in table container\n\t\t\t\t\tvar listRight = hostPosition.left + config._collection.outerWidth();\n\t\t\t\t\tvar tableRight = tableContainer.offset().left + tableContainer.width();\n\t\t\t\t\tif ( listRight > tableRight ) {\n\t\t\t\t\t\tconfig._collection.css( 'left', hostPosition.left - ( listRight - tableRight ) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Right alignment to window\n\t\t\t\t\tvar listOffsetRight = host.offset().left + config._collection.outerWidth();\n\t\t\t\t\tif ( listOffsetRight > $(window).width() ) {\n\t\t\t\t\t\tconfig._collection.css( 'left', hostPosition.left - (listOffsetRight-$(window).width()) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Fix position - centre on screen\n\t\t\t\t\tvar top = config._collection.height() / 2;\n\t\t\t\t\tif ( top > $(window).height() / 2 ) {\n\t\t\t\t\t\ttop = $(window).height() / 2;\n\t\t\t\t\t}\n\n\t\t\t\t\tconfig._collection.css( 'marginTop', top*-1 );\n\t\t\t\t}\n\n\t\t\t\tif ( config.background ) {\n\t\t\t\t\tButtons.background( true, config.backgroundClassName, config.fade, insertPoint );\n\t\t\t\t}\n\n\t\t\t\t// Need to break the 'thread' for the collection button being\n\t\t\t\t// activated by a click - it would also trigger this event\n\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t// This is bonkers, but if we don't have a click listener on the\n\t\t\t\t\t// background element, iOS Safari will ignore the body click\n\t\t\t\t\t// listener below. An empty function here is all that is\n\t\t\t\t\t// required to make it work...\n\t\t\t\t\t$('div.dt-button-background').on( 'click.dtb-collection', function () {} );\n\n\t\t\t\t\t$('body')\n\t\t\t\t\t\t.on( 'click.dtb-collection', function (e) {\n\t\t\t\t\t\t\t// andSelf is deprecated in jQ1.8, but we want 1.7 compat\n\t\t\t\t\t\t\tvar back = $.fn.addBack ? 'addBack' : 'andSelf';\n\n\t\t\t\t\t\t\tif ( ! $(e.target).parents()[back]().filter( config._collection ).length ) {\n\t\t\t\t\t\t\t\tclose();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.on( 'keyup.dtb-collection', function (e) {\n\t\t\t\t\t\t\tif ( e.keyCode === 27 ) {\n\t\t\t\t\t\t\t\tclose();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\n\t\t\t\t\tif ( config.autoClose ) {\n\t\t\t\t\t\tdt.on( 'buttons-action.b-internal', function () {\n\t\t\t\t\t\t\tclose();\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}, 10 );\n\t\t\t}\n\t\t},\n\t\tbackground: true,\n\t\tcollectionLayout: '',\n\t\tcollectionTitle: '',\n\t\tbackgroundClassName: 'dt-button-background',\n\t\trightAlignClassName: 'dt-button-right',\n\t\tautoClose: false,\n\t\tfade: 400,\n\t\tattr: {\n\t\t\t'aria-haspopup': true\n\t\t}\n\t},\n\tcopy: function ( dt, conf ) {\n\t\tif ( _dtButtons.copyHtml5 ) {\n\t\t\treturn 'copyHtml5';\n\t\t}\n\t\tif ( _dtButtons.copyFlash && _dtButtons.copyFlash.available( dt, conf ) ) {\n\t\t\treturn 'copyFlash';\n\t\t}\n\t},\n\tcsv: function ( dt, conf ) {\n\t\t// Common option that will use the HTML5 or Flash export buttons\n\t\tif ( _dtButtons.csvHtml5 && _dtButtons.csvHtml5.available( dt, conf ) ) {\n\t\t\treturn 'csvHtml5';\n\t\t}\n\t\tif ( _dtButtons.csvFlash && _dtButtons.csvFlash.available( dt, conf ) ) {\n\t\t\treturn 'csvFlash';\n\t\t}\n\t},\n\texcel: function ( dt, conf ) {\n\t\t// Common option that will use the HTML5 or Flash export buttons\n\t\tif ( _dtButtons.excelHtml5 && _dtButtons.excelHtml5.available( dt, conf ) ) {\n\t\t\treturn 'excelHtml5';\n\t\t}\n\t\tif ( _dtButtons.excelFlash && _dtButtons.excelFlash.available( dt, conf ) ) {\n\t\t\treturn 'excelFlash';\n\t\t}\n\t},\n\tpdf: function ( dt, conf ) {\n\t\t// Common option that will use the HTML5 or Flash export buttons\n\t\tif ( _dtButtons.pdfHtml5 && _dtButtons.pdfHtml5.available( dt, conf ) ) {\n\t\t\treturn 'pdfHtml5';\n\t\t}\n\t\tif ( _dtButtons.pdfFlash && _dtButtons.pdfFlash.available( dt, conf ) ) {\n\t\t\treturn 'pdfFlash';\n\t\t}\n\t},\n\tpageLength: function ( dt ) {\n\t\tvar lengthMenu = dt.settings()[0].aLengthMenu;\n\t\tvar vals = $.isArray( lengthMenu[0] ) ? lengthMenu[0] : lengthMenu;\n\t\tvar lang = $.isArray( lengthMenu[0] ) ? lengthMenu[1] : lengthMenu;\n\t\tvar text = function ( dt ) {\n\t\t\treturn dt.i18n( 'buttons.pageLength', {\n\t\t\t\t\"-1\": 'Show all rows',\n\t\t\t\t_:    'Show %d rows'\n\t\t\t}, dt.page.len() );\n\t\t};\n\n\t\treturn {\n\t\t\textend: 'collection',\n\t\t\ttext: text,\n\t\t\tclassName: 'buttons-page-length',\n\t\t\tautoClose: true,\n\t\t\tbuttons: $.map( vals, function ( val, i ) {\n\t\t\t\treturn {\n\t\t\t\t\ttext: lang[i],\n\t\t\t\t\tclassName: 'button-page-length',\n\t\t\t\t\taction: function ( e, dt ) {\n\t\t\t\t\t\tdt.page.len( val ).draw();\n\t\t\t\t\t},\n\t\t\t\t\tinit: function ( dt, node, conf ) {\n\t\t\t\t\t\tvar that = this;\n\t\t\t\t\t\tvar fn = function () {\n\t\t\t\t\t\t\tthat.active( dt.page.len() === val );\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tdt.on( 'length.dt'+conf.namespace, fn );\n\t\t\t\t\t\tfn();\n\t\t\t\t\t},\n\t\t\t\t\tdestroy: function ( dt, node, conf ) {\n\t\t\t\t\t\tdt.off( 'length.dt'+conf.namespace );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t} ),\n\t\t\tinit: function ( dt, node, conf ) {\n\t\t\t\tvar that = this;\n\t\t\t\tdt.on( 'length.dt'+conf.namespace, function () {\n\t\t\t\t\tthat.text( conf.text );\n\t\t\t\t} );\n\t\t\t},\n\t\t\tdestroy: function ( dt, node, conf ) {\n\t\t\t\tdt.off( 'length.dt'+conf.namespace );\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables API\n *\n * For complete documentation, please refer to the docs/api directory or the\n * DataTables site\n */\n\n// Buttons group and individual button selector\nDataTable.Api.register( 'buttons()', function ( group, selector ) {\n\t// Argument shifting\n\tif ( selector === undefined ) {\n\t\tselector = group;\n\t\tgroup = undefined;\n\t}\n\n\tthis.selector.buttonGroup = group;\n\n\tvar res = this.iterator( true, 'table', function ( ctx ) {\n\t\tif ( ctx._buttons ) {\n\t\t\treturn Buttons.buttonSelector(\n\t\t\t\tButtons.instanceSelector( group, ctx._buttons ),\n\t\t\t\tselector\n\t\t\t);\n\t\t}\n\t}, true );\n\n\tres._groupSelector = group;\n\treturn res;\n} );\n\n// Individual button selector\nDataTable.Api.register( 'button()', function ( group, selector ) {\n\t// just run buttons() and truncate\n\tvar buttons = this.buttons( group, selector );\n\n\tif ( buttons.length > 1 ) {\n\t\tbuttons.splice( 1, buttons.length );\n\t}\n\n\treturn buttons;\n} );\n\n// Active buttons\nDataTable.Api.registerPlural( 'buttons().active()', 'button().active()', function ( flag ) {\n\tif ( flag === undefined ) {\n\t\treturn this.map( function ( set ) {\n\t\t\treturn set.inst.active( set.node );\n\t\t} );\n\t}\n\n\treturn this.each( function ( set ) {\n\t\tset.inst.active( set.node, flag );\n\t} );\n} );\n\n// Get / set button action\nDataTable.Api.registerPlural( 'buttons().action()', 'button().action()', function ( action ) {\n\tif ( action === undefined ) {\n\t\treturn this.map( function ( set ) {\n\t\t\treturn set.inst.action( set.node );\n\t\t} );\n\t}\n\n\treturn this.each( function ( set ) {\n\t\tset.inst.action( set.node, action );\n\t} );\n} );\n\n// Enable / disable buttons\nDataTable.Api.register( ['buttons().enable()', 'button().enable()'], function ( flag ) {\n\treturn this.each( function ( set ) {\n\t\tset.inst.enable( set.node, flag );\n\t} );\n} );\n\n// Disable buttons\nDataTable.Api.register( ['buttons().disable()', 'button().disable()'], function () {\n\treturn this.each( function ( set ) {\n\t\tset.inst.disable( set.node );\n\t} );\n} );\n\n// Get button nodes\nDataTable.Api.registerPlural( 'buttons().nodes()', 'button().node()', function () {\n\tvar jq = $();\n\n\t// jQuery will automatically reduce duplicates to a single entry\n\t$( this.each( function ( set ) {\n\t\tjq = jq.add( set.inst.node( set.node ) );\n\t} ) );\n\n\treturn jq;\n} );\n\n// Get / set button processing state\nDataTable.Api.registerPlural( 'buttons().processing()', 'button().processing()', function ( flag ) {\n\tif ( flag === undefined ) {\n\t\treturn this.map( function ( set ) {\n\t\t\treturn set.inst.processing( set.node );\n\t\t} );\n\t}\n\n\treturn this.each( function ( set ) {\n\t\tset.inst.processing( set.node, flag );\n\t} );\n} );\n\n// Get / set button text (i.e. the button labels)\nDataTable.Api.registerPlural( 'buttons().text()', 'button().text()', function ( label ) {\n\tif ( label === undefined ) {\n\t\treturn this.map( function ( set ) {\n\t\t\treturn set.inst.text( set.node );\n\t\t} );\n\t}\n\n\treturn this.each( function ( set ) {\n\t\tset.inst.text( set.node, label );\n\t} );\n} );\n\n// Trigger a button's action\nDataTable.Api.registerPlural( 'buttons().trigger()', 'button().trigger()', function () {\n\treturn this.each( function ( set ) {\n\t\tset.inst.node( set.node ).trigger( 'click' );\n\t} );\n} );\n\n// Get the container elements\nDataTable.Api.registerPlural( 'buttons().containers()', 'buttons().container()', function () {\n\tvar jq = $();\n\tvar groupSelector = this._groupSelector;\n\n\t// We need to use the group selector directly, since if there are no buttons\n\t// the result set will be empty\n\tthis.iterator( true, 'table', function ( ctx ) {\n\t\tif ( ctx._buttons ) {\n\t\t\tvar insts = Buttons.instanceSelector( groupSelector, ctx._buttons );\n\n\t\t\tfor ( var i=0, ien=insts.length ; i<ien ; i++ ) {\n\t\t\t\tjq = jq.add( insts[i].container() );\n\t\t\t}\n\t\t}\n\t} );\n\n\treturn jq;\n} );\n\n// Add a new button\nDataTable.Api.register( 'button().add()', function ( idx, conf ) {\n\tvar ctx = this.context;\n\n\t// Don't use `this` as it could be empty - select the instances directly\n\tif ( ctx.length ) {\n\t\tvar inst = Buttons.instanceSelector( this._groupSelector, ctx[0]._buttons );\n\n\t\tif ( inst.length ) {\n\t\t\tinst[0].add( conf, idx );\n\t\t}\n\t}\n\n\treturn this.button( this._groupSelector, idx );\n} );\n\n// Destroy the button sets selected\nDataTable.Api.register( 'buttons().destroy()', function () {\n\tthis.pluck( 'inst' ).unique().each( function ( inst ) {\n\t\tinst.destroy();\n\t} );\n\n\treturn this;\n} );\n\n// Remove a button\nDataTable.Api.registerPlural( 'buttons().remove()', 'buttons().remove()', function () {\n\tthis.each( function ( set ) {\n\t\tset.inst.remove( set.node );\n\t} );\n\n\treturn this;\n} );\n\n// Information box that can be used by buttons\nvar _infoTimer;\nDataTable.Api.register( 'buttons.info()', function ( title, message, time ) {\n\tvar that = this;\n\n\tif ( title === false ) {\n\t\t$('#datatables_buttons_info').fadeOut( function () {\n\t\t\t$(this).remove();\n\t\t} );\n\t\tclearTimeout( _infoTimer );\n\t\t_infoTimer = null;\n\n\t\treturn this;\n\t}\n\n\tif ( _infoTimer ) {\n\t\tclearTimeout( _infoTimer );\n\t}\n\n\tif ( $('#datatables_buttons_info').length ) {\n\t\t$('#datatables_buttons_info').remove();\n\t}\n\n\ttitle = title ? '<h2>'+title+'</h2>' : '';\n\n\t$('<div id=\"datatables_buttons_info\" class=\"dt-button-info\"/>')\n\t\t.html( title )\n\t\t.append( $('<div/>')[ typeof message === 'string' ? 'html' : 'append' ]( message ) )\n\t\t.css( 'display', 'none' )\n\t\t.appendTo( 'body' )\n\t\t.fadeIn();\n\n\tif ( time !== undefined && time !== 0 ) {\n\t\t_infoTimer = setTimeout( function () {\n\t\t\tthat.buttons.info( false );\n\t\t}, time );\n\t}\n\n\treturn this;\n} );\n\n// Get data from the table for export - this is common to a number of plug-in\n// buttons so it is included in the Buttons core library\nDataTable.Api.register( 'buttons.exportData()', function ( options ) {\n\tif ( this.context.length ) {\n\t\treturn _exportData( new DataTable.Api( this.context[0] ), options );\n\t}\n} );\n\n// Get information about the export that is common to many of the export data\n// types (DRY)\nDataTable.Api.register( 'buttons.exportInfo()', function ( conf ) {\n\tif ( ! conf ) {\n\t\tconf = {};\n\t}\n\n\treturn {\n\t\tfilename: _filename( conf ),\n\t\ttitle: _title( conf ),\n\t\tmessageTop: _message(this, conf.message || conf.messageTop, 'top'),\n\t\tmessageBottom: _message(this, conf.messageBottom, 'bottom')\n\t};\n} );\n\n\n\n/**\n * Get the file name for an exported file.\n *\n * @param {object}\tconfig Button configuration\n * @param {boolean} incExtension Include the file name extension\n */\nvar _filename = function ( config )\n{\n\t// Backwards compatibility\n\tvar filename = config.filename === '*' && config.title !== '*' && config.title !== undefined && config.title !== null && config.title !== '' ?\n\t\tconfig.title :\n\t\tconfig.filename;\n\n\tif ( typeof filename === 'function' ) {\n\t\tfilename = filename();\n\t}\n\n\tif ( filename === undefined || filename === null ) {\n\t\treturn null;\n\t}\n\n\tif ( filename.indexOf( '*' ) !== -1 ) {\n\t\tfilename = $.trim( filename.replace( '*', $('head > title').text() ) );\n\t}\n\n\t// Strip characters which the OS will object to\n\tfilename = filename.replace(/[^a-zA-Z0-9_\\u00A1-\\uFFFF\\.,\\-_ !\\(\\)]/g, \"\");\n\n\tvar extension = _stringOrFunction( config.extension );\n\tif ( ! extension ) {\n\t\textension = '';\n\t}\n\n\treturn filename + extension;\n};\n\n/**\n * Simply utility method to allow parameters to be given as a function\n *\n * @param {undefined|string|function} option Option\n * @return {null|string} Resolved value\n */\nvar _stringOrFunction = function ( option )\n{\n\tif ( option === null || option === undefined ) {\n\t\treturn null;\n\t}\n\telse if ( typeof option === 'function' ) {\n\t\treturn option();\n\t}\n\treturn option;\n};\n\n/**\n * Get the title for an exported file.\n *\n * @param {object} config\tButton configuration\n */\nvar _title = function ( config )\n{\n\tvar title = _stringOrFunction( config.title );\n\n\treturn title === null ?\n\t\tnull : title.indexOf( '*' ) !== -1 ?\n\t\t\ttitle.replace( '*', $('head > title').text() || 'Exported data' ) :\n\t\t\ttitle;\n};\n\nvar _message = function ( dt, option, position )\n{\n\tvar message = _stringOrFunction( option );\n\tif ( message === null ) {\n\t\treturn null;\n\t}\n\n\tvar caption = $('caption', dt.table().container()).eq(0);\n\tif ( message === '*' ) {\n\t\tvar side = caption.css( 'caption-side' );\n\t\tif ( side !== position ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn caption.length ?\n\t\t\tcaption.text() :\n\t\t\t'';\n\t}\n\n\treturn message;\n};\n\n\n\n\n\n\n\nvar _exportTextarea = $('<textarea/>')[0];\nvar _exportData = function ( dt, inOpts )\n{\n\tvar config = $.extend( true, {}, {\n\t\trows:           null,\n\t\tcolumns:        '',\n\t\tmodifier:       {\n\t\t\tsearch: 'applied',\n\t\t\torder:  'applied'\n\t\t},\n\t\torthogonal:     'display',\n\t\tstripHtml:      true,\n\t\tstripNewlines:  true,\n\t\tdecodeEntities: true,\n\t\ttrim:           true,\n\t\tformat:         {\n\t\t\theader: function ( d ) {\n\t\t\t\treturn strip( d );\n\t\t\t},\n\t\t\tfooter: function ( d ) {\n\t\t\t\treturn strip( d );\n\t\t\t},\n\t\t\tbody: function ( d ) {\n\t\t\t\treturn strip( d );\n\t\t\t}\n\t\t},\n\t\tcustomizeData: null\n\t}, inOpts );\n\n\tvar strip = function ( str ) {\n\t\tif ( typeof str !== 'string' ) {\n\t\t\treturn str;\n\t\t}\n\n\t\t// Always remove script tags\n\t\tstr = str.replace( /<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi, '' );\n\n\t\t// Always remove comments\n\t\tstr = str.replace( /<!\\-\\-.*?\\-\\->/g, '' );\n\n\t\tif ( config.stripHtml ) {\n\t\t\tstr = str.replace( /<[^>]*>/g, '' );\n\t\t}\n\n\t\tif ( config.trim ) {\n\t\t\tstr = str.replace( /^\\s+|\\s+$/g, '' );\n\t\t}\n\n\t\tif ( config.stripNewlines ) {\n\t\t\tstr = str.replace( /\\n/g, ' ' );\n\t\t}\n\n\t\tif ( config.decodeEntities ) {\n\t\t\t_exportTextarea.innerHTML = str;\n\t\t\tstr = _exportTextarea.value;\n\t\t}\n\n\t\treturn str;\n\t};\n\n\n\tvar header = dt.columns( config.columns ).indexes().map( function (idx) {\n\t\tvar el = dt.column( idx ).header();\n\t\treturn config.format.header( el.innerHTML, idx, el );\n\t} ).toArray();\n\n\tvar footer = dt.table().footer() ?\n\t\tdt.columns( config.columns ).indexes().map( function (idx) {\n\t\t\tvar el = dt.column( idx ).footer();\n\t\t\treturn config.format.footer( el ? el.innerHTML : '', idx, el );\n\t\t} ).toArray() :\n\t\tnull;\n\t\n\t// If Select is available on this table, and any rows are selected, limit the export\n\t// to the selected rows. If no rows are selected, all rows will be exported. Specify\n\t// a `selected` modifier to control directly.\n\tvar modifier = $.extend( {}, config.modifier );\n\tif ( dt.select && typeof dt.select.info === 'function' && modifier.selected === undefined ) {\n\t\tif ( dt.rows( config.rows, $.extend( { selected: true }, modifier ) ).any() ) {\n\t\t\t$.extend( modifier, { selected: true } )\n\t\t}\n\t}\n\n\tvar rowIndexes = dt.rows( config.rows, modifier ).indexes().toArray();\n\tvar selectedCells = dt.cells( rowIndexes, config.columns );\n\tvar cells = selectedCells\n\t\t.render( config.orthogonal )\n\t\t.toArray();\n\tvar cellNodes = selectedCells\n\t\t.nodes()\n\t\t.toArray();\n\n\tvar columns = header.length;\n\tvar rows = columns > 0 ? cells.length / columns : 0;\n\tvar body = [];\n\tvar cellCounter = 0;\n\n\tfor ( var i=0, ien=rows ; i<ien ; i++ ) {\n\t\tvar row = [ columns ];\n\n\t\tfor ( var j=0 ; j<columns ; j++ ) {\n\t\t\trow[j] = config.format.body( cells[ cellCounter ], i, j, cellNodes[ cellCounter ] );\n\t\t\tcellCounter++;\n\t\t}\n\n\t\tbody[i] = row;\n\t}\n\n\tvar data = {\n\t\theader: header,\n\t\tfooter: footer,\n\t\tbody:   body\n\t};\n\n\tif ( config.customizeData ) {\n\t\tconfig.customizeData( data );\n\t}\n\n\treturn data;\n};\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables interface\n */\n\n// Attach to DataTables objects for global access\n$.fn.dataTable.Buttons = Buttons;\n$.fn.DataTable.Buttons = Buttons;\n\n\n\n// DataTables creation - check if the buttons have been defined for this table,\n// they will have been if the `B` option was used in `dom`, otherwise we should\n// create the buttons instance here so they can be inserted into the document\n// using the API. Listen for `init` for compatibility with pre 1.10.10, but to\n// be removed in future.\n$(document).on( 'init.dt plugin-init.dt', function (e, settings) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar opts = settings.oInit.buttons || DataTable.defaults.buttons;\n\n\tif ( opts && ! settings._buttons ) {\n\t\tnew Buttons( settings, opts ).container();\n\t}\n} );\n\nfunction _init ( settings ) {\n\tvar api = new DataTable.Api( settings );\n\tvar opts = api.init().buttons || DataTable.defaults.buttons;\n\n\treturn new Buttons( api, opts ).container();\n}\n\n// DataTables `dom` feature option\nDataTable.ext.feature.push( {\n\tfnInit: _init,\n\tcFeature: \"B\"\n} );\n\n// DataTables 2 layout feature\nif ( DataTable.ext.features ) {\n\tDataTable.ext.features.register( 'buttons', _init );\n}\n\n\nreturn Buttons;\n}));\n\n\n/*! Foundation integration for DataTables' Buttons\n * ©2016 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net-zf', 'datatables.net-buttons'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net-zf')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Buttons ) {\n\t\t\t\trequire('datatables.net-buttons')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n// F6 has different requirements for the dropdown button set. We can use the\n// Foundation version found by DataTables in order to support both F5 and F6 in\n// the same file, but not that this requires DataTables 1.10.11+ for F6 support.\nvar collection = DataTable.ext.foundationVersion === 6 ?\n\t{\n\t\ttag: 'div',\n\t\tclassName: 'dt-button-collection dropdown-pane is-open button-group stacked'\n\t} :\n\t{\n\t\ttag: 'ul',\n\t\tclassName: 'dt-button-collection f-dropdown open dropdown-pane is-open',\n\t\tbutton: {\n\t\t\ttag: 'li',\n\t\t\tclassName: 'small',\n\t\t\tactive: 'active',\n\t\t\tdisabled: 'disabled'\n\t\t},\n\t\tbuttonLiner: {\n\t\t\ttag: 'a'\n\t\t}\n\t};\n\n$.extend( true, DataTable.Buttons.defaults, {\n\tdom: {\n\t\tcontainer: {\n\t\t\ttag: 'div',\n\t\t\tclassName: 'dt-buttons button-group'\n\t\t},\n\t\tbuttonContainer: {\n\t\t\ttag: null,\n\t\t\tclassName: ''\n\t\t},\n\t\tbutton: {\n\t\t\ttag: 'a',\n\t\t\tclassName: 'button small',\n\t\t\tactive: 'secondary'\n\t\t},\n\t\tbuttonLiner: {\n\t\t\ttag: null\n\t\t},\n\t\tcollection: collection\n\t}\n} );\n\n\nDataTable.ext.buttons.collection.className = 'buttons-collection dropdown';\n\n\nreturn DataTable.Buttons;\n}));\n\n\n/*!\n * Column visibility buttons for Buttons and DataTables.\n * 2016 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Buttons ) {\n\t\t\t\trequire('datatables.net-buttons')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n$.extend( DataTable.ext.buttons, {\n\t// A collection of column visibility buttons\n\tcolvis: function ( dt, conf ) {\n\t\treturn {\n\t\t\textend: 'collection',\n\t\t\ttext: function ( dt ) {\n\t\t\t\treturn dt.i18n( 'buttons.colvis', 'Column visibility' );\n\t\t\t},\n\t\t\tclassName: 'buttons-colvis',\n\t\t\tbuttons: [ {\n\t\t\t\textend: 'columnsToggle',\n\t\t\t\tcolumns: conf.columns,\n\t\t\t\tcolumnText: conf.columnText\n\t\t\t} ]\n\t\t};\n\t},\n\n\t// Selected columns with individual buttons - toggle column visibility\n\tcolumnsToggle: function ( dt, conf ) {\n\t\tvar columns = dt.columns( conf.columns ).indexes().map( function ( idx ) {\n\t\t\treturn {\n\t\t\t\textend: 'columnToggle',\n\t\t\t\tcolumns: idx,\n\t\t\t\tcolumnText: conf.columnText\n\t\t\t};\n\t\t} ).toArray();\n\n\t\treturn columns;\n\t},\n\n\t// Single button to toggle column visibility\n\tcolumnToggle: function ( dt, conf ) {\n\t\treturn {\n\t\t\textend: 'columnVisibility',\n\t\t\tcolumns: conf.columns,\n\t\t\tcolumnText: conf.columnText\n\t\t};\n\t},\n\n\t// Selected columns with individual buttons - set column visibility\n\tcolumnsVisibility: function ( dt, conf ) {\n\t\tvar columns = dt.columns( conf.columns ).indexes().map( function ( idx ) {\n\t\t\treturn {\n\t\t\t\textend: 'columnVisibility',\n\t\t\t\tcolumns: idx,\n\t\t\t\tvisibility: conf.visibility,\n\t\t\t\tcolumnText: conf.columnText\n\t\t\t};\n\t\t} ).toArray();\n\n\t\treturn columns;\n\t},\n\n\t// Single button to set column visibility\n\tcolumnVisibility: {\n\t\tcolumns: undefined, // column selector\n\t\ttext: function ( dt, button, conf ) {\n\t\t\treturn conf._columnText( dt, conf );\n\t\t},\n\t\tclassName: 'buttons-columnVisibility',\n\t\taction: function ( e, dt, button, conf ) {\n\t\t\tvar col = dt.columns( conf.columns );\n\t\t\tvar curr = col.visible();\n\n\t\t\tcol.visible( conf.visibility !== undefined ?\n\t\t\t\tconf.visibility :\n\t\t\t\t! (curr.length ? curr[0] : false )\n\t\t\t);\n\t\t},\n\t\tinit: function ( dt, button, conf ) {\n\t\t\tvar that = this;\n\t\t\tbutton.attr( 'data-cv-idx', conf.columns );\n\n\t\t\tdt\n\t\t\t\t.on( 'column-visibility.dt'+conf.namespace, function (e, settings) {\n\t\t\t\t\tif ( ! settings.bDestroying && settings.nTable == dt.settings()[0].nTable ) {\n\t\t\t\t\t\tthat.active( dt.column( conf.columns ).visible() );\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t\t.on( 'column-reorder.dt'+conf.namespace, function (e, settings, details) {\n\t\t\t\t\t// Don't rename buttons based on column name if the button\n\t\t\t\t\t// controls more than one column!\n\t\t\t\t\tif ( dt.columns( conf.columns ).count() !== 1 ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconf.columns = $.inArray( conf.columns, details.mapping );\n\t\t\t\t\tbutton.attr( 'data-cv-idx', conf.columns );\n\n\t\t\t\t\t// Reorder buttons for new table order\n\t\t\t\t\tbutton\n\t\t\t\t\t\t.parent()\n\t\t\t\t\t\t.children('[data-cv-idx]')\n\t\t\t\t\t\t.sort( function (a, b) {\n\t\t\t\t\t\t\treturn (a.getAttribute('data-cv-idx')*1) - (b.getAttribute('data-cv-idx')*1);\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.appendTo(button.parent());\n\t\t\t\t} );\n\n\t\t\tthis.active( dt.column( conf.columns ).visible() );\n\t\t},\n\t\tdestroy: function ( dt, button, conf ) {\n\t\t\tdt\n\t\t\t\t.off( 'column-visibility.dt'+conf.namespace )\n\t\t\t\t.off( 'column-reorder.dt'+conf.namespace );\n\t\t},\n\n\t\t_columnText: function ( dt, conf ) {\n\t\t\t// Use DataTables' internal data structure until this is presented\n\t\t\t// is a public API. The other option is to use\n\t\t\t// `$( column(col).node() ).text()` but the node might not have been\n\t\t\t// populated when Buttons is constructed.\n\t\t\tvar idx = dt.column( conf.columns ).index();\n\t\t\tvar title = dt.settings()[0].aoColumns[ idx ].sTitle\n\t\t\t\t.replace(/\\n/g,\" \")        // remove new lines\n\t\t\t\t.replace(/<br\\s*\\/?>/gi, \" \")  // replace line breaks with spaces\n\t\t\t\t.replace(/<select(.*?)<\\/select>/g, \"\") // remove select tags, including options text\n\t\t\t\t.replace(/<!\\-\\-.*?\\-\\->/g, \"\") // strip HTML comments\n\t\t\t\t.replace(/<.*?>/g, \"\")   // strip HTML\n\t\t\t\t.replace(/^\\s+|\\s+$/g,\"\"); // trim\n\n\t\t\treturn conf.columnText ?\n\t\t\t\tconf.columnText( dt, idx, title ) :\n\t\t\t\ttitle;\n\t\t}\n\t},\n\n\n\tcolvisRestore: {\n\t\tclassName: 'buttons-colvisRestore',\n\n\t\ttext: function ( dt ) {\n\t\t\treturn dt.i18n( 'buttons.colvisRestore', 'Restore visibility' );\n\t\t},\n\n\t\tinit: function ( dt, button, conf ) {\n\t\t\tconf._visOriginal = dt.columns().indexes().map( function ( idx ) {\n\t\t\t\treturn dt.column( idx ).visible();\n\t\t\t} ).toArray();\n\t\t},\n\n\t\taction: function ( e, dt, button, conf ) {\n\t\t\tdt.columns().every( function ( i ) {\n\t\t\t\t// Take into account that ColReorder might have disrupted our\n\t\t\t\t// indexes\n\t\t\t\tvar idx = dt.colReorder && dt.colReorder.transpose ?\n\t\t\t\t\tdt.colReorder.transpose( i, 'toOriginal' ) :\n\t\t\t\t\ti;\n\n\t\t\t\tthis.visible( conf._visOriginal[ idx ] );\n\t\t\t} );\n\t\t}\n\t},\n\n\n\tcolvisGroup: {\n\t\tclassName: 'buttons-colvisGroup',\n\n\t\taction: function ( e, dt, button, conf ) {\n\t\t\tdt.columns( conf.show ).visible( true, false );\n\t\t\tdt.columns( conf.hide ).visible( false, false );\n\n\t\t\tdt.columns.adjust();\n\t\t},\n\n\t\tshow: [],\n\n\t\thide: []\n\t}\n} );\n\n\nreturn DataTable.Buttons;\n}));\n\n\n/*!\n * Flash export buttons for Buttons and DataTables.\n * 2015-2017 SpryMedia Ltd - datatables.net/license\n *\n * ZeroClipbaord - MIT license\n * Copyright (c) 2012 Joseph Huckaby\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Buttons ) {\n\t\t\t\trequire('datatables.net-buttons')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * ZeroClipboard dependency\n */\n\n/*\n * ZeroClipboard 1.0.4 with modifications\n * Author: Joseph Huckaby\n * License: MIT\n *\n * Copyright (c) 2012 Joseph Huckaby\n */\nvar ZeroClipboard_TableTools = {\n\tversion: \"1.0.4-TableTools2\",\n\tclients: {}, // registered upload clients on page, indexed by id\n\tmoviePath: '', // URL to movie\n\tnextId: 1, // ID of next movie\n\n\t$: function(thingy) {\n\t\t// simple DOM lookup utility function\n\t\tif (typeof(thingy) == 'string') {\n\t\t\tthingy = document.getElementById(thingy);\n\t\t}\n\t\tif (!thingy.addClass) {\n\t\t\t// extend element with a few useful methods\n\t\t\tthingy.hide = function() { this.style.display = 'none'; };\n\t\t\tthingy.show = function() { this.style.display = ''; };\n\t\t\tthingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };\n\t\t\tthingy.removeClass = function(name) {\n\t\t\t\tthis.className = this.className.replace( new RegExp(\"\\\\s*\" + name + \"\\\\s*\"), \" \").replace(/^\\s+/, '').replace(/\\s+$/, '');\n\t\t\t};\n\t\t\tthingy.hasClass = function(name) {\n\t\t\t\treturn !!this.className.match( new RegExp(\"\\\\s*\" + name + \"\\\\s*\") );\n\t\t\t};\n\t\t}\n\t\treturn thingy;\n\t},\n\n\tsetMoviePath: function(path) {\n\t\t// set path to ZeroClipboard.swf\n\t\tthis.moviePath = path;\n\t},\n\n\tdispatch: function(id, eventName, args) {\n\t\t// receive event from flash movie, send to client\n\t\tvar client = this.clients[id];\n\t\tif (client) {\n\t\t\tclient.receiveEvent(eventName, args);\n\t\t}\n\t},\n\n\tlog: function ( str ) {\n\t\tconsole.log( 'Flash: '+str );\n\t},\n\n\tregister: function(id, client) {\n\t\t// register new client to receive events\n\t\tthis.clients[id] = client;\n\t},\n\n\tgetDOMObjectPosition: function(obj) {\n\t\t// get absolute coordinates for dom element\n\t\tvar info = {\n\t\t\tleft: 0,\n\t\t\ttop: 0,\n\t\t\twidth: obj.width ? obj.width : obj.offsetWidth,\n\t\t\theight: obj.height ? obj.height : obj.offsetHeight\n\t\t};\n\n\t\tif ( obj.style.width !== \"\" ) {\n\t\t\tinfo.width = obj.style.width.replace(\"px\",\"\");\n\t\t}\n\n\t\tif ( obj.style.height !== \"\" ) {\n\t\t\tinfo.height = obj.style.height.replace(\"px\",\"\");\n\t\t}\n\n\t\twhile (obj) {\n\t\t\tinfo.left += obj.offsetLeft;\n\t\t\tinfo.top += obj.offsetTop;\n\t\t\tobj = obj.offsetParent;\n\t\t}\n\n\t\treturn info;\n\t},\n\n\tClient: function(elem) {\n\t\t// constructor for new simple upload client\n\t\tthis.handlers = {};\n\n\t\t// unique ID\n\t\tthis.id = ZeroClipboard_TableTools.nextId++;\n\t\tthis.movieId = 'ZeroClipboard_TableToolsMovie_' + this.id;\n\n\t\t// register client with singleton to receive flash events\n\t\tZeroClipboard_TableTools.register(this.id, this);\n\n\t\t// create movie\n\t\tif (elem) {\n\t\t\tthis.glue(elem);\n\t\t}\n\t}\n};\n\nZeroClipboard_TableTools.Client.prototype = {\n\n\tid: 0, // unique ID for us\n\tready: false, // whether movie is ready to receive events or not\n\tmovie: null, // reference to movie object\n\tclipText: '', // text to copy to clipboard\n\tfileName: '', // default file save name\n\taction: 'copy', // action to perform\n\thandCursorEnabled: true, // whether to show hand cursor, or default pointer cursor\n\tcssEffects: true, // enable CSS mouse effects on dom container\n\thandlers: null, // user event handlers\n\tsized: false,\n\tsheetName: '', // default sheet name for excel export\n\n\tglue: function(elem, title) {\n\t\t// glue to DOM element\n\t\t// elem can be ID or actual DOM element object\n\t\tthis.domElement = ZeroClipboard_TableTools.$(elem);\n\n\t\t// float just above object, or zIndex 99 if dom element isn't set\n\t\tvar zIndex = 99;\n\t\tif (this.domElement.style.zIndex) {\n\t\t\tzIndex = parseInt(this.domElement.style.zIndex, 10) + 1;\n\t\t}\n\n\t\t// find X/Y position of domElement\n\t\tvar box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);\n\n\t\t// create floating DIV above element\n\t\tthis.div = document.createElement('div');\n\t\tvar style = this.div.style;\n\t\tstyle.position = 'absolute';\n\t\tstyle.left = '0px';\n\t\tstyle.top = '0px';\n\t\tstyle.width = (box.width) + 'px';\n\t\tstyle.height = box.height + 'px';\n\t\tstyle.zIndex = zIndex;\n\n\t\tif ( typeof title != \"undefined\" && title !== \"\" ) {\n\t\t\tthis.div.title = title;\n\t\t}\n\t\tif ( box.width !== 0 && box.height !== 0 ) {\n\t\t\tthis.sized = true;\n\t\t}\n\n\t\t// style.backgroundColor = '#f00'; // debug\n\t\tif ( this.domElement ) {\n\t\t\tthis.domElement.appendChild(this.div);\n\t\t\tthis.div.innerHTML = this.getHTML( box.width, box.height ).replace(/&/g, '&amp;');\n\t\t}\n\t},\n\n\tpositionElement: function() {\n\t\tvar box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);\n\t\tvar style = this.div.style;\n\n\t\tstyle.position = 'absolute';\n\t\t//style.left = (this.domElement.offsetLeft)+'px';\n\t\t//style.top = this.domElement.offsetTop+'px';\n\t\tstyle.width = box.width + 'px';\n\t\tstyle.height = box.height + 'px';\n\n\t\tif ( box.width !== 0 && box.height !== 0 ) {\n\t\t\tthis.sized = true;\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\n\t\tvar flash = this.div.childNodes[0];\n\t\tflash.width = box.width;\n\t\tflash.height = box.height;\n\t},\n\n\tgetHTML: function(width, height) {\n\t\t// return HTML for movie\n\t\tvar html = '';\n\t\tvar flashvars = 'id=' + this.id +\n\t\t\t'&width=' + width +\n\t\t\t'&height=' + height;\n\n\t\tif (navigator.userAgent.match(/MSIE/)) {\n\t\t\t// IE gets an OBJECT tag\n\t\t\tvar protocol = location.href.match(/^https/i) ? 'https://' : 'http://';\n\t\t\thtml += '<object classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" codebase=\"'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,0,0\" width=\"'+width+'\" height=\"'+height+'\" id=\"'+this.movieId+'\" align=\"middle\"><param name=\"allowScriptAccess\" value=\"always\" /><param name=\"allowFullScreen\" value=\"false\" /><param name=\"movie\" value=\"'+ZeroClipboard_TableTools.moviePath+'\" /><param name=\"loop\" value=\"false\" /><param name=\"menu\" value=\"false\" /><param name=\"quality\" value=\"best\" /><param name=\"bgcolor\" value=\"#ffffff\" /><param name=\"flashvars\" value=\"'+flashvars+'\"/><param name=\"wmode\" value=\"transparent\"/></object>';\n\t\t}\n\t\telse {\n\t\t\t// all other browsers get an EMBED tag\n\t\t\thtml += '<embed id=\"'+this.movieId+'\" src=\"'+ZeroClipboard_TableTools.moviePath+'\" loop=\"false\" menu=\"false\" quality=\"best\" bgcolor=\"#ffffff\" width=\"'+width+'\" height=\"'+height+'\" name=\"'+this.movieId+'\" align=\"middle\" allowScriptAccess=\"always\" allowFullScreen=\"false\" type=\"application/x-shockwave-flash\" pluginspage=\"http://www.macromedia.com/go/getflashplayer\" flashvars=\"'+flashvars+'\" wmode=\"transparent\" />';\n\t\t}\n\t\treturn html;\n\t},\n\n\thide: function() {\n\t\t// temporarily hide floater offscreen\n\t\tif (this.div) {\n\t\t\tthis.div.style.left = '-2000px';\n\t\t}\n\t},\n\n\tshow: function() {\n\t\t// show ourselves after a call to hide()\n\t\tthis.reposition();\n\t},\n\n\tdestroy: function() {\n\t\t// destroy control and floater\n\t\tvar that = this;\n\n\t\tif (this.domElement && this.div) {\n\t\t\t$(this.div).remove();\n\n\t\t\tthis.domElement = null;\n\t\t\tthis.div = null;\n\n\t\t\t$.each( ZeroClipboard_TableTools.clients, function ( id, client ) {\n\t\t\t\tif ( client === that ) {\n\t\t\t\t\tdelete ZeroClipboard_TableTools.clients[ id ];\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t},\n\n\treposition: function(elem) {\n\t\t// reposition our floating div, optionally to new container\n\t\t// warning: container CANNOT change size, only position\n\t\tif (elem) {\n\t\t\tthis.domElement = ZeroClipboard_TableTools.$(elem);\n\t\t\tif (!this.domElement) {\n\t\t\t\tthis.hide();\n\t\t\t}\n\t\t}\n\n\t\tif (this.domElement && this.div) {\n\t\t\tvar box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);\n\t\t\tvar style = this.div.style;\n\t\t\tstyle.left = '' + box.left + 'px';\n\t\t\tstyle.top = '' + box.top + 'px';\n\t\t}\n\t},\n\n\tclearText: function() {\n\t\t// clear the text to be copy / saved\n\t\tthis.clipText = '';\n\t\tif (this.ready) {\n\t\t\tthis.movie.clearText();\n\t\t}\n\t},\n\n\tappendText: function(newText) {\n\t\t// append text to that which is to be copied / saved\n\t\tthis.clipText += newText;\n\t\tif (this.ready) { this.movie.appendText(newText) ;}\n\t},\n\n\tsetText: function(newText) {\n\t\t// set text to be copied to be copied / saved\n\t\tthis.clipText = newText;\n\t\tif (this.ready) { this.movie.setText(newText) ;}\n\t},\n\n\tsetFileName: function(newText) {\n\t\t// set the file name\n\t\tthis.fileName = newText;\n\t\tif (this.ready) {\n\t\t\tthis.movie.setFileName(newText);\n\t\t}\n\t},\n\n\tsetSheetData: function(data) {\n\t\t// set the xlsx sheet data\n\t\tif (this.ready) {\n\t\t\tthis.movie.setSheetData( JSON.stringify( data ) );\n\t\t}\n\t},\n\n\tsetAction: function(newText) {\n\t\t// set action (save or copy)\n\t\tthis.action = newText;\n\t\tif (this.ready) {\n\t\t\tthis.movie.setAction(newText);\n\t\t}\n\t},\n\n\taddEventListener: function(eventName, func) {\n\t\t// add user event listener for event\n\t\t// event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel\n\t\teventName = eventName.toString().toLowerCase().replace(/^on/, '');\n\t\tif (!this.handlers[eventName]) {\n\t\t\tthis.handlers[eventName] = [];\n\t\t}\n\t\tthis.handlers[eventName].push(func);\n\t},\n\n\tsetHandCursor: function(enabled) {\n\t\t// enable hand cursor (true), or default arrow cursor (false)\n\t\tthis.handCursorEnabled = enabled;\n\t\tif (this.ready) {\n\t\t\tthis.movie.setHandCursor(enabled);\n\t\t}\n\t},\n\n\tsetCSSEffects: function(enabled) {\n\t\t// enable or disable CSS effects on DOM container\n\t\tthis.cssEffects = !!enabled;\n\t},\n\n\treceiveEvent: function(eventName, args) {\n\t\tvar self;\n\n\t\t// receive event from flash\n\t\teventName = eventName.toString().toLowerCase().replace(/^on/, '');\n\n\t\t// special behavior for certain events\n\t\tswitch (eventName) {\n\t\t\tcase 'load':\n\t\t\t\t// movie claims it is ready, but in IE this isn't always the case...\n\t\t\t\t// bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function\n\t\t\t\tthis.movie = document.getElementById(this.movieId);\n\t\t\t\tif (!this.movie) {\n\t\t\t\t\tself = this;\n\t\t\t\t\tsetTimeout( function() { self.receiveEvent('load', null); }, 1 );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// firefox on pc needs a \"kick\" in order to set these in certain cases\n\t\t\t\tif (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {\n\t\t\t\t\tself = this;\n\t\t\t\t\tsetTimeout( function() { self.receiveEvent('load', null); }, 100 );\n\t\t\t\t\tthis.ready = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.ready = true;\n\t\t\t\tthis.movie.clearText();\n\t\t\t\tthis.movie.appendText( this.clipText );\n\t\t\t\tthis.movie.setFileName( this.fileName );\n\t\t\t\tthis.movie.setAction( this.action );\n\t\t\t\tthis.movie.setHandCursor( this.handCursorEnabled );\n\t\t\t\tbreak;\n\n\t\t\tcase 'mouseover':\n\t\t\t\tif (this.domElement && this.cssEffects) {\n\t\t\t\t\t//this.domElement.addClass('hover');\n\t\t\t\t\tif (this.recoverActive) {\n\t\t\t\t\t\tthis.domElement.addClass('active');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'mouseout':\n\t\t\t\tif (this.domElement && this.cssEffects) {\n\t\t\t\t\tthis.recoverActive = false;\n\t\t\t\t\tif (this.domElement.hasClass('active')) {\n\t\t\t\t\t\tthis.domElement.removeClass('active');\n\t\t\t\t\t\tthis.recoverActive = true;\n\t\t\t\t\t}\n\t\t\t\t\t//this.domElement.removeClass('hover');\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'mousedown':\n\t\t\t\tif (this.domElement && this.cssEffects) {\n\t\t\t\t\tthis.domElement.addClass('active');\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 'mouseup':\n\t\t\t\tif (this.domElement && this.cssEffects) {\n\t\t\t\t\tthis.domElement.removeClass('active');\n\t\t\t\t\tthis.recoverActive = false;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t} // switch eventName\n\n\t\tif (this.handlers[eventName]) {\n\t\t\tfor (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {\n\t\t\t\tvar func = this.handlers[eventName][idx];\n\n\t\t\t\tif (typeof(func) == 'function') {\n\t\t\t\t\t// actual function reference\n\t\t\t\t\tfunc(this, args);\n\t\t\t\t}\n\t\t\t\telse if ((typeof(func) == 'object') && (func.length == 2)) {\n\t\t\t\t\t// PHP style object + method, i.e. [myObject, 'myMethod']\n\t\t\t\t\tfunc[0][ func[1] ](this, args);\n\t\t\t\t}\n\t\t\t\telse if (typeof(func) == 'string') {\n\t\t\t\t\t// name of function\n\t\t\t\t\twindow[func](this, args);\n\t\t\t\t}\n\t\t\t} // foreach event handler defined\n\t\t} // user defined handler for event\n\t}\n};\n\nZeroClipboard_TableTools.hasFlash = function ()\n{\n\ttry {\n\t\tvar fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');\n\t\tif (fo) {\n\t\t\treturn true;\n\t\t}\n\t}\n\tcatch (e) {\n\t\tif (\n\t\t\tnavigator.mimeTypes &&\n\t\t\tnavigator.mimeTypes['application/x-shockwave-flash'] !== undefined &&\n\t\t\tnavigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n};\n\n// For the Flash binding to work, ZeroClipboard_TableTools must be on the global\n// object list\nwindow.ZeroClipboard_TableTools = ZeroClipboard_TableTools;\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Local (private) functions\n */\n\n/**\n * If a Buttons instance is initlaised before it is placed into the DOM, Flash\n * won't be able to bind to it, so we need to wait until it is available, this\n * method abstracts that out.\n *\n * @param {ZeroClipboard} flash ZeroClipboard instance\n * @param {jQuery} node  Button\n */\nvar _glue = function ( flash, node )\n{\n\tvar id = node.attr('id');\n\n\tif ( node.parents('html').length ) {\n\t\tflash.glue( node[0], '' );\n\t}\n\telse {\n\t\tsetTimeout( function () {\n\t\t\t_glue( flash, node );\n\t\t}, 500 );\n\t}\n};\n\n/**\n * Get the sheet name for Excel exports.\n *\n * @param {object}  config       Button configuration\n */\nvar _sheetname = function ( config )\n{\n\tvar sheetName = 'Sheet1';\n\n\tif ( config.sheetName ) {\n\t\tsheetName = config.sheetName.replace(/[\\[\\]\\*\\/\\\\\\?\\:]/g, '');\n\t}\n\n\treturn sheetName;\n};\n\n/**\n * Set the flash text. This has to be broken up into chunks as the Javascript /\n * Flash bridge has a size limit. There is no indication in the Flash\n * documentation what this is, and it probably depends upon the browser.\n * Experimentation shows that the point is around 50k when data starts to get\n * lost, so an 8K limit used here is safe.\n *\n * @param {ZeroClipboard} flash ZeroClipboard instance\n * @param {string}        data  Data to send to Flash\n */\nvar _setText = function ( flash, data )\n{\n\tvar parts = data.match(/[\\s\\S]{1,8192}/g) || [];\n\n\tflash.clearText();\n\tfor ( var i=0, len=parts.length ; i<len ; i++ )\n\t{\n\t\tflash.appendText( parts[i] );\n\t}\n};\n\n/**\n * Get the newline character(s)\n *\n * @param {object}  config Button configuration\n * @return {string}        Newline character\n */\nvar _newLine = function ( config )\n{\n\treturn config.newline ?\n\t\tconfig.newline :\n\t\tnavigator.userAgent.match(/Windows/) ?\n\t\t\t'\\r\\n' :\n\t\t\t'\\n';\n};\n\n/**\n * Combine the data from the `buttons.exportData` method into a string that\n * will be used in the export file.\n *\n * @param  {DataTable.Api} dt     DataTables API instance\n * @param  {object}        config Button configuration\n * @return {object}               The data to export\n */\nvar _exportData = function ( dt, config )\n{\n\tvar newLine = _newLine( config );\n\tvar data = dt.buttons.exportData( config.exportOptions );\n\tvar boundary = config.fieldBoundary;\n\tvar separator = config.fieldSeparator;\n\tvar reBoundary = new RegExp( boundary, 'g' );\n\tvar escapeChar = config.escapeChar !== undefined ?\n\t\tconfig.escapeChar :\n\t\t'\\\\';\n\tvar join = function ( a ) {\n\t\tvar s = '';\n\n\t\t// If there is a field boundary, then we might need to escape it in\n\t\t// the source data\n\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\tif ( i > 0 ) {\n\t\t\t\ts += separator;\n\t\t\t}\n\n\t\t\ts += boundary ?\n\t\t\t\tboundary + ('' + a[i]).replace( reBoundary, escapeChar+boundary ) + boundary :\n\t\t\t\ta[i];\n\t\t}\n\n\t\treturn s;\n\t};\n\n\tvar header = config.header ? join( data.header )+newLine : '';\n\tvar footer = config.footer && data.footer ? newLine+join( data.footer ) : '';\n\tvar body = [];\n\n\tfor ( var i=0, ien=data.body.length ; i<ien ; i++ ) {\n\t\tbody.push( join( data.body[i] ) );\n\t}\n\n\treturn {\n\t\tstr: header + body.join( newLine ) + footer,\n\t\trows: body.length\n\t};\n};\n\n\n// Basic initialisation for the buttons is common between them\nvar flashButton = {\n\tavailable: function () {\n\t\treturn ZeroClipboard_TableTools.hasFlash();\n\t},\n\n\tinit: function ( dt, button, config ) {\n\t\t// Insert the Flash movie\n\t\tZeroClipboard_TableTools.moviePath = DataTable.Buttons.swfPath;\n\t\tvar flash = new ZeroClipboard_TableTools.Client();\n\n\t\tflash.setHandCursor( true );\n\t\tflash.addEventListener('mouseDown', function(client) {\n\t\t\tconfig._fromFlash = true;\n\t\t\tdt.button( button[0] ).trigger();\n\t\t\tconfig._fromFlash = false;\n\t\t} );\n\n\t\t_glue( flash, button );\n\n\t\tconfig._flash = flash;\n\t},\n\n\tdestroy: function ( dt, button, config ) {\n\t\tconfig._flash.destroy();\n\t},\n\n\tfieldSeparator: ',',\n\n\tfieldBoundary: '\"',\n\n\texportOptions: {},\n\n\ttitle: '*',\n\n\tmessageTop: '*',\n\n\tmessageBottom: '*',\n\n\tfilename: '*',\n\n\textension: '.csv',\n\n\theader: true,\n\n\tfooter: false\n};\n\n\n/**\n * Convert from numeric position to letter for column names in Excel\n * @param  {int} n Column number\n * @return {string} Column letter(s) name\n */\nfunction createCellPos( n ){\n\tvar ordA = 'A'.charCodeAt(0);\n\tvar ordZ = 'Z'.charCodeAt(0);\n\tvar len = ordZ - ordA + 1;\n\tvar s = \"\";\n\n\twhile( n >= 0 ) {\n\t\ts = String.fromCharCode(n % len + ordA) + s;\n\t\tn = Math.floor(n / len) - 1;\n\t}\n\n\treturn s;\n}\n\n/**\n * Create an XML node and add any children, attributes, etc without needing to\n * be verbose in the DOM.\n *\n * @param  {object} doc      XML document\n * @param  {string} nodeName Node name\n * @param  {object} opts     Options - can be `attr` (attributes), `children`\n *   (child nodes) and `text` (text content)\n * @return {node}            Created node\n */\nfunction _createNode( doc, nodeName, opts ){\n\tvar tempNode = doc.createElement( nodeName );\n\n\tif ( opts ) {\n\t\tif ( opts.attr ) {\n\t\t\t$(tempNode).attr( opts.attr );\n\t\t}\n\n\t\tif ( opts.children ) {\n\t\t\t$.each( opts.children, function ( key, value ) {\n\t\t\t\ttempNode.appendChild( value );\n\t\t\t} );\n\t\t}\n\n\t\tif ( opts.text !== null && opts.text !== undefined ) {\n\t\t\ttempNode.appendChild( doc.createTextNode( opts.text ) );\n\t\t}\n\t}\n\n\treturn tempNode;\n}\n\n/**\n * Get the width for an Excel column based on the contents of that column\n * @param  {object} data Data for export\n * @param  {int}    col  Column index\n * @return {int}         Column width\n */\nfunction _excelColWidth( data, col ) {\n\tvar max = data.header[col].length;\n\tvar len, lineSplit, str;\n\n\tif ( data.footer && data.footer[col].length > max ) {\n\t\tmax = data.footer[col].length;\n\t}\n\n\tfor ( var i=0, ien=data.body.length ; i<ien ; i++ ) {\n\t\tvar point = data.body[i][col];\n\t\tstr = point !== null && point !== undefined ?\n\t\t\tpoint.toString() :\n\t\t\t'';\n\n\t\t// If there is a newline character, workout the width of the column\n\t\t// based on the longest line in the string\n\t\tif ( str.indexOf('\\n') !== -1 ) {\n\t\t\tlineSplit = str.split('\\n');\n\t\t\tlineSplit.sort( function (a, b) {\n\t\t\t\treturn b.length - a.length;\n\t\t\t} );\n\n\t\t\tlen = lineSplit[0].length;\n\t\t}\n\t\telse {\n\t\t\tlen = str.length;\n\t\t}\n\n\t\tif ( len > max ) {\n\t\t\tmax = len;\n\t\t}\n\n\t\t// Max width rather than having potentially massive column widths\n\t\tif ( max > 40 ) {\n\t\t\treturn 52; // 40 * 1.3\n\t\t}\n\t}\n\n\tmax *= 1.3;\n\n\t// And a min width\n\treturn max > 6 ? max : 6;\n}\n\n  var _serialiser = \"\";\n    if (typeof window.XMLSerializer === 'undefined') {\n        _serialiser = new function () {\n            this.serializeToString = function (input) {\n                return input.xml\n            }\n        };\n    } else {\n        _serialiser =  new XMLSerializer();\n    }\n\n    var _ieExcel;\n\n\n/**\n * Convert XML documents in an object to strings\n * @param  {object} obj XLSX document object\n */\nfunction _xlsxToStrings( obj ) {\n\tif ( _ieExcel === undefined ) {\n\t\t// Detect if we are dealing with IE's _awful_ serialiser by seeing if it\n\t\t// drop attributes\n\t\t_ieExcel = _serialiser\n\t\t\t.serializeToString(\n\t\t\t\t$.parseXML( excelStrings['xl/worksheets/sheet1.xml'] )\n\t\t\t)\n\t\t\t.indexOf( 'xmlns:r' ) === -1;\n\t}\n\n\t$.each( obj, function ( name, val ) {\n\t\tif ( $.isPlainObject( val ) ) {\n\t\t\t_xlsxToStrings( val );\n\t\t}\n\t\telse {\n\t\t\tif ( _ieExcel ) {\n\t\t\t\t// IE's XML serialiser will drop some name space attributes from\n\t\t\t\t// from the root node, so we need to save them. Do this by\n\t\t\t\t// replacing the namespace nodes with a regular attribute that\n\t\t\t\t// we convert back when serialised. Edge does not have this\n\t\t\t\t// issue\n\t\t\t\tvar worksheet = val.childNodes[0];\n\t\t\t\tvar i, ien;\n\t\t\t\tvar attrs = [];\n\n\t\t\t\tfor ( i=worksheet.attributes.length-1 ; i>=0 ; i-- ) {\n\t\t\t\t\tvar attrName = worksheet.attributes[i].nodeName;\n\t\t\t\t\tvar attrValue = worksheet.attributes[i].nodeValue;\n\n\t\t\t\t\tif ( attrName.indexOf( ':' ) !== -1 ) {\n\t\t\t\t\t\tattrs.push( { name: attrName, value: attrValue } );\n\n\t\t\t\t\t\tworksheet.removeAttribute( attrName );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor ( i=0, ien=attrs.length ; i<ien ; i++ ) {\n\t\t\t\t\tvar attr = val.createAttribute( attrs[i].name.replace( ':', '_dt_b_namespace_token_' ) );\n\t\t\t\t\tattr.value = attrs[i].value;\n\t\t\t\t\tworksheet.setAttributeNode( attr );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar str = _serialiser.serializeToString(val);\n\n\t\t\t// Fix IE's XML\n\t\t\tif ( _ieExcel ) {\n\t\t\t\t// IE doesn't include the XML declaration\n\t\t\t\tif ( str.indexOf( '<?xml' ) === -1 ) {\n\t\t\t\t\tstr = '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+str;\n\t\t\t\t}\n\n\t\t\t\t// Return namespace attributes to being as such\n\t\t\t\tstr = str.replace( /_dt_b_namespace_token_/g, ':' );\n\t\t\t}\n\n\t\t\t// Safari, IE and Edge will put empty name space attributes onto\n\t\t\t// various elements making them useless. This strips them out\n\t\t\tstr = str.replace( /<([^<>]*?) xmlns=\"\"([^<>]*?)>/g, '<$1 $2>' );\n\n\t\t\tobj[ name ] = str;\n\t\t}\n\t} );\n}\n\n// Excel - Pre-defined strings to build a basic XLSX file\nvar excelStrings = {\n\t\"_rels/.rels\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">'+\n\t\t\t'<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"xl/workbook.xml\"/>'+\n\t\t'</Relationships>',\n\n\t\"xl/_rels/workbook.xml.rels\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">'+\n\t\t\t'<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\" Target=\"worksheets/sheet1.xml\"/>'+\n\t\t\t'<Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>'+\n\t\t'</Relationships>',\n\n\t\"[Content_Types].xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">'+\n\t\t\t'<Default Extension=\"xml\" ContentType=\"application/xml\" />'+\n\t\t\t'<Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\" />'+\n\t\t\t'<Default Extension=\"jpeg\" ContentType=\"image/jpeg\" />'+\n\t\t\t'<Override PartName=\"/xl/workbook.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\" />'+\n\t\t\t'<Override PartName=\"/xl/worksheets/sheet1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\" />'+\n\t\t\t'<Override PartName=\"/xl/styles.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\" />'+\n\t\t'</Types>',\n\n\t\"xl/workbook.xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">'+\n\t\t\t'<fileVersion appName=\"xl\" lastEdited=\"5\" lowestEdited=\"5\" rupBuild=\"24816\"/>'+\n\t\t\t'<workbookPr showInkAnnotation=\"0\" autoCompressPictures=\"0\"/>'+\n\t\t\t'<bookViews>'+\n\t\t\t\t'<workbookView xWindow=\"0\" yWindow=\"0\" windowWidth=\"25600\" windowHeight=\"19020\" tabRatio=\"500\"/>'+\n\t\t\t'</bookViews>'+\n\t\t\t'<sheets>'+\n\t\t\t\t'<sheet name=\"\" sheetId=\"1\" r:id=\"rId1\"/>'+\n\t\t\t'</sheets>'+\n\t\t'</workbook>',\n\n\t\"xl/worksheets/sheet1.xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" mc:Ignorable=\"x14ac\" xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\">'+\n\t\t\t'<sheetData/>'+\n\t\t\t'<mergeCells count=\"0\"/>'+\n\t\t'</worksheet>',\n\n\t\"xl/styles.xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\"?>'+\n\t\t'<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" mc:Ignorable=\"x14ac\" xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\">'+\n\t\t\t'<numFmts count=\"6\">'+\n\t\t\t\t'<numFmt numFmtId=\"164\" formatCode=\"#,##0.00_-\\ [$$-45C]\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"165\" formatCode=\"&quot;£&quot;#,##0.00\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"166\" formatCode=\"[$€-2]\\ #,##0.00\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"167\" formatCode=\"0.0%\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"168\" formatCode=\"#,##0;(#,##0)\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"169\" formatCode=\"#,##0.00;(#,##0.00)\"/>'+\n\t\t\t'</numFmts>'+\n\t\t\t'<fonts count=\"5\" x14ac:knownFonts=\"1\">'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<color rgb=\"FFFFFFFF\" />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<b />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<i />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<u />'+\n\t\t\t\t'</font>'+\n\t\t\t'</fonts>'+\n\t\t\t'<fills count=\"6\">'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"none\" />'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+ // Excel appears to use this as a dotted background regardless of values but\n\t\t\t\t\t'<patternFill patternType=\"none\" />'+ // to be valid to the schema, use a patternFill\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"FFD9D9D9\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"FFD99795\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"ffc6efce\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"ffc6cfef\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t'</fills>'+\n\t\t\t'<borders count=\"2\">'+\n\t\t\t\t'<border>'+\n\t\t\t\t\t'<left />'+\n\t\t\t\t\t'<right />'+\n\t\t\t\t\t'<top />'+\n\t\t\t\t\t'<bottom />'+\n\t\t\t\t\t'<diagonal />'+\n\t\t\t\t'</border>'+\n\t\t\t\t'<border diagonalUp=\"false\" diagonalDown=\"false\">'+\n\t\t\t\t\t'<left style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</left>'+\n\t\t\t\t\t'<right style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</right>'+\n\t\t\t\t\t'<top style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</top>'+\n\t\t\t\t\t'<bottom style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</bottom>'+\n\t\t\t\t\t'<diagonal />'+\n\t\t\t\t'</border>'+\n\t\t\t'</borders>'+\n\t\t\t'<cellStyleXfs count=\"1\">'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" />'+\n\t\t\t'</cellStyleXfs>'+\n\t\t\t'<cellXfs count=\"61\">'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"left\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"center\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"right\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"fill\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment textRotation=\"90\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment wrapText=\"1\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"9\"   fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"164\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"165\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"166\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"167\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"168\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"169\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"3\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"4\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t'</cellXfs>'+\n\t\t\t'<cellStyles count=\"1\">'+\n\t\t\t\t'<cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\" />'+\n\t\t\t'</cellStyles>'+\n\t\t\t'<dxfs count=\"0\" />'+\n\t\t\t'<tableStyles count=\"0\" defaultTableStyle=\"TableStyleMedium9\" defaultPivotStyle=\"PivotStyleMedium4\" />'+\n\t\t'</styleSheet>'\n};\n// Note we could use 3 `for` loops for the styles, but when gzipped there is\n// virtually no difference in size, since the above can be easily compressed\n\n// Pattern matching for special number formats. Perhaps this should be exposed\n// via an API in future?\nvar _excelSpecials = [\n\t{ match: /^\\-?\\d+\\.\\d%$/,       style: 60, fmt: function (d) { return d/100; } }, // Precent with d.p.\n\t{ match: /^\\-?\\d+\\.?\\d*%$/,     style: 56, fmt: function (d) { return d/100; } }, // Percent\n\t{ match: /^\\-?\\$[\\d,]+.?\\d*$/,  style: 57 }, // Dollars\n\t{ match: /^\\-?£[\\d,]+.?\\d*$/,   style: 58 }, // Pounds\n\t{ match: /^\\-?€[\\d,]+.?\\d*$/,   style: 59 }, // Euros\n\t{ match: /^\\([\\d,]+\\)$/,        style: 61, fmt: function (d) { return -1 * d.replace(/[\\(\\)]/g, ''); } },  // Negative numbers indicated by brackets\n\t{ match: /^\\([\\d,]+\\.\\d{2}\\)$/, style: 62, fmt: function (d) { return -1 * d.replace(/[\\(\\)]/g, ''); } },  // Negative numbers indicated by brackets - 2d.p.\n\t{ match: /^[\\d,]+$/,            style: 63 }, // Numbers with thousand separators\n\t{ match: /^[\\d,]+\\.\\d{2}$/,     style: 64 }  // Numbers with 2d.p. and thousands separators\n];\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables options and methods\n */\n\n// Set the default SWF path\nDataTable.Buttons.swfPath = '//cdn.datatables.net/buttons/'+DataTable.Buttons.version+'/swf/flashExport.swf';\n\n// Method to allow Flash buttons to be resized when made visible - as they are\n// of zero height and width if initialised hidden\nDataTable.Api.register( 'buttons.resize()', function () {\n\t$.each( ZeroClipboard_TableTools.clients, function ( i, client ) {\n\t\tif ( client.domElement !== undefined && client.domElement.parentNode ) {\n\t\t\tclient.positionElement();\n\t\t}\n\t} );\n} );\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Button definitions\n */\n\n// Copy to clipboard\nDataTable.ext.buttons.copyFlash = $.extend( {}, flashButton, {\n\tclassName: 'buttons-copy buttons-flash',\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.copy', 'Copy' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\t// Check that the trigger did actually occur due to a Flash activation\n\t\tif ( ! config._fromFlash ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.processing( true );\n\n\t\tvar flash = config._flash;\n\t\tvar exportData = _exportData( dt, config );\n\t\tvar info = dt.buttons.exportInfo( config );\n\t\tvar newline = _newLine(config);\n\t\tvar output = exportData.str;\n\n\t\tif ( info.title ) {\n\t\t\toutput = info.title + newline + newline + output;\n\t\t}\n\n\t\tif ( info.messageTop ) {\n\t\t\toutput = info.messageTop + newline + newline + output;\n\t\t}\n\n\t\tif ( info.messageBottom ) {\n\t\t\toutput = output + newline + newline + info.messageBottom;\n\t\t}\n\n\t\tif ( config.customize ) {\n\t\t\toutput = config.customize( output, config, dt );\n\t\t}\n\n\t\tflash.setAction( 'copy' );\n\t\t_setText( flash, output );\n\n\t\tthis.processing( false );\n\n\t\tdt.buttons.info(\n\t\t\tdt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),\n\t\t\tdt.i18n( 'buttons.copySuccess', {\n\t\t\t\t_: 'Copied %d rows to clipboard',\n\t\t\t\t1: 'Copied 1 row to clipboard'\n\t\t\t}, data.rows ),\n\t\t\t3000\n\t\t);\n\t},\n\n\tfieldSeparator: '\\t',\n\n\tfieldBoundary: ''\n} );\n\n// CSV save file\nDataTable.ext.buttons.csvFlash = $.extend( {}, flashButton, {\n\tclassName: 'buttons-csv buttons-flash',\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.csv', 'CSV' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\t// Set the text\n\t\tvar flash = config._flash;\n\t\tvar data = _exportData( dt, config );\n\t\tvar info = dt.buttons.exportInfo( config );\n\t\tvar output = config.customize ?\n\t\t\tconfig.customize( data.str, config, dt ) :\n\t\t\tdata.str;\n\n\t\tflash.setAction( 'csv' );\n\t\tflash.setFileName( info.filename );\n\t\t_setText( flash, output );\n\t},\n\n\tescapeChar: '\"'\n} );\n\n// Excel save file - this is really a CSV file using UTF-8 that Excel can read\nDataTable.ext.buttons.excelFlash = $.extend( {}, flashButton, {\n\tclassName: 'buttons-excel buttons-flash',\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.excel', 'Excel' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\tthis.processing( true );\n\n\t\tvar flash = config._flash;\n\t\tvar rowPos = 0;\n\t\tvar rels = $.parseXML( excelStrings['xl/worksheets/sheet1.xml'] ) ; //Parses xml\n\t\tvar relsGet = rels.getElementsByTagName( \"sheetData\" )[0];\n\n\t\tvar xlsx = {\n\t\t\t_rels: {\n\t\t\t\t\".rels\": $.parseXML( excelStrings['_rels/.rels'] )\n\t\t\t},\n\t\t\txl: {\n\t\t\t\t_rels: {\n\t\t\t\t\t\"workbook.xml.rels\": $.parseXML( excelStrings['xl/_rels/workbook.xml.rels'] )\n\t\t\t\t},\n\t\t\t\t\"workbook.xml\": $.parseXML( excelStrings['xl/workbook.xml'] ),\n\t\t\t\t\"styles.xml\": $.parseXML( excelStrings['xl/styles.xml'] ),\n\t\t\t\t\"worksheets\": {\n\t\t\t\t\t\"sheet1.xml\": rels\n\t\t\t\t}\n\n\t\t\t},\n\t\t\t\"[Content_Types].xml\": $.parseXML( excelStrings['[Content_Types].xml'])\n\t\t};\n\n\t\tvar data = dt.buttons.exportData( config.exportOptions );\n\t\tvar currentRow, rowNode;\n\t\tvar addRow = function ( row ) {\n\t\t\tcurrentRow = rowPos+1;\n\t\t\trowNode = _createNode( rels, \"row\", { attr: {r:currentRow} } );\n\n\t\t\tfor ( var i=0, ien=row.length ; i<ien ; i++ ) {\n\t\t\t\t// Concat both the Cell Columns as a letter and the Row of the cell.\n\t\t\t\tvar cellId = createCellPos(i) + '' + currentRow;\n\t\t\t\tvar cell = null;\n\n\t\t\t\t// For null, undefined of blank cell, continue so it doesn't create the _createNode\n\t\t\t\tif ( row[i] === null || row[i] === undefined || row[i] === '' ) {\n\t\t\t\t\tif ( config.createEmptyCells === true ) {\n\t\t\t\t\t\trow[i] = '';\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\trow[i] = $.trim( row[i] );\n\n\t\t\t\t// Special number formatting options\n\t\t\t\tfor ( var j=0, jen=_excelSpecials.length ; j<jen ; j++ ) {\n\t\t\t\t\tvar special = _excelSpecials[j];\n\n\t\t\t\t\t// TODO Need to provide the ability for the specials to say\n\t\t\t\t\t// if they are returning a string, since at the moment it is\n\t\t\t\t\t// assumed to be a number\n\t\t\t\t\tif ( row[i].match && ! row[i].match(/^0\\d+/) && row[i].match( special.match ) ) {\n\t\t\t\t\t\tvar val = row[i].replace(/[^\\d\\.\\-]/g, '');\n\n\t\t\t\t\t\tif ( special.fmt ) {\n\t\t\t\t\t\t\tval = special.fmt( val );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcell = _createNode( rels, 'c', {\n\t\t\t\t\t\t\tattr: {\n\t\t\t\t\t\t\t\tr: cellId,\n\t\t\t\t\t\t\t\ts: special.style\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren: [\n\t\t\t\t\t\t\t\t_createNode( rels, 'v', { text: val } )\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( ! cell ) {\n\t\t\t\t\tif ( typeof row[i] === 'number' || (\n\t\t\t\t\t\trow[i].match &&\n\t\t\t\t\t\trow[i].match(/^-?\\d+(\\.\\d+)?$/) &&\n\t\t\t\t\t\t! row[i].match(/^0\\d+/) )\n\t\t\t\t\t) {\n\t\t\t\t\t\t// Detect numbers - don't match numbers with leading zeros\n\t\t\t\t\t\t// or a negative anywhere but the start\n\t\t\t\t\t\tcell = _createNode( rels, 'c', {\n\t\t\t\t\t\t\tattr: {\n\t\t\t\t\t\t\t\tt: 'n',\n\t\t\t\t\t\t\t\tr: cellId\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren: [\n\t\t\t\t\t\t\t\t_createNode( rels, 'v', { text: row[i] } )\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// String output - replace non standard characters for text output\n\t\t\t\t\t\tvar text = ! row[i].replace ?\n\t\t\t\t\t\t\trow[i] :\n\t\t\t\t\t\t\trow[i].replace(/[\\x00-\\x09\\x0B\\x0C\\x0E-\\x1F\\x7F-\\x9F]/g, '');\n\n\t\t\t\t\t\tcell = _createNode( rels, 'c', {\n\t\t\t\t\t\t\tattr: {\n\t\t\t\t\t\t\t\tt: 'inlineStr',\n\t\t\t\t\t\t\t\tr: cellId\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren:{\n\t\t\t\t\t\t\t\trow: _createNode( rels, 'is', {\n\t\t\t\t\t\t\t\t\tchildren: {\n\t\t\t\t\t\t\t\t\t\trow: _createNode( rels, 't', {\n\t\t\t\t\t\t\t\t\t\t\ttext: text\n\t\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\trowNode.appendChild( cell );\n\t\t\t}\n\n\t\t\trelsGet.appendChild(rowNode);\n\t\t\trowPos++;\n\t\t};\n\n\t\t$( 'sheets sheet', xlsx.xl['workbook.xml'] ).attr( 'name', _sheetname( config ) );\n\n\t\tif ( config.customizeData ) {\n\t\t\tconfig.customizeData( data );\n\t\t}\n\n\t\tvar mergeCells = function ( row, colspan ) {\n\t\t\tvar mergeCells = $('mergeCells', rels);\n\n\t\t\tmergeCells[0].appendChild( _createNode( rels, 'mergeCell', {\n\t\t\t\tattr: {\n\t\t\t\t\tref: 'A'+row+':'+createCellPos(colspan)+row\n\t\t\t\t}\n\t\t\t} ) );\n\t\t\tmergeCells.attr( 'count', mergeCells.attr( 'count' )+1 );\n\t\t\t$('row:eq('+(row-1)+') c', rels).attr( 's', '51' ); // centre\n\t\t};\n\n\t\t// Title and top messages\n\t\tvar exportInfo = dt.buttons.exportInfo( config );\n\t\tif ( exportInfo.title ) {\n\t\t\taddRow( [exportInfo.title], rowPos );\n\t\t\tmergeCells( rowPos, data.header.length-1 );\n\t\t}\n\n\t\tif ( exportInfo.messageTop ) {\n\t\t\taddRow( [exportInfo.messageTop], rowPos );\n\t\t\tmergeCells( rowPos, data.header.length-1 );\n\t\t}\n\n\t\t// Table itself\n\t\tif ( config.header ) {\n\t\t\taddRow( data.header, rowPos );\n\t\t\t$('row:last c', rels).attr( 's', '2' ); // bold\n\t\t}\n\n\t\tfor ( var n=0, ie=data.body.length ; n<ie ; n++ ) {\n\t\t\taddRow( data.body[n], rowPos );\n\t\t}\n\n\t\tif ( config.footer && data.footer ) {\n\t\t\taddRow( data.footer, rowPos);\n\t\t\t$('row:last c', rels).attr( 's', '2' ); // bold\n\t\t}\n\n\t\t// Below the table\n\t\tif ( exportInfo.messageBottom ) {\n\t\t\taddRow( [exportInfo.messageBottom], rowPos );\n\t\t\tmergeCells( rowPos, data.header.length-1 );\n\t\t}\n\n\t\t// Set column widths\n\t\tvar cols = _createNode( rels, 'cols' );\n\t\t$('worksheet', rels).prepend( cols );\n\n\t\tfor ( var i=0, ien=data.header.length ; i<ien ; i++ ) {\n\t\t\tcols.appendChild( _createNode( rels, 'col', {\n\t\t\t\tattr: {\n\t\t\t\t\tmin: i+1,\n\t\t\t\t\tmax: i+1,\n\t\t\t\t\twidth: _excelColWidth( data, i ),\n\t\t\t\t\tcustomWidth: 1\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\t// Let the developer customise the document if they want to\n\t\tif ( config.customize ) {\n\t\t\tconfig.customize( xlsx, config, dt );\n\t\t}\n\n\t\t_xlsxToStrings( xlsx );\n\n\t\tflash.setAction( 'excel' );\n\t\tflash.setFileName( exportInfo.filename );\n\t\tflash.setSheetData( xlsx );\n\t\t_setText( flash, '' );\n\n\t\tthis.processing( false );\n\t},\n\n\textension: '.xlsx',\n\t\n\tcreateEmptyCells: false\n} );\n\n\n\n// PDF export\nDataTable.ext.buttons.pdfFlash = $.extend( {}, flashButton, {\n\tclassName: 'buttons-pdf buttons-flash',\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.pdf', 'PDF' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\tthis.processing( true );\n\n\t\t// Set the text\n\t\tvar flash = config._flash;\n\t\tvar data = dt.buttons.exportData( config.exportOptions );\n\t\tvar info = dt.buttons.exportInfo( config );\n\t\tvar totalWidth = dt.table().node().offsetWidth;\n\n\t\t// Calculate the column width ratios for layout of the table in the PDF\n\t\tvar ratios = dt.columns( config.columns ).indexes().map( function ( idx ) {\n\t\t\treturn dt.column( idx ).header().offsetWidth / totalWidth;\n\t\t} );\n\n\t\tflash.setAction( 'pdf' );\n\t\tflash.setFileName( info.filename );\n\n\t\t_setText( flash, JSON.stringify( {\n\t\t\ttitle:         info.title || '',\n\t\t\tmessageTop:    info.messageTop || '',\n\t\t\tmessageBottom: info.messageBottom || '',\n\t\t\tcolWidth:      ratios.toArray(),\n\t\t\torientation:   config.orientation,\n\t\t\tsize:          config.pageSize,\n\t\t\theader:        config.header ? data.header : null,\n\t\t\tfooter:        config.footer ? data.footer : null,\n\t\t\tbody:          data.body\n\t\t} ) );\n\n\t\tthis.processing( false );\n\t},\n\n\textension: '.pdf',\n\n\torientation: 'portrait',\n\n\tpageSize: 'A4',\n\n\tnewline: '\\n'\n} );\n\n\nreturn DataTable.Buttons;\n}));\n\n\n/*!\n * HTML5 export buttons for Buttons and DataTables.\n * 2016 SpryMedia Ltd - datatables.net/license\n *\n * FileSaver.js (1.3.3) - MIT license\n * Copyright © 2016 Eli Grey - http://eligrey.com\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $, jszip, pdfmake) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Buttons ) {\n\t\t\t\trequire('datatables.net-buttons')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document, jszip, pdfmake );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, jszip, pdfmake, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n// Allow the constructor to pass in JSZip and PDFMake from external requires.\n// Otherwise, use globally defined variables, if they are available.\nfunction _jsZip () {\n\treturn jszip || window.JSZip;\n}\nfunction _pdfMake () {\n\treturn pdfmake || window.pdfMake;\n}\n\nDataTable.Buttons.pdfMake = function (_) {\n\tif ( ! _ ) {\n\t\treturn _pdfMake();\n\t}\n\tpdfmake = m_ake;\n}\n\nDataTable.Buttons.jszip = function (_) {\n\tif ( ! _ ) {\n\t\treturn _jsZip();\n\t}\n\tjszip = _;\n}\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * FileSaver.js dependency\n */\n\n/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */\n\nvar _saveAs = (function(view) {\n\t\"use strict\";\n\t// IE <10 is explicitly unsupported\n\tif (typeof view === \"undefined\" || typeof navigator !== \"undefined\" && /MSIE [1-9]\\./.test(navigator.userAgent)) {\n\t\treturn;\n\t}\n\tvar\n\t\t  doc = view.document\n\t\t  // only get URL when necessary in case Blob.js hasn't overridden it yet\n\t\t, get_URL = function() {\n\t\t\treturn view.URL || view.webkitURL || view;\n\t\t}\n\t\t, save_link = doc.createElementNS(\"http://www.w3.org/1999/xhtml\", \"a\")\n\t\t, can_use_save_link = \"download\" in save_link\n\t\t, click = function(node) {\n\t\t\tvar event = new MouseEvent(\"click\");\n\t\t\tnode.dispatchEvent(event);\n\t\t}\n\t\t, is_safari = /constructor/i.test(view.HTMLElement) || view.safari\n\t\t, is_chrome_ios =/CriOS\\/[\\d]+/.test(navigator.userAgent)\n\t\t, throw_outside = function(ex) {\n\t\t\t(view.setImmediate || view.setTimeout)(function() {\n\t\t\t\tthrow ex;\n\t\t\t}, 0);\n\t\t}\n\t\t, force_saveable_type = \"application/octet-stream\"\n\t\t// the Blob API is fundamentally broken as there is no \"downloadfinished\" event to subscribe to\n\t\t, arbitrary_revoke_timeout = 1000 * 40 // in ms\n\t\t, revoke = function(file) {\n\t\t\tvar revoker = function() {\n\t\t\t\tif (typeof file === \"string\") { // file is an object URL\n\t\t\t\t\tget_URL().revokeObjectURL(file);\n\t\t\t\t} else { // file is a File\n\t\t\t\t\tfile.remove();\n\t\t\t\t}\n\t\t\t};\n\t\t\tsetTimeout(revoker, arbitrary_revoke_timeout);\n\t\t}\n\t\t, dispatch = function(filesaver, event_types, event) {\n\t\t\tevent_types = [].concat(event_types);\n\t\t\tvar i = event_types.length;\n\t\t\twhile (i--) {\n\t\t\t\tvar listener = filesaver[\"on\" + event_types[i]];\n\t\t\t\tif (typeof listener === \"function\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tlistener.call(filesaver, event || filesaver);\n\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\tthrow_outside(ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t, auto_bom = function(blob) {\n\t\t\t// prepend BOM for UTF-8 XML and text/* types (including HTML)\n\t\t\t// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF\n\t\t\tif (/^\\s*(?:text\\/\\S*|application\\/xml|\\S*\\/\\S*\\+xml)\\s*;.*charset\\s*=\\s*utf-8/i.test(blob.type)) {\n\t\t\t\treturn new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});\n\t\t\t}\n\t\t\treturn blob;\n\t\t}\n\t\t, FileSaver = function(blob, name, no_auto_bom) {\n\t\t\tif (!no_auto_bom) {\n\t\t\t\tblob = auto_bom(blob);\n\t\t\t}\n\t\t\t// First try a.download, then web filesystem, then object URLs\n\t\t\tvar\n\t\t\t\t  filesaver = this\n\t\t\t\t, type = blob.type\n\t\t\t\t, force = type === force_saveable_type\n\t\t\t\t, object_url\n\t\t\t\t, dispatch_all = function() {\n\t\t\t\t\tdispatch(filesaver, \"writestart progress write writeend\".split(\" \"));\n\t\t\t\t}\n\t\t\t\t// on any filesys errors revert to saving with object URLs\n\t\t\t\t, fs_error = function() {\n\t\t\t\t\tif ((is_chrome_ios || (force && is_safari)) && view.FileReader) {\n\t\t\t\t\t\t// Safari doesn't allow downloading of blob urls\n\t\t\t\t\t\tvar reader = new FileReader();\n\t\t\t\t\t\treader.onloadend = function() {\n\t\t\t\t\t\t\tvar url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');\n\t\t\t\t\t\t\tvar popup = view.open(url, '_blank');\n\t\t\t\t\t\t\tif(!popup) view.location.href = url;\n\t\t\t\t\t\t\turl=undefined; // release reference before dispatching\n\t\t\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t\t\t\tdispatch_all();\n\t\t\t\t\t\t};\n\t\t\t\t\t\treader.readAsDataURL(blob);\n\t\t\t\t\t\tfilesaver.readyState = filesaver.INIT;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// don't create more object URLs than needed\n\t\t\t\t\tif (!object_url) {\n\t\t\t\t\t\tobject_url = get_URL().createObjectURL(blob);\n\t\t\t\t\t}\n\t\t\t\t\tif (force) {\n\t\t\t\t\t\tview.location.href = object_url;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar opened = view.open(object_url, \"_blank\");\n\t\t\t\t\t\tif (!opened) {\n\t\t\t\t\t\t\t// Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html\n\t\t\t\t\t\t\tview.location.href = object_url;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t\tdispatch_all();\n\t\t\t\t\trevoke(object_url);\n\t\t\t\t}\n\t\t\t;\n\t\t\tfilesaver.readyState = filesaver.INIT;\n\n\t\t\tif (can_use_save_link) {\n\t\t\t\tobject_url = get_URL().createObjectURL(blob);\n\t\t\t\tsetTimeout(function() {\n\t\t\t\t\tsave_link.href = object_url;\n\t\t\t\t\tsave_link.download = name;\n\t\t\t\t\tclick(save_link);\n\t\t\t\t\tdispatch_all();\n\t\t\t\t\trevoke(object_url);\n\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfs_error();\n\t\t}\n\t\t, FS_proto = FileSaver.prototype\n\t\t, saveAs = function(blob, name, no_auto_bom) {\n\t\t\treturn new FileSaver(blob, name || blob.name || \"download\", no_auto_bom);\n\t\t}\n\t;\n\t// IE 10+ (native saveAs)\n\tif (typeof navigator !== \"undefined\" && navigator.msSaveOrOpenBlob) {\n\t\treturn function(blob, name, no_auto_bom) {\n\t\t\tname = name || blob.name || \"download\";\n\n\t\t\tif (!no_auto_bom) {\n\t\t\t\tblob = auto_bom(blob);\n\t\t\t}\n\t\t\treturn navigator.msSaveOrOpenBlob(blob, name);\n\t\t};\n\t}\n\n\tFS_proto.abort = function(){};\n\tFS_proto.readyState = FS_proto.INIT = 0;\n\tFS_proto.WRITING = 1;\n\tFS_proto.DONE = 2;\n\n\tFS_proto.error =\n\tFS_proto.onwritestart =\n\tFS_proto.onprogress =\n\tFS_proto.onwrite =\n\tFS_proto.onabort =\n\tFS_proto.onerror =\n\tFS_proto.onwriteend =\n\t\tnull;\n\n\treturn saveAs;\n}(\n\t   typeof self !== \"undefined\" && self\n\t|| typeof window !== \"undefined\" && window\n\t|| this.content\n));\n\n\n// Expose file saver on the DataTables API. Can't attach to `DataTables.Buttons`\n// since this file can be loaded before Button's core!\nDataTable.fileSave = _saveAs;\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Local (private) functions\n */\n\n/**\n * Get the sheet name for Excel exports.\n *\n * @param {object}\tconfig Button configuration\n */\nvar _sheetname = function ( config )\n{\n\tvar sheetName = 'Sheet1';\n\n\tif ( config.sheetName ) {\n\t\tsheetName = config.sheetName.replace(/[\\[\\]\\*\\/\\\\\\?\\:]/g, '');\n\t}\n\n\treturn sheetName;\n};\n\n/**\n * Get the newline character(s)\n *\n * @param {object}\tconfig Button configuration\n * @return {string}\t\t\t\tNewline character\n */\nvar _newLine = function ( config )\n{\n\treturn config.newline ?\n\t\tconfig.newline :\n\t\tnavigator.userAgent.match(/Windows/) ?\n\t\t\t'\\r\\n' :\n\t\t\t'\\n';\n};\n\n/**\n * Combine the data from the `buttons.exportData` method into a string that\n * will be used in the export file.\n *\n * @param\t{DataTable.Api} dt\t\t DataTables API instance\n * @param\t{object}\t\t\t\tconfig Button configuration\n * @return {object}\t\t\t\t\t\t\t The data to export\n */\nvar _exportData = function ( dt, config )\n{\n\tvar newLine = _newLine( config );\n\tvar data = dt.buttons.exportData( config.exportOptions );\n\tvar boundary = config.fieldBoundary;\n\tvar separator = config.fieldSeparator;\n\tvar reBoundary = new RegExp( boundary, 'g' );\n\tvar escapeChar = config.escapeChar !== undefined ?\n\t\tconfig.escapeChar :\n\t\t'\\\\';\n\tvar join = function ( a ) {\n\t\tvar s = '';\n\n\t\t// If there is a field boundary, then we might need to escape it in\n\t\t// the source data\n\t\tfor ( var i=0, ien=a.length ; i<ien ; i++ ) {\n\t\t\tif ( i > 0 ) {\n\t\t\t\ts += separator;\n\t\t\t}\n\n\t\t\ts += boundary ?\n\t\t\t\tboundary + ('' + a[i]).replace( reBoundary, escapeChar+boundary ) + boundary :\n\t\t\t\ta[i];\n\t\t}\n\n\t\treturn s;\n\t};\n\n\tvar header = config.header ? join( data.header )+newLine : '';\n\tvar footer = config.footer && data.footer ? newLine+join( data.footer ) : '';\n\tvar body = [];\n\n\tfor ( var i=0, ien=data.body.length ; i<ien ; i++ ) {\n\t\tbody.push( join( data.body[i] ) );\n\t}\n\n\treturn {\n\t\tstr: header + body.join( newLine ) + footer,\n\t\trows: body.length\n\t};\n};\n\n/**\n * Older versions of Safari (prior to tech preview 18) don't support the\n * download option required.\n *\n * @return {Boolean} `true` if old Safari\n */\nvar _isDuffSafari = function ()\n{\n\tvar safari = navigator.userAgent.indexOf('Safari') !== -1 &&\n\t\tnavigator.userAgent.indexOf('Chrome') === -1 &&\n\t\tnavigator.userAgent.indexOf('Opera') === -1;\n\n\tif ( ! safari ) {\n\t\treturn false;\n\t}\n\n\tvar version = navigator.userAgent.match( /AppleWebKit\\/(\\d+\\.\\d+)/ );\n\tif ( version && version.length > 1 && version[1]*1 < 603.1 ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\n/**\n * Convert from numeric position to letter for column names in Excel\n * @param  {int} n Column number\n * @return {string} Column letter(s) name\n */\nfunction createCellPos( n ){\n\tvar ordA = 'A'.charCodeAt(0);\n\tvar ordZ = 'Z'.charCodeAt(0);\n\tvar len = ordZ - ordA + 1;\n\tvar s = \"\";\n\n\twhile( n >= 0 ) {\n\t\ts = String.fromCharCode(n % len + ordA) + s;\n\t\tn = Math.floor(n / len) - 1;\n\t}\n\n\treturn s;\n}\n\ntry {\n\tvar _serialiser = new XMLSerializer();\n\tvar _ieExcel;\n}\ncatch (t) {}\n\n/**\n * Recursively add XML files from an object's structure to a ZIP file. This\n * allows the XSLX file to be easily defined with an object's structure matching\n * the files structure.\n *\n * @param {JSZip} zip ZIP package\n * @param {object} obj Object to add (recursive)\n */\nfunction _addToZip( zip, obj ) {\n\tif ( _ieExcel === undefined ) {\n\t\t// Detect if we are dealing with IE's _awful_ serialiser by seeing if it\n\t\t// drop attributes\n\t\t_ieExcel = _serialiser\n\t\t\t.serializeToString(\n\t\t\t\t$.parseXML( excelStrings['xl/worksheets/sheet1.xml'] )\n\t\t\t)\n\t\t\t.indexOf( 'xmlns:r' ) === -1;\n\t}\n\n\t$.each( obj, function ( name, val ) {\n\t\tif ( $.isPlainObject( val ) ) {\n\t\t\tvar newDir = zip.folder( name );\n\t\t\t_addToZip( newDir, val );\n\t\t}\n\t\telse {\n\t\t\tif ( _ieExcel ) {\n\t\t\t\t// IE's XML serialiser will drop some name space attributes from\n\t\t\t\t// from the root node, so we need to save them. Do this by\n\t\t\t\t// replacing the namespace nodes with a regular attribute that\n\t\t\t\t// we convert back when serialised. Edge does not have this\n\t\t\t\t// issue\n\t\t\t\tvar worksheet = val.childNodes[0];\n\t\t\t\tvar i, ien;\n\t\t\t\tvar attrs = [];\n\n\t\t\t\tfor ( i=worksheet.attributes.length-1 ; i>=0 ; i-- ) {\n\t\t\t\t\tvar attrName = worksheet.attributes[i].nodeName;\n\t\t\t\t\tvar attrValue = worksheet.attributes[i].nodeValue;\n\n\t\t\t\t\tif ( attrName.indexOf( ':' ) !== -1 ) {\n\t\t\t\t\t\tattrs.push( { name: attrName, value: attrValue } );\n\n\t\t\t\t\t\tworksheet.removeAttribute( attrName );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor ( i=0, ien=attrs.length ; i<ien ; i++ ) {\n\t\t\t\t\tvar attr = val.createAttribute( attrs[i].name.replace( ':', '_dt_b_namespace_token_' ) );\n\t\t\t\t\tattr.value = attrs[i].value;\n\t\t\t\t\tworksheet.setAttributeNode( attr );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar str = _serialiser.serializeToString(val);\n\n\t\t\t// Fix IE's XML\n\t\t\tif ( _ieExcel ) {\n\t\t\t\t// IE doesn't include the XML declaration\n\t\t\t\tif ( str.indexOf( '<?xml' ) === -1 ) {\n\t\t\t\t\tstr = '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+str;\n\t\t\t\t}\n\n\t\t\t\t// Return namespace attributes to being as such\n\t\t\t\tstr = str.replace( /_dt_b_namespace_token_/g, ':' );\n\n\t\t\t\t// Remove testing name space that IE puts into the space preserve attr\n\t\t\t\tstr = str.replace( /xmlns:NS[\\d]+=\"\" NS[\\d]+:/g, '' );\n\t\t\t}\n\n\t\t\t// Safari, IE and Edge will put empty name space attributes onto\n\t\t\t// various elements making them useless. This strips them out\n\t\t\tstr = str.replace( /<([^<>]*?) xmlns=\"\"([^<>]*?)>/g, '<$1 $2>' );\n\n\t\t\tzip.file( name, str );\n\t\t}\n\t} );\n}\n\n/**\n * Create an XML node and add any children, attributes, etc without needing to\n * be verbose in the DOM.\n *\n * @param  {object} doc      XML document\n * @param  {string} nodeName Node name\n * @param  {object} opts     Options - can be `attr` (attributes), `children`\n *   (child nodes) and `text` (text content)\n * @return {node}            Created node\n */\nfunction _createNode( doc, nodeName, opts ) {\n\tvar tempNode = doc.createElement( nodeName );\n\n\tif ( opts ) {\n\t\tif ( opts.attr ) {\n\t\t\t$(tempNode).attr( opts.attr );\n\t\t}\n\n\t\tif ( opts.children ) {\n\t\t\t$.each( opts.children, function ( key, value ) {\n\t\t\t\ttempNode.appendChild( value );\n\t\t\t} );\n\t\t}\n\n\t\tif ( opts.text !== null && opts.text !== undefined ) {\n\t\t\ttempNode.appendChild( doc.createTextNode( opts.text ) );\n\t\t}\n\t}\n\n\treturn tempNode;\n}\n\n/**\n * Get the width for an Excel column based on the contents of that column\n * @param  {object} data Data for export\n * @param  {int}    col  Column index\n * @return {int}         Column width\n */\nfunction _excelColWidth( data, col ) {\n\tvar max = data.header[col].length;\n\tvar len, lineSplit, str;\n\n\tif ( data.footer && data.footer[col].length > max ) {\n\t\tmax = data.footer[col].length;\n\t}\n\n\tfor ( var i=0, ien=data.body.length ; i<ien ; i++ ) {\n\t\tvar point = data.body[i][col];\n\t\tstr = point !== null && point !== undefined ?\n\t\t\tpoint.toString() :\n\t\t\t'';\n\n\t\t// If there is a newline character, workout the width of the column\n\t\t// based on the longest line in the string\n\t\tif ( str.indexOf('\\n') !== -1 ) {\n\t\t\tlineSplit = str.split('\\n');\n\t\t\tlineSplit.sort( function (a, b) {\n\t\t\t\treturn b.length - a.length;\n\t\t\t} );\n\n\t\t\tlen = lineSplit[0].length;\n\t\t}\n\t\telse {\n\t\t\tlen = str.length;\n\t\t}\n\n\t\tif ( len > max ) {\n\t\t\tmax = len;\n\t\t}\n\n\t\t// Max width rather than having potentially massive column widths\n\t\tif ( max > 40 ) {\n\t\t\treturn 54; // 40 * 1.35\n\t\t}\n\t}\n\n\tmax *= 1.35;\n\n\t// And a min width\n\treturn max > 6 ? max : 6;\n}\n\n// Excel - Pre-defined strings to build a basic XLSX file\nvar excelStrings = {\n\t\"_rels/.rels\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">'+\n\t\t\t'<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"xl/workbook.xml\"/>'+\n\t\t'</Relationships>',\n\n\t\"xl/_rels/workbook.xml.rels\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">'+\n\t\t\t'<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\" Target=\"worksheets/sheet1.xml\"/>'+\n\t\t\t'<Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>'+\n\t\t'</Relationships>',\n\n\t\"[Content_Types].xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">'+\n\t\t\t'<Default Extension=\"xml\" ContentType=\"application/xml\" />'+\n\t\t\t'<Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\" />'+\n\t\t\t'<Default Extension=\"jpeg\" ContentType=\"image/jpeg\" />'+\n\t\t\t'<Override PartName=\"/xl/workbook.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\" />'+\n\t\t\t'<Override PartName=\"/xl/worksheets/sheet1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\" />'+\n\t\t\t'<Override PartName=\"/xl/styles.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\" />'+\n\t\t'</Types>',\n\n\t\"xl/workbook.xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">'+\n\t\t\t'<fileVersion appName=\"xl\" lastEdited=\"5\" lowestEdited=\"5\" rupBuild=\"24816\"/>'+\n\t\t\t'<workbookPr showInkAnnotation=\"0\" autoCompressPictures=\"0\"/>'+\n\t\t\t'<bookViews>'+\n\t\t\t\t'<workbookView xWindow=\"0\" yWindow=\"0\" windowWidth=\"25600\" windowHeight=\"19020\" tabRatio=\"500\"/>'+\n\t\t\t'</bookViews>'+\n\t\t\t'<sheets>'+\n\t\t\t\t'<sheet name=\"Sheet1\" sheetId=\"1\" r:id=\"rId1\"/>'+\n\t\t\t'</sheets>'+\n\t\t\t'<definedNames/>'+\n\t\t'</workbook>',\n\n\t\"xl/worksheets/sheet1.xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>'+\n\t\t'<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" mc:Ignorable=\"x14ac\" xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\">'+\n\t\t\t'<sheetData/>'+\n\t\t\t'<mergeCells count=\"0\"/>'+\n\t\t'</worksheet>',\n\n\t\"xl/styles.xml\":\n\t\t'<?xml version=\"1.0\" encoding=\"UTF-8\"?>'+\n\t\t'<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" mc:Ignorable=\"x14ac\" xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\">'+\n\t\t\t'<numFmts count=\"6\">'+\n\t\t\t\t'<numFmt numFmtId=\"164\" formatCode=\"#,##0.00_-\\ [$$-45C]\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"165\" formatCode=\"&quot;£&quot;#,##0.00\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"166\" formatCode=\"[$€-2]\\ #,##0.00\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"167\" formatCode=\"0.0%\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"168\" formatCode=\"#,##0;(#,##0)\"/>'+\n\t\t\t\t'<numFmt numFmtId=\"169\" formatCode=\"#,##0.00;(#,##0.00)\"/>'+\n\t\t\t'</numFmts>'+\n\t\t\t'<fonts count=\"5\" x14ac:knownFonts=\"1\">'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<color rgb=\"FFFFFFFF\" />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<b />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<i />'+\n\t\t\t\t'</font>'+\n\t\t\t\t'<font>'+\n\t\t\t\t\t'<sz val=\"11\" />'+\n\t\t\t\t\t'<name val=\"Calibri\" />'+\n\t\t\t\t\t'<u />'+\n\t\t\t\t'</font>'+\n\t\t\t'</fonts>'+\n\t\t\t'<fills count=\"6\">'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"none\" />'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+ // Excel appears to use this as a dotted background regardless of values but\n\t\t\t\t\t'<patternFill patternType=\"none\" />'+ // to be valid to the schema, use a patternFill\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"FFD9D9D9\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"FFD99795\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"ffc6efce\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t\t'<fill>'+\n\t\t\t\t\t'<patternFill patternType=\"solid\">'+\n\t\t\t\t\t\t'<fgColor rgb=\"ffc6cfef\" />'+\n\t\t\t\t\t\t'<bgColor indexed=\"64\" />'+\n\t\t\t\t\t'</patternFill>'+\n\t\t\t\t'</fill>'+\n\t\t\t'</fills>'+\n\t\t\t'<borders count=\"2\">'+\n\t\t\t\t'<border>'+\n\t\t\t\t\t'<left />'+\n\t\t\t\t\t'<right />'+\n\t\t\t\t\t'<top />'+\n\t\t\t\t\t'<bottom />'+\n\t\t\t\t\t'<diagonal />'+\n\t\t\t\t'</border>'+\n\t\t\t\t'<border diagonalUp=\"false\" diagonalDown=\"false\">'+\n\t\t\t\t\t'<left style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</left>'+\n\t\t\t\t\t'<right style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</right>'+\n\t\t\t\t\t'<top style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</top>'+\n\t\t\t\t\t'<bottom style=\"thin\">'+\n\t\t\t\t\t\t'<color auto=\"1\" />'+\n\t\t\t\t\t'</bottom>'+\n\t\t\t\t\t'<diagonal />'+\n\t\t\t\t'</border>'+\n\t\t\t'</borders>'+\n\t\t\t'<cellStyleXfs count=\"1\">'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" />'+\n\t\t\t'</cellStyleXfs>'+\n\t\t\t'<cellXfs count=\"67\">'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"2\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"3\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"4\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"5\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"0\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"2\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"3\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"4\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"1\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"2\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"3\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"4\" fillId=\"5\" borderId=\"1\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"left\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"center\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"right\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment horizontal=\"fill\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment textRotation=\"90\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyAlignment=\"1\">'+\n\t\t\t\t\t'<alignment wrapText=\"1\"/>'+\n\t\t\t\t'</xf>'+\n\t\t\t\t'<xf numFmtId=\"9\"   fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"164\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"165\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"166\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"167\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"168\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"169\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"3\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"4\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"1\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t\t'<xf numFmtId=\"2\" fontId=\"0\" fillId=\"0\" borderId=\"0\" applyFont=\"1\" applyFill=\"1\" applyBorder=\"1\" xfId=\"0\" applyNumberFormat=\"1\"/>'+\n\t\t\t'</cellXfs>'+\n\t\t\t'<cellStyles count=\"1\">'+\n\t\t\t\t'<cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\" />'+\n\t\t\t'</cellStyles>'+\n\t\t\t'<dxfs count=\"0\" />'+\n\t\t\t'<tableStyles count=\"0\" defaultTableStyle=\"TableStyleMedium9\" defaultPivotStyle=\"PivotStyleMedium4\" />'+\n\t\t'</styleSheet>'\n};\n// Note we could use 3 `for` loops for the styles, but when gzipped there is\n// virtually no difference in size, since the above can be easily compressed\n\n// Pattern matching for special number formats. Perhaps this should be exposed\n// via an API in future?\n// Ref: section 3.8.30 - built in formatters in open spreadsheet\n//   https://www.ecma-international.org/news/TC45_current_work/Office%20Open%20XML%20Part%204%20-%20Markup%20Language%20Reference.pdf\nvar _excelSpecials = [\n\t{ match: /^\\-?\\d+\\.\\d%$/,       style: 60, fmt: function (d) { return d/100; } }, // Precent with d.p.\n\t{ match: /^\\-?\\d+\\.?\\d*%$/,     style: 56, fmt: function (d) { return d/100; } }, // Percent\n\t{ match: /^\\-?\\$[\\d,]+.?\\d*$/,  style: 57 }, // Dollars\n\t{ match: /^\\-?£[\\d,]+.?\\d*$/,   style: 58 }, // Pounds\n\t{ match: /^\\-?€[\\d,]+.?\\d*$/,   style: 59 }, // Euros\n\t{ match: /^\\-?\\d+$/,            style: 65 }, // Numbers without thousand separators\n\t{ match: /^\\-?\\d+\\.\\d{2}$/,     style: 66 }, // Numbers 2 d.p. without thousands separators\n\t{ match: /^\\([\\d,]+\\)$/,        style: 61, fmt: function (d) { return -1 * d.replace(/[\\(\\)]/g, ''); } },  // Negative numbers indicated by brackets\n\t{ match: /^\\([\\d,]+\\.\\d{2}\\)$/, style: 62, fmt: function (d) { return -1 * d.replace(/[\\(\\)]/g, ''); } },  // Negative numbers indicated by brackets - 2d.p.\n\t{ match: /^\\-?[\\d,]+$/,         style: 63 }, // Numbers with thousand separators\n\t{ match: /^\\-?[\\d,]+\\.\\d{2}$/,  style: 64 }  // Numbers with 2 d.p. and thousands separators\n];\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Buttons\n */\n\n//\n// Copy to clipboard\n//\nDataTable.ext.buttons.copyHtml5 = {\n\tclassName: 'buttons-copy buttons-html5',\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.copy', 'Copy' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\tthis.processing( true );\n\n\t\tvar that = this;\n\t\tvar exportData = _exportData( dt, config );\n\t\tvar info = dt.buttons.exportInfo( config );\n\t\tvar newline = _newLine(config);\n\t\tvar output = exportData.str;\n\t\tvar hiddenDiv = $('<div/>')\n\t\t\t.css( {\n\t\t\t\theight: 1,\n\t\t\t\twidth: 1,\n\t\t\t\toverflow: 'hidden',\n\t\t\t\tposition: 'fixed',\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0\n\t\t\t} );\n\n\t\tif ( info.title ) {\n\t\t\toutput = info.title + newline + newline + output;\n\t\t}\n\n\t\tif ( info.messageTop ) {\n\t\t\toutput = info.messageTop + newline + newline + output;\n\t\t}\n\n\t\tif ( info.messageBottom ) {\n\t\t\toutput = output + newline + newline + info.messageBottom;\n\t\t}\n\n\t\tif ( config.customize ) {\n\t\t\toutput = config.customize( output, config, dt );\n\t\t}\n\n\t\tvar textarea = $('<textarea readonly/>')\n\t\t\t.val( output )\n\t\t\t.appendTo( hiddenDiv );\n\n\t\t// For browsers that support the copy execCommand, try to use it\n\t\tif ( document.queryCommandSupported('copy') ) {\n\t\t\thiddenDiv.appendTo( dt.table().container() );\n\t\t\ttextarea[0].focus();\n\t\t\ttextarea[0].select();\n\n\t\t\ttry {\n\t\t\t\tvar successful = document.execCommand( 'copy' );\n\t\t\t\thiddenDiv.remove();\n\n\t\t\t\tif (successful) {\n\t\t\t\t\tdt.buttons.info(\n\t\t\t\t\t\tdt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),\n\t\t\t\t\t\tdt.i18n( 'buttons.copySuccess', {\n\t\t\t\t\t\t\t1: 'Copied one row to clipboard',\n\t\t\t\t\t\t\t_: 'Copied %d rows to clipboard'\n\t\t\t\t\t\t}, exportData.rows ),\n\t\t\t\t\t\t2000\n\t\t\t\t\t);\n\n\t\t\t\t\tthis.processing( false );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (t) {}\n\t\t}\n\n\t\t// Otherwise we show the text box and instruct the user to use it\n\t\tvar message = $('<span>'+dt.i18n( 'buttons.copyKeys',\n\t\t\t\t'Press <i>ctrl</i> or <i>\\u2318</i> + <i>C</i> to copy the table data<br>to your system clipboard.<br><br>'+\n\t\t\t\t'To cancel, click this message or press escape.' )+'</span>'\n\t\t\t)\n\t\t\t.append( hiddenDiv );\n\n\t\tdt.buttons.info( dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ), message, 0 );\n\n\t\t// Select the text so when the user activates their system clipboard\n\t\t// it will copy that text\n\t\ttextarea[0].focus();\n\t\ttextarea[0].select();\n\n\t\t// Event to hide the message when the user is done\n\t\tvar container = $(message).closest('.dt-button-info');\n\t\tvar close = function () {\n\t\t\tcontainer.off( 'click.buttons-copy' );\n\t\t\t$(document).off( '.buttons-copy' );\n\t\t\tdt.buttons.info( false );\n\t\t};\n\n\t\tcontainer.on( 'click.buttons-copy', close );\n\t\t$(document)\n\t\t\t.on( 'keydown.buttons-copy', function (e) {\n\t\t\t\tif ( e.keyCode === 27 ) { // esc\n\t\t\t\t\tclose();\n\t\t\t\t\tthat.processing( false );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'copy.buttons-copy cut.buttons-copy', function () {\n\t\t\t\tclose();\n\t\t\t\tthat.processing( false );\n\t\t\t} );\n\t},\n\n\texportOptions: {},\n\n\tfieldSeparator: '\\t',\n\n\tfieldBoundary: '',\n\n\theader: true,\n\n\tfooter: false,\n\n\ttitle: '*',\n\n\tmessageTop: '*',\n\n\tmessageBottom: '*'\n};\n\n//\n// CSV export\n//\nDataTable.ext.buttons.csvHtml5 = {\n\tbom: false,\n\n\tclassName: 'buttons-csv buttons-html5',\n\n\tavailable: function () {\n\t\treturn window.FileReader !== undefined && window.Blob;\n\t},\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.csv', 'CSV' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\tthis.processing( true );\n\n\t\t// Set the text\n\t\tvar output = _exportData( dt, config ).str;\n\t\tvar info = dt.buttons.exportInfo(config);\n\t\tvar charset = config.charset;\n\n\t\tif ( config.customize ) {\n\t\t\toutput = config.customize( output, config, dt );\n\t\t}\n\n\t\tif ( charset !== false ) {\n\t\t\tif ( ! charset ) {\n\t\t\t\tcharset = document.characterSet || document.charset;\n\t\t\t}\n\n\t\t\tif ( charset ) {\n\t\t\t\tcharset = ';charset='+charset;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tcharset = '';\n\t\t}\n\n\t\tif ( config.bom ) {\n\t\t\toutput = '\\ufeff' + output;\n\t\t}\n\n\t\t_saveAs(\n\t\t\tnew Blob( [output], {type: 'text/csv'+charset} ),\n\t\t\tinfo.filename,\n\t\t\ttrue\n\t\t);\n\n\t\tthis.processing( false );\n\t},\n\n\tfilename: '*',\n\n\textension: '.csv',\n\n\texportOptions: {},\n\n\tfieldSeparator: ',',\n\n\tfieldBoundary: '\"',\n\n\tescapeChar: '\"',\n\n\tcharset: null,\n\n\theader: true,\n\n\tfooter: false\n};\n\n//\n// Excel (xlsx) export\n//\nDataTable.ext.buttons.excelHtml5 = {\n\tclassName: 'buttons-excel buttons-html5',\n\n\tavailable: function () {\n\t\treturn window.FileReader !== undefined && _jsZip() !== undefined && ! _isDuffSafari() && _serialiser;\n\t},\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.excel', 'Excel' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\tthis.processing( true );\n\n\t\tvar that = this;\n\t\tvar rowPos = 0;\n\t\tvar dataStartRow, dataEndRow;\n\t\tvar getXml = function ( type ) {\n\t\t\tvar str = excelStrings[ type ];\n\n\t\t\t//str = str.replace( /xmlns:/g, 'xmlns_' ).replace( /mc:/g, 'mc_' );\n\n\t\t\treturn $.parseXML( str );\n\t\t};\n\t\tvar rels = getXml('xl/worksheets/sheet1.xml');\n\t\tvar relsGet = rels.getElementsByTagName( \"sheetData\" )[0];\n\n\t\tvar xlsx = {\n\t\t\t_rels: {\n\t\t\t\t\".rels\": getXml('_rels/.rels')\n\t\t\t},\n\t\t\txl: {\n\t\t\t\t_rels: {\n\t\t\t\t\t\"workbook.xml.rels\": getXml('xl/_rels/workbook.xml.rels')\n\t\t\t\t},\n\t\t\t\t\"workbook.xml\": getXml('xl/workbook.xml'),\n\t\t\t\t\"styles.xml\": getXml('xl/styles.xml'),\n\t\t\t\t\"worksheets\": {\n\t\t\t\t\t\"sheet1.xml\": rels\n\t\t\t\t}\n\n\t\t\t},\n\t\t\t\"[Content_Types].xml\": getXml('[Content_Types].xml')\n\t\t};\n\n\t\tvar data = dt.buttons.exportData( config.exportOptions );\n\t\tvar currentRow, rowNode;\n\t\tvar addRow = function ( row ) {\n\t\t\tcurrentRow = rowPos+1;\n\t\t\trowNode = _createNode( rels, \"row\", { attr: {r:currentRow} } );\n\n\t\t\tfor ( var i=0, ien=row.length ; i<ien ; i++ ) {\n\t\t\t\t// Concat both the Cell Columns as a letter and the Row of the cell.\n\t\t\t\tvar cellId = createCellPos(i) + '' + currentRow;\n\t\t\t\tvar cell = null;\n\n\t\t\t\t// For null, undefined of blank cell, continue so it doesn't create the _createNode\n\t\t\t\tif ( row[i] === null || row[i] === undefined || row[i] === '' ) {\n\t\t\t\t\tif ( config.createEmptyCells === true ) {\n\t\t\t\t\t\trow[i] = '';\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar originalContent = row[i];\n\t\t\t\trow[i] = $.trim( row[i] );\n\n\t\t\t\t// Special number formatting options\n\t\t\t\tfor ( var j=0, jen=_excelSpecials.length ; j<jen ; j++ ) {\n\t\t\t\t\tvar special = _excelSpecials[j];\n\n\t\t\t\t\t// TODO Need to provide the ability for the specials to say\n\t\t\t\t\t// if they are returning a string, since at the moment it is\n\t\t\t\t\t// assumed to be a number\n\t\t\t\t\tif ( row[i].match && ! row[i].match(/^0\\d+/) && row[i].match( special.match ) ) {\n\t\t\t\t\t\tvar val = row[i].replace(/[^\\d\\.\\-]/g, '');\n\n\t\t\t\t\t\tif ( special.fmt ) {\n\t\t\t\t\t\t\tval = special.fmt( val );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcell = _createNode( rels, 'c', {\n\t\t\t\t\t\t\tattr: {\n\t\t\t\t\t\t\t\tr: cellId,\n\t\t\t\t\t\t\t\ts: special.style\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren: [\n\t\t\t\t\t\t\t\t_createNode( rels, 'v', { text: val } )\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( ! cell ) {\n\t\t\t\t\tif ( typeof row[i] === 'number' || (\n\t\t\t\t\t\trow[i].match &&\n\t\t\t\t\t\trow[i].match(/^-?\\d+(\\.\\d+)?$/) &&\n\t\t\t\t\t\t! row[i].match(/^0\\d+/) )\n\t\t\t\t\t) {\n\t\t\t\t\t\t// Detect numbers - don't match numbers with leading zeros\n\t\t\t\t\t\t// or a negative anywhere but the start\n\t\t\t\t\t\tcell = _createNode( rels, 'c', {\n\t\t\t\t\t\t\tattr: {\n\t\t\t\t\t\t\t\tt: 'n',\n\t\t\t\t\t\t\t\tr: cellId\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren: [\n\t\t\t\t\t\t\t\t_createNode( rels, 'v', { text: row[i] } )\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// String output - replace non standard characters for text output\n\t\t\t\t\t\tvar text = ! originalContent.replace ?\n\t\t\t\t\t\t\toriginalContent :\n\t\t\t\t\t\t\toriginalContent.replace(/[\\x00-\\x09\\x0B\\x0C\\x0E-\\x1F\\x7F-\\x9F]/g, '');\n\n\t\t\t\t\t\tcell = _createNode( rels, 'c', {\n\t\t\t\t\t\t\tattr: {\n\t\t\t\t\t\t\t\tt: 'inlineStr',\n\t\t\t\t\t\t\t\tr: cellId\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren:{\n\t\t\t\t\t\t\t\trow: _createNode( rels, 'is', {\n\t\t\t\t\t\t\t\t\tchildren: {\n\t\t\t\t\t\t\t\t\t\trow: _createNode( rels, 't', {\n\t\t\t\t\t\t\t\t\t\t\ttext: text,\n\t\t\t\t\t\t\t\t\t\t\tattr: {\n\t\t\t\t\t\t\t\t\t\t\t\t'xml:space': 'preserve'\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\trowNode.appendChild( cell );\n\t\t\t}\n\n\t\t\trelsGet.appendChild(rowNode);\n\t\t\trowPos++;\n\t\t};\n\n\t\tif ( config.customizeData ) {\n\t\t\tconfig.customizeData( data );\n\t\t}\n\n\t\tvar mergeCells = function ( row, colspan ) {\n\t\t\tvar mergeCells = $('mergeCells', rels);\n\n\t\t\tmergeCells[0].appendChild( _createNode( rels, 'mergeCell', {\n\t\t\t\tattr: {\n\t\t\t\t\tref: 'A'+row+':'+createCellPos(colspan)+row\n\t\t\t\t}\n\t\t\t} ) );\n\t\t\tmergeCells.attr( 'count', parseFloat(mergeCells.attr( 'count' ))+1 );\n\t\t\t$('row:eq('+(row-1)+') c', rels).attr( 's', '51' ); // centre\n\t\t};\n\n\t\t// Title and top messages\n\t\tvar exportInfo = dt.buttons.exportInfo( config );\n\t\tif ( exportInfo.title ) {\n\t\t\taddRow( [exportInfo.title], rowPos );\n\t\t\tmergeCells( rowPos, data.header.length-1 );\n\t\t}\n\n\t\tif ( exportInfo.messageTop ) {\n\t\t\taddRow( [exportInfo.messageTop], rowPos );\n\t\t\tmergeCells( rowPos, data.header.length-1 );\n\t\t}\n\n\n\t\t// Table itself\n\t\tif ( config.header ) {\n\t\t\taddRow( data.header, rowPos );\n\t\t\t$('row:last c', rels).attr( 's', '2' ); // bold\n\t\t}\n\t\n\t\tdataStartRow = rowPos;\n\n\t\tfor ( var n=0, ie=data.body.length ; n<ie ; n++ ) {\n\t\t\taddRow( data.body[n], rowPos );\n\t\t}\n\t\n\t\tdataEndRow = rowPos;\n\n\t\tif ( config.footer && data.footer ) {\n\t\t\taddRow( data.footer, rowPos);\n\t\t\t$('row:last c', rels).attr( 's', '2' ); // bold\n\t\t}\n\n\t\t// Below the table\n\t\tif ( exportInfo.messageBottom ) {\n\t\t\taddRow( [exportInfo.messageBottom], rowPos );\n\t\t\tmergeCells( rowPos, data.header.length-1 );\n\t\t}\n\n\t\t// Set column widths\n\t\tvar cols = _createNode( rels, 'cols' );\n\t\t$('worksheet', rels).prepend( cols );\n\n\t\tfor ( var i=0, ien=data.header.length ; i<ien ; i++ ) {\n\t\t\tcols.appendChild( _createNode( rels, 'col', {\n\t\t\t\tattr: {\n\t\t\t\t\tmin: i+1,\n\t\t\t\t\tmax: i+1,\n\t\t\t\t\twidth: _excelColWidth( data, i ),\n\t\t\t\t\tcustomWidth: 1\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\t// Workbook modifications\n\t\tvar workbook = xlsx.xl['workbook.xml'];\n\n\t\t$( 'sheets sheet', workbook ).attr( 'name', _sheetname( config ) );\n\n\t\t// Auto filter for columns\n\t\tif ( config.autoFilter ) {\n\t\t\t$('mergeCells', rels).before( _createNode( rels, 'autoFilter', {\n\t\t\t\tattr: {\n\t\t\t\t\tref: 'A'+dataStartRow+':'+createCellPos(data.header.length-1)+dataEndRow\n\t\t\t\t}\n\t\t\t} ) );\n\n\t\t\t$('definedNames', workbook).append( _createNode( workbook, 'definedName', {\n\t\t\t\tattr: {\n\t\t\t\t\tname: '_xlnm._FilterDatabase',\n\t\t\t\t\tlocalSheetId: '0',\n\t\t\t\t\thidden: 1\n\t\t\t\t},\n\t\t\t\ttext: _sheetname(config)+'!$A$'+dataStartRow+':'+createCellPos(data.header.length-1)+dataEndRow\n\t\t\t} ) );\n\t\t}\n\n\t\t// Let the developer customise the document if they want to\n\t\tif ( config.customize ) {\n\t\t\tconfig.customize( xlsx, config, dt );\n\t\t}\n\n\t\t// Excel doesn't like an empty mergeCells tag\n\t\tif ( $('mergeCells', rels).children().length === 0 ) {\n\t\t\t$('mergeCells', rels).remove();\n\t\t}\n\n\t\tvar jszip = _jsZip();\n\t\tvar zip = new jszip();\n\t\tvar zipConfig = {\n\t\t\ttype: 'blob',\n\t\t\tmimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'\n\t\t};\n\n\t\t_addToZip( zip, xlsx );\n\n\t\tif ( zip.generateAsync ) {\n\t\t\t// JSZip 3+\n\t\t\tzip\n\t\t\t\t.generateAsync( zipConfig )\n\t\t\t\t.then( function ( blob ) {\n\t\t\t\t\t_saveAs( blob, exportInfo.filename );\n\t\t\t\t\tthat.processing( false );\n\t\t\t\t} );\n\t\t}\n\t\telse {\n\t\t\t// JSZip 2.5\n\t\t\t_saveAs(\n\t\t\t\tzip.generate( zipConfig ),\n\t\t\t\texportInfo.filename\n\t\t\t);\n\t\t\tthis.processing( false );\n\t\t}\n\t},\n\n\tfilename: '*',\n\n\textension: '.xlsx',\n\n\texportOptions: {},\n\n\theader: true,\n\n\tfooter: false,\n\n\ttitle: '*',\n\n\tmessageTop: '*',\n\n\tmessageBottom: '*',\n\n\tcreateEmptyCells: false,\n\n\tautoFilter: false,\n\n\tsheetName: ''\n};\n\n//\n// PDF export - using pdfMake - http://pdfmake.org\n//\nDataTable.ext.buttons.pdfHtml5 = {\n\tclassName: 'buttons-pdf buttons-html5',\n\n\tavailable: function () {\n\t\treturn window.FileReader !== undefined && _pdfMake();\n\t},\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.pdf', 'PDF' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\tthis.processing( true );\n\n\t\tvar that = this;\n\t\tvar data = dt.buttons.exportData( config.exportOptions );\n\t\tvar info = dt.buttons.exportInfo( config );\n\t\tvar rows = [];\n\n\t\tif ( config.header ) {\n\t\t\trows.push( $.map( data.header, function ( d ) {\n\t\t\t\treturn {\n\t\t\t\t\ttext: typeof d === 'string' ? d : d+'',\n\t\t\t\t\tstyle: 'tableHeader'\n\t\t\t\t};\n\t\t\t} ) );\n\t\t}\n\n\t\tfor ( var i=0, ien=data.body.length ; i<ien ; i++ ) {\n\t\t\trows.push( $.map( data.body[i], function ( d ) {\n\t\t\t\tif ( d === null || d === undefined ) {\n\t\t\t\t\td = '';\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\ttext: typeof d === 'string' ? d : d+'',\n\t\t\t\t\tstyle: i % 2 ? 'tableBodyEven' : 'tableBodyOdd'\n\t\t\t\t};\n\t\t\t} ) );\n\t\t}\n\n\t\tif ( config.footer && data.footer) {\n\t\t\trows.push( $.map( data.footer, function ( d ) {\n\t\t\t\treturn {\n\t\t\t\t\ttext: typeof d === 'string' ? d : d+'',\n\t\t\t\t\tstyle: 'tableFooter'\n\t\t\t\t};\n\t\t\t} ) );\n\t\t}\n\n\t\tvar doc = {\n\t\t\tpageSize: config.pageSize,\n\t\t\tpageOrientation: config.orientation,\n\t\t\tcontent: [\n\t\t\t\t{\n\t\t\t\t\ttable: {\n\t\t\t\t\t\theaderRows: 1,\n\t\t\t\t\t\tbody: rows\n\t\t\t\t\t},\n\t\t\t\t\tlayout: 'noBorders'\n\t\t\t\t}\n\t\t\t],\n\t\t\tstyles: {\n\t\t\t\ttableHeader: {\n\t\t\t\t\tbold: true,\n\t\t\t\t\tfontSize: 11,\n\t\t\t\t\tcolor: 'white',\n\t\t\t\t\tfillColor: '#2d4154',\n\t\t\t\t\talignment: 'center'\n\t\t\t\t},\n\t\t\t\ttableBodyEven: {},\n\t\t\t\ttableBodyOdd: {\n\t\t\t\t\tfillColor: '#f3f3f3'\n\t\t\t\t},\n\t\t\t\ttableFooter: {\n\t\t\t\t\tbold: true,\n\t\t\t\t\tfontSize: 11,\n\t\t\t\t\tcolor: 'white',\n\t\t\t\t\tfillColor: '#2d4154'\n\t\t\t\t},\n\t\t\t\ttitle: {\n\t\t\t\t\talignment: 'center',\n\t\t\t\t\tfontSize: 15\n\t\t\t\t},\n\t\t\t\tmessage: {}\n\t\t\t},\n\t\t\tdefaultStyle: {\n\t\t\t\tfontSize: 10\n\t\t\t}\n\t\t};\n\n\t\tif ( info.messageTop ) {\n\t\t\tdoc.content.unshift( {\n\t\t\t\ttext: info.messageTop,\n\t\t\t\tstyle: 'message',\n\t\t\t\tmargin: [ 0, 0, 0, 12 ]\n\t\t\t} );\n\t\t}\n\n\t\tif ( info.messageBottom ) {\n\t\t\tdoc.content.push( {\n\t\t\t\ttext: info.messageBottom,\n\t\t\t\tstyle: 'message',\n\t\t\t\tmargin: [ 0, 0, 0, 12 ]\n\t\t\t} );\n\t\t}\n\n\t\tif ( info.title ) {\n\t\t\tdoc.content.unshift( {\n\t\t\t\ttext: info.title,\n\t\t\t\tstyle: 'title',\n\t\t\t\tmargin: [ 0, 0, 0, 12 ]\n\t\t\t} );\n\t\t}\n\n\t\tif ( config.customize ) {\n\t\t\tconfig.customize( doc, config, dt );\n\t\t}\n\n\t\tvar pdf = _pdfMake().createPdf( doc );\n\n\t\tif ( config.download === 'open' && ! _isDuffSafari() ) {\n\t\t\tpdf.open();\n\t\t}\n\t\telse {\n\t\t\tpdf.download( info.filename );\n\t\t}\n\n\t\tthis.processing( false );\n\t},\n\n\ttitle: '*',\n\n\tfilename: '*',\n\n\textension: '.pdf',\n\n\texportOptions: {},\n\n\torientation: 'portrait',\n\n\tpageSize: 'A4',\n\n\theader: true,\n\n\tfooter: false,\n\n\tmessageTop: '*',\n\n\tmessageBottom: '*',\n\n\tcustomize: null,\n\n\tdownload: 'download'\n};\n\n\nreturn DataTable.Buttons;\n}));\n\n\n/*!\n * Print button for Buttons and DataTables.\n * 2016 SpryMedia Ltd - datatables.net/license\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\tif ( ! $.fn.dataTable.Buttons ) {\n\t\t\t\trequire('datatables.net-buttons')(root, $);\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar _link = document.createElement( 'a' );\n\n/**\n * Clone link and style tags, taking into account the need to change the source\n * path.\n *\n * @param  {node}     el Element to convert\n */\nvar _styleToAbs = function( el ) {\n\tvar url;\n\tvar clone = $(el).clone()[0];\n\tvar linkHost;\n\n\tif ( clone.nodeName.toLowerCase() === 'link' ) {\n\t\tclone.href = _relToAbs( clone.href );\n\t}\n\n\treturn clone.outerHTML;\n};\n\n/**\n * Convert a URL from a relative to an absolute address so it will work\n * correctly in the popup window which has no base URL.\n *\n * @param  {string} href URL\n */\nvar _relToAbs = function( href ) {\n\t// Assign to a link on the original page so the browser will do all the\n\t// hard work of figuring out where the file actually is\n\t_link.href = href;\n\tvar linkHost = _link.host;\n\n\t// IE doesn't have a trailing slash on the host\n\t// Chrome has it on the pathname\n\tif ( linkHost.indexOf('/') === -1 && _link.pathname.indexOf('/') !== 0) {\n\t\tlinkHost += '/';\n\t}\n\n\treturn _link.protocol+\"//\"+linkHost+_link.pathname+_link.search;\n};\n\n\nDataTable.ext.buttons.print = {\n\tclassName: 'buttons-print',\n\n\ttext: function ( dt ) {\n\t\treturn dt.i18n( 'buttons.print', 'Print' );\n\t},\n\n\taction: function ( e, dt, button, config ) {\n\t\tvar data = dt.buttons.exportData(\n\t\t\t$.extend( {decodeEntities: false}, config.exportOptions ) // XSS protection\n\t\t);\n\t\tvar exportInfo = dt.buttons.exportInfo( config );\n\t\tvar columnClasses = dt\n\t\t\t.columns( config.exportOptions.columns )\n\t\t\t.flatten()\n\t\t\t.map( function (idx) {\n\t\t\t\treturn dt.settings()[0].aoColumns[dt.column(idx).index()].sClass;\n\t\t\t} )\n\t\t\t.toArray();\n\n\t\tvar addRow = function ( d, tag ) {\n\t\t\tvar str = '<tr>';\n\n\t\t\tfor ( var i=0, ien=d.length ; i<ien ; i++ ) {\n\t\t\t\t// null and undefined aren't useful in the print output\n\t\t\t\tvar dataOut = d[i] === null || d[i] === undefined ?\n\t\t\t\t\t'' :\n\t\t\t\t\td[i];\n\t\t\t\tvar classAttr = columnClasses[i] ?\n\t\t\t\t\t'class=\"'+columnClasses[i]+'\"' :\n\t\t\t\t\t'';\n\n\t\t\t\tstr += '<'+tag+' '+classAttr+'>'+dataOut+'</'+tag+'>';\n\t\t\t}\n\n\t\t\treturn str + '</tr>';\n\t\t};\n\n\t\t// Construct a table for printing\n\t\tvar html = '<table class=\"'+dt.table().node().className+'\">';\n\n\t\tif ( config.header ) {\n\t\t\thtml += '<thead>'+ addRow( data.header, 'th' ) +'</thead>';\n\t\t}\n\n\t\thtml += '<tbody>';\n\t\tfor ( var i=0, ien=data.body.length ; i<ien ; i++ ) {\n\t\t\thtml += addRow( data.body[i], 'td' );\n\t\t}\n\t\thtml += '</tbody>';\n\n\t\tif ( config.footer && data.footer ) {\n\t\t\thtml += '<tfoot>'+ addRow( data.footer, 'th' ) +'</tfoot>';\n\t\t}\n\t\thtml += '</table>';\n\n\t\t// Open a new window for the printable table\n\t\tvar win = window.open( '', '' );\n\t\twin.document.close();\n\n\t\t// Inject the title and also a copy of the style and link tags from this\n\t\t// document so the table can retain its base styling. Note that we have\n\t\t// to use string manipulation as IE won't allow elements to be created\n\t\t// in the host document and then appended to the new window.\n\t\tvar head = '<title>'+exportInfo.title+'</title>';\n\t\t$('style, link').each( function () {\n\t\t\thead += _styleToAbs( this );\n\t\t} );\n\n\t\ttry {\n\t\t\twin.document.head.innerHTML = head; // Work around for Edge\n\t\t}\n\t\tcatch (e) {\n\t\t\t$(win.document.head).html( head ); // Old IE\n\t\t}\n\n\t\t// Inject the table and other surrounding information\n\t\twin.document.body.innerHTML =\n\t\t\t'<h1>'+exportInfo.title+'</h1>'+\n\t\t\t'<div>'+(exportInfo.messageTop || '')+'</div>'+\n\t\t\thtml+\n\t\t\t'<div>'+(exportInfo.messageBottom || '')+'</div>';\n\n\t\t$(win.document.body).addClass('dt-print-view');\n\n\t\t$('img', win.document.body).each( function ( i, img ) {\n\t\t\timg.setAttribute( 'src', _relToAbs( img.getAttribute('src') ) );\n\t\t} );\n\n\t\tif ( config.customize ) {\n\t\t\tconfig.customize( win, config, dt );\n\t\t}\n\n\t\t// Allow stylesheets time to load\n\t\tvar autoPrint = function () {\n\t\t\tif ( config.autoPrint ) {\n\t\t\t\twin.print(); // blocking - so close will not\n\t\t\t\twin.close(); // execute until this is done\n\t\t\t}\n\t\t};\n\n\t\tif ( navigator.userAgent.match(/Trident\\/\\d.\\d/) ) { // IE needs to call this without a setTimeout\n\t\t\tautoPrint();\n\t\t}\n\t\telse {\n\t\t\twin.setTimeout( autoPrint, 1000 );\n\t\t}\n\t},\n\n\ttitle: '*',\n\n\tmessageTop: '*',\n\n\tmessageBottom: '*',\n\n\texportOptions: {},\n\n\theader: true,\n\n\tfooter: false,\n\n\tautoPrint: true,\n\n\tcustomize: null\n};\n\n\nreturn DataTable.Buttons;\n}));\n\n\n/*! ColReorder 1.5.0\n * ©2010-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     ColReorder\n * @description Provide the ability to reorder columns in a DataTable\n * @version     1.5.0\n * @file        dataTables.colReorder.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2010-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/**\n * Switch the key value pairing of an index array to be value key (i.e. the old value is now the\n * key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ].\n *  @method  fnInvertKeyValues\n *  @param   array aIn Array to switch around\n *  @returns array\n */\nfunction fnInvertKeyValues( aIn )\n{\n\tvar aRet=[];\n\tfor ( var i=0, iLen=aIn.length ; i<iLen ; i++ )\n\t{\n\t\taRet[ aIn[i] ] = i;\n\t}\n\treturn aRet;\n}\n\n\n/**\n * Modify an array by switching the position of two elements\n *  @method  fnArraySwitch\n *  @param   array aArray Array to consider, will be modified by reference (i.e. no return)\n *  @param   int iFrom From point\n *  @param   int iTo Insert point\n *  @returns void\n */\nfunction fnArraySwitch( aArray, iFrom, iTo )\n{\n\tvar mStore = aArray.splice( iFrom, 1 )[0];\n\taArray.splice( iTo, 0, mStore );\n}\n\n\n/**\n * Switch the positions of nodes in a parent node (note this is specifically designed for\n * table rows). Note this function considers all element nodes under the parent!\n *  @method  fnDomSwitch\n *  @param   string sTag Tag to consider\n *  @param   int iFrom Element to move\n *  @param   int Point to element the element to (before this point), can be null for append\n *  @returns void\n */\nfunction fnDomSwitch( nParent, iFrom, iTo )\n{\n\tvar anTags = [];\n\tfor ( var i=0, iLen=nParent.childNodes.length ; i<iLen ; i++ )\n\t{\n\t\tif ( nParent.childNodes[i].nodeType == 1 )\n\t\t{\n\t\t\tanTags.push( nParent.childNodes[i] );\n\t\t}\n\t}\n\tvar nStore = anTags[ iFrom ];\n\n\tif ( iTo !== null )\n\t{\n\t\tnParent.insertBefore( nStore, anTags[iTo] );\n\t}\n\telse\n\t{\n\t\tnParent.appendChild( nStore );\n\t}\n}\n\n\n/**\n * Plug-in for DataTables which will reorder the internal column structure by taking the column\n * from one position (iFrom) and insert it into a given point (iTo).\n *  @method  $.fn.dataTableExt.oApi.fnColReorder\n *  @param   object oSettings DataTables settings object - automatically added by DataTables!\n *  @param   int iFrom Take the column to be repositioned from this point\n *  @param   int iTo and insert it into this point\n *  @param   bool drop Indicate if the reorder is the final one (i.e. a drop)\n *    not a live reorder\n *  @param   bool invalidateRows speeds up processing if false passed\n *  @returns void\n */\n$.fn.dataTableExt.oApi.fnColReorder = function ( oSettings, iFrom, iTo, drop, invalidateRows )\n{\n\tvar i, iLen, j, jLen, jen, iCols=oSettings.aoColumns.length, nTrs, oCol;\n\tvar attrMap = function ( obj, prop, mapping ) {\n\t\tif ( ! obj[ prop ] || typeof obj[ prop ] === 'function' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar a = obj[ prop ].split('.');\n\t\tvar num = a.shift();\n\n\t\tif ( isNaN( num*1 ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tobj[ prop ] = mapping[ num*1 ]+'.'+a.join('.');\n\t};\n\n\t/* Sanity check in the input */\n\tif ( iFrom == iTo )\n\t{\n\t\t/* Pointless reorder */\n\t\treturn;\n\t}\n\n\tif ( iFrom < 0 || iFrom >= iCols )\n\t{\n\t\tthis.oApi._fnLog( oSettings, 1, \"ColReorder 'from' index is out of bounds: \"+iFrom );\n\t\treturn;\n\t}\n\n\tif ( iTo < 0 || iTo >= iCols )\n\t{\n\t\tthis.oApi._fnLog( oSettings, 1, \"ColReorder 'to' index is out of bounds: \"+iTo );\n\t\treturn;\n\t}\n\n\t/*\n\t * Calculate the new column array index, so we have a mapping between the old and new\n\t */\n\tvar aiMapping = [];\n\tfor ( i=0, iLen=iCols ; i<iLen ; i++ )\n\t{\n\t\taiMapping[i] = i;\n\t}\n\tfnArraySwitch( aiMapping, iFrom, iTo );\n\tvar aiInvertMapping = fnInvertKeyValues( aiMapping );\n\n\n\t/*\n\t * Convert all internal indexing to the new column order indexes\n\t */\n\t/* Sorting */\n\tfor ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )\n\t{\n\t\toSettings.aaSorting[i][0] = aiInvertMapping[ oSettings.aaSorting[i][0] ];\n\t}\n\n\t/* Fixed sorting */\n\tif ( oSettings.aaSortingFixed !== null )\n\t{\n\t\tfor ( i=0, iLen=oSettings.aaSortingFixed.length ; i<iLen ; i++ )\n\t\t{\n\t\t\toSettings.aaSortingFixed[i][0] = aiInvertMapping[ oSettings.aaSortingFixed[i][0] ];\n\t\t}\n\t}\n\n\t/* Data column sorting (the column which the sort for a given column should take place on) */\n\tfor ( i=0, iLen=iCols ; i<iLen ; i++ )\n\t{\n\t\toCol = oSettings.aoColumns[i];\n\t\tfor ( j=0, jLen=oCol.aDataSort.length ; j<jLen ; j++ )\n\t\t{\n\t\t\toCol.aDataSort[j] = aiInvertMapping[ oCol.aDataSort[j] ];\n\t\t}\n\n\t\t// Update the column indexes\n\t\toCol.idx = aiInvertMapping[ oCol.idx ];\n\t}\n\n\t// Update 1.10 optimised sort class removal variable\n\t$.each( oSettings.aLastSort, function (i, val) {\n\t\toSettings.aLastSort[i].src = aiInvertMapping[ val.src ];\n\t} );\n\n\t/* Update the Get and Set functions for each column */\n\tfor ( i=0, iLen=iCols ; i<iLen ; i++ )\n\t{\n\t\toCol = oSettings.aoColumns[i];\n\n\t\tif ( typeof oCol.mData == 'number' ) {\n\t\t\toCol.mData = aiInvertMapping[ oCol.mData ];\n\t\t}\n\t\telse if ( $.isPlainObject( oCol.mData ) ) {\n\t\t\t// HTML5 data sourced\n\t\t\tattrMap( oCol.mData, '_',      aiInvertMapping );\n\t\t\tattrMap( oCol.mData, 'filter', aiInvertMapping );\n\t\t\tattrMap( oCol.mData, 'sort',   aiInvertMapping );\n\t\t\tattrMap( oCol.mData, 'type',   aiInvertMapping );\n\t\t}\n\t}\n\n\t/*\n\t * Move the DOM elements\n\t */\n\tif ( oSettings.aoColumns[iFrom].bVisible )\n\t{\n\t\t/* Calculate the current visible index and the point to insert the node before. The insert\n\t\t * before needs to take into account that there might not be an element to insert before,\n\t\t * in which case it will be null, and an appendChild should be used\n\t\t */\n\t\tvar iVisibleIndex = this.oApi._fnColumnIndexToVisible( oSettings, iFrom );\n\t\tvar iInsertBeforeIndex = null;\n\n\t\ti = iTo < iFrom ? iTo : iTo + 1;\n\t\twhile ( iInsertBeforeIndex === null && i < iCols )\n\t\t{\n\t\t\tiInsertBeforeIndex = this.oApi._fnColumnIndexToVisible( oSettings, i );\n\t\t\ti++;\n\t\t}\n\n\t\t/* Header */\n\t\tnTrs = oSettings.nTHead.getElementsByTagName('tr');\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );\n\t\t}\n\n\t\t/* Footer */\n\t\tif ( oSettings.nTFoot !== null )\n\t\t{\n\t\t\tnTrs = oSettings.nTFoot.getElementsByTagName('tr');\n\t\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfnDomSwitch( nTrs[i], iVisibleIndex, iInsertBeforeIndex );\n\t\t\t}\n\t\t}\n\n\t\t/* Body */\n\t\tfor ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( oSettings.aoData[i].nTr !== null )\n\t\t\t{\n\t\t\t\tfnDomSwitch( oSettings.aoData[i].nTr, iVisibleIndex, iInsertBeforeIndex );\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t * Move the internal array elements\n\t */\n\t/* Columns */\n\tfnArraySwitch( oSettings.aoColumns, iFrom, iTo );\n\n\t// regenerate the get / set functions\n\tfor ( i=0, iLen=iCols ; i<iLen ; i++ ) {\n\t\toSettings.oApi._fnColumnOptions( oSettings, i, {} );\n\t}\n\n\t/* Search columns */\n\tfnArraySwitch( oSettings.aoPreSearchCols, iFrom, iTo );\n\n\t/* Array array - internal data anodes cache */\n\tfor ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )\n\t{\n\t\tvar data = oSettings.aoData[i];\n\t\tvar cells = data.anCells;\n\n\t\tif ( cells ) {\n\t\t\tfnArraySwitch( cells, iFrom, iTo );\n\n\t\t\t// Longer term, should this be moved into the DataTables' invalidate\n\t\t\t// methods?\n\t\t\tfor ( j=0, jen=cells.length ; j<jen ; j++ ) {\n\t\t\t\tif ( cells[j] && cells[j]._DT_CellIndex ) {\n\t\t\t\t\tcells[j]._DT_CellIndex.column = j;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// For DOM sourced data, the invalidate will reread the cell into\n\t\t// the data array, but for data sources as an array, they need to\n\t\t// be flipped\n\t\tif ( data.src !== 'dom' && $.isArray( data._aData ) ) {\n\t\t\tfnArraySwitch( data._aData, iFrom, iTo );\n\t\t}\n\t}\n\n\t/* Reposition the header elements in the header layout array */\n\tfor ( i=0, iLen=oSettings.aoHeader.length ; i<iLen ; i++ )\n\t{\n\t\tfnArraySwitch( oSettings.aoHeader[i], iFrom, iTo );\n\t}\n\n\tif ( oSettings.aoFooter !== null )\n\t{\n\t\tfor ( i=0, iLen=oSettings.aoFooter.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfnArraySwitch( oSettings.aoFooter[i], iFrom, iTo );\n\t\t}\n\t}\n\n\tif ( invalidateRows || invalidateRows === undefined )\n\t{\n\t\t$.fn.dataTable.Api( oSettings ).rows().invalidate();\n\t}\n\n\t/*\n\t * Update DataTables' event handlers\n\t */\n\n\t/* Sort listener */\n\tfor ( i=0, iLen=iCols ; i<iLen ; i++ )\n\t{\n\t\t$(oSettings.aoColumns[i].nTh).off('.DT');\n\t\tthis.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );\n\t}\n\n\n\t/* Fire an event so other plug-ins can update */\n\t$(oSettings.oInstance).trigger( 'column-reorder.dt', [ oSettings, {\n\t\tfrom: iFrom,\n\t\tto: iTo,\n\t\tmapping: aiInvertMapping,\n\t\tdrop: drop,\n\n\t\t// Old style parameters for compatibility\n\t\tiFrom: iFrom,\n\t\tiTo: iTo,\n\t\taiInvertMapping: aiInvertMapping\n\t} ] );\n};\n\n/**\n * ColReorder provides column visibility control for DataTables\n * @class ColReorder\n * @constructor\n * @param {object} dt DataTables settings object\n * @param {object} opts ColReorder options\n */\nvar ColReorder = function( dt, opts )\n{\n\tvar settings = new $.fn.dataTable.Api( dt ).settings()[0];\n\n\t// Ensure that we can't initialise on the same table twice\n\tif ( settings._colReorder ) {\n\t\treturn settings._colReorder;\n\t}\n\n\t// Allow the options to be a boolean for defaults\n\tif ( opts === true ) {\n\t\topts = {};\n\t}\n\n\t// Convert from camelCase to Hungarian, just as DataTables does\n\tvar camelToHungarian = $.fn.dataTable.camelToHungarian;\n\tif ( camelToHungarian ) {\n\t\tcamelToHungarian( ColReorder.defaults, ColReorder.defaults, true );\n\t\tcamelToHungarian( ColReorder.defaults, opts || {} );\n\t}\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Public class variables\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\t/**\n\t * @namespace Settings object which contains customisable information for ColReorder instance\n\t */\n\tthis.s = {\n\t\t/**\n\t\t * DataTables settings object\n\t\t *  @property dt\n\t\t *  @type     Object\n\t\t *  @default  null\n\t\t */\n\t\t\"dt\": null,\n\n\t\t/**\n\t\t * Enable flag\n\t\t *  @property dt\n\t\t *  @type     Object\n\t\t *  @default  null\n\t\t */\n\t\t\"enable\": null,\n\n\t\t/**\n\t\t * Initialisation object used for this instance\n\t\t *  @property init\n\t\t *  @type     object\n\t\t *  @default  {}\n\t\t */\n\t\t\"init\": $.extend( true, {}, ColReorder.defaults, opts ),\n\n\t\t/**\n\t\t * Number of columns to fix (not allow to be reordered)\n\t\t *  @property fixed\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t */\n\t\t\"fixed\": 0,\n\n\t\t/**\n\t\t * Number of columns to fix counting from right (not allow to be reordered)\n\t\t *  @property fixedRight\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t */\n\t\t\"fixedRight\": 0,\n\n\t\t/**\n\t\t * Callback function for once the reorder has been done\n\t\t *  @property reorderCallback\n\t\t *  @type     function\n\t\t *  @default  null\n\t\t */\n\t\t\"reorderCallback\": null,\n\n\t\t/**\n\t\t * @namespace Information used for the mouse drag\n\t\t */\n\t\t\"mouse\": {\n\t\t\t\"startX\": -1,\n\t\t\t\"startY\": -1,\n\t\t\t\"offsetX\": -1,\n\t\t\t\"offsetY\": -1,\n\t\t\t\"target\": -1,\n\t\t\t\"targetIndex\": -1,\n\t\t\t\"fromIndex\": -1\n\t\t},\n\n\t\t/**\n\t\t * Information which is used for positioning the insert cusor and knowing where to do the\n\t\t * insert. Array of objects with the properties:\n\t\t *   x: x-axis position\n\t\t *   to: insert point\n\t\t *  @property aoTargets\n\t\t *  @type     array\n\t\t *  @default  []\n\t\t */\n\t\t\"aoTargets\": []\n\t};\n\n\n\t/**\n\t * @namespace Common and useful DOM elements for the class instance\n\t */\n\tthis.dom = {\n\t\t/**\n\t\t * Dragging element (the one the mouse is moving)\n\t\t *  @property drag\n\t\t *  @type     element\n\t\t *  @default  null\n\t\t */\n\t\t\"drag\": null,\n\n\t\t/**\n\t\t * The insert cursor\n\t\t *  @property pointer\n\t\t *  @type     element\n\t\t *  @default  null\n\t\t */\n\t\t\"pointer\": null\n\t};\n\n\t/* Constructor logic */\n\tthis.s.enable = this.s.init.bEnable;\n\tthis.s.dt = settings;\n\tthis.s.dt._colReorder = this;\n\tthis._fnConstruct();\n\n\treturn this;\n};\n\n\n\n$.extend( ColReorder.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Public methods\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\t/**\n\t * Enable / disable end user interaction\n\t */\n\tfnEnable: function ( flag )\n\t{\n\t\tif ( flag === false ) {\n\t\t\treturn fnDisable();\n\t\t}\n\n\t\tthis.s.enable = true;\n\t},\n\n\t/**\n\t * Disable end user interaction\n\t */\n\tfnDisable: function ()\n\t{\n\t\tthis.s.enable = false;\n\t},\n\n\t/**\n\t * Reset the column ordering to the original ordering that was detected on\n\t * start up.\n\t *  @return {this} Returns `this` for chaining.\n\t *\n\t *  @example\n\t *    // DataTables initialisation with ColReorder\n\t *    var table = $('#example').dataTable( {\n\t *        \"sDom\": 'Rlfrtip'\n\t *    } );\n\t *\n\t *    // Add click event to a button to reset the ordering\n\t *    $('#resetOrdering').click( function (e) {\n\t *        e.preventDefault();\n\t *        $.fn.dataTable.ColReorder( table ).fnReset();\n\t *    } );\n\t */\n\t\"fnReset\": function ()\n\t{\n\t\tthis._fnOrderColumns( this.fnOrder() );\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * `Deprecated` - Get the current order of the columns, as an array.\n\t *  @return {array} Array of column identifiers\n\t *  @deprecated `fnOrder` should be used in preference to this method.\n\t *      `fnOrder` acts as a getter/setter.\n\t */\n\t\"fnGetCurrentOrder\": function ()\n\t{\n\t\treturn this.fnOrder();\n\t},\n\n\t/**\n\t * Get the current order of the columns, as an array. Note that the values\n\t * given in the array are unique identifiers for each column. Currently\n\t * these are the original ordering of the columns that was detected on\n\t * start up, but this could potentially change in future.\n\t *  @return {array} Array of column identifiers\n\t *\n\t *  @example\n\t *    // Get column ordering for the table\n\t *    var order = $.fn.dataTable.ColReorder( dataTable ).fnOrder();\n\t *//**\n\t * Set the order of the columns, from the positions identified in the\n\t * ordering array given. Note that ColReorder takes a brute force approach\n\t * to reordering, so it is possible multiple reordering events will occur\n\t * before the final order is settled upon.\n\t *  @param {array} [set] Array of column identifiers in the new order. Note\n\t *    that every column must be included, uniquely, in this array.\n\t *  @return {this} Returns `this` for chaining.\n\t *\n\t *  @example\n\t *    // Swap the first and second columns\n\t *    $.fn.dataTable.ColReorder( dataTable ).fnOrder( [1, 0, 2, 3, 4] );\n\t *\n\t *  @example\n\t *    // Move the first column to the end for the table `#example`\n\t *    var curr = $.fn.dataTable.ColReorder( '#example' ).fnOrder();\n\t *    var first = curr.shift();\n\t *    curr.push( first );\n\t *    $.fn.dataTable.ColReorder( '#example' ).fnOrder( curr );\n\t *\n\t *  @example\n\t *    // Reverse the table's order\n\t *    $.fn.dataTable.ColReorder( '#example' ).fnOrder(\n\t *      $.fn.dataTable.ColReorder( '#example' ).fnOrder().reverse()\n\t *    );\n\t */\n\t\"fnOrder\": function ( set, original )\n\t{\n\t\tvar a = [], i, ien, j, jen;\n\t\tvar columns = this.s.dt.aoColumns;\n\n\t\tif ( set === undefined ){\n\t\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\t\ta.push( columns[i]._ColReorder_iOrigCol );\n\t\t\t}\n\n\t\t\treturn a;\n\t\t}\n\n\t\t// The order given is based on the original indexes, rather than the\n\t\t// existing ones, so we need to translate from the original to current\n\t\t// before then doing the order\n\t\tif ( original ) {\n\t\t\tvar order = this.fnOrder();\n\n\t\t\tfor ( i=0, ien=set.length ; i<ien ; i++ ) {\n\t\t\t\ta.push( $.inArray( set[i], order ) );\n\t\t\t}\n\n\t\t\tset = a;\n\t\t}\n\n\t\tthis._fnOrderColumns( fnInvertKeyValues( set ) );\n\n\t\treturn this;\n\t},\n\n\n\t/**\n\t * Convert from the original column index, to the original\n\t *\n\t * @param  {int|array} idx Index(es) to convert\n\t * @param  {string} dir Transpose direction - `fromOriginal` / `toCurrent`\n\t *   or `'toOriginal` / `fromCurrent`\n\t * @return {int|array}     Converted values\n\t */\n\tfnTranspose: function ( idx, dir )\n\t{\n\t\tif ( ! dir ) {\n\t\t\tdir = 'toCurrent';\n\t\t}\n\n\t\tvar order = this.fnOrder();\n\t\tvar columns = this.s.dt.aoColumns;\n\n\t\tif ( dir === 'toCurrent' ) {\n\t\t\t// Given an original index, want the current\n\t\t\treturn ! $.isArray( idx ) ?\n\t\t\t\t$.inArray( idx, order ) :\n\t\t\t\t$.map( idx, function ( index ) {\n\t\t\t\t\treturn $.inArray( index, order );\n\t\t\t\t} );\n\t\t}\n\t\telse {\n\t\t\t// Given a current index, want the original\n\t\t\treturn ! $.isArray( idx ) ?\n\t\t\t\tcolumns[idx]._ColReorder_iOrigCol :\n\t\t\t\t$.map( idx, function ( index ) {\n\t\t\t\t\treturn columns[index]._ColReorder_iOrigCol;\n\t\t\t\t} );\n\t\t}\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods (they are of course public in JS, but recommended as private)\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\t/**\n\t * Constructor logic\n\t *  @method  _fnConstruct\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnConstruct\": function ()\n\t{\n\t\tvar that = this;\n\t\tvar iLen = this.s.dt.aoColumns.length;\n\t\tvar table = this.s.dt.nTable;\n\t\tvar i;\n\n\t\t/* Columns discounted from reordering - counting left to right */\n\t\tif ( this.s.init.iFixedColumns )\n\t\t{\n\t\t\tthis.s.fixed = this.s.init.iFixedColumns;\n\t\t}\n\n\t\tif ( this.s.init.iFixedColumnsLeft )\n\t\t{\n\t\t\tthis.s.fixed = this.s.init.iFixedColumnsLeft;\n\t\t}\n\n\t\t/* Columns discounted from reordering - counting right to left */\n\t\tthis.s.fixedRight = this.s.init.iFixedColumnsRight ?\n\t\t\tthis.s.init.iFixedColumnsRight :\n\t\t\t0;\n\n\t\t/* Drop callback initialisation option */\n\t\tif ( this.s.init.fnReorderCallback )\n\t\t{\n\t\t\tthis.s.reorderCallback = this.s.init.fnReorderCallback;\n\t\t}\n\n\t\t/* Add event handlers for the drag and drop, and also mark the original column order */\n\t\tfor ( i = 0; i < iLen; i++ )\n\t\t{\n\t\t\tif ( i > this.s.fixed-1 && i < iLen - this.s.fixedRight )\n\t\t\t{\n\t\t\t\tthis._fnMouseListener( i, this.s.dt.aoColumns[i].nTh );\n\t\t\t}\n\n\t\t\t/* Mark the original column order for later reference */\n\t\t\tthis.s.dt.aoColumns[i]._ColReorder_iOrigCol = i;\n\t\t}\n\n\t\t/* State saving */\n\t\tthis.s.dt.oApi._fnCallbackReg( this.s.dt, 'aoStateSaveParams', function (oS, oData) {\n\t\t\tthat._fnStateSave.call( that, oData );\n\t\t}, \"ColReorder_State\" );\n\n\t\t/* An initial column order has been specified */\n\t\tvar aiOrder = null;\n\t\tif ( this.s.init.aiOrder )\n\t\t{\n\t\t\taiOrder = this.s.init.aiOrder.slice();\n\t\t}\n\n\t\t/* State loading, overrides the column order given */\n\t\tif ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' &&\n\t\t  this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length )\n\t\t{\n\t\t\taiOrder = this.s.dt.oLoadedState.ColReorder;\n\t\t}\n\n\t\t/* If we have an order to apply - do so */\n\t\tif ( aiOrder )\n\t\t{\n\t\t\t/* We might be called during or after the DataTables initialisation. If before, then we need\n\t\t\t * to wait until the draw is done, if after, then do what we need to do right away\n\t\t\t */\n\t\t\tif ( !that.s.dt._bInitComplete )\n\t\t\t{\n\t\t\t\tvar bDone = false;\n\t\t\t\t$(table).on( 'draw.dt.colReorder', function () {\n\t\t\t\t\tif ( !that.s.dt._bInitComplete && !bDone )\n\t\t\t\t\t{\n\t\t\t\t\t\tbDone = true;\n\t\t\t\t\t\tvar resort = fnInvertKeyValues( aiOrder );\n\t\t\t\t\t\tthat._fnOrderColumns.call( that, resort );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tvar resort = fnInvertKeyValues( aiOrder );\n\t\t\t\tthat._fnOrderColumns.call( that, resort );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tthis._fnSetColumnIndexes();\n\t\t}\n\n\t\t// Destroy clean up\n\t\t$(table).on( 'destroy.dt.colReorder', function () {\n\t\t\t$(table).off( 'destroy.dt.colReorder draw.dt.colReorder' );\n\n\t\t\t$.each( that.s.dt.aoColumns, function (i, column) {\n\t\t\t\t$(column.nTh).off('.ColReorder');\n\t\t\t\t$(column.nTh).removeAttr('data-column-index');\n\t\t\t} );\n\n\t\t\tthat.s.dt._colReorder = null;\n\t\t\tthat.s = null;\n\t\t} );\n\t},\n\n\n\t/**\n\t * Set the column order from an array\n\t *  @method  _fnOrderColumns\n\t *  @param   array a An array of integers which dictate the column order that should be applied\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnOrderColumns\": function ( a )\n\t{\n\t\tvar changed = false;\n\n\t\tif ( a.length != this.s.dt.aoColumns.length )\n\t\t{\n\t\t\tthis.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, \"ColReorder - array reorder does not \"+\n\t\t\t\t\"match known number of columns. Skipping.\" );\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar currIndex = $.inArray( i, a );\n\t\t\tif ( i != currIndex )\n\t\t\t{\n\t\t\t\t/* Reorder our switching array */\n\t\t\t\tfnArraySwitch( a, currIndex, i );\n\n\t\t\t\t/* Do the column reorder in the table */\n\t\t\t\tthis.s.dt.oInstance.fnColReorder( currIndex, i, true, false );\n\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\tthis._fnSetColumnIndexes();\n\n\t\t// Has anything actually changed? If not, then nothing else to do\n\t\tif ( ! changed ) {\n\t\t\treturn;\n\t\t}\n\n\t\t$.fn.dataTable.Api( this.s.dt ).rows().invalidate();\n\n\t\t/* When scrolling we need to recalculate the column sizes to allow for the shift */\n\t\tif ( this.s.dt.oScroll.sX !== \"\" || this.s.dt.oScroll.sY !== \"\" )\n\t\t{\n\t\t\tthis.s.dt.oInstance.fnAdjustColumnSizing( false );\n\t\t}\n\n\t\t/* Save the state */\n\t\tthis.s.dt.oInstance.oApi._fnSaveState( this.s.dt );\n\n\t\tif ( this.s.reorderCallback !== null )\n\t\t{\n\t\t\tthis.s.reorderCallback.call( this );\n\t\t}\n\t},\n\n\n\t/**\n\t * Because we change the indexes of columns in the table, relative to their starting point\n\t * we need to reorder the state columns to what they are at the starting point so we can\n\t * then rearrange them again on state load!\n\t *  @method  _fnStateSave\n\t *  @param   object oState DataTables state\n\t *  @returns string JSON encoded cookie string for DataTables\n\t *  @private\n\t */\n\t\"_fnStateSave\": function ( oState )\n\t{\n\t\tvar i, iLen, aCopy, iOrigColumn;\n\t\tvar oSettings = this.s.dt;\n\t\tvar columns = oSettings.aoColumns;\n\n\t\toState.ColReorder = [];\n\n\t\t/* Sorting */\n\t\tif ( oState.aaSorting ) {\n\t\t\t// 1.10.0-\n\t\t\tfor ( i=0 ; i<oState.aaSorting.length ; i++ ) {\n\t\t\t\toState.aaSorting[i][0] = columns[ oState.aaSorting[i][0] ]._ColReorder_iOrigCol;\n\t\t\t}\n\n\t\t\tvar aSearchCopy = $.extend( true, [], oState.aoSearchCols );\n\n\t\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tiOrigColumn = columns[i]._ColReorder_iOrigCol;\n\n\t\t\t\t/* Column filter */\n\t\t\t\toState.aoSearchCols[ iOrigColumn ] = aSearchCopy[i];\n\n\t\t\t\t/* Visibility */\n\t\t\t\toState.abVisCols[ iOrigColumn ] = columns[i].bVisible;\n\n\t\t\t\t/* Column reordering */\n\t\t\t\toState.ColReorder.push( iOrigColumn );\n\t\t\t}\n\t\t}\n\t\telse if ( oState.order ) {\n\t\t\t// 1.10.1+\n\t\t\tfor ( i=0 ; i<oState.order.length ; i++ ) {\n\t\t\t\toState.order[i][0] = columns[ oState.order[i][0] ]._ColReorder_iOrigCol;\n\t\t\t}\n\n\t\t\tvar stateColumnsCopy = $.extend( true, [], oState.columns );\n\n\t\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tiOrigColumn = columns[i]._ColReorder_iOrigCol;\n\n\t\t\t\t/* Columns */\n\t\t\t\toState.columns[ iOrigColumn ] = stateColumnsCopy[i];\n\n\t\t\t\t/* Column reordering */\n\t\t\t\toState.ColReorder.push( iOrigColumn );\n\t\t\t}\n\t\t}\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Mouse drop and drag\n\t */\n\n\t/**\n\t * Add a mouse down listener to a particluar TH element\n\t *  @method  _fnMouseListener\n\t *  @param   int i Column index\n\t *  @param   element nTh TH element clicked on\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnMouseListener\": function ( i, nTh )\n\t{\n\t\tvar that = this;\n\t\t$(nTh)\n\t\t\t.on( 'mousedown.ColReorder', function (e) {\n\t\t\t\tif ( that.s.enable ) {\n\t\t\t\t\tthat._fnMouseDown.call( that, e, nTh );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'touchstart.ColReorder', function (e) {\n\t\t\t\tif ( that.s.enable ) {\n\t\t\t\t\tthat._fnMouseDown.call( that, e, nTh );\n\t\t\t\t}\n\t\t\t} );\n\t},\n\n\n\t/**\n\t * Mouse down on a TH element in the table header\n\t *  @method  _fnMouseDown\n\t *  @param   event e Mouse event\n\t *  @param   element nTh TH element to be dragged\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnMouseDown\": function ( e, nTh )\n\t{\n\t\tvar that = this;\n\n\t\t/* Store information about the mouse position */\n\t\tvar target = $(e.target).closest('th, td');\n\t\tvar offset = target.offset();\n\t\tvar idx = parseInt( $(nTh).attr('data-column-index'), 10 );\n\n\t\tif ( idx === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.s.mouse.startX = this._fnCursorPosition( e, 'pageX' );\n\t\tthis.s.mouse.startY = this._fnCursorPosition( e, 'pageY' );\n\t\tthis.s.mouse.offsetX = this._fnCursorPosition( e, 'pageX' ) - offset.left;\n\t\tthis.s.mouse.offsetY = this._fnCursorPosition( e, 'pageY' ) - offset.top;\n\t\tthis.s.mouse.target = this.s.dt.aoColumns[ idx ].nTh;//target[0];\n\t\tthis.s.mouse.targetIndex = idx;\n\t\tthis.s.mouse.fromIndex = idx;\n\n\t\tthis._fnRegions();\n\n\t\t/* Add event handlers to the document */\n\t\t$(document)\n\t\t\t.on( 'mousemove.ColReorder touchmove.ColReorder', function (e) {\n\t\t\t\tthat._fnMouseMove.call( that, e );\n\t\t\t} )\n\t\t\t.on( 'mouseup.ColReorder touchend.ColReorder', function (e) {\n\t\t\t\tthat._fnMouseUp.call( that, e );\n\t\t\t} );\n\t},\n\n\n\t/**\n\t * Deal with a mouse move event while dragging a node\n\t *  @method  _fnMouseMove\n\t *  @param   event e Mouse event\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnMouseMove\": function ( e )\n\t{\n\t\tvar that = this;\n\n\t\tif ( this.dom.drag === null )\n\t\t{\n\t\t\t/* Only create the drag element if the mouse has moved a specific distance from the start\n\t\t\t * point - this allows the user to make small mouse movements when sorting and not have a\n\t\t\t * possibly confusing drag element showing up\n\t\t\t */\n\t\t\tif ( Math.pow(\n\t\t\t\tMath.pow(this._fnCursorPosition( e, 'pageX') - this.s.mouse.startX, 2) +\n\t\t\t\tMath.pow(this._fnCursorPosition( e, 'pageY') - this.s.mouse.startY, 2), 0.5 ) < 5 )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._fnCreateDragNode();\n\t\t}\n\n\t\t/* Position the element - we respect where in the element the click occured */\n\t\tthis.dom.drag.css( {\n\t\t\tleft: this._fnCursorPosition( e, 'pageX' ) - this.s.mouse.offsetX,\n\t\t\ttop: this._fnCursorPosition( e, 'pageY' ) - this.s.mouse.offsetY\n\t\t} );\n\n\t\t/* Based on the current mouse position, calculate where the insert should go */\n\t\tvar bSet = false;\n\t\tvar lastToIndex = this.s.mouse.toIndex;\n\n\t\tfor ( var i=1, iLen=this.s.aoTargets.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( this._fnCursorPosition(e, 'pageX') < this.s.aoTargets[i-1].x + ((this.s.aoTargets[i].x-this.s.aoTargets[i-1].x)/2) )\n\t\t\t{\n\t\t\t\tthis.dom.pointer.css( 'left', this.s.aoTargets[i-1].x );\n\t\t\t\tthis.s.mouse.toIndex = this.s.aoTargets[i-1].to;\n\t\t\t\tbSet = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// The insert element wasn't positioned in the array (less than\n\t\t// operator), so we put it at the end\n\t\tif ( !bSet )\n\t\t{\n\t\t\tthis.dom.pointer.css( 'left', this.s.aoTargets[this.s.aoTargets.length-1].x );\n\t\t\tthis.s.mouse.toIndex = this.s.aoTargets[this.s.aoTargets.length-1].to;\n\t\t}\n\n\t\t// Perform reordering if realtime updating is on and the column has moved\n\t\tif ( this.s.init.bRealtime && lastToIndex !== this.s.mouse.toIndex ) {\n\t\t\tthis.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex );\n\t\t\tthis.s.mouse.fromIndex = this.s.mouse.toIndex;\n\n\t\t\t// Not great for performance, but required to keep everything in alignment\n\t\t\tif ( this.s.dt.oScroll.sX !== \"\" || this.s.dt.oScroll.sY !== \"\" )\n\t\t\t{\n\t\t\t\tthis.s.dt.oInstance.fnAdjustColumnSizing( false );\n\t\t\t}\n\n\t\t\tthis._fnRegions();\n\t\t}\n\t},\n\n\n\t/**\n\t * Finish off the mouse drag and insert the column where needed\n\t *  @method  _fnMouseUp\n\t *  @param   event e Mouse event\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnMouseUp\": function ( e )\n\t{\n\t\tvar that = this;\n\n\t\t$(document).off( '.ColReorder' );\n\n\t\tif ( this.dom.drag !== null )\n\t\t{\n\t\t\t/* Remove the guide elements */\n\t\t\tthis.dom.drag.remove();\n\t\t\tthis.dom.pointer.remove();\n\t\t\tthis.dom.drag = null;\n\t\t\tthis.dom.pointer = null;\n\n\t\t\t/* Actually do the reorder */\n\t\t\tthis.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex, true );\n\t\t\tthis._fnSetColumnIndexes();\n\n\t\t\t/* When scrolling we need to recalculate the column sizes to allow for the shift */\n\t\t\tif ( this.s.dt.oScroll.sX !== \"\" || this.s.dt.oScroll.sY !== \"\" )\n\t\t\t{\n\t\t\t\tthis.s.dt.oInstance.fnAdjustColumnSizing( false );\n\t\t\t}\n\n\t\t\t/* Save the state */\n\t\t\tthis.s.dt.oInstance.oApi._fnSaveState( this.s.dt );\n\n\t\t\tif ( this.s.reorderCallback !== null )\n\t\t\t{\n\t\t\t\tthis.s.reorderCallback.call( this );\n\t\t\t}\n\t\t}\n\t},\n\n\n\t/**\n\t * Calculate a cached array with the points of the column inserts, and the\n\t * 'to' points\n\t *  @method  _fnRegions\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnRegions\": function ()\n\t{\n\t\tvar aoColumns = this.s.dt.aoColumns;\n\n\t\tthis.s.aoTargets.splice( 0, this.s.aoTargets.length );\n\n\t\tthis.s.aoTargets.push( {\n\t\t\t\"x\":  $(this.s.dt.nTable).offset().left,\n\t\t\t\"to\": 0\n\t\t} );\n\n\t\tvar iToPoint = 0;\n\t\tvar total = this.s.aoTargets[0].x;\n\n\t\tfor ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\t/* For the column / header in question, we want it's position to remain the same if the\n\t\t\t * position is just to it's immediate left or right, so we only increment the counter for\n\t\t\t * other columns\n\t\t\t */\n\t\t\tif ( i != this.s.mouse.fromIndex )\n\t\t\t{\n\t\t\t\tiToPoint++;\n\t\t\t}\n\n\t\t\tif ( aoColumns[i].bVisible && aoColumns[i].nTh.style.display !=='none' )\n\t\t\t{\n\t\t\t\ttotal += $(aoColumns[i].nTh).outerWidth();\n\n\t\t\t\tthis.s.aoTargets.push( {\n\t\t\t\t\t\"x\":  total,\n\t\t\t\t\t\"to\": iToPoint\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\n\t\t/* Disallow columns for being reordered by drag and drop, counting right to left */\n\t\tif ( this.s.fixedRight !== 0 )\n\t\t{\n\t\t\tthis.s.aoTargets.splice( this.s.aoTargets.length - this.s.fixedRight );\n\t\t}\n\n\t\t/* Disallow columns for being reordered by drag and drop, counting left to right */\n\t\tif ( this.s.fixed !== 0 )\n\t\t{\n\t\t\tthis.s.aoTargets.splice( 0, this.s.fixed );\n\t\t}\n\t},\n\n\n\t/**\n\t * Copy the TH element that is being drags so the user has the idea that they are actually\n\t * moving it around the page.\n\t *  @method  _fnCreateDragNode\n\t *  @returns void\n\t *  @private\n\t */\n\t\"_fnCreateDragNode\": function ()\n\t{\n\t\tvar scrolling = this.s.dt.oScroll.sX !== \"\" || this.s.dt.oScroll.sY !== \"\";\n\n\t\tvar origCell = this.s.dt.aoColumns[ this.s.mouse.targetIndex ].nTh;\n\t\tvar origTr = origCell.parentNode;\n\t\tvar origThead = origTr.parentNode;\n\t\tvar origTable = origThead.parentNode;\n\t\tvar cloneCell = $(origCell).clone();\n\n\t\t// This is a slightly odd combination of jQuery and DOM, but it is the\n\t\t// fastest and least resource intensive way I could think of cloning\n\t\t// the table with just a single header cell in it.\n\t\tthis.dom.drag = $(origTable.cloneNode(false))\n\t\t\t.addClass( 'DTCR_clonedTable' )\n\t\t\t.append(\n\t\t\t\t$(origThead.cloneNode(false)).append(\n\t\t\t\t\t$(origTr.cloneNode(false)).append(\n\t\t\t\t\t\tcloneCell[0]\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t\t\t.css( {\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0,\n\t\t\t\twidth: $(origCell).outerWidth(),\n\t\t\t\theight: $(origCell).outerHeight()\n\t\t\t} )\n\t\t\t.appendTo( 'body' );\n\n\t\tthis.dom.pointer = $('<div></div>')\n\t\t\t.addClass( 'DTCR_pointer' )\n\t\t\t.css( {\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttop: scrolling ?\n\t\t\t\t\t$('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top :\n\t\t\t\t\t$(this.s.dt.nTable).offset().top,\n\t\t\t\theight : scrolling ?\n\t\t\t\t\t$('div.dataTables_scroll', this.s.dt.nTableWrapper).height() :\n\t\t\t\t\t$(this.s.dt.nTable).height()\n\t\t\t} )\n\t\t\t.appendTo( 'body' );\n\t},\n\n\n\t/**\n\t * Add a data attribute to the column headers, so we know the index of\n\t * the row to be reordered. This allows fast detection of the index, and\n\t * for this plug-in to work with FixedHeader which clones the nodes.\n\t *  @private\n\t */\n\t\"_fnSetColumnIndexes\": function ()\n\t{\n\t\t$.each( this.s.dt.aoColumns, function (i, column) {\n\t\t\t$(column.nTh).attr('data-column-index', i);\n\t\t} );\n\t},\n\n\n\t/**\n\t * Get cursor position regardless of mouse or touch input\n\t * @param  {Event}  e    jQuery Event\n\t * @param  {string} prop Property to get\n\t * @return {number}      Value\n\t */\n\t_fnCursorPosition: function ( e, prop ) {\n\t\tif ( e.type.indexOf('touch') !== -1 ) {\n\t\t\treturn e.originalEvent.touches[0][ prop ];\n\t\t}\n\t\treturn e[ prop ];\n\t}\n} );\n\n\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Static parameters\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\n/**\n * ColReorder default settings for initialisation\n *  @namespace\n *  @static\n */\nColReorder.defaults = {\n\t/**\n\t * Predefined ordering for the columns that will be applied automatically\n\t * on initialisation. If not specified then the order that the columns are\n\t * found to be in the HTML is the order used.\n\t *  @type array\n\t *  @default null\n\t *  @static\n\t */\n\taiOrder: null,\n\n\t/**\n\t * ColReorder enable on initialisation\n\t *  @type boolean\n\t *  @default true\n\t *  @static\n\t */\n\tbEnable: true,\n\n\t/**\n\t * Redraw the table's column ordering as the end user draws the column\n\t * (`true`) or wait until the mouse is released (`false` - default). Note\n\t * that this will perform a redraw on each reordering, which involves an\n\t * Ajax request each time if you are using server-side processing in\n\t * DataTables.\n\t *  @type boolean\n\t *  @default false\n\t *  @static\n\t */\n\tbRealtime: true,\n\n\t/**\n\t * Indicate how many columns should be fixed in position (counting from the\n\t * left). This will typically be 1 if used, but can be as high as you like.\n\t *  @type int\n\t *  @default 0\n\t *  @static\n\t */\n\tiFixedColumnsLeft: 0,\n\n\t/**\n\t * As `iFixedColumnsRight` but counting from the right.\n\t *  @type int\n\t *  @default 0\n\t *  @static\n\t */\n\tiFixedColumnsRight: 0,\n\n\t/**\n\t * Callback function that is fired when columns are reordered. The `column-\n\t * reorder` event is preferred over this callback\n\t *  @type function():void\n\t *  @default null\n\t *  @static\n\t */\n\tfnReorderCallback: null\n};\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Constants\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n/**\n * ColReorder version\n *  @constant  version\n *  @type      String\n *  @default   As code\n */\nColReorder.version = \"1.5.0\";\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables interfaces\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n// Expose\n$.fn.dataTable.ColReorder = ColReorder;\n$.fn.DataTable.ColReorder = ColReorder;\n\n\n// Register a new feature with DataTables\nif ( typeof $.fn.dataTable == \"function\" &&\n     typeof $.fn.dataTableExt.fnVersionCheck == \"function\" &&\n     $.fn.dataTableExt.fnVersionCheck('1.10.8') )\n{\n\t$.fn.dataTableExt.aoFeatures.push( {\n\t\t\"fnInit\": function( settings ) {\n\t\t\tvar table = settings.oInstance;\n\n\t\t\tif ( ! settings._colReorder ) {\n\t\t\t\tvar dtInit = settings.oInit;\n\t\t\t\tvar opts = dtInit.colReorder || dtInit.oColReorder || {};\n\n\t\t\t\tnew ColReorder( settings, opts );\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttable.oApi._fnLog( settings, 1, \"ColReorder attempted to initialise twice. Ignoring second\" );\n\t\t\t}\n\n\t\t\treturn null; /* No node for DataTables to insert */\n\t\t},\n\t\t\"cFeature\": \"R\",\n\t\t\"sFeature\": \"ColReorder\"\n\t} );\n}\nelse {\n\talert( \"Warning: ColReorder requires DataTables 1.10.8 or greater - www.datatables.net/download\");\n}\n\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'preInit.dt.colReorder', function (e, settings) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.colReorder;\n\tvar defaults = DataTable.defaults.colReorder;\n\n\tif ( init || defaults ) {\n\t\tvar opts = $.extend( {}, init, defaults );\n\n\t\tif ( init !== false ) {\n\t\t\tnew ColReorder( settings, opts  );\n\t\t}\n\t}\n} );\n\n\n// API augmentation\n$.fn.dataTable.Api.register( 'colReorder.reset()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tctx._colReorder.fnReset();\n\t} );\n} );\n\n$.fn.dataTable.Api.register( 'colReorder.order()', function ( set, original ) {\n\tif ( set ) {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\tctx._colReorder.fnOrder( set, original );\n\t\t} );\n\t}\n\n\treturn this.context.length ?\n\t\tthis.context[0]._colReorder.fnOrder() :\n\t\tnull;\n} );\n\n$.fn.dataTable.Api.register( 'colReorder.transpose()', function ( idx, dir ) {\n\treturn this.context.length && this.context[0]._colReorder ?\n\t\tthis.context[0]._colReorder.fnTranspose( idx, dir ) :\n\t\tidx;\n} );\n\n$.fn.dataTable.Api.register( 'colReorder.move()', function( from, to, drop, invalidateRows ) {\n\tif (this.context.length) {\n\t\tthis.context[0]._colReorder.s.dt.oInstance.fnColReorder( from, to, drop, invalidateRows );\n\t}\n\treturn this;\n} );\n\n$.fn.dataTable.Api.register( 'colReorder.enable()', function( flag ) {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx._colReorder ) {\n\t\t\tctx._colReorder.fnEnable( flag );\n\t\t}\n\t} );\n} );\n\n$.fn.dataTable.Api.register( 'colReorder.disable()', function() {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx._colReorder ) {\n\t\t\tctx._colReorder.fnDisable();\n\t\t}\n\t} );\n} );\n\n\nreturn ColReorder;\n}));\n\n\n/*! FixedColumns 3.2.5\n * ©2010-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     FixedColumns\n * @description Freeze columns in place on a scrolling DataTable\n * @version     3.2.5\n * @file        dataTables.fixedColumns.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2010-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\nvar _firefoxScroll;\n\n/**\n * When making use of DataTables' x-axis scrolling feature, you may wish to\n * fix the left most column in place. This plug-in for DataTables provides\n * exactly this option (note for non-scrolling tables, please use the\n * FixedHeader plug-in, which can fix headers and footers). Key\n * features include:\n *\n * * Freezes the left or right most columns to the side of the table\n * * Option to freeze two or more columns\n * * Full integration with DataTables' scrolling options\n * * Speed - FixedColumns is fast in its operation\n *\n *  @class\n *  @constructor\n *  @global\n *  @param {object} dt DataTables instance. With DataTables 1.10 this can also\n *    be a jQuery collection, a jQuery selector, DataTables API instance or\n *    settings object.\n *  @param {object} [init={}] Configuration object for FixedColumns. Options are\n *    defined by {@link FixedColumns.defaults}\n *\n *  @requires jQuery 1.7+\n *  @requires DataTables 1.8.0+\n *\n *  @example\n *      var table = $('#example').dataTable( {\n *        \"scrollX\": \"100%\"\n *      } );\n *      new $.fn.dataTable.fixedColumns( table );\n */\nvar FixedColumns = function ( dt, init ) {\n\tvar that = this;\n\n\t/* Sanity check - you just know it will happen */\n\tif ( ! ( this instanceof FixedColumns ) ) {\n\t\talert( \"FixedColumns warning: FixedColumns must be initialised with the 'new' keyword.\" );\n\t\treturn;\n\t}\n\n\tif ( init === undefined || init === true ) {\n\t\tinit = {};\n\t}\n\n\t// Use the DataTables Hungarian notation mapping method, if it exists to\n\t// provide forwards compatibility for camel case variables\n\tvar camelToHungarian = $.fn.dataTable.camelToHungarian;\n\tif ( camelToHungarian ) {\n\t\tcamelToHungarian( FixedColumns.defaults, FixedColumns.defaults, true );\n\t\tcamelToHungarian( FixedColumns.defaults, init );\n\t}\n\n\t// v1.10 allows the settings object to be got form a number of sources\n\tvar dtSettings = new $.fn.dataTable.Api( dt ).settings()[0];\n\n\t/**\n\t * Settings object which contains customisable information for FixedColumns instance\n\t * @namespace\n\t * @extends FixedColumns.defaults\n\t * @private\n\t */\n\tthis.s = {\n\t\t/**\n\t\t * DataTables settings objects\n\t\t *  @type     object\n\t\t *  @default  Obtained from DataTables instance\n\t\t */\n\t\t\"dt\": dtSettings,\n\n\t\t/**\n\t\t * Number of columns in the DataTable - stored for quick access\n\t\t *  @type     int\n\t\t *  @default  Obtained from DataTables instance\n\t\t */\n\t\t\"iTableColumns\": dtSettings.aoColumns.length,\n\n\t\t/**\n\t\t * Original outer widths of the columns as rendered by DataTables - used to calculate\n\t\t * the FixedColumns grid bounding box\n\t\t *  @type     array.<int>\n\t\t *  @default  []\n\t\t */\n\t\t\"aiOuterWidths\": [],\n\n\t\t/**\n\t\t * Original inner widths of the columns as rendered by DataTables - used to apply widths\n\t\t * to the columns\n\t\t *  @type     array.<int>\n\t\t *  @default  []\n\t\t */\n\t\t\"aiInnerWidths\": [],\n\n\n\t\t/**\n\t\t * Is the document layout right-to-left\n\t\t * @type boolean\n\t\t */\n\t\trtl: $(dtSettings.nTable).css('direction') === 'rtl'\n\t};\n\n\n\t/**\n\t * DOM elements used by the class instance\n\t * @namespace\n\t * @private\n\t *\n\t */\n\tthis.dom = {\n\t\t/**\n\t\t * DataTables scrolling element\n\t\t *  @type     node\n\t\t *  @default  null\n\t\t */\n\t\t\"scroller\": null,\n\n\t\t/**\n\t\t * DataTables header table\n\t\t *  @type     node\n\t\t *  @default  null\n\t\t */\n\t\t\"header\": null,\n\n\t\t/**\n\t\t * DataTables body table\n\t\t *  @type     node\n\t\t *  @default  null\n\t\t */\n\t\t\"body\": null,\n\n\t\t/**\n\t\t * DataTables footer table\n\t\t *  @type     node\n\t\t *  @default  null\n\t\t */\n\t\t\"footer\": null,\n\n\t\t/**\n\t\t * Display grid elements\n\t\t * @namespace\n\t\t */\n\t\t\"grid\": {\n\t\t\t/**\n\t\t\t * Grid wrapper. This is the container element for the 3x3 grid\n\t\t\t *  @type     node\n\t\t\t *  @default  null\n\t\t\t */\n\t\t\t\"wrapper\": null,\n\n\t\t\t/**\n\t\t\t * DataTables scrolling element. This element is the DataTables\n\t\t\t * component in the display grid (making up the main table - i.e.\n\t\t\t * not the fixed columns).\n\t\t\t *  @type     node\n\t\t\t *  @default  null\n\t\t\t */\n\t\t\t\"dt\": null,\n\n\t\t\t/**\n\t\t\t * Left fixed column grid components\n\t\t\t * @namespace\n\t\t\t */\n\t\t\t\"left\": {\n\t\t\t\t\"wrapper\": null,\n\t\t\t\t\"head\": null,\n\t\t\t\t\"body\": null,\n\t\t\t\t\"foot\": null\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Right fixed column grid components\n\t\t\t * @namespace\n\t\t\t */\n\t\t\t\"right\": {\n\t\t\t\t\"wrapper\": null,\n\t\t\t\t\"head\": null,\n\t\t\t\t\"body\": null,\n\t\t\t\t\"foot\": null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Cloned table nodes\n\t\t * @namespace\n\t\t */\n\t\t\"clone\": {\n\t\t\t/**\n\t\t\t * Left column cloned table nodes\n\t\t\t * @namespace\n\t\t\t */\n\t\t\t\"left\": {\n\t\t\t\t/**\n\t\t\t\t * Cloned header table\n\t\t\t\t *  @type     node\n\t\t\t\t *  @default  null\n\t\t\t\t */\n\t\t\t\t\"header\": null,\n\n\t\t\t\t/**\n\t\t\t\t * Cloned body table\n\t\t\t\t *  @type     node\n\t\t\t\t *  @default  null\n\t\t\t\t */\n\t\t\t\t\"body\": null,\n\n\t\t\t\t/**\n\t\t\t\t * Cloned footer table\n\t\t\t\t *  @type     node\n\t\t\t\t *  @default  null\n\t\t\t\t */\n\t\t\t\t\"footer\": null\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Right column cloned table nodes\n\t\t\t * @namespace\n\t\t\t */\n\t\t\t\"right\": {\n\t\t\t\t/**\n\t\t\t\t * Cloned header table\n\t\t\t\t *  @type     node\n\t\t\t\t *  @default  null\n\t\t\t\t */\n\t\t\t\t\"header\": null,\n\n\t\t\t\t/**\n\t\t\t\t * Cloned body table\n\t\t\t\t *  @type     node\n\t\t\t\t *  @default  null\n\t\t\t\t */\n\t\t\t\t\"body\": null,\n\n\t\t\t\t/**\n\t\t\t\t * Cloned footer table\n\t\t\t\t *  @type     node\n\t\t\t\t *  @default  null\n\t\t\t\t */\n\t\t\t\t\"footer\": null\n\t\t\t}\n\t\t}\n\t};\n\n\tif ( dtSettings._oFixedColumns ) {\n\t\tthrow 'FixedColumns already initialised on this table';\n\t}\n\n\t/* Attach the instance to the DataTables instance so it can be accessed easily */\n\tdtSettings._oFixedColumns = this;\n\n\t/* Let's do it */\n\tif ( ! dtSettings._bInitComplete )\n\t{\n\t\tdtSettings.oApi._fnCallbackReg( dtSettings, 'aoInitComplete', function () {\n\t\t\tthat._fnConstruct( init );\n\t\t}, 'FixedColumns' );\n\t}\n\telse\n\t{\n\t\tthis._fnConstruct( init );\n\t}\n};\n\n\n\n$.extend( FixedColumns.prototype , {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Public methods\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\t/**\n\t * Update the fixed columns - including headers and footers. Note that FixedColumns will\n\t * automatically update the display whenever the host DataTable redraws.\n\t *  @returns {void}\n\t *  @example\n\t *      var table = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      var fc = new $.fn.dataTable.fixedColumns( table );\n\t *\n\t *      // at some later point when the table has been manipulated....\n\t *      fc.fnUpdate();\n\t */\n\t\"fnUpdate\": function ()\n\t{\n\t\tthis._fnDraw( true );\n\t},\n\n\n\t/**\n\t * Recalculate the resizes of the 3x3 grid that FixedColumns uses for display of the table.\n\t * This is useful if you update the width of the table container. Note that FixedColumns will\n\t * perform this function automatically when the window.resize event is fired.\n\t *  @returns {void}\n\t *  @example\n\t *      var table = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      var fc = new $.fn.dataTable.fixedColumns( table );\n\t *\n\t *      // Resize the table container and then have FixedColumns adjust its layout....\n\t *      $('#content').width( 1200 );\n\t *      fc.fnRedrawLayout();\n\t */\n\t\"fnRedrawLayout\": function ()\n\t{\n\t\tthis._fnColCalc();\n\t\tthis._fnGridLayout();\n\t\tthis.fnUpdate();\n\t},\n\n\n\t/**\n\t * Mark a row such that it's height should be recalculated when using 'semiauto' row\n\t * height matching. This function will have no effect when 'none' or 'auto' row height\n\t * matching is used.\n\t *  @param   {Node} nTr TR element that should have it's height recalculated\n\t *  @returns {void}\n\t *  @example\n\t *      var table = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      var fc = new $.fn.dataTable.fixedColumns( table );\n\t *\n\t *      // manipulate the table - mark the row as needing an update then update the table\n\t *      // this allows the redraw performed by DataTables fnUpdate to recalculate the row\n\t *      // height\n\t *      fc.fnRecalculateHeight();\n\t *      table.fnUpdate( $('#example tbody tr:eq(0)')[0], [\"insert date\", 1, 2, 3 ... ]);\n\t */\n\t\"fnRecalculateHeight\": function ( nTr )\n\t{\n\t\tdelete nTr._DTTC_iHeight;\n\t\tnTr.style.height = 'auto';\n\t},\n\n\n\t/**\n\t * Set the height of a given row - provides cross browser compatibility\n\t *  @param   {Node} nTarget TR element that should have it's height recalculated\n\t *  @param   {int} iHeight Height in pixels to set\n\t *  @returns {void}\n\t *  @example\n\t *      var table = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      var fc = new $.fn.dataTable.fixedColumns( table );\n\t *\n\t *      // You may want to do this after manipulating a row in the fixed column\n\t *      fc.fnSetRowHeight( $('#example tbody tr:eq(0)')[0], 50 );\n\t */\n\t\"fnSetRowHeight\": function ( nTarget, iHeight )\n\t{\n\t\tnTarget.style.height = iHeight+\"px\";\n\t},\n\n\n\t/**\n\t * Get data index information about a row or cell in the table body.\n\t * This function is functionally identical to fnGetPosition in DataTables,\n\t * taking the same parameter (TH, TD or TR node) and returning exactly the\n\t * the same information (data index information). THe difference between\n\t * the two is that this method takes into account the fixed columns in the\n\t * table, so you can pass in nodes from the master table, or the cloned\n\t * tables and get the index position for the data in the main table.\n\t *  @param {node} node TR, TH or TD element to get the information about\n\t *  @returns {int} If nNode is given as a TR, then a single index is \n\t *    returned, or if given as a cell, an array of [row index, column index\n\t *    (visible), column index (all)] is given.\n\t */\n\t\"fnGetPosition\": function ( node )\n\t{\n\t\tvar idx;\n\t\tvar inst = this.s.dt.oInstance;\n\n\t\tif ( ! $(node).parents('.DTFC_Cloned').length )\n\t\t{\n\t\t\t// Not in a cloned table\n\t\t\treturn inst.fnGetPosition( node );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Its in the cloned table, so need to look up position\n\t\t\tif ( node.nodeName.toLowerCase() === 'tr' ) {\n\t\t\t\tidx = $(node).index();\n\t\t\t\treturn inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tvar colIdx = $(node).index();\n\t\t\t\tidx = $(node.parentNode).index();\n\t\t\t\tvar row = inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );\n\n\t\t\t\treturn [\n\t\t\t\t\trow,\n\t\t\t\t\tcolIdx,\n\t\t\t\t\tinst.oApi._fnVisibleToColumnIndex( this.s.dt, colIdx )\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\t},\n\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods (they are of course public in JS, but recommended as private)\n\t * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\t/**\n\t * Initialisation for FixedColumns\n\t *  @param   {Object} oInit User settings for initialisation\n\t *  @returns {void}\n\t *  @private\n\t */\n\t\"_fnConstruct\": function ( oInit )\n\t{\n\t\tvar i, iLen, iWidth,\n\t\t\tthat = this;\n\n\t\t/* Sanity checking */\n\t\tif ( typeof this.s.dt.oInstance.fnVersionCheck != 'function' ||\n\t\t     this.s.dt.oInstance.fnVersionCheck( '1.8.0' ) !== true )\n\t\t{\n\t\t\talert( \"FixedColumns \"+FixedColumns.VERSION+\" required DataTables 1.8.0 or later. \"+\n\t\t\t\t\"Please upgrade your DataTables installation\" );\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this.s.dt.oScroll.sX === \"\" )\n\t\t{\n\t\t\tthis.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, \"FixedColumns is not needed (no \"+\n\t\t\t\t\"x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for \"+\n\t\t\t\t\"column fixing when scrolling is not enabled\" );\n\t\t\treturn;\n\t\t}\n\n\t\t/* Apply the settings from the user / defaults */\n\t\tthis.s = $.extend( true, this.s, FixedColumns.defaults, oInit );\n\n\t\t/* Set up the DOM as we need it and cache nodes */\n\t\tvar classes = this.s.dt.oClasses;\n\t\tthis.dom.grid.dt = $(this.s.dt.nTable).parents('div.'+classes.sScrollWrapper)[0];\n\t\tthis.dom.scroller = $('div.'+classes.sScrollBody, this.dom.grid.dt )[0];\n\n\t\t/* Set up the DOM that we want for the fixed column layout grid */\n\t\tthis._fnColCalc();\n\t\tthis._fnGridSetup();\n\n\t\t/* Event handlers */\n\t\tvar mouseController;\n\t\tvar mouseDown = false;\n\n\t\t// When the mouse is down (drag scroll) the mouse controller cannot\n\t\t// change, as the browser keeps the original element as the scrolling one\n\t\t$(this.s.dt.nTableWrapper).on( 'mousedown.DTFC', function (e) {\n\t\t\tif ( e.button === 0 ) {\n\t\t\t\tmouseDown = true;\n\n\t\t\t\t$(document).one( 'mouseup', function () {\n\t\t\t\t\tmouseDown = false;\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\t// When the body is scrolled - scroll the left and right columns\n\t\t$(this.dom.scroller)\n\t\t\t.on( 'mouseover.DTFC touchstart.DTFC', function () {\n\t\t\t\tif ( ! mouseDown ) {\n\t\t\t\t\tmouseController = 'main';\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'scroll.DTFC', function (e) {\n\t\t\t\tif ( ! mouseController && e.originalEvent ) {\n\t\t\t\t\tmouseController = 'main';\n\t\t\t\t}\n\n\t\t\t\tif ( mouseController === 'main' ) {\n\t\t\t\t\tif ( that.s.iLeftColumns > 0 ) {\n\t\t\t\t\t\tthat.dom.grid.left.liner.scrollTop = that.dom.scroller.scrollTop;\n\t\t\t\t\t}\n\t\t\t\t\tif ( that.s.iRightColumns > 0 ) {\n\t\t\t\t\t\tthat.dom.grid.right.liner.scrollTop = that.dom.scroller.scrollTop;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\n\t\tvar wheelType = 'onwheel' in document.createElement('div') ?\n\t\t\t'wheel.DTFC' :\n\t\t\t'mousewheel.DTFC';\n\n\t\tif ( that.s.iLeftColumns > 0 ) {\n\t\t\t// When scrolling the left column, scroll the body and right column\n\t\t\t$(that.dom.grid.left.liner)\n\t\t\t\t.on( 'mouseover.DTFC touchstart.DTFC', function () {\n\t\t\t\t\tif ( ! mouseDown ) {\n\t\t\t\t\t\tmouseController = 'left';\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t\t.on( 'scroll.DTFC', function ( e ) {\n\t\t\t\t\tif ( ! mouseController && e.originalEvent ) {\n\t\t\t\t\t\tmouseController = 'left';\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( mouseController === 'left' ) {\n\t\t\t\t\t\tthat.dom.scroller.scrollTop = that.dom.grid.left.liner.scrollTop;\n\t\t\t\t\t\tif ( that.s.iRightColumns > 0 ) {\n\t\t\t\t\t\t\tthat.dom.grid.right.liner.scrollTop = that.dom.grid.left.liner.scrollTop;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t\t.on( wheelType, function(e) {\n\t\t\t\t\t// Pass horizontal scrolling through\n\t\t\t\t\tvar xDelta = e.type === 'wheel' ?\n\t\t\t\t\t\t-e.originalEvent.deltaX :\n\t\t\t\t\t\te.originalEvent.wheelDeltaX;\n\t\t\t\t\tthat.dom.scroller.scrollLeft -= xDelta;\n\t\t\t\t} );\n\t\t}\n\n\t\tif ( that.s.iRightColumns > 0 ) {\n\t\t\t// When scrolling the right column, scroll the body and the left column\n\t\t\t$(that.dom.grid.right.liner)\n\t\t\t\t.on( 'mouseover.DTFC touchstart.DTFC', function () {\n\t\t\t\t\tif ( ! mouseDown ) {\n\t\t\t\t\t\tmouseController = 'right';\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t\t.on( 'scroll.DTFC', function ( e ) {\n\t\t\t\t\tif ( ! mouseController && e.originalEvent ) {\n\t\t\t\t\t\tmouseController = 'right';\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( mouseController === 'right' ) {\n\t\t\t\t\t\tthat.dom.scroller.scrollTop = that.dom.grid.right.liner.scrollTop;\n\t\t\t\t\t\tif ( that.s.iLeftColumns > 0 ) {\n\t\t\t\t\t\t\tthat.dom.grid.left.liner.scrollTop = that.dom.grid.right.liner.scrollTop;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t\t.on( wheelType, function(e) {\n\t\t\t\t\t// Pass horizontal scrolling through\n\t\t\t\t\tvar xDelta = e.type === 'wheel' ?\n\t\t\t\t\t\t-e.originalEvent.deltaX :\n\t\t\t\t\t\te.originalEvent.wheelDeltaX;\n\t\t\t\t\tthat.dom.scroller.scrollLeft -= xDelta;\n\t\t\t\t} );\n\t\t}\n\n\t\t$(window).on( 'resize.DTFC', function () {\n\t\t\tthat._fnGridLayout.call( that );\n\t\t} );\n\n\t\tvar bFirstDraw = true;\n\t\tvar jqTable = $(this.s.dt.nTable);\n\n\t\tjqTable\n\t\t\t.on( 'draw.dt.DTFC', function () {\n\t\t\t\tthat._fnColCalc();\n\t\t\t\tthat._fnDraw.call( that, bFirstDraw );\n\t\t\t\tbFirstDraw = false;\n\t\t\t} )\n\t\t\t.on( 'column-sizing.dt.DTFC', function () {\n\t\t\t\tthat._fnColCalc();\n\t\t\t\tthat._fnGridLayout( that );\n\t\t\t} )\n\t\t\t.on( 'column-visibility.dt.DTFC', function ( e, settings, column, vis, recalc ) {\n\t\t\t\tif ( recalc === undefined || recalc ) {\n\t\t\t\t\tthat._fnColCalc();\n\t\t\t\t\tthat._fnGridLayout( that );\n\t\t\t\t\tthat._fnDraw( true );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'select.dt.DTFC deselect.dt.DTFC', function ( e, dt, type, indexes ) {\n\t\t\t\tif ( e.namespace === 'dt' ) {\n\t\t\t\t\tthat._fnDraw( false );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.on( 'destroy.dt.DTFC', function () {\n\t\t\t\tjqTable.off( '.DTFC' );\n\n\t\t\t\t$(that.dom.scroller).off( '.DTFC' );\n\t\t\t\t$(window).off( '.DTFC' );\n\t\t\t\t$(that.s.dt.nTableWrapper).off( '.DTFC' );\n\n\t\t\t\t$(that.dom.grid.left.liner).off( '.DTFC '+wheelType );\n\t\t\t\t$(that.dom.grid.left.wrapper).remove();\n\n\t\t\t\t$(that.dom.grid.right.liner).off( '.DTFC '+wheelType );\n\t\t\t\t$(that.dom.grid.right.wrapper).remove();\n\t\t\t} );\n\n\t\t/* Get things right to start with - note that due to adjusting the columns, there must be\n\t\t * another redraw of the main table. It doesn't need to be a full redraw however.\n\t\t */\n\t\tthis._fnGridLayout();\n\t\tthis.s.dt.oInstance.fnDraw(false);\n\t},\n\n\n\t/**\n\t * Calculate the column widths for the grid layout\n\t *  @returns {void}\n\t *  @private\n\t */\n\t\"_fnColCalc\": function ()\n\t{\n\t\tvar that = this;\n\t\tvar iLeftWidth = 0;\n\t\tvar iRightWidth = 0;\n\n\t\tthis.s.aiInnerWidths = [];\n\t\tthis.s.aiOuterWidths = [];\n\n\t\t$.each( this.s.dt.aoColumns, function (i, col) {\n\t\t\tvar th = $(col.nTh);\n\t\t\tvar border;\n\n\t\t\tif ( ! th.filter(':visible').length ) {\n\t\t\t\tthat.s.aiInnerWidths.push( 0 );\n\t\t\t\tthat.s.aiOuterWidths.push( 0 );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Inner width is used to assign widths to cells\n\t\t\t\t// Outer width is used to calculate the container\n\t\t\t\tvar iWidth = th.outerWidth();\n\n\t\t\t\t// When working with the left most-cell, need to add on the\n\t\t\t\t// table's border to the outerWidth, since we need to take\n\t\t\t\t// account of it, but it isn't in any cell\n\t\t\t\tif ( that.s.aiOuterWidths.length === 0 ) {\n\t\t\t\t\tborder = $(that.s.dt.nTable).css('border-left-width');\n\t\t\t\t\tiWidth += typeof border === 'string' && border.indexOf('px') === -1 ?\n\t\t\t\t\t\t1 :\n\t\t\t\t\t\tparseInt( border, 10 );\n\t\t\t\t}\n\n\t\t\t\t// Likewise with the final column on the right\n\t\t\t\tif ( that.s.aiOuterWidths.length === that.s.dt.aoColumns.length-1 ) {\n\t\t\t\t\tborder = $(that.s.dt.nTable).css('border-right-width');\n\t\t\t\t\tiWidth += typeof border === 'string' && border.indexOf('px') === -1 ?\n\t\t\t\t\t\t1 :\n\t\t\t\t\t\tparseInt( border, 10 );\n\t\t\t\t}\n\n\t\t\t\tthat.s.aiOuterWidths.push( iWidth );\n\t\t\t\tthat.s.aiInnerWidths.push( th.width() );\n\n\t\t\t\tif ( i < that.s.iLeftColumns )\n\t\t\t\t{\n\t\t\t\t\tiLeftWidth += iWidth;\n\t\t\t\t}\n\n\t\t\t\tif ( that.s.iTableColumns-that.s.iRightColumns <= i )\n\t\t\t\t{\n\t\t\t\t\tiRightWidth += iWidth;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\tthis.s.iLeftWidth = iLeftWidth;\n\t\tthis.s.iRightWidth = iRightWidth;\n\t},\n\n\n\t/**\n\t * Set up the DOM for the fixed column. The way the layout works is to create a 1x3 grid\n\t * for the left column, the DataTable (for which we just reuse the scrolling element DataTable\n\t * puts into the DOM) and the right column. In each of he two fixed column elements there is a\n\t * grouping wrapper element and then a head, body and footer wrapper. In each of these we then\n\t * place the cloned header, body or footer tables. This effectively gives as 3x3 grid structure.\n\t *  @returns {void}\n\t *  @private\n\t */\n\t\"_fnGridSetup\": function ()\n\t{\n\t\tvar that = this;\n\t\tvar oOverflow = this._fnDTOverflow();\n\t\tvar block;\n\n\t\tthis.dom.body = this.s.dt.nTable;\n\t\tthis.dom.header = this.s.dt.nTHead.parentNode;\n\t\tthis.dom.header.parentNode.parentNode.style.position = \"relative\";\n\n\t\tvar nSWrapper =\n\t\t\t$('<div class=\"DTFC_ScrollWrapper\" style=\"position:relative; clear:both;\">'+\n\t\t\t\t'<div class=\"DTFC_LeftWrapper\" style=\"position:absolute; top:0; left:0;\" aria-hidden=\"true\">'+\n\t\t\t\t\t'<div class=\"DTFC_LeftHeadWrapper\" style=\"position:relative; top:0; left:0; overflow:hidden;\"></div>'+\n\t\t\t\t\t'<div class=\"DTFC_LeftBodyWrapper\" style=\"position:relative; top:0; left:0; overflow:hidden;\">'+\n\t\t\t\t\t\t'<div class=\"DTFC_LeftBodyLiner\" style=\"position:relative; top:0; left:0; overflow-y:scroll;\"></div>'+\n\t\t\t\t\t'</div>'+\n\t\t\t\t\t'<div class=\"DTFC_LeftFootWrapper\" style=\"position:relative; top:0; left:0; overflow:hidden;\"></div>'+\n\t\t\t\t'</div>'+\n\t\t\t\t'<div class=\"DTFC_RightWrapper\" style=\"position:absolute; top:0; right:0;\" aria-hidden=\"true\">'+\n\t\t\t\t\t'<div class=\"DTFC_RightHeadWrapper\" style=\"position:relative; top:0; left:0;\">'+\n\t\t\t\t\t\t'<div class=\"DTFC_RightHeadBlocker DTFC_Blocker\" style=\"position:absolute; top:0; bottom:0;\"></div>'+\n\t\t\t\t\t'</div>'+\n\t\t\t\t\t'<div class=\"DTFC_RightBodyWrapper\" style=\"position:relative; top:0; left:0; overflow:hidden;\">'+\n\t\t\t\t\t\t'<div class=\"DTFC_RightBodyLiner\" style=\"position:relative; top:0; left:0; overflow-y:scroll;\"></div>'+\n\t\t\t\t\t'</div>'+\n\t\t\t\t\t'<div class=\"DTFC_RightFootWrapper\" style=\"position:relative; top:0; left:0;\">'+\n\t\t\t\t\t\t'<div class=\"DTFC_RightFootBlocker DTFC_Blocker\" style=\"position:absolute; top:0; bottom:0;\"></div>'+\n\t\t\t\t\t'</div>'+\n\t\t\t\t'</div>'+\n\t\t\t'</div>')[0];\n\t\tvar nLeft = nSWrapper.childNodes[0];\n\t\tvar nRight = nSWrapper.childNodes[1];\n\n\t\tthis.dom.grid.dt.parentNode.insertBefore( nSWrapper, this.dom.grid.dt );\n\t\tnSWrapper.appendChild( this.dom.grid.dt );\n\n\t\tthis.dom.grid.wrapper = nSWrapper;\n\n\t\tif ( this.s.iLeftColumns > 0 )\n\t\t{\n\t\t\tthis.dom.grid.left.wrapper = nLeft;\n\t\t\tthis.dom.grid.left.head = nLeft.childNodes[0];\n\t\t\tthis.dom.grid.left.body = nLeft.childNodes[1];\n\t\t\tthis.dom.grid.left.liner = $('div.DTFC_LeftBodyLiner', nSWrapper)[0];\n\n\t\t\tnSWrapper.appendChild( nLeft );\n\t\t}\n\n\t\tif ( this.s.iRightColumns > 0 )\n\t\t{\n\t\t\tthis.dom.grid.right.wrapper = nRight;\n\t\t\tthis.dom.grid.right.head = nRight.childNodes[0];\n\t\t\tthis.dom.grid.right.body = nRight.childNodes[1];\n\t\t\tthis.dom.grid.right.liner = $('div.DTFC_RightBodyLiner', nSWrapper)[0];\n\n\t\t\tnRight.style.right = oOverflow.bar+\"px\";\n\n\t\t\tblock = $('div.DTFC_RightHeadBlocker', nSWrapper)[0];\n\t\t\tblock.style.width = oOverflow.bar+\"px\";\n\t\t\tblock.style.right = -oOverflow.bar+\"px\";\n\t\t\tthis.dom.grid.right.headBlock = block;\n\n\t\t\tblock = $('div.DTFC_RightFootBlocker', nSWrapper)[0];\n\t\t\tblock.style.width = oOverflow.bar+\"px\";\n\t\t\tblock.style.right = -oOverflow.bar+\"px\";\n\t\t\tthis.dom.grid.right.footBlock = block;\n\n\t\t\tnSWrapper.appendChild( nRight );\n\t\t}\n\n\t\tif ( this.s.dt.nTFoot )\n\t\t{\n\t\t\tthis.dom.footer = this.s.dt.nTFoot.parentNode;\n\t\t\tif ( this.s.iLeftColumns > 0 )\n\t\t\t{\n\t\t\t\tthis.dom.grid.left.foot = nLeft.childNodes[2];\n\t\t\t}\n\t\t\tif ( this.s.iRightColumns > 0 )\n\t\t\t{\n\t\t\t\tthis.dom.grid.right.foot = nRight.childNodes[2];\n\t\t\t}\n\t\t}\n\n\t\t// RTL support - swap the position of the left and right columns (#48)\n\t\tif ( this.s.rtl ) {\n\t\t\t$('div.DTFC_RightHeadBlocker', nSWrapper).css( {\n\t\t\t\tleft: -oOverflow.bar+'px',\n\t\t\t\tright: ''\n\t\t\t} );\n\t\t}\n\t},\n\n\n\t/**\n\t * Style and position the grid used for the FixedColumns layout\n\t *  @returns {void}\n\t *  @private\n\t */\n\t\"_fnGridLayout\": function ()\n\t{\n\t\tvar that = this;\n\t\tvar oGrid = this.dom.grid;\n\t\tvar iWidth = $(oGrid.wrapper).width();\n\t\tvar iBodyHeight = this.s.dt.nTable.parentNode.offsetHeight;\n\t\tvar iFullHeight = this.s.dt.nTable.parentNode.parentNode.offsetHeight;\n\t\tvar oOverflow = this._fnDTOverflow();\n\t\tvar iLeftWidth = this.s.iLeftWidth;\n\t\tvar iRightWidth = this.s.iRightWidth;\n\t\tvar rtl = $(this.dom.body).css('direction') === 'rtl';\n\t\tvar wrapper;\n\t\tvar scrollbarAdjust = function ( node, width ) {\n\t\t\tif ( ! oOverflow.bar ) {\n\t\t\t\t// If there is no scrollbar (Macs) we need to hide the auto scrollbar\n\t\t\t\tnode.style.width = (width+20)+\"px\";\n\t\t\t\tnode.style.paddingRight = \"20px\";\n\t\t\t\tnode.style.boxSizing = \"border-box\";\n\t\t\t}\n\t\t\telse if ( that._firefoxScrollError() ) {\n\t\t\t\t// See the above function for why this is required\n\t\t\t\tif ( $(node).height() > 34 ) {\n\t\t\t\t\tnode.style.width = (width+oOverflow.bar)+\"px\";\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Otherwise just overflow by the scrollbar\n\t\t\t\tnode.style.width = (width+oOverflow.bar)+\"px\";\n\t\t\t}\n\t\t};\n\n\t\t// When x scrolling - don't paint the fixed columns over the x scrollbar\n\t\tif ( oOverflow.x )\n\t\t{\n\t\t\tiBodyHeight -= oOverflow.bar;\n\t\t}\n\n\t\toGrid.wrapper.style.height = iFullHeight+\"px\";\n\n\t\tif ( this.s.iLeftColumns > 0 )\n\t\t{\n\t\t\twrapper = oGrid.left.wrapper;\n\t\t\twrapper.style.width = iLeftWidth+'px';\n\t\t\twrapper.style.height = '1px';\n\n\t\t\t// Swap the position of the left and right columns for rtl (#48)\n\t\t\t// This is always up against the edge, scrollbar on the far side\n\t\t\tif ( rtl ) {\n\t\t\t\twrapper.style.left = '';\n\t\t\t\twrapper.style.right = 0;\n\t\t\t}\n\t\t\telse {\n\t\t\t\twrapper.style.left = 0;\n\t\t\t\twrapper.style.right = '';\n\t\t\t}\n\n\t\t\toGrid.left.body.style.height = iBodyHeight+\"px\";\n\t\t\tif ( oGrid.left.foot ) {\n\t\t\t\toGrid.left.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+\"px\"; // shift footer for scrollbar\n\t\t\t}\n\n\t\t\tscrollbarAdjust( oGrid.left.liner, iLeftWidth );\n\t\t\toGrid.left.liner.style.height = iBodyHeight+\"px\";\n\t\t\toGrid.left.liner.style.maxHeight = iBodyHeight+\"px\";\n\t\t}\n\n\t\tif ( this.s.iRightColumns > 0 )\n\t\t{\n\t\t\twrapper = oGrid.right.wrapper;\n\t\t\twrapper.style.width = iRightWidth+'px';\n\t\t\twrapper.style.height = '1px';\n\n\t\t\t// Need to take account of the vertical scrollbar\n\t\t\tif ( this.s.rtl ) {\n\t\t\t\twrapper.style.left = oOverflow.y ? oOverflow.bar+'px' : 0;\n\t\t\t\twrapper.style.right = '';\n\t\t\t}\n\t\t\telse {\n\t\t\t\twrapper.style.left = '';\n\t\t\t\twrapper.style.right = oOverflow.y ? oOverflow.bar+'px' : 0;\n\t\t\t}\n\n\t\t\toGrid.right.body.style.height = iBodyHeight+\"px\";\n\t\t\tif ( oGrid.right.foot ) {\n\t\t\t\toGrid.right.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+\"px\";\n\t\t\t}\n\n\t\t\tscrollbarAdjust( oGrid.right.liner, iRightWidth );\n\t\t\toGrid.right.liner.style.height = iBodyHeight+\"px\";\n\t\t\toGrid.right.liner.style.maxHeight = iBodyHeight+\"px\";\n\n\t\t\toGrid.right.headBlock.style.display = oOverflow.y ? 'block' : 'none';\n\t\t\toGrid.right.footBlock.style.display = oOverflow.y ? 'block' : 'none';\n\t\t}\n\t},\n\n\n\t/**\n\t * Get information about the DataTable's scrolling state - specifically if the table is scrolling\n\t * on either the x or y axis, and also the scrollbar width.\n\t *  @returns {object} Information about the DataTables scrolling state with the properties:\n\t *    'x', 'y' and 'bar'\n\t *  @private\n\t */\n\t\"_fnDTOverflow\": function ()\n\t{\n\t\tvar nTable = this.s.dt.nTable;\n\t\tvar nTableScrollBody = nTable.parentNode;\n\t\tvar out = {\n\t\t\t\"x\": false,\n\t\t\t\"y\": false,\n\t\t\t\"bar\": this.s.dt.oScroll.iBarWidth\n\t\t};\n\n\t\tif ( nTable.offsetWidth > nTableScrollBody.clientWidth )\n\t\t{\n\t\t\tout.x = true;\n\t\t}\n\n\t\tif ( nTable.offsetHeight > nTableScrollBody.clientHeight )\n\t\t{\n\t\t\tout.y = true;\n\t\t}\n\n\t\treturn out;\n\t},\n\n\n\t/**\n\t * Clone and position the fixed columns\n\t *  @returns {void}\n\t *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)\n\t *  @private\n\t */\n\t\"_fnDraw\": function ( bAll )\n\t{\n\t\tthis._fnGridLayout();\n\t\tthis._fnCloneLeft( bAll );\n\t\tthis._fnCloneRight( bAll );\n\n\t\t/* Draw callback function */\n\t\tif ( this.s.fnDrawCallback !== null )\n\t\t{\n\t\t\tthis.s.fnDrawCallback.call( this, this.dom.clone.left, this.dom.clone.right );\n\t\t}\n\n\t\t/* Event triggering */\n\t\t$(this).trigger( 'draw.dtfc', {\n\t\t\t\"leftClone\": this.dom.clone.left,\n\t\t\t\"rightClone\": this.dom.clone.right\n\t\t} );\n\t},\n\n\n\t/**\n\t * Clone the right columns\n\t *  @returns {void}\n\t *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)\n\t *  @private\n\t */\n\t\"_fnCloneRight\": function ( bAll )\n\t{\n\t\tif ( this.s.iRightColumns <= 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar that = this,\n\t\t\ti, jq,\n\t\t\taiColumns = [];\n\n\t\tfor ( i=this.s.iTableColumns-this.s.iRightColumns ; i<this.s.iTableColumns ; i++ ) {\n\t\t\tif ( this.s.dt.aoColumns[i].bVisible ) {\n\t\t\t\taiColumns.push( i );\n\t\t\t}\n\t\t}\n\n\t\tthis._fnClone( this.dom.clone.right, this.dom.grid.right, aiColumns, bAll );\n\t},\n\n\n\t/**\n\t * Clone the left columns\n\t *  @returns {void}\n\t *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)\n\t *  @private\n\t */\n\t\"_fnCloneLeft\": function ( bAll )\n\t{\n\t\tif ( this.s.iLeftColumns <= 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar that = this,\n\t\t\ti, jq,\n\t\t\taiColumns = [];\n\n\t\tfor ( i=0 ; i<this.s.iLeftColumns ; i++ ) {\n\t\t\tif ( this.s.dt.aoColumns[i].bVisible ) {\n\t\t\t\taiColumns.push( i );\n\t\t\t}\n\t\t}\n\n\t\tthis._fnClone( this.dom.clone.left, this.dom.grid.left, aiColumns, bAll );\n\t},\n\n\n\t/**\n\t * Make a copy of the layout object for a header or footer element from DataTables. Note that\n\t * this method will clone the nodes in the layout object.\n\t *  @returns {Array} Copy of the layout array\n\t *  @param   {Object} aoOriginal Layout array from DataTables (aoHeader or aoFooter)\n\t *  @param   {Object} aiColumns Columns to copy\n\t *  @param   {boolean} events Copy cell events or not\n\t *  @private\n\t */\n\t\"_fnCopyLayout\": function ( aoOriginal, aiColumns, events )\n\t{\n\t\tvar aReturn = [];\n\t\tvar aClones = [];\n\t\tvar aCloned = [];\n\n\t\tfor ( var i=0, iLen=aoOriginal.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar aRow = [];\n\t\t\taRow.nTr = $(aoOriginal[i].nTr).clone(events, false)[0];\n\n\t\t\tfor ( var j=0, jLen=this.s.iTableColumns ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tif ( $.inArray( j, aiColumns ) === -1 )\n\t\t\t\t{\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tvar iCloned = $.inArray( aoOriginal[i][j].cell, aCloned );\n\t\t\t\tif ( iCloned === -1 )\n\t\t\t\t{\n\t\t\t\t\tvar nClone = $(aoOriginal[i][j].cell).clone(events, false)[0];\n\t\t\t\t\taClones.push( nClone );\n\t\t\t\t\taCloned.push( aoOriginal[i][j].cell );\n\n\t\t\t\t\taRow.push( {\n\t\t\t\t\t\t\"cell\": nClone,\n\t\t\t\t\t\t\"unique\": aoOriginal[i][j].unique\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\taRow.push( {\n\t\t\t\t\t\t\"cell\": aClones[ iCloned ],\n\t\t\t\t\t\t\"unique\": aoOriginal[i][j].unique\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\taReturn.push( aRow );\n\t\t}\n\n\t\treturn aReturn;\n\t},\n\n\n\t/**\n\t * Clone the DataTable nodes and place them in the DOM (sized correctly)\n\t *  @returns {void}\n\t *  @param   {Object} oClone Object containing the header, footer and body cloned DOM elements\n\t *  @param   {Object} oGrid Grid object containing the display grid elements for the cloned\n\t *                    column (left or right)\n\t *  @param   {Array} aiColumns Column indexes which should be operated on from the DataTable\n\t *  @param   {Boolean} bAll Indicate if the header and footer should be updated as well (true)\n\t *  @private\n\t */\n\t\"_fnClone\": function ( oClone, oGrid, aiColumns, bAll )\n\t{\n\t\tvar that = this,\n\t\t\ti, iLen, j, jLen, jq, nTarget, iColumn, nClone, iIndex, aoCloneLayout,\n\t\t\tjqCloneThead, aoFixedHeader,\n\t\t\tdt = this.s.dt;\n\n\t\t/*\n\t\t * Header\n\t\t */\n\t\tif ( bAll )\n\t\t{\n\t\t\t$(oClone.header).remove();\n\n\t\t\toClone.header = $(this.dom.header).clone(true, false)[0];\n\t\t\toClone.header.className += \" DTFC_Cloned\";\n\t\t\toClone.header.style.width = \"100%\";\n\t\t\toGrid.head.appendChild( oClone.header );\n\n\t\t\t/* Copy the DataTables layout cache for the header for our floating column */\n\t\t\taoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns, true );\n\t\t\tjqCloneThead = $('>thead', oClone.header);\n\t\t\tjqCloneThead.empty();\n\n\t\t\t/* Add the created cloned TR elements to the table */\n\t\t\tfor ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tjqCloneThead[0].appendChild( aoCloneLayout[i].nTr );\n\t\t\t}\n\n\t\t\t/* Use the handy _fnDrawHead function in DataTables to do the rowspan/colspan\n\t\t\t * calculations for us\n\t\t\t */\n\t\t\tdt.oApi._fnDrawHead( dt, aoCloneLayout, true );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* To ensure that we copy cell classes exactly, regardless of colspan, multiple rows\n\t\t\t * etc, we make a copy of the header from the DataTable again, but don't insert the\n\t\t\t * cloned cells, just copy the classes across. To get the matching layout for the\n\t\t\t * fixed component, we use the DataTables _fnDetectHeader method, allowing 1:1 mapping\n\t\t\t */\n\t\t\taoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns, false );\n\t\t\taoFixedHeader=[];\n\n\t\t\tdt.oApi._fnDetectHeader( aoFixedHeader, $('>thead', oClone.header)[0] );\n\n\t\t\tfor ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfor ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\taoFixedHeader[i][j].cell.className = aoCloneLayout[i][j].cell.className;\n\n\t\t\t\t\t// If jQuery UI theming is used we need to copy those elements as well\n\t\t\t\t\t$('span.DataTables_sort_icon', aoFixedHeader[i][j].cell).each( function () {\n\t\t\t\t\t\tthis.className = $('span.DataTables_sort_icon', aoCloneLayout[i][j].cell)[0].className;\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis._fnEqualiseHeights( 'thead', this.dom.header, oClone.header );\n\n\t\t/*\n\t\t * Body\n\t\t */\n\t\tif ( this.s.sHeightMatch == 'auto' )\n\t\t{\n\t\t\t/* Remove any heights which have been applied already and let the browser figure it out */\n\t\t\t$('>tbody>tr', that.dom.body).css('height', 'auto');\n\t\t}\n\n\t\tif ( oClone.body !== null )\n\t\t{\n\t\t\t$(oClone.body).remove();\n\t\t\toClone.body = null;\n\t\t}\n\n\t\toClone.body = $(this.dom.body).clone(true)[0];\n\t\toClone.body.className += \" DTFC_Cloned\";\n\t\toClone.body.style.paddingBottom = dt.oScroll.iBarWidth+\"px\";\n\t\toClone.body.style.marginBottom = (dt.oScroll.iBarWidth*2)+\"px\"; /* For IE */\n\t\tif ( oClone.body.getAttribute('id') !== null )\n\t\t{\n\t\t\toClone.body.removeAttribute('id');\n\t\t}\n\n\t\t$('>thead>tr', oClone.body).empty();\n\t\t$('>tfoot', oClone.body).remove();\n\n\t\tvar nBody = $('tbody', oClone.body)[0];\n\t\t$(nBody).empty();\n\t\tif ( dt.aiDisplay.length > 0 )\n\t\t{\n\t\t\t/* Copy the DataTables' header elements to force the column width in exactly the\n\t\t\t * same way that DataTables does it - have the header element, apply the width and\n\t\t\t * colapse it down\n\t\t\t */\n\t\t\tvar nInnerThead = $('>thead>tr', oClone.body)[0];\n\t\t\tfor ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )\n\t\t\t{\n\t\t\t\tiColumn = aiColumns[iIndex];\n\n\t\t\t\tnClone = $(dt.aoColumns[iColumn].nTh).clone(true)[0];\n\t\t\t\tnClone.innerHTML = \"\";\n\n\t\t\t\tvar oStyle = nClone.style;\n\t\t\t\toStyle.paddingTop = \"0\";\n\t\t\t\toStyle.paddingBottom = \"0\";\n\t\t\t\toStyle.borderTopWidth = \"0\";\n\t\t\t\toStyle.borderBottomWidth = \"0\";\n\t\t\t\toStyle.height = 0;\n\t\t\t\toStyle.width = that.s.aiInnerWidths[iColumn]+\"px\";\n\n\t\t\t\tnInnerThead.appendChild( nClone );\n\t\t\t}\n\n\t\t\t/* Add in the tbody elements, cloning form the master table */\n\t\t\t$('>tbody>tr', that.dom.body).each( function (z) {\n\t\t\t\tvar i = that.s.dt.oFeatures.bServerSide===false ?\n\t\t\t\t\tthat.s.dt.aiDisplay[ that.s.dt._iDisplayStart+z ] : z;\n\t\t\t\tvar aTds = that.s.dt.aoData[ i ].anCells || $(this).children('td, th');\n\n\t\t\t\tvar n = this.cloneNode(false);\n\t\t\t\tn.removeAttribute('id');\n\t\t\t\tn.setAttribute( 'data-dt-row', i );\n\n\t\t\t\tfor ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )\n\t\t\t\t{\n\t\t\t\t\tiColumn = aiColumns[iIndex];\n\n\t\t\t\t\tif ( aTds.length > 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\tnClone = $( aTds[iColumn] ).clone(true, true)[0];\n\t\t\t\t\t\tnClone.removeAttribute( 'id' );\n\t\t\t\t\t\tnClone.setAttribute( 'data-dt-row', i );\n\t\t\t\t\t\tnClone.setAttribute( 'data-dt-column', iColumn );\n\t\t\t\t\t\tn.appendChild( nClone );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnBody.appendChild( n );\n\t\t\t} );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$('>tbody>tr', that.dom.body).each( function (z) {\n\t\t\t\tnClone = this.cloneNode(true);\n\t\t\t\tnClone.className += ' DTFC_NoData';\n\t\t\t\t$('td', nClone).html('');\n\t\t\t\tnBody.appendChild( nClone );\n\t\t\t} );\n\t\t}\n\n\t\toClone.body.style.width = \"100%\";\n\t\toClone.body.style.margin = \"0\";\n\t\toClone.body.style.padding = \"0\";\n\n\t\t// Interop with Scroller - need to use a height forcing element in the\n\t\t// scrolling area in the same way that Scroller does in the body scroll.\n\t\tif ( dt.oScroller !== undefined )\n\t\t{\n\t\t\tvar scrollerForcer = dt.oScroller.dom.force;\n\n\t\t\tif ( ! oGrid.forcer ) {\n\t\t\t\toGrid.forcer = scrollerForcer.cloneNode( true );\n\t\t\t\toGrid.liner.appendChild( oGrid.forcer );\n\t\t\t}\n\t\t\telse {\n\t\t\t\toGrid.forcer.style.height = scrollerForcer.style.height;\n\t\t\t}\n\t\t}\n\n\t\toGrid.liner.appendChild( oClone.body );\n\n\t\tthis._fnEqualiseHeights( 'tbody', that.dom.body, oClone.body );\n\n\t\t/*\n\t\t * Footer\n\t\t */\n\t\tif ( dt.nTFoot !== null )\n\t\t{\n\t\t\tif ( bAll )\n\t\t\t{\n\t\t\t\tif ( oClone.footer !== null )\n\t\t\t\t{\n\t\t\t\t\toClone.footer.parentNode.removeChild( oClone.footer );\n\t\t\t\t}\n\t\t\t\toClone.footer = $(this.dom.footer).clone(true, true)[0];\n\t\t\t\toClone.footer.className += \" DTFC_Cloned\";\n\t\t\t\toClone.footer.style.width = \"100%\";\n\t\t\t\toGrid.foot.appendChild( oClone.footer );\n\n\t\t\t\t/* Copy the footer just like we do for the header */\n\t\t\t\taoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, true );\n\t\t\t\tvar jqCloneTfoot = $('>tfoot', oClone.footer);\n\t\t\t\tjqCloneTfoot.empty();\n\n\t\t\t\tfor ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tjqCloneTfoot[0].appendChild( aoCloneLayout[i].nTr );\n\t\t\t\t}\n\t\t\t\tdt.oApi._fnDrawHead( dt, aoCloneLayout, true );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, false );\n\t\t\t\tvar aoCurrFooter=[];\n\n\t\t\t\tdt.oApi._fnDetectHeader( aoCurrFooter, $('>tfoot', oClone.footer)[0] );\n\n\t\t\t\tfor ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\tfor ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )\n\t\t\t\t\t{\n\t\t\t\t\t\taoCurrFooter[i][j].cell.className = aoCloneLayout[i][j].cell.className;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._fnEqualiseHeights( 'tfoot', this.dom.footer, oClone.footer );\n\t\t}\n\n\t\t/* Equalise the column widths between the header footer and body - body get's priority */\n\t\tvar anUnique = dt.oApi._fnGetUniqueThs( dt, $('>thead', oClone.header)[0] );\n\t\t$(anUnique).each( function (i) {\n\t\t\tiColumn = aiColumns[i];\n\t\t\tthis.style.width = that.s.aiInnerWidths[iColumn]+\"px\";\n\t\t} );\n\n\t\tif ( that.s.dt.nTFoot !== null )\n\t\t{\n\t\t\tanUnique = dt.oApi._fnGetUniqueThs( dt, $('>tfoot', oClone.footer)[0] );\n\t\t\t$(anUnique).each( function (i) {\n\t\t\t\tiColumn = aiColumns[i];\n\t\t\t\tthis.style.width = that.s.aiInnerWidths[iColumn]+\"px\";\n\t\t\t} );\n\t\t}\n\t},\n\n\n\t/**\n\t * From a given table node (THEAD etc), get a list of TR direct child elements\n\t *  @param   {Node} nIn Table element to search for TR elements (THEAD, TBODY or TFOOT element)\n\t *  @returns {Array} List of TR elements found\n\t *  @private\n\t */\n\t\"_fnGetTrNodes\": function ( nIn )\n\t{\n\t\tvar aOut = [];\n\t\tfor ( var i=0, iLen=nIn.childNodes.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( nIn.childNodes[i].nodeName.toUpperCase() == \"TR\" )\n\t\t\t{\n\t\t\t\taOut.push( nIn.childNodes[i] );\n\t\t\t}\n\t\t}\n\t\treturn aOut;\n\t},\n\n\n\t/**\n\t * Equalise the heights of the rows in a given table node in a cross browser way\n\t *  @returns {void}\n\t *  @param   {String} nodeName Node type - thead, tbody or tfoot\n\t *  @param   {Node} original Original node to take the heights from\n\t *  @param   {Node} clone Copy the heights to\n\t *  @private\n\t */\n\t\"_fnEqualiseHeights\": function ( nodeName, original, clone )\n\t{\n\t\tif ( this.s.sHeightMatch == 'none' && nodeName !== 'thead' && nodeName !== 'tfoot' )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tvar that = this,\n\t\t\ti, iLen, iHeight, iHeight2, iHeightOriginal, iHeightClone,\n\t\t\trootOriginal = original.getElementsByTagName(nodeName)[0],\n\t\t\trootClone    = clone.getElementsByTagName(nodeName)[0],\n\t\t\tjqBoxHack    = $('>'+nodeName+'>tr:eq(0)', original).children(':first'),\n\t\t\tiBoxHack     = jqBoxHack.outerHeight() - jqBoxHack.height(),\n\t\t\tanOriginal   = this._fnGetTrNodes( rootOriginal ),\n\t\t\tanClone      = this._fnGetTrNodes( rootClone ),\n\t\t\theights      = [];\n\n\t\tfor ( i=0, iLen=anClone.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tiHeightOriginal = anOriginal[i].offsetHeight;\n\t\t\tiHeightClone = anClone[i].offsetHeight;\n\t\t\tiHeight = iHeightClone > iHeightOriginal ? iHeightClone : iHeightOriginal;\n\n\t\t\tif ( this.s.sHeightMatch == 'semiauto' )\n\t\t\t{\n\t\t\t\tanOriginal[i]._DTTC_iHeight = iHeight;\n\t\t\t}\n\n\t\t\theights.push( iHeight );\n\t\t}\n\n\t\tfor ( i=0, iLen=anClone.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tanClone[i].style.height = heights[i]+\"px\";\n\t\t\tanOriginal[i].style.height = heights[i]+\"px\";\n\t\t}\n\t},\n\n\t/**\n\t * Determine if the UA suffers from Firefox's overflow:scroll scrollbars\n\t * not being shown bug.\n\t *\n\t * Firefox doesn't draw scrollbars, even if it is told to using\n\t * overflow:scroll, if the div is less than 34px height. See bugs 292284 and\n\t * 781885. Using UA detection here since this is particularly hard to detect\n\t * using objects - its a straight up rendering error in Firefox.\n\t *\n\t * @return {boolean} True if Firefox error is present, false otherwise\n\t */\n\t_firefoxScrollError: function () {\n\t\tif ( _firefoxScroll === undefined ) {\n\t\t\tvar test = $('<div/>')\n\t\t\t\t.css( {\n\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: 0,\n\t\t\t\t\theight: 10,\n\t\t\t\t\twidth: 50,\n\t\t\t\t\toverflow: 'scroll'\n\t\t\t\t} )\n\t\t\t\t.appendTo( 'body' );\n\n\t\t\t// Make sure this doesn't apply on Macs with 0 width scrollbars\n\t\t\t_firefoxScroll = (\n\t\t\t\ttest[0].clientWidth === test[0].offsetWidth && this._fnDTOverflow().bar !== 0\n\t\t\t);\n\n\t\t\ttest.remove();\n\t\t}\n\n\t\treturn _firefoxScroll;\n\t}\n} );\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Statics\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n/**\n * FixedColumns default settings for initialisation\n *  @name FixedColumns.defaults\n *  @namespace\n *  @static\n */\nFixedColumns.defaults = /** @lends FixedColumns.defaults */{\n\t/**\n\t * Number of left hand columns to fix in position\n\t *  @type     int\n\t *  @default  1\n\t *  @static\n\t *  @example\n\t *      var  = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      new $.fn.dataTable.fixedColumns( table, {\n\t *          \"leftColumns\": 2\n\t *      } );\n\t */\n\t\"iLeftColumns\": 1,\n\n\t/**\n\t * Number of right hand columns to fix in position\n\t *  @type     int\n\t *  @default  0\n\t *  @static\n\t *  @example\n\t *      var table = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      new $.fn.dataTable.fixedColumns( table, {\n\t *          \"rightColumns\": 1\n\t *      } );\n\t */\n\t\"iRightColumns\": 0,\n\n\t/**\n\t * Draw callback function which is called when FixedColumns has redrawn the fixed assets\n\t *  @type     function(object, object):void\n\t *  @default  null\n\t *  @static\n\t *  @example\n\t *      var table = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      new $.fn.dataTable.fixedColumns( table, {\n\t *          \"drawCallback\": function () {\n\t *\t            alert( \"FixedColumns redraw\" );\n\t *\t        }\n\t *      } );\n\t */\n\t\"fnDrawCallback\": null,\n\n\t/**\n\t * Height matching algorthim to use. This can be \"none\" which will result in no height\n\t * matching being applied by FixedColumns (height matching could be forced by CSS in this\n\t * case), \"semiauto\" whereby the height calculation will be performed once, and the result\n\t * cached to be used again (fnRecalculateHeight can be used to force recalculation), or\n\t * \"auto\" when height matching is performed on every draw (slowest but must accurate)\n\t *  @type     string\n\t *  @default  semiauto\n\t *  @static\n\t *  @example\n\t *      var table = $('#example').dataTable( {\n\t *          \"scrollX\": \"100%\"\n\t *      } );\n\t *      new $.fn.dataTable.fixedColumns( table, {\n\t *          \"heightMatch\": \"auto\"\n\t *      } );\n\t */\n\t\"sHeightMatch\": \"semiauto\"\n};\n\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Constants\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n/**\n * FixedColumns version\n *  @name      FixedColumns.version\n *  @type      String\n *  @default   See code\n *  @static\n */\nFixedColumns.version = \"3.2.5\";\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables API integration\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\nDataTable.Api.register( 'fixedColumns()', function () {\n\treturn this;\n} );\n\nDataTable.Api.register( 'fixedColumns().update()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx._oFixedColumns ) {\n\t\t\tctx._oFixedColumns.fnUpdate();\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'fixedColumns().relayout()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx._oFixedColumns ) {\n\t\t\tctx._oFixedColumns.fnRedrawLayout();\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'rows().recalcHeight()', function () {\n\treturn this.iterator( 'row', function ( ctx, idx ) {\n\t\tif ( ctx._oFixedColumns ) {\n\t\t\tctx._oFixedColumns.fnRecalculateHeight( this.row(idx).node() );\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'fixedColumns().rowIndex()', function ( row ) {\n\trow = $(row);\n\n\treturn row.parents('.DTFC_Cloned').length ?\n\t\tthis.rows( { page: 'current' } ).indexes()[ row.index() ] :\n\t\tthis.row( row ).index();\n} );\n\nDataTable.Api.register( 'fixedColumns().cellIndex()', function ( cell ) {\n\tcell = $(cell);\n\n\tif ( cell.parents('.DTFC_Cloned').length ) {\n\t\tvar rowClonedIdx = cell.parent().index();\n\t\tvar rowIdx = this.rows( { page: 'current' } ).indexes()[ rowClonedIdx ];\n\t\tvar columnIdx;\n\n\t\tif ( cell.parents('.DTFC_LeftWrapper').length ) {\n\t\t\tcolumnIdx = cell.index();\n\t\t}\n\t\telse {\n\t\t\tvar columns = this.columns().flatten().length;\n\t\t\tcolumnIdx = columns - this.context[0]._oFixedColumns.s.iRightColumns + cell.index();\n\t\t}\n\n\t\treturn {\n\t\t\trow: rowIdx,\n\t\t\tcolumn: this.column.index( 'toData', columnIdx ),\n\t\t\tcolumnVisible: columnIdx\n\t\t};\n\t}\n\telse {\n\t\treturn this.cell( cell ).index();\n\t}\n} );\n\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Initialisation\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'init.dt.fixedColumns', function (e, settings) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.fixedColumns;\n\tvar defaults = DataTable.defaults.fixedColumns;\n\n\tif ( init || defaults ) {\n\t\tvar opts = $.extend( {}, init, defaults );\n\n\t\tif ( init !== false ) {\n\t\t\tnew FixedColumns( settings, opts );\n\t\t}\n\t}\n} );\n\n\n\n// Make FixedColumns accessible from the DataTables instance\n$.fn.dataTable.FixedColumns = FixedColumns;\n$.fn.DataTable.FixedColumns = FixedColumns;\n\nreturn FixedColumns;\n}));\n\n\n/*! FixedHeader 3.1.4\n * ©2009-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     FixedHeader\n * @description Fix a table's header or footer, so it is always visible while\n *              scrolling\n * @version     3.1.4\n * @file        dataTables.fixedHeader.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2009-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar _instCounter = 0;\n\nvar FixedHeader = function ( dt, config ) {\n\t// Sanity check - you just know it will happen\n\tif ( ! (this instanceof FixedHeader) ) {\n\t\tthrow \"FixedHeader must be initialised with the 'new' keyword.\";\n\t}\n\n\t// Allow a boolean true for defaults\n\tif ( config === true ) {\n\t\tconfig = {};\n\t}\n\n\tdt = new DataTable.Api( dt );\n\n\tthis.c = $.extend( true, {}, FixedHeader.defaults, config );\n\n\tthis.s = {\n\t\tdt: dt,\n\t\tposition: {\n\t\t\ttheadTop: 0,\n\t\t\ttbodyTop: 0,\n\t\t\ttfootTop: 0,\n\t\t\ttfootBottom: 0,\n\t\t\twidth: 0,\n\t\t\tleft: 0,\n\t\t\ttfootHeight: 0,\n\t\t\ttheadHeight: 0,\n\t\t\twindowHeight: $(window).height(),\n\t\t\tvisible: true\n\t\t},\n\t\theaderMode: null,\n\t\tfooterMode: null,\n\t\tautoWidth: dt.settings()[0].oFeatures.bAutoWidth,\n\t\tnamespace: '.dtfc'+(_instCounter++),\n\t\tscrollLeft: {\n\t\t\theader: -1,\n\t\t\tfooter: -1\n\t\t},\n\t\tenable: true\n\t};\n\n\tthis.dom = {\n\t\tfloatingHeader: null,\n\t\tthead: $(dt.table().header()),\n\t\ttbody: $(dt.table().body()),\n\t\ttfoot: $(dt.table().footer()),\n\t\theader: {\n\t\t\thost: null,\n\t\t\tfloating: null,\n\t\t\tplaceholder: null\n\t\t},\n\t\tfooter: {\n\t\t\thost: null,\n\t\t\tfloating: null,\n\t\t\tplaceholder: null\n\t\t}\n\t};\n\n\tthis.dom.header.host = this.dom.thead.parent();\n\tthis.dom.footer.host = this.dom.tfoot.parent();\n\n\tvar dtSettings = dt.settings()[0];\n\tif ( dtSettings._fixedHeader ) {\n\t\tthrow \"FixedHeader already initialised on table \"+dtSettings.nTable.id;\n\t}\n\n\tdtSettings._fixedHeader = this;\n\n\tthis._constructor();\n};\n\n\n/*\n * Variable: FixedHeader\n * Purpose:  Prototype for FixedHeader\n * Scope:    global\n */\n$.extend( FixedHeader.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * API methods\n\t */\n\t\n\t/**\n\t * Enable / disable the fixed elements\n\t *\n\t * @param  {boolean} enable `true` to enable, `false` to disable\n\t */\n\tenable: function ( enable )\n\t{\n\t\tthis.s.enable = enable;\n\n\t\tif ( this.c.header ) {\n\t\t\tthis._modeChange( 'in-place', 'header', true );\n\t\t}\n\n\t\tif ( this.c.footer && this.dom.tfoot.length ) {\n\t\t\tthis._modeChange( 'in-place', 'footer', true );\n\t\t}\n\n\t\tthis.update();\n\t},\n\t\n\t/**\n\t * Set header offset \n\t *\n\t * @param  {int} new value for headerOffset\n\t */\n\theaderOffset: function ( offset )\n\t{\n\t\tif ( offset !== undefined ) {\n\t\t\tthis.c.headerOffset = offset;\n\t\t\tthis.update();\n\t\t}\n\n\t\treturn this.c.headerOffset;\n\t},\n\t\n\t/**\n\t * Set footer offset\n\t *\n\t * @param  {int} new value for footerOffset\n\t */\n\tfooterOffset: function ( offset )\n\t{\n\t\tif ( offset !== undefined ) {\n\t\t\tthis.c.footerOffset = offset;\n\t\t\tthis.update();\n\t\t}\n\n\t\treturn this.c.footerOffset;\n\t},\n\n\t\n\t/**\n\t * Recalculate the position of the fixed elements and force them into place\n\t */\n\tupdate: function ()\n\t{\n\t\tthis._positions();\n\t\tthis._scroll( true );\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\t\n\t/**\n\t * FixedHeader constructor - adding the required event listeners and\n\t * simple initialisation\n\t *\n\t * @private\n\t */\n\t_constructor: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\n\t\t$(window)\n\t\t\t.on( 'scroll'+this.s.namespace, function () {\n\t\t\t\tthat._scroll();\n\t\t\t} )\n\t\t\t.on( 'resize'+this.s.namespace, DataTable.util.throttle( function () {\n\t\t\t\tthat.s.position.windowHeight = $(window).height();\n\t\t\t\tthat.update();\n\t\t\t}, 50 ) );\n\n\t\tvar autoHeader = $('.fh-fixedHeader');\n\t\tif ( ! this.c.headerOffset && autoHeader.length ) {\n\t\t\tthis.c.headerOffset = autoHeader.outerHeight();\n\t\t}\n\n\t\tvar autoFooter = $('.fh-fixedFooter');\n\t\tif ( ! this.c.footerOffset && autoFooter.length ) {\n\t\t\tthis.c.footerOffset = autoFooter.outerHeight();\n\t\t}\n\n\t\tdt.on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc draw.dt.dtfc column-sizing.dt.dtfc responsive-display.dt.dtfc', function () {\n\t\t\tthat.update();\n\t\t} );\n\n\t\tdt.on( 'destroy.dtfc', function () {\n\t\t\tif ( that.c.header ) {\n\t\t\t\tthat._modeChange( 'in-place', 'header', true );\n\t\t\t}\n\n\t\t\tif ( that.c.footer && that.dom.tfoot.length ) {\n\t\t\t\tthat._modeChange( 'in-place', 'footer', true );\n\t\t\t}\n\n\t\t\tdt.off( '.dtfc' );\n\t\t\t$(window).off( that.s.namespace );\n\t\t} );\n\n\t\tthis._positions();\n\t\tthis._scroll();\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\n\t/**\n\t * Clone a fixed item to act as a place holder for the original element\n\t * which is moved into a clone of the table element, and moved around the\n\t * document to give the fixed effect.\n\t *\n\t * @param  {string}  item  'header' or 'footer'\n\t * @param  {boolean} force Force the clone to happen, or allow automatic\n\t *   decision (reuse existing if available)\n\t * @private\n\t */\n\t_clone: function ( item, force )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar itemDom = this.dom[ item ];\n\t\tvar itemElement = item === 'header' ?\n\t\t\tthis.dom.thead :\n\t\t\tthis.dom.tfoot;\n\n\t\tif ( ! force && itemDom.floating ) {\n\t\t\t// existing floating element - reuse it\n\t\t\titemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' );\n\t\t}\n\t\telse {\n\t\t\tif ( itemDom.floating ) {\n\t\t\t\titemDom.placeholder.remove();\n\t\t\t\tthis._unsize( item );\n\t\t\t\titemDom.floating.children().detach();\n\t\t\t\titemDom.floating.remove();\n\t\t\t}\n\n\t\t\titemDom.floating = $( dt.table().node().cloneNode( false ) )\n\t\t\t\t.css( 'table-layout', 'fixed' )\n\t\t\t\t.attr( 'aria-hidden', 'true' )\n\t\t\t\t.removeAttr( 'id' )\n\t\t\t\t.append( itemElement )\n\t\t\t\t.appendTo( 'body' );\n\n\t\t\t// Insert a fake thead/tfoot into the DataTable to stop it jumping around\n\t\t\titemDom.placeholder = itemElement.clone( false )\n\t\t\titemDom.placeholder\n\t\t\t\t.find( '*[id]' )\n\t\t\t\t.removeAttr( 'id' );\n\n\t\t\titemDom.host.prepend( itemDom.placeholder );\n\n\t\t\t// Clone widths\n\t\t\tthis._matchWidths( itemDom.placeholder, itemDom.floating );\n\t\t}\n\t},\n\n\t/**\n\t * Copy widths from the cells in one element to another. This is required\n\t * for the footer as the footer in the main table takes its sizes from the\n\t * header columns. That isn't present in the footer so to have it still\n\t * align correctly, the sizes need to be copied over. It is also required\n\t * for the header when auto width is not enabled\n\t *\n\t * @param  {jQuery} from Copy widths from\n\t * @param  {jQuery} to   Copy widths to\n\t * @private\n\t */\n\t_matchWidths: function ( from, to ) {\n\t\tvar get = function ( name ) {\n\t\t\treturn $(name, from)\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn $(this).width();\n\t\t\t\t} ).toArray();\n\t\t};\n\n\t\tvar set = function ( name, toWidths ) {\n\t\t\t$(name, to).each( function ( i ) {\n\t\t\t\t$(this).css( {\n\t\t\t\t\twidth: toWidths[i],\n\t\t\t\t\tminWidth: toWidths[i]\n\t\t\t\t} );\n\t\t\t} );\n\t\t};\n\n\t\tvar thWidths = get( 'th' );\n\t\tvar tdWidths = get( 'td' );\n\n\t\tset( 'th', thWidths );\n\t\tset( 'td', tdWidths );\n\t},\n\n\t/**\n\t * Remove assigned widths from the cells in an element. This is required\n\t * when inserting the footer back into the main table so the size is defined\n\t * by the header columns and also when auto width is disabled in the\n\t * DataTable.\n\t *\n\t * @param  {string} item The `header` or `footer`\n\t * @private\n\t */\n\t_unsize: function ( item ) {\n\t\tvar el = this.dom[ item ].floating;\n\n\t\tif ( el && (item === 'footer' || (item === 'header' && ! this.s.autoWidth)) ) {\n\t\t\t$('th, td', el).css( {\n\t\t\t\twidth: '',\n\t\t\t\tminWidth: ''\n\t\t\t} );\n\t\t}\n\t\telse if ( el && item === 'header' ) {\n\t\t\t$('th, td', el).css( 'min-width', '' );\n\t\t}\n\t},\n\n\t/**\n\t * Reposition the floating elements to take account of horizontal page\n\t * scroll\n\t *\n\t * @param  {string} item       The `header` or `footer`\n\t * @param  {int}    scrollLeft Document scrollLeft\n\t * @private\n\t */\n\t_horizontal: function ( item, scrollLeft )\n\t{\n\t\tvar itemDom = this.dom[ item ];\n\t\tvar position = this.s.position;\n\t\tvar lastScrollLeft = this.s.scrollLeft;\n\n\t\tif ( itemDom.floating && lastScrollLeft[ item ] !== scrollLeft ) {\n\t\t\titemDom.floating.css( 'left', position.left - scrollLeft );\n\n\t\t\tlastScrollLeft[ item ] = scrollLeft;\n\t\t}\n\t},\n\n\t/**\n\t * Change from one display mode to another. Each fixed item can be in one\n\t * of:\n\t *\n\t * * `in-place` - In the main DataTable\n\t * * `in` - Floating over the DataTable\n\t * * `below` - (Header only) Fixed to the bottom of the table body\n\t * * `above` - (Footer only) Fixed to the top of the table body\n\t * \n\t * @param  {string}  mode        Mode that the item should be shown in\n\t * @param  {string}  item        'header' or 'footer'\n\t * @param  {boolean} forceChange Force a redraw of the mode, even if already\n\t *     in that mode.\n\t * @private\n\t */\n\t_modeChange: function ( mode, item, forceChange )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar itemDom = this.dom[ item ];\n\t\tvar position = this.s.position;\n\n\t\t// Record focus. Browser's will cause input elements to loose focus if\n\t\t// they are inserted else where in the doc\n\t\tvar tablePart = this.dom[ item==='footer' ? 'tfoot' : 'thead' ];\n\t\tvar focus = $.contains( tablePart[0], document.activeElement ) ?\n\t\t\tdocument.activeElement :\n\t\t\tnull;\n\t\t\n\t\tif ( focus ) {\n\t\t\tfocus.blur();\n\t\t}\n\n\t\tif ( mode === 'in-place' ) {\n\t\t\t// Insert the header back into the table's real header\n\t\t\tif ( itemDom.placeholder ) {\n\t\t\t\titemDom.placeholder.remove();\n\t\t\t\titemDom.placeholder = null;\n\t\t\t}\n\n\t\t\tthis._unsize( item );\n\n\t\t\tif ( item === 'header' ) {\n\t\t\t\titemDom.host.prepend( tablePart );\n\t\t\t}\n\t\t\telse {\n\t\t\t\titemDom.host.append( tablePart );\n\t\t\t}\n\n\t\t\tif ( itemDom.floating ) {\n\t\t\t\titemDom.floating.remove();\n\t\t\t\titemDom.floating = null;\n\t\t\t}\n\t\t}\n\t\telse if ( mode === 'in' ) {\n\t\t\t// Remove the header from the read header and insert into a fixed\n\t\t\t// positioned floating table clone\n\t\t\tthis._clone( item, forceChange );\n\n\t\t\titemDom.floating\n\t\t\t\t.addClass( 'fixedHeader-floating' )\n\t\t\t\t.css( item === 'header' ? 'top' : 'bottom', this.c[item+'Offset'] )\n\t\t\t\t.css( 'left', position.left+'px' )\n\t\t\t\t.css( 'width', position.width+'px' );\n\n\t\t\tif ( item === 'footer' ) {\n\t\t\t\titemDom.floating.css( 'top', '' );\n\t\t\t}\n\t\t}\n\t\telse if ( mode === 'below' ) { // only used for the header\n\t\t\t// Fix the position of the floating header at base of the table body\n\t\t\tthis._clone( item, forceChange );\n\n\t\t\titemDom.floating\n\t\t\t\t.addClass( 'fixedHeader-locked' )\n\t\t\t\t.css( 'top', position.tfootTop - position.theadHeight )\n\t\t\t\t.css( 'left', position.left+'px' )\n\t\t\t\t.css( 'width', position.width+'px' );\n\t\t}\n\t\telse if ( mode === 'above' ) { // only used for the footer\n\t\t\t// Fix the position of the floating footer at top of the table body\n\t\t\tthis._clone( item, forceChange );\n\n\t\t\titemDom.floating\n\t\t\t\t.addClass( 'fixedHeader-locked' )\n\t\t\t\t.css( 'top', position.tbodyTop )\n\t\t\t\t.css( 'left', position.left+'px' )\n\t\t\t\t.css( 'width', position.width+'px' );\n\t\t}\n\n\t\t// Restore focus if it was lost\n\t\tif ( focus && focus !== document.activeElement ) {\n\t\t\tsetTimeout( function () {\n\t\t\t\tfocus.focus();\n\t\t\t}, 10 );\n\t\t}\n\n\t\tthis.s.scrollLeft.header = -1;\n\t\tthis.s.scrollLeft.footer = -1;\n\t\tthis.s[item+'Mode'] = mode;\n\t},\n\n\t/**\n\t * Cache the positional information that is required for the mode\n\t * calculations that FixedHeader performs.\n\t *\n\t * @private\n\t */\n\t_positions: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar table = dt.table();\n\t\tvar position = this.s.position;\n\t\tvar dom = this.dom;\n\t\tvar tableNode = $(table.node());\n\n\t\t// Need to use the header and footer that are in the main table,\n\t\t// regardless of if they are clones, since they hold the positions we\n\t\t// want to measure from\n\t\tvar thead = tableNode.children('thead');\n\t\tvar tfoot = tableNode.children('tfoot');\n\t\tvar tbody = dom.tbody;\n\n\t\tposition.visible = tableNode.is(':visible');\n\t\tposition.width = tableNode.outerWidth();\n\t\tposition.left = tableNode.offset().left;\n\t\tposition.theadTop = thead.offset().top;\n\t\tposition.tbodyTop = tbody.offset().top;\n\t\tposition.theadHeight = position.tbodyTop - position.theadTop;\n\n\t\tif ( tfoot.length ) {\n\t\t\tposition.tfootTop = tfoot.offset().top;\n\t\t\tposition.tfootBottom = position.tfootTop + tfoot.outerHeight();\n\t\t\tposition.tfootHeight = position.tfootBottom - position.tfootTop;\n\t\t}\n\t\telse {\n\t\t\tposition.tfootTop = position.tbodyTop + tbody.outerHeight();\n\t\t\tposition.tfootBottom = position.tfootTop;\n\t\t\tposition.tfootHeight = position.tfootTop;\n\t\t}\n\t},\n\n\n\t/**\n\t * Mode calculation - determine what mode the fixed items should be placed\n\t * into.\n\t *\n\t * @param  {boolean} forceChange Force a redraw of the mode, even if already\n\t *     in that mode.\n\t * @private\n\t */\n\t_scroll: function ( forceChange )\n\t{\n\t\tvar windowTop = $(document).scrollTop();\n\t\tvar windowLeft = $(document).scrollLeft();\n\t\tvar position = this.s.position;\n\t\tvar headerMode, footerMode;\n\n\t\tif ( ! this.s.enable ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this.c.header ) {\n\t\t\tif ( ! position.visible || windowTop <= position.theadTop - this.c.headerOffset ) {\n\t\t\t\theaderMode = 'in-place';\n\t\t\t}\n\t\t\telse if ( windowTop <= position.tfootTop - position.theadHeight - this.c.headerOffset ) {\n\t\t\t\theaderMode = 'in';\n\t\t\t}\n\t\t\telse {\n\t\t\t\theaderMode = 'below';\n\t\t\t}\n\n\t\t\tif ( forceChange || headerMode !== this.s.headerMode ) {\n\t\t\t\tthis._modeChange( headerMode, 'header', forceChange );\n\t\t\t}\n\n\t\t\tthis._horizontal( 'header', windowLeft );\n\t\t}\n\n\t\tif ( this.c.footer && this.dom.tfoot.length ) {\n\t\t\tif ( ! position.visible || windowTop + position.windowHeight >= position.tfootBottom + this.c.footerOffset ) {\n\t\t\t\tfooterMode = 'in-place';\n\t\t\t}\n\t\t\telse if ( position.windowHeight + windowTop > position.tbodyTop + position.tfootHeight + this.c.footerOffset ) {\n\t\t\t\tfooterMode = 'in';\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfooterMode = 'above';\n\t\t\t}\n\n\t\t\tif ( forceChange || footerMode !== this.s.footerMode ) {\n\t\t\t\tthis._modeChange( footerMode, 'footer', forceChange );\n\t\t\t}\n\n\t\t\tthis._horizontal( 'footer', windowLeft );\n\t\t}\n\t}\n} );\n\n\n/**\n * Version\n * @type {String}\n * @static\n */\nFixedHeader.version = \"3.1.4\";\n\n/**\n * Defaults\n * @type {Object}\n * @static\n */\nFixedHeader.defaults = {\n\theader: true,\n\tfooter: false,\n\theaderOffset: 0,\n\tfooterOffset: 0\n};\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables interfaces\n */\n\n// Attach for constructor access\n$.fn.dataTable.FixedHeader = FixedHeader;\n$.fn.DataTable.FixedHeader = FixedHeader;\n\n\n// DataTables creation - check if the FixedHeader option has been defined on the\n// table and if so, initialise\n$(document).on( 'init.dt.dtfh', function (e, settings, json) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.fixedHeader;\n\tvar defaults = DataTable.defaults.fixedHeader;\n\n\tif ( (init || defaults) && ! settings._fixedHeader ) {\n\t\tvar opts = $.extend( {}, defaults, init );\n\n\t\tif ( init !== false ) {\n\t\t\tnew FixedHeader( settings, opts );\n\t\t}\n\t}\n} );\n\n// DataTables API methods\nDataTable.Api.register( 'fixedHeader()', function () {} );\n\nDataTable.Api.register( 'fixedHeader.adjust()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tvar fh = ctx._fixedHeader;\n\n\t\tif ( fh ) {\n\t\t\tfh.update();\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'fixedHeader.enable()', function ( flag ) {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tvar fh = ctx._fixedHeader;\n\n\t\tflag = ( flag !== undefined ? flag : true );\n\t\tif ( fh && flag !== fh.s.enable ) {\n\t\t\tfh.enable( flag );\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'fixedHeader.disable()', function ( ) {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tvar fh = ctx._fixedHeader;\n\n\t\tif ( fh && fh.s.enable ) {\n\t\t\tfh.enable( false );\n\t\t}\n\t} );\n} );\n\n$.each( ['header', 'footer'], function ( i, el ) {\n\tDataTable.Api.register( 'fixedHeader.'+el+'Offset()', function ( offset ) {\n\t\tvar ctx = this.context;\n\n\t\tif ( offset === undefined ) {\n\t\t\treturn ctx.length && ctx[0]._fixedHeader ?\n\t\t\t\tctx[0]._fixedHeader[el +'Offset']() :\n\t\t\t\tundefined;\n\t\t}\n\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\tvar fh = ctx._fixedHeader;\n\n\t\t\tif ( fh ) {\n\t\t\t\tfh[ el +'Offset' ]( offset );\n\t\t\t}\n\t\t} );\n\t} );\n} );\n\n\nreturn FixedHeader;\n}));\n\n\n/*! KeyTable 2.5.0\n * ©2009-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     KeyTable\n * @description Spreadsheet like keyboard navigation for DataTables\n * @version     2.5.0\n * @file        dataTables.keyTable.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2009-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar KeyTable = function ( dt, opts ) {\n\t// Sanity check that we are using DataTables 1.10 or newer\n\tif ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {\n\t\tthrow 'KeyTable requires DataTables 1.10.8 or newer';\n\t}\n\n\t// User and defaults configuration object\n\tthis.c = $.extend( true, {},\n\t\tDataTable.defaults.keyTable,\n\t\tKeyTable.defaults,\n\t\topts\n\t);\n\n\t// Internal settings\n\tthis.s = {\n\t\t/** @type {DataTable.Api} DataTables' API instance */\n\t\tdt: new DataTable.Api( dt ),\n\n\t\tenable: true,\n\n\t\t/** @type {bool} Flag for if a draw is triggered by focus */\n\t\tfocusDraw: false,\n\n\t\t/** @type {bool} Flag to indicate when waiting for a draw to happen.\n\t\t  *   Will ignore key presses at this point\n\t\t  */\n\t\twaitingForDraw: false,\n\n\t\t/** @type {object} Information about the last cell that was focused */\n\t\tlastFocus: null\n\t};\n\n\t// DOM items\n\tthis.dom = {\n\n\t};\n\n\t// Check if row reorder has already been initialised on this table\n\tvar settings = this.s.dt.settings()[0];\n\tvar exisiting = settings.keytable;\n\tif ( exisiting ) {\n\t\treturn exisiting;\n\t}\n\n\tsettings.keytable = this;\n\tthis._constructor();\n};\n\n\n$.extend( KeyTable.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * API methods for DataTables API interface\n\t */\n\n\t/**\n\t * Blur the table's cell focus\n\t */\n\tblur: function ()\n\t{\n\t\tthis._blur();\n\t},\n\n\t/**\n\t * Enable cell focus for the table\n\t *\n\t * @param  {string} state Can be `true`, `false` or `-string navigation-only`\n\t */\n\tenable: function ( state )\n\t{\n\t\tthis.s.enable = state;\n\t},\n\n\t/**\n\t * Focus on a cell\n\t * @param  {integer} row    Row index\n\t * @param  {integer} column Column index\n\t */\n\tfocus: function ( row, column )\n\t{\n\t\tthis._focus( this.s.dt.cell( row, column ) );\n\t},\n\n\t/**\n\t * Is the cell focused\n\t * @param  {object} cell Cell index to check\n\t * @returns {boolean} true if focused, false otherwise\n\t */\n\tfocused: function ( cell )\n\t{\n\t\tvar lastFocus = this.s.lastFocus;\n\n\t\tif ( ! lastFocus ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tvar lastIdx = this.s.lastFocus.cell.index();\n\t\treturn cell.row === lastIdx.row && cell.column === lastIdx.column;\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\n\t/**\n\t * Initialise the KeyTable instance\n\t *\n\t * @private\n\t */\n\t_constructor: function ()\n\t{\n\t\tthis._tabInput();\n\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar table = $( dt.table().node() );\n\n\t\t// Need to be able to calculate the cell positions relative to the table\n\t\tif ( table.css('position') === 'static' ) {\n\t\t\ttable.css( 'position', 'relative' );\n\t\t}\n\n\t\t// Click to focus\n\t\t$( dt.table().body() ).on( 'click.keyTable', 'th, td', function (e) {\n\t\t\tif ( that.s.enable === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar cell = dt.cell( this );\n\n\t\t\tif ( ! cell.any() ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthat._focus( cell, null, false, e );\n\t\t} );\n\n\t\t// Key events\n\t\t$( document ).on( 'keydown.keyTable', function (e) {\n\t\t\tthat._key( e );\n\t\t} );\n\n\t\t// Click blur\n\t\tif ( this.c.blurable ) {\n\t\t\t$( document ).on( 'mousedown.keyTable', function ( e ) {\n\t\t\t\t// Click on the search input will blur focus\n\t\t\t\tif ( $(e.target).parents( '.dataTables_filter' ).length ) {\n\t\t\t\t\tthat._blur();\n\t\t\t\t}\n\n\t\t\t\t// If the click was inside the DataTables container, don't blur\n\t\t\t\tif ( $(e.target).parents().filter( dt.table().container() ).length ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Don't blur in Editor form\n\t\t\t\tif ( $(e.target).parents('div.DTE').length ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Or an Editor date input\n\t\t\t\tif ( $(e.target).parents('div.editor-datetime').length ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t//If the click was inside the fixed columns container, don't blur\n\t\t\t\tif ( $(e.target).parents().filter('.DTFC_Cloned').length ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthat._blur();\n\t\t\t} );\n\t\t}\n\n\t\tif ( this.c.editor ) {\n\t\t\tvar editor = this.c.editor;\n\n\t\t\t// Need to disable KeyTable when the main editor is shown\n\t\t\teditor.on( 'open.keyTableMain', function (e, mode, action) {\n\t\t\t\tif ( mode !== 'inline' && that.s.enable ) {\n\t\t\t\t\tthat.enable( false );\n\n\t\t\t\t\teditor.one( 'close.keyTable', function () {\n\t\t\t\t\t\tthat.enable( true );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tif ( this.c.editOnFocus ) {\n\t\t\t\tdt.on( 'key-focus.keyTable key-refocus.keyTable', function ( e, dt, cell, orig ) {\n\t\t\t\t\tthat._editor( null, orig, true );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// Activate Editor when a key is pressed (will be ignored, if\n\t\t\t// already active).\n\t\t\tdt.on( 'key.keyTable', function ( e, dt, key, cell, orig ) {\n\t\t\t\tthat._editor( key, orig, false );\n\t\t\t} );\n\n\t\t\t// Active editing on double click - it will already have focus from\n\t\t\t// the click event handler above\n\t\t\t$( dt.table().body() ).on( 'dblclick.keyTable', 'th, td', function (e) {\n\t\t\t\tif ( that.s.enable === false ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar cell = dt.cell( this );\n\n\t\t\t\tif ( ! cell.any() ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthat._editor( null, e, true );\n\t\t\t} );\n\t\t}\n\n\t\t// Stave saving\n\t\tif ( dt.settings()[0].oFeatures.bStateSave ) {\n\t\t\tdt.on( 'stateSaveParams.keyTable', function (e, s, d) {\n\t\t\t\td.keyTable = that.s.lastFocus ?\n\t\t\t\t\tthat.s.lastFocus.cell.index() :\n\t\t\t\t\tnull;\n\t\t\t} );\n\t\t}\n\n\t\t// Redraw - retain focus on the current cell\n\t\tdt.on( 'draw.keyTable', function (e) {\n\t\t\tif ( that.s.focusDraw ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar lastFocus = that.s.lastFocus;\n\n\t\t\tif ( lastFocus && lastFocus.node && $(lastFocus.node).closest('body') === document.body ) {\n\t\t\t\tvar relative = that.s.lastFocus.relative;\n\t\t\t\tvar info = dt.page.info();\n\t\t\t\tvar row = relative.row + info.start;\n\n\t\t\t\tif ( info.recordsDisplay === 0 ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Reverse if needed\n\t\t\t\tif ( row >= info.recordsDisplay ) {\n\t\t\t\t\trow = info.recordsDisplay - 1;\n\t\t\t\t}\n\n\t\t\t\tthat._focus( row, relative.column, true, e );\n\t\t\t}\n\t\t} );\n\n\t\t// Clipboard support\n\t\tif ( this.c.clipboard ) {\n\t\t\tthis._clipboard();\n\t\t}\n\n\t\tdt.on( 'destroy.keyTable', function () {\n\t\t\tdt.off( '.keyTable' );\n\t\t\t$( dt.table().body() ).off( 'click.keyTable', 'th, td' );\n\t\t\t$( document )\n\t\t\t\t.off( 'keydown.keyTable' )\n\t\t\t\t.off( 'click.keyTable' )\n\t\t\t\t.off( 'copy.keyTable' )\n\t\t\t\t.off( 'paste.keyTable' );\n\t\t} );\n\n\t\t// Initial focus comes from state or options\n\t\tvar state = dt.state.loaded();\n\n\t\tif ( state && state.keyTable ) {\n\t\t\t// Wait until init is done\n\t\t\tdt.one( 'init', function () {\n\t\t\t\tvar cell = dt.cell( state.keyTable );\n\n\t\t\t\t// Ensure that the saved cell still exists\n\t\t\t\tif ( cell.any() ) {\n\t\t\t\t\tcell.focus();\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\telse if ( this.c.focus ) {\n\t\t\tdt.cell( this.c.focus ).focus();\n\t\t}\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\n\t/**\n\t * Blur the control\n\t *\n\t * @private\n\t */\n\t_blur: function ()\n\t{\n\t\tif ( ! this.s.enable || ! this.s.lastFocus ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar cell = this.s.lastFocus.cell;\n\n\t\t$( cell.node() ).removeClass( this.c.className );\n\t\tthis.s.lastFocus = null;\n\n\t\tthis._updateFixedColumns(cell.index().column);\n\n\t\tthis._emitEvent( 'key-blur', [ this.s.dt, cell ] );\n\t},\n\n\n\t/**\n\t * Clipboard interaction handlers\n\t *\n\t * @private\n\t */\n\t_clipboard: function () {\n\t\tvar dt = this.s.dt;\n\t\tvar that = this;\n\n\t\t// IE8 doesn't support getting selected text\n\t\tif ( ! window.getSelection ) {\n\t\t\treturn;\n\t\t}\n\n\t\t$(document).on( 'copy.keyTable', function (ejq) {\n\t\t\tvar e = ejq.originalEvent;\n\t\t\tvar selection = window.getSelection().toString();\n\t\t\tvar focused = that.s.lastFocus;\n\n\t\t\t// Only copy cell text to clipboard if there is no other selection\n\t\t\t// and there is a focused cell\n\t\t\tif ( ! selection && focused ) {\n\t\t\t\te.clipboardData.setData(\n\t\t\t\t\t'text/plain',\n\t\t\t\t\tfocused.cell.render( that.c.clipboardOrthogonal )\n\t\t\t\t);\n\t\t\t\te.preventDefault();\n\t\t\t}\n\t\t} );\n\n\t\t$(document).on( 'paste.keyTable', function (ejq) {\n\t\t\tvar e = ejq.originalEvent;\n\t\t\tvar focused = that.s.lastFocus;\n\t\t\tvar activeEl = document.activeElement;\n\t\t\tvar editor = that.c.editor;\n\t\t\tvar pastedText;\n\n\t\t\tif ( focused && (! activeEl || activeEl.nodeName.toLowerCase() === 'body') ) {\n\t\t\t\te.preventDefault();\n\n\t\t\t\tif ( window.clipboardData && window.clipboardData.getData ) {\n\t\t\t\t\t// IE\n\t\t\t\t\tpastedText = window.clipboardData.getData('Text');\n\t\t\t\t}\n\t\t\t\telse if ( e.clipboardData && e.clipboardData.getData ) {\n\t\t\t\t\t// Everything else\n\t\t\t\t\tpastedText = e.clipboardData.getData('text/plain');\n\t\t\t\t}\n\n\t\t\t\tif ( editor ) {\n\t\t\t\t\t// Got Editor - need to activate inline editing,\n\t\t\t\t\t// set the value and submit\n\t\t\t\t\teditor\n\t\t\t\t\t\t.inline( focused.cell.index() )\n\t\t\t\t\t\t.set( editor.displayed()[0], pastedText )\n\t\t\t\t\t\t.submit();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// No editor, so just dump the data in\n\t\t\t\t\tfocused.cell.data( pastedText );\n\t\t\t\t\tdt.draw(false);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\n\t/**\n\t * Get an array of the column indexes that KeyTable can operate on. This\n\t * is a merge of the user supplied columns and the visible columns.\n\t *\n\t * @private\n\t */\n\t_columns: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar user = dt.columns( this.c.columns ).indexes();\n\t\tvar out = [];\n\n\t\tdt.columns( ':visible' ).every( function (i) {\n\t\t\tif ( user.indexOf( i ) !== -1 ) {\n\t\t\t\tout.push( i );\n\t\t\t}\n\t\t} );\n\n\t\treturn out;\n\t},\n\n\n\t/**\n\t * Perform excel like navigation for Editor by triggering an edit on key\n\t * press\n\t *\n\t * @param  {integer} key Key code for the pressed key\n\t * @param  {object} orig Original event\n\t * @private\n\t */\n\t_editor: function ( key, orig, hardEdit )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar editor = this.c.editor;\n\t\tvar editCell = this.s.lastFocus.cell;\n\n\t\t// Do nothing if there is already an inline edit in this cell\n\t\tif ( $('div.DTE', editCell.node()).length ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Don't activate Editor on control key presses\n\t\tif ( key !== null && (\n\t\t\t(key >= 0x00 && key <= 0x09) ||\n\t\t\tkey === 0x0b ||\n\t\t\tkey === 0x0c ||\n\t\t\t(key >= 0x0e && key <= 0x1f) ||\n\t\t\t(key >= 0x70 && key <= 0x7b) ||\n\t\t\t(key >= 0x7f && key <= 0x9f)\n\t\t) ) {\n\t\t\treturn;\n\t\t}\n\n\t\torig.stopPropagation();\n\n\t\t// Return key should do nothing - for textareas it would empty the\n\t\t// contents\n\t\tif ( key === 13 ) {\n\t\t\torig.preventDefault();\n\t\t}\n\n\t\tvar editInline = function () {\n\t\t\teditor\n\t\t\t\t.one( 'open.keyTable', function () {\n\t\t\t\t\t// Remove cancel open\n\t\t\t\t\teditor.off( 'cancelOpen.keyTable' );\n\n\t\t\t\t\t// Excel style - select all text\n\t\t\t\t\tif ( ! hardEdit ) {\n\t\t\t\t\t\t$('div.DTE_Field_InputControl input, div.DTE_Field_InputControl textarea').select();\n\t\t\t\t\t}\n\n\t\t\t\t\t// Reduce the keys the Keys listens for\n\t\t\t\t\tdt.keys.enable( hardEdit ? 'tab-only' : 'navigation-only' );\n\n\t\t\t\t\t// On blur of the navigation submit\n\t\t\t\t\tdt.on( 'key-blur.editor', function () {\n\t\t\t\t\t\tif ( editor.displayed() ) {\n\t\t\t\t\t\t\teditor.submit();\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\n\t\t\t\t\t// Highlight the cell a different colour on full edit\n\t\t\t\t\tif ( hardEdit ) {\n\t\t\t\t\t\t$( dt.table().container() ).addClass('dtk-focus-alt');\n\t\t\t\t\t}\n\n\t\t\t\t\teditor.on( 'submitUnsuccessful.keyTable', function () {\n\t\t\t\t\t\tthat._focus( editCell, null, false );\n\t\t\t\t\t} );\n\n\t\t\t\t\t// Restore full key navigation on close\n\t\t\t\t\teditor.one( 'close', function () {\n\t\t\t\t\t\tdt.keys.enable( true );\n\t\t\t\t\t\tdt.off( 'key-blur.editor' );\n\t\t\t\t\t\teditor.off( '.keyTable' );\n\t\t\t\t\t\t$( dt.table().container() ).removeClass('dtk-focus-alt');\n\t\t\t\t\t} );\n\t\t\t\t} )\n\t\t\t\t.one( 'cancelOpen.keyTable', function () {\n\t\t\t\t\t// `preOpen` can cancel the display of the form, so it\n\t\t\t\t\t// might be that the open event handler isn't needed\n\t\t\t\t\teditor.off( '.keyTable' );\n\t\t\t\t} )\n\t\t\t\t.inline( editCell.index() );\n\t\t};\n\n\t\t// Editor 1.7 listens for `return` on keyup, so if return is the trigger\n\t\t// key, we need to wait for `keyup` otherwise Editor would just submit\n\t\t// the content triggered by this keypress.\n\t\tif ( key === 13 ) {\n\t\t\thardEdit = true;\n\n\t\t\t$(document).one( 'keyup', function () { // immediately removed\n\t\t\t\teditInline();\n\t\t\t} );\n\t\t}\n\t\telse {\n\t\t\teditInline();\n\t\t}\n\t},\n\n\n\t/**\n\t * Emit an event on the DataTable for listeners\n\t *\n\t * @param  {string} name Event name\n\t * @param  {array} args Event arguments\n\t * @private\n\t */\n\t_emitEvent: function ( name, args )\n\t{\n\t\tthis.s.dt.iterator( 'table', function ( ctx, i ) {\n\t\t\t$(ctx.nTable).triggerHandler( name, args );\n\t\t} );\n\t},\n\n\n\t/**\n\t * Focus on a particular cell, shifting the table's paging if required\n\t *\n\t * @param  {DataTables.Api|integer} row Can be given as an API instance that\n\t *   contains the cell to focus or as an integer. As the latter it is the\n\t *   visible row index (from the whole data set) - NOT the data index\n\t * @param  {integer} [column] Not required if a cell is given as the first\n\t *   parameter. Otherwise this is the column data index for the cell to\n\t *   focus on\n\t * @param {boolean} [shift=true] Should the viewport be moved to show cell\n\t * @private\n\t */\n\t_focus: function ( row, column, shift, originalEvent )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar pageInfo = dt.page.info();\n\t\tvar lastFocus = this.s.lastFocus;\n\n\t\tif ( ! originalEvent) {\n\t\t\toriginalEvent = null;\n\t\t}\n\n\t\tif ( ! this.s.enable ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( typeof row !== 'number' ) {\n\t\t\t// Its an API instance - check that there is actually a row\n\t\t\tif ( ! row.any() ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Convert the cell to a row and column\n\t\t\tvar index = row.index();\n\t\t\tcolumn = index.column;\n\t\t\trow = dt\n\t\t\t\t.rows( { filter: 'applied', order: 'applied' } )\n\t\t\t\t.indexes()\n\t\t\t\t.indexOf( index.row );\n\t\t\t\n\t\t\t// Don't focus rows that were filtered out.\n\t\t\tif ( row < 0 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// For server-side processing normalise the row by adding the start\n\t\t\t// point, since `rows().indexes()` includes only rows that are\n\t\t\t// available at the client-side\n\t\t\tif ( pageInfo.serverSide ) {\n\t\t\t\trow += pageInfo.start;\n\t\t\t}\n\t\t}\n\n\t\t// Is the row on the current page? If not, we need to redraw to show the\n\t\t// page\n\t\tif ( pageInfo.length !== -1 && (row < pageInfo.start || row >= pageInfo.start+pageInfo.length) ) {\n\t\t\tthis.s.focusDraw = true;\n\t\t\tthis.s.waitingForDraw = true;\n\n\t\t\tdt\n\t\t\t\t.one( 'draw', function () {\n\t\t\t\t\tthat.s.focusDraw = false;\n\t\t\t\t\tthat.s.waitingForDraw = false;\n\t\t\t\t\tthat._focus( row, column, undefined, originalEvent );\n\t\t\t\t} )\n\t\t\t\t.page( Math.floor( row / pageInfo.length ) )\n\t\t\t\t.draw( false );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// In the available columns?\n\t\tif ( $.inArray( column, this._columns() ) === -1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// De-normalise the server-side processing row, so we select the row\n\t\t// in its displayed position\n\t\tif ( pageInfo.serverSide ) {\n\t\t\trow -= pageInfo.start;\n\t\t}\n\n\t\t// Get the cell from the current position - ignoring any cells which might\n\t\t// not have been rendered (therefore can't use `:eq()` selector).\n\t\tvar cells = dt.cells( null, column, {search: 'applied', order: 'applied'} ).flatten();\n\t\tvar cell = dt.cell( cells[ row ] );\n\n\t\tif ( lastFocus ) {\n\t\t\t// Don't trigger a refocus on the same cell\n\t\t\tif ( lastFocus.node === cell.node() ) {\n\t\t\t\tthis._emitEvent( 'key-refocus', [ this.s.dt, cell, originalEvent || null ] );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Otherwise blur the old focus\n\t\t\tthis._blur();\n\t\t}\n\n\t\tvar node = $( cell.node() );\n\t\tnode.addClass( this.c.className );\n\n\t\tthis._updateFixedColumns(column);\n\n\t\t// Shift viewpoint and page to make cell visible\n\t\tif ( shift === undefined || shift === true ) {\n\t\t\tthis._scroll( $(window), $(document.body), node, 'offset' );\n\n\t\t\tvar bodyParent = dt.table().body().parentNode;\n\t\t\tif ( bodyParent !== dt.table().header().parentNode ) {\n\t\t\t\tvar parent = $(bodyParent.parentNode);\n\n\t\t\t\tthis._scroll( parent, parent, node, 'position' );\n\t\t\t}\n\t\t}\n\n\t\t// Event and finish\n\t\tthis.s.lastFocus = {\n\t\t\tcell: cell,\n\t\t\tnode: cell.node(),\n\t\t\trelative: {\n\t\t\t\trow: dt.rows( { page: 'current' } ).indexes().indexOf( cell.index().row ),\n\t\t\t\tcolumn: cell.index().column\n\t\t\t}\n\t\t};\n\n\t\tthis._emitEvent( 'key-focus', [ this.s.dt, cell, originalEvent || null ] );\n\t\tdt.state.save();\n\t},\n\n\n\t/**\n\t * Handle key press\n\t *\n\t * @param  {object} e Event\n\t * @private\n\t */\n\t_key: function ( e )\n\t{\n\t\t// If we are waiting for a draw to happen from another key event, then\n\t\t// do nothing for this new key press.\n\t\tif ( this.s.waitingForDraw ) {\n\t\t\te.preventDefault();\n\t\t\treturn;\n\t\t}\n\n\t\tvar enable = this.s.enable;\n\t\tvar navEnable = enable === true || enable === 'navigation-only';\n\t\tif ( ! enable ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( (e.keyCode === 0 || e.ctrlKey || e.metaKey || e.altKey) && !(e.ctrlKey && e.altKey) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If not focused, then there is no key action to take\n\t\tvar lastFocus = this.s.lastFocus;\n\t\tif ( ! lastFocus ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar scrolling = this.s.dt.settings()[0].oScroll.sY ? true : false;\n\n\t\t// If we are not listening for this key, do nothing\n\t\tif ( this.c.keys && $.inArray( e.keyCode, this.c.keys ) === -1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tswitch( e.keyCode ) {\n\t\t\tcase 9: // tab\n\t\t\t\t// `enable` can be tab-only\n\t\t\t\tthis._shift( e, e.shiftKey ? 'left' : 'right', true );\n\t\t\t\tbreak;\n\n\t\t\tcase 27: // esc\n\t\t\t\tif ( this.s.blurable && enable === true ) {\n\t\t\t\t\tthis._blur();\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 33: // page up (previous page)\n\t\t\tcase 34: // page down (next page)\n\t\t\t\tif ( navEnable && !scrolling ) {\n\t\t\t\t\te.preventDefault();\n\n\t\t\t\t\tdt\n\t\t\t\t\t\t.page( e.keyCode === 33 ? 'previous' : 'next' )\n\t\t\t\t\t\t.draw( false );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 35: // end (end of current page)\n\t\t\tcase 36: // home (start of current page)\n\t\t\t\tif ( navEnable ) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tvar indexes = dt.cells( {page: 'current'} ).indexes();\n\t\t\t\t\tvar colIndexes = this._columns();\n\n\t\t\t\t\tthis._focus( dt.cell(\n\t\t\t\t\t\tindexes[ e.keyCode === 35 ? indexes.length-1 : colIndexes[0] ]\n\t\t\t\t\t), null, true, e );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 37: // left arrow\n\t\t\t\tif ( navEnable ) {\n\t\t\t\t\tthis._shift( e, 'left' );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 38: // up arrow\n\t\t\t\tif ( navEnable ) {\n\t\t\t\t\tthis._shift( e, 'up' );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 39: // right arrow\n\t\t\t\tif ( navEnable ) {\n\t\t\t\t\tthis._shift( e, 'right' );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 40: // down arrow\n\t\t\t\tif ( navEnable ) {\n\t\t\t\t\tthis._shift( e, 'down' );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\t// Everything else - pass through only when fully enabled\n\t\t\t\tif ( enable === true ) {\n\t\t\t\t\tthis._emitEvent( 'key', [ dt, e.keyCode, this.s.lastFocus.cell, e ] );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t},\n\n\n\t/**\n\t * Scroll a container to make a cell visible in it. This can be used for\n\t * both DataTables scrolling and native window scrolling.\n\t *\n\t * @param  {jQuery} container Scrolling container\n\t * @param  {jQuery} scroller  Item being scrolled\n\t * @param  {jQuery} cell      Cell in the scroller\n\t * @param  {string} posOff    `position` or `offset` - which to use for the\n\t *   calculation. `offset` for the document, otherwise `position`\n\t * @private\n\t */\n\t_scroll: function ( container, scroller, cell, posOff )\n\t{\n\t\tvar offset = cell[posOff]();\n\t\tvar height = cell.outerHeight();\n\t\tvar width = cell.outerWidth();\n\n\t\tvar scrollTop = scroller.scrollTop();\n\t\tvar scrollLeft = scroller.scrollLeft();\n\t\tvar containerHeight = container.height();\n\t\tvar containerWidth = container.width();\n\n\t\t// If Scroller is being used, the table can be `position: absolute` and that\n\t\t// needs to be taken account of in the offset. If no Scroller, this will be 0\n\t\tif ( posOff === 'position' ) {\n\t\t\toffset.top += parseInt( cell.closest('table').css('top'), 10 );\n\t\t}\n\n\t\t// Top correction\n\t\tif ( offset.top < scrollTop ) {\n\t\t\tscroller.scrollTop( offset.top );\n\t\t}\n\n\t\t// Left correction\n\t\tif ( offset.left < scrollLeft ) {\n\t\t\tscroller.scrollLeft( offset.left );\n\t\t}\n\n\t\t// Bottom correction\n\t\tif ( offset.top + height > scrollTop + containerHeight && height < containerHeight ) {\n\t\t\tscroller.scrollTop( offset.top + height - containerHeight );\n\t\t}\n\n\t\t// Right correction\n\t\tif ( offset.left + width > scrollLeft + containerWidth && width < containerWidth ) {\n\t\t\tscroller.scrollLeft( offset.left + width - containerWidth );\n\t\t}\n\t},\n\n\n\t/**\n\t * Calculate a single offset movement in the table - up, down, left and\n\t * right and then perform the focus if possible\n\t *\n\t * @param  {object}  e           Event object\n\t * @param  {string}  direction   Movement direction\n\t * @param  {boolean} keyBlurable `true` if the key press can result in the\n\t *   table being blurred. This is so arrow keys won't blur the table, but\n\t *   tab will.\n\t * @private\n\t */\n\t_shift: function ( e, direction, keyBlurable )\n\t{\n\t\tvar that         = this;\n\t\tvar dt           = this.s.dt;\n\t\tvar pageInfo     = dt.page.info();\n\t\tvar rows         = pageInfo.recordsDisplay;\n\t\tvar currentCell  = this.s.lastFocus.cell;\n\t\tvar columns      = this._columns();\n\n\t\tif ( ! currentCell ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar currRow = dt\n\t\t\t.rows( { filter: 'applied', order: 'applied' } )\n\t\t\t.indexes()\n\t\t\t.indexOf( currentCell.index().row );\n\n\t\t// When server-side processing, `rows().indexes()` only gives the rows\n\t\t// that are available at the client-side, so we need to normalise the\n\t\t// row's current position by the display start point\n\t\tif ( pageInfo.serverSide ) {\n\t\t\tcurrRow += pageInfo.start;\n\t\t}\n\n\t\tvar currCol = dt\n\t\t\t.columns( columns )\n\t\t\t.indexes()\n\t\t\t.indexOf( currentCell.index().column );\n\n\t\tvar\n\t\t\trow = currRow,\n\t\t\tcolumn = columns[ currCol ]; // row is the display, column is an index\n\n\t\tif ( direction === 'right' ) {\n\t\t\tif ( currCol >= columns.length - 1 ) {\n\t\t\t\trow++;\n\t\t\t\tcolumn = columns[0];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcolumn = columns[ currCol+1 ];\n\t\t\t}\n\t\t}\n\t\telse if ( direction === 'left' ) {\n\t\t\tif ( currCol === 0 ) {\n\t\t\t\trow--;\n\t\t\t\tcolumn = columns[ columns.length - 1 ];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcolumn = columns[ currCol-1 ];\n\t\t\t}\n\t\t}\n\t\telse if ( direction === 'up' ) {\n\t\t\trow--;\n\t\t}\n\t\telse if ( direction === 'down' ) {\n\t\t\trow++;\n\t\t}\n\n\t\tif ( row >= 0 && row < rows && $.inArray( column, columns ) !== -1\n\t\t) {\n\t\t\te.preventDefault();\n\n\t\t\tthis._focus( row, column, true, e );\n\t\t}\n\t\telse if ( ! keyBlurable || ! this.c.blurable ) {\n\t\t\t// No new focus, but if the table isn't blurable, then don't loose\n\t\t\t// focus\n\t\t\te.preventDefault();\n\t\t}\n\t\telse {\n\t\t\tthis._blur();\n\t\t}\n\t},\n\n\n\t/**\n\t * Create a hidden input element that can receive focus on behalf of the\n\t * table\n\t *\n\t * @private\n\t */\n\t_tabInput: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar tabIndex = this.c.tabIndex !== null ?\n\t\t\tthis.c.tabIndex :\n\t\t\tdt.settings()[0].iTabIndex;\n\n\t\tif ( tabIndex == -1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar div = $('<div><input type=\"text\" tabindex=\"'+tabIndex+'\"/></div>')\n\t\t\t.css( {\n\t\t\t\tposition: 'absolute',\n\t\t\t\theight: 1,\n\t\t\t\twidth: 0,\n\t\t\t\toverflow: 'hidden'\n\t\t\t} )\n\t\t\t.insertBefore( dt.table().node() );\n\n\t\tdiv.children().on( 'focus', function (e) {\n\t\t\tif ( dt.cell(':eq(0)', {page: 'current'}).any() ) {\n\t\t\t\tthat._focus( dt.cell(':eq(0)', '0:visible', {page: 'current'}), null, true, e );\n\t\t\t}\n\t\t} );\n\t},\n\n\t/**\n\t * Update fixed columns if they are enabled and if the cell we are\n\t * focusing is inside a fixed column\n\t * @param  {integer} column Index of the column being changed\n\t * @private\n\t */\n\t_updateFixedColumns: function( column )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar settings = dt.settings()[0];\n\n\t\tif ( settings._oFixedColumns ) {\n\t\t\tvar leftCols = settings._oFixedColumns.s.iLeftColumns;\n\t\t\tvar rightCols = settings.aoColumns.length - settings._oFixedColumns.s.iRightColumns;\n\n\t\t\tif (column < leftCols || column >= rightCols) {\n\t\t\t\tdt.fixedColumns().update();\n\t\t\t}\n\t\t}\n\t}\n} );\n\n\n/**\n * KeyTable default settings for initialisation\n *\n * @namespace\n * @name KeyTable.defaults\n * @static\n */\nKeyTable.defaults = {\n\t/**\n\t * Can focus be removed from the table\n\t * @type {Boolean}\n\t */\n\tblurable: true,\n\n\t/**\n\t * Class to give to the focused cell\n\t * @type {String}\n\t */\n\tclassName: 'focus',\n\n\t/**\n\t * Enable or disable clipboard support\n\t * @type {Boolean}\n\t */\n\tclipboard: true,\n\n\t/**\n\t * Orthogonal data that should be copied to clipboard\n\t * @type {string}\n\t */\n\tclipboardOrthogonal: 'display',\n\n\t/**\n\t * Columns that can be focused. This is automatically merged with the\n\t * visible columns as only visible columns can gain focus.\n\t * @type {String}\n\t */\n\tcolumns: '', // all\n\n\t/**\n\t * Editor instance to automatically perform Excel like navigation\n\t * @type {Editor}\n\t */\n\teditor: null,\n\n\t/**\n\t * Trigger editing immediately on focus\n\t * @type {boolean}\n\t */\n\teditOnFocus: false,\n\n\t/**\n\t * Select a cell to automatically select on start up. `null` for no\n\t * automatic selection\n\t * @type {cell-selector}\n\t */\n\tfocus: null,\n\n\t/**\n\t * Array of keys to listen for\n\t * @type {null|array}\n\t */\n\tkeys: null,\n\n\t/**\n\t * Tab index for where the table should sit in the document's tab flow\n\t * @type {integer|null}\n\t */\n\ttabIndex: null\n};\n\n\n\nKeyTable.version = \"2.5.0\";\n\n\n$.fn.dataTable.KeyTable = KeyTable;\n$.fn.DataTable.KeyTable = KeyTable;\n\n\nDataTable.Api.register( 'cell.blur()', function () {\n\treturn this.iterator( 'table', function (ctx) {\n\t\tif ( ctx.keytable ) {\n\t\t\tctx.keytable.blur();\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'cell().focus()', function () {\n\treturn this.iterator( 'cell', function (ctx, row, column) {\n\t\tif ( ctx.keytable ) {\n\t\t\tctx.keytable.focus( row, column );\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'keys.disable()', function () {\n\treturn this.iterator( 'table', function (ctx) {\n\t\tif ( ctx.keytable ) {\n\t\t\tctx.keytable.enable( false );\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'keys.enable()', function ( opts ) {\n\treturn this.iterator( 'table', function (ctx) {\n\t\tif ( ctx.keytable ) {\n\t\t\tctx.keytable.enable( opts === undefined ? true : opts );\n\t\t}\n\t} );\n} );\n\n// Cell selector\nDataTable.ext.selector.cell.push( function ( settings, opts, cells ) {\n\tvar focused = opts.focused;\n\tvar kt = settings.keytable;\n\tvar out = [];\n\n\tif ( ! kt || focused === undefined ) {\n\t\treturn cells;\n\t}\n\n\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\tif ( (focused === true &&  kt.focused( cells[i] ) ) ||\n\t\t\t (focused === false && ! kt.focused( cells[i] ) )\n\t\t) {\n\t\t\tout.push( cells[i] );\n\t\t}\n\t}\n\n\treturn out;\n} );\n\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'preInit.dt.dtk', function (e, settings, json) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.keys;\n\tvar defaults = DataTable.defaults.keys;\n\n\tif ( init || defaults ) {\n\t\tvar opts = $.extend( {}, defaults, init );\n\n\t\tif ( init !== false ) {\n\t\t\tnew KeyTable( settings, opts  );\n\t\t}\n\t}\n} );\n\n\nreturn KeyTable;\n}));\n\n\n/*! Responsive 2.2.2\n * 2014-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     Responsive\n * @description Responsive tables plug-in for DataTables\n * @version     2.2.2\n * @file        dataTables.responsive.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2014-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/**\n * Responsive is a plug-in for the DataTables library that makes use of\n * DataTables' ability to change the visibility of columns, changing the\n * visibility of columns so the displayed columns fit into the table container.\n * The end result is that complex tables will be dynamically adjusted to fit\n * into the viewport, be it on a desktop, tablet or mobile browser.\n *\n * Responsive for DataTables has two modes of operation, which can used\n * individually or combined:\n *\n * * Class name based control - columns assigned class names that match the\n *   breakpoint logic can be shown / hidden as required for each breakpoint.\n * * Automatic control - columns are automatically hidden when there is no\n *   room left to display them. Columns removed from the right.\n *\n * In additional to column visibility control, Responsive also has built into\n * options to use DataTables' child row display to show / hide the information\n * from the table that has been hidden. There are also two modes of operation\n * for this child row display:\n *\n * * Inline - when the control element that the user can use to show / hide\n *   child rows is displayed inside the first column of the table.\n * * Column - where a whole column is dedicated to be the show / hide control.\n *\n * Initialisation of Responsive is performed by:\n *\n * * Adding the class `responsive` or `dt-responsive` to the table. In this case\n *   Responsive will automatically be initialised with the default configuration\n *   options when the DataTable is created.\n * * Using the `responsive` option in the DataTables configuration options. This\n *   can also be used to specify the configuration options, or simply set to\n *   `true` to use the defaults.\n *\n *  @class\n *  @param {object} settings DataTables settings object for the host table\n *  @param {object} [opts] Configuration options\n *  @requires jQuery 1.7+\n *  @requires DataTables 1.10.3+\n *\n *  @example\n *      $('#example').DataTable( {\n *        responsive: true\n *      } );\n *    } );\n */\nvar Responsive = function ( settings, opts ) {\n\t// Sanity check that we are using DataTables 1.10 or newer\n\tif ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.10' ) ) {\n\t\tthrow 'DataTables Responsive requires DataTables 1.10.10 or newer';\n\t}\n\n\tthis.s = {\n\t\tdt: new DataTable.Api( settings ),\n\t\tcolumns: [],\n\t\tcurrent: []\n\t};\n\n\t// Check if responsive has already been initialised on this table\n\tif ( this.s.dt.settings()[0].responsive ) {\n\t\treturn;\n\t}\n\n\t// details is an object, but for simplicity the user can give it as a string\n\t// or a boolean\n\tif ( opts && typeof opts.details === 'string' ) {\n\t\topts.details = { type: opts.details };\n\t}\n\telse if ( opts && opts.details === false ) {\n\t\topts.details = { type: false };\n\t}\n\telse if ( opts && opts.details === true ) {\n\t\topts.details = { type: 'inline' };\n\t}\n\n\tthis.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts );\n\tsettings.responsive = this;\n\tthis._constructor();\n};\n\n$.extend( Responsive.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\n\t/**\n\t * Initialise the Responsive instance\n\t *\n\t * @private\n\t */\n\t_constructor: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar dtPrivateSettings = dt.settings()[0];\n\t\tvar oldWindowWidth = $(window).width();\n\n\t\tdt.settings()[0]._responsive = this;\n\n\t\t// Use DataTables' throttle function to avoid processor thrashing on\n\t\t// resize\n\t\t$(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () {\n\t\t\t// iOS has a bug whereby resize can fire when only scrolling\n\t\t\t// See: http://stackoverflow.com/questions/8898412\n\t\t\tvar width = $(window).width();\n\n\t\t\tif ( width !== oldWindowWidth ) {\n\t\t\t\tthat._resize();\n\t\t\t\toldWindowWidth = width;\n\t\t\t}\n\t\t} ) );\n\n\t\t// DataTables doesn't currently trigger an event when a row is added, so\n\t\t// we need to hook into its private API to enforce the hidden rows when\n\t\t// new data is added\n\t\tdtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) {\n\t\t\tif ( $.inArray( false, that.s.current ) !== -1 ) {\n\t\t\t\t$('>td, >th', tr).each( function ( i ) {\n\t\t\t\t\tvar idx = dt.column.index( 'toData', i );\n\n\t\t\t\t\tif ( that.s.current[idx] === false ) {\n\t\t\t\t\t\t$(this).css('display', 'none');\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\t// Destroy event handler\n\t\tdt.on( 'destroy.dtr', function () {\n\t\t\tdt.off( '.dtr' );\n\t\t\t$( dt.table().body() ).off( '.dtr' );\n\t\t\t$(window).off( 'resize.dtr orientationchange.dtr' );\n\n\t\t\t// Restore the columns that we've hidden\n\t\t\t$.each( that.s.current, function ( i, val ) {\n\t\t\t\tif ( val === false ) {\n\t\t\t\t\tthat._setColumnVis( i, true );\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\n\t\t// Reorder the breakpoints array here in case they have been added out\n\t\t// of order\n\t\tthis.c.breakpoints.sort( function (a, b) {\n\t\t\treturn a.width < b.width ? 1 :\n\t\t\t\ta.width > b.width ? -1 : 0;\n\t\t} );\n\n\t\tthis._classLogic();\n\t\tthis._resizeAuto();\n\n\t\t// Details handler\n\t\tvar details = this.c.details;\n\n\t\tif ( details.type !== false ) {\n\t\t\tthat._detailsInit();\n\n\t\t\t// DataTables will trigger this event on every column it shows and\n\t\t\t// hides individually\n\t\t\tdt.on( 'column-visibility.dtr', function () {\n\t\t\t\t// Use a small debounce to allow multiple columns to be set together\n\t\t\t\tif ( that._timer ) {\n\t\t\t\t\tclearTimeout( that._timer );\n\t\t\t\t}\n\n\t\t\t\tthat._timer = setTimeout( function () {\n\t\t\t\t\tthat._timer = null;\n\n\t\t\t\t\tthat._classLogic();\n\t\t\t\t\tthat._resizeAuto();\n\t\t\t\t\tthat._resize();\n\n\t\t\t\t\tthat._redrawChildren();\n\t\t\t\t}, 100 );\n\t\t\t} );\n\n\t\t\t// Redraw the details box on each draw which will happen if the data\n\t\t\t// has changed. This is used until DataTables implements a native\n\t\t\t// `updated` event for rows\n\t\t\tdt.on( 'draw.dtr', function () {\n\t\t\t\tthat._redrawChildren();\n\t\t\t} );\n\n\t\t\t$(dt.table().node()).addClass( 'dtr-'+details.type );\n\t\t}\n\n\t\tdt.on( 'column-reorder.dtr', function (e, settings, details) {\n\t\t\tthat._classLogic();\n\t\t\tthat._resizeAuto();\n\t\t\tthat._resize();\n\t\t} );\n\n\t\t// Change in column sizes means we need to calc\n\t\tdt.on( 'column-sizing.dtr', function () {\n\t\t\tthat._resizeAuto();\n\t\t\tthat._resize();\n\t\t});\n\n\t\t// On Ajax reload we want to reopen any child rows which are displayed\n\t\t// by responsive\n\t\tdt.on( 'preXhr.dtr', function () {\n\t\t\tvar rowIds = [];\n\t\t\tdt.rows().every( function () {\n\t\t\t\tif ( this.child.isShown() ) {\n\t\t\t\t\trowIds.push( this.id(true) );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tdt.one( 'draw.dtr', function () {\n\t\t\t\tthat._resizeAuto();\n\t\t\t\tthat._resize();\n\n\t\t\t\tdt.rows( rowIds ).every( function () {\n\t\t\t\t\tthat._detailsDisplay( this, false );\n\t\t\t\t} );\n\t\t\t} );\n\t\t});\n\n\t\tdt.on( 'init.dtr', function (e, settings, details) {\n\t\t\tthat._resizeAuto();\n\t\t\tthat._resize();\n\n\t\t\t// If columns were hidden, then DataTables needs to adjust the\n\t\t\t// column sizing\n\t\t\tif ( $.inArray( false, that.s.current ) ) {\n\t\t\t\tdt.columns.adjust();\n\t\t\t}\n\t\t} );\n\n\t\t// First pass - draw the table for the current viewport size\n\t\tthis._resize();\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\n\t/**\n\t * Calculate the visibility for the columns in a table for a given\n\t * breakpoint. The result is pre-determined based on the class logic if\n\t * class names are used to control all columns, but the width of the table\n\t * is also used if there are columns which are to be automatically shown\n\t * and hidden.\n\t *\n\t * @param  {string} breakpoint Breakpoint name to use for the calculation\n\t * @return {array} Array of boolean values initiating the visibility of each\n\t *   column.\n\t *  @private\n\t */\n\t_columnsVisiblity: function ( breakpoint )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar columns = this.s.columns;\n\t\tvar i, ien;\n\n\t\t// Create an array that defines the column ordering based first on the\n\t\t// column's priority, and secondly the column index. This allows the\n\t\t// columns to be removed from the right if the priority matches\n\t\tvar order = columns\n\t\t\t.map( function ( col, idx ) {\n\t\t\t\treturn {\n\t\t\t\t\tcolumnIdx: idx,\n\t\t\t\t\tpriority: col.priority\n\t\t\t\t};\n\t\t\t} )\n\t\t\t.sort( function ( a, b ) {\n\t\t\t\tif ( a.priority !== b.priority ) {\n\t\t\t\t\treturn a.priority - b.priority;\n\t\t\t\t}\n\t\t\t\treturn a.columnIdx - b.columnIdx;\n\t\t\t} );\n\n\t\t// Class logic - determine which columns are in this breakpoint based\n\t\t// on the classes. If no class control (i.e. `auto`) then `-` is used\n\t\t// to indicate this to the rest of the function\n\t\tvar display = $.map( columns, function ( col, i ) {\n\t\t\tif ( dt.column(i).visible() === false ) {\n\t\t\t\treturn 'not-visible';\n\t\t\t}\n\t\t\treturn col.auto && col.minWidth === null ?\n\t\t\t\tfalse :\n\t\t\t\tcol.auto === true ?\n\t\t\t\t\t'-' :\n\t\t\t\t\t$.inArray( breakpoint, col.includeIn ) !== -1;\n\t\t} );\n\n\t\t// Auto column control - first pass: how much width is taken by the\n\t\t// ones that must be included from the non-auto columns\n\t\tvar requiredWidth = 0;\n\t\tfor ( i=0, ien=display.length ; i<ien ; i++ ) {\n\t\t\tif ( display[i] === true ) {\n\t\t\t\trequiredWidth += columns[i].minWidth;\n\t\t\t}\n\t\t}\n\n\t\t// Second pass, use up any remaining width for other columns. For\n\t\t// scrolling tables we need to subtract the width of the scrollbar. It\n\t\t// may not be requires which makes this sub-optimal, but it would\n\t\t// require another full redraw to make complete use of those extra few\n\t\t// pixels\n\t\tvar scrolling = dt.settings()[0].oScroll;\n\t\tvar bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0;\n\t\tvar widthAvailable = dt.table().container().offsetWidth - bar;\n\t\tvar usedWidth = widthAvailable - requiredWidth;\n\n\t\t// Control column needs to always be included. This makes it sub-\n\t\t// optimal in terms of using the available with, but to stop layout\n\t\t// thrashing or overflow. Also we need to account for the control column\n\t\t// width first so we know how much width is available for the other\n\t\t// columns, since the control column might not be the first one shown\n\t\tfor ( i=0, ien=display.length ; i<ien ; i++ ) {\n\t\t\tif ( columns[i].control ) {\n\t\t\t\tusedWidth -= columns[i].minWidth;\n\t\t\t}\n\t\t}\n\n\t\t// Allow columns to be shown (counting by priority and then right to\n\t\t// left) until we run out of room\n\t\tvar empty = false;\n\t\tfor ( i=0, ien=order.length ; i<ien ; i++ ) {\n\t\t\tvar colIdx = order[i].columnIdx;\n\n\t\t\tif ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) {\n\t\t\t\t// Once we've found a column that won't fit we don't let any\n\t\t\t\t// others display either, or columns might disappear in the\n\t\t\t\t// middle of the table\n\t\t\t\tif ( empty || usedWidth - columns[colIdx].minWidth < 0 ) {\n\t\t\t\t\tempty = true;\n\t\t\t\t\tdisplay[colIdx] = false;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdisplay[colIdx] = true;\n\t\t\t\t}\n\n\t\t\t\tusedWidth -= columns[colIdx].minWidth;\n\t\t\t}\n\t\t}\n\n\t\t// Determine if the 'control' column should be shown (if there is one).\n\t\t// This is the case when there is a hidden column (that is not the\n\t\t// control column). The two loops look inefficient here, but they are\n\t\t// trivial and will fly through. We need to know the outcome from the\n\t\t// first , before the action in the second can be taken\n\t\tvar showControl = false;\n\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tif ( ! columns[i].control && ! columns[i].never && display[i] === false ) {\n\t\t\t\tshowControl = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tif ( columns[i].control ) {\n\t\t\t\tdisplay[i] = showControl;\n\t\t\t}\n\n\t\t\t// Replace not visible string with false from the control column detection above\n\t\t\tif ( display[i] === 'not-visible' ) {\n\t\t\t\tdisplay[i] = false;\n\t\t\t}\n\t\t}\n\n\t\t// Finally we need to make sure that there is at least one column that\n\t\t// is visible\n\t\tif ( $.inArray( true, display ) === -1 ) {\n\t\t\tdisplay[0] = true;\n\t\t}\n\n\t\treturn display;\n\t},\n\n\n\t/**\n\t * Create the internal `columns` array with information about the columns\n\t * for the table. This includes determining which breakpoints the column\n\t * will appear in, based upon class names in the column, which makes up the\n\t * vast majority of this method.\n\t *\n\t * @private\n\t */\n\t_classLogic: function ()\n\t{\n\t\tvar that = this;\n\t\tvar calc = {};\n\t\tvar breakpoints = this.c.breakpoints;\n\t\tvar dt = this.s.dt;\n\t\tvar columns = dt.columns().eq(0).map( function (i) {\n\t\t\tvar column = this.column(i);\n\t\t\tvar className = column.header().className;\n\t\t\tvar priority = dt.settings()[0].aoColumns[i].responsivePriority;\n\n\t\t\tif ( priority === undefined ) {\n\t\t\t\tvar dataPriority = $(column.header()).data('priority');\n\n\t\t\t\tpriority = dataPriority !== undefined ?\n\t\t\t\t\tdataPriority * 1 :\n\t\t\t\t\t10000;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tclassName: className,\n\t\t\t\tincludeIn: [],\n\t\t\t\tauto:      false,\n\t\t\t\tcontrol:   false,\n\t\t\t\tnever:     className.match(/\\bnever\\b/) ? true : false,\n\t\t\t\tpriority:  priority\n\t\t\t};\n\t\t} );\n\n\t\t// Simply add a breakpoint to `includeIn` array, ensuring that there are\n\t\t// no duplicates\n\t\tvar add = function ( colIdx, name ) {\n\t\t\tvar includeIn = columns[ colIdx ].includeIn;\n\n\t\t\tif ( $.inArray( name, includeIn ) === -1 ) {\n\t\t\t\tincludeIn.push( name );\n\t\t\t}\n\t\t};\n\n\t\tvar column = function ( colIdx, name, operator, matched ) {\n\t\t\tvar size, i, ien;\n\n\t\t\tif ( ! operator ) {\n\t\t\t\tcolumns[ colIdx ].includeIn.push( name );\n\t\t\t}\n\t\t\telse if ( operator === 'max-' ) {\n\t\t\t\t// Add this breakpoint and all smaller\n\t\t\t\tsize = that._find( name ).width;\n\n\t\t\t\tfor ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( breakpoints[i].width <= size ) {\n\t\t\t\t\t\tadd( colIdx, breakpoints[i].name );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( operator === 'min-' ) {\n\t\t\t\t// Add this breakpoint and all larger\n\t\t\t\tsize = that._find( name ).width;\n\n\t\t\t\tfor ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( breakpoints[i].width >= size ) {\n\t\t\t\t\t\tadd( colIdx, breakpoints[i].name );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( operator === 'not-' ) {\n\t\t\t\t// Add all but this breakpoint\n\t\t\t\tfor ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( breakpoints[i].name.indexOf( matched ) === -1 ) {\n\t\t\t\t\t\tadd( colIdx, breakpoints[i].name );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Loop over each column and determine if it has a responsive control\n\t\t// class\n\t\tcolumns.each( function ( col, i ) {\n\t\t\tvar classNames = col.className.split(' ');\n\t\t\tvar hasClass = false;\n\n\t\t\t// Split the class name up so multiple rules can be applied if needed\n\t\t\tfor ( var k=0, ken=classNames.length ; k<ken ; k++ ) {\n\t\t\t\tvar className = $.trim( classNames[k] );\n\n\t\t\t\tif ( className === 'all' ) {\n\t\t\t\t\t// Include in all\n\t\t\t\t\thasClass = true;\n\t\t\t\t\tcol.includeIn = $.map( breakpoints, function (a) {\n\t\t\t\t\t\treturn a.name;\n\t\t\t\t\t} );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\telse if ( className === 'none' || col.never ) {\n\t\t\t\t\t// Include in none (default) and no auto\n\t\t\t\t\thasClass = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\telse if ( className === 'control' ) {\n\t\t\t\t\t// Special column that is only visible, when one of the other\n\t\t\t\t\t// columns is hidden. This is used for the details control\n\t\t\t\t\thasClass = true;\n\t\t\t\t\tcol.control = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t$.each( breakpoints, function ( j, breakpoint ) {\n\t\t\t\t\t// Does this column have a class that matches this breakpoint?\n\t\t\t\t\tvar brokenPoint = breakpoint.name.split('-');\n\t\t\t\t\tvar re = new RegExp( '(min\\\\-|max\\\\-|not\\\\-)?('+brokenPoint[0]+')(\\\\-[_a-zA-Z0-9])?' );\n\t\t\t\t\tvar match = className.match( re );\n\n\t\t\t\t\tif ( match ) {\n\t\t\t\t\t\thasClass = true;\n\n\t\t\t\t\t\tif ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {\n\t\t\t\t\t\t\t// Class name matches breakpoint name fully\n\t\t\t\t\t\t\tcolumn( i, breakpoint.name, match[1], match[2]+match[3] );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( match[2] === brokenPoint[0] && ! match[3] ) {\n\t\t\t\t\t\t\t// Class name matched primary breakpoint name with no qualifier\n\t\t\t\t\t\t\tcolumn( i, breakpoint.name, match[1], match[2] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// If there was no control class, then automatic sizing is used\n\t\t\tif ( ! hasClass ) {\n\t\t\t\tcol.auto = true;\n\t\t\t}\n\t\t} );\n\n\t\tthis.s.columns = columns;\n\t},\n\n\n\t/**\n\t * Show the details for the child row\n\t *\n\t * @param  {DataTables.Api} row    API instance for the row\n\t * @param  {boolean}        update Update flag\n\t * @private\n\t */\n\t_detailsDisplay: function ( row, update )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar details = this.c.details;\n\n\t\tif ( details && details.type !== false ) {\n\t\t\tvar res = details.display( row, update, function () {\n\t\t\t\treturn details.renderer(\n\t\t\t\t\tdt, row[0], that._detailsObj(row[0])\n\t\t\t\t);\n\t\t\t} );\n\n\t\t\tif ( res === true || res === false ) {\n\t\t\t\t$(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] );\n\t\t\t}\n\t\t}\n\t},\n\n\n\t/**\n\t * Initialisation for the details handler\n\t *\n\t * @private\n\t */\n\t_detailsInit: function ()\n\t{\n\t\tvar that    = this;\n\t\tvar dt      = this.s.dt;\n\t\tvar details = this.c.details;\n\n\t\t// The inline type always uses the first child as the target\n\t\tif ( details.type === 'inline' ) {\n\t\t\tdetails.target = 'td:first-child, th:first-child';\n\t\t}\n\n\t\t// Keyboard accessibility\n\t\tdt.on( 'draw.dtr', function () {\n\t\t\tthat._tabIndexes();\n\t\t} );\n\t\tthat._tabIndexes(); // Initial draw has already happened\n\n\t\t$( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) {\n\t\t\tif ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) {\n\t\t\t\t$(this).click();\n\t\t\t}\n\t\t} );\n\n\t\t// type.target can be a string jQuery selector or a column index\n\t\tvar target   = details.target;\n\t\tvar selector = typeof target === 'string' ? target : 'td, th';\n\n\t\t// Click handler to show / hide the details rows when they are available\n\t\t$( dt.table().body() )\n\t\t\t.on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) {\n\t\t\t\t// If the table is not collapsed (i.e. there is no hidden columns)\n\t\t\t\t// then take no action\n\t\t\t\tif ( ! $(dt.table().node()).hasClass('collapsed' ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Check that the row is actually a DataTable's controlled node\n\t\t\t\tif ( $.inArray( $(this).closest('tr').get(0), dt.rows().nodes().toArray() ) === -1 ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// For column index, we determine if we should act or not in the\n\t\t\t\t// handler - otherwise it is already okay\n\t\t\t\tif ( typeof target === 'number' ) {\n\t\t\t\t\tvar targetIdx = target < 0 ?\n\t\t\t\t\t\tdt.columns().eq(0).length + target :\n\t\t\t\t\t\ttarget;\n\n\t\t\t\t\tif ( dt.cell( this ).index().column !== targetIdx ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// $().closest() includes itself in its check\n\t\t\t\tvar row = dt.row( $(this).closest('tr') );\n\n\t\t\t\t// Check event type to do an action\n\t\t\t\tif ( e.type === 'click' ) {\n\t\t\t\t\t// The renderer is given as a function so the caller can execute it\n\t\t\t\t\t// only when they need (i.e. if hiding there is no point is running\n\t\t\t\t\t// the renderer)\n\t\t\t\t\tthat._detailsDisplay( row, false );\n\t\t\t\t}\n\t\t\t\telse if ( e.type === 'mousedown' ) {\n\t\t\t\t\t// For mouse users, prevent the focus ring from showing\n\t\t\t\t\t$(this).css('outline', 'none');\n\t\t\t\t}\n\t\t\t\telse if ( e.type === 'mouseup' ) {\n\t\t\t\t\t// And then re-allow at the end of the click\n\t\t\t\t\t$(this).blur().css('outline', '');\n\t\t\t\t}\n\t\t\t} );\n\t},\n\n\n\t/**\n\t * Get the details to pass to a renderer for a row\n\t * @param  {int} rowIdx Row index\n\t * @private\n\t */\n\t_detailsObj: function ( rowIdx )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\n\t\treturn $.map( this.s.columns, function( col, i ) {\n\t\t\t// Never and control columns should not be passed to the renderer\n\t\t\tif ( col.never || col.control ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttitle:       dt.settings()[0].aoColumns[ i ].sTitle,\n\t\t\t\tdata:        dt.cell( rowIdx, i ).render( that.c.orthogonal ),\n\t\t\t\thidden:      dt.column( i ).visible() && !that.s.current[ i ],\n\t\t\t\tcolumnIndex: i,\n\t\t\t\trowIndex:    rowIdx\n\t\t\t};\n\t\t} );\n\t},\n\n\n\t/**\n\t * Find a breakpoint object from a name\n\t *\n\t * @param  {string} name Breakpoint name to find\n\t * @return {object}      Breakpoint description object\n\t * @private\n\t */\n\t_find: function ( name )\n\t{\n\t\tvar breakpoints = this.c.breakpoints;\n\n\t\tfor ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {\n\t\t\tif ( breakpoints[i].name === name ) {\n\t\t\t\treturn breakpoints[i];\n\t\t\t}\n\t\t}\n\t},\n\n\n\t/**\n\t * Re-create the contents of the child rows as the display has changed in\n\t * some way.\n\t *\n\t * @private\n\t */\n\t_redrawChildren: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\n\t\tdt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {\n\t\t\tvar row = dt.row( idx );\n\n\t\t\tthat._detailsDisplay( dt.row( idx ), true );\n\t\t} );\n\t},\n\n\n\t/**\n\t * Alter the table display for a resized viewport. This involves first\n\t * determining what breakpoint the window currently is in, getting the\n\t * column visibilities to apply and then setting them.\n\t *\n\t * @private\n\t */\n\t_resize: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar width = $(window).width();\n\t\tvar breakpoints = this.c.breakpoints;\n\t\tvar breakpoint = breakpoints[0].name;\n\t\tvar columns = this.s.columns;\n\t\tvar i, ien;\n\t\tvar oldVis = this.s.current.slice();\n\n\t\t// Determine what breakpoint we are currently at\n\t\tfor ( i=breakpoints.length-1 ; i>=0 ; i-- ) {\n\t\t\tif ( width <= breakpoints[i].width ) {\n\t\t\t\tbreakpoint = breakpoints[i].name;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Show the columns for that break point\n\t\tvar columnsVis = this._columnsVisiblity( breakpoint );\n\t\tthis.s.current = columnsVis;\n\n\t\t// Set the class before the column visibility is changed so event\n\t\t// listeners know what the state is. Need to determine if there are\n\t\t// any columns that are not visible but can be shown\n\t\tvar collapsedClass = false;\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tif ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control && ! dt.column(i).visible() === false ) {\n\t\t\t\tcollapsedClass = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t$( dt.table().node() ).toggleClass( 'collapsed', collapsedClass );\n\n\t\tvar changed = false;\n\t\tvar visible = 0;\n\n\t\tdt.columns().eq(0).each( function ( colIdx, i ) {\n\t\t\tif ( columnsVis[i] === true ) {\n\t\t\t\tvisible++;\n\t\t\t}\n\n\t\t\tif ( columnsVis[i] !== oldVis[i] ) {\n\t\t\t\tchanged = true;\n\t\t\t\tthat._setColumnVis( colIdx, columnsVis[i] );\n\t\t\t}\n\t\t} );\n\n\t\tif ( changed ) {\n\t\t\tthis._redrawChildren();\n\n\t\t\t// Inform listeners of the change\n\t\t\t$(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] );\n\n\t\t\t// If no records, update the \"No records\" display element\n\t\t\tif ( dt.page.info().recordsDisplay === 0 ) {\n\t\t\t\t$('td', dt.table().body()).eq(0).attr('colspan', visible);\n\t\t\t}\n\t\t}\n\t},\n\n\n\t/**\n\t * Determine the width of each column in the table so the auto column hiding\n\t * has that information to work with. This method is never going to be 100%\n\t * perfect since column widths can change slightly per page, but without\n\t * seriously compromising performance this is quite effective.\n\t *\n\t * @private\n\t */\n\t_resizeAuto: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar columns = this.s.columns;\n\n\t\t// Are we allowed to do auto sizing?\n\t\tif ( ! this.c.auto ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Are there any columns that actually need auto-sizing, or do they all\n\t\t// have classes defined\n\t\tif ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Need to restore all children. They will be reinstated by a re-render\n\t\tif ( ! $.isEmptyObject( _childNodeStore ) ) {\n\t\t\t$.each( _childNodeStore, function ( key ) {\n\t\t\t\tvar idx = key.split('-');\n\n\t\t\t\t_childNodesRestore( dt, idx[0]*1, idx[1]*1 );\n\t\t\t} );\n\t\t}\n\n\t\t// Clone the table with the current data in it\n\t\tvar tableWidth   = dt.table().node().offsetWidth;\n\t\tvar columnWidths = dt.columns;\n\t\tvar clonedTable  = dt.table().node().cloneNode( false );\n\t\tvar clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );\n\t\tvar clonedBody   = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8\n\n\t\t// Header\n\t\tvar headerCells = dt.columns()\n\t\t\t.header()\n\t\t\t.filter( function (idx) {\n\t\t\t\treturn dt.column(idx).visible();\n\t\t\t} )\n\t\t\t.to$()\n\t\t\t.clone( false )\n\t\t\t.css( 'display', 'table-cell' )\n\t\t\t.css( 'min-width', 0 );\n\n\t\t// Body rows - we don't need to take account of DataTables' column\n\t\t// visibility since we implement our own here (hence the `display` set)\n\t\t$(clonedBody)\n\t\t\t.append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) )\n\t\t\t.find( 'th, td' ).css( 'display', '' );\n\n\t\t// Footer\n\t\tvar footer = dt.table().footer();\n\t\tif ( footer ) {\n\t\t\tvar clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable );\n\t\t\tvar footerCells = dt.columns()\n\t\t\t\t.footer()\n\t\t\t\t.filter( function (idx) {\n\t\t\t\t\treturn dt.column(idx).visible();\n\t\t\t\t} )\n\t\t\t\t.to$()\n\t\t\t\t.clone( false )\n\t\t\t\t.css( 'display', 'table-cell' );\n\n\t\t\t$('<tr/>')\n\t\t\t\t.append( footerCells )\n\t\t\t\t.appendTo( clonedFooter );\n\t\t}\n\n\t\t$('<tr/>')\n\t\t\t.append( headerCells )\n\t\t\t.appendTo( clonedHeader );\n\n\t\t// In the inline case extra padding is applied to the first column to\n\t\t// give space for the show / hide icon. We need to use this in the\n\t\t// calculation\n\t\tif ( this.c.details.type === 'inline' ) {\n\t\t\t$(clonedTable).addClass( 'dtr-inline collapsed' );\n\t\t}\n\t\t\n\t\t// It is unsafe to insert elements with the same name into the DOM\n\t\t// multiple times. For example, cloning and inserting a checked radio\n\t\t// clears the chcecked state of the original radio.\n\t\t$( clonedTable ).find( '[name]' ).removeAttr( 'name' );\n\n\t\t// A position absolute table would take the table out of the flow of\n\t\t// our container element, bypassing the height and width (Scroller)\n\t\t$( clonedTable ).css( 'position', 'relative' )\n\t\t\n\t\tvar inserted = $('<div/>')\n\t\t\t.css( {\n\t\t\t\twidth: 1,\n\t\t\t\theight: 1,\n\t\t\t\toverflow: 'hidden',\n\t\t\t\tclear: 'both'\n\t\t\t} )\n\t\t\t.append( clonedTable );\n\n\t\tinserted.insertBefore( dt.table().node() );\n\n\t\t// The cloned header now contains the smallest that each column can be\n\t\theaderCells.each( function (i) {\n\t\t\tvar idx = dt.column.index( 'fromVisible', i );\n\t\t\tcolumns[ idx ].minWidth =  this.offsetWidth || 0;\n\t\t} );\n\n\t\tinserted.remove();\n\t},\n\n\t/**\n\t * Set a column's visibility.\n\t *\n\t * We don't use DataTables' column visibility controls in order to ensure\n\t * that column visibility can Responsive can no-exist. Since only IE8+ is\n\t * supported (and all evergreen browsers of course) the control of the\n\t * display attribute works well.\n\t *\n\t * @param {integer} col      Column index\n\t * @param {boolean} showHide Show or hide (true or false)\n\t * @private\n\t */\n\t_setColumnVis: function ( col, showHide )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar display = showHide ? '' : 'none'; // empty string will remove the attr\n\n\t\t$( dt.column( col ).header() ).css( 'display', display );\n\t\t$( dt.column( col ).footer() ).css( 'display', display );\n\t\tdt.column( col ).nodes().to$().css( 'display', display );\n\n\t\t// If the are child nodes stored, we might need to reinsert them\n\t\tif ( ! $.isEmptyObject( _childNodeStore ) ) {\n\t\t\tdt.cells( null, col ).indexes().each( function (idx) {\n\t\t\t\t_childNodesRestore( dt, idx.row, idx.column );\n\t\t\t} );\n\t\t}\n\t},\n\n\n\t/**\n\t * Update the cell tab indexes for keyboard accessibility. This is called on\n\t * every table draw - that is potentially inefficient, but also the least\n\t * complex option given that column visibility can change on the fly. Its a\n\t * shame user-focus was removed from CSS 3 UI, as it would have solved this\n\t * issue with a single CSS statement.\n\t *\n\t * @private\n\t */\n\t_tabIndexes: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar cells = dt.cells( { page: 'current' } ).nodes().to$();\n\t\tvar ctx = dt.settings()[0];\n\t\tvar target = this.c.details.target;\n\n\t\tcells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );\n\n\t\tif ( typeof target === 'number' ) {\n\t\t\tdt.cells( null, target, { page: 'current' } ).nodes().to$()\n\t\t\t\t.attr( 'tabIndex', ctx.iTabIndex )\n\t\t\t\t.data( 'dtr-keyboard', 1 );\n\t\t}\n\t\telse {\n\t\t\t// This is a bit of a hack - we need to limit the selected nodes to just\n\t\t\t// those of this table\n\t\t\tif ( target === 'td:first-child, th:first-child' ) {\n\t\t\t\ttarget = '>td:first-child, >th:first-child';\n\t\t\t}\n\n\t\t\t$( target, dt.rows( { page: 'current' } ).nodes() )\n\t\t\t\t.attr( 'tabIndex', ctx.iTabIndex )\n\t\t\t\t.data( 'dtr-keyboard', 1 );\n\t\t}\n\t}\n} );\n\n\n/**\n * List of default breakpoints. Each item in the array is an object with two\n * properties:\n *\n * * `name` - the breakpoint name.\n * * `width` - the breakpoint width\n *\n * @name Responsive.breakpoints\n * @static\n */\nResponsive.breakpoints = [\n\t{ name: 'desktop',  width: Infinity },\n\t{ name: 'tablet-l', width: 1024 },\n\t{ name: 'tablet-p', width: 768 },\n\t{ name: 'mobile-l', width: 480 },\n\t{ name: 'mobile-p', width: 320 }\n];\n\n\n/**\n * Display methods - functions which define how the hidden data should be shown\n * in the table.\n *\n * @namespace\n * @name Responsive.defaults\n * @static\n */\nResponsive.display = {\n\tchildRow: function ( row, update, render ) {\n\t\tif ( update ) {\n\t\t\tif ( $(row.node()).hasClass('parent') ) {\n\t\t\t\trow.child( render(), 'child' ).show();\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif ( ! row.child.isShown()  ) {\n\t\t\t\trow.child( render(), 'child' ).show();\n\t\t\t\t$( row.node() ).addClass( 'parent' );\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse {\n\t\t\t\trow.child( false );\n\t\t\t\t$( row.node() ).removeClass( 'parent' );\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t},\n\n\tchildRowImmediate: function ( row, update, render ) {\n\t\tif ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {\n\t\t\t// User interaction and the row is show, or nothing to show\n\t\t\trow.child( false );\n\t\t\t$( row.node() ).removeClass( 'parent' );\n\n\t\t\treturn false;\n\t\t}\n\t\telse {\n\t\t\t// Display\n\t\t\trow.child( render(), 'child' ).show();\n\t\t\t$( row.node() ).addClass( 'parent' );\n\n\t\t\treturn true;\n\t\t}\n\t},\n\n\t// This is a wrapper so the modal options for Bootstrap and jQuery UI can\n\t// have options passed into them. This specific one doesn't need to be a\n\t// function but it is for consistency in the `modal` name\n\tmodal: function ( options ) {\n\t\treturn function ( row, update, render ) {\n\t\t\tif ( ! update ) {\n\t\t\t\t// Show a modal\n\t\t\t\tvar close = function () {\n\t\t\t\t\tmodal.remove(); // will tidy events for us\n\t\t\t\t\t$(document).off( 'keypress.dtr' );\n\t\t\t\t};\n\n\t\t\t\tvar modal = $('<div class=\"dtr-modal\"/>')\n\t\t\t\t\t.append( $('<div class=\"dtr-modal-display\"/>')\n\t\t\t\t\t\t.append( $('<div class=\"dtr-modal-content\"/>')\n\t\t\t\t\t\t\t.append( render() )\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.append( $('<div class=\"dtr-modal-close\">&times;</div>' )\n\t\t\t\t\t\t\t.click( function () {\n\t\t\t\t\t\t\t\tclose();\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t.append( $('<div class=\"dtr-modal-background\"/>')\n\t\t\t\t\t\t.click( function () {\n\t\t\t\t\t\t\tclose();\n\t\t\t\t\t\t} )\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo( 'body' );\n\n\t\t\t\t$(document).on( 'keyup.dtr', function (e) {\n\t\t\t\t\tif ( e.keyCode === 27 ) {\n\t\t\t\t\t\te.stopPropagation();\n\n\t\t\t\t\t\tclose();\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t$('div.dtr-modal-content')\n\t\t\t\t\t.empty()\n\t\t\t\t\t.append( render() );\n\t\t\t}\n\n\t\t\tif ( options && options.header ) {\n\t\t\t\t$('div.dtr-modal-content').prepend(\n\t\t\t\t\t'<h2>'+options.header( row )+'</h2>'\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\t}\n};\n\n\nvar _childNodeStore = {};\n\nfunction _childNodes( dt, row, col ) {\n\tvar name = row+'-'+col;\n\n\tif ( _childNodeStore[ name ] ) {\n\t\treturn _childNodeStore[ name ];\n\t}\n\n\t// https://jsperf.com/childnodes-array-slice-vs-loop\n\tvar nodes = [];\n\tvar children = dt.cell( row, col ).node().childNodes;\n\tfor ( var i=0, ien=children.length ; i<ien ; i++ ) {\n\t\tnodes.push( children[i] );\n\t}\n\n\t_childNodeStore[ name ] = nodes;\n\n\treturn nodes;\n}\n\nfunction _childNodesRestore( dt, row, col ) {\n\tvar name = row+'-'+col;\n\n\tif ( ! _childNodeStore[ name ] ) {\n\t\treturn;\n\t}\n\n\tvar node = dt.cell( row, col ).node();\n\tvar store = _childNodeStore[ name ];\n\tvar parent = store[0].parentNode;\n\tvar parentChildren = parent.childNodes;\n\tvar a = [];\n\n\tfor ( var i=0, ien=parentChildren.length ; i<ien ; i++ ) {\n\t\ta.push( parentChildren[i] );\n\t}\n\n\tfor ( var j=0, jen=a.length ; j<jen ; j++ ) {\n\t\tnode.appendChild( a[j] );\n\t}\n\n\t_childNodeStore[ name ] = undefined;\n}\n\n\n/**\n * Display methods - functions which define how the hidden data should be shown\n * in the table.\n *\n * @namespace\n * @name Responsive.defaults\n * @static\n */\nResponsive.renderer = {\n\tlistHiddenNodes: function () {\n\t\treturn function ( api, rowIdx, columns ) {\n\t\t\tvar ul = $('<ul data-dtr-index=\"'+rowIdx+'\" class=\"dtr-details\"/>');\n\t\t\tvar found = false;\n\n\t\t\tvar data = $.each( columns, function ( i, col ) {\n\t\t\t\tif ( col.hidden ) {\n\t\t\t\t\t$(\n\t\t\t\t\t\t'<li data-dtr-index=\"'+col.columnIndex+'\" data-dt-row=\"'+col.rowIndex+'\" data-dt-column=\"'+col.columnIndex+'\">'+\n\t\t\t\t\t\t\t'<span class=\"dtr-title\">'+\n\t\t\t\t\t\t\t\tcol.title+\n\t\t\t\t\t\t\t'</span> '+\n\t\t\t\t\t\t'</li>'\n\t\t\t\t\t)\n\t\t\t\t\t\t.append( $('<span class=\"dtr-data\"/>').append( _childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) )\n\t\t\t\t\t\t.appendTo( ul );\n\n\t\t\t\t\tfound = true;\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\treturn found ?\n\t\t\t\tul :\n\t\t\t\tfalse;\n\t\t};\n\t},\n\n\tlistHidden: function () {\n\t\treturn function ( api, rowIdx, columns ) {\n\t\t\tvar data = $.map( columns, function ( col ) {\n\t\t\t\treturn col.hidden ?\n\t\t\t\t\t'<li data-dtr-index=\"'+col.columnIndex+'\" data-dt-row=\"'+col.rowIndex+'\" data-dt-column=\"'+col.columnIndex+'\">'+\n\t\t\t\t\t\t'<span class=\"dtr-title\">'+\n\t\t\t\t\t\t\tcol.title+\n\t\t\t\t\t\t'</span> '+\n\t\t\t\t\t\t'<span class=\"dtr-data\">'+\n\t\t\t\t\t\t\tcol.data+\n\t\t\t\t\t\t'</span>'+\n\t\t\t\t\t'</li>' :\n\t\t\t\t\t'';\n\t\t\t} ).join('');\n\n\t\t\treturn data ?\n\t\t\t\t$('<ul data-dtr-index=\"'+rowIdx+'\" class=\"dtr-details\"/>').append( data ) :\n\t\t\t\tfalse;\n\t\t}\n\t},\n\n\ttableAll: function ( options ) {\n\t\toptions = $.extend( {\n\t\t\ttableClass: ''\n\t\t}, options );\n\n\t\treturn function ( api, rowIdx, columns ) {\n\t\t\tvar data = $.map( columns, function ( col ) {\n\t\t\t\treturn '<tr data-dt-row=\"'+col.rowIndex+'\" data-dt-column=\"'+col.columnIndex+'\">'+\n\t\t\t\t\t\t'<td>'+col.title+':'+'</td> '+\n\t\t\t\t\t\t'<td>'+col.data+'</td>'+\n\t\t\t\t\t'</tr>';\n\t\t\t} ).join('');\n\n\t\t\treturn $('<table class=\"'+options.tableClass+' dtr-details\" width=\"100%\"/>').append( data );\n\t\t}\n\t}\n};\n\n/**\n * Responsive default settings for initialisation\n *\n * @namespace\n * @name Responsive.defaults\n * @static\n */\nResponsive.defaults = {\n\t/**\n\t * List of breakpoints for the instance. Note that this means that each\n\t * instance can have its own breakpoints. Additionally, the breakpoints\n\t * cannot be changed once an instance has been creased.\n\t *\n\t * @type {Array}\n\t * @default Takes the value of `Responsive.breakpoints`\n\t */\n\tbreakpoints: Responsive.breakpoints,\n\n\t/**\n\t * Enable / disable auto hiding calculations. It can help to increase\n\t * performance slightly if you disable this option, but all columns would\n\t * need to have breakpoint classes assigned to them\n\t *\n\t * @type {Boolean}\n\t * @default  `true`\n\t */\n\tauto: true,\n\n\t/**\n\t * Details control. If given as a string value, the `type` property of the\n\t * default object is set to that value, and the defaults used for the rest\n\t * of the object - this is for ease of implementation.\n\t *\n\t * The object consists of the following properties:\n\t *\n\t * * `display` - A function that is used to show and hide the hidden details\n\t * * `renderer` - function that is called for display of the child row data.\n\t *   The default function will show the data from the hidden columns\n\t * * `target` - Used as the selector for what objects to attach the child\n\t *   open / close to\n\t * * `type` - `false` to disable the details display, `inline` or `column`\n\t *   for the two control types\n\t *\n\t * @type {Object|string}\n\t */\n\tdetails: {\n\t\tdisplay: Responsive.display.childRow,\n\n\t\trenderer: Responsive.renderer.listHidden(),\n\n\t\ttarget: 0,\n\n\t\ttype: 'inline'\n\t},\n\n\t/**\n\t * Orthogonal data request option. This is used to define the data type\n\t * requested when Responsive gets the data to show in the child row.\n\t *\n\t * @type {String}\n\t */\n\torthogonal: 'display'\n};\n\n\n/*\n * API\n */\nvar Api = $.fn.dataTable.Api;\n\n// Doesn't do anything - work around for a bug in DT... Not documented\nApi.register( 'responsive()', function () {\n\treturn this;\n} );\n\nApi.register( 'responsive.index()', function ( li ) {\n\tli = $(li);\n\n\treturn {\n\t\tcolumn: li.data('dtr-index'),\n\t\trow:    li.parent().data('dtr-index')\n\t};\n} );\n\nApi.register( 'responsive.rebuild()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx._responsive ) {\n\t\t\tctx._responsive._classLogic();\n\t\t}\n\t} );\n} );\n\nApi.register( 'responsive.recalc()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx._responsive ) {\n\t\t\tctx._responsive._resizeAuto();\n\t\t\tctx._responsive._resize();\n\t\t}\n\t} );\n} );\n\nApi.register( 'responsive.hasHidden()', function () {\n\tvar ctx = this.context[0];\n\n\treturn ctx._responsive ?\n\t\t$.inArray( false, ctx._responsive.s.current ) !== -1 :\n\t\tfalse;\n} );\n\nApi.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () {\n\treturn this.iterator( 'column', function ( settings, column ) {\n\t\treturn settings._responsive ?\n\t\t\tsettings._responsive.s.current[ column ] :\n\t\t\tfalse;\n\t}, 1 );\n} );\n\n\n/**\n * Version information\n *\n * @name Responsive.version\n * @static\n */\nResponsive.version = '2.2.2';\n\n\n$.fn.dataTable.Responsive = Responsive;\n$.fn.DataTable.Responsive = Responsive;\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'preInit.dt.dtr', function (e, settings, json) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tif ( $(settings.nTable).hasClass( 'responsive' ) ||\n\t\t $(settings.nTable).hasClass( 'dt-responsive' ) ||\n\t\t settings.oInit.responsive ||\n\t\t DataTable.defaults.responsive\n\t) {\n\t\tvar init = settings.oInit.responsive;\n\n\t\tif ( init !== false ) {\n\t\t\tnew Responsive( settings, $.isPlainObject( init ) ? init : {}  );\n\t\t}\n\t}\n} );\n\n\nreturn Responsive;\n}));\n\n\n/*! RowGroup 1.1.0\n * ©2017-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     RowGroup\n * @description RowGrouping for DataTables\n * @version     1.1.0\n * @file        dataTables.rowGroup.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     datatables.net\n * @copyright   Copyright 2017-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\nvar RowGroup = function ( dt, opts ) {\n\t// Sanity check that we are using DataTables 1.10 or newer\n\tif ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {\n\t\tthrow 'RowGroup requires DataTables 1.10.8 or newer';\n\t}\n\n\t// User and defaults configuration object\n\tthis.c = $.extend( true, {},\n\t\tDataTable.defaults.rowGroup,\n\t\tRowGroup.defaults,\n\t\topts\n\t);\n\n\t// Internal settings\n\tthis.s = {\n\t\tdt: new DataTable.Api( dt )\n\t};\n\n\t// DOM items\n\tthis.dom = {\n\n\t};\n\n\t// Check if row grouping has already been initialised on this table\n\tvar settings = this.s.dt.settings()[0];\n\tvar existing = settings.rowGroup;\n\tif ( existing ) {\n\t\treturn existing;\n\t}\n\n\tsettings.rowGroup = this;\n\tthis._constructor();\n};\n\n\n$.extend( RowGroup.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * API methods for DataTables API interface\n\t */\n\n\t/**\n\t * Get/set the grouping data source - need to call draw after this is\n\t * executed as a setter\n\t * @returns string~RowGroup\n\t */\n\tdataSrc: function ( val )\n\t{\n\t\tif ( val === undefined ) {\n\t\t\treturn this.c.dataSrc;\n\t\t}\n\n\t\tvar dt = this.s.dt;\n\n\t\tthis.c.dataSrc = val;\n\n\t\t$(dt.table().node()).triggerHandler( 'rowgroup-datasrc.dt', [ dt, val ] );\n\n\t\treturn this;\n\t},\n\n\t/**\n\t * Disable - need to call draw after this is executed\n\t * @returns RowGroup\n\t */\n\tdisable: function ()\n\t{\n\t\tthis.c.enable = false;\n\t\treturn this;\n\t},\n\n\t/**\n\t * Enable - need to call draw after this is executed\n\t * @returns RowGroup\n\t */\n\tenable: function ( flag )\n\t{\n\t\tif ( flag === false ) {\n\t\t\treturn this.disable();\n\t\t}\n\n\t\tthis.c.enable = true;\n\t\treturn this;\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\t_constructor: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\n\t\tdt.on( 'draw.dtrg', function () {\n\t\t\tif ( that.c.enable ) {\n\t\t\t\tthat._draw();\n\t\t\t}\n\t\t} );\n\n\t\tdt.on( 'column-visibility.dt.dtrg responsive-resize.dt.dtrg', function () {\n\t\t\tthat._adjustColspan();\n\t\t} );\n\n\t\tdt.on( 'destroy', function () {\n\t\t\tdt.off( '.dtrg' );\n\t\t} );\n\n\t\tdt.on('responsive-resize.dt', function () {\n\t\t\tthat._adjustColspan();\n\t\t})\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\n\t/**\n\t * Adjust column span when column visibility changes\n\t * @private\n\t */\n\t_adjustColspan: function ()\n\t{\n\t\t$( 'tr.'+this.c.className, this.s.dt.table().body() ).find('td')\n\t\t\t.attr( 'colspan', this._colspan() );\n\t},\n\n\t/**\n\t * Get the number of columns that a grouping row should span\n\t * @private\n\t */\n\t_colspan: function ()\n\t{\n\t\treturn this.s.dt.columns().visible().reduce( function (a, b) {\n\t\t\treturn a + b;\n\t\t}, 0 );\n\t},\n\n\n\t/**\n\t * Update function that is called whenever we need to draw the grouping rows.\n\t * This is basically a bootstrap for the self iterative _group and _groupDisplay\n\t * methods\n\t * @private\n\t */\n\t_draw: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar groupedRows = this._group( 0, dt.rows( { page: 'current' } ).indexes() );\n\n\t\tthis._groupDisplay( 0, groupedRows );\n\t},\n\n\t/**\n\t * Get the grouping information from a data set (index) of rows\n\t * @param {number} level Nesting level\n\t * @param {DataTables.Api} rows API of the rows to consider for this group\n\t * @returns {object[]} Nested grouping information - it is structured like this:\n\t *\t{\n\t *\t\tdataPoint: 'Edinburgh',\n\t *\t\trows: [ 1,2,3,4,5,6,7 ],\n\t *\t\tchildren: [ {\n\t *\t\t\tdataPoint: 'developer'\n\t *\t\t\trows: [ 1, 2, 3 ]\n\t *\t\t},\n\t *\t\t{\n\t *\t\t\tdataPoint: 'support',\n\t *\t\t\trows: [ 4, 5, 6, 7 ]\n\t *\t\t} ]\n\t *\t}\n\t * @private\n\t */\n\t_group: function ( level, rows ) {\n\t\tvar fns = $.isArray( this.c.dataSrc ) ? this.c.dataSrc : [ this.c.dataSrc ];\n\t\tvar fn = DataTable.ext.oApi._fnGetObjectDataFn( fns[ level ] );\n\t\tvar dt = this.s.dt;\n\t\tvar group, last;\n\t\tvar data = [];\n\n\t\tfor ( var i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\tvar rowIndex = rows[i];\n\t\t\tvar rowData = dt.row( rowIndex ).data();\n\t\t\tvar group = fn( rowData );\n\n\t\t\tif ( group === null || group === undefined ) {\n\t\t\t\tgroup = that.c.emptyDataGroup;\n\t\t\t}\n\t\t\t\n\t\t\tif ( last === undefined || group !== last ) {\n\t\t\t\tdata.push( {\n\t\t\t\t\tdataPoint: group,\n\t\t\t\t\trows: []\n\t\t\t\t} );\n\n\t\t\t\tlast = group;\n\t\t\t}\n\n\t\t\tdata[ data.length-1 ].rows.push( rowIndex );\n\t\t}\n\n\t\tif ( fns[ level+1 ] !== undefined ) {\n\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\tdata[i].children = this._group( level+1, data[i].rows );\n\t\t\t}\n\t\t}\n\n\t\treturn data;\n\t},\n\n\t/**\n\t * Row group display - insert the rows into the document\n\t * @param {number} level Nesting level\n\t * @param {object[]} groups Takes the nested array from `_group`\n\t * @private\n\t */\n\t_groupDisplay: function ( level, groups )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar display;\n\t\n\t\tfor ( var i=0, ien=groups.length ; i<ien ; i++ ) {\n\t\t\tvar group = groups[i];\n\t\t\tvar groupName = group.dataPoint;\n\t\t\tvar row;\n\t\t\tvar rows = group.rows;\n\n\t\t\tif ( this.c.startRender ) {\n\t\t\t\tdisplay = this.c.startRender.call( this, dt.rows(rows), groupName, level );\n\t\t\t\trow = this._rowWrap( display, this.c.startClassName, level );\n\n\t\t\t\tif ( row ) {\n\t\t\t\t\trow.insertBefore( dt.row( rows[0] ).node() );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( this.c.endRender ) {\n\t\t\t\tdisplay = this.c.endRender.call( this, dt.rows(rows), groupName, level );\n\t\t\t\trow = this._rowWrap( display, this.c.endClassName, level );\n\n\t\t\t\tif ( row ) {\n\t\t\t\t\trow.insertAfter( dt.row( rows[ rows.length-1 ] ).node() );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( group.children ) {\n\t\t\t\tthis._groupDisplay( level+1, group.children );\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * Take a rendered value from an end user and make it suitable for display\n\t * as a row, by wrapping it in a row, or detecting that it is a row.\n\t * @param {node|jQuery|string} display Display value\n\t * @param {string} className Class to add to the row\n\t * @param {array} group\n\t * @param {number} group level\n\t * @private\n\t */\n\t_rowWrap: function ( display, className, level )\n\t{\n\t\tvar row;\n\t\t\n\t\tif ( display === null || display === '' ) {\n\t\t\tdisplay = this.c.emptyDataGroup;\n\t\t}\n\n\t\tif ( display === undefined ) {\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\tif ( typeof display === 'object' && display.nodeName && display.nodeName.toLowerCase() === 'tr') {\n\t\t\trow = $(display);\n\t\t}\n\t\telse if (display instanceof $ && display.length && display[0].nodeName.toLowerCase() === 'tr') {\n\t\t\trow = display;\n\t\t}\n\t\telse {\n\t\t\trow = $('<tr/>')\n\t\t\t\t.append(\n\t\t\t\t\t$('<td/>')\n\t\t\t\t\t\t.attr( 'colspan', this._colspan() )\n\t\t\t\t\t\t.append( display  )\n\t\t\t\t);\n\t\t}\n\n\t\treturn row\n\t\t\t.addClass( this.c.className )\n\t\t\t.addClass( className )\n\t\t\t.addClass( 'dtrg-level-'+level );\n\t}\n} );\n\n\n/**\n * RowGroup default settings for initialisation\n *\n * @namespace\n * @name RowGroup.defaults\n * @static\n */\nRowGroup.defaults = {\n\t/**\n\t * Class to apply to grouping rows - applied to both the start and\n\t * end grouping rows.\n\t * @type string\n\t */\n\tclassName: 'dtrg-group',\n\n\t/**\n\t * Data property from which to read the grouping information\n\t * @type string|integer|array\n\t */\n\tdataSrc: 0,\n\n\t/**\n\t * Text to show if no data is found for a group\n\t * @type string\n\t */\n\temptyDataGroup: 'No group',\n\n\t/**\n\t * Initial enablement state\n\t * @boolean\n\t */\n\tenable: true,\n\n\t/**\n\t * Class name to give to the end grouping row\n\t * @type string\n\t */\n\tendClassName: 'dtrg-end',\n\n\t/**\n\t * End grouping label function\n\t * @function\n\t */\n\tendRender: null,\n\n\t/**\n\t * Class name to give to the start grouping row\n\t * @type string\n\t */\n\tstartClassName: 'dtrg-start',\n\n\t/**\n\t * Start grouping label function\n\t * @function\n\t */\n\tstartRender: function ( rows, group ) {\n\t\treturn group;\n\t}\n};\n\n\nRowGroup.version = \"1.1.0\";\n\n\n$.fn.dataTable.RowGroup = RowGroup;\n$.fn.DataTable.RowGroup = RowGroup;\n\n\nDataTable.Api.register( 'rowGroup()', function () {\n\treturn this;\n} );\n\nDataTable.Api.register( 'rowGroup().disable()', function () {\n\treturn this.iterator( 'table', function (ctx) {\n\t\tif ( ctx.rowGroup ) {\n\t\t\tctx.rowGroup.enable( false );\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'rowGroup().enable()', function ( opts ) {\n\treturn this.iterator( 'table', function (ctx) {\n\t\tif ( ctx.rowGroup ) {\n\t\t\tctx.rowGroup.enable( opts === undefined ? true : opts );\n\t\t}\n\t} );\n} );\n\nDataTable.Api.register( 'rowGroup().dataSrc()', function ( val ) {\n\tif ( val === undefined ) {\n\t\treturn this.context[0].rowGroup.dataSrc();\n\t}\n\n\treturn this.iterator( 'table', function (ctx) {\n\t\tif ( ctx.rowGroup ) {\n\t\t\tctx.rowGroup.dataSrc( val );\n\t\t}\n\t} );\n} );\n\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'preInit.dt.dtrg', function (e, settings, json) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.rowGroup;\n\tvar defaults = DataTable.defaults.rowGroup;\n\n\tif ( init || defaults ) {\n\t\tvar opts = $.extend( {}, defaults, init );\n\n\t\tif ( init !== false ) {\n\t\t\tnew RowGroup( settings, opts  );\n\t\t}\n\t}\n} );\n\n\nreturn RowGroup;\n\n}));\n\n\n/*! RowReorder 1.2.4\n * 2015-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     RowReorder\n * @description Row reordering extension for DataTables\n * @version     1.2.4\n * @file        dataTables.rowReorder.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2015-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/**\n * RowReorder provides the ability in DataTables to click and drag rows to\n * reorder them. When a row is dropped the data for the rows effected will be\n * updated to reflect the change. Normally this data point should also be the\n * column being sorted upon in the DataTable but this does not need to be the\n * case. RowReorder implements a \"data swap\" method - so the rows being\n * reordered take the value of the data point from the row that used to occupy\n * the row's new position.\n *\n * Initialisation is done by either:\n *\n * * `rowReorder` parameter in the DataTable initialisation object\n * * `new $.fn.dataTable.RowReorder( table, opts )` after DataTables\n *   initialisation.\n * \n *  @class\n *  @param {object} settings DataTables settings object for the host table\n *  @param {object} [opts] Configuration options\n *  @requires jQuery 1.7+\n *  @requires DataTables 1.10.7+\n */\nvar RowReorder = function ( dt, opts ) {\n\t// Sanity check that we are using DataTables 1.10 or newer\n\tif ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {\n\t\tthrow 'DataTables RowReorder requires DataTables 1.10.8 or newer';\n\t}\n\n\t// User and defaults configuration object\n\tthis.c = $.extend( true, {},\n\t\tDataTable.defaults.rowReorder,\n\t\tRowReorder.defaults,\n\t\topts\n\t);\n\n\t// Internal settings\n\tthis.s = {\n\t\t/** @type {integer} Scroll body top cache */\n\t\tbodyTop: null,\n\n\t\t/** @type {DataTable.Api} DataTables' API instance */\n\t\tdt: new DataTable.Api( dt ),\n\n\t\t/** @type {function} Data fetch function */\n\t\tgetDataFn: DataTable.ext.oApi._fnGetObjectDataFn( this.c.dataSrc ),\n\n\t\t/** @type {array} Pixel positions for row insertion calculation */\n\t\tmiddles: null,\n\n\t\t/** @type {Object} Cached dimension information for use in the mouse move event handler */\n\t\tscroll: {},\n\n\t\t/** @type {integer} Interval object used for smooth scrolling */\n\t\tscrollInterval: null,\n\n\t\t/** @type {function} Data set function */\n\t\tsetDataFn: DataTable.ext.oApi._fnSetObjectDataFn( this.c.dataSrc ),\n\n\t\t/** @type {Object} Mouse down information */\n\t\tstart: {\n\t\t\ttop: 0,\n\t\t\tleft: 0,\n\t\t\toffsetTop: 0,\n\t\t\toffsetLeft: 0,\n\t\t\tnodes: []\n\t\t},\n\n\t\t/** @type {integer} Window height cached value */\n\t\twindowHeight: 0,\n\n\t\t/** @type {integer} Document outer height cached value */\n\t\tdocumentOuterHeight: 0,\n\n\t\t/** @type {integer} DOM clone outer height cached value */\n\t\tdomCloneOuterHeight: 0\n\t};\n\n\t// DOM items\n\tthis.dom = {\n\t\t/** @type {jQuery} Cloned row being moved around */\n\t\tclone: null,\n\n\t\t/** @type {jQuery} DataTables scrolling container */\n\t\tdtScroll: $('div.dataTables_scrollBody', this.s.dt.table().container())\n\t};\n\n\t// Check if row reorder has already been initialised on this table\n\tvar settings = this.s.dt.settings()[0];\n\tvar exisiting = settings.rowreorder;\n\tif ( exisiting ) {\n\t\treturn exisiting;\n\t}\n\n\tsettings.rowreorder = this;\n\tthis._constructor();\n};\n\n\n$.extend( RowReorder.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\n\t/**\n\t * Initialise the RowReorder instance\n\t *\n\t * @private\n\t */\n\t_constructor: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar table = $( dt.table().node() );\n\n\t\t// Need to be able to calculate the row positions relative to the table\n\t\tif ( table.css('position') === 'static' ) {\n\t\t\ttable.css( 'position', 'relative' );\n\t\t}\n\n\t\t// listen for mouse down on the target column - we have to implement\n\t\t// this rather than using HTML5 drag and drop as drag and drop doesn't\n\t\t// appear to work on table rows at this time. Also mobile browsers are\n\t\t// not supported.\n\t\t// Use `table().container()` rather than just the table node for IE8 -\n\t\t// otherwise it only works once...\n\t\t$(dt.table().container()).on( 'mousedown.rowReorder touchstart.rowReorder', this.c.selector, function (e) {\n\t\t\tif ( ! that.c.enable ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Ignore excluded children of the selector\n\t\t\tif ( $(e.target).is(that.c.excludedChildren) ) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tvar tr = $(this).closest('tr');\n\t\t\tvar row = dt.row( tr );\n\n\t\t\t// Double check that it is a DataTable row\n\t\t\tif ( row.any() ) {\n\t\t\t\tthat._emitEvent( 'pre-row-reorder', {\n\t\t\t\t\tnode: row.node(),\n\t\t\t\t\tindex: row.index()\n\t\t\t\t} );\n\n\t\t\t\tthat._mouseDown( e, tr );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} );\n\n\t\tdt.on( 'destroy.rowReorder', function () {\n\t\t\t$(dt.table().container()).off( '.rowReorder' );\n\t\t\tdt.off( '.rowReorder' );\n\t\t} );\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\t\n\t/**\n\t * Cache the measurements that RowReorder needs in the mouse move handler\n\t * to attempt to speed things up, rather than reading from the DOM.\n\t *\n\t * @private\n\t */\n\t_cachePositions: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\n\t\t// Frustratingly, if we add `position:relative` to the tbody, the\n\t\t// position is still relatively to the parent. So we need to adjust\n\t\t// for that\n\t\tvar headerHeight = $( dt.table().node() ).find('thead').outerHeight();\n\n\t\t// Need to pass the nodes through jQuery to get them in document order,\n\t\t// not what DataTables thinks it is, since we have been altering the\n\t\t// order\n\t\tvar nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );\n\t\tvar tops = $.map( nodes, function ( node, i ) {\n\t\t\treturn $(node).position().top - headerHeight;\n\t\t} );\n\n\t\tvar middles = $.map( tops, function ( top, i ) {\n\t\t\treturn tops.length < i-1 ?\n\t\t\t\t(top + tops[i+1]) / 2 :\n\t\t\t\t(top + top + $( dt.row( ':last-child' ).node() ).outerHeight() ) / 2;\n\t\t} );\n\n\t\tthis.s.middles = middles;\n\t\tthis.s.bodyTop = $( dt.table().body() ).offset().top;\n\t\tthis.s.windowHeight = $(window).height();\n\t\tthis.s.documentOuterHeight = $(document).outerHeight();\n\t},\n\n\n\t/**\n\t * Clone a row so it can be floated around the screen\n\t *\n\t * @param  {jQuery} target Node to be cloned\n\t * @private\n\t */\n\t_clone: function ( target )\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar clone = $( dt.table().node().cloneNode(false) )\n\t\t\t.addClass( 'dt-rowReorder-float' )\n\t\t\t.append('<tbody/>')\n\t\t\t.append( target.clone( false ) );\n\n\t\t// Match the table and column widths - read all sizes before setting\n\t\t// to reduce reflows\n\t\tvar tableWidth = target.outerWidth();\n\t\tvar tableHeight = target.outerHeight();\n\t\tvar sizes = target.children().map( function () {\n\t\t\treturn $(this).width();\n\t\t} );\n\n\t\tclone\n\t\t\t.width( tableWidth )\n\t\t\t.height( tableHeight )\n\t\t\t.find('tr').children().each( function (i) {\n\t\t\t\tthis.style.width = sizes[i]+'px';\n\t\t\t} );\n\n\t\t// Insert into the document to have it floating around\n\t\tclone.appendTo( 'body' );\n\n\t\tthis.dom.clone = clone;\n\t\tthis.s.domCloneOuterHeight = clone.outerHeight();\n\t},\n\n\n\t/**\n\t * Update the cloned item's position in the document\n\t *\n\t * @param  {object} e Event giving the mouse's position\n\t * @private\n\t */\n\t_clonePosition: function ( e )\n\t{\n\t\tvar start = this.s.start;\n\t\tvar topDiff = this._eventToPage( e, 'Y' ) - start.top;\n\t\tvar leftDiff = this._eventToPage( e, 'X' ) - start.left;\n\t\tvar snap = this.c.snapX;\n\t\tvar left;\n\t\tvar top = topDiff + start.offsetTop;\n\n\t\tif ( snap === true ) {\n\t\t\tleft = start.offsetLeft;\n\t\t}\n\t\telse if ( typeof snap === 'number' ) {\n\t\t\tleft = start.offsetLeft + snap;\n\t\t}\n\t\telse {\n\t\t\tleft = leftDiff + start.offsetLeft;\n\t\t}\n\n\t\tif(top < 0) {\n\t\t\ttop = 0\n\t\t}\n\t\telse if(top + this.s.domCloneOuterHeight > this.s.documentOuterHeight) {\n\t\t\ttop = this.s.documentOuterHeight - this.s.domCloneOuterHeight;\n\t\t}\n\n\t\tthis.dom.clone.css( {\n\t\t\ttop: top,\n\t\t\tleft: left\n\t\t} );\n\t},\n\n\n\t/**\n\t * Emit an event on the DataTable for listeners\n\t *\n\t * @param  {string} name Event name\n\t * @param  {array} args Event arguments\n\t * @private\n\t */\n\t_emitEvent: function ( name, args )\n\t{\n\t\tthis.s.dt.iterator( 'table', function ( ctx, i ) {\n\t\t\t$(ctx.nTable).triggerHandler( name+'.dt', args );\n\t\t} );\n\t},\n\n\n\t/**\n\t * Get pageX/Y position from an event, regardless of if it is a mouse or\n\t * touch event.\n\t *\n\t * @param  {object} e Event\n\t * @param  {string} pos X or Y (must be a capital)\n\t * @private\n\t */\n\t_eventToPage: function ( e, pos )\n\t{\n\t\tif ( e.type.indexOf( 'touch' ) !== -1 ) {\n\t\t\treturn e.originalEvent.touches[0][ 'page'+pos ];\n\t\t}\n\n\t\treturn e[ 'page'+pos ];\n\t},\n\n\n\t/**\n\t * Mouse down event handler. Read initial positions and add event handlers\n\t * for the move.\n\t *\n\t * @param  {object} e      Mouse event\n\t * @param  {jQuery} target TR element that is to be moved\n\t * @private\n\t */\n\t_mouseDown: function ( e, target )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar start = this.s.start;\n\n\t\tvar offset = target.offset();\n\t\tstart.top = this._eventToPage( e, 'Y' );\n\t\tstart.left = this._eventToPage( e, 'X' );\n\t\tstart.offsetTop = offset.top;\n\t\tstart.offsetLeft = offset.left;\n\t\tstart.nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );\n\n\t\tthis._cachePositions();\n\t\tthis._clone( target );\n\t\tthis._clonePosition( e );\n\n\t\tthis.dom.target = target;\n\t\ttarget.addClass( 'dt-rowReorder-moving' );\n\n\t\t$( document )\n\t\t\t.on( 'mouseup.rowReorder touchend.rowReorder', function (e) {\n\t\t\t\tthat._mouseUp(e);\n\t\t\t} )\n\t\t\t.on( 'mousemove.rowReorder touchmove.rowReorder', function (e) {\n\t\t\t\tthat._mouseMove(e);\n\t\t\t} );\n\n\t\t// Check if window is x-scrolling - if not, disable it for the duration\n\t\t// of the drag\n\t\tif ( $(window).width() === $(document).width() ) {\n\t\t\t$(document.body).addClass( 'dt-rowReorder-noOverflow' );\n\t\t}\n\n\t\t// Cache scrolling information so mouse move doesn't need to read.\n\t\t// This assumes that the window and DT scroller will not change size\n\t\t// during an row drag, which I think is a fair assumption\n\t\tvar scrollWrapper = this.dom.dtScroll;\n\t\tthis.s.scroll = {\n\t\t\twindowHeight: $(window).height(),\n\t\t\twindowWidth:  $(window).width(),\n\t\t\tdtTop:        scrollWrapper.length ? scrollWrapper.offset().top : null,\n\t\t\tdtLeft:       scrollWrapper.length ? scrollWrapper.offset().left : null,\n\t\t\tdtHeight:     scrollWrapper.length ? scrollWrapper.outerHeight() : null,\n\t\t\tdtWidth:      scrollWrapper.length ? scrollWrapper.outerWidth() : null\n\t\t};\n\t},\n\n\n\t/**\n\t * Mouse move event handler - move the cloned row and shuffle the table's\n\t * rows if required.\n\t *\n\t * @param  {object} e Mouse event\n\t * @private\n\t */\n\t_mouseMove: function ( e )\n\t{\n\t\tthis._clonePosition( e );\n\n\t\t// Transform the mouse position into a position in the table's body\n\t\tvar bodyY = this._eventToPage( e, 'Y' ) - this.s.bodyTop;\n\t\tvar middles = this.s.middles;\n\t\tvar insertPoint = null;\n\t\tvar dt = this.s.dt;\n\t\tvar body = dt.table().body();\n\n\t\t// Determine where the row should be inserted based on the mouse\n\t\t// position\n\t\tfor ( var i=0, ien=middles.length ; i<ien ; i++ ) {\n\t\t\tif ( bodyY < middles[i] ) {\n\t\t\t\tinsertPoint = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif ( insertPoint === null ) {\n\t\t\tinsertPoint = middles.length;\n\t\t}\n\n\t\t// Perform the DOM shuffle if it has changed from last time\n\t\tif ( this.s.lastInsert === null || this.s.lastInsert !== insertPoint ) {\n\t\t\tif ( insertPoint === 0 ) {\n\t\t\t\tthis.dom.target.prependTo( body );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tvar nodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );\n\n\t\t\t\tif ( insertPoint > this.s.lastInsert ) {\n\t\t\t\t\tthis.dom.target.insertAfter( nodes[ insertPoint-1 ] );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis.dom.target.insertBefore( nodes[ insertPoint ] );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._cachePositions();\n\n\t\t\tthis.s.lastInsert = insertPoint;\n\t\t}\n\n\t\tthis._shiftScroll( e );\n\t},\n\n\n\t/**\n\t * Mouse up event handler - release the event handlers and perform the\n\t * table updates\n\t *\n\t * @param  {object} e Mouse event\n\t * @private\n\t */\n\t_mouseUp: function ( e )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar i, ien;\n\t\tvar dataSrc = this.c.dataSrc;\n\n\t\tthis.dom.clone.remove();\n\t\tthis.dom.clone = null;\n\n\t\tthis.dom.target.removeClass( 'dt-rowReorder-moving' );\n\t\t//this.dom.target = null;\n\n\t\t$(document).off( '.rowReorder' );\n\t\t$(document.body).removeClass( 'dt-rowReorder-noOverflow' );\n\n\t\tclearInterval( this.s.scrollInterval );\n\t\tthis.s.scrollInterval = null;\n\n\t\t// Calculate the difference\n\t\tvar startNodes = this.s.start.nodes;\n\t\tvar endNodes = $.unique( dt.rows( { page: 'current' } ).nodes().toArray() );\n\t\tvar idDiff = {};\n\t\tvar fullDiff = [];\n\t\tvar diffNodes = [];\n\t\tvar getDataFn = this.s.getDataFn;\n\t\tvar setDataFn = this.s.setDataFn;\n\n\t\tfor ( i=0, ien=startNodes.length ; i<ien ; i++ ) {\n\t\t\tif ( startNodes[i] !== endNodes[i] ) {\n\t\t\t\tvar id = dt.row( endNodes[i] ).id();\n\t\t\t\tvar endRowData = dt.row( endNodes[i] ).data();\n\t\t\t\tvar startRowData = dt.row( startNodes[i] ).data();\n\n\t\t\t\tif ( id ) {\n\t\t\t\t\tidDiff[ id ] = getDataFn( startRowData );\n\t\t\t\t}\n\n\t\t\t\tfullDiff.push( {\n\t\t\t\t\tnode: endNodes[i],\n\t\t\t\t\toldData: getDataFn( endRowData ),\n\t\t\t\t\tnewData: getDataFn( startRowData ),\n\t\t\t\t\tnewPosition: i,\n\t\t\t\t\toldPosition: $.inArray( endNodes[i], startNodes )\n\t\t\t\t} );\n\n\t\t\t\tdiffNodes.push( endNodes[i] );\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Create event args\n\t\tvar eventArgs = [ fullDiff, {\n\t\t\tdataSrc:    dataSrc,\n\t\t\tnodes:      diffNodes,\n\t\t\tvalues:     idDiff,\n\t\t\ttriggerRow: dt.row( this.dom.target )\n\t\t} ];\n\t\t\n\t\t// Emit event\n\t\tthis._emitEvent( 'row-reorder', eventArgs );\n\n\t\tvar update = function () {\n\t\t\tif ( that.c.update ) {\n\t\t\t\tfor ( i=0, ien=fullDiff.length ; i<ien ; i++ ) {\n\t\t\t\t\tvar row = dt.row( fullDiff[i].node );\n\t\t\t\t\tvar rowData = row.data();\n\n\t\t\t\t\tsetDataFn( rowData, fullDiff[i].newData );\n\n\t\t\t\t\t// Invalidate the cell that has the same data source as the dataSrc\n\t\t\t\t\tdt.columns().every( function () {\n\t\t\t\t\t\tif ( this.dataSrc() === dataSrc ) {\n\t\t\t\t\t\t\tdt.cell( fullDiff[i].node, this.index() ).invalidate( 'data' );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\t// Trigger row reordered event\n\t\t\t\tthat._emitEvent( 'row-reordered', eventArgs );\n\n\t\t\t\tdt.draw( false );\n\t\t\t}\n\t\t};\n\n\t\t// Editor interface\n\t\tif ( this.c.editor ) {\n\t\t\t// Disable user interaction while Editor is submitting\n\t\t\tthis.c.enable = false;\n\n\t\t\tthis.c.editor\n\t\t\t\t.edit(\n\t\t\t\t\tdiffNodes,\n\t\t\t\t\tfalse,\n\t\t\t\t\t$.extend( {submit: 'changed'}, this.c.formOptions )\n\t\t\t\t)\n\t\t\t\t.multiSet( dataSrc, idDiff )\n\t\t\t\t.one( 'preSubmitCancelled.rowReorder', function () {\n\t\t\t\t\tthat.c.enable = true;\n\t\t\t\t\tthat.c.editor.off( '.rowReorder' );\n\t\t\t\t\tdt.draw( false );\n\t\t\t\t} )\n\t\t\t\t.one( 'submitUnsuccessful.rowReorder', function () {\n\t\t\t\t\tdt.draw( false );\n\t\t\t\t} )\n\t\t\t\t.one( 'submitSuccess.rowReorder', function () {\n\t\t\t\t\tupdate();\n\t\t\t\t} )\n\t\t\t\t.one( 'submitComplete', function () {\n\t\t\t\t\tthat.c.enable = true;\n\t\t\t\t\tthat.c.editor.off( '.rowReorder' );\n\t\t\t\t} )\n\t\t\t\t.submit();\n\t\t}\n\t\telse {\n\t\t\tupdate();\n\t\t}\n\t},\n\n\n\t/**\n\t * Move the window and DataTables scrolling during a drag to scroll new\n\t * content into view.\n\t *\n\t * This matches the `_shiftScroll` method used in AutoFill, but only\n\t * horizontal scrolling is considered here.\n\t *\n\t * @param  {object} e Mouse move event object\n\t * @private\n\t */\n\t_shiftScroll: function ( e )\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dt;\n\t\tvar scroll = this.s.scroll;\n\t\tvar runInterval = false;\n\t\tvar scrollSpeed = 5;\n\t\tvar buffer = 65;\n\t\tvar\n\t\t\twindowY = e.pageY - document.body.scrollTop,\n\t\t\twindowVert,\n\t\t\tdtVert;\n\n\t\t// Window calculations - based on the mouse position in the window,\n\t\t// regardless of scrolling\n\t\tif ( windowY < buffer ) {\n\t\t\twindowVert = scrollSpeed * -1;\n\t\t}\n\t\telse if ( windowY > scroll.windowHeight - buffer ) {\n\t\t\twindowVert = scrollSpeed;\n\t\t}\n\n\t\t// DataTables scrolling calculations - based on the table's position in\n\t\t// the document and the mouse position on the page\n\t\tif ( scroll.dtTop !== null && e.pageY < scroll.dtTop + buffer ) {\n\t\t\tdtVert = scrollSpeed * -1;\n\t\t}\n\t\telse if ( scroll.dtTop !== null && e.pageY > scroll.dtTop + scroll.dtHeight - buffer ) {\n\t\t\tdtVert = scrollSpeed;\n\t\t}\n\n\t\t// This is where it gets interesting. We want to continue scrolling\n\t\t// without requiring a mouse move, so we need an interval to be\n\t\t// triggered. The interval should continue until it is no longer needed,\n\t\t// but it must also use the latest scroll commands (for example consider\n\t\t// that the mouse might move from scrolling up to scrolling left, all\n\t\t// with the same interval running. We use the `scroll` object to \"pass\"\n\t\t// this information to the interval. Can't use local variables as they\n\t\t// wouldn't be the ones that are used by an already existing interval!\n\t\tif ( windowVert || dtVert ) {\n\t\t\tscroll.windowVert = windowVert;\n\t\t\tscroll.dtVert = dtVert;\n\t\t\trunInterval = true;\n\t\t}\n\t\telse if ( this.s.scrollInterval ) {\n\t\t\t// Don't need to scroll - remove any existing timer\n\t\t\tclearInterval( this.s.scrollInterval );\n\t\t\tthis.s.scrollInterval = null;\n\t\t}\n\n\t\t// If we need to run the interval to scroll and there is no existing\n\t\t// interval (if there is an existing one, it will continue to run)\n\t\tif ( ! this.s.scrollInterval && runInterval ) {\n\t\t\tthis.s.scrollInterval = setInterval( function () {\n\t\t\t\t// Don't need to worry about setting scroll <0 or beyond the\n\t\t\t\t// scroll bound as the browser will just reject that.\n\t\t\t\tif ( scroll.windowVert ) {\n\t\t\t\t\tdocument.body.scrollTop += scroll.windowVert;\n\t\t\t\t}\n\n\t\t\t\t// DataTables scrolling\n\t\t\t\tif ( scroll.dtVert ) {\n\t\t\t\t\tvar scroller = that.dom.dtScroll[0];\n\n\t\t\t\t\tif ( scroll.dtVert ) {\n\t\t\t\t\t\tscroller.scrollTop += scroll.dtVert;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, 20 );\n\t\t}\n\t}\n} );\n\n\n\n/**\n * RowReorder default settings for initialisation\n *\n * @namespace\n * @name RowReorder.defaults\n * @static\n */\nRowReorder.defaults = {\n\t/**\n\t * Data point in the host row's data source object for where to get and set\n\t * the data to reorder. This will normally also be the sorting column.\n\t *\n\t * @type {Number}\n\t */\n\tdataSrc: 0,\n\n\t/**\n\t * Editor instance that will be used to perform the update\n\t *\n\t * @type {DataTable.Editor}\n\t */\n\teditor: null,\n\n\t/**\n\t * Enable / disable RowReorder's user interaction\n\t * @type {Boolean}\n\t */\n\tenable: true,\n\n\t/**\n\t * Form options to pass to Editor when submitting a change in the row order.\n\t * See the Editor `from-options` object for details of the options\n\t * available.\n\t * @type {Object}\n\t */\n\tformOptions: {},\n\n\t/**\n\t * Drag handle selector. This defines the element that when dragged will\n\t * reorder a row.\n\t *\n\t * @type {String}\n\t */\n\tselector: 'td:first-child',\n\n\t/**\n\t * Optionally lock the dragged row's x-position. This can be `true` to\n\t * fix the position match the host table's, `false` to allow free movement\n\t * of the row, or a number to define an offset from the host table.\n\t *\n\t * @type {Boolean|number}\n\t */\n\tsnapX: false,\n\n\t/**\n\t * Update the table's data on drop\n\t *\n\t * @type {Boolean}\n\t */\n\tupdate: true,\n\n\t/**\n\t * Selector for children of the drag handle selector that mouseDown events\n\t * will be passed through to and drag will not activate\n\t *\n\t * @type {String}\n\t */\n\texcludedChildren: 'a'\n};\n\n\n/*\n * API\n */\nvar Api = $.fn.dataTable.Api;\n\n// Doesn't do anything - work around for a bug in DT... Not documented\nApi.register( 'rowReorder()', function () {\n\treturn this;\n} );\n\nApi.register( 'rowReorder.enable()', function ( toggle ) {\n\tif ( toggle === undefined ) {\n\t\ttoggle = true;\n\t}\n\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx.rowreorder ) {\n\t\t\tctx.rowreorder.c.enable = toggle;\n\t\t}\n\t} );\n} );\n\nApi.register( 'rowReorder.disable()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx.rowreorder ) {\n\t\t\tctx.rowreorder.c.enable = false;\n\t\t}\n\t} );\n} );\n\n\n/**\n * Version information\n *\n * @name RowReorder.version\n * @static\n */\nRowReorder.version = '1.2.4';\n\n\n$.fn.dataTable.RowReorder = RowReorder;\n$.fn.DataTable.RowReorder = RowReorder;\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'init.dt.dtr', function (e, settings, json) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.rowReorder;\n\tvar defaults = DataTable.defaults.rowReorder;\n\n\tif ( init || defaults ) {\n\t\tvar opts = $.extend( {}, init, defaults );\n\n\t\tif ( init !== false ) {\n\t\t\tnew RowReorder( settings, opts  );\n\t\t}\n\t}\n} );\n\n\nreturn RowReorder;\n}));\n\n\n/*! Scroller 2.0.0\n * ©2011-2018 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     Scroller\n * @description Virtual rendering for DataTables\n * @version     2.0.0\n * @file        dataTables.scroller.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2011-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n/**\n * Scroller is a virtual rendering plug-in for DataTables which allows large\n * datasets to be drawn on screen every quickly. What the virtual rendering means\n * is that only the visible portion of the table (and a bit to either side to make\n * the scrolling smooth) is drawn, while the scrolling container gives the\n * visual impression that the whole table is visible. This is done by making use\n * of the pagination abilities of DataTables and moving the table around in the\n * scrolling container DataTables adds to the page. The scrolling container is\n * forced to the height it would be for the full table display using an extra\n * element.\n *\n * Note that rows in the table MUST all be the same height. Information in a cell\n * which expands on to multiple lines will cause some odd behaviour in the scrolling.\n *\n * Scroller is initialised by simply including the letter 'S' in the sDom for the\n * table you want to have this feature enabled on. Note that the 'S' must come\n * AFTER the 't' parameter in `dom`.\n *\n * Key features include:\n *   <ul class=\"limit_length\">\n *     <li>Speed! The aim of Scroller for DataTables is to make rendering large data sets fast</li>\n *     <li>Full compatibility with deferred rendering in DataTables for maximum speed</li>\n *     <li>Display millions of rows</li>\n *     <li>Integration with state saving in DataTables (scrolling position is saved)</li>\n *     <li>Easy to use</li>\n *   </ul>\n *\n *  @class\n *  @constructor\n *  @global\n *  @param {object} dt DataTables settings object or API instance\n *  @param {object} [opts={}] Configuration object for FixedColumns. Options \n *    are defined by {@link Scroller.defaults}\n *\n *  @requires jQuery 1.7+\n *  @requires DataTables 1.10.0+\n *\n *  @example\n *    $(document).ready(function() {\n *        $('#example').DataTable( {\n *            \"scrollY\": \"200px\",\n *            \"ajax\": \"media/dataset/large.txt\",\n *            \"scroller\": true,\n *            \"deferRender\": true\n *        } );\n *    } );\n */\nvar Scroller = function ( dt, opts ) {\n\t/* Sanity check - you just know it will happen */\n\tif ( ! (this instanceof Scroller) ) {\n\t\talert( \"Scroller warning: Scroller must be initialised with the 'new' keyword.\" );\n\t\treturn;\n\t}\n\n\tif ( opts === undefined ) {\n\t\topts = {};\n\t}\n\n\tvar dtApi = $.fn.dataTable.Api( dt );\n\n\t/**\n\t * Settings object which contains customisable information for the Scroller instance\n\t * @namespace\n\t * @private\n\t * @extends Scroller.defaults\n\t */\n\tthis.s = {\n\t\t/**\n\t\t * DataTables settings object\n\t\t *  @type     object\n\t\t *  @default  Passed in as first parameter to constructor\n\t\t */\n\t\tdt: dtApi.settings()[0],\n\n\t\t/**\n\t\t * DataTables API instance\n\t\t *  @type     DataTable.Api\n\t\t */\n\t\tdtApi: dtApi,\n\n\t\t/**\n\t\t * Pixel location of the top of the drawn table in the viewport\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t */\n\t\ttableTop: 0,\n\n\t\t/**\n\t\t * Pixel location of the bottom of the drawn table in the viewport\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t */\n\t\ttableBottom: 0,\n\n\t\t/**\n\t\t * Pixel location of the boundary for when the next data set should be loaded and drawn\n\t\t * when scrolling up the way.\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t *  @private\n\t\t */\n\t\tredrawTop: 0,\n\n\t\t/**\n\t\t * Pixel location of the boundary for when the next data set should be loaded and drawn\n\t\t * when scrolling down the way. Note that this is actually calculated as the offset from\n\t\t * the top.\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t *  @private\n\t\t */\n\t\tredrawBottom: 0,\n\n\t\t/**\n\t\t * Auto row height or not indicator\n\t\t *  @type     bool\n\t\t *  @default  0\n\t\t */\n\t\tautoHeight: true,\n\n\t\t/**\n\t\t * Number of rows calculated as visible in the visible viewport\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t */\n\t\tviewportRows: 0,\n\n\t\t/**\n\t\t * setTimeout reference for state saving, used when state saving is enabled in the DataTable\n\t\t * and when the user scrolls the viewport in order to stop the cookie set taking too much\n\t\t * CPU!\n\t\t *  @type     int\n\t\t *  @default  0\n\t\t */\n\t\tstateTO: null,\n\n\t\t/**\n\t\t * setTimeout reference for the redraw, used when server-side processing is enabled in the\n\t\t * DataTables in order to prevent DoSing the server\n\t\t *  @type     int\n\t\t *  @default  null\n\t\t */\n\t\tdrawTO: null,\n\n\t\theights: {\n\t\t\tjump: null,\n\t\t\tpage: null,\n\t\t\tvirtual: null,\n\t\t\tscroll: null,\n\n\t\t\t/**\n\t\t\t * Height of rows in the table\n\t\t\t *  @type     int\n\t\t\t *  @default  0\n\t\t\t */\n\t\t\trow: null,\n\n\t\t\t/**\n\t\t\t * Pixel height of the viewport\n\t\t\t *  @type     int\n\t\t\t *  @default  0\n\t\t\t */\n\t\t\tviewport: null,\n\t\t\tlabelFactor: 1\n\t\t},\n\n\t\ttopRowFloat: 0,\n\t\tscrollDrawDiff: null,\n\t\tloaderVisible: false,\n\t\tforceReposition: false,\n\t\tbaseRowTop: 0,\n\t\tbaseScrollTop: 0,\n\t\tmousedown: false,\n\t\tlastScrollTop: 0\n\t};\n\n\t// @todo The defaults should extend a `c` property and the internal settings\n\t// only held in the `s` property. At the moment they are mixed\n\tthis.s = $.extend( this.s, Scroller.oDefaults, opts );\n\n\t// Workaround for row height being read from height object (see above comment)\n\tthis.s.heights.row = this.s.rowHeight;\n\n\t/**\n\t * DOM elements used by the class instance\n\t * @private\n\t * @namespace\n\t *\n\t */\n\tthis.dom = {\n\t\t\"force\":    document.createElement('div'),\n\t\t\"label\":    $('<div class=\"dts_label\">0</div>'),\n\t\t\"scroller\": null,\n\t\t\"table\":    null,\n\t\t\"loader\":   null\n\t};\n\n\t// Attach the instance to the DataTables instance so it can be accessed in\n\t// future. Don't initialise Scroller twice on the same table\n\tif ( this.s.dt.oScroller ) {\n\t\treturn;\n\t}\n\n\tthis.s.dt.oScroller = this;\n\n\t/* Let's do it */\n\tthis.construct();\n};\n\n\n\n$.extend( Scroller.prototype, {\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Public methods - to be exposed via the DataTables API\n\t */\n\n\t/**\n\t * Calculate and store information about how many rows are to be displayed\n\t * in the scrolling viewport, based on current dimensions in the browser's\n\t * rendering. This can be particularly useful if the table is initially\n\t * drawn in a hidden element - for example in a tab.\n\t *  @param {bool} [redraw=true] Redraw the table automatically after the recalculation, with\n\t *    the new dimensions forming the basis for the draw.\n\t *  @returns {void}\n\t */\n\tmeasure: function ( redraw )\n\t{\n\t\tif ( this.s.autoHeight )\n\t\t{\n\t\t\tthis._calcRowHeight();\n\t\t}\n\n\t\tvar heights = this.s.heights;\n\n\t\tif ( heights.row ) {\n\t\t\theights.viewport = $.contains(document, this.dom.scroller) ?\n\t\t\t\tthis.dom.scroller.clientHeight :\n\t\t\t\tthis._parseHeight($(this.dom.scroller).css('height'));\n\n\t\t\t// If collapsed (no height) use the max-height parameter\n\t\t\tif ( ! heights.viewport ) {\n\t\t\t\theights.viewport = this._parseHeight($(this.dom.scroller).css('max-height'));\n\t\t\t}\n\n\t\t\tthis.s.viewportRows = parseInt( heights.viewport / heights.row, 10 )+1;\n\t\t\tthis.s.dt._iDisplayLength = this.s.viewportRows * this.s.displayBuffer;\n\t\t}\n\n\t\tvar label = this.dom.label.outerHeight();\n\t\theights.labelFactor = (heights.viewport-label) / heights.scroll;\n\n\t\tif ( redraw === undefined || redraw )\n\t\t{\n\t\t\tthis.s.dt.oInstance.fnDraw( false );\n\t\t}\n\t},\n\n\t/**\n\t * Get information about current displayed record range. This corresponds to\n\t * the information usually displayed in the \"Info\" block of the table.\n\t *\n\t * @returns {object} info as an object:\n\t *  {\n\t *      start: {int}, // the 0-indexed record at the top of the viewport\n\t *      end:   {int}, // the 0-indexed record at the bottom of the viewport\n\t *  }\n\t*/\n\tpageInfo: function()\n\t{\n\t\tvar \n\t\t\tdt = this.s.dt,\n\t\t\tiScrollTop = this.dom.scroller.scrollTop,\n\t\t\tiTotal = dt.fnRecordsDisplay(),\n\t\t\tiPossibleEnd = Math.ceil(this.pixelsToRow(iScrollTop + this.s.heights.viewport, false, this.s.ani));\n\n\t\treturn {\n\t\t\tstart: Math.floor(this.pixelsToRow(iScrollTop, false, this.s.ani)),\n\t\t\tend: iTotal < iPossibleEnd ? iTotal-1 : iPossibleEnd-1\n\t\t};\n\t},\n\n\t/**\n\t * Calculate the row number that will be found at the given pixel position\n\t * (y-scroll).\n\t *\n\t * Please note that when the height of the full table exceeds 1 million\n\t * pixels, Scroller switches into a non-linear mode for the scrollbar to fit\n\t * all of the records into a finite area, but this function returns a linear\n\t * value (relative to the last non-linear positioning).\n\t *  @param {int} pixels Offset from top to calculate the row number of\n\t *  @param {int} [intParse=true] If an integer value should be returned\n\t *  @param {int} [virtual=false] Perform the calculations in the virtual domain\n\t *  @returns {int} Row index\n\t */\n\tpixelsToRow: function ( pixels, intParse, virtual )\n\t{\n\t\tvar diff = pixels - this.s.baseScrollTop;\n\t\tvar row = virtual ?\n\t\t\t(this._domain( 'physicalToVirtual', this.s.baseScrollTop ) + diff) / this.s.heights.row :\n\t\t\t( diff / this.s.heights.row ) + this.s.baseRowTop;\n\n\t\treturn intParse || intParse === undefined ?\n\t\t\tparseInt( row, 10 ) :\n\t\t\trow;\n\t},\n\n\t/**\n\t * Calculate the pixel position from the top of the scrolling container for\n\t * a given row\n\t *  @param {int} iRow Row number to calculate the position of\n\t *  @returns {int} Pixels\n\t */\n\trowToPixels: function ( rowIdx, intParse, virtual )\n\t{\n\t\tvar pixels;\n\t\tvar diff = rowIdx - this.s.baseRowTop;\n\n\t\tif ( virtual ) {\n\t\t\tpixels = this._domain( 'virtualToPhysical', this.s.baseScrollTop );\n\t\t\tpixels += diff * this.s.heights.row;\n\t\t}\n\t\telse {\n\t\t\tpixels = this.s.baseScrollTop;\n\t\t\tpixels += diff * this.s.heights.row;\n\t\t}\n\n\t\treturn intParse || intParse === undefined ?\n\t\t\tparseInt( pixels, 10 ) :\n\t\t\tpixels;\n\t},\n\n\n\t/**\n\t * Calculate the row number that will be found at the given pixel position (y-scroll)\n\t *  @param {int} row Row index to scroll to\n\t *  @param {bool} [animate=true] Animate the transition or not\n\t *  @returns {void}\n\t */\n\tscrollToRow: function ( row, animate )\n\t{\n\t\tvar that = this;\n\t\tvar ani = false;\n\t\tvar px = this.rowToPixels( row );\n\n\t\t// We need to know if the table will redraw or not before doing the\n\t\t// scroll. If it will not redraw, then we need to use the currently\n\t\t// displayed table, and scroll with the physical pixels. Otherwise, we\n\t\t// need to calculate the table's new position from the virtual\n\t\t// transform.\n\t\tvar preRows = ((this.s.displayBuffer-1)/2) * this.s.viewportRows;\n\t\tvar drawRow = row - preRows;\n\t\tif ( drawRow < 0 ) {\n\t\t\tdrawRow = 0;\n\t\t}\n\n\t\tif ( (px > this.s.redrawBottom || px < this.s.redrawTop) && this.s.dt._iDisplayStart !== drawRow ) {\n\t\t\tani = true;\n\t\t\tpx = this._domain( 'virtualToPhysical', row * this.s.heights.row );\n\n\t\t\t// If we need records outside the current draw region, but the new\n\t\t\t// scrolling position is inside that (due to the non-linear nature\n\t\t\t// for larger numbers of records), we need to force position update.\n\t\t\tif ( this.s.redrawTop < px && px < this.s.redrawBottom ) {\n\t\t\t\tthis.s.forceReposition = true;\n\t\t\t\tanimate = false;\n\t\t\t}\n\t\t}\n\n\t\tif ( typeof animate == 'undefined' || animate )\n\t\t{\n\t\t\tthis.s.ani = ani;\n\t\t\t$(this.dom.scroller).animate( {\n\t\t\t\t\"scrollTop\": px\n\t\t\t}, function () {\n\t\t\t\t// This needs to happen after the animation has completed and\n\t\t\t\t// the final scroll event fired\n\t\t\t\tsetTimeout( function () {\n\t\t\t\t\tthat.s.ani = false;\n\t\t\t\t}, 25 );\n\t\t\t} );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$(this.dom.scroller).scrollTop( px );\n\t\t}\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Constructor\n\t */\n\n\t/**\n\t * Initialisation for Scroller\n\t *  @returns {void}\n\t *  @private\n\t */\n\tconstruct: function ()\n\t{\n\t\tvar that = this;\n\t\tvar dt = this.s.dtApi;\n\n\t\t/* Sanity check */\n\t\tif ( !this.s.dt.oFeatures.bPaginate ) {\n\t\t\tthis.s.dt.oApi._fnLog( this.s.dt, 0, 'Pagination must be enabled for Scroller' );\n\t\t\treturn;\n\t\t}\n\n\t\t/* Insert a div element that we can use to force the DT scrolling container to\n\t\t * the height that would be required if the whole table was being displayed\n\t\t */\n\t\tthis.dom.force.style.position = \"relative\";\n\t\tthis.dom.force.style.top = \"0px\";\n\t\tthis.dom.force.style.left = \"0px\";\n\t\tthis.dom.force.style.width = \"1px\";\n\n\t\tthis.dom.scroller = $('div.'+this.s.dt.oClasses.sScrollBody, this.s.dt.nTableWrapper)[0];\n\t\tthis.dom.scroller.appendChild( this.dom.force );\n\t\tthis.dom.scroller.style.position = \"relative\";\n\n\t\tthis.dom.table = $('>table', this.dom.scroller)[0];\n\t\tthis.dom.table.style.position = \"absolute\";\n\t\tthis.dom.table.style.top = \"0px\";\n\t\tthis.dom.table.style.left = \"0px\";\n\n\t\t// Add class to 'announce' that we are a Scroller table\n\t\t$(dt.table().container()).addClass('dts DTS');\n\n\t\t// Add a 'loading' indicator\n\t\tif ( this.s.loadingIndicator )\n\t\t{\n\t\t\tthis.dom.loader = $('<div class=\"dataTables_processing dts_loading\">'+this.s.dt.oLanguage.sLoadingRecords+'</div>')\n\t\t\t\t.css('display', 'none');\n\n\t\t\t$(this.dom.scroller.parentNode)\n\t\t\t\t.css('position', 'relative')\n\t\t\t\t.append( this.dom.loader );\n\t\t}\n\n\t\tthis.dom.label.appendTo(this.dom.scroller);\n\n\t\t/* Initial size calculations */\n\t\tif ( this.s.heights.row && this.s.heights.row != 'auto' )\n\t\t{\n\t\t\tthis.s.autoHeight = false;\n\t\t}\n\t\tthis.measure( false );\n\n\t\t// Scrolling callback to see if a page change is needed - use a throttled\n\t\t// function for the save save callback so we aren't hitting it on every\n\t\t// scroll\n\t\tthis.s.ingnoreScroll = true;\n\t\tthis.s.stateSaveThrottle = this.s.dt.oApi._fnThrottle( function () {\n\t\t\tthat.s.dtApi.state.save();\n\t\t}, 500 );\n\t\t$(this.dom.scroller).on( 'scroll.dt-scroller', function (e) {\n\t\t\tthat._scroll.call( that );\n\t\t} );\n\n\t\t// In iOS we catch the touchstart event in case the user tries to scroll\n\t\t// while the display is already scrolling\n\t\t$(this.dom.scroller).on('touchstart.dt-scroller', function () {\n\t\t\tthat._scroll.call( that );\n\t\t} );\n\n\t\t$(this.dom.scroller)\n\t\t\t.on('mousedown.dt-scroller', function () {\n\t\t\t\tthat.s.mousedown = true;\n\t\t\t})\n\t\t\t.on('mouseup.dt-scroller', function () {\n\t\t\t\tthat.s.mouseup = false;\n\t\t\t\tthat.dom.label.css('display', 'none');\n\t\t\t});\n\n\t\t// On resize, update the information element, since the number of rows shown might change\n\t\t$(window).on( 'resize.dt-scroller', function () {\n\t\t\tthat.measure( false );\n\t\t\tthat._info();\n\t\t} );\n\n\t\t// Add a state saving parameter to the DT state saving so we can restore the exact\n\t\t// position of the scrolling. Slightly surprisingly the scroll position isn't actually\n\t\t// stored, but rather tha base units which are needed to calculate it. This allows for\n\t\t// virtual scrolling as well.\n\t\tvar initialStateSave = true;\n\t\tvar loadedState = dt.state.loaded();\n\n\t\tdt.on( 'stateSaveParams.scroller', function ( e, settings, data ) {\n\t\t\t// Need to used the saved position on init\n\t\t\tdata.scroller = {\n\t\t\t\ttopRow: initialStateSave && loadedState && loadedState.scroller ?\n\t\t\t\t\tloadedState.scroller.topRow :\n\t\t\t\t\tthat.s.topRowFloat,\n\t\t\t\tbaseScrollTop: that.s.baseScrollTop,\n\t\t\t\tbaseRowTop: that.s.baseRowTop\n\t\t\t};\n\n\t\t\tinitialStateSave = false;\n\t\t} );\n\n\t\tif ( loadedState && loadedState.scroller ) {\n\t\t\tthis.s.topRowFloat = loadedState.scroller.topRow;\n\t\t\tthis.s.baseScrollTop = loadedState.scroller.baseScrollTop;\n\t\t\tthis.s.baseRowTop = loadedState.scroller.baseRowTop;\n\t\t}\n\n\t\tdt.on( 'init.scroller', function () {\n\t\t\tthat.measure( false );\n\n\t\t\tthat._draw();\n\n\t\t\t// Update the scroller when the DataTable is redrawn\n\t\t\tdt.on( 'draw.scroller', function () {\n\t\t\t\tthat._draw();\n\t\t\t});\n\t\t} );\n\n\t\t// Set height before the draw happens, allowing everything else to update\n\t\t// on draw complete without worry for roder.\n\t\tdt.on( 'preDraw.dt.scroller', function () {\n\t\t\tthat._scrollForce();\n\t\t} );\n\n\t\t// Destructor\n\t\tdt.on( 'destroy.scroller', function () {\n\t\t\t$(window).off( 'resize.dt-scroller' );\n\t\t\t$(that.dom.scroller).off('.dt-scroller');\n\t\t\t$(that.s.dt.nTable).off( '.scroller' );\n\n\t\t\t$(that.s.dt.nTableWrapper).removeClass('DTS');\n\t\t\t$('div.DTS_Loading', that.dom.scroller.parentNode).remove();\n\n\t\t\tthat.dom.table.style.position = \"\";\n\t\t\tthat.dom.table.style.top = \"\";\n\t\t\tthat.dom.table.style.left = \"\";\n\t\t} );\n\t},\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Private methods\n\t */\n\n\t/**\n\t * Automatic calculation of table row height. This is just a little tricky here as using\n\t * initialisation DataTables has tale the table out of the document, so we need to create\n\t * a new table and insert it into the document, calculate the row height and then whip the\n\t * table out.\n\t *  @returns {void}\n\t *  @private\n\t */\n\t_calcRowHeight: function ()\n\t{\n\t\tvar dt = this.s.dt;\n\t\tvar origTable = dt.nTable;\n\t\tvar nTable = origTable.cloneNode( false );\n\t\tvar tbody = $('<tbody/>').appendTo( nTable );\n\t\tvar container = $(\n\t\t\t'<div class=\"'+dt.oClasses.sWrapper+' DTS\">'+\n\t\t\t\t'<div class=\"'+dt.oClasses.sScrollWrapper+'\">'+\n\t\t\t\t\t'<div class=\"'+dt.oClasses.sScrollBody+'\"></div>'+\n\t\t\t\t'</div>'+\n\t\t\t'</div>'\n\t\t);\n\n\t\t// Want 3 rows in the sizing table so :first-child and :last-child\n\t\t// CSS styles don't come into play - take the size of the middle row\n\t\t$('tbody tr:lt(4)', origTable).clone().appendTo( tbody );\n        var rowsCount = $('tr', tbody).length;\n\n        if ( rowsCount === 1 ) {\n            tbody.prepend('<tr><td>&#160;</td></tr>');\n            tbody.append('<tr><td>&#160;</td></tr>');\n\t\t}\n\t\telse {\n            for (; rowsCount < 3; rowsCount++) {\n                tbody.append('<tr><td>&#160;</td></tr>');\n            }\n\t\t}\n\t\n\t\t$('div.'+dt.oClasses.sScrollBody, container).append( nTable );\n\n\t\t// If initialised using `dom`, use the holding element as the insert point\n\t\tvar insertEl = this.s.dt.nHolding || origTable.parentNode;\n\n\t\tif ( ! $(insertEl).is(':visible') ) {\n\t\t\tinsertEl = 'body';\n\t\t}\n\n\t\tcontainer.appendTo( insertEl );\n\t\tthis.s.heights.row = $('tr', tbody).eq(1).outerHeight();\n\n\t\tcontainer.remove();\n\t},\n\n\t/**\n\t * Draw callback function which is fired when the DataTable is redrawn. The main function of\n\t * this method is to position the drawn table correctly the scrolling container for the rows\n\t * that is displays as a result of the scrolling position.\n\t *  @returns {void}\n\t *  @private\n\t */\n\t_draw: function ()\n\t{\n\t\tvar\n\t\t\tthat = this,\n\t\t\theights = this.s.heights,\n\t\t\tiScrollTop = this.dom.scroller.scrollTop,\n\t\t\tiActualScrollTop = iScrollTop,\n\t\t\tiScrollBottom = iScrollTop + heights.viewport,\n\t\t\tiTableHeight = $(this.s.dt.nTable).height(),\n\t\t\tdisplayStart = this.s.dt._iDisplayStart,\n\t\t\tdisplayLen = this.s.dt._iDisplayLength,\n\t\t\tdisplayEnd = this.s.dt.fnRecordsDisplay();\n\n\t\t// Disable the scroll event listener while we are updating the DOM\n\t\tthis.s.skip = true;\n\n\t\t// If paging is reset\n\t\tif ( (this.s.dt.bSorted || this.s.dt.bFiltered) && displayStart === 0 && !this.s.dt._drawHold ) {\n\t\t\tthis.s.topRowFloat = 0;\n\t\t}\n\n\t\tiScrollTop = this.scrollType === 'jump' ?\n\t\t\tthis._domain( 'physicalToVirtual', this.s.topRowFloat * heights.row ) :\n\t\t\tiScrollTop;\n\n\t\t// This doesn't work when scrolling with the mouse wheel\n\t\t$(that.dom.scroller).scrollTop(iScrollTop);\n\n\t\t// Store positional information so positional calculations can be based\n\t\t// upon the current table draw position\n\t\tthis.s.baseScrollTop = iScrollTop;\n\t\tthis.s.baseRowTop = this.s.topRowFloat;\n\n\t\t// Position the table in the virtual scroller\n\t\tvar tableTop = iScrollTop - ((this.s.topRowFloat - displayStart) * heights.row);\n\t\tif ( displayStart === 0 ) {\n\t\t\ttableTop = 0;\n\t\t}\n\t\telse if ( displayStart + displayLen >= displayEnd ) {\n\t\t\ttableTop = heights.scroll - iTableHeight;\n\t\t}\n\n\t\tthis.dom.table.style.top = tableTop+'px';\n\n\t\t/* Cache some information for the scroller */\n\t\tthis.s.tableTop = tableTop;\n\t\tthis.s.tableBottom = iTableHeight + this.s.tableTop;\n\n\t\t// Calculate the boundaries for where a redraw will be triggered by the\n\t\t// scroll event listener\n\t\tvar boundaryPx = (iScrollTop - this.s.tableTop) * this.s.boundaryScale;\n\t\tthis.s.redrawTop = iScrollTop - boundaryPx;\n\t\tthis.s.redrawBottom = iScrollTop + boundaryPx > heights.scroll - heights.viewport - heights.row ?\n\t\t\theights.scroll - heights.viewport - heights.row :\n\t\t\tiScrollTop + boundaryPx;\n\n\t\tthis.s.skip = false;\n\n\t\t// Restore the scrolling position that was saved by DataTable's state\n\t\t// saving Note that this is done on the second draw when data is Ajax\n\t\t// sourced, and the first draw when DOM soured\n\t\tif ( this.s.dt.oFeatures.bStateSave && this.s.dt.oLoadedState !== null &&\n\t\t\t typeof this.s.dt.oLoadedState.iScroller != 'undefined' )\n\t\t{\n\t\t\t// A quirk of DataTables is that the draw callback will occur on an\n\t\t\t// empty set if Ajax sourced, but not if server-side processing.\n\t\t\tvar ajaxSourced = (this.s.dt.sAjaxSource || that.s.dt.ajax) && ! this.s.dt.oFeatures.bServerSide ?\n\t\t\t\ttrue :\n\t\t\t\tfalse;\n\n\t\t\tif ( ( ajaxSourced && this.s.dt.iDraw == 2) ||\n\t\t\t     (!ajaxSourced && this.s.dt.iDraw == 1) )\n\t\t\t{\n\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t$(that.dom.scroller).scrollTop( that.s.dt.oLoadedState.iScroller );\n\t\t\t\t\tthat.s.redrawTop = that.s.dt.oLoadedState.iScroller - (heights.viewport/2);\n\n\t\t\t\t\t// In order to prevent layout thrashing we need another\n\t\t\t\t\t// small delay\n\t\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t\tthat.s.ingnoreScroll = false;\n\t\t\t\t\t}, 0 );\n\t\t\t\t}, 0 );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tthat.s.ingnoreScroll = false;\n\t\t}\n\n\t\t// Because of the order of the DT callbacks, the info update will\n\t\t// take precedence over the one we want here. So a 'thread' break is\n\t\t// needed.  Only add the thread break if bInfo is set\n\t\tif ( this.s.dt.oFeatures.bInfo ) {\n\t\t\tsetTimeout( function () {\n\t\t\t\tthat._info.call( that );\n\t\t\t}, 0 );\n\t\t}\n\n\t\t// Hide the loading indicator\n\t\tif ( this.dom.loader && this.s.loaderVisible ) {\n\t\t\tthis.dom.loader.css( 'display', 'none' );\n\t\t\tthis.s.loaderVisible = false;\n\t\t}\n\t},\n\n\t/**\n\t * Convert from one domain to another. The physical domain is the actual\n\t * pixel count on the screen, while the virtual is if we had browsers which\n\t * had scrolling containers of infinite height (i.e. the absolute value)\n\t *\n\t *  @param {string} dir Domain transform direction, `virtualToPhysical` or\n\t *    `physicalToVirtual` \n\t *  @returns {number} Calculated transform\n\t *  @private\n\t */\n\t_domain: function ( dir, val )\n\t{\n\t\tvar heights = this.s.heights;\n\t\tvar diff;\n\t\tvar magic = 10000; // the point at which the non-linear calculations start to happen\n\n\t\t// If the virtual and physical height match, then we use a linear\n\t\t// transform between the two, allowing the scrollbar to be linear\n\t\tif ( heights.virtual === heights.scroll ) {\n\t\t\treturn val;\n\t\t}\n\n\t\t// In the first 10k pixels and the last 10k pixels, we want the scrolling\n\t\t// to be linear. After that it can be non-linear. It would be unusual for\n\t\t// anyone to mouse wheel through that much.\n\t\tif ( val < magic ) {\n\t\t\treturn val;\n\t\t}\n\t\telse if ( dir === 'virtualToPhysical' && val > heights.virtual - magic ) {\n\t\t\tdiff = heights.virtual - val;\n\t\t\treturn heights.scroll - diff;\n\t\t}\n\t\telse if ( dir === 'physicalToVirtual' && val > heights.scroll - magic ) {\n\t\t\tdiff = heights.scroll - val;\n\t\t\treturn heights.virtual - diff;\n\t\t}\n\n\t\t// Otherwise, we want a non-linear scrollbar to take account of the\n\t\t// redrawing regions at the start and end of the table, otherwise these\n\t\t// can stutter badly - on large tables 30px (for example) scroll might\n\t\t// be hundreds of rows, so the table would be redrawing every few px at\n\t\t// the start and end. Use a simple linear eq. to stop this, effectively\n\t\t// causing a kink in the scrolling ratio. It does mean the scrollbar is\n\t\t// non-linear, but with such massive data sets, the scrollbar is going\n\t\t// to be a best guess anyway\n\t\tvar xMax = dir === 'virtualToPhysical' ?\n\t\t\theights.virtual :\n\t\t\theights.scroll;\n\t\tvar yMax = dir === 'virtualToPhysical' ?\n\t\t\theights.scroll :\n\t\t\theights.virtual;\n\n\t\tvar m = (yMax - magic) / (xMax - magic);\n\t\tvar c = magic - (m*magic);\n\n\t\treturn (m*val) + c;\n\t},\n\n\t/**\n\t * Update any information elements that are controlled by the DataTable based on the scrolling\n\t * viewport and what rows are visible in it. This function basically acts in the same way as\n\t * _fnUpdateInfo in DataTables, and effectively replaces that function.\n\t *  @returns {void}\n\t *  @private\n\t */\n\t_info: function ()\n\t{\n\t\tif ( !this.s.dt.oFeatures.bInfo )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tvar\n\t\t\tdt = this.s.dt,\n\t\t\tlanguage = dt.oLanguage,\n\t\t\tiScrollTop = this.dom.scroller.scrollTop,\n\t\t\tiStart = Math.floor( this.pixelsToRow(iScrollTop, false, this.s.ani)+1 ),\n\t\t\tiMax = dt.fnRecordsTotal(),\n\t\t\tiTotal = dt.fnRecordsDisplay(),\n\t\t\tiPossibleEnd = Math.ceil( this.pixelsToRow(iScrollTop+this.s.heights.viewport, false, this.s.ani) ),\n\t\t\tiEnd = iTotal < iPossibleEnd ? iTotal : iPossibleEnd,\n\t\t\tsStart = dt.fnFormatNumber( iStart ),\n\t\t\tsEnd = dt.fnFormatNumber( iEnd ),\n\t\t\tsMax = dt.fnFormatNumber( iMax ),\n\t\t\tsTotal = dt.fnFormatNumber( iTotal ),\n\t\t\tsOut;\n\n\t\tif ( dt.fnRecordsDisplay() === 0 &&\n\t\t\t   dt.fnRecordsDisplay() == dt.fnRecordsTotal() )\n\t\t{\n\t\t\t/* Empty record set */\n\t\t\tsOut = language.sInfoEmpty+ language.sInfoPostFix;\n\t\t}\n\t\telse if ( dt.fnRecordsDisplay() === 0 )\n\t\t{\n\t\t\t/* Empty record set after filtering */\n\t\t\tsOut = language.sInfoEmpty +' '+\n\t\t\t\tlanguage.sInfoFiltered.replace('_MAX_', sMax)+\n\t\t\t\t\tlanguage.sInfoPostFix;\n\t\t}\n\t\telse if ( dt.fnRecordsDisplay() == dt.fnRecordsTotal() )\n\t\t{\n\t\t\t/* Normal record set */\n\t\t\tsOut = language.sInfo.\n\t\t\t\t\treplace('_START_', sStart).\n\t\t\t\t\treplace('_END_',   sEnd).\n\t\t\t\t\treplace('_MAX_',   sMax).\n\t\t\t\t\treplace('_TOTAL_', sTotal)+\n\t\t\t\tlanguage.sInfoPostFix;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Record set after filtering */\n\t\t\tsOut = language.sInfo.\n\t\t\t\t\treplace('_START_', sStart).\n\t\t\t\t\treplace('_END_',   sEnd).\n\t\t\t\t\treplace('_MAX_',   sMax).\n\t\t\t\t\treplace('_TOTAL_', sTotal) +' '+\n\t\t\t\tlanguage.sInfoFiltered.replace(\n\t\t\t\t\t'_MAX_',\n\t\t\t\t\tdt.fnFormatNumber(dt.fnRecordsTotal())\n\t\t\t\t)+\n\t\t\t\tlanguage.sInfoPostFix;\n\t\t}\n\n\t\tvar callback = language.fnInfoCallback;\n\t\tif ( callback ) {\n\t\t\tsOut = callback.call( dt.oInstance,\n\t\t\t\tdt, iStart, iEnd, iMax, iTotal, sOut\n\t\t\t);\n\t\t}\n\n\t\tvar n = dt.aanFeatures.i;\n\t\tif ( typeof n != 'undefined' )\n\t\t{\n\t\t\tfor ( var i=0, iLen=n.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t$(n[i]).html( sOut );\n\t\t\t}\n\t\t}\n\n\t\t// DT doesn't actually (yet) trigger this event, but it will in future\n\t\t$(dt.nTable).triggerHandler( 'info.dt' );\n\t},\n\n\t/**\n\t * Parse CSS height property string as number\n\t *\n\t * An attempt is made to parse the string as a number. Currently supported units are 'px',\n\t * 'vh', and 'rem'. 'em' is partially supported; it works as long as the parent element's\n\t * font size matches the body element. Zero is returned for unrecognized strings.\n\t *  @param {string} cssHeight CSS height property string\n\t *  @returns {number} height\n\t *  @private\n\t */\n\t_parseHeight: function(cssHeight) {\n\t\tvar height;\n\t\tvar matches = /^([+-]?(?:\\d+(?:\\.\\d+)?|\\.\\d+))(px|em|rem|vh)$/.exec(cssHeight);\n\n\t\tif (matches === null) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar value = parseFloat(matches[1]);\n\t\tvar unit = matches[2];\n\n\t\tif ( unit === 'px' ) {\n\t\t\theight = value;\n\t\t}\n\t\telse if ( unit === 'vh' ) {\n\t\t\theight = ( value / 100 ) * $(window).height();\n\t\t}\n\t\telse if ( unit === 'rem' ) {\n\t\t\theight = value * parseFloat($(':root').css('font-size'));\n\t\t}\n\t\telse if ( unit === 'em' ) {\n\t\t\theight = value * parseFloat($('body').css('font-size'));\n\t\t}\n\n\t\treturn height ?\n\t\t\theight :\n\t\t\t0;\n\t},\n\n\t/**\n\t * Scrolling function - fired whenever the scrolling position is changed.\n\t * This method needs to use the stored values to see if the table should be\n\t * redrawn as we are moving towards the end of the information that is\n\t * currently drawn or not. If needed, then it will redraw the table based on\n\t * the new position.\n\t *  @returns {void}\n\t *  @private\n\t */\n\t_scroll: function ()\n\t{\n\t\tvar\n\t\t\tthat = this,\n\t\t\theights = this.s.heights,\n\t\t\tiScrollTop = this.dom.scroller.scrollTop,\n\t\t\tiTopRow;\n\n\t\tif ( this.s.skip ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this.s.ingnoreScroll ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( iScrollTop === this.s.lastScrollTop ) {\n\t\t\treturn;\n\t\t}\n\n\t\t/* If the table has been sorted or filtered, then we use the redraw that\n\t\t * DataTables as done, rather than performing our own\n\t\t */\n\t\tif ( this.s.dt.bFiltered || this.s.dt.bSorted ) {\n\t\t\tthis.s.lastScrollTop = 0;\n\t\t\treturn;\n\t\t}\n\n\t\t/* Update the table's information display for what is now in the viewport */\n\t\tthis._info();\n\n\t\t/* We don't want to state save on every scroll event - that's heavy\n\t\t * handed, so use a timeout to update the state saving only when the\n\t\t * scrolling has finished\n\t\t */\n\t\tclearTimeout( this.s.stateTO );\n\t\tthis.s.stateTO = setTimeout( function () {\n\t\t\tthat.s.dtApi.state.save();\n\t\t}, 250 );\n\n\t\tthis.s.scrollType = Math.abs(iScrollTop - this.s.lastScrollTop) > heights.viewport ?\n\t\t\t'jump' :\n\t\t\t'cont';\n\n\t\tthis.s.topRowFloat = this.s.scrollType === 'cont' ?\n\t\t\tthis.pixelsToRow( iScrollTop, false, false ) :\n\t\t\tthis._domain( 'physicalToVirtual', iScrollTop ) / heights.row;\n\n\t\tif ( this.s.topRowFloat < 0 ) {\n\t\t\tthis.s.topRowFloat = 0;\n\t\t}\n\n\t\t/* Check if the scroll point is outside the trigger boundary which would required\n\t\t * a DataTables redraw\n\t\t */\n\t\tif ( this.s.forceReposition || iScrollTop < this.s.redrawTop || iScrollTop > this.s.redrawBottom ) {\n\t\t\tvar preRows = Math.ceil( ((this.s.displayBuffer-1)/2) * this.s.viewportRows );\n\n\t\t\tiTopRow = parseInt(this.s.topRowFloat, 10) - preRows;\n\t\t\tthis.s.forceReposition = false;\n\n\t\t\tif ( iTopRow <= 0 ) {\n\t\t\t\t/* At the start of the table */\n\t\t\t\tiTopRow = 0;\n\t\t\t}\n\t\t\telse if ( iTopRow + this.s.dt._iDisplayLength > this.s.dt.fnRecordsDisplay() ) {\n\t\t\t\t/* At the end of the table */\n\t\t\t\tiTopRow = this.s.dt.fnRecordsDisplay() - this.s.dt._iDisplayLength;\n\t\t\t\tif ( iTopRow < 0 ) {\n\t\t\t\t\tiTopRow = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( iTopRow % 2 !== 0 ) {\n\t\t\t\t// For the row-striping classes (odd/even) we want only to start\n\t\t\t\t// on evens otherwise the stripes will change between draws and\n\t\t\t\t// look rubbish\n\t\t\t\tiTopRow++;\n\t\t\t}\n\n\n\t\t\tif ( iTopRow != this.s.dt._iDisplayStart ) {\n\t\t\t\t/* Cache the new table position for quick lookups */\n\t\t\t\tthis.s.tableTop = $(this.s.dt.nTable).offset().top;\n\t\t\t\tthis.s.tableBottom = $(this.s.dt.nTable).height() + this.s.tableTop;\n\n\t\t\t\tvar draw =  function () {\n\t\t\t\t\tif ( that.s.scrollDrawReq === null ) {\n\t\t\t\t\t\tthat.s.scrollDrawReq = iScrollTop;\n\t\t\t\t\t}\n\n\t\t\t\t\tthat.s.dt._iDisplayStart = iTopRow;\n\t\t\t\t\tthat.s.dt.oApi._fnDraw( that.s.dt );\n\t\t\t\t};\n\n\t\t\t\t/* Do the DataTables redraw based on the calculated start point - note that when\n\t\t\t\t * using server-side processing we introduce a small delay to not DoS the server...\n\t\t\t\t */\n\t\t\t\tif ( this.s.dt.oFeatures.bServerSide ) {\n\t\t\t\t\tclearTimeout( this.s.drawTO );\n\t\t\t\t\tthis.s.drawTO = setTimeout( draw, this.s.serverWait );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdraw();\n\t\t\t\t}\n\n\t\t\t\tif ( this.dom.loader && ! this.s.loaderVisible ) {\n\t\t\t\t\tthis.dom.loader.css( 'display', 'block' );\n\t\t\t\t\tthis.s.loaderVisible = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tthis.s.topRowFloat = this.pixelsToRow( iScrollTop, false, true );\n\t\t}\n\n\t\tthis.s.lastScrollTop = iScrollTop;\n\t\tthis.s.stateSaveThrottle();\n\n\t\tif ( this.s.scrollType === 'jump' && this.s.mousedown ) {\n\t\t\tthis.dom.label\n\t\t\t\t.html( this.s.dt.fnFormatNumber( parseInt( this.s.topRowFloat, 10 )+1 ) )\n\t\t\t\t.css( 'top', iScrollTop + (iScrollTop * heights.labelFactor ) )\n\t\t\t\t.css( 'display', 'block' );\n\t\t}\n\t},\n\n\t/**\n\t * Force the scrolling container to have height beyond that of just the\n\t * table that has been drawn so the user can scroll the whole data set.\n\t *\n\t * Note that if the calculated required scrolling height exceeds a maximum\n\t * value (1 million pixels - hard-coded) the forcing element will be set\n\t * only to that maximum value and virtual / physical domain transforms will\n\t * be used to allow Scroller to display tables of any number of records.\n\t *  @returns {void}\n\t *  @private\n\t */\n\t_scrollForce: function ()\n\t{\n\t\tvar heights = this.s.heights;\n\t\tvar max = 1000000;\n\n\t\theights.virtual = heights.row * this.s.dt.fnRecordsDisplay();\n\t\theights.scroll = heights.virtual;\n\n\t\tif ( heights.scroll > max ) {\n\t\t\theights.scroll = max;\n\t\t}\n\n\t\t// Minimum height so there is always a row visible (the 'no rows found'\n\t\t// if reduced to zero filtering)\n\t\tthis.dom.force.style.height = heights.scroll > this.s.heights.row ?\n\t\t\theights.scroll+'px' :\n\t\t\tthis.s.heights.row+'px';\n\t}\n} );\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Statics\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n\n/**\n * Scroller default settings for initialisation\n *  @namespace\n *  @name Scroller.defaults\n *  @static\n */\nScroller.defaults = {\n\t/**\n\t * Scroller uses the boundary scaling factor to decide when to redraw the table - which it\n\t * typically does before you reach the end of the currently loaded data set (in order to\n\t * allow the data to look continuous to a user scrolling through the data). If given as 0\n\t * then the table will be redrawn whenever the viewport is scrolled, while 1 would not\n\t * redraw the table until the currently loaded data has all been shown. You will want\n\t * something in the middle - the default factor of 0.5 is usually suitable.\n\t *  @type     float\n\t *  @default  0.5\n\t *  @static\n\t */\n\tboundaryScale: 0.5,\n\n\t/**\n\t * The display buffer is what Scroller uses to calculate how many rows it should pre-fetch\n\t * for scrolling. Scroller automatically adjusts DataTables' display length to pre-fetch\n\t * rows that will be shown in \"near scrolling\" (i.e. just beyond the current display area).\n\t * The value is based upon the number of rows that can be displayed in the viewport (i.e.\n\t * a value of 1), and will apply the display range to records before before and after the\n\t * current viewport - i.e. a factor of 3 will allow Scroller to pre-fetch 1 viewport's worth\n\t * of rows before the current viewport, the current viewport's rows and 1 viewport's worth\n\t * of rows after the current viewport. Adjusting this value can be useful for ensuring\n\t * smooth scrolling based on your data set.\n\t *  @type     int\n\t *  @default  7\n\t *  @static\n\t */\n\tdisplayBuffer: 9,\n\n\t/**\n\t * Show (or not) the loading element in the background of the table. Note that you should\n\t * include the dataTables.scroller.css file for this to be displayed correctly.\n\t *  @type     boolean\n\t *  @default  false\n\t *  @static\n\t */\n\tloadingIndicator: false,\n\n\t/**\n\t * Scroller will attempt to automatically calculate the height of rows for it's internal\n\t * calculations. However the height that is used can be overridden using this parameter.\n\t *  @type     int|string\n\t *  @default  auto\n\t *  @static\n\t */\n\trowHeight: \"auto\",\n\n\t/**\n\t * When using server-side processing, Scroller will wait a small amount of time to allow\n\t * the scrolling to finish before requesting more data from the server. This prevents\n\t * you from DoSing your own server! The wait time can be configured by this parameter.\n\t *  @type     int\n\t *  @default  200\n\t *  @static\n\t */\n\tserverWait: 200\n};\n\nScroller.oDefaults = Scroller.defaults;\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Constants\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n/**\n * Scroller version\n *  @type      String\n *  @default   See code\n *  @name      Scroller.version\n *  @static\n */\nScroller.version = \"2.0.0\";\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Initialisation\n * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n// Attach a listener to the document which listens for DataTables initialisation\n// events so we can automatically initialise\n$(document).on( 'preInit.dt.dtscroller', function (e, settings) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tvar init = settings.oInit.scroller;\n\tvar defaults = DataTable.defaults.scroller;\n\n\tif ( init || defaults ) {\n\t\tvar opts = $.extend( {}, init, defaults );\n\n\t\tif ( init !== false ) {\n\t\t\tnew Scroller( settings, opts  );\n\t\t}\n\t}\n} );\n\n\n// Attach Scroller to DataTables so it can be accessed as an 'extra'\n$.fn.dataTable.Scroller = Scroller;\n$.fn.DataTable.Scroller = Scroller;\n\n\n// DataTables 1.10 API method aliases\nvar Api = $.fn.dataTable.Api;\n\nApi.register( 'scroller()', function () {\n\treturn this;\n} );\n\n// Undocumented and deprecated - is it actually useful at all?\nApi.register( 'scroller().rowToPixels()', function ( rowIdx, intParse, virtual ) {\n\tvar ctx = this.context;\n\n\tif ( ctx.length && ctx[0].oScroller ) {\n\t\treturn ctx[0].oScroller.rowToPixels( rowIdx, intParse, virtual );\n\t}\n\t// undefined\n} );\n\n// Undocumented and deprecated - is it actually useful at all?\nApi.register( 'scroller().pixelsToRow()', function ( pixels, intParse, virtual ) {\n\tvar ctx = this.context;\n\n\tif ( ctx.length && ctx[0].oScroller ) {\n\t\treturn ctx[0].oScroller.pixelsToRow( pixels, intParse, virtual );\n\t}\n\t// undefined\n} );\n\n// `scroller().scrollToRow()` is undocumented and deprecated. Use `scroller.toPosition()\nApi.register( ['scroller().scrollToRow()', 'scroller.toPosition()'], function ( idx, ani ) {\n\tthis.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx.oScroller ) {\n\t\t\tctx.oScroller.scrollToRow( idx, ani );\n\t\t}\n\t} );\n\n\treturn this;\n} );\n\nApi.register( 'row().scrollTo()', function ( ani ) {\n\tvar that = this;\n\n\tthis.iterator( 'row', function ( ctx, rowIdx ) {\n\t\tif ( ctx.oScroller ) {\n\t\t\tvar displayIdx = that\n\t\t\t\t.rows( { order: 'applied', search: 'applied' } )\n\t\t\t\t.indexes()\n\t\t\t\t.indexOf( rowIdx );\n\n\t\t\tctx.oScroller.scrollToRow( displayIdx, ani );\n\t\t}\n\t} );\n\n\treturn this;\n} );\n\nApi.register( 'scroller.measure()', function ( redraw ) {\n\tthis.iterator( 'table', function ( ctx ) {\n\t\tif ( ctx.oScroller ) {\n\t\t\tctx.oScroller.measure( redraw );\n\t\t}\n\t} );\n\n\treturn this;\n} );\n\nApi.register( 'scroller.page()', function() {\n\tvar ctx = this.context;\n\n\tif ( ctx.length && ctx[0].oScroller ) {\n\t\treturn ctx[0].oScroller.pageInfo();\n\t}\n\t// undefined\n} );\n\nreturn Scroller;\n}));\n\n\n/*! Select for DataTables 1.3.0\n * 2015-2018 SpryMedia Ltd - datatables.net/license/mit\n */\n\n/**\n * @summary     Select for DataTables\n * @description A collection of API methods, events and buttons for DataTables\n *   that provides selection options of the items in a DataTable\n * @version     1.3.0\n * @file        dataTables.select.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     datatables.net/forums\n * @copyright   Copyright 2015-2018 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license/mit\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net/extensions/select\n */\n(function( factory ){\n\tif ( typeof define === 'function' && define.amd ) {\n\t\t// AMD\n\t\tdefine( ['jquery', 'datatables.net'], function ( $ ) {\n\t\t\treturn factory( $, window, document );\n\t\t} );\n\t}\n\telse if ( typeof exports === 'object' ) {\n\t\t// CommonJS\n\t\tmodule.exports = function (root, $) {\n\t\t\tif ( ! root ) {\n\t\t\t\troot = window;\n\t\t\t}\n\n\t\t\tif ( ! $ || ! $.fn.dataTable ) {\n\t\t\t\t$ = require('datatables.net')(root, $).$;\n\t\t\t}\n\n\t\t\treturn factory( $, root, root.document );\n\t\t};\n\t}\n\telse {\n\t\t// Browser\n\t\tfactory( jQuery, window, document );\n\t}\n}(function( $, window, document, undefined ) {\n'use strict';\nvar DataTable = $.fn.dataTable;\n\n\n// Version information for debugger\nDataTable.select = {};\n\nDataTable.select.version = '1.3.0';\n\nDataTable.select.init = function ( dt ) {\n\tvar ctx = dt.settings()[0];\n\tvar init = ctx.oInit.select;\n\tvar defaults = DataTable.defaults.select;\n\tvar opts = init === undefined ?\n\t\tdefaults :\n\t\tinit;\n\n\t// Set defaults\n\tvar items = 'row';\n\tvar style = 'api';\n\tvar blurable = false;\n\tvar info = true;\n\tvar selector = 'td, th';\n\tvar className = 'selected';\n\tvar setStyle = false;\n\n\tctx._select = {};\n\n\t// Initialisation customisations\n\tif ( opts === true ) {\n\t\tstyle = 'os';\n\t\tsetStyle = true;\n\t}\n\telse if ( typeof opts === 'string' ) {\n\t\tstyle = opts;\n\t\tsetStyle = true;\n\t}\n\telse if ( $.isPlainObject( opts ) ) {\n\t\tif ( opts.blurable !== undefined ) {\n\t\t\tblurable = opts.blurable;\n\t\t}\n\n\t\tif ( opts.info !== undefined ) {\n\t\t\tinfo = opts.info;\n\t\t}\n\n\t\tif ( opts.items !== undefined ) {\n\t\t\titems = opts.items;\n\t\t}\n\n\t\tif ( opts.style !== undefined ) {\n\t\t\tstyle = opts.style;\n\t\t\tsetStyle = true;\n\t\t}\n\t\telse {\n\t\t\tstyle = 'os';\n\t\t\tsetStyle = true;\n\t\t}\n\n\t\tif ( opts.selector !== undefined ) {\n\t\t\tselector = opts.selector;\n\t\t}\n\n\t\tif ( opts.className !== undefined ) {\n\t\t\tclassName = opts.className;\n\t\t}\n\t}\n\n\tdt.select.selector( selector );\n\tdt.select.items( items );\n\tdt.select.style( style );\n\tdt.select.blurable( blurable );\n\tdt.select.info( info );\n\tctx._select.className = className;\n\n\n\t// Sort table based on selected rows. Requires Select Datatables extension\n\t$.fn.dataTable.ext.order['select-checkbox'] = function ( settings, col ) {\n\t\treturn this.api().column( col, {order: 'index'} ).nodes().map( function ( td ) {\n\t\t\tif ( settings._select.items === 'row' ) {\n\t\t\t\treturn $( td ).parent().hasClass( settings._select.className );\n\t\t\t} else if ( settings._select.items === 'cell' ) {\n\t\t\t\treturn $( td ).hasClass( settings._select.className );\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\t};\n\n\t// If the init options haven't enabled select, but there is a selectable\n\t// class name, then enable\n\tif ( ! setStyle && $( dt.table().node() ).hasClass( 'selectable' ) ) {\n\t\tdt.select.style( 'os' );\n\t}\n};\n\n/*\n\nSelect is a collection of API methods, event handlers, event emitters and\nbuttons (for the `Buttons` extension) for DataTables. It provides the following\nfeatures, with an overview of how they are implemented:\n\n## Selection of rows, columns and cells. Whether an item is selected or not is\n   stored in:\n\n* rows: a `_select_selected` property which contains a boolean value of the\n  DataTables' `aoData` object for each row\n* columns: a `_select_selected` property which contains a boolean value of the\n  DataTables' `aoColumns` object for each column\n* cells: a `_selected_cells` property which contains an array of boolean values\n  of the `aoData` object for each row. The array is the same length as the\n  columns array, with each element of it representing a cell.\n\nThis method of using boolean flags allows Select to operate when nodes have not\nbeen created for rows / cells (DataTables' defer rendering feature).\n\n## API methods\n\nA range of API methods are available for triggering selection and de-selection\nof rows. Methods are also available to configure the selection events that can\nbe triggered by an end user (such as which items are to be selected). To a large\nextent, these of API methods *is* Select. It is basically a collection of helper\nfunctions that can be used to select items in a DataTable.\n\nConfiguration of select is held in the object `_select` which is attached to the\nDataTables settings object on initialisation. Select being available on a table\nis not optional when Select is loaded, but its default is for selection only to\nbe available via the API - so the end user wouldn't be able to select rows\nwithout additional configuration.\n\nThe `_select` object contains the following properties:\n\n```\n{\n\titems:string     - Can be `rows`, `columns` or `cells`. Defines what item \n\t                   will be selected if the user is allowed to activate row\n\t                   selection using the mouse.\n\tstyle:string     - Can be `none`, `single`, `multi` or `os`. Defines the\n\t                   interaction style when selecting items\n\tblurable:boolean - If row selection can be cleared by clicking outside of\n\t                   the table\n\tinfo:boolean     - If the selection summary should be shown in the table\n\t                   information elements\n}\n```\n\nIn addition to the API methods, Select also extends the DataTables selector\noptions for rows, columns and cells adding a `selected` option to the selector\noptions object, allowing the developer to select only selected items or\nunselected items.\n\n## Mouse selection of items\n\nClicking on items can be used to select items. This is done by a simple event\nhandler that will select the items using the API methods.\n\n */\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Local functions\n */\n\n/**\n * Add one or more cells to the selection when shift clicking in OS selection\n * style cell selection.\n *\n * Cell range is more complicated than row and column as we want to select\n * in the visible grid rather than by index in sequence. For example, if you\n * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1\n * should also be selected (and not 1-3, 1-4. etc)\n * \n * @param  {DataTable.Api} dt   DataTable\n * @param  {object}        idx  Cell index to select to\n * @param  {object}        last Cell index to select from\n * @private\n */\nfunction cellRange( dt, idx, last )\n{\n\tvar indexes;\n\tvar columnIndexes;\n\tvar rowIndexes;\n\tvar selectColumns = function ( start, end ) {\n\t\tif ( start > end ) {\n\t\t\tvar tmp = end;\n\t\t\tend = start;\n\t\t\tstart = tmp;\n\t\t}\n\t\t\n\t\tvar record = false;\n\t\treturn dt.columns( ':visible' ).indexes().filter( function (i) {\n\t\t\tif ( i === start ) {\n\t\t\t\trecord = true;\n\t\t\t}\n\t\t\t\n\t\t\tif ( i === end ) { // not else if, as start might === end\n\t\t\t\trecord = false;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn record;\n\t\t} );\n\t};\n\n\tvar selectRows = function ( start, end ) {\n\t\tvar indexes = dt.rows( { search: 'applied' } ).indexes();\n\n\t\t// Which comes first - might need to swap\n\t\tif ( indexes.indexOf( start ) > indexes.indexOf( end ) ) {\n\t\t\tvar tmp = end;\n\t\t\tend = start;\n\t\t\tstart = tmp;\n\t\t}\n\n\t\tvar record = false;\n\t\treturn indexes.filter( function (i) {\n\t\t\tif ( i === start ) {\n\t\t\t\trecord = true;\n\t\t\t}\n\t\t\t\n\t\t\tif ( i === end ) {\n\t\t\t\trecord = false;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn record;\n\t\t} );\n\t};\n\n\tif ( ! dt.cells( { selected: true } ).any() && ! last ) {\n\t\t// select from the top left cell to this one\n\t\tcolumnIndexes = selectColumns( 0, idx.column );\n\t\trowIndexes = selectRows( 0 , idx.row );\n\t}\n\telse {\n\t\t// Get column indexes between old and new\n\t\tcolumnIndexes = selectColumns( last.column, idx.column );\n\t\trowIndexes = selectRows( last.row , idx.row );\n\t}\n\n\tindexes = dt.cells( rowIndexes, columnIndexes ).flatten();\n\n\tif ( ! dt.cells( idx, { selected: true } ).any() ) {\n\t\t// Select range\n\t\tdt.cells( indexes ).select();\n\t}\n\telse {\n\t\t// Deselect range\n\t\tdt.cells( indexes ).deselect();\n\t}\n}\n\n/**\n * Disable mouse selection by removing the selectors\n *\n * @param {DataTable.Api} dt DataTable to remove events from\n * @private\n */\nfunction disableMouseSelection( dt )\n{\n\tvar ctx = dt.settings()[0];\n\tvar selector = ctx._select.selector;\n\n\t$( dt.table().container() )\n\t\t.off( 'mousedown.dtSelect', selector )\n\t\t.off( 'mouseup.dtSelect', selector )\n\t\t.off( 'click.dtSelect', selector );\n\n\t$('body').off( 'click.dtSelect' + dt.table().node().id );\n}\n\n/**\n * Attach mouse listeners to the table to allow mouse selection of items\n *\n * @param {DataTable.Api} dt DataTable to remove events from\n * @private\n */\nfunction enableMouseSelection ( dt )\n{\n\tvar container = $( dt.table().container() );\n\tvar ctx = dt.settings()[0];\n\tvar selector = ctx._select.selector;\n\tvar matchSelection;\n\n\tcontainer\n\t\t.on( 'mousedown.dtSelect', selector, function(e) {\n\t\t\t// Disallow text selection for shift clicking on the table so multi\n\t\t\t// element selection doesn't look terrible!\n\t\t\tif ( e.shiftKey || e.metaKey || e.ctrlKey ) {\n\t\t\t\tcontainer\n\t\t\t\t\t.css( '-moz-user-select', 'none' )\n\t\t\t\t\t.one('selectstart.dtSelect', selector, function () {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t} );\n\t\t\t}\n\n\t\t\tif ( window.getSelection ) {\n\t\t\t\tmatchSelection = window.getSelection();\n\t\t\t}\n\t\t} )\n\t\t.on( 'mouseup.dtSelect', selector, function() {\n\t\t\t// Allow text selection to occur again, Mozilla style (tested in FF\n\t\t\t// 35.0.1 - still required)\n\t\t\tcontainer.css( '-moz-user-select', '' );\n\t\t} )\n\t\t.on( 'click.dtSelect', selector, function ( e ) {\n\t\t\tvar items = dt.select.items();\n\t\t\tvar idx;\n\n\t\t\t// If text was selected (click and drag), then we shouldn't change\n\t\t\t// the row's selected state\n\t\t\tif ( matchSelection ) {\n\t\t\t\tvar selection = window.getSelection();\n\n\t\t\t\t// If the element that contains the selection is not in the table, we can ignore it\n\t\t\t\t// This can happen if the developer selects text from the click event\n\t\t\t\tif ( ! selection.anchorNode || $(selection.anchorNode).closest('table')[0] === dt.table().node() ) {\n\t\t\t\t\tif ( selection !== matchSelection ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar ctx = dt.settings()[0];\n\t\t\tvar wrapperClass = $.trim(dt.settings()[0].oClasses.sWrapper).replace(/ +/g, '.');\n\n\t\t\t// Ignore clicks inside a sub-table\n\t\t\tif ( $(e.target).closest('div.'+wrapperClass)[0] != dt.table().container() ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar cell = dt.cell( $(e.target).closest('td, th') );\n\n\t\t\t// Check the cell actually belongs to the host DataTable (so child\n\t\t\t// rows, etc, are ignored)\n\t\t\tif ( ! cell.any() ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar event = $.Event('user-select.dt');\n\t\t\teventTrigger( dt, event, [ items, cell, e ] );\n\n\t\t\tif ( event.isDefaultPrevented() ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar cellIndex = cell.index();\n\t\t\tif ( items === 'row' ) {\n\t\t\t\tidx = cellIndex.row;\n\t\t\t\ttypeSelect( e, dt, ctx, 'row', idx );\n\t\t\t}\n\t\t\telse if ( items === 'column' ) {\n\t\t\t\tidx = cell.index().column;\n\t\t\t\ttypeSelect( e, dt, ctx, 'column', idx );\n\t\t\t}\n\t\t\telse if ( items === 'cell' ) {\n\t\t\t\tidx = cell.index();\n\t\t\t\ttypeSelect( e, dt, ctx, 'cell', idx );\n\t\t\t}\n\n\t\t\tctx._select_lastCell = cellIndex;\n\t\t} );\n\n\t// Blurable\n\t$('body').on( 'click.dtSelect' + dt.table().node().id, function ( e ) {\n\t\tif ( ctx._select.blurable ) {\n\t\t\t// If the click was inside the DataTables container, don't blur\n\t\t\tif ( $(e.target).parents().filter( dt.table().container() ).length ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Ignore elements which have been removed from the DOM (i.e. paging\n\t\t\t// buttons)\n\t\t\tif ( $(e.target).parents('html').length === 0 ) {\n\t\t\t \treturn;\n\t\t\t}\n\n\t\t\t// Don't blur in Editor form\n\t\t\tif ( $(e.target).parents('div.DTE').length ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tclear( ctx, true );\n\t\t}\n\t} );\n}\n\n/**\n * Trigger an event on a DataTable\n *\n * @param {DataTable.Api} api      DataTable to trigger events on\n * @param  {boolean}      selected true if selected, false if deselected\n * @param  {string}       type     Item type acting on\n * @param  {boolean}      any      Require that there are values before\n *     triggering\n * @private\n */\nfunction eventTrigger ( api, type, args, any )\n{\n\tif ( any && ! api.flatten().length ) {\n\t\treturn;\n\t}\n\n\tif ( typeof type === 'string' ) {\n\t\ttype = type +'.dt';\n\t}\n\n\targs.unshift( api );\n\n\t$(api.table().node()).trigger( type, args );\n}\n\n/**\n * Update the information element of the DataTable showing information about the\n * items selected. This is done by adding tags to the existing text\n * \n * @param {DataTable.Api} api DataTable to update\n * @private\n */\nfunction info ( api )\n{\n\tvar ctx = api.settings()[0];\n\n\tif ( ! ctx._select.info || ! ctx.aanFeatures.i ) {\n\t\treturn;\n\t}\n\n\tif ( api.select.style() === 'api' ) {\n\t\treturn;\n\t}\n\n\tvar rows    = api.rows( { selected: true } ).flatten().length;\n\tvar columns = api.columns( { selected: true } ).flatten().length;\n\tvar cells   = api.cells( { selected: true } ).flatten().length;\n\n\tvar add = function ( el, name, num ) {\n\t\tel.append( $('<span class=\"select-item\"/>').append( api.i18n(\n\t\t\t'select.'+name+'s',\n\t\t\t{ _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' },\n\t\t\tnum\n\t\t) ) );\n\t};\n\n\t// Internal knowledge of DataTables to loop over all information elements\n\t$.each( ctx.aanFeatures.i, function ( i, el ) {\n\t\tel = $(el);\n\n\t\tvar output  = $('<span class=\"select-info\"/>');\n\t\tadd( output, 'row', rows );\n\t\tadd( output, 'column', columns );\n\t\tadd( output, 'cell', cells  );\n\n\t\tvar exisiting = el.children('span.select-info');\n\t\tif ( exisiting.length ) {\n\t\t\texisiting.remove();\n\t\t}\n\n\t\tif ( output.text() !== '' ) {\n\t\t\tel.append( output );\n\t\t}\n\t} );\n}\n\n/**\n * Initialisation of a new table. Attach event handlers and callbacks to allow\n * Select to operate correctly.\n *\n * This will occur _after_ the initial DataTables initialisation, although\n * before Ajax data is rendered, if there is ajax data\n *\n * @param  {DataTable.settings} ctx Settings object to operate on\n * @private\n */\nfunction init ( ctx ) {\n\tvar api = new DataTable.Api( ctx );\n\n\t// Row callback so that classes can be added to rows and cells if the item\n\t// was selected before the element was created. This will happen with the\n\t// `deferRender` option enabled.\n\t// \n\t// This method of attaching to `aoRowCreatedCallback` is a hack until\n\t// DataTables has proper events for row manipulation If you are reviewing\n\t// this code to create your own plug-ins, please do not do this!\n\tctx.aoRowCreatedCallback.push( {\n\t\tfn: function ( row, data, index ) {\n\t\t\tvar i, ien;\n\t\t\tvar d = ctx.aoData[ index ];\n\n\t\t\t// Row\n\t\t\tif ( d._select_selected ) {\n\t\t\t\t$( row ).addClass( ctx._select.className );\n\t\t\t}\n\n\t\t\t// Cells and columns - if separated out, we would need to do two\n\t\t\t// loops, so it makes sense to combine them into a single one\n\t\t\tfor ( i=0, ien=ctx.aoColumns.length ; i<ien ; i++ ) {\n\t\t\t\tif ( ctx.aoColumns[i]._select_selected || (d._selected_cells && d._selected_cells[i]) ) {\n\t\t\t\t\t$(d.anCells[i]).addClass( ctx._select.className );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tsName: 'select-deferRender'\n\t} );\n\n\t// On Ajax reload we want to reselect all rows which are currently selected,\n\t// if there is an rowId (i.e. a unique value to identify each row with)\n\tapi.on( 'preXhr.dt.dtSelect', function () {\n\t\t// note that column selection doesn't need to be cached and then\n\t\t// reselected, as they are already selected\n\t\tvar rows = api.rows( { selected: true } ).ids( true ).filter( function ( d ) {\n\t\t\treturn d !== undefined;\n\t\t} );\n\n\t\tvar cells = api.cells( { selected: true } ).eq(0).map( function ( cellIdx ) {\n\t\t\tvar id = api.row( cellIdx.row ).id( true );\n\t\t\treturn id ?\n\t\t\t\t{ row: id, column: cellIdx.column } :\n\t\t\t\tundefined;\n\t\t} ).filter( function ( d ) {\n\t\t\treturn d !== undefined;\n\t\t} );\n\n\t\t// On the next draw, reselect the currently selected items\n\t\tapi.one( 'draw.dt.dtSelect', function () {\n\t\t\tapi.rows( rows ).select();\n\n\t\t\t// `cells` is not a cell index selector, so it needs a loop\n\t\t\tif ( cells.any() ) {\n\t\t\t\tcells.each( function ( id ) {\n\t\t\t\t\tapi.cells( id.row, id.column ).select();\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t} );\n\n\t// Update the table information element with selected item summary\n\tapi.on( 'draw.dtSelect.dt select.dtSelect.dt deselect.dtSelect.dt info.dt', function () {\n\t\tinfo( api );\n\t} );\n\n\t// Clean up and release\n\tapi.on( 'destroy.dtSelect', function () {\n\t\tdisableMouseSelection( api );\n\t\tapi.off( '.dtSelect' );\n\t} );\n}\n\n/**\n * Add one or more items (rows or columns) to the selection when shift clicking\n * in OS selection style\n *\n * @param  {DataTable.Api} dt   DataTable\n * @param  {string}        type Row or column range selector\n * @param  {object}        idx  Item index to select to\n * @param  {object}        last Item index to select from\n * @private\n */\nfunction rowColumnRange( dt, type, idx, last )\n{\n\t// Add a range of rows from the last selected row to this one\n\tvar indexes = dt[type+'s']( { search: 'applied' } ).indexes();\n\tvar idx1 = $.inArray( last, indexes );\n\tvar idx2 = $.inArray( idx, indexes );\n\n\tif ( ! dt[type+'s']( { selected: true } ).any() && idx1 === -1 ) {\n\t\t// select from top to here - slightly odd, but both Windows and Mac OS\n\t\t// do this\n\t\tindexes.splice( $.inArray( idx, indexes )+1, indexes.length );\n\t}\n\telse {\n\t\t// reverse so we can shift click 'up' as well as down\n\t\tif ( idx1 > idx2 ) {\n\t\t\tvar tmp = idx2;\n\t\t\tidx2 = idx1;\n\t\t\tidx1 = tmp;\n\t\t}\n\n\t\tindexes.splice( idx2+1, indexes.length );\n\t\tindexes.splice( 0, idx1 );\n\t}\n\n\tif ( ! dt[type]( idx, { selected: true } ).any() ) {\n\t\t// Select range\n\t\tdt[type+'s']( indexes ).select();\n\t}\n\telse {\n\t\t// Deselect range - need to keep the clicked on row selected\n\t\tindexes.splice( $.inArray( idx, indexes ), 1 );\n\t\tdt[type+'s']( indexes ).deselect();\n\t}\n}\n\n/**\n * Clear all selected items\n *\n * @param  {DataTable.settings} ctx Settings object of the host DataTable\n * @param  {boolean} [force=false] Force the de-selection to happen, regardless\n *     of selection style\n * @private\n */\nfunction clear( ctx, force )\n{\n\tif ( force || ctx._select.style === 'single' ) {\n\t\tvar api = new DataTable.Api( ctx );\n\t\t\n\t\tapi.rows( { selected: true } ).deselect();\n\t\tapi.columns( { selected: true } ).deselect();\n\t\tapi.cells( { selected: true } ).deselect();\n\t}\n}\n\n/**\n * Select items based on the current configuration for style and items.\n *\n * @param  {object}             e    Mouse event object\n * @param  {DataTables.Api}     dt   DataTable\n * @param  {DataTable.settings} ctx  Settings object of the host DataTable\n * @param  {string}             type Items to select\n * @param  {int|object}         idx  Index of the item to select\n * @private\n */\nfunction typeSelect ( e, dt, ctx, type, idx )\n{\n\tvar style = dt.select.style();\n\tvar isSelected = dt[type]( idx, { selected: true } ).any();\n\n\tif ( style === 'os' ) {\n\t\tif ( e.ctrlKey || e.metaKey ) {\n\t\t\t// Add or remove from the selection\n\t\t\tdt[type]( idx ).select( ! isSelected );\n\t\t}\n\t\telse if ( e.shiftKey ) {\n\t\t\tif ( type === 'cell' ) {\n\t\t\t\tcellRange( dt, idx, ctx._select_lastCell || null );\n\t\t\t}\n\t\t\telse {\n\t\t\t\trowColumnRange( dt, type, idx, ctx._select_lastCell ?\n\t\t\t\t\tctx._select_lastCell[type] :\n\t\t\t\t\tnull\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// No cmd or shift click - deselect if selected, or select\n\t\t\t// this row only\n\t\t\tvar selected = dt[type+'s']( { selected: true } );\n\n\t\t\tif ( isSelected && selected.flatten().length === 1 ) {\n\t\t\t\tdt[type]( idx ).deselect();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tselected.deselect();\n\t\t\t\tdt[type]( idx ).select();\n\t\t\t}\n\t\t}\n\t} else if ( style == 'multi+shift' ) {\n\t\tif ( e.shiftKey ) {\n\t\t\tif ( type === 'cell' ) {\n\t\t\t\tcellRange( dt, idx, ctx._select_lastCell || null );\n\t\t\t}\n\t\t\telse {\n\t\t\t\trowColumnRange( dt, type, idx, ctx._select_lastCell ?\n\t\t\t\t\tctx._select_lastCell[type] :\n\t\t\t\t\tnull\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tdt[ type ]( idx ).select( ! isSelected );\n\t\t}\n\t}\n\telse {\n\t\tdt[ type ]( idx ).select( ! isSelected );\n\t}\n}\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables selectors\n */\n\n// row and column are basically identical just assigned to different properties\n// and checking a different array, so we can dynamically create the functions to\n// reduce the code size\n$.each( [\n\t{ type: 'row', prop: 'aoData' },\n\t{ type: 'column', prop: 'aoColumns' }\n], function ( i, o ) {\n\tDataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) {\n\t\tvar selected = opts.selected;\n\t\tvar data;\n\t\tvar out = [];\n\n\t\tif ( selected !== true && selected !== false ) {\n\t\t\treturn indexes;\n\t\t}\n\n\t\tfor ( var i=0, ien=indexes.length ; i<ien ; i++ ) {\n\t\t\tdata = settings[ o.prop ][ indexes[i] ];\n\n\t\t\tif ( (selected === true && data._select_selected === true) ||\n\t\t\t     (selected === false && ! data._select_selected )\n\t\t\t) {\n\t\t\t\tout.push( indexes[i] );\n\t\t\t}\n\t\t}\n\n\t\treturn out;\n\t} );\n} );\n\nDataTable.ext.selector.cell.push( function ( settings, opts, cells ) {\n\tvar selected = opts.selected;\n\tvar rowData;\n\tvar out = [];\n\n\tif ( selected === undefined ) {\n\t\treturn cells;\n\t}\n\n\tfor ( var i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\trowData = settings.aoData[ cells[i].row ];\n\n\t\tif ( (selected === true && rowData._selected_cells && rowData._selected_cells[ cells[i].column ] === true) ||\n\t\t     (selected === false && ( ! rowData._selected_cells || ! rowData._selected_cells[ cells[i].column ] ) )\n\t\t) {\n\t\t\tout.push( cells[i] );\n\t\t}\n\t}\n\n\treturn out;\n} );\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * DataTables API\n *\n * For complete documentation, please refer to the docs/api directory or the\n * DataTables site\n */\n\n// Local variables to improve compression\nvar apiRegister = DataTable.Api.register;\nvar apiRegisterPlural = DataTable.Api.registerPlural;\n\napiRegister( 'select()', function () {\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tDataTable.select.init( new DataTable.Api( ctx ) );\n\t} );\n} );\n\napiRegister( 'select.blurable()', function ( flag ) {\n\tif ( flag === undefined ) {\n\t\treturn this.context[0]._select.blurable;\n\t}\n\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tctx._select.blurable = flag;\n\t} );\n} );\n\napiRegister( 'select.info()', function ( flag ) {\n\tif ( info === undefined ) {\n\t\treturn this.context[0]._select.info;\n\t}\n\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tctx._select.info = flag;\n\t} );\n} );\n\napiRegister( 'select.items()', function ( items ) {\n\tif ( items === undefined ) {\n\t\treturn this.context[0]._select.items;\n\t}\n\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tctx._select.items = items;\n\n\t\teventTrigger( new DataTable.Api( ctx ), 'selectItems', [ items ] );\n\t} );\n} );\n\n// Takes effect from the _next_ selection. None disables future selection, but\n// does not clear the current selection. Use the `deselect` methods for that\napiRegister( 'select.style()', function ( style ) {\n\tif ( style === undefined ) {\n\t\treturn this.context[0]._select.style;\n\t}\n\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tctx._select.style = style;\n\n\t\tif ( ! ctx._select_init ) {\n\t\t\tinit( ctx );\n\t\t}\n\n\t\t// Add / remove mouse event handlers. They aren't required when only\n\t\t// API selection is available\n\t\tvar dt = new DataTable.Api( ctx );\n\t\tdisableMouseSelection( dt );\n\t\t\n\t\tif ( style !== 'api' ) {\n\t\t\tenableMouseSelection( dt );\n\t\t}\n\n\t\teventTrigger( new DataTable.Api( ctx ), 'selectStyle', [ style ] );\n\t} );\n} );\n\napiRegister( 'select.selector()', function ( selector ) {\n\tif ( selector === undefined ) {\n\t\treturn this.context[0]._select.selector;\n\t}\n\n\treturn this.iterator( 'table', function ( ctx ) {\n\t\tdisableMouseSelection( new DataTable.Api( ctx ) );\n\n\t\tctx._select.selector = selector;\n\n\t\tif ( ctx._select.style !== 'api' ) {\n\t\t\tenableMouseSelection( new DataTable.Api( ctx ) );\n\t\t}\n\t} );\n} );\n\n\n\napiRegisterPlural( 'rows().select()', 'row().select()', function ( select ) {\n\tvar api = this;\n\n\tif ( select === false ) {\n\t\treturn this.deselect();\n\t}\n\n\tthis.iterator( 'row', function ( ctx, idx ) {\n\t\tclear( ctx );\n\n\t\tctx.aoData[ idx ]._select_selected = true;\n\t\t$( ctx.aoData[ idx ].nTr ).addClass( ctx._select.className );\n\t} );\n\n\tthis.iterator( 'table', function ( ctx, i ) {\n\t\teventTrigger( api, 'select', [ 'row', api[i] ], true );\n\t} );\n\n\treturn this;\n} );\n\napiRegisterPlural( 'columns().select()', 'column().select()', function ( select ) {\n\tvar api = this;\n\n\tif ( select === false ) {\n\t\treturn this.deselect();\n\t}\n\n\tthis.iterator( 'column', function ( ctx, idx ) {\n\t\tclear( ctx );\n\n\t\tctx.aoColumns[ idx ]._select_selected = true;\n\n\t\tvar column = new DataTable.Api( ctx ).column( idx );\n\n\t\t$( column.header() ).addClass( ctx._select.className );\n\t\t$( column.footer() ).addClass( ctx._select.className );\n\n\t\tcolumn.nodes().to$().addClass( ctx._select.className );\n\t} );\n\n\tthis.iterator( 'table', function ( ctx, i ) {\n\t\teventTrigger( api, 'select', [ 'column', api[i] ], true );\n\t} );\n\n\treturn this;\n} );\n\napiRegisterPlural( 'cells().select()', 'cell().select()', function ( select ) {\n\tvar api = this;\n\n\tif ( select === false ) {\n\t\treturn this.deselect();\n\t}\n\n\tthis.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {\n\t\tclear( ctx );\n\n\t\tvar data = ctx.aoData[ rowIdx ];\n\n\t\tif ( data._selected_cells === undefined ) {\n\t\t\tdata._selected_cells = [];\n\t\t}\n\n\t\tdata._selected_cells[ colIdx ] = true;\n\n\t\tif ( data.anCells ) {\n\t\t\t$( data.anCells[ colIdx ] ).addClass( ctx._select.className );\n\t\t}\n\t} );\n\n\tthis.iterator( 'table', function ( ctx, i ) {\n\t\teventTrigger( api, 'select', [ 'cell', api[i] ], true );\n\t} );\n\n\treturn this;\n} );\n\n\napiRegisterPlural( 'rows().deselect()', 'row().deselect()', function () {\n\tvar api = this;\n\n\tthis.iterator( 'row', function ( ctx, idx ) {\n\t\tctx.aoData[ idx ]._select_selected = false;\n\t\t$( ctx.aoData[ idx ].nTr ).removeClass( ctx._select.className );\n\t} );\n\n\tthis.iterator( 'table', function ( ctx, i ) {\n\t\teventTrigger( api, 'deselect', [ 'row', api[i] ], true );\n\t} );\n\n\treturn this;\n} );\n\napiRegisterPlural( 'columns().deselect()', 'column().deselect()', function () {\n\tvar api = this;\n\n\tthis.iterator( 'column', function ( ctx, idx ) {\n\t\tctx.aoColumns[ idx ]._select_selected = false;\n\n\t\tvar api = new DataTable.Api( ctx );\n\t\tvar column = api.column( idx );\n\n\t\t$( column.header() ).removeClass( ctx._select.className );\n\t\t$( column.footer() ).removeClass( ctx._select.className );\n\n\t\t// Need to loop over each cell, rather than just using\n\t\t// `column().nodes()` as cells which are individually selected should\n\t\t// not have the `selected` class removed from them\n\t\tapi.cells( null, idx ).indexes().each( function (cellIdx) {\n\t\t\tvar data = ctx.aoData[ cellIdx.row ];\n\t\t\tvar cellSelected = data._selected_cells;\n\n\t\t\tif ( data.anCells && (! cellSelected || ! cellSelected[ cellIdx.column ]) ) {\n\t\t\t\t$( data.anCells[ cellIdx.column  ] ).removeClass( ctx._select.className );\n\t\t\t}\n\t\t} );\n\t} );\n\n\tthis.iterator( 'table', function ( ctx, i ) {\n\t\teventTrigger( api, 'deselect', [ 'column', api[i] ], true );\n\t} );\n\n\treturn this;\n} );\n\napiRegisterPlural( 'cells().deselect()', 'cell().deselect()', function () {\n\tvar api = this;\n\n\tthis.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {\n\t\tvar data = ctx.aoData[ rowIdx ];\n\n\t\tdata._selected_cells[ colIdx ] = false;\n\n\t\t// Remove class only if the cells exist, and the cell is not column\n\t\t// selected, in which case the class should remain (since it is selected\n\t\t// in the column)\n\t\tif ( data.anCells && ! ctx.aoColumns[ colIdx ]._select_selected ) {\n\t\t\t$( data.anCells[ colIdx ] ).removeClass( ctx._select.className );\n\t\t}\n\t} );\n\n\tthis.iterator( 'table', function ( ctx, i ) {\n\t\teventTrigger( api, 'deselect', [ 'cell', api[i] ], true );\n\t} );\n\n\treturn this;\n} );\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Buttons\n */\nfunction i18n( label, def ) {\n\treturn function (dt) {\n\t\treturn dt.i18n( 'buttons.'+label, def );\n\t};\n}\n\n// Common events with suitable namespaces\nfunction namespacedEvents ( config ) {\n\tvar unique = config._eventNamespace;\n\n\treturn 'draw.dt.DT'+unique+' select.dt.DT'+unique+' deselect.dt.DT'+unique;\n}\n\nfunction enabled ( dt, config ) {\n\tif ( $.inArray( 'rows', config.limitTo ) !== -1 && dt.rows( { selected: true } ).any() ) {\n\t\treturn true;\n\t}\n\n\tif ( $.inArray( 'columns', config.limitTo ) !== -1 && dt.columns( { selected: true } ).any() ) {\n\t\treturn true;\n\t}\n\n\tif ( $.inArray( 'cells', config.limitTo ) !== -1 && dt.cells( { selected: true } ).any() ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nvar _buttonNamespace = 0;\n\n$.extend( DataTable.ext.buttons, {\n\tselected: {\n\t\ttext: i18n( 'selected', 'Selected' ),\n\t\tclassName: 'buttons-selected',\n\t\tlimitTo: [ 'rows', 'columns', 'cells' ],\n\t\tinit: function ( dt, node, config ) {\n\t\t\tvar that = this;\n\t\t\tconfig._eventNamespace = '.select'+(_buttonNamespace++);\n\n\t\t\t// .DT namespace listeners are removed by DataTables automatically\n\t\t\t// on table destroy\n\t\t\tdt.on( namespacedEvents(config), function () {\n\t\t\t\tthat.enable( enabled(dt, config) );\n\t\t\t} );\n\n\t\t\tthis.disable();\n\t\t},\n\t\tdestroy: function ( dt, node, config ) {\n\t\t\tdt.off( config._eventNamespace );\n\t\t}\n\t},\n\tselectedSingle: {\n\t\ttext: i18n( 'selectedSingle', 'Selected single' ),\n\t\tclassName: 'buttons-selected-single',\n\t\tinit: function ( dt, node, config ) {\n\t\t\tvar that = this;\n\t\t\tconfig._eventNamespace = '.select'+(_buttonNamespace++);\n\n\t\t\tdt.on( namespacedEvents(config), function () {\n\t\t\t\tvar count = dt.rows( { selected: true } ).flatten().length +\n\t\t\t\t            dt.columns( { selected: true } ).flatten().length +\n\t\t\t\t            dt.cells( { selected: true } ).flatten().length;\n\n\t\t\t\tthat.enable( count === 1 );\n\t\t\t} );\n\n\t\t\tthis.disable();\n\t\t},\n\t\tdestroy: function ( dt, node, config ) {\n\t\t\tdt.off( config._eventNamespace );\n\t\t}\n\t},\n\tselectAll: {\n\t\ttext: i18n( 'selectAll', 'Select all' ),\n\t\tclassName: 'buttons-select-all',\n\t\taction: function () {\n\t\t\tvar items = this.select.items();\n\t\t\tthis[ items+'s' ]().select();\n\t\t}\n\t},\n\tselectNone: {\n\t\ttext: i18n( 'selectNone', 'Deselect all' ),\n\t\tclassName: 'buttons-select-none',\n\t\taction: function () {\n\t\t\tclear( this.settings()[0], true );\n\t\t},\n\t\tinit: function ( dt, node, config ) {\n\t\t\tvar that = this;\n\t\t\tconfig._eventNamespace = '.select'+(_buttonNamespace++);\n\n\t\t\tdt.on( namespacedEvents(config), function () {\n\t\t\t\tvar count = dt.rows( { selected: true } ).flatten().length +\n\t\t\t\t            dt.columns( { selected: true } ).flatten().length +\n\t\t\t\t            dt.cells( { selected: true } ).flatten().length;\n\n\t\t\t\tthat.enable( count > 0 );\n\t\t\t} );\n\n\t\t\tthis.disable();\n\t\t},\n\t\tdestroy: function ( dt, node, config ) {\n\t\t\tdt.off( config._eventNamespace );\n\t\t}\n\t}\n} );\n\n$.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) {\n\tvar lc = item.toLowerCase();\n\n\tDataTable.ext.buttons[ 'select'+item+'s' ] = {\n\t\ttext: i18n( 'select'+item+'s', 'Select '+lc+'s' ),\n\t\tclassName: 'buttons-select-'+lc+'s',\n\t\taction: function () {\n\t\t\tthis.select.items( lc );\n\t\t},\n\t\tinit: function ( dt ) {\n\t\t\tvar that = this;\n\n\t\t\tdt.on( 'selectItems.dt.DT', function ( e, ctx, items ) {\n\t\t\t\tthat.active( items === lc );\n\t\t\t} );\n\t\t}\n\t};\n} );\n\n\n\n/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n * Initialisation\n */\n\n// DataTables creation - check if select has been defined in the options. Note\n// this required that the table be in the document! If it isn't then something\n// needs to trigger this method unfortunately. The next major release of\n// DataTables will rework the events and address this.\n$(document).on( 'preInit.dt.dtSelect', function (e, ctx) {\n\tif ( e.namespace !== 'dt' ) {\n\t\treturn;\n\t}\n\n\tDataTable.select.init( new DataTable.Api( ctx ) );\n} );\n\n\nreturn DataTable.select;\n}));\n\n\n"
  },
  {
    "path": "static/js/DataTables/jQuery-3.3.1/jquery-3.3.1.js",
    "content": "/*!\n * jQuery JavaScript Library v3.3.1\n * https://jquery.com/\n *\n * Includes Sizzle.js\n * https://sizzlejs.com/\n *\n * Copyright JS Foundation and other contributors\n * Released under the MIT license\n * https://jquery.org/license\n *\n * Date: 2018-01-20T17:24Z\n */\n( function( global, factory ) {\n\n\t\"use strict\";\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\t// For environments that do not have a `window` with a `document`\n\t\t// (such as Node.js), expose a factory as module.exports.\n\t\t// This accentuates the need for the creation of a real `window`.\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket #14549 for more info.\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n} )( typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1\n// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode\n// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common\n// enough that all such attempts are guarded in a try block.\n\"use strict\";\n\nvar arr = [];\n\nvar document = window.document;\n\nvar getProto = Object.getPrototypeOf;\n\nvar slice = arr.slice;\n\nvar concat = arr.concat;\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar fnToString = hasOwn.toString;\n\nvar ObjectFunctionString = fnToString.call( Object );\n\nvar support = {};\n\nvar isFunction = function isFunction( obj ) {\n\n      // Support: Chrome <=57, Firefox <=52\n      // In some browsers, typeof returns \"function\" for HTML <object> elements\n      // (i.e., `typeof document.createElement( \"object\" ) === \"function\"`).\n      // We don't want to classify *any* DOM node as a function.\n      return typeof obj === \"function\" && typeof obj.nodeType !== \"number\";\n  };\n\n\nvar isWindow = function isWindow( obj ) {\n\t\treturn obj != null && obj === obj.window;\n\t};\n\n\n\n\n\tvar preservedScriptAttributes = {\n\t\ttype: true,\n\t\tsrc: true,\n\t\tnoModule: true\n\t};\n\n\tfunction DOMEval( code, doc, node ) {\n\t\tdoc = doc || document;\n\n\t\tvar i,\n\t\t\tscript = doc.createElement( \"script\" );\n\n\t\tscript.text = code;\n\t\tif ( node ) {\n\t\t\tfor ( i in preservedScriptAttributes ) {\n\t\t\t\tif ( node[ i ] ) {\n\t\t\t\t\tscript[ i ] = node[ i ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdoc.head.appendChild( script ).parentNode.removeChild( script );\n\t}\n\n\nfunction toType( obj ) {\n\tif ( obj == null ) {\n\t\treturn obj + \"\";\n\t}\n\n\t// Support: Android <=2.3 only (functionish RegExp)\n\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\ttypeof obj;\n}\n/* global Symbol */\n// Defining this global in .eslintrc.json would create a danger of using the global\n// unguarded in another place, it seems safer to define global only for this module\n\n\n\nvar\n\tversion = \"3.3.1\",\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t},\n\n\t// Support: Android <=4.0 only\n\t// Make sure we trim BOM and NBSP\n\trtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;\n\njQuery.fn = jQuery.prototype = {\n\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\n\t\t// Return all the elements in a clean array\n\t\tif ( num == null ) {\n\t\t\treturn slice.call( this );\n\t\t}\n\n\t\t// Return just the one element from the set\n\t\treturn num < 0 ? this[ num + this.length ] : this[ num ];\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\teach: function( callback ) {\n\t\treturn jQuery.each( this, callback );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map( this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t} ) );\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor();\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: arr.sort,\n\tsplice: arr.splice\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[ 0 ] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !isFunction( target ) ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\n\t\t// Only deal with non-null/undefined values\n\t\tif ( ( options = arguments[ i ] ) != null ) {\n\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tsrc = target[ name ];\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject( copy ) ||\n\t\t\t\t\t( copyIsArray = Array.isArray( copy ) ) ) ) {\n\n\t\t\t\t\tif ( copyIsArray ) {\n\t\t\t\t\t\tcopyIsArray = false;\n\t\t\t\t\t\tclone = src && Array.isArray( src ) ? src : [];\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src && jQuery.isPlainObject( src ) ? src : {};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend( {\n\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisPlainObject: function( obj ) {\n\t\tvar proto, Ctor;\n\n\t\t// Detect obvious negatives\n\t\t// Use toString instead of jQuery.type to catch host objects\n\t\tif ( !obj || toString.call( obj ) !== \"[object Object]\" ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tproto = getProto( obj );\n\n\t\t// Objects with no prototype (e.g., `Object.create( null )`) are plain\n\t\tif ( !proto ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Objects with prototype are plain iff they were constructed by a global Object function\n\t\tCtor = hasOwn.call( proto, \"constructor\" ) && proto.constructor;\n\t\treturn typeof Ctor === \"function\" && fnToString.call( Ctor ) === ObjectFunctionString;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\n\t\t/* eslint-disable no-unused-vars */\n\t\t// See https://github.com/eslint/eslint/issues/6125\n\t\tvar name;\n\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\t// Evaluates a script in a global context\n\tglobalEval: function( code ) {\n\t\tDOMEval( code );\n\t},\n\n\teach: function( obj, callback ) {\n\t\tvar length, i = 0;\n\n\t\tif ( isArrayLike( obj ) ) {\n\t\t\tlength = obj.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( i in obj ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\t// Support: Android <=4.0 only\n\ttrim: function( text ) {\n\t\treturn text == null ?\n\t\t\t\"\" :\n\t\t\t( text + \"\" ).replace( rtrim, \"\" );\n\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArrayLike( Object( arr ) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t// push.apply(_, arraylike) throws on ancient WebKit\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar length, value,\n\t\t\ti = 0,\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArrayLike( elems ) ) {\n\t\t\tlength = elems.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn concat.apply( [], ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n} );\n\nif ( typeof Symbol === \"function\" ) {\n\tjQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n}\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\nfunction( i, name ) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n} );\n\nfunction isArrayLike( obj ) {\n\n\t// Support: real iOS 8.2 only (not reproducible in simulator)\n\t// `in` check used to prevent JIT error (gh-2145)\n\t// hasOwn isn't used here due to false negatives\n\t// regarding Nodelist length in IE\n\tvar length = !!obj && \"length\" in obj && obj.length,\n\t\ttype = toType( obj );\n\n\tif ( isFunction( obj ) || isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\nvar Sizzle =\n/*!\n * Sizzle CSS Selector Engine v2.3.3\n * https://sizzlejs.com/\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2016-08-08\n */\n(function( window ) {\n\nvar i,\n\tsupport,\n\tExpr,\n\tgetText,\n\tisXML,\n\ttokenize,\n\tcompile,\n\tselect,\n\toutermostContext,\n\tsortInput,\n\thasDuplicate,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsHTML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + 1 * new Date(),\n\tpreferredDoc = window.document,\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn 0;\n\t},\n\n\t// Instance methods\n\thasOwn = ({}).hasOwnProperty,\n\tarr = [],\n\tpop = arr.pop,\n\tpush_native = arr.push,\n\tpush = arr.push,\n\tslice = arr.slice,\n\t// Use a stripped-down indexOf as it's faster than native\n\t// https://jsperf.com/thor-indexof-vs-for/5\n\tindexOf = function( list, elem ) {\n\t\tvar i = 0,\n\t\t\tlen = list.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( list[i] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\tbooleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",\n\n\t// Regular expressions\n\n\t// http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\n\t// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier\n\tidentifier = \"(?:\\\\\\\\.|[\\\\w-]|[^\\0-\\\\xa0])+\",\n\n\t// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n\t\t// Operator (capture 2)\n\t\t\"*([*^$|!~]?=)\" + whitespace +\n\t\t// \"Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]\"\n\t\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" + whitespace +\n\t\t\"*\\\\]\",\n\n\tpseudos = \":(\" + identifier + \")(?:\\\\((\" +\n\t\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\t\t// 2. simple (capture 6)\n\t\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\t\t// 3. anything else (capture 2)\n\t\t\".*\" +\n\t\t\")\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace + \"*\" ),\n\n\trattributeQuotes = new RegExp( \"=\" + whitespace + \"*([^\\\\]'\\\"]*?)\" + whitespace + \"*\\\\]\", \"g\" ),\n\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + identifier + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + identifier + \"|[*])\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" + whitespace +\n\t\t\t\"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" + whitespace +\n\t\t\t\"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t\"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace + \"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" +\n\t\t\twhitespace + \"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trsibling = /[+~]/,\n\n\t// CSS escapes\n\t// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = new RegExp( \"\\\\\\\\([\\\\da-f]{1,6}\" + whitespace + \"?|(\" + whitespace + \")|.)\", \"ig\" ),\n\tfunescape = function( _, escaped, escapedWhitespace ) {\n\t\tvar high = \"0x\" + escaped - 0x10000;\n\t\t// NaN means non-codepoint\n\t\t// Support: Firefox<24\n\t\t// Workaround erroneous numeric interpretation of +\"0x\"\n\t\treturn high !== high || escapedWhitespace ?\n\t\t\tescaped :\n\t\t\thigh < 0 ?\n\t\t\t\t// BMP codepoint\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\t// Supplemental Plane codepoint (surrogate pair)\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t},\n\n\t// CSS string/identifier serialization\n\t// https://drafts.csswg.org/cssom/#common-serializing-idioms\n\trcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,\n\tfcssescape = function( ch, asCodePoint ) {\n\t\tif ( asCodePoint ) {\n\n\t\t\t// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n\t\t\tif ( ch === \"\\0\" ) {\n\t\t\t\treturn \"\\uFFFD\";\n\t\t\t}\n\n\t\t\t// Control characters and (dependent upon position) numbers get escaped as code points\n\t\t\treturn ch.slice( 0, -1 ) + \"\\\\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + \" \";\n\t\t}\n\n\t\t// Other potentially-special ASCII characters get backslash-escaped\n\t\treturn \"\\\\\" + ch;\n\t},\n\n\t// Used for iframes\n\t// See setDocument()\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t},\n\n\tdisabledAncestor = addCombinator(\n\t\tfunction( elem ) {\n\t\t\treturn elem.disabled === true && (\"form\" in elem || \"label\" in elem);\n\t\t},\n\t\t{ dir: \"parentNode\", next: \"legend\" }\n\t);\n\n// Optimize for push.apply( _, NodeList )\ntry {\n\tpush.apply(\n\t\t(arr = slice.call( preferredDoc.childNodes )),\n\t\tpreferredDoc.childNodes\n\t);\n\t// Support: Android<4.0\n\t// Detect silently failing push.apply\n\tarr[ preferredDoc.childNodes.length ].nodeType;\n} catch ( e ) {\n\tpush = { apply: arr.length ?\n\n\t\t// Leverage slice if possible\n\t\tfunction( target, els ) {\n\t\t\tpush_native.apply( target, slice.call(els) );\n\t\t} :\n\n\t\t// Support: IE<9\n\t\t// Otherwise append directly\n\t\tfunction( target, els ) {\n\t\t\tvar j = target.length,\n\t\t\t\ti = 0;\n\t\t\t// Can't trust NodeList.length\n\t\t\twhile ( (target[j++] = els[i++]) ) {}\n\t\t\ttarget.length = j - 1;\n\t\t}\n\t};\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar m, i, elem, nid, match, groups, newSelector,\n\t\tnewContext = context && context.ownerDocument,\n\n\t\t// nodeType defaults to 9, since context defaults to document\n\t\tnodeType = context ? context.nodeType : 9;\n\n\tresults = results || [];\n\n\t// Return early from calls with invalid selector or context\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\t// Try to shortcut find operations (as opposed to filters) in HTML documents\n\tif ( !seed ) {\n\n\t\tif ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {\n\t\t\tsetDocument( context );\n\t\t}\n\t\tcontext = context || document;\n\n\t\tif ( documentIsHTML ) {\n\n\t\t\t// If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n\t\t\t// (excepting DocumentFragment context, where the methods don't exist)\n\t\t\tif ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {\n\n\t\t\t\t// ID selector\n\t\t\t\tif ( (m = match[1]) ) {\n\n\t\t\t\t\t// Document context\n\t\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\t\tif ( (elem = context.getElementById( m )) ) {\n\n\t\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t// Element context\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\tif ( newContext && (elem = newContext.getElementById( m )) &&\n\t\t\t\t\t\t\tcontains( context, elem ) &&\n\t\t\t\t\t\t\telem.id === m ) {\n\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// Type selector\n\t\t\t\t} else if ( match[2] ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\t\treturn results;\n\n\t\t\t\t// Class selector\n\t\t\t\t} else if ( (m = match[3]) && support.getElementsByClassName &&\n\t\t\t\t\tcontext.getElementsByClassName ) {\n\n\t\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Take advantage of querySelectorAll\n\t\t\tif ( support.qsa &&\n\t\t\t\t!compilerCache[ selector + \" \" ] &&\n\t\t\t\t(!rbuggyQSA || !rbuggyQSA.test( selector )) ) {\n\n\t\t\t\tif ( nodeType !== 1 ) {\n\t\t\t\t\tnewContext = context;\n\t\t\t\t\tnewSelector = selector;\n\n\t\t\t\t// qSA looks outside Element context, which is not what we want\n\t\t\t\t// Thanks to Andrew Dupont for this workaround technique\n\t\t\t\t// Support: IE <=8\n\t\t\t\t// Exclude object elements\n\t\t\t\t} else if ( context.nodeName.toLowerCase() !== \"object\" ) {\n\n\t\t\t\t\t// Capture the context ID, setting it first if necessary\n\t\t\t\t\tif ( (nid = context.getAttribute( \"id\" )) ) {\n\t\t\t\t\t\tnid = nid.replace( rcssescape, fcssescape );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontext.setAttribute( \"id\", (nid = expando) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prefix every selector in the list\n\t\t\t\t\tgroups = tokenize( selector );\n\t\t\t\t\ti = groups.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tgroups[i] = \"#\" + nid + \" \" + toSelector( groups[i] );\n\t\t\t\t\t}\n\t\t\t\t\tnewSelector = groups.join( \",\" );\n\n\t\t\t\t\t// Expand context for sibling selectors\n\t\t\t\t\tnewContext = rsibling.test( selector ) && testContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext;\n\t\t\t\t}\n\n\t\t\t\tif ( newSelector ) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t} catch ( qsaError ) {\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif ( nid === expando ) {\n\t\t\t\t\t\t\tcontext.removeAttribute( \"id\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {function(string, object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn (cache[ key + \" \" ] = value);\n\t}\n\treturn cache;\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created element and returns a boolean result\n */\nfunction assert( fn ) {\n\tvar el = document.createElement(\"fieldset\");\n\n\ttry {\n\t\treturn !!fn( el );\n\t} catch (e) {\n\t\treturn false;\n\t} finally {\n\t\t// Remove from its parent by default\n\t\tif ( el.parentNode ) {\n\t\t\tel.parentNode.removeChild( el );\n\t\t}\n\t\t// release memory in IE\n\t\tel = null;\n\t}\n}\n\n/**\n * Adds the same handler for all of the specified attrs\n * @param {String} attrs Pipe-separated list of attributes\n * @param {Function} handler The method that will be applied\n */\nfunction addHandle( attrs, handler ) {\n\tvar arr = attrs.split(\"|\"),\n\t\ti = arr.length;\n\n\twhile ( i-- ) {\n\t\tExpr.attrHandle[ arr[i] ] = handler;\n\t}\n}\n\n/**\n * Checks document order of two siblings\n * @param {Element} a\n * @param {Element} b\n * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n */\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n\t\t\ta.sourceIndex - b.sourceIndex;\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( (cur = cur.nextSibling) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn (name === \"input\" || name === \"button\") && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for :enabled/:disabled\n * @param {Boolean} disabled true for :disabled; false for :enabled\n */\nfunction createDisabledPseudo( disabled ) {\n\n\t// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable\n\treturn function( elem ) {\n\n\t\t// Only certain elements can match :enabled or :disabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled\n\t\tif ( \"form\" in elem ) {\n\n\t\t\t// Check for inherited disabledness on relevant non-disabled elements:\n\t\t\t// * listed form-associated elements in a disabled fieldset\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#category-listed\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled\n\t\t\t// * option elements in a disabled optgroup\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled\n\t\t\t// All such elements have a \"form\" property.\n\t\t\tif ( elem.parentNode && elem.disabled === false ) {\n\n\t\t\t\t// Option elements defer to a parent optgroup if present\n\t\t\t\tif ( \"label\" in elem ) {\n\t\t\t\t\tif ( \"label\" in elem.parentNode ) {\n\t\t\t\t\t\treturn elem.parentNode.disabled === disabled;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn elem.disabled === disabled;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Support: IE 6 - 11\n\t\t\t\t// Use the isDisabled shortcut property to check for disabled fieldset ancestors\n\t\t\t\treturn elem.isDisabled === disabled ||\n\n\t\t\t\t\t// Where there is no isDisabled, check manually\n\t\t\t\t\t/* jshint -W018 */\n\t\t\t\t\telem.isDisabled !== !disabled &&\n\t\t\t\t\t\tdisabledAncestor( elem ) === disabled;\n\t\t\t}\n\n\t\t\treturn elem.disabled === disabled;\n\n\t\t// Try to winnow out elements that can't be disabled before trusting the disabled property.\n\t\t// Some victims get caught in our net (label, legend, menu, track), but it shouldn't\n\t\t// even exist on them, let alone have a boolean value.\n\t\t} else if ( \"label\" in elem ) {\n\t\t\treturn elem.disabled === disabled;\n\t\t}\n\n\t\t// Remaining elements are neither :enabled nor :disabled\n\t\treturn false;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction(function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction(function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ (j = matchIndexes[i]) ] ) {\n\t\t\t\t\tseed[j] = !(matches[j] = seed[j]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Checks a node for validity as a Sizzle context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Expose support vars for convenience\nsupport = Sizzle.support = {};\n\n/**\n * Detects XML nodes\n * @param {Element|Object} elem An element or a document\n * @returns {Boolean} True iff elem is a non-HTML XML node\n */\nisXML = Sizzle.isXML = function( elem ) {\n\t// documentElement is verified for cases where it doesn't yet exist\n\t// (such as loading iframes in IE - #4833)\n\tvar documentElement = elem && (elem.ownerDocument || elem).documentElement;\n\treturn documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar hasCompare, subWindow,\n\t\tdoc = node ? node.ownerDocument || node : preferredDoc;\n\n\t// Return early if doc is invalid or already selected\n\tif ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Update global variables\n\tdocument = doc;\n\tdocElem = document.documentElement;\n\tdocumentIsHTML = !isXML( document );\n\n\t// Support: IE 9-11, Edge\n\t// Accessing iframe documents after unload throws \"permission denied\" errors (jQuery #13936)\n\tif ( preferredDoc !== document &&\n\t\t(subWindow = document.defaultView) && subWindow.top !== subWindow ) {\n\n\t\t// Support: IE 11, Edge\n\t\tif ( subWindow.addEventListener ) {\n\t\t\tsubWindow.addEventListener( \"unload\", unloadHandler, false );\n\n\t\t// Support: IE 9 - 10 only\n\t\t} else if ( subWindow.attachEvent ) {\n\t\t\tsubWindow.attachEvent( \"onunload\", unloadHandler );\n\t\t}\n\t}\n\n\t/* Attributes\n\t---------------------------------------------------------------------- */\n\n\t// Support: IE<8\n\t// Verify that getAttribute really returns attributes and not properties\n\t// (excepting IE8 booleans)\n\tsupport.attributes = assert(function( el ) {\n\t\tel.className = \"i\";\n\t\treturn !el.getAttribute(\"className\");\n\t});\n\n\t/* getElement(s)By*\n\t---------------------------------------------------------------------- */\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.getElementsByTagName = assert(function( el ) {\n\t\tel.appendChild( document.createComment(\"\") );\n\t\treturn !el.getElementsByTagName(\"*\").length;\n\t});\n\n\t// Support: IE<9\n\tsupport.getElementsByClassName = rnative.test( document.getElementsByClassName );\n\n\t// Support: IE<10\n\t// Check if getElementById returns elements by name\n\t// The broken getElementById methods don't pick up programmatically-set names,\n\t// so use a roundabout getElementsByName test\n\tsupport.getById = assert(function( el ) {\n\t\tdocElem.appendChild( el ).id = expando;\n\t\treturn !document.getElementsByName || !document.getElementsByName( expando ).length;\n\t});\n\n\t// ID filter and find\n\tif ( support.getById ) {\n\t\tExpr.filter[\"ID\"] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"id\") === attrId;\n\t\t\t};\n\t\t};\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar elem = context.getElementById( id );\n\t\t\t\treturn elem ? [ elem ] : [];\n\t\t\t}\n\t\t};\n\t} else {\n\t\tExpr.filter[\"ID\"] =  function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" &&\n\t\t\t\t\telem.getAttributeNode(\"id\");\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\n\t\t// Support: IE 6 - 7 only\n\t\t// getElementById is not reliable as a find shortcut\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar node, i, elems,\n\t\t\t\t\telem = context.getElementById( id );\n\n\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t// Verify the id attribute\n\t\t\t\t\tnode = elem.getAttributeNode(\"id\");\n\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fall back on getElementsByName\n\t\t\t\t\telems = context.getElementsByName( id );\n\t\t\t\t\ti = 0;\n\t\t\t\t\twhile ( (elem = elems[i++]) ) {\n\t\t\t\t\t\tnode = elem.getAttributeNode(\"id\");\n\t\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn [];\n\t\t\t}\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[\"TAG\"] = support.getElementsByTagName ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else if ( support.qsa ) {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t} :\n\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\t\t\t\t// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( (elem = results[i++]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Class\n\tExpr.find[\"CLASS\"] = support.getElementsByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t/* QSA/matchesSelector\n\t---------------------------------------------------------------------- */\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21)\n\t// We allow this because of a bug in IE8/9 that throws an error\n\t// whenever `document.activeElement` is accessed on an iframe\n\t// So, we allow :focus to pass through QSA all the time to avoid the IE error\n\t// See https://bugs.jquery.com/ticket/13378\n\trbuggyQSA = [];\n\n\tif ( (support.qsa = rnative.test( document.querySelectorAll )) ) {\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert(function( el ) {\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explicitly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// https://bugs.jquery.com/ticket/12359\n\t\t\tdocElem.appendChild( el ).innerHTML = \"<a id='\" + expando + \"'></a>\" +\n\t\t\t\t\"<select id='\" + expando + \"-\\r\\\\' msallowcapture=''>\" +\n\t\t\t\t\"<option selected=''></option></select>\";\n\n\t\t\t// Support: IE8, Opera 11-12.16\n\t\t\t// Nothing should be selected when empty strings follow ^= or $= or *=\n\t\t\t// The test attribute must be unknown in Opera but \"safe\" for WinRT\n\t\t\t// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section\n\t\t\tif ( el.querySelectorAll(\"[msallowcapture^='']\").length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Support: IE8\n\t\t\t// Boolean attributes and \"value\" are not treated correctly\n\t\t\tif ( !el.querySelectorAll(\"[selected]\").length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n\t\t\t}\n\n\t\t\t// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+\n\t\t\tif ( !el.querySelectorAll( \"[id~=\" + expando + \"-]\" ).length ) {\n\t\t\t\trbuggyQSA.push(\"~=\");\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !el.querySelectorAll(\":checked\").length ) {\n\t\t\t\trbuggyQSA.push(\":checked\");\n\t\t\t}\n\n\t\t\t// Support: Safari 8+, iOS 8+\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=136851\n\t\t\t// In-page `selector#id sibling-combinator selector` fails\n\t\t\tif ( !el.querySelectorAll( \"a#\" + expando + \"+*\" ).length ) {\n\t\t\t\trbuggyQSA.push(\".#.+[+~]\");\n\t\t\t}\n\t\t});\n\n\t\tassert(function( el ) {\n\t\t\tel.innerHTML = \"<a href='' disabled='disabled'></a>\" +\n\t\t\t\t\"<select disabled='disabled'><option/></select>\";\n\n\t\t\t// Support: Windows 8 Native Apps\n\t\t\t// The type and name attributes are restricted during .innerHTML assignment\n\t\t\tvar input = document.createElement(\"input\");\n\t\t\tinput.setAttribute( \"type\", \"hidden\" );\n\t\t\tel.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n\t\t\t// Support: IE8\n\t\t\t// Enforce case-sensitivity of name attribute\n\t\t\tif ( el.querySelectorAll(\"[name=d]\").length ) {\n\t\t\t\trbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( el.querySelectorAll(\":enabled\").length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Support: IE9-11+\n\t\t\t// IE's :disabled selector does not pick up the children of disabled fieldsets\n\t\t\tdocElem.appendChild( el ).disabled = true;\n\t\t\tif ( el.querySelectorAll(\":disabled\").length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tel.querySelectorAll(\"*,:x\");\n\t\t\trbuggyQSA.push(\",.*:\");\n\t\t});\n\t}\n\n\tif ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||\n\t\tdocElem.webkitMatchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector) )) ) {\n\n\t\tassert(function( el ) {\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( el, \"*\" );\n\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( el, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t});\n\t}\n\n\trbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join(\"|\") );\n\trbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join(\"|\") );\n\n\t/* Contains\n\t---------------------------------------------------------------------- */\n\thasCompare = rnative.test( docElem.compareDocumentPosition );\n\n\t// Element contains another\n\t// Purposefully self-exclusive\n\t// As in, an element does not contain itself\n\tcontains = hasCompare || rnative.test( docElem.contains ) ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t));\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( (b = b.parentNode) ) {\n\t\t\t\t\tif ( b === a ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t/* Sorting\n\t---------------------------------------------------------------------- */\n\n\t// Document order sorting\n\tsortOrder = hasCompare ?\n\tfunction( a, b ) {\n\n\t\t// Flag for duplicate removal\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Sort on method existence if only one input has compareDocumentPosition\n\t\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\t\tif ( compare ) {\n\t\t\treturn compare;\n\t\t}\n\n\t\t// Calculate position if both inputs belong to the same document\n\t\tcompare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?\n\t\t\ta.compareDocumentPosition( b ) :\n\n\t\t\t// Otherwise we know they are disconnected\n\t\t\t1;\n\n\t\t// Disconnected nodes\n\t\tif ( compare & 1 ||\n\t\t\t(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {\n\n\t\t\t// Choose the first element that is related to our preferred document\n\t\t\tif ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// Maintain original order\n\t\t\treturn sortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\t\t}\n\n\t\treturn compare & 4 ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\tif ( !aup || !bup ) {\n\t\t\treturn a === document ? -1 :\n\t\t\t\tb === document ? 1 :\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\tsortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[i] === bp[i] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[i], bp[i] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\tap[i] === preferredDoc ? -1 :\n\t\t\tbp[i] === preferredDoc ? 1 :\n\t\t\t0;\n\t};\n\n\treturn document;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\t// Make sure that attribute selectors are quoted\n\texpr = expr.replace( rattributeQuotes, \"='$1']\" );\n\n\tif ( support.matchesSelector && documentIsHTML &&\n\t\t!compilerCache[ expr + \" \" ] &&\n\t\t( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n\t\t( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\t\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t\t// fragment in IE 9\n\t\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch (e) {}\n\t}\n\n\treturn Sizzle( expr, document, null, [ elem ] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\t// Set document vars if needed\n\tif ( ( context.ownerDocument || context ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tvar fn = Expr.attrHandle[ name.toLowerCase() ],\n\t\t// Don't get fooled by Object.prototype properties (jQuery #13807)\n\t\tval = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n\t\t\tfn( elem, name, !documentIsHTML ) :\n\t\t\tundefined;\n\n\treturn val !== undefined ?\n\t\tval :\n\t\tsupport.attributes || !documentIsHTML ?\n\t\t\telem.getAttribute( name ) :\n\t\t\t(val = elem.getAttributeNode(name)) && val.specified ?\n\t\t\t\tval.value :\n\t\t\t\tnull;\n};\n\nSizzle.escape = function( sel ) {\n\treturn (sel + \"\").replace( rcssescape, fcssescape );\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tsortInput = !support.sortStable && results.slice( 0 );\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( (elem = results[i++]) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\t// Clear input after sorting to release objects\n\t// See https://github.com/jquery/sizzle/pull/225\n\tsortInput = null;\n\n\treturn results;\n};\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\t\t// If no nodeType, this is expected to be an array\n\t\twhile ( (node = elem[i++]) ) {\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (jQuery #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tattrHandle: {},\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[1] = match[1].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[3] = ( match[3] || match[4] || match[5] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[3] = \" \" + match[3] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[1] = match[1].toLowerCase();\n\n\t\t\tif ( match[1].slice( 0, 3 ) === \"nth\" ) {\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[3] ) {\n\t\t\t\t\tSizzle.error( match[0] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === \"even\" || match[3] === \"odd\" ) );\n\t\t\t\tmatch[5] = +( ( match[7] + match[8] ) || match[3] === \"odd\" );\n\n\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[3] ) {\n\t\t\t\tSizzle.error( match[0] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[6] && match[2];\n\n\t\t\tif ( matchExpr[\"CHILD\"].test( match[0] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[3] ) {\n\t\t\t\tmatch[2] = match[4] || match[5] || \"\";\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t(excess = tokenize( unquoted, true )) &&\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t(excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[0] = match[0].slice( 0, excess );\n\t\t\t\tmatch[2] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeNameSelector ) {\n\t\t\tvar nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\t\t\t\tfunction() { return true; } :\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t(pattern = new RegExp( \"(^|\" + whitespace + \")\" + className + \"(\" + whitespace + \"|$)\" )) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test( typeof elem.className === \"string\" && elem.className || typeof elem.getAttribute !== \"undefined\" && elem.getAttribute(\"class\") || \"\" );\n\t\t\t\t});\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tvar cache, uniqueCache, outerCache, node, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType,\n\t\t\t\t\t\tdiff = false;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( (node = node[ dir ]) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) {\n\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\n\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\tnode = parent;\n\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\tdiff = nodeIndex && cache[ 2 ];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\t\tdiff = nodeIndex;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// xml :nth-child(...)\n\t\t\t\t\t\t\t// or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t\tif ( diff === false ) {\n\t\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t\tif ( ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) &&\n\t\t\t\t\t\t\t\t\t\t++diff ) {\n\n\t\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction(function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf( seed, matched[i] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction(function( selector ) {\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction(function( seed, matches, context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = unmatched[i]) ) {\n\t\t\t\t\t\t\tseed[i] = !(matches[i] = elem);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}) :\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tinput[0] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\t\t\t\t\t// Don't keep the element (issue #299)\n\t\t\t\t\tinput[0] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t}),\n\n\t\t\"has\": markFunction(function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t}),\n\n\t\t\"contains\": markFunction(function( text ) {\n\t\t\ttext = text.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t}),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test(lang || \"\") ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( (elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute(\"xml:lang\") || elem.getAttribute(\"lang\")) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( (elem = elem.parentNode) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t}),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": createDisabledPseudo( false ),\n\t\t\"disabled\": createDisabledPseudo( true ),\n\n\t\t\"checked\": function( elem ) {\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn (nodeName === \"input\" && !!elem.checked) || (nodeName === \"option\" && !!elem.selected);\n\t\t},\n\n\t\t\"selected\": function( elem ) {\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t//   but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[\"empty\"]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\n\t\t\t\t// Support: IE<8\n\t\t\t\t// New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n\t\t\t\t( (attr = elem.getAttribute(\"type\")) == null || attr.toLowerCase() === \"text\" );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo(function() {\n\t\t\treturn [ 0 ];\n\t\t}),\n\n\t\t\"last\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t}),\n\n\t\t\"eq\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t}),\n\n\t\t\"even\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"odd\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"lt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"gt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t})\n\t}\n};\n\nExpr.pseudos[\"nth\"] = Expr.pseudos[\"eq\"];\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = Expr.filters = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\ntokenize = Sizzle.tokenize = function( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || (match = rcomma.exec( soFar )) ) {\n\t\t\tif ( match ) {\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[0].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( (tokens = []) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( (match = rcombinators.exec( soFar )) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push({\n\t\t\t\tvalue: matched,\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[0].replace( rtrim, \" \" )\n\t\t\t});\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||\n\t\t\t\t(match = preFilters[ type ]( match ))) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push({\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t});\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[i].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tskip = combinator.next,\n\t\tkey = skip || dir,\n\t\tcheckNonElements = base && key === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, uniqueCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || (elem[ expando ] = {});\n\n\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\tuniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});\n\n\t\t\t\t\t\tif ( skip && skip === elem.nodeName.toLowerCase() ) {\n\t\t\t\t\t\t\telem = elem[ dir ] || elem;\n\t\t\t\t\t\t} else if ( (oldCache = uniqueCache[ key ]) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn (newCache[ 2 ] = oldCache[ 2 ]);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\tuniqueCache[ key ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[i]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[0];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[i], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (elem = unmatched[i]) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction(function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts( selector || \"*\", context.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( (elem = temp[i]) ) {\n\t\t\t\t\tmatcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = matcherOut[i]) ) {\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( (matcherIn[i] = elem) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, (matcherOut = []), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( (elem = matcherOut[i]) &&\n\t\t\t\t\t\t(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {\n\n\t\t\t\t\t\tseed[temp] = !(results[temp] = elem);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[0].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[\" \"],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\tvar ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t(checkContext = context).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\t\t\t// Avoid hanging onto element (issue #299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (matcher = Expr.relative[ tokens[i].type ]) ) {\n\t\t\tmatchers = [ addCombinator(elementMatcher( matchers ), matcher) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[j].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\t\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\t\ttokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" })\n\t\t\t\t\t).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( (tokens = tokens.slice( j )) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && Expr.find[\"TAG\"]( \"*\", outermost ),\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),\n\t\t\t\tlen = elems.length;\n\n\t\t\tif ( outermost ) {\n\t\t\t\toutermostContext = context === document || context || outermost;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Support: IE<9, Safari\n\t\t\t// Tolerate NodeList properties (IE: \"length\"; Safari: <number>) matching elements by id\n\t\t\tfor ( ; i !== len && (elem = elems[i]) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\tif ( !context && elem.ownerDocument !== document ) {\n\t\t\t\t\t\tsetDocument( elem );\n\t\t\t\t\t\txml = !documentIsHTML;\n\t\t\t\t\t}\n\t\t\t\t\twhile ( (matcher = elementMatchers[j++]) ) {\n\t\t\t\t\t\tif ( matcher( elem, context || document, xml) ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( (elem = !matcher && elem) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// `i` is now the count of elements visited above, and adding it to `matchedCount`\n\t\t\t// makes the latter nonnegative.\n\t\t\tmatchedCount += i;\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n\t\t\t// equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n\t\t\t// no element matchers and no seed.\n\t\t\t// Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n\t\t\t// case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n\t\t\t// numerically zero.\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (matcher = setMatchers[j++]) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !(unmatched[i] || setMatched[i]) ) {\n\t\t\t\t\t\t\t\tsetMatched[i] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[i] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n};\n\n/**\n * A low-level selection function that works with Sizzle's compiled\n *  selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n *  selector function built with Sizzle.compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nselect = Sizzle.select = function( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( (selector = compiled.selector || selector) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is only one selector in the list and no seed\n\t// (the latter of which guarantees us context)\n\tif ( match.length === 1 ) {\n\n\t\t// Reduce context if the leading compound selector is an ID\n\t\ttokens = match[0] = match[0].slice( 0 );\n\t\tif ( tokens.length > 2 && (token = tokens[0]).type === \"ID\" &&\n\t\t\t\tcontext.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) {\n\n\t\t\tcontext = ( Expr.find[\"ID\"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr[\"needsContext\"].test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[i];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( Expr.relative[ (type = token.type) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( (find = Expr.find[ type ]) ) {\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( (seed = find(\n\t\t\t\t\ttoken.matches[0].replace( runescape, funescape ),\n\t\t\t\t\trsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context\n\t\t\t\t)) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\t!context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n};\n\n// One-time assignments\n\n// Sort stability\nsupport.sortStable = expando.split(\"\").sort( sortOrder ).join(\"\") === expando;\n\n// Support: Chrome 14-35+\n// Always assume duplicates if they aren't passed to the comparison function\nsupport.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\nsetDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\nsupport.sortDetached = assert(function( el ) {\n\t// Should return 1, but returns 4 (following)\n\treturn el.compareDocumentPosition( document.createElement(\"fieldset\") ) & 1;\n});\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !assert(function( el ) {\n\tel.innerHTML = \"<a href='#'></a>\";\n\treturn el.firstChild.getAttribute(\"href\") === \"#\" ;\n}) ) {\n\taddHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n\t\tif ( !isXML ) {\n\t\t\treturn elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\nif ( !support.attributes || !assert(function( el ) {\n\tel.innerHTML = \"<input/>\";\n\tel.firstChild.setAttribute( \"value\", \"\" );\n\treturn el.firstChild.getAttribute( \"value\" ) === \"\";\n}) ) {\n\taddHandle( \"value\", function( elem, name, isXML ) {\n\t\tif ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n\t\t\treturn elem.defaultValue;\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\nif ( !assert(function( el ) {\n\treturn el.getAttribute(\"disabled\") == null;\n}) ) {\n\taddHandle( booleans, function( elem, name, isXML ) {\n\t\tvar val;\n\t\tif ( !isXML ) {\n\t\t\treturn elem[ name ] === true ? name.toLowerCase() :\n\t\t\t\t\t(val = elem.getAttributeNode( name )) && val.specified ?\n\t\t\t\t\tval.value :\n\t\t\t\tnull;\n\t\t}\n\t});\n}\n\nreturn Sizzle;\n\n})( window );\n\n\n\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\n\n// Deprecated\njQuery.expr[ \":\" ] = jQuery.expr.pseudos;\njQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\njQuery.escapeSelector = Sizzle.escape;\n\n\n\n\nvar dir = function( elem, dir, until ) {\n\tvar matched = [],\n\t\ttruncate = until !== undefined;\n\n\twhile ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmatched.push( elem );\n\t\t}\n\t}\n\treturn matched;\n};\n\n\nvar siblings = function( n, elem ) {\n\tvar matched = [];\n\n\tfor ( ; n; n = n.nextSibling ) {\n\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\tmatched.push( n );\n\t\t}\n\t}\n\n\treturn matched;\n};\n\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\n\n\nfunction nodeName( elem, name ) {\n\n  return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\n};\nvar rsingleTag = ( /^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i );\n\n\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( isFunction( qualifier ) ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t} );\n\t}\n\n\t// Single element\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t} );\n\t}\n\n\t// Arraylike of elements (jQuery, arguments, Array)\n\tif ( typeof qualifier !== \"string\" ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( indexOf.call( qualifier, elem ) > -1 ) !== not;\n\t\t} );\n\t}\n\n\t// Filtered directly for both simple and complex selectors\n\treturn jQuery.filter( qualifier, elements, not );\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\tif ( elems.length === 1 && elem.nodeType === 1 ) {\n\t\treturn jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];\n\t}\n\n\treturn jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\treturn elem.nodeType === 1;\n\t} ) );\n};\n\njQuery.fn.extend( {\n\tfind: function( selector ) {\n\t\tvar i, ret,\n\t\t\tlen = this.length,\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter( function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} ) );\n\t\t}\n\n\t\tret = this.pushStack( [] );\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\treturn len > 1 ? jQuery.uniqueSort( ret ) : ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], false ) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], true ) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n} );\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\t// Shortcut simple #id case for speed\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/,\n\n\tinit = jQuery.fn.init = function( selector, context, root ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Method init() accepts an alternate rootjQuery\n\t\t// so migrate can support jQuery.sub (gh-2101)\n\t\troot = root || rootjQuery;\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector[ 0 ] === \"<\" &&\n\t\t\t\tselector[ selector.length - 1 ] === \">\" &&\n\t\t\t\tselector.length >= 3 ) {\n\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\tif ( match && ( match[ 1 ] || !context ) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[ 1 ] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[ 0 ] : context;\n\n\t\t\t\t\t// Option to run scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[ 1 ],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[ 2 ] );\n\n\t\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis[ 0 ] = elem;\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || root ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis[ 0 ] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( isFunction( selector ) ) {\n\t\t\treturn root.ready !== undefined ?\n\t\t\t\troot.ready( selector ) :\n\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document );\n\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\n\t// Methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend( {\n\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter( function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[ i ] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\ttargets = typeof selectors !== \"string\" && jQuery( selectors );\n\n\t\t// Positional selectors never match, since there's no _selection_ context\n\t\tif ( !rneedsContext.test( selectors ) ) {\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tfor ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {\n\n\t\t\t\t\t// Always skip document fragments\n\t\t\t\t\tif ( cur.nodeType < 11 && ( targets ?\n\t\t\t\t\t\ttargets.index( cur ) > -1 :\n\n\t\t\t\t\t\t// Don't pass non-elements to Sizzle\n\t\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\t\tjQuery.find.matchesSelector( cur, selectors ) ) ) {\n\n\t\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within the set\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// Index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.uniqueSort(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter( selector )\n\t\t);\n\t}\n} );\n\nfunction sibling( cur, dir ) {\n\twhile ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}\n\treturn cur;\n}\n\njQuery.each( {\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn siblings( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn siblings( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n        if ( nodeName( elem, \"iframe\" ) ) {\n            return elem.contentDocument;\n        }\n\n        // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only\n        // Treat the template element as a regular one in browsers that\n        // don't support it.\n        if ( nodeName( elem, \"template\" ) ) {\n            elem = elem.content || elem;\n        }\n\n        return jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.uniqueSort( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n} );\nvar rnothtmlwhite = ( /[^\\x20\\t\\r\\n\\f]+/g );\n\n\n\n// Convert String-formatted options into Object-formatted ones\nfunction createOptions( options ) {\n\tvar object = {};\n\tjQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t} );\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\tcreateOptions( options ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Flag to know if list is currently firing\n\t\tfiring,\n\n\t\t// Last fire value for non-forgettable lists\n\t\tmemory,\n\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\n\t\t// Flag to prevent firing\n\t\tlocked,\n\n\t\t// Actual callback list\n\t\tlist = [],\n\n\t\t// Queue of execution data for repeatable lists\n\t\tqueue = [],\n\n\t\t// Index of currently firing callback (modified by add/remove as needed)\n\t\tfiringIndex = -1,\n\n\t\t// Fire callbacks\n\t\tfire = function() {\n\n\t\t\t// Enforce single-firing\n\t\t\tlocked = locked || options.once;\n\n\t\t\t// Execute callbacks for all pending executions,\n\t\t\t// respecting firingIndex overrides and runtime changes\n\t\t\tfired = firing = true;\n\t\t\tfor ( ; queue.length; firingIndex = -1 ) {\n\t\t\t\tmemory = queue.shift();\n\t\t\t\twhile ( ++firingIndex < list.length ) {\n\n\t\t\t\t\t// Run callback and check for early termination\n\t\t\t\t\tif ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&\n\t\t\t\t\t\toptions.stopOnFalse ) {\n\n\t\t\t\t\t\t// Jump to end and forget the data so .add doesn't re-fire\n\t\t\t\t\t\tfiringIndex = list.length;\n\t\t\t\t\t\tmemory = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Forget the data if we're done with it\n\t\t\tif ( !options.memory ) {\n\t\t\t\tmemory = false;\n\t\t\t}\n\n\t\t\tfiring = false;\n\n\t\t\t// Clean up if we're done firing for good\n\t\t\tif ( locked ) {\n\n\t\t\t\t// Keep an empty list if we have data for future add calls\n\t\t\t\tif ( memory ) {\n\t\t\t\t\tlist = [];\n\n\t\t\t\t// Otherwise, this object is spent\n\t\t\t\t} else {\n\t\t\t\t\tlist = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t// Actual Callbacks object\n\t\tself = {\n\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\n\t\t\t\t\t// If we have memory from a past run, we should fire after adding\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfiringIndex = list.length - 1;\n\t\t\t\t\t\tqueue.push( memory );\n\t\t\t\t\t}\n\n\t\t\t\t\t( function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tif ( isFunction( arg ) ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && toType( arg ) !== \"string\" ) {\n\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t} )( arguments );\n\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\tvar index;\n\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\tlist.splice( index, 1 );\n\n\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ?\n\t\t\t\t\tjQuery.inArray( fn, list ) > -1 :\n\t\t\t\t\tlist.length > 0;\n\t\t\t},\n\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Disable .fire and .add\n\t\t\t// Abort any current/pending executions\n\t\t\t// Clear all callbacks and values\n\t\t\tdisable: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tlist = memory = \"\";\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\n\t\t\t// Disable .fire\n\t\t\t// Also disable .add unless we have memory (since it would have no effect)\n\t\t\t// Abort any pending executions\n\t\t\tlock: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tif ( !memory && !firing ) {\n\t\t\t\t\tlist = memory = \"\";\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tlocked: function() {\n\t\t\t\treturn !!locked;\n\t\t\t},\n\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( !locked ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tqueue.push( args );\n\t\t\t\t\tif ( !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\nfunction Identity( v ) {\n\treturn v;\n}\nfunction Thrower( ex ) {\n\tthrow ex;\n}\n\nfunction adoptValue( value, resolve, reject, noValue ) {\n\tvar method;\n\n\ttry {\n\n\t\t// Check for promise aspect first to privilege synchronous behavior\n\t\tif ( value && isFunction( ( method = value.promise ) ) ) {\n\t\t\tmethod.call( value ).done( resolve ).fail( reject );\n\n\t\t// Other thenables\n\t\t} else if ( value && isFunction( ( method = value.then ) ) ) {\n\t\t\tmethod.call( value, resolve, reject );\n\n\t\t// Other non-thenables\n\t\t} else {\n\n\t\t\t// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:\n\t\t\t// * false: [ value ].slice( 0 ) => resolve( value )\n\t\t\t// * true: [ value ].slice( 1 ) => resolve()\n\t\t\tresolve.apply( undefined, [ value ].slice( noValue ) );\n\t\t}\n\n\t// For Promises/A+, convert exceptions into rejections\n\t// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in\n\t// Deferred#then to conditionally suppress rejection.\n\t} catch ( value ) {\n\n\t\t// Support: Android 4.0 only\n\t\t// Strict mode functions invoked without .call/.apply get global-object context\n\t\treject.apply( undefined, [ value ] );\n\t}\n}\n\njQuery.extend( {\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\n\t\t\t\t// action, add listener, callbacks,\n\t\t\t\t// ... .then handlers, argument index, [final state]\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks( \"memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"memory\" ), 2 ],\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 0, \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 1, \"rejected\" ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\t\"catch\": function( fn ) {\n\t\t\t\t\treturn promise.then( null, fn );\n\t\t\t\t},\n\n\t\t\t\t// Keep pipe for back-compat\n\t\t\t\tpipe: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( i, tuple ) {\n\n\t\t\t\t\t\t\t// Map tuples (progress, done, fail) to arguments (done, fail, progress)\n\t\t\t\t\t\t\tvar fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];\n\n\t\t\t\t\t\t\t// deferred.progress(function() { bind to newDefer or newDefer.notify })\n\t\t\t\t\t\t\t// deferred.done(function() { bind to newDefer or newDefer.resolve })\n\t\t\t\t\t\t\t// deferred.fail(function() { bind to newDefer or newDefer.reject })\n\t\t\t\t\t\t\tdeferred[ tuple[ 1 ] ]( function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify )\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ](\n\t\t\t\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\t\t\t\tfn ? [ returned ] : arguments\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\t\t\t\tthen: function( onFulfilled, onRejected, onProgress ) {\n\t\t\t\t\tvar maxDepth = 0;\n\t\t\t\t\tfunction resolve( depth, deferred, handler, special ) {\n\t\t\t\t\t\treturn function() {\n\t\t\t\t\t\t\tvar that = this,\n\t\t\t\t\t\t\t\targs = arguments,\n\t\t\t\t\t\t\t\tmightThrow = function() {\n\t\t\t\t\t\t\t\t\tvar returned, then;\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.3\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-59\n\t\t\t\t\t\t\t\t\t// Ignore double-resolution attempts\n\t\t\t\t\t\t\t\t\tif ( depth < maxDepth ) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturned = handler.apply( that, args );\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.1\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-48\n\t\t\t\t\t\t\t\t\tif ( returned === deferred.promise() ) {\n\t\t\t\t\t\t\t\t\t\tthrow new TypeError( \"Thenable self-resolution\" );\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ sections 2.3.3.1, 3.5\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-54\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-75\n\t\t\t\t\t\t\t\t\t// Retrieve `then` only once\n\t\t\t\t\t\t\t\t\tthen = returned &&\n\n\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.4\n\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-64\n\t\t\t\t\t\t\t\t\t\t// Only check objects and functions for thenability\n\t\t\t\t\t\t\t\t\t\t( typeof returned === \"object\" ||\n\t\t\t\t\t\t\t\t\t\t\ttypeof returned === \"function\" ) &&\n\t\t\t\t\t\t\t\t\t\treturned.then;\n\n\t\t\t\t\t\t\t\t\t// Handle a returned thenable\n\t\t\t\t\t\t\t\t\tif ( isFunction( then ) ) {\n\n\t\t\t\t\t\t\t\t\t\t// Special processors (notify) just wait for resolution\n\t\t\t\t\t\t\t\t\t\tif ( special ) {\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special )\n\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t// Normal processors (resolve) also hook into progress\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\t// ...and disregard older resolution values\n\t\t\t\t\t\t\t\t\t\t\tmaxDepth++;\n\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdeferred.notifyWith )\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Handle all other returned values\n\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\tif ( handler !== Identity ) {\n\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\targs = [ returned ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Process the value(s)\n\t\t\t\t\t\t\t\t\t\t// Default process is resolve\n\t\t\t\t\t\t\t\t\t\t( special || deferred.resolveWith )( that, args );\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\t\t// Only normal processors (resolve) catch and reject exceptions\n\t\t\t\t\t\t\t\tprocess = special ?\n\t\t\t\t\t\t\t\t\tmightThrow :\n\t\t\t\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tmightThrow();\n\t\t\t\t\t\t\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t\t\t\t\t\t\tif ( jQuery.Deferred.exceptionHook ) {\n\t\t\t\t\t\t\t\t\t\t\t\tjQuery.Deferred.exceptionHook( e,\n\t\t\t\t\t\t\t\t\t\t\t\t\tprocess.stackTrace );\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.4.1\n\t\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-61\n\t\t\t\t\t\t\t\t\t\t\t// Ignore post-resolution exceptions\n\t\t\t\t\t\t\t\t\t\t\tif ( depth + 1 >= maxDepth ) {\n\n\t\t\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\t\t\tif ( handler !== Thrower ) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\targs = [ e ];\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\tdeferred.rejectWith( that, args );\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.1\n\t\t\t\t\t\t\t// https://promisesaplus.com/#point-57\n\t\t\t\t\t\t\t// Re-resolve promises immediately to dodge false rejection from\n\t\t\t\t\t\t\t// subsequent errors\n\t\t\t\t\t\t\tif ( depth ) {\n\t\t\t\t\t\t\t\tprocess();\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// Call an optional hook to record the stack, in case of exception\n\t\t\t\t\t\t\t\t// since it's otherwise lost when execution goes async\n\t\t\t\t\t\t\t\tif ( jQuery.Deferred.getStackHook ) {\n\t\t\t\t\t\t\t\t\tprocess.stackTrace = jQuery.Deferred.getStackHook();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\twindow.setTimeout( process );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\n\t\t\t\t\t\t// progress_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 0 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onProgress ) ?\n\t\t\t\t\t\t\t\t\tonProgress :\n\t\t\t\t\t\t\t\t\tIdentity,\n\t\t\t\t\t\t\t\tnewDefer.notifyWith\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// fulfilled_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 1 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onFulfilled ) ?\n\t\t\t\t\t\t\t\t\tonFulfilled :\n\t\t\t\t\t\t\t\t\tIdentity\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// rejected_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 2 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onRejected ) ?\n\t\t\t\t\t\t\t\t\tonRejected :\n\t\t\t\t\t\t\t\t\tThrower\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 5 ];\n\n\t\t\t// promise.progress = list.add\n\t\t\t// promise.done = list.add\n\t\t\t// promise.fail = list.add\n\t\t\tpromise[ tuple[ 1 ] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(\n\t\t\t\t\tfunction() {\n\n\t\t\t\t\t\t// state = \"resolved\" (i.e., fulfilled)\n\t\t\t\t\t\t// state = \"rejected\"\n\t\t\t\t\t\tstate = stateString;\n\t\t\t\t\t},\n\n\t\t\t\t\t// rejected_callbacks.disable\n\t\t\t\t\t// fulfilled_callbacks.disable\n\t\t\t\t\ttuples[ 3 - i ][ 2 ].disable,\n\n\t\t\t\t\t// rejected_handlers.disable\n\t\t\t\t\t// fulfilled_handlers.disable\n\t\t\t\t\ttuples[ 3 - i ][ 3 ].disable,\n\n\t\t\t\t\t// progress_callbacks.lock\n\t\t\t\t\ttuples[ 0 ][ 2 ].lock,\n\n\t\t\t\t\t// progress_handlers.lock\n\t\t\t\t\ttuples[ 0 ][ 3 ].lock\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// progress_handlers.fire\n\t\t\t// fulfilled_handlers.fire\n\t\t\t// rejected_handlers.fire\n\t\t\tlist.add( tuple[ 3 ].fire );\n\n\t\t\t// deferred.notify = function() { deferred.notifyWith(...) }\n\t\t\t// deferred.resolve = function() { deferred.resolveWith(...) }\n\t\t\t// deferred.reject = function() { deferred.rejectWith(...) }\n\t\t\tdeferred[ tuple[ 0 ] ] = function() {\n\t\t\t\tdeferred[ tuple[ 0 ] + \"With\" ]( this === deferred ? undefined : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\n\t\t\t// deferred.notifyWith = list.fireWith\n\t\t\t// deferred.resolveWith = list.fireWith\n\t\t\t// deferred.rejectWith = list.fireWith\n\t\t\tdeferred[ tuple[ 0 ] + \"With\" ] = list.fireWith;\n\t\t} );\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( singleValue ) {\n\t\tvar\n\n\t\t\t// count of uncompleted subordinates\n\t\t\tremaining = arguments.length,\n\n\t\t\t// count of unprocessed arguments\n\t\t\ti = remaining,\n\n\t\t\t// subordinate fulfillment data\n\t\t\tresolveContexts = Array( i ),\n\t\t\tresolveValues = slice.call( arguments ),\n\n\t\t\t// the master Deferred\n\t\t\tmaster = jQuery.Deferred(),\n\n\t\t\t// subordinate callback factory\n\t\t\tupdateFunc = function( i ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tresolveContexts[ i ] = this;\n\t\t\t\t\tresolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( !( --remaining ) ) {\n\t\t\t\t\t\tmaster.resolveWith( resolveContexts, resolveValues );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\n\t\t// Single- and empty arguments are adopted like Promise.resolve\n\t\tif ( remaining <= 1 ) {\n\t\t\tadoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,\n\t\t\t\t!remaining );\n\n\t\t\t// Use .then() to unwrap secondary thenables (cf. gh-3000)\n\t\t\tif ( master.state() === \"pending\" ||\n\t\t\t\tisFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {\n\n\t\t\t\treturn master.then();\n\t\t\t}\n\t\t}\n\n\t\t// Multiple arguments are aggregated like Promise.all array elements\n\t\twhile ( i-- ) {\n\t\t\tadoptValue( resolveValues[ i ], updateFunc( i ), master.reject );\n\t\t}\n\n\t\treturn master.promise();\n\t}\n} );\n\n\n// These usually indicate a programmer mistake during development,\n// warn about them ASAP rather than swallowing them by default.\nvar rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;\n\njQuery.Deferred.exceptionHook = function( error, stack ) {\n\n\t// Support: IE 8 - 9 only\n\t// Console exists when dev tools are open, which can happen at any time\n\tif ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {\n\t\twindow.console.warn( \"jQuery.Deferred exception: \" + error.message, error.stack, stack );\n\t}\n};\n\n\n\n\njQuery.readyException = function( error ) {\n\twindow.setTimeout( function() {\n\t\tthrow error;\n\t} );\n};\n\n\n\n\n// The deferred used on DOM ready\nvar readyList = jQuery.Deferred();\n\njQuery.fn.ready = function( fn ) {\n\n\treadyList\n\t\t.then( fn )\n\n\t\t// Wrap jQuery.readyException in a function so that the lookup\n\t\t// happens at the time of error handling instead of callback\n\t\t// registration.\n\t\t.catch( function( error ) {\n\t\t\tjQuery.readyException( error );\n\t\t} );\n\n\treturn this;\n};\n\njQuery.extend( {\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\t}\n} );\n\njQuery.ready.then = readyList.then;\n\n// The ready event handler and self cleanup method\nfunction completed() {\n\tdocument.removeEventListener( \"DOMContentLoaded\", completed );\n\twindow.removeEventListener( \"load\", completed );\n\tjQuery.ready();\n}\n\n// Catch cases where $(document).ready() is called\n// after the browser event has already occurred.\n// Support: IE <=9 - 10 only\n// Older IE sometimes signals \"interactive\" too soon\nif ( document.readyState === \"complete\" ||\n\t( document.readyState !== \"loading\" && !document.documentElement.doScroll ) ) {\n\n\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\twindow.setTimeout( jQuery.ready );\n\n} else {\n\n\t// Use the handy event callback\n\tdocument.addEventListener( \"DOMContentLoaded\", completed );\n\n\t// A fallback to window.onload, that will always work\n\twindow.addEventListener( \"load\", completed );\n}\n\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nvar access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( toType( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\taccess( elems, fn, i, key[ i ], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( !isFunction( value ) ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn(\n\t\t\t\t\telems[ i ], key, raw ?\n\t\t\t\t\tvalue :\n\t\t\t\t\tvalue.call( elems[ i ], i, fn( elems[ i ], key ) )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( chainable ) {\n\t\treturn elems;\n\t}\n\n\t// Gets\n\tif ( bulk ) {\n\t\treturn fn.call( elems );\n\t}\n\n\treturn len ? fn( elems[ 0 ], key ) : emptyGet;\n};\n\n\n// Matches dashed string for camelizing\nvar rmsPrefix = /^-ms-/,\n\trdashAlpha = /-([a-z])/g;\n\n// Used by camelCase as callback to replace()\nfunction fcamelCase( all, letter ) {\n\treturn letter.toUpperCase();\n}\n\n// Convert dashed to camelCase; used by the css and data modules\n// Support: IE <=9 - 11, Edge 12 - 15\n// Microsoft forgot to hump their vendor prefix (#9572)\nfunction camelCase( string ) {\n\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n}\nvar acceptData = function( owner ) {\n\n\t// Accepts only:\n\t//  - Node\n\t//    - Node.ELEMENT_NODE\n\t//    - Node.DOCUMENT_NODE\n\t//  - Object\n\t//    - Any\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n};\n\n\n\n\nfunction Data() {\n\tthis.expando = jQuery.expando + Data.uid++;\n}\n\nData.uid = 1;\n\nData.prototype = {\n\n\tcache: function( owner ) {\n\n\t\t// Check if the owner object already has a cache\n\t\tvar value = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !value ) {\n\t\t\tvalue = {};\n\n\t\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t\t// but we should not, see #8335.\n\t\t\t// Always return an empty object.\n\t\t\tif ( acceptData( owner ) ) {\n\n\t\t\t\t// If it is a node unlikely to be stringify-ed or looped over\n\t\t\t\t// use plain assignment\n\t\t\t\tif ( owner.nodeType ) {\n\t\t\t\t\towner[ this.expando ] = value;\n\n\t\t\t\t// Otherwise secure it in a non-enumerable property\n\t\t\t\t// configurable must be true to allow the property to be\n\t\t\t\t// deleted when data is removed\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty( owner, this.expando, {\n\t\t\t\t\t\tvalue: value,\n\t\t\t\t\t\tconfigurable: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\tcache = this.cache( owner );\n\n\t\t// Handle: [ owner, key, value ] args\n\t\t// Always use camelCase key (gh-2257)\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ camelCase( data ) ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\n\t\t\t// Copy the properties one-by-one to the cache object\n\t\t\tfor ( prop in data ) {\n\t\t\t\tcache[ camelCase( prop ) ] = data[ prop ];\n\t\t\t}\n\t\t}\n\t\treturn cache;\n\t},\n\tget: function( owner, key ) {\n\t\treturn key === undefined ?\n\t\t\tthis.cache( owner ) :\n\n\t\t\t// Always use camelCase key (gh-2257)\n\t\t\towner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];\n\t},\n\taccess: function( owner, key, value ) {\n\n\t\t// In cases where either:\n\t\t//\n\t\t//   1. No key was specified\n\t\t//   2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t//   1. The entire cache object\n\t\t//   2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t( ( key && typeof key === \"string\" ) && value === undefined ) ) {\n\n\t\t\treturn this.get( owner, key );\n\t\t}\n\n\t\t// When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t//   1. An object of properties\n\t\t//   2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i,\n\t\t\tcache = owner[ this.expando ];\n\n\t\tif ( cache === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key !== undefined ) {\n\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( Array.isArray( key ) ) {\n\n\t\t\t\t// If key is an array of keys...\n\t\t\t\t// We always set camelCase keys, so remove that.\n\t\t\t\tkey = key.map( camelCase );\n\t\t\t} else {\n\t\t\t\tkey = camelCase( key );\n\n\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\tkey = key in cache ?\n\t\t\t\t\t[ key ] :\n\t\t\t\t\t( key.match( rnothtmlwhite ) || [] );\n\t\t\t}\n\n\t\t\ti = key.length;\n\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ key[ i ] ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if there's no more data\n\t\tif ( key === undefined || jQuery.isEmptyObject( cache ) ) {\n\n\t\t\t// Support: Chrome <=35 - 45\n\t\t\t// Webkit & Blink performance suffers when deleting properties\n\t\t\t// from DOM nodes, so set to undefined instead\n\t\t\t// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)\n\t\t\tif ( owner.nodeType ) {\n\t\t\t\towner[ this.expando ] = undefined;\n\t\t\t} else {\n\t\t\t\tdelete owner[ this.expando ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\tvar cache = owner[ this.expando ];\n\t\treturn cache !== undefined && !jQuery.isEmptyObject( cache );\n\t}\n};\nvar dataPriv = new Data();\n\nvar dataUser = new Data();\n\n\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /[A-Z]/g;\n\nfunction getData( data ) {\n\tif ( data === \"true\" ) {\n\t\treturn true;\n\t}\n\n\tif ( data === \"false\" ) {\n\t\treturn false;\n\t}\n\n\tif ( data === \"null\" ) {\n\t\treturn null;\n\t}\n\n\t// Only convert to a number if it doesn't change the string\n\tif ( data === +data + \"\" ) {\n\t\treturn +data;\n\t}\n\n\tif ( rbrace.test( data ) ) {\n\t\treturn JSON.parse( data );\n\t}\n\n\treturn data;\n}\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tname = \"data-\" + key.replace( rmultiDash, \"-$&\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = getData( data );\n\t\t\t} catch ( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tdataUser.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend( {\n\thasData: function( elem ) {\n\t\treturn dataUser.hasData( elem ) || dataPriv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn dataUser.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdataUser.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to dataPriv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn dataPriv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdataPriv.remove( elem, name );\n\t}\n} );\n\njQuery.fn.extend( {\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = dataUser.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !dataPriv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\n\t\t\t\t\t\t// Support: IE 11 only\n\t\t\t\t\t\t// The attrs elements can be null (#14894)\n\t\t\t\t\t\tif ( attrs[ i ] ) {\n\t\t\t\t\t\t\tname = attrs[ i ].name;\n\t\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\t\tname = camelCase( name.slice( 5 ) );\n\t\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdataPriv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tdataUser.set( this, key );\n\t\t\t} );\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data;\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// The key will always be camelCased in Data\n\t\t\t\tdata = dataUser.get( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tthis.each( function() {\n\n\t\t\t\t// We always store the camelCased key\n\t\t\t\tdataUser.set( this, key, value );\n\t\t\t} );\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each( function() {\n\t\t\tdataUser.remove( this, key );\n\t\t} );\n\t}\n} );\n\n\njQuery.extend( {\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = dataPriv.get( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || Array.isArray( data ) ) {\n\t\t\t\t\tqueue = dataPriv.access( elem, type, jQuery.makeArray( data ) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// Clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// Not public - generate a queueHooks object, or return the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn dataPriv.get( elem, key ) || dataPriv.access( elem, key, {\n\t\t\tempty: jQuery.Callbacks( \"once memory\" ).add( function() {\n\t\t\t\tdataPriv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t} )\n\t\t} );\n\t}\n} );\n\njQuery.fn.extend( {\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[ 0 ], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each( function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// Ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[ 0 ] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t} );\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t} );\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = dataPriv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n} );\nvar pnum = ( /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/ ).source;\n\nvar rcssNum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" );\n\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\nvar isHiddenWithinTree = function( elem, el ) {\n\n\t\t// isHiddenWithinTree might be called from jQuery#filter function;\n\t\t// in that case, element will be second argument\n\t\telem = el || elem;\n\n\t\t// Inline style trumps all\n\t\treturn elem.style.display === \"none\" ||\n\t\t\telem.style.display === \"\" &&\n\n\t\t\t// Otherwise, check computed style\n\t\t\t// Support: Firefox <=43 - 45\n\t\t\t// Disconnected elements can have computed display: none, so first confirm that elem is\n\t\t\t// in the document.\n\t\t\tjQuery.contains( elem.ownerDocument, elem ) &&\n\n\t\t\tjQuery.css( elem, \"display\" ) === \"none\";\n\t};\n\nvar swap = function( elem, options, callback, args ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.apply( elem, args || [] );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\n\n\nfunction adjustCSS( elem, prop, valueParts, tween ) {\n\tvar adjusted, scale,\n\t\tmaxIterations = 20,\n\t\tcurrentValue = tween ?\n\t\t\tfunction() {\n\t\t\t\treturn tween.cur();\n\t\t\t} :\n\t\t\tfunction() {\n\t\t\t\treturn jQuery.css( elem, prop, \"\" );\n\t\t\t},\n\t\tinitial = currentValue(),\n\t\tunit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n\t\t// Starting value computation is required for potential unit mismatches\n\t\tinitialInUnit = ( jQuery.cssNumber[ prop ] || unit !== \"px\" && +initial ) &&\n\t\t\trcssNum.exec( jQuery.css( elem, prop ) );\n\n\tif ( initialInUnit && initialInUnit[ 3 ] !== unit ) {\n\n\t\t// Support: Firefox <=54\n\t\t// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)\n\t\tinitial = initial / 2;\n\n\t\t// Trust units reported by jQuery.css\n\t\tunit = unit || initialInUnit[ 3 ];\n\n\t\t// Iteratively approximate from a nonzero starting point\n\t\tinitialInUnit = +initial || 1;\n\n\t\twhile ( maxIterations-- ) {\n\n\t\t\t// Evaluate and update our best guess (doubling guesses that zero out).\n\t\t\t// Finish if the scale equals or crosses 1 (making the old*new product non-positive).\n\t\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\t\t\tif ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {\n\t\t\t\tmaxIterations = 0;\n\t\t\t}\n\t\t\tinitialInUnit = initialInUnit / scale;\n\n\t\t}\n\n\t\tinitialInUnit = initialInUnit * 2;\n\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\n\t\t// Make sure we update the tween properties later on\n\t\tvalueParts = valueParts || [];\n\t}\n\n\tif ( valueParts ) {\n\t\tinitialInUnit = +initialInUnit || +initial || 0;\n\n\t\t// Apply relative offset (+=/-=) if specified\n\t\tadjusted = valueParts[ 1 ] ?\n\t\t\tinitialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :\n\t\t\t+valueParts[ 2 ];\n\t\tif ( tween ) {\n\t\t\ttween.unit = unit;\n\t\t\ttween.start = initialInUnit;\n\t\t\ttween.end = adjusted;\n\t\t}\n\t}\n\treturn adjusted;\n}\n\n\nvar defaultDisplayMap = {};\n\nfunction getDefaultDisplay( elem ) {\n\tvar temp,\n\t\tdoc = elem.ownerDocument,\n\t\tnodeName = elem.nodeName,\n\t\tdisplay = defaultDisplayMap[ nodeName ];\n\n\tif ( display ) {\n\t\treturn display;\n\t}\n\n\ttemp = doc.body.appendChild( doc.createElement( nodeName ) );\n\tdisplay = jQuery.css( temp, \"display\" );\n\n\ttemp.parentNode.removeChild( temp );\n\n\tif ( display === \"none\" ) {\n\t\tdisplay = \"block\";\n\t}\n\tdefaultDisplayMap[ nodeName ] = display;\n\n\treturn display;\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\t// Determine new display value for elements that need to change\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\n\t\t\t// Since we force visibility upon cascade-hidden elements, an immediate (and slow)\n\t\t\t// check is required in this first loop unless we have a nonempty display value (either\n\t\t\t// inline or about-to-be-restored)\n\t\t\tif ( display === \"none\" ) {\n\t\t\t\tvalues[ index ] = dataPriv.get( elem, \"display\" ) || null;\n\t\t\t\tif ( !values[ index ] ) {\n\t\t\t\t\telem.style.display = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( elem.style.display === \"\" && isHiddenWithinTree( elem ) ) {\n\t\t\t\tvalues[ index ] = getDefaultDisplay( elem );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( display !== \"none\" ) {\n\t\t\t\tvalues[ index ] = \"none\";\n\n\t\t\t\t// Remember what we're overwriting\n\t\t\t\tdataPriv.set( elem, \"display\", display );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of the elements in a second loop to avoid constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\tif ( values[ index ] != null ) {\n\t\t\telements[ index ].style.display = values[ index ];\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.fn.extend( {\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tif ( isHiddenWithinTree( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t} );\n\t}\n} );\nvar rcheckableType = ( /^(?:checkbox|radio)$/i );\n\nvar rtagName = ( /<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]+)/i );\n\nvar rscriptType = ( /^$|^module$|\\/(?:java|ecma)script/i );\n\n\n\n// We have to close these tags to support XHTML (#13200)\nvar wrapMap = {\n\n\t// Support: IE <=9 only\n\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\n\t// XHTML parsers do not magically insert elements in the\n\t// same way that tag soup parsers do. So we cannot shorten\n\t// this by omitting <tbody> or other required elements.\n\tthead: [ 1, \"<table>\", \"</table>\" ],\n\tcol: [ 2, \"<table><colgroup>\", \"</colgroup></table>\" ],\n\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t_default: [ 0, \"\", \"\" ]\n};\n\n// Support: IE <=9 only\nwrapMap.optgroup = wrapMap.option;\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n\nfunction getAll( context, tag ) {\n\n\t// Support: IE <=9 - 11 only\n\t// Use typeof to avoid zero-argument method invocation on host objects (#15151)\n\tvar ret;\n\n\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\tret = context.getElementsByTagName( tag || \"*\" );\n\n\t} else if ( typeof context.querySelectorAll !== \"undefined\" ) {\n\t\tret = context.querySelectorAll( tag || \"*\" );\n\n\t} else {\n\t\tret = [];\n\t}\n\n\tif ( tag === undefined || tag && nodeName( context, tag ) ) {\n\t\treturn jQuery.merge( [ context ], ret );\n\t}\n\n\treturn ret;\n}\n\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdataPriv.set(\n\t\t\telems[ i ],\n\t\t\t\"globalEval\",\n\t\t\t!refElements || dataPriv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\n\nvar rhtml = /<|&#?\\w+;/;\n\nfunction buildFragment( elems, context, scripts, selection, ignored ) {\n\tvar elem, tmp, tag, wrap, contains, j,\n\t\tfragment = context.createDocumentFragment(),\n\t\tnodes = [],\n\t\ti = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\telem = elems[ i ];\n\n\t\tif ( elem || elem === 0 ) {\n\n\t\t\t// Add nodes directly\n\t\t\tif ( toType( elem ) === \"object\" ) {\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t// Convert non-html into a text node\n\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t// Convert html into DOM nodes\n\t\t\t} else {\n\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement( \"div\" ) );\n\n\t\t\t\t// Deserialize a standard representation\n\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\t\t\t\ttmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];\n\n\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\tj = wrap[ 0 ];\n\t\t\t\twhile ( j-- ) {\n\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t}\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t// Remember the top-level container\n\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t// Ensure the created nodes are orphaned (#12392)\n\t\t\t\ttmp.textContent = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove wrapper from fragment\n\tfragment.textContent = \"\";\n\n\ti = 0;\n\twhile ( ( elem = nodes[ i++ ] ) ) {\n\n\t\t// Skip elements already in the context collection (trac-4087)\n\t\tif ( selection && jQuery.inArray( elem, selection ) > -1 ) {\n\t\t\tif ( ignored ) {\n\t\t\t\tignored.push( elem );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tcontains = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t// Append to fragment\n\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t// Preserve script evaluation history\n\t\tif ( contains ) {\n\t\t\tsetGlobalEval( tmp );\n\t\t}\n\n\t\t// Capture executables\n\t\tif ( scripts ) {\n\t\t\tj = 0;\n\t\t\twhile ( ( elem = tmp[ j++ ] ) ) {\n\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\tscripts.push( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fragment;\n}\n\n\n( function() {\n\tvar fragment = document.createDocumentFragment(),\n\t\tdiv = fragment.appendChild( document.createElement( \"div\" ) ),\n\t\tinput = document.createElement( \"input\" );\n\n\t// Support: Android 4.0 - 4.3 only\n\t// Check state lost if the name is set (#11217)\n\t// Support: Windows Web Apps (WWA)\n\t// `name` and `type` must use .setAttribute for WWA (#14901)\n\tinput.setAttribute( \"type\", \"radio\" );\n\tinput.setAttribute( \"checked\", \"checked\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tdiv.appendChild( input );\n\n\t// Support: Android <=4.1 only\n\t// Older WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE <=11 only\n\t// Make sure textarea (and checkbox) defaultValue is properly cloned\n\tdiv.innerHTML = \"<textarea>x</textarea>\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n} )();\nvar documentElement = document.documentElement;\n\n\n\nvar\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\n// Support: IE <=9 only\n// See #13393 for more info\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\nfunction on( elem, types, selector, data, fn, one ) {\n\tvar origFn, type;\n\n\t// Types can be a map of types/handlers\n\tif ( typeof types === \"object\" ) {\n\n\t\t// ( types-Object, selector, data )\n\t\tif ( typeof selector !== \"string\" ) {\n\n\t\t\t// ( types-Object, data )\n\t\t\tdata = data || selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tfor ( type in types ) {\n\t\t\ton( elem, type, selector, data, types[ type ], one );\n\t\t}\n\t\treturn elem;\n\t}\n\n\tif ( data == null && fn == null ) {\n\n\t\t// ( types, fn )\n\t\tfn = selector;\n\t\tdata = selector = undefined;\n\t} else if ( fn == null ) {\n\t\tif ( typeof selector === \"string\" ) {\n\n\t\t\t// ( types, selector, fn )\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t} else {\n\n\t\t\t// ( types, data, fn )\n\t\t\tfn = data;\n\t\t\tdata = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t}\n\tif ( fn === false ) {\n\t\tfn = returnFalse;\n\t} else if ( !fn ) {\n\t\treturn elem;\n\t}\n\n\tif ( one === 1 ) {\n\t\torigFn = fn;\n\t\tfn = function( event ) {\n\n\t\t\t// Can use an empty set, since event contains the info\n\t\t\tjQuery().off( event );\n\t\t\treturn origFn.apply( this, arguments );\n\t\t};\n\n\t\t// Use same guid so caller can remove using origFn\n\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t}\n\treturn elem.each( function() {\n\t\tjQuery.event.add( this, types, fn, data, selector );\n\t} );\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.get( elem );\n\n\t\t// Don't attach events to noData or text/comment nodes (but allow plain objects)\n\t\tif ( !elemData ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Ensure that invalid selectors throw exceptions at attach time\n\t\t// Evaluate against documentElement in case elem is a non-element node (e.g., document)\n\t\tif ( selector ) {\n\t\t\tjQuery.find.matchesSelector( documentElement, selector );\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !( events = elemData.events ) ) {\n\t\t\tevents = elemData.events = {};\n\t\t}\n\t\tif ( !( eventHandle = elemData.handle ) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend( {\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join( \".\" )\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !( handlers = events[ type ] ) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup ||\n\t\t\t\t\tspecial.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.hasData( elem ) && dataPriv.get( elem );\n\n\t\tif ( !elemData || !( events = elemData.events ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[ 2 ] &&\n\t\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector ||\n\t\t\t\t\t\tselector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown ||\n\t\t\t\t\tspecial.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove data and the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdataPriv.remove( elem, \"handle events\" );\n\t\t}\n\t},\n\n\tdispatch: function( nativeEvent ) {\n\n\t\t// Make a writable jQuery.Event from the native event object\n\t\tvar event = jQuery.event.fix( nativeEvent );\n\n\t\tvar i, j, ret, matched, handleObj, handlerQueue,\n\t\t\targs = new Array( arguments.length ),\n\t\t\thandlers = ( dataPriv.get( this, \"events\" ) || {} )[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[ 0 ] = event;\n\n\t\tfor ( i = 1; i < arguments.length; i++ ) {\n\t\t\targs[ i ] = arguments[ i ];\n\t\t}\n\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( ( handleObj = matched.handlers[ j++ ] ) &&\n\t\t\t\t!event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// Triggered event must either 1) have no namespace, or 2) have namespace(s)\n\t\t\t\t// a subset or equal to those in the bound event (both can have no namespace).\n\t\t\t\tif ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||\n\t\t\t\t\t\thandleObj.handler ).apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( ( event.result = ret ) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, handleObj, sel, matchedHandlers, matchedSelectors,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\tif ( delegateCount &&\n\n\t\t\t// Support: IE <=9\n\t\t\t// Black-hole SVG <use> instance trees (trac-13180)\n\t\t\tcur.nodeType &&\n\n\t\t\t// Support: Firefox <=42\n\t\t\t// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)\n\t\t\t// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click\n\t\t\t// Support: IE 11 only\n\t\t\t// ...but not arrow key \"clicks\" of radio inputs, which can have `button` -1 (gh-2343)\n\t\t\t!( event.type === \"click\" && event.button >= 1 ) ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't check non-elements (#13208)\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.nodeType === 1 && !( event.type === \"click\" && cur.disabled === true ) ) {\n\t\t\t\t\tmatchedHandlers = [];\n\t\t\t\t\tmatchedSelectors = {};\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatchedSelectors[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) > -1 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] ) {\n\t\t\t\t\t\t\tmatchedHandlers.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matchedHandlers.length ) {\n\t\t\t\t\t\thandlerQueue.push( { elem: cur, handlers: matchedHandlers } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tcur = this;\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\taddProp: function( name, hook ) {\n\t\tObject.defineProperty( jQuery.Event.prototype, name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\n\t\t\tget: isFunction( hook ) ?\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\t\treturn hook( this.originalEvent );\n\t\t\t\t\t}\n\t\t\t\t} :\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\t\treturn this.originalEvent[ name ];\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\tset: function( value ) {\n\t\t\t\tObject.defineProperty( this, name, {\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t\tvalue: value\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t},\n\n\tfix: function( originalEvent ) {\n\t\treturn originalEvent[ jQuery.expando ] ?\n\t\t\toriginalEvent :\n\t\t\tnew jQuery.Event( originalEvent );\n\t},\n\n\tspecial: {\n\t\tload: {\n\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tfocus: {\n\n\t\t\t// Fire native event if possible so blur/focus sequence is correct\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this !== safeActiveElement() && this.focus ) {\n\t\t\t\t\tthis.focus();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusin\"\n\t\t},\n\t\tblur: {\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this === safeActiveElement() && this.blur ) {\n\t\t\t\t\tthis.blur();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusout\"\n\t\t},\n\t\tclick: {\n\n\t\t\t// For checkbox, fire native event so checked state will be right\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this.type === \"checkbox\" && this.click && nodeName( this, \"input\" ) ) {\n\t\t\t\t\tthis.click();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, don't fire native .click() on links\n\t\t\t_default: function( event ) {\n\t\t\t\treturn nodeName( event.target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Support: Firefox 20+\n\t\t\t\t// Firefox doesn't alert if the returnValue field is not set.\n\t\t\t\tif ( event.result !== undefined && event.originalEvent ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n};\n\njQuery.removeEvent = function( elem, type, handle ) {\n\n\t// This \"if\" is needed for plain objects\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\n\t// Allow instantiation without the 'new' keyword\n\tif ( !( this instanceof jQuery.Event ) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ||\n\t\t\t\tsrc.defaultPrevented === undefined &&\n\n\t\t\t\t// Support: Android <=2.3 only\n\t\t\t\tsrc.returnValue === false ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t\t// Create target properties\n\t\t// Support: Safari <=6 - 7 only\n\t\t// Target should not be a text node (#504, #13143)\n\t\tthis.target = ( src.target && src.target.nodeType === 3 ) ?\n\t\t\tsrc.target.parentNode :\n\t\t\tsrc.target;\n\n\t\tthis.currentTarget = src.currentTarget;\n\t\tthis.relatedTarget = src.relatedTarget;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || Date.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tconstructor: jQuery.Event,\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\tisSimulated: false,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Includes all common event props including KeyEvent and MouseEvent specific props\njQuery.each( {\n\taltKey: true,\n\tbubbles: true,\n\tcancelable: true,\n\tchangedTouches: true,\n\tctrlKey: true,\n\tdetail: true,\n\teventPhase: true,\n\tmetaKey: true,\n\tpageX: true,\n\tpageY: true,\n\tshiftKey: true,\n\tview: true,\n\t\"char\": true,\n\tcharCode: true,\n\tkey: true,\n\tkeyCode: true,\n\tbutton: true,\n\tbuttons: true,\n\tclientX: true,\n\tclientY: true,\n\toffsetX: true,\n\toffsetY: true,\n\tpointerId: true,\n\tpointerType: true,\n\tscreenX: true,\n\tscreenY: true,\n\ttargetTouches: true,\n\ttoElement: true,\n\ttouches: true,\n\n\twhich: function( event ) {\n\t\tvar button = event.button;\n\n\t\t// Add which for key events\n\t\tif ( event.which == null && rkeyEvent.test( event.type ) ) {\n\t\t\treturn event.charCode != null ? event.charCode : event.keyCode;\n\t\t}\n\n\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\tif ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {\n\t\t\tif ( button & 1 ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tif ( button & 2 ) {\n\t\t\t\treturn 3;\n\t\t\t}\n\n\t\t\tif ( button & 4 ) {\n\t\t\t\treturn 2;\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn event.which;\n\t}\n}, jQuery.event.addProp );\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// so that event delegation works in jQuery.\n// Do the same for pointerenter/pointerleave and pointerover/pointerout\n//\n// Support: Safari 7 only\n// Safari sends mouseenter too often; see:\n// https://bugs.chromium.org/p/chromium/issues/detail?id=470258\n// for the description of the bug (it existed in older Chrome versions as well).\njQuery.each( {\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mouseenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n} );\n\njQuery.fn.extend( {\n\n\ton: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn );\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ?\n\t\t\t\t\thandleObj.origType + \".\" + handleObj.namespace :\n\t\t\t\t\thandleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t} );\n\t}\n} );\n\n\nvar\n\n\t/* eslint-disable max-len */\n\n\t// See https://github.com/eslint/eslint/issues/3229\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,\n\n\t/* eslint-enable */\n\n\t// Support: IE <=10 - 11, Edge 12 - 13 only\n\t// In IE/Edge using regex groups here causes severe slowdowns.\n\t// See https://connect.microsoft.com/IE/feedback/details/1736512/\n\trnoInnerhtml = /<script|<style|<link/i,\n\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;\n\n// Prefer a tbody over its parent table for containing new rows\nfunction manipulationTarget( elem, content ) {\n\tif ( nodeName( elem, \"table\" ) &&\n\t\tnodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ) {\n\n\t\treturn jQuery( elem ).children( \"tbody\" )[ 0 ] || elem;\n\t}\n\n\treturn elem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = ( elem.getAttribute( \"type\" ) !== null ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tif ( ( elem.type || \"\" ).slice( 0, 5 ) === \"true/\" ) {\n\t\telem.type = elem.type.slice( 5 );\n\t} else {\n\t\telem.removeAttribute( \"type\" );\n\t}\n\n\treturn elem;\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\tvar i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;\n\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// 1. Copy private data: events, handlers, etc.\n\tif ( dataPriv.hasData( src ) ) {\n\t\tpdataOld = dataPriv.access( src );\n\t\tpdataCur = dataPriv.set( dest, pdataOld );\n\t\tevents = pdataOld.events;\n\n\t\tif ( events ) {\n\t\t\tdelete pdataCur.handle;\n\t\t\tpdataCur.events = {};\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Copy user data\n\tif ( dataUser.hasData( src ) ) {\n\t\tudataOld = dataUser.access( src );\n\t\tudataCur = jQuery.extend( {}, udataOld );\n\n\t\tdataUser.set( dest, udataCur );\n\t}\n}\n\n// Fix IE bugs, see support tests\nfunction fixInput( src, dest ) {\n\tvar nodeName = dest.nodeName.toLowerCase();\n\n\t// Fails to persist the checked state of a cloned checkbox or radio button.\n\tif ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n\t\tdest.checked = src.checked;\n\n\t// Fails to return the selected option to the default selected state when cloning options\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\nfunction domManip( collection, args, callback, ignored ) {\n\n\t// Flatten any nested arrays\n\targs = concat.apply( [], args );\n\n\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\ti = 0,\n\t\tl = collection.length,\n\t\tiNoClone = l - 1,\n\t\tvalue = args[ 0 ],\n\t\tvalueIsFunction = isFunction( value );\n\n\t// We can't cloneNode fragments that contain checked, in WebKit\n\tif ( valueIsFunction ||\n\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\treturn collection.each( function( index ) {\n\t\t\tvar self = collection.eq( index );\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\t}\n\t\t\tdomManip( self, args, callback, ignored );\n\t\t} );\n\t}\n\n\tif ( l ) {\n\t\tfragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );\n\t\tfirst = fragment.firstChild;\n\n\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\tfragment = first;\n\t\t}\n\n\t\t// Require either new content or an interest in ignored elements to invoke the callback\n\t\tif ( first || ignored ) {\n\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\thasScripts = scripts.length;\n\n\t\t\t// Use the original fragment for the last item\n\t\t\t// instead of the first because it can end up\n\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tnode = fragment;\n\n\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\tif ( hasScripts ) {\n\n\t\t\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcallback.call( collection[ i ], node, i );\n\t\t\t}\n\n\t\t\tif ( hasScripts ) {\n\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t// Reenable scripts\n\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t!dataPriv.access( node, \"globalEval\" ) &&\n\t\t\t\t\t\tjQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\tif ( node.src && ( node.type || \"\" ).toLowerCase()  !== \"module\" ) {\n\n\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\tif ( jQuery._evalUrl ) {\n\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tDOMEval( node.textContent.replace( rcleanScript, \"\" ), doc, node );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn collection;\n}\n\nfunction remove( elem, selector, keepData ) {\n\tvar node,\n\t\tnodes = selector ? jQuery.filter( selector, elem ) : elem,\n\t\ti = 0;\n\n\tfor ( ; ( node = nodes[ i ] ) != null; i++ ) {\n\t\tif ( !keepData && node.nodeType === 1 ) {\n\t\t\tjQuery.cleanData( getAll( node ) );\n\t\t}\n\n\t\tif ( node.parentNode ) {\n\t\t\tif ( keepData && jQuery.contains( node.ownerDocument, node ) ) {\n\t\t\t\tsetGlobalEval( getAll( node, \"script\" ) );\n\t\t\t}\n\t\t\tnode.parentNode.removeChild( node );\n\t\t}\n\t}\n\n\treturn elem;\n}\n\njQuery.extend( {\n\thtmlPrefilter: function( html ) {\n\t\treturn html.replace( rxhtmlTag, \"<$1></$2>\" );\n\t},\n\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar i, l, srcElements, destElements,\n\t\t\tclone = elem.cloneNode( true ),\n\t\t\tinPage = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t// Fix IE cloning issues\n\t\tif ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n\t\t\t\t!jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\tfixInput( srcElements[ i ], destElements[ i ] );\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[ i ], destElements[ i ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {\n\t\t\tif ( acceptData( elem ) ) {\n\t\t\t\tif ( ( data = elem[ dataPriv.expando ] ) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataPriv.expando ] = undefined;\n\t\t\t\t}\n\t\t\t\tif ( elem[ dataUser.expando ] ) {\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataUser.expando ] = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} );\n\njQuery.fn.extend( {\n\tdetach: function( selector ) {\n\t\treturn remove( this, selector, true );\n\t},\n\n\tremove: function( selector ) {\n\t\treturn remove( this, selector );\n\t},\n\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each( function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t} );\n\t},\n\n\tprepend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t} );\n\t},\n\n\tbefore: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t} );\n\t},\n\n\tafter: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t} );\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = this[ i ] ) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t} );\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = jQuery.htmlPrefilter( value );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch ( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar ignored = [];\n\n\t\t// Make the changes, replacing each non-ignored context element with the new content\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tvar parent = this.parentNode;\n\n\t\t\tif ( jQuery.inArray( this, ignored ) < 0 ) {\n\t\t\t\tjQuery.cleanData( getAll( this ) );\n\t\t\t\tif ( parent ) {\n\t\t\t\t\tparent.replaceChild( elem, this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Force callback invocation\n\t\t}, ignored );\n\t}\n} );\n\njQuery.each( {\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\n\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t// .get() because push.apply(_, arraylike) throws on ancient WebKit\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n} );\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar getStyles = function( elem ) {\n\n\t\t// Support: IE <=11 only, Firefox <=30 (#15098, #14150)\n\t\t// IE throws on elements created in popups\n\t\t// FF meanwhile throws on frame elements through \"defaultView.getComputedStyle\"\n\t\tvar view = elem.ownerDocument.defaultView;\n\n\t\tif ( !view || !view.opener ) {\n\t\t\tview = window;\n\t\t}\n\n\t\treturn view.getComputedStyle( elem );\n\t};\n\nvar rboxStyle = new RegExp( cssExpand.join( \"|\" ), \"i\" );\n\n\n\n( function() {\n\n\t// Executing both pixelPosition & boxSizingReliable tests require only one layout\n\t// so they're executed at the same time to save the second computation.\n\tfunction computeStyleTests() {\n\n\t\t// This is a singleton, we need to execute it only once\n\t\tif ( !div ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcontainer.style.cssText = \"position:absolute;left:-11111px;width:60px;\" +\n\t\t\t\"margin-top:1px;padding:0;border:0\";\n\t\tdiv.style.cssText =\n\t\t\t\"position:relative;display:block;box-sizing:border-box;overflow:scroll;\" +\n\t\t\t\"margin:auto;border:1px;padding:1px;\" +\n\t\t\t\"width:60%;top:1%\";\n\t\tdocumentElement.appendChild( container ).appendChild( div );\n\n\t\tvar divStyle = window.getComputedStyle( div );\n\t\tpixelPositionVal = divStyle.top !== \"1%\";\n\n\t\t// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44\n\t\treliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;\n\n\t\t// Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3\n\t\t// Some styles come back with percentage values, even though they shouldn't\n\t\tdiv.style.right = \"60%\";\n\t\tpixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;\n\n\t\t// Support: IE 9 - 11 only\n\t\t// Detect misreporting of content dimensions for box-sizing:border-box elements\n\t\tboxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;\n\n\t\t// Support: IE 9 only\n\t\t// Detect overflow:scroll screwiness (gh-3699)\n\t\tdiv.style.position = \"absolute\";\n\t\tscrollboxSizeVal = div.offsetWidth === 36 || \"absolute\";\n\n\t\tdocumentElement.removeChild( container );\n\n\t\t// Nullify the div so it wouldn't be stored in the memory and\n\t\t// it will also be a sign that checks already performed\n\t\tdiv = null;\n\t}\n\n\tfunction roundPixelMeasures( measure ) {\n\t\treturn Math.round( parseFloat( measure ) );\n\t}\n\n\tvar pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,\n\t\treliableMarginLeftVal,\n\t\tcontainer = document.createElement( \"div\" ),\n\t\tdiv = document.createElement( \"div\" );\n\n\t// Finish early in limited (non-browser) environments\n\tif ( !div.style ) {\n\t\treturn;\n\t}\n\n\t// Support: IE <=9 - 11 only\n\t// Style of cloned element affects source element cloned (#8908)\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\tjQuery.extend( support, {\n\t\tboxSizingReliable: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn boxSizingReliableVal;\n\t\t},\n\t\tpixelBoxStyles: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelBoxStylesVal;\n\t\t},\n\t\tpixelPosition: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelPositionVal;\n\t\t},\n\t\treliableMarginLeft: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn reliableMarginLeftVal;\n\t\t},\n\t\tscrollboxSize: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn scrollboxSizeVal;\n\t\t}\n\t} );\n} )();\n\n\nfunction curCSS( elem, name, computed ) {\n\tvar width, minWidth, maxWidth, ret,\n\n\t\t// Support: Firefox 51+\n\t\t// Retrieving style before computed somehow\n\t\t// fixes an issue with getting wrong values\n\t\t// on detached elements\n\t\tstyle = elem.style;\n\n\tcomputed = computed || getStyles( elem );\n\n\t// getPropertyValue is needed for:\n\t//   .css('filter') (IE 9 only, #12537)\n\t//   .css('--customProperty) (#3144)\n\tif ( computed ) {\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\n\t\tif ( ret === \"\" && !jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// Android Browser returns percentage for some values,\n\t\t// but width seems to be reliably pixels.\n\t\t// This is against the CSSOM draft spec:\n\t\t// https://drafts.csswg.org/cssom/#resolved-values\n\t\tif ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\twidth = style.width;\n\t\t\tminWidth = style.minWidth;\n\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\tret = computed.width;\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.width = width;\n\t\t\tstyle.minWidth = minWidth;\n\t\t\tstyle.maxWidth = maxWidth;\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\n\t\t// Support: IE <=9 - 11 only\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tif ( conditionFn() ) {\n\n\t\t\t\t// Hook not needed (or it's not possible to use it due\n\t\t\t\t// to missing dependency), remove it.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\t\t\treturn ( this.get = hookFn ).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\nvar\n\n\t// Swappable if display is none or starts with table\n\t// except \"table\", \"table-cell\", or \"table-caption\"\n\t// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trcustomProp = /^--/,\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t},\n\n\tcssPrefixes = [ \"Webkit\", \"Moz\", \"ms\" ],\n\temptyStyle = document.createElement( \"div\" ).style;\n\n// Return a css property mapped to a potentially vendor prefixed property\nfunction vendorPropName( name ) {\n\n\t// Shortcut for names that are not vendor prefixed\n\tif ( name in emptyStyle ) {\n\t\treturn name;\n\t}\n\n\t// Check for vendor prefixed names\n\tvar capName = name[ 0 ].toUpperCase() + name.slice( 1 ),\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in emptyStyle ) {\n\t\t\treturn name;\n\t\t}\n\t}\n}\n\n// Return a property mapped along what jQuery.cssProps suggests or to\n// a vendor prefixed property.\nfunction finalPropName( name ) {\n\tvar ret = jQuery.cssProps[ name ];\n\tif ( !ret ) {\n\t\tret = jQuery.cssProps[ name ] = vendorPropName( name ) || name;\n\t}\n\treturn ret;\n}\n\nfunction setPositiveNumber( elem, value, subtract ) {\n\n\t// Any relative (+/-) values have already been\n\t// normalized at this point\n\tvar matches = rcssNum.exec( value );\n\treturn matches ?\n\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {\n\tvar i = dimension === \"width\" ? 1 : 0,\n\t\textra = 0,\n\t\tdelta = 0;\n\n\t// Adjustment may not be necessary\n\tif ( box === ( isBorderBox ? \"border\" : \"content\" ) ) {\n\t\treturn 0;\n\t}\n\n\tfor ( ; i < 4; i += 2 ) {\n\n\t\t// Both box models exclude margin\n\t\tif ( box === \"margin\" ) {\n\t\t\tdelta += jQuery.css( elem, box + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\t// If we get here with a content-box, we're seeking \"padding\" or \"border\" or \"margin\"\n\t\tif ( !isBorderBox ) {\n\n\t\t\t// Add padding\n\t\t\tdelta += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// For \"border\" or \"margin\", add border\n\t\t\tif ( box !== \"padding\" ) {\n\t\t\t\tdelta += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\n\t\t\t// But still keep track of it otherwise\n\t\t\t} else {\n\t\t\t\textra += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\n\t\t// If we get here with a border-box (content + padding + border), we're seeking \"content\" or\n\t\t// \"padding\" or \"margin\"\n\t\t} else {\n\n\t\t\t// For \"content\", subtract padding\n\t\t\tif ( box === \"content\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// For \"content\" or \"padding\", subtract border\n\t\t\tif ( box !== \"margin\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Account for positive content-box scroll gutter when requested by providing computedVal\n\tif ( !isBorderBox && computedVal >= 0 ) {\n\n\t\t// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border\n\t\t// Assuming integer scroll gutter, subtract the rest and round down\n\t\tdelta += Math.max( 0, Math.ceil(\n\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\tcomputedVal -\n\t\t\tdelta -\n\t\t\textra -\n\t\t\t0.5\n\t\t) );\n\t}\n\n\treturn delta;\n}\n\nfunction getWidthOrHeight( elem, dimension, extra ) {\n\n\t// Start with computed style\n\tvar styles = getStyles( elem ),\n\t\tval = curCSS( elem, dimension, styles ),\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\tvalueIsBorderBox = isBorderBox;\n\n\t// Support: Firefox <=54\n\t// Return a confounding non-pixel value or feign ignorance, as appropriate.\n\tif ( rnumnonpx.test( val ) ) {\n\t\tif ( !extra ) {\n\t\t\treturn val;\n\t\t}\n\t\tval = \"auto\";\n\t}\n\n\t// Check for style in case a browser which returns unreliable values\n\t// for getComputedStyle silently falls back to the reliable elem.style\n\tvalueIsBorderBox = valueIsBorderBox &&\n\t\t( support.boxSizingReliable() || val === elem.style[ dimension ] );\n\n\t// Fall back to offsetWidth/offsetHeight when value is \"auto\"\n\t// This happens for inline elements with no explicit setting (gh-3571)\n\t// Support: Android <=4.1 - 4.3 only\n\t// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)\n\tif ( val === \"auto\" ||\n\t\t!parseFloat( val ) && jQuery.css( elem, \"display\", false, styles ) === \"inline\" ) {\n\n\t\tval = elem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ];\n\n\t\t// offsetWidth/offsetHeight provide border-box values\n\t\tvalueIsBorderBox = true;\n\t}\n\n\t// Normalize \"\" and auto\n\tval = parseFloat( val ) || 0;\n\n\t// Adjust for the element's box model\n\treturn ( val +\n\t\tboxModelAdjustment(\n\t\t\telem,\n\t\t\tdimension,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles,\n\n\t\t\t// Provide the current computed size to request scroll gutter calculation (gh-3589)\n\t\t\tval\n\t\t)\n\t) + \"px\";\n}\n\njQuery.extend( {\n\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"animationIterationCount\": true,\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"flexGrow\": true,\n\t\t\"flexShrink\": true,\n\t\t\"fontWeight\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name ),\n\t\t\tstyle = elem.style;\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to query the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Convert \"+=\" or \"-=\" to relative numbers (#7345)\n\t\t\tif ( type === \"string\" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {\n\t\t\t\tvalue = adjustCSS( elem, name, ret );\n\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (#7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add the unit (except for certain CSS properties)\n\t\t\tif ( type === \"number\" ) {\n\t\t\t\tvalue += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? \"\" : \"px\" );\n\t\t\t}\n\n\t\t\t// background-* props affect original clone's values\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !( \"set\" in hooks ) ||\n\t\t\t\t( value = hooks.set( elem, value, extra ) ) !== undefined ) {\n\n\t\t\t\tif ( isCustomProp ) {\n\t\t\t\t\tstyle.setProperty( name, value );\n\t\t\t\t} else {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks &&\n\t\t\t\t( ret = hooks.get( elem, false, extra ) ) !== undefined ) {\n\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name );\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to modify the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || isFinite( num ) ? num || 0 : val;\n\t\t}\n\n\t\treturn val;\n\t}\n} );\n\njQuery.each( [ \"height\", \"width\" ], function( i, dimension ) {\n\tjQuery.cssHooks[ dimension ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Certain elements can have dimension info if we invisibly show them\n\t\t\t\t// but it must have a current display style that would benefit\n\t\t\t\treturn rdisplayswap.test( jQuery.css( elem, \"display\" ) ) &&\n\n\t\t\t\t\t// Support: Safari 8+\n\t\t\t\t\t// Table columns in Safari have non-zero offsetWidth & zero\n\t\t\t\t\t// getBoundingClientRect().width unless display is changed.\n\t\t\t\t\t// Support: IE <=11 only\n\t\t\t\t\t// Running getBoundingClientRect on a disconnected node\n\t\t\t\t\t// in IE throws an error.\n\t\t\t\t\t( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?\n\t\t\t\t\t\tswap( elem, cssShow, function() {\n\t\t\t\t\t\t\treturn getWidthOrHeight( elem, dimension, extra );\n\t\t\t\t\t\t} ) :\n\t\t\t\t\t\tgetWidthOrHeight( elem, dimension, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar matches,\n\t\t\t\tstyles = getStyles( elem ),\n\t\t\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\tsubtract = extra && boxModelAdjustment(\n\t\t\t\t\telem,\n\t\t\t\t\tdimension,\n\t\t\t\t\textra,\n\t\t\t\t\tisBorderBox,\n\t\t\t\t\tstyles\n\t\t\t\t);\n\n\t\t\t// Account for unreliable border-box dimensions by comparing offset* to computed and\n\t\t\t// faking a content-box to get border and padding (gh-3699)\n\t\t\tif ( isBorderBox && support.scrollboxSize() === styles.position ) {\n\t\t\t\tsubtract -= Math.ceil(\n\t\t\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\t\t\tparseFloat( styles[ dimension ] ) -\n\t\t\t\t\tboxModelAdjustment( elem, dimension, \"border\", false, styles ) -\n\t\t\t\t\t0.5\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Convert to pixels if value adjustment is needed\n\t\t\tif ( subtract && ( matches = rcssNum.exec( value ) ) &&\n\t\t\t\t( matches[ 3 ] || \"px\" ) !== \"px\" ) {\n\n\t\t\t\telem.style[ dimension ] = value;\n\t\t\t\tvalue = jQuery.css( elem, dimension );\n\t\t\t}\n\n\t\t\treturn setPositiveNumber( elem, value, subtract );\n\t\t}\n\t};\n} );\n\njQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn ( parseFloat( curCSS( elem, \"marginLeft\" ) ) ||\n\t\t\t\telem.getBoundingClientRect().left -\n\t\t\t\t\tswap( elem, { marginLeft: 0 }, function() {\n\t\t\t\t\t\treturn elem.getBoundingClientRect().left;\n\t\t\t\t\t} )\n\t\t\t\t) + \"px\";\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each( {\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split( \" \" ) : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( prefix !== \"margin\" ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n} );\n\njQuery.fn.extend( {\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( Array.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t}\n} );\n\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || jQuery.easing._default;\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\t// Use a property on the element directly when it is not a DOM element,\n\t\t\t// or when there is no matching style property that exists.\n\t\t\tif ( tween.elem.nodeType !== 1 ||\n\t\t\t\ttween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// Passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails.\n\t\t\t// Simple values such as \"10px\" are parsed to Float;\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as-is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\n\t\t\t// Use step hook for back compat.\n\t\t\t// Use cssHook if its there.\n\t\t\t// Use .style if available and use plain properties where available.\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.nodeType === 1 &&\n\t\t\t\t( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||\n\t\t\t\t\tjQuery.cssHooks[ tween.prop ] ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Support: IE <=9 only\n// Panic based approach to setting things on disconnected nodes\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t},\n\t_default: \"swing\"\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back compat <1.8 extension point\njQuery.fx.step = {};\n\n\n\n\nvar\n\tfxNow, inProgress,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trrun = /queueHooks$/;\n\nfunction schedule() {\n\tif ( inProgress ) {\n\t\tif ( document.hidden === false && window.requestAnimationFrame ) {\n\t\t\twindow.requestAnimationFrame( schedule );\n\t\t} else {\n\t\t\twindow.setTimeout( schedule, jQuery.fx.interval );\n\t\t}\n\n\t\tjQuery.fx.tick();\n\t}\n}\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\twindow.setTimeout( function() {\n\t\tfxNow = undefined;\n\t} );\n\treturn ( fxNow = Date.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// If we include width, step value is 1 to do all cssExpand values,\n\t// otherwise step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {\n\n\t\t\t// We're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\tvar prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,\n\t\tisBox = \"width\" in props || \"height\" in props,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHiddenWithinTree( elem ),\n\t\tdataShow = dataPriv.get( elem, \"fxshow\" );\n\n\t// Queue-skipping animations hijack the fx hooks\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always( function() {\n\n\t\t\t// Ensure the complete handler is called before this completes\n\t\t\tanim.always( function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t// Detect show/hide animations\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.test( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// Pretend to be hidden if this is a \"show\" and\n\t\t\t\t// there is still data from a stopped show/hide\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\n\t\t\t\t// Ignore all other no-op show/hide data\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\t\t}\n\t}\n\n\t// Bail out if this is a no-op like .hide().hide()\n\tpropTween = !jQuery.isEmptyObject( props );\n\tif ( !propTween && jQuery.isEmptyObject( orig ) ) {\n\t\treturn;\n\t}\n\n\t// Restrict \"overflow\" and \"display\" styles during box animations\n\tif ( isBox && elem.nodeType === 1 ) {\n\n\t\t// Support: IE <=9 - 11, Edge 12 - 15\n\t\t// Record all 3 overflow attributes because IE does not infer the shorthand\n\t\t// from identically-valued overflowX and overflowY and Edge just mirrors\n\t\t// the overflowX value there.\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Identify a display type, preferring old show/hide data over the CSS cascade\n\t\trestoreDisplay = dataShow && dataShow.display;\n\t\tif ( restoreDisplay == null ) {\n\t\t\trestoreDisplay = dataPriv.get( elem, \"display\" );\n\t\t}\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\tif ( display === \"none\" ) {\n\t\t\tif ( restoreDisplay ) {\n\t\t\t\tdisplay = restoreDisplay;\n\t\t\t} else {\n\n\t\t\t\t// Get nonempty value(s) by temporarily forcing visibility\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t\trestoreDisplay = elem.style.display || restoreDisplay;\n\t\t\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\t\t\tshowHide( [ elem ] );\n\t\t\t}\n\t\t}\n\n\t\t// Animate inline elements as inline-block\n\t\tif ( display === \"inline\" || display === \"inline-block\" && restoreDisplay != null ) {\n\t\t\tif ( jQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\t\t// Restore the original display value at the end of pure show/hide animations\n\t\t\t\tif ( !propTween ) {\n\t\t\t\t\tanim.done( function() {\n\t\t\t\t\t\tstyle.display = restoreDisplay;\n\t\t\t\t\t} );\n\t\t\t\t\tif ( restoreDisplay == null ) {\n\t\t\t\t\t\tdisplay = style.display;\n\t\t\t\t\t\trestoreDisplay = display === \"none\" ? \"\" : display;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstyle.display = \"inline-block\";\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always( function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t} );\n\t}\n\n\t// Implement show/hide animations\n\tpropTween = false;\n\tfor ( prop in orig ) {\n\n\t\t// General show/hide setup for this element animation\n\t\tif ( !propTween ) {\n\t\t\tif ( dataShow ) {\n\t\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\t\thidden = dataShow.hidden;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdataShow = dataPriv.access( elem, \"fxshow\", { display: restoreDisplay } );\n\t\t\t}\n\n\t\t\t// Store hidden/visible for toggle so `.stop().toggle()` \"reverses\"\n\t\t\tif ( toggle ) {\n\t\t\t\tdataShow.hidden = !hidden;\n\t\t\t}\n\n\t\t\t// Show elements before animating them\n\t\t\tif ( hidden ) {\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t}\n\n\t\t\t/* eslint-disable no-loop-func */\n\n\t\t\tanim.done( function() {\n\n\t\t\t/* eslint-enable no-loop-func */\n\n\t\t\t\t// The final step of a \"hide\" animation is actually hiding the element\n\t\t\t\tif ( !hidden ) {\n\t\t\t\t\tshowHide( [ elem ] );\n\t\t\t\t}\n\t\t\t\tdataPriv.remove( elem, \"fxshow\" );\n\t\t\t\tfor ( prop in orig ) {\n\t\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\t// Per-property setup\n\t\tpropTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\t\tif ( !( prop in dataShow ) ) {\n\t\t\tdataShow[ prop ] = propTween.start;\n\t\t\tif ( hidden ) {\n\t\t\t\tpropTween.end = propTween.start;\n\t\t\t\tpropTween.start = 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( Array.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// Not quite $.extend, this won't overwrite existing keys.\n\t\t\t// Reusing 'index' because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = Animation.prefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\n\t\t\t// Don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t} ),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\n\t\t\t\t// Support: Android 2.3 only\n\t\t\t\t// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ] );\n\n\t\t\t// If there's more to do, yield\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t}\n\n\t\t\t// If this was an empty animation, synthesize a final progress notification\n\t\t\tif ( !length ) {\n\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t}\n\n\t\t\t// Resolve the animation and report its conclusion\n\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\treturn false;\n\t\t},\n\t\tanimation = deferred.promise( {\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, {\n\t\t\t\tspecialEasing: {},\n\t\t\t\teasing: jQuery.easing._default\n\t\t\t}, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\n\t\t\t\t\t// If we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// Resolve when we played the last frame; otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t} ),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length; index++ ) {\n\t\tresult = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\tif ( isFunction( result.stop ) ) {\n\t\t\t\tjQuery._queueHooks( animation.elem, animation.opts.queue ).stop =\n\t\t\t\t\tresult.stop.bind( result );\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\t// Attach callbacks from options\n\tanimation\n\t\t.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t} )\n\t);\n\n\treturn animation;\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweeners: {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value );\n\t\t\tadjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );\n\t\t\treturn tween;\n\t\t} ]\n\t},\n\n\ttweener: function( props, callback ) {\n\t\tif ( isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.match( rnothtmlwhite );\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\tAnimation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];\n\t\t\tAnimation.tweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilters: [ defaultPrefilter ],\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tAnimation.prefilters.unshift( callback );\n\t\t} else {\n\t\t\tAnimation.prefilters.push( callback );\n\t\t}\n\t}\n} );\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tisFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !isFunction( easing ) && easing\n\t};\n\n\t// Go to the end state if fx are off\n\tif ( jQuery.fx.off ) {\n\t\topt.duration = 0;\n\n\t} else {\n\t\tif ( typeof opt.duration !== \"number\" ) {\n\t\t\tif ( opt.duration in jQuery.fx.speeds ) {\n\t\t\t\topt.duration = jQuery.fx.speeds[ opt.duration ];\n\n\t\t\t} else {\n\t\t\t\topt.duration = jQuery.fx.speeds._default;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend( {\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// Show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHiddenWithinTree ).css( \"opacity\", 0 ).show()\n\n\t\t\t// Animate to the value specified\n\t\t\t.end().animate( { opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || dataPriv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\t\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue && type !== false ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = dataPriv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this &&\n\t\t\t\t\t( type == null || timers[ index ].queue === type ) ) {\n\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Start the next in the queue if the last step wasn't forced.\n\t\t\t// Timers currently will call their complete callbacks, which\n\t\t\t// will dequeue but only if they were gotoEnd.\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t} );\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tvar index,\n\t\t\t\tdata = dataPriv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// Enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// Empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// Look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t} );\n\t}\n} );\n\njQuery.each( [ \"toggle\", \"show\", \"hide\" ], function( i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n} );\n\n// Generate shortcuts for custom animations\njQuery.each( {\n\tslideDown: genFx( \"show\" ),\n\tslideUp: genFx( \"hide\" ),\n\tslideToggle: genFx( \"toggle\" ),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n} );\n\njQuery.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = Date.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\n\t\t// Run the timer and safely remove it when done (allowing for external removal)\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tjQuery.fx.start();\n};\n\njQuery.fx.interval = 13;\njQuery.fx.start = function() {\n\tif ( inProgress ) {\n\t\treturn;\n\t}\n\n\tinProgress = true;\n\tschedule();\n};\n\njQuery.fx.stop = function() {\n\tinProgress = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\n\t// Default speed\n\t_default: 400\n};\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = window.setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\twindow.clearTimeout( timeout );\n\t\t};\n\t} );\n};\n\n\n( function() {\n\tvar input = document.createElement( \"input\" ),\n\t\tselect = document.createElement( \"select\" ),\n\t\topt = select.appendChild( document.createElement( \"option\" ) );\n\n\tinput.type = \"checkbox\";\n\n\t// Support: Android <=4.3 only\n\t// Default value for a checkbox should be \"on\"\n\tsupport.checkOn = input.value !== \"\";\n\n\t// Support: IE <=11 only\n\t// Must access selectedIndex to make default options select\n\tsupport.optSelected = opt.selected;\n\n\t// Support: IE <=11 only\n\t// An input loses its value after becoming a radio\n\tinput = document.createElement( \"input\" );\n\tinput.value = \"t\";\n\tinput.type = \"radio\";\n\tsupport.radioValue = input.value === \"t\";\n} )();\n\n\nvar boolHook,\n\tattrHandle = jQuery.expr.attrHandle;\n\njQuery.fn.extend( {\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set attributes on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// Attribute hooks are determined by the lowercase version\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\thooks = jQuery.attrHooks[ name.toLowerCase() ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\treturn value;\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tret = jQuery.find.attr( elem, name );\n\n\t\t// Non-existent attributes return null, we normalize to undefined\n\t\treturn ret == null ? undefined : ret;\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !support.radioValue && value === \"radio\" &&\n\t\t\t\t\tnodeName( elem, \"input\" ) ) {\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name,\n\t\t\ti = 0,\n\n\t\t\t// Attribute names can contain non-HTML whitespace characters\n\t\t\t// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2\n\t\t\tattrNames = value && value.match( rnothtmlwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( ( name = attrNames[ i++ ] ) ) {\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Hooks for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\telem.setAttribute( name, name );\n\t\t}\n\t\treturn name;\n\t}\n};\n\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( i, name ) {\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = function( elem, name, isXML ) {\n\t\tvar ret, handle,\n\t\t\tlowercaseName = name.toLowerCase();\n\n\t\tif ( !isXML ) {\n\n\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\thandle = attrHandle[ lowercaseName ];\n\t\t\tattrHandle[ lowercaseName ] = ret;\n\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\tlowercaseName :\n\t\t\t\tnull;\n\t\t\tattrHandle[ lowercaseName ] = handle;\n\t\t}\n\t\treturn ret;\n\t};\n} );\n\n\n\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i,\n\trclickable = /^(?:a|area)$/i;\n\njQuery.fn.extend( {\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\treturn ( elem[ name ] = value );\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\treturn elem[ name ];\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\t// Support: IE <=9 - 11 only\n\t\t\t\t// elem.tabIndex doesn't always return the\n\t\t\t\t// correct value when it hasn't been explicitly set\n\t\t\t\t// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\t// Use proper attribute retrieval(#12072)\n\t\t\t\tvar tabindex = jQuery.find.attr( elem, \"tabindex\" );\n\n\t\t\t\tif ( tabindex ) {\n\t\t\t\t\treturn parseInt( tabindex, 10 );\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\trfocusable.test( elem.nodeName ) ||\n\t\t\t\t\trclickable.test( elem.nodeName ) &&\n\t\t\t\t\telem.href\n\t\t\t\t) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t}\n} );\n\n// Support: IE <=11 only\n// Accessing the selectedIndex property\n// forces the browser to respect setting selected\n// on the option\n// The getter ensures a default option is selected\n// when in an optgroup\n// eslint rule \"no-unused-expressions\" is disabled for this code\n// since it considers such accessions noop\nif ( !support.optSelected ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tset: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\njQuery.each( [\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n} );\n\n\n\n\n\t// Strip and collapse whitespace according to HTML spec\n\t// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace\n\tfunction stripAndCollapse( value ) {\n\t\tvar tokens = value.match( rnothtmlwhite ) || [];\n\t\treturn tokens.join( \" \" );\n\t}\n\n\nfunction getClass( elem ) {\n\treturn elem.getAttribute && elem.getAttribute( \"class\" ) || \"\";\n}\n\nfunction classesToArray( value ) {\n\tif ( Array.isArray( value ) ) {\n\t\treturn value;\n\t}\n\tif ( typeof value === \"string\" ) {\n\t\treturn value.match( rnothtmlwhite ) || [];\n\t}\n\treturn [];\n}\n\njQuery.fn.extend( {\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( !arguments.length ) {\n\t\t\treturn this.attr( \"class\", \"\" );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) > -1 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value,\n\t\t\tisValidValue = type === \"string\" || Array.isArray( value );\n\n\t\tif ( typeof stateVal === \"boolean\" && isValidValue ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).toggleClass(\n\t\t\t\t\tvalue.call( this, i, getClass( this ), stateVal ),\n\t\t\t\t\tstateVal\n\t\t\t\t);\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar className, i, self, classNames;\n\n\t\t\tif ( isValidValue ) {\n\n\t\t\t\t// Toggle individual class names\n\t\t\t\ti = 0;\n\t\t\t\tself = jQuery( this );\n\t\t\t\tclassNames = classesToArray( value );\n\n\t\t\t\twhile ( ( className = classNames[ i++ ] ) ) {\n\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( value === undefined || type === \"boolean\" ) {\n\t\t\t\tclassName = getClass( this );\n\t\t\t\tif ( className ) {\n\n\t\t\t\t\t// Store className if set\n\t\t\t\t\tdataPriv.set( this, \"__className__\", className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed `false`,\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tif ( this.setAttribute ) {\n\t\t\t\t\tthis.setAttribute( \"class\",\n\t\t\t\t\t\tclassName || value === false ?\n\t\t\t\t\t\t\"\" :\n\t\t\t\t\t\tdataPriv.get( this, \"__className__\" ) || \"\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className, elem,\n\t\t\ti = 0;\n\n\t\tclassName = \" \" + selector + \" \";\n\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\tif ( elem.nodeType === 1 &&\n\t\t\t\t( \" \" + stripAndCollapse( getClass( elem ) ) + \" \" ).indexOf( className ) > -1 ) {\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n} );\n\n\n\n\nvar rreturn = /\\r/g;\n\njQuery.fn.extend( {\n\tval: function( value ) {\n\t\tvar hooks, ret, valueIsFunction,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] ||\n\t\t\t\t\tjQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks &&\n\t\t\t\t\t\"get\" in hooks &&\n\t\t\t\t\t( ret = hooks.get( elem, \"value\" ) ) !== undefined\n\t\t\t\t) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\t// Handle most common string cases\n\t\t\t\tif ( typeof ret === \"string\" ) {\n\t\t\t\t\treturn ret.replace( rreturn, \"\" );\n\t\t\t\t}\n\n\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\treturn ret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tvalueIsFunction = isFunction( value );\n\n\t\treturn this.each( function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( Array.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !( \"set\" in hooks ) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\tvar val = jQuery.find.attr( elem, \"value\" );\n\t\t\t\treturn val != null ?\n\t\t\t\t\tval :\n\n\t\t\t\t\t// Support: IE <=10 - 11 only\n\t\t\t\t\t// option.text throws exceptions (#14686, #14858)\n\t\t\t\t\t// Strip and collapse whitespace\n\t\t\t\t\t// https://html.spec.whatwg.org/#strip-and-collapse-whitespace\n\t\t\t\t\tstripAndCollapse( jQuery.text( elem ) );\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option, i,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\",\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length;\n\n\t\t\t\tif ( index < 0 ) {\n\t\t\t\t\ti = max;\n\n\t\t\t\t} else {\n\t\t\t\t\ti = one ? index : 0;\n\t\t\t\t}\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t// IE8-9 doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t!option.disabled &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled ||\n\t\t\t\t\t\t\t\t!nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t/* eslint-disable no-cond-assign */\n\n\t\t\t\t\tif ( option.selected =\n\t\t\t\t\t\tjQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1\n\t\t\t\t\t) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* eslint-enable no-cond-assign */\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Radios and checkboxes getter/setter\njQuery.each( [ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( Array.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );\n\t\t\t}\n\t\t}\n\t};\n\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\treturn elem.getAttribute( \"value\" ) === null ? \"on\" : elem.value;\n\t\t};\n\t}\n} );\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\nsupport.focusin = \"onfocusin\" in window;\n\n\nvar rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\tstopPropagationCallback = function( e ) {\n\t\te.stopPropagation();\n\t};\n\njQuery.extend( jQuery.event, {\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special, lastElement,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split( \".\" ) : [];\n\n\t\tcur = lastElement = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf( \".\" ) > -1 ) {\n\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split( \".\" );\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf( \":\" ) < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join( \".\" );\n\t\tevent.rnamespace = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === ( elem.ownerDocument || document ) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tlastElement = cur;\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( dataPriv.get( cur, \"events\" ) || {} )[ event.type ] &&\n\t\t\t\tdataPriv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( ( !special._default ||\n\t\t\t\tspecial._default.apply( eventPath.pop(), data ) === false ) &&\n\t\t\t\tacceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.addEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\telem[ type ]();\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.removeEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\t// Piggyback on a donor event to simulate a different one\n\t// Used only for `focus(in | out)` events\n\tsimulate: function( type, elem, event ) {\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true\n\t\t\t}\n\t\t);\n\n\t\tjQuery.event.trigger( e, null, elem );\n\t}\n\n} );\n\njQuery.fn.extend( {\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t} );\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[ 0 ];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n} );\n\n\n// Support: Firefox <=44\n// Firefox doesn't have focus(in | out) events\n// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787\n//\n// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1\n// focus(in | out) events fire after focus & blur events,\n// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order\n// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857\nif ( !support.focusin ) {\n\tjQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );\n\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tdataPriv.access( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tdataPriv.remove( doc, fix );\n\n\t\t\t\t} else {\n\t\t\t\t\tdataPriv.access( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t} );\n}\nvar location = window.location;\n\nvar nonce = Date.now();\n\nvar rquery = ( /\\?/ );\n\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE 9 - 11 only\n\t// IE throws on parseFromString with invalid input.\n\ttry {\n\t\txml = ( new window.DOMParser() ).parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {\n\t\txml = undefined;\n\t}\n\n\tif ( !xml || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\tjQuery.error( \"Invalid XML: \" + data );\n\t}\n\treturn xml;\n};\n\n\nvar\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( Array.isArray( obj ) ) {\n\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams(\n\t\t\t\t\tprefix + \"[\" + ( typeof v === \"object\" && v != null ? i : \"\" ) + \"]\",\n\t\t\t\t\tv,\n\t\t\t\t\ttraditional,\n\t\t\t\t\tadd\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t} else if ( !traditional && toType( obj ) === \"object\" ) {\n\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, valueOrFunction ) {\n\n\t\t\t// If value is a function, invoke it and use its return value\n\t\t\tvar value = isFunction( valueOrFunction ) ?\n\t\t\t\tvalueOrFunction() :\n\t\t\t\tvalueOrFunction;\n\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" +\n\t\t\t\tencodeURIComponent( value == null ? \"\" : value );\n\t\t};\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t} );\n\n\t} else {\n\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" );\n};\n\njQuery.fn.extend( {\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map( function() {\n\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t} )\n\t\t.filter( function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t} )\n\t\t.map( function( i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\tif ( val == null ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( Array.isArray( val ) ) {\n\t\t\t\treturn jQuery.map( val, function( val ) {\n\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t} ).get();\n\t}\n} );\n\n\nvar\n\tr20 = /%20/g,\n\trhash = /#.*$/,\n\trantiCache = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t *    - BEFORE asking for a transport\n\t *    - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat( \"*\" ),\n\n\t// Anchor tag for parsing the document origin\n\toriginAnchor = document.createElement( \"a\" );\n\toriginAnchor.href = location.href;\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];\n\n\t\tif ( isFunction( func ) ) {\n\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( ( dataType = dataTypes[ i++ ] ) ) {\n\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[ 0 ] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" &&\n\t\t\t\t!seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t} );\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\n\n\t// Remove auto dataType and get content-type in the process\n\twhile ( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader( \"Content-Type\" );\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[ 0 ] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n/* Chain conversions given the request and the original response\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s.throws ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tstate: \"parsererror\",\n\t\t\t\t\t\t\t\terror: conv ? e : \"No conversion from \" + prev + \" to \" + current\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\njQuery.extend( {\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: location.href,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( location.protocol ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /\\bxml\\b/,\n\t\t\thtml: /\\bhtml/,\n\t\t\tjson: /\\bjson\\b/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": JSON.parse,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// Url cleanup var\n\t\t\turlAnchor,\n\n\t\t\t// Request state (becomes false upon send and true upon completion)\n\t\t\tcompleted,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\t// Loop variable\n\t\t\ti,\n\n\t\t\t// uncached part of the url\n\t\t\tuncached,\n\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context &&\n\t\t\t\t( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\t\tjQuery.event,\n\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks( \"once memory\" ),\n\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( completed ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( ( match = rheaders.exec( responseHeadersString ) ) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match;\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn completed ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\tname = requestHeadersNames[ name.toLowerCase() ] =\n\t\t\t\t\t\t\trequestHeadersNames[ name.toLowerCase() ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( completed ) {\n\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Lazy-add the new callbacks in a way that preserves old ones\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR );\n\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || location.href ) + \"\" )\n\t\t\t.replace( rprotocol, location.protocol + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = ( s.dataType || \"*\" ).toLowerCase().match( rnothtmlwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when the origin doesn't match the current origin.\n\t\tif ( s.crossDomain == null ) {\n\t\t\turlAnchor = document.createElement( \"a\" );\n\n\t\t\t// Support: IE <=8 - 11, Edge 12 - 15\n\t\t\t// IE throws exception on accessing the href property if url is malformed,\n\t\t\t// e.g. http://example.com:80x/\n\t\t\ttry {\n\t\t\t\turlAnchor.href = s.url;\n\n\t\t\t\t// Support: IE <=8 - 11 only\n\t\t\t\t// Anchor's host property isn't correctly set when s.url is relative\n\t\t\t\turlAnchor.href = urlAnchor.href;\n\t\t\t\ts.crossDomain = originAnchor.protocol + \"//\" + originAnchor.host !==\n\t\t\t\t\turlAnchor.protocol + \"//\" + urlAnchor.host;\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// If there is an error parsing the URL, assume it is crossDomain,\n\t\t\t\t// it can be rejected by the transport if it is invalid\n\t\t\t\ts.crossDomain = true;\n\t\t\t}\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( completed ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\t// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)\n\t\tfireGlobals = jQuery.event && s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger( \"ajaxStart\" );\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\t// Remove hash to simplify url manipulation\n\t\tcacheURL = s.url.replace( rhash, \"\" );\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// Remember the hash so we can put it back\n\t\t\tuncached = s.url.slice( cacheURL.length );\n\n\t\t\t// If data is available and should be processed, append data to url\n\t\t\tif ( s.data && ( s.processData || typeof s.data === \"string\" ) ) {\n\t\t\t\tcacheURL += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data;\n\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add or update anti-cache param if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\tcacheURL = cacheURL.replace( rantiCache, \"$1\" );\n\t\t\t\tuncached = ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + ( nonce++ ) + uncached;\n\t\t\t}\n\n\t\t\t// Put hash and anti-cache on the URL that will be requested (gh-1732)\n\t\t\ts.url = cacheURL + uncached;\n\n\t\t// Change '%20' to '+' if this is encoded form body content (gh-2658)\n\t\t} else if ( s.data && s.processData &&\n\t\t\t( s.contentType || \"\" ).indexOf( \"application/x-www-form-urlencoded\" ) === 0 ) {\n\t\t\ts.data = s.data.replace( r20, \"+\" );\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[ 0 ] ] +\n\t\t\t\t\t( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend &&\n\t\t\t( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {\n\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// Aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tcompleteDeferred.add( s.complete );\n\t\tjqXHR.done( s.success );\n\t\tjqXHR.fail( s.error );\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\n\t\t\t// If request was aborted inside ajaxSend, stop there\n\t\t\tif ( completed ) {\n\t\t\t\treturn jqXHR;\n\t\t\t}\n\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = window.setTimeout( function() {\n\t\t\t\t\tjqXHR.abort( \"timeout\" );\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tcompleted = false;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// Rethrow post-completion exceptions\n\t\t\t\tif ( completed ) {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\n\t\t\t\t// Propagate others as results\n\t\t\t\tdone( -1, e );\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Ignore repeat invocations\n\t\t\tif ( completed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcompleted = true;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\twindow.clearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"Last-Modified\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"etag\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\n\t\t\t\t// Extract error from statusText and normalize for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n} );\n\njQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\n\t\t// Shift arguments if data argument was omitted\n\t\tif ( isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\t// The url can be an options object (which then must have .url)\n\t\treturn jQuery.ajax( jQuery.extend( {\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t}, jQuery.isPlainObject( url ) && url ) );\n\t};\n} );\n\n\njQuery._evalUrl = function( url ) {\n\treturn jQuery.ajax( {\n\t\turl: url,\n\n\t\t// Make this explicit, since user can override this through ajaxSetup (#11264)\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tcache: true,\n\t\tasync: false,\n\t\tglobal: false,\n\t\t\"throws\": true\n\t} );\n};\n\n\njQuery.fn.extend( {\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( this[ 0 ] ) {\n\t\t\tif ( isFunction( html ) ) {\n\t\t\t\thtml = html.call( this[ 0 ] );\n\t\t\t}\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map( function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t} ).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( isFunction( html ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call( this, i ) );\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t} );\n\t},\n\n\twrap: function( html ) {\n\t\tvar htmlIsFunction = isFunction( html );\n\n\t\treturn this.each( function( i ) {\n\t\t\tjQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );\n\t\t} );\n\t},\n\n\tunwrap: function( selector ) {\n\t\tthis.parent( selector ).not( \"body\" ).each( function() {\n\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t} );\n\t\treturn this;\n\t}\n} );\n\n\njQuery.expr.pseudos.hidden = function( elem ) {\n\treturn !jQuery.expr.pseudos.visible( elem );\n};\njQuery.expr.pseudos.visible = function( elem ) {\n\treturn !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );\n};\n\n\n\n\njQuery.ajaxSettings.xhr = function() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch ( e ) {}\n};\n\nvar xhrSuccessStatus = {\n\n\t\t// File protocol always yields status code 0, assume 200\n\t\t0: 200,\n\n\t\t// Support: IE <=9 only\n\t\t// #1450: sometimes IE returns 1223 when it should be 204\n\t\t1223: 204\n\t},\n\txhrSupported = jQuery.ajaxSettings.xhr();\n\nsupport.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nsupport.ajax = xhrSupported = !!xhrSupported;\n\njQuery.ajaxTransport( function( options ) {\n\tvar callback, errorCallback;\n\n\t// Cross domain only allowed if supported through XMLHttpRequest\n\tif ( support.cors || xhrSupported && !options.crossDomain ) {\n\t\treturn {\n\t\t\tsend: function( headers, complete ) {\n\t\t\t\tvar i,\n\t\t\t\t\txhr = options.xhr();\n\n\t\t\t\txhr.open(\n\t\t\t\t\toptions.type,\n\t\t\t\t\toptions.url,\n\t\t\t\t\toptions.async,\n\t\t\t\t\toptions.username,\n\t\t\t\t\toptions.password\n\t\t\t\t);\n\n\t\t\t\t// Apply custom fields if provided\n\t\t\t\tif ( options.xhrFields ) {\n\t\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Override mime type if needed\n\t\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t\t}\n\n\t\t\t\t// X-Requested-With header\n\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\tif ( !options.crossDomain && !headers[ \"X-Requested-With\" ] ) {\n\t\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n\t\t\t\t}\n\n\t\t\t\t// Set headers\n\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t}\n\n\t\t\t\t// Callback\n\t\t\t\tcallback = function( type ) {\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\tcallback = errorCallback = xhr.onload =\n\t\t\t\t\t\t\t\txhr.onerror = xhr.onabort = xhr.ontimeout =\n\t\t\t\t\t\t\t\t\txhr.onreadystatechange = null;\n\n\t\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\n\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t// On a manual native abort, IE9 throws\n\t\t\t\t\t\t\t\t// errors on any property access that is not readyState\n\t\t\t\t\t\t\t\tif ( typeof xhr.status !== \"number\" ) {\n\t\t\t\t\t\t\t\t\tcomplete( 0, \"error\" );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcomplete(\n\n\t\t\t\t\t\t\t\t\t\t// File: protocol always yields status 0; see #8605, #14207\n\t\t\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\t\t\txhr.statusText\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText,\n\n\t\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t\t// IE9 has no XHR2 but throws on binary (trac-11426)\n\t\t\t\t\t\t\t\t\t// For XHR2 non-text, let the caller handle it (gh-2498)\n\t\t\t\t\t\t\t\t\t( xhr.responseType || \"text\" ) !== \"text\"  ||\n\t\t\t\t\t\t\t\t\ttypeof xhr.responseText !== \"string\" ?\n\t\t\t\t\t\t\t\t\t\t{ binary: xhr.response } :\n\t\t\t\t\t\t\t\t\t\t{ text: xhr.responseText },\n\t\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t};\n\n\t\t\t\t// Listen to events\n\t\t\t\txhr.onload = callback();\n\t\t\t\terrorCallback = xhr.onerror = xhr.ontimeout = callback( \"error\" );\n\n\t\t\t\t// Support: IE 9 only\n\t\t\t\t// Use onreadystatechange to replace onabort\n\t\t\t\t// to handle uncaught aborts\n\t\t\t\tif ( xhr.onabort !== undefined ) {\n\t\t\t\t\txhr.onabort = errorCallback;\n\t\t\t\t} else {\n\t\t\t\t\txhr.onreadystatechange = function() {\n\n\t\t\t\t\t\t// Check readyState before timeout as it changes\n\t\t\t\t\t\tif ( xhr.readyState === 4 ) {\n\n\t\t\t\t\t\t\t// Allow onerror to be called first,\n\t\t\t\t\t\t\t// but that will not handle a native abort\n\t\t\t\t\t\t\t// Also, save errorCallback to a variable\n\t\t\t\t\t\t\t// as xhr.onerror cannot be accessed\n\t\t\t\t\t\t\twindow.setTimeout( function() {\n\t\t\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\t\t\terrorCallback();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Create the abort callback\n\t\t\t\tcallback = callback( \"abort\" );\n\n\t\t\t\ttry {\n\n\t\t\t\t\t// Do send the request (this may raise an exception)\n\t\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t// #14683: Only rethrow if this hasn't been notified as an error yet\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\n// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)\njQuery.ajaxPrefilter( function( s ) {\n\tif ( s.crossDomain ) {\n\t\ts.contents.script = false;\n\t}\n} );\n\n// Install script dataType\njQuery.ajaxSetup( {\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, \" +\n\t\t\t\"application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /\\b(?:java|ecma)script\\b/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n} );\n\n// Handle cache's special case and crossDomain\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t}\n} );\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\n\t// This transport only deals with cross domain requests\n\tif ( s.crossDomain ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery( \"<script>\" ).prop( {\n\t\t\t\t\tcharset: s.scriptCharset,\n\t\t\t\t\tsrc: s.url\n\t\t\t\t} ).on(\n\t\t\t\t\t\"load error\",\n\t\t\t\t\tcallback = function( evt ) {\n\t\t\t\t\t\tscript.remove();\n\t\t\t\t\t\tcallback = null;\n\t\t\t\t\t\tif ( evt ) {\n\t\t\t\t\t\t\tcomplete( evt.type === \"error\" ? 404 : 200, evt.type );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t);\n\n\t\t\t\t// Use native DOM manipulation to avoid our domManip AJAX trickery\n\t\t\t\tdocument.head.appendChild( script[ 0 ] );\n\t\t\t},\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\nvar oldCallbacks = [],\n\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\njQuery.ajaxSetup( {\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\tvar callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( nonce++ ) );\n\t\tthis[ callback ] = true;\n\t\treturn callback;\n\t}\n} );\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n\tvar callbackName, overwritten, responseContainer,\n\t\tjsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n\t\t\t\"url\" :\n\t\t\ttypeof s.data === \"string\" &&\n\t\t\t\t( s.contentType || \"\" )\n\t\t\t\t\t.indexOf( \"application/x-www-form-urlencoded\" ) === 0 &&\n\t\t\t\trjsonp.test( s.data ) && \"data\"\n\t\t);\n\n\t// Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n\tif ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n\t\t// Get callback name, remembering preexisting value associated with it\n\t\tcallbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?\n\t\t\ts.jsonpCallback() :\n\t\t\ts.jsonpCallback;\n\n\t\t// Insert callback into url or form data\n\t\tif ( jsonProp ) {\n\t\t\ts[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n\t\t} else if ( s.jsonp !== false ) {\n\t\t\ts.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\n\t\t}\n\n\t\t// Use data converter to retrieve json after script execution\n\t\ts.converters[ \"script json\" ] = function() {\n\t\t\tif ( !responseContainer ) {\n\t\t\t\tjQuery.error( callbackName + \" was not called\" );\n\t\t\t}\n\t\t\treturn responseContainer[ 0 ];\n\t\t};\n\n\t\t// Force json dataType\n\t\ts.dataTypes[ 0 ] = \"json\";\n\n\t\t// Install callback\n\t\toverwritten = window[ callbackName ];\n\t\twindow[ callbackName ] = function() {\n\t\t\tresponseContainer = arguments;\n\t\t};\n\n\t\t// Clean-up function (fires after converters)\n\t\tjqXHR.always( function() {\n\n\t\t\t// If previous value didn't exist - remove it\n\t\t\tif ( overwritten === undefined ) {\n\t\t\t\tjQuery( window ).removeProp( callbackName );\n\n\t\t\t// Otherwise restore preexisting value\n\t\t\t} else {\n\t\t\t\twindow[ callbackName ] = overwritten;\n\t\t\t}\n\n\t\t\t// Save back as free\n\t\t\tif ( s[ callbackName ] ) {\n\n\t\t\t\t// Make sure that re-using the options doesn't screw things around\n\t\t\t\ts.jsonpCallback = originalSettings.jsonpCallback;\n\n\t\t\t\t// Save the callback name for future use\n\t\t\t\toldCallbacks.push( callbackName );\n\t\t\t}\n\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && isFunction( overwritten ) ) {\n\t\t\t\toverwritten( responseContainer[ 0 ] );\n\t\t\t}\n\n\t\t\tresponseContainer = overwritten = undefined;\n\t\t} );\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n} );\n\n\n\n\n// Support: Safari 8 only\n// In Safari 8 documents created via document.implementation.createHTMLDocument\n// collapse sibling forms: the second one becomes a child of the first one.\n// Because of that, this security measure has to be disabled in Safari 8.\n// https://bugs.webkit.org/show_bug.cgi?id=137337\nsupport.createHTMLDocument = ( function() {\n\tvar body = document.implementation.createHTMLDocument( \"\" ).body;\n\tbody.innerHTML = \"<form></form><form></form>\";\n\treturn body.childNodes.length === 2;\n} )();\n\n\n// Argument \"data\" should be string of html\n// context (optional): If specified, the fragment will be created in this context,\n// defaults to document\n// keepScripts (optional): If true, will include scripts passed in the html string\njQuery.parseHTML = function( data, context, keepScripts ) {\n\tif ( typeof data !== \"string\" ) {\n\t\treturn [];\n\t}\n\tif ( typeof context === \"boolean\" ) {\n\t\tkeepScripts = context;\n\t\tcontext = false;\n\t}\n\n\tvar base, parsed, scripts;\n\n\tif ( !context ) {\n\n\t\t// Stop scripts or inline event handlers from being executed immediately\n\t\t// by using document.implementation\n\t\tif ( support.createHTMLDocument ) {\n\t\t\tcontext = document.implementation.createHTMLDocument( \"\" );\n\n\t\t\t// Set the base href for the created document\n\t\t\t// so any parsed elements with URLs\n\t\t\t// are based on the document's URL (gh-2965)\n\t\t\tbase = context.createElement( \"base\" );\n\t\t\tbase.href = document.location.href;\n\t\t\tcontext.head.appendChild( base );\n\t\t} else {\n\t\t\tcontext = document;\n\t\t}\n\t}\n\n\tparsed = rsingleTag.exec( data );\n\tscripts = !keepScripts && [];\n\n\t// Single tag\n\tif ( parsed ) {\n\t\treturn [ context.createElement( parsed[ 1 ] ) ];\n\t}\n\n\tparsed = buildFragment( [ data ], context, scripts );\n\n\tif ( scripts && scripts.length ) {\n\t\tjQuery( scripts ).remove();\n\t}\n\n\treturn jQuery.merge( [], parsed.childNodes );\n};\n\n\n/**\n * Load a url into a page\n */\njQuery.fn.load = function( url, params, callback ) {\n\tvar selector, type, response,\n\t\tself = this,\n\t\toff = url.indexOf( \" \" );\n\n\tif ( off > -1 ) {\n\t\tselector = stripAndCollapse( url.slice( off ) );\n\t\turl = url.slice( 0, off );\n\t}\n\n\t// If it's a function\n\tif ( isFunction( params ) ) {\n\n\t\t// We assume that it's the callback\n\t\tcallback = params;\n\t\tparams = undefined;\n\n\t// Otherwise, build a param string\n\t} else if ( params && typeof params === \"object\" ) {\n\t\ttype = \"POST\";\n\t}\n\n\t// If we have elements to modify, make the request\n\tif ( self.length > 0 ) {\n\t\tjQuery.ajax( {\n\t\t\turl: url,\n\n\t\t\t// If \"type\" variable is undefined, then \"GET\" method will be used.\n\t\t\t// Make value of this field explicit since\n\t\t\t// user can override it through ajaxSetup method\n\t\t\ttype: type || \"GET\",\n\t\t\tdataType: \"html\",\n\t\t\tdata: params\n\t\t} ).done( function( responseText ) {\n\n\t\t\t// Save response for use in complete callback\n\t\t\tresponse = arguments;\n\n\t\t\tself.html( selector ?\n\n\t\t\t\t// If a selector was specified, locate the right elements in a dummy div\n\t\t\t\t// Exclude scripts to avoid IE 'Permission Denied' errors\n\t\t\t\tjQuery( \"<div>\" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t// If the request succeeds, this function gets \"data\", \"status\", \"jqXHR\"\n\t\t// but they are ignored because response was set above.\n\t\t// If it fails, this function gets \"jqXHR\", \"status\", \"error\"\n\t\t} ).always( callback && function( jqXHR, status ) {\n\t\t\tself.each( function() {\n\t\t\t\tcallback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t\t} );\n\t\t} );\n\t}\n\n\treturn this;\n};\n\n\n\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( [\n\t\"ajaxStart\",\n\t\"ajaxStop\",\n\t\"ajaxComplete\",\n\t\"ajaxError\",\n\t\"ajaxSuccess\",\n\t\"ajaxSend\"\n], function( i, type ) {\n\tjQuery.fn[ type ] = function( fn ) {\n\t\treturn this.on( type, fn );\n\t};\n} );\n\n\n\n\njQuery.expr.pseudos.animated = function( elem ) {\n\treturn jQuery.grep( jQuery.timers, function( fn ) {\n\t\treturn elem === fn.elem;\n\t} ).length;\n};\n\n\n\n\njQuery.offset = {\n\tsetOffset: function( elem, options, i ) {\n\t\tvar curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n\t\t\tposition = jQuery.css( elem, \"position\" ),\n\t\t\tcurElem = jQuery( elem ),\n\t\t\tprops = {};\n\n\t\t// Set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tcurOffset = curElem.offset();\n\t\tcurCSSTop = jQuery.css( elem, \"top\" );\n\t\tcurCSSLeft = jQuery.css( elem, \"left\" );\n\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n\t\t\t( curCSSTop + curCSSLeft ).indexOf( \"auto\" ) > -1;\n\n\t\t// Need to be able to calculate position if either\n\t\t// top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( isFunction( options ) ) {\n\n\t\t\t// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)\n\t\t\toptions = options.call( elem, i, jQuery.extend( {}, curOffset ) );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\njQuery.fn.extend( {\n\n\t// offset() relates an element's border box to the document origin\n\toffset: function( options ) {\n\n\t\t// Preserve chaining for setter\n\t\tif ( arguments.length ) {\n\t\t\treturn options === undefined ?\n\t\t\t\tthis :\n\t\t\t\tthis.each( function( i ) {\n\t\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t\t} );\n\t\t}\n\n\t\tvar rect, win,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !elem ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Return zeros for disconnected and hidden (display: none) elements (gh-2310)\n\t\t// Support: IE <=11 only\n\t\t// Running getBoundingClientRect on a\n\t\t// disconnected node in IE throws an error\n\t\tif ( !elem.getClientRects().length ) {\n\t\t\treturn { top: 0, left: 0 };\n\t\t}\n\n\t\t// Get document-relative position by adding viewport scroll to viewport-relative gBCR\n\t\trect = elem.getBoundingClientRect();\n\t\twin = elem.ownerDocument.defaultView;\n\t\treturn {\n\t\t\ttop: rect.top + win.pageYOffset,\n\t\t\tleft: rect.left + win.pageXOffset\n\t\t};\n\t},\n\n\t// position() relates an element's margin box to its offset parent's padding box\n\t// This corresponds to the behavior of CSS absolute positioning\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset, doc,\n\t\t\telem = this[ 0 ],\n\t\t\tparentOffset = { top: 0, left: 0 };\n\n\t\t// position:fixed elements are offset from the viewport, which itself always has zero offset\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\n\t\t\t// Assume position:fixed implies availability of getBoundingClientRect\n\t\t\toffset = elem.getBoundingClientRect();\n\n\t\t} else {\n\t\t\toffset = this.offset();\n\n\t\t\t// Account for the *real* offset parent, which can be the document or its root element\n\t\t\t// when a statically positioned element is identified\n\t\t\tdoc = elem.ownerDocument;\n\t\t\toffsetParent = elem.offsetParent || doc.documentElement;\n\t\t\twhile ( offsetParent &&\n\t\t\t\t( offsetParent === doc.body || offsetParent === doc.documentElement ) &&\n\t\t\t\tjQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\n\t\t\t\toffsetParent = offsetParent.parentNode;\n\t\t\t}\n\t\t\tif ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {\n\n\t\t\t\t// Incorporate borders into its offset, since they are outside its content origin\n\t\t\t\tparentOffset = jQuery( offsetParent ).offset();\n\t\t\t\tparentOffset.top += jQuery.css( offsetParent, \"borderTopWidth\", true );\n\t\t\t\tparentOffset.left += jQuery.css( offsetParent, \"borderLeftWidth\", true );\n\t\t\t}\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\treturn {\n\t\t\ttop: offset.top - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true )\n\t\t};\n\t},\n\n\t// This method will return documentElement in the following cases:\n\t// 1) For the element inside the iframe without offsetParent, this method will return\n\t//    documentElement of the parent window\n\t// 2) For the hidden or detached element\n\t// 3) For body or html element, i.e. in case of the html node - it will return itself\n\t//\n\t// but those exceptions were never presented as a real life use-cases\n\t// and might be considered as more preferable results.\n\t//\n\t// This logic, however, is not guaranteed and can change at any point in the future\n\toffsetParent: function() {\n\t\treturn this.map( function() {\n\t\t\tvar offsetParent = this.offsetParent;\n\n\t\t\twhile ( offsetParent && jQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\n\t\t\treturn offsetParent || documentElement;\n\t\t} );\n\t}\n} );\n\n// Create scrollLeft and scrollTop methods\njQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n\tvar top = \"pageYOffset\" === prop;\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn access( this, function( elem, method, val ) {\n\n\t\t\t// Coalesce documents and windows\n\t\t\tvar win;\n\t\t\tif ( isWindow( elem ) ) {\n\t\t\t\twin = elem;\n\t\t\t} else if ( elem.nodeType === 9 ) {\n\t\t\t\twin = elem.defaultView;\n\t\t\t}\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? win[ prop ] : elem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : win.pageXOffset,\n\t\t\t\t\ttop ? val : win.pageYOffset\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length );\n\t};\n} );\n\n// Support: Safari <=7 - 9.1, Chrome <=37 - 49\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347\n// getComputedStyle returns percent when specified for top/left/bottom/right;\n// rather than make the css module depend on the offset module, just check for it here\njQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n\tjQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n\t\tfunction( elem, computed ) {\n\t\t\tif ( computed ) {\n\t\t\t\tcomputed = curCSS( elem, prop );\n\n\t\t\t\t// If curCSS returns percentage, fallback to offset\n\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\tcomputed;\n\t\t\t}\n\t\t}\n\t);\n} );\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name },\n\t\tfunction( defaultExtra, funcName ) {\n\n\t\t// Margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( isWindow( elem ) ) {\n\n\t\t\t\t\t// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)\n\t\t\t\t\treturn funcName.indexOf( \"outer\" ) === 0 ?\n\t\t\t\t\t\telem[ \"inner\" + name ] :\n\t\t\t\t\t\telem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],\n\t\t\t\t\t// whichever is greatest\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable );\n\t\t};\n\t} );\n} );\n\n\njQuery.each( ( \"blur focus focusin focusout resize scroll click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup contextmenu\" ).split( \" \" ),\n\tfunction( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( data, fn ) {\n\t\treturn arguments.length > 0 ?\n\t\t\tthis.on( name, null, data, fn ) :\n\t\t\tthis.trigger( name );\n\t};\n} );\n\njQuery.fn.extend( {\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t}\n} );\n\n\n\n\njQuery.fn.extend( {\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ?\n\t\t\tthis.off( selector, \"**\" ) :\n\t\t\tthis.off( types, selector || \"**\", fn );\n\t}\n} );\n\n// Bind a function to a context, optionally partially applying any\n// arguments.\n// jQuery.proxy is deprecated to promote standards (specifically Function#bind)\n// However, it is not slated for removal any time soon\njQuery.proxy = function( fn, context ) {\n\tvar tmp, args, proxy;\n\n\tif ( typeof context === \"string\" ) {\n\t\ttmp = fn[ context ];\n\t\tcontext = fn;\n\t\tfn = tmp;\n\t}\n\n\t// Quick check to determine if target is callable, in the spec\n\t// this throws a TypeError, but we will just return undefined.\n\tif ( !isFunction( fn ) ) {\n\t\treturn undefined;\n\t}\n\n\t// Simulated bind\n\targs = slice.call( arguments, 2 );\n\tproxy = function() {\n\t\treturn fn.apply( context || this, args.concat( slice.call( arguments ) ) );\n\t};\n\n\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\tproxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n\treturn proxy;\n};\n\njQuery.holdReady = function( hold ) {\n\tif ( hold ) {\n\t\tjQuery.readyWait++;\n\t} else {\n\t\tjQuery.ready( true );\n\t}\n};\njQuery.isArray = Array.isArray;\njQuery.parseJSON = JSON.parse;\njQuery.nodeName = nodeName;\njQuery.isFunction = isFunction;\njQuery.isWindow = isWindow;\njQuery.camelCase = camelCase;\njQuery.type = toType;\n\njQuery.now = Date.now;\n\njQuery.isNumeric = function( obj ) {\n\n\t// As of jQuery 3.0, isNumeric is limited to\n\t// strings and numbers (primitives or objects)\n\t// that can be coerced to finite numbers (gh-2662)\n\tvar type = jQuery.type( obj );\n\treturn ( type === \"number\" || type === \"string\" ) &&\n\n\t\t// parseFloat NaNs numeric-cast false positives (\"\")\n\t\t// ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n\t\t// subtraction forces infinities to NaN\n\t\t!isNaN( obj - parseFloat( obj ) );\n};\n\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\n\n// Note that for maximum portability, libraries that are not jQuery should\n// declare themselves as anonymous modules, and avoid setting a global if an\n// AMD loader is present. jQuery is a special case. For more information, see\n// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon\n\nif ( typeof define === \"function\" && define.amd ) {\n\tdefine( \"jquery\", [], function() {\n\t\treturn jQuery;\n\t} );\n}\n\n\n\n\nvar\n\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$;\n\njQuery.noConflict = function( deep ) {\n\tif ( window.$ === jQuery ) {\n\t\twindow.$ = _$;\n\t}\n\n\tif ( deep && window.jQuery === jQuery ) {\n\t\twindow.jQuery = _jQuery;\n\t}\n\n\treturn jQuery;\n};\n\n// Expose jQuery and $ identifiers, even in AMD\n// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\nif ( !noGlobal ) {\n\twindow.jQuery = window.$ = jQuery;\n}\n\n\n\n\nreturn jQuery;\n} );\n"
  },
  {
    "path": "static/js/DataTables/pdfmake-0.1.36/pdfmake.js",
    "content": "/*! pdfmake v0.1.36, @license MIT, @link http://pdfmake.org */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse {\n\t\tvar a = factory();\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n\t}\n})(typeof self !== 'undefined' ? self : this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, {\n/******/ \t\t\t\tconfigurable: false,\n/******/ \t\t\t\tenumerable: true,\n/******/ \t\t\t\tget: getter\n/******/ \t\t\t});\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 122);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nfunction isString(variable) {\n\treturn typeof variable === 'string' || variable instanceof String;\n}\n\nfunction isNumber(variable) {\n\treturn typeof variable === 'number' || variable instanceof Number;\n}\n\nfunction isBoolean(variable) {\n\treturn typeof variable === 'boolean';\n}\n\nfunction isArray(variable) {\n\treturn Array.isArray(variable);\n}\n\nfunction isFunction(variable) {\n\treturn typeof variable === 'function';\n}\n\nfunction isObject(variable) {\n\treturn variable !== null && typeof variable === 'object';\n}\n\nfunction isNull(variable) {\n\treturn variable === null;\n}\n\nfunction isUndefined(variable) {\n\treturn variable === undefined;\n}\n\nfunction pack() {\n\tvar result = {};\n\n\tfor (var i = 0, l = arguments.length; i < l; i++) {\n\t\tvar obj = arguments[i];\n\n\t\tif (obj) {\n\t\t\tfor (var key in obj) {\n\t\t\t\tif (obj.hasOwnProperty(key)) {\n\t\t\t\t\tresult[key] = obj[key];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction offsetVector(vector, x, y) {\n\tswitch (vector.type) {\n\t\tcase 'ellipse':\n\t\tcase 'rect':\n\t\t\tvector.x += x;\n\t\t\tvector.y += y;\n\t\t\tbreak;\n\t\tcase 'line':\n\t\t\tvector.x1 += x;\n\t\t\tvector.x2 += x;\n\t\t\tvector.y1 += y;\n\t\t\tvector.y2 += y;\n\t\t\tbreak;\n\t\tcase 'polyline':\n\t\t\tfor (var i = 0, l = vector.points.length; i < l; i++) {\n\t\t\t\tvector.points[i].x += x;\n\t\t\t\tvector.points[i].y += y;\n\t\t\t}\n\t\t\tbreak;\n\t}\n}\n\nfunction fontStringify(key, val) {\n\tif (key === 'font') {\n\t\treturn 'font';\n\t}\n\treturn val;\n}\n\nmodule.exports = {\n\tisString: isString,\n\tisNumber: isNumber,\n\tisBoolean: isBoolean,\n\tisArray: isArray,\n\tisFunction: isFunction,\n\tisObject: isObject,\n\tisNull: isNull,\n\tisUndefined: isUndefined,\n\tpack: pack,\n\tfontStringify: fontStringify,\n\toffsetVector: offsetVector\n};\n\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(global) {/*!\n * The buffer module from node.js, for the browser.\n *\n * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>\n * @license  MIT\n */\n/* eslint-disable no-proto */\n\n\n\nvar base64 = __webpack_require__(124)\nvar ieee754 = __webpack_require__(125)\nvar isArray = __webpack_require__(76)\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n *   === true    Use Uint8Array implementation (fastest)\n *   === false   Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n *   - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n *     See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n *   - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n *   - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n *     incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n  ? global.TYPED_ARRAY_SUPPORT\n  : typedArraySupport()\n\n/*\n * Export kMaxLength after typed array support is determined.\n */\nexports.kMaxLength = kMaxLength()\n\nfunction typedArraySupport () {\n  try {\n    var arr = new Uint8Array(1)\n    arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}\n    return arr.foo() === 42 && // typed array instances can be augmented\n        typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n        arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n  } catch (e) {\n    return false\n  }\n}\n\nfunction kMaxLength () {\n  return Buffer.TYPED_ARRAY_SUPPORT\n    ? 0x7fffffff\n    : 0x3fffffff\n}\n\nfunction createBuffer (that, length) {\n  if (kMaxLength() < length) {\n    throw new RangeError('Invalid typed array length')\n  }\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    // Return an augmented `Uint8Array` instance, for best performance\n    that = new Uint8Array(length)\n    that.__proto__ = Buffer.prototype\n  } else {\n    // Fallback: Return an object instance of the Buffer class\n    if (that === null) {\n      that = new Buffer(length)\n    }\n    that.length = length\n  }\n\n  return that\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\n\nfunction Buffer (arg, encodingOrOffset, length) {\n  if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {\n    return new Buffer(arg, encodingOrOffset, length)\n  }\n\n  // Common case.\n  if (typeof arg === 'number') {\n    if (typeof encodingOrOffset === 'string') {\n      throw new Error(\n        'If encoding is specified then the first argument must be a string'\n      )\n    }\n    return allocUnsafe(this, arg)\n  }\n  return from(this, arg, encodingOrOffset, length)\n}\n\nBuffer.poolSize = 8192 // not used by this implementation\n\n// TODO: Legacy, not needed anymore. Remove in next major version.\nBuffer._augment = function (arr) {\n  arr.__proto__ = Buffer.prototype\n  return arr\n}\n\nfunction from (that, value, encodingOrOffset, length) {\n  if (typeof value === 'number') {\n    throw new TypeError('\"value\" argument must not be a number')\n  }\n\n  if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n    return fromArrayBuffer(that, value, encodingOrOffset, length)\n  }\n\n  if (typeof value === 'string') {\n    return fromString(that, value, encodingOrOffset)\n  }\n\n  return fromObject(that, value)\n}\n\n/**\n * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n * if value is a number.\n * Buffer.from(str[, encoding])\n * Buffer.from(array)\n * Buffer.from(buffer)\n * Buffer.from(arrayBuffer[, byteOffset[, length]])\n **/\nBuffer.from = function (value, encodingOrOffset, length) {\n  return from(null, value, encodingOrOffset, length)\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n  Buffer.prototype.__proto__ = Uint8Array.prototype\n  Buffer.__proto__ = Uint8Array\n  if (typeof Symbol !== 'undefined' && Symbol.species &&\n      Buffer[Symbol.species] === Buffer) {\n    // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97\n    Object.defineProperty(Buffer, Symbol.species, {\n      value: null,\n      configurable: true\n    })\n  }\n}\n\nfunction assertSize (size) {\n  if (typeof size !== 'number') {\n    throw new TypeError('\"size\" argument must be a number')\n  } else if (size < 0) {\n    throw new RangeError('\"size\" argument must not be negative')\n  }\n}\n\nfunction alloc (that, size, fill, encoding) {\n  assertSize(size)\n  if (size <= 0) {\n    return createBuffer(that, size)\n  }\n  if (fill !== undefined) {\n    // Only pay attention to encoding if it's a string. This\n    // prevents accidentally sending in a number that would\n    // be interpretted as a start offset.\n    return typeof encoding === 'string'\n      ? createBuffer(that, size).fill(fill, encoding)\n      : createBuffer(that, size).fill(fill)\n  }\n  return createBuffer(that, size)\n}\n\n/**\n * Creates a new filled Buffer instance.\n * alloc(size[, fill[, encoding]])\n **/\nBuffer.alloc = function (size, fill, encoding) {\n  return alloc(null, size, fill, encoding)\n}\n\nfunction allocUnsafe (that, size) {\n  assertSize(size)\n  that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)\n  if (!Buffer.TYPED_ARRAY_SUPPORT) {\n    for (var i = 0; i < size; ++i) {\n      that[i] = 0\n    }\n  }\n  return that\n}\n\n/**\n * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n * */\nBuffer.allocUnsafe = function (size) {\n  return allocUnsafe(null, size)\n}\n/**\n * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n */\nBuffer.allocUnsafeSlow = function (size) {\n  return allocUnsafe(null, size)\n}\n\nfunction fromString (that, string, encoding) {\n  if (typeof encoding !== 'string' || encoding === '') {\n    encoding = 'utf8'\n  }\n\n  if (!Buffer.isEncoding(encoding)) {\n    throw new TypeError('\"encoding\" must be a valid string encoding')\n  }\n\n  var length = byteLength(string, encoding) | 0\n  that = createBuffer(that, length)\n\n  var actual = that.write(string, encoding)\n\n  if (actual !== length) {\n    // Writing a hex string, for example, that contains invalid characters will\n    // cause everything after the first invalid character to be ignored. (e.g.\n    // 'abxxcd' will be treated as 'ab')\n    that = that.slice(0, actual)\n  }\n\n  return that\n}\n\nfunction fromArrayLike (that, array) {\n  var length = array.length < 0 ? 0 : checked(array.length) | 0\n  that = createBuffer(that, length)\n  for (var i = 0; i < length; i += 1) {\n    that[i] = array[i] & 255\n  }\n  return that\n}\n\nfunction fromArrayBuffer (that, array, byteOffset, length) {\n  array.byteLength // this throws if `array` is not a valid ArrayBuffer\n\n  if (byteOffset < 0 || array.byteLength < byteOffset) {\n    throw new RangeError('\\'offset\\' is out of bounds')\n  }\n\n  if (array.byteLength < byteOffset + (length || 0)) {\n    throw new RangeError('\\'length\\' is out of bounds')\n  }\n\n  if (byteOffset === undefined && length === undefined) {\n    array = new Uint8Array(array)\n  } else if (length === undefined) {\n    array = new Uint8Array(array, byteOffset)\n  } else {\n    array = new Uint8Array(array, byteOffset, length)\n  }\n\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    // Return an augmented `Uint8Array` instance, for best performance\n    that = array\n    that.__proto__ = Buffer.prototype\n  } else {\n    // Fallback: Return an object instance of the Buffer class\n    that = fromArrayLike(that, array)\n  }\n  return that\n}\n\nfunction fromObject (that, obj) {\n  if (Buffer.isBuffer(obj)) {\n    var len = checked(obj.length) | 0\n    that = createBuffer(that, len)\n\n    if (that.length === 0) {\n      return that\n    }\n\n    obj.copy(that, 0, 0, len)\n    return that\n  }\n\n  if (obj) {\n    if ((typeof ArrayBuffer !== 'undefined' &&\n        obj.buffer instanceof ArrayBuffer) || 'length' in obj) {\n      if (typeof obj.length !== 'number' || isnan(obj.length)) {\n        return createBuffer(that, 0)\n      }\n      return fromArrayLike(that, obj)\n    }\n\n    if (obj.type === 'Buffer' && isArray(obj.data)) {\n      return fromArrayLike(that, obj.data)\n    }\n  }\n\n  throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')\n}\n\nfunction checked (length) {\n  // Note: cannot use `length < kMaxLength()` here because that fails when\n  // length is NaN (which is otherwise coerced to zero.)\n  if (length >= kMaxLength()) {\n    throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n                         'size: 0x' + kMaxLength().toString(16) + ' bytes')\n  }\n  return length | 0\n}\n\nfunction SlowBuffer (length) {\n  if (+length != length) { // eslint-disable-line eqeqeq\n    length = 0\n  }\n  return Buffer.alloc(+length)\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n  return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n  if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n    throw new TypeError('Arguments must be Buffers')\n  }\n\n  if (a === b) return 0\n\n  var x = a.length\n  var y = b.length\n\n  for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n    if (a[i] !== b[i]) {\n      x = a[i]\n      y = b[i]\n      break\n    }\n  }\n\n  if (x < y) return -1\n  if (y < x) return 1\n  return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n  switch (String(encoding).toLowerCase()) {\n    case 'hex':\n    case 'utf8':\n    case 'utf-8':\n    case 'ascii':\n    case 'latin1':\n    case 'binary':\n    case 'base64':\n    case 'ucs2':\n    case 'ucs-2':\n    case 'utf16le':\n    case 'utf-16le':\n      return true\n    default:\n      return false\n  }\n}\n\nBuffer.concat = function concat (list, length) {\n  if (!isArray(list)) {\n    throw new TypeError('\"list\" argument must be an Array of Buffers')\n  }\n\n  if (list.length === 0) {\n    return Buffer.alloc(0)\n  }\n\n  var i\n  if (length === undefined) {\n    length = 0\n    for (i = 0; i < list.length; ++i) {\n      length += list[i].length\n    }\n  }\n\n  var buffer = Buffer.allocUnsafe(length)\n  var pos = 0\n  for (i = 0; i < list.length; ++i) {\n    var buf = list[i]\n    if (!Buffer.isBuffer(buf)) {\n      throw new TypeError('\"list\" argument must be an Array of Buffers')\n    }\n    buf.copy(buffer, pos)\n    pos += buf.length\n  }\n  return buffer\n}\n\nfunction byteLength (string, encoding) {\n  if (Buffer.isBuffer(string)) {\n    return string.length\n  }\n  if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&\n      (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n    return string.byteLength\n  }\n  if (typeof string !== 'string') {\n    string = '' + string\n  }\n\n  var len = string.length\n  if (len === 0) return 0\n\n  // Use a for loop to avoid recursion\n  var loweredCase = false\n  for (;;) {\n    switch (encoding) {\n      case 'ascii':\n      case 'latin1':\n      case 'binary':\n        return len\n      case 'utf8':\n      case 'utf-8':\n      case undefined:\n        return utf8ToBytes(string).length\n      case 'ucs2':\n      case 'ucs-2':\n      case 'utf16le':\n      case 'utf-16le':\n        return len * 2\n      case 'hex':\n        return len >>> 1\n      case 'base64':\n        return base64ToBytes(string).length\n      default:\n        if (loweredCase) return utf8ToBytes(string).length // assume utf8\n        encoding = ('' + encoding).toLowerCase()\n        loweredCase = true\n    }\n  }\n}\nBuffer.byteLength = byteLength\n\nfunction slowToString (encoding, start, end) {\n  var loweredCase = false\n\n  // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n  // property of a typed array.\n\n  // This behaves neither like String nor Uint8Array in that we set start/end\n  // to their upper/lower bounds if the value passed is out of range.\n  // undefined is handled specially as per ECMA-262 6th Edition,\n  // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n  if (start === undefined || start < 0) {\n    start = 0\n  }\n  // Return early if start > this.length. Done here to prevent potential uint32\n  // coercion fail below.\n  if (start > this.length) {\n    return ''\n  }\n\n  if (end === undefined || end > this.length) {\n    end = this.length\n  }\n\n  if (end <= 0) {\n    return ''\n  }\n\n  // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n  end >>>= 0\n  start >>>= 0\n\n  if (end <= start) {\n    return ''\n  }\n\n  if (!encoding) encoding = 'utf8'\n\n  while (true) {\n    switch (encoding) {\n      case 'hex':\n        return hexSlice(this, start, end)\n\n      case 'utf8':\n      case 'utf-8':\n        return utf8Slice(this, start, end)\n\n      case 'ascii':\n        return asciiSlice(this, start, end)\n\n      case 'latin1':\n      case 'binary':\n        return latin1Slice(this, start, end)\n\n      case 'base64':\n        return base64Slice(this, start, end)\n\n      case 'ucs2':\n      case 'ucs-2':\n      case 'utf16le':\n      case 'utf-16le':\n        return utf16leSlice(this, start, end)\n\n      default:\n        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n        encoding = (encoding + '').toLowerCase()\n        loweredCase = true\n    }\n  }\n}\n\n// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n// Buffer instances.\nBuffer.prototype._isBuffer = true\n\nfunction swap (b, n, m) {\n  var i = b[n]\n  b[n] = b[m]\n  b[m] = i\n}\n\nBuffer.prototype.swap16 = function swap16 () {\n  var len = this.length\n  if (len % 2 !== 0) {\n    throw new RangeError('Buffer size must be a multiple of 16-bits')\n  }\n  for (var i = 0; i < len; i += 2) {\n    swap(this, i, i + 1)\n  }\n  return this\n}\n\nBuffer.prototype.swap32 = function swap32 () {\n  var len = this.length\n  if (len % 4 !== 0) {\n    throw new RangeError('Buffer size must be a multiple of 32-bits')\n  }\n  for (var i = 0; i < len; i += 4) {\n    swap(this, i, i + 3)\n    swap(this, i + 1, i + 2)\n  }\n  return this\n}\n\nBuffer.prototype.swap64 = function swap64 () {\n  var len = this.length\n  if (len % 8 !== 0) {\n    throw new RangeError('Buffer size must be a multiple of 64-bits')\n  }\n  for (var i = 0; i < len; i += 8) {\n    swap(this, i, i + 7)\n    swap(this, i + 1, i + 6)\n    swap(this, i + 2, i + 5)\n    swap(this, i + 3, i + 4)\n  }\n  return this\n}\n\nBuffer.prototype.toString = function toString () {\n  var length = this.length | 0\n  if (length === 0) return ''\n  if (arguments.length === 0) return utf8Slice(this, 0, length)\n  return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n  if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n  if (this === b) return true\n  return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n  var str = ''\n  var max = exports.INSPECT_MAX_BYTES\n  if (this.length > 0) {\n    str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n    if (this.length > max) str += ' ... '\n  }\n  return '<Buffer ' + str + '>'\n}\n\nBuffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {\n  if (!Buffer.isBuffer(target)) {\n    throw new TypeError('Argument must be a Buffer')\n  }\n\n  if (start === undefined) {\n    start = 0\n  }\n  if (end === undefined) {\n    end = target ? target.length : 0\n  }\n  if (thisStart === undefined) {\n    thisStart = 0\n  }\n  if (thisEnd === undefined) {\n    thisEnd = this.length\n  }\n\n  if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n    throw new RangeError('out of range index')\n  }\n\n  if (thisStart >= thisEnd && start >= end) {\n    return 0\n  }\n  if (thisStart >= thisEnd) {\n    return -1\n  }\n  if (start >= end) {\n    return 1\n  }\n\n  start >>>= 0\n  end >>>= 0\n  thisStart >>>= 0\n  thisEnd >>>= 0\n\n  if (this === target) return 0\n\n  var x = thisEnd - thisStart\n  var y = end - start\n  var len = Math.min(x, y)\n\n  var thisCopy = this.slice(thisStart, thisEnd)\n  var targetCopy = target.slice(start, end)\n\n  for (var i = 0; i < len; ++i) {\n    if (thisCopy[i] !== targetCopy[i]) {\n      x = thisCopy[i]\n      y = targetCopy[i]\n      break\n    }\n  }\n\n  if (x < y) return -1\n  if (y < x) return 1\n  return 0\n}\n\n// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,\n// OR the last index of `val` in `buffer` at offset <= `byteOffset`.\n//\n// Arguments:\n// - buffer - a Buffer to search\n// - val - a string, Buffer, or number\n// - byteOffset - an index into `buffer`; will be clamped to an int32\n// - encoding - an optional encoding, relevant is val is a string\n// - dir - true for indexOf, false for lastIndexOf\nfunction bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {\n  // Empty buffer means no match\n  if (buffer.length === 0) return -1\n\n  // Normalize byteOffset\n  if (typeof byteOffset === 'string') {\n    encoding = byteOffset\n    byteOffset = 0\n  } else if (byteOffset > 0x7fffffff) {\n    byteOffset = 0x7fffffff\n  } else if (byteOffset < -0x80000000) {\n    byteOffset = -0x80000000\n  }\n  byteOffset = +byteOffset  // Coerce to Number.\n  if (isNaN(byteOffset)) {\n    // byteOffset: it it's undefined, null, NaN, \"foo\", etc, search whole buffer\n    byteOffset = dir ? 0 : (buffer.length - 1)\n  }\n\n  // Normalize byteOffset: negative offsets start from the end of the buffer\n  if (byteOffset < 0) byteOffset = buffer.length + byteOffset\n  if (byteOffset >= buffer.length) {\n    if (dir) return -1\n    else byteOffset = buffer.length - 1\n  } else if (byteOffset < 0) {\n    if (dir) byteOffset = 0\n    else return -1\n  }\n\n  // Normalize val\n  if (typeof val === 'string') {\n    val = Buffer.from(val, encoding)\n  }\n\n  // Finally, search either indexOf (if dir is true) or lastIndexOf\n  if (Buffer.isBuffer(val)) {\n    // Special case: looking for empty string/buffer always fails\n    if (val.length === 0) {\n      return -1\n    }\n    return arrayIndexOf(buffer, val, byteOffset, encoding, dir)\n  } else if (typeof val === 'number') {\n    val = val & 0xFF // Search for a byte value [0-255]\n    if (Buffer.TYPED_ARRAY_SUPPORT &&\n        typeof Uint8Array.prototype.indexOf === 'function') {\n      if (dir) {\n        return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)\n      } else {\n        return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)\n      }\n    }\n    return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)\n  }\n\n  throw new TypeError('val must be string, number or Buffer')\n}\n\nfunction arrayIndexOf (arr, val, byteOffset, encoding, dir) {\n  var indexSize = 1\n  var arrLength = arr.length\n  var valLength = val.length\n\n  if (encoding !== undefined) {\n    encoding = String(encoding).toLowerCase()\n    if (encoding === 'ucs2' || encoding === 'ucs-2' ||\n        encoding === 'utf16le' || encoding === 'utf-16le') {\n      if (arr.length < 2 || val.length < 2) {\n        return -1\n      }\n      indexSize = 2\n      arrLength /= 2\n      valLength /= 2\n      byteOffset /= 2\n    }\n  }\n\n  function read (buf, i) {\n    if (indexSize === 1) {\n      return buf[i]\n    } else {\n      return buf.readUInt16BE(i * indexSize)\n    }\n  }\n\n  var i\n  if (dir) {\n    var foundIndex = -1\n    for (i = byteOffset; i < arrLength; i++) {\n      if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n        if (foundIndex === -1) foundIndex = i\n        if (i - foundIndex + 1 === valLength) return foundIndex * indexSize\n      } else {\n        if (foundIndex !== -1) i -= i - foundIndex\n        foundIndex = -1\n      }\n    }\n  } else {\n    if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength\n    for (i = byteOffset; i >= 0; i--) {\n      var found = true\n      for (var j = 0; j < valLength; j++) {\n        if (read(arr, i + j) !== read(val, j)) {\n          found = false\n          break\n        }\n      }\n      if (found) return i\n    }\n  }\n\n  return -1\n}\n\nBuffer.prototype.includes = function includes (val, byteOffset, encoding) {\n  return this.indexOf(val, byteOffset, encoding) !== -1\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {\n  return bidirectionalIndexOf(this, val, byteOffset, encoding, true)\n}\n\nBuffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {\n  return bidirectionalIndexOf(this, val, byteOffset, encoding, false)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n  offset = Number(offset) || 0\n  var remaining = buf.length - offset\n  if (!length) {\n    length = remaining\n  } else {\n    length = Number(length)\n    if (length > remaining) {\n      length = remaining\n    }\n  }\n\n  // must be an even number of digits\n  var strLen = string.length\n  if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')\n\n  if (length > strLen / 2) {\n    length = strLen / 2\n  }\n  for (var i = 0; i < length; ++i) {\n    var parsed = parseInt(string.substr(i * 2, 2), 16)\n    if (isNaN(parsed)) return i\n    buf[offset + i] = parsed\n  }\n  return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n  return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n  return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction latin1Write (buf, string, offset, length) {\n  return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n  return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n  return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n  // Buffer#write(string)\n  if (offset === undefined) {\n    encoding = 'utf8'\n    length = this.length\n    offset = 0\n  // Buffer#write(string, encoding)\n  } else if (length === undefined && typeof offset === 'string') {\n    encoding = offset\n    length = this.length\n    offset = 0\n  // Buffer#write(string, offset[, length][, encoding])\n  } else if (isFinite(offset)) {\n    offset = offset | 0\n    if (isFinite(length)) {\n      length = length | 0\n      if (encoding === undefined) encoding = 'utf8'\n    } else {\n      encoding = length\n      length = undefined\n    }\n  // legacy write(string, encoding, offset, length) - remove in v0.13\n  } else {\n    throw new Error(\n      'Buffer.write(string, encoding, offset[, length]) is no longer supported'\n    )\n  }\n\n  var remaining = this.length - offset\n  if (length === undefined || length > remaining) length = remaining\n\n  if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n    throw new RangeError('Attempt to write outside buffer bounds')\n  }\n\n  if (!encoding) encoding = 'utf8'\n\n  var loweredCase = false\n  for (;;) {\n    switch (encoding) {\n      case 'hex':\n        return hexWrite(this, string, offset, length)\n\n      case 'utf8':\n      case 'utf-8':\n        return utf8Write(this, string, offset, length)\n\n      case 'ascii':\n        return asciiWrite(this, string, offset, length)\n\n      case 'latin1':\n      case 'binary':\n        return latin1Write(this, string, offset, length)\n\n      case 'base64':\n        // Warning: maxLength not taken into account in base64Write\n        return base64Write(this, string, offset, length)\n\n      case 'ucs2':\n      case 'ucs-2':\n      case 'utf16le':\n      case 'utf-16le':\n        return ucs2Write(this, string, offset, length)\n\n      default:\n        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n        encoding = ('' + encoding).toLowerCase()\n        loweredCase = true\n    }\n  }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n  return {\n    type: 'Buffer',\n    data: Array.prototype.slice.call(this._arr || this, 0)\n  }\n}\n\nfunction base64Slice (buf, start, end) {\n  if (start === 0 && end === buf.length) {\n    return base64.fromByteArray(buf)\n  } else {\n    return base64.fromByteArray(buf.slice(start, end))\n  }\n}\n\nfunction utf8Slice (buf, start, end) {\n  end = Math.min(buf.length, end)\n  var res = []\n\n  var i = start\n  while (i < end) {\n    var firstByte = buf[i]\n    var codePoint = null\n    var bytesPerSequence = (firstByte > 0xEF) ? 4\n      : (firstByte > 0xDF) ? 3\n      : (firstByte > 0xBF) ? 2\n      : 1\n\n    if (i + bytesPerSequence <= end) {\n      var secondByte, thirdByte, fourthByte, tempCodePoint\n\n      switch (bytesPerSequence) {\n        case 1:\n          if (firstByte < 0x80) {\n            codePoint = firstByte\n          }\n          break\n        case 2:\n          secondByte = buf[i + 1]\n          if ((secondByte & 0xC0) === 0x80) {\n            tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n            if (tempCodePoint > 0x7F) {\n              codePoint = tempCodePoint\n            }\n          }\n          break\n        case 3:\n          secondByte = buf[i + 1]\n          thirdByte = buf[i + 2]\n          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n            tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n            if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n              codePoint = tempCodePoint\n            }\n          }\n          break\n        case 4:\n          secondByte = buf[i + 1]\n          thirdByte = buf[i + 2]\n          fourthByte = buf[i + 3]\n          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n            tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n            if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n              codePoint = tempCodePoint\n            }\n          }\n      }\n    }\n\n    if (codePoint === null) {\n      // we did not generate a valid codePoint so insert a\n      // replacement char (U+FFFD) and advance only 1 byte\n      codePoint = 0xFFFD\n      bytesPerSequence = 1\n    } else if (codePoint > 0xFFFF) {\n      // encode to utf16 (surrogate pair dance)\n      codePoint -= 0x10000\n      res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n      codePoint = 0xDC00 | codePoint & 0x3FF\n    }\n\n    res.push(codePoint)\n    i += bytesPerSequence\n  }\n\n  return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n  var len = codePoints.length\n  if (len <= MAX_ARGUMENTS_LENGTH) {\n    return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n  }\n\n  // Decode in chunks to avoid \"call stack size exceeded\".\n  var res = ''\n  var i = 0\n  while (i < len) {\n    res += String.fromCharCode.apply(\n      String,\n      codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n    )\n  }\n  return res\n}\n\nfunction asciiSlice (buf, start, end) {\n  var ret = ''\n  end = Math.min(buf.length, end)\n\n  for (var i = start; i < end; ++i) {\n    ret += String.fromCharCode(buf[i] & 0x7F)\n  }\n  return ret\n}\n\nfunction latin1Slice (buf, start, end) {\n  var ret = ''\n  end = Math.min(buf.length, end)\n\n  for (var i = start; i < end; ++i) {\n    ret += String.fromCharCode(buf[i])\n  }\n  return ret\n}\n\nfunction hexSlice (buf, start, end) {\n  var len = buf.length\n\n  if (!start || start < 0) start = 0\n  if (!end || end < 0 || end > len) end = len\n\n  var out = ''\n  for (var i = start; i < end; ++i) {\n    out += toHex(buf[i])\n  }\n  return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n  var bytes = buf.slice(start, end)\n  var res = ''\n  for (var i = 0; i < bytes.length; i += 2) {\n    res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n  }\n  return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n  var len = this.length\n  start = ~~start\n  end = end === undefined ? len : ~~end\n\n  if (start < 0) {\n    start += len\n    if (start < 0) start = 0\n  } else if (start > len) {\n    start = len\n  }\n\n  if (end < 0) {\n    end += len\n    if (end < 0) end = 0\n  } else if (end > len) {\n    end = len\n  }\n\n  if (end < start) end = start\n\n  var newBuf\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    newBuf = this.subarray(start, end)\n    newBuf.__proto__ = Buffer.prototype\n  } else {\n    var sliceLen = end - start\n    newBuf = new Buffer(sliceLen, undefined)\n    for (var i = 0; i < sliceLen; ++i) {\n      newBuf[i] = this[i + start]\n    }\n  }\n\n  return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n  if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n  if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n  var val = this[offset]\n  var mul = 1\n  var i = 0\n  while (++i < byteLength && (mul *= 0x100)) {\n    val += this[offset + i] * mul\n  }\n\n  return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) {\n    checkOffset(offset, byteLength, this.length)\n  }\n\n  var val = this[offset + --byteLength]\n  var mul = 1\n  while (byteLength > 0 && (mul *= 0x100)) {\n    val += this[offset + --byteLength] * mul\n  }\n\n  return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 1, this.length)\n  return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return ((this[offset]) |\n      (this[offset + 1] << 8) |\n      (this[offset + 2] << 16)) +\n      (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return (this[offset] * 0x1000000) +\n    ((this[offset + 1] << 16) |\n    (this[offset + 2] << 8) |\n    this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n  var val = this[offset]\n  var mul = 1\n  var i = 0\n  while (++i < byteLength && (mul *= 0x100)) {\n    val += this[offset + i] * mul\n  }\n  mul *= 0x80\n\n  if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n  return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n  var i = byteLength\n  var mul = 1\n  var val = this[offset + --i]\n  while (i > 0 && (mul *= 0x100)) {\n    val += this[offset + --i] * mul\n  }\n  mul *= 0x80\n\n  if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n  return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 1, this.length)\n  if (!(this[offset] & 0x80)) return (this[offset])\n  return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  var val = this[offset] | (this[offset + 1] << 8)\n  return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  var val = this[offset + 1] | (this[offset] << 8)\n  return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return (this[offset]) |\n    (this[offset + 1] << 8) |\n    (this[offset + 2] << 16) |\n    (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return (this[offset] << 24) |\n    (this[offset + 1] << 16) |\n    (this[offset + 2] << 8) |\n    (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n  return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n  return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 8, this.length)\n  return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 8, this.length)\n  return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n  if (!Buffer.isBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance')\n  if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds')\n  if (offset + ext > buf.length) throw new RangeError('Index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) {\n    var maxBytes = Math.pow(2, 8 * byteLength) - 1\n    checkInt(this, value, offset, byteLength, maxBytes, 0)\n  }\n\n  var mul = 1\n  var i = 0\n  this[offset] = value & 0xFF\n  while (++i < byteLength && (mul *= 0x100)) {\n    this[offset + i] = (value / mul) & 0xFF\n  }\n\n  return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) {\n    var maxBytes = Math.pow(2, 8 * byteLength) - 1\n    checkInt(this, value, offset, byteLength, maxBytes, 0)\n  }\n\n  var i = byteLength - 1\n  var mul = 1\n  this[offset + i] = value & 0xFF\n  while (--i >= 0 && (mul *= 0x100)) {\n    this[offset + i] = (value / mul) & 0xFF\n  }\n\n  return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n  this[offset] = (value & 0xff)\n  return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n  if (value < 0) value = 0xffff + value + 1\n  for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n    buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n      (littleEndian ? i : 1 - i) * 8\n  }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value & 0xff)\n    this[offset + 1] = (value >>> 8)\n  } else {\n    objectWriteUInt16(this, value, offset, true)\n  }\n  return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 8)\n    this[offset + 1] = (value & 0xff)\n  } else {\n    objectWriteUInt16(this, value, offset, false)\n  }\n  return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n  if (value < 0) value = 0xffffffff + value + 1\n  for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n    buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n  }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset + 3] = (value >>> 24)\n    this[offset + 2] = (value >>> 16)\n    this[offset + 1] = (value >>> 8)\n    this[offset] = (value & 0xff)\n  } else {\n    objectWriteUInt32(this, value, offset, true)\n  }\n  return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 24)\n    this[offset + 1] = (value >>> 16)\n    this[offset + 2] = (value >>> 8)\n    this[offset + 3] = (value & 0xff)\n  } else {\n    objectWriteUInt32(this, value, offset, false)\n  }\n  return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) {\n    var limit = Math.pow(2, 8 * byteLength - 1)\n\n    checkInt(this, value, offset, byteLength, limit - 1, -limit)\n  }\n\n  var i = 0\n  var mul = 1\n  var sub = 0\n  this[offset] = value & 0xFF\n  while (++i < byteLength && (mul *= 0x100)) {\n    if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n      sub = 1\n    }\n    this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n  }\n\n  return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) {\n    var limit = Math.pow(2, 8 * byteLength - 1)\n\n    checkInt(this, value, offset, byteLength, limit - 1, -limit)\n  }\n\n  var i = byteLength - 1\n  var mul = 1\n  var sub = 0\n  this[offset + i] = value & 0xFF\n  while (--i >= 0 && (mul *= 0x100)) {\n    if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n      sub = 1\n    }\n    this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n  }\n\n  return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n  if (value < 0) value = 0xff + value + 1\n  this[offset] = (value & 0xff)\n  return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value & 0xff)\n    this[offset + 1] = (value >>> 8)\n  } else {\n    objectWriteUInt16(this, value, offset, true)\n  }\n  return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 8)\n    this[offset + 1] = (value & 0xff)\n  } else {\n    objectWriteUInt16(this, value, offset, false)\n  }\n  return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value & 0xff)\n    this[offset + 1] = (value >>> 8)\n    this[offset + 2] = (value >>> 16)\n    this[offset + 3] = (value >>> 24)\n  } else {\n    objectWriteUInt32(this, value, offset, true)\n  }\n  return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n  if (value < 0) value = 0xffffffff + value + 1\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 24)\n    this[offset + 1] = (value >>> 16)\n    this[offset + 2] = (value >>> 8)\n    this[offset + 3] = (value & 0xff)\n  } else {\n    objectWriteUInt32(this, value, offset, false)\n  }\n  return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n  if (offset + ext > buf.length) throw new RangeError('Index out of range')\n  if (offset < 0) throw new RangeError('Index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n  if (!noAssert) {\n    checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n  }\n  ieee754.write(buf, value, offset, littleEndian, 23, 4)\n  return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n  return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n  return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n  if (!noAssert) {\n    checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n  }\n  ieee754.write(buf, value, offset, littleEndian, 52, 8)\n  return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n  return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n  return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n  if (!start) start = 0\n  if (!end && end !== 0) end = this.length\n  if (targetStart >= target.length) targetStart = target.length\n  if (!targetStart) targetStart = 0\n  if (end > 0 && end < start) end = start\n\n  // Copy 0 bytes; we're done\n  if (end === start) return 0\n  if (target.length === 0 || this.length === 0) return 0\n\n  // Fatal error conditions\n  if (targetStart < 0) {\n    throw new RangeError('targetStart out of bounds')\n  }\n  if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n  if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n  // Are we oob?\n  if (end > this.length) end = this.length\n  if (target.length - targetStart < end - start) {\n    end = target.length - targetStart + start\n  }\n\n  var len = end - start\n  var i\n\n  if (this === target && start < targetStart && targetStart < end) {\n    // descending copy from end\n    for (i = len - 1; i >= 0; --i) {\n      target[i + targetStart] = this[i + start]\n    }\n  } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n    // ascending copy from start\n    for (i = 0; i < len; ++i) {\n      target[i + targetStart] = this[i + start]\n    }\n  } else {\n    Uint8Array.prototype.set.call(\n      target,\n      this.subarray(start, start + len),\n      targetStart\n    )\n  }\n\n  return len\n}\n\n// Usage:\n//    buffer.fill(number[, offset[, end]])\n//    buffer.fill(buffer[, offset[, end]])\n//    buffer.fill(string[, offset[, end]][, encoding])\nBuffer.prototype.fill = function fill (val, start, end, encoding) {\n  // Handle string cases:\n  if (typeof val === 'string') {\n    if (typeof start === 'string') {\n      encoding = start\n      start = 0\n      end = this.length\n    } else if (typeof end === 'string') {\n      encoding = end\n      end = this.length\n    }\n    if (val.length === 1) {\n      var code = val.charCodeAt(0)\n      if (code < 256) {\n        val = code\n      }\n    }\n    if (encoding !== undefined && typeof encoding !== 'string') {\n      throw new TypeError('encoding must be a string')\n    }\n    if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n      throw new TypeError('Unknown encoding: ' + encoding)\n    }\n  } else if (typeof val === 'number') {\n    val = val & 255\n  }\n\n  // Invalid ranges are not set to a default, so can range check early.\n  if (start < 0 || this.length < start || this.length < end) {\n    throw new RangeError('Out of range index')\n  }\n\n  if (end <= start) {\n    return this\n  }\n\n  start = start >>> 0\n  end = end === undefined ? this.length : end >>> 0\n\n  if (!val) val = 0\n\n  var i\n  if (typeof val === 'number') {\n    for (i = start; i < end; ++i) {\n      this[i] = val\n    }\n  } else {\n    var bytes = Buffer.isBuffer(val)\n      ? val\n      : utf8ToBytes(new Buffer(val, encoding).toString())\n    var len = bytes.length\n    for (i = 0; i < end - start; ++i) {\n      this[i + start] = bytes[i % len]\n    }\n  }\n\n  return this\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n  // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n  str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n  // Node converts strings with length < 2 to ''\n  if (str.length < 2) return ''\n  // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n  while (str.length % 4 !== 0) {\n    str = str + '='\n  }\n  return str\n}\n\nfunction stringtrim (str) {\n  if (str.trim) return str.trim()\n  return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n  if (n < 16) return '0' + n.toString(16)\n  return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n  units = units || Infinity\n  var codePoint\n  var length = string.length\n  var leadSurrogate = null\n  var bytes = []\n\n  for (var i = 0; i < length; ++i) {\n    codePoint = string.charCodeAt(i)\n\n    // is surrogate component\n    if (codePoint > 0xD7FF && codePoint < 0xE000) {\n      // last char was a lead\n      if (!leadSurrogate) {\n        // no lead yet\n        if (codePoint > 0xDBFF) {\n          // unexpected trail\n          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n          continue\n        } else if (i + 1 === length) {\n          // unpaired lead\n          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n          continue\n        }\n\n        // valid lead\n        leadSurrogate = codePoint\n\n        continue\n      }\n\n      // 2 leads in a row\n      if (codePoint < 0xDC00) {\n        if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n        leadSurrogate = codePoint\n        continue\n      }\n\n      // valid surrogate pair\n      codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n    } else if (leadSurrogate) {\n      // valid bmp char, but last char was a lead\n      if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n    }\n\n    leadSurrogate = null\n\n    // encode utf8\n    if (codePoint < 0x80) {\n      if ((units -= 1) < 0) break\n      bytes.push(codePoint)\n    } else if (codePoint < 0x800) {\n      if ((units -= 2) < 0) break\n      bytes.push(\n        codePoint >> 0x6 | 0xC0,\n        codePoint & 0x3F | 0x80\n      )\n    } else if (codePoint < 0x10000) {\n      if ((units -= 3) < 0) break\n      bytes.push(\n        codePoint >> 0xC | 0xE0,\n        codePoint >> 0x6 & 0x3F | 0x80,\n        codePoint & 0x3F | 0x80\n      )\n    } else if (codePoint < 0x110000) {\n      if ((units -= 4) < 0) break\n      bytes.push(\n        codePoint >> 0x12 | 0xF0,\n        codePoint >> 0xC & 0x3F | 0x80,\n        codePoint >> 0x6 & 0x3F | 0x80,\n        codePoint & 0x3F | 0x80\n      )\n    } else {\n      throw new Error('Invalid code point')\n    }\n  }\n\n  return bytes\n}\n\nfunction asciiToBytes (str) {\n  var byteArray = []\n  for (var i = 0; i < str.length; ++i) {\n    // Node's code seems to be doing this and not & 0x7F..\n    byteArray.push(str.charCodeAt(i) & 0xFF)\n  }\n  return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n  var c, hi, lo\n  var byteArray = []\n  for (var i = 0; i < str.length; ++i) {\n    if ((units -= 2) < 0) break\n\n    c = str.charCodeAt(i)\n    hi = c >> 8\n    lo = c % 256\n    byteArray.push(lo)\n    byteArray.push(hi)\n  }\n\n  return byteArray\n}\n\nfunction base64ToBytes (str) {\n  return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n  for (var i = 0; i < length; ++i) {\n    if ((i + offset >= dst.length) || (i >= src.length)) break\n    dst[i + offset] = src[i]\n  }\n  return i\n}\n\nfunction isnan (val) {\n  return val !== val // eslint-disable-line no-self-compare\n}\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports) {\n\nvar core = module.exports = { version: '2.5.3' };\nif (typeof __e == 'number') __e = core; // eslint-disable-line no-undef\n\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar global = __webpack_require__(10);\nvar core = __webpack_require__(2);\nvar ctx = __webpack_require__(20);\nvar hide = __webpack_require__(13);\nvar PROTOTYPE = 'prototype';\n\nvar $export = function (type, name, source) {\n  var IS_FORCED = type & $export.F;\n  var IS_GLOBAL = type & $export.G;\n  var IS_STATIC = type & $export.S;\n  var IS_PROTO = type & $export.P;\n  var IS_BIND = type & $export.B;\n  var IS_WRAP = type & $export.W;\n  var exports = IS_GLOBAL ? core : core[name] || (core[name] = {});\n  var expProto = exports[PROTOTYPE];\n  var target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE];\n  var key, own, out;\n  if (IS_GLOBAL) source = name;\n  for (key in source) {\n    // contains in native\n    own = !IS_FORCED && target && target[key] !== undefined;\n    if (own && key in exports) continue;\n    // export native or passed\n    out = own ? target[key] : source[key];\n    // prevent global pollution for namespaces\n    exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key]\n    // bind timers to global for call from export context\n    : IS_BIND && own ? ctx(out, global)\n    // wrap global constructors for prevent change them in library\n    : IS_WRAP && target[key] == out ? (function (C) {\n      var F = function (a, b, c) {\n        if (this instanceof C) {\n          switch (arguments.length) {\n            case 0: return new C();\n            case 1: return new C(a);\n            case 2: return new C(a, b);\n          } return new C(a, b, c);\n        } return C.apply(this, arguments);\n      };\n      F[PROTOTYPE] = C[PROTOTYPE];\n      return F;\n    // make static versions for prototype methods\n    })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out;\n    // export proto methods to core.%CONSTRUCTOR%.methods.%NAME%\n    if (IS_PROTO) {\n      (exports.virtual || (exports.virtual = {}))[key] = out;\n      // export proto methods to core.%CONSTRUCTOR%.prototype.%NAME%\n      if (type & $export.R && expProto && !expProto[key]) hide(expProto, key, out);\n    }\n  }\n};\n// type bitmap\n$export.F = 1;   // forced\n$export.G = 2;   // global\n$export.S = 4;   // static\n$export.P = 8;   // proto\n$export.B = 16;  // bind\n$export.W = 32;  // wrap\n$export.U = 64;  // safe\n$export.R = 128; // real proto method for `library`\nmodule.exports = $export;\n\n\n/***/ }),\n/* 4 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar store = __webpack_require__(65)('wks');\nvar uid = __webpack_require__(38);\nvar Symbol = __webpack_require__(10).Symbol;\nvar USE_SYMBOL = typeof Symbol == 'function';\n\nvar $exports = module.exports = function (name) {\n  return store[name] || (store[name] =\n    USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name));\n};\n\n$exports.store = store;\n\n\n/***/ }),\n/* 5 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Thank's IE8 for his funny defineProperty\nmodule.exports = !__webpack_require__(19)(function () {\n  return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a != 7;\n});\n\n\n/***/ }),\n/* 6 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar anObject = __webpack_require__(14);\nvar IE8_DOM_DEFINE = __webpack_require__(95);\nvar toPrimitive = __webpack_require__(58);\nvar dP = Object.defineProperty;\n\nexports.f = __webpack_require__(5) ? Object.defineProperty : function defineProperty(O, P, Attributes) {\n  anObject(O);\n  P = toPrimitive(P, true);\n  anObject(Attributes);\n  if (IE8_DOM_DEFINE) try {\n    return dP(O, P, Attributes);\n  } catch (e) { /* empty */ }\n  if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported!');\n  if ('value' in Attributes) O[P] = Attributes.value;\n  return O;\n};\n\n\n/***/ }),\n/* 7 */\n/***/ (function(module, exports) {\n\nvar g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || Function(\"return this\")() || (1,eval)(\"this\");\n} catch(e) {\n\t// This works if the window reference is available\n\tif(typeof window === \"object\")\n\t\tg = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n\n\n/***/ }),\n/* 8 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(Buffer, __dirname) {\n\nfunction VirtualFileSystem() {\n\tthis.fileSystem = {};\n\tthis.baseSystem = {};\n}\n\nVirtualFileSystem.prototype.readFileSync = function (filename) {\n\tfilename = fixFilename(filename);\n\n\tvar base64content = this.baseSystem[filename];\n\tif (base64content) {\n\t\treturn new Buffer(base64content, 'base64');\n\t}\n\n\tvar content = this.fileSystem[filename];\n\tif (content) {\n\t\treturn content;\n\t}\n\n\tthrow 'File \\'' + filename + '\\' not found in virtual file system';\n};\n\nVirtualFileSystem.prototype.writeFileSync = function (filename, content) {\n\tthis.fileSystem[fixFilename(filename)] = content;\n};\n\nVirtualFileSystem.prototype.bindFS = function (data) {\n\tthis.baseSystem = data || {};\n};\n\n\nfunction fixFilename(filename) {\n\tif (filename.indexOf(__dirname) === 0) {\n\t\tfilename = filename.substring(__dirname.length);\n\t}\n\n\tif (filename.indexOf('/') === 0) {\n\t\tfilename = filename.substring(1);\n\t}\n\n\treturn filename;\n}\n\nmodule.exports = new VirtualFileSystem();\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer, \"/\"))\n\n/***/ }),\n/* 9 */\n/***/ (function(module, exports) {\n\nmodule.exports = function (it) {\n  return typeof it === 'object' ? it !== null : typeof it === 'function';\n};\n\n\n/***/ }),\n/* 10 */\n/***/ (function(module, exports) {\n\n// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028\nvar global = module.exports = typeof window != 'undefined' && window.Math == Math\n  ? window : typeof self != 'undefined' && self.Math == Math ? self\n  // eslint-disable-next-line no-new-func\n  : Function('return this')();\nif (typeof __g == 'number') __g = global; // eslint-disable-line no-undef\n\n\n/***/ }),\n/* 11 */\n/***/ (function(module, exports) {\n\n// shim for using process in browser\nvar process = module.exports = {};\n\n// cached from whatever global is present so that test runners that stub it\n// don't break things.  But we need to wrap it in a try catch in case it is\n// wrapped in strict mode code which doesn't define any globals.  It's inside a\n// function because try/catches deoptimize in certain engines.\n\nvar cachedSetTimeout;\nvar cachedClearTimeout;\n\nfunction defaultSetTimout() {\n    throw new Error('setTimeout has not been defined');\n}\nfunction defaultClearTimeout () {\n    throw new Error('clearTimeout has not been defined');\n}\n(function () {\n    try {\n        if (typeof setTimeout === 'function') {\n            cachedSetTimeout = setTimeout;\n        } else {\n            cachedSetTimeout = defaultSetTimout;\n        }\n    } catch (e) {\n        cachedSetTimeout = defaultSetTimout;\n    }\n    try {\n        if (typeof clearTimeout === 'function') {\n            cachedClearTimeout = clearTimeout;\n        } else {\n            cachedClearTimeout = defaultClearTimeout;\n        }\n    } catch (e) {\n        cachedClearTimeout = defaultClearTimeout;\n    }\n} ())\nfunction runTimeout(fun) {\n    if (cachedSetTimeout === setTimeout) {\n        //normal enviroments in sane situations\n        return setTimeout(fun, 0);\n    }\n    // if setTimeout wasn't available but was latter defined\n    if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\n        cachedSetTimeout = setTimeout;\n        return setTimeout(fun, 0);\n    }\n    try {\n        // when when somebody has screwed with setTimeout but no I.E. maddness\n        return cachedSetTimeout(fun, 0);\n    } catch(e){\n        try {\n            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n            return cachedSetTimeout.call(null, fun, 0);\n        } catch(e){\n            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n            return cachedSetTimeout.call(this, fun, 0);\n        }\n    }\n\n\n}\nfunction runClearTimeout(marker) {\n    if (cachedClearTimeout === clearTimeout) {\n        //normal enviroments in sane situations\n        return clearTimeout(marker);\n    }\n    // if clearTimeout wasn't available but was latter defined\n    if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\n        cachedClearTimeout = clearTimeout;\n        return clearTimeout(marker);\n    }\n    try {\n        // when when somebody has screwed with setTimeout but no I.E. maddness\n        return cachedClearTimeout(marker);\n    } catch (e){\n        try {\n            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally\n            return cachedClearTimeout.call(null, marker);\n        } catch (e){\n            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n            // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n            return cachedClearTimeout.call(this, marker);\n        }\n    }\n\n\n\n}\nvar queue = [];\nvar draining = false;\nvar currentQueue;\nvar queueIndex = -1;\n\nfunction cleanUpNextTick() {\n    if (!draining || !currentQueue) {\n        return;\n    }\n    draining = false;\n    if (currentQueue.length) {\n        queue = currentQueue.concat(queue);\n    } else {\n        queueIndex = -1;\n    }\n    if (queue.length) {\n        drainQueue();\n    }\n}\n\nfunction drainQueue() {\n    if (draining) {\n        return;\n    }\n    var timeout = runTimeout(cleanUpNextTick);\n    draining = true;\n\n    var len = queue.length;\n    while(len) {\n        currentQueue = queue;\n        queue = [];\n        while (++queueIndex < len) {\n            if (currentQueue) {\n                currentQueue[queueIndex].run();\n            }\n        }\n        queueIndex = -1;\n        len = queue.length;\n    }\n    currentQueue = null;\n    draining = false;\n    runClearTimeout(timeout);\n}\n\nprocess.nextTick = function (fun) {\n    var args = new Array(arguments.length - 1);\n    if (arguments.length > 1) {\n        for (var i = 1; i < arguments.length; i++) {\n            args[i - 1] = arguments[i];\n        }\n    }\n    queue.push(new Item(fun, args));\n    if (queue.length === 1 && !draining) {\n        runTimeout(drainQueue);\n    }\n};\n\n// v8 likes predictible objects\nfunction Item(fun, array) {\n    this.fun = fun;\n    this.array = array;\n}\nItem.prototype.run = function () {\n    this.fun.apply(null, this.array);\n};\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\nprocess.version = ''; // empty string to avoid regexp issues\nprocess.versions = {};\n\nfunction noop() {}\n\nprocess.on = noop;\nprocess.addListener = noop;\nprocess.once = noop;\nprocess.off = noop;\nprocess.removeListener = noop;\nprocess.removeAllListeners = noop;\nprocess.emit = noop;\nprocess.prependListener = noop;\nprocess.prependOnceListener = noop;\n\nprocess.listeners = function (name) { return [] }\n\nprocess.binding = function (name) {\n    throw new Error('process.binding is not supported');\n};\n\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n    throw new Error('process.chdir is not supported');\n};\nprocess.umask = function() { return 0; };\n\n\n/***/ }),\n/* 12 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var NumberT, PropertyDescriptor;\n\n  NumberT = __webpack_require__(22).Number;\n\n  exports.resolveLength = function(length, stream, parent) {\n    var res;\n    if (typeof length === 'number') {\n      res = length;\n    } else if (typeof length === 'function') {\n      res = length.call(parent, parent);\n    } else if (parent && typeof length === 'string') {\n      res = parent[length];\n    } else if (stream && length instanceof NumberT) {\n      res = length.decode(stream);\n    }\n    if (isNaN(res)) {\n      throw new Error('Not a fixed size');\n    }\n    return res;\n  };\n\n  PropertyDescriptor = (function() {\n    function PropertyDescriptor(opts) {\n      var key, val;\n      if (opts == null) {\n        opts = {};\n      }\n      this.enumerable = true;\n      this.configurable = true;\n      for (key in opts) {\n        val = opts[key];\n        this[key] = val;\n      }\n    }\n\n    return PropertyDescriptor;\n\n  })();\n\n  exports.PropertyDescriptor = PropertyDescriptor;\n\n}).call(this);\n\n\n/***/ }),\n/* 13 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar dP = __webpack_require__(6);\nvar createDesc = __webpack_require__(27);\nmodule.exports = __webpack_require__(5) ? function (object, key, value) {\n  return dP.f(object, key, createDesc(1, value));\n} : function (object, key, value) {\n  object[key] = value;\n  return object;\n};\n\n\n/***/ }),\n/* 14 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar isObject = __webpack_require__(9);\nmodule.exports = function (it) {\n  if (!isObject(it)) throw TypeError(it + ' is not an object!');\n  return it;\n};\n\n\n/***/ }),\n/* 15 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nmodule.exports = Stream;\n\nvar EE = __webpack_require__(31).EventEmitter;\nvar inherits = __webpack_require__(21);\n\ninherits(Stream, EE);\nStream.Readable = __webpack_require__(45);\nStream.Writable = __webpack_require__(146);\nStream.Duplex = __webpack_require__(147);\nStream.Transform = __webpack_require__(148);\nStream.PassThrough = __webpack_require__(149);\n\n// Backwards-compat with node 0.4.x\nStream.Stream = Stream;\n\n\n\n// old-style streams.  Note that the pipe method (the only relevant\n// part of this class) is overridden in the Readable class.\n\nfunction Stream() {\n  EE.call(this);\n}\n\nStream.prototype.pipe = function(dest, options) {\n  var source = this;\n\n  function ondata(chunk) {\n    if (dest.writable) {\n      if (false === dest.write(chunk) && source.pause) {\n        source.pause();\n      }\n    }\n  }\n\n  source.on('data', ondata);\n\n  function ondrain() {\n    if (source.readable && source.resume) {\n      source.resume();\n    }\n  }\n\n  dest.on('drain', ondrain);\n\n  // If the 'end' option is not supplied, dest.end() will be called when\n  // source gets the 'end' or 'close' events.  Only dest.end() once.\n  if (!dest._isStdio && (!options || options.end !== false)) {\n    source.on('end', onend);\n    source.on('close', onclose);\n  }\n\n  var didOnEnd = false;\n  function onend() {\n    if (didOnEnd) return;\n    didOnEnd = true;\n\n    dest.end();\n  }\n\n\n  function onclose() {\n    if (didOnEnd) return;\n    didOnEnd = true;\n\n    if (typeof dest.destroy === 'function') dest.destroy();\n  }\n\n  // don't leave dangling pipes when there are errors.\n  function onerror(er) {\n    cleanup();\n    if (EE.listenerCount(this, 'error') === 0) {\n      throw er; // Unhandled stream error in pipe.\n    }\n  }\n\n  source.on('error', onerror);\n  dest.on('error', onerror);\n\n  // remove all the event listeners that were added.\n  function cleanup() {\n    source.removeListener('data', ondata);\n    dest.removeListener('drain', ondrain);\n\n    source.removeListener('end', onend);\n    source.removeListener('close', onclose);\n\n    source.removeListener('error', onerror);\n    dest.removeListener('error', onerror);\n\n    source.removeListener('end', cleanup);\n    source.removeListener('close', cleanup);\n\n    dest.removeListener('close', cleanup);\n  }\n\n  source.on('end', cleanup);\n  source.on('close', cleanup);\n\n  dest.on('close', cleanup);\n\n  dest.emit('pipe', source);\n\n  // Allow for unix-like usage: A.pipe(B).pipe(C)\n  return dest;\n};\n\n\n/***/ }),\n/* 16 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// a duplex stream is just a stream that is both readable and writable.\n// Since JS doesn't have multiple prototypal inheritance, this class\n// prototypally inherits from Readable, and then parasitically from\n// Writable.\n\n\n\n/*<replacement>*/\n\nvar processNextTick = __webpack_require__(32).nextTick;\n/*</replacement>*/\n\n/*<replacement>*/\nvar objectKeys = Object.keys || function (obj) {\n  var keys = [];\n  for (var key in obj) {\n    keys.push(key);\n  }return keys;\n};\n/*</replacement>*/\n\nmodule.exports = Duplex;\n\n/*<replacement>*/\nvar util = __webpack_require__(25);\nutil.inherits = __webpack_require__(21);\n/*</replacement>*/\n\nvar Readable = __webpack_require__(83);\nvar Writable = __webpack_require__(46);\n\nutil.inherits(Duplex, Readable);\n\nvar keys = objectKeys(Writable.prototype);\nfor (var v = 0; v < keys.length; v++) {\n  var method = keys[v];\n  if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];\n}\n\nfunction Duplex(options) {\n  if (!(this instanceof Duplex)) return new Duplex(options);\n\n  Readable.call(this, options);\n  Writable.call(this, options);\n\n  if (options && options.readable === false) this.readable = false;\n\n  if (options && options.writable === false) this.writable = false;\n\n  this.allowHalfOpen = true;\n  if (options && options.allowHalfOpen === false) this.allowHalfOpen = false;\n\n  this.once('end', onend);\n}\n\n// the no-half-open enforcer\nfunction onend() {\n  // if we allow half-open state, or if the writable side ended,\n  // then we're ok.\n  if (this.allowHalfOpen || this._writableState.ended) return;\n\n  // no more data can be written.\n  // But allow more writes to happen in this tick.\n  processNextTick(onEndNT, this);\n}\n\nfunction onEndNT(self) {\n  self.end();\n}\n\nObject.defineProperty(Duplex.prototype, 'destroyed', {\n  get: function () {\n    if (this._readableState === undefined || this._writableState === undefined) {\n      return false;\n    }\n    return this._readableState.destroyed && this._writableState.destroyed;\n  },\n  set: function (value) {\n    // we ignore the value if the stream\n    // has not been initialized yet\n    if (this._readableState === undefined || this._writableState === undefined) {\n      return;\n    }\n\n    // backward compatibility, the user is explicitly\n    // managing destroyed\n    this._readableState.destroyed = value;\n    this._writableState.destroyed = value;\n  }\n});\n\nDuplex.prototype._destroy = function (err, cb) {\n  this.push(null);\n  this.end();\n\n  processNextTick(cb, err);\n};\n\nfunction forEach(xs, f) {\n  for (var i = 0, l = xs.length; i < l; i++) {\n    f(xs[i], i);\n  }\n}\n\n/***/ }),\n/* 17 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// to indexed object, toObject with fallback for non-array-like ES3 strings\nvar IObject = __webpack_require__(54);\nvar defined = __webpack_require__(56);\nmodule.exports = function (it) {\n  return IObject(defined(it));\n};\n\n\n/***/ }),\n/* 18 */\n/***/ (function(module, exports) {\n\nvar hasOwnProperty = {}.hasOwnProperty;\nmodule.exports = function (it, key) {\n  return hasOwnProperty.call(it, key);\n};\n\n\n/***/ }),\n/* 19 */\n/***/ (function(module, exports) {\n\nmodule.exports = function (exec) {\n  try {\n    return !!exec();\n  } catch (e) {\n    return true;\n  }\n};\n\n\n/***/ }),\n/* 20 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// optional / simple context binding\nvar aFunction = __webpack_require__(97);\nmodule.exports = function (fn, that, length) {\n  aFunction(fn);\n  if (that === undefined) return fn;\n  switch (length) {\n    case 1: return function (a) {\n      return fn.call(that, a);\n    };\n    case 2: return function (a, b) {\n      return fn.call(that, a, b);\n    };\n    case 3: return function (a, b, c) {\n      return fn.call(that, a, b, c);\n    };\n  }\n  return function (/* ...args */) {\n    return fn.apply(that, arguments);\n  };\n};\n\n\n/***/ }),\n/* 21 */\n/***/ (function(module, exports) {\n\nif (typeof Object.create === 'function') {\n  // implementation from standard node.js 'util' module\n  module.exports = function inherits(ctor, superCtor) {\n    ctor.super_ = superCtor\n    ctor.prototype = Object.create(superCtor.prototype, {\n      constructor: {\n        value: ctor,\n        enumerable: false,\n        writable: true,\n        configurable: true\n      }\n    });\n  };\n} else {\n  // old school shim for old browsers\n  module.exports = function inherits(ctor, superCtor) {\n    ctor.super_ = superCtor\n    var TempCtor = function () {}\n    TempCtor.prototype = superCtor.prototype\n    ctor.prototype = new TempCtor()\n    ctor.prototype.constructor = ctor\n  }\n}\n\n\n/***/ }),\n/* 22 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var DecodeStream, Fixed, NumberT,\n    __hasProp = {}.hasOwnProperty,\n    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n  DecodeStream = __webpack_require__(51);\n\n  NumberT = (function() {\n    function NumberT(type, endian) {\n      this.type = type;\n      this.endian = endian != null ? endian : 'BE';\n      this.fn = this.type;\n      if (this.type[this.type.length - 1] !== '8') {\n        this.fn += this.endian;\n      }\n    }\n\n    NumberT.prototype.size = function() {\n      return DecodeStream.TYPES[this.type];\n    };\n\n    NumberT.prototype.decode = function(stream) {\n      return stream['read' + this.fn]();\n    };\n\n    NumberT.prototype.encode = function(stream, val) {\n      return stream['write' + this.fn](val);\n    };\n\n    return NumberT;\n\n  })();\n\n  exports.Number = NumberT;\n\n  exports.uint8 = new NumberT('UInt8');\n\n  exports.uint16be = exports.uint16 = new NumberT('UInt16', 'BE');\n\n  exports.uint16le = new NumberT('UInt16', 'LE');\n\n  exports.uint24be = exports.uint24 = new NumberT('UInt24', 'BE');\n\n  exports.uint24le = new NumberT('UInt24', 'LE');\n\n  exports.uint32be = exports.uint32 = new NumberT('UInt32', 'BE');\n\n  exports.uint32le = new NumberT('UInt32', 'LE');\n\n  exports.int8 = new NumberT('Int8');\n\n  exports.int16be = exports.int16 = new NumberT('Int16', 'BE');\n\n  exports.int16le = new NumberT('Int16', 'LE');\n\n  exports.int24be = exports.int24 = new NumberT('Int24', 'BE');\n\n  exports.int24le = new NumberT('Int24', 'LE');\n\n  exports.int32be = exports.int32 = new NumberT('Int32', 'BE');\n\n  exports.int32le = new NumberT('Int32', 'LE');\n\n  exports.floatbe = exports.float = new NumberT('Float', 'BE');\n\n  exports.floatle = new NumberT('Float', 'LE');\n\n  exports.doublebe = exports.double = new NumberT('Double', 'BE');\n\n  exports.doublele = new NumberT('Double', 'LE');\n\n  Fixed = (function(_super) {\n    __extends(Fixed, _super);\n\n    function Fixed(size, endian, fracBits) {\n      if (fracBits == null) {\n        fracBits = size >> 1;\n      }\n      Fixed.__super__.constructor.call(this, \"Int\" + size, endian);\n      this._point = 1 << fracBits;\n    }\n\n    Fixed.prototype.decode = function(stream) {\n      return Fixed.__super__.decode.call(this, stream) / this._point;\n    };\n\n    Fixed.prototype.encode = function(stream, val) {\n      return Fixed.__super__.encode.call(this, stream, val * this._point | 0);\n    };\n\n    return Fixed;\n\n  })(NumberT);\n\n  exports.Fixed = Fixed;\n\n  exports.fixed16be = exports.fixed16 = new Fixed(16, 'BE');\n\n  exports.fixed16le = new Fixed(16, 'LE');\n\n  exports.fixed32be = exports.fixed32 = new Fixed(32, 'BE');\n\n  exports.fixed32le = new Fixed(32, 'LE');\n\n}).call(this);\n\n\n/***/ }),\n/* 23 */\n/***/ (function(module, exports) {\n\nmodule.exports = {};\n\n\n/***/ }),\n/* 24 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar $at = __webpack_require__(207)(true);\n\n// 21.1.3.27 String.prototype[@@iterator]()\n__webpack_require__(61)(String, 'String', function (iterated) {\n  this._t = String(iterated); // target\n  this._i = 0;                // next index\n// 21.1.5.2.1 %StringIteratorPrototype%.next()\n}, function () {\n  var O = this._t;\n  var index = this._i;\n  var point;\n  if (index >= O.length) return { value: undefined, done: true };\n  point = $at(O, index);\n  this._i += point.length;\n  return { value: point, done: false };\n});\n\n\n/***/ }),\n/* 25 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// NOTE: These type checking functions intentionally don't use `instanceof`\n// because it is fragile and can be easily faked with `Object.create()`.\n\nfunction isArray(arg) {\n  if (Array.isArray) {\n    return Array.isArray(arg);\n  }\n  return objectToString(arg) === '[object Array]';\n}\nexports.isArray = isArray;\n\nfunction isBoolean(arg) {\n  return typeof arg === 'boolean';\n}\nexports.isBoolean = isBoolean;\n\nfunction isNull(arg) {\n  return arg === null;\n}\nexports.isNull = isNull;\n\nfunction isNullOrUndefined(arg) {\n  return arg == null;\n}\nexports.isNullOrUndefined = isNullOrUndefined;\n\nfunction isNumber(arg) {\n  return typeof arg === 'number';\n}\nexports.isNumber = isNumber;\n\nfunction isString(arg) {\n  return typeof arg === 'string';\n}\nexports.isString = isString;\n\nfunction isSymbol(arg) {\n  return typeof arg === 'symbol';\n}\nexports.isSymbol = isSymbol;\n\nfunction isUndefined(arg) {\n  return arg === void 0;\n}\nexports.isUndefined = isUndefined;\n\nfunction isRegExp(re) {\n  return objectToString(re) === '[object RegExp]';\n}\nexports.isRegExp = isRegExp;\n\nfunction isObject(arg) {\n  return typeof arg === 'object' && arg !== null;\n}\nexports.isObject = isObject;\n\nfunction isDate(d) {\n  return objectToString(d) === '[object Date]';\n}\nexports.isDate = isDate;\n\nfunction isError(e) {\n  return (objectToString(e) === '[object Error]' || e instanceof Error);\n}\nexports.isError = isError;\n\nfunction isFunction(arg) {\n  return typeof arg === 'function';\n}\nexports.isFunction = isFunction;\n\nfunction isPrimitive(arg) {\n  return arg === null ||\n         typeof arg === 'boolean' ||\n         typeof arg === 'number' ||\n         typeof arg === 'string' ||\n         typeof arg === 'symbol' ||  // ES6 symbol\n         typeof arg === 'undefined';\n}\nexports.isPrimitive = isPrimitive;\n\nexports.isBuffer = Buffer.isBuffer;\n\nfunction objectToString(o) {\n  return Object.prototype.toString.call(o);\n}\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 26 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6\n\n/*\nPDFObject - converts JavaScript types into their corrisponding PDF types.\nBy Devon Govett\n */\n\n(function() {\n  var PDFObject, PDFReference;\n\n  PDFObject = (function() {\n    var escapable, escapableRe, pad, swapBytes;\n\n    function PDFObject() {}\n\n    pad = function(str, length) {\n      return (Array(length + 1).join('0') + str).slice(-length);\n    };\n\n    escapableRe = /[\\n\\r\\t\\b\\f\\(\\)\\\\]/g;\n\n    escapable = {\n      '\\n': '\\\\n',\n      '\\r': '\\\\r',\n      '\\t': '\\\\t',\n      '\\b': '\\\\b',\n      '\\f': '\\\\f',\n      '\\\\': '\\\\\\\\',\n      '(': '\\\\(',\n      ')': '\\\\)'\n    };\n\n    swapBytes = function(buff) {\n      var a, i, j, l, ref;\n      l = buff.length;\n      if (l & 0x01) {\n        throw new Error(\"Buffer length must be even\");\n      } else {\n        for (i = j = 0, ref = l - 1; j < ref; i = j += 2) {\n          a = buff[i];\n          buff[i] = buff[i + 1];\n          buff[i + 1] = a;\n        }\n      }\n      return buff;\n    };\n\n    PDFObject.convert = function(object) {\n      var e, i, isUnicode, items, j, key, out, ref, string, val;\n      if (typeof object === 'string') {\n        return '/' + object;\n      } else if (object instanceof String) {\n        string = object;\n        isUnicode = false;\n        for (i = j = 0, ref = string.length; j < ref; i = j += 1) {\n          if (string.charCodeAt(i) > 0x7f) {\n            isUnicode = true;\n            break;\n          }\n        }\n        if (isUnicode) {\n          string = swapBytes(new Buffer('\\ufeff' + string, 'utf16le')).toString('binary');\n        }\n        string = string.replace(escapableRe, function(c) {\n          return escapable[c];\n        });\n        return '(' + string + ')';\n      } else if (Buffer.isBuffer(object)) {\n        return '<' + object.toString('hex') + '>';\n      } else if (object instanceof PDFReference) {\n        return object.toString();\n      } else if (object instanceof Date) {\n        return '(D:' + pad(object.getUTCFullYear(), 4) + pad(object.getUTCMonth() + 1, 2) + pad(object.getUTCDate(), 2) + pad(object.getUTCHours(), 2) + pad(object.getUTCMinutes(), 2) + pad(object.getUTCSeconds(), 2) + 'Z)';\n      } else if (Array.isArray(object)) {\n        items = ((function() {\n          var k, len, results;\n          results = [];\n          for (k = 0, len = object.length; k < len; k++) {\n            e = object[k];\n            results.push(PDFObject.convert(e));\n          }\n          return results;\n        })()).join(' ');\n        return '[' + items + ']';\n      } else if ({}.toString.call(object) === '[object Object]') {\n        out = ['<<'];\n        for (key in object) {\n          val = object[key];\n          out.push('/' + key + ' ' + PDFObject.convert(val));\n        }\n        out.push('>>');\n        return out.join('\\n');\n      } else if (typeof object === 'number') {\n        return PDFObject.number(object);\n      } else {\n        return '' + object;\n      }\n    };\n\n    PDFObject.number = function(n) {\n      if (n > -1e21 && n < 1e21) {\n        return Math.round(n * 1e6) / 1e6;\n      }\n      throw new Error(\"unsupported number: \" + n);\n    };\n\n    return PDFObject;\n\n  })();\n\n  module.exports = PDFObject;\n\n  PDFReference = __webpack_require__(87);\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 27 */\n/***/ (function(module, exports) {\n\nmodule.exports = function (bitmap, value) {\n  return {\n    enumerable: !(bitmap & 1),\n    configurable: !(bitmap & 2),\n    writable: !(bitmap & 4),\n    value: value\n  };\n};\n\n\n/***/ }),\n/* 28 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(201);\nvar global = __webpack_require__(10);\nvar hide = __webpack_require__(13);\nvar Iterators = __webpack_require__(23);\nvar TO_STRING_TAG = __webpack_require__(4)('toStringTag');\n\nvar DOMIterables = ('CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,' +\n  'DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,' +\n  'MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,' +\n  'SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,' +\n  'TextTrackList,TouchList').split(',');\n\nfor (var i = 0; i < DOMIterables.length; i++) {\n  var NAME = DOMIterables[i];\n  var Collection = global[NAME];\n  var proto = Collection && Collection.prototype;\n  if (proto && !proto[TO_STRING_TAG]) hide(proto, TO_STRING_TAG, NAME);\n  Iterators[NAME] = Iterators.Array;\n}\n\n\n/***/ }),\n/* 29 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.2.14 / 15.2.3.14 Object.keys(O)\nvar $keys = __webpack_require__(101);\nvar enumBugKeys = __webpack_require__(66);\n\nmodule.exports = Object.keys || function keys(O) {\n  return $keys(O, enumBugKeys);\n};\n\n\n/***/ }),\n/* 30 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 7.1.13 ToObject(argument)\nvar defined = __webpack_require__(56);\nmodule.exports = function (it) {\n  return Object(defined(it));\n};\n\n\n/***/ }),\n/* 31 */\n/***/ (function(module, exports) {\n\n// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nfunction EventEmitter() {\n  this._events = this._events || {};\n  this._maxListeners = this._maxListeners || undefined;\n}\nmodule.exports = EventEmitter;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nEventEmitter.defaultMaxListeners = 10;\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function(n) {\n  if (!isNumber(n) || n < 0 || isNaN(n))\n    throw TypeError('n must be a positive number');\n  this._maxListeners = n;\n  return this;\n};\n\nEventEmitter.prototype.emit = function(type) {\n  var er, handler, len, args, i, listeners;\n\n  if (!this._events)\n    this._events = {};\n\n  // If there is no 'error' event listener then throw.\n  if (type === 'error') {\n    if (!this._events.error ||\n        (isObject(this._events.error) && !this._events.error.length)) {\n      er = arguments[1];\n      if (er instanceof Error) {\n        throw er; // Unhandled 'error' event\n      } else {\n        // At least give some kind of context to the user\n        var err = new Error('Uncaught, unspecified \"error\" event. (' + er + ')');\n        err.context = er;\n        throw err;\n      }\n    }\n  }\n\n  handler = this._events[type];\n\n  if (isUndefined(handler))\n    return false;\n\n  if (isFunction(handler)) {\n    switch (arguments.length) {\n      // fast cases\n      case 1:\n        handler.call(this);\n        break;\n      case 2:\n        handler.call(this, arguments[1]);\n        break;\n      case 3:\n        handler.call(this, arguments[1], arguments[2]);\n        break;\n      // slower\n      default:\n        args = Array.prototype.slice.call(arguments, 1);\n        handler.apply(this, args);\n    }\n  } else if (isObject(handler)) {\n    args = Array.prototype.slice.call(arguments, 1);\n    listeners = handler.slice();\n    len = listeners.length;\n    for (i = 0; i < len; i++)\n      listeners[i].apply(this, args);\n  }\n\n  return true;\n};\n\nEventEmitter.prototype.addListener = function(type, listener) {\n  var m;\n\n  if (!isFunction(listener))\n    throw TypeError('listener must be a function');\n\n  if (!this._events)\n    this._events = {};\n\n  // To avoid recursion in the case that type === \"newListener\"! Before\n  // adding it to the listeners, first emit \"newListener\".\n  if (this._events.newListener)\n    this.emit('newListener', type,\n              isFunction(listener.listener) ?\n              listener.listener : listener);\n\n  if (!this._events[type])\n    // Optimize the case of one listener. Don't need the extra array object.\n    this._events[type] = listener;\n  else if (isObject(this._events[type]))\n    // If we've already got an array, just append.\n    this._events[type].push(listener);\n  else\n    // Adding the second element, need to change to array.\n    this._events[type] = [this._events[type], listener];\n\n  // Check for listener leak\n  if (isObject(this._events[type]) && !this._events[type].warned) {\n    if (!isUndefined(this._maxListeners)) {\n      m = this._maxListeners;\n    } else {\n      m = EventEmitter.defaultMaxListeners;\n    }\n\n    if (m && m > 0 && this._events[type].length > m) {\n      this._events[type].warned = true;\n      console.error('(node) warning: possible EventEmitter memory ' +\n                    'leak detected. %d listeners added. ' +\n                    'Use emitter.setMaxListeners() to increase limit.',\n                    this._events[type].length);\n      if (typeof console.trace === 'function') {\n        // not supported in IE 10\n        console.trace();\n      }\n    }\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.once = function(type, listener) {\n  if (!isFunction(listener))\n    throw TypeError('listener must be a function');\n\n  var fired = false;\n\n  function g() {\n    this.removeListener(type, g);\n\n    if (!fired) {\n      fired = true;\n      listener.apply(this, arguments);\n    }\n  }\n\n  g.listener = listener;\n  this.on(type, g);\n\n  return this;\n};\n\n// emits a 'removeListener' event iff the listener was removed\nEventEmitter.prototype.removeListener = function(type, listener) {\n  var list, position, length, i;\n\n  if (!isFunction(listener))\n    throw TypeError('listener must be a function');\n\n  if (!this._events || !this._events[type])\n    return this;\n\n  list = this._events[type];\n  length = list.length;\n  position = -1;\n\n  if (list === listener ||\n      (isFunction(list.listener) && list.listener === listener)) {\n    delete this._events[type];\n    if (this._events.removeListener)\n      this.emit('removeListener', type, listener);\n\n  } else if (isObject(list)) {\n    for (i = length; i-- > 0;) {\n      if (list[i] === listener ||\n          (list[i].listener && list[i].listener === listener)) {\n        position = i;\n        break;\n      }\n    }\n\n    if (position < 0)\n      return this;\n\n    if (list.length === 1) {\n      list.length = 0;\n      delete this._events[type];\n    } else {\n      list.splice(position, 1);\n    }\n\n    if (this._events.removeListener)\n      this.emit('removeListener', type, listener);\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.removeAllListeners = function(type) {\n  var key, listeners;\n\n  if (!this._events)\n    return this;\n\n  // not listening for removeListener, no need to emit\n  if (!this._events.removeListener) {\n    if (arguments.length === 0)\n      this._events = {};\n    else if (this._events[type])\n      delete this._events[type];\n    return this;\n  }\n\n  // emit removeListener for all listeners on all events\n  if (arguments.length === 0) {\n    for (key in this._events) {\n      if (key === 'removeListener') continue;\n      this.removeAllListeners(key);\n    }\n    this.removeAllListeners('removeListener');\n    this._events = {};\n    return this;\n  }\n\n  listeners = this._events[type];\n\n  if (isFunction(listeners)) {\n    this.removeListener(type, listeners);\n  } else if (listeners) {\n    // LIFO order\n    while (listeners.length)\n      this.removeListener(type, listeners[listeners.length - 1]);\n  }\n  delete this._events[type];\n\n  return this;\n};\n\nEventEmitter.prototype.listeners = function(type) {\n  var ret;\n  if (!this._events || !this._events[type])\n    ret = [];\n  else if (isFunction(this._events[type]))\n    ret = [this._events[type]];\n  else\n    ret = this._events[type].slice();\n  return ret;\n};\n\nEventEmitter.prototype.listenerCount = function(type) {\n  if (this._events) {\n    var evlistener = this._events[type];\n\n    if (isFunction(evlistener))\n      return 1;\n    else if (evlistener)\n      return evlistener.length;\n  }\n  return 0;\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n  return emitter.listenerCount(type);\n};\n\nfunction isFunction(arg) {\n  return typeof arg === 'function';\n}\n\nfunction isNumber(arg) {\n  return typeof arg === 'number';\n}\n\nfunction isObject(arg) {\n  return typeof arg === 'object' && arg !== null;\n}\n\nfunction isUndefined(arg) {\n  return arg === void 0;\n}\n\n\n/***/ }),\n/* 32 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(process) {\n\nif (!process.version ||\n    process.version.indexOf('v0.') === 0 ||\n    process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) {\n  module.exports = { nextTick: nextTick };\n} else {\n  module.exports = process\n}\n\nfunction nextTick(fn, arg1, arg2, arg3) {\n  if (typeof fn !== 'function') {\n    throw new TypeError('\"callback\" argument must be a function');\n  }\n  var len = arguments.length;\n  var args, i;\n  switch (len) {\n  case 0:\n  case 1:\n    return process.nextTick(fn);\n  case 2:\n    return process.nextTick(function afterTickOne() {\n      fn.call(null, arg1);\n    });\n  case 3:\n    return process.nextTick(function afterTickTwo() {\n      fn.call(null, arg1, arg2);\n    });\n  case 4:\n    return process.nextTick(function afterTickThree() {\n      fn.call(null, arg1, arg2, arg3);\n    });\n  default:\n    args = new Array(len - 1);\n    i = 0;\n    while (i < args.length) {\n      args[i++] = arguments[i];\n    }\n    return process.nextTick(function afterTick() {\n      fn.apply(null, args);\n    });\n  }\n}\n\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11)))\n\n/***/ }),\n/* 33 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* eslint-disable node/no-deprecated-api */\nvar buffer = __webpack_require__(1)\nvar Buffer = buffer.Buffer\n\n// alternative to using Object.keys for old browsers\nfunction copyProps (src, dst) {\n  for (var key in src) {\n    dst[key] = src[key]\n  }\n}\nif (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) {\n  module.exports = buffer\n} else {\n  // Copy properties from require('buffer')\n  copyProps(buffer, exports)\n  exports.Buffer = SafeBuffer\n}\n\nfunction SafeBuffer (arg, encodingOrOffset, length) {\n  return Buffer(arg, encodingOrOffset, length)\n}\n\n// Copy static methods from Buffer\ncopyProps(Buffer, SafeBuffer)\n\nSafeBuffer.from = function (arg, encodingOrOffset, length) {\n  if (typeof arg === 'number') {\n    throw new TypeError('Argument must not be a number')\n  }\n  return Buffer(arg, encodingOrOffset, length)\n}\n\nSafeBuffer.alloc = function (size, fill, encoding) {\n  if (typeof size !== 'number') {\n    throw new TypeError('Argument must be a number')\n  }\n  var buf = Buffer(size)\n  if (fill !== undefined) {\n    if (typeof encoding === 'string') {\n      buf.fill(fill, encoding)\n    } else {\n      buf.fill(fill)\n    }\n  } else {\n    buf.fill(0)\n  }\n  return buf\n}\n\nSafeBuffer.allocUnsafe = function (size) {\n  if (typeof size !== 'number') {\n    throw new TypeError('Argument must be a number')\n  }\n  return Buffer(size)\n}\n\nSafeBuffer.allocUnsafeSlow = function (size) {\n  if (typeof size !== 'number') {\n    throw new TypeError('Argument must be a number')\n  }\n  return buffer.SlowBuffer(size)\n}\n\n\n/***/ }),\n/* 34 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n\nvar TYPED_OK =  (typeof Uint8Array !== 'undefined') &&\n                (typeof Uint16Array !== 'undefined') &&\n                (typeof Int32Array !== 'undefined');\n\nfunction _has(obj, key) {\n  return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\nexports.assign = function (obj /*from1, from2, from3, ...*/) {\n  var sources = Array.prototype.slice.call(arguments, 1);\n  while (sources.length) {\n    var source = sources.shift();\n    if (!source) { continue; }\n\n    if (typeof source !== 'object') {\n      throw new TypeError(source + 'must be non-object');\n    }\n\n    for (var p in source) {\n      if (_has(source, p)) {\n        obj[p] = source[p];\n      }\n    }\n  }\n\n  return obj;\n};\n\n\n// reduce buffer size, avoiding mem copy\nexports.shrinkBuf = function (buf, size) {\n  if (buf.length === size) { return buf; }\n  if (buf.subarray) { return buf.subarray(0, size); }\n  buf.length = size;\n  return buf;\n};\n\n\nvar fnTyped = {\n  arraySet: function (dest, src, src_offs, len, dest_offs) {\n    if (src.subarray && dest.subarray) {\n      dest.set(src.subarray(src_offs, src_offs + len), dest_offs);\n      return;\n    }\n    // Fallback to ordinary array\n    for (var i = 0; i < len; i++) {\n      dest[dest_offs + i] = src[src_offs + i];\n    }\n  },\n  // Join array of chunks to single array.\n  flattenChunks: function (chunks) {\n    var i, l, len, pos, chunk, result;\n\n    // calculate data length\n    len = 0;\n    for (i = 0, l = chunks.length; i < l; i++) {\n      len += chunks[i].length;\n    }\n\n    // join chunks\n    result = new Uint8Array(len);\n    pos = 0;\n    for (i = 0, l = chunks.length; i < l; i++) {\n      chunk = chunks[i];\n      result.set(chunk, pos);\n      pos += chunk.length;\n    }\n\n    return result;\n  }\n};\n\nvar fnUntyped = {\n  arraySet: function (dest, src, src_offs, len, dest_offs) {\n    for (var i = 0; i < len; i++) {\n      dest[dest_offs + i] = src[src_offs + i];\n    }\n  },\n  // Join array of chunks to single array.\n  flattenChunks: function (chunks) {\n    return [].concat.apply([], chunks);\n  }\n};\n\n\n// Enable/Disable typed arrays use, for testing\n//\nexports.setTyped = function (on) {\n  if (on) {\n    exports.Buf8  = Uint8Array;\n    exports.Buf16 = Uint16Array;\n    exports.Buf32 = Int32Array;\n    exports.assign(exports, fnTyped);\n  } else {\n    exports.Buf8  = Array;\n    exports.Buf16 = Array;\n    exports.Buf32 = Array;\n    exports.assign(exports, fnUntyped);\n  }\n};\n\nexports.setTyped(TYPED_OK);\n\n\n/***/ }),\n/* 35 */\n/***/ (function(module, exports) {\n\nexports.f = {}.propertyIsEnumerable;\n\n\n/***/ }),\n/* 36 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])\nvar anObject = __webpack_require__(14);\nvar dPs = __webpack_require__(100);\nvar enumBugKeys = __webpack_require__(66);\nvar IE_PROTO = __webpack_require__(64)('IE_PROTO');\nvar Empty = function () { /* empty */ };\nvar PROTOTYPE = 'prototype';\n\n// Create object with fake `null` prototype: use iframe Object with cleared prototype\nvar createDict = function () {\n  // Thrash, waste and sodomy: IE GC bug\n  var iframe = __webpack_require__(96)('iframe');\n  var i = enumBugKeys.length;\n  var lt = '<';\n  var gt = '>';\n  var iframeDocument;\n  iframe.style.display = 'none';\n  __webpack_require__(205).appendChild(iframe);\n  iframe.src = 'javascript:'; // eslint-disable-line no-script-url\n  // createDict = iframe.contentWindow.Object;\n  // html.removeChild(iframe);\n  iframeDocument = iframe.contentWindow.document;\n  iframeDocument.open();\n  iframeDocument.write(lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt);\n  iframeDocument.close();\n  createDict = iframeDocument.F;\n  while (i--) delete createDict[PROTOTYPE][enumBugKeys[i]];\n  return createDict();\n};\n\nmodule.exports = Object.create || function create(O, Properties) {\n  var result;\n  if (O !== null) {\n    Empty[PROTOTYPE] = anObject(O);\n    result = new Empty();\n    Empty[PROTOTYPE] = null;\n    // add \"__proto__\" for Object.getPrototypeOf polyfill\n    result[IE_PROTO] = O;\n  } else result = createDict();\n  return Properties === undefined ? result : dPs(result, Properties);\n};\n\n\n/***/ }),\n/* 37 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 7.1.15 ToLength\nvar toInteger = __webpack_require__(63);\nvar min = Math.min;\nmodule.exports = function (it) {\n  return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991\n};\n\n\n/***/ }),\n/* 38 */\n/***/ (function(module, exports) {\n\nvar id = 0;\nvar px = Math.random();\nmodule.exports = function (key) {\n  return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36));\n};\n\n\n/***/ }),\n/* 39 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar def = __webpack_require__(6).f;\nvar has = __webpack_require__(18);\nvar TAG = __webpack_require__(4)('toStringTag');\n\nmodule.exports = function (it, tag, stat) {\n  if (it && !has(it = stat ? it : it.prototype, TAG)) def(it, TAG, { configurable: true, value: tag });\n};\n\n\n/***/ }),\n/* 40 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar META = __webpack_require__(38)('meta');\nvar isObject = __webpack_require__(9);\nvar has = __webpack_require__(18);\nvar setDesc = __webpack_require__(6).f;\nvar id = 0;\nvar isExtensible = Object.isExtensible || function () {\n  return true;\n};\nvar FREEZE = !__webpack_require__(19)(function () {\n  return isExtensible(Object.preventExtensions({}));\n});\nvar setMeta = function (it) {\n  setDesc(it, META, { value: {\n    i: 'O' + ++id, // object ID\n    w: {}          // weak collections IDs\n  } });\n};\nvar fastKey = function (it, create) {\n  // return primitive with prefix\n  if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;\n  if (!has(it, META)) {\n    // can't set metadata to uncaught frozen object\n    if (!isExtensible(it)) return 'F';\n    // not necessary to add metadata\n    if (!create) return 'E';\n    // add missing metadata\n    setMeta(it);\n  // return object ID\n  } return it[META].i;\n};\nvar getWeak = function (it, create) {\n  if (!has(it, META)) {\n    // can't set metadata to uncaught frozen object\n    if (!isExtensible(it)) return true;\n    // not necessary to add metadata\n    if (!create) return false;\n    // add missing metadata\n    setMeta(it);\n  // return hash weak collections IDs\n  } return it[META].w;\n};\n// add metadata on freeze-family methods calling\nvar onFreeze = function (it) {\n  if (FREEZE && meta.NEED && isExtensible(it) && !has(it, META)) setMeta(it);\n  return it;\n};\nvar meta = module.exports = {\n  KEY: META,\n  NEED: false,\n  fastKey: fastKey,\n  getWeak: getWeak,\n  onFreeze: onFreeze\n};\n\n\n/***/ }),\n/* 41 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar ctx = __webpack_require__(20);\nvar call = __webpack_require__(111);\nvar isArrayIter = __webpack_require__(112);\nvar anObject = __webpack_require__(14);\nvar toLength = __webpack_require__(37);\nvar getIterFn = __webpack_require__(67);\nvar BREAK = {};\nvar RETURN = {};\nvar exports = module.exports = function (iterable, entries, fn, that, ITERATOR) {\n  var iterFn = ITERATOR ? function () { return iterable; } : getIterFn(iterable);\n  var f = ctx(fn, that, entries ? 2 : 1);\n  var index = 0;\n  var length, step, iterator, result;\n  if (typeof iterFn != 'function') throw TypeError(iterable + ' is not iterable!');\n  // fast case for arrays with default iterator\n  if (isArrayIter(iterFn)) for (length = toLength(iterable.length); length > index; index++) {\n    result = entries ? f(anObject(step = iterable[index])[0], step[1]) : f(iterable[index]);\n    if (result === BREAK || result === RETURN) return result;\n  } else for (iterator = iterFn.call(iterable); !(step = iterator.next()).done;) {\n    result = call(iterator, f, step.value, entries);\n    if (result === BREAK || result === RETURN) return result;\n  }\n};\nexports.BREAK = BREAK;\nexports.RETURN = RETURN;\n\n\n/***/ }),\n/* 42 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar isString = __webpack_require__(0).isString;\nvar isNumber = __webpack_require__(0).isNumber;\nvar isObject = __webpack_require__(0).isObject;\nvar isArray = __webpack_require__(0).isArray;\nvar LineBreaker = __webpack_require__(78);\n\nvar LEADING = /^(\\s)+/g;\nvar TRAILING = /(\\s)+$/g;\n\n/**\n * Creates an instance of TextTools - text measurement utility\n *\n * @constructor\n * @param {FontProvider} fontProvider\n */\nfunction TextTools(fontProvider) {\n\tthis.fontProvider = fontProvider;\n}\n\n/**\n * Converts an array of strings (or inline-definition-objects) into a collection\n * of inlines and calculated minWidth/maxWidth.\n * and their min/max widths\n * @param  {Object} textArray - an array of inline-definition-objects (or strings)\n * @param  {Object} styleContextStack current style stack\n * @return {Object}                   collection of inlines, minWidth, maxWidth\n */\nTextTools.prototype.buildInlines = function (textArray, styleContextStack) {\n\tvar measured = measure(this.fontProvider, textArray, styleContextStack);\n\n\tvar minWidth = 0,\n\t\tmaxWidth = 0,\n\t\tcurrentLineWidth;\n\n\tmeasured.forEach(function (inline) {\n\t\tminWidth = Math.max(minWidth, inline.width - inline.leadingCut - inline.trailingCut);\n\n\t\tif (!currentLineWidth) {\n\t\t\tcurrentLineWidth = {width: 0, leadingCut: inline.leadingCut, trailingCut: 0};\n\t\t}\n\n\t\tcurrentLineWidth.width += inline.width;\n\t\tcurrentLineWidth.trailingCut = inline.trailingCut;\n\n\t\tmaxWidth = Math.max(maxWidth, getTrimmedWidth(currentLineWidth));\n\n\t\tif (inline.lineEnd) {\n\t\t\tcurrentLineWidth = null;\n\t\t}\n\t});\n\n\tif (getStyleProperty({}, styleContextStack, 'noWrap', false)) {\n\t\tminWidth = maxWidth;\n\t}\n\n\treturn {\n\t\titems: measured,\n\t\tminWidth: minWidth,\n\t\tmaxWidth: maxWidth\n\t};\n\n\tfunction getTrimmedWidth(item) {\n\t\treturn Math.max(0, item.width - item.leadingCut - item.trailingCut);\n\t}\n};\n\n/**\n * Returns size of the specified string (without breaking it) using the current style\n * @param  {String} text              text to be measured\n * @param  {Object} styleContextStack current style stack\n * @return {Object}                   size of the specified string\n */\nTextTools.prototype.sizeOfString = function (text, styleContextStack) {\n\ttext = text ? text.toString().replace(/\\t/g, '    ') : '';\n\n\t//TODO: refactor - extract from measure\n\tvar fontName = getStyleProperty({}, styleContextStack, 'font', 'Roboto');\n\tvar fontSize = getStyleProperty({}, styleContextStack, 'fontSize', 12);\n\tvar fontFeatures = getStyleProperty({}, styleContextStack, 'fontFeatures', null);\n\tvar bold = getStyleProperty({}, styleContextStack, 'bold', false);\n\tvar italics = getStyleProperty({}, styleContextStack, 'italics', false);\n\tvar lineHeight = getStyleProperty({}, styleContextStack, 'lineHeight', 1);\n\tvar characterSpacing = getStyleProperty({}, styleContextStack, 'characterSpacing', 0);\n\n\tvar font = this.fontProvider.provideFont(fontName, bold, italics);\n\n\treturn {\n\t\twidth: widthOfString(text, font, fontSize, characterSpacing, fontFeatures),\n\t\theight: font.lineHeight(fontSize) * lineHeight,\n\t\tfontSize: fontSize,\n\t\tlineHeight: lineHeight,\n\t\tascender: font.ascender / 1000 * fontSize,\n\t\tdescender: font.descender / 1000 * fontSize\n\t};\n};\n\nTextTools.prototype.widthOfString = function (text, font, fontSize, characterSpacing, fontFeatures) {\n\treturn widthOfString(text, font, fontSize, characterSpacing, fontFeatures);\n};\n\nfunction splitWords(text, noWrap) {\n\tvar results = [];\n\ttext = text.replace(/\\t/g, '    ');\n\n\tif (noWrap) {\n\t\tresults.push({text: text});\n\t\treturn results;\n\t}\n\n\tvar breaker = new LineBreaker(text);\n\tvar last = 0;\n\tvar bk;\n\n\twhile (bk = breaker.nextBreak()) {\n\t\tvar word = text.slice(last, bk.position);\n\n\t\tif (bk.required || word.match(/\\r?\\n$|\\r$/)) { // new line\n\t\t\tword = word.replace(/\\r?\\n$|\\r$/, '');\n\t\t\tresults.push({text: word, lineEnd: true});\n\t\t} else {\n\t\t\tresults.push({text: word});\n\t\t}\n\n\t\tlast = bk.position;\n\t}\n\n\treturn results;\n}\n\nfunction copyStyle(source, destination) {\n\tdestination = destination || {};\n\tsource = source || {}; //TODO: default style\n\n\tfor (var key in source) {\n\t\tif (key != 'text' && source.hasOwnProperty(key)) {\n\t\t\tdestination[key] = source[key];\n\t\t}\n\t}\n\n\treturn destination;\n}\n\nfunction normalizeTextArray(array, styleContextStack) {\n\tfunction flatten(array) {\n\t\treturn array.reduce(function (prev, cur) {\n\t\t\tvar current = isArray(cur.text) ? flatten(cur.text) : cur;\n\t\t\tvar more = [].concat(current).some(Array.isArray);\n\t\t\treturn prev.concat(more ? flatten(current) : current);\n\t\t}, []);\n\t}\n\n\tvar results = [];\n\n\tif (!isArray(array)) {\n\t\tarray = [array];\n\t}\n\n\tarray = flatten(array);\n\n\tfor (var i = 0, l = array.length; i < l; i++) {\n\t\tvar item = array[i];\n\t\tvar style = null;\n\t\tvar words;\n\n\t\tvar noWrap = getStyleProperty(item || {}, styleContextStack, 'noWrap', false);\n\t\tif (isObject(item)) {\n\t\t\twords = splitWords(normalizeString(item.text), noWrap);\n\t\t\tstyle = copyStyle(item);\n\t\t} else {\n\t\t\twords = splitWords(normalizeString(item), noWrap);\n\t\t}\n\n\t\tfor (var i2 = 0, l2 = words.length; i2 < l2; i2++) {\n\t\t\tvar result = {\n\t\t\t\ttext: words[i2].text\n\t\t\t};\n\n\t\t\tif (words[i2].lineEnd) {\n\t\t\t\tresult.lineEnd = true;\n\t\t\t}\n\n\t\t\tcopyStyle(style, result);\n\n\t\t\tresults.push(result);\n\t\t}\n\t}\n\n\treturn results;\n}\n\nfunction normalizeString(value) {\n\tif (value === undefined || value === null) {\n\t\treturn '';\n\t} else if (isNumber(value)) {\n\t\treturn value.toString();\n\t} else if (isString(value)) {\n\t\treturn value;\n\t} else {\n\t\treturn value.toString();\n\t}\n}\n\nfunction getStyleProperty(item, styleContextStack, property, defaultValue) {\n\tvar value;\n\n\tif (item[property] !== undefined && item[property] !== null) {\n\t\t// item defines this property\n\t\treturn item[property];\n\t}\n\n\tif (!styleContextStack) {\n\t\treturn defaultValue;\n\t}\n\n\tstyleContextStack.auto(item, function () {\n\t\tvalue = styleContextStack.getProperty(property);\n\t});\n\n\tif (value !== null && value !== undefined) {\n\t\treturn value;\n\t} else {\n\t\treturn defaultValue;\n\t}\n}\n\nfunction measure(fontProvider, textArray, styleContextStack) {\n\tvar normalized = normalizeTextArray(textArray, styleContextStack);\n\n\tif (normalized.length) {\n\t\tvar leadingIndent = getStyleProperty(normalized[0], styleContextStack, 'leadingIndent', 0);\n\n\t\tif (leadingIndent) {\n\t\t\tnormalized[0].leadingCut = -leadingIndent;\n\t\t\tnormalized[0].leadingIndent = leadingIndent;\n\t\t}\n\t}\n\n\tnormalized.forEach(function (item) {\n\t\tvar fontName = getStyleProperty(item, styleContextStack, 'font', 'Roboto');\n\t\tvar fontSize = getStyleProperty(item, styleContextStack, 'fontSize', 12);\n\t\tvar fontFeatures = getStyleProperty(item, styleContextStack, 'fontFeatures', null);\n\t\tvar bold = getStyleProperty(item, styleContextStack, 'bold', false);\n\t\tvar italics = getStyleProperty(item, styleContextStack, 'italics', false);\n\t\tvar color = getStyleProperty(item, styleContextStack, 'color', 'black');\n\t\tvar decoration = getStyleProperty(item, styleContextStack, 'decoration', null);\n\t\tvar decorationColor = getStyleProperty(item, styleContextStack, 'decorationColor', null);\n\t\tvar decorationStyle = getStyleProperty(item, styleContextStack, 'decorationStyle', null);\n\t\tvar background = getStyleProperty(item, styleContextStack, 'background', null);\n\t\tvar lineHeight = getStyleProperty(item, styleContextStack, 'lineHeight', 1);\n\t\tvar characterSpacing = getStyleProperty(item, styleContextStack, 'characterSpacing', 0);\n\t\tvar link = getStyleProperty(item, styleContextStack, 'link', null);\n\t\tvar linkToPage = getStyleProperty(item, styleContextStack, 'linkToPage', null);\n\t\tvar noWrap = getStyleProperty(item, styleContextStack, 'noWrap', null);\n\t\tvar preserveLeadingSpaces = getStyleProperty(item, styleContextStack, 'preserveLeadingSpaces', false);\n\n\t\tvar font = fontProvider.provideFont(fontName, bold, italics);\n\n\t\titem.width = widthOfString(item.text, font, fontSize, characterSpacing, fontFeatures);\n\t\titem.height = font.lineHeight(fontSize) * lineHeight;\n\n\t\tvar leadingSpaces = item.text.match(LEADING);\n\n\t\tif (!item.leadingCut) {\n\t\t\titem.leadingCut = 0;\n\t\t}\n\n\t\tif (leadingSpaces && !preserveLeadingSpaces) {\n\t\t\titem.leadingCut += widthOfString(leadingSpaces[0], font, fontSize, characterSpacing, fontFeatures);\n\t\t}\n\n\t\tvar trailingSpaces = item.text.match(TRAILING);\n\t\tif (trailingSpaces) {\n\t\t\titem.trailingCut = widthOfString(trailingSpaces[0], font, fontSize, characterSpacing, fontFeatures);\n\t\t} else {\n\t\t\titem.trailingCut = 0;\n\t\t}\n\n\t\titem.alignment = getStyleProperty(item, styleContextStack, 'alignment', 'left');\n\t\titem.font = font;\n\t\titem.fontSize = fontSize;\n\t\titem.fontFeatures = fontFeatures;\n\t\titem.characterSpacing = characterSpacing;\n\t\titem.color = color;\n\t\titem.decoration = decoration;\n\t\titem.decorationColor = decorationColor;\n\t\titem.decorationStyle = decorationStyle;\n\t\titem.background = background;\n\t\titem.link = link;\n\t\titem.linkToPage = linkToPage;\n\t\titem.noWrap = noWrap;\n\t});\n\n\treturn normalized;\n}\n\nfunction widthOfString(text, font, fontSize, characterSpacing, fontFeatures) {\n\treturn font.widthOfString(text, fontSize, fontFeatures) + ((characterSpacing || 0) * (text.length - 1));\n}\n\nmodule.exports = TextTools;\n\n\n/***/ }),\n/* 43 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\nvar UnicodeTrie, inflate;\n\ninflate = __webpack_require__(79);\n\nUnicodeTrie = (function() {\n  var DATA_BLOCK_LENGTH, DATA_GRANULARITY, DATA_MASK, INDEX_1_OFFSET, INDEX_2_BLOCK_LENGTH, INDEX_2_BMP_LENGTH, INDEX_2_MASK, INDEX_SHIFT, LSCP_INDEX_2_LENGTH, LSCP_INDEX_2_OFFSET, OMITTED_BMP_INDEX_1_LENGTH, SHIFT_1, SHIFT_1_2, SHIFT_2, UTF8_2B_INDEX_2_LENGTH, UTF8_2B_INDEX_2_OFFSET;\n\n  SHIFT_1 = 6 + 5;\n\n  SHIFT_2 = 5;\n\n  SHIFT_1_2 = SHIFT_1 - SHIFT_2;\n\n  OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> SHIFT_1;\n\n  INDEX_2_BLOCK_LENGTH = 1 << SHIFT_1_2;\n\n  INDEX_2_MASK = INDEX_2_BLOCK_LENGTH - 1;\n\n  INDEX_SHIFT = 2;\n\n  DATA_BLOCK_LENGTH = 1 << SHIFT_2;\n\n  DATA_MASK = DATA_BLOCK_LENGTH - 1;\n\n  LSCP_INDEX_2_OFFSET = 0x10000 >> SHIFT_2;\n\n  LSCP_INDEX_2_LENGTH = 0x400 >> SHIFT_2;\n\n  INDEX_2_BMP_LENGTH = LSCP_INDEX_2_OFFSET + LSCP_INDEX_2_LENGTH;\n\n  UTF8_2B_INDEX_2_OFFSET = INDEX_2_BMP_LENGTH;\n\n  UTF8_2B_INDEX_2_LENGTH = 0x800 >> 6;\n\n  INDEX_1_OFFSET = UTF8_2B_INDEX_2_OFFSET + UTF8_2B_INDEX_2_LENGTH;\n\n  DATA_GRANULARITY = 1 << INDEX_SHIFT;\n\n  function UnicodeTrie(data) {\n    var isBuffer, uncompressedLength, view;\n    isBuffer = typeof data.readUInt32BE === 'function' && typeof data.slice === 'function';\n    if (isBuffer || data instanceof Uint8Array) {\n      if (isBuffer) {\n        this.highStart = data.readUInt32BE(0);\n        this.errorValue = data.readUInt32BE(4);\n        uncompressedLength = data.readUInt32BE(8);\n        data = data.slice(12);\n      } else {\n        view = new DataView(data.buffer);\n        this.highStart = view.getUint32(0);\n        this.errorValue = view.getUint32(4);\n        uncompressedLength = view.getUint32(8);\n        data = data.subarray(12);\n      }\n      data = inflate(data, new Uint8Array(uncompressedLength));\n      data = inflate(data, new Uint8Array(uncompressedLength));\n      this.data = new Uint32Array(data.buffer);\n    } else {\n      this.data = data.data, this.highStart = data.highStart, this.errorValue = data.errorValue;\n    }\n  }\n\n  UnicodeTrie.prototype.get = function(codePoint) {\n    var index;\n    if (codePoint < 0 || codePoint > 0x10ffff) {\n      return this.errorValue;\n    }\n    if (codePoint < 0xd800 || (codePoint > 0xdbff && codePoint <= 0xffff)) {\n      index = (this.data[codePoint >> SHIFT_2] << INDEX_SHIFT) + (codePoint & DATA_MASK);\n      return this.data[index];\n    }\n    if (codePoint <= 0xffff) {\n      index = (this.data[LSCP_INDEX_2_OFFSET + ((codePoint - 0xd800) >> SHIFT_2)] << INDEX_SHIFT) + (codePoint & DATA_MASK);\n      return this.data[index];\n    }\n    if (codePoint < this.highStart) {\n      index = this.data[(INDEX_1_OFFSET - OMITTED_BMP_INDEX_1_LENGTH) + (codePoint >> SHIFT_1)];\n      index = this.data[index + ((codePoint >> SHIFT_2) & INDEX_2_MASK)];\n      index = (index << INDEX_SHIFT) + (codePoint & DATA_MASK);\n      return this.data[index];\n    }\n    return this.data[this.data.length - DATA_GRANULARITY];\n  };\n\n  return UnicodeTrie;\n\n})();\n\nmodule.exports = UnicodeTrie;\n\n\n/***/ }),\n/* 44 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar isString = __webpack_require__(0).isString;\n\nfunction buildColumnWidths(columns, availableWidth) {\n\tvar autoColumns = [],\n\t\tautoMin = 0, autoMax = 0,\n\t\tstarColumns = [],\n\t\tstarMaxMin = 0,\n\t\tstarMaxMax = 0,\n\t\tfixedColumns = [],\n\t\tinitial_availableWidth = availableWidth;\n\n\tcolumns.forEach(function (column) {\n\t\tif (isAutoColumn(column)) {\n\t\t\tautoColumns.push(column);\n\t\t\tautoMin += column._minWidth;\n\t\t\tautoMax += column._maxWidth;\n\t\t} else if (isStarColumn(column)) {\n\t\t\tstarColumns.push(column);\n\t\t\tstarMaxMin = Math.max(starMaxMin, column._minWidth);\n\t\t\tstarMaxMax = Math.max(starMaxMax, column._maxWidth);\n\t\t} else {\n\t\t\tfixedColumns.push(column);\n\t\t}\n\t});\n\n\tfixedColumns.forEach(function (col) {\n\t\t// width specified as %\n\t\tif (isString(col.width) && /\\d+%/.test(col.width)) {\n\t\t\tcol.width = parseFloat(col.width) * initial_availableWidth / 100;\n\t\t}\n\t\tif (col.width < (col._minWidth) && col.elasticWidth) {\n\t\t\tcol._calcWidth = col._minWidth;\n\t\t} else {\n\t\t\tcol._calcWidth = col.width;\n\t\t}\n\n\t\tavailableWidth -= col._calcWidth;\n\t});\n\n\t// http://www.freesoft.org/CIE/RFC/1942/18.htm\n\t// http://www.w3.org/TR/CSS2/tables.html#width-layout\n\t// http://dev.w3.org/csswg/css3-tables-algorithms/Overview.src.htm\n\tvar minW = autoMin + starMaxMin * starColumns.length;\n\tvar maxW = autoMax + starMaxMax * starColumns.length;\n\tif (minW >= availableWidth) {\n\t\t// case 1 - there's no way to fit all columns within available width\n\t\t// that's actually pretty bad situation with PDF as we have no horizontal scroll\n\t\t// no easy workaround (unless we decide, in the future, to split single words)\n\t\t// currently we simply use minWidths for all columns\n\t\tautoColumns.forEach(function (col) {\n\t\t\tcol._calcWidth = col._minWidth;\n\t\t});\n\n\t\tstarColumns.forEach(function (col) {\n\t\t\tcol._calcWidth = starMaxMin; // starMaxMin already contains padding\n\t\t});\n\t} else {\n\t\tif (maxW < availableWidth) {\n\t\t\t// case 2 - we can fit rest of the table within available space\n\t\t\tautoColumns.forEach(function (col) {\n\t\t\t\tcol._calcWidth = col._maxWidth;\n\t\t\t\tavailableWidth -= col._calcWidth;\n\t\t\t});\n\t\t} else {\n\t\t\t// maxW is too large, but minW fits within available width\n\t\t\tvar W = availableWidth - minW;\n\t\t\tvar D = maxW - minW;\n\n\t\t\tautoColumns.forEach(function (col) {\n\t\t\t\tvar d = col._maxWidth - col._minWidth;\n\t\t\t\tcol._calcWidth = col._minWidth + d * W / D;\n\t\t\t\tavailableWidth -= col._calcWidth;\n\t\t\t});\n\t\t}\n\n\t\tif (starColumns.length > 0) {\n\t\t\tvar starSize = availableWidth / starColumns.length;\n\n\t\t\tstarColumns.forEach(function (col) {\n\t\t\t\tcol._calcWidth = starSize;\n\t\t\t});\n\t\t}\n\t}\n}\n\nfunction isAutoColumn(column) {\n\treturn column.width === 'auto';\n}\n\nfunction isStarColumn(column) {\n\treturn column.width === null || column.width === undefined || column.width === '*' || column.width === 'star';\n}\n\n//TODO: refactor and reuse in measureTable\nfunction measureMinMax(columns) {\n\tvar result = {min: 0, max: 0};\n\n\tvar maxStar = {min: 0, max: 0};\n\tvar starCount = 0;\n\n\tfor (var i = 0, l = columns.length; i < l; i++) {\n\t\tvar c = columns[i];\n\n\t\tif (isStarColumn(c)) {\n\t\t\tmaxStar.min = Math.max(maxStar.min, c._minWidth);\n\t\t\tmaxStar.max = Math.max(maxStar.max, c._maxWidth);\n\t\t\tstarCount++;\n\t\t} else if (isAutoColumn(c)) {\n\t\t\tresult.min += c._minWidth;\n\t\t\tresult.max += c._maxWidth;\n\t\t} else {\n\t\t\tresult.min += ((c.width !== undefined && c.width) || c._minWidth);\n\t\t\tresult.max += ((c.width !== undefined && c.width) || c._maxWidth);\n\t\t}\n\t}\n\n\tif (starCount) {\n\t\tresult.min += starCount * maxStar.min;\n\t\tresult.max += starCount * maxStar.max;\n\t}\n\n\treturn result;\n}\n\n/**\n * Calculates column widths\n * @private\n */\nmodule.exports = {\n\tbuildColumnWidths: buildColumnWidths,\n\tmeasureMinMax: measureMinMax,\n\tisAutoColumn: isAutoColumn,\n\tisStarColumn: isStarColumn\n};\n\n\n/***/ }),\n/* 45 */\n/***/ (function(module, exports, __webpack_require__) {\n\nexports = module.exports = __webpack_require__(83);\nexports.Stream = exports;\nexports.Readable = exports;\nexports.Writable = __webpack_require__(46);\nexports.Duplex = __webpack_require__(16);\nexports.Transform = __webpack_require__(86);\nexports.PassThrough = __webpack_require__(145);\n\n\n/***/ }),\n/* 46 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(process, setImmediate, global) {// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// A bit simpler than readable streams.\n// Implement an async ._write(chunk, encoding, cb), and it'll handle all\n// the drain event emission and buffering.\n\n\n\n/*<replacement>*/\n\nvar processNextTick = __webpack_require__(32).nextTick;\n/*</replacement>*/\n\nmodule.exports = Writable;\n\n/* <replacement> */\nfunction WriteReq(chunk, encoding, cb) {\n  this.chunk = chunk;\n  this.encoding = encoding;\n  this.callback = cb;\n  this.next = null;\n}\n\n// It seems a linked list but it is not\n// there will be only 2 of these for each stream\nfunction CorkedRequest(state) {\n  var _this = this;\n\n  this.next = null;\n  this.entry = null;\n  this.finish = function () {\n    onCorkedFinish(_this, state);\n  };\n}\n/* </replacement> */\n\n/*<replacement>*/\nvar asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : processNextTick;\n/*</replacement>*/\n\n/*<replacement>*/\nvar Duplex;\n/*</replacement>*/\n\nWritable.WritableState = WritableState;\n\n/*<replacement>*/\nvar util = __webpack_require__(25);\nutil.inherits = __webpack_require__(21);\n/*</replacement>*/\n\n/*<replacement>*/\nvar internalUtil = {\n  deprecate: __webpack_require__(144)\n};\n/*</replacement>*/\n\n/*<replacement>*/\nvar Stream = __webpack_require__(84);\n/*</replacement>*/\n\n/*<replacement>*/\n\nvar Buffer = __webpack_require__(33).Buffer;\nvar OurUint8Array = global.Uint8Array || function () {};\nfunction _uint8ArrayToBuffer(chunk) {\n  return Buffer.from(chunk);\n}\nfunction _isUint8Array(obj) {\n  return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;\n}\n\n/*</replacement>*/\n\nvar destroyImpl = __webpack_require__(85);\n\nutil.inherits(Writable, Stream);\n\nfunction nop() {}\n\nfunction WritableState(options, stream) {\n  Duplex = Duplex || __webpack_require__(16);\n\n  options = options || {};\n\n  // Duplex streams are both readable and writable, but share\n  // the same options object.\n  // However, some cases require setting options to different\n  // values for the readable and the writable sides of the duplex stream.\n  // These options can be provided separately as readableXXX and writableXXX.\n  var isDuplex = stream instanceof Duplex;\n\n  // object stream flag to indicate whether or not this stream\n  // contains buffers or objects.\n  this.objectMode = !!options.objectMode;\n\n  if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode;\n\n  // the point at which write() starts returning false\n  // Note: 0 is a valid value, means that we always return false if\n  // the entire buffer is not flushed immediately on write()\n  var hwm = options.highWaterMark;\n  var writableHwm = options.writableHighWaterMark;\n  var defaultHwm = this.objectMode ? 16 : 16 * 1024;\n\n  if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (writableHwm || writableHwm === 0)) this.highWaterMark = writableHwm;else this.highWaterMark = defaultHwm;\n\n  // cast to ints.\n  this.highWaterMark = Math.floor(this.highWaterMark);\n\n  // if _final has been called\n  this.finalCalled = false;\n\n  // drain event flag.\n  this.needDrain = false;\n  // at the start of calling end()\n  this.ending = false;\n  // when end() has been called, and returned\n  this.ended = false;\n  // when 'finish' is emitted\n  this.finished = false;\n\n  // has it been destroyed\n  this.destroyed = false;\n\n  // should we decode strings into buffers before passing to _write?\n  // this is here so that some node-core streams can optimize string\n  // handling at a lower level.\n  var noDecode = options.decodeStrings === false;\n  this.decodeStrings = !noDecode;\n\n  // Crypto is kind of old and crusty.  Historically, its default string\n  // encoding is 'binary' so we have to make this configurable.\n  // Everything else in the universe uses 'utf8', though.\n  this.defaultEncoding = options.defaultEncoding || 'utf8';\n\n  // not an actual buffer we keep track of, but a measurement\n  // of how much we're waiting to get pushed to some underlying\n  // socket or file.\n  this.length = 0;\n\n  // a flag to see when we're in the middle of a write.\n  this.writing = false;\n\n  // when true all writes will be buffered until .uncork() call\n  this.corked = 0;\n\n  // a flag to be able to tell if the onwrite cb is called immediately,\n  // or on a later tick.  We set this to true at first, because any\n  // actions that shouldn't happen until \"later\" should generally also\n  // not happen before the first write call.\n  this.sync = true;\n\n  // a flag to know if we're processing previously buffered items, which\n  // may call the _write() callback in the same tick, so that we don't\n  // end up in an overlapped onwrite situation.\n  this.bufferProcessing = false;\n\n  // the callback that's passed to _write(chunk,cb)\n  this.onwrite = function (er) {\n    onwrite(stream, er);\n  };\n\n  // the callback that the user supplies to write(chunk,encoding,cb)\n  this.writecb = null;\n\n  // the amount that is being written when _write is called.\n  this.writelen = 0;\n\n  this.bufferedRequest = null;\n  this.lastBufferedRequest = null;\n\n  // number of pending user-supplied write callbacks\n  // this must be 0 before 'finish' can be emitted\n  this.pendingcb = 0;\n\n  // emit prefinish if the only thing we're waiting for is _write cbs\n  // This is relevant for synchronous Transform streams\n  this.prefinished = false;\n\n  // True if the error was already emitted and should not be thrown again\n  this.errorEmitted = false;\n\n  // count buffered requests\n  this.bufferedRequestCount = 0;\n\n  // allocate the first CorkedRequest, there is always\n  // one allocated and free to use, and we maintain at most two\n  this.corkedRequestsFree = new CorkedRequest(this);\n}\n\nWritableState.prototype.getBuffer = function getBuffer() {\n  var current = this.bufferedRequest;\n  var out = [];\n  while (current) {\n    out.push(current);\n    current = current.next;\n  }\n  return out;\n};\n\n(function () {\n  try {\n    Object.defineProperty(WritableState.prototype, 'buffer', {\n      get: internalUtil.deprecate(function () {\n        return this.getBuffer();\n      }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003')\n    });\n  } catch (_) {}\n})();\n\n// Test _writableState for inheritance to account for Duplex streams,\n// whose prototype chain only points to Readable.\nvar realHasInstance;\nif (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') {\n  realHasInstance = Function.prototype[Symbol.hasInstance];\n  Object.defineProperty(Writable, Symbol.hasInstance, {\n    value: function (object) {\n      if (realHasInstance.call(this, object)) return true;\n      if (this !== Writable) return false;\n\n      return object && object._writableState instanceof WritableState;\n    }\n  });\n} else {\n  realHasInstance = function (object) {\n    return object instanceof this;\n  };\n}\n\nfunction Writable(options) {\n  Duplex = Duplex || __webpack_require__(16);\n\n  // Writable ctor is applied to Duplexes, too.\n  // `realHasInstance` is necessary because using plain `instanceof`\n  // would return false, as no `_writableState` property is attached.\n\n  // Trying to use the custom `instanceof` for Writable here will also break the\n  // Node.js LazyTransform implementation, which has a non-trivial getter for\n  // `_writableState` that would lead to infinite recursion.\n  if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) {\n    return new Writable(options);\n  }\n\n  this._writableState = new WritableState(options, this);\n\n  // legacy.\n  this.writable = true;\n\n  if (options) {\n    if (typeof options.write === 'function') this._write = options.write;\n\n    if (typeof options.writev === 'function') this._writev = options.writev;\n\n    if (typeof options.destroy === 'function') this._destroy = options.destroy;\n\n    if (typeof options.final === 'function') this._final = options.final;\n  }\n\n  Stream.call(this);\n}\n\n// Otherwise people can pipe Writable streams, which is just wrong.\nWritable.prototype.pipe = function () {\n  this.emit('error', new Error('Cannot pipe, not readable'));\n};\n\nfunction writeAfterEnd(stream, cb) {\n  var er = new Error('write after end');\n  // TODO: defer error events consistently everywhere, not just the cb\n  stream.emit('error', er);\n  processNextTick(cb, er);\n}\n\n// Checks that a user-supplied chunk is valid, especially for the particular\n// mode the stream is in. Currently this means that `null` is never accepted\n// and undefined/non-string values are only allowed in object mode.\nfunction validChunk(stream, state, chunk, cb) {\n  var valid = true;\n  var er = false;\n\n  if (chunk === null) {\n    er = new TypeError('May not write null values to stream');\n  } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {\n    er = new TypeError('Invalid non-string/buffer chunk');\n  }\n  if (er) {\n    stream.emit('error', er);\n    processNextTick(cb, er);\n    valid = false;\n  }\n  return valid;\n}\n\nWritable.prototype.write = function (chunk, encoding, cb) {\n  var state = this._writableState;\n  var ret = false;\n  var isBuf = !state.objectMode && _isUint8Array(chunk);\n\n  if (isBuf && !Buffer.isBuffer(chunk)) {\n    chunk = _uint8ArrayToBuffer(chunk);\n  }\n\n  if (typeof encoding === 'function') {\n    cb = encoding;\n    encoding = null;\n  }\n\n  if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding;\n\n  if (typeof cb !== 'function') cb = nop;\n\n  if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) {\n    state.pendingcb++;\n    ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);\n  }\n\n  return ret;\n};\n\nWritable.prototype.cork = function () {\n  var state = this._writableState;\n\n  state.corked++;\n};\n\nWritable.prototype.uncork = function () {\n  var state = this._writableState;\n\n  if (state.corked) {\n    state.corked--;\n\n    if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);\n  }\n};\n\nWritable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {\n  // node::ParseEncoding() requires lower case.\n  if (typeof encoding === 'string') encoding = encoding.toLowerCase();\n  if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding);\n  this._writableState.defaultEncoding = encoding;\n  return this;\n};\n\nfunction decodeChunk(state, chunk, encoding) {\n  if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {\n    chunk = Buffer.from(chunk, encoding);\n  }\n  return chunk;\n}\n\n// if we're already writing something, then just put this\n// in the queue, and wait our turn.  Otherwise, call _write\n// If we return false, then we need a drain event, so set that flag.\nfunction writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {\n  if (!isBuf) {\n    var newChunk = decodeChunk(state, chunk, encoding);\n    if (chunk !== newChunk) {\n      isBuf = true;\n      encoding = 'buffer';\n      chunk = newChunk;\n    }\n  }\n  var len = state.objectMode ? 1 : chunk.length;\n\n  state.length += len;\n\n  var ret = state.length < state.highWaterMark;\n  // we must ensure that previous needDrain will not be reset to false.\n  if (!ret) state.needDrain = true;\n\n  if (state.writing || state.corked) {\n    var last = state.lastBufferedRequest;\n    state.lastBufferedRequest = {\n      chunk: chunk,\n      encoding: encoding,\n      isBuf: isBuf,\n      callback: cb,\n      next: null\n    };\n    if (last) {\n      last.next = state.lastBufferedRequest;\n    } else {\n      state.bufferedRequest = state.lastBufferedRequest;\n    }\n    state.bufferedRequestCount += 1;\n  } else {\n    doWrite(stream, state, false, len, chunk, encoding, cb);\n  }\n\n  return ret;\n}\n\nfunction doWrite(stream, state, writev, len, chunk, encoding, cb) {\n  state.writelen = len;\n  state.writecb = cb;\n  state.writing = true;\n  state.sync = true;\n  if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite);\n  state.sync = false;\n}\n\nfunction onwriteError(stream, state, sync, er, cb) {\n  --state.pendingcb;\n\n  if (sync) {\n    // defer the callback if we are being called synchronously\n    // to avoid piling up things on the stack\n    processNextTick(cb, er);\n    // this can emit finish, and it will always happen\n    // after error\n    processNextTick(finishMaybe, stream, state);\n    stream._writableState.errorEmitted = true;\n    stream.emit('error', er);\n  } else {\n    // the caller expect this to happen before if\n    // it is async\n    cb(er);\n    stream._writableState.errorEmitted = true;\n    stream.emit('error', er);\n    // this can emit finish, but finish must\n    // always follow error\n    finishMaybe(stream, state);\n  }\n}\n\nfunction onwriteStateUpdate(state) {\n  state.writing = false;\n  state.writecb = null;\n  state.length -= state.writelen;\n  state.writelen = 0;\n}\n\nfunction onwrite(stream, er) {\n  var state = stream._writableState;\n  var sync = state.sync;\n  var cb = state.writecb;\n\n  onwriteStateUpdate(state);\n\n  if (er) onwriteError(stream, state, sync, er, cb);else {\n    // Check if we're actually ready to finish, but don't emit yet\n    var finished = needFinish(state);\n\n    if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {\n      clearBuffer(stream, state);\n    }\n\n    if (sync) {\n      /*<replacement>*/\n      asyncWrite(afterWrite, stream, state, finished, cb);\n      /*</replacement>*/\n    } else {\n      afterWrite(stream, state, finished, cb);\n    }\n  }\n}\n\nfunction afterWrite(stream, state, finished, cb) {\n  if (!finished) onwriteDrain(stream, state);\n  state.pendingcb--;\n  cb();\n  finishMaybe(stream, state);\n}\n\n// Must force callback to be called on nextTick, so that we don't\n// emit 'drain' before the write() consumer gets the 'false' return\n// value, and has a chance to attach a 'drain' listener.\nfunction onwriteDrain(stream, state) {\n  if (state.length === 0 && state.needDrain) {\n    state.needDrain = false;\n    stream.emit('drain');\n  }\n}\n\n// if there's something in the buffer waiting, then process it\nfunction clearBuffer(stream, state) {\n  state.bufferProcessing = true;\n  var entry = state.bufferedRequest;\n\n  if (stream._writev && entry && entry.next) {\n    // Fast case, write everything using _writev()\n    var l = state.bufferedRequestCount;\n    var buffer = new Array(l);\n    var holder = state.corkedRequestsFree;\n    holder.entry = entry;\n\n    var count = 0;\n    var allBuffers = true;\n    while (entry) {\n      buffer[count] = entry;\n      if (!entry.isBuf) allBuffers = false;\n      entry = entry.next;\n      count += 1;\n    }\n    buffer.allBuffers = allBuffers;\n\n    doWrite(stream, state, true, state.length, buffer, '', holder.finish);\n\n    // doWrite is almost always async, defer these to save a bit of time\n    // as the hot path ends with doWrite\n    state.pendingcb++;\n    state.lastBufferedRequest = null;\n    if (holder.next) {\n      state.corkedRequestsFree = holder.next;\n      holder.next = null;\n    } else {\n      state.corkedRequestsFree = new CorkedRequest(state);\n    }\n    state.bufferedRequestCount = 0;\n  } else {\n    // Slow case, write chunks one-by-one\n    while (entry) {\n      var chunk = entry.chunk;\n      var encoding = entry.encoding;\n      var cb = entry.callback;\n      var len = state.objectMode ? 1 : chunk.length;\n\n      doWrite(stream, state, false, len, chunk, encoding, cb);\n      entry = entry.next;\n      state.bufferedRequestCount--;\n      // if we didn't call the onwrite immediately, then\n      // it means that we need to wait until it does.\n      // also, that means that the chunk and cb are currently\n      // being processed, so move the buffer counter past them.\n      if (state.writing) {\n        break;\n      }\n    }\n\n    if (entry === null) state.lastBufferedRequest = null;\n  }\n\n  state.bufferedRequest = entry;\n  state.bufferProcessing = false;\n}\n\nWritable.prototype._write = function (chunk, encoding, cb) {\n  cb(new Error('_write() is not implemented'));\n};\n\nWritable.prototype._writev = null;\n\nWritable.prototype.end = function (chunk, encoding, cb) {\n  var state = this._writableState;\n\n  if (typeof chunk === 'function') {\n    cb = chunk;\n    chunk = null;\n    encoding = null;\n  } else if (typeof encoding === 'function') {\n    cb = encoding;\n    encoding = null;\n  }\n\n  if (chunk !== null && chunk !== undefined) this.write(chunk, encoding);\n\n  // .end() fully uncorks\n  if (state.corked) {\n    state.corked = 1;\n    this.uncork();\n  }\n\n  // ignore unnecessary end() calls.\n  if (!state.ending && !state.finished) endWritable(this, state, cb);\n};\n\nfunction needFinish(state) {\n  return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;\n}\nfunction callFinal(stream, state) {\n  stream._final(function (err) {\n    state.pendingcb--;\n    if (err) {\n      stream.emit('error', err);\n    }\n    state.prefinished = true;\n    stream.emit('prefinish');\n    finishMaybe(stream, state);\n  });\n}\nfunction prefinish(stream, state) {\n  if (!state.prefinished && !state.finalCalled) {\n    if (typeof stream._final === 'function') {\n      state.pendingcb++;\n      state.finalCalled = true;\n      processNextTick(callFinal, stream, state);\n    } else {\n      state.prefinished = true;\n      stream.emit('prefinish');\n    }\n  }\n}\n\nfunction finishMaybe(stream, state) {\n  var need = needFinish(state);\n  if (need) {\n    prefinish(stream, state);\n    if (state.pendingcb === 0) {\n      state.finished = true;\n      stream.emit('finish');\n    }\n  }\n  return need;\n}\n\nfunction endWritable(stream, state, cb) {\n  state.ending = true;\n  finishMaybe(stream, state);\n  if (cb) {\n    if (state.finished) processNextTick(cb);else stream.once('finish', cb);\n  }\n  state.ended = true;\n  stream.writable = false;\n}\n\nfunction onCorkedFinish(corkReq, state, err) {\n  var entry = corkReq.entry;\n  corkReq.entry = null;\n  while (entry) {\n    var cb = entry.callback;\n    state.pendingcb--;\n    cb(err);\n    entry = entry.next;\n  }\n  if (state.corkedRequestsFree) {\n    state.corkedRequestsFree.next = corkReq;\n  } else {\n    state.corkedRequestsFree = corkReq;\n  }\n}\n\nObject.defineProperty(Writable.prototype, 'destroyed', {\n  get: function () {\n    if (this._writableState === undefined) {\n      return false;\n    }\n    return this._writableState.destroyed;\n  },\n  set: function (value) {\n    // we ignore the value if the stream\n    // has not been initialized yet\n    if (!this._writableState) {\n      return;\n    }\n\n    // backward compatibility, the user is explicitly\n    // managing destroyed\n    this._writableState.destroyed = value;\n  }\n});\n\nWritable.prototype.destroy = destroyImpl.destroy;\nWritable.prototype._undestroy = destroyImpl.undestroy;\nWritable.prototype._destroy = function (err, cb) {\n  this.end();\n  cb(err);\n};\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11), __webpack_require__(142).setImmediate, __webpack_require__(7)))\n\n/***/ }),\n/* 47 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar Buffer = __webpack_require__(33).Buffer;\n\nvar isEncoding = Buffer.isEncoding || function (encoding) {\n  encoding = '' + encoding;\n  switch (encoding && encoding.toLowerCase()) {\n    case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw':\n      return true;\n    default:\n      return false;\n  }\n};\n\nfunction _normalizeEncoding(enc) {\n  if (!enc) return 'utf8';\n  var retried;\n  while (true) {\n    switch (enc) {\n      case 'utf8':\n      case 'utf-8':\n        return 'utf8';\n      case 'ucs2':\n      case 'ucs-2':\n      case 'utf16le':\n      case 'utf-16le':\n        return 'utf16le';\n      case 'latin1':\n      case 'binary':\n        return 'latin1';\n      case 'base64':\n      case 'ascii':\n      case 'hex':\n        return enc;\n      default:\n        if (retried) return; // undefined\n        enc = ('' + enc).toLowerCase();\n        retried = true;\n    }\n  }\n};\n\n// Do not cache `Buffer.isEncoding` when checking encoding names as some\n// modules monkey-patch it to support additional encodings\nfunction normalizeEncoding(enc) {\n  var nenc = _normalizeEncoding(enc);\n  if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc);\n  return nenc || enc;\n}\n\n// StringDecoder provides an interface for efficiently splitting a series of\n// buffers into a series of JS strings without breaking apart multi-byte\n// characters.\nexports.StringDecoder = StringDecoder;\nfunction StringDecoder(encoding) {\n  this.encoding = normalizeEncoding(encoding);\n  var nb;\n  switch (this.encoding) {\n    case 'utf16le':\n      this.text = utf16Text;\n      this.end = utf16End;\n      nb = 4;\n      break;\n    case 'utf8':\n      this.fillLast = utf8FillLast;\n      nb = 4;\n      break;\n    case 'base64':\n      this.text = base64Text;\n      this.end = base64End;\n      nb = 3;\n      break;\n    default:\n      this.write = simpleWrite;\n      this.end = simpleEnd;\n      return;\n  }\n  this.lastNeed = 0;\n  this.lastTotal = 0;\n  this.lastChar = Buffer.allocUnsafe(nb);\n}\n\nStringDecoder.prototype.write = function (buf) {\n  if (buf.length === 0) return '';\n  var r;\n  var i;\n  if (this.lastNeed) {\n    r = this.fillLast(buf);\n    if (r === undefined) return '';\n    i = this.lastNeed;\n    this.lastNeed = 0;\n  } else {\n    i = 0;\n  }\n  if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i);\n  return r || '';\n};\n\nStringDecoder.prototype.end = utf8End;\n\n// Returns only complete characters in a Buffer\nStringDecoder.prototype.text = utf8Text;\n\n// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer\nStringDecoder.prototype.fillLast = function (buf) {\n  if (this.lastNeed <= buf.length) {\n    buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed);\n    return this.lastChar.toString(this.encoding, 0, this.lastTotal);\n  }\n  buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length);\n  this.lastNeed -= buf.length;\n};\n\n// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a\n// continuation byte.\nfunction utf8CheckByte(byte) {\n  if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4;\n  return -1;\n}\n\n// Checks at most 3 bytes at the end of a Buffer in order to detect an\n// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4)\n// needed to complete the UTF-8 character (if applicable) are returned.\nfunction utf8CheckIncomplete(self, buf, i) {\n  var j = buf.length - 1;\n  if (j < i) return 0;\n  var nb = utf8CheckByte(buf[j]);\n  if (nb >= 0) {\n    if (nb > 0) self.lastNeed = nb - 1;\n    return nb;\n  }\n  if (--j < i) return 0;\n  nb = utf8CheckByte(buf[j]);\n  if (nb >= 0) {\n    if (nb > 0) self.lastNeed = nb - 2;\n    return nb;\n  }\n  if (--j < i) return 0;\n  nb = utf8CheckByte(buf[j]);\n  if (nb >= 0) {\n    if (nb > 0) {\n      if (nb === 2) nb = 0;else self.lastNeed = nb - 3;\n    }\n    return nb;\n  }\n  return 0;\n}\n\n// Validates as many continuation bytes for a multi-byte UTF-8 character as\n// needed or are available. If we see a non-continuation byte where we expect\n// one, we \"replace\" the validated continuation bytes we've seen so far with\n// UTF-8 replacement characters ('\\ufffd'), to match v8's UTF-8 decoding\n// behavior. The continuation byte check is included three times in the case\n// where all of the continuation bytes for a character exist in the same buffer.\n// It is also done this way as a slight performance increase instead of using a\n// loop.\nfunction utf8CheckExtraBytes(self, buf, p) {\n  if ((buf[0] & 0xC0) !== 0x80) {\n    self.lastNeed = 0;\n    return '\\ufffd'.repeat(p);\n  }\n  if (self.lastNeed > 1 && buf.length > 1) {\n    if ((buf[1] & 0xC0) !== 0x80) {\n      self.lastNeed = 1;\n      return '\\ufffd'.repeat(p + 1);\n    }\n    if (self.lastNeed > 2 && buf.length > 2) {\n      if ((buf[2] & 0xC0) !== 0x80) {\n        self.lastNeed = 2;\n        return '\\ufffd'.repeat(p + 2);\n      }\n    }\n  }\n}\n\n// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer.\nfunction utf8FillLast(buf) {\n  var p = this.lastTotal - this.lastNeed;\n  var r = utf8CheckExtraBytes(this, buf, p);\n  if (r !== undefined) return r;\n  if (this.lastNeed <= buf.length) {\n    buf.copy(this.lastChar, p, 0, this.lastNeed);\n    return this.lastChar.toString(this.encoding, 0, this.lastTotal);\n  }\n  buf.copy(this.lastChar, p, 0, buf.length);\n  this.lastNeed -= buf.length;\n}\n\n// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a\n// partial character, the character's bytes are buffered until the required\n// number of bytes are available.\nfunction utf8Text(buf, i) {\n  var total = utf8CheckIncomplete(this, buf, i);\n  if (!this.lastNeed) return buf.toString('utf8', i);\n  this.lastTotal = total;\n  var end = buf.length - (total - this.lastNeed);\n  buf.copy(this.lastChar, 0, end);\n  return buf.toString('utf8', i, end);\n}\n\n// For UTF-8, a replacement character for each buffered byte of a (partial)\n// character needs to be added to the output.\nfunction utf8End(buf) {\n  var r = buf && buf.length ? this.write(buf) : '';\n  if (this.lastNeed) return r + '\\ufffd'.repeat(this.lastTotal - this.lastNeed);\n  return r;\n}\n\n// UTF-16LE typically needs two bytes per character, but even if we have an even\n// number of bytes available, we need to check if we end on a leading/high\n// surrogate. In that case, we need to wait for the next two bytes in order to\n// decode the last character properly.\nfunction utf16Text(buf, i) {\n  if ((buf.length - i) % 2 === 0) {\n    var r = buf.toString('utf16le', i);\n    if (r) {\n      var c = r.charCodeAt(r.length - 1);\n      if (c >= 0xD800 && c <= 0xDBFF) {\n        this.lastNeed = 2;\n        this.lastTotal = 4;\n        this.lastChar[0] = buf[buf.length - 2];\n        this.lastChar[1] = buf[buf.length - 1];\n        return r.slice(0, -1);\n      }\n    }\n    return r;\n  }\n  this.lastNeed = 1;\n  this.lastTotal = 2;\n  this.lastChar[0] = buf[buf.length - 1];\n  return buf.toString('utf16le', i, buf.length - 1);\n}\n\n// For UTF-16LE we do not explicitly append special replacement characters if we\n// end on a partial character, we simply let v8 handle that.\nfunction utf16End(buf) {\n  var r = buf && buf.length ? this.write(buf) : '';\n  if (this.lastNeed) {\n    var end = this.lastTotal - this.lastNeed;\n    return r + this.lastChar.toString('utf16le', 0, end);\n  }\n  return r;\n}\n\nfunction base64Text(buf, i) {\n  var n = (buf.length - i) % 3;\n  if (n === 0) return buf.toString('base64', i);\n  this.lastNeed = 3 - n;\n  this.lastTotal = 3;\n  if (n === 1) {\n    this.lastChar[0] = buf[buf.length - 1];\n  } else {\n    this.lastChar[0] = buf[buf.length - 2];\n    this.lastChar[1] = buf[buf.length - 1];\n  }\n  return buf.toString('base64', i, buf.length - n);\n}\n\nfunction base64End(buf) {\n  var r = buf && buf.length ? this.write(buf) : '';\n  if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed);\n  return r;\n}\n\n// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex)\nfunction simpleWrite(buf) {\n  return buf.toString(this.encoding);\n}\n\nfunction simpleEnd(buf) {\n  return buf && buf.length ? this.write(buf) : '';\n}\n\n/***/ }),\n/* 48 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(process) {\n\nvar Buffer = __webpack_require__(1).Buffer;\nvar Transform = __webpack_require__(15).Transform;\nvar binding = __webpack_require__(150);\nvar util = __webpack_require__(49);\nvar assert = __webpack_require__(88).ok;\nvar kMaxLength = __webpack_require__(1).kMaxLength;\nvar kRangeErrorMessage = 'Cannot create final Buffer. It would be larger ' + 'than 0x' + kMaxLength.toString(16) + ' bytes';\n\n// zlib doesn't provide these, so kludge them in following the same\n// const naming scheme zlib uses.\nbinding.Z_MIN_WINDOWBITS = 8;\nbinding.Z_MAX_WINDOWBITS = 15;\nbinding.Z_DEFAULT_WINDOWBITS = 15;\n\n// fewer than 64 bytes per chunk is stupid.\n// technically it could work with as few as 8, but even 64 bytes\n// is absurdly low.  Usually a MB or more is best.\nbinding.Z_MIN_CHUNK = 64;\nbinding.Z_MAX_CHUNK = Infinity;\nbinding.Z_DEFAULT_CHUNK = 16 * 1024;\n\nbinding.Z_MIN_MEMLEVEL = 1;\nbinding.Z_MAX_MEMLEVEL = 9;\nbinding.Z_DEFAULT_MEMLEVEL = 8;\n\nbinding.Z_MIN_LEVEL = -1;\nbinding.Z_MAX_LEVEL = 9;\nbinding.Z_DEFAULT_LEVEL = binding.Z_DEFAULT_COMPRESSION;\n\n// expose all the zlib constants\nvar bkeys = Object.keys(binding);\nfor (var bk = 0; bk < bkeys.length; bk++) {\n  var bkey = bkeys[bk];\n  if (bkey.match(/^Z/)) {\n    Object.defineProperty(exports, bkey, {\n      enumerable: true, value: binding[bkey], writable: false\n    });\n  }\n}\n\n// translation table for return codes.\nvar codes = {\n  Z_OK: binding.Z_OK,\n  Z_STREAM_END: binding.Z_STREAM_END,\n  Z_NEED_DICT: binding.Z_NEED_DICT,\n  Z_ERRNO: binding.Z_ERRNO,\n  Z_STREAM_ERROR: binding.Z_STREAM_ERROR,\n  Z_DATA_ERROR: binding.Z_DATA_ERROR,\n  Z_MEM_ERROR: binding.Z_MEM_ERROR,\n  Z_BUF_ERROR: binding.Z_BUF_ERROR,\n  Z_VERSION_ERROR: binding.Z_VERSION_ERROR\n};\n\nvar ckeys = Object.keys(codes);\nfor (var ck = 0; ck < ckeys.length; ck++) {\n  var ckey = ckeys[ck];\n  codes[codes[ckey]] = ckey;\n}\n\nObject.defineProperty(exports, 'codes', {\n  enumerable: true, value: Object.freeze(codes), writable: false\n});\n\nexports.Deflate = Deflate;\nexports.Inflate = Inflate;\nexports.Gzip = Gzip;\nexports.Gunzip = Gunzip;\nexports.DeflateRaw = DeflateRaw;\nexports.InflateRaw = InflateRaw;\nexports.Unzip = Unzip;\n\nexports.createDeflate = function (o) {\n  return new Deflate(o);\n};\n\nexports.createInflate = function (o) {\n  return new Inflate(o);\n};\n\nexports.createDeflateRaw = function (o) {\n  return new DeflateRaw(o);\n};\n\nexports.createInflateRaw = function (o) {\n  return new InflateRaw(o);\n};\n\nexports.createGzip = function (o) {\n  return new Gzip(o);\n};\n\nexports.createGunzip = function (o) {\n  return new Gunzip(o);\n};\n\nexports.createUnzip = function (o) {\n  return new Unzip(o);\n};\n\n// Convenience methods.\n// compress/decompress a string or buffer in one step.\nexports.deflate = function (buffer, opts, callback) {\n  if (typeof opts === 'function') {\n    callback = opts;\n    opts = {};\n  }\n  return zlibBuffer(new Deflate(opts), buffer, callback);\n};\n\nexports.deflateSync = function (buffer, opts) {\n  return zlibBufferSync(new Deflate(opts), buffer);\n};\n\nexports.gzip = function (buffer, opts, callback) {\n  if (typeof opts === 'function') {\n    callback = opts;\n    opts = {};\n  }\n  return zlibBuffer(new Gzip(opts), buffer, callback);\n};\n\nexports.gzipSync = function (buffer, opts) {\n  return zlibBufferSync(new Gzip(opts), buffer);\n};\n\nexports.deflateRaw = function (buffer, opts, callback) {\n  if (typeof opts === 'function') {\n    callback = opts;\n    opts = {};\n  }\n  return zlibBuffer(new DeflateRaw(opts), buffer, callback);\n};\n\nexports.deflateRawSync = function (buffer, opts) {\n  return zlibBufferSync(new DeflateRaw(opts), buffer);\n};\n\nexports.unzip = function (buffer, opts, callback) {\n  if (typeof opts === 'function') {\n    callback = opts;\n    opts = {};\n  }\n  return zlibBuffer(new Unzip(opts), buffer, callback);\n};\n\nexports.unzipSync = function (buffer, opts) {\n  return zlibBufferSync(new Unzip(opts), buffer);\n};\n\nexports.inflate = function (buffer, opts, callback) {\n  if (typeof opts === 'function') {\n    callback = opts;\n    opts = {};\n  }\n  return zlibBuffer(new Inflate(opts), buffer, callback);\n};\n\nexports.inflateSync = function (buffer, opts) {\n  return zlibBufferSync(new Inflate(opts), buffer);\n};\n\nexports.gunzip = function (buffer, opts, callback) {\n  if (typeof opts === 'function') {\n    callback = opts;\n    opts = {};\n  }\n  return zlibBuffer(new Gunzip(opts), buffer, callback);\n};\n\nexports.gunzipSync = function (buffer, opts) {\n  return zlibBufferSync(new Gunzip(opts), buffer);\n};\n\nexports.inflateRaw = function (buffer, opts, callback) {\n  if (typeof opts === 'function') {\n    callback = opts;\n    opts = {};\n  }\n  return zlibBuffer(new InflateRaw(opts), buffer, callback);\n};\n\nexports.inflateRawSync = function (buffer, opts) {\n  return zlibBufferSync(new InflateRaw(opts), buffer);\n};\n\nfunction zlibBuffer(engine, buffer, callback) {\n  var buffers = [];\n  var nread = 0;\n\n  engine.on('error', onError);\n  engine.on('end', onEnd);\n\n  engine.end(buffer);\n  flow();\n\n  function flow() {\n    var chunk;\n    while (null !== (chunk = engine.read())) {\n      buffers.push(chunk);\n      nread += chunk.length;\n    }\n    engine.once('readable', flow);\n  }\n\n  function onError(err) {\n    engine.removeListener('end', onEnd);\n    engine.removeListener('readable', flow);\n    callback(err);\n  }\n\n  function onEnd() {\n    var buf;\n    var err = null;\n\n    if (nread >= kMaxLength) {\n      err = new RangeError(kRangeErrorMessage);\n    } else {\n      buf = Buffer.concat(buffers, nread);\n    }\n\n    buffers = [];\n    engine.close();\n    callback(err, buf);\n  }\n}\n\nfunction zlibBufferSync(engine, buffer) {\n  if (typeof buffer === 'string') buffer = Buffer.from(buffer);\n\n  if (!Buffer.isBuffer(buffer)) throw new TypeError('Not a string or buffer');\n\n  var flushFlag = engine._finishFlushFlag;\n\n  return engine._processChunk(buffer, flushFlag);\n}\n\n// generic zlib\n// minimal 2-byte header\nfunction Deflate(opts) {\n  if (!(this instanceof Deflate)) return new Deflate(opts);\n  Zlib.call(this, opts, binding.DEFLATE);\n}\n\nfunction Inflate(opts) {\n  if (!(this instanceof Inflate)) return new Inflate(opts);\n  Zlib.call(this, opts, binding.INFLATE);\n}\n\n// gzip - bigger header, same deflate compression\nfunction Gzip(opts) {\n  if (!(this instanceof Gzip)) return new Gzip(opts);\n  Zlib.call(this, opts, binding.GZIP);\n}\n\nfunction Gunzip(opts) {\n  if (!(this instanceof Gunzip)) return new Gunzip(opts);\n  Zlib.call(this, opts, binding.GUNZIP);\n}\n\n// raw - no header\nfunction DeflateRaw(opts) {\n  if (!(this instanceof DeflateRaw)) return new DeflateRaw(opts);\n  Zlib.call(this, opts, binding.DEFLATERAW);\n}\n\nfunction InflateRaw(opts) {\n  if (!(this instanceof InflateRaw)) return new InflateRaw(opts);\n  Zlib.call(this, opts, binding.INFLATERAW);\n}\n\n// auto-detect header.\nfunction Unzip(opts) {\n  if (!(this instanceof Unzip)) return new Unzip(opts);\n  Zlib.call(this, opts, binding.UNZIP);\n}\n\nfunction isValidFlushFlag(flag) {\n  return flag === binding.Z_NO_FLUSH || flag === binding.Z_PARTIAL_FLUSH || flag === binding.Z_SYNC_FLUSH || flag === binding.Z_FULL_FLUSH || flag === binding.Z_FINISH || flag === binding.Z_BLOCK;\n}\n\n// the Zlib class they all inherit from\n// This thing manages the queue of requests, and returns\n// true or false if there is anything in the queue when\n// you call the .write() method.\n\nfunction Zlib(opts, mode) {\n  var _this = this;\n\n  this._opts = opts = opts || {};\n  this._chunkSize = opts.chunkSize || exports.Z_DEFAULT_CHUNK;\n\n  Transform.call(this, opts);\n\n  if (opts.flush && !isValidFlushFlag(opts.flush)) {\n    throw new Error('Invalid flush flag: ' + opts.flush);\n  }\n  if (opts.finishFlush && !isValidFlushFlag(opts.finishFlush)) {\n    throw new Error('Invalid flush flag: ' + opts.finishFlush);\n  }\n\n  this._flushFlag = opts.flush || binding.Z_NO_FLUSH;\n  this._finishFlushFlag = typeof opts.finishFlush !== 'undefined' ? opts.finishFlush : binding.Z_FINISH;\n\n  if (opts.chunkSize) {\n    if (opts.chunkSize < exports.Z_MIN_CHUNK || opts.chunkSize > exports.Z_MAX_CHUNK) {\n      throw new Error('Invalid chunk size: ' + opts.chunkSize);\n    }\n  }\n\n  if (opts.windowBits) {\n    if (opts.windowBits < exports.Z_MIN_WINDOWBITS || opts.windowBits > exports.Z_MAX_WINDOWBITS) {\n      throw new Error('Invalid windowBits: ' + opts.windowBits);\n    }\n  }\n\n  if (opts.level) {\n    if (opts.level < exports.Z_MIN_LEVEL || opts.level > exports.Z_MAX_LEVEL) {\n      throw new Error('Invalid compression level: ' + opts.level);\n    }\n  }\n\n  if (opts.memLevel) {\n    if (opts.memLevel < exports.Z_MIN_MEMLEVEL || opts.memLevel > exports.Z_MAX_MEMLEVEL) {\n      throw new Error('Invalid memLevel: ' + opts.memLevel);\n    }\n  }\n\n  if (opts.strategy) {\n    if (opts.strategy != exports.Z_FILTERED && opts.strategy != exports.Z_HUFFMAN_ONLY && opts.strategy != exports.Z_RLE && opts.strategy != exports.Z_FIXED && opts.strategy != exports.Z_DEFAULT_STRATEGY) {\n      throw new Error('Invalid strategy: ' + opts.strategy);\n    }\n  }\n\n  if (opts.dictionary) {\n    if (!Buffer.isBuffer(opts.dictionary)) {\n      throw new Error('Invalid dictionary: it should be a Buffer instance');\n    }\n  }\n\n  this._handle = new binding.Zlib(mode);\n\n  var self = this;\n  this._hadError = false;\n  this._handle.onerror = function (message, errno) {\n    // there is no way to cleanly recover.\n    // continuing only obscures problems.\n    _close(self);\n    self._hadError = true;\n\n    var error = new Error(message);\n    error.errno = errno;\n    error.code = exports.codes[errno];\n    self.emit('error', error);\n  };\n\n  var level = exports.Z_DEFAULT_COMPRESSION;\n  if (typeof opts.level === 'number') level = opts.level;\n\n  var strategy = exports.Z_DEFAULT_STRATEGY;\n  if (typeof opts.strategy === 'number') strategy = opts.strategy;\n\n  this._handle.init(opts.windowBits || exports.Z_DEFAULT_WINDOWBITS, level, opts.memLevel || exports.Z_DEFAULT_MEMLEVEL, strategy, opts.dictionary);\n\n  this._buffer = Buffer.allocUnsafe(this._chunkSize);\n  this._offset = 0;\n  this._level = level;\n  this._strategy = strategy;\n\n  this.once('end', this.close);\n\n  Object.defineProperty(this, '_closed', {\n    get: function () {\n      return !_this._handle;\n    },\n    configurable: true,\n    enumerable: true\n  });\n}\n\nutil.inherits(Zlib, Transform);\n\nZlib.prototype.params = function (level, strategy, callback) {\n  if (level < exports.Z_MIN_LEVEL || level > exports.Z_MAX_LEVEL) {\n    throw new RangeError('Invalid compression level: ' + level);\n  }\n  if (strategy != exports.Z_FILTERED && strategy != exports.Z_HUFFMAN_ONLY && strategy != exports.Z_RLE && strategy != exports.Z_FIXED && strategy != exports.Z_DEFAULT_STRATEGY) {\n    throw new TypeError('Invalid strategy: ' + strategy);\n  }\n\n  if (this._level !== level || this._strategy !== strategy) {\n    var self = this;\n    this.flush(binding.Z_SYNC_FLUSH, function () {\n      assert(self._handle, 'zlib binding closed');\n      self._handle.params(level, strategy);\n      if (!self._hadError) {\n        self._level = level;\n        self._strategy = strategy;\n        if (callback) callback();\n      }\n    });\n  } else {\n    process.nextTick(callback);\n  }\n};\n\nZlib.prototype.reset = function () {\n  assert(this._handle, 'zlib binding closed');\n  return this._handle.reset();\n};\n\n// This is the _flush function called by the transform class,\n// internally, when the last chunk has been written.\nZlib.prototype._flush = function (callback) {\n  this._transform(Buffer.alloc(0), '', callback);\n};\n\nZlib.prototype.flush = function (kind, callback) {\n  var _this2 = this;\n\n  var ws = this._writableState;\n\n  if (typeof kind === 'function' || kind === undefined && !callback) {\n    callback = kind;\n    kind = binding.Z_FULL_FLUSH;\n  }\n\n  if (ws.ended) {\n    if (callback) process.nextTick(callback);\n  } else if (ws.ending) {\n    if (callback) this.once('end', callback);\n  } else if (ws.needDrain) {\n    if (callback) {\n      this.once('drain', function () {\n        return _this2.flush(kind, callback);\n      });\n    }\n  } else {\n    this._flushFlag = kind;\n    this.write(Buffer.alloc(0), '', callback);\n  }\n};\n\nZlib.prototype.close = function (callback) {\n  _close(this, callback);\n  process.nextTick(emitCloseNT, this);\n};\n\nfunction _close(engine, callback) {\n  if (callback) process.nextTick(callback);\n\n  // Caller may invoke .close after a zlib error (which will null _handle).\n  if (!engine._handle) return;\n\n  engine._handle.close();\n  engine._handle = null;\n}\n\nfunction emitCloseNT(self) {\n  self.emit('close');\n}\n\nZlib.prototype._transform = function (chunk, encoding, cb) {\n  var flushFlag;\n  var ws = this._writableState;\n  var ending = ws.ending || ws.ended;\n  var last = ending && (!chunk || ws.length === chunk.length);\n\n  if (chunk !== null && !Buffer.isBuffer(chunk)) return cb(new Error('invalid input'));\n\n  if (!this._handle) return cb(new Error('zlib binding closed'));\n\n  // If it's the last chunk, or a final flush, we use the Z_FINISH flush flag\n  // (or whatever flag was provided using opts.finishFlush).\n  // If it's explicitly flushing at some other time, then we use\n  // Z_FULL_FLUSH. Otherwise, use Z_NO_FLUSH for maximum compression\n  // goodness.\n  if (last) flushFlag = this._finishFlushFlag;else {\n    flushFlag = this._flushFlag;\n    // once we've flushed the last of the queue, stop flushing and\n    // go back to the normal behavior.\n    if (chunk.length >= ws.length) {\n      this._flushFlag = this._opts.flush || binding.Z_NO_FLUSH;\n    }\n  }\n\n  this._processChunk(chunk, flushFlag, cb);\n};\n\nZlib.prototype._processChunk = function (chunk, flushFlag, cb) {\n  var availInBefore = chunk && chunk.length;\n  var availOutBefore = this._chunkSize - this._offset;\n  var inOff = 0;\n\n  var self = this;\n\n  var async = typeof cb === 'function';\n\n  if (!async) {\n    var buffers = [];\n    var nread = 0;\n\n    var error;\n    this.on('error', function (er) {\n      error = er;\n    });\n\n    assert(this._handle, 'zlib binding closed');\n    do {\n      var res = this._handle.writeSync(flushFlag, chunk, // in\n      inOff, // in_off\n      availInBefore, // in_len\n      this._buffer, // out\n      this._offset, //out_off\n      availOutBefore); // out_len\n    } while (!this._hadError && callback(res[0], res[1]));\n\n    if (this._hadError) {\n      throw error;\n    }\n\n    if (nread >= kMaxLength) {\n      _close(this);\n      throw new RangeError(kRangeErrorMessage);\n    }\n\n    var buf = Buffer.concat(buffers, nread);\n    _close(this);\n\n    return buf;\n  }\n\n  assert(this._handle, 'zlib binding closed');\n  var req = this._handle.write(flushFlag, chunk, // in\n  inOff, // in_off\n  availInBefore, // in_len\n  this._buffer, // out\n  this._offset, //out_off\n  availOutBefore); // out_len\n\n  req.buffer = chunk;\n  req.callback = callback;\n\n  function callback(availInAfter, availOutAfter) {\n    // When the callback is used in an async write, the callback's\n    // context is the `req` object that was created. The req object\n    // is === this._handle, and that's why it's important to null\n    // out the values after they are done being used. `this._handle`\n    // can stay in memory longer than the callback and buffer are needed.\n    if (this) {\n      this.buffer = null;\n      this.callback = null;\n    }\n\n    if (self._hadError) return;\n\n    var have = availOutBefore - availOutAfter;\n    assert(have >= 0, 'have should not go down');\n\n    if (have > 0) {\n      var out = self._buffer.slice(self._offset, self._offset + have);\n      self._offset += have;\n      // serve some output to the consumer.\n      if (async) {\n        self.push(out);\n      } else {\n        buffers.push(out);\n        nread += out.length;\n      }\n    }\n\n    // exhausted the output buffer, or used all the input create a new one.\n    if (availOutAfter === 0 || self._offset >= self._chunkSize) {\n      availOutBefore = self._chunkSize;\n      self._offset = 0;\n      self._buffer = Buffer.allocUnsafe(self._chunkSize);\n    }\n\n    if (availOutAfter === 0) {\n      // Not actually done.  Need to reprocess.\n      // Also, update the availInBefore to the availInAfter value,\n      // so that if we have to hit it a third (fourth, etc.) time,\n      // it'll have the correct byte counts.\n      inOff += availInBefore - availInAfter;\n      availInBefore = availInAfter;\n\n      if (!async) return true;\n\n      var newReq = self._handle.write(flushFlag, chunk, inOff, availInBefore, self._buffer, self._offset, self._chunkSize);\n      newReq.callback = callback; // this same function\n      newReq.buffer = chunk;\n      return;\n    }\n\n    if (!async) return false;\n\n    // finished with the chunk.\n    cb();\n  }\n};\n\nutil.inherits(Deflate, Zlib);\nutil.inherits(Inflate, Zlib);\nutil.inherits(Gzip, Zlib);\nutil.inherits(Gunzip, Zlib);\nutil.inherits(DeflateRaw, Zlib);\nutil.inherits(InflateRaw, Zlib);\nutil.inherits(Unzip, Zlib);\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11)))\n\n/***/ }),\n/* 49 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(global, process) {// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nvar formatRegExp = /%[sdj%]/g;\nexports.format = function(f) {\n  if (!isString(f)) {\n    var objects = [];\n    for (var i = 0; i < arguments.length; i++) {\n      objects.push(inspect(arguments[i]));\n    }\n    return objects.join(' ');\n  }\n\n  var i = 1;\n  var args = arguments;\n  var len = args.length;\n  var str = String(f).replace(formatRegExp, function(x) {\n    if (x === '%%') return '%';\n    if (i >= len) return x;\n    switch (x) {\n      case '%s': return String(args[i++]);\n      case '%d': return Number(args[i++]);\n      case '%j':\n        try {\n          return JSON.stringify(args[i++]);\n        } catch (_) {\n          return '[Circular]';\n        }\n      default:\n        return x;\n    }\n  });\n  for (var x = args[i]; i < len; x = args[++i]) {\n    if (isNull(x) || !isObject(x)) {\n      str += ' ' + x;\n    } else {\n      str += ' ' + inspect(x);\n    }\n  }\n  return str;\n};\n\n\n// Mark that a method should not be used.\n// Returns a modified function which warns once by default.\n// If --no-deprecation is set, then it is a no-op.\nexports.deprecate = function(fn, msg) {\n  // Allow for deprecating things in the process of starting up.\n  if (isUndefined(global.process)) {\n    return function() {\n      return exports.deprecate(fn, msg).apply(this, arguments);\n    };\n  }\n\n  if (process.noDeprecation === true) {\n    return fn;\n  }\n\n  var warned = false;\n  function deprecated() {\n    if (!warned) {\n      if (process.throwDeprecation) {\n        throw new Error(msg);\n      } else if (process.traceDeprecation) {\n        console.trace(msg);\n      } else {\n        console.error(msg);\n      }\n      warned = true;\n    }\n    return fn.apply(this, arguments);\n  }\n\n  return deprecated;\n};\n\n\nvar debugs = {};\nvar debugEnviron;\nexports.debuglog = function(set) {\n  if (isUndefined(debugEnviron))\n    debugEnviron = process.env.NODE_DEBUG || '';\n  set = set.toUpperCase();\n  if (!debugs[set]) {\n    if (new RegExp('\\\\b' + set + '\\\\b', 'i').test(debugEnviron)) {\n      var pid = process.pid;\n      debugs[set] = function() {\n        var msg = exports.format.apply(exports, arguments);\n        console.error('%s %d: %s', set, pid, msg);\n      };\n    } else {\n      debugs[set] = function() {};\n    }\n  }\n  return debugs[set];\n};\n\n\n/**\n * Echos the value of a value. Trys to print the value out\n * in the best way possible given the different types.\n *\n * @param {Object} obj The object to print out.\n * @param {Object} opts Optional options object that alters the output.\n */\n/* legacy: obj, showHidden, depth, colors*/\nfunction inspect(obj, opts) {\n  // default options\n  var ctx = {\n    seen: [],\n    stylize: stylizeNoColor\n  };\n  // legacy...\n  if (arguments.length >= 3) ctx.depth = arguments[2];\n  if (arguments.length >= 4) ctx.colors = arguments[3];\n  if (isBoolean(opts)) {\n    // legacy...\n    ctx.showHidden = opts;\n  } else if (opts) {\n    // got an \"options\" object\n    exports._extend(ctx, opts);\n  }\n  // set default options\n  if (isUndefined(ctx.showHidden)) ctx.showHidden = false;\n  if (isUndefined(ctx.depth)) ctx.depth = 2;\n  if (isUndefined(ctx.colors)) ctx.colors = false;\n  if (isUndefined(ctx.customInspect)) ctx.customInspect = true;\n  if (ctx.colors) ctx.stylize = stylizeWithColor;\n  return formatValue(ctx, obj, ctx.depth);\n}\nexports.inspect = inspect;\n\n\n// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics\ninspect.colors = {\n  'bold' : [1, 22],\n  'italic' : [3, 23],\n  'underline' : [4, 24],\n  'inverse' : [7, 27],\n  'white' : [37, 39],\n  'grey' : [90, 39],\n  'black' : [30, 39],\n  'blue' : [34, 39],\n  'cyan' : [36, 39],\n  'green' : [32, 39],\n  'magenta' : [35, 39],\n  'red' : [31, 39],\n  'yellow' : [33, 39]\n};\n\n// Don't use 'blue' not visible on cmd.exe\ninspect.styles = {\n  'special': 'cyan',\n  'number': 'yellow',\n  'boolean': 'yellow',\n  'undefined': 'grey',\n  'null': 'bold',\n  'string': 'green',\n  'date': 'magenta',\n  // \"name\": intentionally not styling\n  'regexp': 'red'\n};\n\n\nfunction stylizeWithColor(str, styleType) {\n  var style = inspect.styles[styleType];\n\n  if (style) {\n    return '\\u001b[' + inspect.colors[style][0] + 'm' + str +\n           '\\u001b[' + inspect.colors[style][1] + 'm';\n  } else {\n    return str;\n  }\n}\n\n\nfunction stylizeNoColor(str, styleType) {\n  return str;\n}\n\n\nfunction arrayToHash(array) {\n  var hash = {};\n\n  array.forEach(function(val, idx) {\n    hash[val] = true;\n  });\n\n  return hash;\n}\n\n\nfunction formatValue(ctx, value, recurseTimes) {\n  // Provide a hook for user-specified inspect functions.\n  // Check that value is an object with an inspect function on it\n  if (ctx.customInspect &&\n      value &&\n      isFunction(value.inspect) &&\n      // Filter out the util module, it's inspect function is special\n      value.inspect !== exports.inspect &&\n      // Also filter out any prototype objects using the circular check.\n      !(value.constructor && value.constructor.prototype === value)) {\n    var ret = value.inspect(recurseTimes, ctx);\n    if (!isString(ret)) {\n      ret = formatValue(ctx, ret, recurseTimes);\n    }\n    return ret;\n  }\n\n  // Primitive types cannot have properties\n  var primitive = formatPrimitive(ctx, value);\n  if (primitive) {\n    return primitive;\n  }\n\n  // Look up the keys of the object.\n  var keys = Object.keys(value);\n  var visibleKeys = arrayToHash(keys);\n\n  if (ctx.showHidden) {\n    keys = Object.getOwnPropertyNames(value);\n  }\n\n  // IE doesn't make error fields non-enumerable\n  // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx\n  if (isError(value)\n      && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {\n    return formatError(value);\n  }\n\n  // Some type of object without properties can be shortcutted.\n  if (keys.length === 0) {\n    if (isFunction(value)) {\n      var name = value.name ? ': ' + value.name : '';\n      return ctx.stylize('[Function' + name + ']', 'special');\n    }\n    if (isRegExp(value)) {\n      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');\n    }\n    if (isDate(value)) {\n      return ctx.stylize(Date.prototype.toString.call(value), 'date');\n    }\n    if (isError(value)) {\n      return formatError(value);\n    }\n  }\n\n  var base = '', array = false, braces = ['{', '}'];\n\n  // Make Array say that they are Array\n  if (isArray(value)) {\n    array = true;\n    braces = ['[', ']'];\n  }\n\n  // Make functions say that they are functions\n  if (isFunction(value)) {\n    var n = value.name ? ': ' + value.name : '';\n    base = ' [Function' + n + ']';\n  }\n\n  // Make RegExps say that they are RegExps\n  if (isRegExp(value)) {\n    base = ' ' + RegExp.prototype.toString.call(value);\n  }\n\n  // Make dates with properties first say the date\n  if (isDate(value)) {\n    base = ' ' + Date.prototype.toUTCString.call(value);\n  }\n\n  // Make error with message first say the error\n  if (isError(value)) {\n    base = ' ' + formatError(value);\n  }\n\n  if (keys.length === 0 && (!array || value.length == 0)) {\n    return braces[0] + base + braces[1];\n  }\n\n  if (recurseTimes < 0) {\n    if (isRegExp(value)) {\n      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');\n    } else {\n      return ctx.stylize('[Object]', 'special');\n    }\n  }\n\n  ctx.seen.push(value);\n\n  var output;\n  if (array) {\n    output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);\n  } else {\n    output = keys.map(function(key) {\n      return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);\n    });\n  }\n\n  ctx.seen.pop();\n\n  return reduceToSingleString(output, base, braces);\n}\n\n\nfunction formatPrimitive(ctx, value) {\n  if (isUndefined(value))\n    return ctx.stylize('undefined', 'undefined');\n  if (isString(value)) {\n    var simple = '\\'' + JSON.stringify(value).replace(/^\"|\"$/g, '')\n                                             .replace(/'/g, \"\\\\'\")\n                                             .replace(/\\\\\"/g, '\"') + '\\'';\n    return ctx.stylize(simple, 'string');\n  }\n  if (isNumber(value))\n    return ctx.stylize('' + value, 'number');\n  if (isBoolean(value))\n    return ctx.stylize('' + value, 'boolean');\n  // For some reason typeof null is \"object\", so special case here.\n  if (isNull(value))\n    return ctx.stylize('null', 'null');\n}\n\n\nfunction formatError(value) {\n  return '[' + Error.prototype.toString.call(value) + ']';\n}\n\n\nfunction formatArray(ctx, value, recurseTimes, visibleKeys, keys) {\n  var output = [];\n  for (var i = 0, l = value.length; i < l; ++i) {\n    if (hasOwnProperty(value, String(i))) {\n      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,\n          String(i), true));\n    } else {\n      output.push('');\n    }\n  }\n  keys.forEach(function(key) {\n    if (!key.match(/^\\d+$/)) {\n      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,\n          key, true));\n    }\n  });\n  return output;\n}\n\n\nfunction formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {\n  var name, str, desc;\n  desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };\n  if (desc.get) {\n    if (desc.set) {\n      str = ctx.stylize('[Getter/Setter]', 'special');\n    } else {\n      str = ctx.stylize('[Getter]', 'special');\n    }\n  } else {\n    if (desc.set) {\n      str = ctx.stylize('[Setter]', 'special');\n    }\n  }\n  if (!hasOwnProperty(visibleKeys, key)) {\n    name = '[' + key + ']';\n  }\n  if (!str) {\n    if (ctx.seen.indexOf(desc.value) < 0) {\n      if (isNull(recurseTimes)) {\n        str = formatValue(ctx, desc.value, null);\n      } else {\n        str = formatValue(ctx, desc.value, recurseTimes - 1);\n      }\n      if (str.indexOf('\\n') > -1) {\n        if (array) {\n          str = str.split('\\n').map(function(line) {\n            return '  ' + line;\n          }).join('\\n').substr(2);\n        } else {\n          str = '\\n' + str.split('\\n').map(function(line) {\n            return '   ' + line;\n          }).join('\\n');\n        }\n      }\n    } else {\n      str = ctx.stylize('[Circular]', 'special');\n    }\n  }\n  if (isUndefined(name)) {\n    if (array && key.match(/^\\d+$/)) {\n      return str;\n    }\n    name = JSON.stringify('' + key);\n    if (name.match(/^\"([a-zA-Z_][a-zA-Z_0-9]*)\"$/)) {\n      name = name.substr(1, name.length - 2);\n      name = ctx.stylize(name, 'name');\n    } else {\n      name = name.replace(/'/g, \"\\\\'\")\n                 .replace(/\\\\\"/g, '\"')\n                 .replace(/(^\"|\"$)/g, \"'\");\n      name = ctx.stylize(name, 'string');\n    }\n  }\n\n  return name + ': ' + str;\n}\n\n\nfunction reduceToSingleString(output, base, braces) {\n  var numLinesEst = 0;\n  var length = output.reduce(function(prev, cur) {\n    numLinesEst++;\n    if (cur.indexOf('\\n') >= 0) numLinesEst++;\n    return prev + cur.replace(/\\u001b\\[\\d\\d?m/g, '').length + 1;\n  }, 0);\n\n  if (length > 60) {\n    return braces[0] +\n           (base === '' ? '' : base + '\\n ') +\n           ' ' +\n           output.join(',\\n  ') +\n           ' ' +\n           braces[1];\n  }\n\n  return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];\n}\n\n\n// NOTE: These type checking functions intentionally don't use `instanceof`\n// because it is fragile and can be easily faked with `Object.create()`.\nfunction isArray(ar) {\n  return Array.isArray(ar);\n}\nexports.isArray = isArray;\n\nfunction isBoolean(arg) {\n  return typeof arg === 'boolean';\n}\nexports.isBoolean = isBoolean;\n\nfunction isNull(arg) {\n  return arg === null;\n}\nexports.isNull = isNull;\n\nfunction isNullOrUndefined(arg) {\n  return arg == null;\n}\nexports.isNullOrUndefined = isNullOrUndefined;\n\nfunction isNumber(arg) {\n  return typeof arg === 'number';\n}\nexports.isNumber = isNumber;\n\nfunction isString(arg) {\n  return typeof arg === 'string';\n}\nexports.isString = isString;\n\nfunction isSymbol(arg) {\n  return typeof arg === 'symbol';\n}\nexports.isSymbol = isSymbol;\n\nfunction isUndefined(arg) {\n  return arg === void 0;\n}\nexports.isUndefined = isUndefined;\n\nfunction isRegExp(re) {\n  return isObject(re) && objectToString(re) === '[object RegExp]';\n}\nexports.isRegExp = isRegExp;\n\nfunction isObject(arg) {\n  return typeof arg === 'object' && arg !== null;\n}\nexports.isObject = isObject;\n\nfunction isDate(d) {\n  return isObject(d) && objectToString(d) === '[object Date]';\n}\nexports.isDate = isDate;\n\nfunction isError(e) {\n  return isObject(e) &&\n      (objectToString(e) === '[object Error]' || e instanceof Error);\n}\nexports.isError = isError;\n\nfunction isFunction(arg) {\n  return typeof arg === 'function';\n}\nexports.isFunction = isFunction;\n\nfunction isPrimitive(arg) {\n  return arg === null ||\n         typeof arg === 'boolean' ||\n         typeof arg === 'number' ||\n         typeof arg === 'string' ||\n         typeof arg === 'symbol' ||  // ES6 symbol\n         typeof arg === 'undefined';\n}\nexports.isPrimitive = isPrimitive;\n\nexports.isBuffer = __webpack_require__(151);\n\nfunction objectToString(o) {\n  return Object.prototype.toString.call(o);\n}\n\n\nfunction pad(n) {\n  return n < 10 ? '0' + n.toString(10) : n.toString(10);\n}\n\n\nvar months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',\n              'Oct', 'Nov', 'Dec'];\n\n// 26 Feb 16:19:34\nfunction timestamp() {\n  var d = new Date();\n  var time = [pad(d.getHours()),\n              pad(d.getMinutes()),\n              pad(d.getSeconds())].join(':');\n  return [d.getDate(), months[d.getMonth()], time].join(' ');\n}\n\n\n// log is just a thin wrapper to console.log that prepends a timestamp\nexports.log = function() {\n  console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));\n};\n\n\n/**\n * Inherit the prototype methods from one constructor into another.\n *\n * The Function.prototype.inherits from lang.js rewritten as a standalone\n * function (not on Function.prototype). NOTE: If this file is to be loaded\n * during bootstrapping this function needs to be rewritten using some native\n * functions as prototype setup using normal JavaScript does not work as\n * expected during bootstrapping (see mirror.js in r114903).\n *\n * @param {function} ctor Constructor function which needs to inherit the\n *     prototype.\n * @param {function} superCtor Constructor function to inherit prototype from.\n */\nexports.inherits = __webpack_require__(152);\n\nexports._extend = function(origin, add) {\n  // Don't do anything if add isn't an object\n  if (!add || !isObject(add)) return origin;\n\n  var keys = Object.keys(add);\n  var i = keys.length;\n  while (i--) {\n    origin[keys[i]] = add[keys[i]];\n  }\n  return origin;\n};\n\nfunction hasOwnProperty(obj, prop) {\n  return Object.prototype.hasOwnProperty.call(obj, prop);\n}\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7), __webpack_require__(11)))\n\n/***/ }),\n/* 50 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6\n(function() {\n  var EmbeddedFont, PDFFont, StandardFont, fontkit;\n\n  fontkit = __webpack_require__(167);\n\n  PDFFont = (function() {\n    PDFFont.open = function(document, src, family, id) {\n      var font;\n      if (typeof src === 'string') {\n        if (StandardFont.isStandardFont(src)) {\n          return new StandardFont(document, src, id);\n        }\n        font = fontkit.openSync(src, family);\n      } else if (Buffer.isBuffer(src)) {\n        font = fontkit.create(src, family);\n      } else if (src instanceof Uint8Array) {\n        font = fontkit.create(new Buffer(src), family);\n      } else if (src instanceof ArrayBuffer) {\n        font = fontkit.create(new Buffer(new Uint8Array(src)), family);\n      }\n      if (font == null) {\n        throw new Error('Not a supported font format or standard PDF font.');\n      }\n      return new EmbeddedFont(document, font, id);\n    };\n\n    function PDFFont() {\n      throw new Error('Cannot construct a PDFFont directly.');\n    }\n\n    PDFFont.prototype.encode = function(text) {\n      throw new Error('Must be implemented by subclasses');\n    };\n\n    PDFFont.prototype.widthOfString = function(text) {\n      throw new Error('Must be implemented by subclasses');\n    };\n\n    PDFFont.prototype.ref = function() {\n      return this.dictionary != null ? this.dictionary : this.dictionary = this.document.ref();\n    };\n\n    PDFFont.prototype.finalize = function() {\n      if (this.embedded || (this.dictionary == null)) {\n        return;\n      }\n      this.embed();\n      return this.embedded = true;\n    };\n\n    PDFFont.prototype.embed = function() {\n      throw new Error('Must be implemented by subclasses');\n    };\n\n    PDFFont.prototype.lineHeight = function(size, includeGap) {\n      var gap;\n      if (includeGap == null) {\n        includeGap = false;\n      }\n      gap = includeGap ? this.lineGap : 0;\n      return (this.ascender + gap - this.descender) / 1000 * size;\n    };\n\n    return PDFFont;\n\n  })();\n\n  module.exports = PDFFont;\n\n  StandardFont = __webpack_require__(292);\n\n  EmbeddedFont = __webpack_require__(294);\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 51 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.7.1\n(function() {\n  var DecodeStream, iconv;\n\n  try {\n    iconv = __webpack_require__(52);\n  } catch (_error) {}\n\n  DecodeStream = (function() {\n    var key;\n\n    function DecodeStream(buffer) {\n      this.buffer = buffer;\n      this.pos = 0;\n      this.length = this.buffer.length;\n    }\n\n    DecodeStream.TYPES = {\n      UInt8: 1,\n      UInt16: 2,\n      UInt24: 3,\n      UInt32: 4,\n      Int8: 1,\n      Int16: 2,\n      Int24: 3,\n      Int32: 4,\n      Float: 4,\n      Double: 8\n    };\n\n    for (key in Buffer.prototype) {\n      if (key.slice(0, 4) === 'read') {\n        (function(key) {\n          var bytes;\n          bytes = DecodeStream.TYPES[key.replace(/read|[BL]E/g, '')];\n          return DecodeStream.prototype[key] = function() {\n            var ret;\n            ret = this.buffer[key](this.pos);\n            this.pos += bytes;\n            return ret;\n          };\n        })(key);\n      }\n    }\n\n    DecodeStream.prototype.readString = function(length, encoding) {\n      var buf, byte, i, _i, _ref;\n      if (encoding == null) {\n        encoding = 'ascii';\n      }\n      switch (encoding) {\n        case 'utf16le':\n        case 'ucs2':\n        case 'utf8':\n        case 'ascii':\n          return this.buffer.toString(encoding, this.pos, this.pos += length);\n        case 'utf16be':\n          buf = new Buffer(this.readBuffer(length));\n          for (i = _i = 0, _ref = buf.length - 1; _i < _ref; i = _i += 2) {\n            byte = buf[i];\n            buf[i] = buf[i + 1];\n            buf[i + 1] = byte;\n          }\n          return buf.toString('utf16le');\n        default:\n          buf = this.readBuffer(length);\n          if (iconv) {\n            try {\n              return iconv.decode(buf, encoding);\n            } catch (_error) {}\n          }\n          return buf;\n      }\n    };\n\n    DecodeStream.prototype.readBuffer = function(length) {\n      return this.buffer.slice(this.pos, this.pos += length);\n    };\n\n    DecodeStream.prototype.readUInt24BE = function() {\n      return (this.readUInt16BE() << 8) + this.readUInt8();\n    };\n\n    DecodeStream.prototype.readUInt24LE = function() {\n      return this.readUInt16LE() + (this.readUInt8() << 16);\n    };\n\n    DecodeStream.prototype.readInt24BE = function() {\n      return (this.readInt16BE() << 8) + this.readUInt8();\n    };\n\n    DecodeStream.prototype.readInt24LE = function() {\n      return this.readUInt16LE() + (this.readInt8() << 16);\n    };\n\n    return DecodeStream;\n\n  })();\n\n  module.exports = DecodeStream;\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 52 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(process) {\n\n// Some environments don't have global Buffer (e.g. React Native).\n// Solution would be installing npm modules \"buffer\" and \"stream\" explicitly.\nvar Buffer = __webpack_require__(1).Buffer;\n\nvar bomHandling = __webpack_require__(170),\n    iconv = module.exports;\n\n// All codecs and aliases are kept here, keyed by encoding name/alias.\n// They are lazy loaded in `iconv.getCodec` from `encodings/index.js`.\niconv.encodings = null;\n\n// Characters emitted in case of error.\niconv.defaultCharUnicode = '�';\niconv.defaultCharSingleByte = '?';\n\n// Public API.\niconv.encode = function encode(str, encoding, options) {\n    str = \"\" + (str || \"\"); // Ensure string.\n\n    var encoder = iconv.getEncoder(encoding, options);\n\n    var res = encoder.write(str);\n    var trail = encoder.end();\n    \n    return (trail && trail.length > 0) ? Buffer.concat([res, trail]) : res;\n}\n\niconv.decode = function decode(buf, encoding, options) {\n    if (typeof buf === 'string') {\n        if (!iconv.skipDecodeWarning) {\n            console.error('Iconv-lite warning: decode()-ing strings is deprecated. Refer to https://github.com/ashtuchkin/iconv-lite/wiki/Use-Buffers-when-decoding');\n            iconv.skipDecodeWarning = true;\n        }\n\n        buf = new Buffer(\"\" + (buf || \"\"), \"binary\"); // Ensure buffer.\n    }\n\n    var decoder = iconv.getDecoder(encoding, options);\n\n    var res = decoder.write(buf);\n    var trail = decoder.end();\n\n    return trail ? (res + trail) : res;\n}\n\niconv.encodingExists = function encodingExists(enc) {\n    try {\n        iconv.getCodec(enc);\n        return true;\n    } catch (e) {\n        return false;\n    }\n}\n\n// Legacy aliases to convert functions\niconv.toEncoding = iconv.encode;\niconv.fromEncoding = iconv.decode;\n\n// Search for a codec in iconv.encodings. Cache codec data in iconv._codecDataCache.\niconv._codecDataCache = {};\niconv.getCodec = function getCodec(encoding) {\n    if (!iconv.encodings)\n        iconv.encodings = __webpack_require__(171); // Lazy load all encoding definitions.\n    \n    // Canonicalize encoding name: strip all non-alphanumeric chars and appended year.\n    var enc = (''+encoding).toLowerCase().replace(/[^0-9a-z]|:\\d{4}$/g, \"\");\n\n    // Traverse iconv.encodings to find actual codec.\n    var codecOptions = {};\n    while (true) {\n        var codec = iconv._codecDataCache[enc];\n        if (codec)\n            return codec;\n\n        var codecDef = iconv.encodings[enc];\n\n        switch (typeof codecDef) {\n            case \"string\": // Direct alias to other encoding.\n                enc = codecDef;\n                break;\n\n            case \"object\": // Alias with options. Can be layered.\n                for (var key in codecDef)\n                    codecOptions[key] = codecDef[key];\n\n                if (!codecOptions.encodingName)\n                    codecOptions.encodingName = enc;\n                \n                enc = codecDef.type;\n                break;\n\n            case \"function\": // Codec itself.\n                if (!codecOptions.encodingName)\n                    codecOptions.encodingName = enc;\n\n                // The codec function must load all tables and return object with .encoder and .decoder methods.\n                // It'll be called only once (for each different options object).\n                codec = new codecDef(codecOptions, iconv);\n\n                iconv._codecDataCache[codecOptions.encodingName] = codec; // Save it to be reused later.\n                return codec;\n\n            default:\n                throw new Error(\"Encoding not recognized: '\" + encoding + \"' (searched as: '\"+enc+\"')\");\n        }\n    }\n}\n\niconv.getEncoder = function getEncoder(encoding, options) {\n    var codec = iconv.getCodec(encoding),\n        encoder = new codec.encoder(options, codec);\n\n    if (codec.bomAware && options && options.addBOM)\n        encoder = new bomHandling.PrependBOM(encoder, options);\n\n    return encoder;\n}\n\niconv.getDecoder = function getDecoder(encoding, options) {\n    var codec = iconv.getCodec(encoding),\n        decoder = new codec.decoder(options, codec);\n\n    if (codec.bomAware && !(options && options.stripBOM === false))\n        decoder = new bomHandling.StripBOM(decoder, options);\n\n    return decoder;\n}\n\n\n// Load extensions in Node. All of them are omitted in Browserify build via 'browser' field in package.json.\nvar nodeVer = typeof process !== 'undefined' && process.versions && process.versions.node;\nif (nodeVer) {\n\n    // Load streaming support in Node v0.10+\n    var nodeVerArr = nodeVer.split(\".\").map(Number);\n    if (nodeVerArr[0] > 0 || nodeVerArr[1] >= 10) {\n        __webpack_require__(185)(iconv);\n    }\n\n    // Load Node primitive extensions.\n    __webpack_require__(186)(iconv);\n}\n\nif (false) {\n    console.error(\"iconv-lite warning: javascript files use encoding different from utf-8. See https://github.com/ashtuchkin/iconv-lite/wiki/Javascript-source-file-encodings for more info.\");\n}\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11)))\n\n/***/ }),\n/* 53 */\n/***/ (function(module, exports) {\n\nmodule.exports = [[\"0\",\"\\u0000\",127,\"€\"],[\"8140\",\"丂丄丅丆丏丒丗丟丠両丣並丩丮丯丱丳丵丷丼乀乁乂乄乆乊乑乕乗乚乛乢乣乤乥乧乨乪\",5,\"乲乴\",9,\"乿\",6,\"亇亊\"],[\"8180\",\"亐亖亗亙亜亝亞亣亪亯亰亱亴亶亷亸亹亼亽亾仈仌仏仐仒仚仛仜仠仢仦仧仩仭仮仯仱仴仸仹仺仼仾伀伂\",6,\"伋伌伒\",4,\"伜伝伡伣伨伩伬伭伮伱伳伵伷伹伻伾\",4,\"佄佅佇\",5,\"佒佔佖佡佢佦佨佪佫佭佮佱佲併佷佸佹佺佽侀侁侂侅來侇侊侌侎侐侒侓侕侖侘侙侚侜侞侟価侢\"],[\"8240\",\"侤侫侭侰\",4,\"侶\",8,\"俀俁係俆俇俈俉俋俌俍俒\",4,\"俙俛俠俢俤俥俧俫俬俰俲俴俵俶俷俹俻俼俽俿\",11],[\"8280\",\"個倎倐們倓倕倖倗倛倝倞倠倢倣値倧倫倯\",10,\"倻倽倿偀偁偂偄偅偆偉偊偋偍偐\",4,\"偖偗偘偙偛偝\",7,\"偦\",5,\"偭\",8,\"偸偹偺偼偽傁傂傃傄傆傇傉傊傋傌傎\",20,\"傤傦傪傫傭\",4,\"傳\",6,\"傼\"],[\"8340\",\"傽\",17,\"僐\",5,\"僗僘僙僛\",10,\"僨僩僪僫僯僰僱僲僴僶\",4,\"僼\",9,\"儈\"],[\"8380\",\"儉儊儌\",5,\"儓\",13,\"儢\",28,\"兂兇兊兌兎兏児兒兓兗兘兙兛兝\",4,\"兣兤兦內兩兪兯兲兺兾兿冃冄円冇冊冋冎冏冐冑冓冔冘冚冝冞冟冡冣冦\",4,\"冭冮冴冸冹冺冾冿凁凂凃凅凈凊凍凎凐凒\",5],[\"8440\",\"凘凙凚凜凞凟凢凣凥\",5,\"凬凮凱凲凴凷凾刄刅刉刋刌刏刐刓刔刕刜刞刟刡刢刣別刦刧刪刬刯刱刲刴刵刼刾剄\",5,\"剋剎剏剒剓剕剗剘\"],[\"8480\",\"剙剚剛剝剟剠剢剣剤剦剨剫剬剭剮剰剱剳\",9,\"剾劀劃\",4,\"劉\",6,\"劑劒劔\",6,\"劜劤劥劦劧劮劯劰労\",9,\"勀勁勂勄勅勆勈勊勌勍勎勏勑勓勔動勗務\",5,\"勠勡勢勣勥\",10,\"勱\",7,\"勻勼勽匁匂匃匄匇匉匊匋匌匎\"],[\"8540\",\"匑匒匓匔匘匛匜匞匟匢匤匥匧匨匩匫匬匭匯\",9,\"匼匽區卂卄卆卋卌卍卐協単卙卛卝卥卨卪卬卭卲卶卹卻卼卽卾厀厁厃厇厈厊厎厏\"],[\"8580\",\"厐\",4,\"厖厗厙厛厜厞厠厡厤厧厪厫厬厭厯\",6,\"厷厸厹厺厼厽厾叀參\",4,\"収叏叐叒叓叕叚叜叝叞叡叢叧叴叺叾叿吀吂吅吇吋吔吘吙吚吜吢吤吥吪吰吳吶吷吺吽吿呁呂呄呅呇呉呌呍呎呏呑呚呝\",4,\"呣呥呧呩\",7,\"呴呹呺呾呿咁咃咅咇咈咉咊咍咑咓咗咘咜咞咟咠咡\"],[\"8640\",\"咢咥咮咰咲咵咶咷咹咺咼咾哃哅哊哋哖哘哛哠\",4,\"哫哬哯哰哱哴\",5,\"哻哾唀唂唃唄唅唈唊\",4,\"唒唓唕\",5,\"唜唝唞唟唡唥唦\"],[\"8680\",\"唨唩唫唭唲唴唵唶唸唹唺唻唽啀啂啅啇啈啋\",4,\"啑啒啓啔啗\",4,\"啝啞啟啠啢啣啨啩啫啯\",5,\"啹啺啽啿喅喆喌喍喎喐喒喓喕喖喗喚喛喞喠\",6,\"喨\",8,\"喲喴営喸喺喼喿\",4,\"嗆嗇嗈嗊嗋嗎嗏嗐嗕嗗\",4,\"嗞嗠嗢嗧嗩嗭嗮嗰嗱嗴嗶嗸\",4,\"嗿嘂嘃嘄嘅\"],[\"8740\",\"嘆嘇嘊嘋嘍嘐\",7,\"嘙嘚嘜嘝嘠嘡嘢嘥嘦嘨嘩嘪嘫嘮嘯嘰嘳嘵嘷嘸嘺嘼嘽嘾噀\",11,\"噏\",4,\"噕噖噚噛噝\",4],[\"8780\",\"噣噥噦噧噭噮噯噰噲噳噴噵噷噸噹噺噽\",7,\"嚇\",6,\"嚐嚑嚒嚔\",14,\"嚤\",10,\"嚰\",6,\"嚸嚹嚺嚻嚽\",12,\"囋\",8,\"囕囖囘囙囜団囥\",5,\"囬囮囯囲図囶囷囸囻囼圀圁圂圅圇國\",6],[\"8840\",\"園\",9,\"圝圞圠圡圢圤圥圦圧圫圱圲圴\",4,\"圼圽圿坁坃坄坅坆坈坉坋坒\",4,\"坘坙坢坣坥坧坬坮坰坱坲坴坵坸坹坺坽坾坿垀\"],[\"8880\",\"垁垇垈垉垊垍\",4,\"垔\",6,\"垜垝垞垟垥垨垪垬垯垰垱垳垵垶垷垹\",8,\"埄\",6,\"埌埍埐埑埓埖埗埛埜埞埡埢埣埥\",7,\"埮埰埱埲埳埵埶執埻埼埾埿堁堃堄堅堈堉堊堌堎堏堐堒堓堔堖堗堘堚堛堜堝堟堢堣堥\",4,\"堫\",4,\"報堲堳場堶\",7],[\"8940\",\"堾\",5,\"塅\",6,\"塎塏塐塒塓塕塖塗塙\",4,\"塟\",5,\"塦\",4,\"塭\",16,\"塿墂墄墆墇墈墊墋墌\"],[\"8980\",\"墍\",4,\"墔\",4,\"墛墜墝墠\",7,\"墪\",17,\"墽墾墿壀壂壃壄壆\",10,\"壒壓壔壖\",13,\"壥\",5,\"壭壯壱売壴壵壷壸壺\",7,\"夃夅夆夈\",4,\"夎夐夑夒夓夗夘夛夝夞夠夡夢夣夦夨夬夰夲夳夵夶夻\"],[\"8a40\",\"夽夾夿奀奃奅奆奊奌奍奐奒奓奙奛\",4,\"奡奣奤奦\",12,\"奵奷奺奻奼奾奿妀妅妉妋妌妎妏妐妑妔妕妘妚妛妜妝妟妠妡妢妦\"],[\"8a80\",\"妧妬妭妰妱妳\",5,\"妺妼妽妿\",6,\"姇姈姉姌姍姎姏姕姖姙姛姞\",4,\"姤姦姧姩姪姫姭\",11,\"姺姼姽姾娀娂娊娋娍娎娏娐娒娔娕娖娗娙娚娛娝娞娡娢娤娦娧娨娪\",6,\"娳娵娷\",4,\"娽娾娿婁\",4,\"婇婈婋\",9,\"婖婗婘婙婛\",5],[\"8b40\",\"婡婣婤婥婦婨婩婫\",8,\"婸婹婻婼婽婾媀\",17,\"媓\",6,\"媜\",13,\"媫媬\"],[\"8b80\",\"媭\",4,\"媴媶媷媹\",4,\"媿嫀嫃\",5,\"嫊嫋嫍\",4,\"嫓嫕嫗嫙嫚嫛嫝嫞嫟嫢嫤嫥嫧嫨嫪嫬\",4,\"嫲\",22,\"嬊\",11,\"嬘\",25,\"嬳嬵嬶嬸\",7,\"孁\",6],[\"8c40\",\"孈\",7,\"孒孖孞孠孡孧孨孫孭孮孯孲孴孶孷學孹孻孼孾孿宂宆宊宍宎宐宑宒宔宖実宧宨宩宬宭宮宯宱宲宷宺宻宼寀寁寃寈寉寊寋寍寎寏\"],[\"8c80\",\"寑寔\",8,\"寠寢寣實寧審\",4,\"寯寱\",6,\"寽対尀専尃尅將專尋尌對導尐尒尓尗尙尛尞尟尠尡尣尦尨尩尪尫尭尮尯尰尲尳尵尶尷屃屄屆屇屌屍屒屓屔屖屗屘屚屛屜屝屟屢層屧\",6,\"屰屲\",6,\"屻屼屽屾岀岃\",4,\"岉岊岋岎岏岒岓岕岝\",4,\"岤\",4],[\"8d40\",\"岪岮岯岰岲岴岶岹岺岻岼岾峀峂峃峅\",5,\"峌\",5,\"峓\",5,\"峚\",6,\"峢峣峧峩峫峬峮峯峱\",9,\"峼\",4],[\"8d80\",\"崁崄崅崈\",5,\"崏\",4,\"崕崗崘崙崚崜崝崟\",4,\"崥崨崪崫崬崯\",4,\"崵\",7,\"崿\",7,\"嵈嵉嵍\",10,\"嵙嵚嵜嵞\",10,\"嵪嵭嵮嵰嵱嵲嵳嵵\",12,\"嶃\",21,\"嶚嶛嶜嶞嶟嶠\"],[\"8e40\",\"嶡\",21,\"嶸\",12,\"巆\",6,\"巎\",12,\"巜巟巠巣巤巪巬巭\"],[\"8e80\",\"巰巵巶巸\",4,\"巿帀帄帇帉帊帋帍帎帒帓帗帞\",7,\"帨\",4,\"帯帰帲\",4,\"帹帺帾帿幀幁幃幆\",5,\"幍\",6,\"幖\",4,\"幜幝幟幠幣\",14,\"幵幷幹幾庁庂広庅庈庉庌庍庎庒庘庛庝庡庢庣庤庨\",4,\"庮\",4,\"庴庺庻庼庽庿\",6],[\"8f40\",\"廆廇廈廋\",5,\"廔廕廗廘廙廚廜\",11,\"廩廫\",8,\"廵廸廹廻廼廽弅弆弇弉弌弍弎弐弒弔弖弙弚弜弝弞弡弢弣弤\"],[\"8f80\",\"弨弫弬弮弰弲\",6,\"弻弽弾弿彁\",14,\"彑彔彙彚彛彜彞彟彠彣彥彧彨彫彮彯彲彴彵彶彸彺彽彾彿徃徆徍徎徏徑従徔徖徚徛徝從徟徠徢\",5,\"復徫徬徯\",5,\"徶徸徹徺徻徾\",4,\"忇忈忊忋忎忓忔忕忚忛応忞忟忢忣忥忦忨忩忬忯忰忲忳忴忶忷忹忺忼怇\"],[\"9040\",\"怈怉怋怌怐怑怓怗怘怚怞怟怢怣怤怬怭怮怰\",4,\"怶\",4,\"怽怾恀恄\",6,\"恌恎恏恑恓恔恖恗恘恛恜恞恟恠恡恥恦恮恱恲恴恵恷恾悀\"],[\"9080\",\"悁悂悅悆悇悈悊悋悎悏悐悑悓悕悗悘悙悜悞悡悢悤悥悧悩悪悮悰悳悵悶悷悹悺悽\",7,\"惇惈惉惌\",4,\"惒惓惔惖惗惙惛惞惡\",4,\"惪惱惲惵惷惸惻\",4,\"愂愃愄愅愇愊愋愌愐\",4,\"愖愗愘愙愛愜愝愞愡愢愥愨愩愪愬\",18,\"慀\",6],[\"9140\",\"慇慉態慍慏慐慒慓慔慖\",6,\"慞慟慠慡慣慤慥慦慩\",6,\"慱慲慳慴慶慸\",18,\"憌憍憏\",4,\"憕\"],[\"9180\",\"憖\",6,\"憞\",8,\"憪憫憭\",9,\"憸\",5,\"憿懀懁懃\",4,\"應懌\",4,\"懓懕\",16,\"懧\",13,\"懶\",8,\"戀\",5,\"戇戉戓戔戙戜戝戞戠戣戦戧戨戩戫戭戯戰戱戲戵戶戸\",4,\"扂扄扅扆扊\"],[\"9240\",\"扏扐払扖扗扙扚扜\",6,\"扤扥扨扱扲扴扵扷扸扺扻扽抁抂抃抅抆抇抈抋\",5,\"抔抙抜抝択抣抦抧抩抪抭抮抯抰抲抳抴抶抷抸抺抾拀拁\"],[\"9280\",\"拃拋拏拑拕拝拞拠拡拤拪拫拰拲拵拸拹拺拻挀挃挄挅挆挊挋挌挍挏挐挒挓挔挕挗挘挙挜挦挧挩挬挭挮挰挱挳\",5,\"挻挼挾挿捀捁捄捇捈捊捑捒捓捔捖\",7,\"捠捤捥捦捨捪捫捬捯捰捲捳捴捵捸捹捼捽捾捿掁掃掄掅掆掋掍掑掓掔掕掗掙\",6,\"採掤掦掫掯掱掲掵掶掹掻掽掿揀\"],[\"9340\",\"揁揂揃揅揇揈揊揋揌揑揓揔揕揗\",6,\"揟揢揤\",4,\"揫揬揮揯揰揱揳揵揷揹揺揻揼揾搃搄搆\",4,\"損搎搑搒搕\",5,\"搝搟搢搣搤\"],[\"9380\",\"搥搧搨搩搫搮\",5,\"搵\",4,\"搻搼搾摀摂摃摉摋\",6,\"摓摕摖摗摙\",4,\"摟\",7,\"摨摪摫摬摮\",9,\"摻\",6,\"撃撆撈\",8,\"撓撔撗撘撚撛撜撝撟\",4,\"撥撦撧撨撪撫撯撱撲撳撴撶撹撻撽撾撿擁擃擄擆\",6,\"擏擑擓擔擕擖擙據\"],[\"9440\",\"擛擜擝擟擠擡擣擥擧\",24,\"攁\",7,\"攊\",7,\"攓\",4,\"攙\",8],[\"9480\",\"攢攣攤攦\",4,\"攬攭攰攱攲攳攷攺攼攽敀\",4,\"敆敇敊敋敍敎敐敒敓敔敗敘敚敜敟敠敡敤敥敧敨敩敪敭敮敯敱敳敵敶數\",14,\"斈斉斊斍斎斏斒斔斕斖斘斚斝斞斠斢斣斦斨斪斬斮斱\",7,\"斺斻斾斿旀旂旇旈旉旊旍旐旑旓旔旕旘\",7,\"旡旣旤旪旫\"],[\"9540\",\"旲旳旴旵旸旹旻\",4,\"昁昄昅昇昈昉昋昍昐昑昒昖昗昘昚昛昜昞昡昢昣昤昦昩昪昫昬昮昰昲昳昷\",4,\"昽昿晀時晄\",6,\"晍晎晐晑晘\"],[\"9580\",\"晙晛晜晝晞晠晢晣晥晧晩\",4,\"晱晲晳晵晸晹晻晼晽晿暀暁暃暅暆暈暉暊暋暍暎暏暐暒暓暔暕暘\",4,\"暞\",8,\"暩\",4,\"暯\",4,\"暵暶暷暸暺暻暼暽暿\",25,\"曚曞\",7,\"曧曨曪\",5,\"曱曵曶書曺曻曽朁朂會\"],[\"9640\",\"朄朅朆朇朌朎朏朑朒朓朖朘朙朚朜朞朠\",5,\"朧朩朮朰朲朳朶朷朸朹朻朼朾朿杁杄杅杇杊杋杍杒杔杕杗\",4,\"杝杢杣杤杦杧杫杬杮東杴杶\"],[\"9680\",\"杸杹杺杻杽枀枂枃枅枆枈枊枌枍枎枏枑枒枓枔枖枙枛枟枠枡枤枦枩枬枮枱枲枴枹\",7,\"柂柅\",9,\"柕柖柗柛柟柡柣柤柦柧柨柪柫柭柮柲柵\",7,\"柾栁栂栃栄栆栍栐栒栔栕栘\",4,\"栞栟栠栢\",6,\"栫\",6,\"栴栵栶栺栻栿桇桋桍桏桒桖\",5],[\"9740\",\"桜桝桞桟桪桬\",7,\"桵桸\",8,\"梂梄梇\",7,\"梐梑梒梔梕梖梘\",9,\"梣梤梥梩梪梫梬梮梱梲梴梶梷梸\"],[\"9780\",\"梹\",6,\"棁棃\",5,\"棊棌棎棏棐棑棓棔棖棗棙棛\",4,\"棡棢棤\",9,\"棯棲棳棴棶棷棸棻棽棾棿椀椂椃椄椆\",4,\"椌椏椑椓\",11,\"椡椢椣椥\",7,\"椮椯椱椲椳椵椶椷椸椺椻椼椾楀楁楃\",16,\"楕楖楘楙楛楜楟\"],[\"9840\",\"楡楢楤楥楧楨楩楪楬業楯楰楲\",4,\"楺楻楽楾楿榁榃榅榊榋榌榎\",5,\"榖榗榙榚榝\",9,\"榩榪榬榮榯榰榲榳榵榶榸榹榺榼榽\"],[\"9880\",\"榾榿槀槂\",7,\"構槍槏槑槒槓槕\",5,\"槜槝槞槡\",11,\"槮槯槰槱槳\",9,\"槾樀\",9,\"樋\",11,\"標\",5,\"樠樢\",5,\"権樫樬樭樮樰樲樳樴樶\",6,\"樿\",4,\"橅橆橈\",7,\"橑\",6,\"橚\"],[\"9940\",\"橜\",4,\"橢橣橤橦\",10,\"橲\",6,\"橺橻橽橾橿檁檂檃檅\",8,\"檏檒\",4,\"檘\",7,\"檡\",5],[\"9980\",\"檧檨檪檭\",114,\"欥欦欨\",6],[\"9a40\",\"欯欰欱欳欴欵欶欸欻欼欽欿歀歁歂歄歅歈歊歋歍\",11,\"歚\",7,\"歨歩歫\",13,\"歺歽歾歿殀殅殈\"],[\"9a80\",\"殌殎殏殐殑殔殕殗殘殙殜\",4,\"殢\",7,\"殫\",7,\"殶殸\",6,\"毀毃毄毆\",4,\"毌毎毐毑毘毚毜\",4,\"毢\",7,\"毬毭毮毰毱毲毴毶毷毸毺毻毼毾\",6,\"氈\",4,\"氎氒気氜氝氞氠氣氥氫氬氭氱氳氶氷氹氺氻氼氾氿汃汄汅汈汋\",4,\"汑汒汓汖汘\"],[\"9b40\",\"汙汚汢汣汥汦汧汫\",4,\"汱汳汵汷汸決汻汼汿沀沄沇沊沋沍沎沑沒沕沖沗沘沚沜沝沞沠沢沨沬沯沰沴沵沶沷沺泀況泂泃泆泇泈泋泍泎泏泑泒泘\"],[\"9b80\",\"泙泚泜泝泟泤泦泧泩泬泭泲泴泹泿洀洂洃洅洆洈洉洊洍洏洐洑洓洔洕洖洘洜洝洟\",5,\"洦洨洩洬洭洯洰洴洶洷洸洺洿浀浂浄浉浌浐浕浖浗浘浛浝浟浡浢浤浥浧浨浫浬浭浰浱浲浳浵浶浹浺浻浽\",4,\"涃涄涆涇涊涋涍涏涐涒涖\",4,\"涜涢涥涬涭涰涱涳涴涶涷涹\",5,\"淁淂淃淈淉淊\"],[\"9c40\",\"淍淎淏淐淒淓淔淕淗淚淛淜淟淢淣淥淧淨淩淪淭淯淰淲淴淵淶淸淺淽\",7,\"渆渇済渉渋渏渒渓渕渘渙減渜渞渟渢渦渧渨渪測渮渰渱渳渵\"],[\"9c80\",\"渶渷渹渻\",7,\"湅\",7,\"湏湐湑湒湕湗湙湚湜湝湞湠\",10,\"湬湭湯\",14,\"満溁溂溄溇溈溊\",4,\"溑\",6,\"溙溚溛溝溞溠溡溣溤溦溨溩溫溬溭溮溰溳溵溸溹溼溾溿滀滃滄滅滆滈滉滊滌滍滎滐滒滖滘滙滛滜滝滣滧滪\",5],[\"9d40\",\"滰滱滲滳滵滶滷滸滺\",7,\"漃漄漅漇漈漊\",4,\"漐漑漒漖\",9,\"漡漢漣漥漦漧漨漬漮漰漲漴漵漷\",6,\"漿潀潁潂\"],[\"9d80\",\"潃潄潅潈潉潊潌潎\",9,\"潙潚潛潝潟潠潡潣潤潥潧\",5,\"潯潰潱潳潵潶潷潹潻潽\",6,\"澅澆澇澊澋澏\",12,\"澝澞澟澠澢\",4,\"澨\",10,\"澴澵澷澸澺\",5,\"濁濃\",5,\"濊\",6,\"濓\",10,\"濟濢濣濤濥\"],[\"9e40\",\"濦\",7,\"濰\",32,\"瀒\",7,\"瀜\",6,\"瀤\",6],[\"9e80\",\"瀫\",9,\"瀶瀷瀸瀺\",17,\"灍灎灐\",13,\"灟\",11,\"灮灱灲灳灴灷灹灺灻災炁炂炃炄炆炇炈炋炌炍炏炐炑炓炗炘炚炛炞\",12,\"炰炲炴炵炶為炾炿烄烅烆烇烉烋\",12,\"烚\"],[\"9f40\",\"烜烝烞烠烡烢烣烥烪烮烰\",6,\"烸烺烻烼烾\",10,\"焋\",4,\"焑焒焔焗焛\",10,\"焧\",7,\"焲焳焴\"],[\"9f80\",\"焵焷\",13,\"煆煇煈煉煋煍煏\",12,\"煝煟\",4,\"煥煩\",4,\"煯煰煱煴煵煶煷煹煻煼煾\",5,\"熅\",4,\"熋熌熍熎熐熑熒熓熕熖熗熚\",4,\"熡\",6,\"熩熪熫熭\",5,\"熴熶熷熸熺\",8,\"燄\",9,\"燏\",4],[\"a040\",\"燖\",9,\"燡燢燣燤燦燨\",5,\"燯\",9,\"燺\",11,\"爇\",19],[\"a080\",\"爛爜爞\",9,\"爩爫爭爮爯爲爳爴爺爼爾牀\",6,\"牉牊牋牎牏牐牑牓牔牕牗牘牚牜牞牠牣牤牥牨牪牫牬牭牰牱牳牴牶牷牸牻牼牽犂犃犅\",4,\"犌犎犐犑犓\",11,\"犠\",11,\"犮犱犲犳犵犺\",6,\"狅狆狇狉狊狋狌狏狑狓狔狕狖狘狚狛\"],[\"a1a1\",\"　、。·ˉˇ¨〃々—～‖…‘’“”〔〕〈\",7,\"〖〗【】±×÷∶∧∨∑∏∪∩∈∷√⊥∥∠⌒⊙∫∮≡≌≈∽∝≠≮≯≤≥∞∵∴♂♀°′″℃＄¤￠￡‰§№☆★○●◎◇◆□■△▲※→←↑↓〓\"],[\"a2a1\",\"ⅰ\",9],[\"a2b1\",\"⒈\",19,\"⑴\",19,\"①\",9],[\"a2e5\",\"㈠\",9],[\"a2f1\",\"Ⅰ\",11],[\"a3a1\",\"！＂＃￥％\",88,\"￣\"],[\"a4a1\",\"ぁ\",82],[\"a5a1\",\"ァ\",85],[\"a6a1\",\"Α\",16,\"Σ\",6],[\"a6c1\",\"α\",16,\"σ\",6],[\"a6e0\",\"︵︶︹︺︿﹀︽︾﹁﹂﹃﹄\"],[\"a6ee\",\"︻︼︷︸︱\"],[\"a6f4\",\"︳︴\"],[\"a7a1\",\"А\",5,\"ЁЖ\",25],[\"a7d1\",\"а\",5,\"ёж\",25],[\"a840\",\"ˊˋ˙–―‥‵℅℉↖↗↘↙∕∟∣≒≦≧⊿═\",35,\"▁\",6],[\"a880\",\"█\",7,\"▓▔▕▼▽◢◣◤◥☉⊕〒〝〞\"],[\"a8a1\",\"āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜüêɑ\"],[\"a8bd\",\"ńň\"],[\"a8c0\",\"ɡ\"],[\"a8c5\",\"ㄅ\",36],[\"a940\",\"〡\",8,\"㊣㎎㎏㎜㎝㎞㎡㏄㏎㏑㏒㏕︰￢￤\"],[\"a959\",\"℡㈱\"],[\"a95c\",\"‐\"],[\"a960\",\"ー゛゜ヽヾ〆ゝゞ﹉\",9,\"﹔﹕﹖﹗﹙\",8],[\"a980\",\"﹢\",4,\"﹨﹩﹪﹫\"],[\"a996\",\"〇\"],[\"a9a4\",\"─\",75],[\"aa40\",\"狜狝狟狢\",5,\"狪狫狵狶狹狽狾狿猀猂猄\",5,\"猋猌猍猏猐猑猒猔猘猙猚猟猠猣猤猦猧猨猭猯猰猲猳猵猶猺猻猼猽獀\",8],[\"aa80\",\"獉獊獋獌獎獏獑獓獔獕獖獘\",7,\"獡\",10,\"獮獰獱\"],[\"ab40\",\"獲\",11,\"獿\",4,\"玅玆玈玊玌玍玏玐玒玓玔玕玗玘玙玚玜玝玞玠玡玣\",5,\"玪玬玭玱玴玵玶玸玹玼玽玾玿珁珃\",4],[\"ab80\",\"珋珌珎珒\",6,\"珚珛珜珝珟珡珢珣珤珦珨珪珫珬珮珯珰珱珳\",4],[\"ac40\",\"珸\",10,\"琄琇琈琋琌琍琎琑\",8,\"琜\",5,\"琣琤琧琩琫琭琯琱琲琷\",4,\"琽琾琿瑀瑂\",11],[\"ac80\",\"瑎\",6,\"瑖瑘瑝瑠\",12,\"瑮瑯瑱\",4,\"瑸瑹瑺\"],[\"ad40\",\"瑻瑼瑽瑿璂璄璅璆璈璉璊璌璍璏璑\",10,\"璝璟\",7,\"璪\",15,\"璻\",12],[\"ad80\",\"瓈\",9,\"瓓\",8,\"瓝瓟瓡瓥瓧\",6,\"瓰瓱瓲\"],[\"ae40\",\"瓳瓵瓸\",6,\"甀甁甂甃甅\",7,\"甎甐甒甔甕甖甗甛甝甞甠\",4,\"甦甧甪甮甴甶甹甼甽甿畁畂畃畄畆畇畉畊畍畐畑畒畓畕畖畗畘\"],[\"ae80\",\"畝\",7,\"畧畨畩畫\",6,\"畳畵當畷畺\",4,\"疀疁疂疄疅疇\"],[\"af40\",\"疈疉疊疌疍疎疐疓疕疘疛疜疞疢疦\",4,\"疭疶疷疺疻疿痀痁痆痋痌痎痏痐痑痓痗痙痚痜痝痟痠痡痥痩痬痭痮痯痲痳痵痶痷痸痺痻痽痾瘂瘄瘆瘇\"],[\"af80\",\"瘈瘉瘋瘍瘎瘏瘑瘒瘓瘔瘖瘚瘜瘝瘞瘡瘣瘧瘨瘬瘮瘯瘱瘲瘶瘷瘹瘺瘻瘽癁療癄\"],[\"b040\",\"癅\",6,\"癎\",5,\"癕癗\",4,\"癝癟癠癡癢癤\",6,\"癬癭癮癰\",7,\"癹発發癿皀皁皃皅皉皊皌皍皏皐皒皔皕皗皘皚皛\"],[\"b080\",\"皜\",7,\"皥\",8,\"皯皰皳皵\",9,\"盀盁盃啊阿埃挨哎唉哀皑癌蔼矮艾碍爱隘鞍氨安俺按暗岸胺案肮昂盎凹敖熬翱袄傲奥懊澳芭捌扒叭吧笆八疤巴拔跋靶把耙坝霸罢爸白柏百摆佰败拜稗斑班搬扳般颁板版扮拌伴瓣半办绊邦帮梆榜膀绑棒磅蚌镑傍谤苞胞包褒剥\"],[\"b140\",\"盄盇盉盋盌盓盕盙盚盜盝盞盠\",4,\"盦\",7,\"盰盳盵盶盷盺盻盽盿眀眂眃眅眆眊県眎\",10,\"眛眜眝眞眡眣眤眥眧眪眫\"],[\"b180\",\"眬眮眰\",4,\"眹眻眽眾眿睂睄睅睆睈\",7,\"睒\",7,\"睜薄雹保堡饱宝抱报暴豹鲍爆杯碑悲卑北辈背贝钡倍狈备惫焙被奔苯本笨崩绷甭泵蹦迸逼鼻比鄙笔彼碧蓖蔽毕毙毖币庇痹闭敝弊必辟壁臂避陛鞭边编贬扁便变卞辨辩辫遍标彪膘表鳖憋别瘪彬斌濒滨宾摈兵冰柄丙秉饼炳\"],[\"b240\",\"睝睞睟睠睤睧睩睪睭\",11,\"睺睻睼瞁瞂瞃瞆\",5,\"瞏瞐瞓\",11,\"瞡瞣瞤瞦瞨瞫瞭瞮瞯瞱瞲瞴瞶\",4],[\"b280\",\"瞼瞾矀\",12,\"矎\",8,\"矘矙矚矝\",4,\"矤病并玻菠播拨钵波博勃搏铂箔伯帛舶脖膊渤泊驳捕卜哺补埠不布步簿部怖擦猜裁材才财睬踩采彩菜蔡餐参蚕残惭惨灿苍舱仓沧藏操糙槽曹草厕策侧册测层蹭插叉茬茶查碴搽察岔差诧拆柴豺搀掺蝉馋谗缠铲产阐颤昌猖\"],[\"b340\",\"矦矨矪矯矰矱矲矴矵矷矹矺矻矼砃\",5,\"砊砋砎砏砐砓砕砙砛砞砠砡砢砤砨砪砫砮砯砱砲砳砵砶砽砿硁硂硃硄硆硈硉硊硋硍硏硑硓硔硘硙硚\"],[\"b380\",\"硛硜硞\",11,\"硯\",7,\"硸硹硺硻硽\",6,\"场尝常长偿肠厂敞畅唱倡超抄钞朝嘲潮巢吵炒车扯撤掣彻澈郴臣辰尘晨忱沉陈趁衬撑称城橙成呈乘程惩澄诚承逞骋秤吃痴持匙池迟弛驰耻齿侈尺赤翅斥炽充冲虫崇宠抽酬畴踌稠愁筹仇绸瞅丑臭初出橱厨躇锄雏滁除楚\"],[\"b440\",\"碄碅碆碈碊碋碏碐碒碔碕碖碙碝碞碠碢碤碦碨\",7,\"碵碶碷碸確碻碼碽碿磀磂磃磄磆磇磈磌磍磎磏磑磒磓磖磗磘磚\",9],[\"b480\",\"磤磥磦磧磩磪磫磭\",4,\"磳磵磶磸磹磻\",5,\"礂礃礄礆\",6,\"础储矗搐触处揣川穿椽传船喘串疮窗幢床闯创吹炊捶锤垂春椿醇唇淳纯蠢戳绰疵茨磁雌辞慈瓷词此刺赐次聪葱囱匆从丛凑粗醋簇促蹿篡窜摧崔催脆瘁粹淬翠村存寸磋撮搓措挫错搭达答瘩打大呆歹傣戴带殆代贷袋待逮\"],[\"b540\",\"礍\",5,\"礔\",9,\"礟\",4,\"礥\",14,\"礵\",4,\"礽礿祂祃祄祅祇祊\",8,\"祔祕祘祙祡祣\"],[\"b580\",\"祤祦祩祪祫祬祮祰\",6,\"祹祻\",4,\"禂禃禆禇禈禉禋禌禍禎禐禑禒怠耽担丹单郸掸胆旦氮但惮淡诞弹蛋当挡党荡档刀捣蹈倒岛祷导到稻悼道盗德得的蹬灯登等瞪凳邓堤低滴迪敌笛狄涤翟嫡抵底地蒂第帝弟递缔颠掂滇碘点典靛垫电佃甸店惦奠淀殿碉叼雕凋刁掉吊钓调跌爹碟蝶迭谍叠\"],[\"b640\",\"禓\",6,\"禛\",11,\"禨\",10,\"禴\",4,\"禼禿秂秄秅秇秈秊秌秎秏秐秓秔秖秗秙\",5,\"秠秡秢秥秨秪\"],[\"b680\",\"秬秮秱\",6,\"秹秺秼秾秿稁稄稅稇稈稉稊稌稏\",4,\"稕稖稘稙稛稜丁盯叮钉顶鼎锭定订丢东冬董懂动栋侗恫冻洞兜抖斗陡豆逗痘都督毒犊独读堵睹赌杜镀肚度渡妒端短锻段断缎堆兑队对墩吨蹲敦顿囤钝盾遁掇哆多夺垛躲朵跺舵剁惰堕蛾峨鹅俄额讹娥恶厄扼遏鄂饿恩而儿耳尔饵洱二\"],[\"b740\",\"稝稟稡稢稤\",14,\"稴稵稶稸稺稾穀\",5,\"穇\",9,\"穒\",4,\"穘\",16],[\"b780\",\"穩\",6,\"穱穲穳穵穻穼穽穾窂窅窇窉窊窋窌窎窏窐窓窔窙窚窛窞窡窢贰发罚筏伐乏阀法珐藩帆番翻樊矾钒繁凡烦反返范贩犯饭泛坊芳方肪房防妨仿访纺放菲非啡飞肥匪诽吠肺废沸费芬酚吩氛分纷坟焚汾粉奋份忿愤粪丰封枫蜂峰锋风疯烽逢冯缝讽奉凤佛否夫敷肤孵扶拂辐幅氟符伏俘服\"],[\"b840\",\"窣窤窧窩窪窫窮\",4,\"窴\",10,\"竀\",10,\"竌\",9,\"竗竘竚竛竜竝竡竢竤竧\",5,\"竮竰竱竲竳\"],[\"b880\",\"竴\",4,\"竻竼竾笀笁笂笅笇笉笌笍笎笐笒笓笖笗笘笚笜笝笟笡笢笣笧笩笭浮涪福袱弗甫抚辅俯釜斧脯腑府腐赴副覆赋复傅付阜父腹负富讣附妇缚咐噶嘎该改概钙盖溉干甘杆柑竿肝赶感秆敢赣冈刚钢缸肛纲岗港杠篙皋高膏羔糕搞镐稿告哥歌搁戈鸽胳疙割革葛格蛤阁隔铬个各给根跟耕更庚羹\"],[\"b940\",\"笯笰笲笴笵笶笷笹笻笽笿\",5,\"筆筈筊筍筎筓筕筗筙筜筞筟筡筣\",10,\"筯筰筳筴筶筸筺筼筽筿箁箂箃箄箆\",6,\"箎箏\"],[\"b980\",\"箑箒箓箖箘箙箚箛箞箟箠箣箤箥箮箯箰箲箳箵箶箷箹\",7,\"篂篃範埂耿梗工攻功恭龚供躬公宫弓巩汞拱贡共钩勾沟苟狗垢构购够辜菇咕箍估沽孤姑鼓古蛊骨谷股故顾固雇刮瓜剐寡挂褂乖拐怪棺关官冠观管馆罐惯灌贯光广逛瑰规圭硅归龟闺轨鬼诡癸桂柜跪贵刽辊滚棍锅郭国果裹过哈\"],[\"ba40\",\"篅篈築篊篋篍篎篏篐篒篔\",4,\"篛篜篞篟篠篢篣篤篧篨篩篫篬篭篯篰篲\",4,\"篸篹篺篻篽篿\",7,\"簈簉簊簍簎簐\",5,\"簗簘簙\"],[\"ba80\",\"簚\",4,\"簠\",5,\"簨簩簫\",12,\"簹\",5,\"籂骸孩海氦亥害骇酣憨邯韩含涵寒函喊罕翰撼捍旱憾悍焊汗汉夯杭航壕嚎豪毫郝好耗号浩呵喝荷菏核禾和何合盒貉阂河涸赫褐鹤贺嘿黑痕很狠恨哼亨横衡恒轰哄烘虹鸿洪宏弘红喉侯猴吼厚候后呼乎忽瑚壶葫胡蝴狐糊湖\"],[\"bb40\",\"籃\",9,\"籎\",36,\"籵\",5,\"籾\",9],[\"bb80\",\"粈粊\",6,\"粓粔粖粙粚粛粠粡粣粦粧粨粩粫粬粭粯粰粴\",4,\"粺粻弧虎唬护互沪户花哗华猾滑画划化话槐徊怀淮坏欢环桓还缓换患唤痪豢焕涣宦幻荒慌黄磺蝗簧皇凰惶煌晃幌恍谎灰挥辉徽恢蛔回毁悔慧卉惠晦贿秽会烩汇讳诲绘荤昏婚魂浑混豁活伙火获或惑霍货祸击圾基机畸稽积箕\"],[\"bc40\",\"粿糀糂糃糄糆糉糋糎\",6,\"糘糚糛糝糞糡\",6,\"糩\",5,\"糰\",7,\"糹糺糼\",13,\"紋\",5],[\"bc80\",\"紑\",14,\"紡紣紤紥紦紨紩紪紬紭紮細\",6,\"肌饥迹激讥鸡姬绩缉吉极棘辑籍集及急疾汲即嫉级挤几脊己蓟技冀季伎祭剂悸济寄寂计记既忌际妓继纪嘉枷夹佳家加荚颊贾甲钾假稼价架驾嫁歼监坚尖笺间煎兼肩艰奸缄茧检柬碱硷拣捡简俭剪减荐槛鉴践贱见键箭件\"],[\"bd40\",\"紷\",54,\"絯\",7],[\"bd80\",\"絸\",32,\"健舰剑饯渐溅涧建僵姜将浆江疆蒋桨奖讲匠酱降蕉椒礁焦胶交郊浇骄娇嚼搅铰矫侥脚狡角饺缴绞剿教酵轿较叫窖揭接皆秸街阶截劫节桔杰捷睫竭洁结解姐戒藉芥界借介疥诫届巾筋斤金今津襟紧锦仅谨进靳晋禁近烬浸\"],[\"be40\",\"継\",12,\"綧\",6,\"綯\",42],[\"be80\",\"線\",32,\"尽劲荆兢茎睛晶鲸京惊精粳经井警景颈静境敬镜径痉靖竟竞净炯窘揪究纠玖韭久灸九酒厩救旧臼舅咎就疚鞠拘狙疽居驹菊局咀矩举沮聚拒据巨具距踞锯俱句惧炬剧捐鹃娟倦眷卷绢撅攫抉掘倔爵觉决诀绝均菌钧军君峻\"],[\"bf40\",\"緻\",62],[\"bf80\",\"縺縼\",4,\"繂\",4,\"繈\",21,\"俊竣浚郡骏喀咖卡咯开揩楷凯慨刊堪勘坎砍看康慷糠扛抗亢炕考拷烤靠坷苛柯棵磕颗科壳咳可渴克刻客课肯啃垦恳坑吭空恐孔控抠口扣寇枯哭窟苦酷库裤夸垮挎跨胯块筷侩快宽款匡筐狂框矿眶旷况亏盔岿窥葵奎魁傀\"],[\"c040\",\"繞\",35,\"纃\",23,\"纜纝纞\"],[\"c080\",\"纮纴纻纼绖绤绬绹缊缐缞缷缹缻\",6,\"罃罆\",9,\"罒罓馈愧溃坤昆捆困括扩廓阔垃拉喇蜡腊辣啦莱来赖蓝婪栏拦篮阑兰澜谰揽览懒缆烂滥琅榔狼廊郎朗浪捞劳牢老佬姥酪烙涝勒乐雷镭蕾磊累儡垒擂肋类泪棱楞冷厘梨犁黎篱狸离漓理李里鲤礼莉荔吏栗丽厉励砾历利傈例俐\"],[\"c140\",\"罖罙罛罜罝罞罠罣\",4,\"罫罬罭罯罰罳罵罶罷罸罺罻罼罽罿羀羂\",7,\"羋羍羏\",4,\"羕\",4,\"羛羜羠羢羣羥羦羨\",6,\"羱\"],[\"c180\",\"羳\",4,\"羺羻羾翀翂翃翄翆翇翈翉翋翍翏\",4,\"翖翗翙\",5,\"翢翣痢立粒沥隶力璃哩俩联莲连镰廉怜涟帘敛脸链恋炼练粮凉梁粱良两辆量晾亮谅撩聊僚疗燎寥辽潦了撂镣廖料列裂烈劣猎琳林磷霖临邻鳞淋凛赁吝拎玲菱零龄铃伶羚凌灵陵岭领另令溜琉榴硫馏留刘瘤流柳六龙聋咙笼窿\"],[\"c240\",\"翤翧翨翪翫翬翭翯翲翴\",6,\"翽翾翿耂耇耈耉耊耎耏耑耓耚耛耝耞耟耡耣耤耫\",5,\"耲耴耹耺耼耾聀聁聄聅聇聈聉聎聏聐聑聓聕聖聗\"],[\"c280\",\"聙聛\",13,\"聫\",5,\"聲\",11,\"隆垄拢陇楼娄搂篓漏陋芦卢颅庐炉掳卤虏鲁麓碌露路赂鹿潞禄录陆戮驴吕铝侣旅履屡缕虑氯律率滤绿峦挛孪滦卵乱掠略抡轮伦仑沦纶论萝螺罗逻锣箩骡裸落洛骆络妈麻玛码蚂马骂嘛吗埋买麦卖迈脉瞒馒蛮满蔓曼慢漫\"],[\"c340\",\"聾肁肂肅肈肊肍\",5,\"肔肕肗肙肞肣肦肧肨肬肰肳肵肶肸肹肻胅胇\",4,\"胏\",6,\"胘胟胠胢胣胦胮胵胷胹胻胾胿脀脁脃脄脅脇脈脋\"],[\"c380\",\"脌脕脗脙脛脜脝脟\",12,\"脭脮脰脳脴脵脷脹\",4,\"脿谩芒茫盲氓忙莽猫茅锚毛矛铆卯茂冒帽貌贸么玫枚梅酶霉煤没眉媒镁每美昧寐妹媚门闷们萌蒙檬盟锰猛梦孟眯醚靡糜迷谜弥米秘觅泌蜜密幂棉眠绵冕免勉娩缅面苗描瞄藐秒渺庙妙蔑灭民抿皿敏悯闽明螟鸣铭名命谬摸\"],[\"c440\",\"腀\",5,\"腇腉腍腎腏腒腖腗腘腛\",4,\"腡腢腣腤腦腨腪腫腬腯腲腳腵腶腷腸膁膃\",4,\"膉膋膌膍膎膐膒\",5,\"膙膚膞\",4,\"膤膥\"],[\"c480\",\"膧膩膫\",7,\"膴\",5,\"膼膽膾膿臄臅臇臈臉臋臍\",6,\"摹蘑模膜磨摩魔抹末莫墨默沫漠寞陌谋牟某拇牡亩姆母墓暮幕募慕木目睦牧穆拿哪呐钠那娜纳氖乃奶耐奈南男难囊挠脑恼闹淖呢馁内嫩能妮霓倪泥尼拟你匿腻逆溺蔫拈年碾撵捻念娘酿鸟尿捏聂孽啮镊镍涅您柠狞凝宁\"],[\"c540\",\"臔\",14,\"臤臥臦臨臩臫臮\",4,\"臵\",5,\"臽臿舃與\",4,\"舎舏舑舓舕\",5,\"舝舠舤舥舦舧舩舮舲舺舼舽舿\"],[\"c580\",\"艀艁艂艃艅艆艈艊艌艍艎艐\",7,\"艙艛艜艝艞艠\",7,\"艩拧泞牛扭钮纽脓浓农弄奴努怒女暖虐疟挪懦糯诺哦欧鸥殴藕呕偶沤啪趴爬帕怕琶拍排牌徘湃派攀潘盘磐盼畔判叛乓庞旁耪胖抛咆刨炮袍跑泡呸胚培裴赔陪配佩沛喷盆砰抨烹澎彭蓬棚硼篷膨朋鹏捧碰坯砒霹批披劈琵毗\"],[\"c640\",\"艪艫艬艭艱艵艶艷艸艻艼芀芁芃芅芆芇芉芌芐芓芔芕芖芚芛芞芠芢芣芧芲芵芶芺芻芼芿苀苂苃苅苆苉苐苖苙苚苝苢苧苨苩苪苬苭苮苰苲苳苵苶苸\"],[\"c680\",\"苺苼\",4,\"茊茋茍茐茒茓茖茘茙茝\",9,\"茩茪茮茰茲茷茻茽啤脾疲皮匹痞僻屁譬篇偏片骗飘漂瓢票撇瞥拼频贫品聘乒坪苹萍平凭瓶评屏坡泼颇婆破魄迫粕剖扑铺仆莆葡菩蒲埔朴圃普浦谱曝瀑期欺栖戚妻七凄漆柒沏其棋奇歧畦崎脐齐旗祈祁骑起岂乞企启契砌器气迄弃汽泣讫掐\"],[\"c740\",\"茾茿荁荂荄荅荈荊\",4,\"荓荕\",4,\"荝荢荰\",6,\"荹荺荾\",6,\"莇莈莊莋莌莍莏莐莑莔莕莖莗莙莚莝莟莡\",6,\"莬莭莮\"],[\"c780\",\"莯莵莻莾莿菂菃菄菆菈菉菋菍菎菐菑菒菓菕菗菙菚菛菞菢菣菤菦菧菨菫菬菭恰洽牵扦钎铅千迁签仟谦乾黔钱钳前潜遣浅谴堑嵌欠歉枪呛腔羌墙蔷强抢橇锹敲悄桥瞧乔侨巧鞘撬翘峭俏窍切茄且怯窃钦侵亲秦琴勤芹擒禽寝沁青轻氢倾卿清擎晴氰情顷请庆琼穷秋丘邱球求囚酋泅趋区蛆曲躯屈驱渠\"],[\"c840\",\"菮華菳\",4,\"菺菻菼菾菿萀萂萅萇萈萉萊萐萒\",5,\"萙萚萛萞\",5,\"萩\",7,\"萲\",5,\"萹萺萻萾\",7,\"葇葈葉\"],[\"c880\",\"葊\",6,\"葒\",4,\"葘葝葞葟葠葢葤\",4,\"葪葮葯葰葲葴葷葹葻葼取娶龋趣去圈颧权醛泉全痊拳犬券劝缺炔瘸却鹊榷确雀裙群然燃冉染瓤壤攘嚷让饶扰绕惹热壬仁人忍韧任认刃妊纫扔仍日戎茸蓉荣融熔溶容绒冗揉柔肉茹蠕儒孺如辱乳汝入褥软阮蕊瑞锐闰润若弱撒洒萨腮鳃塞赛三叁\"],[\"c940\",\"葽\",4,\"蒃蒄蒅蒆蒊蒍蒏\",7,\"蒘蒚蒛蒝蒞蒟蒠蒢\",12,\"蒰蒱蒳蒵蒶蒷蒻蒼蒾蓀蓂蓃蓅蓆蓇蓈蓋蓌蓎蓏蓒蓔蓕蓗\"],[\"c980\",\"蓘\",4,\"蓞蓡蓢蓤蓧\",4,\"蓭蓮蓯蓱\",10,\"蓽蓾蔀蔁蔂伞散桑嗓丧搔骚扫嫂瑟色涩森僧莎砂杀刹沙纱傻啥煞筛晒珊苫杉山删煽衫闪陕擅赡膳善汕扇缮墒伤商赏晌上尚裳梢捎稍烧芍勺韶少哨邵绍奢赊蛇舌舍赦摄射慑涉社设砷申呻伸身深娠绅神沈审婶甚肾慎渗声生甥牲升绳\"],[\"ca40\",\"蔃\",8,\"蔍蔎蔏蔐蔒蔔蔕蔖蔘蔙蔛蔜蔝蔞蔠蔢\",8,\"蔭\",9,\"蔾\",4,\"蕄蕅蕆蕇蕋\",10],[\"ca80\",\"蕗蕘蕚蕛蕜蕝蕟\",4,\"蕥蕦蕧蕩\",8,\"蕳蕵蕶蕷蕸蕼蕽蕿薀薁省盛剩胜圣师失狮施湿诗尸虱十石拾时什食蚀实识史矢使屎驶始式示士世柿事拭誓逝势是嗜噬适仕侍释饰氏市恃室视试收手首守寿授售受瘦兽蔬枢梳殊抒输叔舒淑疏书赎孰熟薯暑曙署蜀黍鼠属术述树束戍竖墅庶数漱\"],[\"cb40\",\"薂薃薆薈\",6,\"薐\",10,\"薝\",6,\"薥薦薧薩薫薬薭薱\",5,\"薸薺\",6,\"藂\",6,\"藊\",4,\"藑藒\"],[\"cb80\",\"藔藖\",5,\"藝\",6,\"藥藦藧藨藪\",14,\"恕刷耍摔衰甩帅栓拴霜双爽谁水睡税吮瞬顺舜说硕朔烁斯撕嘶思私司丝死肆寺嗣四伺似饲巳松耸怂颂送宋讼诵搜艘擞嗽苏酥俗素速粟僳塑溯宿诉肃酸蒜算虽隋随绥髓碎岁穗遂隧祟孙损笋蓑梭唆缩琐索锁所塌他它她塔\"],[\"cc40\",\"藹藺藼藽藾蘀\",4,\"蘆\",10,\"蘒蘓蘔蘕蘗\",15,\"蘨蘪\",13,\"蘹蘺蘻蘽蘾蘿虀\"],[\"cc80\",\"虁\",11,\"虒虓處\",4,\"虛虜虝號虠虡虣\",7,\"獭挞蹋踏胎苔抬台泰酞太态汰坍摊贪瘫滩坛檀痰潭谭谈坦毯袒碳探叹炭汤塘搪堂棠膛唐糖倘躺淌趟烫掏涛滔绦萄桃逃淘陶讨套特藤腾疼誊梯剔踢锑提题蹄啼体替嚏惕涕剃屉天添填田甜恬舔腆挑条迢眺跳贴铁帖厅听烃\"],[\"cd40\",\"虭虯虰虲\",6,\"蚃\",6,\"蚎\",4,\"蚔蚖\",5,\"蚞\",4,\"蚥蚦蚫蚭蚮蚲蚳蚷蚸蚹蚻\",4,\"蛁蛂蛃蛅蛈蛌蛍蛒蛓蛕蛖蛗蛚蛜\"],[\"cd80\",\"蛝蛠蛡蛢蛣蛥蛦蛧蛨蛪蛫蛬蛯蛵蛶蛷蛺蛻蛼蛽蛿蜁蜄蜅蜆蜋蜌蜎蜏蜐蜑蜔蜖汀廷停亭庭挺艇通桐酮瞳同铜彤童桶捅筒统痛偷投头透凸秃突图徒途涂屠土吐兔湍团推颓腿蜕褪退吞屯臀拖托脱鸵陀驮驼椭妥拓唾挖哇蛙洼娃瓦袜歪外豌弯湾玩顽丸烷完碗挽晚皖惋宛婉万腕汪王亡枉网往旺望忘妄威\"],[\"ce40\",\"蜙蜛蜝蜟蜠蜤蜦蜧蜨蜪蜫蜬蜭蜯蜰蜲蜳蜵蜶蜸蜹蜺蜼蜽蝀\",6,\"蝊蝋蝍蝏蝐蝑蝒蝔蝕蝖蝘蝚\",5,\"蝡蝢蝦\",7,\"蝯蝱蝲蝳蝵\"],[\"ce80\",\"蝷蝸蝹蝺蝿螀螁螄螆螇螉螊螌螎\",4,\"螔螕螖螘\",6,\"螠\",4,\"巍微危韦违桅围唯惟为潍维苇萎委伟伪尾纬未蔚味畏胃喂魏位渭谓尉慰卫瘟温蚊文闻纹吻稳紊问嗡翁瓮挝蜗涡窝我斡卧握沃巫呜钨乌污诬屋无芜梧吾吴毋武五捂午舞伍侮坞戊雾晤物勿务悟误昔熙析西硒矽晰嘻吸锡牺\"],[\"cf40\",\"螥螦螧螩螪螮螰螱螲螴螶螷螸螹螻螼螾螿蟁\",4,\"蟇蟈蟉蟌\",4,\"蟔\",6,\"蟜蟝蟞蟟蟡蟢蟣蟤蟦蟧蟨蟩蟫蟬蟭蟯\",9],[\"cf80\",\"蟺蟻蟼蟽蟿蠀蠁蠂蠄\",5,\"蠋\",7,\"蠔蠗蠘蠙蠚蠜\",4,\"蠣稀息希悉膝夕惜熄烯溪汐犀檄袭席习媳喜铣洗系隙戏细瞎虾匣霞辖暇峡侠狭下厦夏吓掀锨先仙鲜纤咸贤衔舷闲涎弦嫌显险现献县腺馅羡宪陷限线相厢镶香箱襄湘乡翔祥详想响享项巷橡像向象萧硝霄削哮嚣销消宵淆晓\"],[\"d040\",\"蠤\",13,\"蠳\",5,\"蠺蠻蠽蠾蠿衁衂衃衆\",5,\"衎\",5,\"衕衖衘衚\",6,\"衦衧衪衭衯衱衳衴衵衶衸衹衺\"],[\"d080\",\"衻衼袀袃袆袇袉袊袌袎袏袐袑袓袔袕袗\",4,\"袝\",4,\"袣袥\",5,\"小孝校肖啸笑效楔些歇蝎鞋协挟携邪斜胁谐写械卸蟹懈泄泻谢屑薪芯锌欣辛新忻心信衅星腥猩惺兴刑型形邢行醒幸杏性姓兄凶胸匈汹雄熊休修羞朽嗅锈秀袖绣墟戌需虚嘘须徐许蓄酗叙旭序畜恤絮婿绪续轩喧宣悬旋玄\"],[\"d140\",\"袬袮袯袰袲\",4,\"袸袹袺袻袽袾袿裀裃裄裇裈裊裋裌裍裏裐裑裓裖裗裚\",4,\"裠裡裦裧裩\",6,\"裲裵裶裷裺裻製裿褀褁褃\",5],[\"d180\",\"褉褋\",4,\"褑褔\",4,\"褜\",4,\"褢褣褤褦褧褨褩褬褭褮褯褱褲褳褵褷选癣眩绚靴薛学穴雪血勋熏循旬询寻驯巡殉汛训讯逊迅压押鸦鸭呀丫芽牙蚜崖衙涯雅哑亚讶焉咽阉烟淹盐严研蜒岩延言颜阎炎沿奄掩眼衍演艳堰燕厌砚雁唁彦焰宴谚验殃央鸯秧杨扬佯疡羊洋阳氧仰痒养样漾邀腰妖瑶\"],[\"d240\",\"褸\",8,\"襂襃襅\",24,\"襠\",5,\"襧\",19,\"襼\"],[\"d280\",\"襽襾覀覂覄覅覇\",26,\"摇尧遥窑谣姚咬舀药要耀椰噎耶爷野冶也页掖业叶曳腋夜液一壹医揖铱依伊衣颐夷遗移仪胰疑沂宜姨彝椅蚁倚已乙矣以艺抑易邑屹亿役臆逸肄疫亦裔意毅忆义益溢诣议谊译异翼翌绎茵荫因殷音阴姻吟银淫寅饮尹引隐\"],[\"d340\",\"覢\",30,\"觃觍觓觔觕觗觘觙觛觝觟觠觡觢觤觧觨觩觪觬觭觮觰觱觲觴\",6],[\"d380\",\"觻\",4,\"訁\",5,\"計\",21,\"印英樱婴鹰应缨莹萤营荧蝇迎赢盈影颖硬映哟拥佣臃痈庸雍踊蛹咏泳涌永恿勇用幽优悠忧尤由邮铀犹油游酉有友右佑釉诱又幼迂淤于盂榆虞愚舆余俞逾鱼愉渝渔隅予娱雨与屿禹宇语羽玉域芋郁吁遇喻峪御愈欲狱育誉\"],[\"d440\",\"訞\",31,\"訿\",8,\"詉\",21],[\"d480\",\"詟\",25,\"詺\",6,\"浴寓裕预豫驭鸳渊冤元垣袁原援辕园员圆猿源缘远苑愿怨院曰约越跃钥岳粤月悦阅耘云郧匀陨允运蕴酝晕韵孕匝砸杂栽哉灾宰载再在咱攒暂赞赃脏葬遭糟凿藻枣早澡蚤躁噪造皂灶燥责择则泽贼怎增憎曾赠扎喳渣札轧\"],[\"d540\",\"誁\",7,\"誋\",7,\"誔\",46],[\"d580\",\"諃\",32,\"铡闸眨栅榨咋乍炸诈摘斋宅窄债寨瞻毡詹粘沾盏斩辗崭展蘸栈占战站湛绽樟章彰漳张掌涨杖丈帐账仗胀瘴障招昭找沼赵照罩兆肇召遮折哲蛰辙者锗蔗这浙珍斟真甄砧臻贞针侦枕疹诊震振镇阵蒸挣睁征狰争怔整拯正政\"],[\"d640\",\"諤\",34,\"謈\",27],[\"d680\",\"謤謥謧\",30,\"帧症郑证芝枝支吱蜘知肢脂汁之织职直植殖执值侄址指止趾只旨纸志挚掷至致置帜峙制智秩稚质炙痔滞治窒中盅忠钟衷终种肿重仲众舟周州洲诌粥轴肘帚咒皱宙昼骤珠株蛛朱猪诸诛逐竹烛煮拄瞩嘱主著柱助蛀贮铸筑\"],[\"d740\",\"譆\",31,\"譧\",4,\"譭\",25],[\"d780\",\"讇\",24,\"讬讱讻诇诐诪谉谞住注祝驻抓爪拽专砖转撰赚篆桩庄装妆撞壮状椎锥追赘坠缀谆准捉拙卓桌琢茁酌啄着灼浊兹咨资姿滋淄孜紫仔籽滓子自渍字鬃棕踪宗综总纵邹走奏揍租足卒族祖诅阻组钻纂嘴醉最罪尊遵昨左佐柞做作坐座\"],[\"d840\",\"谸\",8,\"豂豃豄豅豈豊豋豍\",7,\"豖豗豘豙豛\",5,\"豣\",6,\"豬\",6,\"豴豵豶豷豻\",6,\"貃貄貆貇\"],[\"d880\",\"貈貋貍\",6,\"貕貖貗貙\",20,\"亍丌兀丐廿卅丕亘丞鬲孬噩丨禺丿匕乇夭爻卮氐囟胤馗毓睾鼗丶亟鼐乜乩亓芈孛啬嘏仄厍厝厣厥厮靥赝匚叵匦匮匾赜卦卣刂刈刎刭刳刿剀剌剞剡剜蒯剽劂劁劐劓冂罔亻仃仉仂仨仡仫仞伛仳伢佤仵伥伧伉伫佞佧攸佚佝\"],[\"d940\",\"貮\",62],[\"d980\",\"賭\",32,\"佟佗伲伽佶佴侑侉侃侏佾佻侪佼侬侔俦俨俪俅俚俣俜俑俟俸倩偌俳倬倏倮倭俾倜倌倥倨偾偃偕偈偎偬偻傥傧傩傺僖儆僭僬僦僮儇儋仝氽佘佥俎龠汆籴兮巽黉馘冁夔勹匍訇匐凫夙兕亠兖亳衮袤亵脔裒禀嬴蠃羸冫冱冽冼\"],[\"da40\",\"贎\",14,\"贠赑赒赗赟赥赨赩赪赬赮赯赱赲赸\",8,\"趂趃趆趇趈趉趌\",4,\"趒趓趕\",9,\"趠趡\"],[\"da80\",\"趢趤\",12,\"趲趶趷趹趻趽跀跁跂跅跇跈跉跊跍跐跒跓跔凇冖冢冥讠讦讧讪讴讵讷诂诃诋诏诎诒诓诔诖诘诙诜诟诠诤诨诩诮诰诳诶诹诼诿谀谂谄谇谌谏谑谒谔谕谖谙谛谘谝谟谠谡谥谧谪谫谮谯谲谳谵谶卩卺阝阢阡阱阪阽阼陂陉陔陟陧陬陲陴隈隍隗隰邗邛邝邙邬邡邴邳邶邺\"],[\"db40\",\"跕跘跙跜跠跡跢跥跦跧跩跭跮跰跱跲跴跶跼跾\",6,\"踆踇踈踋踍踎踐踑踒踓踕\",7,\"踠踡踤\",4,\"踫踭踰踲踳踴踶踷踸踻踼踾\"],[\"db80\",\"踿蹃蹅蹆蹌\",4,\"蹓\",5,\"蹚\",11,\"蹧蹨蹪蹫蹮蹱邸邰郏郅邾郐郄郇郓郦郢郜郗郛郫郯郾鄄鄢鄞鄣鄱鄯鄹酃酆刍奂劢劬劭劾哿勐勖勰叟燮矍廴凵凼鬯厶弁畚巯坌垩垡塾墼壅壑圩圬圪圳圹圮圯坜圻坂坩垅坫垆坼坻坨坭坶坳垭垤垌垲埏垧垴垓垠埕埘埚埙埒垸埴埯埸埤埝\"],[\"dc40\",\"蹳蹵蹷\",4,\"蹽蹾躀躂躃躄躆躈\",6,\"躑躒躓躕\",6,\"躝躟\",11,\"躭躮躰躱躳\",6,\"躻\",7],[\"dc80\",\"軃\",10,\"軏\",21,\"堋堍埽埭堀堞堙塄堠塥塬墁墉墚墀馨鼙懿艹艽艿芏芊芨芄芎芑芗芙芫芸芾芰苈苊苣芘芷芮苋苌苁芩芴芡芪芟苄苎芤苡茉苷苤茏茇苜苴苒苘茌苻苓茑茚茆茔茕苠苕茜荑荛荜茈莒茼茴茱莛荞茯荏荇荃荟荀茗荠茭茺茳荦荥\"],[\"dd40\",\"軥\",62],[\"dd80\",\"輤\",32,\"荨茛荩荬荪荭荮莰荸莳莴莠莪莓莜莅荼莶莩荽莸荻莘莞莨莺莼菁萁菥菘堇萘萋菝菽菖萜萸萑萆菔菟萏萃菸菹菪菅菀萦菰菡葜葑葚葙葳蒇蒈葺蒉葸萼葆葩葶蒌蒎萱葭蓁蓍蓐蓦蒽蓓蓊蒿蒺蓠蒡蒹蒴蒗蓥蓣蔌甍蔸蓰蔹蔟蔺\"],[\"de40\",\"轅\",32,\"轪辀辌辒辝辠辡辢辤辥辦辧辪辬辭辮辯農辳辴辵辷辸辺辻込辿迀迃迆\"],[\"de80\",\"迉\",4,\"迏迒迖迗迚迠迡迣迧迬迯迱迲迴迵迶迺迻迼迾迿逇逈逌逎逓逕逘蕖蔻蓿蓼蕙蕈蕨蕤蕞蕺瞢蕃蕲蕻薤薨薇薏蕹薮薜薅薹薷薰藓藁藜藿蘧蘅蘩蘖蘼廾弈夼奁耷奕奚奘匏尢尥尬尴扌扪抟抻拊拚拗拮挢拶挹捋捃掭揶捱捺掎掴捭掬掊捩掮掼揲揸揠揿揄揞揎摒揆掾摅摁搋搛搠搌搦搡摞撄摭撖\"],[\"df40\",\"這逜連逤逥逧\",5,\"逰\",4,\"逷逹逺逽逿遀遃遅遆遈\",4,\"過達違遖遙遚遜\",5,\"遤遦遧適遪遫遬遯\",4,\"遶\",6,\"遾邁\"],[\"df80\",\"還邅邆邇邉邊邌\",4,\"邒邔邖邘邚邜邞邟邠邤邥邧邨邩邫邭邲邷邼邽邿郀摺撷撸撙撺擀擐擗擤擢攉攥攮弋忒甙弑卟叱叽叩叨叻吒吖吆呋呒呓呔呖呃吡呗呙吣吲咂咔呷呱呤咚咛咄呶呦咝哐咭哂咴哒咧咦哓哔呲咣哕咻咿哌哙哚哜咩咪咤哝哏哞唛哧唠哽唔哳唢唣唏唑唧唪啧喏喵啉啭啁啕唿啐唼\"],[\"e040\",\"郂郃郆郈郉郋郌郍郒郔郕郖郘郙郚郞郟郠郣郤郥郩郪郬郮郰郱郲郳郵郶郷郹郺郻郼郿鄀鄁鄃鄅\",19,\"鄚鄛鄜\"],[\"e080\",\"鄝鄟鄠鄡鄤\",10,\"鄰鄲\",6,\"鄺\",8,\"酄唷啖啵啶啷唳唰啜喋嗒喃喱喹喈喁喟啾嗖喑啻嗟喽喾喔喙嗪嗷嗉嘟嗑嗫嗬嗔嗦嗝嗄嗯嗥嗲嗳嗌嗍嗨嗵嗤辔嘞嘈嘌嘁嘤嘣嗾嘀嘧嘭噘嘹噗嘬噍噢噙噜噌噔嚆噤噱噫噻噼嚅嚓嚯囔囗囝囡囵囫囹囿圄圊圉圜帏帙帔帑帱帻帼\"],[\"e140\",\"酅酇酈酑酓酔酕酖酘酙酛酜酟酠酦酧酨酫酭酳酺酻酼醀\",4,\"醆醈醊醎醏醓\",6,\"醜\",5,\"醤\",5,\"醫醬醰醱醲醳醶醷醸醹醻\"],[\"e180\",\"醼\",10,\"釈釋釐釒\",9,\"針\",8,\"帷幄幔幛幞幡岌屺岍岐岖岈岘岙岑岚岜岵岢岽岬岫岱岣峁岷峄峒峤峋峥崂崃崧崦崮崤崞崆崛嵘崾崴崽嵬嵛嵯嵝嵫嵋嵊嵩嵴嶂嶙嶝豳嶷巅彳彷徂徇徉後徕徙徜徨徭徵徼衢彡犭犰犴犷犸狃狁狎狍狒狨狯狩狲狴狷猁狳猃狺\"],[\"e240\",\"釦\",62],[\"e280\",\"鈥\",32,\"狻猗猓猡猊猞猝猕猢猹猥猬猸猱獐獍獗獠獬獯獾舛夥飧夤夂饣饧\",5,\"饴饷饽馀馄馇馊馍馐馑馓馔馕庀庑庋庖庥庠庹庵庾庳赓廒廑廛廨廪膺忄忉忖忏怃忮怄忡忤忾怅怆忪忭忸怙怵怦怛怏怍怩怫怊怿怡恸恹恻恺恂\"],[\"e340\",\"鉆\",45,\"鉵\",16],[\"e380\",\"銆\",7,\"銏\",24,\"恪恽悖悚悭悝悃悒悌悛惬悻悱惝惘惆惚悴愠愦愕愣惴愀愎愫慊慵憬憔憧憷懔懵忝隳闩闫闱闳闵闶闼闾阃阄阆阈阊阋阌阍阏阒阕阖阗阙阚丬爿戕氵汔汜汊沣沅沐沔沌汨汩汴汶沆沩泐泔沭泷泸泱泗沲泠泖泺泫泮沱泓泯泾\"],[\"e440\",\"銨\",5,\"銯\",24,\"鋉\",31],[\"e480\",\"鋩\",32,\"洹洧洌浃浈洇洄洙洎洫浍洮洵洚浏浒浔洳涑浯涞涠浞涓涔浜浠浼浣渚淇淅淞渎涿淠渑淦淝淙渖涫渌涮渫湮湎湫溲湟溆湓湔渲渥湄滟溱溘滠漭滢溥溧溽溻溷滗溴滏溏滂溟潢潆潇漤漕滹漯漶潋潴漪漉漩澉澍澌潸潲潼潺濑\"],[\"e540\",\"錊\",51,\"錿\",10],[\"e580\",\"鍊\",31,\"鍫濉澧澹澶濂濡濮濞濠濯瀚瀣瀛瀹瀵灏灞宀宄宕宓宥宸甯骞搴寤寮褰寰蹇謇辶迓迕迥迮迤迩迦迳迨逅逄逋逦逑逍逖逡逵逶逭逯遄遑遒遐遨遘遢遛暹遴遽邂邈邃邋彐彗彖彘尻咫屐屙孱屣屦羼弪弩弭艴弼鬻屮妁妃妍妩妪妣\"],[\"e640\",\"鍬\",34,\"鎐\",27],[\"e680\",\"鎬\",29,\"鏋鏌鏍妗姊妫妞妤姒妲妯姗妾娅娆姝娈姣姘姹娌娉娲娴娑娣娓婀婧婊婕娼婢婵胬媪媛婷婺媾嫫媲嫒嫔媸嫠嫣嫱嫖嫦嫘嫜嬉嬗嬖嬲嬷孀尕尜孚孥孳孑孓孢驵驷驸驺驿驽骀骁骅骈骊骐骒骓骖骘骛骜骝骟骠骢骣骥骧纟纡纣纥纨纩\"],[\"e740\",\"鏎\",7,\"鏗\",54],[\"e780\",\"鐎\",32,\"纭纰纾绀绁绂绉绋绌绐绔绗绛绠绡绨绫绮绯绱绲缍绶绺绻绾缁缂缃缇缈缋缌缏缑缒缗缙缜缛缟缡\",6,\"缪缫缬缭缯\",4,\"缵幺畿巛甾邕玎玑玮玢玟珏珂珑玷玳珀珉珈珥珙顼琊珩珧珞玺珲琏琪瑛琦琥琨琰琮琬\"],[\"e840\",\"鐯\",14,\"鐿\",43,\"鑬鑭鑮鑯\"],[\"e880\",\"鑰\",20,\"钑钖钘铇铏铓铔铚铦铻锜锠琛琚瑁瑜瑗瑕瑙瑷瑭瑾璜璎璀璁璇璋璞璨璩璐璧瓒璺韪韫韬杌杓杞杈杩枥枇杪杳枘枧杵枨枞枭枋杷杼柰栉柘栊柩枰栌柙枵柚枳柝栀柃枸柢栎柁柽栲栳桠桡桎桢桄桤梃栝桕桦桁桧桀栾桊桉栩梵梏桴桷梓桫棂楮棼椟椠棹\"],[\"e940\",\"锧锳锽镃镈镋镕镚镠镮镴镵長\",7,\"門\",42],[\"e980\",\"閫\",32,\"椤棰椋椁楗棣椐楱椹楠楂楝榄楫榀榘楸椴槌榇榈槎榉楦楣楹榛榧榻榫榭槔榱槁槊槟榕槠榍槿樯槭樗樘橥槲橄樾檠橐橛樵檎橹樽樨橘橼檑檐檩檗檫猷獒殁殂殇殄殒殓殍殚殛殡殪轫轭轱轲轳轵轶轸轷轹轺轼轾辁辂辄辇辋\"],[\"ea40\",\"闌\",27,\"闬闿阇阓阘阛阞阠阣\",6,\"阫阬阭阯阰阷阸阹阺阾陁陃陊陎陏陑陒陓陖陗\"],[\"ea80\",\"陘陙陚陜陝陞陠陣陥陦陫陭\",4,\"陳陸\",12,\"隇隉隊辍辎辏辘辚軎戋戗戛戟戢戡戥戤戬臧瓯瓴瓿甏甑甓攴旮旯旰昊昙杲昃昕昀炅曷昝昴昱昶昵耆晟晔晁晏晖晡晗晷暄暌暧暝暾曛曜曦曩贲贳贶贻贽赀赅赆赈赉赇赍赕赙觇觊觋觌觎觏觐觑牮犟牝牦牯牾牿犄犋犍犏犒挈挲掰\"],[\"eb40\",\"隌階隑隒隓隕隖隚際隝\",9,\"隨\",7,\"隱隲隴隵隷隸隺隻隿雂雃雈雊雋雐雑雓雔雖\",9,\"雡\",6,\"雫\"],[\"eb80\",\"雬雭雮雰雱雲雴雵雸雺電雼雽雿霂霃霅霊霋霌霐霑霒霔霕霗\",4,\"霝霟霠搿擘耄毪毳毽毵毹氅氇氆氍氕氘氙氚氡氩氤氪氲攵敕敫牍牒牖爰虢刖肟肜肓肼朊肽肱肫肭肴肷胧胨胩胪胛胂胄胙胍胗朐胝胫胱胴胭脍脎胲胼朕脒豚脶脞脬脘脲腈腌腓腴腙腚腱腠腩腼腽腭腧塍媵膈膂膑滕膣膪臌朦臊膻\"],[\"ec40\",\"霡\",8,\"霫霬霮霯霱霳\",4,\"霺霻霼霽霿\",18,\"靔靕靗靘靚靜靝靟靣靤靦靧靨靪\",7],[\"ec80\",\"靲靵靷\",4,\"靽\",7,\"鞆\",4,\"鞌鞎鞏鞐鞓鞕鞖鞗鞙\",4,\"臁膦欤欷欹歃歆歙飑飒飓飕飙飚殳彀毂觳斐齑斓於旆旄旃旌旎旒旖炀炜炖炝炻烀炷炫炱烨烊焐焓焖焯焱煳煜煨煅煲煊煸煺熘熳熵熨熠燠燔燧燹爝爨灬焘煦熹戾戽扃扈扉礻祀祆祉祛祜祓祚祢祗祠祯祧祺禅禊禚禧禳忑忐\"],[\"ed40\",\"鞞鞟鞡鞢鞤\",6,\"鞬鞮鞰鞱鞳鞵\",46],[\"ed80\",\"韤韥韨韮\",4,\"韴韷\",23,\"怼恝恚恧恁恙恣悫愆愍慝憩憝懋懑戆肀聿沓泶淼矶矸砀砉砗砘砑斫砭砜砝砹砺砻砟砼砥砬砣砩硎硭硖硗砦硐硇硌硪碛碓碚碇碜碡碣碲碹碥磔磙磉磬磲礅磴礓礤礞礴龛黹黻黼盱眄眍盹眇眈眚眢眙眭眦眵眸睐睑睇睃睚睨\"],[\"ee40\",\"頏\",62],[\"ee80\",\"顎\",32,\"睢睥睿瞍睽瞀瞌瞑瞟瞠瞰瞵瞽町畀畎畋畈畛畲畹疃罘罡罟詈罨罴罱罹羁罾盍盥蠲钅钆钇钋钊钌钍钏钐钔钗钕钚钛钜钣钤钫钪钭钬钯钰钲钴钶\",4,\"钼钽钿铄铈\",6,\"铐铑铒铕铖铗铙铘铛铞铟铠铢铤铥铧铨铪\"],[\"ef40\",\"顯\",5,\"颋颎颒颕颙颣風\",37,\"飏飐飔飖飗飛飜飝飠\",4],[\"ef80\",\"飥飦飩\",30,\"铩铫铮铯铳铴铵铷铹铼铽铿锃锂锆锇锉锊锍锎锏锒\",4,\"锘锛锝锞锟锢锪锫锩锬锱锲锴锶锷锸锼锾锿镂锵镄镅镆镉镌镎镏镒镓镔镖镗镘镙镛镞镟镝镡镢镤\",8,\"镯镱镲镳锺矧矬雉秕秭秣秫稆嵇稃稂稞稔\"],[\"f040\",\"餈\",4,\"餎餏餑\",28,\"餯\",26],[\"f080\",\"饊\",9,\"饖\",12,\"饤饦饳饸饹饻饾馂馃馉稹稷穑黏馥穰皈皎皓皙皤瓞瓠甬鸠鸢鸨\",4,\"鸲鸱鸶鸸鸷鸹鸺鸾鹁鹂鹄鹆鹇鹈鹉鹋鹌鹎鹑鹕鹗鹚鹛鹜鹞鹣鹦\",6,\"鹱鹭鹳疒疔疖疠疝疬疣疳疴疸痄疱疰痃痂痖痍痣痨痦痤痫痧瘃痱痼痿瘐瘀瘅瘌瘗瘊瘥瘘瘕瘙\"],[\"f140\",\"馌馎馚\",10,\"馦馧馩\",47],[\"f180\",\"駙\",32,\"瘛瘼瘢瘠癀瘭瘰瘿瘵癃瘾瘳癍癞癔癜癖癫癯翊竦穸穹窀窆窈窕窦窠窬窨窭窳衤衩衲衽衿袂袢裆袷袼裉裢裎裣裥裱褚裼裨裾裰褡褙褓褛褊褴褫褶襁襦襻疋胥皲皴矜耒耔耖耜耠耢耥耦耧耩耨耱耋耵聃聆聍聒聩聱覃顸颀颃\"],[\"f240\",\"駺\",62],[\"f280\",\"騹\",32,\"颉颌颍颏颔颚颛颞颟颡颢颥颦虍虔虬虮虿虺虼虻蚨蚍蚋蚬蚝蚧蚣蚪蚓蚩蚶蛄蚵蛎蚰蚺蚱蚯蛉蛏蚴蛩蛱蛲蛭蛳蛐蜓蛞蛴蛟蛘蛑蜃蜇蛸蜈蜊蜍蜉蜣蜻蜞蜥蜮蜚蜾蝈蜴蜱蜩蜷蜿螂蜢蝽蝾蝻蝠蝰蝌蝮螋蝓蝣蝼蝤蝙蝥螓螯螨蟒\"],[\"f340\",\"驚\",17,\"驲骃骉骍骎骔骕骙骦骩\",6,\"骲骳骴骵骹骻骽骾骿髃髄髆\",4,\"髍髎髏髐髒體髕髖髗髙髚髛髜\"],[\"f380\",\"髝髞髠髢髣髤髥髧髨髩髪髬髮髰\",8,\"髺髼\",6,\"鬄鬅鬆蟆螈螅螭螗螃螫蟥螬螵螳蟋蟓螽蟑蟀蟊蟛蟪蟠蟮蠖蠓蟾蠊蠛蠡蠹蠼缶罂罄罅舐竺竽笈笃笄笕笊笫笏筇笸笪笙笮笱笠笥笤笳笾笞筘筚筅筵筌筝筠筮筻筢筲筱箐箦箧箸箬箝箨箅箪箜箢箫箴篑篁篌篝篚篥篦篪簌篾篼簏簖簋\"],[\"f440\",\"鬇鬉\",5,\"鬐鬑鬒鬔\",10,\"鬠鬡鬢鬤\",10,\"鬰鬱鬳\",7,\"鬽鬾鬿魀魆魊魋魌魎魐魒魓魕\",5],[\"f480\",\"魛\",32,\"簟簪簦簸籁籀臾舁舂舄臬衄舡舢舣舭舯舨舫舸舻舳舴舾艄艉艋艏艚艟艨衾袅袈裘裟襞羝羟羧羯羰羲籼敉粑粝粜粞粢粲粼粽糁糇糌糍糈糅糗糨艮暨羿翎翕翥翡翦翩翮翳糸絷綦綮繇纛麸麴赳趄趔趑趱赧赭豇豉酊酐酎酏酤\"],[\"f540\",\"魼\",62],[\"f580\",\"鮻\",32,\"酢酡酰酩酯酽酾酲酴酹醌醅醐醍醑醢醣醪醭醮醯醵醴醺豕鹾趸跫踅蹙蹩趵趿趼趺跄跖跗跚跞跎跏跛跆跬跷跸跣跹跻跤踉跽踔踝踟踬踮踣踯踺蹀踹踵踽踱蹉蹁蹂蹑蹒蹊蹰蹶蹼蹯蹴躅躏躔躐躜躞豸貂貊貅貘貔斛觖觞觚觜\"],[\"f640\",\"鯜\",62],[\"f680\",\"鰛\",32,\"觥觫觯訾謦靓雩雳雯霆霁霈霏霎霪霭霰霾龀龃龅\",5,\"龌黾鼋鼍隹隼隽雎雒瞿雠銎銮鋈錾鍪鏊鎏鐾鑫鱿鲂鲅鲆鲇鲈稣鲋鲎鲐鲑鲒鲔鲕鲚鲛鲞\",5,\"鲥\",4,\"鲫鲭鲮鲰\",7,\"鲺鲻鲼鲽鳄鳅鳆鳇鳊鳋\"],[\"f740\",\"鰼\",62],[\"f780\",\"鱻鱽鱾鲀鲃鲄鲉鲊鲌鲏鲓鲖鲗鲘鲙鲝鲪鲬鲯鲹鲾\",4,\"鳈鳉鳑鳒鳚鳛鳠鳡鳌\",4,\"鳓鳔鳕鳗鳘鳙鳜鳝鳟鳢靼鞅鞑鞒鞔鞯鞫鞣鞲鞴骱骰骷鹘骶骺骼髁髀髅髂髋髌髑魅魃魇魉魈魍魑飨餍餮饕饔髟髡髦髯髫髻髭髹鬈鬏鬓鬟鬣麽麾縻麂麇麈麋麒鏖麝麟黛黜黝黠黟黢黩黧黥黪黯鼢鼬鼯鼹鼷鼽鼾齄\"],[\"f840\",\"鳣\",62],[\"f880\",\"鴢\",32],[\"f940\",\"鵃\",62],[\"f980\",\"鶂\",32],[\"fa40\",\"鶣\",62],[\"fa80\",\"鷢\",32],[\"fb40\",\"鸃\",27,\"鸤鸧鸮鸰鸴鸻鸼鹀鹍鹐鹒鹓鹔鹖鹙鹝鹟鹠鹡鹢鹥鹮鹯鹲鹴\",9,\"麀\"],[\"fb80\",\"麁麃麄麅麆麉麊麌\",5,\"麔\",8,\"麞麠\",5,\"麧麨麩麪\"],[\"fc40\",\"麫\",8,\"麵麶麷麹麺麼麿\",4,\"黅黆黇黈黊黋黌黐黒黓黕黖黗黙黚點黡黣黤黦黨黫黬黭黮黰\",8,\"黺黽黿\",6],[\"fc80\",\"鼆\",4,\"鼌鼏鼑鼒鼔鼕鼖鼘鼚\",5,\"鼡鼣\",8,\"鼭鼮鼰鼱\"],[\"fd40\",\"鼲\",4,\"鼸鼺鼼鼿\",4,\"齅\",10,\"齒\",38],[\"fd80\",\"齹\",5,\"龁龂龍\",11,\"龜龝龞龡\",4,\"郎凉秊裏隣\"],[\"fe40\",\"兀嗀﨎﨏﨑﨓﨔礼﨟蘒﨡﨣﨤﨧﨨﨩\"]]\n\n/***/ }),\n/* 54 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// fallback for non-array-like ES3 and non-enumerable old V8 strings\nvar cof = __webpack_require__(55);\n// eslint-disable-next-line no-prototype-builtins\nmodule.exports = Object('z').propertyIsEnumerable(0) ? Object : function (it) {\n  return cof(it) == 'String' ? it.split('') : Object(it);\n};\n\n\n/***/ }),\n/* 55 */\n/***/ (function(module, exports) {\n\nvar toString = {}.toString;\n\nmodule.exports = function (it) {\n  return toString.call(it).slice(8, -1);\n};\n\n\n/***/ }),\n/* 56 */\n/***/ (function(module, exports) {\n\n// 7.2.1 RequireObjectCoercible(argument)\nmodule.exports = function (it) {\n  if (it == undefined) throw TypeError(\"Can't call method on  \" + it);\n  return it;\n};\n\n\n/***/ }),\n/* 57 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar pIE = __webpack_require__(35);\nvar createDesc = __webpack_require__(27);\nvar toIObject = __webpack_require__(17);\nvar toPrimitive = __webpack_require__(58);\nvar has = __webpack_require__(18);\nvar IE8_DOM_DEFINE = __webpack_require__(95);\nvar gOPD = Object.getOwnPropertyDescriptor;\n\nexports.f = __webpack_require__(5) ? gOPD : function getOwnPropertyDescriptor(O, P) {\n  O = toIObject(O);\n  P = toPrimitive(P, true);\n  if (IE8_DOM_DEFINE) try {\n    return gOPD(O, P);\n  } catch (e) { /* empty */ }\n  if (has(O, P)) return createDesc(!pIE.f.call(O, P), O[P]);\n};\n\n\n/***/ }),\n/* 58 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 7.1.1 ToPrimitive(input [, PreferredType])\nvar isObject = __webpack_require__(9);\n// instead of the ES6 spec version, we didn't implement @@toPrimitive case\n// and the second argument - flag - preferred type is a string\nmodule.exports = function (it, S) {\n  if (!isObject(it)) return it;\n  var fn, val;\n  if (S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val;\n  if (typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it))) return val;\n  if (!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val;\n  throw TypeError(\"Can't convert object to primitive value\");\n};\n\n\n/***/ }),\n/* 59 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// most Object methods by ES6 should accept primitives\nvar $export = __webpack_require__(3);\nvar core = __webpack_require__(2);\nvar fails = __webpack_require__(19);\nmodule.exports = function (KEY, exec) {\n  var fn = (core.Object || {})[KEY] || Object[KEY];\n  var exp = {};\n  exp[KEY] = exec(fn);\n  $export($export.S + $export.F * fails(function () { fn(1); }), 'Object', exp);\n};\n\n\n/***/ }),\n/* 60 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(200), __esModule: true };\n\n/***/ }),\n/* 61 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar LIBRARY = __webpack_require__(62);\nvar $export = __webpack_require__(3);\nvar redefine = __webpack_require__(99);\nvar hide = __webpack_require__(13);\nvar has = __webpack_require__(18);\nvar Iterators = __webpack_require__(23);\nvar $iterCreate = __webpack_require__(203);\nvar setToStringTag = __webpack_require__(39);\nvar getPrototypeOf = __webpack_require__(206);\nvar ITERATOR = __webpack_require__(4)('iterator');\nvar BUGGY = !([].keys && 'next' in [].keys()); // Safari has buggy iterators w/o `next`\nvar FF_ITERATOR = '@@iterator';\nvar KEYS = 'keys';\nvar VALUES = 'values';\n\nvar returnThis = function () { return this; };\n\nmodule.exports = function (Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED) {\n  $iterCreate(Constructor, NAME, next);\n  var getMethod = function (kind) {\n    if (!BUGGY && kind in proto) return proto[kind];\n    switch (kind) {\n      case KEYS: return function keys() { return new Constructor(this, kind); };\n      case VALUES: return function values() { return new Constructor(this, kind); };\n    } return function entries() { return new Constructor(this, kind); };\n  };\n  var TAG = NAME + ' Iterator';\n  var DEF_VALUES = DEFAULT == VALUES;\n  var VALUES_BUG = false;\n  var proto = Base.prototype;\n  var $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT];\n  var $default = (!BUGGY && $native) || getMethod(DEFAULT);\n  var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined;\n  var $anyNative = NAME == 'Array' ? proto.entries || $native : $native;\n  var methods, key, IteratorPrototype;\n  // Fix native\n  if ($anyNative) {\n    IteratorPrototype = getPrototypeOf($anyNative.call(new Base()));\n    if (IteratorPrototype !== Object.prototype && IteratorPrototype.next) {\n      // Set @@toStringTag to native iterators\n      setToStringTag(IteratorPrototype, TAG, true);\n      // fix for some old engines\n      if (!LIBRARY && !has(IteratorPrototype, ITERATOR)) hide(IteratorPrototype, ITERATOR, returnThis);\n    }\n  }\n  // fix Array#{values, @@iterator}.name in V8 / FF\n  if (DEF_VALUES && $native && $native.name !== VALUES) {\n    VALUES_BUG = true;\n    $default = function values() { return $native.call(this); };\n  }\n  // Define iterator\n  if ((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])) {\n    hide(proto, ITERATOR, $default);\n  }\n  // Plug for library\n  Iterators[NAME] = $default;\n  Iterators[TAG] = returnThis;\n  if (DEFAULT) {\n    methods = {\n      values: DEF_VALUES ? $default : getMethod(VALUES),\n      keys: IS_SET ? $default : getMethod(KEYS),\n      entries: $entries\n    };\n    if (FORCED) for (key in methods) {\n      if (!(key in proto)) redefine(proto, key, methods[key]);\n    } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods);\n  }\n  return methods;\n};\n\n\n/***/ }),\n/* 62 */\n/***/ (function(module, exports) {\n\nmodule.exports = true;\n\n\n/***/ }),\n/* 63 */\n/***/ (function(module, exports) {\n\n// 7.1.4 ToInteger\nvar ceil = Math.ceil;\nvar floor = Math.floor;\nmodule.exports = function (it) {\n  return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it);\n};\n\n\n/***/ }),\n/* 64 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar shared = __webpack_require__(65)('keys');\nvar uid = __webpack_require__(38);\nmodule.exports = function (key) {\n  return shared[key] || (shared[key] = uid(key));\n};\n\n\n/***/ }),\n/* 65 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar global = __webpack_require__(10);\nvar SHARED = '__core-js_shared__';\nvar store = global[SHARED] || (global[SHARED] = {});\nmodule.exports = function (key) {\n  return store[key] || (store[key] = {});\n};\n\n\n/***/ }),\n/* 66 */\n/***/ (function(module, exports) {\n\n// IE 8- don't enum bug keys\nmodule.exports = (\n  'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf'\n).split(',');\n\n\n/***/ }),\n/* 67 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar classof = __webpack_require__(68);\nvar ITERATOR = __webpack_require__(4)('iterator');\nvar Iterators = __webpack_require__(23);\nmodule.exports = __webpack_require__(2).getIteratorMethod = function (it) {\n  if (it != undefined) return it[ITERATOR]\n    || it['@@iterator']\n    || Iterators[classof(it)];\n};\n\n\n/***/ }),\n/* 68 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// getting tag from 19.1.3.6 Object.prototype.toString()\nvar cof = __webpack_require__(55);\nvar TAG = __webpack_require__(4)('toStringTag');\n// ES3 wrong here\nvar ARG = cof(function () { return arguments; }()) == 'Arguments';\n\n// fallback for IE11 Script Access Denied error\nvar tryGet = function (it, key) {\n  try {\n    return it[key];\n  } catch (e) { /* empty */ }\n};\n\nmodule.exports = function (it) {\n  var O, T, B;\n  return it === undefined ? 'Undefined' : it === null ? 'Null'\n    // @@toStringTag case\n    : typeof (T = tryGet(O = Object(it), TAG)) == 'string' ? T\n    // builtinTag case\n    : ARG ? cof(O)\n    // ES3 arguments fallback\n    : (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B;\n};\n\n\n/***/ }),\n/* 69 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nvar _iterator = __webpack_require__(103);\n\nvar _iterator2 = _interopRequireDefault(_iterator);\n\nvar _symbol = __webpack_require__(216);\n\nvar _symbol2 = _interopRequireDefault(_symbol);\n\nvar _typeof = typeof _symbol2.default === \"function\" && typeof _iterator2.default === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof _symbol2.default === \"function\" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? \"symbol\" : typeof obj; };\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nexports.default = typeof _symbol2.default === \"function\" && _typeof(_iterator2.default) === \"symbol\" ? function (obj) {\n  return typeof obj === \"undefined\" ? \"undefined\" : _typeof(obj);\n} : function (obj) {\n  return obj && typeof _symbol2.default === \"function\" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? \"symbol\" : typeof obj === \"undefined\" ? \"undefined\" : _typeof(obj);\n};\n\n/***/ }),\n/* 70 */\n/***/ (function(module, exports, __webpack_require__) {\n\nexports.f = __webpack_require__(4);\n\n\n/***/ }),\n/* 71 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar global = __webpack_require__(10);\nvar core = __webpack_require__(2);\nvar LIBRARY = __webpack_require__(62);\nvar wksExt = __webpack_require__(70);\nvar defineProperty = __webpack_require__(6).f;\nmodule.exports = function (name) {\n  var $Symbol = core.Symbol || (core.Symbol = LIBRARY ? {} : global.Symbol || {});\n  if (name.charAt(0) != '_' && !(name in $Symbol)) defineProperty($Symbol, name, { value: wksExt.f(name) });\n};\n\n\n/***/ }),\n/* 72 */\n/***/ (function(module, exports) {\n\nexports.f = Object.getOwnPropertySymbols;\n\n\n/***/ }),\n/* 73 */\n/***/ (function(module, exports) {\n\n\n\n/***/ }),\n/* 74 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(223), __esModule: true };\n\n/***/ }),\n/* 75 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar isObject = __webpack_require__(9);\nmodule.exports = function (it, TYPE) {\n  if (!isObject(it) || it._t !== TYPE) throw TypeError('Incompatible receiver, ' + TYPE + ' required!');\n  return it;\n};\n\n\n/***/ }),\n/* 76 */\n/***/ (function(module, exports) {\n\nvar toString = {}.toString;\n\nmodule.exports = Array.isArray || function (arr) {\n  return toString.call(arr) == '[object Array]';\n};\n\n\n/***/ }),\n/* 77 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nfunction TraversalTracker() {\n\tthis.events = {};\n}\n\nTraversalTracker.prototype.startTracking = function (event, callback) {\n\tvar callbacks = this.events[event] || (this.events[event] = []);\n\n\tif (callbacks.indexOf(callback) < 0) {\n\t\tcallbacks.push(callback);\n\t}\n};\n\nTraversalTracker.prototype.stopTracking = function (event, callback) {\n\tvar callbacks = this.events[event];\n\n\tif (!callbacks) {\n\t\treturn;\n\t}\n\n\tvar index = callbacks.indexOf(callback);\n\tif (index >= 0) {\n\t\tcallbacks.splice(index, 1);\n\t}\n};\n\nTraversalTracker.prototype.emit = function (event) {\n\tvar args = Array.prototype.slice.call(arguments, 1);\n\tvar callbacks = this.events[event];\n\n\tif (!callbacks) {\n\t\treturn;\n\t}\n\n\tcallbacks.forEach(function (callback) {\n\t\tcallback.apply(this, args);\n\t});\n};\n\nTraversalTracker.prototype.auto = function (event, callback, innerFunction) {\n\tthis.startTracking(event, callback);\n\tinnerFunction();\n\tthis.stopTracking(event, callback);\n};\n\nmodule.exports = TraversalTracker;\n\n\n/***/ }),\n/* 78 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var AI, AL, BA, BK, CB, CI_BRK, CJ, CP_BRK, CR, DI_BRK, ID, IN_BRK, LF, LineBreaker, NL, NS, PR_BRK, SA, SG, SP, UnicodeTrie, WJ, XX, base64, characterClasses, classTrie, data, fs, pairTable, _ref, _ref1;\n\n  UnicodeTrie = __webpack_require__(43);\n\n  \n\n  base64 = __webpack_require__(131);\n\n  _ref = __webpack_require__(132), BK = _ref.BK, CR = _ref.CR, LF = _ref.LF, NL = _ref.NL, CB = _ref.CB, BA = _ref.BA, SP = _ref.SP, WJ = _ref.WJ, SP = _ref.SP, BK = _ref.BK, LF = _ref.LF, NL = _ref.NL, AI = _ref.AI, AL = _ref.AL, SA = _ref.SA, SG = _ref.SG, XX = _ref.XX, CJ = _ref.CJ, ID = _ref.ID, NS = _ref.NS, characterClasses = _ref.characterClasses;\n\n  _ref1 = __webpack_require__(133), DI_BRK = _ref1.DI_BRK, IN_BRK = _ref1.IN_BRK, CI_BRK = _ref1.CI_BRK, CP_BRK = _ref1.CP_BRK, PR_BRK = _ref1.PR_BRK, pairTable = _ref1.pairTable;\n\n  data = base64.toByteArray(\"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\");\n\n  classTrie = new UnicodeTrie(data);\n\n  LineBreaker = (function() {\n    var Break, mapClass, mapFirst;\n\n    function LineBreaker(string) {\n      this.string = string;\n      this.pos = 0;\n      this.lastPos = 0;\n      this.curClass = null;\n      this.nextClass = null;\n    }\n\n    LineBreaker.prototype.nextCodePoint = function() {\n      var code, next;\n      code = this.string.charCodeAt(this.pos++);\n      next = this.string.charCodeAt(this.pos);\n      if ((0xd800 <= code && code <= 0xdbff) && (0xdc00 <= next && next <= 0xdfff)) {\n        this.pos++;\n        return ((code - 0xd800) * 0x400) + (next - 0xdc00) + 0x10000;\n      }\n      return code;\n    };\n\n    mapClass = function(c) {\n      switch (c) {\n        case AI:\n          return AL;\n        case SA:\n        case SG:\n        case XX:\n          return AL;\n        case CJ:\n          return NS;\n        default:\n          return c;\n      }\n    };\n\n    mapFirst = function(c) {\n      switch (c) {\n        case LF:\n        case NL:\n          return BK;\n        case CB:\n          return BA;\n        case SP:\n          return WJ;\n        default:\n          return c;\n      }\n    };\n\n    LineBreaker.prototype.nextCharClass = function(first) {\n      if (first == null) {\n        first = false;\n      }\n      return mapClass(classTrie.get(this.nextCodePoint()));\n    };\n\n    Break = (function() {\n      function Break(position, required) {\n        this.position = position;\n        this.required = required != null ? required : false;\n      }\n\n      return Break;\n\n    })();\n\n    LineBreaker.prototype.nextBreak = function() {\n      var cur, lastClass, shouldBreak;\n      if (this.curClass == null) {\n        this.curClass = mapFirst(this.nextCharClass());\n      }\n      while (this.pos < this.string.length) {\n        this.lastPos = this.pos;\n        lastClass = this.nextClass;\n        this.nextClass = this.nextCharClass();\n        if (this.curClass === BK || (this.curClass === CR && this.nextClass !== LF)) {\n          this.curClass = mapFirst(mapClass(this.nextClass));\n          return new Break(this.lastPos, true);\n        }\n        cur = (function() {\n          switch (this.nextClass) {\n            case SP:\n              return this.curClass;\n            case BK:\n            case LF:\n            case NL:\n              return BK;\n            case CR:\n              return CR;\n            case CB:\n              return BA;\n          }\n        }).call(this);\n        if (cur != null) {\n          this.curClass = cur;\n          if (this.nextClass === CB) {\n            return new Break(this.lastPos);\n          }\n          continue;\n        }\n        shouldBreak = false;\n        switch (pairTable[this.curClass][this.nextClass]) {\n          case DI_BRK:\n            shouldBreak = true;\n            break;\n          case IN_BRK:\n            shouldBreak = lastClass === SP;\n            break;\n          case CI_BRK:\n            shouldBreak = lastClass === SP;\n            if (!shouldBreak) {\n              continue;\n            }\n            break;\n          case CP_BRK:\n            if (lastClass !== SP) {\n              continue;\n            }\n        }\n        this.curClass = this.nextClass;\n        if (shouldBreak) {\n          return new Break(this.lastPos);\n        }\n      }\n      if (this.pos >= this.string.length) {\n        if (this.lastPos < this.string.length) {\n          this.lastPos = this.string.length;\n          return new Break(this.string.length);\n        } else {\n          return null;\n        }\n      }\n    };\n\n    return LineBreaker;\n\n  })();\n\n  module.exports = LineBreaker;\n\n}).call(this);\n\n\n/***/ }),\n/* 79 */\n/***/ (function(module, exports) {\n\nvar TINF_OK = 0;\nvar TINF_DATA_ERROR = -3;\n\nfunction Tree() {\n  this.table = new Uint16Array(16);   /* table of code length counts */\n  this.trans = new Uint16Array(288);  /* code -> symbol translation table */\n}\n\nfunction Data(source, dest) {\n  this.source = source;\n  this.sourceIndex = 0;\n  this.tag = 0;\n  this.bitcount = 0;\n  \n  this.dest = dest;\n  this.destLen = 0;\n  \n  this.ltree = new Tree();  /* dynamic length/symbol tree */\n  this.dtree = new Tree();  /* dynamic distance tree */\n}\n\n/* --------------------------------------------------- *\n * -- uninitialized global data (static structures) -- *\n * --------------------------------------------------- */\n\nvar sltree = new Tree();\nvar sdtree = new Tree();\n\n/* extra bits and base tables for length codes */\nvar length_bits = new Uint8Array(30);\nvar length_base = new Uint16Array(30);\n\n/* extra bits and base tables for distance codes */\nvar dist_bits = new Uint8Array(30);\nvar dist_base = new Uint16Array(30);\n\n/* special ordering of code length codes */\nvar clcidx = new Uint8Array([\n  16, 17, 18, 0, 8, 7, 9, 6,\n  10, 5, 11, 4, 12, 3, 13, 2,\n  14, 1, 15\n]);\n\n/* used by tinf_decode_trees, avoids allocations every call */\nvar code_tree = new Tree();\nvar lengths = new Uint8Array(288 + 32);\n\n/* ----------------------- *\n * -- utility functions -- *\n * ----------------------- */\n\n/* build extra bits and base tables */\nfunction tinf_build_bits_base(bits, base, delta, first) {\n  var i, sum;\n\n  /* build bits table */\n  for (i = 0; i < delta; ++i) bits[i] = 0;\n  for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta | 0;\n\n  /* build base table */\n  for (sum = first, i = 0; i < 30; ++i) {\n    base[i] = sum;\n    sum += 1 << bits[i];\n  }\n}\n\n/* build the fixed huffman trees */\nfunction tinf_build_fixed_trees(lt, dt) {\n  var i;\n\n  /* build fixed length tree */\n  for (i = 0; i < 7; ++i) lt.table[i] = 0;\n\n  lt.table[7] = 24;\n  lt.table[8] = 152;\n  lt.table[9] = 112;\n\n  for (i = 0; i < 24; ++i) lt.trans[i] = 256 + i;\n  for (i = 0; i < 144; ++i) lt.trans[24 + i] = i;\n  for (i = 0; i < 8; ++i) lt.trans[24 + 144 + i] = 280 + i;\n  for (i = 0; i < 112; ++i) lt.trans[24 + 144 + 8 + i] = 144 + i;\n\n  /* build fixed distance tree */\n  for (i = 0; i < 5; ++i) dt.table[i] = 0;\n\n  dt.table[5] = 32;\n\n  for (i = 0; i < 32; ++i) dt.trans[i] = i;\n}\n\n/* given an array of code lengths, build a tree */\nvar offs = new Uint16Array(16);\n\nfunction tinf_build_tree(t, lengths, off, num) {\n  var i, sum;\n\n  /* clear code length count table */\n  for (i = 0; i < 16; ++i) t.table[i] = 0;\n\n  /* scan symbol lengths, and sum code length counts */\n  for (i = 0; i < num; ++i) t.table[lengths[off + i]]++;\n\n  t.table[0] = 0;\n\n  /* compute offset table for distribution sort */\n  for (sum = 0, i = 0; i < 16; ++i) {\n    offs[i] = sum;\n    sum += t.table[i];\n  }\n\n  /* create code->symbol translation table (symbols sorted by code) */\n  for (i = 0; i < num; ++i) {\n    if (lengths[off + i]) t.trans[offs[lengths[off + i]]++] = i;\n  }\n}\n\n/* ---------------------- *\n * -- decode functions -- *\n * ---------------------- */\n\n/* get one bit from source stream */\nfunction tinf_getbit(d) {\n  /* check if tag is empty */\n  if (!d.bitcount--) {\n    /* load next tag */\n    d.tag = d.source[d.sourceIndex++];\n    d.bitcount = 7;\n  }\n\n  /* shift bit out of tag */\n  var bit = d.tag & 1;\n  d.tag >>>= 1;\n\n  return bit;\n}\n\n/* read a num bit value from a stream and add base */\nfunction tinf_read_bits(d, num, base) {\n  if (!num)\n    return base;\n\n  while (d.bitcount < 24) {\n    d.tag |= d.source[d.sourceIndex++] << d.bitcount;\n    d.bitcount += 8;\n  }\n\n  var val = d.tag & (0xffff >>> (16 - num));\n  d.tag >>>= num;\n  d.bitcount -= num;\n  return val + base;\n}\n\n/* given a data stream and a tree, decode a symbol */\nfunction tinf_decode_symbol(d, t) {\n  while (d.bitcount < 24) {\n    d.tag |= d.source[d.sourceIndex++] << d.bitcount;\n    d.bitcount += 8;\n  }\n  \n  var sum = 0, cur = 0, len = 0;\n  var tag = d.tag;\n\n  /* get more bits while code value is above sum */\n  do {\n    cur = 2 * cur + (tag & 1);\n    tag >>>= 1;\n    ++len;\n\n    sum += t.table[len];\n    cur -= t.table[len];\n  } while (cur >= 0);\n  \n  d.tag = tag;\n  d.bitcount -= len;\n\n  return t.trans[sum + cur];\n}\n\n/* given a data stream, decode dynamic trees from it */\nfunction tinf_decode_trees(d, lt, dt) {\n  var hlit, hdist, hclen;\n  var i, num, length;\n\n  /* get 5 bits HLIT (257-286) */\n  hlit = tinf_read_bits(d, 5, 257);\n\n  /* get 5 bits HDIST (1-32) */\n  hdist = tinf_read_bits(d, 5, 1);\n\n  /* get 4 bits HCLEN (4-19) */\n  hclen = tinf_read_bits(d, 4, 4);\n\n  for (i = 0; i < 19; ++i) lengths[i] = 0;\n\n  /* read code lengths for code length alphabet */\n  for (i = 0; i < hclen; ++i) {\n    /* get 3 bits code length (0-7) */\n    var clen = tinf_read_bits(d, 3, 0);\n    lengths[clcidx[i]] = clen;\n  }\n\n  /* build code length tree */\n  tinf_build_tree(code_tree, lengths, 0, 19);\n\n  /* decode code lengths for the dynamic trees */\n  for (num = 0; num < hlit + hdist;) {\n    var sym = tinf_decode_symbol(d, code_tree);\n\n    switch (sym) {\n      case 16:\n        /* copy previous code length 3-6 times (read 2 bits) */\n        var prev = lengths[num - 1];\n        for (length = tinf_read_bits(d, 2, 3); length; --length) {\n          lengths[num++] = prev;\n        }\n        break;\n      case 17:\n        /* repeat code length 0 for 3-10 times (read 3 bits) */\n        for (length = tinf_read_bits(d, 3, 3); length; --length) {\n          lengths[num++] = 0;\n        }\n        break;\n      case 18:\n        /* repeat code length 0 for 11-138 times (read 7 bits) */\n        for (length = tinf_read_bits(d, 7, 11); length; --length) {\n          lengths[num++] = 0;\n        }\n        break;\n      default:\n        /* values 0-15 represent the actual code lengths */\n        lengths[num++] = sym;\n        break;\n    }\n  }\n\n  /* build dynamic trees */\n  tinf_build_tree(lt, lengths, 0, hlit);\n  tinf_build_tree(dt, lengths, hlit, hdist);\n}\n\n/* ----------------------------- *\n * -- block inflate functions -- *\n * ----------------------------- */\n\n/* given a stream and two trees, inflate a block of data */\nfunction tinf_inflate_block_data(d, lt, dt) {\n  while (1) {\n    var sym = tinf_decode_symbol(d, lt);\n\n    /* check for end of block */\n    if (sym === 256) {\n      return TINF_OK;\n    }\n\n    if (sym < 256) {\n      d.dest[d.destLen++] = sym;\n    } else {\n      var length, dist, offs;\n      var i;\n\n      sym -= 257;\n\n      /* possibly get more bits from length code */\n      length = tinf_read_bits(d, length_bits[sym], length_base[sym]);\n\n      dist = tinf_decode_symbol(d, dt);\n\n      /* possibly get more bits from distance code */\n      offs = d.destLen - tinf_read_bits(d, dist_bits[dist], dist_base[dist]);\n\n      /* copy match */\n      for (i = offs; i < offs + length; ++i) {\n        d.dest[d.destLen++] = d.dest[i];\n      }\n    }\n  }\n}\n\n/* inflate an uncompressed block of data */\nfunction tinf_inflate_uncompressed_block(d) {\n  var length, invlength;\n  var i;\n  \n  /* unread from bitbuffer */\n  while (d.bitcount > 8) {\n    d.sourceIndex--;\n    d.bitcount -= 8;\n  }\n\n  /* get length */\n  length = d.source[d.sourceIndex + 1];\n  length = 256 * length + d.source[d.sourceIndex];\n\n  /* get one's complement of length */\n  invlength = d.source[d.sourceIndex + 3];\n  invlength = 256 * invlength + d.source[d.sourceIndex + 2];\n\n  /* check length */\n  if (length !== (~invlength & 0x0000ffff))\n    return TINF_DATA_ERROR;\n\n  d.sourceIndex += 4;\n\n  /* copy block */\n  for (i = length; i; --i)\n    d.dest[d.destLen++] = d.source[d.sourceIndex++];\n\n  /* make sure we start next block on a byte boundary */\n  d.bitcount = 0;\n\n  return TINF_OK;\n}\n\n/* inflate stream from source to dest */\nfunction tinf_uncompress(source, dest) {\n  var d = new Data(source, dest);\n  var bfinal, btype, res;\n\n  do {\n    /* read final block flag */\n    bfinal = tinf_getbit(d);\n\n    /* read block type (2 bits) */\n    btype = tinf_read_bits(d, 2, 0);\n\n    /* decompress block */\n    switch (btype) {\n      case 0:\n        /* decompress uncompressed block */\n        res = tinf_inflate_uncompressed_block(d);\n        break;\n      case 1:\n        /* decompress block with fixed huffman trees */\n        res = tinf_inflate_block_data(d, sltree, sdtree);\n        break;\n      case 2:\n        /* decompress block with dynamic huffman trees */\n        tinf_decode_trees(d, d.ltree, d.dtree);\n        res = tinf_inflate_block_data(d, d.ltree, d.dtree);\n        break;\n      default:\n        res = TINF_DATA_ERROR;\n    }\n\n    if (res !== TINF_OK)\n      throw new Error('Data error');\n\n  } while (!bfinal);\n\n  if (d.destLen < d.dest.length) {\n    if (typeof d.dest.slice === 'function')\n      return d.dest.slice(0, d.destLen);\n    else\n      return d.dest.subarray(0, d.destLen);\n  }\n  \n  return d.dest;\n}\n\n/* -------------------- *\n * -- initialization -- *\n * -------------------- */\n\n/* build fixed huffman trees */\ntinf_build_fixed_trees(sltree, sdtree);\n\n/* build extra bits and base tables */\ntinf_build_bits_base(length_bits, length_base, 4, 3);\ntinf_build_bits_base(dist_bits, dist_base, 2, 1);\n\n/* fix a special case */\nlength_bits[28] = 0;\nlength_base[28] = 258;\n\nmodule.exports = tinf_uncompress;\n\n\n/***/ }),\n/* 80 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar isString = __webpack_require__(0).isString;\nvar isArray = __webpack_require__(0).isArray;\nvar isUndefined = __webpack_require__(0).isUndefined;\nvar isNull = __webpack_require__(0).isNull;\n\n/**\n * Creates an instance of StyleContextStack used for style inheritance and style overrides\n *\n * @constructor\n * @this {StyleContextStack}\n * @param {Object} named styles dictionary\n * @param {Object} optional default style definition\n */\nfunction StyleContextStack(styleDictionary, defaultStyle) {\n\tthis.defaultStyle = defaultStyle || {};\n\tthis.styleDictionary = styleDictionary;\n\tthis.styleOverrides = [];\n}\n\n/**\n * Creates cloned version of current stack\n * @return {StyleContextStack} current stack snapshot\n */\nStyleContextStack.prototype.clone = function () {\n\tvar stack = new StyleContextStack(this.styleDictionary, this.defaultStyle);\n\n\tthis.styleOverrides.forEach(function (item) {\n\t\tstack.styleOverrides.push(item);\n\t});\n\n\treturn stack;\n};\n\n/**\n * Pushes style-name or style-overrides-object onto the stack for future evaluation\n *\n * @param {String|Object} styleNameOrOverride style-name (referring to styleDictionary) or\n *                                            a new dictionary defining overriding properties\n */\nStyleContextStack.prototype.push = function (styleNameOrOverride) {\n\tthis.styleOverrides.push(styleNameOrOverride);\n};\n\n/**\n * Removes last style-name or style-overrides-object from the stack\n *\n * @param {Number} howMany - optional number of elements to be popped (if not specified,\n *                           one element will be removed from the stack)\n */\nStyleContextStack.prototype.pop = function (howMany) {\n\thowMany = howMany || 1;\n\n\twhile (howMany-- > 0) {\n\t\tthis.styleOverrides.pop();\n\t}\n};\n\n/**\n * Creates a set of named styles or/and a style-overrides-object based on the item,\n * pushes those elements onto the stack for future evaluation and returns the number\n * of elements pushed, so they can be easily poped then.\n *\n * @param {Object} item - an object with optional style property and/or style overrides\n * @return the number of items pushed onto the stack\n */\nStyleContextStack.prototype.autopush = function (item) {\n\tif (isString(item)) {\n\t\treturn 0;\n\t}\n\n\tvar styleNames = [];\n\n\tif (item.style) {\n\t\tif (isArray(item.style)) {\n\t\t\tstyleNames = item.style;\n\t\t} else {\n\t\t\tstyleNames = [item.style];\n\t\t}\n\t}\n\n\tfor (var i = 0, l = styleNames.length; i < l; i++) {\n\t\tthis.push(styleNames[i]);\n\t}\n\n\tvar styleProperties = [\n\t\t'font',\n\t\t'fontSize',\n\t\t'fontFeatures',\n\t\t'bold',\n\t\t'italics',\n\t\t'alignment',\n\t\t'color',\n\t\t'columnGap',\n\t\t'fillColor',\n\t\t'decoration',\n\t\t'decorationStyle',\n\t\t'decorationColor',\n\t\t'background',\n\t\t'lineHeight',\n\t\t'characterSpacing',\n\t\t'noWrap',\n\t\t'markerColor',\n\t\t'leadingIndent'\n\t\t\t//'tableCellPadding'\n\t\t\t// 'cellBorder',\n\t\t\t// 'headerCellBorder',\n\t\t\t// 'oddRowCellBorder',\n\t\t\t// 'evenRowCellBorder',\n\t\t\t// 'tableBorder'\n\t];\n\tvar styleOverrideObject = {};\n\tvar pushStyleOverrideObject = false;\n\n\tstyleProperties.forEach(function (key) {\n\t\tif (!isUndefined(item[key]) && !isNull(item[key])) {\n\t\t\tstyleOverrideObject[key] = item[key];\n\t\t\tpushStyleOverrideObject = true;\n\t\t}\n\t});\n\n\tif (pushStyleOverrideObject) {\n\t\tthis.push(styleOverrideObject);\n\t}\n\n\treturn styleNames.length + (pushStyleOverrideObject ? 1 : 0);\n};\n\n/**\n * Automatically pushes elements onto the stack, using autopush based on item,\n * executes callback and then pops elements back. Returns value returned by callback\n *\n * @param  {Object}   item - an object with optional style property and/or style overrides\n * @param  {Function} function to be called between autopush and pop\n * @return {Object} value returned by callback\n */\nStyleContextStack.prototype.auto = function (item, callback) {\n\tvar pushedItems = this.autopush(item);\n\tvar result = callback();\n\n\tif (pushedItems > 0) {\n\t\tthis.pop(pushedItems);\n\t}\n\n\treturn result;\n};\n\n/**\n * Evaluates stack and returns value of a named property\n *\n * @param {String} property - property name\n * @return property value or null if not found\n */\nStyleContextStack.prototype.getProperty = function (property) {\n\tif (this.styleOverrides) {\n\t\tfor (var i = this.styleOverrides.length - 1; i >= 0; i--) {\n\t\t\tvar item = this.styleOverrides[i];\n\n\t\t\tif (isString(item)) {\n\t\t\t\t// named-style-override\n\t\t\t\tvar style = this.styleDictionary[item];\n\t\t\t\tif (style && !isUndefined(style[property]) && !isNull(style[property])) {\n\t\t\t\t\treturn style[property];\n\t\t\t\t}\n\t\t\t} else if (!isUndefined(item[property]) && !isNull(item[property])) {\n\t\t\t\t// style-overrides-object\n\t\t\t\treturn item[property];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn this.defaultStyle && this.defaultStyle[property];\n};\n\nmodule.exports = StyleContextStack;\n\n\n/***/ }),\n/* 81 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar TraversalTracker = __webpack_require__(77);\nvar isString = __webpack_require__(0).isString;\n\n/**\n * Creates an instance of DocumentContext - a store for current x, y positions and available width/height.\n * It facilitates column divisions and vertical sync\n */\nfunction DocumentContext(pageSize, pageMargins) {\n\tthis.pages = [];\n\n\tthis.pageMargins = pageMargins;\n\n\tthis.x = pageMargins.left;\n\tthis.availableWidth = pageSize.width - pageMargins.left - pageMargins.right;\n\tthis.availableHeight = 0;\n\tthis.page = -1;\n\n\tthis.snapshots = [];\n\n\tthis.endingCell = null;\n\n\tthis.tracker = new TraversalTracker();\n\n\tthis.addPage(pageSize);\n\n\tthis.hasBackground = false;\n}\n\nDocumentContext.prototype.beginColumnGroup = function () {\n\tthis.snapshots.push({\n\t\tx: this.x,\n\t\ty: this.y,\n\t\tavailableHeight: this.availableHeight,\n\t\tavailableWidth: this.availableWidth,\n\t\tpage: this.page,\n\t\tbottomMost: {\n\t\t\tx: this.x,\n\t\t\ty: this.y,\n\t\t\tavailableHeight: this.availableHeight,\n\t\t\tavailableWidth: this.availableWidth,\n\t\t\tpage: this.page\n\t\t},\n\t\tendingCell: this.endingCell,\n\t\tlastColumnWidth: this.lastColumnWidth\n\t});\n\n\tthis.lastColumnWidth = 0;\n};\n\nDocumentContext.prototype.beginColumn = function (width, offset, endingCell) {\n\tvar saved = this.snapshots[this.snapshots.length - 1];\n\n\tthis.calculateBottomMost(saved);\n\n\tthis.endingCell = endingCell;\n\tthis.page = saved.page;\n\tthis.x = this.x + this.lastColumnWidth + (offset || 0);\n\tthis.y = saved.y;\n\tthis.availableWidth = width;\t//saved.availableWidth - offset;\n\tthis.availableHeight = saved.availableHeight;\n\n\tthis.lastColumnWidth = width;\n};\n\nDocumentContext.prototype.calculateBottomMost = function (destContext) {\n\tif (this.endingCell) {\n\t\tthis.saveContextInEndingCell(this.endingCell);\n\t\tthis.endingCell = null;\n\t} else {\n\t\tdestContext.bottomMost = bottomMostContext(this, destContext.bottomMost);\n\t}\n};\n\nDocumentContext.prototype.markEnding = function (endingCell) {\n\tthis.page = endingCell._columnEndingContext.page;\n\tthis.x = endingCell._columnEndingContext.x;\n\tthis.y = endingCell._columnEndingContext.y;\n\tthis.availableWidth = endingCell._columnEndingContext.availableWidth;\n\tthis.availableHeight = endingCell._columnEndingContext.availableHeight;\n\tthis.lastColumnWidth = endingCell._columnEndingContext.lastColumnWidth;\n};\n\nDocumentContext.prototype.saveContextInEndingCell = function (endingCell) {\n\tendingCell._columnEndingContext = {\n\t\tpage: this.page,\n\t\tx: this.x,\n\t\ty: this.y,\n\t\tavailableHeight: this.availableHeight,\n\t\tavailableWidth: this.availableWidth,\n\t\tlastColumnWidth: this.lastColumnWidth\n\t};\n};\n\nDocumentContext.prototype.completeColumnGroup = function (height) {\n\tvar saved = this.snapshots.pop();\n\n\tthis.calculateBottomMost(saved);\n\n\tthis.endingCell = null;\n\tthis.x = saved.x;\n\n\tvar y = saved.bottomMost.y;\n\tif (height) {\n\t\tif (saved.page === saved.bottomMost.page) {\n\t\t\tif ((saved.y + height) > y) {\n\t\t\t\ty = saved.y + height;\n\t\t\t}\n\t\t} else {\n\t\t\ty += height;\n\t\t}\n\t}\n\n\tthis.y = y;\n\tthis.page = saved.bottomMost.page;\n\tthis.availableWidth = saved.availableWidth;\n\tthis.availableHeight = saved.bottomMost.availableHeight;\n\tif (height) {\n\t\tthis.availableHeight -= (y - saved.bottomMost.y);\n\t}\n\tthis.lastColumnWidth = saved.lastColumnWidth;\n};\n\nDocumentContext.prototype.addMargin = function (left, right) {\n\tthis.x += left;\n\tthis.availableWidth -= left + (right || 0);\n};\n\nDocumentContext.prototype.moveDown = function (offset) {\n\tthis.y += offset;\n\tthis.availableHeight -= offset;\n\n\treturn this.availableHeight > 0;\n};\n\nDocumentContext.prototype.initializePage = function () {\n\tthis.y = this.pageMargins.top;\n\tthis.availableHeight = this.getCurrentPage().pageSize.height - this.pageMargins.top - this.pageMargins.bottom;\n\tthis.pageSnapshot().availableWidth = this.getCurrentPage().pageSize.width - this.pageMargins.left - this.pageMargins.right;\n};\n\nDocumentContext.prototype.pageSnapshot = function () {\n\tif (this.snapshots[0]) {\n\t\treturn this.snapshots[0];\n\t} else {\n\t\treturn this;\n\t}\n};\n\nDocumentContext.prototype.moveTo = function (x, y) {\n\tif (x !== undefined && x !== null) {\n\t\tthis.x = x;\n\t\tthis.availableWidth = this.getCurrentPage().pageSize.width - this.x - this.pageMargins.right;\n\t}\n\tif (y !== undefined && y !== null) {\n\t\tthis.y = y;\n\t\tthis.availableHeight = this.getCurrentPage().pageSize.height - this.y - this.pageMargins.bottom;\n\t}\n};\n\nDocumentContext.prototype.beginDetachedBlock = function () {\n\tthis.snapshots.push({\n\t\tx: this.x,\n\t\ty: this.y,\n\t\tavailableHeight: this.availableHeight,\n\t\tavailableWidth: this.availableWidth,\n\t\tpage: this.page,\n\t\tendingCell: this.endingCell,\n\t\tlastColumnWidth: this.lastColumnWidth\n\t});\n};\n\nDocumentContext.prototype.endDetachedBlock = function () {\n\tvar saved = this.snapshots.pop();\n\n\tthis.x = saved.x;\n\tthis.y = saved.y;\n\tthis.availableWidth = saved.availableWidth;\n\tthis.availableHeight = saved.availableHeight;\n\tthis.page = saved.page;\n\tthis.endingCell = saved.endingCell;\n\tthis.lastColumnWidth = saved.lastColumnWidth;\n};\n\nfunction pageOrientation(pageOrientationString, currentPageOrientation) {\n\tif (pageOrientationString === undefined) {\n\t\treturn currentPageOrientation;\n\t} else if (isString(pageOrientationString) && (pageOrientationString.toLowerCase() === 'landscape')) {\n\t\treturn 'landscape';\n\t} else {\n\t\treturn 'portrait';\n\t}\n}\n\nvar getPageSize = function (currentPage, newPageOrientation) {\n\n\tnewPageOrientation = pageOrientation(newPageOrientation, currentPage.pageSize.orientation);\n\n\tif (newPageOrientation !== currentPage.pageSize.orientation) {\n\t\treturn {\n\t\t\torientation: newPageOrientation,\n\t\t\twidth: currentPage.pageSize.height,\n\t\t\theight: currentPage.pageSize.width\n\t\t};\n\t} else {\n\t\treturn {\n\t\t\torientation: currentPage.pageSize.orientation,\n\t\t\twidth: currentPage.pageSize.width,\n\t\t\theight: currentPage.pageSize.height\n\t\t};\n\t}\n\n};\n\n\nDocumentContext.prototype.moveToNextPage = function (pageOrientation) {\n\tvar nextPageIndex = this.page + 1;\n\n\tvar prevPage = this.page;\n\tvar prevY = this.y;\n\n\tvar createNewPage = nextPageIndex >= this.pages.length;\n\tif (createNewPage) {\n\t\tvar currentAvailableWidth = this.availableWidth;\n\t\tvar currentPageOrientation = this.getCurrentPage().pageSize.orientation;\n\n\t\tvar pageSize = getPageSize(this.getCurrentPage(), pageOrientation);\n\t\tthis.addPage(pageSize);\n\n\t\tif (currentPageOrientation === pageSize.orientation) {\n\t\t\tthis.availableWidth = currentAvailableWidth;\n\t\t}\n\t} else {\n\t\tthis.page = nextPageIndex;\n\t\tthis.initializePage();\n\t}\n\n\treturn {\n\t\tnewPageCreated: createNewPage,\n\t\tprevPage: prevPage,\n\t\tprevY: prevY,\n\t\ty: this.y\n\t};\n};\n\n\nDocumentContext.prototype.addPage = function (pageSize) {\n\tvar page = {items: [], pageSize: pageSize};\n\tthis.pages.push(page);\n\tthis.page = this.pages.length - 1;\n\tthis.initializePage();\n\n\tthis.tracker.emit('pageAdded');\n\n\treturn page;\n};\n\nDocumentContext.prototype.getCurrentPage = function () {\n\tif (this.page < 0 || this.page >= this.pages.length) {\n\t\treturn null;\n\t}\n\n\treturn this.pages[this.page];\n};\n\nDocumentContext.prototype.getCurrentPosition = function () {\n\tvar pageSize = this.getCurrentPage().pageSize;\n\tvar innerHeight = pageSize.height - this.pageMargins.top - this.pageMargins.bottom;\n\tvar innerWidth = pageSize.width - this.pageMargins.left - this.pageMargins.right;\n\n\treturn {\n\t\tpageNumber: this.page + 1,\n\t\tpageOrientation: pageSize.orientation,\n\t\tpageInnerHeight: innerHeight,\n\t\tpageInnerWidth: innerWidth,\n\t\tleft: this.x,\n\t\ttop: this.y,\n\t\tverticalRatio: ((this.y - this.pageMargins.top) / innerHeight),\n\t\thorizontalRatio: ((this.x - this.pageMargins.left) / innerWidth)\n\t};\n};\n\nfunction bottomMostContext(c1, c2) {\n\tvar r;\n\n\tif (c1.page > c2.page) {\n\t\tr = c1;\n\t} else if (c2.page > c1.page) {\n\t\tr = c2;\n\t} else {\n\t\tr = (c1.y > c2.y) ? c1 : c2;\n\t}\n\n\treturn {\n\t\tpage: r.page,\n\t\tx: r.x,\n\t\ty: r.y,\n\t\tavailableHeight: r.availableHeight,\n\t\tavailableWidth: r.availableWidth\n\t};\n}\n\nmodule.exports = DocumentContext;\n\n\n/***/ }),\n/* 82 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n/**\n * Creates an instance of Line\n *\n * @constructor\n * @this {Line}\n * @param {Number} Maximum width this line can have\n */\nfunction Line(maxWidth) {\n\tthis.maxWidth = maxWidth;\n\tthis.leadingCut = 0;\n\tthis.trailingCut = 0;\n\tthis.inlineWidths = 0;\n\tthis.inlines = [];\n}\n\nLine.prototype.getAscenderHeight = function () {\n\tvar y = 0;\n\n\tthis.inlines.forEach(function (inline) {\n\t\ty = Math.max(y, inline.font.ascender / 1000 * inline.fontSize);\n\t});\n\treturn y;\n};\n\nLine.prototype.hasEnoughSpaceForInline = function (inline) {\n\tif (this.inlines.length === 0) {\n\t\treturn true;\n\t}\n\tif (this.newLineForced) {\n\t\treturn false;\n\t}\n\n\treturn this.inlineWidths + inline.width - this.leadingCut - (inline.trailingCut || 0) <= this.maxWidth;\n};\n\nLine.prototype.addInline = function (inline) {\n\tif (this.inlines.length === 0) {\n\t\tthis.leadingCut = inline.leadingCut || 0;\n\t}\n\tthis.trailingCut = inline.trailingCut || 0;\n\n\tinline.x = this.inlineWidths - this.leadingCut;\n\n\tthis.inlines.push(inline);\n\tthis.inlineWidths += inline.width;\n\n\tif (inline.lineEnd) {\n\t\tthis.newLineForced = true;\n\t}\n};\n\nLine.prototype.getWidth = function () {\n\treturn this.inlineWidths - this.leadingCut - this.trailingCut;\n};\n\n/**\n * Returns line height\n * @return {Number}\n */\nLine.prototype.getHeight = function () {\n\tvar max = 0;\n\n\tthis.inlines.forEach(function (item) {\n\t\tmax = Math.max(max, item.height || 0);\n\t});\n\n\treturn max;\n};\n\nmodule.exports = Line;\n\n\n/***/ }),\n/* 83 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(global, process) {// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n\n/*<replacement>*/\n\nvar processNextTick = __webpack_require__(32).nextTick;\n/*</replacement>*/\n\nmodule.exports = Readable;\n\n/*<replacement>*/\nvar isArray = __webpack_require__(76);\n/*</replacement>*/\n\n/*<replacement>*/\nvar Duplex;\n/*</replacement>*/\n\nReadable.ReadableState = ReadableState;\n\n/*<replacement>*/\nvar EE = __webpack_require__(31).EventEmitter;\n\nvar EElistenerCount = function (emitter, type) {\n  return emitter.listeners(type).length;\n};\n/*</replacement>*/\n\n/*<replacement>*/\nvar Stream = __webpack_require__(84);\n/*</replacement>*/\n\n/*<replacement>*/\n\nvar Buffer = __webpack_require__(33).Buffer;\nvar OurUint8Array = global.Uint8Array || function () {};\nfunction _uint8ArrayToBuffer(chunk) {\n  return Buffer.from(chunk);\n}\nfunction _isUint8Array(obj) {\n  return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;\n}\n\n/*</replacement>*/\n\n/*<replacement>*/\nvar util = __webpack_require__(25);\nutil.inherits = __webpack_require__(21);\n/*</replacement>*/\n\n/*<replacement>*/\nvar debugUtil = __webpack_require__(139);\nvar debug = void 0;\nif (debugUtil && debugUtil.debuglog) {\n  debug = debugUtil.debuglog('stream');\n} else {\n  debug = function () {};\n}\n/*</replacement>*/\n\nvar BufferList = __webpack_require__(140);\nvar destroyImpl = __webpack_require__(85);\nvar StringDecoder;\n\nutil.inherits(Readable, Stream);\n\nvar kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume'];\n\nfunction prependListener(emitter, event, fn) {\n  // Sadly this is not cacheable as some libraries bundle their own\n  // event emitter implementation with them.\n  if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn);\n\n  // This is a hack to make sure that our error handler is attached before any\n  // userland ones.  NEVER DO THIS. This is here only because this code needs\n  // to continue to work with older versions of Node.js that do not include\n  // the prependListener() method. The goal is to eventually remove this hack.\n  if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]];\n}\n\nfunction ReadableState(options, stream) {\n  Duplex = Duplex || __webpack_require__(16);\n\n  options = options || {};\n\n  // Duplex streams are both readable and writable, but share\n  // the same options object.\n  // However, some cases require setting options to different\n  // values for the readable and the writable sides of the duplex stream.\n  // These options can be provided separately as readableXXX and writableXXX.\n  var isDuplex = stream instanceof Duplex;\n\n  // object stream flag. Used to make read(n) ignore n and to\n  // make all the buffer merging and length checks go away\n  this.objectMode = !!options.objectMode;\n\n  if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode;\n\n  // the point at which it stops calling _read() to fill the buffer\n  // Note: 0 is a valid value, means \"don't call _read preemptively ever\"\n  var hwm = options.highWaterMark;\n  var readableHwm = options.readableHighWaterMark;\n  var defaultHwm = this.objectMode ? 16 : 16 * 1024;\n\n  if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (readableHwm || readableHwm === 0)) this.highWaterMark = readableHwm;else this.highWaterMark = defaultHwm;\n\n  // cast to ints.\n  this.highWaterMark = Math.floor(this.highWaterMark);\n\n  // A linked list is used to store data chunks instead of an array because the\n  // linked list can remove elements from the beginning faster than\n  // array.shift()\n  this.buffer = new BufferList();\n  this.length = 0;\n  this.pipes = null;\n  this.pipesCount = 0;\n  this.flowing = null;\n  this.ended = false;\n  this.endEmitted = false;\n  this.reading = false;\n\n  // a flag to be able to tell if the event 'readable'/'data' is emitted\n  // immediately, or on a later tick.  We set this to true at first, because\n  // any actions that shouldn't happen until \"later\" should generally also\n  // not happen before the first read call.\n  this.sync = true;\n\n  // whenever we return null, then we set a flag to say\n  // that we're awaiting a 'readable' event emission.\n  this.needReadable = false;\n  this.emittedReadable = false;\n  this.readableListening = false;\n  this.resumeScheduled = false;\n\n  // has it been destroyed\n  this.destroyed = false;\n\n  // Crypto is kind of old and crusty.  Historically, its default string\n  // encoding is 'binary' so we have to make this configurable.\n  // Everything else in the universe uses 'utf8', though.\n  this.defaultEncoding = options.defaultEncoding || 'utf8';\n\n  // the number of writers that are awaiting a drain event in .pipe()s\n  this.awaitDrain = 0;\n\n  // if true, a maybeReadMore has been scheduled\n  this.readingMore = false;\n\n  this.decoder = null;\n  this.encoding = null;\n  if (options.encoding) {\n    if (!StringDecoder) StringDecoder = __webpack_require__(47).StringDecoder;\n    this.decoder = new StringDecoder(options.encoding);\n    this.encoding = options.encoding;\n  }\n}\n\nfunction Readable(options) {\n  Duplex = Duplex || __webpack_require__(16);\n\n  if (!(this instanceof Readable)) return new Readable(options);\n\n  this._readableState = new ReadableState(options, this);\n\n  // legacy\n  this.readable = true;\n\n  if (options) {\n    if (typeof options.read === 'function') this._read = options.read;\n\n    if (typeof options.destroy === 'function') this._destroy = options.destroy;\n  }\n\n  Stream.call(this);\n}\n\nObject.defineProperty(Readable.prototype, 'destroyed', {\n  get: function () {\n    if (this._readableState === undefined) {\n      return false;\n    }\n    return this._readableState.destroyed;\n  },\n  set: function (value) {\n    // we ignore the value if the stream\n    // has not been initialized yet\n    if (!this._readableState) {\n      return;\n    }\n\n    // backward compatibility, the user is explicitly\n    // managing destroyed\n    this._readableState.destroyed = value;\n  }\n});\n\nReadable.prototype.destroy = destroyImpl.destroy;\nReadable.prototype._undestroy = destroyImpl.undestroy;\nReadable.prototype._destroy = function (err, cb) {\n  this.push(null);\n  cb(err);\n};\n\n// Manually shove something into the read() buffer.\n// This returns true if the highWaterMark has not been hit yet,\n// similar to how Writable.write() returns true if you should\n// write() some more.\nReadable.prototype.push = function (chunk, encoding) {\n  var state = this._readableState;\n  var skipChunkCheck;\n\n  if (!state.objectMode) {\n    if (typeof chunk === 'string') {\n      encoding = encoding || state.defaultEncoding;\n      if (encoding !== state.encoding) {\n        chunk = Buffer.from(chunk, encoding);\n        encoding = '';\n      }\n      skipChunkCheck = true;\n    }\n  } else {\n    skipChunkCheck = true;\n  }\n\n  return readableAddChunk(this, chunk, encoding, false, skipChunkCheck);\n};\n\n// Unshift should *always* be something directly out of read()\nReadable.prototype.unshift = function (chunk) {\n  return readableAddChunk(this, chunk, null, true, false);\n};\n\nfunction readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) {\n  var state = stream._readableState;\n  if (chunk === null) {\n    state.reading = false;\n    onEofChunk(stream, state);\n  } else {\n    var er;\n    if (!skipChunkCheck) er = chunkInvalid(state, chunk);\n    if (er) {\n      stream.emit('error', er);\n    } else if (state.objectMode || chunk && chunk.length > 0) {\n      if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) {\n        chunk = _uint8ArrayToBuffer(chunk);\n      }\n\n      if (addToFront) {\n        if (state.endEmitted) stream.emit('error', new Error('stream.unshift() after end event'));else addChunk(stream, state, chunk, true);\n      } else if (state.ended) {\n        stream.emit('error', new Error('stream.push() after EOF'));\n      } else {\n        state.reading = false;\n        if (state.decoder && !encoding) {\n          chunk = state.decoder.write(chunk);\n          if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state);\n        } else {\n          addChunk(stream, state, chunk, false);\n        }\n      }\n    } else if (!addToFront) {\n      state.reading = false;\n    }\n  }\n\n  return needMoreData(state);\n}\n\nfunction addChunk(stream, state, chunk, addToFront) {\n  if (state.flowing && state.length === 0 && !state.sync) {\n    stream.emit('data', chunk);\n    stream.read(0);\n  } else {\n    // update the buffer info.\n    state.length += state.objectMode ? 1 : chunk.length;\n    if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk);\n\n    if (state.needReadable) emitReadable(stream);\n  }\n  maybeReadMore(stream, state);\n}\n\nfunction chunkInvalid(state, chunk) {\n  var er;\n  if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {\n    er = new TypeError('Invalid non-string/buffer chunk');\n  }\n  return er;\n}\n\n// if it's past the high water mark, we can push in some more.\n// Also, if we have no data yet, we can stand some\n// more bytes.  This is to work around cases where hwm=0,\n// such as the repl.  Also, if the push() triggered a\n// readable event, and the user called read(largeNumber) such that\n// needReadable was set, then we ought to push more, so that another\n// 'readable' event will be triggered.\nfunction needMoreData(state) {\n  return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0);\n}\n\nReadable.prototype.isPaused = function () {\n  return this._readableState.flowing === false;\n};\n\n// backwards compatibility.\nReadable.prototype.setEncoding = function (enc) {\n  if (!StringDecoder) StringDecoder = __webpack_require__(47).StringDecoder;\n  this._readableState.decoder = new StringDecoder(enc);\n  this._readableState.encoding = enc;\n  return this;\n};\n\n// Don't raise the hwm > 8MB\nvar MAX_HWM = 0x800000;\nfunction computeNewHighWaterMark(n) {\n  if (n >= MAX_HWM) {\n    n = MAX_HWM;\n  } else {\n    // Get the next highest power of 2 to prevent increasing hwm excessively in\n    // tiny amounts\n    n--;\n    n |= n >>> 1;\n    n |= n >>> 2;\n    n |= n >>> 4;\n    n |= n >>> 8;\n    n |= n >>> 16;\n    n++;\n  }\n  return n;\n}\n\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction howMuchToRead(n, state) {\n  if (n <= 0 || state.length === 0 && state.ended) return 0;\n  if (state.objectMode) return 1;\n  if (n !== n) {\n    // Only flow one buffer at a time\n    if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length;\n  }\n  // If we're asking for more than the current hwm, then raise the hwm.\n  if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n);\n  if (n <= state.length) return n;\n  // Don't have enough\n  if (!state.ended) {\n    state.needReadable = true;\n    return 0;\n  }\n  return state.length;\n}\n\n// you can override either this method, or the async _read(n) below.\nReadable.prototype.read = function (n) {\n  debug('read', n);\n  n = parseInt(n, 10);\n  var state = this._readableState;\n  var nOrig = n;\n\n  if (n !== 0) state.emittedReadable = false;\n\n  // if we're doing read(0) to trigger a readable event, but we\n  // already have a bunch of data in the buffer, then just trigger\n  // the 'readable' event and move on.\n  if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) {\n    debug('read: emitReadable', state.length, state.ended);\n    if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this);\n    return null;\n  }\n\n  n = howMuchToRead(n, state);\n\n  // if we've ended, and we're now clear, then finish it up.\n  if (n === 0 && state.ended) {\n    if (state.length === 0) endReadable(this);\n    return null;\n  }\n\n  // All the actual chunk generation logic needs to be\n  // *below* the call to _read.  The reason is that in certain\n  // synthetic stream cases, such as passthrough streams, _read\n  // may be a completely synchronous operation which may change\n  // the state of the read buffer, providing enough data when\n  // before there was *not* enough.\n  //\n  // So, the steps are:\n  // 1. Figure out what the state of things will be after we do\n  // a read from the buffer.\n  //\n  // 2. If that resulting state will trigger a _read, then call _read.\n  // Note that this may be asynchronous, or synchronous.  Yes, it is\n  // deeply ugly to write APIs this way, but that still doesn't mean\n  // that the Readable class should behave improperly, as streams are\n  // designed to be sync/async agnostic.\n  // Take note if the _read call is sync or async (ie, if the read call\n  // has returned yet), so that we know whether or not it's safe to emit\n  // 'readable' etc.\n  //\n  // 3. Actually pull the requested chunks out of the buffer and return.\n\n  // if we need a readable event, then we need to do some reading.\n  var doRead = state.needReadable;\n  debug('need readable', doRead);\n\n  // if we currently have less than the highWaterMark, then also read some\n  if (state.length === 0 || state.length - n < state.highWaterMark) {\n    doRead = true;\n    debug('length less than watermark', doRead);\n  }\n\n  // however, if we've ended, then there's no point, and if we're already\n  // reading, then it's unnecessary.\n  if (state.ended || state.reading) {\n    doRead = false;\n    debug('reading or ended', doRead);\n  } else if (doRead) {\n    debug('do read');\n    state.reading = true;\n    state.sync = true;\n    // if the length is currently zero, then we *need* a readable event.\n    if (state.length === 0) state.needReadable = true;\n    // call internal read method\n    this._read(state.highWaterMark);\n    state.sync = false;\n    // If _read pushed data synchronously, then `reading` will be false,\n    // and we need to re-evaluate how much data we can return to the user.\n    if (!state.reading) n = howMuchToRead(nOrig, state);\n  }\n\n  var ret;\n  if (n > 0) ret = fromList(n, state);else ret = null;\n\n  if (ret === null) {\n    state.needReadable = true;\n    n = 0;\n  } else {\n    state.length -= n;\n  }\n\n  if (state.length === 0) {\n    // If we have nothing in the buffer, then we want to know\n    // as soon as we *do* get something into the buffer.\n    if (!state.ended) state.needReadable = true;\n\n    // If we tried to read() past the EOF, then emit end on the next tick.\n    if (nOrig !== n && state.ended) endReadable(this);\n  }\n\n  if (ret !== null) this.emit('data', ret);\n\n  return ret;\n};\n\nfunction onEofChunk(stream, state) {\n  if (state.ended) return;\n  if (state.decoder) {\n    var chunk = state.decoder.end();\n    if (chunk && chunk.length) {\n      state.buffer.push(chunk);\n      state.length += state.objectMode ? 1 : chunk.length;\n    }\n  }\n  state.ended = true;\n\n  // emit 'readable' now to make sure it gets picked up.\n  emitReadable(stream);\n}\n\n// Don't emit readable right away in sync mode, because this can trigger\n// another read() call => stack overflow.  This way, it might trigger\n// a nextTick recursion warning, but that's not so bad.\nfunction emitReadable(stream) {\n  var state = stream._readableState;\n  state.needReadable = false;\n  if (!state.emittedReadable) {\n    debug('emitReadable', state.flowing);\n    state.emittedReadable = true;\n    if (state.sync) processNextTick(emitReadable_, stream);else emitReadable_(stream);\n  }\n}\n\nfunction emitReadable_(stream) {\n  debug('emit readable');\n  stream.emit('readable');\n  flow(stream);\n}\n\n// at this point, the user has presumably seen the 'readable' event,\n// and called read() to consume some data.  that may have triggered\n// in turn another _read(n) call, in which case reading = true if\n// it's in progress.\n// However, if we're not ended, or reading, and the length < hwm,\n// then go ahead and try to read some more preemptively.\nfunction maybeReadMore(stream, state) {\n  if (!state.readingMore) {\n    state.readingMore = true;\n    processNextTick(maybeReadMore_, stream, state);\n  }\n}\n\nfunction maybeReadMore_(stream, state) {\n  var len = state.length;\n  while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) {\n    debug('maybeReadMore read 0');\n    stream.read(0);\n    if (len === state.length)\n      // didn't get any data, stop spinning.\n      break;else len = state.length;\n  }\n  state.readingMore = false;\n}\n\n// abstract method.  to be overridden in specific implementation classes.\n// call cb(er, data) where data is <= n in length.\n// for virtual (non-string, non-buffer) streams, \"length\" is somewhat\n// arbitrary, and perhaps not very meaningful.\nReadable.prototype._read = function (n) {\n  this.emit('error', new Error('_read() is not implemented'));\n};\n\nReadable.prototype.pipe = function (dest, pipeOpts) {\n  var src = this;\n  var state = this._readableState;\n\n  switch (state.pipesCount) {\n    case 0:\n      state.pipes = dest;\n      break;\n    case 1:\n      state.pipes = [state.pipes, dest];\n      break;\n    default:\n      state.pipes.push(dest);\n      break;\n  }\n  state.pipesCount += 1;\n  debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts);\n\n  var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr;\n\n  var endFn = doEnd ? onend : unpipe;\n  if (state.endEmitted) processNextTick(endFn);else src.once('end', endFn);\n\n  dest.on('unpipe', onunpipe);\n  function onunpipe(readable, unpipeInfo) {\n    debug('onunpipe');\n    if (readable === src) {\n      if (unpipeInfo && unpipeInfo.hasUnpiped === false) {\n        unpipeInfo.hasUnpiped = true;\n        cleanup();\n      }\n    }\n  }\n\n  function onend() {\n    debug('onend');\n    dest.end();\n  }\n\n  // when the dest drains, it reduces the awaitDrain counter\n  // on the source.  This would be more elegant with a .once()\n  // handler in flow(), but adding and removing repeatedly is\n  // too slow.\n  var ondrain = pipeOnDrain(src);\n  dest.on('drain', ondrain);\n\n  var cleanedUp = false;\n  function cleanup() {\n    debug('cleanup');\n    // cleanup event handlers once the pipe is broken\n    dest.removeListener('close', onclose);\n    dest.removeListener('finish', onfinish);\n    dest.removeListener('drain', ondrain);\n    dest.removeListener('error', onerror);\n    dest.removeListener('unpipe', onunpipe);\n    src.removeListener('end', onend);\n    src.removeListener('end', unpipe);\n    src.removeListener('data', ondata);\n\n    cleanedUp = true;\n\n    // if the reader is waiting for a drain event from this\n    // specific writer, then it would cause it to never start\n    // flowing again.\n    // So, if this is awaiting a drain, then we just call it now.\n    // If we don't know, then assume that we are waiting for one.\n    if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain();\n  }\n\n  // If the user pushes more data while we're writing to dest then we'll end up\n  // in ondata again. However, we only want to increase awaitDrain once because\n  // dest will only emit one 'drain' event for the multiple writes.\n  // => Introduce a guard on increasing awaitDrain.\n  var increasedAwaitDrain = false;\n  src.on('data', ondata);\n  function ondata(chunk) {\n    debug('ondata');\n    increasedAwaitDrain = false;\n    var ret = dest.write(chunk);\n    if (false === ret && !increasedAwaitDrain) {\n      // If the user unpiped during `dest.write()`, it is possible\n      // to get stuck in a permanently paused state if that write\n      // also returned false.\n      // => Check whether `dest` is still a piping destination.\n      if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) {\n        debug('false write response, pause', src._readableState.awaitDrain);\n        src._readableState.awaitDrain++;\n        increasedAwaitDrain = true;\n      }\n      src.pause();\n    }\n  }\n\n  // if the dest has an error, then stop piping into it.\n  // however, don't suppress the throwing behavior for this.\n  function onerror(er) {\n    debug('onerror', er);\n    unpipe();\n    dest.removeListener('error', onerror);\n    if (EElistenerCount(dest, 'error') === 0) dest.emit('error', er);\n  }\n\n  // Make sure our error handler is attached before userland ones.\n  prependListener(dest, 'error', onerror);\n\n  // Both close and finish should trigger unpipe, but only once.\n  function onclose() {\n    dest.removeListener('finish', onfinish);\n    unpipe();\n  }\n  dest.once('close', onclose);\n  function onfinish() {\n    debug('onfinish');\n    dest.removeListener('close', onclose);\n    unpipe();\n  }\n  dest.once('finish', onfinish);\n\n  function unpipe() {\n    debug('unpipe');\n    src.unpipe(dest);\n  }\n\n  // tell the dest that it's being piped to\n  dest.emit('pipe', src);\n\n  // start the flow if it hasn't been started already.\n  if (!state.flowing) {\n    debug('pipe resume');\n    src.resume();\n  }\n\n  return dest;\n};\n\nfunction pipeOnDrain(src) {\n  return function () {\n    var state = src._readableState;\n    debug('pipeOnDrain', state.awaitDrain);\n    if (state.awaitDrain) state.awaitDrain--;\n    if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) {\n      state.flowing = true;\n      flow(src);\n    }\n  };\n}\n\nReadable.prototype.unpipe = function (dest) {\n  var state = this._readableState;\n  var unpipeInfo = { hasUnpiped: false };\n\n  // if we're not piping anywhere, then do nothing.\n  if (state.pipesCount === 0) return this;\n\n  // just one destination.  most common case.\n  if (state.pipesCount === 1) {\n    // passed in one, but it's not the right one.\n    if (dest && dest !== state.pipes) return this;\n\n    if (!dest) dest = state.pipes;\n\n    // got a match.\n    state.pipes = null;\n    state.pipesCount = 0;\n    state.flowing = false;\n    if (dest) dest.emit('unpipe', this, unpipeInfo);\n    return this;\n  }\n\n  // slow case. multiple pipe destinations.\n\n  if (!dest) {\n    // remove all.\n    var dests = state.pipes;\n    var len = state.pipesCount;\n    state.pipes = null;\n    state.pipesCount = 0;\n    state.flowing = false;\n\n    for (var i = 0; i < len; i++) {\n      dests[i].emit('unpipe', this, unpipeInfo);\n    }return this;\n  }\n\n  // try to find the right one.\n  var index = indexOf(state.pipes, dest);\n  if (index === -1) return this;\n\n  state.pipes.splice(index, 1);\n  state.pipesCount -= 1;\n  if (state.pipesCount === 1) state.pipes = state.pipes[0];\n\n  dest.emit('unpipe', this, unpipeInfo);\n\n  return this;\n};\n\n// set up data events if they are asked for\n// Ensure readable listeners eventually get something\nReadable.prototype.on = function (ev, fn) {\n  var res = Stream.prototype.on.call(this, ev, fn);\n\n  if (ev === 'data') {\n    // Start flowing on next tick if stream isn't explicitly paused\n    if (this._readableState.flowing !== false) this.resume();\n  } else if (ev === 'readable') {\n    var state = this._readableState;\n    if (!state.endEmitted && !state.readableListening) {\n      state.readableListening = state.needReadable = true;\n      state.emittedReadable = false;\n      if (!state.reading) {\n        processNextTick(nReadingNextTick, this);\n      } else if (state.length) {\n        emitReadable(this);\n      }\n    }\n  }\n\n  return res;\n};\nReadable.prototype.addListener = Readable.prototype.on;\n\nfunction nReadingNextTick(self) {\n  debug('readable nexttick read 0');\n  self.read(0);\n}\n\n// pause() and resume() are remnants of the legacy readable stream API\n// If the user uses them, then switch into old mode.\nReadable.prototype.resume = function () {\n  var state = this._readableState;\n  if (!state.flowing) {\n    debug('resume');\n    state.flowing = true;\n    resume(this, state);\n  }\n  return this;\n};\n\nfunction resume(stream, state) {\n  if (!state.resumeScheduled) {\n    state.resumeScheduled = true;\n    processNextTick(resume_, stream, state);\n  }\n}\n\nfunction resume_(stream, state) {\n  if (!state.reading) {\n    debug('resume read 0');\n    stream.read(0);\n  }\n\n  state.resumeScheduled = false;\n  state.awaitDrain = 0;\n  stream.emit('resume');\n  flow(stream);\n  if (state.flowing && !state.reading) stream.read(0);\n}\n\nReadable.prototype.pause = function () {\n  debug('call pause flowing=%j', this._readableState.flowing);\n  if (false !== this._readableState.flowing) {\n    debug('pause');\n    this._readableState.flowing = false;\n    this.emit('pause');\n  }\n  return this;\n};\n\nfunction flow(stream) {\n  var state = stream._readableState;\n  debug('flow', state.flowing);\n  while (state.flowing && stream.read() !== null) {}\n}\n\n// wrap an old-style stream as the async data source.\n// This is *not* part of the readable stream interface.\n// It is an ugly unfortunate mess of history.\nReadable.prototype.wrap = function (stream) {\n  var _this = this;\n\n  var state = this._readableState;\n  var paused = false;\n\n  stream.on('end', function () {\n    debug('wrapped end');\n    if (state.decoder && !state.ended) {\n      var chunk = state.decoder.end();\n      if (chunk && chunk.length) _this.push(chunk);\n    }\n\n    _this.push(null);\n  });\n\n  stream.on('data', function (chunk) {\n    debug('wrapped data');\n    if (state.decoder) chunk = state.decoder.write(chunk);\n\n    // don't skip over falsy values in objectMode\n    if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return;\n\n    var ret = _this.push(chunk);\n    if (!ret) {\n      paused = true;\n      stream.pause();\n    }\n  });\n\n  // proxy all the other methods.\n  // important when wrapping filters and duplexes.\n  for (var i in stream) {\n    if (this[i] === undefined && typeof stream[i] === 'function') {\n      this[i] = function (method) {\n        return function () {\n          return stream[method].apply(stream, arguments);\n        };\n      }(i);\n    }\n  }\n\n  // proxy certain important events.\n  for (var n = 0; n < kProxyEvents.length; n++) {\n    stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n]));\n  }\n\n  // when we try to consume some more bytes, simply unpause the\n  // underlying stream.\n  this._read = function (n) {\n    debug('wrapped _read', n);\n    if (paused) {\n      paused = false;\n      stream.resume();\n    }\n  };\n\n  return this;\n};\n\n// exposed for testing purposes only.\nReadable._fromList = fromList;\n\n// Pluck off n bytes from an array of buffers.\n// Length is the combined lengths of all the buffers in the list.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction fromList(n, state) {\n  // nothing buffered\n  if (state.length === 0) return null;\n\n  var ret;\n  if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) {\n    // read it all, truncate the list\n    if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length);\n    state.buffer.clear();\n  } else {\n    // read part of list\n    ret = fromListPartial(n, state.buffer, state.decoder);\n  }\n\n  return ret;\n}\n\n// Extracts only enough buffered data to satisfy the amount requested.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction fromListPartial(n, list, hasStrings) {\n  var ret;\n  if (n < list.head.data.length) {\n    // slice is the same for buffers and strings\n    ret = list.head.data.slice(0, n);\n    list.head.data = list.head.data.slice(n);\n  } else if (n === list.head.data.length) {\n    // first chunk is a perfect match\n    ret = list.shift();\n  } else {\n    // result spans more than one buffer\n    ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list);\n  }\n  return ret;\n}\n\n// Copies a specified amount of characters from the list of buffered data\n// chunks.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction copyFromBufferString(n, list) {\n  var p = list.head;\n  var c = 1;\n  var ret = p.data;\n  n -= ret.length;\n  while (p = p.next) {\n    var str = p.data;\n    var nb = n > str.length ? str.length : n;\n    if (nb === str.length) ret += str;else ret += str.slice(0, n);\n    n -= nb;\n    if (n === 0) {\n      if (nb === str.length) {\n        ++c;\n        if (p.next) list.head = p.next;else list.head = list.tail = null;\n      } else {\n        list.head = p;\n        p.data = str.slice(nb);\n      }\n      break;\n    }\n    ++c;\n  }\n  list.length -= c;\n  return ret;\n}\n\n// Copies a specified amount of bytes from the list of buffered data chunks.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction copyFromBuffer(n, list) {\n  var ret = Buffer.allocUnsafe(n);\n  var p = list.head;\n  var c = 1;\n  p.data.copy(ret);\n  n -= p.data.length;\n  while (p = p.next) {\n    var buf = p.data;\n    var nb = n > buf.length ? buf.length : n;\n    buf.copy(ret, ret.length - n, 0, nb);\n    n -= nb;\n    if (n === 0) {\n      if (nb === buf.length) {\n        ++c;\n        if (p.next) list.head = p.next;else list.head = list.tail = null;\n      } else {\n        list.head = p;\n        p.data = buf.slice(nb);\n      }\n      break;\n    }\n    ++c;\n  }\n  list.length -= c;\n  return ret;\n}\n\nfunction endReadable(stream) {\n  var state = stream._readableState;\n\n  // If we get here before consuming all the bytes, then that is a\n  // bug in node.  Should never happen.\n  if (state.length > 0) throw new Error('\"endReadable()\" called on non-empty stream');\n\n  if (!state.endEmitted) {\n    state.ended = true;\n    processNextTick(endReadableNT, state, stream);\n  }\n}\n\nfunction endReadableNT(state, stream) {\n  // Check that we didn't get one last unshift.\n  if (!state.endEmitted && state.length === 0) {\n    state.endEmitted = true;\n    stream.readable = false;\n    stream.emit('end');\n  }\n}\n\nfunction forEach(xs, f) {\n  for (var i = 0, l = xs.length; i < l; i++) {\n    f(xs[i], i);\n  }\n}\n\nfunction indexOf(xs, x) {\n  for (var i = 0, l = xs.length; i < l; i++) {\n    if (xs[i] === x) return i;\n  }\n  return -1;\n}\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7), __webpack_require__(11)))\n\n/***/ }),\n/* 84 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(31).EventEmitter;\n\n\n/***/ }),\n/* 85 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n/*<replacement>*/\n\nvar processNextTick = __webpack_require__(32).nextTick;\n/*</replacement>*/\n\n// undocumented cb() API, needed for core, not for public API\nfunction destroy(err, cb) {\n  var _this = this;\n\n  var readableDestroyed = this._readableState && this._readableState.destroyed;\n  var writableDestroyed = this._writableState && this._writableState.destroyed;\n\n  if (readableDestroyed || writableDestroyed) {\n    if (cb) {\n      cb(err);\n    } else if (err && (!this._writableState || !this._writableState.errorEmitted)) {\n      processNextTick(emitErrorNT, this, err);\n    }\n    return this;\n  }\n\n  // we set destroyed to true before firing error callbacks in order\n  // to make it re-entrance safe in case destroy() is called within callbacks\n\n  if (this._readableState) {\n    this._readableState.destroyed = true;\n  }\n\n  // if this is a duplex stream mark the writable part as destroyed as well\n  if (this._writableState) {\n    this._writableState.destroyed = true;\n  }\n\n  this._destroy(err || null, function (err) {\n    if (!cb && err) {\n      processNextTick(emitErrorNT, _this, err);\n      if (_this._writableState) {\n        _this._writableState.errorEmitted = true;\n      }\n    } else if (cb) {\n      cb(err);\n    }\n  });\n\n  return this;\n}\n\nfunction undestroy() {\n  if (this._readableState) {\n    this._readableState.destroyed = false;\n    this._readableState.reading = false;\n    this._readableState.ended = false;\n    this._readableState.endEmitted = false;\n  }\n\n  if (this._writableState) {\n    this._writableState.destroyed = false;\n    this._writableState.ended = false;\n    this._writableState.ending = false;\n    this._writableState.finished = false;\n    this._writableState.errorEmitted = false;\n  }\n}\n\nfunction emitErrorNT(self, err) {\n  self.emit('error', err);\n}\n\nmodule.exports = {\n  destroy: destroy,\n  undestroy: undestroy\n};\n\n/***/ }),\n/* 86 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// a transform stream is a readable/writable stream where you do\n// something with the data.  Sometimes it's called a \"filter\",\n// but that's not a great name for it, since that implies a thing where\n// some bits pass through, and others are simply ignored.  (That would\n// be a valid example of a transform, of course.)\n//\n// While the output is causally related to the input, it's not a\n// necessarily symmetric or synchronous transformation.  For example,\n// a zlib stream might take multiple plain-text writes(), and then\n// emit a single compressed chunk some time in the future.\n//\n// Here's how this works:\n//\n// The Transform stream has all the aspects of the readable and writable\n// stream classes.  When you write(chunk), that calls _write(chunk,cb)\n// internally, and returns false if there's a lot of pending writes\n// buffered up.  When you call read(), that calls _read(n) until\n// there's enough pending readable data buffered up.\n//\n// In a transform stream, the written data is placed in a buffer.  When\n// _read(n) is called, it transforms the queued up data, calling the\n// buffered _write cb's as it consumes chunks.  If consuming a single\n// written chunk would result in multiple output chunks, then the first\n// outputted bit calls the readcb, and subsequent chunks just go into\n// the read buffer, and will cause it to emit 'readable' if necessary.\n//\n// This way, back-pressure is actually determined by the reading side,\n// since _read has to be called to start processing a new chunk.  However,\n// a pathological inflate type of transform can cause excessive buffering\n// here.  For example, imagine a stream where every byte of input is\n// interpreted as an integer from 0-255, and then results in that many\n// bytes of output.  Writing the 4 bytes {ff,ff,ff,ff} would result in\n// 1kb of data being output.  In this case, you could write a very small\n// amount of input, and end up with a very large amount of output.  In\n// such a pathological inflating mechanism, there'd be no way to tell\n// the system to stop doing the transform.  A single 4MB write could\n// cause the system to run out of memory.\n//\n// However, even in such a pathological case, only a single written chunk\n// would be consumed, and then the rest would wait (un-transformed) until\n// the results of the previous transformed chunk were consumed.\n\n\n\nmodule.exports = Transform;\n\nvar Duplex = __webpack_require__(16);\n\n/*<replacement>*/\nvar util = __webpack_require__(25);\nutil.inherits = __webpack_require__(21);\n/*</replacement>*/\n\nutil.inherits(Transform, Duplex);\n\nfunction afterTransform(er, data) {\n  var ts = this._transformState;\n  ts.transforming = false;\n\n  var cb = ts.writecb;\n\n  if (!cb) {\n    return this.emit('error', new Error('write callback called multiple times'));\n  }\n\n  ts.writechunk = null;\n  ts.writecb = null;\n\n  if (data != null) // single equals check for both `null` and `undefined`\n    this.push(data);\n\n  cb(er);\n\n  var rs = this._readableState;\n  rs.reading = false;\n  if (rs.needReadable || rs.length < rs.highWaterMark) {\n    this._read(rs.highWaterMark);\n  }\n}\n\nfunction Transform(options) {\n  if (!(this instanceof Transform)) return new Transform(options);\n\n  Duplex.call(this, options);\n\n  this._transformState = {\n    afterTransform: afterTransform.bind(this),\n    needTransform: false,\n    transforming: false,\n    writecb: null,\n    writechunk: null,\n    writeencoding: null\n  };\n\n  // start out asking for a readable event once data is transformed.\n  this._readableState.needReadable = true;\n\n  // we have implemented the _read method, and done the other things\n  // that Readable wants before the first _read call, so unset the\n  // sync guard flag.\n  this._readableState.sync = false;\n\n  if (options) {\n    if (typeof options.transform === 'function') this._transform = options.transform;\n\n    if (typeof options.flush === 'function') this._flush = options.flush;\n  }\n\n  // When the writable side finishes, then flush out anything remaining.\n  this.on('prefinish', prefinish);\n}\n\nfunction prefinish() {\n  var _this = this;\n\n  if (typeof this._flush === 'function') {\n    this._flush(function (er, data) {\n      done(_this, er, data);\n    });\n  } else {\n    done(this, null, null);\n  }\n}\n\nTransform.prototype.push = function (chunk, encoding) {\n  this._transformState.needTransform = false;\n  return Duplex.prototype.push.call(this, chunk, encoding);\n};\n\n// This is the part where you do stuff!\n// override this function in implementation classes.\n// 'chunk' is an input chunk.\n//\n// Call `push(newChunk)` to pass along transformed output\n// to the readable side.  You may call 'push' zero or more times.\n//\n// Call `cb(err)` when you are done with this chunk.  If you pass\n// an error, then that'll put the hurt on the whole operation.  If you\n// never call cb(), then you'll never get another chunk.\nTransform.prototype._transform = function (chunk, encoding, cb) {\n  throw new Error('_transform() is not implemented');\n};\n\nTransform.prototype._write = function (chunk, encoding, cb) {\n  var ts = this._transformState;\n  ts.writecb = cb;\n  ts.writechunk = chunk;\n  ts.writeencoding = encoding;\n  if (!ts.transforming) {\n    var rs = this._readableState;\n    if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark);\n  }\n};\n\n// Doesn't matter what the args are here.\n// _transform does all the work.\n// That we got here means that the readable side wants more data.\nTransform.prototype._read = function (n) {\n  var ts = this._transformState;\n\n  if (ts.writechunk !== null && ts.writecb && !ts.transforming) {\n    ts.transforming = true;\n    this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);\n  } else {\n    // mark that we need a transform, so that any data that comes in\n    // will get processed, now that we've asked for it.\n    ts.needTransform = true;\n  }\n};\n\nTransform.prototype._destroy = function (err, cb) {\n  var _this2 = this;\n\n  Duplex.prototype._destroy.call(this, err, function (err2) {\n    cb(err2);\n    _this2.emit('close');\n  });\n};\n\nfunction done(stream, er, data) {\n  if (er) return stream.emit('error', er);\n\n  if (data != null) // single equals check for both `null` and `undefined`\n    stream.push(data);\n\n  // if there's nothing in the write buffer, then that means\n  // that nothing more will ever be provided\n  if (stream._writableState.length) throw new Error('Calling transform done when ws.length != 0');\n\n  if (stream._transformState.transforming) throw new Error('Calling transform done when still transforming');\n\n  return stream.push(null);\n}\n\n/***/ }),\n/* 87 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6\n\n/*\nPDFReference - represents a reference to another object in the PDF object heirarchy\nBy Devon Govett\n */\n\n(function() {\n  var PDFObject, PDFReference, stream, zlib,\n    bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },\n    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n    hasProp = {}.hasOwnProperty;\n\n  zlib = __webpack_require__(48);\n\n  stream = __webpack_require__(15);\n\n  PDFReference = (function(superClass) {\n    extend(PDFReference, superClass);\n\n    function PDFReference(document, id, data) {\n      this.document = document;\n      this.id = id;\n      this.data = data != null ? data : {};\n      this.finalize = bind(this.finalize, this);\n      PDFReference.__super__.constructor.call(this, {\n        decodeStrings: false\n      });\n      this.gen = 0;\n      this.deflate = null;\n      this.compress = this.document.compress && !this.data.Filter;\n      this.uncompressedLength = 0;\n      this.chunks = [];\n    }\n\n    PDFReference.prototype.initDeflate = function() {\n      this.data.Filter = 'FlateDecode';\n      this.deflate = zlib.createDeflate();\n      this.deflate.on('data', (function(_this) {\n        return function(chunk) {\n          _this.chunks.push(chunk);\n          return _this.data.Length += chunk.length;\n        };\n      })(this));\n      return this.deflate.on('end', this.finalize);\n    };\n\n    PDFReference.prototype._write = function(chunk, encoding, callback) {\n      var base;\n      if (!Buffer.isBuffer(chunk)) {\n        chunk = new Buffer(chunk + '\\n', 'binary');\n      }\n      this.uncompressedLength += chunk.length;\n      if ((base = this.data).Length == null) {\n        base.Length = 0;\n      }\n      if (this.compress) {\n        if (!this.deflate) {\n          this.initDeflate();\n        }\n        this.deflate.write(chunk);\n      } else {\n        this.chunks.push(chunk);\n        this.data.Length += chunk.length;\n      }\n      return callback();\n    };\n\n    PDFReference.prototype.end = function(chunk) {\n      PDFReference.__super__.end.apply(this, arguments);\n      if (this.deflate) {\n        return this.deflate.end();\n      } else {\n        return this.finalize();\n      }\n    };\n\n    PDFReference.prototype.finalize = function() {\n      var chunk, i, len, ref;\n      this.offset = this.document._offset;\n      this.document._write(this.id + \" \" + this.gen + \" obj\");\n      this.document._write(PDFObject.convert(this.data));\n      if (this.chunks.length) {\n        this.document._write('stream');\n        ref = this.chunks;\n        for (i = 0, len = ref.length; i < len; i++) {\n          chunk = ref[i];\n          this.document._write(chunk);\n        }\n        this.chunks.length = 0;\n        this.document._write('\\nendstream');\n      }\n      this.document._write('endobj');\n      return this.document._refEnd(this);\n    };\n\n    PDFReference.prototype.toString = function() {\n      return this.id + \" \" + this.gen + \" R\";\n    };\n\n    return PDFReference;\n\n  })(stream.Writable);\n\n  module.exports = PDFReference;\n\n  PDFObject = __webpack_require__(26);\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 88 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(global) {\n\n// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js\n// original notice:\n\n/*!\n * The buffer module from node.js, for the browser.\n *\n * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>\n * @license  MIT\n */\nfunction compare(a, b) {\n  if (a === b) {\n    return 0;\n  }\n\n  var x = a.length;\n  var y = b.length;\n\n  for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n    if (a[i] !== b[i]) {\n      x = a[i];\n      y = b[i];\n      break;\n    }\n  }\n\n  if (x < y) {\n    return -1;\n  }\n  if (y < x) {\n    return 1;\n  }\n  return 0;\n}\nfunction isBuffer(b) {\n  if (global.Buffer && typeof global.Buffer.isBuffer === 'function') {\n    return global.Buffer.isBuffer(b);\n  }\n  return !!(b != null && b._isBuffer);\n}\n\n// based on node assert, original notice:\n\n// http://wiki.commonjs.org/wiki/Unit_Testing/1.0\n//\n// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!\n//\n// Originally from narwhal.js (http://narwhaljs.org)\n// Copyright (c) 2009 Thomas Robinson <280north.com>\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the 'Software'), to\n// deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n// sell copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nvar util = __webpack_require__(49);\nvar hasOwn = Object.prototype.hasOwnProperty;\nvar pSlice = Array.prototype.slice;\nvar functionsHaveNames = (function () {\n  return function foo() {}.name === 'foo';\n}());\nfunction pToString (obj) {\n  return Object.prototype.toString.call(obj);\n}\nfunction isView(arrbuf) {\n  if (isBuffer(arrbuf)) {\n    return false;\n  }\n  if (typeof global.ArrayBuffer !== 'function') {\n    return false;\n  }\n  if (typeof ArrayBuffer.isView === 'function') {\n    return ArrayBuffer.isView(arrbuf);\n  }\n  if (!arrbuf) {\n    return false;\n  }\n  if (arrbuf instanceof DataView) {\n    return true;\n  }\n  if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) {\n    return true;\n  }\n  return false;\n}\n// 1. The assert module provides functions that throw\n// AssertionError's when particular conditions are not met. The\n// assert module must conform to the following interface.\n\nvar assert = module.exports = ok;\n\n// 2. The AssertionError is defined in assert.\n// new assert.AssertionError({ message: message,\n//                             actual: actual,\n//                             expected: expected })\n\nvar regex = /\\s*function\\s+([^\\(\\s]*)\\s*/;\n// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js\nfunction getName(func) {\n  if (!util.isFunction(func)) {\n    return;\n  }\n  if (functionsHaveNames) {\n    return func.name;\n  }\n  var str = func.toString();\n  var match = str.match(regex);\n  return match && match[1];\n}\nassert.AssertionError = function AssertionError(options) {\n  this.name = 'AssertionError';\n  this.actual = options.actual;\n  this.expected = options.expected;\n  this.operator = options.operator;\n  if (options.message) {\n    this.message = options.message;\n    this.generatedMessage = false;\n  } else {\n    this.message = getMessage(this);\n    this.generatedMessage = true;\n  }\n  var stackStartFunction = options.stackStartFunction || fail;\n  if (Error.captureStackTrace) {\n    Error.captureStackTrace(this, stackStartFunction);\n  } else {\n    // non v8 browsers so we can have a stacktrace\n    var err = new Error();\n    if (err.stack) {\n      var out = err.stack;\n\n      // try to strip useless frames\n      var fn_name = getName(stackStartFunction);\n      var idx = out.indexOf('\\n' + fn_name);\n      if (idx >= 0) {\n        // once we have located the function frame\n        // we need to strip out everything before it (and its line)\n        var next_line = out.indexOf('\\n', idx + 1);\n        out = out.substring(next_line + 1);\n      }\n\n      this.stack = out;\n    }\n  }\n};\n\n// assert.AssertionError instanceof Error\nutil.inherits(assert.AssertionError, Error);\n\nfunction truncate(s, n) {\n  if (typeof s === 'string') {\n    return s.length < n ? s : s.slice(0, n);\n  } else {\n    return s;\n  }\n}\nfunction inspect(something) {\n  if (functionsHaveNames || !util.isFunction(something)) {\n    return util.inspect(something);\n  }\n  var rawname = getName(something);\n  var name = rawname ? ': ' + rawname : '';\n  return '[Function' +  name + ']';\n}\nfunction getMessage(self) {\n  return truncate(inspect(self.actual), 128) + ' ' +\n         self.operator + ' ' +\n         truncate(inspect(self.expected), 128);\n}\n\n// At present only the three keys mentioned above are used and\n// understood by the spec. Implementations or sub modules can pass\n// other keys to the AssertionError's constructor - they will be\n// ignored.\n\n// 3. All of the following functions must throw an AssertionError\n// when a corresponding condition is not met, with a message that\n// may be undefined if not provided.  All assertion methods provide\n// both the actual and expected values to the assertion error for\n// display purposes.\n\nfunction fail(actual, expected, message, operator, stackStartFunction) {\n  throw new assert.AssertionError({\n    message: message,\n    actual: actual,\n    expected: expected,\n    operator: operator,\n    stackStartFunction: stackStartFunction\n  });\n}\n\n// EXTENSION! allows for well behaved errors defined elsewhere.\nassert.fail = fail;\n\n// 4. Pure assertion tests whether a value is truthy, as determined\n// by !!guard.\n// assert.ok(guard, message_opt);\n// This statement is equivalent to assert.equal(true, !!guard,\n// message_opt);. To test strictly for the value true, use\n// assert.strictEqual(true, guard, message_opt);.\n\nfunction ok(value, message) {\n  if (!value) fail(value, true, message, '==', assert.ok);\n}\nassert.ok = ok;\n\n// 5. The equality assertion tests shallow, coercive equality with\n// ==.\n// assert.equal(actual, expected, message_opt);\n\nassert.equal = function equal(actual, expected, message) {\n  if (actual != expected) fail(actual, expected, message, '==', assert.equal);\n};\n\n// 6. The non-equality assertion tests for whether two objects are not equal\n// with != assert.notEqual(actual, expected, message_opt);\n\nassert.notEqual = function notEqual(actual, expected, message) {\n  if (actual == expected) {\n    fail(actual, expected, message, '!=', assert.notEqual);\n  }\n};\n\n// 7. The equivalence assertion tests a deep equality relation.\n// assert.deepEqual(actual, expected, message_opt);\n\nassert.deepEqual = function deepEqual(actual, expected, message) {\n  if (!_deepEqual(actual, expected, false)) {\n    fail(actual, expected, message, 'deepEqual', assert.deepEqual);\n  }\n};\n\nassert.deepStrictEqual = function deepStrictEqual(actual, expected, message) {\n  if (!_deepEqual(actual, expected, true)) {\n    fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual);\n  }\n};\n\nfunction _deepEqual(actual, expected, strict, memos) {\n  // 7.1. All identical values are equivalent, as determined by ===.\n  if (actual === expected) {\n    return true;\n  } else if (isBuffer(actual) && isBuffer(expected)) {\n    return compare(actual, expected) === 0;\n\n  // 7.2. If the expected value is a Date object, the actual value is\n  // equivalent if it is also a Date object that refers to the same time.\n  } else if (util.isDate(actual) && util.isDate(expected)) {\n    return actual.getTime() === expected.getTime();\n\n  // 7.3 If the expected value is a RegExp object, the actual value is\n  // equivalent if it is also a RegExp object with the same source and\n  // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).\n  } else if (util.isRegExp(actual) && util.isRegExp(expected)) {\n    return actual.source === expected.source &&\n           actual.global === expected.global &&\n           actual.multiline === expected.multiline &&\n           actual.lastIndex === expected.lastIndex &&\n           actual.ignoreCase === expected.ignoreCase;\n\n  // 7.4. Other pairs that do not both pass typeof value == 'object',\n  // equivalence is determined by ==.\n  } else if ((actual === null || typeof actual !== 'object') &&\n             (expected === null || typeof expected !== 'object')) {\n    return strict ? actual === expected : actual == expected;\n\n  // If both values are instances of typed arrays, wrap their underlying\n  // ArrayBuffers in a Buffer each to increase performance\n  // This optimization requires the arrays to have the same type as checked by\n  // Object.prototype.toString (aka pToString). Never perform binary\n  // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their\n  // bit patterns are not identical.\n  } else if (isView(actual) && isView(expected) &&\n             pToString(actual) === pToString(expected) &&\n             !(actual instanceof Float32Array ||\n               actual instanceof Float64Array)) {\n    return compare(new Uint8Array(actual.buffer),\n                   new Uint8Array(expected.buffer)) === 0;\n\n  // 7.5 For all other Object pairs, including Array objects, equivalence is\n  // determined by having the same number of owned properties (as verified\n  // with Object.prototype.hasOwnProperty.call), the same set of keys\n  // (although not necessarily the same order), equivalent values for every\n  // corresponding key, and an identical 'prototype' property. Note: this\n  // accounts for both named and indexed properties on Arrays.\n  } else if (isBuffer(actual) !== isBuffer(expected)) {\n    return false;\n  } else {\n    memos = memos || {actual: [], expected: []};\n\n    var actualIndex = memos.actual.indexOf(actual);\n    if (actualIndex !== -1) {\n      if (actualIndex === memos.expected.indexOf(expected)) {\n        return true;\n      }\n    }\n\n    memos.actual.push(actual);\n    memos.expected.push(expected);\n\n    return objEquiv(actual, expected, strict, memos);\n  }\n}\n\nfunction isArguments(object) {\n  return Object.prototype.toString.call(object) == '[object Arguments]';\n}\n\nfunction objEquiv(a, b, strict, actualVisitedObjects) {\n  if (a === null || a === undefined || b === null || b === undefined)\n    return false;\n  // if one is a primitive, the other must be same\n  if (util.isPrimitive(a) || util.isPrimitive(b))\n    return a === b;\n  if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b))\n    return false;\n  var aIsArgs = isArguments(a);\n  var bIsArgs = isArguments(b);\n  if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs))\n    return false;\n  if (aIsArgs) {\n    a = pSlice.call(a);\n    b = pSlice.call(b);\n    return _deepEqual(a, b, strict);\n  }\n  var ka = objectKeys(a);\n  var kb = objectKeys(b);\n  var key, i;\n  // having the same number of owned properties (keys incorporates\n  // hasOwnProperty)\n  if (ka.length !== kb.length)\n    return false;\n  //the same set of keys (although not necessarily the same order),\n  ka.sort();\n  kb.sort();\n  //~~~cheap key test\n  for (i = ka.length - 1; i >= 0; i--) {\n    if (ka[i] !== kb[i])\n      return false;\n  }\n  //equivalent values for every corresponding key, and\n  //~~~possibly expensive deep test\n  for (i = ka.length - 1; i >= 0; i--) {\n    key = ka[i];\n    if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects))\n      return false;\n  }\n  return true;\n}\n\n// 8. The non-equivalence assertion tests for any deep inequality.\n// assert.notDeepEqual(actual, expected, message_opt);\n\nassert.notDeepEqual = function notDeepEqual(actual, expected, message) {\n  if (_deepEqual(actual, expected, false)) {\n    fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);\n  }\n};\n\nassert.notDeepStrictEqual = notDeepStrictEqual;\nfunction notDeepStrictEqual(actual, expected, message) {\n  if (_deepEqual(actual, expected, true)) {\n    fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual);\n  }\n}\n\n\n// 9. The strict equality assertion tests strict equality, as determined by ===.\n// assert.strictEqual(actual, expected, message_opt);\n\nassert.strictEqual = function strictEqual(actual, expected, message) {\n  if (actual !== expected) {\n    fail(actual, expected, message, '===', assert.strictEqual);\n  }\n};\n\n// 10. The strict non-equality assertion tests for strict inequality, as\n// determined by !==.  assert.notStrictEqual(actual, expected, message_opt);\n\nassert.notStrictEqual = function notStrictEqual(actual, expected, message) {\n  if (actual === expected) {\n    fail(actual, expected, message, '!==', assert.notStrictEqual);\n  }\n};\n\nfunction expectedException(actual, expected) {\n  if (!actual || !expected) {\n    return false;\n  }\n\n  if (Object.prototype.toString.call(expected) == '[object RegExp]') {\n    return expected.test(actual);\n  }\n\n  try {\n    if (actual instanceof expected) {\n      return true;\n    }\n  } catch (e) {\n    // Ignore.  The instanceof check doesn't work for arrow functions.\n  }\n\n  if (Error.isPrototypeOf(expected)) {\n    return false;\n  }\n\n  return expected.call({}, actual) === true;\n}\n\nfunction _tryBlock(block) {\n  var error;\n  try {\n    block();\n  } catch (e) {\n    error = e;\n  }\n  return error;\n}\n\nfunction _throws(shouldThrow, block, expected, message) {\n  var actual;\n\n  if (typeof block !== 'function') {\n    throw new TypeError('\"block\" argument must be a function');\n  }\n\n  if (typeof expected === 'string') {\n    message = expected;\n    expected = null;\n  }\n\n  actual = _tryBlock(block);\n\n  message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +\n            (message ? ' ' + message : '.');\n\n  if (shouldThrow && !actual) {\n    fail(actual, expected, 'Missing expected exception' + message);\n  }\n\n  var userProvidedMessage = typeof message === 'string';\n  var isUnwantedException = !shouldThrow && util.isError(actual);\n  var isUnexpectedException = !shouldThrow && actual && !expected;\n\n  if ((isUnwantedException &&\n      userProvidedMessage &&\n      expectedException(actual, expected)) ||\n      isUnexpectedException) {\n    fail(actual, expected, 'Got unwanted exception' + message);\n  }\n\n  if ((shouldThrow && actual && expected &&\n      !expectedException(actual, expected)) || (!shouldThrow && actual)) {\n    throw actual;\n  }\n}\n\n// 11. Expected to throw an error:\n// assert.throws(block, Error_opt, message_opt);\n\nassert.throws = function(block, /*optional*/error, /*optional*/message) {\n  _throws(true, block, error, message);\n};\n\n// EXTENSION! This is annoying to write outside this module.\nassert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {\n  _throws(false, block, error, message);\n};\n\nassert.ifError = function(err) { if (err) throw err; };\n\nvar objectKeys = Object.keys || function (obj) {\n  var keys = [];\n  for (var key in obj) {\n    if (hasOwn.call(obj, key)) keys.push(key);\n  }\n  return keys;\n};\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))\n\n/***/ }),\n/* 89 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// Note: adler32 takes 12% for level 0 and 2% for level 6.\n// It isn't worth it to make additional optimizations as in original.\n// Small size is preferable.\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nfunction adler32(adler, buf, len, pos) {\n  var s1 = (adler & 0xffff) |0,\n      s2 = ((adler >>> 16) & 0xffff) |0,\n      n = 0;\n\n  while (len !== 0) {\n    // Set limit ~ twice less than 5552, to keep\n    // s2 in 31-bits, because we force signed ints.\n    // in other case %= will fail.\n    n = len > 2000 ? 2000 : len;\n    len -= n;\n\n    do {\n      s1 = (s1 + buf[pos++]) |0;\n      s2 = (s2 + s1) |0;\n    } while (--n);\n\n    s1 %= 65521;\n    s2 %= 65521;\n  }\n\n  return (s1 | (s2 << 16)) |0;\n}\n\n\nmodule.exports = adler32;\n\n\n/***/ }),\n/* 90 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// Note: we can't get significant speed boost here.\n// So write code to minimize size - no pregenerated tables\n// and array tools dependencies.\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\n// Use ordinary array, since untyped makes no boost here\nfunction makeTable() {\n  var c, table = [];\n\n  for (var n = 0; n < 256; n++) {\n    c = n;\n    for (var k = 0; k < 8; k++) {\n      c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));\n    }\n    table[n] = c;\n  }\n\n  return table;\n}\n\n// Create table on load. Just 255 signed longs. Not a problem.\nvar crcTable = makeTable();\n\n\nfunction crc32(crc, buf, len, pos) {\n  var t = crcTable,\n      end = pos + len;\n\n  crc ^= -1;\n\n  for (var i = pos; i < end; i++) {\n    crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];\n  }\n\n  return (crc ^ (-1)); // >>> 0;\n}\n\n\nmodule.exports = crc32;\n\n\n/***/ }),\n/* 91 */\n/***/ (function(module, exports) {\n\nmodule.exports = [[\"a140\",\"\",62],[\"a180\",\"\",32],[\"a240\",\"\",62],[\"a280\",\"\",32],[\"a2ab\",\"\",5],[\"a2e3\",\"€\"],[\"a2ef\",\"\"],[\"a2fd\",\"\"],[\"a340\",\"\",62],[\"a380\",\"\",31,\"　\"],[\"a440\",\"\",62],[\"a480\",\"\",32],[\"a4f4\",\"\",10],[\"a540\",\"\",62],[\"a580\",\"\",32],[\"a5f7\",\"\",7],[\"a640\",\"\",62],[\"a680\",\"\",32],[\"a6b9\",\"\",7],[\"a6d9\",\"\",6],[\"a6ec\",\"\"],[\"a6f3\",\"\"],[\"a6f6\",\"\",8],[\"a740\",\"\",62],[\"a780\",\"\",32],[\"a7c2\",\"\",14],[\"a7f2\",\"\",12],[\"a896\",\"\",10],[\"a8bc\",\"\"],[\"a8bf\",\"ǹ\"],[\"a8c1\",\"\"],[\"a8ea\",\"\",20],[\"a958\",\"\"],[\"a95b\",\"\"],[\"a95d\",\"\"],[\"a989\",\"〾⿰\",11],[\"a997\",\"\",12],[\"a9f0\",\"\",14],[\"aaa1\",\"\",93],[\"aba1\",\"\",93],[\"aca1\",\"\",93],[\"ada1\",\"\",93],[\"aea1\",\"\",93],[\"afa1\",\"\",93],[\"d7fa\",\"\",4],[\"f8a1\",\"\",93],[\"f9a1\",\"\",93],[\"faa1\",\"\",93],[\"fba1\",\"\",93],[\"fca1\",\"\",93],[\"fda1\",\"\",93],[\"fe50\",\"⺁⺄㑳㑇⺈⺋㖞㘚㘎⺌⺗㥮㤘㧏㧟㩳㧐㭎㱮㳠⺧⺪䁖䅟⺮䌷⺳⺶⺷䎱䎬⺻䏝䓖䙡䙌\"],[\"fe80\",\"䜣䜩䝼䞍⻊䥇䥺䥽䦂䦃䦅䦆䦟䦛䦷䦶䲣䲟䲠䲡䱷䲢䴓\",6,\"䶮\",93]]\n\n/***/ }),\n/* 92 */\n/***/ (function(module, exports) {\n\nmodule.exports = [[\"0\",\"\\u0000\",127],[\"a140\",\"　，、。．‧；：？！︰…‥﹐﹑﹒·﹔﹕﹖﹗｜–︱—︳╴︴﹏（）︵︶｛｝︷︸〔〕︹︺【】︻︼《》︽︾〈〉︿﹀「」﹁﹂『』﹃﹄﹙﹚\"],[\"a1a1\",\"﹛﹜﹝﹞‘’“”〝〞‵′＃＆＊※§〃○●△▲◎☆★◇◆□■▽▼㊣℅¯￣＿ˍ﹉﹊﹍﹎﹋﹌﹟﹠﹡＋－×÷±√＜＞＝≦≧≠∞≒≡﹢\",4,\"～∩∪⊥∠∟⊿㏒㏑∫∮∵∴♀♂⊕⊙↑↓←→↖↗↙↘∥∣／\"],[\"a240\",\"＼∕﹨＄￥〒￠￡％＠℃℉﹩﹪﹫㏕㎜㎝㎞㏎㎡㎎㎏㏄°兙兛兞兝兡兣嗧瓩糎▁\",7,\"▏▎▍▌▋▊▉┼┴┬┤├▔─│▕┌┐└┘╭\"],[\"a2a1\",\"╮╰╯═╞╪╡◢◣◥◤╱╲╳０\",9,\"Ⅰ\",9,\"〡\",8,\"十卄卅Ａ\",25,\"ａ\",21],[\"a340\",\"ｗｘｙｚΑ\",16,\"Σ\",6,\"α\",16,\"σ\",6,\"ㄅ\",10],[\"a3a1\",\"ㄐ\",25,\"˙ˉˊˇˋ\"],[\"a3e1\",\"€\"],[\"a440\",\"一乙丁七乃九了二人儿入八几刀刁力匕十卜又三下丈上丫丸凡久么也乞于亡兀刃勺千叉口土士夕大女子孑孓寸小尢尸山川工己已巳巾干廾弋弓才\"],[\"a4a1\",\"丑丐不中丰丹之尹予云井互五亢仁什仃仆仇仍今介仄元允內六兮公冗凶分切刈勻勾勿化匹午升卅卞厄友及反壬天夫太夭孔少尤尺屯巴幻廿弔引心戈戶手扎支文斗斤方日曰月木欠止歹毋比毛氏水火爪父爻片牙牛犬王丙\"],[\"a540\",\"世丕且丘主乍乏乎以付仔仕他仗代令仙仞充兄冉冊冬凹出凸刊加功包匆北匝仟半卉卡占卯卮去可古右召叮叩叨叼司叵叫另只史叱台句叭叻四囚外\"],[\"a5a1\",\"央失奴奶孕它尼巨巧左市布平幼弁弘弗必戊打扔扒扑斥旦朮本未末札正母民氐永汁汀氾犯玄玉瓜瓦甘生用甩田由甲申疋白皮皿目矛矢石示禾穴立丞丟乒乓乩亙交亦亥仿伉伙伊伕伍伐休伏仲件任仰仳份企伋光兇兆先全\"],[\"a640\",\"共再冰列刑划刎刖劣匈匡匠印危吉吏同吊吐吁吋各向名合吃后吆吒因回囝圳地在圭圬圯圩夙多夷夸妄奸妃好她如妁字存宇守宅安寺尖屹州帆并年\"],[\"a6a1\",\"式弛忙忖戎戌戍成扣扛托收早旨旬旭曲曳有朽朴朱朵次此死氖汝汗汙江池汐汕污汛汍汎灰牟牝百竹米糸缶羊羽老考而耒耳聿肉肋肌臣自至臼舌舛舟艮色艾虫血行衣西阡串亨位住佇佗佞伴佛何估佐佑伽伺伸佃佔似但佣\"],[\"a740\",\"作你伯低伶余佝佈佚兌克免兵冶冷別判利刪刨劫助努劬匣即卵吝吭吞吾否呎吧呆呃吳呈呂君吩告吹吻吸吮吵吶吠吼呀吱含吟听囪困囤囫坊坑址坍\"],[\"a7a1\",\"均坎圾坐坏圻壯夾妝妒妨妞妣妙妖妍妤妓妊妥孝孜孚孛完宋宏尬局屁尿尾岐岑岔岌巫希序庇床廷弄弟彤形彷役忘忌志忍忱快忸忪戒我抄抗抖技扶抉扭把扼找批扳抒扯折扮投抓抑抆改攻攸旱更束李杏材村杜杖杞杉杆杠\"],[\"a840\",\"杓杗步每求汞沙沁沈沉沅沛汪決沐汰沌汨沖沒汽沃汲汾汴沆汶沍沔沘沂灶灼災灸牢牡牠狄狂玖甬甫男甸皂盯矣私秀禿究系罕肖肓肝肘肛肚育良芒\"],[\"a8a1\",\"芋芍見角言谷豆豕貝赤走足身車辛辰迂迆迅迄巡邑邢邪邦那酉釆里防阮阱阪阬並乖乳事些亞享京佯依侍佳使佬供例來侃佰併侈佩佻侖佾侏侑佺兔兒兕兩具其典冽函刻券刷刺到刮制剁劾劻卒協卓卑卦卷卸卹取叔受味呵\"],[\"a940\",\"咖呸咕咀呻呷咄咒咆呼咐呱呶和咚呢周咋命咎固垃坷坪坩坡坦坤坼夜奉奇奈奄奔妾妻委妹妮姑姆姐姍始姓姊妯妳姒姅孟孤季宗定官宜宙宛尚屈居\"],[\"a9a1\",\"屆岷岡岸岩岫岱岳帘帚帖帕帛帑幸庚店府底庖延弦弧弩往征彿彼忝忠忽念忿怏怔怯怵怖怪怕怡性怩怫怛或戕房戾所承拉拌拄抿拂抹拒招披拓拔拋拈抨抽押拐拙拇拍抵拚抱拘拖拗拆抬拎放斧於旺昔易昌昆昂明昀昏昕昊\"],[\"aa40\",\"昇服朋杭枋枕東果杳杷枇枝林杯杰板枉松析杵枚枓杼杪杲欣武歧歿氓氛泣注泳沱泌泥河沽沾沼波沫法泓沸泄油況沮泗泅泱沿治泡泛泊沬泯泜泖泠\"],[\"aaa1\",\"炕炎炒炊炙爬爭爸版牧物狀狎狙狗狐玩玨玟玫玥甽疝疙疚的盂盲直知矽社祀祁秉秈空穹竺糾罔羌羋者肺肥肢肱股肫肩肴肪肯臥臾舍芳芝芙芭芽芟芹花芬芥芯芸芣芰芾芷虎虱初表軋迎返近邵邸邱邶采金長門阜陀阿阻附\"],[\"ab40\",\"陂隹雨青非亟亭亮信侵侯便俠俑俏保促侶俘俟俊俗侮俐俄係俚俎俞侷兗冒冑冠剎剃削前剌剋則勇勉勃勁匍南卻厚叛咬哀咨哎哉咸咦咳哇哂咽咪品\"],[\"aba1\",\"哄哈咯咫咱咻咩咧咿囿垂型垠垣垢城垮垓奕契奏奎奐姜姘姿姣姨娃姥姪姚姦威姻孩宣宦室客宥封屎屏屍屋峙峒巷帝帥帟幽庠度建弈弭彥很待徊律徇後徉怒思怠急怎怨恍恰恨恢恆恃恬恫恪恤扁拜挖按拼拭持拮拽指拱拷\"],[\"ac40\",\"拯括拾拴挑挂政故斫施既春昭映昧是星昨昱昤曷柿染柱柔某柬架枯柵柩柯柄柑枴柚查枸柏柞柳枰柙柢柝柒歪殃殆段毒毗氟泉洋洲洪流津洌洱洞洗\"],[\"aca1\",\"活洽派洶洛泵洹洧洸洩洮洵洎洫炫為炳炬炯炭炸炮炤爰牲牯牴狩狠狡玷珊玻玲珍珀玳甚甭畏界畎畋疫疤疥疢疣癸皆皇皈盈盆盃盅省盹相眉看盾盼眇矜砂研砌砍祆祉祈祇禹禺科秒秋穿突竿竽籽紂紅紀紉紇約紆缸美羿耄\"],[\"ad40\",\"耐耍耑耶胖胥胚胃胄背胡胛胎胞胤胝致舢苧范茅苣苛苦茄若茂茉苒苗英茁苜苔苑苞苓苟苯茆虐虹虻虺衍衫要觔計訂訃貞負赴赳趴軍軌述迦迢迪迥\"],[\"ada1\",\"迭迫迤迨郊郎郁郃酋酊重閂限陋陌降面革韋韭音頁風飛食首香乘亳倌倍倣俯倦倥俸倩倖倆值借倚倒們俺倀倔倨俱倡個候倘俳修倭倪俾倫倉兼冤冥冢凍凌准凋剖剜剔剛剝匪卿原厝叟哨唐唁唷哼哥哲唆哺唔哩哭員唉哮哪\"],[\"ae40\",\"哦唧唇哽唏圃圄埂埔埋埃堉夏套奘奚娑娘娜娟娛娓姬娠娣娩娥娌娉孫屘宰害家宴宮宵容宸射屑展屐峭峽峻峪峨峰島崁峴差席師庫庭座弱徒徑徐恙\"],[\"aea1\",\"恣恥恐恕恭恩息悄悟悚悍悔悌悅悖扇拳挈拿捎挾振捕捂捆捏捉挺捐挽挪挫挨捍捌效敉料旁旅時晉晏晃晒晌晅晁書朔朕朗校核案框桓根桂桔栩梳栗桌桑栽柴桐桀格桃株桅栓栘桁殊殉殷氣氧氨氦氤泰浪涕消涇浦浸海浙涓\"],[\"af40\",\"浬涉浮浚浴浩涌涊浹涅浥涔烊烘烤烙烈烏爹特狼狹狽狸狷玆班琉珮珠珪珞畔畝畜畚留疾病症疲疳疽疼疹痂疸皋皰益盍盎眩真眠眨矩砰砧砸砝破砷\"],[\"afa1\",\"砥砭砠砟砲祕祐祠祟祖神祝祗祚秤秣秧租秦秩秘窄窈站笆笑粉紡紗紋紊素索純紐紕級紜納紙紛缺罟羔翅翁耆耘耕耙耗耽耿胱脂胰脅胭胴脆胸胳脈能脊胼胯臭臬舀舐航舫舨般芻茫荒荔荊茸荐草茵茴荏茲茹茶茗荀茱茨荃\"],[\"b040\",\"虔蚊蚪蚓蚤蚩蚌蚣蚜衰衷袁袂衽衹記訐討訌訕訊託訓訖訏訑豈豺豹財貢起躬軒軔軏辱送逆迷退迺迴逃追逅迸邕郡郝郢酒配酌釘針釗釜釙閃院陣陡\"],[\"b0a1\",\"陛陝除陘陞隻飢馬骨高鬥鬲鬼乾偺偽停假偃偌做偉健偶偎偕偵側偷偏倏偯偭兜冕凰剪副勒務勘動匐匏匙匿區匾參曼商啪啦啄啞啡啃啊唱啖問啕唯啤唸售啜唬啣唳啁啗圈國圉域堅堊堆埠埤基堂堵執培夠奢娶婁婉婦婪婀\"],[\"b140\",\"娼婢婚婆婊孰寇寅寄寂宿密尉專將屠屜屝崇崆崎崛崖崢崑崩崔崙崤崧崗巢常帶帳帷康庸庶庵庾張強彗彬彩彫得徙從徘御徠徜恿患悉悠您惋悴惦悽\"],[\"b1a1\",\"情悻悵惜悼惘惕惆惟悸惚惇戚戛扈掠控捲掖探接捷捧掘措捱掩掉掃掛捫推掄授掙採掬排掏掀捻捩捨捺敝敖救教敗啟敏敘敕敔斜斛斬族旋旌旎晝晚晤晨晦晞曹勗望梁梯梢梓梵桿桶梱梧梗械梃棄梭梆梅梔條梨梟梡梂欲殺\"],[\"b240\",\"毫毬氫涎涼淳淙液淡淌淤添淺清淇淋涯淑涮淞淹涸混淵淅淒渚涵淚淫淘淪深淮淨淆淄涪淬涿淦烹焉焊烽烯爽牽犁猜猛猖猓猙率琅琊球理現琍瓠瓶\"],[\"b2a1\",\"瓷甜產略畦畢異疏痔痕疵痊痍皎盔盒盛眷眾眼眶眸眺硫硃硎祥票祭移窒窕笠笨笛第符笙笞笮粒粗粕絆絃統紮紹紼絀細紳組累終紲紱缽羞羚翌翎習耜聊聆脯脖脣脫脩脰脤舂舵舷舶船莎莞莘荸莢莖莽莫莒莊莓莉莠荷荻荼\"],[\"b340\",\"莆莧處彪蛇蛀蚶蛄蚵蛆蛋蚱蚯蛉術袞袈被袒袖袍袋覓規訪訝訣訥許設訟訛訢豉豚販責貫貨貪貧赧赦趾趺軛軟這逍通逗連速逝逐逕逞造透逢逖逛途\"],[\"b3a1\",\"部郭都酗野釵釦釣釧釭釩閉陪陵陳陸陰陴陶陷陬雀雪雩章竟頂頃魚鳥鹵鹿麥麻傢傍傅備傑傀傖傘傚最凱割剴創剩勞勝勛博厥啻喀喧啼喊喝喘喂喜喪喔喇喋喃喳單喟唾喲喚喻喬喱啾喉喫喙圍堯堪場堤堰報堡堝堠壹壺奠\"],[\"b440\",\"婷媚婿媒媛媧孳孱寒富寓寐尊尋就嵌嵐崴嵇巽幅帽幀幃幾廊廁廂廄弼彭復循徨惑惡悲悶惠愜愣惺愕惰惻惴慨惱愎惶愉愀愒戟扉掣掌描揀揩揉揆揍\"],[\"b4a1\",\"插揣提握揖揭揮捶援揪換摒揚揹敞敦敢散斑斐斯普晰晴晶景暑智晾晷曾替期朝棺棕棠棘棗椅棟棵森棧棹棒棲棣棋棍植椒椎棉棚楮棻款欺欽殘殖殼毯氮氯氬港游湔渡渲湧湊渠渥渣減湛湘渤湖湮渭渦湯渴湍渺測湃渝渾滋\"],[\"b540\",\"溉渙湎湣湄湲湩湟焙焚焦焰無然煮焜牌犄犀猶猥猴猩琺琪琳琢琥琵琶琴琯琛琦琨甥甦畫番痢痛痣痙痘痞痠登發皖皓皴盜睏短硝硬硯稍稈程稅稀窘\"],[\"b5a1\",\"窗窖童竣等策筆筐筒答筍筋筏筑粟粥絞結絨絕紫絮絲絡給絢絰絳善翔翕耋聒肅腕腔腋腑腎脹腆脾腌腓腴舒舜菩萃菸萍菠菅萋菁華菱菴著萊菰萌菌菽菲菊萸萎萄菜萇菔菟虛蛟蛙蛭蛔蛛蛤蛐蛞街裁裂袱覃視註詠評詞証詁\"],[\"b640\",\"詔詛詐詆訴診訶詖象貂貯貼貳貽賁費賀貴買貶貿貸越超趁跎距跋跚跑跌跛跆軻軸軼辜逮逵週逸進逶鄂郵鄉郾酣酥量鈔鈕鈣鈉鈞鈍鈐鈇鈑閔閏開閑\"],[\"b6a1\",\"間閒閎隊階隋陽隅隆隍陲隄雁雅雄集雇雯雲韌項順須飧飪飯飩飲飭馮馭黃黍黑亂傭債傲傳僅傾催傷傻傯僇剿剷剽募勦勤勢勣匯嗟嗨嗓嗦嗎嗜嗇嗑嗣嗤嗯嗚嗡嗅嗆嗥嗉園圓塞塑塘塗塚塔填塌塭塊塢塒塋奧嫁嫉嫌媾媽媼\"],[\"b740\",\"媳嫂媲嵩嵯幌幹廉廈弒彙徬微愚意慈感想愛惹愁愈慎慌慄慍愾愴愧愍愆愷戡戢搓搾搞搪搭搽搬搏搜搔損搶搖搗搆敬斟新暗暉暇暈暖暄暘暍會榔業\"],[\"b7a1\",\"楚楷楠楔極椰概楊楨楫楞楓楹榆楝楣楛歇歲毀殿毓毽溢溯滓溶滂源溝滇滅溥溘溼溺溫滑準溜滄滔溪溧溴煎煙煩煤煉照煜煬煦煌煥煞煆煨煖爺牒猷獅猿猾瑯瑚瑕瑟瑞瑁琿瑙瑛瑜當畸瘀痰瘁痲痱痺痿痴痳盞盟睛睫睦睞督\"],[\"b840\",\"睹睪睬睜睥睨睢矮碎碰碗碘碌碉硼碑碓硿祺祿禁萬禽稜稚稠稔稟稞窟窠筷節筠筮筧粱粳粵經絹綑綁綏絛置罩罪署義羨群聖聘肆肄腱腰腸腥腮腳腫\"],[\"b8a1\",\"腹腺腦舅艇蒂葷落萱葵葦葫葉葬葛萼萵葡董葩葭葆虞虜號蛹蜓蜈蜇蜀蛾蛻蜂蜃蜆蜊衙裟裔裙補裘裝裡裊裕裒覜解詫該詳試詩詰誇詼詣誠話誅詭詢詮詬詹詻訾詨豢貊貉賊資賈賄貲賃賂賅跡跟跨路跳跺跪跤跦躲較載軾輊\"],[\"b940\",\"辟農運遊道遂達逼違遐遇遏過遍遑逾遁鄒鄗酬酪酩釉鈷鉗鈸鈽鉀鈾鉛鉋鉤鉑鈴鉉鉍鉅鈹鈿鉚閘隘隔隕雍雋雉雊雷電雹零靖靴靶預頑頓頊頒頌飼飴\"],[\"b9a1\",\"飽飾馳馱馴髡鳩麂鼎鼓鼠僧僮僥僖僭僚僕像僑僱僎僩兢凳劃劂匱厭嗾嘀嘛嘗嗽嘔嘆嘉嘍嘎嗷嘖嘟嘈嘐嗶團圖塵塾境墓墊塹墅塽壽夥夢夤奪奩嫡嫦嫩嫗嫖嫘嫣孵寞寧寡寥實寨寢寤察對屢嶄嶇幛幣幕幗幔廓廖弊彆彰徹慇\"],[\"ba40\",\"愿態慷慢慣慟慚慘慵截撇摘摔撤摸摟摺摑摧搴摭摻敲斡旗旖暢暨暝榜榨榕槁榮槓構榛榷榻榫榴槐槍榭槌榦槃榣歉歌氳漳演滾漓滴漩漾漠漬漏漂漢\"],[\"baa1\",\"滿滯漆漱漸漲漣漕漫漯澈漪滬漁滲滌滷熔熙煽熊熄熒爾犒犖獄獐瑤瑣瑪瑰瑭甄疑瘧瘍瘋瘉瘓盡監瞄睽睿睡磁碟碧碳碩碣禎福禍種稱窪窩竭端管箕箋筵算箝箔箏箸箇箄粹粽精綻綰綜綽綾綠緊綴網綱綺綢綿綵綸維緒緇綬\"],[\"bb40\",\"罰翠翡翟聞聚肇腐膀膏膈膊腿膂臧臺與舔舞艋蓉蒿蓆蓄蒙蒞蒲蒜蓋蒸蓀蓓蒐蒼蓑蓊蜿蜜蜻蜢蜥蜴蜘蝕蜷蜩裳褂裴裹裸製裨褚裯誦誌語誣認誡誓誤\"],[\"bba1\",\"說誥誨誘誑誚誧豪貍貌賓賑賒赫趙趕跼輔輒輕輓辣遠遘遜遣遙遞遢遝遛鄙鄘鄞酵酸酷酴鉸銀銅銘銖鉻銓銜銨鉼銑閡閨閩閣閥閤隙障際雌雒需靼鞅韶頗領颯颱餃餅餌餉駁骯骰髦魁魂鳴鳶鳳麼鼻齊億儀僻僵價儂儈儉儅凜\"],[\"bc40\",\"劇劈劉劍劊勰厲嘮嘻嘹嘲嘿嘴嘩噓噎噗噴嘶嘯嘰墀墟增墳墜墮墩墦奭嬉嫻嬋嫵嬌嬈寮寬審寫層履嶝嶔幢幟幡廢廚廟廝廣廠彈影德徵慶慧慮慝慕憂\"],[\"bca1\",\"慼慰慫慾憧憐憫憎憬憚憤憔憮戮摩摯摹撞撲撈撐撰撥撓撕撩撒撮播撫撚撬撙撢撳敵敷數暮暫暴暱樣樟槨樁樞標槽模樓樊槳樂樅槭樑歐歎殤毅毆漿潼澄潑潦潔澆潭潛潸潮澎潺潰潤澗潘滕潯潠潟熟熬熱熨牖犛獎獗瑩璋璃\"],[\"bd40\",\"瑾璀畿瘠瘩瘟瘤瘦瘡瘢皚皺盤瞎瞇瞌瞑瞋磋磅確磊碾磕碼磐稿稼穀稽稷稻窯窮箭箱範箴篆篇篁箠篌糊締練緯緻緘緬緝編緣線緞緩綞緙緲緹罵罷羯\"],[\"bda1\",\"翩耦膛膜膝膠膚膘蔗蔽蔚蓮蔬蔭蔓蔑蔣蔡蔔蓬蔥蓿蔆螂蝴蝶蝠蝦蝸蝨蝙蝗蝌蝓衛衝褐複褒褓褕褊誼諒談諄誕請諸課諉諂調誰論諍誶誹諛豌豎豬賠賞賦賤賬賭賢賣賜質賡赭趟趣踫踐踝踢踏踩踟踡踞躺輝輛輟輩輦輪輜輞\"],[\"be40\",\"輥適遮遨遭遷鄰鄭鄧鄱醇醉醋醃鋅銻銷鋪銬鋤鋁銳銼鋒鋇鋰銲閭閱霄霆震霉靠鞍鞋鞏頡頫頜颳養餓餒餘駝駐駟駛駑駕駒駙骷髮髯鬧魅魄魷魯鴆鴉\"],[\"bea1\",\"鴃麩麾黎墨齒儒儘儔儐儕冀冪凝劑劓勳噙噫噹噩噤噸噪器噥噱噯噬噢噶壁墾壇壅奮嬝嬴學寰導彊憲憑憩憊懍憶憾懊懈戰擅擁擋撻撼據擄擇擂操撿擒擔撾整曆曉暹曄曇暸樽樸樺橙橫橘樹橄橢橡橋橇樵機橈歙歷氅濂澱澡\"],[\"bf40\",\"濃澤濁澧澳激澹澶澦澠澴熾燉燐燒燈燕熹燎燙燜燃燄獨璜璣璘璟璞瓢甌甍瘴瘸瘺盧盥瞠瞞瞟瞥磨磚磬磧禦積穎穆穌穋窺篙簑築篤篛篡篩篦糕糖縊\"],[\"bfa1\",\"縑縈縛縣縞縝縉縐罹羲翰翱翮耨膳膩膨臻興艘艙蕊蕙蕈蕨蕩蕃蕉蕭蕪蕞螃螟螞螢融衡褪褲褥褫褡親覦諦諺諫諱謀諜諧諮諾謁謂諷諭諳諶諼豫豭貓賴蹄踱踴蹂踹踵輻輯輸輳辨辦遵遴選遲遼遺鄴醒錠錶鋸錳錯錢鋼錫錄錚\"],[\"c040\",\"錐錦錡錕錮錙閻隧隨險雕霎霑霖霍霓霏靛靜靦鞘頰頸頻頷頭頹頤餐館餞餛餡餚駭駢駱骸骼髻髭鬨鮑鴕鴣鴦鴨鴒鴛默黔龍龜優償儡儲勵嚎嚀嚐嚅嚇\"],[\"c0a1\",\"嚏壕壓壑壎嬰嬪嬤孺尷屨嶼嶺嶽嶸幫彌徽應懂懇懦懋戲戴擎擊擘擠擰擦擬擱擢擭斂斃曙曖檀檔檄檢檜櫛檣橾檗檐檠歜殮毚氈濘濱濟濠濛濤濫濯澀濬濡濩濕濮濰燧營燮燦燥燭燬燴燠爵牆獰獲璩環璦璨癆療癌盪瞳瞪瞰瞬\"],[\"c140\",\"瞧瞭矯磷磺磴磯礁禧禪穗窿簇簍篾篷簌篠糠糜糞糢糟糙糝縮績繆縷縲繃縫總縱繅繁縴縹繈縵縿縯罄翳翼聱聲聰聯聳臆臃膺臂臀膿膽臉膾臨舉艱薪\"],[\"c1a1\",\"薄蕾薜薑薔薯薛薇薨薊虧蟀蟑螳蟒蟆螫螻螺蟈蟋褻褶襄褸褽覬謎謗謙講謊謠謝謄謐豁谿豳賺賽購賸賻趨蹉蹋蹈蹊轄輾轂轅輿避遽還邁邂邀鄹醣醞醜鍍鎂錨鍵鍊鍥鍋錘鍾鍬鍛鍰鍚鍔闊闋闌闈闆隱隸雖霜霞鞠韓顆颶餵騁\"],[\"c240\",\"駿鮮鮫鮪鮭鴻鴿麋黏點黜黝黛鼾齋叢嚕嚮壙壘嬸彝懣戳擴擲擾攆擺擻擷斷曜朦檳檬櫃檻檸櫂檮檯歟歸殯瀉瀋濾瀆濺瀑瀏燻燼燾燸獷獵璧璿甕癖癘\"],[\"c2a1\",\"癒瞽瞿瞻瞼礎禮穡穢穠竄竅簫簧簪簞簣簡糧織繕繞繚繡繒繙罈翹翻職聶臍臏舊藏薩藍藐藉薰薺薹薦蟯蟬蟲蟠覆覲觴謨謹謬謫豐贅蹙蹣蹦蹤蹟蹕軀轉轍邇邃邈醫醬釐鎔鎊鎖鎢鎳鎮鎬鎰鎘鎚鎗闔闖闐闕離雜雙雛雞霤鞣鞦\"],[\"c340\",\"鞭韹額顏題顎顓颺餾餿餽餮馥騎髁鬃鬆魏魎魍鯊鯉鯽鯈鯀鵑鵝鵠黠鼕鼬儳嚥壞壟壢寵龐廬懲懷懶懵攀攏曠曝櫥櫝櫚櫓瀛瀟瀨瀚瀝瀕瀘爆爍牘犢獸\"],[\"c3a1\",\"獺璽瓊瓣疇疆癟癡矇礙禱穫穩簾簿簸簽簷籀繫繭繹繩繪羅繳羶羹羸臘藩藝藪藕藤藥藷蟻蠅蠍蟹蟾襠襟襖襞譁譜識證譚譎譏譆譙贈贊蹼蹲躇蹶蹬蹺蹴轔轎辭邊邋醱醮鏡鏑鏟鏃鏈鏜鏝鏖鏢鏍鏘鏤鏗鏨關隴難霪霧靡韜韻類\"],[\"c440\",\"願顛颼饅饉騖騙鬍鯨鯧鯖鯛鶉鵡鵲鵪鵬麒麗麓麴勸嚨嚷嚶嚴嚼壤孀孃孽寶巉懸懺攘攔攙曦朧櫬瀾瀰瀲爐獻瓏癢癥礦礪礬礫竇競籌籃籍糯糰辮繽繼\"],[\"c4a1\",\"纂罌耀臚艦藻藹蘑藺蘆蘋蘇蘊蠔蠕襤覺觸議譬警譯譟譫贏贍躉躁躅躂醴釋鐘鐃鏽闡霰飄饒饑馨騫騰騷騵鰓鰍鹹麵黨鼯齟齣齡儷儸囁囀囂夔屬巍懼懾攝攜斕曩櫻欄櫺殲灌爛犧瓖瓔癩矓籐纏續羼蘗蘭蘚蠣蠢蠡蠟襪襬覽譴\"],[\"c540\",\"護譽贓躊躍躋轟辯醺鐮鐳鐵鐺鐸鐲鐫闢霸霹露響顧顥饗驅驃驀騾髏魔魑鰭鰥鶯鶴鷂鶸麝黯鼙齜齦齧儼儻囈囊囉孿巔巒彎懿攤權歡灑灘玀瓤疊癮癬\"],[\"c5a1\",\"禳籠籟聾聽臟襲襯觼讀贖贗躑躓轡酈鑄鑑鑒霽霾韃韁顫饕驕驍髒鬚鱉鰱鰾鰻鷓鷗鼴齬齪龔囌巖戀攣攫攪曬欐瓚竊籤籣籥纓纖纔臢蘸蘿蠱變邐邏鑣鑠鑤靨顯饜驚驛驗髓體髑鱔鱗鱖鷥麟黴囑壩攬灞癱癲矗罐羈蠶蠹衢讓讒\"],[\"c640\",\"讖艷贛釀鑪靂靈靄韆顰驟鬢魘鱟鷹鷺鹼鹽鼇齷齲廳欖灣籬籮蠻觀躡釁鑲鑰顱饞髖鬣黌灤矚讚鑷韉驢驥纜讜躪釅鑽鑾鑼鱷鱸黷豔鑿鸚爨驪鬱鸛鸞籲\"],[\"c940\",\"乂乜凵匚厂万丌乇亍囗兀屮彳丏冇与丮亓仂仉仈冘勼卬厹圠夃夬尐巿旡殳毌气爿丱丼仨仜仩仡仝仚刌匜卌圢圣夗夯宁宄尒尻屴屳帄庀庂忉戉扐氕\"],[\"c9a1\",\"氶汃氿氻犮犰玊禸肊阞伎优伬仵伔仱伀价伈伝伂伅伢伓伄仴伒冱刓刉刐劦匢匟卍厊吇囡囟圮圪圴夼妀奼妅奻奾奷奿孖尕尥屼屺屻屾巟幵庄异弚彴忕忔忏扜扞扤扡扦扢扙扠扚扥旯旮朾朹朸朻机朿朼朳氘汆汒汜汏汊汔汋\"],[\"ca40\",\"汌灱牞犴犵玎甪癿穵网艸艼芀艽艿虍襾邙邗邘邛邔阢阤阠阣佖伻佢佉体佤伾佧佒佟佁佘伭伳伿佡冏冹刜刞刡劭劮匉卣卲厎厏吰吷吪呔呅吙吜吥吘\"],[\"caa1\",\"吽呏呁吨吤呇囮囧囥坁坅坌坉坋坒夆奀妦妘妠妗妎妢妐妏妧妡宎宒尨尪岍岏岈岋岉岒岊岆岓岕巠帊帎庋庉庌庈庍弅弝彸彶忒忑忐忭忨忮忳忡忤忣忺忯忷忻怀忴戺抃抌抎抏抔抇扱扻扺扰抁抈扷扽扲扴攷旰旴旳旲旵杅杇\"],[\"cb40\",\"杙杕杌杈杝杍杚杋毐氙氚汸汧汫沄沋沏汱汯汩沚汭沇沕沜汦汳汥汻沎灴灺牣犿犽狃狆狁犺狅玕玗玓玔玒町甹疔疕皁礽耴肕肙肐肒肜芐芏芅芎芑芓\"],[\"cba1\",\"芊芃芄豸迉辿邟邡邥邞邧邠阰阨阯阭丳侘佼侅佽侀侇佶佴侉侄佷佌侗佪侚佹侁佸侐侜侔侞侒侂侕佫佮冞冼冾刵刲刳剆刱劼匊匋匼厒厔咇呿咁咑咂咈呫呺呾呥呬呴呦咍呯呡呠咘呣呧呤囷囹坯坲坭坫坱坰坶垀坵坻坳坴坢\"],[\"cc40\",\"坨坽夌奅妵妺姏姎妲姌姁妶妼姃姖妱妽姀姈妴姇孢孥宓宕屄屇岮岤岠岵岯岨岬岟岣岭岢岪岧岝岥岶岰岦帗帔帙弨弢弣弤彔徂彾彽忞忥怭怦怙怲怋\"],[\"cca1\",\"怴怊怗怳怚怞怬怢怍怐怮怓怑怌怉怜戔戽抭抴拑抾抪抶拊抮抳抯抻抩抰抸攽斨斻昉旼昄昒昈旻昃昋昍昅旽昑昐曶朊枅杬枎枒杶杻枘枆构杴枍枌杺枟枑枙枃杽极杸杹枔欥殀歾毞氝沓泬泫泮泙沶泔沭泧沷泐泂沺泃泆泭泲\"],[\"cd40\",\"泒泝沴沊沝沀泞泀洰泍泇沰泹泏泩泑炔炘炅炓炆炄炑炖炂炚炃牪狖狋狘狉狜狒狔狚狌狑玤玡玭玦玢玠玬玝瓝瓨甿畀甾疌疘皯盳盱盰盵矸矼矹矻矺\"],[\"cda1\",\"矷祂礿秅穸穻竻籵糽耵肏肮肣肸肵肭舠芠苀芫芚芘芛芵芧芮芼芞芺芴芨芡芩苂芤苃芶芢虰虯虭虮豖迒迋迓迍迖迕迗邲邴邯邳邰阹阽阼阺陃俍俅俓侲俉俋俁俔俜俙侻侳俛俇俖侺俀侹俬剄剉勀勂匽卼厗厖厙厘咺咡咭咥哏\"],[\"ce40\",\"哃茍咷咮哖咶哅哆咠呰咼咢咾呲哞咰垵垞垟垤垌垗垝垛垔垘垏垙垥垚垕壴复奓姡姞姮娀姱姝姺姽姼姶姤姲姷姛姩姳姵姠姾姴姭宨屌峐峘峌峗峋峛\"],[\"cea1\",\"峞峚峉峇峊峖峓峔峏峈峆峎峟峸巹帡帢帣帠帤庰庤庢庛庣庥弇弮彖徆怷怹恔恲恞恅恓恇恉恛恌恀恂恟怤恄恘恦恮扂扃拏挍挋拵挎挃拫拹挏挌拸拶挀挓挔拺挕拻拰敁敃斪斿昶昡昲昵昜昦昢昳昫昺昝昴昹昮朏朐柁柲柈枺\"],[\"cf40\",\"柜枻柸柘柀枷柅柫柤柟枵柍枳柷柶柮柣柂枹柎柧柰枲柼柆柭柌枮柦柛柺柉柊柃柪柋欨殂殄殶毖毘毠氠氡洨洴洭洟洼洿洒洊泚洳洄洙洺洚洑洀洝浂\"],[\"cfa1\",\"洁洘洷洃洏浀洇洠洬洈洢洉洐炷炟炾炱炰炡炴炵炩牁牉牊牬牰牳牮狊狤狨狫狟狪狦狣玅珌珂珈珅玹玶玵玴珫玿珇玾珃珆玸珋瓬瓮甮畇畈疧疪癹盄眈眃眄眅眊盷盻盺矧矨砆砑砒砅砐砏砎砉砃砓祊祌祋祅祄秕种秏秖秎窀\"],[\"d040\",\"穾竑笀笁籺籸籹籿粀粁紃紈紁罘羑羍羾耇耎耏耔耷胘胇胠胑胈胂胐胅胣胙胜胊胕胉胏胗胦胍臿舡芔苙苾苹茇苨茀苕茺苫苖苴苬苡苲苵茌苻苶苰苪\"],[\"d0a1\",\"苤苠苺苳苭虷虴虼虳衁衎衧衪衩觓訄訇赲迣迡迮迠郱邽邿郕郅邾郇郋郈釔釓陔陏陑陓陊陎倞倅倇倓倢倰倛俵俴倳倷倬俶俷倗倜倠倧倵倯倱倎党冔冓凊凄凅凈凎剡剚剒剞剟剕剢勍匎厞唦哢唗唒哧哳哤唚哿唄唈哫唑唅哱\"],[\"d140\",\"唊哻哷哸哠唎唃唋圁圂埌堲埕埒垺埆垽垼垸垶垿埇埐垹埁夎奊娙娖娭娮娕娏娗娊娞娳孬宧宭宬尃屖屔峬峿峮峱峷崀峹帩帨庨庮庪庬弳弰彧恝恚恧\"],[\"d1a1\",\"恁悢悈悀悒悁悝悃悕悛悗悇悜悎戙扆拲挐捖挬捄捅挶捃揤挹捋捊挼挩捁挴捘捔捙挭捇挳捚捑挸捗捀捈敊敆旆旃旄旂晊晟晇晑朒朓栟栚桉栲栳栻桋桏栖栱栜栵栫栭栯桎桄栴栝栒栔栦栨栮桍栺栥栠欬欯欭欱欴歭肂殈毦毤\"],[\"d240\",\"毨毣毢毧氥浺浣浤浶洍浡涒浘浢浭浯涑涍淯浿涆浞浧浠涗浰浼浟涂涘洯浨涋浾涀涄洖涃浻浽浵涐烜烓烑烝烋缹烢烗烒烞烠烔烍烅烆烇烚烎烡牂牸\"],[\"d2a1\",\"牷牶猀狺狴狾狶狳狻猁珓珙珥珖玼珧珣珩珜珒珛珔珝珚珗珘珨瓞瓟瓴瓵甡畛畟疰痁疻痄痀疿疶疺皊盉眝眛眐眓眒眣眑眕眙眚眢眧砣砬砢砵砯砨砮砫砡砩砳砪砱祔祛祏祜祓祒祑秫秬秠秮秭秪秜秞秝窆窉窅窋窌窊窇竘笐\"],[\"d340\",\"笄笓笅笏笈笊笎笉笒粄粑粊粌粈粍粅紞紝紑紎紘紖紓紟紒紏紌罜罡罞罠罝罛羖羒翃翂翀耖耾耹胺胲胹胵脁胻脀舁舯舥茳茭荄茙荑茥荖茿荁茦茜茢\"],[\"d3a1\",\"荂荎茛茪茈茼荍茖茤茠茷茯茩荇荅荌荓茞茬荋茧荈虓虒蚢蚨蚖蚍蚑蚞蚇蚗蚆蚋蚚蚅蚥蚙蚡蚧蚕蚘蚎蚝蚐蚔衃衄衭衵衶衲袀衱衿衯袃衾衴衼訒豇豗豻貤貣赶赸趵趷趶軑軓迾迵适迿迻逄迼迶郖郠郙郚郣郟郥郘郛郗郜郤酐\"],[\"d440\",\"酎酏釕釢釚陜陟隼飣髟鬯乿偰偪偡偞偠偓偋偝偲偈偍偁偛偊偢倕偅偟偩偫偣偤偆偀偮偳偗偑凐剫剭剬剮勖勓匭厜啵啶唼啍啐唴唪啑啢唶唵唰啒啅\"],[\"d4a1\",\"唌唲啥啎唹啈唭唻啀啋圊圇埻堔埢埶埜埴堀埭埽堈埸堋埳埏堇埮埣埲埥埬埡堎埼堐埧堁堌埱埩埰堍堄奜婠婘婕婧婞娸娵婭婐婟婥婬婓婤婗婃婝婒婄婛婈媎娾婍娹婌婰婩婇婑婖婂婜孲孮寁寀屙崞崋崝崚崠崌崨崍崦崥崏\"],[\"d540\",\"崰崒崣崟崮帾帴庱庴庹庲庳弶弸徛徖徟悊悐悆悾悰悺惓惔惏惤惙惝惈悱惛悷惊悿惃惍惀挲捥掊掂捽掽掞掭掝掗掫掎捯掇掐据掯捵掜捭掮捼掤挻掟\"],[\"d5a1\",\"捸掅掁掑掍捰敓旍晥晡晛晙晜晢朘桹梇梐梜桭桮梮梫楖桯梣梬梩桵桴梲梏桷梒桼桫桲梪梀桱桾梛梖梋梠梉梤桸桻梑梌梊桽欶欳欷欸殑殏殍殎殌氪淀涫涴涳湴涬淩淢涷淶淔渀淈淠淟淖涾淥淜淝淛淴淊涽淭淰涺淕淂淏淉\"],[\"d640\",\"淐淲淓淽淗淍淣涻烺焍烷焗烴焌烰焄烳焐烼烿焆焓焀烸烶焋焂焎牾牻牼牿猝猗猇猑猘猊猈狿猏猞玈珶珸珵琄琁珽琇琀珺珼珿琌琋珴琈畤畣痎痒痏\"],[\"d6a1\",\"痋痌痑痐皏皉盓眹眯眭眱眲眴眳眽眥眻眵硈硒硉硍硊硌砦硅硐祤祧祩祪祣祫祡离秺秸秶秷窏窔窐笵筇笴笥笰笢笤笳笘笪笝笱笫笭笯笲笸笚笣粔粘粖粣紵紽紸紶紺絅紬紩絁絇紾紿絊紻紨罣羕羜羝羛翊翋翍翐翑翇翏翉耟\"],[\"d740\",\"耞耛聇聃聈脘脥脙脛脭脟脬脞脡脕脧脝脢舑舸舳舺舴舲艴莐莣莨莍荺荳莤荴莏莁莕莙荵莔莩荽莃莌莝莛莪莋荾莥莯莈莗莰荿莦莇莮荶莚虙虖蚿蚷\"],[\"d7a1\",\"蛂蛁蛅蚺蚰蛈蚹蚳蚸蛌蚴蚻蚼蛃蚽蚾衒袉袕袨袢袪袚袑袡袟袘袧袙袛袗袤袬袌袓袎覂觖觙觕訰訧訬訞谹谻豜豝豽貥赽赻赹趼跂趹趿跁軘軞軝軜軗軠軡逤逋逑逜逌逡郯郪郰郴郲郳郔郫郬郩酖酘酚酓酕釬釴釱釳釸釤釹釪\"],[\"d840\",\"釫釷釨釮镺閆閈陼陭陫陱陯隿靪頄飥馗傛傕傔傞傋傣傃傌傎傝偨傜傒傂傇兟凔匒匑厤厧喑喨喥喭啷噅喢喓喈喏喵喁喣喒喤啽喌喦啿喕喡喎圌堩堷\"],[\"d8a1\",\"堙堞堧堣堨埵塈堥堜堛堳堿堶堮堹堸堭堬堻奡媯媔媟婺媢媞婸媦婼媥媬媕媮娷媄媊媗媃媋媩婻婽媌媜媏媓媝寪寍寋寔寑寊寎尌尰崷嵃嵫嵁嵋崿崵嵑嵎嵕崳崺嵒崽崱嵙嵂崹嵉崸崼崲崶嵀嵅幄幁彘徦徥徫惉悹惌惢惎惄愔\"],[\"d940\",\"惲愊愖愅惵愓惸惼惾惁愃愘愝愐惿愄愋扊掔掱掰揎揥揨揯揃撝揳揊揠揶揕揲揵摡揟掾揝揜揄揘揓揂揇揌揋揈揰揗揙攲敧敪敤敜敨敥斌斝斞斮旐旒\"],[\"d9a1\",\"晼晬晻暀晱晹晪晲朁椌棓椄棜椪棬棪棱椏棖棷棫棤棶椓椐棳棡椇棌椈楰梴椑棯棆椔棸棐棽棼棨椋椊椗棎棈棝棞棦棴棑椆棔棩椕椥棇欹欻欿欼殔殗殙殕殽毰毲毳氰淼湆湇渟湉溈渼渽湅湢渫渿湁湝湳渜渳湋湀湑渻渃渮湞\"],[\"da40\",\"湨湜湡渱渨湠湱湫渹渢渰湓湥渧湸湤湷湕湹湒湦渵渶湚焠焞焯烻焮焱焣焥焢焲焟焨焺焛牋牚犈犉犆犅犋猒猋猰猢猱猳猧猲猭猦猣猵猌琮琬琰琫琖\"],[\"daa1\",\"琚琡琭琱琤琣琝琩琠琲瓻甯畯畬痧痚痡痦痝痟痤痗皕皒盚睆睇睄睍睅睊睎睋睌矞矬硠硤硥硜硭硱硪确硰硩硨硞硢祴祳祲祰稂稊稃稌稄窙竦竤筊笻筄筈筌筎筀筘筅粢粞粨粡絘絯絣絓絖絧絪絏絭絜絫絒絔絩絑絟絎缾缿罥\"],[\"db40\",\"罦羢羠羡翗聑聏聐胾胔腃腊腒腏腇脽腍脺臦臮臷臸臹舄舼舽舿艵茻菏菹萣菀菨萒菧菤菼菶萐菆菈菫菣莿萁菝菥菘菿菡菋菎菖菵菉萉萏菞萑萆菂菳\"],[\"dba1\",\"菕菺菇菑菪萓菃菬菮菄菻菗菢萛菛菾蛘蛢蛦蛓蛣蛚蛪蛝蛫蛜蛬蛩蛗蛨蛑衈衖衕袺裗袹袸裀袾袶袼袷袽袲褁裉覕覘覗觝觚觛詎詍訹詙詀詗詘詄詅詒詈詑詊詌詏豟貁貀貺貾貰貹貵趄趀趉跘跓跍跇跖跜跏跕跙跈跗跅軯軷軺\"],[\"dc40\",\"軹軦軮軥軵軧軨軶軫軱軬軴軩逭逴逯鄆鄬鄄郿郼鄈郹郻鄁鄀鄇鄅鄃酡酤酟酢酠鈁鈊鈥鈃鈚鈦鈏鈌鈀鈒釿釽鈆鈄鈧鈂鈜鈤鈙鈗鈅鈖镻閍閌閐隇陾隈\"],[\"dca1\",\"隉隃隀雂雈雃雱雰靬靰靮頇颩飫鳦黹亃亄亶傽傿僆傮僄僊傴僈僂傰僁傺傱僋僉傶傸凗剺剸剻剼嗃嗛嗌嗐嗋嗊嗝嗀嗔嗄嗩喿嗒喍嗏嗕嗢嗖嗈嗲嗍嗙嗂圔塓塨塤塏塍塉塯塕塎塝塙塥塛堽塣塱壼嫇嫄嫋媺媸媱媵媰媿嫈媻嫆\"],[\"dd40\",\"媷嫀嫊媴媶嫍媹媐寖寘寙尟尳嵱嵣嵊嵥嵲嵬嵞嵨嵧嵢巰幏幎幊幍幋廅廌廆廋廇彀徯徭惷慉慊愫慅愶愲愮慆愯慏愩慀戠酨戣戥戤揅揱揫搐搒搉搠搤\"],[\"dda1\",\"搳摃搟搕搘搹搷搢搣搌搦搰搨摁搵搯搊搚摀搥搧搋揧搛搮搡搎敯斒旓暆暌暕暐暋暊暙暔晸朠楦楟椸楎楢楱椿楅楪椹楂楗楙楺楈楉椵楬椳椽楥棰楸椴楩楀楯楄楶楘楁楴楌椻楋椷楜楏楑椲楒椯楻椼歆歅歃歂歈歁殛嗀毻毼\"],[\"de40\",\"毹毷毸溛滖滈溏滀溟溓溔溠溱溹滆滒溽滁溞滉溷溰滍溦滏溲溾滃滜滘溙溒溎溍溤溡溿溳滐滊溗溮溣煇煔煒煣煠煁煝煢煲煸煪煡煂煘煃煋煰煟煐煓\"],[\"dea1\",\"煄煍煚牏犍犌犑犐犎猼獂猻猺獀獊獉瑄瑊瑋瑒瑑瑗瑀瑏瑐瑎瑂瑆瑍瑔瓡瓿瓾瓽甝畹畷榃痯瘏瘃痷痾痼痹痸瘐痻痶痭痵痽皙皵盝睕睟睠睒睖睚睩睧睔睙睭矠碇碚碔碏碄碕碅碆碡碃硹碙碀碖硻祼禂祽祹稑稘稙稒稗稕稢稓\"],[\"df40\",\"稛稐窣窢窞竫筦筤筭筴筩筲筥筳筱筰筡筸筶筣粲粴粯綈綆綀綍絿綅絺綎絻綃絼綌綔綄絽綒罭罫罧罨罬羦羥羧翛翜耡腤腠腷腜腩腛腢腲朡腞腶腧腯\"],[\"dfa1\",\"腄腡舝艉艄艀艂艅蓱萿葖葶葹蒏蒍葥葑葀蒆葧萰葍葽葚葙葴葳葝蔇葞萷萺萴葺葃葸萲葅萩菙葋萯葂萭葟葰萹葎葌葒葯蓅蒎萻葇萶萳葨葾葄萫葠葔葮葐蜋蜄蛷蜌蛺蛖蛵蝍蛸蜎蜉蜁蛶蜍蜅裖裋裍裎裞裛裚裌裐覅覛觟觥觤\"],[\"e040\",\"觡觠觢觜触詶誆詿詡訿詷誂誄詵誃誁詴詺谼豋豊豥豤豦貆貄貅賌赨赩趑趌趎趏趍趓趔趐趒跰跠跬跱跮跐跩跣跢跧跲跫跴輆軿輁輀輅輇輈輂輋遒逿\"],[\"e0a1\",\"遄遉逽鄐鄍鄏鄑鄖鄔鄋鄎酮酯鉈鉒鈰鈺鉦鈳鉥鉞銃鈮鉊鉆鉭鉬鉏鉠鉧鉯鈶鉡鉰鈱鉔鉣鉐鉲鉎鉓鉌鉖鈲閟閜閞閛隒隓隑隗雎雺雽雸雵靳靷靸靲頏頍頎颬飶飹馯馲馰馵骭骫魛鳪鳭鳧麀黽僦僔僗僨僳僛僪僝僤僓僬僰僯僣僠\"],[\"e140\",\"凘劀劁勩勫匰厬嘧嘕嘌嘒嗼嘏嘜嘁嘓嘂嗺嘝嘄嗿嗹墉塼墐墘墆墁塿塴墋塺墇墑墎塶墂墈塻墔墏壾奫嫜嫮嫥嫕嫪嫚嫭嫫嫳嫢嫠嫛嫬嫞嫝嫙嫨嫟孷寠\"],[\"e1a1\",\"寣屣嶂嶀嵽嶆嵺嶁嵷嶊嶉嶈嵾嵼嶍嵹嵿幘幙幓廘廑廗廎廜廕廙廒廔彄彃彯徶愬愨慁慞慱慳慒慓慲慬憀慴慔慺慛慥愻慪慡慖戩戧戫搫摍摛摝摴摶摲摳摽摵摦撦摎撂摞摜摋摓摠摐摿搿摬摫摙摥摷敳斠暡暠暟朅朄朢榱榶槉\"],[\"e240\",\"榠槎榖榰榬榼榑榙榎榧榍榩榾榯榿槄榽榤槔榹槊榚槏榳榓榪榡榞槙榗榐槂榵榥槆歊歍歋殞殟殠毃毄毾滎滵滱漃漥滸漷滻漮漉潎漙漚漧漘漻漒滭漊\"],[\"e2a1\",\"漶潳滹滮漭潀漰漼漵滫漇漎潃漅滽滶漹漜滼漺漟漍漞漈漡熇熐熉熀熅熂熏煻熆熁熗牄牓犗犕犓獃獍獑獌瑢瑳瑱瑵瑲瑧瑮甀甂甃畽疐瘖瘈瘌瘕瘑瘊瘔皸瞁睼瞅瞂睮瞀睯睾瞃碲碪碴碭碨硾碫碞碥碠碬碢碤禘禊禋禖禕禔禓\"],[\"e340\",\"禗禈禒禐稫穊稰稯稨稦窨窫窬竮箈箜箊箑箐箖箍箌箛箎箅箘劄箙箤箂粻粿粼粺綧綷緂綣綪緁緀緅綝緎緄緆緋緌綯綹綖綼綟綦綮綩綡緉罳翢翣翥翞\"],[\"e3a1\",\"耤聝聜膉膆膃膇膍膌膋舕蒗蒤蒡蒟蒺蓎蓂蒬蒮蒫蒹蒴蓁蓍蒪蒚蒱蓐蒝蒧蒻蒢蒔蓇蓌蒛蒩蒯蒨蓖蒘蒶蓏蒠蓗蓔蓒蓛蒰蒑虡蜳蜣蜨蝫蝀蜮蜞蜡蜙蜛蝃蜬蝁蜾蝆蜠蜲蜪蜭蜼蜒蜺蜱蜵蝂蜦蜧蜸蜤蜚蜰蜑裷裧裱裲裺裾裮裼裶裻\"],[\"e440\",\"裰裬裫覝覡覟覞觩觫觨誫誙誋誒誏誖谽豨豩賕賏賗趖踉踂跿踍跽踊踃踇踆踅跾踀踄輐輑輎輍鄣鄜鄠鄢鄟鄝鄚鄤鄡鄛酺酲酹酳銥銤鉶銛鉺銠銔銪銍\"],[\"e4a1\",\"銦銚銫鉹銗鉿銣鋮銎銂銕銢鉽銈銡銊銆銌銙銧鉾銇銩銝銋鈭隞隡雿靘靽靺靾鞃鞀鞂靻鞄鞁靿韎韍頖颭颮餂餀餇馝馜駃馹馻馺駂馽駇骱髣髧鬾鬿魠魡魟鳱鳲鳵麧僿儃儰僸儆儇僶僾儋儌僽儊劋劌勱勯噈噂噌嘵噁噊噉噆噘\"],[\"e540\",\"噚噀嘳嘽嘬嘾嘸嘪嘺圚墫墝墱墠墣墯墬墥墡壿嫿嫴嫽嫷嫶嬃嫸嬂嫹嬁嬇嬅嬏屧嶙嶗嶟嶒嶢嶓嶕嶠嶜嶡嶚嶞幩幝幠幜緳廛廞廡彉徲憋憃慹憱憰憢憉\"],[\"e5a1\",\"憛憓憯憭憟憒憪憡憍慦憳戭摮摰撖撠撅撗撜撏撋撊撌撣撟摨撱撘敶敺敹敻斲斳暵暰暩暲暷暪暯樀樆樗槥槸樕槱槤樠槿槬槢樛樝槾樧槲槮樔槷槧橀樈槦槻樍槼槫樉樄樘樥樏槶樦樇槴樖歑殥殣殢殦氁氀毿氂潁漦潾澇濆澒\"],[\"e640\",\"澍澉澌潢潏澅潚澖潶潬澂潕潲潒潐潗澔澓潝漀潡潫潽潧澐潓澋潩潿澕潣潷潪潻熲熯熛熰熠熚熩熵熝熥熞熤熡熪熜熧熳犘犚獘獒獞獟獠獝獛獡獚獙\"],[\"e6a1\",\"獢璇璉璊璆璁瑽璅璈瑼瑹甈甇畾瘥瘞瘙瘝瘜瘣瘚瘨瘛皜皝皞皛瞍瞏瞉瞈磍碻磏磌磑磎磔磈磃磄磉禚禡禠禜禢禛歶稹窲窴窳箷篋箾箬篎箯箹篊箵糅糈糌糋緷緛緪緧緗緡縃緺緦緶緱緰緮緟罶羬羰羭翭翫翪翬翦翨聤聧膣膟\"],[\"e740\",\"膞膕膢膙膗舖艏艓艒艐艎艑蔤蔻蔏蔀蔩蔎蔉蔍蔟蔊蔧蔜蓻蔫蓺蔈蔌蓴蔪蓲蔕蓷蓫蓳蓼蔒蓪蓩蔖蓾蔨蔝蔮蔂蓽蔞蓶蔱蔦蓧蓨蓰蓯蓹蔘蔠蔰蔋蔙蔯虢\"],[\"e7a1\",\"蝖蝣蝤蝷蟡蝳蝘蝔蝛蝒蝡蝚蝑蝞蝭蝪蝐蝎蝟蝝蝯蝬蝺蝮蝜蝥蝏蝻蝵蝢蝧蝩衚褅褌褔褋褗褘褙褆褖褑褎褉覢覤覣觭觰觬諏諆誸諓諑諔諕誻諗誾諀諅諘諃誺誽諙谾豍貏賥賟賙賨賚賝賧趠趜趡趛踠踣踥踤踮踕踛踖踑踙踦踧\"],[\"e840\",\"踔踒踘踓踜踗踚輬輤輘輚輠輣輖輗遳遰遯遧遫鄯鄫鄩鄪鄲鄦鄮醅醆醊醁醂醄醀鋐鋃鋄鋀鋙銶鋏鋱鋟鋘鋩鋗鋝鋌鋯鋂鋨鋊鋈鋎鋦鋍鋕鋉鋠鋞鋧鋑鋓\"],[\"e8a1\",\"銵鋡鋆銴镼閬閫閮閰隤隢雓霅霈霂靚鞊鞎鞈韐韏頞頝頦頩頨頠頛頧颲餈飺餑餔餖餗餕駜駍駏駓駔駎駉駖駘駋駗駌骳髬髫髳髲髱魆魃魧魴魱魦魶魵魰魨魤魬鳼鳺鳽鳿鳷鴇鴀鳹鳻鴈鴅鴄麃黓鼏鼐儜儓儗儚儑凞匴叡噰噠噮\"],[\"e940\",\"噳噦噣噭噲噞噷圜圛壈墽壉墿墺壂墼壆嬗嬙嬛嬡嬔嬓嬐嬖嬨嬚嬠嬞寯嶬嶱嶩嶧嶵嶰嶮嶪嶨嶲嶭嶯嶴幧幨幦幯廩廧廦廨廥彋徼憝憨憖懅憴懆懁懌憺\"],[\"e9a1\",\"憿憸憌擗擖擐擏擉撽撉擃擛擳擙攳敿敼斢曈暾曀曊曋曏暽暻暺曌朣樴橦橉橧樲橨樾橝橭橶橛橑樨橚樻樿橁橪橤橐橏橔橯橩橠樼橞橖橕橍橎橆歕歔歖殧殪殫毈毇氄氃氆澭濋澣濇澼濎濈潞濄澽澞濊澨瀄澥澮澺澬澪濏澿澸\"],[\"ea40\",\"澢濉澫濍澯澲澰燅燂熿熸燖燀燁燋燔燊燇燏熽燘熼燆燚燛犝犞獩獦獧獬獥獫獪瑿璚璠璔璒璕璡甋疀瘯瘭瘱瘽瘳瘼瘵瘲瘰皻盦瞚瞝瞡瞜瞛瞢瞣瞕瞙\"],[\"eaa1\",\"瞗磝磩磥磪磞磣磛磡磢磭磟磠禤穄穈穇窶窸窵窱窷篞篣篧篝篕篥篚篨篹篔篪篢篜篫篘篟糒糔糗糐糑縒縡縗縌縟縠縓縎縜縕縚縢縋縏縖縍縔縥縤罃罻罼罺羱翯耪耩聬膱膦膮膹膵膫膰膬膴膲膷膧臲艕艖艗蕖蕅蕫蕍蕓蕡蕘\"],[\"eb40\",\"蕀蕆蕤蕁蕢蕄蕑蕇蕣蔾蕛蕱蕎蕮蕵蕕蕧蕠薌蕦蕝蕔蕥蕬虣虥虤螛螏螗螓螒螈螁螖螘蝹螇螣螅螐螑螝螄螔螜螚螉褞褦褰褭褮褧褱褢褩褣褯褬褟觱諠\"],[\"eba1\",\"諢諲諴諵諝謔諤諟諰諈諞諡諨諿諯諻貑貒貐賵賮賱賰賳赬赮趥趧踳踾踸蹀蹅踶踼踽蹁踰踿躽輶輮輵輲輹輷輴遶遹遻邆郺鄳鄵鄶醓醐醑醍醏錧錞錈錟錆錏鍺錸錼錛錣錒錁鍆錭錎錍鋋錝鋺錥錓鋹鋷錴錂錤鋿錩錹錵錪錔錌\"],[\"ec40\",\"錋鋾錉錀鋻錖閼闍閾閹閺閶閿閵閽隩雔霋霒霐鞙鞗鞔韰韸頵頯頲餤餟餧餩馞駮駬駥駤駰駣駪駩駧骹骿骴骻髶髺髹髷鬳鮀鮅鮇魼魾魻鮂鮓鮒鮐魺鮕\"],[\"eca1\",\"魽鮈鴥鴗鴠鴞鴔鴩鴝鴘鴢鴐鴙鴟麈麆麇麮麭黕黖黺鼒鼽儦儥儢儤儠儩勴嚓嚌嚍嚆嚄嚃噾嚂噿嚁壖壔壏壒嬭嬥嬲嬣嬬嬧嬦嬯嬮孻寱寲嶷幬幪徾徻懃憵憼懧懠懥懤懨懞擯擩擣擫擤擨斁斀斶旚曒檍檖檁檥檉檟檛檡檞檇檓檎\"],[\"ed40\",\"檕檃檨檤檑橿檦檚檅檌檒歛殭氉濌澩濴濔濣濜濭濧濦濞濲濝濢濨燡燱燨燲燤燰燢獳獮獯璗璲璫璐璪璭璱璥璯甐甑甒甏疄癃癈癉癇皤盩瞵瞫瞲瞷瞶\"],[\"eda1\",\"瞴瞱瞨矰磳磽礂磻磼磲礅磹磾礄禫禨穜穛穖穘穔穚窾竀竁簅簏篲簀篿篻簎篴簋篳簂簉簃簁篸篽簆篰篱簐簊糨縭縼繂縳顈縸縪繉繀繇縩繌縰縻縶繄縺罅罿罾罽翴翲耬膻臄臌臊臅臇膼臩艛艚艜薃薀薏薧薕薠薋薣蕻薤薚薞\"],[\"ee40\",\"蕷蕼薉薡蕺蕸蕗薎薖薆薍薙薝薁薢薂薈薅蕹蕶薘薐薟虨螾螪螭蟅螰螬螹螵螼螮蟉蟃蟂蟌螷螯蟄蟊螴螶螿螸螽蟞螲褵褳褼褾襁襒褷襂覭覯覮觲觳謞\"],[\"eea1\",\"謘謖謑謅謋謢謏謒謕謇謍謈謆謜謓謚豏豰豲豱豯貕貔賹赯蹎蹍蹓蹐蹌蹇轃轀邅遾鄸醚醢醛醙醟醡醝醠鎡鎃鎯鍤鍖鍇鍼鍘鍜鍶鍉鍐鍑鍠鍭鎏鍌鍪鍹鍗鍕鍒鍏鍱鍷鍻鍡鍞鍣鍧鎀鍎鍙闇闀闉闃闅閷隮隰隬霠霟霘霝霙鞚鞡鞜\"],[\"ef40\",\"鞞鞝韕韔韱顁顄顊顉顅顃餥餫餬餪餳餲餯餭餱餰馘馣馡騂駺駴駷駹駸駶駻駽駾駼騃骾髾髽鬁髼魈鮚鮨鮞鮛鮦鮡鮥鮤鮆鮢鮠鮯鴳鵁鵧鴶鴮鴯鴱鴸鴰\"],[\"efa1\",\"鵅鵂鵃鴾鴷鵀鴽翵鴭麊麉麍麰黈黚黻黿鼤鼣鼢齔龠儱儭儮嚘嚜嚗嚚嚝嚙奰嬼屩屪巀幭幮懘懟懭懮懱懪懰懫懖懩擿攄擽擸攁攃擼斔旛曚曛曘櫅檹檽櫡櫆檺檶檷櫇檴檭歞毉氋瀇瀌瀍瀁瀅瀔瀎濿瀀濻瀦濼濷瀊爁燿燹爃燽獶\"],[\"f040\",\"璸瓀璵瓁璾璶璻瓂甔甓癜癤癙癐癓癗癚皦皽盬矂瞺磿礌礓礔礉礐礒礑禭禬穟簜簩簙簠簟簭簝簦簨簢簥簰繜繐繖繣繘繢繟繑繠繗繓羵羳翷翸聵臑臒\"],[\"f0a1\",\"臐艟艞薴藆藀藃藂薳薵薽藇藄薿藋藎藈藅薱薶藒蘤薸薷薾虩蟧蟦蟢蟛蟫蟪蟥蟟蟳蟤蟔蟜蟓蟭蟘蟣螤蟗蟙蠁蟴蟨蟝襓襋襏襌襆襐襑襉謪謧謣謳謰謵譇謯謼謾謱謥謷謦謶謮謤謻謽謺豂豵貙貘貗賾贄贂贀蹜蹢蹠蹗蹖蹞蹥蹧\"],[\"f140\",\"蹛蹚蹡蹝蹩蹔轆轇轈轋鄨鄺鄻鄾醨醥醧醯醪鎵鎌鎒鎷鎛鎝鎉鎧鎎鎪鎞鎦鎕鎈鎙鎟鎍鎱鎑鎲鎤鎨鎴鎣鎥闒闓闑隳雗雚巂雟雘雝霣霢霥鞬鞮鞨鞫鞤鞪\"],[\"f1a1\",\"鞢鞥韗韙韖韘韺顐顑顒颸饁餼餺騏騋騉騍騄騑騊騅騇騆髀髜鬈鬄鬅鬩鬵魊魌魋鯇鯆鯃鮿鯁鮵鮸鯓鮶鯄鮹鮽鵜鵓鵏鵊鵛鵋鵙鵖鵌鵗鵒鵔鵟鵘鵚麎麌黟鼁鼀鼖鼥鼫鼪鼩鼨齌齕儴儵劖勷厴嚫嚭嚦嚧嚪嚬壚壝壛夒嬽嬾嬿巃幰\"],[\"f240\",\"徿懻攇攐攍攉攌攎斄旞旝曞櫧櫠櫌櫑櫙櫋櫟櫜櫐櫫櫏櫍櫞歠殰氌瀙瀧瀠瀖瀫瀡瀢瀣瀩瀗瀤瀜瀪爌爊爇爂爅犥犦犤犣犡瓋瓅璷瓃甖癠矉矊矄矱礝礛\"],[\"f2a1\",\"礡礜礗礞禰穧穨簳簼簹簬簻糬糪繶繵繸繰繷繯繺繲繴繨罋罊羃羆羷翽翾聸臗臕艤艡艣藫藱藭藙藡藨藚藗藬藲藸藘藟藣藜藑藰藦藯藞藢蠀蟺蠃蟶蟷蠉蠌蠋蠆蟼蠈蟿蠊蠂襢襚襛襗襡襜襘襝襙覈覷覶觶譐譈譊譀譓譖譔譋譕\"],[\"f340\",\"譑譂譒譗豃豷豶貚贆贇贉趬趪趭趫蹭蹸蹳蹪蹯蹻軂轒轑轏轐轓辴酀鄿醰醭鏞鏇鏏鏂鏚鏐鏹鏬鏌鏙鎩鏦鏊鏔鏮鏣鏕鏄鏎鏀鏒鏧镽闚闛雡霩霫霬霨霦\"],[\"f3a1\",\"鞳鞷鞶韝韞韟顜顙顝顗颿颽颻颾饈饇饃馦馧騚騕騥騝騤騛騢騠騧騣騞騜騔髂鬋鬊鬎鬌鬷鯪鯫鯠鯞鯤鯦鯢鯰鯔鯗鯬鯜鯙鯥鯕鯡鯚鵷鶁鶊鶄鶈鵱鶀鵸鶆鶋鶌鵽鵫鵴鵵鵰鵩鶅鵳鵻鶂鵯鵹鵿鶇鵨麔麑黀黼鼭齀齁齍齖齗齘匷嚲\"],[\"f440\",\"嚵嚳壣孅巆巇廮廯忀忁懹攗攖攕攓旟曨曣曤櫳櫰櫪櫨櫹櫱櫮櫯瀼瀵瀯瀷瀴瀱灂瀸瀿瀺瀹灀瀻瀳灁爓爔犨獽獼璺皫皪皾盭矌矎矏矍矲礥礣礧礨礤礩\"],[\"f4a1\",\"禲穮穬穭竷籉籈籊籇籅糮繻繾纁纀羺翿聹臛臙舋艨艩蘢藿蘁藾蘛蘀藶蘄蘉蘅蘌藽蠙蠐蠑蠗蠓蠖襣襦覹觷譠譪譝譨譣譥譧譭趮躆躈躄轙轖轗轕轘轚邍酃酁醷醵醲醳鐋鐓鏻鐠鐏鐔鏾鐕鐐鐨鐙鐍鏵鐀鏷鐇鐎鐖鐒鏺鐉鏸鐊鏿\"],[\"f540\",\"鏼鐌鏶鐑鐆闞闠闟霮霯鞹鞻韽韾顠顢顣顟飁飂饐饎饙饌饋饓騲騴騱騬騪騶騩騮騸騭髇髊髆鬐鬒鬑鰋鰈鯷鰅鰒鯸鱀鰇鰎鰆鰗鰔鰉鶟鶙鶤鶝鶒鶘鶐鶛\"],[\"f5a1\",\"鶠鶔鶜鶪鶗鶡鶚鶢鶨鶞鶣鶿鶩鶖鶦鶧麙麛麚黥黤黧黦鼰鼮齛齠齞齝齙龑儺儹劘劗囃嚽嚾孈孇巋巏廱懽攛欂櫼欃櫸欀灃灄灊灈灉灅灆爝爚爙獾甗癪矐礭礱礯籔籓糲纊纇纈纋纆纍罍羻耰臝蘘蘪蘦蘟蘣蘜蘙蘧蘮蘡蘠蘩蘞蘥\"],[\"f640\",\"蠩蠝蠛蠠蠤蠜蠫衊襭襩襮襫觺譹譸譅譺譻贐贔趯躎躌轞轛轝酆酄酅醹鐿鐻鐶鐩鐽鐼鐰鐹鐪鐷鐬鑀鐱闥闤闣霵霺鞿韡顤飉飆飀饘饖騹騽驆驄驂驁騺\"],[\"f6a1\",\"騿髍鬕鬗鬘鬖鬺魒鰫鰝鰜鰬鰣鰨鰩鰤鰡鶷鶶鶼鷁鷇鷊鷏鶾鷅鷃鶻鶵鷎鶹鶺鶬鷈鶱鶭鷌鶳鷍鶲鹺麜黫黮黭鼛鼘鼚鼱齎齥齤龒亹囆囅囋奱孋孌巕巑廲攡攠攦攢欋欈欉氍灕灖灗灒爞爟犩獿瓘瓕瓙瓗癭皭礵禴穰穱籗籜籙籛籚\"],[\"f740\",\"糴糱纑罏羇臞艫蘴蘵蘳蘬蘲蘶蠬蠨蠦蠪蠥襱覿覾觻譾讄讂讆讅譿贕躕躔躚躒躐躖躗轠轢酇鑌鑐鑊鑋鑏鑇鑅鑈鑉鑆霿韣顪顩飋饔饛驎驓驔驌驏驈驊\"],[\"f7a1\",\"驉驒驐髐鬙鬫鬻魖魕鱆鱈鰿鱄鰹鰳鱁鰼鰷鰴鰲鰽鰶鷛鷒鷞鷚鷋鷐鷜鷑鷟鷩鷙鷘鷖鷵鷕鷝麶黰鼵鼳鼲齂齫龕龢儽劙壨壧奲孍巘蠯彏戁戃戄攩攥斖曫欑欒欏毊灛灚爢玂玁玃癰矔籧籦纕艬蘺虀蘹蘼蘱蘻蘾蠰蠲蠮蠳襶襴襳觾\"],[\"f840\",\"讌讎讋讈豅贙躘轤轣醼鑢鑕鑝鑗鑞韄韅頀驖驙鬞鬟鬠鱒鱘鱐鱊鱍鱋鱕鱙鱌鱎鷻鷷鷯鷣鷫鷸鷤鷶鷡鷮鷦鷲鷰鷢鷬鷴鷳鷨鷭黂黐黲黳鼆鼜鼸鼷鼶齃齏\"],[\"f8a1\",\"齱齰齮齯囓囍孎屭攭曭曮欓灟灡灝灠爣瓛瓥矕礸禷禶籪纗羉艭虃蠸蠷蠵衋讔讕躞躟躠躝醾醽釂鑫鑨鑩雥靆靃靇韇韥驞髕魙鱣鱧鱦鱢鱞鱠鸂鷾鸇鸃鸆鸅鸀鸁鸉鷿鷽鸄麠鼞齆齴齵齶囔攮斸欘欙欗欚灢爦犪矘矙礹籩籫糶纚\"],[\"f940\",\"纘纛纙臠臡虆虇虈襹襺襼襻觿讘讙躥躤躣鑮鑭鑯鑱鑳靉顲饟鱨鱮鱭鸋鸍鸐鸏鸒鸑麡黵鼉齇齸齻齺齹圞灦籯蠼趲躦釃鑴鑸鑶鑵驠鱴鱳鱱鱵鸔鸓黶鼊\"],[\"f9a1\",\"龤灨灥糷虪蠾蠽蠿讞貜躩軉靋顳顴飌饡馫驤驦驧鬤鸕鸗齈戇欞爧虌躨钂钀钁驩驨鬮鸙爩虋讟钃鱹麷癵驫鱺鸝灩灪麤齾齉龘碁銹裏墻恒粧嫺╔╦╗╠╬╣╚╩╝╒╤╕╞╪╡╘╧╛╓╥╖╟╫╢╙╨╜║═╭╮╰╯▓\"]]\n\n/***/ }),\n/* 93 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var ArrayT, NumberT, utils;\n\n  NumberT = __webpack_require__(22).Number;\n\n  utils = __webpack_require__(12);\n\n  ArrayT = (function() {\n    function ArrayT(type, length, lengthType) {\n      this.type = type;\n      this.length = length;\n      this.lengthType = lengthType != null ? lengthType : 'count';\n    }\n\n    ArrayT.prototype.decode = function(stream, parent) {\n      var ctx, i, length, pos, res, target, _i;\n      pos = stream.pos;\n      res = [];\n      ctx = parent;\n      if (this.length != null) {\n        length = utils.resolveLength(this.length, stream, parent);\n      }\n      if (this.length instanceof NumberT) {\n        Object.defineProperties(res, {\n          parent: {\n            value: parent\n          },\n          _startOffset: {\n            value: pos\n          },\n          _currentOffset: {\n            value: 0,\n            writable: true\n          },\n          _length: {\n            value: length\n          }\n        });\n        ctx = res;\n      }\n      if ((length == null) || this.lengthType === 'bytes') {\n        target = length != null ? stream.pos + length : (parent != null ? parent._length : void 0) ? parent._startOffset + parent._length : stream.length;\n        while (stream.pos < target) {\n          res.push(this.type.decode(stream, ctx));\n        }\n      } else {\n        for (i = _i = 0; _i < length; i = _i += 1) {\n          res.push(this.type.decode(stream, ctx));\n        }\n      }\n      return res;\n    };\n\n    ArrayT.prototype.size = function(array, ctx) {\n      var item, size, _i, _len;\n      if (!array) {\n        return this.type.size(null, ctx) * utils.resolveLength(this.length, null, ctx);\n      }\n      size = 0;\n      if (this.length instanceof NumberT) {\n        size += this.length.size();\n        ctx = {\n          parent: ctx\n        };\n      }\n      for (_i = 0, _len = array.length; _i < _len; _i++) {\n        item = array[_i];\n        size += this.type.size(item, ctx);\n      }\n      return size;\n    };\n\n    ArrayT.prototype.encode = function(stream, array, parent) {\n      var ctx, i, item, ptr, _i, _len;\n      ctx = parent;\n      if (this.length instanceof NumberT) {\n        ctx = {\n          pointers: [],\n          startOffset: stream.pos,\n          parent: parent\n        };\n        ctx.pointerOffset = stream.pos + this.size(array, ctx);\n        this.length.encode(stream, array.length);\n      }\n      for (_i = 0, _len = array.length; _i < _len; _i++) {\n        item = array[_i];\n        this.type.encode(stream, item, ctx);\n      }\n      if (this.length instanceof NumberT) {\n        i = 0;\n        while (i < ctx.pointers.length) {\n          ptr = ctx.pointers[i++];\n          ptr.type.encode(stream, ptr.val);\n        }\n      }\n    };\n\n    return ArrayT;\n\n  })();\n\n  module.exports = ArrayT;\n\n}).call(this);\n\n\n/***/ }),\n/* 94 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var Struct, utils;\n\n  utils = __webpack_require__(12);\n\n  Struct = (function() {\n    function Struct(fields) {\n      this.fields = fields != null ? fields : {};\n    }\n\n    Struct.prototype.decode = function(stream, parent, length) {\n      var res, _ref;\n      if (length == null) {\n        length = 0;\n      }\n      res = this._setup(stream, parent, length);\n      this._parseFields(stream, res, this.fields);\n      if ((_ref = this.process) != null) {\n        _ref.call(res, stream);\n      }\n      return res;\n    };\n\n    Struct.prototype._setup = function(stream, parent, length) {\n      var res;\n      res = {};\n      Object.defineProperties(res, {\n        parent: {\n          value: parent\n        },\n        _startOffset: {\n          value: stream.pos\n        },\n        _currentOffset: {\n          value: 0,\n          writable: true\n        },\n        _length: {\n          value: length\n        }\n      });\n      return res;\n    };\n\n    Struct.prototype._parseFields = function(stream, res, fields) {\n      var key, type, val;\n      for (key in fields) {\n        type = fields[key];\n        if (typeof type === 'function') {\n          val = type.call(res, res);\n        } else {\n          val = type.decode(stream, res);\n        }\n        if (val !== void 0) {\n          if (val instanceof utils.PropertyDescriptor) {\n            Object.defineProperty(res, key, val);\n          } else {\n            res[key] = val;\n          }\n        }\n        res._currentOffset = stream.pos - res._startOffset;\n      }\n    };\n\n    Struct.prototype.size = function(val, parent, includePointers) {\n      var ctx, key, size, type, _ref;\n      if (val == null) {\n        val = {};\n      }\n      if (includePointers == null) {\n        includePointers = true;\n      }\n      ctx = {\n        parent: parent,\n        val: val,\n        pointerSize: 0\n      };\n      size = 0;\n      _ref = this.fields;\n      for (key in _ref) {\n        type = _ref[key];\n        if (type.size != null) {\n          size += type.size(val[key], ctx);\n        }\n      }\n      if (includePointers) {\n        size += ctx.pointerSize;\n      }\n      return size;\n    };\n\n    Struct.prototype.encode = function(stream, val, parent) {\n      var ctx, i, key, ptr, type, _ref, _ref1;\n      if ((_ref = this.preEncode) != null) {\n        _ref.call(val, stream);\n      }\n      ctx = {\n        pointers: [],\n        startOffset: stream.pos,\n        parent: parent,\n        val: val,\n        pointerSize: 0\n      };\n      ctx.pointerOffset = stream.pos + this.size(val, ctx, false);\n      _ref1 = this.fields;\n      for (key in _ref1) {\n        type = _ref1[key];\n        if (type.encode != null) {\n          type.encode(stream, val[key], ctx);\n        }\n      }\n      i = 0;\n      while (i < ctx.pointers.length) {\n        ptr = ctx.pointers[i++];\n        ptr.type.encode(stream, ptr.val, ptr.parent);\n      }\n    };\n\n    return Struct;\n\n  })();\n\n  module.exports = Struct;\n\n}).call(this);\n\n\n/***/ }),\n/* 95 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = !__webpack_require__(5) && !__webpack_require__(19)(function () {\n  return Object.defineProperty(__webpack_require__(96)('div'), 'a', { get: function () { return 7; } }).a != 7;\n});\n\n\n/***/ }),\n/* 96 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar isObject = __webpack_require__(9);\nvar document = __webpack_require__(10).document;\n// typeof document.createElement is 'object' in old IE\nvar is = isObject(document) && isObject(document.createElement);\nmodule.exports = function (it) {\n  return is ? document.createElement(it) : {};\n};\n\n\n/***/ }),\n/* 97 */\n/***/ (function(module, exports) {\n\nmodule.exports = function (it) {\n  if (typeof it != 'function') throw TypeError(it + ' is not a function!');\n  return it;\n};\n\n\n/***/ }),\n/* 98 */\n/***/ (function(module, exports) {\n\nmodule.exports = function (done, value) {\n  return { value: value, done: !!done };\n};\n\n\n/***/ }),\n/* 99 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(13);\n\n\n/***/ }),\n/* 100 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar dP = __webpack_require__(6);\nvar anObject = __webpack_require__(14);\nvar getKeys = __webpack_require__(29);\n\nmodule.exports = __webpack_require__(5) ? Object.defineProperties : function defineProperties(O, Properties) {\n  anObject(O);\n  var keys = getKeys(Properties);\n  var length = keys.length;\n  var i = 0;\n  var P;\n  while (length > i) dP.f(O, P = keys[i++], Properties[P]);\n  return O;\n};\n\n\n/***/ }),\n/* 101 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar has = __webpack_require__(18);\nvar toIObject = __webpack_require__(17);\nvar arrayIndexOf = __webpack_require__(204)(false);\nvar IE_PROTO = __webpack_require__(64)('IE_PROTO');\n\nmodule.exports = function (object, names) {\n  var O = toIObject(object);\n  var i = 0;\n  var result = [];\n  var key;\n  for (key in O) if (key != IE_PROTO) has(O, key) && result.push(key);\n  // Don't enum bug & hidden keys\n  while (names.length > i) if (has(O, key = names[i++])) {\n    ~arrayIndexOf(result, key) || result.push(key);\n  }\n  return result;\n};\n\n\n/***/ }),\n/* 102 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar toInteger = __webpack_require__(63);\nvar max = Math.max;\nvar min = Math.min;\nmodule.exports = function (index, length) {\n  index = toInteger(index);\n  return index < 0 ? max(index + length, 0) : min(index, length);\n};\n\n\n/***/ }),\n/* 103 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(215), __esModule: true };\n\n/***/ }),\n/* 104 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 7.2.2 IsArray(argument)\nvar cof = __webpack_require__(55);\nmodule.exports = Array.isArray || function isArray(arg) {\n  return cof(arg) == 'Array';\n};\n\n\n/***/ }),\n/* 105 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.2.7 / 15.2.3.4 Object.getOwnPropertyNames(O)\nvar $keys = __webpack_require__(101);\nvar hiddenKeys = __webpack_require__(66).concat('length', 'prototype');\n\nexports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {\n  return $keys(O, hiddenKeys);\n};\n\n\n/***/ }),\n/* 106 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nexports.default = function (instance, Constructor) {\n  if (!(instance instanceof Constructor)) {\n    throw new TypeError(\"Cannot call a class as a function\");\n  }\n};\n\n/***/ }),\n/* 107 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nvar _defineProperty = __webpack_require__(74);\n\nvar _defineProperty2 = _interopRequireDefault(_defineProperty);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nexports.default = function () {\n  function defineProperties(target, props) {\n    for (var i = 0; i < props.length; i++) {\n      var descriptor = props[i];\n      descriptor.enumerable = descriptor.enumerable || false;\n      descriptor.configurable = true;\n      if (\"value\" in descriptor) descriptor.writable = true;\n      (0, _defineProperty2.default)(target, descriptor.key, descriptor);\n    }\n  }\n\n  return function (Constructor, protoProps, staticProps) {\n    if (protoProps) defineProperties(Constructor.prototype, protoProps);\n    if (staticProps) defineProperties(Constructor, staticProps);\n    return Constructor;\n  };\n}();\n\n/***/ }),\n/* 108 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar dP = __webpack_require__(6).f;\nvar create = __webpack_require__(36);\nvar redefineAll = __webpack_require__(109);\nvar ctx = __webpack_require__(20);\nvar anInstance = __webpack_require__(110);\nvar forOf = __webpack_require__(41);\nvar $iterDefine = __webpack_require__(61);\nvar step = __webpack_require__(98);\nvar setSpecies = __webpack_require__(228);\nvar DESCRIPTORS = __webpack_require__(5);\nvar fastKey = __webpack_require__(40).fastKey;\nvar validate = __webpack_require__(75);\nvar SIZE = DESCRIPTORS ? '_s' : 'size';\n\nvar getEntry = function (that, key) {\n  // fast case\n  var index = fastKey(key);\n  var entry;\n  if (index !== 'F') return that._i[index];\n  // frozen object case\n  for (entry = that._f; entry; entry = entry.n) {\n    if (entry.k == key) return entry;\n  }\n};\n\nmodule.exports = {\n  getConstructor: function (wrapper, NAME, IS_MAP, ADDER) {\n    var C = wrapper(function (that, iterable) {\n      anInstance(that, C, NAME, '_i');\n      that._t = NAME;         // collection type\n      that._i = create(null); // index\n      that._f = undefined;    // first entry\n      that._l = undefined;    // last entry\n      that[SIZE] = 0;         // size\n      if (iterable != undefined) forOf(iterable, IS_MAP, that[ADDER], that);\n    });\n    redefineAll(C.prototype, {\n      // 23.1.3.1 Map.prototype.clear()\n      // 23.2.3.2 Set.prototype.clear()\n      clear: function clear() {\n        for (var that = validate(this, NAME), data = that._i, entry = that._f; entry; entry = entry.n) {\n          entry.r = true;\n          if (entry.p) entry.p = entry.p.n = undefined;\n          delete data[entry.i];\n        }\n        that._f = that._l = undefined;\n        that[SIZE] = 0;\n      },\n      // 23.1.3.3 Map.prototype.delete(key)\n      // 23.2.3.4 Set.prototype.delete(value)\n      'delete': function (key) {\n        var that = validate(this, NAME);\n        var entry = getEntry(that, key);\n        if (entry) {\n          var next = entry.n;\n          var prev = entry.p;\n          delete that._i[entry.i];\n          entry.r = true;\n          if (prev) prev.n = next;\n          if (next) next.p = prev;\n          if (that._f == entry) that._f = next;\n          if (that._l == entry) that._l = prev;\n          that[SIZE]--;\n        } return !!entry;\n      },\n      // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)\n      // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)\n      forEach: function forEach(callbackfn /* , that = undefined */) {\n        validate(this, NAME);\n        var f = ctx(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);\n        var entry;\n        while (entry = entry ? entry.n : this._f) {\n          f(entry.v, entry.k, this);\n          // revert to the last existing entry\n          while (entry && entry.r) entry = entry.p;\n        }\n      },\n      // 23.1.3.7 Map.prototype.has(key)\n      // 23.2.3.7 Set.prototype.has(value)\n      has: function has(key) {\n        return !!getEntry(validate(this, NAME), key);\n      }\n    });\n    if (DESCRIPTORS) dP(C.prototype, 'size', {\n      get: function () {\n        return validate(this, NAME)[SIZE];\n      }\n    });\n    return C;\n  },\n  def: function (that, key, value) {\n    var entry = getEntry(that, key);\n    var prev, index;\n    // change existing entry\n    if (entry) {\n      entry.v = value;\n    // create new entry\n    } else {\n      that._l = entry = {\n        i: index = fastKey(key, true), // <- index\n        k: key,                        // <- key\n        v: value,                      // <- value\n        p: prev = that._l,             // <- previous entry\n        n: undefined,                  // <- next entry\n        r: false                       // <- removed\n      };\n      if (!that._f) that._f = entry;\n      if (prev) prev.n = entry;\n      that[SIZE]++;\n      // add to index\n      if (index !== 'F') that._i[index] = entry;\n    } return that;\n  },\n  getEntry: getEntry,\n  setStrong: function (C, NAME, IS_MAP) {\n    // add .keys, .values, .entries, [@@iterator]\n    // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11\n    $iterDefine(C, NAME, function (iterated, kind) {\n      this._t = validate(iterated, NAME); // target\n      this._k = kind;                     // kind\n      this._l = undefined;                // previous\n    }, function () {\n      var that = this;\n      var kind = that._k;\n      var entry = that._l;\n      // revert to the last existing entry\n      while (entry && entry.r) entry = entry.p;\n      // get next entry\n      if (!that._t || !(that._l = entry = entry ? entry.n : that._t._f)) {\n        // or finish the iteration\n        that._t = undefined;\n        return step(1);\n      }\n      // return step by kind\n      if (kind == 'keys') return step(0, entry.k);\n      if (kind == 'values') return step(0, entry.v);\n      return step(0, [entry.k, entry.v]);\n    }, IS_MAP ? 'entries' : 'values', !IS_MAP, true);\n\n    // add [@@species], 23.1.2.2, 23.2.2.2\n    setSpecies(NAME);\n  }\n};\n\n\n/***/ }),\n/* 109 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar hide = __webpack_require__(13);\nmodule.exports = function (target, src, safe) {\n  for (var key in src) {\n    if (safe && target[key]) target[key] = src[key];\n    else hide(target, key, src[key]);\n  } return target;\n};\n\n\n/***/ }),\n/* 110 */\n/***/ (function(module, exports) {\n\nmodule.exports = function (it, Constructor, name, forbiddenField) {\n  if (!(it instanceof Constructor) || (forbiddenField !== undefined && forbiddenField in it)) {\n    throw TypeError(name + ': incorrect invocation!');\n  } return it;\n};\n\n\n/***/ }),\n/* 111 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// call something on iterator step with safe closing on error\nvar anObject = __webpack_require__(14);\nmodule.exports = function (iterator, fn, value, entries) {\n  try {\n    return entries ? fn(anObject(value)[0], value[1]) : fn(value);\n  // 7.4.6 IteratorClose(iterator, completion)\n  } catch (e) {\n    var ret = iterator['return'];\n    if (ret !== undefined) anObject(ret.call(iterator));\n    throw e;\n  }\n};\n\n\n/***/ }),\n/* 112 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// check on default Array iterator\nvar Iterators = __webpack_require__(23);\nvar ITERATOR = __webpack_require__(4)('iterator');\nvar ArrayProto = Array.prototype;\n\nmodule.exports = function (it) {\n  return it !== undefined && (Iterators.Array === it || ArrayProto[ITERATOR] === it);\n};\n\n\n/***/ }),\n/* 113 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar global = __webpack_require__(10);\nvar $export = __webpack_require__(3);\nvar meta = __webpack_require__(40);\nvar fails = __webpack_require__(19);\nvar hide = __webpack_require__(13);\nvar redefineAll = __webpack_require__(109);\nvar forOf = __webpack_require__(41);\nvar anInstance = __webpack_require__(110);\nvar isObject = __webpack_require__(9);\nvar setToStringTag = __webpack_require__(39);\nvar dP = __webpack_require__(6).f;\nvar each = __webpack_require__(229)(0);\nvar DESCRIPTORS = __webpack_require__(5);\n\nmodule.exports = function (NAME, wrapper, methods, common, IS_MAP, IS_WEAK) {\n  var Base = global[NAME];\n  var C = Base;\n  var ADDER = IS_MAP ? 'set' : 'add';\n  var proto = C && C.prototype;\n  var O = {};\n  if (!DESCRIPTORS || typeof C != 'function' || !(IS_WEAK || proto.forEach && !fails(function () {\n    new C().entries().next();\n  }))) {\n    // create collection constructor\n    C = common.getConstructor(wrapper, NAME, IS_MAP, ADDER);\n    redefineAll(C.prototype, methods);\n    meta.NEED = true;\n  } else {\n    C = wrapper(function (target, iterable) {\n      anInstance(target, C, NAME, '_c');\n      target._c = new Base();\n      if (iterable != undefined) forOf(iterable, IS_MAP, target[ADDER], target);\n    });\n    each('add,clear,delete,forEach,get,has,set,keys,values,entries,toJSON'.split(','), function (KEY) {\n      var IS_ADDER = KEY == 'add' || KEY == 'set';\n      if (KEY in proto && !(IS_WEAK && KEY == 'clear')) hide(C.prototype, KEY, function (a, b) {\n        anInstance(this, C, KEY);\n        if (!IS_ADDER && IS_WEAK && !isObject(a)) return KEY == 'get' ? undefined : false;\n        var result = this._c[KEY](a === 0 ? 0 : a, b);\n        return IS_ADDER ? this : result;\n      });\n    });\n    IS_WEAK || dP(C.prototype, 'size', {\n      get: function () {\n        return this._c.size;\n      }\n    });\n  }\n\n  setToStringTag(C, NAME);\n\n  O[NAME] = C;\n  $export($export.G + $export.W + $export.F, O);\n\n  if (!IS_WEAK) common.setStrong(C, NAME, IS_MAP);\n\n  return C;\n};\n\n\n/***/ }),\n/* 114 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// https://github.com/DavidBruant/Map-Set.prototype.toJSON\nvar classof = __webpack_require__(68);\nvar from = __webpack_require__(233);\nmodule.exports = function (NAME) {\n  return function toJSON() {\n    if (classof(this) != NAME) throw TypeError(NAME + \"#toJSON isn't generic\");\n    return from(this);\n  };\n};\n\n\n/***/ }),\n/* 115 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n// https://tc39.github.io/proposal-setmap-offrom/\nvar $export = __webpack_require__(3);\n\nmodule.exports = function (COLLECTION) {\n  $export($export.S, COLLECTION, { of: function of() {\n    var length = arguments.length;\n    var A = new Array(length);\n    while (length--) A[length] = arguments[length];\n    return new this(A);\n  } });\n};\n\n\n/***/ }),\n/* 116 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n// https://tc39.github.io/proposal-setmap-offrom/\nvar $export = __webpack_require__(3);\nvar aFunction = __webpack_require__(97);\nvar ctx = __webpack_require__(20);\nvar forOf = __webpack_require__(41);\n\nmodule.exports = function (COLLECTION) {\n  $export($export.S, COLLECTION, { from: function from(source /* , mapFn, thisArg */) {\n    var mapFn = arguments[1];\n    var mapping, A, n, cb;\n    aFunction(this);\n    mapping = mapFn !== undefined;\n    if (mapping) aFunction(mapFn);\n    if (source == undefined) return new this();\n    A = [];\n    if (mapping) {\n      n = 0;\n      cb = ctx(mapFn, arguments[2], 2);\n      forOf(source, false, function (nextItem) {\n        A.push(cb(nextItem, n++));\n      });\n    } else {\n      forOf(source, false, A.push, A);\n    }\n    return new this(A);\n  } });\n};\n\n\n/***/ }),\n/* 117 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n*/\n\nvar BrotliInput = __webpack_require__(118).BrotliInput;\nvar BrotliOutput = __webpack_require__(118).BrotliOutput;\nvar BrotliBitReader = __webpack_require__(285);\nvar BrotliDictionary = __webpack_require__(119);\nvar HuffmanCode = __webpack_require__(120).HuffmanCode;\nvar BrotliBuildHuffmanTable = __webpack_require__(120).BrotliBuildHuffmanTable;\nvar Context = __webpack_require__(289);\nvar Prefix = __webpack_require__(290);\nvar Transform = __webpack_require__(291);\n\nvar kDefaultCodeLength = 8;\nvar kCodeLengthRepeatCode = 16;\nvar kNumLiteralCodes = 256;\nvar kNumInsertAndCopyCodes = 704;\nvar kNumBlockLengthCodes = 26;\nvar kLiteralContextBits = 6;\nvar kDistanceContextBits = 2;\n\nvar HUFFMAN_TABLE_BITS = 8;\nvar HUFFMAN_TABLE_MASK = 0xff;\n/* Maximum possible Huffman table size for an alphabet size of 704, max code\n * length 15 and root table bits 8. */\nvar HUFFMAN_MAX_TABLE_SIZE = 1080;\n\nvar CODE_LENGTH_CODES = 18;\nvar kCodeLengthCodeOrder = new Uint8Array([\n  1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n]);\n\nvar NUM_DISTANCE_SHORT_CODES = 16;\nvar kDistanceShortCodeIndexOffset = new Uint8Array([\n  3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2\n]);\n\nvar kDistanceShortCodeValueOffset = new Int8Array([\n  0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3\n]);\n\nvar kMaxHuffmanTableSize = new Uint16Array([\n  256, 402, 436, 468, 500, 534, 566, 598, 630, 662, 694, 726, 758, 790, 822,\n  854, 886, 920, 952, 984, 1016, 1048, 1080\n]);\n\nfunction DecodeWindowBits(br) {\n  var n;\n  if (br.readBits(1) === 0) {\n    return 16;\n  }\n  \n  n = br.readBits(3);\n  if (n > 0) {\n    return 17 + n;\n  }\n  \n  n = br.readBits(3);\n  if (n > 0) {\n    return 8 + n;\n  }\n  \n  return 17;\n}\n\n/* Decodes a number in the range [0..255], by reading 1 - 11 bits. */\nfunction DecodeVarLenUint8(br) {\n  if (br.readBits(1)) {\n    var nbits = br.readBits(3);\n    if (nbits === 0) {\n      return 1;\n    } else {\n      return br.readBits(nbits) + (1 << nbits);\n    }\n  }\n  return 0;\n}\n\nfunction MetaBlockLength() {\n  this.meta_block_length = 0;\n  this.input_end = 0;\n  this.is_uncompressed = 0;\n  this.is_metadata = false;\n}\n\nfunction DecodeMetaBlockLength(br) {\n  var out = new MetaBlockLength;  \n  var size_nibbles;\n  var size_bytes;\n  var i;\n  \n  out.input_end = br.readBits(1);\n  if (out.input_end && br.readBits(1)) {\n    return out;\n  }\n  \n  size_nibbles = br.readBits(2) + 4;\n  if (size_nibbles === 7) {\n    out.is_metadata = true;\n    \n    if (br.readBits(1) !== 0)\n      throw new Error('Invalid reserved bit');\n    \n    size_bytes = br.readBits(2);\n    if (size_bytes === 0)\n      return out;\n    \n    for (i = 0; i < size_bytes; i++) {\n      var next_byte = br.readBits(8);\n      if (i + 1 === size_bytes && size_bytes > 1 && next_byte === 0)\n        throw new Error('Invalid size byte');\n      \n      out.meta_block_length |= next_byte << (i * 8);\n    }\n  } else {\n    for (i = 0; i < size_nibbles; ++i) {\n      var next_nibble = br.readBits(4);\n      if (i + 1 === size_nibbles && size_nibbles > 4 && next_nibble === 0)\n        throw new Error('Invalid size nibble');\n      \n      out.meta_block_length |= next_nibble << (i * 4);\n    }\n  }\n  \n  ++out.meta_block_length;\n  \n  if (!out.input_end && !out.is_metadata) {\n    out.is_uncompressed = br.readBits(1);\n  }\n  \n  return out;\n}\n\n/* Decodes the next Huffman code from bit-stream. */\nfunction ReadSymbol(table, index, br) {\n  var start_index = index;\n  \n  var nbits;\n  br.fillBitWindow();\n  index += (br.val_ >>> br.bit_pos_) & HUFFMAN_TABLE_MASK;\n  nbits = table[index].bits - HUFFMAN_TABLE_BITS;\n  if (nbits > 0) {\n    br.bit_pos_ += HUFFMAN_TABLE_BITS;\n    index += table[index].value;\n    index += (br.val_ >>> br.bit_pos_) & ((1 << nbits) - 1);\n  }\n  br.bit_pos_ += table[index].bits;\n  return table[index].value;\n}\n\nfunction ReadHuffmanCodeLengths(code_length_code_lengths, num_symbols, code_lengths, br) {\n  var symbol = 0;\n  var prev_code_len = kDefaultCodeLength;\n  var repeat = 0;\n  var repeat_code_len = 0;\n  var space = 32768;\n  \n  var table = [];\n  for (var i = 0; i < 32; i++)\n    table.push(new HuffmanCode(0, 0));\n  \n  BrotliBuildHuffmanTable(table, 0, 5, code_length_code_lengths, CODE_LENGTH_CODES);\n\n  while (symbol < num_symbols && space > 0) {\n    var p = 0;\n    var code_len;\n    \n    br.readMoreInput();\n    br.fillBitWindow();\n    p += (br.val_ >>> br.bit_pos_) & 31;\n    br.bit_pos_ += table[p].bits;\n    code_len = table[p].value & 0xff;\n    if (code_len < kCodeLengthRepeatCode) {\n      repeat = 0;\n      code_lengths[symbol++] = code_len;\n      if (code_len !== 0) {\n        prev_code_len = code_len;\n        space -= 32768 >> code_len;\n      }\n    } else {\n      var extra_bits = code_len - 14;\n      var old_repeat;\n      var repeat_delta;\n      var new_len = 0;\n      if (code_len === kCodeLengthRepeatCode) {\n        new_len = prev_code_len;\n      }\n      if (repeat_code_len !== new_len) {\n        repeat = 0;\n        repeat_code_len = new_len;\n      }\n      old_repeat = repeat;\n      if (repeat > 0) {\n        repeat -= 2;\n        repeat <<= extra_bits;\n      }\n      repeat += br.readBits(extra_bits) + 3;\n      repeat_delta = repeat - old_repeat;\n      if (symbol + repeat_delta > num_symbols) {\n        throw new Error('[ReadHuffmanCodeLengths] symbol + repeat_delta > num_symbols');\n      }\n      \n      for (var x = 0; x < repeat_delta; x++)\n        code_lengths[symbol + x] = repeat_code_len;\n      \n      symbol += repeat_delta;\n      \n      if (repeat_code_len !== 0) {\n        space -= repeat_delta << (15 - repeat_code_len);\n      }\n    }\n  }\n  if (space !== 0) {\n    throw new Error(\"[ReadHuffmanCodeLengths] space = \" + space);\n  }\n  \n  for (; symbol < num_symbols; symbol++)\n    code_lengths[symbol] = 0;\n}\n\nfunction ReadHuffmanCode(alphabet_size, tables, table, br) {\n  var table_size = 0;\n  var simple_code_or_skip;\n  var code_lengths = new Uint8Array(alphabet_size);\n  \n  br.readMoreInput();\n  \n  /* simple_code_or_skip is used as follows:\n     1 for simple code;\n     0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */\n  simple_code_or_skip = br.readBits(2);\n  if (simple_code_or_skip === 1) {\n    /* Read symbols, codes & code lengths directly. */\n    var i;\n    var max_bits_counter = alphabet_size - 1;\n    var max_bits = 0;\n    var symbols = new Int32Array(4);\n    var num_symbols = br.readBits(2) + 1;\n    while (max_bits_counter) {\n      max_bits_counter >>= 1;\n      ++max_bits;\n    }\n\n    for (i = 0; i < num_symbols; ++i) {\n      symbols[i] = br.readBits(max_bits) % alphabet_size;\n      code_lengths[symbols[i]] = 2;\n    }\n    code_lengths[symbols[0]] = 1;\n    switch (num_symbols) {\n      case 1:\n        break;\n      case 3:\n        if ((symbols[0] === symbols[1]) ||\n            (symbols[0] === symbols[2]) ||\n            (symbols[1] === symbols[2])) {\n          throw new Error('[ReadHuffmanCode] invalid symbols');\n        }\n        break;\n      case 2:\n        if (symbols[0] === symbols[1]) {\n          throw new Error('[ReadHuffmanCode] invalid symbols');\n        }\n        \n        code_lengths[symbols[1]] = 1;\n        break;\n      case 4:\n        if ((symbols[0] === symbols[1]) ||\n            (symbols[0] === symbols[2]) ||\n            (symbols[0] === symbols[3]) ||\n            (symbols[1] === symbols[2]) ||\n            (symbols[1] === symbols[3]) ||\n            (symbols[2] === symbols[3])) {\n          throw new Error('[ReadHuffmanCode] invalid symbols');\n        }\n        \n        if (br.readBits(1)) {\n          code_lengths[symbols[2]] = 3;\n          code_lengths[symbols[3]] = 3;\n        } else {\n          code_lengths[symbols[0]] = 2;\n        }\n        break;\n    }\n  } else {  /* Decode Huffman-coded code lengths. */\n    var i;\n    var code_length_code_lengths = new Uint8Array(CODE_LENGTH_CODES);\n    var space = 32;\n    var num_codes = 0;\n    /* Static Huffman code for the code length code lengths */\n    var huff = [\n      new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(3, 2), \n      new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(4, 1),\n      new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(3, 2), \n      new HuffmanCode(2, 0), new HuffmanCode(2, 4), new HuffmanCode(2, 3), new HuffmanCode(4, 5)\n    ];\n    for (i = simple_code_or_skip; i < CODE_LENGTH_CODES && space > 0; ++i) {\n      var code_len_idx = kCodeLengthCodeOrder[i];\n      var p = 0;\n      var v;\n      br.fillBitWindow();\n      p += (br.val_ >>> br.bit_pos_) & 15;\n      br.bit_pos_ += huff[p].bits;\n      v = huff[p].value;\n      code_length_code_lengths[code_len_idx] = v;\n      if (v !== 0) {\n        space -= (32 >> v);\n        ++num_codes;\n      }\n    }\n    \n    if (!(num_codes === 1 || space === 0))\n      throw new Error('[ReadHuffmanCode] invalid num_codes or space');\n    \n    ReadHuffmanCodeLengths(code_length_code_lengths, alphabet_size, code_lengths, br);\n  }\n  \n  table_size = BrotliBuildHuffmanTable(tables, table, HUFFMAN_TABLE_BITS, code_lengths, alphabet_size);\n  \n  if (table_size === 0) {\n    throw new Error(\"[ReadHuffmanCode] BuildHuffmanTable failed: \");\n  }\n  \n  return table_size;\n}\n\nfunction ReadBlockLength(table, index, br) {\n  var code;\n  var nbits;\n  code = ReadSymbol(table, index, br);\n  nbits = Prefix.kBlockLengthPrefixCode[code].nbits;\n  return Prefix.kBlockLengthPrefixCode[code].offset + br.readBits(nbits);\n}\n\nfunction TranslateShortCodes(code, ringbuffer, index) {\n  var val;\n  if (code < NUM_DISTANCE_SHORT_CODES) {\n    index += kDistanceShortCodeIndexOffset[code];\n    index &= 3;\n    val = ringbuffer[index] + kDistanceShortCodeValueOffset[code];\n  } else {\n    val = code - NUM_DISTANCE_SHORT_CODES + 1;\n  }\n  return val;\n}\n\nfunction MoveToFront(v, index) {\n  var value = v[index];\n  var i = index;\n  for (; i; --i) v[i] = v[i - 1];\n  v[0] = value;\n}\n\nfunction InverseMoveToFrontTransform(v, v_len) {\n  var mtf = new Uint8Array(256);\n  var i;\n  for (i = 0; i < 256; ++i) {\n    mtf[i] = i;\n  }\n  for (i = 0; i < v_len; ++i) {\n    var index = v[i];\n    v[i] = mtf[index];\n    if (index) MoveToFront(mtf, index);\n  }\n}\n\n/* Contains a collection of huffman trees with the same alphabet size. */\nfunction HuffmanTreeGroup(alphabet_size, num_htrees) {\n  this.alphabet_size = alphabet_size;\n  this.num_htrees = num_htrees;\n  this.codes = new Array(num_htrees + num_htrees * kMaxHuffmanTableSize[(alphabet_size + 31) >>> 5]);  \n  this.htrees = new Uint32Array(num_htrees);\n}\n\nHuffmanTreeGroup.prototype.decode = function(br) {\n  var i;\n  var table_size;\n  var next = 0;\n  for (i = 0; i < this.num_htrees; ++i) {\n    this.htrees[i] = next;\n    table_size = ReadHuffmanCode(this.alphabet_size, this.codes, next, br);\n    next += table_size;\n  }\n};\n\nfunction DecodeContextMap(context_map_size, br) {\n  var out = { num_htrees: null, context_map: null };\n  var use_rle_for_zeros;\n  var max_run_length_prefix = 0;\n  var table;\n  var i;\n  \n  br.readMoreInput();\n  var num_htrees = out.num_htrees = DecodeVarLenUint8(br) + 1;\n\n  var context_map = out.context_map = new Uint8Array(context_map_size);\n  if (num_htrees <= 1) {\n    return out;\n  }\n\n  use_rle_for_zeros = br.readBits(1);\n  if (use_rle_for_zeros) {\n    max_run_length_prefix = br.readBits(4) + 1;\n  }\n  \n  table = [];\n  for (i = 0; i < HUFFMAN_MAX_TABLE_SIZE; i++) {\n    table[i] = new HuffmanCode(0, 0);\n  }\n  \n  ReadHuffmanCode(num_htrees + max_run_length_prefix, table, 0, br);\n  \n  for (i = 0; i < context_map_size;) {\n    var code;\n\n    br.readMoreInput();\n    code = ReadSymbol(table, 0, br);\n    if (code === 0) {\n      context_map[i] = 0;\n      ++i;\n    } else if (code <= max_run_length_prefix) {\n      var reps = 1 + (1 << code) + br.readBits(code);\n      while (--reps) {\n        if (i >= context_map_size) {\n          throw new Error(\"[DecodeContextMap] i >= context_map_size\");\n        }\n        context_map[i] = 0;\n        ++i;\n      }\n    } else {\n      context_map[i] = code - max_run_length_prefix;\n      ++i;\n    }\n  }\n  if (br.readBits(1)) {\n    InverseMoveToFrontTransform(context_map, context_map_size);\n  }\n  \n  return out;\n}\n\nfunction DecodeBlockType(max_block_type, trees, tree_type, block_types, ringbuffers, indexes, br) {\n  var ringbuffer = tree_type * 2;\n  var index = tree_type;\n  var type_code = ReadSymbol(trees, tree_type * HUFFMAN_MAX_TABLE_SIZE, br);\n  var block_type;\n  if (type_code === 0) {\n    block_type = ringbuffers[ringbuffer + (indexes[index] & 1)];\n  } else if (type_code === 1) {\n    block_type = ringbuffers[ringbuffer + ((indexes[index] - 1) & 1)] + 1;\n  } else {\n    block_type = type_code - 2;\n  }\n  if (block_type >= max_block_type) {\n    block_type -= max_block_type;\n  }\n  block_types[tree_type] = block_type;\n  ringbuffers[ringbuffer + (indexes[index] & 1)] = block_type;\n  ++indexes[index];\n}\n\nfunction CopyUncompressedBlockToOutput(output, len, pos, ringbuffer, ringbuffer_mask, br) {\n  var rb_size = ringbuffer_mask + 1;\n  var rb_pos = pos & ringbuffer_mask;\n  var br_pos = br.pos_ & BrotliBitReader.IBUF_MASK;\n  var nbytes;\n\n  /* For short lengths copy byte-by-byte */\n  if (len < 8 || br.bit_pos_ + (len << 3) < br.bit_end_pos_) {\n    while (len-- > 0) {\n      br.readMoreInput();\n      ringbuffer[rb_pos++] = br.readBits(8);\n      if (rb_pos === rb_size) {\n        output.write(ringbuffer, rb_size);\n        rb_pos = 0;\n      }\n    }\n    return;\n  }\n\n  if (br.bit_end_pos_ < 32) {\n    throw new Error('[CopyUncompressedBlockToOutput] br.bit_end_pos_ < 32');\n  }\n\n  /* Copy remaining 0-4 bytes from br.val_ to ringbuffer. */\n  while (br.bit_pos_ < 32) {\n    ringbuffer[rb_pos] = (br.val_ >>> br.bit_pos_);\n    br.bit_pos_ += 8;\n    ++rb_pos;\n    --len;\n  }\n\n  /* Copy remaining bytes from br.buf_ to ringbuffer. */\n  nbytes = (br.bit_end_pos_ - br.bit_pos_) >> 3;\n  if (br_pos + nbytes > BrotliBitReader.IBUF_MASK) {\n    var tail = BrotliBitReader.IBUF_MASK + 1 - br_pos;\n    for (var x = 0; x < tail; x++)\n      ringbuffer[rb_pos + x] = br.buf_[br_pos + x];\n    \n    nbytes -= tail;\n    rb_pos += tail;\n    len -= tail;\n    br_pos = 0;\n  }\n\n  for (var x = 0; x < nbytes; x++)\n    ringbuffer[rb_pos + x] = br.buf_[br_pos + x];\n  \n  rb_pos += nbytes;\n  len -= nbytes;\n\n  /* If we wrote past the logical end of the ringbuffer, copy the tail of the\n     ringbuffer to its beginning and flush the ringbuffer to the output. */\n  if (rb_pos >= rb_size) {\n    output.write(ringbuffer, rb_size);\n    rb_pos -= rb_size;    \n    for (var x = 0; x < rb_pos; x++)\n      ringbuffer[x] = ringbuffer[rb_size + x];\n  }\n\n  /* If we have more to copy than the remaining size of the ringbuffer, then we\n     first fill the ringbuffer from the input and then flush the ringbuffer to\n     the output */\n  while (rb_pos + len >= rb_size) {\n    nbytes = rb_size - rb_pos;\n    if (br.input_.read(ringbuffer, rb_pos, nbytes) < nbytes) {\n      throw new Error('[CopyUncompressedBlockToOutput] not enough bytes');\n    }\n    output.write(ringbuffer, rb_size);\n    len -= nbytes;\n    rb_pos = 0;\n  }\n\n  /* Copy straight from the input onto the ringbuffer. The ringbuffer will be\n     flushed to the output at a later time. */\n  if (br.input_.read(ringbuffer, rb_pos, len) < len) {\n    throw new Error('[CopyUncompressedBlockToOutput] not enough bytes');\n  }\n\n  /* Restore the state of the bit reader. */\n  br.reset();\n}\n\n/* Advances the bit reader position to the next byte boundary and verifies\n   that any skipped bits are set to zero. */\nfunction JumpToByteBoundary(br) {\n  var new_bit_pos = (br.bit_pos_ + 7) & ~7;\n  var pad_bits = br.readBits(new_bit_pos - br.bit_pos_);\n  return pad_bits == 0;\n}\n\nfunction BrotliDecompressedSize(buffer) {\n  var input = new BrotliInput(buffer);\n  var br = new BrotliBitReader(input);\n  DecodeWindowBits(br);\n  var out = DecodeMetaBlockLength(br);\n  return out.meta_block_length;\n}\n\nexports.BrotliDecompressedSize = BrotliDecompressedSize;\n\nfunction BrotliDecompressBuffer(buffer, output_size) {\n  var input = new BrotliInput(buffer);\n  \n  if (output_size == null) {\n    output_size = BrotliDecompressedSize(buffer);\n  }\n  \n  var output_buffer = new Uint8Array(output_size);\n  var output = new BrotliOutput(output_buffer);\n  \n  BrotliDecompress(input, output);\n  \n  if (output.pos < output.buffer.length) {\n    output.buffer = output.buffer.subarray(0, output.pos);\n  }\n  \n  return output.buffer;\n}\n\nexports.BrotliDecompressBuffer = BrotliDecompressBuffer;\n\nfunction BrotliDecompress(input, output) {\n  var i;\n  var pos = 0;\n  var input_end = 0;\n  var window_bits = 0;\n  var max_backward_distance;\n  var max_distance = 0;\n  var ringbuffer_size;\n  var ringbuffer_mask;\n  var ringbuffer;\n  var ringbuffer_end;\n  /* This ring buffer holds a few past copy distances that will be used by */\n  /* some special distance codes. */\n  var dist_rb = [ 16, 15, 11, 4 ];\n  var dist_rb_idx = 0;\n  /* The previous 2 bytes used for context. */\n  var prev_byte1 = 0;\n  var prev_byte2 = 0;\n  var hgroup = [new HuffmanTreeGroup(0, 0), new HuffmanTreeGroup(0, 0), new HuffmanTreeGroup(0, 0)];\n  var block_type_trees;\n  var block_len_trees;\n  var br;\n\n  /* We need the slack region for the following reasons:\n       - always doing two 8-byte copies for fast backward copying\n       - transforms\n       - flushing the input ringbuffer when decoding uncompressed blocks */\n  var kRingBufferWriteAheadSlack = 128 + BrotliBitReader.READ_SIZE;\n\n  br = new BrotliBitReader(input);\n\n  /* Decode window size. */\n  window_bits = DecodeWindowBits(br);\n  max_backward_distance = (1 << window_bits) - 16;\n\n  ringbuffer_size = 1 << window_bits;\n  ringbuffer_mask = ringbuffer_size - 1;\n  ringbuffer = new Uint8Array(ringbuffer_size + kRingBufferWriteAheadSlack + BrotliDictionary.maxDictionaryWordLength);\n  ringbuffer_end = ringbuffer_size;\n\n  block_type_trees = [];\n  block_len_trees = [];\n  for (var x = 0; x < 3 * HUFFMAN_MAX_TABLE_SIZE; x++) {\n    block_type_trees[x] = new HuffmanCode(0, 0);\n    block_len_trees[x] = new HuffmanCode(0, 0);\n  }\n\n  while (!input_end) {\n    var meta_block_remaining_len = 0;\n    var is_uncompressed;\n    var block_length = [ 1 << 28, 1 << 28, 1 << 28 ];\n    var block_type = [ 0 ];\n    var num_block_types = [ 1, 1, 1 ];\n    var block_type_rb = [ 0, 1, 0, 1, 0, 1 ];\n    var block_type_rb_index = [ 0 ];\n    var distance_postfix_bits;\n    var num_direct_distance_codes;\n    var distance_postfix_mask;\n    var num_distance_codes;\n    var context_map = null;\n    var context_modes = null;\n    var num_literal_htrees;\n    var dist_context_map = null;\n    var num_dist_htrees;\n    var context_offset = 0;\n    var context_map_slice = null;\n    var literal_htree_index = 0;\n    var dist_context_offset = 0;\n    var dist_context_map_slice = null;\n    var dist_htree_index = 0;\n    var context_lookup_offset1 = 0;\n    var context_lookup_offset2 = 0;\n    var context_mode;\n    var htree_command;\n\n    for (i = 0; i < 3; ++i) {\n      hgroup[i].codes = null;\n      hgroup[i].htrees = null;\n    }\n\n    br.readMoreInput();\n    \n    var _out = DecodeMetaBlockLength(br);\n    meta_block_remaining_len = _out.meta_block_length;\n    if (pos + meta_block_remaining_len > output.buffer.length) {\n      /* We need to grow the output buffer to fit the additional data. */\n      var tmp = new Uint8Array( pos + meta_block_remaining_len );\n      tmp.set( output.buffer );\n      output.buffer = tmp;\n    }    \n    input_end = _out.input_end;\n    is_uncompressed = _out.is_uncompressed;\n    \n    if (_out.is_metadata) {\n      JumpToByteBoundary(br);\n      \n      for (; meta_block_remaining_len > 0; --meta_block_remaining_len) {\n        br.readMoreInput();\n        /* Read one byte and ignore it. */\n        br.readBits(8);\n      }\n      \n      continue;\n    }\n    \n    if (meta_block_remaining_len === 0) {\n      continue;\n    }\n    \n    if (is_uncompressed) {\n      br.bit_pos_ = (br.bit_pos_ + 7) & ~7;\n      CopyUncompressedBlockToOutput(output, meta_block_remaining_len, pos,\n                                    ringbuffer, ringbuffer_mask, br);\n      pos += meta_block_remaining_len;\n      continue;\n    }\n    \n    for (i = 0; i < 3; ++i) {\n      num_block_types[i] = DecodeVarLenUint8(br) + 1;\n      if (num_block_types[i] >= 2) {\n        ReadHuffmanCode(num_block_types[i] + 2, block_type_trees, i * HUFFMAN_MAX_TABLE_SIZE, br);\n        ReadHuffmanCode(kNumBlockLengthCodes, block_len_trees, i * HUFFMAN_MAX_TABLE_SIZE, br);\n        block_length[i] = ReadBlockLength(block_len_trees, i * HUFFMAN_MAX_TABLE_SIZE, br);\n        block_type_rb_index[i] = 1;\n      }\n    }\n    \n    br.readMoreInput();\n    \n    distance_postfix_bits = br.readBits(2);\n    num_direct_distance_codes = NUM_DISTANCE_SHORT_CODES + (br.readBits(4) << distance_postfix_bits);\n    distance_postfix_mask = (1 << distance_postfix_bits) - 1;\n    num_distance_codes = (num_direct_distance_codes + (48 << distance_postfix_bits));\n    context_modes = new Uint8Array(num_block_types[0]);\n\n    for (i = 0; i < num_block_types[0]; ++i) {\n       br.readMoreInput();\n       context_modes[i] = (br.readBits(2) << 1);\n    }\n    \n    var _o1 = DecodeContextMap(num_block_types[0] << kLiteralContextBits, br);\n    num_literal_htrees = _o1.num_htrees;\n    context_map = _o1.context_map;\n    \n    var _o2 = DecodeContextMap(num_block_types[2] << kDistanceContextBits, br);\n    num_dist_htrees = _o2.num_htrees;\n    dist_context_map = _o2.context_map;\n    \n    hgroup[0] = new HuffmanTreeGroup(kNumLiteralCodes, num_literal_htrees);\n    hgroup[1] = new HuffmanTreeGroup(kNumInsertAndCopyCodes, num_block_types[1]);\n    hgroup[2] = new HuffmanTreeGroup(num_distance_codes, num_dist_htrees);\n\n    for (i = 0; i < 3; ++i) {\n      hgroup[i].decode(br);\n    }\n\n    context_map_slice = 0;\n    dist_context_map_slice = 0;\n    context_mode = context_modes[block_type[0]];\n    context_lookup_offset1 = Context.lookupOffsets[context_mode];\n    context_lookup_offset2 = Context.lookupOffsets[context_mode + 1];\n    htree_command = hgroup[1].htrees[0];\n\n    while (meta_block_remaining_len > 0) {\n      var cmd_code;\n      var range_idx;\n      var insert_code;\n      var copy_code;\n      var insert_length;\n      var copy_length;\n      var distance_code;\n      var distance;\n      var context;\n      var j;\n      var copy_dst;\n\n      br.readMoreInput();\n      \n      if (block_length[1] === 0) {\n        DecodeBlockType(num_block_types[1],\n                        block_type_trees, 1, block_type, block_type_rb,\n                        block_type_rb_index, br);\n        block_length[1] = ReadBlockLength(block_len_trees, HUFFMAN_MAX_TABLE_SIZE, br);\n        htree_command = hgroup[1].htrees[block_type[1]];\n      }\n      --block_length[1];\n      cmd_code = ReadSymbol(hgroup[1].codes, htree_command, br);\n      range_idx = cmd_code >> 6;\n      if (range_idx >= 2) {\n        range_idx -= 2;\n        distance_code = -1;\n      } else {\n        distance_code = 0;\n      }\n      insert_code = Prefix.kInsertRangeLut[range_idx] + ((cmd_code >> 3) & 7);\n      copy_code = Prefix.kCopyRangeLut[range_idx] + (cmd_code & 7);\n      insert_length = Prefix.kInsertLengthPrefixCode[insert_code].offset +\n          br.readBits(Prefix.kInsertLengthPrefixCode[insert_code].nbits);\n      copy_length = Prefix.kCopyLengthPrefixCode[copy_code].offset +\n          br.readBits(Prefix.kCopyLengthPrefixCode[copy_code].nbits);\n      prev_byte1 = ringbuffer[pos-1 & ringbuffer_mask];\n      prev_byte2 = ringbuffer[pos-2 & ringbuffer_mask];\n      for (j = 0; j < insert_length; ++j) {\n        br.readMoreInput();\n\n        if (block_length[0] === 0) {\n          DecodeBlockType(num_block_types[0],\n                          block_type_trees, 0, block_type, block_type_rb,\n                          block_type_rb_index, br);\n          block_length[0] = ReadBlockLength(block_len_trees, 0, br);\n          context_offset = block_type[0] << kLiteralContextBits;\n          context_map_slice = context_offset;\n          context_mode = context_modes[block_type[0]];\n          context_lookup_offset1 = Context.lookupOffsets[context_mode];\n          context_lookup_offset2 = Context.lookupOffsets[context_mode + 1];\n        }\n        context = (Context.lookup[context_lookup_offset1 + prev_byte1] |\n                   Context.lookup[context_lookup_offset2 + prev_byte2]);\n        literal_htree_index = context_map[context_map_slice + context];\n        --block_length[0];\n        prev_byte2 = prev_byte1;\n        prev_byte1 = ReadSymbol(hgroup[0].codes, hgroup[0].htrees[literal_htree_index], br);\n        ringbuffer[pos & ringbuffer_mask] = prev_byte1;\n        if ((pos & ringbuffer_mask) === ringbuffer_mask) {\n          output.write(ringbuffer, ringbuffer_size);\n        }\n        ++pos;\n      }\n      meta_block_remaining_len -= insert_length;\n      if (meta_block_remaining_len <= 0) break;\n\n      if (distance_code < 0) {\n        var context;\n        \n        br.readMoreInput();\n        if (block_length[2] === 0) {\n          DecodeBlockType(num_block_types[2],\n                          block_type_trees, 2, block_type, block_type_rb,\n                          block_type_rb_index, br);\n          block_length[2] = ReadBlockLength(block_len_trees, 2 * HUFFMAN_MAX_TABLE_SIZE, br);\n          dist_context_offset = block_type[2] << kDistanceContextBits;\n          dist_context_map_slice = dist_context_offset;\n        }\n        --block_length[2];\n        context = (copy_length > 4 ? 3 : copy_length - 2) & 0xff;\n        dist_htree_index = dist_context_map[dist_context_map_slice + context];\n        distance_code = ReadSymbol(hgroup[2].codes, hgroup[2].htrees[dist_htree_index], br);\n        if (distance_code >= num_direct_distance_codes) {\n          var nbits;\n          var postfix;\n          var offset;\n          distance_code -= num_direct_distance_codes;\n          postfix = distance_code & distance_postfix_mask;\n          distance_code >>= distance_postfix_bits;\n          nbits = (distance_code >> 1) + 1;\n          offset = ((2 + (distance_code & 1)) << nbits) - 4;\n          distance_code = num_direct_distance_codes +\n              ((offset + br.readBits(nbits)) <<\n               distance_postfix_bits) + postfix;\n        }\n      }\n\n      /* Convert the distance code to the actual distance by possibly looking */\n      /* up past distnaces from the ringbuffer. */\n      distance = TranslateShortCodes(distance_code, dist_rb, dist_rb_idx);\n      if (distance < 0) {\n        throw new Error('[BrotliDecompress] invalid distance');\n      }\n\n      if (pos < max_backward_distance &&\n          max_distance !== max_backward_distance) {\n        max_distance = pos;\n      } else {\n        max_distance = max_backward_distance;\n      }\n\n      copy_dst = pos & ringbuffer_mask;\n\n      if (distance > max_distance) {\n        if (copy_length >= BrotliDictionary.minDictionaryWordLength &&\n            copy_length <= BrotliDictionary.maxDictionaryWordLength) {\n          var offset = BrotliDictionary.offsetsByLength[copy_length];\n          var word_id = distance - max_distance - 1;\n          var shift = BrotliDictionary.sizeBitsByLength[copy_length];\n          var mask = (1 << shift) - 1;\n          var word_idx = word_id & mask;\n          var transform_idx = word_id >> shift;\n          offset += word_idx * copy_length;\n          if (transform_idx < Transform.kNumTransforms) {\n            var len = Transform.transformDictionaryWord(ringbuffer, copy_dst, offset, copy_length, transform_idx);\n            copy_dst += len;\n            pos += len;\n            meta_block_remaining_len -= len;\n            if (copy_dst >= ringbuffer_end) {\n              output.write(ringbuffer, ringbuffer_size);\n              \n              for (var _x = 0; _x < (copy_dst - ringbuffer_end); _x++)\n                ringbuffer[_x] = ringbuffer[ringbuffer_end + _x];\n            }\n          } else {\n            throw new Error(\"Invalid backward reference. pos: \" + pos + \" distance: \" + distance +\n              \" len: \" + copy_length + \" bytes left: \" + meta_block_remaining_len);\n          }\n        } else {\n          throw new Error(\"Invalid backward reference. pos: \" + pos + \" distance: \" + distance +\n            \" len: \" + copy_length + \" bytes left: \" + meta_block_remaining_len);\n        }\n      } else {\n        if (distance_code > 0) {\n          dist_rb[dist_rb_idx & 3] = distance;\n          ++dist_rb_idx;\n        }\n\n        if (copy_length > meta_block_remaining_len) {\n          throw new Error(\"Invalid backward reference. pos: \" + pos + \" distance: \" + distance +\n            \" len: \" + copy_length + \" bytes left: \" + meta_block_remaining_len);\n        }\n\n        for (j = 0; j < copy_length; ++j) {\n          ringbuffer[pos & ringbuffer_mask] = ringbuffer[(pos - distance) & ringbuffer_mask];\n          if ((pos & ringbuffer_mask) === ringbuffer_mask) {\n            output.write(ringbuffer, ringbuffer_size);\n          }\n          ++pos;\n          --meta_block_remaining_len;\n        }\n      }\n\n      /* When we get here, we must have inserted at least one literal and */\n      /* made a copy of at least length two, therefore accessing the last 2 */\n      /* bytes is valid. */\n      prev_byte1 = ringbuffer[(pos - 1) & ringbuffer_mask];\n      prev_byte2 = ringbuffer[(pos - 2) & ringbuffer_mask];\n    }\n\n    /* Protect pos from overflow, wrap it around at every GB of input data */\n    pos &= 0x3fffffff;\n  }\n\n  output.write(ringbuffer, pos & ringbuffer_mask);\n}\n\nexports.BrotliDecompress = BrotliDecompress;\n\nBrotliDictionary.init();\n\n\n/***/ }),\n/* 118 */\n/***/ (function(module, exports) {\n\nfunction BrotliInput(buffer) {\n  this.buffer = buffer;\n  this.pos = 0;\n}\n\nBrotliInput.prototype.read = function(buf, i, count) {\n  if (this.pos + count > this.buffer.length) {\n    count = this.buffer.length - this.pos;\n  }\n  \n  for (var p = 0; p < count; p++)\n    buf[i + p] = this.buffer[this.pos + p];\n  \n  this.pos += count;\n  return count;\n}\n\nexports.BrotliInput = BrotliInput;\n\nfunction BrotliOutput(buf) {\n  this.buffer = buf;\n  this.pos = 0;\n}\n\nBrotliOutput.prototype.write = function(buf, count) {\n  if (this.pos + count > this.buffer.length)\n    throw new Error('Output buffer is not large enough');\n  \n  this.buffer.set(buf.subarray(0, count), this.pos);\n  this.pos += count;\n  return count;\n};\n\nexports.BrotliOutput = BrotliOutput;\n\n\n/***/ }),\n/* 119 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n   Collection of static dictionary words.\n*/\n\nvar data = __webpack_require__(286);\nexports.init = function() {\n  exports.dictionary = data.init();\n};\n\nexports.offsetsByLength = new Uint32Array([\n     0,     0,     0,     0,     0,  4096,  9216, 21504, 35840, 44032,\n 53248, 63488, 74752, 87040, 93696, 100864, 104704, 106752, 108928, 113536,\n 115968, 118528, 119872, 121280, 122016,\n]);\n\nexports.sizeBitsByLength = new Uint8Array([\n  0,  0,  0,  0, 10, 10, 11, 11, 10, 10,\n 10, 10, 10,  9,  9,  8,  7,  7,  8,  7,\n  7,  6,  6,  5,  5,\n]);\n\nexports.minDictionaryWordLength = 4;\nexports.maxDictionaryWordLength = 24;\n\n\n/***/ }),\n/* 120 */\n/***/ (function(module, exports) {\n\nfunction HuffmanCode(bits, value) {\n  this.bits = bits;   /* number of bits used for this symbol */\n  this.value = value; /* symbol value or table offset */\n}\n\nexports.HuffmanCode = HuffmanCode;\n\nvar MAX_LENGTH = 15;\n\n/* Returns reverse(reverse(key, len) + 1, len), where reverse(key, len) is the\n   bit-wise reversal of the len least significant bits of key. */\nfunction GetNextKey(key, len) {\n  var step = 1 << (len - 1);\n  while (key & step) {\n    step >>= 1;\n  }\n  return (key & (step - 1)) + step;\n}\n\n/* Stores code in table[0], table[step], table[2*step], ..., table[end] */\n/* Assumes that end is an integer multiple of step */\nfunction ReplicateValue(table, i, step, end, code) {\n  do {\n    end -= step;\n    table[i + end] = new HuffmanCode(code.bits, code.value);\n  } while (end > 0);\n}\n\n/* Returns the table width of the next 2nd level table. count is the histogram\n   of bit lengths for the remaining symbols, len is the code length of the next\n   processed symbol */\nfunction NextTableBitSize(count, len, root_bits) {\n  var left = 1 << (len - root_bits);\n  while (len < MAX_LENGTH) {\n    left -= count[len];\n    if (left <= 0) break;\n    ++len;\n    left <<= 1;\n  }\n  return len - root_bits;\n}\n\nexports.BrotliBuildHuffmanTable = function(root_table, table, root_bits, code_lengths, code_lengths_size) {\n  var start_table = table;\n  var code;            /* current table entry */\n  var len;             /* current code length */\n  var symbol;          /* symbol index in original or sorted table */\n  var key;             /* reversed prefix code */\n  var step;            /* step size to replicate values in current table */\n  var low;             /* low bits for current root entry */\n  var mask;            /* mask for low bits */\n  var table_bits;      /* key length of current table */\n  var table_size;      /* size of current table */\n  var total_size;      /* sum of root table size and 2nd level table sizes */\n  var sorted;          /* symbols sorted by code length */\n  var count = new Int32Array(MAX_LENGTH + 1);  /* number of codes of each length */\n  var offset = new Int32Array(MAX_LENGTH + 1);  /* offsets in sorted table for each length */\n\n  sorted = new Int32Array(code_lengths_size);\n\n  /* build histogram of code lengths */\n  for (symbol = 0; symbol < code_lengths_size; symbol++) {\n    count[code_lengths[symbol]]++;\n  }\n\n  /* generate offsets into sorted symbol table by code length */\n  offset[1] = 0;\n  for (len = 1; len < MAX_LENGTH; len++) {\n    offset[len + 1] = offset[len] + count[len];\n  }\n\n  /* sort symbols by length, by symbol order within each length */\n  for (symbol = 0; symbol < code_lengths_size; symbol++) {\n    if (code_lengths[symbol] !== 0) {\n      sorted[offset[code_lengths[symbol]]++] = symbol;\n    }\n  }\n  \n  table_bits = root_bits;\n  table_size = 1 << table_bits;\n  total_size = table_size;\n\n  /* special case code with only one value */\n  if (offset[MAX_LENGTH] === 1) {\n    for (key = 0; key < total_size; ++key) {\n      root_table[table + key] = new HuffmanCode(0, sorted[0] & 0xffff);\n    }\n    \n    return total_size;\n  }\n\n  /* fill in root table */\n  key = 0;\n  symbol = 0;\n  for (len = 1, step = 2; len <= root_bits; ++len, step <<= 1) {\n    for (; count[len] > 0; --count[len]) {\n      code = new HuffmanCode(len & 0xff, sorted[symbol++] & 0xffff);\n      ReplicateValue(root_table, table + key, step, table_size, code);\n      key = GetNextKey(key, len);\n    }\n  }\n\n  /* fill in 2nd level tables and add pointers to root table */\n  mask = total_size - 1;\n  low = -1;\n  for (len = root_bits + 1, step = 2; len <= MAX_LENGTH; ++len, step <<= 1) {\n    for (; count[len] > 0; --count[len]) {\n      if ((key & mask) !== low) {\n        table += table_size;\n        table_bits = NextTableBitSize(count, len, root_bits);\n        table_size = 1 << table_bits;\n        total_size += table_size;\n        low = key & mask;\n        root_table[start_table + low] = new HuffmanCode((table_bits + root_bits) & 0xff, ((table - start_table) - low) & 0xffff);\n      }\n      code = new HuffmanCode((len - root_bits) & 0xff, sorted[symbol++] & 0xffff);\n      ReplicateValue(root_table, table + (key >> root_bits), step, table_size, code);\n      key = GetNextKey(key, len);\n    }\n  }\n  \n  return total_size;\n}\n\n\n/***/ }),\n/* 121 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6\n\n/*\nPDFImage - embeds images in PDF documents\nBy Devon Govett\n */\n\n(function() {\n  var Data, JPEG, PDFImage, PNG, fs;\n\n  fs = __webpack_require__(8);\n\n  Data = __webpack_require__(298);\n\n  JPEG = __webpack_require__(299);\n\n  PNG = __webpack_require__(300);\n\n  PDFImage = (function() {\n    function PDFImage() {}\n\n    PDFImage.open = function(src, label) {\n      var data, match;\n      if (Buffer.isBuffer(src)) {\n        data = src;\n      } else if (src instanceof ArrayBuffer) {\n        data = new Buffer(new Uint8Array(src));\n      } else {\n        if (match = /^data:.+;base64,(.*)$/.exec(src)) {\n          data = new Buffer(match[1], 'base64');\n        } else {\n          data = fs.readFileSync(src);\n          if (!data) {\n            return;\n          }\n        }\n      }\n      if (data[0] === 0xff && data[1] === 0xd8) {\n        return new JPEG(data, label);\n      } else if (data[0] === 0x89 && data.toString('ascii', 1, 4) === 'PNG') {\n        return new PNG(data, label);\n      } else {\n        throw new Error('Unknown image format.');\n      }\n    };\n\n    return PDFImage;\n\n  })();\n\n  module.exports = PDFImage;\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 122 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(global) {module.exports = global[\"pdfMake\"] = __webpack_require__(123);\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))\n\n/***/ }),\n/* 123 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(Buffer, global) {\n\nvar PdfPrinter = __webpack_require__(126);\nvar isFunction = __webpack_require__(0).isFunction;\nvar FileSaver = __webpack_require__(306);\nvar saveAs = FileSaver.saveAs;\n\nvar defaultClientFonts = {\n\tRoboto: {\n\t\tnormal: 'Roboto-Regular.ttf',\n\t\tbold: 'Roboto-Medium.ttf',\n\t\titalics: 'Roboto-Italic.ttf',\n\t\tbolditalics: 'Roboto-MediumItalic.ttf'\n\t}\n};\n\nfunction Document(docDefinition, tableLayouts, fonts, vfs) {\n\tthis.docDefinition = docDefinition;\n\tthis.tableLayouts = tableLayouts || null;\n\tthis.fonts = fonts || defaultClientFonts;\n\tthis.vfs = vfs;\n}\n\nfunction canCreatePdf() {\n\t// Ensure the browser provides the level of support needed\n\tif (!Object.keys) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nDocument.prototype._createDoc = function (options, callback) {\n\toptions = options || {};\n\tif (this.tableLayouts) {\n\t\toptions.tableLayouts = this.tableLayouts;\n\t}\n\n\tvar printer = new PdfPrinter(this.fonts);\n\t__webpack_require__(8).bindFS(this.vfs); // bind virtual file system to file system\n\n\tvar doc = printer.createPdfKitDocument(this.docDefinition, options);\n\tvar chunks = [];\n\tvar result;\n\n\tdoc.on('readable', function () {\n\t\tvar chunk;\n\t\twhile ((chunk = doc.read(9007199254740991)) !== null) {\n\t\t\tchunks.push(chunk);\n\t\t}\n\t});\n\tdoc.on('end', function () {\n\t\tresult = Buffer.concat(chunks);\n\t\tcallback(result, doc._pdfMakePages);\n\t});\n\tdoc.end();\n};\n\nDocument.prototype._getPages = function (options, cb) {\n\tif (!cb) {\n\t\tthrow '_getPages is an async method and needs a callback argument';\n\t}\n\tthis._createDoc(options, function (ignoreBuffer, pages) {\n\t\tcb(pages);\n\t});\n};\n\nDocument.prototype._bufferToBlob = function (buffer) {\n\tvar blob;\n\ttry {\n\t\tblob = new Blob([buffer], {type: 'application/pdf'});\n\t} catch (e) {\n\t\t// Old browser which can't handle it without making it an byte array (ie10)\n\t\tif (e.name === 'InvalidStateError') {\n\t\t\tvar byteArray = new Uint8Array(buffer);\n\t\t\tblob = new Blob([byteArray.buffer], {type: 'application/pdf'});\n\t\t}\n\t}\n\n\tif (!blob) {\n\t\tthrow 'Could not generate blob';\n\t}\n\n\treturn blob;\n};\n\nDocument.prototype._openWindow = function () {\n\t// we have to open the window immediately and store the reference\n\t// otherwise popup blockers will stop us\n\tvar win = window.open('', '_blank');\n\tif (win === null) {\n\t\tthrow 'Open PDF in new window blocked by browser';\n\t}\n\n\treturn win;\n};\n\nDocument.prototype._openPdf = function (options, win) {\n\tif (!win) {\n\t\twin = this._openWindow();\n\t}\n\ttry {\n\t\tthis.getBlob(function (result) {\n\t\t\tvar urlCreator = window.URL || window.webkitURL;\n\t\t\tvar pdfUrl = urlCreator.createObjectURL(result);\n\t\t\twin.location.href = pdfUrl;\n\t\t}, options);\n\t} catch (e) {\n\t\twin.close();\n\t\tthrow e;\n\t}\n};\n\nDocument.prototype.open = function (options, win) {\n\toptions = options || {};\n\toptions.autoPrint = false;\n\twin = win || null;\n\n\tthis._openPdf(options, win);\n};\n\n\nDocument.prototype.print = function (options, win) {\n\toptions = options || {};\n\toptions.autoPrint = true;\n\twin = win || null;\n\n\tthis._openPdf(options, win);\n};\n\nDocument.prototype.download = function (defaultFileName, cb, options) {\n\tif (isFunction(defaultFileName)) {\n\t\tcb = defaultFileName;\n\t\tdefaultFileName = null;\n\t}\n\n\tdefaultFileName = defaultFileName || 'file.pdf';\n\tthis.getBlob(function (result) {\n\t\tsaveAs(result, defaultFileName);\n\n\t\tif (isFunction(cb)) {\n\t\t\tcb();\n\t\t}\n\t}, options);\n};\n\nDocument.prototype.getBase64 = function (cb, options) {\n\tif (!cb) {\n\t\tthrow 'getBase64 is an async method and needs a callback argument';\n\t}\n\tthis.getBuffer(function (buffer) {\n\t\tcb(buffer.toString('base64'));\n\t}, options);\n};\n\nDocument.prototype.getDataUrl = function (cb, options) {\n\tif (!cb) {\n\t\tthrow 'getDataUrl is an async method and needs a callback argument';\n\t}\n\tthis.getBuffer(function (buffer) {\n\t\tcb('data:application/pdf;base64,' + buffer.toString('base64'));\n\t}, options);\n};\n\nDocument.prototype.getBlob = function (cb, options) {\n\tif (!cb) {\n\t\tthrow 'getBlob is an async method and needs a callback argument';\n\t}\n\tvar that = this;\n\tthis.getBuffer(function (result) {\n\t\tvar blob = that._bufferToBlob(result);\n\t\tcb(blob);\n\t}, options);\n};\n\nDocument.prototype.getBuffer = function (cb, options) {\n\tif (!cb) {\n\t\tthrow 'getBuffer is an async method and needs a callback argument';\n\t}\n\tthis._createDoc(options, function (buffer) {\n\t\tcb(buffer);\n\t});\n};\n\nmodule.exports = {\n\tcreatePdf: function (docDefinition) {\n\t\tif (!canCreatePdf()) {\n\t\t\tthrow 'Your browser does not provide the level of support needed';\n\t\t}\n\t\treturn new Document(docDefinition, global.pdfMake.tableLayouts, global.pdfMake.fonts, global.pdfMake.vfs);\n\t}\n};\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer, __webpack_require__(7)))\n\n/***/ }),\n/* 124 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.byteLength = byteLength\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nvar code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\nfor (var i = 0, len = code.length; i < len; ++i) {\n  lookup[i] = code[i]\n  revLookup[code.charCodeAt(i)] = i\n}\n\n// Support decoding URL-safe base64 strings, as Node.js does.\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\nrevLookup['-'.charCodeAt(0)] = 62\nrevLookup['_'.charCodeAt(0)] = 63\n\nfunction placeHoldersCount (b64) {\n  var len = b64.length\n  if (len % 4 > 0) {\n    throw new Error('Invalid string. Length must be a multiple of 4')\n  }\n\n  // the number of equal signs (place holders)\n  // if there are two placeholders, than the two characters before it\n  // represent one byte\n  // if there is only one, then the three characters before it represent 2 bytes\n  // this is just a cheap hack to not do indexOf twice\n  return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0\n}\n\nfunction byteLength (b64) {\n  // base64 is 4/3 + up to two characters of the original data\n  return (b64.length * 3 / 4) - placeHoldersCount(b64)\n}\n\nfunction toByteArray (b64) {\n  var i, l, tmp, placeHolders, arr\n  var len = b64.length\n  placeHolders = placeHoldersCount(b64)\n\n  arr = new Arr((len * 3 / 4) - placeHolders)\n\n  // if there are placeholders, only get up to the last complete 4 chars\n  l = placeHolders > 0 ? len - 4 : len\n\n  var L = 0\n\n  for (i = 0; i < l; i += 4) {\n    tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]\n    arr[L++] = (tmp >> 16) & 0xFF\n    arr[L++] = (tmp >> 8) & 0xFF\n    arr[L++] = tmp & 0xFF\n  }\n\n  if (placeHolders === 2) {\n    tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)\n    arr[L++] = tmp & 0xFF\n  } else if (placeHolders === 1) {\n    tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)\n    arr[L++] = (tmp >> 8) & 0xFF\n    arr[L++] = tmp & 0xFF\n  }\n\n  return arr\n}\n\nfunction tripletToBase64 (num) {\n  return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n  var tmp\n  var output = []\n  for (var i = start; i < end; i += 3) {\n    tmp = ((uint8[i] << 16) & 0xFF0000) + ((uint8[i + 1] << 8) & 0xFF00) + (uint8[i + 2] & 0xFF)\n    output.push(tripletToBase64(tmp))\n  }\n  return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n  var tmp\n  var len = uint8.length\n  var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n  var output = ''\n  var parts = []\n  var maxChunkLength = 16383 // must be multiple of 3\n\n  // go through the array every three bytes, we'll deal with trailing stuff later\n  for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n    parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n  }\n\n  // pad the end with zeros, but make sure to not forget the extra bytes\n  if (extraBytes === 1) {\n    tmp = uint8[len - 1]\n    output += lookup[tmp >> 2]\n    output += lookup[(tmp << 4) & 0x3F]\n    output += '=='\n  } else if (extraBytes === 2) {\n    tmp = (uint8[len - 2] << 8) + (uint8[len - 1])\n    output += lookup[tmp >> 10]\n    output += lookup[(tmp >> 4) & 0x3F]\n    output += lookup[(tmp << 2) & 0x3F]\n    output += '='\n  }\n\n  parts.push(output)\n\n  return parts.join('')\n}\n\n\n/***/ }),\n/* 125 */\n/***/ (function(module, exports) {\n\nexports.read = function (buffer, offset, isLE, mLen, nBytes) {\n  var e, m\n  var eLen = nBytes * 8 - mLen - 1\n  var eMax = (1 << eLen) - 1\n  var eBias = eMax >> 1\n  var nBits = -7\n  var i = isLE ? (nBytes - 1) : 0\n  var d = isLE ? -1 : 1\n  var s = buffer[offset + i]\n\n  i += d\n\n  e = s & ((1 << (-nBits)) - 1)\n  s >>= (-nBits)\n  nBits += eLen\n  for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n  m = e & ((1 << (-nBits)) - 1)\n  e >>= (-nBits)\n  nBits += mLen\n  for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n  if (e === 0) {\n    e = 1 - eBias\n  } else if (e === eMax) {\n    return m ? NaN : ((s ? -1 : 1) * Infinity)\n  } else {\n    m = m + Math.pow(2, mLen)\n    e = e - eBias\n  }\n  return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n  var e, m, c\n  var eLen = nBytes * 8 - mLen - 1\n  var eMax = (1 << eLen) - 1\n  var eBias = eMax >> 1\n  var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n  var i = isLE ? 0 : (nBytes - 1)\n  var d = isLE ? 1 : -1\n  var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n  value = Math.abs(value)\n\n  if (isNaN(value) || value === Infinity) {\n    m = isNaN(value) ? 1 : 0\n    e = eMax\n  } else {\n    e = Math.floor(Math.log(value) / Math.LN2)\n    if (value * (c = Math.pow(2, -e)) < 1) {\n      e--\n      c *= 2\n    }\n    if (e + eBias >= 1) {\n      value += rt / c\n    } else {\n      value += rt * Math.pow(2, 1 - eBias)\n    }\n    if (value * c >= 2) {\n      e++\n      c /= 2\n    }\n\n    if (e + eBias >= eMax) {\n      m = 0\n      e = eMax\n    } else if (e + eBias >= 1) {\n      m = (value * c - 1) * Math.pow(2, mLen)\n      e = e + eBias\n    } else {\n      m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n      e = 0\n    }\n  }\n\n  for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n  e = (e << mLen) | m\n  eLen += mLen\n  for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n  buffer[offset + i - d] |= s * 128\n}\n\n\n/***/ }),\n/* 126 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/*eslint no-unused-vars: [\"error\", {\"args\": \"none\"}]*/\n\n\nvar FontProvider = __webpack_require__(127);\nvar LayoutBuilder = __webpack_require__(128);\nvar PdfKit = __webpack_require__(138);\nvar sizes = __webpack_require__(303);\nvar ImageMeasure = __webpack_require__(304);\nvar textDecorator = __webpack_require__(305);\nvar TextTools = __webpack_require__(42);\nvar isFunction = __webpack_require__(0).isFunction;\nvar isString = __webpack_require__(0).isString;\nvar isNumber = __webpack_require__(0).isNumber;\nvar isBoolean = __webpack_require__(0).isBoolean;\nvar isArray = __webpack_require__(0).isArray;\n\n////////////////////////////////////////\n// PdfPrinter\n\n/**\n * @class Creates an instance of a PdfPrinter which turns document definition into a pdf\n *\n * @param {Object} fontDescriptors font definition dictionary\n *\n * @example\n * var fontDescriptors = {\n *\tRoboto: {\n *\t\tnormal: 'fonts/Roboto-Regular.ttf',\n *\t\tbold: 'fonts/Roboto-Medium.ttf',\n *\t\titalics: 'fonts/Roboto-Italic.ttf',\n *\t\tbolditalics: 'fonts/Roboto-MediumItalic.ttf'\n *\t}\n * };\n *\n * var printer = new PdfPrinter(fontDescriptors);\n */\nfunction PdfPrinter(fontDescriptors) {\n\tthis.fontDescriptors = fontDescriptors;\n}\n\n/**\n * Executes layout engine for the specified document and renders it into a pdfkit document\n * ready to be saved.\n *\n * @param {Object} docDefinition document definition\n * @param {Object} docDefinition.content an array describing the pdf structure (for more information take a look at the examples in the /examples folder)\n * @param {Object} [docDefinition.defaultStyle] default (implicit) style definition\n * @param {Object} [docDefinition.styles] dictionary defining all styles which can be used in the document\n * @param {Object} [docDefinition.pageSize] page size (pdfkit units, A4 dimensions by default)\n * @param {Number} docDefinition.pageSize.width width\n * @param {Number} docDefinition.pageSize.height height\n * @param {Object} [docDefinition.pageMargins] page margins (pdfkit units)\n * @param {Number} docDefinition.maxPagesNumber maximum number of pages to render\n *\n * @example\n *\n * var docDefinition = {\n * \tinfo: {\n *\t\ttitle: 'awesome Document',\n *\t\tauthor: 'john doe',\n *\t\tsubject: 'subject of document',\n *\t\tkeywords: 'keywords for document',\n * \t},\n *\tcontent: [\n *\t\t'First paragraph',\n *\t\t'Second paragraph, this time a little bit longer',\n *\t\t{ text: 'Third paragraph, slightly bigger font size', fontSize: 20 },\n *\t\t{ text: 'Another paragraph using a named style', style: 'header' },\n *\t\t{ text: ['playing with ', 'inlines' ] },\n *\t\t{ text: ['and ', { text: 'restyling ', bold: true }, 'them'] },\n *\t],\n *\tstyles: {\n *\t\theader: { fontSize: 30, bold: true }\n *\t}\n * }\n *\n * var pdfKitDoc = printer.createPdfKitDocument(docDefinition);\n *\n * pdfKitDoc.pipe(fs.createWriteStream('sample.pdf'));\n * pdfKitDoc.end();\n *\n * @return {Object} a pdfKit document object which can be saved or encode to data-url\n */\nPdfPrinter.prototype.createPdfKitDocument = function (docDefinition, options) {\n\toptions = options || {};\n\n\tvar pageSize = fixPageSize(docDefinition.pageSize, docDefinition.pageOrientation);\n\tvar compressPdf = isBoolean(docDefinition.compress) ? docDefinition.compress : true;\n\n\tthis.pdfKitDoc = new PdfKit({size: [pageSize.width, pageSize.height], autoFirstPage: false, compress: compressPdf});\n\tsetMetadata(docDefinition, this.pdfKitDoc);\n\n\tthis.fontProvider = new FontProvider(this.fontDescriptors, this.pdfKitDoc);\n\n\tdocDefinition.images = docDefinition.images || {};\n\n\tvar builder = new LayoutBuilder(pageSize, fixPageMargins(docDefinition.pageMargins || 40), new ImageMeasure(this.pdfKitDoc, docDefinition.images));\n\n\tregisterDefaultTableLayouts(builder);\n\tif (options.tableLayouts) {\n\t\tbuilder.registerTableLayouts(options.tableLayouts);\n\t}\n\n\tvar pages = builder.layoutDocument(docDefinition.content, this.fontProvider, docDefinition.styles || {}, docDefinition.defaultStyle || {fontSize: 12, font: 'Roboto'}, docDefinition.background, docDefinition.header, docDefinition.footer, docDefinition.images, docDefinition.watermark, docDefinition.pageBreakBefore);\n\tvar maxNumberPages = docDefinition.maxPagesNumber || -1;\n\tif (isNumber(maxNumberPages) && maxNumberPages > -1) {\n\t\tpages = pages.slice(0, maxNumberPages);\n\t}\n\n\t// if pageSize.height is set to Infinity, calculate the actual height of the page that\n\t// was laid out using the height of each of the items in the page.\n\tif (pageSize.height === Infinity) {\n\t\tvar pageHeight = calculatePageHeight(pages, docDefinition.pageMargins);\n\t\tthis.pdfKitDoc.options.size = [pageSize.width, pageHeight];\n\t}\n\n\trenderPages(pages, this.fontProvider, this.pdfKitDoc, options.progressCallback);\n\n\tif (options.autoPrint) {\n\t\tvar printActionRef = this.pdfKitDoc.ref({\n\t\t\tType: 'Action',\n\t\t\tS: 'Named',\n\t\t\tN: 'Print'\n\t\t});\n\t\tthis.pdfKitDoc._root.data.OpenAction = printActionRef;\n\t\tprintActionRef.end();\n\t}\n\treturn this.pdfKitDoc;\n};\n\nfunction setMetadata(docDefinition, pdfKitDoc) {\n\t// PDF standard has these properties reserved: Title, Author, Subject, Keywords,\n\t// Creator, Producer, CreationDate, ModDate, Trapped.\n\t// To keep the pdfmake api consistent, the info field are defined lowercase.\n\t// Custom properties don't contain a space.\n\tfunction standardizePropertyKey(key) {\n\t\tvar standardProperties = ['Title', 'Author', 'Subject', 'Keywords',\n\t\t\t'Creator', 'Producer', 'CreationDate', 'ModDate', 'Trapped'];\n\t\tvar standardizedKey = key.charAt(0).toUpperCase() + key.slice(1);\n\t\tif (standardProperties.indexOf(standardizedKey) !== -1) {\n\t\t\treturn standardizedKey;\n\t\t}\n\n\t\treturn key.replace(/\\s+/g, '');\n\t}\n\n\tpdfKitDoc.info.Producer = 'pdfmake';\n\tpdfKitDoc.info.Creator = 'pdfmake';\n\n\tif (docDefinition.info) {\n\t\tfor (var key in docDefinition.info) {\n\t\t\tvar value = docDefinition.info[key];\n\t\t\tif (value) {\n\t\t\t\tkey = standardizePropertyKey(key);\n\t\t\t\tpdfKitDoc.info[key] = value;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction calculatePageHeight(pages, margins) {\n\tfunction getItemHeight(item) {\n\t\tif (isFunction(item.item.getHeight)) {\n\t\t\treturn item.item.getHeight();\n\t\t} else if (item.item._height) {\n\t\t\treturn item.item._height;\n\t\t} else {\n\t\t\t// TODO: add support for next item types\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tvar fixedMargins = fixPageMargins(margins || 40);\n\tvar height = fixedMargins.top + fixedMargins.bottom;\n\tpages.forEach(function (page) {\n\t\tpage.items.forEach(function (item) {\n\t\t\theight += getItemHeight(item);\n\t\t});\n\t});\n\treturn height;\n}\n\nfunction fixPageSize(pageSize, pageOrientation) {\n\tfunction isNeedSwapPageSizes(pageOrientation) {\n\t\tif (isString(pageOrientation)) {\n\t\t\tpageOrientation = pageOrientation.toLowerCase();\n\t\t\treturn ((pageOrientation === 'portrait') && (size.width > size.height)) ||\n\t\t\t\t((pageOrientation === 'landscape') && (size.width < size.height));\n\t\t}\n\t\treturn false;\n\t}\n\n\t// if pageSize.height is set to auto, set the height to infinity so there are no page breaks.\n\tif (pageSize && pageSize.height === 'auto') {\n\t\tpageSize.height = Infinity;\n\t}\n\n\tvar size = pageSize2widthAndHeight(pageSize || 'A4');\n\tif (isNeedSwapPageSizes(pageOrientation)) { // swap page sizes\n\t\tsize = {width: size.height, height: size.width};\n\t}\n\tsize.orientation = size.width > size.height ? 'landscape' : 'portrait';\n\treturn size;\n}\n\nfunction fixPageMargins(margin) {\n\tif (!margin) {\n\t\treturn null;\n\t}\n\n\tif (isNumber(margin)) {\n\t\tmargin = {left: margin, right: margin, top: margin, bottom: margin};\n\t} else if (isArray(margin)) {\n\t\tif (margin.length === 2) {\n\t\t\tmargin = {left: margin[0], top: margin[1], right: margin[0], bottom: margin[1]};\n\t\t} else if (margin.length === 4) {\n\t\t\tmargin = {left: margin[0], top: margin[1], right: margin[2], bottom: margin[3]};\n\t\t} else {\n\t\t\tthrow 'Invalid pageMargins definition';\n\t\t}\n\t}\n\n\treturn margin;\n}\n\nfunction registerDefaultTableLayouts(layoutBuilder) {\n\tlayoutBuilder.registerTableLayouts({\n\t\tnoBorders: {\n\t\t\thLineWidth: function (i) {\n\t\t\t\treturn 0;\n\t\t\t},\n\t\t\tvLineWidth: function (i) {\n\t\t\t\treturn 0;\n\t\t\t},\n\t\t\tpaddingLeft: function (i) {\n\t\t\t\treturn i && 4 || 0;\n\t\t\t},\n\t\t\tpaddingRight: function (i, node) {\n\t\t\t\treturn (i < node.table.widths.length - 1) ? 4 : 0;\n\t\t\t}\n\t\t},\n\t\theaderLineOnly: {\n\t\t\thLineWidth: function (i, node) {\n\t\t\t\tif (i === 0 || i === node.table.body.length) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\treturn (i === node.table.headerRows) ? 2 : 0;\n\t\t\t},\n\t\t\tvLineWidth: function (i) {\n\t\t\t\treturn 0;\n\t\t\t},\n\t\t\tpaddingLeft: function (i) {\n\t\t\t\treturn i === 0 ? 0 : 8;\n\t\t\t},\n\t\t\tpaddingRight: function (i, node) {\n\t\t\t\treturn (i === node.table.widths.length - 1) ? 0 : 8;\n\t\t\t}\n\t\t},\n\t\tlightHorizontalLines: {\n\t\t\thLineWidth: function (i, node) {\n\t\t\t\tif (i === 0 || i === node.table.body.length) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\treturn (i === node.table.headerRows) ? 2 : 1;\n\t\t\t},\n\t\t\tvLineWidth: function (i) {\n\t\t\t\treturn 0;\n\t\t\t},\n\t\t\thLineColor: function (i) {\n\t\t\t\treturn i === 1 ? 'black' : '#aaa';\n\t\t\t},\n\t\t\tpaddingLeft: function (i) {\n\t\t\t\treturn i === 0 ? 0 : 8;\n\t\t\t},\n\t\t\tpaddingRight: function (i, node) {\n\t\t\t\treturn (i === node.table.widths.length - 1) ? 0 : 8;\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction pageSize2widthAndHeight(pageSize) {\n\tif (isString(pageSize)) {\n\t\tvar size = sizes[pageSize.toUpperCase()];\n\t\tif (!size) {\n\t\t\tthrow 'Page size ' + pageSize + ' not recognized';\n\t\t}\n\t\treturn {width: size[0], height: size[1]};\n\t}\n\n\treturn pageSize;\n}\n\nfunction updatePageOrientationInOptions(currentPage, pdfKitDoc) {\n\tvar previousPageOrientation = pdfKitDoc.options.size[0] > pdfKitDoc.options.size[1] ? 'landscape' : 'portrait';\n\n\tif (currentPage.pageSize.orientation !== previousPageOrientation) {\n\t\tvar width = pdfKitDoc.options.size[0];\n\t\tvar height = pdfKitDoc.options.size[1];\n\t\tpdfKitDoc.options.size = [height, width];\n\t}\n}\n\nfunction renderPages(pages, fontProvider, pdfKitDoc, progressCallback) {\n\tpdfKitDoc._pdfMakePages = pages;\n\tpdfKitDoc.addPage();\n\n\tvar totalItems = 0;\n\tif (progressCallback) {\n\t\tpages.forEach(function (page) {\n\t\t\ttotalItems += page.items.length;\n\t\t});\n\t}\n\n\tvar renderedItems = 0;\n\tprogressCallback = progressCallback || function () {};\n\n\tfor (var i = 0; i < pages.length; i++) {\n\t\tif (i > 0) {\n\t\t\tupdatePageOrientationInOptions(pages[i], pdfKitDoc);\n\t\t\tpdfKitDoc.addPage(pdfKitDoc.options);\n\t\t}\n\n\t\tvar page = pages[i];\n\t\tfor (var ii = 0, il = page.items.length; ii < il; ii++) {\n\t\t\tvar item = page.items[ii];\n\t\t\tswitch (item.type) {\n\t\t\t\tcase 'vector':\n\t\t\t\t\trenderVector(item.item, pdfKitDoc);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'line':\n\t\t\t\t\trenderLine(item.item, item.item.x, item.item.y, pdfKitDoc);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'image':\n\t\t\t\t\trenderImage(item.item, item.item.x, item.item.y, pdfKitDoc);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'beginClip':\n\t\t\t\t\tbeginClip(item.item, pdfKitDoc);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'endClip':\n\t\t\t\t\tendClip(pdfKitDoc);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\trenderedItems++;\n\t\t\tprogressCallback(renderedItems / totalItems);\n\t\t}\n\t\tif (page.watermark) {\n\t\t\trenderWatermark(page, pdfKitDoc);\n\t\t}\n\t}\n}\n\nfunction renderLine(line, x, y, pdfKitDoc) {\n\tif (line._pageNodeRef) {\n\t\tvar newWidth;\n\t\tvar diffWidth;\n\t\tvar textTools = new TextTools(null);\n\t\tvar pageNumber = line._pageNodeRef.positions[0].pageNumber.toString();\n\n\t\tline.inlines[0].text = pageNumber;\n\t\tline.inlines[0].linkToPage = pageNumber;\n\t\tnewWidth = textTools.widthOfString(line.inlines[0].text, line.inlines[0].font, line.inlines[0].fontSize, line.inlines[0].characterSpacing, line.inlines[0].fontFeatures);\n\t\tdiffWidth = line.inlines[0].width - newWidth;\n\t\tline.inlines[0].width = newWidth;\n\n\t\tswitch (line.inlines[0].alignment) {\n\t\t\tcase 'right':\n\t\t\t\tline.inlines[0].x += diffWidth;\n\t\t\t\tbreak;\n\t\t\tcase 'center':\n\t\t\t\tline.inlines[0].x += diffWidth / 2;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tx = x || 0;\n\ty = y || 0;\n\n\tvar lineHeight = line.getHeight();\n\tvar ascenderHeight = line.getAscenderHeight();\n\tvar descent = lineHeight - ascenderHeight;\n\n\ttextDecorator.drawBackground(line, x, y, pdfKitDoc);\n\n\t//TODO: line.optimizeInlines();\n\tfor (var i = 0, l = line.inlines.length; i < l; i++) {\n\t\tvar inline = line.inlines[i];\n\t\tvar shiftToBaseline = lineHeight - ((inline.font.ascender / 1000) * inline.fontSize) - descent;\n\t\tvar options = {\n\t\t\tlineBreak: false,\n\t\t\ttextWidth: inline.width,\n\t\t\tcharacterSpacing: inline.characterSpacing,\n\t\t\twordCount: 1,\n\t\t\tlink: inline.link\n\t\t};\n\n\t\tif (inline.fontFeatures) {\n\t\t\toptions.features = inline.fontFeatures;\n\t\t}\n\n\t\tpdfKitDoc.fill(inline.color || 'black');\n\n\t\tpdfKitDoc._font = inline.font;\n\t\tpdfKitDoc.fontSize(inline.fontSize);\n\t\tpdfKitDoc.text(inline.text, x + inline.x, y + shiftToBaseline, options);\n\n\t\tif (inline.linkToPage) {\n\t\t\tvar _ref = pdfKitDoc.ref({Type: 'Action', S: 'GoTo', D: [inline.linkToPage, 0, 0]}).end();\n\t\t\tpdfKitDoc.annotate(x + inline.x, y + shiftToBaseline, inline.width, inline.height, {Subtype: 'Link', Dest: [inline.linkToPage - 1, 'XYZ', null, null, null]});\n\t\t}\n\n\t}\n\n\ttextDecorator.drawDecorations(line, x, y, pdfKitDoc);\n}\n\nfunction renderWatermark(page, pdfKitDoc) {\n\tvar watermark = page.watermark;\n\n\tpdfKitDoc.fill(watermark.color);\n\tpdfKitDoc.opacity(watermark.opacity);\n\n\tpdfKitDoc.save();\n\n\tvar angle = Math.atan2(pdfKitDoc.page.height, pdfKitDoc.page.width) * -180 / Math.PI;\n\tpdfKitDoc.rotate(angle, {origin: [pdfKitDoc.page.width / 2, pdfKitDoc.page.height / 2]});\n\n\tvar x = pdfKitDoc.page.width / 2 - watermark.size.size.width / 2;\n\tvar y = pdfKitDoc.page.height / 2 - watermark.size.size.height / 4;\n\n\tpdfKitDoc._font = watermark.font;\n\tpdfKitDoc.fontSize(watermark.size.fontSize);\n\tpdfKitDoc.text(watermark.text, x, y, {lineBreak: false});\n\n\tpdfKitDoc.restore();\n}\n\nfunction renderVector(vector, pdfKitDoc) {\n\t//TODO: pdf optimization (there's no need to write all properties everytime)\n\tpdfKitDoc.lineWidth(vector.lineWidth || 1);\n\tif (vector.dash) {\n\t\tpdfKitDoc.dash(vector.dash.length, {space: vector.dash.space || vector.dash.length, phase: vector.dash.phase || 0});\n\t} else {\n\t\tpdfKitDoc.undash();\n\t}\n\tpdfKitDoc.lineJoin(vector.lineJoin || 'miter');\n\tpdfKitDoc.lineCap(vector.lineCap || 'butt');\n\n\t//TODO: clipping\n\n\tswitch (vector.type) {\n\t\tcase 'ellipse':\n\t\t\tpdfKitDoc.ellipse(vector.x, vector.y, vector.r1, vector.r2);\n\t\t\tbreak;\n\t\tcase 'rect':\n\t\t\tif (vector.r) {\n\t\t\t\tpdfKitDoc.roundedRect(vector.x, vector.y, vector.w, vector.h, vector.r);\n\t\t\t} else {\n\t\t\t\tpdfKitDoc.rect(vector.x, vector.y, vector.w, vector.h);\n\t\t\t}\n\n\t\t\tif (vector.linearGradient) {\n\t\t\t\tvar gradient = pdfKitDoc.linearGradient(vector.x, vector.y, vector.x + vector.w, vector.y);\n\t\t\t\tvar step = 1 / (vector.linearGradient.length - 1);\n\n\t\t\t\tfor (var i = 0; i < vector.linearGradient.length; i++) {\n\t\t\t\t\tgradient.stop(i * step, vector.linearGradient[i]);\n\t\t\t\t}\n\n\t\t\t\tvector.color = gradient;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'line':\n\t\t\tpdfKitDoc.moveTo(vector.x1, vector.y1);\n\t\t\tpdfKitDoc.lineTo(vector.x2, vector.y2);\n\t\t\tbreak;\n\t\tcase 'polyline':\n\t\t\tif (vector.points.length === 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tpdfKitDoc.moveTo(vector.points[0].x, vector.points[0].y);\n\t\t\tfor (var i = 1, l = vector.points.length; i < l; i++) {\n\t\t\t\tpdfKitDoc.lineTo(vector.points[i].x, vector.points[i].y);\n\t\t\t}\n\n\t\t\tif (vector.points.length > 1) {\n\t\t\t\tvar p1 = vector.points[0];\n\t\t\t\tvar pn = vector.points[vector.points.length - 1];\n\n\t\t\t\tif (vector.closePath || p1.x === pn.x && p1.y === pn.y) {\n\t\t\t\t\tpdfKitDoc.closePath();\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'path':\n\t\t\tpdfKitDoc.path(vector.d);\n\t\t\tbreak;\n\t}\n\n\tif (vector.color && vector.lineColor) {\n\t\tpdfKitDoc.fillColor(vector.color, vector.fillOpacity || 1);\n\t\tpdfKitDoc.strokeColor(vector.lineColor, vector.strokeOpacity || 1);\n\t\tpdfKitDoc.fillAndStroke();\n\t} else if (vector.color) {\n\t\tpdfKitDoc.fillColor(vector.color, vector.fillOpacity || 1);\n\t\tpdfKitDoc.fill();\n\t} else {\n\t\tpdfKitDoc.strokeColor(vector.lineColor || 'black', vector.strokeOpacity || 1);\n\t\tpdfKitDoc.stroke();\n\t}\n}\n\nfunction renderImage(image, x, y, pdfKitDoc) {\n\tpdfKitDoc.image(image.image, image.x, image.y, {width: image._width, height: image._height});\n\tif (image.link) {\n\t\tpdfKitDoc.link(image.x, image.y, image._width, image._height, image.link);\n\t}\n}\n\nfunction beginClip(rect, pdfKitDoc) {\n\tpdfKitDoc.save();\n\tpdfKitDoc.addContent('' + rect.x + ' ' + rect.y + ' ' + rect.width + ' ' + rect.height + ' re');\n\tpdfKitDoc.clip();\n}\n\nfunction endClip(pdfKitDoc) {\n\tpdfKitDoc.restore();\n}\n\nmodule.exports = PdfPrinter;\n\n\n/***/ }),\n/* 127 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar isArray = __webpack_require__(0).isArray;\n\nfunction typeName(bold, italics) {\n\tvar type = 'normal';\n\tif (bold && italics) {\n\t\ttype = 'bolditalics';\n\t} else if (bold) {\n\t\ttype = 'bold';\n\t} else if (italics) {\n\t\ttype = 'italics';\n\t}\n\treturn type;\n}\n\nfunction FontProvider(fontDescriptors, pdfKitDoc) {\n\tthis.fonts = {};\n\tthis.pdfKitDoc = pdfKitDoc;\n\tthis.fontCache = {};\n\n\tfor (var font in fontDescriptors) {\n\t\tif (fontDescriptors.hasOwnProperty(font)) {\n\t\t\tvar fontDef = fontDescriptors[font];\n\n\t\t\tthis.fonts[font] = {\n\t\t\t\tnormal: fontDef.normal,\n\t\t\t\tbold: fontDef.bold,\n\t\t\t\titalics: fontDef.italics,\n\t\t\t\tbolditalics: fontDef.bolditalics\n\t\t\t};\n\t\t}\n\t}\n}\n\nFontProvider.prototype.provideFont = function (familyName, bold, italics) {\n\tvar type = typeName(bold, italics);\n\tif (!this.fonts[familyName] || !this.fonts[familyName][type]) {\n\t\tthrow new Error('Font \\'' + familyName + '\\' in style \\'' + type + '\\' is not defined in the font section of the document definition.');\n\t}\n\n\tthis.fontCache[familyName] = this.fontCache[familyName] || {};\n\n\tif (!this.fontCache[familyName][type]) {\n\t\tvar def = this.fonts[familyName][type];\n\t\tif (!isArray(def)) {\n\t\t\tdef = [def];\n\t\t}\n\t\tthis.fontCache[familyName][type] = this.pdfKitDoc.font.apply(this.pdfKitDoc, def)._font;\n\t}\n\n\treturn this.fontCache[familyName][type];\n};\n\nmodule.exports = FontProvider;\n\n\n/***/ }),\n/* 128 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar TraversalTracker = __webpack_require__(77);\nvar DocPreprocessor = __webpack_require__(129);\nvar DocMeasure = __webpack_require__(130);\nvar DocumentContext = __webpack_require__(81);\nvar PageElementWriter = __webpack_require__(135);\nvar ColumnCalculator = __webpack_require__(44);\nvar TableProcessor = __webpack_require__(137);\nvar Line = __webpack_require__(82);\nvar isString = __webpack_require__(0).isString;\nvar isArray = __webpack_require__(0).isArray;\nvar pack = __webpack_require__(0).pack;\nvar offsetVector = __webpack_require__(0).offsetVector;\nvar fontStringify = __webpack_require__(0).fontStringify;\nvar isFunction = __webpack_require__(0).isFunction;\nvar TextTools = __webpack_require__(42);\nvar StyleContextStack = __webpack_require__(80);\n\nfunction addAll(target, otherArray) {\n\totherArray.forEach(function (item) {\n\t\ttarget.push(item);\n\t});\n}\n\n/**\n * Creates an instance of LayoutBuilder - layout engine which turns document-definition-object\n * into a set of pages, lines, inlines and vectors ready to be rendered into a PDF\n *\n * @param {Object} pageSize - an object defining page width and height\n * @param {Object} pageMargins - an object defining top, left, right and bottom margins\n */\nfunction LayoutBuilder(pageSize, pageMargins, imageMeasure) {\n\tthis.pageSize = pageSize;\n\tthis.pageMargins = pageMargins;\n\tthis.tracker = new TraversalTracker();\n\tthis.imageMeasure = imageMeasure;\n\tthis.tableLayouts = {};\n}\n\nLayoutBuilder.prototype.registerTableLayouts = function (tableLayouts) {\n\tthis.tableLayouts = pack(this.tableLayouts, tableLayouts);\n};\n\n/**\n * Executes layout engine on document-definition-object and creates an array of pages\n * containing positioned Blocks, Lines and inlines\n *\n * @param {Object} docStructure document-definition-object\n * @param {Object} fontProvider font provider\n * @param {Object} styleDictionary dictionary with style definitions\n * @param {Object} defaultStyle default style definition\n * @return {Array} an array of pages\n */\nLayoutBuilder.prototype.layoutDocument = function (docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark, pageBreakBeforeFct) {\n\n\tfunction addPageBreaksIfNecessary(linearNodeList, pages) {\n\n\t\tif (!isFunction(pageBreakBeforeFct)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlinearNodeList = linearNodeList.filter(function (node) {\n\t\t\treturn node.positions.length > 0;\n\t\t});\n\n\t\tlinearNodeList.forEach(function (node) {\n\t\t\tvar nodeInfo = {};\n\t\t\t[\n\t\t\t\t'id', 'text', 'ul', 'ol', 'table', 'image', 'qr', 'canvas', 'columns',\n\t\t\t\t'headlineLevel', 'style', 'pageBreak', 'pageOrientation',\n\t\t\t\t'width', 'height'\n\t\t\t].forEach(function (key) {\n\t\t\t\tif (node[key] !== undefined) {\n\t\t\t\t\tnodeInfo[key] = node[key];\n\t\t\t\t}\n\t\t\t});\n\t\t\tnodeInfo.startPosition = node.positions[0];\n\t\t\tnodeInfo.pageNumbers = node.positions.map(function (node) {\n\t\t\t\treturn node.pageNumber;\n\t\t\t}).filter(function (element, position, array) {\n\t\t\t\treturn array.indexOf(element) === position;\n\t\t\t});\n\t\t\tnodeInfo.pages = pages.length;\n\t\t\tnodeInfo.stack = isArray(node.stack);\n\n\t\t\tnode.nodeInfo = nodeInfo;\n\t\t});\n\n\t\treturn linearNodeList.some(function (node, index, followingNodeList) {\n\t\t\tif (node.pageBreak !== 'before' && !node.pageBreakCalculated) {\n\t\t\t\tnode.pageBreakCalculated = true;\n\t\t\t\tvar pageNumber = node.nodeInfo.pageNumbers[0];\n\n\t\t\t\tvar followingNodesOnPage = followingNodeList.slice(index + 1).filter(function (node0) {\n\t\t\t\t\treturn node0.nodeInfo.pageNumbers.indexOf(pageNumber) > -1;\n\t\t\t\t});\n\n\t\t\t\tvar nodesOnNextPage = followingNodeList.slice(index + 1).filter(function (node0) {\n\t\t\t\t\treturn node0.nodeInfo.pageNumbers.indexOf(pageNumber + 1) > -1;\n\t\t\t\t});\n\n\t\t\t\tvar previousNodesOnPage = followingNodeList.slice(0, index).filter(function (node0) {\n\t\t\t\t\treturn node0.nodeInfo.pageNumbers.indexOf(pageNumber) > -1;\n\t\t\t\t});\n\n\t\t\t\tif (\n\t\t\t\t\tpageBreakBeforeFct(\n\t\t\t\t\t\tnode.nodeInfo,\n\t\t\t\t\t\tfollowingNodesOnPage.map(function (node) {\n\t\t\t\t\t\t\treturn node.nodeInfo;\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tnodesOnNextPage.map(function (node) {\n\t\t\t\t\t\t\treturn node.nodeInfo;\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tpreviousNodesOnPage.map(function (node) {\n\t\t\t\t\t\t\treturn node.nodeInfo;\n\t\t\t\t\t\t}))) {\n\t\t\t\t\tnode.pageBreak = 'before';\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tthis.docPreprocessor = new DocPreprocessor();\n\tthis.docMeasure = new DocMeasure(fontProvider, styleDictionary, defaultStyle, this.imageMeasure, this.tableLayouts, images);\n\n\n\tfunction resetXYs(result) {\n\t\tresult.linearNodeList.forEach(function (node) {\n\t\t\tnode.resetXY();\n\t\t});\n\t}\n\n\tvar result = this.tryLayoutDocument(docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark);\n\twhile (addPageBreaksIfNecessary(result.linearNodeList, result.pages)) {\n\t\tresetXYs(result);\n\t\tresult = this.tryLayoutDocument(docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark);\n\t}\n\n\treturn result.pages;\n};\n\nLayoutBuilder.prototype.tryLayoutDocument = function (docStructure, fontProvider, styleDictionary, defaultStyle, background, header, footer, images, watermark, pageBreakBeforeFct) {\n\n\tthis.linearNodeList = [];\n\tdocStructure = this.docPreprocessor.preprocessDocument(docStructure);\n\tdocStructure = this.docMeasure.measureDocument(docStructure);\n\n\tthis.writer = new PageElementWriter(\n\t\tnew DocumentContext(this.pageSize, this.pageMargins), this.tracker);\n\n\tvar _this = this;\n\tthis.writer.context().tracker.startTracking('pageAdded', function () {\n\t\t_this.addBackground(background);\n\t});\n\n\tthis.addBackground(background);\n\tthis.processNode(docStructure);\n\tthis.addHeadersAndFooters(header, footer);\n\tif (watermark != null) {\n\t\tthis.addWatermark(watermark, fontProvider, defaultStyle);\n\t}\n\n\treturn {pages: this.writer.context().pages, linearNodeList: this.linearNodeList};\n};\n\n\nLayoutBuilder.prototype.addBackground = function (background) {\n\tvar backgroundGetter = isFunction(background) ? background : function () {\n\t\treturn background;\n\t};\n\n\tvar pageBackground = backgroundGetter(this.writer.context().page + 1);\n\n\tif (pageBackground) {\n\t\tvar pageSize = this.writer.context().getCurrentPage().pageSize;\n\t\tthis.writer.beginUnbreakableBlock(pageSize.width, pageSize.height);\n\t\tpageBackground = this.docPreprocessor.preprocessDocument(pageBackground);\n\t\tthis.processNode(this.docMeasure.measureDocument(pageBackground));\n\t\tthis.writer.commitUnbreakableBlock(0, 0);\n\t\tthis.writer.context().hasBackground = true;\n\t}\n};\n\nLayoutBuilder.prototype.addStaticRepeatable = function (headerOrFooter, sizeFunction) {\n\tthis.addDynamicRepeatable(function () {\n\t\treturn JSON.parse(JSON.stringify(headerOrFooter)); // copy to new object\n\t}, sizeFunction);\n};\n\nLayoutBuilder.prototype.addDynamicRepeatable = function (nodeGetter, sizeFunction) {\n\tvar pages = this.writer.context().pages;\n\n\tfor (var pageIndex = 0, l = pages.length; pageIndex < l; pageIndex++) {\n\t\tthis.writer.context().page = pageIndex;\n\n\t\tvar node = nodeGetter(pageIndex + 1, l, this.writer.context().pages[pageIndex].pageSize);\n\n\t\tif (node) {\n\t\t\tvar sizes = sizeFunction(this.writer.context().getCurrentPage().pageSize, this.pageMargins);\n\t\t\tthis.writer.beginUnbreakableBlock(sizes.width, sizes.height);\n\t\t\tnode = this.docPreprocessor.preprocessDocument(node);\n\t\t\tthis.processNode(this.docMeasure.measureDocument(node));\n\t\t\tthis.writer.commitUnbreakableBlock(sizes.x, sizes.y);\n\t\t}\n\t}\n};\n\nLayoutBuilder.prototype.addHeadersAndFooters = function (header, footer) {\n\tvar headerSizeFct = function (pageSize, pageMargins) {\n\t\treturn {\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t\twidth: pageSize.width,\n\t\t\theight: pageMargins.top\n\t\t};\n\t};\n\n\tvar footerSizeFct = function (pageSize, pageMargins) {\n\t\treturn {\n\t\t\tx: 0,\n\t\t\ty: pageSize.height - pageMargins.bottom,\n\t\t\twidth: pageSize.width,\n\t\t\theight: pageMargins.bottom\n\t\t};\n\t};\n\n\tif (isFunction(header)) {\n\t\tthis.addDynamicRepeatable(header, headerSizeFct);\n\t} else if (header) {\n\t\tthis.addStaticRepeatable(header, headerSizeFct);\n\t}\n\n\tif (isFunction(footer)) {\n\t\tthis.addDynamicRepeatable(footer, footerSizeFct);\n\t} else if (footer) {\n\t\tthis.addStaticRepeatable(footer, footerSizeFct);\n\t}\n};\n\nLayoutBuilder.prototype.addWatermark = function (watermark, fontProvider, defaultStyle) {\n\tif (isString(watermark)) {\n\t\twatermark = {'text': watermark};\n\t}\n\n\tif (!watermark.text) { // empty watermark text\n\t\treturn;\n\t}\n\n\twatermark.font = watermark.font || defaultStyle.font || 'Roboto';\n\twatermark.color = watermark.color || 'black';\n\twatermark.opacity = watermark.opacity || 0.6;\n\twatermark.bold = watermark.bold || false;\n\twatermark.italics = watermark.italics || false;\n\n\tvar watermarkObject = {\n\t\ttext: watermark.text,\n\t\tfont: fontProvider.provideFont(watermark.font, watermark.bold, watermark.italics),\n\t\tsize: getSize(this.pageSize, watermark, fontProvider),\n\t\tcolor: watermark.color,\n\t\topacity: watermark.opacity\n\t};\n\n\tvar pages = this.writer.context().pages;\n\tfor (var i = 0, l = pages.length; i < l; i++) {\n\t\tpages[i].watermark = watermarkObject;\n\t}\n\n\tfunction getSize(pageSize, watermark, fontProvider) {\n\t\tvar width = pageSize.width;\n\t\tvar height = pageSize.height;\n\t\tvar targetWidth = Math.sqrt(width * width + height * height) * 0.8; /* page diagonal * sample factor */\n\t\tvar textTools = new TextTools(fontProvider);\n\t\tvar styleContextStack = new StyleContextStack(null, {font: watermark.font, bold: watermark.bold, italics: watermark.italics});\n\t\tvar size;\n\n\t\t/**\n\t\t * Binary search the best font size.\n\t\t * Initial bounds [0, 1000]\n\t\t * Break when range < 1\n\t\t */\n\t\tvar a = 0;\n\t\tvar b = 1000;\n\t\tvar c = (a + b) / 2;\n\t\twhile (Math.abs(a - b) > 1) {\n\t\t\tstyleContextStack.push({\n\t\t\t\tfontSize: c\n\t\t\t});\n\t\t\tsize = textTools.sizeOfString(watermark.text, styleContextStack);\n\t\t\tif (size.width > targetWidth) {\n\t\t\t\tb = c;\n\t\t\t\tc = (a + b) / 2;\n\t\t\t} else if (size.width < targetWidth) {\n\t\t\t\ta = c;\n\t\t\t\tc = (a + b) / 2;\n\t\t\t}\n\t\t\tstyleContextStack.pop();\n\t\t}\n\t\t/*\n\t\t End binary search\n\t\t */\n\t\treturn {size: size, fontSize: c};\n\t}\n};\n\nfunction decorateNode(node) {\n\tvar x = node.x, y = node.y;\n\tnode.positions = [];\n\n\tif (isArray(node.canvas)) {\n\t\tnode.canvas.forEach(function (vector) {\n\t\t\tvar x = vector.x, y = vector.y, x1 = vector.x1, y1 = vector.y1, x2 = vector.x2, y2 = vector.y2;\n\t\t\tvector.resetXY = function () {\n\t\t\t\tvector.x = x;\n\t\t\t\tvector.y = y;\n\t\t\t\tvector.x1 = x1;\n\t\t\t\tvector.y1 = y1;\n\t\t\t\tvector.x2 = x2;\n\t\t\t\tvector.y2 = y2;\n\t\t\t};\n\t\t});\n\t}\n\n\tnode.resetXY = function () {\n\t\tnode.x = x;\n\t\tnode.y = y;\n\t\tif (isArray(node.canvas)) {\n\t\t\tnode.canvas.forEach(function (vector) {\n\t\t\t\tvector.resetXY();\n\t\t\t});\n\t\t}\n\t};\n}\n\nLayoutBuilder.prototype.processNode = function (node) {\n\tvar self = this;\n\n\tthis.linearNodeList.push(node);\n\tdecorateNode(node);\n\n\tapplyMargins(function () {\n\t\tvar unbreakable = node.unbreakable;\n\t\tif (unbreakable) {\n\t\t\tself.writer.beginUnbreakableBlock();\n\t\t}\n\n\t\tvar absPosition = node.absolutePosition;\n\t\tif (absPosition) {\n\t\t\tself.writer.context().beginDetachedBlock();\n\t\t\tself.writer.context().moveTo(absPosition.x || 0, absPosition.y || 0);\n\t\t}\n\n\t\tvar relPosition = node.relativePosition;\n\t\tif (relPosition) {\n\t\t\tself.writer.context().beginDetachedBlock();\n\t\t\tself.writer.context().moveTo((relPosition.x || 0) + self.writer.context().x, (relPosition.y || 0) + self.writer.context().y);\n\t\t}\n\n\t\tif (node.stack) {\n\t\t\tself.processVerticalContainer(node);\n\t\t} else if (node.columns) {\n\t\t\tself.processColumns(node);\n\t\t} else if (node.ul) {\n\t\t\tself.processList(false, node);\n\t\t} else if (node.ol) {\n\t\t\tself.processList(true, node);\n\t\t} else if (node.table) {\n\t\t\tself.processTable(node);\n\t\t} else if (node.text !== undefined) {\n\t\t\tself.processLeaf(node);\n\t\t} else if (node.toc) {\n\t\t\tself.processToc(node);\n\t\t} else if (node.image) {\n\t\t\tself.processImage(node);\n\t\t} else if (node.canvas) {\n\t\t\tself.processCanvas(node);\n\t\t} else if (node.qr) {\n\t\t\tself.processQr(node);\n\t\t} else if (!node._span) {\n\t\t\tthrow 'Unrecognized document structure: ' + JSON.stringify(node, fontStringify);\n\t\t}\n\n\t\tif (absPosition || relPosition) {\n\t\t\tself.writer.context().endDetachedBlock();\n\t\t}\n\n\t\tif (unbreakable) {\n\t\t\tself.writer.commitUnbreakableBlock();\n\t\t}\n\t});\n\n\tfunction applyMargins(callback) {\n\t\tvar margin = node._margin;\n\n\t\tif (node.pageBreak === 'before') {\n\t\t\tself.writer.moveToNextPage(node.pageOrientation);\n\t\t}\n\n\t\tif (margin) {\n\t\t\tself.writer.context().moveDown(margin[1]);\n\t\t\tself.writer.context().addMargin(margin[0], margin[2]);\n\t\t}\n\n\t\tcallback();\n\n\t\tif (margin) {\n\t\t\tself.writer.context().addMargin(-margin[0], -margin[2]);\n\t\t\tself.writer.context().moveDown(margin[3]);\n\t\t}\n\n\t\tif (node.pageBreak === 'after') {\n\t\t\tself.writer.moveToNextPage(node.pageOrientation);\n\t\t}\n\t}\n};\n\n// vertical container\nLayoutBuilder.prototype.processVerticalContainer = function (node) {\n\tvar self = this;\n\tnode.stack.forEach(function (item) {\n\t\tself.processNode(item);\n\t\taddAll(node.positions, item.positions);\n\n\t\t//TODO: paragraph gap\n\t});\n};\n\n// columns\nLayoutBuilder.prototype.processColumns = function (columnNode) {\n\tvar columns = columnNode.columns;\n\tvar availableWidth = this.writer.context().availableWidth;\n\tvar gaps = gapArray(columnNode._gap);\n\n\tif (gaps) {\n\t\tavailableWidth -= (gaps.length - 1) * columnNode._gap;\n\t}\n\n\tColumnCalculator.buildColumnWidths(columns, availableWidth);\n\tvar result = this.processRow(columns, columns, gaps);\n\taddAll(columnNode.positions, result.positions);\n\n\n\tfunction gapArray(gap) {\n\t\tif (!gap) {\n\t\t\treturn null;\n\t\t}\n\n\t\tvar gaps = [];\n\t\tgaps.push(0);\n\n\t\tfor (var i = columns.length - 1; i > 0; i--) {\n\t\t\tgaps.push(gap);\n\t\t}\n\n\t\treturn gaps;\n\t}\n};\n\nLayoutBuilder.prototype.processRow = function (columns, widths, gaps, tableBody, tableRow, height) {\n\tvar self = this;\n\tvar pageBreaks = [], positions = [];\n\n\tthis.tracker.auto('pageChanged', storePageBreakData, function () {\n\t\twidths = widths || columns;\n\n\t\tself.writer.context().beginColumnGroup();\n\n\t\tfor (var i = 0, l = columns.length; i < l; i++) {\n\t\t\tvar column = columns[i];\n\t\t\tvar width = widths[i]._calcWidth;\n\t\t\tvar leftOffset = colLeftOffset(i);\n\n\t\t\tif (column.colSpan && column.colSpan > 1) {\n\t\t\t\tfor (var j = 1; j < column.colSpan; j++) {\n\t\t\t\t\twidth += widths[++i]._calcWidth + gaps[i];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tself.writer.context().beginColumn(width, leftOffset, getEndingCell(column, i));\n\t\t\tif (!column._span) {\n\t\t\t\tself.processNode(column);\n\t\t\t\taddAll(positions, column.positions);\n\t\t\t} else if (column._columnEndingContext) {\n\t\t\t\t// row-span ending\n\t\t\t\tself.writer.context().markEnding(column);\n\t\t\t}\n\t\t}\n\n\t\tself.writer.context().completeColumnGroup(height);\n\t});\n\n\treturn {pageBreaks: pageBreaks, positions: positions};\n\n\tfunction storePageBreakData(data) {\n\t\tvar pageDesc;\n\n\t\tfor (var i = 0, l = pageBreaks.length; i < l; i++) {\n\t\t\tvar desc = pageBreaks[i];\n\t\t\tif (desc.prevPage === data.prevPage) {\n\t\t\t\tpageDesc = desc;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!pageDesc) {\n\t\t\tpageDesc = data;\n\t\t\tpageBreaks.push(pageDesc);\n\t\t}\n\t\tpageDesc.prevY = Math.max(pageDesc.prevY, data.prevY);\n\t\tpageDesc.y = Math.min(pageDesc.y, data.y);\n\t}\n\n\tfunction colLeftOffset(i) {\n\t\tif (gaps && gaps.length > i) {\n\t\t\treturn gaps[i];\n\t\t}\n\t\treturn 0;\n\t}\n\n\tfunction getEndingCell(column, columnIndex) {\n\t\tif (column.rowSpan && column.rowSpan > 1) {\n\t\t\tvar endingRow = tableRow + column.rowSpan - 1;\n\t\t\tif (endingRow >= tableBody.length) {\n\t\t\t\tthrow 'Row span for column ' + columnIndex + ' (with indexes starting from 0) exceeded row count';\n\t\t\t}\n\t\t\treturn tableBody[endingRow][columnIndex];\n\t\t}\n\n\t\treturn null;\n\t}\n};\n\n// lists\nLayoutBuilder.prototype.processList = function (orderedList, node) {\n\tvar self = this,\n\t\titems = orderedList ? node.ol : node.ul,\n\t\tgapSize = node._gapSize;\n\n\tthis.writer.context().addMargin(gapSize.width);\n\n\tvar nextMarker;\n\tthis.tracker.auto('lineAdded', addMarkerToFirstLeaf, function () {\n\t\titems.forEach(function (item) {\n\t\t\tnextMarker = item.listMarker;\n\t\t\tself.processNode(item);\n\t\t\taddAll(node.positions, item.positions);\n\t\t});\n\t});\n\n\tthis.writer.context().addMargin(-gapSize.width);\n\n\tfunction addMarkerToFirstLeaf(line) {\n\t\t// I'm not very happy with the way list processing is implemented\n\t\t// (both code and algorithm should be rethinked)\n\t\tif (nextMarker) {\n\t\t\tvar marker = nextMarker;\n\t\t\tnextMarker = null;\n\n\t\t\tif (marker.canvas) {\n\t\t\t\tvar vector = marker.canvas[0];\n\n\t\t\t\toffsetVector(vector, -marker._minWidth, 0);\n\t\t\t\tself.writer.addVector(vector);\n\t\t\t} else if (marker._inlines) {\n\t\t\t\tvar markerLine = new Line(self.pageSize.width);\n\t\t\t\tmarkerLine.addInline(marker._inlines[0]);\n\t\t\t\tmarkerLine.x = -marker._minWidth;\n\t\t\t\tmarkerLine.y = line.getAscenderHeight() - markerLine.getAscenderHeight();\n\t\t\t\tself.writer.addLine(markerLine, true);\n\t\t\t}\n\t\t}\n\t}\n};\n\n// tables\nLayoutBuilder.prototype.processTable = function (tableNode) {\n\tvar processor = new TableProcessor(tableNode);\n\n\tprocessor.beginTable(this.writer);\n\n\tvar rowHeights = tableNode.table.heights;\n\tfor (var i = 0, l = tableNode.table.body.length; i < l; i++) {\n\t\tprocessor.beginRow(i, this.writer);\n\n\t\tvar height;\n\t\tif (isFunction(rowHeights)) {\n\t\t\theight = rowHeights(i);\n\t\t} else if (isArray(rowHeights)) {\n\t\t\theight = rowHeights[i];\n\t\t} else {\n\t\t\theight = rowHeights;\n\t\t}\n\n\t\tif (height === 'auto') {\n\t\t\theight = undefined;\n\t\t}\n\n\t\tvar result = this.processRow(tableNode.table.body[i], tableNode.table.widths, tableNode._offsets.offsets, tableNode.table.body, i, height);\n\t\taddAll(tableNode.positions, result.positions);\n\n\t\tprocessor.endRow(i, this.writer, result.pageBreaks);\n\t}\n\n\tprocessor.endTable(this.writer);\n};\n\n// leafs (texts)\nLayoutBuilder.prototype.processLeaf = function (node) {\n\tvar line = this.buildNextLine(node);\n\tvar currentHeight = (line) ? line.getHeight() : 0;\n\tvar maxHeight = node.maxHeight || -1;\n\n\tif (node._tocItemRef) {\n\t\tline._pageNodeRef = node._tocItemRef;\n\t}\n\n\tif (node._pageRef) {\n\t\tline._pageNodeRef = node._pageRef._nodeRef;\n\t}\n\n\twhile (line && (maxHeight === -1 || currentHeight < maxHeight)) {\n\t\tvar positions = this.writer.addLine(line);\n\t\tnode.positions.push(positions);\n\t\tline = this.buildNextLine(node);\n\t\tif (line) {\n\t\t\tcurrentHeight += line.getHeight();\n\t\t}\n\t}\n};\n\nLayoutBuilder.prototype.processToc = function (node) {\n\tif (node.toc.title) {\n\t\tthis.processNode(node.toc.title);\n\t}\n\tthis.processNode(node.toc._table);\n};\n\nLayoutBuilder.prototype.buildNextLine = function (textNode) {\n\n\tfunction cloneInline(inline) {\n\t\tvar newInline = inline.constructor();\n\t\tfor (var key in inline) {\n\t\t\tnewInline[key] = inline[key];\n\t\t}\n\t\treturn newInline;\n\t}\n\n\tif (!textNode._inlines || textNode._inlines.length === 0) {\n\t\treturn null;\n\t}\n\n\tvar line = new Line(this.writer.context().availableWidth);\n\tvar textTools = new TextTools(null);\n\n\twhile (textNode._inlines && textNode._inlines.length > 0 && line.hasEnoughSpaceForInline(textNode._inlines[0])) {\n\t\tvar inline = textNode._inlines.shift();\n\n\t\tif (!inline.noWrap && inline.text.length > 1 && inline.width > line.maxWidth) {\n\t\t\tvar widthPerChar = inline.width / inline.text.length;\n\t\t\tvar maxChars = Math.floor(line.maxWidth / widthPerChar);\n\t\t\tif (maxChars < 1) {\n\t\t\t\tmaxChars = 1;\n\t\t\t}\n\t\t\tif (maxChars < inline.text.length) {\n\t\t\t\tvar newInline = cloneInline(inline);\n\n\t\t\t\tnewInline.text = inline.text.substr(maxChars);\n\t\t\t\tinline.text = inline.text.substr(0, maxChars);\n\n\t\t\t\tnewInline.width = textTools.widthOfString(newInline.text, newInline.font, newInline.fontSize, newInline.characterSpacing, newInline.fontFeatures);\n\t\t\t\tinline.width = textTools.widthOfString(inline.text, inline.font, inline.fontSize, inline.characterSpacing, inline.fontFeatures);\n\n\t\t\t\ttextNode._inlines.unshift(newInline);\n\t\t\t}\n\t\t}\n\n\t\tline.addInline(inline);\n\t}\n\n\tline.lastLineInParagraph = textNode._inlines.length === 0;\n\n\treturn line;\n};\n\n// images\nLayoutBuilder.prototype.processImage = function (node) {\n\tvar position = this.writer.addImage(node);\n\tnode.positions.push(position);\n};\n\nLayoutBuilder.prototype.processCanvas = function (node) {\n\tvar height = node._minHeight;\n\n\tif (node.absolutePosition === undefined && this.writer.context().availableHeight < height) {\n\t\t// TODO: support for canvas larger than a page\n\t\t// TODO: support for other overflow methods\n\n\t\tthis.writer.moveToNextPage();\n\t}\n\n\tthis.writer.alignCanvas(node);\n\n\tnode.canvas.forEach(function (vector) {\n\t\tvar position = this.writer.addVector(vector);\n\t\tnode.positions.push(position);\n\t}, this);\n\n\tthis.writer.context().moveDown(height);\n};\n\nLayoutBuilder.prototype.processQr = function (node) {\n\tvar position = this.writer.addQr(node);\n\tnode.positions.push(position);\n};\n\nmodule.exports = LayoutBuilder;\n\n\n/***/ }),\n/* 129 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(Buffer) {\n\nvar isString = __webpack_require__(0).isString;\nvar isNumber = __webpack_require__(0).isNumber;\nvar isBoolean = __webpack_require__(0).isBoolean;\nvar isArray = __webpack_require__(0).isArray;\nvar isUndefined = __webpack_require__(0).isUndefined;\nvar fontStringify = __webpack_require__(0).fontStringify;\n\nfunction DocPreprocessor() {\n\n}\n\nDocPreprocessor.prototype.preprocessDocument = function (docStructure) {\n\tthis.tocs = [];\n\tthis.nodeReferences = [];\n\treturn this.preprocessNode(docStructure);\n};\n\nDocPreprocessor.prototype.preprocessNode = function (node) {\n\t// expand shortcuts and casting values\n\tif (isArray(node)) {\n\t\tnode = {stack: node};\n\t} else if (isString(node)) {\n\t\tnode = {text: node};\n\t} else if (isNumber(node) || isBoolean(node)) {\n\t\tnode = {text: node.toString()};\n\t} else if (node === null) {\n\t\tnode = {text: ''};\n\t} else if (Object.keys(node).length === 0) { // empty object\n\t\tnode = {text: ''};\n\t}\n\n\tif (node.columns) {\n\t\treturn this.preprocessColumns(node);\n\t} else if (node.stack) {\n\t\treturn this.preprocessVerticalContainer(node);\n\t} else if (node.ul) {\n\t\treturn this.preprocessList(node);\n\t} else if (node.ol) {\n\t\treturn this.preprocessList(node);\n\t} else if (node.table) {\n\t\treturn this.preprocessTable(node);\n\t} else if (node.text !== undefined) {\n\t\treturn this.preprocessText(node);\n\t} else if (node.toc) {\n\t\treturn this.preprocessToc(node);\n\t} else if (node.image) {\n\t\treturn this.preprocessImage(node);\n\t} else if (node.canvas) {\n\t\treturn this.preprocessCanvas(node);\n\t} else if (node.qr) {\n\t\treturn this.preprocessQr(node);\n\t} else if (node.pageReference || node.textReference) {\n\t\treturn this.preprocessText(node);\n\t} else {\n\t\tthrow 'Unrecognized document structure: ' + JSON.stringify(node, fontStringify);\n\t}\n};\n\nDocPreprocessor.prototype.preprocessColumns = function (node) {\n\tvar columns = node.columns;\n\n\tfor (var i = 0, l = columns.length; i < l; i++) {\n\t\tcolumns[i] = this.preprocessNode(columns[i]);\n\t}\n\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessVerticalContainer = function (node) {\n\tvar items = node.stack;\n\n\tfor (var i = 0, l = items.length; i < l; i++) {\n\t\titems[i] = this.preprocessNode(items[i]);\n\t}\n\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessList = function (node) {\n\tvar items = node.ul || node.ol;\n\n\tfor (var i = 0, l = items.length; i < l; i++) {\n\t\titems[i] = this.preprocessNode(items[i]);\n\t}\n\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessTable = function (node) {\n\tvar col, row, cols, rows;\n\n\tfor (col = 0, cols = node.table.body[0].length; col < cols; col++) {\n\t\tfor (row = 0, rows = node.table.body.length; row < rows; row++) {\n\t\t\tvar rowData = node.table.body[row];\n\t\t\tvar data = rowData[col];\n\t\t\tif (data !== undefined) {\n\t\t\t\tif (data === null) { // transform to object\n\t\t\t\t\tdata = '';\n\t\t\t\t}\n\t\t\t\tif (!data._span) {\n\t\t\t\t\trowData[col] = this.preprocessNode(data);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessText = function (node) {\n\tif (node.tocItem) {\n\t\tif (!isArray(node.tocItem)) {\n\t\t\tnode.tocItem = [node.tocItem];\n\t\t}\n\n\t\tfor (var i = 0, l = node.tocItem.length; i < l; i++) {\n\t\t\tif (!isString(node.tocItem[i])) {\n\t\t\t\tnode.tocItem[i] = '_default_';\n\t\t\t}\n\n\t\t\tvar tocItemId = node.tocItem[i];\n\n\t\t\tif (!this.tocs[tocItemId]) {\n\t\t\t\tthis.tocs[tocItemId] = {toc: {_items: [], _pseudo: true}};\n\t\t\t}\n\n\t\t\tthis.tocs[tocItemId].toc._items.push(node);\n\t\t}\n\t}\n\n\tif (node.id) {\n\t\tif (this.nodeReferences[node.id]) {\n\t\t\tif (!this.nodeReferences[node.id]._pseudo) {\n\t\t\t\tthrow \"Node id '\" + node.id + \"' already exists\";\n\t\t\t}\n\n\t\t\tthis.nodeReferences[node.id]._nodeRef = node;\n\t\t\tthis.nodeReferences[node.id]._pseudo = false;\n\t\t} else {\n\t\t\tthis.nodeReferences[node.id] = {_nodeRef: node};\n\t\t}\n\t}\n\n\tif (node.pageReference) {\n\t\tif (!this.nodeReferences[node.pageReference]) {\n\t\t\tthis.nodeReferences[node.pageReference] = {_nodeRef: {}, _pseudo: true};\n\t\t}\n\t\tnode.text = '00000';\n\t\tnode._pageRef = this.nodeReferences[node.pageReference];\n\t}\n\n\tif (node.textReference) {\n\t\tif (!this.nodeReferences[node.textReference]) {\n\t\t\tthis.nodeReferences[node.textReference] = {_nodeRef: {}, _pseudo: true};\n\t\t}\n\n\t\tnode.text = '';\n\t\tnode._textRef = this.nodeReferences[node.textReference];\n\t}\n\n\tif (node.text && node.text.text) {\n\t\tnode.text = [this.preprocessNode(node.text)];\n\t}\n\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessToc = function (node) {\n\tif (!node.toc.id) {\n\t\tnode.toc.id = '_default_';\n\t}\n\n\tnode.toc.title = node.toc.title ? this.preprocessNode(node.toc.title) : null;\n\tnode.toc._items = [];\n\n\tif (this.tocs[node.toc.id]) {\n\t\tif (!this.tocs[node.toc.id].toc._pseudo) {\n\t\t\tthrow \"TOC '\" + node.toc.id + \"' already exists\";\n\t\t}\n\n\t\tnode.toc._items = this.tocs[node.toc.id].toc._items;\n\t}\n\n\tthis.tocs[node.toc.id] = node;\n\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessImage = function (node) {\n\tif (!isUndefined(node.image.type) && !isUndefined(node.image.data) && (node.image.type === 'Buffer') && isArray(node.image.data)) {\n\t\tnode.image = Buffer.from(node.image.data);\n\t}\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessCanvas = function (node) {\n\treturn node;\n};\n\nDocPreprocessor.prototype.preprocessQr = function (node) {\n\treturn node;\n};\n\nmodule.exports = DocPreprocessor;\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 130 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/*eslint no-unused-vars: [\"error\", {\"args\": \"none\"}]*/\n\n\n\nvar TextTools = __webpack_require__(42);\nvar StyleContextStack = __webpack_require__(80);\nvar ColumnCalculator = __webpack_require__(44);\nvar isString = __webpack_require__(0).isString;\nvar isNumber = __webpack_require__(0).isNumber;\nvar isObject = __webpack_require__(0).isObject;\nvar isArray = __webpack_require__(0).isArray;\nvar fontStringify = __webpack_require__(0).fontStringify;\nvar pack = __webpack_require__(0).pack;\nvar qrEncoder = __webpack_require__(134);\n\n/**\n * @private\n */\nfunction DocMeasure(fontProvider, styleDictionary, defaultStyle, imageMeasure, tableLayouts, images) {\n\tthis.textTools = new TextTools(fontProvider);\n\tthis.styleStack = new StyleContextStack(styleDictionary, defaultStyle);\n\tthis.imageMeasure = imageMeasure;\n\tthis.tableLayouts = tableLayouts;\n\tthis.images = images;\n\tthis.autoImageIndex = 1;\n}\n\n/**\n * Measures all nodes and sets min/max-width properties required for the second\n * layout-pass.\n * @param  {Object} docStructure document-definition-object\n * @return {Object}              document-measurement-object\n */\nDocMeasure.prototype.measureDocument = function (docStructure) {\n\treturn this.measureNode(docStructure);\n};\n\nDocMeasure.prototype.measureNode = function (node) {\n\n\tvar self = this;\n\n\treturn this.styleStack.auto(node, function () {\n\t\t// TODO: refactor + rethink whether this is the proper way to handle margins\n\t\tnode._margin = getNodeMargin(node);\n\n\t\tif (node.columns) {\n\t\t\treturn extendMargins(self.measureColumns(node));\n\t\t} else if (node.stack) {\n\t\t\treturn extendMargins(self.measureVerticalContainer(node));\n\t\t} else if (node.ul) {\n\t\t\treturn extendMargins(self.measureUnorderedList(node));\n\t\t} else if (node.ol) {\n\t\t\treturn extendMargins(self.measureOrderedList(node));\n\t\t} else if (node.table) {\n\t\t\treturn extendMargins(self.measureTable(node));\n\t\t} else if (node.text !== undefined) {\n\t\t\treturn extendMargins(self.measureLeaf(node));\n\t\t} else if (node.toc) {\n\t\t\treturn extendMargins(self.measureToc(node));\n\t\t} else if (node.image) {\n\t\t\treturn extendMargins(self.measureImage(node));\n\t\t} else if (node.canvas) {\n\t\t\treturn extendMargins(self.measureCanvas(node));\n\t\t} else if (node.qr) {\n\t\t\treturn extendMargins(self.measureQr(node));\n\t\t} else {\n\t\t\tthrow 'Unrecognized document structure: ' + JSON.stringify(node, fontStringify);\n\t\t}\n\t});\n\n\tfunction extendMargins(node) {\n\t\tvar margin = node._margin;\n\n\t\tif (margin) {\n\t\t\tnode._minWidth += margin[0] + margin[2];\n\t\t\tnode._maxWidth += margin[0] + margin[2];\n\t\t}\n\n\t\treturn node;\n\t}\n\n\tfunction getNodeMargin() {\n\n\t\tfunction processSingleMargins(node, currentMargin) {\n\t\t\tif (node.marginLeft || node.marginTop || node.marginRight || node.marginBottom) {\n\t\t\t\treturn [\n\t\t\t\t\tnode.marginLeft || currentMargin[0] || 0,\n\t\t\t\t\tnode.marginTop || currentMargin[1] || 0,\n\t\t\t\t\tnode.marginRight || currentMargin[2] || 0,\n\t\t\t\t\tnode.marginBottom || currentMargin[3] || 0\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn currentMargin;\n\t\t}\n\n\t\tfunction flattenStyleArray(styleArray) {\n\t\t\tvar flattenedStyles = {};\n\t\t\tfor (var i = styleArray.length - 1; i >= 0; i--) {\n\t\t\t\tvar styleName = styleArray[i];\n\t\t\t\tvar style = self.styleStack.styleDictionary[styleName];\n\t\t\t\tfor (var key in style) {\n\t\t\t\t\tif (style.hasOwnProperty(key)) {\n\t\t\t\t\t\tflattenedStyles[key] = style[key];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn flattenedStyles;\n\t\t}\n\n\t\tfunction convertMargin(margin) {\n\t\t\tif (isNumber(margin)) {\n\t\t\t\tmargin = [margin, margin, margin, margin];\n\t\t\t} else if (isArray(margin)) {\n\t\t\t\tif (margin.length === 2) {\n\t\t\t\t\tmargin = [margin[0], margin[1], margin[0], margin[1]];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn margin;\n\t\t}\n\n\t\tvar margin = [undefined, undefined, undefined, undefined];\n\n\t\tif (node.style) {\n\t\t\tvar styleArray = isArray(node.style) ? node.style : [node.style];\n\t\t\tvar flattenedStyleArray = flattenStyleArray(styleArray);\n\n\t\t\tif (flattenedStyleArray) {\n\t\t\t\tmargin = processSingleMargins(flattenedStyleArray, margin);\n\t\t\t}\n\n\t\t\tif (flattenedStyleArray.margin) {\n\t\t\t\tmargin = convertMargin(flattenedStyleArray.margin);\n\t\t\t}\n\t\t}\n\n\t\tmargin = processSingleMargins(node, margin);\n\n\t\tif (node.margin) {\n\t\t\tmargin = convertMargin(node.margin);\n\t\t}\n\n\t\tif (margin[0] === undefined && margin[1] === undefined && margin[2] === undefined && margin[3] === undefined) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\treturn margin;\n\t\t}\n\t}\n};\n\nDocMeasure.prototype.convertIfBase64Image = function (node) {\n\tif (/^data:image\\/(jpeg|jpg|png);base64,/.test(node.image)) {\n\t\tvar label = '$$pdfmake$$' + this.autoImageIndex++;\n\t\tthis.images[label] = node.image;\n\t\tnode.image = label;\n\t}\n};\n\nDocMeasure.prototype.measureImage = function (node) {\n\tif (this.images) {\n\t\tthis.convertIfBase64Image(node);\n\t}\n\n\tvar imageSize = this.imageMeasure.measureImage(node.image);\n\n\tif (node.fit) {\n\t\tvar factor = (imageSize.width / imageSize.height > node.fit[0] / node.fit[1]) ? node.fit[0] / imageSize.width : node.fit[1] / imageSize.height;\n\t\tnode._width = node._minWidth = node._maxWidth = imageSize.width * factor;\n\t\tnode._height = imageSize.height * factor;\n\t} else {\n\t\tnode._width = node._minWidth = node._maxWidth = node.width || imageSize.width;\n\t\tnode._height = node.height || (imageSize.height * node._width / imageSize.width);\n\n\t\tif (isNumber(node.maxWidth) && node.maxWidth < node._width) {\n\t\t\tnode._width = node._minWidth = node._maxWidth = node.maxWidth;\n\t\t\tnode._height = node._width * imageSize.height / imageSize.width;\n\t\t}\n\n\t\tif (isNumber(node.maxHeight) && node.maxHeight < node._height) {\n\t\t\tnode._height = node.maxHeight;\n\t\t\tnode._width = node._minWidth = node._maxWidth = node._height * imageSize.width / imageSize.height;\n\t\t}\n\n\t\tif (isNumber(node.minWidth) && node.minWidth > node._width) {\n\t\t\tnode._width = node._minWidth = node._maxWidth = node.minWidth;\n\t\t\tnode._height = node._width * imageSize.height / imageSize.width;\n\t\t}\n\n\t\tif (isNumber(node.minHeight) && node.minHeight > node._height) {\n\t\t\tnode._height = node.minHeight;\n\t\t\tnode._width = node._minWidth = node._maxWidth = node._height * imageSize.width / imageSize.height;\n\t\t}\n\t}\n\n\tnode._alignment = this.styleStack.getProperty('alignment');\n\treturn node;\n};\n\nDocMeasure.prototype.measureLeaf = function (node) {\n\n\tif (node._textRef && node._textRef._nodeRef.text) {\n\t\tnode.text = node._textRef._nodeRef.text;\n\t}\n\n\t// Make sure style properties of the node itself are considered when building inlines.\n\t// We could also just pass [node] to buildInlines, but that fails for bullet points.\n\tvar styleStack = this.styleStack.clone();\n\tstyleStack.push(node);\n\n\tvar data = this.textTools.buildInlines(node.text, styleStack);\n\n\tnode._inlines = data.items;\n\tnode._minWidth = data.minWidth;\n\tnode._maxWidth = data.maxWidth;\n\n\treturn node;\n};\n\nDocMeasure.prototype.measureToc = function (node) {\n\tif (node.toc.title) {\n\t\tnode.toc.title = this.measureNode(node.toc.title);\n\t}\n\n\tvar body = [];\n\tvar textStyle = node.toc.textStyle || {};\n\tvar numberStyle = node.toc.numberStyle || textStyle;\n\tvar textMargin = node.toc.textMargin || [0, 0, 0, 0];\n\tfor (var i = 0, l = node.toc._items.length; i < l; i++) {\n\t\tvar item = node.toc._items[i];\n\t\tvar lineStyle = node.toc._items[i].tocStyle || textStyle;\n\t\tvar lineMargin = node.toc._items[i].tocMargin || textMargin;\n\t\tbody.push([\n\t\t\t{text: item.text, alignment: 'left', style: lineStyle, margin: lineMargin},\n\t\t\t{text: '00000', alignment: 'right', _tocItemRef: item, style: numberStyle, margin: [0, lineMargin[1], 0, lineMargin[3]]}\n\t\t]);\n\t}\n\n\n\tnode.toc._table = {\n\t\ttable: {\n\t\t\tdontBreakRows: true,\n\t\t\twidths: ['*', 'auto'],\n\t\t\tbody: body\n\t\t},\n\t\tlayout: 'noBorders'\n\t};\n\n\tnode.toc._table = this.measureNode(node.toc._table);\n\n\treturn node;\n};\n\nDocMeasure.prototype.measureVerticalContainer = function (node) {\n\tvar items = node.stack;\n\n\tnode._minWidth = 0;\n\tnode._maxWidth = 0;\n\n\tfor (var i = 0, l = items.length; i < l; i++) {\n\t\titems[i] = this.measureNode(items[i]);\n\n\t\tnode._minWidth = Math.max(node._minWidth, items[i]._minWidth);\n\t\tnode._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth);\n\t}\n\n\treturn node;\n};\n\nDocMeasure.prototype.gapSizeForList = function () {\n\treturn this.textTools.sizeOfString('9. ', this.styleStack);\n};\n\nDocMeasure.prototype.buildUnorderedMarker = function (styleStack, gapSize, type) {\n\tfunction buildDisc(gapSize, color) {\n\t\t// TODO: ascender-based calculations\n\t\tvar radius = gapSize.fontSize / 6;\n\t\treturn {\n\t\t\tcanvas: [{\n\t\t\t\t\tx: radius,\n\t\t\t\t\ty: (gapSize.height / gapSize.lineHeight) + gapSize.descender - gapSize.fontSize / 3,\n\t\t\t\t\tr1: radius,\n\t\t\t\t\tr2: radius,\n\t\t\t\t\ttype: 'ellipse',\n\t\t\t\t\tcolor: color\n\t\t\t\t}]\n\t\t};\n\t}\n\n\tfunction buildSquare(gapSize, color) {\n\t\t// TODO: ascender-based calculations\n\t\tvar size = gapSize.fontSize / 3;\n\t\treturn {\n\t\t\tcanvas: [{\n\t\t\t\t\tx: 0,\n\t\t\t\t\ty: (gapSize.height / gapSize.lineHeight) + gapSize.descender - (gapSize.fontSize / 3) - (size / 2),\n\t\t\t\t\th: size,\n\t\t\t\t\tw: size,\n\t\t\t\t\ttype: 'rect',\n\t\t\t\t\tcolor: color\n\t\t\t\t}]\n\t\t};\n\t}\n\n\tfunction buildCircle(gapSize, color) {\n\t\t// TODO: ascender-based calculations\n\t\tvar radius = gapSize.fontSize / 6;\n\t\treturn {\n\t\t\tcanvas: [{\n\t\t\t\t\tx: radius,\n\t\t\t\t\ty: (gapSize.height / gapSize.lineHeight) + gapSize.descender - gapSize.fontSize / 3,\n\t\t\t\t\tr1: radius,\n\t\t\t\t\tr2: radius,\n\t\t\t\t\ttype: 'ellipse',\n\t\t\t\t\tlineColor: color\n\t\t\t\t}]\n\t\t};\n\t}\n\n\tvar marker;\n\tvar color = styleStack.getProperty('markerColor') || styleStack.getProperty('color') || 'black';\n\n\tswitch (type) {\n\t\tcase 'circle':\n\t\t\tmarker = buildCircle(gapSize, color);\n\t\t\tbreak;\n\n\t\tcase 'square':\n\t\t\tmarker = buildSquare(gapSize, color);\n\t\t\tbreak;\n\n\t\tcase 'none':\n\t\t\tmarker = {};\n\t\t\tbreak;\n\n\t\tcase 'disc':\n\t\tdefault:\n\t\t\tmarker = buildDisc(gapSize, color);\n\t\t\tbreak;\n\t}\n\n\tmarker._minWidth = marker._maxWidth = gapSize.width;\n\tmarker._minHeight = marker._maxHeight = gapSize.height;\n\n\treturn marker;\n};\n\nDocMeasure.prototype.buildOrderedMarker = function (counter, styleStack, type, separator) {\n\tfunction prepareAlpha(counter) {\n\t\tfunction toAlpha(num) {\n\t\t\treturn (num >= 26 ? toAlpha((num / 26 >> 0) - 1) : '') + 'abcdefghijklmnopqrstuvwxyz'[num % 26 >> 0];\n\t\t}\n\n\t\tif (counter < 1) {\n\t\t\treturn counter.toString();\n\t\t}\n\n\t\treturn toAlpha(counter - 1);\n\t}\n\n\tfunction prepareRoman(counter) {\n\t\tif (counter < 1 || counter > 4999) {\n\t\t\treturn counter.toString();\n\t\t}\n\t\tvar num = counter;\n\t\tvar lookup = {M: 1000, CM: 900, D: 500, CD: 400, C: 100, XC: 90, L: 50, XL: 40, X: 10, IX: 9, V: 5, IV: 4, I: 1}, roman = '', i;\n\t\tfor (i in lookup) {\n\t\t\twhile (num >= lookup[i]) {\n\t\t\t\troman += i;\n\t\t\t\tnum -= lookup[i];\n\t\t\t}\n\t\t}\n\t\treturn roman;\n\t}\n\n\tfunction prepareDecimal(counter) {\n\t\treturn counter.toString();\n\t}\n\n\tvar counterText;\n\tswitch (type) {\n\t\tcase 'none':\n\t\t\tcounterText = null;\n\t\t\tbreak;\n\n\t\tcase 'upper-alpha':\n\t\t\tcounterText = prepareAlpha(counter).toUpperCase();\n\t\t\tbreak;\n\n\t\tcase 'lower-alpha':\n\t\t\tcounterText = prepareAlpha(counter);\n\t\t\tbreak;\n\n\t\tcase 'upper-roman':\n\t\t\tcounterText = prepareRoman(counter);\n\t\t\tbreak;\n\n\t\tcase 'lower-roman':\n\t\t\tcounterText = prepareRoman(counter).toLowerCase();\n\t\t\tbreak;\n\n\t\tcase 'decimal':\n\t\tdefault:\n\t\t\tcounterText = prepareDecimal(counter);\n\t\t\tbreak;\n\t}\n\n\tif (counterText === null) {\n\t\treturn {};\n\t}\n\n\tif (separator) {\n\t\tif (isArray(separator)) {\n\t\t\tif (separator[0]) {\n\t\t\t\tcounterText = separator[0] + counterText;\n\t\t\t}\n\n\t\t\tif (separator[1]) {\n\t\t\t\tcounterText += separator[1];\n\t\t\t}\n\t\t\tcounterText += ' ';\n\t\t} else {\n\t\t\tcounterText += separator + ' ';\n\t\t}\n\t}\n\n\tvar textArray = {text: counterText};\n\tvar markerColor = styleStack.getProperty('markerColor');\n\tif (markerColor) {\n\t\ttextArray.color = markerColor;\n\t}\n\n\treturn {_inlines: this.textTools.buildInlines(textArray, styleStack).items};\n};\n\nDocMeasure.prototype.measureUnorderedList = function (node) {\n\tvar style = this.styleStack.clone();\n\tvar items = node.ul;\n\tnode.type = node.type || 'disc';\n\tnode._gapSize = this.gapSizeForList();\n\tnode._minWidth = 0;\n\tnode._maxWidth = 0;\n\n\tfor (var i = 0, l = items.length; i < l; i++) {\n\t\tvar item = items[i] = this.measureNode(items[i]);\n\n\t\tif (!item.ol && !item.ul) {\n\t\t\titem.listMarker = this.buildUnorderedMarker(style, node._gapSize, item.listType || node.type);\n\t\t}\n\n\t\tnode._minWidth = Math.max(node._minWidth, items[i]._minWidth + node._gapSize.width);\n\t\tnode._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth + node._gapSize.width);\n\t}\n\n\treturn node;\n};\n\nDocMeasure.prototype.measureOrderedList = function (node) {\n\tvar style = this.styleStack.clone();\n\tvar items = node.ol;\n\tnode.type = node.type || 'decimal';\n\tnode.separator = node.separator || '.';\n\tnode.reversed = node.reversed || false;\n\tif (!node.start) {\n\t\tnode.start = node.reversed ? items.length : 1;\n\t}\n\tnode._gapSize = this.gapSizeForList();\n\tnode._minWidth = 0;\n\tnode._maxWidth = 0;\n\n\tvar counter = node.start;\n\tfor (var i = 0, l = items.length; i < l; i++) {\n\t\tvar item = items[i] = this.measureNode(items[i]);\n\n\t\tif (!item.ol && !item.ul) {\n\t\t\titem.listMarker = this.buildOrderedMarker(item.counter || counter, style, item.listType || node.type, node.separator);\n\t\t\tif (item.listMarker._inlines) {\n\t\t\t\tnode._gapSize.width = Math.max(node._gapSize.width, item.listMarker._inlines[0].width);\n\t\t\t}\n\t\t}  // TODO: else - nested lists numbering\n\n\t\tnode._minWidth = Math.max(node._minWidth, items[i]._minWidth);\n\t\tnode._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth);\n\n\t\tif (node.reversed) {\n\t\t\tcounter--;\n\t\t} else {\n\t\t\tcounter++;\n\t\t}\n\t}\n\n\tnode._minWidth += node._gapSize.width;\n\tnode._maxWidth += node._gapSize.width;\n\n\tfor (var i = 0, l = items.length; i < l; i++) {\n\t\tvar item = items[i];\n\t\tif (!item.ol && !item.ul) {\n\t\t\titem.listMarker._minWidth = item.listMarker._maxWidth = node._gapSize.width;\n\t\t}\n\t}\n\n\treturn node;\n};\n\nDocMeasure.prototype.measureColumns = function (node) {\n\tvar columns = node.columns;\n\tnode._gap = this.styleStack.getProperty('columnGap') || 0;\n\n\tfor (var i = 0, l = columns.length; i < l; i++) {\n\t\tcolumns[i] = this.measureNode(columns[i]);\n\t}\n\n\tvar measures = ColumnCalculator.measureMinMax(columns);\n\n\tvar numGaps = (columns.length > 0) ? (columns.length - 1) : 0;\n\tnode._minWidth = measures.min + node._gap * numGaps;\n\tnode._maxWidth = measures.max + node._gap * numGaps;\n\n\treturn node;\n};\n\nDocMeasure.prototype.measureTable = function (node) {\n\textendTableWidths(node);\n\tnode._layout = getLayout(this.tableLayouts);\n\tnode._offsets = getOffsets(node._layout);\n\n\tvar colSpans = [];\n\tvar col, row, cols, rows;\n\n\tfor (col = 0, cols = node.table.body[0].length; col < cols; col++) {\n\t\tvar c = node.table.widths[col];\n\t\tc._minWidth = 0;\n\t\tc._maxWidth = 0;\n\n\t\tfor (row = 0, rows = node.table.body.length; row < rows; row++) {\n\t\t\tvar rowData = node.table.body[row];\n\t\t\tvar data = rowData[col];\n\t\t\tif (data === undefined) {\n\t\t\t\tconsole.error('Malformed table row ', rowData, 'in node ', node);\n\t\t\t\tthrow 'Malformed table row, a cell is undefined.';\n\t\t\t}\n\t\t\tif (data === null) { // transform to object\n\t\t\t\tdata = '';\n\t\t\t}\n\n\t\t\tif (!data._span) {\n\t\t\t\tdata = rowData[col] = this.styleStack.auto(data, measureCb(this, data));\n\n\t\t\t\tif (data.colSpan && data.colSpan > 1) {\n\t\t\t\t\tmarkSpans(rowData, col, data.colSpan);\n\t\t\t\t\tcolSpans.push({col: col, span: data.colSpan, minWidth: data._minWidth, maxWidth: data._maxWidth});\n\t\t\t\t} else {\n\t\t\t\t\tc._minWidth = Math.max(c._minWidth, data._minWidth);\n\t\t\t\t\tc._maxWidth = Math.max(c._maxWidth, data._maxWidth);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (data.rowSpan && data.rowSpan > 1) {\n\t\t\t\tmarkVSpans(node.table, row, col, data.rowSpan);\n\t\t\t}\n\t\t}\n\t}\n\n\textendWidthsForColSpans();\n\n\tvar measures = ColumnCalculator.measureMinMax(node.table.widths);\n\n\tnode._minWidth = measures.min + node._offsets.total;\n\tnode._maxWidth = measures.max + node._offsets.total;\n\n\treturn node;\n\n\tfunction measureCb(_this, data) {\n\t\treturn function () {\n\t\t\tif (isObject(data)) {\n\t\t\t\tdata.fillColor = _this.styleStack.getProperty('fillColor');\n\t\t\t}\n\t\t\treturn _this.measureNode(data);\n\t\t};\n\t}\n\n\tfunction getLayout(tableLayouts) {\n\t\tvar layout = node.layout;\n\n\t\tif (isString(layout)) {\n\t\t\tlayout = tableLayouts[layout];\n\t\t}\n\n\t\tvar defaultLayout = {\n\t\t\thLineWidth: function (i, node) {\n\t\t\t\treturn 1;\n\t\t\t},\n\t\t\tvLineWidth: function (i, node) {\n\t\t\t\treturn 1;\n\t\t\t},\n\t\t\thLineColor: function (i, node) {\n\t\t\t\treturn 'black';\n\t\t\t},\n\t\t\tvLineColor: function (i, node) {\n\t\t\t\treturn 'black';\n\t\t\t},\n\t\t\tpaddingLeft: function (i, node) {\n\t\t\t\treturn 4;\n\t\t\t},\n\t\t\tpaddingRight: function (i, node) {\n\t\t\t\treturn 4;\n\t\t\t},\n\t\t\tpaddingTop: function (i, node) {\n\t\t\t\treturn 2;\n\t\t\t},\n\t\t\tpaddingBottom: function (i, node) {\n\t\t\t\treturn 2;\n\t\t\t},\n\t\t\tfillColor: function (i, node) {\n\t\t\t\treturn null;\n\t\t\t},\n\t\t\tdefaultBorder: true\n\t\t};\n\n\t\treturn pack(defaultLayout, layout);\n\t}\n\n\tfunction getOffsets(layout) {\n\t\tvar offsets = [];\n\t\tvar totalOffset = 0;\n\t\tvar prevRightPadding = 0;\n\n\t\tfor (var i = 0, l = node.table.widths.length; i < l; i++) {\n\t\t\tvar lOffset = prevRightPadding + layout.vLineWidth(i, node) + layout.paddingLeft(i, node);\n\t\t\toffsets.push(lOffset);\n\t\t\ttotalOffset += lOffset;\n\t\t\tprevRightPadding = layout.paddingRight(i, node);\n\t\t}\n\n\t\ttotalOffset += prevRightPadding + layout.vLineWidth(node.table.widths.length, node);\n\n\t\treturn {\n\t\t\ttotal: totalOffset,\n\t\t\toffsets: offsets\n\t\t};\n\t}\n\n\tfunction extendWidthsForColSpans() {\n\t\tvar q, j;\n\n\t\tfor (var i = 0, l = colSpans.length; i < l; i++) {\n\t\t\tvar span = colSpans[i];\n\n\t\t\tvar currentMinMax = getMinMax(span.col, span.span, node._offsets);\n\t\t\tvar minDifference = span.minWidth - currentMinMax.minWidth;\n\t\t\tvar maxDifference = span.maxWidth - currentMinMax.maxWidth;\n\n\t\t\tif (minDifference > 0) {\n\t\t\t\tq = minDifference / span.span;\n\n\t\t\t\tfor (j = 0; j < span.span; j++) {\n\t\t\t\t\tnode.table.widths[span.col + j]._minWidth += q;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (maxDifference > 0) {\n\t\t\t\tq = maxDifference / span.span;\n\n\t\t\t\tfor (j = 0; j < span.span; j++) {\n\t\t\t\t\tnode.table.widths[span.col + j]._maxWidth += q;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction getMinMax(col, span, offsets) {\n\t\tvar result = {minWidth: 0, maxWidth: 0};\n\n\t\tfor (var i = 0; i < span; i++) {\n\t\t\tresult.minWidth += node.table.widths[col + i]._minWidth + (i ? offsets.offsets[col + i] : 0);\n\t\t\tresult.maxWidth += node.table.widths[col + i]._maxWidth + (i ? offsets.offsets[col + i] : 0);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tfunction markSpans(rowData, col, span) {\n\t\tfor (var i = 1; i < span; i++) {\n\t\t\trowData[col + i] = {\n\t\t\t\t_span: true,\n\t\t\t\t_minWidth: 0,\n\t\t\t\t_maxWidth: 0,\n\t\t\t\trowSpan: rowData[col].rowSpan\n\t\t\t};\n\t\t}\n\t}\n\n\tfunction markVSpans(table, row, col, span) {\n\t\tfor (var i = 1; i < span; i++) {\n\t\t\ttable.body[row + i][col] = {\n\t\t\t\t_span: true,\n\t\t\t\t_minWidth: 0,\n\t\t\t\t_maxWidth: 0,\n\t\t\t\tfillColor: table.body[row][col].fillColor\n\t\t\t};\n\t\t}\n\t}\n\n\tfunction extendTableWidths(node) {\n\t\tif (!node.table.widths) {\n\t\t\tnode.table.widths = 'auto';\n\t\t}\n\n\t\tif (isString(node.table.widths)) {\n\t\t\tnode.table.widths = [node.table.widths];\n\n\t\t\twhile (node.table.widths.length < node.table.body[0].length) {\n\t\t\t\tnode.table.widths.push(node.table.widths[node.table.widths.length - 1]);\n\t\t\t}\n\t\t}\n\n\t\tfor (var i = 0, l = node.table.widths.length; i < l; i++) {\n\t\t\tvar w = node.table.widths[i];\n\t\t\tif (isNumber(w) || isString(w)) {\n\t\t\t\tnode.table.widths[i] = {width: w};\n\t\t\t}\n\t\t}\n\t}\n};\n\nDocMeasure.prototype.measureCanvas = function (node) {\n\tvar w = 0, h = 0;\n\n\tfor (var i = 0, l = node.canvas.length; i < l; i++) {\n\t\tvar vector = node.canvas[i];\n\n\t\tswitch (vector.type) {\n\t\t\tcase 'ellipse':\n\t\t\t\tw = Math.max(w, vector.x + vector.r1);\n\t\t\t\th = Math.max(h, vector.y + vector.r2);\n\t\t\t\tbreak;\n\t\t\tcase 'rect':\n\t\t\t\tw = Math.max(w, vector.x + vector.w);\n\t\t\t\th = Math.max(h, vector.y + vector.h);\n\t\t\t\tbreak;\n\t\t\tcase 'line':\n\t\t\t\tw = Math.max(w, vector.x1, vector.x2);\n\t\t\t\th = Math.max(h, vector.y1, vector.y2);\n\t\t\t\tbreak;\n\t\t\tcase 'polyline':\n\t\t\t\tfor (var i2 = 0, l2 = vector.points.length; i2 < l2; i2++) {\n\t\t\t\t\tw = Math.max(w, vector.points[i2].x);\n\t\t\t\t\th = Math.max(h, vector.points[i2].y);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tnode._minWidth = node._maxWidth = w;\n\tnode._minHeight = node._maxHeight = h;\n\tnode._alignment = this.styleStack.getProperty('alignment');\n\n\treturn node;\n};\n\nDocMeasure.prototype.measureQr = function (node) {\n\tnode = qrEncoder.measure(node);\n\tnode._alignment = this.styleStack.getProperty('alignment');\n\treturn node;\n};\n\nmodule.exports = DocMeasure;\n\n\n/***/ }),\n/* 131 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n;(function (exports) {\n\t'use strict';\n\n  var Arr = (typeof Uint8Array !== 'undefined')\n    ? Uint8Array\n    : Array\n\n\tvar PLUS   = '+'.charCodeAt(0)\n\tvar SLASH  = '/'.charCodeAt(0)\n\tvar NUMBER = '0'.charCodeAt(0)\n\tvar LOWER  = 'a'.charCodeAt(0)\n\tvar UPPER  = 'A'.charCodeAt(0)\n\tvar PLUS_URL_SAFE = '-'.charCodeAt(0)\n\tvar SLASH_URL_SAFE = '_'.charCodeAt(0)\n\n\tfunction decode (elt) {\n\t\tvar code = elt.charCodeAt(0)\n\t\tif (code === PLUS ||\n\t\t    code === PLUS_URL_SAFE)\n\t\t\treturn 62 // '+'\n\t\tif (code === SLASH ||\n\t\t    code === SLASH_URL_SAFE)\n\t\t\treturn 63 // '/'\n\t\tif (code < NUMBER)\n\t\t\treturn -1 //no match\n\t\tif (code < NUMBER + 10)\n\t\t\treturn code - NUMBER + 26 + 26\n\t\tif (code < UPPER + 26)\n\t\t\treturn code - UPPER\n\t\tif (code < LOWER + 26)\n\t\t\treturn code - LOWER + 26\n\t}\n\n\tfunction b64ToByteArray (b64) {\n\t\tvar i, j, l, tmp, placeHolders, arr\n\n\t\tif (b64.length % 4 > 0) {\n\t\t\tthrow new Error('Invalid string. Length must be a multiple of 4')\n\t\t}\n\n\t\t// the number of equal signs (place holders)\n\t\t// if there are two placeholders, than the two characters before it\n\t\t// represent one byte\n\t\t// if there is only one, then the three characters before it represent 2 bytes\n\t\t// this is just a cheap hack to not do indexOf twice\n\t\tvar len = b64.length\n\t\tplaceHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0\n\n\t\t// base64 is 4/3 + up to two characters of the original data\n\t\tarr = new Arr(b64.length * 3 / 4 - placeHolders)\n\n\t\t// if there are placeholders, only get up to the last complete 4 chars\n\t\tl = placeHolders > 0 ? b64.length - 4 : b64.length\n\n\t\tvar L = 0\n\n\t\tfunction push (v) {\n\t\t\tarr[L++] = v\n\t\t}\n\n\t\tfor (i = 0, j = 0; i < l; i += 4, j += 3) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))\n\t\t\tpush((tmp & 0xFF0000) >> 16)\n\t\t\tpush((tmp & 0xFF00) >> 8)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\tif (placeHolders === 2) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)\n\t\t\tpush(tmp & 0xFF)\n\t\t} else if (placeHolders === 1) {\n\t\t\ttmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)\n\t\t\tpush((tmp >> 8) & 0xFF)\n\t\t\tpush(tmp & 0xFF)\n\t\t}\n\n\t\treturn arr\n\t}\n\n\tfunction uint8ToBase64 (uint8) {\n\t\tvar i,\n\t\t\textraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes\n\t\t\toutput = \"\",\n\t\t\ttemp, length\n\n\t\tfunction encode (num) {\n\t\t\treturn lookup.charAt(num)\n\t\t}\n\n\t\tfunction tripletToBase64 (num) {\n\t\t\treturn encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)\n\t\t}\n\n\t\t// go through the array every three bytes, we'll deal with trailing stuff later\n\t\tfor (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {\n\t\t\ttemp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n\t\t\toutput += tripletToBase64(temp)\n\t\t}\n\n\t\t// pad the end with zeros, but make sure to not forget the extra bytes\n\t\tswitch (extraBytes) {\n\t\t\tcase 1:\n\t\t\t\ttemp = uint8[uint8.length - 1]\n\t\t\t\toutput += encode(temp >> 2)\n\t\t\t\toutput += encode((temp << 4) & 0x3F)\n\t\t\t\toutput += '=='\n\t\t\t\tbreak\n\t\t\tcase 2:\n\t\t\t\ttemp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])\n\t\t\t\toutput += encode(temp >> 10)\n\t\t\t\toutput += encode((temp >> 4) & 0x3F)\n\t\t\t\toutput += encode((temp << 2) & 0x3F)\n\t\t\t\toutput += '='\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn output\n\t}\n\n\texports.toByteArray = b64ToByteArray\n\texports.fromByteArray = uint8ToBase64\n}( false ? (this.base64js = {}) : exports))\n\n\n/***/ }),\n/* 132 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var AI, AL, B2, BA, BB, BK, CB, CJ, CL, CM, CP, CR, EX, GL, H2, H3, HL, HY, ID, IN, IS, JL, JT, JV, LF, NL, NS, NU, OP, PO, PR, QU, RI, SA, SG, SP, SY, WJ, XX, ZW;\n\n  exports.OP = OP = 0;\n\n  exports.CL = CL = 1;\n\n  exports.CP = CP = 2;\n\n  exports.QU = QU = 3;\n\n  exports.GL = GL = 4;\n\n  exports.NS = NS = 5;\n\n  exports.EX = EX = 6;\n\n  exports.SY = SY = 7;\n\n  exports.IS = IS = 8;\n\n  exports.PR = PR = 9;\n\n  exports.PO = PO = 10;\n\n  exports.NU = NU = 11;\n\n  exports.AL = AL = 12;\n\n  exports.HL = HL = 13;\n\n  exports.ID = ID = 14;\n\n  exports.IN = IN = 15;\n\n  exports.HY = HY = 16;\n\n  exports.BA = BA = 17;\n\n  exports.BB = BB = 18;\n\n  exports.B2 = B2 = 19;\n\n  exports.ZW = ZW = 20;\n\n  exports.CM = CM = 21;\n\n  exports.WJ = WJ = 22;\n\n  exports.H2 = H2 = 23;\n\n  exports.H3 = H3 = 24;\n\n  exports.JL = JL = 25;\n\n  exports.JV = JV = 26;\n\n  exports.JT = JT = 27;\n\n  exports.RI = RI = 28;\n\n  exports.AI = AI = 29;\n\n  exports.BK = BK = 30;\n\n  exports.CB = CB = 31;\n\n  exports.CJ = CJ = 32;\n\n  exports.CR = CR = 33;\n\n  exports.LF = LF = 34;\n\n  exports.NL = NL = 35;\n\n  exports.SA = SA = 36;\n\n  exports.SG = SG = 37;\n\n  exports.SP = SP = 38;\n\n  exports.XX = XX = 39;\n\n}).call(this);\n\n\n/***/ }),\n/* 133 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var CI_BRK, CP_BRK, DI_BRK, IN_BRK, PR_BRK;\n\n  exports.DI_BRK = DI_BRK = 0;\n\n  exports.IN_BRK = IN_BRK = 1;\n\n  exports.CI_BRK = CI_BRK = 2;\n\n  exports.CP_BRK = CP_BRK = 3;\n\n  exports.PR_BRK = PR_BRK = 4;\n\n  exports.pairTable = [[PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, CP_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, DI_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, DI_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, PR_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK], [IN_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, IN_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, DI_BRK], [DI_BRK, PR_BRK, PR_BRK, IN_BRK, IN_BRK, IN_BRK, PR_BRK, PR_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK, IN_BRK, DI_BRK, DI_BRK, PR_BRK, CI_BRK, PR_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, DI_BRK, IN_BRK]];\n\n}).call(this);\n\n\n/***/ }),\n/* 134 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/*eslint no-unused-vars: [\"error\", {\"args\": \"none\"}]*/\n/*eslint no-redeclare: \"off\"*/\n\n\n/* qr.js -- QR code generator in Javascript (revision 2011-01-19)\n * Written by Kang Seonghoon <public+qrjs@mearie.org>.\n *\n * This source code is in the public domain; if your jurisdiction does not\n * recognize the public domain the terms of Creative Commons CC0 license\n * apply. In the other words, you can always do what you want.\n */\n\n\n// per-version information (cf. JIS X 0510:2004 pp. 30--36, 71)\n//\n// [0]: the degree of generator polynomial by ECC levels\n// [1]: # of code blocks by ECC levels\n// [2]: left-top positions of alignment patterns\n//\n// the number in this table (in particular, [0]) does not exactly match with\n// the numbers in the specficiation. see augumenteccs below for the reason.\nvar VERSIONS = [\n\tnull,\n\t[[10, 7, 17, 13], [1, 1, 1, 1], []],\n\t[[16, 10, 28, 22], [1, 1, 1, 1], [4, 16]],\n\t[[26, 15, 22, 18], [1, 1, 2, 2], [4, 20]],\n\t[[18, 20, 16, 26], [2, 1, 4, 2], [4, 24]],\n\t[[24, 26, 22, 18], [2, 1, 4, 4], [4, 28]],\n\t[[16, 18, 28, 24], [4, 2, 4, 4], [4, 32]],\n\t[[18, 20, 26, 18], [4, 2, 5, 6], [4, 20, 36]],\n\t[[22, 24, 26, 22], [4, 2, 6, 6], [4, 22, 40]],\n\t[[22, 30, 24, 20], [5, 2, 8, 8], [4, 24, 44]],\n\t[[26, 18, 28, 24], [5, 4, 8, 8], [4, 26, 48]],\n\t[[30, 20, 24, 28], [5, 4, 11, 8], [4, 28, 52]],\n\t[[22, 24, 28, 26], [8, 4, 11, 10], [4, 30, 56]],\n\t[[22, 26, 22, 24], [9, 4, 16, 12], [4, 32, 60]],\n\t[[24, 30, 24, 20], [9, 4, 16, 16], [4, 24, 44, 64]],\n\t[[24, 22, 24, 30], [10, 6, 18, 12], [4, 24, 46, 68]],\n\t[[28, 24, 30, 24], [10, 6, 16, 17], [4, 24, 48, 72]],\n\t[[28, 28, 28, 28], [11, 6, 19, 16], [4, 28, 52, 76]],\n\t[[26, 30, 28, 28], [13, 6, 21, 18], [4, 28, 54, 80]],\n\t[[26, 28, 26, 26], [14, 7, 25, 21], [4, 28, 56, 84]],\n\t[[26, 28, 28, 30], [16, 8, 25, 20], [4, 32, 60, 88]],\n\t[[26, 28, 30, 28], [17, 8, 25, 23], [4, 26, 48, 70, 92]],\n\t[[28, 28, 24, 30], [17, 9, 34, 23], [4, 24, 48, 72, 96]],\n\t[[28, 30, 30, 30], [18, 9, 30, 25], [4, 28, 52, 76, 100]],\n\t[[28, 30, 30, 30], [20, 10, 32, 27], [4, 26, 52, 78, 104]],\n\t[[28, 26, 30, 30], [21, 12, 35, 29], [4, 30, 56, 82, 108]],\n\t[[28, 28, 30, 28], [23, 12, 37, 34], [4, 28, 56, 84, 112]],\n\t[[28, 30, 30, 30], [25, 12, 40, 34], [4, 32, 60, 88, 116]],\n\t[[28, 30, 30, 30], [26, 13, 42, 35], [4, 24, 48, 72, 96, 120]],\n\t[[28, 30, 30, 30], [28, 14, 45, 38], [4, 28, 52, 76, 100, 124]],\n\t[[28, 30, 30, 30], [29, 15, 48, 40], [4, 24, 50, 76, 102, 128]],\n\t[[28, 30, 30, 30], [31, 16, 51, 43], [4, 28, 54, 80, 106, 132]],\n\t[[28, 30, 30, 30], [33, 17, 54, 45], [4, 32, 58, 84, 110, 136]],\n\t[[28, 30, 30, 30], [35, 18, 57, 48], [4, 28, 56, 84, 112, 140]],\n\t[[28, 30, 30, 30], [37, 19, 60, 51], [4, 32, 60, 88, 116, 144]],\n\t[[28, 30, 30, 30], [38, 19, 63, 53], [4, 28, 52, 76, 100, 124, 148]],\n\t[[28, 30, 30, 30], [40, 20, 66, 56], [4, 22, 48, 74, 100, 126, 152]],\n\t[[28, 30, 30, 30], [43, 21, 70, 59], [4, 26, 52, 78, 104, 130, 156]],\n\t[[28, 30, 30, 30], [45, 22, 74, 62], [4, 30, 56, 82, 108, 134, 160]],\n\t[[28, 30, 30, 30], [47, 24, 77, 65], [4, 24, 52, 80, 108, 136, 164]],\n\t[[28, 30, 30, 30], [49, 25, 81, 68], [4, 28, 56, 84, 112, 140, 168]]];\n\n// mode constants (cf. Table 2 in JIS X 0510:2004 p. 16)\nvar MODE_TERMINATOR = 0;\nvar MODE_NUMERIC = 1, MODE_ALPHANUMERIC = 2, MODE_OCTET = 4, MODE_KANJI = 8;\n\n// validation regexps\nvar NUMERIC_REGEXP = /^\\d*$/;\nvar ALPHANUMERIC_REGEXP = /^[A-Za-z0-9 $%*+\\-./:]*$/;\nvar ALPHANUMERIC_OUT_REGEXP = /^[A-Z0-9 $%*+\\-./:]*$/;\n\n// ECC levels (cf. Table 22 in JIS X 0510:2004 p. 45)\nvar ECCLEVEL_L = 1, ECCLEVEL_M = 0, ECCLEVEL_Q = 3, ECCLEVEL_H = 2;\n\n// GF(2^8)-to-integer mapping with a reducing polynomial x^8+x^4+x^3+x^2+1\n// invariant: GF256_MAP[GF256_INVMAP[i]] == i for all i in [1,256)\nvar GF256_MAP = [], GF256_INVMAP = [-1];\nfor (var i = 0, v = 1; i < 255; ++i) {\n\tGF256_MAP.push(v);\n\tGF256_INVMAP[v] = i;\n\tv = (v * 2) ^ (v >= 128 ? 0x11d : 0);\n}\n\n// generator polynomials up to degree 30\n// (should match with polynomials in JIS X 0510:2004 Appendix A)\n//\n// generator polynomial of degree K is product of (x-\\alpha^0), (x-\\alpha^1),\n// ..., (x-\\alpha^(K-1)). by convention, we omit the K-th coefficient (always 1)\n// from the result; also other coefficients are written in terms of the exponent\n// to \\alpha to avoid the redundant calculation. (see also calculateecc below.)\nvar GF256_GENPOLY = [[]];\nfor (var i = 0; i < 30; ++i) {\n\tvar prevpoly = GF256_GENPOLY[i], poly = [];\n\tfor (var j = 0; j <= i; ++j) {\n\t\tvar a = (j < i ? GF256_MAP[prevpoly[j]] : 0);\n\t\tvar b = GF256_MAP[(i + (prevpoly[j - 1] || 0)) % 255];\n\t\tpoly.push(GF256_INVMAP[a ^ b]);\n\t}\n\tGF256_GENPOLY.push(poly);\n}\n\n// alphanumeric character mapping (cf. Table 5 in JIS X 0510:2004 p. 19)\nvar ALPHANUMERIC_MAP = {};\nfor (var i = 0; i < 45; ++i) {\n\tALPHANUMERIC_MAP['0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'.charAt(i)] = i;\n}\n\n// mask functions in terms of row # and column #\n// (cf. Table 20 in JIS X 0510:2004 p. 42)\n/*jshint unused: false */\nvar MASKFUNCS = [\n\tfunction (i, j) {\n\t\treturn (i + j) % 2 === 0;\n\t},\n\tfunction (i, j) {\n\t\treturn i % 2 === 0;\n\t},\n\tfunction (i, j) {\n\t\treturn j % 3 === 0;\n\t},\n\tfunction (i, j) {\n\t\treturn (i + j) % 3 === 0;\n\t},\n\tfunction (i, j) {\n\t\treturn (((i / 2) | 0) + ((j / 3) | 0)) % 2 === 0;\n\t},\n\tfunction (i, j) {\n\t\treturn (i * j) % 2 + (i * j) % 3 === 0;\n\t},\n\tfunction (i, j) {\n\t\treturn ((i * j) % 2 + (i * j) % 3) % 2 === 0;\n\t},\n\tfunction (i, j) {\n\t\treturn ((i + j) % 2 + (i * j) % 3) % 2 === 0;\n\t}];\n\n// returns true when the version information has to be embeded.\nvar needsverinfo = function (ver) {\n\treturn ver > 6;\n};\n\n// returns the size of entire QR code for given version.\nvar getsizebyver = function (ver) {\n\treturn 4 * ver + 17;\n};\n\n// returns the number of bits available for code words in this version.\nvar nfullbits = function (ver) {\n\t/*\n\t * |<--------------- n --------------->|\n\t * |        |<----- n-17 ---->|        |\n\t * +-------+                ///+-------+ ----\n\t * |       |                ///|       |    ^\n\t * |  9x9  |       @@@@@    ///|  9x8  |    |\n\t * |       | # # # @5x5@ # # # |       |    |\n\t * +-------+       @@@@@       +-------+    |\n\t *       #                               ---|\n\t *                                        ^ |\n\t *       #                                |\n\t *     @@@@@       @@@@@       @@@@@      | n\n\t *     @5x5@       @5x5@       @5x5@   n-17\n\t *     @@@@@       @@@@@       @@@@@      | |\n\t *       #                                | |\n\t * //////                                 v |\n\t * //////#                               ---|\n\t * +-------+       @@@@@       @@@@@        |\n\t * |       |       @5x5@       @5x5@        |\n\t * |  8x9  |       @@@@@       @@@@@        |\n\t * |       |                                v\n\t * +-------+                             ----\n\t *\n\t * when the entire code has n^2 modules and there are m^2-3 alignment\n\t * patterns, we have:\n\t * - 225 (= 9x9 + 9x8 + 8x9) modules for finder patterns and\n\t *   format information;\n\t * - 2n-34 (= 2(n-17)) modules for timing patterns;\n\t * - 36 (= 3x6 + 6x3) modules for version information, if any;\n\t * - 25m^2-75 (= (m^2-3)(5x5)) modules for alignment patterns\n\t *   if any, but 10m-20 (= 2(m-2)x5) of them overlaps with\n\t *   timing patterns.\n\t */\n\tvar v = VERSIONS[ver];\n\tvar nbits = 16 * ver * ver + 128 * ver + 64; // finder, timing and format info.\n\tif (needsverinfo(ver))\n\t\tnbits -= 36; // version information\n\tif (v[2].length) { // alignment patterns\n\t\tnbits -= 25 * v[2].length * v[2].length - 10 * v[2].length - 55;\n\t}\n\treturn nbits;\n};\n\n// returns the number of bits available for data portions (i.e. excludes ECC\n// bits but includes mode and length bits) in this version and ECC level.\nvar ndatabits = function (ver, ecclevel) {\n\tvar nbits = nfullbits(ver) & ~7; // no sub-octet code words\n\tvar v = VERSIONS[ver];\n\tnbits -= 8 * v[0][ecclevel] * v[1][ecclevel]; // ecc bits\n\treturn nbits;\n};\n\n// returns the number of bits required for the length of data.\n// (cf. Table 3 in JIS X 0510:2004 p. 16)\nvar ndatalenbits = function (ver, mode) {\n\tswitch (mode) {\n\t\tcase MODE_NUMERIC:\n\t\t\treturn (ver < 10 ? 10 : ver < 27 ? 12 : 14);\n\t\tcase MODE_ALPHANUMERIC:\n\t\t\treturn (ver < 10 ? 9 : ver < 27 ? 11 : 13);\n\t\tcase MODE_OCTET:\n\t\t\treturn (ver < 10 ? 8 : 16);\n\t\tcase MODE_KANJI:\n\t\t\treturn (ver < 10 ? 8 : ver < 27 ? 10 : 12);\n\t}\n};\n\n// returns the maximum length of data possible in given configuration.\nvar getmaxdatalen = function (ver, mode, ecclevel) {\n\tvar nbits = ndatabits(ver, ecclevel) - 4 - ndatalenbits(ver, mode); // 4 for mode bits\n\tswitch (mode) {\n\t\tcase MODE_NUMERIC:\n\t\t\treturn ((nbits / 10) | 0) * 3 + (nbits % 10 < 4 ? 0 : nbits % 10 < 7 ? 1 : 2);\n\t\tcase MODE_ALPHANUMERIC:\n\t\t\treturn ((nbits / 11) | 0) * 2 + (nbits % 11 < 6 ? 0 : 1);\n\t\tcase MODE_OCTET:\n\t\t\treturn (nbits / 8) | 0;\n\t\tcase MODE_KANJI:\n\t\t\treturn (nbits / 13) | 0;\n\t}\n};\n\n// checks if the given data can be encoded in given mode, and returns\n// the converted data for the further processing if possible. otherwise\n// returns null.\n//\n// this function does not check the length of data; it is a duty of\n// encode function below (as it depends on the version and ECC level too).\nvar validatedata = function (mode, data) {\n\tswitch (mode) {\n\t\tcase MODE_NUMERIC:\n\t\t\tif (!data.match(NUMERIC_REGEXP))\n\t\t\t\treturn null;\n\t\t\treturn data;\n\n\t\tcase MODE_ALPHANUMERIC:\n\t\t\tif (!data.match(ALPHANUMERIC_REGEXP))\n\t\t\t\treturn null;\n\t\t\treturn data.toUpperCase();\n\n\t\tcase MODE_OCTET:\n\t\t\tif (typeof data === 'string') { // encode as utf-8 string\n\t\t\t\tvar newdata = [];\n\t\t\t\tfor (var i = 0; i < data.length; ++i) {\n\t\t\t\t\tvar ch = data.charCodeAt(i);\n\t\t\t\t\tif (ch < 0x80) {\n\t\t\t\t\t\tnewdata.push(ch);\n\t\t\t\t\t} else if (ch < 0x800) {\n\t\t\t\t\t\tnewdata.push(0xc0 | (ch >> 6),\n\t\t\t\t\t\t\t0x80 | (ch & 0x3f));\n\t\t\t\t\t} else if (ch < 0x10000) {\n\t\t\t\t\t\tnewdata.push(0xe0 | (ch >> 12),\n\t\t\t\t\t\t\t0x80 | ((ch >> 6) & 0x3f),\n\t\t\t\t\t\t\t0x80 | (ch & 0x3f));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnewdata.push(0xf0 | (ch >> 18),\n\t\t\t\t\t\t\t0x80 | ((ch >> 12) & 0x3f),\n\t\t\t\t\t\t\t0x80 | ((ch >> 6) & 0x3f),\n\t\t\t\t\t\t\t0x80 | (ch & 0x3f));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn newdata;\n\t\t\t} else {\n\t\t\t\treturn data;\n\t\t\t}\n\t}\n};\n\n// returns the code words (sans ECC bits) for given data and configurations.\n// requires data to be preprocessed by validatedata. no length check is\n// performed, and everything has to be checked before calling this function.\nvar encode = function (ver, mode, data, maxbuflen) {\n\tvar buf = [];\n\tvar bits = 0, remaining = 8;\n\tvar datalen = data.length;\n\n\t// this function is intentionally no-op when n=0.\n\tvar pack = function (x, n) {\n\t\tif (n >= remaining) {\n\t\t\tbuf.push(bits | (x >> (n -= remaining)));\n\t\t\twhile (n >= 8)\n\t\t\t\tbuf.push((x >> (n -= 8)) & 255);\n\t\t\tbits = 0;\n\t\t\tremaining = 8;\n\t\t}\n\t\tif (n > 0)\n\t\t\tbits |= (x & ((1 << n) - 1)) << (remaining -= n);\n\t};\n\n\tvar nlenbits = ndatalenbits(ver, mode);\n\tpack(mode, 4);\n\tpack(datalen, nlenbits);\n\n\tswitch (mode) {\n\t\tcase MODE_NUMERIC:\n\t\t\tfor (var i = 2; i < datalen; i += 3) {\n\t\t\t\tpack(parseInt(data.substring(i - 2, i + 1), 10), 10);\n\t\t\t}\n\t\t\tpack(parseInt(data.substring(i - 2), 10), [0, 4, 7][datalen % 3]);\n\t\t\tbreak;\n\n\t\tcase MODE_ALPHANUMERIC:\n\t\t\tfor (var i = 1; i < datalen; i += 2) {\n\t\t\t\tpack(ALPHANUMERIC_MAP[data.charAt(i - 1)] * 45 +\n\t\t\t\t\tALPHANUMERIC_MAP[data.charAt(i)], 11);\n\t\t\t}\n\t\t\tif (datalen % 2 == 1) {\n\t\t\t\tpack(ALPHANUMERIC_MAP[data.charAt(i - 1)], 6);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase MODE_OCTET:\n\t\t\tfor (var i = 0; i < datalen; ++i) {\n\t\t\t\tpack(data[i], 8);\n\t\t\t}\n\t\t\tbreak;\n\t}\n\n\t// final bits. it is possible that adding terminator causes the buffer\n\t// to overflow, but then the buffer truncated to the maximum size will\n\t// be valid as the truncated terminator mode bits and padding is\n\t// identical in appearance (cf. JIS X 0510:2004 sec 8.4.8).\n\tpack(MODE_TERMINATOR, 4);\n\tif (remaining < 8)\n\t\tbuf.push(bits);\n\n\t// the padding to fill up the remaining space. we should not add any\n\t// words when the overflow already occurred.\n\twhile (buf.length + 1 < maxbuflen)\n\t\tbuf.push(0xec, 0x11);\n\tif (buf.length < maxbuflen)\n\t\tbuf.push(0xec);\n\treturn buf;\n};\n\n// calculates ECC code words for given code words and generator polynomial.\n//\n// this is quite similar to CRC calculation as both Reed-Solomon and CRC use\n// the certain kind of cyclic codes, which is effectively the division of\n// zero-augumented polynomial by the generator polynomial. the only difference\n// is that Reed-Solomon uses GF(2^8), instead of CRC's GF(2), and Reed-Solomon\n// uses the different generator polynomial than CRC's.\nvar calculateecc = function (poly, genpoly) {\n\tvar modulus = poly.slice(0);\n\tvar polylen = poly.length, genpolylen = genpoly.length;\n\tfor (var i = 0; i < genpolylen; ++i)\n\t\tmodulus.push(0);\n\tfor (var i = 0; i < polylen; ) {\n\t\tvar quotient = GF256_INVMAP[modulus[i++]];\n\t\tif (quotient >= 0) {\n\t\t\tfor (var j = 0; j < genpolylen; ++j) {\n\t\t\t\tmodulus[i + j] ^= GF256_MAP[(quotient + genpoly[j]) % 255];\n\t\t\t}\n\t\t}\n\t}\n\treturn modulus.slice(polylen);\n};\n\n// auguments ECC code words to given code words. the resulting words are\n// ready to be encoded in the matrix.\n//\n// the much of actual augumenting procedure follows JIS X 0510:2004 sec 8.7.\n// the code is simplified using the fact that the size of each code & ECC\n// blocks is almost same; for example, when we have 4 blocks and 46 data words\n// the number of code words in those blocks are 11, 11, 12, 12 respectively.\nvar augumenteccs = function (poly, nblocks, genpoly) {\n\tvar subsizes = [];\n\tvar subsize = (poly.length / nblocks) | 0, subsize0 = 0;\n\tvar pivot = nblocks - poly.length % nblocks;\n\tfor (var i = 0; i < pivot; ++i) {\n\t\tsubsizes.push(subsize0);\n\t\tsubsize0 += subsize;\n\t}\n\tfor (var i = pivot; i < nblocks; ++i) {\n\t\tsubsizes.push(subsize0);\n\t\tsubsize0 += subsize + 1;\n\t}\n\tsubsizes.push(subsize0);\n\n\tvar eccs = [];\n\tfor (var i = 0; i < nblocks; ++i) {\n\t\teccs.push(calculateecc(poly.slice(subsizes[i], subsizes[i + 1]), genpoly));\n\t}\n\n\tvar result = [];\n\tvar nitemsperblock = (poly.length / nblocks) | 0;\n\tfor (var i = 0; i < nitemsperblock; ++i) {\n\t\tfor (var j = 0; j < nblocks; ++j) {\n\t\t\tresult.push(poly[subsizes[j] + i]);\n\t\t}\n\t}\n\tfor (var j = pivot; j < nblocks; ++j) {\n\t\tresult.push(poly[subsizes[j + 1] - 1]);\n\t}\n\tfor (var i = 0; i < genpoly.length; ++i) {\n\t\tfor (var j = 0; j < nblocks; ++j) {\n\t\t\tresult.push(eccs[j][i]);\n\t\t}\n\t}\n\treturn result;\n};\n\n// auguments BCH(p+q,q) code to the polynomial over GF(2), given the proper\n// genpoly. the both input and output are in binary numbers, and unlike\n// calculateecc genpoly should include the 1 bit for the highest degree.\n//\n// actual polynomials used for this procedure are as follows:\n// - p=10, q=5, genpoly=x^10+x^8+x^5+x^4+x^2+x+1 (JIS X 0510:2004 Appendix C)\n// - p=18, q=6, genpoly=x^12+x^11+x^10+x^9+x^8+x^5+x^2+1 (ibid. Appendix D)\nvar augumentbch = function (poly, p, genpoly, q) {\n\tvar modulus = poly << q;\n\tfor (var i = p - 1; i >= 0; --i) {\n\t\tif ((modulus >> (q + i)) & 1)\n\t\t\tmodulus ^= genpoly << i;\n\t}\n\treturn (poly << q) | modulus;\n};\n\n// creates the base matrix for given version. it returns two matrices, one of\n// them is the actual one and the another represents the \"reserved\" portion\n// (e.g. finder and timing patterns) of the matrix.\n//\n// some entries in the matrix may be undefined, rather than 0 or 1. this is\n// intentional (no initialization needed!), and putdata below will fill\n// the remaining ones.\nvar makebasematrix = function (ver) {\n\tvar v = VERSIONS[ver], n = getsizebyver(ver);\n\tvar matrix = [], reserved = [];\n\tfor (var i = 0; i < n; ++i) {\n\t\tmatrix.push([]);\n\t\treserved.push([]);\n\t}\n\n\tvar blit = function (y, x, h, w, bits) {\n\t\tfor (var i = 0; i < h; ++i) {\n\t\t\tfor (var j = 0; j < w; ++j) {\n\t\t\t\tmatrix[y + i][x + j] = (bits[i] >> j) & 1;\n\t\t\t\treserved[y + i][x + j] = 1;\n\t\t\t}\n\t\t}\n\t};\n\n\t// finder patterns and a part of timing patterns\n\t// will also mark the format information area (not yet written) as reserved.\n\tblit(0, 0, 9, 9, [0x7f, 0x41, 0x5d, 0x5d, 0x5d, 0x41, 0x17f, 0x00, 0x40]);\n\tblit(n - 8, 0, 8, 9, [0x100, 0x7f, 0x41, 0x5d, 0x5d, 0x5d, 0x41, 0x7f]);\n\tblit(0, n - 8, 9, 8, [0xfe, 0x82, 0xba, 0xba, 0xba, 0x82, 0xfe, 0x00, 0x00]);\n\n\t// the rest of timing patterns\n\tfor (var i = 9; i < n - 8; ++i) {\n\t\tmatrix[6][i] = matrix[i][6] = ~i & 1;\n\t\treserved[6][i] = reserved[i][6] = 1;\n\t}\n\n\t// alignment patterns\n\tvar aligns = v[2], m = aligns.length;\n\tfor (var i = 0; i < m; ++i) {\n\t\tvar minj = (i === 0 || i === m - 1 ? 1 : 0), maxj = (i === 0 ? m - 1 : m);\n\t\tfor (var j = minj; j < maxj; ++j) {\n\t\t\tblit(aligns[i], aligns[j], 5, 5, [0x1f, 0x11, 0x15, 0x11, 0x1f]);\n\t\t}\n\t}\n\n\t// version information\n\tif (needsverinfo(ver)) {\n\t\tvar code = augumentbch(ver, 6, 0x1f25, 12);\n\t\tvar k = 0;\n\t\tfor (var i = 0; i < 6; ++i) {\n\t\t\tfor (var j = 0; j < 3; ++j) {\n\t\t\t\tmatrix[i][(n - 11) + j] = matrix[(n - 11) + j][i] = (code >> k++) & 1;\n\t\t\t\treserved[i][(n - 11) + j] = reserved[(n - 11) + j][i] = 1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {matrix: matrix, reserved: reserved};\n};\n\n// fills the data portion (i.e. unmarked in reserved) of the matrix with given\n// code words. the size of code words should be no more than available bits,\n// and remaining bits are padded to 0 (cf. JIS X 0510:2004 sec 8.7.3).\nvar putdata = function (matrix, reserved, buf) {\n\tvar n = matrix.length;\n\tvar k = 0, dir = -1;\n\tfor (var i = n - 1; i >= 0; i -= 2) {\n\t\tif (i == 6)\n\t\t\t--i; // skip the entire timing pattern column\n\t\tvar jj = (dir < 0 ? n - 1 : 0);\n\t\tfor (var j = 0; j < n; ++j) {\n\t\t\tfor (var ii = i; ii > i - 2; --ii) {\n\t\t\t\tif (!reserved[jj][ii]) {\n\t\t\t\t\t// may overflow, but (undefined >> x)\n\t\t\t\t\t// is 0 so it will auto-pad to zero.\n\t\t\t\t\tmatrix[jj][ii] = (buf[k >> 3] >> (~k & 7)) & 1;\n\t\t\t\t\t++k;\n\t\t\t\t}\n\t\t\t}\n\t\t\tjj += dir;\n\t\t}\n\t\tdir = -dir;\n\t}\n\treturn matrix;\n};\n\n// XOR-masks the data portion of the matrix. repeating the call with the same\n// arguments will revert the prior call (convenient in the matrix evaluation).\nvar maskdata = function (matrix, reserved, mask) {\n\tvar maskf = MASKFUNCS[mask];\n\tvar n = matrix.length;\n\tfor (var i = 0; i < n; ++i) {\n\t\tfor (var j = 0; j < n; ++j) {\n\t\t\tif (!reserved[i][j])\n\t\t\t\tmatrix[i][j] ^= maskf(i, j);\n\t\t}\n\t}\n\treturn matrix;\n};\n\n// puts the format information.\nvar putformatinfo = function (matrix, reserved, ecclevel, mask) {\n\tvar n = matrix.length;\n\tvar code = augumentbch((ecclevel << 3) | mask, 5, 0x537, 10) ^ 0x5412;\n\tfor (var i = 0; i < 15; ++i) {\n\t\tvar r = [0, 1, 2, 3, 4, 5, 7, 8, n - 7, n - 6, n - 5, n - 4, n - 3, n - 2, n - 1][i];\n\t\tvar c = [n - 1, n - 2, n - 3, n - 4, n - 5, n - 6, n - 7, n - 8, 7, 5, 4, 3, 2, 1, 0][i];\n\t\tmatrix[r][8] = matrix[8][c] = (code >> i) & 1;\n\t\t// we don't have to mark those bits reserved; always done\n\t\t// in makebasematrix above.\n\t}\n\treturn matrix;\n};\n\n// evaluates the resulting matrix and returns the score (lower is better).\n// (cf. JIS X 0510:2004 sec 8.8.2)\n//\n// the evaluation procedure tries to avoid the problematic patterns naturally\n// occuring from the original matrix. for example, it penaltizes the patterns\n// which just look like the finder pattern which will confuse the decoder.\n// we choose the mask which results in the lowest score among 8 possible ones.\n//\n// note: zxing seems to use the same procedure and in many cases its choice\n// agrees to ours, but sometimes it does not. practically it doesn't matter.\nvar evaluatematrix = function (matrix) {\n\t// N1+(k-5) points for each consecutive row of k same-colored modules,\n\t// where k >= 5. no overlapping row counts.\n\tvar PENALTY_CONSECUTIVE = 3;\n\t// N2 points for each 2x2 block of same-colored modules.\n\t// overlapping block does count.\n\tvar PENALTY_TWOBYTWO = 3;\n\t// N3 points for each pattern with >4W:1B:1W:3B:1W:1B or\n\t// 1B:1W:3B:1W:1B:>4W, or their multiples (e.g. highly unlikely,\n\t// but 13W:3B:3W:9B:3W:3B counts).\n\tvar PENALTY_FINDERLIKE = 40;\n\t// N4*k points for every (5*k)% deviation from 50% black density.\n\t// i.e. k=1 for 55~60% and 40~45%, k=2 for 60~65% and 35~40%, etc.\n\tvar PENALTY_DENSITY = 10;\n\n\tvar evaluategroup = function (groups) { // assumes [W,B,W,B,W,...,B,W]\n\t\tvar score = 0;\n\t\tfor (var i = 0; i < groups.length; ++i) {\n\t\t\tif (groups[i] >= 5)\n\t\t\t\tscore += PENALTY_CONSECUTIVE + (groups[i] - 5);\n\t\t}\n\t\tfor (var i = 5; i < groups.length; i += 2) {\n\t\t\tvar p = groups[i];\n\t\t\tif (groups[i - 1] == p && groups[i - 2] == 3 * p && groups[i - 3] == p &&\n\t\t\t\tgroups[i - 4] == p && (groups[i - 5] >= 4 * p || groups[i + 1] >= 4 * p)) {\n\t\t\t\t// this part differs from zxing...\n\t\t\t\tscore += PENALTY_FINDERLIKE;\n\t\t\t}\n\t\t}\n\t\treturn score;\n\t};\n\n\tvar n = matrix.length;\n\tvar score = 0, nblacks = 0;\n\tfor (var i = 0; i < n; ++i) {\n\t\tvar row = matrix[i];\n\t\tvar groups;\n\n\t\t// evaluate the current row\n\t\tgroups = [0]; // the first empty group of white\n\t\tfor (var j = 0; j < n; ) {\n\t\t\tvar k;\n\t\t\tfor (k = 0; j < n && row[j]; ++k)\n\t\t\t\t++j;\n\t\t\tgroups.push(k);\n\t\t\tfor (k = 0; j < n && !row[j]; ++k)\n\t\t\t\t++j;\n\t\t\tgroups.push(k);\n\t\t}\n\t\tscore += evaluategroup(groups);\n\n\t\t// evaluate the current column\n\t\tgroups = [0];\n\t\tfor (var j = 0; j < n; ) {\n\t\t\tvar k;\n\t\t\tfor (k = 0; j < n && matrix[j][i]; ++k)\n\t\t\t\t++j;\n\t\t\tgroups.push(k);\n\t\t\tfor (k = 0; j < n && !matrix[j][i]; ++k)\n\t\t\t\t++j;\n\t\t\tgroups.push(k);\n\t\t}\n\t\tscore += evaluategroup(groups);\n\n\t\t// check the 2x2 box and calculate the density\n\t\tvar nextrow = matrix[i + 1] || [];\n\t\tnblacks += row[0];\n\t\tfor (var j = 1; j < n; ++j) {\n\t\t\tvar p = row[j];\n\t\t\tnblacks += p;\n\t\t\t// at least comparison with next row should be strict...\n\t\t\tif (row[j - 1] == p && nextrow[j] === p && nextrow[j - 1] === p) {\n\t\t\t\tscore += PENALTY_TWOBYTWO;\n\t\t\t}\n\t\t}\n\t}\n\n\tscore += PENALTY_DENSITY * ((Math.abs(nblacks / n / n - 0.5) / 0.05) | 0);\n\treturn score;\n};\n\n// returns the fully encoded QR code matrix which contains given data.\n// it also chooses the best mask automatically when mask is -1.\nvar generate = function (data, ver, mode, ecclevel, mask) {\n\tvar v = VERSIONS[ver];\n\tvar buf = encode(ver, mode, data, ndatabits(ver, ecclevel) >> 3);\n\tbuf = augumenteccs(buf, v[1][ecclevel], GF256_GENPOLY[v[0][ecclevel]]);\n\n\tvar result = makebasematrix(ver);\n\tvar matrix = result.matrix, reserved = result.reserved;\n\tputdata(matrix, reserved, buf);\n\n\tif (mask < 0) {\n\t\t// find the best mask\n\t\tmaskdata(matrix, reserved, 0);\n\t\tputformatinfo(matrix, reserved, ecclevel, 0);\n\t\tvar bestmask = 0, bestscore = evaluatematrix(matrix);\n\t\tmaskdata(matrix, reserved, 0);\n\t\tfor (mask = 1; mask < 8; ++mask) {\n\t\t\tmaskdata(matrix, reserved, mask);\n\t\t\tputformatinfo(matrix, reserved, ecclevel, mask);\n\t\t\tvar score = evaluatematrix(matrix);\n\t\t\tif (bestscore > score) {\n\t\t\t\tbestscore = score;\n\t\t\t\tbestmask = mask;\n\t\t\t}\n\t\t\tmaskdata(matrix, reserved, mask);\n\t\t}\n\t\tmask = bestmask;\n\t}\n\n\tmaskdata(matrix, reserved, mask);\n\tputformatinfo(matrix, reserved, ecclevel, mask);\n\treturn matrix;\n};\n\n// the public interface is trivial; the options available are as follows:\n//\n// - version: an integer in [1,40]. when omitted (or -1) the smallest possible\n//   version is chosen.\n// - mode: one of 'numeric', 'alphanumeric', 'octet'. when omitted the smallest\n//   possible mode is chosen.\n// - eccLevel: one of 'L', 'M', 'Q', 'H'. defaults to 'L'.\n// - mask: an integer in [0,7]. when omitted (or -1) the best mask is chosen.\n//\n\nfunction generateFrame(data, options) {\n\tvar MODES = {'numeric': MODE_NUMERIC, 'alphanumeric': MODE_ALPHANUMERIC,\n\t\t'octet': MODE_OCTET};\n\tvar ECCLEVELS = {'L': ECCLEVEL_L, 'M': ECCLEVEL_M, 'Q': ECCLEVEL_Q,\n\t\t'H': ECCLEVEL_H};\n\n\toptions = options || {};\n\tvar ver = options.version || -1;\n\tvar ecclevel = ECCLEVELS[(options.eccLevel || 'L').toUpperCase()];\n\tvar mode = options.mode ? MODES[options.mode.toLowerCase()] : -1;\n\tvar mask = 'mask' in options ? options.mask : -1;\n\n\tif (mode < 0) {\n\t\tif (typeof data === 'string') {\n\t\t\tif (data.match(NUMERIC_REGEXP)) {\n\t\t\t\tmode = MODE_NUMERIC;\n\t\t\t} else if (data.match(ALPHANUMERIC_OUT_REGEXP)) {\n\t\t\t\t// while encode supports case-insensitive encoding, we restrict the data to be uppercased when auto-selecting the mode.\n\t\t\t\tmode = MODE_ALPHANUMERIC;\n\t\t\t} else {\n\t\t\t\tmode = MODE_OCTET;\n\t\t\t}\n\t\t} else {\n\t\t\tmode = MODE_OCTET;\n\t\t}\n\t} else if (!(mode == MODE_NUMERIC || mode == MODE_ALPHANUMERIC ||\n\t\tmode == MODE_OCTET)) {\n\t\tthrow 'invalid or unsupported mode';\n\t}\n\n\tdata = validatedata(mode, data);\n\tif (data === null)\n\t\tthrow 'invalid data format';\n\n\tif (ecclevel < 0 || ecclevel > 3)\n\t\tthrow 'invalid ECC level';\n\n\tif (ver < 0) {\n\t\tfor (ver = 1; ver <= 40; ++ver) {\n\t\t\tif (data.length <= getmaxdatalen(ver, mode, ecclevel))\n\t\t\t\tbreak;\n\t\t}\n\t\tif (ver > 40)\n\t\t\tthrow 'too large data for the Qr format';\n\t} else if (ver < 1 || ver > 40) {\n\t\tthrow 'invalid Qr version! should be between 1 and 40';\n\t}\n\n\tif (mask != -1 && (mask < 0 || mask > 8))\n\t\tthrow 'invalid mask';\n\t//console.log('version:', ver, 'mode:', mode, 'ECC:', ecclevel, 'mask:', mask )\n\treturn generate(data, ver, mode, ecclevel, mask);\n}\n\n\n// options\n// - modulesize: a number. this is a size of each modules in pixels, and\n//   defaults to 5px.\n// - margin: a number. this is a size of margin in *modules*, and defaults to\n//   4 (white modules). the specficiation mandates the margin no less than 4\n//   modules, so it is better not to alter this value unless you know what\n//   you're doing.\nfunction buildCanvas(data, options) {\n\n\tvar canvas = [];\n\tvar background = options.background || '#fff';\n\tvar foreground = options.foreground || '#000';\n\t//var margin = options.margin || 4;\n\tvar matrix = generateFrame(data, options);\n\tvar n = matrix.length;\n\tvar modSize = Math.floor(options.fit ? options.fit / n : 5);\n\tvar size = n * modSize;\n\n\tcanvas.push({\n\t\ttype: 'rect',\n\t\tx: 0, y: 0, w: size, h: size, lineWidth: 0, color: background\n\t});\n\n\tfor (var i = 0; i < n; ++i) {\n\t\tfor (var j = 0; j < n; ++j) {\n\t\t\tif (matrix[i][j]) {\n\t\t\t\tcanvas.push({\n\t\t\t\t\ttype: 'rect',\n\t\t\t\t\tx: modSize * j,\n\t\t\t\t\ty: modSize * i,\n\t\t\t\t\tw: modSize,\n\t\t\t\t\th: modSize,\n\t\t\t\t\tlineWidth: 0,\n\t\t\t\t\tcolor: foreground\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tcanvas: canvas,\n\t\tsize: size\n\t};\n\n}\n\nfunction measure(node) {\n\tvar cd = buildCanvas(node.qr, node);\n\tnode._canvas = cd.canvas;\n\tnode._width = node._height = node._minWidth = node._maxWidth = node._minHeight = node._maxHeight = cd.size;\n\treturn node;\n}\n\nmodule.exports = {\n\tmeasure: measure\n};\n\n/***/ }),\n/* 135 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar ElementWriter = __webpack_require__(136);\n\n/**\n * Creates an instance of PageElementWriter - an extended ElementWriter\n * which can handle:\n * - page-breaks (it adds new pages when there's not enough space left),\n * - repeatable fragments (like table-headers, which are repeated everytime\n *                         a page-break occurs)\n * - transactions (used for unbreakable-blocks when we want to make sure\n *                 whole block will be rendered on the same page)\n */\nfunction PageElementWriter(context, tracker) {\n\tthis.transactionLevel = 0;\n\tthis.repeatables = [];\n\tthis.tracker = tracker;\n\tthis.writer = new ElementWriter(context, tracker);\n}\n\nfunction fitOnPage(self, addFct) {\n\tvar position = addFct(self);\n\tif (!position) {\n\t\tself.moveToNextPage();\n\t\tposition = addFct(self);\n\t}\n\treturn position;\n}\n\nPageElementWriter.prototype.addLine = function (line, dontUpdateContextPosition, index) {\n\treturn fitOnPage(this, function (self) {\n\t\treturn self.writer.addLine(line, dontUpdateContextPosition, index);\n\t});\n};\n\nPageElementWriter.prototype.addImage = function (image, index) {\n\treturn fitOnPage(this, function (self) {\n\t\treturn self.writer.addImage(image, index);\n\t});\n};\n\nPageElementWriter.prototype.addQr = function (qr, index) {\n\treturn fitOnPage(this, function (self) {\n\t\treturn self.writer.addQr(qr, index);\n\t});\n};\n\nPageElementWriter.prototype.addVector = function (vector, ignoreContextX, ignoreContextY, index) {\n\treturn this.writer.addVector(vector, ignoreContextX, ignoreContextY, index);\n};\n\nPageElementWriter.prototype.beginClip = function (width, height) {\n\treturn this.writer.beginClip(width, height);\n};\n\nPageElementWriter.prototype.endClip = function () {\n\treturn this.writer.endClip();\n};\n\nPageElementWriter.prototype.alignCanvas = function (node) {\n\tthis.writer.alignCanvas(node);\n};\n\nPageElementWriter.prototype.addFragment = function (fragment, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition) {\n\tif (!this.writer.addFragment(fragment, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition)) {\n\t\tthis.moveToNextPage();\n\t\tthis.writer.addFragment(fragment, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition);\n\t}\n};\n\nPageElementWriter.prototype.moveToNextPage = function (pageOrientation) {\n\n\tvar nextPage = this.writer.context.moveToNextPage(pageOrientation);\n\n\tif (nextPage.newPageCreated) {\n\t\tthis.repeatables.forEach(function (rep) {\n\t\t\tthis.writer.addFragment(rep, true);\n\t\t}, this);\n\t} else {\n\t\tthis.repeatables.forEach(function (rep) {\n\t\t\tthis.writer.context.moveDown(rep.height);\n\t\t}, this);\n\t}\n\n\tthis.writer.tracker.emit('pageChanged', {\n\t\tprevPage: nextPage.prevPage,\n\t\tprevY: nextPage.prevY,\n\t\ty: nextPage.y\n\t});\n};\n\nPageElementWriter.prototype.beginUnbreakableBlock = function (width, height) {\n\tif (this.transactionLevel++ === 0) {\n\t\tthis.originalX = this.writer.context.x;\n\t\tthis.writer.pushContext(width, height);\n\t}\n};\n\nPageElementWriter.prototype.commitUnbreakableBlock = function (forcedX, forcedY) {\n\tif (--this.transactionLevel === 0) {\n\t\tvar unbreakableContext = this.writer.context;\n\t\tthis.writer.popContext();\n\n\t\tvar nbPages = unbreakableContext.pages.length;\n\t\tif (nbPages > 0) {\n\t\t\t// no support for multi-page unbreakableBlocks\n\t\t\tvar fragment = unbreakableContext.pages[0];\n\t\t\tfragment.xOffset = forcedX;\n\t\t\tfragment.yOffset = forcedY;\n\n\t\t\t//TODO: vectors can influence height in some situations\n\t\t\tif (nbPages > 1) {\n\t\t\t\t// on out-of-context blocs (headers, footers, background) height should be the whole DocumentContext height\n\t\t\t\tif (forcedX !== undefined || forcedY !== undefined) {\n\t\t\t\t\tfragment.height = unbreakableContext.getCurrentPage().pageSize.height - unbreakableContext.pageMargins.top - unbreakableContext.pageMargins.bottom;\n\t\t\t\t} else {\n\t\t\t\t\tfragment.height = this.writer.context.getCurrentPage().pageSize.height - this.writer.context.pageMargins.top - this.writer.context.pageMargins.bottom;\n\t\t\t\t\tfor (var i = 0, l = this.repeatables.length; i < l; i++) {\n\t\t\t\t\t\tfragment.height -= this.repeatables[i].height;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfragment.height = unbreakableContext.y;\n\t\t\t}\n\n\t\t\tif (forcedX !== undefined || forcedY !== undefined) {\n\t\t\t\tthis.writer.addFragment(fragment, true, true, true);\n\t\t\t} else {\n\t\t\t\tthis.addFragment(fragment);\n\t\t\t}\n\t\t}\n\t}\n};\n\nPageElementWriter.prototype.currentBlockToRepeatable = function () {\n\tvar unbreakableContext = this.writer.context;\n\tvar rep = {items: []};\n\n\tunbreakableContext.pages[0].items.forEach(function (item) {\n\t\trep.items.push(item);\n\t});\n\n\trep.xOffset = this.originalX;\n\n\t//TODO: vectors can influence height in some situations\n\trep.height = unbreakableContext.y;\n\n\treturn rep;\n};\n\nPageElementWriter.prototype.pushToRepeatables = function (rep) {\n\tthis.repeatables.push(rep);\n};\n\nPageElementWriter.prototype.popFromRepeatables = function () {\n\tthis.repeatables.pop();\n};\n\nPageElementWriter.prototype.context = function () {\n\treturn this.writer.context;\n};\n\nmodule.exports = PageElementWriter;\n\n\n/***/ }),\n/* 136 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar Line = __webpack_require__(82);\nvar isNumber = __webpack_require__(0).isNumber;\nvar pack = __webpack_require__(0).pack;\nvar offsetVector = __webpack_require__(0).offsetVector;\nvar DocumentContext = __webpack_require__(81);\n\n/**\n * Creates an instance of ElementWriter - a line/vector writer, which adds\n * elements to current page and sets their positions based on the context\n */\nfunction ElementWriter(context, tracker) {\n\tthis.context = context;\n\tthis.contextStack = [];\n\tthis.tracker = tracker;\n}\n\nfunction addPageItem(page, item, index) {\n\tif (index === null || index === undefined || index < 0 || index > page.items.length) {\n\t\tpage.items.push(item);\n\t} else {\n\t\tpage.items.splice(index, 0, item);\n\t}\n}\n\nElementWriter.prototype.addLine = function (line, dontUpdateContextPosition, index) {\n\tvar height = line.getHeight();\n\tvar context = this.context;\n\tvar page = context.getCurrentPage(),\n\t\tposition = this.getCurrentPositionOnPage();\n\n\tif (context.availableHeight < height || !page) {\n\t\treturn false;\n\t}\n\n\tline.x = context.x + (line.x || 0);\n\tline.y = context.y + (line.y || 0);\n\n\tthis.alignLine(line);\n\n\taddPageItem(page, {\n\t\ttype: 'line',\n\t\titem: line\n\t}, index);\n\tthis.tracker.emit('lineAdded', line);\n\n\tif (!dontUpdateContextPosition) {\n\t\tcontext.moveDown(height);\n\t}\n\n\treturn position;\n};\n\nElementWriter.prototype.alignLine = function (line) {\n\tvar width = this.context.availableWidth;\n\tvar lineWidth = line.getWidth();\n\n\tvar alignment = line.inlines && line.inlines.length > 0 && line.inlines[0].alignment;\n\n\tvar offset = 0;\n\tswitch (alignment) {\n\t\tcase 'right':\n\t\t\toffset = width - lineWidth;\n\t\t\tbreak;\n\t\tcase 'center':\n\t\t\toffset = (width - lineWidth) / 2;\n\t\t\tbreak;\n\t}\n\n\tif (offset) {\n\t\tline.x = (line.x || 0) + offset;\n\t}\n\n\tif (alignment === 'justify' &&\n\t\t!line.newLineForced &&\n\t\t!line.lastLineInParagraph &&\n\t\tline.inlines.length > 1) {\n\t\tvar additionalSpacing = (width - lineWidth) / (line.inlines.length - 1);\n\n\t\tfor (var i = 1, l = line.inlines.length; i < l; i++) {\n\t\t\toffset = i * additionalSpacing;\n\n\t\t\tline.inlines[i].x += offset;\n\t\t\tline.inlines[i].justifyShift = additionalSpacing;\n\t\t}\n\t}\n};\n\nElementWriter.prototype.addImage = function (image, index) {\n\tvar context = this.context;\n\tvar page = context.getCurrentPage(),\n\t\tposition = this.getCurrentPositionOnPage();\n\n\tif (!page || (image.absolutePosition === undefined && context.availableHeight < image._height && page.items.length > 0)) {\n\t\treturn false;\n\t}\n\n\tif (image._x === undefined) {\n\t\timage._x = image.x || 0;\n\t}\n\n\timage.x = context.x + image._x;\n\timage.y = context.y;\n\n\tthis.alignImage(image);\n\n\taddPageItem(page, {\n\t\ttype: 'image',\n\t\titem: image\n\t}, index);\n\n\tcontext.moveDown(image._height);\n\n\treturn position;\n};\n\nElementWriter.prototype.addQr = function (qr, index) {\n\tvar context = this.context;\n\tvar page = context.getCurrentPage(),\n\t\tposition = this.getCurrentPositionOnPage();\n\n\tif (!page || (qr.absolutePosition === undefined && context.availableHeight < qr._height)) {\n\t\treturn false;\n\t}\n\n\tif (qr._x === undefined) {\n\t\tqr._x = qr.x || 0;\n\t}\n\n\tqr.x = context.x + qr._x;\n\tqr.y = context.y;\n\n\tthis.alignImage(qr);\n\n\tfor (var i = 0, l = qr._canvas.length; i < l; i++) {\n\t\tvar vector = qr._canvas[i];\n\t\tvector.x += qr.x;\n\t\tvector.y += qr.y;\n\t\tthis.addVector(vector, true, true, index);\n\t}\n\n\tcontext.moveDown(qr._height);\n\n\treturn position;\n};\n\nElementWriter.prototype.alignImage = function (image) {\n\tvar width = this.context.availableWidth;\n\tvar imageWidth = image._minWidth;\n\tvar offset = 0;\n\tswitch (image._alignment) {\n\t\tcase 'right':\n\t\t\toffset = width - imageWidth;\n\t\t\tbreak;\n\t\tcase 'center':\n\t\t\toffset = (width - imageWidth) / 2;\n\t\t\tbreak;\n\t}\n\n\tif (offset) {\n\t\timage.x = (image.x || 0) + offset;\n\t}\n};\n\nElementWriter.prototype.alignCanvas = function (node) {\n\tvar width = this.context.availableWidth;\n\tvar canvasWidth = node._minWidth;\n\tvar offset = 0;\n\tswitch (node._alignment) {\n\t\tcase 'right':\n\t\t\toffset = width - canvasWidth;\n\t\t\tbreak;\n\t\tcase 'center':\n\t\t\toffset = (width - canvasWidth) / 2;\n\t\t\tbreak;\n\t}\n\tif (offset) {\n\t\tnode.canvas.forEach(function (vector) {\n\t\t\toffsetVector(vector, offset, 0);\n\t\t});\n\t}\n};\n\nElementWriter.prototype.addVector = function (vector, ignoreContextX, ignoreContextY, index) {\n\tvar context = this.context;\n\tvar page = context.getCurrentPage(),\n\t\tposition = this.getCurrentPositionOnPage();\n\n\tif (page) {\n\t\toffsetVector(vector, ignoreContextX ? 0 : context.x, ignoreContextY ? 0 : context.y);\n\t\taddPageItem(page, {\n\t\t\ttype: 'vector',\n\t\t\titem: vector\n\t\t}, index);\n\t\treturn position;\n\t}\n};\n\nElementWriter.prototype.beginClip = function (width, height) {\n\tvar ctx = this.context;\n\tvar page = ctx.getCurrentPage();\n\tpage.items.push({\n\t\ttype: 'beginClip',\n\t\titem: {x: ctx.x, y: ctx.y, width: width, height: height}\n\t});\n\treturn true;\n};\n\nElementWriter.prototype.endClip = function () {\n\tvar ctx = this.context;\n\tvar page = ctx.getCurrentPage();\n\tpage.items.push({\n\t\ttype: 'endClip'\n\t});\n\treturn true;\n};\n\nfunction cloneLine(line) {\n\tvar result = new Line(line.maxWidth);\n\n\tfor (var key in line) {\n\t\tif (line.hasOwnProperty(key)) {\n\t\t\tresult[key] = line[key];\n\t\t}\n\t}\n\n\treturn result;\n}\n\nElementWriter.prototype.addFragment = function (block, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition) {\n\tvar ctx = this.context;\n\tvar page = ctx.getCurrentPage();\n\n\tif (!useBlockXOffset && block.height > ctx.availableHeight) {\n\t\treturn false;\n\t}\n\n\tblock.items.forEach(function (item) {\n\t\tswitch (item.type) {\n\t\t\tcase 'line':\n\t\t\t\tvar l = cloneLine(item.item);\n\n\t\t\t\tl.x = (l.x || 0) + (useBlockXOffset ? (block.xOffset || 0) : ctx.x);\n\t\t\t\tl.y = (l.y || 0) + (useBlockYOffset ? (block.yOffset || 0) : ctx.y);\n\n\t\t\t\tpage.items.push({\n\t\t\t\t\ttype: 'line',\n\t\t\t\t\titem: l\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase 'vector':\n\t\t\t\tvar v = pack(item.item);\n\n\t\t\t\toffsetVector(v, useBlockXOffset ? (block.xOffset || 0) : ctx.x, useBlockYOffset ? (block.yOffset || 0) : ctx.y);\n\t\t\t\tpage.items.push({\n\t\t\t\t\ttype: 'vector',\n\t\t\t\t\titem: v\n\t\t\t\t});\n\t\t\t\tbreak;\n\n\t\t\tcase 'image':\n\t\t\t\tvar img = pack(item.item);\n\n\t\t\t\timg.x = (img.x || 0) + (useBlockXOffset ? (block.xOffset || 0) : ctx.x);\n\t\t\t\timg.y = (img.y || 0) + (useBlockYOffset ? (block.yOffset || 0) : ctx.y);\n\n\t\t\t\tpage.items.push({\n\t\t\t\t\ttype: 'image',\n\t\t\t\t\titem: img\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t}\n\t});\n\n\tif (!dontUpdateContextPosition) {\n\t\tctx.moveDown(block.height);\n\t}\n\n\treturn true;\n};\n\n/**\n * Pushes the provided context onto the stack or creates a new one\n *\n * pushContext(context) - pushes the provided context and makes it current\n * pushContext(width, height) - creates and pushes a new context with the specified width and height\n * pushContext() - creates a new context for unbreakable blocks (with current availableWidth and full-page-height)\n */\nElementWriter.prototype.pushContext = function (contextOrWidth, height) {\n\tif (contextOrWidth === undefined) {\n\t\theight = this.context.getCurrentPage().height - this.context.pageMargins.top - this.context.pageMargins.bottom;\n\t\tcontextOrWidth = this.context.availableWidth;\n\t}\n\n\tif (isNumber(contextOrWidth)) {\n\t\tcontextOrWidth = new DocumentContext({width: contextOrWidth, height: height}, {left: 0, right: 0, top: 0, bottom: 0});\n\t}\n\n\tthis.contextStack.push(this.context);\n\tthis.context = contextOrWidth;\n};\n\nElementWriter.prototype.popContext = function () {\n\tthis.context = this.contextStack.pop();\n};\n\nElementWriter.prototype.getCurrentPositionOnPage = function () {\n\treturn (this.contextStack[0] || this.context).getCurrentPosition();\n};\n\n\nmodule.exports = ElementWriter;\n\n\n/***/ }),\n/* 137 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar ColumnCalculator = __webpack_require__(44);\nvar isFunction = __webpack_require__(0).isFunction;\n\nfunction TableProcessor(tableNode) {\n\tthis.tableNode = tableNode;\n}\n\nTableProcessor.prototype.beginTable = function (writer) {\n\tvar tableNode;\n\tvar availableWidth;\n\tvar self = this;\n\n\ttableNode = this.tableNode;\n\tthis.offsets = tableNode._offsets;\n\tthis.layout = tableNode._layout;\n\n\tavailableWidth = writer.context().availableWidth - this.offsets.total;\n\tColumnCalculator.buildColumnWidths(tableNode.table.widths, availableWidth);\n\n\tthis.tableWidth = tableNode._offsets.total + getTableInnerContentWidth();\n\tthis.rowSpanData = prepareRowSpanData();\n\tthis.cleanUpRepeatables = false;\n\n\tthis.headerRows = tableNode.table.headerRows || 0;\n\tthis.rowsWithoutPageBreak = this.headerRows + (tableNode.table.keepWithHeaderRows || 0);\n\tthis.dontBreakRows = tableNode.table.dontBreakRows || false;\n\n\tif (this.rowsWithoutPageBreak) {\n\t\twriter.beginUnbreakableBlock();\n\t}\n\n\t// update the border properties of all cells before drawing any lines\n\tprepareCellBorders(this.tableNode.table.body);\n\n\tthis.drawHorizontalLine(0, writer);\n\n\tfunction getTableInnerContentWidth() {\n\t\tvar width = 0;\n\n\t\ttableNode.table.widths.forEach(function (w) {\n\t\t\twidth += w._calcWidth;\n\t\t});\n\n\t\treturn width;\n\t}\n\n\tfunction prepareRowSpanData() {\n\t\tvar rsd = [];\n\t\tvar x = 0;\n\t\tvar lastWidth = 0;\n\n\t\trsd.push({left: 0, rowSpan: 0});\n\n\t\tfor (var i = 0, l = self.tableNode.table.body[0].length; i < l; i++) {\n\t\t\tvar paddings = self.layout.paddingLeft(i, self.tableNode) + self.layout.paddingRight(i, self.tableNode);\n\t\t\tvar lBorder = self.layout.vLineWidth(i, self.tableNode);\n\t\t\tlastWidth = paddings + lBorder + self.tableNode.table.widths[i]._calcWidth;\n\t\t\trsd[rsd.length - 1].width = lastWidth;\n\t\t\tx += lastWidth;\n\t\t\trsd.push({left: x, rowSpan: 0, width: 0});\n\t\t}\n\n\t\treturn rsd;\n\t}\n\n\t// Iterate through all cells. If the current cell is the start of a\n\t// rowSpan/colSpan, update the border property of the cells on its\n\t// bottom/right accordingly. This is needed since each iteration of the\n\t// line-drawing loops draws lines for a single cell, not for an entire\n\t// rowSpan/colSpan.\n\tfunction prepareCellBorders(body) {\n\t\tfor (var rowIndex = 0; rowIndex < body.length; rowIndex++) {\n\t\t\tvar row = body[rowIndex];\n\n\t\t\tfor (var colIndex = 0; colIndex < row.length; colIndex++) {\n\t\t\t\tvar cell = row[colIndex];\n\n\t\t\t\tif (cell.border) {\n\t\t\t\t\tvar rowSpan = cell.rowSpan || 1;\n\t\t\t\t\tvar colSpan = cell.colSpan || 1;\n\n\t\t\t\t\tfor (var rowOffset = 0; rowOffset < rowSpan; rowOffset++) {\n\t\t\t\t\t\t// set left border\n\t\t\t\t\t\tif (cell.border[0] !== undefined && rowOffset > 0) {\n\t\t\t\t\t\t\tsetBorder(rowIndex + rowOffset, colIndex, 0, cell.border[0]);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// set right border\n\t\t\t\t\t\tif (cell.border[2] !== undefined) {\n\t\t\t\t\t\t\tsetBorder(rowIndex + rowOffset, colIndex + colSpan - 1, 2, cell.border[2]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (var colOffset = 0; colOffset < colSpan; colOffset++) {\n\t\t\t\t\t\t// set top border\n\t\t\t\t\t\tif (cell.border[1] !== undefined && colOffset > 0) {\n\t\t\t\t\t\t\tsetBorder(rowIndex, colIndex + colOffset, 1, cell.border[1]);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// set bottom border\n\t\t\t\t\t\tif (cell.border[3] !== undefined) {\n\t\t\t\t\t\t\tsetBorder(rowIndex + rowSpan - 1, colIndex + colOffset, 3, cell.border[3]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// helper function to set the border for a given cell\n\t\tfunction setBorder(rowIndex, colIndex, borderIndex, borderValue) {\n\t\t\tvar cell = body[rowIndex][colIndex];\n\t\t\tcell.border = cell.border || {};\n\t\t\tcell.border[borderIndex] = borderValue;\n\t\t}\n\t}\n};\n\nTableProcessor.prototype.onRowBreak = function (rowIndex, writer) {\n\tvar self = this;\n\treturn function () {\n\t\tvar offset = self.rowPaddingTop + (!self.headerRows ? self.topLineWidth : 0);\n\t\twriter.context().availableHeight -= self.reservedAtBottom;\n\t\twriter.context().moveDown(offset);\n\t};\n};\n\nTableProcessor.prototype.beginRow = function (rowIndex, writer) {\n\tthis.topLineWidth = this.layout.hLineWidth(rowIndex, this.tableNode);\n\tthis.rowPaddingTop = this.layout.paddingTop(rowIndex, this.tableNode);\n\tthis.bottomLineWidth = this.layout.hLineWidth(rowIndex + 1, this.tableNode);\n\tthis.rowPaddingBottom = this.layout.paddingBottom(rowIndex, this.tableNode);\n\n\tthis.rowCallback = this.onRowBreak(rowIndex, writer);\n\twriter.tracker.startTracking('pageChanged', this.rowCallback);\n\tif (this.dontBreakRows) {\n\t\twriter.beginUnbreakableBlock();\n\t}\n\tthis.rowTopY = writer.context().y;\n\tthis.reservedAtBottom = this.bottomLineWidth + this.rowPaddingBottom;\n\n\twriter.context().availableHeight -= this.reservedAtBottom;\n\n\twriter.context().moveDown(this.rowPaddingTop);\n};\n\nTableProcessor.prototype.drawHorizontalLine = function (lineIndex, writer, overrideY) {\n\tvar lineWidth = this.layout.hLineWidth(lineIndex, this.tableNode);\n\tif (lineWidth) {\n\t\tvar offset = lineWidth / 2;\n\t\tvar currentLine = null;\n\t\tvar body = this.tableNode.table.body;\n\n\t\tfor (var i = 0, l = this.rowSpanData.length; i < l; i++) {\n\t\t\tvar data = this.rowSpanData[i];\n\t\t\tvar shouldDrawLine = !data.rowSpan;\n\n\t\t\t// draw only if the current cell requires a top border or the cell in the\n\t\t\t// row above requires a bottom border\n\t\t\tif (shouldDrawLine && i < l - 1) {\n\t\t\t\tvar topBorder = false, bottomBorder = false;\n\n\t\t\t\t// the current cell\n\t\t\t\tif (lineIndex < body.length) {\n\t\t\t\t\tvar cell = body[lineIndex][i];\n\t\t\t\t\ttopBorder = cell.border ? cell.border[1] : this.layout.defaultBorder;\n\t\t\t\t}\n\n\t\t\t\t// the cell in the row above\n\t\t\t\tif (lineIndex > 0) {\n\t\t\t\t\tvar cellAbove = body[lineIndex - 1][i];\n\t\t\t\t\tbottomBorder = cellAbove.border ? cellAbove.border[3] : this.layout.defaultBorder;\n\t\t\t\t}\n\n\t\t\t\tshouldDrawLine = topBorder || bottomBorder;\n\t\t\t}\n\n\t\t\tif (!currentLine && shouldDrawLine) {\n\t\t\t\tcurrentLine = {left: data.left, width: 0};\n\t\t\t}\n\n\t\t\tif (shouldDrawLine) {\n\t\t\t\tcurrentLine.width += (data.width || 0);\n\t\t\t}\n\n\t\t\tvar y = (overrideY || 0) + offset;\n\n\t\t\tif (!shouldDrawLine || i === l - 1) {\n\t\t\t\tif (currentLine && currentLine.width) {\n\t\t\t\t\twriter.addVector({\n\t\t\t\t\t\ttype: 'line',\n\t\t\t\t\t\tx1: currentLine.left,\n\t\t\t\t\t\tx2: currentLine.left + currentLine.width,\n\t\t\t\t\t\ty1: y,\n\t\t\t\t\t\ty2: y,\n\t\t\t\t\t\tlineWidth: lineWidth,\n\t\t\t\t\t\tlineColor: isFunction(this.layout.hLineColor) ? this.layout.hLineColor(lineIndex, this.tableNode) : this.layout.hLineColor\n\t\t\t\t\t}, false, overrideY);\n\t\t\t\t\tcurrentLine = null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\twriter.context().moveDown(lineWidth);\n\t}\n};\n\nTableProcessor.prototype.drawVerticalLine = function (x, y0, y1, vLineIndex, writer) {\n\tvar width = this.layout.vLineWidth(vLineIndex, this.tableNode);\n\tif (width === 0) {\n\t\treturn;\n\t}\n\twriter.addVector({\n\t\ttype: 'line',\n\t\tx1: x + width / 2,\n\t\tx2: x + width / 2,\n\t\ty1: y0,\n\t\ty2: y1,\n\t\tlineWidth: width,\n\t\tlineColor: isFunction(this.layout.vLineColor) ? this.layout.vLineColor(vLineIndex, this.tableNode) : this.layout.vLineColor\n\t}, false, true);\n};\n\nTableProcessor.prototype.endTable = function (writer) {\n\tif (this.cleanUpRepeatables) {\n\t\twriter.popFromRepeatables();\n\t\tthis.headerRepeatableHeight = null;\n\t}\n};\n\nTableProcessor.prototype.endRow = function (rowIndex, writer, pageBreaks) {\n\tvar l, i;\n\tvar self = this;\n\twriter.tracker.stopTracking('pageChanged', this.rowCallback);\n\twriter.context().moveDown(this.layout.paddingBottom(rowIndex, this.tableNode));\n\twriter.context().availableHeight += this.reservedAtBottom;\n\n\tvar endingPage = writer.context().page;\n\tvar endingY = writer.context().y;\n\n\tvar xs = getLineXs();\n\n\tvar ys = [];\n\n\tvar hasBreaks = pageBreaks && pageBreaks.length > 0;\n\tvar body = this.tableNode.table.body;\n\n\tys.push({\n\t\ty0: this.rowTopY,\n\t\tpage: hasBreaks ? pageBreaks[0].prevPage : endingPage\n\t});\n\n\tif (hasBreaks) {\n\t\tfor (i = 0, l = pageBreaks.length; i < l; i++) {\n\t\t\tvar pageBreak = pageBreaks[i];\n\t\t\tys[ys.length - 1].y1 = pageBreak.prevY;\n\n\t\t\tys.push({y0: pageBreak.y, page: pageBreak.prevPage + 1});\n\n\t\t\tif (this.headerRepeatableHeight) {\n\t\t\t\tys[ys.length - 1].y0 += this.headerRepeatableHeight;\n\t\t\t}\n\t\t}\n\t}\n\n\tys[ys.length - 1].y1 = endingY;\n\n\tvar skipOrphanePadding = (ys[0].y1 - ys[0].y0 === this.rowPaddingTop);\n\tfor (var yi = (skipOrphanePadding ? 1 : 0), yl = ys.length; yi < yl; yi++) {\n\t\tvar willBreak = yi < ys.length - 1;\n\t\tvar rowBreakWithoutHeader = (yi > 0 && !this.headerRows);\n\t\tvar hzLineOffset = rowBreakWithoutHeader ? 0 : this.topLineWidth;\n\t\tvar y1 = ys[yi].y0;\n\t\tvar y2 = ys[yi].y1;\n\n\t\tif (willBreak) {\n\t\t\ty2 = y2 + this.rowPaddingBottom;\n\t\t}\n\n\t\tif (writer.context().page != ys[yi].page) {\n\t\t\twriter.context().page = ys[yi].page;\n\n\t\t\t//TODO: buggy, availableHeight should be updated on every pageChanged event\n\t\t\t// TableProcessor should be pageChanged listener, instead of processRow\n\t\t\tthis.reservedAtBottom = 0;\n\t\t}\n\n\t\tfor (i = 0, l = xs.length; i < l; i++) {\n\t\t\tvar leftBorder = false, rightBorder = false;\n\t\t\tvar colIndex = xs[i].index;\n\n\t\t\t// the current cell\n\t\t\tif (colIndex < body[rowIndex].length) {\n\t\t\t\tvar cell = body[rowIndex][colIndex];\n\t\t\t\tleftBorder = cell.border ? cell.border[0] : this.layout.defaultBorder;\n\t\t\t}\n\n\t\t\t// the cell from before column\n\t\t\tif (colIndex > 0) {\n\t\t\t\tvar cell = body[rowIndex][colIndex - 1];\n\t\t\t\trightBorder = cell.border ? cell.border[2] : this.layout.defaultBorder;\n\t\t\t}\n\n\t\t\tif (leftBorder || rightBorder) {\n\t\t\t\tthis.drawVerticalLine(xs[i].x, y1 - hzLineOffset, y2 + this.bottomLineWidth, xs[i].index, writer);\n\t\t\t}\n\n\t\t\tif (i < l - 1) {\n\t\t\t\tvar fillColor = body[rowIndex][colIndex].fillColor;\n\t\t\t\tif (!fillColor) {\n\t\t\t\t\tfillColor = isFunction(this.layout.fillColor) ? this.layout.fillColor(rowIndex, this.tableNode, colIndex) : this.layout.fillColor;\n\t\t\t\t}\n\t\t\t\tif (fillColor) {\n\t\t\t\t\tvar wBorder = (leftBorder || rightBorder) ? this.layout.vLineWidth(colIndex, this.tableNode) : 0;\n\t\t\t\t\tvar xf = xs[i].x + wBorder;\n\t\t\t\t\tvar yf = this.dontBreakRows ? y1 : y1 - hzLineOffset;\n\t\t\t\t\twriter.addVector({\n\t\t\t\t\t\ttype: 'rect',\n\t\t\t\t\t\tx: xf,\n\t\t\t\t\t\ty: yf,\n\t\t\t\t\t\tw: xs[i + 1].x - xf,\n\t\t\t\t\t\th: y2 + this.bottomLineWidth - yf,\n\t\t\t\t\t\tlineWidth: 0,\n\t\t\t\t\t\tcolor: fillColor\n\t\t\t\t\t}, false, true, writer.context().hasBackground ? 1 : 0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (willBreak && this.layout.hLineWhenBroken !== false) {\n\t\t\tthis.drawHorizontalLine(rowIndex + 1, writer, y2);\n\t\t}\n\t\tif (rowBreakWithoutHeader && this.layout.hLineWhenBroken !== false) {\n\t\t\tthis.drawHorizontalLine(rowIndex, writer, y1);\n\t\t}\n\t}\n\n\twriter.context().page = endingPage;\n\twriter.context().y = endingY;\n\n\tvar row = this.tableNode.table.body[rowIndex];\n\tfor (i = 0, l = row.length; i < l; i++) {\n\t\tif (row[i].rowSpan) {\n\t\t\tthis.rowSpanData[i].rowSpan = row[i].rowSpan;\n\n\t\t\t// fix colSpans\n\t\t\tif (row[i].colSpan && row[i].colSpan > 1) {\n\t\t\t\tfor (var j = 1; j < row[i].rowSpan; j++) {\n\t\t\t\t\tthis.tableNode.table.body[rowIndex + j][i]._colSpan = row[i].colSpan;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.rowSpanData[i].rowSpan > 0) {\n\t\t\tthis.rowSpanData[i].rowSpan--;\n\t\t}\n\t}\n\n\tthis.drawHorizontalLine(rowIndex + 1, writer);\n\n\tif (this.headerRows && rowIndex === this.headerRows - 1) {\n\t\tthis.headerRepeatable = writer.currentBlockToRepeatable();\n\t}\n\n\tif (this.dontBreakRows) {\n\t\twriter.tracker.auto('pageChanged',\n\t\t\tfunction () {\n\t\t\t\tif (!self.headerRows && self.layout.hLineWhenBroken !== false) {\n\t\t\t\t\tself.drawHorizontalLine(rowIndex, writer);\n\t\t\t\t}\n\t\t\t},\n\t\t\tfunction () {\n\t\t\t\twriter.commitUnbreakableBlock();\n\t\t\t}\n\t\t);\n\t}\n\n\tif (this.headerRepeatable && (rowIndex === (this.rowsWithoutPageBreak - 1) || rowIndex === this.tableNode.table.body.length - 1)) {\n\t\tthis.headerRepeatableHeight = this.headerRepeatable.height;\n\t\twriter.commitUnbreakableBlock();\n\t\twriter.pushToRepeatables(this.headerRepeatable);\n\t\tthis.cleanUpRepeatables = true;\n\t\tthis.headerRepeatable = null;\n\t}\n\n\tfunction getLineXs() {\n\t\tvar result = [];\n\t\tvar cols = 0;\n\n\t\tfor (var i = 0, l = self.tableNode.table.body[rowIndex].length; i < l; i++) {\n\t\t\tif (!cols) {\n\t\t\t\tresult.push({x: self.rowSpanData[i].left, index: i});\n\n\t\t\t\tvar item = self.tableNode.table.body[rowIndex][i];\n\t\t\t\tcols = (item._colSpan || item.colSpan || 0);\n\t\t\t}\n\t\t\tif (cols > 0) {\n\t\t\t\tcols--;\n\t\t\t}\n\t\t}\n\n\t\tresult.push({x: self.rowSpanData[self.rowSpanData.length - 1].left, index: self.rowSpanData.length - 1});\n\n\t\treturn result;\n\t}\n};\n\nmodule.exports = TableProcessor;\n\n\n/***/ }),\n/* 138 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6\n\n/*\nPDFDocument - represents an entire PDF document\nBy Devon Govett\n */\n\n(function() {\n  var PDFDocument, PDFObject, PDFPage, PDFReference, fs, stream,\n    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n    hasProp = {}.hasOwnProperty;\n\n  stream = __webpack_require__(15);\n\n  fs = __webpack_require__(8);\n\n  PDFObject = __webpack_require__(26);\n\n  PDFReference = __webpack_require__(87);\n\n  PDFPage = __webpack_require__(161);\n\n  PDFDocument = (function(superClass) {\n    var mixin;\n\n    extend(PDFDocument, superClass);\n\n    function PDFDocument(options1) {\n      var key, ref1, ref2, val;\n      this.options = options1 != null ? options1 : {};\n      PDFDocument.__super__.constructor.apply(this, arguments);\n      this.version = 1.3;\n      this.compress = (ref1 = this.options.compress) != null ? ref1 : true;\n      this._pageBuffer = [];\n      this._pageBufferStart = 0;\n      this._offsets = [];\n      this._waiting = 0;\n      this._ended = false;\n      this._offset = 0;\n      this._root = this.ref({\n        Type: 'Catalog',\n        Pages: this.ref({\n          Type: 'Pages',\n          Count: 0,\n          Kids: []\n        })\n      });\n      this.page = null;\n      this.initColor();\n      this.initVector();\n      this.initFonts();\n      this.initText();\n      this.initImages();\n      this.info = {\n        Producer: 'PDFKit',\n        Creator: 'PDFKit',\n        CreationDate: new Date()\n      };\n      if (this.options.info) {\n        ref2 = this.options.info;\n        for (key in ref2) {\n          val = ref2[key];\n          this.info[key] = val;\n        }\n      }\n      this._write(\"%PDF-\" + this.version);\n      this._write(\"%\\xFF\\xFF\\xFF\\xFF\");\n      if (this.options.autoFirstPage !== false) {\n        this.addPage();\n      }\n    }\n\n    mixin = function(methods) {\n      var method, name, results;\n      results = [];\n      for (name in methods) {\n        method = methods[name];\n        results.push(PDFDocument.prototype[name] = method);\n      }\n      return results;\n    };\n\n    mixin(__webpack_require__(162));\n\n    mixin(__webpack_require__(164));\n\n    mixin(__webpack_require__(166));\n\n    mixin(__webpack_require__(295));\n\n    mixin(__webpack_require__(297));\n\n    mixin(__webpack_require__(302));\n\n    PDFDocument.prototype.addPage = function(options) {\n      var pages;\n      if (options == null) {\n        options = this.options;\n      }\n      if (!this.options.bufferPages) {\n        this.flushPages();\n      }\n      this.page = new PDFPage(this, options);\n      this._pageBuffer.push(this.page);\n      pages = this._root.data.Pages.data;\n      pages.Kids.push(this.page.dictionary);\n      pages.Count++;\n      this.x = this.page.margins.left;\n      this.y = this.page.margins.top;\n      this._ctm = [1, 0, 0, 1, 0, 0];\n      this.transform(1, 0, 0, -1, 0, this.page.height);\n      this.emit('pageAdded');\n      return this;\n    };\n\n    PDFDocument.prototype.bufferedPageRange = function() {\n      return {\n        start: this._pageBufferStart,\n        count: this._pageBuffer.length\n      };\n    };\n\n    PDFDocument.prototype.switchToPage = function(n) {\n      var page;\n      if (!(page = this._pageBuffer[n - this._pageBufferStart])) {\n        throw new Error(\"switchToPage(\" + n + \") out of bounds, current buffer covers pages \" + this._pageBufferStart + \" to \" + (this._pageBufferStart + this._pageBuffer.length - 1));\n      }\n      return this.page = page;\n    };\n\n    PDFDocument.prototype.flushPages = function() {\n      var i, len, page, pages;\n      pages = this._pageBuffer;\n      this._pageBuffer = [];\n      this._pageBufferStart += pages.length;\n      for (i = 0, len = pages.length; i < len; i++) {\n        page = pages[i];\n        page.end();\n      }\n    };\n\n    PDFDocument.prototype.ref = function(data) {\n      var ref;\n      ref = new PDFReference(this, this._offsets.length + 1, data);\n      this._offsets.push(null);\n      this._waiting++;\n      return ref;\n    };\n\n    PDFDocument.prototype._read = function() {};\n\n    PDFDocument.prototype._write = function(data) {\n      if (!Buffer.isBuffer(data)) {\n        data = new Buffer(data + '\\n', 'binary');\n      }\n      this.push(data);\n      return this._offset += data.length;\n    };\n\n    PDFDocument.prototype.addContent = function(data) {\n      this.page.write(data);\n      return this;\n    };\n\n    PDFDocument.prototype._refEnd = function(ref) {\n      this._offsets[ref.id - 1] = ref.offset;\n      if (--this._waiting === 0 && this._ended) {\n        this._finalize();\n        return this._ended = false;\n      }\n    };\n\n    PDFDocument.prototype.write = function(filename, fn) {\n      var err;\n      err = new Error('PDFDocument#write is deprecated, and will be removed in a future version of PDFKit. Please pipe the document into a Node stream.');\n      console.warn(err.stack);\n      this.pipe(fs.createWriteStream(filename));\n      this.end();\n      return this.once('end', fn);\n    };\n\n    PDFDocument.prototype.output = function(fn) {\n      throw new Error('PDFDocument#output is deprecated, and has been removed from PDFKit. Please pipe the document into a Node stream.');\n    };\n\n    PDFDocument.prototype.end = function() {\n      var font, key, name, ref1, ref2, val;\n      this.flushPages();\n      this._info = this.ref();\n      ref1 = this.info;\n      for (key in ref1) {\n        val = ref1[key];\n        if (typeof val === 'string') {\n          val = new String(val);\n        }\n        this._info.data[key] = val;\n      }\n      this._info.end();\n      ref2 = this._fontFamilies;\n      for (name in ref2) {\n        font = ref2[name];\n        font.finalize();\n      }\n      this._root.end();\n      this._root.data.Pages.end();\n      if (this._waiting === 0) {\n        return this._finalize();\n      } else {\n        return this._ended = true;\n      }\n    };\n\n    PDFDocument.prototype._finalize = function(fn) {\n      var i, len, offset, ref1, xRefOffset;\n      xRefOffset = this._offset;\n      this._write(\"xref\");\n      this._write(\"0 \" + (this._offsets.length + 1));\n      this._write(\"0000000000 65535 f \");\n      ref1 = this._offsets;\n      for (i = 0, len = ref1.length; i < len; i++) {\n        offset = ref1[i];\n        offset = ('0000000000' + offset).slice(-10);\n        this._write(offset + ' 00000 n ');\n      }\n      this._write('trailer');\n      this._write(PDFObject.convert({\n        Size: this._offsets.length + 1,\n        Root: this._root,\n        Info: this._info\n      }));\n      this._write('startxref');\n      this._write(\"\" + xRefOffset);\n      this._write('%%EOF');\n      return this.push(null);\n    };\n\n    PDFDocument.prototype.toString = function() {\n      return \"[object PDFDocument]\";\n    };\n\n    return PDFDocument;\n\n  })(stream.Readable);\n\n  module.exports = PDFDocument;\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 139 */\n/***/ (function(module, exports) {\n\n/* (ignored) */\n\n/***/ }),\n/* 140 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar Buffer = __webpack_require__(33).Buffer;\nvar util = __webpack_require__(141);\n\nfunction copyBuffer(src, target, offset) {\n  src.copy(target, offset);\n}\n\nmodule.exports = function () {\n  function BufferList() {\n    _classCallCheck(this, BufferList);\n\n    this.head = null;\n    this.tail = null;\n    this.length = 0;\n  }\n\n  BufferList.prototype.push = function push(v) {\n    var entry = { data: v, next: null };\n    if (this.length > 0) this.tail.next = entry;else this.head = entry;\n    this.tail = entry;\n    ++this.length;\n  };\n\n  BufferList.prototype.unshift = function unshift(v) {\n    var entry = { data: v, next: this.head };\n    if (this.length === 0) this.tail = entry;\n    this.head = entry;\n    ++this.length;\n  };\n\n  BufferList.prototype.shift = function shift() {\n    if (this.length === 0) return;\n    var ret = this.head.data;\n    if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next;\n    --this.length;\n    return ret;\n  };\n\n  BufferList.prototype.clear = function clear() {\n    this.head = this.tail = null;\n    this.length = 0;\n  };\n\n  BufferList.prototype.join = function join(s) {\n    if (this.length === 0) return '';\n    var p = this.head;\n    var ret = '' + p.data;\n    while (p = p.next) {\n      ret += s + p.data;\n    }return ret;\n  };\n\n  BufferList.prototype.concat = function concat(n) {\n    if (this.length === 0) return Buffer.alloc(0);\n    if (this.length === 1) return this.head.data;\n    var ret = Buffer.allocUnsafe(n >>> 0);\n    var p = this.head;\n    var i = 0;\n    while (p) {\n      copyBuffer(p.data, ret, i);\n      i += p.data.length;\n      p = p.next;\n    }\n    return ret;\n  };\n\n  return BufferList;\n}();\n\nif (util && util.inspect && util.inspect.custom) {\n  module.exports.prototype[util.inspect.custom] = function () {\n    var obj = util.inspect({ length: this.length });\n    return this.constructor.name + ' ' + obj;\n  };\n}\n\n/***/ }),\n/* 141 */\n/***/ (function(module, exports) {\n\n/* (ignored) */\n\n/***/ }),\n/* 142 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(global) {var apply = Function.prototype.apply;\n\n// DOM APIs, for completeness\n\nexports.setTimeout = function() {\n  return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout);\n};\nexports.setInterval = function() {\n  return new Timeout(apply.call(setInterval, window, arguments), clearInterval);\n};\nexports.clearTimeout =\nexports.clearInterval = function(timeout) {\n  if (timeout) {\n    timeout.close();\n  }\n};\n\nfunction Timeout(id, clearFn) {\n  this._id = id;\n  this._clearFn = clearFn;\n}\nTimeout.prototype.unref = Timeout.prototype.ref = function() {};\nTimeout.prototype.close = function() {\n  this._clearFn.call(window, this._id);\n};\n\n// Does not start the time, just sets up the members needed.\nexports.enroll = function(item, msecs) {\n  clearTimeout(item._idleTimeoutId);\n  item._idleTimeout = msecs;\n};\n\nexports.unenroll = function(item) {\n  clearTimeout(item._idleTimeoutId);\n  item._idleTimeout = -1;\n};\n\nexports._unrefActive = exports.active = function(item) {\n  clearTimeout(item._idleTimeoutId);\n\n  var msecs = item._idleTimeout;\n  if (msecs >= 0) {\n    item._idleTimeoutId = setTimeout(function onTimeout() {\n      if (item._onTimeout)\n        item._onTimeout();\n    }, msecs);\n  }\n};\n\n// setimmediate attaches itself to the global object\n__webpack_require__(143);\n// On some exotic environments, it's not clear which object `setimmeidate` was\n// able to install onto.  Search each possibility in the same order as the\n// `setimmediate` library.\nexports.setImmediate = (typeof self !== \"undefined\" && self.setImmediate) ||\n                       (typeof global !== \"undefined\" && global.setImmediate) ||\n                       (this && this.setImmediate);\nexports.clearImmediate = (typeof self !== \"undefined\" && self.clearImmediate) ||\n                         (typeof global !== \"undefined\" && global.clearImmediate) ||\n                         (this && this.clearImmediate);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))\n\n/***/ }),\n/* 143 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(global, process) {(function (global, undefined) {\n    \"use strict\";\n\n    if (global.setImmediate) {\n        return;\n    }\n\n    var nextHandle = 1; // Spec says greater than zero\n    var tasksByHandle = {};\n    var currentlyRunningATask = false;\n    var doc = global.document;\n    var registerImmediate;\n\n    function setImmediate(callback) {\n      // Callback can either be a function or a string\n      if (typeof callback !== \"function\") {\n        callback = new Function(\"\" + callback);\n      }\n      // Copy function arguments\n      var args = new Array(arguments.length - 1);\n      for (var i = 0; i < args.length; i++) {\n          args[i] = arguments[i + 1];\n      }\n      // Store and register the task\n      var task = { callback: callback, args: args };\n      tasksByHandle[nextHandle] = task;\n      registerImmediate(nextHandle);\n      return nextHandle++;\n    }\n\n    function clearImmediate(handle) {\n        delete tasksByHandle[handle];\n    }\n\n    function run(task) {\n        var callback = task.callback;\n        var args = task.args;\n        switch (args.length) {\n        case 0:\n            callback();\n            break;\n        case 1:\n            callback(args[0]);\n            break;\n        case 2:\n            callback(args[0], args[1]);\n            break;\n        case 3:\n            callback(args[0], args[1], args[2]);\n            break;\n        default:\n            callback.apply(undefined, args);\n            break;\n        }\n    }\n\n    function runIfPresent(handle) {\n        // From the spec: \"Wait until any invocations of this algorithm started before this one have completed.\"\n        // So if we're currently running a task, we'll need to delay this invocation.\n        if (currentlyRunningATask) {\n            // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a\n            // \"too much recursion\" error.\n            setTimeout(runIfPresent, 0, handle);\n        } else {\n            var task = tasksByHandle[handle];\n            if (task) {\n                currentlyRunningATask = true;\n                try {\n                    run(task);\n                } finally {\n                    clearImmediate(handle);\n                    currentlyRunningATask = false;\n                }\n            }\n        }\n    }\n\n    function installNextTickImplementation() {\n        registerImmediate = function(handle) {\n            process.nextTick(function () { runIfPresent(handle); });\n        };\n    }\n\n    function canUsePostMessage() {\n        // The test against `importScripts` prevents this implementation from being installed inside a web worker,\n        // where `global.postMessage` means something completely different and can't be used for this purpose.\n        if (global.postMessage && !global.importScripts) {\n            var postMessageIsAsynchronous = true;\n            var oldOnMessage = global.onmessage;\n            global.onmessage = function() {\n                postMessageIsAsynchronous = false;\n            };\n            global.postMessage(\"\", \"*\");\n            global.onmessage = oldOnMessage;\n            return postMessageIsAsynchronous;\n        }\n    }\n\n    function installPostMessageImplementation() {\n        // Installs an event handler on `global` for the `message` event: see\n        // * https://developer.mozilla.org/en/DOM/window.postMessage\n        // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages\n\n        var messagePrefix = \"setImmediate$\" + Math.random() + \"$\";\n        var onGlobalMessage = function(event) {\n            if (event.source === global &&\n                typeof event.data === \"string\" &&\n                event.data.indexOf(messagePrefix) === 0) {\n                runIfPresent(+event.data.slice(messagePrefix.length));\n            }\n        };\n\n        if (global.addEventListener) {\n            global.addEventListener(\"message\", onGlobalMessage, false);\n        } else {\n            global.attachEvent(\"onmessage\", onGlobalMessage);\n        }\n\n        registerImmediate = function(handle) {\n            global.postMessage(messagePrefix + handle, \"*\");\n        };\n    }\n\n    function installMessageChannelImplementation() {\n        var channel = new MessageChannel();\n        channel.port1.onmessage = function(event) {\n            var handle = event.data;\n            runIfPresent(handle);\n        };\n\n        registerImmediate = function(handle) {\n            channel.port2.postMessage(handle);\n        };\n    }\n\n    function installReadyStateChangeImplementation() {\n        var html = doc.documentElement;\n        registerImmediate = function(handle) {\n            // Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted\n            // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.\n            var script = doc.createElement(\"script\");\n            script.onreadystatechange = function () {\n                runIfPresent(handle);\n                script.onreadystatechange = null;\n                html.removeChild(script);\n                script = null;\n            };\n            html.appendChild(script);\n        };\n    }\n\n    function installSetTimeoutImplementation() {\n        registerImmediate = function(handle) {\n            setTimeout(runIfPresent, 0, handle);\n        };\n    }\n\n    // If supported, we should attach to the prototype of global, since that is where setTimeout et al. live.\n    var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global);\n    attachTo = attachTo && attachTo.setTimeout ? attachTo : global;\n\n    // Don't get fooled by e.g. browserify environments.\n    if ({}.toString.call(global.process) === \"[object process]\") {\n        // For Node.js before 0.9\n        installNextTickImplementation();\n\n    } else if (canUsePostMessage()) {\n        // For non-IE10 modern browsers\n        installPostMessageImplementation();\n\n    } else if (global.MessageChannel) {\n        // For web workers, where supported\n        installMessageChannelImplementation();\n\n    } else if (doc && \"onreadystatechange\" in doc.createElement(\"script\")) {\n        // For IE 6–8\n        installReadyStateChangeImplementation();\n\n    } else {\n        // For older browsers\n        installSetTimeoutImplementation();\n    }\n\n    attachTo.setImmediate = setImmediate;\n    attachTo.clearImmediate = clearImmediate;\n}(typeof self === \"undefined\" ? typeof global === \"undefined\" ? this : global : self));\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7), __webpack_require__(11)))\n\n/***/ }),\n/* 144 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(global) {\n/**\n * Module exports.\n */\n\nmodule.exports = deprecate;\n\n/**\n * Mark that a method should not be used.\n * Returns a modified function which warns once by default.\n *\n * If `localStorage.noDeprecation = true` is set, then it is a no-op.\n *\n * If `localStorage.throwDeprecation = true` is set, then deprecated functions\n * will throw an Error when invoked.\n *\n * If `localStorage.traceDeprecation = true` is set, then deprecated functions\n * will invoke `console.trace()` instead of `console.error()`.\n *\n * @param {Function} fn - the function to deprecate\n * @param {String} msg - the string to print to the console when `fn` is invoked\n * @returns {Function} a new \"deprecated\" version of `fn`\n * @api public\n */\n\nfunction deprecate (fn, msg) {\n  if (config('noDeprecation')) {\n    return fn;\n  }\n\n  var warned = false;\n  function deprecated() {\n    if (!warned) {\n      if (config('throwDeprecation')) {\n        throw new Error(msg);\n      } else if (config('traceDeprecation')) {\n        console.trace(msg);\n      } else {\n        console.warn(msg);\n      }\n      warned = true;\n    }\n    return fn.apply(this, arguments);\n  }\n\n  return deprecated;\n}\n\n/**\n * Checks `localStorage` for boolean values for the given `name`.\n *\n * @param {String} name\n * @returns {Boolean}\n * @api private\n */\n\nfunction config (name) {\n  // accessing global.localStorage can trigger a DOMException in sandboxed iframes\n  try {\n    if (!global.localStorage) return false;\n  } catch (_) {\n    return false;\n  }\n  var val = global.localStorage[name];\n  if (null == val) return false;\n  return String(val).toLowerCase() === 'true';\n}\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))\n\n/***/ }),\n/* 145 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// a passthrough stream.\n// basically just the most minimal sort of Transform stream.\n// Every written chunk gets output as-is.\n\n\n\nmodule.exports = PassThrough;\n\nvar Transform = __webpack_require__(86);\n\n/*<replacement>*/\nvar util = __webpack_require__(25);\nutil.inherits = __webpack_require__(21);\n/*</replacement>*/\n\nutil.inherits(PassThrough, Transform);\n\nfunction PassThrough(options) {\n  if (!(this instanceof PassThrough)) return new PassThrough(options);\n\n  Transform.call(this, options);\n}\n\nPassThrough.prototype._transform = function (chunk, encoding, cb) {\n  cb(null, chunk);\n};\n\n/***/ }),\n/* 146 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(46);\n\n\n/***/ }),\n/* 147 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(16);\n\n\n/***/ }),\n/* 148 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(45).Transform\n\n\n/***/ }),\n/* 149 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(45).PassThrough\n\n\n/***/ }),\n/* 150 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(Buffer, process) {\n/* eslint camelcase: \"off\" */\n\nvar assert = __webpack_require__(88);\n\nvar Zstream = __webpack_require__(153);\nvar zlib_deflate = __webpack_require__(154);\nvar zlib_inflate = __webpack_require__(157);\nvar constants = __webpack_require__(160);\n\nfor (var key in constants) {\n  exports[key] = constants[key];\n}\n\n// zlib modes\nexports.NONE = 0;\nexports.DEFLATE = 1;\nexports.INFLATE = 2;\nexports.GZIP = 3;\nexports.GUNZIP = 4;\nexports.DEFLATERAW = 5;\nexports.INFLATERAW = 6;\nexports.UNZIP = 7;\n\nvar GZIP_HEADER_ID1 = 0x1f;\nvar GZIP_HEADER_ID2 = 0x8b;\n\n/**\n * Emulate Node's zlib C++ layer for use by the JS layer in index.js\n */\nfunction Zlib(mode) {\n  if (typeof mode !== 'number' || mode < exports.DEFLATE || mode > exports.UNZIP) {\n    throw new TypeError('Bad argument');\n  }\n\n  this.dictionary = null;\n  this.err = 0;\n  this.flush = 0;\n  this.init_done = false;\n  this.level = 0;\n  this.memLevel = 0;\n  this.mode = mode;\n  this.strategy = 0;\n  this.windowBits = 0;\n  this.write_in_progress = false;\n  this.pending_close = false;\n  this.gzip_id_bytes_read = 0;\n}\n\nZlib.prototype.close = function () {\n  if (this.write_in_progress) {\n    this.pending_close = true;\n    return;\n  }\n\n  this.pending_close = false;\n\n  assert(this.init_done, 'close before init');\n  assert(this.mode <= exports.UNZIP);\n\n  if (this.mode === exports.DEFLATE || this.mode === exports.GZIP || this.mode === exports.DEFLATERAW) {\n    zlib_deflate.deflateEnd(this.strm);\n  } else if (this.mode === exports.INFLATE || this.mode === exports.GUNZIP || this.mode === exports.INFLATERAW || this.mode === exports.UNZIP) {\n    zlib_inflate.inflateEnd(this.strm);\n  }\n\n  this.mode = exports.NONE;\n\n  this.dictionary = null;\n};\n\nZlib.prototype.write = function (flush, input, in_off, in_len, out, out_off, out_len) {\n  return this._write(true, flush, input, in_off, in_len, out, out_off, out_len);\n};\n\nZlib.prototype.writeSync = function (flush, input, in_off, in_len, out, out_off, out_len) {\n  return this._write(false, flush, input, in_off, in_len, out, out_off, out_len);\n};\n\nZlib.prototype._write = function (async, flush, input, in_off, in_len, out, out_off, out_len) {\n  assert.equal(arguments.length, 8);\n\n  assert(this.init_done, 'write before init');\n  assert(this.mode !== exports.NONE, 'already finalized');\n  assert.equal(false, this.write_in_progress, 'write already in progress');\n  assert.equal(false, this.pending_close, 'close is pending');\n\n  this.write_in_progress = true;\n\n  assert.equal(false, flush === undefined, 'must provide flush value');\n\n  this.write_in_progress = true;\n\n  if (flush !== exports.Z_NO_FLUSH && flush !== exports.Z_PARTIAL_FLUSH && flush !== exports.Z_SYNC_FLUSH && flush !== exports.Z_FULL_FLUSH && flush !== exports.Z_FINISH && flush !== exports.Z_BLOCK) {\n    throw new Error('Invalid flush value');\n  }\n\n  if (input == null) {\n    input = Buffer.alloc(0);\n    in_len = 0;\n    in_off = 0;\n  }\n\n  this.strm.avail_in = in_len;\n  this.strm.input = input;\n  this.strm.next_in = in_off;\n  this.strm.avail_out = out_len;\n  this.strm.output = out;\n  this.strm.next_out = out_off;\n  this.flush = flush;\n\n  if (!async) {\n    // sync version\n    this._process();\n\n    if (this._checkError()) {\n      return this._afterSync();\n    }\n    return;\n  }\n\n  // async version\n  var self = this;\n  process.nextTick(function () {\n    self._process();\n    self._after();\n  });\n\n  return this;\n};\n\nZlib.prototype._afterSync = function () {\n  var avail_out = this.strm.avail_out;\n  var avail_in = this.strm.avail_in;\n\n  this.write_in_progress = false;\n\n  return [avail_in, avail_out];\n};\n\nZlib.prototype._process = function () {\n  var next_expected_header_byte = null;\n\n  // If the avail_out is left at 0, then it means that it ran out\n  // of room.  If there was avail_out left over, then it means\n  // that all of the input was consumed.\n  switch (this.mode) {\n    case exports.DEFLATE:\n    case exports.GZIP:\n    case exports.DEFLATERAW:\n      this.err = zlib_deflate.deflate(this.strm, this.flush);\n      break;\n    case exports.UNZIP:\n      if (this.strm.avail_in > 0) {\n        next_expected_header_byte = this.strm.next_in;\n      }\n\n      switch (this.gzip_id_bytes_read) {\n        case 0:\n          if (next_expected_header_byte === null) {\n            break;\n          }\n\n          if (this.strm.input[next_expected_header_byte] === GZIP_HEADER_ID1) {\n            this.gzip_id_bytes_read = 1;\n            next_expected_header_byte++;\n\n            if (this.strm.avail_in === 1) {\n              // The only available byte was already read.\n              break;\n            }\n          } else {\n            this.mode = exports.INFLATE;\n            break;\n          }\n\n        // fallthrough\n        case 1:\n          if (next_expected_header_byte === null) {\n            break;\n          }\n\n          if (this.strm.input[next_expected_header_byte] === GZIP_HEADER_ID2) {\n            this.gzip_id_bytes_read = 2;\n            this.mode = exports.GUNZIP;\n          } else {\n            // There is no actual difference between INFLATE and INFLATERAW\n            // (after initialization).\n            this.mode = exports.INFLATE;\n          }\n\n          break;\n        default:\n          throw new Error('invalid number of gzip magic number bytes read');\n      }\n\n    // fallthrough\n    case exports.INFLATE:\n    case exports.GUNZIP:\n    case exports.INFLATERAW:\n      this.err = zlib_inflate.inflate(this.strm, this.flush\n\n      // If data was encoded with dictionary\n      );if (this.err === exports.Z_NEED_DICT && this.dictionary) {\n        // Load it\n        this.err = zlib_inflate.inflateSetDictionary(this.strm, this.dictionary);\n        if (this.err === exports.Z_OK) {\n          // And try to decode again\n          this.err = zlib_inflate.inflate(this.strm, this.flush);\n        } else if (this.err === exports.Z_DATA_ERROR) {\n          // Both inflateSetDictionary() and inflate() return Z_DATA_ERROR.\n          // Make it possible for After() to tell a bad dictionary from bad\n          // input.\n          this.err = exports.Z_NEED_DICT;\n        }\n      }\n      while (this.strm.avail_in > 0 && this.mode === exports.GUNZIP && this.err === exports.Z_STREAM_END && this.strm.next_in[0] !== 0x00) {\n        // Bytes remain in input buffer. Perhaps this is another compressed\n        // member in the same archive, or just trailing garbage.\n        // Trailing zero bytes are okay, though, since they are frequently\n        // used for padding.\n\n        this.reset();\n        this.err = zlib_inflate.inflate(this.strm, this.flush);\n      }\n      break;\n    default:\n      throw new Error('Unknown mode ' + this.mode);\n  }\n};\n\nZlib.prototype._checkError = function () {\n  // Acceptable error states depend on the type of zlib stream.\n  switch (this.err) {\n    case exports.Z_OK:\n    case exports.Z_BUF_ERROR:\n      if (this.strm.avail_out !== 0 && this.flush === exports.Z_FINISH) {\n        this._error('unexpected end of file');\n        return false;\n      }\n      break;\n    case exports.Z_STREAM_END:\n      // normal statuses, not fatal\n      break;\n    case exports.Z_NEED_DICT:\n      if (this.dictionary == null) {\n        this._error('Missing dictionary');\n      } else {\n        this._error('Bad dictionary');\n      }\n      return false;\n    default:\n      // something else.\n      this._error('Zlib error');\n      return false;\n  }\n\n  return true;\n};\n\nZlib.prototype._after = function () {\n  if (!this._checkError()) {\n    return;\n  }\n\n  var avail_out = this.strm.avail_out;\n  var avail_in = this.strm.avail_in;\n\n  this.write_in_progress = false;\n\n  // call the write() cb\n  this.callback(avail_in, avail_out);\n\n  if (this.pending_close) {\n    this.close();\n  }\n};\n\nZlib.prototype._error = function (message) {\n  if (this.strm.msg) {\n    message = this.strm.msg;\n  }\n  this.onerror(message, this.err\n\n  // no hope of rescue.\n  );this.write_in_progress = false;\n  if (this.pending_close) {\n    this.close();\n  }\n};\n\nZlib.prototype.init = function (windowBits, level, memLevel, strategy, dictionary) {\n  assert(arguments.length === 4 || arguments.length === 5, 'init(windowBits, level, memLevel, strategy, [dictionary])');\n\n  assert(windowBits >= 8 && windowBits <= 15, 'invalid windowBits');\n  assert(level >= -1 && level <= 9, 'invalid compression level');\n\n  assert(memLevel >= 1 && memLevel <= 9, 'invalid memlevel');\n\n  assert(strategy === exports.Z_FILTERED || strategy === exports.Z_HUFFMAN_ONLY || strategy === exports.Z_RLE || strategy === exports.Z_FIXED || strategy === exports.Z_DEFAULT_STRATEGY, 'invalid strategy');\n\n  this._init(level, windowBits, memLevel, strategy, dictionary);\n  this._setDictionary();\n};\n\nZlib.prototype.params = function () {\n  throw new Error('deflateParams Not supported');\n};\n\nZlib.prototype.reset = function () {\n  this._reset();\n  this._setDictionary();\n};\n\nZlib.prototype._init = function (level, windowBits, memLevel, strategy, dictionary) {\n  this.level = level;\n  this.windowBits = windowBits;\n  this.memLevel = memLevel;\n  this.strategy = strategy;\n\n  this.flush = exports.Z_NO_FLUSH;\n\n  this.err = exports.Z_OK;\n\n  if (this.mode === exports.GZIP || this.mode === exports.GUNZIP) {\n    this.windowBits += 16;\n  }\n\n  if (this.mode === exports.UNZIP) {\n    this.windowBits += 32;\n  }\n\n  if (this.mode === exports.DEFLATERAW || this.mode === exports.INFLATERAW) {\n    this.windowBits = -1 * this.windowBits;\n  }\n\n  this.strm = new Zstream();\n\n  switch (this.mode) {\n    case exports.DEFLATE:\n    case exports.GZIP:\n    case exports.DEFLATERAW:\n      this.err = zlib_deflate.deflateInit2(this.strm, this.level, exports.Z_DEFLATED, this.windowBits, this.memLevel, this.strategy);\n      break;\n    case exports.INFLATE:\n    case exports.GUNZIP:\n    case exports.INFLATERAW:\n    case exports.UNZIP:\n      this.err = zlib_inflate.inflateInit2(this.strm, this.windowBits);\n      break;\n    default:\n      throw new Error('Unknown mode ' + this.mode);\n  }\n\n  if (this.err !== exports.Z_OK) {\n    this._error('Init error');\n  }\n\n  this.dictionary = dictionary;\n\n  this.write_in_progress = false;\n  this.init_done = true;\n};\n\nZlib.prototype._setDictionary = function () {\n  if (this.dictionary == null) {\n    return;\n  }\n\n  this.err = exports.Z_OK;\n\n  switch (this.mode) {\n    case exports.DEFLATE:\n    case exports.DEFLATERAW:\n      this.err = zlib_deflate.deflateSetDictionary(this.strm, this.dictionary);\n      break;\n    default:\n      break;\n  }\n\n  if (this.err !== exports.Z_OK) {\n    this._error('Failed to set dictionary');\n  }\n};\n\nZlib.prototype._reset = function () {\n  this.err = exports.Z_OK;\n\n  switch (this.mode) {\n    case exports.DEFLATE:\n    case exports.DEFLATERAW:\n    case exports.GZIP:\n      this.err = zlib_deflate.deflateReset(this.strm);\n      break;\n    case exports.INFLATE:\n    case exports.INFLATERAW:\n    case exports.GUNZIP:\n      this.err = zlib_inflate.inflateReset(this.strm);\n      break;\n    default:\n      break;\n  }\n\n  if (this.err !== exports.Z_OK) {\n    this._error('Failed to reset stream');\n  }\n};\n\nexports.Zlib = Zlib;\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer, __webpack_require__(11)))\n\n/***/ }),\n/* 151 */\n/***/ (function(module, exports) {\n\nmodule.exports = function isBuffer(arg) {\n  return arg && typeof arg === 'object'\n    && typeof arg.copy === 'function'\n    && typeof arg.fill === 'function'\n    && typeof arg.readUInt8 === 'function';\n}\n\n/***/ }),\n/* 152 */\n/***/ (function(module, exports) {\n\nif (typeof Object.create === 'function') {\n  // implementation from standard node.js 'util' module\n  module.exports = function inherits(ctor, superCtor) {\n    ctor.super_ = superCtor\n    ctor.prototype = Object.create(superCtor.prototype, {\n      constructor: {\n        value: ctor,\n        enumerable: false,\n        writable: true,\n        configurable: true\n      }\n    });\n  };\n} else {\n  // old school shim for old browsers\n  module.exports = function inherits(ctor, superCtor) {\n    ctor.super_ = superCtor\n    var TempCtor = function () {}\n    TempCtor.prototype = superCtor.prototype\n    ctor.prototype = new TempCtor()\n    ctor.prototype.constructor = ctor\n  }\n}\n\n\n/***/ }),\n/* 153 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nfunction ZStream() {\n  /* next input byte */\n  this.input = null; // JS specific, because we have no pointers\n  this.next_in = 0;\n  /* number of bytes available at input */\n  this.avail_in = 0;\n  /* total number of input bytes read so far */\n  this.total_in = 0;\n  /* next output byte should be put there */\n  this.output = null; // JS specific, because we have no pointers\n  this.next_out = 0;\n  /* remaining free space at output */\n  this.avail_out = 0;\n  /* total number of bytes output so far */\n  this.total_out = 0;\n  /* last error message, NULL if no error */\n  this.msg = ''/*Z_NULL*/;\n  /* not visible by applications */\n  this.state = null;\n  /* best guess about the data type: binary or text */\n  this.data_type = 2/*Z_UNKNOWN*/;\n  /* adler32 value of the uncompressed data */\n  this.adler = 0;\n}\n\nmodule.exports = ZStream;\n\n\n/***/ }),\n/* 154 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nvar utils   = __webpack_require__(34);\nvar trees   = __webpack_require__(155);\nvar adler32 = __webpack_require__(89);\nvar crc32   = __webpack_require__(90);\nvar msg     = __webpack_require__(156);\n\n/* Public constants ==========================================================*/\n/* ===========================================================================*/\n\n\n/* Allowed flush values; see deflate() and inflate() below for details */\nvar Z_NO_FLUSH      = 0;\nvar Z_PARTIAL_FLUSH = 1;\n//var Z_SYNC_FLUSH    = 2;\nvar Z_FULL_FLUSH    = 3;\nvar Z_FINISH        = 4;\nvar Z_BLOCK         = 5;\n//var Z_TREES         = 6;\n\n\n/* Return codes for the compression/decompression functions. Negative values\n * are errors, positive values are used for special but normal events.\n */\nvar Z_OK            = 0;\nvar Z_STREAM_END    = 1;\n//var Z_NEED_DICT     = 2;\n//var Z_ERRNO         = -1;\nvar Z_STREAM_ERROR  = -2;\nvar Z_DATA_ERROR    = -3;\n//var Z_MEM_ERROR     = -4;\nvar Z_BUF_ERROR     = -5;\n//var Z_VERSION_ERROR = -6;\n\n\n/* compression levels */\n//var Z_NO_COMPRESSION      = 0;\n//var Z_BEST_SPEED          = 1;\n//var Z_BEST_COMPRESSION    = 9;\nvar Z_DEFAULT_COMPRESSION = -1;\n\n\nvar Z_FILTERED            = 1;\nvar Z_HUFFMAN_ONLY        = 2;\nvar Z_RLE                 = 3;\nvar Z_FIXED               = 4;\nvar Z_DEFAULT_STRATEGY    = 0;\n\n/* Possible values of the data_type field (though see inflate()) */\n//var Z_BINARY              = 0;\n//var Z_TEXT                = 1;\n//var Z_ASCII               = 1; // = Z_TEXT\nvar Z_UNKNOWN             = 2;\n\n\n/* The deflate compression method */\nvar Z_DEFLATED  = 8;\n\n/*============================================================================*/\n\n\nvar MAX_MEM_LEVEL = 9;\n/* Maximum value for memLevel in deflateInit2 */\nvar MAX_WBITS = 15;\n/* 32K LZ77 window */\nvar DEF_MEM_LEVEL = 8;\n\n\nvar LENGTH_CODES  = 29;\n/* number of length codes, not counting the special END_BLOCK code */\nvar LITERALS      = 256;\n/* number of literal bytes 0..255 */\nvar L_CODES       = LITERALS + 1 + LENGTH_CODES;\n/* number of Literal or Length codes, including the END_BLOCK code */\nvar D_CODES       = 30;\n/* number of distance codes */\nvar BL_CODES      = 19;\n/* number of codes used to transfer the bit lengths */\nvar HEAP_SIZE     = 2 * L_CODES + 1;\n/* maximum heap size */\nvar MAX_BITS  = 15;\n/* All codes must not exceed MAX_BITS bits */\n\nvar MIN_MATCH = 3;\nvar MAX_MATCH = 258;\nvar MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);\n\nvar PRESET_DICT = 0x20;\n\nvar INIT_STATE = 42;\nvar EXTRA_STATE = 69;\nvar NAME_STATE = 73;\nvar COMMENT_STATE = 91;\nvar HCRC_STATE = 103;\nvar BUSY_STATE = 113;\nvar FINISH_STATE = 666;\n\nvar BS_NEED_MORE      = 1; /* block not completed, need more input or more output */\nvar BS_BLOCK_DONE     = 2; /* block flush performed */\nvar BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */\nvar BS_FINISH_DONE    = 4; /* finish done, accept no more input or output */\n\nvar OS_CODE = 0x03; // Unix :) . Don't detect, use this default.\n\nfunction err(strm, errorCode) {\n  strm.msg = msg[errorCode];\n  return errorCode;\n}\n\nfunction rank(f) {\n  return ((f) << 1) - ((f) > 4 ? 9 : 0);\n}\n\nfunction zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }\n\n\n/* =========================================================================\n * Flush as much pending output as possible. All deflate() output goes\n * through this function so some applications may wish to modify it\n * to avoid allocating a large strm->output buffer and copying into it.\n * (See also read_buf()).\n */\nfunction flush_pending(strm) {\n  var s = strm.state;\n\n  //_tr_flush_bits(s);\n  var len = s.pending;\n  if (len > strm.avail_out) {\n    len = strm.avail_out;\n  }\n  if (len === 0) { return; }\n\n  utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out);\n  strm.next_out += len;\n  s.pending_out += len;\n  strm.total_out += len;\n  strm.avail_out -= len;\n  s.pending -= len;\n  if (s.pending === 0) {\n    s.pending_out = 0;\n  }\n}\n\n\nfunction flush_block_only(s, last) {\n  trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);\n  s.block_start = s.strstart;\n  flush_pending(s.strm);\n}\n\n\nfunction put_byte(s, b) {\n  s.pending_buf[s.pending++] = b;\n}\n\n\n/* =========================================================================\n * Put a short in the pending buffer. The 16-bit value is put in MSB order.\n * IN assertion: the stream state is correct and there is enough room in\n * pending_buf.\n */\nfunction putShortMSB(s, b) {\n//  put_byte(s, (Byte)(b >> 8));\n//  put_byte(s, (Byte)(b & 0xff));\n  s.pending_buf[s.pending++] = (b >>> 8) & 0xff;\n  s.pending_buf[s.pending++] = b & 0xff;\n}\n\n\n/* ===========================================================================\n * Read a new buffer from the current input stream, update the adler32\n * and total number of bytes read.  All deflate() input goes through\n * this function so some applications may wish to modify it to avoid\n * allocating a large strm->input buffer and copying from it.\n * (See also flush_pending()).\n */\nfunction read_buf(strm, buf, start, size) {\n  var len = strm.avail_in;\n\n  if (len > size) { len = size; }\n  if (len === 0) { return 0; }\n\n  strm.avail_in -= len;\n\n  // zmemcpy(buf, strm->next_in, len);\n  utils.arraySet(buf, strm.input, strm.next_in, len, start);\n  if (strm.state.wrap === 1) {\n    strm.adler = adler32(strm.adler, buf, len, start);\n  }\n\n  else if (strm.state.wrap === 2) {\n    strm.adler = crc32(strm.adler, buf, len, start);\n  }\n\n  strm.next_in += len;\n  strm.total_in += len;\n\n  return len;\n}\n\n\n/* ===========================================================================\n * Set match_start to the longest match starting at the given string and\n * return its length. Matches shorter or equal to prev_length are discarded,\n * in which case the result is equal to prev_length and match_start is\n * garbage.\n * IN assertions: cur_match is the head of the hash chain for the current\n *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1\n * OUT assertion: the match length is not greater than s->lookahead.\n */\nfunction longest_match(s, cur_match) {\n  var chain_length = s.max_chain_length;      /* max hash chain length */\n  var scan = s.strstart; /* current string */\n  var match;                       /* matched string */\n  var len;                           /* length of current match */\n  var best_len = s.prev_length;              /* best match length so far */\n  var nice_match = s.nice_match;             /* stop if match long enough */\n  var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?\n      s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;\n\n  var _win = s.window; // shortcut\n\n  var wmask = s.w_mask;\n  var prev  = s.prev;\n\n  /* Stop when cur_match becomes <= limit. To simplify the code,\n   * we prevent matches with the string of window index 0.\n   */\n\n  var strend = s.strstart + MAX_MATCH;\n  var scan_end1  = _win[scan + best_len - 1];\n  var scan_end   = _win[scan + best_len];\n\n  /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.\n   * It is easy to get rid of this optimization if necessary.\n   */\n  // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, \"Code too clever\");\n\n  /* Do not waste too much time if we already have a good match: */\n  if (s.prev_length >= s.good_match) {\n    chain_length >>= 2;\n  }\n  /* Do not look for matches beyond the end of the input. This is necessary\n   * to make deflate deterministic.\n   */\n  if (nice_match > s.lookahead) { nice_match = s.lookahead; }\n\n  // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, \"need lookahead\");\n\n  do {\n    // Assert(cur_match < s->strstart, \"no future\");\n    match = cur_match;\n\n    /* Skip to next match if the match length cannot increase\n     * or if the match length is less than 2.  Note that the checks below\n     * for insufficient lookahead only occur occasionally for performance\n     * reasons.  Therefore uninitialized memory will be accessed, and\n     * conditional jumps will be made that depend on those values.\n     * However the length of the match is limited to the lookahead, so\n     * the output of deflate is not affected by the uninitialized values.\n     */\n\n    if (_win[match + best_len]     !== scan_end  ||\n        _win[match + best_len - 1] !== scan_end1 ||\n        _win[match]                !== _win[scan] ||\n        _win[++match]              !== _win[scan + 1]) {\n      continue;\n    }\n\n    /* The check at best_len-1 can be removed because it will be made\n     * again later. (This heuristic is not always a win.)\n     * It is not necessary to compare scan[2] and match[2] since they\n     * are always equal when the other bytes match, given that\n     * the hash keys are equal and that HASH_BITS >= 8.\n     */\n    scan += 2;\n    match++;\n    // Assert(*scan == *match, \"match[2]?\");\n\n    /* We check for insufficient lookahead only every 8th comparison;\n     * the 256th check will be made at strstart+258.\n     */\n    do {\n      /*jshint noempty:false*/\n    } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&\n             scan < strend);\n\n    // Assert(scan <= s->window+(unsigned)(s->window_size-1), \"wild scan\");\n\n    len = MAX_MATCH - (strend - scan);\n    scan = strend - MAX_MATCH;\n\n    if (len > best_len) {\n      s.match_start = cur_match;\n      best_len = len;\n      if (len >= nice_match) {\n        break;\n      }\n      scan_end1  = _win[scan + best_len - 1];\n      scan_end   = _win[scan + best_len];\n    }\n  } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);\n\n  if (best_len <= s.lookahead) {\n    return best_len;\n  }\n  return s.lookahead;\n}\n\n\n/* ===========================================================================\n * Fill the window when the lookahead becomes insufficient.\n * Updates strstart and lookahead.\n *\n * IN assertion: lookahead < MIN_LOOKAHEAD\n * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD\n *    At least one byte has been read, or avail_in == 0; reads are\n *    performed for at least two bytes (required for the zip translate_eol\n *    option -- not supported here).\n */\nfunction fill_window(s) {\n  var _w_size = s.w_size;\n  var p, n, m, more, str;\n\n  //Assert(s->lookahead < MIN_LOOKAHEAD, \"already enough lookahead\");\n\n  do {\n    more = s.window_size - s.lookahead - s.strstart;\n\n    // JS ints have 32 bit, block below not needed\n    /* Deal with !@#$% 64K limit: */\n    //if (sizeof(int) <= 2) {\n    //    if (more == 0 && s->strstart == 0 && s->lookahead == 0) {\n    //        more = wsize;\n    //\n    //  } else if (more == (unsigned)(-1)) {\n    //        /* Very unlikely, but possible on 16 bit machine if\n    //         * strstart == 0 && lookahead == 1 (input done a byte at time)\n    //         */\n    //        more--;\n    //    }\n    //}\n\n\n    /* If the window is almost full and there is insufficient lookahead,\n     * move the upper half to the lower one to make room in the upper half.\n     */\n    if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {\n\n      utils.arraySet(s.window, s.window, _w_size, _w_size, 0);\n      s.match_start -= _w_size;\n      s.strstart -= _w_size;\n      /* we now have strstart >= MAX_DIST */\n      s.block_start -= _w_size;\n\n      /* Slide the hash table (could be avoided with 32 bit values\n       at the expense of memory usage). We slide even when level == 0\n       to keep the hash table consistent if we switch back to level > 0\n       later. (Using level 0 permanently is not an optimal usage of\n       zlib, so we don't care about this pathological case.)\n       */\n\n      n = s.hash_size;\n      p = n;\n      do {\n        m = s.head[--p];\n        s.head[p] = (m >= _w_size ? m - _w_size : 0);\n      } while (--n);\n\n      n = _w_size;\n      p = n;\n      do {\n        m = s.prev[--p];\n        s.prev[p] = (m >= _w_size ? m - _w_size : 0);\n        /* If n is not on any hash chain, prev[n] is garbage but\n         * its value will never be used.\n         */\n      } while (--n);\n\n      more += _w_size;\n    }\n    if (s.strm.avail_in === 0) {\n      break;\n    }\n\n    /* If there was no sliding:\n     *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&\n     *    more == window_size - lookahead - strstart\n     * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)\n     * => more >= window_size - 2*WSIZE + 2\n     * In the BIG_MEM or MMAP case (not yet supported),\n     *   window_size == input_size + MIN_LOOKAHEAD  &&\n     *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.\n     * Otherwise, window_size == 2*WSIZE so more >= 2.\n     * If there was sliding, more >= WSIZE. So in all cases, more >= 2.\n     */\n    //Assert(more >= 2, \"more < 2\");\n    n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);\n    s.lookahead += n;\n\n    /* Initialize the hash value now that we have some input: */\n    if (s.lookahead + s.insert >= MIN_MATCH) {\n      str = s.strstart - s.insert;\n      s.ins_h = s.window[str];\n\n      /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */\n      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask;\n//#if MIN_MATCH != 3\n//        Call update_hash() MIN_MATCH-3 more times\n//#endif\n      while (s.insert) {\n        /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */\n        s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask;\n\n        s.prev[str & s.w_mask] = s.head[s.ins_h];\n        s.head[s.ins_h] = str;\n        str++;\n        s.insert--;\n        if (s.lookahead + s.insert < MIN_MATCH) {\n          break;\n        }\n      }\n    }\n    /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,\n     * but this is not important since only literal bytes will be emitted.\n     */\n\n  } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);\n\n  /* If the WIN_INIT bytes after the end of the current data have never been\n   * written, then zero those bytes in order to avoid memory check reports of\n   * the use of uninitialized (or uninitialised as Julian writes) bytes by\n   * the longest match routines.  Update the high water mark for the next\n   * time through here.  WIN_INIT is set to MAX_MATCH since the longest match\n   * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.\n   */\n//  if (s.high_water < s.window_size) {\n//    var curr = s.strstart + s.lookahead;\n//    var init = 0;\n//\n//    if (s.high_water < curr) {\n//      /* Previous high water mark below current data -- zero WIN_INIT\n//       * bytes or up to end of window, whichever is less.\n//       */\n//      init = s.window_size - curr;\n//      if (init > WIN_INIT)\n//        init = WIN_INIT;\n//      zmemzero(s->window + curr, (unsigned)init);\n//      s->high_water = curr + init;\n//    }\n//    else if (s->high_water < (ulg)curr + WIN_INIT) {\n//      /* High water mark at or above current data, but below current data\n//       * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up\n//       * to end of window, whichever is less.\n//       */\n//      init = (ulg)curr + WIN_INIT - s->high_water;\n//      if (init > s->window_size - s->high_water)\n//        init = s->window_size - s->high_water;\n//      zmemzero(s->window + s->high_water, (unsigned)init);\n//      s->high_water += init;\n//    }\n//  }\n//\n//  Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,\n//    \"not enough room for search\");\n}\n\n/* ===========================================================================\n * Copy without compression as much as possible from the input stream, return\n * the current block state.\n * This function does not insert new strings in the dictionary since\n * uncompressible data is probably not useful. This function is used\n * only for the level=0 compression option.\n * NOTE: this function should be optimized to avoid extra copying from\n * window to pending_buf.\n */\nfunction deflate_stored(s, flush) {\n  /* Stored blocks are limited to 0xffff bytes, pending_buf is limited\n   * to pending_buf_size, and each stored block has a 5 byte header:\n   */\n  var max_block_size = 0xffff;\n\n  if (max_block_size > s.pending_buf_size - 5) {\n    max_block_size = s.pending_buf_size - 5;\n  }\n\n  /* Copy as much as possible from input to output: */\n  for (;;) {\n    /* Fill the window as much as possible: */\n    if (s.lookahead <= 1) {\n\n      //Assert(s->strstart < s->w_size+MAX_DIST(s) ||\n      //  s->block_start >= (long)s->w_size, \"slide too late\");\n//      if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) ||\n//        s.block_start >= s.w_size)) {\n//        throw  new Error(\"slide too late\");\n//      }\n\n      fill_window(s);\n      if (s.lookahead === 0 && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n\n      if (s.lookahead === 0) {\n        break;\n      }\n      /* flush the current block */\n    }\n    //Assert(s->block_start >= 0L, \"block gone\");\n//    if (s.block_start < 0) throw new Error(\"block gone\");\n\n    s.strstart += s.lookahead;\n    s.lookahead = 0;\n\n    /* Emit a stored block if pending_buf will be full: */\n    var max_start = s.block_start + max_block_size;\n\n    if (s.strstart === 0 || s.strstart >= max_start) {\n      /* strstart == 0 is possible when wraparound on 16-bit machine */\n      s.lookahead = s.strstart - max_start;\n      s.strstart = max_start;\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n\n\n    }\n    /* Flush if we may have to slide, otherwise block_start may become\n     * negative and the data will be gone:\n     */\n    if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n\n  s.insert = 0;\n\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n\n  if (s.strstart > s.block_start) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n\n  return BS_NEED_MORE;\n}\n\n/* ===========================================================================\n * Compress as much as possible from the input stream, return the current\n * block state.\n * This function does not perform lazy evaluation of matches and inserts\n * new strings in the dictionary only for unmatched strings or for short\n * matches. It is used only for the fast compression options.\n */\nfunction deflate_fast(s, flush) {\n  var hash_head;        /* head of the hash chain */\n  var bflush;           /* set if current block must be flushed */\n\n  for (;;) {\n    /* Make sure that we always have enough lookahead, except\n     * at the end of the input file. We need MAX_MATCH bytes\n     * for the next match, plus MIN_MATCH bytes to insert the\n     * string following the next match.\n     */\n    if (s.lookahead < MIN_LOOKAHEAD) {\n      fill_window(s);\n      if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n      if (s.lookahead === 0) {\n        break; /* flush the current block */\n      }\n    }\n\n    /* Insert the string window[strstart .. strstart+2] in the\n     * dictionary, and set hash_head to the head of the hash chain:\n     */\n    hash_head = 0/*NIL*/;\n    if (s.lookahead >= MIN_MATCH) {\n      /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n      hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n      s.head[s.ins_h] = s.strstart;\n      /***/\n    }\n\n    /* Find the longest match, discarding those <= prev_length.\n     * At this point we have always match_length < MIN_MATCH\n     */\n    if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {\n      /* To simplify the code, we prevent matches with the string\n       * of window index 0 (in particular we have to avoid a match\n       * of the string with itself at the start of the input file).\n       */\n      s.match_length = longest_match(s, hash_head);\n      /* longest_match() sets match_start */\n    }\n    if (s.match_length >= MIN_MATCH) {\n      // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only\n\n      /*** _tr_tally_dist(s, s.strstart - s.match_start,\n                     s.match_length - MIN_MATCH, bflush); ***/\n      bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);\n\n      s.lookahead -= s.match_length;\n\n      /* Insert new strings in the hash table only if the match length\n       * is not too large. This saves time but degrades compression.\n       */\n      if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) {\n        s.match_length--; /* string at strstart already in table */\n        do {\n          s.strstart++;\n          /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n          s.head[s.ins_h] = s.strstart;\n          /***/\n          /* strstart never exceeds WSIZE-MAX_MATCH, so there are\n           * always MIN_MATCH bytes ahead.\n           */\n        } while (--s.match_length !== 0);\n        s.strstart++;\n      } else\n      {\n        s.strstart += s.match_length;\n        s.match_length = 0;\n        s.ins_h = s.window[s.strstart];\n        /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */\n        s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask;\n\n//#if MIN_MATCH != 3\n//                Call UPDATE_HASH() MIN_MATCH-3 more times\n//#endif\n        /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not\n         * matter since it will be recomputed at next deflate call.\n         */\n      }\n    } else {\n      /* No match, output a literal byte */\n      //Tracevv((stderr,\"%c\", s.window[s.strstart]));\n      /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/\n      bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n\n      s.lookahead--;\n      s.strstart++;\n    }\n    if (bflush) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n  s.insert = ((s.strstart < (MIN_MATCH - 1)) ? s.strstart : MIN_MATCH - 1);\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n  return BS_BLOCK_DONE;\n}\n\n/* ===========================================================================\n * Same as above, but achieves better compression. We use a lazy\n * evaluation for matches: a match is finally adopted only if there is\n * no better match at the next window position.\n */\nfunction deflate_slow(s, flush) {\n  var hash_head;          /* head of hash chain */\n  var bflush;              /* set if current block must be flushed */\n\n  var max_insert;\n\n  /* Process the input block. */\n  for (;;) {\n    /* Make sure that we always have enough lookahead, except\n     * at the end of the input file. We need MAX_MATCH bytes\n     * for the next match, plus MIN_MATCH bytes to insert the\n     * string following the next match.\n     */\n    if (s.lookahead < MIN_LOOKAHEAD) {\n      fill_window(s);\n      if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n      if (s.lookahead === 0) { break; } /* flush the current block */\n    }\n\n    /* Insert the string window[strstart .. strstart+2] in the\n     * dictionary, and set hash_head to the head of the hash chain:\n     */\n    hash_head = 0/*NIL*/;\n    if (s.lookahead >= MIN_MATCH) {\n      /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n      hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n      s.head[s.ins_h] = s.strstart;\n      /***/\n    }\n\n    /* Find the longest match, discarding those <= prev_length.\n     */\n    s.prev_length = s.match_length;\n    s.prev_match = s.match_start;\n    s.match_length = MIN_MATCH - 1;\n\n    if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&\n        s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {\n      /* To simplify the code, we prevent matches with the string\n       * of window index 0 (in particular we have to avoid a match\n       * of the string with itself at the start of the input file).\n       */\n      s.match_length = longest_match(s, hash_head);\n      /* longest_match() sets match_start */\n\n      if (s.match_length <= 5 &&\n         (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {\n\n        /* If prev_match is also MIN_MATCH, match_start is garbage\n         * but we will ignore the current match anyway.\n         */\n        s.match_length = MIN_MATCH - 1;\n      }\n    }\n    /* If there was a match at the previous step and the current\n     * match is not better, output the previous match:\n     */\n    if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {\n      max_insert = s.strstart + s.lookahead - MIN_MATCH;\n      /* Do not insert strings in hash table beyond this. */\n\n      //check_match(s, s.strstart-1, s.prev_match, s.prev_length);\n\n      /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,\n                     s.prev_length - MIN_MATCH, bflush);***/\n      bflush = trees._tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH);\n      /* Insert in hash table all strings up to the end of the match.\n       * strstart-1 and strstart are already inserted. If there is not\n       * enough lookahead, the last two strings are not inserted in\n       * the hash table.\n       */\n      s.lookahead -= s.prev_length - 1;\n      s.prev_length -= 2;\n      do {\n        if (++s.strstart <= max_insert) {\n          /*** INSERT_STRING(s, s.strstart, hash_head); ***/\n          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;\n          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];\n          s.head[s.ins_h] = s.strstart;\n          /***/\n        }\n      } while (--s.prev_length !== 0);\n      s.match_available = 0;\n      s.match_length = MIN_MATCH - 1;\n      s.strstart++;\n\n      if (bflush) {\n        /*** FLUSH_BLOCK(s, 0); ***/\n        flush_block_only(s, false);\n        if (s.strm.avail_out === 0) {\n          return BS_NEED_MORE;\n        }\n        /***/\n      }\n\n    } else if (s.match_available) {\n      /* If there was no match at the previous position, output a\n       * single literal. If there was a match but the current match\n       * is longer, truncate the previous match to a single literal.\n       */\n      //Tracevv((stderr,\"%c\", s->window[s->strstart-1]));\n      /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/\n      bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]);\n\n      if (bflush) {\n        /*** FLUSH_BLOCK_ONLY(s, 0) ***/\n        flush_block_only(s, false);\n        /***/\n      }\n      s.strstart++;\n      s.lookahead--;\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n    } else {\n      /* There is no previous match to compare with, wait for\n       * the next step to decide.\n       */\n      s.match_available = 1;\n      s.strstart++;\n      s.lookahead--;\n    }\n  }\n  //Assert (flush != Z_NO_FLUSH, \"no flush?\");\n  if (s.match_available) {\n    //Tracevv((stderr,\"%c\", s->window[s->strstart-1]));\n    /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/\n    bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]);\n\n    s.match_available = 0;\n  }\n  s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1;\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n\n  return BS_BLOCK_DONE;\n}\n\n\n/* ===========================================================================\n * For Z_RLE, simply look for runs of bytes, generate matches only of distance\n * one.  Do not maintain a hash table.  (It will be regenerated if this run of\n * deflate switches away from Z_RLE.)\n */\nfunction deflate_rle(s, flush) {\n  var bflush;            /* set if current block must be flushed */\n  var prev;              /* byte at distance one to match */\n  var scan, strend;      /* scan goes up to strend for length of run */\n\n  var _win = s.window;\n\n  for (;;) {\n    /* Make sure that we always have enough lookahead, except\n     * at the end of the input file. We need MAX_MATCH bytes\n     * for the longest run, plus one for the unrolled loop.\n     */\n    if (s.lookahead <= MAX_MATCH) {\n      fill_window(s);\n      if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) {\n        return BS_NEED_MORE;\n      }\n      if (s.lookahead === 0) { break; } /* flush the current block */\n    }\n\n    /* See how many times the previous byte repeats */\n    s.match_length = 0;\n    if (s.lookahead >= MIN_MATCH && s.strstart > 0) {\n      scan = s.strstart - 1;\n      prev = _win[scan];\n      if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {\n        strend = s.strstart + MAX_MATCH;\n        do {\n          /*jshint noempty:false*/\n        } while (prev === _win[++scan] && prev === _win[++scan] &&\n                 prev === _win[++scan] && prev === _win[++scan] &&\n                 prev === _win[++scan] && prev === _win[++scan] &&\n                 prev === _win[++scan] && prev === _win[++scan] &&\n                 scan < strend);\n        s.match_length = MAX_MATCH - (strend - scan);\n        if (s.match_length > s.lookahead) {\n          s.match_length = s.lookahead;\n        }\n      }\n      //Assert(scan <= s->window+(uInt)(s->window_size-1), \"wild scan\");\n    }\n\n    /* Emit match if have run of MIN_MATCH or longer, else emit literal */\n    if (s.match_length >= MIN_MATCH) {\n      //check_match(s, s.strstart, s.strstart - 1, s.match_length);\n\n      /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/\n      bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH);\n\n      s.lookahead -= s.match_length;\n      s.strstart += s.match_length;\n      s.match_length = 0;\n    } else {\n      /* No match, output a literal byte */\n      //Tracevv((stderr,\"%c\", s->window[s->strstart]));\n      /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/\n      bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n\n      s.lookahead--;\n      s.strstart++;\n    }\n    if (bflush) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n  s.insert = 0;\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n  return BS_BLOCK_DONE;\n}\n\n/* ===========================================================================\n * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.\n * (It will be regenerated if this run of deflate switches away from Huffman.)\n */\nfunction deflate_huff(s, flush) {\n  var bflush;             /* set if current block must be flushed */\n\n  for (;;) {\n    /* Make sure that we have a literal to write. */\n    if (s.lookahead === 0) {\n      fill_window(s);\n      if (s.lookahead === 0) {\n        if (flush === Z_NO_FLUSH) {\n          return BS_NEED_MORE;\n        }\n        break;      /* flush the current block */\n      }\n    }\n\n    /* Output a literal byte */\n    s.match_length = 0;\n    //Tracevv((stderr,\"%c\", s->window[s->strstart]));\n    /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/\n    bflush = trees._tr_tally(s, 0, s.window[s.strstart]);\n    s.lookahead--;\n    s.strstart++;\n    if (bflush) {\n      /*** FLUSH_BLOCK(s, 0); ***/\n      flush_block_only(s, false);\n      if (s.strm.avail_out === 0) {\n        return BS_NEED_MORE;\n      }\n      /***/\n    }\n  }\n  s.insert = 0;\n  if (flush === Z_FINISH) {\n    /*** FLUSH_BLOCK(s, 1); ***/\n    flush_block_only(s, true);\n    if (s.strm.avail_out === 0) {\n      return BS_FINISH_STARTED;\n    }\n    /***/\n    return BS_FINISH_DONE;\n  }\n  if (s.last_lit) {\n    /*** FLUSH_BLOCK(s, 0); ***/\n    flush_block_only(s, false);\n    if (s.strm.avail_out === 0) {\n      return BS_NEED_MORE;\n    }\n    /***/\n  }\n  return BS_BLOCK_DONE;\n}\n\n/* Values for max_lazy_match, good_match and max_chain_length, depending on\n * the desired pack level (0..9). The values given below have been tuned to\n * exclude worst case performance for pathological files. Better values may be\n * found for specific files.\n */\nfunction Config(good_length, max_lazy, nice_length, max_chain, func) {\n  this.good_length = good_length;\n  this.max_lazy = max_lazy;\n  this.nice_length = nice_length;\n  this.max_chain = max_chain;\n  this.func = func;\n}\n\nvar configuration_table;\n\nconfiguration_table = [\n  /*      good lazy nice chain */\n  new Config(0, 0, 0, 0, deflate_stored),          /* 0 store only */\n  new Config(4, 4, 8, 4, deflate_fast),            /* 1 max speed, no lazy matches */\n  new Config(4, 5, 16, 8, deflate_fast),           /* 2 */\n  new Config(4, 6, 32, 32, deflate_fast),          /* 3 */\n\n  new Config(4, 4, 16, 16, deflate_slow),          /* 4 lazy matches */\n  new Config(8, 16, 32, 32, deflate_slow),         /* 5 */\n  new Config(8, 16, 128, 128, deflate_slow),       /* 6 */\n  new Config(8, 32, 128, 256, deflate_slow),       /* 7 */\n  new Config(32, 128, 258, 1024, deflate_slow),    /* 8 */\n  new Config(32, 258, 258, 4096, deflate_slow)     /* 9 max compression */\n];\n\n\n/* ===========================================================================\n * Initialize the \"longest match\" routines for a new zlib stream\n */\nfunction lm_init(s) {\n  s.window_size = 2 * s.w_size;\n\n  /*** CLEAR_HASH(s); ***/\n  zero(s.head); // Fill with NIL (= 0);\n\n  /* Set the default configuration parameters:\n   */\n  s.max_lazy_match = configuration_table[s.level].max_lazy;\n  s.good_match = configuration_table[s.level].good_length;\n  s.nice_match = configuration_table[s.level].nice_length;\n  s.max_chain_length = configuration_table[s.level].max_chain;\n\n  s.strstart = 0;\n  s.block_start = 0;\n  s.lookahead = 0;\n  s.insert = 0;\n  s.match_length = s.prev_length = MIN_MATCH - 1;\n  s.match_available = 0;\n  s.ins_h = 0;\n}\n\n\nfunction DeflateState() {\n  this.strm = null;            /* pointer back to this zlib stream */\n  this.status = 0;            /* as the name implies */\n  this.pending_buf = null;      /* output still pending */\n  this.pending_buf_size = 0;  /* size of pending_buf */\n  this.pending_out = 0;       /* next pending byte to output to the stream */\n  this.pending = 0;           /* nb of bytes in the pending buffer */\n  this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */\n  this.gzhead = null;         /* gzip header information to write */\n  this.gzindex = 0;           /* where in extra, name, or comment */\n  this.method = Z_DEFLATED; /* can only be DEFLATED */\n  this.last_flush = -1;   /* value of flush param for previous deflate call */\n\n  this.w_size = 0;  /* LZ77 window size (32K by default) */\n  this.w_bits = 0;  /* log2(w_size)  (8..16) */\n  this.w_mask = 0;  /* w_size - 1 */\n\n  this.window = null;\n  /* Sliding window. Input bytes are read into the second half of the window,\n   * and move to the first half later to keep a dictionary of at least wSize\n   * bytes. With this organization, matches are limited to a distance of\n   * wSize-MAX_MATCH bytes, but this ensures that IO is always\n   * performed with a length multiple of the block size.\n   */\n\n  this.window_size = 0;\n  /* Actual size of window: 2*wSize, except when the user input buffer\n   * is directly used as sliding window.\n   */\n\n  this.prev = null;\n  /* Link to older string with same hash index. To limit the size of this\n   * array to 64K, this link is maintained only for the last 32K strings.\n   * An index in this array is thus a window index modulo 32K.\n   */\n\n  this.head = null;   /* Heads of the hash chains or NIL. */\n\n  this.ins_h = 0;       /* hash index of string to be inserted */\n  this.hash_size = 0;   /* number of elements in hash table */\n  this.hash_bits = 0;   /* log2(hash_size) */\n  this.hash_mask = 0;   /* hash_size-1 */\n\n  this.hash_shift = 0;\n  /* Number of bits by which ins_h must be shifted at each input\n   * step. It must be such that after MIN_MATCH steps, the oldest\n   * byte no longer takes part in the hash key, that is:\n   *   hash_shift * MIN_MATCH >= hash_bits\n   */\n\n  this.block_start = 0;\n  /* Window position at the beginning of the current output block. Gets\n   * negative when the window is moved backwards.\n   */\n\n  this.match_length = 0;      /* length of best match */\n  this.prev_match = 0;        /* previous match */\n  this.match_available = 0;   /* set if previous match exists */\n  this.strstart = 0;          /* start of string to insert */\n  this.match_start = 0;       /* start of matching string */\n  this.lookahead = 0;         /* number of valid bytes ahead in window */\n\n  this.prev_length = 0;\n  /* Length of the best match at previous step. Matches not greater than this\n   * are discarded. This is used in the lazy match evaluation.\n   */\n\n  this.max_chain_length = 0;\n  /* To speed up deflation, hash chains are never searched beyond this\n   * length.  A higher limit improves compression ratio but degrades the\n   * speed.\n   */\n\n  this.max_lazy_match = 0;\n  /* Attempt to find a better match only when the current match is strictly\n   * smaller than this value. This mechanism is used only for compression\n   * levels >= 4.\n   */\n  // That's alias to max_lazy_match, don't use directly\n  //this.max_insert_length = 0;\n  /* Insert new strings in the hash table only if the match length is not\n   * greater than this length. This saves time but degrades compression.\n   * max_insert_length is used only for compression levels <= 3.\n   */\n\n  this.level = 0;     /* compression level (1..9) */\n  this.strategy = 0;  /* favor or force Huffman coding*/\n\n  this.good_match = 0;\n  /* Use a faster search when the previous match is longer than this */\n\n  this.nice_match = 0; /* Stop searching when current match exceeds this */\n\n              /* used by trees.c: */\n\n  /* Didn't use ct_data typedef below to suppress compiler warning */\n\n  // struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */\n  // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */\n  // struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */\n\n  // Use flat array of DOUBLE size, with interleaved fata,\n  // because JS does not support effective\n  this.dyn_ltree  = new utils.Buf16(HEAP_SIZE * 2);\n  this.dyn_dtree  = new utils.Buf16((2 * D_CODES + 1) * 2);\n  this.bl_tree    = new utils.Buf16((2 * BL_CODES + 1) * 2);\n  zero(this.dyn_ltree);\n  zero(this.dyn_dtree);\n  zero(this.bl_tree);\n\n  this.l_desc   = null;         /* desc. for literal tree */\n  this.d_desc   = null;         /* desc. for distance tree */\n  this.bl_desc  = null;         /* desc. for bit length tree */\n\n  //ush bl_count[MAX_BITS+1];\n  this.bl_count = new utils.Buf16(MAX_BITS + 1);\n  /* number of codes at each bit length for an optimal tree */\n\n  //int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */\n  this.heap = new utils.Buf16(2 * L_CODES + 1);  /* heap used to build the Huffman trees */\n  zero(this.heap);\n\n  this.heap_len = 0;               /* number of elements in the heap */\n  this.heap_max = 0;               /* element of largest frequency */\n  /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.\n   * The same heap array is used to build all trees.\n   */\n\n  this.depth = new utils.Buf16(2 * L_CODES + 1); //uch depth[2*L_CODES+1];\n  zero(this.depth);\n  /* Depth of each subtree used as tie breaker for trees of equal frequency\n   */\n\n  this.l_buf = 0;          /* buffer index for literals or lengths */\n\n  this.lit_bufsize = 0;\n  /* Size of match buffer for literals/lengths.  There are 4 reasons for\n   * limiting lit_bufsize to 64K:\n   *   - frequencies can be kept in 16 bit counters\n   *   - if compression is not successful for the first block, all input\n   *     data is still in the window so we can still emit a stored block even\n   *     when input comes from standard input.  (This can also be done for\n   *     all blocks if lit_bufsize is not greater than 32K.)\n   *   - if compression is not successful for a file smaller than 64K, we can\n   *     even emit a stored file instead of a stored block (saving 5 bytes).\n   *     This is applicable only for zip (not gzip or zlib).\n   *   - creating new Huffman trees less frequently may not provide fast\n   *     adaptation to changes in the input data statistics. (Take for\n   *     example a binary file with poorly compressible code followed by\n   *     a highly compressible string table.) Smaller buffer sizes give\n   *     fast adaptation but have of course the overhead of transmitting\n   *     trees more frequently.\n   *   - I can't count above 4\n   */\n\n  this.last_lit = 0;      /* running index in l_buf */\n\n  this.d_buf = 0;\n  /* Buffer index for distances. To simplify the code, d_buf and l_buf have\n   * the same number of elements. To use different lengths, an extra flag\n   * array would be necessary.\n   */\n\n  this.opt_len = 0;       /* bit length of current block with optimal trees */\n  this.static_len = 0;    /* bit length of current block with static trees */\n  this.matches = 0;       /* number of string matches in current block */\n  this.insert = 0;        /* bytes at end of window left to insert */\n\n\n  this.bi_buf = 0;\n  /* Output buffer. bits are inserted starting at the bottom (least\n   * significant bits).\n   */\n  this.bi_valid = 0;\n  /* Number of valid bits in bi_buf.  All bits above the last valid bit\n   * are always zero.\n   */\n\n  // Used for window memory init. We safely ignore it for JS. That makes\n  // sense only for pointers and memory check tools.\n  //this.high_water = 0;\n  /* High water mark offset in window for initialized bytes -- bytes above\n   * this are set to zero in order to avoid memory check warnings when\n   * longest match routines access bytes past the input.  This is then\n   * updated to the new high water mark.\n   */\n}\n\n\nfunction deflateResetKeep(strm) {\n  var s;\n\n  if (!strm || !strm.state) {\n    return err(strm, Z_STREAM_ERROR);\n  }\n\n  strm.total_in = strm.total_out = 0;\n  strm.data_type = Z_UNKNOWN;\n\n  s = strm.state;\n  s.pending = 0;\n  s.pending_out = 0;\n\n  if (s.wrap < 0) {\n    s.wrap = -s.wrap;\n    /* was made negative by deflate(..., Z_FINISH); */\n  }\n  s.status = (s.wrap ? INIT_STATE : BUSY_STATE);\n  strm.adler = (s.wrap === 2) ?\n    0  // crc32(0, Z_NULL, 0)\n  :\n    1; // adler32(0, Z_NULL, 0)\n  s.last_flush = Z_NO_FLUSH;\n  trees._tr_init(s);\n  return Z_OK;\n}\n\n\nfunction deflateReset(strm) {\n  var ret = deflateResetKeep(strm);\n  if (ret === Z_OK) {\n    lm_init(strm.state);\n  }\n  return ret;\n}\n\n\nfunction deflateSetHeader(strm, head) {\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; }\n  strm.state.gzhead = head;\n  return Z_OK;\n}\n\n\nfunction deflateInit2(strm, level, method, windowBits, memLevel, strategy) {\n  if (!strm) { // === Z_NULL\n    return Z_STREAM_ERROR;\n  }\n  var wrap = 1;\n\n  if (level === Z_DEFAULT_COMPRESSION) {\n    level = 6;\n  }\n\n  if (windowBits < 0) { /* suppress zlib wrapper */\n    wrap = 0;\n    windowBits = -windowBits;\n  }\n\n  else if (windowBits > 15) {\n    wrap = 2;           /* write gzip wrapper instead */\n    windowBits -= 16;\n  }\n\n\n  if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED ||\n    windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||\n    strategy < 0 || strategy > Z_FIXED) {\n    return err(strm, Z_STREAM_ERROR);\n  }\n\n\n  if (windowBits === 8) {\n    windowBits = 9;\n  }\n  /* until 256-byte window bug fixed */\n\n  var s = new DeflateState();\n\n  strm.state = s;\n  s.strm = strm;\n\n  s.wrap = wrap;\n  s.gzhead = null;\n  s.w_bits = windowBits;\n  s.w_size = 1 << s.w_bits;\n  s.w_mask = s.w_size - 1;\n\n  s.hash_bits = memLevel + 7;\n  s.hash_size = 1 << s.hash_bits;\n  s.hash_mask = s.hash_size - 1;\n  s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);\n\n  s.window = new utils.Buf8(s.w_size * 2);\n  s.head = new utils.Buf16(s.hash_size);\n  s.prev = new utils.Buf16(s.w_size);\n\n  // Don't need mem init magic for JS.\n  //s.high_water = 0;  /* nothing written to s->window yet */\n\n  s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */\n\n  s.pending_buf_size = s.lit_bufsize * 4;\n\n  //overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);\n  //s->pending_buf = (uchf *) overlay;\n  s.pending_buf = new utils.Buf8(s.pending_buf_size);\n\n  // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`)\n  //s->d_buf = overlay + s->lit_bufsize/sizeof(ush);\n  s.d_buf = 1 * s.lit_bufsize;\n\n  //s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;\n  s.l_buf = (1 + 2) * s.lit_bufsize;\n\n  s.level = level;\n  s.strategy = strategy;\n  s.method = method;\n\n  return deflateReset(strm);\n}\n\nfunction deflateInit(strm, level) {\n  return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);\n}\n\n\nfunction deflate(strm, flush) {\n  var old_flush, s;\n  var beg, val; // for gzip header write only\n\n  if (!strm || !strm.state ||\n    flush > Z_BLOCK || flush < 0) {\n    return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR;\n  }\n\n  s = strm.state;\n\n  if (!strm.output ||\n      (!strm.input && strm.avail_in !== 0) ||\n      (s.status === FINISH_STATE && flush !== Z_FINISH)) {\n    return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR);\n  }\n\n  s.strm = strm; /* just in case */\n  old_flush = s.last_flush;\n  s.last_flush = flush;\n\n  /* Write the header */\n  if (s.status === INIT_STATE) {\n\n    if (s.wrap === 2) { // GZIP header\n      strm.adler = 0;  //crc32(0L, Z_NULL, 0);\n      put_byte(s, 31);\n      put_byte(s, 139);\n      put_byte(s, 8);\n      if (!s.gzhead) { // s->gzhead == Z_NULL\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, 0);\n        put_byte(s, s.level === 9 ? 2 :\n                    (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?\n                     4 : 0));\n        put_byte(s, OS_CODE);\n        s.status = BUSY_STATE;\n      }\n      else {\n        put_byte(s, (s.gzhead.text ? 1 : 0) +\n                    (s.gzhead.hcrc ? 2 : 0) +\n                    (!s.gzhead.extra ? 0 : 4) +\n                    (!s.gzhead.name ? 0 : 8) +\n                    (!s.gzhead.comment ? 0 : 16)\n                );\n        put_byte(s, s.gzhead.time & 0xff);\n        put_byte(s, (s.gzhead.time >> 8) & 0xff);\n        put_byte(s, (s.gzhead.time >> 16) & 0xff);\n        put_byte(s, (s.gzhead.time >> 24) & 0xff);\n        put_byte(s, s.level === 9 ? 2 :\n                    (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?\n                     4 : 0));\n        put_byte(s, s.gzhead.os & 0xff);\n        if (s.gzhead.extra && s.gzhead.extra.length) {\n          put_byte(s, s.gzhead.extra.length & 0xff);\n          put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);\n        }\n        if (s.gzhead.hcrc) {\n          strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0);\n        }\n        s.gzindex = 0;\n        s.status = EXTRA_STATE;\n      }\n    }\n    else // DEFLATE header\n    {\n      var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8;\n      var level_flags = -1;\n\n      if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {\n        level_flags = 0;\n      } else if (s.level < 6) {\n        level_flags = 1;\n      } else if (s.level === 6) {\n        level_flags = 2;\n      } else {\n        level_flags = 3;\n      }\n      header |= (level_flags << 6);\n      if (s.strstart !== 0) { header |= PRESET_DICT; }\n      header += 31 - (header % 31);\n\n      s.status = BUSY_STATE;\n      putShortMSB(s, header);\n\n      /* Save the adler32 of the preset dictionary: */\n      if (s.strstart !== 0) {\n        putShortMSB(s, strm.adler >>> 16);\n        putShortMSB(s, strm.adler & 0xffff);\n      }\n      strm.adler = 1; // adler32(0L, Z_NULL, 0);\n    }\n  }\n\n//#ifdef GZIP\n  if (s.status === EXTRA_STATE) {\n    if (s.gzhead.extra/* != Z_NULL*/) {\n      beg = s.pending;  /* start of bytes to update crc */\n\n      while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {\n        if (s.pending === s.pending_buf_size) {\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          flush_pending(strm);\n          beg = s.pending;\n          if (s.pending === s.pending_buf_size) {\n            break;\n          }\n        }\n        put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);\n        s.gzindex++;\n      }\n      if (s.gzhead.hcrc && s.pending > beg) {\n        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n      }\n      if (s.gzindex === s.gzhead.extra.length) {\n        s.gzindex = 0;\n        s.status = NAME_STATE;\n      }\n    }\n    else {\n      s.status = NAME_STATE;\n    }\n  }\n  if (s.status === NAME_STATE) {\n    if (s.gzhead.name/* != Z_NULL*/) {\n      beg = s.pending;  /* start of bytes to update crc */\n      //int val;\n\n      do {\n        if (s.pending === s.pending_buf_size) {\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          flush_pending(strm);\n          beg = s.pending;\n          if (s.pending === s.pending_buf_size) {\n            val = 1;\n            break;\n          }\n        }\n        // JS specific: little magic to add zero terminator to end of string\n        if (s.gzindex < s.gzhead.name.length) {\n          val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;\n        } else {\n          val = 0;\n        }\n        put_byte(s, val);\n      } while (val !== 0);\n\n      if (s.gzhead.hcrc && s.pending > beg) {\n        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n      }\n      if (val === 0) {\n        s.gzindex = 0;\n        s.status = COMMENT_STATE;\n      }\n    }\n    else {\n      s.status = COMMENT_STATE;\n    }\n  }\n  if (s.status === COMMENT_STATE) {\n    if (s.gzhead.comment/* != Z_NULL*/) {\n      beg = s.pending;  /* start of bytes to update crc */\n      //int val;\n\n      do {\n        if (s.pending === s.pending_buf_size) {\n          if (s.gzhead.hcrc && s.pending > beg) {\n            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n          }\n          flush_pending(strm);\n          beg = s.pending;\n          if (s.pending === s.pending_buf_size) {\n            val = 1;\n            break;\n          }\n        }\n        // JS specific: little magic to add zero terminator to end of string\n        if (s.gzindex < s.gzhead.comment.length) {\n          val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;\n        } else {\n          val = 0;\n        }\n        put_byte(s, val);\n      } while (val !== 0);\n\n      if (s.gzhead.hcrc && s.pending > beg) {\n        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);\n      }\n      if (val === 0) {\n        s.status = HCRC_STATE;\n      }\n    }\n    else {\n      s.status = HCRC_STATE;\n    }\n  }\n  if (s.status === HCRC_STATE) {\n    if (s.gzhead.hcrc) {\n      if (s.pending + 2 > s.pending_buf_size) {\n        flush_pending(strm);\n      }\n      if (s.pending + 2 <= s.pending_buf_size) {\n        put_byte(s, strm.adler & 0xff);\n        put_byte(s, (strm.adler >> 8) & 0xff);\n        strm.adler = 0; //crc32(0L, Z_NULL, 0);\n        s.status = BUSY_STATE;\n      }\n    }\n    else {\n      s.status = BUSY_STATE;\n    }\n  }\n//#endif\n\n  /* Flush as much pending output as possible */\n  if (s.pending !== 0) {\n    flush_pending(strm);\n    if (strm.avail_out === 0) {\n      /* Since avail_out is 0, deflate will be called again with\n       * more output space, but possibly with both pending and\n       * avail_in equal to zero. There won't be anything to do,\n       * but this is not an error situation so make sure we\n       * return OK instead of BUF_ERROR at next call of deflate:\n       */\n      s.last_flush = -1;\n      return Z_OK;\n    }\n\n    /* Make sure there is something to do and avoid duplicate consecutive\n     * flushes. For repeated and useless calls with Z_FINISH, we keep\n     * returning Z_STREAM_END instead of Z_BUF_ERROR.\n     */\n  } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&\n    flush !== Z_FINISH) {\n    return err(strm, Z_BUF_ERROR);\n  }\n\n  /* User must not provide more input after the first FINISH: */\n  if (s.status === FINISH_STATE && strm.avail_in !== 0) {\n    return err(strm, Z_BUF_ERROR);\n  }\n\n  /* Start a new block or continue the current one.\n   */\n  if (strm.avail_in !== 0 || s.lookahead !== 0 ||\n    (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) {\n    var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) :\n      (s.strategy === Z_RLE ? deflate_rle(s, flush) :\n        configuration_table[s.level].func(s, flush));\n\n    if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {\n      s.status = FINISH_STATE;\n    }\n    if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {\n      if (strm.avail_out === 0) {\n        s.last_flush = -1;\n        /* avoid BUF_ERROR next call, see above */\n      }\n      return Z_OK;\n      /* If flush != Z_NO_FLUSH && avail_out == 0, the next call\n       * of deflate should use the same flush parameter to make sure\n       * that the flush is complete. So we don't have to output an\n       * empty block here, this will be done at next call. This also\n       * ensures that for a very small output buffer, we emit at most\n       * one empty block.\n       */\n    }\n    if (bstate === BS_BLOCK_DONE) {\n      if (flush === Z_PARTIAL_FLUSH) {\n        trees._tr_align(s);\n      }\n      else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */\n\n        trees._tr_stored_block(s, 0, 0, false);\n        /* For a full flush, this empty block will be recognized\n         * as a special marker by inflate_sync().\n         */\n        if (flush === Z_FULL_FLUSH) {\n          /*** CLEAR_HASH(s); ***/             /* forget history */\n          zero(s.head); // Fill with NIL (= 0);\n\n          if (s.lookahead === 0) {\n            s.strstart = 0;\n            s.block_start = 0;\n            s.insert = 0;\n          }\n        }\n      }\n      flush_pending(strm);\n      if (strm.avail_out === 0) {\n        s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */\n        return Z_OK;\n      }\n    }\n  }\n  //Assert(strm->avail_out > 0, \"bug2\");\n  //if (strm.avail_out <= 0) { throw new Error(\"bug2\");}\n\n  if (flush !== Z_FINISH) { return Z_OK; }\n  if (s.wrap <= 0) { return Z_STREAM_END; }\n\n  /* Write the trailer */\n  if (s.wrap === 2) {\n    put_byte(s, strm.adler & 0xff);\n    put_byte(s, (strm.adler >> 8) & 0xff);\n    put_byte(s, (strm.adler >> 16) & 0xff);\n    put_byte(s, (strm.adler >> 24) & 0xff);\n    put_byte(s, strm.total_in & 0xff);\n    put_byte(s, (strm.total_in >> 8) & 0xff);\n    put_byte(s, (strm.total_in >> 16) & 0xff);\n    put_byte(s, (strm.total_in >> 24) & 0xff);\n  }\n  else\n  {\n    putShortMSB(s, strm.adler >>> 16);\n    putShortMSB(s, strm.adler & 0xffff);\n  }\n\n  flush_pending(strm);\n  /* If avail_out is zero, the application will call deflate again\n   * to flush the rest.\n   */\n  if (s.wrap > 0) { s.wrap = -s.wrap; }\n  /* write the trailer only once! */\n  return s.pending !== 0 ? Z_OK : Z_STREAM_END;\n}\n\nfunction deflateEnd(strm) {\n  var status;\n\n  if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {\n    return Z_STREAM_ERROR;\n  }\n\n  status = strm.state.status;\n  if (status !== INIT_STATE &&\n    status !== EXTRA_STATE &&\n    status !== NAME_STATE &&\n    status !== COMMENT_STATE &&\n    status !== HCRC_STATE &&\n    status !== BUSY_STATE &&\n    status !== FINISH_STATE\n  ) {\n    return err(strm, Z_STREAM_ERROR);\n  }\n\n  strm.state = null;\n\n  return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK;\n}\n\n\n/* =========================================================================\n * Initializes the compression dictionary from the given byte\n * sequence without producing any compressed output.\n */\nfunction deflateSetDictionary(strm, dictionary) {\n  var dictLength = dictionary.length;\n\n  var s;\n  var str, n;\n  var wrap;\n  var avail;\n  var next;\n  var input;\n  var tmpDict;\n\n  if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {\n    return Z_STREAM_ERROR;\n  }\n\n  s = strm.state;\n  wrap = s.wrap;\n\n  if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) {\n    return Z_STREAM_ERROR;\n  }\n\n  /* when using zlib wrappers, compute Adler-32 for provided dictionary */\n  if (wrap === 1) {\n    /* adler32(strm->adler, dictionary, dictLength); */\n    strm.adler = adler32(strm.adler, dictionary, dictLength, 0);\n  }\n\n  s.wrap = 0;   /* avoid computing Adler-32 in read_buf */\n\n  /* if dictionary would fill window, just replace the history */\n  if (dictLength >= s.w_size) {\n    if (wrap === 0) {            /* already empty otherwise */\n      /*** CLEAR_HASH(s); ***/\n      zero(s.head); // Fill with NIL (= 0);\n      s.strstart = 0;\n      s.block_start = 0;\n      s.insert = 0;\n    }\n    /* use the tail */\n    // dictionary = dictionary.slice(dictLength - s.w_size);\n    tmpDict = new utils.Buf8(s.w_size);\n    utils.arraySet(tmpDict, dictionary, dictLength - s.w_size, s.w_size, 0);\n    dictionary = tmpDict;\n    dictLength = s.w_size;\n  }\n  /* insert dictionary into window and hash */\n  avail = strm.avail_in;\n  next = strm.next_in;\n  input = strm.input;\n  strm.avail_in = dictLength;\n  strm.next_in = 0;\n  strm.input = dictionary;\n  fill_window(s);\n  while (s.lookahead >= MIN_MATCH) {\n    str = s.strstart;\n    n = s.lookahead - (MIN_MATCH - 1);\n    do {\n      /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */\n      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask;\n\n      s.prev[str & s.w_mask] = s.head[s.ins_h];\n\n      s.head[s.ins_h] = str;\n      str++;\n    } while (--n);\n    s.strstart = str;\n    s.lookahead = MIN_MATCH - 1;\n    fill_window(s);\n  }\n  s.strstart += s.lookahead;\n  s.block_start = s.strstart;\n  s.insert = s.lookahead;\n  s.lookahead = 0;\n  s.match_length = s.prev_length = MIN_MATCH - 1;\n  s.match_available = 0;\n  strm.next_in = next;\n  strm.input = input;\n  strm.avail_in = avail;\n  s.wrap = wrap;\n  return Z_OK;\n}\n\n\nexports.deflateInit = deflateInit;\nexports.deflateInit2 = deflateInit2;\nexports.deflateReset = deflateReset;\nexports.deflateResetKeep = deflateResetKeep;\nexports.deflateSetHeader = deflateSetHeader;\nexports.deflate = deflate;\nexports.deflateEnd = deflateEnd;\nexports.deflateSetDictionary = deflateSetDictionary;\nexports.deflateInfo = 'pako deflate (from Nodeca project)';\n\n/* Not implemented\nexports.deflateBound = deflateBound;\nexports.deflateCopy = deflateCopy;\nexports.deflateParams = deflateParams;\nexports.deflatePending = deflatePending;\nexports.deflatePrime = deflatePrime;\nexports.deflateTune = deflateTune;\n*/\n\n\n/***/ }),\n/* 155 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nvar utils = __webpack_require__(34);\n\n/* Public constants ==========================================================*/\n/* ===========================================================================*/\n\n\n//var Z_FILTERED          = 1;\n//var Z_HUFFMAN_ONLY      = 2;\n//var Z_RLE               = 3;\nvar Z_FIXED               = 4;\n//var Z_DEFAULT_STRATEGY  = 0;\n\n/* Possible values of the data_type field (though see inflate()) */\nvar Z_BINARY              = 0;\nvar Z_TEXT                = 1;\n//var Z_ASCII             = 1; // = Z_TEXT\nvar Z_UNKNOWN             = 2;\n\n/*============================================================================*/\n\n\nfunction zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }\n\n// From zutil.h\n\nvar STORED_BLOCK = 0;\nvar STATIC_TREES = 1;\nvar DYN_TREES    = 2;\n/* The three kinds of block type */\n\nvar MIN_MATCH    = 3;\nvar MAX_MATCH    = 258;\n/* The minimum and maximum match lengths */\n\n// From deflate.h\n/* ===========================================================================\n * Internal compression state.\n */\n\nvar LENGTH_CODES  = 29;\n/* number of length codes, not counting the special END_BLOCK code */\n\nvar LITERALS      = 256;\n/* number of literal bytes 0..255 */\n\nvar L_CODES       = LITERALS + 1 + LENGTH_CODES;\n/* number of Literal or Length codes, including the END_BLOCK code */\n\nvar D_CODES       = 30;\n/* number of distance codes */\n\nvar BL_CODES      = 19;\n/* number of codes used to transfer the bit lengths */\n\nvar HEAP_SIZE     = 2 * L_CODES + 1;\n/* maximum heap size */\n\nvar MAX_BITS      = 15;\n/* All codes must not exceed MAX_BITS bits */\n\nvar Buf_size      = 16;\n/* size of bit buffer in bi_buf */\n\n\n/* ===========================================================================\n * Constants\n */\n\nvar MAX_BL_BITS = 7;\n/* Bit length codes must not exceed MAX_BL_BITS bits */\n\nvar END_BLOCK   = 256;\n/* end of block literal code */\n\nvar REP_3_6     = 16;\n/* repeat previous bit length 3-6 times (2 bits of repeat count) */\n\nvar REPZ_3_10   = 17;\n/* repeat a zero length 3-10 times  (3 bits of repeat count) */\n\nvar REPZ_11_138 = 18;\n/* repeat a zero length 11-138 times  (7 bits of repeat count) */\n\n/* eslint-disable comma-spacing,array-bracket-spacing */\nvar extra_lbits =   /* extra bits for each length code */\n  [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0];\n\nvar extra_dbits =   /* extra bits for each distance code */\n  [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];\n\nvar extra_blbits =  /* extra bits for each bit length code */\n  [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];\n\nvar bl_order =\n  [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];\n/* eslint-enable comma-spacing,array-bracket-spacing */\n\n/* The lengths of the bit length codes are sent in order of decreasing\n * probability, to avoid transmitting the lengths for unused bit length codes.\n */\n\n/* ===========================================================================\n * Local data. These are initialized only once.\n */\n\n// We pre-fill arrays with 0 to avoid uninitialized gaps\n\nvar DIST_CODE_LEN = 512; /* see definition of array dist_code below */\n\n// !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1\nvar static_ltree  = new Array((L_CODES + 2) * 2);\nzero(static_ltree);\n/* The static literal tree. Since the bit lengths are imposed, there is no\n * need for the L_CODES extra codes used during heap construction. However\n * The codes 286 and 287 are needed to build a canonical tree (see _tr_init\n * below).\n */\n\nvar static_dtree  = new Array(D_CODES * 2);\nzero(static_dtree);\n/* The static distance tree. (Actually a trivial tree since all codes use\n * 5 bits.)\n */\n\nvar _dist_code    = new Array(DIST_CODE_LEN);\nzero(_dist_code);\n/* Distance codes. The first 256 values correspond to the distances\n * 3 .. 258, the last 256 values correspond to the top 8 bits of\n * the 15 bit distances.\n */\n\nvar _length_code  = new Array(MAX_MATCH - MIN_MATCH + 1);\nzero(_length_code);\n/* length code for each normalized match length (0 == MIN_MATCH) */\n\nvar base_length   = new Array(LENGTH_CODES);\nzero(base_length);\n/* First normalized length for each code (0 = MIN_MATCH) */\n\nvar base_dist     = new Array(D_CODES);\nzero(base_dist);\n/* First normalized distance for each code (0 = distance of 1) */\n\n\nfunction StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) {\n\n  this.static_tree  = static_tree;  /* static tree or NULL */\n  this.extra_bits   = extra_bits;   /* extra bits for each code or NULL */\n  this.extra_base   = extra_base;   /* base index for extra_bits */\n  this.elems        = elems;        /* max number of elements in the tree */\n  this.max_length   = max_length;   /* max bit length for the codes */\n\n  // show if `static_tree` has data or dummy - needed for monomorphic objects\n  this.has_stree    = static_tree && static_tree.length;\n}\n\n\nvar static_l_desc;\nvar static_d_desc;\nvar static_bl_desc;\n\n\nfunction TreeDesc(dyn_tree, stat_desc) {\n  this.dyn_tree = dyn_tree;     /* the dynamic tree */\n  this.max_code = 0;            /* largest code with non zero frequency */\n  this.stat_desc = stat_desc;   /* the corresponding static tree */\n}\n\n\n\nfunction d_code(dist) {\n  return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];\n}\n\n\n/* ===========================================================================\n * Output a short LSB first on the stream.\n * IN assertion: there is enough room in pendingBuf.\n */\nfunction put_short(s, w) {\n//    put_byte(s, (uch)((w) & 0xff));\n//    put_byte(s, (uch)((ush)(w) >> 8));\n  s.pending_buf[s.pending++] = (w) & 0xff;\n  s.pending_buf[s.pending++] = (w >>> 8) & 0xff;\n}\n\n\n/* ===========================================================================\n * Send a value on a given number of bits.\n * IN assertion: length <= 16 and value fits in length bits.\n */\nfunction send_bits(s, value, length) {\n  if (s.bi_valid > (Buf_size - length)) {\n    s.bi_buf |= (value << s.bi_valid) & 0xffff;\n    put_short(s, s.bi_buf);\n    s.bi_buf = value >> (Buf_size - s.bi_valid);\n    s.bi_valid += length - Buf_size;\n  } else {\n    s.bi_buf |= (value << s.bi_valid) & 0xffff;\n    s.bi_valid += length;\n  }\n}\n\n\nfunction send_code(s, c, tree) {\n  send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/);\n}\n\n\n/* ===========================================================================\n * Reverse the first len bits of a code, using straightforward code (a faster\n * method would use a table)\n * IN assertion: 1 <= len <= 15\n */\nfunction bi_reverse(code, len) {\n  var res = 0;\n  do {\n    res |= code & 1;\n    code >>>= 1;\n    res <<= 1;\n  } while (--len > 0);\n  return res >>> 1;\n}\n\n\n/* ===========================================================================\n * Flush the bit buffer, keeping at most 7 bits in it.\n */\nfunction bi_flush(s) {\n  if (s.bi_valid === 16) {\n    put_short(s, s.bi_buf);\n    s.bi_buf = 0;\n    s.bi_valid = 0;\n\n  } else if (s.bi_valid >= 8) {\n    s.pending_buf[s.pending++] = s.bi_buf & 0xff;\n    s.bi_buf >>= 8;\n    s.bi_valid -= 8;\n  }\n}\n\n\n/* ===========================================================================\n * Compute the optimal bit lengths for a tree and update the total bit length\n * for the current block.\n * IN assertion: the fields freq and dad are set, heap[heap_max] and\n *    above are the tree nodes sorted by increasing frequency.\n * OUT assertions: the field len is set to the optimal bit length, the\n *     array bl_count contains the frequencies for each bit length.\n *     The length opt_len is updated; static_len is also updated if stree is\n *     not null.\n */\nfunction gen_bitlen(s, desc)\n//    deflate_state *s;\n//    tree_desc *desc;    /* the tree descriptor */\n{\n  var tree            = desc.dyn_tree;\n  var max_code        = desc.max_code;\n  var stree           = desc.stat_desc.static_tree;\n  var has_stree       = desc.stat_desc.has_stree;\n  var extra           = desc.stat_desc.extra_bits;\n  var base            = desc.stat_desc.extra_base;\n  var max_length      = desc.stat_desc.max_length;\n  var h;              /* heap index */\n  var n, m;           /* iterate over the tree elements */\n  var bits;           /* bit length */\n  var xbits;          /* extra bits */\n  var f;              /* frequency */\n  var overflow = 0;   /* number of elements with bit length too large */\n\n  for (bits = 0; bits <= MAX_BITS; bits++) {\n    s.bl_count[bits] = 0;\n  }\n\n  /* In a first pass, compute the optimal bit lengths (which may\n   * overflow in the case of the bit length tree).\n   */\n  tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */\n\n  for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {\n    n = s.heap[h];\n    bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;\n    if (bits > max_length) {\n      bits = max_length;\n      overflow++;\n    }\n    tree[n * 2 + 1]/*.Len*/ = bits;\n    /* We overwrite tree[n].Dad which is no longer needed */\n\n    if (n > max_code) { continue; } /* not a leaf node */\n\n    s.bl_count[bits]++;\n    xbits = 0;\n    if (n >= base) {\n      xbits = extra[n - base];\n    }\n    f = tree[n * 2]/*.Freq*/;\n    s.opt_len += f * (bits + xbits);\n    if (has_stree) {\n      s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits);\n    }\n  }\n  if (overflow === 0) { return; }\n\n  // Trace((stderr,\"\\nbit length overflow\\n\"));\n  /* This happens for example on obj2 and pic of the Calgary corpus */\n\n  /* Find the first bit length which could increase: */\n  do {\n    bits = max_length - 1;\n    while (s.bl_count[bits] === 0) { bits--; }\n    s.bl_count[bits]--;      /* move one leaf down the tree */\n    s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */\n    s.bl_count[max_length]--;\n    /* The brother of the overflow item also moves one step up,\n     * but this does not affect bl_count[max_length]\n     */\n    overflow -= 2;\n  } while (overflow > 0);\n\n  /* Now recompute all bit lengths, scanning in increasing frequency.\n   * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all\n   * lengths instead of fixing only the wrong ones. This idea is taken\n   * from 'ar' written by Haruhiko Okumura.)\n   */\n  for (bits = max_length; bits !== 0; bits--) {\n    n = s.bl_count[bits];\n    while (n !== 0) {\n      m = s.heap[--h];\n      if (m > max_code) { continue; }\n      if (tree[m * 2 + 1]/*.Len*/ !== bits) {\n        // Trace((stderr,\"code %d bits %d->%d\\n\", m, tree[m].Len, bits));\n        s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/;\n        tree[m * 2 + 1]/*.Len*/ = bits;\n      }\n      n--;\n    }\n  }\n}\n\n\n/* ===========================================================================\n * Generate the codes for a given tree and bit counts (which need not be\n * optimal).\n * IN assertion: the array bl_count contains the bit length statistics for\n * the given tree and the field len is set for all tree elements.\n * OUT assertion: the field code is set for all tree elements of non\n *     zero code length.\n */\nfunction gen_codes(tree, max_code, bl_count)\n//    ct_data *tree;             /* the tree to decorate */\n//    int max_code;              /* largest code with non zero frequency */\n//    ushf *bl_count;            /* number of codes at each bit length */\n{\n  var next_code = new Array(MAX_BITS + 1); /* next code value for each bit length */\n  var code = 0;              /* running code value */\n  var bits;                  /* bit index */\n  var n;                     /* code index */\n\n  /* The distribution counts are first used to generate the code values\n   * without bit reversal.\n   */\n  for (bits = 1; bits <= MAX_BITS; bits++) {\n    next_code[bits] = code = (code + bl_count[bits - 1]) << 1;\n  }\n  /* Check that the bit counts in bl_count are consistent. The last code\n   * must be all ones.\n   */\n  //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,\n  //        \"inconsistent bit counts\");\n  //Tracev((stderr,\"\\ngen_codes: max_code %d \", max_code));\n\n  for (n = 0;  n <= max_code; n++) {\n    var len = tree[n * 2 + 1]/*.Len*/;\n    if (len === 0) { continue; }\n    /* Now reverse the bits */\n    tree[n * 2]/*.Code*/ = bi_reverse(next_code[len]++, len);\n\n    //Tracecv(tree != static_ltree, (stderr,\"\\nn %3d %c l %2d c %4x (%x) \",\n    //     n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));\n  }\n}\n\n\n/* ===========================================================================\n * Initialize the various 'constant' tables.\n */\nfunction tr_static_init() {\n  var n;        /* iterates over tree elements */\n  var bits;     /* bit counter */\n  var length;   /* length value */\n  var code;     /* code value */\n  var dist;     /* distance index */\n  var bl_count = new Array(MAX_BITS + 1);\n  /* number of codes at each bit length for an optimal tree */\n\n  // do check in _tr_init()\n  //if (static_init_done) return;\n\n  /* For some embedded targets, global variables are not initialized: */\n/*#ifdef NO_INIT_GLOBAL_POINTERS\n  static_l_desc.static_tree = static_ltree;\n  static_l_desc.extra_bits = extra_lbits;\n  static_d_desc.static_tree = static_dtree;\n  static_d_desc.extra_bits = extra_dbits;\n  static_bl_desc.extra_bits = extra_blbits;\n#endif*/\n\n  /* Initialize the mapping length (0..255) -> length code (0..28) */\n  length = 0;\n  for (code = 0; code < LENGTH_CODES - 1; code++) {\n    base_length[code] = length;\n    for (n = 0; n < (1 << extra_lbits[code]); n++) {\n      _length_code[length++] = code;\n    }\n  }\n  //Assert (length == 256, \"tr_static_init: length != 256\");\n  /* Note that the length 255 (match length 258) can be represented\n   * in two different ways: code 284 + 5 bits or code 285, so we\n   * overwrite length_code[255] to use the best encoding:\n   */\n  _length_code[length - 1] = code;\n\n  /* Initialize the mapping dist (0..32K) -> dist code (0..29) */\n  dist = 0;\n  for (code = 0; code < 16; code++) {\n    base_dist[code] = dist;\n    for (n = 0; n < (1 << extra_dbits[code]); n++) {\n      _dist_code[dist++] = code;\n    }\n  }\n  //Assert (dist == 256, \"tr_static_init: dist != 256\");\n  dist >>= 7; /* from now on, all distances are divided by 128 */\n  for (; code < D_CODES; code++) {\n    base_dist[code] = dist << 7;\n    for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {\n      _dist_code[256 + dist++] = code;\n    }\n  }\n  //Assert (dist == 256, \"tr_static_init: 256+dist != 512\");\n\n  /* Construct the codes of the static literal tree */\n  for (bits = 0; bits <= MAX_BITS; bits++) {\n    bl_count[bits] = 0;\n  }\n\n  n = 0;\n  while (n <= 143) {\n    static_ltree[n * 2 + 1]/*.Len*/ = 8;\n    n++;\n    bl_count[8]++;\n  }\n  while (n <= 255) {\n    static_ltree[n * 2 + 1]/*.Len*/ = 9;\n    n++;\n    bl_count[9]++;\n  }\n  while (n <= 279) {\n    static_ltree[n * 2 + 1]/*.Len*/ = 7;\n    n++;\n    bl_count[7]++;\n  }\n  while (n <= 287) {\n    static_ltree[n * 2 + 1]/*.Len*/ = 8;\n    n++;\n    bl_count[8]++;\n  }\n  /* Codes 286 and 287 do not exist, but we must include them in the\n   * tree construction to get a canonical Huffman tree (longest code\n   * all ones)\n   */\n  gen_codes(static_ltree, L_CODES + 1, bl_count);\n\n  /* The static distance tree is trivial: */\n  for (n = 0; n < D_CODES; n++) {\n    static_dtree[n * 2 + 1]/*.Len*/ = 5;\n    static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5);\n  }\n\n  // Now data ready and we can init static trees\n  static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);\n  static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS);\n  static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0,         BL_CODES, MAX_BL_BITS);\n\n  //static_init_done = true;\n}\n\n\n/* ===========================================================================\n * Initialize a new block.\n */\nfunction init_block(s) {\n  var n; /* iterates over tree elements */\n\n  /* Initialize the trees. */\n  for (n = 0; n < L_CODES;  n++) { s.dyn_ltree[n * 2]/*.Freq*/ = 0; }\n  for (n = 0; n < D_CODES;  n++) { s.dyn_dtree[n * 2]/*.Freq*/ = 0; }\n  for (n = 0; n < BL_CODES; n++) { s.bl_tree[n * 2]/*.Freq*/ = 0; }\n\n  s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1;\n  s.opt_len = s.static_len = 0;\n  s.last_lit = s.matches = 0;\n}\n\n\n/* ===========================================================================\n * Flush the bit buffer and align the output on a byte boundary\n */\nfunction bi_windup(s)\n{\n  if (s.bi_valid > 8) {\n    put_short(s, s.bi_buf);\n  } else if (s.bi_valid > 0) {\n    //put_byte(s, (Byte)s->bi_buf);\n    s.pending_buf[s.pending++] = s.bi_buf;\n  }\n  s.bi_buf = 0;\n  s.bi_valid = 0;\n}\n\n/* ===========================================================================\n * Copy a stored block, storing first the length and its\n * one's complement if requested.\n */\nfunction copy_block(s, buf, len, header)\n//DeflateState *s;\n//charf    *buf;    /* the input data */\n//unsigned len;     /* its length */\n//int      header;  /* true if block header must be written */\n{\n  bi_windup(s);        /* align on byte boundary */\n\n  if (header) {\n    put_short(s, len);\n    put_short(s, ~len);\n  }\n//  while (len--) {\n//    put_byte(s, *buf++);\n//  }\n  utils.arraySet(s.pending_buf, s.window, buf, len, s.pending);\n  s.pending += len;\n}\n\n/* ===========================================================================\n * Compares to subtrees, using the tree depth as tie breaker when\n * the subtrees have equal frequency. This minimizes the worst case length.\n */\nfunction smaller(tree, n, m, depth) {\n  var _n2 = n * 2;\n  var _m2 = m * 2;\n  return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||\n         (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m]));\n}\n\n/* ===========================================================================\n * Restore the heap property by moving down the tree starting at node k,\n * exchanging a node with the smallest of its two sons if necessary, stopping\n * when the heap property is re-established (each father smaller than its\n * two sons).\n */\nfunction pqdownheap(s, tree, k)\n//    deflate_state *s;\n//    ct_data *tree;  /* the tree to restore */\n//    int k;               /* node to move down */\n{\n  var v = s.heap[k];\n  var j = k << 1;  /* left son of k */\n  while (j <= s.heap_len) {\n    /* Set j to the smallest of the two sons: */\n    if (j < s.heap_len &&\n      smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) {\n      j++;\n    }\n    /* Exit if v is smaller than both sons */\n    if (smaller(tree, v, s.heap[j], s.depth)) { break; }\n\n    /* Exchange v with the smallest son */\n    s.heap[k] = s.heap[j];\n    k = j;\n\n    /* And continue down the tree, setting j to the left son of k */\n    j <<= 1;\n  }\n  s.heap[k] = v;\n}\n\n\n// inlined manually\n// var SMALLEST = 1;\n\n/* ===========================================================================\n * Send the block data compressed using the given Huffman trees\n */\nfunction compress_block(s, ltree, dtree)\n//    deflate_state *s;\n//    const ct_data *ltree; /* literal tree */\n//    const ct_data *dtree; /* distance tree */\n{\n  var dist;           /* distance of matched string */\n  var lc;             /* match length or unmatched char (if dist == 0) */\n  var lx = 0;         /* running index in l_buf */\n  var code;           /* the code to send */\n  var extra;          /* number of extra bits to send */\n\n  if (s.last_lit !== 0) {\n    do {\n      dist = (s.pending_buf[s.d_buf + lx * 2] << 8) | (s.pending_buf[s.d_buf + lx * 2 + 1]);\n      lc = s.pending_buf[s.l_buf + lx];\n      lx++;\n\n      if (dist === 0) {\n        send_code(s, lc, ltree); /* send a literal byte */\n        //Tracecv(isgraph(lc), (stderr,\" '%c' \", lc));\n      } else {\n        /* Here, lc is the match length - MIN_MATCH */\n        code = _length_code[lc];\n        send_code(s, code + LITERALS + 1, ltree); /* send the length code */\n        extra = extra_lbits[code];\n        if (extra !== 0) {\n          lc -= base_length[code];\n          send_bits(s, lc, extra);       /* send the extra length bits */\n        }\n        dist--; /* dist is now the match distance - 1 */\n        code = d_code(dist);\n        //Assert (code < D_CODES, \"bad d_code\");\n\n        send_code(s, code, dtree);       /* send the distance code */\n        extra = extra_dbits[code];\n        if (extra !== 0) {\n          dist -= base_dist[code];\n          send_bits(s, dist, extra);   /* send the extra distance bits */\n        }\n      } /* literal or match pair ? */\n\n      /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */\n      //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,\n      //       \"pendingBuf overflow\");\n\n    } while (lx < s.last_lit);\n  }\n\n  send_code(s, END_BLOCK, ltree);\n}\n\n\n/* ===========================================================================\n * Construct one Huffman tree and assigns the code bit strings and lengths.\n * Update the total bit length for the current block.\n * IN assertion: the field freq is set for all tree elements.\n * OUT assertions: the fields len and code are set to the optimal bit length\n *     and corresponding code. The length opt_len is updated; static_len is\n *     also updated if stree is not null. The field max_code is set.\n */\nfunction build_tree(s, desc)\n//    deflate_state *s;\n//    tree_desc *desc; /* the tree descriptor */\n{\n  var tree     = desc.dyn_tree;\n  var stree    = desc.stat_desc.static_tree;\n  var has_stree = desc.stat_desc.has_stree;\n  var elems    = desc.stat_desc.elems;\n  var n, m;          /* iterate over heap elements */\n  var max_code = -1; /* largest code with non zero frequency */\n  var node;          /* new node being created */\n\n  /* Construct the initial heap, with least frequent element in\n   * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].\n   * heap[0] is not used.\n   */\n  s.heap_len = 0;\n  s.heap_max = HEAP_SIZE;\n\n  for (n = 0; n < elems; n++) {\n    if (tree[n * 2]/*.Freq*/ !== 0) {\n      s.heap[++s.heap_len] = max_code = n;\n      s.depth[n] = 0;\n\n    } else {\n      tree[n * 2 + 1]/*.Len*/ = 0;\n    }\n  }\n\n  /* The pkzip format requires that at least one distance code exists,\n   * and that at least one bit should be sent even if there is only one\n   * possible code. So to avoid special checks later on we force at least\n   * two codes of non zero frequency.\n   */\n  while (s.heap_len < 2) {\n    node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);\n    tree[node * 2]/*.Freq*/ = 1;\n    s.depth[node] = 0;\n    s.opt_len--;\n\n    if (has_stree) {\n      s.static_len -= stree[node * 2 + 1]/*.Len*/;\n    }\n    /* node is 0 or 1 so it does not have extra bits */\n  }\n  desc.max_code = max_code;\n\n  /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,\n   * establish sub-heaps of increasing lengths:\n   */\n  for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); }\n\n  /* Construct the Huffman tree by repeatedly combining the least two\n   * frequent nodes.\n   */\n  node = elems;              /* next internal node of the tree */\n  do {\n    //pqremove(s, tree, n);  /* n = node of least frequency */\n    /*** pqremove ***/\n    n = s.heap[1/*SMALLEST*/];\n    s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];\n    pqdownheap(s, tree, 1/*SMALLEST*/);\n    /***/\n\n    m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */\n\n    s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */\n    s.heap[--s.heap_max] = m;\n\n    /* Create a new node father of n and m */\n    tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;\n    s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;\n    tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node;\n\n    /* and insert the new node in the heap */\n    s.heap[1/*SMALLEST*/] = node++;\n    pqdownheap(s, tree, 1/*SMALLEST*/);\n\n  } while (s.heap_len >= 2);\n\n  s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];\n\n  /* At this point, the fields freq and dad are set. We can now\n   * generate the bit lengths.\n   */\n  gen_bitlen(s, desc);\n\n  /* The field len is now set, we can generate the bit codes */\n  gen_codes(tree, max_code, s.bl_count);\n}\n\n\n/* ===========================================================================\n * Scan a literal or distance tree to determine the frequencies of the codes\n * in the bit length tree.\n */\nfunction scan_tree(s, tree, max_code)\n//    deflate_state *s;\n//    ct_data *tree;   /* the tree to be scanned */\n//    int max_code;    /* and its largest code of non zero frequency */\n{\n  var n;                     /* iterates over all tree elements */\n  var prevlen = -1;          /* last emitted length */\n  var curlen;                /* length of current code */\n\n  var nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */\n\n  var count = 0;             /* repeat count of the current code */\n  var max_count = 7;         /* max repeat count */\n  var min_count = 4;         /* min repeat count */\n\n  if (nextlen === 0) {\n    max_count = 138;\n    min_count = 3;\n  }\n  tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */\n\n  for (n = 0; n <= max_code; n++) {\n    curlen = nextlen;\n    nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;\n\n    if (++count < max_count && curlen === nextlen) {\n      continue;\n\n    } else if (count < min_count) {\n      s.bl_tree[curlen * 2]/*.Freq*/ += count;\n\n    } else if (curlen !== 0) {\n\n      if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; }\n      s.bl_tree[REP_3_6 * 2]/*.Freq*/++;\n\n    } else if (count <= 10) {\n      s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++;\n\n    } else {\n      s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++;\n    }\n\n    count = 0;\n    prevlen = curlen;\n\n    if (nextlen === 0) {\n      max_count = 138;\n      min_count = 3;\n\n    } else if (curlen === nextlen) {\n      max_count = 6;\n      min_count = 3;\n\n    } else {\n      max_count = 7;\n      min_count = 4;\n    }\n  }\n}\n\n\n/* ===========================================================================\n * Send a literal or distance tree in compressed form, using the codes in\n * bl_tree.\n */\nfunction send_tree(s, tree, max_code)\n//    deflate_state *s;\n//    ct_data *tree; /* the tree to be scanned */\n//    int max_code;       /* and its largest code of non zero frequency */\n{\n  var n;                     /* iterates over all tree elements */\n  var prevlen = -1;          /* last emitted length */\n  var curlen;                /* length of current code */\n\n  var nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */\n\n  var count = 0;             /* repeat count of the current code */\n  var max_count = 7;         /* max repeat count */\n  var min_count = 4;         /* min repeat count */\n\n  /* tree[max_code+1].Len = -1; */  /* guard already set */\n  if (nextlen === 0) {\n    max_count = 138;\n    min_count = 3;\n  }\n\n  for (n = 0; n <= max_code; n++) {\n    curlen = nextlen;\n    nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;\n\n    if (++count < max_count && curlen === nextlen) {\n      continue;\n\n    } else if (count < min_count) {\n      do { send_code(s, curlen, s.bl_tree); } while (--count !== 0);\n\n    } else if (curlen !== 0) {\n      if (curlen !== prevlen) {\n        send_code(s, curlen, s.bl_tree);\n        count--;\n      }\n      //Assert(count >= 3 && count <= 6, \" 3_6?\");\n      send_code(s, REP_3_6, s.bl_tree);\n      send_bits(s, count - 3, 2);\n\n    } else if (count <= 10) {\n      send_code(s, REPZ_3_10, s.bl_tree);\n      send_bits(s, count - 3, 3);\n\n    } else {\n      send_code(s, REPZ_11_138, s.bl_tree);\n      send_bits(s, count - 11, 7);\n    }\n\n    count = 0;\n    prevlen = curlen;\n    if (nextlen === 0) {\n      max_count = 138;\n      min_count = 3;\n\n    } else if (curlen === nextlen) {\n      max_count = 6;\n      min_count = 3;\n\n    } else {\n      max_count = 7;\n      min_count = 4;\n    }\n  }\n}\n\n\n/* ===========================================================================\n * Construct the Huffman tree for the bit lengths and return the index in\n * bl_order of the last bit length code to send.\n */\nfunction build_bl_tree(s) {\n  var max_blindex;  /* index of last bit length code of non zero freq */\n\n  /* Determine the bit length frequencies for literal and distance trees */\n  scan_tree(s, s.dyn_ltree, s.l_desc.max_code);\n  scan_tree(s, s.dyn_dtree, s.d_desc.max_code);\n\n  /* Build the bit length tree: */\n  build_tree(s, s.bl_desc);\n  /* opt_len now includes the length of the tree representations, except\n   * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.\n   */\n\n  /* Determine the number of bit length codes to send. The pkzip format\n   * requires that at least 4 bit length codes be sent. (appnote.txt says\n   * 3 but the actual value used is 4.)\n   */\n  for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {\n    if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) {\n      break;\n    }\n  }\n  /* Update opt_len to include the bit length tree and counts */\n  s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;\n  //Tracev((stderr, \"\\ndyn trees: dyn %ld, stat %ld\",\n  //        s->opt_len, s->static_len));\n\n  return max_blindex;\n}\n\n\n/* ===========================================================================\n * Send the header for a block using dynamic Huffman trees: the counts, the\n * lengths of the bit length codes, the literal tree and the distance tree.\n * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.\n */\nfunction send_all_trees(s, lcodes, dcodes, blcodes)\n//    deflate_state *s;\n//    int lcodes, dcodes, blcodes; /* number of codes for each tree */\n{\n  var rank;                    /* index in bl_order */\n\n  //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, \"not enough codes\");\n  //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,\n  //        \"too many codes\");\n  //Tracev((stderr, \"\\nbl counts: \"));\n  send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */\n  send_bits(s, dcodes - 1,   5);\n  send_bits(s, blcodes - 4,  4); /* not -3 as stated in appnote.txt */\n  for (rank = 0; rank < blcodes; rank++) {\n    //Tracev((stderr, \"\\nbl code %2d \", bl_order[rank]));\n    send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3);\n  }\n  //Tracev((stderr, \"\\nbl tree: sent %ld\", s->bits_sent));\n\n  send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */\n  //Tracev((stderr, \"\\nlit tree: sent %ld\", s->bits_sent));\n\n  send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */\n  //Tracev((stderr, \"\\ndist tree: sent %ld\", s->bits_sent));\n}\n\n\n/* ===========================================================================\n * Check if the data type is TEXT or BINARY, using the following algorithm:\n * - TEXT if the two conditions below are satisfied:\n *    a) There are no non-portable control characters belonging to the\n *       \"black list\" (0..6, 14..25, 28..31).\n *    b) There is at least one printable character belonging to the\n *       \"white list\" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).\n * - BINARY otherwise.\n * - The following partially-portable control characters form a\n *   \"gray list\" that is ignored in this detection algorithm:\n *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).\n * IN assertion: the fields Freq of dyn_ltree are set.\n */\nfunction detect_data_type(s) {\n  /* black_mask is the bit mask of black-listed bytes\n   * set bits 0..6, 14..25, and 28..31\n   * 0xf3ffc07f = binary 11110011111111111100000001111111\n   */\n  var black_mask = 0xf3ffc07f;\n  var n;\n\n  /* Check for non-textual (\"black-listed\") bytes. */\n  for (n = 0; n <= 31; n++, black_mask >>>= 1) {\n    if ((black_mask & 1) && (s.dyn_ltree[n * 2]/*.Freq*/ !== 0)) {\n      return Z_BINARY;\n    }\n  }\n\n  /* Check for textual (\"white-listed\") bytes. */\n  if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||\n      s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {\n    return Z_TEXT;\n  }\n  for (n = 32; n < LITERALS; n++) {\n    if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {\n      return Z_TEXT;\n    }\n  }\n\n  /* There are no \"black-listed\" or \"white-listed\" bytes:\n   * this stream either is empty or has tolerated (\"gray-listed\") bytes only.\n   */\n  return Z_BINARY;\n}\n\n\nvar static_init_done = false;\n\n/* ===========================================================================\n * Initialize the tree data structures for a new zlib stream.\n */\nfunction _tr_init(s)\n{\n\n  if (!static_init_done) {\n    tr_static_init();\n    static_init_done = true;\n  }\n\n  s.l_desc  = new TreeDesc(s.dyn_ltree, static_l_desc);\n  s.d_desc  = new TreeDesc(s.dyn_dtree, static_d_desc);\n  s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);\n\n  s.bi_buf = 0;\n  s.bi_valid = 0;\n\n  /* Initialize the first block of the first file: */\n  init_block(s);\n}\n\n\n/* ===========================================================================\n * Send a stored block\n */\nfunction _tr_stored_block(s, buf, stored_len, last)\n//DeflateState *s;\n//charf *buf;       /* input block */\n//ulg stored_len;   /* length of input block */\n//int last;         /* one if this is the last block for a file */\n{\n  send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3);    /* send block type */\n  copy_block(s, buf, stored_len, true); /* with header */\n}\n\n\n/* ===========================================================================\n * Send one empty static block to give enough lookahead for inflate.\n * This takes 10 bits, of which 7 may remain in the bit buffer.\n */\nfunction _tr_align(s) {\n  send_bits(s, STATIC_TREES << 1, 3);\n  send_code(s, END_BLOCK, static_ltree);\n  bi_flush(s);\n}\n\n\n/* ===========================================================================\n * Determine the best encoding for the current block: dynamic trees, static\n * trees or store, and output the encoded block to the zip file.\n */\nfunction _tr_flush_block(s, buf, stored_len, last)\n//DeflateState *s;\n//charf *buf;       /* input block, or NULL if too old */\n//ulg stored_len;   /* length of input block */\n//int last;         /* one if this is the last block for a file */\n{\n  var opt_lenb, static_lenb;  /* opt_len and static_len in bytes */\n  var max_blindex = 0;        /* index of last bit length code of non zero freq */\n\n  /* Build the Huffman trees unless a stored block is forced */\n  if (s.level > 0) {\n\n    /* Check if the file is binary or text */\n    if (s.strm.data_type === Z_UNKNOWN) {\n      s.strm.data_type = detect_data_type(s);\n    }\n\n    /* Construct the literal and distance trees */\n    build_tree(s, s.l_desc);\n    // Tracev((stderr, \"\\nlit data: dyn %ld, stat %ld\", s->opt_len,\n    //        s->static_len));\n\n    build_tree(s, s.d_desc);\n    // Tracev((stderr, \"\\ndist data: dyn %ld, stat %ld\", s->opt_len,\n    //        s->static_len));\n    /* At this point, opt_len and static_len are the total bit lengths of\n     * the compressed block data, excluding the tree representations.\n     */\n\n    /* Build the bit length tree for the above two trees, and get the index\n     * in bl_order of the last bit length code to send.\n     */\n    max_blindex = build_bl_tree(s);\n\n    /* Determine the best encoding. Compute the block lengths in bytes. */\n    opt_lenb = (s.opt_len + 3 + 7) >>> 3;\n    static_lenb = (s.static_len + 3 + 7) >>> 3;\n\n    // Tracev((stderr, \"\\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u \",\n    //        opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,\n    //        s->last_lit));\n\n    if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; }\n\n  } else {\n    // Assert(buf != (char*)0, \"lost buf\");\n    opt_lenb = static_lenb = stored_len + 5; /* force a stored block */\n  }\n\n  if ((stored_len + 4 <= opt_lenb) && (buf !== -1)) {\n    /* 4: two words for the lengths */\n\n    /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.\n     * Otherwise we can't have processed more than WSIZE input bytes since\n     * the last block flush, because compression would have been\n     * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to\n     * transform a block into a stored block.\n     */\n    _tr_stored_block(s, buf, stored_len, last);\n\n  } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) {\n\n    send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3);\n    compress_block(s, static_ltree, static_dtree);\n\n  } else {\n    send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3);\n    send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1);\n    compress_block(s, s.dyn_ltree, s.dyn_dtree);\n  }\n  // Assert (s->compressed_len == s->bits_sent, \"bad compressed size\");\n  /* The above check is made mod 2^32, for files larger than 512 MB\n   * and uLong implemented on 32 bits.\n   */\n  init_block(s);\n\n  if (last) {\n    bi_windup(s);\n  }\n  // Tracev((stderr,\"\\ncomprlen %lu(%lu) \", s->compressed_len>>3,\n  //       s->compressed_len-7*last));\n}\n\n/* ===========================================================================\n * Save the match info and tally the frequency counts. Return true if\n * the current block must be flushed.\n */\nfunction _tr_tally(s, dist, lc)\n//    deflate_state *s;\n//    unsigned dist;  /* distance of matched string */\n//    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */\n{\n  //var out_length, in_length, dcode;\n\n  s.pending_buf[s.d_buf + s.last_lit * 2]     = (dist >>> 8) & 0xff;\n  s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff;\n\n  s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff;\n  s.last_lit++;\n\n  if (dist === 0) {\n    /* lc is the unmatched char */\n    s.dyn_ltree[lc * 2]/*.Freq*/++;\n  } else {\n    s.matches++;\n    /* Here, lc is the match length - MIN_MATCH */\n    dist--;             /* dist = match distance - 1 */\n    //Assert((ush)dist < (ush)MAX_DIST(s) &&\n    //       (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&\n    //       (ush)d_code(dist) < (ush)D_CODES,  \"_tr_tally: bad match\");\n\n    s.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]/*.Freq*/++;\n    s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;\n  }\n\n// (!) This block is disabled in zlib defaults,\n// don't enable it for binary compatibility\n\n//#ifdef TRUNCATE_BLOCK\n//  /* Try to guess if it is profitable to stop the current block here */\n//  if ((s.last_lit & 0x1fff) === 0 && s.level > 2) {\n//    /* Compute an upper bound for the compressed length */\n//    out_length = s.last_lit*8;\n//    in_length = s.strstart - s.block_start;\n//\n//    for (dcode = 0; dcode < D_CODES; dcode++) {\n//      out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]);\n//    }\n//    out_length >>>= 3;\n//    //Tracev((stderr,\"\\nlast_lit %u, in %ld, out ~%ld(%ld%%) \",\n//    //       s->last_lit, in_length, out_length,\n//    //       100L - out_length*100L/in_length));\n//    if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) {\n//      return true;\n//    }\n//  }\n//#endif\n\n  return (s.last_lit === s.lit_bufsize - 1);\n  /* We avoid equality with lit_bufsize because of wraparound at 64K\n   * on 16 bit machines and because stored blocks are restricted to\n   * 64K-1 bytes.\n   */\n}\n\nexports._tr_init  = _tr_init;\nexports._tr_stored_block = _tr_stored_block;\nexports._tr_flush_block  = _tr_flush_block;\nexports._tr_tally = _tr_tally;\nexports._tr_align = _tr_align;\n\n\n/***/ }),\n/* 156 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nmodule.exports = {\n  2:      'need dictionary',     /* Z_NEED_DICT       2  */\n  1:      'stream end',          /* Z_STREAM_END      1  */\n  0:      '',                    /* Z_OK              0  */\n  '-1':   'file error',          /* Z_ERRNO         (-1) */\n  '-2':   'stream error',        /* Z_STREAM_ERROR  (-2) */\n  '-3':   'data error',          /* Z_DATA_ERROR    (-3) */\n  '-4':   'insufficient memory', /* Z_MEM_ERROR     (-4) */\n  '-5':   'buffer error',        /* Z_BUF_ERROR     (-5) */\n  '-6':   'incompatible version' /* Z_VERSION_ERROR (-6) */\n};\n\n\n/***/ }),\n/* 157 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nvar utils         = __webpack_require__(34);\nvar adler32       = __webpack_require__(89);\nvar crc32         = __webpack_require__(90);\nvar inflate_fast  = __webpack_require__(158);\nvar inflate_table = __webpack_require__(159);\n\nvar CODES = 0;\nvar LENS = 1;\nvar DISTS = 2;\n\n/* Public constants ==========================================================*/\n/* ===========================================================================*/\n\n\n/* Allowed flush values; see deflate() and inflate() below for details */\n//var Z_NO_FLUSH      = 0;\n//var Z_PARTIAL_FLUSH = 1;\n//var Z_SYNC_FLUSH    = 2;\n//var Z_FULL_FLUSH    = 3;\nvar Z_FINISH        = 4;\nvar Z_BLOCK         = 5;\nvar Z_TREES         = 6;\n\n\n/* Return codes for the compression/decompression functions. Negative values\n * are errors, positive values are used for special but normal events.\n */\nvar Z_OK            = 0;\nvar Z_STREAM_END    = 1;\nvar Z_NEED_DICT     = 2;\n//var Z_ERRNO         = -1;\nvar Z_STREAM_ERROR  = -2;\nvar Z_DATA_ERROR    = -3;\nvar Z_MEM_ERROR     = -4;\nvar Z_BUF_ERROR     = -5;\n//var Z_VERSION_ERROR = -6;\n\n/* The deflate compression method */\nvar Z_DEFLATED  = 8;\n\n\n/* STATES ====================================================================*/\n/* ===========================================================================*/\n\n\nvar    HEAD = 1;       /* i: waiting for magic header */\nvar    FLAGS = 2;      /* i: waiting for method and flags (gzip) */\nvar    TIME = 3;       /* i: waiting for modification time (gzip) */\nvar    OS = 4;         /* i: waiting for extra flags and operating system (gzip) */\nvar    EXLEN = 5;      /* i: waiting for extra length (gzip) */\nvar    EXTRA = 6;      /* i: waiting for extra bytes (gzip) */\nvar    NAME = 7;       /* i: waiting for end of file name (gzip) */\nvar    COMMENT = 8;    /* i: waiting for end of comment (gzip) */\nvar    HCRC = 9;       /* i: waiting for header crc (gzip) */\nvar    DICTID = 10;    /* i: waiting for dictionary check value */\nvar    DICT = 11;      /* waiting for inflateSetDictionary() call */\nvar        TYPE = 12;      /* i: waiting for type bits, including last-flag bit */\nvar        TYPEDO = 13;    /* i: same, but skip check to exit inflate on new block */\nvar        STORED = 14;    /* i: waiting for stored size (length and complement) */\nvar        COPY_ = 15;     /* i/o: same as COPY below, but only first time in */\nvar        COPY = 16;      /* i/o: waiting for input or output to copy stored block */\nvar        TABLE = 17;     /* i: waiting for dynamic block table lengths */\nvar        LENLENS = 18;   /* i: waiting for code length code lengths */\nvar        CODELENS = 19;  /* i: waiting for length/lit and distance code lengths */\nvar            LEN_ = 20;      /* i: same as LEN below, but only first time in */\nvar            LEN = 21;       /* i: waiting for length/lit/eob code */\nvar            LENEXT = 22;    /* i: waiting for length extra bits */\nvar            DIST = 23;      /* i: waiting for distance code */\nvar            DISTEXT = 24;   /* i: waiting for distance extra bits */\nvar            MATCH = 25;     /* o: waiting for output space to copy string */\nvar            LIT = 26;       /* o: waiting for output space to write literal */\nvar    CHECK = 27;     /* i: waiting for 32-bit check value */\nvar    LENGTH = 28;    /* i: waiting for 32-bit length (gzip) */\nvar    DONE = 29;      /* finished check, done -- remain here until reset */\nvar    BAD = 30;       /* got a data error -- remain here until reset */\nvar    MEM = 31;       /* got an inflate() memory error -- remain here until reset */\nvar    SYNC = 32;      /* looking for synchronization bytes to restart inflate() */\n\n/* ===========================================================================*/\n\n\n\nvar ENOUGH_LENS = 852;\nvar ENOUGH_DISTS = 592;\n//var ENOUGH =  (ENOUGH_LENS+ENOUGH_DISTS);\n\nvar MAX_WBITS = 15;\n/* 32K LZ77 window */\nvar DEF_WBITS = MAX_WBITS;\n\n\nfunction zswap32(q) {\n  return  (((q >>> 24) & 0xff) +\n          ((q >>> 8) & 0xff00) +\n          ((q & 0xff00) << 8) +\n          ((q & 0xff) << 24));\n}\n\n\nfunction InflateState() {\n  this.mode = 0;             /* current inflate mode */\n  this.last = false;          /* true if processing last block */\n  this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */\n  this.havedict = false;      /* true if dictionary provided */\n  this.flags = 0;             /* gzip header method and flags (0 if zlib) */\n  this.dmax = 0;              /* zlib header max distance (INFLATE_STRICT) */\n  this.check = 0;             /* protected copy of check value */\n  this.total = 0;             /* protected copy of output count */\n  // TODO: may be {}\n  this.head = null;           /* where to save gzip header information */\n\n  /* sliding window */\n  this.wbits = 0;             /* log base 2 of requested window size */\n  this.wsize = 0;             /* window size or zero if not using window */\n  this.whave = 0;             /* valid bytes in the window */\n  this.wnext = 0;             /* window write index */\n  this.window = null;         /* allocated sliding window, if needed */\n\n  /* bit accumulator */\n  this.hold = 0;              /* input bit accumulator */\n  this.bits = 0;              /* number of bits in \"in\" */\n\n  /* for string and stored block copying */\n  this.length = 0;            /* literal or length of data to copy */\n  this.offset = 0;            /* distance back to copy string from */\n\n  /* for table and code decoding */\n  this.extra = 0;             /* extra bits needed */\n\n  /* fixed and dynamic code tables */\n  this.lencode = null;          /* starting table for length/literal codes */\n  this.distcode = null;         /* starting table for distance codes */\n  this.lenbits = 0;           /* index bits for lencode */\n  this.distbits = 0;          /* index bits for distcode */\n\n  /* dynamic table building */\n  this.ncode = 0;             /* number of code length code lengths */\n  this.nlen = 0;              /* number of length code lengths */\n  this.ndist = 0;             /* number of distance code lengths */\n  this.have = 0;              /* number of code lengths in lens[] */\n  this.next = null;              /* next available space in codes[] */\n\n  this.lens = new utils.Buf16(320); /* temporary storage for code lengths */\n  this.work = new utils.Buf16(288); /* work area for code table building */\n\n  /*\n   because we don't have pointers in js, we use lencode and distcode directly\n   as buffers so we don't need codes\n  */\n  //this.codes = new utils.Buf32(ENOUGH);       /* space for code tables */\n  this.lendyn = null;              /* dynamic table for length/literal codes (JS specific) */\n  this.distdyn = null;             /* dynamic table for distance codes (JS specific) */\n  this.sane = 0;                   /* if false, allow invalid distance too far */\n  this.back = 0;                   /* bits back of last unprocessed length/lit */\n  this.was = 0;                    /* initial length of match */\n}\n\nfunction inflateResetKeep(strm) {\n  var state;\n\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n  strm.total_in = strm.total_out = state.total = 0;\n  strm.msg = ''; /*Z_NULL*/\n  if (state.wrap) {       /* to support ill-conceived Java test suite */\n    strm.adler = state.wrap & 1;\n  }\n  state.mode = HEAD;\n  state.last = 0;\n  state.havedict = 0;\n  state.dmax = 32768;\n  state.head = null/*Z_NULL*/;\n  state.hold = 0;\n  state.bits = 0;\n  //state.lencode = state.distcode = state.next = state.codes;\n  state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS);\n  state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS);\n\n  state.sane = 1;\n  state.back = -1;\n  //Tracev((stderr, \"inflate: reset\\n\"));\n  return Z_OK;\n}\n\nfunction inflateReset(strm) {\n  var state;\n\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n  state.wsize = 0;\n  state.whave = 0;\n  state.wnext = 0;\n  return inflateResetKeep(strm);\n\n}\n\nfunction inflateReset2(strm, windowBits) {\n  var wrap;\n  var state;\n\n  /* get the state */\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n\n  /* extract wrap request from windowBits parameter */\n  if (windowBits < 0) {\n    wrap = 0;\n    windowBits = -windowBits;\n  }\n  else {\n    wrap = (windowBits >> 4) + 1;\n    if (windowBits < 48) {\n      windowBits &= 15;\n    }\n  }\n\n  /* set number of window bits, free window if different */\n  if (windowBits && (windowBits < 8 || windowBits > 15)) {\n    return Z_STREAM_ERROR;\n  }\n  if (state.window !== null && state.wbits !== windowBits) {\n    state.window = null;\n  }\n\n  /* update state and reset the rest of it */\n  state.wrap = wrap;\n  state.wbits = windowBits;\n  return inflateReset(strm);\n}\n\nfunction inflateInit2(strm, windowBits) {\n  var ret;\n  var state;\n\n  if (!strm) { return Z_STREAM_ERROR; }\n  //strm.msg = Z_NULL;                 /* in case we return an error */\n\n  state = new InflateState();\n\n  //if (state === Z_NULL) return Z_MEM_ERROR;\n  //Tracev((stderr, \"inflate: allocated\\n\"));\n  strm.state = state;\n  state.window = null/*Z_NULL*/;\n  ret = inflateReset2(strm, windowBits);\n  if (ret !== Z_OK) {\n    strm.state = null/*Z_NULL*/;\n  }\n  return ret;\n}\n\nfunction inflateInit(strm) {\n  return inflateInit2(strm, DEF_WBITS);\n}\n\n\n/*\n Return state with length and distance decoding tables and index sizes set to\n fixed code decoding.  Normally this returns fixed tables from inffixed.h.\n If BUILDFIXED is defined, then instead this routine builds the tables the\n first time it's called, and returns those tables the first time and\n thereafter.  This reduces the size of the code by about 2K bytes, in\n exchange for a little execution time.  However, BUILDFIXED should not be\n used for threaded applications, since the rewriting of the tables and virgin\n may not be thread-safe.\n */\nvar virgin = true;\n\nvar lenfix, distfix; // We have no pointers in JS, so keep tables separate\n\nfunction fixedtables(state) {\n  /* build fixed huffman tables if first call (may not be thread safe) */\n  if (virgin) {\n    var sym;\n\n    lenfix = new utils.Buf32(512);\n    distfix = new utils.Buf32(32);\n\n    /* literal/length table */\n    sym = 0;\n    while (sym < 144) { state.lens[sym++] = 8; }\n    while (sym < 256) { state.lens[sym++] = 9; }\n    while (sym < 280) { state.lens[sym++] = 7; }\n    while (sym < 288) { state.lens[sym++] = 8; }\n\n    inflate_table(LENS,  state.lens, 0, 288, lenfix,   0, state.work, { bits: 9 });\n\n    /* distance table */\n    sym = 0;\n    while (sym < 32) { state.lens[sym++] = 5; }\n\n    inflate_table(DISTS, state.lens, 0, 32,   distfix, 0, state.work, { bits: 5 });\n\n    /* do this just once */\n    virgin = false;\n  }\n\n  state.lencode = lenfix;\n  state.lenbits = 9;\n  state.distcode = distfix;\n  state.distbits = 5;\n}\n\n\n/*\n Update the window with the last wsize (normally 32K) bytes written before\n returning.  If window does not exist yet, create it.  This is only called\n when a window is already in use, or when output has been written during this\n inflate call, but the end of the deflate stream has not been reached yet.\n It is also called to create a window for dictionary data when a dictionary\n is loaded.\n\n Providing output buffers larger than 32K to inflate() should provide a speed\n advantage, since only the last 32K of output is copied to the sliding window\n upon return from inflate(), and since all distances after the first 32K of\n output will fall in the output data, making match copies simpler and faster.\n The advantage may be dependent on the size of the processor's data caches.\n */\nfunction updatewindow(strm, src, end, copy) {\n  var dist;\n  var state = strm.state;\n\n  /* if it hasn't been done already, allocate space for the window */\n  if (state.window === null) {\n    state.wsize = 1 << state.wbits;\n    state.wnext = 0;\n    state.whave = 0;\n\n    state.window = new utils.Buf8(state.wsize);\n  }\n\n  /* copy state->wsize or less output bytes into the circular window */\n  if (copy >= state.wsize) {\n    utils.arraySet(state.window, src, end - state.wsize, state.wsize, 0);\n    state.wnext = 0;\n    state.whave = state.wsize;\n  }\n  else {\n    dist = state.wsize - state.wnext;\n    if (dist > copy) {\n      dist = copy;\n    }\n    //zmemcpy(state->window + state->wnext, end - copy, dist);\n    utils.arraySet(state.window, src, end - copy, dist, state.wnext);\n    copy -= dist;\n    if (copy) {\n      //zmemcpy(state->window, end - copy, copy);\n      utils.arraySet(state.window, src, end - copy, copy, 0);\n      state.wnext = copy;\n      state.whave = state.wsize;\n    }\n    else {\n      state.wnext += dist;\n      if (state.wnext === state.wsize) { state.wnext = 0; }\n      if (state.whave < state.wsize) { state.whave += dist; }\n    }\n  }\n  return 0;\n}\n\nfunction inflate(strm, flush) {\n  var state;\n  var input, output;          // input/output buffers\n  var next;                   /* next input INDEX */\n  var put;                    /* next output INDEX */\n  var have, left;             /* available input and output */\n  var hold;                   /* bit buffer */\n  var bits;                   /* bits in bit buffer */\n  var _in, _out;              /* save starting available input and output */\n  var copy;                   /* number of stored or match bytes to copy */\n  var from;                   /* where to copy match bytes from */\n  var from_source;\n  var here = 0;               /* current decoding table entry */\n  var here_bits, here_op, here_val; // paked \"here\" denormalized (JS specific)\n  //var last;                   /* parent table entry */\n  var last_bits, last_op, last_val; // paked \"last\" denormalized (JS specific)\n  var len;                    /* length to copy for repeats, bits to drop */\n  var ret;                    /* return code */\n  var hbuf = new utils.Buf8(4);    /* buffer for gzip header crc calculation */\n  var opts;\n\n  var n; // temporary var for NEED_BITS\n\n  var order = /* permutation of code lengths */\n    [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];\n\n\n  if (!strm || !strm.state || !strm.output ||\n      (!strm.input && strm.avail_in !== 0)) {\n    return Z_STREAM_ERROR;\n  }\n\n  state = strm.state;\n  if (state.mode === TYPE) { state.mode = TYPEDO; }    /* skip check */\n\n\n  //--- LOAD() ---\n  put = strm.next_out;\n  output = strm.output;\n  left = strm.avail_out;\n  next = strm.next_in;\n  input = strm.input;\n  have = strm.avail_in;\n  hold = state.hold;\n  bits = state.bits;\n  //---\n\n  _in = have;\n  _out = left;\n  ret = Z_OK;\n\n  inf_leave: // goto emulation\n  for (;;) {\n    switch (state.mode) {\n      case HEAD:\n        if (state.wrap === 0) {\n          state.mode = TYPEDO;\n          break;\n        }\n        //=== NEEDBITS(16);\n        while (bits < 16) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        if ((state.wrap & 2) && hold === 0x8b1f) {  /* gzip header */\n          state.check = 0/*crc32(0L, Z_NULL, 0)*/;\n          //=== CRC2(state.check, hold);\n          hbuf[0] = hold & 0xff;\n          hbuf[1] = (hold >>> 8) & 0xff;\n          state.check = crc32(state.check, hbuf, 2, 0);\n          //===//\n\n          //=== INITBITS();\n          hold = 0;\n          bits = 0;\n          //===//\n          state.mode = FLAGS;\n          break;\n        }\n        state.flags = 0;           /* expect zlib header */\n        if (state.head) {\n          state.head.done = false;\n        }\n        if (!(state.wrap & 1) ||   /* check if zlib header allowed */\n          (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {\n          strm.msg = 'incorrect header check';\n          state.mode = BAD;\n          break;\n        }\n        if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {\n          strm.msg = 'unknown compression method';\n          state.mode = BAD;\n          break;\n        }\n        //--- DROPBITS(4) ---//\n        hold >>>= 4;\n        bits -= 4;\n        //---//\n        len = (hold & 0x0f)/*BITS(4)*/ + 8;\n        if (state.wbits === 0) {\n          state.wbits = len;\n        }\n        else if (len > state.wbits) {\n          strm.msg = 'invalid window size';\n          state.mode = BAD;\n          break;\n        }\n        state.dmax = 1 << len;\n        //Tracev((stderr, \"inflate:   zlib header ok\\n\"));\n        strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;\n        state.mode = hold & 0x200 ? DICTID : TYPE;\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        break;\n      case FLAGS:\n        //=== NEEDBITS(16); */\n        while (bits < 16) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        state.flags = hold;\n        if ((state.flags & 0xff) !== Z_DEFLATED) {\n          strm.msg = 'unknown compression method';\n          state.mode = BAD;\n          break;\n        }\n        if (state.flags & 0xe000) {\n          strm.msg = 'unknown header flags set';\n          state.mode = BAD;\n          break;\n        }\n        if (state.head) {\n          state.head.text = ((hold >> 8) & 1);\n        }\n        if (state.flags & 0x0200) {\n          //=== CRC2(state.check, hold);\n          hbuf[0] = hold & 0xff;\n          hbuf[1] = (hold >>> 8) & 0xff;\n          state.check = crc32(state.check, hbuf, 2, 0);\n          //===//\n        }\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        state.mode = TIME;\n        /* falls through */\n      case TIME:\n        //=== NEEDBITS(32); */\n        while (bits < 32) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        if (state.head) {\n          state.head.time = hold;\n        }\n        if (state.flags & 0x0200) {\n          //=== CRC4(state.check, hold)\n          hbuf[0] = hold & 0xff;\n          hbuf[1] = (hold >>> 8) & 0xff;\n          hbuf[2] = (hold >>> 16) & 0xff;\n          hbuf[3] = (hold >>> 24) & 0xff;\n          state.check = crc32(state.check, hbuf, 4, 0);\n          //===\n        }\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        state.mode = OS;\n        /* falls through */\n      case OS:\n        //=== NEEDBITS(16); */\n        while (bits < 16) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        if (state.head) {\n          state.head.xflags = (hold & 0xff);\n          state.head.os = (hold >> 8);\n        }\n        if (state.flags & 0x0200) {\n          //=== CRC2(state.check, hold);\n          hbuf[0] = hold & 0xff;\n          hbuf[1] = (hold >>> 8) & 0xff;\n          state.check = crc32(state.check, hbuf, 2, 0);\n          //===//\n        }\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        state.mode = EXLEN;\n        /* falls through */\n      case EXLEN:\n        if (state.flags & 0x0400) {\n          //=== NEEDBITS(16); */\n          while (bits < 16) {\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n          }\n          //===//\n          state.length = hold;\n          if (state.head) {\n            state.head.extra_len = hold;\n          }\n          if (state.flags & 0x0200) {\n            //=== CRC2(state.check, hold);\n            hbuf[0] = hold & 0xff;\n            hbuf[1] = (hold >>> 8) & 0xff;\n            state.check = crc32(state.check, hbuf, 2, 0);\n            //===//\n          }\n          //=== INITBITS();\n          hold = 0;\n          bits = 0;\n          //===//\n        }\n        else if (state.head) {\n          state.head.extra = null/*Z_NULL*/;\n        }\n        state.mode = EXTRA;\n        /* falls through */\n      case EXTRA:\n        if (state.flags & 0x0400) {\n          copy = state.length;\n          if (copy > have) { copy = have; }\n          if (copy) {\n            if (state.head) {\n              len = state.head.extra_len - state.length;\n              if (!state.head.extra) {\n                // Use untyped array for more convenient processing later\n                state.head.extra = new Array(state.head.extra_len);\n              }\n              utils.arraySet(\n                state.head.extra,\n                input,\n                next,\n                // extra field is limited to 65536 bytes\n                // - no need for additional size check\n                copy,\n                /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/\n                len\n              );\n              //zmemcpy(state.head.extra + len, next,\n              //        len + copy > state.head.extra_max ?\n              //        state.head.extra_max - len : copy);\n            }\n            if (state.flags & 0x0200) {\n              state.check = crc32(state.check, input, copy, next);\n            }\n            have -= copy;\n            next += copy;\n            state.length -= copy;\n          }\n          if (state.length) { break inf_leave; }\n        }\n        state.length = 0;\n        state.mode = NAME;\n        /* falls through */\n      case NAME:\n        if (state.flags & 0x0800) {\n          if (have === 0) { break inf_leave; }\n          copy = 0;\n          do {\n            // TODO: 2 or 1 bytes?\n            len = input[next + copy++];\n            /* use constant limit because in js we should not preallocate memory */\n            if (state.head && len &&\n                (state.length < 65536 /*state.head.name_max*/)) {\n              state.head.name += String.fromCharCode(len);\n            }\n          } while (len && copy < have);\n\n          if (state.flags & 0x0200) {\n            state.check = crc32(state.check, input, copy, next);\n          }\n          have -= copy;\n          next += copy;\n          if (len) { break inf_leave; }\n        }\n        else if (state.head) {\n          state.head.name = null;\n        }\n        state.length = 0;\n        state.mode = COMMENT;\n        /* falls through */\n      case COMMENT:\n        if (state.flags & 0x1000) {\n          if (have === 0) { break inf_leave; }\n          copy = 0;\n          do {\n            len = input[next + copy++];\n            /* use constant limit because in js we should not preallocate memory */\n            if (state.head && len &&\n                (state.length < 65536 /*state.head.comm_max*/)) {\n              state.head.comment += String.fromCharCode(len);\n            }\n          } while (len && copy < have);\n          if (state.flags & 0x0200) {\n            state.check = crc32(state.check, input, copy, next);\n          }\n          have -= copy;\n          next += copy;\n          if (len) { break inf_leave; }\n        }\n        else if (state.head) {\n          state.head.comment = null;\n        }\n        state.mode = HCRC;\n        /* falls through */\n      case HCRC:\n        if (state.flags & 0x0200) {\n          //=== NEEDBITS(16); */\n          while (bits < 16) {\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n          }\n          //===//\n          if (hold !== (state.check & 0xffff)) {\n            strm.msg = 'header crc mismatch';\n            state.mode = BAD;\n            break;\n          }\n          //=== INITBITS();\n          hold = 0;\n          bits = 0;\n          //===//\n        }\n        if (state.head) {\n          state.head.hcrc = ((state.flags >> 9) & 1);\n          state.head.done = true;\n        }\n        strm.adler = state.check = 0;\n        state.mode = TYPE;\n        break;\n      case DICTID:\n        //=== NEEDBITS(32); */\n        while (bits < 32) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        strm.adler = state.check = zswap32(hold);\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        state.mode = DICT;\n        /* falls through */\n      case DICT:\n        if (state.havedict === 0) {\n          //--- RESTORE() ---\n          strm.next_out = put;\n          strm.avail_out = left;\n          strm.next_in = next;\n          strm.avail_in = have;\n          state.hold = hold;\n          state.bits = bits;\n          //---\n          return Z_NEED_DICT;\n        }\n        strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;\n        state.mode = TYPE;\n        /* falls through */\n      case TYPE:\n        if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }\n        /* falls through */\n      case TYPEDO:\n        if (state.last) {\n          //--- BYTEBITS() ---//\n          hold >>>= bits & 7;\n          bits -= bits & 7;\n          //---//\n          state.mode = CHECK;\n          break;\n        }\n        //=== NEEDBITS(3); */\n        while (bits < 3) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        state.last = (hold & 0x01)/*BITS(1)*/;\n        //--- DROPBITS(1) ---//\n        hold >>>= 1;\n        bits -= 1;\n        //---//\n\n        switch ((hold & 0x03)/*BITS(2)*/) {\n          case 0:                             /* stored block */\n            //Tracev((stderr, \"inflate:     stored block%s\\n\",\n            //        state.last ? \" (last)\" : \"\"));\n            state.mode = STORED;\n            break;\n          case 1:                             /* fixed block */\n            fixedtables(state);\n            //Tracev((stderr, \"inflate:     fixed codes block%s\\n\",\n            //        state.last ? \" (last)\" : \"\"));\n            state.mode = LEN_;             /* decode codes */\n            if (flush === Z_TREES) {\n              //--- DROPBITS(2) ---//\n              hold >>>= 2;\n              bits -= 2;\n              //---//\n              break inf_leave;\n            }\n            break;\n          case 2:                             /* dynamic block */\n            //Tracev((stderr, \"inflate:     dynamic codes block%s\\n\",\n            //        state.last ? \" (last)\" : \"\"));\n            state.mode = TABLE;\n            break;\n          case 3:\n            strm.msg = 'invalid block type';\n            state.mode = BAD;\n        }\n        //--- DROPBITS(2) ---//\n        hold >>>= 2;\n        bits -= 2;\n        //---//\n        break;\n      case STORED:\n        //--- BYTEBITS() ---// /* go to byte boundary */\n        hold >>>= bits & 7;\n        bits -= bits & 7;\n        //---//\n        //=== NEEDBITS(32); */\n        while (bits < 32) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {\n          strm.msg = 'invalid stored block lengths';\n          state.mode = BAD;\n          break;\n        }\n        state.length = hold & 0xffff;\n        //Tracev((stderr, \"inflate:       stored length %u\\n\",\n        //        state.length));\n        //=== INITBITS();\n        hold = 0;\n        bits = 0;\n        //===//\n        state.mode = COPY_;\n        if (flush === Z_TREES) { break inf_leave; }\n        /* falls through */\n      case COPY_:\n        state.mode = COPY;\n        /* falls through */\n      case COPY:\n        copy = state.length;\n        if (copy) {\n          if (copy > have) { copy = have; }\n          if (copy > left) { copy = left; }\n          if (copy === 0) { break inf_leave; }\n          //--- zmemcpy(put, next, copy); ---\n          utils.arraySet(output, input, next, copy, put);\n          //---//\n          have -= copy;\n          next += copy;\n          left -= copy;\n          put += copy;\n          state.length -= copy;\n          break;\n        }\n        //Tracev((stderr, \"inflate:       stored end\\n\"));\n        state.mode = TYPE;\n        break;\n      case TABLE:\n        //=== NEEDBITS(14); */\n        while (bits < 14) {\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n        }\n        //===//\n        state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;\n        //--- DROPBITS(5) ---//\n        hold >>>= 5;\n        bits -= 5;\n        //---//\n        state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;\n        //--- DROPBITS(5) ---//\n        hold >>>= 5;\n        bits -= 5;\n        //---//\n        state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;\n        //--- DROPBITS(4) ---//\n        hold >>>= 4;\n        bits -= 4;\n        //---//\n//#ifndef PKZIP_BUG_WORKAROUND\n        if (state.nlen > 286 || state.ndist > 30) {\n          strm.msg = 'too many length or distance symbols';\n          state.mode = BAD;\n          break;\n        }\n//#endif\n        //Tracev((stderr, \"inflate:       table sizes ok\\n\"));\n        state.have = 0;\n        state.mode = LENLENS;\n        /* falls through */\n      case LENLENS:\n        while (state.have < state.ncode) {\n          //=== NEEDBITS(3);\n          while (bits < 3) {\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n          }\n          //===//\n          state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);\n          //--- DROPBITS(3) ---//\n          hold >>>= 3;\n          bits -= 3;\n          //---//\n        }\n        while (state.have < 19) {\n          state.lens[order[state.have++]] = 0;\n        }\n        // We have separate tables & no pointers. 2 commented lines below not needed.\n        //state.next = state.codes;\n        //state.lencode = state.next;\n        // Switch to use dynamic table\n        state.lencode = state.lendyn;\n        state.lenbits = 7;\n\n        opts = { bits: state.lenbits };\n        ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);\n        state.lenbits = opts.bits;\n\n        if (ret) {\n          strm.msg = 'invalid code lengths set';\n          state.mode = BAD;\n          break;\n        }\n        //Tracev((stderr, \"inflate:       code lengths ok\\n\"));\n        state.have = 0;\n        state.mode = CODELENS;\n        /* falls through */\n      case CODELENS:\n        while (state.have < state.nlen + state.ndist) {\n          for (;;) {\n            here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/\n            here_bits = here >>> 24;\n            here_op = (here >>> 16) & 0xff;\n            here_val = here & 0xffff;\n\n            if ((here_bits) <= bits) { break; }\n            //--- PULLBYTE() ---//\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n            //---//\n          }\n          if (here_val < 16) {\n            //--- DROPBITS(here.bits) ---//\n            hold >>>= here_bits;\n            bits -= here_bits;\n            //---//\n            state.lens[state.have++] = here_val;\n          }\n          else {\n            if (here_val === 16) {\n              //=== NEEDBITS(here.bits + 2);\n              n = here_bits + 2;\n              while (bits < n) {\n                if (have === 0) { break inf_leave; }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              //===//\n              //--- DROPBITS(here.bits) ---//\n              hold >>>= here_bits;\n              bits -= here_bits;\n              //---//\n              if (state.have === 0) {\n                strm.msg = 'invalid bit length repeat';\n                state.mode = BAD;\n                break;\n              }\n              len = state.lens[state.have - 1];\n              copy = 3 + (hold & 0x03);//BITS(2);\n              //--- DROPBITS(2) ---//\n              hold >>>= 2;\n              bits -= 2;\n              //---//\n            }\n            else if (here_val === 17) {\n              //=== NEEDBITS(here.bits + 3);\n              n = here_bits + 3;\n              while (bits < n) {\n                if (have === 0) { break inf_leave; }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              //===//\n              //--- DROPBITS(here.bits) ---//\n              hold >>>= here_bits;\n              bits -= here_bits;\n              //---//\n              len = 0;\n              copy = 3 + (hold & 0x07);//BITS(3);\n              //--- DROPBITS(3) ---//\n              hold >>>= 3;\n              bits -= 3;\n              //---//\n            }\n            else {\n              //=== NEEDBITS(here.bits + 7);\n              n = here_bits + 7;\n              while (bits < n) {\n                if (have === 0) { break inf_leave; }\n                have--;\n                hold += input[next++] << bits;\n                bits += 8;\n              }\n              //===//\n              //--- DROPBITS(here.bits) ---//\n              hold >>>= here_bits;\n              bits -= here_bits;\n              //---//\n              len = 0;\n              copy = 11 + (hold & 0x7f);//BITS(7);\n              //--- DROPBITS(7) ---//\n              hold >>>= 7;\n              bits -= 7;\n              //---//\n            }\n            if (state.have + copy > state.nlen + state.ndist) {\n              strm.msg = 'invalid bit length repeat';\n              state.mode = BAD;\n              break;\n            }\n            while (copy--) {\n              state.lens[state.have++] = len;\n            }\n          }\n        }\n\n        /* handle error breaks in while */\n        if (state.mode === BAD) { break; }\n\n        /* check for end-of-block code (better have one) */\n        if (state.lens[256] === 0) {\n          strm.msg = 'invalid code -- missing end-of-block';\n          state.mode = BAD;\n          break;\n        }\n\n        /* build code tables -- note: do not change the lenbits or distbits\n           values here (9 and 6) without reading the comments in inftrees.h\n           concerning the ENOUGH constants, which depend on those values */\n        state.lenbits = 9;\n\n        opts = { bits: state.lenbits };\n        ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);\n        // We have separate tables & no pointers. 2 commented lines below not needed.\n        // state.next_index = opts.table_index;\n        state.lenbits = opts.bits;\n        // state.lencode = state.next;\n\n        if (ret) {\n          strm.msg = 'invalid literal/lengths set';\n          state.mode = BAD;\n          break;\n        }\n\n        state.distbits = 6;\n        //state.distcode.copy(state.codes);\n        // Switch to use dynamic table\n        state.distcode = state.distdyn;\n        opts = { bits: state.distbits };\n        ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);\n        // We have separate tables & no pointers. 2 commented lines below not needed.\n        // state.next_index = opts.table_index;\n        state.distbits = opts.bits;\n        // state.distcode = state.next;\n\n        if (ret) {\n          strm.msg = 'invalid distances set';\n          state.mode = BAD;\n          break;\n        }\n        //Tracev((stderr, 'inflate:       codes ok\\n'));\n        state.mode = LEN_;\n        if (flush === Z_TREES) { break inf_leave; }\n        /* falls through */\n      case LEN_:\n        state.mode = LEN;\n        /* falls through */\n      case LEN:\n        if (have >= 6 && left >= 258) {\n          //--- RESTORE() ---\n          strm.next_out = put;\n          strm.avail_out = left;\n          strm.next_in = next;\n          strm.avail_in = have;\n          state.hold = hold;\n          state.bits = bits;\n          //---\n          inflate_fast(strm, _out);\n          //--- LOAD() ---\n          put = strm.next_out;\n          output = strm.output;\n          left = strm.avail_out;\n          next = strm.next_in;\n          input = strm.input;\n          have = strm.avail_in;\n          hold = state.hold;\n          bits = state.bits;\n          //---\n\n          if (state.mode === TYPE) {\n            state.back = -1;\n          }\n          break;\n        }\n        state.back = 0;\n        for (;;) {\n          here = state.lencode[hold & ((1 << state.lenbits) - 1)];  /*BITS(state.lenbits)*/\n          here_bits = here >>> 24;\n          here_op = (here >>> 16) & 0xff;\n          here_val = here & 0xffff;\n\n          if (here_bits <= bits) { break; }\n          //--- PULLBYTE() ---//\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n          //---//\n        }\n        if (here_op && (here_op & 0xf0) === 0) {\n          last_bits = here_bits;\n          last_op = here_op;\n          last_val = here_val;\n          for (;;) {\n            here = state.lencode[last_val +\n                    ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];\n            here_bits = here >>> 24;\n            here_op = (here >>> 16) & 0xff;\n            here_val = here & 0xffff;\n\n            if ((last_bits + here_bits) <= bits) { break; }\n            //--- PULLBYTE() ---//\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n            //---//\n          }\n          //--- DROPBITS(last.bits) ---//\n          hold >>>= last_bits;\n          bits -= last_bits;\n          //---//\n          state.back += last_bits;\n        }\n        //--- DROPBITS(here.bits) ---//\n        hold >>>= here_bits;\n        bits -= here_bits;\n        //---//\n        state.back += here_bits;\n        state.length = here_val;\n        if (here_op === 0) {\n          //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?\n          //        \"inflate:         literal '%c'\\n\" :\n          //        \"inflate:         literal 0x%02x\\n\", here.val));\n          state.mode = LIT;\n          break;\n        }\n        if (here_op & 32) {\n          //Tracevv((stderr, \"inflate:         end of block\\n\"));\n          state.back = -1;\n          state.mode = TYPE;\n          break;\n        }\n        if (here_op & 64) {\n          strm.msg = 'invalid literal/length code';\n          state.mode = BAD;\n          break;\n        }\n        state.extra = here_op & 15;\n        state.mode = LENEXT;\n        /* falls through */\n      case LENEXT:\n        if (state.extra) {\n          //=== NEEDBITS(state.extra);\n          n = state.extra;\n          while (bits < n) {\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n          }\n          //===//\n          state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;\n          //--- DROPBITS(state.extra) ---//\n          hold >>>= state.extra;\n          bits -= state.extra;\n          //---//\n          state.back += state.extra;\n        }\n        //Tracevv((stderr, \"inflate:         length %u\\n\", state.length));\n        state.was = state.length;\n        state.mode = DIST;\n        /* falls through */\n      case DIST:\n        for (;;) {\n          here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/\n          here_bits = here >>> 24;\n          here_op = (here >>> 16) & 0xff;\n          here_val = here & 0xffff;\n\n          if ((here_bits) <= bits) { break; }\n          //--- PULLBYTE() ---//\n          if (have === 0) { break inf_leave; }\n          have--;\n          hold += input[next++] << bits;\n          bits += 8;\n          //---//\n        }\n        if ((here_op & 0xf0) === 0) {\n          last_bits = here_bits;\n          last_op = here_op;\n          last_val = here_val;\n          for (;;) {\n            here = state.distcode[last_val +\n                    ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];\n            here_bits = here >>> 24;\n            here_op = (here >>> 16) & 0xff;\n            here_val = here & 0xffff;\n\n            if ((last_bits + here_bits) <= bits) { break; }\n            //--- PULLBYTE() ---//\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n            //---//\n          }\n          //--- DROPBITS(last.bits) ---//\n          hold >>>= last_bits;\n          bits -= last_bits;\n          //---//\n          state.back += last_bits;\n        }\n        //--- DROPBITS(here.bits) ---//\n        hold >>>= here_bits;\n        bits -= here_bits;\n        //---//\n        state.back += here_bits;\n        if (here_op & 64) {\n          strm.msg = 'invalid distance code';\n          state.mode = BAD;\n          break;\n        }\n        state.offset = here_val;\n        state.extra = (here_op) & 15;\n        state.mode = DISTEXT;\n        /* falls through */\n      case DISTEXT:\n        if (state.extra) {\n          //=== NEEDBITS(state.extra);\n          n = state.extra;\n          while (bits < n) {\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n          }\n          //===//\n          state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;\n          //--- DROPBITS(state.extra) ---//\n          hold >>>= state.extra;\n          bits -= state.extra;\n          //---//\n          state.back += state.extra;\n        }\n//#ifdef INFLATE_STRICT\n        if (state.offset > state.dmax) {\n          strm.msg = 'invalid distance too far back';\n          state.mode = BAD;\n          break;\n        }\n//#endif\n        //Tracevv((stderr, \"inflate:         distance %u\\n\", state.offset));\n        state.mode = MATCH;\n        /* falls through */\n      case MATCH:\n        if (left === 0) { break inf_leave; }\n        copy = _out - left;\n        if (state.offset > copy) {         /* copy from window */\n          copy = state.offset - copy;\n          if (copy > state.whave) {\n            if (state.sane) {\n              strm.msg = 'invalid distance too far back';\n              state.mode = BAD;\n              break;\n            }\n// (!) This block is disabled in zlib defaults,\n// don't enable it for binary compatibility\n//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR\n//          Trace((stderr, \"inflate.c too far\\n\"));\n//          copy -= state.whave;\n//          if (copy > state.length) { copy = state.length; }\n//          if (copy > left) { copy = left; }\n//          left -= copy;\n//          state.length -= copy;\n//          do {\n//            output[put++] = 0;\n//          } while (--copy);\n//          if (state.length === 0) { state.mode = LEN; }\n//          break;\n//#endif\n          }\n          if (copy > state.wnext) {\n            copy -= state.wnext;\n            from = state.wsize - copy;\n          }\n          else {\n            from = state.wnext - copy;\n          }\n          if (copy > state.length) { copy = state.length; }\n          from_source = state.window;\n        }\n        else {                              /* copy from output */\n          from_source = output;\n          from = put - state.offset;\n          copy = state.length;\n        }\n        if (copy > left) { copy = left; }\n        left -= copy;\n        state.length -= copy;\n        do {\n          output[put++] = from_source[from++];\n        } while (--copy);\n        if (state.length === 0) { state.mode = LEN; }\n        break;\n      case LIT:\n        if (left === 0) { break inf_leave; }\n        output[put++] = state.length;\n        left--;\n        state.mode = LEN;\n        break;\n      case CHECK:\n        if (state.wrap) {\n          //=== NEEDBITS(32);\n          while (bits < 32) {\n            if (have === 0) { break inf_leave; }\n            have--;\n            // Use '|' instead of '+' to make sure that result is signed\n            hold |= input[next++] << bits;\n            bits += 8;\n          }\n          //===//\n          _out -= left;\n          strm.total_out += _out;\n          state.total += _out;\n          if (_out) {\n            strm.adler = state.check =\n                /*UPDATE(state.check, put - _out, _out);*/\n                (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out));\n\n          }\n          _out = left;\n          // NB: crc32 stored as signed 32-bit int, zswap32 returns signed too\n          if ((state.flags ? hold : zswap32(hold)) !== state.check) {\n            strm.msg = 'incorrect data check';\n            state.mode = BAD;\n            break;\n          }\n          //=== INITBITS();\n          hold = 0;\n          bits = 0;\n          //===//\n          //Tracev((stderr, \"inflate:   check matches trailer\\n\"));\n        }\n        state.mode = LENGTH;\n        /* falls through */\n      case LENGTH:\n        if (state.wrap && state.flags) {\n          //=== NEEDBITS(32);\n          while (bits < 32) {\n            if (have === 0) { break inf_leave; }\n            have--;\n            hold += input[next++] << bits;\n            bits += 8;\n          }\n          //===//\n          if (hold !== (state.total & 0xffffffff)) {\n            strm.msg = 'incorrect length check';\n            state.mode = BAD;\n            break;\n          }\n          //=== INITBITS();\n          hold = 0;\n          bits = 0;\n          //===//\n          //Tracev((stderr, \"inflate:   length matches trailer\\n\"));\n        }\n        state.mode = DONE;\n        /* falls through */\n      case DONE:\n        ret = Z_STREAM_END;\n        break inf_leave;\n      case BAD:\n        ret = Z_DATA_ERROR;\n        break inf_leave;\n      case MEM:\n        return Z_MEM_ERROR;\n      case SYNC:\n        /* falls through */\n      default:\n        return Z_STREAM_ERROR;\n    }\n  }\n\n  // inf_leave <- here is real place for \"goto inf_leave\", emulated via \"break inf_leave\"\n\n  /*\n     Return from inflate(), updating the total counts and the check value.\n     If there was no progress during the inflate() call, return a buffer\n     error.  Call updatewindow() to create and/or update the window state.\n     Note: a memory error from inflate() is non-recoverable.\n   */\n\n  //--- RESTORE() ---\n  strm.next_out = put;\n  strm.avail_out = left;\n  strm.next_in = next;\n  strm.avail_in = have;\n  state.hold = hold;\n  state.bits = bits;\n  //---\n\n  if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&\n                      (state.mode < CHECK || flush !== Z_FINISH))) {\n    if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {\n      state.mode = MEM;\n      return Z_MEM_ERROR;\n    }\n  }\n  _in -= strm.avail_in;\n  _out -= strm.avail_out;\n  strm.total_in += _in;\n  strm.total_out += _out;\n  state.total += _out;\n  if (state.wrap && _out) {\n    strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/\n      (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out));\n  }\n  strm.data_type = state.bits + (state.last ? 64 : 0) +\n                    (state.mode === TYPE ? 128 : 0) +\n                    (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);\n  if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) {\n    ret = Z_BUF_ERROR;\n  }\n  return ret;\n}\n\nfunction inflateEnd(strm) {\n\n  if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {\n    return Z_STREAM_ERROR;\n  }\n\n  var state = strm.state;\n  if (state.window) {\n    state.window = null;\n  }\n  strm.state = null;\n  return Z_OK;\n}\n\nfunction inflateGetHeader(strm, head) {\n  var state;\n\n  /* check state */\n  if (!strm || !strm.state) { return Z_STREAM_ERROR; }\n  state = strm.state;\n  if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; }\n\n  /* save header structure */\n  state.head = head;\n  head.done = false;\n  return Z_OK;\n}\n\nfunction inflateSetDictionary(strm, dictionary) {\n  var dictLength = dictionary.length;\n\n  var state;\n  var dictid;\n  var ret;\n\n  /* check state */\n  if (!strm /* == Z_NULL */ || !strm.state /* == Z_NULL */) { return Z_STREAM_ERROR; }\n  state = strm.state;\n\n  if (state.wrap !== 0 && state.mode !== DICT) {\n    return Z_STREAM_ERROR;\n  }\n\n  /* check for correct dictionary identifier */\n  if (state.mode === DICT) {\n    dictid = 1; /* adler32(0, null, 0)*/\n    /* dictid = adler32(dictid, dictionary, dictLength); */\n    dictid = adler32(dictid, dictionary, dictLength, 0);\n    if (dictid !== state.check) {\n      return Z_DATA_ERROR;\n    }\n  }\n  /* copy dictionary to window using updatewindow(), which will amend the\n   existing dictionary if appropriate */\n  ret = updatewindow(strm, dictionary, dictLength, dictLength);\n  if (ret) {\n    state.mode = MEM;\n    return Z_MEM_ERROR;\n  }\n  state.havedict = 1;\n  // Tracev((stderr, \"inflate:   dictionary set\\n\"));\n  return Z_OK;\n}\n\nexports.inflateReset = inflateReset;\nexports.inflateReset2 = inflateReset2;\nexports.inflateResetKeep = inflateResetKeep;\nexports.inflateInit = inflateInit;\nexports.inflateInit2 = inflateInit2;\nexports.inflate = inflate;\nexports.inflateEnd = inflateEnd;\nexports.inflateGetHeader = inflateGetHeader;\nexports.inflateSetDictionary = inflateSetDictionary;\nexports.inflateInfo = 'pako inflate (from Nodeca project)';\n\n/* Not implemented\nexports.inflateCopy = inflateCopy;\nexports.inflateGetDictionary = inflateGetDictionary;\nexports.inflateMark = inflateMark;\nexports.inflatePrime = inflatePrime;\nexports.inflateSync = inflateSync;\nexports.inflateSyncPoint = inflateSyncPoint;\nexports.inflateUndermine = inflateUndermine;\n*/\n\n\n/***/ }),\n/* 158 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\n// See state defs from inflate.js\nvar BAD = 30;       /* got a data error -- remain here until reset */\nvar TYPE = 12;      /* i: waiting for type bits, including last-flag bit */\n\n/*\n   Decode literal, length, and distance codes and write out the resulting\n   literal and match bytes until either not enough input or output is\n   available, an end-of-block is encountered, or a data error is encountered.\n   When large enough input and output buffers are supplied to inflate(), for\n   example, a 16K input buffer and a 64K output buffer, more than 95% of the\n   inflate execution time is spent in this routine.\n\n   Entry assumptions:\n\n        state.mode === LEN\n        strm.avail_in >= 6\n        strm.avail_out >= 258\n        start >= strm.avail_out\n        state.bits < 8\n\n   On return, state.mode is one of:\n\n        LEN -- ran out of enough output space or enough available input\n        TYPE -- reached end of block code, inflate() to interpret next block\n        BAD -- error in block data\n\n   Notes:\n\n    - The maximum input bits used by a length/distance pair is 15 bits for the\n      length code, 5 bits for the length extra, 15 bits for the distance code,\n      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.\n      Therefore if strm.avail_in >= 6, then there is enough input to avoid\n      checking for available input while decoding.\n\n    - The maximum bytes that a single length/distance pair can output is 258\n      bytes, which is the maximum length that can be coded.  inflate_fast()\n      requires strm.avail_out >= 258 for each loop to avoid checking for\n      output space.\n */\nmodule.exports = function inflate_fast(strm, start) {\n  var state;\n  var _in;                    /* local strm.input */\n  var last;                   /* have enough input while in < last */\n  var _out;                   /* local strm.output */\n  var beg;                    /* inflate()'s initial strm.output */\n  var end;                    /* while out < end, enough space available */\n//#ifdef INFLATE_STRICT\n  var dmax;                   /* maximum distance from zlib header */\n//#endif\n  var wsize;                  /* window size or zero if not using window */\n  var whave;                  /* valid bytes in the window */\n  var wnext;                  /* window write index */\n  // Use `s_window` instead `window`, avoid conflict with instrumentation tools\n  var s_window;               /* allocated sliding window, if wsize != 0 */\n  var hold;                   /* local strm.hold */\n  var bits;                   /* local strm.bits */\n  var lcode;                  /* local strm.lencode */\n  var dcode;                  /* local strm.distcode */\n  var lmask;                  /* mask for first level of length codes */\n  var dmask;                  /* mask for first level of distance codes */\n  var here;                   /* retrieved table entry */\n  var op;                     /* code bits, operation, extra bits, or */\n                              /*  window position, window bytes to copy */\n  var len;                    /* match length, unused bytes */\n  var dist;                   /* match distance */\n  var from;                   /* where to copy match from */\n  var from_source;\n\n\n  var input, output; // JS specific, because we have no pointers\n\n  /* copy state to local variables */\n  state = strm.state;\n  //here = state.here;\n  _in = strm.next_in;\n  input = strm.input;\n  last = _in + (strm.avail_in - 5);\n  _out = strm.next_out;\n  output = strm.output;\n  beg = _out - (start - strm.avail_out);\n  end = _out + (strm.avail_out - 257);\n//#ifdef INFLATE_STRICT\n  dmax = state.dmax;\n//#endif\n  wsize = state.wsize;\n  whave = state.whave;\n  wnext = state.wnext;\n  s_window = state.window;\n  hold = state.hold;\n  bits = state.bits;\n  lcode = state.lencode;\n  dcode = state.distcode;\n  lmask = (1 << state.lenbits) - 1;\n  dmask = (1 << state.distbits) - 1;\n\n\n  /* decode literals and length/distances until end-of-block or not enough\n     input data or output space */\n\n  top:\n  do {\n    if (bits < 15) {\n      hold += input[_in++] << bits;\n      bits += 8;\n      hold += input[_in++] << bits;\n      bits += 8;\n    }\n\n    here = lcode[hold & lmask];\n\n    dolen:\n    for (;;) { // Goto emulation\n      op = here >>> 24/*here.bits*/;\n      hold >>>= op;\n      bits -= op;\n      op = (here >>> 16) & 0xff/*here.op*/;\n      if (op === 0) {                          /* literal */\n        //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?\n        //        \"inflate:         literal '%c'\\n\" :\n        //        \"inflate:         literal 0x%02x\\n\", here.val));\n        output[_out++] = here & 0xffff/*here.val*/;\n      }\n      else if (op & 16) {                     /* length base */\n        len = here & 0xffff/*here.val*/;\n        op &= 15;                           /* number of extra bits */\n        if (op) {\n          if (bits < op) {\n            hold += input[_in++] << bits;\n            bits += 8;\n          }\n          len += hold & ((1 << op) - 1);\n          hold >>>= op;\n          bits -= op;\n        }\n        //Tracevv((stderr, \"inflate:         length %u\\n\", len));\n        if (bits < 15) {\n          hold += input[_in++] << bits;\n          bits += 8;\n          hold += input[_in++] << bits;\n          bits += 8;\n        }\n        here = dcode[hold & dmask];\n\n        dodist:\n        for (;;) { // goto emulation\n          op = here >>> 24/*here.bits*/;\n          hold >>>= op;\n          bits -= op;\n          op = (here >>> 16) & 0xff/*here.op*/;\n\n          if (op & 16) {                      /* distance base */\n            dist = here & 0xffff/*here.val*/;\n            op &= 15;                       /* number of extra bits */\n            if (bits < op) {\n              hold += input[_in++] << bits;\n              bits += 8;\n              if (bits < op) {\n                hold += input[_in++] << bits;\n                bits += 8;\n              }\n            }\n            dist += hold & ((1 << op) - 1);\n//#ifdef INFLATE_STRICT\n            if (dist > dmax) {\n              strm.msg = 'invalid distance too far back';\n              state.mode = BAD;\n              break top;\n            }\n//#endif\n            hold >>>= op;\n            bits -= op;\n            //Tracevv((stderr, \"inflate:         distance %u\\n\", dist));\n            op = _out - beg;                /* max distance in output */\n            if (dist > op) {                /* see if copy from window */\n              op = dist - op;               /* distance back in window */\n              if (op > whave) {\n                if (state.sane) {\n                  strm.msg = 'invalid distance too far back';\n                  state.mode = BAD;\n                  break top;\n                }\n\n// (!) This block is disabled in zlib defaults,\n// don't enable it for binary compatibility\n//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR\n//                if (len <= op - whave) {\n//                  do {\n//                    output[_out++] = 0;\n//                  } while (--len);\n//                  continue top;\n//                }\n//                len -= op - whave;\n//                do {\n//                  output[_out++] = 0;\n//                } while (--op > whave);\n//                if (op === 0) {\n//                  from = _out - dist;\n//                  do {\n//                    output[_out++] = output[from++];\n//                  } while (--len);\n//                  continue top;\n//                }\n//#endif\n              }\n              from = 0; // window index\n              from_source = s_window;\n              if (wnext === 0) {           /* very common case */\n                from += wsize - op;\n                if (op < len) {         /* some from window */\n                  len -= op;\n                  do {\n                    output[_out++] = s_window[from++];\n                  } while (--op);\n                  from = _out - dist;  /* rest from output */\n                  from_source = output;\n                }\n              }\n              else if (wnext < op) {      /* wrap around window */\n                from += wsize + wnext - op;\n                op -= wnext;\n                if (op < len) {         /* some from end of window */\n                  len -= op;\n                  do {\n                    output[_out++] = s_window[from++];\n                  } while (--op);\n                  from = 0;\n                  if (wnext < len) {  /* some from start of window */\n                    op = wnext;\n                    len -= op;\n                    do {\n                      output[_out++] = s_window[from++];\n                    } while (--op);\n                    from = _out - dist;      /* rest from output */\n                    from_source = output;\n                  }\n                }\n              }\n              else {                      /* contiguous in window */\n                from += wnext - op;\n                if (op < len) {         /* some from window */\n                  len -= op;\n                  do {\n                    output[_out++] = s_window[from++];\n                  } while (--op);\n                  from = _out - dist;  /* rest from output */\n                  from_source = output;\n                }\n              }\n              while (len > 2) {\n                output[_out++] = from_source[from++];\n                output[_out++] = from_source[from++];\n                output[_out++] = from_source[from++];\n                len -= 3;\n              }\n              if (len) {\n                output[_out++] = from_source[from++];\n                if (len > 1) {\n                  output[_out++] = from_source[from++];\n                }\n              }\n            }\n            else {\n              from = _out - dist;          /* copy direct from output */\n              do {                        /* minimum length is three */\n                output[_out++] = output[from++];\n                output[_out++] = output[from++];\n                output[_out++] = output[from++];\n                len -= 3;\n              } while (len > 2);\n              if (len) {\n                output[_out++] = output[from++];\n                if (len > 1) {\n                  output[_out++] = output[from++];\n                }\n              }\n            }\n          }\n          else if ((op & 64) === 0) {          /* 2nd level distance code */\n            here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];\n            continue dodist;\n          }\n          else {\n            strm.msg = 'invalid distance code';\n            state.mode = BAD;\n            break top;\n          }\n\n          break; // need to emulate goto via \"continue\"\n        }\n      }\n      else if ((op & 64) === 0) {              /* 2nd level length code */\n        here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];\n        continue dolen;\n      }\n      else if (op & 32) {                     /* end-of-block */\n        //Tracevv((stderr, \"inflate:         end of block\\n\"));\n        state.mode = TYPE;\n        break top;\n      }\n      else {\n        strm.msg = 'invalid literal/length code';\n        state.mode = BAD;\n        break top;\n      }\n\n      break; // need to emulate goto via \"continue\"\n    }\n  } while (_in < last && _out < end);\n\n  /* return unused bytes (on entry, bits < 8, so in won't go too far back) */\n  len = bits >> 3;\n  _in -= len;\n  bits -= len << 3;\n  hold &= (1 << bits) - 1;\n\n  /* update state and return */\n  strm.next_in = _in;\n  strm.next_out = _out;\n  strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));\n  strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));\n  state.hold = hold;\n  state.bits = bits;\n  return;\n};\n\n\n/***/ }),\n/* 159 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nvar utils = __webpack_require__(34);\n\nvar MAXBITS = 15;\nvar ENOUGH_LENS = 852;\nvar ENOUGH_DISTS = 592;\n//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);\n\nvar CODES = 0;\nvar LENS = 1;\nvar DISTS = 2;\n\nvar lbase = [ /* Length codes 257..285 base */\n  3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,\n  35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0\n];\n\nvar lext = [ /* Length codes 257..285 extra */\n  16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,\n  19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78\n];\n\nvar dbase = [ /* Distance codes 0..29 base */\n  1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,\n  257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,\n  8193, 12289, 16385, 24577, 0, 0\n];\n\nvar dext = [ /* Distance codes 0..29 extra */\n  16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,\n  23, 23, 24, 24, 25, 25, 26, 26, 27, 27,\n  28, 28, 29, 29, 64, 64\n];\n\nmodule.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts)\n{\n  var bits = opts.bits;\n      //here = opts.here; /* table entry for duplication */\n\n  var len = 0;               /* a code's length in bits */\n  var sym = 0;               /* index of code symbols */\n  var min = 0, max = 0;          /* minimum and maximum code lengths */\n  var root = 0;              /* number of index bits for root table */\n  var curr = 0;              /* number of index bits for current table */\n  var drop = 0;              /* code bits to drop for sub-table */\n  var left = 0;                   /* number of prefix codes available */\n  var used = 0;              /* code entries in table used */\n  var huff = 0;              /* Huffman code */\n  var incr;              /* for incrementing code, index */\n  var fill;              /* index for replicating entries */\n  var low;               /* low bits for current root entry */\n  var mask;              /* mask for low root bits */\n  var next;             /* next available space in table */\n  var base = null;     /* base value table to use */\n  var base_index = 0;\n//  var shoextra;    /* extra bits table to use */\n  var end;                    /* use base and extra for symbol > end */\n  var count = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1];    /* number of codes of each length */\n  var offs = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1];     /* offsets in table for each length */\n  var extra = null;\n  var extra_index = 0;\n\n  var here_bits, here_op, here_val;\n\n  /*\n   Process a set of code lengths to create a canonical Huffman code.  The\n   code lengths are lens[0..codes-1].  Each length corresponds to the\n   symbols 0..codes-1.  The Huffman code is generated by first sorting the\n   symbols by length from short to long, and retaining the symbol order\n   for codes with equal lengths.  Then the code starts with all zero bits\n   for the first code of the shortest length, and the codes are integer\n   increments for the same length, and zeros are appended as the length\n   increases.  For the deflate format, these bits are stored backwards\n   from their more natural integer increment ordering, and so when the\n   decoding tables are built in the large loop below, the integer codes\n   are incremented backwards.\n\n   This routine assumes, but does not check, that all of the entries in\n   lens[] are in the range 0..MAXBITS.  The caller must assure this.\n   1..MAXBITS is interpreted as that code length.  zero means that that\n   symbol does not occur in this code.\n\n   The codes are sorted by computing a count of codes for each length,\n   creating from that a table of starting indices for each length in the\n   sorted table, and then entering the symbols in order in the sorted\n   table.  The sorted table is work[], with that space being provided by\n   the caller.\n\n   The length counts are used for other purposes as well, i.e. finding\n   the minimum and maximum length codes, determining if there are any\n   codes at all, checking for a valid set of lengths, and looking ahead\n   at length counts to determine sub-table sizes when building the\n   decoding tables.\n   */\n\n  /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */\n  for (len = 0; len <= MAXBITS; len++) {\n    count[len] = 0;\n  }\n  for (sym = 0; sym < codes; sym++) {\n    count[lens[lens_index + sym]]++;\n  }\n\n  /* bound code lengths, force root to be within code lengths */\n  root = bits;\n  for (max = MAXBITS; max >= 1; max--) {\n    if (count[max] !== 0) { break; }\n  }\n  if (root > max) {\n    root = max;\n  }\n  if (max === 0) {                     /* no symbols to code at all */\n    //table.op[opts.table_index] = 64;  //here.op = (var char)64;    /* invalid code marker */\n    //table.bits[opts.table_index] = 1;   //here.bits = (var char)1;\n    //table.val[opts.table_index++] = 0;   //here.val = (var short)0;\n    table[table_index++] = (1 << 24) | (64 << 16) | 0;\n\n\n    //table.op[opts.table_index] = 64;\n    //table.bits[opts.table_index] = 1;\n    //table.val[opts.table_index++] = 0;\n    table[table_index++] = (1 << 24) | (64 << 16) | 0;\n\n    opts.bits = 1;\n    return 0;     /* no symbols, but wait for decoding to report error */\n  }\n  for (min = 1; min < max; min++) {\n    if (count[min] !== 0) { break; }\n  }\n  if (root < min) {\n    root = min;\n  }\n\n  /* check for an over-subscribed or incomplete set of lengths */\n  left = 1;\n  for (len = 1; len <= MAXBITS; len++) {\n    left <<= 1;\n    left -= count[len];\n    if (left < 0) {\n      return -1;\n    }        /* over-subscribed */\n  }\n  if (left > 0 && (type === CODES || max !== 1)) {\n    return -1;                      /* incomplete set */\n  }\n\n  /* generate offsets into symbol table for each length for sorting */\n  offs[1] = 0;\n  for (len = 1; len < MAXBITS; len++) {\n    offs[len + 1] = offs[len] + count[len];\n  }\n\n  /* sort symbols by length, by symbol order within each length */\n  for (sym = 0; sym < codes; sym++) {\n    if (lens[lens_index + sym] !== 0) {\n      work[offs[lens[lens_index + sym]]++] = sym;\n    }\n  }\n\n  /*\n   Create and fill in decoding tables.  In this loop, the table being\n   filled is at next and has curr index bits.  The code being used is huff\n   with length len.  That code is converted to an index by dropping drop\n   bits off of the bottom.  For codes where len is less than drop + curr,\n   those top drop + curr - len bits are incremented through all values to\n   fill the table with replicated entries.\n\n   root is the number of index bits for the root table.  When len exceeds\n   root, sub-tables are created pointed to by the root entry with an index\n   of the low root bits of huff.  This is saved in low to check for when a\n   new sub-table should be started.  drop is zero when the root table is\n   being filled, and drop is root when sub-tables are being filled.\n\n   When a new sub-table is needed, it is necessary to look ahead in the\n   code lengths to determine what size sub-table is needed.  The length\n   counts are used for this, and so count[] is decremented as codes are\n   entered in the tables.\n\n   used keeps track of how many table entries have been allocated from the\n   provided *table space.  It is checked for LENS and DIST tables against\n   the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in\n   the initial root table size constants.  See the comments in inftrees.h\n   for more information.\n\n   sym increments through all symbols, and the loop terminates when\n   all codes of length max, i.e. all codes, have been processed.  This\n   routine permits incomplete codes, so another loop after this one fills\n   in the rest of the decoding tables with invalid code markers.\n   */\n\n  /* set up for code type */\n  // poor man optimization - use if-else instead of switch,\n  // to avoid deopts in old v8\n  if (type === CODES) {\n    base = extra = work;    /* dummy value--not used */\n    end = 19;\n\n  } else if (type === LENS) {\n    base = lbase;\n    base_index -= 257;\n    extra = lext;\n    extra_index -= 257;\n    end = 256;\n\n  } else {                    /* DISTS */\n    base = dbase;\n    extra = dext;\n    end = -1;\n  }\n\n  /* initialize opts for loop */\n  huff = 0;                   /* starting code */\n  sym = 0;                    /* starting code symbol */\n  len = min;                  /* starting code length */\n  next = table_index;              /* current table to fill in */\n  curr = root;                /* current table index bits */\n  drop = 0;                   /* current bits to drop from code for index */\n  low = -1;                   /* trigger new sub-table when len > root */\n  used = 1 << root;          /* use root table entries */\n  mask = used - 1;            /* mask for comparing low */\n\n  /* check available table space */\n  if ((type === LENS && used > ENOUGH_LENS) ||\n    (type === DISTS && used > ENOUGH_DISTS)) {\n    return 1;\n  }\n\n  /* process all codes and make table entries */\n  for (;;) {\n    /* create table entry */\n    here_bits = len - drop;\n    if (work[sym] < end) {\n      here_op = 0;\n      here_val = work[sym];\n    }\n    else if (work[sym] > end) {\n      here_op = extra[extra_index + work[sym]];\n      here_val = base[base_index + work[sym]];\n    }\n    else {\n      here_op = 32 + 64;         /* end of block */\n      here_val = 0;\n    }\n\n    /* replicate for those indices with low len bits equal to huff */\n    incr = 1 << (len - drop);\n    fill = 1 << curr;\n    min = fill;                 /* save offset to next table */\n    do {\n      fill -= incr;\n      table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;\n    } while (fill !== 0);\n\n    /* backwards increment the len-bit code huff */\n    incr = 1 << (len - 1);\n    while (huff & incr) {\n      incr >>= 1;\n    }\n    if (incr !== 0) {\n      huff &= incr - 1;\n      huff += incr;\n    } else {\n      huff = 0;\n    }\n\n    /* go to next symbol, update count, len */\n    sym++;\n    if (--count[len] === 0) {\n      if (len === max) { break; }\n      len = lens[lens_index + work[sym]];\n    }\n\n    /* create new sub-table if needed */\n    if (len > root && (huff & mask) !== low) {\n      /* if first time, transition to sub-tables */\n      if (drop === 0) {\n        drop = root;\n      }\n\n      /* increment past last table */\n      next += min;            /* here min is 1 << curr */\n\n      /* determine length of next table */\n      curr = len - drop;\n      left = 1 << curr;\n      while (curr + drop < max) {\n        left -= count[curr + drop];\n        if (left <= 0) { break; }\n        curr++;\n        left <<= 1;\n      }\n\n      /* check for enough space */\n      used += 1 << curr;\n      if ((type === LENS && used > ENOUGH_LENS) ||\n        (type === DISTS && used > ENOUGH_DISTS)) {\n        return 1;\n      }\n\n      /* point entry in root table to sub-table */\n      low = huff & mask;\n      /*table.op[low] = curr;\n      table.bits[low] = root;\n      table.val[low] = next - opts.table_index;*/\n      table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;\n    }\n  }\n\n  /* fill in remaining table entry if code is incomplete (guaranteed to have\n   at most one remaining entry, since if the code is incomplete, the\n   maximum code length that was allowed to get this far is one bit) */\n  if (huff !== 0) {\n    //table.op[next + huff] = 64;            /* invalid code marker */\n    //table.bits[next + huff] = len - drop;\n    //table.val[next + huff] = 0;\n    table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;\n  }\n\n  /* set return parameters */\n  //opts.table_index += used;\n  opts.bits = root;\n  return 0;\n};\n\n\n/***/ }),\n/* 160 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n//   claim that you wrote the original software. If you use this software\n//   in a product, an acknowledgment in the product documentation would be\n//   appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n//   misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nmodule.exports = {\n\n  /* Allowed flush values; see deflate() and inflate() below for details */\n  Z_NO_FLUSH:         0,\n  Z_PARTIAL_FLUSH:    1,\n  Z_SYNC_FLUSH:       2,\n  Z_FULL_FLUSH:       3,\n  Z_FINISH:           4,\n  Z_BLOCK:            5,\n  Z_TREES:            6,\n\n  /* Return codes for the compression/decompression functions. Negative values\n  * are errors, positive values are used for special but normal events.\n  */\n  Z_OK:               0,\n  Z_STREAM_END:       1,\n  Z_NEED_DICT:        2,\n  Z_ERRNO:           -1,\n  Z_STREAM_ERROR:    -2,\n  Z_DATA_ERROR:      -3,\n  //Z_MEM_ERROR:     -4,\n  Z_BUF_ERROR:       -5,\n  //Z_VERSION_ERROR: -6,\n\n  /* compression levels */\n  Z_NO_COMPRESSION:         0,\n  Z_BEST_SPEED:             1,\n  Z_BEST_COMPRESSION:       9,\n  Z_DEFAULT_COMPRESSION:   -1,\n\n\n  Z_FILTERED:               1,\n  Z_HUFFMAN_ONLY:           2,\n  Z_RLE:                    3,\n  Z_FIXED:                  4,\n  Z_DEFAULT_STRATEGY:       0,\n\n  /* Possible values of the data_type field (though see inflate()) */\n  Z_BINARY:                 0,\n  Z_TEXT:                   1,\n  //Z_ASCII:                1, // = Z_TEXT (deprecated)\n  Z_UNKNOWN:                2,\n\n  /* The deflate compression method */\n  Z_DEFLATED:               8\n  //Z_NULL:                 null // Use -1 or null inline, depending on var type\n};\n\n\n/***/ }),\n/* 161 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.12.6\n\n/*\nPDFPage - represents a single page in the PDF document\nBy Devon Govett\n */\n\n(function() {\n  var PDFPage;\n\n  PDFPage = (function() {\n    var DEFAULT_MARGINS, SIZES;\n\n    function PDFPage(document, options) {\n      var dimensions;\n      this.document = document;\n      if (options == null) {\n        options = {};\n      }\n      this.size = options.size || 'letter';\n      this.layout = options.layout || 'portrait';\n      if (typeof options.margin === 'number') {\n        this.margins = {\n          top: options.margin,\n          left: options.margin,\n          bottom: options.margin,\n          right: options.margin\n        };\n      } else {\n        this.margins = options.margins || DEFAULT_MARGINS;\n      }\n      dimensions = Array.isArray(this.size) ? this.size : SIZES[this.size.toUpperCase()];\n      this.width = dimensions[this.layout === 'portrait' ? 0 : 1];\n      this.height = dimensions[this.layout === 'portrait' ? 1 : 0];\n      this.content = this.document.ref();\n      this.resources = this.document.ref({\n        ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI']\n      });\n      Object.defineProperties(this, {\n        fonts: {\n          get: (function(_this) {\n            return function() {\n              var base;\n              return (base = _this.resources.data).Font != null ? base.Font : base.Font = {};\n            };\n          })(this)\n        },\n        xobjects: {\n          get: (function(_this) {\n            return function() {\n              var base;\n              return (base = _this.resources.data).XObject != null ? base.XObject : base.XObject = {};\n            };\n          })(this)\n        },\n        ext_gstates: {\n          get: (function(_this) {\n            return function() {\n              var base;\n              return (base = _this.resources.data).ExtGState != null ? base.ExtGState : base.ExtGState = {};\n            };\n          })(this)\n        },\n        patterns: {\n          get: (function(_this) {\n            return function() {\n              var base;\n              return (base = _this.resources.data).Pattern != null ? base.Pattern : base.Pattern = {};\n            };\n          })(this)\n        },\n        annotations: {\n          get: (function(_this) {\n            return function() {\n              var base;\n              return (base = _this.dictionary.data).Annots != null ? base.Annots : base.Annots = [];\n            };\n          })(this)\n        }\n      });\n      this.dictionary = this.document.ref({\n        Type: 'Page',\n        Parent: this.document._root.data.Pages,\n        MediaBox: [0, 0, this.width, this.height],\n        Contents: this.content,\n        Resources: this.resources\n      });\n    }\n\n    PDFPage.prototype.maxY = function() {\n      return this.height - this.margins.bottom;\n    };\n\n    PDFPage.prototype.write = function(chunk) {\n      return this.content.write(chunk);\n    };\n\n    PDFPage.prototype.end = function() {\n      this.dictionary.end();\n      this.resources.end();\n      return this.content.end();\n    };\n\n    DEFAULT_MARGINS = {\n      top: 72,\n      left: 72,\n      bottom: 72,\n      right: 72\n    };\n\n    SIZES = {\n      '4A0': [4767.87, 6740.79],\n      '2A0': [3370.39, 4767.87],\n      A0: [2383.94, 3370.39],\n      A1: [1683.78, 2383.94],\n      A2: [1190.55, 1683.78],\n      A3: [841.89, 1190.55],\n      A4: [595.28, 841.89],\n      A5: [419.53, 595.28],\n      A6: [297.64, 419.53],\n      A7: [209.76, 297.64],\n      A8: [147.40, 209.76],\n      A9: [104.88, 147.40],\n      A10: [73.70, 104.88],\n      B0: [2834.65, 4008.19],\n      B1: [2004.09, 2834.65],\n      B2: [1417.32, 2004.09],\n      B3: [1000.63, 1417.32],\n      B4: [708.66, 1000.63],\n      B5: [498.90, 708.66],\n      B6: [354.33, 498.90],\n      B7: [249.45, 354.33],\n      B8: [175.75, 249.45],\n      B9: [124.72, 175.75],\n      B10: [87.87, 124.72],\n      C0: [2599.37, 3676.54],\n      C1: [1836.85, 2599.37],\n      C2: [1298.27, 1836.85],\n      C3: [918.43, 1298.27],\n      C4: [649.13, 918.43],\n      C5: [459.21, 649.13],\n      C6: [323.15, 459.21],\n      C7: [229.61, 323.15],\n      C8: [161.57, 229.61],\n      C9: [113.39, 161.57],\n      C10: [79.37, 113.39],\n      RA0: [2437.80, 3458.27],\n      RA1: [1729.13, 2437.80],\n      RA2: [1218.90, 1729.13],\n      RA3: [864.57, 1218.90],\n      RA4: [609.45, 864.57],\n      SRA0: [2551.18, 3628.35],\n      SRA1: [1814.17, 2551.18],\n      SRA2: [1275.59, 1814.17],\n      SRA3: [907.09, 1275.59],\n      SRA4: [637.80, 907.09],\n      EXECUTIVE: [521.86, 756.00],\n      FOLIO: [612.00, 936.00],\n      LEGAL: [612.00, 1008.00],\n      LETTER: [612.00, 792.00],\n      TABLOID: [792.00, 1224.00]\n    };\n\n    return PDFPage;\n\n  })();\n\n  module.exports = PDFPage;\n\n}).call(this);\n\n\n/***/ }),\n/* 162 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var PDFGradient, PDFLinearGradient, PDFRadialGradient, namedColors, ref;\n\n  ref = __webpack_require__(163), PDFGradient = ref.PDFGradient, PDFLinearGradient = ref.PDFLinearGradient, PDFRadialGradient = ref.PDFRadialGradient;\n\n  module.exports = {\n    initColor: function() {\n      this._opacityRegistry = {};\n      this._opacityCount = 0;\n      return this._gradCount = 0;\n    },\n    _normalizeColor: function(color) {\n      var hex, part;\n      if (color instanceof PDFGradient) {\n        return color;\n      }\n      if (typeof color === 'string') {\n        if (color.charAt(0) === '#') {\n          if (color.length === 4) {\n            color = color.replace(/#([0-9A-F])([0-9A-F])([0-9A-F])/i, \"#$1$1$2$2$3$3\");\n          }\n          hex = parseInt(color.slice(1), 16);\n          color = [hex >> 16, hex >> 8 & 0xff, hex & 0xff];\n        } else if (namedColors[color]) {\n          color = namedColors[color];\n        }\n      }\n      if (Array.isArray(color)) {\n        if (color.length === 3) {\n          color = (function() {\n            var i, len, results;\n            results = [];\n            for (i = 0, len = color.length; i < len; i++) {\n              part = color[i];\n              results.push(part / 255);\n            }\n            return results;\n          })();\n        } else if (color.length === 4) {\n          color = (function() {\n            var i, len, results;\n            results = [];\n            for (i = 0, len = color.length; i < len; i++) {\n              part = color[i];\n              results.push(part / 100);\n            }\n            return results;\n          })();\n        }\n        return color;\n      }\n      return null;\n    },\n    _setColor: function(color, stroke) {\n      var op, space;\n      color = this._normalizeColor(color);\n      if (!color) {\n        return false;\n      }\n      op = stroke ? 'SCN' : 'scn';\n      if (color instanceof PDFGradient) {\n        this._setColorSpace('Pattern', stroke);\n        color.apply(op);\n      } else {\n        space = color.length === 4 ? 'DeviceCMYK' : 'DeviceRGB';\n        this._setColorSpace(space, stroke);\n        color = color.join(' ');\n        this.addContent(color + \" \" + op);\n      }\n      return true;\n    },\n    _setColorSpace: function(space, stroke) {\n      var op;\n      op = stroke ? 'CS' : 'cs';\n      return this.addContent(\"/\" + space + \" \" + op);\n    },\n    fillColor: function(color, opacity) {\n      var set;\n      set = this._setColor(color, false);\n      if (set) {\n        this.fillOpacity(opacity);\n      }\n      this._fillColor = [color, opacity];\n      return this;\n    },\n    strokeColor: function(color, opacity) {\n      var set;\n      set = this._setColor(color, true);\n      if (set) {\n        this.strokeOpacity(opacity);\n      }\n      return this;\n    },\n    opacity: function(opacity) {\n      this._doOpacity(opacity, opacity);\n      return this;\n    },\n    fillOpacity: function(opacity) {\n      this._doOpacity(opacity, null);\n      return this;\n    },\n    strokeOpacity: function(opacity) {\n      this._doOpacity(null, opacity);\n      return this;\n    },\n    _doOpacity: function(fillOpacity, strokeOpacity) {\n      var dictionary, id, key, name, ref1;\n      if (!((fillOpacity != null) || (strokeOpacity != null))) {\n        return;\n      }\n      if (fillOpacity != null) {\n        fillOpacity = Math.max(0, Math.min(1, fillOpacity));\n      }\n      if (strokeOpacity != null) {\n        strokeOpacity = Math.max(0, Math.min(1, strokeOpacity));\n      }\n      key = fillOpacity + \"_\" + strokeOpacity;\n      if (this._opacityRegistry[key]) {\n        ref1 = this._opacityRegistry[key], dictionary = ref1[0], name = ref1[1];\n      } else {\n        dictionary = {\n          Type: 'ExtGState'\n        };\n        if (fillOpacity != null) {\n          dictionary.ca = fillOpacity;\n        }\n        if (strokeOpacity != null) {\n          dictionary.CA = strokeOpacity;\n        }\n        dictionary = this.ref(dictionary);\n        dictionary.end();\n        id = ++this._opacityCount;\n        name = \"Gs\" + id;\n        this._opacityRegistry[key] = [dictionary, name];\n      }\n      this.page.ext_gstates[name] = dictionary;\n      return this.addContent(\"/\" + name + \" gs\");\n    },\n    linearGradient: function(x1, y1, x2, y2) {\n      return new PDFLinearGradient(this, x1, y1, x2, y2);\n    },\n    radialGradient: function(x1, y1, r1, x2, y2, r2) {\n      return new PDFRadialGradient(this, x1, y1, r1, x2, y2, r2);\n    }\n  };\n\n  namedColors = {\n    aliceblue: [240, 248, 255],\n    antiquewhite: [250, 235, 215],\n    aqua: [0, 255, 255],\n    aquamarine: [127, 255, 212],\n    azure: [240, 255, 255],\n    beige: [245, 245, 220],\n    bisque: [255, 228, 196],\n    black: [0, 0, 0],\n    blanchedalmond: [255, 235, 205],\n    blue: [0, 0, 255],\n    blueviolet: [138, 43, 226],\n    brown: [165, 42, 42],\n    burlywood: [222, 184, 135],\n    cadetblue: [95, 158, 160],\n    chartreuse: [127, 255, 0],\n    chocolate: [210, 105, 30],\n    coral: [255, 127, 80],\n    cornflowerblue: [100, 149, 237],\n    cornsilk: [255, 248, 220],\n    crimson: [220, 20, 60],\n    cyan: [0, 255, 255],\n    darkblue: [0, 0, 139],\n    darkcyan: [0, 139, 139],\n    darkgoldenrod: [184, 134, 11],\n    darkgray: [169, 169, 169],\n    darkgreen: [0, 100, 0],\n    darkgrey: [169, 169, 169],\n    darkkhaki: [189, 183, 107],\n    darkmagenta: [139, 0, 139],\n    darkolivegreen: [85, 107, 47],\n    darkorange: [255, 140, 0],\n    darkorchid: [153, 50, 204],\n    darkred: [139, 0, 0],\n    darksalmon: [233, 150, 122],\n    darkseagreen: [143, 188, 143],\n    darkslateblue: [72, 61, 139],\n    darkslategray: [47, 79, 79],\n    darkslategrey: [47, 79, 79],\n    darkturquoise: [0, 206, 209],\n    darkviolet: [148, 0, 211],\n    deeppink: [255, 20, 147],\n    deepskyblue: [0, 191, 255],\n    dimgray: [105, 105, 105],\n    dimgrey: [105, 105, 105],\n    dodgerblue: [30, 144, 255],\n    firebrick: [178, 34, 34],\n    floralwhite: [255, 250, 240],\n    forestgreen: [34, 139, 34],\n    fuchsia: [255, 0, 255],\n    gainsboro: [220, 220, 220],\n    ghostwhite: [248, 248, 255],\n    gold: [255, 215, 0],\n    goldenrod: [218, 165, 32],\n    gray: [128, 128, 128],\n    grey: [128, 128, 128],\n    green: [0, 128, 0],\n    greenyellow: [173, 255, 47],\n    honeydew: [240, 255, 240],\n    hotpink: [255, 105, 180],\n    indianred: [205, 92, 92],\n    indigo: [75, 0, 130],\n    ivory: [255, 255, 240],\n    khaki: [240, 230, 140],\n    lavender: [230, 230, 250],\n    lavenderblush: [255, 240, 245],\n    lawngreen: [124, 252, 0],\n    lemonchiffon: [255, 250, 205],\n    lightblue: [173, 216, 230],\n    lightcoral: [240, 128, 128],\n    lightcyan: [224, 255, 255],\n    lightgoldenrodyellow: [250, 250, 210],\n    lightgray: [211, 211, 211],\n    lightgreen: [144, 238, 144],\n    lightgrey: [211, 211, 211],\n    lightpink: [255, 182, 193],\n    lightsalmon: [255, 160, 122],\n    lightseagreen: [32, 178, 170],\n    lightskyblue: [135, 206, 250],\n    lightslategray: [119, 136, 153],\n    lightslategrey: [119, 136, 153],\n    lightsteelblue: [176, 196, 222],\n    lightyellow: [255, 255, 224],\n    lime: [0, 255, 0],\n    limegreen: [50, 205, 50],\n    linen: [250, 240, 230],\n    magenta: [255, 0, 255],\n    maroon: [128, 0, 0],\n    mediumaquamarine: [102, 205, 170],\n    mediumblue: [0, 0, 205],\n    mediumorchid: [186, 85, 211],\n    mediumpurple: [147, 112, 219],\n    mediumseagreen: [60, 179, 113],\n    mediumslateblue: [123, 104, 238],\n    mediumspringgreen: [0, 250, 154],\n    mediumturquoise: [72, 209, 204],\n    mediumvioletred: [199, 21, 133],\n    midnightblue: [25, 25, 112],\n    mintcream: [245, 255, 250],\n    mistyrose: [255, 228, 225],\n    moccasin: [255, 228, 181],\n    navajowhite: [255, 222, 173],\n    navy: [0, 0, 128],\n    oldlace: [253, 245, 230],\n    olive: [128, 128, 0],\n    olivedrab: [107, 142, 35],\n    orange: [255, 165, 0],\n    orangered: [255, 69, 0],\n    orchid: [218, 112, 214],\n    palegoldenrod: [238, 232, 170],\n    palegreen: [152, 251, 152],\n    paleturquoise: [175, 238, 238],\n    palevioletred: [219, 112, 147],\n    papayawhip: [255, 239, 213],\n    peachpuff: [255, 218, 185],\n    peru: [205, 133, 63],\n    pink: [255, 192, 203],\n    plum: [221, 160, 221],\n    powderblue: [176, 224, 230],\n    purple: [128, 0, 128],\n    red: [255, 0, 0],\n    rosybrown: [188, 143, 143],\n    royalblue: [65, 105, 225],\n    saddlebrown: [139, 69, 19],\n    salmon: [250, 128, 114],\n    sandybrown: [244, 164, 96],\n    seagreen: [46, 139, 87],\n    seashell: [255, 245, 238],\n    sienna: [160, 82, 45],\n    silver: [192, 192, 192],\n    skyblue: [135, 206, 235],\n    slateblue: [106, 90, 205],\n    slategray: [112, 128, 144],\n    slategrey: [112, 128, 144],\n    snow: [255, 250, 250],\n    springgreen: [0, 255, 127],\n    steelblue: [70, 130, 180],\n    tan: [210, 180, 140],\n    teal: [0, 128, 128],\n    thistle: [216, 191, 216],\n    tomato: [255, 99, 71],\n    turquoise: [64, 224, 208],\n    violet: [238, 130, 238],\n    wheat: [245, 222, 179],\n    white: [255, 255, 255],\n    whitesmoke: [245, 245, 245],\n    yellow: [255, 255, 0],\n    yellowgreen: [154, 205, 50]\n  };\n\n}).call(this);\n\n\n/***/ }),\n/* 163 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var PDFGradient, PDFLinearGradient, PDFRadialGradient,\n    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n    hasProp = {}.hasOwnProperty;\n\n  PDFGradient = (function() {\n    function PDFGradient(doc) {\n      this.doc = doc;\n      this.stops = [];\n      this.embedded = false;\n      this.transform = [1, 0, 0, 1, 0, 0];\n      this._colorSpace = 'DeviceRGB';\n    }\n\n    PDFGradient.prototype.stop = function(pos, color, opacity) {\n      if (opacity == null) {\n        opacity = 1;\n      }\n      opacity = Math.max(0, Math.min(1, opacity));\n      this.stops.push([pos, this.doc._normalizeColor(color), opacity]);\n      return this;\n    };\n\n    PDFGradient.prototype.setTransform = function(m11, m12, m21, m22, dx, dy) {\n      this.transform = [m11, m12, m21, m22, dx, dy];\n      return this;\n    };\n\n    PDFGradient.prototype.embed = function(m) {\n      var bounds, encode, fn, form, grad, gstate, i, j, k, last, len, opacityPattern, pageBBox, pattern, ref, ref1, shader, stop, stops, v;\n      if (this.stops.length === 0) {\n        return;\n      }\n      this.embedded = true;\n      this.matrix = m;\n      last = this.stops[this.stops.length - 1];\n      if (last[0] < 1) {\n        this.stops.push([1, last[1], last[2]]);\n      }\n      bounds = [];\n      encode = [];\n      stops = [];\n      for (i = j = 0, ref = this.stops.length - 1; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {\n        encode.push(0, 1);\n        if (i + 2 !== this.stops.length) {\n          bounds.push(this.stops[i + 1][0]);\n        }\n        fn = this.doc.ref({\n          FunctionType: 2,\n          Domain: [0, 1],\n          C0: this.stops[i + 0][1],\n          C1: this.stops[i + 1][1],\n          N: 1\n        });\n        stops.push(fn);\n        fn.end();\n      }\n      if (stops.length === 1) {\n        fn = stops[0];\n      } else {\n        fn = this.doc.ref({\n          FunctionType: 3,\n          Domain: [0, 1],\n          Functions: stops,\n          Bounds: bounds,\n          Encode: encode\n        });\n        fn.end();\n      }\n      this.id = 'Sh' + (++this.doc._gradCount);\n      shader = this.shader(fn);\n      shader.end();\n      pattern = this.doc.ref({\n        Type: 'Pattern',\n        PatternType: 2,\n        Shading: shader,\n        Matrix: (function() {\n          var k, len, ref1, results;\n          ref1 = this.matrix;\n          results = [];\n          for (k = 0, len = ref1.length; k < len; k++) {\n            v = ref1[k];\n            results.push(+v.toFixed(5));\n          }\n          return results;\n        }).call(this)\n      });\n      pattern.end();\n      if (this.stops.some(function(stop) {\n        return stop[2] < 1;\n      })) {\n        grad = this.opacityGradient();\n        grad._colorSpace = 'DeviceGray';\n        ref1 = this.stops;\n        for (k = 0, len = ref1.length; k < len; k++) {\n          stop = ref1[k];\n          grad.stop(stop[0], [stop[2]]);\n        }\n        grad = grad.embed(this.matrix);\n        pageBBox = [0, 0, this.doc.page.width, this.doc.page.height];\n        form = this.doc.ref({\n          Type: 'XObject',\n          Subtype: 'Form',\n          FormType: 1,\n          BBox: pageBBox,\n          Group: {\n            Type: 'Group',\n            S: 'Transparency',\n            CS: 'DeviceGray'\n          },\n          Resources: {\n            ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'],\n            Pattern: {\n              Sh1: grad\n            }\n          }\n        });\n        form.write(\"/Pattern cs /Sh1 scn\");\n        form.end((pageBBox.join(\" \")) + \" re f\");\n        gstate = this.doc.ref({\n          Type: 'ExtGState',\n          SMask: {\n            Type: 'Mask',\n            S: 'Luminosity',\n            G: form\n          }\n        });\n        gstate.end();\n        opacityPattern = this.doc.ref({\n          Type: 'Pattern',\n          PatternType: 1,\n          PaintType: 1,\n          TilingType: 2,\n          BBox: pageBBox,\n          XStep: pageBBox[2],\n          YStep: pageBBox[3],\n          Resources: {\n            ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'],\n            Pattern: {\n              Sh1: pattern\n            },\n            ExtGState: {\n              Gs1: gstate\n            }\n          }\n        });\n        opacityPattern.write(\"/Gs1 gs /Pattern cs /Sh1 scn\");\n        opacityPattern.end((pageBBox.join(\" \")) + \" re f\");\n        this.doc.page.patterns[this.id] = opacityPattern;\n      } else {\n        this.doc.page.patterns[this.id] = pattern;\n      }\n      return pattern;\n    };\n\n    PDFGradient.prototype.apply = function(op) {\n      var dx, dy, m, m0, m1, m11, m12, m2, m21, m22, m3, m4, m5, ref, ref1;\n      ref = this.doc._ctm.slice(), m0 = ref[0], m1 = ref[1], m2 = ref[2], m3 = ref[3], m4 = ref[4], m5 = ref[5];\n      ref1 = this.transform, m11 = ref1[0], m12 = ref1[1], m21 = ref1[2], m22 = ref1[3], dx = ref1[4], dy = ref1[5];\n      m = [m0 * m11 + m2 * m12, m1 * m11 + m3 * m12, m0 * m21 + m2 * m22, m1 * m21 + m3 * m22, m0 * dx + m2 * dy + m4, m1 * dx + m3 * dy + m5];\n      if (!(this.embedded && m.join(\" \") === this.matrix.join(\" \"))) {\n        this.embed(m);\n      }\n      return this.doc.addContent(\"/\" + this.id + \" \" + op);\n    };\n\n    return PDFGradient;\n\n  })();\n\n  PDFLinearGradient = (function(superClass) {\n    extend(PDFLinearGradient, superClass);\n\n    function PDFLinearGradient(doc, x1, y1, x2, y2) {\n      this.doc = doc;\n      this.x1 = x1;\n      this.y1 = y1;\n      this.x2 = x2;\n      this.y2 = y2;\n      PDFLinearGradient.__super__.constructor.apply(this, arguments);\n    }\n\n    PDFLinearGradient.prototype.shader = function(fn) {\n      return this.doc.ref({\n        ShadingType: 2,\n        ColorSpace: this._colorSpace,\n        Coords: [this.x1, this.y1, this.x2, this.y2],\n        Function: fn,\n        Extend: [true, true]\n      });\n    };\n\n    PDFLinearGradient.prototype.opacityGradient = function() {\n      return new PDFLinearGradient(this.doc, this.x1, this.y1, this.x2, this.y2);\n    };\n\n    return PDFLinearGradient;\n\n  })(PDFGradient);\n\n  PDFRadialGradient = (function(superClass) {\n    extend(PDFRadialGradient, superClass);\n\n    function PDFRadialGradient(doc, x1, y1, r1, x2, y2, r2) {\n      this.doc = doc;\n      this.x1 = x1;\n      this.y1 = y1;\n      this.r1 = r1;\n      this.x2 = x2;\n      this.y2 = y2;\n      this.r2 = r2;\n      PDFRadialGradient.__super__.constructor.apply(this, arguments);\n    }\n\n    PDFRadialGradient.prototype.shader = function(fn) {\n      return this.doc.ref({\n        ShadingType: 3,\n        ColorSpace: this._colorSpace,\n        Coords: [this.x1, this.y1, this.r1, this.x2, this.y2, this.r2],\n        Function: fn,\n        Extend: [true, true]\n      });\n    };\n\n    PDFRadialGradient.prototype.opacityGradient = function() {\n      return new PDFRadialGradient(this.doc, this.x1, this.y1, this.r1, this.x2, this.y2, this.r2);\n    };\n\n    return PDFRadialGradient;\n\n  })(PDFGradient);\n\n  module.exports = {\n    PDFGradient: PDFGradient,\n    PDFLinearGradient: PDFLinearGradient,\n    PDFRadialGradient: PDFRadialGradient\n  };\n\n}).call(this);\n\n\n/***/ }),\n/* 164 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var KAPPA, SVGPath, number,\n    slice = [].slice;\n\n  SVGPath = __webpack_require__(165);\n\n  number = __webpack_require__(26).number;\n\n  KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0);\n\n  module.exports = {\n    initVector: function() {\n      this._ctm = [1, 0, 0, 1, 0, 0];\n      return this._ctmStack = [];\n    },\n    save: function() {\n      this._ctmStack.push(this._ctm.slice());\n      return this.addContent('q');\n    },\n    restore: function() {\n      this._ctm = this._ctmStack.pop() || [1, 0, 0, 1, 0, 0];\n      return this.addContent('Q');\n    },\n    closePath: function() {\n      return this.addContent('h');\n    },\n    lineWidth: function(w) {\n      return this.addContent((number(w)) + \" w\");\n    },\n    _CAP_STYLES: {\n      BUTT: 0,\n      ROUND: 1,\n      SQUARE: 2\n    },\n    lineCap: function(c) {\n      if (typeof c === 'string') {\n        c = this._CAP_STYLES[c.toUpperCase()];\n      }\n      return this.addContent(c + \" J\");\n    },\n    _JOIN_STYLES: {\n      MITER: 0,\n      ROUND: 1,\n      BEVEL: 2\n    },\n    lineJoin: function(j) {\n      if (typeof j === 'string') {\n        j = this._JOIN_STYLES[j.toUpperCase()];\n      }\n      return this.addContent(j + \" j\");\n    },\n    miterLimit: function(m) {\n      return this.addContent((number(m)) + \" M\");\n    },\n    dash: function(length, options) {\n      var phase, ref, space, v;\n      if (options == null) {\n        options = {};\n      }\n      if (length == null) {\n        return this;\n      }\n      if (Array.isArray(length)) {\n        length = ((function() {\n          var i, len, results;\n          results = [];\n          for (i = 0, len = length.length; i < len; i++) {\n            v = length[i];\n            results.push(number(v));\n          }\n          return results;\n        })()).join(' ');\n        phase = options.phase || 0;\n        return this.addContent(\"[\" + length + \"] \" + (number(phase)) + \" d\");\n      } else {\n        space = (ref = options.space) != null ? ref : length;\n        phase = options.phase || 0;\n        return this.addContent(\"[\" + (number(length)) + \" \" + (number(space)) + \"] \" + (number(phase)) + \" d\");\n      }\n    },\n    undash: function() {\n      return this.addContent(\"[] 0 d\");\n    },\n    moveTo: function(x, y) {\n      return this.addContent((number(x)) + \" \" + (number(y)) + \" m\");\n    },\n    lineTo: function(x, y) {\n      return this.addContent((number(x)) + \" \" + (number(y)) + \" l\");\n    },\n    bezierCurveTo: function(cp1x, cp1y, cp2x, cp2y, x, y) {\n      return this.addContent((number(cp1x)) + \" \" + (number(cp1y)) + \" \" + (number(cp2x)) + \" \" + (number(cp2y)) + \" \" + (number(x)) + \" \" + (number(y)) + \" c\");\n    },\n    quadraticCurveTo: function(cpx, cpy, x, y) {\n      return this.addContent((number(cpx)) + \" \" + (number(cpy)) + \" \" + (number(x)) + \" \" + (number(y)) + \" v\");\n    },\n    rect: function(x, y, w, h) {\n      return this.addContent((number(x)) + \" \" + (number(y)) + \" \" + (number(w)) + \" \" + (number(h)) + \" re\");\n    },\n    roundedRect: function(x, y, w, h, r) {\n      var c;\n      if (r == null) {\n        r = 0;\n      }\n      r = Math.min(r, 0.5 * w, 0.5 * h);\n      c = r * (1.0 - KAPPA);\n      this.moveTo(x + r, y);\n      this.lineTo(x + w - r, y);\n      this.bezierCurveTo(x + w - c, y, x + w, y + c, x + w, y + r);\n      this.lineTo(x + w, y + h - r);\n      this.bezierCurveTo(x + w, y + h - c, x + w - c, y + h, x + w - r, y + h);\n      this.lineTo(x + r, y + h);\n      this.bezierCurveTo(x + c, y + h, x, y + h - c, x, y + h - r);\n      this.lineTo(x, y + r);\n      this.bezierCurveTo(x, y + c, x + c, y, x + r, y);\n      return this.closePath();\n    },\n    ellipse: function(x, y, r1, r2) {\n      var ox, oy, xe, xm, ye, ym;\n      if (r2 == null) {\n        r2 = r1;\n      }\n      x -= r1;\n      y -= r2;\n      ox = r1 * KAPPA;\n      oy = r2 * KAPPA;\n      xe = x + r1 * 2;\n      ye = y + r2 * 2;\n      xm = x + r1;\n      ym = y + r2;\n      this.moveTo(x, ym);\n      this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);\n      this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);\n      this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);\n      this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);\n      return this.closePath();\n    },\n    circle: function(x, y, radius) {\n      return this.ellipse(x, y, radius);\n    },\n    arc: function(x, y, radius, startAngle, endAngle, anticlockwise) {\n      var HALF_PI, TWO_PI, ax, ay, cp1x, cp1y, cp2x, cp2y, curAng, deltaAng, deltaCx, deltaCy, dir, handleLen, i, numSegs, ref, segAng, segIdx;\n      if (anticlockwise == null) {\n        anticlockwise = false;\n      }\n      TWO_PI = 2.0 * Math.PI;\n      HALF_PI = 0.5 * Math.PI;\n      deltaAng = endAngle - startAngle;\n      if (Math.abs(deltaAng) > TWO_PI) {\n        deltaAng = TWO_PI;\n      } else if (deltaAng !== 0 && anticlockwise !== (deltaAng < 0)) {\n        dir = anticlockwise ? -1 : 1;\n        deltaAng = dir * TWO_PI + deltaAng;\n      }\n      numSegs = Math.ceil(Math.abs(deltaAng) / HALF_PI);\n      segAng = deltaAng / numSegs;\n      handleLen = (segAng / HALF_PI) * KAPPA * radius;\n      curAng = startAngle;\n      deltaCx = -Math.sin(curAng) * handleLen;\n      deltaCy = Math.cos(curAng) * handleLen;\n      ax = x + Math.cos(curAng) * radius;\n      ay = y + Math.sin(curAng) * radius;\n      this.moveTo(ax, ay);\n      for (segIdx = i = 0, ref = numSegs; 0 <= ref ? i < ref : i > ref; segIdx = 0 <= ref ? ++i : --i) {\n        cp1x = ax + deltaCx;\n        cp1y = ay + deltaCy;\n        curAng += segAng;\n        ax = x + Math.cos(curAng) * radius;\n        ay = y + Math.sin(curAng) * radius;\n        deltaCx = -Math.sin(curAng) * handleLen;\n        deltaCy = Math.cos(curAng) * handleLen;\n        cp2x = ax - deltaCx;\n        cp2y = ay - deltaCy;\n        this.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, ax, ay);\n      }\n      return this;\n    },\n    polygon: function() {\n      var i, len, point, points;\n      points = 1 <= arguments.length ? slice.call(arguments, 0) : [];\n      this.moveTo.apply(this, points.shift());\n      for (i = 0, len = points.length; i < len; i++) {\n        point = points[i];\n        this.lineTo.apply(this, point);\n      }\n      return this.closePath();\n    },\n    path: function(path) {\n      SVGPath.apply(this, path);\n      return this;\n    },\n    _windingRule: function(rule) {\n      if (/even-?odd/.test(rule)) {\n        return '*';\n      }\n      return '';\n    },\n    fill: function(color, rule) {\n      if (/(even-?odd)|(non-?zero)/.test(color)) {\n        rule = color;\n        color = null;\n      }\n      if (color) {\n        this.fillColor(color);\n      }\n      return this.addContent('f' + this._windingRule(rule));\n    },\n    stroke: function(color) {\n      if (color) {\n        this.strokeColor(color);\n      }\n      return this.addContent('S');\n    },\n    fillAndStroke: function(fillColor, strokeColor, rule) {\n      var isFillRule;\n      if (strokeColor == null) {\n        strokeColor = fillColor;\n      }\n      isFillRule = /(even-?odd)|(non-?zero)/;\n      if (isFillRule.test(fillColor)) {\n        rule = fillColor;\n        fillColor = null;\n      }\n      if (isFillRule.test(strokeColor)) {\n        rule = strokeColor;\n        strokeColor = fillColor;\n      }\n      if (fillColor) {\n        this.fillColor(fillColor);\n        this.strokeColor(strokeColor);\n      }\n      return this.addContent('B' + this._windingRule(rule));\n    },\n    clip: function(rule) {\n      return this.addContent('W' + this._windingRule(rule) + ' n');\n    },\n    transform: function(m11, m12, m21, m22, dx, dy) {\n      var m, m0, m1, m2, m3, m4, m5, v, values;\n      m = this._ctm;\n      m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3], m4 = m[4], m5 = m[5];\n      m[0] = m0 * m11 + m2 * m12;\n      m[1] = m1 * m11 + m3 * m12;\n      m[2] = m0 * m21 + m2 * m22;\n      m[3] = m1 * m21 + m3 * m22;\n      m[4] = m0 * dx + m2 * dy + m4;\n      m[5] = m1 * dx + m3 * dy + m5;\n      values = ((function() {\n        var i, len, ref, results;\n        ref = [m11, m12, m21, m22, dx, dy];\n        results = [];\n        for (i = 0, len = ref.length; i < len; i++) {\n          v = ref[i];\n          results.push(number(v));\n        }\n        return results;\n      })()).join(' ');\n      return this.addContent(values + \" cm\");\n    },\n    translate: function(x, y) {\n      return this.transform(1, 0, 0, 1, x, y);\n    },\n    rotate: function(angle, options) {\n      var cos, rad, ref, sin, x, x1, y, y1;\n      if (options == null) {\n        options = {};\n      }\n      rad = angle * Math.PI / 180;\n      cos = Math.cos(rad);\n      sin = Math.sin(rad);\n      x = y = 0;\n      if (options.origin != null) {\n        ref = options.origin, x = ref[0], y = ref[1];\n        x1 = x * cos - y * sin;\n        y1 = x * sin + y * cos;\n        x -= x1;\n        y -= y1;\n      }\n      return this.transform(cos, sin, -sin, cos, x, y);\n    },\n    scale: function(xFactor, yFactor, options) {\n      var ref, x, y;\n      if (yFactor == null) {\n        yFactor = xFactor;\n      }\n      if (options == null) {\n        options = {};\n      }\n      if (typeof yFactor === \"object\") {\n        options = yFactor;\n        yFactor = xFactor;\n      }\n      x = y = 0;\n      if (options.origin != null) {\n        ref = options.origin, x = ref[0], y = ref[1];\n        x -= xFactor * x;\n        y -= yFactor * y;\n      }\n      return this.transform(xFactor, 0, 0, yFactor, x, y);\n    }\n  };\n\n}).call(this);\n\n\n/***/ }),\n/* 165 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var SVGPath;\n\n  SVGPath = (function() {\n    var apply, arcToSegments, cx, cy, parameters, parse, px, py, runners, segmentToBezier, solveArc, sx, sy;\n\n    function SVGPath() {}\n\n    SVGPath.apply = function(doc, path) {\n      var commands;\n      commands = parse(path);\n      return apply(commands, doc);\n    };\n\n    parameters = {\n      A: 7,\n      a: 7,\n      C: 6,\n      c: 6,\n      H: 1,\n      h: 1,\n      L: 2,\n      l: 2,\n      M: 2,\n      m: 2,\n      Q: 4,\n      q: 4,\n      S: 4,\n      s: 4,\n      T: 2,\n      t: 2,\n      V: 1,\n      v: 1,\n      Z: 0,\n      z: 0\n    };\n\n    parse = function(path) {\n      var args, c, cmd, curArg, foundDecimal, j, len, params, ret;\n      ret = [];\n      args = [];\n      curArg = \"\";\n      foundDecimal = false;\n      params = 0;\n      for (j = 0, len = path.length; j < len; j++) {\n        c = path[j];\n        if (parameters[c] != null) {\n          params = parameters[c];\n          if (cmd) {\n            if (curArg.length > 0) {\n              args[args.length] = +curArg;\n            }\n            ret[ret.length] = {\n              cmd: cmd,\n              args: args\n            };\n            args = [];\n            curArg = \"\";\n            foundDecimal = false;\n          }\n          cmd = c;\n        } else if ((c === \" \" || c === \",\") || (c === \"-\" && curArg.length > 0 && curArg[curArg.length - 1] !== 'e') || (c === \".\" && foundDecimal)) {\n          if (curArg.length === 0) {\n            continue;\n          }\n          if (args.length === params) {\n            ret[ret.length] = {\n              cmd: cmd,\n              args: args\n            };\n            args = [+curArg];\n            if (cmd === \"M\") {\n              cmd = \"L\";\n            }\n            if (cmd === \"m\") {\n              cmd = \"l\";\n            }\n          } else {\n            args[args.length] = +curArg;\n          }\n          foundDecimal = c === \".\";\n          curArg = c === '-' || c === '.' ? c : '';\n        } else {\n          curArg += c;\n          if (c === '.') {\n            foundDecimal = true;\n          }\n        }\n      }\n      if (curArg.length > 0) {\n        if (args.length === params) {\n          ret[ret.length] = {\n            cmd: cmd,\n            args: args\n          };\n          args = [+curArg];\n          if (cmd === \"M\") {\n            cmd = \"L\";\n          }\n          if (cmd === \"m\") {\n            cmd = \"l\";\n          }\n        } else {\n          args[args.length] = +curArg;\n        }\n      }\n      ret[ret.length] = {\n        cmd: cmd,\n        args: args\n      };\n      return ret;\n    };\n\n    cx = cy = px = py = sx = sy = 0;\n\n    apply = function(commands, doc) {\n      var c, i, j, len, name;\n      cx = cy = px = py = sx = sy = 0;\n      for (i = j = 0, len = commands.length; j < len; i = ++j) {\n        c = commands[i];\n        if (typeof runners[name = c.cmd] === \"function\") {\n          runners[name](doc, c.args);\n        }\n      }\n      return cx = cy = px = py = 0;\n    };\n\n    runners = {\n      M: function(doc, a) {\n        cx = a[0];\n        cy = a[1];\n        px = py = null;\n        sx = cx;\n        sy = cy;\n        return doc.moveTo(cx, cy);\n      },\n      m: function(doc, a) {\n        cx += a[0];\n        cy += a[1];\n        px = py = null;\n        sx = cx;\n        sy = cy;\n        return doc.moveTo(cx, cy);\n      },\n      C: function(doc, a) {\n        cx = a[4];\n        cy = a[5];\n        px = a[2];\n        py = a[3];\n        return doc.bezierCurveTo.apply(doc, a);\n      },\n      c: function(doc, a) {\n        doc.bezierCurveTo(a[0] + cx, a[1] + cy, a[2] + cx, a[3] + cy, a[4] + cx, a[5] + cy);\n        px = cx + a[2];\n        py = cy + a[3];\n        cx += a[4];\n        return cy += a[5];\n      },\n      S: function(doc, a) {\n        if (px === null) {\n          px = cx;\n          py = cy;\n        }\n        doc.bezierCurveTo(cx - (px - cx), cy - (py - cy), a[0], a[1], a[2], a[3]);\n        px = a[0];\n        py = a[1];\n        cx = a[2];\n        return cy = a[3];\n      },\n      s: function(doc, a) {\n        if (px === null) {\n          px = cx;\n          py = cy;\n        }\n        doc.bezierCurveTo(cx - (px - cx), cy - (py - cy), cx + a[0], cy + a[1], cx + a[2], cy + a[3]);\n        px = cx + a[0];\n        py = cy + a[1];\n        cx += a[2];\n        return cy += a[3];\n      },\n      Q: function(doc, a) {\n        px = a[0];\n        py = a[1];\n        cx = a[2];\n        cy = a[3];\n        return doc.quadraticCurveTo(a[0], a[1], cx, cy);\n      },\n      q: function(doc, a) {\n        doc.quadraticCurveTo(a[0] + cx, a[1] + cy, a[2] + cx, a[3] + cy);\n        px = cx + a[0];\n        py = cy + a[1];\n        cx += a[2];\n        return cy += a[3];\n      },\n      T: function(doc, a) {\n        if (px === null) {\n          px = cx;\n          py = cy;\n        } else {\n          px = cx - (px - cx);\n          py = cy - (py - cy);\n        }\n        doc.quadraticCurveTo(px, py, a[0], a[1]);\n        px = cx - (px - cx);\n        py = cy - (py - cy);\n        cx = a[0];\n        return cy = a[1];\n      },\n      t: function(doc, a) {\n        if (px === null) {\n          px = cx;\n          py = cy;\n        } else {\n          px = cx - (px - cx);\n          py = cy - (py - cy);\n        }\n        doc.quadraticCurveTo(px, py, cx + a[0], cy + a[1]);\n        cx += a[0];\n        return cy += a[1];\n      },\n      A: function(doc, a) {\n        solveArc(doc, cx, cy, a);\n        cx = a[5];\n        return cy = a[6];\n      },\n      a: function(doc, a) {\n        a[5] += cx;\n        a[6] += cy;\n        solveArc(doc, cx, cy, a);\n        cx = a[5];\n        return cy = a[6];\n      },\n      L: function(doc, a) {\n        cx = a[0];\n        cy = a[1];\n        px = py = null;\n        return doc.lineTo(cx, cy);\n      },\n      l: function(doc, a) {\n        cx += a[0];\n        cy += a[1];\n        px = py = null;\n        return doc.lineTo(cx, cy);\n      },\n      H: function(doc, a) {\n        cx = a[0];\n        px = py = null;\n        return doc.lineTo(cx, cy);\n      },\n      h: function(doc, a) {\n        cx += a[0];\n        px = py = null;\n        return doc.lineTo(cx, cy);\n      },\n      V: function(doc, a) {\n        cy = a[0];\n        px = py = null;\n        return doc.lineTo(cx, cy);\n      },\n      v: function(doc, a) {\n        cy += a[0];\n        px = py = null;\n        return doc.lineTo(cx, cy);\n      },\n      Z: function(doc) {\n        doc.closePath();\n        cx = sx;\n        return cy = sy;\n      },\n      z: function(doc) {\n        doc.closePath();\n        cx = sx;\n        return cy = sy;\n      }\n    };\n\n    solveArc = function(doc, x, y, coords) {\n      var bez, ex, ey, j, large, len, results, rot, rx, ry, seg, segs, sweep;\n      rx = coords[0], ry = coords[1], rot = coords[2], large = coords[3], sweep = coords[4], ex = coords[5], ey = coords[6];\n      segs = arcToSegments(ex, ey, rx, ry, large, sweep, rot, x, y);\n      results = [];\n      for (j = 0, len = segs.length; j < len; j++) {\n        seg = segs[j];\n        bez = segmentToBezier.apply(null, seg);\n        results.push(doc.bezierCurveTo.apply(doc, bez));\n      }\n      return results;\n    };\n\n    arcToSegments = function(x, y, rx, ry, large, sweep, rotateX, ox, oy) {\n      var a00, a01, a10, a11, cos_th, d, i, j, pl, ref, result, segments, sfactor, sfactor_sq, sin_th, th, th0, th1, th2, th3, th_arc, x0, x1, xc, y0, y1, yc;\n      th = rotateX * (Math.PI / 180);\n      sin_th = Math.sin(th);\n      cos_th = Math.cos(th);\n      rx = Math.abs(rx);\n      ry = Math.abs(ry);\n      px = cos_th * (ox - x) * 0.5 + sin_th * (oy - y) * 0.5;\n      py = cos_th * (oy - y) * 0.5 - sin_th * (ox - x) * 0.5;\n      pl = (px * px) / (rx * rx) + (py * py) / (ry * ry);\n      if (pl > 1) {\n        pl = Math.sqrt(pl);\n        rx *= pl;\n        ry *= pl;\n      }\n      a00 = cos_th / rx;\n      a01 = sin_th / rx;\n      a10 = (-sin_th) / ry;\n      a11 = cos_th / ry;\n      x0 = a00 * ox + a01 * oy;\n      y0 = a10 * ox + a11 * oy;\n      x1 = a00 * x + a01 * y;\n      y1 = a10 * x + a11 * y;\n      d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);\n      sfactor_sq = 1 / d - 0.25;\n      if (sfactor_sq < 0) {\n        sfactor_sq = 0;\n      }\n      sfactor = Math.sqrt(sfactor_sq);\n      if (sweep === large) {\n        sfactor = -sfactor;\n      }\n      xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);\n      yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);\n      th0 = Math.atan2(y0 - yc, x0 - xc);\n      th1 = Math.atan2(y1 - yc, x1 - xc);\n      th_arc = th1 - th0;\n      if (th_arc < 0 && sweep === 1) {\n        th_arc += 2 * Math.PI;\n      } else if (th_arc > 0 && sweep === 0) {\n        th_arc -= 2 * Math.PI;\n      }\n      segments = Math.ceil(Math.abs(th_arc / (Math.PI * 0.5 + 0.001)));\n      result = [];\n      for (i = j = 0, ref = segments; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {\n        th2 = th0 + i * th_arc / segments;\n        th3 = th0 + (i + 1) * th_arc / segments;\n        result[i] = [xc, yc, th2, th3, rx, ry, sin_th, cos_th];\n      }\n      return result;\n    };\n\n    segmentToBezier = function(cx, cy, th0, th1, rx, ry, sin_th, cos_th) {\n      var a00, a01, a10, a11, t, th_half, x1, x2, x3, y1, y2, y3;\n      a00 = cos_th * rx;\n      a01 = -sin_th * ry;\n      a10 = sin_th * rx;\n      a11 = cos_th * ry;\n      th_half = 0.5 * (th1 - th0);\n      t = (8 / 3) * Math.sin(th_half * 0.5) * Math.sin(th_half * 0.5) / Math.sin(th_half);\n      x1 = cx + Math.cos(th0) - t * Math.sin(th0);\n      y1 = cy + Math.sin(th0) + t * Math.cos(th0);\n      x3 = cx + Math.cos(th1);\n      y3 = cy + Math.sin(th1);\n      x2 = x3 + t * Math.sin(th1);\n      y2 = y3 - t * Math.cos(th1);\n      return [a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, a00 * x3 + a01 * y3, a10 * x3 + a11 * y3];\n    };\n\n    return SVGPath;\n\n  })();\n\n  module.exports = SVGPath;\n\n}).call(this);\n\n\n/***/ }),\n/* 166 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var PDFFont;\n\n  PDFFont = __webpack_require__(50);\n\n  module.exports = {\n    initFonts: function() {\n      this._fontFamilies = {};\n      this._fontCount = 0;\n      this._fontSize = 12;\n      this._font = null;\n      this._registeredFonts = {};\n      \n    },\n    font: function(src, family, size) {\n      var cacheKey, font, id, ref;\n      if (typeof family === 'number') {\n        size = family;\n        family = null;\n      }\n      if (typeof src === 'string' && this._registeredFonts[src]) {\n        cacheKey = src;\n        ref = this._registeredFonts[src], src = ref.src, family = ref.family;\n      } else {\n        cacheKey = family || src;\n        if (typeof cacheKey !== 'string') {\n          cacheKey = null;\n        }\n      }\n      if (size != null) {\n        this.fontSize(size);\n      }\n      if (font = this._fontFamilies[cacheKey]) {\n        this._font = font;\n        return this;\n      }\n      id = 'F' + (++this._fontCount);\n      this._font = PDFFont.open(this, src, family, id);\n      if (font = this._fontFamilies[this._font.name]) {\n        this._font = font;\n        return this;\n      }\n      if (cacheKey) {\n        this._fontFamilies[cacheKey] = this._font;\n      }\n      if (this._font.name) {\n        this._fontFamilies[this._font.name] = this._font;\n      }\n      return this;\n    },\n    fontSize: function(_fontSize) {\n      this._fontSize = _fontSize;\n      return this;\n    },\n    currentLineHeight: function(includeGap) {\n      if (includeGap == null) {\n        includeGap = false;\n      }\n      return this._font.lineHeight(this._fontSize, includeGap);\n    },\n    registerFont: function(name, src, family) {\n      this._registeredFonts[name] = {\n        src: src,\n        family: family\n      };\n      return this;\n    }\n  };\n\n}).call(this);\n\n\n/***/ }),\n/* 167 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(Buffer, process) {\n\nfunction _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }\n\nvar r = _interopDefault(__webpack_require__(168));\nvar _Object$getOwnPropertyDescriptor = _interopDefault(__webpack_require__(197));\nvar _getIterator = _interopDefault(__webpack_require__(60));\nvar _Object$freeze = _interopDefault(__webpack_require__(209));\nvar _Object$keys = _interopDefault(__webpack_require__(212));\nvar _typeof = _interopDefault(__webpack_require__(69));\nvar _Object$defineProperty = _interopDefault(__webpack_require__(74));\nvar _classCallCheck = _interopDefault(__webpack_require__(106));\nvar _createClass = _interopDefault(__webpack_require__(107));\nvar _Map = _interopDefault(__webpack_require__(225));\nvar _possibleConstructorReturn = _interopDefault(__webpack_require__(236));\nvar _inherits = _interopDefault(__webpack_require__(237));\nvar restructure_src_utils = __webpack_require__(12);\nvar _Object$defineProperties = _interopDefault(__webpack_require__(245));\nvar isEqual = _interopDefault(__webpack_require__(248));\nvar _Object$assign = _interopDefault(__webpack_require__(251));\nvar _String$fromCodePoint = _interopDefault(__webpack_require__(255));\nvar _Array$from = _interopDefault(__webpack_require__(258));\nvar _Set = _interopDefault(__webpack_require__(263));\nvar unicode = _interopDefault(__webpack_require__(269));\nvar UnicodeTrie = _interopDefault(__webpack_require__(43));\nvar StateMachine = _interopDefault(__webpack_require__(271));\nvar _Number$EPSILON = _interopDefault(__webpack_require__(280));\nvar cloneDeep = _interopDefault(__webpack_require__(283));\nvar inflate = _interopDefault(__webpack_require__(79));\nvar brotli = _interopDefault(__webpack_require__(284));\n\n\n\nvar fontkit = {};\nfontkit.logErrors = false;\n\nvar formats = [];\nfontkit.registerFormat = function (format) {\n  formats.push(format);\n};\n\nfontkit.openSync = function (filename, postscriptName) {\n  var buffer = __webpack_require__(8).readFileSync(filename);\n  return fontkit.create(buffer, postscriptName);\n};\n\nfontkit.open = function (filename, postscriptName, callback) {\n  if (typeof postscriptName === 'function') {\n    callback = postscriptName;\n    postscriptName = null;\n  }\n\n  __webpack_require__(8).readFile(filename, function (err, buffer) {\n    if (err) {\n      return callback(err);\n    }\n\n    try {\n      var font = fontkit.create(buffer, postscriptName);\n    } catch (e) {\n      return callback(e);\n    }\n\n    return callback(null, font);\n  });\n\n  return;\n};\n\nfontkit.create = function (buffer, postscriptName) {\n  for (var i = 0; i < formats.length; i++) {\n    var format = formats[i];\n    if (format.probe(buffer)) {\n      var font = new format(new r.DecodeStream(buffer));\n      if (postscriptName) {\n        return font.getFont(postscriptName);\n      }\n\n      return font;\n    }\n  }\n\n  throw new Error('Unknown font format');\n};\n\n/**\n * This decorator caches the results of a getter or method such that\n * the results are lazily computed once, and then cached.\n * @private\n */\nfunction cache(target, key, descriptor) {\n  if (descriptor.get) {\n    var get = descriptor.get;\n    descriptor.get = function () {\n      var value = get.call(this);\n      _Object$defineProperty(this, key, { value: value });\n      return value;\n    };\n  } else if (typeof descriptor.value === 'function') {\n    var fn = descriptor.value;\n\n    return {\n      get: function get() {\n        var cache = new _Map();\n        function memoized() {\n          for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {\n            args[_key] = arguments[_key];\n          }\n\n          var key = args.length > 0 ? args[0] : 'value';\n          if (cache.has(key)) {\n            return cache.get(key);\n          }\n\n          var result = fn.apply(this, args);\n          cache.set(key, result);\n          return result;\n        };\n\n        _Object$defineProperty(this, key, { value: memoized });\n        return memoized;\n      }\n    };\n  }\n}\n\nvar SubHeader = new r.Struct({\n  firstCode: r.uint16,\n  entryCount: r.uint16,\n  idDelta: r.int16,\n  idRangeOffset: r.uint16\n});\n\nvar CmapGroup = new r.Struct({\n  startCharCode: r.uint32,\n  endCharCode: r.uint32,\n  glyphID: r.uint32\n});\n\nvar UnicodeValueRange = new r.Struct({\n  startUnicodeValue: r.uint24,\n  additionalCount: r.uint8\n});\n\nvar UVSMapping = new r.Struct({\n  unicodeValue: r.uint24,\n  glyphID: r.uint16\n});\n\nvar DefaultUVS = new r.Array(UnicodeValueRange, r.uint32);\nvar NonDefaultUVS = new r.Array(UVSMapping, r.uint32);\n\nvar VarSelectorRecord = new r.Struct({\n  varSelector: r.uint24,\n  defaultUVS: new r.Pointer(r.uint32, DefaultUVS, { type: 'parent' }),\n  nonDefaultUVS: new r.Pointer(r.uint32, NonDefaultUVS, { type: 'parent' })\n});\n\nvar CmapSubtable = new r.VersionedStruct(r.uint16, {\n  0: { // Byte encoding\n    length: r.uint16, // Total table length in bytes (set to 262 for format 0)\n    language: r.uint16, // Language code for this encoding subtable, or zero if language-independent\n    codeMap: new r.LazyArray(r.uint8, 256)\n  },\n\n  2: { // High-byte mapping (CJK)\n    length: r.uint16,\n    language: r.uint16,\n    subHeaderKeys: new r.Array(r.uint16, 256),\n    subHeaderCount: function subHeaderCount(t) {\n      return Math.max.apply(Math, t.subHeaderKeys);\n    },\n    subHeaders: new r.LazyArray(SubHeader, 'subHeaderCount'),\n    glyphIndexArray: new r.LazyArray(r.uint16, 'subHeaderCount')\n  },\n\n  4: { // Segment mapping to delta values\n    length: r.uint16, // Total table length in bytes\n    language: r.uint16, // Language code\n    segCountX2: r.uint16,\n    segCount: function segCount(t) {\n      return t.segCountX2 >> 1;\n    },\n    searchRange: r.uint16,\n    entrySelector: r.uint16,\n    rangeShift: r.uint16,\n    endCode: new r.LazyArray(r.uint16, 'segCount'),\n    reservedPad: new r.Reserved(r.uint16), // This value should be zero\n    startCode: new r.LazyArray(r.uint16, 'segCount'),\n    idDelta: new r.LazyArray(r.int16, 'segCount'),\n    idRangeOffset: new r.LazyArray(r.uint16, 'segCount'),\n    glyphIndexArray: new r.LazyArray(r.uint16, function (t) {\n      return (t.length - t._currentOffset) / 2;\n    })\n  },\n\n  6: { // Trimmed table\n    length: r.uint16,\n    language: r.uint16,\n    firstCode: r.uint16,\n    entryCount: r.uint16,\n    glyphIndices: new r.LazyArray(r.uint16, 'entryCount')\n  },\n\n  8: { // mixed 16-bit and 32-bit coverage\n    reserved: new r.Reserved(r.uint16),\n    length: r.uint32,\n    language: r.uint16,\n    is32: new r.LazyArray(r.uint8, 8192),\n    nGroups: r.uint32,\n    groups: new r.LazyArray(CmapGroup, 'nGroups')\n  },\n\n  10: { // Trimmed Array\n    reserved: new r.Reserved(r.uint16),\n    length: r.uint32,\n    language: r.uint32,\n    firstCode: r.uint32,\n    entryCount: r.uint32,\n    glyphIndices: new r.LazyArray(r.uint16, 'numChars')\n  },\n\n  12: { // Segmented coverage\n    reserved: new r.Reserved(r.uint16),\n    length: r.uint32,\n    language: r.uint32,\n    nGroups: r.uint32,\n    groups: new r.LazyArray(CmapGroup, 'nGroups')\n  },\n\n  13: { // Many-to-one range mappings (same as 12 except for group.startGlyphID)\n    reserved: new r.Reserved(r.uint16),\n    length: r.uint32,\n    language: r.uint32,\n    nGroups: r.uint32,\n    groups: new r.LazyArray(CmapGroup, 'nGroups')\n  },\n\n  14: { // Unicode Variation Sequences\n    length: r.uint32,\n    numRecords: r.uint32,\n    varSelectors: new r.LazyArray(VarSelectorRecord, 'numRecords')\n  }\n});\n\nvar CmapEntry = new r.Struct({\n  platformID: r.uint16, // Platform identifier\n  encodingID: r.uint16, // Platform-specific encoding identifier\n  table: new r.Pointer(r.uint32, CmapSubtable, { type: 'parent', lazy: true })\n});\n\n// character to glyph mapping\nvar cmap = new r.Struct({\n  version: r.uint16,\n  numSubtables: r.uint16,\n  tables: new r.Array(CmapEntry, 'numSubtables')\n});\n\n// font header\nvar head = new r.Struct({\n  version: r.int32, // 0x00010000 (version 1.0)\n  revision: r.int32, // set by font manufacturer\n  checkSumAdjustment: r.uint32,\n  magicNumber: r.uint32, // set to 0x5F0F3CF5\n  flags: r.uint16,\n  unitsPerEm: r.uint16, // range from 64 to 16384\n  created: new r.Array(r.int32, 2),\n  modified: new r.Array(r.int32, 2),\n  xMin: r.int16, // for all glyph bounding boxes\n  yMin: r.int16, // for all glyph bounding boxes\n  xMax: r.int16, // for all glyph bounding boxes\n  yMax: r.int16, // for all glyph bounding boxes\n  macStyle: new r.Bitfield(r.uint16, ['bold', 'italic', 'underline', 'outline', 'shadow', 'condensed', 'extended']),\n  lowestRecPPEM: r.uint16, // smallest readable size in pixels\n  fontDirectionHint: r.int16,\n  indexToLocFormat: r.int16, // 0 for short offsets, 1 for long\n  glyphDataFormat: r.int16 // 0 for current format\n});\n\n// horizontal header\nvar hhea = new r.Struct({\n  version: r.int32,\n  ascent: r.int16, // Distance from baseline of highest ascender\n  descent: r.int16, // Distance from baseline of lowest descender\n  lineGap: r.int16, // Typographic line gap\n  advanceWidthMax: r.uint16, // Maximum advance width value in 'hmtx' table\n  minLeftSideBearing: r.int16, // Maximum advance width value in 'hmtx' table\n  minRightSideBearing: r.int16, // Minimum right sidebearing value\n  xMaxExtent: r.int16,\n  caretSlopeRise: r.int16, // Used to calculate the slope of the cursor (rise/run); 1 for vertical\n  caretSlopeRun: r.int16, // 0 for vertical\n  caretOffset: r.int16, // Set to 0 for non-slanted fonts\n  reserved: new r.Reserved(r.int16, 4),\n  metricDataFormat: r.int16, // 0 for current format\n  numberOfMetrics: r.uint16 // Number of advance widths in 'hmtx' table\n});\n\nvar HmtxEntry = new r.Struct({\n  advance: r.uint16,\n  bearing: r.int16\n});\n\nvar hmtx = new r.Struct({\n  metrics: new r.LazyArray(HmtxEntry, function (t) {\n    return t.parent.hhea.numberOfMetrics;\n  }),\n  bearings: new r.LazyArray(r.int16, function (t) {\n    return t.parent.maxp.numGlyphs - t.parent.hhea.numberOfMetrics;\n  })\n});\n\n// maxiumum profile\nvar maxp = new r.Struct({\n  version: r.int32,\n  numGlyphs: r.uint16, // The number of glyphs in the font\n  maxPoints: r.uint16, // Maximum points in a non-composite glyph\n  maxContours: r.uint16, // Maximum contours in a non-composite glyph\n  maxComponentPoints: r.uint16, // Maximum points in a composite glyph\n  maxComponentContours: r.uint16, // Maximum contours in a composite glyph\n  maxZones: r.uint16, // 1 if instructions do not use the twilight zone, 2 otherwise\n  maxTwilightPoints: r.uint16, // Maximum points used in Z0\n  maxStorage: r.uint16, // Number of Storage Area locations\n  maxFunctionDefs: r.uint16, // Number of FDEFs\n  maxInstructionDefs: r.uint16, // Number of IDEFs\n  maxStackElements: r.uint16, // Maximum stack depth\n  maxSizeOfInstructions: r.uint16, // Maximum byte count for glyph instructions\n  maxComponentElements: r.uint16, // Maximum number of components referenced at “top level” for any composite glyph\n  maxComponentDepth: r.uint16 // Maximum levels of recursion; 1 for simple components\n});\n\n/**\n * Gets an encoding name from platform, encoding, and language ids.\n * Returned encoding names can be used in iconv-lite to decode text.\n */\nfunction getEncoding(platformID, encodingID) {\n  var languageID = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n\n  if (platformID === 1 && MAC_LANGUAGE_ENCODINGS[languageID]) {\n    return MAC_LANGUAGE_ENCODINGS[languageID];\n  }\n\n  return ENCODINGS[platformID][encodingID];\n}\n\n// Map of platform ids to encoding ids.\nvar ENCODINGS = [\n// unicode\n['utf16be', 'utf16be', 'utf16be', 'utf16be', 'utf16be', 'utf16be'],\n\n// macintosh\n// Mappings available at http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/\n// 0\tRoman                 17\tMalayalam\n// 1\tJapanese\t            18\tSinhalese\n// 2\tTraditional Chinese\t  19\tBurmese\n// 3\tKorean\t              20\tKhmer\n// 4\tArabic\t              21\tThai\n// 5\tHebrew\t              22\tLaotian\n// 6\tGreek\t                23\tGeorgian\n// 7\tRussian\t              24\tArmenian\n// 8\tRSymbol\t              25\tSimplified Chinese\n// 9\tDevanagari\t          26\tTibetan\n// 10\tGurmukhi\t            27\tMongolian\n// 11\tGujarati\t            28\tGeez\n// 12\tOriya\t                29\tSlavic\n// 13\tBengali\t              30\tVietnamese\n// 14\tTamil\t                31\tSindhi\n// 15\tTelugu\t              32\t(Uninterpreted)\n// 16\tKannada\n['macroman', 'shift-jis', 'big5', 'euc-kr', 'iso-8859-6', 'iso-8859-8', 'macgreek', 'maccyrillic', 'symbol', 'Devanagari', 'Gurmukhi', 'Gujarati', 'Oriya', 'Bengali', 'Tamil', 'Telugu', 'Kannada', 'Malayalam', 'Sinhalese', 'Burmese', 'Khmer', 'macthai', 'Laotian', 'Georgian', 'Armenian', 'gb-2312-80', 'Tibetan', 'Mongolian', 'Geez', 'maccenteuro', 'Vietnamese', 'Sindhi'],\n\n// ISO (deprecated)\n['ascii'],\n\n// windows\n// Docs here: http://msdn.microsoft.com/en-us/library/system.text.encoding(v=vs.110).aspx\n['symbol', 'utf16be', 'shift-jis', 'gb18030', 'big5', 'wansung', 'johab', null, null, null, 'utf16be']];\n\n// Overrides for Mac scripts by language id.\n// See http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/Readme.txt\nvar MAC_LANGUAGE_ENCODINGS = {\n  15: 'maciceland',\n  17: 'macturkish',\n  18: 'maccroatian',\n  24: 'maccenteuro',\n  25: 'maccenteuro',\n  26: 'maccenteuro',\n  27: 'maccenteuro',\n  28: 'maccenteuro',\n  30: 'maciceland',\n  37: 'macromania',\n  38: 'maccenteuro',\n  39: 'maccenteuro',\n  40: 'maccenteuro',\n  143: 'macinuit', // Unsupported by iconv-lite\n  146: 'macgaelic' // Unsupported by iconv-lite\n};\n\n// Map of platform ids to BCP-47 language codes.\nvar LANGUAGES = [\n// unicode\n[], { // macintosh\n  0: 'en', 30: 'fo', 60: 'ks', 90: 'rw',\n  1: 'fr', 31: 'fa', 61: 'ku', 91: 'rn',\n  2: 'de', 32: 'ru', 62: 'sd', 92: 'ny',\n  3: 'it', 33: 'zh', 63: 'bo', 93: 'mg',\n  4: 'nl', 34: 'nl-BE', 64: 'ne', 94: 'eo',\n  5: 'sv', 35: 'ga', 65: 'sa', 128: 'cy',\n  6: 'es', 36: 'sq', 66: 'mr', 129: 'eu',\n  7: 'da', 37: 'ro', 67: 'bn', 130: 'ca',\n  8: 'pt', 38: 'cz', 68: 'as', 131: 'la',\n  9: 'no', 39: 'sk', 69: 'gu', 132: 'qu',\n  10: 'he', 40: 'si', 70: 'pa', 133: 'gn',\n  11: 'ja', 41: 'yi', 71: 'or', 134: 'ay',\n  12: 'ar', 42: 'sr', 72: 'ml', 135: 'tt',\n  13: 'fi', 43: 'mk', 73: 'kn', 136: 'ug',\n  14: 'el', 44: 'bg', 74: 'ta', 137: 'dz',\n  15: 'is', 45: 'uk', 75: 'te', 138: 'jv',\n  16: 'mt', 46: 'be', 76: 'si', 139: 'su',\n  17: 'tr', 47: 'uz', 77: 'my', 140: 'gl',\n  18: 'hr', 48: 'kk', 78: 'km', 141: 'af',\n  19: 'zh-Hant', 49: 'az-Cyrl', 79: 'lo', 142: 'br',\n  20: 'ur', 50: 'az-Arab', 80: 'vi', 143: 'iu',\n  21: 'hi', 51: 'hy', 81: 'id', 144: 'gd',\n  22: 'th', 52: 'ka', 82: 'tl', 145: 'gv',\n  23: 'ko', 53: 'mo', 83: 'ms', 146: 'ga',\n  24: 'lt', 54: 'ky', 84: 'ms-Arab', 147: 'to',\n  25: 'pl', 55: 'tg', 85: 'am', 148: 'el-polyton',\n  26: 'hu', 56: 'tk', 86: 'ti', 149: 'kl',\n  27: 'es', 57: 'mn-CN', 87: 'om', 150: 'az',\n  28: 'lv', 58: 'mn', 88: 'so', 151: 'nn',\n  29: 'se', 59: 'ps', 89: 'sw'\n},\n\n// ISO (deprecated)\n[], { // windows                                        \n  0x0436: 'af', 0x4009: 'en-IN', 0x0487: 'rw', 0x0432: 'tn',\n  0x041C: 'sq', 0x1809: 'en-IE', 0x0441: 'sw', 0x045B: 'si',\n  0x0484: 'gsw', 0x2009: 'en-JM', 0x0457: 'kok', 0x041B: 'sk',\n  0x045E: 'am', 0x4409: 'en-MY', 0x0412: 'ko', 0x0424: 'sl',\n  0x1401: 'ar-DZ', 0x1409: 'en-NZ', 0x0440: 'ky', 0x2C0A: 'es-AR',\n  0x3C01: 'ar-BH', 0x3409: 'en-PH', 0x0454: 'lo', 0x400A: 'es-BO',\n  0x0C01: 'ar', 0x4809: 'en-SG', 0x0426: 'lv', 0x340A: 'es-CL',\n  0x0801: 'ar-IQ', 0x1C09: 'en-ZA', 0x0427: 'lt', 0x240A: 'es-CO',\n  0x2C01: 'ar-JO', 0x2C09: 'en-TT', 0x082E: 'dsb', 0x140A: 'es-CR',\n  0x3401: 'ar-KW', 0x0809: 'en-GB', 0x046E: 'lb', 0x1C0A: 'es-DO',\n  0x3001: 'ar-LB', 0x0409: 'en', 0x042F: 'mk', 0x300A: 'es-EC',\n  0x1001: 'ar-LY', 0x3009: 'en-ZW', 0x083E: 'ms-BN', 0x440A: 'es-SV',\n  0x1801: 'ary', 0x0425: 'et', 0x043E: 'ms', 0x100A: 'es-GT',\n  0x2001: 'ar-OM', 0x0438: 'fo', 0x044C: 'ml', 0x480A: 'es-HN',\n  0x4001: 'ar-QA', 0x0464: 'fil', 0x043A: 'mt', 0x080A: 'es-MX',\n  0x0401: 'ar-SA', 0x040B: 'fi', 0x0481: 'mi', 0x4C0A: 'es-NI',\n  0x2801: 'ar-SY', 0x080C: 'fr-BE', 0x047A: 'arn', 0x180A: 'es-PA',\n  0x1C01: 'aeb', 0x0C0C: 'fr-CA', 0x044E: 'mr', 0x3C0A: 'es-PY',\n  0x3801: 'ar-AE', 0x040C: 'fr', 0x047C: 'moh', 0x280A: 'es-PE',\n  0x2401: 'ar-YE', 0x140C: 'fr-LU', 0x0450: 'mn', 0x500A: 'es-PR',\n  0x042B: 'hy', 0x180C: 'fr-MC', 0x0850: 'mn-CN', 0x0C0A: 'es',\n  0x044D: 'as', 0x100C: 'fr-CH', 0x0461: 'ne', 0x040A: 'es',\n  0x082C: 'az-Cyrl', 0x0462: 'fy', 0x0414: 'nb', 0x540A: 'es-US',\n  0x042C: 'az', 0x0456: 'gl', 0x0814: 'nn', 0x380A: 'es-UY',\n  0x046D: 'ba', 0x0437: 'ka', 0x0482: 'oc', 0x200A: 'es-VE',\n  0x042D: 'eu', 0x0C07: 'de-AT', 0x0448: 'or', 0x081D: 'sv-FI',\n  0x0423: 'be', 0x0407: 'de', 0x0463: 'ps', 0x041D: 'sv',\n  0x0845: 'bn', 0x1407: 'de-LI', 0x0415: 'pl', 0x045A: 'syr',\n  0x0445: 'bn-IN', 0x1007: 'de-LU', 0x0416: 'pt', 0x0428: 'tg',\n  0x201A: 'bs-Cyrl', 0x0807: 'de-CH', 0x0816: 'pt-PT', 0x085F: 'tzm',\n  0x141A: 'bs', 0x0408: 'el', 0x0446: 'pa', 0x0449: 'ta',\n  0x047E: 'br', 0x046F: 'kl', 0x046B: 'qu-BO', 0x0444: 'tt',\n  0x0402: 'bg', 0x0447: 'gu', 0x086B: 'qu-EC', 0x044A: 'te',\n  0x0403: 'ca', 0x0468: 'ha', 0x0C6B: 'qu', 0x041E: 'th',\n  0x0C04: 'zh-HK', 0x040D: 'he', 0x0418: 'ro', 0x0451: 'bo',\n  0x1404: 'zh-MO', 0x0439: 'hi', 0x0417: 'rm', 0x041F: 'tr',\n  0x0804: 'zh', 0x040E: 'hu', 0x0419: 'ru', 0x0442: 'tk',\n  0x1004: 'zh-SG', 0x040F: 'is', 0x243B: 'smn', 0x0480: 'ug',\n  0x0404: 'zh-TW', 0x0470: 'ig', 0x103B: 'smj-NO', 0x0422: 'uk',\n  0x0483: 'co', 0x0421: 'id', 0x143B: 'smj', 0x042E: 'hsb',\n  0x041A: 'hr', 0x045D: 'iu', 0x0C3B: 'se-FI', 0x0420: 'ur',\n  0x101A: 'hr-BA', 0x085D: 'iu-Latn', 0x043B: 'se', 0x0843: 'uz-Cyrl',\n  0x0405: 'cs', 0x083C: 'ga', 0x083B: 'se-SE', 0x0443: 'uz',\n  0x0406: 'da', 0x0434: 'xh', 0x203B: 'sms', 0x042A: 'vi',\n  0x048C: 'prs', 0x0435: 'zu', 0x183B: 'sma-NO', 0x0452: 'cy',\n  0x0465: 'dv', 0x0410: 'it', 0x1C3B: 'sms', 0x0488: 'wo',\n  0x0813: 'nl-BE', 0x0810: 'it-CH', 0x044F: 'sa', 0x0485: 'sah',\n  0x0413: 'nl', 0x0411: 'ja', 0x1C1A: 'sr-Cyrl-BA', 0x0478: 'ii',\n  0x0C09: 'en-AU', 0x044B: 'kn', 0x0C1A: 'sr', 0x046A: 'yo',\n  0x2809: 'en-BZ', 0x043F: 'kk', 0x181A: 'sr-Latn-BA',\n  0x1009: 'en-CA', 0x0453: 'km', 0x081A: 'sr-Latn',\n  0x2409: 'en-029', 0x0486: 'quc', 0x046C: 'nso'\n}];\n\nvar NameRecord = new r.Struct({\n  platformID: r.uint16,\n  encodingID: r.uint16,\n  languageID: r.uint16,\n  nameID: r.uint16,\n  length: r.uint16,\n  string: new r.Pointer(r.uint16, new r.String('length', function (t) {\n    return getEncoding(t.platformID, t.encodingID, t.languageID);\n  }), { type: 'parent', relativeTo: 'parent.stringOffset', allowNull: false })\n});\n\nvar LangTagRecord = new r.Struct({\n  length: r.uint16,\n  tag: new r.Pointer(r.uint16, new r.String('length', 'utf16be'), { type: 'parent', relativeTo: 'stringOffset' })\n});\n\nvar NameTable = new r.VersionedStruct(r.uint16, {\n  0: {\n    count: r.uint16,\n    stringOffset: r.uint16,\n    records: new r.Array(NameRecord, 'count')\n  },\n  1: {\n    count: r.uint16,\n    stringOffset: r.uint16,\n    records: new r.Array(NameRecord, 'count'),\n    langTagCount: r.uint16,\n    langTags: new r.Array(LangTagRecord, 'langTagCount')\n  }\n});\n\nvar NAMES = ['copyright', 'fontFamily', 'fontSubfamily', 'uniqueSubfamily', 'fullName', 'version', 'postscriptName', // Note: A font may have only one PostScript name and that name must be ASCII.\n'trademark', 'manufacturer', 'designer', 'description', 'vendorURL', 'designerURL', 'license', 'licenseURL', null, // reserved\n'preferredFamily', 'preferredSubfamily', 'compatibleFull', 'sampleText', 'postscriptCIDFontName', 'wwsFamilyName', 'wwsSubfamilyName'];\n\nNameTable.process = function (stream) {\n  var records = {};\n  for (var _iterator = this.records, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n    var _ref;\n\n    if (_isArray) {\n      if (_i >= _iterator.length) break;\n      _ref = _iterator[_i++];\n    } else {\n      _i = _iterator.next();\n      if (_i.done) break;\n      _ref = _i.value;\n    }\n\n    var record = _ref;\n\n    // find out what language this is for\n    var language = LANGUAGES[record.platformID][record.languageID];\n\n    if (language == null && this.langTags != null && record.languageID >= 0x8000) {\n      language = this.langTags[record.languageID - 0x8000].tag;\n    }\n\n    if (language == null) {\n      language = record.platformID + '-' + record.languageID;\n    }\n\n    // if the nameID is >= 256, it is a font feature record (AAT)\n    var key = record.nameID >= 256 ? 'fontFeatures' : NAMES[record.nameID] || record.nameID;\n    if (records[key] == null) {\n      records[key] = {};\n    }\n\n    var obj = records[key];\n    if (record.nameID >= 256) {\n      obj = obj[record.nameID] || (obj[record.nameID] = {});\n    }\n\n    if (typeof record.string === 'string' || typeof obj[language] !== 'string') {\n      obj[language] = record.string;\n    }\n  }\n\n  this.records = records;\n};\n\nNameTable.preEncode = function () {\n  if (Array.isArray(this.records)) return;\n  this.version = 0;\n\n  var records = [];\n  for (var key in this.records) {\n    var val = this.records[key];\n    if (key === 'fontFeatures') continue;\n\n    records.push({\n      platformID: 3,\n      encodingID: 1,\n      languageID: 0x409,\n      nameID: NAMES.indexOf(key),\n      length: Buffer.byteLength(val.en, 'utf16le'),\n      string: val.en\n    });\n\n    if (key === 'postscriptName') {\n      records.push({\n        platformID: 1,\n        encodingID: 0,\n        languageID: 0,\n        nameID: NAMES.indexOf(key),\n        length: val.en.length,\n        string: val.en\n      });\n    }\n  }\n\n  this.records = records;\n  this.count = records.length;\n  this.stringOffset = NameTable.size(this, null, false);\n};\n\nvar OS2 = new r.VersionedStruct(r.uint16, {\n  header: {\n    xAvgCharWidth: r.int16, // average weighted advance width of lower case letters and space\n    usWeightClass: r.uint16, // visual weight of stroke in glyphs\n    usWidthClass: r.uint16, // relative change from the normal aspect ratio (width to height ratio)\n    fsType: new r.Bitfield(r.uint16, [// Indicates font embedding licensing rights\n    null, 'noEmbedding', 'viewOnly', 'editable', null, null, null, null, 'noSubsetting', 'bitmapOnly']),\n    ySubscriptXSize: r.int16, // recommended horizontal size in pixels for subscripts\n    ySubscriptYSize: r.int16, // recommended vertical size in pixels for subscripts\n    ySubscriptXOffset: r.int16, // recommended horizontal offset for subscripts\n    ySubscriptYOffset: r.int16, // recommended vertical offset form the baseline for subscripts\n    ySuperscriptXSize: r.int16, // recommended horizontal size in pixels for superscripts\n    ySuperscriptYSize: r.int16, // recommended vertical size in pixels for superscripts\n    ySuperscriptXOffset: r.int16, // recommended horizontal offset for superscripts\n    ySuperscriptYOffset: r.int16, // recommended vertical offset from the baseline for superscripts\n    yStrikeoutSize: r.int16, // width of the strikeout stroke\n    yStrikeoutPosition: r.int16, // position of the strikeout stroke relative to the baseline\n    sFamilyClass: r.int16, // classification of font-family design\n    panose: new r.Array(r.uint8, 10), // describe the visual characteristics of a given typeface\n    ulCharRange: new r.Array(r.uint32, 4),\n    vendorID: new r.String(4), // four character identifier for the font vendor\n    fsSelection: new r.Bitfield(r.uint16, [// bit field containing information about the font\n    'italic', 'underscore', 'negative', 'outlined', 'strikeout', 'bold', 'regular', 'useTypoMetrics', 'wws', 'oblique']),\n    usFirstCharIndex: r.uint16, // The minimum Unicode index in this font\n    usLastCharIndex: r.uint16 // The maximum Unicode index in this font\n  },\n\n  // The Apple version of this table ends here, but the Microsoft one continues on...\n  0: {},\n\n  1: {\n    typoAscender: r.int16,\n    typoDescender: r.int16,\n    typoLineGap: r.int16,\n    winAscent: r.uint16,\n    winDescent: r.uint16,\n    codePageRange: new r.Array(r.uint32, 2)\n  },\n\n  2: {\n    // these should be common with version 1 somehow\n    typoAscender: r.int16,\n    typoDescender: r.int16,\n    typoLineGap: r.int16,\n    winAscent: r.uint16,\n    winDescent: r.uint16,\n    codePageRange: new r.Array(r.uint32, 2),\n\n    xHeight: r.int16,\n    capHeight: r.int16,\n    defaultChar: r.uint16,\n    breakChar: r.uint16,\n    maxContent: r.uint16\n  },\n\n  5: {\n    typoAscender: r.int16,\n    typoDescender: r.int16,\n    typoLineGap: r.int16,\n    winAscent: r.uint16,\n    winDescent: r.uint16,\n    codePageRange: new r.Array(r.uint32, 2),\n\n    xHeight: r.int16,\n    capHeight: r.int16,\n    defaultChar: r.uint16,\n    breakChar: r.uint16,\n    maxContent: r.uint16,\n\n    usLowerOpticalPointSize: r.uint16,\n    usUpperOpticalPointSize: r.uint16\n  }\n});\n\nvar versions = OS2.versions;\nversions[3] = versions[4] = versions[2];\n\n// PostScript information\nvar post = new r.VersionedStruct(r.fixed32, {\n  header: { // these fields exist at the top of all versions\n    italicAngle: r.fixed32, // Italic angle in counter-clockwise degrees from the vertical.\n    underlinePosition: r.int16, // Suggested distance of the top of the underline from the baseline\n    underlineThickness: r.int16, // Suggested values for the underline thickness\n    isFixedPitch: r.uint32, // Whether the font is monospaced\n    minMemType42: r.uint32, // Minimum memory usage when a TrueType font is downloaded as a Type 42 font\n    maxMemType42: r.uint32, // Maximum memory usage when a TrueType font is downloaded as a Type 42 font\n    minMemType1: r.uint32, // Minimum memory usage when a TrueType font is downloaded as a Type 1 font\n    maxMemType1: r.uint32 // Maximum memory usage when a TrueType font is downloaded as a Type 1 font\n  },\n\n  1: {}, // version 1 has no additional fields\n\n  2: {\n    numberOfGlyphs: r.uint16,\n    glyphNameIndex: new r.Array(r.uint16, 'numberOfGlyphs'),\n    names: new r.Array(new r.String(r.uint8))\n  },\n\n  2.5: {\n    numberOfGlyphs: r.uint16,\n    offsets: new r.Array(r.uint8, 'numberOfGlyphs')\n  },\n\n  3: {}, // version 3 has no additional fields\n\n  4: {\n    map: new r.Array(r.uint32, function (t) {\n      return t.parent.maxp.numGlyphs;\n    })\n  }\n});\n\n// An array of predefined values accessible by instructions\nvar cvt = new r.Struct({\n  controlValues: new r.Array(r.int16)\n});\n\n// A list of instructions that are executed once when a font is first used.\n// These instructions are known as the font program. The main use of this table\n// is for the definition of functions that are used in many different glyph programs.\nvar fpgm = new r.Struct({\n  instructions: new r.Array(r.uint8)\n});\n\nvar loca = new r.VersionedStruct('head.indexToLocFormat', {\n  0: {\n    offsets: new r.Array(r.uint16)\n  },\n  1: {\n    offsets: new r.Array(r.uint32)\n  }\n});\n\nloca.process = function () {\n  if (this.version === 0) {\n    for (var i = 0; i < this.offsets.length; i++) {\n      this.offsets[i] <<= 1;\n    }\n  }\n};\n\nloca.preEncode = function () {\n  if (this.version != null) return;\n\n  // assume this.offsets is a sorted array\n  this.version = this.offsets[this.offsets.length - 1] > 0xffff ? 1 : 0;\n\n  if (this.version === 0) {\n    for (var i = 0; i < this.offsets.length; i++) {\n      this.offsets[i] >>>= 1;\n    }\n  }\n};\n\n// Set of instructions executed whenever the point size or font transformation change\nvar prep = new r.Struct({\n  controlValueProgram: new r.Array(r.uint8)\n});\n\n// only used for encoding\nvar glyf = new r.Array(new r.Buffer());\n\nvar CFFIndex = function () {\n  function CFFIndex(type) {\n    _classCallCheck(this, CFFIndex);\n\n    this.type = type;\n  }\n\n  CFFIndex.prototype.getCFFVersion = function getCFFVersion(ctx) {\n    while (ctx && !ctx.hdrSize) {\n      ctx = ctx.parent;\n    }\n\n    return ctx ? ctx.version : -1;\n  };\n\n  CFFIndex.prototype.decode = function decode(stream, parent) {\n    var version = this.getCFFVersion(parent);\n    var count = version >= 2 ? stream.readUInt32BE() : stream.readUInt16BE();\n\n    if (count === 0) {\n      return [];\n    }\n\n    var offSize = stream.readUInt8();\n    var offsetType = void 0;\n    if (offSize === 1) {\n      offsetType = r.uint8;\n    } else if (offSize === 2) {\n      offsetType = r.uint16;\n    } else if (offSize === 3) {\n      offsetType = r.uint24;\n    } else if (offSize === 4) {\n      offsetType = r.uint32;\n    } else {\n      throw new Error(\"Bad offset size in CFFIndex: \" + offSize + \" \" + stream.pos);\n    }\n\n    var ret = [];\n    var startPos = stream.pos + (count + 1) * offSize - 1;\n\n    var start = offsetType.decode(stream);\n    for (var i = 0; i < count; i++) {\n      var end = offsetType.decode(stream);\n\n      if (this.type != null) {\n        var pos = stream.pos;\n        stream.pos = startPos + start;\n\n        parent.length = end - start;\n        ret.push(this.type.decode(stream, parent));\n        stream.pos = pos;\n      } else {\n        ret.push({\n          offset: startPos + start,\n          length: end - start\n        });\n      }\n\n      start = end;\n    }\n\n    stream.pos = startPos + start;\n    return ret;\n  };\n\n  CFFIndex.prototype.size = function size(arr, parent) {\n    var size = 2;\n    if (arr.length === 0) {\n      return size;\n    }\n\n    var type = this.type || new r.Buffer();\n\n    // find maximum offset to detminine offset type\n    var offset = 1;\n    for (var i = 0; i < arr.length; i++) {\n      var item = arr[i];\n      offset += type.size(item, parent);\n    }\n\n    var offsetType = void 0;\n    if (offset <= 0xff) {\n      offsetType = r.uint8;\n    } else if (offset <= 0xffff) {\n      offsetType = r.uint16;\n    } else if (offset <= 0xffffff) {\n      offsetType = r.uint24;\n    } else if (offset <= 0xffffffff) {\n      offsetType = r.uint32;\n    } else {\n      throw new Error(\"Bad offset in CFFIndex\");\n    }\n\n    size += 1 + offsetType.size() * (arr.length + 1);\n    size += offset - 1;\n\n    return size;\n  };\n\n  CFFIndex.prototype.encode = function encode(stream, arr, parent) {\n    stream.writeUInt16BE(arr.length);\n    if (arr.length === 0) {\n      return;\n    }\n\n    var type = this.type || new r.Buffer();\n\n    // find maximum offset to detminine offset type\n    var sizes = [];\n    var offset = 1;\n    for (var _iterator = arr, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var item = _ref;\n\n      var s = type.size(item, parent);\n      sizes.push(s);\n      offset += s;\n    }\n\n    var offsetType = void 0;\n    if (offset <= 0xff) {\n      offsetType = r.uint8;\n    } else if (offset <= 0xffff) {\n      offsetType = r.uint16;\n    } else if (offset <= 0xffffff) {\n      offsetType = r.uint24;\n    } else if (offset <= 0xffffffff) {\n      offsetType = r.uint32;\n    } else {\n      throw new Error(\"Bad offset in CFFIndex\");\n    }\n\n    // write offset size\n    stream.writeUInt8(offsetType.size());\n\n    // write elements\n    offset = 1;\n    offsetType.encode(stream, offset);\n\n    for (var _iterator2 = sizes, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n      var _ref2;\n\n      if (_isArray2) {\n        if (_i2 >= _iterator2.length) break;\n        _ref2 = _iterator2[_i2++];\n      } else {\n        _i2 = _iterator2.next();\n        if (_i2.done) break;\n        _ref2 = _i2.value;\n      }\n\n      var size = _ref2;\n\n      offset += size;\n      offsetType.encode(stream, offset);\n    }\n\n    for (var _iterator3 = arr, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n      var _ref3;\n\n      if (_isArray3) {\n        if (_i3 >= _iterator3.length) break;\n        _ref3 = _iterator3[_i3++];\n      } else {\n        _i3 = _iterator3.next();\n        if (_i3.done) break;\n        _ref3 = _i3.value;\n      }\n\n      var _item = _ref3;\n\n      type.encode(stream, _item, parent);\n    }\n\n    return;\n  };\n\n  return CFFIndex;\n}();\n\nvar FLOAT_EOF = 0xf;\nvar FLOAT_LOOKUP = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'E', 'E-', null, '-'];\n\nvar FLOAT_ENCODE_LOOKUP = {\n  '.': 10,\n  'E': 11,\n  'E-': 12,\n  '-': 14\n};\n\nvar CFFOperand = function () {\n  function CFFOperand() {\n    _classCallCheck(this, CFFOperand);\n  }\n\n  CFFOperand.decode = function decode(stream, value) {\n    if (32 <= value && value <= 246) {\n      return value - 139;\n    }\n\n    if (247 <= value && value <= 250) {\n      return (value - 247) * 256 + stream.readUInt8() + 108;\n    }\n\n    if (251 <= value && value <= 254) {\n      return -(value - 251) * 256 - stream.readUInt8() - 108;\n    }\n\n    if (value === 28) {\n      return stream.readInt16BE();\n    }\n\n    if (value === 29) {\n      return stream.readInt32BE();\n    }\n\n    if (value === 30) {\n      var str = '';\n      while (true) {\n        var b = stream.readUInt8();\n\n        var n1 = b >> 4;\n        if (n1 === FLOAT_EOF) {\n          break;\n        }\n        str += FLOAT_LOOKUP[n1];\n\n        var n2 = b & 15;\n        if (n2 === FLOAT_EOF) {\n          break;\n        }\n        str += FLOAT_LOOKUP[n2];\n      }\n\n      return parseFloat(str);\n    }\n\n    return null;\n  };\n\n  CFFOperand.size = function size(value) {\n    // if the value needs to be forced to the largest size (32 bit)\n    // e.g. for unknown pointers, set to 32768\n    if (value.forceLarge) {\n      value = 32768;\n    }\n\n    if ((value | 0) !== value) {\n      // floating point\n      var str = '' + value;\n      return 1 + Math.ceil((str.length + 1) / 2);\n    } else if (-107 <= value && value <= 107) {\n      return 1;\n    } else if (108 <= value && value <= 1131 || -1131 <= value && value <= -108) {\n      return 2;\n    } else if (-32768 <= value && value <= 32767) {\n      return 3;\n    } else {\n      return 5;\n    }\n  };\n\n  CFFOperand.encode = function encode(stream, value) {\n    // if the value needs to be forced to the largest size (32 bit)\n    // e.g. for unknown pointers, save the old value and set to 32768\n    var val = Number(value);\n\n    if (value.forceLarge) {\n      stream.writeUInt8(29);\n      return stream.writeInt32BE(val);\n    } else if ((val | 0) !== val) {\n      // floating point\n      stream.writeUInt8(30);\n\n      var str = '' + val;\n      for (var i = 0; i < str.length; i += 2) {\n        var c1 = str[i];\n        var n1 = FLOAT_ENCODE_LOOKUP[c1] || +c1;\n\n        if (i === str.length - 1) {\n          var n2 = FLOAT_EOF;\n        } else {\n          var c2 = str[i + 1];\n          var n2 = FLOAT_ENCODE_LOOKUP[c2] || +c2;\n        }\n\n        stream.writeUInt8(n1 << 4 | n2 & 15);\n      }\n\n      if (n2 !== FLOAT_EOF) {\n        return stream.writeUInt8(FLOAT_EOF << 4);\n      }\n    } else if (-107 <= val && val <= 107) {\n      return stream.writeUInt8(val + 139);\n    } else if (108 <= val && val <= 1131) {\n      val -= 108;\n      stream.writeUInt8((val >> 8) + 247);\n      return stream.writeUInt8(val & 0xff);\n    } else if (-1131 <= val && val <= -108) {\n      val = -val - 108;\n      stream.writeUInt8((val >> 8) + 251);\n      return stream.writeUInt8(val & 0xff);\n    } else if (-32768 <= val && val <= 32767) {\n      stream.writeUInt8(28);\n      return stream.writeInt16BE(val);\n    } else {\n      stream.writeUInt8(29);\n      return stream.writeInt32BE(val);\n    }\n  };\n\n  return CFFOperand;\n}();\n\nvar CFFDict = function () {\n  function CFFDict() {\n    var ops = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n\n    _classCallCheck(this, CFFDict);\n\n    this.ops = ops;\n    this.fields = {};\n    for (var _iterator = ops, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var field = _ref;\n\n      var key = Array.isArray(field[0]) ? field[0][0] << 8 | field[0][1] : field[0];\n      this.fields[key] = field;\n    }\n  }\n\n  CFFDict.prototype.decodeOperands = function decodeOperands(type, stream, ret, operands) {\n    var _this = this;\n\n    if (Array.isArray(type)) {\n      return operands.map(function (op, i) {\n        return _this.decodeOperands(type[i], stream, ret, [op]);\n      });\n    } else if (type.decode != null) {\n      return type.decode(stream, ret, operands);\n    } else {\n      switch (type) {\n        case 'number':\n        case 'offset':\n        case 'sid':\n          return operands[0];\n        case 'boolean':\n          return !!operands[0];\n        default:\n          return operands;\n      }\n    }\n  };\n\n  CFFDict.prototype.encodeOperands = function encodeOperands(type, stream, ctx, operands) {\n    var _this2 = this;\n\n    if (Array.isArray(type)) {\n      return operands.map(function (op, i) {\n        return _this2.encodeOperands(type[i], stream, ctx, op)[0];\n      });\n    } else if (type.encode != null) {\n      return type.encode(stream, operands, ctx);\n    } else if (typeof operands === 'number') {\n      return [operands];\n    } else if (typeof operands === 'boolean') {\n      return [+operands];\n    } else if (Array.isArray(operands)) {\n      return operands;\n    } else {\n      return [operands];\n    }\n  };\n\n  CFFDict.prototype.decode = function decode(stream, parent) {\n    var end = stream.pos + parent.length;\n    var ret = {};\n    var operands = [];\n\n    // define hidden properties\n    _Object$defineProperties(ret, {\n      parent: { value: parent },\n      _startOffset: { value: stream.pos }\n    });\n\n    // fill in defaults\n    for (var key in this.fields) {\n      var field = this.fields[key];\n      ret[field[1]] = field[3];\n    }\n\n    while (stream.pos < end) {\n      var b = stream.readUInt8();\n      if (b < 28) {\n        if (b === 12) {\n          b = b << 8 | stream.readUInt8();\n        }\n\n        var _field = this.fields[b];\n        if (!_field) {\n          throw new Error('Unknown operator ' + b);\n        }\n\n        var val = this.decodeOperands(_field[2], stream, ret, operands);\n        if (val != null) {\n          if (val instanceof restructure_src_utils.PropertyDescriptor) {\n            _Object$defineProperty(ret, _field[1], val);\n          } else {\n            ret[_field[1]] = val;\n          }\n        }\n\n        operands = [];\n      } else {\n        operands.push(CFFOperand.decode(stream, b));\n      }\n    }\n\n    return ret;\n  };\n\n  CFFDict.prototype.size = function size(dict, parent) {\n    var includePointers = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n\n    var ctx = {\n      parent: parent,\n      val: dict,\n      pointerSize: 0,\n      startOffset: parent.startOffset || 0\n    };\n\n    var len = 0;\n\n    for (var k in this.fields) {\n      var field = this.fields[k];\n      var val = dict[field[1]];\n      if (val == null || isEqual(val, field[3])) {\n        continue;\n      }\n\n      var operands = this.encodeOperands(field[2], null, ctx, val);\n      for (var _iterator2 = operands, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n        var _ref2;\n\n        if (_isArray2) {\n          if (_i2 >= _iterator2.length) break;\n          _ref2 = _iterator2[_i2++];\n        } else {\n          _i2 = _iterator2.next();\n          if (_i2.done) break;\n          _ref2 = _i2.value;\n        }\n\n        var op = _ref2;\n\n        len += CFFOperand.size(op);\n      }\n\n      var key = Array.isArray(field[0]) ? field[0] : [field[0]];\n      len += key.length;\n    }\n\n    if (includePointers) {\n      len += ctx.pointerSize;\n    }\n\n    return len;\n  };\n\n  CFFDict.prototype.encode = function encode(stream, dict, parent) {\n    var ctx = {\n      pointers: [],\n      startOffset: stream.pos,\n      parent: parent,\n      val: dict,\n      pointerSize: 0\n    };\n\n    ctx.pointerOffset = stream.pos + this.size(dict, ctx, false);\n\n    for (var _iterator3 = this.ops, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n      var _ref3;\n\n      if (_isArray3) {\n        if (_i3 >= _iterator3.length) break;\n        _ref3 = _iterator3[_i3++];\n      } else {\n        _i3 = _iterator3.next();\n        if (_i3.done) break;\n        _ref3 = _i3.value;\n      }\n\n      var field = _ref3;\n\n      var val = dict[field[1]];\n      if (val == null || isEqual(val, field[3])) {\n        continue;\n      }\n\n      var operands = this.encodeOperands(field[2], stream, ctx, val);\n      for (var _iterator4 = operands, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _getIterator(_iterator4);;) {\n        var _ref4;\n\n        if (_isArray4) {\n          if (_i4 >= _iterator4.length) break;\n          _ref4 = _iterator4[_i4++];\n        } else {\n          _i4 = _iterator4.next();\n          if (_i4.done) break;\n          _ref4 = _i4.value;\n        }\n\n        var op = _ref4;\n\n        CFFOperand.encode(stream, op);\n      }\n\n      var key = Array.isArray(field[0]) ? field[0] : [field[0]];\n      for (var _iterator5 = key, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _getIterator(_iterator5);;) {\n        var _ref5;\n\n        if (_isArray5) {\n          if (_i5 >= _iterator5.length) break;\n          _ref5 = _iterator5[_i5++];\n        } else {\n          _i5 = _iterator5.next();\n          if (_i5.done) break;\n          _ref5 = _i5.value;\n        }\n\n        var _op = _ref5;\n\n        stream.writeUInt8(_op);\n      }\n    }\n\n    var i = 0;\n    while (i < ctx.pointers.length) {\n      var ptr = ctx.pointers[i++];\n      ptr.type.encode(stream, ptr.val, ptr.parent);\n    }\n\n    return;\n  };\n\n  return CFFDict;\n}();\n\nvar CFFPointer = function (_r$Pointer) {\n  _inherits(CFFPointer, _r$Pointer);\n\n  function CFFPointer(type) {\n    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n    _classCallCheck(this, CFFPointer);\n\n    if (options.type == null) {\n      options.type = 'global';\n    }\n\n    return _possibleConstructorReturn(this, _r$Pointer.call(this, null, type, options));\n  }\n\n  CFFPointer.prototype.decode = function decode(stream, parent, operands) {\n    this.offsetType = {\n      decode: function decode() {\n        return operands[0];\n      }\n    };\n\n    return _r$Pointer.prototype.decode.call(this, stream, parent, operands);\n  };\n\n  CFFPointer.prototype.encode = function encode(stream, value, ctx) {\n    if (!stream) {\n      // compute the size (so ctx.pointerSize is correct)\n      this.offsetType = {\n        size: function size() {\n          return 0;\n        }\n      };\n\n      this.size(value, ctx);\n      return [new Ptr(0)];\n    }\n\n    var ptr = null;\n    this.offsetType = {\n      encode: function encode(stream, val) {\n        return ptr = val;\n      }\n    };\n\n    _r$Pointer.prototype.encode.call(this, stream, value, ctx);\n    return [new Ptr(ptr)];\n  };\n\n  return CFFPointer;\n}(r.Pointer);\n\nvar Ptr = function () {\n  function Ptr(val) {\n    _classCallCheck(this, Ptr);\n\n    this.val = val;\n    this.forceLarge = true;\n  }\n\n  Ptr.prototype.valueOf = function valueOf() {\n    return this.val;\n  };\n\n  return Ptr;\n}();\n\nvar CFFBlendOp = function () {\n  function CFFBlendOp() {\n    _classCallCheck(this, CFFBlendOp);\n  }\n\n  CFFBlendOp.decode = function decode(stream, parent, operands) {\n    var numBlends = operands.pop();\n\n    // TODO: actually blend. For now just consume the deltas\n    // since we don't use any of the values anyway.\n    while (operands.length > numBlends) {\n      operands.pop();\n    }\n  };\n\n  return CFFBlendOp;\n}();\n\nvar CFFPrivateDict = new CFFDict([\n// key       name                    type                                          default\n[6, 'BlueValues', 'delta', null], [7, 'OtherBlues', 'delta', null], [8, 'FamilyBlues', 'delta', null], [9, 'FamilyOtherBlues', 'delta', null], [[12, 9], 'BlueScale', 'number', 0.039625], [[12, 10], 'BlueShift', 'number', 7], [[12, 11], 'BlueFuzz', 'number', 1], [10, 'StdHW', 'number', null], [11, 'StdVW', 'number', null], [[12, 12], 'StemSnapH', 'delta', null], [[12, 13], 'StemSnapV', 'delta', null], [[12, 14], 'ForceBold', 'boolean', false], [[12, 17], 'LanguageGroup', 'number', 0], [[12, 18], 'ExpansionFactor', 'number', 0.06], [[12, 19], 'initialRandomSeed', 'number', 0], [20, 'defaultWidthX', 'number', 0], [21, 'nominalWidthX', 'number', 0], [22, 'vsindex', 'number', 0], [23, 'blend', CFFBlendOp, null], [19, 'Subrs', new CFFPointer(new CFFIndex(), { type: 'local' }), null]]);\n\n// Automatically generated from Appendix A of the CFF specification; do\n// not edit. Length should be 391.\nvar standardStrings = [\".notdef\", \"space\", \"exclam\", \"quotedbl\", \"numbersign\", \"dollar\", \"percent\", \"ampersand\", \"quoteright\", \"parenleft\", \"parenright\", \"asterisk\", \"plus\", \"comma\", \"hyphen\", \"period\", \"slash\", \"zero\", \"one\", \"two\", \"three\", \"four\", \"five\", \"six\", \"seven\", \"eight\", \"nine\", \"colon\", \"semicolon\", \"less\", \"equal\", \"greater\", \"question\", \"at\", \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\", \"J\", \"K\", \"L\", \"M\", \"N\", \"O\", \"P\", \"Q\", \"R\", \"S\", \"T\", \"U\", \"V\", \"W\", \"X\", \"Y\", \"Z\", \"bracketleft\", \"backslash\", \"bracketright\", \"asciicircum\", \"underscore\", \"quoteleft\", \"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\", \"i\", \"j\", \"k\", \"l\", \"m\", \"n\", \"o\", \"p\", \"q\", \"r\", \"s\", \"t\", \"u\", \"v\", \"w\", \"x\", \"y\", \"z\", \"braceleft\", \"bar\", \"braceright\", \"asciitilde\", \"exclamdown\", \"cent\", \"sterling\", \"fraction\", \"yen\", \"florin\", \"section\", \"currency\", \"quotesingle\", \"quotedblleft\", \"guillemotleft\", \"guilsinglleft\", \"guilsinglright\", \"fi\", \"fl\", \"endash\", \"dagger\", \"daggerdbl\", \"periodcentered\", \"paragraph\", \"bullet\", \"quotesinglbase\", \"quotedblbase\", \"quotedblright\", \"guillemotright\", \"ellipsis\", \"perthousand\", \"questiondown\", \"grave\", \"acute\", \"circumflex\", \"tilde\", \"macron\", \"breve\", \"dotaccent\", \"dieresis\", \"ring\", \"cedilla\", \"hungarumlaut\", \"ogonek\", \"caron\", \"emdash\", \"AE\", \"ordfeminine\", \"Lslash\", \"Oslash\", \"OE\", \"ordmasculine\", \"ae\", \"dotlessi\", \"lslash\", \"oslash\", \"oe\", \"germandbls\", \"onesuperior\", \"logicalnot\", \"mu\", \"trademark\", \"Eth\", \"onehalf\", \"plusminus\", \"Thorn\", \"onequarter\", \"divide\", \"brokenbar\", \"degree\", \"thorn\", \"threequarters\", \"twosuperior\", \"registered\", \"minus\", \"eth\", \"multiply\", \"threesuperior\", \"copyright\", \"Aacute\", \"Acircumflex\", \"Adieresis\", \"Agrave\", \"Aring\", \"Atilde\", \"Ccedilla\", \"Eacute\", \"Ecircumflex\", \"Edieresis\", \"Egrave\", \"Iacute\", \"Icircumflex\", \"Idieresis\", \"Igrave\", \"Ntilde\", \"Oacute\", \"Ocircumflex\", \"Odieresis\", \"Ograve\", \"Otilde\", \"Scaron\", \"Uacute\", \"Ucircumflex\", \"Udieresis\", \"Ugrave\", \"Yacute\", \"Ydieresis\", \"Zcaron\", \"aacute\", \"acircumflex\", \"adieresis\", \"agrave\", \"aring\", \"atilde\", \"ccedilla\", \"eacute\", \"ecircumflex\", \"edieresis\", \"egrave\", \"iacute\", \"icircumflex\", \"idieresis\", \"igrave\", \"ntilde\", \"oacute\", \"ocircumflex\", \"odieresis\", \"ograve\", \"otilde\", \"scaron\", \"uacute\", \"ucircumflex\", \"udieresis\", \"ugrave\", \"yacute\", \"ydieresis\", \"zcaron\", \"exclamsmall\", \"Hungarumlautsmall\", \"dollaroldstyle\", \"dollarsuperior\", \"ampersandsmall\", \"Acutesmall\", \"parenleftsuperior\", \"parenrightsuperior\", \"twodotenleader\", \"onedotenleader\", \"zerooldstyle\", \"oneoldstyle\", \"twooldstyle\", \"threeoldstyle\", \"fouroldstyle\", \"fiveoldstyle\", \"sixoldstyle\", \"sevenoldstyle\", \"eightoldstyle\", \"nineoldstyle\", \"commasuperior\", \"threequartersemdash\", \"periodsuperior\", \"questionsmall\", \"asuperior\", \"bsuperior\", \"centsuperior\", \"dsuperior\", \"esuperior\", \"isuperior\", \"lsuperior\", \"msuperior\", \"nsuperior\", \"osuperior\", \"rsuperior\", \"ssuperior\", \"tsuperior\", \"ff\", \"ffi\", \"ffl\", \"parenleftinferior\", \"parenrightinferior\", \"Circumflexsmall\", \"hyphensuperior\", \"Gravesmall\", \"Asmall\", \"Bsmall\", \"Csmall\", \"Dsmall\", \"Esmall\", \"Fsmall\", \"Gsmall\", \"Hsmall\", \"Ismall\", \"Jsmall\", \"Ksmall\", \"Lsmall\", \"Msmall\", \"Nsmall\", \"Osmall\", \"Psmall\", \"Qsmall\", \"Rsmall\", \"Ssmall\", \"Tsmall\", \"Usmall\", \"Vsmall\", \"Wsmall\", \"Xsmall\", \"Ysmall\", \"Zsmall\", \"colonmonetary\", \"onefitted\", \"rupiah\", \"Tildesmall\", \"exclamdownsmall\", \"centoldstyle\", \"Lslashsmall\", \"Scaronsmall\", \"Zcaronsmall\", \"Dieresissmall\", \"Brevesmall\", \"Caronsmall\", \"Dotaccentsmall\", \"Macronsmall\", \"figuredash\", \"hypheninferior\", \"Ogoneksmall\", \"Ringsmall\", \"Cedillasmall\", \"questiondownsmall\", \"oneeighth\", \"threeeighths\", \"fiveeighths\", \"seveneighths\", \"onethird\", \"twothirds\", \"zerosuperior\", \"foursuperior\", \"fivesuperior\", \"sixsuperior\", \"sevensuperior\", \"eightsuperior\", \"ninesuperior\", \"zeroinferior\", \"oneinferior\", \"twoinferior\", \"threeinferior\", \"fourinferior\", \"fiveinferior\", \"sixinferior\", \"seveninferior\", \"eightinferior\", \"nineinferior\", \"centinferior\", \"dollarinferior\", \"periodinferior\", \"commainferior\", \"Agravesmall\", \"Aacutesmall\", \"Acircumflexsmall\", \"Atildesmall\", \"Adieresissmall\", \"Aringsmall\", \"AEsmall\", \"Ccedillasmall\", \"Egravesmall\", \"Eacutesmall\", \"Ecircumflexsmall\", \"Edieresissmall\", \"Igravesmall\", \"Iacutesmall\", \"Icircumflexsmall\", \"Idieresissmall\", \"Ethsmall\", \"Ntildesmall\", \"Ogravesmall\", \"Oacutesmall\", \"Ocircumflexsmall\", \"Otildesmall\", \"Odieresissmall\", \"OEsmall\", \"Oslashsmall\", \"Ugravesmall\", \"Uacutesmall\", \"Ucircumflexsmall\", \"Udieresissmall\", \"Yacutesmall\", \"Thornsmall\", \"Ydieresissmall\", \"001.000\", \"001.001\", \"001.002\", \"001.003\", \"Black\", \"Bold\", \"Book\", \"Light\", \"Medium\", \"Regular\", \"Roman\", \"Semibold\"];\n\nvar StandardEncoding = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger', 'daggerdbl', 'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla', '', 'hungarumlaut', 'ogonek', 'caron', 'emdash', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '', '', '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae', '', '', '', 'dotlessi', '', '', 'lslash', 'oslash', 'oe', 'germandbls'];\n\nvar ExpertEncoding = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', '', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior', '', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', '', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '', 'figuredash', 'hypheninferior', '', '', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters', 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', '', '', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall'];\n\nvar ISOAdobeCharset = ['.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl', 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', 'yacute', 'ydieresis', 'zcaron'];\n\nvar ExpertCharset = ['.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', 'onequarter', 'onehalf', 'threequarters', 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall'];\n\nvar ExpertSubsetCharset = ['.notdef', 'space', 'dollaroldstyle', 'dollarsuperior', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior', 'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted', 'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter', 'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior', 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior'];\n\n//########################\n// Scripts and Languages #\n//########################\n\nvar LangSysTable = new r.Struct({\n  reserved: new r.Reserved(r.uint16),\n  reqFeatureIndex: r.uint16,\n  featureCount: r.uint16,\n  featureIndexes: new r.Array(r.uint16, 'featureCount')\n});\n\nvar LangSysRecord = new r.Struct({\n  tag: new r.String(4),\n  langSys: new r.Pointer(r.uint16, LangSysTable, { type: 'parent' })\n});\n\nvar Script = new r.Struct({\n  defaultLangSys: new r.Pointer(r.uint16, LangSysTable),\n  count: r.uint16,\n  langSysRecords: new r.Array(LangSysRecord, 'count')\n});\n\nvar ScriptRecord = new r.Struct({\n  tag: new r.String(4),\n  script: new r.Pointer(r.uint16, Script, { type: 'parent' })\n});\n\nvar ScriptList = new r.Array(ScriptRecord, r.uint16);\n\n//#######################\n// Features and Lookups #\n//#######################\n\nvar Feature = new r.Struct({\n  featureParams: r.uint16, // pointer\n  lookupCount: r.uint16,\n  lookupListIndexes: new r.Array(r.uint16, 'lookupCount')\n});\n\nvar FeatureRecord = new r.Struct({\n  tag: new r.String(4),\n  feature: new r.Pointer(r.uint16, Feature, { type: 'parent' })\n});\n\nvar FeatureList = new r.Array(FeatureRecord, r.uint16);\n\nvar LookupFlags = new r.Struct({\n  markAttachmentType: r.uint8,\n  flags: new r.Bitfield(r.uint8, ['rightToLeft', 'ignoreBaseGlyphs', 'ignoreLigatures', 'ignoreMarks', 'useMarkFilteringSet'])\n});\n\nfunction LookupList(SubTable) {\n  var Lookup = new r.Struct({\n    lookupType: r.uint16,\n    flags: LookupFlags,\n    subTableCount: r.uint16,\n    subTables: new r.Array(new r.Pointer(r.uint16, SubTable), 'subTableCount'),\n    markFilteringSet: new r.Optional(r.uint16, function (t) {\n      return t.flags.flags.useMarkFilteringSet;\n    })\n  });\n\n  return new r.LazyArray(new r.Pointer(r.uint16, Lookup), r.uint16);\n}\n\n//#################\n// Coverage Table #\n//#################\n\nvar RangeRecord = new r.Struct({\n  start: r.uint16,\n  end: r.uint16,\n  startCoverageIndex: r.uint16\n});\n\nvar Coverage = new r.VersionedStruct(r.uint16, {\n  1: {\n    glyphCount: r.uint16,\n    glyphs: new r.Array(r.uint16, 'glyphCount')\n  },\n  2: {\n    rangeCount: r.uint16,\n    rangeRecords: new r.Array(RangeRecord, 'rangeCount')\n  }\n});\n\n//#########################\n// Class Definition Table #\n//#########################\n\nvar ClassRangeRecord = new r.Struct({\n  start: r.uint16,\n  end: r.uint16,\n  class: r.uint16\n});\n\nvar ClassDef = new r.VersionedStruct(r.uint16, {\n  1: { // Class array\n    startGlyph: r.uint16,\n    glyphCount: r.uint16,\n    classValueArray: new r.Array(r.uint16, 'glyphCount')\n  },\n  2: { // Class ranges\n    classRangeCount: r.uint16,\n    classRangeRecord: new r.Array(ClassRangeRecord, 'classRangeCount')\n  }\n});\n\n//###############\n// Device Table #\n//###############\n\nvar Device = new r.Struct({\n  a: r.uint16, // startSize for hinting Device, outerIndex for VariationIndex\n  b: r.uint16, // endSize for Device, innerIndex for VariationIndex\n  deltaFormat: r.uint16\n});\n\n//#############################################\n// Contextual Substitution/Positioning Tables #\n//#############################################\n\nvar LookupRecord = new r.Struct({\n  sequenceIndex: r.uint16,\n  lookupListIndex: r.uint16\n});\n\nvar Rule = new r.Struct({\n  glyphCount: r.uint16,\n  lookupCount: r.uint16,\n  input: new r.Array(r.uint16, function (t) {\n    return t.glyphCount - 1;\n  }),\n  lookupRecords: new r.Array(LookupRecord, 'lookupCount')\n});\n\nvar RuleSet = new r.Array(new r.Pointer(r.uint16, Rule), r.uint16);\n\nvar ClassRule = new r.Struct({\n  glyphCount: r.uint16,\n  lookupCount: r.uint16,\n  classes: new r.Array(r.uint16, function (t) {\n    return t.glyphCount - 1;\n  }),\n  lookupRecords: new r.Array(LookupRecord, 'lookupCount')\n});\n\nvar ClassSet = new r.Array(new r.Pointer(r.uint16, ClassRule), r.uint16);\n\nvar Context = new r.VersionedStruct(r.uint16, {\n  1: { // Simple context\n    coverage: new r.Pointer(r.uint16, Coverage),\n    ruleSetCount: r.uint16,\n    ruleSets: new r.Array(new r.Pointer(r.uint16, RuleSet), 'ruleSetCount')\n  },\n  2: { // Class-based context\n    coverage: new r.Pointer(r.uint16, Coverage),\n    classDef: new r.Pointer(r.uint16, ClassDef),\n    classSetCnt: r.uint16,\n    classSet: new r.Array(new r.Pointer(r.uint16, ClassSet), 'classSetCnt')\n  },\n  3: {\n    glyphCount: r.uint16,\n    lookupCount: r.uint16,\n    coverages: new r.Array(new r.Pointer(r.uint16, Coverage), 'glyphCount'),\n    lookupRecords: new r.Array(LookupRecord, 'lookupCount')\n  }\n});\n\n//######################################################\n// Chaining Contextual Substitution/Positioning Tables #\n//######################################################\n\nvar ChainRule = new r.Struct({\n  backtrackGlyphCount: r.uint16,\n  backtrack: new r.Array(r.uint16, 'backtrackGlyphCount'),\n  inputGlyphCount: r.uint16,\n  input: new r.Array(r.uint16, function (t) {\n    return t.inputGlyphCount - 1;\n  }),\n  lookaheadGlyphCount: r.uint16,\n  lookahead: new r.Array(r.uint16, 'lookaheadGlyphCount'),\n  lookupCount: r.uint16,\n  lookupRecords: new r.Array(LookupRecord, 'lookupCount')\n});\n\nvar ChainRuleSet = new r.Array(new r.Pointer(r.uint16, ChainRule), r.uint16);\n\nvar ChainingContext = new r.VersionedStruct(r.uint16, {\n  1: { // Simple context glyph substitution\n    coverage: new r.Pointer(r.uint16, Coverage),\n    chainCount: r.uint16,\n    chainRuleSets: new r.Array(new r.Pointer(r.uint16, ChainRuleSet), 'chainCount')\n  },\n\n  2: { // Class-based chaining context\n    coverage: new r.Pointer(r.uint16, Coverage),\n    backtrackClassDef: new r.Pointer(r.uint16, ClassDef),\n    inputClassDef: new r.Pointer(r.uint16, ClassDef),\n    lookaheadClassDef: new r.Pointer(r.uint16, ClassDef),\n    chainCount: r.uint16,\n    chainClassSet: new r.Array(new r.Pointer(r.uint16, ChainRuleSet), 'chainCount')\n  },\n\n  3: { // Coverage-based chaining context\n    backtrackGlyphCount: r.uint16,\n    backtrackCoverage: new r.Array(new r.Pointer(r.uint16, Coverage), 'backtrackGlyphCount'),\n    inputGlyphCount: r.uint16,\n    inputCoverage: new r.Array(new r.Pointer(r.uint16, Coverage), 'inputGlyphCount'),\n    lookaheadGlyphCount: r.uint16,\n    lookaheadCoverage: new r.Array(new r.Pointer(r.uint16, Coverage), 'lookaheadGlyphCount'),\n    lookupCount: r.uint16,\n    lookupRecords: new r.Array(LookupRecord, 'lookupCount')\n  }\n});\n\nvar _;\n\n/*******************\n * Variation Store *\n *******************/\n\nvar F2DOT14 = new r.Fixed(16, 'BE', 14);\nvar RegionAxisCoordinates = new r.Struct({\n  startCoord: F2DOT14,\n  peakCoord: F2DOT14,\n  endCoord: F2DOT14\n});\n\nvar VariationRegionList = new r.Struct({\n  axisCount: r.uint16,\n  regionCount: r.uint16,\n  variationRegions: new r.Array(new r.Array(RegionAxisCoordinates, 'axisCount'), 'regionCount')\n});\n\nvar DeltaSet = new r.Struct({\n  shortDeltas: new r.Array(r.int16, function (t) {\n    return t.parent.shortDeltaCount;\n  }),\n  regionDeltas: new r.Array(r.int8, function (t) {\n    return t.parent.regionIndexCount - t.parent.shortDeltaCount;\n  }),\n  deltas: function deltas(t) {\n    return t.shortDeltas.concat(t.regionDeltas);\n  }\n});\n\nvar ItemVariationData = new r.Struct({\n  itemCount: r.uint16,\n  shortDeltaCount: r.uint16,\n  regionIndexCount: r.uint16,\n  regionIndexes: new r.Array(r.uint16, 'regionIndexCount'),\n  deltaSets: new r.Array(DeltaSet, 'itemCount')\n});\n\nvar ItemVariationStore = new r.Struct({\n  format: r.uint16,\n  variationRegionList: new r.Pointer(r.uint32, VariationRegionList),\n  variationDataCount: r.uint16,\n  itemVariationData: new r.Array(new r.Pointer(r.uint32, ItemVariationData), 'variationDataCount')\n});\n\n/**********************\n * Feature Variations *\n **********************/\n\nvar ConditionTable = new r.VersionedStruct(r.uint16, {\n  1: (_ = {\n    axisIndex: r.uint16\n  }, _['axisIndex'] = r.uint16, _.filterRangeMinValue = F2DOT14, _.filterRangeMaxValue = F2DOT14, _)\n});\n\nvar ConditionSet = new r.Struct({\n  conditionCount: r.uint16,\n  conditionTable: new r.Array(new r.Pointer(r.uint32, ConditionTable), 'conditionCount')\n});\n\nvar FeatureTableSubstitutionRecord = new r.Struct({\n  featureIndex: r.uint16,\n  alternateFeatureTable: new r.Pointer(r.uint32, Feature, { type: 'parent' })\n});\n\nvar FeatureTableSubstitution = new r.Struct({\n  version: r.fixed32,\n  substitutionCount: r.uint16,\n  substitutions: new r.Array(FeatureTableSubstitutionRecord, 'substitutionCount')\n});\n\nvar FeatureVariationRecord = new r.Struct({\n  conditionSet: new r.Pointer(r.uint32, ConditionSet, { type: 'parent' }),\n  featureTableSubstitution: new r.Pointer(r.uint32, FeatureTableSubstitution, { type: 'parent' })\n});\n\nvar FeatureVariations = new r.Struct({\n  majorVersion: r.uint16,\n  minorVersion: r.uint16,\n  featureVariationRecordCount: r.uint32,\n  featureVariationRecords: new r.Array(FeatureVariationRecord, 'featureVariationRecordCount')\n});\n\n// Checks if an operand is an index of a predefined value,\n// otherwise delegates to the provided type.\n\nvar PredefinedOp = function () {\n  function PredefinedOp(predefinedOps, type) {\n    _classCallCheck(this, PredefinedOp);\n\n    this.predefinedOps = predefinedOps;\n    this.type = type;\n  }\n\n  PredefinedOp.prototype.decode = function decode(stream, parent, operands) {\n    if (this.predefinedOps[operands[0]]) {\n      return this.predefinedOps[operands[0]];\n    }\n\n    return this.type.decode(stream, parent, operands);\n  };\n\n  PredefinedOp.prototype.size = function size(value, ctx) {\n    return this.type.size(value, ctx);\n  };\n\n  PredefinedOp.prototype.encode = function encode(stream, value, ctx) {\n    var index = this.predefinedOps.indexOf(value);\n    if (index !== -1) {\n      return index;\n    }\n\n    return this.type.encode(stream, value, ctx);\n  };\n\n  return PredefinedOp;\n}();\n\nvar CFFEncodingVersion = function (_r$Number) {\n  _inherits(CFFEncodingVersion, _r$Number);\n\n  function CFFEncodingVersion() {\n    _classCallCheck(this, CFFEncodingVersion);\n\n    return _possibleConstructorReturn(this, _r$Number.call(this, 'UInt8'));\n  }\n\n  CFFEncodingVersion.prototype.decode = function decode(stream) {\n    return r.uint8.decode(stream) & 0x7f;\n  };\n\n  return CFFEncodingVersion;\n}(r.Number);\n\nvar Range1 = new r.Struct({\n  first: r.uint16,\n  nLeft: r.uint8\n});\n\nvar Range2 = new r.Struct({\n  first: r.uint16,\n  nLeft: r.uint16\n});\n\nvar CFFCustomEncoding = new r.VersionedStruct(new CFFEncodingVersion(), {\n  0: {\n    nCodes: r.uint8,\n    codes: new r.Array(r.uint8, 'nCodes')\n  },\n\n  1: {\n    nRanges: r.uint8,\n    ranges: new r.Array(Range1, 'nRanges')\n  }\n\n  // TODO: supplement?\n});\n\nvar CFFEncoding = new PredefinedOp([StandardEncoding, ExpertEncoding], new CFFPointer(CFFCustomEncoding, { lazy: true }));\n\n// Decodes an array of ranges until the total\n// length is equal to the provided length.\n\nvar RangeArray = function (_r$Array) {\n  _inherits(RangeArray, _r$Array);\n\n  function RangeArray() {\n    _classCallCheck(this, RangeArray);\n\n    return _possibleConstructorReturn(this, _r$Array.apply(this, arguments));\n  }\n\n  RangeArray.prototype.decode = function decode(stream, parent) {\n    var length = restructure_src_utils.resolveLength(this.length, stream, parent);\n    var count = 0;\n    var res = [];\n    while (count < length) {\n      var range = this.type.decode(stream, parent);\n      range.offset = count;\n      count += range.nLeft + 1;\n      res.push(range);\n    }\n\n    return res;\n  };\n\n  return RangeArray;\n}(r.Array);\n\nvar CFFCustomCharset = new r.VersionedStruct(r.uint8, {\n  0: {\n    glyphs: new r.Array(r.uint16, function (t) {\n      return t.parent.CharStrings.length - 1;\n    })\n  },\n\n  1: {\n    ranges: new RangeArray(Range1, function (t) {\n      return t.parent.CharStrings.length - 1;\n    })\n  },\n\n  2: {\n    ranges: new RangeArray(Range2, function (t) {\n      return t.parent.CharStrings.length - 1;\n    })\n  }\n});\n\nvar CFFCharset = new PredefinedOp([ISOAdobeCharset, ExpertCharset, ExpertSubsetCharset], new CFFPointer(CFFCustomCharset, { lazy: true }));\n\nvar FDRange3 = new r.Struct({\n  first: r.uint16,\n  fd: r.uint8\n});\n\nvar FDRange4 = new r.Struct({\n  first: r.uint32,\n  fd: r.uint16\n});\n\nvar FDSelect = new r.VersionedStruct(r.uint8, {\n  0: {\n    fds: new r.Array(r.uint8, function (t) {\n      return t.parent.CharStrings.length;\n    })\n  },\n\n  3: {\n    nRanges: r.uint16,\n    ranges: new r.Array(FDRange3, 'nRanges'),\n    sentinel: r.uint16\n  },\n\n  4: {\n    nRanges: r.uint32,\n    ranges: new r.Array(FDRange4, 'nRanges'),\n    sentinel: r.uint32\n  }\n});\n\nvar ptr = new CFFPointer(CFFPrivateDict);\n\nvar CFFPrivateOp = function () {\n  function CFFPrivateOp() {\n    _classCallCheck(this, CFFPrivateOp);\n  }\n\n  CFFPrivateOp.prototype.decode = function decode(stream, parent, operands) {\n    parent.length = operands[0];\n    return ptr.decode(stream, parent, [operands[1]]);\n  };\n\n  CFFPrivateOp.prototype.size = function size(dict, ctx) {\n    return [CFFPrivateDict.size(dict, ctx, false), ptr.size(dict, ctx)[0]];\n  };\n\n  CFFPrivateOp.prototype.encode = function encode(stream, dict, ctx) {\n    return [CFFPrivateDict.size(dict, ctx, false), ptr.encode(stream, dict, ctx)[0]];\n  };\n\n  return CFFPrivateOp;\n}();\n\nvar FontDict = new CFFDict([\n// key       name                   type(s)                                 default\n[18, 'Private', new CFFPrivateOp(), null], [[12, 38], 'FontName', 'sid', null]]);\n\nvar CFFTopDict = new CFFDict([\n// key       name                   type(s)                                 default\n[[12, 30], 'ROS', ['sid', 'sid', 'number'], null], [0, 'version', 'sid', null], [1, 'Notice', 'sid', null], [[12, 0], 'Copyright', 'sid', null], [2, 'FullName', 'sid', null], [3, 'FamilyName', 'sid', null], [4, 'Weight', 'sid', null], [[12, 1], 'isFixedPitch', 'boolean', false], [[12, 2], 'ItalicAngle', 'number', 0], [[12, 3], 'UnderlinePosition', 'number', -100], [[12, 4], 'UnderlineThickness', 'number', 50], [[12, 5], 'PaintType', 'number', 0], [[12, 6], 'CharstringType', 'number', 2], [[12, 7], 'FontMatrix', 'array', [0.001, 0, 0, 0.001, 0, 0]], [13, 'UniqueID', 'number', null], [5, 'FontBBox', 'array', [0, 0, 0, 0]], [[12, 8], 'StrokeWidth', 'number', 0], [14, 'XUID', 'array', null], [15, 'charset', CFFCharset, ISOAdobeCharset], [16, 'Encoding', CFFEncoding, StandardEncoding], [17, 'CharStrings', new CFFPointer(new CFFIndex()), null], [18, 'Private', new CFFPrivateOp(), null], [[12, 20], 'SyntheticBase', 'number', null], [[12, 21], 'PostScript', 'sid', null], [[12, 22], 'BaseFontName', 'sid', null], [[12, 23], 'BaseFontBlend', 'delta', null],\n\n// CID font specific\n[[12, 31], 'CIDFontVersion', 'number', 0], [[12, 32], 'CIDFontRevision', 'number', 0], [[12, 33], 'CIDFontType', 'number', 0], [[12, 34], 'CIDCount', 'number', 8720], [[12, 35], 'UIDBase', 'number', null], [[12, 37], 'FDSelect', new CFFPointer(FDSelect), null], [[12, 36], 'FDArray', new CFFPointer(new CFFIndex(FontDict)), null], [[12, 38], 'FontName', 'sid', null]]);\n\nvar VariationStore = new r.Struct({\n  length: r.uint16,\n  itemVariationStore: ItemVariationStore\n});\n\nvar CFF2TopDict = new CFFDict([[[12, 7], 'FontMatrix', 'array', [0.001, 0, 0, 0.001, 0, 0]], [17, 'CharStrings', new CFFPointer(new CFFIndex()), null], [[12, 37], 'FDSelect', new CFFPointer(FDSelect), null], [[12, 36], 'FDArray', new CFFPointer(new CFFIndex(FontDict)), null], [24, 'vstore', new CFFPointer(VariationStore), null], [25, 'maxstack', 'number', 193]]);\n\nvar CFFTop = new r.VersionedStruct(r.fixed16, {\n  1: {\n    hdrSize: r.uint8,\n    offSize: r.uint8,\n    nameIndex: new CFFIndex(new r.String('length')),\n    topDictIndex: new CFFIndex(CFFTopDict),\n    stringIndex: new CFFIndex(new r.String('length')),\n    globalSubrIndex: new CFFIndex()\n  },\n\n  2: {\n    hdrSize: r.uint8,\n    length: r.uint16,\n    topDict: CFF2TopDict,\n    globalSubrIndex: new CFFIndex()\n  }\n});\n\nvar CFFFont = function () {\n  function CFFFont(stream) {\n    _classCallCheck(this, CFFFont);\n\n    this.stream = stream;\n    this.decode();\n  }\n\n  CFFFont.decode = function decode(stream) {\n    return new CFFFont(stream);\n  };\n\n  CFFFont.prototype.decode = function decode() {\n    var start = this.stream.pos;\n    var top = CFFTop.decode(this.stream);\n    for (var key in top) {\n      var val = top[key];\n      this[key] = val;\n    }\n\n    if (this.version < 2) {\n      if (this.topDictIndex.length !== 1) {\n        throw new Error(\"Only a single font is allowed in CFF\");\n      }\n\n      this.topDict = this.topDictIndex[0];\n    }\n\n    this.isCIDFont = this.topDict.ROS != null;\n    return this;\n  };\n\n  CFFFont.prototype.string = function string(sid) {\n    if (this.version >= 2) {\n      return null;\n    }\n\n    if (sid < standardStrings.length) {\n      return standardStrings[sid];\n    }\n\n    return this.stringIndex[sid - standardStrings.length];\n  };\n\n  CFFFont.prototype.getCharString = function getCharString(glyph) {\n    this.stream.pos = this.topDict.CharStrings[glyph].offset;\n    return this.stream.readBuffer(this.topDict.CharStrings[glyph].length);\n  };\n\n  CFFFont.prototype.getGlyphName = function getGlyphName(gid) {\n    // CFF2 glyph names are in the post table.\n    if (this.version >= 2) {\n      return null;\n    }\n\n    // CID-keyed fonts don't have glyph names\n    if (this.isCIDFont) {\n      return null;\n    }\n\n    var charset = this.topDict.charset;\n\n    if (Array.isArray(charset)) {\n      return charset[gid];\n    }\n\n    if (gid === 0) {\n      return '.notdef';\n    }\n\n    gid -= 1;\n\n    switch (charset.version) {\n      case 0:\n        return this.string(charset.glyphs[gid]);\n\n      case 1:\n      case 2:\n        for (var i = 0; i < charset.ranges.length; i++) {\n          var range = charset.ranges[i];\n          if (range.offset <= gid && gid <= range.offset + range.nLeft) {\n            return this.string(range.first + (gid - range.offset));\n          }\n        }\n        break;\n    }\n\n    return null;\n  };\n\n  CFFFont.prototype.fdForGlyph = function fdForGlyph(gid) {\n    if (!this.topDict.FDSelect) {\n      return null;\n    }\n\n    switch (this.topDict.FDSelect.version) {\n      case 0:\n        return this.topDict.FDSelect.fds[gid];\n\n      case 3:\n      case 4:\n        var ranges = this.topDict.FDSelect.ranges;\n\n        var low = 0;\n        var high = ranges.length - 1;\n\n        while (low <= high) {\n          var mid = low + high >> 1;\n\n          if (gid < ranges[mid].first) {\n            high = mid - 1;\n          } else if (mid < high && gid > ranges[mid + 1].first) {\n            low = mid + 1;\n          } else {\n            return ranges[mid].fd;\n          }\n        }\n      default:\n        throw new Error('Unknown FDSelect version: ' + this.topDict.FDSelect.version);\n    }\n  };\n\n  CFFFont.prototype.privateDictForGlyph = function privateDictForGlyph(gid) {\n    if (this.topDict.FDSelect) {\n      var fd = this.fdForGlyph(gid);\n      if (this.topDict.FDArray[fd]) {\n        return this.topDict.FDArray[fd].Private;\n      }\n\n      return null;\n    }\n\n    if (this.version < 2) {\n      return this.topDict.Private;\n    }\n\n    return this.topDict.FDArray[0].Private;\n  };\n\n  _createClass(CFFFont, [{\n    key: 'postscriptName',\n    get: function get() {\n      if (this.version < 2) {\n        return this.nameIndex[0];\n      }\n\n      return null;\n    }\n  }, {\n    key: 'fullName',\n    get: function get() {\n      return this.string(this.topDict.FullName);\n    }\n  }, {\n    key: 'familyName',\n    get: function get() {\n      return this.string(this.topDict.FamilyName);\n    }\n  }]);\n\n  return CFFFont;\n}();\n\nvar VerticalOrigin = new r.Struct({\n  glyphIndex: r.uint16,\n  vertOriginY: r.int16\n});\n\nvar VORG = new r.Struct({\n  majorVersion: r.uint16,\n  minorVersion: r.uint16,\n  defaultVertOriginY: r.int16,\n  numVertOriginYMetrics: r.uint16,\n  metrics: new r.Array(VerticalOrigin, 'numVertOriginYMetrics')\n});\n\nvar BigMetrics = new r.Struct({\n  height: r.uint8,\n  width: r.uint8,\n  horiBearingX: r.int8,\n  horiBearingY: r.int8,\n  horiAdvance: r.uint8,\n  vertBearingX: r.int8,\n  vertBearingY: r.int8,\n  vertAdvance: r.uint8\n});\n\nvar SmallMetrics = new r.Struct({\n  height: r.uint8,\n  width: r.uint8,\n  bearingX: r.int8,\n  bearingY: r.int8,\n  advance: r.uint8\n});\n\nvar EBDTComponent = new r.Struct({\n  glyph: r.uint16,\n  xOffset: r.int8,\n  yOffset: r.int8\n});\n\nvar ByteAligned = function ByteAligned() {\n  _classCallCheck(this, ByteAligned);\n};\n\nvar BitAligned = function BitAligned() {\n  _classCallCheck(this, BitAligned);\n};\n\nvar glyph = new r.VersionedStruct('version', {\n  1: {\n    metrics: SmallMetrics,\n    data: ByteAligned\n  },\n\n  2: {\n    metrics: SmallMetrics,\n    data: BitAligned\n  },\n\n  // format 3 is deprecated\n  // format 4 is not supported by Microsoft\n\n  5: {\n    data: BitAligned\n  },\n\n  6: {\n    metrics: BigMetrics,\n    data: ByteAligned\n  },\n\n  7: {\n    metrics: BigMetrics,\n    data: BitAligned\n  },\n\n  8: {\n    metrics: SmallMetrics,\n    pad: new r.Reserved(r.uint8),\n    numComponents: r.uint16,\n    components: new r.Array(EBDTComponent, 'numComponents')\n  },\n\n  9: {\n    metrics: BigMetrics,\n    pad: new r.Reserved(r.uint8),\n    numComponents: r.uint16,\n    components: new r.Array(EBDTComponent, 'numComponents')\n  },\n\n  17: {\n    metrics: SmallMetrics,\n    dataLen: r.uint32,\n    data: new r.Buffer('dataLen')\n  },\n\n  18: {\n    metrics: BigMetrics,\n    dataLen: r.uint32,\n    data: new r.Buffer('dataLen')\n  },\n\n  19: {\n    dataLen: r.uint32,\n    data: new r.Buffer('dataLen')\n  }\n});\n\nvar SBitLineMetrics = new r.Struct({\n  ascender: r.int8,\n  descender: r.int8,\n  widthMax: r.uint8,\n  caretSlopeNumerator: r.int8,\n  caretSlopeDenominator: r.int8,\n  caretOffset: r.int8,\n  minOriginSB: r.int8,\n  minAdvanceSB: r.int8,\n  maxBeforeBL: r.int8,\n  minAfterBL: r.int8,\n  pad: new r.Reserved(r.int8, 2)\n});\n\nvar CodeOffsetPair = new r.Struct({\n  glyphCode: r.uint16,\n  offset: r.uint16\n});\n\nvar IndexSubtable = new r.VersionedStruct(r.uint16, {\n  header: {\n    imageFormat: r.uint16,\n    imageDataOffset: r.uint32\n  },\n\n  1: {\n    offsetArray: new r.Array(r.uint32, function (t) {\n      return t.parent.lastGlyphIndex - t.parent.firstGlyphIndex + 1;\n    })\n  },\n\n  2: {\n    imageSize: r.uint32,\n    bigMetrics: BigMetrics\n  },\n\n  3: {\n    offsetArray: new r.Array(r.uint16, function (t) {\n      return t.parent.lastGlyphIndex - t.parent.firstGlyphIndex + 1;\n    })\n  },\n\n  4: {\n    numGlyphs: r.uint32,\n    glyphArray: new r.Array(CodeOffsetPair, function (t) {\n      return t.numGlyphs + 1;\n    })\n  },\n\n  5: {\n    imageSize: r.uint32,\n    bigMetrics: BigMetrics,\n    numGlyphs: r.uint32,\n    glyphCodeArray: new r.Array(r.uint16, 'numGlyphs')\n  }\n});\n\nvar IndexSubtableArray = new r.Struct({\n  firstGlyphIndex: r.uint16,\n  lastGlyphIndex: r.uint16,\n  subtable: new r.Pointer(r.uint32, IndexSubtable)\n});\n\nvar BitmapSizeTable = new r.Struct({\n  indexSubTableArray: new r.Pointer(r.uint32, new r.Array(IndexSubtableArray, 1), { type: 'parent' }),\n  indexTablesSize: r.uint32,\n  numberOfIndexSubTables: r.uint32,\n  colorRef: r.uint32,\n  hori: SBitLineMetrics,\n  vert: SBitLineMetrics,\n  startGlyphIndex: r.uint16,\n  endGlyphIndex: r.uint16,\n  ppemX: r.uint8,\n  ppemY: r.uint8,\n  bitDepth: r.uint8,\n  flags: new r.Bitfield(r.uint8, ['horizontal', 'vertical'])\n});\n\nvar EBLC = new r.Struct({\n  version: r.uint32, // 0x00020000\n  numSizes: r.uint32,\n  sizes: new r.Array(BitmapSizeTable, 'numSizes')\n});\n\nvar ImageTable = new r.Struct({\n  ppem: r.uint16,\n  resolution: r.uint16,\n  imageOffsets: new r.Array(new r.Pointer(r.uint32, 'void'), function (t) {\n    return t.parent.parent.maxp.numGlyphs + 1;\n  })\n});\n\n// This is the Apple sbix table, used by the \"Apple Color Emoji\" font.\n// It includes several image tables with images for each bitmap glyph\n// of several different sizes.\nvar sbix = new r.Struct({\n  version: r.uint16,\n  flags: new r.Bitfield(r.uint16, ['renderOutlines']),\n  numImgTables: r.uint32,\n  imageTables: new r.Array(new r.Pointer(r.uint32, ImageTable), 'numImgTables')\n});\n\nvar LayerRecord = new r.Struct({\n  gid: r.uint16, // Glyph ID of layer glyph (must be in z-order from bottom to top).\n  paletteIndex: r.uint16 // Index value to use in the appropriate palette. This value must\n}); // be less than numPaletteEntries in the CPAL table, except for\n// the special case noted below. Each palette entry is 16 bits.\n// A palette index of 0xFFFF is a special case indicating that\n// the text foreground color should be used.\n\nvar BaseGlyphRecord = new r.Struct({\n  gid: r.uint16, // Glyph ID of reference glyph. This glyph is for reference only\n  // and is not rendered for color.\n  firstLayerIndex: r.uint16, // Index (from beginning of the Layer Records) to the layer record.\n  // There will be numLayers consecutive entries for this base glyph.\n  numLayers: r.uint16\n});\n\nvar COLR = new r.Struct({\n  version: r.uint16,\n  numBaseGlyphRecords: r.uint16,\n  baseGlyphRecord: new r.Pointer(r.uint32, new r.Array(BaseGlyphRecord, 'numBaseGlyphRecords')),\n  layerRecords: new r.Pointer(r.uint32, new r.Array(LayerRecord, 'numLayerRecords'), { lazy: true }),\n  numLayerRecords: r.uint16\n});\n\nvar ColorRecord = new r.Struct({\n  blue: r.uint8,\n  green: r.uint8,\n  red: r.uint8,\n  alpha: r.uint8\n});\n\nvar CPAL = new r.VersionedStruct(r.uint16, {\n  header: {\n    numPaletteEntries: r.uint16,\n    numPalettes: r.uint16,\n    numColorRecords: r.uint16,\n    colorRecords: new r.Pointer(r.uint32, new r.Array(ColorRecord, 'numColorRecords')),\n    colorRecordIndices: new r.Array(r.uint16, 'numPalettes')\n  },\n  0: {},\n  1: {\n    offsetPaletteTypeArray: new r.Pointer(r.uint32, new r.Array(r.uint32, 'numPalettes')),\n    offsetPaletteLabelArray: new r.Pointer(r.uint32, new r.Array(r.uint16, 'numPalettes')),\n    offsetPaletteEntryLabelArray: new r.Pointer(r.uint32, new r.Array(r.uint16, 'numPaletteEntries'))\n  }\n});\n\nvar BaseCoord = new r.VersionedStruct(r.uint16, {\n  1: { // Design units only\n    coordinate: r.int16 // X or Y value, in design units\n  },\n\n  2: { // Design units plus contour point\n    coordinate: r.int16, // X or Y value, in design units\n    referenceGlyph: r.uint16, // GlyphID of control glyph\n    baseCoordPoint: r.uint16 // Index of contour point on the referenceGlyph\n  },\n\n  3: { // Design units plus Device table\n    coordinate: r.int16, // X or Y value, in design units\n    deviceTable: new r.Pointer(r.uint16, Device) // Device table for X or Y value\n  }\n});\n\nvar BaseValues = new r.Struct({\n  defaultIndex: r.uint16, // Index of default baseline for this script-same index in the BaseTagList\n  baseCoordCount: r.uint16,\n  baseCoords: new r.Array(new r.Pointer(r.uint16, BaseCoord), 'baseCoordCount')\n});\n\nvar FeatMinMaxRecord = new r.Struct({\n  tag: new r.String(4), // 4-byte feature identification tag-must match FeatureTag in FeatureList\n  minCoord: new r.Pointer(r.uint16, BaseCoord, { type: 'parent' }), // May be NULL\n  maxCoord: new r.Pointer(r.uint16, BaseCoord, { type: 'parent' }) // May be NULL\n});\n\nvar MinMax = new r.Struct({\n  minCoord: new r.Pointer(r.uint16, BaseCoord), // May be NULL\n  maxCoord: new r.Pointer(r.uint16, BaseCoord), // May be NULL\n  featMinMaxCount: r.uint16, // May be 0\n  featMinMaxRecords: new r.Array(FeatMinMaxRecord, 'featMinMaxCount') // In alphabetical order\n});\n\nvar BaseLangSysRecord = new r.Struct({\n  tag: new r.String(4), // 4-byte language system identification tag\n  minMax: new r.Pointer(r.uint16, MinMax, { type: 'parent' })\n});\n\nvar BaseScript = new r.Struct({\n  baseValues: new r.Pointer(r.uint16, BaseValues), // May be NULL\n  defaultMinMax: new r.Pointer(r.uint16, MinMax), // May be NULL\n  baseLangSysCount: r.uint16, // May be 0\n  baseLangSysRecords: new r.Array(BaseLangSysRecord, 'baseLangSysCount') // in alphabetical order by BaseLangSysTag\n});\n\nvar BaseScriptRecord = new r.Struct({\n  tag: new r.String(4), // 4-byte script identification tag\n  script: new r.Pointer(r.uint16, BaseScript, { type: 'parent' })\n});\n\nvar BaseScriptList = new r.Array(BaseScriptRecord, r.uint16);\n\n// Array of 4-byte baseline identification tags-must be in alphabetical order\nvar BaseTagList = new r.Array(new r.String(4), r.uint16);\n\nvar Axis = new r.Struct({\n  baseTagList: new r.Pointer(r.uint16, BaseTagList), // May be NULL\n  baseScriptList: new r.Pointer(r.uint16, BaseScriptList)\n});\n\nvar BASE = new r.VersionedStruct(r.uint32, {\n  header: {\n    horizAxis: new r.Pointer(r.uint16, Axis), // May be NULL\n    vertAxis: new r.Pointer(r.uint16, Axis) // May be NULL\n  },\n\n  0x00010000: {},\n  0x00010001: {\n    itemVariationStore: new r.Pointer(r.uint32, ItemVariationStore)\n  }\n});\n\nvar AttachPoint = new r.Array(r.uint16, r.uint16);\nvar AttachList = new r.Struct({\n  coverage: new r.Pointer(r.uint16, Coverage),\n  glyphCount: r.uint16,\n  attachPoints: new r.Array(new r.Pointer(r.uint16, AttachPoint), 'glyphCount')\n});\n\nvar CaretValue = new r.VersionedStruct(r.uint16, {\n  1: { // Design units only\n    coordinate: r.int16\n  },\n\n  2: { // Contour point\n    caretValuePoint: r.uint16\n  },\n\n  3: { // Design units plus Device table\n    coordinate: r.int16,\n    deviceTable: new r.Pointer(r.uint16, Device)\n  }\n});\n\nvar LigGlyph = new r.Array(new r.Pointer(r.uint16, CaretValue), r.uint16);\n\nvar LigCaretList = new r.Struct({\n  coverage: new r.Pointer(r.uint16, Coverage),\n  ligGlyphCount: r.uint16,\n  ligGlyphs: new r.Array(new r.Pointer(r.uint16, LigGlyph), 'ligGlyphCount')\n});\n\nvar MarkGlyphSetsDef = new r.Struct({\n  markSetTableFormat: r.uint16,\n  markSetCount: r.uint16,\n  coverage: new r.Array(new r.Pointer(r.uint32, Coverage), 'markSetCount')\n});\n\nvar GDEF = new r.VersionedStruct(r.uint32, {\n  header: {\n    glyphClassDef: new r.Pointer(r.uint16, ClassDef),\n    attachList: new r.Pointer(r.uint16, AttachList),\n    ligCaretList: new r.Pointer(r.uint16, LigCaretList),\n    markAttachClassDef: new r.Pointer(r.uint16, ClassDef)\n  },\n\n  0x00010000: {},\n  0x00010002: {\n    markGlyphSetsDef: new r.Pointer(r.uint16, MarkGlyphSetsDef)\n  },\n  0x00010003: {\n    markGlyphSetsDef: new r.Pointer(r.uint16, MarkGlyphSetsDef),\n    itemVariationStore: new r.Pointer(r.uint32, ItemVariationStore)\n  }\n});\n\nvar ValueFormat = new r.Bitfield(r.uint16, ['xPlacement', 'yPlacement', 'xAdvance', 'yAdvance', 'xPlaDevice', 'yPlaDevice', 'xAdvDevice', 'yAdvDevice']);\n\nvar types = {\n  xPlacement: r.int16,\n  yPlacement: r.int16,\n  xAdvance: r.int16,\n  yAdvance: r.int16,\n  xPlaDevice: new r.Pointer(r.uint16, Device, { type: 'global', relativeTo: 'rel' }),\n  yPlaDevice: new r.Pointer(r.uint16, Device, { type: 'global', relativeTo: 'rel' }),\n  xAdvDevice: new r.Pointer(r.uint16, Device, { type: 'global', relativeTo: 'rel' }),\n  yAdvDevice: new r.Pointer(r.uint16, Device, { type: 'global', relativeTo: 'rel' })\n};\n\nvar ValueRecord = function () {\n  function ValueRecord() {\n    var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'valueFormat';\n\n    _classCallCheck(this, ValueRecord);\n\n    this.key = key;\n  }\n\n  ValueRecord.prototype.buildStruct = function buildStruct(parent) {\n    var struct = parent;\n    while (!struct[this.key] && struct.parent) {\n      struct = struct.parent;\n    }\n\n    if (!struct[this.key]) return;\n\n    var fields = {};\n    fields.rel = function () {\n      return struct._startOffset;\n    };\n\n    var format = struct[this.key];\n    for (var key in format) {\n      if (format[key]) {\n        fields[key] = types[key];\n      }\n    }\n\n    return new r.Struct(fields);\n  };\n\n  ValueRecord.prototype.size = function size(val, ctx) {\n    return this.buildStruct(ctx).size(val, ctx);\n  };\n\n  ValueRecord.prototype.decode = function decode(stream, parent) {\n    var res = this.buildStruct(parent).decode(stream, parent);\n    delete res.rel;\n    return res;\n  };\n\n  return ValueRecord;\n}();\n\nvar PairValueRecord = new r.Struct({\n  secondGlyph: r.uint16,\n  value1: new ValueRecord('valueFormat1'),\n  value2: new ValueRecord('valueFormat2')\n});\n\nvar PairSet = new r.Array(PairValueRecord, r.uint16);\n\nvar Class2Record = new r.Struct({\n  value1: new ValueRecord('valueFormat1'),\n  value2: new ValueRecord('valueFormat2')\n});\n\nvar Anchor = new r.VersionedStruct(r.uint16, {\n  1: { // Design units only\n    xCoordinate: r.int16,\n    yCoordinate: r.int16\n  },\n\n  2: { // Design units plus contour point\n    xCoordinate: r.int16,\n    yCoordinate: r.int16,\n    anchorPoint: r.uint16\n  },\n\n  3: { // Design units plus Device tables\n    xCoordinate: r.int16,\n    yCoordinate: r.int16,\n    xDeviceTable: new r.Pointer(r.uint16, Device),\n    yDeviceTable: new r.Pointer(r.uint16, Device)\n  }\n});\n\nvar EntryExitRecord = new r.Struct({\n  entryAnchor: new r.Pointer(r.uint16, Anchor, { type: 'parent' }),\n  exitAnchor: new r.Pointer(r.uint16, Anchor, { type: 'parent' })\n});\n\nvar MarkRecord = new r.Struct({\n  class: r.uint16,\n  markAnchor: new r.Pointer(r.uint16, Anchor, { type: 'parent' })\n});\n\nvar MarkArray = new r.Array(MarkRecord, r.uint16);\n\nvar BaseRecord = new r.Array(new r.Pointer(r.uint16, Anchor), function (t) {\n  return t.parent.classCount;\n});\nvar BaseArray = new r.Array(BaseRecord, r.uint16);\n\nvar ComponentRecord = new r.Array(new r.Pointer(r.uint16, Anchor), function (t) {\n  return t.parent.parent.classCount;\n});\nvar LigatureAttach = new r.Array(ComponentRecord, r.uint16);\nvar LigatureArray = new r.Array(new r.Pointer(r.uint16, LigatureAttach), r.uint16);\n\nvar GPOSLookup = new r.VersionedStruct('lookupType', {\n  1: new r.VersionedStruct(r.uint16, { // Single Adjustment\n    1: { // Single positioning value\n      coverage: new r.Pointer(r.uint16, Coverage),\n      valueFormat: ValueFormat,\n      value: new ValueRecord()\n    },\n    2: {\n      coverage: new r.Pointer(r.uint16, Coverage),\n      valueFormat: ValueFormat,\n      valueCount: r.uint16,\n      values: new r.LazyArray(new ValueRecord(), 'valueCount')\n    }\n  }),\n\n  2: new r.VersionedStruct(r.uint16, { // Pair Adjustment Positioning\n    1: { // Adjustments for glyph pairs\n      coverage: new r.Pointer(r.uint16, Coverage),\n      valueFormat1: ValueFormat,\n      valueFormat2: ValueFormat,\n      pairSetCount: r.uint16,\n      pairSets: new r.LazyArray(new r.Pointer(r.uint16, PairSet), 'pairSetCount')\n    },\n\n    2: { // Class pair adjustment\n      coverage: new r.Pointer(r.uint16, Coverage),\n      valueFormat1: ValueFormat,\n      valueFormat2: ValueFormat,\n      classDef1: new r.Pointer(r.uint16, ClassDef),\n      classDef2: new r.Pointer(r.uint16, ClassDef),\n      class1Count: r.uint16,\n      class2Count: r.uint16,\n      classRecords: new r.LazyArray(new r.LazyArray(Class2Record, 'class2Count'), 'class1Count')\n    }\n  }),\n\n  3: { // Cursive Attachment Positioning\n    format: r.uint16,\n    coverage: new r.Pointer(r.uint16, Coverage),\n    entryExitCount: r.uint16,\n    entryExitRecords: new r.Array(EntryExitRecord, 'entryExitCount')\n  },\n\n  4: { // MarkToBase Attachment Positioning\n    format: r.uint16,\n    markCoverage: new r.Pointer(r.uint16, Coverage),\n    baseCoverage: new r.Pointer(r.uint16, Coverage),\n    classCount: r.uint16,\n    markArray: new r.Pointer(r.uint16, MarkArray),\n    baseArray: new r.Pointer(r.uint16, BaseArray)\n  },\n\n  5: { // MarkToLigature Attachment Positioning\n    format: r.uint16,\n    markCoverage: new r.Pointer(r.uint16, Coverage),\n    ligatureCoverage: new r.Pointer(r.uint16, Coverage),\n    classCount: r.uint16,\n    markArray: new r.Pointer(r.uint16, MarkArray),\n    ligatureArray: new r.Pointer(r.uint16, LigatureArray)\n  },\n\n  6: { // MarkToMark Attachment Positioning\n    format: r.uint16,\n    mark1Coverage: new r.Pointer(r.uint16, Coverage),\n    mark2Coverage: new r.Pointer(r.uint16, Coverage),\n    classCount: r.uint16,\n    mark1Array: new r.Pointer(r.uint16, MarkArray),\n    mark2Array: new r.Pointer(r.uint16, BaseArray)\n  },\n\n  7: Context, // Contextual positioning\n  8: ChainingContext, // Chaining contextual positioning\n\n  9: { // Extension Positioning\n    posFormat: r.uint16,\n    lookupType: r.uint16, // cannot also be 9\n    extension: new r.Pointer(r.uint32, GPOSLookup)\n  }\n});\n\n// Fix circular reference\nGPOSLookup.versions[9].extension.type = GPOSLookup;\n\nvar GPOS = new r.VersionedStruct(r.uint32, {\n  header: {\n    scriptList: new r.Pointer(r.uint16, ScriptList),\n    featureList: new r.Pointer(r.uint16, FeatureList),\n    lookupList: new r.Pointer(r.uint16, new LookupList(GPOSLookup))\n  },\n\n  0x00010000: {},\n  0x00010001: {\n    featureVariations: new r.Pointer(r.uint32, FeatureVariations)\n  }\n});\n\nvar Sequence = new r.Array(r.uint16, r.uint16);\nvar AlternateSet = Sequence;\n\nvar Ligature = new r.Struct({\n  glyph: r.uint16,\n  compCount: r.uint16,\n  components: new r.Array(r.uint16, function (t) {\n    return t.compCount - 1;\n  })\n});\n\nvar LigatureSet = new r.Array(new r.Pointer(r.uint16, Ligature), r.uint16);\n\nvar GSUBLookup = new r.VersionedStruct('lookupType', {\n  1: new r.VersionedStruct(r.uint16, { // Single Substitution\n    1: {\n      coverage: new r.Pointer(r.uint16, Coverage),\n      deltaGlyphID: r.int16\n    },\n    2: {\n      coverage: new r.Pointer(r.uint16, Coverage),\n      glyphCount: r.uint16,\n      substitute: new r.LazyArray(r.uint16, 'glyphCount')\n    }\n  }),\n\n  2: { // Multiple Substitution\n    substFormat: r.uint16,\n    coverage: new r.Pointer(r.uint16, Coverage),\n    count: r.uint16,\n    sequences: new r.LazyArray(new r.Pointer(r.uint16, Sequence), 'count')\n  },\n\n  3: { // Alternate Substitution\n    substFormat: r.uint16,\n    coverage: new r.Pointer(r.uint16, Coverage),\n    count: r.uint16,\n    alternateSet: new r.LazyArray(new r.Pointer(r.uint16, AlternateSet), 'count')\n  },\n\n  4: { // Ligature Substitution\n    substFormat: r.uint16,\n    coverage: new r.Pointer(r.uint16, Coverage),\n    count: r.uint16,\n    ligatureSets: new r.LazyArray(new r.Pointer(r.uint16, LigatureSet), 'count')\n  },\n\n  5: Context, // Contextual Substitution\n  6: ChainingContext, // Chaining Contextual Substitution\n\n  7: { // Extension Substitution\n    substFormat: r.uint16,\n    lookupType: r.uint16, // cannot also be 7\n    extension: new r.Pointer(r.uint32, GSUBLookup)\n  },\n\n  8: { // Reverse Chaining Contextual Single Substitution\n    substFormat: r.uint16,\n    coverage: new r.Pointer(r.uint16, Coverage),\n    backtrackCoverage: new r.Array(new r.Pointer(r.uint16, Coverage), 'backtrackGlyphCount'),\n    lookaheadGlyphCount: r.uint16,\n    lookaheadCoverage: new r.Array(new r.Pointer(r.uint16, Coverage), 'lookaheadGlyphCount'),\n    glyphCount: r.uint16,\n    substitutes: new r.Array(r.uint16, 'glyphCount')\n  }\n});\n\n// Fix circular reference\nGSUBLookup.versions[7].extension.type = GSUBLookup;\n\nvar GSUB = new r.VersionedStruct(r.uint32, {\n  header: {\n    scriptList: new r.Pointer(r.uint16, ScriptList),\n    featureList: new r.Pointer(r.uint16, FeatureList),\n    lookupList: new r.Pointer(r.uint16, new LookupList(GSUBLookup))\n  },\n\n  0x00010000: {},\n  0x00010001: {\n    featureVariations: new r.Pointer(r.uint32, FeatureVariations)\n  }\n});\n\nvar JstfGSUBModList = new r.Array(r.uint16, r.uint16);\n\nvar JstfPriority = new r.Struct({\n  shrinkageEnableGSUB: new r.Pointer(r.uint16, JstfGSUBModList),\n  shrinkageDisableGSUB: new r.Pointer(r.uint16, JstfGSUBModList),\n  shrinkageEnableGPOS: new r.Pointer(r.uint16, JstfGSUBModList),\n  shrinkageDisableGPOS: new r.Pointer(r.uint16, JstfGSUBModList),\n  shrinkageJstfMax: new r.Pointer(r.uint16, new LookupList(GPOSLookup)),\n  extensionEnableGSUB: new r.Pointer(r.uint16, JstfGSUBModList),\n  extensionDisableGSUB: new r.Pointer(r.uint16, JstfGSUBModList),\n  extensionEnableGPOS: new r.Pointer(r.uint16, JstfGSUBModList),\n  extensionDisableGPOS: new r.Pointer(r.uint16, JstfGSUBModList),\n  extensionJstfMax: new r.Pointer(r.uint16, new LookupList(GPOSLookup))\n});\n\nvar JstfLangSys = new r.Array(new r.Pointer(r.uint16, JstfPriority), r.uint16);\n\nvar JstfLangSysRecord = new r.Struct({\n  tag: new r.String(4),\n  jstfLangSys: new r.Pointer(r.uint16, JstfLangSys)\n});\n\nvar JstfScript = new r.Struct({\n  extenderGlyphs: new r.Pointer(r.uint16, new r.Array(r.uint16, r.uint16)), // array of glyphs to extend line length\n  defaultLangSys: new r.Pointer(r.uint16, JstfLangSys),\n  langSysCount: r.uint16,\n  langSysRecords: new r.Array(JstfLangSysRecord, 'langSysCount')\n});\n\nvar JstfScriptRecord = new r.Struct({\n  tag: new r.String(4),\n  script: new r.Pointer(r.uint16, JstfScript, { type: 'parent' })\n});\n\nvar JSTF = new r.Struct({\n  version: r.uint32, // should be 0x00010000\n  scriptCount: r.uint16,\n  scriptList: new r.Array(JstfScriptRecord, 'scriptCount')\n});\n\n// TODO: add this to restructure\n\nvar VariableSizeNumber = function () {\n  function VariableSizeNumber(size) {\n    _classCallCheck(this, VariableSizeNumber);\n\n    this._size = size;\n  }\n\n  VariableSizeNumber.prototype.decode = function decode(stream, parent) {\n    switch (this.size(0, parent)) {\n      case 1:\n        return stream.readUInt8();\n      case 2:\n        return stream.readUInt16BE();\n      case 3:\n        return stream.readUInt24BE();\n      case 4:\n        return stream.readUInt32BE();\n    }\n  };\n\n  VariableSizeNumber.prototype.size = function size(val, parent) {\n    return restructure_src_utils.resolveLength(this._size, null, parent);\n  };\n\n  return VariableSizeNumber;\n}();\n\nvar MapDataEntry = new r.Struct({\n  entry: new VariableSizeNumber(function (t) {\n    return ((t.parent.entryFormat & 0x0030) >> 4) + 1;\n  }),\n  outerIndex: function outerIndex(t) {\n    return t.entry >> (t.parent.entryFormat & 0x000F) + 1;\n  },\n  innerIndex: function innerIndex(t) {\n    return t.entry & (1 << (t.parent.entryFormat & 0x000F) + 1) - 1;\n  }\n});\n\nvar DeltaSetIndexMap = new r.Struct({\n  entryFormat: r.uint16,\n  mapCount: r.uint16,\n  mapData: new r.Array(MapDataEntry, 'mapCount')\n});\n\nvar HVAR = new r.Struct({\n  majorVersion: r.uint16,\n  minorVersion: r.uint16,\n  itemVariationStore: new r.Pointer(r.uint32, ItemVariationStore),\n  advanceWidthMapping: new r.Pointer(r.uint32, DeltaSetIndexMap),\n  LSBMapping: new r.Pointer(r.uint32, DeltaSetIndexMap),\n  RSBMapping: new r.Pointer(r.uint32, DeltaSetIndexMap)\n});\n\nvar Signature = new r.Struct({\n  format: r.uint32,\n  length: r.uint32,\n  offset: r.uint32\n});\n\nvar SignatureBlock = new r.Struct({\n  reserved: new r.Reserved(r.uint16, 2),\n  cbSignature: r.uint32, // Length (in bytes) of the PKCS#7 packet in pbSignature\n  signature: new r.Buffer('cbSignature')\n});\n\nvar DSIG = new r.Struct({\n  ulVersion: r.uint32, // Version number of the DSIG table (0x00000001)\n  usNumSigs: r.uint16, // Number of signatures in the table\n  usFlag: r.uint16, // Permission flags\n  signatures: new r.Array(Signature, 'usNumSigs'),\n  signatureBlocks: new r.Array(SignatureBlock, 'usNumSigs')\n});\n\nvar GaspRange = new r.Struct({\n  rangeMaxPPEM: r.uint16, // Upper limit of range, in ppem\n  rangeGaspBehavior: new r.Bitfield(r.uint16, [// Flags describing desired rasterizer behavior\n  'grayscale', 'gridfit', 'symmetricSmoothing', 'symmetricGridfit' // only in version 1, for ClearType\n  ])\n});\n\nvar gasp = new r.Struct({\n  version: r.uint16, // set to 0\n  numRanges: r.uint16,\n  gaspRanges: new r.Array(GaspRange, 'numRanges') // Sorted by ppem\n});\n\nvar DeviceRecord = new r.Struct({\n  pixelSize: r.uint8,\n  maximumWidth: r.uint8,\n  widths: new r.Array(r.uint8, function (t) {\n    return t.parent.parent.maxp.numGlyphs;\n  })\n});\n\n// The Horizontal Device Metrics table stores integer advance widths scaled to particular pixel sizes\nvar hdmx = new r.Struct({\n  version: r.uint16,\n  numRecords: r.int16,\n  sizeDeviceRecord: r.int32,\n  records: new r.Array(DeviceRecord, 'numRecords')\n});\n\nvar KernPair = new r.Struct({\n  left: r.uint16,\n  right: r.uint16,\n  value: r.int16\n});\n\nvar ClassTable = new r.Struct({\n  firstGlyph: r.uint16,\n  nGlyphs: r.uint16,\n  offsets: new r.Array(r.uint16, 'nGlyphs'),\n  max: function max(t) {\n    return t.offsets.length && Math.max.apply(Math, t.offsets);\n  }\n});\n\nvar Kern2Array = new r.Struct({\n  off: function off(t) {\n    return t._startOffset - t.parent.parent._startOffset;\n  },\n  len: function len(t) {\n    return ((t.parent.leftTable.max - t.off) / t.parent.rowWidth + 1) * (t.parent.rowWidth / 2);\n  },\n  values: new r.LazyArray(r.int16, 'len')\n});\n\nvar KernSubtable = new r.VersionedStruct('format', {\n  0: {\n    nPairs: r.uint16,\n    searchRange: r.uint16,\n    entrySelector: r.uint16,\n    rangeShift: r.uint16,\n    pairs: new r.Array(KernPair, 'nPairs')\n  },\n\n  2: {\n    rowWidth: r.uint16,\n    leftTable: new r.Pointer(r.uint16, ClassTable, { type: 'parent' }),\n    rightTable: new r.Pointer(r.uint16, ClassTable, { type: 'parent' }),\n    array: new r.Pointer(r.uint16, Kern2Array, { type: 'parent' })\n  },\n\n  3: {\n    glyphCount: r.uint16,\n    kernValueCount: r.uint8,\n    leftClassCount: r.uint8,\n    rightClassCount: r.uint8,\n    flags: r.uint8,\n    kernValue: new r.Array(r.int16, 'kernValueCount'),\n    leftClass: new r.Array(r.uint8, 'glyphCount'),\n    rightClass: new r.Array(r.uint8, 'glyphCount'),\n    kernIndex: new r.Array(r.uint8, function (t) {\n      return t.leftClassCount * t.rightClassCount;\n    })\n  }\n});\n\nvar KernTable = new r.VersionedStruct('version', {\n  0: { // Microsoft uses this format\n    subVersion: r.uint16, // Microsoft has an extra sub-table version number\n    length: r.uint16, // Length of the subtable, in bytes\n    format: r.uint8, // Format of subtable\n    coverage: new r.Bitfield(r.uint8, ['horizontal', // 1 if table has horizontal data, 0 if vertical\n    'minimum', // If set to 1, the table has minimum values. If set to 0, the table has kerning values.\n    'crossStream', // If set to 1, kerning is perpendicular to the flow of the text\n    'override' // If set to 1 the value in this table replaces the accumulated value\n    ]),\n    subtable: KernSubtable,\n    padding: new r.Reserved(r.uint8, function (t) {\n      return t.length - t._currentOffset;\n    })\n  },\n  1: { // Apple uses this format\n    length: r.uint32,\n    coverage: new r.Bitfield(r.uint8, [null, null, null, null, null, 'variation', // Set if table has variation kerning values\n    'crossStream', // Set if table has cross-stream kerning values\n    'vertical' // Set if table has vertical kerning values\n    ]),\n    format: r.uint8,\n    tupleIndex: r.uint16,\n    subtable: KernSubtable,\n    padding: new r.Reserved(r.uint8, function (t) {\n      return t.length - t._currentOffset;\n    })\n  }\n});\n\nvar kern = new r.VersionedStruct(r.uint16, {\n  0: { // Microsoft Version\n    nTables: r.uint16,\n    tables: new r.Array(KernTable, 'nTables')\n  },\n\n  1: { // Apple Version\n    reserved: new r.Reserved(r.uint16), // the other half of the version number\n    nTables: r.uint32,\n    tables: new r.Array(KernTable, 'nTables')\n  }\n});\n\n// Linear Threshold table\n// Records the ppem for each glyph at which the scaling becomes linear again,\n// despite instructions effecting the advance width\nvar LTSH = new r.Struct({\n  version: r.uint16,\n  numGlyphs: r.uint16,\n  yPels: new r.Array(r.uint8, 'numGlyphs')\n});\n\n// PCL 5 Table\n// NOTE: The PCLT table is strongly discouraged for OpenType fonts with TrueType outlines\nvar PCLT = new r.Struct({\n  version: r.uint16,\n  fontNumber: r.uint32,\n  pitch: r.uint16,\n  xHeight: r.uint16,\n  style: r.uint16,\n  typeFamily: r.uint16,\n  capHeight: r.uint16,\n  symbolSet: r.uint16,\n  typeface: new r.String(16),\n  characterComplement: new r.String(8),\n  fileName: new r.String(6),\n  strokeWeight: new r.String(1),\n  widthType: new r.String(1),\n  serifStyle: r.uint8,\n  reserved: new r.Reserved(r.uint8)\n});\n\n// VDMX tables contain ascender/descender overrides for certain (usually small)\n// sizes. This is needed in order to match font metrics on Windows.\n\nvar Ratio = new r.Struct({\n  bCharSet: r.uint8, // Character set\n  xRatio: r.uint8, // Value to use for x-Ratio\n  yStartRatio: r.uint8, // Starting y-Ratio value\n  yEndRatio: r.uint8 // Ending y-Ratio value\n});\n\nvar vTable = new r.Struct({\n  yPelHeight: r.uint16, // yPelHeight to which values apply\n  yMax: r.int16, // Maximum value (in pels) for this yPelHeight\n  yMin: r.int16 // Minimum value (in pels) for this yPelHeight\n});\n\nvar VdmxGroup = new r.Struct({\n  recs: r.uint16, // Number of height records in this group\n  startsz: r.uint8, // Starting yPelHeight\n  endsz: r.uint8, // Ending yPelHeight\n  entries: new r.Array(vTable, 'recs') // The VDMX records\n});\n\nvar VDMX = new r.Struct({\n  version: r.uint16, // Version number (0 or 1)\n  numRecs: r.uint16, // Number of VDMX groups present\n  numRatios: r.uint16, // Number of aspect ratio groupings\n  ratioRanges: new r.Array(Ratio, 'numRatios'), // Ratio ranges\n  offsets: new r.Array(r.uint16, 'numRatios'), // Offset to the VDMX group for this ratio range\n  groups: new r.Array(VdmxGroup, 'numRecs') // The actual VDMX groupings\n});\n\n// Vertical Header Table\nvar vhea = new r.Struct({\n  version: r.uint16, // Version number of the Vertical Header Table\n  ascent: r.int16, // The vertical typographic ascender for this font\n  descent: r.int16, // The vertical typographic descender for this font\n  lineGap: r.int16, // The vertical typographic line gap for this font\n  advanceHeightMax: r.int16, // The maximum advance height measurement found in the font\n  minTopSideBearing: r.int16, // The minimum top side bearing measurement found in the font\n  minBottomSideBearing: r.int16, // The minimum bottom side bearing measurement found in the font\n  yMaxExtent: r.int16,\n  caretSlopeRise: r.int16, // Caret slope (rise/run)\n  caretSlopeRun: r.int16,\n  caretOffset: r.int16, // Set value equal to 0 for nonslanted fonts\n  reserved: new r.Reserved(r.int16, 4),\n  metricDataFormat: r.int16, // Set to 0\n  numberOfMetrics: r.uint16 // Number of advance heights in the Vertical Metrics table\n});\n\nvar VmtxEntry = new r.Struct({\n  advance: r.uint16, // The advance height of the glyph\n  bearing: r.int16 // The top sidebearing of the glyph\n});\n\n// Vertical Metrics Table\nvar vmtx = new r.Struct({\n  metrics: new r.LazyArray(VmtxEntry, function (t) {\n    return t.parent.vhea.numberOfMetrics;\n  }),\n  bearings: new r.LazyArray(r.int16, function (t) {\n    return t.parent.maxp.numGlyphs - t.parent.vhea.numberOfMetrics;\n  })\n});\n\nvar shortFrac = new r.Fixed(16, 'BE', 14);\n\nvar Correspondence = new r.Struct({\n  fromCoord: shortFrac,\n  toCoord: shortFrac\n});\n\nvar Segment = new r.Struct({\n  pairCount: r.uint16,\n  correspondence: new r.Array(Correspondence, 'pairCount')\n});\n\nvar avar = new r.Struct({\n  version: r.fixed32,\n  axisCount: r.uint32,\n  segment: new r.Array(Segment, 'axisCount')\n});\n\nvar UnboundedArrayAccessor = function () {\n  function UnboundedArrayAccessor(type, stream, parent) {\n    _classCallCheck(this, UnboundedArrayAccessor);\n\n    this.type = type;\n    this.stream = stream;\n    this.parent = parent;\n    this.base = this.stream.pos;\n    this._items = [];\n  }\n\n  UnboundedArrayAccessor.prototype.getItem = function getItem(index) {\n    if (this._items[index] == null) {\n      var pos = this.stream.pos;\n      this.stream.pos = this.base + this.type.size(null, this.parent) * index;\n      this._items[index] = this.type.decode(this.stream, this.parent);\n      this.stream.pos = pos;\n    }\n\n    return this._items[index];\n  };\n\n  UnboundedArrayAccessor.prototype.inspect = function inspect() {\n    return '[UnboundedArray ' + this.type.constructor.name + ']';\n  };\n\n  return UnboundedArrayAccessor;\n}();\n\nvar UnboundedArray = function (_r$Array) {\n  _inherits(UnboundedArray, _r$Array);\n\n  function UnboundedArray(type) {\n    _classCallCheck(this, UnboundedArray);\n\n    return _possibleConstructorReturn(this, _r$Array.call(this, type, 0));\n  }\n\n  UnboundedArray.prototype.decode = function decode(stream, parent) {\n    return new UnboundedArrayAccessor(this.type, stream, parent);\n  };\n\n  return UnboundedArray;\n}(r.Array);\n\nvar LookupTable = function LookupTable() {\n  var ValueType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : r.uint16;\n\n  // Helper class that makes internal structures invisible to pointers\n  var Shadow = function () {\n    function Shadow(type) {\n      _classCallCheck(this, Shadow);\n\n      this.type = type;\n    }\n\n    Shadow.prototype.decode = function decode(stream, ctx) {\n      ctx = ctx.parent.parent;\n      return this.type.decode(stream, ctx);\n    };\n\n    Shadow.prototype.size = function size(val, ctx) {\n      ctx = ctx.parent.parent;\n      return this.type.size(val, ctx);\n    };\n\n    Shadow.prototype.encode = function encode(stream, val, ctx) {\n      ctx = ctx.parent.parent;\n      return this.type.encode(stream, val, ctx);\n    };\n\n    return Shadow;\n  }();\n\n  ValueType = new Shadow(ValueType);\n\n  var BinarySearchHeader = new r.Struct({\n    unitSize: r.uint16,\n    nUnits: r.uint16,\n    searchRange: r.uint16,\n    entrySelector: r.uint16,\n    rangeShift: r.uint16\n  });\n\n  var LookupSegmentSingle = new r.Struct({\n    lastGlyph: r.uint16,\n    firstGlyph: r.uint16,\n    value: ValueType\n  });\n\n  var LookupSegmentArray = new r.Struct({\n    lastGlyph: r.uint16,\n    firstGlyph: r.uint16,\n    values: new r.Pointer(r.uint16, new r.Array(ValueType, function (t) {\n      return t.lastGlyph - t.firstGlyph + 1;\n    }), { type: 'parent' })\n  });\n\n  var LookupSingle = new r.Struct({\n    glyph: r.uint16,\n    value: ValueType\n  });\n\n  return new r.VersionedStruct(r.uint16, {\n    0: {\n      values: new UnboundedArray(ValueType) // length == number of glyphs maybe?\n    },\n    2: {\n      binarySearchHeader: BinarySearchHeader,\n      segments: new r.Array(LookupSegmentSingle, function (t) {\n        return t.binarySearchHeader.nUnits;\n      })\n    },\n    4: {\n      binarySearchHeader: BinarySearchHeader,\n      segments: new r.Array(LookupSegmentArray, function (t) {\n        return t.binarySearchHeader.nUnits;\n      })\n    },\n    6: {\n      binarySearchHeader: BinarySearchHeader,\n      segments: new r.Array(LookupSingle, function (t) {\n        return t.binarySearchHeader.nUnits;\n      })\n    },\n    8: {\n      firstGlyph: r.uint16,\n      count: r.uint16,\n      values: new r.Array(ValueType, 'count')\n    }\n  });\n};\n\nfunction StateTable() {\n  var entryData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n  var lookupType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : r.uint16;\n\n  var entry = _Object$assign({\n    newState: r.uint16,\n    flags: r.uint16\n  }, entryData);\n\n  var Entry = new r.Struct(entry);\n  var StateArray = new UnboundedArray(new r.Array(r.uint16, function (t) {\n    return t.nClasses;\n  }));\n\n  var StateHeader = new r.Struct({\n    nClasses: r.uint32,\n    classTable: new r.Pointer(r.uint32, new LookupTable(lookupType)),\n    stateArray: new r.Pointer(r.uint32, StateArray),\n    entryTable: new r.Pointer(r.uint32, new UnboundedArray(Entry))\n  });\n\n  return StateHeader;\n}\n\n// This is the old version of the StateTable structure\nfunction StateTable1() {\n  var entryData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n  var lookupType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : r.uint16;\n\n  var ClassLookupTable = new r.Struct({\n    version: function version() {\n      return 8;\n    },\n    // simulate LookupTable\n    firstGlyph: r.uint16,\n    values: new r.Array(r.uint8, r.uint16)\n  });\n\n  var entry = _Object$assign({\n    newStateOffset: r.uint16,\n    // convert offset to stateArray index\n    newState: function newState(t) {\n      return (t.newStateOffset - (t.parent.stateArray.base - t.parent._startOffset)) / t.parent.nClasses;\n    },\n    flags: r.uint16\n  }, entryData);\n\n  var Entry = new r.Struct(entry);\n  var StateArray = new UnboundedArray(new r.Array(r.uint8, function (t) {\n    return t.nClasses;\n  }));\n\n  var StateHeader1 = new r.Struct({\n    nClasses: r.uint16,\n    classTable: new r.Pointer(r.uint16, ClassLookupTable),\n    stateArray: new r.Pointer(r.uint16, StateArray),\n    entryTable: new r.Pointer(r.uint16, new UnboundedArray(Entry))\n  });\n\n  return StateHeader1;\n}\n\nvar BslnSubtable = new r.VersionedStruct('format', {\n  0: { // Distance-based, no mapping\n    deltas: new r.Array(r.int16, 32)\n  },\n\n  1: { // Distance-based, with mapping\n    deltas: new r.Array(r.int16, 32),\n    mappingData: new LookupTable(r.uint16)\n  },\n\n  2: { // Control point-based, no mapping\n    standardGlyph: r.uint16,\n    controlPoints: new r.Array(r.uint16, 32)\n  },\n\n  3: { // Control point-based, with mapping\n    standardGlyph: r.uint16,\n    controlPoints: new r.Array(r.uint16, 32),\n    mappingData: new LookupTable(r.uint16)\n  }\n});\n\nvar bsln = new r.Struct({\n  version: r.fixed32,\n  format: r.uint16,\n  defaultBaseline: r.uint16,\n  subtable: BslnSubtable\n});\n\nvar Setting = new r.Struct({\n  setting: r.uint16,\n  nameIndex: r.int16,\n  name: function name(t) {\n    return t.parent.parent.parent.name.records.fontFeatures[t.nameIndex];\n  }\n});\n\nvar FeatureName = new r.Struct({\n  feature: r.uint16,\n  nSettings: r.uint16,\n  settingTable: new r.Pointer(r.uint32, new r.Array(Setting, 'nSettings'), { type: 'parent' }),\n  featureFlags: new r.Bitfield(r.uint8, [null, null, null, null, null, null, 'hasDefault', 'exclusive']),\n  defaultSetting: r.uint8,\n  nameIndex: r.int16,\n  name: function name(t) {\n    return t.parent.parent.name.records.fontFeatures[t.nameIndex];\n  }\n});\n\nvar feat = new r.Struct({\n  version: r.fixed32,\n  featureNameCount: r.uint16,\n  reserved1: new r.Reserved(r.uint16),\n  reserved2: new r.Reserved(r.uint32),\n  featureNames: new r.Array(FeatureName, 'featureNameCount')\n});\n\nvar Axis$1 = new r.Struct({\n  axisTag: new r.String(4),\n  minValue: r.fixed32,\n  defaultValue: r.fixed32,\n  maxValue: r.fixed32,\n  flags: r.uint16,\n  nameID: r.uint16,\n  name: function name(t) {\n    return t.parent.parent.name.records.fontFeatures[t.nameID];\n  }\n});\n\nvar Instance = new r.Struct({\n  nameID: r.uint16,\n  name: function name(t) {\n    return t.parent.parent.name.records.fontFeatures[t.nameID];\n  },\n  flags: r.uint16,\n  coord: new r.Array(r.fixed32, function (t) {\n    return t.parent.axisCount;\n  }),\n  postscriptNameID: new r.Optional(r.uint16, function (t) {\n    return t.parent.instanceSize - t._currentOffset > 0;\n  })\n});\n\nvar fvar = new r.Struct({\n  version: r.fixed32,\n  offsetToData: r.uint16,\n  countSizePairs: r.uint16,\n  axisCount: r.uint16,\n  axisSize: r.uint16,\n  instanceCount: r.uint16,\n  instanceSize: r.uint16,\n  axis: new r.Array(Axis$1, 'axisCount'),\n  instance: new r.Array(Instance, 'instanceCount')\n});\n\nvar shortFrac$1 = new r.Fixed(16, 'BE', 14);\n\nvar Offset = function () {\n  function Offset() {\n    _classCallCheck(this, Offset);\n  }\n\n  Offset.decode = function decode(stream, parent) {\n    // In short format, offsets are multiplied by 2.\n    // This doesn't seem to be documented by Apple, but it\n    // is implemented this way in Freetype.\n    return parent.flags ? stream.readUInt32BE() : stream.readUInt16BE() * 2;\n  };\n\n  return Offset;\n}();\n\nvar gvar = new r.Struct({\n  version: r.uint16,\n  reserved: new r.Reserved(r.uint16),\n  axisCount: r.uint16,\n  globalCoordCount: r.uint16,\n  globalCoords: new r.Pointer(r.uint32, new r.Array(new r.Array(shortFrac$1, 'axisCount'), 'globalCoordCount')),\n  glyphCount: r.uint16,\n  flags: r.uint16,\n  offsetToData: r.uint32,\n  offsets: new r.Array(new r.Pointer(Offset, 'void', { relativeTo: 'offsetToData', allowNull: false }), function (t) {\n    return t.glyphCount + 1;\n  })\n});\n\nvar ClassTable$1 = new r.Struct({\n  length: r.uint16,\n  coverage: r.uint16,\n  subFeatureFlags: r.uint32,\n  stateTable: new StateTable1()\n});\n\nvar WidthDeltaRecord = new r.Struct({\n  justClass: r.uint32,\n  beforeGrowLimit: r.fixed32,\n  beforeShrinkLimit: r.fixed32,\n  afterGrowLimit: r.fixed32,\n  afterShrinkLimit: r.fixed32,\n  growFlags: r.uint16,\n  shrinkFlags: r.uint16\n});\n\nvar WidthDeltaCluster = new r.Array(WidthDeltaRecord, r.uint32);\n\nvar ActionData = new r.VersionedStruct('actionType', {\n  0: { // Decomposition action\n    lowerLimit: r.fixed32,\n    upperLimit: r.fixed32,\n    order: r.uint16,\n    glyphs: new r.Array(r.uint16, r.uint16)\n  },\n\n  1: { // Unconditional add glyph action\n    addGlyph: r.uint16\n  },\n\n  2: { // Conditional add glyph action\n    substThreshold: r.fixed32,\n    addGlyph: r.uint16,\n    substGlyph: r.uint16\n  },\n\n  3: {}, // Stretch glyph action (no data, not supported by CoreText)\n\n  4: { // Ductile glyph action (not supported by CoreText)\n    variationAxis: r.uint32,\n    minimumLimit: r.fixed32,\n    noStretchValue: r.fixed32,\n    maximumLimit: r.fixed32\n  },\n\n  5: { // Repeated add glyph action\n    flags: r.uint16,\n    glyph: r.uint16\n  }\n});\n\nvar Action = new r.Struct({\n  actionClass: r.uint16,\n  actionType: r.uint16,\n  actionLength: r.uint32,\n  actionData: ActionData,\n  padding: new r.Reserved(r.uint8, function (t) {\n    return t.actionLength - t._currentOffset;\n  })\n});\n\nvar PostcompensationAction = new r.Array(Action, r.uint32);\nvar PostCompensationTable = new r.Struct({\n  lookupTable: new LookupTable(new r.Pointer(r.uint16, PostcompensationAction))\n});\n\nvar JustificationTable = new r.Struct({\n  classTable: new r.Pointer(r.uint16, ClassTable$1, { type: 'parent' }),\n  wdcOffset: r.uint16,\n  postCompensationTable: new r.Pointer(r.uint16, PostCompensationTable, { type: 'parent' }),\n  widthDeltaClusters: new LookupTable(new r.Pointer(r.uint16, WidthDeltaCluster, { type: 'parent', relativeTo: 'wdcOffset' }))\n});\n\nvar just = new r.Struct({\n  version: r.uint32,\n  format: r.uint16,\n  horizontal: new r.Pointer(r.uint16, JustificationTable),\n  vertical: new r.Pointer(r.uint16, JustificationTable)\n});\n\nvar LigatureData = {\n  action: r.uint16\n};\n\nvar ContextualData = {\n  markIndex: r.uint16,\n  currentIndex: r.uint16\n};\n\nvar InsertionData = {\n  currentInsertIndex: r.uint16,\n  markedInsertIndex: r.uint16\n};\n\nvar SubstitutionTable = new r.Struct({\n  items: new UnboundedArray(new r.Pointer(r.uint32, new LookupTable()))\n});\n\nvar SubtableData = new r.VersionedStruct('type', {\n  0: { // Indic Rearrangement Subtable\n    stateTable: new StateTable()\n  },\n\n  1: { // Contextual Glyph Substitution Subtable\n    stateTable: new StateTable(ContextualData),\n    substitutionTable: new r.Pointer(r.uint32, SubstitutionTable)\n  },\n\n  2: { // Ligature subtable\n    stateTable: new StateTable(LigatureData),\n    ligatureActions: new r.Pointer(r.uint32, new UnboundedArray(r.uint32)),\n    components: new r.Pointer(r.uint32, new UnboundedArray(r.uint16)),\n    ligatureList: new r.Pointer(r.uint32, new UnboundedArray(r.uint16))\n  },\n\n  4: { // Non-contextual Glyph Substitution Subtable\n    lookupTable: new LookupTable()\n  },\n\n  5: { // Glyph Insertion Subtable\n    stateTable: new StateTable(InsertionData),\n    insertionActions: new r.Pointer(r.uint32, new UnboundedArray(r.uint16))\n  }\n});\n\nvar Subtable = new r.Struct({\n  length: r.uint32,\n  coverage: r.uint24,\n  type: r.uint8,\n  subFeatureFlags: r.uint32,\n  table: SubtableData,\n  padding: new r.Reserved(r.uint8, function (t) {\n    return t.length - t._currentOffset;\n  })\n});\n\nvar FeatureEntry = new r.Struct({\n  featureType: r.uint16,\n  featureSetting: r.uint16,\n  enableFlags: r.uint32,\n  disableFlags: r.uint32\n});\n\nvar MorxChain = new r.Struct({\n  defaultFlags: r.uint32,\n  chainLength: r.uint32,\n  nFeatureEntries: r.uint32,\n  nSubtables: r.uint32,\n  features: new r.Array(FeatureEntry, 'nFeatureEntries'),\n  subtables: new r.Array(Subtable, 'nSubtables')\n});\n\nvar morx = new r.Struct({\n  version: r.uint16,\n  unused: new r.Reserved(r.uint16),\n  nChains: r.uint32,\n  chains: new r.Array(MorxChain, 'nChains')\n});\n\nvar OpticalBounds = new r.Struct({\n  left: r.int16,\n  top: r.int16,\n  right: r.int16,\n  bottom: r.int16\n});\n\nvar opbd = new r.Struct({\n  version: r.fixed32,\n  format: r.uint16,\n  lookupTable: new LookupTable(OpticalBounds)\n});\n\nvar tables = {};\n// Required Tables\ntables.cmap = cmap;\ntables.head = head;\ntables.hhea = hhea;\ntables.hmtx = hmtx;\ntables.maxp = maxp;\ntables.name = NameTable;\ntables['OS/2'] = OS2;\ntables.post = post;\n\n// TrueType Outlines\ntables.fpgm = fpgm;\ntables.loca = loca;\ntables.prep = prep;\ntables['cvt '] = cvt;\ntables.glyf = glyf;\n\n// PostScript Outlines\ntables['CFF '] = CFFFont;\ntables['CFF2'] = CFFFont;\ntables.VORG = VORG;\n\n// Bitmap Glyphs\ntables.EBLC = EBLC;\ntables.CBLC = tables.EBLC;\ntables.sbix = sbix;\ntables.COLR = COLR;\ntables.CPAL = CPAL;\n\n// Advanced OpenType Tables\ntables.BASE = BASE;\ntables.GDEF = GDEF;\ntables.GPOS = GPOS;\ntables.GSUB = GSUB;\ntables.JSTF = JSTF;\n\n// OpenType variations tables\ntables.HVAR = HVAR;\n\n// Other OpenType Tables\ntables.DSIG = DSIG;\ntables.gasp = gasp;\ntables.hdmx = hdmx;\ntables.kern = kern;\ntables.LTSH = LTSH;\ntables.PCLT = PCLT;\ntables.VDMX = VDMX;\ntables.vhea = vhea;\ntables.vmtx = vmtx;\n\n// Apple Advanced Typography Tables\ntables.avar = avar;\ntables.bsln = bsln;\ntables.feat = feat;\ntables.fvar = fvar;\ntables.gvar = gvar;\ntables.just = just;\ntables.morx = morx;\ntables.opbd = opbd;\n\nvar TableEntry = new r.Struct({\n  tag: new r.String(4),\n  checkSum: r.uint32,\n  offset: new r.Pointer(r.uint32, 'void', { type: 'global' }),\n  length: r.uint32\n});\n\nvar Directory = new r.Struct({\n  tag: new r.String(4),\n  numTables: r.uint16,\n  searchRange: r.uint16,\n  entrySelector: r.uint16,\n  rangeShift: r.uint16,\n  tables: new r.Array(TableEntry, 'numTables')\n});\n\nDirectory.process = function () {\n  var tables = {};\n  for (var _iterator = this.tables, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n    var _ref;\n\n    if (_isArray) {\n      if (_i >= _iterator.length) break;\n      _ref = _iterator[_i++];\n    } else {\n      _i = _iterator.next();\n      if (_i.done) break;\n      _ref = _i.value;\n    }\n\n    var table = _ref;\n\n    tables[table.tag] = table;\n  }\n\n  this.tables = tables;\n};\n\nDirectory.preEncode = function (stream) {\n  var tables$$ = [];\n  for (var tag in this.tables) {\n    var table = this.tables[tag];\n    if (table) {\n      tables$$.push({\n        tag: tag,\n        checkSum: 0,\n        offset: new r.VoidPointer(tables[tag], table),\n        length: tables[tag].size(table)\n      });\n    }\n  }\n\n  this.tag = 'true';\n  this.numTables = tables$$.length;\n  this.tables = tables$$;\n\n  this.searchRange = Math.floor(Math.log(this.numTables) / Math.LN2) * 16;\n  this.entrySelector = Math.floor(this.searchRange / Math.LN2);\n  this.rangeShift = this.numTables * 16 - this.searchRange;\n};\n\nfunction binarySearch(arr, cmp) {\n  var min = 0;\n  var max = arr.length - 1;\n  while (min <= max) {\n    var mid = min + max >> 1;\n    var res = cmp(arr[mid]);\n\n    if (res < 0) {\n      max = mid - 1;\n    } else if (res > 0) {\n      min = mid + 1;\n    } else {\n      return mid;\n    }\n  }\n\n  return -1;\n}\n\nfunction range(index, end) {\n  var range = [];\n  while (index < end) {\n    range.push(index++);\n  }\n  return range;\n}\n\nvar _class$1;\nfunction _applyDecoratedDescriptor$1(target, property, decorators, descriptor, context) {\n  var desc = {};\n  Object['ke' + 'ys'](descriptor).forEach(function (key) {\n    desc[key] = descriptor[key];\n  });\n  desc.enumerable = !!desc.enumerable;\n  desc.configurable = !!desc.configurable;\n\n  if ('value' in desc || desc.initializer) {\n    desc.writable = true;\n  }\n\n  desc = decorators.slice().reverse().reduce(function (desc, decorator) {\n    return decorator(target, property, desc) || desc;\n  }, desc);\n\n  if (context && desc.initializer !== void 0) {\n    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;\n    desc.initializer = undefined;\n  }\n\n  if (desc.initializer === void 0) {\n    Object['define' + 'Property'](target, property, desc);\n    desc = null;\n  }\n\n  return desc;\n}\n\n// iconv-lite is an optional dependency.\ntry {\n  var iconv = __webpack_require__(52);\n} catch (err) {}\n\nvar CmapProcessor = (_class$1 = function () {\n  function CmapProcessor(cmapTable) {\n    _classCallCheck(this, CmapProcessor);\n\n    // Attempt to find a Unicode cmap first\n    this.encoding = null;\n    this.cmap = this.findSubtable(cmapTable, [\n    // 32-bit subtables\n    [3, 10], [0, 6], [0, 4],\n\n    // 16-bit subtables\n    [3, 1], [0, 3], [0, 2], [0, 1], [0, 0]]);\n\n    // If not unicode cmap was found, and iconv-lite is installed,\n    // take the first table with a supported encoding.\n    if (!this.cmap && iconv) {\n      for (var _iterator = cmapTable.tables, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n        var _ref;\n\n        if (_isArray) {\n          if (_i >= _iterator.length) break;\n          _ref = _iterator[_i++];\n        } else {\n          _i = _iterator.next();\n          if (_i.done) break;\n          _ref = _i.value;\n        }\n\n        var cmap = _ref;\n\n        var encoding = getEncoding(cmap.platformID, cmap.encodingID, cmap.table.language - 1);\n        if (iconv.encodingExists(encoding)) {\n          this.cmap = cmap.table;\n          this.encoding = encoding;\n        }\n      }\n    }\n\n    if (!this.cmap) {\n      throw new Error(\"Could not find a supported cmap table\");\n    }\n\n    this.uvs = this.findSubtable(cmapTable, [[0, 5]]);\n    if (this.uvs && this.uvs.version !== 14) {\n      this.uvs = null;\n    }\n  }\n\n  CmapProcessor.prototype.findSubtable = function findSubtable(cmapTable, pairs) {\n    for (var _iterator2 = pairs, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n      var _ref2;\n\n      if (_isArray2) {\n        if (_i2 >= _iterator2.length) break;\n        _ref2 = _iterator2[_i2++];\n      } else {\n        _i2 = _iterator2.next();\n        if (_i2.done) break;\n        _ref2 = _i2.value;\n      }\n\n      var _ref3 = _ref2,\n          platformID = _ref3[0],\n          encodingID = _ref3[1];\n\n      for (var _iterator3 = cmapTable.tables, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n        var _ref4;\n\n        if (_isArray3) {\n          if (_i3 >= _iterator3.length) break;\n          _ref4 = _iterator3[_i3++];\n        } else {\n          _i3 = _iterator3.next();\n          if (_i3.done) break;\n          _ref4 = _i3.value;\n        }\n\n        var cmap = _ref4;\n\n        if (cmap.platformID === platformID && cmap.encodingID === encodingID) {\n          return cmap.table;\n        }\n      }\n    }\n\n    return null;\n  };\n\n  CmapProcessor.prototype.lookup = function lookup(codepoint, variationSelector) {\n    // If there is no Unicode cmap in this font, we need to re-encode\n    // the codepoint in the encoding that the cmap supports.\n    if (this.encoding) {\n      var buf = iconv.encode(_String$fromCodePoint(codepoint), this.encoding);\n      codepoint = 0;\n      for (var i = 0; i < buf.length; i++) {\n        codepoint = codepoint << 8 | buf[i];\n      }\n\n      // Otherwise, try to get a Unicode variation selector for this codepoint if one is provided.\n    } else if (variationSelector) {\n      var gid = this.getVariationSelector(codepoint, variationSelector);\n      if (gid) {\n        return gid;\n      }\n    }\n\n    var cmap = this.cmap;\n    switch (cmap.version) {\n      case 0:\n        return cmap.codeMap.get(codepoint) || 0;\n\n      case 4:\n        {\n          var min = 0;\n          var max = cmap.segCount - 1;\n          while (min <= max) {\n            var mid = min + max >> 1;\n\n            if (codepoint < cmap.startCode.get(mid)) {\n              max = mid - 1;\n            } else if (codepoint > cmap.endCode.get(mid)) {\n              min = mid + 1;\n            } else {\n              var rangeOffset = cmap.idRangeOffset.get(mid);\n              var _gid = void 0;\n\n              if (rangeOffset === 0) {\n                _gid = codepoint + cmap.idDelta.get(mid);\n              } else {\n                var index = rangeOffset / 2 + (codepoint - cmap.startCode.get(mid)) - (cmap.segCount - mid);\n                _gid = cmap.glyphIndexArray.get(index) || 0;\n                if (_gid !== 0) {\n                  _gid += cmap.idDelta.get(mid);\n                }\n              }\n\n              return _gid & 0xffff;\n            }\n          }\n\n          return 0;\n        }\n\n      case 8:\n        throw new Error('TODO: cmap format 8');\n\n      case 6:\n      case 10:\n        return cmap.glyphIndices.get(codepoint - cmap.firstCode) || 0;\n\n      case 12:\n      case 13:\n        {\n          var _min = 0;\n          var _max = cmap.nGroups - 1;\n          while (_min <= _max) {\n            var _mid = _min + _max >> 1;\n            var group = cmap.groups.get(_mid);\n\n            if (codepoint < group.startCharCode) {\n              _max = _mid - 1;\n            } else if (codepoint > group.endCharCode) {\n              _min = _mid + 1;\n            } else {\n              if (cmap.version === 12) {\n                return group.glyphID + (codepoint - group.startCharCode);\n              } else {\n                return group.glyphID;\n              }\n            }\n          }\n\n          return 0;\n        }\n\n      case 14:\n        throw new Error('TODO: cmap format 14');\n\n      default:\n        throw new Error('Unknown cmap format ' + cmap.version);\n    }\n  };\n\n  CmapProcessor.prototype.getVariationSelector = function getVariationSelector(codepoint, variationSelector) {\n    if (!this.uvs) {\n      return 0;\n    }\n\n    var selectors = this.uvs.varSelectors.toArray();\n    var i = binarySearch(selectors, function (x) {\n      return variationSelector - x.varSelector;\n    });\n    var sel = selectors[i];\n\n    if (i !== -1 && sel.defaultUVS) {\n      i = binarySearch(sel.defaultUVS, function (x) {\n        return codepoint < x.startUnicodeValue ? -1 : codepoint > x.startUnicodeValue + x.additionalCount ? +1 : 0;\n      });\n    }\n\n    if (i !== -1 && sel.nonDefaultUVS) {\n      i = binarySearch(sel.nonDefaultUVS, function (x) {\n        return codepoint - x.unicodeValue;\n      });\n      if (i !== -1) {\n        return sel.nonDefaultUVS[i].glyphID;\n      }\n    }\n\n    return 0;\n  };\n\n  CmapProcessor.prototype.getCharacterSet = function getCharacterSet() {\n    var cmap = this.cmap;\n    switch (cmap.version) {\n      case 0:\n        return range(0, cmap.codeMap.length);\n\n      case 4:\n        {\n          var res = [];\n          var endCodes = cmap.endCode.toArray();\n          for (var i = 0; i < endCodes.length; i++) {\n            var tail = endCodes[i] + 1;\n            var start = cmap.startCode.get(i);\n            res.push.apply(res, range(start, tail));\n          }\n\n          return res;\n        }\n\n      case 8:\n        throw new Error('TODO: cmap format 8');\n\n      case 6:\n      case 10:\n        return range(cmap.firstCode, cmap.firstCode + cmap.glyphIndices.length);\n\n      case 12:\n      case 13:\n        {\n          var _res = [];\n          for (var _iterator4 = cmap.groups.toArray(), _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _getIterator(_iterator4);;) {\n            var _ref5;\n\n            if (_isArray4) {\n              if (_i4 >= _iterator4.length) break;\n              _ref5 = _iterator4[_i4++];\n            } else {\n              _i4 = _iterator4.next();\n              if (_i4.done) break;\n              _ref5 = _i4.value;\n            }\n\n            var group = _ref5;\n\n            _res.push.apply(_res, range(group.startCharCode, group.endCharCode + 1));\n          }\n\n          return _res;\n        }\n\n      case 14:\n        throw new Error('TODO: cmap format 14');\n\n      default:\n        throw new Error('Unknown cmap format ' + cmap.version);\n    }\n  };\n\n  CmapProcessor.prototype.codePointsForGlyph = function codePointsForGlyph(gid) {\n    var cmap = this.cmap;\n    switch (cmap.version) {\n      case 0:\n        {\n          var res = [];\n          for (var i = 0; i < 256; i++) {\n            if (cmap.codeMap.get(i) === gid) {\n              res.push(i);\n            }\n          }\n\n          return res;\n        }\n\n      case 4:\n        {\n          var _res2 = [];\n          for (var _i5 = 0; _i5 < cmap.segCount; _i5++) {\n            var end = cmap.endCode.get(_i5);\n            var start = cmap.startCode.get(_i5);\n            var rangeOffset = cmap.idRangeOffset.get(_i5);\n            var delta = cmap.idDelta.get(_i5);\n\n            for (var c = start; c <= end; c++) {\n              var g = 0;\n              if (rangeOffset === 0) {\n                g = c + delta;\n              } else {\n                var index = rangeOffset / 2 + (c - start) - (cmap.segCount - _i5);\n                g = cmap.glyphIndexArray.get(index) || 0;\n                if (g !== 0) {\n                  g += delta;\n                }\n              }\n\n              if (g === gid) {\n                _res2.push(c);\n              }\n            }\n          }\n\n          return _res2;\n        }\n\n      case 12:\n        {\n          var _res3 = [];\n          for (var _iterator5 = cmap.groups.toArray(), _isArray5 = Array.isArray(_iterator5), _i6 = 0, _iterator5 = _isArray5 ? _iterator5 : _getIterator(_iterator5);;) {\n            var _ref6;\n\n            if (_isArray5) {\n              if (_i6 >= _iterator5.length) break;\n              _ref6 = _iterator5[_i6++];\n            } else {\n              _i6 = _iterator5.next();\n              if (_i6.done) break;\n              _ref6 = _i6.value;\n            }\n\n            var group = _ref6;\n\n            if (gid >= group.glyphID && gid <= group.glyphID + (group.endCharCode - group.startCharCode)) {\n              _res3.push(group.startCharCode + (gid - group.glyphID));\n            }\n          }\n\n          return _res3;\n        }\n\n      case 13:\n        {\n          var _res4 = [];\n          for (var _iterator6 = cmap.groups.toArray(), _isArray6 = Array.isArray(_iterator6), _i7 = 0, _iterator6 = _isArray6 ? _iterator6 : _getIterator(_iterator6);;) {\n            var _ref7;\n\n            if (_isArray6) {\n              if (_i7 >= _iterator6.length) break;\n              _ref7 = _iterator6[_i7++];\n            } else {\n              _i7 = _iterator6.next();\n              if (_i7.done) break;\n              _ref7 = _i7.value;\n            }\n\n            var _group = _ref7;\n\n            if (gid === _group.glyphID) {\n              _res4.push.apply(_res4, range(_group.startCharCode, _group.endCharCode + 1));\n            }\n          }\n\n          return _res4;\n        }\n\n      default:\n        throw new Error('Unknown cmap format ' + cmap.version);\n    }\n  };\n\n  return CmapProcessor;\n}(), (_applyDecoratedDescriptor$1(_class$1.prototype, 'getCharacterSet', [cache], _Object$getOwnPropertyDescriptor(_class$1.prototype, 'getCharacterSet'), _class$1.prototype), _applyDecoratedDescriptor$1(_class$1.prototype, 'codePointsForGlyph', [cache], _Object$getOwnPropertyDescriptor(_class$1.prototype, 'codePointsForGlyph'), _class$1.prototype)), _class$1);\n\nvar KernProcessor = function () {\n  function KernProcessor(font) {\n    _classCallCheck(this, KernProcessor);\n\n    this.kern = font.kern;\n  }\n\n  KernProcessor.prototype.process = function process(glyphs, positions) {\n    for (var glyphIndex = 0; glyphIndex < glyphs.length - 1; glyphIndex++) {\n      var left = glyphs[glyphIndex].id;\n      var right = glyphs[glyphIndex + 1].id;\n      positions[glyphIndex].xAdvance += this.getKerning(left, right);\n    }\n  };\n\n  KernProcessor.prototype.getKerning = function getKerning(left, right) {\n    var res = 0;\n\n    for (var _iterator = this.kern.tables, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var table = _ref;\n\n      if (table.coverage.crossStream) {\n        continue;\n      }\n\n      switch (table.version) {\n        case 0:\n          if (!table.coverage.horizontal) {\n            continue;\n          }\n\n          break;\n        case 1:\n          if (table.coverage.vertical || table.coverage.variation) {\n            continue;\n          }\n\n          break;\n        default:\n          throw new Error('Unsupported kerning table version ' + table.version);\n      }\n\n      var val = 0;\n      var s = table.subtable;\n      switch (table.format) {\n        case 0:\n          var pairIdx = binarySearch(s.pairs, function (pair) {\n            return left - pair.left || right - pair.right;\n          });\n\n          if (pairIdx >= 0) {\n            val = s.pairs[pairIdx].value;\n          }\n\n          break;\n\n        case 2:\n          var leftOffset = 0,\n              rightOffset = 0;\n          if (left >= s.leftTable.firstGlyph && left < s.leftTable.firstGlyph + s.leftTable.nGlyphs) {\n            leftOffset = s.leftTable.offsets[left - s.leftTable.firstGlyph];\n          } else {\n            leftOffset = s.array.off;\n          }\n\n          if (right >= s.rightTable.firstGlyph && right < s.rightTable.firstGlyph + s.rightTable.nGlyphs) {\n            rightOffset = s.rightTable.offsets[right - s.rightTable.firstGlyph];\n          }\n\n          var index = (leftOffset + rightOffset - s.array.off) / 2;\n          val = s.array.values.get(index);\n          break;\n\n        case 3:\n          if (left >= s.glyphCount || right >= s.glyphCount) {\n            return 0;\n          }\n\n          val = s.kernValue[s.kernIndex[s.leftClass[left] * s.rightClassCount + s.rightClass[right]]];\n          break;\n\n        default:\n          throw new Error('Unsupported kerning sub-table format ' + table.format);\n      }\n\n      // Microsoft supports the override flag, which resets the result\n      // Otherwise, the sum of the results from all subtables is returned\n      if (table.coverage.override) {\n        res = val;\n      } else {\n        res += val;\n      }\n    }\n\n    return res;\n  };\n\n  return KernProcessor;\n}();\n\n/**\n * This class is used when GPOS does not define 'mark' or 'mkmk' features\n * for positioning marks relative to base glyphs. It uses the unicode\n * combining class property to position marks.\n *\n * Based on code from Harfbuzz, thanks!\n * https://github.com/behdad/harfbuzz/blob/master/src/hb-ot-shape-fallback.cc\n */\n\nvar UnicodeLayoutEngine = function () {\n  function UnicodeLayoutEngine(font) {\n    _classCallCheck(this, UnicodeLayoutEngine);\n\n    this.font = font;\n  }\n\n  UnicodeLayoutEngine.prototype.positionGlyphs = function positionGlyphs(glyphs, positions) {\n    // find each base + mark cluster, and position the marks relative to the base\n    var clusterStart = 0;\n    var clusterEnd = 0;\n    for (var index = 0; index < glyphs.length; index++) {\n      var glyph = glyphs[index];\n      if (glyph.isMark) {\n        // TODO: handle ligatures\n        clusterEnd = index;\n      } else {\n        if (clusterStart !== clusterEnd) {\n          this.positionCluster(glyphs, positions, clusterStart, clusterEnd);\n        }\n\n        clusterStart = clusterEnd = index;\n      }\n    }\n\n    if (clusterStart !== clusterEnd) {\n      this.positionCluster(glyphs, positions, clusterStart, clusterEnd);\n    }\n\n    return positions;\n  };\n\n  UnicodeLayoutEngine.prototype.positionCluster = function positionCluster(glyphs, positions, clusterStart, clusterEnd) {\n    var base = glyphs[clusterStart];\n    var baseBox = base.cbox.copy();\n\n    // adjust bounding box for ligature glyphs\n    if (base.codePoints.length > 1) {\n      // LTR. TODO: RTL support.\n      baseBox.minX += (base.codePoints.length - 1) * baseBox.width / base.codePoints.length;\n    }\n\n    var xOffset = -positions[clusterStart].xAdvance;\n    var yOffset = 0;\n    var yGap = this.font.unitsPerEm / 16;\n\n    // position each of the mark glyphs relative to the base glyph\n    for (var index = clusterStart + 1; index <= clusterEnd; index++) {\n      var mark = glyphs[index];\n      var markBox = mark.cbox;\n      var position = positions[index];\n\n      var combiningClass = this.getCombiningClass(mark.codePoints[0]);\n\n      if (combiningClass !== 'Not_Reordered') {\n        position.xOffset = position.yOffset = 0;\n\n        // x positioning\n        switch (combiningClass) {\n          case 'Double_Above':\n          case 'Double_Below':\n            // LTR. TODO: RTL support.\n            position.xOffset += baseBox.minX - markBox.width / 2 - markBox.minX;\n            break;\n\n          case 'Attached_Below_Left':\n          case 'Below_Left':\n          case 'Above_Left':\n            // left align\n            position.xOffset += baseBox.minX - markBox.minX;\n            break;\n\n          case 'Attached_Above_Right':\n          case 'Below_Right':\n          case 'Above_Right':\n            // right align\n            position.xOffset += baseBox.maxX - markBox.width - markBox.minX;\n            break;\n\n          default:\n            // Attached_Below, Attached_Above, Below, Above, other\n            // center align\n            position.xOffset += baseBox.minX + (baseBox.width - markBox.width) / 2 - markBox.minX;\n        }\n\n        // y positioning\n        switch (combiningClass) {\n          case 'Double_Below':\n          case 'Below_Left':\n          case 'Below':\n          case 'Below_Right':\n          case 'Attached_Below_Left':\n          case 'Attached_Below':\n            // add a small gap between the glyphs if they are not attached\n            if (combiningClass === 'Attached_Below_Left' || combiningClass === 'Attached_Below') {\n              baseBox.minY += yGap;\n            }\n\n            position.yOffset = -baseBox.minY - markBox.maxY;\n            baseBox.minY += markBox.height;\n            break;\n\n          case 'Double_Above':\n          case 'Above_Left':\n          case 'Above':\n          case 'Above_Right':\n          case 'Attached_Above':\n          case 'Attached_Above_Right':\n            // add a small gap between the glyphs if they are not attached\n            if (combiningClass === 'Attached_Above' || combiningClass === 'Attached_Above_Right') {\n              baseBox.maxY += yGap;\n            }\n\n            position.yOffset = baseBox.maxY - markBox.minY;\n            baseBox.maxY += markBox.height;\n            break;\n        }\n\n        position.xAdvance = position.yAdvance = 0;\n        position.xOffset += xOffset;\n        position.yOffset += yOffset;\n      } else {\n        xOffset -= position.xAdvance;\n        yOffset -= position.yAdvance;\n      }\n    }\n\n    return;\n  };\n\n  UnicodeLayoutEngine.prototype.getCombiningClass = function getCombiningClass(codePoint) {\n    var combiningClass = unicode.getCombiningClass(codePoint);\n\n    // Thai / Lao need some per-character work\n    if ((codePoint & ~0xff) === 0x0e00) {\n      if (combiningClass === 'Not_Reordered') {\n        switch (codePoint) {\n          case 0x0e31:\n          case 0x0e34:\n          case 0x0e35:\n          case 0x0e36:\n          case 0x0e37:\n          case 0x0e47:\n          case 0x0e4c:\n          case 0x0e3d:\n          case 0x0e4e:\n            return 'Above_Right';\n\n          case 0x0eb1:\n          case 0x0eb4:\n          case 0x0eb5:\n          case 0x0eb6:\n          case 0x0eb7:\n          case 0x0ebb:\n          case 0x0ecc:\n          case 0x0ecd:\n            return 'Above';\n\n          case 0x0ebc:\n            return 'Below';\n        }\n      } else if (codePoint === 0x0e3a) {\n        // virama\n        return 'Below_Right';\n      }\n    }\n\n    switch (combiningClass) {\n      // Hebrew\n\n      case 'CCC10': // sheva\n      case 'CCC11': // hataf segol\n      case 'CCC12': // hataf patah\n      case 'CCC13': // hataf qamats\n      case 'CCC14': // hiriq\n      case 'CCC15': // tsere\n      case 'CCC16': // segol\n      case 'CCC17': // patah\n      case 'CCC18': // qamats\n      case 'CCC20': // qubuts\n      case 'CCC22':\n        // meteg\n        return 'Below';\n\n      case 'CCC23':\n        // rafe\n        return 'Attached_Above';\n\n      case 'CCC24':\n        // shin dot\n        return 'Above_Right';\n\n      case 'CCC25': // sin dot\n      case 'CCC19':\n        // holam\n        return 'Above_Left';\n\n      case 'CCC26':\n        // point varika\n        return 'Above';\n\n      case 'CCC21':\n        // dagesh\n        break;\n\n      // Arabic and Syriac\n\n      case 'CCC27': // fathatan\n      case 'CCC28': // dammatan\n      case 'CCC30': // fatha\n      case 'CCC31': // damma\n      case 'CCC33': // shadda\n      case 'CCC34': // sukun\n      case 'CCC35': // superscript alef\n      case 'CCC36':\n        // superscript alaph\n        return 'Above';\n\n      case 'CCC29': // kasratan\n      case 'CCC32':\n        // kasra\n        return 'Below';\n\n      // Thai\n\n      case 'CCC103':\n        // sara u / sara uu\n        return 'Below_Right';\n\n      case 'CCC107':\n        // mai\n        return 'Above_Right';\n\n      // Lao\n\n      case 'CCC118':\n        // sign u / sign uu\n        return 'Below';\n\n      case 'CCC122':\n        // mai\n        return 'Above';\n\n      // Tibetan\n\n      case 'CCC129': // sign aa\n      case 'CCC132':\n        // sign u\n        return 'Below';\n\n      case 'CCC130':\n        // sign i\n        return 'Above';\n    }\n\n    return combiningClass;\n  };\n\n  return UnicodeLayoutEngine;\n}();\n\n/**\n * Represents a glyph bounding box\n */\nvar BBox = function () {\n  function BBox() {\n    var minX = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Infinity;\n    var minY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Infinity;\n    var maxX = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : -Infinity;\n    var maxY = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : -Infinity;\n\n    _classCallCheck(this, BBox);\n\n    /**\n     * The minimum X position in the bounding box\n     * @type {number}\n     */\n    this.minX = minX;\n\n    /**\n     * The minimum Y position in the bounding box\n     * @type {number}\n     */\n    this.minY = minY;\n\n    /**\n     * The maxmimum X position in the bounding box\n     * @type {number}\n     */\n    this.maxX = maxX;\n\n    /**\n     * The maxmimum Y position in the bounding box\n     * @type {number}\n     */\n    this.maxY = maxY;\n  }\n\n  /**\n   * The width of the bounding box\n   * @type {number}\n   */\n\n\n  BBox.prototype.addPoint = function addPoint(x, y) {\n    if (Math.abs(x) !== Infinity) {\n      if (x < this.minX) {\n        this.minX = x;\n      }\n\n      if (x > this.maxX) {\n        this.maxX = x;\n      }\n    }\n\n    if (Math.abs(y) !== Infinity) {\n      if (y < this.minY) {\n        this.minY = y;\n      }\n\n      if (y > this.maxY) {\n        this.maxY = y;\n      }\n    }\n  };\n\n  BBox.prototype.copy = function copy() {\n    return new BBox(this.minX, this.minY, this.maxX, this.maxY);\n  };\n\n  _createClass(BBox, [{\n    key: \"width\",\n    get: function get() {\n      return this.maxX - this.minX;\n    }\n\n    /**\n     * The height of the bounding box\n     * @type {number}\n     */\n\n  }, {\n    key: \"height\",\n    get: function get() {\n      return this.maxY - this.minY;\n    }\n  }]);\n\n  return BBox;\n}();\n\n// This maps the Unicode Script property to an OpenType script tag\n// Data from http://www.microsoft.com/typography/otspec/scripttags.htm\n// and http://www.unicode.org/Public/UNIDATA/PropertyValueAliases.txt.\nvar UNICODE_SCRIPTS = {\n  Caucasian_Albanian: 'aghb',\n  Arabic: 'arab',\n  Imperial_Aramaic: 'armi',\n  Armenian: 'armn',\n  Avestan: 'avst',\n  Balinese: 'bali',\n  Bamum: 'bamu',\n  Bassa_Vah: 'bass',\n  Batak: 'batk',\n  Bengali: ['bng2', 'beng'],\n  Bopomofo: 'bopo',\n  Brahmi: 'brah',\n  Braille: 'brai',\n  Buginese: 'bugi',\n  Buhid: 'buhd',\n  Chakma: 'cakm',\n  Canadian_Aboriginal: 'cans',\n  Carian: 'cari',\n  Cham: 'cham',\n  Cherokee: 'cher',\n  Coptic: 'copt',\n  Cypriot: 'cprt',\n  Cyrillic: 'cyrl',\n  Devanagari: ['dev2', 'deva'],\n  Deseret: 'dsrt',\n  Duployan: 'dupl',\n  Egyptian_Hieroglyphs: 'egyp',\n  Elbasan: 'elba',\n  Ethiopic: 'ethi',\n  Georgian: 'geor',\n  Glagolitic: 'glag',\n  Gothic: 'goth',\n  Grantha: 'gran',\n  Greek: 'grek',\n  Gujarati: ['gjr2', 'gujr'],\n  Gurmukhi: ['gur2', 'guru'],\n  Hangul: 'hang',\n  Han: 'hani',\n  Hanunoo: 'hano',\n  Hebrew: 'hebr',\n  Hiragana: 'hira',\n  Pahawh_Hmong: 'hmng',\n  Katakana_Or_Hiragana: 'hrkt',\n  Old_Italic: 'ital',\n  Javanese: 'java',\n  Kayah_Li: 'kali',\n  Katakana: 'kana',\n  Kharoshthi: 'khar',\n  Khmer: 'khmr',\n  Khojki: 'khoj',\n  Kannada: ['knd2', 'knda'],\n  Kaithi: 'kthi',\n  Tai_Tham: 'lana',\n  Lao: 'lao ',\n  Latin: 'latn',\n  Lepcha: 'lepc',\n  Limbu: 'limb',\n  Linear_A: 'lina',\n  Linear_B: 'linb',\n  Lisu: 'lisu',\n  Lycian: 'lyci',\n  Lydian: 'lydi',\n  Mahajani: 'mahj',\n  Mandaic: 'mand',\n  Manichaean: 'mani',\n  Mende_Kikakui: 'mend',\n  Meroitic_Cursive: 'merc',\n  Meroitic_Hieroglyphs: 'mero',\n  Malayalam: ['mlm2', 'mlym'],\n  Modi: 'modi',\n  Mongolian: 'mong',\n  Mro: 'mroo',\n  Meetei_Mayek: 'mtei',\n  Myanmar: ['mym2', 'mymr'],\n  Old_North_Arabian: 'narb',\n  Nabataean: 'nbat',\n  Nko: 'nko ',\n  Ogham: 'ogam',\n  Ol_Chiki: 'olck',\n  Old_Turkic: 'orkh',\n  Oriya: ['ory2', 'orya'],\n  Osmanya: 'osma',\n  Palmyrene: 'palm',\n  Pau_Cin_Hau: 'pauc',\n  Old_Permic: 'perm',\n  Phags_Pa: 'phag',\n  Inscriptional_Pahlavi: 'phli',\n  Psalter_Pahlavi: 'phlp',\n  Phoenician: 'phnx',\n  Miao: 'plrd',\n  Inscriptional_Parthian: 'prti',\n  Rejang: 'rjng',\n  Runic: 'runr',\n  Samaritan: 'samr',\n  Old_South_Arabian: 'sarb',\n  Saurashtra: 'saur',\n  Shavian: 'shaw',\n  Sharada: 'shrd',\n  Siddham: 'sidd',\n  Khudawadi: 'sind',\n  Sinhala: 'sinh',\n  Sora_Sompeng: 'sora',\n  Sundanese: 'sund',\n  Syloti_Nagri: 'sylo',\n  Syriac: 'syrc',\n  Tagbanwa: 'tagb',\n  Takri: 'takr',\n  Tai_Le: 'tale',\n  New_Tai_Lue: 'talu',\n  Tamil: ['tml2', 'taml'],\n  Tai_Viet: 'tavt',\n  Telugu: ['tel2', 'telu'],\n  Tifinagh: 'tfng',\n  Tagalog: 'tglg',\n  Thaana: 'thaa',\n  Thai: 'thai',\n  Tibetan: 'tibt',\n  Tirhuta: 'tirh',\n  Ugaritic: 'ugar',\n  Vai: 'vai ',\n  Warang_Citi: 'wara',\n  Old_Persian: 'xpeo',\n  Cuneiform: 'xsux',\n  Yi: 'yi  ',\n  Inherited: 'zinh',\n  Common: 'zyyy',\n  Unknown: 'zzzz'\n};\n\nvar OPENTYPE_SCRIPTS = {};\nfor (var script in UNICODE_SCRIPTS) {\n  var tag = UNICODE_SCRIPTS[script];\n  if (Array.isArray(tag)) {\n    for (var _iterator = tag, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var t = _ref;\n\n      OPENTYPE_SCRIPTS[t] = script;\n    }\n  } else {\n    OPENTYPE_SCRIPTS[tag] = script;\n  }\n}\n\nfunction fromOpenType(tag) {\n  return OPENTYPE_SCRIPTS[tag];\n}\n\nfunction forString(string) {\n  var len = string.length;\n  var idx = 0;\n  while (idx < len) {\n    var code = string.charCodeAt(idx++);\n\n    // Check if this is a high surrogate\n    if (0xd800 <= code && code <= 0xdbff && idx < len) {\n      var next = string.charCodeAt(idx);\n\n      // Check if this is a low surrogate\n      if (0xdc00 <= next && next <= 0xdfff) {\n        idx++;\n        code = ((code & 0x3FF) << 10) + (next & 0x3FF) + 0x10000;\n      }\n    }\n\n    var _script = unicode.getScript(code);\n    if (_script !== 'Common' && _script !== 'Inherited' && _script !== 'Unknown') {\n      return UNICODE_SCRIPTS[_script];\n    }\n  }\n\n  return UNICODE_SCRIPTS.Unknown;\n}\n\nfunction forCodePoints(codePoints) {\n  for (var i = 0; i < codePoints.length; i++) {\n    var codePoint = codePoints[i];\n    var _script2 = unicode.getScript(codePoint);\n    if (_script2 !== 'Common' && _script2 !== 'Inherited' && _script2 !== 'Unknown') {\n      return UNICODE_SCRIPTS[_script2];\n    }\n  }\n\n  return UNICODE_SCRIPTS.Unknown;\n}\n\n// The scripts in this map are written from right to left\nvar RTL = {\n  arab: true, // Arabic\n  hebr: true, // Hebrew\n  syrc: true, // Syriac\n  thaa: true, // Thaana\n  cprt: true, // Cypriot Syllabary\n  khar: true, // Kharosthi\n  phnx: true, // Phoenician\n  'nko ': true, // N'Ko\n  lydi: true, // Lydian\n  avst: true, // Avestan\n  armi: true, // Imperial Aramaic\n  phli: true, // Inscriptional Pahlavi\n  prti: true, // Inscriptional Parthian\n  sarb: true, // Old South Arabian\n  orkh: true, // Old Turkic, Orkhon Runic\n  samr: true, // Samaritan\n  mand: true, // Mandaic, Mandaean\n  merc: true, // Meroitic Cursive\n  mero: true, // Meroitic Hieroglyphs\n\n  // Unicode 7.0 (not listed on http://www.microsoft.com/typography/otspec/scripttags.htm)\n  mani: true, // Manichaean\n  mend: true, // Mende Kikakui\n  nbat: true, // Nabataean\n  narb: true, // Old North Arabian\n  palm: true, // Palmyrene\n  phlp: true // Psalter Pahlavi\n};\n\nfunction direction(script) {\n  if (RTL[script]) {\n    return 'rtl';\n  }\n\n  return 'ltr';\n}\n\n/**\n * Represents a run of Glyph and GlyphPosition objects.\n * Returned by the font layout method.\n */\n\nvar GlyphRun = function () {\n  function GlyphRun(glyphs, features, script, language, direction$$) {\n    _classCallCheck(this, GlyphRun);\n\n    /**\n     * An array of Glyph objects in the run\n     * @type {Glyph[]}\n     */\n    this.glyphs = glyphs;\n\n    /**\n     * An array of GlyphPosition objects for each glyph in the run\n     * @type {GlyphPosition[]}\n     */\n    this.positions = null;\n\n    /**\n     * The script that was requested for shaping. This was either passed in or detected automatically.\n     * @type {string}\n     */\n    this.script = script;\n\n    /**\n     * The language requested for shaping, as passed in. If `null`, the default language for the\n     * script was used.\n     * @type {string}\n     */\n    this.language = language || null;\n\n    /**\n     * The direction requested for shaping, as passed in (either ltr or rtl).\n     * If `null`, the default direction of the script is used.\n     * @type {string}\n     */\n    this.direction = direction$$ || direction(script);\n\n    /**\n     * The features requested during shaping. This is a combination of user\n     * specified features and features chosen by the shaper.\n     * @type {object}\n     */\n    this.features = {};\n\n    // Convert features to an object\n    if (Array.isArray(features)) {\n      for (var _iterator = features, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n        var _ref;\n\n        if (_isArray) {\n          if (_i >= _iterator.length) break;\n          _ref = _iterator[_i++];\n        } else {\n          _i = _iterator.next();\n          if (_i.done) break;\n          _ref = _i.value;\n        }\n\n        var tag = _ref;\n\n        this.features[tag] = true;\n      }\n    } else if ((typeof features === 'undefined' ? 'undefined' : _typeof(features)) === 'object') {\n      this.features = features;\n    }\n  }\n\n  /**\n   * The total advance width of the run.\n   * @type {number}\n   */\n\n\n  _createClass(GlyphRun, [{\n    key: 'advanceWidth',\n    get: function get() {\n      var width = 0;\n      for (var _iterator2 = this.positions, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n        var _ref2;\n\n        if (_isArray2) {\n          if (_i2 >= _iterator2.length) break;\n          _ref2 = _iterator2[_i2++];\n        } else {\n          _i2 = _iterator2.next();\n          if (_i2.done) break;\n          _ref2 = _i2.value;\n        }\n\n        var position = _ref2;\n\n        width += position.xAdvance;\n      }\n\n      return width;\n    }\n\n    /**\n     * The total advance height of the run.\n     * @type {number}\n     */\n\n  }, {\n    key: 'advanceHeight',\n    get: function get() {\n      var height = 0;\n      for (var _iterator3 = this.positions, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n        var _ref3;\n\n        if (_isArray3) {\n          if (_i3 >= _iterator3.length) break;\n          _ref3 = _iterator3[_i3++];\n        } else {\n          _i3 = _iterator3.next();\n          if (_i3.done) break;\n          _ref3 = _i3.value;\n        }\n\n        var position = _ref3;\n\n        height += position.yAdvance;\n      }\n\n      return height;\n    }\n\n    /**\n     * The bounding box containing all glyphs in the run.\n     * @type {BBox}\n     */\n\n  }, {\n    key: 'bbox',\n    get: function get() {\n      var bbox = new BBox();\n\n      var x = 0;\n      var y = 0;\n      for (var index = 0; index < this.glyphs.length; index++) {\n        var glyph = this.glyphs[index];\n        var p = this.positions[index];\n        var b = glyph.bbox;\n\n        bbox.addPoint(b.minX + x + p.xOffset, b.minY + y + p.yOffset);\n        bbox.addPoint(b.maxX + x + p.xOffset, b.maxY + y + p.yOffset);\n\n        x += p.xAdvance;\n        y += p.yAdvance;\n      }\n\n      return bbox;\n    }\n  }]);\n\n  return GlyphRun;\n}();\n\n/**\n * Represents positioning information for a glyph in a GlyphRun.\n */\nvar GlyphPosition = function GlyphPosition() {\n  var xAdvance = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;\n  var yAdvance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n  var xOffset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n  var yOffset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;\n\n  _classCallCheck(this, GlyphPosition);\n\n  /**\n   * The amount to move the virtual pen in the X direction after rendering this glyph.\n   * @type {number}\n   */\n  this.xAdvance = xAdvance;\n\n  /**\n   * The amount to move the virtual pen in the Y direction after rendering this glyph.\n   * @type {number}\n   */\n  this.yAdvance = yAdvance;\n\n  /**\n   * The offset from the pen position in the X direction at which to render this glyph.\n   * @type {number}\n   */\n  this.xOffset = xOffset;\n\n  /**\n   * The offset from the pen position in the Y direction at which to render this glyph.\n   * @type {number}\n   */\n  this.yOffset = yOffset;\n};\n\n// see https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html\n// and /System/Library/Frameworks/CoreText.framework/Versions/A/Headers/SFNTLayoutTypes.h on a Mac\nvar features = {\n  allTypographicFeatures: {\n    code: 0,\n    exclusive: false,\n    allTypeFeatures: 0\n  },\n  ligatures: {\n    code: 1,\n    exclusive: false,\n    requiredLigatures: 0,\n    commonLigatures: 2,\n    rareLigatures: 4,\n    // logos: 6\n    rebusPictures: 8,\n    diphthongLigatures: 10,\n    squaredLigatures: 12,\n    abbrevSquaredLigatures: 14,\n    symbolLigatures: 16,\n    contextualLigatures: 18,\n    historicalLigatures: 20\n  },\n  cursiveConnection: {\n    code: 2,\n    exclusive: true,\n    unconnected: 0,\n    partiallyConnected: 1,\n    cursive: 2\n  },\n  letterCase: {\n    code: 3,\n    exclusive: true\n  },\n  // upperAndLowerCase: 0          # deprecated\n  // allCaps: 1                    # deprecated\n  // allLowerCase: 2               # deprecated\n  // smallCaps: 3                  # deprecated\n  // initialCaps: 4                # deprecated\n  // initialCapsAndSmallCaps: 5    # deprecated\n  verticalSubstitution: {\n    code: 4,\n    exclusive: false,\n    substituteVerticalForms: 0\n  },\n  linguisticRearrangement: {\n    code: 5,\n    exclusive: false,\n    linguisticRearrangement: 0\n  },\n  numberSpacing: {\n    code: 6,\n    exclusive: true,\n    monospacedNumbers: 0,\n    proportionalNumbers: 1,\n    thirdWidthNumbers: 2,\n    quarterWidthNumbers: 3\n  },\n  smartSwash: {\n    code: 8,\n    exclusive: false,\n    wordInitialSwashes: 0,\n    wordFinalSwashes: 2,\n    // lineInitialSwashes: 4\n    // lineFinalSwashes: 6\n    nonFinalSwashes: 8\n  },\n  diacritics: {\n    code: 9,\n    exclusive: true,\n    showDiacritics: 0,\n    hideDiacritics: 1,\n    decomposeDiacritics: 2\n  },\n  verticalPosition: {\n    code: 10,\n    exclusive: true,\n    normalPosition: 0,\n    superiors: 1,\n    inferiors: 2,\n    ordinals: 3,\n    scientificInferiors: 4\n  },\n  fractions: {\n    code: 11,\n    exclusive: true,\n    noFractions: 0,\n    verticalFractions: 1,\n    diagonalFractions: 2\n  },\n  overlappingCharacters: {\n    code: 13,\n    exclusive: false,\n    preventOverlap: 0\n  },\n  typographicExtras: {\n    code: 14,\n    exclusive: false,\n    // hyphensToEmDash: 0\n    // hyphenToEnDash: 2\n    slashedZero: 4\n  },\n  // formInterrobang: 6\n  // smartQuotes: 8\n  // periodsToEllipsis: 10\n  mathematicalExtras: {\n    code: 15,\n    exclusive: false,\n    // hyphenToMinus: 0\n    // asteristoMultiply: 2\n    // slashToDivide: 4\n    // inequalityLigatures: 6\n    // exponents: 8\n    mathematicalGreek: 10\n  },\n  ornamentSets: {\n    code: 16,\n    exclusive: true,\n    noOrnaments: 0,\n    dingbats: 1,\n    piCharacters: 2,\n    fleurons: 3,\n    decorativeBorders: 4,\n    internationalSymbols: 5,\n    mathSymbols: 6\n  },\n  characterAlternatives: {\n    code: 17,\n    exclusive: true,\n    noAlternates: 0\n  },\n  // user defined options\n  designComplexity: {\n    code: 18,\n    exclusive: true,\n    designLevel1: 0,\n    designLevel2: 1,\n    designLevel3: 2,\n    designLevel4: 3,\n    designLevel5: 4\n  },\n  styleOptions: {\n    code: 19,\n    exclusive: true,\n    noStyleOptions: 0,\n    displayText: 1,\n    engravedText: 2,\n    illuminatedCaps: 3,\n    titlingCaps: 4,\n    tallCaps: 5\n  },\n  characterShape: {\n    code: 20,\n    exclusive: true,\n    traditionalCharacters: 0,\n    simplifiedCharacters: 1,\n    JIS1978Characters: 2,\n    JIS1983Characters: 3,\n    JIS1990Characters: 4,\n    traditionalAltOne: 5,\n    traditionalAltTwo: 6,\n    traditionalAltThree: 7,\n    traditionalAltFour: 8,\n    traditionalAltFive: 9,\n    expertCharacters: 10,\n    JIS2004Characters: 11,\n    hojoCharacters: 12,\n    NLCCharacters: 13,\n    traditionalNamesCharacters: 14\n  },\n  numberCase: {\n    code: 21,\n    exclusive: true,\n    lowerCaseNumbers: 0,\n    upperCaseNumbers: 1\n  },\n  textSpacing: {\n    code: 22,\n    exclusive: true,\n    proportionalText: 0,\n    monospacedText: 1,\n    halfWidthText: 2,\n    thirdWidthText: 3,\n    quarterWidthText: 4,\n    altProportionalText: 5,\n    altHalfWidthText: 6\n  },\n  transliteration: {\n    code: 23,\n    exclusive: true,\n    noTransliteration: 0\n  },\n  // hanjaToHangul: 1\n  // hiraganaToKatakana: 2\n  // katakanaToHiragana: 3\n  // kanaToRomanization: 4\n  // romanizationToHiragana: 5\n  // romanizationToKatakana: 6\n  // hanjaToHangulAltOne: 7\n  // hanjaToHangulAltTwo: 8\n  // hanjaToHangulAltThree: 9\n  annotation: {\n    code: 24,\n    exclusive: true,\n    noAnnotation: 0,\n    boxAnnotation: 1,\n    roundedBoxAnnotation: 2,\n    circleAnnotation: 3,\n    invertedCircleAnnotation: 4,\n    parenthesisAnnotation: 5,\n    periodAnnotation: 6,\n    romanNumeralAnnotation: 7,\n    diamondAnnotation: 8,\n    invertedBoxAnnotation: 9,\n    invertedRoundedBoxAnnotation: 10\n  },\n  kanaSpacing: {\n    code: 25,\n    exclusive: true,\n    fullWidthKana: 0,\n    proportionalKana: 1\n  },\n  ideographicSpacing: {\n    code: 26,\n    exclusive: true,\n    fullWidthIdeographs: 0,\n    proportionalIdeographs: 1,\n    halfWidthIdeographs: 2\n  },\n  unicodeDecomposition: {\n    code: 27,\n    exclusive: false,\n    canonicalComposition: 0,\n    compatibilityComposition: 2,\n    transcodingComposition: 4\n  },\n  rubyKana: {\n    code: 28,\n    exclusive: false,\n    // noRubyKana: 0     # deprecated - use rubyKanaOff instead\n    // rubyKana: 1     # deprecated - use rubyKanaOn instead\n    rubyKana: 2\n  },\n  CJKSymbolAlternatives: {\n    code: 29,\n    exclusive: true,\n    noCJKSymbolAlternatives: 0,\n    CJKSymbolAltOne: 1,\n    CJKSymbolAltTwo: 2,\n    CJKSymbolAltThree: 3,\n    CJKSymbolAltFour: 4,\n    CJKSymbolAltFive: 5\n  },\n  ideographicAlternatives: {\n    code: 30,\n    exclusive: true,\n    noIdeographicAlternatives: 0,\n    ideographicAltOne: 1,\n    ideographicAltTwo: 2,\n    ideographicAltThree: 3,\n    ideographicAltFour: 4,\n    ideographicAltFive: 5\n  },\n  CJKVerticalRomanPlacement: {\n    code: 31,\n    exclusive: true,\n    CJKVerticalRomanCentered: 0,\n    CJKVerticalRomanHBaseline: 1\n  },\n  italicCJKRoman: {\n    code: 32,\n    exclusive: false,\n    // noCJKItalicRoman: 0     # deprecated - use CJKItalicRomanOff instead\n    // CJKItalicRoman: 1     # deprecated - use CJKItalicRomanOn instead\n    CJKItalicRoman: 2\n  },\n  caseSensitiveLayout: {\n    code: 33,\n    exclusive: false,\n    caseSensitiveLayout: 0,\n    caseSensitiveSpacing: 2\n  },\n  alternateKana: {\n    code: 34,\n    exclusive: false,\n    alternateHorizKana: 0,\n    alternateVertKana: 2\n  },\n  stylisticAlternatives: {\n    code: 35,\n    exclusive: false,\n    noStylisticAlternates: 0,\n    stylisticAltOne: 2,\n    stylisticAltTwo: 4,\n    stylisticAltThree: 6,\n    stylisticAltFour: 8,\n    stylisticAltFive: 10,\n    stylisticAltSix: 12,\n    stylisticAltSeven: 14,\n    stylisticAltEight: 16,\n    stylisticAltNine: 18,\n    stylisticAltTen: 20,\n    stylisticAltEleven: 22,\n    stylisticAltTwelve: 24,\n    stylisticAltThirteen: 26,\n    stylisticAltFourteen: 28,\n    stylisticAltFifteen: 30,\n    stylisticAltSixteen: 32,\n    stylisticAltSeventeen: 34,\n    stylisticAltEighteen: 36,\n    stylisticAltNineteen: 38,\n    stylisticAltTwenty: 40\n  },\n  contextualAlternates: {\n    code: 36,\n    exclusive: false,\n    contextualAlternates: 0,\n    swashAlternates: 2,\n    contextualSwashAlternates: 4\n  },\n  lowerCase: {\n    code: 37,\n    exclusive: true,\n    defaultLowerCase: 0,\n    lowerCaseSmallCaps: 1,\n    lowerCasePetiteCaps: 2\n  },\n  upperCase: {\n    code: 38,\n    exclusive: true,\n    defaultUpperCase: 0,\n    upperCaseSmallCaps: 1,\n    upperCasePetiteCaps: 2\n  },\n  languageTag: { // indices into ltag table\n    code: 39,\n    exclusive: true\n  },\n  CJKRomanSpacing: {\n    code: 103,\n    exclusive: true,\n    halfWidthCJKRoman: 0,\n    proportionalCJKRoman: 1,\n    defaultCJKRoman: 2,\n    fullWidthCJKRoman: 3\n  }\n};\n\nvar feature = function feature(name, selector) {\n  return [features[name].code, features[name][selector]];\n};\n\nvar OTMapping = {\n  rlig: feature('ligatures', 'requiredLigatures'),\n  clig: feature('ligatures', 'contextualLigatures'),\n  dlig: feature('ligatures', 'rareLigatures'),\n  hlig: feature('ligatures', 'historicalLigatures'),\n  liga: feature('ligatures', 'commonLigatures'),\n  hist: feature('ligatures', 'historicalLigatures'), // ??\n\n  smcp: feature('lowerCase', 'lowerCaseSmallCaps'),\n  pcap: feature('lowerCase', 'lowerCasePetiteCaps'),\n\n  frac: feature('fractions', 'diagonalFractions'),\n  dnom: feature('fractions', 'diagonalFractions'), // ??\n  numr: feature('fractions', 'diagonalFractions'), // ??\n  afrc: feature('fractions', 'verticalFractions'),\n  // aalt\n  // abvf, abvm, abvs, akhn, blwf, blwm, blws, cfar, cjct, cpsp, falt, isol, jalt, ljmo, mset?\n  // ltra, ltrm, nukt, pref, pres, pstf, psts, rand, rkrf, rphf, rtla, rtlm, size, tjmo, tnum?\n  // unic, vatu, vhal, vjmo, vpal, vrt2\n  // dist -> trak table?\n  // kern, vkrn -> kern table\n  // lfbd + opbd + rtbd -> opbd table?\n  // mark, mkmk -> acnt table?\n  // locl -> languageTag + ltag table\n\n  case: feature('caseSensitiveLayout', 'caseSensitiveLayout'), // also caseSensitiveSpacing\n  ccmp: feature('unicodeDecomposition', 'canonicalComposition'), // compatibilityComposition?\n  cpct: feature('CJKVerticalRomanPlacement', 'CJKVerticalRomanCentered'), // guess..., probably not given below\n  valt: feature('CJKVerticalRomanPlacement', 'CJKVerticalRomanCentered'),\n  swsh: feature('contextualAlternates', 'swashAlternates'),\n  cswh: feature('contextualAlternates', 'contextualSwashAlternates'),\n  curs: feature('cursiveConnection', 'cursive'), // ??\n  c2pc: feature('upperCase', 'upperCasePetiteCaps'),\n  c2sc: feature('upperCase', 'upperCaseSmallCaps'),\n\n  init: feature('smartSwash', 'wordInitialSwashes'), // ??\n  fin2: feature('smartSwash', 'wordFinalSwashes'), // ??\n  medi: feature('smartSwash', 'nonFinalSwashes'), // ??\n  med2: feature('smartSwash', 'nonFinalSwashes'), // ??\n  fin3: feature('smartSwash', 'wordFinalSwashes'), // ??\n  fina: feature('smartSwash', 'wordFinalSwashes'), // ??\n\n  pkna: feature('kanaSpacing', 'proportionalKana'),\n  half: feature('textSpacing', 'halfWidthText'), // also HalfWidthCJKRoman, HalfWidthIdeographs?\n  halt: feature('textSpacing', 'altHalfWidthText'),\n\n  hkna: feature('alternateKana', 'alternateHorizKana'),\n  vkna: feature('alternateKana', 'alternateVertKana'),\n  // hngl: feature 'transliteration', 'hanjaToHangulSelector' # deprecated\n\n  ital: feature('italicCJKRoman', 'CJKItalicRoman'),\n  lnum: feature('numberCase', 'upperCaseNumbers'),\n  onum: feature('numberCase', 'lowerCaseNumbers'),\n  mgrk: feature('mathematicalExtras', 'mathematicalGreek'),\n\n  // nalt: not enough info. what type of annotation?\n  // ornm: ditto, which ornament style?\n\n  calt: feature('contextualAlternates', 'contextualAlternates'), // or more?\n  vrt2: feature('verticalSubstitution', 'substituteVerticalForms'), // oh... below?\n  vert: feature('verticalSubstitution', 'substituteVerticalForms'),\n  tnum: feature('numberSpacing', 'monospacedNumbers'),\n  pnum: feature('numberSpacing', 'proportionalNumbers'),\n  sups: feature('verticalPosition', 'superiors'),\n  subs: feature('verticalPosition', 'inferiors'),\n  ordn: feature('verticalPosition', 'ordinals'),\n  pwid: feature('textSpacing', 'proportionalText'),\n  hwid: feature('textSpacing', 'halfWidthText'),\n  qwid: feature('textSpacing', 'quarterWidthText'), // also QuarterWidthNumbers?\n  twid: feature('textSpacing', 'thirdWidthText'), // also ThirdWidthNumbers?\n  fwid: feature('textSpacing', 'proportionalText'), //??\n  palt: feature('textSpacing', 'altProportionalText'),\n  trad: feature('characterShape', 'traditionalCharacters'),\n  smpl: feature('characterShape', 'simplifiedCharacters'),\n  jp78: feature('characterShape', 'JIS1978Characters'),\n  jp83: feature('characterShape', 'JIS1983Characters'),\n  jp90: feature('characterShape', 'JIS1990Characters'),\n  jp04: feature('characterShape', 'JIS2004Characters'),\n  expt: feature('characterShape', 'expertCharacters'),\n  hojo: feature('characterShape', 'hojoCharacters'),\n  nlck: feature('characterShape', 'NLCCharacters'),\n  tnam: feature('characterShape', 'traditionalNamesCharacters'),\n  ruby: feature('rubyKana', 'rubyKana'),\n  titl: feature('styleOptions', 'titlingCaps'),\n  zero: feature('typographicExtras', 'slashedZero'),\n\n  ss01: feature('stylisticAlternatives', 'stylisticAltOne'),\n  ss02: feature('stylisticAlternatives', 'stylisticAltTwo'),\n  ss03: feature('stylisticAlternatives', 'stylisticAltThree'),\n  ss04: feature('stylisticAlternatives', 'stylisticAltFour'),\n  ss05: feature('stylisticAlternatives', 'stylisticAltFive'),\n  ss06: feature('stylisticAlternatives', 'stylisticAltSix'),\n  ss07: feature('stylisticAlternatives', 'stylisticAltSeven'),\n  ss08: feature('stylisticAlternatives', 'stylisticAltEight'),\n  ss09: feature('stylisticAlternatives', 'stylisticAltNine'),\n  ss10: feature('stylisticAlternatives', 'stylisticAltTen'),\n  ss11: feature('stylisticAlternatives', 'stylisticAltEleven'),\n  ss12: feature('stylisticAlternatives', 'stylisticAltTwelve'),\n  ss13: feature('stylisticAlternatives', 'stylisticAltThirteen'),\n  ss14: feature('stylisticAlternatives', 'stylisticAltFourteen'),\n  ss15: feature('stylisticAlternatives', 'stylisticAltFifteen'),\n  ss16: feature('stylisticAlternatives', 'stylisticAltSixteen'),\n  ss17: feature('stylisticAlternatives', 'stylisticAltSeventeen'),\n  ss18: feature('stylisticAlternatives', 'stylisticAltEighteen'),\n  ss19: feature('stylisticAlternatives', 'stylisticAltNineteen'),\n  ss20: feature('stylisticAlternatives', 'stylisticAltTwenty')\n};\n\n// salt: feature 'stylisticAlternatives', 'stylisticAltOne' # hmm, which one to choose\n\n// Add cv01-cv99 features\nfor (var i = 1; i <= 99; i++) {\n  OTMapping['cv' + ('00' + i).slice(-2)] = [features.characterAlternatives.code, i];\n}\n\n// create inverse mapping\nvar AATMapping = {};\nfor (var ot in OTMapping) {\n  var aat = OTMapping[ot];\n  if (AATMapping[aat[0]] == null) {\n    AATMapping[aat[0]] = {};\n  }\n\n  AATMapping[aat[0]][aat[1]] = ot;\n}\n\n// Maps an array of OpenType features to AAT features\n// in the form of {featureType:{featureSetting:true}}\nfunction mapOTToAAT(features) {\n  var res = {};\n  for (var k in features) {\n    var r = void 0;\n    if (r = OTMapping[k]) {\n      if (res[r[0]] == null) {\n        res[r[0]] = {};\n      }\n\n      res[r[0]][r[1]] = features[k];\n    }\n  }\n\n  return res;\n}\n\n// Maps strings in a [featureType, featureSetting]\n// to their equivalent number codes\nfunction mapFeatureStrings(f) {\n  var type = f[0],\n      setting = f[1];\n\n  if (isNaN(type)) {\n    var typeCode = features[type] && features[type].code;\n  } else {\n    var typeCode = type;\n  }\n\n  if (isNaN(setting)) {\n    var settingCode = features[type] && features[type][setting];\n  } else {\n    var settingCode = setting;\n  }\n\n  return [typeCode, settingCode];\n}\n\n// Maps AAT features to an array of OpenType features\n// Supports both arrays in the form of [[featureType, featureSetting]]\n// and objects in the form of {featureType:{featureSetting:true}}\n// featureTypes and featureSettings can be either strings or number codes\nfunction mapAATToOT(features) {\n  var res = {};\n  if (Array.isArray(features)) {\n    for (var k = 0; k < features.length; k++) {\n      var r = void 0;\n      var f = mapFeatureStrings(features[k]);\n      if (r = AATMapping[f[0]] && AATMapping[f[0]][f[1]]) {\n        res[r] = true;\n      }\n    }\n  } else if ((typeof features === 'undefined' ? 'undefined' : _typeof(features)) === 'object') {\n    for (var type in features) {\n      var _feature = features[type];\n      for (var setting in _feature) {\n        var _r = void 0;\n        var _f = mapFeatureStrings([type, setting]);\n        if (_feature[setting] && (_r = AATMapping[_f[0]] && AATMapping[_f[0]][_f[1]])) {\n          res[_r] = true;\n        }\n      }\n    }\n  }\n\n  return _Object$keys(res);\n}\n\nvar _class$3;\nfunction _applyDecoratedDescriptor$3(target, property, decorators, descriptor, context) {\n  var desc = {};\n  Object['ke' + 'ys'](descriptor).forEach(function (key) {\n    desc[key] = descriptor[key];\n  });\n  desc.enumerable = !!desc.enumerable;\n  desc.configurable = !!desc.configurable;\n\n  if ('value' in desc || desc.initializer) {\n    desc.writable = true;\n  }\n\n  desc = decorators.slice().reverse().reduce(function (desc, decorator) {\n    return decorator(target, property, desc) || desc;\n  }, desc);\n\n  if (context && desc.initializer !== void 0) {\n    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;\n    desc.initializer = undefined;\n  }\n\n  if (desc.initializer === void 0) {\n    Object['define' + 'Property'](target, property, desc);\n    desc = null;\n  }\n\n  return desc;\n}\n\nvar AATLookupTable = (_class$3 = function () {\n  function AATLookupTable(table) {\n    _classCallCheck(this, AATLookupTable);\n\n    this.table = table;\n  }\n\n  AATLookupTable.prototype.lookup = function lookup(glyph) {\n    switch (this.table.version) {\n      case 0:\n        // simple array format\n        return this.table.values.getItem(glyph);\n\n      case 2: // segment format\n      case 4:\n        {\n          var min = 0;\n          var max = this.table.binarySearchHeader.nUnits - 1;\n\n          while (min <= max) {\n            var mid = min + max >> 1;\n            var seg = this.table.segments[mid];\n\n            // special end of search value\n            if (seg.firstGlyph === 0xffff) {\n              return null;\n            }\n\n            if (glyph < seg.firstGlyph) {\n              max = mid - 1;\n            } else if (glyph > seg.lastGlyph) {\n              min = mid + 1;\n            } else {\n              if (this.table.version === 2) {\n                return seg.value;\n              } else {\n                return seg.values[glyph - seg.firstGlyph];\n              }\n            }\n          }\n\n          return null;\n        }\n\n      case 6:\n        {\n          // lookup single\n          var _min = 0;\n          var _max = this.table.binarySearchHeader.nUnits - 1;\n\n          while (_min <= _max) {\n            var mid = _min + _max >> 1;\n            var seg = this.table.segments[mid];\n\n            // special end of search value\n            if (seg.glyph === 0xffff) {\n              return null;\n            }\n\n            if (glyph < seg.glyph) {\n              _max = mid - 1;\n            } else if (glyph > seg.glyph) {\n              _min = mid + 1;\n            } else {\n              return seg.value;\n            }\n          }\n\n          return null;\n        }\n\n      case 8:\n        // lookup trimmed\n        return this.table.values[glyph - this.table.firstGlyph];\n\n      default:\n        throw new Error('Unknown lookup table format: ' + this.table.version);\n    }\n  };\n\n  AATLookupTable.prototype.glyphsForValue = function glyphsForValue(classValue) {\n    var res = [];\n\n    switch (this.table.version) {\n      case 2: // segment format\n      case 4:\n        {\n          for (var _iterator = this.table.segments, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n            var _ref;\n\n            if (_isArray) {\n              if (_i >= _iterator.length) break;\n              _ref = _iterator[_i++];\n            } else {\n              _i = _iterator.next();\n              if (_i.done) break;\n              _ref = _i.value;\n            }\n\n            var segment = _ref;\n\n            if (this.table.version === 2 && segment.value === classValue) {\n              res.push.apply(res, range(segment.firstGlyph, segment.lastGlyph + 1));\n            } else {\n              for (var index = 0; index < segment.values.length; index++) {\n                if (segment.values[index] === classValue) {\n                  res.push(segment.firstGlyph + index);\n                }\n              }\n            }\n          }\n\n          break;\n        }\n\n      case 6:\n        {\n          // lookup single\n          for (var _iterator2 = this.table.segments, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n            var _ref2;\n\n            if (_isArray2) {\n              if (_i2 >= _iterator2.length) break;\n              _ref2 = _iterator2[_i2++];\n            } else {\n              _i2 = _iterator2.next();\n              if (_i2.done) break;\n              _ref2 = _i2.value;\n            }\n\n            var _segment = _ref2;\n\n            if (_segment.value === classValue) {\n              res.push(_segment.glyph);\n            }\n          }\n\n          break;\n        }\n\n      case 8:\n        {\n          // lookup trimmed\n          for (var i = 0; i < this.table.values.length; i++) {\n            if (this.table.values[i] === classValue) {\n              res.push(this.table.firstGlyph + i);\n            }\n          }\n\n          break;\n        }\n\n      default:\n        throw new Error('Unknown lookup table format: ' + this.table.version);\n    }\n\n    return res;\n  };\n\n  return AATLookupTable;\n}(), (_applyDecoratedDescriptor$3(_class$3.prototype, 'glyphsForValue', [cache], _Object$getOwnPropertyDescriptor(_class$3.prototype, 'glyphsForValue'), _class$3.prototype)), _class$3);\n\nvar START_OF_TEXT_STATE = 0;\nvar END_OF_TEXT_CLASS = 0;\nvar OUT_OF_BOUNDS_CLASS = 1;\nvar DELETED_GLYPH_CLASS = 2;\nvar DONT_ADVANCE = 0x4000;\n\nvar AATStateMachine = function () {\n  function AATStateMachine(stateTable) {\n    _classCallCheck(this, AATStateMachine);\n\n    this.stateTable = stateTable;\n    this.lookupTable = new AATLookupTable(stateTable.classTable);\n  }\n\n  AATStateMachine.prototype.process = function process(glyphs, reverse, processEntry) {\n    var currentState = START_OF_TEXT_STATE; // START_OF_LINE_STATE is used for kashida glyph insertions sometimes I think?\n    var index = reverse ? glyphs.length - 1 : 0;\n    var dir = reverse ? -1 : 1;\n\n    while (dir === 1 && index <= glyphs.length || dir === -1 && index >= -1) {\n      var glyph = null;\n      var classCode = OUT_OF_BOUNDS_CLASS;\n      var shouldAdvance = true;\n\n      if (index === glyphs.length || index === -1) {\n        classCode = END_OF_TEXT_CLASS;\n      } else {\n        glyph = glyphs[index];\n        if (glyph.id === 0xffff) {\n          // deleted glyph\n          classCode = DELETED_GLYPH_CLASS;\n        } else {\n          classCode = this.lookupTable.lookup(glyph.id);\n          if (classCode == null) {\n            classCode = OUT_OF_BOUNDS_CLASS;\n          }\n        }\n      }\n\n      var row = this.stateTable.stateArray.getItem(currentState);\n      var entryIndex = row[classCode];\n      var entry = this.stateTable.entryTable.getItem(entryIndex);\n\n      if (classCode !== END_OF_TEXT_CLASS && classCode !== DELETED_GLYPH_CLASS) {\n        processEntry(glyph, entry, index);\n        shouldAdvance = !(entry.flags & DONT_ADVANCE);\n      }\n\n      currentState = entry.newState;\n      if (shouldAdvance) {\n        index += dir;\n      }\n    }\n\n    return glyphs;\n  };\n\n  /**\n   * Performs a depth-first traversal of the glyph strings\n   * represented by the state machine.\n   */\n\n\n  AATStateMachine.prototype.traverse = function traverse(opts) {\n    var state = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n    var visited = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : new _Set();\n\n    if (visited.has(state)) {\n      return;\n    }\n\n    visited.add(state);\n\n    var _stateTable = this.stateTable,\n        nClasses = _stateTable.nClasses,\n        stateArray = _stateTable.stateArray,\n        entryTable = _stateTable.entryTable;\n\n    var row = stateArray.getItem(state);\n\n    // Skip predefined classes\n    for (var classCode = 4; classCode < nClasses; classCode++) {\n      var entryIndex = row[classCode];\n      var entry = entryTable.getItem(entryIndex);\n\n      // Try all glyphs in the class\n      for (var _iterator = this.lookupTable.glyphsForValue(classCode), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n        var _ref;\n\n        if (_isArray) {\n          if (_i >= _iterator.length) break;\n          _ref = _iterator[_i++];\n        } else {\n          _i = _iterator.next();\n          if (_i.done) break;\n          _ref = _i.value;\n        }\n\n        var glyph = _ref;\n\n        if (opts.enter) {\n          opts.enter(glyph, entry);\n        }\n\n        if (entry.newState !== 0) {\n          this.traverse(opts, entry.newState, visited);\n        }\n\n        if (opts.exit) {\n          opts.exit(glyph, entry);\n        }\n      }\n    }\n  };\n\n  return AATStateMachine;\n}();\n\nvar _class$2;\nfunction _applyDecoratedDescriptor$2(target, property, decorators, descriptor, context) {\n  var desc = {};\n  Object['ke' + 'ys'](descriptor).forEach(function (key) {\n    desc[key] = descriptor[key];\n  });\n  desc.enumerable = !!desc.enumerable;\n  desc.configurable = !!desc.configurable;\n\n  if ('value' in desc || desc.initializer) {\n    desc.writable = true;\n  }\n\n  desc = decorators.slice().reverse().reduce(function (desc, decorator) {\n    return decorator(target, property, desc) || desc;\n  }, desc);\n\n  if (context && desc.initializer !== void 0) {\n    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;\n    desc.initializer = undefined;\n  }\n\n  if (desc.initializer === void 0) {\n    Object['define' + 'Property'](target, property, desc);\n    desc = null;\n  }\n\n  return desc;\n}\n\n// indic replacement flags\nvar MARK_FIRST = 0x8000;\nvar MARK_LAST = 0x2000;\nvar VERB = 0x000F;\n\n// contextual substitution and glyph insertion flag\nvar SET_MARK = 0x8000;\n\n// ligature entry flags\nvar SET_COMPONENT = 0x8000;\nvar PERFORM_ACTION = 0x2000;\n\n// ligature action masks\nvar LAST_MASK = 0x80000000;\nvar STORE_MASK = 0x40000000;\nvar OFFSET_MASK = 0x3FFFFFFF;\n\nvar REVERSE_DIRECTION = 0x400000;\nvar CURRENT_INSERT_BEFORE = 0x0800;\nvar MARKED_INSERT_BEFORE = 0x0400;\nvar CURRENT_INSERT_COUNT = 0x03E0;\nvar MARKED_INSERT_COUNT = 0x001F;\n\nvar AATMorxProcessor = (_class$2 = function () {\n  function AATMorxProcessor(font) {\n    _classCallCheck(this, AATMorxProcessor);\n\n    this.processIndicRearragement = this.processIndicRearragement.bind(this);\n    this.processContextualSubstitution = this.processContextualSubstitution.bind(this);\n    this.processLigature = this.processLigature.bind(this);\n    this.processNoncontextualSubstitutions = this.processNoncontextualSubstitutions.bind(this);\n    this.processGlyphInsertion = this.processGlyphInsertion.bind(this);\n    this.font = font;\n    this.morx = font.morx;\n    this.inputCache = null;\n  }\n\n  // Processes an array of glyphs and applies the specified features\n  // Features should be in the form of {featureType:{featureSetting:true}}\n\n\n  AATMorxProcessor.prototype.process = function process(glyphs) {\n    var features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\n    for (var _iterator = this.morx.chains, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var chain = _ref;\n\n      var flags = chain.defaultFlags;\n\n      // enable/disable the requested features\n      for (var _iterator2 = chain.features, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n        var _ref2;\n\n        if (_isArray2) {\n          if (_i2 >= _iterator2.length) break;\n          _ref2 = _iterator2[_i2++];\n        } else {\n          _i2 = _iterator2.next();\n          if (_i2.done) break;\n          _ref2 = _i2.value;\n        }\n\n        var feature = _ref2;\n\n        var f = void 0;\n        if ((f = features[feature.featureType]) && f[feature.featureSetting]) {\n          flags &= feature.disableFlags;\n          flags |= feature.enableFlags;\n        }\n      }\n\n      for (var _iterator3 = chain.subtables, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n        var _ref3;\n\n        if (_isArray3) {\n          if (_i3 >= _iterator3.length) break;\n          _ref3 = _iterator3[_i3++];\n        } else {\n          _i3 = _iterator3.next();\n          if (_i3.done) break;\n          _ref3 = _i3.value;\n        }\n\n        var subtable = _ref3;\n\n        if (subtable.subFeatureFlags & flags) {\n          this.processSubtable(subtable, glyphs);\n        }\n      }\n    }\n\n    // remove deleted glyphs\n    var index = glyphs.length - 1;\n    while (index >= 0) {\n      if (glyphs[index].id === 0xffff) {\n        glyphs.splice(index, 1);\n      }\n\n      index--;\n    }\n\n    return glyphs;\n  };\n\n  AATMorxProcessor.prototype.processSubtable = function processSubtable(subtable, glyphs) {\n    this.subtable = subtable;\n    this.glyphs = glyphs;\n    if (this.subtable.type === 4) {\n      this.processNoncontextualSubstitutions(this.subtable, this.glyphs);\n      return;\n    }\n\n    this.ligatureStack = [];\n    this.markedGlyph = null;\n    this.firstGlyph = null;\n    this.lastGlyph = null;\n    this.markedIndex = null;\n\n    var stateMachine = this.getStateMachine(subtable);\n    var process = this.getProcessor();\n\n    var reverse = !!(this.subtable.coverage & REVERSE_DIRECTION);\n    return stateMachine.process(this.glyphs, reverse, process);\n  };\n\n  AATMorxProcessor.prototype.getStateMachine = function getStateMachine(subtable) {\n    return new AATStateMachine(subtable.table.stateTable);\n  };\n\n  AATMorxProcessor.prototype.getProcessor = function getProcessor() {\n    switch (this.subtable.type) {\n      case 0:\n        return this.processIndicRearragement;\n      case 1:\n        return this.processContextualSubstitution;\n      case 2:\n        return this.processLigature;\n      case 4:\n        return this.processNoncontextualSubstitutions;\n      case 5:\n        return this.processGlyphInsertion;\n      default:\n        throw new Error('Invalid morx subtable type: ' + this.subtable.type);\n    }\n  };\n\n  AATMorxProcessor.prototype.processIndicRearragement = function processIndicRearragement(glyph, entry, index) {\n    if (entry.flags & MARK_FIRST) {\n      this.firstGlyph = index;\n    }\n\n    if (entry.flags & MARK_LAST) {\n      this.lastGlyph = index;\n    }\n\n    reorderGlyphs(this.glyphs, entry.flags & VERB, this.firstGlyph, this.lastGlyph);\n  };\n\n  AATMorxProcessor.prototype.processContextualSubstitution = function processContextualSubstitution(glyph, entry, index) {\n    var subsitutions = this.subtable.table.substitutionTable.items;\n    if (entry.markIndex !== 0xffff) {\n      var lookup = subsitutions.getItem(entry.markIndex);\n      var lookupTable = new AATLookupTable(lookup);\n      glyph = this.glyphs[this.markedGlyph];\n      var gid = lookupTable.lookup(glyph.id);\n      if (gid) {\n        this.glyphs[this.markedGlyph] = this.font.getGlyph(gid, glyph.codePoints);\n      }\n    }\n\n    if (entry.currentIndex !== 0xffff) {\n      var _lookup = subsitutions.getItem(entry.currentIndex);\n      var _lookupTable = new AATLookupTable(_lookup);\n      glyph = this.glyphs[index];\n      var gid = _lookupTable.lookup(glyph.id);\n      if (gid) {\n        this.glyphs[index] = this.font.getGlyph(gid, glyph.codePoints);\n      }\n    }\n\n    if (entry.flags & SET_MARK) {\n      this.markedGlyph = index;\n    }\n  };\n\n  AATMorxProcessor.prototype.processLigature = function processLigature(glyph, entry, index) {\n    if (entry.flags & SET_COMPONENT) {\n      this.ligatureStack.push(index);\n    }\n\n    if (entry.flags & PERFORM_ACTION) {\n      var _ligatureStack;\n\n      var actions = this.subtable.table.ligatureActions;\n      var components = this.subtable.table.components;\n      var ligatureList = this.subtable.table.ligatureList;\n\n      var actionIndex = entry.action;\n      var last = false;\n      var ligatureIndex = 0;\n      var codePoints = [];\n      var ligatureGlyphs = [];\n\n      while (!last) {\n        var _codePoints;\n\n        var componentGlyph = this.ligatureStack.pop();\n        (_codePoints = codePoints).unshift.apply(_codePoints, this.glyphs[componentGlyph].codePoints);\n\n        var action = actions.getItem(actionIndex++);\n        last = !!(action & LAST_MASK);\n        var store = !!(action & STORE_MASK);\n        var offset = (action & OFFSET_MASK) << 2 >> 2; // sign extend 30 to 32 bits\n        offset += this.glyphs[componentGlyph].id;\n\n        var component = components.getItem(offset);\n        ligatureIndex += component;\n\n        if (last || store) {\n          var ligatureEntry = ligatureList.getItem(ligatureIndex);\n          this.glyphs[componentGlyph] = this.font.getGlyph(ligatureEntry, codePoints);\n          ligatureGlyphs.push(componentGlyph);\n          ligatureIndex = 0;\n          codePoints = [];\n        } else {\n          this.glyphs[componentGlyph] = this.font.getGlyph(0xffff);\n        }\n      }\n\n      // Put ligature glyph indexes back on the stack\n      (_ligatureStack = this.ligatureStack).push.apply(_ligatureStack, ligatureGlyphs);\n    }\n  };\n\n  AATMorxProcessor.prototype.processNoncontextualSubstitutions = function processNoncontextualSubstitutions(subtable, glyphs, index) {\n    var lookupTable = new AATLookupTable(subtable.table.lookupTable);\n\n    for (index = 0; index < glyphs.length; index++) {\n      var glyph = glyphs[index];\n      if (glyph.id !== 0xffff) {\n        var gid = lookupTable.lookup(glyph.id);\n        if (gid) {\n          // 0 means do nothing\n          glyphs[index] = this.font.getGlyph(gid, glyph.codePoints);\n        }\n      }\n    }\n  };\n\n  AATMorxProcessor.prototype._insertGlyphs = function _insertGlyphs(glyphIndex, insertionActionIndex, count, isBefore) {\n    var _glyphs;\n\n    var insertions = [];\n    while (count--) {\n      var gid = this.subtable.table.insertionActions.getItem(insertionActionIndex++);\n      insertions.push(this.font.getGlyph(gid));\n    }\n\n    if (!isBefore) {\n      glyphIndex++;\n    }\n\n    (_glyphs = this.glyphs).splice.apply(_glyphs, [glyphIndex, 0].concat(insertions));\n  };\n\n  AATMorxProcessor.prototype.processGlyphInsertion = function processGlyphInsertion(glyph, entry, index) {\n    if (entry.flags & SET_MARK) {\n      this.markedIndex = index;\n    }\n\n    if (entry.markedInsertIndex !== 0xffff) {\n      var count = (entry.flags & MARKED_INSERT_COUNT) >>> 5;\n      var isBefore = !!(entry.flags & MARKED_INSERT_BEFORE);\n      this._insertGlyphs(this.markedIndex, entry.markedInsertIndex, count, isBefore);\n    }\n\n    if (entry.currentInsertIndex !== 0xffff) {\n      var _count = (entry.flags & CURRENT_INSERT_COUNT) >>> 5;\n      var _isBefore = !!(entry.flags & CURRENT_INSERT_BEFORE);\n      this._insertGlyphs(index, entry.currentInsertIndex, _count, _isBefore);\n    }\n  };\n\n  AATMorxProcessor.prototype.getSupportedFeatures = function getSupportedFeatures() {\n    var features = [];\n    for (var _iterator4 = this.morx.chains, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _getIterator(_iterator4);;) {\n      var _ref4;\n\n      if (_isArray4) {\n        if (_i4 >= _iterator4.length) break;\n        _ref4 = _iterator4[_i4++];\n      } else {\n        _i4 = _iterator4.next();\n        if (_i4.done) break;\n        _ref4 = _i4.value;\n      }\n\n      var chain = _ref4;\n\n      for (var _iterator5 = chain.features, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _getIterator(_iterator5);;) {\n        var _ref5;\n\n        if (_isArray5) {\n          if (_i5 >= _iterator5.length) break;\n          _ref5 = _iterator5[_i5++];\n        } else {\n          _i5 = _iterator5.next();\n          if (_i5.done) break;\n          _ref5 = _i5.value;\n        }\n\n        var feature = _ref5;\n\n        features.push([feature.featureType, feature.featureSetting]);\n      }\n    }\n\n    return features;\n  };\n\n  AATMorxProcessor.prototype.generateInputs = function generateInputs(gid) {\n    if (!this.inputCache) {\n      this.generateInputCache();\n    }\n\n    return this.inputCache[gid] || [];\n  };\n\n  AATMorxProcessor.prototype.generateInputCache = function generateInputCache() {\n    this.inputCache = {};\n\n    for (var _iterator6 = this.morx.chains, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _getIterator(_iterator6);;) {\n      var _ref6;\n\n      if (_isArray6) {\n        if (_i6 >= _iterator6.length) break;\n        _ref6 = _iterator6[_i6++];\n      } else {\n        _i6 = _iterator6.next();\n        if (_i6.done) break;\n        _ref6 = _i6.value;\n      }\n\n      var chain = _ref6;\n\n      var flags = chain.defaultFlags;\n\n      for (var _iterator7 = chain.subtables, _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _getIterator(_iterator7);;) {\n        var _ref7;\n\n        if (_isArray7) {\n          if (_i7 >= _iterator7.length) break;\n          _ref7 = _iterator7[_i7++];\n        } else {\n          _i7 = _iterator7.next();\n          if (_i7.done) break;\n          _ref7 = _i7.value;\n        }\n\n        var subtable = _ref7;\n\n        if (subtable.subFeatureFlags & flags) {\n          this.generateInputsForSubtable(subtable);\n        }\n      }\n    }\n  };\n\n  AATMorxProcessor.prototype.generateInputsForSubtable = function generateInputsForSubtable(subtable) {\n    var _this = this;\n\n    // Currently, only supporting ligature subtables.\n    if (subtable.type !== 2) {\n      return;\n    }\n\n    var reverse = !!(subtable.coverage & REVERSE_DIRECTION);\n    if (reverse) {\n      throw new Error('Reverse subtable, not supported.');\n    }\n\n    this.subtable = subtable;\n    this.ligatureStack = [];\n\n    var stateMachine = this.getStateMachine(subtable);\n    var process = this.getProcessor();\n\n    var input = [];\n    var stack = [];\n    this.glyphs = [];\n\n    stateMachine.traverse({\n      enter: function enter(glyph, entry) {\n        var glyphs = _this.glyphs;\n        stack.push({\n          glyphs: glyphs.slice(),\n          ligatureStack: _this.ligatureStack.slice()\n        });\n\n        // Add glyph to input and glyphs to process.\n        var g = _this.font.getGlyph(glyph);\n        input.push(g);\n        glyphs.push(input[input.length - 1]);\n\n        // Process ligature substitution\n        process(glyphs[glyphs.length - 1], entry, glyphs.length - 1);\n\n        // Add input to result if only one matching (non-deleted) glyph remains.\n        var count = 0;\n        var found = 0;\n        for (var i = 0; i < glyphs.length && count <= 1; i++) {\n          if (glyphs[i].id !== 0xffff) {\n            count++;\n            found = glyphs[i].id;\n          }\n        }\n\n        if (count === 1) {\n          var result = input.map(function (g) {\n            return g.id;\n          });\n          var _cache = _this.inputCache[found];\n          if (_cache) {\n            _cache.push(result);\n          } else {\n            _this.inputCache[found] = [result];\n          }\n        }\n      },\n\n      exit: function exit() {\n        var _stack$pop = stack.pop();\n\n        _this.glyphs = _stack$pop.glyphs;\n        _this.ligatureStack = _stack$pop.ligatureStack;\n\n        input.pop();\n      }\n    });\n  };\n\n  return AATMorxProcessor;\n}(), (_applyDecoratedDescriptor$2(_class$2.prototype, 'getStateMachine', [cache], _Object$getOwnPropertyDescriptor(_class$2.prototype, 'getStateMachine'), _class$2.prototype)), _class$2);\n\nfunction swap(glyphs, rangeA, rangeB) {\n  var reverseA = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;\n  var reverseB = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;\n\n  var end = glyphs.splice(rangeB[0] - (rangeB[1] - 1), rangeB[1]);\n  if (reverseB) {\n    end.reverse();\n  }\n\n  var start = glyphs.splice.apply(glyphs, [rangeA[0], rangeA[1]].concat(end));\n  if (reverseA) {\n    start.reverse();\n  }\n\n  glyphs.splice.apply(glyphs, [rangeB[0] - (rangeA[1] - 1), 0].concat(start));\n  return glyphs;\n}\n\nfunction reorderGlyphs(glyphs, verb, firstGlyph, lastGlyph) {\n  var length = lastGlyph - firstGlyph + 1;\n  switch (verb) {\n    case 0:\n      // no change\n      return glyphs;\n\n    case 1:\n      // Ax => xA\n      return swap(glyphs, [firstGlyph, 1], [lastGlyph, 0]);\n\n    case 2:\n      // xD => Dx\n      return swap(glyphs, [firstGlyph, 0], [lastGlyph, 1]);\n\n    case 3:\n      // AxD => DxA\n      return swap(glyphs, [firstGlyph, 1], [lastGlyph, 1]);\n\n    case 4:\n      // ABx => xAB\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 0]);\n\n    case 5:\n      // ABx => xBA\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 0], true, false);\n\n    case 6:\n      // xCD => CDx\n      return swap(glyphs, [firstGlyph, 0], [lastGlyph, 2]);\n\n    case 7:\n      // xCD => DCx\n      return swap(glyphs, [firstGlyph, 0], [lastGlyph, 2], false, true);\n\n    case 8:\n      // AxCD => CDxA\n      return swap(glyphs, [firstGlyph, 1], [lastGlyph, 2]);\n\n    case 9:\n      // AxCD => DCxA\n      return swap(glyphs, [firstGlyph, 1], [lastGlyph, 2], false, true);\n\n    case 10:\n      // ABxD => DxAB\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 1]);\n\n    case 11:\n      // ABxD => DxBA\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 1], true, false);\n\n    case 12:\n      // ABxCD => CDxAB\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2]);\n\n    case 13:\n      // ABxCD => CDxBA\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2], true, false);\n\n    case 14:\n      // ABxCD => DCxAB\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2], false, true);\n\n    case 15:\n      // ABxCD => DCxBA\n      return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2], true, true);\n\n    default:\n      throw new Error('Unknown verb: ' + verb);\n  }\n}\n\nvar AATLayoutEngine = function () {\n  function AATLayoutEngine(font) {\n    _classCallCheck(this, AATLayoutEngine);\n\n    this.font = font;\n    this.morxProcessor = new AATMorxProcessor(font);\n    this.fallbackPosition = false;\n  }\n\n  AATLayoutEngine.prototype.substitute = function substitute(glyphRun) {\n    // AAT expects the glyphs to be in visual order prior to morx processing,\n    // so reverse the glyphs if the script is right-to-left.\n    if (glyphRun.direction === 'rtl') {\n      glyphRun.glyphs.reverse();\n    }\n\n    this.morxProcessor.process(glyphRun.glyphs, mapOTToAAT(glyphRun.features));\n  };\n\n  AATLayoutEngine.prototype.getAvailableFeatures = function getAvailableFeatures(script, language) {\n    return mapAATToOT(this.morxProcessor.getSupportedFeatures());\n  };\n\n  AATLayoutEngine.prototype.stringsForGlyph = function stringsForGlyph(gid) {\n    var glyphStrings = this.morxProcessor.generateInputs(gid);\n    var result = new _Set();\n\n    for (var _iterator = glyphStrings, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var glyphs = _ref;\n\n      this._addStrings(glyphs, 0, result, '');\n    }\n\n    return result;\n  };\n\n  AATLayoutEngine.prototype._addStrings = function _addStrings(glyphs, index, strings, string) {\n    var codePoints = this.font._cmapProcessor.codePointsForGlyph(glyphs[index]);\n\n    for (var _iterator2 = codePoints, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n      var _ref2;\n\n      if (_isArray2) {\n        if (_i2 >= _iterator2.length) break;\n        _ref2 = _iterator2[_i2++];\n      } else {\n        _i2 = _iterator2.next();\n        if (_i2.done) break;\n        _ref2 = _i2.value;\n      }\n\n      var codePoint = _ref2;\n\n      var s = string + _String$fromCodePoint(codePoint);\n      if (index < glyphs.length - 1) {\n        this._addStrings(glyphs, index + 1, strings, s);\n      } else {\n        strings.add(s);\n      }\n    }\n  };\n\n  return AATLayoutEngine;\n}();\n\n/**\n * ShapingPlans are used by the OpenType shapers to store which\n * features should by applied, and in what order to apply them.\n * The features are applied in groups called stages. A feature\n * can be applied globally to all glyphs, or locally to only\n * specific glyphs.\n *\n * @private\n */\n\nvar ShapingPlan = function () {\n  function ShapingPlan(font, script, direction) {\n    _classCallCheck(this, ShapingPlan);\n\n    this.font = font;\n    this.script = script;\n    this.direction = direction;\n    this.stages = [];\n    this.globalFeatures = {};\n    this.allFeatures = {};\n  }\n\n  /**\n   * Adds the given features to the last stage.\n   * Ignores features that have already been applied.\n   */\n\n\n  ShapingPlan.prototype._addFeatures = function _addFeatures(features, global) {\n    var stageIndex = this.stages.length - 1;\n    var stage = this.stages[stageIndex];\n    for (var _iterator = features, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var feature = _ref;\n\n      if (this.allFeatures[feature] == null) {\n        stage.push(feature);\n        this.allFeatures[feature] = stageIndex;\n\n        if (global) {\n          this.globalFeatures[feature] = true;\n        }\n      }\n    }\n  };\n\n  /**\n   * Add features to the last stage\n   */\n\n\n  ShapingPlan.prototype.add = function add(arg) {\n    var global = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n\n    if (this.stages.length === 0) {\n      this.stages.push([]);\n    }\n\n    if (typeof arg === 'string') {\n      arg = [arg];\n    }\n\n    if (Array.isArray(arg)) {\n      this._addFeatures(arg, global);\n    } else if ((typeof arg === 'undefined' ? 'undefined' : _typeof(arg)) === 'object') {\n      this._addFeatures(arg.global || [], true);\n      this._addFeatures(arg.local || [], false);\n    } else {\n      throw new Error(\"Unsupported argument to ShapingPlan#add\");\n    }\n  };\n\n  /**\n   * Add a new stage\n   */\n\n\n  ShapingPlan.prototype.addStage = function addStage(arg, global) {\n    if (typeof arg === 'function') {\n      this.stages.push(arg, []);\n    } else {\n      this.stages.push([]);\n      this.add(arg, global);\n    }\n  };\n\n  ShapingPlan.prototype.setFeatureOverrides = function setFeatureOverrides(features) {\n    if (Array.isArray(features)) {\n      this.add(features);\n    } else if ((typeof features === 'undefined' ? 'undefined' : _typeof(features)) === 'object') {\n      for (var tag in features) {\n        if (features[tag]) {\n          this.add(tag);\n        } else if (this.allFeatures[tag] != null) {\n          var stage = this.stages[this.allFeatures[tag]];\n          stage.splice(stage.indexOf(tag), 1);\n          delete this.allFeatures[tag];\n          delete this.globalFeatures[tag];\n        }\n      }\n    }\n  };\n\n  /**\n   * Assigns the global features to the given glyphs\n   */\n\n\n  ShapingPlan.prototype.assignGlobalFeatures = function assignGlobalFeatures(glyphs) {\n    for (var _iterator2 = glyphs, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n      var _ref2;\n\n      if (_isArray2) {\n        if (_i2 >= _iterator2.length) break;\n        _ref2 = _iterator2[_i2++];\n      } else {\n        _i2 = _iterator2.next();\n        if (_i2.done) break;\n        _ref2 = _i2.value;\n      }\n\n      var glyph = _ref2;\n\n      for (var feature in this.globalFeatures) {\n        glyph.features[feature] = true;\n      }\n    }\n  };\n\n  /**\n   * Executes the planned stages using the given OTProcessor\n   */\n\n\n  ShapingPlan.prototype.process = function process(processor, glyphs, positions) {\n    for (var _iterator3 = this.stages, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n      var _ref3;\n\n      if (_isArray3) {\n        if (_i3 >= _iterator3.length) break;\n        _ref3 = _iterator3[_i3++];\n      } else {\n        _i3 = _iterator3.next();\n        if (_i3.done) break;\n        _ref3 = _i3.value;\n      }\n\n      var stage = _ref3;\n\n      if (typeof stage === 'function') {\n        if (!positions) {\n          stage(this.font, glyphs, this);\n        }\n      } else if (stage.length > 0) {\n        processor.applyFeatures(stage, glyphs, positions);\n      }\n    }\n  };\n\n  return ShapingPlan;\n}();\n\nvar _class$4;\nvar _temp;\nvar VARIATION_FEATURES = ['rvrn'];\nvar COMMON_FEATURES = ['ccmp', 'locl', 'rlig', 'mark', 'mkmk'];\nvar FRACTIONAL_FEATURES = ['frac', 'numr', 'dnom'];\nvar HORIZONTAL_FEATURES = ['calt', 'clig', 'liga', 'rclt', 'curs', 'kern'];\nvar DIRECTIONAL_FEATURES = {\n  ltr: ['ltra', 'ltrm'],\n  rtl: ['rtla', 'rtlm']\n};\n\nvar DefaultShaper = (_temp = _class$4 = function () {\n  function DefaultShaper() {\n    _classCallCheck(this, DefaultShaper);\n  }\n\n  DefaultShaper.plan = function plan(_plan, glyphs, features) {\n    // Plan the features we want to apply\n    this.planPreprocessing(_plan);\n    this.planFeatures(_plan);\n    this.planPostprocessing(_plan, features);\n\n    // Assign the global features to all the glyphs\n    _plan.assignGlobalFeatures(glyphs);\n\n    // Assign local features to glyphs\n    this.assignFeatures(_plan, glyphs);\n  };\n\n  DefaultShaper.planPreprocessing = function planPreprocessing(plan) {\n    plan.add({\n      global: [].concat(VARIATION_FEATURES, DIRECTIONAL_FEATURES[plan.direction]),\n      local: FRACTIONAL_FEATURES\n    });\n  };\n\n  DefaultShaper.planFeatures = function planFeatures(plan) {\n    // Do nothing by default. Let subclasses override this.\n  };\n\n  DefaultShaper.planPostprocessing = function planPostprocessing(plan, userFeatures) {\n    plan.add([].concat(COMMON_FEATURES, HORIZONTAL_FEATURES));\n    plan.setFeatureOverrides(userFeatures);\n  };\n\n  DefaultShaper.assignFeatures = function assignFeatures(plan, glyphs) {\n    // Enable contextual fractions\n    for (var i = 0; i < glyphs.length; i++) {\n      var glyph = glyphs[i];\n      if (glyph.codePoints[0] === 0x2044) {\n        // fraction slash\n        var start = i;\n        var end = i + 1;\n\n        // Apply numerator\n        while (start > 0 && unicode.isDigit(glyphs[start - 1].codePoints[0])) {\n          glyphs[start - 1].features.numr = true;\n          glyphs[start - 1].features.frac = true;\n          start--;\n        }\n\n        // Apply denominator\n        while (end < glyphs.length && unicode.isDigit(glyphs[end].codePoints[0])) {\n          glyphs[end].features.dnom = true;\n          glyphs[end].features.frac = true;\n          end++;\n        }\n\n        // Apply fraction slash\n        glyph.features.frac = true;\n        i = end - 1;\n      }\n    }\n  };\n\n  return DefaultShaper;\n}(), _class$4.zeroMarkWidths = 'AFTER_GPOS', _temp);\n\nvar trie = new UnicodeTrie(Buffer(\"AAEQAAAAAAAAADGgAZUBav7t2CtPA0EUBeDZB00pin9AJZIEgyUEj0QhweDAgQOJxCBRBElQSBwSicLgkOAwnNKZ5GaY2c7uzj4o5yZfZrrbefbuIx2nSq3CGmzAWH/+K+UO7MIe7MMhHMMpnMMFXMIVXIt2t3CnP088iPqjqNN8e4Ij7Rle4LUH82rLm6i/92A+RERERERERERNmfz/89GDeRARERERzbN8ceps2Iwt9H0C9/AJ6yOlDkbTczcot5VSm8Pm1vcFWfb7+BKOLTuOd2UlTX4wGP85Eg953lWPFbnuN7PkjtLmalOWbNenkHOSa7T3KmR9MVTZ2zZkVj1kHa68MueVKH0R4zqQ44WEXLM8VjcWHP0PtKLfPzQnMtGn3W4QYf6qxFxceVI394r2xnV+1rih0fV1Vzf3fO1n3evL5J78ruvZ5ptX2Rwy92Tfb1wlEqut3U+sZ3HXOeJ7/zDrbyuP6+Zz0fqa6Nv3vhY7Yu1xWnGevmsvsUpTT/RYIe8waUH/rvHMWKFzLfN8L+rTfp645mfX7ftlnfDtYxN59w0=\",\"base64\"));\nvar FEATURES = ['isol', 'fina', 'fin2', 'fin3', 'medi', 'med2', 'init'];\n\nvar ShapingClasses = {\n  Non_Joining: 0,\n  Left_Joining: 1,\n  Right_Joining: 2,\n  Dual_Joining: 3,\n  Join_Causing: 3,\n  ALAPH: 4,\n  'DALATH RISH': 5,\n  Transparent: 6\n};\n\nvar ISOL = 'isol';\nvar FINA = 'fina';\nvar FIN2 = 'fin2';\nvar FIN3 = 'fin3';\nvar MEDI = 'medi';\nvar MED2 = 'med2';\nvar INIT = 'init';\nvar NONE = null;\n\n// Each entry is [prevAction, curAction, nextState]\nvar STATE_TABLE = [\n//   Non_Joining,        Left_Joining,       Right_Joining,     Dual_Joining,           ALAPH,            DALATH RISH\n// State 0: prev was U,  not willing to join.\n[[NONE, NONE, 0], [NONE, ISOL, 2], [NONE, ISOL, 1], [NONE, ISOL, 2], [NONE, ISOL, 1], [NONE, ISOL, 6]],\n\n// State 1: prev was R or ISOL/ALAPH,  not willing to join.\n[[NONE, NONE, 0], [NONE, ISOL, 2], [NONE, ISOL, 1], [NONE, ISOL, 2], [NONE, FIN2, 5], [NONE, ISOL, 6]],\n\n// State 2: prev was D/L in ISOL form,  willing to join.\n[[NONE, NONE, 0], [NONE, ISOL, 2], [INIT, FINA, 1], [INIT, FINA, 3], [INIT, FINA, 4], [INIT, FINA, 6]],\n\n// State 3: prev was D in FINA form,  willing to join.\n[[NONE, NONE, 0], [NONE, ISOL, 2], [MEDI, FINA, 1], [MEDI, FINA, 3], [MEDI, FINA, 4], [MEDI, FINA, 6]],\n\n// State 4: prev was FINA ALAPH,  not willing to join.\n[[NONE, NONE, 0], [NONE, ISOL, 2], [MED2, ISOL, 1], [MED2, ISOL, 2], [MED2, FIN2, 5], [MED2, ISOL, 6]],\n\n// State 5: prev was FIN2/FIN3 ALAPH,  not willing to join.\n[[NONE, NONE, 0], [NONE, ISOL, 2], [ISOL, ISOL, 1], [ISOL, ISOL, 2], [ISOL, FIN2, 5], [ISOL, ISOL, 6]],\n\n// State 6: prev was DALATH/RISH,  not willing to join.\n[[NONE, NONE, 0], [NONE, ISOL, 2], [NONE, ISOL, 1], [NONE, ISOL, 2], [NONE, FIN3, 5], [NONE, ISOL, 6]]];\n\n/**\n * This is a shaper for Arabic, and other cursive scripts.\n * It uses data from ArabicShaping.txt in the Unicode database,\n * compiled to a UnicodeTrie by generate-data.coffee.\n *\n * The shaping state machine was ported from Harfbuzz.\n * https://github.com/behdad/harfbuzz/blob/master/src/hb-ot-shape-complex-arabic.cc\n */\n\nvar ArabicShaper = function (_DefaultShaper) {\n  _inherits(ArabicShaper, _DefaultShaper);\n\n  function ArabicShaper() {\n    _classCallCheck(this, ArabicShaper);\n\n    return _possibleConstructorReturn(this, _DefaultShaper.apply(this, arguments));\n  }\n\n  ArabicShaper.planFeatures = function planFeatures(plan) {\n    plan.add(['ccmp', 'locl']);\n    for (var i = 0; i < FEATURES.length; i++) {\n      var feature = FEATURES[i];\n      plan.addStage(feature, false);\n    }\n\n    plan.addStage('mset');\n  };\n\n  ArabicShaper.assignFeatures = function assignFeatures(plan, glyphs) {\n    _DefaultShaper.assignFeatures.call(this, plan, glyphs);\n\n    var prev = -1;\n    var state = 0;\n    var actions = [];\n\n    // Apply the state machine to map glyphs to features\n    for (var i = 0; i < glyphs.length; i++) {\n      var curAction = void 0,\n          prevAction = void 0;\n      var glyph = glyphs[i];\n      var type = getShapingClass(glyph.codePoints[0]);\n      if (type === ShapingClasses.Transparent) {\n        actions[i] = NONE;\n        continue;\n      }\n\n      var _STATE_TABLE$state$ty = STATE_TABLE[state][type];\n      prevAction = _STATE_TABLE$state$ty[0];\n      curAction = _STATE_TABLE$state$ty[1];\n      state = _STATE_TABLE$state$ty[2];\n\n\n      if (prevAction !== NONE && prev !== -1) {\n        actions[prev] = prevAction;\n      }\n\n      actions[i] = curAction;\n      prev = i;\n    }\n\n    // Apply the chosen features to their respective glyphs\n    for (var index = 0; index < glyphs.length; index++) {\n      var feature = void 0;\n      var glyph = glyphs[index];\n      if (feature = actions[index]) {\n        glyph.features[feature] = true;\n      }\n    }\n  };\n\n  return ArabicShaper;\n}(DefaultShaper);\n\nfunction getShapingClass(codePoint) {\n  var res = trie.get(codePoint);\n  if (res) {\n    return res - 1;\n  }\n\n  var category = unicode.getCategory(codePoint);\n  if (category === 'Mn' || category === 'Me' || category === 'Cf') {\n    return ShapingClasses.Transparent;\n  }\n\n  return ShapingClasses.Non_Joining;\n}\n\nvar GlyphIterator = function () {\n  function GlyphIterator(glyphs, options) {\n    _classCallCheck(this, GlyphIterator);\n\n    this.glyphs = glyphs;\n    this.reset(options);\n  }\n\n  GlyphIterator.prototype.reset = function reset() {\n    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n    var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n\n    this.options = options;\n    this.flags = options.flags || {};\n    this.markAttachmentType = options.markAttachmentType || 0;\n    this.index = index;\n  };\n\n  GlyphIterator.prototype.shouldIgnore = function shouldIgnore(glyph) {\n    return this.flags.ignoreMarks && glyph.isMark || this.flags.ignoreBaseGlyphs && glyph.isBase || this.flags.ignoreLigatures && glyph.isLigature || this.markAttachmentType && glyph.isMark && glyph.markAttachmentType !== this.markAttachmentType;\n  };\n\n  GlyphIterator.prototype.move = function move(dir) {\n    this.index += dir;\n    while (0 <= this.index && this.index < this.glyphs.length && this.shouldIgnore(this.glyphs[this.index])) {\n      this.index += dir;\n    }\n\n    if (0 > this.index || this.index >= this.glyphs.length) {\n      return null;\n    }\n\n    return this.glyphs[this.index];\n  };\n\n  GlyphIterator.prototype.next = function next() {\n    return this.move(+1);\n  };\n\n  GlyphIterator.prototype.prev = function prev() {\n    return this.move(-1);\n  };\n\n  GlyphIterator.prototype.peek = function peek() {\n    var count = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;\n\n    var idx = this.index;\n    var res = this.increment(count);\n    this.index = idx;\n    return res;\n  };\n\n  GlyphIterator.prototype.peekIndex = function peekIndex() {\n    var count = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;\n\n    var idx = this.index;\n    this.increment(count);\n    var res = this.index;\n    this.index = idx;\n    return res;\n  };\n\n  GlyphIterator.prototype.increment = function increment() {\n    var count = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;\n\n    var dir = count < 0 ? -1 : 1;\n    count = Math.abs(count);\n    while (count--) {\n      this.move(dir);\n    }\n\n    return this.glyphs[this.index];\n  };\n\n  _createClass(GlyphIterator, [{\n    key: \"cur\",\n    get: function get() {\n      return this.glyphs[this.index] || null;\n    }\n  }]);\n\n  return GlyphIterator;\n}();\n\nvar DEFAULT_SCRIPTS = ['DFLT', 'dflt', 'latn'];\n\nvar OTProcessor = function () {\n  function OTProcessor(font, table) {\n    _classCallCheck(this, OTProcessor);\n\n    this.font = font;\n    this.table = table;\n\n    this.script = null;\n    this.scriptTag = null;\n\n    this.language = null;\n    this.languageTag = null;\n\n    this.features = {};\n    this.lookups = {};\n\n    // Setup variation substitutions\n    this.variationsIndex = font._variationProcessor ? this.findVariationsIndex(font._variationProcessor.normalizedCoords) : -1;\n\n    // initialize to default script + language\n    this.selectScript();\n\n    // current context (set by applyFeatures)\n    this.glyphs = [];\n    this.positions = []; // only used by GPOS\n    this.ligatureID = 1;\n    this.currentFeature = null;\n  }\n\n  OTProcessor.prototype.findScript = function findScript(script) {\n    if (this.table.scriptList == null) {\n      return null;\n    }\n\n    if (!Array.isArray(script)) {\n      script = [script];\n    }\n\n    for (var _iterator = script, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var s = _ref;\n\n      for (var _iterator2 = this.table.scriptList, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n        var _ref2;\n\n        if (_isArray2) {\n          if (_i2 >= _iterator2.length) break;\n          _ref2 = _iterator2[_i2++];\n        } else {\n          _i2 = _iterator2.next();\n          if (_i2.done) break;\n          _ref2 = _i2.value;\n        }\n\n        var entry = _ref2;\n\n        if (entry.tag === s) {\n          return entry;\n        }\n      }\n    }\n\n    return null;\n  };\n\n  OTProcessor.prototype.selectScript = function selectScript(script, language, direction$$) {\n    var changed = false;\n    var entry = void 0;\n    if (!this.script || script !== this.scriptTag) {\n      entry = this.findScript(script);\n      if (!entry) {\n        entry = this.findScript(DEFAULT_SCRIPTS);\n      }\n\n      if (!entry) {\n        return this.scriptTag;\n      }\n\n      this.scriptTag = entry.tag;\n      this.script = entry.script;\n      this.language = null;\n      this.languageTag = null;\n      changed = true;\n    }\n\n    if (!direction$$ || direction$$ !== this.direction) {\n      this.direction = direction$$ || direction(script);\n    }\n\n    if (language && language.length < 4) {\n      language += ' '.repeat(4 - language.length);\n    }\n\n    if (!language || language !== this.languageTag) {\n      this.language = null;\n\n      for (var _iterator3 = this.script.langSysRecords, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n        var _ref3;\n\n        if (_isArray3) {\n          if (_i3 >= _iterator3.length) break;\n          _ref3 = _iterator3[_i3++];\n        } else {\n          _i3 = _iterator3.next();\n          if (_i3.done) break;\n          _ref3 = _i3.value;\n        }\n\n        var lang = _ref3;\n\n        if (lang.tag === language) {\n          this.language = lang.langSys;\n          this.languageTag = lang.tag;\n          break;\n        }\n      }\n\n      if (!this.language) {\n        this.language = this.script.defaultLangSys;\n        this.languageTag = null;\n      }\n\n      changed = true;\n    }\n\n    // Build a feature lookup table\n    if (changed) {\n      this.features = {};\n      if (this.language) {\n        for (var _iterator4 = this.language.featureIndexes, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _getIterator(_iterator4);;) {\n          var _ref4;\n\n          if (_isArray4) {\n            if (_i4 >= _iterator4.length) break;\n            _ref4 = _iterator4[_i4++];\n          } else {\n            _i4 = _iterator4.next();\n            if (_i4.done) break;\n            _ref4 = _i4.value;\n          }\n\n          var featureIndex = _ref4;\n\n          var record = this.table.featureList[featureIndex];\n          var substituteFeature = this.substituteFeatureForVariations(featureIndex);\n          this.features[record.tag] = substituteFeature || record.feature;\n        }\n      }\n    }\n\n    return this.scriptTag;\n  };\n\n  OTProcessor.prototype.lookupsForFeatures = function lookupsForFeatures() {\n    var userFeatures = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];\n    var exclude = arguments[1];\n\n    var lookups = [];\n    for (var _iterator5 = userFeatures, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _getIterator(_iterator5);;) {\n      var _ref5;\n\n      if (_isArray5) {\n        if (_i5 >= _iterator5.length) break;\n        _ref5 = _iterator5[_i5++];\n      } else {\n        _i5 = _iterator5.next();\n        if (_i5.done) break;\n        _ref5 = _i5.value;\n      }\n\n      var tag = _ref5;\n\n      var feature = this.features[tag];\n      if (!feature) {\n        continue;\n      }\n\n      for (var _iterator6 = feature.lookupListIndexes, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _getIterator(_iterator6);;) {\n        var _ref6;\n\n        if (_isArray6) {\n          if (_i6 >= _iterator6.length) break;\n          _ref6 = _iterator6[_i6++];\n        } else {\n          _i6 = _iterator6.next();\n          if (_i6.done) break;\n          _ref6 = _i6.value;\n        }\n\n        var lookupIndex = _ref6;\n\n        if (exclude && exclude.indexOf(lookupIndex) !== -1) {\n          continue;\n        }\n\n        lookups.push({\n          feature: tag,\n          index: lookupIndex,\n          lookup: this.table.lookupList.get(lookupIndex)\n        });\n      }\n    }\n\n    lookups.sort(function (a, b) {\n      return a.index - b.index;\n    });\n    return lookups;\n  };\n\n  OTProcessor.prototype.substituteFeatureForVariations = function substituteFeatureForVariations(featureIndex) {\n    if (this.variationsIndex === -1) {\n      return null;\n    }\n\n    var record = this.table.featureVariations.featureVariationRecords[this.variationsIndex];\n    var substitutions = record.featureTableSubstitution.substitutions;\n    for (var _iterator7 = substitutions, _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _getIterator(_iterator7);;) {\n      var _ref7;\n\n      if (_isArray7) {\n        if (_i7 >= _iterator7.length) break;\n        _ref7 = _iterator7[_i7++];\n      } else {\n        _i7 = _iterator7.next();\n        if (_i7.done) break;\n        _ref7 = _i7.value;\n      }\n\n      var substitution = _ref7;\n\n      if (substitution.featureIndex === featureIndex) {\n        return substitution.alternateFeatureTable;\n      }\n    }\n\n    return null;\n  };\n\n  OTProcessor.prototype.findVariationsIndex = function findVariationsIndex(coords) {\n    var variations = this.table.featureVariations;\n    if (!variations) {\n      return -1;\n    }\n\n    var records = variations.featureVariationRecords;\n    for (var i = 0; i < records.length; i++) {\n      var conditions = records[i].conditionSet.conditionTable;\n      if (this.variationConditionsMatch(conditions, coords)) {\n        return i;\n      }\n    }\n\n    return -1;\n  };\n\n  OTProcessor.prototype.variationConditionsMatch = function variationConditionsMatch(conditions, coords) {\n    return conditions.every(function (condition) {\n      var coord = condition.axisIndex < coords.length ? coords[condition.axisIndex] : 0;\n      return condition.filterRangeMinValue <= coord && coord <= condition.filterRangeMaxValue;\n    });\n  };\n\n  OTProcessor.prototype.applyFeatures = function applyFeatures(userFeatures, glyphs, advances) {\n    var lookups = this.lookupsForFeatures(userFeatures);\n    this.applyLookups(lookups, glyphs, advances);\n  };\n\n  OTProcessor.prototype.applyLookups = function applyLookups(lookups, glyphs, positions) {\n    this.glyphs = glyphs;\n    this.positions = positions;\n    this.glyphIterator = new GlyphIterator(glyphs);\n\n    for (var _iterator8 = lookups, _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _getIterator(_iterator8);;) {\n      var _ref8;\n\n      if (_isArray8) {\n        if (_i8 >= _iterator8.length) break;\n        _ref8 = _iterator8[_i8++];\n      } else {\n        _i8 = _iterator8.next();\n        if (_i8.done) break;\n        _ref8 = _i8.value;\n      }\n\n      var _ref9 = _ref8,\n          feature = _ref9.feature,\n          lookup = _ref9.lookup;\n\n      this.currentFeature = feature;\n      this.glyphIterator.reset(lookup.flags);\n\n      while (this.glyphIterator.index < glyphs.length) {\n        if (!(feature in this.glyphIterator.cur.features)) {\n          this.glyphIterator.next();\n          continue;\n        }\n\n        for (var _iterator9 = lookup.subTables, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _getIterator(_iterator9);;) {\n          var _ref10;\n\n          if (_isArray9) {\n            if (_i9 >= _iterator9.length) break;\n            _ref10 = _iterator9[_i9++];\n          } else {\n            _i9 = _iterator9.next();\n            if (_i9.done) break;\n            _ref10 = _i9.value;\n          }\n\n          var table = _ref10;\n\n          var res = this.applyLookup(lookup.lookupType, table);\n          if (res) {\n            break;\n          }\n        }\n\n        this.glyphIterator.next();\n      }\n    }\n  };\n\n  OTProcessor.prototype.applyLookup = function applyLookup(lookup, table) {\n    throw new Error(\"applyLookup must be implemented by subclasses\");\n  };\n\n  OTProcessor.prototype.applyLookupList = function applyLookupList(lookupRecords) {\n    var options = this.glyphIterator.options;\n    var glyphIndex = this.glyphIterator.index;\n\n    for (var _iterator10 = lookupRecords, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _getIterator(_iterator10);;) {\n      var _ref11;\n\n      if (_isArray10) {\n        if (_i10 >= _iterator10.length) break;\n        _ref11 = _iterator10[_i10++];\n      } else {\n        _i10 = _iterator10.next();\n        if (_i10.done) break;\n        _ref11 = _i10.value;\n      }\n\n      var lookupRecord = _ref11;\n\n      // Reset flags and find glyph index for this lookup record\n      this.glyphIterator.reset(options, glyphIndex);\n      this.glyphIterator.increment(lookupRecord.sequenceIndex);\n\n      // Get the lookup and setup flags for subtables\n      var lookup = this.table.lookupList.get(lookupRecord.lookupListIndex);\n      this.glyphIterator.reset(lookup.flags, this.glyphIterator.index);\n\n      // Apply lookup subtables until one matches\n      for (var _iterator11 = lookup.subTables, _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _getIterator(_iterator11);;) {\n        var _ref12;\n\n        if (_isArray11) {\n          if (_i11 >= _iterator11.length) break;\n          _ref12 = _iterator11[_i11++];\n        } else {\n          _i11 = _iterator11.next();\n          if (_i11.done) break;\n          _ref12 = _i11.value;\n        }\n\n        var table = _ref12;\n\n        if (this.applyLookup(lookup.lookupType, table)) {\n          break;\n        }\n      }\n    }\n\n    this.glyphIterator.reset(options, glyphIndex);\n    return true;\n  };\n\n  OTProcessor.prototype.coverageIndex = function coverageIndex(coverage, glyph) {\n    if (glyph == null) {\n      glyph = this.glyphIterator.cur.id;\n    }\n\n    switch (coverage.version) {\n      case 1:\n        return coverage.glyphs.indexOf(glyph);\n\n      case 2:\n        for (var _iterator12 = coverage.rangeRecords, _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _getIterator(_iterator12);;) {\n          var _ref13;\n\n          if (_isArray12) {\n            if (_i12 >= _iterator12.length) break;\n            _ref13 = _iterator12[_i12++];\n          } else {\n            _i12 = _iterator12.next();\n            if (_i12.done) break;\n            _ref13 = _i12.value;\n          }\n\n          var range = _ref13;\n\n          if (range.start <= glyph && glyph <= range.end) {\n            return range.startCoverageIndex + glyph - range.start;\n          }\n        }\n\n        break;\n    }\n\n    return -1;\n  };\n\n  OTProcessor.prototype.match = function match(sequenceIndex, sequence, fn, matched) {\n    var pos = this.glyphIterator.index;\n    var glyph = this.glyphIterator.increment(sequenceIndex);\n    var idx = 0;\n\n    while (idx < sequence.length && glyph && fn(sequence[idx], glyph)) {\n      if (matched) {\n        matched.push(this.glyphIterator.index);\n      }\n\n      idx++;\n      glyph = this.glyphIterator.next();\n    }\n\n    this.glyphIterator.index = pos;\n    if (idx < sequence.length) {\n      return false;\n    }\n\n    return matched || true;\n  };\n\n  OTProcessor.prototype.sequenceMatches = function sequenceMatches(sequenceIndex, sequence) {\n    return this.match(sequenceIndex, sequence, function (component, glyph) {\n      return component === glyph.id;\n    });\n  };\n\n  OTProcessor.prototype.sequenceMatchIndices = function sequenceMatchIndices(sequenceIndex, sequence) {\n    var _this = this;\n\n    return this.match(sequenceIndex, sequence, function (component, glyph) {\n      // If the current feature doesn't apply to this glyph,\n      if (!(_this.currentFeature in glyph.features)) {\n        return false;\n      }\n\n      return component === glyph.id;\n    }, []);\n  };\n\n  OTProcessor.prototype.coverageSequenceMatches = function coverageSequenceMatches(sequenceIndex, sequence) {\n    var _this2 = this;\n\n    return this.match(sequenceIndex, sequence, function (coverage, glyph) {\n      return _this2.coverageIndex(coverage, glyph.id) >= 0;\n    });\n  };\n\n  OTProcessor.prototype.getClassID = function getClassID(glyph, classDef) {\n    switch (classDef.version) {\n      case 1:\n        // Class array\n        var i = glyph - classDef.startGlyph;\n        if (i >= 0 && i < classDef.classValueArray.length) {\n          return classDef.classValueArray[i];\n        }\n\n        break;\n\n      case 2:\n        for (var _iterator13 = classDef.classRangeRecord, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _getIterator(_iterator13);;) {\n          var _ref14;\n\n          if (_isArray13) {\n            if (_i13 >= _iterator13.length) break;\n            _ref14 = _iterator13[_i13++];\n          } else {\n            _i13 = _iterator13.next();\n            if (_i13.done) break;\n            _ref14 = _i13.value;\n          }\n\n          var range = _ref14;\n\n          if (range.start <= glyph && glyph <= range.end) {\n            return range.class;\n          }\n        }\n\n        break;\n    }\n\n    return 0;\n  };\n\n  OTProcessor.prototype.classSequenceMatches = function classSequenceMatches(sequenceIndex, sequence, classDef) {\n    var _this3 = this;\n\n    return this.match(sequenceIndex, sequence, function (classID, glyph) {\n      return classID === _this3.getClassID(glyph.id, classDef);\n    });\n  };\n\n  OTProcessor.prototype.applyContext = function applyContext(table) {\n    switch (table.version) {\n      case 1:\n        var index = this.coverageIndex(table.coverage);\n        if (index === -1) {\n          return false;\n        }\n\n        var set = table.ruleSets[index];\n        for (var _iterator14 = set, _isArray14 = Array.isArray(_iterator14), _i14 = 0, _iterator14 = _isArray14 ? _iterator14 : _getIterator(_iterator14);;) {\n          var _ref15;\n\n          if (_isArray14) {\n            if (_i14 >= _iterator14.length) break;\n            _ref15 = _iterator14[_i14++];\n          } else {\n            _i14 = _iterator14.next();\n            if (_i14.done) break;\n            _ref15 = _i14.value;\n          }\n\n          var rule = _ref15;\n\n          if (this.sequenceMatches(1, rule.input)) {\n            return this.applyLookupList(rule.lookupRecords);\n          }\n        }\n\n        break;\n\n      case 2:\n        if (this.coverageIndex(table.coverage) === -1) {\n          return false;\n        }\n\n        index = this.getClassID(this.glyphIterator.cur.id, table.classDef);\n        if (index === -1) {\n          return false;\n        }\n\n        set = table.classSet[index];\n        for (var _iterator15 = set, _isArray15 = Array.isArray(_iterator15), _i15 = 0, _iterator15 = _isArray15 ? _iterator15 : _getIterator(_iterator15);;) {\n          var _ref16;\n\n          if (_isArray15) {\n            if (_i15 >= _iterator15.length) break;\n            _ref16 = _iterator15[_i15++];\n          } else {\n            _i15 = _iterator15.next();\n            if (_i15.done) break;\n            _ref16 = _i15.value;\n          }\n\n          var _rule = _ref16;\n\n          if (this.classSequenceMatches(1, _rule.classes, table.classDef)) {\n            return this.applyLookupList(_rule.lookupRecords);\n          }\n        }\n\n        break;\n\n      case 3:\n        if (this.coverageSequenceMatches(0, table.coverages)) {\n          return this.applyLookupList(table.lookupRecords);\n        }\n\n        break;\n    }\n\n    return false;\n  };\n\n  OTProcessor.prototype.applyChainingContext = function applyChainingContext(table) {\n    switch (table.version) {\n      case 1:\n        var index = this.coverageIndex(table.coverage);\n        if (index === -1) {\n          return false;\n        }\n\n        var set = table.chainRuleSets[index];\n        for (var _iterator16 = set, _isArray16 = Array.isArray(_iterator16), _i16 = 0, _iterator16 = _isArray16 ? _iterator16 : _getIterator(_iterator16);;) {\n          var _ref17;\n\n          if (_isArray16) {\n            if (_i16 >= _iterator16.length) break;\n            _ref17 = _iterator16[_i16++];\n          } else {\n            _i16 = _iterator16.next();\n            if (_i16.done) break;\n            _ref17 = _i16.value;\n          }\n\n          var rule = _ref17;\n\n          if (this.sequenceMatches(-rule.backtrack.length, rule.backtrack) && this.sequenceMatches(1, rule.input) && this.sequenceMatches(1 + rule.input.length, rule.lookahead)) {\n            return this.applyLookupList(rule.lookupRecords);\n          }\n        }\n\n        break;\n\n      case 2:\n        if (this.coverageIndex(table.coverage) === -1) {\n          return false;\n        }\n\n        index = this.getClassID(this.glyphIterator.cur.id, table.inputClassDef);\n        var rules = table.chainClassSet[index];\n        if (!rules) {\n          return false;\n        }\n\n        for (var _iterator17 = rules, _isArray17 = Array.isArray(_iterator17), _i17 = 0, _iterator17 = _isArray17 ? _iterator17 : _getIterator(_iterator17);;) {\n          var _ref18;\n\n          if (_isArray17) {\n            if (_i17 >= _iterator17.length) break;\n            _ref18 = _iterator17[_i17++];\n          } else {\n            _i17 = _iterator17.next();\n            if (_i17.done) break;\n            _ref18 = _i17.value;\n          }\n\n          var _rule2 = _ref18;\n\n          if (this.classSequenceMatches(-_rule2.backtrack.length, _rule2.backtrack, table.backtrackClassDef) && this.classSequenceMatches(1, _rule2.input, table.inputClassDef) && this.classSequenceMatches(1 + _rule2.input.length, _rule2.lookahead, table.lookaheadClassDef)) {\n            return this.applyLookupList(_rule2.lookupRecords);\n          }\n        }\n\n        break;\n\n      case 3:\n        if (this.coverageSequenceMatches(-table.backtrackGlyphCount, table.backtrackCoverage) && this.coverageSequenceMatches(0, table.inputCoverage) && this.coverageSequenceMatches(table.inputGlyphCount, table.lookaheadCoverage)) {\n          return this.applyLookupList(table.lookupRecords);\n        }\n\n        break;\n    }\n\n    return false;\n  };\n\n  return OTProcessor;\n}();\n\nvar GlyphInfo = function () {\n  function GlyphInfo(font, id) {\n    var codePoints = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];\n    var features = arguments[3];\n\n    _classCallCheck(this, GlyphInfo);\n\n    this._font = font;\n    this.codePoints = codePoints;\n    this.id = id;\n\n    this.features = {};\n    if (Array.isArray(features)) {\n      for (var i = 0; i < features.length; i++) {\n        var feature = features[i];\n        this.features[feature] = true;\n      }\n    } else if ((typeof features === 'undefined' ? 'undefined' : _typeof(features)) === 'object') {\n      _Object$assign(this.features, features);\n    }\n\n    this.ligatureID = null;\n    this.ligatureComponent = null;\n    this.isLigated = false;\n    this.cursiveAttachment = null;\n    this.markAttachment = null;\n    this.shaperInfo = null;\n    this.substituted = false;\n    this.isMultiplied = false;\n  }\n\n  GlyphInfo.prototype.copy = function copy() {\n    return new GlyphInfo(this._font, this.id, this.codePoints, this.features);\n  };\n\n  _createClass(GlyphInfo, [{\n    key: 'id',\n    get: function get() {\n      return this._id;\n    },\n    set: function set(id) {\n      this._id = id;\n      this.substituted = true;\n\n      var GDEF = this._font.GDEF;\n      if (GDEF && GDEF.glyphClassDef) {\n        // TODO: clean this up\n        var classID = OTProcessor.prototype.getClassID(id, GDEF.glyphClassDef);\n        this.isBase = classID === 1;\n        this.isLigature = classID === 2;\n        this.isMark = classID === 3;\n        this.markAttachmentType = GDEF.markAttachClassDef ? OTProcessor.prototype.getClassID(id, GDEF.markAttachClassDef) : 0;\n      } else {\n        this.isMark = this.codePoints.every(unicode.isMark);\n        this.isBase = !this.isMark;\n        this.isLigature = this.codePoints.length > 1;\n        this.markAttachmentType = 0;\n      }\n    }\n  }]);\n\n  return GlyphInfo;\n}();\n\nvar _class$5;\nvar _temp$1;\n/**\n * This is a shaper for the Hangul script, used by the Korean language.\n * It does the following:\n *   - decompose if unsupported by the font:\n *     <LV>   -> <L,V>\n *     <LVT>  -> <L,V,T>\n *     <LV,T> -> <L,V,T>\n *\n *   - compose if supported by the font:\n *     <L,V>   -> <LV>\n *     <L,V,T> -> <LVT>\n *     <LV,T>  -> <LVT>\n *\n *   - reorder tone marks (S is any valid syllable):\n *     <S, M> -> <M, S>\n *\n *   - apply ljmo, vjmo, and tjmo OpenType features to decomposed Jamo sequences.\n *\n * This logic is based on the following documents:\n *   - http://www.microsoft.com/typography/OpenTypeDev/hangul/intro.htm\n *   - http://ktug.org/~nomos/harfbuzz-hangul/hangulshaper.pdf\n */\nvar HangulShaper = (_temp$1 = _class$5 = function (_DefaultShaper) {\n  _inherits(HangulShaper, _DefaultShaper);\n\n  function HangulShaper() {\n    _classCallCheck(this, HangulShaper);\n\n    return _possibleConstructorReturn(this, _DefaultShaper.apply(this, arguments));\n  }\n\n  HangulShaper.planFeatures = function planFeatures(plan) {\n    plan.add(['ljmo', 'vjmo', 'tjmo'], false);\n  };\n\n  HangulShaper.assignFeatures = function assignFeatures(plan, glyphs) {\n    var state = 0;\n    var i = 0;\n    while (i < glyphs.length) {\n      var action = void 0;\n      var glyph = glyphs[i];\n      var code = glyph.codePoints[0];\n      var type = getType(code);\n\n      var _STATE_TABLE$state$ty = STATE_TABLE$1[state][type];\n      action = _STATE_TABLE$state$ty[0];\n      state = _STATE_TABLE$state$ty[1];\n\n\n      switch (action) {\n        case DECOMPOSE:\n          // Decompose the composed syllable if it is not supported by the font.\n          if (!plan.font.hasGlyphForCodePoint(code)) {\n            i = decompose(glyphs, i, plan.font);\n          }\n          break;\n\n        case COMPOSE:\n          // Found a decomposed syllable. Try to compose if supported by the font.\n          i = compose(glyphs, i, plan.font);\n          break;\n\n        case TONE_MARK:\n          // Got a valid syllable, followed by a tone mark. Move the tone mark to the beginning of the syllable.\n          reorderToneMark(glyphs, i, plan.font);\n          break;\n\n        case INVALID:\n          // Tone mark has no valid syllable to attach to, so insert a dotted circle\n          i = insertDottedCircle(glyphs, i, plan.font);\n          break;\n      }\n\n      i++;\n    }\n  };\n\n  return HangulShaper;\n}(DefaultShaper), _class$5.zeroMarkWidths = 'NONE', _temp$1);\nvar HANGUL_BASE = 0xac00;\nvar HANGUL_END = 0xd7a4;\nvar HANGUL_COUNT = HANGUL_END - HANGUL_BASE + 1;\nvar L_BASE = 0x1100; // lead\nvar V_BASE = 0x1161; // vowel\nvar T_BASE = 0x11a7; // trail\nvar L_COUNT = 19;\nvar V_COUNT = 21;\nvar T_COUNT = 28;\nvar L_END = L_BASE + L_COUNT - 1;\nvar V_END = V_BASE + V_COUNT - 1;\nvar T_END = T_BASE + T_COUNT - 1;\nvar DOTTED_CIRCLE = 0x25cc;\n\nvar isL = function isL(code) {\n  return 0x1100 <= code && code <= 0x115f || 0xa960 <= code && code <= 0xa97c;\n};\nvar isV = function isV(code) {\n  return 0x1160 <= code && code <= 0x11a7 || 0xd7b0 <= code && code <= 0xd7c6;\n};\nvar isT = function isT(code) {\n  return 0x11a8 <= code && code <= 0x11ff || 0xd7cb <= code && code <= 0xd7fb;\n};\nvar isTone = function isTone(code) {\n  return 0x302e <= code && code <= 0x302f;\n};\nvar isLVT = function isLVT(code) {\n  return HANGUL_BASE <= code && code <= HANGUL_END;\n};\nvar isLV = function isLV(code) {\n  return code - HANGUL_BASE < HANGUL_COUNT && (code - HANGUL_BASE) % T_COUNT === 0;\n};\nvar isCombiningL = function isCombiningL(code) {\n  return L_BASE <= code && code <= L_END;\n};\nvar isCombiningV = function isCombiningV(code) {\n  return V_BASE <= code && code <= V_END;\n};\nvar isCombiningT = function isCombiningT(code) {\n  return T_BASE + 1 && 1 <= code && code <= T_END;\n};\n\n// Character categories\nvar X = 0; // Other character\nvar L = 1; // Leading consonant\nvar V = 2; // Medial vowel\nvar T = 3; // Trailing consonant\nvar LV = 4; // Composed <LV> syllable\nvar LVT = 5; // Composed <LVT> syllable\nvar M = 6; // Tone mark\n\n// This function classifies a character using the above categories.\nfunction getType(code) {\n  if (isL(code)) {\n    return L;\n  }\n  if (isV(code)) {\n    return V;\n  }\n  if (isT(code)) {\n    return T;\n  }\n  if (isLV(code)) {\n    return LV;\n  }\n  if (isLVT(code)) {\n    return LVT;\n  }\n  if (isTone(code)) {\n    return M;\n  }\n  return X;\n}\n\n// State machine actions\nvar NO_ACTION = 0;\nvar DECOMPOSE = 1;\nvar COMPOSE = 2;\nvar TONE_MARK = 4;\nvar INVALID = 5;\n\n// Build a state machine that accepts valid syllables, and applies actions along the way.\n// The logic this is implementing is documented at the top of the file.\nvar STATE_TABLE$1 = [\n//       X                 L                 V                T                  LV                LVT               M\n// State 0: start state\n[[NO_ACTION, 0], [NO_ACTION, 1], [NO_ACTION, 0], [NO_ACTION, 0], [DECOMPOSE, 2], [DECOMPOSE, 3], [INVALID, 0]],\n\n// State 1: <L>\n[[NO_ACTION, 0], [NO_ACTION, 1], [COMPOSE, 2], [NO_ACTION, 0], [DECOMPOSE, 2], [DECOMPOSE, 3], [INVALID, 0]],\n\n// State 2: <L,V> or <LV>\n[[NO_ACTION, 0], [NO_ACTION, 1], [NO_ACTION, 0], [COMPOSE, 3], [DECOMPOSE, 2], [DECOMPOSE, 3], [TONE_MARK, 0]],\n\n// State 3: <L,V,T> or <LVT>\n[[NO_ACTION, 0], [NO_ACTION, 1], [NO_ACTION, 0], [NO_ACTION, 0], [DECOMPOSE, 2], [DECOMPOSE, 3], [TONE_MARK, 0]]];\n\nfunction getGlyph(font, code, features) {\n  return new GlyphInfo(font, font.glyphForCodePoint(code).id, [code], features);\n}\n\nfunction decompose(glyphs, i, font) {\n  var glyph = glyphs[i];\n  var code = glyph.codePoints[0];\n\n  var s = code - HANGUL_BASE;\n  var t = T_BASE + s % T_COUNT;\n  s = s / T_COUNT | 0;\n  var l = L_BASE + s / V_COUNT | 0;\n  var v = V_BASE + s % V_COUNT;\n\n  // Don't decompose if all of the components are not available\n  if (!font.hasGlyphForCodePoint(l) || !font.hasGlyphForCodePoint(v) || t !== T_BASE && !font.hasGlyphForCodePoint(t)) {\n    return i;\n  }\n\n  // Replace the current glyph with decomposed L, V, and T glyphs,\n  // and apply the proper OpenType features to each component.\n  var ljmo = getGlyph(font, l, glyph.features);\n  ljmo.features.ljmo = true;\n\n  var vjmo = getGlyph(font, v, glyph.features);\n  vjmo.features.vjmo = true;\n\n  var insert = [ljmo, vjmo];\n\n  if (t > T_BASE) {\n    var tjmo = getGlyph(font, t, glyph.features);\n    tjmo.features.tjmo = true;\n    insert.push(tjmo);\n  }\n\n  glyphs.splice.apply(glyphs, [i, 1].concat(insert));\n  return i + insert.length - 1;\n}\n\nfunction compose(glyphs, i, font) {\n  var glyph = glyphs[i];\n  var code = glyphs[i].codePoints[0];\n  var type = getType(code);\n\n  var prev = glyphs[i - 1].codePoints[0];\n  var prevType = getType(prev);\n\n  // Figure out what type of syllable we're dealing with\n  var lv = void 0,\n      ljmo = void 0,\n      vjmo = void 0,\n      tjmo = void 0;\n  if (prevType === LV && type === T) {\n    // <LV,T>\n    lv = prev;\n    tjmo = glyph;\n  } else {\n    if (type === V) {\n      // <L,V>\n      ljmo = glyphs[i - 1];\n      vjmo = glyph;\n    } else {\n      // <L,V,T>\n      ljmo = glyphs[i - 2];\n      vjmo = glyphs[i - 1];\n      tjmo = glyph;\n    }\n\n    var l = ljmo.codePoints[0];\n    var v = vjmo.codePoints[0];\n\n    // Make sure L and V are combining characters\n    if (isCombiningL(l) && isCombiningV(v)) {\n      lv = HANGUL_BASE + ((l - L_BASE) * V_COUNT + (v - V_BASE)) * T_COUNT;\n    }\n  }\n\n  var t = tjmo && tjmo.codePoints[0] || T_BASE;\n  if (lv != null && (t === T_BASE || isCombiningT(t))) {\n    var s = lv + (t - T_BASE);\n\n    // Replace with a composed glyph if supported by the font,\n    // otherwise apply the proper OpenType features to each component.\n    if (font.hasGlyphForCodePoint(s)) {\n      var del = prevType === V ? 3 : 2;\n      glyphs.splice(i - del + 1, del, getGlyph(font, s, glyph.features));\n      return i - del + 1;\n    }\n  }\n\n  // Didn't compose (either a non-combining component or unsupported by font).\n  if (ljmo) {\n    ljmo.features.ljmo = true;\n  }\n  if (vjmo) {\n    vjmo.features.vjmo = true;\n  }\n  if (tjmo) {\n    tjmo.features.tjmo = true;\n  }\n\n  if (prevType === LV) {\n    // Sequence was originally <L,V>, which got combined earlier.\n    // Either the T was non-combining, or the LVT glyph wasn't supported.\n    // Decompose the glyph again and apply OT features.\n    decompose(glyphs, i - 1, font);\n    return i + 1;\n  }\n\n  return i;\n}\n\nfunction getLength(code) {\n  switch (getType(code)) {\n    case LV:\n    case LVT:\n      return 1;\n    case V:\n      return 2;\n    case T:\n      return 3;\n  }\n}\n\nfunction reorderToneMark(glyphs, i, font) {\n  var glyph = glyphs[i];\n  var code = glyphs[i].codePoints[0];\n\n  // Move tone mark to the beginning of the previous syllable, unless it is zero width\n  if (font.glyphForCodePoint(code).advanceWidth === 0) {\n    return;\n  }\n\n  var prev = glyphs[i - 1].codePoints[0];\n  var len = getLength(prev);\n\n  glyphs.splice(i, 1);\n  return glyphs.splice(i - len, 0, glyph);\n}\n\nfunction insertDottedCircle(glyphs, i, font) {\n  var glyph = glyphs[i];\n  var code = glyphs[i].codePoints[0];\n\n  if (font.hasGlyphForCodePoint(DOTTED_CIRCLE)) {\n    var dottedCircle = getGlyph(font, DOTTED_CIRCLE, glyph.features);\n\n    // If the tone mark is zero width, insert the dotted circle before, otherwise after\n    var idx = font.glyphForCodePoint(code).advanceWidth === 0 ? i : i + 1;\n    glyphs.splice(idx, 0, dottedCircle);\n    i++;\n  }\n\n  return i;\n}\n\nvar stateTable = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 11, 12, 13, 14, 15, 16, 17], [0, 0, 0, 18, 19, 20, 21, 22, 23, 0, 24, 0, 0, 25, 26, 0, 0, 27, 0], [0, 0, 0, 28, 29, 30, 31, 32, 33, 0, 34, 0, 0, 35, 36, 0, 0, 37, 0], [0, 0, 0, 38, 5, 7, 7, 8, 9, 0, 10, 0, 0, 0, 13, 0, 0, 16, 0], [0, 39, 0, 0, 0, 40, 41, 0, 9, 0, 10, 0, 0, 0, 42, 0, 39, 0, 0], [0, 0, 0, 0, 43, 44, 44, 8, 9, 0, 0, 0, 0, 12, 43, 0, 0, 0, 0], [0, 0, 0, 0, 43, 44, 44, 8, 9, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0], [0, 0, 0, 45, 46, 47, 48, 49, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 50, 0, 0, 51, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 53, 54, 55, 56, 57, 58, 0, 59, 0, 0, 60, 61, 0, 0, 62, 0], [0, 0, 0, 4, 5, 7, 7, 8, 9, 0, 10, 0, 0, 0, 13, 0, 0, 16, 0], [0, 63, 64, 0, 0, 40, 41, 0, 9, 0, 10, 0, 0, 0, 42, 0, 63, 0, 0], [0, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 11, 12, 13, 0, 2, 16, 0], [0, 0, 0, 18, 65, 20, 21, 22, 23, 0, 24, 0, 0, 25, 26, 0, 0, 27, 0], [0, 0, 0, 0, 66, 67, 67, 8, 9, 0, 10, 0, 0, 0, 68, 0, 0, 0, 0], [0, 0, 0, 69, 0, 70, 70, 0, 71, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 73, 19, 74, 74, 22, 23, 0, 24, 0, 0, 0, 26, 0, 0, 27, 0], [0, 75, 0, 0, 0, 76, 77, 0, 23, 0, 24, 0, 0, 0, 78, 0, 75, 0, 0], [0, 0, 0, 0, 79, 80, 80, 22, 23, 0, 0, 0, 0, 25, 79, 0, 0, 0, 0], [0, 0, 0, 18, 19, 20, 74, 22, 23, 0, 24, 0, 0, 25, 26, 0, 0, 27, 0], [0, 0, 0, 81, 82, 83, 84, 85, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 86, 0, 0, 87, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 18, 19, 74, 74, 22, 23, 0, 24, 0, 0, 0, 26, 0, 0, 27, 0], [0, 89, 90, 0, 0, 76, 77, 0, 23, 0, 24, 0, 0, 0, 78, 0, 89, 0, 0], [0, 0, 0, 0, 91, 92, 92, 22, 23, 0, 24, 0, 0, 0, 93, 0, 0, 0, 0], [0, 0, 0, 94, 29, 95, 31, 32, 33, 0, 34, 0, 0, 0, 36, 0, 0, 37, 0], [0, 96, 0, 0, 0, 97, 98, 0, 33, 0, 34, 0, 0, 0, 99, 0, 96, 0, 0], [0, 0, 0, 0, 100, 101, 101, 32, 33, 0, 0, 0, 0, 35, 100, 0, 0, 0, 0], [0, 0, 0, 0, 100, 101, 101, 32, 33, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0], [0, 0, 0, 102, 103, 104, 105, 106, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 107, 0, 0, 108, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 28, 29, 95, 31, 32, 33, 0, 34, 0, 0, 0, 36, 0, 0, 37, 0], [0, 110, 111, 0, 0, 97, 98, 0, 33, 0, 34, 0, 0, 0, 99, 0, 110, 0, 0], [0, 0, 0, 0, 112, 113, 113, 32, 33, 0, 34, 0, 0, 0, 114, 0, 0, 0, 0], [0, 0, 0, 0, 5, 7, 7, 8, 9, 0, 10, 0, 0, 0, 13, 0, 0, 16, 0], [0, 0, 0, 115, 116, 117, 118, 8, 9, 0, 10, 0, 0, 119, 120, 0, 0, 16, 0], [0, 0, 0, 0, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 39, 0, 122, 0, 123, 123, 8, 9, 0, 10, 0, 0, 0, 42, 0, 39, 0, 0], [0, 124, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 0], [0, 39, 0, 0, 0, 121, 125, 0, 9, 0, 10, 0, 0, 0, 42, 0, 39, 0, 0], [0, 0, 0, 0, 0, 126, 126, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 46, 47, 48, 49, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 47, 47, 49, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 127, 127, 49, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 128, 127, 127, 49, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 129, 130, 131, 132, 133, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 135, 54, 56, 56, 57, 58, 0, 59, 0, 0, 0, 61, 0, 0, 62, 0], [0, 136, 0, 0, 0, 137, 138, 0, 58, 0, 59, 0, 0, 0, 139, 0, 136, 0, 0], [0, 0, 0, 0, 140, 141, 141, 57, 58, 0, 0, 0, 0, 60, 140, 0, 0, 0, 0], [0, 0, 0, 0, 140, 141, 141, 57, 58, 0, 0, 0, 0, 0, 140, 0, 0, 0, 0], [0, 0, 0, 142, 143, 144, 145, 146, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 147, 0, 0, 148, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 149, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 53, 54, 56, 56, 57, 58, 0, 59, 0, 0, 0, 61, 0, 0, 62, 0], [0, 150, 151, 0, 0, 137, 138, 0, 58, 0, 59, 0, 0, 0, 139, 0, 150, 0, 0], [0, 0, 0, 0, 152, 153, 153, 57, 58, 0, 59, 0, 0, 0, 154, 0, 0, 0, 0], [0, 0, 0, 155, 116, 156, 157, 8, 9, 0, 10, 0, 0, 158, 120, 0, 0, 16, 0], [0, 0, 0, 0, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0], [0, 75, 3, 4, 5, 159, 160, 8, 161, 0, 162, 0, 11, 12, 163, 0, 75, 16, 0], [0, 0, 0, 0, 0, 40, 164, 0, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 165, 44, 44, 8, 9, 0, 0, 0, 0, 0, 165, 0, 0, 0, 0], [0, 124, 64, 0, 0, 40, 164, 0, 9, 0, 10, 0, 0, 0, 42, 0, 124, 0, 0], [0, 0, 0, 0, 0, 70, 70, 0, 71, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 166, 0, 0, 167, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 19, 74, 74, 22, 23, 0, 24, 0, 0, 0, 26, 0, 0, 27, 0], [0, 0, 0, 0, 79, 80, 80, 22, 23, 0, 0, 0, 0, 0, 79, 0, 0, 0, 0], [0, 0, 0, 169, 170, 171, 172, 22, 23, 0, 24, 0, 0, 173, 174, 0, 0, 27, 0], [0, 0, 0, 0, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 75, 0, 176, 0, 177, 177, 22, 23, 0, 24, 0, 0, 0, 78, 0, 75, 0, 0], [0, 178, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 0, 0], [0, 75, 0, 0, 0, 175, 179, 0, 23, 0, 24, 0, 0, 0, 78, 0, 75, 0, 0], [0, 0, 0, 0, 0, 180, 180, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 82, 83, 84, 85, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 83, 83, 85, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 181, 181, 85, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 182, 181, 181, 85, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 183, 184, 185, 186, 187, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 188, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 189, 170, 190, 191, 22, 23, 0, 24, 0, 0, 192, 174, 0, 0, 27, 0], [0, 0, 0, 0, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 76, 193, 0, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 194, 80, 80, 22, 23, 0, 0, 0, 0, 0, 194, 0, 0, 0, 0], [0, 178, 90, 0, 0, 76, 193, 0, 23, 0, 24, 0, 0, 0, 78, 0, 178, 0, 0], [0, 0, 0, 0, 29, 95, 31, 32, 33, 0, 34, 0, 0, 0, 36, 0, 0, 37, 0], [0, 0, 0, 0, 100, 101, 101, 32, 33, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0], [0, 0, 0, 195, 196, 197, 198, 32, 33, 0, 34, 0, 0, 199, 200, 0, 0, 37, 0], [0, 0, 0, 0, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 96, 0, 202, 0, 203, 203, 32, 33, 0, 34, 0, 0, 0, 99, 0, 96, 0, 0], [0, 204, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 204, 0, 0], [0, 96, 0, 0, 0, 201, 205, 0, 33, 0, 34, 0, 0, 0, 99, 0, 96, 0, 0], [0, 0, 0, 0, 0, 206, 206, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 103, 104, 105, 106, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 104, 104, 106, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 207, 207, 106, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 208, 207, 207, 106, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 209, 210, 211, 212, 213, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 107, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 215, 196, 216, 217, 32, 33, 0, 34, 0, 0, 218, 200, 0, 0, 37, 0], [0, 0, 0, 0, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 97, 219, 0, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 220, 101, 101, 32, 33, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0], [0, 204, 111, 0, 0, 97, 219, 0, 33, 0, 34, 0, 0, 0, 99, 0, 204, 0, 0], [0, 0, 0, 221, 116, 222, 222, 8, 9, 0, 10, 0, 0, 0, 120, 0, 0, 16, 0], [0, 223, 0, 0, 0, 40, 224, 0, 9, 0, 10, 0, 0, 0, 42, 0, 223, 0, 0], [0, 0, 0, 0, 225, 44, 44, 8, 9, 0, 0, 0, 0, 119, 225, 0, 0, 0, 0], [0, 0, 0, 115, 116, 117, 222, 8, 9, 0, 10, 0, 0, 119, 120, 0, 0, 16, 0], [0, 0, 0, 115, 116, 222, 222, 8, 9, 0, 10, 0, 0, 0, 120, 0, 0, 16, 0], [0, 226, 64, 0, 0, 40, 224, 0, 9, 0, 10, 0, 0, 0, 42, 0, 226, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 39, 0, 0, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 39, 0, 0], [0, 0, 0, 0, 0, 44, 44, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 227, 0, 228, 229, 0, 9, 0, 10, 0, 0, 230, 0, 0, 0, 0, 0], [0, 39, 0, 122, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 39, 0, 0], [0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 231, 231, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 130, 131, 132, 133, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 131, 131, 133, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 233, 233, 133, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 234, 233, 233, 133, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 235, 236, 237, 238, 239, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 54, 56, 56, 57, 58, 0, 59, 0, 0, 0, 61, 0, 0, 62, 0], [0, 0, 0, 240, 241, 242, 243, 57, 58, 0, 59, 0, 0, 244, 245, 0, 0, 62, 0], [0, 0, 0, 0, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 136, 0, 247, 0, 248, 248, 57, 58, 0, 59, 0, 0, 0, 139, 0, 136, 0, 0], [0, 249, 151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 0, 0], [0, 136, 0, 0, 0, 246, 250, 0, 58, 0, 59, 0, 0, 0, 139, 0, 136, 0, 0], [0, 0, 0, 0, 0, 251, 251, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 143, 144, 145, 146, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 144, 144, 146, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 252, 252, 146, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 253, 252, 252, 146, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 254, 255, 256, 257, 258, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 147, 0, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 260, 241, 261, 262, 57, 58, 0, 59, 0, 0, 263, 245, 0, 0, 62, 0], [0, 0, 0, 0, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 137, 264, 0, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 265, 141, 141, 57, 58, 0, 0, 0, 0, 0, 265, 0, 0, 0, 0], [0, 249, 151, 0, 0, 137, 264, 0, 58, 0, 59, 0, 0, 0, 139, 0, 249, 0, 0], [0, 0, 0, 221, 116, 222, 222, 8, 9, 0, 10, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 225, 44, 44, 8, 9, 0, 0, 0, 0, 158, 225, 0, 0, 0, 0], [0, 0, 0, 155, 116, 156, 222, 8, 9, 0, 10, 0, 0, 158, 120, 0, 0, 16, 0], [0, 0, 0, 155, 116, 222, 222, 8, 9, 0, 10, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 43, 266, 266, 8, 161, 0, 24, 0, 0, 12, 267, 0, 0, 0, 0], [0, 75, 0, 176, 43, 268, 268, 269, 161, 0, 24, 0, 0, 0, 267, 0, 75, 0, 0], [0, 0, 0, 0, 0, 270, 0, 0, 271, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0], [0, 273, 274, 0, 0, 40, 41, 0, 9, 0, 10, 0, 0, 0, 42, 0, 273, 0, 0], [0, 0, 0, 40, 0, 123, 123, 8, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 121, 275, 0, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 166, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 276, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 277, 170, 278, 278, 22, 23, 0, 24, 0, 0, 0, 174, 0, 0, 27, 0], [0, 279, 0, 0, 0, 76, 280, 0, 23, 0, 24, 0, 0, 0, 78, 0, 279, 0, 0], [0, 0, 0, 0, 281, 80, 80, 22, 23, 0, 0, 0, 0, 173, 281, 0, 0, 0, 0], [0, 0, 0, 169, 170, 171, 278, 22, 23, 0, 24, 0, 0, 173, 174, 0, 0, 27, 0], [0, 0, 0, 169, 170, 278, 278, 22, 23, 0, 24, 0, 0, 0, 174, 0, 0, 27, 0], [0, 282, 90, 0, 0, 76, 280, 0, 23, 0, 24, 0, 0, 0, 78, 0, 282, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 75, 0, 0, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 75, 0, 0], [0, 0, 0, 0, 0, 80, 80, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 283, 0, 284, 285, 0, 23, 0, 24, 0, 0, 286, 0, 0, 0, 0, 0], [0, 75, 0, 176, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 75, 0, 0], [0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 287, 287, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 184, 185, 186, 187, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 185, 185, 187, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 289, 289, 187, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 290, 289, 289, 187, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 291, 292, 293, 294, 295, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 277, 170, 278, 278, 22, 23, 0, 24, 0, 0, 0, 174, 0, 0, 27, 0], [0, 0, 0, 0, 281, 80, 80, 22, 23, 0, 0, 0, 0, 192, 281, 0, 0, 0, 0], [0, 0, 0, 189, 170, 190, 278, 22, 23, 0, 24, 0, 0, 192, 174, 0, 0, 27, 0], [0, 0, 0, 189, 170, 278, 278, 22, 23, 0, 24, 0, 0, 0, 174, 0, 0, 27, 0], [0, 0, 0, 76, 0, 177, 177, 22, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 175, 296, 0, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 297, 196, 298, 298, 32, 33, 0, 34, 0, 0, 0, 200, 0, 0, 37, 0], [0, 299, 0, 0, 0, 97, 300, 0, 33, 0, 34, 0, 0, 0, 99, 0, 299, 0, 0], [0, 0, 0, 0, 301, 101, 101, 32, 33, 0, 0, 0, 0, 199, 301, 0, 0, 0, 0], [0, 0, 0, 195, 196, 197, 298, 32, 33, 0, 34, 0, 0, 199, 200, 0, 0, 37, 0], [0, 0, 0, 195, 196, 298, 298, 32, 33, 0, 34, 0, 0, 0, 200, 0, 0, 37, 0], [0, 302, 111, 0, 0, 97, 300, 0, 33, 0, 34, 0, 0, 0, 99, 0, 302, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 96, 0, 0, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 96, 0, 0], [0, 0, 0, 0, 0, 101, 101, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 303, 0, 304, 305, 0, 33, 0, 34, 0, 0, 306, 0, 0, 0, 0, 0], [0, 96, 0, 202, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 96, 0, 0], [0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 307, 307, 106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 210, 211, 212, 213, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 211, 211, 213, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 309, 309, 213, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 310, 309, 309, 213, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 311, 312, 313, 314, 315, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 297, 196, 298, 298, 32, 33, 0, 34, 0, 0, 0, 200, 0, 0, 37, 0], [0, 0, 0, 0, 301, 101, 101, 32, 33, 0, 0, 0, 0, 218, 301, 0, 0, 0, 0], [0, 0, 0, 215, 196, 216, 298, 32, 33, 0, 34, 0, 0, 218, 200, 0, 0, 37, 0], [0, 0, 0, 215, 196, 298, 298, 32, 33, 0, 34, 0, 0, 0, 200, 0, 0, 37, 0], [0, 0, 0, 97, 0, 203, 203, 32, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 201, 316, 0, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 116, 222, 222, 8, 9, 0, 10, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 225, 44, 44, 8, 9, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0], [0, 0, 0, 317, 318, 319, 320, 8, 9, 0, 10, 0, 0, 321, 322, 0, 0, 16, 0], [0, 223, 0, 323, 0, 123, 123, 8, 9, 0, 10, 0, 0, 0, 42, 0, 223, 0, 0], [0, 223, 0, 0, 0, 121, 324, 0, 9, 0, 10, 0, 0, 0, 42, 0, 223, 0, 0], [0, 0, 0, 325, 318, 326, 327, 8, 9, 0, 10, 0, 0, 328, 322, 0, 0, 16, 0], [0, 0, 0, 64, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 230, 0, 0, 0, 0, 0], [0, 0, 0, 227, 0, 228, 121, 0, 9, 0, 10, 0, 0, 230, 0, 0, 0, 0, 0], [0, 0, 0, 227, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0], [0, 0, 0, 0, 0, 329, 329, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 236, 237, 238, 239, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 237, 237, 239, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 331, 331, 239, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 332, 331, 331, 239, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 333, 40, 121, 334, 0, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 335, 241, 336, 336, 57, 58, 0, 59, 0, 0, 0, 245, 0, 0, 62, 0], [0, 337, 0, 0, 0, 137, 338, 0, 58, 0, 59, 0, 0, 0, 139, 0, 337, 0, 0], [0, 0, 0, 0, 339, 141, 141, 57, 58, 0, 0, 0, 0, 244, 339, 0, 0, 0, 0], [0, 0, 0, 240, 241, 242, 336, 57, 58, 0, 59, 0, 0, 244, 245, 0, 0, 62, 0], [0, 0, 0, 240, 241, 336, 336, 57, 58, 0, 59, 0, 0, 0, 245, 0, 0, 62, 0], [0, 340, 151, 0, 0, 137, 338, 0, 58, 0, 59, 0, 0, 0, 139, 0, 340, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 136, 0, 0, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 136, 0, 0], [0, 0, 0, 0, 0, 141, 141, 57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 341, 0, 342, 343, 0, 58, 0, 59, 0, 0, 344, 0, 0, 0, 0, 0], [0, 136, 0, 247, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 136, 0, 0], [0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 345, 345, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 255, 256, 257, 258, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 256, 256, 258, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 347, 347, 258, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 348, 347, 347, 258, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 349, 350, 351, 352, 353, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 335, 241, 336, 336, 57, 58, 0, 59, 0, 0, 0, 245, 0, 0, 62, 0], [0, 0, 0, 0, 339, 141, 141, 57, 58, 0, 0, 0, 0, 263, 339, 0, 0, 0, 0], [0, 0, 0, 260, 241, 261, 336, 57, 58, 0, 59, 0, 0, 263, 245, 0, 0, 62, 0], [0, 0, 0, 260, 241, 336, 336, 57, 58, 0, 59, 0, 0, 0, 245, 0, 0, 62, 0], [0, 0, 0, 137, 0, 248, 248, 57, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 246, 354, 0, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 126, 126, 8, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 355, 90, 0, 0, 121, 125, 0, 9, 0, 10, 0, 0, 0, 42, 0, 355, 0, 0], [0, 0, 0, 0, 0, 356, 356, 269, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 357, 358, 359, 360, 361, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 270, 0, 0, 0, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 363, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 364, 116, 365, 366, 8, 161, 0, 162, 0, 0, 367, 120, 0, 0, 16, 0], [0, 0, 0, 0, 0, 368, 368, 0, 161, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 40, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 170, 278, 278, 22, 23, 0, 24, 0, 0, 0, 174, 0, 0, 27, 0], [0, 0, 0, 0, 281, 80, 80, 22, 23, 0, 0, 0, 0, 0, 281, 0, 0, 0, 0], [0, 0, 0, 369, 370, 371, 372, 22, 23, 0, 24, 0, 0, 373, 374, 0, 0, 27, 0], [0, 279, 0, 375, 0, 177, 177, 22, 23, 0, 24, 0, 0, 0, 78, 0, 279, 0, 0], [0, 279, 0, 0, 0, 175, 376, 0, 23, 0, 24, 0, 0, 0, 78, 0, 279, 0, 0], [0, 0, 0, 377, 370, 378, 379, 22, 23, 0, 24, 0, 0, 380, 374, 0, 0, 27, 0], [0, 0, 0, 90, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 286, 0, 0, 0, 0, 0], [0, 0, 0, 283, 0, 284, 175, 0, 23, 0, 24, 0, 0, 286, 0, 0, 0, 0, 0], [0, 0, 0, 283, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 0, 0], [0, 0, 0, 0, 0, 381, 381, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 382, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 292, 293, 294, 295, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 293, 293, 295, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 0, 383, 383, 295, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 384, 383, 383, 295, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 385, 76, 175, 386, 0, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 76, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 196, 298, 298, 32, 33, 0, 34, 0, 0, 0, 200, 0, 0, 37, 0], [0, 0, 0, 0, 301, 101, 101, 32, 33, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0], [0, 0, 0, 387, 388, 389, 390, 32, 33, 0, 34, 0, 0, 391, 392, 0, 0, 37, 0], [0, 299, 0, 393, 0, 203, 203, 32, 33, 0, 34, 0, 0, 0, 99, 0, 299, 0, 0], [0, 299, 0, 0, 0, 201, 394, 0, 33, 0, 34, 0, 0, 0, 99, 0, 299, 0, 0], [0, 0, 0, 395, 388, 396, 397, 32, 33, 0, 34, 0, 0, 398, 392, 0, 0, 37, 0], [0, 0, 0, 111, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 306, 0, 0, 0, 0, 0], [0, 0, 0, 303, 0, 304, 201, 0, 33, 0, 34, 0, 0, 306, 0, 0, 0, 0, 0], [0, 0, 0, 303, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, 0], [0, 0, 0, 0, 0, 399, 399, 213, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 312, 313, 314, 315, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 313, 313, 315, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 0, 401, 401, 315, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 402, 401, 401, 315, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 403, 97, 201, 404, 0, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 97, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 405, 318, 406, 406, 8, 9, 0, 10, 0, 0, 0, 322, 0, 0, 16, 0], [0, 407, 0, 0, 0, 40, 408, 0, 9, 0, 10, 0, 0, 0, 42, 0, 407, 0, 0], [0, 0, 0, 0, 409, 44, 44, 8, 9, 0, 0, 0, 0, 321, 409, 0, 0, 0, 0], [0, 0, 0, 317, 318, 319, 406, 8, 9, 0, 10, 0, 0, 321, 322, 0, 0, 16, 0], [0, 0, 0, 317, 318, 406, 406, 8, 9, 0, 10, 0, 0, 0, 322, 0, 0, 16, 0], [0, 410, 64, 0, 0, 40, 408, 0, 9, 0, 10, 0, 0, 0, 42, 0, 410, 0, 0], [0, 223, 0, 0, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 223, 0, 0], [0, 223, 0, 323, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 223, 0, 0], [0, 0, 0, 405, 318, 406, 406, 8, 9, 0, 10, 0, 0, 0, 322, 0, 0, 16, 0], [0, 0, 0, 0, 409, 44, 44, 8, 9, 0, 0, 0, 0, 328, 409, 0, 0, 0, 0], [0, 0, 0, 325, 318, 326, 406, 8, 9, 0, 10, 0, 0, 328, 322, 0, 0, 16, 0], [0, 0, 0, 325, 318, 406, 406, 8, 9, 0, 10, 0, 0, 0, 322, 0, 0, 16, 0], [0, 0, 0, 0, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0], [0, 0, 0, 0, 0, 411, 411, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 412, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 40, 121, 334, 0, 9, 0, 10, 0, 0, 0, 42, 0, 0, 0, 0], [0, 0, 0, 0, 413, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 241, 336, 336, 57, 58, 0, 59, 0, 0, 0, 245, 0, 0, 62, 0], [0, 0, 0, 0, 339, 141, 141, 57, 58, 0, 0, 0, 0, 0, 339, 0, 0, 0, 0], [0, 0, 0, 414, 415, 416, 417, 57, 58, 0, 59, 0, 0, 418, 419, 0, 0, 62, 0], [0, 337, 0, 420, 0, 248, 248, 57, 58, 0, 59, 0, 0, 0, 139, 0, 337, 0, 0], [0, 337, 0, 0, 0, 246, 421, 0, 58, 0, 59, 0, 0, 0, 139, 0, 337, 0, 0], [0, 0, 0, 422, 415, 423, 424, 57, 58, 0, 59, 0, 0, 425, 419, 0, 0, 62, 0], [0, 0, 0, 151, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0], [0, 0, 0, 341, 0, 342, 246, 0, 58, 0, 59, 0, 0, 344, 0, 0, 0, 0, 0], [0, 0, 0, 341, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143, 0, 0], [0, 0, 0, 0, 0, 426, 426, 258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 350, 351, 352, 353, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 351, 351, 353, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 0, 428, 428, 353, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 429, 428, 428, 353, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 430, 137, 246, 431, 0, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 137, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 432, 116, 433, 434, 8, 161, 0, 162, 0, 0, 435, 120, 0, 0, 16, 0], [0, 0, 0, 0, 0, 180, 180, 269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 358, 359, 360, 361, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 359, 359, 361, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 436, 436, 361, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 437, 436, 436, 361, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 438, 439, 440, 441, 442, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 443, 274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 443, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 444, 116, 445, 445, 8, 161, 0, 162, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 225, 44, 44, 8, 161, 0, 0, 0, 0, 367, 225, 0, 0, 0, 0], [0, 0, 0, 364, 116, 365, 445, 8, 161, 0, 162, 0, 0, 367, 120, 0, 0, 16, 0], [0, 0, 0, 364, 116, 445, 445, 8, 161, 0, 162, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 0, 0, 0, 0, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 446, 370, 447, 447, 22, 23, 0, 24, 0, 0, 0, 374, 0, 0, 27, 0], [0, 448, 0, 0, 0, 76, 449, 0, 23, 0, 24, 0, 0, 0, 78, 0, 448, 0, 0], [0, 0, 0, 0, 450, 80, 80, 22, 23, 0, 0, 0, 0, 373, 450, 0, 0, 0, 0], [0, 0, 0, 369, 370, 371, 447, 22, 23, 0, 24, 0, 0, 373, 374, 0, 0, 27, 0], [0, 0, 0, 369, 370, 447, 447, 22, 23, 0, 24, 0, 0, 0, 374, 0, 0, 27, 0], [0, 451, 90, 0, 0, 76, 449, 0, 23, 0, 24, 0, 0, 0, 78, 0, 451, 0, 0], [0, 279, 0, 0, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 279, 0, 0], [0, 279, 0, 375, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 279, 0, 0], [0, 0, 0, 446, 370, 447, 447, 22, 23, 0, 24, 0, 0, 0, 374, 0, 0, 27, 0], [0, 0, 0, 0, 450, 80, 80, 22, 23, 0, 0, 0, 0, 380, 450, 0, 0, 0, 0], [0, 0, 0, 377, 370, 378, 447, 22, 23, 0, 24, 0, 0, 380, 374, 0, 0, 27, 0], [0, 0, 0, 377, 370, 447, 447, 22, 23, 0, 24, 0, 0, 0, 374, 0, 0, 27, 0], [0, 0, 0, 0, 0, 0, 0, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 184, 0, 0], [0, 0, 0, 0, 0, 452, 452, 295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 453, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 76, 175, 386, 0, 23, 0, 24, 0, 0, 0, 78, 0, 0, 0, 0], [0, 0, 0, 0, 454, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 455, 388, 456, 456, 32, 33, 0, 34, 0, 0, 0, 392, 0, 0, 37, 0], [0, 457, 0, 0, 0, 97, 458, 0, 33, 0, 34, 0, 0, 0, 99, 0, 457, 0, 0], [0, 0, 0, 0, 459, 101, 101, 32, 33, 0, 0, 0, 0, 391, 459, 0, 0, 0, 0], [0, 0, 0, 387, 388, 389, 456, 32, 33, 0, 34, 0, 0, 391, 392, 0, 0, 37, 0], [0, 0, 0, 387, 388, 456, 456, 32, 33, 0, 34, 0, 0, 0, 392, 0, 0, 37, 0], [0, 460, 111, 0, 0, 97, 458, 0, 33, 0, 34, 0, 0, 0, 99, 0, 460, 0, 0], [0, 299, 0, 0, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 299, 0, 0], [0, 299, 0, 393, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 299, 0, 0], [0, 0, 0, 455, 388, 456, 456, 32, 33, 0, 34, 0, 0, 0, 392, 0, 0, 37, 0], [0, 0, 0, 0, 459, 101, 101, 32, 33, 0, 0, 0, 0, 398, 459, 0, 0, 0, 0], [0, 0, 0, 395, 388, 396, 456, 32, 33, 0, 34, 0, 0, 398, 392, 0, 0, 37, 0], [0, 0, 0, 395, 388, 456, 456, 32, 33, 0, 34, 0, 0, 0, 392, 0, 0, 37, 0], [0, 0, 0, 0, 0, 0, 0, 213, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 210, 0, 0], [0, 0, 0, 0, 0, 461, 461, 315, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 462, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 97, 201, 404, 0, 33, 0, 34, 0, 0, 0, 99, 0, 0, 0, 0], [0, 0, 0, 0, 463, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 318, 406, 406, 8, 9, 0, 10, 0, 0, 0, 322, 0, 0, 16, 0], [0, 0, 0, 0, 409, 44, 44, 8, 9, 0, 0, 0, 0, 0, 409, 0, 0, 0, 0], [0, 0, 0, 464, 465, 466, 467, 8, 9, 0, 10, 0, 0, 468, 469, 0, 0, 16, 0], [0, 407, 0, 470, 0, 123, 123, 8, 9, 0, 10, 0, 0, 0, 42, 0, 407, 0, 0], [0, 407, 0, 0, 0, 121, 471, 0, 9, 0, 10, 0, 0, 0, 42, 0, 407, 0, 0], [0, 0, 0, 472, 465, 473, 474, 8, 9, 0, 10, 0, 0, 475, 469, 0, 0, 16, 0], [0, 0, 0, 0, 0, 0, 0, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 236, 0, 0], [0, 0, 0, 0, 0, 0, 476, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 477, 415, 478, 478, 57, 58, 0, 59, 0, 0, 0, 419, 0, 0, 62, 0], [0, 479, 0, 0, 0, 137, 480, 0, 58, 0, 59, 0, 0, 0, 139, 0, 479, 0, 0], [0, 0, 0, 0, 481, 141, 141, 57, 58, 0, 0, 0, 0, 418, 481, 0, 0, 0, 0], [0, 0, 0, 414, 415, 416, 478, 57, 58, 0, 59, 0, 0, 418, 419, 0, 0, 62, 0], [0, 0, 0, 414, 415, 478, 478, 57, 58, 0, 59, 0, 0, 0, 419, 0, 0, 62, 0], [0, 482, 151, 0, 0, 137, 480, 0, 58, 0, 59, 0, 0, 0, 139, 0, 482, 0, 0], [0, 337, 0, 0, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 337, 0, 0], [0, 337, 0, 420, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 337, 0, 0], [0, 0, 0, 477, 415, 478, 478, 57, 58, 0, 59, 0, 0, 0, 419, 0, 0, 62, 0], [0, 0, 0, 0, 481, 141, 141, 57, 58, 0, 0, 0, 0, 425, 481, 0, 0, 0, 0], [0, 0, 0, 422, 415, 423, 478, 57, 58, 0, 59, 0, 0, 425, 419, 0, 0, 62, 0], [0, 0, 0, 422, 415, 478, 478, 57, 58, 0, 59, 0, 0, 0, 419, 0, 0, 62, 0], [0, 0, 0, 0, 0, 0, 0, 258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0], [0, 0, 0, 0, 0, 483, 483, 353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 484, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 137, 246, 431, 0, 58, 0, 59, 0, 0, 0, 139, 0, 0, 0, 0], [0, 0, 0, 0, 485, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 444, 116, 445, 445, 8, 161, 0, 162, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 225, 44, 44, 8, 161, 0, 0, 0, 0, 435, 225, 0, 0, 0, 0], [0, 0, 0, 432, 116, 433, 445, 8, 161, 0, 162, 0, 0, 435, 120, 0, 0, 16, 0], [0, 0, 0, 432, 116, 445, 445, 8, 161, 0, 162, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 0, 486, 486, 361, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 439, 440, 441, 442, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 440, 440, 442, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 488, 488, 442, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 489, 488, 488, 442, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 490, 491, 492, 493, 494, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 495, 0, 496, 497, 0, 161, 0, 162, 0, 0, 498, 0, 0, 0, 0, 0], [0, 0, 0, 0, 116, 445, 445, 8, 161, 0, 162, 0, 0, 0, 120, 0, 0, 16, 0], [0, 0, 0, 0, 225, 44, 44, 8, 161, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0], [0, 0, 0, 0, 370, 447, 447, 22, 23, 0, 24, 0, 0, 0, 374, 0, 0, 27, 0], [0, 0, 0, 0, 450, 80, 80, 22, 23, 0, 0, 0, 0, 0, 450, 0, 0, 0, 0], [0, 0, 0, 499, 500, 501, 502, 22, 23, 0, 24, 0, 0, 503, 504, 0, 0, 27, 0], [0, 448, 0, 505, 0, 177, 177, 22, 23, 0, 24, 0, 0, 0, 78, 0, 448, 0, 0], [0, 448, 0, 0, 0, 175, 506, 0, 23, 0, 24, 0, 0, 0, 78, 0, 448, 0, 0], [0, 0, 0, 507, 500, 508, 509, 22, 23, 0, 24, 0, 0, 510, 504, 0, 0, 27, 0], [0, 0, 0, 0, 0, 0, 0, 295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 292, 0, 0], [0, 0, 0, 0, 0, 0, 511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 388, 456, 456, 32, 33, 0, 34, 0, 0, 0, 392, 0, 0, 37, 0], [0, 0, 0, 0, 459, 101, 101, 32, 33, 0, 0, 0, 0, 0, 459, 0, 0, 0, 0], [0, 0, 0, 512, 513, 514, 515, 32, 33, 0, 34, 0, 0, 516, 517, 0, 0, 37, 0], [0, 457, 0, 518, 0, 203, 203, 32, 33, 0, 34, 0, 0, 0, 99, 0, 457, 0, 0], [0, 457, 0, 0, 0, 201, 519, 0, 33, 0, 34, 0, 0, 0, 99, 0, 457, 0, 0], [0, 0, 0, 520, 513, 521, 522, 32, 33, 0, 34, 0, 0, 523, 517, 0, 0, 37, 0], [0, 0, 0, 0, 0, 0, 0, 315, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 312, 0, 0], [0, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 525, 465, 526, 526, 8, 9, 0, 10, 0, 0, 0, 469, 0, 0, 16, 0], [0, 527, 0, 0, 0, 40, 528, 0, 9, 0, 10, 0, 0, 0, 42, 0, 527, 0, 0], [0, 0, 0, 0, 529, 44, 44, 8, 9, 0, 0, 0, 0, 468, 529, 0, 0, 0, 0], [0, 0, 0, 464, 465, 466, 526, 8, 9, 0, 10, 0, 0, 468, 469, 0, 0, 16, 0], [0, 0, 0, 464, 465, 526, 526, 8, 9, 0, 10, 0, 0, 0, 469, 0, 0, 16, 0], [0, 530, 64, 0, 0, 40, 528, 0, 9, 0, 10, 0, 0, 0, 42, 0, 530, 0, 0], [0, 407, 0, 0, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 407, 0, 0], [0, 407, 0, 470, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 407, 0, 0], [0, 0, 0, 525, 465, 526, 526, 8, 9, 0, 10, 0, 0, 0, 469, 0, 0, 16, 0], [0, 0, 0, 0, 529, 44, 44, 8, 9, 0, 0, 0, 0, 475, 529, 0, 0, 0, 0], [0, 0, 0, 472, 465, 473, 526, 8, 9, 0, 10, 0, 0, 475, 469, 0, 0, 16, 0], [0, 0, 0, 472, 465, 526, 526, 8, 9, 0, 10, 0, 0, 0, 469, 0, 0, 16, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0], [0, 0, 0, 0, 415, 478, 478, 57, 58, 0, 59, 0, 0, 0, 419, 0, 0, 62, 0], [0, 0, 0, 0, 481, 141, 141, 57, 58, 0, 0, 0, 0, 0, 481, 0, 0, 0, 0], [0, 0, 0, 531, 532, 533, 534, 57, 58, 0, 59, 0, 0, 535, 536, 0, 0, 62, 0], [0, 479, 0, 537, 0, 248, 248, 57, 58, 0, 59, 0, 0, 0, 139, 0, 479, 0, 0], [0, 479, 0, 0, 0, 246, 538, 0, 58, 0, 59, 0, 0, 0, 139, 0, 479, 0, 0], [0, 0, 0, 539, 532, 540, 541, 57, 58, 0, 59, 0, 0, 542, 536, 0, 0, 62, 0], [0, 0, 0, 0, 0, 0, 0, 353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 350, 0, 0], [0, 0, 0, 0, 0, 0, 543, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 361, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 358, 0, 0], [0, 0, 0, 0, 0, 544, 544, 442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 545, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 491, 492, 493, 494, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 492, 492, 494, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 546, 546, 494, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 547, 546, 546, 494, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 548, 549, 368, 550, 0, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 274, 0, 368, 368, 0, 161, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 161, 0, 0, 0, 0, 498, 0, 0, 0, 0, 0], [0, 0, 0, 495, 0, 496, 368, 0, 161, 0, 162, 0, 0, 498, 0, 0, 0, 0, 0], [0, 0, 0, 495, 0, 368, 368, 0, 161, 0, 162, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 551, 500, 552, 552, 22, 23, 0, 24, 0, 0, 0, 504, 0, 0, 27, 0], [0, 553, 0, 0, 0, 76, 554, 0, 23, 0, 24, 0, 0, 0, 78, 0, 553, 0, 0], [0, 0, 0, 0, 555, 80, 80, 22, 23, 0, 0, 0, 0, 503, 555, 0, 0, 0, 0], [0, 0, 0, 499, 500, 501, 552, 22, 23, 0, 24, 0, 0, 503, 504, 0, 0, 27, 0], [0, 0, 0, 499, 500, 552, 552, 22, 23, 0, 24, 0, 0, 0, 504, 0, 0, 27, 0], [0, 556, 90, 0, 0, 76, 554, 0, 23, 0, 24, 0, 0, 0, 78, 0, 556, 0, 0], [0, 448, 0, 0, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 448, 0, 0], [0, 448, 0, 505, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 448, 0, 0], [0, 0, 0, 551, 500, 552, 552, 22, 23, 0, 24, 0, 0, 0, 504, 0, 0, 27, 0], [0, 0, 0, 0, 555, 80, 80, 22, 23, 0, 0, 0, 0, 510, 555, 0, 0, 0, 0], [0, 0, 0, 507, 500, 508, 552, 22, 23, 0, 24, 0, 0, 510, 504, 0, 0, 27, 0], [0, 0, 0, 507, 500, 552, 552, 22, 23, 0, 24, 0, 0, 0, 504, 0, 0, 27, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 0, 0], [0, 0, 0, 557, 513, 558, 558, 32, 33, 0, 34, 0, 0, 0, 517, 0, 0, 37, 0], [0, 559, 0, 0, 0, 97, 560, 0, 33, 0, 34, 0, 0, 0, 99, 0, 559, 0, 0], [0, 0, 0, 0, 561, 101, 101, 32, 33, 0, 0, 0, 0, 516, 561, 0, 0, 0, 0], [0, 0, 0, 512, 513, 514, 558, 32, 33, 0, 34, 0, 0, 516, 517, 0, 0, 37, 0], [0, 0, 0, 512, 513, 558, 558, 32, 33, 0, 34, 0, 0, 0, 517, 0, 0, 37, 0], [0, 562, 111, 0, 0, 97, 560, 0, 33, 0, 34, 0, 0, 0, 99, 0, 562, 0, 0], [0, 457, 0, 0, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 457, 0, 0], [0, 457, 0, 518, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 457, 0, 0], [0, 0, 0, 557, 513, 558, 558, 32, 33, 0, 34, 0, 0, 0, 517, 0, 0, 37, 0], [0, 0, 0, 0, 561, 101, 101, 32, 33, 0, 0, 0, 0, 523, 561, 0, 0, 0, 0], [0, 0, 0, 520, 513, 521, 558, 32, 33, 0, 34, 0, 0, 523, 517, 0, 0, 37, 0], [0, 0, 0, 520, 513, 558, 558, 32, 33, 0, 34, 0, 0, 0, 517, 0, 0, 37, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 0, 0], [0, 0, 0, 0, 465, 526, 526, 8, 9, 0, 10, 0, 0, 0, 469, 0, 0, 16, 0], [0, 0, 0, 0, 529, 44, 44, 8, 9, 0, 0, 0, 0, 0, 529, 0, 0, 0, 0], [0, 0, 0, 563, 66, 564, 565, 8, 9, 0, 10, 0, 0, 566, 68, 0, 0, 16, 0], [0, 527, 0, 567, 0, 123, 123, 8, 9, 0, 10, 0, 0, 0, 42, 0, 527, 0, 0], [0, 527, 0, 0, 0, 121, 568, 0, 9, 0, 10, 0, 0, 0, 42, 0, 527, 0, 0], [0, 0, 0, 569, 66, 570, 571, 8, 9, 0, 10, 0, 0, 572, 68, 0, 0, 16, 0], [0, 0, 0, 573, 532, 574, 574, 57, 58, 0, 59, 0, 0, 0, 536, 0, 0, 62, 0], [0, 575, 0, 0, 0, 137, 576, 0, 58, 0, 59, 0, 0, 0, 139, 0, 575, 0, 0], [0, 0, 0, 0, 577, 141, 141, 57, 58, 0, 0, 0, 0, 535, 577, 0, 0, 0, 0], [0, 0, 0, 531, 532, 533, 574, 57, 58, 0, 59, 0, 0, 535, 536, 0, 0, 62, 0], [0, 0, 0, 531, 532, 574, 574, 57, 58, 0, 59, 0, 0, 0, 536, 0, 0, 62, 0], [0, 578, 151, 0, 0, 137, 576, 0, 58, 0, 59, 0, 0, 0, 139, 0, 578, 0, 0], [0, 479, 0, 0, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 479, 0, 0], [0, 479, 0, 537, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 479, 0, 0], [0, 0, 0, 573, 532, 574, 574, 57, 58, 0, 59, 0, 0, 0, 536, 0, 0, 62, 0], [0, 0, 0, 0, 577, 141, 141, 57, 58, 0, 0, 0, 0, 542, 577, 0, 0, 0, 0], [0, 0, 0, 539, 532, 540, 574, 57, 58, 0, 59, 0, 0, 542, 536, 0, 0, 62, 0], [0, 0, 0, 539, 532, 574, 574, 57, 58, 0, 59, 0, 0, 0, 536, 0, 0, 62, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 137, 0, 0], [0, 0, 0, 0, 0, 0, 0, 442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 439, 0, 0], [0, 0, 0, 0, 0, 579, 579, 494, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 549, 368, 550, 0, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 0, 368, 368, 0, 161, 0, 162, 0, 0, 0, 362, 0, 0, 0, 0], [0, 0, 0, 0, 581, 0, 0, 0, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 500, 552, 552, 22, 23, 0, 24, 0, 0, 0, 504, 0, 0, 27, 0], [0, 0, 0, 0, 555, 80, 80, 22, 23, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0], [0, 0, 0, 582, 91, 583, 584, 22, 23, 0, 24, 0, 0, 585, 93, 0, 0, 27, 0], [0, 553, 0, 586, 0, 177, 177, 22, 23, 0, 24, 0, 0, 0, 78, 0, 553, 0, 0], [0, 553, 0, 0, 0, 175, 587, 0, 23, 0, 24, 0, 0, 0, 78, 0, 553, 0, 0], [0, 0, 0, 588, 91, 589, 590, 22, 23, 0, 24, 0, 0, 591, 93, 0, 0, 27, 0], [0, 0, 0, 0, 513, 558, 558, 32, 33, 0, 34, 0, 0, 0, 517, 0, 0, 37, 0], [0, 0, 0, 0, 561, 101, 101, 32, 33, 0, 0, 0, 0, 0, 561, 0, 0, 0, 0], [0, 0, 0, 592, 112, 593, 594, 32, 33, 0, 34, 0, 0, 595, 114, 0, 0, 37, 0], [0, 559, 0, 596, 0, 203, 203, 32, 33, 0, 34, 0, 0, 0, 99, 0, 559, 0, 0], [0, 559, 0, 0, 0, 201, 597, 0, 33, 0, 34, 0, 0, 0, 99, 0, 559, 0, 0], [0, 0, 0, 598, 112, 599, 600, 32, 33, 0, 34, 0, 0, 601, 114, 0, 0, 37, 0], [0, 0, 0, 602, 66, 67, 67, 8, 9, 0, 10, 0, 0, 0, 68, 0, 0, 16, 0], [0, 0, 0, 0, 165, 44, 44, 8, 9, 0, 0, 0, 0, 566, 165, 0, 0, 0, 0], [0, 0, 0, 563, 66, 564, 67, 8, 9, 0, 10, 0, 0, 566, 68, 0, 0, 16, 0], [0, 0, 0, 563, 66, 67, 67, 8, 9, 0, 10, 0, 0, 0, 68, 0, 0, 16, 0], [0, 527, 0, 0, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 527, 0, 0], [0, 527, 0, 567, 0, 121, 121, 0, 9, 0, 10, 0, 0, 0, 42, 0, 527, 0, 0], [0, 0, 0, 602, 66, 67, 67, 8, 9, 0, 10, 0, 0, 0, 68, 0, 0, 16, 0], [0, 0, 0, 0, 165, 44, 44, 8, 9, 0, 0, 0, 0, 572, 165, 0, 0, 0, 0], [0, 0, 0, 569, 66, 570, 67, 8, 9, 0, 10, 0, 0, 572, 68, 0, 0, 16, 0], [0, 0, 0, 569, 66, 67, 67, 8, 9, 0, 10, 0, 0, 0, 68, 0, 0, 16, 0], [0, 0, 0, 0, 532, 574, 574, 57, 58, 0, 59, 0, 0, 0, 536, 0, 0, 62, 0], [0, 0, 0, 0, 577, 141, 141, 57, 58, 0, 0, 0, 0, 0, 577, 0, 0, 0, 0], [0, 0, 0, 603, 152, 604, 605, 57, 58, 0, 59, 0, 0, 606, 154, 0, 0, 62, 0], [0, 575, 0, 607, 0, 248, 248, 57, 58, 0, 59, 0, 0, 0, 139, 0, 575, 0, 0], [0, 575, 0, 0, 0, 246, 608, 0, 58, 0, 59, 0, 0, 0, 139, 0, 575, 0, 0], [0, 0, 0, 609, 152, 610, 611, 57, 58, 0, 59, 0, 0, 612, 154, 0, 0, 62, 0], [0, 0, 0, 0, 0, 0, 0, 494, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 491, 0, 0], [0, 0, 0, 0, 0, 0, 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 614, 91, 92, 92, 22, 23, 0, 24, 0, 0, 0, 93, 0, 0, 27, 0], [0, 0, 0, 0, 194, 80, 80, 22, 23, 0, 0, 0, 0, 585, 194, 0, 0, 0, 0], [0, 0, 0, 582, 91, 583, 92, 22, 23, 0, 24, 0, 0, 585, 93, 0, 0, 27, 0], [0, 0, 0, 582, 91, 92, 92, 22, 23, 0, 24, 0, 0, 0, 93, 0, 0, 27, 0], [0, 553, 0, 0, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 553, 0, 0], [0, 553, 0, 586, 0, 175, 175, 0, 23, 0, 24, 0, 0, 0, 78, 0, 553, 0, 0], [0, 0, 0, 614, 91, 92, 92, 22, 23, 0, 24, 0, 0, 0, 93, 0, 0, 27, 0], [0, 0, 0, 0, 194, 80, 80, 22, 23, 0, 0, 0, 0, 591, 194, 0, 0, 0, 0], [0, 0, 0, 588, 91, 589, 92, 22, 23, 0, 24, 0, 0, 591, 93, 0, 0, 27, 0], [0, 0, 0, 588, 91, 92, 92, 22, 23, 0, 24, 0, 0, 0, 93, 0, 0, 27, 0], [0, 0, 0, 615, 112, 113, 113, 32, 33, 0, 34, 0, 0, 0, 114, 0, 0, 37, 0], [0, 0, 0, 0, 220, 101, 101, 32, 33, 0, 0, 0, 0, 595, 220, 0, 0, 0, 0], [0, 0, 0, 592, 112, 593, 113, 32, 33, 0, 34, 0, 0, 595, 114, 0, 0, 37, 0], [0, 0, 0, 592, 112, 113, 113, 32, 33, 0, 34, 0, 0, 0, 114, 0, 0, 37, 0], [0, 559, 0, 0, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 559, 0, 0], [0, 559, 0, 596, 0, 201, 201, 0, 33, 0, 34, 0, 0, 0, 99, 0, 559, 0, 0], [0, 0, 0, 615, 112, 113, 113, 32, 33, 0, 34, 0, 0, 0, 114, 0, 0, 37, 0], [0, 0, 0, 0, 220, 101, 101, 32, 33, 0, 0, 0, 0, 601, 220, 0, 0, 0, 0], [0, 0, 0, 598, 112, 599, 113, 32, 33, 0, 34, 0, 0, 601, 114, 0, 0, 37, 0], [0, 0, 0, 598, 112, 113, 113, 32, 33, 0, 34, 0, 0, 0, 114, 0, 0, 37, 0], [0, 0, 0, 0, 66, 67, 67, 8, 9, 0, 10, 0, 0, 0, 68, 0, 0, 16, 0], [0, 0, 0, 616, 152, 153, 153, 57, 58, 0, 59, 0, 0, 0, 154, 0, 0, 62, 0], [0, 0, 0, 0, 265, 141, 141, 57, 58, 0, 0, 0, 0, 606, 265, 0, 0, 0, 0], [0, 0, 0, 603, 152, 604, 153, 57, 58, 0, 59, 0, 0, 606, 154, 0, 0, 62, 0], [0, 0, 0, 603, 152, 153, 153, 57, 58, 0, 59, 0, 0, 0, 154, 0, 0, 62, 0], [0, 575, 0, 0, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 575, 0, 0], [0, 575, 0, 607, 0, 246, 246, 0, 58, 0, 59, 0, 0, 0, 139, 0, 575, 0, 0], [0, 0, 0, 616, 152, 153, 153, 57, 58, 0, 59, 0, 0, 0, 154, 0, 0, 62, 0], [0, 0, 0, 0, 265, 141, 141, 57, 58, 0, 0, 0, 0, 612, 265, 0, 0, 0, 0], [0, 0, 0, 609, 152, 610, 153, 57, 58, 0, 59, 0, 0, 612, 154, 0, 0, 62, 0], [0, 0, 0, 609, 152, 153, 153, 57, 58, 0, 59, 0, 0, 0, 154, 0, 0, 62, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 549, 0, 0], [0, 0, 0, 0, 91, 92, 92, 22, 23, 0, 24, 0, 0, 0, 93, 0, 0, 27, 0], [0, 0, 0, 0, 112, 113, 113, 32, 33, 0, 34, 0, 0, 0, 114, 0, 0, 37, 0], [0, 0, 0, 0, 152, 153, 153, 57, 58, 0, 59, 0, 0, 0, 154, 0, 0, 62, 0]];\nvar accepting = [false, true, true, true, true, true, false, false, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, false, true, false, true, true, false, false, true, true, true, true, true, true, false, false, true, true, true, true, true, true, true, true, true, true, false, true, true, false, true, true, true, false, true, true, true, false, true, false, true, true, false, false, true, true, true, true, true, true, true, false, true, true, false, true, true, true, false, true, false, true, true, false, false, true, true, true, true, true, true, true, false, true, true, true, false, true, true, true, false, true, false, true, true, false, false, false, true, true, false, false, true, true, true, true, true, true, false, true, false, true, true, false, false, true, true, true, true, true, true, true, false, true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, false, true, false, true, true, false, false, false, true, true, false, false, true, true, true, false, true, true, true, true, true, true, false, true, true, true, false, true, false, true, true, false, false, false, true, true, false, false, true, true, true, false, true, true, true, true, true, false, true, true, true, true, true, false, true, true, false, false, false, false, true, true, false, false, true, true, true, false, true, true, true, false, true, false, true, true, false, false, false, true, true, false, false, true, true, true, false, true, true, true, true, false, true, false, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, false, true, true, false, false, false, false, true, true, false, false, true, true, true, false, true, true, true, true, true, false, true, true, false, false, false, false, true, true, false, false, true, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false, false, false, true, false, true, false, true, true, true, true, true, false, true, true, false, false, false, false, true, true, false, false, true, true, true, false, true, true, false, false, true, false, true, true, false, true, true, false, true, true, false, true, true, true, true, true, true, false, true, true, false, false, false, false, true, false, true, true, false, true, true, true, true, true, true, false, true, true, false, false, false, false, true, false, true, false, true, true, true, true, false, false, false, true, true, false, true, true, true, true, true, true, false, true, true, false, false, false, false, true, false, true, false, true, true, false, false, true, true, false, false, true, true, true, false, true, false, true, true, true, true, false, false, false, true, false, true, true, true, true, false, false, false, true, true, false, true, true, true, true, true, true, false, true, true, false, true, false, true, true, true, true, false, false, false, false, false, false, false, true, true, false, false, true, true, false, true, true, true, true, false, true, true, true, true, true, true, false, true, true, false, true, true, false, true, true, true, true, true, true, false, true, true, false, true, false, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false, false, false, false, true, true, false, true, false, true, true, true, true, true, false, true, true, true, true, true, false, true, true, true, true, true, false, true, true, true, false, true, true, true, true, false, false, false, true, false, true, true, true, true, true, false, true, true, true, false, true, true, true, true, true, false, true, true, true, true, false, true, true, true, true, true, false, true, true, false, true, true, true];\nvar tags = [[], [\"broken_cluster\"], [\"consonant_syllable\"], [\"vowel_syllable\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"standalone_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"consonant_syllable\"], [\"broken_cluster\"], [\"symbol_cluster\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"symbol_cluster\"], [], [\"symbol_cluster\"], [\"symbol_cluster\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"symbol_cluster\"], [\"symbol_cluster\"], [\"symbol_cluster\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [\"broken_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"broken_cluster\"], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"broken_cluster\"], [\"symbol_cluster\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [], [], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [], [], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [], [], [\"broken_cluster\"], [], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [], [], [], [\"consonant_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [], [], [], [\"vowel_syllable\"], [], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [], [], [\"standalone_cluster\"], [], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [], [], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [], [], [], [], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [], [], [], [\"consonant_syllable\", \"broken_cluster\"], [\"consonant_syllable\", \"broken_cluster\"], [], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [], [], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"consonant_syllable\"], [], [\"consonant_syllable\"], [\"consonant_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"vowel_syllable\"], [], [\"vowel_syllable\"], [\"vowel_syllable\"], [\"broken_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"standalone_cluster\"], [\"standalone_cluster\"], [], [\"consonant_syllable\"], [\"vowel_syllable\"], [\"standalone_cluster\"]];\nvar indicMachine = {\n\tstateTable: stateTable,\n\taccepting: accepting,\n\ttags: tags\n};\n\nvar categories = [\"O\", \"IND\", \"S\", \"GB\", \"B\", \"FM\", \"CGJ\", \"VMAbv\", \"VMPst\", \"VAbv\", \"VPst\", \"CMBlw\", \"VPre\", \"VBlw\", \"H\", \"VMBlw\", \"CMAbv\", \"MBlw\", \"CS\", \"R\", \"SUB\", \"MPst\", \"MPre\", \"FAbv\", \"FPst\", \"FBlw\", \"SMAbv\", \"SMBlw\", \"VMPre\", \"ZWNJ\", \"ZWJ\", \"WJ\", \"VS\", \"N\", \"HN\", \"MAbv\"];\nvar decompositions$1 = { \"2507\": [2503, 2494], \"2508\": [2503, 2519], \"2888\": [2887, 2902], \"2891\": [2887, 2878], \"2892\": [2887, 2903], \"3018\": [3014, 3006], \"3019\": [3015, 3006], \"3020\": [3014, 3031], \"3144\": [3142, 3158], \"3264\": [3263, 3285], \"3271\": [3270, 3285], \"3272\": [3270, 3286], \"3274\": [3270, 3266], \"3275\": [3270, 3266, 3285], \"3402\": [3398, 3390], \"3403\": [3399, 3390], \"3404\": [3398, 3415], \"3546\": [3545, 3530], \"3548\": [3545, 3535], \"3549\": [3545, 3535, 3530], \"3550\": [3545, 3551], \"3635\": [3661, 3634], \"3763\": [3789, 3762], \"3955\": [3953, 3954], \"3957\": [3953, 3956], \"3958\": [4018, 3968], \"3959\": [4018, 3953, 3968], \"3960\": [4019, 3968], \"3961\": [4019, 3953, 3968], \"3969\": [3953, 3968], \"6971\": [6970, 6965], \"6973\": [6972, 6965], \"6976\": [6974, 6965], \"6977\": [6975, 6965], \"6979\": [6978, 6965], \"69934\": [69937, 69927], \"69935\": [69938, 69927], \"70475\": [70471, 70462], \"70476\": [70471, 70487], \"70843\": [70841, 70842], \"70844\": [70841, 70832], \"70846\": [70841, 70845], \"71098\": [71096, 71087], \"71099\": [71097, 71087] };\nvar stateTable$1 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2, 2, 3, 4, 4, 5, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 17, 18, 11, 19, 20, 21, 22, 0, 0, 23, 0, 0, 2, 0, 24, 0, 25], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 0, 0, 0, 0, 27, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 0, 0, 41, 35, 42, 43, 44, 45, 0, 0, 46, 0, 0, 0, 39, 0, 0, 47], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 0, 0, 12, 0, 14, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 9, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 16, 0, 0, 18, 11, 19, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 25], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 0, 11, 12, 0, 14, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 9, 0, 0, 12, 0, 14, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 0, 7, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 18, 11, 19, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 25], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 0, 11, 12, 0, 14, 0, 0, 0, 0, 0, 11, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 4, 4, 5, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 18, 11, 19, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 25], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 48, 11, 12, 13, 14, 48, 16, 0, 0, 18, 11, 19, 20, 21, 22, 0, 0, 23, 0, 0, 0, 49, 0, 0, 25], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 0, 11, 12, 0, 14, 0, 16, 0, 0, 0, 11, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 25], [0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 0, 11, 12, 0, 14, 0, 16, 0, 0, 0, 11, 0, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 0, 0, 36, 0, 38, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 0, 33, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 34, 35, 36, 37, 38, 0, 40, 0, 0, 41, 35, 42, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 47], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 0, 35, 36, 0, 38, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 0, 33, 0, 0, 36, 0, 38, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 0, 31, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 0, 0, 41, 35, 42, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 47], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 0, 35, 36, 0, 38, 0, 0, 0, 0, 0, 35, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 52, 35, 36, 37, 38, 52, 40, 0, 0, 41, 35, 42, 43, 44, 45, 0, 0, 46, 0, 0, 0, 53, 0, 0, 47], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 0, 35, 36, 0, 38, 0, 40, 0, 0, 0, 35, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 47], [0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 0, 35, 36, 0, 38, 0, 40, 0, 0, 0, 35, 0, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 48, 11, 12, 13, 14, 0, 16, 0, 0, 18, 11, 19, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 25], [0, 0, 0, 0, 0, 5, 0, 6, 7, 8, 9, 48, 11, 12, 13, 14, 48, 16, 0, 0, 18, 11, 19, 20, 21, 22, 0, 0, 23, 0, 0, 0, 0, 0, 0, 25], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 52, 35, 36, 37, 38, 0, 40, 0, 0, 41, 35, 42, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 47], [0, 0, 0, 0, 0, 29, 0, 30, 31, 32, 33, 52, 35, 36, 37, 38, 52, 40, 0, 0, 41, 35, 42, 43, 44, 45, 0, 0, 46, 0, 0, 0, 0, 0, 0, 47], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0]];\nvar accepting$1 = [false, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true];\nvar tags$1 = [[], [\"broken_cluster\"], [\"independent_cluster\"], [\"symbol_cluster\"], [\"standard_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"numeral_cluster\"], [\"broken_cluster\"], [\"independent_cluster\"], [\"symbol_cluster\"], [\"symbol_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"virama_terminated_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"broken_cluster\"], [\"broken_cluster\"], [\"numeral_cluster\"], [\"number_joiner_terminated_cluster\"], [\"standard_cluster\"], [\"standard_cluster\"], [\"numeral_cluster\"]];\nvar useData = {\n\tcategories: categories,\n\tdecompositions: decompositions$1,\n\tstateTable: stateTable$1,\n\taccepting: accepting$1,\n\ttags: tags$1\n};\n\n// Cateories used in the OpenType spec:\n// https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx\nvar CATEGORIES = {\n  X: 1 << 0,\n  C: 1 << 1,\n  V: 1 << 2,\n  N: 1 << 3,\n  H: 1 << 4,\n  ZWNJ: 1 << 5,\n  ZWJ: 1 << 6,\n  M: 1 << 7,\n  SM: 1 << 8,\n  VD: 1 << 9,\n  A: 1 << 10,\n  Placeholder: 1 << 11,\n  Dotted_Circle: 1 << 12,\n  RS: 1 << 13, // Register Shifter, used in Khmer OT spec.\n  Coeng: 1 << 14, // Khmer-style Virama.\n  Repha: 1 << 15, // Atomically-encoded logical or visual repha.\n  Ra: 1 << 16,\n  CM: 1 << 17, // Consonant-Medial.\n  Symbol: 1 << 18 // Avagraha, etc that take marks (SM,A,VD).\n};\n\n// Visual positions in a syllable from left to right.\nvar POSITIONS = {\n  Start: 1 << 0,\n\n  Ra_To_Become_Reph: 1 << 1,\n  Pre_M: 1 << 2,\n  Pre_C: 1 << 3,\n\n  Base_C: 1 << 4,\n  After_Main: 1 << 5,\n\n  Above_C: 1 << 6,\n\n  Before_Sub: 1 << 7,\n  Below_C: 1 << 8,\n  After_Sub: 1 << 9,\n\n  Before_Post: 1 << 10,\n  Post_C: 1 << 11,\n  After_Post: 1 << 12,\n\n  Final_C: 1 << 13,\n  SMVD: 1 << 14,\n\n  End: 1 << 15\n};\n\nvar CONSONANT_FLAGS = CATEGORIES.C | CATEGORIES.Ra | CATEGORIES.CM | CATEGORIES.V | CATEGORIES.Placeholder | CATEGORIES.Dotted_Circle;\nvar JOINER_FLAGS = CATEGORIES.ZWJ | CATEGORIES.ZWNJ;\nvar HALANT_OR_COENG_FLAGS = CATEGORIES.H | CATEGORIES.Coeng;\n\nvar INDIC_CONFIGS = {\n  Default: {\n    hasOldSpec: false,\n    virama: 0,\n    basePos: 'Last',\n    rephPos: POSITIONS.Before_Post,\n    rephMode: 'Implicit',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  Devanagari: {\n    hasOldSpec: true,\n    virama: 0x094D,\n    basePos: 'Last',\n    rephPos: POSITIONS.Before_Post,\n    rephMode: 'Implicit',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  Bengali: {\n    hasOldSpec: true,\n    virama: 0x09CD,\n    basePos: 'Last',\n    rephPos: POSITIONS.After_Sub,\n    rephMode: 'Implicit',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  Gurmukhi: {\n    hasOldSpec: true,\n    virama: 0x0A4D,\n    basePos: 'Last',\n    rephPos: POSITIONS.Before_Sub,\n    rephMode: 'Implicit',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  Gujarati: {\n    hasOldSpec: true,\n    virama: 0x0ACD,\n    basePos: 'Last',\n    rephPos: POSITIONS.Before_Post,\n    rephMode: 'Implicit',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  Oriya: {\n    hasOldSpec: true,\n    virama: 0x0B4D,\n    basePos: 'Last',\n    rephPos: POSITIONS.After_Main,\n    rephMode: 'Implicit',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  Tamil: {\n    hasOldSpec: true,\n    virama: 0x0BCD,\n    basePos: 'Last',\n    rephPos: POSITIONS.After_Post,\n    rephMode: 'Implicit',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  Telugu: {\n    hasOldSpec: true,\n    virama: 0x0C4D,\n    basePos: 'Last',\n    rephPos: POSITIONS.After_Post,\n    rephMode: 'Explicit',\n    blwfMode: 'Post_Only'\n  },\n\n  Kannada: {\n    hasOldSpec: true,\n    virama: 0x0CCD,\n    basePos: 'Last',\n    rephPos: POSITIONS.After_Post,\n    rephMode: 'Implicit',\n    blwfMode: 'Post_Only'\n  },\n\n  Malayalam: {\n    hasOldSpec: true,\n    virama: 0x0D4D,\n    basePos: 'Last',\n    rephPos: POSITIONS.After_Main,\n    rephMode: 'Log_Repha',\n    blwfMode: 'Pre_And_Post'\n  },\n\n  // Handled by UniversalShaper\n  // Sinhala: {\n  //   hasOldSpec: false,\n  //   virama: 0x0DCA,\n  //   basePos: 'Last_Sinhala',\n  //   rephPos: POSITIONS.After_Main,\n  //   rephMode: 'Explicit',\n  //   blwfMode: 'Pre_And_Post'\n  // },\n\n  Khmer: {\n    hasOldSpec: false,\n    virama: 0x17D2,\n    basePos: 'First',\n    rephPos: POSITIONS.Ra_To_Become_Reph,\n    rephMode: 'Vis_Repha',\n    blwfMode: 'Pre_And_Post'\n  }\n};\n\n// Additional decompositions that aren't in Unicode\nvar INDIC_DECOMPOSITIONS = {\n  // Khmer\n  0x17BE: [0x17C1, 0x17BE],\n  0x17BF: [0x17C1, 0x17BF],\n  0x17C0: [0x17C1, 0x17C0],\n  0x17C4: [0x17C1, 0x17C4],\n  0x17C5: [0x17C1, 0x17C5]\n};\n\nvar _class$6;\nvar _temp$2;\nvar decompositions = useData.decompositions;\n\nvar trie$1 = new UnicodeTrie(Buffer(\"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\",\"base64\"));\nvar stateMachine = new StateMachine(indicMachine);\n\n/**\n * The IndicShaper supports indic scripts e.g. Devanagari, Kannada, etc.\n * Based on code from Harfbuzz: https://github.com/behdad/harfbuzz/blob/master/src/hb-ot-shape-complex-indic.cc\n */\nvar IndicShaper = (_temp$2 = _class$6 = function (_DefaultShaper) {\n  _inherits(IndicShaper, _DefaultShaper);\n\n  function IndicShaper() {\n    _classCallCheck(this, IndicShaper);\n\n    return _possibleConstructorReturn(this, _DefaultShaper.apply(this, arguments));\n  }\n\n  IndicShaper.planFeatures = function planFeatures(plan) {\n    plan.addStage(setupSyllables);\n\n    plan.addStage(['locl', 'ccmp']);\n\n    plan.addStage(initialReordering);\n\n    plan.addStage('nukt');\n    plan.addStage('akhn');\n    plan.addStage('rphf', false);\n    plan.addStage('rkrf');\n    plan.addStage('pref', false);\n    plan.addStage('blwf', false);\n    plan.addStage('abvf', false);\n    plan.addStage('half', false);\n    plan.addStage('pstf', false);\n    plan.addStage('vatu');\n    plan.addStage('cjct');\n    plan.addStage('cfar', false);\n\n    plan.addStage(finalReordering);\n\n    plan.addStage({\n      local: ['init'],\n      global: ['pres', 'abvs', 'blws', 'psts', 'haln', 'dist', 'abvm', 'blwm', 'calt', 'clig']\n    });\n\n    // Setup the indic config for the selected script\n    plan.unicodeScript = fromOpenType(plan.script);\n    plan.indicConfig = INDIC_CONFIGS[plan.unicodeScript] || INDIC_CONFIGS.Default;\n    plan.isOldSpec = plan.indicConfig.hasOldSpec && plan.script[plan.script.length - 1] !== '2';\n\n    // TODO: turn off kern (Khmer) and liga features.\n  };\n\n  IndicShaper.assignFeatures = function assignFeatures(plan, glyphs) {\n    var _loop = function _loop(i) {\n      var codepoint = glyphs[i].codePoints[0];\n      var d = INDIC_DECOMPOSITIONS[codepoint] || decompositions[codepoint];\n      if (d) {\n        var decomposed = d.map(function (c) {\n          var g = plan.font.glyphForCodePoint(c);\n          return new GlyphInfo(plan.font, g.id, [c], glyphs[i].features);\n        });\n\n        glyphs.splice.apply(glyphs, [i, 1].concat(decomposed));\n      }\n    };\n\n    // Decompose split matras\n    // TODO: do this in a more general unicode normalizer\n    for (var i = glyphs.length - 1; i >= 0; i--) {\n      _loop(i);\n    }\n  };\n\n  return IndicShaper;\n}(DefaultShaper), _class$6.zeroMarkWidths = 'NONE', _temp$2);\nfunction indicCategory(glyph) {\n  return trie$1.get(glyph.codePoints[0]) >> 8;\n}\n\nfunction indicPosition(glyph) {\n  return 1 << (trie$1.get(glyph.codePoints[0]) & 0xff);\n}\n\nvar IndicInfo = function IndicInfo(category, position, syllableType, syllable) {\n  _classCallCheck(this, IndicInfo);\n\n  this.category = category;\n  this.position = position;\n  this.syllableType = syllableType;\n  this.syllable = syllable;\n};\n\nfunction setupSyllables(font, glyphs) {\n  var syllable = 0;\n  var last = 0;\n  for (var _iterator = stateMachine.match(glyphs.map(indicCategory)), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n    var _ref;\n\n    if (_isArray) {\n      if (_i >= _iterator.length) break;\n      _ref = _iterator[_i++];\n    } else {\n      _i = _iterator.next();\n      if (_i.done) break;\n      _ref = _i.value;\n    }\n\n    var _ref2 = _ref,\n        start = _ref2[0],\n        end = _ref2[1],\n        tags = _ref2[2];\n\n    if (start > last) {\n      ++syllable;\n      for (var _i2 = last; _i2 < start; _i2++) {\n        glyphs[_i2].shaperInfo = new IndicInfo(CATEGORIES.X, POSITIONS.End, 'non_indic_cluster', syllable);\n      }\n    }\n\n    ++syllable;\n\n    // Create shaper info\n    for (var _i3 = start; _i3 <= end; _i3++) {\n      glyphs[_i3].shaperInfo = new IndicInfo(1 << indicCategory(glyphs[_i3]), indicPosition(glyphs[_i3]), tags[0], syllable);\n    }\n\n    last = end + 1;\n  }\n\n  if (last < glyphs.length) {\n    ++syllable;\n    for (var i = last; i < glyphs.length; i++) {\n      glyphs[i].shaperInfo = new IndicInfo(CATEGORIES.X, POSITIONS.End, 'non_indic_cluster', syllable);\n    }\n  }\n}\n\nfunction isConsonant(glyph) {\n  return glyph.shaperInfo.category & CONSONANT_FLAGS;\n}\n\nfunction isJoiner(glyph) {\n  return glyph.shaperInfo.category & JOINER_FLAGS;\n}\n\nfunction isHalantOrCoeng(glyph) {\n  return glyph.shaperInfo.category & HALANT_OR_COENG_FLAGS;\n}\n\nfunction wouldSubstitute(glyphs, feature) {\n  for (var _iterator2 = glyphs, _isArray2 = Array.isArray(_iterator2), _i4 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n    var _glyph$features;\n\n    var _ref3;\n\n    if (_isArray2) {\n      if (_i4 >= _iterator2.length) break;\n      _ref3 = _iterator2[_i4++];\n    } else {\n      _i4 = _iterator2.next();\n      if (_i4.done) break;\n      _ref3 = _i4.value;\n    }\n\n    var glyph = _ref3;\n\n    glyph.features = (_glyph$features = {}, _glyph$features[feature] = true, _glyph$features);\n  }\n\n  var GSUB = glyphs[0]._font._layoutEngine.engine.GSUBProcessor;\n  GSUB.applyFeatures([feature], glyphs);\n\n  return glyphs.length === 1;\n}\n\nfunction consonantPosition(font, consonant, virama) {\n  var glyphs = [virama, consonant, virama];\n  if (wouldSubstitute(glyphs.slice(0, 2), 'blwf') || wouldSubstitute(glyphs.slice(1, 3), 'blwf')) {\n    return POSITIONS.Below_C;\n  } else if (wouldSubstitute(glyphs.slice(0, 2), 'pstf') || wouldSubstitute(glyphs.slice(1, 3), 'pstf')) {\n    return POSITIONS.Post_C;\n  } else if (wouldSubstitute(glyphs.slice(0, 2), 'pref') || wouldSubstitute(glyphs.slice(1, 3), 'pref')) {\n    return POSITIONS.Post_C;\n  }\n\n  return POSITIONS.Base_C;\n}\n\nfunction initialReordering(font, glyphs, plan) {\n  var indicConfig = plan.indicConfig;\n  var features = font._layoutEngine.engine.GSUBProcessor.features;\n\n  var dottedCircle = font.glyphForCodePoint(0x25cc).id;\n  var virama = font.glyphForCodePoint(indicConfig.virama).id;\n  if (virama) {\n    var info = new GlyphInfo(font, virama, [indicConfig.virama]);\n    for (var i = 0; i < glyphs.length; i++) {\n      if (glyphs[i].shaperInfo.position === POSITIONS.Base_C) {\n        glyphs[i].shaperInfo.position = consonantPosition(font, glyphs[i].copy(), info);\n      }\n    }\n  }\n\n  for (var start = 0, end = nextSyllable(glyphs, 0); start < glyphs.length; start = end, end = nextSyllable(glyphs, start)) {\n    var _glyphs$start$shaperI = glyphs[start].shaperInfo,\n        category = _glyphs$start$shaperI.category,\n        syllableType = _glyphs$start$shaperI.syllableType;\n\n\n    if (syllableType === 'symbol_cluster' || syllableType === 'non_indic_cluster') {\n      continue;\n    }\n\n    if (syllableType === 'broken_cluster' && dottedCircle) {\n      var g = new GlyphInfo(font, dottedCircle, [0x25cc]);\n      g.shaperInfo = new IndicInfo(1 << indicCategory(g), indicPosition(g), glyphs[start].shaperInfo.syllableType, glyphs[start].shaperInfo.syllable);\n\n      // Insert after possible Repha.\n      var _i5 = start;\n      while (_i5 < end && glyphs[_i5].shaperInfo.category === CATEGORIES.Repha) {\n        _i5++;\n      }\n\n      glyphs.splice(_i5++, 0, g);\n      end++;\n    }\n\n    // 1. Find base consonant:\n    //\n    // The shaping engine finds the base consonant of the syllable, using the\n    // following algorithm: starting from the end of the syllable, move backwards\n    // until a consonant is found that does not have a below-base or post-base\n    // form (post-base forms have to follow below-base forms), or that is not a\n    // pre-base reordering Ra, or arrive at the first consonant. The consonant\n    // stopped at will be the base.\n\n    var base = end;\n    var limit = start;\n    var hasReph = false;\n\n    // If the syllable starts with Ra + Halant (in a script that has Reph)\n    // and has more than one consonant, Ra is excluded from candidates for\n    // base consonants.\n    if (indicConfig.rephPos !== POSITIONS.Ra_To_Become_Reph && features.rphf && start + 3 <= end && (indicConfig.rephMode === 'Implicit' && !isJoiner(glyphs[start + 2]) || indicConfig.rephMode === 'Explicit' && glyphs[start + 2].shaperInfo.category === CATEGORIES.ZWJ)) {\n      // See if it matches the 'rphf' feature.\n      var _g = [glyphs[start].copy(), glyphs[start + 1].copy(), glyphs[start + 2].copy()];\n      if (wouldSubstitute(_g.slice(0, 2), 'rphf') || indicConfig.rephMode === 'Explicit' && wouldSubstitute(_g, 'rphf')) {\n        limit += 2;\n        while (limit < end && isJoiner(glyphs[limit])) {\n          limit++;\n        }\n        base = start;\n        hasReph = true;\n      }\n    } else if (indicConfig.rephMode === 'Log_Repha' && glyphs[start].shaperInfo.category === CATEGORIES.Repha) {\n      limit++;\n      while (limit < end && isJoiner(glyphs[limit])) {\n        limit++;\n      }\n      base = start;\n      hasReph = true;\n    }\n\n    switch (indicConfig.basePos) {\n      case 'Last':\n        {\n          // starting from the end of the syllable, move backwards\n          var _i6 = end;\n          var seenBelow = false;\n\n          do {\n            var _info = glyphs[--_i6].shaperInfo;\n\n            // until a consonant is found\n            if (isConsonant(glyphs[_i6])) {\n              // that does not have a below-base or post-base form\n              // (post-base forms have to follow below-base forms),\n              if (_info.position !== POSITIONS.Below_C && (_info.position !== POSITIONS.Post_C || seenBelow)) {\n                base = _i6;\n                break;\n              }\n\n              // or that is not a pre-base reordering Ra,\n              //\n              // IMPLEMENTATION NOTES:\n              //\n              // Our pre-base reordering Ra's are marked POS_POST_C, so will be skipped\n              // by the logic above already.\n              //\n\n              // or arrive at the first consonant. The consonant stopped at will\n              // be the base.\n              if (_info.position === POSITIONS.Below_C) {\n                seenBelow = true;\n              }\n\n              base = _i6;\n            } else if (start < _i6 && _info.category === CATEGORIES.ZWJ && glyphs[_i6 - 1].shaperInfo.category === CATEGORIES.H) {\n              // A ZWJ after a Halant stops the base search, and requests an explicit\n              // half form.\n              // A ZWJ before a Halant, requests a subjoined form instead, and hence\n              // search continues.  This is particularly important for Bengali\n              // sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya.\n              break;\n            }\n          } while (_i6 > limit);\n          break;\n        }\n\n      case 'First':\n        {\n          // The first consonant is always the base.\n          base = start;\n\n          // Mark all subsequent consonants as below.\n          for (var _i7 = base + 1; _i7 < end; _i7++) {\n            if (isConsonant(glyphs[_i7])) {\n              glyphs[_i7].shaperInfo.position = POSITIONS.Below_C;\n            }\n          }\n        }\n    }\n\n    // If the syllable starts with Ra + Halant (in a script that has Reph)\n    // and has more than one consonant, Ra is excluded from candidates for\n    // base consonants.\n    //\n    //  Only do this for unforced Reph. (ie. not for Ra,H,ZWJ)\n    if (hasReph && base === start && limit - base <= 2) {\n      hasReph = false;\n    }\n\n    // 2. Decompose and reorder Matras:\n    //\n    // Each matra and any syllable modifier sign in the cluster are moved to the\n    // appropriate position relative to the consonant(s) in the cluster. The\n    // shaping engine decomposes two- or three-part matras into their constituent\n    // parts before any repositioning. Matra characters are classified by which\n    // consonant in a conjunct they have affinity for and are reordered to the\n    // following positions:\n    //\n    //   o Before first half form in the syllable\n    //   o After subjoined consonants\n    //   o After post-form consonant\n    //   o After main consonant (for above marks)\n    //\n    // IMPLEMENTATION NOTES:\n    //\n    // The normalize() routine has already decomposed matras for us, so we don't\n    // need to worry about that.\n\n    // 3.  Reorder marks to canonical order:\n    //\n    // Adjacent nukta and halant or nukta and vedic sign are always repositioned\n    // if necessary, so that the nukta is first.\n    //\n    // IMPLEMENTATION NOTES:\n    //\n    // We don't need to do this: the normalize() routine already did this for us.\n\n    // Reorder characters\n\n    for (var _i8 = start; _i8 < base; _i8++) {\n      var _info2 = glyphs[_i8].shaperInfo;\n      _info2.position = Math.min(POSITIONS.Pre_C, _info2.position);\n    }\n\n    if (base < end) {\n      glyphs[base].shaperInfo.position = POSITIONS.Base_C;\n    }\n\n    // Mark final consonants.  A final consonant is one appearing after a matra,\n    // like in Khmer.\n    for (var _i9 = base + 1; _i9 < end; _i9++) {\n      if (glyphs[_i9].shaperInfo.category === CATEGORIES.M) {\n        for (var j = _i9 + 1; j < end; j++) {\n          if (isConsonant(glyphs[j])) {\n            glyphs[j].shaperInfo.position = POSITIONS.Final_C;\n            break;\n          }\n        }\n        break;\n      }\n    }\n\n    // Handle beginning Ra\n    if (hasReph) {\n      glyphs[start].shaperInfo.position = POSITIONS.Ra_To_Become_Reph;\n    }\n\n    // For old-style Indic script tags, move the first post-base Halant after\n    // last consonant.\n    //\n    // Reports suggest that in some scripts Uniscribe does this only if there\n    // is *not* a Halant after last consonant already (eg. Kannada), while it\n    // does it unconditionally in other scripts (eg. Malayalam).  We don't\n    // currently know about other scripts, so we single out Malayalam for now.\n    //\n    // Kannada test case:\n    // U+0C9A,U+0CCD,U+0C9A,U+0CCD\n    // With some versions of Lohit Kannada.\n    // https://bugs.freedesktop.org/show_bug.cgi?id=59118\n    //\n    // Malayalam test case:\n    // U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D\n    // With lohit-ttf-20121122/Lohit-Malayalam.ttf\n    if (plan.isOldSpec) {\n      var disallowDoubleHalants = plan.unicodeScript !== 'Malayalam';\n      for (var _i10 = base + 1; _i10 < end; _i10++) {\n        if (glyphs[_i10].shaperInfo.category === CATEGORIES.H) {\n          var _j = void 0;\n          for (_j = end - 1; _j > _i10; _j--) {\n            if (isConsonant(glyphs[_j]) || disallowDoubleHalants && glyphs[_j].shaperInfo.category === CATEGORIES.H) {\n              break;\n            }\n          }\n\n          if (glyphs[_j].shaperInfo.category !== CATEGORIES.H && _j > _i10) {\n            // Move Halant to after last consonant.\n            var t = glyphs[_i10];\n            glyphs.splice.apply(glyphs, [_i10, 0].concat(glyphs.splice(_i10 + 1, _j - _i10)));\n            glyphs[_j] = t;\n          }\n\n          break;\n        }\n      }\n    }\n\n    // Attach misc marks to previous char to move with them.\n    var lastPos = POSITIONS.Start;\n    for (var _i11 = start; _i11 < end; _i11++) {\n      var _info3 = glyphs[_i11].shaperInfo;\n      if (_info3.category & (JOINER_FLAGS | CATEGORIES.N | CATEGORIES.RS | CATEGORIES.CM | HALANT_OR_COENG_FLAGS & _info3.category)) {\n        _info3.position = lastPos;\n        if (_info3.category === CATEGORIES.H && _info3.position === POSITIONS.Pre_M) {\n          // Uniscribe doesn't move the Halant with Left Matra.\n          // TEST: U+092B,U+093F,U+094DE\n          // We follow.  This is important for the Sinhala\n          // U+0DDA split matra since it decomposes to U+0DD9,U+0DCA\n          // where U+0DD9 is a left matra and U+0DCA is the virama.\n          // We don't want to move the virama with the left matra.\n          // TEST: U+0D9A,U+0DDA\n          for (var _j2 = _i11; _j2 > start; _j2--) {\n            if (glyphs[_j2 - 1].shaperInfo.position !== POSITIONS.Pre_M) {\n              _info3.position = glyphs[_j2 - 1].shaperInfo.position;\n              break;\n            }\n          }\n        }\n      } else if (_info3.position !== POSITIONS.SMVD) {\n        lastPos = _info3.position;\n      }\n    }\n\n    // For post-base consonants let them own anything before them\n    // since the last consonant or matra.\n    var last = base;\n    for (var _i12 = base + 1; _i12 < end; _i12++) {\n      if (isConsonant(glyphs[_i12])) {\n        for (var _j3 = last + 1; _j3 < _i12; _j3++) {\n          if (glyphs[_j3].shaperInfo.position < POSITIONS.SMVD) {\n            glyphs[_j3].shaperInfo.position = glyphs[_i12].shaperInfo.position;\n          }\n        }\n        last = _i12;\n      } else if (glyphs[_i12].shaperInfo.category === CATEGORIES.M) {\n        last = _i12;\n      }\n    }\n\n    var arr = glyphs.slice(start, end);\n    arr.sort(function (a, b) {\n      return a.shaperInfo.position - b.shaperInfo.position;\n    });\n    glyphs.splice.apply(glyphs, [start, arr.length].concat(arr));\n\n    // Find base again\n    for (var _i13 = start; _i13 < end; _i13++) {\n      if (glyphs[_i13].shaperInfo.position === POSITIONS.Base_C) {\n        base = _i13;\n        break;\n      }\n    }\n\n    // Setup features now\n\n    // Reph\n    for (var _i14 = start; _i14 < end && glyphs[_i14].shaperInfo.position === POSITIONS.Ra_To_Become_Reph; _i14++) {\n      glyphs[_i14].features.rphf = true;\n    }\n\n    // Pre-base\n    var blwf = !plan.isOldSpec && indicConfig.blwfMode === 'Pre_And_Post';\n    for (var _i15 = start; _i15 < base; _i15++) {\n      glyphs[_i15].features.half = true;\n      if (blwf) {\n        glyphs[_i15].features.blwf = true;\n      }\n    }\n\n    // Post-base\n    for (var _i16 = base + 1; _i16 < end; _i16++) {\n      glyphs[_i16].features.abvf = true;\n      glyphs[_i16].features.pstf = true;\n      glyphs[_i16].features.blwf = true;\n    }\n\n    if (plan.isOldSpec && plan.unicodeScript === 'Devanagari') {\n      // Old-spec eye-lash Ra needs special handling.  From the\n      // spec:\n      //\n      // \"The feature 'below-base form' is applied to consonants\n      // having below-base forms and following the base consonant.\n      // The exception is vattu, which may appear below half forms\n      // as well as below the base glyph. The feature 'below-base\n      // form' will be applied to all such occurrences of Ra as well.\"\n      //\n      // Test case: U+0924,U+094D,U+0930,U+094d,U+0915\n      // with Sanskrit 2003 font.\n      //\n      // However, note that Ra,Halant,ZWJ is the correct way to\n      // request eyelash form of Ra, so we wouldbn't inhibit it\n      // in that sequence.\n      //\n      // Test case: U+0924,U+094D,U+0930,U+094d,U+200D,U+0915\n      for (var _i17 = start; _i17 + 1 < base; _i17++) {\n        if (glyphs[_i17].shaperInfo.category === CATEGORIES.Ra && glyphs[_i17 + 1].shaperInfo.category === CATEGORIES.H && (_i17 + 1 === base || glyphs[_i17 + 2].shaperInfo.category === CATEGORIES.ZWJ)) {\n          glyphs[_i17].features.blwf = true;\n          glyphs[_i17 + 1].features.blwf = true;\n        }\n      }\n    }\n\n    var prefLen = 2;\n    if (features.pref && base + prefLen < end) {\n      // Find a Halant,Ra sequence and mark it for pre-base reordering processing.\n      for (var _i18 = base + 1; _i18 + prefLen - 1 < end; _i18++) {\n        var _g2 = [glyphs[_i18].copy(), glyphs[_i18 + 1].copy()];\n        if (wouldSubstitute(_g2, 'pref')) {\n          for (var _j4 = 0; _j4 < prefLen; _j4++) {\n            glyphs[_i18++].features.pref = true;\n          }\n\n          // Mark the subsequent stuff with 'cfar'.  Used in Khmer.\n          // Read the feature spec.\n          // This allows distinguishing the following cases with MS Khmer fonts:\n          // U+1784,U+17D2,U+179A,U+17D2,U+1782\n          // U+1784,U+17D2,U+1782,U+17D2,U+179A\n          if (features.cfar) {\n            for (; _i18 < end; _i18++) {\n              glyphs[_i18].features.cfar = true;\n            }\n          }\n\n          break;\n        }\n      }\n    }\n\n    // Apply ZWJ/ZWNJ effects\n    for (var _i19 = start + 1; _i19 < end; _i19++) {\n      if (isJoiner(glyphs[_i19])) {\n        var nonJoiner = glyphs[_i19].shaperInfo.category === CATEGORIES.ZWNJ;\n        var _j5 = _i19;\n\n        do {\n          _j5--;\n\n          // ZWJ/ZWNJ should disable CJCT.  They do that by simply\n          // being there, since we don't skip them for the CJCT\n          // feature (ie. F_MANUAL_ZWJ)\n\n          // A ZWNJ disables HALF.\n          if (nonJoiner) {\n            delete glyphs[_j5].features.half;\n          }\n        } while (_j5 > start && !isConsonant(glyphs[_j5]));\n      }\n    }\n  }\n}\n\nfunction finalReordering(font, glyphs, plan) {\n  var indicConfig = plan.indicConfig;\n  var features = font._layoutEngine.engine.GSUBProcessor.features;\n\n  for (var start = 0, end = nextSyllable(glyphs, 0); start < glyphs.length; start = end, end = nextSyllable(glyphs, start)) {\n    // 4. Final reordering:\n    //\n    // After the localized forms and basic shaping forms GSUB features have been\n    // applied (see below), the shaping engine performs some final glyph\n    // reordering before applying all the remaining font features to the entire\n    // cluster.\n\n    var tryPref = !!features.pref;\n\n    // Find base again\n    var base = start;\n    for (; base < end; base++) {\n      if (glyphs[base].shaperInfo.position >= POSITIONS.Base_C) {\n        if (tryPref && base + 1 < end) {\n          for (var i = base + 1; i < end; i++) {\n            if (glyphs[i].features.pref) {\n              if (!(glyphs[i].substituted && glyphs[i].isLigated && !glyphs[i].isMultiplied)) {\n                // Ok, this was a 'pref' candidate but didn't form any.\n                // Base is around here...\n                base = i;\n                while (base < end && isHalantOrCoeng(glyphs[base])) {\n                  base++;\n                }\n                glyphs[base].shaperInfo.position = POSITIONS.BASE_C;\n                tryPref = false;\n              }\n              break;\n            }\n          }\n        }\n\n        // For Malayalam, skip over unformed below- (but NOT post-) forms.\n        if (plan.unicodeScript === 'Malayalam') {\n          for (var _i20 = base + 1; _i20 < end; _i20++) {\n            while (_i20 < end && isJoiner(glyphs[_i20])) {\n              _i20++;\n            }\n\n            if (_i20 === end || !isHalantOrCoeng(glyphs[_i20])) {\n              break;\n            }\n\n            _i20++; // Skip halant.\n            while (_i20 < end && isJoiner(glyphs[_i20])) {\n              _i20++;\n            }\n\n            if (_i20 < end && isConsonant(glyphs[_i20]) && glyphs[_i20].shaperInfo.position === POSITIONS.Below_C) {\n              base = _i20;\n              glyphs[base].shaperInfo.position = POSITIONS.Base_C;\n            }\n          }\n        }\n\n        if (start < base && glyphs[base].shaperInfo.position > POSITIONS.Base_C) {\n          base--;\n        }\n        break;\n      }\n    }\n\n    if (base === end && start < base && glyphs[base - 1].shaperInfo.category === CATEGORIES.ZWJ) {\n      base--;\n    }\n\n    if (base < end) {\n      while (start < base && glyphs[base].shaperInfo.category & (CATEGORIES.N | HALANT_OR_COENG_FLAGS)) {\n        base--;\n      }\n    }\n\n    // o Reorder matras:\n    //\n    // If a pre-base matra character had been reordered before applying basic\n    // features, the glyph can be moved closer to the main consonant based on\n    // whether half-forms had been formed. Actual position for the matra is\n    // defined as “after last standalone halant glyph, after initial matra\n    // position and before the main consonant”. If ZWJ or ZWNJ follow this\n    // halant, position is moved after it.\n    //\n\n    if (start + 1 < end && start < base) {\n      // Otherwise there can't be any pre-base matra characters.\n      // If we lost track of base, alas, position before last thingy.\n      var newPos = base === end ? base - 2 : base - 1;\n\n      // Malayalam / Tamil do not have \"half\" forms or explicit virama forms.\n      // The glyphs formed by 'half' are Chillus or ligated explicit viramas.\n      // We want to position matra after them.\n      if (plan.unicodeScript !== 'Malayalam' && plan.unicodeScript !== 'Tamil') {\n        while (newPos > start && !(glyphs[newPos].shaperInfo.category & (CATEGORIES.M | HALANT_OR_COENG_FLAGS))) {\n          newPos--;\n        }\n\n        // If we found no Halant we are done.\n        // Otherwise only proceed if the Halant does\n        // not belong to the Matra itself!\n        if (isHalantOrCoeng(glyphs[newPos]) && glyphs[newPos].shaperInfo.position !== POSITIONS.Pre_M) {\n          // If ZWJ or ZWNJ follow this halant, position is moved after it.\n          if (newPos + 1 < end && isJoiner(glyphs[newPos + 1])) {\n            newPos++;\n          }\n        } else {\n          newPos = start; // No move.\n        }\n      }\n\n      if (start < newPos && glyphs[newPos].shaperInfo.position !== POSITIONS.Pre_M) {\n        // Now go see if there's actually any matras...\n        for (var _i21 = newPos; _i21 > start; _i21--) {\n          if (glyphs[_i21 - 1].shaperInfo.position === POSITIONS.Pre_M) {\n            var oldPos = _i21 - 1;\n            if (oldPos < base && base <= newPos) {\n              // Shouldn't actually happen.\n              base--;\n            }\n\n            var tmp = glyphs[oldPos];\n            glyphs.splice.apply(glyphs, [oldPos, 0].concat(glyphs.splice(oldPos + 1, newPos - oldPos)));\n            glyphs[newPos] = tmp;\n\n            newPos--;\n          }\n        }\n      }\n    }\n\n    // o Reorder reph:\n    //\n    // Reph’s original position is always at the beginning of the syllable,\n    // (i.e. it is not reordered at the character reordering stage). However,\n    // it will be reordered according to the basic-forms shaping results.\n    // Possible positions for reph, depending on the script, are; after main,\n    // before post-base consonant forms, and after post-base consonant forms.\n\n    // Two cases:\n    //\n    // - If repha is encoded as a sequence of characters (Ra,H or Ra,H,ZWJ), then\n    //   we should only move it if the sequence ligated to the repha form.\n    //\n    // - If repha is encoded separately and in the logical position, we should only\n    //   move it if it did NOT ligate.  If it ligated, it's probably the font trying\n    //   to make it work without the reordering.\n    if (start + 1 < end && glyphs[start].shaperInfo.position === POSITIONS.Ra_To_Become_Reph && glyphs[start].shaperInfo.category === CATEGORIES.Repha !== (glyphs[start].isLigated && !glyphs[start].isMultiplied)) {\n      var newRephPos = void 0;\n      var rephPos = indicConfig.rephPos;\n      var found = false;\n\n      // 1. If reph should be positioned after post-base consonant forms,\n      //    proceed to step 5.\n      if (rephPos !== POSITIONS.After_Post) {\n        //  2. If the reph repositioning class is not after post-base: target\n        //     position is after the first explicit halant glyph between the\n        //     first post-reph consonant and last main consonant. If ZWJ or ZWNJ\n        //     are following this halant, position is moved after it. If such\n        //     position is found, this is the target position. Otherwise,\n        //     proceed to the next step.\n        //\n        //     Note: in old-implementation fonts, where classifications were\n        //     fixed in shaping engine, there was no case where reph position\n        //     will be found on this step.\n        newRephPos = start + 1;\n        while (newRephPos < base && !isHalantOrCoeng(glyphs[newRephPos])) {\n          newRephPos++;\n        }\n\n        if (newRephPos < base && isHalantOrCoeng(glyphs[newRephPos])) {\n          // ->If ZWJ or ZWNJ are following this halant, position is moved after it.\n          if (newRephPos + 1 < base && isJoiner(glyphs[newRephPos + 1])) {\n            newRephPos++;\n          }\n\n          found = true;\n        }\n\n        // 3. If reph should be repositioned after the main consonant: find the\n        //    first consonant not ligated with main, or find the first\n        //    consonant that is not a potential pre-base reordering Ra.\n        if (!found && rephPos === POSITIONS.After_Main) {\n          newRephPos = base;\n          while (newRephPos + 1 < end && glyphs[newRephPos + 1].shaperInfo.position <= POSITIONS.After_Main) {\n            newRephPos++;\n          }\n\n          found = newRephPos < end;\n        }\n\n        // 4. If reph should be positioned before post-base consonant, find\n        //    first post-base classified consonant not ligated with main. If no\n        //    consonant is found, the target position should be before the\n        //    first matra, syllable modifier sign or vedic sign.\n        //\n        // This is our take on what step 4 is trying to say (and failing, BADLY).\n        if (!found && rephPos === POSITIONS.After_Sub) {\n          newRephPos = base;\n          while (newRephPos + 1 < end && !(glyphs[newRephPos + 1].shaperInfo.position & (POSITIONS.Post_C | POSITIONS.After_Post | POSITIONS.SMVD))) {\n            newRephPos++;\n          }\n\n          found = newRephPos < end;\n        }\n      }\n\n      //  5. If no consonant is found in steps 3 or 4, move reph to a position\n      //     immediately before the first post-base matra, syllable modifier\n      //     sign or vedic sign that has a reordering class after the intended\n      //     reph position. For example, if the reordering position for reph\n      //     is post-main, it will skip above-base matras that also have a\n      //     post-main position.\n      if (!found) {\n        // Copied from step 2.\n        newRephPos = start + 1;\n        while (newRephPos < base && !isHalantOrCoeng(glyphs[newRephPos])) {\n          newRephPos++;\n        }\n\n        if (newRephPos < base && isHalantOrCoeng(glyphs[newRephPos])) {\n          // ->If ZWJ or ZWNJ are following this halant, position is moved after it.\n          if (newRephPos + 1 < base && isJoiner(glyphs[newRephPos + 1])) {\n            newRephPos++;\n          }\n\n          found = true;\n        }\n      }\n\n      // 6. Otherwise, reorder reph to the end of the syllable.\n      if (!found) {\n        newRephPos = end - 1;\n        while (newRephPos > start && glyphs[newRephPos].shaperInfo.position === POSITIONS.SMVD) {\n          newRephPos--;\n        }\n\n        // If the Reph is to be ending up after a Matra,Halant sequence,\n        // position it before that Halant so it can interact with the Matra.\n        // However, if it's a plain Consonant,Halant we shouldn't do that.\n        // Uniscribe doesn't do this.\n        // TEST: U+0930,U+094D,U+0915,U+094B,U+094D\n        if (isHalantOrCoeng(glyphs[newRephPos])) {\n          for (var _i22 = base + 1; _i22 < newRephPos; _i22++) {\n            if (glyphs[_i22].shaperInfo.category === CATEGORIES.M) {\n              newRephPos--;\n            }\n          }\n        }\n      }\n\n      var reph = glyphs[start];\n      glyphs.splice.apply(glyphs, [start, 0].concat(glyphs.splice(start + 1, newRephPos - start)));\n      glyphs[newRephPos] = reph;\n\n      if (start < base && base <= newRephPos) {\n        base--;\n      }\n    }\n\n    // o Reorder pre-base reordering consonants:\n    //\n    // If a pre-base reordering consonant is found, reorder it according to\n    // the following rules:\n    if (tryPref && base + 1 < end) {\n      for (var _i23 = base + 1; _i23 < end; _i23++) {\n        if (glyphs[_i23].features.pref) {\n          // 1. Only reorder a glyph produced by substitution during application\n          //    of the <pref> feature. (Note that a font may shape a Ra consonant with\n          //    the feature generally but block it in certain contexts.)\n\n          // Note: We just check that something got substituted.  We don't check that\n          // the <pref> feature actually did it...\n          //\n          // Reorder pref only if it ligated.\n          if (glyphs[_i23].isLigated && !glyphs[_i23].isMultiplied) {\n            // 2. Try to find a target position the same way as for pre-base matra.\n            //    If it is found, reorder pre-base consonant glyph.\n            //\n            // 3. If position is not found, reorder immediately before main\n            //    consonant.\n            var _newPos = base;\n\n            // Malayalam / Tamil do not have \"half\" forms or explicit virama forms.\n            // The glyphs formed by 'half' are Chillus or ligated explicit viramas.\n            // We want to position matra after them.\n            if (plan.unicodeScript !== 'Malayalam' && plan.unicodeScript !== 'Tamil') {\n              while (_newPos > start && !(glyphs[_newPos - 1].shaperInfo.category & (CATEGORIES.M | HALANT_OR_COENG_FLAGS))) {\n                _newPos--;\n              }\n\n              // In Khmer coeng model, a H,Ra can go *after* matras.  If it goes after a\n              // split matra, it should be reordered to *before* the left part of such matra.\n              if (_newPos > start && glyphs[_newPos - 1].shaperInfo.category === CATEGORIES.M) {\n                var _oldPos2 = _i23;\n                for (var j = base + 1; j < _oldPos2; j++) {\n                  if (glyphs[j].shaperInfo.category === CATEGORIES.M) {\n                    _newPos--;\n                    break;\n                  }\n                }\n              }\n            }\n\n            if (_newPos > start && isHalantOrCoeng(glyphs[_newPos - 1])) {\n              // -> If ZWJ or ZWNJ follow this halant, position is moved after it.\n              if (_newPos < end && isJoiner(glyphs[_newPos])) {\n                _newPos++;\n              }\n            }\n\n            var _oldPos = _i23;\n            var _tmp = glyphs[_oldPos];\n            glyphs.splice.apply(glyphs, [_newPos + 1, 0].concat(glyphs.splice(_newPos, _oldPos - _newPos)));\n            glyphs[_newPos] = _tmp;\n\n            if (_newPos <= base && base < _oldPos) {\n              base++;\n            }\n          }\n\n          break;\n        }\n      }\n    }\n\n    // Apply 'init' to the Left Matra if it's a word start.\n    if (glyphs[start].shaperInfo.position === POSITIONS.Pre_M && (!start || !/Cf|Mn/.test(unicode.getCategory(glyphs[start - 1].codePoints[0])))) {\n      glyphs[start].features.init = true;\n    }\n  }\n}\n\nfunction nextSyllable(glyphs, start) {\n  if (start >= glyphs.length) return start;\n  var syllable = glyphs[start].shaperInfo.syllable;\n  while (++start < glyphs.length && glyphs[start].shaperInfo.syllable === syllable) {}\n  return start;\n}\n\nvar _class$7;\nvar _temp$3;\nvar categories$1 = useData.categories;\nvar decompositions$2 = useData.decompositions;\nvar trie$2 = new UnicodeTrie(Buffer(\"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\",\"base64\"));\nvar stateMachine$1 = new StateMachine(useData);\n\n/**\n * This shaper is an implementation of the Universal Shaping Engine, which\n * uses Unicode data to shape a number of scripts without a dedicated shaping engine.\n * See https://www.microsoft.com/typography/OpenTypeDev/USE/intro.htm.\n */\nvar UniversalShaper = (_temp$3 = _class$7 = function (_DefaultShaper) {\n  _inherits(UniversalShaper, _DefaultShaper);\n\n  function UniversalShaper() {\n    _classCallCheck(this, UniversalShaper);\n\n    return _possibleConstructorReturn(this, _DefaultShaper.apply(this, arguments));\n  }\n\n  UniversalShaper.planFeatures = function planFeatures(plan) {\n    plan.addStage(setupSyllables$1);\n\n    // Default glyph pre-processing group\n    plan.addStage(['locl', 'ccmp', 'nukt', 'akhn']);\n\n    // Reordering group\n    plan.addStage(clearSubstitutionFlags);\n    plan.addStage(['rphf'], false);\n    plan.addStage(recordRphf);\n    plan.addStage(clearSubstitutionFlags);\n    plan.addStage(['pref']);\n    plan.addStage(recordPref);\n\n    // Orthographic unit shaping group\n    plan.addStage(['rkrf', 'abvf', 'blwf', 'half', 'pstf', 'vatu', 'cjct']);\n    plan.addStage(reorder);\n\n    // Topographical features\n    // Scripts that need this are handled by the Arabic shaper, not implemented here for now.\n    // plan.addStage(['isol', 'init', 'medi', 'fina', 'med2', 'fin2', 'fin3'], false);\n\n    // Standard topographic presentation and positional feature application\n    plan.addStage(['abvs', 'blws', 'pres', 'psts', 'dist', 'abvm', 'blwm']);\n  };\n\n  UniversalShaper.assignFeatures = function assignFeatures(plan, glyphs) {\n    var _loop = function _loop(i) {\n      var codepoint = glyphs[i].codePoints[0];\n      if (decompositions$2[codepoint]) {\n        var decomposed = decompositions$2[codepoint].map(function (c) {\n          var g = plan.font.glyphForCodePoint(c);\n          return new GlyphInfo(plan.font, g.id, [c], glyphs[i].features);\n        });\n\n        glyphs.splice.apply(glyphs, [i, 1].concat(decomposed));\n      }\n    };\n\n    // Decompose split vowels\n    // TODO: do this in a more general unicode normalizer\n    for (var i = glyphs.length - 1; i >= 0; i--) {\n      _loop(i);\n    }\n  };\n\n  return UniversalShaper;\n}(DefaultShaper), _class$7.zeroMarkWidths = 'BEFORE_GPOS', _temp$3);\nfunction useCategory(glyph) {\n  return trie$2.get(glyph.codePoints[0]);\n}\n\nvar USEInfo = function USEInfo(category, syllableType, syllable) {\n  _classCallCheck(this, USEInfo);\n\n  this.category = category;\n  this.syllableType = syllableType;\n  this.syllable = syllable;\n};\n\nfunction setupSyllables$1(font, glyphs) {\n  var syllable = 0;\n  for (var _iterator = stateMachine$1.match(glyphs.map(useCategory)), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n    var _ref;\n\n    if (_isArray) {\n      if (_i >= _iterator.length) break;\n      _ref = _iterator[_i++];\n    } else {\n      _i = _iterator.next();\n      if (_i.done) break;\n      _ref = _i.value;\n    }\n\n    var _ref2 = _ref,\n        start = _ref2[0],\n        end = _ref2[1],\n        tags = _ref2[2];\n\n    ++syllable;\n\n    // Create shaper info\n    for (var i = start; i <= end; i++) {\n      glyphs[i].shaperInfo = new USEInfo(categories$1[useCategory(glyphs[i])], tags[0], syllable);\n    }\n\n    // Assign rphf feature\n    var limit = glyphs[start].shaperInfo.category === 'R' ? 1 : Math.min(3, end - start);\n    for (var _i2 = start; _i2 < start + limit; _i2++) {\n      glyphs[_i2].features.rphf = true;\n    }\n  }\n}\n\nfunction clearSubstitutionFlags(font, glyphs) {\n  for (var _iterator2 = glyphs, _isArray2 = Array.isArray(_iterator2), _i3 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n    var _ref3;\n\n    if (_isArray2) {\n      if (_i3 >= _iterator2.length) break;\n      _ref3 = _iterator2[_i3++];\n    } else {\n      _i3 = _iterator2.next();\n      if (_i3.done) break;\n      _ref3 = _i3.value;\n    }\n\n    var glyph = _ref3;\n\n    glyph.substituted = false;\n  }\n}\n\nfunction recordRphf(font, glyphs) {\n  for (var _iterator3 = glyphs, _isArray3 = Array.isArray(_iterator3), _i4 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n    var _ref4;\n\n    if (_isArray3) {\n      if (_i4 >= _iterator3.length) break;\n      _ref4 = _iterator3[_i4++];\n    } else {\n      _i4 = _iterator3.next();\n      if (_i4.done) break;\n      _ref4 = _i4.value;\n    }\n\n    var glyph = _ref4;\n\n    if (glyph.substituted && glyph.features.rphf) {\n      // Mark a substituted repha.\n      glyph.shaperInfo.category = 'R';\n    }\n  }\n}\n\nfunction recordPref(font, glyphs) {\n  for (var _iterator4 = glyphs, _isArray4 = Array.isArray(_iterator4), _i5 = 0, _iterator4 = _isArray4 ? _iterator4 : _getIterator(_iterator4);;) {\n    var _ref5;\n\n    if (_isArray4) {\n      if (_i5 >= _iterator4.length) break;\n      _ref5 = _iterator4[_i5++];\n    } else {\n      _i5 = _iterator4.next();\n      if (_i5.done) break;\n      _ref5 = _i5.value;\n    }\n\n    var glyph = _ref5;\n\n    if (glyph.substituted) {\n      // Mark a substituted pref as VPre, as they behave the same way.\n      glyph.shaperInfo.category = 'VPre';\n    }\n  }\n}\n\nfunction reorder(font, glyphs) {\n  var dottedCircle = font.glyphForCodePoint(0x25cc).id;\n\n  for (var start = 0, end = nextSyllable$1(glyphs, 0); start < glyphs.length; start = end, end = nextSyllable$1(glyphs, start)) {\n    var i = void 0,\n        j = void 0;\n    var info = glyphs[start].shaperInfo;\n    var type = info.syllableType;\n\n    // Only a few syllable types need reordering.\n    if (type !== 'virama_terminated_cluster' && type !== 'standard_cluster' && type !== 'broken_cluster') {\n      continue;\n    }\n\n    // Insert a dotted circle glyph in broken clusters.\n    if (type === 'broken_cluster' && dottedCircle) {\n      var g = new GlyphInfo(font, dottedCircle, [0x25cc]);\n      g.shaperInfo = info;\n\n      // Insert after possible Repha.\n      for (i = start; i < end && glyphs[i].shaperInfo.category === 'R'; i++) {}\n      glyphs.splice(++i, 0, g);\n      end++;\n    }\n\n    // Move things forward.\n    if (info.category === 'R' && end - start > 1) {\n      // Got a repha. Reorder it to after first base, before first halant.\n      for (i = start + 1; i < end; i++) {\n        info = glyphs[i].shaperInfo;\n        if (isBase(info) || isHalant(glyphs[i])) {\n          // If we hit a halant, move before it; otherwise it's a base: move to it's\n          // place, and shift things in between backward.\n          if (isHalant(glyphs[i])) {\n            i--;\n          }\n\n          glyphs.splice.apply(glyphs, [start, 0].concat(glyphs.splice(start + 1, i - start), [glyphs[i]]));\n          break;\n        }\n      }\n    }\n\n    // Move things back.\n    for (i = start, j = end; i < end; i++) {\n      info = glyphs[i].shaperInfo;\n      if (isBase(info) || isHalant(glyphs[i])) {\n        // If we hit a halant, move after it; otherwise it's a base: move to it's\n        // place, and shift things in between backward.\n        j = isHalant(glyphs[i]) ? i + 1 : i;\n      } else if ((info.category === 'VPre' || info.category === 'VMPre') && j < i) {\n        glyphs.splice.apply(glyphs, [j, 1, glyphs[i]].concat(glyphs.splice(j, i - j)));\n      }\n    }\n  }\n}\n\nfunction nextSyllable$1(glyphs, start) {\n  if (start >= glyphs.length) return start;\n  var syllable = glyphs[start].shaperInfo.syllable;\n  while (++start < glyphs.length && glyphs[start].shaperInfo.syllable === syllable) {}\n  return start;\n}\n\nfunction isHalant(glyph) {\n  return glyph.shaperInfo.category === 'H' && !glyph.isLigated;\n}\n\nfunction isBase(info) {\n  return info.category === 'B' || info.category === 'GB';\n}\n\nvar SHAPERS = {\n  arab: ArabicShaper, // Arabic\n  mong: ArabicShaper, // Mongolian\n  syrc: ArabicShaper, // Syriac\n  'nko ': ArabicShaper, // N'Ko\n  phag: ArabicShaper, // Phags Pa\n  mand: ArabicShaper, // Mandaic\n  mani: ArabicShaper, // Manichaean\n  phlp: ArabicShaper, // Psalter Pahlavi\n\n  hang: HangulShaper, // Hangul\n\n  bng2: IndicShaper, // Bengali\n  beng: IndicShaper, // Bengali\n  dev2: IndicShaper, // Devanagari\n  deva: IndicShaper, // Devanagari\n  gjr2: IndicShaper, // Gujarati\n  gujr: IndicShaper, // Gujarati\n  guru: IndicShaper, // Gurmukhi\n  gur2: IndicShaper, // Gurmukhi\n  knda: IndicShaper, // Kannada\n  knd2: IndicShaper, // Kannada\n  mlm2: IndicShaper, // Malayalam\n  mlym: IndicShaper, // Malayalam\n  ory2: IndicShaper, // Oriya\n  orya: IndicShaper, // Oriya\n  taml: IndicShaper, // Tamil\n  tml2: IndicShaper, // Tamil\n  telu: IndicShaper, // Telugu\n  tel2: IndicShaper, // Telugu\n  khmr: IndicShaper, // Khmer\n\n  bali: UniversalShaper, // Balinese\n  batk: UniversalShaper, // Batak\n  brah: UniversalShaper, // Brahmi\n  bugi: UniversalShaper, // Buginese\n  buhd: UniversalShaper, // Buhid\n  cakm: UniversalShaper, // Chakma\n  cham: UniversalShaper, // Cham\n  dupl: UniversalShaper, // Duployan\n  egyp: UniversalShaper, // Egyptian Hieroglyphs\n  gran: UniversalShaper, // Grantha\n  hano: UniversalShaper, // Hanunoo\n  java: UniversalShaper, // Javanese\n  kthi: UniversalShaper, // Kaithi\n  kali: UniversalShaper, // Kayah Li\n  khar: UniversalShaper, // Kharoshthi\n  khoj: UniversalShaper, // Khojki\n  sind: UniversalShaper, // Khudawadi\n  lepc: UniversalShaper, // Lepcha\n  limb: UniversalShaper, // Limbu\n  mahj: UniversalShaper, // Mahajani\n  // mand: UniversalShaper, // Mandaic\n  // mani: UniversalShaper, // Manichaean\n  mtei: UniversalShaper, // Meitei Mayek\n  modi: UniversalShaper, // Modi\n  // mong: UniversalShaper, // Mongolian\n  // 'nko ': UniversalShaper, // N’Ko\n  hmng: UniversalShaper, // Pahawh Hmong\n  // phag: UniversalShaper, // Phags-pa\n  // phlp: UniversalShaper, // Psalter Pahlavi\n  rjng: UniversalShaper, // Rejang\n  saur: UniversalShaper, // Saurashtra\n  shrd: UniversalShaper, // Sharada\n  sidd: UniversalShaper, // Siddham\n  sinh: UniversalShaper, // Sinhala\n  sund: UniversalShaper, // Sundanese\n  sylo: UniversalShaper, // Syloti Nagri\n  tglg: UniversalShaper, // Tagalog\n  tagb: UniversalShaper, // Tagbanwa\n  tale: UniversalShaper, // Tai Le\n  lana: UniversalShaper, // Tai Tham\n  tavt: UniversalShaper, // Tai Viet\n  takr: UniversalShaper, // Takri\n  tibt: UniversalShaper, // Tibetan\n  tfng: UniversalShaper, // Tifinagh\n  tirh: UniversalShaper, // Tirhuta\n\n  latn: DefaultShaper, // Latin\n  DFLT: DefaultShaper // Default\n};\n\nfunction choose(script) {\n  if (!Array.isArray(script)) {\n    script = [script];\n  }\n\n  for (var _iterator = script, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n    var _ref;\n\n    if (_isArray) {\n      if (_i >= _iterator.length) break;\n      _ref = _iterator[_i++];\n    } else {\n      _i = _iterator.next();\n      if (_i.done) break;\n      _ref = _i.value;\n    }\n\n    var s = _ref;\n\n    var shaper = SHAPERS[s];\n    if (shaper) {\n      return shaper;\n    }\n  }\n\n  return DefaultShaper;\n}\n\nvar GSUBProcessor = function (_OTProcessor) {\n  _inherits(GSUBProcessor, _OTProcessor);\n\n  function GSUBProcessor() {\n    _classCallCheck(this, GSUBProcessor);\n\n    return _possibleConstructorReturn(this, _OTProcessor.apply(this, arguments));\n  }\n\n  GSUBProcessor.prototype.applyLookup = function applyLookup(lookupType, table) {\n    var _this2 = this;\n\n    switch (lookupType) {\n      case 1:\n        {\n          // Single Substitution\n          var index = this.coverageIndex(table.coverage);\n          if (index === -1) {\n            return false;\n          }\n\n          var glyph = this.glyphIterator.cur;\n          switch (table.version) {\n            case 1:\n              glyph.id = glyph.id + table.deltaGlyphID & 0xffff;\n              break;\n\n            case 2:\n              glyph.id = table.substitute.get(index);\n              break;\n          }\n\n          return true;\n        }\n\n      case 2:\n        {\n          // Multiple Substitution\n          var _index = this.coverageIndex(table.coverage);\n          if (_index !== -1) {\n            var _glyphs;\n\n            var sequence = table.sequences.get(_index);\n            this.glyphIterator.cur.id = sequence[0];\n            this.glyphIterator.cur.ligatureComponent = 0;\n\n            var features = this.glyphIterator.cur.features;\n            var curGlyph = this.glyphIterator.cur;\n            var replacement = sequence.slice(1).map(function (gid, i) {\n              var glyph = new GlyphInfo(_this2.font, gid, undefined, features);\n              glyph.shaperInfo = curGlyph.shaperInfo;\n              glyph.isLigated = curGlyph.isLigated;\n              glyph.ligatureComponent = i + 1;\n              glyph.substituted = true;\n              glyph.isMultiplied = true;\n              return glyph;\n            });\n\n            (_glyphs = this.glyphs).splice.apply(_glyphs, [this.glyphIterator.index + 1, 0].concat(replacement));\n            return true;\n          }\n\n          return false;\n        }\n\n      case 3:\n        {\n          // Alternate Substitution\n          var _index2 = this.coverageIndex(table.coverage);\n          if (_index2 !== -1) {\n            var USER_INDEX = 0; // TODO\n            this.glyphIterator.cur.id = table.alternateSet.get(_index2)[USER_INDEX];\n            return true;\n          }\n\n          return false;\n        }\n\n      case 4:\n        {\n          // Ligature Substitution\n          var _index3 = this.coverageIndex(table.coverage);\n          if (_index3 === -1) {\n            return false;\n          }\n\n          for (var _iterator = table.ligatureSets.get(_index3), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n            var _ref;\n\n            if (_isArray) {\n              if (_i >= _iterator.length) break;\n              _ref = _iterator[_i++];\n            } else {\n              _i = _iterator.next();\n              if (_i.done) break;\n              _ref = _i.value;\n            }\n\n            var ligature = _ref;\n\n            var matched = this.sequenceMatchIndices(1, ligature.components);\n            if (!matched) {\n              continue;\n            }\n\n            var _curGlyph = this.glyphIterator.cur;\n\n            // Concatenate all of the characters the new ligature will represent\n            var characters = _curGlyph.codePoints.slice();\n            for (var _iterator2 = matched, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n              var _ref2;\n\n              if (_isArray2) {\n                if (_i2 >= _iterator2.length) break;\n                _ref2 = _iterator2[_i2++];\n              } else {\n                _i2 = _iterator2.next();\n                if (_i2.done) break;\n                _ref2 = _i2.value;\n              }\n\n              var _index4 = _ref2;\n\n              characters.push.apply(characters, this.glyphs[_index4].codePoints);\n            }\n\n            // Create the replacement ligature glyph\n            var ligatureGlyph = new GlyphInfo(this.font, ligature.glyph, characters, _curGlyph.features);\n            ligatureGlyph.shaperInfo = _curGlyph.shaperInfo;\n            ligatureGlyph.isLigated = true;\n            ligatureGlyph.substituted = true;\n\n            // From Harfbuzz:\n            // - If it *is* a mark ligature, we don't allocate a new ligature id, and leave\n            //   the ligature to keep its old ligature id.  This will allow it to attach to\n            //   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,\n            //   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a\n            //   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature\n            //   later, we don't want them to lose their ligature id/component, otherwise\n            //   GPOS will fail to correctly position the mark ligature on top of the\n            //   LAM,LAM,HEH ligature. See https://bugzilla.gnome.org/show_bug.cgi?id=676343\n            //\n            // - If a ligature is formed of components that some of which are also ligatures\n            //   themselves, and those ligature components had marks attached to *their*\n            //   components, we have to attach the marks to the new ligature component\n            //   positions!  Now *that*'s tricky!  And these marks may be following the\n            //   last component of the whole sequence, so we should loop forward looking\n            //   for them and update them.\n            //\n            //   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a\n            //   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature\n            //   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature\n            //   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to\n            //   the new ligature with a component value of 2.\n            //\n            //   This in fact happened to a font...  See https://bugzilla.gnome.org/show_bug.cgi?id=437633\n            var isMarkLigature = _curGlyph.isMark;\n            for (var i = 0; i < matched.length && isMarkLigature; i++) {\n              isMarkLigature = this.glyphs[matched[i]].isMark;\n            }\n\n            ligatureGlyph.ligatureID = isMarkLigature ? null : this.ligatureID++;\n\n            var lastLigID = _curGlyph.ligatureID;\n            var lastNumComps = _curGlyph.codePoints.length;\n            var curComps = lastNumComps;\n            var idx = this.glyphIterator.index + 1;\n\n            // Set ligatureID and ligatureComponent on glyphs that were skipped in the matched sequence.\n            // This allows GPOS to attach marks to the correct ligature components.\n            for (var _iterator3 = matched, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n              var _ref3;\n\n              if (_isArray3) {\n                if (_i3 >= _iterator3.length) break;\n                _ref3 = _iterator3[_i3++];\n              } else {\n                _i3 = _iterator3.next();\n                if (_i3.done) break;\n                _ref3 = _i3.value;\n              }\n\n              var matchIndex = _ref3;\n\n              // Don't assign new ligature components for mark ligatures (see above)\n              if (isMarkLigature) {\n                idx = matchIndex;\n              } else {\n                while (idx < matchIndex) {\n                  var ligatureComponent = curComps - lastNumComps + Math.min(this.glyphs[idx].ligatureComponent || 1, lastNumComps);\n                  this.glyphs[idx].ligatureID = ligatureGlyph.ligatureID;\n                  this.glyphs[idx].ligatureComponent = ligatureComponent;\n                  idx++;\n                }\n              }\n\n              lastLigID = this.glyphs[idx].ligatureID;\n              lastNumComps = this.glyphs[idx].codePoints.length;\n              curComps += lastNumComps;\n              idx++; // skip base glyph\n            }\n\n            // Adjust ligature components for any marks following\n            if (lastLigID && !isMarkLigature) {\n              for (var _i4 = idx; _i4 < this.glyphs.length; _i4++) {\n                if (this.glyphs[_i4].ligatureID === lastLigID) {\n                  var ligatureComponent = curComps - lastNumComps + Math.min(this.glyphs[_i4].ligatureComponent || 1, lastNumComps);\n                  this.glyphs[_i4].ligatureComponent = ligatureComponent;\n                } else {\n                  break;\n                }\n              }\n            }\n\n            // Delete the matched glyphs, and replace the current glyph with the ligature glyph\n            for (var _i5 = matched.length - 1; _i5 >= 0; _i5--) {\n              this.glyphs.splice(matched[_i5], 1);\n            }\n\n            this.glyphs[this.glyphIterator.index] = ligatureGlyph;\n            return true;\n          }\n\n          return false;\n        }\n\n      case 5:\n        // Contextual Substitution\n        return this.applyContext(table);\n\n      case 6:\n        // Chaining Contextual Substitution\n        return this.applyChainingContext(table);\n\n      case 7:\n        // Extension Substitution\n        return this.applyLookup(table.lookupType, table.extension);\n\n      default:\n        throw new Error('GSUB lookupType ' + lookupType + ' is not supported');\n    }\n  };\n\n  return GSUBProcessor;\n}(OTProcessor);\n\nvar GPOSProcessor = function (_OTProcessor) {\n  _inherits(GPOSProcessor, _OTProcessor);\n\n  function GPOSProcessor() {\n    _classCallCheck(this, GPOSProcessor);\n\n    return _possibleConstructorReturn(this, _OTProcessor.apply(this, arguments));\n  }\n\n  GPOSProcessor.prototype.applyPositionValue = function applyPositionValue(sequenceIndex, value) {\n    var position = this.positions[this.glyphIterator.peekIndex(sequenceIndex)];\n    if (value.xAdvance != null) {\n      position.xAdvance += value.xAdvance;\n    }\n\n    if (value.yAdvance != null) {\n      position.yAdvance += value.yAdvance;\n    }\n\n    if (value.xPlacement != null) {\n      position.xOffset += value.xPlacement;\n    }\n\n    if (value.yPlacement != null) {\n      position.yOffset += value.yPlacement;\n    }\n\n    // Adjustments for font variations\n    var variationProcessor = this.font._variationProcessor;\n    var variationStore = this.font.GDEF && this.font.GDEF.itemVariationStore;\n    if (variationProcessor && variationStore) {\n      if (value.xPlaDevice) {\n        position.xOffset += variationProcessor.getDelta(variationStore, value.xPlaDevice.a, value.xPlaDevice.b);\n      }\n\n      if (value.yPlaDevice) {\n        position.yOffset += variationProcessor.getDelta(variationStore, value.yPlaDevice.a, value.yPlaDevice.b);\n      }\n\n      if (value.xAdvDevice) {\n        position.xAdvance += variationProcessor.getDelta(variationStore, value.xAdvDevice.a, value.xAdvDevice.b);\n      }\n\n      if (value.yAdvDevice) {\n        position.yAdvance += variationProcessor.getDelta(variationStore, value.yAdvDevice.a, value.yAdvDevice.b);\n      }\n    }\n\n    // TODO: device tables\n  };\n\n  GPOSProcessor.prototype.applyLookup = function applyLookup(lookupType, table) {\n    switch (lookupType) {\n      case 1:\n        {\n          // Single positioning value\n          var index = this.coverageIndex(table.coverage);\n          if (index === -1) {\n            return false;\n          }\n\n          switch (table.version) {\n            case 1:\n              this.applyPositionValue(0, table.value);\n              break;\n\n            case 2:\n              this.applyPositionValue(0, table.values.get(index));\n              break;\n          }\n\n          return true;\n        }\n\n      case 2:\n        {\n          // Pair Adjustment Positioning\n          var nextGlyph = this.glyphIterator.peek();\n          if (!nextGlyph) {\n            return false;\n          }\n\n          var _index = this.coverageIndex(table.coverage);\n          if (_index === -1) {\n            return false;\n          }\n\n          switch (table.version) {\n            case 1:\n              // Adjustments for glyph pairs\n              var set = table.pairSets.get(_index);\n\n              for (var _iterator = set, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n                var _ref;\n\n                if (_isArray) {\n                  if (_i >= _iterator.length) break;\n                  _ref = _iterator[_i++];\n                } else {\n                  _i = _iterator.next();\n                  if (_i.done) break;\n                  _ref = _i.value;\n                }\n\n                var _pair = _ref;\n\n                if (_pair.secondGlyph === nextGlyph.id) {\n                  this.applyPositionValue(0, _pair.value1);\n                  this.applyPositionValue(1, _pair.value2);\n                  return true;\n                }\n              }\n\n              return false;\n\n            case 2:\n              // Class pair adjustment\n              var class1 = this.getClassID(this.glyphIterator.cur.id, table.classDef1);\n              var class2 = this.getClassID(nextGlyph.id, table.classDef2);\n              if (class1 === -1 || class2 === -1) {\n                return false;\n              }\n\n              var pair = table.classRecords.get(class1).get(class2);\n              this.applyPositionValue(0, pair.value1);\n              this.applyPositionValue(1, pair.value2);\n              return true;\n          }\n        }\n\n      case 3:\n        {\n          // Cursive Attachment Positioning\n          var nextIndex = this.glyphIterator.peekIndex();\n          var _nextGlyph = this.glyphs[nextIndex];\n          if (!_nextGlyph) {\n            return false;\n          }\n\n          var curRecord = table.entryExitRecords[this.coverageIndex(table.coverage)];\n          if (!curRecord || !curRecord.exitAnchor) {\n            return false;\n          }\n\n          var nextRecord = table.entryExitRecords[this.coverageIndex(table.coverage, _nextGlyph.id)];\n          if (!nextRecord || !nextRecord.entryAnchor) {\n            return false;\n          }\n\n          var entry = this.getAnchor(nextRecord.entryAnchor);\n          var exit = this.getAnchor(curRecord.exitAnchor);\n\n          var cur = this.positions[this.glyphIterator.index];\n          var next = this.positions[nextIndex];\n\n          switch (this.direction) {\n            case 'ltr':\n              cur.xAdvance = exit.x + cur.xOffset;\n\n              var d = entry.x + next.xOffset;\n              next.xAdvance -= d;\n              next.xOffset -= d;\n              break;\n\n            case 'rtl':\n              d = exit.x + cur.xOffset;\n              cur.xAdvance -= d;\n              cur.xOffset -= d;\n              next.xAdvance = entry.x + next.xOffset;\n              break;\n          }\n\n          if (this.glyphIterator.flags.rightToLeft) {\n            this.glyphIterator.cur.cursiveAttachment = nextIndex;\n            cur.yOffset = entry.y - exit.y;\n          } else {\n            _nextGlyph.cursiveAttachment = this.glyphIterator.index;\n            cur.yOffset = exit.y - entry.y;\n          }\n\n          return true;\n        }\n\n      case 4:\n        {\n          // Mark to base positioning\n          var markIndex = this.coverageIndex(table.markCoverage);\n          if (markIndex === -1) {\n            return false;\n          }\n\n          // search backward for a base glyph\n          var baseGlyphIndex = this.glyphIterator.index;\n          while (--baseGlyphIndex >= 0 && (this.glyphs[baseGlyphIndex].isMark || this.glyphs[baseGlyphIndex].ligatureComponent > 0)) {}\n\n          if (baseGlyphIndex < 0) {\n            return false;\n          }\n\n          var baseIndex = this.coverageIndex(table.baseCoverage, this.glyphs[baseGlyphIndex].id);\n          if (baseIndex === -1) {\n            return false;\n          }\n\n          var markRecord = table.markArray[markIndex];\n          var baseAnchor = table.baseArray[baseIndex][markRecord.class];\n          this.applyAnchor(markRecord, baseAnchor, baseGlyphIndex);\n          return true;\n        }\n\n      case 5:\n        {\n          // Mark to ligature positioning\n          var _markIndex = this.coverageIndex(table.markCoverage);\n          if (_markIndex === -1) {\n            return false;\n          }\n\n          // search backward for a base glyph\n          var _baseGlyphIndex = this.glyphIterator.index;\n          while (--_baseGlyphIndex >= 0 && this.glyphs[_baseGlyphIndex].isMark) {}\n\n          if (_baseGlyphIndex < 0) {\n            return false;\n          }\n\n          var ligIndex = this.coverageIndex(table.ligatureCoverage, this.glyphs[_baseGlyphIndex].id);\n          if (ligIndex === -1) {\n            return false;\n          }\n\n          var ligAttach = table.ligatureArray[ligIndex];\n          var markGlyph = this.glyphIterator.cur;\n          var ligGlyph = this.glyphs[_baseGlyphIndex];\n          var compIndex = ligGlyph.ligatureID && ligGlyph.ligatureID === markGlyph.ligatureID && markGlyph.ligatureComponent > 0 ? Math.min(markGlyph.ligatureComponent, ligGlyph.codePoints.length) - 1 : ligGlyph.codePoints.length - 1;\n\n          var _markRecord = table.markArray[_markIndex];\n          var _baseAnchor = ligAttach[compIndex][_markRecord.class];\n          this.applyAnchor(_markRecord, _baseAnchor, _baseGlyphIndex);\n          return true;\n        }\n\n      case 6:\n        {\n          // Mark to mark positioning\n          var mark1Index = this.coverageIndex(table.mark1Coverage);\n          if (mark1Index === -1) {\n            return false;\n          }\n\n          // get the previous mark to attach to\n          var prevIndex = this.glyphIterator.peekIndex(-1);\n          var prev = this.glyphs[prevIndex];\n          if (!prev || !prev.isMark) {\n            return false;\n          }\n\n          var _cur = this.glyphIterator.cur;\n\n          // The following logic was borrowed from Harfbuzz\n          var good = false;\n          if (_cur.ligatureID === prev.ligatureID) {\n            if (!_cur.ligatureID) {\n              // Marks belonging to the same base\n              good = true;\n            } else if (_cur.ligatureComponent === prev.ligatureComponent) {\n              // Marks belonging to the same ligature component\n              good = true;\n            }\n          } else {\n            // If ligature ids don't match, it may be the case that one of the marks\n            // itself is a ligature, in which case match.\n            if (_cur.ligatureID && !_cur.ligatureComponent || prev.ligatureID && !prev.ligatureComponent) {\n              good = true;\n            }\n          }\n\n          if (!good) {\n            return false;\n          }\n\n          var mark2Index = this.coverageIndex(table.mark2Coverage, prev.id);\n          if (mark2Index === -1) {\n            return false;\n          }\n\n          var _markRecord2 = table.mark1Array[mark1Index];\n          var _baseAnchor2 = table.mark2Array[mark2Index][_markRecord2.class];\n          this.applyAnchor(_markRecord2, _baseAnchor2, prevIndex);\n          return true;\n        }\n\n      case 7:\n        // Contextual positioning\n        return this.applyContext(table);\n\n      case 8:\n        // Chaining contextual positioning\n        return this.applyChainingContext(table);\n\n      case 9:\n        // Extension positioning\n        return this.applyLookup(table.lookupType, table.extension);\n\n      default:\n        throw new Error('Unsupported GPOS table: ' + lookupType);\n    }\n  };\n\n  GPOSProcessor.prototype.applyAnchor = function applyAnchor(markRecord, baseAnchor, baseGlyphIndex) {\n    var baseCoords = this.getAnchor(baseAnchor);\n    var markCoords = this.getAnchor(markRecord.markAnchor);\n\n    var basePos = this.positions[baseGlyphIndex];\n    var markPos = this.positions[this.glyphIterator.index];\n\n    markPos.xOffset = baseCoords.x - markCoords.x;\n    markPos.yOffset = baseCoords.y - markCoords.y;\n    this.glyphIterator.cur.markAttachment = baseGlyphIndex;\n  };\n\n  GPOSProcessor.prototype.getAnchor = function getAnchor(anchor) {\n    // TODO: contour point, device tables\n    var x = anchor.xCoordinate;\n    var y = anchor.yCoordinate;\n\n    // Adjustments for font variations\n    var variationProcessor = this.font._variationProcessor;\n    var variationStore = this.font.GDEF && this.font.GDEF.itemVariationStore;\n    if (variationProcessor && variationStore) {\n      if (anchor.xDeviceTable) {\n        x += variationProcessor.getDelta(variationStore, anchor.xDeviceTable.a, anchor.xDeviceTable.b);\n      }\n\n      if (anchor.yDeviceTable) {\n        y += variationProcessor.getDelta(variationStore, anchor.yDeviceTable.a, anchor.yDeviceTable.b);\n      }\n    }\n\n    return { x: x, y: y };\n  };\n\n  GPOSProcessor.prototype.applyFeatures = function applyFeatures(userFeatures, glyphs, advances) {\n    _OTProcessor.prototype.applyFeatures.call(this, userFeatures, glyphs, advances);\n\n    for (var i = 0; i < this.glyphs.length; i++) {\n      this.fixCursiveAttachment(i);\n    }\n\n    this.fixMarkAttachment();\n  };\n\n  GPOSProcessor.prototype.fixCursiveAttachment = function fixCursiveAttachment(i) {\n    var glyph = this.glyphs[i];\n    if (glyph.cursiveAttachment != null) {\n      var j = glyph.cursiveAttachment;\n\n      glyph.cursiveAttachment = null;\n      this.fixCursiveAttachment(j);\n\n      this.positions[i].yOffset += this.positions[j].yOffset;\n    }\n  };\n\n  GPOSProcessor.prototype.fixMarkAttachment = function fixMarkAttachment() {\n    for (var i = 0; i < this.glyphs.length; i++) {\n      var glyph = this.glyphs[i];\n      if (glyph.markAttachment != null) {\n        var j = glyph.markAttachment;\n\n        this.positions[i].xOffset += this.positions[j].xOffset;\n        this.positions[i].yOffset += this.positions[j].yOffset;\n\n        if (this.direction === 'ltr') {\n          for (var k = j; k < i; k++) {\n            this.positions[i].xOffset -= this.positions[k].xAdvance;\n            this.positions[i].yOffset -= this.positions[k].yAdvance;\n          }\n        } else {\n          for (var _k = j + 1; _k < i + 1; _k++) {\n            this.positions[i].xOffset += this.positions[_k].xAdvance;\n            this.positions[i].yOffset += this.positions[_k].yAdvance;\n          }\n        }\n      }\n    }\n  };\n\n  return GPOSProcessor;\n}(OTProcessor);\n\nvar OTLayoutEngine = function () {\n  function OTLayoutEngine(font) {\n    _classCallCheck(this, OTLayoutEngine);\n\n    this.font = font;\n    this.glyphInfos = null;\n    this.plan = null;\n    this.GSUBProcessor = null;\n    this.GPOSProcessor = null;\n    this.fallbackPosition = true;\n\n    if (font.GSUB) {\n      this.GSUBProcessor = new GSUBProcessor(font, font.GSUB);\n    }\n\n    if (font.GPOS) {\n      this.GPOSProcessor = new GPOSProcessor(font, font.GPOS);\n    }\n  }\n\n  OTLayoutEngine.prototype.setup = function setup(glyphRun) {\n    var _this = this;\n\n    // Map glyphs to GlyphInfo objects so data can be passed between\n    // GSUB and GPOS without mutating the real (shared) Glyph objects.\n    this.glyphInfos = glyphRun.glyphs.map(function (glyph) {\n      return new GlyphInfo(_this.font, glyph.id, [].concat(glyph.codePoints));\n    });\n\n    // Select a script based on what is available in GSUB/GPOS.\n    var script = null;\n    if (this.GPOSProcessor) {\n      script = this.GPOSProcessor.selectScript(glyphRun.script, glyphRun.language, glyphRun.direction);\n    }\n\n    if (this.GSUBProcessor) {\n      script = this.GSUBProcessor.selectScript(glyphRun.script, glyphRun.language, glyphRun.direction);\n    }\n\n    // Choose a shaper based on the script, and setup a shaping plan.\n    // This determines which features to apply to which glyphs.\n    this.shaper = choose(script);\n    this.plan = new ShapingPlan(this.font, script, glyphRun.direction);\n    this.shaper.plan(this.plan, this.glyphInfos, glyphRun.features);\n\n    // Assign chosen features to output glyph run\n    for (var key in this.plan.allFeatures) {\n      glyphRun.features[key] = true;\n    }\n  };\n\n  OTLayoutEngine.prototype.substitute = function substitute(glyphRun) {\n    var _this2 = this;\n\n    if (this.GSUBProcessor) {\n      this.plan.process(this.GSUBProcessor, this.glyphInfos);\n\n      // Map glyph infos back to normal Glyph objects\n      glyphRun.glyphs = this.glyphInfos.map(function (glyphInfo) {\n        return _this2.font.getGlyph(glyphInfo.id, glyphInfo.codePoints);\n      });\n    }\n  };\n\n  OTLayoutEngine.prototype.position = function position(glyphRun) {\n    if (this.shaper.zeroMarkWidths === 'BEFORE_GPOS') {\n      this.zeroMarkAdvances(glyphRun.positions);\n    }\n\n    if (this.GPOSProcessor) {\n      this.plan.process(this.GPOSProcessor, this.glyphInfos, glyphRun.positions);\n    }\n\n    if (this.shaper.zeroMarkWidths === 'AFTER_GPOS') {\n      this.zeroMarkAdvances(glyphRun.positions);\n    }\n\n    // Reverse the glyphs and positions if the script is right-to-left\n    if (glyphRun.direction === 'rtl') {\n      glyphRun.glyphs.reverse();\n      glyphRun.positions.reverse();\n    }\n\n    return this.GPOSProcessor && this.GPOSProcessor.features;\n  };\n\n  OTLayoutEngine.prototype.zeroMarkAdvances = function zeroMarkAdvances(positions) {\n    for (var i = 0; i < this.glyphInfos.length; i++) {\n      if (this.glyphInfos[i].isMark) {\n        positions[i].xAdvance = 0;\n        positions[i].yAdvance = 0;\n      }\n    }\n  };\n\n  OTLayoutEngine.prototype.cleanup = function cleanup() {\n    this.glyphInfos = null;\n    this.plan = null;\n    this.shaper = null;\n  };\n\n  OTLayoutEngine.prototype.getAvailableFeatures = function getAvailableFeatures(script, language) {\n    var features = [];\n\n    if (this.GSUBProcessor) {\n      this.GSUBProcessor.selectScript(script, language);\n      features.push.apply(features, _Object$keys(this.GSUBProcessor.features));\n    }\n\n    if (this.GPOSProcessor) {\n      this.GPOSProcessor.selectScript(script, language);\n      features.push.apply(features, _Object$keys(this.GPOSProcessor.features));\n    }\n\n    return features;\n  };\n\n  return OTLayoutEngine;\n}();\n\nvar LayoutEngine = function () {\n  function LayoutEngine(font) {\n    _classCallCheck(this, LayoutEngine);\n\n    this.font = font;\n    this.unicodeLayoutEngine = null;\n    this.kernProcessor = null;\n\n    // Choose an advanced layout engine. We try the AAT morx table first since more\n    // scripts are currently supported because the shaping logic is built into the font.\n    if (this.font.morx) {\n      this.engine = new AATLayoutEngine(this.font);\n    } else if (this.font.GSUB || this.font.GPOS) {\n      this.engine = new OTLayoutEngine(this.font);\n    }\n  }\n\n  LayoutEngine.prototype.layout = function layout(string, features, script, language, direction) {\n    // Make the features parameter optional\n    if (typeof features === 'string') {\n      direction = language;\n      language = script;\n      script = features;\n      features = [];\n    }\n\n    // Map string to glyphs if needed\n    if (typeof string === 'string') {\n      // Attempt to detect the script from the string if not provided.\n      if (script == null) {\n        script = forString(string);\n      }\n\n      var glyphs = this.font.glyphsForString(string);\n    } else {\n      // Attempt to detect the script from the glyph code points if not provided.\n      if (script == null) {\n        var codePoints = [];\n        for (var _iterator = string, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n          var _ref;\n\n          if (_isArray) {\n            if (_i >= _iterator.length) break;\n            _ref = _iterator[_i++];\n          } else {\n            _i = _iterator.next();\n            if (_i.done) break;\n            _ref = _i.value;\n          }\n\n          var glyph = _ref;\n\n          codePoints.push.apply(codePoints, glyph.codePoints);\n        }\n\n        script = forCodePoints(codePoints);\n      }\n\n      var glyphs = string;\n    }\n\n    var glyphRun = new GlyphRun(glyphs, features, script, language, direction);\n\n    // Return early if there are no glyphs\n    if (glyphs.length === 0) {\n      glyphRun.positions = [];\n      return glyphRun;\n    }\n\n    // Setup the advanced layout engine\n    if (this.engine && this.engine.setup) {\n      this.engine.setup(glyphRun);\n    }\n\n    // Substitute and position the glyphs\n    this.substitute(glyphRun);\n    this.position(glyphRun);\n\n    this.hideDefaultIgnorables(glyphRun.glyphs, glyphRun.positions);\n\n    // Let the layout engine clean up any state it might have\n    if (this.engine && this.engine.cleanup) {\n      this.engine.cleanup();\n    }\n\n    return glyphRun;\n  };\n\n  LayoutEngine.prototype.substitute = function substitute(glyphRun) {\n    // Call the advanced layout engine to make substitutions\n    if (this.engine && this.engine.substitute) {\n      this.engine.substitute(glyphRun);\n    }\n  };\n\n  LayoutEngine.prototype.position = function position(glyphRun) {\n    // Get initial glyph positions\n    glyphRun.positions = glyphRun.glyphs.map(function (glyph) {\n      return new GlyphPosition(glyph.advanceWidth);\n    });\n    var positioned = null;\n\n    // Call the advanced layout engine. Returns the features applied.\n    if (this.engine && this.engine.position) {\n      positioned = this.engine.position(glyphRun);\n    }\n\n    // if there is no GPOS table, use unicode properties to position marks.\n    if (!positioned && (!this.engine || this.engine.fallbackPosition)) {\n      if (!this.unicodeLayoutEngine) {\n        this.unicodeLayoutEngine = new UnicodeLayoutEngine(this.font);\n      }\n\n      this.unicodeLayoutEngine.positionGlyphs(glyphRun.glyphs, glyphRun.positions);\n    }\n\n    // if kerning is not supported by GPOS, do kerning with the TrueType/AAT kern table\n    if ((!positioned || !positioned.kern) && glyphRun.features.kern !== false && this.font.kern) {\n      if (!this.kernProcessor) {\n        this.kernProcessor = new KernProcessor(this.font);\n      }\n\n      this.kernProcessor.process(glyphRun.glyphs, glyphRun.positions);\n      glyphRun.features.kern = true;\n    }\n  };\n\n  LayoutEngine.prototype.hideDefaultIgnorables = function hideDefaultIgnorables(glyphs, positions) {\n    var space = this.font.glyphForCodePoint(0x20);\n    for (var i = 0; i < glyphs.length; i++) {\n      if (this.isDefaultIgnorable(glyphs[i].codePoints[0])) {\n        glyphs[i] = space;\n        positions[i].xAdvance = 0;\n        positions[i].yAdvance = 0;\n      }\n    }\n  };\n\n  LayoutEngine.prototype.isDefaultIgnorable = function isDefaultIgnorable(ch) {\n    // From DerivedCoreProperties.txt in the Unicode database,\n    // minus U+115F, U+1160, U+3164 and U+FFA0, which is what\n    // Harfbuzz and Uniscribe do.\n    var plane = ch >> 16;\n    if (plane === 0) {\n      // BMP\n      switch (ch >> 8) {\n        case 0x00:\n          return ch === 0x00AD;\n        case 0x03:\n          return ch === 0x034F;\n        case 0x06:\n          return ch === 0x061C;\n        case 0x17:\n          return 0x17B4 <= ch && ch <= 0x17B5;\n        case 0x18:\n          return 0x180B <= ch && ch <= 0x180E;\n        case 0x20:\n          return 0x200B <= ch && ch <= 0x200F || 0x202A <= ch && ch <= 0x202E || 0x2060 <= ch && ch <= 0x206F;\n        case 0xFE:\n          return 0xFE00 <= ch && ch <= 0xFE0F || ch === 0xFEFF;\n        case 0xFF:\n          return 0xFFF0 <= ch && ch <= 0xFFF8;\n        default:\n          return false;\n      }\n    } else {\n      // Other planes\n      switch (plane) {\n        case 0x01:\n          return 0x1BCA0 <= ch && ch <= 0x1BCA3 || 0x1D173 <= ch && ch <= 0x1D17A;\n        case 0x0E:\n          return 0xE0000 <= ch && ch <= 0xE0FFF;\n        default:\n          return false;\n      }\n    }\n  };\n\n  LayoutEngine.prototype.getAvailableFeatures = function getAvailableFeatures(script, language) {\n    var features = [];\n\n    if (this.engine) {\n      features.push.apply(features, this.engine.getAvailableFeatures(script, language));\n    }\n\n    if (this.font.kern && features.indexOf('kern') === -1) {\n      features.push('kern');\n    }\n\n    return features;\n  };\n\n  LayoutEngine.prototype.stringsForGlyph = function stringsForGlyph(gid) {\n    var result = new _Set();\n\n    var codePoints = this.font._cmapProcessor.codePointsForGlyph(gid);\n    for (var _iterator2 = codePoints, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n      var _ref2;\n\n      if (_isArray2) {\n        if (_i2 >= _iterator2.length) break;\n        _ref2 = _iterator2[_i2++];\n      } else {\n        _i2 = _iterator2.next();\n        if (_i2.done) break;\n        _ref2 = _i2.value;\n      }\n\n      var codePoint = _ref2;\n\n      result.add(_String$fromCodePoint(codePoint));\n    }\n\n    if (this.engine && this.engine.stringsForGlyph) {\n      for (var _iterator3 = this.engine.stringsForGlyph(gid), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n        var _ref3;\n\n        if (_isArray3) {\n          if (_i3 >= _iterator3.length) break;\n          _ref3 = _iterator3[_i3++];\n        } else {\n          _i3 = _iterator3.next();\n          if (_i3.done) break;\n          _ref3 = _i3.value;\n        }\n\n        var string = _ref3;\n\n        result.add(string);\n      }\n    }\n\n    return _Array$from(result);\n  };\n\n  return LayoutEngine;\n}();\n\nvar SVG_COMMANDS = {\n  moveTo: 'M',\n  lineTo: 'L',\n  quadraticCurveTo: 'Q',\n  bezierCurveTo: 'C',\n  closePath: 'Z'\n};\n\n/**\n * Path objects are returned by glyphs and represent the actual\n * vector outlines for each glyph in the font. Paths can be converted\n * to SVG path data strings, or to functions that can be applied to\n * render the path to a graphics context.\n */\n\nvar Path = function () {\n  function Path() {\n    _classCallCheck(this, Path);\n\n    this.commands = [];\n    this._bbox = null;\n    this._cbox = null;\n  }\n\n  /**\n   * Compiles the path to a JavaScript function that can be applied with\n   * a graphics context in order to render the path.\n   * @return {string}\n   */\n\n\n  Path.prototype.toFunction = function toFunction() {\n    var cmds = this.commands.map(function (c) {\n      return '  ctx.' + c.command + '(' + c.args.join(', ') + ');';\n    });\n    return new Function('ctx', cmds.join('\\n'));\n  };\n\n  /**\n   * Converts the path to an SVG path data string\n   * @return {string}\n   */\n\n\n  Path.prototype.toSVG = function toSVG() {\n    var cmds = this.commands.map(function (c) {\n      var args = c.args.map(function (arg) {\n        return Math.round(arg * 100) / 100;\n      });\n      return '' + SVG_COMMANDS[c.command] + args.join(' ');\n    });\n\n    return cmds.join('');\n  };\n\n  /**\n   * Gets the \"control box\" of a path.\n   * This is like the bounding box, but it includes all points including\n   * control points of bezier segments and is much faster to compute than\n   * the real bounding box.\n   * @type {BBox}\n   */\n\n\n  /**\n   * Applies a mapping function to each point in the path.\n   * @param {function} fn\n   * @return {Path}\n   */\n  Path.prototype.mapPoints = function mapPoints(fn) {\n    var path = new Path();\n\n    for (var _iterator = this.commands, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var c = _ref;\n\n      var args = [];\n      for (var _i2 = 0; _i2 < c.args.length; _i2 += 2) {\n        var _fn = fn(c.args[_i2], c.args[_i2 + 1]),\n            x = _fn[0],\n            y = _fn[1];\n\n        args.push(x, y);\n      }\n\n      path[c.command].apply(path, args);\n    }\n\n    return path;\n  };\n\n  /**\n   * Transforms the path by the given matrix.\n   */\n\n\n  Path.prototype.transform = function transform(m0, m1, m2, m3, m4, m5) {\n    return this.mapPoints(function (x, y) {\n      x = m0 * x + m2 * y + m4;\n      y = m1 * x + m3 * y + m5;\n      return [x, y];\n    });\n  };\n\n  /**\n   * Translates the path by the given offset.\n   */\n\n\n  Path.prototype.translate = function translate(x, y) {\n    return this.transform(1, 0, 0, 1, x, y);\n  };\n\n  /**\n   * Rotates the path by the given angle (in radians).\n   */\n\n\n  Path.prototype.rotate = function rotate(angle) {\n    var cos = Math.cos(angle);\n    var sin = Math.sin(angle);\n    return this.transform(cos, sin, -sin, cos, 0, 0);\n  };\n\n  /**\n   * Scales the path.\n   */\n\n\n  Path.prototype.scale = function scale(scaleX) {\n    var scaleY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : scaleX;\n\n    return this.transform(scaleX, 0, 0, scaleY, 0, 0);\n  };\n\n  _createClass(Path, [{\n    key: 'cbox',\n    get: function get() {\n      if (!this._cbox) {\n        var cbox = new BBox();\n        for (var _iterator2 = this.commands, _isArray2 = Array.isArray(_iterator2), _i3 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n          var _ref2;\n\n          if (_isArray2) {\n            if (_i3 >= _iterator2.length) break;\n            _ref2 = _iterator2[_i3++];\n          } else {\n            _i3 = _iterator2.next();\n            if (_i3.done) break;\n            _ref2 = _i3.value;\n          }\n\n          var command = _ref2;\n\n          for (var _i4 = 0; _i4 < command.args.length; _i4 += 2) {\n            cbox.addPoint(command.args[_i4], command.args[_i4 + 1]);\n          }\n        }\n\n        this._cbox = _Object$freeze(cbox);\n      }\n\n      return this._cbox;\n    }\n\n    /**\n     * Gets the exact bounding box of the path by evaluating curve segments.\n     * Slower to compute than the control box, but more accurate.\n     * @type {BBox}\n     */\n\n  }, {\n    key: 'bbox',\n    get: function get() {\n      if (this._bbox) {\n        return this._bbox;\n      }\n\n      var bbox = new BBox();\n      var cx = 0,\n          cy = 0;\n\n      var f = function f(t) {\n        return Math.pow(1 - t, 3) * p0[i] + 3 * Math.pow(1 - t, 2) * t * p1[i] + 3 * (1 - t) * Math.pow(t, 2) * p2[i] + Math.pow(t, 3) * p3[i];\n      };\n\n      for (var _iterator3 = this.commands, _isArray3 = Array.isArray(_iterator3), _i5 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n        var _ref3;\n\n        if (_isArray3) {\n          if (_i5 >= _iterator3.length) break;\n          _ref3 = _iterator3[_i5++];\n        } else {\n          _i5 = _iterator3.next();\n          if (_i5.done) break;\n          _ref3 = _i5.value;\n        }\n\n        var c = _ref3;\n\n        switch (c.command) {\n          case 'moveTo':\n          case 'lineTo':\n            var _c$args = c.args,\n                x = _c$args[0],\n                y = _c$args[1];\n\n            bbox.addPoint(x, y);\n            cx = x;\n            cy = y;\n            break;\n\n          case 'quadraticCurveTo':\n          case 'bezierCurveTo':\n            if (c.command === 'quadraticCurveTo') {\n              // http://fontforge.org/bezier.html\n              var _c$args2 = c.args,\n                  qp1x = _c$args2[0],\n                  qp1y = _c$args2[1],\n                  p3x = _c$args2[2],\n                  p3y = _c$args2[3];\n\n              var cp1x = cx + 2 / 3 * (qp1x - cx); // CP1 = QP0 + 2/3 * (QP1-QP0)\n              var cp1y = cy + 2 / 3 * (qp1y - cy);\n              var cp2x = p3x + 2 / 3 * (qp1x - p3x); // CP2 = QP2 + 2/3 * (QP1-QP2)\n              var cp2y = p3y + 2 / 3 * (qp1y - p3y);\n            } else {\n              var _c$args3 = c.args,\n                  cp1x = _c$args3[0],\n                  cp1y = _c$args3[1],\n                  cp2x = _c$args3[2],\n                  cp2y = _c$args3[3],\n                  p3x = _c$args3[4],\n                  p3y = _c$args3[5];\n            }\n\n            // http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html\n            bbox.addPoint(p3x, p3y);\n\n            var p0 = [cx, cy];\n            var p1 = [cp1x, cp1y];\n            var p2 = [cp2x, cp2y];\n            var p3 = [p3x, p3y];\n\n            for (var i = 0; i <= 1; i++) {\n              var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i];\n              var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i];\n              c = 3 * p1[i] - 3 * p0[i];\n\n              if (a === 0) {\n                if (b === 0) {\n                  continue;\n                }\n\n                var t = -c / b;\n                if (0 < t && t < 1) {\n                  if (i === 0) {\n                    bbox.addPoint(f(t), bbox.maxY);\n                  } else if (i === 1) {\n                    bbox.addPoint(bbox.maxX, f(t));\n                  }\n                }\n\n                continue;\n              }\n\n              var b2ac = Math.pow(b, 2) - 4 * c * a;\n              if (b2ac < 0) {\n                continue;\n              }\n\n              var t1 = (-b + Math.sqrt(b2ac)) / (2 * a);\n              if (0 < t1 && t1 < 1) {\n                if (i === 0) {\n                  bbox.addPoint(f(t1), bbox.maxY);\n                } else if (i === 1) {\n                  bbox.addPoint(bbox.maxX, f(t1));\n                }\n              }\n\n              var t2 = (-b - Math.sqrt(b2ac)) / (2 * a);\n              if (0 < t2 && t2 < 1) {\n                if (i === 0) {\n                  bbox.addPoint(f(t2), bbox.maxY);\n                } else if (i === 1) {\n                  bbox.addPoint(bbox.maxX, f(t2));\n                }\n              }\n            }\n\n            cx = p3x;\n            cy = p3y;\n            break;\n        }\n      }\n\n      return this._bbox = _Object$freeze(bbox);\n    }\n  }]);\n\n  return Path;\n}();\n\nvar _arr = ['moveTo', 'lineTo', 'quadraticCurveTo', 'bezierCurveTo', 'closePath'];\n\nvar _loop = function _loop() {\n  var command = _arr[_i6];\n  Path.prototype[command] = function () {\n    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {\n      args[_key] = arguments[_key];\n    }\n\n    this._bbox = this._cbox = null;\n    this.commands.push({\n      command: command,\n      args: args\n    });\n\n    return this;\n  };\n};\n\nfor (var _i6 = 0; _i6 < _arr.length; _i6++) {\n  _loop();\n}\n\nvar StandardNames = ['.notdef', '.null', 'nonmarkingreturn', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', 'Ntilde', 'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex', 'adieresis', 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', 'edieresis', 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', 'oacute', 'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave', 'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section', 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', 'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus', 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff', 'summation', 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis', 'nonbreakingspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash', 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction', 'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered', 'quotesinglbase', 'quotedblbase', 'perthousand', 'Acircumflex', 'Ecircumflex', 'Aacute', 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', 'Ocircumflex', 'apple', 'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi', 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', 'Lslash', 'lslash', 'Scaron', 'scaron', 'Zcaron', 'zcaron', 'brokenbar', 'Eth', 'eth', 'Yacute', 'yacute', 'Thorn', 'thorn', 'minus', 'multiply', 'onesuperior', 'twosuperior', 'threesuperior', 'onehalf', 'onequarter', 'threequarters', 'franc', 'Gbreve', 'gbreve', 'Idotaccent', 'Scedilla', 'scedilla', 'Cacute', 'cacute', 'Ccaron', 'ccaron', 'dcroat'];\n\nvar _class$8;\nfunction _applyDecoratedDescriptor$4(target, property, decorators, descriptor, context) {\n  var desc = {};\n  Object['ke' + 'ys'](descriptor).forEach(function (key) {\n    desc[key] = descriptor[key];\n  });\n  desc.enumerable = !!desc.enumerable;\n  desc.configurable = !!desc.configurable;\n\n  if ('value' in desc || desc.initializer) {\n    desc.writable = true;\n  }\n\n  desc = decorators.slice().reverse().reduce(function (desc, decorator) {\n    return decorator(target, property, desc) || desc;\n  }, desc);\n\n  if (context && desc.initializer !== void 0) {\n    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;\n    desc.initializer = undefined;\n  }\n\n  if (desc.initializer === void 0) {\n    Object['define' + 'Property'](target, property, desc);\n    desc = null;\n  }\n\n  return desc;\n}\n\n/**\n * Glyph objects represent a glyph in the font. They have various properties for accessing metrics and\n * the actual vector path the glyph represents, and methods for rendering the glyph to a graphics context.\n *\n * You do not create glyph objects directly. They are created by various methods on the font object.\n * There are several subclasses of the base Glyph class internally that may be returned depending\n * on the font format, but they all inherit from this class.\n */\nvar Glyph = (_class$8 = function () {\n  function Glyph(id, codePoints, font) {\n    _classCallCheck(this, Glyph);\n\n    /**\n     * The glyph id in the font\n     * @type {number}\n     */\n    this.id = id;\n\n    /**\n     * An array of unicode code points that are represented by this glyph.\n     * There can be multiple code points in the case of ligatures and other glyphs\n     * that represent multiple visual characters.\n     * @type {number[]}\n     */\n    this.codePoints = codePoints;\n    this._font = font;\n\n    // TODO: get this info from GDEF if available\n    this.isMark = this.codePoints.every(unicode.isMark);\n    this.isLigature = this.codePoints.length > 1;\n  }\n\n  Glyph.prototype._getPath = function _getPath() {\n    return new Path();\n  };\n\n  Glyph.prototype._getCBox = function _getCBox() {\n    return this.path.cbox;\n  };\n\n  Glyph.prototype._getBBox = function _getBBox() {\n    return this.path.bbox;\n  };\n\n  Glyph.prototype._getTableMetrics = function _getTableMetrics(table) {\n    if (this.id < table.metrics.length) {\n      return table.metrics.get(this.id);\n    }\n\n    var metric = table.metrics.get(table.metrics.length - 1);\n    var res = {\n      advance: metric ? metric.advance : 0,\n      bearing: table.bearings.get(this.id - table.metrics.length) || 0\n    };\n\n    return res;\n  };\n\n  Glyph.prototype._getMetrics = function _getMetrics(cbox) {\n    if (this._metrics) {\n      return this._metrics;\n    }\n\n    var _getTableMetrics2 = this._getTableMetrics(this._font.hmtx),\n        advanceWidth = _getTableMetrics2.advance,\n        leftBearing = _getTableMetrics2.bearing;\n\n    // For vertical metrics, use vmtx if available, or fall back to global data from OS/2 or hhea\n\n\n    if (this._font.vmtx) {\n      var _getTableMetrics3 = this._getTableMetrics(this._font.vmtx),\n          advanceHeight = _getTableMetrics3.advance,\n          topBearing = _getTableMetrics3.bearing;\n    } else {\n      var os2 = void 0;\n      if (typeof cbox === 'undefined' || cbox === null) {\n        cbox = this.cbox;\n      }\n\n      if ((os2 = this._font['OS/2']) && os2.version > 0) {\n        var advanceHeight = Math.abs(os2.typoAscender - os2.typoDescender);\n        var topBearing = os2.typoAscender - cbox.maxY;\n      } else {\n        var hhea = this._font.hhea;\n\n        var advanceHeight = Math.abs(hhea.ascent - hhea.descent);\n        var topBearing = hhea.ascent - cbox.maxY;\n      }\n    }\n\n    if (this._font._variationProcessor && this._font.HVAR) {\n      advanceWidth += this._font._variationProcessor.getAdvanceAdjustment(this.id, this._font.HVAR);\n    }\n\n    return this._metrics = { advanceWidth: advanceWidth, advanceHeight: advanceHeight, leftBearing: leftBearing, topBearing: topBearing };\n  };\n\n  /**\n   * The glyph’s control box.\n   * This is often the same as the bounding box, but is faster to compute.\n   * Because of the way bezier curves are defined, some of the control points\n   * can be outside of the bounding box. Where `bbox` takes this into account,\n   * `cbox` does not. Thus, cbox is less accurate, but faster to compute.\n   * See [here](http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-2)\n   * for a more detailed description.\n   *\n   * @type {BBox}\n   */\n\n\n  /**\n   * Returns a path scaled to the given font size.\n   * @param {number} size\n   * @return {Path}\n   */\n  Glyph.prototype.getScaledPath = function getScaledPath(size) {\n    var scale = 1 / this._font.unitsPerEm * size;\n    return this.path.scale(scale);\n  };\n\n  /**\n   * The glyph's advance width.\n   * @type {number}\n   */\n\n\n  Glyph.prototype._getName = function _getName() {\n    var post = this._font.post;\n\n    if (!post) {\n      return null;\n    }\n\n    switch (post.version) {\n      case 1:\n        return StandardNames[this.id];\n\n      case 2:\n        var id = post.glyphNameIndex[this.id];\n        if (id < StandardNames.length) {\n          return StandardNames[id];\n        }\n\n        return post.names[id - StandardNames.length];\n\n      case 2.5:\n        return StandardNames[this.id + post.offsets[this.id]];\n\n      case 4:\n        return String.fromCharCode(post.map[this.id]);\n    }\n  };\n\n  /**\n   * The glyph's name\n   * @type {string}\n   */\n\n\n  /**\n   * Renders the glyph to the given graphics context, at the specified font size.\n   * @param {CanvasRenderingContext2d} ctx\n   * @param {number} size\n   */\n  Glyph.prototype.render = function render(ctx, size) {\n    ctx.save();\n\n    var scale = 1 / this._font.head.unitsPerEm * size;\n    ctx.scale(scale, scale);\n\n    var fn = this.path.toFunction();\n    fn(ctx);\n    ctx.fill();\n\n    ctx.restore();\n  };\n\n  _createClass(Glyph, [{\n    key: 'cbox',\n    get: function get() {\n      return this._getCBox();\n    }\n\n    /**\n     * The glyph’s bounding box, i.e. the rectangle that encloses the\n     * glyph outline as tightly as possible.\n     * @type {BBox}\n     */\n\n  }, {\n    key: 'bbox',\n    get: function get() {\n      return this._getBBox();\n    }\n\n    /**\n     * A vector Path object representing the glyph outline.\n     * @type {Path}\n     */\n\n  }, {\n    key: 'path',\n    get: function get() {\n      // Cache the path so we only decode it once\n      // Decoding is actually performed by subclasses\n      return this._getPath();\n    }\n  }, {\n    key: 'advanceWidth',\n    get: function get() {\n      return this._getMetrics().advanceWidth;\n    }\n\n    /**\n     * The glyph's advance height.\n     * @type {number}\n     */\n\n  }, {\n    key: 'advanceHeight',\n    get: function get() {\n      return this._getMetrics().advanceHeight;\n    }\n  }, {\n    key: 'ligatureCaretPositions',\n    get: function get() {}\n  }, {\n    key: 'name',\n    get: function get() {\n      return this._getName();\n    }\n  }]);\n\n  return Glyph;\n}(), (_applyDecoratedDescriptor$4(_class$8.prototype, 'cbox', [cache], _Object$getOwnPropertyDescriptor(_class$8.prototype, 'cbox'), _class$8.prototype), _applyDecoratedDescriptor$4(_class$8.prototype, 'bbox', [cache], _Object$getOwnPropertyDescriptor(_class$8.prototype, 'bbox'), _class$8.prototype), _applyDecoratedDescriptor$4(_class$8.prototype, 'path', [cache], _Object$getOwnPropertyDescriptor(_class$8.prototype, 'path'), _class$8.prototype), _applyDecoratedDescriptor$4(_class$8.prototype, 'advanceWidth', [cache], _Object$getOwnPropertyDescriptor(_class$8.prototype, 'advanceWidth'), _class$8.prototype), _applyDecoratedDescriptor$4(_class$8.prototype, 'advanceHeight', [cache], _Object$getOwnPropertyDescriptor(_class$8.prototype, 'advanceHeight'), _class$8.prototype), _applyDecoratedDescriptor$4(_class$8.prototype, 'name', [cache], _Object$getOwnPropertyDescriptor(_class$8.prototype, 'name'), _class$8.prototype)), _class$8);\n\n// The header for both simple and composite glyphs\nvar GlyfHeader = new r.Struct({\n  numberOfContours: r.int16, // if negative, this is a composite glyph\n  xMin: r.int16,\n  yMin: r.int16,\n  xMax: r.int16,\n  yMax: r.int16\n});\n\n// Flags for simple glyphs\nvar ON_CURVE = 1 << 0;\nvar X_SHORT_VECTOR = 1 << 1;\nvar Y_SHORT_VECTOR = 1 << 2;\nvar REPEAT = 1 << 3;\nvar SAME_X = 1 << 4;\nvar SAME_Y = 1 << 5;\n\n// Flags for composite glyphs\nvar ARG_1_AND_2_ARE_WORDS = 1 << 0;\nvar WE_HAVE_A_SCALE = 1 << 3;\nvar MORE_COMPONENTS = 1 << 5;\nvar WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;\nvar WE_HAVE_A_TWO_BY_TWO = 1 << 7;\nvar WE_HAVE_INSTRUCTIONS = 1 << 8;\n// Represents a point in a simple glyph\nvar Point = function () {\n  function Point(onCurve, endContour) {\n    var x = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n    var y = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;\n\n    _classCallCheck(this, Point);\n\n    this.onCurve = onCurve;\n    this.endContour = endContour;\n    this.x = x;\n    this.y = y;\n  }\n\n  Point.prototype.copy = function copy() {\n    return new Point(this.onCurve, this.endContour, this.x, this.y);\n  };\n\n  return Point;\n}();\n\n// Represents a component in a composite glyph\n\nvar Component = function Component(glyphID, dx, dy) {\n  _classCallCheck(this, Component);\n\n  this.glyphID = glyphID;\n  this.dx = dx;\n  this.dy = dy;\n  this.pos = 0;\n  this.scaleX = this.scaleY = 1;\n  this.scale01 = this.scale10 = 0;\n};\n\n/**\n * Represents a TrueType glyph.\n */\n\n\nvar TTFGlyph = function (_Glyph) {\n  _inherits(TTFGlyph, _Glyph);\n\n  function TTFGlyph() {\n    _classCallCheck(this, TTFGlyph);\n\n    return _possibleConstructorReturn(this, _Glyph.apply(this, arguments));\n  }\n\n  // Parses just the glyph header and returns the bounding box\n  TTFGlyph.prototype._getCBox = function _getCBox(internal) {\n    // We need to decode the glyph if variation processing is requested,\n    // so it's easier just to recompute the path's cbox after decoding.\n    if (this._font._variationProcessor && !internal) {\n      return this.path.cbox;\n    }\n\n    var stream = this._font._getTableStream('glyf');\n    stream.pos += this._font.loca.offsets[this.id];\n    var glyph = GlyfHeader.decode(stream);\n\n    var cbox = new BBox(glyph.xMin, glyph.yMin, glyph.xMax, glyph.yMax);\n    return _Object$freeze(cbox);\n  };\n\n  // Parses a single glyph coordinate\n\n\n  TTFGlyph.prototype._parseGlyphCoord = function _parseGlyphCoord(stream, prev, short, same) {\n    if (short) {\n      var val = stream.readUInt8();\n      if (!same) {\n        val = -val;\n      }\n\n      val += prev;\n    } else {\n      if (same) {\n        var val = prev;\n      } else {\n        var val = prev + stream.readInt16BE();\n      }\n    }\n\n    return val;\n  };\n\n  // Decodes the glyph data into points for simple glyphs,\n  // or components for composite glyphs\n\n\n  TTFGlyph.prototype._decode = function _decode() {\n    var glyfPos = this._font.loca.offsets[this.id];\n    var nextPos = this._font.loca.offsets[this.id + 1];\n\n    // Nothing to do if there is no data for this glyph\n    if (glyfPos === nextPos) {\n      return null;\n    }\n\n    var stream = this._font._getTableStream('glyf');\n    stream.pos += glyfPos;\n    var startPos = stream.pos;\n\n    var glyph = GlyfHeader.decode(stream);\n\n    if (glyph.numberOfContours > 0) {\n      this._decodeSimple(glyph, stream);\n    } else if (glyph.numberOfContours < 0) {\n      this._decodeComposite(glyph, stream, startPos);\n    }\n\n    return glyph;\n  };\n\n  TTFGlyph.prototype._decodeSimple = function _decodeSimple(glyph, stream) {\n    // this is a simple glyph\n    glyph.points = [];\n\n    var endPtsOfContours = new r.Array(r.uint16, glyph.numberOfContours).decode(stream);\n    glyph.instructions = new r.Array(r.uint8, r.uint16).decode(stream);\n\n    var flags = [];\n    var numCoords = endPtsOfContours[endPtsOfContours.length - 1] + 1;\n\n    while (flags.length < numCoords) {\n      var flag = stream.readUInt8();\n      flags.push(flag);\n\n      // check for repeat flag\n      if (flag & REPEAT) {\n        var count = stream.readUInt8();\n        for (var j = 0; j < count; j++) {\n          flags.push(flag);\n        }\n      }\n    }\n\n    for (var i = 0; i < flags.length; i++) {\n      var flag = flags[i];\n      var point = new Point(!!(flag & ON_CURVE), endPtsOfContours.indexOf(i) >= 0, 0, 0);\n      glyph.points.push(point);\n    }\n\n    var px = 0;\n    for (var i = 0; i < flags.length; i++) {\n      var flag = flags[i];\n      glyph.points[i].x = px = this._parseGlyphCoord(stream, px, flag & X_SHORT_VECTOR, flag & SAME_X);\n    }\n\n    var py = 0;\n    for (var i = 0; i < flags.length; i++) {\n      var flag = flags[i];\n      glyph.points[i].y = py = this._parseGlyphCoord(stream, py, flag & Y_SHORT_VECTOR, flag & SAME_Y);\n    }\n\n    if (this._font._variationProcessor) {\n      var points = glyph.points.slice();\n      points.push.apply(points, this._getPhantomPoints(glyph));\n\n      this._font._variationProcessor.transformPoints(this.id, points);\n      glyph.phantomPoints = points.slice(-4);\n    }\n\n    return;\n  };\n\n  TTFGlyph.prototype._decodeComposite = function _decodeComposite(glyph, stream) {\n    var offset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;\n\n    // this is a composite glyph\n    glyph.components = [];\n    var haveInstructions = false;\n    var flags = MORE_COMPONENTS;\n\n    while (flags & MORE_COMPONENTS) {\n      flags = stream.readUInt16BE();\n      var gPos = stream.pos - offset;\n      var glyphID = stream.readUInt16BE();\n      if (!haveInstructions) {\n        haveInstructions = (flags & WE_HAVE_INSTRUCTIONS) !== 0;\n      }\n\n      if (flags & ARG_1_AND_2_ARE_WORDS) {\n        var dx = stream.readInt16BE();\n        var dy = stream.readInt16BE();\n      } else {\n        var dx = stream.readInt8();\n        var dy = stream.readInt8();\n      }\n\n      var component = new Component(glyphID, dx, dy);\n      component.pos = gPos;\n\n      if (flags & WE_HAVE_A_SCALE) {\n        // fixed number with 14 bits of fraction\n        component.scaleX = component.scaleY = (stream.readUInt8() << 24 | stream.readUInt8() << 16) / 1073741824;\n      } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {\n        component.scaleX = (stream.readUInt8() << 24 | stream.readUInt8() << 16) / 1073741824;\n        component.scaleY = (stream.readUInt8() << 24 | stream.readUInt8() << 16) / 1073741824;\n      } else if (flags & WE_HAVE_A_TWO_BY_TWO) {\n        component.scaleX = (stream.readUInt8() << 24 | stream.readUInt8() << 16) / 1073741824;\n        component.scale01 = (stream.readUInt8() << 24 | stream.readUInt8() << 16) / 1073741824;\n        component.scale10 = (stream.readUInt8() << 24 | stream.readUInt8() << 16) / 1073741824;\n        component.scaleY = (stream.readUInt8() << 24 | stream.readUInt8() << 16) / 1073741824;\n      }\n\n      glyph.components.push(component);\n    }\n\n    if (this._font._variationProcessor) {\n      var points = [];\n      for (var j = 0; j < glyph.components.length; j++) {\n        var component = glyph.components[j];\n        points.push(new Point(true, true, component.dx, component.dy));\n      }\n\n      points.push.apply(points, this._getPhantomPoints(glyph));\n\n      this._font._variationProcessor.transformPoints(this.id, points);\n      glyph.phantomPoints = points.splice(-4, 4);\n\n      for (var i = 0; i < points.length; i++) {\n        var point = points[i];\n        glyph.components[i].dx = point.x;\n        glyph.components[i].dy = point.y;\n      }\n    }\n\n    return haveInstructions;\n  };\n\n  TTFGlyph.prototype._getPhantomPoints = function _getPhantomPoints(glyph) {\n    var cbox = this._getCBox(true);\n    if (this._metrics == null) {\n      this._metrics = Glyph.prototype._getMetrics.call(this, cbox);\n    }\n\n    var _metrics = this._metrics,\n        advanceWidth = _metrics.advanceWidth,\n        advanceHeight = _metrics.advanceHeight,\n        leftBearing = _metrics.leftBearing,\n        topBearing = _metrics.topBearing;\n\n\n    return [new Point(false, true, glyph.xMin - leftBearing, 0), new Point(false, true, glyph.xMin - leftBearing + advanceWidth, 0), new Point(false, true, 0, glyph.yMax + topBearing), new Point(false, true, 0, glyph.yMax + topBearing + advanceHeight)];\n  };\n\n  // Decodes font data, resolves composite glyphs, and returns an array of contours\n\n\n  TTFGlyph.prototype._getContours = function _getContours() {\n    var glyph = this._decode();\n    if (!glyph) {\n      return [];\n    }\n\n    var points = [];\n\n    if (glyph.numberOfContours < 0) {\n      // resolve composite glyphs\n      for (var _iterator = glyph.components, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n        var _ref;\n\n        if (_isArray) {\n          if (_i >= _iterator.length) break;\n          _ref = _iterator[_i++];\n        } else {\n          _i = _iterator.next();\n          if (_i.done) break;\n          _ref = _i.value;\n        }\n\n        var component = _ref;\n\n        var _contours = this._font.getGlyph(component.glyphID)._getContours();\n        for (var i = 0; i < _contours.length; i++) {\n          var contour = _contours[i];\n          for (var j = 0; j < contour.length; j++) {\n            var _point = contour[j];\n            var x = _point.x * component.scaleX + _point.y * component.scale01 + component.dx;\n            var y = _point.y * component.scaleY + _point.x * component.scale10 + component.dy;\n            points.push(new Point(_point.onCurve, _point.endContour, x, y));\n          }\n        }\n      }\n    } else {\n      points = glyph.points || [];\n    }\n\n    // Recompute and cache metrics if we performed variation processing, and don't have an HVAR table\n    if (glyph.phantomPoints && !this._font.directory.tables.HVAR) {\n      this._metrics.advanceWidth = glyph.phantomPoints[1].x - glyph.phantomPoints[0].x;\n      this._metrics.advanceHeight = glyph.phantomPoints[3].y - glyph.phantomPoints[2].y;\n      this._metrics.leftBearing = glyph.xMin - glyph.phantomPoints[0].x;\n      this._metrics.topBearing = glyph.phantomPoints[2].y - glyph.yMax;\n    }\n\n    var contours = [];\n    var cur = [];\n    for (var k = 0; k < points.length; k++) {\n      var point = points[k];\n      cur.push(point);\n      if (point.endContour) {\n        contours.push(cur);\n        cur = [];\n      }\n    }\n\n    return contours;\n  };\n\n  TTFGlyph.prototype._getMetrics = function _getMetrics() {\n    if (this._metrics) {\n      return this._metrics;\n    }\n\n    var cbox = this._getCBox(true);\n    _Glyph.prototype._getMetrics.call(this, cbox);\n\n    if (this._font._variationProcessor && !this._font.HVAR) {\n      // No HVAR table, decode the glyph. This triggers recomputation of metrics.\n      this.path;\n    }\n\n    return this._metrics;\n  };\n\n  // Converts contours to a Path object that can be rendered\n\n\n  TTFGlyph.prototype._getPath = function _getPath() {\n    var contours = this._getContours();\n    var path = new Path();\n\n    for (var i = 0; i < contours.length; i++) {\n      var contour = contours[i];\n      var firstPt = contour[0];\n      var lastPt = contour[contour.length - 1];\n      var start = 0;\n\n      if (firstPt.onCurve) {\n        // The first point will be consumed by the moveTo command, so skip in the loop\n        var curvePt = null;\n        start = 1;\n      } else {\n        if (lastPt.onCurve) {\n          // Start at the last point if the first point is off curve and the last point is on curve\n          firstPt = lastPt;\n        } else {\n          // Start at the middle if both the first and last points are off curve\n          firstPt = new Point(false, false, (firstPt.x + lastPt.x) / 2, (firstPt.y + lastPt.y) / 2);\n        }\n\n        var curvePt = firstPt;\n      }\n\n      path.moveTo(firstPt.x, firstPt.y);\n\n      for (var j = start; j < contour.length; j++) {\n        var pt = contour[j];\n        var prevPt = j === 0 ? firstPt : contour[j - 1];\n\n        if (prevPt.onCurve && pt.onCurve) {\n          path.lineTo(pt.x, pt.y);\n        } else if (prevPt.onCurve && !pt.onCurve) {\n          var curvePt = pt;\n        } else if (!prevPt.onCurve && !pt.onCurve) {\n          var midX = (prevPt.x + pt.x) / 2;\n          var midY = (prevPt.y + pt.y) / 2;\n          path.quadraticCurveTo(prevPt.x, prevPt.y, midX, midY);\n          var curvePt = pt;\n        } else if (!prevPt.onCurve && pt.onCurve) {\n          path.quadraticCurveTo(curvePt.x, curvePt.y, pt.x, pt.y);\n          var curvePt = null;\n        } else {\n          throw new Error(\"Unknown TTF path state\");\n        }\n      }\n\n      // Connect the first and last points\n      if (curvePt) {\n        path.quadraticCurveTo(curvePt.x, curvePt.y, firstPt.x, firstPt.y);\n      }\n\n      path.closePath();\n    }\n\n    return path;\n  };\n\n  return TTFGlyph;\n}(Glyph);\n\n/**\n * Represents an OpenType PostScript glyph, in the Compact Font Format.\n */\n\nvar CFFGlyph = function (_Glyph) {\n  _inherits(CFFGlyph, _Glyph);\n\n  function CFFGlyph() {\n    _classCallCheck(this, CFFGlyph);\n\n    return _possibleConstructorReturn(this, _Glyph.apply(this, arguments));\n  }\n\n  CFFGlyph.prototype._getName = function _getName() {\n    if (this._font.CFF2) {\n      return _Glyph.prototype._getName.call(this);\n    }\n\n    return this._font['CFF '].getGlyphName(this.id);\n  };\n\n  CFFGlyph.prototype.bias = function bias(s) {\n    if (s.length < 1240) {\n      return 107;\n    } else if (s.length < 33900) {\n      return 1131;\n    } else {\n      return 32768;\n    }\n  };\n\n  CFFGlyph.prototype._getPath = function _getPath() {\n    var stream = this._font.stream;\n    var pos = stream.pos;\n\n\n    var cff = this._font.CFF2 || this._font['CFF '];\n    var str = cff.topDict.CharStrings[this.id];\n    var end = str.offset + str.length;\n    stream.pos = str.offset;\n\n    var path = new Path();\n    var stack = [];\n    var trans = [];\n\n    var width = null;\n    var nStems = 0;\n    var x = 0,\n        y = 0;\n    var usedGsubrs = void 0;\n    var usedSubrs = void 0;\n    var open = false;\n\n    this._usedGsubrs = usedGsubrs = {};\n    this._usedSubrs = usedSubrs = {};\n\n    var gsubrs = cff.globalSubrIndex || [];\n    var gsubrsBias = this.bias(gsubrs);\n\n    var privateDict = cff.privateDictForGlyph(this.id);\n    var subrs = privateDict.Subrs || [];\n    var subrsBias = this.bias(subrs);\n\n    var vstore = cff.topDict.vstore && cff.topDict.vstore.itemVariationStore;\n    var vsindex = privateDict.vsindex;\n    var variationProcessor = this._font._variationProcessor;\n\n    function checkWidth() {\n      if (width == null) {\n        width = stack.shift() + privateDict.nominalWidthX;\n      }\n    }\n\n    function parseStems() {\n      if (stack.length % 2 !== 0) {\n        checkWidth();\n      }\n\n      nStems += stack.length >> 1;\n      return stack.length = 0;\n    }\n\n    function moveTo(x, y) {\n      if (open) {\n        path.closePath();\n      }\n\n      path.moveTo(x, y);\n      open = true;\n    }\n\n    var parse = function parse() {\n      while (stream.pos < end) {\n        var op = stream.readUInt8();\n        if (op < 32) {\n          switch (op) {\n            case 1: // hstem\n            case 3: // vstem\n            case 18: // hstemhm\n            case 23:\n              // vstemhm\n              parseStems();\n              break;\n\n            case 4:\n              // vmoveto\n              if (stack.length > 1) {\n                checkWidth();\n              }\n\n              y += stack.shift();\n              moveTo(x, y);\n              break;\n\n            case 5:\n              // rlineto\n              while (stack.length >= 2) {\n                x += stack.shift();\n                y += stack.shift();\n                path.lineTo(x, y);\n              }\n              break;\n\n            case 6: // hlineto\n            case 7:\n              // vlineto\n              var phase = op === 6;\n              while (stack.length >= 1) {\n                if (phase) {\n                  x += stack.shift();\n                } else {\n                  y += stack.shift();\n                }\n\n                path.lineTo(x, y);\n                phase = !phase;\n              }\n              break;\n\n            case 8:\n              // rrcurveto\n              while (stack.length > 0) {\n                var c1x = x + stack.shift();\n                var c1y = y + stack.shift();\n                var c2x = c1x + stack.shift();\n                var c2y = c1y + stack.shift();\n                x = c2x + stack.shift();\n                y = c2y + stack.shift();\n                path.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n              }\n              break;\n\n            case 10:\n              // callsubr\n              var index = stack.pop() + subrsBias;\n              var subr = subrs[index];\n              if (subr) {\n                usedSubrs[index] = true;\n                var p = stream.pos;\n                var e = end;\n                stream.pos = subr.offset;\n                end = subr.offset + subr.length;\n                parse();\n                stream.pos = p;\n                end = e;\n              }\n              break;\n\n            case 11:\n              // return\n              if (cff.version >= 2) {\n                break;\n              }\n              return;\n\n            case 14:\n              // endchar\n              if (cff.version >= 2) {\n                break;\n              }\n\n              if (stack.length > 0) {\n                checkWidth();\n              }\n\n              if (open) {\n                path.closePath();\n                open = false;\n              }\n              break;\n\n            case 15:\n              {\n                // vsindex\n                if (cff.version < 2) {\n                  throw new Error('vsindex operator not supported in CFF v1');\n                }\n\n                vsindex = stack.pop();\n                break;\n              }\n\n            case 16:\n              {\n                // blend\n                if (cff.version < 2) {\n                  throw new Error('blend operator not supported in CFF v1');\n                }\n\n                if (!variationProcessor) {\n                  throw new Error('blend operator in non-variation font');\n                }\n\n                var blendVector = variationProcessor.getBlendVector(vstore, vsindex);\n                var numBlends = stack.pop();\n                var numOperands = numBlends * blendVector.length;\n                var delta = stack.length - numOperands;\n                var base = delta - numBlends;\n\n                for (var i = 0; i < numBlends; i++) {\n                  var sum = stack[base + i];\n                  for (var j = 0; j < blendVector.length; j++) {\n                    sum += blendVector[j] * stack[delta++];\n                  }\n\n                  stack[base + i] = sum;\n                }\n\n                while (numOperands--) {\n                  stack.pop();\n                }\n\n                break;\n              }\n\n            case 19: // hintmask\n            case 20:\n              // cntrmask\n              parseStems();\n              stream.pos += nStems + 7 >> 3;\n              break;\n\n            case 21:\n              // rmoveto\n              if (stack.length > 2) {\n                checkWidth();\n              }\n\n              x += stack.shift();\n              y += stack.shift();\n              moveTo(x, y);\n              break;\n\n            case 22:\n              // hmoveto\n              if (stack.length > 1) {\n                checkWidth();\n              }\n\n              x += stack.shift();\n              moveTo(x, y);\n              break;\n\n            case 24:\n              // rcurveline\n              while (stack.length >= 8) {\n                var c1x = x + stack.shift();\n                var c1y = y + stack.shift();\n                var c2x = c1x + stack.shift();\n                var c2y = c1y + stack.shift();\n                x = c2x + stack.shift();\n                y = c2y + stack.shift();\n                path.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n              }\n\n              x += stack.shift();\n              y += stack.shift();\n              path.lineTo(x, y);\n              break;\n\n            case 25:\n              // rlinecurve\n              while (stack.length >= 8) {\n                x += stack.shift();\n                y += stack.shift();\n                path.lineTo(x, y);\n              }\n\n              var c1x = x + stack.shift();\n              var c1y = y + stack.shift();\n              var c2x = c1x + stack.shift();\n              var c2y = c1y + stack.shift();\n              x = c2x + stack.shift();\n              y = c2y + stack.shift();\n              path.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n              break;\n\n            case 26:\n              // vvcurveto\n              if (stack.length % 2) {\n                x += stack.shift();\n              }\n\n              while (stack.length >= 4) {\n                c1x = x;\n                c1y = y + stack.shift();\n                c2x = c1x + stack.shift();\n                c2y = c1y + stack.shift();\n                x = c2x;\n                y = c2y + stack.shift();\n                path.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n              }\n              break;\n\n            case 27:\n              // hhcurveto\n              if (stack.length % 2) {\n                y += stack.shift();\n              }\n\n              while (stack.length >= 4) {\n                c1x = x + stack.shift();\n                c1y = y;\n                c2x = c1x + stack.shift();\n                c2y = c1y + stack.shift();\n                x = c2x + stack.shift();\n                y = c2y;\n                path.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n              }\n              break;\n\n            case 28:\n              // shortint\n              stack.push(stream.readInt16BE());\n              break;\n\n            case 29:\n              // callgsubr\n              index = stack.pop() + gsubrsBias;\n              subr = gsubrs[index];\n              if (subr) {\n                usedGsubrs[index] = true;\n                var p = stream.pos;\n                var e = end;\n                stream.pos = subr.offset;\n                end = subr.offset + subr.length;\n                parse();\n                stream.pos = p;\n                end = e;\n              }\n              break;\n\n            case 30: // vhcurveto\n            case 31:\n              // hvcurveto\n              phase = op === 31;\n              while (stack.length >= 4) {\n                if (phase) {\n                  c1x = x + stack.shift();\n                  c1y = y;\n                  c2x = c1x + stack.shift();\n                  c2y = c1y + stack.shift();\n                  y = c2y + stack.shift();\n                  x = c2x + (stack.length === 1 ? stack.shift() : 0);\n                } else {\n                  c1x = x;\n                  c1y = y + stack.shift();\n                  c2x = c1x + stack.shift();\n                  c2y = c1y + stack.shift();\n                  x = c2x + stack.shift();\n                  y = c2y + (stack.length === 1 ? stack.shift() : 0);\n                }\n\n                path.bezierCurveTo(c1x, c1y, c2x, c2y, x, y);\n                phase = !phase;\n              }\n              break;\n\n            case 12:\n              op = stream.readUInt8();\n              switch (op) {\n                case 3:\n                  // and\n                  var a = stack.pop();\n                  var b = stack.pop();\n                  stack.push(a && b ? 1 : 0);\n                  break;\n\n                case 4:\n                  // or\n                  a = stack.pop();\n                  b = stack.pop();\n                  stack.push(a || b ? 1 : 0);\n                  break;\n\n                case 5:\n                  // not\n                  a = stack.pop();\n                  stack.push(a ? 0 : 1);\n                  break;\n\n                case 9:\n                  // abs\n                  a = stack.pop();\n                  stack.push(Math.abs(a));\n                  break;\n\n                case 10:\n                  // add\n                  a = stack.pop();\n                  b = stack.pop();\n                  stack.push(a + b);\n                  break;\n\n                case 11:\n                  // sub\n                  a = stack.pop();\n                  b = stack.pop();\n                  stack.push(a - b);\n                  break;\n\n                case 12:\n                  // div\n                  a = stack.pop();\n                  b = stack.pop();\n                  stack.push(a / b);\n                  break;\n\n                case 14:\n                  // neg\n                  a = stack.pop();\n                  stack.push(-a);\n                  break;\n\n                case 15:\n                  // eq\n                  a = stack.pop();\n                  b = stack.pop();\n                  stack.push(a === b ? 1 : 0);\n                  break;\n\n                case 18:\n                  // drop\n                  stack.pop();\n                  break;\n\n                case 20:\n                  // put\n                  var val = stack.pop();\n                  var idx = stack.pop();\n                  trans[idx] = val;\n                  break;\n\n                case 21:\n                  // get\n                  idx = stack.pop();\n                  stack.push(trans[idx] || 0);\n                  break;\n\n                case 22:\n                  // ifelse\n                  var s1 = stack.pop();\n                  var s2 = stack.pop();\n                  var v1 = stack.pop();\n                  var v2 = stack.pop();\n                  stack.push(v1 <= v2 ? s1 : s2);\n                  break;\n\n                case 23:\n                  // random\n                  stack.push(Math.random());\n                  break;\n\n                case 24:\n                  // mul\n                  a = stack.pop();\n                  b = stack.pop();\n                  stack.push(a * b);\n                  break;\n\n                case 26:\n                  // sqrt\n                  a = stack.pop();\n                  stack.push(Math.sqrt(a));\n                  break;\n\n                case 27:\n                  // dup\n                  a = stack.pop();\n                  stack.push(a, a);\n                  break;\n\n                case 28:\n                  // exch\n                  a = stack.pop();\n                  b = stack.pop();\n                  stack.push(b, a);\n                  break;\n\n                case 29:\n                  // index\n                  idx = stack.pop();\n                  if (idx < 0) {\n                    idx = 0;\n                  } else if (idx > stack.length - 1) {\n                    idx = stack.length - 1;\n                  }\n\n                  stack.push(stack[idx]);\n                  break;\n\n                case 30:\n                  // roll\n                  var n = stack.pop();\n                  var _j = stack.pop();\n\n                  if (_j >= 0) {\n                    while (_j > 0) {\n                      var t = stack[n - 1];\n                      for (var _i = n - 2; _i >= 0; _i--) {\n                        stack[_i + 1] = stack[_i];\n                      }\n\n                      stack[0] = t;\n                      _j--;\n                    }\n                  } else {\n                    while (_j < 0) {\n                      var t = stack[0];\n                      for (var _i2 = 0; _i2 <= n; _i2++) {\n                        stack[_i2] = stack[_i2 + 1];\n                      }\n\n                      stack[n - 1] = t;\n                      _j++;\n                    }\n                  }\n                  break;\n\n                case 34:\n                  // hflex\n                  c1x = x + stack.shift();\n                  c1y = y;\n                  c2x = c1x + stack.shift();\n                  c2y = c1y + stack.shift();\n                  var c3x = c2x + stack.shift();\n                  var c3y = c2y;\n                  var c4x = c3x + stack.shift();\n                  var c4y = c3y;\n                  var c5x = c4x + stack.shift();\n                  var c5y = c4y;\n                  var c6x = c5x + stack.shift();\n                  var c6y = c5y;\n                  x = c6x;\n                  y = c6y;\n\n                  path.bezierCurveTo(c1x, c1y, c2x, c2y, c3x, c3y);\n                  path.bezierCurveTo(c4x, c4y, c5x, c5y, c6x, c6y);\n                  break;\n\n                case 35:\n                  // flex\n                  var pts = [];\n\n                  for (var _i3 = 0; _i3 <= 5; _i3++) {\n                    x += stack.shift();\n                    y += stack.shift();\n                    pts.push(x, y);\n                  }\n\n                  path.bezierCurveTo.apply(path, pts.slice(0, 6));\n                  path.bezierCurveTo.apply(path, pts.slice(6));\n                  stack.shift(); // fd\n                  break;\n\n                case 36:\n                  // hflex1\n                  c1x = x + stack.shift();\n                  c1y = y + stack.shift();\n                  c2x = c1x + stack.shift();\n                  c2y = c1y + stack.shift();\n                  c3x = c2x + stack.shift();\n                  c3y = c2y;\n                  c4x = c3x + stack.shift();\n                  c4y = c3y;\n                  c5x = c4x + stack.shift();\n                  c5y = c4y + stack.shift();\n                  c6x = c5x + stack.shift();\n                  c6y = c5y;\n                  x = c6x;\n                  y = c6y;\n\n                  path.bezierCurveTo(c1x, c1y, c2x, c2y, c3x, c3y);\n                  path.bezierCurveTo(c4x, c4y, c5x, c5y, c6x, c6y);\n                  break;\n\n                case 37:\n                  // flex1\n                  var startx = x;\n                  var starty = y;\n\n                  pts = [];\n                  for (var _i4 = 0; _i4 <= 4; _i4++) {\n                    x += stack.shift();\n                    y += stack.shift();\n                    pts.push(x, y);\n                  }\n\n                  if (Math.abs(x - startx) > Math.abs(y - starty)) {\n                    // horizontal\n                    x += stack.shift();\n                    y = starty;\n                  } else {\n                    x = startx;\n                    y += stack.shift();\n                  }\n\n                  pts.push(x, y);\n                  path.bezierCurveTo.apply(path, pts.slice(0, 6));\n                  path.bezierCurveTo.apply(path, pts.slice(6));\n                  break;\n\n                default:\n                  throw new Error('Unknown op: 12 ' + op);\n              }\n              break;\n\n            default:\n              throw new Error('Unknown op: ' + op);\n          }\n        } else if (op < 247) {\n          stack.push(op - 139);\n        } else if (op < 251) {\n          var b1 = stream.readUInt8();\n          stack.push((op - 247) * 256 + b1 + 108);\n        } else if (op < 255) {\n          var b1 = stream.readUInt8();\n          stack.push(-(op - 251) * 256 - b1 - 108);\n        } else {\n          stack.push(stream.readInt32BE() / 65536);\n        }\n      }\n    };\n\n    parse();\n\n    if (open) {\n      path.closePath();\n    }\n\n    return path;\n  };\n\n  return CFFGlyph;\n}(Glyph);\n\nvar SBIXImage = new r.Struct({\n  originX: r.uint16,\n  originY: r.uint16,\n  type: new r.String(4),\n  data: new r.Buffer(function (t) {\n    return t.parent.buflen - t._currentOffset;\n  })\n});\n\n/**\n * Represents a color (e.g. emoji) glyph in Apple's SBIX format.\n */\n\nvar SBIXGlyph = function (_TTFGlyph) {\n  _inherits(SBIXGlyph, _TTFGlyph);\n\n  function SBIXGlyph() {\n    _classCallCheck(this, SBIXGlyph);\n\n    return _possibleConstructorReturn(this, _TTFGlyph.apply(this, arguments));\n  }\n\n  /**\n   * Returns an object representing a glyph image at the given point size.\n   * The object has a data property with a Buffer containing the actual image data,\n   * along with the image type, and origin.\n   *\n   * @param {number} size\n   * @return {object}\n   */\n  SBIXGlyph.prototype.getImageForSize = function getImageForSize(size) {\n    for (var i = 0; i < this._font.sbix.imageTables.length; i++) {\n      var table = this._font.sbix.imageTables[i];\n      if (table.ppem >= size) {\n        break;\n      }\n    }\n\n    var offsets = table.imageOffsets;\n    var start = offsets[this.id];\n    var end = offsets[this.id + 1];\n\n    if (start === end) {\n      return null;\n    }\n\n    this._font.stream.pos = start;\n    return SBIXImage.decode(this._font.stream, { buflen: end - start });\n  };\n\n  SBIXGlyph.prototype.render = function render(ctx, size) {\n    var img = this.getImageForSize(size);\n    if (img != null) {\n      var scale = size / this._font.unitsPerEm;\n      ctx.image(img.data, { height: size, x: img.originX, y: (this.bbox.minY - img.originY) * scale });\n    }\n\n    if (this._font.sbix.flags.renderOutlines) {\n      _TTFGlyph.prototype.render.call(this, ctx, size);\n    }\n  };\n\n  return SBIXGlyph;\n}(TTFGlyph);\n\nvar COLRLayer = function COLRLayer(glyph, color) {\n  _classCallCheck(this, COLRLayer);\n\n  this.glyph = glyph;\n  this.color = color;\n};\n\n/**\n * Represents a color (e.g. emoji) glyph in Microsoft's COLR format.\n * Each glyph in this format contain a list of colored layers, each\n * of which  is another vector glyph.\n */\n\n\nvar COLRGlyph = function (_Glyph) {\n  _inherits(COLRGlyph, _Glyph);\n\n  function COLRGlyph() {\n    _classCallCheck(this, COLRGlyph);\n\n    return _possibleConstructorReturn(this, _Glyph.apply(this, arguments));\n  }\n\n  COLRGlyph.prototype._getBBox = function _getBBox() {\n    var bbox = new BBox();\n    for (var i = 0; i < this.layers.length; i++) {\n      var layer = this.layers[i];\n      var b = layer.glyph.bbox;\n      bbox.addPoint(b.minX, b.minY);\n      bbox.addPoint(b.maxX, b.maxY);\n    }\n\n    return bbox;\n  };\n\n  /**\n   * Returns an array of objects containing the glyph and color for\n   * each layer in the composite color glyph.\n   * @type {object[]}\n   */\n\n\n  COLRGlyph.prototype.render = function render(ctx, size) {\n    for (var _iterator = this.layers, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var _ref2 = _ref,\n          glyph = _ref2.glyph,\n          color = _ref2.color;\n\n      ctx.fillColor([color.red, color.green, color.blue], color.alpha / 255 * 100);\n      glyph.render(ctx, size);\n    }\n\n    return;\n  };\n\n  _createClass(COLRGlyph, [{\n    key: 'layers',\n    get: function get() {\n      var cpal = this._font.CPAL;\n      var colr = this._font.COLR;\n      var low = 0;\n      var high = colr.baseGlyphRecord.length - 1;\n\n      while (low <= high) {\n        var mid = low + high >> 1;\n        var rec = colr.baseGlyphRecord[mid];\n\n        if (this.id < rec.gid) {\n          high = mid - 1;\n        } else if (this.id > rec.gid) {\n          low = mid + 1;\n        } else {\n          var baseLayer = rec;\n          break;\n        }\n      }\n\n      // if base glyph not found in COLR table,\n      // default to normal glyph from glyf or CFF\n      if (baseLayer == null) {\n        var g = this._font._getBaseGlyph(this.id);\n        var color = {\n          red: 0,\n          green: 0,\n          blue: 0,\n          alpha: 255\n        };\n\n        return [new COLRLayer(g, color)];\n      }\n\n      // otherwise, return an array of all the layers\n      var layers = [];\n      for (var i = baseLayer.firstLayerIndex; i < baseLayer.firstLayerIndex + baseLayer.numLayers; i++) {\n        var rec = colr.layerRecords[i];\n        var color = cpal.colorRecords[rec.paletteIndex];\n        var g = this._font._getBaseGlyph(rec.gid);\n        layers.push(new COLRLayer(g, color));\n      }\n\n      return layers;\n    }\n  }]);\n\n  return COLRGlyph;\n}(Glyph);\n\nvar TUPLES_SHARE_POINT_NUMBERS = 0x8000;\nvar TUPLE_COUNT_MASK = 0x0fff;\nvar EMBEDDED_TUPLE_COORD = 0x8000;\nvar INTERMEDIATE_TUPLE = 0x4000;\nvar PRIVATE_POINT_NUMBERS = 0x2000;\nvar TUPLE_INDEX_MASK = 0x0fff;\nvar POINTS_ARE_WORDS = 0x80;\nvar POINT_RUN_COUNT_MASK = 0x7f;\nvar DELTAS_ARE_ZERO = 0x80;\nvar DELTAS_ARE_WORDS = 0x40;\nvar DELTA_RUN_COUNT_MASK = 0x3f;\n\n/**\n * This class is transforms TrueType glyphs according to the data from\n * the Apple Advanced Typography variation tables (fvar, gvar, and avar).\n * These tables allow infinite adjustments to glyph weight, width, slant,\n * and optical size without the designer needing to specify every exact style.\n *\n * Apple's documentation for these tables is not great, so thanks to the\n * Freetype project for figuring much of this out.\n *\n * @private\n */\n\nvar GlyphVariationProcessor = function () {\n  function GlyphVariationProcessor(font, coords) {\n    _classCallCheck(this, GlyphVariationProcessor);\n\n    this.font = font;\n    this.normalizedCoords = this.normalizeCoords(coords);\n    this.blendVectors = new _Map();\n  }\n\n  GlyphVariationProcessor.prototype.normalizeCoords = function normalizeCoords(coords) {\n    // the default mapping is linear along each axis, in two segments:\n    // from the minValue to defaultValue, and from defaultValue to maxValue.\n    var normalized = [];\n    for (var i = 0; i < this.font.fvar.axis.length; i++) {\n      var axis = this.font.fvar.axis[i];\n      if (coords[i] < axis.defaultValue) {\n        normalized.push((coords[i] - axis.defaultValue + _Number$EPSILON) / (axis.defaultValue - axis.minValue + _Number$EPSILON));\n      } else {\n        normalized.push((coords[i] - axis.defaultValue + _Number$EPSILON) / (axis.maxValue - axis.defaultValue + _Number$EPSILON));\n      }\n    }\n\n    // if there is an avar table, the normalized value is calculated\n    // by interpolating between the two nearest mapped values.\n    if (this.font.avar) {\n      for (var i = 0; i < this.font.avar.segment.length; i++) {\n        var segment = this.font.avar.segment[i];\n        for (var j = 0; j < segment.correspondence.length; j++) {\n          var pair = segment.correspondence[j];\n          if (j >= 1 && normalized[i] < pair.fromCoord) {\n            var prev = segment.correspondence[j - 1];\n            normalized[i] = ((normalized[i] - prev.fromCoord) * (pair.toCoord - prev.toCoord) + _Number$EPSILON) / (pair.fromCoord - prev.fromCoord + _Number$EPSILON) + prev.toCoord;\n\n            break;\n          }\n        }\n      }\n    }\n\n    return normalized;\n  };\n\n  GlyphVariationProcessor.prototype.transformPoints = function transformPoints(gid, glyphPoints) {\n    if (!this.font.fvar || !this.font.gvar) {\n      return;\n    }\n\n    var gvar = this.font.gvar;\n\n    if (gid >= gvar.glyphCount) {\n      return;\n    }\n\n    var offset = gvar.offsets[gid];\n    if (offset === gvar.offsets[gid + 1]) {\n      return;\n    }\n\n    // Read the gvar data for this glyph\n    var stream = this.font.stream;\n\n    stream.pos = offset;\n    if (stream.pos >= stream.length) {\n      return;\n    }\n\n    var tupleCount = stream.readUInt16BE();\n    var offsetToData = offset + stream.readUInt16BE();\n\n    if (tupleCount & TUPLES_SHARE_POINT_NUMBERS) {\n      var here = stream.pos;\n      stream.pos = offsetToData;\n      var sharedPoints = this.decodePoints();\n      offsetToData = stream.pos;\n      stream.pos = here;\n    }\n\n    var origPoints = glyphPoints.map(function (pt) {\n      return pt.copy();\n    });\n\n    tupleCount &= TUPLE_COUNT_MASK;\n    for (var i = 0; i < tupleCount; i++) {\n      var tupleDataSize = stream.readUInt16BE();\n      var tupleIndex = stream.readUInt16BE();\n\n      if (tupleIndex & EMBEDDED_TUPLE_COORD) {\n        var tupleCoords = [];\n        for (var a = 0; a < gvar.axisCount; a++) {\n          tupleCoords.push(stream.readInt16BE() / 16384);\n        }\n      } else {\n        if ((tupleIndex & TUPLE_INDEX_MASK) >= gvar.globalCoordCount) {\n          throw new Error('Invalid gvar table');\n        }\n\n        var tupleCoords = gvar.globalCoords[tupleIndex & TUPLE_INDEX_MASK];\n      }\n\n      if (tupleIndex & INTERMEDIATE_TUPLE) {\n        var startCoords = [];\n        for (var _a = 0; _a < gvar.axisCount; _a++) {\n          startCoords.push(stream.readInt16BE() / 16384);\n        }\n\n        var endCoords = [];\n        for (var _a2 = 0; _a2 < gvar.axisCount; _a2++) {\n          endCoords.push(stream.readInt16BE() / 16384);\n        }\n      }\n\n      // Get the factor at which to apply this tuple\n      var factor = this.tupleFactor(tupleIndex, tupleCoords, startCoords, endCoords);\n      if (factor === 0) {\n        offsetToData += tupleDataSize;\n        continue;\n      }\n\n      var here = stream.pos;\n      stream.pos = offsetToData;\n\n      if (tupleIndex & PRIVATE_POINT_NUMBERS) {\n        var points = this.decodePoints();\n      } else {\n        var points = sharedPoints;\n      }\n\n      // points.length = 0 means there are deltas for all points\n      var nPoints = points.length === 0 ? glyphPoints.length : points.length;\n      var xDeltas = this.decodeDeltas(nPoints);\n      var yDeltas = this.decodeDeltas(nPoints);\n\n      if (points.length === 0) {\n        // all points\n        for (var _i = 0; _i < glyphPoints.length; _i++) {\n          var point = glyphPoints[_i];\n          point.x += Math.round(xDeltas[_i] * factor);\n          point.y += Math.round(yDeltas[_i] * factor);\n        }\n      } else {\n        var outPoints = origPoints.map(function (pt) {\n          return pt.copy();\n        });\n        var hasDelta = glyphPoints.map(function () {\n          return false;\n        });\n\n        for (var _i2 = 0; _i2 < points.length; _i2++) {\n          var idx = points[_i2];\n          if (idx < glyphPoints.length) {\n            var _point = outPoints[idx];\n            hasDelta[idx] = true;\n\n            _point.x += Math.round(xDeltas[_i2] * factor);\n            _point.y += Math.round(yDeltas[_i2] * factor);\n          }\n        }\n\n        this.interpolateMissingDeltas(outPoints, origPoints, hasDelta);\n\n        for (var _i3 = 0; _i3 < glyphPoints.length; _i3++) {\n          var deltaX = outPoints[_i3].x - origPoints[_i3].x;\n          var deltaY = outPoints[_i3].y - origPoints[_i3].y;\n\n          glyphPoints[_i3].x += deltaX;\n          glyphPoints[_i3].y += deltaY;\n        }\n      }\n\n      offsetToData += tupleDataSize;\n      stream.pos = here;\n    }\n  };\n\n  GlyphVariationProcessor.prototype.decodePoints = function decodePoints() {\n    var stream = this.font.stream;\n    var count = stream.readUInt8();\n\n    if (count & POINTS_ARE_WORDS) {\n      count = (count & POINT_RUN_COUNT_MASK) << 8 | stream.readUInt8();\n    }\n\n    var points = new Uint16Array(count);\n    var i = 0;\n    var point = 0;\n    while (i < count) {\n      var run = stream.readUInt8();\n      var runCount = (run & POINT_RUN_COUNT_MASK) + 1;\n      var fn = run & POINTS_ARE_WORDS ? stream.readUInt16 : stream.readUInt8;\n\n      for (var j = 0; j < runCount && i < count; j++) {\n        point += fn.call(stream);\n        points[i++] = point;\n      }\n    }\n\n    return points;\n  };\n\n  GlyphVariationProcessor.prototype.decodeDeltas = function decodeDeltas(count) {\n    var stream = this.font.stream;\n    var i = 0;\n    var deltas = new Int16Array(count);\n\n    while (i < count) {\n      var run = stream.readUInt8();\n      var runCount = (run & DELTA_RUN_COUNT_MASK) + 1;\n\n      if (run & DELTAS_ARE_ZERO) {\n        i += runCount;\n      } else {\n        var fn = run & DELTAS_ARE_WORDS ? stream.readInt16BE : stream.readInt8;\n        for (var j = 0; j < runCount && i < count; j++) {\n          deltas[i++] = fn.call(stream);\n        }\n      }\n    }\n\n    return deltas;\n  };\n\n  GlyphVariationProcessor.prototype.tupleFactor = function tupleFactor(tupleIndex, tupleCoords, startCoords, endCoords) {\n    var normalized = this.normalizedCoords;\n    var gvar = this.font.gvar;\n\n    var factor = 1;\n\n    for (var i = 0; i < gvar.axisCount; i++) {\n      if (tupleCoords[i] === 0) {\n        continue;\n      }\n\n      if (normalized[i] === 0) {\n        return 0;\n      }\n\n      if ((tupleIndex & INTERMEDIATE_TUPLE) === 0) {\n        if (normalized[i] < Math.min(0, tupleCoords[i]) || normalized[i] > Math.max(0, tupleCoords[i])) {\n          return 0;\n        }\n\n        factor = (factor * normalized[i] + _Number$EPSILON) / (tupleCoords[i] + _Number$EPSILON);\n      } else {\n        if (normalized[i] < startCoords[i] || normalized[i] > endCoords[i]) {\n          return 0;\n        } else if (normalized[i] < tupleCoords[i]) {\n          factor = factor * (normalized[i] - startCoords[i] + _Number$EPSILON) / (tupleCoords[i] - startCoords[i] + _Number$EPSILON);\n        } else {\n          factor = factor * (endCoords[i] - normalized[i] + _Number$EPSILON) / (endCoords[i] - tupleCoords[i] + _Number$EPSILON);\n        }\n      }\n    }\n\n    return factor;\n  };\n\n  // Interpolates points without delta values.\n  // Needed for the Ø and Q glyphs in Skia.\n  // Algorithm from Freetype.\n\n\n  GlyphVariationProcessor.prototype.interpolateMissingDeltas = function interpolateMissingDeltas(points, inPoints, hasDelta) {\n    if (points.length === 0) {\n      return;\n    }\n\n    var point = 0;\n    while (point < points.length) {\n      var firstPoint = point;\n\n      // find the end point of the contour\n      var endPoint = point;\n      var pt = points[endPoint];\n      while (!pt.endContour) {\n        pt = points[++endPoint];\n      }\n\n      // find the first point that has a delta\n      while (point <= endPoint && !hasDelta[point]) {\n        point++;\n      }\n\n      if (point > endPoint) {\n        continue;\n      }\n\n      var firstDelta = point;\n      var curDelta = point;\n      point++;\n\n      while (point <= endPoint) {\n        // find the next point with a delta, and interpolate intermediate points\n        if (hasDelta[point]) {\n          this.deltaInterpolate(curDelta + 1, point - 1, curDelta, point, inPoints, points);\n          curDelta = point;\n        }\n\n        point++;\n      }\n\n      // shift contour if we only have a single delta\n      if (curDelta === firstDelta) {\n        this.deltaShift(firstPoint, endPoint, curDelta, inPoints, points);\n      } else {\n        // otherwise, handle the remaining points at the end and beginning of the contour\n        this.deltaInterpolate(curDelta + 1, endPoint, curDelta, firstDelta, inPoints, points);\n\n        if (firstDelta > 0) {\n          this.deltaInterpolate(firstPoint, firstDelta - 1, curDelta, firstDelta, inPoints, points);\n        }\n      }\n\n      point = endPoint + 1;\n    }\n  };\n\n  GlyphVariationProcessor.prototype.deltaInterpolate = function deltaInterpolate(p1, p2, ref1, ref2, inPoints, outPoints) {\n    if (p1 > p2) {\n      return;\n    }\n\n    var iterable = ['x', 'y'];\n    for (var i = 0; i < iterable.length; i++) {\n      var k = iterable[i];\n      if (inPoints[ref1][k] > inPoints[ref2][k]) {\n        var p = ref1;\n        ref1 = ref2;\n        ref2 = p;\n      }\n\n      var in1 = inPoints[ref1][k];\n      var in2 = inPoints[ref2][k];\n      var out1 = outPoints[ref1][k];\n      var out2 = outPoints[ref2][k];\n\n      // If the reference points have the same coordinate but different\n      // delta, inferred delta is zero.  Otherwise interpolate.\n      if (in1 !== in2 || out1 === out2) {\n        var scale = in1 === in2 ? 0 : (out2 - out1) / (in2 - in1);\n\n        for (var _p = p1; _p <= p2; _p++) {\n          var out = inPoints[_p][k];\n\n          if (out <= in1) {\n            out += out1 - in1;\n          } else if (out >= in2) {\n            out += out2 - in2;\n          } else {\n            out = out1 + (out - in1) * scale;\n          }\n\n          outPoints[_p][k] = out;\n        }\n      }\n    }\n  };\n\n  GlyphVariationProcessor.prototype.deltaShift = function deltaShift(p1, p2, ref, inPoints, outPoints) {\n    var deltaX = outPoints[ref].x - inPoints[ref].x;\n    var deltaY = outPoints[ref].y - inPoints[ref].y;\n\n    if (deltaX === 0 && deltaY === 0) {\n      return;\n    }\n\n    for (var p = p1; p <= p2; p++) {\n      if (p !== ref) {\n        outPoints[p].x += deltaX;\n        outPoints[p].y += deltaY;\n      }\n    }\n  };\n\n  GlyphVariationProcessor.prototype.getAdvanceAdjustment = function getAdvanceAdjustment(gid, table) {\n    var outerIndex = void 0,\n        innerIndex = void 0;\n\n    if (table.advanceWidthMapping) {\n      var idx = gid;\n      if (idx >= table.advanceWidthMapping.mapCount) {\n        idx = table.advanceWidthMapping.mapCount - 1;\n      }\n\n      var entryFormat = table.advanceWidthMapping.entryFormat;\n      var _table$advanceWidthMa = table.advanceWidthMapping.mapData[idx];\n      outerIndex = _table$advanceWidthMa.outerIndex;\n      innerIndex = _table$advanceWidthMa.innerIndex;\n    } else {\n      outerIndex = 0;\n      innerIndex = gid;\n    }\n\n    return this.getDelta(table.itemVariationStore, outerIndex, innerIndex);\n  };\n\n  // See pseudo code from `Font Variations Overview'\n  // in the OpenType specification.\n\n\n  GlyphVariationProcessor.prototype.getDelta = function getDelta(itemStore, outerIndex, innerIndex) {\n    if (outerIndex >= itemStore.itemVariationData.length) {\n      return 0;\n    }\n\n    var varData = itemStore.itemVariationData[outerIndex];\n    if (innerIndex >= varData.deltaSets.length) {\n      return 0;\n    }\n\n    var deltaSet = varData.deltaSets[innerIndex];\n    var blendVector = this.getBlendVector(itemStore, outerIndex);\n    var netAdjustment = 0;\n\n    for (var master = 0; master < varData.regionIndexCount; master++) {\n      netAdjustment += deltaSet.deltas[master] * blendVector[master];\n    }\n\n    return netAdjustment;\n  };\n\n  GlyphVariationProcessor.prototype.getBlendVector = function getBlendVector(itemStore, outerIndex) {\n    var varData = itemStore.itemVariationData[outerIndex];\n    if (this.blendVectors.has(varData)) {\n      return this.blendVectors.get(varData);\n    }\n\n    var normalizedCoords = this.normalizedCoords;\n    var blendVector = [];\n\n    // outer loop steps through master designs to be blended\n    for (var master = 0; master < varData.regionIndexCount; master++) {\n      var scalar = 1;\n      var regionIndex = varData.regionIndexes[master];\n      var axes = itemStore.variationRegionList.variationRegions[regionIndex];\n\n      // inner loop steps through axes in this region\n      for (var j = 0; j < axes.length; j++) {\n        var axis = axes[j];\n        var axisScalar = void 0;\n\n        // compute the scalar contribution of this axis\n        // ignore invalid ranges\n        if (axis.startCoord > axis.peakCoord || axis.peakCoord > axis.endCoord) {\n          axisScalar = 1;\n        } else if (axis.startCoord < 0 && axis.endCoord > 0 && axis.peakCoord !== 0) {\n          axisScalar = 1;\n\n          // peak of 0 means ignore this axis\n        } else if (axis.peakCoord === 0) {\n          axisScalar = 1;\n\n          // ignore this region if coords are out of range\n        } else if (normalizedCoords[j] < axis.startCoord || normalizedCoords[j] > axis.endCoord) {\n          axisScalar = 0;\n\n          // calculate a proportional factor\n        } else {\n          if (normalizedCoords[j] === axis.peakCoord) {\n            axisScalar = 1;\n          } else if (normalizedCoords[j] < axis.peakCoord) {\n            axisScalar = (normalizedCoords[j] - axis.startCoord + _Number$EPSILON) / (axis.peakCoord - axis.startCoord + _Number$EPSILON);\n          } else {\n            axisScalar = (axis.endCoord - normalizedCoords[j] + _Number$EPSILON) / (axis.endCoord - axis.peakCoord + _Number$EPSILON);\n          }\n        }\n\n        // take product of all the axis scalars\n        scalar *= axisScalar;\n      }\n\n      blendVector[master] = scalar;\n    }\n\n    this.blendVectors.set(varData, blendVector);\n    return blendVector;\n  };\n\n  return GlyphVariationProcessor;\n}();\n\nvar Subset = function () {\n  function Subset(font) {\n    _classCallCheck(this, Subset);\n\n    this.font = font;\n    this.glyphs = [];\n    this.mapping = {};\n\n    // always include the missing glyph\n    this.includeGlyph(0);\n  }\n\n  Subset.prototype.includeGlyph = function includeGlyph(glyph) {\n    if ((typeof glyph === 'undefined' ? 'undefined' : _typeof(glyph)) === 'object') {\n      glyph = glyph.id;\n    }\n\n    if (this.mapping[glyph] == null) {\n      this.glyphs.push(glyph);\n      this.mapping[glyph] = this.glyphs.length - 1;\n    }\n\n    return this.mapping[glyph];\n  };\n\n  Subset.prototype.encodeStream = function encodeStream() {\n    var _this = this;\n\n    var s = new r.EncodeStream();\n\n    process.nextTick(function () {\n      _this.encode(s);\n      return s.end();\n    });\n\n    return s;\n  };\n\n  return Subset;\n}();\n\n// Flags for simple glyphs\nvar ON_CURVE$1 = 1 << 0;\nvar X_SHORT_VECTOR$1 = 1 << 1;\nvar Y_SHORT_VECTOR$1 = 1 << 2;\nvar REPEAT$1 = 1 << 3;\nvar SAME_X$1 = 1 << 4;\nvar SAME_Y$1 = 1 << 5;\n\nvar Point$1 = function () {\n  function Point() {\n    _classCallCheck(this, Point);\n  }\n\n  Point.size = function size(val) {\n    return val >= 0 && val <= 255 ? 1 : 2;\n  };\n\n  Point.encode = function encode(stream, value) {\n    if (value >= 0 && value <= 255) {\n      stream.writeUInt8(value);\n    } else {\n      stream.writeInt16BE(value);\n    }\n  };\n\n  return Point;\n}();\n\nvar Glyf = new r.Struct({\n  numberOfContours: r.int16, // if negative, this is a composite glyph\n  xMin: r.int16,\n  yMin: r.int16,\n  xMax: r.int16,\n  yMax: r.int16,\n  endPtsOfContours: new r.Array(r.uint16, 'numberOfContours'),\n  instructions: new r.Array(r.uint8, r.uint16),\n  flags: new r.Array(r.uint8, 0),\n  xPoints: new r.Array(Point$1, 0),\n  yPoints: new r.Array(Point$1, 0)\n});\n\n/**\n * Encodes TrueType glyph outlines\n */\n\nvar TTFGlyphEncoder = function () {\n  function TTFGlyphEncoder() {\n    _classCallCheck(this, TTFGlyphEncoder);\n  }\n\n  TTFGlyphEncoder.prototype.encodeSimple = function encodeSimple(path) {\n    var instructions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n\n    var endPtsOfContours = [];\n    var xPoints = [];\n    var yPoints = [];\n    var flags = [];\n    var same = 0;\n    var lastX = 0,\n        lastY = 0,\n        lastFlag = 0;\n    var pointCount = 0;\n\n    for (var i = 0; i < path.commands.length; i++) {\n      var c = path.commands[i];\n\n      for (var j = 0; j < c.args.length; j += 2) {\n        var x = c.args[j];\n        var y = c.args[j + 1];\n        var flag = 0;\n\n        // If the ending point of a quadratic curve is the midpoint\n        // between the control point and the control point of the next\n        // quadratic curve, we can omit the ending point.\n        if (c.command === 'quadraticCurveTo' && j === 2) {\n          var next = path.commands[i + 1];\n          if (next && next.command === 'quadraticCurveTo') {\n            var midX = (lastX + next.args[0]) / 2;\n            var midY = (lastY + next.args[1]) / 2;\n\n            if (x === midX && y === midY) {\n              continue;\n            }\n          }\n        }\n\n        // All points except control points are on curve.\n        if (!(c.command === 'quadraticCurveTo' && j === 0)) {\n          flag |= ON_CURVE$1;\n        }\n\n        flag = this._encodePoint(x, lastX, xPoints, flag, X_SHORT_VECTOR$1, SAME_X$1);\n        flag = this._encodePoint(y, lastY, yPoints, flag, Y_SHORT_VECTOR$1, SAME_Y$1);\n\n        if (flag === lastFlag && same < 255) {\n          flags[flags.length - 1] |= REPEAT$1;\n          same++;\n        } else {\n          if (same > 0) {\n            flags.push(same);\n            same = 0;\n          }\n\n          flags.push(flag);\n          lastFlag = flag;\n        }\n\n        lastX = x;\n        lastY = y;\n        pointCount++;\n      }\n\n      if (c.command === 'closePath') {\n        endPtsOfContours.push(pointCount - 1);\n      }\n    }\n\n    // Close the path if the last command didn't already\n    if (path.commands.length > 1 && path.commands[path.commands.length - 1].command !== 'closePath') {\n      endPtsOfContours.push(pointCount - 1);\n    }\n\n    var bbox = path.bbox;\n    var glyf = {\n      numberOfContours: endPtsOfContours.length,\n      xMin: bbox.minX,\n      yMin: bbox.minY,\n      xMax: bbox.maxX,\n      yMax: bbox.maxY,\n      endPtsOfContours: endPtsOfContours,\n      instructions: instructions,\n      flags: flags,\n      xPoints: xPoints,\n      yPoints: yPoints\n    };\n\n    var size = Glyf.size(glyf);\n    var tail = 4 - size % 4;\n\n    var stream = new r.EncodeStream(size + tail);\n    Glyf.encode(stream, glyf);\n\n    // Align to 4-byte length\n    if (tail !== 0) {\n      stream.fill(0, tail);\n    }\n\n    return stream.buffer;\n  };\n\n  TTFGlyphEncoder.prototype._encodePoint = function _encodePoint(value, last, points, flag, shortFlag, sameFlag) {\n    var diff = value - last;\n\n    if (value === last) {\n      flag |= sameFlag;\n    } else {\n      if (-255 <= diff && diff <= 255) {\n        flag |= shortFlag;\n        if (diff < 0) {\n          diff = -diff;\n        } else {\n          flag |= sameFlag;\n        }\n      }\n\n      points.push(diff);\n    }\n\n    return flag;\n  };\n\n  return TTFGlyphEncoder;\n}();\n\nvar TTFSubset = function (_Subset) {\n  _inherits(TTFSubset, _Subset);\n\n  function TTFSubset(font) {\n    _classCallCheck(this, TTFSubset);\n\n    var _this = _possibleConstructorReturn(this, _Subset.call(this, font));\n\n    _this.glyphEncoder = new TTFGlyphEncoder();\n    return _this;\n  }\n\n  TTFSubset.prototype._addGlyph = function _addGlyph(gid) {\n    var glyph = this.font.getGlyph(gid);\n    var glyf = glyph._decode();\n\n    // get the offset to the glyph from the loca table\n    var curOffset = this.font.loca.offsets[gid];\n    var nextOffset = this.font.loca.offsets[gid + 1];\n\n    var stream = this.font._getTableStream('glyf');\n    stream.pos += curOffset;\n\n    var buffer = stream.readBuffer(nextOffset - curOffset);\n\n    // if it is a compound glyph, include its components\n    if (glyf && glyf.numberOfContours < 0) {\n      buffer = new Buffer(buffer);\n      for (var _iterator = glyf.components, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n        var _ref;\n\n        if (_isArray) {\n          if (_i >= _iterator.length) break;\n          _ref = _iterator[_i++];\n        } else {\n          _i = _iterator.next();\n          if (_i.done) break;\n          _ref = _i.value;\n        }\n\n        var component = _ref;\n\n        gid = this.includeGlyph(component.glyphID);\n        buffer.writeUInt16BE(gid, component.pos);\n      }\n    } else if (glyf && this.font._variationProcessor) {\n      // If this is a TrueType variation glyph, re-encode the path\n      buffer = this.glyphEncoder.encodeSimple(glyph.path, glyf.instructions);\n    }\n\n    this.glyf.push(buffer);\n    this.loca.offsets.push(this.offset);\n\n    this.hmtx.metrics.push({\n      advance: glyph.advanceWidth,\n      bearing: glyph._getMetrics().leftBearing\n    });\n\n    this.offset += buffer.length;\n    return this.glyf.length - 1;\n  };\n\n  TTFSubset.prototype.encode = function encode(stream) {\n    // tables required by PDF spec:\n    //   head, hhea, loca, maxp, cvt , prep, glyf, hmtx, fpgm\n    //\n    // additional tables required for standalone fonts:\n    //   name, cmap, OS/2, post\n\n    this.glyf = [];\n    this.offset = 0;\n    this.loca = {\n      offsets: []\n    };\n\n    this.hmtx = {\n      metrics: [],\n      bearings: []\n    };\n\n    // include all the glyphs\n    // not using a for loop because we need to support adding more\n    // glyphs to the array as we go, and CoffeeScript caches the length.\n    var i = 0;\n    while (i < this.glyphs.length) {\n      this._addGlyph(this.glyphs[i++]);\n    }\n\n    var maxp = cloneDeep(this.font.maxp);\n    maxp.numGlyphs = this.glyf.length;\n\n    this.loca.offsets.push(this.offset);\n    tables.loca.preEncode.call(this.loca);\n\n    var head = cloneDeep(this.font.head);\n    head.indexToLocFormat = this.loca.version;\n\n    var hhea = cloneDeep(this.font.hhea);\n    hhea.numberOfMetrics = this.hmtx.metrics.length;\n\n    // map = []\n    // for index in [0...256]\n    //     if index < @numGlyphs\n    //         map[index] = index\n    //     else\n    //         map[index] = 0\n    //\n    // cmapTable =\n    //     version: 0\n    //     length: 262\n    //     language: 0\n    //     codeMap: map\n    //\n    // cmap =\n    //     version: 0\n    //     numSubtables: 1\n    //     tables: [\n    //         platformID: 1\n    //         encodingID: 0\n    //         table: cmapTable\n    //     ]\n\n    // TODO: subset prep, cvt, fpgm?\n    Directory.encode(stream, {\n      tables: {\n        head: head,\n        hhea: hhea,\n        loca: this.loca,\n        maxp: maxp,\n        'cvt ': this.font['cvt '],\n        prep: this.font.prep,\n        glyf: this.glyf,\n        hmtx: this.hmtx,\n        fpgm: this.font.fpgm\n\n        // name: clone @font.name\n        // 'OS/2': clone @font['OS/2']\n        // post: clone @font.post\n        // cmap: cmap\n      }\n    });\n  };\n\n  return TTFSubset;\n}(Subset);\n\nvar CFFSubset = function (_Subset) {\n  _inherits(CFFSubset, _Subset);\n\n  function CFFSubset(font) {\n    _classCallCheck(this, CFFSubset);\n\n    var _this = _possibleConstructorReturn(this, _Subset.call(this, font));\n\n    _this.cff = _this.font['CFF '];\n    if (!_this.cff) {\n      throw new Error('Not a CFF Font');\n    }\n    return _this;\n  }\n\n  CFFSubset.prototype.subsetCharstrings = function subsetCharstrings() {\n    this.charstrings = [];\n    var gsubrs = {};\n\n    for (var _iterator = this.glyphs, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var gid = _ref;\n\n      this.charstrings.push(this.cff.getCharString(gid));\n\n      var glyph = this.font.getGlyph(gid);\n      var path = glyph.path; // this causes the glyph to be parsed\n\n      for (var subr in glyph._usedGsubrs) {\n        gsubrs[subr] = true;\n      }\n    }\n\n    this.gsubrs = this.subsetSubrs(this.cff.globalSubrIndex, gsubrs);\n  };\n\n  CFFSubset.prototype.subsetSubrs = function subsetSubrs(subrs, used) {\n    var res = [];\n    for (var i = 0; i < subrs.length; i++) {\n      var subr = subrs[i];\n      if (used[i]) {\n        this.cff.stream.pos = subr.offset;\n        res.push(this.cff.stream.readBuffer(subr.length));\n      } else {\n        res.push(new Buffer([11])); // return\n      }\n    }\n\n    return res;\n  };\n\n  CFFSubset.prototype.subsetFontdict = function subsetFontdict(topDict) {\n    topDict.FDArray = [];\n    topDict.FDSelect = {\n      version: 0,\n      fds: []\n    };\n\n    var used_fds = {};\n    var used_subrs = [];\n    for (var _iterator2 = this.glyphs, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n      var _ref2;\n\n      if (_isArray2) {\n        if (_i2 >= _iterator2.length) break;\n        _ref2 = _iterator2[_i2++];\n      } else {\n        _i2 = _iterator2.next();\n        if (_i2.done) break;\n        _ref2 = _i2.value;\n      }\n\n      var gid = _ref2;\n\n      var fd = this.cff.fdForGlyph(gid);\n      if (fd == null) {\n        continue;\n      }\n\n      if (!used_fds[fd]) {\n        topDict.FDArray.push(_Object$assign({}, this.cff.topDict.FDArray[fd]));\n        used_subrs.push({});\n      }\n\n      used_fds[fd] = true;\n      topDict.FDSelect.fds.push(topDict.FDArray.length - 1);\n\n      var glyph = this.font.getGlyph(gid);\n      var path = glyph.path; // this causes the glyph to be parsed\n      for (var subr in glyph._usedSubrs) {\n        used_subrs[used_subrs.length - 1][subr] = true;\n      }\n    }\n\n    for (var i = 0; i < topDict.FDArray.length; i++) {\n      var dict = topDict.FDArray[i];\n      delete dict.FontName;\n      if (dict.Private && dict.Private.Subrs) {\n        dict.Private = _Object$assign({}, dict.Private);\n        dict.Private.Subrs = this.subsetSubrs(dict.Private.Subrs, used_subrs[i]);\n      }\n    }\n\n    return;\n  };\n\n  CFFSubset.prototype.createCIDFontdict = function createCIDFontdict(topDict) {\n    var used_subrs = {};\n    for (var _iterator3 = this.glyphs, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n      var _ref3;\n\n      if (_isArray3) {\n        if (_i3 >= _iterator3.length) break;\n        _ref3 = _iterator3[_i3++];\n      } else {\n        _i3 = _iterator3.next();\n        if (_i3.done) break;\n        _ref3 = _i3.value;\n      }\n\n      var gid = _ref3;\n\n      var glyph = this.font.getGlyph(gid);\n      var path = glyph.path; // this causes the glyph to be parsed\n\n      for (var subr in glyph._usedSubrs) {\n        used_subrs[subr] = true;\n      }\n    }\n\n    var privateDict = _Object$assign({}, this.cff.topDict.Private);\n    privateDict.Subrs = this.subsetSubrs(this.cff.topDict.Private.Subrs, used_subrs);\n\n    topDict.FDArray = [{ Private: privateDict }];\n    return topDict.FDSelect = {\n      version: 3,\n      nRanges: 1,\n      ranges: [{ first: 0, fd: 0 }],\n      sentinel: this.charstrings.length\n    };\n  };\n\n  CFFSubset.prototype.addString = function addString(string) {\n    if (!string) {\n      return null;\n    }\n\n    if (!this.strings) {\n      this.strings = [];\n    }\n\n    this.strings.push(string);\n    return standardStrings.length + this.strings.length - 1;\n  };\n\n  CFFSubset.prototype.encode = function encode(stream) {\n    this.subsetCharstrings();\n\n    var charset = {\n      version: this.charstrings.length > 255 ? 2 : 1,\n      ranges: [{ first: 1, nLeft: this.charstrings.length - 2 }]\n    };\n\n    var topDict = _Object$assign({}, this.cff.topDict);\n    topDict.Private = null;\n    topDict.charset = charset;\n    topDict.Encoding = null;\n    topDict.CharStrings = this.charstrings;\n\n    var _arr = ['version', 'Notice', 'Copyright', 'FullName', 'FamilyName', 'Weight', 'PostScript', 'BaseFontName', 'FontName'];\n    for (var _i4 = 0; _i4 < _arr.length; _i4++) {\n      var key = _arr[_i4];\n      topDict[key] = this.addString(this.cff.string(topDict[key]));\n    }\n\n    topDict.ROS = [this.addString('Adobe'), this.addString('Identity'), 0];\n    topDict.CIDCount = this.charstrings.length;\n\n    if (this.cff.isCIDFont) {\n      this.subsetFontdict(topDict);\n    } else {\n      this.createCIDFontdict(topDict);\n    }\n\n    var top = {\n      version: 1,\n      hdrSize: this.cff.hdrSize,\n      offSize: this.cff.length,\n      header: this.cff.header,\n      nameIndex: [this.cff.postscriptName],\n      topDictIndex: [topDict],\n      stringIndex: this.strings,\n      globalSubrIndex: this.gsubrs\n    };\n\n    CFFTop.encode(stream, top);\n  };\n\n  return CFFSubset;\n}(Subset);\n\nvar _class;\nfunction _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {\n  var desc = {};\n  Object['ke' + 'ys'](descriptor).forEach(function (key) {\n    desc[key] = descriptor[key];\n  });\n  desc.enumerable = !!desc.enumerable;\n  desc.configurable = !!desc.configurable;\n\n  if ('value' in desc || desc.initializer) {\n    desc.writable = true;\n  }\n\n  desc = decorators.slice().reverse().reduce(function (desc, decorator) {\n    return decorator(target, property, desc) || desc;\n  }, desc);\n\n  if (context && desc.initializer !== void 0) {\n    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;\n    desc.initializer = undefined;\n  }\n\n  if (desc.initializer === void 0) {\n    Object['define' + 'Property'](target, property, desc);\n    desc = null;\n  }\n\n  return desc;\n}\n\n/**\n * This is the base class for all SFNT-based font formats in fontkit.\n * It supports TrueType, and PostScript glyphs, and several color glyph formats.\n */\nvar TTFFont = (_class = function () {\n  TTFFont.probe = function probe(buffer) {\n    var format = buffer.toString('ascii', 0, 4);\n    return format === 'true' || format === 'OTTO' || format === String.fromCharCode(0, 1, 0, 0);\n  };\n\n  function TTFFont(stream) {\n    var variationCoords = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\n\n    _classCallCheck(this, TTFFont);\n\n    this.stream = stream;\n    this.variationCoords = variationCoords;\n\n    this._directoryPos = this.stream.pos;\n    this._tables = {};\n    this._glyphs = {};\n    this._decodeDirectory();\n\n    // define properties for each table to lazily parse\n    for (var tag in this.directory.tables) {\n      var table = this.directory.tables[tag];\n      if (tables[tag] && table.length > 0) {\n        _Object$defineProperty(this, tag, {\n          get: this._getTable.bind(this, table)\n        });\n      }\n    }\n  }\n\n  TTFFont.prototype._getTable = function _getTable(table) {\n    if (!(table.tag in this._tables)) {\n      try {\n        this._tables[table.tag] = this._decodeTable(table);\n      } catch (e) {\n        if (fontkit.logErrors) {\n          console.error('Error decoding table ' + table.tag);\n          console.error(e.stack);\n        }\n      }\n    }\n\n    return this._tables[table.tag];\n  };\n\n  TTFFont.prototype._getTableStream = function _getTableStream(tag) {\n    var table = this.directory.tables[tag];\n    if (table) {\n      this.stream.pos = table.offset;\n      return this.stream;\n    }\n\n    return null;\n  };\n\n  TTFFont.prototype._decodeDirectory = function _decodeDirectory() {\n    return this.directory = Directory.decode(this.stream, { _startOffset: 0 });\n  };\n\n  TTFFont.prototype._decodeTable = function _decodeTable(table) {\n    var pos = this.stream.pos;\n\n    var stream = this._getTableStream(table.tag);\n    var result = tables[table.tag].decode(stream, this, table.length);\n\n    this.stream.pos = pos;\n    return result;\n  };\n\n  /**\n   * The unique PostScript name for this font\n   * @type {string}\n   */\n\n\n  /**\n   * Gets a string from the font's `name` table\n   * `lang` is a BCP-47 language code.\n   * @return {string}\n   */\n  TTFFont.prototype.getName = function getName(key) {\n    var lang = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'en';\n\n    var record = this.name.records[key];\n    if (record) {\n      return record[lang];\n    }\n\n    return null;\n  };\n\n  /**\n   * The font's full name, e.g. \"Helvetica Bold\"\n   * @type {string}\n   */\n\n\n  /**\n   * Returns whether there is glyph in the font for the given unicode code point.\n   *\n   * @param {number} codePoint\n   * @return {boolean}\n   */\n  TTFFont.prototype.hasGlyphForCodePoint = function hasGlyphForCodePoint(codePoint) {\n    return !!this._cmapProcessor.lookup(codePoint);\n  };\n\n  /**\n   * Maps a single unicode code point to a Glyph object.\n   * Does not perform any advanced substitutions (there is no context to do so).\n   *\n   * @param {number} codePoint\n   * @return {Glyph}\n   */\n\n\n  TTFFont.prototype.glyphForCodePoint = function glyphForCodePoint(codePoint) {\n    return this.getGlyph(this._cmapProcessor.lookup(codePoint), [codePoint]);\n  };\n\n  /**\n   * Returns an array of Glyph objects for the given string.\n   * This is only a one-to-one mapping from characters to glyphs.\n   * For most uses, you should use font.layout (described below), which\n   * provides a much more advanced mapping supporting AAT and OpenType shaping.\n   *\n   * @param {string} string\n   * @return {Glyph[]}\n   */\n\n\n  TTFFont.prototype.glyphsForString = function glyphsForString(string) {\n    var glyphs = [];\n    var len = string.length;\n    var idx = 0;\n    var last = -1;\n    var state = -1;\n\n    while (idx <= len) {\n      var code = 0;\n      var nextState = 0;\n\n      if (idx < len) {\n        // Decode the next codepoint from UTF 16\n        code = string.charCodeAt(idx++);\n        if (0xd800 <= code && code <= 0xdbff && idx < len) {\n          var next = string.charCodeAt(idx);\n          if (0xdc00 <= next && next <= 0xdfff) {\n            idx++;\n            code = ((code & 0x3ff) << 10) + (next & 0x3ff) + 0x10000;\n          }\n        }\n\n        // Compute the next state: 1 if the next codepoint is a variation selector, 0 otherwise.\n        nextState = 0xfe00 <= code && code <= 0xfe0f || 0xe0100 <= code && code <= 0xe01ef ? 1 : 0;\n      } else {\n        idx++;\n      }\n\n      if (state === 0 && nextState === 1) {\n        // Variation selector following normal codepoint.\n        glyphs.push(this.getGlyph(this._cmapProcessor.lookup(last, code), [last, code]));\n      } else if (state === 0 && nextState === 0) {\n        // Normal codepoint following normal codepoint.\n        glyphs.push(this.glyphForCodePoint(last));\n      }\n\n      last = code;\n      state = nextState;\n    }\n\n    return glyphs;\n  };\n\n  /**\n   * Returns a GlyphRun object, which includes an array of Glyphs and GlyphPositions for the given string.\n   *\n   * @param {string} string\n   * @param {string[]} [userFeatures]\n   * @param {string} [script]\n   * @param {string} [language]\n   * @param {string} [direction]\n   * @return {GlyphRun}\n   */\n  TTFFont.prototype.layout = function layout(string, userFeatures, script, language, direction) {\n    return this._layoutEngine.layout(string, userFeatures, script, language, direction);\n  };\n\n  /**\n   * Returns an array of strings that map to the given glyph id.\n   * @param {number} gid - glyph id\n   */\n\n\n  TTFFont.prototype.stringsForGlyph = function stringsForGlyph(gid) {\n    return this._layoutEngine.stringsForGlyph(gid);\n  };\n\n  /**\n   * An array of all [OpenType feature tags](https://www.microsoft.com/typography/otspec/featuretags.htm)\n   * (or mapped AAT tags) supported by the font.\n   * The features parameter is an array of OpenType feature tags to be applied in addition to the default set.\n   * If this is an AAT font, the OpenType feature tags are mapped to AAT features.\n   *\n   * @type {string[]}\n   */\n\n\n  TTFFont.prototype.getAvailableFeatures = function getAvailableFeatures(script, language) {\n    return this._layoutEngine.getAvailableFeatures(script, language);\n  };\n\n  TTFFont.prototype._getBaseGlyph = function _getBaseGlyph(glyph) {\n    var characters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n\n    if (!this._glyphs[glyph]) {\n      if (this.directory.tables.glyf) {\n        this._glyphs[glyph] = new TTFGlyph(glyph, characters, this);\n      } else if (this.directory.tables['CFF '] || this.directory.tables.CFF2) {\n        this._glyphs[glyph] = new CFFGlyph(glyph, characters, this);\n      }\n    }\n\n    return this._glyphs[glyph] || null;\n  };\n\n  /**\n   * Returns a glyph object for the given glyph id.\n   * You can pass the array of code points this glyph represents for\n   * your use later, and it will be stored in the glyph object.\n   *\n   * @param {number} glyph\n   * @param {number[]} characters\n   * @return {Glyph}\n   */\n\n\n  TTFFont.prototype.getGlyph = function getGlyph(glyph) {\n    var characters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n\n    if (!this._glyphs[glyph]) {\n      if (this.directory.tables.sbix) {\n        this._glyphs[glyph] = new SBIXGlyph(glyph, characters, this);\n      } else if (this.directory.tables.COLR && this.directory.tables.CPAL) {\n        this._glyphs[glyph] = new COLRGlyph(glyph, characters, this);\n      } else {\n        this._getBaseGlyph(glyph, characters);\n      }\n    }\n\n    return this._glyphs[glyph] || null;\n  };\n\n  /**\n   * Returns a Subset for this font.\n   * @return {Subset}\n   */\n\n\n  TTFFont.prototype.createSubset = function createSubset() {\n    if (this.directory.tables['CFF ']) {\n      return new CFFSubset(this);\n    }\n\n    return new TTFSubset(this);\n  };\n\n  /**\n   * Returns an object describing the available variation axes\n   * that this font supports. Keys are setting tags, and values\n   * contain the axis name, range, and default value.\n   *\n   * @type {object}\n   */\n\n\n  /**\n   * Returns a new font with the given variation settings applied.\n   * Settings can either be an instance name, or an object containing\n   * variation tags as specified by the `variationAxes` property.\n   *\n   * @param {object} settings\n   * @return {TTFFont}\n   */\n  TTFFont.prototype.getVariation = function getVariation(settings) {\n    if (!(this.directory.tables.fvar && (this.directory.tables.gvar && this.directory.tables.glyf || this.directory.tables.CFF2))) {\n      throw new Error('Variations require a font with the fvar, gvar and glyf, or CFF2 tables.');\n    }\n\n    if (typeof settings === 'string') {\n      settings = this.namedVariations[settings];\n    }\n\n    if ((typeof settings === 'undefined' ? 'undefined' : _typeof(settings)) !== 'object') {\n      throw new Error('Variation settings must be either a variation name or settings object.');\n    }\n\n    // normalize the coordinates\n    var coords = this.fvar.axis.map(function (axis, i) {\n      var axisTag = axis.axisTag.trim();\n      if (axisTag in settings) {\n        return Math.max(axis.minValue, Math.min(axis.maxValue, settings[axisTag]));\n      } else {\n        return axis.defaultValue;\n      }\n    });\n\n    var stream = new r.DecodeStream(this.stream.buffer);\n    stream.pos = this._directoryPos;\n\n    var font = new TTFFont(stream, coords);\n    font._tables = this._tables;\n\n    return font;\n  };\n\n  // Standardized format plugin API\n  TTFFont.prototype.getFont = function getFont(name) {\n    return this.getVariation(name);\n  };\n\n  _createClass(TTFFont, [{\n    key: 'postscriptName',\n    get: function get() {\n      var name = this.name.records.postscriptName;\n      if (name) {\n        var lang = _Object$keys(name)[0];\n        return name[lang];\n      }\n\n      return null;\n    }\n  }, {\n    key: 'fullName',\n    get: function get() {\n      return this.getName('fullName');\n    }\n\n    /**\n     * The font's family name, e.g. \"Helvetica\"\n     * @type {string}\n     */\n\n  }, {\n    key: 'familyName',\n    get: function get() {\n      return this.getName('fontFamily');\n    }\n\n    /**\n     * The font's sub-family, e.g. \"Bold\".\n     * @type {string}\n     */\n\n  }, {\n    key: 'subfamilyName',\n    get: function get() {\n      return this.getName('fontSubfamily');\n    }\n\n    /**\n     * The font's copyright information\n     * @type {string}\n     */\n\n  }, {\n    key: 'copyright',\n    get: function get() {\n      return this.getName('copyright');\n    }\n\n    /**\n     * The font's version number\n     * @type {string}\n     */\n\n  }, {\n    key: 'version',\n    get: function get() {\n      return this.getName('version');\n    }\n\n    /**\n     * The font’s [ascender](https://en.wikipedia.org/wiki/Ascender_(typography))\n     * @type {number}\n     */\n\n  }, {\n    key: 'ascent',\n    get: function get() {\n      return this.hhea.ascent;\n    }\n\n    /**\n     * The font’s [descender](https://en.wikipedia.org/wiki/Descender)\n     * @type {number}\n     */\n\n  }, {\n    key: 'descent',\n    get: function get() {\n      return this.hhea.descent;\n    }\n\n    /**\n     * The amount of space that should be included between lines\n     * @type {number}\n     */\n\n  }, {\n    key: 'lineGap',\n    get: function get() {\n      return this.hhea.lineGap;\n    }\n\n    /**\n     * The offset from the normal underline position that should be used\n     * @type {number}\n     */\n\n  }, {\n    key: 'underlinePosition',\n    get: function get() {\n      return this.post.underlinePosition;\n    }\n\n    /**\n     * The weight of the underline that should be used\n     * @type {number}\n     */\n\n  }, {\n    key: 'underlineThickness',\n    get: function get() {\n      return this.post.underlineThickness;\n    }\n\n    /**\n     * If this is an italic font, the angle the cursor should be drawn at to match the font design\n     * @type {number}\n     */\n\n  }, {\n    key: 'italicAngle',\n    get: function get() {\n      return this.post.italicAngle;\n    }\n\n    /**\n     * The height of capital letters above the baseline.\n     * See [here](https://en.wikipedia.org/wiki/Cap_height) for more details.\n     * @type {number}\n     */\n\n  }, {\n    key: 'capHeight',\n    get: function get() {\n      var os2 = this['OS/2'];\n      return os2 ? os2.capHeight : this.ascent;\n    }\n\n    /**\n     * The height of lower case letters in the font.\n     * See [here](https://en.wikipedia.org/wiki/X-height) for more details.\n     * @type {number}\n     */\n\n  }, {\n    key: 'xHeight',\n    get: function get() {\n      var os2 = this['OS/2'];\n      return os2 ? os2.xHeight : 0;\n    }\n\n    /**\n     * The number of glyphs in the font.\n     * @type {number}\n     */\n\n  }, {\n    key: 'numGlyphs',\n    get: function get() {\n      return this.maxp.numGlyphs;\n    }\n\n    /**\n     * The size of the font’s internal coordinate grid\n     * @type {number}\n     */\n\n  }, {\n    key: 'unitsPerEm',\n    get: function get() {\n      return this.head.unitsPerEm;\n    }\n\n    /**\n     * The font’s bounding box, i.e. the box that encloses all glyphs in the font.\n     * @type {BBox}\n     */\n\n  }, {\n    key: 'bbox',\n    get: function get() {\n      return _Object$freeze(new BBox(this.head.xMin, this.head.yMin, this.head.xMax, this.head.yMax));\n    }\n  }, {\n    key: '_cmapProcessor',\n    get: function get() {\n      return new CmapProcessor(this.cmap);\n    }\n\n    /**\n     * An array of all of the unicode code points supported by the font.\n     * @type {number[]}\n     */\n\n  }, {\n    key: 'characterSet',\n    get: function get() {\n      return this._cmapProcessor.getCharacterSet();\n    }\n  }, {\n    key: '_layoutEngine',\n    get: function get() {\n      return new LayoutEngine(this);\n    }\n  }, {\n    key: 'availableFeatures',\n    get: function get() {\n      return this._layoutEngine.getAvailableFeatures();\n    }\n  }, {\n    key: 'variationAxes',\n    get: function get() {\n      var res = {};\n      if (!this.fvar) {\n        return res;\n      }\n\n      for (var _iterator = this.fvar.axis, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n        var _ref;\n\n        if (_isArray) {\n          if (_i >= _iterator.length) break;\n          _ref = _iterator[_i++];\n        } else {\n          _i = _iterator.next();\n          if (_i.done) break;\n          _ref = _i.value;\n        }\n\n        var axis = _ref;\n\n        res[axis.axisTag.trim()] = {\n          name: axis.name.en,\n          min: axis.minValue,\n          default: axis.defaultValue,\n          max: axis.maxValue\n        };\n      }\n\n      return res;\n    }\n\n    /**\n     * Returns an object describing the named variation instances\n     * that the font designer has specified. Keys are variation names\n     * and values are the variation settings for this instance.\n     *\n     * @type {object}\n     */\n\n  }, {\n    key: 'namedVariations',\n    get: function get() {\n      var res = {};\n      if (!this.fvar) {\n        return res;\n      }\n\n      for (var _iterator2 = this.fvar.instance, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n        var _ref2;\n\n        if (_isArray2) {\n          if (_i2 >= _iterator2.length) break;\n          _ref2 = _iterator2[_i2++];\n        } else {\n          _i2 = _iterator2.next();\n          if (_i2.done) break;\n          _ref2 = _i2.value;\n        }\n\n        var instance = _ref2;\n\n        var settings = {};\n        for (var i = 0; i < this.fvar.axis.length; i++) {\n          var axis = this.fvar.axis[i];\n          settings[axis.axisTag.trim()] = instance.coord[i];\n        }\n\n        res[instance.name.en] = settings;\n      }\n\n      return res;\n    }\n  }, {\n    key: '_variationProcessor',\n    get: function get() {\n      if (!this.fvar) {\n        return null;\n      }\n\n      var variationCoords = this.variationCoords;\n\n      // Ignore if no variation coords and not CFF2\n      if (!variationCoords && !this.CFF2) {\n        return null;\n      }\n\n      if (!variationCoords) {\n        variationCoords = this.fvar.axis.map(function (axis) {\n          return axis.defaultValue;\n        });\n      }\n\n      return new GlyphVariationProcessor(this, variationCoords);\n    }\n  }]);\n\n  return TTFFont;\n}(), (_applyDecoratedDescriptor(_class.prototype, 'bbox', [cache], _Object$getOwnPropertyDescriptor(_class.prototype, 'bbox'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, '_cmapProcessor', [cache], _Object$getOwnPropertyDescriptor(_class.prototype, '_cmapProcessor'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'characterSet', [cache], _Object$getOwnPropertyDescriptor(_class.prototype, 'characterSet'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, '_layoutEngine', [cache], _Object$getOwnPropertyDescriptor(_class.prototype, '_layoutEngine'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'variationAxes', [cache], _Object$getOwnPropertyDescriptor(_class.prototype, 'variationAxes'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'namedVariations', [cache], _Object$getOwnPropertyDescriptor(_class.prototype, 'namedVariations'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, '_variationProcessor', [cache], _Object$getOwnPropertyDescriptor(_class.prototype, '_variationProcessor'), _class.prototype)), _class);\n\nvar WOFFDirectoryEntry = new r.Struct({\n  tag: new r.String(4),\n  offset: new r.Pointer(r.uint32, 'void', { type: 'global' }),\n  compLength: r.uint32,\n  length: r.uint32,\n  origChecksum: r.uint32\n});\n\nvar WOFFDirectory = new r.Struct({\n  tag: new r.String(4), // should be 'wOFF'\n  flavor: r.uint32,\n  length: r.uint32,\n  numTables: r.uint16,\n  reserved: new r.Reserved(r.uint16),\n  totalSfntSize: r.uint32,\n  majorVersion: r.uint16,\n  minorVersion: r.uint16,\n  metaOffset: r.uint32,\n  metaLength: r.uint32,\n  metaOrigLength: r.uint32,\n  privOffset: r.uint32,\n  privLength: r.uint32,\n  tables: new r.Array(WOFFDirectoryEntry, 'numTables')\n});\n\nWOFFDirectory.process = function () {\n  var tables = {};\n  for (var _iterator = this.tables, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n    var _ref;\n\n    if (_isArray) {\n      if (_i >= _iterator.length) break;\n      _ref = _iterator[_i++];\n    } else {\n      _i = _iterator.next();\n      if (_i.done) break;\n      _ref = _i.value;\n    }\n\n    var table = _ref;\n\n    tables[table.tag] = table;\n  }\n\n  this.tables = tables;\n};\n\nvar WOFFFont = function (_TTFFont) {\n  _inherits(WOFFFont, _TTFFont);\n\n  function WOFFFont() {\n    _classCallCheck(this, WOFFFont);\n\n    return _possibleConstructorReturn(this, _TTFFont.apply(this, arguments));\n  }\n\n  WOFFFont.probe = function probe(buffer) {\n    return buffer.toString('ascii', 0, 4) === 'wOFF';\n  };\n\n  WOFFFont.prototype._decodeDirectory = function _decodeDirectory() {\n    this.directory = WOFFDirectory.decode(this.stream, { _startOffset: 0 });\n  };\n\n  WOFFFont.prototype._getTableStream = function _getTableStream(tag) {\n    var table = this.directory.tables[tag];\n    if (table) {\n      this.stream.pos = table.offset;\n\n      if (table.compLength < table.length) {\n        this.stream.pos += 2; // skip deflate header\n        var outBuffer = new Buffer(table.length);\n        var buf = inflate(this.stream.readBuffer(table.compLength - 2), outBuffer);\n        return new r.DecodeStream(buf);\n      } else {\n        return this.stream;\n      }\n    }\n\n    return null;\n  };\n\n  return WOFFFont;\n}(TTFFont);\n\n/**\n * Represents a TrueType glyph in the WOFF2 format, which compresses glyphs differently.\n */\n\nvar WOFF2Glyph = function (_TTFGlyph) {\n  _inherits(WOFF2Glyph, _TTFGlyph);\n\n  function WOFF2Glyph() {\n    _classCallCheck(this, WOFF2Glyph);\n\n    return _possibleConstructorReturn(this, _TTFGlyph.apply(this, arguments));\n  }\n\n  WOFF2Glyph.prototype._decode = function _decode() {\n    // We have to decode in advance (in WOFF2Font), so just return the pre-decoded data.\n    return this._font._transformedGlyphs[this.id];\n  };\n\n  WOFF2Glyph.prototype._getCBox = function _getCBox() {\n    return this.path.bbox;\n  };\n\n  return WOFF2Glyph;\n}(TTFGlyph);\n\nvar Base128 = {\n  decode: function decode(stream) {\n    var result = 0;\n    var iterable = [0, 1, 2, 3, 4];\n    for (var j = 0; j < iterable.length; j++) {\n      var i = iterable[j];\n      var code = stream.readUInt8();\n\n      // If any of the top seven bits are set then we're about to overflow.\n      if (result & 0xe0000000) {\n        throw new Error('Overflow');\n      }\n\n      result = result << 7 | code & 0x7f;\n      if ((code & 0x80) === 0) {\n        return result;\n      }\n    }\n\n    throw new Error('Bad base 128 number');\n  }\n};\n\nvar knownTags = ['cmap', 'head', 'hhea', 'hmtx', 'maxp', 'name', 'OS/2', 'post', 'cvt ', 'fpgm', 'glyf', 'loca', 'prep', 'CFF ', 'VORG', 'EBDT', 'EBLC', 'gasp', 'hdmx', 'kern', 'LTSH', 'PCLT', 'VDMX', 'vhea', 'vmtx', 'BASE', 'GDEF', 'GPOS', 'GSUB', 'EBSC', 'JSTF', 'MATH', 'CBDT', 'CBLC', 'COLR', 'CPAL', 'SVG ', 'sbix', 'acnt', 'avar', 'bdat', 'bloc', 'bsln', 'cvar', 'fdsc', 'feat', 'fmtx', 'fvar', 'gvar', 'hsty', 'just', 'lcar', 'mort', 'morx', 'opbd', 'prop', 'trak', 'Zapf', 'Silf', 'Glat', 'Gloc', 'Feat', 'Sill'];\n\nvar WOFF2DirectoryEntry = new r.Struct({\n  flags: r.uint8,\n  customTag: new r.Optional(new r.String(4), function (t) {\n    return (t.flags & 0x3f) === 0x3f;\n  }),\n  tag: function tag(t) {\n    return t.customTag || knownTags[t.flags & 0x3f];\n  }, // || (() => { throw new Error(`Bad tag: ${flags & 0x3f}`); })(); },\n  length: Base128,\n  transformVersion: function transformVersion(t) {\n    return t.flags >>> 6 & 0x03;\n  },\n  transformed: function transformed(t) {\n    return t.tag === 'glyf' || t.tag === 'loca' ? t.transformVersion === 0 : t.transformVersion !== 0;\n  },\n  transformLength: new r.Optional(Base128, function (t) {\n    return t.transformed;\n  })\n});\n\nvar WOFF2Directory = new r.Struct({\n  tag: new r.String(4), // should be 'wOF2'\n  flavor: r.uint32,\n  length: r.uint32,\n  numTables: r.uint16,\n  reserved: new r.Reserved(r.uint16),\n  totalSfntSize: r.uint32,\n  totalCompressedSize: r.uint32,\n  majorVersion: r.uint16,\n  minorVersion: r.uint16,\n  metaOffset: r.uint32,\n  metaLength: r.uint32,\n  metaOrigLength: r.uint32,\n  privOffset: r.uint32,\n  privLength: r.uint32,\n  tables: new r.Array(WOFF2DirectoryEntry, 'numTables')\n});\n\nWOFF2Directory.process = function () {\n  var tables = {};\n  for (var i = 0; i < this.tables.length; i++) {\n    var table = this.tables[i];\n    tables[table.tag] = table;\n  }\n\n  return this.tables = tables;\n};\n\n/**\n * Subclass of TTFFont that represents a TTF/OTF font compressed by WOFF2\n * See spec here: http://www.w3.org/TR/WOFF2/\n */\n\nvar WOFF2Font = function (_TTFFont) {\n  _inherits(WOFF2Font, _TTFFont);\n\n  function WOFF2Font() {\n    _classCallCheck(this, WOFF2Font);\n\n    return _possibleConstructorReturn(this, _TTFFont.apply(this, arguments));\n  }\n\n  WOFF2Font.probe = function probe(buffer) {\n    return buffer.toString('ascii', 0, 4) === 'wOF2';\n  };\n\n  WOFF2Font.prototype._decodeDirectory = function _decodeDirectory() {\n    this.directory = WOFF2Directory.decode(this.stream);\n    this._dataPos = this.stream.pos;\n  };\n\n  WOFF2Font.prototype._decompress = function _decompress() {\n    // decompress data and setup table offsets if we haven't already\n    if (!this._decompressed) {\n      this.stream.pos = this._dataPos;\n      var buffer = this.stream.readBuffer(this.directory.totalCompressedSize);\n\n      var decompressedSize = 0;\n      for (var tag in this.directory.tables) {\n        var entry = this.directory.tables[tag];\n        entry.offset = decompressedSize;\n        decompressedSize += entry.transformLength != null ? entry.transformLength : entry.length;\n      }\n\n      var decompressed = brotli(buffer, decompressedSize);\n      if (!decompressed) {\n        throw new Error('Error decoding compressed data in WOFF2');\n      }\n\n      this.stream = new r.DecodeStream(new Buffer(decompressed));\n      this._decompressed = true;\n    }\n  };\n\n  WOFF2Font.prototype._decodeTable = function _decodeTable(table) {\n    this._decompress();\n    return _TTFFont.prototype._decodeTable.call(this, table);\n  };\n\n  // Override this method to get a glyph and return our\n  // custom subclass if there is a glyf table.\n\n\n  WOFF2Font.prototype._getBaseGlyph = function _getBaseGlyph(glyph) {\n    var characters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n\n    if (!this._glyphs[glyph]) {\n      if (this.directory.tables.glyf && this.directory.tables.glyf.transformed) {\n        if (!this._transformedGlyphs) {\n          this._transformGlyfTable();\n        }\n        return this._glyphs[glyph] = new WOFF2Glyph(glyph, characters, this);\n      } else {\n        return _TTFFont.prototype._getBaseGlyph.call(this, glyph, characters);\n      }\n    }\n  };\n\n  WOFF2Font.prototype._transformGlyfTable = function _transformGlyfTable() {\n    this._decompress();\n    this.stream.pos = this.directory.tables.glyf.offset;\n    var table = GlyfTable.decode(this.stream);\n    var glyphs = [];\n\n    for (var index = 0; index < table.numGlyphs; index++) {\n      var glyph = {};\n      var nContours = table.nContours.readInt16BE();\n      glyph.numberOfContours = nContours;\n\n      if (nContours > 0) {\n        // simple glyph\n        var nPoints = [];\n        var totalPoints = 0;\n\n        for (var i = 0; i < nContours; i++) {\n          var _r = read255UInt16(table.nPoints);\n          totalPoints += _r;\n          nPoints.push(totalPoints);\n        }\n\n        glyph.points = decodeTriplet(table.flags, table.glyphs, totalPoints);\n        for (var _i = 0; _i < nContours; _i++) {\n          glyph.points[nPoints[_i] - 1].endContour = true;\n        }\n\n        var instructionSize = read255UInt16(table.glyphs);\n      } else if (nContours < 0) {\n        // composite glyph\n        var haveInstructions = TTFGlyph.prototype._decodeComposite.call({ _font: this }, glyph, table.composites);\n        if (haveInstructions) {\n          var instructionSize = read255UInt16(table.glyphs);\n        }\n      }\n\n      glyphs.push(glyph);\n    }\n\n    this._transformedGlyphs = glyphs;\n  };\n\n  return WOFF2Font;\n}(TTFFont);\n\nvar Substream = function () {\n  function Substream(length) {\n    _classCallCheck(this, Substream);\n\n    this.length = length;\n    this._buf = new r.Buffer(length);\n  }\n\n  Substream.prototype.decode = function decode(stream, parent) {\n    return new r.DecodeStream(this._buf.decode(stream, parent));\n  };\n\n  return Substream;\n}();\n\n// This struct represents the entire glyf table\n\n\nvar GlyfTable = new r.Struct({\n  version: r.uint32,\n  numGlyphs: r.uint16,\n  indexFormat: r.uint16,\n  nContourStreamSize: r.uint32,\n  nPointsStreamSize: r.uint32,\n  flagStreamSize: r.uint32,\n  glyphStreamSize: r.uint32,\n  compositeStreamSize: r.uint32,\n  bboxStreamSize: r.uint32,\n  instructionStreamSize: r.uint32,\n  nContours: new Substream('nContourStreamSize'),\n  nPoints: new Substream('nPointsStreamSize'),\n  flags: new Substream('flagStreamSize'),\n  glyphs: new Substream('glyphStreamSize'),\n  composites: new Substream('compositeStreamSize'),\n  bboxes: new Substream('bboxStreamSize'),\n  instructions: new Substream('instructionStreamSize')\n});\n\nvar WORD_CODE = 253;\nvar ONE_MORE_BYTE_CODE2 = 254;\nvar ONE_MORE_BYTE_CODE1 = 255;\nvar LOWEST_U_CODE = 253;\n\nfunction read255UInt16(stream) {\n  var code = stream.readUInt8();\n\n  if (code === WORD_CODE) {\n    return stream.readUInt16BE();\n  }\n\n  if (code === ONE_MORE_BYTE_CODE1) {\n    return stream.readUInt8() + LOWEST_U_CODE;\n  }\n\n  if (code === ONE_MORE_BYTE_CODE2) {\n    return stream.readUInt8() + LOWEST_U_CODE * 2;\n  }\n\n  return code;\n}\n\nfunction withSign(flag, baseval) {\n  return flag & 1 ? baseval : -baseval;\n}\n\nfunction decodeTriplet(flags, glyphs, nPoints) {\n  var y = void 0;\n  var x = y = 0;\n  var res = [];\n\n  for (var i = 0; i < nPoints; i++) {\n    var dx = 0,\n        dy = 0;\n    var flag = flags.readUInt8();\n    var onCurve = !(flag >> 7);\n    flag &= 0x7f;\n\n    if (flag < 10) {\n      dx = 0;\n      dy = withSign(flag, ((flag & 14) << 7) + glyphs.readUInt8());\n    } else if (flag < 20) {\n      dx = withSign(flag, ((flag - 10 & 14) << 7) + glyphs.readUInt8());\n      dy = 0;\n    } else if (flag < 84) {\n      var b0 = flag - 20;\n      var b1 = glyphs.readUInt8();\n      dx = withSign(flag, 1 + (b0 & 0x30) + (b1 >> 4));\n      dy = withSign(flag >> 1, 1 + ((b0 & 0x0c) << 2) + (b1 & 0x0f));\n    } else if (flag < 120) {\n      var b0 = flag - 84;\n      dx = withSign(flag, 1 + (b0 / 12 << 8) + glyphs.readUInt8());\n      dy = withSign(flag >> 1, 1 + (b0 % 12 >> 2 << 8) + glyphs.readUInt8());\n    } else if (flag < 124) {\n      var b1 = glyphs.readUInt8();\n      var b2 = glyphs.readUInt8();\n      dx = withSign(flag, (b1 << 4) + (b2 >> 4));\n      dy = withSign(flag >> 1, ((b2 & 0x0f) << 8) + glyphs.readUInt8());\n    } else {\n      dx = withSign(flag, glyphs.readUInt16BE());\n      dy = withSign(flag >> 1, glyphs.readUInt16BE());\n    }\n\n    x += dx;\n    y += dy;\n    res.push(new Point(onCurve, false, x, y));\n  }\n\n  return res;\n}\n\nvar TTCHeader = new r.VersionedStruct(r.uint32, {\n  0x00010000: {\n    numFonts: r.uint32,\n    offsets: new r.Array(r.uint32, 'numFonts')\n  },\n  0x00020000: {\n    numFonts: r.uint32,\n    offsets: new r.Array(r.uint32, 'numFonts'),\n    dsigTag: r.uint32,\n    dsigLength: r.uint32,\n    dsigOffset: r.uint32\n  }\n});\n\nvar TrueTypeCollection = function () {\n  TrueTypeCollection.probe = function probe(buffer) {\n    return buffer.toString('ascii', 0, 4) === 'ttcf';\n  };\n\n  function TrueTypeCollection(stream) {\n    _classCallCheck(this, TrueTypeCollection);\n\n    this.stream = stream;\n    if (stream.readString(4) !== 'ttcf') {\n      throw new Error('Not a TrueType collection');\n    }\n\n    this.header = TTCHeader.decode(stream);\n  }\n\n  TrueTypeCollection.prototype.getFont = function getFont(name) {\n    for (var _iterator = this.header.offsets, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var offset = _ref;\n\n      var stream = new r.DecodeStream(this.stream.buffer);\n      stream.pos = offset;\n      var font = new TTFFont(stream);\n      if (font.postscriptName === name) {\n        return font;\n      }\n    }\n\n    return null;\n  };\n\n  _createClass(TrueTypeCollection, [{\n    key: 'fonts',\n    get: function get() {\n      var fonts = [];\n      for (var _iterator2 = this.header.offsets, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n        var _ref2;\n\n        if (_isArray2) {\n          if (_i2 >= _iterator2.length) break;\n          _ref2 = _iterator2[_i2++];\n        } else {\n          _i2 = _iterator2.next();\n          if (_i2.done) break;\n          _ref2 = _i2.value;\n        }\n\n        var offset = _ref2;\n\n        var stream = new r.DecodeStream(this.stream.buffer);\n        stream.pos = offset;\n        fonts.push(new TTFFont(stream));\n      }\n\n      return fonts;\n    }\n  }]);\n\n  return TrueTypeCollection;\n}();\n\nvar DFontName = new r.String(r.uint8);\nvar DFontData = new r.Struct({\n  len: r.uint32,\n  buf: new r.Buffer('len')\n});\n\nvar Ref = new r.Struct({\n  id: r.uint16,\n  nameOffset: r.int16,\n  attr: r.uint8,\n  dataOffset: r.uint24,\n  handle: r.uint32\n});\n\nvar Type = new r.Struct({\n  name: new r.String(4),\n  maxTypeIndex: r.uint16,\n  refList: new r.Pointer(r.uint16, new r.Array(Ref, function (t) {\n    return t.maxTypeIndex + 1;\n  }), { type: 'parent' })\n});\n\nvar TypeList = new r.Struct({\n  length: r.uint16,\n  types: new r.Array(Type, function (t) {\n    return t.length + 1;\n  })\n});\n\nvar DFontMap = new r.Struct({\n  reserved: new r.Reserved(r.uint8, 24),\n  typeList: new r.Pointer(r.uint16, TypeList),\n  nameListOffset: new r.Pointer(r.uint16, 'void')\n});\n\nvar DFontHeader = new r.Struct({\n  dataOffset: r.uint32,\n  map: new r.Pointer(r.uint32, DFontMap),\n  dataLength: r.uint32,\n  mapLength: r.uint32\n});\n\nvar DFont = function () {\n  DFont.probe = function probe(buffer) {\n    var stream = new r.DecodeStream(buffer);\n\n    try {\n      var header = DFontHeader.decode(stream);\n    } catch (e) {\n      return false;\n    }\n\n    for (var _iterator = header.map.typeList.types, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _getIterator(_iterator);;) {\n      var _ref;\n\n      if (_isArray) {\n        if (_i >= _iterator.length) break;\n        _ref = _iterator[_i++];\n      } else {\n        _i = _iterator.next();\n        if (_i.done) break;\n        _ref = _i.value;\n      }\n\n      var type = _ref;\n\n      if (type.name === 'sfnt') {\n        return true;\n      }\n    }\n\n    return false;\n  };\n\n  function DFont(stream) {\n    _classCallCheck(this, DFont);\n\n    this.stream = stream;\n    this.header = DFontHeader.decode(this.stream);\n\n    for (var _iterator2 = this.header.map.typeList.types, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _getIterator(_iterator2);;) {\n      var _ref2;\n\n      if (_isArray2) {\n        if (_i2 >= _iterator2.length) break;\n        _ref2 = _iterator2[_i2++];\n      } else {\n        _i2 = _iterator2.next();\n        if (_i2.done) break;\n        _ref2 = _i2.value;\n      }\n\n      var type = _ref2;\n\n      for (var _iterator3 = type.refList, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _getIterator(_iterator3);;) {\n        var _ref3;\n\n        if (_isArray3) {\n          if (_i3 >= _iterator3.length) break;\n          _ref3 = _iterator3[_i3++];\n        } else {\n          _i3 = _iterator3.next();\n          if (_i3.done) break;\n          _ref3 = _i3.value;\n        }\n\n        var ref = _ref3;\n\n        if (ref.nameOffset >= 0) {\n          this.stream.pos = ref.nameOffset + this.header.map.nameListOffset;\n          ref.name = DFontName.decode(this.stream);\n        } else {\n          ref.name = null;\n        }\n      }\n\n      if (type.name === 'sfnt') {\n        this.sfnt = type;\n      }\n    }\n  }\n\n  DFont.prototype.getFont = function getFont(name) {\n    if (!this.sfnt) {\n      return null;\n    }\n\n    for (var _iterator4 = this.sfnt.refList, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _getIterator(_iterator4);;) {\n      var _ref4;\n\n      if (_isArray4) {\n        if (_i4 >= _iterator4.length) break;\n        _ref4 = _iterator4[_i4++];\n      } else {\n        _i4 = _iterator4.next();\n        if (_i4.done) break;\n        _ref4 = _i4.value;\n      }\n\n      var ref = _ref4;\n\n      var pos = this.header.dataOffset + ref.dataOffset + 4;\n      var stream = new r.DecodeStream(this.stream.buffer.slice(pos));\n      var font = new TTFFont(stream);\n      if (font.postscriptName === name) {\n        return font;\n      }\n    }\n\n    return null;\n  };\n\n  _createClass(DFont, [{\n    key: 'fonts',\n    get: function get() {\n      var fonts = [];\n      for (var _iterator5 = this.sfnt.refList, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _getIterator(_iterator5);;) {\n        var _ref5;\n\n        if (_isArray5) {\n          if (_i5 >= _iterator5.length) break;\n          _ref5 = _iterator5[_i5++];\n        } else {\n          _i5 = _iterator5.next();\n          if (_i5.done) break;\n          _ref5 = _i5.value;\n        }\n\n        var ref = _ref5;\n\n        var pos = this.header.dataOffset + ref.dataOffset + 4;\n        var stream = new r.DecodeStream(this.stream.buffer.slice(pos));\n        fonts.push(new TTFFont(stream));\n      }\n\n      return fonts;\n    }\n  }]);\n\n  return DFont;\n}();\n\n// Register font formats\nfontkit.registerFormat(TTFFont);\nfontkit.registerFormat(WOFFFont);\nfontkit.registerFormat(WOFF2Font);\nfontkit.registerFormat(TrueTypeCollection);\nfontkit.registerFormat(DFont);\n\nmodule.exports = fontkit;\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer, __webpack_require__(11)))\n\n/***/ }),\n/* 168 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var key, val, _ref, _ref1;\n\n  exports.EncodeStream = __webpack_require__(169);\n\n  exports.DecodeStream = __webpack_require__(51);\n\n  exports.Array = __webpack_require__(93);\n\n  exports.LazyArray = __webpack_require__(187);\n\n  exports.Bitfield = __webpack_require__(188);\n\n  exports.Boolean = __webpack_require__(189);\n\n  exports.Buffer = __webpack_require__(190);\n\n  exports.Enum = __webpack_require__(191);\n\n  exports.Optional = __webpack_require__(192);\n\n  exports.Reserved = __webpack_require__(193);\n\n  exports.String = __webpack_require__(194);\n\n  exports.Struct = __webpack_require__(94);\n\n  exports.VersionedStruct = __webpack_require__(195);\n\n  _ref = __webpack_require__(22);\n  for (key in _ref) {\n    val = _ref[key];\n    exports[key] = val;\n  }\n\n  _ref1 = __webpack_require__(196);\n  for (key in _ref1) {\n    val = _ref1[key];\n    exports[key] = val;\n  }\n\n}).call(this);\n\n\n/***/ }),\n/* 169 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.7.1\n(function() {\n  var DecodeStream, EncodeStream, iconv, stream,\n    __hasProp = {}.hasOwnProperty,\n    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n  stream = __webpack_require__(15);\n\n  DecodeStream = __webpack_require__(51);\n\n  try {\n    iconv = __webpack_require__(52);\n  } catch (_error) {}\n\n  EncodeStream = (function(_super) {\n    var key;\n\n    __extends(EncodeStream, _super);\n\n    function EncodeStream(bufferSize) {\n      if (bufferSize == null) {\n        bufferSize = 65536;\n      }\n      EncodeStream.__super__.constructor.apply(this, arguments);\n      this.buffer = new Buffer(bufferSize);\n      this.bufferOffset = 0;\n      this.pos = 0;\n    }\n\n    for (key in Buffer.prototype) {\n      if (key.slice(0, 5) === 'write') {\n        (function(key) {\n          var bytes;\n          bytes = +DecodeStream.TYPES[key.replace(/write|[BL]E/g, '')];\n          return EncodeStream.prototype[key] = function(value) {\n            this.ensure(bytes);\n            this.buffer[key](value, this.bufferOffset);\n            this.bufferOffset += bytes;\n            return this.pos += bytes;\n          };\n        })(key);\n      }\n    }\n\n    EncodeStream.prototype._read = function() {};\n\n    EncodeStream.prototype.ensure = function(bytes) {\n      if (this.bufferOffset + bytes > this.buffer.length) {\n        return this.flush();\n      }\n    };\n\n    EncodeStream.prototype.flush = function() {\n      if (this.bufferOffset > 0) {\n        this.push(new Buffer(this.buffer.slice(0, this.bufferOffset)));\n        return this.bufferOffset = 0;\n      }\n    };\n\n    EncodeStream.prototype.writeBuffer = function(buffer) {\n      this.flush();\n      this.push(buffer);\n      return this.pos += buffer.length;\n    };\n\n    EncodeStream.prototype.writeString = function(string, encoding) {\n      var buf, byte, i, _i, _ref;\n      if (encoding == null) {\n        encoding = 'ascii';\n      }\n      switch (encoding) {\n        case 'utf16le':\n        case 'ucs2':\n        case 'utf8':\n        case 'ascii':\n          return this.writeBuffer(new Buffer(string, encoding));\n        case 'utf16be':\n          buf = new Buffer(string, 'utf16le');\n          for (i = _i = 0, _ref = buf.length - 1; _i < _ref; i = _i += 2) {\n            byte = buf[i];\n            buf[i] = buf[i + 1];\n            buf[i + 1] = byte;\n          }\n          return this.writeBuffer(buf);\n        default:\n          if (iconv) {\n            return this.writeBuffer(iconv.encode(string, encoding));\n          } else {\n            throw new Error('Install iconv-lite to enable additional string encodings.');\n          }\n      }\n    };\n\n    EncodeStream.prototype.writeUInt24BE = function(val) {\n      this.ensure(3);\n      this.buffer[this.bufferOffset++] = val >>> 16 & 0xff;\n      this.buffer[this.bufferOffset++] = val >>> 8 & 0xff;\n      this.buffer[this.bufferOffset++] = val & 0xff;\n      return this.pos += 3;\n    };\n\n    EncodeStream.prototype.writeUInt24LE = function(val) {\n      this.ensure(3);\n      this.buffer[this.bufferOffset++] = val & 0xff;\n      this.buffer[this.bufferOffset++] = val >>> 8 & 0xff;\n      this.buffer[this.bufferOffset++] = val >>> 16 & 0xff;\n      return this.pos += 3;\n    };\n\n    EncodeStream.prototype.writeInt24BE = function(val) {\n      if (val >= 0) {\n        return this.writeUInt24BE(val);\n      } else {\n        return this.writeUInt24BE(val + 0xffffff + 1);\n      }\n    };\n\n    EncodeStream.prototype.writeInt24LE = function(val) {\n      if (val >= 0) {\n        return this.writeUInt24LE(val);\n      } else {\n        return this.writeUInt24LE(val + 0xffffff + 1);\n      }\n    };\n\n    EncodeStream.prototype.fill = function(val, length) {\n      var buf;\n      if (length < this.buffer.length) {\n        this.ensure(length);\n        this.buffer.fill(val, this.bufferOffset, this.bufferOffset + length);\n        this.bufferOffset += length;\n        return this.pos += length;\n      } else {\n        buf = new Buffer(length);\n        buf.fill(val);\n        return this.writeBuffer(buf);\n      }\n    };\n\n    EncodeStream.prototype.end = function() {\n      this.flush();\n      return this.push(null);\n    };\n\n    return EncodeStream;\n\n  })(stream.Readable);\n\n  module.exports = EncodeStream;\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 170 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar BOMChar = '\\uFEFF';\n\nexports.PrependBOM = PrependBOMWrapper\nfunction PrependBOMWrapper(encoder, options) {\n    this.encoder = encoder;\n    this.addBOM = true;\n}\n\nPrependBOMWrapper.prototype.write = function(str) {\n    if (this.addBOM) {\n        str = BOMChar + str;\n        this.addBOM = false;\n    }\n\n    return this.encoder.write(str);\n}\n\nPrependBOMWrapper.prototype.end = function() {\n    return this.encoder.end();\n}\n\n\n//------------------------------------------------------------------------------\n\nexports.StripBOM = StripBOMWrapper;\nfunction StripBOMWrapper(decoder, options) {\n    this.decoder = decoder;\n    this.pass = false;\n    this.options = options || {};\n}\n\nStripBOMWrapper.prototype.write = function(buf) {\n    var res = this.decoder.write(buf);\n    if (this.pass || !res)\n        return res;\n\n    if (res[0] === BOMChar) {\n        res = res.slice(1);\n        if (typeof this.options.stripBOM === 'function')\n            this.options.stripBOM();\n    }\n\n    this.pass = true;\n    return res;\n}\n\nStripBOMWrapper.prototype.end = function() {\n    return this.decoder.end();\n}\n\n\n\n/***/ }),\n/* 171 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// Update this array if you add/rename/remove files in this directory.\n// We support Browserify by skipping automatic module discovery and requiring modules directly.\nvar modules = [\n    __webpack_require__(172),\n    __webpack_require__(173),\n    __webpack_require__(174),\n    __webpack_require__(175),\n    __webpack_require__(176),\n    __webpack_require__(177),\n    __webpack_require__(178),\n    __webpack_require__(179),\n];\n\n// Put all encoding/alias/codec definitions to single object and export it. \nfor (var i = 0; i < modules.length; i++) {\n    var module = modules[i];\n    for (var enc in module)\n        if (Object.prototype.hasOwnProperty.call(module, enc))\n            exports[enc] = module[enc];\n}\n\n\n/***/ }),\n/* 172 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar Buffer = __webpack_require__(1).Buffer;\n\n// Export Node.js internal encodings.\n\nmodule.exports = {\n    // Encodings\n    utf8:   { type: \"_internal\", bomAware: true},\n    cesu8:  { type: \"_internal\", bomAware: true},\n    unicode11utf8: \"utf8\",\n\n    ucs2:   { type: \"_internal\", bomAware: true},\n    utf16le: \"ucs2\",\n\n    binary: { type: \"_internal\" },\n    base64: { type: \"_internal\" },\n    hex:    { type: \"_internal\" },\n\n    // Codec.\n    _internal: InternalCodec,\n};\n\n//------------------------------------------------------------------------------\n\nfunction InternalCodec(codecOptions, iconv) {\n    this.enc = codecOptions.encodingName;\n    this.bomAware = codecOptions.bomAware;\n\n    if (this.enc === \"base64\")\n        this.encoder = InternalEncoderBase64;\n    else if (this.enc === \"cesu8\") {\n        this.enc = \"utf8\"; // Use utf8 for decoding.\n        this.encoder = InternalEncoderCesu8;\n\n        // Add decoder for versions of Node not supporting CESU-8\n        if (new Buffer('eda0bdedb2a9', 'hex').toString() !== '💩') {\n            this.decoder = InternalDecoderCesu8;\n            this.defaultCharUnicode = iconv.defaultCharUnicode;\n        }\n    }\n}\n\nInternalCodec.prototype.encoder = InternalEncoder;\nInternalCodec.prototype.decoder = InternalDecoder;\n\n//------------------------------------------------------------------------------\n\n// We use node.js internal decoder. Its signature is the same as ours.\nvar StringDecoder = __webpack_require__(47).StringDecoder;\n\nif (!StringDecoder.prototype.end) // Node v0.8 doesn't have this method.\n    StringDecoder.prototype.end = function() {};\n\n\nfunction InternalDecoder(options, codec) {\n    StringDecoder.call(this, codec.enc);\n}\n\nInternalDecoder.prototype = StringDecoder.prototype;\n\n\n//------------------------------------------------------------------------------\n// Encoder is mostly trivial\n\nfunction InternalEncoder(options, codec) {\n    this.enc = codec.enc;\n}\n\nInternalEncoder.prototype.write = function(str) {\n    return new Buffer(str, this.enc);\n}\n\nInternalEncoder.prototype.end = function() {\n}\n\n\n//------------------------------------------------------------------------------\n// Except base64 encoder, which must keep its state.\n\nfunction InternalEncoderBase64(options, codec) {\n    this.prevStr = '';\n}\n\nInternalEncoderBase64.prototype.write = function(str) {\n    str = this.prevStr + str;\n    var completeQuads = str.length - (str.length % 4);\n    this.prevStr = str.slice(completeQuads);\n    str = str.slice(0, completeQuads);\n\n    return new Buffer(str, \"base64\");\n}\n\nInternalEncoderBase64.prototype.end = function() {\n    return new Buffer(this.prevStr, \"base64\");\n}\n\n\n//------------------------------------------------------------------------------\n// CESU-8 encoder is also special.\n\nfunction InternalEncoderCesu8(options, codec) {\n}\n\nInternalEncoderCesu8.prototype.write = function(str) {\n    var buf = new Buffer(str.length * 3), bufIdx = 0;\n    for (var i = 0; i < str.length; i++) {\n        var charCode = str.charCodeAt(i);\n        // Naive implementation, but it works because CESU-8 is especially easy\n        // to convert from UTF-16 (which all JS strings are encoded in).\n        if (charCode < 0x80)\n            buf[bufIdx++] = charCode;\n        else if (charCode < 0x800) {\n            buf[bufIdx++] = 0xC0 + (charCode >>> 6);\n            buf[bufIdx++] = 0x80 + (charCode & 0x3f);\n        }\n        else { // charCode will always be < 0x10000 in javascript.\n            buf[bufIdx++] = 0xE0 + (charCode >>> 12);\n            buf[bufIdx++] = 0x80 + ((charCode >>> 6) & 0x3f);\n            buf[bufIdx++] = 0x80 + (charCode & 0x3f);\n        }\n    }\n    return buf.slice(0, bufIdx);\n}\n\nInternalEncoderCesu8.prototype.end = function() {\n}\n\n//------------------------------------------------------------------------------\n// CESU-8 decoder is not implemented in Node v4.0+\n\nfunction InternalDecoderCesu8(options, codec) {\n    this.acc = 0;\n    this.contBytes = 0;\n    this.accBytes = 0;\n    this.defaultCharUnicode = codec.defaultCharUnicode;\n}\n\nInternalDecoderCesu8.prototype.write = function(buf) {\n    var acc = this.acc, contBytes = this.contBytes, accBytes = this.accBytes, \n        res = '';\n    for (var i = 0; i < buf.length; i++) {\n        var curByte = buf[i];\n        if ((curByte & 0xC0) !== 0x80) { // Leading byte\n            if (contBytes > 0) { // Previous code is invalid\n                res += this.defaultCharUnicode;\n                contBytes = 0;\n            }\n\n            if (curByte < 0x80) { // Single-byte code\n                res += String.fromCharCode(curByte);\n            } else if (curByte < 0xE0) { // Two-byte code\n                acc = curByte & 0x1F;\n                contBytes = 1; accBytes = 1;\n            } else if (curByte < 0xF0) { // Three-byte code\n                acc = curByte & 0x0F;\n                contBytes = 2; accBytes = 1;\n            } else { // Four or more are not supported for CESU-8.\n                res += this.defaultCharUnicode;\n            }\n        } else { // Continuation byte\n            if (contBytes > 0) { // We're waiting for it.\n                acc = (acc << 6) | (curByte & 0x3f);\n                contBytes--; accBytes++;\n                if (contBytes === 0) {\n                    // Check for overlong encoding, but support Modified UTF-8 (encoding NULL as C0 80)\n                    if (accBytes === 2 && acc < 0x80 && acc > 0)\n                        res += this.defaultCharUnicode;\n                    else if (accBytes === 3 && acc < 0x800)\n                        res += this.defaultCharUnicode;\n                    else\n                        // Actually add character.\n                        res += String.fromCharCode(acc);\n                }\n            } else { // Unexpected continuation byte\n                res += this.defaultCharUnicode;\n            }\n        }\n    }\n    this.acc = acc; this.contBytes = contBytes; this.accBytes = accBytes;\n    return res;\n}\n\nInternalDecoderCesu8.prototype.end = function() {\n    var res = 0;\n    if (this.contBytes > 0)\n        res += this.defaultCharUnicode;\n    return res;\n}\n\n\n/***/ }),\n/* 173 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar Buffer = __webpack_require__(1).Buffer;\n\n// Note: UTF16-LE (or UCS2) codec is Node.js native. See encodings/internal.js\n\n// == UTF16-BE codec. ==========================================================\n\nexports.utf16be = Utf16BECodec;\nfunction Utf16BECodec() {\n}\n\nUtf16BECodec.prototype.encoder = Utf16BEEncoder;\nUtf16BECodec.prototype.decoder = Utf16BEDecoder;\nUtf16BECodec.prototype.bomAware = true;\n\n\n// -- Encoding\n\nfunction Utf16BEEncoder() {\n}\n\nUtf16BEEncoder.prototype.write = function(str) {\n    var buf = new Buffer(str, 'ucs2');\n    for (var i = 0; i < buf.length; i += 2) {\n        var tmp = buf[i]; buf[i] = buf[i+1]; buf[i+1] = tmp;\n    }\n    return buf;\n}\n\nUtf16BEEncoder.prototype.end = function() {\n}\n\n\n// -- Decoding\n\nfunction Utf16BEDecoder() {\n    this.overflowByte = -1;\n}\n\nUtf16BEDecoder.prototype.write = function(buf) {\n    if (buf.length == 0)\n        return '';\n\n    var buf2 = new Buffer(buf.length + 1),\n        i = 0, j = 0;\n\n    if (this.overflowByte !== -1) {\n        buf2[0] = buf[0];\n        buf2[1] = this.overflowByte;\n        i = 1; j = 2;\n    }\n\n    for (; i < buf.length-1; i += 2, j+= 2) {\n        buf2[j] = buf[i+1];\n        buf2[j+1] = buf[i];\n    }\n\n    this.overflowByte = (i == buf.length-1) ? buf[buf.length-1] : -1;\n\n    return buf2.slice(0, j).toString('ucs2');\n}\n\nUtf16BEDecoder.prototype.end = function() {\n}\n\n\n// == UTF-16 codec =============================================================\n// Decoder chooses automatically from UTF-16LE and UTF-16BE using BOM and space-based heuristic.\n// Defaults to UTF-16LE, as it's prevalent and default in Node.\n// http://en.wikipedia.org/wiki/UTF-16 and http://encoding.spec.whatwg.org/#utf-16le\n// Decoder default can be changed: iconv.decode(buf, 'utf16', {defaultEncoding: 'utf-16be'});\n\n// Encoder uses UTF-16LE and prepends BOM (which can be overridden with addBOM: false).\n\nexports.utf16 = Utf16Codec;\nfunction Utf16Codec(codecOptions, iconv) {\n    this.iconv = iconv;\n}\n\nUtf16Codec.prototype.encoder = Utf16Encoder;\nUtf16Codec.prototype.decoder = Utf16Decoder;\n\n\n// -- Encoding (pass-through)\n\nfunction Utf16Encoder(options, codec) {\n    options = options || {};\n    if (options.addBOM === undefined)\n        options.addBOM = true;\n    this.encoder = codec.iconv.getEncoder('utf-16le', options);\n}\n\nUtf16Encoder.prototype.write = function(str) {\n    return this.encoder.write(str);\n}\n\nUtf16Encoder.prototype.end = function() {\n    return this.encoder.end();\n}\n\n\n// -- Decoding\n\nfunction Utf16Decoder(options, codec) {\n    this.decoder = null;\n    this.initialBytes = [];\n    this.initialBytesLen = 0;\n\n    this.options = options || {};\n    this.iconv = codec.iconv;\n}\n\nUtf16Decoder.prototype.write = function(buf) {\n    if (!this.decoder) {\n        // Codec is not chosen yet. Accumulate initial bytes.\n        this.initialBytes.push(buf);\n        this.initialBytesLen += buf.length;\n        \n        if (this.initialBytesLen < 16) // We need more bytes to use space heuristic (see below)\n            return '';\n\n        // We have enough bytes -> detect endianness.\n        var buf = Buffer.concat(this.initialBytes),\n            encoding = detectEncoding(buf, this.options.defaultEncoding);\n        this.decoder = this.iconv.getDecoder(encoding, this.options);\n        this.initialBytes.length = this.initialBytesLen = 0;\n    }\n\n    return this.decoder.write(buf);\n}\n\nUtf16Decoder.prototype.end = function() {\n    if (!this.decoder) {\n        var buf = Buffer.concat(this.initialBytes),\n            encoding = detectEncoding(buf, this.options.defaultEncoding);\n        this.decoder = this.iconv.getDecoder(encoding, this.options);\n\n        var res = this.decoder.write(buf),\n            trail = this.decoder.end();\n\n        return trail ? (res + trail) : res;\n    }\n    return this.decoder.end();\n}\n\nfunction detectEncoding(buf, defaultEncoding) {\n    var enc = defaultEncoding || 'utf-16le';\n\n    if (buf.length >= 2) {\n        // Check BOM.\n        if (buf[0] == 0xFE && buf[1] == 0xFF) // UTF-16BE BOM\n            enc = 'utf-16be';\n        else if (buf[0] == 0xFF && buf[1] == 0xFE) // UTF-16LE BOM\n            enc = 'utf-16le';\n        else {\n            // No BOM found. Try to deduce encoding from initial content.\n            // Most of the time, the content has ASCII chars (U+00**), but the opposite (U+**00) is uncommon.\n            // So, we count ASCII as if it was LE or BE, and decide from that.\n            var asciiCharsLE = 0, asciiCharsBE = 0, // Counts of chars in both positions\n                _len = Math.min(buf.length - (buf.length % 2), 64); // Len is always even.\n\n            for (var i = 0; i < _len; i += 2) {\n                if (buf[i] === 0 && buf[i+1] !== 0) asciiCharsBE++;\n                if (buf[i] !== 0 && buf[i+1] === 0) asciiCharsLE++;\n            }\n\n            if (asciiCharsBE > asciiCharsLE)\n                enc = 'utf-16be';\n            else if (asciiCharsBE < asciiCharsLE)\n                enc = 'utf-16le';\n        }\n    }\n\n    return enc;\n}\n\n\n\n\n/***/ }),\n/* 174 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar Buffer = __webpack_require__(1).Buffer;\n\n// UTF-7 codec, according to https://tools.ietf.org/html/rfc2152\n// See also below a UTF-7-IMAP codec, according to http://tools.ietf.org/html/rfc3501#section-5.1.3\n\nexports.utf7 = Utf7Codec;\nexports.unicode11utf7 = 'utf7'; // Alias UNICODE-1-1-UTF-7\nfunction Utf7Codec(codecOptions, iconv) {\n    this.iconv = iconv;\n};\n\nUtf7Codec.prototype.encoder = Utf7Encoder;\nUtf7Codec.prototype.decoder = Utf7Decoder;\nUtf7Codec.prototype.bomAware = true;\n\n\n// -- Encoding\n\nvar nonDirectChars = /[^A-Za-z0-9'\\(\\),-\\.\\/:\\? \\n\\r\\t]+/g;\n\nfunction Utf7Encoder(options, codec) {\n    this.iconv = codec.iconv;\n}\n\nUtf7Encoder.prototype.write = function(str) {\n    // Naive implementation.\n    // Non-direct chars are encoded as \"+<base64>-\"; single \"+\" char is encoded as \"+-\".\n    return new Buffer(str.replace(nonDirectChars, function(chunk) {\n        return \"+\" + (chunk === '+' ? '' : \n            this.iconv.encode(chunk, 'utf16-be').toString('base64').replace(/=+$/, '')) \n            + \"-\";\n    }.bind(this)));\n}\n\nUtf7Encoder.prototype.end = function() {\n}\n\n\n// -- Decoding\n\nfunction Utf7Decoder(options, codec) {\n    this.iconv = codec.iconv;\n    this.inBase64 = false;\n    this.base64Accum = '';\n}\n\nvar base64Regex = /[A-Za-z0-9\\/+]/;\nvar base64Chars = [];\nfor (var i = 0; i < 256; i++)\n    base64Chars[i] = base64Regex.test(String.fromCharCode(i));\n\nvar plusChar = '+'.charCodeAt(0), \n    minusChar = '-'.charCodeAt(0),\n    andChar = '&'.charCodeAt(0);\n\nUtf7Decoder.prototype.write = function(buf) {\n    var res = \"\", lastI = 0,\n        inBase64 = this.inBase64,\n        base64Accum = this.base64Accum;\n\n    // The decoder is more involved as we must handle chunks in stream.\n\n    for (var i = 0; i < buf.length; i++) {\n        if (!inBase64) { // We're in direct mode.\n            // Write direct chars until '+'\n            if (buf[i] == plusChar) {\n                res += this.iconv.decode(buf.slice(lastI, i), \"ascii\"); // Write direct chars.\n                lastI = i+1;\n                inBase64 = true;\n            }\n        } else { // We decode base64.\n            if (!base64Chars[buf[i]]) { // Base64 ended.\n                if (i == lastI && buf[i] == minusChar) {// \"+-\" -> \"+\"\n                    res += \"+\";\n                } else {\n                    var b64str = base64Accum + buf.slice(lastI, i).toString();\n                    res += this.iconv.decode(new Buffer(b64str, 'base64'), \"utf16-be\");\n                }\n\n                if (buf[i] != minusChar) // Minus is absorbed after base64.\n                    i--;\n\n                lastI = i+1;\n                inBase64 = false;\n                base64Accum = '';\n            }\n        }\n    }\n\n    if (!inBase64) {\n        res += this.iconv.decode(buf.slice(lastI), \"ascii\"); // Write direct chars.\n    } else {\n        var b64str = base64Accum + buf.slice(lastI).toString();\n\n        var canBeDecoded = b64str.length - (b64str.length % 8); // Minimal chunk: 2 quads -> 2x3 bytes -> 3 chars.\n        base64Accum = b64str.slice(canBeDecoded); // The rest will be decoded in future.\n        b64str = b64str.slice(0, canBeDecoded);\n\n        res += this.iconv.decode(new Buffer(b64str, 'base64'), \"utf16-be\");\n    }\n\n    this.inBase64 = inBase64;\n    this.base64Accum = base64Accum;\n\n    return res;\n}\n\nUtf7Decoder.prototype.end = function() {\n    var res = \"\";\n    if (this.inBase64 && this.base64Accum.length > 0)\n        res = this.iconv.decode(new Buffer(this.base64Accum, 'base64'), \"utf16-be\");\n\n    this.inBase64 = false;\n    this.base64Accum = '';\n    return res;\n}\n\n\n// UTF-7-IMAP codec.\n// RFC3501 Sec. 5.1.3 Modified UTF-7 (http://tools.ietf.org/html/rfc3501#section-5.1.3)\n// Differences:\n//  * Base64 part is started by \"&\" instead of \"+\"\n//  * Direct characters are 0x20-0x7E, except \"&\" (0x26)\n//  * In Base64, \",\" is used instead of \"/\"\n//  * Base64 must not be used to represent direct characters.\n//  * No implicit shift back from Base64 (should always end with '-')\n//  * String must end in non-shifted position.\n//  * \"-&\" while in base64 is not allowed.\n\n\nexports.utf7imap = Utf7IMAPCodec;\nfunction Utf7IMAPCodec(codecOptions, iconv) {\n    this.iconv = iconv;\n};\n\nUtf7IMAPCodec.prototype.encoder = Utf7IMAPEncoder;\nUtf7IMAPCodec.prototype.decoder = Utf7IMAPDecoder;\nUtf7IMAPCodec.prototype.bomAware = true;\n\n\n// -- Encoding\n\nfunction Utf7IMAPEncoder(options, codec) {\n    this.iconv = codec.iconv;\n    this.inBase64 = false;\n    this.base64Accum = new Buffer(6);\n    this.base64AccumIdx = 0;\n}\n\nUtf7IMAPEncoder.prototype.write = function(str) {\n    var inBase64 = this.inBase64,\n        base64Accum = this.base64Accum,\n        base64AccumIdx = this.base64AccumIdx,\n        buf = new Buffer(str.length*5 + 10), bufIdx = 0;\n\n    for (var i = 0; i < str.length; i++) {\n        var uChar = str.charCodeAt(i);\n        if (0x20 <= uChar && uChar <= 0x7E) { // Direct character or '&'.\n            if (inBase64) {\n                if (base64AccumIdx > 0) {\n                    bufIdx += buf.write(base64Accum.slice(0, base64AccumIdx).toString('base64').replace(/\\//g, ',').replace(/=+$/, ''), bufIdx);\n                    base64AccumIdx = 0;\n                }\n\n                buf[bufIdx++] = minusChar; // Write '-', then go to direct mode.\n                inBase64 = false;\n            }\n\n            if (!inBase64) {\n                buf[bufIdx++] = uChar; // Write direct character\n\n                if (uChar === andChar)  // Ampersand -> '&-'\n                    buf[bufIdx++] = minusChar;\n            }\n\n        } else { // Non-direct character\n            if (!inBase64) {\n                buf[bufIdx++] = andChar; // Write '&', then go to base64 mode.\n                inBase64 = true;\n            }\n            if (inBase64) {\n                base64Accum[base64AccumIdx++] = uChar >> 8;\n                base64Accum[base64AccumIdx++] = uChar & 0xFF;\n\n                if (base64AccumIdx == base64Accum.length) {\n                    bufIdx += buf.write(base64Accum.toString('base64').replace(/\\//g, ','), bufIdx);\n                    base64AccumIdx = 0;\n                }\n            }\n        }\n    }\n\n    this.inBase64 = inBase64;\n    this.base64AccumIdx = base64AccumIdx;\n\n    return buf.slice(0, bufIdx);\n}\n\nUtf7IMAPEncoder.prototype.end = function() {\n    var buf = new Buffer(10), bufIdx = 0;\n    if (this.inBase64) {\n        if (this.base64AccumIdx > 0) {\n            bufIdx += buf.write(this.base64Accum.slice(0, this.base64AccumIdx).toString('base64').replace(/\\//g, ',').replace(/=+$/, ''), bufIdx);\n            this.base64AccumIdx = 0;\n        }\n\n        buf[bufIdx++] = minusChar; // Write '-', then go to direct mode.\n        this.inBase64 = false;\n    }\n\n    return buf.slice(0, bufIdx);\n}\n\n\n// -- Decoding\n\nfunction Utf7IMAPDecoder(options, codec) {\n    this.iconv = codec.iconv;\n    this.inBase64 = false;\n    this.base64Accum = '';\n}\n\nvar base64IMAPChars = base64Chars.slice();\nbase64IMAPChars[','.charCodeAt(0)] = true;\n\nUtf7IMAPDecoder.prototype.write = function(buf) {\n    var res = \"\", lastI = 0,\n        inBase64 = this.inBase64,\n        base64Accum = this.base64Accum;\n\n    // The decoder is more involved as we must handle chunks in stream.\n    // It is forgiving, closer to standard UTF-7 (for example, '-' is optional at the end).\n\n    for (var i = 0; i < buf.length; i++) {\n        if (!inBase64) { // We're in direct mode.\n            // Write direct chars until '&'\n            if (buf[i] == andChar) {\n                res += this.iconv.decode(buf.slice(lastI, i), \"ascii\"); // Write direct chars.\n                lastI = i+1;\n                inBase64 = true;\n            }\n        } else { // We decode base64.\n            if (!base64IMAPChars[buf[i]]) { // Base64 ended.\n                if (i == lastI && buf[i] == minusChar) { // \"&-\" -> \"&\"\n                    res += \"&\";\n                } else {\n                    var b64str = base64Accum + buf.slice(lastI, i).toString().replace(/,/g, '/');\n                    res += this.iconv.decode(new Buffer(b64str, 'base64'), \"utf16-be\");\n                }\n\n                if (buf[i] != minusChar) // Minus may be absorbed after base64.\n                    i--;\n\n                lastI = i+1;\n                inBase64 = false;\n                base64Accum = '';\n            }\n        }\n    }\n\n    if (!inBase64) {\n        res += this.iconv.decode(buf.slice(lastI), \"ascii\"); // Write direct chars.\n    } else {\n        var b64str = base64Accum + buf.slice(lastI).toString().replace(/,/g, '/');\n\n        var canBeDecoded = b64str.length - (b64str.length % 8); // Minimal chunk: 2 quads -> 2x3 bytes -> 3 chars.\n        base64Accum = b64str.slice(canBeDecoded); // The rest will be decoded in future.\n        b64str = b64str.slice(0, canBeDecoded);\n\n        res += this.iconv.decode(new Buffer(b64str, 'base64'), \"utf16-be\");\n    }\n\n    this.inBase64 = inBase64;\n    this.base64Accum = base64Accum;\n\n    return res;\n}\n\nUtf7IMAPDecoder.prototype.end = function() {\n    var res = \"\";\n    if (this.inBase64 && this.base64Accum.length > 0)\n        res = this.iconv.decode(new Buffer(this.base64Accum, 'base64'), \"utf16-be\");\n\n    this.inBase64 = false;\n    this.base64Accum = '';\n    return res;\n}\n\n\n\n\n/***/ }),\n/* 175 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar Buffer = __webpack_require__(1).Buffer;\n\n// Single-byte codec. Needs a 'chars' string parameter that contains 256 or 128 chars that\n// correspond to encoded bytes (if 128 - then lower half is ASCII). \n\nexports._sbcs = SBCSCodec;\nfunction SBCSCodec(codecOptions, iconv) {\n    if (!codecOptions)\n        throw new Error(\"SBCS codec is called without the data.\")\n    \n    // Prepare char buffer for decoding.\n    if (!codecOptions.chars || (codecOptions.chars.length !== 128 && codecOptions.chars.length !== 256))\n        throw new Error(\"Encoding '\"+codecOptions.type+\"' has incorrect 'chars' (must be of len 128 or 256)\");\n    \n    if (codecOptions.chars.length === 128) {\n        var asciiString = \"\";\n        for (var i = 0; i < 128; i++)\n            asciiString += String.fromCharCode(i);\n        codecOptions.chars = asciiString + codecOptions.chars;\n    }\n\n    this.decodeBuf = new Buffer(codecOptions.chars, 'ucs2');\n    \n    // Encoding buffer.\n    var encodeBuf = new Buffer(65536);\n    encodeBuf.fill(iconv.defaultCharSingleByte.charCodeAt(0));\n\n    for (var i = 0; i < codecOptions.chars.length; i++)\n        encodeBuf[codecOptions.chars.charCodeAt(i)] = i;\n\n    this.encodeBuf = encodeBuf;\n}\n\nSBCSCodec.prototype.encoder = SBCSEncoder;\nSBCSCodec.prototype.decoder = SBCSDecoder;\n\n\nfunction SBCSEncoder(options, codec) {\n    this.encodeBuf = codec.encodeBuf;\n}\n\nSBCSEncoder.prototype.write = function(str) {\n    var buf = new Buffer(str.length);\n    for (var i = 0; i < str.length; i++)\n        buf[i] = this.encodeBuf[str.charCodeAt(i)];\n    \n    return buf;\n}\n\nSBCSEncoder.prototype.end = function() {\n}\n\n\nfunction SBCSDecoder(options, codec) {\n    this.decodeBuf = codec.decodeBuf;\n}\n\nSBCSDecoder.prototype.write = function(buf) {\n    // Strings are immutable in JS -> we use ucs2 buffer to speed up computations.\n    var decodeBuf = this.decodeBuf;\n    var newBuf = new Buffer(buf.length*2);\n    var idx1 = 0, idx2 = 0;\n    for (var i = 0; i < buf.length; i++) {\n        idx1 = buf[i]*2; idx2 = i*2;\n        newBuf[idx2] = decodeBuf[idx1];\n        newBuf[idx2+1] = decodeBuf[idx1+1];\n    }\n    return newBuf.toString('ucs2');\n}\n\nSBCSDecoder.prototype.end = function() {\n}\n\n\n/***/ }),\n/* 176 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// Manually added data to be used by sbcs codec in addition to generated one.\n\nmodule.exports = {\n    // Not supported by iconv, not sure why.\n    \"10029\": \"maccenteuro\",\n    \"maccenteuro\": {\n        \"type\": \"_sbcs\",\n        \"chars\": \"ÄĀāÉĄÖÜáąČäčĆćéŹźĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅņŃ¬√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ\"\n    },\n\n    \"808\": \"cp808\",\n    \"ibm808\": \"cp808\",\n    \"cp808\": {\n        \"type\": \"_sbcs\",\n        \"chars\": \"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёЄєЇїЎў°∙·√№€■ \"\n    },\n\n    // Aliases of generated encodings.\n    \"ascii8bit\": \"ascii\",\n    \"usascii\": \"ascii\",\n    \"ansix34\": \"ascii\",\n    \"ansix341968\": \"ascii\",\n    \"ansix341986\": \"ascii\",\n    \"csascii\": \"ascii\",\n    \"cp367\": \"ascii\",\n    \"ibm367\": \"ascii\",\n    \"isoir6\": \"ascii\",\n    \"iso646us\": \"ascii\",\n    \"iso646irv\": \"ascii\",\n    \"us\": \"ascii\",\n\n    \"latin1\": \"iso88591\",\n    \"latin2\": \"iso88592\",\n    \"latin3\": \"iso88593\",\n    \"latin4\": \"iso88594\",\n    \"latin5\": \"iso88599\",\n    \"latin6\": \"iso885910\",\n    \"latin7\": \"iso885913\",\n    \"latin8\": \"iso885914\",\n    \"latin9\": \"iso885915\",\n    \"latin10\": \"iso885916\",\n\n    \"csisolatin1\": \"iso88591\",\n    \"csisolatin2\": \"iso88592\",\n    \"csisolatin3\": \"iso88593\",\n    \"csisolatin4\": \"iso88594\",\n    \"csisolatincyrillic\": \"iso88595\",\n    \"csisolatinarabic\": \"iso88596\",\n    \"csisolatingreek\" : \"iso88597\",\n    \"csisolatinhebrew\": \"iso88598\",\n    \"csisolatin5\": \"iso88599\",\n    \"csisolatin6\": \"iso885910\",\n\n    \"l1\": \"iso88591\",\n    \"l2\": \"iso88592\",\n    \"l3\": \"iso88593\",\n    \"l4\": \"iso88594\",\n    \"l5\": \"iso88599\",\n    \"l6\": \"iso885910\",\n    \"l7\": \"iso885913\",\n    \"l8\": \"iso885914\",\n    \"l9\": \"iso885915\",\n    \"l10\": \"iso885916\",\n\n    \"isoir14\": \"iso646jp\",\n    \"isoir57\": \"iso646cn\",\n    \"isoir100\": \"iso88591\",\n    \"isoir101\": \"iso88592\",\n    \"isoir109\": \"iso88593\",\n    \"isoir110\": \"iso88594\",\n    \"isoir144\": \"iso88595\",\n    \"isoir127\": \"iso88596\",\n    \"isoir126\": \"iso88597\",\n    \"isoir138\": \"iso88598\",\n    \"isoir148\": \"iso88599\",\n    \"isoir157\": \"iso885910\",\n    \"isoir166\": \"tis620\",\n    \"isoir179\": \"iso885913\",\n    \"isoir199\": \"iso885914\",\n    \"isoir203\": \"iso885915\",\n    \"isoir226\": \"iso885916\",\n\n    \"cp819\": \"iso88591\",\n    \"ibm819\": \"iso88591\",\n\n    \"cyrillic\": \"iso88595\",\n\n    \"arabic\": \"iso88596\",\n    \"arabic8\": \"iso88596\",\n    \"ecma114\": \"iso88596\",\n    \"asmo708\": \"iso88596\",\n\n    \"greek\" : \"iso88597\",\n    \"greek8\" : \"iso88597\",\n    \"ecma118\" : \"iso88597\",\n    \"elot928\" : \"iso88597\",\n\n    \"hebrew\": \"iso88598\",\n    \"hebrew8\": \"iso88598\",\n\n    \"turkish\": \"iso88599\",\n    \"turkish8\": \"iso88599\",\n\n    \"thai\": \"iso885911\",\n    \"thai8\": \"iso885911\",\n\n    \"celtic\": \"iso885914\",\n    \"celtic8\": \"iso885914\",\n    \"isoceltic\": \"iso885914\",\n\n    \"tis6200\": \"tis620\",\n    \"tis62025291\": \"tis620\",\n    \"tis62025330\": \"tis620\",\n\n    \"10000\": \"macroman\",\n    \"10006\": \"macgreek\",\n    \"10007\": \"maccyrillic\",\n    \"10079\": \"maciceland\",\n    \"10081\": \"macturkish\",\n\n    \"cspc8codepage437\": \"cp437\",\n    \"cspc775baltic\": \"cp775\",\n    \"cspc850multilingual\": \"cp850\",\n    \"cspcp852\": \"cp852\",\n    \"cspc862latinhebrew\": \"cp862\",\n    \"cpgr\": \"cp869\",\n\n    \"msee\": \"cp1250\",\n    \"mscyrl\": \"cp1251\",\n    \"msansi\": \"cp1252\",\n    \"msgreek\": \"cp1253\",\n    \"msturk\": \"cp1254\",\n    \"mshebr\": \"cp1255\",\n    \"msarab\": \"cp1256\",\n    \"winbaltrim\": \"cp1257\",\n\n    \"cp20866\": \"koi8r\",\n    \"20866\": \"koi8r\",\n    \"ibm878\": \"koi8r\",\n    \"cskoi8r\": \"koi8r\",\n\n    \"cp21866\": \"koi8u\",\n    \"21866\": \"koi8u\",\n    \"ibm1168\": \"koi8u\",\n\n    \"strk10482002\": \"rk1048\",\n\n    \"tcvn5712\": \"tcvn\",\n    \"tcvn57121\": \"tcvn\",\n\n    \"gb198880\": \"iso646cn\",\n    \"cn\": \"iso646cn\",\n\n    \"csiso14jisc6220ro\": \"iso646jp\",\n    \"jisc62201969ro\": \"iso646jp\",\n    \"jp\": \"iso646jp\",\n\n    \"cshproman8\": \"hproman8\",\n    \"r8\": \"hproman8\",\n    \"roman8\": \"hproman8\",\n    \"xroman8\": \"hproman8\",\n    \"ibm1051\": \"hproman8\",\n\n    \"mac\": \"macintosh\",\n    \"csmacintosh\": \"macintosh\",\n};\n\n\n\n/***/ }),\n/* 177 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// Generated data for sbcs codec. Don't edit manually. Regenerate using generation/gen-sbcs.js script.\nmodule.exports = {\n  \"437\": \"cp437\",\n  \"737\": \"cp737\",\n  \"775\": \"cp775\",\n  \"850\": \"cp850\",\n  \"852\": \"cp852\",\n  \"855\": \"cp855\",\n  \"856\": \"cp856\",\n  \"857\": \"cp857\",\n  \"858\": \"cp858\",\n  \"860\": \"cp860\",\n  \"861\": \"cp861\",\n  \"862\": \"cp862\",\n  \"863\": \"cp863\",\n  \"864\": \"cp864\",\n  \"865\": \"cp865\",\n  \"866\": \"cp866\",\n  \"869\": \"cp869\",\n  \"874\": \"windows874\",\n  \"922\": \"cp922\",\n  \"1046\": \"cp1046\",\n  \"1124\": \"cp1124\",\n  \"1125\": \"cp1125\",\n  \"1129\": \"cp1129\",\n  \"1133\": \"cp1133\",\n  \"1161\": \"cp1161\",\n  \"1162\": \"cp1162\",\n  \"1163\": \"cp1163\",\n  \"1250\": \"windows1250\",\n  \"1251\": \"windows1251\",\n  \"1252\": \"windows1252\",\n  \"1253\": \"windows1253\",\n  \"1254\": \"windows1254\",\n  \"1255\": \"windows1255\",\n  \"1256\": \"windows1256\",\n  \"1257\": \"windows1257\",\n  \"1258\": \"windows1258\",\n  \"28591\": \"iso88591\",\n  \"28592\": \"iso88592\",\n  \"28593\": \"iso88593\",\n  \"28594\": \"iso88594\",\n  \"28595\": \"iso88595\",\n  \"28596\": \"iso88596\",\n  \"28597\": \"iso88597\",\n  \"28598\": \"iso88598\",\n  \"28599\": \"iso88599\",\n  \"28600\": \"iso885910\",\n  \"28601\": \"iso885911\",\n  \"28603\": \"iso885913\",\n  \"28604\": \"iso885914\",\n  \"28605\": \"iso885915\",\n  \"28606\": \"iso885916\",\n  \"windows874\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€����…�����������‘’“”•–—�������� กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����\"\n  },\n  \"win874\": \"windows874\",\n  \"cp874\": \"windows874\",\n  \"windows1250\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€�‚�„…†‡�‰Š‹ŚŤŽŹ�‘’“”•–—�™š›śťžź ˇ˘Ł¤Ą¦§¨©Ş«¬­®Ż°±˛ł´µ¶·¸ąş»Ľ˝ľżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙\"\n  },\n  \"win1250\": \"windows1250\",\n  \"cp1250\": \"windows1250\",\n  \"windows1251\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ЂЃ‚ѓ„…†‡€‰Љ‹ЊЌЋЏђ‘’“”•–—�™љ›њќћџ ЎўЈ¤Ґ¦§Ё©Є«¬­®Ї°±Ііґµ¶·ё№є»јЅѕїАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя\"\n  },\n  \"win1251\": \"windows1251\",\n  \"cp1251\": \"windows1251\",\n  \"windows1252\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€�‚ƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"\n  },\n  \"win1252\": \"windows1252\",\n  \"cp1252\": \"windows1252\",\n  \"windows1253\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€�‚ƒ„…†‡�‰�‹�����‘’“”•–—�™�›���� ΅Ά£¤¥¦§¨©�«¬­®―°±²³΄µ¶·ΈΉΊ»Ό½ΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ�ΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ�\"\n  },\n  \"win1253\": \"windows1253\",\n  \"cp1253\": \"windows1253\",\n  \"windows1254\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€�‚ƒ„…†‡ˆ‰Š‹Œ����‘’“”•–—˜™š›œ��Ÿ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖ×ØÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ\"\n  },\n  \"win1254\": \"windows1254\",\n  \"cp1254\": \"windows1254\",\n  \"windows1255\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€�‚ƒ„…†‡ˆ‰�‹�����‘’“”•–—˜™�›���� ¡¢£₪¥¦§¨©×«¬­®¯°±²³´µ¶·¸¹÷»¼½¾¿ְֱֲֳִֵֶַָֹֺֻּֽ־ֿ׀ׁׂ׃װױײ׳״�������אבגדהוזחטיךכלםמןנסעףפץצקרשת��‎‏�\"\n  },\n  \"win1255\": \"windows1255\",\n  \"cp1255\": \"windows1255\",\n  \"windows1256\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€پ‚ƒ„…†‡ˆ‰ٹ‹Œچژڈگ‘’“”•–—ک™ڑ›œ‌‍ں ،¢£¤¥¦§¨©ھ«¬­®¯°±²³´µ¶·¸¹؛»¼½¾؟ہءآأؤإئابةتثجحخدذرزسشصض×طظعغـفقكàلâمنهوçèéêëىيîïًٌٍَôُِ÷ّùْûü‎‏ے\"\n  },\n  \"win1256\": \"windows1256\",\n  \"cp1256\": \"windows1256\",\n  \"windows1257\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€�‚�„…†‡�‰�‹�¨ˇ¸�‘’“”•–—�™�›�¯˛� �¢£¤�¦§Ø©Ŗ«¬­®Æ°±²³´µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżž˙\"\n  },\n  \"win1257\": \"windows1257\",\n  \"cp1257\": \"windows1257\",\n  \"windows1258\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€�‚ƒ„…†‡ˆ‰�‹Œ����‘’“”•–—˜™�›œ��Ÿ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂĂÄÅÆÇÈÉÊË̀ÍÎÏĐÑ̉ÓÔƠÖ×ØÙÚÛÜỮßàáâăäåæçèéêë́íîïđṇ̃óôơö÷øùúûüư₫ÿ\"\n  },\n  \"win1258\": \"windows1258\",\n  \"cp1258\": \"windows1258\",\n  \"iso88591\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"\n  },\n  \"cp28591\": \"iso88591\",\n  \"iso88592\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" Ą˘Ł¤ĽŚ§¨ŠŞŤŹ­ŽŻ°ą˛ł´ľśˇ¸šşťź˝žżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙\"\n  },\n  \"cp28592\": \"iso88592\",\n  \"iso88593\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" Ħ˘£¤�Ĥ§¨İŞĞĴ­�Ż°ħ²³´µĥ·¸ışğĵ½�żÀÁÂ�ÄĊĈÇÈÉÊËÌÍÎÏ�ÑÒÓÔĠÖ×ĜÙÚÛÜŬŜßàáâ�äċĉçèéêëìíîï�ñòóôġö÷ĝùúûüŭŝ˙\"\n  },\n  \"cp28593\": \"iso88593\",\n  \"iso88594\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ĄĸŖ¤ĨĻ§¨ŠĒĢŦ­Ž¯°ą˛ŗ´ĩļˇ¸šēģŧŊžŋĀÁÂÃÄÅÆĮČÉĘËĖÍÎĪĐŅŌĶÔÕÖ×ØŲÚÛÜŨŪßāáâãäåæįčéęëėíîīđņōķôõö÷øųúûüũū˙\"\n  },\n  \"cp28594\": \"iso88594\",\n  \"iso88595\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ЁЂЃЄЅІЇЈЉЊЋЌ­ЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя№ёђѓєѕіїјљњћќ§ўџ\"\n  },\n  \"cp28595\": \"iso88595\",\n  \"iso88596\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ���¤�������،­�������������؛���؟�ءآأؤإئابةتثجحخدذرزسشصضطظعغ�����ـفقكلمنهوىيًٌٍَُِّْ�������������\"\n  },\n  \"cp28596\": \"iso88596\",\n  \"iso88597\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ‘’£€₯¦§¨©ͺ«¬­�―°±²³΄΅Ά·ΈΉΊ»Ό½ΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ�ΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ�\"\n  },\n  \"cp28597\": \"iso88597\",\n  \"iso88598\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" �¢£¤¥¦§¨©×«¬­®¯°±²³´µ¶·¸¹÷»¼½¾��������������������������������‗אבגדהוזחטיךכלםמןנסעףפץצקרשת��‎‏�\"\n  },\n  \"cp28598\": \"iso88598\",\n  \"iso88599\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖ×ØÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ\"\n  },\n  \"cp28599\": \"iso88599\",\n  \"iso885910\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ĄĒĢĪĨĶ§ĻĐŠŦŽ­ŪŊ°ąēģīĩķ·ļđšŧž―ūŋĀÁÂÃÄÅÆĮČÉĘËĖÍÎÏÐŅŌÓÔÕÖŨØŲÚÛÜÝÞßāáâãäåæįčéęëėíîïðņōóôõöũøųúûüýþĸ\"\n  },\n  \"cp28600\": \"iso885910\",\n  \"iso885911\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����\"\n  },\n  \"cp28601\": \"iso885911\",\n  \"iso885913\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ”¢£¤„¦§Ø©Ŗ«¬­®Æ°±²³“µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżž’\"\n  },\n  \"cp28603\": \"iso885913\",\n  \"iso885914\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" Ḃḃ£ĊċḊ§Ẁ©ẂḋỲ­®ŸḞḟĠġṀṁ¶ṖẁṗẃṠỳẄẅṡÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏŴÑÒÓÔÕÖṪØÙÚÛÜÝŶßàáâãäåæçèéêëìíîïŵñòóôõöṫøùúûüýŷÿ\"\n  },\n  \"cp28604\": \"iso885914\",\n  \"iso885915\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ¡¢£€¥Š§š©ª«¬­®¯°±²³Žµ¶·ž¹º»ŒœŸ¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"\n  },\n  \"cp28605\": \"iso885915\",\n  \"iso885916\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ĄąŁ€„Š§š©Ș«Ź­źŻ°±ČłŽ”¶·žčș»ŒœŸżÀÁÂĂÄĆÆÇÈÉÊËÌÍÎÏĐŃÒÓÔŐÖŚŰÙÚÛÜĘȚßàáâăäćæçèéêëìíîïđńòóôőöśűùúûüęțÿ\"\n  },\n  \"cp28606\": \"iso885916\",\n  \"cp437\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñÑªº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ \"\n  },\n  \"ibm437\": \"cp437\",\n  \"csibm437\": \"cp437\",\n  \"cp737\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρσςτυφχψ░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀ωάέήϊίόύϋώΆΈΉΊΌΎΏ±≥≤ΪΫ÷≈°∙·√ⁿ²■ \"\n  },\n  \"ibm737\": \"cp737\",\n  \"csibm737\": \"cp737\",\n  \"cp775\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ĆüéāäģåćłēŖŗīŹÄÅÉæÆōöĢ¢ŚśÖÜø£Ø×¤ĀĪóŻżź”¦©®¬½¼Ł«»░▒▓│┤ĄČĘĖ╣║╗╝ĮŠ┐└┴┬├─┼ŲŪ╚╔╩╦╠═╬Žąčęėįšųūž┘┌█▄▌▐▀ÓßŌŃõÕµńĶķĻļņĒŅ’­±“¾¶§÷„°∙·¹³²■ \"\n  },\n  \"ibm775\": \"cp775\",\n  \"csibm775\": \"cp775\",\n  \"cp850\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø×ƒáíóúñÑªº¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ðÐÊËÈıÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµþÞÚÛÙýÝ¯´­±‗¾¶§÷¸°¨·¹³²■ \"\n  },\n  \"ibm850\": \"cp850\",\n  \"csibm850\": \"cp850\",\n  \"cp852\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâäůćçłëŐőîŹÄĆÉĹĺôöĽľŚśÖÜŤťŁ×čáíóúĄąŽžĘę¬źČş«»░▒▓│┤ÁÂĚŞ╣║╗╝Żż┐└┴┬├─┼Ăă╚╔╩╦╠═╬¤đĐĎËďŇÍÎě┘┌█▄ŢŮ▀ÓßÔŃńňŠšŔÚŕŰýÝţ´­˝˛ˇ˘§÷¸°¨˙űŘř■ \"\n  },\n  \"ibm852\": \"cp852\",\n  \"csibm852\": \"cp852\",\n  \"cp855\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ђЂѓЃёЁєЄѕЅіІїЇјЈљЉњЊћЋќЌўЎџЏюЮъЪаАбБцЦдДеЕфФгГ«»░▒▓│┤хХиИ╣║╗╝йЙ┐└┴┬├─┼кК╚╔╩╦╠═╬¤лЛмМнНоОп┘┌█▄Пя▀ЯрРсСтТуУжЖвВьЬ№­ыЫзЗшШэЭщЩчЧ§■ \"\n  },\n  \"ibm855\": \"cp855\",\n  \"csibm855\": \"cp855\",\n  \"cp856\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"אבגדהוזחטיךכלםמןנסעףפץצקרשת�£�×����������®¬½¼�«»░▒▓│┤���©╣║╗╝¢¥┐└┴┬├─┼��╚╔╩╦╠═╬¤���������┘┌█▄¦�▀������µ�������¯´­±‗¾¶§÷¸°¨·¹³²■ \"\n  },\n  \"ibm856\": \"cp856\",\n  \"csibm856\": \"cp856\",\n  \"cp857\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâäàåçêëèïîıÄÅÉæÆôöòûùİÖÜø£ØŞşáíóúñÑĞğ¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ºªÊËÈ�ÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµ�×ÚÛÙìÿ¯´­±�¾¶§÷¸°¨·¹³²■ \"\n  },\n  \"ibm857\": \"cp857\",\n  \"csibm857\": \"cp857\",\n  \"cp858\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø×ƒáíóúñÑªº¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ðÐÊËÈ€ÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµþÞÚÛÙýÝ¯´­±‗¾¶§÷¸°¨·¹³²■ \"\n  },\n  \"ibm858\": \"cp858\",\n  \"csibm858\": \"cp858\",\n  \"cp860\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâãàÁçêÊèÍÔìÃÂÉÀÈôõòÚùÌÕÜ¢£Ù₧ÓáíóúñÑªº¿Ò¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ \"\n  },\n  \"ibm860\": \"cp860\",\n  \"csibm860\": \"cp860\",\n  \"cp861\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâäàåçêëèÐðÞÄÅÉæÆôöþûÝýÖÜø£Ø₧ƒáíóúÁÍÓÚ¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ \"\n  },\n  \"ibm861\": \"cp861\",\n  \"csibm861\": \"cp861\",\n  \"cp862\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"אבגדהוזחטיךכלםמןנסעףפץצקרשת¢£¥₧ƒáíóúñÑªº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ \"\n  },\n  \"ibm862\": \"cp862\",\n  \"csibm862\": \"cp862\",\n  \"cp863\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâÂà¶çêëèïî‗À§ÉÈÊôËÏûù¤ÔÜ¢£ÙÛƒ¦´óú¨¸³¯Î⌐¬½¼¾«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ \"\n  },\n  \"ibm863\": \"cp863\",\n  \"csibm863\": \"cp863\",\n  \"cp864\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f !\\\"#$٪&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~°·∙√▒─│┼┤┬├┴┐┌└┘β∞φ±½¼≈«»ﻷﻸ��ﻻﻼ� ­ﺂ£¤ﺄ��ﺎﺏﺕﺙ،ﺝﺡﺥ٠١٢٣٤٥٦٧٨٩ﻑ؛ﺱﺵﺹ؟¢ﺀﺁﺃﺅﻊﺋﺍﺑﺓﺗﺛﺟﺣﺧﺩﺫﺭﺯﺳﺷﺻﺿﻁﻅﻋﻏ¦¬÷×ﻉـﻓﻗﻛﻟﻣﻧﻫﻭﻯﻳﺽﻌﻎﻍﻡﹽّﻥﻩﻬﻰﻲﻐﻕﻵﻶﻝﻙﻱ■�\"\n  },\n  \"ibm864\": \"cp864\",\n  \"csibm864\": \"cp864\",\n  \"cp865\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø₧ƒáíóúñÑªº¿⌐¬½¼¡«¤░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ \"\n  },\n  \"ibm865\": \"cp865\",\n  \"csibm865\": \"cp865\",\n  \"cp866\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёЄєЇїЎў°∙·√№¤■ \"\n  },\n  \"ibm866\": \"cp866\",\n  \"csibm866\": \"cp866\",\n  \"cp869\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"������Ά�·¬¦‘’Έ―ΉΊΪΌ��ΎΫ©Ώ²³ά£έήίϊΐόύΑΒΓΔΕΖΗ½ΘΙ«»░▒▓│┤ΚΛΜΝ╣║╗╝ΞΟ┐└┴┬├─┼ΠΡ╚╔╩╦╠═╬ΣΤΥΦΧΨΩαβγ┘┌█▄δε▀ζηθικλμνξοπρσςτ΄­±υφχ§ψ΅°¨ωϋΰώ■ \"\n  },\n  \"ibm869\": \"cp869\",\n  \"csibm869\": \"cp869\",\n  \"cp922\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ¡¢£¤¥¦§¨©ª«¬­®‾°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏŠÑÒÓÔÕÖ×ØÙÚÛÜÝŽßàáâãäåæçèéêëìíîïšñòóôõö÷øùúûüýžÿ\"\n  },\n  \"ibm922\": \"cp922\",\n  \"csibm922\": \"cp922\",\n  \"cp1046\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ﺈ×÷ﹱ■│─┐┌└┘ﹹﹻﹽﹿﹷﺊﻰﻳﻲﻎﻏﻐﻶﻸﻺﻼ ¤ﺋﺑﺗﺛﺟﺣ،­ﺧﺳ٠١٢٣٤٥٦٧٨٩ﺷ؛ﺻﺿﻊ؟ﻋءآأؤإئابةتثجحخدذرزسشصضطﻇعغﻌﺂﺄﺎﻓـفقكلمنهوىيًٌٍَُِّْﻗﻛﻟﻵﻷﻹﻻﻣﻧﻬﻩ�\"\n  },\n  \"ibm1046\": \"cp1046\",\n  \"csibm1046\": \"cp1046\",\n  \"cp1124\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ЁЂҐЄЅІЇЈЉЊЋЌ­ЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя№ёђґєѕіїјљњћќ§ўџ\"\n  },\n  \"ibm1124\": \"cp1124\",\n  \"csibm1124\": \"cp1124\",\n  \"cp1125\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёҐґЄєІіЇї·√№¤■ \"\n  },\n  \"ibm1125\": \"cp1125\",\n  \"csibm1125\": \"cp1125\",\n  \"cp1129\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ¡¢£¤¥¦§œ©ª«¬­®¯°±²³Ÿµ¶·Œ¹º»¼½¾¿ÀÁÂĂÄÅÆÇÈÉÊË̀ÍÎÏĐÑ̉ÓÔƠÖ×ØÙÚÛÜỮßàáâăäåæçèéêë́íîïđṇ̃óôơö÷øùúûüư₫ÿ\"\n  },\n  \"ibm1129\": \"cp1129\",\n  \"csibm1129\": \"cp1129\",\n  \"cp1133\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ກຂຄງຈສຊຍດຕຖທນບປຜຝພຟມຢຣລວຫອຮ���ຯະາຳິີຶືຸູຼັົຽ���ເແໂໃໄ່້໊໋໌ໍໆ�ໜໝ₭����������������໐໑໒໓໔໕໖໗໘໙��¢¬¦�\"\n  },\n  \"ibm1133\": \"cp1133\",\n  \"csibm1133\": \"cp1133\",\n  \"cp1161\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"��������������������������������่กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู้๊๋€฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛¢¬¦ \"\n  },\n  \"ibm1161\": \"cp1161\",\n  \"csibm1161\": \"cp1161\",\n  \"cp1162\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"€…‘’“”•–— กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����\"\n  },\n  \"ibm1162\": \"cp1162\",\n  \"csibm1162\": \"cp1162\",\n  \"cp1163\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ¡¢£€¥¦§œ©ª«¬­®¯°±²³Ÿµ¶·Œ¹º»¼½¾¿ÀÁÂĂÄÅÆÇÈÉÊË̀ÍÎÏĐÑ̉ÓÔƠÖ×ØÙÚÛÜỮßàáâăäåæçèéêë́íîïđṇ̃óôơö÷øùúûüư₫ÿ\"\n  },\n  \"ibm1163\": \"cp1163\",\n  \"csibm1163\": \"cp1163\",\n  \"maccroatian\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®Š™´¨≠ŽØ∞±≤≥∆µ∂∑∏š∫ªºΩžø¿¡¬√ƒ≈Ć«Č… ÀÃÕŒœĐ—“”‘’÷◊�©⁄¤‹›Æ»–·‚„‰ÂćÁčÈÍÎÏÌÓÔđÒÚÛÙıˆ˜¯πË˚¸Êæˇ\"\n  },\n  \"maccyrillic\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°¢£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµ∂ЈЄєЇїЉљЊњјЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю¤\"\n  },\n  \"macgreek\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"Ä¹²É³ÖÜ΅àâä΄¨çéèêë£™îï•½‰ôö¦­ùûü†ΓΔΘΛΞΠß®©ΣΪ§≠°·Α±≤≥¥ΒΕΖΗΙΚΜΦΫΨΩάΝ¬ΟΡ≈Τ«»… ΥΧΆΈœ–―“”‘’÷ΉΊΌΎέήίόΏύαβψδεφγηιξκλμνοπώρστθωςχυζϊϋΐΰ�\"\n  },\n  \"maciceland\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûüÝ°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤ÐðÞþý·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ\"\n  },\n  \"macroman\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤‹›ﬁﬂ‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ\"\n  },\n  \"macromania\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ĂŞ∞±≤≥¥µ∂∑∏π∫ªºΩăş¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤‹›Ţţ‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ\"\n  },\n  \"macthai\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"«»…“”�•‘’� กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู﻿​–—฿เแโใไๅๆ็่้๊๋์ํ™๏๐๑๒๓๔๕๖๗๘๙®©����\"\n  },\n  \"macturkish\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸĞğİıŞş‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙ�ˆ˜¯˘˙˚¸˝˛ˇ\"\n  },\n  \"macukraine\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°Ґ£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµґЈЄєЇїЉљЊњјЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю¤\"\n  },\n  \"koi8r\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ё╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡Ё╢╣╤╥╦╧╨╩╪╫╬©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ\"\n  },\n  \"koi8u\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ёє╔ії╗╘╙╚╛ґ╝╞╟╠╡ЁЄ╣ІЇ╦╧╨╩╪Ґ╬©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ\"\n  },\n  \"koi8ru\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ёє╔ії╗╘╙╚╛ґў╞╟╠╡ЁЄ╣ІЇ╦╧╨╩╪ҐЎ©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ\"\n  },\n  \"koi8t\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"қғ‚Ғ„…†‡�‰ҳ‹ҲҷҶ�Қ‘’“”•–—�™�›�����ӯӮё¤ӣ¦§���«¬­®�°±²Ё�Ӣ¶·�№�»���©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ\"\n  },\n  \"armscii8\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" �և։)(»«—.՝,-֊…՜՛՞ԱաԲբԳգԴդԵեԶզԷէԸըԹթԺժԻիԼլԽխԾծԿկՀհՁձՂղՃճՄմՅյՆնՇշՈոՉչՊպՋջՌռՍսՎվՏտՐրՑցՒւՓփՔքՕօՖֆ՚�\"\n  },\n  \"rk1048\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ЂЃ‚ѓ„…†‡€‰Љ‹ЊҚҺЏђ‘’“”•–—�™љ›њқһџ ҰұӘ¤Ө¦§Ё©Ғ«¬­®Ү°±Ііөµ¶·ё№ғ»әҢңүАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя\"\n  },\n  \"tcvn\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"\\u0000ÚỤ\\u0003ỪỬỮ\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010ỨỰỲỶỸÝỴ\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÀẢÃÁẠẶẬÈẺẼÉẸỆÌỈĨÍỊÒỎÕÓỌỘỜỞỠỚỢÙỦŨ ĂÂÊÔƠƯĐăâêôơưđẶ̀̀̉̃́àảãáạẲằẳẵắẴẮẦẨẪẤỀặầẩẫấậèỂẻẽéẹềểễếệìỉỄẾỒĩíịòỔỏõóọồổỗốộờởỡớợùỖủũúụừửữứựỳỷỹýỵỐ\"\n  },\n  \"georgianacademy\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"‚ƒ„…†‡ˆ‰Š‹Œ‘’“”•–—˜™š›œŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿აბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰჱჲჳჴჵჶçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"\n  },\n  \"georgianps\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"‚ƒ„…†‡ˆ‰Š‹Œ‘’“”•–—˜™š›œŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿აბგდევზჱთიკლმნჲოპჟრსტჳუფქღყშჩცძწჭხჴჯჰჵæçèéêëìíîïðñòóôõö÷øùúûüýþÿ\"\n  },\n  \"pt154\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ҖҒӮғ„…ҶҮҲүҠӢҢҚҺҸҗ‘’“”•–—ҳҷҡӣңқһҹ ЎўЈӨҘҰ§Ё©Ә«¬ӯ®Ҝ°ұІіҙө¶·ё№ә»јҪҫҝАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя\"\n  },\n  \"viscii\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"\\u0000\\u0001Ẳ\\u0003\\u0004ẴẪ\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013Ỷ\\u0015\\u0016\\u0017\\u0018Ỹ\\u001a\\u001b\\u001c\\u001dỴ\\u001f !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ẠẮẰẶẤẦẨẬẼẸẾỀỂỄỆỐỒỔỖỘỢỚỜỞỊỎỌỈỦŨỤỲÕắằặấầẩậẽẹếềểễệốồổỗỠƠộờởịỰỨỪỬơớƯÀÁÂÃẢĂẳẵÈÉÊẺÌÍĨỳĐứÒÓÔạỷừửÙÚỹỵÝỡưàáâãảăữẫèéêẻìíĩỉđựòóôõỏọụùúũủýợỮ\"\n  },\n  \"iso646cn\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f !\\\"#¥%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}‾��������������������������������������������������������������������������������������������������������������������������������\"\n  },\n  \"iso646jp\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[¥]^_`abcdefghijklmnopqrstuvwxyz{|}‾��������������������������������������������������������������������������������������������������������������������������������\"\n  },\n  \"hproman8\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \" ÀÂÈÊËÎÏ´ˋˆ¨˜ÙÛ₤¯Ýý°ÇçÑñ¡¿¤£¥§ƒ¢âêôûáéóúàèòùäëöüÅîØÆåíøæÄìÖÜÉïßÔÁÃãÐðÍÌÓÒÕõŠšÚŸÿÞþ·µ¶¾—¼½ªº«■»±�\"\n  },\n  \"macintosh\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤‹›ﬁﬂ‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ�ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ\"\n  },\n  \"ascii\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"��������������������������������������������������������������������������������������������������������������������������������\"\n  },\n  \"tis620\": {\n    \"type\": \"_sbcs\",\n    \"chars\": \"���������������������������������กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����\"\n  }\n}\n\n/***/ }),\n/* 178 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar Buffer = __webpack_require__(1).Buffer;\n\n// Multibyte codec. In this scheme, a character is represented by 1 or more bytes.\n// Our codec supports UTF-16 surrogates, extensions for GB18030 and unicode sequences.\n// To save memory and loading time, we read table files only when requested.\n\nexports._dbcs = DBCSCodec;\n\nvar UNASSIGNED = -1,\n    GB18030_CODE = -2,\n    SEQ_START  = -10,\n    NODE_START = -1000,\n    UNASSIGNED_NODE = new Array(0x100),\n    DEF_CHAR = -1;\n\nfor (var i = 0; i < 0x100; i++)\n    UNASSIGNED_NODE[i] = UNASSIGNED;\n\n\n// Class DBCSCodec reads and initializes mapping tables.\nfunction DBCSCodec(codecOptions, iconv) {\n    this.encodingName = codecOptions.encodingName;\n    if (!codecOptions)\n        throw new Error(\"DBCS codec is called without the data.\")\n    if (!codecOptions.table)\n        throw new Error(\"Encoding '\" + this.encodingName + \"' has no data.\");\n\n    // Load tables.\n    var mappingTable = codecOptions.table();\n\n\n    // Decode tables: MBCS -> Unicode.\n\n    // decodeTables is a trie, encoded as an array of arrays of integers. Internal arrays are trie nodes and all have len = 256.\n    // Trie root is decodeTables[0].\n    // Values: >=  0 -> unicode character code. can be > 0xFFFF\n    //         == UNASSIGNED -> unknown/unassigned sequence.\n    //         == GB18030_CODE -> this is the end of a GB18030 4-byte sequence.\n    //         <= NODE_START -> index of the next node in our trie to process next byte.\n    //         <= SEQ_START  -> index of the start of a character code sequence, in decodeTableSeq.\n    this.decodeTables = [];\n    this.decodeTables[0] = UNASSIGNED_NODE.slice(0); // Create root node.\n\n    // Sometimes a MBCS char corresponds to a sequence of unicode chars. We store them as arrays of integers here. \n    this.decodeTableSeq = [];\n\n    // Actual mapping tables consist of chunks. Use them to fill up decode tables.\n    for (var i = 0; i < mappingTable.length; i++)\n        this._addDecodeChunk(mappingTable[i]);\n\n    this.defaultCharUnicode = iconv.defaultCharUnicode;\n\n    \n    // Encode tables: Unicode -> DBCS.\n\n    // `encodeTable` is array mapping from unicode char to encoded char. All its values are integers for performance.\n    // Because it can be sparse, it is represented as array of buckets by 256 chars each. Bucket can be null.\n    // Values: >=  0 -> it is a normal char. Write the value (if <=256 then 1 byte, if <=65536 then 2 bytes, etc.).\n    //         == UNASSIGNED -> no conversion found. Output a default char.\n    //         <= SEQ_START  -> it's an index in encodeTableSeq, see below. The character starts a sequence.\n    this.encodeTable = [];\n    \n    // `encodeTableSeq` is used when a sequence of unicode characters is encoded as a single code. We use a tree of\n    // objects where keys correspond to characters in sequence and leafs are the encoded dbcs values. A special DEF_CHAR key\n    // means end of sequence (needed when one sequence is a strict subsequence of another).\n    // Objects are kept separately from encodeTable to increase performance.\n    this.encodeTableSeq = [];\n\n    // Some chars can be decoded, but need not be encoded.\n    var skipEncodeChars = {};\n    if (codecOptions.encodeSkipVals)\n        for (var i = 0; i < codecOptions.encodeSkipVals.length; i++) {\n            var val = codecOptions.encodeSkipVals[i];\n            if (typeof val === 'number')\n                skipEncodeChars[val] = true;\n            else\n                for (var j = val.from; j <= val.to; j++)\n                    skipEncodeChars[j] = true;\n        }\n        \n    // Use decode trie to recursively fill out encode tables.\n    this._fillEncodeTable(0, 0, skipEncodeChars);\n\n    // Add more encoding pairs when needed.\n    if (codecOptions.encodeAdd) {\n        for (var uChar in codecOptions.encodeAdd)\n            if (Object.prototype.hasOwnProperty.call(codecOptions.encodeAdd, uChar))\n                this._setEncodeChar(uChar.charCodeAt(0), codecOptions.encodeAdd[uChar]);\n    }\n\n    this.defCharSB  = this.encodeTable[0][iconv.defaultCharSingleByte.charCodeAt(0)];\n    if (this.defCharSB === UNASSIGNED) this.defCharSB = this.encodeTable[0]['?'];\n    if (this.defCharSB === UNASSIGNED) this.defCharSB = \"?\".charCodeAt(0);\n\n\n    // Load & create GB18030 tables when needed.\n    if (typeof codecOptions.gb18030 === 'function') {\n        this.gb18030 = codecOptions.gb18030(); // Load GB18030 ranges.\n\n        // Add GB18030 decode tables.\n        var thirdByteNodeIdx = this.decodeTables.length;\n        var thirdByteNode = this.decodeTables[thirdByteNodeIdx] = UNASSIGNED_NODE.slice(0);\n\n        var fourthByteNodeIdx = this.decodeTables.length;\n        var fourthByteNode = this.decodeTables[fourthByteNodeIdx] = UNASSIGNED_NODE.slice(0);\n\n        for (var i = 0x81; i <= 0xFE; i++) {\n            var secondByteNodeIdx = NODE_START - this.decodeTables[0][i];\n            var secondByteNode = this.decodeTables[secondByteNodeIdx];\n            for (var j = 0x30; j <= 0x39; j++)\n                secondByteNode[j] = NODE_START - thirdByteNodeIdx;\n        }\n        for (var i = 0x81; i <= 0xFE; i++)\n            thirdByteNode[i] = NODE_START - fourthByteNodeIdx;\n        for (var i = 0x30; i <= 0x39; i++)\n            fourthByteNode[i] = GB18030_CODE\n    }        \n}\n\nDBCSCodec.prototype.encoder = DBCSEncoder;\nDBCSCodec.prototype.decoder = DBCSDecoder;\n\n// Decoder helpers\nDBCSCodec.prototype._getDecodeTrieNode = function(addr) {\n    var bytes = [];\n    for (; addr > 0; addr >>= 8)\n        bytes.push(addr & 0xFF);\n    if (bytes.length == 0)\n        bytes.push(0);\n\n    var node = this.decodeTables[0];\n    for (var i = bytes.length-1; i > 0; i--) { // Traverse nodes deeper into the trie.\n        var val = node[bytes[i]];\n\n        if (val == UNASSIGNED) { // Create new node.\n            node[bytes[i]] = NODE_START - this.decodeTables.length;\n            this.decodeTables.push(node = UNASSIGNED_NODE.slice(0));\n        }\n        else if (val <= NODE_START) { // Existing node.\n            node = this.decodeTables[NODE_START - val];\n        }\n        else\n            throw new Error(\"Overwrite byte in \" + this.encodingName + \", addr: \" + addr.toString(16));\n    }\n    return node;\n}\n\n\nDBCSCodec.prototype._addDecodeChunk = function(chunk) {\n    // First element of chunk is the hex mbcs code where we start.\n    var curAddr = parseInt(chunk[0], 16);\n\n    // Choose the decoding node where we'll write our chars.\n    var writeTable = this._getDecodeTrieNode(curAddr);\n    curAddr = curAddr & 0xFF;\n\n    // Write all other elements of the chunk to the table.\n    for (var k = 1; k < chunk.length; k++) {\n        var part = chunk[k];\n        if (typeof part === \"string\") { // String, write as-is.\n            for (var l = 0; l < part.length;) {\n                var code = part.charCodeAt(l++);\n                if (0xD800 <= code && code < 0xDC00) { // Decode surrogate\n                    var codeTrail = part.charCodeAt(l++);\n                    if (0xDC00 <= codeTrail && codeTrail < 0xE000)\n                        writeTable[curAddr++] = 0x10000 + (code - 0xD800) * 0x400 + (codeTrail - 0xDC00);\n                    else\n                        throw new Error(\"Incorrect surrogate pair in \"  + this.encodingName + \" at chunk \" + chunk[0]);\n                }\n                else if (0x0FF0 < code && code <= 0x0FFF) { // Character sequence (our own encoding used)\n                    var len = 0xFFF - code + 2;\n                    var seq = [];\n                    for (var m = 0; m < len; m++)\n                        seq.push(part.charCodeAt(l++)); // Simple variation: don't support surrogates or subsequences in seq.\n\n                    writeTable[curAddr++] = SEQ_START - this.decodeTableSeq.length;\n                    this.decodeTableSeq.push(seq);\n                }\n                else\n                    writeTable[curAddr++] = code; // Basic char\n            }\n        } \n        else if (typeof part === \"number\") { // Integer, meaning increasing sequence starting with prev character.\n            var charCode = writeTable[curAddr - 1] + 1;\n            for (var l = 0; l < part; l++)\n                writeTable[curAddr++] = charCode++;\n        }\n        else\n            throw new Error(\"Incorrect type '\" + typeof part + \"' given in \"  + this.encodingName + \" at chunk \" + chunk[0]);\n    }\n    if (curAddr > 0xFF)\n        throw new Error(\"Incorrect chunk in \"  + this.encodingName + \" at addr \" + chunk[0] + \": too long\" + curAddr);\n}\n\n// Encoder helpers\nDBCSCodec.prototype._getEncodeBucket = function(uCode) {\n    var high = uCode >> 8; // This could be > 0xFF because of astral characters.\n    if (this.encodeTable[high] === undefined)\n        this.encodeTable[high] = UNASSIGNED_NODE.slice(0); // Create bucket on demand.\n    return this.encodeTable[high];\n}\n\nDBCSCodec.prototype._setEncodeChar = function(uCode, dbcsCode) {\n    var bucket = this._getEncodeBucket(uCode);\n    var low = uCode & 0xFF;\n    if (bucket[low] <= SEQ_START)\n        this.encodeTableSeq[SEQ_START-bucket[low]][DEF_CHAR] = dbcsCode; // There's already a sequence, set a single-char subsequence of it.\n    else if (bucket[low] == UNASSIGNED)\n        bucket[low] = dbcsCode;\n}\n\nDBCSCodec.prototype._setEncodeSequence = function(seq, dbcsCode) {\n    \n    // Get the root of character tree according to first character of the sequence.\n    var uCode = seq[0];\n    var bucket = this._getEncodeBucket(uCode);\n    var low = uCode & 0xFF;\n\n    var node;\n    if (bucket[low] <= SEQ_START) {\n        // There's already a sequence with  - use it.\n        node = this.encodeTableSeq[SEQ_START-bucket[low]];\n    }\n    else {\n        // There was no sequence object - allocate a new one.\n        node = {};\n        if (bucket[low] !== UNASSIGNED) node[DEF_CHAR] = bucket[low]; // If a char was set before - make it a single-char subsequence.\n        bucket[low] = SEQ_START - this.encodeTableSeq.length;\n        this.encodeTableSeq.push(node);\n    }\n\n    // Traverse the character tree, allocating new nodes as needed.\n    for (var j = 1; j < seq.length-1; j++) {\n        var oldVal = node[uCode];\n        if (typeof oldVal === 'object')\n            node = oldVal;\n        else {\n            node = node[uCode] = {}\n            if (oldVal !== undefined)\n                node[DEF_CHAR] = oldVal\n        }\n    }\n\n    // Set the leaf to given dbcsCode.\n    uCode = seq[seq.length-1];\n    node[uCode] = dbcsCode;\n}\n\nDBCSCodec.prototype._fillEncodeTable = function(nodeIdx, prefix, skipEncodeChars) {\n    var node = this.decodeTables[nodeIdx];\n    for (var i = 0; i < 0x100; i++) {\n        var uCode = node[i];\n        var mbCode = prefix + i;\n        if (skipEncodeChars[mbCode])\n            continue;\n\n        if (uCode >= 0)\n            this._setEncodeChar(uCode, mbCode);\n        else if (uCode <= NODE_START)\n            this._fillEncodeTable(NODE_START - uCode, mbCode << 8, skipEncodeChars);\n        else if (uCode <= SEQ_START)\n            this._setEncodeSequence(this.decodeTableSeq[SEQ_START - uCode], mbCode);\n    }\n}\n\n\n\n// == Encoder ==================================================================\n\nfunction DBCSEncoder(options, codec) {\n    // Encoder state\n    this.leadSurrogate = -1;\n    this.seqObj = undefined;\n    \n    // Static data\n    this.encodeTable = codec.encodeTable;\n    this.encodeTableSeq = codec.encodeTableSeq;\n    this.defaultCharSingleByte = codec.defCharSB;\n    this.gb18030 = codec.gb18030;\n}\n\nDBCSEncoder.prototype.write = function(str) {\n    var newBuf = new Buffer(str.length * (this.gb18030 ? 4 : 3)), \n        leadSurrogate = this.leadSurrogate,\n        seqObj = this.seqObj, nextChar = -1,\n        i = 0, j = 0;\n\n    while (true) {\n        // 0. Get next character.\n        if (nextChar === -1) {\n            if (i == str.length) break;\n            var uCode = str.charCodeAt(i++);\n        }\n        else {\n            var uCode = nextChar;\n            nextChar = -1;    \n        }\n\n        // 1. Handle surrogates.\n        if (0xD800 <= uCode && uCode < 0xE000) { // Char is one of surrogates.\n            if (uCode < 0xDC00) { // We've got lead surrogate.\n                if (leadSurrogate === -1) {\n                    leadSurrogate = uCode;\n                    continue;\n                } else {\n                    leadSurrogate = uCode;\n                    // Double lead surrogate found.\n                    uCode = UNASSIGNED;\n                }\n            } else { // We've got trail surrogate.\n                if (leadSurrogate !== -1) {\n                    uCode = 0x10000 + (leadSurrogate - 0xD800) * 0x400 + (uCode - 0xDC00);\n                    leadSurrogate = -1;\n                } else {\n                    // Incomplete surrogate pair - only trail surrogate found.\n                    uCode = UNASSIGNED;\n                }\n                \n            }\n        }\n        else if (leadSurrogate !== -1) {\n            // Incomplete surrogate pair - only lead surrogate found.\n            nextChar = uCode; uCode = UNASSIGNED; // Write an error, then current char.\n            leadSurrogate = -1;\n        }\n\n        // 2. Convert uCode character.\n        var dbcsCode = UNASSIGNED;\n        if (seqObj !== undefined && uCode != UNASSIGNED) { // We are in the middle of the sequence\n            var resCode = seqObj[uCode];\n            if (typeof resCode === 'object') { // Sequence continues.\n                seqObj = resCode;\n                continue;\n\n            } else if (typeof resCode == 'number') { // Sequence finished. Write it.\n                dbcsCode = resCode;\n\n            } else if (resCode == undefined) { // Current character is not part of the sequence.\n\n                // Try default character for this sequence\n                resCode = seqObj[DEF_CHAR];\n                if (resCode !== undefined) {\n                    dbcsCode = resCode; // Found. Write it.\n                    nextChar = uCode; // Current character will be written too in the next iteration.\n\n                } else {\n                    // TODO: What if we have no default? (resCode == undefined)\n                    // Then, we should write first char of the sequence as-is and try the rest recursively.\n                    // Didn't do it for now because no encoding has this situation yet.\n                    // Currently, just skip the sequence and write current char.\n                }\n            }\n            seqObj = undefined;\n        }\n        else if (uCode >= 0) {  // Regular character\n            var subtable = this.encodeTable[uCode >> 8];\n            if (subtable !== undefined)\n                dbcsCode = subtable[uCode & 0xFF];\n            \n            if (dbcsCode <= SEQ_START) { // Sequence start\n                seqObj = this.encodeTableSeq[SEQ_START-dbcsCode];\n                continue;\n            }\n\n            if (dbcsCode == UNASSIGNED && this.gb18030) {\n                // Use GB18030 algorithm to find character(s) to write.\n                var idx = findIdx(this.gb18030.uChars, uCode);\n                if (idx != -1) {\n                    var dbcsCode = this.gb18030.gbChars[idx] + (uCode - this.gb18030.uChars[idx]);\n                    newBuf[j++] = 0x81 + Math.floor(dbcsCode / 12600); dbcsCode = dbcsCode % 12600;\n                    newBuf[j++] = 0x30 + Math.floor(dbcsCode / 1260); dbcsCode = dbcsCode % 1260;\n                    newBuf[j++] = 0x81 + Math.floor(dbcsCode / 10); dbcsCode = dbcsCode % 10;\n                    newBuf[j++] = 0x30 + dbcsCode;\n                    continue;\n                }\n            }\n        }\n\n        // 3. Write dbcsCode character.\n        if (dbcsCode === UNASSIGNED)\n            dbcsCode = this.defaultCharSingleByte;\n        \n        if (dbcsCode < 0x100) {\n            newBuf[j++] = dbcsCode;\n        }\n        else if (dbcsCode < 0x10000) {\n            newBuf[j++] = dbcsCode >> 8;   // high byte\n            newBuf[j++] = dbcsCode & 0xFF; // low byte\n        }\n        else {\n            newBuf[j++] = dbcsCode >> 16;\n            newBuf[j++] = (dbcsCode >> 8) & 0xFF;\n            newBuf[j++] = dbcsCode & 0xFF;\n        }\n    }\n\n    this.seqObj = seqObj;\n    this.leadSurrogate = leadSurrogate;\n    return newBuf.slice(0, j);\n}\n\nDBCSEncoder.prototype.end = function() {\n    if (this.leadSurrogate === -1 && this.seqObj === undefined)\n        return; // All clean. Most often case.\n\n    var newBuf = new Buffer(10), j = 0;\n\n    if (this.seqObj) { // We're in the sequence.\n        var dbcsCode = this.seqObj[DEF_CHAR];\n        if (dbcsCode !== undefined) { // Write beginning of the sequence.\n            if (dbcsCode < 0x100) {\n                newBuf[j++] = dbcsCode;\n            }\n            else {\n                newBuf[j++] = dbcsCode >> 8;   // high byte\n                newBuf[j++] = dbcsCode & 0xFF; // low byte\n            }\n        } else {\n            // See todo above.\n        }\n        this.seqObj = undefined;\n    }\n\n    if (this.leadSurrogate !== -1) {\n        // Incomplete surrogate pair - only lead surrogate found.\n        newBuf[j++] = this.defaultCharSingleByte;\n        this.leadSurrogate = -1;\n    }\n    \n    return newBuf.slice(0, j);\n}\n\n// Export for testing\nDBCSEncoder.prototype.findIdx = findIdx;\n\n\n// == Decoder ==================================================================\n\nfunction DBCSDecoder(options, codec) {\n    // Decoder state\n    this.nodeIdx = 0;\n    this.prevBuf = new Buffer(0);\n\n    // Static data\n    this.decodeTables = codec.decodeTables;\n    this.decodeTableSeq = codec.decodeTableSeq;\n    this.defaultCharUnicode = codec.defaultCharUnicode;\n    this.gb18030 = codec.gb18030;\n}\n\nDBCSDecoder.prototype.write = function(buf) {\n    var newBuf = new Buffer(buf.length*2),\n        nodeIdx = this.nodeIdx, \n        prevBuf = this.prevBuf, prevBufOffset = this.prevBuf.length,\n        seqStart = -this.prevBuf.length, // idx of the start of current parsed sequence.\n        uCode;\n\n    if (prevBufOffset > 0) // Make prev buf overlap a little to make it easier to slice later.\n        prevBuf = Buffer.concat([prevBuf, buf.slice(0, 10)]);\n    \n    for (var i = 0, j = 0; i < buf.length; i++) {\n        var curByte = (i >= 0) ? buf[i] : prevBuf[i + prevBufOffset];\n\n        // Lookup in current trie node.\n        var uCode = this.decodeTables[nodeIdx][curByte];\n\n        if (uCode >= 0) { \n            // Normal character, just use it.\n        }\n        else if (uCode === UNASSIGNED) { // Unknown char.\n            // TODO: Callback with seq.\n            //var curSeq = (seqStart >= 0) ? buf.slice(seqStart, i+1) : prevBuf.slice(seqStart + prevBufOffset, i+1 + prevBufOffset);\n            i = seqStart; // Try to parse again, after skipping first byte of the sequence ('i' will be incremented by 'for' cycle).\n            uCode = this.defaultCharUnicode.charCodeAt(0);\n        }\n        else if (uCode === GB18030_CODE) {\n            var curSeq = (seqStart >= 0) ? buf.slice(seqStart, i+1) : prevBuf.slice(seqStart + prevBufOffset, i+1 + prevBufOffset);\n            var ptr = (curSeq[0]-0x81)*12600 + (curSeq[1]-0x30)*1260 + (curSeq[2]-0x81)*10 + (curSeq[3]-0x30);\n            var idx = findIdx(this.gb18030.gbChars, ptr);\n            uCode = this.gb18030.uChars[idx] + ptr - this.gb18030.gbChars[idx];\n        }\n        else if (uCode <= NODE_START) { // Go to next trie node.\n            nodeIdx = NODE_START - uCode;\n            continue;\n        }\n        else if (uCode <= SEQ_START) { // Output a sequence of chars.\n            var seq = this.decodeTableSeq[SEQ_START - uCode];\n            for (var k = 0; k < seq.length - 1; k++) {\n                uCode = seq[k];\n                newBuf[j++] = uCode & 0xFF;\n                newBuf[j++] = uCode >> 8;\n            }\n            uCode = seq[seq.length-1];\n        }\n        else\n            throw new Error(\"iconv-lite internal error: invalid decoding table value \" + uCode + \" at \" + nodeIdx + \"/\" + curByte);\n\n        // Write the character to buffer, handling higher planes using surrogate pair.\n        if (uCode > 0xFFFF) { \n            uCode -= 0x10000;\n            var uCodeLead = 0xD800 + Math.floor(uCode / 0x400);\n            newBuf[j++] = uCodeLead & 0xFF;\n            newBuf[j++] = uCodeLead >> 8;\n\n            uCode = 0xDC00 + uCode % 0x400;\n        }\n        newBuf[j++] = uCode & 0xFF;\n        newBuf[j++] = uCode >> 8;\n\n        // Reset trie node.\n        nodeIdx = 0; seqStart = i+1;\n    }\n\n    this.nodeIdx = nodeIdx;\n    this.prevBuf = (seqStart >= 0) ? buf.slice(seqStart) : prevBuf.slice(seqStart + prevBufOffset);\n    return newBuf.slice(0, j).toString('ucs2');\n}\n\nDBCSDecoder.prototype.end = function() {\n    var ret = '';\n\n    // Try to parse all remaining chars.\n    while (this.prevBuf.length > 0) {\n        // Skip 1 character in the buffer.\n        ret += this.defaultCharUnicode;\n        var buf = this.prevBuf.slice(1);\n\n        // Parse remaining as usual.\n        this.prevBuf = new Buffer(0);\n        this.nodeIdx = 0;\n        if (buf.length > 0)\n            ret += this.write(buf);\n    }\n\n    this.nodeIdx = 0;\n    return ret;\n}\n\n// Binary search for GB18030. Returns largest i such that table[i] <= val.\nfunction findIdx(table, val) {\n    if (table[0] > val)\n        return -1;\n\n    var l = 0, r = table.length;\n    while (l < r-1) { // always table[l] <= val < table[r]\n        var mid = l + Math.floor((r-l+1)/2);\n        if (table[mid] <= val)\n            l = mid;\n        else\n            r = mid;\n    }\n    return l;\n}\n\n\n\n/***/ }),\n/* 179 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\n// Description of supported double byte encodings and aliases.\n// Tables are not require()-d until they are needed to speed up library load.\n// require()-s are direct to support Browserify.\n\nmodule.exports = {\n    \n    // == Japanese/ShiftJIS ====================================================\n    // All japanese encodings are based on JIS X set of standards:\n    // JIS X 0201 - Single-byte encoding of ASCII + ¥ + Kana chars at 0xA1-0xDF.\n    // JIS X 0208 - Main set of 6879 characters, placed in 94x94 plane, to be encoded by 2 bytes. \n    //              Has several variations in 1978, 1983, 1990 and 1997.\n    // JIS X 0212 - Supplementary plane of 6067 chars in 94x94 plane. 1990. Effectively dead.\n    // JIS X 0213 - Extension and modern replacement of 0208 and 0212. Total chars: 11233.\n    //              2 planes, first is superset of 0208, second - revised 0212.\n    //              Introduced in 2000, revised 2004. Some characters are in Unicode Plane 2 (0x2xxxx)\n\n    // Byte encodings are:\n    //  * Shift_JIS: Compatible with 0201, uses not defined chars in top half as lead bytes for double-byte\n    //               encoding of 0208. Lead byte ranges: 0x81-0x9F, 0xE0-0xEF; Trail byte ranges: 0x40-0x7E, 0x80-0x9E, 0x9F-0xFC.\n    //               Windows CP932 is a superset of Shift_JIS. Some companies added more chars, notably KDDI.\n    //  * EUC-JP:    Up to 3 bytes per character. Used mostly on *nixes.\n    //               0x00-0x7F       - lower part of 0201\n    //               0x8E, 0xA1-0xDF - upper part of 0201\n    //               (0xA1-0xFE)x2   - 0208 plane (94x94).\n    //               0x8F, (0xA1-0xFE)x2 - 0212 plane (94x94).\n    //  * JIS X 208: 7-bit, direct encoding of 0208. Byte ranges: 0x21-0x7E (94 values). Uncommon.\n    //               Used as-is in ISO2022 family.\n    //  * ISO2022-JP: Stateful encoding, with escape sequences to switch between ASCII, \n    //                0201-1976 Roman, 0208-1978, 0208-1983.\n    //  * ISO2022-JP-1: Adds esc seq for 0212-1990.\n    //  * ISO2022-JP-2: Adds esc seq for GB2313-1980, KSX1001-1992, ISO8859-1, ISO8859-7.\n    //  * ISO2022-JP-3: Adds esc seq for 0201-1976 Kana set, 0213-2000 Planes 1, 2.\n    //  * ISO2022-JP-2004: Adds 0213-2004 Plane 1.\n    //\n    // After JIS X 0213 appeared, Shift_JIS-2004, EUC-JISX0213 and ISO2022-JP-2004 followed, with just changing the planes.\n    //\n    // Overall, it seems that it's a mess :( http://www8.plala.or.jp/tkubota1/unicode-symbols-map2.html\n\n    'shiftjis': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(180) },\n        encodeAdd: {'\\u00a5': 0x5C, '\\u203E': 0x7E},\n        encodeSkipVals: [{from: 0xED40, to: 0xF940}],\n    },\n    'csshiftjis': 'shiftjis',\n    'mskanji': 'shiftjis',\n    'sjis': 'shiftjis',\n    'windows31j': 'shiftjis',\n    'ms31j': 'shiftjis',\n    'xsjis': 'shiftjis',\n    'windows932': 'shiftjis',\n    'ms932': 'shiftjis',\n    '932': 'shiftjis',\n    'cp932': 'shiftjis',\n\n    'eucjp': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(181) },\n        encodeAdd: {'\\u00a5': 0x5C, '\\u203E': 0x7E},\n    },\n\n    // TODO: KDDI extension to Shift_JIS\n    // TODO: IBM CCSID 942 = CP932, but F0-F9 custom chars and other char changes.\n    // TODO: IBM CCSID 943 = Shift_JIS = CP932 with original Shift_JIS lower 128 chars.\n\n\n    // == Chinese/GBK ==========================================================\n    // http://en.wikipedia.org/wiki/GBK\n    // We mostly implement W3C recommendation: https://www.w3.org/TR/encoding/#gbk-encoder\n\n    // Oldest GB2312 (1981, ~7600 chars) is a subset of CP936\n    'gb2312': 'cp936',\n    'gb231280': 'cp936',\n    'gb23121980': 'cp936',\n    'csgb2312': 'cp936',\n    'csiso58gb231280': 'cp936',\n    'euccn': 'cp936',\n\n    // Microsoft's CP936 is a subset and approximation of GBK.\n    'windows936': 'cp936',\n    'ms936': 'cp936',\n    '936': 'cp936',\n    'cp936': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(53) },\n    },\n\n    // GBK (~22000 chars) is an extension of CP936 that added user-mapped chars and some other.\n    'gbk': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(53).concat(__webpack_require__(91)) },\n    },\n    'xgbk': 'gbk',\n    'isoir58': 'gbk',\n\n    // GB18030 is an algorithmic extension of GBK.\n    // Main source: https://www.w3.org/TR/encoding/#gbk-encoder\n    // http://icu-project.org/docs/papers/gb18030.html\n    // http://source.icu-project.org/repos/icu/data/trunk/charset/data/xml/gb-18030-2000.xml\n    // http://www.khngai.com/chinese/charmap/tblgbk.php?page=0\n    'gb18030': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(53).concat(__webpack_require__(91)) },\n        gb18030: function() { return __webpack_require__(182) },\n        encodeSkipVals: [0x80],\n        encodeAdd: {'€': 0xA2E3},\n    },\n\n    'chinese': 'gb18030',\n\n\n    // == Korean ===============================================================\n    // EUC-KR, KS_C_5601 and KS X 1001 are exactly the same.\n    'windows949': 'cp949',\n    'ms949': 'cp949',\n    '949': 'cp949',\n    'cp949': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(183) },\n    },\n\n    'cseuckr': 'cp949',\n    'csksc56011987': 'cp949',\n    'euckr': 'cp949',\n    'isoir149': 'cp949',\n    'korean': 'cp949',\n    'ksc56011987': 'cp949',\n    'ksc56011989': 'cp949',\n    'ksc5601': 'cp949',\n\n\n    // == Big5/Taiwan/Hong Kong ================================================\n    // There are lots of tables for Big5 and cp950. Please see the following links for history:\n    // http://moztw.org/docs/big5/  http://www.haible.de/bruno/charsets/conversion-tables/Big5.html\n    // Variations, in roughly number of defined chars:\n    //  * Windows CP 950: Microsoft variant of Big5. Canonical: http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP950.TXT\n    //  * Windows CP 951: Microsoft variant of Big5-HKSCS-2001. Seems to be never public. http://me.abelcheung.org/articles/research/what-is-cp951/\n    //  * Big5-2003 (Taiwan standard) almost superset of cp950.\n    //  * Unicode-at-on (UAO) / Mozilla 1.8. Falling out of use on the Web. Not supported by other browsers.\n    //  * Big5-HKSCS (-2001, -2004, -2008). Hong Kong standard. \n    //    many unicode code points moved from PUA to Supplementary plane (U+2XXXX) over the years.\n    //    Plus, it has 4 combining sequences.\n    //    Seems that Mozilla refused to support it for 10 yrs. https://bugzilla.mozilla.org/show_bug.cgi?id=162431 https://bugzilla.mozilla.org/show_bug.cgi?id=310299\n    //    because big5-hkscs is the only encoding to include astral characters in non-algorithmic way.\n    //    Implementations are not consistent within browsers; sometimes labeled as just big5.\n    //    MS Internet Explorer switches from big5 to big5-hkscs when a patch applied.\n    //    Great discussion & recap of what's going on https://bugzilla.mozilla.org/show_bug.cgi?id=912470#c31\n    //    In the encoder, it might make sense to support encoding old PUA mappings to Big5 bytes seq-s.\n    //    Official spec: http://www.ogcio.gov.hk/en/business/tech_promotion/ccli/terms/doc/2003cmp_2008.txt\n    //                   http://www.ogcio.gov.hk/tc/business/tech_promotion/ccli/terms/doc/hkscs-2008-big5-iso.txt\n    // \n    // Current understanding of how to deal with Big5(-HKSCS) is in the Encoding Standard, http://encoding.spec.whatwg.org/#big5-encoder\n    // Unicode mapping (http://www.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/OTHER/BIG5.TXT) is said to be wrong.\n\n    'windows950': 'cp950',\n    'ms950': 'cp950',\n    '950': 'cp950',\n    'cp950': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(92) },\n    },\n\n    // Big5 has many variations and is an extension of cp950. We use Encoding Standard's as a consensus.\n    'big5': 'big5hkscs',\n    'big5hkscs': {\n        type: '_dbcs',\n        table: function() { return __webpack_require__(92).concat(__webpack_require__(184)) },\n        encodeSkipVals: [0xa2cc],\n    },\n\n    'cnbig5': 'big5hkscs',\n    'csbig5': 'big5hkscs',\n    'xxbig5': 'big5hkscs',\n};\n\n\n/***/ }),\n/* 180 */\n/***/ (function(module, exports) {\n\nmodule.exports = [[\"0\",\"\\u0000\",128],[\"a1\",\"｡\",62],[\"8140\",\"　、。，．・：；？！゛゜´｀¨＾￣＿ヽヾゝゞ〃仝々〆〇ー―‐／＼～∥｜…‥‘’“”（）〔〕［］｛｝〈\",9,\"＋－±×\"],[\"8180\",\"÷＝≠＜＞≦≧∞∴♂♀°′″℃￥＄￠￡％＃＆＊＠§☆★○●◎◇◆□■△▲▽▼※〒→←↑↓〓\"],[\"81b8\",\"∈∋⊆⊇⊂⊃∪∩\"],[\"81c8\",\"∧∨￢⇒⇔∀∃\"],[\"81da\",\"∠⊥⌒∂∇≡≒≪≫√∽∝∵∫∬\"],[\"81f0\",\"Å‰♯♭♪†‡¶\"],[\"81fc\",\"◯\"],[\"824f\",\"０\",9],[\"8260\",\"Ａ\",25],[\"8281\",\"ａ\",25],[\"829f\",\"ぁ\",82],[\"8340\",\"ァ\",62],[\"8380\",\"ム\",22],[\"839f\",\"Α\",16,\"Σ\",6],[\"83bf\",\"α\",16,\"σ\",6],[\"8440\",\"А\",5,\"ЁЖ\",25],[\"8470\",\"а\",5,\"ёж\",7],[\"8480\",\"о\",17],[\"849f\",\"─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂\"],[\"8740\",\"①\",19,\"Ⅰ\",9],[\"875f\",\"㍉㌔㌢㍍㌘㌧㌃㌶㍑㍗㌍㌦㌣㌫㍊㌻㎜㎝㎞㎎㎏㏄㎡\"],[\"877e\",\"㍻\"],[\"8780\",\"〝〟№㏍℡㊤\",4,\"㈱㈲㈹㍾㍽㍼≒≡∫∮∑√⊥∠∟⊿∵∩∪\"],[\"889f\",\"亜唖娃阿哀愛挨姶逢葵茜穐悪握渥旭葦芦鯵梓圧斡扱宛姐虻飴絢綾鮎或粟袷安庵按暗案闇鞍杏以伊位依偉囲夷委威尉惟意慰易椅為畏異移維緯胃萎衣謂違遺医井亥域育郁磯一壱溢逸稲茨芋鰯允印咽員因姻引飲淫胤蔭\"],[\"8940\",\"院陰隠韻吋右宇烏羽迂雨卯鵜窺丑碓臼渦嘘唄欝蔚鰻姥厩浦瓜閏噂云運雲荏餌叡営嬰影映曳栄永泳洩瑛盈穎頴英衛詠鋭液疫益駅悦謁越閲榎厭円\"],[\"8980\",\"園堰奄宴延怨掩援沿演炎焔煙燕猿縁艶苑薗遠鉛鴛塩於汚甥凹央奥往応押旺横欧殴王翁襖鴬鴎黄岡沖荻億屋憶臆桶牡乙俺卸恩温穏音下化仮何伽価佳加可嘉夏嫁家寡科暇果架歌河火珂禍禾稼箇花苛茄荷華菓蝦課嘩貨迦過霞蚊俄峨我牙画臥芽蛾賀雅餓駕介会解回塊壊廻快怪悔恢懐戒拐改\"],[\"8a40\",\"魁晦械海灰界皆絵芥蟹開階貝凱劾外咳害崖慨概涯碍蓋街該鎧骸浬馨蛙垣柿蛎鈎劃嚇各廓拡撹格核殻獲確穫覚角赫較郭閣隔革学岳楽額顎掛笠樫\"],[\"8a80\",\"橿梶鰍潟割喝恰括活渇滑葛褐轄且鰹叶椛樺鞄株兜竃蒲釜鎌噛鴨栢茅萱粥刈苅瓦乾侃冠寒刊勘勧巻喚堪姦完官寛干幹患感慣憾換敢柑桓棺款歓汗漢澗潅環甘監看竿管簡緩缶翰肝艦莞観諌貫還鑑間閑関陥韓館舘丸含岸巌玩癌眼岩翫贋雁頑顔願企伎危喜器基奇嬉寄岐希幾忌揮机旗既期棋棄\"],[\"8b40\",\"機帰毅気汽畿祈季稀紀徽規記貴起軌輝飢騎鬼亀偽儀妓宜戯技擬欺犠疑祇義蟻誼議掬菊鞠吉吃喫桔橘詰砧杵黍却客脚虐逆丘久仇休及吸宮弓急救\"],[\"8b80\",\"朽求汲泣灸球究窮笈級糾給旧牛去居巨拒拠挙渠虚許距鋸漁禦魚亨享京供侠僑兇競共凶協匡卿叫喬境峡強彊怯恐恭挟教橋況狂狭矯胸脅興蕎郷鏡響饗驚仰凝尭暁業局曲極玉桐粁僅勤均巾錦斤欣欽琴禁禽筋緊芹菌衿襟謹近金吟銀九倶句区狗玖矩苦躯駆駈駒具愚虞喰空偶寓遇隅串櫛釧屑屈\"],[\"8c40\",\"掘窟沓靴轡窪熊隈粂栗繰桑鍬勲君薫訓群軍郡卦袈祁係傾刑兄啓圭珪型契形径恵慶慧憩掲携敬景桂渓畦稽系経継繋罫茎荊蛍計詣警軽頚鶏芸迎鯨\"],[\"8c80\",\"劇戟撃激隙桁傑欠決潔穴結血訣月件倹倦健兼券剣喧圏堅嫌建憲懸拳捲検権牽犬献研硯絹県肩見謙賢軒遣鍵険顕験鹸元原厳幻弦減源玄現絃舷言諺限乎個古呼固姑孤己庫弧戸故枯湖狐糊袴股胡菰虎誇跨鈷雇顧鼓五互伍午呉吾娯後御悟梧檎瑚碁語誤護醐乞鯉交佼侯候倖光公功効勾厚口向\"],[\"8d40\",\"后喉坑垢好孔孝宏工巧巷幸広庚康弘恒慌抗拘控攻昂晃更杭校梗構江洪浩港溝甲皇硬稿糠紅紘絞綱耕考肯肱腔膏航荒行衡講貢購郊酵鉱砿鋼閤降\"],[\"8d80\",\"項香高鴻剛劫号合壕拷濠豪轟麹克刻告国穀酷鵠黒獄漉腰甑忽惚骨狛込此頃今困坤墾婚恨懇昏昆根梱混痕紺艮魂些佐叉唆嵯左差査沙瑳砂詐鎖裟坐座挫債催再最哉塞妻宰彩才採栽歳済災采犀砕砦祭斎細菜裁載際剤在材罪財冴坂阪堺榊肴咲崎埼碕鷺作削咋搾昨朔柵窄策索錯桜鮭笹匙冊刷\"],[\"8e40\",\"察拶撮擦札殺薩雑皐鯖捌錆鮫皿晒三傘参山惨撒散桟燦珊産算纂蚕讃賛酸餐斬暫残仕仔伺使刺司史嗣四士始姉姿子屍市師志思指支孜斯施旨枝止\"],[\"8e80\",\"死氏獅祉私糸紙紫肢脂至視詞詩試誌諮資賜雌飼歯事似侍児字寺慈持時次滋治爾璽痔磁示而耳自蒔辞汐鹿式識鴫竺軸宍雫七叱執失嫉室悉湿漆疾質実蔀篠偲柴芝屡蕊縞舎写射捨赦斜煮社紗者謝車遮蛇邪借勺尺杓灼爵酌釈錫若寂弱惹主取守手朱殊狩珠種腫趣酒首儒受呪寿授樹綬需囚収周\"],[\"8f40\",\"宗就州修愁拾洲秀秋終繍習臭舟蒐衆襲讐蹴輯週酋酬集醜什住充十従戎柔汁渋獣縦重銃叔夙宿淑祝縮粛塾熟出術述俊峻春瞬竣舜駿准循旬楯殉淳\"],[\"8f80\",\"準潤盾純巡遵醇順処初所暑曙渚庶緒署書薯藷諸助叙女序徐恕鋤除傷償勝匠升召哨商唱嘗奨妾娼宵将小少尚庄床廠彰承抄招掌捷昇昌昭晶松梢樟樵沼消渉湘焼焦照症省硝礁祥称章笑粧紹肖菖蒋蕉衝裳訟証詔詳象賞醤鉦鍾鐘障鞘上丈丞乗冗剰城場壌嬢常情擾条杖浄状畳穣蒸譲醸錠嘱埴飾\"],[\"9040\",\"拭植殖燭織職色触食蝕辱尻伸信侵唇娠寝審心慎振新晋森榛浸深申疹真神秦紳臣芯薪親診身辛進針震人仁刃塵壬尋甚尽腎訊迅陣靭笥諏須酢図厨\"],[\"9080\",\"逗吹垂帥推水炊睡粋翠衰遂酔錐錘随瑞髄崇嵩数枢趨雛据杉椙菅頗雀裾澄摺寸世瀬畝是凄制勢姓征性成政整星晴棲栖正清牲生盛精聖声製西誠誓請逝醒青静斉税脆隻席惜戚斥昔析石積籍績脊責赤跡蹟碩切拙接摂折設窃節説雪絶舌蝉仙先千占宣専尖川戦扇撰栓栴泉浅洗染潜煎煽旋穿箭線\"],[\"9140\",\"繊羨腺舛船薦詮賎践選遷銭銑閃鮮前善漸然全禅繕膳糎噌塑岨措曾曽楚狙疏疎礎祖租粗素組蘇訴阻遡鼠僧創双叢倉喪壮奏爽宋層匝惣想捜掃挿掻\"],[\"9180\",\"操早曹巣槍槽漕燥争痩相窓糟総綜聡草荘葬蒼藻装走送遭鎗霜騒像増憎臓蔵贈造促側則即息捉束測足速俗属賊族続卒袖其揃存孫尊損村遜他多太汰詑唾堕妥惰打柁舵楕陀駄騨体堆対耐岱帯待怠態戴替泰滞胎腿苔袋貸退逮隊黛鯛代台大第醍題鷹滝瀧卓啄宅托択拓沢濯琢託鐸濁諾茸凧蛸只\"],[\"9240\",\"叩但達辰奪脱巽竪辿棚谷狸鱈樽誰丹単嘆坦担探旦歎淡湛炭短端箪綻耽胆蛋誕鍛団壇弾断暖檀段男談値知地弛恥智池痴稚置致蜘遅馳築畜竹筑蓄\"],[\"9280\",\"逐秩窒茶嫡着中仲宙忠抽昼柱注虫衷註酎鋳駐樗瀦猪苧著貯丁兆凋喋寵帖帳庁弔張彫徴懲挑暢朝潮牒町眺聴脹腸蝶調諜超跳銚長頂鳥勅捗直朕沈珍賃鎮陳津墜椎槌追鎚痛通塚栂掴槻佃漬柘辻蔦綴鍔椿潰坪壷嬬紬爪吊釣鶴亭低停偵剃貞呈堤定帝底庭廷弟悌抵挺提梯汀碇禎程締艇訂諦蹄逓\"],[\"9340\",\"邸鄭釘鼎泥摘擢敵滴的笛適鏑溺哲徹撤轍迭鉄典填天展店添纏甜貼転顛点伝殿澱田電兎吐堵塗妬屠徒斗杜渡登菟賭途都鍍砥砺努度土奴怒倒党冬\"],[\"9380\",\"凍刀唐塔塘套宕島嶋悼投搭東桃梼棟盗淘湯涛灯燈当痘祷等答筒糖統到董蕩藤討謄豆踏逃透鐙陶頭騰闘働動同堂導憧撞洞瞳童胴萄道銅峠鴇匿得徳涜特督禿篤毒独読栃橡凸突椴届鳶苫寅酉瀞噸屯惇敦沌豚遁頓呑曇鈍奈那内乍凪薙謎灘捺鍋楢馴縄畷南楠軟難汝二尼弐迩匂賑肉虹廿日乳入\"],[\"9440\",\"如尿韮任妊忍認濡禰祢寧葱猫熱年念捻撚燃粘乃廼之埜嚢悩濃納能脳膿農覗蚤巴把播覇杷波派琶破婆罵芭馬俳廃拝排敗杯盃牌背肺輩配倍培媒梅\"],[\"9480\",\"楳煤狽買売賠陪這蝿秤矧萩伯剥博拍柏泊白箔粕舶薄迫曝漠爆縛莫駁麦函箱硲箸肇筈櫨幡肌畑畠八鉢溌発醗髪伐罰抜筏閥鳩噺塙蛤隼伴判半反叛帆搬斑板氾汎版犯班畔繁般藩販範釆煩頒飯挽晩番盤磐蕃蛮匪卑否妃庇彼悲扉批披斐比泌疲皮碑秘緋罷肥被誹費避非飛樋簸備尾微枇毘琵眉美\"],[\"9540\",\"鼻柊稗匹疋髭彦膝菱肘弼必畢筆逼桧姫媛紐百謬俵彪標氷漂瓢票表評豹廟描病秒苗錨鋲蒜蛭鰭品彬斌浜瀕貧賓頻敏瓶不付埠夫婦富冨布府怖扶敷\"],[\"9580\",\"斧普浮父符腐膚芙譜負賦赴阜附侮撫武舞葡蕪部封楓風葺蕗伏副復幅服福腹複覆淵弗払沸仏物鮒分吻噴墳憤扮焚奮粉糞紛雰文聞丙併兵塀幣平弊柄並蔽閉陛米頁僻壁癖碧別瞥蔑箆偏変片篇編辺返遍便勉娩弁鞭保舗鋪圃捕歩甫補輔穂募墓慕戊暮母簿菩倣俸包呆報奉宝峰峯崩庖抱捧放方朋\"],[\"9640\",\"法泡烹砲縫胞芳萌蓬蜂褒訪豊邦鋒飽鳳鵬乏亡傍剖坊妨帽忘忙房暴望某棒冒紡肪膨謀貌貿鉾防吠頬北僕卜墨撲朴牧睦穆釦勃没殆堀幌奔本翻凡盆\"],[\"9680\",\"摩磨魔麻埋妹昧枚毎哩槙幕膜枕鮪柾鱒桝亦俣又抹末沫迄侭繭麿万慢満漫蔓味未魅巳箕岬密蜜湊蓑稔脈妙粍民眠務夢無牟矛霧鵡椋婿娘冥名命明盟迷銘鳴姪牝滅免棉綿緬面麺摸模茂妄孟毛猛盲網耗蒙儲木黙目杢勿餅尤戻籾貰問悶紋門匁也冶夜爺耶野弥矢厄役約薬訳躍靖柳薮鑓愉愈油癒\"],[\"9740\",\"諭輸唯佑優勇友宥幽悠憂揖有柚湧涌猶猷由祐裕誘遊邑郵雄融夕予余与誉輿預傭幼妖容庸揚揺擁曜楊様洋溶熔用窯羊耀葉蓉要謡踊遥陽養慾抑欲\"],[\"9780\",\"沃浴翌翼淀羅螺裸来莱頼雷洛絡落酪乱卵嵐欄濫藍蘭覧利吏履李梨理璃痢裏裡里離陸律率立葎掠略劉流溜琉留硫粒隆竜龍侶慮旅虜了亮僚両凌寮料梁涼猟療瞭稜糧良諒遼量陵領力緑倫厘林淋燐琳臨輪隣鱗麟瑠塁涙累類令伶例冷励嶺怜玲礼苓鈴隷零霊麗齢暦歴列劣烈裂廉恋憐漣煉簾練聯\"],[\"9840\",\"蓮連錬呂魯櫓炉賂路露労婁廊弄朗楼榔浪漏牢狼篭老聾蝋郎六麓禄肋録論倭和話歪賄脇惑枠鷲亙亘鰐詫藁蕨椀湾碗腕\"],[\"989f\",\"弌丐丕个丱丶丼丿乂乖乘亂亅豫亊舒弍于亞亟亠亢亰亳亶从仍仄仆仂仗仞仭仟价伉佚估佛佝佗佇佶侈侏侘佻佩佰侑佯來侖儘俔俟俎俘俛俑俚俐俤俥倚倨倔倪倥倅伜俶倡倩倬俾俯們倆偃假會偕偐偈做偖偬偸傀傚傅傴傲\"],[\"9940\",\"僉僊傳僂僖僞僥僭僣僮價僵儉儁儂儖儕儔儚儡儺儷儼儻儿兀兒兌兔兢竸兩兪兮冀冂囘册冉冏冑冓冕冖冤冦冢冩冪冫决冱冲冰况冽凅凉凛几處凩凭\"],[\"9980\",\"凰凵凾刄刋刔刎刧刪刮刳刹剏剄剋剌剞剔剪剴剩剳剿剽劍劔劒剱劈劑辨辧劬劭劼劵勁勍勗勞勣勦飭勠勳勵勸勹匆匈甸匍匐匏匕匚匣匯匱匳匸區卆卅丗卉卍凖卞卩卮夘卻卷厂厖厠厦厥厮厰厶參簒雙叟曼燮叮叨叭叺吁吽呀听吭吼吮吶吩吝呎咏呵咎呟呱呷呰咒呻咀呶咄咐咆哇咢咸咥咬哄哈咨\"],[\"9a40\",\"咫哂咤咾咼哘哥哦唏唔哽哮哭哺哢唹啀啣啌售啜啅啖啗唸唳啝喙喀咯喊喟啻啾喘喞單啼喃喩喇喨嗚嗅嗟嗄嗜嗤嗔嘔嗷嘖嗾嗽嘛嗹噎噐營嘴嘶嘲嘸\"],[\"9a80\",\"噫噤嘯噬噪嚆嚀嚊嚠嚔嚏嚥嚮嚶嚴囂嚼囁囃囀囈囎囑囓囗囮囹圀囿圄圉圈國圍圓團圖嗇圜圦圷圸坎圻址坏坩埀垈坡坿垉垓垠垳垤垪垰埃埆埔埒埓堊埖埣堋堙堝塲堡塢塋塰毀塒堽塹墅墹墟墫墺壞墻墸墮壅壓壑壗壙壘壥壜壤壟壯壺壹壻壼壽夂夊夐夛梦夥夬夭夲夸夾竒奕奐奎奚奘奢奠奧奬奩\"],[\"9b40\",\"奸妁妝佞侫妣妲姆姨姜妍姙姚娥娟娑娜娉娚婀婬婉娵娶婢婪媚媼媾嫋嫂媽嫣嫗嫦嫩嫖嫺嫻嬌嬋嬖嬲嫐嬪嬶嬾孃孅孀孑孕孚孛孥孩孰孳孵學斈孺宀\"],[\"9b80\",\"它宦宸寃寇寉寔寐寤實寢寞寥寫寰寶寳尅將專對尓尠尢尨尸尹屁屆屎屓屐屏孱屬屮乢屶屹岌岑岔妛岫岻岶岼岷峅岾峇峙峩峽峺峭嶌峪崋崕崗嵜崟崛崑崔崢崚崙崘嵌嵒嵎嵋嵬嵳嵶嶇嶄嶂嶢嶝嶬嶮嶽嶐嶷嶼巉巍巓巒巖巛巫已巵帋帚帙帑帛帶帷幄幃幀幎幗幔幟幢幤幇幵并幺麼广庠廁廂廈廐廏\"],[\"9c40\",\"廖廣廝廚廛廢廡廨廩廬廱廳廰廴廸廾弃弉彝彜弋弑弖弩弭弸彁彈彌彎弯彑彖彗彙彡彭彳彷徃徂彿徊很徑徇從徙徘徠徨徭徼忖忻忤忸忱忝悳忿怡恠\"],[\"9c80\",\"怙怐怩怎怱怛怕怫怦怏怺恚恁恪恷恟恊恆恍恣恃恤恂恬恫恙悁悍惧悃悚悄悛悖悗悒悧悋惡悸惠惓悴忰悽惆悵惘慍愕愆惶惷愀惴惺愃愡惻惱愍愎慇愾愨愧慊愿愼愬愴愽慂慄慳慷慘慙慚慫慴慯慥慱慟慝慓慵憙憖憇憬憔憚憊憑憫憮懌懊應懷懈懃懆憺懋罹懍懦懣懶懺懴懿懽懼懾戀戈戉戍戌戔戛\"],[\"9d40\",\"戞戡截戮戰戲戳扁扎扞扣扛扠扨扼抂抉找抒抓抖拔抃抔拗拑抻拏拿拆擔拈拜拌拊拂拇抛拉挌拮拱挧挂挈拯拵捐挾捍搜捏掖掎掀掫捶掣掏掉掟掵捫\"],[\"9d80\",\"捩掾揩揀揆揣揉插揶揄搖搴搆搓搦搶攝搗搨搏摧摯摶摎攪撕撓撥撩撈撼據擒擅擇撻擘擂擱擧舉擠擡抬擣擯攬擶擴擲擺攀擽攘攜攅攤攣攫攴攵攷收攸畋效敖敕敍敘敞敝敲數斂斃變斛斟斫斷旃旆旁旄旌旒旛旙无旡旱杲昊昃旻杳昵昶昴昜晏晄晉晁晞晝晤晧晨晟晢晰暃暈暎暉暄暘暝曁暹曉暾暼\"],[\"9e40\",\"曄暸曖曚曠昿曦曩曰曵曷朏朖朞朦朧霸朮朿朶杁朸朷杆杞杠杙杣杤枉杰枩杼杪枌枋枦枡枅枷柯枴柬枳柩枸柤柞柝柢柮枹柎柆柧檜栞框栩桀桍栲桎\"],[\"9e80\",\"梳栫桙档桷桿梟梏梭梔條梛梃檮梹桴梵梠梺椏梍桾椁棊椈棘椢椦棡椌棍棔棧棕椶椒椄棗棣椥棹棠棯椨椪椚椣椡棆楹楷楜楸楫楔楾楮椹楴椽楙椰楡楞楝榁楪榲榮槐榿槁槓榾槎寨槊槝榻槃榧樮榑榠榜榕榴槞槨樂樛槿權槹槲槧樅榱樞槭樔槫樊樒櫁樣樓橄樌橲樶橸橇橢橙橦橈樸樢檐檍檠檄檢檣\"],[\"9f40\",\"檗蘗檻櫃櫂檸檳檬櫞櫑櫟檪櫚櫪櫻欅蘖櫺欒欖鬱欟欸欷盜欹飮歇歃歉歐歙歔歛歟歡歸歹歿殀殄殃殍殘殕殞殤殪殫殯殲殱殳殷殼毆毋毓毟毬毫毳毯\"],[\"9f80\",\"麾氈氓气氛氤氣汞汕汢汪沂沍沚沁沛汾汨汳沒沐泄泱泓沽泗泅泝沮沱沾沺泛泯泙泪洟衍洶洫洽洸洙洵洳洒洌浣涓浤浚浹浙涎涕濤涅淹渕渊涵淇淦涸淆淬淞淌淨淒淅淺淙淤淕淪淮渭湮渮渙湲湟渾渣湫渫湶湍渟湃渺湎渤滿渝游溂溪溘滉溷滓溽溯滄溲滔滕溏溥滂溟潁漑灌滬滸滾漿滲漱滯漲滌\"],[\"e040\",\"漾漓滷澆潺潸澁澀潯潛濳潭澂潼潘澎澑濂潦澳澣澡澤澹濆澪濟濕濬濔濘濱濮濛瀉瀋濺瀑瀁瀏濾瀛瀚潴瀝瀘瀟瀰瀾瀲灑灣炙炒炯烱炬炸炳炮烟烋烝\"],[\"e080\",\"烙焉烽焜焙煥煕熈煦煢煌煖煬熏燻熄熕熨熬燗熹熾燒燉燔燎燠燬燧燵燼燹燿爍爐爛爨爭爬爰爲爻爼爿牀牆牋牘牴牾犂犁犇犒犖犢犧犹犲狃狆狄狎狒狢狠狡狹狷倏猗猊猜猖猝猴猯猩猥猾獎獏默獗獪獨獰獸獵獻獺珈玳珎玻珀珥珮珞璢琅瑯琥珸琲琺瑕琿瑟瑙瑁瑜瑩瑰瑣瑪瑶瑾璋璞璧瓊瓏瓔珱\"],[\"e140\",\"瓠瓣瓧瓩瓮瓲瓰瓱瓸瓷甄甃甅甌甎甍甕甓甞甦甬甼畄畍畊畉畛畆畚畩畤畧畫畭畸當疆疇畴疊疉疂疔疚疝疥疣痂疳痃疵疽疸疼疱痍痊痒痙痣痞痾痿\"],[\"e180\",\"痼瘁痰痺痲痳瘋瘍瘉瘟瘧瘠瘡瘢瘤瘴瘰瘻癇癈癆癜癘癡癢癨癩癪癧癬癰癲癶癸發皀皃皈皋皎皖皓皙皚皰皴皸皹皺盂盍盖盒盞盡盥盧盪蘯盻眈眇眄眩眤眞眥眦眛眷眸睇睚睨睫睛睥睿睾睹瞎瞋瞑瞠瞞瞰瞶瞹瞿瞼瞽瞻矇矍矗矚矜矣矮矼砌砒礦砠礪硅碎硴碆硼碚碌碣碵碪碯磑磆磋磔碾碼磅磊磬\"],[\"e240\",\"磧磚磽磴礇礒礑礙礬礫祀祠祗祟祚祕祓祺祿禊禝禧齋禪禮禳禹禺秉秕秧秬秡秣稈稍稘稙稠稟禀稱稻稾稷穃穗穉穡穢穩龝穰穹穽窈窗窕窘窖窩竈窰\"],[\"e280\",\"窶竅竄窿邃竇竊竍竏竕竓站竚竝竡竢竦竭竰笂笏笊笆笳笘笙笞笵笨笶筐筺笄筍笋筌筅筵筥筴筧筰筱筬筮箝箘箟箍箜箚箋箒箏筝箙篋篁篌篏箴篆篝篩簑簔篦篥籠簀簇簓篳篷簗簍篶簣簧簪簟簷簫簽籌籃籔籏籀籐籘籟籤籖籥籬籵粃粐粤粭粢粫粡粨粳粲粱粮粹粽糀糅糂糘糒糜糢鬻糯糲糴糶糺紆\"],[\"e340\",\"紂紜紕紊絅絋紮紲紿紵絆絳絖絎絲絨絮絏絣經綉絛綏絽綛綺綮綣綵緇綽綫總綢綯緜綸綟綰緘緝緤緞緻緲緡縅縊縣縡縒縱縟縉縋縢繆繦縻縵縹繃縷\"],[\"e380\",\"縲縺繧繝繖繞繙繚繹繪繩繼繻纃緕繽辮繿纈纉續纒纐纓纔纖纎纛纜缸缺罅罌罍罎罐网罕罔罘罟罠罨罩罧罸羂羆羃羈羇羌羔羞羝羚羣羯羲羹羮羶羸譱翅翆翊翕翔翡翦翩翳翹飜耆耄耋耒耘耙耜耡耨耿耻聊聆聒聘聚聟聢聨聳聲聰聶聹聽聿肄肆肅肛肓肚肭冐肬胛胥胙胝胄胚胖脉胯胱脛脩脣脯腋\"],[\"e440\",\"隋腆脾腓腑胼腱腮腥腦腴膃膈膊膀膂膠膕膤膣腟膓膩膰膵膾膸膽臀臂膺臉臍臑臙臘臈臚臟臠臧臺臻臾舁舂舅與舊舍舐舖舩舫舸舳艀艙艘艝艚艟艤\"],[\"e480\",\"艢艨艪艫舮艱艷艸艾芍芒芫芟芻芬苡苣苟苒苴苳苺莓范苻苹苞茆苜茉苙茵茴茖茲茱荀茹荐荅茯茫茗茘莅莚莪莟莢莖茣莎莇莊荼莵荳荵莠莉莨菴萓菫菎菽萃菘萋菁菷萇菠菲萍萢萠莽萸蔆菻葭萪萼蕚蒄葷葫蒭葮蒂葩葆萬葯葹萵蓊葢蒹蒿蒟蓙蓍蒻蓚蓐蓁蓆蓖蒡蔡蓿蓴蔗蔘蔬蔟蔕蔔蓼蕀蕣蕘蕈\"],[\"e540\",\"蕁蘂蕋蕕薀薤薈薑薊薨蕭薔薛藪薇薜蕷蕾薐藉薺藏薹藐藕藝藥藜藹蘊蘓蘋藾藺蘆蘢蘚蘰蘿虍乕虔號虧虱蚓蚣蚩蚪蚋蚌蚶蚯蛄蛆蚰蛉蠣蚫蛔蛞蛩蛬\"],[\"e580\",\"蛟蛛蛯蜒蜆蜈蜀蜃蛻蜑蜉蜍蛹蜊蜴蜿蜷蜻蜥蜩蜚蝠蝟蝸蝌蝎蝴蝗蝨蝮蝙蝓蝣蝪蠅螢螟螂螯蟋螽蟀蟐雖螫蟄螳蟇蟆螻蟯蟲蟠蠏蠍蟾蟶蟷蠎蟒蠑蠖蠕蠢蠡蠱蠶蠹蠧蠻衄衂衒衙衞衢衫袁衾袞衵衽袵衲袂袗袒袮袙袢袍袤袰袿袱裃裄裔裘裙裝裹褂裼裴裨裲褄褌褊褓襃褞褥褪褫襁襄褻褶褸襌褝襠襞\"],[\"e640\",\"襦襤襭襪襯襴襷襾覃覈覊覓覘覡覩覦覬覯覲覺覽覿觀觚觜觝觧觴觸訃訖訐訌訛訝訥訶詁詛詒詆詈詼詭詬詢誅誂誄誨誡誑誥誦誚誣諄諍諂諚諫諳諧\"],[\"e680\",\"諤諱謔諠諢諷諞諛謌謇謚諡謖謐謗謠謳鞫謦謫謾謨譁譌譏譎證譖譛譚譫譟譬譯譴譽讀讌讎讒讓讖讙讚谺豁谿豈豌豎豐豕豢豬豸豺貂貉貅貊貍貎貔豼貘戝貭貪貽貲貳貮貶賈賁賤賣賚賽賺賻贄贅贊贇贏贍贐齎贓賍贔贖赧赭赱赳趁趙跂趾趺跏跚跖跌跛跋跪跫跟跣跼踈踉跿踝踞踐踟蹂踵踰踴蹊\"],[\"e740\",\"蹇蹉蹌蹐蹈蹙蹤蹠踪蹣蹕蹶蹲蹼躁躇躅躄躋躊躓躑躔躙躪躡躬躰軆躱躾軅軈軋軛軣軼軻軫軾輊輅輕輒輙輓輜輟輛輌輦輳輻輹轅轂輾轌轉轆轎轗轜\"],[\"e780\",\"轢轣轤辜辟辣辭辯辷迚迥迢迪迯邇迴逅迹迺逑逕逡逍逞逖逋逧逶逵逹迸遏遐遑遒逎遉逾遖遘遞遨遯遶隨遲邂遽邁邀邊邉邏邨邯邱邵郢郤扈郛鄂鄒鄙鄲鄰酊酖酘酣酥酩酳酲醋醉醂醢醫醯醪醵醴醺釀釁釉釋釐釖釟釡釛釼釵釶鈞釿鈔鈬鈕鈑鉞鉗鉅鉉鉤鉈銕鈿鉋鉐銜銖銓銛鉚鋏銹銷鋩錏鋺鍄錮\"],[\"e840\",\"錙錢錚錣錺錵錻鍜鍠鍼鍮鍖鎰鎬鎭鎔鎹鏖鏗鏨鏥鏘鏃鏝鏐鏈鏤鐚鐔鐓鐃鐇鐐鐶鐫鐵鐡鐺鑁鑒鑄鑛鑠鑢鑞鑪鈩鑰鑵鑷鑽鑚鑼鑾钁鑿閂閇閊閔閖閘閙\"],[\"e880\",\"閠閨閧閭閼閻閹閾闊濶闃闍闌闕闔闖關闡闥闢阡阨阮阯陂陌陏陋陷陜陞陝陟陦陲陬隍隘隕隗險隧隱隲隰隴隶隸隹雎雋雉雍襍雜霍雕雹霄霆霈霓霎霑霏霖霙霤霪霰霹霽霾靄靆靈靂靉靜靠靤靦靨勒靫靱靹鞅靼鞁靺鞆鞋鞏鞐鞜鞨鞦鞣鞳鞴韃韆韈韋韜韭齏韲竟韶韵頏頌頸頤頡頷頽顆顏顋顫顯顰\"],[\"e940\",\"顱顴顳颪颯颱颶飄飃飆飩飫餃餉餒餔餘餡餝餞餤餠餬餮餽餾饂饉饅饐饋饑饒饌饕馗馘馥馭馮馼駟駛駝駘駑駭駮駱駲駻駸騁騏騅駢騙騫騷驅驂驀驃\"],[\"e980\",\"騾驕驍驛驗驟驢驥驤驩驫驪骭骰骼髀髏髑髓體髞髟髢髣髦髯髫髮髴髱髷髻鬆鬘鬚鬟鬢鬣鬥鬧鬨鬩鬪鬮鬯鬲魄魃魏魍魎魑魘魴鮓鮃鮑鮖鮗鮟鮠鮨鮴鯀鯊鮹鯆鯏鯑鯒鯣鯢鯤鯔鯡鰺鯲鯱鯰鰕鰔鰉鰓鰌鰆鰈鰒鰊鰄鰮鰛鰥鰤鰡鰰鱇鰲鱆鰾鱚鱠鱧鱶鱸鳧鳬鳰鴉鴈鳫鴃鴆鴪鴦鶯鴣鴟鵄鴕鴒鵁鴿鴾鵆鵈\"],[\"ea40\",\"鵝鵞鵤鵑鵐鵙鵲鶉鶇鶫鵯鵺鶚鶤鶩鶲鷄鷁鶻鶸鶺鷆鷏鷂鷙鷓鷸鷦鷭鷯鷽鸚鸛鸞鹵鹹鹽麁麈麋麌麒麕麑麝麥麩麸麪麭靡黌黎黏黐黔黜點黝黠黥黨黯\"],[\"ea80\",\"黴黶黷黹黻黼黽鼇鼈皷鼕鼡鼬鼾齊齒齔齣齟齠齡齦齧齬齪齷齲齶龕龜龠堯槇遙瑤凜熙\"],[\"ed40\",\"纊褜鍈銈蓜俉炻昱棈鋹曻彅丨仡仼伀伃伹佖侒侊侚侔俍偀倢俿倞偆偰偂傔僴僘兊兤冝冾凬刕劜劦勀勛匀匇匤卲厓厲叝﨎咜咊咩哿喆坙坥垬埈埇﨏\"],[\"ed80\",\"塚增墲夋奓奛奝奣妤妺孖寀甯寘寬尞岦岺峵崧嵓﨑嵂嵭嶸嶹巐弡弴彧德忞恝悅悊惞惕愠惲愑愷愰憘戓抦揵摠撝擎敎昀昕昻昉昮昞昤晥晗晙晴晳暙暠暲暿曺朎朗杦枻桒柀栁桄棏﨓楨﨔榘槢樰橫橆橳橾櫢櫤毖氿汜沆汯泚洄涇浯涖涬淏淸淲淼渹湜渧渼溿澈澵濵瀅瀇瀨炅炫焏焄煜煆煇凞燁燾犱\"],[\"ee40\",\"犾猤猪獷玽珉珖珣珒琇珵琦琪琩琮瑢璉璟甁畯皂皜皞皛皦益睆劯砡硎硤硺礰礼神祥禔福禛竑竧靖竫箞精絈絜綷綠緖繒罇羡羽茁荢荿菇菶葈蒴蕓蕙\"],[\"ee80\",\"蕫﨟薰蘒﨡蠇裵訒訷詹誧誾諟諸諶譓譿賰賴贒赶﨣軏﨤逸遧郞都鄕鄧釚釗釞釭釮釤釥鈆鈐鈊鈺鉀鈼鉎鉙鉑鈹鉧銧鉷鉸鋧鋗鋙鋐﨧鋕鋠鋓錥錡鋻﨨錞鋿錝錂鍰鍗鎤鏆鏞鏸鐱鑅鑈閒隆﨩隝隯霳霻靃靍靏靑靕顗顥飯飼餧館馞驎髙髜魵魲鮏鮱鮻鰀鵰鵫鶴鸙黑\"],[\"eeef\",\"ⅰ\",9,\"￢￤＇＂\"],[\"f040\",\"\",62],[\"f080\",\"\",124],[\"f140\",\"\",62],[\"f180\",\"\",124],[\"f240\",\"\",62],[\"f280\",\"\",124],[\"f340\",\"\",62],[\"f380\",\"\",124],[\"f440\",\"\",62],[\"f480\",\"\",124],[\"f540\",\"\",62],[\"f580\",\"\",124],[\"f640\",\"\",62],[\"f680\",\"\",124],[\"f740\",\"\",62],[\"f780\",\"\",124],[\"f840\",\"\",62],[\"f880\",\"\",124],[\"f940\",\"\"],[\"fa40\",\"ⅰ\",9,\"Ⅰ\",9,\"￢￤＇＂㈱№℡∵纊褜鍈銈蓜俉炻昱棈鋹曻彅丨仡仼伀伃伹佖侒侊侚侔俍偀倢俿倞偆偰偂傔僴僘兊\"],[\"fa80\",\"兤冝冾凬刕劜劦勀勛匀匇匤卲厓厲叝﨎咜咊咩哿喆坙坥垬埈埇﨏塚增墲夋奓奛奝奣妤妺孖寀甯寘寬尞岦岺峵崧嵓﨑嵂嵭嶸嶹巐弡弴彧德忞恝悅悊惞惕愠惲愑愷愰憘戓抦揵摠撝擎敎昀昕昻昉昮昞昤晥晗晙晴晳暙暠暲暿曺朎朗杦枻桒柀栁桄棏﨓楨﨔榘槢樰橫橆橳橾櫢櫤毖氿汜沆汯泚洄涇浯\"],[\"fb40\",\"涖涬淏淸淲淼渹湜渧渼溿澈澵濵瀅瀇瀨炅炫焏焄煜煆煇凞燁燾犱犾猤猪獷玽珉珖珣珒琇珵琦琪琩琮瑢璉璟甁畯皂皜皞皛皦益睆劯砡硎硤硺礰礼神\"],[\"fb80\",\"祥禔福禛竑竧靖竫箞精絈絜綷綠緖繒罇羡羽茁荢荿菇菶葈蒴蕓蕙蕫﨟薰蘒﨡蠇裵訒訷詹誧誾諟諸諶譓譿賰賴贒赶﨣軏﨤逸遧郞都鄕鄧釚釗釞釭釮釤釥鈆鈐鈊鈺鉀鈼鉎鉙鉑鈹鉧銧鉷鉸鋧鋗鋙鋐﨧鋕鋠鋓錥錡鋻﨨錞鋿錝錂鍰鍗鎤鏆鏞鏸鐱鑅鑈閒隆﨩隝隯霳霻靃靍靏靑靕顗顥飯飼餧館馞驎髙\"],[\"fc40\",\"髜魵魲鮏鮱鮻鰀鵰鵫鶴鸙黑\"]]\n\n/***/ }),\n/* 181 */\n/***/ (function(module, exports) {\n\nmodule.exports = [[\"0\",\"\\u0000\",127],[\"8ea1\",\"｡\",62],[\"a1a1\",\"　、。，．・：；？！゛゜´｀¨＾￣＿ヽヾゝゞ〃仝々〆〇ー―‐／＼～∥｜…‥‘’“”（）〔〕［］｛｝〈\",9,\"＋－±×÷＝≠＜＞≦≧∞∴♂♀°′″℃￥＄￠￡％＃＆＊＠§☆★○●◎◇\"],[\"a2a1\",\"◆□■△▲▽▼※〒→←↑↓〓\"],[\"a2ba\",\"∈∋⊆⊇⊂⊃∪∩\"],[\"a2ca\",\"∧∨￢⇒⇔∀∃\"],[\"a2dc\",\"∠⊥⌒∂∇≡≒≪≫√∽∝∵∫∬\"],[\"a2f2\",\"Å‰♯♭♪†‡¶\"],[\"a2fe\",\"◯\"],[\"a3b0\",\"０\",9],[\"a3c1\",\"Ａ\",25],[\"a3e1\",\"ａ\",25],[\"a4a1\",\"ぁ\",82],[\"a5a1\",\"ァ\",85],[\"a6a1\",\"Α\",16,\"Σ\",6],[\"a6c1\",\"α\",16,\"σ\",6],[\"a7a1\",\"А\",5,\"ЁЖ\",25],[\"a7d1\",\"а\",5,\"ёж\",25],[\"a8a1\",\"─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂\"],[\"ada1\",\"①\",19,\"Ⅰ\",9],[\"adc0\",\"㍉㌔㌢㍍㌘㌧㌃㌶㍑㍗㌍㌦㌣㌫㍊㌻㎜㎝㎞㎎㎏㏄㎡\"],[\"addf\",\"㍻〝〟№㏍℡㊤\",4,\"㈱㈲㈹㍾㍽㍼≒≡∫∮∑√⊥∠∟⊿∵∩∪\"],[\"b0a1\",\"亜唖娃阿哀愛挨姶逢葵茜穐悪握渥旭葦芦鯵梓圧斡扱宛姐虻飴絢綾鮎或粟袷安庵按暗案闇鞍杏以伊位依偉囲夷委威尉惟意慰易椅為畏異移維緯胃萎衣謂違遺医井亥域育郁磯一壱溢逸稲茨芋鰯允印咽員因姻引飲淫胤蔭\"],[\"b1a1\",\"院陰隠韻吋右宇烏羽迂雨卯鵜窺丑碓臼渦嘘唄欝蔚鰻姥厩浦瓜閏噂云運雲荏餌叡営嬰影映曳栄永泳洩瑛盈穎頴英衛詠鋭液疫益駅悦謁越閲榎厭円園堰奄宴延怨掩援沿演炎焔煙燕猿縁艶苑薗遠鉛鴛塩於汚甥凹央奥往応\"],[\"b2a1\",\"押旺横欧殴王翁襖鴬鴎黄岡沖荻億屋憶臆桶牡乙俺卸恩温穏音下化仮何伽価佳加可嘉夏嫁家寡科暇果架歌河火珂禍禾稼箇花苛茄荷華菓蝦課嘩貨迦過霞蚊俄峨我牙画臥芽蛾賀雅餓駕介会解回塊壊廻快怪悔恢懐戒拐改\"],[\"b3a1\",\"魁晦械海灰界皆絵芥蟹開階貝凱劾外咳害崖慨概涯碍蓋街該鎧骸浬馨蛙垣柿蛎鈎劃嚇各廓拡撹格核殻獲確穫覚角赫較郭閣隔革学岳楽額顎掛笠樫橿梶鰍潟割喝恰括活渇滑葛褐轄且鰹叶椛樺鞄株兜竃蒲釜鎌噛鴨栢茅萱\"],[\"b4a1\",\"粥刈苅瓦乾侃冠寒刊勘勧巻喚堪姦完官寛干幹患感慣憾換敢柑桓棺款歓汗漢澗潅環甘監看竿管簡緩缶翰肝艦莞観諌貫還鑑間閑関陥韓館舘丸含岸巌玩癌眼岩翫贋雁頑顔願企伎危喜器基奇嬉寄岐希幾忌揮机旗既期棋棄\"],[\"b5a1\",\"機帰毅気汽畿祈季稀紀徽規記貴起軌輝飢騎鬼亀偽儀妓宜戯技擬欺犠疑祇義蟻誼議掬菊鞠吉吃喫桔橘詰砧杵黍却客脚虐逆丘久仇休及吸宮弓急救朽求汲泣灸球究窮笈級糾給旧牛去居巨拒拠挙渠虚許距鋸漁禦魚亨享京\"],[\"b6a1\",\"供侠僑兇競共凶協匡卿叫喬境峡強彊怯恐恭挟教橋況狂狭矯胸脅興蕎郷鏡響饗驚仰凝尭暁業局曲極玉桐粁僅勤均巾錦斤欣欽琴禁禽筋緊芹菌衿襟謹近金吟銀九倶句区狗玖矩苦躯駆駈駒具愚虞喰空偶寓遇隅串櫛釧屑屈\"],[\"b7a1\",\"掘窟沓靴轡窪熊隈粂栗繰桑鍬勲君薫訓群軍郡卦袈祁係傾刑兄啓圭珪型契形径恵慶慧憩掲携敬景桂渓畦稽系経継繋罫茎荊蛍計詣警軽頚鶏芸迎鯨劇戟撃激隙桁傑欠決潔穴結血訣月件倹倦健兼券剣喧圏堅嫌建憲懸拳捲\"],[\"b8a1\",\"検権牽犬献研硯絹県肩見謙賢軒遣鍵険顕験鹸元原厳幻弦減源玄現絃舷言諺限乎個古呼固姑孤己庫弧戸故枯湖狐糊袴股胡菰虎誇跨鈷雇顧鼓五互伍午呉吾娯後御悟梧檎瑚碁語誤護醐乞鯉交佼侯候倖光公功効勾厚口向\"],[\"b9a1\",\"后喉坑垢好孔孝宏工巧巷幸広庚康弘恒慌抗拘控攻昂晃更杭校梗構江洪浩港溝甲皇硬稿糠紅紘絞綱耕考肯肱腔膏航荒行衡講貢購郊酵鉱砿鋼閤降項香高鴻剛劫号合壕拷濠豪轟麹克刻告国穀酷鵠黒獄漉腰甑忽惚骨狛込\"],[\"baa1\",\"此頃今困坤墾婚恨懇昏昆根梱混痕紺艮魂些佐叉唆嵯左差査沙瑳砂詐鎖裟坐座挫債催再最哉塞妻宰彩才採栽歳済災采犀砕砦祭斎細菜裁載際剤在材罪財冴坂阪堺榊肴咲崎埼碕鷺作削咋搾昨朔柵窄策索錯桜鮭笹匙冊刷\"],[\"bba1\",\"察拶撮擦札殺薩雑皐鯖捌錆鮫皿晒三傘参山惨撒散桟燦珊産算纂蚕讃賛酸餐斬暫残仕仔伺使刺司史嗣四士始姉姿子屍市師志思指支孜斯施旨枝止死氏獅祉私糸紙紫肢脂至視詞詩試誌諮資賜雌飼歯事似侍児字寺慈持時\"],[\"bca1\",\"次滋治爾璽痔磁示而耳自蒔辞汐鹿式識鴫竺軸宍雫七叱執失嫉室悉湿漆疾質実蔀篠偲柴芝屡蕊縞舎写射捨赦斜煮社紗者謝車遮蛇邪借勺尺杓灼爵酌釈錫若寂弱惹主取守手朱殊狩珠種腫趣酒首儒受呪寿授樹綬需囚収周\"],[\"bda1\",\"宗就州修愁拾洲秀秋終繍習臭舟蒐衆襲讐蹴輯週酋酬集醜什住充十従戎柔汁渋獣縦重銃叔夙宿淑祝縮粛塾熟出術述俊峻春瞬竣舜駿准循旬楯殉淳準潤盾純巡遵醇順処初所暑曙渚庶緒署書薯藷諸助叙女序徐恕鋤除傷償\"],[\"bea1\",\"勝匠升召哨商唱嘗奨妾娼宵将小少尚庄床廠彰承抄招掌捷昇昌昭晶松梢樟樵沼消渉湘焼焦照症省硝礁祥称章笑粧紹肖菖蒋蕉衝裳訟証詔詳象賞醤鉦鍾鐘障鞘上丈丞乗冗剰城場壌嬢常情擾条杖浄状畳穣蒸譲醸錠嘱埴飾\"],[\"bfa1\",\"拭植殖燭織職色触食蝕辱尻伸信侵唇娠寝審心慎振新晋森榛浸深申疹真神秦紳臣芯薪親診身辛進針震人仁刃塵壬尋甚尽腎訊迅陣靭笥諏須酢図厨逗吹垂帥推水炊睡粋翠衰遂酔錐錘随瑞髄崇嵩数枢趨雛据杉椙菅頗雀裾\"],[\"c0a1\",\"澄摺寸世瀬畝是凄制勢姓征性成政整星晴棲栖正清牲生盛精聖声製西誠誓請逝醒青静斉税脆隻席惜戚斥昔析石積籍績脊責赤跡蹟碩切拙接摂折設窃節説雪絶舌蝉仙先千占宣専尖川戦扇撰栓栴泉浅洗染潜煎煽旋穿箭線\"],[\"c1a1\",\"繊羨腺舛船薦詮賎践選遷銭銑閃鮮前善漸然全禅繕膳糎噌塑岨措曾曽楚狙疏疎礎祖租粗素組蘇訴阻遡鼠僧創双叢倉喪壮奏爽宋層匝惣想捜掃挿掻操早曹巣槍槽漕燥争痩相窓糟総綜聡草荘葬蒼藻装走送遭鎗霜騒像増憎\"],[\"c2a1\",\"臓蔵贈造促側則即息捉束測足速俗属賊族続卒袖其揃存孫尊損村遜他多太汰詑唾堕妥惰打柁舵楕陀駄騨体堆対耐岱帯待怠態戴替泰滞胎腿苔袋貸退逮隊黛鯛代台大第醍題鷹滝瀧卓啄宅托択拓沢濯琢託鐸濁諾茸凧蛸只\"],[\"c3a1\",\"叩但達辰奪脱巽竪辿棚谷狸鱈樽誰丹単嘆坦担探旦歎淡湛炭短端箪綻耽胆蛋誕鍛団壇弾断暖檀段男談値知地弛恥智池痴稚置致蜘遅馳築畜竹筑蓄逐秩窒茶嫡着中仲宙忠抽昼柱注虫衷註酎鋳駐樗瀦猪苧著貯丁兆凋喋寵\"],[\"c4a1\",\"帖帳庁弔張彫徴懲挑暢朝潮牒町眺聴脹腸蝶調諜超跳銚長頂鳥勅捗直朕沈珍賃鎮陳津墜椎槌追鎚痛通塚栂掴槻佃漬柘辻蔦綴鍔椿潰坪壷嬬紬爪吊釣鶴亭低停偵剃貞呈堤定帝底庭廷弟悌抵挺提梯汀碇禎程締艇訂諦蹄逓\"],[\"c5a1\",\"邸鄭釘鼎泥摘擢敵滴的笛適鏑溺哲徹撤轍迭鉄典填天展店添纏甜貼転顛点伝殿澱田電兎吐堵塗妬屠徒斗杜渡登菟賭途都鍍砥砺努度土奴怒倒党冬凍刀唐塔塘套宕島嶋悼投搭東桃梼棟盗淘湯涛灯燈当痘祷等答筒糖統到\"],[\"c6a1\",\"董蕩藤討謄豆踏逃透鐙陶頭騰闘働動同堂導憧撞洞瞳童胴萄道銅峠鴇匿得徳涜特督禿篤毒独読栃橡凸突椴届鳶苫寅酉瀞噸屯惇敦沌豚遁頓呑曇鈍奈那内乍凪薙謎灘捺鍋楢馴縄畷南楠軟難汝二尼弐迩匂賑肉虹廿日乳入\"],[\"c7a1\",\"如尿韮任妊忍認濡禰祢寧葱猫熱年念捻撚燃粘乃廼之埜嚢悩濃納能脳膿農覗蚤巴把播覇杷波派琶破婆罵芭馬俳廃拝排敗杯盃牌背肺輩配倍培媒梅楳煤狽買売賠陪這蝿秤矧萩伯剥博拍柏泊白箔粕舶薄迫曝漠爆縛莫駁麦\"],[\"c8a1\",\"函箱硲箸肇筈櫨幡肌畑畠八鉢溌発醗髪伐罰抜筏閥鳩噺塙蛤隼伴判半反叛帆搬斑板氾汎版犯班畔繁般藩販範釆煩頒飯挽晩番盤磐蕃蛮匪卑否妃庇彼悲扉批披斐比泌疲皮碑秘緋罷肥被誹費避非飛樋簸備尾微枇毘琵眉美\"],[\"c9a1\",\"鼻柊稗匹疋髭彦膝菱肘弼必畢筆逼桧姫媛紐百謬俵彪標氷漂瓢票表評豹廟描病秒苗錨鋲蒜蛭鰭品彬斌浜瀕貧賓頻敏瓶不付埠夫婦富冨布府怖扶敷斧普浮父符腐膚芙譜負賦赴阜附侮撫武舞葡蕪部封楓風葺蕗伏副復幅服\"],[\"caa1\",\"福腹複覆淵弗払沸仏物鮒分吻噴墳憤扮焚奮粉糞紛雰文聞丙併兵塀幣平弊柄並蔽閉陛米頁僻壁癖碧別瞥蔑箆偏変片篇編辺返遍便勉娩弁鞭保舗鋪圃捕歩甫補輔穂募墓慕戊暮母簿菩倣俸包呆報奉宝峰峯崩庖抱捧放方朋\"],[\"cba1\",\"法泡烹砲縫胞芳萌蓬蜂褒訪豊邦鋒飽鳳鵬乏亡傍剖坊妨帽忘忙房暴望某棒冒紡肪膨謀貌貿鉾防吠頬北僕卜墨撲朴牧睦穆釦勃没殆堀幌奔本翻凡盆摩磨魔麻埋妹昧枚毎哩槙幕膜枕鮪柾鱒桝亦俣又抹末沫迄侭繭麿万慢満\"],[\"cca1\",\"漫蔓味未魅巳箕岬密蜜湊蓑稔脈妙粍民眠務夢無牟矛霧鵡椋婿娘冥名命明盟迷銘鳴姪牝滅免棉綿緬面麺摸模茂妄孟毛猛盲網耗蒙儲木黙目杢勿餅尤戻籾貰問悶紋門匁也冶夜爺耶野弥矢厄役約薬訳躍靖柳薮鑓愉愈油癒\"],[\"cda1\",\"諭輸唯佑優勇友宥幽悠憂揖有柚湧涌猶猷由祐裕誘遊邑郵雄融夕予余与誉輿預傭幼妖容庸揚揺擁曜楊様洋溶熔用窯羊耀葉蓉要謡踊遥陽養慾抑欲沃浴翌翼淀羅螺裸来莱頼雷洛絡落酪乱卵嵐欄濫藍蘭覧利吏履李梨理璃\"],[\"cea1\",\"痢裏裡里離陸律率立葎掠略劉流溜琉留硫粒隆竜龍侶慮旅虜了亮僚両凌寮料梁涼猟療瞭稜糧良諒遼量陵領力緑倫厘林淋燐琳臨輪隣鱗麟瑠塁涙累類令伶例冷励嶺怜玲礼苓鈴隷零霊麗齢暦歴列劣烈裂廉恋憐漣煉簾練聯\"],[\"cfa1\",\"蓮連錬呂魯櫓炉賂路露労婁廊弄朗楼榔浪漏牢狼篭老聾蝋郎六麓禄肋録論倭和話歪賄脇惑枠鷲亙亘鰐詫藁蕨椀湾碗腕\"],[\"d0a1\",\"弌丐丕个丱丶丼丿乂乖乘亂亅豫亊舒弍于亞亟亠亢亰亳亶从仍仄仆仂仗仞仭仟价伉佚估佛佝佗佇佶侈侏侘佻佩佰侑佯來侖儘俔俟俎俘俛俑俚俐俤俥倚倨倔倪倥倅伜俶倡倩倬俾俯們倆偃假會偕偐偈做偖偬偸傀傚傅傴傲\"],[\"d1a1\",\"僉僊傳僂僖僞僥僭僣僮價僵儉儁儂儖儕儔儚儡儺儷儼儻儿兀兒兌兔兢竸兩兪兮冀冂囘册冉冏冑冓冕冖冤冦冢冩冪冫决冱冲冰况冽凅凉凛几處凩凭凰凵凾刄刋刔刎刧刪刮刳刹剏剄剋剌剞剔剪剴剩剳剿剽劍劔劒剱劈劑辨\"],[\"d2a1\",\"辧劬劭劼劵勁勍勗勞勣勦飭勠勳勵勸勹匆匈甸匍匐匏匕匚匣匯匱匳匸區卆卅丗卉卍凖卞卩卮夘卻卷厂厖厠厦厥厮厰厶參簒雙叟曼燮叮叨叭叺吁吽呀听吭吼吮吶吩吝呎咏呵咎呟呱呷呰咒呻咀呶咄咐咆哇咢咸咥咬哄哈咨\"],[\"d3a1\",\"咫哂咤咾咼哘哥哦唏唔哽哮哭哺哢唹啀啣啌售啜啅啖啗唸唳啝喙喀咯喊喟啻啾喘喞單啼喃喩喇喨嗚嗅嗟嗄嗜嗤嗔嘔嗷嘖嗾嗽嘛嗹噎噐營嘴嘶嘲嘸噫噤嘯噬噪嚆嚀嚊嚠嚔嚏嚥嚮嚶嚴囂嚼囁囃囀囈囎囑囓囗囮囹圀囿圄圉\"],[\"d4a1\",\"圈國圍圓團圖嗇圜圦圷圸坎圻址坏坩埀垈坡坿垉垓垠垳垤垪垰埃埆埔埒埓堊埖埣堋堙堝塲堡塢塋塰毀塒堽塹墅墹墟墫墺壞墻墸墮壅壓壑壗壙壘壥壜壤壟壯壺壹壻壼壽夂夊夐夛梦夥夬夭夲夸夾竒奕奐奎奚奘奢奠奧奬奩\"],[\"d5a1\",\"奸妁妝佞侫妣妲姆姨姜妍姙姚娥娟娑娜娉娚婀婬婉娵娶婢婪媚媼媾嫋嫂媽嫣嫗嫦嫩嫖嫺嫻嬌嬋嬖嬲嫐嬪嬶嬾孃孅孀孑孕孚孛孥孩孰孳孵學斈孺宀它宦宸寃寇寉寔寐寤實寢寞寥寫寰寶寳尅將專對尓尠尢尨尸尹屁屆屎屓\"],[\"d6a1\",\"屐屏孱屬屮乢屶屹岌岑岔妛岫岻岶岼岷峅岾峇峙峩峽峺峭嶌峪崋崕崗嵜崟崛崑崔崢崚崙崘嵌嵒嵎嵋嵬嵳嵶嶇嶄嶂嶢嶝嶬嶮嶽嶐嶷嶼巉巍巓巒巖巛巫已巵帋帚帙帑帛帶帷幄幃幀幎幗幔幟幢幤幇幵并幺麼广庠廁廂廈廐廏\"],[\"d7a1\",\"廖廣廝廚廛廢廡廨廩廬廱廳廰廴廸廾弃弉彝彜弋弑弖弩弭弸彁彈彌彎弯彑彖彗彙彡彭彳彷徃徂彿徊很徑徇從徙徘徠徨徭徼忖忻忤忸忱忝悳忿怡恠怙怐怩怎怱怛怕怫怦怏怺恚恁恪恷恟恊恆恍恣恃恤恂恬恫恙悁悍惧悃悚\"],[\"d8a1\",\"悄悛悖悗悒悧悋惡悸惠惓悴忰悽惆悵惘慍愕愆惶惷愀惴惺愃愡惻惱愍愎慇愾愨愧慊愿愼愬愴愽慂慄慳慷慘慙慚慫慴慯慥慱慟慝慓慵憙憖憇憬憔憚憊憑憫憮懌懊應懷懈懃懆憺懋罹懍懦懣懶懺懴懿懽懼懾戀戈戉戍戌戔戛\"],[\"d9a1\",\"戞戡截戮戰戲戳扁扎扞扣扛扠扨扼抂抉找抒抓抖拔抃抔拗拑抻拏拿拆擔拈拜拌拊拂拇抛拉挌拮拱挧挂挈拯拵捐挾捍搜捏掖掎掀掫捶掣掏掉掟掵捫捩掾揩揀揆揣揉插揶揄搖搴搆搓搦搶攝搗搨搏摧摯摶摎攪撕撓撥撩撈撼\"],[\"daa1\",\"據擒擅擇撻擘擂擱擧舉擠擡抬擣擯攬擶擴擲擺攀擽攘攜攅攤攣攫攴攵攷收攸畋效敖敕敍敘敞敝敲數斂斃變斛斟斫斷旃旆旁旄旌旒旛旙无旡旱杲昊昃旻杳昵昶昴昜晏晄晉晁晞晝晤晧晨晟晢晰暃暈暎暉暄暘暝曁暹曉暾暼\"],[\"dba1\",\"曄暸曖曚曠昿曦曩曰曵曷朏朖朞朦朧霸朮朿朶杁朸朷杆杞杠杙杣杤枉杰枩杼杪枌枋枦枡枅枷柯枴柬枳柩枸柤柞柝柢柮枹柎柆柧檜栞框栩桀桍栲桎梳栫桙档桷桿梟梏梭梔條梛梃檮梹桴梵梠梺椏梍桾椁棊椈棘椢椦棡椌棍\"],[\"dca1\",\"棔棧棕椶椒椄棗棣椥棹棠棯椨椪椚椣椡棆楹楷楜楸楫楔楾楮椹楴椽楙椰楡楞楝榁楪榲榮槐榿槁槓榾槎寨槊槝榻槃榧樮榑榠榜榕榴槞槨樂樛槿權槹槲槧樅榱樞槭樔槫樊樒櫁樣樓橄樌橲樶橸橇橢橙橦橈樸樢檐檍檠檄檢檣\"],[\"dda1\",\"檗蘗檻櫃櫂檸檳檬櫞櫑櫟檪櫚櫪櫻欅蘖櫺欒欖鬱欟欸欷盜欹飮歇歃歉歐歙歔歛歟歡歸歹歿殀殄殃殍殘殕殞殤殪殫殯殲殱殳殷殼毆毋毓毟毬毫毳毯麾氈氓气氛氤氣汞汕汢汪沂沍沚沁沛汾汨汳沒沐泄泱泓沽泗泅泝沮沱沾\"],[\"dea1\",\"沺泛泯泙泪洟衍洶洫洽洸洙洵洳洒洌浣涓浤浚浹浙涎涕濤涅淹渕渊涵淇淦涸淆淬淞淌淨淒淅淺淙淤淕淪淮渭湮渮渙湲湟渾渣湫渫湶湍渟湃渺湎渤滿渝游溂溪溘滉溷滓溽溯滄溲滔滕溏溥滂溟潁漑灌滬滸滾漿滲漱滯漲滌\"],[\"dfa1\",\"漾漓滷澆潺潸澁澀潯潛濳潭澂潼潘澎澑濂潦澳澣澡澤澹濆澪濟濕濬濔濘濱濮濛瀉瀋濺瀑瀁瀏濾瀛瀚潴瀝瀘瀟瀰瀾瀲灑灣炙炒炯烱炬炸炳炮烟烋烝烙焉烽焜焙煥煕熈煦煢煌煖煬熏燻熄熕熨熬燗熹熾燒燉燔燎燠燬燧燵燼\"],[\"e0a1\",\"燹燿爍爐爛爨爭爬爰爲爻爼爿牀牆牋牘牴牾犂犁犇犒犖犢犧犹犲狃狆狄狎狒狢狠狡狹狷倏猗猊猜猖猝猴猯猩猥猾獎獏默獗獪獨獰獸獵獻獺珈玳珎玻珀珥珮珞璢琅瑯琥珸琲琺瑕琿瑟瑙瑁瑜瑩瑰瑣瑪瑶瑾璋璞璧瓊瓏瓔珱\"],[\"e1a1\",\"瓠瓣瓧瓩瓮瓲瓰瓱瓸瓷甄甃甅甌甎甍甕甓甞甦甬甼畄畍畊畉畛畆畚畩畤畧畫畭畸當疆疇畴疊疉疂疔疚疝疥疣痂疳痃疵疽疸疼疱痍痊痒痙痣痞痾痿痼瘁痰痺痲痳瘋瘍瘉瘟瘧瘠瘡瘢瘤瘴瘰瘻癇癈癆癜癘癡癢癨癩癪癧癬癰\"],[\"e2a1\",\"癲癶癸發皀皃皈皋皎皖皓皙皚皰皴皸皹皺盂盍盖盒盞盡盥盧盪蘯盻眈眇眄眩眤眞眥眦眛眷眸睇睚睨睫睛睥睿睾睹瞎瞋瞑瞠瞞瞰瞶瞹瞿瞼瞽瞻矇矍矗矚矜矣矮矼砌砒礦砠礪硅碎硴碆硼碚碌碣碵碪碯磑磆磋磔碾碼磅磊磬\"],[\"e3a1\",\"磧磚磽磴礇礒礑礙礬礫祀祠祗祟祚祕祓祺祿禊禝禧齋禪禮禳禹禺秉秕秧秬秡秣稈稍稘稙稠稟禀稱稻稾稷穃穗穉穡穢穩龝穰穹穽窈窗窕窘窖窩竈窰窶竅竄窿邃竇竊竍竏竕竓站竚竝竡竢竦竭竰笂笏笊笆笳笘笙笞笵笨笶筐\"],[\"e4a1\",\"筺笄筍笋筌筅筵筥筴筧筰筱筬筮箝箘箟箍箜箚箋箒箏筝箙篋篁篌篏箴篆篝篩簑簔篦篥籠簀簇簓篳篷簗簍篶簣簧簪簟簷簫簽籌籃籔籏籀籐籘籟籤籖籥籬籵粃粐粤粭粢粫粡粨粳粲粱粮粹粽糀糅糂糘糒糜糢鬻糯糲糴糶糺紆\"],[\"e5a1\",\"紂紜紕紊絅絋紮紲紿紵絆絳絖絎絲絨絮絏絣經綉絛綏絽綛綺綮綣綵緇綽綫總綢綯緜綸綟綰緘緝緤緞緻緲緡縅縊縣縡縒縱縟縉縋縢繆繦縻縵縹繃縷縲縺繧繝繖繞繙繚繹繪繩繼繻纃緕繽辮繿纈纉續纒纐纓纔纖纎纛纜缸缺\"],[\"e6a1\",\"罅罌罍罎罐网罕罔罘罟罠罨罩罧罸羂羆羃羈羇羌羔羞羝羚羣羯羲羹羮羶羸譱翅翆翊翕翔翡翦翩翳翹飜耆耄耋耒耘耙耜耡耨耿耻聊聆聒聘聚聟聢聨聳聲聰聶聹聽聿肄肆肅肛肓肚肭冐肬胛胥胙胝胄胚胖脉胯胱脛脩脣脯腋\"],[\"e7a1\",\"隋腆脾腓腑胼腱腮腥腦腴膃膈膊膀膂膠膕膤膣腟膓膩膰膵膾膸膽臀臂膺臉臍臑臙臘臈臚臟臠臧臺臻臾舁舂舅與舊舍舐舖舩舫舸舳艀艙艘艝艚艟艤艢艨艪艫舮艱艷艸艾芍芒芫芟芻芬苡苣苟苒苴苳苺莓范苻苹苞茆苜茉苙\"],[\"e8a1\",\"茵茴茖茲茱荀茹荐荅茯茫茗茘莅莚莪莟莢莖茣莎莇莊荼莵荳荵莠莉莨菴萓菫菎菽萃菘萋菁菷萇菠菲萍萢萠莽萸蔆菻葭萪萼蕚蒄葷葫蒭葮蒂葩葆萬葯葹萵蓊葢蒹蒿蒟蓙蓍蒻蓚蓐蓁蓆蓖蒡蔡蓿蓴蔗蔘蔬蔟蔕蔔蓼蕀蕣蕘蕈\"],[\"e9a1\",\"蕁蘂蕋蕕薀薤薈薑薊薨蕭薔薛藪薇薜蕷蕾薐藉薺藏薹藐藕藝藥藜藹蘊蘓蘋藾藺蘆蘢蘚蘰蘿虍乕虔號虧虱蚓蚣蚩蚪蚋蚌蚶蚯蛄蛆蚰蛉蠣蚫蛔蛞蛩蛬蛟蛛蛯蜒蜆蜈蜀蜃蛻蜑蜉蜍蛹蜊蜴蜿蜷蜻蜥蜩蜚蝠蝟蝸蝌蝎蝴蝗蝨蝮蝙\"],[\"eaa1\",\"蝓蝣蝪蠅螢螟螂螯蟋螽蟀蟐雖螫蟄螳蟇蟆螻蟯蟲蟠蠏蠍蟾蟶蟷蠎蟒蠑蠖蠕蠢蠡蠱蠶蠹蠧蠻衄衂衒衙衞衢衫袁衾袞衵衽袵衲袂袗袒袮袙袢袍袤袰袿袱裃裄裔裘裙裝裹褂裼裴裨裲褄褌褊褓襃褞褥褪褫襁襄褻褶褸襌褝襠襞\"],[\"eba1\",\"襦襤襭襪襯襴襷襾覃覈覊覓覘覡覩覦覬覯覲覺覽覿觀觚觜觝觧觴觸訃訖訐訌訛訝訥訶詁詛詒詆詈詼詭詬詢誅誂誄誨誡誑誥誦誚誣諄諍諂諚諫諳諧諤諱謔諠諢諷諞諛謌謇謚諡謖謐謗謠謳鞫謦謫謾謨譁譌譏譎證譖譛譚譫\"],[\"eca1\",\"譟譬譯譴譽讀讌讎讒讓讖讙讚谺豁谿豈豌豎豐豕豢豬豸豺貂貉貅貊貍貎貔豼貘戝貭貪貽貲貳貮貶賈賁賤賣賚賽賺賻贄贅贊贇贏贍贐齎贓賍贔贖赧赭赱赳趁趙跂趾趺跏跚跖跌跛跋跪跫跟跣跼踈踉跿踝踞踐踟蹂踵踰踴蹊\"],[\"eda1\",\"蹇蹉蹌蹐蹈蹙蹤蹠踪蹣蹕蹶蹲蹼躁躇躅躄躋躊躓躑躔躙躪躡躬躰軆躱躾軅軈軋軛軣軼軻軫軾輊輅輕輒輙輓輜輟輛輌輦輳輻輹轅轂輾轌轉轆轎轗轜轢轣轤辜辟辣辭辯辷迚迥迢迪迯邇迴逅迹迺逑逕逡逍逞逖逋逧逶逵逹迸\"],[\"eea1\",\"遏遐遑遒逎遉逾遖遘遞遨遯遶隨遲邂遽邁邀邊邉邏邨邯邱邵郢郤扈郛鄂鄒鄙鄲鄰酊酖酘酣酥酩酳酲醋醉醂醢醫醯醪醵醴醺釀釁釉釋釐釖釟釡釛釼釵釶鈞釿鈔鈬鈕鈑鉞鉗鉅鉉鉤鉈銕鈿鉋鉐銜銖銓銛鉚鋏銹銷鋩錏鋺鍄錮\"],[\"efa1\",\"錙錢錚錣錺錵錻鍜鍠鍼鍮鍖鎰鎬鎭鎔鎹鏖鏗鏨鏥鏘鏃鏝鏐鏈鏤鐚鐔鐓鐃鐇鐐鐶鐫鐵鐡鐺鑁鑒鑄鑛鑠鑢鑞鑪鈩鑰鑵鑷鑽鑚鑼鑾钁鑿閂閇閊閔閖閘閙閠閨閧閭閼閻閹閾闊濶闃闍闌闕闔闖關闡闥闢阡阨阮阯陂陌陏陋陷陜陞\"],[\"f0a1\",\"陝陟陦陲陬隍隘隕隗險隧隱隲隰隴隶隸隹雎雋雉雍襍雜霍雕雹霄霆霈霓霎霑霏霖霙霤霪霰霹霽霾靄靆靈靂靉靜靠靤靦靨勒靫靱靹鞅靼鞁靺鞆鞋鞏鞐鞜鞨鞦鞣鞳鞴韃韆韈韋韜韭齏韲竟韶韵頏頌頸頤頡頷頽顆顏顋顫顯顰\"],[\"f1a1\",\"顱顴顳颪颯颱颶飄飃飆飩飫餃餉餒餔餘餡餝餞餤餠餬餮餽餾饂饉饅饐饋饑饒饌饕馗馘馥馭馮馼駟駛駝駘駑駭駮駱駲駻駸騁騏騅駢騙騫騷驅驂驀驃騾驕驍驛驗驟驢驥驤驩驫驪骭骰骼髀髏髑髓體髞髟髢髣髦髯髫髮髴髱髷\"],[\"f2a1\",\"髻鬆鬘鬚鬟鬢鬣鬥鬧鬨鬩鬪鬮鬯鬲魄魃魏魍魎魑魘魴鮓鮃鮑鮖鮗鮟鮠鮨鮴鯀鯊鮹鯆鯏鯑鯒鯣鯢鯤鯔鯡鰺鯲鯱鯰鰕鰔鰉鰓鰌鰆鰈鰒鰊鰄鰮鰛鰥鰤鰡鰰鱇鰲鱆鰾鱚鱠鱧鱶鱸鳧鳬鳰鴉鴈鳫鴃鴆鴪鴦鶯鴣鴟鵄鴕鴒鵁鴿鴾鵆鵈\"],[\"f3a1\",\"鵝鵞鵤鵑鵐鵙鵲鶉鶇鶫鵯鵺鶚鶤鶩鶲鷄鷁鶻鶸鶺鷆鷏鷂鷙鷓鷸鷦鷭鷯鷽鸚鸛鸞鹵鹹鹽麁麈麋麌麒麕麑麝麥麩麸麪麭靡黌黎黏黐黔黜點黝黠黥黨黯黴黶黷黹黻黼黽鼇鼈皷鼕鼡鼬鼾齊齒齔齣齟齠齡齦齧齬齪齷齲齶龕龜龠\"],[\"f4a1\",\"堯槇遙瑤凜熙\"],[\"f9a1\",\"纊褜鍈銈蓜俉炻昱棈鋹曻彅丨仡仼伀伃伹佖侒侊侚侔俍偀倢俿倞偆偰偂傔僴僘兊兤冝冾凬刕劜劦勀勛匀匇匤卲厓厲叝﨎咜咊咩哿喆坙坥垬埈埇﨏塚增墲夋奓奛奝奣妤妺孖寀甯寘寬尞岦岺峵崧嵓﨑嵂嵭嶸嶹巐弡弴彧德\"],[\"faa1\",\"忞恝悅悊惞惕愠惲愑愷愰憘戓抦揵摠撝擎敎昀昕昻昉昮昞昤晥晗晙晴晳暙暠暲暿曺朎朗杦枻桒柀栁桄棏﨓楨﨔榘槢樰橫橆橳橾櫢櫤毖氿汜沆汯泚洄涇浯涖涬淏淸淲淼渹湜渧渼溿澈澵濵瀅瀇瀨炅炫焏焄煜煆煇凞燁燾犱\"],[\"fba1\",\"犾猤猪獷玽珉珖珣珒琇珵琦琪琩琮瑢璉璟甁畯皂皜皞皛皦益睆劯砡硎硤硺礰礼神祥禔福禛竑竧靖竫箞精絈絜綷綠緖繒罇羡羽茁荢荿菇菶葈蒴蕓蕙蕫﨟薰蘒﨡蠇裵訒訷詹誧誾諟諸諶譓譿賰賴贒赶﨣軏﨤逸遧郞都鄕鄧釚\"],[\"fca1\",\"釗釞釭釮釤釥鈆鈐鈊鈺鉀鈼鉎鉙鉑鈹鉧銧鉷鉸鋧鋗鋙鋐﨧鋕鋠鋓錥錡鋻﨨錞鋿錝錂鍰鍗鎤鏆鏞鏸鐱鑅鑈閒隆﨩隝隯霳霻靃靍靏靑靕顗顥飯飼餧館馞驎髙髜魵魲鮏鮱鮻鰀鵰鵫鶴鸙黑\"],[\"fcf1\",\"ⅰ\",9,\"￢￤＇＂\"],[\"8fa2af\",\"˘ˇ¸˙˝¯˛˚～΄΅\"],[\"8fa2c2\",\"¡¦¿\"],[\"8fa2eb\",\"ºª©®™¤№\"],[\"8fa6e1\",\"ΆΈΉΊΪ\"],[\"8fa6e7\",\"Ό\"],[\"8fa6e9\",\"ΎΫ\"],[\"8fa6ec\",\"Ώ\"],[\"8fa6f1\",\"άέήίϊΐόςύϋΰώ\"],[\"8fa7c2\",\"Ђ\",10,\"ЎЏ\"],[\"8fa7f2\",\"ђ\",10,\"ўџ\"],[\"8fa9a1\",\"ÆĐ\"],[\"8fa9a4\",\"Ħ\"],[\"8fa9a6\",\"Ĳ\"],[\"8fa9a8\",\"ŁĿ\"],[\"8fa9ab\",\"ŊØŒ\"],[\"8fa9af\",\"ŦÞ\"],[\"8fa9c1\",\"æđðħıĳĸłŀŉŋøœßŧþ\"],[\"8faaa1\",\"ÁÀÄÂĂǍĀĄÅÃĆĈČÇĊĎÉÈËÊĚĖĒĘ\"],[\"8faaba\",\"ĜĞĢĠĤÍÌÏÎǏİĪĮĨĴĶĹĽĻŃŇŅÑÓÒÖÔǑŐŌÕŔŘŖŚŜŠŞŤŢÚÙÜÛŬǓŰŪŲŮŨǗǛǙǕŴÝŸŶŹŽŻ\"],[\"8faba1\",\"áàäâăǎāąåãćĉčçċďéèëêěėēęǵĝğ\"],[\"8fabbd\",\"ġĥíìïîǐ\"],[\"8fabc5\",\"īįĩĵķĺľļńňņñóòöôǒőōõŕřŗśŝšşťţúùüûŭǔűūųůũǘǜǚǖŵýÿŷźžż\"],[\"8fb0a1\",\"丂丄丅丌丒丟丣两丨丫丮丯丰丵乀乁乄乇乑乚乜乣乨乩乴乵乹乿亍亖亗亝亯亹仃仐仚仛仠仡仢仨仯仱仳仵份仾仿伀伂伃伈伋伌伒伕伖众伙伮伱你伳伵伷伹伻伾佀佂佈佉佋佌佒佔佖佘佟佣佪佬佮佱佷佸佹佺佽佾侁侂侄\"],[\"8fb1a1\",\"侅侉侊侌侎侐侒侓侔侗侙侚侞侟侲侷侹侻侼侽侾俀俁俅俆俈俉俋俌俍俏俒俜俠俢俰俲俼俽俿倀倁倄倇倊倌倎倐倓倗倘倛倜倝倞倢倧倮倰倲倳倵偀偁偂偅偆偊偌偎偑偒偓偗偙偟偠偢偣偦偧偪偭偰偱倻傁傃傄傆傊傎傏傐\"],[\"8fb2a1\",\"傒傓傔傖傛傜傞\",4,\"傪傯傰傹傺傽僀僃僄僇僌僎僐僓僔僘僜僝僟僢僤僦僨僩僯僱僶僺僾儃儆儇儈儋儌儍儎僲儐儗儙儛儜儝儞儣儧儨儬儭儯儱儳儴儵儸儹兂兊兏兓兕兗兘兟兤兦兾冃冄冋冎冘冝冡冣冭冸冺冼冾冿凂\"],[\"8fb3a1\",\"凈减凑凒凓凕凘凞凢凥凮凲凳凴凷刁刂刅划刓刕刖刘刢刨刱刲刵刼剅剉剕剗剘剚剜剟剠剡剦剮剷剸剹劀劂劅劊劌劓劕劖劗劘劚劜劤劥劦劧劯劰劶劷劸劺劻劽勀勄勆勈勌勏勑勔勖勛勜勡勥勨勩勪勬勰勱勴勶勷匀匃匊匋\"],[\"8fb4a1\",\"匌匑匓匘匛匜匞匟匥匧匨匩匫匬匭匰匲匵匼匽匾卂卌卋卙卛卡卣卥卬卭卲卹卾厃厇厈厎厓厔厙厝厡厤厪厫厯厲厴厵厷厸厺厽叀叅叏叒叓叕叚叝叞叠另叧叵吂吓吚吡吧吨吪启吱吴吵呃呄呇呍呏呞呢呤呦呧呩呫呭呮呴呿\"],[\"8fb5a1\",\"咁咃咅咈咉咍咑咕咖咜咟咡咦咧咩咪咭咮咱咷咹咺咻咿哆哊响哎哠哪哬哯哶哼哾哿唀唁唅唈唉唌唍唎唕唪唫唲唵唶唻唼唽啁啇啉啊啍啐啑啘啚啛啞啠啡啤啦啿喁喂喆喈喎喏喑喒喓喔喗喣喤喭喲喿嗁嗃嗆嗉嗋嗌嗎嗑嗒\"],[\"8fb6a1\",\"嗓嗗嗘嗛嗞嗢嗩嗶嗿嘅嘈嘊嘍\",5,\"嘙嘬嘰嘳嘵嘷嘹嘻嘼嘽嘿噀噁噃噄噆噉噋噍噏噔噞噠噡噢噣噦噩噭噯噱噲噵嚄嚅嚈嚋嚌嚕嚙嚚嚝嚞嚟嚦嚧嚨嚩嚫嚬嚭嚱嚳嚷嚾囅囉囊囋囏囐囌囍囙囜囝囟囡囤\",4,\"囱囫园\"],[\"8fb7a1\",\"囶囷圁圂圇圊圌圑圕圚圛圝圠圢圣圤圥圩圪圬圮圯圳圴圽圾圿坅坆坌坍坒坢坥坧坨坫坭\",4,\"坳坴坵坷坹坺坻坼坾垁垃垌垔垗垙垚垜垝垞垟垡垕垧垨垩垬垸垽埇埈埌埏埕埝埞埤埦埧埩埭埰埵埶埸埽埾埿堃堄堈堉埡\"],[\"8fb8a1\",\"堌堍堛堞堟堠堦堧堭堲堹堿塉塌塍塏塐塕塟塡塤塧塨塸塼塿墀墁墇墈墉墊墌墍墏墐墔墖墝墠墡墢墦墩墱墲壄墼壂壈壍壎壐壒壔壖壚壝壡壢壩壳夅夆夋夌夒夓夔虁夝夡夣夤夨夯夰夳夵夶夿奃奆奒奓奙奛奝奞奟奡奣奫奭\"],[\"8fb9a1\",\"奯奲奵奶她奻奼妋妌妎妒妕妗妟妤妧妭妮妯妰妳妷妺妼姁姃姄姈姊姍姒姝姞姟姣姤姧姮姯姱姲姴姷娀娄娌娍娎娒娓娞娣娤娧娨娪娭娰婄婅婇婈婌婐婕婞婣婥婧婭婷婺婻婾媋媐媓媖媙媜媞媟媠媢媧媬媱媲媳媵媸媺媻媿\"],[\"8fbaa1\",\"嫄嫆嫈嫏嫚嫜嫠嫥嫪嫮嫵嫶嫽嬀嬁嬈嬗嬴嬙嬛嬝嬡嬥嬭嬸孁孋孌孒孖孞孨孮孯孼孽孾孿宁宄宆宊宎宐宑宓宔宖宨宩宬宭宯宱宲宷宺宼寀寁寍寏寖\",4,\"寠寯寱寴寽尌尗尞尟尣尦尩尫尬尮尰尲尵尶屙屚屜屢屣屧屨屩\"],[\"8fbba1\",\"屭屰屴屵屺屻屼屽岇岈岊岏岒岝岟岠岢岣岦岪岲岴岵岺峉峋峒峝峗峮峱峲峴崁崆崍崒崫崣崤崦崧崱崴崹崽崿嵂嵃嵆嵈嵕嵑嵙嵊嵟嵠嵡嵢嵤嵪嵭嵰嵹嵺嵾嵿嶁嶃嶈嶊嶒嶓嶔嶕嶙嶛嶟嶠嶧嶫嶰嶴嶸嶹巃巇巋巐巎巘巙巠巤\"],[\"8fbca1\",\"巩巸巹帀帇帍帒帔帕帘帟帠帮帨帲帵帾幋幐幉幑幖幘幛幜幞幨幪\",4,\"幰庀庋庎庢庤庥庨庪庬庱庳庽庾庿廆廌廋廎廑廒廔廕廜廞廥廫异弆弇弈弎弙弜弝弡弢弣弤弨弫弬弮弰弴弶弻弽弿彀彄彅彇彍彐彔彘彛彠彣彤彧\"],[\"8fbda1\",\"彯彲彴彵彸彺彽彾徉徍徏徖徜徝徢徧徫徤徬徯徰徱徸忄忇忈忉忋忐\",4,\"忞忡忢忨忩忪忬忭忮忯忲忳忶忺忼怇怊怍怓怔怗怘怚怟怤怭怳怵恀恇恈恉恌恑恔恖恗恝恡恧恱恾恿悂悆悈悊悎悑悓悕悘悝悞悢悤悥您悰悱悷\"],[\"8fbea1\",\"悻悾惂惄惈惉惊惋惎惏惔惕惙惛惝惞惢惥惲惵惸惼惽愂愇愊愌愐\",4,\"愖愗愙愜愞愢愪愫愰愱愵愶愷愹慁慅慆慉慞慠慬慲慸慻慼慿憀憁憃憄憋憍憒憓憗憘憜憝憟憠憥憨憪憭憸憹憼懀懁懂懎懏懕懜懝懞懟懡懢懧懩懥\"],[\"8fbfa1\",\"懬懭懯戁戃戄戇戓戕戜戠戢戣戧戩戫戹戽扂扃扄扆扌扐扑扒扔扖扚扜扤扭扯扳扺扽抍抎抏抐抦抨抳抶抷抺抾抿拄拎拕拖拚拪拲拴拼拽挃挄挊挋挍挐挓挖挘挩挪挭挵挶挹挼捁捂捃捄捆捊捋捎捒捓捔捘捛捥捦捬捭捱捴捵\"],[\"8fc0a1\",\"捸捼捽捿掂掄掇掊掐掔掕掙掚掞掤掦掭掮掯掽揁揅揈揎揑揓揔揕揜揠揥揪揬揲揳揵揸揹搉搊搐搒搔搘搞搠搢搤搥搩搪搯搰搵搽搿摋摏摑摒摓摔摚摛摜摝摟摠摡摣摭摳摴摻摽撅撇撏撐撑撘撙撛撝撟撡撣撦撨撬撳撽撾撿\"],[\"8fc1a1\",\"擄擉擊擋擌擎擐擑擕擗擤擥擩擪擭擰擵擷擻擿攁攄攈攉攊攏攓攔攖攙攛攞攟攢攦攩攮攱攺攼攽敃敇敉敐敒敔敟敠敧敫敺敽斁斅斊斒斕斘斝斠斣斦斮斲斳斴斿旂旈旉旎旐旔旖旘旟旰旲旴旵旹旾旿昀昄昈昉昍昑昒昕昖昝\"],[\"8fc2a1\",\"昞昡昢昣昤昦昩昪昫昬昮昰昱昳昹昷晀晅晆晊晌晑晎晗晘晙晛晜晠晡曻晪晫晬晾晳晵晿晷晸晹晻暀晼暋暌暍暐暒暙暚暛暜暟暠暤暭暱暲暵暻暿曀曂曃曈曌曎曏曔曛曟曨曫曬曮曺朅朇朎朓朙朜朠朢朳朾杅杇杈杌杔杕杝\"],[\"8fc3a1\",\"杦杬杮杴杶杻极构枎枏枑枓枖枘枙枛枰枱枲枵枻枼枽柹柀柂柃柅柈柉柒柗柙柜柡柦柰柲柶柷桒栔栙栝栟栨栧栬栭栯栰栱栳栻栿桄桅桊桌桕桗桘桛桫桮\",4,\"桵桹桺桻桼梂梄梆梈梖梘梚梜梡梣梥梩梪梮梲梻棅棈棌棏\"],[\"8fc4a1\",\"棐棑棓棖棙棜棝棥棨棪棫棬棭棰棱棵棶棻棼棽椆椉椊椐椑椓椖椗椱椳椵椸椻楂楅楉楎楗楛楣楤楥楦楨楩楬楰楱楲楺楻楿榀榍榒榖榘榡榥榦榨榫榭榯榷榸榺榼槅槈槑槖槗槢槥槮槯槱槳槵槾樀樁樃樏樑樕樚樝樠樤樨樰樲\"],[\"8fc5a1\",\"樴樷樻樾樿橅橆橉橊橎橐橑橒橕橖橛橤橧橪橱橳橾檁檃檆檇檉檋檑檛檝檞檟檥檫檯檰檱檴檽檾檿櫆櫉櫈櫌櫐櫔櫕櫖櫜櫝櫤櫧櫬櫰櫱櫲櫼櫽欂欃欆欇欉欏欐欑欗欛欞欤欨欫欬欯欵欶欻欿歆歊歍歒歖歘歝歠歧歫歮歰歵歽\"],[\"8fc6a1\",\"歾殂殅殗殛殟殠殢殣殨殩殬殭殮殰殸殹殽殾毃毄毉毌毖毚毡毣毦毧毮毱毷毹毿氂氄氅氉氍氎氐氒氙氟氦氧氨氬氮氳氵氶氺氻氿汊汋汍汏汒汔汙汛汜汫汭汯汴汶汸汹汻沅沆沇沉沔沕沗沘沜沟沰沲沴泂泆泍泏泐泑泒泔泖\"],[\"8fc7a1\",\"泚泜泠泧泩泫泬泮泲泴洄洇洊洎洏洑洓洚洦洧洨汧洮洯洱洹洼洿浗浞浟浡浥浧浯浰浼涂涇涑涒涔涖涗涘涪涬涴涷涹涽涿淄淈淊淎淏淖淛淝淟淠淢淥淩淯淰淴淶淼渀渄渞渢渧渲渶渹渻渼湄湅湈湉湋湏湑湒湓湔湗湜湝湞\"],[\"8fc8a1\",\"湢湣湨湳湻湽溍溓溙溠溧溭溮溱溳溻溿滀滁滃滇滈滊滍滎滏滫滭滮滹滻滽漄漈漊漌漍漖漘漚漛漦漩漪漯漰漳漶漻漼漭潏潑潒潓潗潙潚潝潞潡潢潨潬潽潾澃澇澈澋澌澍澐澒澓澔澖澚澟澠澥澦澧澨澮澯澰澵澶澼濅濇濈濊\"],[\"8fc9a1\",\"濚濞濨濩濰濵濹濼濽瀀瀅瀆瀇瀍瀗瀠瀣瀯瀴瀷瀹瀼灃灄灈灉灊灋灔灕灝灞灎灤灥灬灮灵灶灾炁炅炆炔\",4,\"炛炤炫炰炱炴炷烊烑烓烔烕烖烘烜烤烺焃\",4,\"焋焌焏焞焠焫焭焯焰焱焸煁煅煆煇煊煋煐煒煗煚煜煞煠\"],[\"8fcaa1\",\"煨煹熀熅熇熌熒熚熛熠熢熯熰熲熳熺熿燀燁燄燋燌燓燖燙燚燜燸燾爀爇爈爉爓爗爚爝爟爤爫爯爴爸爹牁牂牃牅牎牏牐牓牕牖牚牜牞牠牣牨牫牮牯牱牷牸牻牼牿犄犉犍犎犓犛犨犭犮犱犴犾狁狇狉狌狕狖狘狟狥狳狴狺狻\"],[\"8fcba1\",\"狾猂猄猅猇猋猍猒猓猘猙猞猢猤猧猨猬猱猲猵猺猻猽獃獍獐獒獖獘獝獞獟獠獦獧獩獫獬獮獯獱獷獹獼玀玁玃玅玆玎玐玓玕玗玘玜玞玟玠玢玥玦玪玫玭玵玷玹玼玽玿珅珆珉珋珌珏珒珓珖珙珝珡珣珦珧珩珴珵珷珹珺珻珽\"],[\"8fcca1\",\"珿琀琁琄琇琊琑琚琛琤琦琨\",9,\"琹瑀瑃瑄瑆瑇瑋瑍瑑瑒瑗瑝瑢瑦瑧瑨瑫瑭瑮瑱瑲璀璁璅璆璇璉璏璐璑璒璘璙璚璜璟璠璡璣璦璨璩璪璫璮璯璱璲璵璹璻璿瓈瓉瓌瓐瓓瓘瓚瓛瓞瓟瓤瓨瓪瓫瓯瓴瓺瓻瓼瓿甆\"],[\"8fcda1\",\"甒甖甗甠甡甤甧甩甪甯甶甹甽甾甿畀畃畇畈畎畐畒畗畞畟畡畯畱畹\",5,\"疁疅疐疒疓疕疙疜疢疤疴疺疿痀痁痄痆痌痎痏痗痜痟痠痡痤痧痬痮痯痱痹瘀瘂瘃瘄瘇瘈瘊瘌瘏瘒瘓瘕瘖瘙瘛瘜瘝瘞瘣瘥瘦瘩瘭瘲瘳瘵瘸瘹\"],[\"8fcea1\",\"瘺瘼癊癀癁癃癄癅癉癋癕癙癟癤癥癭癮癯癱癴皁皅皌皍皕皛皜皝皟皠皢\",6,\"皪皭皽盁盅盉盋盌盎盔盙盠盦盨盬盰盱盶盹盼眀眆眊眎眒眔眕眗眙眚眜眢眨眭眮眯眴眵眶眹眽眾睂睅睆睊睍睎睏睒睖睗睜睞睟睠睢\"],[\"8fcfa1\",\"睤睧睪睬睰睲睳睴睺睽瞀瞄瞌瞍瞔瞕瞖瞚瞟瞢瞧瞪瞮瞯瞱瞵瞾矃矉矑矒矕矙矞矟矠矤矦矪矬矰矱矴矸矻砅砆砉砍砎砑砝砡砢砣砭砮砰砵砷硃硄硇硈硌硎硒硜硞硠硡硣硤硨硪确硺硾碊碏碔碘碡碝碞碟碤碨碬碭碰碱碲碳\"],[\"8fd0a1\",\"碻碽碿磇磈磉磌磎磒磓磕磖磤磛磟磠磡磦磪磲磳礀磶磷磺磻磿礆礌礐礚礜礞礟礠礥礧礩礭礱礴礵礻礽礿祄祅祆祊祋祏祑祔祘祛祜祧祩祫祲祹祻祼祾禋禌禑禓禔禕禖禘禛禜禡禨禩禫禯禱禴禸离秂秄秇秈秊秏秔秖秚秝秞\"],[\"8fd1a1\",\"秠秢秥秪秫秭秱秸秼稂稃稇稉稊稌稑稕稛稞稡稧稫稭稯稰稴稵稸稹稺穄穅穇穈穌穕穖穙穜穝穟穠穥穧穪穭穵穸穾窀窂窅窆窊窋窐窑窔窞窠窣窬窳窵窹窻窼竆竉竌竎竑竛竨竩竫竬竱竴竻竽竾笇笔笟笣笧笩笪笫笭笮笯笰\"],[\"8fd2a1\",\"笱笴笽笿筀筁筇筎筕筠筤筦筩筪筭筯筲筳筷箄箉箎箐箑箖箛箞箠箥箬箯箰箲箵箶箺箻箼箽篂篅篈篊篔篖篗篙篚篛篨篪篲篴篵篸篹篺篼篾簁簂簃簄簆簉簋簌簎簏簙簛簠簥簦簨簬簱簳簴簶簹簺籆籊籕籑籒籓籙\",5],[\"8fd3a1\",\"籡籣籧籩籭籮籰籲籹籼籽粆粇粏粔粞粠粦粰粶粷粺粻粼粿糄糇糈糉糍糏糓糔糕糗糙糚糝糦糩糫糵紃紇紈紉紏紑紒紓紖紝紞紣紦紪紭紱紼紽紾絀絁絇絈絍絑絓絗絙絚絜絝絥絧絪絰絸絺絻絿綁綂綃綅綆綈綋綌綍綑綖綗綝\"],[\"8fd4a1\",\"綞綦綧綪綳綶綷綹緂\",4,\"緌緍緎緗緙縀緢緥緦緪緫緭緱緵緶緹緺縈縐縑縕縗縜縝縠縧縨縬縭縯縳縶縿繄繅繇繎繐繒繘繟繡繢繥繫繮繯繳繸繾纁纆纇纊纍纑纕纘纚纝纞缼缻缽缾缿罃罄罇罏罒罓罛罜罝罡罣罤罥罦罭\"],[\"8fd5a1\",\"罱罽罾罿羀羋羍羏羐羑羖羗羜羡羢羦羪羭羴羼羿翀翃翈翎翏翛翟翣翥翨翬翮翯翲翺翽翾翿耇耈耊耍耎耏耑耓耔耖耝耞耟耠耤耦耬耮耰耴耵耷耹耺耼耾聀聄聠聤聦聭聱聵肁肈肎肜肞肦肧肫肸肹胈胍胏胒胔胕胗胘胠胭胮\"],[\"8fd6a1\",\"胰胲胳胶胹胺胾脃脋脖脗脘脜脞脠脤脧脬脰脵脺脼腅腇腊腌腒腗腠腡腧腨腩腭腯腷膁膐膄膅膆膋膎膖膘膛膞膢膮膲膴膻臋臃臅臊臎臏臕臗臛臝臞臡臤臫臬臰臱臲臵臶臸臹臽臿舀舃舏舓舔舙舚舝舡舢舨舲舴舺艃艄艅艆\"],[\"8fd7a1\",\"艋艎艏艑艖艜艠艣艧艭艴艻艽艿芀芁芃芄芇芉芊芎芑芔芖芘芚芛芠芡芣芤芧芨芩芪芮芰芲芴芷芺芼芾芿苆苐苕苚苠苢苤苨苪苭苯苶苷苽苾茀茁茇茈茊茋荔茛茝茞茟茡茢茬茭茮茰茳茷茺茼茽荂荃荄荇荍荎荑荕荖荗荰荸\"],[\"8fd8a1\",\"荽荿莀莂莄莆莍莒莔莕莘莙莛莜莝莦莧莩莬莾莿菀菇菉菏菐菑菔菝荓菨菪菶菸菹菼萁萆萊萏萑萕萙莭萯萹葅葇葈葊葍葏葑葒葖葘葙葚葜葠葤葥葧葪葰葳葴葶葸葼葽蒁蒅蒒蒓蒕蒞蒦蒨蒩蒪蒯蒱蒴蒺蒽蒾蓀蓂蓇蓈蓌蓏蓓\"],[\"8fd9a1\",\"蓜蓧蓪蓯蓰蓱蓲蓷蔲蓺蓻蓽蔂蔃蔇蔌蔎蔐蔜蔞蔢蔣蔤蔥蔧蔪蔫蔯蔳蔴蔶蔿蕆蕏\",4,\"蕖蕙蕜\",6,\"蕤蕫蕯蕹蕺蕻蕽蕿薁薅薆薉薋薌薏薓薘薝薟薠薢薥薧薴薶薷薸薼薽薾薿藂藇藊藋藎薭藘藚藟藠藦藨藭藳藶藼\"],[\"8fdaa1\",\"藿蘀蘄蘅蘍蘎蘐蘑蘒蘘蘙蘛蘞蘡蘧蘩蘶蘸蘺蘼蘽虀虂虆虒虓虖虗虘虙虝虠\",4,\"虩虬虯虵虶虷虺蚍蚑蚖蚘蚚蚜蚡蚦蚧蚨蚭蚱蚳蚴蚵蚷蚸蚹蚿蛀蛁蛃蛅蛑蛒蛕蛗蛚蛜蛠蛣蛥蛧蚈蛺蛼蛽蜄蜅蜇蜋蜎蜏蜐蜓蜔蜙蜞蜟蜡蜣\"],[\"8fdba1\",\"蜨蜮蜯蜱蜲蜹蜺蜼蜽蜾蝀蝃蝅蝍蝘蝝蝡蝤蝥蝯蝱蝲蝻螃\",6,\"螋螌螐螓螕螗螘螙螞螠螣螧螬螭螮螱螵螾螿蟁蟈蟉蟊蟎蟕蟖蟙蟚蟜蟟蟢蟣蟤蟪蟫蟭蟱蟳蟸蟺蟿蠁蠃蠆蠉蠊蠋蠐蠙蠒蠓蠔蠘蠚蠛蠜蠞蠟蠨蠭蠮蠰蠲蠵\"],[\"8fdca1\",\"蠺蠼衁衃衅衈衉衊衋衎衑衕衖衘衚衜衟衠衤衩衱衹衻袀袘袚袛袜袟袠袨袪袺袽袾裀裊\",4,\"裑裒裓裛裞裧裯裰裱裵裷褁褆褍褎褏褕褖褘褙褚褜褠褦褧褨褰褱褲褵褹褺褾襀襂襅襆襉襏襒襗襚襛襜襡襢襣襫襮襰襳襵襺\"],[\"8fdda1\",\"襻襼襽覉覍覐覔覕覛覜覟覠覥覰覴覵覶覷覼觔\",4,\"觥觩觫觭觱觳觶觹觽觿訄訅訇訏訑訒訔訕訞訠訢訤訦訫訬訯訵訷訽訾詀詃詅詇詉詍詎詓詖詗詘詜詝詡詥詧詵詶詷詹詺詻詾詿誀誃誆誋誏誐誒誖誗誙誟誧誩誮誯誳\"],[\"8fdea1\",\"誶誷誻誾諃諆諈諉諊諑諓諔諕諗諝諟諬諰諴諵諶諼諿謅謆謋謑謜謞謟謊謭謰謷謼譂\",4,\"譈譒譓譔譙譍譞譣譭譶譸譹譼譾讁讄讅讋讍讏讔讕讜讞讟谸谹谽谾豅豇豉豋豏豑豓豔豗豘豛豝豙豣豤豦豨豩豭豳豵豶豻豾貆\"],[\"8fdfa1\",\"貇貋貐貒貓貙貛貜貤貹貺賅賆賉賋賏賖賕賙賝賡賨賬賯賰賲賵賷賸賾賿贁贃贉贒贗贛赥赩赬赮赿趂趄趈趍趐趑趕趞趟趠趦趫趬趯趲趵趷趹趻跀跅跆跇跈跊跎跑跔跕跗跙跤跥跧跬跰趼跱跲跴跽踁踄踅踆踋踑踔踖踠踡踢\"],[\"8fe0a1\",\"踣踦踧踱踳踶踷踸踹踽蹀蹁蹋蹍蹎蹏蹔蹛蹜蹝蹞蹡蹢蹩蹬蹭蹯蹰蹱蹹蹺蹻躂躃躉躐躒躕躚躛躝躞躢躧躩躭躮躳躵躺躻軀軁軃軄軇軏軑軔軜軨軮軰軱軷軹軺軭輀輂輇輈輏輐輖輗輘輞輠輡輣輥輧輨輬輭輮輴輵輶輷輺轀轁\"],[\"8fe1a1\",\"轃轇轏轑\",4,\"轘轝轞轥辝辠辡辤辥辦辵辶辸达迀迁迆迊迋迍运迒迓迕迠迣迤迨迮迱迵迶迻迾适逄逈逌逘逛逨逩逯逪逬逭逳逴逷逿遃遄遌遛遝遢遦遧遬遰遴遹邅邈邋邌邎邐邕邗邘邙邛邠邡邢邥邰邲邳邴邶邽郌邾郃\"],[\"8fe2a1\",\"郄郅郇郈郕郗郘郙郜郝郟郥郒郶郫郯郰郴郾郿鄀鄄鄅鄆鄈鄍鄐鄔鄖鄗鄘鄚鄜鄞鄠鄥鄢鄣鄧鄩鄮鄯鄱鄴鄶鄷鄹鄺鄼鄽酃酇酈酏酓酗酙酚酛酡酤酧酭酴酹酺酻醁醃醅醆醊醎醑醓醔醕醘醞醡醦醨醬醭醮醰醱醲醳醶醻醼醽醿\"],[\"8fe3a1\",\"釂釃釅釓釔釗釙釚釞釤釥釩釪釬\",5,\"釷釹釻釽鈀鈁鈄鈅鈆鈇鈉鈊鈌鈐鈒鈓鈖鈘鈜鈝鈣鈤鈥鈦鈨鈮鈯鈰鈳鈵鈶鈸鈹鈺鈼鈾鉀鉂鉃鉆鉇鉊鉍鉎鉏鉑鉘鉙鉜鉝鉠鉡鉥鉧鉨鉩鉮鉯鉰鉵\",4,\"鉻鉼鉽鉿銈銉銊銍銎銒銗\"],[\"8fe4a1\",\"銙銟銠銤銥銧銨銫銯銲銶銸銺銻銼銽銿\",4,\"鋅鋆鋇鋈鋋鋌鋍鋎鋐鋓鋕鋗鋘鋙鋜鋝鋟鋠鋡鋣鋥鋧鋨鋬鋮鋰鋹鋻鋿錀錂錈錍錑錔錕錜錝錞錟錡錤錥錧錩錪錳錴錶錷鍇鍈鍉鍐鍑鍒鍕鍗鍘鍚鍞鍤鍥鍧鍩鍪鍭鍯鍰鍱鍳鍴鍶\"],[\"8fe5a1\",\"鍺鍽鍿鎀鎁鎂鎈鎊鎋鎍鎏鎒鎕鎘鎛鎞鎡鎣鎤鎦鎨鎫鎴鎵鎶鎺鎩鏁鏄鏅鏆鏇鏉\",4,\"鏓鏙鏜鏞鏟鏢鏦鏧鏹鏷鏸鏺鏻鏽鐁鐂鐄鐈鐉鐍鐎鐏鐕鐖鐗鐟鐮鐯鐱鐲鐳鐴鐻鐿鐽鑃鑅鑈鑊鑌鑕鑙鑜鑟鑡鑣鑨鑫鑭鑮鑯鑱鑲钄钃镸镹\"],[\"8fe6a1\",\"镾閄閈閌閍閎閝閞閟閡閦閩閫閬閴閶閺閽閿闆闈闉闋闐闑闒闓闙闚闝闞闟闠闤闦阝阞阢阤阥阦阬阱阳阷阸阹阺阼阽陁陒陔陖陗陘陡陮陴陻陼陾陿隁隂隃隄隉隑隖隚隝隟隤隥隦隩隮隯隳隺雊雒嶲雘雚雝雞雟雩雯雱雺霂\"],[\"8fe7a1\",\"霃霅霉霚霛霝霡霢霣霨霱霳靁靃靊靎靏靕靗靘靚靛靣靧靪靮靳靶靷靸靻靽靿鞀鞉鞕鞖鞗鞙鞚鞞鞟鞢鞬鞮鞱鞲鞵鞶鞸鞹鞺鞼鞾鞿韁韄韅韇韉韊韌韍韎韐韑韔韗韘韙韝韞韠韛韡韤韯韱韴韷韸韺頇頊頙頍頎頔頖頜頞頠頣頦\"],[\"8fe8a1\",\"頫頮頯頰頲頳頵頥頾顄顇顊顑顒顓顖顗顙顚顢顣顥顦顪顬颫颭颮颰颴颷颸颺颻颿飂飅飈飌飡飣飥飦飧飪飳飶餂餇餈餑餕餖餗餚餛餜餟餢餦餧餫餱\",4,\"餹餺餻餼饀饁饆饇饈饍饎饔饘饙饛饜饞饟饠馛馝馟馦馰馱馲馵\"],[\"8fe9a1\",\"馹馺馽馿駃駉駓駔駙駚駜駞駧駪駫駬駰駴駵駹駽駾騂騃騄騋騌騐騑騖騞騠騢騣騤騧騭騮騳騵騶騸驇驁驄驊驋驌驎驑驔驖驝骪骬骮骯骲骴骵骶骹骻骾骿髁髃髆髈髎髐髒髕髖髗髛髜髠髤髥髧髩髬髲髳髵髹髺髽髿\",4],[\"8feaa1\",\"鬄鬅鬈鬉鬋鬌鬍鬎鬐鬒鬖鬙鬛鬜鬠鬦鬫鬭鬳鬴鬵鬷鬹鬺鬽魈魋魌魕魖魗魛魞魡魣魥魦魨魪\",4,\"魳魵魷魸魹魿鮀鮄鮅鮆鮇鮉鮊鮋鮍鮏鮐鮔鮚鮝鮞鮦鮧鮩鮬鮰鮱鮲鮷鮸鮻鮼鮾鮿鯁鯇鯈鯎鯐鯗鯘鯝鯟鯥鯧鯪鯫鯯鯳鯷鯸\"],[\"8feba1\",\"鯹鯺鯽鯿鰀鰂鰋鰏鰑鰖鰘鰙鰚鰜鰞鰢鰣鰦\",4,\"鰱鰵鰶鰷鰽鱁鱃鱄鱅鱉鱊鱎鱏鱐鱓鱔鱖鱘鱛鱝鱞鱟鱣鱩鱪鱜鱫鱨鱮鱰鱲鱵鱷鱻鳦鳲鳷鳹鴋鴂鴑鴗鴘鴜鴝鴞鴯鴰鴲鴳鴴鴺鴼鵅鴽鵂鵃鵇鵊鵓鵔鵟鵣鵢鵥鵩鵪鵫鵰鵶鵷鵻\"],[\"8feca1\",\"鵼鵾鶃鶄鶆鶊鶍鶎鶒鶓鶕鶖鶗鶘鶡鶪鶬鶮鶱鶵鶹鶼鶿鷃鷇鷉鷊鷔鷕鷖鷗鷚鷞鷟鷠鷥鷧鷩鷫鷮鷰鷳鷴鷾鸊鸂鸇鸎鸐鸑鸒鸕鸖鸙鸜鸝鹺鹻鹼麀麂麃麄麅麇麎麏麖麘麛麞麤麨麬麮麯麰麳麴麵黆黈黋黕黟黤黧黬黭黮黰黱黲黵\"],[\"8feda1\",\"黸黿鼂鼃鼉鼏鼐鼑鼒鼔鼖鼗鼙鼚鼛鼟鼢鼦鼪鼫鼯鼱鼲鼴鼷鼹鼺鼼鼽鼿齁齃\",4,\"齓齕齖齗齘齚齝齞齨齩齭\",4,\"齳齵齺齽龏龐龑龒龔龖龗龞龡龢龣龥\"]]\n\n/***/ }),\n/* 182 */\n/***/ (function(module, exports) {\n\nmodule.exports = {\"uChars\":[128,165,169,178,184,216,226,235,238,244,248,251,253,258,276,284,300,325,329,334,364,463,465,467,469,471,473,475,477,506,594,610,712,716,730,930,938,962,970,1026,1104,1106,8209,8215,8218,8222,8231,8241,8244,8246,8252,8365,8452,8454,8458,8471,8482,8556,8570,8596,8602,8713,8720,8722,8726,8731,8737,8740,8742,8748,8751,8760,8766,8777,8781,8787,8802,8808,8816,8854,8858,8870,8896,8979,9322,9372,9548,9588,9616,9622,9634,9652,9662,9672,9676,9680,9702,9735,9738,9793,9795,11906,11909,11913,11917,11928,11944,11947,11951,11956,11960,11964,11979,12284,12292,12312,12319,12330,12351,12436,12447,12535,12543,12586,12842,12850,12964,13200,13215,13218,13253,13263,13267,13270,13384,13428,13727,13839,13851,14617,14703,14801,14816,14964,15183,15471,15585,16471,16736,17208,17325,17330,17374,17623,17997,18018,18212,18218,18301,18318,18760,18811,18814,18820,18823,18844,18848,18872,19576,19620,19738,19887,40870,59244,59336,59367,59413,59417,59423,59431,59437,59443,59452,59460,59478,59493,63789,63866,63894,63976,63986,64016,64018,64021,64025,64034,64037,64042,65074,65093,65107,65112,65127,65132,65375,65510,65536],\"gbChars\":[0,36,38,45,50,81,89,95,96,100,103,104,105,109,126,133,148,172,175,179,208,306,307,308,309,310,311,312,313,341,428,443,544,545,558,741,742,749,750,805,819,820,7922,7924,7925,7927,7934,7943,7944,7945,7950,8062,8148,8149,8152,8164,8174,8236,8240,8262,8264,8374,8380,8381,8384,8388,8390,8392,8393,8394,8396,8401,8406,8416,8419,8424,8437,8439,8445,8482,8485,8496,8521,8603,8936,8946,9046,9050,9063,9066,9076,9092,9100,9108,9111,9113,9131,9162,9164,9218,9219,11329,11331,11334,11336,11346,11361,11363,11366,11370,11372,11375,11389,11682,11686,11687,11692,11694,11714,11716,11723,11725,11730,11736,11982,11989,12102,12336,12348,12350,12384,12393,12395,12397,12510,12553,12851,12962,12973,13738,13823,13919,13933,14080,14298,14585,14698,15583,15847,16318,16434,16438,16481,16729,17102,17122,17315,17320,17402,17418,17859,17909,17911,17915,17916,17936,17939,17961,18664,18703,18814,18962,19043,33469,33470,33471,33484,33485,33490,33497,33501,33505,33513,33520,33536,33550,37845,37921,37948,38029,38038,38064,38065,38066,38069,38075,38076,38078,39108,39109,39113,39114,39115,39116,39265,39394,189000]}\n\n/***/ }),\n/* 183 */\n/***/ (function(module, exports) {\n\nmodule.exports = [[\"0\",\"\\u0000\",127],[\"8141\",\"갂갃갅갆갋\",4,\"갘갞갟갡갢갣갥\",6,\"갮갲갳갴\"],[\"8161\",\"갵갶갷갺갻갽갾갿걁\",9,\"걌걎\",5,\"걕\"],[\"8181\",\"걖걗걙걚걛걝\",18,\"걲걳걵걶걹걻\",4,\"겂겇겈겍겎겏겑겒겓겕\",6,\"겞겢\",5,\"겫겭겮겱\",6,\"겺겾겿곀곂곃곅곆곇곉곊곋곍\",7,\"곖곘\",7,\"곢곣곥곦곩곫곭곮곲곴곷\",4,\"곾곿괁괂괃괅괇\",4,\"괎괐괒괓\"],[\"8241\",\"괔괕괖괗괙괚괛괝괞괟괡\",7,\"괪괫괮\",5],[\"8261\",\"괶괷괹괺괻괽\",6,\"굆굈굊\",5,\"굑굒굓굕굖굗\"],[\"8281\",\"굙\",7,\"굢굤\",7,\"굮굯굱굲굷굸굹굺굾궀궃\",4,\"궊궋궍궎궏궑\",10,\"궞\",5,\"궥\",17,\"궸\",7,\"귂귃귅귆귇귉\",6,\"귒귔\",7,\"귝귞귟귡귢귣귥\",18],[\"8341\",\"귺귻귽귾긂\",5,\"긊긌긎\",5,\"긕\",7],[\"8361\",\"긝\",18,\"긲긳긵긶긹긻긼\"],[\"8381\",\"긽긾긿깂깄깇깈깉깋깏깑깒깓깕깗\",4,\"깞깢깣깤깦깧깪깫깭깮깯깱\",6,\"깺깾\",5,\"꺆\",5,\"꺍\",46,\"꺿껁껂껃껅\",6,\"껎껒\",5,\"껚껛껝\",8],[\"8441\",\"껦껧껩껪껬껮\",5,\"껵껶껷껹껺껻껽\",8],[\"8461\",\"꼆꼉꼊꼋꼌꼎꼏꼑\",18],[\"8481\",\"꼤\",7,\"꼮꼯꼱꼳꼵\",6,\"꼾꽀꽄꽅꽆꽇꽊\",5,\"꽑\",10,\"꽞\",5,\"꽦\",18,\"꽺\",5,\"꾁꾂꾃꾅꾆꾇꾉\",6,\"꾒꾓꾔꾖\",5,\"꾝\",26,\"꾺꾻꾽꾾\"],[\"8541\",\"꾿꿁\",5,\"꿊꿌꿏\",4,\"꿕\",6,\"꿝\",4],[\"8561\",\"꿢\",5,\"꿪\",5,\"꿲꿳꿵꿶꿷꿹\",6,\"뀂뀃\"],[\"8581\",\"뀅\",6,\"뀍뀎뀏뀑뀒뀓뀕\",6,\"뀞\",9,\"뀩\",26,\"끆끇끉끋끍끏끐끑끒끖끘끚끛끜끞\",29,\"끾끿낁낂낃낅\",6,\"낎낐낒\",5,\"낛낝낞낣낤\"],[\"8641\",\"낥낦낧낪낰낲낶낷낹낺낻낽\",6,\"냆냊\",5,\"냒\"],[\"8661\",\"냓냕냖냗냙\",6,\"냡냢냣냤냦\",10],[\"8681\",\"냱\",22,\"넊넍넎넏넑넔넕넖넗넚넞\",4,\"넦넧넩넪넫넭\",6,\"넶넺\",5,\"녂녃녅녆녇녉\",6,\"녒녓녖녗녙녚녛녝녞녟녡\",22,\"녺녻녽녾녿놁놃\",4,\"놊놌놎놏놐놑놕놖놗놙놚놛놝\"],[\"8741\",\"놞\",9,\"놩\",15],[\"8761\",\"놹\",18,\"뇍뇎뇏뇑뇒뇓뇕\"],[\"8781\",\"뇖\",5,\"뇞뇠\",7,\"뇪뇫뇭뇮뇯뇱\",7,\"뇺뇼뇾\",5,\"눆눇눉눊눍\",6,\"눖눘눚\",5,\"눡\",18,\"눵\",6,\"눽\",26,\"뉙뉚뉛뉝뉞뉟뉡\",6,\"뉪\",4],[\"8841\",\"뉯\",4,\"뉶\",5,\"뉽\",6,\"늆늇늈늊\",4],[\"8861\",\"늏늒늓늕늖늗늛\",4,\"늢늤늧늨늩늫늭늮늯늱늲늳늵늶늷\"],[\"8881\",\"늸\",15,\"닊닋닍닎닏닑닓\",4,\"닚닜닞닟닠닡닣닧닩닪닰닱닲닶닼닽닾댂댃댅댆댇댉\",6,\"댒댖\",5,\"댝\",54,\"덗덙덚덝덠덡덢덣\"],[\"8941\",\"덦덨덪덬덭덯덲덳덵덶덷덹\",6,\"뎂뎆\",5,\"뎍\"],[\"8961\",\"뎎뎏뎑뎒뎓뎕\",10,\"뎢\",5,\"뎩뎪뎫뎭\"],[\"8981\",\"뎮\",21,\"돆돇돉돊돍돏돑돒돓돖돘돚돜돞돟돡돢돣돥돦돧돩\",18,\"돽\",18,\"됑\",6,\"됙됚됛됝됞됟됡\",6,\"됪됬\",7,\"됵\",15],[\"8a41\",\"둅\",10,\"둒둓둕둖둗둙\",6,\"둢둤둦\"],[\"8a61\",\"둧\",4,\"둭\",18,\"뒁뒂\"],[\"8a81\",\"뒃\",4,\"뒉\",19,\"뒞\",5,\"뒥뒦뒧뒩뒪뒫뒭\",7,\"뒶뒸뒺\",5,\"듁듂듃듅듆듇듉\",6,\"듑듒듓듔듖\",5,\"듞듟듡듢듥듧\",4,\"듮듰듲\",5,\"듹\",26,\"딖딗딙딚딝\"],[\"8b41\",\"딞\",5,\"딦딫\",4,\"딲딳딵딶딷딹\",6,\"땂땆\"],[\"8b61\",\"땇땈땉땊땎땏땑땒땓땕\",6,\"땞땢\",8],[\"8b81\",\"땫\",52,\"떢떣떥떦떧떩떬떭떮떯떲떶\",4,\"떾떿뗁뗂뗃뗅\",6,\"뗎뗒\",5,\"뗙\",18,\"뗭\",18],[\"8c41\",\"똀\",15,\"똒똓똕똖똗똙\",4],[\"8c61\",\"똞\",6,\"똦\",5,\"똭\",6,\"똵\",5],[\"8c81\",\"똻\",12,\"뙉\",26,\"뙥뙦뙧뙩\",50,\"뚞뚟뚡뚢뚣뚥\",5,\"뚭뚮뚯뚰뚲\",16],[\"8d41\",\"뛃\",16,\"뛕\",8],[\"8d61\",\"뛞\",17,\"뛱뛲뛳뛵뛶뛷뛹뛺\"],[\"8d81\",\"뛻\",4,\"뜂뜃뜄뜆\",33,\"뜪뜫뜭뜮뜱\",6,\"뜺뜼\",7,\"띅띆띇띉띊띋띍\",6,\"띖\",9,\"띡띢띣띥띦띧띩\",6,\"띲띴띶\",5,\"띾띿랁랂랃랅\",6,\"랎랓랔랕랚랛랝랞\"],[\"8e41\",\"랟랡\",6,\"랪랮\",5,\"랶랷랹\",8],[\"8e61\",\"럂\",4,\"럈럊\",19],[\"8e81\",\"럞\",13,\"럮럯럱럲럳럵\",6,\"럾렂\",4,\"렊렋렍렎렏렑\",6,\"렚렜렞\",5,\"렦렧렩렪렫렭\",6,\"렶렺\",5,\"롁롂롃롅\",11,\"롒롔\",7,\"롞롟롡롢롣롥\",6,\"롮롰롲\",5,\"롹롺롻롽\",7],[\"8f41\",\"뢅\",7,\"뢎\",17],[\"8f61\",\"뢠\",7,\"뢩\",6,\"뢱뢲뢳뢵뢶뢷뢹\",4],[\"8f81\",\"뢾뢿룂룄룆\",5,\"룍룎룏룑룒룓룕\",7,\"룞룠룢\",5,\"룪룫룭룮룯룱\",6,\"룺룼룾\",5,\"뤅\",18,\"뤙\",6,\"뤡\",26,\"뤾뤿륁륂륃륅\",6,\"륍륎륐륒\",5],[\"9041\",\"륚륛륝륞륟륡\",6,\"륪륬륮\",5,\"륶륷륹륺륻륽\"],[\"9061\",\"륾\",5,\"릆릈릋릌릏\",15],[\"9081\",\"릟\",12,\"릮릯릱릲릳릵\",6,\"릾맀맂\",5,\"맊맋맍맓\",4,\"맚맜맟맠맢맦맧맩맪맫맭\",6,\"맶맻\",4,\"먂\",5,\"먉\",11,\"먖\",33,\"먺먻먽먾먿멁멃멄멅멆\"],[\"9141\",\"멇멊멌멏멐멑멒멖멗멙멚멛멝\",6,\"멦멪\",5],[\"9161\",\"멲멳멵멶멷멹\",9,\"몆몈몉몊몋몍\",5],[\"9181\",\"몓\",20,\"몪몭몮몯몱몳\",4,\"몺몼몾\",5,\"뫅뫆뫇뫉\",14,\"뫚\",33,\"뫽뫾뫿묁묂묃묅\",7,\"묎묐묒\",5,\"묙묚묛묝묞묟묡\",6],[\"9241\",\"묨묪묬\",7,\"묷묹묺묿\",4,\"뭆뭈뭊뭋뭌뭎뭑뭒\"],[\"9261\",\"뭓뭕뭖뭗뭙\",7,\"뭢뭤\",7,\"뭭\",4],[\"9281\",\"뭲\",21,\"뮉뮊뮋뮍뮎뮏뮑\",18,\"뮥뮦뮧뮩뮪뮫뮭\",6,\"뮵뮶뮸\",7,\"믁믂믃믅믆믇믉\",6,\"믑믒믔\",35,\"믺믻믽믾밁\"],[\"9341\",\"밃\",4,\"밊밎밐밒밓밙밚밠밡밢밣밦밨밪밫밬밮밯밲밳밵\"],[\"9361\",\"밶밷밹\",6,\"뱂뱆뱇뱈뱊뱋뱎뱏뱑\",8],[\"9381\",\"뱚뱛뱜뱞\",37,\"벆벇벉벊벍벏\",4,\"벖벘벛\",4,\"벢벣벥벦벩\",6,\"벲벶\",5,\"벾벿볁볂볃볅\",7,\"볎볒볓볔볖볗볙볚볛볝\",22,\"볷볹볺볻볽\"],[\"9441\",\"볾\",5,\"봆봈봊\",5,\"봑봒봓봕\",8],[\"9461\",\"봞\",5,\"봥\",6,\"봭\",12],[\"9481\",\"봺\",5,\"뵁\",6,\"뵊뵋뵍뵎뵏뵑\",6,\"뵚\",9,\"뵥뵦뵧뵩\",22,\"붂붃붅붆붋\",4,\"붒붔붖붗붘붛붝\",6,\"붥\",10,\"붱\",6,\"붹\",24],[\"9541\",\"뷒뷓뷖뷗뷙뷚뷛뷝\",11,\"뷪\",5,\"뷱\"],[\"9561\",\"뷲뷳뷵뷶뷷뷹\",6,\"븁븂븄븆\",5,\"븎븏븑븒븓\"],[\"9581\",\"븕\",6,\"븞븠\",35,\"빆빇빉빊빋빍빏\",4,\"빖빘빜빝빞빟빢빣빥빦빧빩빫\",4,\"빲빶\",4,\"빾빿뺁뺂뺃뺅\",6,\"뺎뺒\",5,\"뺚\",13,\"뺩\",14],[\"9641\",\"뺸\",23,\"뻒뻓\"],[\"9661\",\"뻕뻖뻙\",6,\"뻡뻢뻦\",5,\"뻭\",8],[\"9681\",\"뻶\",10,\"뼂\",5,\"뼊\",13,\"뼚뼞\",33,\"뽂뽃뽅뽆뽇뽉\",6,\"뽒뽓뽔뽖\",44],[\"9741\",\"뾃\",16,\"뾕\",8],[\"9761\",\"뾞\",17,\"뾱\",7],[\"9781\",\"뾹\",11,\"뿆\",5,\"뿎뿏뿑뿒뿓뿕\",6,\"뿝뿞뿠뿢\",89,\"쀽쀾쀿\"],[\"9841\",\"쁀\",16,\"쁒\",5,\"쁙쁚쁛\"],[\"9861\",\"쁝쁞쁟쁡\",6,\"쁪\",15],[\"9881\",\"쁺\",21,\"삒삓삕삖삗삙\",6,\"삢삤삦\",5,\"삮삱삲삷\",4,\"삾샂샃샄샆샇샊샋샍샎샏샑\",6,\"샚샞\",5,\"샦샧샩샪샫샭\",6,\"샶샸샺\",5,\"섁섂섃섅섆섇섉\",6,\"섑섒섓섔섖\",5,\"섡섢섥섨섩섪섫섮\"],[\"9941\",\"섲섳섴섵섷섺섻섽섾섿셁\",6,\"셊셎\",5,\"셖셗\"],[\"9961\",\"셙셚셛셝\",6,\"셦셪\",5,\"셱셲셳셵셶셷셹셺셻\"],[\"9981\",\"셼\",8,\"솆\",5,\"솏솑솒솓솕솗\",4,\"솞솠솢솣솤솦솧솪솫솭솮솯솱\",11,\"솾\",5,\"쇅쇆쇇쇉쇊쇋쇍\",6,\"쇕쇖쇙\",6,\"쇡쇢쇣쇥쇦쇧쇩\",6,\"쇲쇴\",7,\"쇾쇿숁숂숃숅\",6,\"숎숐숒\",5,\"숚숛숝숞숡숢숣\"],[\"9a41\",\"숤숥숦숧숪숬숮숰숳숵\",16],[\"9a61\",\"쉆쉇쉉\",6,\"쉒쉓쉕쉖쉗쉙\",6,\"쉡쉢쉣쉤쉦\"],[\"9a81\",\"쉧\",4,\"쉮쉯쉱쉲쉳쉵\",6,\"쉾슀슂\",5,\"슊\",5,\"슑\",6,\"슙슚슜슞\",5,\"슦슧슩슪슫슮\",5,\"슶슸슺\",33,\"싞싟싡싢싥\",5,\"싮싰싲싳싴싵싷싺싽싾싿쌁\",6,\"쌊쌋쌎쌏\"],[\"9b41\",\"쌐쌑쌒쌖쌗쌙쌚쌛쌝\",6,\"쌦쌧쌪\",8],[\"9b61\",\"쌳\",17,\"썆\",7],[\"9b81\",\"썎\",25,\"썪썫썭썮썯썱썳\",4,\"썺썻썾\",5,\"쎅쎆쎇쎉쎊쎋쎍\",50,\"쏁\",22,\"쏚\"],[\"9c41\",\"쏛쏝쏞쏡쏣\",4,\"쏪쏫쏬쏮\",5,\"쏶쏷쏹\",5],[\"9c61\",\"쏿\",8,\"쐉\",6,\"쐑\",9],[\"9c81\",\"쐛\",8,\"쐥\",6,\"쐭쐮쐯쐱쐲쐳쐵\",6,\"쐾\",9,\"쑉\",26,\"쑦쑧쑩쑪쑫쑭\",6,\"쑶쑷쑸쑺\",5,\"쒁\",18,\"쒕\",6,\"쒝\",12],[\"9d41\",\"쒪\",13,\"쒹쒺쒻쒽\",8],[\"9d61\",\"쓆\",25],[\"9d81\",\"쓠\",8,\"쓪\",5,\"쓲쓳쓵쓶쓷쓹쓻쓼쓽쓾씂\",9,\"씍씎씏씑씒씓씕\",6,\"씝\",10,\"씪씫씭씮씯씱\",6,\"씺씼씾\",5,\"앆앇앋앏앐앑앒앖앚앛앜앟앢앣앥앦앧앩\",6,\"앲앶\",5,\"앾앿얁얂얃얅얆얈얉얊얋얎얐얒얓얔\"],[\"9e41\",\"얖얙얚얛얝얞얟얡\",7,\"얪\",9,\"얶\"],[\"9e61\",\"얷얺얿\",4,\"엋엍엏엒엓엕엖엗엙\",6,\"엢엤엦엧\"],[\"9e81\",\"엨엩엪엫엯엱엲엳엵엸엹엺엻옂옃옄옉옊옋옍옎옏옑\",6,\"옚옝\",6,\"옦옧옩옪옫옯옱옲옶옸옺옼옽옾옿왂왃왅왆왇왉\",6,\"왒왖\",5,\"왞왟왡\",10,\"왭왮왰왲\",5,\"왺왻왽왾왿욁\",6,\"욊욌욎\",5,\"욖욗욙욚욛욝\",6,\"욦\"],[\"9f41\",\"욨욪\",5,\"욲욳욵욶욷욻\",4,\"웂웄웆\",5,\"웎\"],[\"9f61\",\"웏웑웒웓웕\",6,\"웞웟웢\",5,\"웪웫웭웮웯웱웲\"],[\"9f81\",\"웳\",4,\"웺웻웼웾\",5,\"윆윇윉윊윋윍\",6,\"윖윘윚\",5,\"윢윣윥윦윧윩\",6,\"윲윴윶윸윹윺윻윾윿읁읂읃읅\",4,\"읋읎읐읙읚읛읝읞읟읡\",6,\"읩읪읬\",7,\"읶읷읹읺읻읿잀잁잂잆잋잌잍잏잒잓잕잙잛\",4,\"잢잧\",4,\"잮잯잱잲잳잵잶잷\"],[\"a041\",\"잸잹잺잻잾쟂\",5,\"쟊쟋쟍쟏쟑\",6,\"쟙쟚쟛쟜\"],[\"a061\",\"쟞\",5,\"쟥쟦쟧쟩쟪쟫쟭\",13],[\"a081\",\"쟻\",4,\"젂젃젅젆젇젉젋\",4,\"젒젔젗\",4,\"젞젟젡젢젣젥\",6,\"젮젰젲\",5,\"젹젺젻젽젾젿졁\",6,\"졊졋졎\",5,\"졕\",26,\"졲졳졵졶졷졹졻\",4,\"좂좄좈좉좊좎\",5,\"좕\",7,\"좞좠좢좣좤\"],[\"a141\",\"좥좦좧좩\",18,\"좾좿죀죁\"],[\"a161\",\"죂죃죅죆죇죉죊죋죍\",6,\"죖죘죚\",5,\"죢죣죥\"],[\"a181\",\"죦\",14,\"죶\",5,\"죾죿줁줂줃줇\",4,\"줎　、。·‥…¨〃­―∥＼∼‘’“”〔〕〈\",9,\"±×÷≠≤≥∞∴°′″℃Å￠￡￥♂♀∠⊥⌒∂∇≡≒§※☆★○●◎◇◆□■△▲▽▼→←↑↓↔〓≪≫√∽∝∵∫∬∈∋⊆⊇⊂⊃∪∩∧∨￢\"],[\"a241\",\"줐줒\",5,\"줙\",18],[\"a261\",\"줭\",6,\"줵\",18],[\"a281\",\"쥈\",7,\"쥒쥓쥕쥖쥗쥙\",6,\"쥢쥤\",7,\"쥭쥮쥯⇒⇔∀∃´～ˇ˘˝˚˙¸˛¡¿ː∮∑∏¤℉‰◁◀▷▶♤♠♡♥♧♣⊙◈▣◐◑▒▤▥▨▧▦▩♨☏☎☜☞¶†‡↕↗↙↖↘♭♩♪♬㉿㈜№㏇™㏂㏘℡€®\"],[\"a341\",\"쥱쥲쥳쥵\",6,\"쥽\",10,\"즊즋즍즎즏\"],[\"a361\",\"즑\",6,\"즚즜즞\",16],[\"a381\",\"즯\",16,\"짂짃짅짆짉짋\",4,\"짒짔짗짘짛！\",58,\"￦］\",32,\"￣\"],[\"a441\",\"짞짟짡짣짥짦짨짩짪짫짮짲\",5,\"짺짻짽짾짿쨁쨂쨃쨄\"],[\"a461\",\"쨅쨆쨇쨊쨎\",5,\"쨕쨖쨗쨙\",12],[\"a481\",\"쨦쨧쨨쨪\",28,\"ㄱ\",93],[\"a541\",\"쩇\",4,\"쩎쩏쩑쩒쩓쩕\",6,\"쩞쩢\",5,\"쩩쩪\"],[\"a561\",\"쩫\",17,\"쩾\",5,\"쪅쪆\"],[\"a581\",\"쪇\",16,\"쪙\",14,\"ⅰ\",9],[\"a5b0\",\"Ⅰ\",9],[\"a5c1\",\"Α\",16,\"Σ\",6],[\"a5e1\",\"α\",16,\"σ\",6],[\"a641\",\"쪨\",19,\"쪾쪿쫁쫂쫃쫅\"],[\"a661\",\"쫆\",5,\"쫎쫐쫒쫔쫕쫖쫗쫚\",5,\"쫡\",6],[\"a681\",\"쫨쫩쫪쫫쫭\",6,\"쫵\",18,\"쬉쬊─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂┒┑┚┙┖┕┎┍┞┟┡┢┦┧┩┪┭┮┱┲┵┶┹┺┽┾╀╁╃\",7],[\"a741\",\"쬋\",4,\"쬑쬒쬓쬕쬖쬗쬙\",6,\"쬢\",7],[\"a761\",\"쬪\",22,\"쭂쭃쭄\"],[\"a781\",\"쭅쭆쭇쭊쭋쭍쭎쭏쭑\",6,\"쭚쭛쭜쭞\",5,\"쭥\",7,\"㎕㎖㎗ℓ㎘㏄㎣㎤㎥㎦㎙\",9,\"㏊㎍㎎㎏㏏㎈㎉㏈㎧㎨㎰\",9,\"㎀\",4,\"㎺\",5,\"㎐\",4,\"Ω㏀㏁㎊㎋㎌㏖㏅㎭㎮㎯㏛㎩㎪㎫㎬㏝㏐㏓㏃㏉㏜㏆\"],[\"a841\",\"쭭\",10,\"쭺\",14],[\"a861\",\"쮉\",18,\"쮝\",6],[\"a881\",\"쮤\",19,\"쮹\",11,\"ÆÐªĦ\"],[\"a8a6\",\"Ĳ\"],[\"a8a8\",\"ĿŁØŒºÞŦŊ\"],[\"a8b1\",\"㉠\",27,\"ⓐ\",25,\"①\",14,\"½⅓⅔¼¾⅛⅜⅝⅞\"],[\"a941\",\"쯅\",14,\"쯕\",10],[\"a961\",\"쯠쯡쯢쯣쯥쯦쯨쯪\",18],[\"a981\",\"쯽\",14,\"찎찏찑찒찓찕\",6,\"찞찟찠찣찤æđðħıĳĸŀłøœßþŧŋŉ㈀\",27,\"⒜\",25,\"⑴\",14,\"¹²³⁴ⁿ₁₂₃₄\"],[\"aa41\",\"찥찦찪찫찭찯찱\",6,\"찺찿\",4,\"챆챇챉챊챋챍챎\"],[\"aa61\",\"챏\",4,\"챖챚\",5,\"챡챢챣챥챧챩\",6,\"챱챲\"],[\"aa81\",\"챳챴챶\",29,\"ぁ\",82],[\"ab41\",\"첔첕첖첗첚첛첝첞첟첡\",6,\"첪첮\",5,\"첶첷첹\"],[\"ab61\",\"첺첻첽\",6,\"쳆쳈쳊\",5,\"쳑쳒쳓쳕\",5],[\"ab81\",\"쳛\",8,\"쳥\",6,\"쳭쳮쳯쳱\",12,\"ァ\",85],[\"ac41\",\"쳾쳿촀촂\",5,\"촊촋촍촎촏촑\",6,\"촚촜촞촟촠\"],[\"ac61\",\"촡촢촣촥촦촧촩촪촫촭\",11,\"촺\",4],[\"ac81\",\"촿\",28,\"쵝쵞쵟А\",5,\"ЁЖ\",25],[\"acd1\",\"а\",5,\"ёж\",25],[\"ad41\",\"쵡쵢쵣쵥\",6,\"쵮쵰쵲\",5,\"쵹\",7],[\"ad61\",\"춁\",6,\"춉\",10,\"춖춗춙춚춛춝춞춟\"],[\"ad81\",\"춠춡춢춣춦춨춪\",5,\"춱\",18,\"췅\"],[\"ae41\",\"췆\",5,\"췍췎췏췑\",16],[\"ae61\",\"췢\",5,\"췩췪췫췭췮췯췱\",6,\"췺췼췾\",4],[\"ae81\",\"츃츅츆츇츉츊츋츍\",6,\"츕츖츗츘츚\",5,\"츢츣츥츦츧츩츪츫\"],[\"af41\",\"츬츭츮츯츲츴츶\",19],[\"af61\",\"칊\",13,\"칚칛칝칞칢\",5,\"칪칬\"],[\"af81\",\"칮\",5,\"칶칷칹칺칻칽\",6,\"캆캈캊\",5,\"캒캓캕캖캗캙\"],[\"b041\",\"캚\",5,\"캢캦\",5,\"캮\",12],[\"b061\",\"캻\",5,\"컂\",19],[\"b081\",\"컖\",13,\"컦컧컩컪컭\",6,\"컶컺\",5,\"가각간갇갈갉갊감\",7,\"같\",4,\"갠갤갬갭갯갰갱갸갹갼걀걋걍걔걘걜거걱건걷걸걺검겁것겄겅겆겉겊겋게겐겔겜겝겟겠겡겨격겪견겯결겸겹겻겼경곁계곈곌곕곗고곡곤곧골곪곬곯곰곱곳공곶과곽관괄괆\"],[\"b141\",\"켂켃켅켆켇켉\",6,\"켒켔켖\",5,\"켝켞켟켡켢켣\"],[\"b161\",\"켥\",6,\"켮켲\",5,\"켹\",11],[\"b181\",\"콅\",14,\"콖콗콙콚콛콝\",6,\"콦콨콪콫콬괌괍괏광괘괜괠괩괬괭괴괵괸괼굄굅굇굉교굔굘굡굣구국군굳굴굵굶굻굼굽굿궁궂궈궉권궐궜궝궤궷귀귁귄귈귐귑귓규균귤그극근귿글긁금급긋긍긔기긱긴긷길긺김깁깃깅깆깊까깍깎깐깔깖깜깝깟깠깡깥깨깩깬깰깸\"],[\"b241\",\"콭콮콯콲콳콵콶콷콹\",6,\"쾁쾂쾃쾄쾆\",5,\"쾍\"],[\"b261\",\"쾎\",18,\"쾢\",5,\"쾩\"],[\"b281\",\"쾪\",5,\"쾱\",18,\"쿅\",6,\"깹깻깼깽꺄꺅꺌꺼꺽꺾껀껄껌껍껏껐껑께껙껜껨껫껭껴껸껼꼇꼈꼍꼐꼬꼭꼰꼲꼴꼼꼽꼿꽁꽂꽃꽈꽉꽐꽜꽝꽤꽥꽹꾀꾄꾈꾐꾑꾕꾜꾸꾹꾼꿀꿇꿈꿉꿋꿍꿎꿔꿜꿨꿩꿰꿱꿴꿸뀀뀁뀄뀌뀐뀔뀜뀝뀨끄끅끈끊끌끎끓끔끕끗끙\"],[\"b341\",\"쿌\",19,\"쿢쿣쿥쿦쿧쿩\"],[\"b361\",\"쿪\",5,\"쿲쿴쿶\",5,\"쿽쿾쿿퀁퀂퀃퀅\",5],[\"b381\",\"퀋\",5,\"퀒\",5,\"퀙\",19,\"끝끼끽낀낄낌낍낏낑나낙낚난낟날낡낢남납낫\",4,\"낱낳내낵낸낼냄냅냇냈냉냐냑냔냘냠냥너넉넋넌널넒넓넘넙넛넜넝넣네넥넨넬넴넵넷넸넹녀녁년녈념녑녔녕녘녜녠노녹논놀놂놈놉놋농높놓놔놘놜놨뇌뇐뇔뇜뇝\"],[\"b441\",\"퀮\",5,\"퀶퀷퀹퀺퀻퀽\",6,\"큆큈큊\",5],[\"b461\",\"큑큒큓큕큖큗큙\",6,\"큡\",10,\"큮큯\"],[\"b481\",\"큱큲큳큵\",6,\"큾큿킀킂\",18,\"뇟뇨뇩뇬뇰뇹뇻뇽누눅눈눋눌눔눕눗눙눠눴눼뉘뉜뉠뉨뉩뉴뉵뉼늄늅늉느늑는늘늙늚늠늡늣능늦늪늬늰늴니닉닌닐닒님닙닛닝닢다닥닦단닫\",4,\"닳담답닷\",4,\"닿대댁댄댈댐댑댓댔댕댜더덕덖던덛덜덞덟덤덥\"],[\"b541\",\"킕\",14,\"킦킧킩킪킫킭\",5],[\"b561\",\"킳킶킸킺\",5,\"탂탃탅탆탇탊\",5,\"탒탖\",4],[\"b581\",\"탛탞탟탡탢탣탥\",6,\"탮탲\",5,\"탹\",11,\"덧덩덫덮데덱덴델뎀뎁뎃뎄뎅뎌뎐뎔뎠뎡뎨뎬도독돈돋돌돎돐돔돕돗동돛돝돠돤돨돼됐되된될됨됩됫됴두둑둔둘둠둡둣둥둬뒀뒈뒝뒤뒨뒬뒵뒷뒹듀듄듈듐듕드득든듣들듦듬듭듯등듸디딕딘딛딜딤딥딧딨딩딪따딱딴딸\"],[\"b641\",\"턅\",7,\"턎\",17],[\"b661\",\"턠\",15,\"턲턳턵턶턷턹턻턼턽턾\"],[\"b681\",\"턿텂텆\",5,\"텎텏텑텒텓텕\",6,\"텞텠텢\",5,\"텩텪텫텭땀땁땃땄땅땋때땍땐땔땜땝땟땠땡떠떡떤떨떪떫떰떱떳떴떵떻떼떽뗀뗄뗌뗍뗏뗐뗑뗘뗬또똑똔똘똥똬똴뙈뙤뙨뚜뚝뚠뚤뚫뚬뚱뛔뛰뛴뛸뜀뜁뜅뜨뜩뜬뜯뜰뜸뜹뜻띄띈띌띔띕띠띤띨띰띱띳띵라락란랄람랍랏랐랑랒랖랗\"],[\"b741\",\"텮\",13,\"텽\",6,\"톅톆톇톉톊\"],[\"b761\",\"톋\",20,\"톢톣톥톦톧\"],[\"b781\",\"톩\",6,\"톲톴톶톷톸톹톻톽톾톿퇁\",14,\"래랙랜랠램랩랫랬랭랴략랸럇량러럭런럴럼럽럿렀렁렇레렉렌렐렘렙렛렝려력련렬렴렵렷렸령례롄롑롓로록론롤롬롭롯롱롸롼뢍뢨뢰뢴뢸룀룁룃룅료룐룔룝룟룡루룩룬룰룸룹룻룽뤄뤘뤠뤼뤽륀륄륌륏륑류륙륜률륨륩\"],[\"b841\",\"퇐\",7,\"퇙\",17],[\"b861\",\"퇫\",8,\"퇵퇶퇷퇹\",13],[\"b881\",\"툈툊\",5,\"툑\",24,\"륫륭르륵른를름릅릇릉릊릍릎리릭린릴림립릿링마막만많\",4,\"맘맙맛망맞맡맣매맥맨맬맴맵맷맸맹맺먀먁먈먕머먹먼멀멂멈멉멋멍멎멓메멕멘멜멤멥멧멨멩며멱면멸몃몄명몇몌모목몫몬몰몲몸몹못몽뫄뫈뫘뫙뫼\"],[\"b941\",\"툪툫툮툯툱툲툳툵\",6,\"툾퉀퉂\",5,\"퉉퉊퉋퉌\"],[\"b961\",\"퉍\",14,\"퉝\",6,\"퉥퉦퉧퉨\"],[\"b981\",\"퉩\",22,\"튂튃튅튆튇튉튊튋튌묀묄묍묏묑묘묜묠묩묫무묵묶문묻물묽묾뭄뭅뭇뭉뭍뭏뭐뭔뭘뭡뭣뭬뮈뮌뮐뮤뮨뮬뮴뮷므믄믈믐믓미믹민믿밀밂밈밉밋밌밍및밑바\",4,\"받\",4,\"밤밥밧방밭배백밴밸뱀뱁뱃뱄뱅뱉뱌뱍뱐뱝버벅번벋벌벎범법벗\"],[\"ba41\",\"튍튎튏튒튓튔튖\",5,\"튝튞튟튡튢튣튥\",6,\"튭\"],[\"ba61\",\"튮튯튰튲\",5,\"튺튻튽튾틁틃\",4,\"틊틌\",5],[\"ba81\",\"틒틓틕틖틗틙틚틛틝\",6,\"틦\",9,\"틲틳틵틶틷틹틺벙벚베벡벤벧벨벰벱벳벴벵벼벽변별볍볏볐병볕볘볜보복볶본볼봄봅봇봉봐봔봤봬뵀뵈뵉뵌뵐뵘뵙뵤뵨부북분붇불붉붊붐붑붓붕붙붚붜붤붰붸뷔뷕뷘뷜뷩뷰뷴뷸븀븃븅브븍븐블븜븝븟비빅빈빌빎빔빕빗빙빚빛빠빡빤\"],[\"bb41\",\"틻\",4,\"팂팄팆\",5,\"팏팑팒팓팕팗\",4,\"팞팢팣\"],[\"bb61\",\"팤팦팧팪팫팭팮팯팱\",6,\"팺팾\",5,\"퍆퍇퍈퍉\"],[\"bb81\",\"퍊\",31,\"빨빪빰빱빳빴빵빻빼빽뺀뺄뺌뺍뺏뺐뺑뺘뺙뺨뻐뻑뻔뻗뻘뻠뻣뻤뻥뻬뼁뼈뼉뼘뼙뼛뼜뼝뽀뽁뽄뽈뽐뽑뽕뾔뾰뿅뿌뿍뿐뿔뿜뿟뿡쀼쁑쁘쁜쁠쁨쁩삐삑삔삘삠삡삣삥사삭삯산삳살삵삶삼삽삿샀상샅새색샌샐샘샙샛샜생샤\"],[\"bc41\",\"퍪\",17,\"퍾퍿펁펂펃펅펆펇\"],[\"bc61\",\"펈펉펊펋펎펒\",5,\"펚펛펝펞펟펡\",6,\"펪펬펮\"],[\"bc81\",\"펯\",4,\"펵펶펷펹펺펻펽\",6,\"폆폇폊\",5,\"폑\",5,\"샥샨샬샴샵샷샹섀섄섈섐섕서\",4,\"섣설섦섧섬섭섯섰성섶세섹센셀셈셉셋셌셍셔셕션셜셤셥셧셨셩셰셴셸솅소속솎손솔솖솜솝솟송솥솨솩솬솰솽쇄쇈쇌쇔쇗쇘쇠쇤쇨쇰쇱쇳쇼쇽숀숄숌숍숏숑수숙순숟술숨숩숫숭\"],[\"bd41\",\"폗폙\",7,\"폢폤\",7,\"폮폯폱폲폳폵폶폷\"],[\"bd61\",\"폸폹폺폻폾퐀퐂\",5,\"퐉\",13],[\"bd81\",\"퐗\",5,\"퐞\",25,\"숯숱숲숴쉈쉐쉑쉔쉘쉠쉥쉬쉭쉰쉴쉼쉽쉿슁슈슉슐슘슛슝스슥슨슬슭슴습슷승시식신싣실싫심십싯싱싶싸싹싻싼쌀쌈쌉쌌쌍쌓쌔쌕쌘쌜쌤쌥쌨쌩썅써썩썬썰썲썸썹썼썽쎄쎈쎌쏀쏘쏙쏜쏟쏠쏢쏨쏩쏭쏴쏵쏸쐈쐐쐤쐬쐰\"],[\"be41\",\"퐸\",7,\"푁푂푃푅\",14],[\"be61\",\"푔\",7,\"푝푞푟푡푢푣푥\",7,\"푮푰푱푲\"],[\"be81\",\"푳\",4,\"푺푻푽푾풁풃\",4,\"풊풌풎\",5,\"풕\",8,\"쐴쐼쐽쑈쑤쑥쑨쑬쑴쑵쑹쒀쒔쒜쒸쒼쓩쓰쓱쓴쓸쓺쓿씀씁씌씐씔씜씨씩씬씰씸씹씻씽아악안앉않알앍앎앓암압앗았앙앝앞애액앤앨앰앱앳앴앵야약얀얄얇얌얍얏양얕얗얘얜얠얩어억언얹얻얼얽얾엄\",6,\"엌엎\"],[\"bf41\",\"풞\",10,\"풪\",14],[\"bf61\",\"풹\",18,\"퓍퓎퓏퓑퓒퓓퓕\"],[\"bf81\",\"퓖\",5,\"퓝퓞퓠\",7,\"퓩퓪퓫퓭퓮퓯퓱\",6,\"퓹퓺퓼에엑엔엘엠엡엣엥여역엮연열엶엷염\",5,\"옅옆옇예옌옐옘옙옛옜오옥온올옭옮옰옳옴옵옷옹옻와왁완왈왐왑왓왔왕왜왝왠왬왯왱외왹왼욀욈욉욋욍요욕욘욜욤욥욧용우욱운울욹욺움웁웃웅워웍원월웜웝웠웡웨\"],[\"c041\",\"퓾\",5,\"픅픆픇픉픊픋픍\",6,\"픖픘\",5],[\"c061\",\"픞\",25],[\"c081\",\"픸픹픺픻픾픿핁핂핃핅\",6,\"핎핐핒\",5,\"핚핛핝핞핟핡핢핣웩웬웰웸웹웽위윅윈윌윔윕윗윙유육윤율윰윱윳융윷으윽은을읊음읍읏응\",7,\"읜읠읨읫이익인일읽읾잃임입잇있잉잊잎자작잔잖잗잘잚잠잡잣잤장잦재잭잰잴잼잽잿쟀쟁쟈쟉쟌쟎쟐쟘쟝쟤쟨쟬저적전절젊\"],[\"c141\",\"핤핦핧핪핬핮\",5,\"핶핷핹핺핻핽\",6,\"햆햊햋\"],[\"c161\",\"햌햍햎햏햑\",19,\"햦햧\"],[\"c181\",\"햨\",31,\"점접젓정젖제젝젠젤젬젭젯젱져젼졀졈졉졌졍졔조족존졸졺좀좁좃종좆좇좋좌좍좔좝좟좡좨좼좽죄죈죌죔죕죗죙죠죡죤죵주죽준줄줅줆줌줍줏중줘줬줴쥐쥑쥔쥘쥠쥡쥣쥬쥰쥴쥼즈즉즌즐즘즙즛증지직진짇질짊짐집짓\"],[\"c241\",\"헊헋헍헎헏헑헓\",4,\"헚헜헞\",5,\"헦헧헩헪헫헭헮\"],[\"c261\",\"헯\",4,\"헶헸헺\",5,\"혂혃혅혆혇혉\",6,\"혒\"],[\"c281\",\"혖\",5,\"혝혞혟혡혢혣혥\",7,\"혮\",9,\"혺혻징짖짙짚짜짝짠짢짤짧짬짭짯짰짱째짹짼쨀쨈쨉쨋쨌쨍쨔쨘쨩쩌쩍쩐쩔쩜쩝쩟쩠쩡쩨쩽쪄쪘쪼쪽쫀쫄쫌쫍쫏쫑쫓쫘쫙쫠쫬쫴쬈쬐쬔쬘쬠쬡쭁쭈쭉쭌쭐쭘쭙쭝쭤쭸쭹쮜쮸쯔쯤쯧쯩찌찍찐찔찜찝찡찢찧차착찬찮찰참찹찻\"],[\"c341\",\"혽혾혿홁홂홃홄홆홇홊홌홎홏홐홒홓홖홗홙홚홛홝\",4],[\"c361\",\"홢\",4,\"홨홪\",5,\"홲홳홵\",11],[\"c381\",\"횁횂횄횆\",5,\"횎횏횑횒횓횕\",7,\"횞횠횢\",5,\"횩횪찼창찾채책챈챌챔챕챗챘챙챠챤챦챨챰챵처척천철첨첩첫첬청체첵첸첼쳄쳅쳇쳉쳐쳔쳤쳬쳰촁초촉촌촐촘촙촛총촤촨촬촹최쵠쵤쵬쵭쵯쵱쵸춈추축춘출춤춥춧충춰췄췌췐취췬췰췸췹췻췽츄츈츌츔츙츠측츤츨츰츱츳층\"],[\"c441\",\"횫횭횮횯횱\",7,\"횺횼\",7,\"훆훇훉훊훋\"],[\"c461\",\"훍훎훏훐훒훓훕훖훘훚\",5,\"훡훢훣훥훦훧훩\",4],[\"c481\",\"훮훯훱훲훳훴훶\",5,\"훾훿휁휂휃휅\",11,\"휒휓휔치칙친칟칠칡침칩칫칭카칵칸칼캄캅캇캉캐캑캔캘캠캡캣캤캥캬캭컁커컥컨컫컬컴컵컷컸컹케켁켄켈켐켑켓켕켜켠켤켬켭켯켰켱켸코콕콘콜콤콥콧콩콰콱콴콸쾀쾅쾌쾡쾨쾰쿄쿠쿡쿤쿨쿰쿱쿳쿵쿼퀀퀄퀑퀘퀭퀴퀵퀸퀼\"],[\"c541\",\"휕휖휗휚휛휝휞휟휡\",6,\"휪휬휮\",5,\"휶휷휹\"],[\"c561\",\"휺휻휽\",6,\"흅흆흈흊\",5,\"흒흓흕흚\",4],[\"c581\",\"흟흢흤흦흧흨흪흫흭흮흯흱흲흳흵\",6,\"흾흿힀힂\",5,\"힊힋큄큅큇큉큐큔큘큠크큭큰클큼큽킁키킥킨킬킴킵킷킹타탁탄탈탉탐탑탓탔탕태택탠탤탬탭탯탰탱탸턍터턱턴털턺텀텁텃텄텅테텍텐텔템텝텟텡텨텬텼톄톈토톡톤톨톰톱톳통톺톼퇀퇘퇴퇸툇툉툐투툭툰툴툼툽툿퉁퉈퉜\"],[\"c641\",\"힍힎힏힑\",6,\"힚힜힞\",5],[\"c6a1\",\"퉤튀튁튄튈튐튑튕튜튠튤튬튱트특튼튿틀틂틈틉틋틔틘틜틤틥티틱틴틸팀팁팃팅파팍팎판팔팖팜팝팟팠팡팥패팩팬팰팸팹팻팼팽퍄퍅퍼퍽펀펄펌펍펏펐펑페펙펜펠펨펩펫펭펴편펼폄폅폈평폐폘폡폣포폭폰폴폼폽폿퐁\"],[\"c7a1\",\"퐈퐝푀푄표푠푤푭푯푸푹푼푿풀풂품풉풋풍풔풩퓌퓐퓔퓜퓟퓨퓬퓰퓸퓻퓽프픈플픔픕픗피픽핀필핌핍핏핑하학한할핥함합핫항해핵핸핼햄햅햇했행햐향허헉헌헐헒험헙헛헝헤헥헨헬헴헵헷헹혀혁현혈혐협혓혔형혜혠\"],[\"c8a1\",\"혤혭호혹혼홀홅홈홉홋홍홑화확환활홧황홰홱홴횃횅회획횐횔횝횟횡효횬횰횹횻후훅훈훌훑훔훗훙훠훤훨훰훵훼훽휀휄휑휘휙휜휠휨휩휫휭휴휵휸휼흄흇흉흐흑흔흖흗흘흙흠흡흣흥흩희흰흴흼흽힁히힉힌힐힘힙힛힝\"],[\"caa1\",\"伽佳假價加可呵哥嘉嫁家暇架枷柯歌珂痂稼苛茄街袈訶賈跏軻迦駕刻却各恪慤殼珏脚覺角閣侃刊墾奸姦干幹懇揀杆柬桿澗癎看磵稈竿簡肝艮艱諫間乫喝曷渴碣竭葛褐蝎鞨勘坎堪嵌感憾戡敢柑橄減甘疳監瞰紺邯鑑鑒龕\"],[\"cba1\",\"匣岬甲胛鉀閘剛堈姜岡崗康强彊慷江畺疆糠絳綱羌腔舡薑襁講鋼降鱇介价個凱塏愷愾慨改槪漑疥皆盖箇芥蓋豈鎧開喀客坑更粳羹醵倨去居巨拒据據擧渠炬祛距踞車遽鉅鋸乾件健巾建愆楗腱虔蹇鍵騫乞傑杰桀儉劍劒檢\"],[\"cca1\",\"瞼鈐黔劫怯迲偈憩揭擊格檄激膈覡隔堅牽犬甄絹繭肩見譴遣鵑抉決潔結缺訣兼慊箝謙鉗鎌京俓倞傾儆勁勍卿坰境庚徑慶憬擎敬景暻更梗涇炅烱璟璥瓊痙硬磬竟競絅經耕耿脛莖警輕逕鏡頃頸驚鯨係啓堺契季屆悸戒桂械\"],[\"cda1\",\"棨溪界癸磎稽系繫繼計誡谿階鷄古叩告呱固姑孤尻庫拷攷故敲暠枯槁沽痼皐睾稿羔考股膏苦苽菰藁蠱袴誥賈辜錮雇顧高鼓哭斛曲梏穀谷鵠困坤崑昆梱棍滾琨袞鯤汨滑骨供公共功孔工恐恭拱控攻珙空蚣貢鞏串寡戈果瓜\"],[\"cea1\",\"科菓誇課跨過鍋顆廓槨藿郭串冠官寬慣棺款灌琯瓘管罐菅觀貫關館刮恝括适侊光匡壙廣曠洸炚狂珖筐胱鑛卦掛罫乖傀塊壞怪愧拐槐魁宏紘肱轟交僑咬喬嬌嶠巧攪敎校橋狡皎矯絞翹膠蕎蛟較轎郊餃驕鮫丘久九仇俱具勾\"],[\"cfa1\",\"區口句咎嘔坵垢寇嶇廐懼拘救枸柩構歐毆毬求溝灸狗玖球瞿矩究絿耉臼舅舊苟衢謳購軀逑邱鉤銶駒驅鳩鷗龜國局菊鞠鞫麴君窘群裙軍郡堀屈掘窟宮弓穹窮芎躬倦券勸卷圈拳捲權淃眷厥獗蕨蹶闕机櫃潰詭軌饋句晷歸貴\"],[\"d0a1\",\"鬼龜叫圭奎揆槻珪硅窺竅糾葵規赳逵閨勻均畇筠菌鈞龜橘克剋劇戟棘極隙僅劤勤懃斤根槿瑾筋芹菫覲謹近饉契今妗擒昑檎琴禁禽芩衾衿襟金錦伋及急扱汲級給亘兢矜肯企伎其冀嗜器圻基埼夔奇妓寄岐崎己幾忌技旗旣\"],[\"d1a1\",\"朞期杞棋棄機欺氣汽沂淇玘琦琪璂璣畸畿碁磯祁祇祈祺箕紀綺羈耆耭肌記譏豈起錡錤飢饑騎騏驥麒緊佶吉拮桔金喫儺喇奈娜懦懶拏拿癩\",5,\"那樂\",4,\"諾酪駱亂卵暖欄煖爛蘭難鸞捏捺南嵐枏楠湳濫男藍襤拉\"],[\"d2a1\",\"納臘蠟衲囊娘廊\",4,\"乃來內奈柰耐冷女年撚秊念恬拈捻寧寗努勞奴弩怒擄櫓爐瑙盧\",5,\"駑魯\",10,\"濃籠聾膿農惱牢磊腦賂雷尿壘\",7,\"嫩訥杻紐勒\",5,\"能菱陵尼泥匿溺多茶\"],[\"d3a1\",\"丹亶但單團壇彖斷旦檀段湍短端簞緞蛋袒鄲鍛撻澾獺疸達啖坍憺擔曇淡湛潭澹痰聃膽蕁覃談譚錟沓畓答踏遝唐堂塘幢戇撞棠當糖螳黨代垈坮大對岱帶待戴擡玳臺袋貸隊黛宅德悳倒刀到圖堵塗導屠島嶋度徒悼挑掉搗桃\"],[\"d4a1\",\"棹櫂淘渡滔濤燾盜睹禱稻萄覩賭跳蹈逃途道都鍍陶韜毒瀆牘犢獨督禿篤纛讀墩惇敦旽暾沌焞燉豚頓乭突仝冬凍動同憧東桐棟洞潼疼瞳童胴董銅兜斗杜枓痘竇荳讀豆逗頭屯臀芚遁遯鈍得嶝橙燈登等藤謄鄧騰喇懶拏癩羅\"],[\"d5a1\",\"蘿螺裸邏樂洛烙珞絡落諾酪駱丹亂卵欄欒瀾爛蘭鸞剌辣嵐擥攬欖濫籃纜藍襤覽拉臘蠟廊朗浪狼琅瑯螂郞來崍徠萊冷掠略亮倆兩凉梁樑粮粱糧良諒輛量侶儷勵呂廬慮戾旅櫚濾礪藜蠣閭驢驪麗黎力曆歷瀝礫轢靂憐戀攣漣\"],[\"d6a1\",\"煉璉練聯蓮輦連鍊冽列劣洌烈裂廉斂殮濂簾獵令伶囹寧岺嶺怜玲笭羚翎聆逞鈴零靈領齡例澧禮醴隷勞怒撈擄櫓潞瀘爐盧老蘆虜路輅露魯鷺鹵碌祿綠菉錄鹿麓論壟弄朧瀧瓏籠聾儡瀨牢磊賂賚賴雷了僚寮廖料燎療瞭聊蓼\"],[\"d7a1\",\"遼鬧龍壘婁屢樓淚漏瘻累縷蔞褸鏤陋劉旒柳榴流溜瀏琉瑠留瘤硫謬類六戮陸侖倫崙淪綸輪律慄栗率隆勒肋凜凌楞稜綾菱陵俚利厘吏唎履悧李梨浬犁狸理璃異痢籬罹羸莉裏裡里釐離鯉吝潾燐璘藺躪隣鱗麟林淋琳臨霖砬\"],[\"d8a1\",\"立笠粒摩瑪痲碼磨馬魔麻寞幕漠膜莫邈万卍娩巒彎慢挽晩曼滿漫灣瞞萬蔓蠻輓饅鰻唜抹末沫茉襪靺亡妄忘忙望網罔芒茫莽輞邙埋妹媒寐昧枚梅每煤罵買賣邁魅脈貊陌驀麥孟氓猛盲盟萌冪覓免冕勉棉沔眄眠綿緬面麵滅\"],[\"d9a1\",\"蔑冥名命明暝椧溟皿瞑茗蓂螟酩銘鳴袂侮冒募姆帽慕摸摹暮某模母毛牟牡瑁眸矛耗芼茅謀謨貌木沐牧目睦穆鶩歿沒夢朦蒙卯墓妙廟描昴杳渺猫竗苗錨務巫憮懋戊拇撫无楙武毋無珷畝繆舞茂蕪誣貿霧鵡墨默們刎吻問文\"],[\"daa1\",\"汶紊紋聞蚊門雯勿沕物味媚尾嵋彌微未梶楣渼湄眉米美薇謎迷靡黴岷悶愍憫敏旻旼民泯玟珉緡閔密蜜謐剝博拍搏撲朴樸泊珀璞箔粕縛膊舶薄迫雹駁伴半反叛拌搬攀斑槃泮潘班畔瘢盤盼磐磻礬絆般蟠返頒飯勃拔撥渤潑\"],[\"dba1\",\"發跋醱鉢髮魃倣傍坊妨尨幇彷房放方旁昉枋榜滂磅紡肪膀舫芳蒡蚌訪謗邦防龐倍俳北培徘拜排杯湃焙盃背胚裴裵褙賠輩配陪伯佰帛柏栢白百魄幡樊煩燔番磻繁蕃藩飜伐筏罰閥凡帆梵氾汎泛犯範范法琺僻劈壁擘檗璧癖\"],[\"dca1\",\"碧蘗闢霹便卞弁變辨辯邊別瞥鱉鼈丙倂兵屛幷昞昺柄棅炳甁病秉竝輧餠騈保堡報寶普步洑湺潽珤甫菩補褓譜輔伏僕匐卜宓復服福腹茯蔔複覆輹輻馥鰒本乶俸奉封峯峰捧棒烽熢琫縫蓬蜂逢鋒鳳不付俯傅剖副否咐埠夫婦\"],[\"dda1\",\"孚孵富府復扶敷斧浮溥父符簿缶腐腑膚艀芙莩訃負賦賻赴趺部釜阜附駙鳧北分吩噴墳奔奮忿憤扮昐汾焚盆粉糞紛芬賁雰不佛弗彿拂崩朋棚硼繃鵬丕備匕匪卑妃婢庇悲憊扉批斐枇榧比毖毗毘沸泌琵痺砒碑秕秘粃緋翡肥\"],[\"dea1\",\"脾臂菲蜚裨誹譬費鄙非飛鼻嚬嬪彬斌檳殯浜濱瀕牝玭貧賓頻憑氷聘騁乍事些仕伺似使俟僿史司唆嗣四士奢娑寫寺射巳師徙思捨斜斯柶査梭死沙泗渣瀉獅砂社祀祠私篩紗絲肆舍莎蓑蛇裟詐詞謝賜赦辭邪飼駟麝削數朔索\"],[\"dfa1\",\"傘刪山散汕珊産疝算蒜酸霰乷撒殺煞薩三參杉森渗芟蔘衫揷澁鈒颯上傷像償商喪嘗孀尙峠常床庠廂想桑橡湘爽牀狀相祥箱翔裳觴詳象賞霜塞璽賽嗇塞穡索色牲生甥省笙墅壻嶼序庶徐恕抒捿敍暑曙書栖棲犀瑞筮絮緖署\"],[\"e0a1\",\"胥舒薯西誓逝鋤黍鼠夕奭席惜昔晳析汐淅潟石碩蓆釋錫仙僊先善嬋宣扇敾旋渲煽琁瑄璇璿癬禪線繕羨腺膳船蘚蟬詵跣選銑鐥饍鮮卨屑楔泄洩渫舌薛褻設說雪齧剡暹殲纖蟾贍閃陝攝涉燮葉城姓宬性惺成星晟猩珹盛省筬\"],[\"e1a1\",\"聖聲腥誠醒世勢歲洗稅笹細說貰召嘯塑宵小少巢所掃搔昭梳沼消溯瀟炤燒甦疏疎瘙笑篠簫素紹蔬蕭蘇訴逍遡邵銷韶騷俗屬束涑粟續謖贖速孫巽損蓀遜飡率宋悚松淞訟誦送頌刷殺灑碎鎖衰釗修受嗽囚垂壽嫂守岫峀帥愁\"],[\"e2a1\",\"戍手授搜收數樹殊水洙漱燧狩獸琇璲瘦睡秀穗竪粹綏綬繡羞脩茱蒐蓚藪袖誰讐輸遂邃酬銖銹隋隧隨雖需須首髓鬚叔塾夙孰宿淑潚熟琡璹肅菽巡徇循恂旬栒楯橓殉洵淳珣盾瞬筍純脣舜荀蓴蕣詢諄醇錞順馴戌術述鉥崇崧\"],[\"e3a1\",\"嵩瑟膝蝨濕拾習褶襲丞乘僧勝升承昇繩蠅陞侍匙嘶始媤尸屎屍市弑恃施是時枾柴猜矢示翅蒔蓍視試詩諡豕豺埴寔式息拭植殖湜熄篒蝕識軾食飾伸侁信呻娠宸愼新晨燼申神紳腎臣莘薪藎蜃訊身辛辰迅失室實悉審尋心沁\"],[\"e4a1\",\"沈深瀋甚芯諶什十拾雙氏亞俄兒啞娥峨我牙芽莪蛾衙訝阿雅餓鴉鵝堊岳嶽幄惡愕握樂渥鄂鍔顎鰐齷安岸按晏案眼雁鞍顔鮟斡謁軋閼唵岩巖庵暗癌菴闇壓押狎鴨仰央怏昻殃秧鴦厓哀埃崖愛曖涯碍艾隘靄厄扼掖液縊腋額\"],[\"e5a1\",\"櫻罌鶯鸚也倻冶夜惹揶椰爺耶若野弱掠略約若葯蒻藥躍亮佯兩凉壤孃恙揚攘敭暘梁楊樣洋瀁煬痒瘍禳穰糧羊良襄諒讓釀陽量養圄御於漁瘀禦語馭魚齬億憶抑檍臆偃堰彦焉言諺孼蘖俺儼嚴奄掩淹嶪業円予余勵呂女如廬\"],[\"e6a1\",\"旅歟汝濾璵礖礪與艅茹輿轝閭餘驪麗黎亦力域役易曆歷疫繹譯轢逆驛嚥堧姸娟宴年延憐戀捐挻撚椽沇沿涎涓淵演漣烟然煙煉燃燕璉硏硯秊筵緣練縯聯衍軟輦蓮連鉛鍊鳶列劣咽悅涅烈熱裂說閱厭廉念捻染殮炎焰琰艶苒\"],[\"e7a1\",\"簾閻髥鹽曄獵燁葉令囹塋寧嶺嶸影怜映暎楹榮永泳渶潁濚瀛瀯煐營獰玲瑛瑩瓔盈穎纓羚聆英詠迎鈴鍈零霙靈領乂倪例刈叡曳汭濊猊睿穢芮藝蘂禮裔詣譽豫醴銳隸霓預五伍俉傲午吾吳嗚塢墺奧娛寤悟惡懊敖旿晤梧汚澳\"],[\"e8a1\",\"烏熬獒筽蜈誤鰲鼇屋沃獄玉鈺溫瑥瘟穩縕蘊兀壅擁瓮甕癰翁邕雍饔渦瓦窩窪臥蛙蝸訛婉完宛梡椀浣玩琓琬碗緩翫脘腕莞豌阮頑曰往旺枉汪王倭娃歪矮外嵬巍猥畏了僚僥凹堯夭妖姚寥寮尿嶢拗搖撓擾料曜樂橈燎燿瑤療\"],[\"e9a1\",\"窈窯繇繞耀腰蓼蟯要謠遙遼邀饒慾欲浴縟褥辱俑傭冗勇埇墉容庸慂榕涌湧溶熔瑢用甬聳茸蓉踊鎔鏞龍于佑偶優又友右宇寓尤愚憂旴牛玗瑀盂祐禑禹紆羽芋藕虞迂遇郵釪隅雨雩勖彧旭昱栯煜稶郁頊云暈橒殞澐熉耘芸蕓\"],[\"eaa1\",\"運隕雲韻蔚鬱亐熊雄元原員圓園垣媛嫄寃怨愿援沅洹湲源爰猿瑗苑袁轅遠阮院願鴛月越鉞位偉僞危圍委威尉慰暐渭爲瑋緯胃萎葦蔿蝟衛褘謂違韋魏乳侑儒兪劉唯喩孺宥幼幽庾悠惟愈愉揄攸有杻柔柚柳楡楢油洧流游溜\"],[\"eba1\",\"濡猶猷琉瑜由留癒硫紐維臾萸裕誘諛諭踰蹂遊逾遺酉釉鍮類六堉戮毓肉育陸倫允奫尹崙淪潤玧胤贇輪鈗閏律慄栗率聿戎瀜絨融隆垠恩慇殷誾銀隱乙吟淫蔭陰音飮揖泣邑凝應膺鷹依倚儀宜意懿擬椅毅疑矣義艤薏蟻衣誼\"],[\"eca1\",\"議醫二以伊利吏夷姨履已弛彛怡易李梨泥爾珥理異痍痢移罹而耳肄苡荑裏裡貽貳邇里離飴餌匿溺瀷益翊翌翼謚人仁刃印吝咽因姻寅引忍湮燐璘絪茵藺蚓認隣靭靷鱗麟一佚佾壹日溢逸鎰馹任壬妊姙恁林淋稔臨荏賃入卄\"],[\"eda1\",\"立笠粒仍剩孕芿仔刺咨姉姿子字孜恣慈滋炙煮玆瓷疵磁紫者自茨蔗藉諮資雌作勺嚼斫昨灼炸爵綽芍酌雀鵲孱棧殘潺盞岑暫潛箴簪蠶雜丈仗匠場墻壯奬將帳庄張掌暲杖樟檣欌漿牆狀獐璋章粧腸臟臧莊葬蔣薔藏裝贓醬長\"],[\"eea1\",\"障再哉在宰才材栽梓渽滓災縡裁財載齋齎爭箏諍錚佇低儲咀姐底抵杵楮樗沮渚狙猪疽箸紵苧菹著藷詛貯躇這邸雎齟勣吊嫡寂摘敵滴狄炙的積笛籍績翟荻謫賊赤跡蹟迪迹適鏑佃佺傳全典前剪塡塼奠專展廛悛戰栓殿氈澱\"],[\"efa1\",\"煎琠田甸畑癲筌箋箭篆纏詮輾轉鈿銓錢鐫電顚顫餞切截折浙癤竊節絶占岾店漸点粘霑鮎點接摺蝶丁井亭停偵呈姃定幀庭廷征情挺政整旌晶晸柾楨檉正汀淀淨渟湞瀞炡玎珽町睛碇禎程穽精綎艇訂諪貞鄭酊釘鉦鋌錠霆靖\"],[\"f0a1\",\"靜頂鼎制劑啼堤帝弟悌提梯濟祭第臍薺製諸蹄醍除際霽題齊俎兆凋助嘲弔彫措操早晁曺曹朝條棗槽漕潮照燥爪璪眺祖祚租稠窕粗糟組繰肇藻蚤詔調趙躁造遭釣阻雕鳥族簇足鏃存尊卒拙猝倧宗從悰慫棕淙琮種終綜縱腫\"],[\"f1a1\",\"踪踵鍾鐘佐坐左座挫罪主住侏做姝胄呪周嗾奏宙州廚晝朱柱株注洲湊澍炷珠疇籌紂紬綢舟蛛註誅走躊輳週酎酒鑄駐竹粥俊儁准埈寯峻晙樽浚準濬焌畯竣蠢逡遵雋駿茁中仲衆重卽櫛楫汁葺增憎曾拯烝甑症繒蒸證贈之只\"],[\"f2a1\",\"咫地址志持指摯支旨智枝枳止池沚漬知砥祉祗紙肢脂至芝芷蜘誌識贄趾遲直稙稷織職唇嗔塵振搢晉晋桭榛殄津溱珍瑨璡畛疹盡眞瞋秦縉縝臻蔯袗診賑軫辰進鎭陣陳震侄叱姪嫉帙桎瓆疾秩窒膣蛭質跌迭斟朕什執潗緝輯\"],[\"f3a1\",\"鏶集徵懲澄且侘借叉嗟嵯差次此磋箚茶蹉車遮捉搾着窄錯鑿齪撰澯燦璨瓚竄簒纂粲纘讚贊鑽餐饌刹察擦札紮僭參塹慘慙懺斬站讒讖倉倡創唱娼廠彰愴敞昌昶暢槍滄漲猖瘡窓脹艙菖蒼債埰寀寨彩採砦綵菜蔡采釵冊柵策\"],[\"f4a1\",\"責凄妻悽處倜刺剔尺慽戚拓擲斥滌瘠脊蹠陟隻仟千喘天川擅泉淺玔穿舛薦賤踐遷釧闡阡韆凸哲喆徹撤澈綴輟轍鐵僉尖沾添甛瞻簽籤詹諂堞妾帖捷牒疊睫諜貼輒廳晴淸聽菁請靑鯖切剃替涕滯締諦逮遞體初剿哨憔抄招梢\"],[\"f5a1\",\"椒楚樵炒焦硝礁礎秒稍肖艸苕草蕉貂超酢醋醮促囑燭矗蜀觸寸忖村邨叢塚寵悤憁摠總聰蔥銃撮催崔最墜抽推椎楸樞湫皺秋芻萩諏趨追鄒酋醜錐錘鎚雛騶鰍丑畜祝竺筑築縮蓄蹙蹴軸逐春椿瑃出朮黜充忠沖蟲衝衷悴膵萃\"],[\"f6a1\",\"贅取吹嘴娶就炊翠聚脆臭趣醉驟鷲側仄厠惻測層侈値嗤峙幟恥梔治淄熾痔痴癡稚穉緇緻置致蚩輜雉馳齒則勅飭親七柒漆侵寢枕沈浸琛砧針鍼蟄秤稱快他咤唾墮妥惰打拖朶楕舵陀馱駝倬卓啄坼度托拓擢晫柝濁濯琢琸託\"],[\"f7a1\",\"鐸呑嘆坦彈憚歎灘炭綻誕奪脫探眈耽貪塔搭榻宕帑湯糖蕩兌台太怠態殆汰泰笞胎苔跆邰颱宅擇澤撑攄兎吐土討慟桶洞痛筒統通堆槌腿褪退頹偸套妬投透鬪慝特闖坡婆巴把播擺杷波派爬琶破罷芭跛頗判坂板版瓣販辦鈑\"],[\"f8a1\",\"阪八叭捌佩唄悖敗沛浿牌狽稗覇貝彭澎烹膨愎便偏扁片篇編翩遍鞭騙貶坪平枰萍評吠嬖幣廢弊斃肺蔽閉陛佈包匍匏咆哺圃布怖抛抱捕暴泡浦疱砲胞脯苞葡蒲袍褒逋鋪飽鮑幅暴曝瀑爆輻俵剽彪慓杓標漂瓢票表豹飇飄驃\"],[\"f9a1\",\"品稟楓諷豊風馮彼披疲皮被避陂匹弼必泌珌畢疋筆苾馝乏逼下何厦夏廈昰河瑕荷蝦賀遐霞鰕壑學虐謔鶴寒恨悍旱汗漢澣瀚罕翰閑閒限韓割轄函含咸啣喊檻涵緘艦銜陷鹹合哈盒蛤閤闔陜亢伉姮嫦巷恒抗杭桁沆港缸肛航\"],[\"faa1\",\"行降項亥偕咳垓奚孩害懈楷海瀣蟹解該諧邂駭骸劾核倖幸杏荇行享向嚮珦鄕響餉饗香噓墟虛許憲櫶獻軒歇險驗奕爀赫革俔峴弦懸晛泫炫玄玹現眩睍絃絢縣舷衒見賢鉉顯孑穴血頁嫌俠協夾峽挾浹狹脅脇莢鋏頰亨兄刑型\"],[\"fba1\",\"形泂滎瀅灐炯熒珩瑩荊螢衡逈邢鎣馨兮彗惠慧暳蕙蹊醯鞋乎互呼壕壺好岵弧戶扈昊晧毫浩淏湖滸澔濠濩灝狐琥瑚瓠皓祜糊縞胡芦葫蒿虎號蝴護豪鎬頀顥惑或酷婚昏混渾琿魂忽惚笏哄弘汞泓洪烘紅虹訌鴻化和嬅樺火畵\"],[\"fca1\",\"禍禾花華話譁貨靴廓擴攫確碻穫丸喚奐宦幻患換歡晥桓渙煥環紈還驩鰥活滑猾豁闊凰幌徨恍惶愰慌晃晄榥況湟滉潢煌璜皇篁簧荒蝗遑隍黃匯回廻徊恢悔懷晦會檜淮澮灰獪繪膾茴蛔誨賄劃獲宖橫鐄哮嚆孝效斅曉梟涍淆\"],[\"fda1\",\"爻肴酵驍侯候厚后吼喉嗅帿後朽煦珝逅勛勳塤壎焄熏燻薰訓暈薨喧暄煊萱卉喙毁彙徽揮暉煇諱輝麾休携烋畦虧恤譎鷸兇凶匈洶胸黑昕欣炘痕吃屹紇訖欠欽歆吸恰洽翕興僖凞喜噫囍姬嬉希憙憘戱晞曦熙熹熺犧禧稀羲詰\"]]\n\n/***/ }),\n/* 184 */\n/***/ (function(module, exports) {\n\nmodule.exports = [[\"8740\",\"䏰䰲䘃䖦䕸𧉧䵷䖳𧲱䳢𧳅㮕䜶䝄䱇䱀𤊿𣘗𧍒𦺋𧃒䱗𪍑䝏䗚䲅𧱬䴇䪤䚡𦬣爥𥩔𡩣𣸆𣽡晍囻\"],[\"8767\",\"綕夝𨮹㷴霴𧯯寛𡵞媤㘥𩺰嫑宷峼杮薓𩥅瑡璝㡵𡵓𣚞𦀡㻬\"],[\"87a1\",\"𥣞㫵竼龗𤅡𨤍𣇪𠪊𣉞䌊蒄龖鐯䤰蘓墖靊鈘秐稲晠権袝瑌篅枂稬剏遆㓦珄𥶹瓆鿇垳䤯呌䄱𣚎堘穲𧭥讏䚮𦺈䆁𥶙箮𢒼鿈𢓁𢓉𢓌鿉蔄𣖻䂴鿊䓡𪷿拁灮鿋\"],[\"8840\",\"㇀\",4,\"𠄌㇅𠃑𠃍㇆㇇𠃋𡿨㇈𠃊㇉㇊㇋㇌𠄎㇍㇎ĀÁǍÀĒÉĚÈŌÓǑÒ࿿Ê̄Ế࿿Ê̌ỀÊāáǎàɑēéěèīíǐìōóǒòūúǔùǖǘǚ\"],[\"88a1\",\"ǜü࿿ê̄ế࿿ê̌ềêɡ⏚⏛\"],[\"8940\",\"𪎩𡅅\"],[\"8943\",\"攊\"],[\"8946\",\"丽滝鵎釟\"],[\"894c\",\"𧜵撑会伨侨兖兴农凤务动医华发变团声处备夲头学实実岚庆总斉柾栄桥济炼电纤纬纺织经统缆缷艺苏药视设询车轧轮\"],[\"89a1\",\"琑糼緍楆竉刧\"],[\"89ab\",\"醌碸酞肼\"],[\"89b0\",\"贋胶𠧧\"],[\"89b5\",\"肟黇䳍鷉鸌䰾𩷶𧀎鸊𪄳㗁\"],[\"89c1\",\"溚舾甙\"],[\"89c5\",\"䤑马骏龙禇𨑬𡷊𠗐𢫦两亁亀亇亿仫伷㑌侽㹈倃傈㑽㒓㒥円夅凛凼刅争剹劐匧㗇厩㕑厰㕓参吣㕭㕲㚁咓咣咴咹哐哯唘唣唨㖘唿㖥㖿嗗㗅\"],[\"8a40\",\"𧶄唥\"],[\"8a43\",\"𠱂𠴕𥄫喐𢳆㧬𠍁蹆𤶸𩓥䁓𨂾睺𢰸㨴䟕𨅝𦧲𤷪擝𠵼𠾴𠳕𡃴撍蹾𠺖𠰋𠽤𢲩𨉖𤓓\"],[\"8a64\",\"𠵆𩩍𨃩䟴𤺧𢳂骲㩧𩗴㿭㔆𥋇𩟔𧣈𢵄鵮頕\"],[\"8a76\",\"䏙𦂥撴哣𢵌𢯊𡁷㧻𡁯\"],[\"8aa1\",\"𦛚𦜖𧦠擪𥁒𠱃蹨𢆡𨭌𠜱\"],[\"8aac\",\"䠋𠆩㿺塳𢶍\"],[\"8ab2\",\"𤗈𠓼𦂗𠽌𠶖啹䂻䎺\"],[\"8abb\",\"䪴𢩦𡂝膪飵𠶜捹㧾𢝵跀嚡摼㹃\"],[\"8ac9\",\"𪘁𠸉𢫏𢳉\"],[\"8ace\",\"𡃈𣧂㦒㨆𨊛㕸𥹉𢃇噒𠼱𢲲𩜠㒼氽𤸻\"],[\"8adf\",\"𧕴𢺋𢈈𪙛𨳍𠹺𠰴𦠜羓𡃏𢠃𢤹㗻𥇣𠺌𠾍𠺪㾓𠼰𠵇𡅏𠹌\"],[\"8af6\",\"𠺫𠮩𠵈𡃀𡄽㿹𢚖搲𠾭\"],[\"8b40\",\"𣏴𧘹𢯎𠵾𠵿𢱑𢱕㨘𠺘𡃇𠼮𪘲𦭐𨳒𨶙𨳊閪哌苄喹\"],[\"8b55\",\"𩻃鰦骶𧝞𢷮煀腭胬尜𦕲脴㞗卟𨂽醶𠻺𠸏𠹷𠻻㗝𤷫㘉𠳖嚯𢞵𡃉𠸐𠹸𡁸𡅈𨈇𡑕𠹹𤹐𢶤婔𡀝𡀞𡃵𡃶垜𠸑\"],[\"8ba1\",\"𧚔𨋍𠾵𠹻𥅾㜃𠾶𡆀𥋘𪊽𤧚𡠺𤅷𨉼墙剨㘚𥜽箲孨䠀䬬鼧䧧鰟鮍𥭴𣄽嗻㗲嚉丨夂𡯁屮靑𠂆乛亻㔾尣彑忄㣺扌攵歺氵氺灬爫丬犭𤣩罒礻糹罓𦉪㓁\"],[\"8bde\",\"𦍋耂肀𦘒𦥑卝衤见𧢲讠贝钅镸长门𨸏韦页风飞饣𩠐鱼鸟黄歯龜丷𠂇阝户钢\"],[\"8c40\",\"倻淾𩱳龦㷉袏𤅎灷峵䬠𥇍㕙𥴰愢𨨲辧釶熑朙玺𣊁𪄇㲋𡦀䬐磤琂冮𨜏䀉橣𪊺䈣蘏𠩯稪𩥇𨫪靕灍匤𢁾鏴盙𨧣龧矝亣俰傼丯众龨吴綋墒壐𡶶庒庙忂𢜒斋\"],[\"8ca1\",\"𣏹椙橃𣱣泿\"],[\"8ca7\",\"爀𤔅玌㻛𤨓嬕璹讃𥲤𥚕窓篬糃繬苸薗龩袐龪躹龫迏蕟駠鈡龬𨶹𡐿䁱䊢娚\"],[\"8cc9\",\"顨杫䉶圽\"],[\"8cce\",\"藖𤥻芿𧄍䲁𦵴嵻𦬕𦾾龭龮宖龯曧繛湗秊㶈䓃𣉖𢞖䎚䔶\"],[\"8ce6\",\"峕𣬚諹屸㴒𣕑嵸龲煗䕘𤃬𡸣䱷㥸㑊𠆤𦱁諌侴𠈹妿腬顖𩣺弻\"],[\"8d40\",\"𠮟\"],[\"8d42\",\"𢇁𨥭䄂䚻𩁹㼇龳𪆵䃸㟖䛷𦱆䅼𨚲𧏿䕭㣔𥒚䕡䔛䶉䱻䵶䗪㿈𤬏㙡䓞䒽䇭崾嵈嵖㷼㠏嶤嶹㠠㠸幂庽弥徃㤈㤔㤿㥍惗愽峥㦉憷憹懏㦸戬抐拥挘㧸嚱\"],[\"8da1\",\"㨃揢揻搇摚㩋擀崕嘡龟㪗斆㪽旿晓㫲暒㬢朖㭂枤栀㭘桊梄㭲㭱㭻椉楃牜楤榟榅㮼槖㯝橥橴橱檂㯬檙㯲檫檵櫔櫶殁毁毪汵沪㳋洂洆洦涁㳯涤涱渕渘温溆𨧀溻滢滚齿滨滩漤漴㵆𣽁澁澾㵪㵵熷岙㶊瀬㶑灐灔灯灿炉𠌥䏁㗱𠻘\"],[\"8e40\",\"𣻗垾𦻓焾𥟠㙎榢𨯩孴穉𥣡𩓙穥穽𥦬窻窰竂竃燑𦒍䇊竚竝竪䇯咲𥰁笋筕笩𥌎𥳾箢筯莜𥮴𦱿篐萡箒箸𥴠㶭𥱥蒒篺簆簵𥳁籄粃𤢂粦晽𤕸糉糇糦籴糳糵糎\"],[\"8ea1\",\"繧䔝𦹄絝𦻖璍綉綫焵綳緒𤁗𦀩緤㴓緵𡟹緥𨍭縝𦄡𦅚繮纒䌫鑬縧罀罁罇礶𦋐駡羗𦍑羣𡙡𠁨䕜𣝦䔃𨌺翺𦒉者耈耝耨耯𪂇𦳃耻耼聡𢜔䦉𦘦𣷣𦛨朥肧𨩈脇脚墰𢛶汿𦒘𤾸擧𡒊舘𡡞橓𤩥𤪕䑺舩𠬍𦩒𣵾俹𡓽蓢荢𦬊𤦧𣔰𡝳𣷸芪椛芳䇛\"],[\"8f40\",\"蕋苐茚𠸖𡞴㛁𣅽𣕚艻苢茘𣺋𦶣𦬅𦮗𣗎㶿茝嗬莅䔋𦶥莬菁菓㑾𦻔橗蕚㒖𦹂𢻯葘𥯤葱㷓䓤檧葊𣲵祘蒨𦮖𦹷𦹃蓞萏莑䒠蒓蓤𥲑䉀𥳀䕃蔴嫲𦺙䔧蕳䔖枿蘖\"],[\"8fa1\",\"𨘥𨘻藁𧂈蘂𡖂𧃍䕫䕪蘨㙈𡢢号𧎚虾蝱𪃸蟮𢰧螱蟚蠏噡虬桖䘏衅衆𧗠𣶹𧗤衞袜䙛袴袵揁装睷𧜏覇覊覦覩覧覼𨨥觧𧤤𧪽誜瞓釾誐𧩙竩𧬺𣾏䜓𧬸煼謌謟𥐰𥕥謿譌譍誩𤩺讐讛誯𡛟䘕衏貛𧵔𧶏貫㜥𧵓賖𧶘𧶽贒贃𡤐賛灜贑𤳉㻐起\"],[\"9040\",\"趩𨀂𡀔𤦊㭼𨆼𧄌竧躭躶軃鋔輙輭𨍥𨐒辥錃𪊟𠩐辳䤪𨧞𨔽𣶻廸𣉢迹𪀔𨚼𨔁𢌥㦀𦻗逷𨔼𧪾遡𨕬𨘋邨𨜓郄𨛦邮都酧㫰醩釄粬𨤳𡺉鈎沟鉁鉢𥖹銹𨫆𣲛𨬌𥗛\"],[\"90a1\",\"𠴱錬鍫𨫡𨯫炏嫃𨫢𨫥䥥鉄𨯬𨰹𨯿鍳鑛躼閅閦鐦閠濶䊹𢙺𨛘𡉼𣸮䧟氜陻隖䅬隣𦻕懚隶磵𨫠隽双䦡𦲸𠉴𦐐𩂯𩃥𤫑𡤕𣌊霱虂霶䨏䔽䖅𤫩灵孁霛靜𩇕靗孊𩇫靟鐥僐𣂷𣂼鞉鞟鞱鞾韀韒韠𥑬韮琜𩐳響韵𩐝𧥺䫑頴頳顋顦㬎𧅵㵑𠘰𤅜\"],[\"9140\",\"𥜆飊颷飈飇䫿𦴧𡛓喰飡飦飬鍸餹𤨩䭲𩡗𩤅駵騌騻騐驘𥜥㛄𩂱𩯕髠髢𩬅髴䰎鬔鬭𨘀倴鬴𦦨㣃𣁽魐魀𩴾婅𡡣鮎𤉋鰂鯿鰌𩹨鷔𩾷𪆒𪆫𪃡𪄣𪇟鵾鶃𪄴鸎梈\"],[\"91a1\",\"鷄𢅛𪆓𪈠𡤻𪈳鴹𪂹𪊴麐麕麞麢䴴麪麯𤍤黁㭠㧥㴝伲㞾𨰫鼂鼈䮖鐤𦶢鼗鼖鼹嚟嚊齅馸𩂋韲葿齢齩竜龎爖䮾𤥵𤦻煷𤧸𤍈𤩑玞𨯚𡣺禟𨥾𨸶鍩鏳𨩄鋬鎁鏋𨥬𤒹爗㻫睲穃烐𤑳𤏸煾𡟯炣𡢾𣖙㻇𡢅𥐯𡟸㜢𡛻𡠹㛡𡝴𡣑𥽋㜣𡛀坛𤨥𡏾𡊨\"],[\"9240\",\"𡏆𡒶蔃𣚦蔃葕𤦔𧅥𣸱𥕜𣻻𧁒䓴𣛮𩦝𦼦柹㜳㰕㷧塬𡤢栐䁗𣜿𤃡𤂋𤄏𦰡哋嚞𦚱嚒𠿟𠮨𠸍鏆𨬓鎜仸儫㠙𤐶亼𠑥𠍿佋侊𥙑婨𠆫𠏋㦙𠌊𠐔㐵伩𠋀𨺳𠉵諚𠈌亘\"],[\"92a1\",\"働儍侢伃𤨎𣺊佂倮偬傁俌俥偘僼兙兛兝兞湶𣖕𣸹𣺿浲𡢄𣺉冨凃𠗠䓝𠒣𠒒𠒑赺𨪜𠜎剙劤𠡳勡鍮䙺熌𤎌𠰠𤦬𡃤槑𠸝瑹㻞璙琔瑖玘䮎𤪼𤂍叐㖄爏𤃉喴𠍅响𠯆圝鉝雴鍦埝垍坿㘾壋媙𨩆𡛺𡝯𡜐娬妸銏婾嫏娒𥥆𡧳𡡡𤊕㛵洅瑃娡𥺃\"],[\"9340\",\"媁𨯗𠐓鏠璌𡌃焅䥲鐈𨧻鎽㞠尞岞幞幈𡦖𡥼𣫮廍孏𡤃𡤄㜁𡢠㛝𡛾㛓脪𨩇𡶺𣑲𨦨弌弎𡤧𡞫婫𡜻孄蘔𧗽衠恾𢡠𢘫忛㺸𢖯𢖾𩂈𦽳懀𠀾𠁆𢘛憙憘恵𢲛𢴇𤛔𩅍\"],[\"93a1\",\"摱𤙥𢭪㨩𢬢𣑐𩣪𢹸挷𪑛撶挱揑𤧣𢵧护𢲡搻敫楲㯴𣂎𣊭𤦉𣊫唍𣋠𡣙𩐿曎𣊉𣆳㫠䆐𥖄𨬢𥖏𡛼𥕛𥐥磮𣄃𡠪𣈴㑤𣈏𣆂𤋉暎𦴤晫䮓昰𧡰𡷫晣𣋒𣋡昞𥡲㣑𣠺𣞼㮙𣞢𣏾瓐㮖枏𤘪梶栞㯄檾㡣𣟕𤒇樳橒櫉欅𡤒攑梘橌㯗橺歗𣿀𣲚鎠鋲𨯪𨫋\"],[\"9440\",\"銉𨀞𨧜鑧涥漋𤧬浧𣽿㶏渄𤀼娽渊塇洤硂焻𤌚𤉶烱牐犇犔𤞏𤜥兹𤪤𠗫瑺𣻸𣙟𤩊𤤗𥿡㼆㺱𤫟𨰣𣼵悧㻳瓌琼鎇琷䒟𦷪䕑疃㽣𤳙𤴆㽘畕癳𪗆㬙瑨𨫌𤦫𤦎㫻\"],[\"94a1\",\"㷍𤩎㻿𤧅𤣳釺圲鍂𨫣𡡤僟𥈡𥇧睸𣈲眎眏睻𤚗𣞁㩞𤣰琸璛㺿𤪺𤫇䃈𤪖𦆮錇𥖁砞碍碈磒珐祙𧝁𥛣䄎禛蒖禥樭𣻺稺秴䅮𡛦䄲鈵秱𠵌𤦌𠊙𣶺𡝮㖗啫㕰㚪𠇔𠰍竢婙𢛵𥪯𥪜娍𠉛磰娪𥯆竾䇹籝籭䈑𥮳𥺼𥺦糍𤧹𡞰粎籼粮檲緜縇緓罎𦉡\"],[\"9540\",\"𦅜𧭈綗𥺂䉪𦭵𠤖柖𠁎𣗏埄𦐒𦏸𤥢翝笧𠠬𥫩𥵃笌𥸎駦虅驣樜𣐿㧢𤧷𦖭騟𦖠蒀𧄧𦳑䓪脷䐂胆脉腂𦞴飃𦩂艢艥𦩑葓𦶧蘐𧈛媆䅿𡡀嬫𡢡嫤𡣘蚠蜨𣶏蠭𧐢娂\"],[\"95a1\",\"衮佅袇袿裦襥襍𥚃襔𧞅𧞄𨯵𨯙𨮜𨧹㺭蒣䛵䛏㟲訽訜𩑈彍鈫𤊄旔焩烄𡡅鵭貟賩𧷜妚矃姰䍮㛔踪躧𤰉輰轊䋴汘澻𢌡䢛潹溋𡟚鯩㚵𤤯邻邗啱䤆醻鐄𨩋䁢𨫼鐧𨰝𨰻蓥訫閙閧閗閖𨴴瑅㻂𤣿𤩂𤏪㻧𣈥随𨻧𨹦𨹥㻌𤧭𤩸𣿮琒瑫㻼靁𩂰\"],[\"9640\",\"桇䨝𩂓𥟟靝鍨𨦉𨰦𨬯𦎾銺嬑譩䤼珹𤈛鞛靱餸𠼦巁𨯅𤪲頟𩓚鋶𩗗釥䓀𨭐𤩧𨭤飜𨩅㼀鈪䤥萔餻饍𧬆㷽馛䭯馪驜𨭥𥣈檏騡嫾騯𩣱䮐𩥈馼䮽䮗鍽塲𡌂堢𤦸\"],[\"96a1\",\"𡓨硄𢜟𣶸棅㵽鑘㤧慐𢞁𢥫愇鱏鱓鱻鰵鰐魿鯏𩸭鮟𪇵𪃾鴡䲮𤄄鸘䲰鴌𪆴𪃭𪃳𩤯鶥蒽𦸒𦿟𦮂藼䔳𦶤𦺄𦷰萠藮𦸀𣟗𦁤秢𣖜𣙀䤭𤧞㵢鏛銾鍈𠊿碹鉷鑍俤㑀遤𥕝砽硔碶硋𡝗𣇉𤥁㚚佲濚濙瀞瀞吔𤆵垻壳垊鴖埗焴㒯𤆬燫𦱀𤾗嬨𡞵𨩉\"],[\"9740\",\"愌嫎娋䊼𤒈㜬䭻𨧼鎻鎸𡣖𠼝葲𦳀𡐓𤋺𢰦𤏁妔𣶷𦝁綨𦅛𦂤𤦹𤦋𨧺鋥珢㻩璴𨭣𡢟㻡𤪳櫘珳珻㻖𤨾𤪔𡟙𤩦𠎧𡐤𤧥瑈𤤖炥𤥶銄珦鍟𠓾錱𨫎𨨖鎆𨯧𥗕䤵𨪂煫\"],[\"97a1\",\"𤥃𠳿嚤𠘚𠯫𠲸唂秄𡟺緾𡛂𤩐𡡒䔮鐁㜊𨫀𤦭妰𡢿𡢃𧒄媡㛢𣵛㚰鉟婹𨪁𡡢鍴㳍𠪴䪖㦊僴㵩㵌𡎜煵䋻𨈘渏𩃤䓫浗𧹏灧沯㳖𣿭𣸭渂漌㵯𠏵畑㚼㓈䚀㻚䡱姄鉮䤾轁𨰜𦯀堒埈㛖𡑒烾𤍢𤩱𢿣𡊰𢎽梹楧𡎘𣓥𧯴𣛟𨪃𣟖𣏺𤲟樚𣚭𦲷萾䓟䓎\"],[\"9840\",\"𦴦𦵑𦲂𦿞漗𧄉茽𡜺菭𦲀𧁓𡟛妉媂𡞳婡婱𡤅𤇼㜭姯𡜼㛇熎鎐暚𤊥婮娫𤊓樫𣻹𧜶𤑛𤋊焝𤉙𨧡侰𦴨峂𤓎𧹍𤎽樌𤉖𡌄炦焳𤏩㶥泟勇𤩏繥姫崯㷳彜𤩝𡟟綤萦\"],[\"98a1\",\"咅𣫺𣌀𠈔坾𠣕𠘙㿥𡾞𪊶瀃𩅛嵰玏糓𨩙𩐠俈翧狍猐𧫴猸猹𥛶獁獈㺩𧬘遬燵𤣲珡臶㻊県㻑沢国琙琞琟㻢㻰㻴㻺瓓㼎㽓畂畭畲疍㽼痈痜㿀癍㿗癴㿜発𤽜熈嘣覀塩䀝睃䀹条䁅㗛瞘䁪䁯属瞾矋売砘点砜䂨砹硇硑硦葈𥔵礳栃礲䄃\"],[\"9940\",\"䄉禑禙辻稆込䅧窑䆲窼艹䇄竏竛䇏両筢筬筻簒簛䉠䉺类粜䊌粸䊔糭输烀𠳏総緔緐緽羮羴犟䎗耠耥笹耮耱联㷌垴炠肷胩䏭脌猪脎脒畠脔䐁㬹腖腙腚\"],[\"99a1\",\"䐓堺腼膄䐥膓䐭膥埯臁臤艔䒏芦艶苊苘苿䒰荗险榊萅烵葤惣蒈䔄蒾蓡蓸蔐蔸蕒䔻蕯蕰藠䕷虲蚒蚲蛯际螋䘆䘗袮裿褤襇覑𧥧訩訸誔誴豑賔賲贜䞘塟跃䟭仮踺嗘坔蹱嗵躰䠷軎転軤軭軲辷迁迊迌逳駄䢭飠鈓䤞鈨鉘鉫銱銮銿\"],[\"9a40\",\"鋣鋫鋳鋴鋽鍃鎄鎭䥅䥑麿鐗匁鐝鐭鐾䥪鑔鑹锭関䦧间阳䧥枠䨤靀䨵鞲韂噔䫤惨颹䬙飱塄餎餙冴餜餷饂饝饢䭰駅䮝騼鬏窃魩鮁鯝鯱鯴䱭鰠㝯𡯂鵉鰺\"],[\"9aa1\",\"黾噐鶓鶽鷀鷼银辶鹻麬麱麽黆铜黢黱黸竈齄𠂔𠊷𠎠椚铃妬𠓗塀铁㞹𠗕𠘕𠙶𡚺块煳𠫂𠫍𠮿呪吆𠯋咞𠯻𠰻𠱓𠱥𠱼惧𠲍噺𠲵𠳝𠳭𠵯𠶲𠷈楕鰯螥𠸄𠸎𠻗𠾐𠼭𠹳尠𠾼帋𡁜𡁏𡁶朞𡁻𡂈𡂖㙇𡂿𡃓𡄯𡄻卤蒭𡋣𡍵𡌶讁𡕷𡘙𡟃𡟇乸炻𡠭𡥪\"],[\"9b40\",\"𡨭𡩅𡰪𡱰𡲬𡻈拃𡻕𡼕熘桕𢁅槩㛈𢉼𢏗𢏺𢜪𢡱𢥏苽𢥧𢦓𢫕覥𢫨辠𢬎鞸𢬿顇骽𢱌\"],[\"9b62\",\"𢲈𢲷𥯨𢴈𢴒𢶷𢶕𢹂𢽴𢿌𣀳𣁦𣌟𣏞徱晈暿𧩹𣕧𣗳爁𤦺矗𣘚𣜖纇𠍆墵朎\"],[\"9ba1\",\"椘𣪧𧙗𥿢𣸑𣺹𧗾𢂚䣐䪸𤄙𨪚𤋮𤌍𤀻𤌴𤎖𤩅𠗊凒𠘑妟𡺨㮾𣳿𤐄𤓖垈𤙴㦛𤜯𨗨𩧉㝢𢇃譞𨭎駖𤠒𤣻𤨕爉𤫀𠱸奥𤺥𤾆𠝹軚𥀬劏圿煱𥊙𥐙𣽊𤪧喼𥑆𥑮𦭒釔㑳𥔿𧘲𥕞䜘𥕢𥕦𥟇𤤿𥡝偦㓻𣏌惞𥤃䝼𨥈𥪮𥮉𥰆𡶐垡煑澶𦄂𧰒遖𦆲𤾚譢𦐂𦑊\"],[\"9c40\",\"嵛𦯷輶𦒄𡤜諪𤧶𦒈𣿯𦔒䯀𦖿𦚵𢜛鑥𥟡憕娧晉侻嚹𤔡𦛼乪𤤴陖涏𦲽㘘襷𦞙𦡮𦐑𦡞營𦣇筂𩃀𠨑𦤦鄄𦤹穅鷰𦧺騦𦨭㙟𦑩𠀡禃𦨴𦭛崬𣔙菏𦮝䛐𦲤画补𦶮墶\"],[\"9ca1\",\"㜜𢖍𧁋𧇍㱔𧊀𧊅銁𢅺𧊋錰𧋦𤧐氹钟𧑐𠻸蠧裵𢤦𨑳𡞱溸𤨪𡠠㦤㚹尐秣䔿暶𩲭𩢤襃𧟌𧡘囖䃟𡘊㦡𣜯𨃨𡏅熭荦𧧝𩆨婧䲷𧂯𨦫𧧽𧨊𧬋𧵦𤅺筃祾𨀉澵𪋟樃𨌘厢𦸇鎿栶靝𨅯𨀣𦦵𡏭𣈯𨁈嶅𨰰𨂃圕頣𨥉嶫𤦈斾槕叒𤪥𣾁㰑朶𨂐𨃴𨄮𡾡𨅏\"],[\"9d40\",\"𨆉𨆯𨈚𨌆𨌯𨎊㗊𨑨𨚪䣺揦𨥖砈鉕𨦸䏲𨧧䏟𨧨𨭆𨯔姸𨰉輋𨿅𩃬筑𩄐𩄼㷷𩅞𤫊运犏嚋𩓧𩗩𩖰𩖸𩜲𩣑𩥉𩥪𩧃𩨨𩬎𩵚𩶛纟𩻸𩼣䲤镇𪊓熢𪋿䶑递𪗋䶜𠲜达嗁\"],[\"9da1\",\"辺𢒰边𤪓䔉繿潖檱仪㓤𨬬𧢝㜺躀𡟵𨀤𨭬𨮙𧨾𦚯㷫𧙕𣲷𥘵𥥖亚𥺁𦉘嚿𠹭踎孭𣺈𤲞揞拐𡟶𡡻攰嘭𥱊吚𥌑㷆𩶘䱽嘢嘞罉𥻘奵𣵀蝰东𠿪𠵉𣚺脗鵞贘瘻鱅癎瞹鍅吲腈苷嘥脲萘肽嗪祢噃吖𠺝㗎嘅嗱曱𨋢㘭甴嗰喺咗啲𠱁𠲖廐𥅈𠹶𢱢\"],[\"9e40\",\"𠺢麫絚嗞𡁵抝靭咔賍燶酶揼掹揾啩𢭃鱲𢺳冚㓟𠶧冧呍唞唓癦踭𦢊疱肶蠄螆裇膶萜𡃁䓬猄𤜆宐茋𦢓噻𢛴𧴯𤆣𧵳𦻐𧊶酰𡇙鈈𣳼𪚩𠺬𠻹牦𡲢䝎𤿂𧿹𠿫䃺\"],[\"9ea1\",\"鱝攟𢶠䣳𤟠𩵼𠿬𠸊恢𧖣𠿭\"],[\"9ead\",\"𦁈𡆇熣纎鵐业丄㕷嬍沲卧㚬㧜卽㚥𤘘墚𤭮舭呋垪𥪕𠥹\"],[\"9ec5\",\"㩒𢑥獴𩺬䴉鯭𣳾𩼰䱛𤾩𩖞𩿞葜𣶶𧊲𦞳𣜠挮紥𣻷𣸬㨪逈勌㹴㙺䗩𠒎癀嫰𠺶硺𧼮墧䂿噼鮋嵴癔𪐴麅䳡痹㟻愙𣃚𤏲\"],[\"9ef5\",\"噝𡊩垧𤥣𩸆刴𧂮㖭汊鵼\"],[\"9f40\",\"籖鬹埞𡝬屓擓𩓐𦌵𧅤蚭𠴨𦴢𤫢𠵱\"],[\"9f4f\",\"凾𡼏嶎霃𡷑麁遌笟鬂峑箣扨挵髿篏鬪籾鬮籂粆鰕篼鬉鼗鰛𤤾齚啳寃俽麘俲剠㸆勑坧偖妷帒韈鶫轜呩鞴饀鞺匬愰\"],[\"9fa1\",\"椬叚鰊鴂䰻陁榀傦畆𡝭駚剳\"],[\"9fae\",\"酙隁酜\"],[\"9fb2\",\"酑𨺗捿𦴣櫊嘑醎畺抅𠏼獏籰𥰡𣳽\"],[\"9fc1\",\"𤤙盖鮝个𠳔莾衂\"],[\"9fc9\",\"届槀僭坺刟巵从氱𠇲伹咜哚劚趂㗾弌㗳\"],[\"9fdb\",\"歒酼龥鮗頮颴骺麨麄煺笔\"],[\"9fe7\",\"毺蠘罸\"],[\"9feb\",\"嘠𪙊蹷齓\"],[\"9ff0\",\"跔蹏鸜踁抂𨍽踨蹵竓𤩷稾磘泪詧瘇\"],[\"a040\",\"𨩚鼦泎蟖痃𪊲硓咢贌狢獱謭猂瓱賫𤪻蘯徺袠䒷\"],[\"a055\",\"𡠻𦸅\"],[\"a058\",\"詾𢔛\"],[\"a05b\",\"惽癧髗鵄鍮鮏蟵\"],[\"a063\",\"蠏賷猬霡鮰㗖犲䰇籑饊𦅙慙䰄麖慽\"],[\"a073\",\"坟慯抦戹拎㩜懢厪𣏵捤栂㗒\"],[\"a0a1\",\"嵗𨯂迚𨸹\"],[\"a0a6\",\"僙𡵆礆匲阸𠼻䁥\"],[\"a0ae\",\"矾\"],[\"a0b0\",\"糂𥼚糚稭聦聣絍甅瓲覔舚朌聢𧒆聛瓰脃眤覉𦟌畓𦻑螩蟎臈螌詉貭譃眫瓸蓚㘵榲趦\"],[\"a0d4\",\"覩瑨涹蟁𤀑瓧㷛煶悤憜㳑煢恷\"],[\"a0e2\",\"罱𨬭牐惩䭾删㰘𣳇𥻗𧙖𥔱𡥄𡋾𩤃𦷜𧂭峁𦆭𨨏𣙷𠃮𦡆𤼎䕢嬟𦍌齐麦𦉫\"],[\"a3c0\",\"␀\",31,\"␡\"],[\"c6a1\",\"①\",9,\"⑴\",9,\"ⅰ\",9,\"丶丿亅亠冂冖冫勹匸卩厶夊宀巛⼳广廴彐彡攴无疒癶辵隶¨ˆヽヾゝゞ〃仝々〆〇ー［］✽ぁ\",23],[\"c740\",\"す\",58,\"ァアィイ\"],[\"c7a1\",\"ゥ\",81,\"А\",5,\"ЁЖ\",4],[\"c840\",\"Л\",26,\"ёж\",25,\"⇧↸↹㇏𠃌乚𠂊刂䒑\"],[\"c8a1\",\"龰冈龱𧘇\"],[\"c8cd\",\"￢￤＇＂㈱№℡゛゜⺀⺄⺆⺇⺈⺊⺌⺍⺕⺜⺝⺥⺧⺪⺬⺮⺶⺼⺾⻆⻊⻌⻍⻏⻖⻗⻞⻣\"],[\"c8f5\",\"ʃɐɛɔɵœøŋʊɪ\"],[\"f9fe\",\"￭\"],[\"fa40\",\"𠕇鋛𠗟𣿅蕌䊵珯况㙉𤥂𨧤鍄𡧛苮𣳈砼杄拟𤤳𨦪𠊠𦮳𡌅侫𢓭倈𦴩𧪄𣘀𤪱𢔓倩𠍾徤𠎀𠍇滛𠐟偽儁㑺儎顬㝃萖𤦤𠒇兠𣎴兪𠯿𢃼𠋥𢔰𠖎𣈳𡦃宂蝽𠖳𣲙冲冸\"],[\"faa1\",\"鴴凉减凑㳜凓𤪦决凢卂凭菍椾𣜭彻刋刦刼劵剗劔効勅簕蕂勠蘍𦬓包𨫞啉滙𣾀𠥔𣿬匳卄𠯢泋𡜦栛珕恊㺪㣌𡛨燝䒢卭却𨚫卾卿𡖖𡘓矦厓𨪛厠厫厮玧𥝲㽙玜叁叅汉义埾叙㪫𠮏叠𣿫𢶣叶𠱷吓灹唫晗浛呭𦭓𠵴啝咏咤䞦𡜍𠻝㶴𠵍\"],[\"fb40\",\"𨦼𢚘啇䳭启琗喆喩嘅𡣗𤀺䕒𤐵暳𡂴嘷曍𣊊暤暭噍噏磱囱鞇叾圀囯园𨭦㘣𡉏坆𤆥汮炋坂㚱𦱾埦𡐖堃𡑔𤍣堦𤯵塜墪㕡壠壜𡈼壻寿坃𪅐𤉸鏓㖡够梦㛃湙\"],[\"fba1\",\"𡘾娤啓𡚒蔅姉𠵎𦲁𦴪𡟜姙𡟻𡞲𦶦浱𡠨𡛕姹𦹅媫婣㛦𤦩婷㜈媖瑥嫓𦾡𢕔㶅𡤑㜲𡚸広勐孶斈孼𧨎䀄䡝𠈄寕慠𡨴𥧌𠖥寳宝䴐尅𡭄尓珎尔𡲥𦬨屉䣝岅峩峯嶋𡷹𡸷崐崘嵆𡺤岺巗苼㠭𤤁𢁉𢅳芇㠶㯂帮檊幵幺𤒼𠳓厦亷廐厨𡝱帉廴𨒂\"],[\"fc40\",\"廹廻㢠廼栾鐛弍𠇁弢㫞䢮𡌺强𦢈𢏐彘𢑱彣鞽𦹮彲鍀𨨶徧嶶㵟𥉐𡽪𧃸𢙨釖𠊞𨨩怱暅𡡷㥣㷇㘹垐𢞴祱㹀悞悤悳𤦂𤦏𧩓璤僡媠慤萤慂慈𦻒憁凴𠙖憇宪𣾷\"],[\"fca1\",\"𢡟懓𨮝𩥝懐㤲𢦀𢣁怣慜攞掋𠄘担𡝰拕𢸍捬𤧟㨗搸揸𡎎𡟼撐澊𢸶頔𤂌𥜝擡擥鑻㩦携㩗敍漖𤨨𤨣斅敭敟𣁾斵𤥀䬷旑䃘𡠩无旣忟𣐀昘𣇷𣇸晄𣆤𣆥晋𠹵晧𥇦晳晴𡸽𣈱𨗴𣇈𥌓矅𢣷馤朂𤎜𤨡㬫槺𣟂杞杧杢𤇍𩃭柗䓩栢湐鈼栁𣏦𦶠桝\"],[\"fd40\",\"𣑯槡樋𨫟楳棃𣗍椁椀㴲㨁𣘼㮀枬楡𨩊䋼椶榘㮡𠏉荣傐槹𣙙𢄪橅𣜃檝㯳枱櫈𩆜㰍欝𠤣惞欵歴𢟍溵𣫛𠎵𡥘㝀吡𣭚毡𣻼毜氷𢒋𤣱𦭑汚舦汹𣶼䓅𣶽𤆤𤤌𤤀\"],[\"fda1\",\"𣳉㛥㳫𠴲鮃𣇹𢒑羏样𦴥𦶡𦷫涖浜湼漄𤥿𤂅𦹲蔳𦽴凇沜渝萮𨬡港𣸯瑓𣾂秌湏媑𣁋濸㜍澝𣸰滺𡒗𤀽䕕鏰潄潜㵎潴𩅰㴻澟𤅄濓𤂑𤅕𤀹𣿰𣾴𤄿凟𤅖𤅗𤅀𦇝灋灾炧炁烌烕烖烟䄄㷨熴熖𤉷焫煅媈煊煮岜𤍥煏鍢𤋁焬𤑚𤨧𤨢熺𨯨炽爎\"],[\"fe40\",\"鑂爕夑鑃爤鍁𥘅爮牀𤥴梽牕牗㹕𣁄栍漽犂猪猫𤠣𨠫䣭𨠄猨献珏玪𠰺𦨮珉瑉𤇢𡛧𤨤昣㛅𤦷𤦍𤧻珷琕椃𤨦琹𠗃㻗瑜𢢭瑠𨺲瑇珤瑶莹瑬㜰瑴鏱樬璂䥓𤪌\"],[\"fea1\",\"𤅟𤩹𨮏孆𨰃𡢞瓈𡦈甎瓩甞𨻙𡩋寗𨺬鎅畍畊畧畮𤾂㼄𤴓疎瑝疞疴瘂瘬癑癏癯癶𦏵皐臯㟸𦤑𦤎皡皥皷盌𦾟葢𥂝𥅽𡸜眞眦着撯𥈠睘𣊬瞯𨥤𨥨𡛁矴砉𡍶𤨒棊碯磇磓隥礮𥗠磗礴碱𧘌辸袄𨬫𦂃𢘜禆褀椂禀𥡗禝𧬹礼禩渪𧄦㺨秆𩄍秔\"]]\n\n/***/ }),\n/* 185 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar Buffer = __webpack_require__(1).Buffer,\n    Transform = __webpack_require__(15).Transform;\n\n\n// == Exports ==================================================================\nmodule.exports = function(iconv) {\n    \n    // Additional Public API.\n    iconv.encodeStream = function encodeStream(encoding, options) {\n        return new IconvLiteEncoderStream(iconv.getEncoder(encoding, options), options);\n    }\n\n    iconv.decodeStream = function decodeStream(encoding, options) {\n        return new IconvLiteDecoderStream(iconv.getDecoder(encoding, options), options);\n    }\n\n    iconv.supportsStreams = true;\n\n\n    // Not published yet.\n    iconv.IconvLiteEncoderStream = IconvLiteEncoderStream;\n    iconv.IconvLiteDecoderStream = IconvLiteDecoderStream;\n    iconv._collect = IconvLiteDecoderStream.prototype.collect;\n};\n\n\n// == Encoder stream =======================================================\nfunction IconvLiteEncoderStream(conv, options) {\n    this.conv = conv;\n    options = options || {};\n    options.decodeStrings = false; // We accept only strings, so we don't need to decode them.\n    Transform.call(this, options);\n}\n\nIconvLiteEncoderStream.prototype = Object.create(Transform.prototype, {\n    constructor: { value: IconvLiteEncoderStream }\n});\n\nIconvLiteEncoderStream.prototype._transform = function(chunk, encoding, done) {\n    if (typeof chunk != 'string')\n        return done(new Error(\"Iconv encoding stream needs strings as its input.\"));\n    try {\n        var res = this.conv.write(chunk);\n        if (res && res.length) this.push(res);\n        done();\n    }\n    catch (e) {\n        done(e);\n    }\n}\n\nIconvLiteEncoderStream.prototype._flush = function(done) {\n    try {\n        var res = this.conv.end();\n        if (res && res.length) this.push(res);\n        done();\n    }\n    catch (e) {\n        done(e);\n    }\n}\n\nIconvLiteEncoderStream.prototype.collect = function(cb) {\n    var chunks = [];\n    this.on('error', cb);\n    this.on('data', function(chunk) { chunks.push(chunk); });\n    this.on('end', function() {\n        cb(null, Buffer.concat(chunks));\n    });\n    return this;\n}\n\n\n// == Decoder stream =======================================================\nfunction IconvLiteDecoderStream(conv, options) {\n    this.conv = conv;\n    options = options || {};\n    options.encoding = this.encoding = 'utf8'; // We output strings.\n    Transform.call(this, options);\n}\n\nIconvLiteDecoderStream.prototype = Object.create(Transform.prototype, {\n    constructor: { value: IconvLiteDecoderStream }\n});\n\nIconvLiteDecoderStream.prototype._transform = function(chunk, encoding, done) {\n    if (!Buffer.isBuffer(chunk))\n        return done(new Error(\"Iconv decoding stream needs buffers as its input.\"));\n    try {\n        var res = this.conv.write(chunk);\n        if (res && res.length) this.push(res, this.encoding);\n        done();\n    }\n    catch (e) {\n        done(e);\n    }\n}\n\nIconvLiteDecoderStream.prototype._flush = function(done) {\n    try {\n        var res = this.conv.end();\n        if (res && res.length) this.push(res, this.encoding);                \n        done();\n    }\n    catch (e) {\n        done(e);\n    }\n}\n\nIconvLiteDecoderStream.prototype.collect = function(cb) {\n    var res = '';\n    this.on('error', cb);\n    this.on('data', function(chunk) { res += chunk; });\n    this.on('end', function() {\n        cb(null, res);\n    });\n    return this;\n}\n\n\n\n/***/ }),\n/* 186 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar Buffer = __webpack_require__(1).Buffer;\n\n// == Extend Node primitives to use iconv-lite =================================\n\nmodule.exports = function (iconv) {\n    var original = undefined; // Place to keep original methods.\n\n    // Node authors rewrote Buffer internals to make it compatible with\n    // Uint8Array and we cannot patch key functions since then.\n    iconv.supportsNodeEncodingsExtension = !(new Buffer(0) instanceof Uint8Array);\n\n    iconv.extendNodeEncodings = function extendNodeEncodings() {\n        if (original) return;\n        original = {};\n\n        if (!iconv.supportsNodeEncodingsExtension) {\n            console.error(\"ACTION NEEDED: require('iconv-lite').extendNodeEncodings() is not supported in your version of Node\");\n            console.error(\"See more info at https://github.com/ashtuchkin/iconv-lite/wiki/Node-v4-compatibility\");\n            return;\n        }\n\n        var nodeNativeEncodings = {\n            'hex': true, 'utf8': true, 'utf-8': true, 'ascii': true, 'binary': true, \n            'base64': true, 'ucs2': true, 'ucs-2': true, 'utf16le': true, 'utf-16le': true,\n        };\n\n        Buffer.isNativeEncoding = function(enc) {\n            return enc && nodeNativeEncodings[enc.toLowerCase()];\n        }\n\n        // -- SlowBuffer -----------------------------------------------------------\n        var SlowBuffer = __webpack_require__(1).SlowBuffer;\n\n        original.SlowBufferToString = SlowBuffer.prototype.toString;\n        SlowBuffer.prototype.toString = function(encoding, start, end) {\n            encoding = String(encoding || 'utf8').toLowerCase();\n\n            // Use native conversion when possible\n            if (Buffer.isNativeEncoding(encoding))\n                return original.SlowBufferToString.call(this, encoding, start, end);\n\n            // Otherwise, use our decoding method.\n            if (typeof start == 'undefined') start = 0;\n            if (typeof end == 'undefined') end = this.length;\n            return iconv.decode(this.slice(start, end), encoding);\n        }\n\n        original.SlowBufferWrite = SlowBuffer.prototype.write;\n        SlowBuffer.prototype.write = function(string, offset, length, encoding) {\n            // Support both (string, offset, length, encoding)\n            // and the legacy (string, encoding, offset, length)\n            if (isFinite(offset)) {\n                if (!isFinite(length)) {\n                    encoding = length;\n                    length = undefined;\n                }\n            } else {  // legacy\n                var swap = encoding;\n                encoding = offset;\n                offset = length;\n                length = swap;\n            }\n\n            offset = +offset || 0;\n            var remaining = this.length - offset;\n            if (!length) {\n                length = remaining;\n            } else {\n                length = +length;\n                if (length > remaining) {\n                    length = remaining;\n                }\n            }\n            encoding = String(encoding || 'utf8').toLowerCase();\n\n            // Use native conversion when possible\n            if (Buffer.isNativeEncoding(encoding))\n                return original.SlowBufferWrite.call(this, string, offset, length, encoding);\n\n            if (string.length > 0 && (length < 0 || offset < 0))\n                throw new RangeError('attempt to write beyond buffer bounds');\n\n            // Otherwise, use our encoding method.\n            var buf = iconv.encode(string, encoding);\n            if (buf.length < length) length = buf.length;\n            buf.copy(this, offset, 0, length);\n            return length;\n        }\n\n        // -- Buffer ---------------------------------------------------------------\n\n        original.BufferIsEncoding = Buffer.isEncoding;\n        Buffer.isEncoding = function(encoding) {\n            return Buffer.isNativeEncoding(encoding) || iconv.encodingExists(encoding);\n        }\n\n        original.BufferByteLength = Buffer.byteLength;\n        Buffer.byteLength = SlowBuffer.byteLength = function(str, encoding) {\n            encoding = String(encoding || 'utf8').toLowerCase();\n\n            // Use native conversion when possible\n            if (Buffer.isNativeEncoding(encoding))\n                return original.BufferByteLength.call(this, str, encoding);\n\n            // Slow, I know, but we don't have a better way yet.\n            return iconv.encode(str, encoding).length;\n        }\n\n        original.BufferToString = Buffer.prototype.toString;\n        Buffer.prototype.toString = function(encoding, start, end) {\n            encoding = String(encoding || 'utf8').toLowerCase();\n\n            // Use native conversion when possible\n            if (Buffer.isNativeEncoding(encoding))\n                return original.BufferToString.call(this, encoding, start, end);\n\n            // Otherwise, use our decoding method.\n            if (typeof start == 'undefined') start = 0;\n            if (typeof end == 'undefined') end = this.length;\n            return iconv.decode(this.slice(start, end), encoding);\n        }\n\n        original.BufferWrite = Buffer.prototype.write;\n        Buffer.prototype.write = function(string, offset, length, encoding) {\n            var _offset = offset, _length = length, _encoding = encoding;\n            // Support both (string, offset, length, encoding)\n            // and the legacy (string, encoding, offset, length)\n            if (isFinite(offset)) {\n                if (!isFinite(length)) {\n                    encoding = length;\n                    length = undefined;\n                }\n            } else {  // legacy\n                var swap = encoding;\n                encoding = offset;\n                offset = length;\n                length = swap;\n            }\n\n            encoding = String(encoding || 'utf8').toLowerCase();\n\n            // Use native conversion when possible\n            if (Buffer.isNativeEncoding(encoding))\n                return original.BufferWrite.call(this, string, _offset, _length, _encoding);\n\n            offset = +offset || 0;\n            var remaining = this.length - offset;\n            if (!length) {\n                length = remaining;\n            } else {\n                length = +length;\n                if (length > remaining) {\n                    length = remaining;\n                }\n            }\n\n            if (string.length > 0 && (length < 0 || offset < 0))\n                throw new RangeError('attempt to write beyond buffer bounds');\n\n            // Otherwise, use our encoding method.\n            var buf = iconv.encode(string, encoding);\n            if (buf.length < length) length = buf.length;\n            buf.copy(this, offset, 0, length);\n            return length;\n\n            // TODO: Set _charsWritten.\n        }\n\n\n        // -- Readable -------------------------------------------------------------\n        if (iconv.supportsStreams) {\n            var Readable = __webpack_require__(15).Readable;\n\n            original.ReadableSetEncoding = Readable.prototype.setEncoding;\n            Readable.prototype.setEncoding = function setEncoding(enc, options) {\n                // Use our own decoder, it has the same interface.\n                // We cannot use original function as it doesn't handle BOM-s.\n                this._readableState.decoder = iconv.getDecoder(enc, options);\n                this._readableState.encoding = enc;\n            }\n\n            Readable.prototype.collect = iconv._collect;\n        }\n    }\n\n    // Remove iconv-lite Node primitive extensions.\n    iconv.undoExtendNodeEncodings = function undoExtendNodeEncodings() {\n        if (!iconv.supportsNodeEncodingsExtension)\n            return;\n        if (!original)\n            throw new Error(\"require('iconv-lite').undoExtendNodeEncodings(): Nothing to undo; extendNodeEncodings() is not called.\")\n\n        delete Buffer.isNativeEncoding;\n\n        var SlowBuffer = __webpack_require__(1).SlowBuffer;\n\n        SlowBuffer.prototype.toString = original.SlowBufferToString;\n        SlowBuffer.prototype.write = original.SlowBufferWrite;\n\n        Buffer.isEncoding = original.BufferIsEncoding;\n        Buffer.byteLength = original.BufferByteLength;\n        Buffer.prototype.toString = original.BufferToString;\n        Buffer.prototype.write = original.BufferWrite;\n\n        if (iconv.supportsStreams) {\n            var Readable = __webpack_require__(15).Readable;\n\n            Readable.prototype.setEncoding = original.ReadableSetEncoding;\n            delete Readable.prototype.collect;\n        }\n\n        original = undefined;\n    }\n}\n\n\n/***/ }),\n/* 187 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var ArrayT, LazyArray, LazyArrayT, NumberT, inspect, utils,\n    __hasProp = {}.hasOwnProperty,\n    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n  ArrayT = __webpack_require__(93);\n\n  NumberT = __webpack_require__(22).Number;\n\n  utils = __webpack_require__(12);\n\n  inspect = __webpack_require__(49).inspect;\n\n  LazyArrayT = (function(_super) {\n    __extends(LazyArrayT, _super);\n\n    function LazyArrayT() {\n      return LazyArrayT.__super__.constructor.apply(this, arguments);\n    }\n\n    LazyArrayT.prototype.decode = function(stream, parent) {\n      var length, pos, res;\n      pos = stream.pos;\n      length = utils.resolveLength(this.length, stream, parent);\n      if (this.length instanceof NumberT) {\n        parent = {\n          parent: parent,\n          _startOffset: pos,\n          _currentOffset: 0,\n          _length: length\n        };\n      }\n      res = new LazyArray(this.type, length, stream, parent);\n      stream.pos += length * this.type.size(null, parent);\n      return res;\n    };\n\n    LazyArrayT.prototype.size = function(val, ctx) {\n      if (val instanceof LazyArray) {\n        val = val.toArray();\n      }\n      return LazyArrayT.__super__.size.call(this, val, ctx);\n    };\n\n    LazyArrayT.prototype.encode = function(stream, val, ctx) {\n      if (val instanceof LazyArray) {\n        val = val.toArray();\n      }\n      return LazyArrayT.__super__.encode.call(this, stream, val, ctx);\n    };\n\n    return LazyArrayT;\n\n  })(ArrayT);\n\n  LazyArray = (function() {\n    function LazyArray(type, length, stream, ctx) {\n      this.type = type;\n      this.length = length;\n      this.stream = stream;\n      this.ctx = ctx;\n      this.base = this.stream.pos;\n      this.items = [];\n    }\n\n    LazyArray.prototype.get = function(index) {\n      var pos;\n      if (index < 0 || index >= this.length) {\n        return void 0;\n      }\n      if (this.items[index] == null) {\n        pos = this.stream.pos;\n        this.stream.pos = this.base + this.type.size(null, this.ctx) * index;\n        this.items[index] = this.type.decode(this.stream, this.ctx);\n        this.stream.pos = pos;\n      }\n      return this.items[index];\n    };\n\n    LazyArray.prototype.toArray = function() {\n      var i, _i, _ref, _results;\n      _results = [];\n      for (i = _i = 0, _ref = this.length; _i < _ref; i = _i += 1) {\n        _results.push(this.get(i));\n      }\n      return _results;\n    };\n\n    LazyArray.prototype.inspect = function() {\n      return inspect(this.toArray());\n    };\n\n    return LazyArray;\n\n  })();\n\n  module.exports = LazyArrayT;\n\n}).call(this);\n\n\n/***/ }),\n/* 188 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var Bitfield;\n\n  Bitfield = (function() {\n    function Bitfield(type, flags) {\n      this.type = type;\n      this.flags = flags != null ? flags : [];\n    }\n\n    Bitfield.prototype.decode = function(stream) {\n      var flag, i, res, val, _i, _len, _ref;\n      val = this.type.decode(stream);\n      res = {};\n      _ref = this.flags;\n      for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {\n        flag = _ref[i];\n        if (flag != null) {\n          res[flag] = !!(val & (1 << i));\n        }\n      }\n      return res;\n    };\n\n    Bitfield.prototype.size = function() {\n      return this.type.size();\n    };\n\n    Bitfield.prototype.encode = function(stream, keys) {\n      var flag, i, val, _i, _len, _ref;\n      val = 0;\n      _ref = this.flags;\n      for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {\n        flag = _ref[i];\n        if (flag != null) {\n          if (keys[flag]) {\n            val |= 1 << i;\n          }\n        }\n      }\n      return this.type.encode(stream, val);\n    };\n\n    return Bitfield;\n\n  })();\n\n  module.exports = Bitfield;\n\n}).call(this);\n\n\n/***/ }),\n/* 189 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var BooleanT;\n\n  BooleanT = (function() {\n    function BooleanT(type) {\n      this.type = type;\n    }\n\n    BooleanT.prototype.decode = function(stream, parent) {\n      return !!this.type.decode(stream, parent);\n    };\n\n    BooleanT.prototype.size = function(val, parent) {\n      return this.type.size(val, parent);\n    };\n\n    BooleanT.prototype.encode = function(stream, val, parent) {\n      return this.type.encode(stream, +val, parent);\n    };\n\n    return BooleanT;\n\n  })();\n\n  module.exports = BooleanT;\n\n}).call(this);\n\n\n/***/ }),\n/* 190 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var BufferT, NumberT, utils;\n\n  utils = __webpack_require__(12);\n\n  NumberT = __webpack_require__(22).Number;\n\n  BufferT = (function() {\n    function BufferT(length) {\n      this.length = length;\n    }\n\n    BufferT.prototype.decode = function(stream, parent) {\n      var length;\n      length = utils.resolveLength(this.length, stream, parent);\n      return stream.readBuffer(length);\n    };\n\n    BufferT.prototype.size = function(val, parent) {\n      if (!val) {\n        return utils.resolveLength(this.length, null, parent);\n      }\n      return val.length;\n    };\n\n    BufferT.prototype.encode = function(stream, buf, parent) {\n      if (this.length instanceof NumberT) {\n        this.length.encode(stream, buf.length);\n      }\n      return stream.writeBuffer(buf);\n    };\n\n    return BufferT;\n\n  })();\n\n  module.exports = BufferT;\n\n}).call(this);\n\n\n/***/ }),\n/* 191 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var Enum;\n\n  Enum = (function() {\n    function Enum(type, options) {\n      this.type = type;\n      this.options = options != null ? options : [];\n    }\n\n    Enum.prototype.decode = function(stream) {\n      var index;\n      index = this.type.decode(stream);\n      return this.options[index] || index;\n    };\n\n    Enum.prototype.size = function() {\n      return this.type.size();\n    };\n\n    Enum.prototype.encode = function(stream, val) {\n      var index;\n      index = this.options.indexOf(val);\n      if (index === -1) {\n        throw new Error(\"Unknown option in enum: \" + val);\n      }\n      return this.type.encode(stream, index);\n    };\n\n    return Enum;\n\n  })();\n\n  module.exports = Enum;\n\n}).call(this);\n\n\n/***/ }),\n/* 192 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var Optional;\n\n  Optional = (function() {\n    function Optional(type, condition) {\n      this.type = type;\n      this.condition = condition != null ? condition : true;\n    }\n\n    Optional.prototype.decode = function(stream, parent) {\n      var condition;\n      condition = this.condition;\n      if (typeof condition === 'function') {\n        condition = condition.call(parent, parent);\n      }\n      if (condition) {\n        return this.type.decode(stream, parent);\n      }\n    };\n\n    Optional.prototype.size = function(val, parent) {\n      var condition;\n      condition = this.condition;\n      if (typeof condition === 'function') {\n        condition = condition.call(parent, parent);\n      }\n      if (condition) {\n        return this.type.size(val, parent);\n      } else {\n        return 0;\n      }\n    };\n\n    Optional.prototype.encode = function(stream, val, parent) {\n      var condition;\n      condition = this.condition;\n      if (typeof condition === 'function') {\n        condition = condition.call(parent, parent);\n      }\n      if (condition) {\n        return this.type.encode(stream, val, parent);\n      }\n    };\n\n    return Optional;\n\n  })();\n\n  module.exports = Optional;\n\n}).call(this);\n\n\n/***/ }),\n/* 193 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var Reserved, utils;\n\n  utils = __webpack_require__(12);\n\n  Reserved = (function() {\n    function Reserved(type, count) {\n      this.type = type;\n      this.count = count != null ? count : 1;\n    }\n\n    Reserved.prototype.decode = function(stream, parent) {\n      stream.pos += this.size(null, parent);\n      return void 0;\n    };\n\n    Reserved.prototype.size = function(data, parent) {\n      var count;\n      count = utils.resolveLength(this.count, null, parent);\n      return this.type.size() * count;\n    };\n\n    Reserved.prototype.encode = function(stream, val, parent) {\n      return stream.fill(0, this.size(val, parent));\n    };\n\n    return Reserved;\n\n  })();\n\n  module.exports = Reserved;\n\n}).call(this);\n\n\n/***/ }),\n/* 194 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.7.1\n(function() {\n  var NumberT, StringT, utils;\n\n  NumberT = __webpack_require__(22).Number;\n\n  utils = __webpack_require__(12);\n\n  StringT = (function() {\n    function StringT(length, encoding) {\n      this.length = length;\n      this.encoding = encoding != null ? encoding : 'ascii';\n    }\n\n    StringT.prototype.decode = function(stream, parent) {\n      var buffer, encoding, length, pos, string;\n      length = (function() {\n        if (this.length != null) {\n          return utils.resolveLength(this.length, stream, parent);\n        } else {\n          buffer = stream.buffer, length = stream.length, pos = stream.pos;\n          while (pos < length && buffer[pos] !== 0x00) {\n            ++pos;\n          }\n          return pos - stream.pos;\n        }\n      }).call(this);\n      encoding = this.encoding;\n      if (typeof encoding === 'function') {\n        encoding = encoding.call(parent, parent) || 'ascii';\n      }\n      string = stream.readString(length, encoding);\n      if ((this.length == null) && stream.pos < stream.length) {\n        stream.pos++;\n      }\n      return string;\n    };\n\n    StringT.prototype.size = function(val, parent) {\n      var encoding, size;\n      if (!val) {\n        return utils.resolveLength(this.length, null, parent);\n      }\n      encoding = this.encoding;\n      if (typeof encoding === 'function') {\n        encoding = encoding.call(parent != null ? parent.val : void 0, parent != null ? parent.val : void 0) || 'ascii';\n      }\n      if (encoding === 'utf16be') {\n        encoding = 'utf16le';\n      }\n      size = Buffer.byteLength(val, encoding);\n      if (this.length instanceof NumberT) {\n        size += this.length.size();\n      }\n      if (this.length == null) {\n        size++;\n      }\n      return size;\n    };\n\n    StringT.prototype.encode = function(stream, val, parent) {\n      var encoding;\n      encoding = this.encoding;\n      if (typeof encoding === 'function') {\n        encoding = encoding.call(parent != null ? parent.val : void 0, parent != null ? parent.val : void 0) || 'ascii';\n      }\n      if (this.length instanceof NumberT) {\n        this.length.encode(stream, Buffer.byteLength(val, encoding));\n      }\n      stream.writeString(val, encoding);\n      if (this.length == null) {\n        return stream.writeUInt8(0x00);\n      }\n    };\n\n    return StringT;\n\n  })();\n\n  module.exports = StringT;\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 195 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var Struct, VersionedStruct,\n    __hasProp = {}.hasOwnProperty,\n    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n  Struct = __webpack_require__(94);\n\n  VersionedStruct = (function(_super) {\n    __extends(VersionedStruct, _super);\n\n    function VersionedStruct(type, versions) {\n      this.type = type;\n      this.versions = versions != null ? versions : {};\n      if (typeof this.type === 'string') {\n        this.versionGetter = new Function('parent', \"return parent.\" + this.type);\n        this.versionSetter = new Function('parent', 'version', \"return parent.\" + this.type + \" = version\");\n      }\n    }\n\n    VersionedStruct.prototype.decode = function(stream, parent, length) {\n      var fields, res, _ref;\n      if (length == null) {\n        length = 0;\n      }\n      res = this._setup(stream, parent, length);\n      if (typeof this.type === 'string') {\n        res.version = this.versionGetter(parent);\n      } else {\n        res.version = this.type.decode(stream);\n      }\n      if (this.versions.header) {\n        this._parseFields(stream, res, this.versions.header);\n      }\n      fields = this.versions[res.version];\n      if (fields == null) {\n        throw new Error(\"Unknown version \" + res.version);\n      }\n      if (fields instanceof VersionedStruct) {\n        return fields.decode(stream, parent);\n      }\n      this._parseFields(stream, res, fields);\n      if ((_ref = this.process) != null) {\n        _ref.call(res, stream);\n      }\n      return res;\n    };\n\n    VersionedStruct.prototype.size = function(val, parent, includePointers) {\n      var ctx, fields, key, size, type, _ref;\n      if (includePointers == null) {\n        includePointers = true;\n      }\n      if (!val) {\n        throw new Error('Not a fixed size');\n      }\n      ctx = {\n        parent: parent,\n        val: val,\n        pointerSize: 0\n      };\n      size = 0;\n      if (typeof this.type !== 'string') {\n        size += this.type.size(val.version, ctx);\n      }\n      if (this.versions.header) {\n        _ref = this.versions.header;\n        for (key in _ref) {\n          type = _ref[key];\n          if (type.size != null) {\n            size += type.size(val[key], ctx);\n          }\n        }\n      }\n      fields = this.versions[val.version];\n      if (fields == null) {\n        throw new Error(\"Unknown version \" + val.version);\n      }\n      for (key in fields) {\n        type = fields[key];\n        if (type.size != null) {\n          size += type.size(val[key], ctx);\n        }\n      }\n      if (includePointers) {\n        size += ctx.pointerSize;\n      }\n      return size;\n    };\n\n    VersionedStruct.prototype.encode = function(stream, val, parent) {\n      var ctx, fields, i, key, ptr, type, _ref, _ref1;\n      if ((_ref = this.preEncode) != null) {\n        _ref.call(val, stream);\n      }\n      ctx = {\n        pointers: [],\n        startOffset: stream.pos,\n        parent: parent,\n        val: val,\n        pointerSize: 0\n      };\n      ctx.pointerOffset = stream.pos + this.size(val, ctx, false);\n      if (typeof this.type !== 'string') {\n        this.type.encode(stream, val.version);\n      }\n      if (this.versions.header) {\n        _ref1 = this.versions.header;\n        for (key in _ref1) {\n          type = _ref1[key];\n          if (type.encode != null) {\n            type.encode(stream, val[key], ctx);\n          }\n        }\n      }\n      fields = this.versions[val.version];\n      for (key in fields) {\n        type = fields[key];\n        if (type.encode != null) {\n          type.encode(stream, val[key], ctx);\n        }\n      }\n      i = 0;\n      while (i < ctx.pointers.length) {\n        ptr = ctx.pointers[i++];\n        ptr.type.encode(stream, ptr.val, ptr.parent);\n      }\n    };\n\n    return VersionedStruct;\n\n  })(Struct);\n\n  module.exports = VersionedStruct;\n\n}).call(this);\n\n\n/***/ }),\n/* 196 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.7.1\n(function() {\n  var Pointer, VoidPointer, utils;\n\n  utils = __webpack_require__(12);\n\n  Pointer = (function() {\n    function Pointer(offsetType, type, options) {\n      var _base, _base1, _base2, _base3;\n      this.offsetType = offsetType;\n      this.type = type;\n      this.options = options != null ? options : {};\n      if (this.type === 'void') {\n        this.type = null;\n      }\n      if ((_base = this.options).type == null) {\n        _base.type = 'local';\n      }\n      if ((_base1 = this.options).allowNull == null) {\n        _base1.allowNull = true;\n      }\n      if ((_base2 = this.options).nullValue == null) {\n        _base2.nullValue = 0;\n      }\n      if ((_base3 = this.options).lazy == null) {\n        _base3.lazy = false;\n      }\n      if (this.options.relativeTo) {\n        this.relativeToGetter = new Function('ctx', \"return ctx.\" + this.options.relativeTo);\n      }\n    }\n\n    Pointer.prototype.decode = function(stream, ctx) {\n      var c, decodeValue, offset, ptr, relative, val;\n      offset = this.offsetType.decode(stream, ctx);\n      if (offset === this.options.nullValue && this.options.allowNull) {\n        return null;\n      }\n      relative = (function() {\n        switch (this.options.type) {\n          case 'local':\n            return ctx._startOffset;\n          case 'immediate':\n            return stream.pos - this.offsetType.size();\n          case 'parent':\n            return ctx.parent._startOffset;\n          default:\n            c = ctx;\n            while (c.parent) {\n              c = c.parent;\n            }\n            return c._startOffset || 0;\n        }\n      }).call(this);\n      if (this.options.relativeTo) {\n        relative += this.relativeToGetter(ctx);\n      }\n      ptr = offset + relative;\n      if (this.type != null) {\n        val = null;\n        decodeValue = (function(_this) {\n          return function() {\n            var pos;\n            if (val != null) {\n              return val;\n            }\n            pos = stream.pos;\n            stream.pos = ptr;\n            val = _this.type.decode(stream, ctx);\n            stream.pos = pos;\n            return val;\n          };\n        })(this);\n        if (this.options.lazy) {\n          return new utils.PropertyDescriptor({\n            get: decodeValue\n          });\n        }\n        return decodeValue();\n      } else {\n        return ptr;\n      }\n    };\n\n    Pointer.prototype.size = function(val, ctx) {\n      var parent, type;\n      parent = ctx;\n      switch (this.options.type) {\n        case 'local':\n        case 'immediate':\n          break;\n        case 'parent':\n          ctx = ctx.parent;\n          break;\n        default:\n          while (ctx.parent) {\n            ctx = ctx.parent;\n          }\n      }\n      type = this.type;\n      if (type == null) {\n        if (!(val instanceof VoidPointer)) {\n          throw new Error(\"Must be a VoidPointer\");\n        }\n        type = val.type;\n        val = val.value;\n      }\n      if (val && ctx) {\n        ctx.pointerSize += type.size(val, parent);\n      }\n      return this.offsetType.size();\n    };\n\n    Pointer.prototype.encode = function(stream, val, ctx) {\n      var parent, relative, type;\n      parent = ctx;\n      if (val == null) {\n        this.offsetType.encode(stream, this.options.nullValue);\n        return;\n      }\n      switch (this.options.type) {\n        case 'local':\n          relative = ctx.startOffset;\n          break;\n        case 'immediate':\n          relative = stream.pos + this.offsetType.size(val, parent);\n          break;\n        case 'parent':\n          ctx = ctx.parent;\n          relative = ctx.startOffset;\n          break;\n        default:\n          relative = 0;\n          while (ctx.parent) {\n            ctx = ctx.parent;\n          }\n      }\n      if (this.options.relativeTo) {\n        relative += this.relativeToGetter(parent.val);\n      }\n      this.offsetType.encode(stream, ctx.pointerOffset - relative);\n      type = this.type;\n      if (type == null) {\n        if (!(val instanceof VoidPointer)) {\n          throw new Error(\"Must be a VoidPointer\");\n        }\n        type = val.type;\n        val = val.value;\n      }\n      ctx.pointers.push({\n        type: type,\n        val: val,\n        parent: parent\n      });\n      return ctx.pointerOffset += type.size(val, parent);\n    };\n\n    return Pointer;\n\n  })();\n\n  VoidPointer = (function() {\n    function VoidPointer(type, value) {\n      this.type = type;\n      this.value = value;\n    }\n\n    return VoidPointer;\n\n  })();\n\n  exports.Pointer = Pointer;\n\n  exports.VoidPointer = VoidPointer;\n\n}).call(this);\n\n\n/***/ }),\n/* 197 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(198), __esModule: true };\n\n/***/ }),\n/* 198 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(199);\nvar $Object = __webpack_require__(2).Object;\nmodule.exports = function getOwnPropertyDescriptor(it, key) {\n  return $Object.getOwnPropertyDescriptor(it, key);\n};\n\n\n/***/ }),\n/* 199 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.2.6 Object.getOwnPropertyDescriptor(O, P)\nvar toIObject = __webpack_require__(17);\nvar $getOwnPropertyDescriptor = __webpack_require__(57).f;\n\n__webpack_require__(59)('getOwnPropertyDescriptor', function () {\n  return function getOwnPropertyDescriptor(it, key) {\n    return $getOwnPropertyDescriptor(toIObject(it), key);\n  };\n});\n\n\n/***/ }),\n/* 200 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(28);\n__webpack_require__(24);\nmodule.exports = __webpack_require__(208);\n\n\n/***/ }),\n/* 201 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar addToUnscopables = __webpack_require__(202);\nvar step = __webpack_require__(98);\nvar Iterators = __webpack_require__(23);\nvar toIObject = __webpack_require__(17);\n\n// 22.1.3.4 Array.prototype.entries()\n// 22.1.3.13 Array.prototype.keys()\n// 22.1.3.29 Array.prototype.values()\n// 22.1.3.30 Array.prototype[@@iterator]()\nmodule.exports = __webpack_require__(61)(Array, 'Array', function (iterated, kind) {\n  this._t = toIObject(iterated); // target\n  this._i = 0;                   // next index\n  this._k = kind;                // kind\n// 22.1.5.2.1 %ArrayIteratorPrototype%.next()\n}, function () {\n  var O = this._t;\n  var kind = this._k;\n  var index = this._i++;\n  if (!O || index >= O.length) {\n    this._t = undefined;\n    return step(1);\n  }\n  if (kind == 'keys') return step(0, index);\n  if (kind == 'values') return step(0, O[index]);\n  return step(0, [index, O[index]]);\n}, 'values');\n\n// argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7)\nIterators.Arguments = Iterators.Array;\n\naddToUnscopables('keys');\naddToUnscopables('values');\naddToUnscopables('entries');\n\n\n/***/ }),\n/* 202 */\n/***/ (function(module, exports) {\n\nmodule.exports = function () { /* empty */ };\n\n\n/***/ }),\n/* 203 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar create = __webpack_require__(36);\nvar descriptor = __webpack_require__(27);\nvar setToStringTag = __webpack_require__(39);\nvar IteratorPrototype = {};\n\n// 25.1.2.1.1 %IteratorPrototype%[@@iterator]()\n__webpack_require__(13)(IteratorPrototype, __webpack_require__(4)('iterator'), function () { return this; });\n\nmodule.exports = function (Constructor, NAME, next) {\n  Constructor.prototype = create(IteratorPrototype, { next: descriptor(1, next) });\n  setToStringTag(Constructor, NAME + ' Iterator');\n};\n\n\n/***/ }),\n/* 204 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// false -> Array#indexOf\n// true  -> Array#includes\nvar toIObject = __webpack_require__(17);\nvar toLength = __webpack_require__(37);\nvar toAbsoluteIndex = __webpack_require__(102);\nmodule.exports = function (IS_INCLUDES) {\n  return function ($this, el, fromIndex) {\n    var O = toIObject($this);\n    var length = toLength(O.length);\n    var index = toAbsoluteIndex(fromIndex, length);\n    var value;\n    // Array#includes uses SameValueZero equality algorithm\n    // eslint-disable-next-line no-self-compare\n    if (IS_INCLUDES && el != el) while (length > index) {\n      value = O[index++];\n      // eslint-disable-next-line no-self-compare\n      if (value != value) return true;\n    // Array#indexOf ignores holes, Array#includes - not\n    } else for (;length > index; index++) if (IS_INCLUDES || index in O) {\n      if (O[index] === el) return IS_INCLUDES || index || 0;\n    } return !IS_INCLUDES && -1;\n  };\n};\n\n\n/***/ }),\n/* 205 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar document = __webpack_require__(10).document;\nmodule.exports = document && document.documentElement;\n\n\n/***/ }),\n/* 206 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O)\nvar has = __webpack_require__(18);\nvar toObject = __webpack_require__(30);\nvar IE_PROTO = __webpack_require__(64)('IE_PROTO');\nvar ObjectProto = Object.prototype;\n\nmodule.exports = Object.getPrototypeOf || function (O) {\n  O = toObject(O);\n  if (has(O, IE_PROTO)) return O[IE_PROTO];\n  if (typeof O.constructor == 'function' && O instanceof O.constructor) {\n    return O.constructor.prototype;\n  } return O instanceof Object ? ObjectProto : null;\n};\n\n\n/***/ }),\n/* 207 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar toInteger = __webpack_require__(63);\nvar defined = __webpack_require__(56);\n// true  -> String#at\n// false -> String#codePointAt\nmodule.exports = function (TO_STRING) {\n  return function (that, pos) {\n    var s = String(defined(that));\n    var i = toInteger(pos);\n    var l = s.length;\n    var a, b;\n    if (i < 0 || i >= l) return TO_STRING ? '' : undefined;\n    a = s.charCodeAt(i);\n    return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff\n      ? TO_STRING ? s.charAt(i) : a\n      : TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000;\n  };\n};\n\n\n/***/ }),\n/* 208 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar anObject = __webpack_require__(14);\nvar get = __webpack_require__(67);\nmodule.exports = __webpack_require__(2).getIterator = function (it) {\n  var iterFn = get(it);\n  if (typeof iterFn != 'function') throw TypeError(it + ' is not iterable!');\n  return anObject(iterFn.call(it));\n};\n\n\n/***/ }),\n/* 209 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(210), __esModule: true };\n\n/***/ }),\n/* 210 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(211);\nmodule.exports = __webpack_require__(2).Object.freeze;\n\n\n/***/ }),\n/* 211 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.2.5 Object.freeze(O)\nvar isObject = __webpack_require__(9);\nvar meta = __webpack_require__(40).onFreeze;\n\n__webpack_require__(59)('freeze', function ($freeze) {\n  return function freeze(it) {\n    return $freeze && isObject(it) ? $freeze(meta(it)) : it;\n  };\n});\n\n\n/***/ }),\n/* 212 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(213), __esModule: true };\n\n/***/ }),\n/* 213 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(214);\nmodule.exports = __webpack_require__(2).Object.keys;\n\n\n/***/ }),\n/* 214 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.2.14 Object.keys(O)\nvar toObject = __webpack_require__(30);\nvar $keys = __webpack_require__(29);\n\n__webpack_require__(59)('keys', function () {\n  return function keys(it) {\n    return $keys(toObject(it));\n  };\n});\n\n\n/***/ }),\n/* 215 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(24);\n__webpack_require__(28);\nmodule.exports = __webpack_require__(70).f('iterator');\n\n\n/***/ }),\n/* 216 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(217), __esModule: true };\n\n/***/ }),\n/* 217 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(218);\n__webpack_require__(73);\n__webpack_require__(221);\n__webpack_require__(222);\nmodule.exports = __webpack_require__(2).Symbol;\n\n\n/***/ }),\n/* 218 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n// ECMAScript 6 symbols shim\nvar global = __webpack_require__(10);\nvar has = __webpack_require__(18);\nvar DESCRIPTORS = __webpack_require__(5);\nvar $export = __webpack_require__(3);\nvar redefine = __webpack_require__(99);\nvar META = __webpack_require__(40).KEY;\nvar $fails = __webpack_require__(19);\nvar shared = __webpack_require__(65);\nvar setToStringTag = __webpack_require__(39);\nvar uid = __webpack_require__(38);\nvar wks = __webpack_require__(4);\nvar wksExt = __webpack_require__(70);\nvar wksDefine = __webpack_require__(71);\nvar enumKeys = __webpack_require__(219);\nvar isArray = __webpack_require__(104);\nvar anObject = __webpack_require__(14);\nvar isObject = __webpack_require__(9);\nvar toIObject = __webpack_require__(17);\nvar toPrimitive = __webpack_require__(58);\nvar createDesc = __webpack_require__(27);\nvar _create = __webpack_require__(36);\nvar gOPNExt = __webpack_require__(220);\nvar $GOPD = __webpack_require__(57);\nvar $DP = __webpack_require__(6);\nvar $keys = __webpack_require__(29);\nvar gOPD = $GOPD.f;\nvar dP = $DP.f;\nvar gOPN = gOPNExt.f;\nvar $Symbol = global.Symbol;\nvar $JSON = global.JSON;\nvar _stringify = $JSON && $JSON.stringify;\nvar PROTOTYPE = 'prototype';\nvar HIDDEN = wks('_hidden');\nvar TO_PRIMITIVE = wks('toPrimitive');\nvar isEnum = {}.propertyIsEnumerable;\nvar SymbolRegistry = shared('symbol-registry');\nvar AllSymbols = shared('symbols');\nvar OPSymbols = shared('op-symbols');\nvar ObjectProto = Object[PROTOTYPE];\nvar USE_NATIVE = typeof $Symbol == 'function';\nvar QObject = global.QObject;\n// Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173\nvar setter = !QObject || !QObject[PROTOTYPE] || !QObject[PROTOTYPE].findChild;\n\n// fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687\nvar setSymbolDesc = DESCRIPTORS && $fails(function () {\n  return _create(dP({}, 'a', {\n    get: function () { return dP(this, 'a', { value: 7 }).a; }\n  })).a != 7;\n}) ? function (it, key, D) {\n  var protoDesc = gOPD(ObjectProto, key);\n  if (protoDesc) delete ObjectProto[key];\n  dP(it, key, D);\n  if (protoDesc && it !== ObjectProto) dP(ObjectProto, key, protoDesc);\n} : dP;\n\nvar wrap = function (tag) {\n  var sym = AllSymbols[tag] = _create($Symbol[PROTOTYPE]);\n  sym._k = tag;\n  return sym;\n};\n\nvar isSymbol = USE_NATIVE && typeof $Symbol.iterator == 'symbol' ? function (it) {\n  return typeof it == 'symbol';\n} : function (it) {\n  return it instanceof $Symbol;\n};\n\nvar $defineProperty = function defineProperty(it, key, D) {\n  if (it === ObjectProto) $defineProperty(OPSymbols, key, D);\n  anObject(it);\n  key = toPrimitive(key, true);\n  anObject(D);\n  if (has(AllSymbols, key)) {\n    if (!D.enumerable) {\n      if (!has(it, HIDDEN)) dP(it, HIDDEN, createDesc(1, {}));\n      it[HIDDEN][key] = true;\n    } else {\n      if (has(it, HIDDEN) && it[HIDDEN][key]) it[HIDDEN][key] = false;\n      D = _create(D, { enumerable: createDesc(0, false) });\n    } return setSymbolDesc(it, key, D);\n  } return dP(it, key, D);\n};\nvar $defineProperties = function defineProperties(it, P) {\n  anObject(it);\n  var keys = enumKeys(P = toIObject(P));\n  var i = 0;\n  var l = keys.length;\n  var key;\n  while (l > i) $defineProperty(it, key = keys[i++], P[key]);\n  return it;\n};\nvar $create = function create(it, P) {\n  return P === undefined ? _create(it) : $defineProperties(_create(it), P);\n};\nvar $propertyIsEnumerable = function propertyIsEnumerable(key) {\n  var E = isEnum.call(this, key = toPrimitive(key, true));\n  if (this === ObjectProto && has(AllSymbols, key) && !has(OPSymbols, key)) return false;\n  return E || !has(this, key) || !has(AllSymbols, key) || has(this, HIDDEN) && this[HIDDEN][key] ? E : true;\n};\nvar $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(it, key) {\n  it = toIObject(it);\n  key = toPrimitive(key, true);\n  if (it === ObjectProto && has(AllSymbols, key) && !has(OPSymbols, key)) return;\n  var D = gOPD(it, key);\n  if (D && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key])) D.enumerable = true;\n  return D;\n};\nvar $getOwnPropertyNames = function getOwnPropertyNames(it) {\n  var names = gOPN(toIObject(it));\n  var result = [];\n  var i = 0;\n  var key;\n  while (names.length > i) {\n    if (!has(AllSymbols, key = names[i++]) && key != HIDDEN && key != META) result.push(key);\n  } return result;\n};\nvar $getOwnPropertySymbols = function getOwnPropertySymbols(it) {\n  var IS_OP = it === ObjectProto;\n  var names = gOPN(IS_OP ? OPSymbols : toIObject(it));\n  var result = [];\n  var i = 0;\n  var key;\n  while (names.length > i) {\n    if (has(AllSymbols, key = names[i++]) && (IS_OP ? has(ObjectProto, key) : true)) result.push(AllSymbols[key]);\n  } return result;\n};\n\n// 19.4.1.1 Symbol([description])\nif (!USE_NATIVE) {\n  $Symbol = function Symbol() {\n    if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor!');\n    var tag = uid(arguments.length > 0 ? arguments[0] : undefined);\n    var $set = function (value) {\n      if (this === ObjectProto) $set.call(OPSymbols, value);\n      if (has(this, HIDDEN) && has(this[HIDDEN], tag)) this[HIDDEN][tag] = false;\n      setSymbolDesc(this, tag, createDesc(1, value));\n    };\n    if (DESCRIPTORS && setter) setSymbolDesc(ObjectProto, tag, { configurable: true, set: $set });\n    return wrap(tag);\n  };\n  redefine($Symbol[PROTOTYPE], 'toString', function toString() {\n    return this._k;\n  });\n\n  $GOPD.f = $getOwnPropertyDescriptor;\n  $DP.f = $defineProperty;\n  __webpack_require__(105).f = gOPNExt.f = $getOwnPropertyNames;\n  __webpack_require__(35).f = $propertyIsEnumerable;\n  __webpack_require__(72).f = $getOwnPropertySymbols;\n\n  if (DESCRIPTORS && !__webpack_require__(62)) {\n    redefine(ObjectProto, 'propertyIsEnumerable', $propertyIsEnumerable, true);\n  }\n\n  wksExt.f = function (name) {\n    return wrap(wks(name));\n  };\n}\n\n$export($export.G + $export.W + $export.F * !USE_NATIVE, { Symbol: $Symbol });\n\nfor (var es6Symbols = (\n  // 19.4.2.2, 19.4.2.3, 19.4.2.4, 19.4.2.6, 19.4.2.8, 19.4.2.9, 19.4.2.10, 19.4.2.11, 19.4.2.12, 19.4.2.13, 19.4.2.14\n  'hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables'\n).split(','), j = 0; es6Symbols.length > j;)wks(es6Symbols[j++]);\n\nfor (var wellKnownSymbols = $keys(wks.store), k = 0; wellKnownSymbols.length > k;) wksDefine(wellKnownSymbols[k++]);\n\n$export($export.S + $export.F * !USE_NATIVE, 'Symbol', {\n  // 19.4.2.1 Symbol.for(key)\n  'for': function (key) {\n    return has(SymbolRegistry, key += '')\n      ? SymbolRegistry[key]\n      : SymbolRegistry[key] = $Symbol(key);\n  },\n  // 19.4.2.5 Symbol.keyFor(sym)\n  keyFor: function keyFor(sym) {\n    if (!isSymbol(sym)) throw TypeError(sym + ' is not a symbol!');\n    for (var key in SymbolRegistry) if (SymbolRegistry[key] === sym) return key;\n  },\n  useSetter: function () { setter = true; },\n  useSimple: function () { setter = false; }\n});\n\n$export($export.S + $export.F * !USE_NATIVE, 'Object', {\n  // 19.1.2.2 Object.create(O [, Properties])\n  create: $create,\n  // 19.1.2.4 Object.defineProperty(O, P, Attributes)\n  defineProperty: $defineProperty,\n  // 19.1.2.3 Object.defineProperties(O, Properties)\n  defineProperties: $defineProperties,\n  // 19.1.2.6 Object.getOwnPropertyDescriptor(O, P)\n  getOwnPropertyDescriptor: $getOwnPropertyDescriptor,\n  // 19.1.2.7 Object.getOwnPropertyNames(O)\n  getOwnPropertyNames: $getOwnPropertyNames,\n  // 19.1.2.8 Object.getOwnPropertySymbols(O)\n  getOwnPropertySymbols: $getOwnPropertySymbols\n});\n\n// 24.3.2 JSON.stringify(value [, replacer [, space]])\n$JSON && $export($export.S + $export.F * (!USE_NATIVE || $fails(function () {\n  var S = $Symbol();\n  // MS Edge converts symbol values to JSON as {}\n  // WebKit converts symbol values to JSON as null\n  // V8 throws on boxed symbols\n  return _stringify([S]) != '[null]' || _stringify({ a: S }) != '{}' || _stringify(Object(S)) != '{}';\n})), 'JSON', {\n  stringify: function stringify(it) {\n    var args = [it];\n    var i = 1;\n    var replacer, $replacer;\n    while (arguments.length > i) args.push(arguments[i++]);\n    $replacer = replacer = args[1];\n    if (!isObject(replacer) && it === undefined || isSymbol(it)) return; // IE8 returns string on undefined\n    if (!isArray(replacer)) replacer = function (key, value) {\n      if (typeof $replacer == 'function') value = $replacer.call(this, key, value);\n      if (!isSymbol(value)) return value;\n    };\n    args[1] = replacer;\n    return _stringify.apply($JSON, args);\n  }\n});\n\n// 19.4.3.4 Symbol.prototype[@@toPrimitive](hint)\n$Symbol[PROTOTYPE][TO_PRIMITIVE] || __webpack_require__(13)($Symbol[PROTOTYPE], TO_PRIMITIVE, $Symbol[PROTOTYPE].valueOf);\n// 19.4.3.5 Symbol.prototype[@@toStringTag]\nsetToStringTag($Symbol, 'Symbol');\n// 20.2.1.9 Math[@@toStringTag]\nsetToStringTag(Math, 'Math', true);\n// 24.3.3 JSON[@@toStringTag]\nsetToStringTag(global.JSON, 'JSON', true);\n\n\n/***/ }),\n/* 219 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// all enumerable object keys, includes symbols\nvar getKeys = __webpack_require__(29);\nvar gOPS = __webpack_require__(72);\nvar pIE = __webpack_require__(35);\nmodule.exports = function (it) {\n  var result = getKeys(it);\n  var getSymbols = gOPS.f;\n  if (getSymbols) {\n    var symbols = getSymbols(it);\n    var isEnum = pIE.f;\n    var i = 0;\n    var key;\n    while (symbols.length > i) if (isEnum.call(it, key = symbols[i++])) result.push(key);\n  } return result;\n};\n\n\n/***/ }),\n/* 220 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window\nvar toIObject = __webpack_require__(17);\nvar gOPN = __webpack_require__(105).f;\nvar toString = {}.toString;\n\nvar windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames\n  ? Object.getOwnPropertyNames(window) : [];\n\nvar getWindowNames = function (it) {\n  try {\n    return gOPN(it);\n  } catch (e) {\n    return windowNames.slice();\n  }\n};\n\nmodule.exports.f = function getOwnPropertyNames(it) {\n  return windowNames && toString.call(it) == '[object Window]' ? getWindowNames(it) : gOPN(toIObject(it));\n};\n\n\n/***/ }),\n/* 221 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(71)('asyncIterator');\n\n\n/***/ }),\n/* 222 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(71)('observable');\n\n\n/***/ }),\n/* 223 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(224);\nvar $Object = __webpack_require__(2).Object;\nmodule.exports = function defineProperty(it, key, desc) {\n  return $Object.defineProperty(it, key, desc);\n};\n\n\n/***/ }),\n/* 224 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar $export = __webpack_require__(3);\n// 19.1.2.4 / 15.2.3.6 Object.defineProperty(O, P, Attributes)\n$export($export.S + $export.F * !__webpack_require__(5), 'Object', { defineProperty: __webpack_require__(6).f });\n\n\n/***/ }),\n/* 225 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(226), __esModule: true };\n\n/***/ }),\n/* 226 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(73);\n__webpack_require__(24);\n__webpack_require__(28);\n__webpack_require__(227);\n__webpack_require__(232);\n__webpack_require__(234);\n__webpack_require__(235);\nmodule.exports = __webpack_require__(2).Map;\n\n\n/***/ }),\n/* 227 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar strong = __webpack_require__(108);\nvar validate = __webpack_require__(75);\nvar MAP = 'Map';\n\n// 23.1 Map Objects\nmodule.exports = __webpack_require__(113)(MAP, function (get) {\n  return function Map() { return get(this, arguments.length > 0 ? arguments[0] : undefined); };\n}, {\n  // 23.1.3.6 Map.prototype.get(key)\n  get: function get(key) {\n    var entry = strong.getEntry(validate(this, MAP), key);\n    return entry && entry.v;\n  },\n  // 23.1.3.9 Map.prototype.set(key, value)\n  set: function set(key, value) {\n    return strong.def(validate(this, MAP), key === 0 ? 0 : key, value);\n  }\n}, strong, true);\n\n\n/***/ }),\n/* 228 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar global = __webpack_require__(10);\nvar core = __webpack_require__(2);\nvar dP = __webpack_require__(6);\nvar DESCRIPTORS = __webpack_require__(5);\nvar SPECIES = __webpack_require__(4)('species');\n\nmodule.exports = function (KEY) {\n  var C = typeof core[KEY] == 'function' ? core[KEY] : global[KEY];\n  if (DESCRIPTORS && C && !C[SPECIES]) dP.f(C, SPECIES, {\n    configurable: true,\n    get: function () { return this; }\n  });\n};\n\n\n/***/ }),\n/* 229 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 0 -> Array#forEach\n// 1 -> Array#map\n// 2 -> Array#filter\n// 3 -> Array#some\n// 4 -> Array#every\n// 5 -> Array#find\n// 6 -> Array#findIndex\nvar ctx = __webpack_require__(20);\nvar IObject = __webpack_require__(54);\nvar toObject = __webpack_require__(30);\nvar toLength = __webpack_require__(37);\nvar asc = __webpack_require__(230);\nmodule.exports = function (TYPE, $create) {\n  var IS_MAP = TYPE == 1;\n  var IS_FILTER = TYPE == 2;\n  var IS_SOME = TYPE == 3;\n  var IS_EVERY = TYPE == 4;\n  var IS_FIND_INDEX = TYPE == 6;\n  var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;\n  var create = $create || asc;\n  return function ($this, callbackfn, that) {\n    var O = toObject($this);\n    var self = IObject(O);\n    var f = ctx(callbackfn, that, 3);\n    var length = toLength(self.length);\n    var index = 0;\n    var result = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined;\n    var val, res;\n    for (;length > index; index++) if (NO_HOLES || index in self) {\n      val = self[index];\n      res = f(val, index, O);\n      if (TYPE) {\n        if (IS_MAP) result[index] = res;   // map\n        else if (res) switch (TYPE) {\n          case 3: return true;             // some\n          case 5: return val;              // find\n          case 6: return index;            // findIndex\n          case 2: result.push(val);        // filter\n        } else if (IS_EVERY) return false; // every\n      }\n    }\n    return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : result;\n  };\n};\n\n\n/***/ }),\n/* 230 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 9.4.2.3 ArraySpeciesCreate(originalArray, length)\nvar speciesConstructor = __webpack_require__(231);\n\nmodule.exports = function (original, length) {\n  return new (speciesConstructor(original))(length);\n};\n\n\n/***/ }),\n/* 231 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar isObject = __webpack_require__(9);\nvar isArray = __webpack_require__(104);\nvar SPECIES = __webpack_require__(4)('species');\n\nmodule.exports = function (original) {\n  var C;\n  if (isArray(original)) {\n    C = original.constructor;\n    // cross-realm fallback\n    if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined;\n    if (isObject(C)) {\n      C = C[SPECIES];\n      if (C === null) C = undefined;\n    }\n  } return C === undefined ? Array : C;\n};\n\n\n/***/ }),\n/* 232 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// https://github.com/DavidBruant/Map-Set.prototype.toJSON\nvar $export = __webpack_require__(3);\n\n$export($export.P + $export.R, 'Map', { toJSON: __webpack_require__(114)('Map') });\n\n\n/***/ }),\n/* 233 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar forOf = __webpack_require__(41);\n\nmodule.exports = function (iter, ITERATOR) {\n  var result = [];\n  forOf(iter, false, result.push, result, ITERATOR);\n  return result;\n};\n\n\n/***/ }),\n/* 234 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// https://tc39.github.io/proposal-setmap-offrom/#sec-map.of\n__webpack_require__(115)('Map');\n\n\n/***/ }),\n/* 235 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// https://tc39.github.io/proposal-setmap-offrom/#sec-map.from\n__webpack_require__(116)('Map');\n\n\n/***/ }),\n/* 236 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nvar _typeof2 = __webpack_require__(69);\n\nvar _typeof3 = _interopRequireDefault(_typeof2);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nexports.default = function (self, call) {\n  if (!self) {\n    throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n  }\n\n  return call && ((typeof call === \"undefined\" ? \"undefined\" : (0, _typeof3.default)(call)) === \"object\" || typeof call === \"function\") ? call : self;\n};\n\n/***/ }),\n/* 237 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nvar _setPrototypeOf = __webpack_require__(238);\n\nvar _setPrototypeOf2 = _interopRequireDefault(_setPrototypeOf);\n\nvar _create = __webpack_require__(242);\n\nvar _create2 = _interopRequireDefault(_create);\n\nvar _typeof2 = __webpack_require__(69);\n\nvar _typeof3 = _interopRequireDefault(_typeof2);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nexports.default = function (subClass, superClass) {\n  if (typeof superClass !== \"function\" && superClass !== null) {\n    throw new TypeError(\"Super expression must either be null or a function, not \" + (typeof superClass === \"undefined\" ? \"undefined\" : (0, _typeof3.default)(superClass)));\n  }\n\n  subClass.prototype = (0, _create2.default)(superClass && superClass.prototype, {\n    constructor: {\n      value: subClass,\n      enumerable: false,\n      writable: true,\n      configurable: true\n    }\n  });\n  if (superClass) _setPrototypeOf2.default ? (0, _setPrototypeOf2.default)(subClass, superClass) : subClass.__proto__ = superClass;\n};\n\n/***/ }),\n/* 238 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(239), __esModule: true };\n\n/***/ }),\n/* 239 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(240);\nmodule.exports = __webpack_require__(2).Object.setPrototypeOf;\n\n\n/***/ }),\n/* 240 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.3.19 Object.setPrototypeOf(O, proto)\nvar $export = __webpack_require__(3);\n$export($export.S, 'Object', { setPrototypeOf: __webpack_require__(241).set });\n\n\n/***/ }),\n/* 241 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Works with __proto__ only. Old v8 can't work with null proto objects.\n/* eslint-disable no-proto */\nvar isObject = __webpack_require__(9);\nvar anObject = __webpack_require__(14);\nvar check = function (O, proto) {\n  anObject(O);\n  if (!isObject(proto) && proto !== null) throw TypeError(proto + \": can't set as prototype!\");\n};\nmodule.exports = {\n  set: Object.setPrototypeOf || ('__proto__' in {} ? // eslint-disable-line\n    function (test, buggy, set) {\n      try {\n        set = __webpack_require__(20)(Function.call, __webpack_require__(57).f(Object.prototype, '__proto__').set, 2);\n        set(test, []);\n        buggy = !(test instanceof Array);\n      } catch (e) { buggy = true; }\n      return function setPrototypeOf(O, proto) {\n        check(O, proto);\n        if (buggy) O.__proto__ = proto;\n        else set(O, proto);\n        return O;\n      };\n    }({}, false) : undefined),\n  check: check\n};\n\n\n/***/ }),\n/* 242 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(243), __esModule: true };\n\n/***/ }),\n/* 243 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(244);\nvar $Object = __webpack_require__(2).Object;\nmodule.exports = function create(P, D) {\n  return $Object.create(P, D);\n};\n\n\n/***/ }),\n/* 244 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar $export = __webpack_require__(3);\n// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])\n$export($export.S, 'Object', { create: __webpack_require__(36) });\n\n\n/***/ }),\n/* 245 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(246), __esModule: true };\n\n/***/ }),\n/* 246 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(247);\nvar $Object = __webpack_require__(2).Object;\nmodule.exports = function defineProperties(T, D) {\n  return $Object.defineProperties(T, D);\n};\n\n\n/***/ }),\n/* 247 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar $export = __webpack_require__(3);\n// 19.1.2.3 / 15.2.3.7 Object.defineProperties(O, Properties)\n$export($export.S + $export.F * !__webpack_require__(5), 'Object', { defineProperties: __webpack_require__(100) });\n\n\n/***/ }),\n/* 248 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar pSlice = Array.prototype.slice;\nvar objectKeys = __webpack_require__(249);\nvar isArguments = __webpack_require__(250);\n\nvar deepEqual = module.exports = function (actual, expected, opts) {\n  if (!opts) opts = {};\n  // 7.1. All identical values are equivalent, as determined by ===.\n  if (actual === expected) {\n    return true;\n\n  } else if (actual instanceof Date && expected instanceof Date) {\n    return actual.getTime() === expected.getTime();\n\n  // 7.3. Other pairs that do not both pass typeof value == 'object',\n  // equivalence is determined by ==.\n  } else if (!actual || !expected || typeof actual != 'object' && typeof expected != 'object') {\n    return opts.strict ? actual === expected : actual == expected;\n\n  // 7.4. For all other Object pairs, including Array objects, equivalence is\n  // determined by having the same number of owned properties (as verified\n  // with Object.prototype.hasOwnProperty.call), the same set of keys\n  // (although not necessarily the same order), equivalent values for every\n  // corresponding key, and an identical 'prototype' property. Note: this\n  // accounts for both named and indexed properties on Arrays.\n  } else {\n    return objEquiv(actual, expected, opts);\n  }\n}\n\nfunction isUndefinedOrNull(value) {\n  return value === null || value === undefined;\n}\n\nfunction isBuffer (x) {\n  if (!x || typeof x !== 'object' || typeof x.length !== 'number') return false;\n  if (typeof x.copy !== 'function' || typeof x.slice !== 'function') {\n    return false;\n  }\n  if (x.length > 0 && typeof x[0] !== 'number') return false;\n  return true;\n}\n\nfunction objEquiv(a, b, opts) {\n  var i, key;\n  if (isUndefinedOrNull(a) || isUndefinedOrNull(b))\n    return false;\n  // an identical 'prototype' property.\n  if (a.prototype !== b.prototype) return false;\n  //~~~I've managed to break Object.keys through screwy arguments passing.\n  //   Converting to array solves the problem.\n  if (isArguments(a)) {\n    if (!isArguments(b)) {\n      return false;\n    }\n    a = pSlice.call(a);\n    b = pSlice.call(b);\n    return deepEqual(a, b, opts);\n  }\n  if (isBuffer(a)) {\n    if (!isBuffer(b)) {\n      return false;\n    }\n    if (a.length !== b.length) return false;\n    for (i = 0; i < a.length; i++) {\n      if (a[i] !== b[i]) return false;\n    }\n    return true;\n  }\n  try {\n    var ka = objectKeys(a),\n        kb = objectKeys(b);\n  } catch (e) {//happens when one is a string literal and the other isn't\n    return false;\n  }\n  // having the same number of owned properties (keys incorporates\n  // hasOwnProperty)\n  if (ka.length != kb.length)\n    return false;\n  //the same set of keys (although not necessarily the same order),\n  ka.sort();\n  kb.sort();\n  //~~~cheap key test\n  for (i = ka.length - 1; i >= 0; i--) {\n    if (ka[i] != kb[i])\n      return false;\n  }\n  //equivalent values for every corresponding key, and\n  //~~~possibly expensive deep test\n  for (i = ka.length - 1; i >= 0; i--) {\n    key = ka[i];\n    if (!deepEqual(a[key], b[key], opts)) return false;\n  }\n  return typeof a === typeof b;\n}\n\n\n/***/ }),\n/* 249 */\n/***/ (function(module, exports) {\n\nexports = module.exports = typeof Object.keys === 'function'\n  ? Object.keys : shim;\n\nexports.shim = shim;\nfunction shim (obj) {\n  var keys = [];\n  for (var key in obj) keys.push(key);\n  return keys;\n}\n\n\n/***/ }),\n/* 250 */\n/***/ (function(module, exports) {\n\nvar supportsArgumentsClass = (function(){\n  return Object.prototype.toString.call(arguments)\n})() == '[object Arguments]';\n\nexports = module.exports = supportsArgumentsClass ? supported : unsupported;\n\nexports.supported = supported;\nfunction supported(object) {\n  return Object.prototype.toString.call(object) == '[object Arguments]';\n};\n\nexports.unsupported = unsupported;\nfunction unsupported(object){\n  return object &&\n    typeof object == 'object' &&\n    typeof object.length == 'number' &&\n    Object.prototype.hasOwnProperty.call(object, 'callee') &&\n    !Object.prototype.propertyIsEnumerable.call(object, 'callee') ||\n    false;\n};\n\n\n/***/ }),\n/* 251 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(252), __esModule: true };\n\n/***/ }),\n/* 252 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(253);\nmodule.exports = __webpack_require__(2).Object.assign;\n\n\n/***/ }),\n/* 253 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 19.1.3.1 Object.assign(target, source)\nvar $export = __webpack_require__(3);\n\n$export($export.S + $export.F, 'Object', { assign: __webpack_require__(254) });\n\n\n/***/ }),\n/* 254 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n// 19.1.2.1 Object.assign(target, source, ...)\nvar getKeys = __webpack_require__(29);\nvar gOPS = __webpack_require__(72);\nvar pIE = __webpack_require__(35);\nvar toObject = __webpack_require__(30);\nvar IObject = __webpack_require__(54);\nvar $assign = Object.assign;\n\n// should work with symbols and should have deterministic property order (V8 bug)\nmodule.exports = !$assign || __webpack_require__(19)(function () {\n  var A = {};\n  var B = {};\n  // eslint-disable-next-line no-undef\n  var S = Symbol();\n  var K = 'abcdefghijklmnopqrst';\n  A[S] = 7;\n  K.split('').forEach(function (k) { B[k] = k; });\n  return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join('') != K;\n}) ? function assign(target, source) { // eslint-disable-line no-unused-vars\n  var T = toObject(target);\n  var aLen = arguments.length;\n  var index = 1;\n  var getSymbols = gOPS.f;\n  var isEnum = pIE.f;\n  while (aLen > index) {\n    var S = IObject(arguments[index++]);\n    var keys = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S);\n    var length = keys.length;\n    var j = 0;\n    var key;\n    while (length > j) if (isEnum.call(S, key = keys[j++])) T[key] = S[key];\n  } return T;\n} : $assign;\n\n\n/***/ }),\n/* 255 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(256), __esModule: true };\n\n/***/ }),\n/* 256 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(257);\nmodule.exports = __webpack_require__(2).String.fromCodePoint;\n\n\n/***/ }),\n/* 257 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar $export = __webpack_require__(3);\nvar toAbsoluteIndex = __webpack_require__(102);\nvar fromCharCode = String.fromCharCode;\nvar $fromCodePoint = String.fromCodePoint;\n\n// length should be 1, old FF problem\n$export($export.S + $export.F * (!!$fromCodePoint && $fromCodePoint.length != 1), 'String', {\n  // 21.1.2.2 String.fromCodePoint(...codePoints)\n  fromCodePoint: function fromCodePoint(x) { // eslint-disable-line no-unused-vars\n    var res = [];\n    var aLen = arguments.length;\n    var i = 0;\n    var code;\n    while (aLen > i) {\n      code = +arguments[i++];\n      if (toAbsoluteIndex(code, 0x10ffff) !== code) throw RangeError(code + ' is not a valid code point');\n      res.push(code < 0x10000\n        ? fromCharCode(code)\n        : fromCharCode(((code -= 0x10000) >> 10) + 0xd800, code % 0x400 + 0xdc00)\n      );\n    } return res.join('');\n  }\n});\n\n\n/***/ }),\n/* 258 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(259), __esModule: true };\n\n/***/ }),\n/* 259 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(24);\n__webpack_require__(260);\nmodule.exports = __webpack_require__(2).Array.from;\n\n\n/***/ }),\n/* 260 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar ctx = __webpack_require__(20);\nvar $export = __webpack_require__(3);\nvar toObject = __webpack_require__(30);\nvar call = __webpack_require__(111);\nvar isArrayIter = __webpack_require__(112);\nvar toLength = __webpack_require__(37);\nvar createProperty = __webpack_require__(261);\nvar getIterFn = __webpack_require__(67);\n\n$export($export.S + $export.F * !__webpack_require__(262)(function (iter) { Array.from(iter); }), 'Array', {\n  // 22.1.2.1 Array.from(arrayLike, mapfn = undefined, thisArg = undefined)\n  from: function from(arrayLike /* , mapfn = undefined, thisArg = undefined */) {\n    var O = toObject(arrayLike);\n    var C = typeof this == 'function' ? this : Array;\n    var aLen = arguments.length;\n    var mapfn = aLen > 1 ? arguments[1] : undefined;\n    var mapping = mapfn !== undefined;\n    var index = 0;\n    var iterFn = getIterFn(O);\n    var length, result, step, iterator;\n    if (mapping) mapfn = ctx(mapfn, aLen > 2 ? arguments[2] : undefined, 2);\n    // if object isn't iterable or it's array with default iterator - use simple case\n    if (iterFn != undefined && !(C == Array && isArrayIter(iterFn))) {\n      for (iterator = iterFn.call(O), result = new C(); !(step = iterator.next()).done; index++) {\n        createProperty(result, index, mapping ? call(iterator, mapfn, [step.value, index], true) : step.value);\n      }\n    } else {\n      length = toLength(O.length);\n      for (result = new C(length); length > index; index++) {\n        createProperty(result, index, mapping ? mapfn(O[index], index) : O[index]);\n      }\n    }\n    result.length = index;\n    return result;\n  }\n});\n\n\n/***/ }),\n/* 261 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar $defineProperty = __webpack_require__(6);\nvar createDesc = __webpack_require__(27);\n\nmodule.exports = function (object, index, value) {\n  if (index in object) $defineProperty.f(object, index, createDesc(0, value));\n  else object[index] = value;\n};\n\n\n/***/ }),\n/* 262 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar ITERATOR = __webpack_require__(4)('iterator');\nvar SAFE_CLOSING = false;\n\ntry {\n  var riter = [7][ITERATOR]();\n  riter['return'] = function () { SAFE_CLOSING = true; };\n  // eslint-disable-next-line no-throw-literal\n  Array.from(riter, function () { throw 2; });\n} catch (e) { /* empty */ }\n\nmodule.exports = function (exec, skipClosing) {\n  if (!skipClosing && !SAFE_CLOSING) return false;\n  var safe = false;\n  try {\n    var arr = [7];\n    var iter = arr[ITERATOR]();\n    iter.next = function () { return { done: safe = true }; };\n    arr[ITERATOR] = function () { return iter; };\n    exec(arr);\n  } catch (e) { /* empty */ }\n  return safe;\n};\n\n\n/***/ }),\n/* 263 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(264), __esModule: true };\n\n/***/ }),\n/* 264 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(73);\n__webpack_require__(24);\n__webpack_require__(28);\n__webpack_require__(265);\n__webpack_require__(266);\n__webpack_require__(267);\n__webpack_require__(268);\nmodule.exports = __webpack_require__(2).Set;\n\n\n/***/ }),\n/* 265 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\nvar strong = __webpack_require__(108);\nvar validate = __webpack_require__(75);\nvar SET = 'Set';\n\n// 23.2 Set Objects\nmodule.exports = __webpack_require__(113)(SET, function (get) {\n  return function Set() { return get(this, arguments.length > 0 ? arguments[0] : undefined); };\n}, {\n  // 23.2.3.1 Set.prototype.add(value)\n  add: function add(value) {\n    return strong.def(validate(this, SET), value = value === 0 ? 0 : value, value);\n  }\n}, strong);\n\n\n/***/ }),\n/* 266 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// https://github.com/DavidBruant/Map-Set.prototype.toJSON\nvar $export = __webpack_require__(3);\n\n$export($export.P + $export.R, 'Set', { toJSON: __webpack_require__(114)('Set') });\n\n\n/***/ }),\n/* 267 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// https://tc39.github.io/proposal-setmap-offrom/#sec-set.of\n__webpack_require__(115)('Set');\n\n\n/***/ }),\n/* 268 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// https://tc39.github.io/proposal-setmap-offrom/#sec-set.from\n__webpack_require__(116)('Set');\n\n\n/***/ }),\n/* 269 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.9.1\nvar CATEGORY_BITS, CATEGORY_MASK, CATEGORY_SHIFT, COMBINING_BITS, COMBINING_MASK, COMBINING_SHIFT, EAW_BITS, EAW_MASK, EAW_SHIFT, NUMBER_BITS, NUMBER_MASK, SCRIPT_BITS, SCRIPT_MASK, SCRIPT_SHIFT, UnicodeTrie, bits, data, fs, log2, trie;\n\nUnicodeTrie = __webpack_require__(43);\n\ndata = __webpack_require__(270);\n\n\n\ntrie = new UnicodeTrie(Buffer(\"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\",\"base64\"));\n\nlog2 = Math.log2 || function(n) {\n  return Math.log(n) / Math.LN2;\n};\n\nbits = function(n) {\n  return (log2(n) + 1) | 0;\n};\n\nCATEGORY_BITS = bits(data.categories.length - 1);\n\nCOMBINING_BITS = bits(data.combiningClasses.length - 1);\n\nSCRIPT_BITS = bits(data.scripts.length - 1);\n\nEAW_BITS = bits(data.eaw.length - 1);\n\nNUMBER_BITS = 10;\n\nCATEGORY_SHIFT = COMBINING_BITS + SCRIPT_BITS + EAW_BITS + NUMBER_BITS;\n\nCOMBINING_SHIFT = SCRIPT_BITS + EAW_BITS + NUMBER_BITS;\n\nSCRIPT_SHIFT = EAW_BITS + NUMBER_BITS;\n\nEAW_SHIFT = NUMBER_BITS;\n\nCATEGORY_MASK = (1 << CATEGORY_BITS) - 1;\n\nCOMBINING_MASK = (1 << COMBINING_BITS) - 1;\n\nSCRIPT_MASK = (1 << SCRIPT_BITS) - 1;\n\nEAW_MASK = (1 << EAW_BITS) - 1;\n\nNUMBER_MASK = (1 << NUMBER_BITS) - 1;\n\nexports.getCategory = function(codePoint) {\n  var val;\n  val = trie.get(codePoint);\n  return data.categories[(val >> CATEGORY_SHIFT) & CATEGORY_MASK];\n};\n\nexports.getCombiningClass = function(codePoint) {\n  var val;\n  val = trie.get(codePoint);\n  return data.combiningClasses[(val >> COMBINING_SHIFT) & COMBINING_MASK];\n};\n\nexports.getScript = function(codePoint) {\n  var val;\n  val = trie.get(codePoint);\n  return data.scripts[(val >> SCRIPT_SHIFT) & SCRIPT_MASK];\n};\n\nexports.getEastAsianWidth = function(codePoint) {\n  var val;\n  val = trie.get(codePoint);\n  return data.eaw[(val >> EAW_SHIFT) & EAW_MASK];\n};\n\nexports.getNumericValue = function(codePoint) {\n  var denominator, exp, num, numerator, val;\n  val = trie.get(codePoint);\n  num = val & NUMBER_MASK;\n  if (num === 0) {\n    return null;\n  } else if (num <= 50) {\n    return num - 1;\n  } else if (num < 0x1e0) {\n    numerator = (num >> 4) - 12;\n    denominator = (num & 0xf) + 1;\n    return numerator / denominator;\n  } else if (num < 0x300) {\n    val = (num >> 5) - 14;\n    exp = (num & 0x1f) + 2;\n    while (exp > 0) {\n      val *= 10;\n      exp--;\n    }\n    return val;\n  } else {\n    val = (num >> 2) - 0xbf;\n    exp = (num & 3) + 1;\n    while (exp > 0) {\n      val *= 60;\n      exp--;\n    }\n    return val;\n  }\n};\n\nexports.isAlphabetic = function(codePoint) {\n  var ref;\n  return (ref = exports.getCategory(codePoint)) === 'Lu' || ref === 'Ll' || ref === 'Lt' || ref === 'Lm' || ref === 'Lo' || ref === 'Nl';\n};\n\nexports.isDigit = function(codePoint) {\n  return exports.getCategory(codePoint) === 'Nd';\n};\n\nexports.isPunctuation = function(codePoint) {\n  var ref;\n  return (ref = exports.getCategory(codePoint)) === 'Pc' || ref === 'Pd' || ref === 'Pe' || ref === 'Pf' || ref === 'Pi' || ref === 'Po' || ref === 'Ps';\n};\n\nexports.isLowerCase = function(codePoint) {\n  return exports.getCategory(codePoint) === 'Ll';\n};\n\nexports.isUpperCase = function(codePoint) {\n  return exports.getCategory(codePoint) === 'Lu';\n};\n\nexports.isTitleCase = function(codePoint) {\n  return exports.getCategory(codePoint) === 'Lt';\n};\n\nexports.isWhiteSpace = function(codePoint) {\n  var ref;\n  return (ref = exports.getCategory(codePoint)) === 'Zs' || ref === 'Zl' || ref === 'Zp';\n};\n\nexports.isBaseForm = function(codePoint) {\n  var ref;\n  return (ref = exports.getCategory(codePoint)) === 'Nd' || ref === 'No' || ref === 'Nl' || ref === 'Lu' || ref === 'Ll' || ref === 'Lt' || ref === 'Lm' || ref === 'Lo' || ref === 'Me' || ref === 'Mc';\n};\n\nexports.isMark = function(codePoint) {\n  var ref;\n  return (ref = exports.getCategory(codePoint)) === 'Mn' || ref === 'Me' || ref === 'Mc';\n};\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 270 */\n/***/ (function(module, exports) {\n\nmodule.exports = {\"categories\":[\"Cc\",\"Zs\",\"Po\",\"Sc\",\"Ps\",\"Pe\",\"Sm\",\"Pd\",\"Nd\",\"Lu\",\"Sk\",\"Pc\",\"Ll\",\"So\",\"Lo\",\"Pi\",\"Cf\",\"No\",\"Pf\",\"Lt\",\"Lm\",\"Mn\",\"Me\",\"Mc\",\"Nl\",\"Zl\",\"Zp\",\"Cs\",\"Co\"],\"combiningClasses\":[\"Not_Reordered\",\"Above\",\"Above_Right\",\"Below\",\"Attached_Above_Right\",\"Attached_Below\",\"Overlay\",\"Iota_Subscript\",\"Double_Below\",\"Double_Above\",\"Below_Right\",\"Above_Left\",\"CCC10\",\"CCC11\",\"CCC12\",\"CCC13\",\"CCC14\",\"CCC15\",\"CCC16\",\"CCC17\",\"CCC18\",\"CCC19\",\"CCC20\",\"CCC21\",\"CCC22\",\"CCC23\",\"CCC24\",\"CCC25\",\"CCC30\",\"CCC31\",\"CCC32\",\"CCC27\",\"CCC28\",\"CCC29\",\"CCC33\",\"CCC34\",\"CCC35\",\"CCC36\",\"Nukta\",\"Virama\",\"CCC84\",\"CCC91\",\"CCC103\",\"CCC107\",\"CCC118\",\"CCC122\",\"CCC129\",\"CCC130\",\"CCC132\",\"Attached_Above\",\"Below_Left\",\"Left\",\"Kana_Voicing\",\"CCC26\",\"Right\"],\"scripts\":[\"Common\",\"Latin\",\"Bopomofo\",\"Inherited\",\"Greek\",\"Coptic\",\"Cyrillic\",\"Armenian\",\"Hebrew\",\"Arabic\",\"Syriac\",\"Thaana\",\"Nko\",\"Samaritan\",\"Mandaic\",\"Devanagari\",\"Bengali\",\"Gurmukhi\",\"Gujarati\",\"Oriya\",\"Tamil\",\"Telugu\",\"Kannada\",\"Malayalam\",\"Sinhala\",\"Thai\",\"Lao\",\"Tibetan\",\"Myanmar\",\"Georgian\",\"Hangul\",\"Ethiopic\",\"Cherokee\",\"Canadian_Aboriginal\",\"Ogham\",\"Runic\",\"Tagalog\",\"Hanunoo\",\"Buhid\",\"Tagbanwa\",\"Khmer\",\"Mongolian\",\"Limbu\",\"Tai_Le\",\"New_Tai_Lue\",\"Buginese\",\"Tai_Tham\",\"Balinese\",\"Sundanese\",\"Batak\",\"Lepcha\",\"Ol_Chiki\",\"Braille\",\"Glagolitic\",\"Tifinagh\",\"Han\",\"Hiragana\",\"Katakana\",\"Yi\",\"Lisu\",\"Vai\",\"Bamum\",\"Syloti_Nagri\",\"Phags_Pa\",\"Saurashtra\",\"Kayah_Li\",\"Rejang\",\"Javanese\",\"Cham\",\"Tai_Viet\",\"Meetei_Mayek\",\"null\",\"Linear_B\",\"Lycian\",\"Carian\",\"Old_Italic\",\"Gothic\",\"Old_Permic\",\"Ugaritic\",\"Old_Persian\",\"Deseret\",\"Shavian\",\"Osmanya\",\"Elbasan\",\"Caucasian_Albanian\",\"Linear_A\",\"Cypriot\",\"Imperial_Aramaic\",\"Palmyrene\",\"Nabataean\",\"Hatran\",\"Phoenician\",\"Lydian\",\"Meroitic_Hieroglyphs\",\"Meroitic_Cursive\",\"Kharoshthi\",\"Old_South_Arabian\",\"Old_North_Arabian\",\"Manichaean\",\"Avestan\",\"Inscriptional_Parthian\",\"Inscriptional_Pahlavi\",\"Psalter_Pahlavi\",\"Old_Turkic\",\"Old_Hungarian\",\"Brahmi\",\"Kaithi\",\"Sora_Sompeng\",\"Chakma\",\"Mahajani\",\"Sharada\",\"Khojki\",\"Multani\",\"Khudawadi\",\"Grantha\",\"Tirhuta\",\"Siddham\",\"Modi\",\"Takri\",\"Ahom\",\"Warang_Citi\",\"Pau_Cin_Hau\",\"Cuneiform\",\"Egyptian_Hieroglyphs\",\"Anatolian_Hieroglyphs\",\"Mro\",\"Bassa_Vah\",\"Pahawh_Hmong\",\"Miao\",\"Duployan\",\"SignWriting\",\"Mende_Kikakui\"],\"eaw\":[\"N\",\"Na\",\"A\",\"W\",\"H\",\"F\"]}\n\n/***/ }),\n/* 271 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nfunction _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }\n\nvar _slicedToArray = _interopDefault(__webpack_require__(272));\nvar _getIterator = _interopDefault(__webpack_require__(60));\nvar _defineProperty = _interopDefault(__webpack_require__(276));\nvar _regeneratorRuntime = _interopDefault(__webpack_require__(277));\nvar _Symbol$iterator = _interopDefault(__webpack_require__(103));\nvar _classCallCheck = _interopDefault(__webpack_require__(106));\nvar _createClass = _interopDefault(__webpack_require__(107));\n\nvar INITIAL_STATE = 1;\nvar FAIL_STATE = 0;\n\n/**\n * A StateMachine represents a deterministic finite automaton.\n * It can perform matches over a sequence of values, similar to a regular expression.\n */\n\nvar StateMachine = function () {\n  function StateMachine(dfa) {\n    _classCallCheck(this, StateMachine);\n\n    this.stateTable = dfa.stateTable;\n    this.accepting = dfa.accepting;\n    this.tags = dfa.tags;\n  }\n\n  /**\n   * Returns an iterable object that yields pattern matches over the input sequence.\n   * Matches are of the form [startIndex, endIndex, tags].\n   */\n\n\n  _createClass(StateMachine, [{\n    key: 'match',\n    value: function match(str) {\n      var self = this;\n      return _defineProperty({}, _Symbol$iterator, _regeneratorRuntime.mark(function _callee() {\n        var state, startRun, lastAccepting, lastState, p, c;\n        return _regeneratorRuntime.wrap(function _callee$(_context) {\n          while (1) {\n            switch (_context.prev = _context.next) {\n              case 0:\n                state = INITIAL_STATE;\n                startRun = null;\n                lastAccepting = null;\n                lastState = null;\n                p = 0;\n\n              case 5:\n                if (!(p < str.length)) {\n                  _context.next = 21;\n                  break;\n                }\n\n                c = str[p];\n\n\n                lastState = state;\n                state = self.stateTable[state][c];\n\n                if (!(state === FAIL_STATE)) {\n                  _context.next = 15;\n                  break;\n                }\n\n                if (!(startRun != null && lastAccepting != null && lastAccepting >= startRun)) {\n                  _context.next = 13;\n                  break;\n                }\n\n                _context.next = 13;\n                return [startRun, lastAccepting, self.tags[lastState]];\n\n              case 13:\n\n                // reset the state as if we started over from the initial state\n                state = self.stateTable[INITIAL_STATE][c];\n                startRun = null;\n\n              case 15:\n\n                // start a run if not in the failure state\n                if (state !== FAIL_STATE && startRun == null) {\n                  startRun = p;\n                }\n\n                // if accepting, mark the potential match end\n                if (self.accepting[state]) {\n                  lastAccepting = p;\n                }\n\n                // reset the state to the initial state if we get into the failure state\n                if (state === FAIL_STATE) {\n                  state = INITIAL_STATE;\n                }\n\n              case 18:\n                p++;\n                _context.next = 5;\n                break;\n\n              case 21:\n                if (!(startRun != null && lastAccepting != null && lastAccepting >= startRun)) {\n                  _context.next = 24;\n                  break;\n                }\n\n                _context.next = 24;\n                return [startRun, lastAccepting, self.tags[state]];\n\n              case 24:\n              case 'end':\n                return _context.stop();\n            }\n          }\n        }, _callee, this);\n      }));\n    }\n\n    /**\n     * For each match over the input sequence, action functions matching\n     * the tag definitions in the input pattern are called with the startIndex,\n     * endIndex, and sub-match sequence.\n     */\n\n  }, {\n    key: 'apply',\n    value: function apply(str, actions) {\n      var _iteratorNormalCompletion = true;\n      var _didIteratorError = false;\n      var _iteratorError = undefined;\n\n      try {\n        for (var _iterator = _getIterator(this.match(str)), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {\n          var _step$value = _slicedToArray(_step.value, 3);\n\n          var start = _step$value[0];\n          var end = _step$value[1];\n          var tags = _step$value[2];\n          var _iteratorNormalCompletion2 = true;\n          var _didIteratorError2 = false;\n          var _iteratorError2 = undefined;\n\n          try {\n            for (var _iterator2 = _getIterator(tags), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {\n              var tag = _step2.value;\n\n              if (typeof actions[tag] === 'function') {\n                actions[tag](start, end, str.slice(start, end + 1));\n              }\n            }\n          } catch (err) {\n            _didIteratorError2 = true;\n            _iteratorError2 = err;\n          } finally {\n            try {\n              if (!_iteratorNormalCompletion2 && _iterator2.return) {\n                _iterator2.return();\n              }\n            } finally {\n              if (_didIteratorError2) {\n                throw _iteratorError2;\n              }\n            }\n          }\n        }\n      } catch (err) {\n        _didIteratorError = true;\n        _iteratorError = err;\n      } finally {\n        try {\n          if (!_iteratorNormalCompletion && _iterator.return) {\n            _iterator.return();\n          }\n        } finally {\n          if (_didIteratorError) {\n            throw _iteratorError;\n          }\n        }\n      }\n    }\n  }]);\n\n  return StateMachine;\n}();\n\nmodule.exports = StateMachine;\n\n\n/***/ }),\n/* 272 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nvar _isIterable2 = __webpack_require__(273);\n\nvar _isIterable3 = _interopRequireDefault(_isIterable2);\n\nvar _getIterator2 = __webpack_require__(60);\n\nvar _getIterator3 = _interopRequireDefault(_getIterator2);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nexports.default = function () {\n  function sliceIterator(arr, i) {\n    var _arr = [];\n    var _n = true;\n    var _d = false;\n    var _e = undefined;\n\n    try {\n      for (var _i = (0, _getIterator3.default)(arr), _s; !(_n = (_s = _i.next()).done); _n = true) {\n        _arr.push(_s.value);\n\n        if (i && _arr.length === i) break;\n      }\n    } catch (err) {\n      _d = true;\n      _e = err;\n    } finally {\n      try {\n        if (!_n && _i[\"return\"]) _i[\"return\"]();\n      } finally {\n        if (_d) throw _e;\n      }\n    }\n\n    return _arr;\n  }\n\n  return function (arr, i) {\n    if (Array.isArray(arr)) {\n      return arr;\n    } else if ((0, _isIterable3.default)(Object(arr))) {\n      return sliceIterator(arr, i);\n    } else {\n      throw new TypeError(\"Invalid attempt to destructure non-iterable instance\");\n    }\n  };\n}();\n\n/***/ }),\n/* 273 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(274), __esModule: true };\n\n/***/ }),\n/* 274 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(28);\n__webpack_require__(24);\nmodule.exports = __webpack_require__(275);\n\n\n/***/ }),\n/* 275 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar classof = __webpack_require__(68);\nvar ITERATOR = __webpack_require__(4)('iterator');\nvar Iterators = __webpack_require__(23);\nmodule.exports = __webpack_require__(2).isIterable = function (it) {\n  var O = Object(it);\n  return O[ITERATOR] !== undefined\n    || '@@iterator' in O\n    // eslint-disable-next-line no-prototype-builtins\n    || Iterators.hasOwnProperty(classof(O));\n};\n\n\n/***/ }),\n/* 276 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.__esModule = true;\n\nvar _defineProperty = __webpack_require__(74);\n\nvar _defineProperty2 = _interopRequireDefault(_defineProperty);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nexports.default = function (obj, key, value) {\n  if (key in obj) {\n    (0, _defineProperty2.default)(obj, key, {\n      value: value,\n      enumerable: true,\n      configurable: true,\n      writable: true\n    });\n  } else {\n    obj[key] = value;\n  }\n\n  return obj;\n};\n\n/***/ }),\n/* 277 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(278);\n\n\n/***/ }),\n/* 278 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n * Copyright (c) 2014-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n// This method of obtaining a reference to the global object needs to be\n// kept identical to the way it is obtained in runtime.js\nvar g = (function() { return this })() || Function(\"return this\")();\n\n// Use `getOwnPropertyNames` because not all browsers support calling\n// `hasOwnProperty` on the global `self` object in a worker. See #183.\nvar hadRuntime = g.regeneratorRuntime &&\n  Object.getOwnPropertyNames(g).indexOf(\"regeneratorRuntime\") >= 0;\n\n// Save the old regeneratorRuntime in case it needs to be restored later.\nvar oldRuntime = hadRuntime && g.regeneratorRuntime;\n\n// Force reevalutation of runtime.js.\ng.regeneratorRuntime = undefined;\n\nmodule.exports = __webpack_require__(279);\n\nif (hadRuntime) {\n  // Restore the original runtime.\n  g.regeneratorRuntime = oldRuntime;\n} else {\n  // Remove the global property added by runtime.js.\n  try {\n    delete g.regeneratorRuntime;\n  } catch(e) {\n    g.regeneratorRuntime = undefined;\n  }\n}\n\n\n/***/ }),\n/* 279 */\n/***/ (function(module, exports) {\n\n/**\n * Copyright (c) 2014-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n!(function(global) {\n  \"use strict\";\n\n  var Op = Object.prototype;\n  var hasOwn = Op.hasOwnProperty;\n  var undefined; // More compressible than void 0.\n  var $Symbol = typeof Symbol === \"function\" ? Symbol : {};\n  var iteratorSymbol = $Symbol.iterator || \"@@iterator\";\n  var asyncIteratorSymbol = $Symbol.asyncIterator || \"@@asyncIterator\";\n  var toStringTagSymbol = $Symbol.toStringTag || \"@@toStringTag\";\n\n  var inModule = typeof module === \"object\";\n  var runtime = global.regeneratorRuntime;\n  if (runtime) {\n    if (inModule) {\n      // If regeneratorRuntime is defined globally and we're in a module,\n      // make the exports object identical to regeneratorRuntime.\n      module.exports = runtime;\n    }\n    // Don't bother evaluating the rest of this file if the runtime was\n    // already defined globally.\n    return;\n  }\n\n  // Define the runtime globally (as expected by generated code) as either\n  // module.exports (if we're in a module) or a new, empty object.\n  runtime = global.regeneratorRuntime = inModule ? module.exports : {};\n\n  function wrap(innerFn, outerFn, self, tryLocsList) {\n    // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.\n    var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;\n    var generator = Object.create(protoGenerator.prototype);\n    var context = new Context(tryLocsList || []);\n\n    // The ._invoke method unifies the implementations of the .next,\n    // .throw, and .return methods.\n    generator._invoke = makeInvokeMethod(innerFn, self, context);\n\n    return generator;\n  }\n  runtime.wrap = wrap;\n\n  // Try/catch helper to minimize deoptimizations. Returns a completion\n  // record like context.tryEntries[i].completion. This interface could\n  // have been (and was previously) designed to take a closure to be\n  // invoked without arguments, but in all the cases we care about we\n  // already have an existing method we want to call, so there's no need\n  // to create a new function object. We can even get away with assuming\n  // the method takes exactly one argument, since that happens to be true\n  // in every case, so we don't have to touch the arguments object. The\n  // only additional allocation required is the completion record, which\n  // has a stable shape and so hopefully should be cheap to allocate.\n  function tryCatch(fn, obj, arg) {\n    try {\n      return { type: \"normal\", arg: fn.call(obj, arg) };\n    } catch (err) {\n      return { type: \"throw\", arg: err };\n    }\n  }\n\n  var GenStateSuspendedStart = \"suspendedStart\";\n  var GenStateSuspendedYield = \"suspendedYield\";\n  var GenStateExecuting = \"executing\";\n  var GenStateCompleted = \"completed\";\n\n  // Returning this object from the innerFn has the same effect as\n  // breaking out of the dispatch switch statement.\n  var ContinueSentinel = {};\n\n  // Dummy constructor functions that we use as the .constructor and\n  // .constructor.prototype properties for functions that return Generator\n  // objects. For full spec compliance, you may wish to configure your\n  // minifier not to mangle the names of these two functions.\n  function Generator() {}\n  function GeneratorFunction() {}\n  function GeneratorFunctionPrototype() {}\n\n  // This is a polyfill for %IteratorPrototype% for environments that\n  // don't natively support it.\n  var IteratorPrototype = {};\n  IteratorPrototype[iteratorSymbol] = function () {\n    return this;\n  };\n\n  var getProto = Object.getPrototypeOf;\n  var NativeIteratorPrototype = getProto && getProto(getProto(values([])));\n  if (NativeIteratorPrototype &&\n      NativeIteratorPrototype !== Op &&\n      hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {\n    // This environment has a native %IteratorPrototype%; use it instead\n    // of the polyfill.\n    IteratorPrototype = NativeIteratorPrototype;\n  }\n\n  var Gp = GeneratorFunctionPrototype.prototype =\n    Generator.prototype = Object.create(IteratorPrototype);\n  GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;\n  GeneratorFunctionPrototype.constructor = GeneratorFunction;\n  GeneratorFunctionPrototype[toStringTagSymbol] =\n    GeneratorFunction.displayName = \"GeneratorFunction\";\n\n  // Helper for defining the .next, .throw, and .return methods of the\n  // Iterator interface in terms of a single ._invoke method.\n  function defineIteratorMethods(prototype) {\n    [\"next\", \"throw\", \"return\"].forEach(function(method) {\n      prototype[method] = function(arg) {\n        return this._invoke(method, arg);\n      };\n    });\n  }\n\n  runtime.isGeneratorFunction = function(genFun) {\n    var ctor = typeof genFun === \"function\" && genFun.constructor;\n    return ctor\n      ? ctor === GeneratorFunction ||\n        // For the native GeneratorFunction constructor, the best we can\n        // do is to check its .name property.\n        (ctor.displayName || ctor.name) === \"GeneratorFunction\"\n      : false;\n  };\n\n  runtime.mark = function(genFun) {\n    if (Object.setPrototypeOf) {\n      Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);\n    } else {\n      genFun.__proto__ = GeneratorFunctionPrototype;\n      if (!(toStringTagSymbol in genFun)) {\n        genFun[toStringTagSymbol] = \"GeneratorFunction\";\n      }\n    }\n    genFun.prototype = Object.create(Gp);\n    return genFun;\n  };\n\n  // Within the body of any async function, `await x` is transformed to\n  // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test\n  // `hasOwn.call(value, \"__await\")` to determine if the yielded value is\n  // meant to be awaited.\n  runtime.awrap = function(arg) {\n    return { __await: arg };\n  };\n\n  function AsyncIterator(generator) {\n    function invoke(method, arg, resolve, reject) {\n      var record = tryCatch(generator[method], generator, arg);\n      if (record.type === \"throw\") {\n        reject(record.arg);\n      } else {\n        var result = record.arg;\n        var value = result.value;\n        if (value &&\n            typeof value === \"object\" &&\n            hasOwn.call(value, \"__await\")) {\n          return Promise.resolve(value.__await).then(function(value) {\n            invoke(\"next\", value, resolve, reject);\n          }, function(err) {\n            invoke(\"throw\", err, resolve, reject);\n          });\n        }\n\n        return Promise.resolve(value).then(function(unwrapped) {\n          // When a yielded Promise is resolved, its final value becomes\n          // the .value of the Promise<{value,done}> result for the\n          // current iteration. If the Promise is rejected, however, the\n          // result for this iteration will be rejected with the same\n          // reason. Note that rejections of yielded Promises are not\n          // thrown back into the generator function, as is the case\n          // when an awaited Promise is rejected. This difference in\n          // behavior between yield and await is important, because it\n          // allows the consumer to decide what to do with the yielded\n          // rejection (swallow it and continue, manually .throw it back\n          // into the generator, abandon iteration, whatever). With\n          // await, by contrast, there is no opportunity to examine the\n          // rejection reason outside the generator function, so the\n          // only option is to throw it from the await expression, and\n          // let the generator function handle the exception.\n          result.value = unwrapped;\n          resolve(result);\n        }, reject);\n      }\n    }\n\n    var previousPromise;\n\n    function enqueue(method, arg) {\n      function callInvokeWithMethodAndArg() {\n        return new Promise(function(resolve, reject) {\n          invoke(method, arg, resolve, reject);\n        });\n      }\n\n      return previousPromise =\n        // If enqueue has been called before, then we want to wait until\n        // all previous Promises have been resolved before calling invoke,\n        // so that results are always delivered in the correct order. If\n        // enqueue has not been called before, then it is important to\n        // call invoke immediately, without waiting on a callback to fire,\n        // so that the async generator function has the opportunity to do\n        // any necessary setup in a predictable way. This predictability\n        // is why the Promise constructor synchronously invokes its\n        // executor callback, and why async functions synchronously\n        // execute code before the first await. Since we implement simple\n        // async functions in terms of async generators, it is especially\n        // important to get this right, even though it requires care.\n        previousPromise ? previousPromise.then(\n          callInvokeWithMethodAndArg,\n          // Avoid propagating failures to Promises returned by later\n          // invocations of the iterator.\n          callInvokeWithMethodAndArg\n        ) : callInvokeWithMethodAndArg();\n    }\n\n    // Define the unified helper method that is used to implement .next,\n    // .throw, and .return (see defineIteratorMethods).\n    this._invoke = enqueue;\n  }\n\n  defineIteratorMethods(AsyncIterator.prototype);\n  AsyncIterator.prototype[asyncIteratorSymbol] = function () {\n    return this;\n  };\n  runtime.AsyncIterator = AsyncIterator;\n\n  // Note that simple async functions are implemented on top of\n  // AsyncIterator objects; they just return a Promise for the value of\n  // the final result produced by the iterator.\n  runtime.async = function(innerFn, outerFn, self, tryLocsList) {\n    var iter = new AsyncIterator(\n      wrap(innerFn, outerFn, self, tryLocsList)\n    );\n\n    return runtime.isGeneratorFunction(outerFn)\n      ? iter // If outerFn is a generator, return the full iterator.\n      : iter.next().then(function(result) {\n          return result.done ? result.value : iter.next();\n        });\n  };\n\n  function makeInvokeMethod(innerFn, self, context) {\n    var state = GenStateSuspendedStart;\n\n    return function invoke(method, arg) {\n      if (state === GenStateExecuting) {\n        throw new Error(\"Generator is already running\");\n      }\n\n      if (state === GenStateCompleted) {\n        if (method === \"throw\") {\n          throw arg;\n        }\n\n        // Be forgiving, per 25.3.3.3.3 of the spec:\n        // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume\n        return doneResult();\n      }\n\n      context.method = method;\n      context.arg = arg;\n\n      while (true) {\n        var delegate = context.delegate;\n        if (delegate) {\n          var delegateResult = maybeInvokeDelegate(delegate, context);\n          if (delegateResult) {\n            if (delegateResult === ContinueSentinel) continue;\n            return delegateResult;\n          }\n        }\n\n        if (context.method === \"next\") {\n          // Setting context._sent for legacy support of Babel's\n          // function.sent implementation.\n          context.sent = context._sent = context.arg;\n\n        } else if (context.method === \"throw\") {\n          if (state === GenStateSuspendedStart) {\n            state = GenStateCompleted;\n            throw context.arg;\n          }\n\n          context.dispatchException(context.arg);\n\n        } else if (context.method === \"return\") {\n          context.abrupt(\"return\", context.arg);\n        }\n\n        state = GenStateExecuting;\n\n        var record = tryCatch(innerFn, self, context);\n        if (record.type === \"normal\") {\n          // If an exception is thrown from innerFn, we leave state ===\n          // GenStateExecuting and loop back for another invocation.\n          state = context.done\n            ? GenStateCompleted\n            : GenStateSuspendedYield;\n\n          if (record.arg === ContinueSentinel) {\n            continue;\n          }\n\n          return {\n            value: record.arg,\n            done: context.done\n          };\n\n        } else if (record.type === \"throw\") {\n          state = GenStateCompleted;\n          // Dispatch the exception by looping back around to the\n          // context.dispatchException(context.arg) call above.\n          context.method = \"throw\";\n          context.arg = record.arg;\n        }\n      }\n    };\n  }\n\n  // Call delegate.iterator[context.method](context.arg) and handle the\n  // result, either by returning a { value, done } result from the\n  // delegate iterator, or by modifying context.method and context.arg,\n  // setting context.delegate to null, and returning the ContinueSentinel.\n  function maybeInvokeDelegate(delegate, context) {\n    var method = delegate.iterator[context.method];\n    if (method === undefined) {\n      // A .throw or .return when the delegate iterator has no .throw\n      // method always terminates the yield* loop.\n      context.delegate = null;\n\n      if (context.method === \"throw\") {\n        if (delegate.iterator.return) {\n          // If the delegate iterator has a return method, give it a\n          // chance to clean up.\n          context.method = \"return\";\n          context.arg = undefined;\n          maybeInvokeDelegate(delegate, context);\n\n          if (context.method === \"throw\") {\n            // If maybeInvokeDelegate(context) changed context.method from\n            // \"return\" to \"throw\", let that override the TypeError below.\n            return ContinueSentinel;\n          }\n        }\n\n        context.method = \"throw\";\n        context.arg = new TypeError(\n          \"The iterator does not provide a 'throw' method\");\n      }\n\n      return ContinueSentinel;\n    }\n\n    var record = tryCatch(method, delegate.iterator, context.arg);\n\n    if (record.type === \"throw\") {\n      context.method = \"throw\";\n      context.arg = record.arg;\n      context.delegate = null;\n      return ContinueSentinel;\n    }\n\n    var info = record.arg;\n\n    if (! info) {\n      context.method = \"throw\";\n      context.arg = new TypeError(\"iterator result is not an object\");\n      context.delegate = null;\n      return ContinueSentinel;\n    }\n\n    if (info.done) {\n      // Assign the result of the finished delegate to the temporary\n      // variable specified by delegate.resultName (see delegateYield).\n      context[delegate.resultName] = info.value;\n\n      // Resume execution at the desired location (see delegateYield).\n      context.next = delegate.nextLoc;\n\n      // If context.method was \"throw\" but the delegate handled the\n      // exception, let the outer generator proceed normally. If\n      // context.method was \"next\", forget context.arg since it has been\n      // \"consumed\" by the delegate iterator. If context.method was\n      // \"return\", allow the original .return call to continue in the\n      // outer generator.\n      if (context.method !== \"return\") {\n        context.method = \"next\";\n        context.arg = undefined;\n      }\n\n    } else {\n      // Re-yield the result returned by the delegate method.\n      return info;\n    }\n\n    // The delegate iterator is finished, so forget it and continue with\n    // the outer generator.\n    context.delegate = null;\n    return ContinueSentinel;\n  }\n\n  // Define Generator.prototype.{next,throw,return} in terms of the\n  // unified ._invoke helper method.\n  defineIteratorMethods(Gp);\n\n  Gp[toStringTagSymbol] = \"Generator\";\n\n  // A Generator should always return itself as the iterator object when the\n  // @@iterator function is called on it. Some browsers' implementations of the\n  // iterator prototype chain incorrectly implement this, causing the Generator\n  // object to not be returned from this call. This ensures that doesn't happen.\n  // See https://github.com/facebook/regenerator/issues/274 for more details.\n  Gp[iteratorSymbol] = function() {\n    return this;\n  };\n\n  Gp.toString = function() {\n    return \"[object Generator]\";\n  };\n\n  function pushTryEntry(locs) {\n    var entry = { tryLoc: locs[0] };\n\n    if (1 in locs) {\n      entry.catchLoc = locs[1];\n    }\n\n    if (2 in locs) {\n      entry.finallyLoc = locs[2];\n      entry.afterLoc = locs[3];\n    }\n\n    this.tryEntries.push(entry);\n  }\n\n  function resetTryEntry(entry) {\n    var record = entry.completion || {};\n    record.type = \"normal\";\n    delete record.arg;\n    entry.completion = record;\n  }\n\n  function Context(tryLocsList) {\n    // The root entry object (effectively a try statement without a catch\n    // or a finally block) gives us a place to store values thrown from\n    // locations where there is no enclosing try statement.\n    this.tryEntries = [{ tryLoc: \"root\" }];\n    tryLocsList.forEach(pushTryEntry, this);\n    this.reset(true);\n  }\n\n  runtime.keys = function(object) {\n    var keys = [];\n    for (var key in object) {\n      keys.push(key);\n    }\n    keys.reverse();\n\n    // Rather than returning an object with a next method, we keep\n    // things simple and return the next function itself.\n    return function next() {\n      while (keys.length) {\n        var key = keys.pop();\n        if (key in object) {\n          next.value = key;\n          next.done = false;\n          return next;\n        }\n      }\n\n      // To avoid creating an additional object, we just hang the .value\n      // and .done properties off the next function object itself. This\n      // also ensures that the minifier will not anonymize the function.\n      next.done = true;\n      return next;\n    };\n  };\n\n  function values(iterable) {\n    if (iterable) {\n      var iteratorMethod = iterable[iteratorSymbol];\n      if (iteratorMethod) {\n        return iteratorMethod.call(iterable);\n      }\n\n      if (typeof iterable.next === \"function\") {\n        return iterable;\n      }\n\n      if (!isNaN(iterable.length)) {\n        var i = -1, next = function next() {\n          while (++i < iterable.length) {\n            if (hasOwn.call(iterable, i)) {\n              next.value = iterable[i];\n              next.done = false;\n              return next;\n            }\n          }\n\n          next.value = undefined;\n          next.done = true;\n\n          return next;\n        };\n\n        return next.next = next;\n      }\n    }\n\n    // Return an iterator with no values.\n    return { next: doneResult };\n  }\n  runtime.values = values;\n\n  function doneResult() {\n    return { value: undefined, done: true };\n  }\n\n  Context.prototype = {\n    constructor: Context,\n\n    reset: function(skipTempReset) {\n      this.prev = 0;\n      this.next = 0;\n      // Resetting context._sent for legacy support of Babel's\n      // function.sent implementation.\n      this.sent = this._sent = undefined;\n      this.done = false;\n      this.delegate = null;\n\n      this.method = \"next\";\n      this.arg = undefined;\n\n      this.tryEntries.forEach(resetTryEntry);\n\n      if (!skipTempReset) {\n        for (var name in this) {\n          // Not sure about the optimal order of these conditions:\n          if (name.charAt(0) === \"t\" &&\n              hasOwn.call(this, name) &&\n              !isNaN(+name.slice(1))) {\n            this[name] = undefined;\n          }\n        }\n      }\n    },\n\n    stop: function() {\n      this.done = true;\n\n      var rootEntry = this.tryEntries[0];\n      var rootRecord = rootEntry.completion;\n      if (rootRecord.type === \"throw\") {\n        throw rootRecord.arg;\n      }\n\n      return this.rval;\n    },\n\n    dispatchException: function(exception) {\n      if (this.done) {\n        throw exception;\n      }\n\n      var context = this;\n      function handle(loc, caught) {\n        record.type = \"throw\";\n        record.arg = exception;\n        context.next = loc;\n\n        if (caught) {\n          // If the dispatched exception was caught by a catch block,\n          // then let that catch block handle the exception normally.\n          context.method = \"next\";\n          context.arg = undefined;\n        }\n\n        return !! caught;\n      }\n\n      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n        var entry = this.tryEntries[i];\n        var record = entry.completion;\n\n        if (entry.tryLoc === \"root\") {\n          // Exception thrown outside of any try block that could handle\n          // it, so set the completion value of the entire function to\n          // throw the exception.\n          return handle(\"end\");\n        }\n\n        if (entry.tryLoc <= this.prev) {\n          var hasCatch = hasOwn.call(entry, \"catchLoc\");\n          var hasFinally = hasOwn.call(entry, \"finallyLoc\");\n\n          if (hasCatch && hasFinally) {\n            if (this.prev < entry.catchLoc) {\n              return handle(entry.catchLoc, true);\n            } else if (this.prev < entry.finallyLoc) {\n              return handle(entry.finallyLoc);\n            }\n\n          } else if (hasCatch) {\n            if (this.prev < entry.catchLoc) {\n              return handle(entry.catchLoc, true);\n            }\n\n          } else if (hasFinally) {\n            if (this.prev < entry.finallyLoc) {\n              return handle(entry.finallyLoc);\n            }\n\n          } else {\n            throw new Error(\"try statement without catch or finally\");\n          }\n        }\n      }\n    },\n\n    abrupt: function(type, arg) {\n      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n        var entry = this.tryEntries[i];\n        if (entry.tryLoc <= this.prev &&\n            hasOwn.call(entry, \"finallyLoc\") &&\n            this.prev < entry.finallyLoc) {\n          var finallyEntry = entry;\n          break;\n        }\n      }\n\n      if (finallyEntry &&\n          (type === \"break\" ||\n           type === \"continue\") &&\n          finallyEntry.tryLoc <= arg &&\n          arg <= finallyEntry.finallyLoc) {\n        // Ignore the finally entry if control is not jumping to a\n        // location outside the try/catch block.\n        finallyEntry = null;\n      }\n\n      var record = finallyEntry ? finallyEntry.completion : {};\n      record.type = type;\n      record.arg = arg;\n\n      if (finallyEntry) {\n        this.method = \"next\";\n        this.next = finallyEntry.finallyLoc;\n        return ContinueSentinel;\n      }\n\n      return this.complete(record);\n    },\n\n    complete: function(record, afterLoc) {\n      if (record.type === \"throw\") {\n        throw record.arg;\n      }\n\n      if (record.type === \"break\" ||\n          record.type === \"continue\") {\n        this.next = record.arg;\n      } else if (record.type === \"return\") {\n        this.rval = this.arg = record.arg;\n        this.method = \"return\";\n        this.next = \"end\";\n      } else if (record.type === \"normal\" && afterLoc) {\n        this.next = afterLoc;\n      }\n\n      return ContinueSentinel;\n    },\n\n    finish: function(finallyLoc) {\n      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n        var entry = this.tryEntries[i];\n        if (entry.finallyLoc === finallyLoc) {\n          this.complete(entry.completion, entry.afterLoc);\n          resetTryEntry(entry);\n          return ContinueSentinel;\n        }\n      }\n    },\n\n    \"catch\": function(tryLoc) {\n      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n        var entry = this.tryEntries[i];\n        if (entry.tryLoc === tryLoc) {\n          var record = entry.completion;\n          if (record.type === \"throw\") {\n            var thrown = record.arg;\n            resetTryEntry(entry);\n          }\n          return thrown;\n        }\n      }\n\n      // The context.catch method must only be called with a location\n      // argument that corresponds to a known catch block.\n      throw new Error(\"illegal catch attempt\");\n    },\n\n    delegateYield: function(iterable, resultName, nextLoc) {\n      this.delegate = {\n        iterator: values(iterable),\n        resultName: resultName,\n        nextLoc: nextLoc\n      };\n\n      if (this.method === \"next\") {\n        // Deliberately forget the last sent value so that we don't\n        // accidentally pass it on to the delegate.\n        this.arg = undefined;\n      }\n\n      return ContinueSentinel;\n    }\n  };\n})(\n  // In sloppy mode, unbound `this` refers to the global object, fallback to\n  // Function constructor if we're in global strict mode. That is sadly a form\n  // of indirect eval which violates Content Security Policy.\n  (function() { return this })() || Function(\"return this\")()\n);\n\n\n/***/ }),\n/* 280 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = { \"default\": __webpack_require__(281), __esModule: true };\n\n/***/ }),\n/* 281 */\n/***/ (function(module, exports, __webpack_require__) {\n\n__webpack_require__(282);\nmodule.exports = Math.pow(2, -52);\n\n\n/***/ }),\n/* 282 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// 20.1.2.1 Number.EPSILON\nvar $export = __webpack_require__(3);\n\n$export($export.S, 'Number', { EPSILON: Math.pow(2, -52) });\n\n\n/***/ }),\n/* 283 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {var clone = (function() {\n'use strict';\n\n/**\n * Clones (copies) an Object using deep copying.\n *\n * This function supports circular references by default, but if you are certain\n * there are no circular references in your object, you can save some CPU time\n * by calling clone(obj, false).\n *\n * Caution: if `circular` is false and `parent` contains circular references,\n * your program may enter an infinite loop and crash.\n *\n * @param `parent` - the object to be cloned\n * @param `circular` - set to true if the object to be cloned may contain\n *    circular references. (optional - true by default)\n * @param `depth` - set to a number if the object is only to be cloned to\n *    a particular depth. (optional - defaults to Infinity)\n * @param `prototype` - sets the prototype to be used when cloning an object.\n *    (optional - defaults to parent prototype).\n*/\nfunction clone(parent, circular, depth, prototype) {\n  var filter;\n  if (typeof circular === 'object') {\n    depth = circular.depth;\n    prototype = circular.prototype;\n    filter = circular.filter;\n    circular = circular.circular\n  }\n  // maintain two arrays for circular references, where corresponding parents\n  // and children have the same index\n  var allParents = [];\n  var allChildren = [];\n\n  var useBuffer = typeof Buffer != 'undefined';\n\n  if (typeof circular == 'undefined')\n    circular = true;\n\n  if (typeof depth == 'undefined')\n    depth = Infinity;\n\n  // recurse this function so we don't reset allParents and allChildren\n  function _clone(parent, depth) {\n    // cloning null always returns null\n    if (parent === null)\n      return null;\n\n    if (depth == 0)\n      return parent;\n\n    var child;\n    var proto;\n    if (typeof parent != 'object') {\n      return parent;\n    }\n\n    if (clone.__isArray(parent)) {\n      child = [];\n    } else if (clone.__isRegExp(parent)) {\n      child = new RegExp(parent.source, __getRegExpFlags(parent));\n      if (parent.lastIndex) child.lastIndex = parent.lastIndex;\n    } else if (clone.__isDate(parent)) {\n      child = new Date(parent.getTime());\n    } else if (useBuffer && Buffer.isBuffer(parent)) {\n      child = new Buffer(parent.length);\n      parent.copy(child);\n      return child;\n    } else {\n      if (typeof prototype == 'undefined') {\n        proto = Object.getPrototypeOf(parent);\n        child = Object.create(proto);\n      }\n      else {\n        child = Object.create(prototype);\n        proto = prototype;\n      }\n    }\n\n    if (circular) {\n      var index = allParents.indexOf(parent);\n\n      if (index != -1) {\n        return allChildren[index];\n      }\n      allParents.push(parent);\n      allChildren.push(child);\n    }\n\n    for (var i in parent) {\n      var attrs;\n      if (proto) {\n        attrs = Object.getOwnPropertyDescriptor(proto, i);\n      }\n\n      if (attrs && attrs.set == null) {\n        continue;\n      }\n      child[i] = _clone(parent[i], depth - 1);\n    }\n\n    return child;\n  }\n\n  return _clone(parent, depth);\n}\n\n/**\n * Simple flat clone using prototype, accepts only objects, usefull for property\n * override on FLAT configuration object (no nested props).\n *\n * USE WITH CAUTION! This may not behave as you wish if you do not know how this\n * works.\n */\nclone.clonePrototype = function clonePrototype(parent) {\n  if (parent === null)\n    return null;\n\n  var c = function () {};\n  c.prototype = parent;\n  return new c();\n};\n\n// private utility functions\n\nfunction __objToStr(o) {\n  return Object.prototype.toString.call(o);\n};\nclone.__objToStr = __objToStr;\n\nfunction __isDate(o) {\n  return typeof o === 'object' && __objToStr(o) === '[object Date]';\n};\nclone.__isDate = __isDate;\n\nfunction __isArray(o) {\n  return typeof o === 'object' && __objToStr(o) === '[object Array]';\n};\nclone.__isArray = __isArray;\n\nfunction __isRegExp(o) {\n  return typeof o === 'object' && __objToStr(o) === '[object RegExp]';\n};\nclone.__isRegExp = __isRegExp;\n\nfunction __getRegExpFlags(re) {\n  var flags = '';\n  if (re.global) flags += 'g';\n  if (re.ignoreCase) flags += 'i';\n  if (re.multiline) flags += 'm';\n  return flags;\n};\nclone.__getRegExpFlags = __getRegExpFlags;\n\nreturn clone;\n})();\n\nif (typeof module === 'object' && module.exports) {\n  module.exports = clone;\n}\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 284 */\n/***/ (function(module, exports, __webpack_require__) {\n\nmodule.exports = __webpack_require__(117).BrotliDecompressBuffer;\n\n\n/***/ }),\n/* 285 */\n/***/ (function(module, exports) {\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n   Bit reading helpers\n*/\n\nvar BROTLI_READ_SIZE = 4096;\nvar BROTLI_IBUF_SIZE =  (2 * BROTLI_READ_SIZE + 32);\nvar BROTLI_IBUF_MASK =  (2 * BROTLI_READ_SIZE - 1);\n\nvar kBitMask = new Uint32Array([\n  0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767,\n  65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215\n]);\n\n/* Input byte buffer, consist of a ringbuffer and a \"slack\" region where */\n/* bytes from the start of the ringbuffer are copied. */\nfunction BrotliBitReader(input) {\n  this.buf_ = new Uint8Array(BROTLI_IBUF_SIZE);\n  this.input_ = input;    /* input callback */\n  \n  this.reset();\n}\n\nBrotliBitReader.READ_SIZE = BROTLI_READ_SIZE;\nBrotliBitReader.IBUF_MASK = BROTLI_IBUF_MASK;\n\nBrotliBitReader.prototype.reset = function() {\n  this.buf_ptr_ = 0;      /* next input will write here */\n  this.val_ = 0;          /* pre-fetched bits */\n  this.pos_ = 0;          /* byte position in stream */\n  this.bit_pos_ = 0;      /* current bit-reading position in val_ */\n  this.bit_end_pos_ = 0;  /* bit-reading end position from LSB of val_ */\n  this.eos_ = 0;          /* input stream is finished */\n  \n  this.readMoreInput();\n  for (var i = 0; i < 4; i++) {\n    this.val_ |= this.buf_[this.pos_] << (8 * i);\n    ++this.pos_;\n  }\n  \n  return this.bit_end_pos_ > 0;\n};\n\n/* Fills up the input ringbuffer by calling the input callback.\n\n   Does nothing if there are at least 32 bytes present after current position.\n\n   Returns 0 if either:\n    - the input callback returned an error, or\n    - there is no more input and the position is past the end of the stream.\n\n   After encountering the end of the input stream, 32 additional zero bytes are\n   copied to the ringbuffer, therefore it is safe to call this function after\n   every 32 bytes of input is read.\n*/\nBrotliBitReader.prototype.readMoreInput = function() {\n  if (this.bit_end_pos_ > 256) {\n    return;\n  } else if (this.eos_) {\n    if (this.bit_pos_ > this.bit_end_pos_)\n      throw new Error('Unexpected end of input ' + this.bit_pos_ + ' ' + this.bit_end_pos_);\n  } else {\n    var dst = this.buf_ptr_;\n    var bytes_read = this.input_.read(this.buf_, dst, BROTLI_READ_SIZE);\n    if (bytes_read < 0) {\n      throw new Error('Unexpected end of input');\n    }\n    \n    if (bytes_read < BROTLI_READ_SIZE) {\n      this.eos_ = 1;\n      /* Store 32 bytes of zero after the stream end. */\n      for (var p = 0; p < 32; p++)\n        this.buf_[dst + bytes_read + p] = 0;\n    }\n    \n    if (dst === 0) {\n      /* Copy the head of the ringbuffer to the slack region. */\n      for (var p = 0; p < 32; p++)\n        this.buf_[(BROTLI_READ_SIZE << 1) + p] = this.buf_[p];\n\n      this.buf_ptr_ = BROTLI_READ_SIZE;\n    } else {\n      this.buf_ptr_ = 0;\n    }\n    \n    this.bit_end_pos_ += bytes_read << 3;\n  }\n};\n\n/* Guarantees that there are at least 24 bits in the buffer. */\nBrotliBitReader.prototype.fillBitWindow = function() {    \n  while (this.bit_pos_ >= 8) {\n    this.val_ >>>= 8;\n    this.val_ |= this.buf_[this.pos_ & BROTLI_IBUF_MASK] << 24;\n    ++this.pos_;\n    this.bit_pos_ = this.bit_pos_ - 8 >>> 0;\n    this.bit_end_pos_ = this.bit_end_pos_ - 8 >>> 0;\n  }\n};\n\n/* Reads the specified number of bits from Read Buffer. */\nBrotliBitReader.prototype.readBits = function(n_bits) {\n  if (32 - this.bit_pos_ < n_bits) {\n    this.fillBitWindow();\n  }\n  \n  var val = ((this.val_ >>> this.bit_pos_) & kBitMask[n_bits]);\n  this.bit_pos_ += n_bits;\n  return val;\n};\n\nmodule.exports = BrotliBitReader;\n\n\n/***/ }),\n/* 286 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar base64 = __webpack_require__(287);\nvar fs = __webpack_require__(8);\n\n/**\n * The normal dictionary-data.js is quite large, which makes it \n * unsuitable for browser usage. In order to make it smaller, \n * we read dictionary.bin, which is a compressed version of\n * the dictionary, and on initial load, Brotli decompresses \n * it's own dictionary. 😜\n */\nexports.init = function() {\n  var BrotliDecompressBuffer = __webpack_require__(117).BrotliDecompressBuffer;\n  var compressed = base64.toByteArray(__webpack_require__(288));\n  return BrotliDecompressBuffer(compressed);\n};\n\n\n/***/ }),\n/* 287 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nexports.byteLength = byteLength\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nvar code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\nfor (var i = 0, len = code.length; i < len; ++i) {\n  lookup[i] = code[i]\n  revLookup[code.charCodeAt(i)] = i\n}\n\n// Support decoding URL-safe base64 strings, as Node.js does.\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\nrevLookup['-'.charCodeAt(0)] = 62\nrevLookup['_'.charCodeAt(0)] = 63\n\nfunction placeHoldersCount (b64) {\n  var len = b64.length\n  if (len % 4 > 0) {\n    throw new Error('Invalid string. Length must be a multiple of 4')\n  }\n\n  // the number of equal signs (place holders)\n  // if there are two placeholders, than the two characters before it\n  // represent one byte\n  // if there is only one, then the three characters before it represent 2 bytes\n  // this is just a cheap hack to not do indexOf twice\n  return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0\n}\n\nfunction byteLength (b64) {\n  // base64 is 4/3 + up to two characters of the original data\n  return (b64.length * 3 / 4) - placeHoldersCount(b64)\n}\n\nfunction toByteArray (b64) {\n  var i, l, tmp, placeHolders, arr\n  var len = b64.length\n  placeHolders = placeHoldersCount(b64)\n\n  arr = new Arr((len * 3 / 4) - placeHolders)\n\n  // if there are placeholders, only get up to the last complete 4 chars\n  l = placeHolders > 0 ? len - 4 : len\n\n  var L = 0\n\n  for (i = 0; i < l; i += 4) {\n    tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]\n    arr[L++] = (tmp >> 16) & 0xFF\n    arr[L++] = (tmp >> 8) & 0xFF\n    arr[L++] = tmp & 0xFF\n  }\n\n  if (placeHolders === 2) {\n    tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)\n    arr[L++] = tmp & 0xFF\n  } else if (placeHolders === 1) {\n    tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)\n    arr[L++] = (tmp >> 8) & 0xFF\n    arr[L++] = tmp & 0xFF\n  }\n\n  return arr\n}\n\nfunction tripletToBase64 (num) {\n  return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n  var tmp\n  var output = []\n  for (var i = start; i < end; i += 3) {\n    tmp = ((uint8[i] << 16) & 0xFF0000) + ((uint8[i + 1] << 8) & 0xFF00) + (uint8[i + 2] & 0xFF)\n    output.push(tripletToBase64(tmp))\n  }\n  return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n  var tmp\n  var len = uint8.length\n  var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n  var output = ''\n  var parts = []\n  var maxChunkLength = 16383 // must be multiple of 3\n\n  // go through the array every three bytes, we'll deal with trailing stuff later\n  for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n    parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n  }\n\n  // pad the end with zeros, but make sure to not forget the extra bytes\n  if (extraBytes === 1) {\n    tmp = uint8[len - 1]\n    output += lookup[tmp >> 2]\n    output += lookup[(tmp << 4) & 0x3F]\n    output += '=='\n  } else if (extraBytes === 2) {\n    tmp = (uint8[len - 2] << 8) + (uint8[len - 1])\n    output += lookup[tmp >> 10]\n    output += lookup[(tmp >> 4) & 0x3F]\n    output += lookup[(tmp << 2) & 0x3F]\n    output += '='\n  }\n\n  parts.push(output)\n\n  return parts.join('')\n}\n\n\n/***/ }),\n/* 288 */\n/***/ (function(module, exports) {\n\nmodule.exports=\"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\";\n\n\n/***/ }),\n/* 289 */\n/***/ (function(module, exports) {\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n   Lookup table to map the previous two bytes to a context id.\n\n   There are four different context modeling modes defined here:\n     CONTEXT_LSB6: context id is the least significant 6 bits of the last byte,\n     CONTEXT_MSB6: context id is the most significant 6 bits of the last byte,\n     CONTEXT_UTF8: second-order context model tuned for UTF8-encoded text,\n     CONTEXT_SIGNED: second-order context model tuned for signed integers.\n\n   The context id for the UTF8 context model is calculated as follows. If p1\n   and p2 are the previous two bytes, we calcualte the context as\n\n     context = kContextLookup[p1] | kContextLookup[p2 + 256].\n\n   If the previous two bytes are ASCII characters (i.e. < 128), this will be\n   equivalent to\n\n     context = 4 * context1(p1) + context2(p2),\n\n   where context1 is based on the previous byte in the following way:\n\n     0  : non-ASCII control\n     1  : \\t, \\n, \\r\n     2  : space\n     3  : other punctuation\n     4  : \" '\n     5  : %\n     6  : ( < [ {\n     7  : ) > ] }\n     8  : , ; :\n     9  : .\n     10 : =\n     11 : number\n     12 : upper-case vowel\n     13 : upper-case consonant\n     14 : lower-case vowel\n     15 : lower-case consonant\n\n   and context2 is based on the second last byte:\n\n     0 : control, space\n     1 : punctuation\n     2 : upper-case letter, number\n     3 : lower-case letter\n\n   If the last byte is ASCII, and the second last byte is not (in a valid UTF8\n   stream it will be a continuation byte, value between 128 and 191), the\n   context is the same as if the second last byte was an ASCII control or space.\n\n   If the last byte is a UTF8 lead byte (value >= 192), then the next byte will\n   be a continuation byte and the context id is 2 or 3 depending on the LSB of\n   the last byte and to a lesser extent on the second last byte if it is ASCII.\n\n   If the last byte is a UTF8 continuation byte, the second last byte can be:\n     - continuation byte: the next byte is probably ASCII or lead byte (assuming\n       4-byte UTF8 characters are rare) and the context id is 0 or 1.\n     - lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1\n     - lead byte (208 - 255): next byte is continuation byte, context is 2 or 3\n\n   The possible value combinations of the previous two bytes, the range of\n   context ids and the type of the next byte is summarized in the table below:\n\n   |--------\\-----------------------------------------------------------------|\n   |         \\                         Last byte                              |\n   | Second   \\---------------------------------------------------------------|\n   | last byte \\    ASCII            |   cont. byte        |   lead byte      |\n   |            \\   (0-127)          |   (128-191)         |   (192-)         |\n   |=============|===================|=====================|==================|\n   |  ASCII      | next: ASCII/lead  |  not valid          |  next: cont.     |\n   |  (0-127)    | context: 4 - 63   |                     |  context: 2 - 3  |\n   |-------------|-------------------|---------------------|------------------|\n   |  cont. byte | next: ASCII/lead  |  next: ASCII/lead   |  next: cont.     |\n   |  (128-191)  | context: 4 - 63   |  context: 0 - 1     |  context: 2 - 3  |\n   |-------------|-------------------|---------------------|------------------|\n   |  lead byte  | not valid         |  next: ASCII/lead   |  not valid       |\n   |  (192-207)  |                   |  context: 0 - 1     |                  |\n   |-------------|-------------------|---------------------|------------------|\n   |  lead byte  | not valid         |  next: cont.        |  not valid       |\n   |  (208-)     |                   |  context: 2 - 3     |                  |\n   |-------------|-------------------|---------------------|------------------|\n\n   The context id for the signed context mode is calculated as:\n\n     context = (kContextLookup[512 + p1] << 3) | kContextLookup[512 + p2].\n\n   For any context modeling modes, the context ids can be calculated by |-ing\n   together two lookups from one table using context model dependent offsets:\n\n     context = kContextLookup[offset1 + p1] | kContextLookup[offset2 + p2].\n\n   where offset1 and offset2 are dependent on the context mode.\n*/\n\nvar CONTEXT_LSB6         = 0;\nvar CONTEXT_MSB6         = 1;\nvar CONTEXT_UTF8         = 2;\nvar CONTEXT_SIGNED       = 3;\n\n/* Common context lookup table for all context modes. */\nexports.lookup = new Uint8Array([\n  /* CONTEXT_UTF8, last byte. */\n  /* ASCII range. */\n   0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  4,  0,  0,  4,  0,  0,\n   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,\n   8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,\n  44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,\n  12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,\n  52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,\n  12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,\n  60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12,  0,\n  /* UTF8 continuation byte range. */\n  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,\n  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,\n  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,\n  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,\n  /* UTF8 lead byte range. */\n  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,\n  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,\n  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,\n  2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,\n  /* CONTEXT_UTF8 second last byte. */\n  /* ASCII range. */\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,\n  1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,\n  1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0,\n  /* UTF8 continuation byte range. */\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  /* UTF8 lead byte range. */\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n  /* CONTEXT_SIGNED, second last byte. */\n  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n  4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,\n  /* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */\n   0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,\n  16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,\n  16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,\n  16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,\n  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,\n  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,\n  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,\n  32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,\n  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,\n  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,\n  40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,\n  48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56,\n  /* CONTEXT_LSB6, last byte. */\n   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,\n  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,\n  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\n   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,\n  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,\n  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\n   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,\n  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,\n  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\n   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,\n  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,\n  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\n  /* CONTEXT_MSB6, last byte. */\n   0,  0,  0,  0,  1,  1,  1,  1,  2,  2,  2,  2,  3,  3,  3,  3,\n   4,  4,  4,  4,  5,  5,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,\n   8,  8,  8,  8,  9,  9,  9,  9, 10, 10, 10, 10, 11, 11, 11, 11,\n  12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,\n  16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,\n  20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,\n  24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,\n  28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,\n  32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,\n  36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,\n  40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,\n  44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,\n  48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,\n  52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,\n  56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,\n  60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,\n  /* CONTEXT_{M,L}SB6, second last byte, */\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n]);\n\nexports.lookupOffsets = new Uint16Array([\n  /* CONTEXT_LSB6 */\n  1024, 1536,\n  /* CONTEXT_MSB6 */\n  1280, 1536,\n  /* CONTEXT_UTF8 */\n  0, 256,\n  /* CONTEXT_SIGNED */\n  768, 512,\n]);\n\n\n/***/ }),\n/* 290 */\n/***/ (function(module, exports) {\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n   Lookup tables to map prefix codes to value ranges. This is used during\n   decoding of the block lengths, literal insertion lengths and copy lengths.\n*/\n\n/* Represents the range of values belonging to a prefix code: */\n/* [offset, offset + 2^nbits) */\nfunction PrefixCodeRange(offset, nbits) {\n  this.offset = offset;\n  this.nbits = nbits;\n}\n\nexports.kBlockLengthPrefixCode = [\n  new PrefixCodeRange(1, 2), new PrefixCodeRange(5, 2), new PrefixCodeRange(9, 2), new PrefixCodeRange(13, 2),\n  new PrefixCodeRange(17, 3), new PrefixCodeRange(25, 3), new PrefixCodeRange(33, 3), new PrefixCodeRange(41, 3),\n  new PrefixCodeRange(49, 4), new PrefixCodeRange(65, 4), new PrefixCodeRange(81, 4), new PrefixCodeRange(97, 4),\n  new PrefixCodeRange(113, 5), new PrefixCodeRange(145, 5), new PrefixCodeRange(177, 5), new PrefixCodeRange(209, 5),\n  new PrefixCodeRange(241, 6), new PrefixCodeRange(305, 6), new PrefixCodeRange(369, 7), new PrefixCodeRange(497, 8),\n  new PrefixCodeRange(753, 9), new PrefixCodeRange(1265, 10), new PrefixCodeRange(2289, 11), new PrefixCodeRange(4337, 12),\n  new PrefixCodeRange(8433, 13), new PrefixCodeRange(16625, 24)\n];\n\nexports.kInsertLengthPrefixCode = [\n  new PrefixCodeRange(0, 0), new PrefixCodeRange(1, 0), new PrefixCodeRange(2, 0), new PrefixCodeRange(3, 0),\n  new PrefixCodeRange(4, 0), new PrefixCodeRange(5, 0), new PrefixCodeRange(6, 1), new PrefixCodeRange(8, 1),\n  new PrefixCodeRange(10, 2), new PrefixCodeRange(14, 2), new PrefixCodeRange(18, 3), new PrefixCodeRange(26, 3),\n  new PrefixCodeRange(34, 4), new PrefixCodeRange(50, 4), new PrefixCodeRange(66, 5), new PrefixCodeRange(98, 5),\n  new PrefixCodeRange(130, 6), new PrefixCodeRange(194, 7), new PrefixCodeRange(322, 8), new PrefixCodeRange(578, 9),\n  new PrefixCodeRange(1090, 10), new PrefixCodeRange(2114, 12), new PrefixCodeRange(6210, 14), new PrefixCodeRange(22594, 24),\n];\n\nexports.kCopyLengthPrefixCode = [\n  new PrefixCodeRange(2, 0), new PrefixCodeRange(3, 0), new PrefixCodeRange(4, 0), new PrefixCodeRange(5, 0),\n  new PrefixCodeRange(6, 0), new PrefixCodeRange(7, 0), new PrefixCodeRange(8, 0), new PrefixCodeRange(9, 0),\n  new PrefixCodeRange(10, 1), new PrefixCodeRange(12, 1), new PrefixCodeRange(14, 2), new PrefixCodeRange(18, 2),\n  new PrefixCodeRange(22, 3), new PrefixCodeRange(30, 3), new PrefixCodeRange(38, 4), new PrefixCodeRange(54, 4),\n  new PrefixCodeRange(70, 5), new PrefixCodeRange(102, 5), new PrefixCodeRange(134, 6), new PrefixCodeRange(198, 7),\n  new PrefixCodeRange(326, 8), new PrefixCodeRange(582, 9), new PrefixCodeRange(1094, 10), new PrefixCodeRange(2118, 24),\n];\n\nexports.kInsertRangeLut = [\n  0, 0, 8, 8, 0, 16, 8, 16, 16,\n];\n\nexports.kCopyRangeLut = [\n  0, 8, 0, 8, 16, 0, 16, 8, 16,\n];\n\n\n/***/ }),\n/* 291 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n   Transformations on dictionary words.\n*/\n\nvar BrotliDictionary = __webpack_require__(119);\n\nvar kIdentity       = 0;\nvar kOmitLast1      = 1;\nvar kOmitLast2      = 2;\nvar kOmitLast3      = 3;\nvar kOmitLast4      = 4;\nvar kOmitLast5      = 5;\nvar kOmitLast6      = 6;\nvar kOmitLast7      = 7;\nvar kOmitLast8      = 8;\nvar kOmitLast9      = 9;\nvar kUppercaseFirst = 10;\nvar kUppercaseAll   = 11;\nvar kOmitFirst1     = 12;\nvar kOmitFirst2     = 13;\nvar kOmitFirst3     = 14;\nvar kOmitFirst4     = 15;\nvar kOmitFirst5     = 16;\nvar kOmitFirst6     = 17;\nvar kOmitFirst7     = 18;\nvar kOmitFirst8     = 19;\nvar kOmitFirst9     = 20;\n\nfunction Transform(prefix, transform, suffix) {\n  this.prefix = new Uint8Array(prefix.length);\n  this.transform = transform;\n  this.suffix = new Uint8Array(suffix.length);\n  \n  for (var i = 0; i < prefix.length; i++)\n    this.prefix[i] = prefix.charCodeAt(i);\n  \n  for (var i = 0; i < suffix.length; i++)\n    this.suffix[i] = suffix.charCodeAt(i);\n}\n\nvar kTransforms = [\n     new Transform(         \"\", kIdentity,       \"\"           ),\n     new Transform(         \"\", kIdentity,       \" \"          ),\n     new Transform(        \" \", kIdentity,       \" \"          ),\n     new Transform(         \"\", kOmitFirst1,     \"\"           ),\n     new Transform(         \"\", kUppercaseFirst, \" \"          ),\n     new Transform(         \"\", kIdentity,       \" the \"      ),\n     new Transform(        \" \", kIdentity,       \"\"           ),\n     new Transform(       \"s \", kIdentity,       \" \"          ),\n     new Transform(         \"\", kIdentity,       \" of \"       ),\n     new Transform(         \"\", kUppercaseFirst, \"\"           ),\n     new Transform(         \"\", kIdentity,       \" and \"      ),\n     new Transform(         \"\", kOmitFirst2,     \"\"           ),\n     new Transform(         \"\", kOmitLast1,      \"\"           ),\n     new Transform(       \", \", kIdentity,       \" \"          ),\n     new Transform(         \"\", kIdentity,       \", \"         ),\n     new Transform(        \" \", kUppercaseFirst, \" \"          ),\n     new Transform(         \"\", kIdentity,       \" in \"       ),\n     new Transform(         \"\", kIdentity,       \" to \"       ),\n     new Transform(       \"e \", kIdentity,       \" \"          ),\n     new Transform(         \"\", kIdentity,       \"\\\"\"         ),\n     new Transform(         \"\", kIdentity,       \".\"          ),\n     new Transform(         \"\", kIdentity,       \"\\\">\"        ),\n     new Transform(         \"\", kIdentity,       \"\\n\"         ),\n     new Transform(         \"\", kOmitLast3,      \"\"           ),\n     new Transform(         \"\", kIdentity,       \"]\"          ),\n     new Transform(         \"\", kIdentity,       \" for \"      ),\n     new Transform(         \"\", kOmitFirst3,     \"\"           ),\n     new Transform(         \"\", kOmitLast2,      \"\"           ),\n     new Transform(         \"\", kIdentity,       \" a \"        ),\n     new Transform(         \"\", kIdentity,       \" that \"     ),\n     new Transform(        \" \", kUppercaseFirst, \"\"           ),\n     new Transform(         \"\", kIdentity,       \". \"         ),\n     new Transform(        \".\", kIdentity,       \"\"           ),\n     new Transform(        \" \", kIdentity,       \", \"         ),\n     new Transform(         \"\", kOmitFirst4,     \"\"           ),\n     new Transform(         \"\", kIdentity,       \" with \"     ),\n     new Transform(         \"\", kIdentity,       \"'\"          ),\n     new Transform(         \"\", kIdentity,       \" from \"     ),\n     new Transform(         \"\", kIdentity,       \" by \"       ),\n     new Transform(         \"\", kOmitFirst5,     \"\"           ),\n     new Transform(         \"\", kOmitFirst6,     \"\"           ),\n     new Transform(    \" the \", kIdentity,       \"\"           ),\n     new Transform(         \"\", kOmitLast4,      \"\"           ),\n     new Transform(         \"\", kIdentity,       \". The \"     ),\n     new Transform(         \"\", kUppercaseAll,   \"\"           ),\n     new Transform(         \"\", kIdentity,       \" on \"       ),\n     new Transform(         \"\", kIdentity,       \" as \"       ),\n     new Transform(         \"\", kIdentity,       \" is \"       ),\n     new Transform(         \"\", kOmitLast7,      \"\"           ),\n     new Transform(         \"\", kOmitLast1,      \"ing \"       ),\n     new Transform(         \"\", kIdentity,       \"\\n\\t\"       ),\n     new Transform(         \"\", kIdentity,       \":\"          ),\n     new Transform(        \" \", kIdentity,       \". \"         ),\n     new Transform(         \"\", kIdentity,       \"ed \"        ),\n     new Transform(         \"\", kOmitFirst9,     \"\"           ),\n     new Transform(         \"\", kOmitFirst7,     \"\"           ),\n     new Transform(         \"\", kOmitLast6,      \"\"           ),\n     new Transform(         \"\", kIdentity,       \"(\"          ),\n     new Transform(         \"\", kUppercaseFirst, \", \"         ),\n     new Transform(         \"\", kOmitLast8,      \"\"           ),\n     new Transform(         \"\", kIdentity,       \" at \"       ),\n     new Transform(         \"\", kIdentity,       \"ly \"        ),\n     new Transform(    \" the \", kIdentity,       \" of \"       ),\n     new Transform(         \"\", kOmitLast5,      \"\"           ),\n     new Transform(         \"\", kOmitLast9,      \"\"           ),\n     new Transform(        \" \", kUppercaseFirst, \", \"         ),\n     new Transform(         \"\", kUppercaseFirst, \"\\\"\"         ),\n     new Transform(        \".\", kIdentity,       \"(\"          ),\n     new Transform(         \"\", kUppercaseAll,   \" \"          ),\n     new Transform(         \"\", kUppercaseFirst, \"\\\">\"        ),\n     new Transform(         \"\", kIdentity,       \"=\\\"\"        ),\n     new Transform(        \" \", kIdentity,       \".\"          ),\n     new Transform(    \".com/\", kIdentity,       \"\"           ),\n     new Transform(    \" the \", kIdentity,       \" of the \"   ),\n     new Transform(         \"\", kUppercaseFirst, \"'\"          ),\n     new Transform(         \"\", kIdentity,       \". This \"    ),\n     new Transform(         \"\", kIdentity,       \",\"          ),\n     new Transform(        \".\", kIdentity,       \" \"          ),\n     new Transform(         \"\", kUppercaseFirst, \"(\"          ),\n     new Transform(         \"\", kUppercaseFirst, \".\"          ),\n     new Transform(         \"\", kIdentity,       \" not \"      ),\n     new Transform(        \" \", kIdentity,       \"=\\\"\"        ),\n     new Transform(         \"\", kIdentity,       \"er \"        ),\n     new Transform(        \" \", kUppercaseAll,   \" \"          ),\n     new Transform(         \"\", kIdentity,       \"al \"        ),\n     new Transform(        \" \", kUppercaseAll,   \"\"           ),\n     new Transform(         \"\", kIdentity,       \"='\"         ),\n     new Transform(         \"\", kUppercaseAll,   \"\\\"\"         ),\n     new Transform(         \"\", kUppercaseFirst, \". \"         ),\n     new Transform(        \" \", kIdentity,       \"(\"          ),\n     new Transform(         \"\", kIdentity,       \"ful \"       ),\n     new Transform(        \" \", kUppercaseFirst, \". \"         ),\n     new Transform(         \"\", kIdentity,       \"ive \"       ),\n     new Transform(         \"\", kIdentity,       \"less \"      ),\n     new Transform(         \"\", kUppercaseAll,   \"'\"          ),\n     new Transform(         \"\", kIdentity,       \"est \"       ),\n     new Transform(        \" \", kUppercaseFirst, \".\"          ),\n     new Transform(         \"\", kUppercaseAll,   \"\\\">\"        ),\n     new Transform(        \" \", kIdentity,       \"='\"         ),\n     new Transform(         \"\", kUppercaseFirst, \",\"          ),\n     new Transform(         \"\", kIdentity,       \"ize \"       ),\n     new Transform(         \"\", kUppercaseAll,   \".\"          ),\n     new Transform( \"\\xc2\\xa0\", kIdentity,       \"\"           ),\n     new Transform(        \" \", kIdentity,       \",\"          ),\n     new Transform(         \"\", kUppercaseFirst, \"=\\\"\"        ),\n     new Transform(         \"\", kUppercaseAll,   \"=\\\"\"        ),\n     new Transform(         \"\", kIdentity,       \"ous \"       ),\n     new Transform(         \"\", kUppercaseAll,   \", \"         ),\n     new Transform(         \"\", kUppercaseFirst, \"='\"         ),\n     new Transform(        \" \", kUppercaseFirst, \",\"          ),\n     new Transform(        \" \", kUppercaseAll,   \"=\\\"\"        ),\n     new Transform(        \" \", kUppercaseAll,   \", \"         ),\n     new Transform(         \"\", kUppercaseAll,   \",\"          ),\n     new Transform(         \"\", kUppercaseAll,   \"(\"          ),\n     new Transform(         \"\", kUppercaseAll,   \". \"         ),\n     new Transform(        \" \", kUppercaseAll,   \".\"          ),\n     new Transform(         \"\", kUppercaseAll,   \"='\"         ),\n     new Transform(        \" \", kUppercaseAll,   \". \"         ),\n     new Transform(        \" \", kUppercaseFirst, \"=\\\"\"        ),\n     new Transform(        \" \", kUppercaseAll,   \"='\"         ),\n     new Transform(        \" \", kUppercaseFirst, \"='\"         )\n];\n\nexports.kTransforms = kTransforms;\nexports.kNumTransforms = kTransforms.length;\n\nfunction ToUpperCase(p, i) {\n  if (p[i] < 0xc0) {\n    if (p[i] >= 97 && p[i] <= 122) {\n      p[i] ^= 32;\n    }\n    return 1;\n  }\n  \n  /* An overly simplified uppercasing model for utf-8. */\n  if (p[i] < 0xe0) {\n    p[i + 1] ^= 32;\n    return 2;\n  }\n  \n  /* An arbitrary transform for three byte characters. */\n  p[i + 2] ^= 5;\n  return 3;\n}\n\nexports.transformDictionaryWord = function(dst, idx, word, len, transform) {\n  var prefix = kTransforms[transform].prefix;\n  var suffix = kTransforms[transform].suffix;\n  var t = kTransforms[transform].transform;\n  var skip = t < kOmitFirst1 ? 0 : t - (kOmitFirst1 - 1);\n  var i = 0;\n  var start_idx = idx;\n  var uppercase;\n  \n  if (skip > len) {\n    skip = len;\n  }\n  \n  var prefix_pos = 0;\n  while (prefix_pos < prefix.length) {\n    dst[idx++] = prefix[prefix_pos++];\n  }\n  \n  word += skip;\n  len -= skip;\n  \n  if (t <= kOmitLast9) {\n    len -= t;\n  }\n  \n  for (i = 0; i < len; i++) {\n    dst[idx++] = BrotliDictionary.dictionary[word + i];\n  }\n  \n  uppercase = idx - len;\n  \n  if (t === kUppercaseFirst) {\n    ToUpperCase(dst, uppercase);\n  } else if (t === kUppercaseAll) {\n    while (len > 0) {\n      var step = ToUpperCase(dst, uppercase);\n      uppercase += step;\n      len -= step;\n    }\n  }\n  \n  var suffix_pos = 0;\n  while (suffix_pos < suffix.length) {\n    dst[idx++] = suffix[suffix_pos++];\n  }\n  \n  return idx - start_idx;\n}\n\n\n/***/ }),\n/* 292 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(__dirname) {// Generated by CoffeeScript 1.12.6\n(function() {\n  var AFMFont, PDFFont, StandardFont, fs,\n    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n    hasProp = {}.hasOwnProperty;\n\n  AFMFont = __webpack_require__(293);\n\n  PDFFont = __webpack_require__(50);\n\n  fs = __webpack_require__(8);\n\n  StandardFont = (function(superClass) {\n    var STANDARD_FONTS;\n\n    extend(StandardFont, superClass);\n\n    function StandardFont(document, name1, id) {\n      var ref;\n      this.document = document;\n      this.name = name1;\n      this.id = id;\n      this.font = new AFMFont(STANDARD_FONTS[this.name]());\n      ref = this.font, this.ascender = ref.ascender, this.descender = ref.descender, this.bbox = ref.bbox, this.lineGap = ref.lineGap;\n    }\n\n    StandardFont.prototype.embed = function() {\n      this.dictionary.data = {\n        Type: 'Font',\n        BaseFont: this.name,\n        Subtype: 'Type1',\n        Encoding: 'WinAnsiEncoding'\n      };\n      return this.dictionary.end();\n    };\n\n    StandardFont.prototype.encode = function(text) {\n      var advances, encoded, glyph, glyphs, i, j, len, positions;\n      encoded = this.font.encodeText(text);\n      glyphs = this.font.glyphsForString('' + text);\n      advances = this.font.advancesForGlyphs(glyphs);\n      positions = [];\n      for (i = j = 0, len = glyphs.length; j < len; i = ++j) {\n        glyph = glyphs[i];\n        positions.push({\n          xAdvance: advances[i],\n          yAdvance: 0,\n          xOffset: 0,\n          yOffset: 0,\n          advanceWidth: this.font.widthOfGlyph(glyph)\n        });\n      }\n      return [encoded, positions];\n    };\n\n    StandardFont.prototype.widthOfString = function(string, size) {\n      var advance, advances, glyphs, j, len, scale, width;\n      glyphs = this.font.glyphsForString('' + string);\n      advances = this.font.advancesForGlyphs(glyphs);\n      width = 0;\n      for (j = 0, len = advances.length; j < len; j++) {\n        advance = advances[j];\n        width += advance;\n      }\n      scale = size / 1000;\n      return width * scale;\n    };\n\n    StandardFont.isStandardFont = function(name) {\n      return name in STANDARD_FONTS;\n    };\n\n    STANDARD_FONTS = {\n      \"Courier\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Courier.afm\", 'utf8');\n      },\n      \"Courier-Bold\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Courier-Bold.afm\", 'utf8');\n      },\n      \"Courier-Oblique\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Courier-Oblique.afm\", 'utf8');\n      },\n      \"Courier-BoldOblique\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Courier-BoldOblique.afm\", 'utf8');\n      },\n      \"Helvetica\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Helvetica.afm\", 'utf8');\n      },\n      \"Helvetica-Bold\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Helvetica-Bold.afm\", 'utf8');\n      },\n      \"Helvetica-Oblique\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Helvetica-Oblique.afm\", 'utf8');\n      },\n      \"Helvetica-BoldOblique\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Helvetica-BoldOblique.afm\", 'utf8');\n      },\n      \"Times-Roman\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Times-Roman.afm\", 'utf8');\n      },\n      \"Times-Bold\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Times-Bold.afm\", 'utf8');\n      },\n      \"Times-Italic\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Times-Italic.afm\", 'utf8');\n      },\n      \"Times-BoldItalic\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Times-BoldItalic.afm\", 'utf8');\n      },\n      \"Symbol\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/Symbol.afm\", 'utf8');\n      },\n      \"ZapfDingbats\": function() {\n        return fs.readFileSync(__dirname + \"/../font/data/ZapfDingbats.afm\", 'utf8');\n      }\n    };\n\n    return StandardFont;\n\n  })(PDFFont);\n\n  module.exports = StandardFont;\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, \"/\"))\n\n/***/ }),\n/* 293 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var AFMFont, fs;\n\n  fs = __webpack_require__(8);\n\n  AFMFont = (function() {\n    var WIN_ANSI_MAP, characters;\n\n    AFMFont.open = function(filename) {\n      return new AFMFont(fs.readFileSync(filename, 'utf8'));\n    };\n\n    function AFMFont(contents) {\n      var e, i;\n      this.contents = contents;\n      this.attributes = {};\n      this.glyphWidths = {};\n      this.boundingBoxes = {};\n      this.kernPairs = {};\n      this.parse();\n      this.charWidths = (function() {\n        var j, results;\n        results = [];\n        for (i = j = 0; j <= 255; i = ++j) {\n          results.push(this.glyphWidths[characters[i]]);\n        }\n        return results;\n      }).call(this);\n      this.bbox = (function() {\n        var j, len, ref, results;\n        ref = this.attributes['FontBBox'].split(/\\s+/);\n        results = [];\n        for (j = 0, len = ref.length; j < len; j++) {\n          e = ref[j];\n          results.push(+e);\n        }\n        return results;\n      }).call(this);\n      this.ascender = +(this.attributes['Ascender'] || 0);\n      this.descender = +(this.attributes['Descender'] || 0);\n      this.lineGap = (this.bbox[3] - this.bbox[1]) - (this.ascender - this.descender);\n    }\n\n    AFMFont.prototype.parse = function() {\n      var a, j, key, len, line, match, name, ref, section, value;\n      section = '';\n      ref = this.contents.split('\\n');\n      for (j = 0, len = ref.length; j < len; j++) {\n        line = ref[j];\n        if (match = line.match(/^Start(\\w+)/)) {\n          section = match[1];\n          continue;\n        } else if (match = line.match(/^End(\\w+)/)) {\n          section = '';\n          continue;\n        }\n        switch (section) {\n          case 'FontMetrics':\n            match = line.match(/(^\\w+)\\s+(.*)/);\n            key = match[1];\n            value = match[2];\n            if (a = this.attributes[key]) {\n              if (!Array.isArray(a)) {\n                a = this.attributes[key] = [a];\n              }\n              a.push(value);\n            } else {\n              this.attributes[key] = value;\n            }\n            break;\n          case 'CharMetrics':\n            if (!/^CH?\\s/.test(line)) {\n              continue;\n            }\n            name = line.match(/\\bN\\s+(\\.?\\w+)\\s*;/)[1];\n            this.glyphWidths[name] = +line.match(/\\bWX\\s+(\\d+)\\s*;/)[1];\n            break;\n          case 'KernPairs':\n            match = line.match(/^KPX\\s+(\\.?\\w+)\\s+(\\.?\\w+)\\s+(-?\\d+)/);\n            if (match) {\n              this.kernPairs[match[1] + '\\0' + match[2]] = parseInt(match[3]);\n            }\n        }\n      }\n    };\n\n    WIN_ANSI_MAP = {\n      402: 131,\n      8211: 150,\n      8212: 151,\n      8216: 145,\n      8217: 146,\n      8218: 130,\n      8220: 147,\n      8221: 148,\n      8222: 132,\n      8224: 134,\n      8225: 135,\n      8226: 149,\n      8230: 133,\n      8364: 128,\n      8240: 137,\n      8249: 139,\n      8250: 155,\n      710: 136,\n      8482: 153,\n      338: 140,\n      339: 156,\n      732: 152,\n      352: 138,\n      353: 154,\n      376: 159,\n      381: 142,\n      382: 158\n    };\n\n    AFMFont.prototype.encodeText = function(text) {\n      var char, i, j, ref, res;\n      res = [];\n      for (i = j = 0, ref = text.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {\n        char = text.charCodeAt(i);\n        char = WIN_ANSI_MAP[char] || char;\n        res.push(char.toString(16));\n      }\n      return res;\n    };\n\n    AFMFont.prototype.glyphsForString = function(string) {\n      var charCode, glyphs, i, j, ref;\n      glyphs = [];\n      for (i = j = 0, ref = string.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {\n        charCode = string.charCodeAt(i);\n        glyphs.push(this.characterToGlyph(charCode));\n      }\n      return glyphs;\n    };\n\n    AFMFont.prototype.characterToGlyph = function(character) {\n      return characters[WIN_ANSI_MAP[character] || character] || '.notdef';\n    };\n\n    AFMFont.prototype.widthOfGlyph = function(glyph) {\n      return this.glyphWidths[glyph] || 0;\n    };\n\n    AFMFont.prototype.getKernPair = function(left, right) {\n      return this.kernPairs[left + '\\0' + right] || 0;\n    };\n\n    AFMFont.prototype.advancesForGlyphs = function(glyphs) {\n      var advances, index, j, left, len, right;\n      advances = [];\n      for (index = j = 0, len = glyphs.length; j < len; index = ++j) {\n        left = glyphs[index];\n        right = glyphs[index + 1];\n        advances.push(this.widthOfGlyph(left) + this.getKernPair(left, right));\n      }\n      return advances;\n    };\n\n    characters = '.notdef       .notdef        .notdef        .notdef\\n.notdef       .notdef        .notdef        .notdef\\n.notdef       .notdef        .notdef        .notdef\\n.notdef       .notdef        .notdef        .notdef\\n.notdef       .notdef        .notdef        .notdef\\n.notdef       .notdef        .notdef        .notdef\\n.notdef       .notdef        .notdef        .notdef\\n.notdef       .notdef        .notdef        .notdef\\n\\nspace         exclam         quotedbl       numbersign\\ndollar        percent        ampersand      quotesingle\\nparenleft     parenright     asterisk       plus\\ncomma         hyphen         period         slash\\nzero          one            two            three\\nfour          five           six            seven\\neight         nine           colon          semicolon\\nless          equal          greater        question\\n\\nat            A              B              C\\nD             E              F              G\\nH             I              J              K\\nL             M              N              O\\nP             Q              R              S\\nT             U              V              W\\nX             Y              Z              bracketleft\\nbackslash     bracketright   asciicircum    underscore\\n\\ngrave         a              b              c\\nd             e              f              g\\nh             i              j              k\\nl             m              n              o\\np             q              r              s\\nt             u              v              w\\nx             y              z              braceleft\\nbar           braceright     asciitilde     .notdef\\n\\nEuro          .notdef        quotesinglbase florin\\nquotedblbase  ellipsis       dagger         daggerdbl\\ncircumflex    perthousand    Scaron         guilsinglleft\\nOE            .notdef        Zcaron         .notdef\\n.notdef       quoteleft      quoteright     quotedblleft\\nquotedblright bullet         endash         emdash\\ntilde         trademark      scaron         guilsinglright\\noe            .notdef        zcaron         ydieresis\\n\\nspace         exclamdown     cent           sterling\\ncurrency      yen            brokenbar      section\\ndieresis      copyright      ordfeminine    guillemotleft\\nlogicalnot    hyphen         registered     macron\\ndegree        plusminus      twosuperior    threesuperior\\nacute         mu             paragraph      periodcentered\\ncedilla       onesuperior    ordmasculine   guillemotright\\nonequarter    onehalf        threequarters  questiondown\\n\\nAgrave        Aacute         Acircumflex    Atilde\\nAdieresis     Aring          AE             Ccedilla\\nEgrave        Eacute         Ecircumflex    Edieresis\\nIgrave        Iacute         Icircumflex    Idieresis\\nEth           Ntilde         Ograve         Oacute\\nOcircumflex   Otilde         Odieresis      multiply\\nOslash        Ugrave         Uacute         Ucircumflex\\nUdieresis     Yacute         Thorn          germandbls\\n\\nagrave        aacute         acircumflex    atilde\\nadieresis     aring          ae             ccedilla\\negrave        eacute         ecircumflex    edieresis\\nigrave        iacute         icircumflex    idieresis\\neth           ntilde         ograve         oacute\\nocircumflex   otilde         odieresis      divide\\noslash        ugrave         uacute         ucircumflex\\nudieresis     yacute         thorn          ydieresis'.split(/\\s+/);\n\n    return AFMFont;\n\n  })();\n\n  module.exports = AFMFont;\n\n}).call(this);\n\n\n/***/ }),\n/* 294 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var EmbeddedFont, PDFFont, PDFObject,\n    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n    hasProp = {}.hasOwnProperty,\n    slice = [].slice;\n\n  PDFFont = __webpack_require__(50);\n\n  PDFObject = __webpack_require__(26);\n\n  EmbeddedFont = (function(superClass) {\n    var toHex;\n\n    extend(EmbeddedFont, superClass);\n\n    function EmbeddedFont(document, font, id) {\n      this.document = document;\n      this.font = font;\n      this.id = id;\n      this.subset = this.font.createSubset();\n      this.unicode = [[0]];\n      this.widths = [this.font.getGlyph(0).advanceWidth];\n      this.name = this.font.postscriptName;\n      this.scale = 1000 / this.font.unitsPerEm;\n      this.ascender = this.font.ascent * this.scale;\n      this.descender = this.font.descent * this.scale;\n      this.lineGap = this.font.lineGap * this.scale;\n      this.bbox = this.font.bbox;\n      this.layoutCache = Object.create(null);\n    }\n\n    EmbeddedFont.prototype.layoutRun = function(text, features) {\n      var i, j, key, len, position, ref, run;\n      run = this.font.layout(text, features);\n      ref = run.positions;\n      for (i = j = 0, len = ref.length; j < len; i = ++j) {\n        position = ref[i];\n        for (key in position) {\n          position[key] *= this.scale;\n        }\n        position.advanceWidth = run.glyphs[i].advanceWidth * this.scale;\n      }\n      return run;\n    };\n\n    EmbeddedFont.prototype.layoutCached = function(text) {\n      var cached, run;\n      if (cached = this.layoutCache[text]) {\n        return cached;\n      }\n      run = this.layoutRun(text);\n      this.layoutCache[text] = run;\n      return run;\n    };\n\n    EmbeddedFont.prototype.layout = function(text, features, onlyWidth) {\n      var advanceWidth, glyphs, index, last, positions, ref, run;\n      if (onlyWidth == null) {\n        onlyWidth = false;\n      }\n      if (features) {\n        return this.layoutRun(text, features);\n      }\n      glyphs = onlyWidth ? null : [];\n      positions = onlyWidth ? null : [];\n      advanceWidth = 0;\n      last = 0;\n      index = 0;\n      while (index <= text.length) {\n        if ((index === text.length && last < index) || ((ref = text.charAt(index)) === ' ' || ref === '\\t')) {\n          run = this.layoutCached(text.slice(last, ++index));\n          if (!onlyWidth) {\n            glyphs.push.apply(glyphs, run.glyphs);\n            positions.push.apply(positions, run.positions);\n          }\n          advanceWidth += run.advanceWidth;\n          last = index;\n        } else {\n          index++;\n        }\n      }\n      return {\n        glyphs: glyphs,\n        positions: positions,\n        advanceWidth: advanceWidth\n      };\n    };\n\n    EmbeddedFont.prototype.encode = function(text, features) {\n      var base, base1, gid, glyph, glyphs, i, j, len, positions, ref, res;\n      ref = this.layout(text, features), glyphs = ref.glyphs, positions = ref.positions;\n      res = [];\n      for (i = j = 0, len = glyphs.length; j < len; i = ++j) {\n        glyph = glyphs[i];\n        gid = this.subset.includeGlyph(glyph.id);\n        res.push(('0000' + gid.toString(16)).slice(-4));\n        if ((base = this.widths)[gid] == null) {\n          base[gid] = glyph.advanceWidth * this.scale;\n        }\n        if ((base1 = this.unicode)[gid] == null) {\n          base1[gid] = glyph.codePoints;\n        }\n      }\n      return [res, positions];\n    };\n\n    EmbeddedFont.prototype.widthOfString = function(string, size, features) {\n      var scale, width;\n      width = this.layout(string, features, true).advanceWidth;\n      scale = size / 1000;\n      return width * scale;\n    };\n\n    EmbeddedFont.prototype.embed = function() {\n      var bbox, descendantFont, descriptor, familyClass, flags, fontFile, i, isCFF, name, ref, tag;\n      isCFF = this.subset.cff != null;\n      fontFile = this.document.ref();\n      if (isCFF) {\n        fontFile.data.Subtype = 'CIDFontType0C';\n      }\n      this.subset.encodeStream().pipe(fontFile);\n      familyClass = (((ref = this.font['OS/2']) != null ? ref.sFamilyClass : void 0) || 0) >> 8;\n      flags = 0;\n      if (this.font.post.isFixedPitch) {\n        flags |= 1 << 0;\n      }\n      if ((1 <= familyClass && familyClass <= 7)) {\n        flags |= 1 << 1;\n      }\n      flags |= 1 << 2;\n      if (familyClass === 10) {\n        flags |= 1 << 3;\n      }\n      if (this.font.head.macStyle.italic) {\n        flags |= 1 << 6;\n      }\n      tag = ((function() {\n        var j, results;\n        results = [];\n        for (i = j = 0; j < 6; i = ++j) {\n          results.push(String.fromCharCode(Math.random() * 26 + 65));\n        }\n        return results;\n      })()).join('');\n      name = tag + '+' + this.font.postscriptName;\n      bbox = this.font.bbox;\n      descriptor = this.document.ref({\n        Type: 'FontDescriptor',\n        FontName: name,\n        Flags: flags,\n        FontBBox: [bbox.minX * this.scale, bbox.minY * this.scale, bbox.maxX * this.scale, bbox.maxY * this.scale],\n        ItalicAngle: this.font.italicAngle,\n        Ascent: this.ascender,\n        Descent: this.descender,\n        CapHeight: (this.font.capHeight || this.font.ascent) * this.scale,\n        XHeight: (this.font.xHeight || 0) * this.scale,\n        StemV: 0\n      });\n      if (isCFF) {\n        descriptor.data.FontFile3 = fontFile;\n      } else {\n        descriptor.data.FontFile2 = fontFile;\n      }\n      descriptor.end();\n      descendantFont = this.document.ref({\n        Type: 'Font',\n        Subtype: isCFF ? 'CIDFontType0' : 'CIDFontType2',\n        BaseFont: name,\n        CIDSystemInfo: {\n          Registry: new String('Adobe'),\n          Ordering: new String('Identity'),\n          Supplement: 0\n        },\n        FontDescriptor: descriptor,\n        W: [0, this.widths]\n      });\n      descendantFont.end();\n      this.dictionary.data = {\n        Type: 'Font',\n        Subtype: 'Type0',\n        BaseFont: name,\n        Encoding: 'Identity-H',\n        DescendantFonts: [descendantFont],\n        ToUnicode: this.toUnicodeCmap()\n      };\n      return this.dictionary.end();\n    };\n\n    toHex = function() {\n      var code, codePoints, codes;\n      codePoints = 1 <= arguments.length ? slice.call(arguments, 0) : [];\n      codes = (function() {\n        var j, len, results;\n        results = [];\n        for (j = 0, len = codePoints.length; j < len; j++) {\n          code = codePoints[j];\n          results.push(('0000' + code.toString(16)).slice(-4));\n        }\n        return results;\n      })();\n      return codes.join('');\n    };\n\n    EmbeddedFont.prototype.toUnicodeCmap = function() {\n      var cmap, codePoints, encoded, entries, j, k, len, len1, ref, value;\n      cmap = this.document.ref();\n      entries = [];\n      ref = this.unicode;\n      for (j = 0, len = ref.length; j < len; j++) {\n        codePoints = ref[j];\n        encoded = [];\n        for (k = 0, len1 = codePoints.length; k < len1; k++) {\n          value = codePoints[k];\n          if (value > 0xffff) {\n            value -= 0x10000;\n            encoded.push(toHex(value >>> 10 & 0x3ff | 0xd800));\n            value = 0xdc00 | value & 0x3ff;\n          }\n          encoded.push(toHex(value));\n        }\n        entries.push(\"<\" + (encoded.join(' ')) + \">\");\n      }\n      cmap.end(\"/CIDInit /ProcSet findresource begin\\n12 dict begin\\nbegincmap\\n/CIDSystemInfo <<\\n  /Registry (Adobe)\\n  /Ordering (UCS)\\n  /Supplement 0\\n>> def\\n/CMapName /Adobe-Identity-UCS def\\n/CMapType 2 def\\n1 begincodespacerange\\n<0000><ffff>\\nendcodespacerange\\n1 beginbfrange\\n<0000> <\" + (toHex(entries.length - 1)) + \"> [\" + (entries.join(' ')) + \"]\\nendbfrange\\nendcmap\\nCMapName currentdict /CMap defineresource pop\\nend\\nend\");\n      return cmap;\n    };\n\n    return EmbeddedFont;\n\n  })(PDFFont);\n\n  module.exports = EmbeddedFont;\n\n}).call(this);\n\n\n/***/ }),\n/* 295 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var LineWrapper, number;\n\n  LineWrapper = __webpack_require__(296);\n\n  number = __webpack_require__(26).number;\n\n  module.exports = {\n    initText: function() {\n      this.x = 0;\n      this.y = 0;\n      return this._lineGap = 0;\n    },\n    lineGap: function(_lineGap) {\n      this._lineGap = _lineGap;\n      return this;\n    },\n    moveDown: function(lines) {\n      if (lines == null) {\n        lines = 1;\n      }\n      this.y += this.currentLineHeight(true) * lines + this._lineGap;\n      return this;\n    },\n    moveUp: function(lines) {\n      if (lines == null) {\n        lines = 1;\n      }\n      this.y -= this.currentLineHeight(true) * lines + this._lineGap;\n      return this;\n    },\n    _text: function(text, x, y, options, lineCallback) {\n      var j, len, line, ref, wrapper;\n      options = this._initOptions(x, y, options);\n      text = text == null ? '' : '' + text;\n      if (options.wordSpacing) {\n        text = text.replace(/\\s{2,}/g, ' ');\n      }\n      if (options.width) {\n        wrapper = this._wrapper;\n        if (!wrapper) {\n          wrapper = new LineWrapper(this, options);\n          wrapper.on('line', lineCallback);\n        }\n        this._wrapper = options.continued ? wrapper : null;\n        this._textOptions = options.continued ? options : null;\n        wrapper.wrap(text, options);\n      } else {\n        ref = text.split('\\n');\n        for (j = 0, len = ref.length; j < len; j++) {\n          line = ref[j];\n          lineCallback(line, options);\n        }\n      }\n      return this;\n    },\n    text: function(text, x, y, options) {\n      return this._text(text, x, y, options, this._line.bind(this));\n    },\n    widthOfString: function(string, options) {\n      if (options == null) {\n        options = {};\n      }\n      return this._font.widthOfString(string, this._fontSize, options.features) + (options.characterSpacing || 0) * (string.length - 1);\n    },\n    heightOfString: function(text, options) {\n      var height, lineGap, ref, x, y;\n      if (options == null) {\n        options = {};\n      }\n      ref = this, x = ref.x, y = ref.y;\n      options = this._initOptions(options);\n      options.height = 2e308;\n      lineGap = options.lineGap || this._lineGap || 0;\n      this._text(text, this.x, this.y, options, (function(_this) {\n        return function(line, options) {\n          return _this.y += _this.currentLineHeight(true) + lineGap;\n        };\n      })(this));\n      height = this.y - y;\n      this.x = x;\n      this.y = y;\n      return height;\n    },\n    list: function(list, x, y, options, wrapper) {\n      var flatten, i, indent, itemIndent, items, level, levels, midLine, r;\n      options = this._initOptions(x, y, options);\n      midLine = Math.round((this._font.ascender / 1000 * this._fontSize) / 2);\n      r = options.bulletRadius || Math.round((this._font.ascender / 1000 * this._fontSize) / 3);\n      indent = options.textIndent || r * 5;\n      itemIndent = options.bulletIndent || r * 8;\n      level = 1;\n      items = [];\n      levels = [];\n      flatten = function(list) {\n        var i, item, j, len, results;\n        results = [];\n        for (i = j = 0, len = list.length; j < len; i = ++j) {\n          item = list[i];\n          if (Array.isArray(item)) {\n            level++;\n            flatten(item);\n            results.push(level--);\n          } else {\n            items.push(item);\n            results.push(levels.push(level));\n          }\n        }\n        return results;\n      };\n      flatten(list);\n      wrapper = new LineWrapper(this, options);\n      wrapper.on('line', this._line.bind(this));\n      level = 1;\n      i = 0;\n      wrapper.on('firstLine', (function(_this) {\n        return function() {\n          var diff, l;\n          if ((l = levels[i++]) !== level) {\n            diff = itemIndent * (l - level);\n            _this.x += diff;\n            wrapper.lineWidth -= diff;\n            level = l;\n          }\n          _this.circle(_this.x - indent + r, _this.y + midLine, r);\n          return _this.fill();\n        };\n      })(this));\n      wrapper.on('sectionStart', (function(_this) {\n        return function() {\n          var pos;\n          pos = indent + itemIndent * (level - 1);\n          _this.x += pos;\n          return wrapper.lineWidth -= pos;\n        };\n      })(this));\n      wrapper.on('sectionEnd', (function(_this) {\n        return function() {\n          var pos;\n          pos = indent + itemIndent * (level - 1);\n          _this.x -= pos;\n          return wrapper.lineWidth += pos;\n        };\n      })(this));\n      wrapper.wrap(items.join('\\n'), options);\n      return this;\n    },\n    _initOptions: function(x, y, options) {\n      var key, ref, val;\n      if (x == null) {\n        x = {};\n      }\n      if (options == null) {\n        options = {};\n      }\n      if (typeof x === 'object') {\n        options = x;\n        x = null;\n      }\n      options = (function() {\n        var k, opts, v;\n        opts = {};\n        for (k in options) {\n          v = options[k];\n          opts[k] = v;\n        }\n        return opts;\n      })();\n      if (this._textOptions) {\n        ref = this._textOptions;\n        for (key in ref) {\n          val = ref[key];\n          if (key !== 'continued') {\n            if (options[key] == null) {\n              options[key] = val;\n            }\n          }\n        }\n      }\n      if (x != null) {\n        this.x = x;\n      }\n      if (y != null) {\n        this.y = y;\n      }\n      if (options.lineBreak !== false) {\n        if (options.width == null) {\n          options.width = this.page.width - this.x - this.page.margins.right;\n        }\n      }\n      options.columns || (options.columns = 0);\n      if (options.columnGap == null) {\n        options.columnGap = 18;\n      }\n      return options;\n    },\n    _line: function(text, options, wrapper) {\n      var lineGap;\n      if (options == null) {\n        options = {};\n      }\n      this._fragment(text, this.x, this.y, options);\n      lineGap = options.lineGap || this._lineGap || 0;\n      if (!wrapper) {\n        return this.x += this.widthOfString(text);\n      } else {\n        return this.y += this.currentLineHeight(true) + lineGap;\n      }\n    },\n    _fragment: function(text, x, y, options) {\n      var addSegment, align, base, characterSpacing, commands, d, encoded, encodedWord, flush, hadOffset, i, j, key, last, len, len1, lineWidth, lineY, m, mode, name, pos, positions, positionsWord, ref, ref1, ref2, renderedWidth, scale, space, spaceWidth, textWidth, val, word, wordSpacing, words;\n      text = ('' + text).replace(/\\n/g, '');\n      if (text.length === 0) {\n        return;\n      }\n      align = options.align || 'left';\n      wordSpacing = options.wordSpacing || 0;\n      characterSpacing = options.characterSpacing || 0;\n      if (options.width) {\n        switch (align) {\n          case 'right':\n            textWidth = this.widthOfString(text.replace(/\\s+$/, ''), options);\n            x += options.lineWidth - textWidth;\n            break;\n          case 'center':\n            x += options.lineWidth / 2 - options.textWidth / 2;\n            break;\n          case 'justify':\n            words = text.trim().split(/\\s+/);\n            textWidth = this.widthOfString(text.replace(/\\s+/g, ''), options);\n            spaceWidth = this.widthOfString(' ') + characterSpacing;\n            wordSpacing = Math.max(0, (options.lineWidth - textWidth) / Math.max(1, words.length - 1) - spaceWidth);\n        }\n      }\n      renderedWidth = options.textWidth + (wordSpacing * (options.wordCount - 1)) + (characterSpacing * (text.length - 1));\n      if (options.link) {\n        this.link(x, y, renderedWidth, this.currentLineHeight(), options.link);\n      }\n      if (options.underline || options.strike) {\n        this.save();\n        if (!options.stroke) {\n          this.strokeColor.apply(this, this._fillColor);\n        }\n        lineWidth = this._fontSize < 10 ? 0.5 : Math.floor(this._fontSize / 10);\n        this.lineWidth(lineWidth);\n        d = options.underline ? 1 : 2;\n        lineY = y + this.currentLineHeight() / d;\n        if (options.underline) {\n          lineY -= lineWidth;\n        }\n        this.moveTo(x, lineY);\n        this.lineTo(x + renderedWidth, lineY);\n        this.stroke();\n        this.restore();\n      }\n      this.save();\n      this.transform(1, 0, 0, -1, 0, this.page.height);\n      y = this.page.height - y - (this._font.ascender / 1000 * this._fontSize);\n      if ((base = this.page.fonts)[name = this._font.id] == null) {\n        base[name] = this._font.ref();\n      }\n      this.addContent(\"BT\");\n      this.addContent(\"1 0 0 1 \" + (number(x)) + \" \" + (number(y)) + \" Tm\");\n      this.addContent(\"/\" + this._font.id + \" \" + (number(this._fontSize)) + \" Tf\");\n      mode = options.fill && options.stroke ? 2 : options.stroke ? 1 : 0;\n      if (mode) {\n        this.addContent(mode + \" Tr\");\n      }\n      if (characterSpacing) {\n        this.addContent((number(characterSpacing)) + \" Tc\");\n      }\n      if (wordSpacing) {\n        words = text.trim().split(/\\s+/);\n        wordSpacing += this.widthOfString(' ') + characterSpacing;\n        wordSpacing *= 1000 / this._fontSize;\n        encoded = [];\n        positions = [];\n        for (j = 0, len = words.length; j < len; j++) {\n          word = words[j];\n          ref = this._font.encode(word, options.features), encodedWord = ref[0], positionsWord = ref[1];\n          encoded.push.apply(encoded, encodedWord);\n          positions.push.apply(positions, positionsWord);\n          space = {};\n          ref1 = positions[positions.length - 1];\n          for (key in ref1) {\n            val = ref1[key];\n            space[key] = val;\n          }\n          space.xAdvance += wordSpacing;\n          positions[positions.length - 1] = space;\n        }\n      } else {\n        ref2 = this._font.encode(text, options.features), encoded = ref2[0], positions = ref2[1];\n      }\n      scale = this._fontSize / 1000;\n      commands = [];\n      last = 0;\n      hadOffset = false;\n      addSegment = (function(_this) {\n        return function(cur) {\n          var advance, hex;\n          if (last < cur) {\n            hex = encoded.slice(last, cur).join('');\n            advance = positions[cur - 1].xAdvance - positions[cur - 1].advanceWidth;\n            commands.push(\"<\" + hex + \"> \" + (number(-advance)));\n          }\n          return last = cur;\n        };\n      })(this);\n      flush = (function(_this) {\n        return function(i) {\n          addSegment(i);\n          if (commands.length > 0) {\n            _this.addContent(\"[\" + (commands.join(' ')) + \"] TJ\");\n            return commands.length = 0;\n          }\n        };\n      })(this);\n      for (i = m = 0, len1 = positions.length; m < len1; i = ++m) {\n        pos = positions[i];\n        if (pos.xOffset || pos.yOffset) {\n          flush(i);\n          this.addContent(\"1 0 0 1 \" + (number(x + pos.xOffset * scale)) + \" \" + (number(y + pos.yOffset * scale)) + \" Tm\");\n          flush(i + 1);\n          hadOffset = true;\n        } else {\n          if (hadOffset) {\n            this.addContent(\"1 0 0 1 \" + (number(x)) + \" \" + (number(y)) + \" Tm\");\n            hadOffset = false;\n          }\n          if (pos.xAdvance - pos.advanceWidth !== 0) {\n            addSegment(i + 1);\n          }\n        }\n        x += pos.xAdvance * scale;\n      }\n      flush(i);\n      this.addContent(\"ET\");\n      return this.restore();\n    }\n  };\n\n}).call(this);\n\n\n/***/ }),\n/* 296 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var EventEmitter, LineBreaker, LineWrapper,\n    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n    hasProp = {}.hasOwnProperty;\n\n  EventEmitter = __webpack_require__(31).EventEmitter;\n\n  LineBreaker = __webpack_require__(78);\n\n  LineWrapper = (function(superClass) {\n    extend(LineWrapper, superClass);\n\n    function LineWrapper(document, options) {\n      var ref;\n      this.document = document;\n      this.indent = options.indent || 0;\n      this.characterSpacing = options.characterSpacing || 0;\n      this.wordSpacing = options.wordSpacing === 0;\n      this.columns = options.columns || 1;\n      this.columnGap = (ref = options.columnGap) != null ? ref : 18;\n      this.lineWidth = (options.width - (this.columnGap * (this.columns - 1))) / this.columns;\n      this.spaceLeft = this.lineWidth;\n      this.startX = this.document.x;\n      this.startY = this.document.y;\n      this.column = 1;\n      this.ellipsis = options.ellipsis;\n      this.continuedX = 0;\n      this.features = options.features;\n      if (options.height != null) {\n        this.height = options.height;\n        this.maxY = this.startY + options.height;\n      } else {\n        this.maxY = this.document.page.maxY();\n      }\n      this.on('firstLine', (function(_this) {\n        return function(options) {\n          var indent;\n          indent = _this.continuedX || _this.indent;\n          _this.document.x += indent;\n          _this.lineWidth -= indent;\n          return _this.once('line', function() {\n            _this.document.x -= indent;\n            _this.lineWidth += indent;\n            if (options.continued && !_this.continuedX) {\n              _this.continuedX = _this.indent;\n            }\n            if (!options.continued) {\n              return _this.continuedX = 0;\n            }\n          });\n        };\n      })(this));\n      this.on('lastLine', (function(_this) {\n        return function(options) {\n          var align;\n          align = options.align;\n          if (align === 'justify') {\n            options.align = 'left';\n          }\n          _this.lastLine = true;\n          return _this.once('line', function() {\n            _this.document.y += options.paragraphGap || 0;\n            options.align = align;\n            return _this.lastLine = false;\n          });\n        };\n      })(this));\n    }\n\n    LineWrapper.prototype.wordWidth = function(word) {\n      return this.document.widthOfString(word, this) + this.characterSpacing + this.wordSpacing;\n    };\n\n    LineWrapper.prototype.eachWord = function(text, fn) {\n      var bk, breaker, fbk, l, last, lbk, shouldContinue, w, word, wordWidths;\n      breaker = new LineBreaker(text);\n      last = null;\n      wordWidths = Object.create(null);\n      while (bk = breaker.nextBreak()) {\n        word = text.slice((last != null ? last.position : void 0) || 0, bk.position);\n        w = wordWidths[word] != null ? wordWidths[word] : wordWidths[word] = this.wordWidth(word);\n        if (w > this.lineWidth + this.continuedX) {\n          lbk = last;\n          fbk = {};\n          while (word.length) {\n            l = word.length;\n            while (w > this.spaceLeft) {\n              w = this.wordWidth(word.slice(0, --l));\n            }\n            fbk.required = l < word.length;\n            shouldContinue = fn(word.slice(0, l), w, fbk, lbk);\n            lbk = {\n              required: false\n            };\n            word = word.slice(l);\n            w = this.wordWidth(word);\n            if (shouldContinue === false) {\n              break;\n            }\n          }\n        } else {\n          shouldContinue = fn(word, w, bk, last);\n        }\n        if (shouldContinue === false) {\n          break;\n        }\n        last = bk;\n      }\n    };\n\n    LineWrapper.prototype.wrap = function(text, options) {\n      var buffer, emitLine, lc, nextY, textWidth, wc, y;\n      if (options.indent != null) {\n        this.indent = options.indent;\n      }\n      if (options.characterSpacing != null) {\n        this.characterSpacing = options.characterSpacing;\n      }\n      if (options.wordSpacing != null) {\n        this.wordSpacing = options.wordSpacing;\n      }\n      if (options.ellipsis != null) {\n        this.ellipsis = options.ellipsis;\n      }\n      nextY = this.document.y + this.document.currentLineHeight(true);\n      if (this.document.y > this.maxY || nextY > this.maxY) {\n        this.nextSection();\n      }\n      buffer = '';\n      textWidth = 0;\n      wc = 0;\n      lc = 0;\n      y = this.document.y;\n      emitLine = (function(_this) {\n        return function() {\n          options.textWidth = textWidth + _this.wordSpacing * (wc - 1);\n          options.wordCount = wc;\n          options.lineWidth = _this.lineWidth;\n          y = _this.document.y;\n          _this.emit('line', buffer, options, _this);\n          return lc++;\n        };\n      })(this);\n      this.emit('sectionStart', options, this);\n      this.eachWord(text, (function(_this) {\n        return function(word, w, bk, last) {\n          var lh, shouldContinue;\n          if ((last == null) || last.required) {\n            _this.emit('firstLine', options, _this);\n            _this.spaceLeft = _this.lineWidth;\n          }\n          if (w <= _this.spaceLeft) {\n            buffer += word;\n            textWidth += w;\n            wc++;\n          }\n          if (bk.required || w > _this.spaceLeft) {\n            if (bk.required) {\n              _this.emit('lastLine', options, _this);\n            }\n            lh = _this.document.currentLineHeight(true);\n            if ((_this.height != null) && _this.ellipsis && _this.document.y + lh * 2 > _this.maxY && _this.column >= _this.columns) {\n              if (_this.ellipsis === true) {\n                _this.ellipsis = '…';\n              }\n              buffer = buffer.replace(/\\s+$/, '');\n              textWidth = _this.wordWidth(buffer + _this.ellipsis);\n              while (textWidth > _this.lineWidth) {\n                buffer = buffer.slice(0, -1).replace(/\\s+$/, '');\n                textWidth = _this.wordWidth(buffer + _this.ellipsis);\n              }\n              buffer = buffer + _this.ellipsis;\n            }\n            if (bk.required && w > _this.spaceLeft) {\n              buffer = word;\n              textWidth = w;\n              wc = 1;\n            }\n            emitLine();\n            if (_this.document.y + lh > _this.maxY) {\n              shouldContinue = _this.nextSection();\n              if (!shouldContinue) {\n                wc = 0;\n                buffer = '';\n                return false;\n              }\n            }\n            if (bk.required) {\n              _this.spaceLeft = _this.lineWidth;\n              buffer = '';\n              textWidth = 0;\n              return wc = 0;\n            } else {\n              _this.spaceLeft = _this.lineWidth - w;\n              buffer = word;\n              textWidth = w;\n              return wc = 1;\n            }\n          } else {\n            return _this.spaceLeft -= w;\n          }\n        };\n      })(this));\n      if (wc > 0) {\n        this.emit('lastLine', options, this);\n        emitLine();\n      }\n      this.emit('sectionEnd', options, this);\n      if (options.continued === true) {\n        if (lc > 1) {\n          this.continuedX = 0;\n        }\n        this.continuedX += options.textWidth;\n        return this.document.y = y;\n      } else {\n        return this.document.x = this.startX;\n      }\n    };\n\n    LineWrapper.prototype.nextSection = function(options) {\n      var ref;\n      this.emit('sectionEnd', options, this);\n      if (++this.column > this.columns) {\n        if (this.height != null) {\n          return false;\n        }\n        this.document.addPage();\n        this.column = 1;\n        this.startY = this.document.page.margins.top;\n        this.maxY = this.document.page.maxY();\n        this.document.x = this.startX;\n        if (this.document._fillColor) {\n          (ref = this.document).fillColor.apply(ref, this.document._fillColor);\n        }\n        this.emit('pageBreak', options, this);\n      } else {\n        this.document.x += this.lineWidth + this.columnGap;\n        this.document.y = this.startY;\n        this.emit('columnBreak', options, this);\n      }\n      this.emit('sectionStart', options, this);\n      return true;\n    };\n\n    return LineWrapper;\n\n  })(EventEmitter);\n\n  module.exports = LineWrapper;\n\n}).call(this);\n\n\n/***/ }),\n/* 297 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var PDFImage;\n\n  PDFImage = __webpack_require__(121);\n\n  module.exports = {\n    initImages: function() {\n      this._imageRegistry = {};\n      return this._imageCount = 0;\n    },\n    image: function(src, x, y, options) {\n      var base, bh, bp, bw, h, hp, image, ip, name, ref, ref1, ref2, ref3, w, wp;\n      if (options == null) {\n        options = {};\n      }\n      if (typeof x === 'object') {\n        options = x;\n        x = null;\n      }\n      x = (ref = x != null ? x : options.x) != null ? ref : this.x;\n      y = (ref1 = y != null ? y : options.y) != null ? ref1 : this.y;\n      if (typeof src === 'string') {\n        image = this._imageRegistry[src];\n      }\n      if (!image) {\n        if (src.width && src.height) {\n          image = src;\n        } else {\n          image = this.openImage(src);\n        }\n      }\n      if (!image.obj) {\n        image.embed(this);\n      }\n      if ((base = this.page.xobjects)[name = image.label] == null) {\n        base[name] = image.obj;\n      }\n      w = options.width || image.width;\n      h = options.height || image.height;\n      if (options.width && !options.height) {\n        wp = w / image.width;\n        w = image.width * wp;\n        h = image.height * wp;\n      } else if (options.height && !options.width) {\n        hp = h / image.height;\n        w = image.width * hp;\n        h = image.height * hp;\n      } else if (options.scale) {\n        w = image.width * options.scale;\n        h = image.height * options.scale;\n      } else if (options.fit) {\n        ref2 = options.fit, bw = ref2[0], bh = ref2[1];\n        bp = bw / bh;\n        ip = image.width / image.height;\n        if (ip > bp) {\n          w = bw;\n          h = bw / ip;\n        } else {\n          h = bh;\n          w = bh * ip;\n        }\n      } else if (options.cover) {\n        ref3 = options.cover, bw = ref3[0], bh = ref3[1];\n        bp = bw / bh;\n        ip = image.width / image.height;\n        if (ip > bp) {\n          h = bh;\n          w = bh * ip;\n        } else {\n          w = bw;\n          h = bw / ip;\n        }\n      }\n      if (options.fit || options.cover) {\n        if (options.align === 'center') {\n          x = x + bw / 2 - w / 2;\n        } else if (options.align === 'right') {\n          x = x + bw - w;\n        }\n        if (options.valign === 'center') {\n          y = y + bh / 2 - h / 2;\n        } else if (options.valign === 'bottom') {\n          y = y + bh - h;\n        }\n      }\n      if (this.y === y) {\n        this.y += h;\n      }\n      this.save();\n      this.transform(w, 0, 0, -h, x, y + h);\n      this.addContent(\"/\" + image.label + \" Do\");\n      this.restore();\n      return this;\n    },\n    openImage: function(src) {\n      var image;\n      if (typeof src === 'string') {\n        image = this._imageRegistry[src];\n      }\n      if (!image) {\n        image = PDFImage.open(src, 'I' + (++this._imageCount));\n        if (typeof src === 'string') {\n          this._imageRegistry[src] = image;\n        }\n      }\n      return image;\n    }\n  };\n\n}).call(this);\n\n\n/***/ }),\n/* 298 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var Data;\n\n  Data = (function() {\n    function Data(data) {\n      this.data = data != null ? data : [];\n      this.pos = 0;\n      this.length = this.data.length;\n    }\n\n    Data.prototype.readByte = function() {\n      return this.data[this.pos++];\n    };\n\n    Data.prototype.writeByte = function(byte) {\n      return this.data[this.pos++] = byte;\n    };\n\n    Data.prototype.byteAt = function(index) {\n      return this.data[index];\n    };\n\n    Data.prototype.readBool = function() {\n      return !!this.readByte();\n    };\n\n    Data.prototype.writeBool = function(val) {\n      return this.writeByte(val ? 1 : 0);\n    };\n\n    Data.prototype.readUInt32 = function() {\n      var b1, b2, b3, b4;\n      b1 = this.readByte() * 0x1000000;\n      b2 = this.readByte() << 16;\n      b3 = this.readByte() << 8;\n      b4 = this.readByte();\n      return b1 + b2 + b3 + b4;\n    };\n\n    Data.prototype.writeUInt32 = function(val) {\n      this.writeByte((val >>> 24) & 0xff);\n      this.writeByte((val >> 16) & 0xff);\n      this.writeByte((val >> 8) & 0xff);\n      return this.writeByte(val & 0xff);\n    };\n\n    Data.prototype.readInt32 = function() {\n      var int;\n      int = this.readUInt32();\n      if (int >= 0x80000000) {\n        return int - 0x100000000;\n      } else {\n        return int;\n      }\n    };\n\n    Data.prototype.writeInt32 = function(val) {\n      if (val < 0) {\n        val += 0x100000000;\n      }\n      return this.writeUInt32(val);\n    };\n\n    Data.prototype.readUInt16 = function() {\n      var b1, b2;\n      b1 = this.readByte() << 8;\n      b2 = this.readByte();\n      return b1 | b2;\n    };\n\n    Data.prototype.writeUInt16 = function(val) {\n      this.writeByte((val >> 8) & 0xff);\n      return this.writeByte(val & 0xff);\n    };\n\n    Data.prototype.readInt16 = function() {\n      var int;\n      int = this.readUInt16();\n      if (int >= 0x8000) {\n        return int - 0x10000;\n      } else {\n        return int;\n      }\n    };\n\n    Data.prototype.writeInt16 = function(val) {\n      if (val < 0) {\n        val += 0x10000;\n      }\n      return this.writeUInt16(val);\n    };\n\n    Data.prototype.readString = function(length) {\n      var i, j, ref, ret;\n      ret = [];\n      for (i = j = 0, ref = length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {\n        ret[i] = String.fromCharCode(this.readByte());\n      }\n      return ret.join('');\n    };\n\n    Data.prototype.writeString = function(val) {\n      var i, j, ref, results;\n      results = [];\n      for (i = j = 0, ref = val.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {\n        results.push(this.writeByte(val.charCodeAt(i)));\n      }\n      return results;\n    };\n\n    Data.prototype.stringAt = function(pos, length) {\n      this.pos = pos;\n      return this.readString(length);\n    };\n\n    Data.prototype.readShort = function() {\n      return this.readInt16();\n    };\n\n    Data.prototype.writeShort = function(val) {\n      return this.writeInt16(val);\n    };\n\n    Data.prototype.readLongLong = function() {\n      var b1, b2, b3, b4, b5, b6, b7, b8;\n      b1 = this.readByte();\n      b2 = this.readByte();\n      b3 = this.readByte();\n      b4 = this.readByte();\n      b5 = this.readByte();\n      b6 = this.readByte();\n      b7 = this.readByte();\n      b8 = this.readByte();\n      if (b1 & 0x80) {\n        return ((b1 ^ 0xff) * 0x100000000000000 + (b2 ^ 0xff) * 0x1000000000000 + (b3 ^ 0xff) * 0x10000000000 + (b4 ^ 0xff) * 0x100000000 + (b5 ^ 0xff) * 0x1000000 + (b6 ^ 0xff) * 0x10000 + (b7 ^ 0xff) * 0x100 + (b8 ^ 0xff) + 1) * -1;\n      }\n      return b1 * 0x100000000000000 + b2 * 0x1000000000000 + b3 * 0x10000000000 + b4 * 0x100000000 + b5 * 0x1000000 + b6 * 0x10000 + b7 * 0x100 + b8;\n    };\n\n    Data.prototype.writeLongLong = function(val) {\n      var high, low;\n      high = Math.floor(val / 0x100000000);\n      low = val & 0xffffffff;\n      this.writeByte((high >> 24) & 0xff);\n      this.writeByte((high >> 16) & 0xff);\n      this.writeByte((high >> 8) & 0xff);\n      this.writeByte(high & 0xff);\n      this.writeByte((low >> 24) & 0xff);\n      this.writeByte((low >> 16) & 0xff);\n      this.writeByte((low >> 8) & 0xff);\n      return this.writeByte(low & 0xff);\n    };\n\n    Data.prototype.readInt = function() {\n      return this.readInt32();\n    };\n\n    Data.prototype.writeInt = function(val) {\n      return this.writeInt32(val);\n    };\n\n    Data.prototype.slice = function(start, end) {\n      return this.data.slice(start, end);\n    };\n\n    Data.prototype.read = function(bytes) {\n      var buf, i, j, ref;\n      buf = [];\n      for (i = j = 0, ref = bytes; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {\n        buf.push(this.readByte());\n      }\n      return buf;\n    };\n\n    Data.prototype.write = function(bytes) {\n      var byte, j, len, results;\n      results = [];\n      for (j = 0, len = bytes.length; j < len; j++) {\n        byte = bytes[j];\n        results.push(this.writeByte(byte));\n      }\n      return results;\n    };\n\n    return Data;\n\n  })();\n\n  module.exports = Data;\n\n}).call(this);\n\n\n/***/ }),\n/* 299 */\n/***/ (function(module, exports, __webpack_require__) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  var JPEG, fs,\n    indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };\n\n  fs = __webpack_require__(8);\n\n  JPEG = (function() {\n    var MARKERS;\n\n    MARKERS = [0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC5, 0xFFC6, 0xFFC7, 0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF];\n\n    function JPEG(data, label) {\n      var channels, marker, pos;\n      this.data = data;\n      this.label = label;\n      if (this.data.readUInt16BE(0) !== 0xFFD8) {\n        throw \"SOI not found in JPEG\";\n      }\n      pos = 2;\n      while (pos < this.data.length) {\n        marker = this.data.readUInt16BE(pos);\n        pos += 2;\n        if (indexOf.call(MARKERS, marker) >= 0) {\n          break;\n        }\n        pos += this.data.readUInt16BE(pos);\n      }\n      if (indexOf.call(MARKERS, marker) < 0) {\n        throw \"Invalid JPEG.\";\n      }\n      pos += 2;\n      this.bits = this.data[pos++];\n      this.height = this.data.readUInt16BE(pos);\n      pos += 2;\n      this.width = this.data.readUInt16BE(pos);\n      pos += 2;\n      channels = this.data[pos++];\n      this.colorSpace = (function() {\n        switch (channels) {\n          case 1:\n            return 'DeviceGray';\n          case 3:\n            return 'DeviceRGB';\n          case 4:\n            return 'DeviceCMYK';\n        }\n      })();\n      this.obj = null;\n    }\n\n    JPEG.prototype.embed = function(document) {\n      if (this.obj) {\n        return;\n      }\n      this.obj = document.ref({\n        Type: 'XObject',\n        Subtype: 'Image',\n        BitsPerComponent: this.bits,\n        Width: this.width,\n        Height: this.height,\n        ColorSpace: this.colorSpace,\n        Filter: 'DCTDecode'\n      });\n      if (this.colorSpace === 'DeviceCMYK') {\n        this.obj.data['Decode'] = [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0];\n      }\n      this.obj.end(this.data);\n      return this.data = null;\n    };\n\n    return JPEG;\n\n  })();\n\n  module.exports = JPEG;\n\n}).call(this);\n\n\n/***/ }),\n/* 300 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.12.6\n(function() {\n  var PNG, PNGImage, zlib;\n\n  zlib = __webpack_require__(48);\n\n  PNG = __webpack_require__(301);\n\n  PNGImage = (function() {\n    function PNGImage(data, label) {\n      this.label = label;\n      this.image = new PNG(data);\n      this.width = this.image.width;\n      this.height = this.image.height;\n      this.imgData = this.image.imgData;\n      this.obj = null;\n    }\n\n    PNGImage.prototype.embed = function(document) {\n      var k, len1, mask, palette, params, rgb, val, x;\n      this.document = document;\n      if (this.obj) {\n        return;\n      }\n      this.obj = this.document.ref({\n        Type: 'XObject',\n        Subtype: 'Image',\n        BitsPerComponent: this.image.bits,\n        Width: this.width,\n        Height: this.height,\n        Filter: 'FlateDecode'\n      });\n      if (!this.image.hasAlphaChannel) {\n        params = this.document.ref({\n          Predictor: 15,\n          Colors: this.image.colors,\n          BitsPerComponent: this.image.bits,\n          Columns: this.width\n        });\n        this.obj.data['DecodeParms'] = params;\n        params.end();\n      }\n      if (this.image.palette.length === 0) {\n        this.obj.data['ColorSpace'] = this.image.colorSpace;\n      } else {\n        palette = this.document.ref();\n        palette.end(new Buffer(this.image.palette));\n        this.obj.data['ColorSpace'] = ['Indexed', 'DeviceRGB', (this.image.palette.length / 3) - 1, palette];\n      }\n      if (this.image.transparency.grayscale) {\n        val = this.image.transparency.greyscale;\n        return this.obj.data['Mask'] = [val, val];\n      } else if (this.image.transparency.rgb) {\n        rgb = this.image.transparency.rgb;\n        mask = [];\n        for (k = 0, len1 = rgb.length; k < len1; k++) {\n          x = rgb[k];\n          mask.push(x, x);\n        }\n        return this.obj.data['Mask'] = mask;\n      } else if (this.image.transparency.indexed) {\n        return this.loadIndexedAlphaChannel();\n      } else if (this.image.hasAlphaChannel) {\n        return this.splitAlphaChannel();\n      } else {\n        return this.finalize();\n      }\n    };\n\n    PNGImage.prototype.finalize = function() {\n      var sMask;\n      if (this.alphaChannel) {\n        sMask = this.document.ref({\n          Type: 'XObject',\n          Subtype: 'Image',\n          Height: this.height,\n          Width: this.width,\n          BitsPerComponent: 8,\n          Filter: 'FlateDecode',\n          ColorSpace: 'DeviceGray',\n          Decode: [0, 1]\n        });\n        sMask.end(this.alphaChannel);\n        this.obj.data['SMask'] = sMask;\n      }\n      this.obj.end(this.imgData);\n      this.image = null;\n      return this.imgData = null;\n    };\n\n    PNGImage.prototype.splitAlphaChannel = function() {\n      return this.image.decodePixels((function(_this) {\n        return function(pixels) {\n          var a, alphaChannel, colorByteSize, done, i, imgData, len, p, pixelCount;\n          colorByteSize = _this.image.colors * _this.image.bits / 8;\n          pixelCount = _this.width * _this.height;\n          imgData = new Buffer(pixelCount * colorByteSize);\n          alphaChannel = new Buffer(pixelCount);\n          i = p = a = 0;\n          len = pixels.length;\n          while (i < len) {\n            imgData[p++] = pixels[i++];\n            imgData[p++] = pixels[i++];\n            imgData[p++] = pixels[i++];\n            alphaChannel[a++] = pixels[i++];\n          }\n          done = 0;\n          zlib.deflate(imgData, function(err, imgData1) {\n            _this.imgData = imgData1;\n            if (err) {\n              throw err;\n            }\n            if (++done === 2) {\n              return _this.finalize();\n            }\n          });\n          return zlib.deflate(alphaChannel, function(err, alphaChannel1) {\n            _this.alphaChannel = alphaChannel1;\n            if (err) {\n              throw err;\n            }\n            if (++done === 2) {\n              return _this.finalize();\n            }\n          });\n        };\n      })(this));\n    };\n\n    PNGImage.prototype.loadIndexedAlphaChannel = function(fn) {\n      var transparency;\n      transparency = this.image.transparency.indexed;\n      return this.image.decodePixels((function(_this) {\n        return function(pixels) {\n          var alphaChannel, i, j, k, ref;\n          alphaChannel = new Buffer(_this.width * _this.height);\n          i = 0;\n          for (j = k = 0, ref = pixels.length; k < ref; j = k += 1) {\n            alphaChannel[i++] = transparency[pixels[j]];\n          }\n          return zlib.deflate(alphaChannel, function(err, alphaChannel1) {\n            _this.alphaChannel = alphaChannel1;\n            if (err) {\n              throw err;\n            }\n            return _this.finalize();\n          });\n        };\n      })(this));\n    };\n\n    return PNGImage;\n\n  })();\n\n  module.exports = PNGImage;\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 301 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* WEBPACK VAR INJECTION */(function(Buffer) {// Generated by CoffeeScript 1.4.0\n\n/*\n# MIT LICENSE\n# Copyright (c) 2011 Devon Govett\n# \n# Permission is hereby granted, free of charge, to any person obtaining a copy of this \n# software and associated documentation files (the \"Software\"), to deal in the Software \n# without restriction, including without limitation the rights to use, copy, modify, merge, \n# publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons \n# to whom the Software is furnished to do so, subject to the following conditions:\n# \n# The above copyright notice and this permission notice shall be included in all copies or \n# substantial portions of the Software.\n# \n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING \n# BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \n# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, \n# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n\n(function() {\n  var PNG, fs, zlib;\n\n  fs = __webpack_require__(8);\n\n  zlib = __webpack_require__(48);\n\n  module.exports = PNG = (function() {\n\n    PNG.decode = function(path, fn) {\n      return fs.readFile(path, function(err, file) {\n        var png;\n        png = new PNG(file);\n        return png.decode(function(pixels) {\n          return fn(pixels);\n        });\n      });\n    };\n\n    PNG.load = function(path) {\n      var file;\n      file = fs.readFileSync(path);\n      return new PNG(file);\n    };\n\n    function PNG(data) {\n      var chunkSize, colors, i, index, key, section, short, text, _i, _j, _ref;\n      this.data = data;\n      this.pos = 8;\n      this.palette = [];\n      this.imgData = [];\n      this.transparency = {};\n      this.text = {};\n      while (true) {\n        chunkSize = this.readUInt32();\n        section = ((function() {\n          var _i, _results;\n          _results = [];\n          for (i = _i = 0; _i < 4; i = ++_i) {\n            _results.push(String.fromCharCode(this.data[this.pos++]));\n          }\n          return _results;\n        }).call(this)).join('');\n        switch (section) {\n          case 'IHDR':\n            this.width = this.readUInt32();\n            this.height = this.readUInt32();\n            this.bits = this.data[this.pos++];\n            this.colorType = this.data[this.pos++];\n            this.compressionMethod = this.data[this.pos++];\n            this.filterMethod = this.data[this.pos++];\n            this.interlaceMethod = this.data[this.pos++];\n            break;\n          case 'PLTE':\n            this.palette = this.read(chunkSize);\n            break;\n          case 'IDAT':\n            for (i = _i = 0; _i < chunkSize; i = _i += 1) {\n              this.imgData.push(this.data[this.pos++]);\n            }\n            break;\n          case 'tRNS':\n            this.transparency = {};\n            switch (this.colorType) {\n              case 3:\n                this.transparency.indexed = this.read(chunkSize);\n                short = 255 - this.transparency.indexed.length;\n                if (short > 0) {\n                  for (i = _j = 0; 0 <= short ? _j < short : _j > short; i = 0 <= short ? ++_j : --_j) {\n                    this.transparency.indexed.push(255);\n                  }\n                }\n                break;\n              case 0:\n                this.transparency.grayscale = this.read(chunkSize)[0];\n                break;\n              case 2:\n                this.transparency.rgb = this.read(chunkSize);\n            }\n            break;\n          case 'tEXt':\n            text = this.read(chunkSize);\n            index = text.indexOf(0);\n            key = String.fromCharCode.apply(String, text.slice(0, index));\n            this.text[key] = String.fromCharCode.apply(String, text.slice(index + 1));\n            break;\n          case 'IEND':\n            this.colors = (function() {\n              switch (this.colorType) {\n                case 0:\n                case 3:\n                case 4:\n                  return 1;\n                case 2:\n                case 6:\n                  return 3;\n              }\n            }).call(this);\n            this.hasAlphaChannel = (_ref = this.colorType) === 4 || _ref === 6;\n            colors = this.colors + (this.hasAlphaChannel ? 1 : 0);\n            this.pixelBitlength = this.bits * colors;\n            this.colorSpace = (function() {\n              switch (this.colors) {\n                case 1:\n                  return 'DeviceGray';\n                case 3:\n                  return 'DeviceRGB';\n              }\n            }).call(this);\n            this.imgData = new Buffer(this.imgData);\n            return;\n          default:\n            this.pos += chunkSize;\n        }\n        this.pos += 4;\n        if (this.pos > this.data.length) {\n          throw new Error(\"Incomplete or corrupt PNG file\");\n        }\n      }\n      return;\n    }\n\n    PNG.prototype.read = function(bytes) {\n      var i, _i, _results;\n      _results = [];\n      for (i = _i = 0; 0 <= bytes ? _i < bytes : _i > bytes; i = 0 <= bytes ? ++_i : --_i) {\n        _results.push(this.data[this.pos++]);\n      }\n      return _results;\n    };\n\n    PNG.prototype.readUInt32 = function() {\n      var b1, b2, b3, b4;\n      b1 = this.data[this.pos++] << 24;\n      b2 = this.data[this.pos++] << 16;\n      b3 = this.data[this.pos++] << 8;\n      b4 = this.data[this.pos++];\n      return b1 | b2 | b3 | b4;\n    };\n\n    PNG.prototype.readUInt16 = function() {\n      var b1, b2;\n      b1 = this.data[this.pos++] << 8;\n      b2 = this.data[this.pos++];\n      return b1 | b2;\n    };\n\n    PNG.prototype.decodePixels = function(fn) {\n      var _this = this;\n      return zlib.inflate(this.imgData, function(err, data) {\n        var byte, c, col, i, left, length, p, pa, paeth, pb, pc, pixelBytes, pixels, pos, row, scanlineLength, upper, upperLeft, _i, _j, _k, _l, _m;\n        if (err) {\n          throw err;\n        }\n        pixelBytes = _this.pixelBitlength / 8;\n        scanlineLength = pixelBytes * _this.width;\n        pixels = new Buffer(scanlineLength * _this.height);\n        length = data.length;\n        row = 0;\n        pos = 0;\n        c = 0;\n        while (pos < length) {\n          switch (data[pos++]) {\n            case 0:\n              for (i = _i = 0; _i < scanlineLength; i = _i += 1) {\n                pixels[c++] = data[pos++];\n              }\n              break;\n            case 1:\n              for (i = _j = 0; _j < scanlineLength; i = _j += 1) {\n                byte = data[pos++];\n                left = i < pixelBytes ? 0 : pixels[c - pixelBytes];\n                pixels[c++] = (byte + left) % 256;\n              }\n              break;\n            case 2:\n              for (i = _k = 0; _k < scanlineLength; i = _k += 1) {\n                byte = data[pos++];\n                col = (i - (i % pixelBytes)) / pixelBytes;\n                upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];\n                pixels[c++] = (upper + byte) % 256;\n              }\n              break;\n            case 3:\n              for (i = _l = 0; _l < scanlineLength; i = _l += 1) {\n                byte = data[pos++];\n                col = (i - (i % pixelBytes)) / pixelBytes;\n                left = i < pixelBytes ? 0 : pixels[c - pixelBytes];\n                upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];\n                pixels[c++] = (byte + Math.floor((left + upper) / 2)) % 256;\n              }\n              break;\n            case 4:\n              for (i = _m = 0; _m < scanlineLength; i = _m += 1) {\n                byte = data[pos++];\n                col = (i - (i % pixelBytes)) / pixelBytes;\n                left = i < pixelBytes ? 0 : pixels[c - pixelBytes];\n                if (row === 0) {\n                  upper = upperLeft = 0;\n                } else {\n                  upper = pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];\n                  upperLeft = col && pixels[(row - 1) * scanlineLength + (col - 1) * pixelBytes + (i % pixelBytes)];\n                }\n                p = left + upper - upperLeft;\n                pa = Math.abs(p - left);\n                pb = Math.abs(p - upper);\n                pc = Math.abs(p - upperLeft);\n                if (pa <= pb && pa <= pc) {\n                  paeth = left;\n                } else if (pb <= pc) {\n                  paeth = upper;\n                } else {\n                  paeth = upperLeft;\n                }\n                pixels[c++] = (byte + paeth) % 256;\n              }\n              break;\n            default:\n              throw new Error(\"Invalid filter algorithm: \" + data[pos - 1]);\n          }\n          row++;\n        }\n        return fn(pixels);\n      });\n    };\n\n    PNG.prototype.decodePalette = function() {\n      var c, i, length, palette, pos, ret, transparency, _i, _ref, _ref1;\n      palette = this.palette;\n      transparency = this.transparency.indexed || [];\n      ret = new Buffer(transparency.length + palette.length);\n      pos = 0;\n      length = palette.length;\n      c = 0;\n      for (i = _i = 0, _ref = palette.length; _i < _ref; i = _i += 3) {\n        ret[pos++] = palette[i];\n        ret[pos++] = palette[i + 1];\n        ret[pos++] = palette[i + 2];\n        ret[pos++] = (_ref1 = transparency[c++]) != null ? _ref1 : 255;\n      }\n      return ret;\n    };\n\n    PNG.prototype.copyToImageData = function(imageData, pixels) {\n      var alpha, colors, data, i, input, j, k, length, palette, v, _ref;\n      colors = this.colors;\n      palette = null;\n      alpha = this.hasAlphaChannel;\n      if (this.palette.length) {\n        palette = (_ref = this._decodedPalette) != null ? _ref : this._decodedPalette = this.decodePalette();\n        colors = 4;\n        alpha = true;\n      }\n      data = (imageData != null ? imageData.data : void 0) || imageData;\n      length = data.length;\n      input = palette || pixels;\n      i = j = 0;\n      if (colors === 1) {\n        while (i < length) {\n          k = palette ? pixels[i / 4] * 4 : j;\n          v = input[k++];\n          data[i++] = v;\n          data[i++] = v;\n          data[i++] = v;\n          data[i++] = alpha ? input[k++] : 255;\n          j = k;\n        }\n      } else {\n        while (i < length) {\n          k = palette ? pixels[i / 4] * 4 : j;\n          data[i++] = input[k++];\n          data[i++] = input[k++];\n          data[i++] = input[k++];\n          data[i++] = alpha ? input[k++] : 255;\n          j = k;\n        }\n      }\n    };\n\n    PNG.prototype.decode = function(fn) {\n      var ret,\n        _this = this;\n      ret = new Buffer(this.width * this.height * 4);\n      return this.decodePixels(function(pixels) {\n        _this.copyToImageData(ret, pixels);\n        return fn(ret);\n      });\n    };\n\n    return PNG;\n\n  })();\n\n}).call(this);\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 302 */\n/***/ (function(module, exports) {\n\n// Generated by CoffeeScript 1.12.6\n(function() {\n  module.exports = {\n    annotate: function(x, y, w, h, options) {\n      var key, ref, val;\n      options.Type = 'Annot';\n      options.Rect = this._convertRect(x, y, w, h);\n      options.Border = [0, 0, 0];\n      if (options.Subtype !== 'Link') {\n        if (options.C == null) {\n          options.C = this._normalizeColor(options.color || [0, 0, 0]);\n        }\n      }\n      delete options.color;\n      if (typeof options.Dest === 'string') {\n        options.Dest = new String(options.Dest);\n      }\n      for (key in options) {\n        val = options[key];\n        options[key[0].toUpperCase() + key.slice(1)] = val;\n      }\n      ref = this.ref(options);\n      this.page.annotations.push(ref);\n      ref.end();\n      return this;\n    },\n    note: function(x, y, w, h, contents, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'Text';\n      options.Contents = new String(contents);\n      options.Name = 'Comment';\n      if (options.color == null) {\n        options.color = [243, 223, 92];\n      }\n      return this.annotate(x, y, w, h, options);\n    },\n    link: function(x, y, w, h, url, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'Link';\n      options.A = this.ref({\n        S: 'URI',\n        URI: new String(url)\n      });\n      options.A.end();\n      return this.annotate(x, y, w, h, options);\n    },\n    _markup: function(x, y, w, h, options) {\n      var ref1, x1, x2, y1, y2;\n      if (options == null) {\n        options = {};\n      }\n      ref1 = this._convertRect(x, y, w, h), x1 = ref1[0], y1 = ref1[1], x2 = ref1[2], y2 = ref1[3];\n      options.QuadPoints = [x1, y2, x2, y2, x1, y1, x2, y1];\n      options.Contents = new String;\n      return this.annotate(x, y, w, h, options);\n    },\n    highlight: function(x, y, w, h, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'Highlight';\n      if (options.color == null) {\n        options.color = [241, 238, 148];\n      }\n      return this._markup(x, y, w, h, options);\n    },\n    underline: function(x, y, w, h, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'Underline';\n      return this._markup(x, y, w, h, options);\n    },\n    strike: function(x, y, w, h, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'StrikeOut';\n      return this._markup(x, y, w, h, options);\n    },\n    lineAnnotation: function(x1, y1, x2, y2, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'Line';\n      options.Contents = new String;\n      options.L = [x1, this.page.height - y1, x2, this.page.height - y2];\n      return this.annotate(x1, y1, x2, y2, options);\n    },\n    rectAnnotation: function(x, y, w, h, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'Square';\n      options.Contents = new String;\n      return this.annotate(x, y, w, h, options);\n    },\n    ellipseAnnotation: function(x, y, w, h, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'Circle';\n      options.Contents = new String;\n      return this.annotate(x, y, w, h, options);\n    },\n    textAnnotation: function(x, y, w, h, text, options) {\n      if (options == null) {\n        options = {};\n      }\n      options.Subtype = 'FreeText';\n      options.Contents = new String(text);\n      options.DA = new String;\n      return this.annotate(x, y, w, h, options);\n    },\n    _convertRect: function(x1, y1, w, h) {\n      var m0, m1, m2, m3, m4, m5, ref1, x2, y2;\n      y2 = y1;\n      y1 += h;\n      x2 = x1 + w;\n      ref1 = this._ctm, m0 = ref1[0], m1 = ref1[1], m2 = ref1[2], m3 = ref1[3], m4 = ref1[4], m5 = ref1[5];\n      x1 = m0 * x1 + m2 * y1 + m4;\n      y1 = m1 * x1 + m3 * y1 + m5;\n      x2 = m0 * x2 + m2 * y2 + m4;\n      y2 = m1 * x2 + m3 * y2 + m5;\n      return [x1, y1, x2, y2];\n    }\n  };\n\n}).call(this);\n\n\n/***/ }),\n/* 303 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nmodule.exports = {\n\t'4A0': [4767.87, 6740.79],\n\t'2A0': [3370.39, 4767.87],\n\tA0: [2383.94, 3370.39],\n\tA1: [1683.78, 2383.94],\n\tA2: [1190.55, 1683.78],\n\tA3: [841.89, 1190.55],\n\tA4: [595.28, 841.89],\n\tA5: [419.53, 595.28],\n\tA6: [297.64, 419.53],\n\tA7: [209.76, 297.64],\n\tA8: [147.40, 209.76],\n\tA9: [104.88, 147.40],\n\tA10: [73.70, 104.88],\n\tB0: [2834.65, 4008.19],\n\tB1: [2004.09, 2834.65],\n\tB2: [1417.32, 2004.09],\n\tB3: [1000.63, 1417.32],\n\tB4: [708.66, 1000.63],\n\tB5: [498.90, 708.66],\n\tB6: [354.33, 498.90],\n\tB7: [249.45, 354.33],\n\tB8: [175.75, 249.45],\n\tB9: [124.72, 175.75],\n\tB10: [87.87, 124.72],\n\tC0: [2599.37, 3676.54],\n\tC1: [1836.85, 2599.37],\n\tC2: [1298.27, 1836.85],\n\tC3: [918.43, 1298.27],\n\tC4: [649.13, 918.43],\n\tC5: [459.21, 649.13],\n\tC6: [323.15, 459.21],\n\tC7: [229.61, 323.15],\n\tC8: [161.57, 229.61],\n\tC9: [113.39, 161.57],\n\tC10: [79.37, 113.39],\n\tRA0: [2437.80, 3458.27],\n\tRA1: [1729.13, 2437.80],\n\tRA2: [1218.90, 1729.13],\n\tRA3: [864.57, 1218.90],\n\tRA4: [609.45, 864.57],\n\tSRA0: [2551.18, 3628.35],\n\tSRA1: [1814.17, 2551.18],\n\tSRA2: [1275.59, 1814.17],\n\tSRA3: [907.09, 1275.59],\n\tSRA4: [637.80, 907.09],\n\tEXECUTIVE: [521.86, 756.00],\n\tFOLIO: [612.00, 936.00],\n\tLEGAL: [612.00, 1008.00],\n\tLETTER: [612.00, 792.00],\n\tTABLOID: [792.00, 1224.00]\n};\n\n\n/***/ }),\n/* 304 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n/* WEBPACK VAR INJECTION */(function(Buffer) {\n\nvar PDFImage = __webpack_require__(121);\n\nfunction ImageMeasure(pdfKitDoc, imageDictionary) {\n\tthis.pdfKitDoc = pdfKitDoc;\n\tthis.imageDictionary = imageDictionary || {};\n}\n\nImageMeasure.prototype.measureImage = function (src) {\n\tvar image, label;\n\tvar that = this;\n\n\tif (!this.pdfKitDoc._imageRegistry[src]) {\n\t\tlabel = 'I' + (++this.pdfKitDoc._imageCount);\n\t\ttry {\n\t\t\timage = PDFImage.open(realImageSrc(src), label);\n\t\t} catch (error) {\n\t\t\timage = null;\n\t\t}\n\t\tif (image === null || image === undefined) {\n\t\t\tthrow 'invalid image, images dictionary should contain dataURL entries (or local file paths in node.js)';\n\t\t}\n\t\timage.embed(this.pdfKitDoc);\n\t\tthis.pdfKitDoc._imageRegistry[src] = image;\n\t} else {\n\t\timage = this.pdfKitDoc._imageRegistry[src];\n\t}\n\n\treturn {width: image.width, height: image.height};\n\n\tfunction realImageSrc(src) {\n\t\tvar img = that.imageDictionary[src];\n\n\t\tif (!img) {\n\t\t\treturn src;\n\t\t}\n\n\t\tvar index = img.indexOf('base64,');\n\t\tif (index < 0) {\n\t\t\treturn that.imageDictionary[src];\n\t\t}\n\n\t\treturn Buffer.from(img.substring(index + 7), 'base64');\n\t}\n};\n\nmodule.exports = ImageMeasure;\n\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1).Buffer))\n\n/***/ }),\n/* 305 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\n\nvar isArray = __webpack_require__(0).isArray;\n\nfunction groupDecorations(line) {\n\tvar groups = [], currentGroup = null;\n\tfor (var i = 0, l = line.inlines.length; i < l; i++) {\n\t\tvar inline = line.inlines[i];\n\t\tvar decoration = inline.decoration;\n\t\tif (!decoration) {\n\t\t\tcurrentGroup = null;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!isArray(decoration)) {\n\t\t\tdecoration = [decoration];\n\t\t}\n\t\tvar color = inline.decorationColor || inline.color || 'black';\n\t\tvar style = inline.decorationStyle || 'solid';\n\t\tfor (var ii = 0, ll = decoration.length; ii < ll; ii++) {\n\t\t\tvar decorationItem = decoration[ii];\n\t\t\tif (!currentGroup || decorationItem !== currentGroup.decoration ||\n\t\t\t\tstyle !== currentGroup.decorationStyle || color !== currentGroup.decorationColor ||\n\t\t\t\tdecorationItem === 'lineThrough') {\n\n\t\t\t\tcurrentGroup = {\n\t\t\t\t\tline: line,\n\t\t\t\t\tdecoration: decorationItem,\n\t\t\t\t\tdecorationColor: color,\n\t\t\t\t\tdecorationStyle: style,\n\t\t\t\t\tinlines: [inline]\n\t\t\t\t};\n\t\t\t\tgroups.push(currentGroup);\n\t\t\t} else {\n\t\t\t\tcurrentGroup.inlines.push(inline);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn groups;\n}\n\nfunction drawDecoration(group, x, y, pdfKitDoc) {\n\tfunction maxInline() {\n\t\tvar max = 0;\n\t\tfor (var i = 0, l = group.inlines.length; i < l; i++) {\n\t\t\tvar inline = group.inlines[i];\n\t\t\tmax = inline.fontSize > max ? i : max;\n\t\t}\n\t\treturn group.inlines[max];\n\t}\n\tfunction width() {\n\t\tvar sum = 0;\n\t\tfor (var i = 0, l = group.inlines.length; i < l; i++) {\n\t\t\tsum += group.inlines[i].width;\n\t\t}\n\t\treturn sum;\n\t}\n\tvar firstInline = group.inlines[0],\n\t\tbiggerInline = maxInline(),\n\t\ttotalWidth = width(),\n\t\tlineAscent = group.line.getAscenderHeight(),\n\t\tascent = biggerInline.font.ascender / 1000 * biggerInline.fontSize,\n\t\theight = biggerInline.height,\n\t\tdescent = height - ascent;\n\n\tvar lw = 0.5 + Math.floor(Math.max(biggerInline.fontSize - 8, 0) / 2) * 0.12;\n\n\tswitch (group.decoration) {\n\t\tcase 'underline':\n\t\t\ty += lineAscent + descent * 0.45;\n\t\t\tbreak;\n\t\tcase 'overline':\n\t\t\ty += lineAscent - (ascent * 0.85);\n\t\t\tbreak;\n\t\tcase 'lineThrough':\n\t\t\ty += lineAscent - (ascent * 0.25);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tthrow 'Unkown decoration : ' + group.decoration;\n\t}\n\tpdfKitDoc.save();\n\n\tif (group.decorationStyle === 'double') {\n\t\tvar gap = Math.max(0.5, lw * 2);\n\t\tpdfKitDoc.fillColor(group.decorationColor)\n\t\t\t.rect(x + firstInline.x, y - lw / 2, totalWidth, lw / 2).fill()\n\t\t\t.rect(x + firstInline.x, y + gap - lw / 2, totalWidth, lw / 2).fill();\n\t} else if (group.decorationStyle === 'dashed') {\n\t\tvar nbDashes = Math.ceil(totalWidth / (3.96 + 2.84));\n\t\tvar rdx = x + firstInline.x;\n\t\tpdfKitDoc.rect(rdx, y, totalWidth, lw).clip();\n\t\tpdfKitDoc.fillColor(group.decorationColor);\n\t\tfor (var i = 0; i < nbDashes; i++) {\n\t\t\tpdfKitDoc.rect(rdx, y - lw / 2, 3.96, lw).fill();\n\t\t\trdx += 3.96 + 2.84;\n\t\t}\n\t} else if (group.decorationStyle === 'dotted') {\n\t\tvar nbDots = Math.ceil(totalWidth / (lw * 3));\n\t\tvar rx = x + firstInline.x;\n\t\tpdfKitDoc.rect(rx, y, totalWidth, lw).clip();\n\t\tpdfKitDoc.fillColor(group.decorationColor);\n\t\tfor (var ii = 0; ii < nbDots; ii++) {\n\t\t\tpdfKitDoc.rect(rx, y - lw / 2, lw, lw).fill();\n\t\t\trx += (lw * 3);\n\t\t}\n\t} else if (group.decorationStyle === 'wavy') {\n\t\tvar sh = 0.7, sv = 1;\n\t\tvar nbWaves = Math.ceil(totalWidth / (sh * 2)) + 1;\n\t\tvar rwx = x + firstInline.x - 1;\n\t\tpdfKitDoc.rect(x + firstInline.x, y - sv, totalWidth, y + sv).clip();\n\t\tpdfKitDoc.lineWidth(0.24);\n\t\tpdfKitDoc.moveTo(rwx, y);\n\t\tfor (var iii = 0; iii < nbWaves; iii++) {\n\t\t\tpdfKitDoc.bezierCurveTo(rwx + sh, y - sv, rwx + sh * 2, y - sv, rwx + sh * 3, y)\n\t\t\t\t.bezierCurveTo(rwx + sh * 4, y + sv, rwx + sh * 5, y + sv, rwx + sh * 6, y);\n\t\t\trwx += sh * 6;\n\t\t}\n\t\tpdfKitDoc.stroke(group.decorationColor);\n\t} else {\n\t\tpdfKitDoc.fillColor(group.decorationColor)\n\t\t\t.rect(x + firstInline.x, y - lw / 2, totalWidth, lw)\n\t\t\t.fill();\n\t}\n\tpdfKitDoc.restore();\n}\n\nfunction drawDecorations(line, x, y, pdfKitDoc) {\n\tvar groups = groupDecorations(line);\n\tfor (var i = 0, l = groups.length; i < l; i++) {\n\t\tdrawDecoration(groups[i], x, y, pdfKitDoc);\n\t}\n}\n\nfunction drawBackground(line, x, y, pdfKitDoc) {\n\tvar height = line.getHeight();\n\tfor (var i = 0, l = line.inlines.length; i < l; i++) {\n\t\tvar inline = line.inlines[i];\n\t\tif (!inline.background) {\n\t\t\tcontinue;\n\t\t}\n\t\tvar justifyShift = (inline.justifyShift || 0);\n\t\tpdfKitDoc.fillColor(inline.background)\n\t\t\t.rect(x + inline.x - justifyShift, y, inline.width + justifyShift, height)\n\t\t\t.fill();\n\t}\n}\n\nmodule.exports = {\n\tdrawBackground: drawBackground,\n\tdrawDecorations: drawDecorations\n};\n\n/***/ }),\n/* 306 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar __WEBPACK_AMD_DEFINE_RESULT__;/* FileSaver.js\n * A saveAs() FileSaver implementation.\n * 1.3.2\n * 2016-06-16 18:25:19\n *\n * By Eli Grey, http://eligrey.com\n * License: MIT\n *   See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md\n */\n\n/*global self */\n/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */\n\n/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */\n\nvar saveAs = saveAs || (function(view) {\n\t\"use strict\";\n\t// IE <10 is explicitly unsupported\n\tif (typeof view === \"undefined\" || typeof navigator !== \"undefined\" && /MSIE [1-9]\\./.test(navigator.userAgent)) {\n\t\treturn;\n\t}\n\tvar\n\t\t  doc = view.document\n\t\t  // only get URL when necessary in case Blob.js hasn't overridden it yet\n\t\t, get_URL = function() {\n\t\t\treturn view.URL || view.webkitURL || view;\n\t\t}\n\t\t, save_link = doc ? doc.createElementNS(\"http://www.w3.org/1999/xhtml\", \"a\") : []\n\t\t, can_use_save_link = \"download\" in save_link\n\t\t, click = function(node) {\n\t\t\tvar event = new MouseEvent(\"click\");\n\t\t\tnode.dispatchEvent(event);\n\t\t}\n\t\t, is_safari = /constructor/i.test(view.HTMLElement) || view.safari\n\t\t, is_chrome_ios =/CriOS\\/[\\d]+/.test(navigator.userAgent)\n\t\t, throw_outside = function(ex) {\n\t\t\t(view.setImmediate || view.setTimeout)(function() {\n\t\t\t\tthrow ex;\n\t\t\t}, 0);\n\t\t}\n\t\t, force_saveable_type = \"application/octet-stream\"\n\t\t// the Blob API is fundamentally broken as there is no \"downloadfinished\" event to subscribe to\n\t\t, arbitrary_revoke_timeout = 1000 * 40 // in ms\n\t\t, revoke = function(file) {\n\t\t\tvar revoker = function() {\n\t\t\t\tif (typeof file === \"string\") { // file is an object URL\n\t\t\t\t\tget_URL().revokeObjectURL(file);\n\t\t\t\t} else { // file is a File\n\t\t\t\t\tfile.remove();\n\t\t\t\t}\n\t\t\t};\n\t\t\tsetTimeout(revoker, arbitrary_revoke_timeout);\n\t\t}\n\t\t, dispatch = function(filesaver, event_types, event) {\n\t\t\tevent_types = [].concat(event_types);\n\t\t\tvar i = event_types.length;\n\t\t\twhile (i--) {\n\t\t\t\tvar listener = filesaver[\"on\" + event_types[i]];\n\t\t\t\tif (typeof listener === \"function\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tlistener.call(filesaver, event || filesaver);\n\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\tthrow_outside(ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t, auto_bom = function(blob) {\n\t\t\t// prepend BOM for UTF-8 XML and text/* types (including HTML)\n\t\t\t// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF\n\t\t\tif (/^\\s*(?:text\\/\\S*|application\\/xml|\\S*\\/\\S*\\+xml)\\s*;.*charset\\s*=\\s*utf-8/i.test(blob.type)) {\n\t\t\t\treturn new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});\n\t\t\t}\n\t\t\treturn blob;\n\t\t}\n\t\t, FileSaver = function(blob, name, no_auto_bom) {\n\t\t\tif (!no_auto_bom) {\n\t\t\t\tblob = auto_bom(blob);\n\t\t\t}\n\t\t\t// First try a.download, then web filesystem, then object URLs\n\t\t\tvar\n\t\t\t\t  filesaver = this\n\t\t\t\t, type = blob.type\n\t\t\t\t, force = type === force_saveable_type\n\t\t\t\t, object_url\n\t\t\t\t, dispatch_all = function() {\n\t\t\t\t\tdispatch(filesaver, \"writestart progress write writeend\".split(\" \"));\n\t\t\t\t}\n\t\t\t\t// on any filesys errors revert to saving with object URLs\n\t\t\t\t, fs_error = function() {\n\t\t\t\t\tif ((is_chrome_ios || (force && is_safari)) && view.FileReader) {\n\t\t\t\t\t\t// Safari doesn't allow downloading of blob urls\n\t\t\t\t\t\tvar reader = new FileReader();\n\t\t\t\t\t\treader.onloadend = function() {\n\t\t\t\t\t\t\tvar url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');\n\t\t\t\t\t\t\tvar popup = view.open(url, '_blank');\n\t\t\t\t\t\t\tif(!popup) view.location.href = url;\n\t\t\t\t\t\t\turl=undefined; // release reference before dispatching\n\t\t\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t\t\t\tdispatch_all();\n\t\t\t\t\t\t};\n\t\t\t\t\t\treader.readAsDataURL(blob);\n\t\t\t\t\t\tfilesaver.readyState = filesaver.INIT;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// don't create more object URLs than needed\n\t\t\t\t\tif (!object_url) {\n\t\t\t\t\t\tobject_url = get_URL().createObjectURL(blob);\n\t\t\t\t\t}\n\t\t\t\t\tif (force) {\n\t\t\t\t\t\tview.location.href = object_url;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar opened = view.open(object_url, \"_blank\");\n\t\t\t\t\t\tif (!opened) {\n\t\t\t\t\t\t\t// Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html\n\t\t\t\t\t\t\tview.location.href = object_url;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t\tdispatch_all();\n\t\t\t\t\trevoke(object_url);\n\t\t\t\t}\n\t\t\t;\n\t\t\tfilesaver.readyState = filesaver.INIT;\n\n\t\t\tif (can_use_save_link) {\n\t\t\t\tobject_url = get_URL().createObjectURL(blob);\n\t\t\t\tsetTimeout(function() {\n\t\t\t\t\tsave_link.href = object_url;\n\t\t\t\t\tsave_link.download = name;\n\t\t\t\t\tclick(save_link);\n\t\t\t\t\tdispatch_all();\n\t\t\t\t\trevoke(object_url);\n\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfs_error();\n\t\t}\n\t\t, FS_proto = FileSaver.prototype\n\t\t, saveAs = function(blob, name, no_auto_bom) {\n\t\t\treturn new FileSaver(blob, name || blob.name || \"download\", no_auto_bom);\n\t\t}\n\t;\n\t// IE 10+ (native saveAs)\n\tif (typeof navigator !== \"undefined\" && navigator.msSaveOrOpenBlob) {\n\t\treturn function(blob, name, no_auto_bom) {\n\t\t\tname = name || blob.name || \"download\";\n\n\t\t\tif (!no_auto_bom) {\n\t\t\t\tblob = auto_bom(blob);\n\t\t\t}\n\t\t\treturn navigator.msSaveOrOpenBlob(blob, name);\n\t\t};\n\t}\n\n\tFS_proto.abort = function(){};\n\tFS_proto.readyState = FS_proto.INIT = 0;\n\tFS_proto.WRITING = 1;\n\tFS_proto.DONE = 2;\n\n\tFS_proto.error =\n\tFS_proto.onwritestart =\n\tFS_proto.onprogress =\n\tFS_proto.onwrite =\n\tFS_proto.onabort =\n\tFS_proto.onerror =\n\tFS_proto.onwriteend =\n\t\tnull;\n\n\treturn saveAs;\n}(\n\t   typeof self !== \"undefined\" && self\n\t|| typeof window !== \"undefined\" && window\n\t|| this.content\n));\n// `self` is undefined in Firefox for Android content script context\n// while `this` is nsIContentFrameMessageManager\n// with an attribute `content` that corresponds to the window\n\nif (typeof module !== \"undefined\" && module.exports) {\n  module.exports.saveAs = saveAs;\n} else if ((\"function\" !== \"undefined\" && __webpack_require__(307) !== null) && (__webpack_require__(308) !== null)) {\n  !(__WEBPACK_AMD_DEFINE_RESULT__ = (function() {\n    return saveAs;\n  }).call(exports, __webpack_require__, exports, module),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n}\n\n\n/***/ }),\n/* 307 */\n/***/ (function(module, exports) {\n\nmodule.exports = function() {\n\tthrow new Error(\"define cannot be used indirect\");\n};\n\n\n/***/ }),\n/* 308 */\n/***/ (function(module, exports) {\n\n/* WEBPACK VAR INJECTION */(function(__webpack_amd_options__) {/* globals __webpack_amd_options__ */\nmodule.exports = __webpack_amd_options__;\n\n/* WEBPACK VAR INJECTION */}.call(exports, {}))\n\n/***/ })\n/******/ ]);\n});"
  },
  {
    "path": "static/js/DataTables/pdfmake-0.1.36/vfs_fonts.js",
    "content": "this.pdfMake = this.pdfMake || {}; this.pdfMake.vfs = {\n  \"Roboto-Italic.ttf\": \"AAEAAAASAQAABAAgR0RFRtRX1FkAAgp8AAACREdQT1NKcuCzAAIMwAAAUiRHU1VCw4aZEQACXuQAABfoT1MvMqCnsO0AAAGoAAAAYGNtYXBAbb9DAAAafAAABoBjdnQgJEEG5QAAI5QAAABMZnBnbWf0XKsAACD8AAABvGdhc3AACAATAAIKcAAAAAxnbHlmoLsktAAALagAAdn2aGRteCEe/AUAABWQAAAE7GhlYWT4gasAAAABLAAAADZoaGVhDKYSegAAAWQAAAAkaG10eHJO1ygAAAIIAAATiGxvY2EXM5zBAAAj4AAACcZtYXhwBxICWwAAAYgAAAAgbmFtZTlLZFAAAgegAAACrnBvc3T/YQBkAAIKUAAAACBwcmVwdKCP7AAAIrgAAADbAAEAAAACAAAcadIiXw889QAbCAAAAAAAxPARLgAAAADQ206M+jj91QlMCHMAAgAJAAIAAAAAAAAAAQAAB2z+DAAACRb6OP52CUwIAAGzAAAAAAAAAAAAAAAABOIAAQAABOIAkAAWAFYABQABAAAAAAAOAAACAAFzAAYAAQADBAsBkAAFAAAFmgUzAAABHwWaBTMAAAPRAGYCAAAAAgAAAAAAAAAAAOAACv9QACF/AAAAIQAAAABHT09HAAEAAP/9BgD+AABmB5oCACAAAZ8AAAAABDoFsAAgACAAAgOWAGQACgAAAAoAAAH2AAAB9gAAAgkAQwKFAMgE0QBSBGYASgW5ALsE3QA6AWQAqgKxAG0Cvf+PA2IAawRwAEwBkP+PAi4AGQIVADUDPf+PBGYAaARmAPkEZgAXBGYANARmAAUEZgByBGYAcARmAJ0EZgBBBGYAlAHrACsBrv+bA/wAQQRMAHAEGAA6A7QApQcCAEQFGv+vBN8AOwUXAHQFIQA7BHMAOwRUADsFUwB5BZIAOwImAEkEUgAKBOcAOwQ3ADsG0AA7BZIAOwVgAHcE7wA7BWAAbwTRADoEpQAnBKsAqAUSAGcE+gCkBuwAwwTn/9QEswCoBK//6wIZ//8DOQC/Ahn/egNIAE8Div+BAnAAzwRDADMEZQAfBBoARgRqAEsEJgBFArwAdARlAAQEUAAfAewALwHk/xQD+QAgAewALwbXAB4EUgAfBHcARQRl/9cEcwBJAqoAHwQKAC4CkwBDBFEAWwPMAG4F3wCAA+P/xAO2/6UD4//tAqoAOAHuACECqv+MBVEAaQHu//EESABSBIz/8wWSABIEvQBTAeb/9wTM/90DSADbBiMAYgOCAMMDrgBZBFYAgQYkAGEDmADjAvAA6AQvACUC4gBcAuIAbgJ5ANUEb//lA9UAewIQAKUB9v/IAuIA3wORAMADrQAPBbkAuQYPALQGEwCeA7b/0wdL/4QELQAoBWAAIASgADgEpwAeBpcAEwSWAFwEeABEBG8AOQSD/+AFeQA1AfUALgRbAC0EOAAiAiIAIwVqADUEbwAkB3AAVAcWAEcB9wAzBWcAUQKu/0kFXgBnBHkAQgVvAGcE1wBaAf7/CQQhAD4DsQEXA3wBJgOZAOMDWgEHAewBDgKiAQECI/+vA7MA3QLvAMICUv/pAAr9agAK/esACv0LAAr99QAK/NsB6vy7AgcBIQP2APMCEQClBFsAQwWD/7EFUQBpBSD/xAR4AAwFkwBEBHj/2gWZAFQFaACGBTMACgRsAEgEo//wA+0AhARvAEMEOQApBA8AggRvACQEdQBzAo0AhQRW/7cD2AA/BKkAYARv/9wENgBOBG8ASgQWAIcERQBnBYIAQQV5AE8GbgBmBIcAUQQrAGcGIgBmBdsAoQVFAHgIWf/MCGwAQwZaALQFkgBCBO4ANAXg/4sHFf+sBKUAJQWSAEMFiP/KBOoAkwYHAFsFtgBBBVoAzgdXAEIHjgBCBe0AiQbAAEUE6AA2BUUAdAb6AEkE+//oBFQARgR5ADADSwAtBLn/jQX7/6UD+wAhBIUALwQ7AC8Ehv/IBcsAMASEAC8EhQAvA8QAYAWqAEwEowAvBEIAewZQAC8GdQAkBNsAVgYQADAEQQAwBDYANAZfADAETP+/BFAAHwQ2AE4Gn//DBrkALwRwAB8EhQAvBtwAbwYGAE8EPwAuBv4ASQXUACwEt/+6BC//ogbfAFoF5wBOBqcAJgW+ACkIyQBIB58ALgQN/84Dx//KBVEAaQRyAEIE7QCtA+4AhAVRAGoEbwBEBtUAdAX/AFIG3ABvBgYATwUUAGYEMABNBOEAQAAK/OgACv0LAAr+FwAK/jsACvo4AAr6TwQ/AC4E/gA6BHD/1wRLADUDfwAkBMAAQwPwACQE7AA2BGYALQZkALsFYwB0B50AOgWSACQH/ABCBskAJAXKAHEEuABfBv8ArAU9AFcFTwDEBFIAmAVQAOwGCgCKBKMABwTsADUEQwAtBZAAQwRvACQFZwBRBI4APASO//wEnf/4Azr/6QTaADEGawAyBrkATAYvAK0FDQBoBDIArwPyAKAHj//fBk3/2gfIADsGeAAjBNoAagQHAEwFiwCaBQMAfQVFAGoDEgDyA/8AAAf0AAAD/wAAB/QAAAKuAAACBAAAAVwAAARmAAACKQAAAZ8AAADVAAAACgAAAi0AGQItABkFIgCnBhkAmQOU/18BlwCuAZcAiQGV/5gBlwDUAsgAtgLPAJUCtv+UBFEAdwR2//YCpwCgA7EAOQU7ADkA+QAaB3kAlwJeAF8CXgACA5H/7wLiAGEDUAB+BIz/8wYuAAoGaAA5CD8AOgc0ACIGBgAfBGYAUQW3AEMEDABJBFwACgUp//IFMP/lBcQAzAO7AEsIBQA1BOUA6gT6AIIGAQC1BqwAkgalAI8GQwC+BHYATQVtACQElf+sBHkAqwSqAEEIBQBNAgb/GgRpADEETABwA/z/1AQZABkD8wBBAkQAeAKFAHAB/v/jBNcAdARWAFgEcgB0BqoAdAaqAHQE0gB0BnIAKQAKAAAH/v+rCDUAXAQKAGIEhQBBAff/DwGP/70DkgETA4wBEgONARED4ADNA/kAzgPfACID2wDSA5IBEQH4APwEbP+lBDkAHQRkAEcEZwAdA9IAHQO4AB0EkgBMBMcAHQHjACoDvP/2BD0AHQOiAB0F3gAdBMcAHQShAEoERQAdBKEARQQzAB0ECgARBBAAbQRkAEUETwB6BfAAlQQ9/7YEFQB0BA3/3ALiAB0C4gBrAuL/6QLi//sC4v/wAuIAFgLiAB4C4gAvAuIACwLiADYDhACTAqoBCwQk/5oEqABLBS0AQwUHAEQD/gAlBR8ARAP6ACUECgASBB0ABgQlADQDnQAdBE//sAShAEoET/+wA3j/0wSzAB0D2//VBUgAUQT6AH4E1gAMBVIAbARkAEcHE//EByEAHQVUAG0EsgAdBEIAHwUH/4kF5/+vBCgAEQTQAB8ENwAeBKb/xAQJAFgFCgAdBFIAWgYqAB0GgwAdBQAAUAXNAB8ENwAfBGMAIAZOAB0Ebv/fA/z/+gYh/68EYQAeBOwAHgUZAGkFoABQBEcAdASO/7YGOgBsBFIAWgRSAB0FoQAvBK8AQQQoABEEoQBKBB3//wPPAB4H7gAdBJH/3QRlAB8EHABDBHoARwRzACQDaACpBHT/1wSDAEYEJgBFBGUANQVhAIEFjACEBXIARAW9AIUFwACFA8IAuwRpADkDnQAdBEH/gQS0/9MC4gCQAuIAYQLiAIkC4gCRAuIAogLiAH4C4gCpBFP/1QQYACsGewBJBJ8APwTkAGQCAP8JAf//CQH2AC4B9v96AfYALgH2//EEOQAdAfYAAAIuABkFPwAvBT8ALwRuAD0EqwCoApP/9AUa/68FGv+vBRr/rwUa/68FGv+vBRr/rwUa/68FFwB0BHMAOwRzADsEcwA7BHMAOwImAEkCJgBJAiYASQImAEkFkgA7BWAAdwVgAHcFYAB3BWAAdwVgAHcFEgBnBRIAZwUSAGcFEgBnBLMAqARDADMEQwAzBEMAMwRDADMEQwAzBEMAMwRDADMEGgBGBCYARQQmAEUEJgBFBCYARQH1AC4B9QAuAfUALgH1AC4EUgAfBHcARQR3AEUEdwBFBHcARQR3AEUEUQBbBFEAWwRRAFsEUQBbA7b/pQO2/6UFGv+vBEMAMwUa/68EQwAzBRr/rwRDADMFFwB0BBoARgUXAHQEGgBGBRcAdAQaAEYFFwB0BBoARgUhADsFAABLBHMAOwQmAEUEcwA7BCYARQRzADsEJgBFBHMAOwQmAEUEcwA7BCYARQVTAHkEZQAEBVMAeQRlAAQFUwB5BGUABAVTAHkEZQAEBZIAOwRQAB8CJgBJAfUAEQImAEkB9QAaAiYASQH1AC4CJv+OAez/cAImAEkGeABJA9AALwRSAAoB/v8JBOcAOwP5ACAENwA7AewALwQ3ADsB7P+jBDcAOwKCAC8ENwA7AsgALwWSADsEUgAfBZIAOwRSAB8FkgA7BFIAHwRSAB8FYAB3BHcARQVgAHcEdwBFBWAAdwR3AEUE0QA6AqoAHwTRADoCqv+fBNEAOgKqAB8EpQAnBAoALgSlACcECgAuBKUAJwQKAC4EpQAnBAoALgSlACcECgAuBKsAqAKTAEMEqwCoApMAQwSrAKgCuwBDBRIAZwRRAFsFEgBnBFEAWwUSAGcEUQBbBRIAZwRRAFsFEgBnBFEAWwUSAGcEUQBbBuwAwwXfAIAEswCoA7b/pQSzAKgEr//rA+P/7QSv/+sD4//tBK//6wPj/+0HS/+EBpcAEwVgACAEbwA5BGf/sARn/7AEEABtBGz/pQRs/6UEbP+lBGz/pQRs/6UEbP+lBGz/pQRkAEcD0gAdA9IAHQPSAB0D0gAdAeMAKgHjACoB4wAqAeMAKgTHAB0EoQBKBKEASgShAEoEoQBKBKEASgRkAEUEZABFBGQARQRkAEUEFQB0BGz/pQRs/6UEbP+lBGQARwRkAEcEZABHBGQARwRnAB0D0gAdA9IAHQPSAB0D0gAdA9IAHQSSAEwEkgBMBJIATASSAEwExwAdAeMADwHjABgB4wAqAeP/egHjACoDvP/2BD0AHQOiAB0DogAdA6IAHQOiAB0ExwAdBMcAHQTHAB0EoQBKBKEASgShAEoEMwAdBDMAHQQzAB0ECgARBAoAEQQKABEECgARBBAAbQQQAG0EEABtBGQARQRkAEUEZABFBGQARQRkAEUEZABFBfAAlQQVAHQEFQB0BA3/3AQN/9wEDf/cBRr/rwTXAGMF9gBxAooAdwV0AGoFF//uBUcAHgKNACAFGv+vBN8AOwRzADsEr//rBZIAOwImAEkE5wA7BtAAOwWSADsFYAB3BO8AOwSrAKgEswCoBOf/1AImAEkEswCoBGwASAQ5ACkEbwAkAo0AhQRFAGcEWwAtBHcARQRv/+UDzABuA+P/xAKNAGcERQBnBHcARQRFAGcGbgBmBHMAOwRbAEMEpQAnAiYASQImAEkEUgAKBQcARATnADsE6gCTBRr/rwTfADsEWwBDBHMAOwWSAEMG0AA7BZIAOwVgAHcFkwBEBO8AOwUXAHQEqwCoBOf/1ARDADMEJgBFBIUALwR3AEUEZf/XBBoARgO2/6UD4//EBCYARQNLAC0ECgAuAewALwH1AC4B5P8UBDsALwO2/6UG7ADDBd8AgAbsAMMF3wCABuwAwwXfAIAEswCoA7b/pQFkAKoChQDIBBIAQwH+/wkBlwCJBtAAOwbXAB4FGv+vBEMAMwRzADsFkgBDBCYARQSFAC8FaACGBXkATwTtAK0D7gCECC0ARQkWAHcEpQAlA/sAIQUXAHQEGgBGBLMAqAPtAIQCJgBJBxX/rAX7/6UCJgBJBRr/rwRDADMFGv+vBEMAMwdL/4QGlwATBHMAOwQmAEUFZwBRBCEAPgQhAD4HFf+sBfv/pQSlACUD+wAhBZIAQwSFAC8FkgBDBIUALwVgAHcEdwBFBVEAaQRyAEIFUQBpBHIAQgVFAHQENgA0BOoAkwO2/6UE6gCTA7b/pQTqAJMDtv+lBVoAzgRCAHsGwABFBhAAMATn/9QD4//EBGoASwWI/8oEhv/IBRr/rwRDADMFGv+vBEMAMwUa/68EQwAzBRr/rwRDADMFGv+vBEMAMwUa/68EQwAzBRr/rwRDADMFGv+vBEMAMwUa/68EQwAzBRr/rwRDADMFGv+vBEMAMwUa/68EQwAzBHMAOwQmAEUEcwA7BCYARQRzADsEJgBFBHMAOwQmAEUEcwA7BCYARQRzADsEJgBFBHMAOwQmAEUEcwA7BCYARQImAEkB9QAuAiYADgHs//EFYAB3BHcARQVgAHcEdwBFBWAAdwR3AEUFYAB3BHcARQVgAHcEdwBFBWAAdwR3AEUFYAB3BHcARQVeAGcEeQBCBV4AZwR5AEIFXgBnBHkAQgVeAGcEeQBCBV4AZwR5AEIFEgBnBFEAWwUSAGcEUQBbBW8AZwTXAFoFbwBnBNcAWgVvAGcE1wBaBW8AZwTXAFoFbwBnBNcAWgSzAKgDtv+lBLMAqAO2/6UEswCoA7b/pQSIAEsEiAAABQcARAQ7AC8FkgA7BIQALwSrAKgDxABgBOf/1APj/8QFWgDOBEIAewVaAM4EQgB7BFsAQwNLAC0HFf+sBfv/pQYKAIoEowAHBFAAHwToACsE6AArBFsAEANL/+YFGwBYBBIAOQWSAEMEhQAvBZIAOwSEAC8G0AA7BcsAMAWI/8oEhv/IBLMAqAPtAF0E5//UA+P/xAQ5ACkEVP/XBhkAmQRmABcEZgA0BGYABQRmAHIEegCUBI4AfAVTAHkEZQAEBZIAOwRSAB8FGv+vBEMAMwRzADsEJgBFAib/3wH1/40FYAB3BHcARQTRADoCqgAfBRIAZwRRAFsEj/+yBN8AOwRlAB8FIQA7BGoASwUhADsEagBLBZIAOwRQAB8E5wA7A/kAIATnADsD+QAgBDcAOwHs//IG0AA7BtcAHgWSADsEUgAfBO8AOwRl/9cE0QA6Aqr/7gSlACcECgAuBKsAqAKTAEME+gCkA8wAbgT6AKQDzABuBuwAwwXfAIAEr//rA+P/7QWm/wwEbP+lBA7/4QUD//0CHwABBKsAHQRR/5sE4AAWBGz/pQQ5AB0D0gAdBA3/3ATHAB0B4wAqBD0AHQXeAB0EoQBKBEUAHQQQAG0EFQB0BD3/tgHjACoEFQB0A9IAHQOdAB0ECgARAeMAKgHjACoDvP/2BD0AHQQJAFgEbP+lBDkAHQOdAB0D0gAdBNAAHwXeAB0ExwAdBKEASgSzAB0ERQAdBGQARwQQAG0EPf+2BCgAEQTHAB0EZABIBBUAdAWhAC8E0AAfBAkAWAVIAFEFGv+vBEMAMwRzADsEJgBFAAAAAQAABOQJCgQAAAICAgMFBQYFAgMDBAUCAgIEBQUFBQUFBQUFBQICBAUFBAgGBQYGBQUGBgIFBgUIBgYGBgUFBQYGCAYFBQIEAgQEAwUFBQUFAwUFAgIEAggFBQUFAwUDBQQHBAQEAwIDBgIFBQYFAgUEBwQEBQcEAwUDAwMFBAICAwQEBgcHBAgFBgUFBwUFBQUGAgUFAgYFCAgCBgMGBQYFAgUEBAQEAgMCBAMDAAAAAAACAgQCBQYGBgUGBQYGBgUFBAUFBQUFAwUEBQUFBQUFBgYHBQUHBwYJCQcGBgcIBQYGBgcGBggJBwgGBggGBQUEBQcEBQUFBwUFBAYFBQcHBQcFBQcFBQUHCAUFCAcFCAcFBQgHBwYKCQUEBgUGBAYFCAcIBwYFBQAAAAAAAAUGBQUEBQQGBQcGCQYJCAcFCAYGBQYHBQYFBgUGBQUFBAUHCAcGBQQJBwkHBQUGBgYDBQkFCQMCAgUCAgEAAgIGBwQCAgICAwMDBQUDBAYBCAMDBAMEBQcHCQgHBQYFBQYGBgQJBgYHCAcHBQYFBQUJAgUFBAUEAwMCBQUFCAgFBwAJCQUFAgIEBAQEBAQEBAIFBQUFBAQFBQIEBQQHBQUFBQUFBQUFBwUFBQMDAwMDAwMDAwMEAwUFBgYEBgQFBQUEBQUFBAUEBgYFBgUICAYFBQYHBQUFBQUGBQcHBgcFBQcFBAcFBgYGBQUHBQUGBQUFBQQJBQUFBQUEBQUFBQYGBgYGBAUEBQUDAwMDAwMDBQUHBQYCAgICAgIFAgIGBgUFAwYGBgYGBgYGBQUFBQICAgIGBgYGBgYGBgYGBQUFBQUFBQUFBQUFBQICAgIFBQUFBQUFBQUFBAQGBQYFBgUGBQYFBgUGBQYGBQUFBQUFBQUFBQYFBgUGBQYFBgUCAgICAgICAgIHBAUCBgQFAgUCBQMFAwYFBgUGBQUGBQYFBgUFAwUDBQMFBQUFBQUFBQUFBQMFAwUDBgUGBQYFBgUGBQYFCAcFBAUFBAUEBQQIBwYFBQUFBQUF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c3dzd3N/c4dzkXObc7Jz0XPvdA50LnQ6dEZ0d3S4dR11QnVOdV51cnZGdmJ2f3aSdqZ273d6eBx4qXi1eXh503pZewR7ZnvpfEd8uH1dfcl+W368fyR/Pn9Yf3J/jH//gCeAYYB9gLKBO4GBgfiCOYJHglWCjoKbgsKC24Lng0qDo4Q3hMKFQ4YXhheHlIfxiCKIgIiviMWJKIl6ibqKLIqFisWLCItIi2KLqIwejHqMx40TjU+Nto4EjiKOWI6cjsSPFo9Uj7OQA5BhkLWRI5FPkYuRvpISkleSi5LIkxuTRpOVlAaUSJSolQiVNZW+liCWN5aBlz6XuZgtmHyYwpkEmUyZzJo4mq+a2psQm4ibuZwHnDqcepzunVCdu54enoyfA597n9KgDaBpoMGhN6G8ofqiS6KUotijE6Nbo5uj5aRApEyknaURpZyl+aZIptCnM6eYp/iooqiuqQGpTamiqeuqZarSqzerq6xHrM6tb63irk+uqK8Tr5yvpLAQsH6w6bFysdWyQLKSsvSzWrOFs9q0BLRdtKG0tbTJtNu077UBtRi1LLWOtba2RLa0tw23FbcdtyW3MLc4t0S3sLewt7i4KLiYuPq5QLmoub+51rntugS6HLovuju6R7peunC6h7qaurG6w7rauu27BLsbuy27RLtbu267hbuXu667wbvTu+q7/LwSvCO8NrxJvFW8Ybx4vIq8oLyzvMm82rzxvQm9Gr0xvUO9Wb1qvX29lL2mvby9z73hvfO+Cr4gvje+Sb62v2S/dr+Iv5q/q7+9v8+/4b/ywATAEMAiwDPARcBXwGnAe8DvwX3Bj8GgwbLBw8HVwefB+cILwhfCKcI7wk/CYcJzwoXCl8KpwrvCxsLRwuPC78L7ww3DH8MrwzfDScNbw2fDc8OIw5TDoMOsw77D0MPcw+jD+sQLxBfEKcQ6xEzEXsRxxITElsSoxLTEwMTSxOPE9cUHxRnFKsU2xULFTsVaxWzFfcWJxZXFocWtxb/Fy8Xdxe7GAMYRxiPGNcZIxlvGbsaBxuLHUcdjx3XHh8eYx6vHvcfPx+HH88gFyBbILchEyFvIcsiVyLjIyMjfyPHJB8kYySvJPslKyVbJbcl/yZDJosm4ycnJ28nuygDKF8opyjvKTcpgynfKicqayq3Kv8rQyuLLSctby2zLfsuQy6HLssvDy9XMT8xgzHHMg8yVzKHMs8zFzNfM6cz0zQXNF80jzTTNQM1VzWHNc81/zZHNo821zcjN2s3mzffOCc4azibON85DzlTOYM5xzoLOlM6nzrrPJc83z0jPWs9sz37Pj8+az6bPss++z8rP1s/iz/3QBdAN0BXQHdAl0C3QNdA90EXQTdBV0F3QZdBt0IDQk9Cl0LfQydDa0O/Q99D/0QfRD9EX0SnRO9FN0V/RcdGJ0aDSFdId0jDSONJA0lfSbtJ20n7ShtKO0qDSqNKw0rjSwNLI0tDS2NLg0ujS8NMC0wrTEtNv03fTf9OS06nTsdO508zT1NPr1AHUGNQv1EbUXdR11I3UpNS71MPUy9TX1O7U9tUN1STVMNU81VPVatWB1ZjVoNWo1cDV2NXk1fDV/NYI1hTWINYo1jDWONZP1mbWbtaF1pzWtNbH1s/W19bp1vvXDtcW1ynXPNdP12LXdNeG15fXqte919DX49fr1/PYBtgZ2CzYP9hR2GLYddiH2J/Yt9jP2OHY/dkZ2SXZMdk52UXZUdld2WnZe9mN2aXZvNnU2evaA9oa2jLaSdpk2n7akdqk2rfaytrd2vDbA9sW2zHbTNtY22TbdtuI25rbq9vD29rb8twJ3CHcONxQ3Gfcgtyc3K7cwNzM3Njc5Nzw3QLdFN0s3UPdW91y3Yrdod253dDd694F3hzeM95K3mHeeN6P3qbevN7I3tTe4N7s3v7fEN8n3z7fVd9s34Pfmt+x38ff09/f3+vf9+AJ4BvgLeA+4L7gzuDa4Obg8uD+4QrhFuEi4S7hOuFG4VLhXuFq4XbhguGO4ZrhpuGu4hjihOLK4xDjb+PK4+XkAOQM5BjkJOQw5DzkSOST5OPlO+WV5Z3lqeWz5bvlw+XL5dPl2+Xj5frmEeYo5j/mV+Zv5ofmn+a35s/m5+b/5xfnL+dH51/na+d354Pnj+eb56fns+e/58vn4uf06ADoDOgY6CToMOg86EjoVOhr6ILojuia6Kbosui+6Mro4ej36QPpD+kb6SfpM+k/6UvpV+lj6W/pe+mH6ZPpn+mn6a/pt+m/6cfpz+nX6d/p5+nv6ffp/+oH6h/qNupN6mTqbOp06ozqlOqr6sHqyerR6tnq4er46wDrCOsQ6xjrIOso6zDrOOvD7B3sguyK7JbsrezD7Mvs1+zj7O/s+wAAAAUAZAAAAygFsAADAAYACQAMAA8AcbIMEBEREjmwDBCwANCwDBCwBtCwDBCwCdCwDBCwDdAAsABFWLACLxuxAhw+WbAARViwAC8bsQAQPlmyBAIAERI5sgUCABESObIHAgAREjmyCAIAERI5sQoM9LIMAgAREjmyDQIAERI5sAIQsQ4M9DAxISERIQMRAQERAQMhATUBIQMo/TwCxDb+7v66AQzkAgP+/gEC/f0FsPqkBQf9fQJ3+xECeP1eAl6IAl4AAgBD//IB9AWwAAMADgA/sgkPEBESObAJELAA0ACwAEVYsAIvG7ECHD5ZsABFWLANLxuxDRA+WbIHBQorWCHYG/RZsgEHAhESObABLzAxASMTMwE2Njc2FhUUBgYmATGkqb7+TwE6MC48PF47AZsEFfqqLz0CAjwuLzsEOgAAAgDIBBECpgYIAAQACQAZALADL7ICCgMREjmwAi+wB9CwAxCwCNAwMQEDBxMXFwMjExcBiVNuUIjvU25QiAVu/qQBAfcJkf6kAfYJAAIAUgAABPsFsAAbAB8AjwCwAEVYsAwvG7EMHD5ZsABFWLAQLxuxEBw+WbAARViwAi8bsQIQPlmwAEVYsBovG7EaED5Zsh0MAhESOXywHS8YsgADCitYIdgb9FmwBNCwHRCwBtCwHRCwC9CwCy+yCAMKK1gh2Bv0WbALELAO0LALELAS0LAIELAU0LAdELAW0LAAELAY0LAIELAe0DAxASMDIxMjNzMTIzchEzMDMxMzAzMHIwMzByMDIwMzEyMCw/qWkJXmGP+A+BgBEpiRmfuYkpnEGN6A2BjxlZI0+oH6AZr+ZgGaiQFiiwGg/mABoP5gi/6eif5mAiMBYgAAAQBK/zAEPAacACsAbbIfLC0REjkAsABFWLAJLxuxCRw+WbAARViwIi8bsSIQPlmyAiIJERI5sAkQsAzQsAkQsBDQsAkQshMBCitYIdgb9FmwAhCyGQEKK1gh2Bv0WbAiELAf0LAiELAm0LAiELIpAQorWCHYG/RZMDEBNiYmJyY3NjY3NzMHFhYHIzYmJyYGBwYWBBYWBwYGBwcjNyYmNzMGFhcWNgMhCmr9S5QOC9exJ5IolJEPswhnZHGTDAldARKOQQcN5b0ikSOkqAu1C3V2f6sBflaAYT15xKTXF9veHfHAk50DAoNvVnxtd5pjq9IUv8EY6rqDnAIChQAFALv/5gU4BcgADQAbACkANwA7AImyJTw9ERI5sCUQsAXQsCUQsBbQsCUQsCvQsCUQsDjQALA4L7A6L7AARViwAC8bsQAcPlmwAEVYsCMvG7EjED5ZsAAQsAfQsAcvshEECitYIdgb9FmwABCyGAQKK1gh2Bv0WbAjELAc0LAcL7AjELItBAorWCHYG/RZsBwQsjQECitYIdgb9FkwMQEWFgcHBgYnJiY3NzY2AwYWFxY2Nzc2JicmBgcBFhYHBwYGJyYmNzc2NgMGFhcWNjc3NiYnJgYHBScBFwINeY8IBg+1fXmSCAYNt0MFRUBEZQsJB0JDRWYLAtt8jggGDbWAeJMIBg2yPgVDQkZjCwkHQkNHZAv982MDcWMFxgSpgU2GqgQCrH5AkK3+gVFfAgJlUU5MZgICZlH9+gSrfkONrwQCqoFEi67+gVBhAgJmUU9LZgICZlD1SARoRwADADr/6QSHBcgAHAAlADEAmLIeMjMREjmwHhCwD9CwHhCwMNAAsABFWLAJLxuxCRw+WbAARViwGi8bsRoQPlmwAEVYsBcvG7EXED5ZsiAaCRESObIpCRoREjmyAyApERI5sg8pIBESObIQGgkREjmyEhoJERI5shgaCRESObIVEBgREjmwGhCyHQEKK1gh2Bv0WbIfHRAREjmwCRCyLwEKK1gh2Bv0WTAxEzY3NycmNzY2FxYWBwYHBxM2NzMGBxcjJwYnJiYFFjcBBwYHBhYTBhcXNzY3NiYjIgZHD89yK0gIDNikh7AICcyT+VsXoRuancpJrtG95gGphpb+8SuzEw9+cAg5G5lrCwZSRFNwAYC6kkxNhHGlyQQCq3+sj2L+g4eb/6z1cYgEAuFNA3QBqB58g2yOA9xUZS9nUGlAVHkAAQCqBCEBiQYAAAQAEACwAy+yAgUDERI5sAIvMDEBAyMTMwF2TIBNkgWK/pcB3wAAAQBt/ioDGAZsABIAELICExQREjkAsAQvsA0vMDETNhIANxcGAgIXFBIXByYCEzY3hSGzAQSgG53hegJrZS2nsQgCDAJL5wG2ATVPfHX+h/35/M/+xVtwdAHGASVgVwAAAf+P/ikCOAZrABIAELIHExQREjkAsAQvsAwvMDEBBgIABycAEzYnAic3FhISBwYHAiMjuP7/nBwBV3MuAgXLL3CbSQQDDAJJ9P5N/tVOcwECAjvm1QGtunBO/v3+qbhhVgABAGsCXwOKBbAADgAgALAARViwBC8bsQQcPlmwANAZsAAvGLAJ0BmwCS8YMDEBJTcFEzMDJRcFEwcDAycBgP7rRAEWM5ZGAS8T/sWTgIPecgPbWpBxAVz+qGyfW/7tWAEi/uhiAAABAEwAkgQ0BLYACwAaALAJL7AA0LAJELIGAQorWCHYG/RZsAPQMDEBIQchAyMTITchEzMCqgGKH/53ULZQ/nYfAYlKtgMNr/40AcyvAakAAAH/j/7dAOoA2wAHABcAsAgvsgQFCitYIdgb9FmwANCwAC8wMQMnNjc3MwcGCWh0HBqxFST+3UuPjZeH5AAAAQAZAh8CDwK2AAMAEQCwAi+yAQEKK1gh2Bv0WTAxASE3IQH0/iUbAdsCH5cAAAEANf/yARUA0wAIACKyAwkKERI5ALAARViwBS8bsQUQPlmyAAUKK1gh2Bv0WTAxNzYWDgImNDakMUACQGA+PtIBPmI9BDtiQQAAAf+P/4MDkgWwAAMAEwCwAC+wAEVYsAIvG7ECHD5ZMDEXIwEzM6QDYKN9Bi0AAAIAaP/nBCsFyQARACEARrIXIiMREjmwFxCwCNAAsABFWLAJLxuxCRw+WbAARViwAC8bsQAQPlmwCRCyFgEKK1gh2Bv0WbAAELIeAQorWCHYG/RZMDEFJiY3Njc3EgAXFhYHBgcHAgATNicmJyYGBwMGFxIXFjY3Adi4uAgCCSQwAQ7durcHAwkjNf70tQ4BBcCMrSIrDgEFv4WtJRQE/e5KSPMBNwEyBQT360tI6/63/tADhXlD/gcF2ej+3nRJ/vcHBtDiAAEA+QAAA1QFtwAGADkAsABFWLAFLxuxBRw+WbAARViwAC8bsQAQPlmyBAAFERI5sAQvsgMBCitYIdgb9FmyAgMFERI5MDEhIxMFNyUzAly21v59HwIcIATMiLDDAAABABcAAAQrBccAGQBUsgMaGxESOQCwAEVYsBEvG7ERHD5ZsABFWLAALxuxABA+WbIZAQorWCHYG/RZsALQsgMRGRESObARELIJAQorWCHYG/RZsBEQsAzQshcZERESOTAxISE3ATc2NzYmJyYGBwc+AhcWFgcGBwcBIQO2/GEWAhliqRINcGaDsBOzDYvjhbXVDxHMXP4sAr+NAgphqY9uiwQEoYwBhs9vAwTTqMDUXf5DAAABADT/6AQhBccAKAB/sggpKhESOQCwAEVYsA4vG7EOHD5ZsABFWLAaLxuxGhA+WbIAGg4REjmwAC+yzwABXbKfAAFxsi8AAV2yXwABcrAOELIHAQorWCHYG/RZsA4QsArQsAAQsigBCitYIdgb9FmyFCgAERI5sBoQsB3QsBoQsiEBCitYIdgb9FkwMQEXMjY3NiYnJgYHBzYkFxYWBwYGBxYWBwYEJyYmNxcGFhcWNjc2JicnAaB4hLUNDXBrcp8SsxEBEb230Q4JjHxjYggQ/ufJu94ItQZ4coCqDAuCgYsDMgGLd3SFAgKJdAG04QIE3bVnqjgorXTF8AQE4LEBcIkEBJqBd4UEAQAAAgAFAAAEHQWwAAoADgBJALAARViwCS8bsQkcPlmwAEVYsAQvG7EEED5ZsgEJBBESObABL7ICAQorWCHYG/RZsAbQsAEQsAvQsggGCxESObINCQQREjkwMQEzByMDIxMhNwEzASETBwNZxBvDO7Y7/XwVAyDG/PMBsIIdAemX/q4BUncD5/w5AswqAAABAHL/5wRqBbAAHQBoshseHxESOQCwAEVYsAEvG7EBHD5ZsABFWLANLxuxDRA+WbABELIDAQorWCHYG/RZsgcBDRESObAHL7IaAQorWCHYG/RZsgUHGhESObANELAR0LANELIUAQorWCHYG/RZsBoQsB3QMDETEyEHIQM2FxYSBwYAJyYmJzMWFhcWNjc2JicmBgfbuQLWG/3GcG6AtcISE/7o0a7WBqkHemiArxAOenZJcTgC3QLTq/5yQQIC/vPQ4P7wBALct3iEAgS+moevBAIwLQAAAgBw/+YD+AWyABYAJgBishgnKBESObAYELAO0ACwAEVYsAAvG7EAHD5ZsABFWLAOLxuxDhA+WbAAELIBAQorWCHYG/RZsgcADhESObAHL7IFBw4REjmyFwEKK1gh2Bv0WbAOELIgAQorWCHYG/RZMDEBByMGBAc2Fx4CBwYAJyYmJyY3EgAhASYGDwIUFhYXFjY3NiYmA7sQI8j+5E6ItnOkTQwU/uvKotAPCCFFAZcBOv7GYaouBwIyYkJ5rREKKmEFsp0E8OqIBAJ72YPd/uEGBObBabMBdQGK/XACdFpDUVKaUAEFvptallcAAAEAnQAABIwFsAAGADIAsABFWLAFLxuxBRw+WbAARViwAS8bsQEQPlmwBRCyAwEKK1gh2Bv0WbIAAwUREjkwMQEBIwEhNyEEevzpxgMT/QgYA7wFPvrCBRiYAAMAQf/oBDYFyAAXACMALwBvshswMRESObAbELAU0LAbELAo0ACwAEVYsBUvG7EVHD5ZsABFWLAJLxuxCRA+WbItFQkREjmwLS+yGwEKK1gh2Bv0WbIDLRsREjmyDxstERI5sAkQsiEBCitYIdgb9FmwFRCyJwEKK1gh2Bv0WTAxAQYGBxYWBwYEJyYmNzY2NyYmNzYkFxYWATYmJyYGBwYWFxY2EzYmJyYGBwYWFxY2BCgJiXZeWwgP/uLKvdwPC5qFTksIDgEGv67M/ugMeHJ8sA4MeW9+sGILaWFwmg0La2FtmwQ9ba85NrVrwekEBOKvfbs6NqReueQEBNr8sHGXBAKhf3SMAgSbAyFligQCk3RohgICkQACAJT//gQTBcgAGAAoAGWyEikqERI5sBIQsBnQALAARViwCy8bsQscPlmwAEVYsBMvG7ETED5ZsgMTCxESObADL7IAAwsREjmwExCyFQEKK1gh2Bv0WbADELIZAQorWCHYG/RZsAsQsiEBCitYIdgb9FkwMQEGBicuAjc+AhcWFhcWBwIABSM3MzYkJxY2PwImJicmBgcGFhcWAzdKplJzo0sMDYjbhK7GCAMcQv57/s8tECXXARPWW6g2CAMEa2R8rw4HEhs2AoBOTQICftyCkPCDBAT0zWuf/or+hQacBOn5BG9eSVGbqAQFyZc9fjBh//8AK//yAaQERgAmABL2AAEHABIAjwNzABAAsABFWLAJLxuxCRg+WTAx////m/7dAY0ERgAnABIAeANzAQYAEAwAABAAsABFWLAALxuxABg+WTAxAAEAQQDIA7gETwAGABYAsABFWLAFLxuxBRg+WbAC0LACLzAxAQUHATcBBwEHAjUh/SYaA10kAoD9uwF7kgF6zQACAHABjwP/A88AAwAHACUAsAcvsAPQsAMvsgABCitYIdgb9FmwBxCyBAEKK1gh2Bv0WTAxASE3IQMhNyED4vzWHAMrZfzWHAMrAy6h/cCgAAEAOgC/A9QERwAGABYAsABFWLACLxuxAhg+WbAF0LAFLzAxAQE3AQcBNwMN/aohAvwa/IAkAo4BA7b+hZH+hMkAAAIApf/yA78FxwAYACQAXbIeJSYREjmwHhCwCtAAsABFWLAQLxuxEBw+WbAARViwIi8bsSIQPlmyHAUKK1gh2Bv0WbAA0LAAL7IEEAAREjmwEBCyCQEKK1gh2Bv0WbAQELAM0LIVABAREjkwMQE2Njc3Njc2JicmBgcHNjYXFhYHBgcHBgcDNjY3NhYHFAYHBiYBQQ1gbFF9EAxWW2aDEbQT9bGouQ4Ru3piF/gBOjAuPQE8Ly87AZlzsGBHb3pedgQCcVkBpccCBMyltqhoWZf+wC89AgE7Ly48AQI6AAIARP47BpsFmgA3AEQAh7JCRUYREjmwQhCwC9AAsCcvsDAvsABFWLAFLxuxBRA+WbAARViwAC8bsQAQPlmyAzAAERI5sgwwABESObAML7AAELITAgorWCHYG/RZsDAQshoCCitYIdgb9FmwJxCyIgIKK1gh2Bv0WbAFELI6AgorWCHYG/RZsAwQskECCitYIdgb9FkwMQUmJicGJyYmNzYSNhcWFwMGFQYXFhITNgImJyYEAgMGEhYXFjcXBiMmJAI1JhIAJBcWBBIVFAIGAQYXFj8CEyYnJgIHBK9ZbQ2Ij3RwDAqY3IKLhYUKBWGTtgsHauep3f6G9QwIbuCiqaobi+W//uaaAp8BGwFpyMIBF5OD3f1OBXVrXSABhTQ3i8EiFAJZTawDAracoQFPsQIDZv3SQhuHAwYBVgEOtAESjAME/v4a/um1/uSRAQRSdVcBpwFB0tkBwwFXsQMDqP6+zOH+oLUBPqsDBZU1CwH6HAEF/ujtAAAC/68AAASLBbAABwAKAEYAsABFWLAELxuxBBw+WbAARViwAi8bsQIQPlmwAEVYsAYvG7EGED5ZsgkEAhESObAJL7IAAQorWCHYG/RZsgoEAhESOTAxASEDIwEzASMBIQMDjf2yx8kDF6UBILn9wAHfeQF8/oQFsPpQAhoCpwADADsAAASgBbAADQAWAB8AaLIYICEREjmwGBCwDdCwGBCwENAAsABFWLACLxuxAhw+WbAARViwAC8bsQAQPlmyGAIAERI5sBgvshYBCitYIdgb9FmyBxYYERI5sAAQshABCitYIdgb9FmwAhCyHgEKK1gh2Bv0WTAxMxMFMhYHBgcWFgcGBCMDAwUyNjc2JiclBTI2NzYmJyU7/QGr394OEvViYQkP/uLjyFsBKYi4Dw5udv7UAQ9/rw8NbX7+4gWwAciz0WomuG/F5wKp/fQBknx2hASbAYJyamwFAQABAHT/5gT5BckAHwBOshUgIRESOQCwAEVYsA0vG7ENHD5ZsABFWLADLxuxAxA+WbIADQMREjmyEAMNERI5sA0QshQBCitYIdgb9FmwAxCyHAEKK1gh2Bv0WTAxAQYAJy4CJyY3NxIABRYSFyMCJycmAg8CBhYXFjY3BJEq/rvjh8pwBgQLES8BbwEHzfAHuw3jIb39JRYGBo+NmMc0AdDi/vgGA3/vkVJOeAFIAXsFBP7/5AEyGAIF/t38l1i42QQFnK0AAgA7AAAE1QWwAAoAFQBDsg4WFxESObAOELAC0ACwAEVYsAIvG7ECHD5ZsABFWLAALxuxABA+WbINAQorWCHYG/RZsAIQshUBCitYIdgb9FkwMTMTBTIEEgcHAgAhEwMXMgA3NicmJic7/QF6sgEBcBcKLP5q/s0ZxrnUAScsIwsPsJQFsAGy/sfCSf7C/oUFEvuLAQEI5riBm68EAAABADsAAASxBbAACwBOALAARViwBi8bsQYcPlmwAEVYsAQvG7EEED5ZsgsEBhESObALL7IAAQorWCHYG/RZsAQQsgIBCitYIdgb9FmwBhCyCAEKK1gh2Bv0WTAxASEDIQchEyEHIQMhA9D9nFoCyBz8ff0DeRz9Q1ECZAKh/fydBbCe/iwAAAEAOwAABKQFsAAJAEAAsABFWLAELxuxBBw+WbAARViwAi8bsQIQPlmyCQIEERI5sAkvsgABCitYIdgb9FmwBBCyBgEKK1gh2Bv0WTAxASEDIxMhByEDIQO3/bBwvP0DbBz9UFYCUQKD/X0FsJ7+DgABAHn/6gUGBccAIQBcsh8iIxESOQCwAEVYsAwvG7EMHD5ZsABFWLADLxuxAxA+WbIQDAMREjmwDBCyEwEKK1gh2Bv0WbADELIbAQorWCHYG/RZsiEMAxESObAhL7IeAQorWCHYG/RZMDElBgQnLgInJhISJBcWFhcjJiYnJgIDBwcUFhcWNxMhNyEEe0n+6bOP1noJB0m2ARGwy/ERuguQf7z9KBMDopLTfDz+uBwCAMBnbwIDgO+YdwGWASicAwTp04qUBAf+5P7vjEzF1wIFbQFHnAAAAQA7AAAFdwWwAAsAVQCwAEVYsAYvG7EGHD5ZsABFWLAKLxuxChw+WbAARViwAC8bsQAQPlmwAEVYsAQvG7EEED5ZsAAQsAnQsAkvsp8JAXKyLwkBXbICAQorWCHYG/RZMDEhIxMhAyMTMwMhEzMEerx1/Tl1vP28bQLGbb0Cof1fBbD9jgJyAAEASQAAAgEFsAADAB0AsABFWLACLxuxAhw+WbAARViwAC8bsQAQPlkwMSEjEzMBBLv9uwWwAAEACv/mBEoFsAAPAC4AsABFWLAALxuxABw+WbAARViwBS8bsQUQPlmwCdCwBRCyDAEKK1gh2Bv0WTAxATMDBgQnJiY3MwYWFxY2NwOOvK8d/uzOwNIMuwtwcHuqEwWw+/nO9QQE4MR4jwIEooEAAQA7AAAFUAWwAAsAdACwAEVYsAUvG7EFHD5ZsABFWLAHLxuxBxw+WbAARViwAi8bsQIQPlmwAEVYsAsvG7ELED5ZsgACBRESOUARSgBaAGoAegCKAJoAqgC6AAhdsjkAAV2yBgUCERI5QBM2BkYGVgZmBnYGhgaWBqYGtgYJXTAxAQcDIxMzAwEzAQEjAiDVVLz9vHwC5vL9WwHF0QKjv/4cBbD9OwLF/XT83AAAAQA7AAADsQWwAAUAKACwAEVYsAQvG7EEHD5ZsABFWLACLxuxAhA+WbIAAQorWCHYG/RZMDElIQchEzMBEwKeHPym/b2dnQWwAAABADsAAAa3BbAADgBZALAARViwAC8bsQAcPlmwAEVYsAIvG7ECHD5ZsABFWLAELxuxBBA+WbAARViwCC8bsQgQPlmwAEVYsAwvG7EMED5ZsgEABBESObIHAAQREjmyCgAEERI5MDEBEwEzAyMTEwEjAQMDIxMCJf8CnPf9u2R3/WyQ/vxaYbz9BbD7XgSi+lACQAJK+3YEof2M/dMFsAAAAQA7AAAFdwWwAAkATLIBCgsREjkAsABFWLAFLxuxBRw+WbAARViwCC8bsQgcPlmwAEVYsAAvG7EAED5ZsABFWLADLxuxAxA+WbICBQAREjmyBwUAERI5MDEhIwEDIxMzARMzBHq2/fjEvf22AgnFuwRq+5YFsPuRBG8AAAIAd//nBQ0FyAASACIARrIXIyQREjmwFxCwCdAAsABFWLAKLxuxChw+WbAARViwAC8bsQAQPlmwChCyFgEKK1gh2Bv0WbAAELIeAQorWCHYG/RZMDEFLgInJhISNzYXFhIXFgICBwYBNiYnJgYCBwcGFhcWEhM2AlGLzXYGBkKidJ3J1fYJBDODZbABDgaWlIbThxIDBpiRvfkpFBQDgPmbeQFkAR5WdAQE/uH1af68/upepAOXxdkEBJj+0ehBxN4EBQEbAQB+AAACADsAAATzBbAACgATAE2yChQVERI5sAoQsAzQALAARViwAy8bsQMcPlmwAEVYsAEvG7EBED5ZsgsDARESObALL7IAAQorWCHYG/RZsAMQshIBCitYIdgb9FkwMQEDIxMFMhYHBgQjJQUyNjc2JiclAVpjvP0B5uH0ERL+1/P+wQFEmcQREIaA/qcCOv3GBbAB78bR8J4Bmol7mQQBAAIAb/8KBQQFyAAXACgARrIcKSoREjmwHBCwBNAAsABFWLAPLxuxDxw+WbAARViwBS8bsQUQPlmwDxCyGwEKK1gh2Bv0WbAFELIkAQorWCHYG/RZMDElFwcnBiMuAicmEhI3NhceAhcWBwcCAzYmJyYGAgcHBhYWFxYSNzYDi9mL/kpKidBzBgZBnnCgzo3QcgYDCgw+aQeYkobThxIDBD6HYrj7KhVM0XHzEAGD95x+AV0BGVZ6BAOC95xUU1X+UQJ9yNYEBJj+0ehBc8hoAwcBGP9/AAACADoAAATCBbAADgAXAGGyBRgZERI5sAUQsBbQALAARViwBC8bsQQcPlmwAEVYsAIvG7ECED5ZsABFWLANLxuxDRA+WbIQBAIREjmwEC+yAAEKK1gh2Bv0WbILAAQREjmwBBCyFgEKK1gh2Bv0WTAxASEDIxMFFhYHBgYHEwcjAQUyNjc2JiclAq3+sGa9/QG25fATC7GT4gHI/f8BFJDGEQ+Chf7dAk39swWwAQHmxonQNf2ZDQLqAZmAfY4EAQABACf/6QSjBccAKABhshMpKhESOQCwAEVYsAovG7EKHD5ZsABFWLAfLxuxHxA+WbICHwoREjmwChCwD9CwChCyEgEKK1gh2Bv0WbACELIYAQorWCHYG/RZsB8QsCTQsB8QsiYBCitYIdgb9FkwMQE2LwIkNz4CFx4CByc2JicmBgcGHwIEAw4CJy4CNxcGFgQ2A20WvK06/twTCpLxiITPbAa9CoyCibgOFMuVSwEaFQuQ946J43YHvAmfASK8AXegSj8ZhfF5umUDA3DJfgGGkwIChHKVTTUggv8Ae7NiAwFzyH8BgpkEggABAKgAAAUJBbAABwAuALAARViwBi8bsQYcPlmwAEVYsAIvG7ECED5ZsAYQsgABCitYIdgb9FmwBNAwMQEhAyMTITchBO3+O+G74f47HARFBRL67gUSngAAAQBn/+cFIAWwABIAPLIPExQREjkAsABFWLAKLxuxChw+WbAARViwEi8bsRIcPlmwAEVYsAQvG7EEED5Zsg4BCitYIdgb9FkwMQEDBgAnLgI3EzMDBhYXFjY3EwUgqCL+vOWP02QRqLmnEYqMmNEbqAWw/Cfj/vMEA3vfjgPa/CWZrwQGsaAD3AAAAQCkAAAFYQWwAAYAOLIABwgREjkAsABFWLABLxuxARw+WbAARViwBS8bsQUcPlmwAEVYsAMvG7EDED5ZsgABAxESOTAxAQEzASMBMwI+Ak/U/RCm/tnFAQEEr/pQBbAAAQDDAAAHQQWwABIAWQCwAEVYsAMvG7EDHD5ZsABFWLAILxuxCBw+WbAARViwES8bsREcPlmwAEVYsAovG7EKED5ZsABFWLAPLxuxDxA+WbIBAwoREjmyBgMKERI5sg0DChESOTAxAQc3ATMTFzcBMwEjAycHASMDMwG+BEQBs59zCj8BdMH9xqt+BCr+MKtytwHBsKwD8/wApskD3fpQBC1kdPvjBbAAAf/UAAAFKwWwAAsAawCwAEVYsAEvG7EBHD5ZsABFWLAKLxuxChw+WbAARViwBC8bsQQQPlmwAEVYsAcvG7EHED5ZsgABBBESOUAJhgCWAKYAtgAEXbIGAQQREjlACYkGmQapBrkGBF2yAwAGERI5sgkGABESOTAxAQEzAQEjAQEjAQEzApoBqej9yQFT0/7+/kroAkP+ttADgwIt/SX9KwI3/ckC5wLJAAABAKgAAAUyBbAACAAxALAARViwAS8bsQEcPlmwAEVYsAcvG7EHHD5ZsABFWLAELxuxBBA+WbIAAQQREjkwMQEBMwEDIxMBMwJjAe/g/XNdu2D+u8wC1gLa/GX96wIqA4YAAAH/6wAABM4FsAAJAEQAsABFWLAHLxuxBxw+WbAARViwAi8bsQIQPlmyAAEKK1gh2Bv0WbIEAAIREjmwBxCyBQEKK1gh2Bv0WbIJBQcREjkwMTchByE3ASE3IQfqAyIc+/sbA8b9DBwD2hqdnZoEeJ6XAAH///7IAqMGgAAHACIAsAQvsAcvsgABCitYIdgb9FmwBBCyAwEKK1gh2Bv0WTAxASMBMwchASECirn++7oY/pEBNAFwBej5eJgHuAABAL//gwKeBbAAAwATALACL7AARViwAC8bsQAcPlkwMRMzASO/pAE7owWw+dMAAf96/sgCHwaAAAcAJQCwAi+wAS+wAhCyBQEKK1gh2Bv0WbABELIGAQorWCHYG/RZMDETIQEhNzMBI68BcP7L/pAYuwEFvAaA+EiYBogAAQBPAtkDDwWwAAYAJ7IABwgREjkAsABFWLADLxuxAxw+WbAA0LIBBwMREjmwAS+wBdAwMQEBIwEzEyMCDP70sQGhfKOeBLn+IALX/SkAAf+B/2kDFgAAAAMAGwCwAEVYsAMvG7EDED5ZsgABCitYIdgb9FkwMQUhNyEC+/yGGwN6l5cAAQDPBNgCKwX+AAMAIwCwAS+yDwEBXbAA0BmwAC8YsAEQsALQsAIvtA8CHwICXTAxASMDMwIrj83NBNgBJgACADP/6APPBFEAIAArAHmyBCwtERI5sAQQsCLQALAARViwGC8bsRgYPlmwAEVYsAUvG7EFED5ZsABFWLAALxuxABA+WbIDGAUREjmyCxgFERI5sAsvsBgQshABCitYIdgb9FmyEwsYERI5sAUQsiEBCitYIdgb9FmwCxCyJgEKK1gh2Bv0WTAxISY1NwYnJiY3NiQzFzc2JicmBgcHPgIXFhYHAwcGFwclFjY3NyciBgcGFgK1BwOVp4+zCAoBGeW9DApfX12PELYJgsxtqbwPWAUCDgL+LFebOCeJq7YMCVkdHDmKBAKxhazBAVZhcQICX04BX5NRAgTFo/3oTTc2EYwCV03fAWxjTGUAAgAf/+gD/gYAABIAHgBkshwfIBESObAcELAE0ACwCS+wAEVYsA0vG7ENGD5ZsABFWLAELxuxBBA+WbAARViwBy8bsQcQPlmyBg0EERI5sgsNBBESObANELIWAQorWCHYG/RZsAQQshsBCitYIdgb9FkwMQEGAgYnJicHIwEzAzYXFhYXFgcnNiYnJgcDFhcWNjYD9RSOynvEXyWnAQu1bYK6nK4FAQeuA2hrqXVRPKVqn1ICGKb+9oADBI9+BgD9wpAEBN7DQDxUkpsEBK7+KaUEBIbxAAEARv/pA+YEUgAgAEuyACEiERI5ALAARViwES8bsREYPlmwAEVYsAgvG7EIED5ZsgABCitYIdgb9FmyBBEIERI5shQRCBESObARELIYAQorWCHYG/RZMDElFjY3Nw4CJy4CNzc+AhcWFhUnJiYnJgYHBwYXFhYB6GGcGKsPhcpqh7tYDgUTkOiMqsypAnJhjbsXAwYEB3aCAnVfAWaoXgMCifWZMpz2iQQE3KkBaoMEA9jCGkBEdYgAAAIAS//oBHUGAAARAB0AZLIEHh8REjmwBBCwGtAAsAcvsABFWLAELxuxBBg+WbAARViwDS8bsQ0QPlmwAEVYsAovG7EKED5ZsgYEDRESObILBA0REjmwDRCyFQEKK1gh2Bv0WbAEELIaAQorWCHYG/RZMDETNhI2FxYXEzMBIzcGJyYmJyYXBhYXFjcTJicmBgZTFI7QfbVhaLX+9qUTgLyWsgcDtgNsaJ16Vjyea6NVAh+lAQqEAwSAAjX6AHSMBATjvzsWj54CB6UB9JQEA4fzAAIARf/qA+AEUQAXAB8AabISICEREjmwEhCwGdAAsABFWLAILxuxCBg+WbAARViwAC8bsQAQPlmyHAgAERI5sBwvtL8czxwCXbIOAQorWCHYG/RZsAAQshIBCitYIdgb9FmyFAgAERI5sAgQshgBCitYIdgb9FkwMQUmAjc3NhI2FxYWFxYHByEGFhcWNxcGBgMmBgcFNzYmAfPK5BIFEZ3ig6e+CQMHC/09EoWEoIhoRNcRcKcxAg4EEHEUBAEi4iuhAQqHAwTWt0FBU5POBASUWGJvA80DnpwBEH6nAAEAdAAAA1AGGQAWAGOyBhcYERI5ALAARViwCS8bsQkePlmwAEVYsAMvG7EDGD5ZsABFWLASLxuxEhg+WbAARViwAC8bsQAQPlmwAxCyAQEKK1gh2Bv0WbAJELIOAQorWCHYG/RZsAEQsBTQsBXQMDEzEyM3Mzc2NzYXMhcHJiciBgcHMwcjA3ekpxmmEhpkaaMzThYwMV51DhDgGeCjA6uPgKNcYAIRlwoCdWFrj/xVAAACAAT+TwQoBFIAHQApAIOyCyorERI5sAsQsCbQALAARViwBC8bsQQYPlmwAEVYsAcvG7EHGD5ZsABFWLAMLxuxDBI+WbAARViwGC8bsRgQPlmyBgQYERI5shAYDBESObAMELISAQorWCHYG/RZshYEGBESObAYELIhAQorWCHYG/RZsAQQsiYBCitYIdgb9FkwMRM2EjYXFhc3MwMGBCcmJic3FhcWNjc3BicuAicmFwYWFxY3EyYnJgYHVBiPzXq8YCSmtB3+6sxuyTpnYqGBsx0UhLFllVIEArcDaWqidVU8nZO9EQIfsQEFfQMEinn73c/5BgJkV2+RBASYjGCEBANnw3g7FI+dBASjAfGUBgT40wABAB8AAAPjBgAAEgBJsgETFBESOQCwEi+wAEVYsAIvG7ECGD5ZsABFWLAPLxuxDxA+WbAARViwBy8bsQcQPlmyAAIPERI5sAIQsgwBCitYIdgb9FkwMQE2FxYWBwMjEzYnJicmBwMjATMBcY65mJMTdrV3BgURlKZ4hrUBC7UDtpsEAs25/TsCyDEqjAMEsvz8BgAAAgAvAAAB4wXHAAMADQAxALAARViwAi8bsQIYPlmwAEVYsAEvG7EBED5ZsAIQsArQsAovsgQFCitYIdgb9FkwMTMjEzMDNhYVDgImNjbjtLy0Jy49ATtePAI6BDoBiwI7MC88BDpePgAC/xT+RgHVBccADAAYADwAsABFWLAMLxuxDBg+WbAARViwBC8bsQQSPlmyCQEKK1gh2Bv0WbAMELAX0LAXL7IQBQorWCHYG/RZMDEBAwYGJyYnNxYXMjcTEzY2NzYWFQYGBwYmAZbNFKWFNUIQJS6BGs8fATkwLj0BPC8tPAQ6+0WZoAICEpQJApoEuwEcLz4CAj0uLzwCAjwAAQAgAAAEGgYAAAwAdQCwAEVYsAQvG7EEHj5ZsABFWLAILxuxCBg+WbAARViwAi8bsQIQPlmwAEVYsAsvG7ELED5ZsgAIAhESOUAVOgBKAFoAagB6AIoAmgCqALoAygAKXbIGCAIREjlAFTYGRgZWBmYGdgaGBpYGpga2BsYGCl0wMQEHAyMBMwM3ATMBASMBo45AtQELtaBvAYDr/g8BVsYB83/+jAYA/GpwAWD+M/2TAAEALwAAAe4GAAADAB0AsABFWLACLxuxAh4+WbAARViwAC8bsQAQPlkwMTMjATPjtAEKtQYAAAEAHgAABmoEUgAgAHeyFiEiERI5ALAARViwAy8bsQMYPlmwAEVYsAgvG7EIGD5ZsABFWLAALxuxABg+WbAARViwFy8bsRcQPlmwAEVYsA0vG7ENED5ZsABFWLAeLxuxHhA+WbIBHgMREjmyBgMXERI5sAMQshsBCitYIdgb9FmwEtAwMQEHNhcWFhc2FxYWBwMjEzYnJicmBgcDIxM2JicmBwMjEwGEF4jBZ48bmM+imhR3tHYGBhOfY6EXe7Z4DV1iqWSJtbwEO3mQBAJaUrIEBNKx/TkCyTQriAMCf2f9MQLIb3gCBJ786QQ6AAABAB8AAAPjBFIAEgBTsgITFBESOQCwAEVYsAMvG7EDGD5ZsABFWLAALxuxABg+WbAARViwEC8bsRAQPlmwAEVYsAgvG7EIED5ZsgEDEBESObADELINAQorWCHYG/RZMDEBBzYXFhYHAyMTNicmJyYHAyMTAYYakrqZkhN2tXcGBRGUo3uGtbwEO4mgBATMuf07AsgxKowDA7H8/AQ6AAIARf/oBB8EUgAQACIAQ7IXIyQREjmwFxCwCNAAsABFWLAALxuxABg+WbAARViwCS8bsQkQPlmyFgEKK1gh2Bv0WbAAELIfAQorWCHYG/RZMDEBHgIHBw4CJy4CNzYSNgMGFxYWFxY2Njc2JyYmJyYGBwJ4iMJdDwITlu6Oh8NaDQ+Y7+AHBwp5ZVqYaA8IBQx6ZYzEFwROApD9lhae/44EApD4lagBDJP9uD9EdowDA1/AdVw/eYwEA+K3AAAC/9f+YAP8BFIAEgAeAGeyBB8gERI5sAQQsB3QALAARViwDS8bsQ0YPlmwAEVYsAovG7EKGD5ZsABFWLAHLxuxBxI+WbAARViwBC8bsQQQPlmyCw0HERI5sA0QshcBCitYIdgb9FmwBBCyHAEKK1gh2Bv0WTAxAQYCBicmJwMjATcHNhcWFhcWByM3NCYnJgcDFhcWNgPzFIrMfLxkYbUBBKQUhrucrgUBBrUFb2mdcls9noe9Ahil/viDAwR7/fYF2gF5kAQE3sNAPFSSmwQEmf35kAQD2QACAEn+YAQoBFIAEAAcAGiyAB0eERI5sBrQALAARViwAC8bsQAYPlmwAEVYsAMvG7EDGD5ZsABFWLAFLxuxBRI+WbAARViwCS8bsQkQPlmyAgAJERI5sgcACRESObIVAQorWCHYG/RZsAAQshoBCitYIdgb9FkwMQEWFzczASMTBicmJicmEjY2AwcGFhcWNxMmJyYGAkm3YCGn/vy0YoKsmLYHBkaLvs8FA29omXZeQpaJvARPBH9u+iYCBHwEAuLAfAETzWb9uFSRoQIElgIUiwQD2AAAAQAfAAAC1ARUAAwARrIDDQ4REjkAsABFWLAKLxuxChg+WbAARViwBy8bsQcYPlmwAEVYsAQvG7EEED5ZsAoQsgEOCitYIdgb9FmyCAoBERI5MDEBJyIHAyMTNwc2FzIXAsBVrmSFtbyvG3OcITUDlQmd/P8EOgF+lwQPAAEALv/pA7YEUAAmAGOyFicoERI5ALAARViwCC8bsQgYPlmwAEVYsB0vG7EdED5ZsgMdCBESObILCB0REjmwCBCyDwEKK1gh2Bv0WbADELIVAQorWCHYG/RZsiAIHRESObAdELIkAQorWCHYG/RZMDEBNicnJjc2NhcWFgcnNiYnJgcGBwYXFxYWBw4CJyYmNxcUFjMWNgK9D4q87ggH96ekzQS0AmpYXkQ/Cg2AW7qcBgZ4yHGs4AS1dGVjkAElcC43Ur6PtwICu5YBUWYCAjAtSV4rGTCacmWWTwMCxZsBW24CVwAAAQBD/+0ClAVAABYAX7IWFxgREjkAsABFWLABLxuxARg+WbAARViwFC8bsRQYPlmwAEVYsA4vG7EOED5ZsAEQsADQsAAvsAEQsgMBCitYIdgb9FmwDhCyCQEKK1gh2Bv0WbADELAS0LAT0DAxAQMzByMDBhcWMzI3BwYjJiY3EyM3MxMB/S7FGcRxAwIHTiE3DkFDbGwMbr8Zvy4FQP76j/1fGhZOCpcSApuDAp6PAQYAAAEAW//oBB4EOgATAEyyARQVERI5ALAARViwBi8bsQYYPlmwAEVYsBAvG7EQGD5ZsABFWLACLxuxAhA+WbAARViwEy8bsRMQPlmwAhCyDQEKK1gh2Bv0WTAxJQYnJiY3EzMDBhcWFhcWNxMzAyMCzn/Em5UTdLV1BQMFTETCaoi1vKtrgwQE1rkCu/1CLCpIUgMGowMU+8YAAQBuAAAD7QQ6AAYAOLIABwgREjkAsABFWLABLxuxARg+WbAARViwBS8bsQUYPlmwAEVYsAMvG7EDED5ZsgAFAxESOTAxJQEzASMDMwGoAYa//d+K1LL9Az37xgQ6AAEAgAAABf4EOgAMAGCyBQ0OERI5ALAARViwAS8bsQEYPlmwAEVYsAgvG7EIGD5ZsABFWLALLxuxCxg+WbAARViwAy8bsQMQPlmwAEVYsAYvG7EGED5ZsgALAxESObIFCwMREjmyCgsDERI5MDEBATMBIwMBIwMzEwEzA+oBWbv+E5Nw/nqTda1CAYCSAQADOvvGAzL8zgQ6/NoDJgAAAf/EAAAD9AQ6AAsAUwCwAEVYsAEvG7EBGD5ZsABFWLAKLxuxChg+WbAARViwBC8bsQQQPlmwAEVYsAcvG7EHED5ZsgAKBBESObIGCgQREjmyAwAGERI5sgkGABESOTAxAQEzAQEjAwEjAQEzAfABJt7+TgEIxbP+z90Bv/8AxgKwAYr94P3mAZT+bAIsAg4AAf+l/kUD7AQ6AA8AP7IAEBEREjkAsABFWLAPLxuxDxg+WbAARViwBS8bsQUSPlmyAAUPERI5sA8QsAHQsAUQsgkBCitYIdgb9FkwMQEBMwECJyYnNxcWNjc3AzMBowGByP1+htIlSBAvVn0wQbu9AREDKfsS/vkDARGWBQRVX3wEIwAAAf/tAAADzgQ6AAkARACwAEVYsAcvG7EHGD5ZsABFWLACLxuxAhA+WbIAAQorWCHYG/RZsgQAAhESObAHELIFAQorWCHYG/RZsgkFBxESOTAxNyEHITcBITchB+oCYBv8vhkCxf3LHAMcGJeXkQMQmYwAAQA4/pMDFQY/AB0ALrIMHh8REjkAsAAvsA4vsgkADhESOXywCS8YsggDCitYIdgb9FmyFAgJERI5MDEBJiY3NzYnJic3Njc3EiUXBgMHBgcWFxYPAhcWFwHenpQTHAYFEZMQ2SAfOwFfG9QtIiGyZwoDBB8CAhGG/pM176zPMSqICJEK6+QBU2V1Rv718MheTY4sK/NHH581AAEAIf7yAcEFsAADABMAsAAvsABFWLACLxuxAhw+WTAxEyMBM7OSAQ6S/vIGvgAB/4z+kAJqBjsAHAAushkdHhESOQCwDi+wHC+yFhwOERI5fLAWLxiyFwMKK1gh2Bv0WbIFFxYREjkwMQc2Ezc2NyYnJj8CJic3FhYHBwYXFhcHBgcHAgV02SsfH8NxDQQFHwIDlS2ckBMbBgUQkw/aIBwz/pb7RwER4tBdRZMqLfZHuDpxNe+r0DIphwiRCu7P/p5oAAABAGkBjgTdAycAFwA4shEYGRESOQCwDy+wANCwDxCwFNCwFC+yAwEKK1gh2Bv0WbAPELIIAQorWCHYG/RZsAMQsAzQMDEBBgYnJicnJiMmDwI2NhcWFxcWMzI2NwTdDsOMfns8SEKILAicEMONd2xZRD9LaRIDCqPZAgNwOkMDpyUDotEEA11TPW5mAAL/8f6YAaEETwADAA4AJACwAy+wAEVYsAwvG7EMGD5ZsgcFCitYIdgb9FmwAdCwAS8wMRMzAyMBFAYGJjU2Njc2FrOlqb4BrzpgOwE7Ly49Aqz77AVPLz4EPi0wOwIBOgAAAQBS/wsD8wUmACIAUrIHIyQREjkAsABFWLASLxuxEhg+WbAARViwBy8bsQcQPlmyAAMKK1gh2Bv0WbAHELAD0LAHELAK0LASELAV0LAZ0LAVELIcAworWCHYG/RZMDElFjY3NwYGBwcjNyYmJyYSNjY3NzMHFhYVIzQmJyYCBwcGFgHpYZ0brBXRoC61L3eRDgwsebp3LbUtg5OqcGGYxg4BA3SCAnNhAYa9HunsHryNbwEL0oUV4uEgy5VqhAQG/wDkKo6dAAAB//MAAASJBcoAHwBrshEgIRESOQCwAEVYsBIvG7ESHD5ZsABFWLAFLxuxBRA+WbIdEgUREjmwHS+yAAEKK1gh2Bv0WbAFELIDAQorWCHYG/RZsAjQsAAQsAvQsB0QsA3QshUSBRESObASELIZAQorWCHYG/RZMDEBBwYHJQchNxc2NzcjNzM3NiQXFhYHJzYmJyYGBwchBwG4HBRYAssd/BUdQ3EdG6AbnB8ZARbAqMAIuwdiZW6aECABNhsCbtSZZwOdnAIp3c6d/cz2BgTRsQFqegQEpIH7nQAAAgAS/+UFjQTxAB0ALQA/sisuLxESObArELAQ0ACwAEVYsAIvG7ECED5ZsBHQsBEvsAIQsiIBCitYIdgb9FmwERCyKgEKK1gh2Bv0WTAxJQYnJicHJzcmJyYSNyc3FzYXFhc3FwcWFxYCBxcHAQYWFhcWNjY3NiYmJyYGBgPku77HiJ1tnx4KE1lodY1ys7a8ia9vrSAMElFjc4/84g9Kn2x115EQDkmebHbYkG6GBAR+iJCGVVeWASF1nX+UegQCd5iSk1dZkP7meJZ/AnJy0HsEBH7ee3POeQQEftwAAQBTAAAFJAWwABYAawCwAEVYsBYvG7EWHD5ZsABFWLABLxuxARw+WbAARViwDC8bsQwQPlmyDxMDK7IADBYREjm0DxMfEwJdsBMQsAPQsBMQshICCitYIdgb9FmwBtCwDxCwB9CwDxCyDgIKK1gh2Bv0WbAK0DAxAQEzASEHIQchByEDIxMhNyE3ITchATMCbgHV4f3uASkW/owdAXUW/ow5vDj+kRYBbh3+kRYBNv7nywMPAqH9MH2lfP6+AUJ8pX0C0AAAAv/3/vIB2QWwAAMABwAYALAAL7AARViwBi8bsQYcPlmyBQEDKzAxAxMzAxMjEzMJiraKqLaEtv7yAxf86QPIAvYAAv/d/g4EoQXGADEAPwBzALAHL7AARViwIi8bsSIcPlmyFQciERI5sBUQsjoBCitYIdgb9FmyAhU6ERI5sAcQsAvQsAcQsg8BCitYIdgb9FmyLiIHERI5sC4QsjMBCitYIdgb9FmyGzMuERI5sCIQsCbQsCIQsikBCitYIdgb9FkwMQEGBxYHBgQnJiY3NwYWFhcWNjY3NiYkJyY3NjcmNzY2NzYXFhYHIzYmJyYGBwYWBBcEJScGBwYXFgQXNjc2JicEPxLTZw0O/uDe2fILtQY/glhTlFwJDGv+61DyFA7SYw0Ihnd7jc/hDLQIhHyHtw8LYAEPRwEN/hSapxYOSzIBAkGuFgtfdwG3v2Bnqa7MAgTmxwFVfkUBAjZjRU1vWSZz7LhnaqZsrS8wAgTlxn6WBAJ1aVFtVB90BzQvl2Q9KVEZNJNJcCoAAgDbBO4DUgXHAAsAFwAdALAJL7IDBQorWCHYG/RZsA/QsAkQsBXQsBUvMDETNjY3NhYHFAYHBiYlNjY3NhYHFAYHBibbATovLz0BPC8vOwGhATovMDwBPC8uPQVZLj0CATsvLjwCATotLj4CATswLzsCAToAAAMAYv/qBe0FyAAbACkAOgCCALAARViwLi8bsS4cPlmwAEVYsDcvG7E3ED5ZsgM3LhESObADL7QPAx8DAl2yCi43ERI5sAovtAAKEAoCXbIOCgMREjmyEQIKK1gh2Bv0WbADELIZAgorWCHYG/RZshsDChESObA3ELIfBAorWCHYG/RZsC4QsiYECitYIdgb9FkwMQEGBicmJjc3NjYXFhYHJzYmJyYGBhcXFhYXFjcFFgAXFiQSJyYAJyYEAgc2EiQXFgQSBwYCBCcjJiQCBEUOupWRoA4KFM+djpsGjwZFWl9/HQECB09EqiP9LRYBBL67AU23FBb/AMG9/rO2WxbkAV7CsgEcjhUX5P6ovAq3/uiOAlWXpwQE2KdivdsCBKOUAVViAgKR/x4jTVoDB78az/75AgTfAX2+zQECBQTg/ogmxwFkywQCxP6lxMv+nsgBBMQBWwAAAgDDArMDTgXHAB0AJwBgALAARViwFi8bsRYcPlmyAygWERI5sAMvsADQsAAvsgkDFhESObAJL7AWELIPAworWCHYG/RZshIJFhESOXywEi8YsAMQsh4DCitYIdgb9FmwCRCyIQQKK1gh2Bv0WTAxAScGIyImNzY2Mxc3NicmJyYGByc2NhcWFgcDBwYXJTI3NyMGBgcGFgJ2BFxyaXgEBbqnbwkDAgdVOFcPnAuwg3uFCjYEAQj+u0tbHF1YaAgFNgK/SlZ7YXN8ATYbGE8DATE4C21/AgSVfP6lOi0uekSPA0A3Ky4A//8AWQCXA44DswAmAXr6/gAHAXoBOv/+AAEAgQF3A8UDIAAFABoAsAQvsAHQsAEvsAQQsgIBCitYIdgb9FkwMQEjEyE3IQN7ti/9jR0DJwF3AQihAAQAYf/mBe0FyAAPAB8AOQBCAIQAsABFWLAELxuxBBw+WbAARViwDC8bsQwQPlmyFAQKK1gh2Bv0WbAEELIcBAorWCHYG/RZsiEMBBESObAhL7IjBAwREjmwIy+0ACMQIwJdsjohIxESObA6L7IgAgorWCHYG/RZsiogOhESObAhELAy0LAyL7AjELJCAgorWCHYG/RZMDETNhIkFxYEEgcGAgQnJiQCNx4CFxYkEicuAicmBAIFAyMTBRYWBwYGBxYXBwYXFwcjJj8CNiYnJxc2Njc2JicjdhbkAV7CrwEbkxYX5v6lwLP+6JOEDIHNfrsBSroTDoHLfrn+tr0BvTWKhQEBi5UHA0RRTQkBCwIDAooGAgcGBzBElI9IZQkKQVmMAtLHAWTLBAK//qXJzP6dygQEvwFeLoPcdgME3AF8w4XYdAME1v6Db/6uA1EBBYFyOmAuLGE9Vx9AESUkSDZCRQSBAQJFOj8+AwABAOMFIQOwBbAAAwARALABL7ICAworWCHYG/RZMDEBITchA5n9ShcCtgUhjwAAAgDoA70C2AXHAAsAFwAvALAARViwAy8bsQMcPlmwD9CwDy+yCQIKK1gh2Bv0WbADELIVAgorWCHYG/RZMDETNjYXFhYHBgYnJiY3BhYzMjY3NiYjIgbsBKFnYX8CBJ9mYoN9Bj0xNlUGBjg0NlcEt2+hAgKVZXCcAgKRZzFJUDgwT1UAAgAlAAAD/wTzAAsADwBGALAJL7AARViwDS8bsQ0QPlmwCRCwANCwCRCyBgEKK1gh2Bv0WbAD0LANELIOAQorWCHYG/RZsgUOBhESObQLBRsFAl0wMQEhByEDIxMhNyETMxMhNyECngFhGP6gQaRB/ooZAXVBo3H81RgDKwNWl/5iAZ6XAZ37DZgAAQBcApsC5gW/ABcATgCwAEVYsA8vG7EPHD5ZsABFWLAALxuxABQ+WbIXAgorWCHYG/RZsALQsgMXDxESObAPELIIAgorWCHYG/RZsgsPABESObIUFw8REjkwMQEhNwE2NzYmJyYGBwc2NhcWFgcGDwIhAqL9uhQBY2MMBzUwQlAOmguugHiLBQiXQMQBewKbdAEqVEowNgEBSz4BdZUCAn5me30zkQAAAQBuAo0C6wW8ACQAcQCwAEVYsA0vG7ENHD5ZsABFWLAXLxuxFxQ+WbIAFw0REjl8sAAvGLbQAOAA8AADXbANELIHAgorWCHYG/RZsgkADRESObAAELIjBAorWCHYG/RZshIjABESObIbFw0REjmwFxCyHgIKK1gh2Bv0WTAxARc2Njc2JiMiByM2NjMWFgcGBxYHBgYnJiY1MxQWMzI2NzYnJwFXTkJdBwY+MnAdnAuffX6OBQeYdgQFtYV3lZdCOkBbBw2NVwRlAQI9NjExXWV5A3Zhd0IrgW+BAgJ8bDI3QDVmBQEAAAEA1QTYAqUF/gADACMAsAIvsg8CAV2wANCwAC+0DwAfAAJdsAIQsAPQGbADLxgwMQEzASMBv+b+zp4F/v7aAAAB/+X+YAQlBDoAEwBZsg0UFRESOQCwAEVYsAAvG7EAGD5ZsABFWLAILxuxCBg+WbAARViwES8bsRESPlmwAEVYsA4vG7EOED5ZsABFWLALLxuxCxA+WbAOELIFAQorWCHYG/RZMDEBAwYXFhcWNxMzAyM3BiciJwMjAQGeZwoDCpK3YYu2vKITb6KHUFm0AQQEOv2QVDq3AwadAyH7xnOKAkv+KgXaAAABAHsAAAPGBbEACwAksgAMDRESOQCwAEVYsAovG7EKHD5ZsABFWLAALxuxABA+WTAxIRMnJiY3PgIzBQMCFFtA0+EUDpTwkAEV/AIIAQP/yY7adQH6UAAAAQClAmgBhQNMAAsADwCwAy+xCQorWNgb3FkwMRM2Njc2FhUGBgcGJqUBPTIwQAFAMS1BAtYxQQICPjIxPwICOwAAAf/I/ksBEwAAAA0AOQCwAEVYsAYvG7EGEj5ZsABFWLANLxuxDRA+WbIBDQYREjmwBhCyBwYKK1gh2Bv0WbIMBgEREjkwMTMHFgcGBgc3Njc2Jyc3pxWBBAOulgSmEAxoLi43HYZmcgNsBmVHDAaFAAEA3wKiAnAFtwAGAECyAQcIERI5ALAARViwBS8bsQUcPlmwAEVYsAAvG7EAFD5ZsgQABRESObAEL7IDAgorWCHYG/RZsgIDBRESOTAxASMTBzclMwHtmmjcGAFkFQKiAlU4h3EAAAIAwAKtA3sFyQANABsAMwCwAEVYsAAvG7EAHD5ZsgccABESObAHL7IRAworWCHYG/RZsAAQshgDCitYIdgb9FkwMQEWFgcHBgYnJiY3NzY2AwYWFxY2Nzc2JicmBgcCTY2hDQcR0ZaOoQ0HEdNLCkhNT3APCQhKSFJwDgXFBMWZR6bJBATIlkaoyP5IYHMCA3JoUWZtAgJ0ZP//AA8AmANWA7UAJgF7DQAABwF7AV8AAP//ALkAAAUzBa0AJwHVAE4CmAAnAXwBEQAIAQcB2ALAAAAAEACwAEVYsAUvG7EFHD5ZMDH//wC0AAAFeQWtACcBfADmAAgAJwHVAEkCmAEHAdYDBgAAABAAsABFWLAJLxuxCRw+WTAx//8AngAABYwFvQAnAXwBjAAIACcB2AMZAAABBwHXAKMCmwAQALAARViwIC8bsSAcPlkwMQAC/9P+egL2BE8AGAAkAEYAsBAvsABFWLAiLxuxIhg+WbIcBQorWCHYG/RZsADQsAAvsgMQABESObAQELIJAQorWCHYG/RZsBAQsAzQshYAEBESOTAxAQYGBwcGBwYWFxY2NzcGBicmJjc2Nzc2NxMUBgcGJjU2Njc2FgJIDFNpYXcNDV5dYoUStBP0sa2+Dw+/dFsZ9jsvMDsBPC4uPQKpbaFkW3NzYnQCAnFeAafLBATKprevZlWVAUAvPgICPi0vOwIBOQAC/4QAAAd4BbAADwASAHcAsABFWLAGLxuxBhw+WbAARViwAC8bsQAQPlmwAEVYsAQvG7EEED5ZshEGABESObARL7ICAQorWCHYG/RZsAYQsggBCitYIdgb9FmyCwAGERI5sAsvsgwBCitYIdgb9FmwABCyDgEKK1gh2Bv0WbISBgAREjkwMSEhEyEBIwEhByEDIQchAyEBIRMGt/ynL/3k/vvoBFIDohv9Yj8CPhv9yUcCrfseAbRgAWH+nwWwmP4pl/3tAXgC0gAAAQAoAM4EAgRjAAsAOACwAy+yCQwDERI5sAkvsgoJAxESObIEAwkREjmyAQoEERI5sAMQsAXQsgcEChESObAJELAL0DAxEwEBNwEBFwEBBwEBKAF7/vuAAQYBeWX+iAEGgP75/oUBUgFPAVBy/rIBToP+sP6wcgFQ/rAAAAMAIP+kBZwF6wAZACMALQBmsgwuLxESObAMELAg0LAMELAp0ACwAEVYsA0vG7ENHD5ZsABFWLAALxuxABA+WbIcDQAREjmyJg0AERI5sCYQsB3QsA0Qsh8BCitYIdgb9FmwHBCwJ9CwABCyKQEKK1gh2Bv0WTAxBSYnByM3Jjc2EhI2NhcWFzczAxYXFgICBwYBFhcBJicmAgcGATYnARYXFhITNgJOpnV8l71qBQExd7Lif86Bg5bQMQoOVuKfcP5gAh8Cxk2ctvwsIgMpBAv9TUpyv/0oFhUEUJvoq+ZhASwBA7lhAwR6pf8AdHqp/kT+wUIvAf9sUwOMaAUF/uz0wAFHTk78ijoEBQEmAQ6TAAACADgAAARiBbAADQAWAFqyEBcYERI5sBAQsAnQALAARViwAC8bsQAcPlmwAEVYsAsvG7ELED5ZsgEACxESObABL7IKCwAREjmwCi+wARCyDgEKK1gh2Bv0WbAKELIPAQorWCHYG/RZMDEBAxcWFgcOAiMlAyMTEwMFMjY3NiYnAesz7tDsDwuN7pH+6Te2/WlfAQGLwhEOgXYFsP7bAQHjvILFawH+xwWw/kP93gGZf3iOBAABAB7/5wQZBhUALABbsiAtLhESOQCwAEVYsAYvG7EGHj5ZsABFWLAULxuxFBA+WbAARViwAC8bsQAQPlmyCwYUERI5sBQQshkBCitYIdgb9FmyHxQGERI5sAYQsikBCitYIdgb9FkwMTMjEz4CFxYWBwYGBwYeAgcGBicmJzcWFzI2NzYuAjc+Azc2JicmBgfTtb4Sdrp5n64NCaIMCTaSOgMK6K2ycjtqcWWLCwc3kz0GBThBOQgKTFFpiBUEV4bOagIEspRf9Ew3bJRxPKS7BAJJmUsCY1Y5a5Z3PzthW186UmwEA5eRAAADABP/6AZhBFIALAA3AEEAx7ICQkMREjmwAhCwMdCwAhCwO9AAsABFWLAcLxuxHBg+WbAARViwAC8bsQAQPlmwAEVYsAUvG7EFED5ZsgMcABESObILHAAREjmwCy+0vwvPCwJdsBwQsjgBCitYIdgb9FmwENCyEwscERI5sBwQsBfQshocABESObI8HAAREjmwPC+0vzzPPAJdsiEBCitYIdgb9FmwABCyJwEKK1gh2Bv0WbIqHAAREjmwBRCyLQEKK1gh2Bv0WbALELIyAQorWCHYG/RZMDEFJiYnBiUmJjc2NjMXNzYmJyYGByc2NhcWFhc2Fx4CBwchBhcWFhcWNjcXBiUWNjc3JyIGBwYWASYGByE3NicmJgRwebkzqf7skqkKCv7Z4gwMVlpokA+zEPy6baMiosJ/rkoREv1CCQkNgWhanUo1ivwVRp9CK8t4pgwJWgO7bqo1AgoGCQcLZhQCXVW4BAKtjaC0AVZoeQQCa1YTl7ACAldNqQQCft2KdkRAa30BAjwviXiVAkk57gFxW0pXAzUDnZ4gNzJQXAAAAgBc/+gEVAYrABwAKABQshYpKhESObAWELAm0ACwDi+wAEVYsBgvG7EYHj5ZsABFWLAHLxuxBxA+WbIQDgcREjmwDhCyHwEKK1gh2Bv0WbAHELIlAQorWCHYG/RZMDEBEgMHBgIGJyYCNz4CFxYXJicHJzcmJzcWFzcXAyYnJgYHBhYXFjY3A56xMg0YneGCvOATDorehJpvBGrvO89mskbcltE65ziqkMQTD4Bwf7YfBRP+2f6NW6f+9oUDBAETyZDziAQEb7aZlGx+VjSdOIiCbf03fgUEy6mLuwMF28AAAAMARACpBC4EvQADAA4AGQA7ALACL7IBDgorWCHYG/RZsAIQsQ0KK1jYG9xZsQcKK1jYG9xZsAEQsRIKK1jYG9xZsRgKK1jYG9xZMDEBITchATQ2NzYWFQ4CJgM2Njc2FhUOAiYEDvw2IQPJ/eg9MjBAAT9iPo0BPTIwQAFAYj0CWLgBNzFBAgI+MjE+BDz9ADFBAgI+MjE+BD0AAAMAOf96BCoEuAAZACEAKwBmsgwsLRESObAMELAf0LAMELAo0ACwAEVYsAAvG7EAGD5ZsABFWLANLxuxDRA+WbIcAA0REjmyJAANERI5sCQQsB3QsAAQsh8BCitYIdgb9FmwHBCwJdCwDRCyJwEKK1gh2Bv0WTAxARYXNxcHFhcWBwYCBicmJwcnNyYnJjc3EgADBhcBJicmAiUmJwEWFxY2NzYCfmdbZoSQbgcCCBOf8I5ZXWaEjXYHAgYCJAE2sAozAcs3QJ3RAlcDH/44MjmMyR8NBFACK5UBz4LGN1ac/vmIAgIjlQHNfM09PBABBwEz/WuEWwK6HQIE/u0TSkX9TBcCA9y7XwAAAv/g/mAEBAYAABEAHQBdsgQeHxESObAEELAc0ACwCS+wAEVYsA0vG7ENGD5ZsABFWLAHLxuxBxI+WbAARViwBC8bsQQQPlmyCw0HERI5sA0QshYBCitYIdgb9FmwBBCyGwEKK1gh2Bv0WTAxAQYCBicmJwMjATMDNhcWFhcWBzc0JicmBwMWFxY2A/wUjMt8umVhtQFTtGqDtZ6tAwG6BXBooHBaPZ2JvQIYpv72gQMEfP32B6D9yYkEBOS9PT5UkZwCBJj9+Y8FA9sAAgA1AAAFwQWwABMAFwBrALAARViwDy8bsQ8cPlmwAEVYsAgvG7EIED5ZshQIDxESObAUL7IQFA8REjmwEC+wANCwEBCyFwEKK1gh2Bv0WbAD0LAIELAF0LAUELIHAQorWCHYG/RZsBcQsArQsBAQsA3QsA8QsBLQMDEBMwcjAyMTIQMjEyM3MxMzAyETMwEhNyEFPoMZgrK8df06db2yghmCMr0zAsYzvPwRAsUj/ToEjo78AAKh/V8EAI4BIv7eASL9jsIAAQAuAAABnwQ6AAMAHQCwAEVYsAIvG7ECGD5ZsABFWLABLxuxARA+WTAxMyMTM+O1vLUEOgAAAQAtAAAEVwQ6AAwAaACwAEVYsAQvG7EEGD5ZsABFWLAILxuxCBg+WbAARViwAi8bsQIQPlmwAEVYsAsvG7ELED5ZsAIQsAbQsAYvsp8GAV20vwbPBgJdsi8GAV2y/wYBXbIBAQorWCHYG/RZsgoBBhESOTAxASMDIxMzAzMBMwEBIwGhblC2vLZRUAHR6P3lAXTUAc3+MwQ6/jYByv3q/dwAAQAiAAADsAWwAA0AWwCwAEVYsAwvG7EMHD5ZsABFWLAGLxuxBhA+WbIBDAYREjmwAS+wANCwARCyAgEKK1gh2Bv0WbAD0LAGELIEAQorWCHYG/RZsAMQsAjQsAnQsAAQsAvQsArQMDEBJQcFAyEHIRMHNzcTMwGKAQ4Y/vNhAp4c/KZyihiJdL0DT1OEU/3SnQKNKYQpAp8AAAEAIwAAAjYGAAALAEoAsABFWLAKLxuxCh4+WbAARViwBC8bsQQQPlmyAQQKERI5sAEvsADQsAEQsgIBCitYIdgb9FmwA9CwBtCwB9CwABCwCdCwCNAwMQE3BwcDIxMHNzcTMwGRpRijgbZ1lheVgLUDajyDPf0aAp42gzcC3gAAAQA1/kUFYQWwABMAWrIGFBUREjkAsABFWLAALxuxABw+WbAARViwEC8bsRAcPlmwAEVYsAQvG7EEEj5ZsABFWLAOLxuxDhA+WbAEELIJAQorWCHYG/RZsg0OEBESObISDgAREjkwMQEBBgYnIic3FjMyNzcBAyMTMwETBWH++RnBlzVDHjgphCUR/gzGu/y1AfjFBbD5/ay8BBSZEb1eBHL7jgWw+5AEcAABACT+RwPyBFIAGwBaALAARViwAC8bsQAYPlmwAEVYsAMvG7EDGD5ZsABFWLAKLxuxChI+WbAARViwGS8bsRkQPlmyARkDERI5sAoQsg8BCitYIdgb9FmwAxCyFgEKK1gh2Bv0WTAxAQc2FxYWBwMGBiciJzcWMzI3EzYnJicmBwMjEwGBFoy/o5kVfRa/ljVDHzUujCB8BgMOpJ9xjra8BDubsgQE4738/aa6AhScEMUC+TYwoAUEifzTBDoAAgBU/+0HZQXHABYAJACRshUlJhESObAVELAa0ACwAEVYsAsvG7ELHD5ZsABFWLANLxuxDRw+WbAARViwAC8bsQAQPlmwAEVYsAMvG7EDED5ZsA0Qsg8BCitYIdgb9FmyEg0AERI5sBIvshMBCitYIdgb9FmwABCyFQEKK1gh2Bv0WbADELIXAQorWCHYG/RZsAsQshwBCitYIdgb9FkwMSEhBwcmJgI3ExIAHwIhByEDIQchAyEFFjcTJiMmBgcDBhcWFgZy/NTZRZjbYRUvKwFZ80rTAzkc/UNRAmQc/Z1aAsj7oEyK0Wxfr+whLwoHCo4SAQSeARKfASsBEgFKAgITnv4snf38GAMNBJARAvPU/tROToOXAAMAR//mBuIEUwAiADMAPQChshk+PxESObAZELAt0LAZELA30ACwAEVYsAUvG7EFGD5ZsABFWLAALxuxABg+WbAARViwGy8bsRsQPlmwAEVYsBYvG7EWED5ZsgMFFhESObI4BRYREjmwOC+yCgEKK1gh2Bv0WbAWELIQAQorWCHYG/RZshIFFhESObIZBRYREjmwGxCyKAEKK1gh2Bv0WbAFELIwAQorWCHYG/RZsDTQMDEBFhYXNhceAgcHIQYXFhYXFjcXBgYnJiYnBicuAjc3EgADBhcWFhcWNj8CNCYnJgYHASYGBwU3NicmJgJ+eb4rstl9sEoRE/1MCAYKdWCskD1EyHN8vSyr9IW8VRACJAEtnQcEBXNliMMaAgVzbYzBFwRSZaU3Af4FCAcNZwROAnRj3QMCftyIej1AbIEDBm9/QUICAnFf2QYCjvmVEAEFATT9tz5EdY8DBdy7FlePpAQF57UBlwOalwEcNTFPWwABADMAAAMKBhoADQArALAARViwBC8bsQQePlmwAEVYsA0vG7ENED5ZsAQQsgkBCitYIdgb9FkwMTMTNjYXMhcHJiciBgcDM8sWxp4vYyEsLFd1Ec0Eq6vEAhaPDAJvZvtUAAIAUf/pBSoFxgAaACQAUQCwAEVYsBIvG7ESHD5ZsABFWLAALxuxABA+WbIFABIREjmwBS+wEhCyDAEKK1gh2Bv0WbAAELIbAQorWCHYG/RZsAUQsh8BCitYIdgb9FkwMQUmJgI3NwU3NicmJicmByc2NhcWBBIHBwYCBCcWNjcFBwYXFhYCT67tYxoUA9ADFQkPvZimyiNE1IG4AQFxGg4fzv7fnaX7R/zoBw8KEKQUAqgBL758AwxjYJy5AwNWkS82AwKz/r7GY8j+uKqgBfXyASNZUIGRAAH/Sf5GAy8GGgAdAHGyEh4fERI5ALAARViwFC8bsRQePlmwAEVYsA8vG7EPGD5ZsABFWLAcLxuxHBg+WbAARViwBS8bsQUSPlmwHBCyAAEKK1gh2Bv0WbAFELIKAQorWCHYG/RZsAAQsA3QsA7QsBQQshkBCitYIdgb9FkwMQEjAwYGJyYnNxYzMjcTIzczNzY2FzIXByYjIgcHMwKDxJ0Uu5c1Phw1KoggnaYWpg4VxpgzXB03KLQdDcUDq/v8p7oCAhOSEM4D/o9xr8ACFZUM3WMAAgBn/+kGGwY3ABgAKABOALAARViwCi8bsQocPlmwAEVYsAAvG7EAED5ZsgwAChESObAML7ISAgorWCHYG/RZsAoQshwBCitYIdgb9FmwABCyJAEKK1gh2Bv0WTAxBS4CJyY3NhIkFxYXNjY3NwIFFhcWAgIEATYmJyYCAwYHBhYXFhI3NgJAi9BzBgUbIsUBFaflhmRzE6Ej/uQaBQZNuf7wAVQGlZW+/iYTAQaWlMT8IhIUA4P1nG2nzwFBoAMEmQqFgAH+tkJpaZj+cf7XoAOWxNgEBf7Z/v5/SL/jBAUBL/6DAAACAEL/5wT/BLAAFgAlAE4AsABFWLAALxuxABg+WbAARViwDy8bsQ8QPlmyAg8AERI5sAIvsgkCCitYIdgb9FmwDxCyGgEKK1gh2Bv0WbAAELIiAQorWCHYG/RZMDEBFhc2NjczBgYHFhcWAgQnLgI3NzYAAxQWFxY2NzYnJiYnJgYGAoLEeUtSE5AQeXYSBAqO/vSliL9YEAMiATSoeG6NyRsHBAl2Zm6uWwRPBIkOY32UpCBLS8f+qb0EBI74lRX+ATb9YIyhBAXjyT9FeY0EBI/4AAEAZ//oBpoGAgAaAEYAsABFWLASLxuxEhw+WbAARViwDS8bsQ0QPlmwEhCwGtCyAQ0aERI5sAEvsggCCitYIdgb9FmwDRCyFgEKK1gh2Bv0WTAxAQc2Njc3BgYHAw4CJyYCNxMzAwYWFxY2NxMFJh5vdxOZF9LAcBaf/5ja9BqouacRi4yV0ByrBbDZDoyQAc7WC/2DlOF5AwQBD9gD2vwlm64EBKqdA+UAAQBa/+gFTgSRABsAUwCwAEVYsA0vG7ENGD5ZsABFWLAFLxuxBRA+WbAARViwCC8bsQgQPlmwDRCwFtCyGBYIERI5sBgvsgMCCitYIdgb9FmwCBCyEwEKK1gh2Bv0WTAxAQYGBwMjNwYnJiY3EzMDBhcWFhcWNxMzBzY2NwVODqKllqsXfcWclxV0tXUFAwVMRMFriLQYW1cUBJGongb8u2uDBATYtwK7/UIsKkhSAwilAxSGB1SBAAH/Cf5GAa8EOgAMACgAsABFWLAMLxuxDBg+WbAARViwBC8bsQQSPlmyCQEKK1gh2Bv0WTAxAQMGBicmJzcWMzI3EwGvxha+mDY+HjUqiiTGBDr7bqa8AgITkhDTBIgAAAIAPv/pA98ETgAYACIAUQCwAEVYsAAvG7EAGD5ZsABFWLAJLxuxCRA+WbIOAAkREjmwDi+wABCyEwEKK1gh2Bv0WbAJELIZAQorWCHYG/RZsA4QshwBCitYIdgb9FkwMQEeAgcHBgIGJyYCNzchNicmJicmByc2NwMWNjclBwYXFhYCR4a8Vg8EEZXlgsHAGhICswgGCnRgqZM9e9NOZKU3/gMGCAgLaQROAoz2lSSW/v+RBAYBCNR5PUBtgQMGb353C/w2A5qXARw1MU5eAAABARcE4gNkBgAACAAxALAFL7AB0LABL7EACitY2BvcWbAFELAH0LAHL7QPBx8HAl2wA9CwABCwBtCwBi8wMQEVJycHBzUBMwNkk3GwmQEWagTwDgKpqAMQAQ4AAAEBJgTjA4AGAQAIACAAsAQvsALQsAIvtA8CHwICXbIABAIREjmwB9CwBy8wMQE3NxcBIwM1FwIvsZ8B/uJuzpYFVqgDDf7vARAOAv//AOMFIQOwBbAABgBwAAAAAQEHBMcDTAXYAAwAIgCwAy+yDwMBXbIJBAorWCHYG/RZsAfQsAcvsADQsAAvMDEBBgYnJiY3FwYXFjY3A0wMq4B7kwKTB4FHUgwF132TBAKSeQGSBAFVQQAAAQEOBOsB4wXFAAsAEQCwCS+yAwUKK1gh2Bv0WTAxATQ2NzYWFQYGBwYmAQ46MC49ATsvLD4FVC8+AgI7MC88AgI5AAACAQEEswKkBlEACwAXACUAsAkvsBXQsBUvsgMICitYIdgb9FmwCRCyDwgKK1gh2Bv0WTAxATY2MzIWFQYGIyImNwYWMzI2NzYmIyIGAQMCgVlScwKBWVRzYgQ2Ky5PBgY4Ki5QBXhbfnRVWXxyVS4/RzIuQkkAAf+v/k8BFgA5AA8AJwCwEC+wAEVYsAovG7EKEj5ZsgUDCitYIdgb9FmwEBCwD9CwDy8wMQUHBgcGFxY3FwYjIiY3NiUBFkF6CQdBIEMERFNOXwIDARYDL1pZPwIBGnkrZVKxggAAAQDdBNoDrgXnABUAPgCwAy+wCNCwCC+0DwgfCAJdsAMQsArQsAovsAgQsg4DCitYIdgb9FmwAxCyEwMKK1gh2Bv0WbAOELAV0DAxAQYGIyIuAgcGByc2NhcyHgI3MjcDrgx6XSU9PD4kVR96DH1dGy9qMRtWIAXdb4YfJh4BA20HbowCEUESAXEAAgDCBNADvgX/AAMABwA7ALACL7AA0LAAL7QPAB8AAl2wAhCwA9AZsAMvGLAAELAF0LAFL7ACELAG0LAGL7ADELAH0BmwBy8YMDEBMwEjAzMBIwLm2P7GszTN/vefBf/+0QEv/tEAAv/p/moBNf+2AAsAFwA5ALAYL7AD0LADL0ALAAMQAyADMANAAwVdsA/QsA8vsgkHCitYIdgb9FmwAxCyFQcKK1gh2Bv0WTAxBzQ2MzIWFRQGIyImNwYWMzI2NzYmIyIGF2hGRFpjRkVeVAQoIB87BwQmHiU6+UlmX0NHY1lGHy8xJyEwOQAB/WoE2P6/Bf4AAwAeALABL7AA0BmwAC8YsAEQsALQsAIvtA8CHwICXTAxASMDM/6/jsfMBNgBJgAAAf3rBNj/wgX+AAMAHgCwAi+wAdCwAS+0DwEfAQJdsAIQsAPQGbADLxgwMQEXASP+2en+yJ8F/gH+2wD///0LBNr/3AXnAAcApPwuAAAAAf31BNj/NgZzAA0AJQCwDS+wB9CwBy+yDA0HERI5sgEHDBESObIGBgorWCHYG/RZMDEBNzc2NzYjNxYWBwYHB/31FilrCgubD4KMAweiDATZmQQKQkdqA2BRgh1IAAL82wTk/4YF7gADAAcANwCwAS+wANAZsAAvGLABELAF0LAFL7AG0LAGL7YPBh8GLwYDXbAD0LADL7AAELAE0BmwBC8YMDEBIwMzASMDM/6KtPvqAcGfwdYE5AEK/vYBCgAAAfy7/p/9kP95AAsAEQCwAy+yCQUKK1gh2Bv0WTAxBTY2NzYWFQYGBwYm/LsBOi8uPQE7Lyw++C8+AgI7MC88AgI5AAABASEE7gJBBj8AAwAdALACL7AA0LAAL7IPAAFdsgMCABESORmwAy8YMDEBMwMjAZGwrHQGP/6vAAMA8wTtA+4GiAADAA4AGQA6ALAML7AC0LACL7AA0LAAL7ACELAD0BmwAy8YsAwQsgYFCitYIdgb9FmwDBCwFdCwFS+wBhCwGdAwMQEzAyMFPgIWFRQGBwYmJTYWFQYGBwYmNjYCir6Riv7GATpePDwvLD4CkCw/ATwuLzwCOgaI/vgoLz0EPC4vPAICOZ0CPC8vPAICOl4+AP//AKUCaAGFA0wABgB4AAAAAQBDAAAEpQWwAAUAKwCwAEVYsAQvG7EEHD5ZsABFWLACLxuxAhA+WbAEELIAAQorWCHYG/RZMDEBIQMjEyEEif1Y4b39A2UFEvruBbAAAv+xAAAE3gWwAAMABgAvALAARViwAC8bsQAcPlmwAEVYsAIvG7ECED5ZsgQBCitYIdgb9FmyBgIAERI5MDEBMwEhJSEDAwKnATX60wEjAzLUBbD6UJ0EJgAAAwBp/+kE/AXIAAMAFgAnAFcAsABFWLANLxuxDRw+WbAARViwBC8bsQQQPlmyAgQNERI5fLACLxi0YAJwAgJdsgEBCitYIdgb9FmwDRCyGwEKK1gh2Bv0WbAEELIjAQorWCHYG/RZMDEBITchASYCJyYSNzYkFxYSFxYHBwYCBAE2JiYnJgADBgcGFhcWEhM2A6/+CRsB9/540/cKBTBCXQEwvtT2CQMKDB/C/ucBVAQ8iGPB/wAkEAEGlpS6+ykUApOY/MEEAR/0YgFCjMTRBAT+4/dUU1TZ/ralA5V7v2UDBf7O/vh0Q8DhBAcBGwEBfgAB/8QAAARxBbAABgAxALAARViwAy8bsQMcPlmwAEVYsAEvG7EBED5ZsABFWLAFLxuxBRA+WbIAAwEREjkwMQEBIwEzASMC7P2p0QL/qAEGwgSH+3kFsPpQAAADAAwAAASGBbAAAwAHAAsATwCwAEVYsAgvG7EIHD5ZsABFWLACLxuxAhA+WbIAAQorWCHYG/RZsAIQsAXQsAUvsi8FAV2yBgEKK1gh2Bv0WbAIELIKAQorWCHYG/RZMDE3IQchEyEHIRMhByEoA44c/HLlAtwb/SM4A3kc/IadnQM/nQMOngAAAQBEAAAFcAWwAAcAOACwAEVYsAYvG7EGHD5ZsABFWLAALxuxABA+WbAARViwBC8bsQQQPlmwBhCyAgEKK1gh2Bv0WTAxISMTIQMjEyEEc7zh/UnhvP0ELwUS+u4FsAAAAf/aAAAEiQWwAAwAPACwAEVYsAgvG7EIHD5ZsABFWLADLxuxAxA+WbIBAQorWCHYG/RZsAXQsAgQsgoBCitYIdgb9FmwB9AwMQEBIQchNwEBNyEHIQEC8v31AvEc/B4bAjj+khgDshz9MwFUAtD9zZ2YAkoCR4ee/dYAAAMAVAAABXAFsAAJABMALABZALAARViwHi8bsR4cPlmwAEVYsCsvG7ErED5ZshQrHhESObAUL7IAAQorWCHYG/RZsh0eKxESObAdL7Ag0LIKAQorWCHYG/RZsAHQsAAQsAvQsBQQsCnQMDEBEyMmBgYHBhYXAQMXFjY2NzYmJwEGJiY3NhIkFzM3FwcyFhYHBgIEJyMHIzcCO5MCZLiFDhWQnAFWlANit4QRFZKa/pqF4m8PD6sBFZ4NJ7opiuJvDxCt/uOZBiS+JAFOAwwRX89zpM0LAwr89QENW8d7qMkL/FgBjvmUmwEBkwK5AbiO+ZSc/vyTBq+wAAABAIYAAAWdBbAAGQBcsgoaGxESOQCwAEVYsAQvG7EEHD5ZsABFWLAQLxuxEBw+WbAARViwGC8bsRgcPlmwAEVYsAsvG7ELED5ZshcECxESObAXL7AA0LAXELIMAQorWCHYG/RZsAnQMDEBNjY3EzMDBgAHAyMTJgI3EzMDBhcWFhcTMwL/nM0dXLxdK/7D70S9RdDXG1i8WQkHCndkpr0CCBnTowIZ/dvr/uEX/pYBbB4BNuICDv3xRUFqjRgDpAABAAoAAATaBccAJgBZsgAnKBESOQCwAEVYsBovG7EaHD5ZsABFWLAQLxuxEBA+WbAARViwJS8bsSUQPlmyIwEKK1gh2Bv0WbAA0LAaELIIAQorWCHYG/RZsAAQsA/QsCMQsBLQMDElNhI/AjYmJyYGAhcWFhcHITc3AhM3NhIkFx4CFxYCBwYHNwchAnuYxiYRCAOKiKjmSQQDaV8Z/iIc1qEpFB61AQief8Z0CQc9WVB32Bz+KaEhARj3eWuqxAQF+f5JfpWvGKKdAgEDATSEtAEhmAMDdt+LaP6clodeA50AAgBI/+cEMgRUABgAJQB5shUmJxESObAVELAi0ACwAEVYsBUvG7EVGD5ZsABFWLAYLxuxGBg+WbAARViwDi8bsQ4QPlmwAEVYsAovG7EKED5ZsgUBCitYIdgb9FmyDBUKERI5shcVChESObAOELIdAQorWCHYG/RZsBUQsiIBCitYIdgb9FkwMQEDBhcWFzM3FwYnJicGJyYCNzc2ABcWFzcBBwYWFxY3EyYnJgYHBDKECAQFKhEQCjU9jBCKwK+1FwssAQG5wFgv/X4FA21mpHVMOJqMthoEOvzrOh04AgOLIAEEn6kEAwEc50v5AR8FBp2O/bNRhJYCA74BwbMHBe3MAAAC//D+gARMBccAEwApAGWyGyorERI5sBsQsBPQALAOL7AARViwAC8bsQAcPlmwAEVYsAsvG7ELED5ZshQACxESObAUL7InAQorWCHYG/RZsgUnFBESObAAELIaAQorWCHYG/RZsAsQsiEBCitYIdgb9FkwMQEWFgcGBxYWBwYEJyYnAyMTPgITNjY3NiYnJgYHAxYWMxY2NzYmJyc3AtKszg4R1l5gCRD+5susb1a2+RGL2A16mgsKaWJsqROOKYhJg7oQDmhhlxsFxATXprxyLrp9y/4EBF3+NAWxcrpq/ZECgW1hgQQCj2/8wzs4AqeFcZ8FAZcAAAEAhP5gBBoEOgAIADiyAAkKERI5ALAARViwAS8bsQEYPlmwAEVYsAcvG7EHGD5ZsABFWLAELxuxBBI+WbIABwQREjkwMQEBMwEDIxMDMwG+AZzA/dhQtVW+sQEWAyT79P4yAesD7wAAAgBD/+cEEwYgACAALwBisgIwMRESObACELAo0ACwAEVYsAMvG7EDHj5ZsABFWLAVLxuxFRA+WbADELIIAQorWCHYG/RZsi0VAxESObAtL7IOAQorWCHYG/RZsh0tDhESObAVELInAQorWCHYG/RZMDEBNjYXFhcHJgciBgcGFxcWEgcHBgAnLgI3NzY2NzcmJgMGFxYXFhcWNjc2JicmBgFPB+KqepAUgn5VdQoPjzW1pRQDIf7U0oe9Vg4DF9mjA0xUQQcFC1cwTYXAHg97bYfEBO2OpQICN6E/Ak5AXUEYS/7lwhX2/t0FBIjwkhaz/R8NJYb9Xz5BjEMlAgXOyoniDxLnAAEAKf/nA+UETQAoAHiyJikqERI5ALAARViwGS8bsRkYPlmwAEVYsA0vG7ENED5ZsicZDRESOXywJy8YsoAnAV20QCdQJwJdsgABCitYIdgb9FmwDRCyBgEKK1gh2Bv0WbIKGQ0REjmyEwAnERI5sh0ZDRESObAZELIhAQorWCHYG/RZMDEBIgYHBhYXFjY3NwYEJyYnJjc2NyYmNzY2NzcWFgcnNiYnIgYHBhcXBwIFfJUKCXxqa6gRtRD+9MSLaKQKCudCTQQG2rwtrtUDsgJzY2yYDBPQ1BsB315ZSlwDAmtXAZ67BQI2Vq24UiJ0Q4utCgEFsI0BS10DW1GSBgGUAAEAgv6ABDwFsAAcADmyEx0eERI5ALANL7AUL7AARViwAC8bsQAcPlmyGgEKK1gh2Bv0WbAB0LAUELIIAQorWCHYG/RZMDEBBwEHBgcGFhcXFgcGByc3Njc2JycmJjcSAQEhNwQ8F/4vKsYZCilKzYsKCsZcIk4KCF9vin4QHAFCAVb9nRsFsIH+IC3X0EtpG0UyhJiZWSRURDogISurkAEMAUoBTJgAAAEAJP5hA/MEUgASAFOyCBMUERI5ALAARViwAy8bsQMYPlmwAEVYsAAvG7EAGD5ZsABFWLAHLxuxBxI+WbAARViwEC8bsRAQPlmyAQMHERI5sAMQsg0BCitYIdgb9FkwMQEHNhcWFgcDIxM2JyYnJgcDIxMBghWOu6aXFbu1uwYEDaWpboi2vAQ7iaAEBNPB+6sEUjYvnAMEqfzuBDoAAwBz/+UEKwXKABEAGwAkAGayGSUmERI5sBkQsADQsBkQsCLQALAARViwCS8bsQkcPlmwAEVYsAAvG7EAED5ZshIACRESOXywEi8YsAkQshgBCitYIdgb9FmwEhCyHQEKK1gh2Bv0WbAAELIiAQorWCHYG/RZMDEFLgI3NhI3NgUWEgcGBwcCAAEhNzYnAicmBgcFIQYXFhYXFhMB3HmlSwQDTmKQAQO2uAYCCRwz/un+lQIYCQ8CC7iIrykB+/3pFgMDZFr0WxQDfu2XcwHen+kGBP727UtFt/61/q4DOzlySgERBwTo8NCAZYyTAwwBkQABAIX/9AHuBDoADgAoALAARViwAC8bsQAYPlmwAEVYsAovG7EKED5ZsgUBCitYIdgb9FkwMQEDBhcWFzI3BwYnJiY3EwHMiAMCBk8iNAxHPmxsDIcEOvzXGhZKAwqYEgICmIQDJgAB/7f/8APABewAGQBNsg4aGxESOQCwAC+wAEVYsAovG7EKED5ZsABFWLAPLxuxDxA+WbAKELIFAQorWCHYG/RZsg4AChESObAAELIVAQorWCHYG/RZsBfQMDEBMhcTFhczNwcGByImJwMBIwEnJiYnJwc3NgGOtijiFDkTEgYeKFBiIH3+Y9ECNzQRKyMYGQwwBeyu+6tTAwKaCQJWdQJO/PcEEOA6JwIBAY4LAAABAD/+dwQPBcgALgBSshkvMBESOQCwGC+wHi+wAEVYsCwvG7EsHD5ZsgIBCitYIdgb9FmyCSwYERI5sAkvsgsBCitYIdgb9FmwHhCyEQEKK1gh2Bv0WbIlCwkREjkwMQEmIyIGBwYWFxcHJyIGBwYeBAcGBgcnNzY3NicmJyYTNjY3JiY3Njc2FxYXA+V+WYyzDQ+PlIsbf8HoEQxx9Fk/IwMFaWBkOz4IClinRPUXDLuvXWYFC6SPxYN7BQgmaVtkbwEBmAGvm2ycQyAtRTNInElXPUQ/OhgtIXQBFo/POSqVVrVeUQMCJwABAGD/9ASkBDoAFgBcsg0XGBESOQCwAEVYsBUvG7EVGD5ZsABFWLALLxuxCxA+WbAARViwES8bsREQPlmwFRCyAAEKK1gh2Bv0WbALELIGAQorWCHYG/RZsAAQsA/QsBDQsBPQsBTQMDEBIwMGFxYzFjcHBicmJjcTIQMjEyM3IQSJl28DAgdPJS8JQkJtbQxs/nyhtaGkGwQpA6H9cBoWTAIMmRIBApiFAo38XwOhmQAAAv/c/mAD+QRTABMAIABQsg8hIhESObAPELAX0ACwAEVYsAUvG7EFGD5ZsABFWLASLxuxEhI+WbAARViwDy8bsQ8QPlmyFgEKK1gh2Bv0WbAFELIdAQorWCHYG/RZMDETNjY3NhceAhcWBw4CJyYnAyMBFhcWNjc3NiYnJgYHhhFXR4rGc6VYAwEJE4HJgbxjYbYBL0GZibcWCQdkbXqoHgJBcMlJkAUDbM1/PGKY84ECBHr99wKzjQQDzapro7AEAtS3AAEATv6JA+sEUwAhAEqyGSIjERI5ALATL7AARViwAC8bsQAYPlmwAEVYsBkvG7EZED5ZsgMAExESObAAELIHAQorWCHYG/RZsBkQsg0BCitYIdgb9FkwMQEWFgcnNiYnJgYHBwIFFxYHBgYHJzc2NzYnJyYCNzc2EjYCe6vFCqoHaGWDvRsEHgE0VpUKBWtdXClHCQdOLs/HEwQRlucETwTYrwFtgQQF274d/vFjHTiIR6BHWitLRz0XDDkBB8UrlgEAjQACAEr/5gStBDsAEgAhAEyyHiIjERI5sB4QsBHQALAARViwEi8bsRIYPlmwAEVYsAcvG7EHED5ZsBIQsgEBCitYIdgb9FmwBxCyFgEKK1gh2Bv0WbABELAe0DAxAQUWBwcGACcuAicmNzc2ADMFARQWFxY2NzYnJiYnJgYGBJL+7ZAXAR7+zM1urGYJBQcCIAEq2wI1/FVzbIvBGgkFCXVjaqZYA6EDqfAK7v7ZBgFmwHZCQxDzASoB/XqPoAQF37laPHCFAwOC6QAAAQCH/+wEEAQ6ABEASbIDEhMREjkAsABFWLAQLxuxEBg+WbAARViwCi8bsQoQPlmwEBCyAAEKK1gh2Bv0WbAKELIFAQorWCHYG/RZsAAQsA7QsA/QMDEBIQMHFDMyNxcGJyYmNxMhNyED9v6YcAFIITseT11sZw1r/q8bA24DpP1oLVQXhDIBApaSAo2WAAEAZ//lA/oEPAAVADyyBhYXERI5ALAARViwAC8bsQAYPlmwAEVYsAsvG7ELGD5ZsABFWLARLxuxERA+WbIFAQorWCHYG/RZMDEBAwcUFhcWEgMnJicXFhcSACUmJjcTAaFtBUpHpNsHAgoitiYFD/7G/v6vqBdtBDr9bV1dagIGAXUBFjaDfQJ9gv57/i8GBPDNAo4AAAIAQf4iBTgEPgAaACMAX7IYJCUREjmwGBCwG9AAsBkvsABFWLARLxuxERg+WbAARViwBi8bsQYYPlmwAEVYsAAvG7EAED5Zsg0BCitYIdgb9FmwABCwGNCwDRCwG9CwERCyIQEKK1gh2Bv0WTAxBSYCNzYSNxcGAhcWFhcTNjYXHgIHBgAFAyMBNhInJiYHBgcCAuDhHRSljlaBexMOhm17DZJufsJdDhv+rP78VbUBI8HtBgd4YzwSDx0BOeaoAQxaiGr+2IRskRgCz2eAAgKU+If1/tIV/jMCYx8BFL6OpggEQQAAAQBP/igFTwQ8AB0ARLIdHh8REjkAsA8vsABFWLAWLxuxFhg+WbAARViwES8bsREQPlmyHAEKK1gh2Bv0WbAB0LAWELAd0LAH0LARELAO0DAxAQM2EgMnJicXFhcSBQYHAyMTJgI3EzMDBhcWFhcTA2ul1u8JAwwltScIHf74pPJUtVXe0CFStVIKBAV5cKkEOvxLJQFCARU+gnsCe4H+JdqHE/45AcsfAUb8Aeb+F0xJe58ZA7EAAAEAZv/kBfwEPAAqAFqyISssERI5ALAARViwAC8bsQAYPlmwAEVYsBgvG7EYGD5ZsABFWLAfLxuxHxA+WbAARViwJC8bsSQQPlmyCAEKK1gh2Bv0WbIMHwAREjmwEtCyIggfERI5MDEBBwYCBxUUFhcWExMzAwYHBhYXFhM2JyYnFxYXFgIGJyYmJwYnLgI3EhMCCUhLWwJPStM8M7YvBgECUlC1TDQUDS23LwoRb+CbbJgUfd9nkEEDBdcEOX+D/vqfCn+FAw0BTwE//tQvOmt/AgcBKMzOg30CfILa/l7ZBAKBbPYHA3DSgAFeASwAAAIAUf/nBG0FywAkAC8Aa7ImMDEREjmwJhCwFNAAsABFWLAeLxuxHhw+WbAARViwBy8bsQcQPlmyKB4HERI5sCgvshcBCitYIdgb9FmwAtCyDR4HERI5sAcQshMBCitYIdgb9FmwKBCwItCwHhCyLAEKK1gh2Bv0WTAxAQYHBwYHBicuAjcTNwMGFxYWFxY2NzcmAjc3NjYXFhYHAzY3AQYWFxM3JicmBgcEZzRgHyeCgLh6tFQPNrY2BwcLaVV3lxYewNIOAg7MlZGXEjtONv3kCm5+OwQEb0hbCgJyEg230nNwBQN10H8BTgL+rzg1VmQDA52QqSYBFMUQmscEBM6k/p4LDgFQgLklAVhIjQICaVkAAAEAZwAABNgFwQAaAEmyABscERI5ALAARViwBC8bsQQcPlmwAEVYsBcvG7EXHD5ZsABFWLANLxuxDRA+WbIABA0REjmwBBCyCQEKK1gh2Bv0WbAS0DAxAQE2NhcyFwcmIyYHAQMjEwMmJyYHJzYzFhYXAi0BLTZ5T0BALx0VQjb+amG6Za0aOw8mFTY+S2QgAwgB+2ZYAhyXCQJT/Wv90QJIAntJAwEImRkCV2AAAAIAZv/kBkQEOgAWACwAarIJLS4REjmwCRCwJ9AAsABFWLAVLxuxFRg+WbAARViwBy8bsQcQPlmwAEVYsAwvG7EMED5ZsBUQsgABCitYIdgb9FmyChUHERI5sBTQsBnQsAcQsikBCitYIdgb9FmwINCyJBkHERI5MDEBIxYVFAIGJyYmJwYnLgI3NjY3BzchASYnJQYGBwYWFxYTNzMHBwYWFxYTNgYngAdyw4VvlxJ+3WGCOAYHREB1HAWm/rMDC/zTUEkHBT1C2TgmtycGB1JWqTwdA6FcWtD+hroEAoNr9wcDctt9ledvApn+slpbAYvqmn+OBQ4BaPf8RYSLAgQBTqEAAQCh//IFegWwABkAYQCwAEVYsBgvG7EYHD5ZsABFWLAULxuxFBA+WbAARViwCi8bsQoQPlmwGBCyFwEKK1gh2Bv0WbAB0LIEFBgREjmwBC+wChCyCwEKK1gh2Bv0WbAEELIRAQorWCHYG/RZMDEBIQM2FxYWBwYEBzc2Njc2JicmBwMjEyE3IQTq/gdWo3bW8BES/t7zC5e5Dw6JhXynerzh/m0cBEkFEv44MgMC8c7U7gSYAp6PhpECAy79WQUSngABAHj/5gT/BccAJABqALAARViwDS8bsQ0cPlmwAEVYsAMvG7EDED5ZsA0QsREKK1jYG9xZsA0QshQBCitYIdgb9FmwAxCwGNCwGC+yLxgBXbIZAQorWCHYG/RZsAMQsiEBCitYIdgb9FmwAxCxJAorWNgb3FkwMQEGACcuAicmEhI3NhcWEhcjJiYnJgYDIQclBwYHBhYWFxY2NwSXKv6744fJcQYGTeaobXvN8Ae6B4qBrvY7AjAc/d0CDAMGQYJcmsczAdDi/vgGA3/uknABuAFFQSsDBP7/5KihAwX8/v2dBQo0Om6/ZAMFnawAAv/MAAAH8gWwABgAIQBushoiIxESObAaELAK0ACwAEVYsAAvG7EAHD5ZsABFWLAILxuxCBA+WbAARViwEC8bsRAQPlmyAgAIERI5sAIvsAAQsgoBCitYIdgb9FmwEBCyEgEKK1gh2Bv0WbAb0LACELIhAQorWCHYG/RZMDEBAwUWFgcGBCMhEyEDBwICByM3NzY2EzcTAQMFMjY3NiYnBV5jAUjM4xET/tbk/eXi/hF4Hz7wu0wSJoSoKxWPAuFkAUqMwhIPf3cFsP3LAQbwwM33BRL91Jn+zv7pBJwBBugBBHcCqv0t/cABpYd8lAQAAgBDAAAH/gWwABIAGwCCsgEcHRESObABELAT0ACwAEVYsBIvG7ESHD5ZsABFWLACLxuxAhw+WbAARViwDy8bsQ8QPlmwAEVYsAwvG7EMED5ZsgACDxESObAAL7IEDAIREjmwBC+wABCyDgEKK1gh2Bv0WbAEELITAQorWCHYG/RZsAwQshQBCitYIdgb9FkwMQEhEzMDBRYWBwYEIyETIQMjEzMBAwUyNjc2JicBjwK3brtqATfR8Q8R/tjn/eh0/Ul0vf28Au5bAUmLwBEPfX0DOQJ3/Z4BAd27x+0CnP1kBbD9Af31AZN/bocEAAEAtAAABaIFsAAXAFeyAxgZERI5ALAARViwFi8bsRYcPlmwAEVYsAgvG7EIED5ZsABFWLASLxuxEhA+WbAWELIVAQorWCHYG/RZsAHQsgQIFhESObAEL7IPAQorWCHYG/RZMDEBIQM2FxYWBwMjEzYnJiYnJgcDIxMhNyEE/P4AUZyp39MXS71MCAgMb2uMw3+84v5zHARIBRL+TykCBOvS/jkByEU2UVMDAyr9PQUSngABAEL+mQVuBbAACwBIALAJL7AARViwAC8bsQAcPlmwAEVYsAQvG7EEHD5ZsABFWLAGLxuxBhA+WbAARViwCi8bsQoQPlmyAgEKK1gh2Bv0WbAD0DAxATMDIRMzAyEDIxMhAT+84QK34rv9/k4+vT/+PwWw+u0FE/pQ/pkBZwACADQAAASWBbAADAAVAFuyDxYXERI5sA8QsAPQALAARViwCy8bsQscPlmwAEVYsAkvG7EJED5ZsAsQsgABCitYIdgb9FmyAgsJERI5sAIvsg0BCitYIdgb9FmwCRCyDgEKK1gh2Bv0WTAxASEDBRYWBwYEIyETIQEDBTI2NzYmJwR6/VhLATbY7BEQ/tjp/eX9A2X81mABSo3AEQ58fAUS/kwBAeK/x/QFsP0Q/d0BnoN2iAQAAAL/i/6aBXoFsAAOABUAVbISFhcREjmwEhCwC9AAsAQvsABFWLALLxuxCxw+WbAARViwAi8bsQIQPlmwBBCwAdCwAhCyBwEKK1gh2Bv0WbAP0LAN0LALELIRAQorWCHYG/RZMDEBIxMhAyMTFzYTNxMhAzMFJRMhAwcCBPa7PvwMP7tZa89lFJQDT+K5+9gCs8b+JG4dXf6bAWX+mgIDAqkBfk4CoPrtAwMEdf4Lcv6pAAAB/6wAAAd1BbAAFQCGALAARViwCS8bsQkcPlmwAEVYsA0vG7ENHD5ZsABFWLARLxuxERw+WbAARViwAi8bsQIQPlmwAEVYsAYvG7EGED5ZsABFWLAULxuxFBA+WbACELAQ0LAQL7IvEAFdss8QAV2yAAEKK1gh2Bv0WbAE0LIIEAAREjmwEBCwC9CyEwAQERI5MDEBIwMjEyMBIwEBMwEzEzMDMwEzAQEjBJWcc7x0mf399gJo/sXRAQqlbrtukgHm6f3JAVLcApj9aAKY/WgDCgKm/YgCeP2IAnj9R/0JAAEAJf/qBJgFxwAqAGAAsABFWLANLxuxDRw+WbAARViwGS8bsRkQPlmwDRCyBgEKK1gh2Bv0WbANELAK0LAZELAq0LAqL7IpAQorWCHYG/RZshIpKhESObAZELAd0LAZELIgAQorWCHYG/RZMDEBMjY3NiYnJgYHBzYkFxYWBwYFFhYHBgYEJyYmNxcGFhcWNjc2NzYmJyc3Am2UvQ4NlYB+uxS6EgEs0tvwEBH+9WdfCAuX/vmZ0PMJugiUfEWGNm4QDoKUrRwDNIV4c4ICAolvAbbgAgXdtdR0LaxvhMVrAgTovQF1kwQCJCVMf3WCBQGeAAABAEMAAAVuBbAACQBdALAARViwAC8bsQAcPlmwAEVYsAcvG7EHHD5ZsABFWLACLxuxAhA+WbAARViwBS8bsQUQPlmyBAACERI5QAmKBJoEqgS6BARdsgkAAhESOUAJhQmVCaUJtQkEXTAxATMDIxMBIxMzAwSswv27wfyPw/28wQWw+lAEVvuqBbD7qgAAAf/KAAAFZQWwABAATbIEERIREjkAsABFWLAALxuxABw+WbAARViwAS8bsQEQPlmwAEVYsAgvG7EIED5ZsAAQsgMBCitYIdgb9FmwCBCyCgEKK1gh2Bv0WTAxAQMjEyEDAgYHIzc3NjY3NxMFZfy84f4Ip0Hiq1cSJIemKxaPBbD6UAUS/Pb+8/UGnQEI5P99AqoAAAEAk//mBUAFsAAQADyyAxESERI5ALAARViwAS8bsQEcPlmwAEVYsBAvG7EQHD5ZsABFWLAGLxuxBhA+WbIKAQorWCHYG/RZMDEBATMBBgYnJic3FzI/AgEzAoYB2OL9PVG0ejwvFlljRSQ6/tvJAmQDTPtCk3kCAgmYBmM4ZgQqAAADAFv/xAXfBewAGAAhACoAarIeKywREjmwHhCwC9CwHhCwI9AAsBcvshYXKxESObAWL7AA0LAAL7INKxcREjmwDS+wCtCwCi+wDRCwDNCwDC+wDRCyHQEKK1gh2Bv0WbAWELIfAQorWCHYG/RZsB0QsCPQsB8QsCrQMDEBFxYWEgcGAgQnIwcjNyImAjc2EiQ3MzczAQYWFxcTIwYEJQMzNiQ3NiYnA9gUmOpxEBK6/tunICe2KKjscxAQswEcojYqsP0iF5uiLp8evP7/ApKeHboBARkWpKcFHQEDl/73nKj+65kBxMWWAQygowEQnATO/N+45QwCA2kD9vf8lwP0yL/kBwAAAQBB/qEFbQWwAAsAOwCwCS+wAEVYsAAvG7EAHD5ZsABFWLAELxuxBBw+WbAARViwCi8bsQoQPlmyAgEKK1gh2Bv0WbAG0DAxATMDIRMzAzMDIxMhAT684QK34rvhlWqqPvv2BbD67QUT+vH+AAFfAAEAzgAABUQFsAASAEiyDxMUERI5ALAARViwEi8bsRIcPlmwAEVYsAovG7EKHD5ZsABFWLABLxuxARA+WbIPAQoREjl8sA8vGLIFAQorWCHYG/RZMDEBAyMTBicmJjcTMwMGFxYXFjcTBUT9vG+xydzWF0y8SwgIGM+h4H0FsPpQAlw3AgLr1QHH/jhFNaUDAzYCtwABAEIAAAc4BbAACwBIALAARViwAC8bsQAcPlmwAEVYsAMvG7EDHD5ZsABFWLAHLxuxBxw+WbAARViwCS8bsQkQPlmyAQEKK1gh2Bv0WbAF0LAG0DAxAQMhEzMDIRMzAyETAfvhAeXhu+IB4uG8/foH/QWw+u0FE/rtBRP6UAWwAAEAQv6hBzgFsAAPAFQAsAsvsABFWLAALxuxABw+WbAARViwAy8bsQMcPlmwAEVYsAcvG7EHHD5ZsABFWLANLxuxDRA+WbIBAQorWCHYG/RZsAXQsAbQsAnQsArQsALQMDEBAyETMwMhEzMDMwMjEyETAfvhAeXhu+IB4uG84o9poj36K/0FsPrtBRP67QUT+uf+CgFfBbAAAgCJAAAFgAWwAAwAFQBesgEWFxESObABELAN0ACwAEVYsAAvG7EAHD5ZsABFWLAJLxuxCRA+WbICAAkREjmwAi+wABCyCwEKK1gh2Bv0WbACELINAQorWCHYG/RZsAkQsg4BCitYIdgb9FkwMRMhAwUWFgcGBCMhEyEBAwUyNjc2JiekAkpnATba6RER/tno/ebi/nIB42ABSo2/EQ58ewWw/a4BAeW9yfEFGP2o/d0BnoN2iAQAAAMARQAABpYFsAAKABMAFwBtshIYGRESObASELAG0LASELAV0ACwAEVYsAkvG7EJHD5ZsABFWLAWLxuxFhw+WbAARViwBy8bsQcQPlmwAEVYsBQvG7EUED5ZsgAJBxESObAAL7ILAQorWCHYG/RZsAcQsgwBCitYIdgb9FkwMQEFFhYHBgQjIRMzAwMFMjY3NiYnASMTMwGWATbY7BEQ/tjp/ef8vIJgAUqNwBEOfHwCwLv9uwNeAQHiv8f0BbD9EP3dAZ6DdogE/UEFsAAAAgA2AAAEgQWwAAoAEwBNsg0UFRESObANELAB0ACwAEVYsAkvG7EJHD5ZsABFWLAHLxuxBxA+WbIACQcREjmwAC+yCwEKK1gh2Bv0WbAHELIMAQorWCHYG/RZMDEBBRYWBwYEIyETMwMDBTI2NzYmJwGHATbY7BEQ/tjp/ef8vIJgAUqNwBEOfHwDXgEB4r/H9AWw/RD93QGeg3aIBAABAHT/6QT8BcoAIgBgALAARViwFS8bsRUcPlmwAEVYsB8vG7EfED5ZsADQsB8QsgMBCitYIdgb9FmwHxCwCNCwCC+yLwgBXbLPCAFdsgcBCitYIdgb9FmwFRCyDgEKK1gh2Bv0WbAVELAR0DAxARYWFxYSNwU3ITY3NiYnJgYHBzYAFx4CFxYCAgcGJyYmJwEwB42OrOw3/c0cAikJAgOZkY/FMbsuAT3cjM53BwZL26BvfdX5CAHPp5wEBQEI/QGeODu50gQFpKsB5gEIBgN97JRy/k/+vEQwAwT+4QACAEn/5wbOBccAFwAnAHeyASgpERI5sAEQsCLQALAARViwDy8bsQ8cPlmwAEVYsAkvG7EJHD5ZsABFWLAALxuxABA+WbAARViwBi8bsQYQPlmyCgYJERI5fLAKLxiyBQEKK1gh2Bv0WbAPELIbAQorWCHYG/RZsAAQsiMBCitYIdgb9FkwMQUmJgI3IwMjEzMDMzYSJBcWEhcWAgIHBgE2JicmBgIHBwYWFxYSEzYEEpveaRDObrv9u3THIcIBGabV9gkEM4NlsAEOBpaUhtOHEgMGmJG9+SkUFAOiATa2/YMFsP1kzgFCowME/uH1af68/upepAOXxdkEBJj+0ehBxN4EBQEbAQB+AAL/6AAABNgFsQANABYAYbIRFxgREjmwERCwAtAAsABFWLALLxuxCxw+WbAARViwAC8bsQAQPlmwAEVYsAMvG7EDED5ZshIACxESObASL7IBAQorWCHYG/RZsgUBCxESObALELIUAQorWCHYG/RZMDEhEyEBIwEmJjc2JDMFAwEGFhcFEyciBgMeY/7B/nnTAbxyaAsSATTsAdH9/bYQhX0BGWT+msYCN/3JAnA6yH/Q8AH6UAPyfJ0EAQI+AZoAAAIARv/nBFUGEQAcACsATbIZLC0REjmwGRCwHdAAsBQvsABFWLAILxuxCBA+WbIACBQREjmwAC+yGwAIERI5sAgQsiUBCitYIdgb9FmwABCyKwEKK1gh2Bv0WTAxAR4CBwcGACcuAj8CEgA3NzY3Mw4CBAYHNhcmBg8CFhYXFjY3NiYnAo16sVYMAx7+19GGwlkQBAUnASfycZcZlQpLiv660kCpmn+2GwcDA3lsibsaDn55A/wCfuCHF/T+3QUCjfGPHi0BTwGmMRUhb2B3SUC4p66bA6uVL1WEnQIDzsiYtQQAAAMAMAAABA0EOgANABYAHgBXALAARViwAS8bsQEYPlmwAEVYsAAvG7EAED5ZshcAARESOXywFy8Ysg4BCitYIdgb9FmyBw4XERI5sAAQsg8BCitYIdgb9FmwARCyHgEKK1gh2Bv0WTAxMxMFFhYHBgcWFgcGBgcDAwUyNjc2JiclFzI2NzYnJzC8AX7K2QoKylBaBAbmwfE5AR5wiwsKYWH+5t6DkgsV7PEEOgEBk4ybVhiBVJKnAgHb/roBW1FITwOVAVJOjgcBAAABAC0AAAODBDoABQArALAARViwBC8bsQQYPlmwAEVYsAIvG7ECED5ZsAQQsgABCitYIdgb9FkwMQEhAyMTIQNn/h2htrwCmgOh/F8EOgAC/43+wgQ+BDoADgAUAFKyEhUWERI5sBIQsAnQALAML7AARViwBC8bsQQYPlmwAEVYsAovG7EKED5ZsgABCitYIdgb9FmwD9CwBtCwDBCwCdCwBBCyEQEKK1gh2Bv0WTAxNzY2NxMhAzMDIxMhAyMTBSUTIQMCLW+IIFQCpqKHUrQ3/SU3tVMBJAHjhP6/RESUZvyuAZb8Xf4rAT7+wgHVAwMC+P67/uUAAAH/pQAABg4EOgAVAJAAsABFWLAJLxuxCRg+WbAARViwDS8bsQ0YPlmwAEVYsBEvG7ERGD5ZsABFWLACLxuxAhA+WbAARViwBi8bsQYQPlmwAEVYsBQvG7EUED5ZsAIQsBDQsBAvsr8QAV2y/xABXbIvEAFdss8QAXGyAAEKK1gh2Bv0WbAE0LIIEAAREjmwEBCwC9CyEwAQERI5MDEBIwMjEyMBIwEDMxMzEzMDMwEzAQEjA7yDUbVSd/6I8QHi9c7BgE61T3MBX+f+SAES1wHW/ioB1v4qAjoCAP5AAcD+QAHA/ev92wABACH/6gOqBFAAJwBqALAARViwDS8bsQ0YPlmwAEVYsBkvG7EZED5ZsA0QsgYBCitYIdgb9FmwDRCwCtCwGRCwJ9CwJy+yLycBXbK/JwFdsiYBCitYIdgb9FmyEiYnERI5sBkQsBzQsBkQsiABCitYIdgb9FkwMQEyNjc2JiMmBgcHNjYXFhYHBgcWFgcOAicmJjcXBhYXFjY3NicnNwIBZnsICWNYWo4RtBD5rKnBCgrCS0UFBnfMd6nVBrEEdF9nkwsVzbkcAnVWT0dYAmBOAZWvAgKli5xZIX1RaJZQAwK6mAFSawICZFShAQGcAAABAC8AAAQ3BDoACQBFALAARViwAC8bsQAYPlmwAEVYsAcvG7EHGD5ZsABFWLACLxuxAhA+WbAARViwBS8bsQUQPlmyBAcCERI5sgkHAhESOTAxATMDIxMBIxMzAwN8u7y1iP2cu7y0hwQ6+8YDCfz3BDr89gAAAQAvAAAEVwQ6AAwAdwCwAEVYsAQvG7EEGD5ZsABFWLAILxuxCBg+WbAARViwAi8bsQIQPlmwAEVYsAsvG7ELED5ZsAIQsAbQsAYvsp8GAV2y/wYBXbLPBgFxsp8GAXG0vwbPBgJdsi8GAV2ybwYBcrIBAQorWCHYG/RZsgoBBhESOTAxASMDIxMzAzMBMwEBIwG+iVG1vLVQbgGw6f3+AVvWAc3+MwQ6/jYByv3v/dcAAAH/yAAABDkEOgARAE2yBBITERI5ALAARViwAC8bsQAYPlmwAEVYsAEvG7EBED5ZsABFWLAJLxuxCRA+WbAAELIDAQorWCHYG/RZsAkQsgwBCitYIdgb9FkwMQEDIxMhAwcGBgcjNzc2Njc3EwQ5vLai/pxRFjW+lU4SJ2F8IBJiBDr7xgOh/o5s8s4DogIGoa5nAdoAAAEAMAAABX4EOgAMAFkAsABFWLABLxuxARg+WbAARViwCy8bsQsYPlmwAEVYsAMvG7EDED5ZsABFWLAGLxuxBhA+WbAARViwCS8bsQkQPlmyAAsDERI5sgULAxESObIICwMREjkwMSUBMwMjEwEjAwMjEzMCogH25ry1h/4sftCOtLzl9wND+8YDBfz7Ayz81AQ6AAABAC8AAAQ2BDoACwCKALAARViwBi8bsQYYPlmwAEVYsAovG7EKGD5ZsABFWLAALxuxABA+WbAARViwBC8bsQQQPlmwABCwCdCwCS+ybwkBXbS/Cc8JAl2yPwkBcbTPCd8JAnGyDwkBcrSfCa8JAnGy/wkBXbIPCQFxsp8JAV2yLwkBXbRvCX8JAnKyAgEKK1gh2Bv0WTAxISMTIQMjEzMDIRMzA3q1Uf4fUbW8tVEB4FK1Ac7+MgQ6/isB1QAAAQAvAAAENwQ6AAcAOACwAEVYsAYvG7EGGD5ZsABFWLAALxuxABA+WbAARViwBC8bsQQQPlmwBhCyAgEKK1gh2Bv0WTAxISMTIQMjEyEDe7Wi/h6itbwDTAOh/F8EOgAAAQBgAAAD6AQ6AAcAMQCwAEVYsAYvG7EGGD5ZsABFWLACLxuxAhA+WbAGELIAAQorWCHYG/RZsATQsAXQMDEBIQMjEyE3IQPO/qCitKH+pxoDbgOk/FwDpJYAAwBM/mAFPQYAAB8ALAA6AH2yJzs8ERI5sCcQsBLQsCcQsDXQALADL7AARViwAC8bsQAYPlmwAEVYsAcvG7EHGD5ZsABFWLATLxuxExI+WbAARViwFy8bsRcQPlmwENCwBxCyJAEKK1gh2Bv0WbAXELIyAQorWCHYG/RZsCnQsAAQsjcBCitYIdgb9FkwMQEWFxMzAzYXFhcWDwIGAicmJwMjEwYnIiYnJjc3EhIBNicmJyYHAxYXFjY3BQYVFxYXFjcTJiMmBgcCJ1JBV7VZTVHVQRwCCAIi8bhXTFC1UUlHkJ8DAQYMLesDCAsDEKYzPY4sO3+pGvyMBgITnS86jjQqfaEgBFACHgHQ/iojAQPrZ3R4EPn+5AMCIf5UAakdAdW5OzdSAQABE/29ZEfzBwIU/O8QAgLHtg01PjC/BwISAxMSAs3PAAEAL/6/BDcEOgALADsAsAgvsABFWLAALxuxABg+WbAARViwBC8bsQQYPlmwAEVYsAovG7EKED5ZsgIBCitYIdgb9FmwBtAwMRMzAyETMwMzAyMTIeu1oQHhorWifmSiOPzqBDr8XQOj/F3+KAFBAAABAHsAAAQABDsAEgBIsg4TFBESOQCwAEVYsBEvG7ERGD5ZsABFWLAJLxuxCRg+WbAARViwAS8bsQEQPlmyDgEJERI5fLAOLxiyBAEKK1gh2Bv0WTAxISMTBicmJjcTMwMGFxYXFjcTMwNEtkt7drK7FTK1MwYFEJ5uiWK2AYkhAgLauQE8/sM0LZQGAx8CGwABAC8AAAYIBDoACwBIALAARViwAC8bsQAYPlmwAEVYsAMvG7EDGD5ZsABFWLAHLxuxBxg+WbAARViwCS8bsQkQPlmyAQEKK1gh2Bv0WbAF0LAG0DAxAQMhEzMDIRMzAyETAaChAX+htaIBfqK2vPrjvAQ6/F0Do/xdA6P7xgQ6AAEAJP6/Bf0EOgAPAEsAsAwvsABFWLAALxuxABg+WbAARViwAy8bsQMYPlmwAEVYsAcvG7EHGD5ZsABFWLANLxuxDRA+WbIBAQorWCHYG/RZsAXQsAnQMDEBAyETMwMhEzMDMwMjEyETAZaiAX+itKEBfaK2opRjozj7A7wEOvxdA6P8XQOj/F3+KAFBBDoAAAIAVgAABHsEOgAMABUAXrIBFhcREjmwARCwDdAAsABFWLAALxuxABg+WbAARViwCS8bsQkQPlmyAgAJERI5sAIvsAAQsgsBCitYIdgb9FmwAhCyDQEKK1gh2Bv0WbAJELIOAQorWCHYG/RZMDETIQMXFhYHBgYjIRMhAQMFNjY3NiYncQHsQf6jvgsL87v+NaH+yQGsRwEAa4cNC1ZYBDr+iwEEupilyQOi/oz+aQECcV5XawQAAwAwAAAFqQQ6AAoAEwAXAFoAsABFWLAKLxuxChg+WbAARViwFi8bsRYYPlmwAEVYsAgvG7EIED5ZsABFWLAVLxuxFRA+WbIACAoREjmwAC+yCwEKK1gh2Bv0WbAIELIMAQorWCHYG/RZMDEBFxYWBwYGIyETMwMDBTY2NzYmJwEjEzMBX+2xwgsL873+N7y1W0cBAGuHDQtXVwKStby1AsUCAbuZpckEOv30/mkBAnFeV2sE/dMEOgAAAgAwAAADvwQ6AAoAEwBNsgcUFRESObAHELAN0ACwAEVYsAkvG7EJGD5ZsABFWLAHLxuxBxA+WbIACQcREjmwAC+yCwEKK1gh2Bv0WbAHELIMAQorWCHYG/RZMDEBFxYWBwYGIyETMwMDBTY2NzYmJwFf7bHCCwvzvf43vLVbRwEAa4cNC1dXAsUCAbuZpckEOv30/mkBAnFeV2sEAAABADT/5wPEBFAAIQBoALAARViwCC8bsQgYPlmwAEVYsBIvG7ESED5ZsAgQsgABCitYIdgb9FmwCBCwBNCwEhCwFdCwEhCyGQEKK1gh2Bv0WbASELAe0LAeL7IvHgFdsr8eAV2yIB4BcbIdAQorWCHYG/RZMDEBJgYHBz4CFx4CFxYHBwYAJyYmNxcGFhcWNjchNyE2JgI7Y5gUqwqDyWxspGMJBQYDHf7V0KXKCKsGa2B0sDH+cBsBhAhzA7cCeF4BZKtfAQNju3dBQRn7/sYFBNyoAWWJBAWxrpiRsAACADD/5wYHBFQAFQAmAH0AsABFWLAVLxuxFRg+WbAARViwBC8bsQQYPlmwAEVYsBIvG7ESED5ZsABFWLAMLxuxDBA+WbIAEhUREjl8sAAvGLKAAAFdtEAAUAACXbRQAGAAAnGyEQEKK1gh2Bv0WbAMELIbAQorWCHYG/RZsAQQsiMBCitYIdgb9FkwMQEzNgAXHgIHBwIAJy4CNwUDIxMzAQYXFBYXFjY3NicmJicmBgcBUPRCASPAiL9XDwEi/szYfsFdC/7/U7S8tAFPBQF4bovLGwcFCXZmjMgaAm/lAQAFBI/6mAn+/P7KBQKE4IYB/ikEOv3QKi2NoQQF5Mk/RXiNBAXjuAAC/78AAAP/BDsADQAWAGGyFBcYERI5sBQQsA3QALAARViwAC8bsQAYPlmwAEVYsAEvG7EBED5ZsABFWLAFLxuxBRA+WbISAAEREjmwEi+yAwEKK1gh2Bv0WbIHAwAREjmwABCyEwEKK1gh2Bv0WTAxAQMjEyEBIwEmJjc2NjMBBhYXBRMnBgYD/7y2Sf75/r/PAV9VUAYL+rj++ApWTgEiP/dpjgQ6+8YBpf5bAcUqnF2buP6sTVgEAQFnAQJmAAABAB/+RQPjBgAAIwCAALAhL7AARViwBC8bsQQYPlmwAEVYsAsvG7ELEj5ZsABFWLAaLxuxGhA+WbK/IQFdsi8hAV2yDyEBXbIiGiEREjmwIi+yAQEKK1gh2Bv0WbICGgQREjmwCxCyEAEKK1gh2Bv0WbAEELIXAQorWCHYG/RZsAEQsBzQsCIQsB/QMDEBIQM2FxYWBwMGBiciJzcWMzI3EzYnJicmBwMjEyM3MzczByECu/7rNo66mpETgRbAlS1LHzExiyOBBgQRlaZ4hrXSnxqfH7UfARYEuf79mwQEz7X84qi6BBSSD9MDFTEqjAMEsvz8BLmYr68AAQBO/+gD/QRTAB4AZQCwAEVYsA8vG7EPGD5ZsABFWLAILxuxCBA+WbIAAQorWCHYG/RZsAgQsATQsA8QsBLQsA8QshYBCitYIdgb9FmwCBCwGtCwGi+yvxoBXbL/GgFdsi8aAV2yGwEKK1gh2Bv0WTAxJRY2NzcOAicmAjc3EgAXFhYHIzQmJyYGByEHIQYWAfFhnRusD4XOa8rRFwMeAS3XqcoCqnFferIxAY4b/n0PdoICc2EBZahgAwUBKO0bAQIBMQUE3ahrgwQFp62YlrUAAv/DAAAGLwQ6ABgAIQB5sgoiIxESObAKELAa0ACwAEVYsAAvG7EAGD5ZsABFWLAILxuxCBA+WbAARViwEC8bsRAQPlmyAgAIERI5sAIvsAAQsgoBCitYIdgb9FmwEBCyEwEKK1gh2Bv0WbAIELIbAQorWCHYG/RZsAIQsiEBCitYIdgb9FkwMQEDFxYWBwYGIyETIQMHBgYHIzc3NjY3NxMBAwU2Njc2JicEFkj+pb4JCfG+/jai/rtRGDPAmkgTJmF8IBJiAkdAAQBmjAsLWFsEOv5kAQWtkZu/A6H+jnbn0QGiAgahrmcB2v3M/o8BAm1ZSloFAAACAC8AAAZPBDoAEgAbAHuyARwdERI5sAEQsBPQALAARViwAi8bsQIYPlmwAEVYsBEvG7ERGD5ZsABFWLALLxuxCxA+WbAARViwDy8bsQ8QPlmyARELERI5sAEvsATQsAEQsg0BCitYIdgb9FmwBBCyEwEKK1gh2Bv0WbALELIUAQorWCHYG/RZMDEBIRMzAxcWFgcGBiMhEyEDIxMzAQMFNjY3NiYnAVkB4Ue1SP6jwAkJ8b7+N1v+H1u1vLUCNEABAGaKDQtXXAKhAZn+YwEErpCbvwIK/fYEOv3M/o8BAmxaSloFAAEAHwAAA+MGAAAaAHmyAxscERI5ALAXL7AARViwBC8bsQQYPlmwAEVYsAgvG7EIED5ZsABFWLARLxuxERA+WbK/FwFdsi8XAV2yDxcBXbIaERcREjmwGi+yAAEKK1gh2Bv0WbICBBEREjmwBBCyDgEKK1gh2Bv0WbAAELAT0LAaELAV0DAxASEDNhcWFgcDIxM2JyYnJgcDIxMjNzM3MwchAtH+0TGOuZiTE3a1dwYFEZSmeIa104sbih61IAEtBL7++JsEAs25/TsCyDEqjAMEsvz8BL6Xq6sAAQAv/pwENwQ6AAsARQCwCC+wAEVYsAAvG7EAGD5ZsABFWLADLxuxAxg+WbAARViwBS8bsQUQPlmwAEVYsAkvG7EJED5ZsgEBCitYIdgb9FkwMQEDIRMzAyEDIxMhEwGgoQHhorW8/rg/tD7+sbwEOvxdA6P7xv6cAWQEOgAAAQBv/+QG4wWwACEAYLIGIiMREjkAsABFWLAALxuxABw+WbAARViwGS8bsRkcPlmwAEVYsA4vG7EOHD5ZsABFWLAELxuxBBA+WbAARViwCS8bsQkQPlmyFAEKK1gh2Bv0WbIHFAQREjmwHdAwMQEDBgYnJiYnBicmJjcTMwMGFxYWFxY2NxMzAwYWFxY2NxMG47Qb/7lqnCCL3au0E7S8swUEB1JFbZwRtcKzDF5eZI4VtgWw+93E4wQCX1C3BgbntgQj+9wtLU5aAwWQegQk+9x4igMDhncELwABAE//5gXfBDoAIQBLALAARViwDi8bsQ4YPlmwAEVYsBgvG7EYGD5ZsABFWLAhLxuxIRg+WbAARViwCS8bsQkQPlmwBNCwCRCyFAEKK1gh2Bv0WbAd0DAxAQMGBicmJicGJyYmNxMzAwYXFhYXFjY3EzMDBhYXFjY3EwXfehndrFqIH3u+mKIRerR6BAMDRDxbgxJ7tnoKT09VeBJ6BDr9KLDMBAJNRZgEBM6lAtn9JiYmQFADBHhrAtr9JmZ3AgN1bQLaAAACAC7//APDBhYAEgAbAHGyFRwdERI5sBUQsAnQALAARViwDy8bsQ8ePlmwAEVYsAkvG7EJED5ZshIPCRESObASL7IAAQorWCHYG/RZsgMPCRESObADL7AAELAL0LASELAN0LAJELIVAQorWCHYG/RZsAMQshsBCitYIdgb9FkwMQEhAxcWFgcGBichEyM3MxMzAyEBAxc2Njc2JicC1v7JOv2lvAwO+7X+Nby6G7g5tjkBOP5aTf9ojgwNV1YEOv6wAQbEnrDVBAQ6lwFF/rv9gf5FAgJ7aVt3BAAAAQBJ/+cGswXKACsAh7IYLC0REjkAsABFWLArLxuxKxw+WbAARViwBi8bsQYcPlmwAEVYsCgvG7EoED5ZsABFWLAgLxuxIBA+WbIAKygREjmwAC+wBhCwCtCwBhCyDQEKK1gh2Bv0WbAAELAQ0LAAELInAQorWCHYG/RZsBLQsCAQshkBCitYIdgb9FmwIBCwHNAwMQEzNjY3NhcWEhcjJiYnJgYHIQclBgcGFhYXFjY3NwYAJyYCJyY3NwcDIxMzAZa5IXxasPnP7wa6B4qBq/M9AhQb/fcOAgY+gV2ZyDS6L/6648r3BwMOBsZ3vP28A0CQ+VeqBQT+/eKooQMF9PmXAU49bsBkAwWdrAHj/vsGBAEY5VBQHAH9VwWwAAEALP/oBY0EUwAkAMSyAyUmERI5ALAARViwBC8bsQQYPlmwAEVYsCQvG7EkGD5ZsABFWLAhLxuxIRA+WbAARViwHC8bsRwQPlmyDxwEERI5sA8vtL8Pzw8CXbQ/D08PAnG0zw/fDwJxtA8PHw8CcrSfD68PAnGy/w8BXbIPDwFxtC8PPw8CXbRvD38PAnKwANCyCA8EERI5sAQQsgsBCitYIdgb9FmwDxCyEAEKK1gh2Bv0WbAcELIUAQorWCHYG/RZshccBBESObAQELAf0DAxATM2JBcWFgcjNCYnJgYHIQchBhYXFjY3Nw4CJyYCNwcDIxMzAUyxQQEZw6fMAqpwX32xMAGuG/5dD3Z2ZpkarA+HzGu/2xPAULa8tgJn8PwFBN2oaoQEA6mql5a1AwJ1XwFlqV8DBAETzwH+MAQ6AAAC/7oAAARTBbAACwAOAFYAsABFWLAILxuxCBw+WbAARViwAi8bsQIQPlmwAEVYsAYvG7EGED5ZsABFWLAKLxuxChA+WbINCAIREjmwDS+yAAEKK1gh2Bv0WbAE0LIOCAIREjkwMQEjAyMTIwMjATMTIwEhAwNVp0y4TZbeyQL6p/i4/hoBhlsBtv5KAbb+SgWw+lACWgJHAAL/ogAAA5oEOgALABAAVgCwAEVYsAgvG7EIGD5ZsABFWLACLxuxAhA+WbAARViwBi8bsQYQPlmwAEVYsAovG7EKED5Zsg0CCBESObANL7IBAQorWCHYG/RZsATQsg8IAhESOTAxASMDIxMjAyMBMxMjASEDJwcCpnQ0tTRyqMECaJz0sf52ASVIBSgBKf7XASn+1wQ6+8YBwQFGTFsAAgBaAAAGVQWwABMAFgB8ALAARViwAi8bsQIcPlmwAEVYsBIvG7ESHD5ZsABFWLAELxuxBBA+WbAARViwCC8bsQgQPlmwAEVYsAwvG7EMED5ZsABFWLAQLxuxEBA+WbIVAgQREjmwFS+wANCwFRCyBgEKK1gh2Bv0WbAK0LAGELAO0LIWAgQREjkwMQEhATMTIwMjAyMTIwMjEyEDIxMzASEDAX8BdgHBp/i5RqdMuE2V4Mjn/sJNvf29AaMBhVoCWQNX+lABtv5KAbb+SgG4/kgFsPyqAkcAAgBOAAAFSwQ6ABMAGAB/ALAARViwAi8bsQIYPlmwAEVYsBIvG7ESGD5ZsABFWLAELxuxBBA+WbAARViwCC8bsQgQPlmwAEVYsAwvG7EMED5ZsABFWLAQLxuxEBA+WbIAEBIREjmwAC+wAdCyDgEKK1gh2Bv0WbAL0LAH0LABELAU0LAV0LIXEgQREjkwMQEhATMTIwMjAyMTIwMjEyMDIxMzASEDJwcBUQECAWmb9LBDdTS1NXOowarGNLW8tgFRASVIBicBwQJ5+8YBKf7XASn+1wEo/tgEOv2HAUZMWwACACYAAAYvBbAAHgAiAHayDiMkERI5sA4QsB/QALAARViwHS8bsR0cPlmwAEVYsBYvG7EWED5ZsABFWLAGLxuxBhA+WbAARViwDi8bsQ4QPlmyGw4dERI5sBsvsADQsBsQshIBCitYIdgb9FmwDNCwGxCwH9CwHRCyIgEKK1gh2Bv0WTAxATMyFgcDIxM2JyYnJwcDIxMnJyYGBwMjEzYkMzMBBQEzAQUEQg3Y1Rg8vT0IBxXJdx5tvXIGgJmoGD28PR4BEPgk/vwEhv08DwFo/dUDJ+bQ/o8BckM0oAMCJf2XAngTAwKIkf6JAXHb3wKFAv18AegBAAIAKQAABQsEOgAcACAAWACwAEVYsAUvG7EFGD5ZsABFWLAcLxuxHBA+WbIEHAUREjmwBC+wB9CwHBCwFdCwDNCwBBCyGAEKK1gh2Bv0WbAR0LAEELAd0LAFELIgAQorWCHYG/RZMDEzNzY2NwMhARYWBwcjNzYnJicnBwMjEycnJgYHBwEXEyEpGh7t1rwDo/6Nq6cWGbYZBwIKtTURT7VUAzqDmxgcAfUJ6/6fqtLXCQHe/h4L5MWkpT0zqAcCFv5QAbwJAQKCj7cCXAEBRwACAEgAAAhaBbAAJAAoAJmyICkqERI5sCAQsCjQALAARViwBy8bsQccPlmwAEVYsAsvG7ELHD5ZsABFWLAALxuxABA+WbAARViwBS8bsQUQPlmwAEVYsBMvG7ETED5ZsABFWLAcLxuxHBA+WbIJBQcREjmwCS+yBAEKK1gh2Bv0WbAJELAN0LAEELAZ0LAEELAf0LAJELAl0LALELIoAQorWCHYG/RZMDEhEzY3BQMjEzMDIQEhATMWFxYHAyMTNicmJycHAyMTJycmBgcDATMBBQJHQyFf/m1zvP28cANF/vQEkP4KE9ZoaBc8vT0IBxSwkR9tvHIHgJWqGD4CiQ8BaP3VAYyoYwP9bAWw/XwChP13AXJz0P6PAXJDNJQNBCf9mQJ3FAICg5X+iQMqAegBAAACAC4AAAbtBDoAIgAmAIwAsABFWLALLxuxCxg+WbAARViwCC8bsQgYPlmwAEVYsAUvG7EFED5ZsABFWLAALxuxABA+WbAARViwGy8bsRsQPlmwAEVYsBIvG7ESED5ZsgkFCBESObAJL7IEAQorWCHYG/RZsAkQsA3QsAQQsBfQsAQQsB7QsAkQsCPQsAsQsiYBCitYIdgb9FkwMSE3NjcFAyMTMwMhAyEBFhYHByM3NicmJycHAyMTJyciBgcHARcTIQIKHB1f/pBPtby2VALBxAOk/oyupBYZthkHAgq1NRFPtVQDR4GUFxkB9Qnr/p+qs2oD/jwEOv4iAd7+HQ3kwqSlPTOoBwIW/lABvAgCiZmkAlwBAUcAAv/O/kgEIQeIAC0ANgCGALAzL7AARViwCS8bsQkcPlmwAEVYsB4vG7EeEj5ZsABFWLAYLxuxGBA+WbAJELIIAQorWCHYG/RZsBgQsC3QsC0vsiwBCitYIdgb9FmyECwtERI5sBgQsiQBCitYIdgb9FmyDzMBXbAzELA20LA2L7QPNh82Al2yLjM2ERI5sDDQsDAvMDEBMjY3NiYnJyU3BR4CBwYFFhYHDgIjJwYGBwYXByYmNzY2MzMyNjc2JicnNwE3NxcBIwM1FwGzk78QDHBzD/7LGwEeesNhCBH+7mpkCQqL7I00UVkGEI5RbWsDBb2pIIzADw6GkZUbAZuxoAH+4m/NlgM2g3pheQkBAZgBA2OqcdVwLK5xgsVrAQM/Nm9EejmhW36Jmn15hQUBmAOmqAMN/u8BEA4CAAL/yv5IA5gGMgAoADEAnwCwLi+wAEVYsAgvG7EIGD5ZsABFWLAbLxuxGxI+WbAARViwFS8bsRUQPlmwCBCyBwEKK1gh2Bv0WbAVELAo0LAoL7IvKAFdsv8oAV2yjygBcbK/KAFdss8oAXGyXygBcrInAQorWCHYG/RZsg8nKBESObAVELIhAQorWCHYG/RZsC4QsDDQsDAvtA8wHzACXbIpLjAREjmwK9CwKy8wMQEyNjc2JiclNwUWFgcGBgcWFgcGBCMjBgcGFwcmJjc2NjMyNjc2Jyc3ATc3FwEjAzUXAYiHmQsJZ23+zxwBGLTPCAVndlZTBAj++9QinxEQjlJncQQFuriMmQsV+KQbAT6xnwH+4m/NlwJoVlM/TQMBmQEFpIJJdjMjdkuYswVza0l5NqFefYpfUZYGAZgDHqgDDf7vARAOAgADAGn/6QT8BcgAEgAbACQAZrIIJSYREjmwCBCwFNCwCBCwHdAAsABFWLAJLxuxCRw+WbAARViwAC8bsQAQPlmwCRCyEwEKK1gh2Bv0WbIWAAkREjl8sBYvGLAAELIcAQorWCHYG/RZsBYQsiABCitYIdgb9FkwMQUmAicmEjc2JBcWEhcWBwcGAgQTJgIDITY3NiYBFjY3IQYXFBYCQtP3CgU3R2ABKLfU9gkDCgwfwv7nMbH3OwL+CAIDmP6ervU6/QIHAZgUBAEf9G4BUIq7wgQE/uP3VFNU2f62pQU3Bf75/vw4PL7Q+3MG/P42ObHQAAMAQv/nBCAEUwARABgAHwBNALAARViwBC8bsQQYPlmwAEVYsA0vG7ENED5ZshIBCitYIdgb9FmyHA0EERI5fLAcLxiyFgEKK1gh2Bv0WbAEELIZAQorWCHYG/RZMDETNhI2Fx4CBwcGAgYnLgI3ARY2NyEGFgEmBgchNiZUFJvvj4i/WBACFJzvjoi/WBABl3i4OP2wDHwBB3m3NQJNB34CIJ4BBo8EBI/8lhed/v6NBASO+JX+eAWpsJDBAzIDqqKQtgABAK0AAAVLBcYADwA/ALAARViwDy8bsQ8cPlmwAEVYsAYvG7EGHD5ZsABFWLANLxuxDRA+WbIBDQ8REjmwBhCyCA4KK1gh2Bv0WTAxARc3ATY2MxcHIyYHASMDMwIJCDwBfUmbajMVCmhF/cKn7cQBbneGAyKqfQKrA5T7eAWwAAEAhAAABDwEUAAQAEayAhESERI5ALAARViwBS8bsQUYPlmwAEVYsBAvG7EQGD5ZsABFWLANLxuxDRA+WbIBDRAREjmwBRCyCgEKK1gh2Bv0WTAxARc3EzYzMhcHJiMiBwEjAzMBmgQs8GasPDQkFhNKOv5YibaxATJXaQIe7huSCXH8xQQ6AAACAGr/cwT6BjUAFQApAEgAsABFWLALLxuxCxw+WbAARViwAy8bsQMQPlmwANCwCxCwDtCwCxCyGwEKK1gh2Bv0WbAY0LAAELIlAQorWCHYG/RZsCLQMDEFByM3JgInJjcSADc3FwcWEhcUBwIAEwInByc3BgIPAgIXNxcHNhI3NgKZG7UbsMYDARoyATvqGbUar7oCHjT+0cgPthS1FprMJBEJFOYWtReXxCIfDIGBIAEg4W6aASEBYR93AXon/uDceqL+6v6vA78BAz1iAWYi/vnVcmX+m0ZnAWYnAQfeyQAAAgBE/4gELQS2ABMAJwBLALAARViwAC8bsQAYPlmwAEVYsA0vG7ENED5ZsAAQsAPQsA0QsArQshQBCitYIdgb9FmwABCyHQEKK1gh2Bv0WbAa0LAUELAl0DAxATcXBxYSBwcGAgcHJzcmAjc3NhITNhI1NCYnByc3BgYHBwYVFBc3FwI2F7UYoaIWAhz/xRe1F56eFQMe/M+JmkpFFbUWcY0XAgeKFrUERXEBcSb+2s4X2/7cIGwBbiYBI8oW4wEh/GkvARbEZJAeYwFkK8qRFTM50EFnAQAAAwB0/+YGmgdWADEARABMAJkAsABFWLAWLxuxFhw+WbAARViwDS8bsQ0QPlmwFhCwANCwDRCwCNCyCw0WERI5sBYQshcBCitYIdgb9FmwDRCyHwEKK1gh2Bv0WbIjFg0REjmwKNCwFxCwMdCwFhCwPNCwPC+wNNCwNC+yMgIKK1gh2Bv0WbA0ELA30LA3L7JAAgorWCHYG/RZsDwQsEjQsEgvsEzQsEwvMDEBFhYHAw4CJyYmJwYnJiY3NxM2NzY3BwYDAwYXFhYXFjY3EzMDBhYXFjY3EzYnJiYnEwcnJiQjIgYHByc3NjYXHgMBNjc3FwcGBwU/q7AXXBN8wXpsoyOI26OxCgNfI3l5vhLaMVkFAgJQSmyZFUe8Rg5mZ2GGGF0GAQJNSawKPkb+8Ew2RQkCfQMJhW0wV7Zb/gBMDxKaDxObBa8J98X9xYnSbgQCXU6xBAXhuSYCVMlxcASeB/7N/dUtMllrBAWMfgGt/lN1jQQDlZACQy8yVWgGAcWBAgZ6OzUSASRscgIBGE8Y/pJRQWABZW9ZAAADAFL/5QWmBfYAKwA/AEcAkgCwAEVYsBMvG7ETGD5ZsABFWLAMLxuxDBA+WbATELAA0LAMELAH0LATELIUAQorWCHYG/RZsAwQshsBCitYIdgb9FmyHwwTERI5sCTQsBQQsCvQsBMQsDbQsDYvsC3QsC0vsiwCCitYIdgb9FmwLRCwMtCwMi+yOwIKK1gh2Bv0WbAtELBE0LBEL7BH0LBHLzAxARYWBwMGBicmJicGJyYmNxM2NjcHBgMDBwYWFxY2NzczBwYWFxY2NxM3NCcTBy4DIyYGBwcnNzY2Fx4DATY3NxcHBgcEdJqYEiob2aRijiF9vJieEywd164RuScpAwNCQVuDESa0JAtZV1JwEy0EfO0KWFKxWC01RgkCfQILhW0vV75V/fxJDhWbDhSYBEQJ4bL+38TdBAJPRJoGA+O1AS+/zgSYB/7z/uQtY2sCBXlr7OxkegIDiIABM0ShDQHKgQIXTRoBOjUSASRtcQIBGFIV/ohQNW0BZXJXAAACAG//4gbjBwMAIgAqAHUAsABFWLAZLxuxGRw+WbAARViwDy8bsQ8cPlmwAEVYsCIvG7EiHD5ZsABFWLAKLxuxChA+WbAE0LIICg8REjmwChCyFQEKK1gh2Bv0WbAe0LAZELAp0LApL7Aq0LAqL7IkBgorWCHYG/RZsCoQsCfQsCcvMDEBAwYGByMmJicGJyYmNxMzAwYXFhYXFjY3EzMDBhYXFjY3EyU3IQchByM3BuO0G/azDm2aII3bq7QTtLyzBQQHUkVrmha0wrMMXl5kjhW2/IcTAxUS/r8WpBYFsPvdwOIBAmBPuQgG57YEI/vcLS1OWgMFioAEJPvceIoDA4Z3BC/oa2t9fQAAAgBP/+YF3wWwACAAKABgALAARViwFy8bsRcYPlmwAEVYsAgvG7EIED5ZsATQsBcQsA3QsAgQshMBCitYIdgb9FmwHNCwFxCwINCwFxCwJ9CwJy+wKNCwKC+yIgYKK1gh2Bv0WbAoELAl0LAlLzAxAQMGBicmJwYnJiY3EzMDBhcWFhcWNjcTMwMGFhcWNjcTATchByEHIzcF33sX3qu+RHu+m58RerR6BAMDRDxbgxJ7tnoKT09VeBJ6/NsUAxQQ/r4XpRcEOv0or80EBY+YBATUnwLZ/SYmJkBQAwR4awLa/SZmdwIDdW0C2gELa2uAgAABAGb+hATyBcgAHABCALABL7AARViwCy8bsQscPlmwAEVYsAIvG7ECED5ZsAsQsA/QsAsQshIBCitYIdgb9FmwAhCyGwEKK1gh2Bv0WTAxASMTJiYCNzc2EiQXFhIHIzYmJyYGBgcDBxQWFxcCWbtFgrJJFCYevQEJmt33DrwLkI5otoQWKgSNfHv+hAFuGLABDZT0vwEnkwME/vXZnKsEA27iif7yTqXEBAEAAQBN/oID5ARSABkAQgCwAS+wAEVYsAsvG7ELGD5ZsABFWLACLxuxAhA+WbALELAP0LALELISAQorWCHYG/RZsAIQshgDCitYIdgb9FkwMQEjEy4CNzc+AhcWFgcnNiYnJgIHBhYXFwHptUZpijoOBBOX5YilyQiqBmtfmcsCA2pmbv6CAXIZlOKCK5r+igQE3qgBZYkEBv7b5IijBgEAAAEAQAAABLgFPgATABMAsA4vsABFWLAELxuxBBA+WTAxARcHJwMjASc3FwEnNxcTMwEXBycCLPxS/OqwASX7Uv4BDf1U/PKs/tT/VfoBt6xyqf6+AZWrcqoBdat0qgFM/mGrcakAAAH86ASm/9AF/AAHABEAsAAvsgMGCitYIdgb9FkwMQEHJzchNxcH/aEXoioCCxKhJgUjfQHpbAHYAAAB/QsFFv/qBhQAEwArALASL7AN0LANL7IFAgorWCHYG/RZsBIQsArQsBIQshMCCitYIdgb9FkwMQE+AxcWFgcHJzc2JyYGBgcHN/08QHhudz1lbwUDegIIYCxU+kNKDAWVASktKAEBb2YnARRkBAESZQUBfwAAAf4XBRX+5AZXAAUADACwAS+wBdCwBS8wMQE3MwcXB/4XFK8bJU0F5XKXcjkAAAH+OwUX/1EGVwAFAAwAsAMvsADQsAAvMDEBJzc3Mwf+gkdQFbEYBRdIeX+EAAAI+jj+wgGUBbEACwAXACMALwA7AEcAUwBfAHoAsD8vsEsvsFcvsDMvsABFWLADLxuxAxw+WbIJCworWCHYG/RZsD8QsA/QsD8QskULCitYIdgb9FmwFdCwSxCwG9CwSxCyUQsKK1gh2Bv0WbAh0LBXELAn0LBXELJdCworWCHYG/RZsC3QsDMQsjkLCitYIdgb9FkwMQE2NhcWFhUnNiMmBwE2NhcyFhUnNiMmBwM2NjMWFhUnNiMiBwE2NhcWFhUnNiMiBwE2NhcWFhUnNiMmBwE2NhcWFhUnNiMmBwE2NhcWFhUnNiMiBwM2NhcWFhUnNiMiB/2TCnFbWGlsBVFTHQGfCXFaWGpsBVJSGxEIcVtYaGsFUVMd/nsIc1hYaGsFUVUa/TEKcVtYaGsFUVIe/kIKc1pYaWwFUVQb/pAJcFtYaGsFUlQbJghzWVhpbAVSUxsE81llAQFmWAFmAmb+6lhmAWlWAWYCZv4IVWcBZVgBZmT9+FdnAgFlWAFmZP7jWWUBAmVYAWYCZgUZWWUBAmVYAWYCZv4IWGUBAWVYAWZk/fhXZwIBZVgBZmQACPpP/mMBUwXGAAQACQAOABMAGAAdACIAJwA5ALAhL7ASL7ALL7AbL7AmL7AARViwBy8bsQccPlmwAEVYsBYvG7EWGj5ZsABFWLACLxuxAhI+WTAxBRcDIxMTJxMzAwE3BQclBQclNwUBNyUXBQEHBSclEycDNxMBFxMHA/3FDaxlf6ENq2R+AawLATcR/sD7jgr+yREBQAPNAwFMPf7N/GgD/rU+ATRpEV1DlAKzEF5FkjoS/q8BYASiEAFR/qH+EQp/XEU8Cn9bRAGuEZlNv/yNEplOvwLlAgFPPv7Q/OYC/rI/AS8AAAIALv/8A8MGcQASABsAdLIQHB0REjmwEBCwFdAAsABFWLANLxuxDRw+WbAARViwES8bsREcPlmwAEVYsAkvG7EJED5ZsBEQsgABCitYIdgb9FmyAg0JERI5sAIvsAAQsAvQsAzQsAIQshMBCitYIdgb9FmwCRCyFAEKK1gh2Bv0WTAxASEDFxYWBwYGJyETIzczNzMHIQEDFzY2NzYmJwL9/slh/aW8DA77tf414robuSK2IgE4/jNN/2iODA1XVgUY/dIBBsSesNUEBRiYwcH8ov5FAgJ7aVt3BAACADoAAATuBbAADwAcAE2yDx0eERI5sA8QsBjQALAARViwBC8bsQQcPlmwAEVYsAEvG7EBED5ZshcEARESObAXL7IAAQorWCHYG/RZsAQQshUBCitYIdgb9FkwMQEDIxMFHgIHBgcXBycGIwE2NzYmJyUDITI3JzcBWmO9/QH9ic1kDhKDYnNqgKgBODUNEoZ+/qhjATxeWlV0Ajr9xgWwAQRtxH+6e5BemDYBG01XfpYEAf3FH4BdAAAC/9f+YAP9BFIAFQAmAG6yIicoERI5sCIQsAfQALAARViwEC8bsRAYPlmwAEVYsAwvG7EMGD5ZsABFWLAKLxuxChI+WbAARViwBy8bsQcQPlmyCRAHERI5sg4QBxESObAQELIaAQorWCHYG/RZsAcQsh8BCitYIdgb9FkwMQEGBxcHJwYnJicDIwE3BzYXFhYXFgcnNzYmJyYHAxYXMjcnNxc2NwP0II1XdFNpZbhkYbUBBKQUhrubsAUBB7cGA29rnXJbO5pEVE50RUgXAhfxnYNeezgCAnv99gXaAXmQBATgwkA8AVSLogQEmf35jQQpeF5ob40AAAEANQAABM0HAAAJADWyAwoLERI5ALAIL7AARViwBi8bsQYcPlmwAEVYsAQvG7EEED5ZsAYQsgIBCitYIdgb9FkwMQEjFSEDIxMhEzMEhAP9UOG7/AKyPK4FGAb67gWwAVAAAQAkAAADtAV2AAcALgCwBi+wAEVYsAQvG7EEGD5ZsABFWLACLxuxAhA+WbAEELIAAQorWCHYG/RZMDEBIQMjEyETMwNj/hihtrwB6Di0A6H8XwQ6ATwAAAEAQ/7eBKUFsAAWAFuyAxcYERI5ALAKL7AARViwFS8bsRUcPlmwAEVYsBMvG7ETED5ZsBUQsgABCitYIdgb9FmyAxUTERI5sAMvsAoQsgsDCitYIdgb9FmwAxCyEQEKK1gh2Bv0WTAxASEDFxYWEgcCAAc3NjY3NiYnJwMjEyEEif1YUaSm6moRHP7k6w6TtRcWp6+zdL39A2UFEv4vAQSO/wCn/v3+3gSSA87Hw9IBAf1hBbAAAQAk/uEDegQ6ABYAW7IMFxgREjkAsAovsABFWLAVLxuxFRg+WbAARViwEy8bsRMQPlmwFRCyAAEKK1gh2Bv0WbICFRMREjmwAi+wChCyCwEKK1gh2Bv0WbACELISAQorWCHYG/RZMDEBIQMXHgIHBgIHJzY2NzYmJycDIxMhA1/+HDFjh81kDRH2siR5nhAPin96VLa8ApoDof7kAQR404Sp/v8mliCdf4miBAH+HQQ6AAEANgAABUgFsAAUAGIAsABFWLAALxuxABw+WbAARViwDC8bsQwcPlmwAEVYsAIvG7ECED5ZsABFWLAKLxuxChA+WbAP0LAPL7IvDwFdss8PAV2yCAEKK1gh2Bv0WbIBCA8REjmwBdCwDxCwEtAwMQkCIwMjByM3IwMjEzMDMxMzAzMBBUj9/AEo4OJSK5EsZHK8/L1wZC2RLkUBqQWw/UT9DAKO9PT9cgWw/X8BAP8AAoEAAAEALQAABJMEOgAUAHsAsABFWLANLxuxDRg+WbAARViwFC8bsRQYPlmwAEVYsAovG7EKED5ZsABFWLADLxuxAxA+WbAKELAO0LAOL7KfDgFdsv8OAV2ynw4BcbS/Ds8OAl2yLw4BXbJvDgFysgkBCitYIdgb9FmyAQkOERI5sAXQsA4QsBLQMDEJAiMDJwcjNyMDIxMzAzM3Mwc3AQST/lcBBdm7MieRI2FQtry2UWEmkSsnAUsEOv30/dIBzQHDwv4zBDr+NtXXAQHLAAEAuwAABswFsAAOAGsAsABFWLAGLxuxBhw+WbAARViwCi8bsQocPlmwAEVYsAIvG7ECED5ZsABFWLANLxuxDRA+WbIIBgIREjmwCC+yLwgBXbLPCAFdsgEBCitYIdgb9FmwBhCyBAEKK1gh2Bv0WbIMAQgREjkwMQEjAyMTITchAzMBMwEBIwOFsXG94v4zGwKJb4kCXPf9YgG92AKO/XIFGJj9fgKC/Tb9GgABAHQAAAWMBDoADgCAALAARViwBi8bsQYYPlmwAEVYsAovG7EKGD5ZsABFWLACLxuxAhA+WbAARViwDS8bsQ0QPlmwAhCwCdCwCS+ynwkBXbL/CQFdsp8JAXG0vwnPCQJdsi8JAV2ybwkBcrIAAQorWCHYG/RZsAYQsgQBCitYIdgb9FmyDAAJERI5MDEBIwMjEyE3IQMzATMBASMC8opQtqL+cBwCRFBuAbDq/fwBXNYBzf4zA6GZ/jYByv3v/dcAAAEAOgAAB+AFsAANAF4AsABFWLACLxuxAhw+WbAARViwDC8bsQwcPlmwAEVYsAYvG7EGED5ZsABFWLAKLxuxChA+WbAB0LABL7IvAQFdsAIQsgQBCitYIdgb9FmwARCyCAEKK1gh2Bv0WTAxASETIQchAyMTIQMjEzMBhwLGbQMmG/2W4rt1/Tl1vf29Az4Ccpj66AKh/V8FsAABACQAAAWUBDoADQCbALAARViwAi8bsQIYPlmwAEVYsAwvG7EMGD5ZsABFWLAGLxuxBhA+WbAARViwCi8bsQoQPlmwBhCwAdCwAS+ybwEBXbS/Ac8BAl2yPwEBcbTPAd8BAnGyDwEBcrSfAa8BAnGy/wEBXbIPAQFxsp8BAV2yLwEBXbRvAX8BAnKwAhCyBAEKK1gh2Bv0WbABELIIAQorWCHYG/RZMDEBIRMhByEDIxMhAyMTMwFEAeFRAh4b/piitFD+H1C2vLYCZQHVmfxfAc7+MgQ6AAABAEL+3gdvBbAAFwBoshEYGRESOQCwBy+wAEVYsBYvG7EWHD5ZsABFWLAULxuxFBA+WbAARViwES8bsREQPlmyARYHERI5sAEvsAcQsggBCitYIdgb9FmwARCyDgEKK1gh2Bv0WbAWELISAQorWCHYG/RZMDEBMxYABwIABzc2Njc2JicjAyMTIQMjEyEFAWr9AQcaHP7k6w6TtRcWoq2BdLzh/UnhvP0ELwNABv7M//79/t4EkgPOx8DSBP1iBRL67gWwAAABACT+4QZBBDoAGABXALAIL7AARViwGC8bsRgYPlmwAEVYsBUvG7EVED5ZsBLQsgASGBESObAAL7AIELIJAQorWCHYG/RZsAAQshABCitYIdgb9FmwGBCyEwEKK1gh2Bv0WTAxARceAgcGBgcnNjY3NiYnJwMjEyEDIxMhA+CWi9dpDhH1siSAlg8QkYmuVLSh/h6htrwDTAKFAQN31ISs/yaWIqJ4hKcEAf4dA6H8XwQ6AAACAHH/4wWpBccAKgA5AIEAsABFWLAfLxuxHxw+WbAARViwBC8bsQQQPlmwANCyAgQfERI5sAIvsB8QsA7Qsg8BCitYIdgb9FmwBBCyFwEKK1gh2Bv0WbACELItDgorWCHYG/RZshkCLRESObIoLQIREjmwABCyKgEKK1gh2Bv0WbAfELI0AQorWCHYG/RZMDEFJicGJy4CJyY3NxIANwcGBg8CFBYXFjcmEzc2EhceAhcWBwcCBxYXARYXNhM3NicmJyYGBwcGBRXNo5ufjdmCCwcPGTEBIdQSh7IhHAOolTpMvykiJ/66ZJJOAgEHJDX4XnT98gqZ2zEgDgQLj2iQHiIKHQRFQgIDgvCaXGCkARoBTQWlBfzdwla54QICEOcBNt36ATUFA23Jdz856P6uxRQCAbHWd5oBPM5ZUOMHBMnB3EIAAAIAX//qBFoEVQAnADIAgQCwAEVYsB4vG7EeGD5ZsABFWLAELxuxBBA+WbAA0LICBB4REjmwAi+wHhCwDdCyDgEKK1gh2Bv0WbAEELIWAQorWCHYG/RZsAIQsioBCitYIdgb9FmyGAIqERI5siUqAhESObAAELInAQorWCHYG/RZsB4QsjABCitYIdgb9FkwMQUmJwYnLgInJhI2NjcHBgYHBwYWFhcWNyY3NzY2FxYWFxYHBgcWFwEGFzY2NzUmJyYDBBulg4SCbq5kBwczcKdsEmB4EAMCLmZJIz6OHQsawZF1hgMCFiOcQ2H+bhaDTEoLBVeEIQ0ENUICAXDSgHQBB7hrA54FzsY4YJ9WAQEMtvBZzfMFBL6gT4XbnQ8CAajSeE7hvymqBAT+7QAAAQCs/qEGYwWwABMAWwCwES+wAEVYsAcvG7EHHD5ZsABFWLAMLxuxDBw+WbAARViwEy8bsRMQPlmwBxCyCAEKK1gh2Bv0WbAA0LAHELAF0LAD0LAC0LATELIKAQorWCHYG/RZsA7QMDEBITchNTMVIQchAyETMwMzAyMTIQIY/pQaAWS8AX4b/ovHArjhveGUa6g9+/YFGJcBAZf7hQUT+vH+AAFfAAEAV/6/BMgEOgAPAEsAsA0vsABFWLADLxuxAxg+WbAARViwDy8bsQ8QPlmwAxCyBAEKK1gh2Bv0WbAA0LAPELIGAQorWCHYG/RZsAMQsAjQsAYQsArQMDEBITchByMDIRMzAzMDIxMhAWH+9hoCsRvxiAHioraifWSiOPzqA6OXl/z0A6P8Xf4oAUEAAQDEAAAFOQWwABkAUbIHGhsREjkAsABFWLAALxuxABw+WbAARViwDC8bsQwcPlmwAEVYsA8vG7EPED5ZsgYADxESOXywBi8YsAnQsAYQshUBCitYIdgb9FmwEtAwMQEDBhcWFhcTMwM2NxMzAyMTBgcHIzcmJjcTAeJLCQgMbms7kjhijny9/bxudX0uki7U0hdLBbD+N0Y1UFIGATb+0Q0hArf6UAJcIwzv6gfi2AHHAAEAmAAABBoEOwAYAEoAsABFWLAXLxuxFxg+WbAARViwDC8bsQwYPlmwAEVYsAEvG7EBED5ZshEBDBESOXywES8YsgcBCitYIdgb9FmwBNCwERCwFNAwMSEjEwYHByM3JiY3EzMDBhcWFxMzAzY3EzMDXrZKNGUckhyWmRIytTQFAQN7NpM0PVphtgGJDw2IhxLUrQE8/sMrKIsdARj+6QgTAhsAAQDsAAAFYgWwABIAPwCwAEVYsAIvG7ECHD5ZsABFWLASLxuxEhA+WbAARViwCi8bsQoQPlmyBRICERI5sAUvsg8BCitYIdgb9FkwMTMTMwM2FxYWBwMjEzYnJicmBwPs/bxvscne1BdMvEsICBjPoeB9BbD9pDcCBOrU/jkByEU2oQYDNv1JAAIAiv/rBcUFyAAjAC4AVwCwAEVYsBEvG7ERHD5ZsABFWLAALxuxABA+WbIlABEREjmwJS+yFwEKK1gh2Bv0WbAF0LAlELAN0LAAELIeAQorWCHYG/RZsBEQsioBCitYIdgb9FkwMQUmJgI3NyYmNxcGFxYXNxIAFxYSFxYHByEHBhcWFhcWNjcXBgElNjc2JicmBgcHA3Or+m0bE4WAC5MEAwprFE4BPNjJ5AUBDRD8ng8MCxCoi16qVSKA/eACqw4CA4qEjdM8DxUBpQEfq2caxpgCKCR2K0wBCgEnBQT+9u1aUmReWlOGmgMCLiWQYANXAk48obEEBMrQOgAAAgAH/+oERwRTAB8AKQBeALAARViwDy8bsQ8YPlmwAEVYsAAvG7EAED5ZsiQADxESObAkL7S/JM8kAl2yFQEKK1gh2Bv0WbAF0LAkELAM0LAAELIZAQorWCHYG/RZsA8QsiABCitYIdgb9FkwMQUuAjc3JiY3FwcGFzYkFxYWFxYHByEGFhcWNjcXBgYTJgYHBTc2JyYmAlCFy1cXBGBdB48EAz9GARippr0GAggM/T0ThH9ckT1oSNwFba00Ag4ECAcLaRQCkPCJEx6rhgE3Xi3Q7QUE2LZAQVOYygMCUUFYaGkDzQWdnwISNTRUZwAAAQA1/tMFRAWwABYAXbIVFxgREjkAsA4vsABFWLACLxuxAhw+WbAARViwBi8bsQYcPlmwAEVYsAAvG7EAED5ZsgQAAhESObAEL7AI0LAOELIPAQorWCHYG/RZsAQQshYBCitYIdgb9FkwMTMjEzMDMwEzARYSBwIABzc2Njc2Jicl8r39vW14Al/r/ZDT2Bga/t7qC5K1Fxajrf71BbD9jwJx/YQY/s/q/v3+2waaAs3EwNMBAQABAC3++gRWBDoAFgBjALAGL7AARViwEi8bsRIYPlmwAEVYsBUvG7EVGD5ZsABFWLAPLxuxDxA+WbAT0LATL7S/E88TAl2yLxMBXbL/EwFdsADQsAYQsgcBCitYIdgb9FmwExCyDgEKK1gh2Bv0WTAxARYWBwYGByc2Njc2JicnAyMTMwMzATMCbKOqEBHzsSR/lw0PjJOwULa8tlFQAc7qAmAg6KKl8iWWH5pvf5AFAf4zBDr+NgHKAAABAEP+RwVtBbAAFABmALAIL7AARViwAC8bsQAcPlmwAEVYsAMvG7EDHD5ZsABFWLASLxuxEhA+WbIBEgAREjl8sAEvGLIfAQFxtGABcAECXbKQAQFdsAgQsg0BCitYIdgb9FmwARCyEQEKK1gh2Bv0WTAxAQMhEzMBBgYnIic3FjMyNxMhAyMTAfxyArVzu/75GcKVLkkeOCiMI3j9S2+9/QWw/W4Ckvn8rbgCFJkR0gLK/X8FsAAAAQAk/kcEKwQ6ABQAfgCwAEVYsAAvG7EAGD5ZsABFWLADLxuxAxg+WbAARViwCC8bsQgSPlmwAEVYsBIvG7ESED5ZsAHQsAEvsm8BAV20vwHPAQJdsv8BAV2yDwEBcbKfAQFdsi8BAV2yPwEBcbAIELINAQorWCHYG/RZsAEQshEBCitYIdgb9FkwMQEDIRMzAwYGJyInNxYzMjcTIQMjEwGWUgHhUrTHFr6WLEsfNSuMI1r+H1C2vAQ6/isB1fttp7kCFJIQ0wIc/jIEOgACAFH/6QUqBcYAGgAkAF6yGiUmERI5sBoQsBzQALAARViwAC8bsQAcPlmwAEVYsAkvG7EJED5Zsg8ACRESObAPL7AAELIVAQorWCHYG/RZsAkQshsBCitYIdgb9FmwDxCyHwMKK1gh2Bv0WTAxARYEEgcHBgIEJyYmAjc3BTc2JyYmJyYHJzY2AxY2NwUHBhcWFgMAuAEBcRoMHdD+3aWv7GMaFAPQAxUJD72YpsojRNQopftH/OgHDwoQpAXDArP+vsZVzv6wqgMEpwEtv3wDDGNgnLkDA1aRLzb6wwX18gEjWVCBkQAAAQA8/+cEewWwABsAZbIZHB0REjkAsABFWLACLxuxAhw+WbAARViwDC8bsQwQPlmwAhCyAAEKK1gh2Bv0WbIEAAIREjmyBQIMERI5sAUvsAwQsBDQsAwQshMBCitYIdgb9FmwBRCyGQMKK1gh2Bv0WTAxASE3IQcBFhYHDgInJiY3MwYWFxY2NzYmJyc3A3z9kRwDUhf+I7TEDguQ8o2+3Qy6CHtug78QEYKLlBwFEp6G/iQQ5rqDyGwDBOy6dJMEBJZ/jJIEAaAAAAH//P5xBDUEOgAaAGGyBRscERI5ALALL7AARViwAi8bsQIYPlmyAAEKK1gh2Bv0WbIEAAIREjmyGgsCERI5sBovsAXQsAsQsQ8KK1jYG9xZsAsQshIBCitYIdgb9FmwGhCyGQEKK1gh2Bv0WTAxASE3IQcBFhYHBgQnJiY3MwYWFxY2NzYmJyc3Ayz9ohsDTBX+J7S/DhH+1dq93Qy0CHxwhsMPEIiKlBsDoZl//hYS4rXE8wQE7LhzmAQEm36NkAQBoP////j+RQTnBbAAJgCwQgAAJgHeuUAABwGvAOkAAP///+n+RQPQBDoAJgDrTQAAJgHem44BBwGvANoAAAAIALIACQFdMDEAAgAxAAAE4QWwAAoAEwBQsgQUFRESObAEELAN0ACwAEVYsAEvG7EBHD5ZsABFWLADLxuxAxA+WbIAAQMREjmwAC+wAxCyCwEKK1gh2Bv0WbAAELIMAQorWCHYG/RZMDEBEzMDJSYmNzYkMxMTJSIGBwYWFwPAY779/fvJ5RERAS7f4mP+to2/ERB6ewNzAj36UAEG68PN8v0pAjgBmoR3nQYAAgAy//4GMwWwABcAIABashghIhESObAYELAH0ACwAEVYsAgvG7EIHD5ZsABFWLAXLxuxFxA+WbIGFwgREjmwBi+wFxCyGAEKK1gh2Bv0WbAK0LIQBhcREjmwBhCyGgEKK1gh2Bv0WTAxJSYmNzYkMwUTMwMXNjYnJicXFhcWAgYnJRMlIgYHBhYXAeLN4xETASviAWBkveJLjZ4FAhOvDwgPc+WT/v5i/raMwBEQfXgBCO2/zfIBAj366wEC59FSUAFRUKv+65YCnQI4AZqEeZ0EAAACAEz/5gZBBhgAIwAzAICyBjQ1ERI5sAYQsCTQALAARViwBy8bsQcePlmwAEVYsAQvG7EEGD5ZsABFWLAeLxuxHhA+WbAARViwGi8bsRoQPlmyBgQeERI5sg4BCitYIdgb9FmyFAQeERI5shwEHhESObAEELImAQorWCHYG/RZsB4Qsi8BCitYIdgb9FkwMRM2EjYXFhcTMwMGFxYWFxYSEzYnNxYXFgIEJyYnBicmJicmNwEmJyYGBwcGFxYWFxY2NzdVFYzLgK5dbbXPBAQFQjmjxggCEKgNAweI/v2m7i2LzJexBwMGAuI/kIi2HgMHAwVrYVeDMwYCArIBFocDBIACTvtAJCU/SgMJAUEBImNkAWRj1/6gvwMFsbsEAtS1PTsBQoAEBd/TFDw/bX8DA1NCPwAAAQCt/+gFqgWwAC0AXACwAEVYsA4vG7EOHD5ZsABFWLAqLxuxKhA+WbIFLg4REjmwBS+yBAEKK1gh2Bv0WbAOELINAQorWCHYG/RZshUEBRESObAqELIdAQorWCHYG/RZsiMqDhESOTAxATYmJyc3FzI2NzYmJyU3BRYXFgcGBRYWFxYHBhYXFjYSNzYnMxYXFgIGJyYmNwKBCWNjyRyCobgQDXuA/pkcATn7cl8PFf71RlIGBAwHOz9dkFcGAxCvDAQGgvCfj5cIAXV2hwUCngGFhHJ8BAGeAQF/aqjncB96UTR5R1wEBYQBF8BjZGRj1v6fvwICqJsAAAEAaP/jBLgEOgAnAFkAsABFWLAeLxuxHhg+WbAARViwDi8bsQ4QPlmyAgEKK1gh2Bv0WbIHDh4REjmyFigeERI5sBYvshUBCitYIdgb9FmwHhCyHQEKK1gh2Bv0WbIlFRYREjkwMSUGFxY2NzYnFxYXFgIGJyYmNzc2Jyc3FzI2NzYnJTcXFhYHBgcHFgcCkQhSapYYGiipDwkSceWQfX0GCAux2BmrdYwKFdT+9xT4t8cKCJk+mA/TUwQFopCenQFOTpz+2aEDAnxyTYwKAZYBWVGfCwGWAQWljolPHTiyAAABAK/+1gOVBa8AJwBWALAbL7AARViwCi8bsQocPlmwAEVYsB4vG7EeED5ZsgEoChESObABL7IAAQorWCHYG/RZsAoQsgkBCitYIdgb9FmyEQABERI5sB4QsRcKK1jYG9xZMDETNxcyNjc2JiclNxcWFgcGBgcWFxYPAjcHBgcnNjcjJicmNzc2JievG5OnvA8Ne4D+6Bvu3eURC4mEkBAEBxcGqhckuWhXL2AhBQQIFg1nagJ5lwGLgXiABAGXAQHYvHGnO0CrMzWIGAGN3ZRMZ3crRyU/nHOOBAAAAQCg/sYDdgQ6ACMAVgCwGi+wAEVYsAovG7EKGD5ZsABFWLAdLxuxHRA+WbIBJAoREjmwAS+yAAEKK1gh2Bv0WbAKELIJAQorWCHYG/RZshEAARESObAdELEWCitY2BvcWTAxEzcXMjY3NiYnJTcFFhYHBgYHFhcWBwc3BwYHJzY3IyY3NzYnoBnEdo4LCmFn/uAbAQi1xwoFa3J3EAUGDJsWIrxnXixcKQYRD7EBuJcBWFNRVgMBlgEFpY5Qei0tfikoSwGO25VMc3srVI+fCQAAAf/f/+UHOwWwACQAYrIjJSYREjkAsABFWLAOLxuxDhw+WbAARViwIS8bsSEQPlmwAEVYsAYvG7EGED5ZsA4QsgABCitYIdgb9FmwBhCyCAEKK1gh2Bv0WbAhELIVAQorWCHYG/RZshsOBhESOTAxASEDBwICByM3NzY2NzcTIQMGFxYWFxYSEzYnNxYXFgIEJyYmNwSA/it3Jz/tt0sRM36dKxmQA0e8BAQFQTefwwgCEa8NAweJ/v2koJ0RBRL93bz+2/72BJwDDN3wjgKq+6kjJD5JAwkBPQEhY2QBZGPZ/qDABAbCqQAAAf/a/+UGBQQ6ACQAYrIAJSYREjkAsABFWLAOLxuxDhg+WbAARViwIS8bsSEQPlmwAEVYsAYvG7EGED5ZsA4QsgABCitYIdgb9FmwBhCyCQEKK1gh2Bv0WbAhELIVAQorWCHYG/RZshohDhESOTAxASEDBwYGByM3NzY2NzcTIQMGFxYWFxYSEzYnMxYXFgIGJyYmNwNR/sdSFjW+lU4TJmR+IA1iApx7AwMFQzeJoQUBEagNBQh55JCbnREDof6ObPLOA6ICBqnDSgHa/R4jJUBNAQYBJgEEXl5eXsT+s7AEBMCsAAABADv/5gc8BbAAHgB7ALAARViwGy8bsRscPlmwAEVYsB4vG7EeHD5ZsABFWLAYLxuxGBA+WbAARViwEi8bsRIQPlmyBgEKK1gh2Bv0WbILEh4REjmwGBCwHNCwHC+y/xwBXbJfHAFdss8cAV2yLxwBXbIfHAFxsk8cAXGyFwEKK1gh2Bv0WTAxAQMGFxYWFxYSEzYnNxYXFgIEJyYmNxMhAyMTMwMhEwVYugMDBUI1n8QGAhGwDQQHif7+ppycDS/9WG+9/b1zAqhyBbD7pyMkPkkBCAE/AR5jZAFkY9v+o8ADBMSpASf9fwWw/W4CkgABACP/5wYXBDoAHgCLALAARViwBS8bsQUYPlmwAEVYsAgvG7EIGD5ZsABFWLAbLxuxGxA+WbAARViwAi8bsQIQPlmwBtCwBi+ybwYBXbL/BgFdsg8GAXG0nwavBgJxsj8GAXG0vwbPBgJdsi8GAV20zwbfBgJxsgEBCitYIdgb9FmwGxCyDwEKK1gh2Bv0WbIUGwgREjkwMQEhAyMTMwMhEzMDBhcWFhcWEhM2JzMWFxYCBicmJjcDEv4WULW8tVIB6VK1ewQEBUE4iaQDARGnDgUIeeKTmZ0PAc3+MwQ6/ioB1v0eIyVBSgMGASkBAV5eXl3I/revAgLGqAABAGr/6ASCBcgAIgBAALAARViwCS8bsQkcPlmwAEVYsAAvG7EAED5ZsAkQsg4BCitYIdgb9FmwABCyFwEKK1gh2Bv0WbIdAAkREjkwMQUmJicmNzcSABcWFwcmJyYCBwcGFxYWFxY2Njc0JzMXFgIEAkjG/hMHCictAWr8yYtFfpew/yMnBwIDnoZop1cBC7MKB4b+/hUF/M5MT/kBHgFcAgJWi0UCAv763PY0Np3EAgNowrJaWbPV/vGUAAEATP/nA4oEUgAfAD0AsABFWLATLxuxExg+WbAARViwCy8bsQsQPlmyAAEKK1gh2Bv0WbIFCxMREjmwExCyGAEKK1gh2Bv0WTAxJRY2NjcnMxcWBgYnLgI3NzYAFxYXByYjJgYHBhcWFgH2SmouAgKpBgNlwnmHv1gQAx0BKtKoajlhfoXAGgwGCnuCAj9ydHV0n7xkAwSN+JIa+wE4AgJEjj0C2rFnRnSMAAABAJr/5QUgBbAAGgBDALAARViwAy8bsQMcPlmwAEVYsBcvG7EXED5ZsAMQsgQBCitYIdgb9FmwANCwFxCyCQEKK1gh2Bv0WbIPFwMREjkwMQEhNyEHIQMGFhcWNhI3Nic3FhcWAgcGJyYmNwJn/jMcBF8c/iuhCENDa6NZAwEQrg4DBV9elN2YoA0FEp6e/EdibQIEkAEZsGNkAWRjtf7JaKUEAsOsAAABAH3/6ASIBDoAGgBNsgUbHBESOQCwAEVYsAIvG7ECGD5ZsABFWLAXLxuxFxA+WbACELIAAQorWCHYG/RZsATQsAXQsBcQsgsBCitYIdgb9FmyEAIXERI5MDEBITchByEDBhcWFhcWEicmJxcWFxYCBicmJjcB2P6lGgNxGv6gYQQEBUI5haMGAxKnDgkQceOTmp0NA6SWlv20JCU/SwMGAQLTUU8BT0+i/tigAQLEqgAAAQBq/+kFIwXHACwAZrIaLS4REjkAsABFWLAbLxuxGxw+WbAARViwDi8bsQ4QPlmyBgEKK1gh2Bv0WbIKGw4REjmwDhCwK9CwKy+yLAEKK1gh2Bv0WbIULCsREjmyHxsOERI5sBsQsiMBCitYIdgb9FkwMQEiBgcGFhcWNjc3BgYEJy4CNzYlJiY3NjYkFx4CByc2JicmBwYHBhYXFwcCzb3QDg+wnZXhFbwOn/75m5nxdAoVATJfZAUIlAEPp4bYdgW7BZyFnGt3EA6Zm7QcApiPf3WLAwKTewGEwWYDAmy6ev9jMKBdgMFpAgNltncBbYQFAkBIf3F6AQGeAAACAPIEcgNMBdYABQAQABsAsA0vsAbQsAYvsAHQsAEvsA0QsAXQsAUvMDEBEzMHAQcDMwcGFxYXByYmNwHqo78B/vZY4qQNCggIJkhISAkElQFBFv7FAgFTTz42NzM3LoxW//8AGQIfAg8CtgAGABEAAP//ABkCHwIPArYABgARAAD//wCnAosElQMiAEYBl9oATM1AAP//AJkCiwXXAyIARgGXiABmZkAA////X/5sAx8AAAAnAEP/3v8DAQYAQwkAABQAQAkAAhACIAIwAgRdsrACAV0wMQABAK4EMQIFBhMABwAWALAARViwAC8bsQAePlmwBdCwBS8wMQEXBgcHIzc2AaFkcBsYtBIkBhNKjIaGcN4AAAEAiQQWAeAGAAAHABYAsABFWLAELxuxBB4+WbAA0LAALzAxEyc2NzczBwbtZHYYF7ITJAQWSpOKg3nhAAH/mP7lAOoAtQAHABcAsAgvsgQFCitYIdgb9FmwANCwAC8wMQMnNjc3MwcGBWNzGBK1DyP+5UuQi2pg3AAAAQDUBBcBugYAAAsADACwCy+wBtCwBi8wMQEHBhcWFwcmJyY3NwGhFgsKCiZqZxAFBhUGAIVNRkdFRWqdMTGA//8AtgQxAz4GEwAmAWwIAAAHAWwBOQAA//8AlQQWAxUGAAAmAW0MAAAHAW0BNQAAAAL/lP7SAhUA9gAHAA8AIwCwEC+yBAUKK1gh2Bv0WbAM0LAML7AI0LAIL7AA0LAALzAxAyc2NzczBwYXJzY3NzMHBgRodBsetBknZmd0Gh61GSf+0kuXl6uc8ZdLmpSrnPAAAQB3AAAEUQWwAAsASwCwAEVYsAgvG7EIHD5ZsABFWLAGLxuxBhg+WbAARViwCi8bsQoYPlmwAEVYsAIvG7ECED5ZsAoQsgABCitYIdgb9FmwBNCwBdAwMQEhAyMTITchEzMDIQQ4/nmStZH+fBgBgzu2OwGJA6H8XwOhmQF2/ooAAAH/9v5gBGAFsAATAHwAsABFWLAMLxuxDBw+WbAARViwCi8bsQoYPlmwAEVYsA4vG7EOGD5ZsABFWLACLxuxAhI+WbAARViwAC8bsQAQPlmwAEVYsAQvG7EEED5ZsgYBCitYIdgb9FmwDhCyCAEKK1gh2Bv0WbAJ0LAQ0LAR0LAGELAS0LAT0DAxISEDIxMhNyETITchEzMDIQchAyEDt/52QbZC/n4YAYF6/n4YAYE7tjsBihj+dnkBiv5gAaCXAwqZAXb+ipn89gABAKACFQIsA8wADQAWsgoODxESOQCwAy+xCgorWNgb3FkwMRM2NjMyFhUHBgYjIiY1oQZ1VlFpAgZxWlJnAv1ecW1YKlpualUA//8AOf/yAsEA0wAmABIEAAAHABIBrAAA//8AOf/yBFMA0wAmABIEAAAnABIBrAAAAAcAEgM+AAAAAQAaAh4A2wK3AAMADwCwAi+xAQorWNgb3FkwMRMjNzO/pRumAh6ZAAYAl//nBv4FxwAXACYAKgA4AEYAVACFALApL7AnL7AARViwGC8bsRgcPlmwAEVYsBEvG7ERED5ZsADQsAAvsAXQsAUvsBEQsA3QsA0vsBgQsB/QsB8vsBEQsi4ECitYIdgb9FmwABCyNQQKK1gh2Bv0WbAuELA80LA1ELBD0LAfELJKBAorWCHYG/RZsBgQslEECitYIdgb9FkwMQEWFhc2FxYXFgcHBgYnJicGJyYmNzc2NgEWFgcHBgYnJiY3Nz4CAycBFwEGFhcWNjc3NiYnJgYHBQYWFxY2Nzc2JicmBgcBBhYXFjY3NzYmJyYGBwQ7QnAeZod4SEYIBg23gpU+ZIV4kQgGDbf+MXyOCAYPtn15kggHCFmNPWIDcWL+rQdEQkZjCwkHQkNGYwwBtAdDQkdjCwkHQkNGYwz77AdEQkNlDAkHQkNIYwsCkwI8PHoCAldVfkOOrQIFdHsEAqt/Qo2vAzEEq39NhqoEAqx+TFWPTPqpSARoR/w8TmQCAmdRT05jAgJjU1BMZgICaU9PS2YCAmNTAuRNZAICY1ROTGYCAmhPAAABAF8AmQJUA7UABgAQALAFL7ICBwUREjmwAi8wMQETIwM3ATMBC7J94QIBW5gCHP59AYMUAYUAAAEAAgCYAfcDtQAGABAAsAAvsgMHABESObADLzAxARMHASMBAwEW4QL+pZgBSLEDtf59Ff57AZgBhQAB/+8AcAPCBSAAAwAJALAAL7ACLzAxNycBF1FiA3FicEgEaEgA//8AYQKQAuQFpQMHAdgAcQKQABMAsABFWLAJLxuxCRw+WbAN0DAxAAABAH4CiwNKBboAEQBMALAARViwAC8bsQAcPlmwAEVYsAMvG7EDHD5ZsABFWLAPLxuxDxQ+WbAARViwCC8bsQgUPlmyAQMPERI5sAMQsgwDCitYIdgb9FkwMQEXNjMyFgcDIxM3JicmBwMjEwGEAVyGcXIMU6ZNAwRmY0Ngp4sFrHyKopH+BAHdQn4DAm/9zQMgAAH/8wAABIkFygAnAI8AsABFWLAXLxuxFxw+WbAARViwBi8bsQYQPlmyJwYXERI5sCcvsgACCitYIdgb9FmwBhCyBQEKK1gh2Bv0WbAJ0LAAELAN0LAnELAP0LAnELAj0LAjL7YPIx8jLyMDXbIkAgorWCHYG/RZsBHQsCMQsBPQsBcQsRsKK1jYG9xZsBcQsh4BCitYIdgb9FkwMQEhBwYHJQchNxc2NzcHNzM3IzczNzYkFxYWByc2JicmBgcHIQchByEC5/6+CRhUAssd/BUdQ2klC6sWoRSeFpkVGQEWwKjACLsHZGNvmg8VAVIW/rMUAUoB1kSUYwKdnAIm0EcBfYh9r832BgTRsQFreQQEp32vfYgABQAKAAAGQgWwABsAHwAjACYAKQCxALAARViwFy8bsRccPlmwAEVYsBovG7EaHD5ZsABFWLAMLxuxDBA+WbAARViwCS8bsQkQPlmyEAwXERI5sBAvsBTQsBQvtA8UHxQCXbAk0LAkL7AY0LAYL7AA0LAAL7AUELITAQorWCHYG/RZsB/QsCPQsAPQsBAQsBzQsBwvsCDQsCAvsATQsAQvsBAQsg8BCitYIdgb9FmwC9CwKdCwB9CyJhcMERI5sicJGhESOTAxATMHIwczByMDIwMhAyMTIzczNyM3MxMzEyETMwEhJyMFMzchJTMnATcjBWrYGtga2BrYVbfh/mpVvFXTG9Ia0xvSWrXtAYhau/vuATdE2AHjyxr+2P55eVcCPB1qA6yYlJj+GAHo/hgB6JiUmAIE/fwCBPzQlJSUmL7816cAAgA5/+0GJQWwACAAKQCIALAARViwHC8bsRwYPlmwAEVYsBYvG7EWHD5ZsABFWLAULxuxFBA+WbAARViwCy8bsQsQPlmwHBCwH9CyAQEKK1gh2Bv0WbALELIGAQorWCHYG/RZsAEQsA/QsiEWFBESObAhL7ITAQorWCHYG/RZsBwQsB3QsB0vsBYQsikBCitYIdgb9FkwMQEjAwYXFjMyNwcGJyYmNxMjAiEnAyMTBR4CBzcTMwMzARc+AicmJycGC8NyAwIHTyA1C0JEa2wMboFv/nTFY7X9AWJ4tFsFkC+1LsX7RbB4m0MME7zFA6v9YBoXTQqYEgEClYgCnv6JAf3LBbABA1yncAEBBv76/pIBAmrEa6kIAQD//wA6/+kH6gWwACYANgAAAAcAVwQ0AAAABwAiAAAHaQWwAB8AIwAnACsAMAA1ADoAtwCwAEVYsB4vG7EeHD5ZsABFWLAbLxuxGxw+WbAARViwAi8bsQIcPlmwAEVYsA0vG7ENED5ZsABFWLAQLxuxEBA+WbIUEBsREjmwFC+wGNCwGC+wHNCwNtCwANCwBNCwGBCyFwEKK1gh2Bv0WbAn0LAj0LAr0LAH0LAUELAk0LAg0LAo0LAI0LAUELITAQorWCHYG/RZsDLQsA/QsC3QsAvQsjQQHhESObA0ELAv0LI5HhAREjkwMQEhEzMDMwcjBzMHIQMjAyEDIwMhNzMnIzczAzMTIRMzASEnIwUzNyMFMzcjEwcXFzclBxcHNwE3JycHBKQBSbnDwo4bsVDgG/79w6sx/pHdqx7++xvhDLQbjx22GAFK153+nAEaFK3+Xp5Y/wMEn03+fFYDBUP9BlMBCUUBlWIKAisD1AHc/iSYwpj+HgHi/h4B4pjCmAHc/iQB3PzKwsLCwsL+qAIpssMaARi6pQIcAltiawAAAgAf//wFyAQ6AA4AGwBKALAARViwFi8bsRYYPlmwAEVYsAwvG7EMED5ZsA/QshIBCitYIdgb9FmwFhCwDtCyBRIOERI5sgsBCitYIdgb9FmyEAsPERI5MDEBFhYHAyMTNicmJyUDIxsCMwMFMjcTMwMGBicC65mPEzW1NgYCCpL+waG1vMGAtWUBKuEodLVyGcurBDgFzcD+twFMMCyVBQL8XwQ6+8YC3f27AvUCr/1Zyc4EAAABAFH/7ASIBccAJQCKsh8mJxESOQCwAEVYsBgvG7EYHD5ZsABFWLALLxuxCxA+WbIlGAsREjmwJS+yAAIKK1gh2Bv0WbALELIGAQorWCHYG/RZsAAQsA/QsCUQsBDQsCUQsBXQsBUvtg8VHxUvFQNdshICCitYIdgb9FmwGBCyHQEKK1gh2Bv0WbAVELAg0LASELAi0DAxASEGFxYWFxY3FwYnJgI3BzczNyM3MxIAFzIXByYnJgYHIQchByEDLv6OCQcMhnJffAVyd+LuILQWrBmtFqU+ATvoWZQiamOh0y4Behb+jBgBdQIdSkd4hgMDIqEdAgQBNvYBfIl9AQ0BGwIepCQCAsrCfYkABABDAAAF+wWwABkAHgAjACgAwACwAEVYsAsvG7ELHD5ZsABFWLABLxuxARA+WbALELIoAQorWCHYG/RZsCTQsCQvQAkAJBAkICQwJARdsAbQsAYvtA8GHwYCXbQgBjAGAl2ysAYBXbAj0LAjL7SwI8AjAl1ACQAjECMgIzAjBF2yAAEKK1gh2Bv0WbAGELIDAQorWCHYG/RZsCQQshwBCitYIdgb9FmwB9CwJBCwCtCwCi+wJBCwD9CwHBCwEtCwBhCwHdCwFNCwAxCwItCwF9AwMQEDIxMjNzM3IzczNwUyFhczBycHBzcHBwYhATcFBwUFNjcFBxMlJichAZRju43AGsARwRvAKgHtpeIn7hu4Cg7BG9SY/qQBdgn9fBACff6coXL9uhBUAjY4lf6nAjr9xgMwl16X9AF+dZcBMy4ClwH2Abk0AV4B8AJaAlkB5QJPBQAAAQBJAAAEcgWwABoAXwCwAEVYsBkvG7EZHD5ZsABFWLAMLxuxDBA+WbAZELIYAQorWCHYG/RZsAHQsBgQsBPQsBMvsAPQsBMQshIBCitYIdgb9FmwBtCwEhCwDtCwDi+yCQEKK1gh2Bv0WTAxAQcWBzMHIwYEBwEHIwE3FzI3BTchJiYnJTchBCnmJwTPSY80/wDlAXwB2f5jFOL1Zv3GSQIBBnxo/uBJA4kFEgFeZ56yrwf9yA4CcnQCywGeXWQEAZ4AAAEACv/pBBQFsAAeAI0AsABFWLARLxuxERw+WbAARViwBS8bsQUQPlmyExEFERI5sBMvsBfQsBcvsgAXAV2yGAEKK1gh2Bv0WbAZ0LAI0LAJ0LAXELAW0LAL0LAK0LATELIUAQorWCHYG/RZsBXQsAzQsA3QsBMQsBLQsA/QsA7QsAUQshoBCitYIdgb9FmyHgURERI5sB4vMDEBBwYCBCcmJxMFPwIFNyUTMwclBwUHJQcFAzYSNzcEFAobwf7lrkpyYv7/Iv8a/v8hAQA7vC0BCCH++RkBCCH++WG/8yUOAwNO1f6zqgICEwJUbrxvjm68bwFU+3K8co9yvHP94QUBFfBrAAAB//IAAASGBDoAHABVALAARViwHC8bsRwYPlmwAEVYsAgvG7EIED5ZsABFWLAPLxuxDxA+WbAARViwFS8bsRUQPlmyAA8cERI5sAAvsg4BCitYIdgb9FmwEdCwABCwGtAwMQEeAhUUBwcjNzYnJiYnAyMTBgIHByM3EgA3NzMDFHanVQoetRwUBgtpXYG1gZfGJyK1Hy8BNuootQNvF5Pti0tIuqp8Z4yYHP0zAswl/wDZzrkBKwFqI8kAAAL/5QAABTUFsAAWAB8AbQCwAEVYsAwvG7EMHD5ZsABFWLADLxuxAxA+WbIGAwwREjmwBi+yBQEKK1gh2Bv0WbAB0LAGELAK0LAKL7QPCh8KAl2yCQEKK1gh2Bv0WbAU0LAGELAV0LAKELAX0LAMELIfAQorWCHYG/RZMDEBIQMjEyM3MzcjNzMTBRYWBwYEIyUHIQEFMjY3NiYnJQKt/rwwuzDJHMgZyhzIfwH90+oREv7V8P6lGAFF/u4BRZnDERCHfv6mARP+7QETnomdAtkBB+y+0vMBiQEmAZyLepYEAQAEAMz/5gU5BcgAGwApADcAOwB7ALA4L7A6L7AARViwCi8bsQocPlmwAEVYsCMvG7EjED5ZsAoQsAPQsAMvsgADChESObIOCgMREjmwChCyEQQKK1gh2Bv0WbADELIYBAorWCHYG/RZsCMQsBzQsBwvsCMQsi0ECitYIdgb9FmwHBCyNAQKK1gh2Bv0WTAxAQYGJyYmNzc2NhcWFgcnNiYnIgYHBwYWFzI2NwEWFgcHBgYnJiY3NzY2AwYWFxY2Nzc2JicmBgcFJwEXAuUMn3NziAkGDat8b4kChwM2QEFcCggIODw8Tg0B0HuPCAYNtYF5kQgGDLQ/BUNCSGELCQdDQkVmC/3zZANxYwQec48EAqt+Q4uvAgKPcQE6TQJoVkZKZwJLO/50BKl/Q42vBAKrgESLrf6CUGECAmlOT0xmAgJmUfVIBGhHAAACAEv/6wPDBhcAHAAkAFMAsAkvsABFWLAPLxuxDx4+WbAARViwAC8bsQAQPlmwCRCyCAEKK1gh2Bv0WbAW0LAAELIcAQorWCHYG/RZsAkQsB3QsA8QsiIBCitYIdgb9FkwMQUmJicmNzcGBzc2NxM2NhcWFgcHBgAHBwYVBhYXAzYSNzYnJgcCVYOoFA0PBGRtFGVsXhiuhHF6CgMT/wDHEQgCUlBtfo0GBENuGRUGlIFPWBQbArACIQIhtskDBK+HH8f+jXFjNTJVYgUCX28BCqRtBQblAAAEADUAAAfvBcUAAwARACAAKgCIALAARViwJy8bsSccPlmwAEVYsCkvG7EpHD5ZsABFWLAELxuxBBw+WbAARViwIS8bsSEQPlmwAEVYsCQvG7EkED5ZsAQQsAvQsAsvsALQsAIvsgEDCitYIdgb9FmwCxCyFQMKK1gh2Bv0WbAEELIdAworWCHYG/RZsiMpJBESObIoISkREjkwMQEhNyEDFhYHBwYGJyYmNzc2NgMGFhcWNj8DJicmBgcBIwEDIxMzARMzB0n9qhoCVqKQngwJEdCWj6EMCA/USghLSk5rEQILAQaIUm0O/gTB/oPHtPzBAX/HswGcjgOXBMOTV6XCBATCklaiyP4+Y2cCA2VgDGMpoAMCbWL7mQR2+4oFsPuHBHkAAgDqA5YErQWwAAwAFABtALAARViwBi8bsQYcPlmwAEVYsAkvG7EJHD5ZsABFWLATLxuxExw+WbIBFQYREjmwAS+yAAkBERI5sgMBBhESObAE0LIIAQkREjmwARCwC9CwBhCxDQorWNgb3FmwARCwD9CwDRCwEdCwEtAwMQEDBwMDIxMzExMzAyMBIwMjEyM3IQQ6wzRGR1leakXScV5Y/mqOUFlPjw4BeAUS/oYCAZH+cAIZ/nMBjf3nAcj+OAHIUQACAIL/6QR8BFIAFQAcAGKyAh0eERI5sAIQsBbQALAARViwCi8bsQoYPlmwAEVYsAIvG7ECED5ZshoKAhESObAaL7IPCgorWCHYG/RZsAIQshMKCitYIdgb9FmyFQoCERI5sAoQshYKCitYIdgb9FkwMSUGJyYmAjc2EiQXHgIHByEDFhcWNwMmBwMhEyYDsLi+hNBkDg6yAQSKgL5gCwX9FDtfj6rWzoiaMwILM11ddAQCmgECiZIBEZsEBIr7kjH+tmcEB38DKwN8/uoBH2z//wC1//QFdAWbACcB1QBKAoYAJwF8AN8AAAEHAdwC/AAAABAAsABFWLAFLxuxBRw+WTAx//8Akv/0BhAFtgAnAdcAlwKUACcBfAGYAAABBwHcA5gAAAAQALAARViwDS8bsQ0cPlkwMf//AI//9AYGBaQAJwHZAHkCjwAnAXwBdwAAAQcB3AOOAAAAEACwAEVYsAEvG7EBHD5ZMDH//wC+//QFvAWkACcB2wCPAo8AJwF8ARcAAAEHAdwDRAAAABAAsABFWLAFLxuxBRw+WTAxAAIATf/nBDcF7AAeACwARwCwDy+wAEVYsBcvG7EXED5ZsgAPFxESObAAL7APELIJAQorWCHYG/RZsAAQsh8BCitYIdgb9FmwFxCyJgEKK1gh2Bv0WTAxARYWFzYnLgInJgYHJzYXFhYSBwICBCcmAj8CNgAXJgYGFxYWFxY2Nzc2JgJkVpc0BAIEQXlSS49GApOlk8NUCA2e/v6ku9YGAwIdASLVbKxWCwlyY4/CJAoDkwP+AktFLjVlsmADAiMYmEQBA57+08D+2/56ywQFAQTTMRLlARWdA33kj3KDBAXz5UFUeQAAAQAk/ysFRgWwAAcAJwCwBC+wAEVYsAYvG7EGHD5ZsAQQsAHQsAYQsgIBCitYIdgb9FkwMQUjEyEDIwEhBEG17v1M7bUBBQQd1QXt+hMGhQAB/6z+8wTSBbAADAA1ALADL7AARViwCC8bsQgcPlmwAxCyAgEKK1gh2Bv0WbAF0LAIELIKAQorWCHYG/RZsAfQMDEBASEHITcBATchByEBA0/9WgNjG/u7GgLM/i0YA/sb/NkBwQJC/UmYmALMAtKHmP1EAAEAqwKLA/EDIgADABsAsABFWLACLxuxAhY+WbIBAQorWCHYG/RZMDEBITchA9b81RsDKwKLlwAAAQBBAAAFDgWwAAgAPLIDCQoREjkAsAcvsABFWLABLxuxARw+WbAARViwAy8bsQMQPlmyAAEDERI5sAcQsgYBCitYIdgb9FkwMQEBMwEjAyM3IQHlAmnA/PaKgbgcAS4BHgSS+lACdJoAAAMATf/mB6EEUgAZACoAOwBEALAARViwBi8bsQYQPlmwANCwBhCwDdCwDS+wE9CwBhCyHQEKK1gh2Bv0WbANELInAQorWCHYG/RZsC/QsB0QsDjQMDEFJiYnBgYnJiYnJhIkFxYWFzY2Fx4CBwIAARQWFxY2Njc3NiYnJicmBgYFNyYmJyYGBgcHBhYWFxY2NwVpjtQoffSFo9QSE5IBC56N1Sh69oqBu1kPHv7I+tV3alSriRwHBT84Tl5ppWIFzwQDc2lUqI4dBwZNh0+NxBcVBMefyaUDBOW3rAFawgQExqHEqwMEk/uN/v3+uQHMiacCAm7CXSpKqDpRBASD9w9Tj6EEAmnDYClPvXMEBeezAAAB/xr+RQMHBhoAFQA9sgIWFxESOQCwAEVYsA4vG7EOHj5ZsABFWLADLxuxAxI+WbIIAQorWCHYG/RZsA4QshMBCitYIdgb9FkwMRcGBicmJzcWFxY3EzY2FxYXByYjIgfxE7mVNUEcNBmcHsMTxZ02XCIwKLcja6OtAgIUkg4BB8kFDKjEAgEVjw3lAAIAMQEVBC0D8wAWACkAawCwGS+wAtCwAi+wCNCwCC+wAhCwC9CwCBCyDgEKK1gh2Bv0WbACELIUAQorWCHYG/RZsA4QsBbQsBkQsB3QsB0vsBkQsB/QsB0QsiIBCitYIdgb9FmwGRCyJgEKK1gh2Bv0WbAiELAp0DAxEzYzMhcXFhYzMjY3BwYnIiYnJyYjIgcHNjM2FhYzMjcHBiciJiYjIgcHjG2QU1A4MV46PHdNFW+CO2AxMlRSf4k4bo0yU9RNeoQUb4IsStlUbHAtA4ZtKx8dKThHvW8CKR0cL3/mbgEaeH+8bwIWelkmAAABAHAAnQP/BNMAEwA3ALATL7IAAQorWCHYG/RZsATQsBMQsAfQsBMQsA/QsA8vshABCitYIdgb9FmwCNCwDxCwC9AwMQEhByc3IzczNyE3IRMXBzMHIQchA5r+A7NbhaQc/b3+chwB6cFbkrgd/u68AaMBj/JBsaD/oQEEQcOh/wD////UAAIDyQRCAGYAIBFhQAA5mgAHAZf/Kf13//8AGQABA+gETQBmACIUc0AAOZoABwGX/279dgACAEEAAAPUBbAABQAJADiyCAoLERI5sAgQsAHQALAARViwAC8bsQAcPlmwAEVYsAMvG7EDED5ZsgYAAxESObIIAAMREjkwMQEzAQEjCQITAQI9iQEO/gWK/vICKP6PtAFyBbD9Hf0zAuECBP3n/f4CF///AHgApAHwBPcAJwASAEMAsgAHABIA2wQkAAIAcAJ5AncEOgADAAcAJQCwAEVYsAMvG7EDGD5ZsADQsAAvsAXQsAUvsAMQsAbQsAYvMDETIxMzEyMTM/qKTorgik+KAnkBwf4/AcEAAAH/4/9fAQ8A7wAHAAwAsAQvsADQsAAvMDEXJzY3NzMHBkZjWxYPrAkeoUp7eVI/0wD//wB0AAAFawYZACYASgAAAAcASgIbAAAAAgBYAAAEBQYZABYAGgBpALAARViwCS8bsQkePlmwAEVYsBMvG7ETGD5ZsABFWLAZLxuxGRg+WbAARViwFi8bsRYQPlmwAEVYsBgvG7EYED5ZsBMQshQBCitYIdgb9FmwAdCwExCwBNCwCRCyDwEKK1gh2Bv0WTAxMxMjPwI2NzYXFhYXByYnJgcHMwcjAyEjEzNbo6YZpg4beHOvR4VGLHFv5SIN1xnWowI4try2A6uPAWS3ZF8CAiMYnjMCBORXj/xVBDoAAQB0AAAEYgYaABgAXACwAEVYsBMvG7ETHj5ZsABFWLAHLxuxBxg+WbAARViwCi8bsQoQPlmwAEVYsBgvG7EYED5ZsBMQsgIBCitYIdgb9FmwBxCyCAEKK1gh2Bv0WbAM0LAHELAP0DAxASYjIgYHBzMHIwMjEyM3Mzc2NhcWFxcDIwOfgTtjeA8S4Rngo7WkpxmmEhrYpm24YP61BWUWb19zj/xVA6uPf6e6AgIqFPooAAIAdAAABlcGGwAnACsAlwCwAEVYsAgvG7EIHj5ZsABFWLAWLxuxFh4+WbAARViwIC8bsSAYPlmwAEVYsCovG7EqGD5ZsABFWLAnLxuxJxA+WbAARViwJC8bsSQQPlmwAEVYsCkvG7EpED5ZsCAQsiEBCitYIdgb9FmwJdCwAdCwIBCwEtCwBNCwCBCyDQEKK1gh2Bv0WbAWELIcAQorWCHYG/RZMDEzEyM3Mzc2NhcWFwcmJyIGBwchNzY2FxYWFwcmJyYHBzMHIwMjEyEDISMTM3ekpxmmERfUoDZLFjAxWXUREwGDDhrntUiJRC9zb+QiDdgZ16O1o/59owRvtby1A6uPeajAAgIQmAoCal55ZbHJAgImGJszAgLiV4/8VQOr/FUEOgAAAQB0AAAGmQYbACoAigCwAEVYsAkvG7EJHj5ZsABFWLAXLxuxFx4+WbAARViwIy8bsSMYPlmwAEVYsCovG7EqED5ZsABFWLAnLxuxJxA+WbAARViwHC8bsRwQPlmwIxCyJAEKK1gh2Bv0WbAo0LAB0LAjELAT0LAE0LAJELIOAQorWCHYG/RZsBcQsh8BCitYIdgb9FkwMTMTIzczNzY3NhcWFwcmIyIGBwchNzY2FxYXFwMjEyYjJgcHMwcjAyMTIQN3o6YZphIdemaONUsWOihbdRARAYQPGdaqVnG//rXzgTzNIg7hGt+jtaP+faMDq49/tl5OAgIQmAxuZ2xrtMECAhYo+igFZBYC41+P/FUDq/xVAAABAHT/7QTIBhoAJgCBALAARViwIi8bsSIePlmwAEVYsB4vG7EeGD5ZsABFWLARLxuxERg+WbAARViwJS8bsSUYPlmwAEVYsAsvG7ELED5ZsABFWLAZLxuxGRA+WbAeELIbAQorWCHYG/RZsBDQsAHQsAsQsgYBCitYIdgb9FmwIhCyFQEKK1gh2Bv0WTAxASMDBhcWMzI3BwYnJiY3EyM3MxMmJyIGBwMjEyM3Mzc2NhcWFwMzBK7DcgMCB08iMgpCQW5sDG7AGr8zRWpVchLNtaSnGaYRF8WerNU8xQOr/WAaF00KmBIBApuCAp6PASEkAmtp+1MDq494pcMCA2b+iwABACn/6QZ2BhMATQC2ALAARViwSC8bsUgePlmwAEVYsEEvG7FBGD5ZsABFWLASLxuxEhg+WbAARViwLi8bsS4QPlmwAEVYsAovG7EKED5ZsBIQsEzQsgEBCitYIdgb9FmwChCyBQEKK1gh2Bv0WbABELAP0LBIELIXAQorWCHYG/RZsh9BLhESObBBELIiAQorWCHYG/RZsjouQRESObA6ELInAQorWCHYG/RZsjIuQRESObAuELI1AQorWCHYG/RZMDEBIwMHFBcWNwcGJyYmNzcTIzczNzYnJicmBh8CFgcjNiYnJgYHBgQXFgcOAicmJjczFBYXFjY3NicnJjc+AjMWFyY3NjYXFhYHBzMGXcRsAVIbOAxLOmFqAwJqtxm1DAUEDotlegwFFgcGtQJoWF2EDA4BJzzKCwZ5ynKr3Qa0cWVkkAwSkqD/CwV1xW1bWRMHD92UqbEUDcQDq/19NGQDAQuYEwIBkIckAoGPVisqjgMDiZI7q0A8UmUCAltLaU0bWbRkllADAsWbXWsCAldNcy0uVcBglFMBH3s/hqMCBNKqVwAAFv+r/nIIRgWuAA0AHAApADgAPgBEAEoAUABXAFsAXwBjAGcAawBvAHcAewB/AIMAhwCLAI8BDACwPi+wAEVYsEcvG7FHHD5Zsn9KAyuyfHsDK7J4gwMrsoA7AyuyCj5HERI5sAovsAPQsAMvsA7QsA4vsAoQsA/QsA8vslEODxESObBRL7JwBworWCHYG/RZshZRcBESObAKELIgBworWCHYG/RZsAMQsiYHCitYIdgb9FmwDxCwKtCwKi+wDhCwL9CwLy+yNQcKK1gh2Bv0WbA+ELI9CgorWCHYG/RZsD4QsGzQsGjQsGTQsD/QsD0QsG3QsGnQsGXQsEDQsEcQskgKCitYIdgb9FmwYNCwXNCwWNCwS9CwRxCwYdCwXdCwWdCwTNCwDhCyUgcKK1gh2Bv0WbAPELJ3BworWCHYG/RZMDEBBgYnJiY3NzY2FxYWBxMTFxYWBwYGBxYVBgcGBwE2JicmBgcHBhYWNjcBMwMGBiMiJicXBjc2NjcBEzMHMwchNzM3MwMBEyEHIwclNyEDIzcBBzM2NzYnATchByE3IQchNyEHEzchByE3IQchNyEHATc2NzYvAgEjNzM3IzczAyM3MyUjNzM3IzczAyM3MwMQCotfXnQECQiLYF10Agtgql5fAwI3J08BFjSF/rgFODo7VgwNBzl4VQsD0GE7CmtNUmYBWQRYLDkJ+WM3byS/FAT/FMAkbTf5tTIBLRS+HgXbFAEuMm0e++geb28ODVIBShUBDxX9bhUBDhX9bxUBDRXNFAEPFP1uFAEOFP1vFAENFAFYV3sNCkUhXvzOby1vFW8sb69vLW8HAG0sbRVtLW2vbSxtAdRlegICemFuZXsCAnpg/rgCJQEDSkIwORUdWDAhTgQBS0NOAgJOSHI/UgRRRQFP/oVPW1JVAl8CATgp/MoBO8pxccr+xQYfAR10qal0/uOp/LapBVRIBwNLdHR0dHR0+ThxcXFxcXEDwgEGUTcHAwH+0vx++vwV+X78fvr8FfkABQBc/dUH1whzAAMAHAAgACQAKAA0ALAlL7AhL7IcHgMrsCUQsADQsAAvsCEQsALQsAIvsg0AHBESObANL7IfAh4REjmwHy8wMQkDBTQ2NzY2NTQmIyIGBzM2NjMyFhUUBwYGFRcjFTMDMxUjAzMVIwQYA7/8QfxEBA8eJEpcp5WQoALLAjorOThdWy/KyspLBAQCBAQGUvwx/DEDz/E6Ohgnh0qAl4t/MzRANF88QVxMW6r9TAQKngQAAQBiAAAESgWwAAYAObIBBwgREjkAsABFWLAFLxuxBRw+WbAARViwAi8bsQIQPlmwBRCyAwEKK1gh2Bv0WbIAAwUREjkwMQEBIwEhNyEENvzrvwMS/T4bA30FPfrDBRiYAAACAEH/6AQoBFIAEgAhAEOyCCIjERI5sAgQsBfQALAARViwAC8bsQAYPlmwAEVYsAkvG7EJED5ZshYBCitYIdgb9FmwABCyHgEKK1gh2Bv0WTAxAR4CBwcOAicmJicmNzc2EjYDFhYXFjY3NicmJicmBgYCgIrDWw8DFZ31j6LXGgwJAxWg8PcDe3CM0h0FAQN8cW2yYQROBI/6lxag/40EBMuuUFEWowEFiv1fh6QEBeLKKy6IqQQEjPsAAAH/D/5FAQ8AmAAMACcAsA0vsABFWLAELxuxBBI+WbIJAQorWCHYG/RZsA0QsAzQsAwvMDElAwYGJyYnNxYXMjc3AQ8nG7yPND8bLjGFJCmY/vugrgICEZ8OArP8AAAB/73+mQDMAJkAAwASALAEL7AC0LACL7AA0LAALzAxEyMTM3O2Wbb+mQIAAAIBEwTXA3MGzwALAB4AXACwAy+yCQQKK1gh2Bv0WbAH0LAHL7AL0LALL7AHELAP0LAPL7AS0LASL7I/EgFdsA8QsBTQsBQvsBIQshgECitYIdgb9FmwDxCyHAQKK1gh2Bv0WbAYELAe0DAxAQYGJyYmNRcGFzI3EwYGIyImBwYHJzY2MzIWFjc2NwNMCaR/e5KQBH2DHLgJXkYpgidFHlIMYUMkeCQTQyIFr2ZyAgJ1YAJ1AnYBDVBnTwEDVRRTZUYKAQNWAAIBEgTeA0UHAwALABoAQwCwAy+yCQQKK1gh2Bv0WbAL0LALL7AH0LAHL7ALELAa0LAaL7AU0LAUL7IZGhQREjmyDRQZERI5sRMKK1jYG9xZMDEBBgYnJiY1FwYXMjcnNzc2NzYmIzcXFgcGBwcDRQuhfHqRjAaAhBu/Ei9hBwRAUgwX9AQDmwoFsWZtAgJwYAJyAnMSfAMIMxobUwEMfWIYPwAAAgERBN8DXAaKAA4AEgA3ALAEL7ILBAorWCHYG/RZsA7QsA4vsAnQsAkvsA4QsBHQsBEvsA/QsA8vsBEQsBLQGbASLxgwMQEGBgcjJiYnNRcGFxY2NycXBwcDXAqdfw+BkwKSBIM9WQ45osJxBbBibQIDb2ABAnMCATk82wHEAQACAM0E5AOWBtMABgAYAI0AsAEvsAbQsAYvQAkPBh8GLwY/BgRdsgABBhESORmwAC8YsAYQsALQsAEQsAPQsAMvsAAQsATQGbAELxiwBhCwCtCwCi9ACx8KLwo/Ck8KXwoFXbAN0LANL7Q/DU8NAl2wChCwD9CwDy+wDRCyEwYKK1gh2Bv0WbAKELIWBgorWCHYG/RZsBMQsBjQMDEBIycHIyUzNwYGIyImBwYHJzY2MzIWNzY3A5aTpdq3AU+A6wtdPSlxJz4iTwtdQCZ2JkAiBOSdnfTmRllKAQRGE0VdSQECRgACAM4E5AR5Bs8ABgAVAF0AsAEvsADQGbAALxiwARCwBtCwBi+2DwYfBi8GA12wAtCwARCwA9CwAy+wABCwBNAZsAQvGLABELAH0LAHL7AO0LAOL7IIBw4REjmxDQorWNgb3FmyFA4HERI5MDEBIycHBwEzFzc3NjYnJzcWFgcGBgcHA5aUoN62ATa3qBMrVg5hHwt3cgMDREoKBOS5uAEBBnyDBQtqBQJdB1BDNkUQPQAAAgAiBM8DkwaCAAYACgBOALABL7AA0BmwAC8YsAEQsAPQsAMvsAXQsAUvtg8FHwUvBQNdsALQsAAQsATQGbAELxiwARCwCNCwCC+wB9AZsAcvGLAIELAK0LAKLzAxASMnByMBMwUjAzMDk6+KwNABR5T+j3yWtgTPnZ0BBlUBAgACANIE4QT7BpUABgAKAFQAsAMvsAHQsAEvtg8BHwEvAQNdsAMQsALQGbACLxiwARCwBNCwAxCwBdCwBS+wAhCwBtAZsAYvGLADELAJ0LAJL7AH0LAHL7AJELAK0BmwCi8YMDEBMxMjJwcjATMDIwIbleuviMDSA1nQ8ZYF6P75np4BtP79AAIBEQTfA1wGigAOABIANwCwBC+yCwQKK1gh2Bv0WbAO0LAOL7AJ0LAJL7AOELAS0LASL7AQ0LAQL7ASELAR0BmwES8YMDEBBgYHIyYmJzUXBhcWNjclMxcjA1wKnX8PgZMCkgSDPVkO/uGJS1YFsGJtAgNvYAECcwIBOTzbxgAAAQD8BI4CJwY9AAcADACwBS+wANCwAC8wMQEXBgcHIzc2AcBnSxQYtBEdBj1XbmaEcsEAAAL/pQAAA+MEjQAHAAoAU7IECwwREjmwBBCwCtAAsABFWLAELxuxBBo+WbAARViwAi8bsQIQPlmwAEVYsAcvG7EHED5ZsggCBBESObAIL7IAAQorWCHYG/RZsgoCBBESOTAxASEDIwEzASMBIQMC+f4JnMECm6IBAbD+IwGEaAEX/ukEjftzAa4B+wAAAwAdAAAD5wSNAA0AFgAeAHuyGB8gERI5sBgQsA3QsBgQsBbQALAARViwAS8bsQEaPlmwAEVYsAAvG7EAED5ZshcAARESObAXL7K/FwFdtB8XLxcCXbTfF+8XAl2yDgEKK1gh2Bv0WbIHDhcREjmwABCyDwEKK1gh2Bv0WbABELIeAQorWCHYG/RZMDEzEwUWFgcGBxYWBwYGBwMDFzI2NzYmJycXMjY3NicnHcsBfr/CCgrST1YECO3Av0L0bpUMC1dk+dlvjgoU1+EEjQEFpIyqUxqOXZ21AwIS/oUBZlpUYgWOAV1ToAUBAAABAEf/7AQ3BKMAHABOshMdHhESOQCwAEVYsAsvG7ELGj5ZsABFWLADLxuxAxA+WbIACwMREjmyDgMLERI5sAsQshIBCitYIdgb9FmwAxCyGgEKK1gh2Bv0WTAxAQYEJy4CNzcSABcWFhcjJiYnJgYHBhcWFhcWNwPmI/7tyIrBVhEMJQE54LjVCLMFbXiTyh8bBgV2bPtMAXq70wQEjPuYWAEIATAGBNW2coIEBcq2nmN1iwQK/AAAAgAdAAAEDwSNAAoAFQBDshUWFxESObAVELAC0ACwAEVYsAIvG7ECGj5ZsABFWLAALxuxABA+WbINAQorWCHYG/RZsAIQshUBCitYIdgb9FkwMTMTBR4CBwcCACETAxcyNjc3NicmJx3LAVKW2mUQBRz+ov76CJaUvPMZBhI4RawEjQEEjfiaMP78/ssD9PyjAdvHMaJmfAYAAAEAHQAAA+8EjQALAGGyCQwNERI5ALAARViwBi8bsQYaPlmwAEVYsAQvG7EEED5ZsgsGBBESObALL7QfCy8LAl2yvwsBXbIAAQorWCHYG/RZsAQQsgIBCitYIdgb9FmwBhCyCAEKK1gh2Bv0WTAxASEDIQchEyEHIQMhAzH9/UICWRv888sDBxv9rjoCBAIO/omXBI2Z/rIAAQAdAAAD4gSNAAkAR7IHCgsREjkAsABFWLAELxuxBBo+WbAARViwAi8bsQIQPlmyCAIEERI5sAgvsgEBCitYIdgb9FmwBBCyBwEKK1gh2Bv0WTAxASEDIxMhByEDIQMh/ghXtcsC+hv9uz8B+QHz/g0EjZn+mAAAAQBM/+4EQQSjAB8AXLIeICEREjkAsABFWLALLxuxCxo+WbAARViwAy8bsQMQPlmyDgsDERI5sAsQshEBCitYIdgb9FmwAxCyGQEKK1gh2Bv0WbIfCwMREjmwHy+yHAEKK1gh2Bv0WTAxJQYGJy4CNzcSABcWFhcnJicmBgcGFxYWFxY3NyE3IQPWP/Cekc9dEQchATvos9YQsRTalMwgHAsMhW+lai3+7hoBw5ZRVwMCkPydOwEWATYGBMCvAdMIBci4n196iAMFTu6QAAABAB0AAASaBI0ACwBosgEMDRESOQCwAEVYsAovG7EKGj5ZsABFWLAHLxuxBxo+WbAARViwBC8bsQQQPlmwAEVYsAEvG7EBED5ZsggEBxESOXywCC8YtGAIcAgCcbKgCAFdtGAIcAgCXbIDAQorWCHYG/RZMDEhIxMhAyMTMwMhEzMDz7RW/bhXtcu0WQJIWrUB8v4OBI39/QIDAAABACoAAAGqBI0AAwAksgIEBRESOQCwAEVYsAIvG7ECGj5ZsABFWLAALxuxABA+WTAxMyMTM+C2yrYEjQAB//b/6wObBI0ADgAvsgwPEBESOQCwAEVYsAAvG7EAGj5ZsABFWLAFLxuxBRA+WbILAQorWCHYG/RZMDEBMwMGBicmJjcXBhcWNjcC5LeMFuyorcIItQzIW34RBI38xaPEBAS5oAHBBAJvZAABAB0AAAR/BI0ADABMsgoNDhESOQCwAEVYsAQvG7EEGj5ZsABFWLAILxuxCBo+WbAARViwAi8bsQIQPlmwAEVYsAsvG7ELED5ZsgAEAhESObIGBAIREjkwMQEHAyMTMwM3ATMBASMBwrBAtcu0X5IBw+39zAF8zAIGlf6PBI394IkBl/3w/YMAAQAdAAADIwSNAAUAL7IFBgcREjkAsABFWLAELxuxBBo+WbAARViwAi8bsQIQPlmyAQEKK1gh2Bv0WTAxNyEHIRMz7AI3G/0Vy7SXlwSNAAABAB0AAAWwBI0ADgBgsggPEBESOQCwAEVYsAAvG7EAGj5ZsABFWLACLxuxAho+WbAARViwBC8bsQQQPlmwAEVYsAgvG7EIED5ZsABFWLAMLxuxDBA+WbIBAAQREjmyBwAEERI5sgoABBESOTAxARMBMwMjExMBIwsCIxMBzd0CF+/KtEdq/eWF4kxEtMsEjfxzA437cwGbAfv8agOs/dv+eQSNAAEAHQAABJoEjQAJAEyyAQoLERI5ALAARViwBS8bsQUaPlmwAEVYsAgvG7EIGj5ZsABFWLAALxuxABA+WbAARViwAy8bsQMQPlmyAgUAERI5sgcFABESOTAxISMBAyMTMwETMwPPrf5KmrXLrQG3mrQDdPyMBI38iwN1AAACAEr/6gROBKMADwAfAEayHCAhERI5sBwQsAjQALAARViwCC8bsQgaPlmwAEVYsAAvG7EAED5ZsAgQshMBCitYIdgb9FmwABCyGwEKK1gh2Bv0WTAxBSYmAjc3EgAXHgIHBwIAEyYmJyYGBwYXFhYXFjY3NgH2j8VYEQUgAT/lj8RXEAQc/sKuCX1tldEdFQgKfmyUzh8VEASRAQOcKwENAUcGBI7+nyn+8P61AxN4iQQF17aFX3yNBAXRvIMAAgAdAAAEKQSNAAoAEwBNsgoUFRESObAKELAM0ACwAEVYsAMvG7EDGj5ZsABFWLABLxuxARA+WbIMAwEREjmwDC+yCgEKK1gh2Bv0WbADELITAQorWCHYG/RZMDEBAyMTBRYWBwYEIyUFMjY3NiYnJQEeTLXLAbmz1QsM/vrR/v0BB32fDgtvZ/7kAbb+SgSNAQTCoKzFmQFyZV9sBAEAAAIARf83BEsEowATACMAOQCwAEVYsA0vG7ENGj5ZsABFWLAFLxuxBRA+WbANELIXAQorWCHYG/RZsAUQsh8BCitYIdgb9FkwMSUXBycGIyYCPwISABcWFhIHBwIDJiYnJgYHBhcWFhcWNjc2Awy2gttCN8fgDAMGHwFA5JDGWBIGKoAJfm6Vzx0VCAl8bZXOHxZBpGbFCwMBHegnNQEIAUYGBJH+/Z4y/qcCHXqLBAXYtoRfeo8EBdC9hQAAAgAdAAAEAQSNAA0AFgBNALAARViwBC8bsQQaPlmwAEVYsAIvG7ECED5Zsg4CBBESObAOL7IBAQorWCHYG/RZsgoBBBESObACELAN0LAEELIWAQorWCHYG/RZMDEBIQMjEwUWFgcGBRMVIwEXMjY3NiYnJwIz/u1OtcsBkb3LDBL++cbA/ljkd6AMC2hu9AHB/j8EjQEFuJ3oYf4jDAJYAXRgW2gFAQAAAQAR/+sD7QSdACcAVACwAEVYsAovG7EKGj5ZsABFWLAeLxuxHhA+WbIDHgoREjmwChCyEgEKK1gh2Bv0WbAO0LADELIXAQorWCHYG/RZsB4QsiUBCitYIdgb9FmwItAwMQE2LwIkNzY2NzcWFgcnNicmJyIGBwYXFxYWBwYEJyYmNxcGFhcyNgLZEqR9Pv7/DQjnsymz1wW0BSk3f3GSDBG6QrulCAr+98G67wW1B4B8eJYBMXs2JxdmzoyyCgEExJ0BUTRFA15ScTkUN7J7mLEFAselAWVxAlwAAAEAbQAABEIEjQAHAC4AsABFWLAGLxuxBho+WbAARViwAy8bsQMQPlmwBhCyBQEKK1gh2Bv0WbAB0DAxASEDIxMhNyEEJv5+sLWw/n4cA7kD9PwMA/SZAAABAEX/6gRXBI0AEQAuALAARViwCS8bsQkaPlmwAEVYsAQvG7EEED5Zsg0BCitYIdgb9FmwCRCwEdAwMQEDBgQnJiY3EzMDBhYXFjY3EwRXgxn+6si/2RODs4QNdXR6qRWEBI389breBATcswMM/PN1gQMEgnsDDQABAHoAAASZBI4ACAA4sgUJChESOQCwAEVYsAgvG7EIGj5ZsABFWLADLxuxAxo+WbAARViwBS8bsQUQPlmyAQgFERI5MDEBFzcBMwEjAzcB0gcsAcvJ/Xqp8LUBJFthA2P7cwSNAQABAJUAAAYpBI4AEgBZALAARViwAy8bsQMaPlmwAEVYsBIvG7ESGj5ZsABFWLAILxuxCBo+WbAARViwDy8bsQ8QPlmwAEVYsAsvG7ELED5ZsgEPEhESObIGCwgREjmyDRILERI5MDEBBzcBMxMXNwEzASMDNQcBIwM3AWsGGwGLoVEBHwFTuf4VqloE/l6qVacBJlJCA3f8hj1cA1v7cwOVCgv8bASNAQAB/7YAAARtBI0ACwBMsgAMDRESOQCwAEVYsAEvG7EBGj5ZsABFWLAKLxuxCho+WbAARViwBC8bsQQQPlmwAEVYsAcvG7EHED5ZsgABBBESObIGAQQREjkwMQEBMwEBIwMBIwEBMwIoAWHk/hQBIsnV/pTjAfj+6MgC2wGy/bT9vwG6/kYCVQI4AAABAHQAAARlBI0ACAA4sgAJChESOQCwAEVYsAEvG7EBGj5ZsABFWLAHLxuxBxo+WbAARViwBC8bsQQQPlmyAAEEERI5MDEBATMBAyMTATMB/AGT1v3URbVL/urAAksCQv0A/nMBrQLgAAH/3AAABA4EjQAJAEuyBQoLERI5ALAARViwBy8bsQcaPlmwAEVYsAIvG7ECED5ZsgEBCitYIdgb9FmyBAIBERI5sAcQsgYBCitYIdgb9FmyCQYHERI5MDE3IQchNwEhNyEH4AKWG/yBGAMV/YsbA18Xl5eFA2+ZggAAAgAd//ACgQMlAA0AGQBGshAaGxESObAQELAH0ACwAEVYsAcvG7EHFj5ZsABFWLAALxuxABA+WbAHELIQAgorWCHYG/RZsAAQshYCCitYIdgb9FkwMQUmJjc3NjYXFhYHBwYGEyYnJg8CFhcWNzcBIIKBDA0TrYmBgQwOE6s0BGOFHRQBBGWEHRMMBLSZeq64BAS1mYGqtAIxfAMDxLM3fwMGybYAAAEAawAAAfwDFQAGADIAsABFWLAFLxuxBRY+WbAARViwAS8bsQEQPlmyBAEFERI5sAQvsgMCCitYIdgb9FkwMSEjEwc3JTMBeZpo3BgBZBUCVTiHcQAAAf/pAAACcwMkABcARwCwAEVYsA8vG7EPFj5ZsABFWLABLxuxARA+WbIWAgorWCHYG/RZsALQsgMPFhESObAPELIIAgorWCHYG/RZshUWDxESOTAxISE3ATY3NiYnJgYHBzY2FxYWBwYPAiECL/26FAFjYwwHNTBCUA6aC66AeIsFCJdAxAF7dAEqVEowNgEBSz4BdZUCAn5me30zkQAB//v/8wJ4AyIAJABsALAARViwDS8bsQ0WPlmwAEVYsBcvG7EXED5ZsgAXDRESOXywAC8YtoAAkACgAANdtqAAsADAAANxsA0QsgcCCitYIdgb9FmwABCyJAIKK1gh2Bv0WbISJAAREjmwFxCyHgIKK1gh2Bv0WTAxExc2Njc2JiMiByM2NjMWFgcGBxYHBgYnJiY1MxQWMzI2NzYnJ+ROQl0HBj4ycB2cC599fo4FB5h2BAW1hXeVl0I6QFsHDY1XAcsBAj02MTFdZXkDdmF3QiuBb4ECAnxsMjdANWYFAQAAAv/wAAACcwMVAAoADgBFALAARViwCS8bsQkWPlmwAEVYsAUvG7EFED5ZsgwFCRESObAML7AA0LIDAgorWCHYG/RZsAbQsAwQsAjQsg0JBRESOTAxATMHIwcjNyE3ATMBMxMHAgtoF2cemh7+lQ0Bv6T+QdA6FgErgqmpcAH8/hYBIx4AAQAW//MCjwMVABsAYACwAEVYsAEvG7EBFj5ZsABFWLANLxuxDRA+WbABELIEAgorWCHYG/RZsgcNARESObAHL7AF0LANELAR0LANELITAgorWCHYG/RZsAcQshkCCitYIdgb9FmwBxCwG9AwMRMTIQchBzYzMhYHBgYnJiYnFxY3MjY3NiYnIgdGdgHTGP6wO0BCbYEEBq6DdZEFlAlvQVYIBkE8Qz8BhgGPhKschXN8mwICgGMBZQJSRDxGASoAAgAe//ICaAMgABIAHQBVALAARViwAC8bsQAWPlmwAEVYsAwvG7EMED5ZsAAQsgECCitYIdgb9FmyBgwAERI5sAYvsgQGDBESObITAgorWCHYG/RZsAwQshgCCitYIdgb9FkwMQEHIyYHNhcyFgcGBiYmNzc2JDMDJgcHBhYyNjc2JgI8DQv+VlJmanYGBrD8kgsFFgEJ1MddPQQHOn5XBgc8Ax+DA+FOApNsep8ErIw4zO7+bgJRIkdgVz05SgAAAQAvAAACswMVAAYAMgCwAEVYsAUvG7EFFj5ZsABFWLACLxuxAhA+WbAFELIEAgorWCHYG/RZsgAEBRESOTAxAQEjASE3IQKh/jutAcX+ThcCWgKx/U8Ck4IAAwAL//QCeAMjABQAIAAsAH4AsABFWLASLxuxEhY+WbAARViwCC8bsQgQPlmyKggSERI5fLAqLxi0UCpgKgJxtqAqsCrAKgNxtoAqkCqgKgNdtCAqMCoCcrIYAgorWCHYG/RZsgIqGBESObINGCoREjmwCBCyHgIKK1gh2Bv0WbASELIkAgorWCHYG/RZMDEBBgcWBwYGByMmJjc2NyY3NjYXFhYDNiYjIgYHBhYzMjYTNiYjIgYHBhYzMjYCcweIbAQDo30QfpAFB5xbBASjeHSJxAVCNj5VBwZCNj5WLwU2MDZJBgY4LjJOAktxSTt2aYADA3digkk3aWt9AgJ3/kIxN0A0MjdBAYoqNTwvKzU9AAIANv/3AncDIgATACEAUQCwAEVYsAgvG7EIFj5ZsABFWLAPLxuxDxA+WbICDwgREjmwAi+wDxCyEQIKK1gh2Bv0WbACELIUAgorWCHYG/RZsAgQshwCCitYIdgb9FkwMQEGIyImNzY2FxYWBwcGBCMnNzI2JxY3NzYnJiYjIgYHBhYBwk1aa3oGBq+Cf4ULBBb+/9QUDYebWFE9CAMDBTctPVUHBjsBQECOcXuoAgKxkDPS4QF/XqIESz4dHS84XEI8TAABAJMCiwMYAyIAAwARALACL7IBAQorWCHYG/RZMDEBITchAv39lhsCagKLlwAAAwELBD8DGwZxAAMADwAZAD4AsABFWLANLxuxDRg+WbAH0LAHL7AC0LACL7AA0LAAL7ANELISBworWCHYG/RZsAcQshgHCitYIdgb9FkwMQEzByMHNDYzMhYVFAYjIiY3FjMyNjc2JiMiAlPI9n+bZUdDWWFGRVxSBT4hOgcEIiJEBnG23kZoXURFZltEUDMnHzQAAAP/mv5HBEkEUgAqADgARgCPALAARViwJy8bsScYPlmwAEVYsBYvG7EWEj5ZsCcQsCrQsCovsgADCitYIdgb9FmyCBYnERI5sAgvsg8IFhESObAPL7SQD6APAl2yOAEKK1gh2Bv0WbIcOA8REjmyIAgnERI5sBYQsjEBCitYIdgb9FmwCBCyPAEKK1gh2Bv0WbAnELJDAQorWCHYG/RZMDEBBxYHBwYHBiciJwYHBhcXFhYHBgYEJyYmNzY2NyY3NjcmNzc2NzYfAgUBJwYHBhYzMjY2NzYmJwMGFhcWNjc3NiYnJgYHBC+QIQkFHJ58l0lNQggJYLC6tQgGk/7qhsLiBwVxXyYGCouCCwERnoCjJmsBcfz1T4IRCYFyXK9lCQpTbt8GdVljnA8CB3BdYpwQA6cBXGEkrmNNAhc4OUYEAgaUg2OcYAMFjnlZizAvP3xebLAMvmdTAgITAfvyBz95SVIzWjk/RAMCnVZvAgJ4WxZWdQICdV4AAAIAS//kBIcEUgATACUAbrIiJicREjmwIhCwC9AAsABFWLALLxuxCxg+WbAARViwDy8bsQ8YPlmwAEVYsAIvG7ECED5ZsABFWLATLxuxExA+WbIAAgsREjmyDgsCERI5sAIQshkBCitYIdgb9FmwCxCyIgEKK1gh2Bv0WTAxJQInJiYnJjc2EjYXFhYXNzMDEyMBBhcWFhcWNzY3NzYnJicmBgcDMpf8mbEHAwgUjc9+fKogULDKEKj94gcDBWxgoG8xFwUGHTODjLQa8v7yBwTUtTlWpwEbiQMEinXu/db98AHtPD9vgAMD0F1iI25krwYF7cwAAAIAQwAABOUFrwAcACUAYbIeJicREjmwHhCwHNAAsABFWLADLxuxAxw+WbAARViwAS8bsQEQPlmwAEVYsBMvG7ETED5Zsh0BAxESObAdL7IAAQorWCHYG/RZsgkAHRESObADELIlAQorWCHYG/RZMDEBAyMTBTIWBwYFFhcWBwcGFxYXByMmJyY3NzYmJyUFMjY3NiYnJQFtbb39Ad3e6hEV/vWQEAQGFgcDBCEDuSAFAwkUDWlo/rYBJaK5EA16f/61AnT9jAWvAde/5HBAqzM1lTcoOioZLUYuRYp0iQaeAYiCdH4EAQABAEQAAAVqBbAADABksgoNDhESOQCwAEVYsAQvG7EEHD5ZsABFWLAILxuxCBw+WbAARViwAi8bsQIQPlmwAEVYsAsvG7ELED5ZsgYCBBESObAGL7LPBgFdsi8GAV2yAQEKK1gh2Bv0WbIKAQYREjkwMQEjAyMTMwMzATMBASMCI7JxvP27b4kCXff9YQG81gKO/XIFsP1+AoL9Nf0bAAEAJQAABB4GAAAMAFCyBQ0OERI5ALAEL7AARViwCC8bsQgYPlmwAEVYsAIvG7ECED5ZsABFWLALLxuxCxA+WbIGAggREjmwBi+yAQEKK1gh2Bv0WbIKAQYREjkwMQEjAyMBMwMzATMBASMBtIJXtgELtZlyAXzk/jIBN8gB9f4LBgD8jgGs/gr9vAAAAQBEAAAFSgWwAAsATLIJDA0REjkAsABFWLADLxuxAxw+WbAARViwBy8bsQccPlmwAEVYsAEvG7EBED5ZsABFWLAKLxuxChA+WbIAAwEREjmyBQMBERI5MDEBAyMTMwMzATMBASMBeXm8/bt2CQLB+vz6AiHXArz9RAWw/XgCiP0y/R4AAQAlAAAEBgYYAAwAU7IFDQ4REjkAsABFWLAELxuxBB4+WbAARViwCC8bsQgYPlmwAEVYsAIvG7ECED5ZsABFWLALLxuxCxA+WbIABAIREjmyBgQCERI5sgoHABESOTAxASMDIwEzAxcBMwEBIwE8Blu2AQ+2pwIByPn92QGFzAHz/g0GGPxzAQGw/gT9wgAAAQAS/xMD7wVzACwAbbIgLS4REjkAsABFWLAJLxuxCRo+WbAARViwIy8bsSMQPlmyBCMJERI5sAkQsAzQsAkQsBDQsAwQshQBCitYIdgb9FmwBBCyGQEKK1gh2Bv0WbAjELAg0LAjELAn0LAgELIqAQorWCHYG/RZMDEBNi8CJDc2Njc3MwcWFgcnNicmJyIGBwYWFhcWBwYGBwcjNyYmNxcGFhcyNgLaEqR9Pv7/DQneryyRK5GdBrQFKTd/cZIMB1rvSMUMCNO3LJItorgGtAV+fHiWATF7NicXZs6JrBHZ3Ry/gwFRNEUDXlI8VUYmaL2EqhLh4xjBjwFmcAJcAAEABgAAA9gEogAeAGqyGh8gERI5ALAARViwEy8bsRMaPlmwAEVYsAYvG7EGED5Zsh4GExESObAeL7IABAorWCHYG/RZsAYQsgUBCitYIdgb9FmwCNCwABCwDNCwHhCwD9CwExCwF9CwExCyGQEKK1gh2Bv0WTAxASUGBwclByE3FzY3Nwc3Mzc2NhcWFgcnNicmBgcHIQL0/oIjMiEChBv8nRYJZiMUphacCxfqraeqCrYQrWB9EA0BiQH0Ac5cNQKYlgEpxXIBeWrb8AUE0q4B4gcDmY5yAAEANAAABG4EjQAXAJSyABgZERI5ALAARViwAS8bsQEaPlmwAEVYsBcvG7EXGj5ZsABFWLANLxuxDRA+WbIADRcREjmyEBcNERI5sBAvsg8QAV2wFNCwFC+0DxQfFAJxQA8PFB8ULxQ/FE8UXxRvFAddsATQsAQvsBQQshMECitYIdgb9FmwBdCwEBCwCdCwEBCyDwQKK1gh2Bv0WbAK0DAxAQEzATMHJQcHJQchByM3ITchNyE3MwMzAgUBk9b+OO8W/tELEQE/Fv7HJ7Un/sUVAToO/sUV/uy/AkwCQf2MeQIMQwJ43d14S3kCdAABAB0AAAPNBI0ABQAysgEGBxESOQCwAEVYsAQvG7EEGj5ZsABFWLACLxuxAhA+WbAEELIBAQorWCHYG/RZMDEBIQMjEyEDsv3QsLXLAuUD9PwMBI0AAAL/sAAAA84EjQADAAgAPLICCQoREjmwAhCwBtAAsABFWLACLxuxAho+WbAARViwAC8bsQAQPlmyBQIAERI5sggBCitYIdgb9FkwMSEhATMDJwcBIQPO++IChqZyCib+fQI0BI3+z2xX/ScAAAMASv/qBFgEpAADABIAIgBnshcjJBESObAXELAC0LAXELAE0ACwAEVYsAsvG7ELGj5ZsABFWLAELxuxBBA+WbAC0LACL7LfAgFdsh8CAV2yAQEKK1gh2Bv0WbALELIWAQorWCHYG/RZsAQQsh4BCitYIdgb9FkwMQEhNyEBJgI3NxIAFxYWEgcHAgATJiYnJgYHBhcWFhcWNjc2Azv+LBsB1P6q1uAbBSABQOSPxFcQBiH+xLMJfG6W0B0VCAh/bZTOHxUB+Zn9XgUBO/QsAQwBSAYEjv8AnzT+7/7CAxR4iAQF2bSEYHmQBAXRvIQAAAH/sAAAA84EjQAIADiyAgkKERI5ALAARViwAi8bsQIaPlmwAEVYsAAvG7EAED5ZsABFWLAELxuxBBA+WbIHAgAREjkwMTMjATMTIwMnB2S0Aoam8sedCioEjftzA1xsYAAAA//TAAADlQSNAAMABwALAGSyAAwNERI5sATQsAAQsArQALAARViwCi8bsQoaPlmwAEVYsAAvG7EAED5ZsgMBCitYIdgb9FmwABCwB9CwBy+yHwcBXbLfBwFdsgQBCitYIdgb9FmwChCyCQEKK1gh2Bv0WTAxISE3IREhNyETITchAsr9CRsC9/2KGwJ2ev0JGwL3mAF7mAFJmQAAAQAdAAAEhgSNAAcAP7IBCAkREjkAsABFWLAGLxuxBho+WbAARViwAC8bsQAQPlmwAEVYsAQvG7EEED5ZsAYQsgMBCitYIdgb9FkwMSEjEyEDIxMhA7y2sP3MsLXLA54D9PwMBI0AAf/VAAAD3gSNAAwAQ7IGDQ4REjkAsABFWLAILxuxCBo+WbAARViwAy8bsQMQPlmyAgEKK1gh2Bv0WbAF0LAIELILAQorWCHYG/RZsAfQMDEBASEHITcBAzchByETAln+fgKIG/yRGgGU/BgDPxz9m/4COv5fmZkBuAG1h5n+YAADAFEAAATzBI0AEgAYAB4Ab7IHHyAREjmwBxCwFtCwBxCwHNAAsABFWLARLxuxERo+WbAARViwCC8bsQgQPlmyEBEIERI5sBAvsADQsgkIERESObAJL7AG0LAJELIVAQorWCHYG/RZsAAQshsBCitYIdgb9FmwFtCwFRCwHNAwMQEWFgcGAAcHIzcmJjc+Ajc3MwECBRMGBgUSJQM2NgNJyeEPEv7L6xi1GMvhEQyT+JwZtf2yHwEYdKK6Awof/up1oLsEFBP1wND+/w1ucBH9vIrReQl2/a3+7h8CdQ2nfQEPH/2MDagAAQB+AAAE9QSNABoAXLIZGxwREjkAsABFWLADLxuxAxo+WbAARViwES8bsREaPlmwAEVYsBkvG7EZGj5ZsABFWLAJLxuxCRA+WbIYAwkREjmwGC+wANCwGBCyCwEKK1gh2Bv0WbAI0DAxASQTEzMDBgAHAyMTJiYnJjcTMwMGFxYWFxMzArIBHzs0tTUk/ubgOLY4l7YUDQ00tjQJAgJkXYK2Abk6AWIBOP7I9/7bGP7fASEWwJpfZQE4/sdAQXKRFwLUAAEADAAABGoEoQAiAFmyACMkERI5ALAARViwGC8bsRgaPlmwAEVYsA8vG7EPED5ZsABFWLAhLxuxIRA+WbIgAQorWCHYG/RZsADQsBgQsgYBCitYIdgb9FmwABCwDtCwIBCwEdAwMSUkEzc2JicmBgcGBxcWFwchNzcmJyYSJBcWEg8CAgc3ByECVQEfNAUThIyZ0xYMAQEOqhj+ShypYAEElAESp8jpBwMGKdSyG/5JnEMBjSSpxgMEza10OSniN52XAo7F1AE2qwQE/vjTLyz+zp0DlwABAGz/6wToBI0AGABosgcZGhESOQCwAEVYsAIvG7ECGj5ZsABFWLAOLxuxDhA+WbAARViwFy8bsRcQPlmwAhCyAQEKK1gh2Bv0WbAF0LIIAhcREjmwCC+wDhCyDwEKK1gh2Bv0WbAIELIUAQorWCHYG/RZMDEBITchByEDNhcWFgcGBgc3JDc2JicmBwMjAcX+pxsDbxv+nzqVlbnFDA7/6A8BFxkNXXJ+tma0A/SZmf7WNAQEzri8xwKXBeluggIDMv3NAAABAEf/7AQ3BKMAHwBqshMgIRESOQCwAEVYsAsvG7ELGj5ZsABFWLADLxuxAxA+WbALELAP0LALELISAQorWCHYG/RZsAMQsBbQsBYvst8WAV2yHxYBXbIXAQorWCHYG/RZsAMQsh0BCitYIdgb9FmwAxCwH9AwMQEGBCcuAjc3EgAXFhYXIyYmJyYGByEHIQYXFhYXFjcD5iP+7ciKwVYRDCUBOeC41QizBW14kMIuAbkb/lIIBgh5Z/tMAXq70wQEjPuYWAEIATAGBNW2coIEA7m9mEJBboAECPoAAv/EAAAGqASNABcAIAB2sgghIhESObAIELAZ0ACwAEVYsBUvG7EVGj5ZsABFWLAGLxuxBhA+WbAARViwDS8bsQ0QPlmwFRCyCQEKK1gh2Bv0WbANELIQAQorWCHYG/RZshcGFRESObAXL7IYAQorWCHYG/RZsAYQshoBCitYIdgb9FkwMQEWFgcGBCMhEyEDBgYHIzczMjY3NxMhAwcDBTI2NzYmJwUtrs0LDf7+yv42r/5tczbKnEMWImOBIRJtAvlNGkkBAnKeDQtkZgLWBL+dqswD9P3K6dQBpKS+awIc/kqY/lkBfGZXaQUAAAIAHQAABrUEjQASABsAhLIBHB0REjmwARCwFNAAsABFWLACLxuxAho+WbAARViwES8bsREaPlmwAEVYsAsvG7ELED5ZsABFWLAPLxuxDxA+WbIADxEREjl8sAAvGLIECwIREjmwBC+wABCyDgEKK1gh2Bv0WbAEELITAQorWCHYG/RZsAsQshUBCitYIdgb9FkwMQEhEzMDBRYWBwYEIyETIQMjEzMBAwUyNjc2JicBQwI1WrRMAQCuzQsL/v7L/jVX/ctXtcu0AoRKAQJynw0LYmgCigID/koBBL+dqM4B8v4OBI39sv5ZAXpoVmoFAAEAbQAABO0EjQAWAFeyBxcYERI5ALAARViwAi8bsQIaPlmwAEVYsAwvG7EMED5ZsABFWLAVLxuxFRA+WbACELIBAQorWCHYG/RZsAXQsggMAhESObAIL7ISAQorWCHYG/RZMDEBITchByEDNhcWFgcDIxM2JyYnJgcDIwHG/qccA28b/p86kZq8xBQ6tTkHBhaogbNmtQP0mZn+1jIDAti7/pwBZTgukQYDMv3NAAEAHf6bBIUEjQALAEKyAQwNERI5ALACL7AARViwBi8bsQYaPlmwAEVYsAovG7EKGj5ZsABFWLAALxuxABA+WbAE0LIIAQorWCHYG/RZMDEhIQMjEyETMwMhEzMDu/6NPrU+/orLtLACNbC0/psBZQSN/AsD9QACAB//+wPbBI0ADAAVAFuyExYXERI5sBMQsAPQALAARViwCy8bsQsaPlmwAEVYsAovG7EKED5ZsAsQsgEBCitYIdgb9FmyAgoLERI5sAIvshQBCitYIdgb9FmwChCyFQEKK1gh2Bv0WTAxASEDBRYWBwYEJyUTIQE2Njc2JiclAwPB/cAyARmtvhQW/uvB/kzKAvL+KXGUBAJyZ/7/SgP3/uABBL6erc4EAQSN/AoCeGdbZgUB/lkAAv+J/qwEmgSNAA4AFQBVshIWFxESObASELAE0ACwDC+wAEVYsAQvG7EEGj5ZsABFWLAKLxuxChA+WbIGAQorWCHYG/RZsAwQsAnQsAYQsA7QsBDQsAQQshEBCitYIdgb9FkwMTc2NjcTIQMzAyMTIQMjEwUlEyEDBwItbIYnYgLysItWtTz81Du2VwEjAjKV/nNMEEWWYvi3Aeb8C/4UAVT+rQHrAwMDXP6QQ/7tAAAB/68AAAYEBI0AFQCSsg0WFxESOQCwAEVYsAkvG7EJGj5ZsABFWLANLxuxDRo+WbAARViwES8bsREaPlmwAEVYsAIvG7ECED5ZsABFWLAGLxuxBhA+WbAARViwFC8bsRQQPlmyDAINERI5fLAMLxiyoAwBXbRgDHAMAl2yBAEKK1gh2Bv0WbAB0LIIBAwREjmwDBCwD9CyEwwEERI5MDEBJwMjEyMBIwEDMxMzEzMDMwEzAQEjA6BoV7ZYWv538QHq8M7LW1i2WU8BfOf+PAEQ1AH1Af4KAfb+CgJbAjL+AwH9/gMB/f3D/bAAAAEAEf/uA94EoAAoAIKyGikqERI5ALAARViwDy8bsQ8aPlmwAEVYsBsvG7EbED5ZsA8QsgcBCitYIdgb9FmyDA8bERI5sigPGxESObAoL7K/KAFdsi8oAV203yjvKAJdtK8ovygCcbInAQorWCHYG/RZshQnKBESObIfGw8REjmwGxCyIQEKK1gh2Bv0WTAxATI2NzYnJicmBwYHBzY2FxYWBwYHFhYHDgInJiY3MxQXFjY3NiUnNwIBf5IKBxkzlmtFQxG2EPu3vtcKCvJVYAUHfeKJtdMFstmBqQsY/vuEGwKfYVc2JU0EAi0sUQGWsAIDpo24YiGGXWudVAICtZqxBQNmW7wCAZgAAQAfAAAEoQSNAAkATLIDCgsREjkAsABFWLAALxuxABo+WbAARViwBy8bsQcaPlmwAEVYsAIvG7ECED5ZsABFWLAFLxuxBRA+WbIEAAIREjmyCQACERI5MDEBMwMjEwEjEzMDA/WsyrKc/QmryrKcBI37cwN//IEEjfyBAAEAHgAABFcEjQAMAGiyCg0OERI5ALAARViwBC8bsQQaPlmwAEVYsAgvG7EIGj5ZsABFWLACLxuxAhA+WbAARViwCy8bsQsQPlmyBgQCERI5fLAGLxiyoAYBXbRgBnAGAl2yAQEKK1gh2Bv0WbIKAQYREjkwMQEjAyMTMwMzATMBASMBl21Xtcu0WFgB0uj91wFw2gH2/goEjf4DAf39vP23AAH/xAAABHkEjQAQAE2yBBESERI5ALAARViwAC8bsQAaPlmwAEVYsAEvG7EBED5ZsABFWLAILxuxCBA+WbAAELIDAQorWCHYG/RZsAgQsgoBCitYIdgb9FkwMQEDIxMhAwYGByM3NzY2NzcTBHnLtK/+bXU2x5VLFilgfCASbwSN+3MD9P3P6NcEpAIHnrhuAhwAAQBY/+gEVASNABEAQ7IBEhMREjkAsABFWLACLxuxAho+WbAARViwEC8bsRAaPlmwAEVYsAgvG7EIED5ZsgECCBESObINAQorWCHYG/RZMDEBFwEzAQ4CIyInNxY3MjcDMwHeFAGJ2f3aPmN8UDU0EzodXlLryAInbQLT/GRwZTQJlQgBbwOfAAEAHf6sBIYEjQALAEKyCQwNERI5ALACL7AARViwBi8bsQYaPlmwAEVYsAovG7EKGj5ZsABFWLAELxuxBBA+WbIAAQorWCHYG/RZsAnQMDElMwMjEyETMwMhEzMD16hnojv8bMu0sAI1sLWY/hQBVASN/AsD9QABAFoAAAQuBI0AEgBIsg8TFBESOQCwAEVYsAgvG7EIGj5ZsABFWLARLxuxERo+WbAARViwAC8bsQAQPlmyDgAIERI5fLAOLxiyBAEKK1gh2Bv0WTAxISMTBicmJjcTMwMGFxYXFjcTMwNktVWPnbrEFDm1OgcHFqqCsGa0AcMxAgLWvgFj/pw4LpMDAzECMgABAB0AAAX9BI0ACwBMsgYMDRESOQCwAEVYsAIvG7ECGj5ZsABFWLAGLxuxBho+WbAARViwCi8bsQoaPlmwAEVYsAAvG7EAED5ZsgkBCitYIdgb9FmwBdAwMSEhEzMDIRMzAyETMwUy+uvLtLABe7C2sAF7sLUEjfwLA/X8CwP1AAEAHf6sBf4EjQAPAFKyDBARERI5ALACL7AARViwBi8bsQYaPlmwAEVYsAovG7EKGj5ZsABFWLAOLxuxDho+WbAARViwBC8bsQQQPlmyAAEKK1gh2Bv0WbAN0LAJ0DAxJTMDIxMhEzMDIRMzAyETMwVOqWejPPr0y7SwAXuwtrABe7C2mP4UAVQEjfwLA/X8CwP1AAACAFD/+wSbBI0ADAAVAFuyBhYXERI5sAYQsA3QALAARViwCi8bsQoaPlmwAEVYsAcvG7EHED5ZsAoQsgkBCitYIdgb9FmyDAcKERI5sAwvshQBCitYIdgb9FmwBxCyFQEKK1gh2Bv0WTAxARYWBwYEJyUTITchAxM2Njc2JiclAwMwrb4UFv7swf5KsP66GwH5TLVzkQQCcWj/AEoC1gS+nqvQBAED9Jn+Sv3AAnlmWmcFAf5Z//8AH//7BaEEjQAmAggAAAAHAcID9wAAAAIAH//7A9MEjQAKABMATbILFBUREjmwCxCwBtAAsABFWLAILxuxCBo+WbAARViwBy8bsQcQPlmyCgcIERI5sAovshIBCitYIdgb9FmwBxCyEwEKK1gh2Bv0WTAxARYWBwYEJyUTMwMTNjY3NiYnJQMCaK2+FBb+7ML+TMqyTLVxlAQEcmn+/0oC1gS+nqvQBAEEjf5K/cACeGdWawUB/lkAAAEAIP/qBBoEoQAfAHOyBCAhERI5ALAARViwFS8bsRUaPlmwAEVYsBwvG7EcED5ZsADQsBwQsgMBCitYIdgb9FmyCBwVERI5fLAILxi0YAhwCAJdsqAIAV20YAhwCAJxsgcBCitYIdgb9FmwFRCyDgEKK1gh2Bv0WbAVELAS0DAxExYWFxY2NyE3ITYnJiYnJgYHBzYkFxYSBwcCACcmJifTB3R7jLwt/kgbAawIBgx8aYCbIrUmAQ/F0+EbCiL+zN693AgBend6AwO6vphDQmx+BASEdgG81gQE/s7vT/74/skGBNOzAAACAB3/6gX3BKIAFQAmAIqyAScoERI5sAEQsCLQALAARViwCS8bsQkaPlmwAEVYsA4vG7EOGj5ZsABFWLAGLxuxBhA+WbAARViwAC8bsQAQPlmyCgYJERI5fLAKLxi0YApwCgJxsqAKAV20YApwCgJdsgUBCitYIdgb9FmwDhCyGwEKK1gh2Bv0WbAAELIjAQorWCHYG/RZMDEFLgI3BwMjEzMDMzYAFxYWEgcHAgATNicmJicmBgcGFxYWFxY2NwOfhshgEddZtcu0V8lAASzTj8RXEAYh/sWwBwQJfm6S0B8WCAl+bZbOHhACifWPAf4CBI3+CfkBEwQEjv8AnzP+7/7BAoFGR3qMBAXRtYRneo8EBdTAAAL/3wAABEAEjgANABUAYbIQFhcREjmwEBCwB9AAsABFWLAHLxuxBxo+WbAARViwAC8bsQAQPlmwAEVYsAkvG7EJED5ZshEHABESObARL7ILAQorWCHYG/RZsgELERESObAHELISAQorWCHYG/RZMDEjASYmNzY2MwUDIxMhARMGFwUTJyIGIQF9XFsGC/nJAcjKtVT+4P61thbjAQJC/naRAhEmlWSmuAH7cwHf/iEDKa8BAQF8AWsAAAH/+gAABCwEjQANAGWyCw4PERI5ALAARViwCC8bsQgaPlmwAEVYsAIvG7ECED5ZsgcCCBESOXywBy8YsqAHAV20YAdwBwJdtGAHcAcCcbIEAQorWCHYG/RZsAHQsAgQsgsBCitYIdgb9FmwBxCwDNAwMQEjAyMTIzczEyEHIQMzAmXbWbVZ2xvaWALlG/3QPdsB/f4DAf2XAfmZ/qAAAf+v/qwGBASNABkArbIUGhsREjkAsAMvsABFWLAQLxuxEBo+WbAARViwFC8bsRQaPlmwAEVYsBgvG7EYGj5ZsABFWLAFLxuxBRA+WbAARViwCS8bsQkQPlmwAEVYsA0vG7ENED5ZshYQBRESOXywFi8YsqAWAV20YBZwFgJdtGAWcBYCcbIIAQorWCHYG/RZsgAIFhESObAFELIBAQorWCHYG/RZsAgQsAvQsg8WCBESObAWELAS0DAxARMzAyMTIwMjAyMTIwEjAQMzEzMTMwMzATMEQMubVaQ8cNxlV7ZYWv538QHq8M7LW1i2WU8BfOcCUP5G/hYBVAH2/goB9v4KAlsCMv4DAf3+AwH9AAABAB7+rARXBI0AEACAsgAREhESOQCwAy+wAEVYsAsvG7ELGj5ZsABFWLAPLxuxDxo+WbAARViwBi8bsQYQPlmwAEVYsAkvG7EJED5Zsg0JCxESOXywDS8YtGANcA0CcbKgDQFdtGANcA0CXbIIAQorWCHYG/RZsgAIDRESObAGELIBAQorWCHYG/RZMDEBATMDIxMjASMDIxMzAzMBMwIuARGhVaU8Xv7TbVe1y7RYWAHS6AJJ/k3+FgFUAfb+CgSN/gMB/QABAB4AAAUNBI0AFAB4sgUVFhESOQCwAEVYsAYvG7EGGj5ZsABFWLATLxuxExo+WbAARViwCS8bsQkQPlmwAEVYsBEvG7ERED5ZsgAGCRESOXywAC8YsqAAAV20YABwAAJdtGAAcAACcbAE0LAAELIQAQorWCHYG/RZsggQABESObAM0DAxATc3MwczATMBASMBJwcjNyMDIxMzAT9TJ5EtNgHS6P3WAXDa/tRBKZElTFi1y68CjwHk5QH+/bz9twH2Ac/O/goEjQAAAQBpAAAFOgSNAA4AfbIHDxAREjkAsABFWLAGLxuxBho+WbAARViwCi8bsQoaPlmwAEVYsAIvG7ECED5ZsABFWLANLxuxDRA+WbIIBgIREjl8sAgvGLKgCAFdtGAIcAgCXbRgCHAIAnGyAQEKK1gh2Bv0WbAGELIFAQorWCHYG/RZsgwBCBESOTAxASMDIxMhNyEDNwEzAQEjAnlsV7aw/rkbAfxZWQHR6f3WAXDaAfb+CgP1mP4DAQH8/bz9twAAAgBQ/+oFOASiACQAMQCishYyMxESObAWELAl0ACwAEVYsAsvG7ELGj5ZsABFWLAbLxuxGxo+WbAARViwBC8bsQQQPlmwAEVYsAAvG7EAED5ZsgIEGxESObACL7ALELIMAQorWCHYG/RZsAQQshQBCitYIdgb9FmwAhCyJwEKK1gh2Bv0WbIWFCcREjmwABCyJAEKK1gh2Bv0WbIiJCcREjmwGxCyLgEKK1gh2Bv0WTAxBSYnBicmAhM3EgA3BwYGAhcWFxYXMjcmExISFxYWFxYHAgcWFwEWFzYTNjc1JicmBgcE4MyblZf//h4DIAEa2xF1o0sOEXdCaTA/pB8a77iWoAMBDSnbSH/9/QeWxyYMAwqKe4QGFQQ3PAIEAVABEiABAwEnBJ4Bmf7RkKtKKQEJxAEuAQIBGwUEzKtBbv7atgwCAYDPY4cBFWk8LrUGBfLR//8AdAAABGUEjQAmAdIAAAAHAd4AEP7eAAH/tv6sBG0EjQAQAFqyABESERI5ALAHL7AARViwAS8bsQEaPlmwAEVYsA8vG7EPGj5ZsABFWLAMLxuxDBA+WbAARViwCi8bsQoQPlmyAAEHERI5sgQBCitYIdgb9FmyCwEHERI5MDEBATMBEzUXAyMTIwMBIwEBMwIoAWHk/hTVq1SlPGrV/pTjAfj+6MgC2wGy/bT+VQME/hcBVAG6/kYCVQI4AAABAGz+rAV/BI0ADwBWsgsQERESOQCwAi+wAEVYsAgvG7EIGj5ZsABFWLAOLxuxDho+WbAARViwBC8bsQQQPlmyAAEKK1gh2Bv0WbAIELIHAQorWCHYG/RZsAvQsAAQsA3QMDElMwMjEyETITchByEDIRMzBM+pZ6I8/Gyv/qYbA28b/qCVAjOwtpj+FAFUA/SZmfykA/UAAAEAWgAABC0EjQAYAFGyBBkaERI5ALAARViwCy8bsQsaPlmwAEVYsBcvG7EXGj5ZsABFWLAALxuxABA+WbIRCwAREjl8sBEvGLIHAQorWCHYG/RZsATQsBEQsBTQMDEhIxMGBwcjNyYmNxMzAwYXFhc3Mwc2NxMzA2O1VWdnJ5InqKESOrU7BgMKjS+RLVlzZrQBwyIKx8US1a4BY/6cMCqHHPDuDSACMgAAAQAdAAAD7ASNABMARrIQFBUREjkAsABFWLAALxuxABo+WbAARViwCS8bsQkQPlmwAEVYsBIvG7ESED5ZsgQSABESObAEL7IPAQorWCHYG/RZMDETMwM2Fx4CBwMjEzYnJicmBwMj6LVVlpR9rVANOrU6BwYWqny3ZrUEjf49MgIDYLp5/pwBZTgukQYDM/3OAAACAC//8QVhBKEAHgAnAGmyDigpERI5sA4QsCDQALAARViwDy8bsQ8aPlmwAEVYsAAvG7EAED5ZsiMADxESObAjL7K/IwFdshQBCitYIdgb9FmwBdCwIxCwDNCwABCyGgEKK1gh2Bv0WbAPELIfAQorWCHYG/RZMDEFLgI3NyYmNxcGFhc2ABceAgcHIQYXFhYXFjcXBgMmBgcFNicmJgMfk+pqHAGQlguVCUhSOAE31ZPRWRMU/MsNDBOXd4idLX5djs8qAoURCxOGDwGM9Y8IC8mhAWNtEO0BFgQCiPCahlBCaXQBAkiTVQQRA8GpAWM9XmcAAgBB/+wEZAScABcAIQBeshMiIxESObATELAY0ACwAEVYsAAvG7EAGj5ZsABFWLAILxuxCBA+WbINCAAREjmwDS+wABCyEwEKK1gh2Bv0WbAIELIYAQorWCHYG/RZsA0Qsh0BCitYIdgb9FkwMQEeAgcHBgAnLgI3NwU2JyYmJyYHJzYTFjc2NyUGFxYWApKU2mQRECL+u96Vz1kTFAMyFAwUnHWEoyqKULJzQiD9exEMEYgEnAOJ85R19/7PBAOF8JqGBVlCZnUBAkmUVfvtBJdYfQFhP11pAAABABH/6APwBI0AGwBmsgscHRESOQCwAEVYsAIvG7ECGj5ZsABFWLAMLxuxDBA+WbACELIBAQorWCHYG/RZsATQshsMAhESObAbL7IZAQorWCHYG/RZsgUbGRESObIQDAIREjmwDBCyEwEKK1gh2Bv0WTAxASE3IQcBFhYHDgInJiY3MxQWFxY2NzYmJyc3AuD91BwDIBT+dJOwCAeG4Ia10gWycmaGpgwKcHOIHgP0mX7+nxS5h3OnWAMFtZxYYwICdGdYYwUBrgAAAwBK/+oEWASkAA4AFQAcAHOyFx0eERI5sBcQsADQsBcQsBDQALAARViwBy8bsQcaPlmwAEVYsAAvG7EAED5Zsg8BCitYIdgb9FmyGQAHERI5fLAZLxiyoBkBXbRgGXAZAl20YBlwGQJxshMBCitYIdgb9FmwBxCyFgEKK1gh2Bv0WTAxBSYCNzcSABcWFhIHBwIAJxY2NyEGFgEmBgchNiYCANbgGwUgAUDkj8RXEAUc/sLgjMgu/YgPgwEeisouAncRgBAFATv0LAEMAUgGBI7/AJ4v/vP+uJ8FvbmlxwN0Bb63pMcAAAH//wAAA9gEogAnAK+yJSgpERI5ALAARViwHi8bsR4aPlmwAEVYsAwvG7EMED5ZsgYMHhESObAGL7IPBgFdsAHQsAEvQAkfAS8BPwFPAQRdsgABAV2yAgQKK1gh2Bv0WbAGELIHBAorWCHYG/RZsAwQsgsBCitYIdgb9FmwDtCwBxCwE9CwBhCwFNCwAhCwGNCwARCwGdCwHhCwItCyDyIBXbI9IgFdskwiAV2wHhCyJAEKK1gh2Bv0WTAxASEHIQcHJQclBgclByE3FzY3Nwc3Fzc3IzczNzY2FxYWByc2JyYGBwGDAZEV/nkQBQGJFf5/Jy8ChBv8nRYJRCYRoRabBBCdFpMIH+aqp6oKthCtWXoYAqh5XBIBeQFvRQKYlgEdZzEBeQESXHk62uYFBNKuAeIHA4WEAAEAHv/wA98EoQAiAJWyAyMkERI5ALAARViwFi8bsRYaPlmwAEVYsAkvG7EJED5ZsiIJFhESObAiL7IMIgFdtBAiICICXbAO0LINBAorWCHYG/RZsAHQsAkQsgQBCitYIdgb9FmwIhCwHtCwHi9ACR8eLx4/Hk8eBF2yAB4BXbAT0LIQBAorWCHYG/RZsBYQshsBCitYIdgb9FmwEBCwINAwMQEFBhYXFjcXBicmJjcHNzM3IzczNiQXFhcHJiMmAyEHIQchAvb+dAR2cVB5DXBsutsKnhWSFJMVjj0BD8RciiRZb/laAZMW/nETAZABlgF+iwIDHZcdAgLiwQF5bXnT2QICH5UfBP7peW0AAAQAHQAAB6YEogADABEAHwApAKiyKCorERI5sCgQsAHQsCgQsA3QsCgQsBPQALAARViwJi8bsSYaPlmwAEVYsCgvG7EoGj5ZsABFWLAELxuxBBo+WbAARViwIC8bsSAQPlmwAEVYsCMvG7EjED5ZsAQQsAvQsAsvsALQsAIvtAACEAICXbIBAworWCHYG/RZsAsQshUDCitYIdgb9FmwBBCyHAMKK1gh2Bv0WbIiJiAREjmyJyAmERI5MDElITchAxYWBwcGBicmJjc3NjYDBhYXFjY3NzYmJyYGBwEjAQMjEzMBEzMG7v3jGQIekpCgDAcP0JeOoQoHD9NJB0tLUWwOCQdMSVFwC/4urf5KmrXLrQG3mrS9jgNTBL6OSZ7ABAS7kEmfwP5WWmYCAmldVVxkAgJtX/y5A3T8jASN/IsDdQAC/90AAARwBI0AFgAfAHYAsABFWLAMLxuxDBo+WbAARViwAy8bsQMQPlmyBgMMERI5sAYvsBXQsgEBCitYIdgb9FmwBNCwBhCwCtCwCi+0vgrOCgJdQAkOCh4KLgo+CgRdsggBCitYIdgb9FmwFNCwChCwF9CwDBCyHwEKK1gh2Bv0WTAxJSMHIzcjNzM3IzczEwUWFgcGBCMlBzMnBTY2NzYmJyUCSPogtiC7G7oQuxu6ZwG1rsoLC/77xv7pEPvRAQJznA0MaF/+6bS0tJhZmAJQAQTIn6rTAVnxAgJ9ZWFwBAEAAAIAH//mBBEGAAATACAAZLIFISIREjmwBRCwHdAAsAovsABFWLAOLxuxDhg+WbAARViwCC8bsQgQPlmwAEVYsAUvG7EFED5ZsgcOCBESObIMDggREjmwDhCyFwEKK1gh2Bv0WbAFELIcAQorWCHYG/RZMDEBBgYHBicmJwcjATMDNhceAhcWJyYmJyYHAxYXFjY3NgQJEFlDi8XHXiueAQu1bYK6Z55XBQK4CXNkqXVROqaKxhoJAhh50kybBQSTggYA/cKQBAFoxHU9QnWJAwSu/immBAXeuloAAQBD/+gD9gRUABwAS7IAHR4REjkAsABFWLAPLxuxDxg+WbAARViwCC8bsQgQPlmyAAEKK1gh2Bv0WbIEDwgREjmyEggPERI5sA8QshYBCitYIdgb9FkwMSUWNjc3DgInJgI3NxIAFxYWByM0JicmAgcHFBYB6mGdG6wQhsxrytUZAx4BLtimzQKqcV+byQsBdoICcmIBZalfAwQBLOobAQABNAYE2axrgwQG/vjiJJSXAAIAR//nBIUGAAASACAAYbIEISIREjmwBBCwHdAAsAcvsABFWLAELxuxBBg+WbAARViwCi8bsQoQPlmwAEVYsA0vG7ENED5ZsgYEChESObILBAoREjmyGAEKK1gh2Bv0WbAEELIdAQorWCHYG/RZMDETNhI2FxYXEzMBIzcGJyYmJyY3MwYXFBYXFjcTJicmBgdQE5bZgLRhabX+9ZsOhLybuwwEBrUFAXhronVWPJ2OxhsCH6ABDYYDBIACNfoAeJEEBOW7PzwpLImjAgSjAfSTBAXctgACACT+UAQ2BFQAGwAqAHyyCyssERI5sAsQsCbQALAARViwBC8bsQQYPlmwAEVYsAcvG7EHGD5ZsABFWLAMLxuxDBI+WbAARViwFi8bsRYQPlmyBgQWERI5sAwQshEBCitYIdgb9FmyFAQWERI5sBYQsiEBCitYIdgb9FmwBBCyJgEKK1gh2Bv0WTAxEzY3NhcWFzczAwYAJyYnNxYXBBM3BicmJicmNzMGFxYWFxY3EyYnJgcGB1AXYpXywV8rm6wj/ufWuJxBeJ4BBFETiLCbuwoEBrUHBQl0Y6J3VTqgvmo4DwIfwZTgBgSRgfwU8P7yBARmi1oEBgEyVYQEBOW6Pzw+Q3WJBASlAe6WBgO7ZHf//wCpAAADBAW3AAYAFbAAAAL/1/5gBBAEUgARAB4AZLIAHyAREjmwG9AAsABFWLAJLxuxCRg+WbAARViwBi8bsQYYPlmwAEVYsAMvG7EDEj5ZsABFWLAALxuxABA+WbIHCQMREjmwCRCyFQEKK1gh2Bv0WbAAELIaAQorWCHYG/RZMDEFJicDIwE3BzYXFhYXFgcHBgATJiYnJgcDFhcWNjc2Agy7ZGG1AQSaD4i+oLgJAwcJKv7zjQt4ZJ5yWz2djs0ZCBUEe/32BdoBfpUEBN7BQD477f7hAst2iAMEmf35jwUD5LVcAAIARv5gBDUEVAARAB4Aa7IDHyAREjmwAxCwHNAAsABFWLAGLxuxBhg+WbAARViwAy8bsQMYPlmwAEVYsAgvG7EIEj5ZsABFWLAMLxuxDBA+WbIFBgwREjmyCgYMERI5shcBCitYIdgb9FmwAxCyHAEKK1gh2Bv0WTAxEzYAFxYXNzMBIxMGJy4CJyY3BhcWFhcWNxMmJyYGTyABGc65YSee/vy1YoKsZp5bBwS8BwYJd2OZd11BlZDMAh75AT0FBIRz+iYCBHwEAWfCdzhEPkR3iwMElwITiQYF5QACAEX/6wP7BFMAFQAfAF+yACAhERI5sBfQALAARViwCC8bsQgYPlmwAEVYsAAvG7EAED5ZshoIABESObAaL7S/Gs8aAl2yDAEKK1gh2Bv0WbAAELIQAQorWCHYG/RZsAgQshYBCitYIdgb9FkwMQUmAjc3Ejc2FxYSBwchBhYXFjcXBgYDJgYHBTc2JyYmAgzY7xUDHaCWxsPCGxP9Pg+Ti42SLEC2Am6uNAIRBQkHDWgTAgEv5xwBAZ6TBQb+8th6l8kEBF2BOTgDzAWboQEbNzNTXQAAAgA1/lAEKARSABwAKgB8sgsrLBESObALELAn0ACwAEVYsAcvG7EHGD5ZsABFWLAELxuxBBg+WbAARViwDC8bsQwSPlmwAEVYsBYvG7EWED5ZsgYHFhESObAMELIRAQorWCHYG/RZshQHFhESObAWELIiAQorWCHYG/RZsAQQsicBCitYIdgb9FkwMRM2EjYXFhc3MwMGACcmJzcWFxYTNwYnJiYnJyY3MwYXFhYXFjcTJicmBgdVFIvPf8FfK5uuI/7p1qiNQW+I/U8ahLGMrBQEAga2BwMEaWKeeVU8nYq3GwIepAELhQMEkYD8Aun+/QQEU4tJAgYBFXKEBATBqTY+OztDd4kEB6cB8ZQGA9bBAAEAgf/nBUEFyAAfAE6yCyAhERI5ALAARViwDC8bsQwcPlmwAEVYsAMvG7EDED5ZsgAMAxESObIQAwwREjmwDBCyFAEKK1gh2Bv0WbADELIdAQorWCHYG/RZMDEBBgAnLgInJhISJBcWABcjJicmJyYGAgcHFBYWFwQTBNws/rbjj9uDCgtd0AEUntUBBAi7Bj1Pm4fflxMDTZJlATJnAc/g/vgEA4T+naIBbQEejgME/vnfilNrBASY/tTUVHzNbAMLAVEAAAEAhP/oBUMFxwAhAFyyFCIjERI5ALAARViwDS8bsQ0cPlmwAEVYsAMvG7EDED5ZshEDDRESObANELITAQorWCHYG/RZsAMQshsBCitYIdgb9FmyIA0DERI5sCAvsh8BCitYIdgb9FkwMSUGBCcuAicmNzYSJBcWFhcjAiUmBgIXFBYWFxY3EyE3IQS2Sf7es5jkiAsFDR7PAS2x1/4SuRz+55bskgJRnWzegDz+uRwCAL5lcQMDh/+gUX7YAVywAwTp0wEaCAS6/qDIe9NwAQVuAUabAAACAEQAAAUWBbAADAAXAEayCxgZERI5sAsQsBfQALAARViwAS8bsQEcPlmwAEVYsAAvG7EAED5ZsAEQsg0BCitYIdgb9FmwABCyDgEKK1gh2Bv0WTAxMxMFMgQXFgcHBgIEBwMDFzI2NhInJiYnRP0Bj70BEz05FAMY2f6ozAnGzZT4qDsQFsCdBbABvaaevxvS/re4AQUS+4sBf+wBMX+htQQAAAIAhf/oBV4FyAATACAARrIIISIREjmwCBCwGNAAsABFWLAJLxuxCRw+WbAARViwAC8bsQAQPlmwCRCyFwEKK1gh2Bv0WbAAELIdAQorWCHYG/RZMDEFJiYCJyYSEiQXHgIXFgcHBgIEATQmJyYGAhIWFxY2EgKCjdmACwxj1QERmYzZggsFCQYd0f7RAW+pmZPzlQarlpHzkhUDiQEBnq0BXwEYjgMDh/+eVlQr0/6otgOHwO4EBLz+p/5w7gQGuAFdAAACAIX/BAVkBcgAFQAjAEayAyQlERI5sAMQsBrQALAARViwDi8bsQ4cPlmwAEVYsAUvG7EFED5ZsA4QshkBCitYIdgb9FmwBRCyIAEKK1gh2Bv0WTAxJRcHJwYjJiYCJyYSEiQXFhYSFxYCAhMmJicmBgIXFhYXFjYSA6zQi/84OorWhAsMZdMBEJqN3H8LCmHJZwOplpL1lAMDq5aS9ZA9yHHyCgGGAQOhrQFhARWOAwOJ/wCerf6h/vwC4szkBAS+/qbFyO4EBrsBYQABALsAAAMRBI0ABgAyALAARViwBS8bsQUaPlmwAEVYsAEvG7EBED5ZsgQFARESObAEL7IDAQorWCHYG/RZMDEhIxMFNyUzAky0of6CIAIUIgOhirDGAAEAOQAAA/kEowAYAE0AsABFWLAQLxuxEBo+WbAARViwAC8bsQAQPlmyGAEKK1gh2Bv0WbAC0LIEEBgREjmwEBCyCQEKK1gh2Bv0WbAQELAM0LIWGBAREjkwMSEhNwE3Njc2JicmBgcHNiQXHgIHBgcBIQOZ/KAZAjIpgAwLZVt1phWyEQEcv2uqVggQ6P5eAl2LAcEjb3NRZgIEkHgBs+sCA1OTYLu5/rMAAQAdAAAEAwXEAAcAKwCwAEVYsAYvG7EGGj5ZsABFWLAELxuxBBA+WbAGELIDAQorWCHYG/RZMDEBMwMhAyMTIQNOtVH90LC1ywIwBcT+MPwMBI0AAf+B/qEEEASNABoATgCwDS+wAEVYsAIvG7ECGj5ZsgEBCitYIdgb9FmwBNCyBQ0CERI5sAUvsA0QshIBCitYIdgb9FmwBRCyGQEKK1gh2Bv0WbIaBRkREjkwMQEhNyEHAR4CBwYGBCcmJzcWFxYkNzYmJyc3Aw39jxsDWRb+RGeVRwkPpf7rqLXRPpKrrgEAFhOVpEEPA/SZfv5wE3u7a6D9jQICZIxXBATSrJunBQFvAAL/0/62BDAEjQAKAA4ARgCwAEVYsAkvG7EJGj5ZsABFWLAGLxuxBhA+WbIMAQorWCHYG/RZsADQsAYQsAPQsAYQsAXQsAUvsAwQsAjQsAkQsA3QMDElMwcjAyMTITcBMwEhEwcDcMAbvzm2Ov0yFQNwyfynAfKMJZaX/rcBSXcEF/wJAv43AP//AJACiAL0Bb0DBwHUAHMCmAATALAARViwBy8bsQccPlmwENAwMQD//wBhApgC5AWtAwcB2ABxApgAEwCwAEVYsAkvG7EJHD5ZsA3QMDEA//8AiQKLAwIFrQMHAdkAcwKYABAAsABFWLABLxuxARw+WTAx//8AkQKKAtsFuAMHAdoAcwKYABMAsABFWLASLxuxEhw+WbAT0DAxAP//AKICmAMmBa0DBwHbAHMCmAAQALAARViwBS8bsQUcPlkwMf//AH4CjALrBbsDBwHcAHMCmAAZALAARViwEi8bsRIcPlmwGNCwEhCwJNAwMQD//wCpAo8C6gW6AwcB3QBzApgAEwCwAEVYsAgvG7EIHD5ZsBzQMDEAAAH/1f6aBEQEjAAcAFuyBx0eERI5ALAOL7AARViwAS8bsQEaPlmyAwEKK1gh2Bv0WbIHAQ4REjmwBy+wBdCyEQEOERI5sA4QshMBCitYIdgb9FmwBxCyGQEKK1gh2Bv0WbAHELAc0DAxExMhByEDNhceAgcGACcmJzcWFxY2NzYmJyYGB1jtAv8e/ZSCb5B6rE0NGP6z6cezRHPInuITD3t6W4YqAXYDFqv+c0MCAX7chu7+1AQEb4xjBQLdpIWzBAM+UQABACv+tgQ3BI0ABgAosgEHCBESOQCwAS+wAEVYsAUvG7EFGj5ZsgMBCitYIdgb9FmwANAwMQEBIwEhNyEEI/zHvwMu/TYbA40EGfqdBT+YAAIASf/yBqcEoAAWACIAnbILIyQREjmwCxCwGdAAsABFWLANLxuxDRo+WbAARViwCi8bsQoaPlmwAEVYsAIvG7ECED5ZsABFWLAALxuxABA+WbANELIPAQorWCHYG/RZshINABESObASL7QfEi8SAl2yvxIBXbITAQorWCHYG/RZsAAQshYBCitYIdgb9FmwAhCyFwEKK1gh2Bv0WbAKELIaAQorWCHYG/RZMDEhIQUjJgI3NxIAFzIWMyEHIQMhByEDIQU3EycmBgcGFxQWFwXj/ZX+2VXU3xsGIAE/5lzIYAJ0G/2uOwIFG/39QgJa/HlzoeKa1BsNAXx0DgUBOvMyAQoBQAIRmf6ymP6JCgMDaQwC3sJwMZClBAAAAgA//qUEPgSmABkAJwBRshsoKRESObAbELAN0ACwFS+wAEVYsA0vG7ENGj5ZsBUQsgABCitYIdgb9FmyBBUNERI5sAQvshoBCitYIdgb9FmwDRCyIgEKK1gh2Bv0WTAxBQQTBicuAjc2Njc2FxYSBwcGAgQnJic3FgEWNj8CNiYnJgYHBhYBQAFYnoipfrVUDQpWRo/R2NUeJyPD/uOpknwzbQE3Zac1FwYDdnSGtREPc8EHAdZsBAGB4Itsx0mXBAX+zP352v6zpwMCPYwyAfwEXFWWWoygBAPWpY/DAAACAGT/5wR4BKYAEQAgADkAsABFWLAKLxuxCho+WbAARViwAC8bsQAQPlmwChCyFQEKK1gh2Bv0WbAAELIcAQorWCHYG/RZMDEFJiYCNzc2Njc2FxYSBwcGAgYBJyYnJgIHFRQWFxY2NzYCGZXIWBICEGNRouvP4AoEE6D+AQIEH9ex5AeDeZ3XHAoVBJYBDKgUfuRSpQUF/uLxN7b+4JkC3j/+CAb+2Pkhm64EBezPXAD///8J/kYBrwQ6AAYAmwAA////Cf5GAa8EOgAGAJsAAP//AC4AAAGfBDoABgCMAAD///96/lkBnwQ6ACYAjAAAAAYAo8sK//8ALgAAAZ8EOgAGAIwAAP////H+qQGfBDoAJgCMAAAABwCsAzYACgABAB3/5wPUBKIAIQBfALAARViwFS8bsRUaPlmwAEVYsBAvG7EQED5ZsABFWLAfLxuxHxA+WbICAQorWCHYG/RZsgkfFRESObAJL7IIAworWCHYG/RZsBUQsgwBCitYIdgb9FmyGQkIERI5MDElFhcyNjc2Jyc3ASYnJgYHAyMTNjYXFhYXARYWBwYGJyYnAWVKVWGJDBPtXRkBGDxjaoYUgLSAHei8Z7Nc/ryOlwcM8LJrcbUzAoNlqwMBkgEhPAICk4b9DwLx1dwEBFhc/rISnXyv1wICMf//ABkCHwIPArYCBgARAAAAAgAvAAAE8wWwAA4AHQBtALAARViwBS8bsQUcPlmwAEVYsAAvG7EAED5ZsgMABRESObADL7LPAwFdsp8DAXGyLwMBXbRvA38DAnKyAgEKK1gh2Bv0WbAQ0LAAELIRAQorWCHYG/RZsAUQshsBCitYIdgb9FmwAxCwHdAwMTMTIzczEwUyBBIHBwIAIRMhAxcyADc2JyYmJycDIVlznRudbwF6sgEBcBcKLP5q/s28/u9YudQBJywjCw+wlN9UARICmpcCfwGy/sfCSf7C/oUCmv4DAQEI5riBm68EAf4fAAACAC8AAATzBbAADgAdAG2yDx4fERI5sA8QsAbQALAARViwBi8bsQYcPlmwAEVYsAAvG7EAED5ZsAPQsAMvsi8DAV2yzwMBXbICAQorWCHYG/RZsBDQsAAQshIBCitYIdgb9FmwBhCyGgEKK1gh2Bv0WbADELAc0LAd0DAxMxMjNzMTBTIEEgcHAgAhEyEDFzIANzYnJiYnJwMhWXOdG51vAXqyAQFwFwos/mr+zbz+71i51AEnLCMLD7CU31QBEgKalwJ/AbL+x8JJ/sL+hQKa/gMBAQjmuIGbrwQB/h8AAAEAPQAABAEGAAAaAGMAsBgvsABFWLAELxuxBBg+WbAARViwES8bsREQPlmwAEVYsAkvG7EJED5Zsi8YAV2yDxgBXbIWERgREjmwFi+yEwEKK1gh2Bv0WbAB0LAEELIOAQorWCHYG/RZsBYQsBnQMDEBIQM2FxYWBwMjEzYnJicmBwMjEyM3MzczByEC1/7tNY65mJMTdrV3BgURlKZ4hrXWphulG7UdARIE0v7kmwQCzbn9OwLIMSqMAwSy/PwE0peXlwABAKgAAAUJBbAADwBMALAARViwCi8bsQocPlmwAEVYsAIvG7ECED5ZsgYCChESObAGL7IFAQorWCHYG/RZsAHQsAoQsgkBCitYIdgb9FmwDdCwBhCwDtAwMQEjAyMTIzczEyE3IQchAzMDtN+Ou47QG885/jscBEUc/js54AM3/MkDN5cBRJ6e/rwAAAH/9P/tApQFQAAeAGoAsABFWLAZLxuxGRg+WbAARViwCy8bsQsQPlmwGRCwHdCwHS+yAB0BXbAS0LIPAQorWCHYG/RZsAHQsAsQsgYBCitYIdgb9FmwGRCyHAEKK1gh2Bv0WbAT0LAZELAW0LAZELAY0LAYLzAxASMDBhcWMzI3BwYjJiY3EyM3MzcjNzMTMwMzByMHMwJe4DgDAgdOITcOQUNsbAw21hvUH78Zvy60LsUZxB/hAlr+sBoWTgqXEgKbgwFNl7qPAQb++o+6AP///68AAASLBzQCJgAlAAABBwBEAWkBNgATALAARViwBC8bsQQcPlmwDNwwMQD///+vAAAEmAc0AiYAJQAAAQcAdQHzATYAEwCwAEVYsAUvG7EFHD5ZsA3cMDEA////rwAABIsHNgImACUAAAEHAJ0A+QE2ABMAsABFWLAELxuxBBw+WbAQ3DAxAP///68AAASvByECJgAlAAABBwCkAQEBOgATALAARViwBS8bsQUcPlmwDtwwMQD///+vAAAEiwb9AiYAJQAAAQcAagEzATYAFgCwAEVYsAQvG7EEHD5ZsBTcsCDQMDH///+vAAAEiweSAiYAJQAAAQcAogF+AUEADACwBC+wFNywF9AwMf///68AAASdB5MCJgAlAAAABwHfAYIBIv//AHT+QgT5BckCJgAnAAAABwB5AcL/9///ADsAAASxB0ACJgApAAABBwBEATcBQgATALAARViwBi8bsQYcPlmwDdwwMQD//wA7AAAEsQdAAiYAKQAAAQcAdQHBAUIACQCwBi+wDtwwMQD//wA7AAAEsQdCAiYAKQAAAQcAnQDHAUIAEwCwAEVYsAYvG7EGHD5ZsBHcMDEA//8AOwAABLEHCQImACkAAAEHAGoBAQFCAAwAsAYvsCHcsAzQMDH//wBJAAACGQdAAiYALQAAAQcARP/uAUIAEwCwAEVYsAIvG7ECHD5ZsAXcMDEA//8ASQAAAxwHQAImAC0AAAEHAHUAdwFCAAkAsAIvsAbcMDEA//8ASQAAAuIHQgImAC0AAAEHAJ3/fgFCABMAsABFWLACLxuxAhw+WbAJ3DAxAP//AEkAAAMKBwkCJgAtAAABBwBq/7gBQgAMALACL7AZ3LAE0DAx//8AOwAABXcHIQImADIAAAEHAKQBNQE6ABMAsABFWLAILxuxCBw+WbAN3DAxAP//AHf/5wUNBzYCJgAzAAABBwBEAYoBOAATALAARViwCi8bsQocPlmwJNwwMQD//wB3/+cFDQc2AiYAMwAAAQcAdQIUATgACQCwCi+wJdwwMQD//wB3/+cFDQc4AiYAMwAAAQcAnQEaATgAEwCwAEVYsAovG7EKHD5ZsCjcMDEA//8Ad//nBQ0HIwImADMAAAEHAKQBIgE8ABMAsABFWLAKLxuxChw+WbAm3DAxAP//AHf/5wUNBv8CJgAzAAABBwBqAVQBOAAMALAKL7A43LAj0DAx//8AZ//nBSAHNAImADkAAAEHAEQBZAE2ABMAsABFWLAKLxuxChw+WbAU3DAxAP//AGf/5wUgBzQCJgA5AAABBwB1Ae4BNgAJALAAL7AV3DAxAP//AGf/5wUgBzYCJgA5AAABBwCdAPQBNgATALAARViwCi8bsQocPlmwGNwwMQD//wBn/+cFIAb9AiYAOQAAAQcAagEuATYADACwAC+wKNywE9AwMf//AKgAAAUyBzQCJgA9AAABBwB1Ab0BNgAJALABL7AL3DAxAP//ADP/6APPBf4CJgBFAAABBwBEANsAAAATALAARViwGC8bsRgYPlmwLdwwMQD//wAz/+gECgX+AiYARQAAAQcAdQFlAAAACQCwGC+wLtwwMQD//wAz/+gDzwYAAiYARQAAAQYAnWsAABMAsABFWLAYLxuxGBg+WbAx3DAxAP//ADP/6AQhBesCJgBFAAABBgCkcwQACQCwGC+wNtwwMQD//wAz/+gD9wXHAiYARQAAAQcAagClAAAADACwGC+wQdywLNAwMf//ADP/6APPBlwCJgBFAAABBwCiAPAACwAMALAYL7A13LA40DAx//8AM//oBA8GXgImAEUAAAAHAd8A9P/t//8ARv5CA+YEUgImAEcAAAAHAHkBPv/3//8ARf/qA+AF/gImAEkAAAEHAEQAwAAAABMAsABFWLAILxuxCBg+WbAh3DAxAP//AEX/6gPvBf4CJgBJAAABBwB1AUoAAAAJALAIL7Ai3DAxAP//AEX/6gPgBgACJgBJAAABBgCdUAAAEwCwAEVYsAgvG7EIGD5ZsCXcMDEA//8ARf/qA+AFxwImAEkAAAEHAGoAigAAAAwAsAgvsDXcsCDQMDH//wAuAAABxwX9AiYAjAAAAQYARJz/ABMAsABFWLACLxuxAhg+WbAF3DAxAP//AC4AAALKBf0CJgCMAAABBgB1Jf8ACQCwAi+wBtwwMQD//wAuAAACkAX/AiYAjAAAAQcAnf8s//8AEwCwAEVYsAIvG7ECGD5ZsAncMDEA//8ALgAAArgFxgImAIwAAAEHAGr/Zv//ABYAsABFWLACLxuxAhg+WbAN3LAZ0DAx//8AHwAABBgF6wImAFIAAAEGAKRqBAAJALADL7Ad3DAxAP//AEX/6AQfBf4CJgBTAAABBwBEAMkAAAATALAARViwAC8bsQAYPlmwJNwwMQD//wBF/+gEHwX+AiYAUwAAAQcAdQFTAAAACQCwAC+wJdwwMQD//wBF/+gEHwYAAiYAUwAAAQYAnVkAABMAsABFWLAALxuxABg+WbAo3DAxAP//AEX/6AQfBesCJgBTAAABBgCkYQQACQCwAC+wLdwwMQD//wBF/+gEHwXHAiYAUwAAAQcAagCTAAAADACwAC+wONywI9AwMf//AFv/6AQeBf4CJgBZAAABBwBEAM0AAAATALAARViwBy8bsQcYPlmwFdwwMQD//wBb/+gEHgX+AiYAWQAAAQcAdQFXAAAACQCwBi+wFtwwMQD//wBb/+gEHgYAAiYAWQAAAQYAnV0AABMAsABFWLAGLxuxBhg+WbAZ3DAxAP//AFv/6AQeBccCJgBZAAABBwBqAJcAAAAMALAGL7Ap3LAU0DAx////pf5FA+wF/gImAF0AAAEHAHUBHgAAAAkAsAEvsBLcMDEA////pf5FA+wFxwImAF0AAAEGAGpeAAAMALABL7Al3LAQ0DAx////rwAABLQG7gImACUAAAEHAHABBAE+ABMAsABFWLAELxuxBBw+WbAM3DAxAP//ADP/6AQmBbgCJgBFAAABBgBwdggAEwCwAEVYsBgvG7EYGD5ZsC3cMDEA////rwAABIsHDwImACUAAAEHAKABLgE3ABMAsABFWLAELxuxBBw+WbAO3DAxAP//ADP/6APsBdkCJgBFAAABBwCgAKAAAQAJALAYL7Av3DAxAAAC/6/+TwSLBbAAFwAaAHSyFRscERI5sBUQsBrQALAARViwFS8bsRUcPlmwAEVYsBMvG7ETED5ZsABFWLAXLxuxFxA+WbAARViwCy8bsQsSPlmyBgMKK1gh2Bv0WbAXELAQ0LAQL7IYExUREjmwGC+yEgEKK1gh2Bv0WbIaFRMREjkwMSEXBwYHBhcWNxcGIyImNzY3AyEDIwEzAQEhAwRlBEF6CQdBIEMERFNOXwIDyEL9ssfJAxelASD9BwHfeQMvWlk/AgEaeStlUppxAWv+hAWw+lACGgKnAAIAM/5PA88EUQAvADoAnbITOzwREjmwExCwMdAAsABFWLAnLxuxJxg+WbAARViwCy8bsQsSPlmwAEVYsBQvG7EUED5ZsABFWLAvLxuxLxA+WbALELIGAworWCHYG/RZsC8QsBDQsBAvshInFBESObIaJxQREjmwGi+wJxCyHwEKK1gh2Bv0WbIiGicREjmwFBCyMAEKK1gh2Bv0WbAaELI1AQorWCHYG/RZMDEhFwcGBwYXFjcXBiMiJjc2Nyc3BicmJjc2JDMXNzYmJyYGBwc+AhcWFgcDBwYXByUWNjc3JyIGBwYWA0QEQXoJB0EgQwREU05fAgPLAwOVp4+zCAoBGeW9DApfX12PELYJgsxtqbwPWAUCDgL+LFebOCeJq7YMCVkDL1pZPwIBGnkrZVKacjAwigQCsYWswQFWYXECAl9OAV+TUQIExaP96E03NhGMAldN3wFsY0xl//8AdP/mBPkHVQImACcAAAEHAHUB/wFXAAkAsA0vsCLcMDEA//8ARv/pA+YF/gImAEcAAAEHAHUBKgAAAAkAsBEvsCPcMDEA//8AdP/mBPkHVwImACcAAAEHAJ0BBQFXAAkAsA0vsCHcMDEA//8ARv/pA+YGAAImAEcAAAEGAJ0wAAAJALARL7Ai3DAxAP//AHT/5gT5BxwCJgAnAAABBwChAdwBVwAJALANL7Ap3DAxAP//AEb/6QPmBcUCJgBHAAABBwChAQcAAAAJALARL7Aq3DAxAP//AHT/5gT5B1kCJgAnAAABBwCeARoBWAAJALANL7Ak3DAxAP//AEb/6QPmBgICJgBHAAABBgCeRQEACQCwES+wJdwwMQD//wA7AAAE1QdEAiYAKAAAAQcAngDSAUMACQCwAS+wGtwwMQD//wBL/+gFpgYCACYASAAAAAcBogSXBRP//wA7AAAEsQb6AiYAKQAAAQcAcADSAUoACQCwBi+wDNwwMQD//wBF/+oECwW4AiYASQAAAQYAcFsIAAkAsAgvsCDcMDEA//8AOwAABLEHGwImACkAAAEHAKAA/AFDAAkAsAYvsA/cMDEA//8ARf/qA+AF2QImAEkAAAEHAKAAhQABAAkAsAgvsCPcMDEA//8AOwAABLEHBwImACkAAAEHAKEBngFCAAkAsAYvsBXcMDEA//8ARf/qA+AFxQImAEkAAAEHAKEBJwAAAAkAsAgvsCncMDEAAAEAO/5PBLEFsAAcAICyFB0eERI5ALAARViwFy8bsRccPlmwAEVYsBAvG7EQEj5ZsABFWLAELxuxBBA+WbAARViwFS8bsRUQPlmyHBcEERI5sBwvsgABCitYIdgb9FmwFRCyAgEKK1gh2Bv0WbAD0LAQELILAworWCHYG/RZsBcQshkBCitYIdgb9FkwMQEhAyEHIxcHBgcGFxY3FwYjIiY3NjchEyEHIQMhA9D9nFoCyBxLBEF6CQdBIEMERFNOXwIDq/17/QN5HP1DUQJkAqH9/J0DL1pZPwIBGnkrZVKRaQWwnv4sAAACAEX+aAPZBFEAJgAuAH6yBC8wERI5sAQQsCjQALAML7AARViwGi8bsRoYPlmwAEVYsBEvG7ERED5ZsiQBCitYIdgb9FmyAhEkERI5sAwQsgcDCitYIdgb9FmyKxoRERI5sCsvtL8rzysCXbIgAQorWCHYG/RZsiYaERESObAaELInAQorWCHYG/RZMDElBgcHBgcGFxY3FwYjIiY3NjcuAjc3NhI2FxYWFxYHByEGFhcWNwMmBgcFNzYmA4tThTt1CgdBIEMERFNOXwIDcHy0VgsFEZ3ig6e+CQMHC/09EoWEoIjEcKcxAg4EEHG7dzUrV1k/AgEaeStlUnJdConoiyuhAQqHAwTWt0FBU5POBASUAqQDnpwBEH6n//8AOwAABLEHRAImACkAAAEHAJ4A3AFDAAkAsAYvsBDcMDEA//8ARf/qA+UGAgImAEkAAAEGAJ5lAQAJALAIL7Ak3DAxAP//AHn/6gUGB1cCJgArAAABBwCdAP0BVwAJALAML7Aj3DAxAP//AAT+TwQoBgACJgBLAAABBgCdUwAACQCwBC+wK9wwMQD//wB5/+oFBgcwAiYAKwAAAQcAoAEyAVgACQCwDC+wJdwwMQD//wAE/k8EKAXZAiYASwAAAQcAoACIAAEACQCwBC+wLdwwMQD//wB5/+oFBgccAiYAKwAAAQcAoQHUAVcACQCwDC+wK9wwMQD//wAE/k8EKAXFAiYASwAAAQcAoQEqAAAACQCwBC+wM9wwMQD//wB5/fYFBgXHAiYAKwAAAAcBogFY/pf//wAE/k8EKAaVAiYASwAAAQcBuQEyAFgACQCwBC+wLtwwMQD//wA7AAAFdwdCAiYALAAAAQcAnQEhAUIACQCwBi+wDdwwMQD//wAfAAAD4wdBAiYATAAAAQcAnQBUAUEADgCwES+wFNyy3xQBXTAx//8ASQAAAzQHLQImAC0AAAEHAKT/hgFGAAkAsAIvsA7cMDEA//8AEQAAAuIF6QImAIwAAAEHAKT/NAACAAkAsAIvsA7cMDEA//8ASQAAAzkG+gImAC0AAAEHAHD/iQFKAAkAsAIvsATcMDEA//8AGgAAAucFtgImAIwAAAEHAHD/NwAGAAkAsAIvsATcMDEA//8ASQAAAv8HGwImAC0AAAEHAKD/swFDAAkAsAIvsAfcMDEA//8ALgAAAq0F2AImAIwAAAEHAKD/YQAAAAkAsAIvsAfcMDEA////jv5YAgEFsAImAC0AAAAGAKPfCf///3D+TwHjBccCJgBNAAAABgCjwQD//wBJAAACNwcHAiYALQAAAQcAoQBUAUIACQCwAi+wDdwwMQD//wBJ/+YGcAWwACYALQAAAAcALgImAAD//wAv/kYDwQXHACYATQAAAAcATgHsAAD//wAK/+YFCgc1AiYALgAAAQcAnQGmATUACQCwAC+wEdwwMQD///8J/kYClgXYAiYAmwAAAQcAnf8y/9gACQCwAC+wDtwwMQD//wA7/lgFUAWwAiYALwAAAAcBogFa/vn//wAg/kUEGgYAAiYATwAAAAcBogDY/ub//wA7AAADsQcvAiYAMAAAAQcAdQBlATEACQCwBC+wCNwwMQD//wAvAAADDgeUAiYAUAAAAQcAdQBpAZYACQCwAi+wBtwwMQD//wA7/gkDsQWwAiYAMAAAAAcBogEl/qr///+j/gkB7gYAAiYAUAAAAAcBov/A/qr//wA7AAADsQWxAiYAMAAAAQcBogKaBMIAEACwAEVYsAovG7EKHD5ZMDH//wAvAAADOwYCACYAUAAAAAcBogIsBRP//wA7AAADsQWwAiYAMAAAAAcAoQFM/cX//wAvAAACrAYAACYAUAAAAAcAoQDJ/bb//wA7AAAFdwc0AiYAMgAAAQcAdQInATYACQCwBS+wDNwwMQD//wAfAAAEAQX+AiYAUgAAAQcAdQFcAAAACQCwAy+wFdwwMQD//wA7/gkFdwWwAiYAMgAAAAcBogGG/qr//wAf/gkD4wRSAiYAUgAAAAcBogDu/qr//wA7AAAFdwc4AiYAMgAAAQcAngFCATcACQCwBS+wDtwwMQD//wAfAAAD9wYCAiYAUgAAAQYAnncBAAkAsAMvsBfcMDEA//8AHwAAA+MGBAImAFIAAAAHAaIARQUV//8Ad//nBQ0G8AImADMAAAEHAHABJQFAAAkAsAovsCPcMDEA//8ARf/oBB8FuAImAFMAAAEGAHBkCAAJALAAL7Aj3DAxAP//AHf/5wUNBxECJgAzAAABBwCgAU8BOQAJALAKL7Am3DAxAP//AEX/6AQfBdkCJgBTAAABBwCgAI4AAQAJALAAL7Am3DAxAP//AHf/5wVUBzcCJgAzAAABBwClAZYBOAAMALAKL7Al3LAn0DAx//8ARf/oBJMF/wImAFMAAAEHAKUA1QAAAAwAsAAvsCXcsCfQMDH//wA6AAAEwgc0AiYANgAAAQcAdQG2ATYACQCwBC+wGtwwMQD//wAfAAADYQX+AiYAVgAAAQcAdQC8AAAACQCwCi+wD9wwMQD//wA6/gkEwgWwAiYANgAAAAcBogEd/qr///+f/gkC1ARUAiYAVgAAAAcBov+8/qr//wA6AAAEwgc4AiYANgAAAQcAngDRATcACQCwBC+wHNwwMQD//wAfAAADWAYCAiYAVgAAAQYAntgBAAkAsAovsBHcMDEA//8AJ//pBKMHNgImADcAAAEHAHUBwgE4AAkAsAovsCvcMDEA//8ALv/pA+wF/gImAFcAAAEHAHUBRwAAAAkAsAgvsCncMDEA//8AJ//pBKMHOAImADcAAAEHAJ0AyAE4AAkAsAovsCrcMDEA//8ALv/pA7YGAAImAFcAAAEGAJ1NAAAJALAIL7Ao3DAxAP//ACf+SwSjBccCJgA3AAAABwB5AZIAAP//AC7+QwO2BFACJgBXAAAABwB5AVv/+P//ACf9/wSjBccCJgA3AAAABwGiASz+oP//AC799gO2BFACJgBXAAAABwGiAPX+l///ACf/6QSjBzoCJgA3AAABBwCeAN0BOQAJALAKL7At3DAxAP//AC7/6QPiBgICJgBXAAABBgCeYgEACQCwCC+wK9wwMQD//wCo/f8FCQWwAiYAOAAAAAcBogEe/qD//wBD/f8ClAVAAiYAWAAAAAcBogCC/qD//wCo/ksFCQWwAiYAOAAAAAcAeQGEAAD//wBD/ksClAVAAiYAWAAAAAcAeQDoAAD//wCoAAAFCQc4AiYAOAAAAQcAngDSATcACQCwBi+wDNwwMQD//wBD/+0DjQZ5ACYAWAAAAAcBogJ+BYr//wBn/+cFIAchAiYAOQAAAQcApAD8AToACQCwAC+wHdwwMQD//wBb/+gEHgXrAiYAWQAAAQYApGUEAAkAsAYvsB7cMDEA//8AZ//nBSAG7gImADkAAAEHAHAA/wE+AAkAsAAvsBPcMDEA//8AW//oBB4FuAImAFkAAAEGAHBoCAAJALAGL7AU3DAxAP//AGf/5wUgBw8CJgA5AAABBwCgASkBNwAJALAAL7AW3DAxAP//AFv/6AQeBdkCJgBZAAABBwCgAJIAAQAJALAGL7AX3DAxAP//AGf/5wUgB5ICJgA5AAABBwCiAXkBQQAMALAAL7Ac3LAf0DAx//8AW//oBB4GXAImAFkAAAEHAKIA4gALAAwAsAYvsB3csCDQMDH//wBn/+cFLgc1AiYAOQAAAQcApQFwATYADACwAC+wFdywF9AwMf//AFv/6ASXBf8CJgBZAAABBwClANkAAAAMALAGL7AW3LAY0DAxAAEAZ/57BSgFsAAfAFAAsABFWLAXLxuxFxw+WbAARViwDS8bsQ0SPlmwAEVYsBIvG7ESED5ZshsBCitYIdgb9FmyBBIbERI5sA0QsggDCitYIdgb9FmwFxCwH9AwMQEDBgYHBgcGFxY3FwYjIiY3NjcmAjcTMwMGFhcWNjcTBSioF72WlQkHQSBDBERTTl8CBFbZ8RmouacRioyY0RuoBbD8J5/0NmdgPwIBGnkrZVJnUgYBD9YD2vwlma8EBrGgA9wAAQBb/k8EHgQ6ACMAYwCwAEVYsBgvG7EYGD5ZsABFWLATLxuxExA+WbAARViwIy8bsSMQPlmwAEVYsAsvG7ELEj5ZsgYDCitYIdgb9FmwIxCwENCyERMYERI5sBMQsh4BCitYIdgb9FmwGBCwIdAwMSEXBwYHBhcWNxcGIyImNzY3NwYnJiY3EzMDBhcWFhcWNxMzAwNUBEF6CQdBIEMERFNOXwIDxBR/xJuVE3S1dQUDBUxEwmqItbwDL1pZPwIBGnkrZVKXcV2DBATWuQK7/UIsKkhSAwajAxT7xgD//wDDAAAHQQc2AiYAOwAAAQcAnQHcATYACQCwAy+wFNwwMQD//wCAAAAF/gYAAiYAWwAAAQcAnQEbAAAACQCwAS+wDtwwMQD//wCoAAAFMgc2AiYAPQAAAQcAnQDDATYACQCwAS+wCtwwMQD///+l/kUD7AYAAiYAXQAAAQYAnSQAAAkAsAEvsBHcMDEA//8AqAAABTIG/QImAD0AAAEHAGoA/QE2AAwAsAEvsB7csAnQMDH////rAAAEzgc0AiYAPgAAAQcAdQG8ATYACQCwBy+wDNwwMQD////tAAADzgX+AiYAXgAAAQcAdQEkAAAACQCwBy+wDNwwMQD////rAAAEzgb7AiYAPgAAAQcAoQGZATYACQCwBy+wE9wwMQD////tAAADzgXFAiYAXgAAAQcAoQEBAAAACQCwBy+wE9wwMQD////rAAAEzgc4AiYAPgAAAQcAngDXATcACQCwBy+wDtwwMQD////tAAADzgYCAiYAXgAAAQYAnj8BAAkAsAcvsA7cMDEA////hAAAB3gHQAImAIEAAAEHAHUC9wFCABMAsABFWLAGLxuxBhw+WbAV3DAxAP//ABP/6AZhBf8CJgCGAAABBwB1AnMAAQATALAARViwFy8bsRcYPlmwRNwwMQD//wAg/6QFnAd+AiYAgwAAAQcAdQIoAYAAEwCwAEVYsA0vG7ENHD5ZsDDcMDEA//8AOf96BCoF/gImAIkAAAEHAHUBOQAAABMAsABFWLAALxuxABg+WbAu3DAxAP///7AAAAQPBI0CJgG9AAABBwHe/x3/eAAsALIfGQFxtN8Z7xkCcbQfGS8ZAl2ybxkBcrJPGQFxtO8Z/xkCXbJfGQFdMDH///+wAAAEDwSNAiYBvQAAAQcB3v8d/3gALACyHxkBcbTfGe8ZAnG0HxkvGQJdsm8ZAXKyTxkBcbTvGf8ZAl2yXxkBXTAx//8AbQAABEIEjQImAc0AAAEGAd494AAIALIACwFdMDH///+lAAAD4wYcAiYBugAAAQcARADgAB4AEwCwAEVYsAQvG7EEGj5ZsAzcMDEA////pQAABA8GHAImAboAAAEHAHUBagAeAAkAsAQvsA3cMDEA////pQAAA+MGHgImAboAAAEGAJ1wHgATALAARViwBC8bsQQaPlmwENwwMQD///+lAAAEJgYJAiYBugAAAQYApHgiAAkAsAQvsBXcMDEA////pQAAA/wF5QImAboAAAEHAGoAqgAeAAwAsAQvsCDcsAvQMDH///+lAAAD4wZ6AiYBugAAAQcAogD1ACkADACwBC+wFNywF9AwMf///6UAAAQUBnsCJgG6AAAABwHfAPkACv//AEf+SAQ3BKMCJgG8AAAABwB5AWj//f//AB0AAAPvBhwCJgG+AAABBwBEALQAHgATALAARViwBi8bsQYaPlmwDdwwMQD//wAdAAAD7wYcAiYBvgAAAQcAdQE+AB4ACQCwBi+wDtwwMQD//wAdAAAD7wYeAiYBvgAAAQYAnUQeAAkAsAYvsA3cMDEA//8AHQAAA+8F5QImAb4AAAEGAGp+HgAMALAGL7Ah3LAM0DAx//8AKgAAAcUGHAImAcIAAAEGAESaHgATALAARViwAi8bsQIaPlmwBdwwMQD//wAqAAACyAYcAiYBwgAAAQYAdSMeAAkAsAIvsAbcMDEA//8AKgAAAo4GHgImAcIAAAEHAJ3/KgAeAAkAsAIvsAXcMDEA//8AKgAAArYF5QImAcIAAAEHAGr/ZAAeAAwAsAIvsBncsATQMDH//wAdAAAEmgYJAiYBxwAAAQcApACiACIACQCwBS+wFNwwMQD//wBK/+oETgYcAiYByAAAAQcARAD4AB4AEwCwAEVYsAgvG7EIGj5ZsCHcMDEA//8ASv/qBE4GHAImAcgAAAEHAHUBggAeAAkAsAgvsCLcMDEA//8ASv/qBE4GHgImAcgAAAEHAJ0AiAAeAAkAsAgvsCHcMDEA//8ASv/qBE4GCQImAcgAAAEHAKQAkAAiAAkAsAgvsCrcMDEA//8ASv/qBE4F5QImAcgAAAEHAGoAwgAeAAwAsAgvsDXcsCDQMDH//wBF/+oEVwYcAiYBzgAAAQcARADaAB4AEwCwAEVYsAkvG7EJGj5ZsBPcMDEA//8ARf/qBFcGHAImAc4AAAEHAHUBZAAeAAkAsAAvsBTcMDEA//8ARf/qBFcGHgImAc4AAAEGAJ1qHgAJALAAL7AT3DAxAP//AEX/6gRXBeUCJgHOAAABBwBqAKQAHgAMALAAL7An3LAS0DAx//8AdAAABGUGHAImAdIAAAEHAHUBOgAeAAkAsAEvsAvcMDEA////pQAABCsF1gImAboAAAEGAHB7JgAJALAEL7AL3DAxAP///6UAAAPxBfcCJgG6AAABBwCgAKUAHwAJALAEL7AO3DAxAAAC/6X+TwPjBI0AFgAZAGuyFBobERI5sBQQsBnQALAARViwFC8bsRQaPlmwAEVYsBIvG7ESED5ZsABFWLAWLxuxFhA+WbAARViwCi8bsQoSPlmyBQMKK1gh2Bv0WbIXEhQREjmwFy+yEQEKK1gh2Bv0WbIZFBIREjkwMSEHBgcGFxY3FwYjIiY3NjcDIQMjATMBASEDA8FBegkHQSBDBERTTl8CA881/gmcwQKbogEB/XMBhGgyWlk/AgEaeStlUpp1AQL+6QSN+3MBrgH7//8AR//sBDcGHAImAbwAAAEHAHUBbwAeAAkAsAsvsB/cMDEA//8AR//sBDcGHgImAbwAAAEGAJ11HgAJALALL7Ae3DAxAP//AEf/7AQ3BeMCJgG8AAABBwChAUwAHgAJALALL7Am3DAxAP//AEf/7AQ3BiACJgG8AAABBwCeAIoAHwAJALALL7Ah3DAxAP//AB0AAAQPBiACJgG9AAABBgCeNR8ACQCwAS+wGtwwMQD//wAdAAAD/wXWAiYBvgAAAQYAcE8mAAkAsAYvsAzcMDEA//8AHQAAA+8F9wImAb4AAAEGAKB5HwAJALAGL7AP3DAxAP//AB0AAAPvBeMCJgG+AAABBwChARsAHgAJALAGL7AV3DAxAAABAB3+TwPvBI0AHACMshEdHhESOQCwAEVYsBcvG7EXGj5ZsABFWLAQLxuxEBI+WbAARViwBC8bsQQQPlmwAEVYsBUvG7EVED5ZshwXBBESObAcL7QfHC8cAl2yvxwBXbIAAQorWCHYG/RZsBUQsgIBCitYIdgb9FmwA9CwEBCyCwMKK1gh2Bv0WbAXELIZAQorWCHYG/RZMDEBIQMhByMXBwYHBhcWNxcGIyImNzY3IRMhByEDIQMx/f1CAlkbPwRBegkHQSBDBERTTl8CA6v95csDBxv9rjoCBAIO/omXAy9aWT8CARp5K2VSkWkEjZn+sgD//wAdAAAD7wYgAiYBvgAAAQYAnlkfAAkAsAYvsBDcMDEA//8ATP/uBEEGHgImAcAAAAEGAJ1zHgAJALALL7Ah3DAxAP//AEz/7gRBBfcCJgHAAAABBwCgAKgAHwAJALALL7Aj3DAxAP//AEz/7gRBBeMCJgHAAAABBwChAUoAHgAJALALL7Ap3DAxAP//AEz9/ARBBKMCJgHAAAAABwGiAQf+nf//AB0AAASaBh4CJgHBAAABBwCdAJEAHgAJALAGL7AN3DAxAP//AA8AAALgBgkCJgHCAAABBwCk/zIAIgAJALACL7AO3DAxAP//ABgAAALlBdYCJgHCAAABBwBw/zUAJgAJALACL7AE3DAxAP//ACoAAAKrBfcCJgHCAAABBwCg/18AHwAJALACL7AH3DAxAP///3r+TwGqBI0CJgHCAAAABgCjywD//wAqAAAB4wXjAiYBwgAAAQYAoQAeAAkAsAIvsA3cMDEA////9v/rBGgGHgImAcMAAAEHAJ0BBAAeAAkAsAAvsBDcMDEA//8AHf4FBH8EjQImAcQAAAAHAaIAz/6m//8AHQAAAyMGHAImAcUAAAEGAHUXHgAJALAEL7AI3DAxAP//AB3+BwMjBI0CJgHFAAAABwGiAMz+qP//AB0AAAMjBI4CJgHFAAABBwGiAhMDnwAQALAARViwCi8bsQoaPlkwMf//AB0AAAMjBI0CJgHFAAAABwChAOD9N///AB0AAASaBhwCJgHHAAABBwB1AZQAHgAJALAFL7AM3DAxAP//AB3+AwSaBI0CJgHHAAAABwGiAST+pP//AB0AAASaBiACJgHHAAABBwCeAK8AHwAJALAFL7AO3DAxAP//AEr/6gROBdYCJgHIAAABBwBwAJMAJgAJALAIL7Ag3DAxAP//AEr/6gROBfcCJgHIAAABBwCgAL0AHwAJALAIL7Aj3DAxAP//AEr/6gTCBh0CJgHIAAABBwClAQQAHgAMALAIL7Ai3LAk0DAx//8AHQAABAEGHAImAcsAAAEHAHUBLwAeAAkAsAQvsBncMDEA//8AHf4HBAEEjQImAcsAAAAHAaIAyf6o//8AHQAABAEGIAImAcsAAAEGAJ5KHwAJALAEL7Ab3DAxAP//ABH/6wPtBhwCJgHMAAABBwB1AUUAHgAJALAKL7Aq3DAxAP//ABH/6wPtBh4CJgHMAAABBgCdSx4ACQCwCi+wKdwwMQD//wAR/ksD7QSdAiYBzAAAAAcAeQFJAAD//wAR/+sD7QYgAiYBzAAAAQYAnmAfAAkAsAovsCzcMDEA//8Abf4BBEIEjQImAc0AAAAHAaIAz/6i//8AbQAABEIGIAImAc0AAAEGAJ5UHwAJALAGL7AM3DAxAP//AG3+TQRCBI0CJgHNAAAABwB5ATUAAv//AEX/6gRXBgkCJgHOAAABBgCkciIACQCwAC+wHNwwMQD//wBF/+oEVwXWAiYBzgAAAQYAcHUmAAkAsAAvsBLcMDEA//8ARf/qBFcF9wImAc4AAAEHAKAAnwAfAAkAsAAvsBXcMDEA//8ARf/qBFcGegImAc4AAAEHAKIA7wApAAwAsAAvsBvcsB7QMDH//wBF/+oEpAYdAiYBzgAAAQcApQDmAB4ADACwAC+wFNywFtAwMQABAEX+dARXBI0AIABhsgkhIhESOQCwAEVYsCAvG7EgGj5ZsABFWLAYLxuxGBo+WbAARViwDi8bsQ4SPlmwAEVYsBMvG7ETED5ZsgQTIBESObAOELIJAworWCHYG/RZsBMQshwBCitYIdgb9FkwMQEDBgYHBgYHBhcWNxcGIyImNzY3JiY3EzMDBhYXFjY3EwRXgxOkgFRKBAdBIEMERFNOXwIEYrTHE4OzhA11dHqpFYQEjfz1h8cqO2AvPwIBGnkrZVJwVQ3aqgMM/PN1gQMEgnsDDQD//wCVAAAGKQYeAiYB0AAAAQcAnQE3AB4ACQCwEi+wFNwwMQD//wB0AAAEZQYeAiYB0gAAAQYAnUAeAAkAsAEvsArcMDEA//8AdAAABGUF5QImAdIAAAEGAGp6HgAMALABL7Ae3LAJ0DAx////3AAABA4GHAImAdMAAAEHAHUBOgAeAAkAsAcvsAzcMDEA////3AAABA4F4wImAdMAAAEHAKEBFwAeAAkAsAcvsBPcMDEA////3AAABA4GIAImAdMAAAEGAJ5VHwAJALAHL7AO3DAxAP///68AAASLBj8CJgAlAAAABgCtBAD//wBjAAAFFQY/ACYAKWQAAAcArf9CAAD//wBxAAAF2wZBACYALGQAAAcArf9QAAL//wB3AAACZQZAACYALWQAAAcArf9WAAH//wBq/+cFIQY/ACYAMxQAAAcArf9JAAD////uAAAFlgY/ACYAPWQAAAcArf7NAAD//wAeAAAE7gY/ACYAuRQAAAcArf9MAAD//wAg//QDGwZ0AiYAwgAAAQcArv8t/+wAHACwAEVYsA4vG7EOGD5ZsBvcsBHQsBsQsCTQMDH///+vAAAEiwWwAgYAJQAA//8AOwAABKAFsAIGACYAAP//ADsAAASxBbACBgApAAD////rAAAEzgWwAgYAPgAA//8AOwAABXcFsAIGACwAAP//AEkAAAIBBbACBgAtAAD//wA7AAAFUAWwAgYALwAA//8AOwAABrcFsAIGADEAAP//ADsAAAV3BbACBgAyAAD//wB3/+cFDQXIAgYAMwAA//8AOwAABPMFsAIGADQAAP//AKgAAAUJBbACBgA4AAD//wCoAAAFMgWwAgYAPQAA////1AAABSsFsAIGADwAAP//AEkAAAMKBwkCJgAtAAABBwBq/7gBQgAMALACL7AZ3LAE0DAx//8AqAAABTIG/QImAD0AAAEHAGoA/QE2AAwAsAEvsB7csAnQMDH//wBI/+cEMgY6AiYAugAAAQcArQFo//sACQCwFS+wKNwwMQD//wAp/+cD5QY5AiYAvgAAAQcArQEh//oACQCwGi+wK9wwMQD//wAk/mED8wY6AiYAwAAAAQcArQE7//sACQCwAy+wFdwwMQD//wCF//QCZQYlAiYAwgAAAQYArSTmAAkAsAAvsBHcMDEA//8AZ//lBAoGdAImAMoAAAEGAK4c7AASALALL7Ar3LAW0LArELAa0DAx//8ALQAABFcEOgIGAI0AAP//AEX/6AQfBFICBgBTAAD////l/mAEJQQ6AgYAdgAA//8AbgAAA+0EOgIGAFoAAP///8QAAAP0BDoCBgBcAAD//wBn//QC3gWzAiYAwgAAAQYAaozsAAwAsAAvsCTcsA/QMDH//wBn/+UD+gWzAiYAygAAAQYAanvs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3LAi0DAx//8Ak//mBUAG+gImAN0AAAEHAHAA7AFKAAkAsAEvsBHcMDEA////pf5FA+wFuAImAF0AAAEGAHAvCAAJALABL7AQ3DAxAP//AJP/5gVABwkCJgDdAAABBwBqARsBQgAMALABL7Am3LAR0DAx////pf5FA+wFxwImAF0AAAEGAGpeAAAMALABL7Al3LAQ0DAx//8Ak//mBUAHQQImAN0AAAEHAKUBXQFCABYAsABFWLABLxuxARw+WbAT3LAX0DAx////pf5FBF4F/wImAF0AAAEHAKUAoAAAABYAsABFWLABLxuxARg+WbAS3LAW0DAx//8AzgAABUQHCQImAOAAAAEHAGoBRAFCABYAsABFWLASLxuxEhw+WbAo3LAc0DAx//8AewAABAAFswImAPgAAAEGAGpp7AAMALAIL7Ao3LAT0DAx//8ARQAABpYHCQAmAOUPAAAnAC0ElQAAAQcAagIIAUIAFgCwAEVYsAovG7EKHD5ZsCHcsC3QMDH//wAwAAAFqQWzACYA/QAAACcAjAQKAAABBwBqAWr/7AAWALAARViwCi8bsQoYPlmwIdywLdAwMf///9T+RQUrBbACJgA8AAAABwGvA5UAAP///8T+RQP0BDoCJgBcAAAABwGvAqoAAP//AEv/6AR1BgACBgBIAAD////K/kUFZQWwAiYA3AAAAAcBrwQkAAD////I/kUESgQ6AiYA8QAAAAcBrwM7AAD///+v/p8EiwWwAiYAJQAAAAcArATcAAD//wAz/p8DzwRRAiYARQAAAAcArAQpAAD///+vAAAEiwe5AiYAJQAAAQcAqgUBAUYACQCwBC+wGNwwMQD//wAz/+gDzwaDAiYARQAAAQcAqgRzABAACQCwGC+wOdwwMQD///+vAAAF7QfDAiYAJQAAAQcBtwDyAS4AFgCwAEVYsAUvG7EFHD5ZsA7csBTQMDH//wAz/+gFXwaOAiYARQAAAQYBt2T5ABYAsABFWLAYLxuxGBg+WbAv3LA10DAx////rwAABIsHvwImACUAAAEHAbYA+AE9ABYAsABFWLAFLxuxBRw+WbAM3LAT0DAx//8AM//oA/0GiQImAEUAAAEGAbZqBwAWALAARViwGC8bsRgYPlmwL9ywNNAwMf///68AAAVsB+oCJgAlAAABBwG1APMBGwAWALAARViwBS8bsQUc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ALAARViwBC8bsQQcPlmwDNywENAwMf//ADP/6APPBesCJgBFAAABBwCrA/L//QAWALAARViwGC8bsRgYPlmwLdywMdAwMf//ADsAAASxBywCJgApAAABBwCrBE4BPgAWALAARViwBi8bsQYcPlmwDdywEdAwMf//AEX/6gPgBesCJgBJAAABBwCrA9f//QAWALAARViwCC8bsQgYPlmwIdywJdAwMf///98AAAKKBywCJgAtAAABBwCrAwQBPgAWALAARViwAi8bsQIcPlmwBdywCdAwMf///40AAAI4BekCJgCMAAABBwCrArL/+wAWALAARViwAi8bsQIYPlmwBdywCdAwMf//AHf/5wUNByICJgAzAAABBwCrBKEBNAAWALAARViwCi8bsQocPlmwJNywKNAwMf//AEX/6AQfBesCJgBTAAABBwCrA+D//QAWALAARViwAC8bsQAYPlmwJNywKNAwMf//ADoAAATCByACJgA2AAABBwCrBEMBMgAWALAARViwBC8bsQQcPlmwGdywHdAwMf//AB8AAALUBesCJgBWAAABBwCrA0n//QAWALAARViwCi8bsQoYPlmwEtywDdAwMf//AGf/5wUgByACJgA5AAABBwCrBHsBMgAWALAARViwCi8bsQocPlmwFNywGNAwMf//AFv/6AQeBesCJgBZAAABBwCrA+T//QAWALAARViwBy8bsQcYPlmwFdywGdAwMf///7IAAAU8Bj8AJgDPZAAABwCt/pEAAP//ADv+qQSgBbACJgAmAAAABwCsBJgACv//AB/+lgP+BgACJgBGAAAABwCsBIb/9///ADv+qQTVBbACJgAoAAAABwCsBJcACv//AEv+nwR1BgACJgBIAAAABwCsBJkAAP//ADv+CQTVBbACJgAoAAAABwGiAR/+qv//AEv9/wR1BgACJgBIAAAABwGiASH+oP//ADv+qQV3BbACJgAsAAAABwCsBPoACv//AB/+qQPjBgACJgBMAAAABwCsBH8ACv//ADsAAAVQBy4CJgAvAAABBwB1AbABMAATALAARViwBS8bsQUcPlmwDtwwMQD//wAgAAAEIgc/AiYATwAAAQcAdQF9AUEACQCwBS+wD9wwMQD//wA7/vgFUAWwAiYALwAAAAcArATSAFn//wAg/uUEGgYAAiYATwAAAAcArARQAEb//wA7/qkDsQWwAiYAMAAAAAcArASdAAr////y/qkB7gYAAiYAUAAAAAcArAM3AAr//wA7/qkGtwWwAiYAMQAAAAcArAWnAAr//wAe/qkGagRSAiYAUQAAAAcArAWrAAr//wA7/qkFdwWwAiYAMgAAAAcArAT+AAr//wAf/qkD4wRSAiYAUgAAAAcArARmAAr//wA7AAAE8wdAAiYANAAAAQcAdQG0AUIAEwCwAEVYsAMvG7EDHD5ZsBbcMDEA////1/5gBDYF9QImAFQAAAEHAHUBkf/3ABMAsABFWLANLxuxDRg+WbAh3DAxAP//ADr+qQTCBbACJgA2AAAABwCsBJUACv///+7+qQLUBFQCJgBWAAAABwCsAzMACv//ACf+nwSjBccCJgA3AAAABwCsBKQAAP//AC7+lwO2BFACJgBXAAAABwCsBG3/+P//AKj+nwUJBbACJgA4AAAABwCsBJYAAP//AEP+nwKUBUACJgBYAAAABwCsA/oAAP//AKQAAAVhBy0CJgA6AAABBwCkAOEBRgATALAARViwAS8bsQEcPlmwCtwwMQD//wBuAAAD7QXiAiYAWgAAAQYApBv7ABMAsABFWLABLxuxARg+WbAK3DAxAP//AKT+qQVhBbACJgA6AAAABwCsBMoACv//AG7+qQPtBDoCJgBaAAAABwCsBDgACv//AMP+qQdBBbACJgA7AAAABwCsBc0ACv//AID+qQX+BDoCJgBbAAAABwCsBSwACv///+v+qQTOBbACJgA+AAAABwCsBJgACv///+3+qQPOBDoCJgBeAAAABwCsBEIACv///wz/5wVTBdYAJgAzRgAABwFa/hoAAP///6UAAAPjBRwCJgG6AAAABwCt/6v+3f///+EAAAQrBR8AJgG+PAAABwCt/sD+4P////0AAATWBRwAJgHBPAAABwCt/tz+3f//AAEAAAHmBR4AJgHCPAAABwCt/uD+3///AB3/6gRYBRwAJgHICgAABwCt/vz+3f///5sAAAShBRwAJgHSPAAABwCt/nr+3f//ABYAAAR0BRsAJgHzCgAABwCt/xT+3P///6UAAAPjBI0CBgG6AAD//wAdAAAD5wSNAgYBuwAA//8AHQAAA+8EjQIGAb4AAP///9wAAAQOBI0CBgHTAAD//wAdAAAEmgSNAgYBwQAA//8AKgAAAaoEjQIGAcIAAP//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DAAGiA7uDu4MRg6gCiIO7g7uD5oKigaSDGYMRgrYCqwNUg8QCl4L4gsQDBYGmA22DbYNtgwgCxAKUAxMDbAMTAsQBqYN5gtwD5oLcAasBrIGvAbCBsgMTAbOBtgNtgb+BxQHKgcwB0YHTAdSB4QHigeQDcANwAe+Du4H4AgCDVIIMA7uDu4LJg7uDu4IRg3ADcAIeAiCCIwIpg1ICLgNsAjSCOgLEAkyCUwJaAloCxAJYgloCWgJaAtwDCAK2AxMCxAN5g1IDqAOoA1ICtIK0grSCtIK0gmKCbAJugnECeIJ9AoGChgK/g+aD5oPmg+aDGYLcAtwC3ALcAtwC3ALcAr+DAAMAAwADAAO7g7uDu4O7g7uD5oPmg+aD5oPmgxGDEYMRgxGDxAL4gviC+IL4gviC+IL4gwWDBYMFgwWDbYMIAwgDCAMIAwgDEwMTAtwC+ILcAviC3AL4gr+Cv4K/gr+D5oMAAwWDAAMFgwADBYMAAwWDAAMFg7uDbYO7g7uDu4O7g7uDEYOoAoiCiIKIgoiDu4Ntg7uDbYO7g22DbYPmgwgD5oMIA+aDCAKUApQClAMZgxmDGYMRgxGDEYMRgxGDEYKrA8QDEwPEApeCl4KXgtwDAAO7g7uD5oPEAtwCoAMAApeDu4O7g6gDu4O7g+aCooMZg8QDVIO7g8QDbYMIAxMDCAMAA3mDu4O7gxGDqAOoAsmC3AKgA3mDAAO7g7uD5oKigr+DGYNUgviDBYMIAsQDEwNsAwWDUgMTAqsCqwKrA8QDEwK0grSCtIO7g22C3AL4gwADBYK2AxMCv4PEAxMDu4NUg2wDu4LcAviC3AL4gwADBYMFgwWDVINsA+aDCAMIAsQCyYMTAsmDEwLJgxMDVINsAtwC+ILcAviC3AL4gtwC+ILcAviC3AL4gtwC+ILcAviC3AL4gtwC+ILcAviC3AL4gwADBYMAAwWDAAMFgwADBYMAAwWDAAMFgwADBYMAAwWDu4O7g+aDCAPmgwgD5oMIA+aDCAPmgwgD5oMIA+aDCAMIAxGDEYPEAxMDxAMTA8QDEwOoA7uDGYNUg2wDeYNSA1SDbANtg3ADeYOoA7uDu4PEA+aAAIAhwAGAAYAAAALAAsAAQATABMAAgAlACoAAwAsADUACQA4AD4AEwBFAEYAGgBJAEoAHABMAEwAHgBRAFQAHwBWAFYAIwBaAFoAJABcAF0AJQCKAIoAJwCcAJwAKACwALQAKQC2ALgALgC6ALoAMQC8AL0AMgC/AMAANADCAMQANgDGAMsAOQDRANEAPwDTAN0AQADfAN8ASwDhAOMATADlAOcATwDpAO0AUgDwAPAAVwD1APcAWAD6APsAWwD9AP8AXQEDAQQAYAEJAQkAYgEMAQwAYwEXARkAZAErAS0AZwEwATAAagEyATIAawFJAUkAbAFsAW0AbQFvAXEAbwG6AboAcgG9Ab0AcwHEAcUAdAHIAcgAdgHKAcsAdwHNAc0AeQIoAigAegIqAisAewJHAkgAfQJKAkoAfwJMAm0AgAJvAnIAogJ3AnwApgKBAokArAKLAosAtQKNAo0AtgKPAo8AtwKRApEAuAKTApwAuQKlAqcAwwKpAqkAxgKrAqsAxwKtAq0AyAKvAq8AyQKyArIAygK0ArQAywK2ArYAzAK4ArgAzQK6AroAzgK8ArwAzwK+AsoA0ALMAswA3QLOAs4A3gLQAtAA3wLbAtsA4ALdAt0A4QLfAt8A4gLhAuEA4wLjAuMA5ALlAuUA5QLnAucA5gLpAukA5wLrAusA6ALtAu0A6QLvAvIA6gL0AvQA7gL2AvYA7wNTA1gA8ANbA2oA9gNtA20BBgNxA3EBBwNzA3MBCAN3A3cBCQN6A3sBCgN9A4YBDAOIA4oBFgOMA5EBGQOTA5QBHwOWA5kBIQOfA6ABJQOiA6IBJwOkA6QBKAOmA6kBKQOsA7EBLQOzA7MBMwO3A7gBNAO9A70BNgO/A8gBNwPLA8wBQQPOA9EBQwPYA9kBRwPdA90BSQPfA+UBSgPqA+sBUQPvBBcBUwQZBBkBfAQbBCgBfQQwBDABiwQzBDMBjAQ1BDUBjQRBBEYBjgRJBEkBlARLBEsBlQRNBE0BlgRPBFABlwRVBFgBmQRbBFsBnQRdBF4BngRgBGABoARkBGQBoQRmBGYBogRqBGoBowSqBKoBpAABABP/IAACAFb/5gG6/8AAAQG6AA4AAwANABQAQQASAGEAEwABAPX/9QABAMMADQACALf/wgDDABAAAQDD/+IAAQDG//IAAQDDAA4AAgDJ/+0A9f/AAAkAvv/mAMH/6wDC/+kAxP/wAMX/5wDJ/+MAy//OAMz/1ADN/9sABQDB/+wAwwAPAMX/6gDJ/8QAy//nAAUASv/pAMH/7gDD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Aor/6wKM/+sCjv/rApD/6wKS/+sClP/rApb/6wKY/+sCmv/rApz/6wKe/+sCoP/rAqL/6wKk/+sCsv74Asb/6wLI/+sCyv/rAtsAFALdABQC3wAUAuL/6gLk/+oC5v/qAuj/6gLq/+oC7P/qAvD/6ANT/1YDW/9WA2v/6wNv/+oDcf/rA3P/6AN2/+oDd//rA3j/6gN//vgDg/9WA44AFAOQ/94Dkf/rA5P/6wOV/+sDlv/oA5j/6wOf/+gDp//oA6//VgOw/94Ds//rA7j/6AO5/+sDvv/rA8D/6APF/1YDxv/eA8f/VgPI/94DzP/rA87/6wPP/+sD2f/rA9v/6wPd/+sD4f/oA+P/6APl/+gD7P/rA+//VgPw/94D8f9WA/L/3gPz/1YD9P/eA/X/VgP2/94D9/9WA/j/3gP5/1YD+v/eA/v/VgP8/94D/f9WA/7/3gP//1YEAP/eBAH/VgQC/94EA/9WBAT/3gQF/1YEBv/eBAj/6wQK/+sEDP/rBA7/6wQQ/+sEEv/rBBT/6wQW/+sEHP/rBB7/6wQg/+sEIv/rBCT/6wQm/+sEKP/rBCr/6wQs/+sELv/rBDD/6wQy/+sENP/qBDb/6gQ4/+oEOv/qBDz/6gQ+/+oEQP/qBEL/6ARE/+gERv/oBE0AFAAfADj/1QA6/+QAO//sAD3/3QDR/9UA1f/VARj/5AEy/9UBOv/VAmb/3QLb/9UC3f/VAt//1QLt/+wC7//dAvH/3QNY/90DZ//dA2r/3QOO/9UDoP/sA6L/7AOk/+wDpv/dA7f/5AO//90EQf/dBEP/3QRF/90ETf/VBGr/3QAaADj/sAA6/+0APf/QANH/sADV/7ABGP/tATL/sAE6/7ACZv/QAtv/sALd/7AC3/+wAu//0ALx/9ADWP/QA2f/0ANq/9ADjv+wA6b/0AO3/+0Dv//QBEH/0ARD/9AERf/QBE3/sARq/9AAEAAu/+4AOf/uAmL/7gJj/+4CZP/uAmX/7gKy/+4C4f/uAuP/7gLl/+4C5//uAun/7gLr/+4Df//uBDP/7gQ1/+4ARwAGABAACwAQAEf/6ABI/+gASf/oAEv/6ABV/+gAk//oAJj/6AC6/+gAx//oAMj/6AD2/+gBAv/oAR3/6AEh/+gBOf/oAUv/6AFM/+gBVv/oAWwAEAFtABABbwAQAXAAEAFxABACbv/o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/90AWv/hAF3/4QCT/9wAmP/cAJr/3QC6/9wAvP/hAMD/8wDH/9wAyP/cAMr/3QDr//MA7//zAPD/8wDy//MA8//zAPT/8wD2/9wA9//zAPn/8wD6//MA/f/zAP//8wEC/9wBBP/zARf/1gEZ/+EBHf/cASH/3AE1//MBOf/cAUT/8wFJ//MBS//cAUz/3AFW/9wCbv/cAm//3AJw/9wCcf/cAnL/3AJ3//MCeP/WAnn/1gJ6/9YCe//WAnz/1gJ9/90Cfv/dAn//3QKA/90Cgf/hAoL/4QKK/9wCjP/cAo7/3AKQ/9wCkv/cApT/3AKW/9wCmP/cApr/3AKc/9wCnv/cAqD/3AKi/9wCpP/cAr//8wLB//MCw//zAsT/8wLG/9YCyP/WAsr/1gLi/90C5P/dAub/3QLo/90C6v/dAuz/3QLw/+EDa//cA23/8wNv/90Dcf/WA3P/4QN2/90Dd//WA3j/3QOR/9wDkv/zA5P/1gOU//MDlf/cA5b/4QOY/9wDmf/zA57/8wOf/+EDp//hA67/8wOz/9wDtP/zA7j/4QO5/9wDvv/cA8D/4QPM/9wDzv/cA8//3APV//MD1//zA9n/1gPb/9wD3f/WA+H/4QPj/+ED5f/hA+n/8wPs/9wECP/cBAr/3AQM/9wEDv/cBBD/3AQS/9wEFP/cBBb/3AQc/9YEHv/WBCD/1gQi/9YEJP/WBCb/1gQo/9YEKv/cBCz/3AQu/9wEMP/WBDL/3AQ0/90ENv/dBDj/3QQ6/90EPP/dBD7/3QRA/90EQv/hBET/4QRG/+EESv/zBEz/8wRW//MEY//zBGX/8wRn//MAcQAG/9oAC//aAEf/8ABI//AASf/wAEv/8ABV//AAWf/vAFr/3ABd/9wAk//wAJj/8ACa/+8Auv/wALz/3ADH//AAyP/wAMr/7wD2//ABAv/wARn/3AEd//ABIf/wATn/8AFL//ABTP/wAVb/8AFs/9oBbf/aAW//2gFw/9oBcf/aAm7/8AJv//ACcP/wAnH/8AJy//ACff/vAn7/7wJ//+8CgP/vAoH/3AKC/9wCiv/wAoz/8AKO//ACkP/wApL/8AKU//AClv/wApj/8AKa//ACnP/wAp7/8AKg//ACov/wAqT/8ALi/+8C5P/vAub/7wLo/+8C6v/vAuz/7wLw/9wDa//wA2//7wNz/9wDdv/vA3j/7wOR//ADlf/wA5b/3AOY//ADn//cA6f/3AOo/9oDqf/aA6z/2gOz//ADuP/cA7n/8AO+//ADwP/cA8z/8APO//ADz//wA9v/8APh/9wD4//cA+X/3APs//AECP/wBAr/8AQM//AEDv/wBBD/8AQS//AEFP/wBBb/8AQq//AELP/wBC7/8AQy//AENP/vBDb/7wQ4/+8EOv/vBDz/7wQ+/+8EQP/vBEL/3ARE/9wERv/cADQABv+gAAv/oABZ//EAWv/FAF3/xQCa//EAvP/FAMr/8QEZ/8UBbP+gAW3/oAFv/6ABcP+gAXH/oAJ9//ECfv/xAn//8QKA//ECgf/FAoL/xQLi//EC5P/xAub/8QLo//EC6v/xAuz/8QLw/8UDb//xA3P/xQN2//EDeP/xA5b/xQOf/8UDp//FA6j/oAOp/6ADrP+gA7j/xQPA/8UD4f/FA+P/xQPl/8UENP/xBDb/8QQ4//EEOv/xBDz/8QQ+//EEQP/xBEL/xQRE/8UERv/FAD0AR//nAEj/5wBJ/+cAS//nAFX/5wCT/+cAmP/nALr/5wDH/+cAyP/nAPb/5wEC/+cBHf/nASH/5wE5/+cBS//nAUz/5wFW/+cCbv/nAm//5wJw/+cCcf/nAnL/5wKK/+cCjP/nAo7/5wKQ/+cCkv/nApT/5wKW/+cCmP/nApr/5wKc/+cCnv/nAqD/5wKi/+cCpP/nA2v/5wOR/+cDlf/nA5j/5wOz/+cDuf/nA77/5wPM/+cDzv/nA8//5wPb/+cD7P/nBAj/5wQK/+cEDP/nBA7/5wQQ/+cEEv/nBBT/5wQW/+cEKv/nBCz/5wQu/+cEMv/nAHEABgAMAAsADABH/+gASP/oAEn/6ABL/+gAU//qAFX/6ABaAAsAXQALAJP/6ACY/+gAuv/oALwACwDH/+gAyP/oAPb/6AEC/+gBF//qARkACwEd/+gBIf/oATn/6AFL/+gBTP/oAVb/6AFsAAwBbQAMAW8ADAFwAAwBcQAMAm7/6AJv/+gCcP/oAnH/6AJy/+gCeP/qAnn/6gJ6/+oCe//qAnz/6gKBAAsCggALAor/6AKM/+gCjv/oApD/6AKS/+gClP/oApb/6AKY/+gCmv/oApz/6AKe/+gCoP/oAqL/6AKk/+gCxv/qAsj/6gLK/+oC8AALA2v/6ANx/+oDcwALA3f/6gOR/+gDk//qA5X/6AOWAAsDmP/oA58ACwOnAAsDqAAMA6kADAOsAAwDs//oA7gACwO5/+gDvv/oA8AACwPM/+gDzv/oA8//6APZ/+oD2//oA93/6gPhAAsD4wALA+UACwPs/+gECP/oBAr/6AQM/+gEDv/oBBD/6AQS/+gEFP/oBBb/6AQc/+oEHv/qBCD/6gQi/+oEJP/qBCb/6gQo/+oEKv/oBCz/6AQu/+gEMP/qBDL/6ARCAAsERAALBEYACwAMAFz/7QBe/+0A7f/tAvP/7QL1/+0C9//tA5f/7QPD/+0D0f/tA+v/7QRQ/+0EWP/tAAwAXP/yAF7/8gDt//IC8//yAvX/8gL3//IDl//yA8P/8gPR//ID6//yBFD/8gRY//IAHwBa//QAXP/yAF3/9ABe//MAvP/0AO3/8gEZ//QCgf/0AoL/9ALw//QC8//zAvX/8wL3//MDc//0A5b/9AOX//IDn//0A6f/9AO4//QDwP/0A8P/8gPR//ID4f/0A+P/9APl//QD6//yBEL/9ARE//QERv/0BFD/8gRY//IAeQAG/8oAC//KADj/0gA6/9QAPP/0AD3/0wBR/9EAUv/RAFT/0QBa/+YAXP/vAF3/5gC8/+YAwP/RANH/0gDV/9IA2f/0AN3/7QDg/+EA6//RAO3/7wDv/9EA8P/RAPL/0QDz/9EA9P/RAPf/0QD5/9EA+v/RAP3/0QD//9EBBP/RARj/1AEZ/+YBMv/SATX/0QE6/9IBRP/RAUn/0QFs/8oBbf/KAW//ygFw/8oBcf/KAmb/0wJ3/9ECgf/mAoL/5gK//9ECwf/RAsP/0QLE/9EC2//SAt3/0gLf/9IC7//TAvD/5gLx/9MDWP/TA2f/0wNo//QDav/TA23/0QNz/+YDgv/tA47/0gOP//QDkv/RA5T/0QOW/+YDl//vA5n/0QOe/9EDn//mA6b/0wOn/+YDqP/KA6n/ygOs/8oDrv/RA7T/0QO3/9QDuP/mA7//0wPA/+YDwv/0A8P/7wPQ//QD0f/vA9X/0QPX/9ED4P/tA+H/5gPi/+0D4//mA+T/7QPl/+YD5v/hA+n/0QPq//QD6//vBEH/0wRC/+YEQ//TBET/5gRF/9MERv/mBEr/0QRM/9EETf/SBE//9ARQ/+8EUf/hBFP/4QRW/9EEV//0BFj/7wRj/9EEZf/RBGf/0QRq/9MAHQA4/74AWv/vAF3/7wC8/+8A0f++ANX/vgEZ/+8BMv++ATr/vgKB/+8Cgv/vAtv/vgLd/74C3/++AvD/7wNz/+8Djv++A5b/7wOf/+8Dp//vA7j/7wPA/+8D4f/vA+P/7wPl/+8EQv/vBET/7wRG/+8ETf++ADQAOP/mADr/5wA8//IAPf/nAFz/8QDR/+YA1f/mANn/8gDd/+4A4P/oAO3/8QEY/+cBMv/mATr/5gJm/+cC2//mAt3/5gLf/+YC7//nAvH/5wNY/+cDZ//nA2j/8gNq/+cDgv/uA47/5gOP//IDl//xA6b/5wO3/+cDv//nA8L/8gPD//ED0P/yA9H/8QPg/+4D4v/uA+T/7gPm/+gD6v/yA+v/8QRB/+cEQ//nBEX/5wRN/+YET//yBFD/8QRR/+gEU//oBFf/8gRY//EEav/nAIgAJQAQACf/6AAr/+gAM//oADX/6AA4/+AAOv/gAD3/3wCD/+gAkv/oAJf/6ACxABAAsv/oALMAEADR/+AA0v/oANMAEADV/+AA3AAQAOD/4QDxABAA+P/gAQMAEAEH/+gBDAAQARb/6AEY/+ABGv/oARz/6AEe/+gBIP/oATL/4AE4/+gBOv/gAVEAEAFV/+gCKP/oAin/6AIr/+gCLP/oAkwAEAJNABACTgAQAk8AEAJQABACUQAQAlIAEAJT/+gCXf/oAl7/6AJf/+gCYP/oAmH/6AJm/98CgwAQAoUAEAKHABACif/oAov/6AKN/+gCj//oAp3/6AKf/+gCof/oAqP/6ALF/+gCx//oAsn/6ALb/+AC3f/gAt//4ALv/98C8f/fAvr/6ANTABADV//oA1j/3wNbABADZP/oA2f/3wNq/98DgwAQA4r/6AON/+gDjv/gA6b/3wOvABADt//gA7r/6AO9/+gDv//fA8UAEAPHABAD2P/oA9r/6APc/+gD5v/hA+f/4APtABAD7gAQA+8AEAPxABAD8wAQA/UAEAP3ABAD+QAQA/sAEAP9ABAD/wAQBAEAEAQDABAEBQAQBBv/6AQd/+gEH//oBCH/6AQj/+gEJf/oBCf/6AQp/+gEK//oBC3/6AQv/+gEMf/oBEH/3wRD/98ERf/fBE3/4ARR/+EEUv/gBFP/4QRU/+AEaAAQBGkAEARq/98Eqv/oAC0AOP/xADr/9AA8//QAPf/wANH/8QDT//UA1f/xANn/9ADc//UA3f/zARj/9AEy//EBOv/xAVH/9QJm//AC2//xAt3/8QLf//EC7//wAvH/8ANY//ADZ//wA2j/9ANq//ADgv/zA47/8QOP//QDpv/wA7f/9AO///ADwv/0A9D/9APg//MD4v/zA+T/8wPq//QD7f/1BEH/8ARD//AERf/wBE3/8QRP//QEV//0BGj/9QRq//AAWQAlAA8AOP/mADr/5gA8AA4APf/mALEADwCzAA8A0f/mANMADgDV/+YA2QAOANwADgDdAAsA4P/lAPEADwD4/+gBAwAPAQwADwEY/+YBMv/mATr/5gFRAA4CTAAPAk0ADwJOAA8CTwAPAlAADwJRAA8CUgAPAmb/5gKDAA8ChQAPAocADwLb/+YC3f/mAt//5gLv/+YC8f/mA1MADwNY/+YDWwAPA2f/5gNoAA4Dav/mA4IACwODAA8Djv/mA48ADgOm/+YDrwAPA7f/5gO//+YDwgAOA8UADwPHAA8D0AAOA+AACwPiAAsD5AALA+b/5QPn/+gD6gAOA+0ADgPuAA8D7wAPA/EADwPzAA8D9QAPA/cADwP5AA8D+wAPA/0ADwP/AA8EAQAPBAMADwQFAA8EQf/mBEP/5gRF/+YETf/mBE8ADgRR/+UEUv/oBFP/5QRU/+gEVwAOBGgADgRpAA8Eav/mAC4AOP/jADz/5QA9/+QA0f/jANP/5QDV/+MA2f/lANz/5QDd/+kA8f/qAQP/6gEy/+MBOv/jAVH/5QJm/+QC2//jAt3/4wLf/+MC7//kAvH/5ANY/+QDZ//kA2j/5QNq/+QDgv/pA47/4wOP/+UDpv/kA7//5APC/+UD0P/lA+D/6QPi/+kD5P/pA+r/5QPt/+UD7v/qBEH/5ARD/+QERf/kBE3/4wRP/+UEV//lBGj/5QRp/+oEav/kACEAOP/iADz/5ADR/+IA0//kANX/4gDZ/+QA3P/kAN3/6QDx/+sBA//rATL/4gE6/+IBUf/kAtv/4gLd/+IC3//iA2j/5AOC/+kDjv/iA4//5APC/+QD0P/kA+D/6QPi/+kD5P/pA+r/5APt/+QD7v/rBE3/4gRP/+QEV//kBGj/5ARp/+sAFwA4/+sAPf/zANH/6wDV/+sBMv/rATr/6wJm//MC2//rAt3/6wLf/+sC7//zAvH/8wNY//MDZ//zA2r/8wOO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ABgEJwQnAAMEKAQoABgEMAQwABgEMwQzAAwENQQ1AAwEQQRBAA8EQgRCABkEQwRDAA8ERAREABkERQRFAA8ERgRGABkESQRJAAkESwRLAAIETQRNAAYETwRPAA4EUARQABsEVQRVAAcEVgRWAAgEVwRXAA4EWARYABsEWwRbABcEXQRdAB8EXgReAAcEYARgAAkEZARkAAIEZgRmAAIEagRqAA8EqgSqAAMAAgFtAAYABgAHAAsACwAHABAAEAATABEAEQAXABIAEgATACUAJQARACcAJwAFACsAKwAFAC4ALgAcADMAMwAFADUANQAFADcANwAZADgAOAAKADkAOQAGADoAOgANADsAOwAJADwAPAASAD0APQAOAD4APgAUAEUARQAaAEcASQAVAEsASwAVAFEAUgAYAFMAUwAIAFQAVAAYAFUAVQAVAFcAVwAbAFkAWQALAFoAWgACAFwAXAAWAF0AXQACAF4AXgAMAIMAgwAFAJIAkgAFAJMAkwAVAJcAlwAFAJgAmAAVAJoAmgALALEAsQARALIAsgAFALMAswARALoAugAVALwAvAACAMAAwAAYAMcAyAAVAMoAygALANEA0QAKANIA0gAFANMA0wABANUA1QAKANkA2QASANwA3AABAN0A3QAQAOAA4AAPAOsA6wAYAO0A7QAWAO8A8AAYAPEA8QAEAPIA9AAYAPYA9gAVAPcA9wAYAPgA+AADAPkA+gAYAP0A/QAYAP8A/wAYAQIBAgAVAQMBAwAEAQQBBAAYAQcBBwAFAQwBDAARARYBFgAFARcBFwAIARgBGAANARkBGQACARoBGgAFARwBHAAFAR0BHQAVAR4BHgAFASABIAAFASEBIQAVATIBMgAKATUBNQAYATgBOAAFATkBOQAVAToBOgAKAUQBRAAYAUkBSQAYAUsBTAAVAVEBUQABAVUBVQAFAVYBVgAVAWkBagAXAWwBbQAHAW4BbgATAW8BcQAHAXIBcgATAXYBdwATAigCKQAFAisCLAAFAkYCRgAXAkwCUgARAlMCUwAFAl0CYQAFAmICZQAGAmYCZgAOAmcCbQAaAm4CcgAVAncCdwAYAngCfAAIAn0CgAALAoECggACAoMCgwARAoQChAAaAoUChQARAoYChgAaAocChwARAogCiAAaAokCiQAFAooCigAVAosCiwAFAowCjAAVAo0CjQAFAo4CjgAVAo8CjwAFApACkAAVApICkgAVApQClAAVApYClgAVApgCmAAVApoCmgAVApwCnAAVAp0CnQAFAp4CngAVAp8CnwAFAqACoAAVAqECoQAFAqICogAVAqMCowAFAqQCpAAVArICsgAcAr8CvwAYAsECwQAYAsMCxAAYAsUCxQAFAsYCxgAIAscCxwAFAsgCyAAIAskCyQAFAsoCygAIAtEC0QAZAtIC0gAbAtMC0wAZAtQC1AAbAtUC1QAZAtYC1gAbAtcC1wAZAtgC2AAbAtkC2QAZAtoC2gAbAtsC2wAKAt0C3QAKAt8C3wAKAuEC4QAGAuIC4gALAuMC4wAGAuQC5AALAuUC5QAGAuYC5gALAucC5wAGAugC6AALAukC6QAGAuoC6gALAusC6wAGAuwC7AALAu0C7QAJAu8C7wAOAvAC8AACAvEC8QAOAvIC8gAUAvMC8wAMAvQC9AAUAvUC9QAMAvYC9gAUAvcC9wAMAvoC+gAFA1MDUwARA1cDVwAFA1gDWAAOA1sDWwARA14DXgAUA2QDZAAFA2cDZwAOA2gDaAASA2oDagAOA2sDawAVA20DbQAYA28DbwALA3EDcQAIA3MDcwACA3YDdgALA3cDdwAIA3gDeAALA38DfwAcA4IDggAQA4MDgwARA4oDigAFA40DjQAFA44DjgAKA48DjwASA5ADkAAaA5EDkQAVA5IDkgAYA5MDkwAIA5QDlAAYA5UDlQAVA5YDlgACA5cDlwAWA5gDmAAVA5kDmQAYA5oDmgAbA54DngAYA58DnwACA6ADoAAJA6IDogAJA6QDpAAJA6YDpgAOA6cDpwACA6gDqQAHA6wDrAAHA64DrgAYA68DrwARA7ADsAAaA7MDswAVA7QDtAAYA7cDtwANA7gDuAACA7kDuQAVA7oDugAFA70DvQAFA74DvgAVA78DvwAOA8ADwAACA8IDwgASA8MDwwAWA8UDxQARA8YDxgAaA8cDxwARA8gDyAAaA8wDzAAVA84DzwAVA9AD0AASA9ED0QAWA9UD1QAYA9cD1wAYA9gD2AAFA9kD2QAIA9oD2gAFA9sD2wAVA9wD3AAFA90D3QAIA+AD4AAQA+ED4QACA+ID4gAQA+MD4wACA+QD5AAQA+UD5QACA+YD5gAPA+cD5wADA+kD6QAYA+oD6gASA+sD6wAWA+wD7AAVA+0D7QABA+4D7gAEA+8D7wARA/AD8AAaA/ED8QARA/ID8gAaA/MD8wARA/QD9AAaA/UD9QARA/YD9gAaA/cD9wARA/gD+AAaA/kD+QARA/oD+gAaA/sD+wARA/wD/AAaA/0D/QARA/4D/gAaA/8D/wARBAAEAAAaBAEEAQARBAIEAgAaBAMEAwARBAQEBAAaBAUEBQARBAYEBgAaBAgECAAVBAoECgAVBAwEDAAVBA4EDgAVBBAEEAAVBBIEEgAVBBQEFAAVBBYEFgAVBBsEGwAFBBwEHAAIBB0EHQAFBB4EHgAIBB8EHwAFBCAEIAAIBCEEIQAFBCIEIgAIBCMEIwAFBCQEJAAIBCUEJQAFBCYEJgAIBCcEJwAFBCgEKAAIBCkEKQAFBCoEKgAVBCsEKwAFBCwELAAVBC0ELQAFBC4ELgAVBC8ELwAFBDAEMAAIBDEEMQAFBDIEMgAVBDMEMwAGBDQENAALBDUENQAGBDYENgALBDgEOAALBDoEOgALBDwEPAALBD4EPgALBEAEQAALBEEEQQAOBEIEQgACBEMEQwAOBEQERAACBEUERQAOBEYERgACBEoESgAYBEwETAAYBE0ETQAKBE8ETwASBFAEUAAWBFEEUQAPBFIEUgADBFMEUwAPBFQEVAADBFYEVgAYBFcEVwASBFgEWAAWBGMEYwAYBGUEZQAYBGcEZwAYBGgEaAABBGkEaQAEBGoEagAOBHAEcAAXBKoEqgAFAAEAAAAKAgYG8AAEREZMVAAaY3lybABIZ3JlawB2bGF0bgCkAAQAAAAA//8AEgAAAAoAFAAeACgANABBAEsAVQBfAGkAcwB9AIcAkQCbAKUArwAEAAAAAP//ABIAAQALABUAHwApADUAQgBMAFYAYABqAHQAfgCIAJIAnACmALAABAAAAAD//wASAAIADAAWACAAKgA2AEMATQBXAGEAawB1AH8AiQCTAJ0ApwCxACgABkFaRSAAVENSVCAAfk1PTCAAqE5BViAA1FJPTSABAFRVUiABLAAA//8AEwADAA0AFwAhACsAMgA3AEQATgBYAGIAbAB2AIAAigCUAJ4AqACyAAD//wASAAQADgAYACIALAA4AEUATwBZAGMAbQB3AIEAiwCVAJ8AqQCzAAD//wASAAUADwAZACMALQA5AEYAUABaAGQAbgB4AIIAjACWAKAAqgC0AAD//wATAAYAEAAaACQALgA6AD4ARwBRAFsAZQBvAHkAgwCNAJcAoQCrALUAAP//ABMABwARABsAJQAvADsAPwBIAFIAXABmAHAAegCEAI4AmACiAKwAtgAA//8AEwAIABIAHAAmADAAPABAAEkAUwBdAGcAcQB7AIUAjwCZAKMArQC3AAD//wATAAkAEwAdACcAMQAzAD0ASgBUAF4AaAByAHwAhgCQAJoApACuALgAuWMyc2MEWGMyc2MEWGMyc2MEWGMyc2MEWGMyc2MEWGMyc2MEWGMyc2MEWGMyc2MEWGMyc2MEWGMyc2MEWGNjbXAEXmNjbXAEXmNjbXAEXmNjbXAEXmNjbXAEXmNjbXAEXmNjbXAEXmNjbXAEXmNjbXAEXmNjbXAEXmRsaWcEZmRsaWcEZmRsaWcEZmRsaWcEZmRsaWcEZmRsaWcEZmRsaWcEZmRsaWcEZmRsaWcEZmRsaWcEZmRub20EbGRub20EbGRub20EbGRub20EbGRub20EbGRub20EbGRub20EbGRub20EbGRub20EbGRub20EbGZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmxpZ2EEfGxpZ2EEhGxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxvY2wEkGxvY2wElmxvY2wEnG51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqHBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5AAAAAEAAAAAAAIAAgADAAAAAQAHAAAAAQAYAAAAAwAVABYAFwAAAAIACAAJAAAAAQAJAAAAAQAUAAAAAQAEAAAAAQAGAAAAAQAFAAAAAQAZAAAAAQARAAAAAQATAAAAAQABAAAAAQAKAAAAAQALAAAAAQAMAAAAAQANAAAAAQAOAAAAAQAPAAAAAQAQAAAAAQASABsAOAPGBrQHYA3wDfAOBg4oDl4OhA6yDsYO2g7uDwAPGg9cD3oPmA/KD/wQLhBCEHoQbBB6EKYAAQAAAAEACAACAcQA3wHnAboBuwG8Ab0BvgG/AcABwQHCAcMBxAHFAcYBxwHIAckBygHLAcwBzQHOAc8B0AHRAdIB0wHoAekCRAI7AeoB6wHsAe0B7gHvAfAB8QHyAfMB9AH1AfYB9wH4AfkB+gH7AfwB/QH+AgACAQTdAgICAwIEAgUCBgIHAggCCQIKAgsCLwIPAhACEQIUAhUCFgIXAhgCGQIbAhwCHgIdAvwC/QL+Av8DAAMBAwIDAwMEAwUDBgMHAwgDCQMKAwsDDAMNAw4DDwMQAxEDEgMTAxQDFQMWAxcDGAMZAxoDGwMcAx0DHgMfAyADIQMiAyMDJAMlAyYDJwMoAykDKgMrAywDLQMuAy8DMAMxAzIDMwM0AzUDNgM3AzgDOQM6AzsDPAM9Az4DPwNAA0EDQgNDA0QDRgNFA0cDSANJA0oDSwNMA00DTgNPA1ADUQNSBKsErAStBK4ErwSwBLEEsgSzBLQEtQS2BLcEuAS5BLoEuwS8BL0EvgS/BMAEwQTCBMMExATFBMYB/wTHBMgEyQTKBMsEzATNBM4EzwTQBNEE0gTTBNQE1QTWBNgE2QTbAhoE3AIOBNcCEwINBNoCDAISAAEA3wAIACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgBlAGcAhQCSALAAsQCyALMAtAC1ALYAtwC4ALkA0QDSANMA1ADVANYA1wDYANkA2gDbANwA3QDeAN8A4ADhAOIA4wDkAOUA5gDnAOgBLAEwATIBOAE6ATwBPgE/AUUBRgF/AYUBigGNAkcCSAJKAkwCTQJOAk8CUAJRAlICUwJUAlUCVgJXAlgCWQJaAlsCXAJdAl4CXwJgAmECYgJjAmQCZQJmAoMChQKHAokCiwKNAo8CkQKTApUClwKZApsCnQKfAqECowKlAqcCqQKrAq0CrwKyArQCtgK4AroCvAK+AsACwgLFAscCyQLLAs0CzwLRAtMC1QLZAtsC3QLfAuEC4wLlAucC6QLrAu0C7wLxAvIC9AL2A1MDVANVA1YDVwNYA1kDWwNcA10DXgNfA2ADYQNiA2QDZQNmA2cDaANpA2oDegN7A3wDfQN+A38DgAOBA4IDgwOEA4UDhgOHA4gDiQOKA4sDjAONA44DjwO7A70DvwPUA9oD4ARJBEsETwRXBFkEXgRqAAEAAAABAAgAAgF0ALcBugG7AbwBvQG+Ab8BwAHBAcIBwwHEAcUBxgHHAcgByQHKAcsBzAHNAc4BzwHQAdEB0gHTAv0DMAI7AfoEygTLAfsB/AH9Af4B/wIABM4EzwTRBNQE3QICAgMCBAIFAgYCBwIIAgkCCgILAfQB9QH2AfcB+AH5Ai8CDwIQAhECFAIVAhcCGQL+Av8DAAMBAwIDAwMEAwUDBgMHAwgDCQMKAwsDDAMNAw4DDwMQAxEDEgMTAxQDFQMWAxcDGAMZA08DGgMbAxwDHQMeAx8DIAMhAyIDIwMkAyUDJgMnAygDKQMqAysDLAMtAy4DLwMxAzIDMwM0AzUDNgM3AzgDOQM6AzsDPAM9Az4DPwNAA0EDQgNDA0QDRgNFA0cDSANJA0oDSwNMA00DTgNQA1EDUgTJBMwEzQTQBNIE0wIBBNUEwQTCBMMExATFBMYExwTIBNYE2ATZAhgE2wIaBNwC/AIOBNcCEwINBNoCFgIMAhIAAQC3AEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0AXgCHAIwAkwDpAOoA6wDsAO0A7gDvAPAA8QDyAPMA9AD1APYA9wD4APkA+gD7APwA/QD+AP8BAAEBAQIBAwEEAQUBBgEtATEBMwE5ATsBPQFAAUcCSwJnAmgCaQJqAmsCbAJtAm4CbwJwAnECcgJzAnQCdQJ2AncCeAJ5AnoCewJ8An0CfgJ/AoACgQKCAoQChgKIAooCjAKOApACkgKUApYCmAKaApwCngKgAqICpAKmAqgCqgKsAq4CswK1ArcCuQK7Ar0CvwLBAsMCxgLIAsoCzALOAtAC0gLUAtYC2gLcAt4C4ALiAuQC5gLoAuoC7ALuAvAC8wL1AvcDkAORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwO8A74DwAPOA9UD2wPhBEcESgRMBFAEWARaBFsEXwRrAAYAAAAGABIAKgBCAFoAcgCKAAMAAAABABIAAQCQAAEAAAAaAAEAAQBNAAMAAAABABIAAQB4AAEAAAAaAAEAAQBOAAMAAAABABIAAQBgAAEAAAAaAAEAAQKuAAMAAAABABIAAQBIAAEAAAAaAAEAAQObAAMAAAABABIAAQAwAAEAAAAaAAEAAQOdAAMAAAABABIAAQAYAAEAAAAaAAEAAQQaAAIAAQCnAKsAAAAEAAAAAQAIAAEGHgA2AHIApACuALgAygD8AQ4BGAFKAWQBfgGQAboB7AH2AhgCMgJEAnYCiAKiAswC3gMQAxoDJAM2A2gDcgN8A4YDoAO6A8wD9gQoBDIEVARuBIAEsgTEBN4FCAUaBSQFLgU4BUIFbAWWBcAF6gYUAAYADgAUABoAIAAmACwCTAACAKcCTQACAKgCTwACAKkD8QACAKoEewACAKsD7wACAKwAAQAEBIgAAgCsAAEABAKJAAIAqAACAAYADASKAAIArASMAAIBogAGAA4AFAAaACAAJgAsAlQAAgCnAlUAAgCoBAsAAgCpBAkAAgCqBH0AAgCrBAcAAgCsAAIABgAMBHcAAgCoAqMAAgGiAAEABASOAAIArAAGAA4AFAAaACAAJgAsAlgAAgCnAlkAAgCoAqcAAgCpBBcAAgCqBH8AAgCrBBkAAgCsAAMACAAOABQEkAACAKgEkgACAKwCtAACAaIAAwAIAA4AFAK2AAIAqASUAAIArAK4AAIBogACAAYADAOtAAIAqASWAAIArAAFAAwAEgAYAB4AJAR5AAIApwK+AAIAqAJcAAIAqQSYAAIArALAAAIBogAGAA4AFAAaACAAJgAsAl0AAgCnAl4AAgCoAmAAAgCpBB0AAgCqBIEAAgCrBBsAAgCsAAEABASaAAIAqAAEAAoAEAAWABwCywACAKgEgwACAKsEnAACAKwCzQACAaIAAwAIAA4AFALRAAIAqASeAAIArALXAAIBogACAAYADASgAAIArALbAAIBogAGAA4AFAAaACAAJgAsAmIAAgCnAmMAAgCoAuEAAgCpBDUAAgCqBIUAAgCrBDMAAgCsAAIABgAMBKIAAgCpBKQAAgCsAAMACAAOABQDoAACAKcDogACAKgEpgACAKwABQAMABIAGAAeACQDpgACAKcCZgACAKgERQACAKkEQwACAKoEQQACAKwAAgAGAAwC8gACAKgEqAACAKwABgAOABQAGgAgACYALAJnAAIApwJoAAIAqAJqAAIAqQPyAAIAqgR8AAIAqwPwAAIArAABAAQEiQACAKwAAQAEAooAAgCoAAIABgAMBIsAAgCsBI0AAgGiAAYADgAUABoAIAAmACwCbwACAKcCcAACAKgEDAACAKkECgACAKoEfgACAKsECAACAKwAAQAEBHgAAgCoAAEABASPAAIArAABAAQEGgACAKwAAwAIAA4AFASRAAIAqASTAAIArAK1AAIBogADAAgADgAUArcAAgCoBJUAAgCsArkAAgGiAAIABgAMA64AAgCoBJcAAgCsAAUADAASABgAHgAkBHoAAgCnAr8AAgCoAncAAgCpBJkAAgCsAsEAAgGiAAYADgAUABoAIAAmACwCeAACAKcCeQACAKgCewACAKkEHgACAKoEggACAKsEHAACAKwAAQAEBJsAAgCoAAQACgAQABYAHALMAAIAqASEAAIAqwSdAAIArALOAAIBogADAAgADgAUAtIAAgCoBJ8AAgCsAtgAAgGiAAIABgAMBKEAAgCsAtwAAgGiAAYADgAUABoAIAAmACwCfQACAKcCfgACAKgC4gACAKkENgACAKoEhgACAKsENAACAKwAAgAGAAwEowACAKkEpQACAKwAAwAIAA4AFAOhAAIApwOjAAIAqASnAAIArAAFAAwAEgAYAB4AJAOnAAIApwKBAAIAqARGAAIAqQREAAIAqgRCAAIArAACAAYADALzAAIAqASpAAIArAABAAQC+AACAKgAAQAEAvoAAgCoAAEABAL5AAIAqAABAAQC+wACAKgABQAMABIAGAAeACQCcwACAKcCdAACAKgCqAACAKkEGAACAKoEgAACAKsABQAMABIAGAAeACQEKwACAKcEKQACAKgELwACAKkELQACAKoEMQACAKwABQAMABIAGAAeACQELAACAKcEKgACAKgEMAACAKkELgACAKoEMgACAKwABQAMABIAGAAeACQEOQACAKcENwACAKgEPQACAKkEOwACAKoEPwACAKwABQAMABIAGAAeACQEOgACAKcEOAACAKgEPgACAKkEPAACAKoEQAACAKwAAQAEBIcAAgCoAAIAEQAlACkAAAArAC0ABQAvADQACAA2ADsADgA9AD4AFABFAEkAFgBLAE0AGwBPAFQAHgBWAFsAJABdAF4AKgCBAIEALACDAIMALQCGAIYALgCJAIkALwCMAIwAMACXAJoAMQDPAM8ANQABAAAAAQAIAAEABgACAAEAAgLVAtYAAQAAAAEACAACAA4ABATeBN8E4AThAAEABAKHAogCmQKaAAQAAAABAAgAAQAmAAIACgAcAAIABgAMAaMAAgBKAagAAgBYAAEABAGpAAIAWAABAAIASgBXAAQAAAABAAgAAQBEAAIACgAUAAEABAGkAAIATQABAAQBpgACAE0ABAAAAAEACAABAB4AAgAKABQAAQAEAaUAAgBQAAEABAGnAAIAUAABAAIASgGjAAEAAAABAAgAAQAGAZUAAQABAEsAAQAAAAEACAABAAYBJwABAAEAugABAAAAAQAIAAEABgGsAAEAAQA2AAEAAAABAAgAAgAcAAIB4wHkAAEAAAABAAgAAgAKAAIB5QHmAAEAAgAvAE8AAQAAAAEACAACAB4ADAIoAioCKQIrAiwCHwIgAiECIgGuAiQCJQABAAwAJwAoACsAMwA1AEYARwBIAEsAUwBUAFUAAQAAAAEACAACAAwAAwImAicCJwABAAMASQBLAiIAAQAAAAEACAACAGYACAI9Ai0CLgIwAjECOQI6AjwAAQAAAAEACAACABYACAAbABUAFgAXABgAGQAdABQAAQAIAa0CIwRxBHIEcwR0BHUEdgABAAAAAQAIAAIAFgAIBHYCIwRxBHIEcwR0Aa0EdQABAAgAFAAVABYAFwAYABkAGwAdAAEAAAABAAgAAgAWAAgAFQAWABcAGAAZABsAHQAUAAEACAItAi4CMAIxAjkCOgI8Aj0AAQAAAAEACAABAAYBaQABAAEAEwAGAAAAAQAIAAMAAQASAAEAUgAAAAEAAAAaAAIAAgF8AXwAAAHUAd0AAQABAAAAAQAIAAEAKAHAAAEAAAABAAgAAgAaAAoCMgB6AHMAdAIzAjQCNQI2AjcCOAACAAEAFAAdAAAAAQAAAAEACAACACYAEAHUAdUB1gHXAdgB2QHaAdsB3AHdAkACPgJBAkICPwJDAAEAEAAUABUAFgAXABgAGQAaABsAHAAdAE0ATgKuA5sDnQQa\",\n  \"Roboto-Medium.ttf\": \"AAEAAAARAQAABAAQR1BPU32qcYwAAgioAABZDEdTVUJMnCjgAAJhtAAAGWhPUy8yoQuxtgAAAZgAAABgY21hcEAmSHIAABpsAAASyGN2dCAElytKAAAvvAAAAFZmcGdte/lhqwAALTQAAAG8Z2FzcAAIABMAAgicAAAADGdseWaunmLpAAA53AABy8xoZG14PT88IAAAFYAAAATsaGVhZPh7qwgAAAEcAAAANmhoZWEK7wqbAAABVAAAACRobXR4JPNE9QAAAfgAABOIbG9jYd3eZq0AADAUAAAJxm1heHAHEgL1AAABeAAAACBuYW1lPWNvTAACBagAAALUcG9zdP9tAGQAAgh8AAAAIHByZXAbsfg2AAAu8AAAAMwAAQAAAAIAABFApG1fDzz1ABsIAAAAAADE8BEuAAAAANDbTpT6JP3VCVwIcwAAAAkAAgAAAAAAAAABAAAHbP4MAAAJa/ok/kEJXAABAAAAAAAAAAAAAAAAAAAE4gABAAAE4gCPABYATgAFAAEAAAAAAA4AAAIAAhYABgABAAMElQH0AAUAAAWaBTMAAAEfBZoFMwAAA9EAZgIAAAACAAAAAAAAAAAA4AAK/1AAIX8AAAAhAAAAAEdPT0cAQAAA//0GAP4AAGYHmgIAIAABnwAAAAAEOgWwACAAIAACA4wAZAAAAAAAAAAAAf4AAAH+AAACJQCPApgAZQTiAGAEjABkBeAAYwUdAFYBWgBSAsoAgALSACgDiQAbBHUARAHCABwCoABHAjwAhwMqAAIEjABpBIwAqASMAFEEjABPBIwANASMAIEEjAB1BIwARQSMAGgEjABdAh8AggHnAC4EEQA/BHoAkQQqAIAD5AA8BygAWwVTABIFDACUBTkAZgU6AJQEhgCUBGUAlAVyAGoFrwCUAkIAowRxAC0FCwCUBFQAlAcBAJQFrgCUBYYAZgUdAJQFhgBgBP4AlATUAEoE2wAtBTcAfQUtABIHCgAwBRAAKQTgAAcE0QBQAjEAhANYABQCMQAMA2sANQOcAAMClAAxBFQAWgSBAHwEMABPBIQATwRLAFMC1gAtBIkAUgRxAHkCCwB9AgH/tQQtAH0CCwCMBvYAfARzAHkEjgBPBIEAfASLAE8C0AB8BCEASwKpAAgEcgB3A/UAFgXyACEEBgAfA+UADAQGAFICrwA4AgIArgKvABsFUQB1Ah4AhgR9AGQEtQBeBZ0AXQTgABkB/ACIBPgAWgOFAF0GRABXA5EAjQPiAFcEbQB/BkQAVwPbAIcDCgB/BEoAXwL2ADwC9gA3ApsAcAS7AJID7QBFAkIAjgIQAG0C9gCAA6cAdwPiAF0F0ABZBisAUAZXAGcD5ABCB4X/9gREAE0FhABpBMoAlATnAIgGwQBIBKcAZwSRAEMEiABPBJcAggWwAB8CGgCPBJgAjgRkACICTwAhBZMAkASIAH4HtABkBzoAWwIMAIsFiABRAtD/5AWKAFgEngBPBaQAfQTyAHcCJv+1BDwAWQPmAJQDsAByA9wAhwN8AHUCCwCBArIAeAJNACkD2AB6Ax8ASQJsAIIAAPyOAAD9XgAA/HMAAP0+AAD8DAAA/RwCXQDGBDwAZwJCAI4EdQCbBb8AGQV6AFsFOAAgBJAAbAWxAJsEkABHBe8ASgWqAEQFWwBrBIQAVgTGAJYEDgAgBIgAVARgAGAEGgBhBIgAfgShAHMCqgCpBGoAFgQTAGQE8wAtBIgAgAQ3AFIEkABSBC0APwRgAIAF0ABEBckATwaUAGYEswB2BHv/4QZxADMF/gAiBVkAaAiIAC0IjwCbBlsAMQWqAJIFCACQBgYAJAeiABYE1gBJBagAlAWpAC0FCgA5Bl8ATwX5AJIFiQCOB5sAmAf5AJgGGgAYBvkAmwUHAJAFUABrB1QAoAT3ACAEfQBbBI8AjwNaAIUE9gAnBnYAHgQWAE0EmACGBG4AjwSaACEGAwCPBJcAhgSYAIYD9QAjBdMAVATTAIYEZgBfBo4AhgbsAH4FFwAfBm8AjwRoAI8EPABRBoQAkQRwACcEcf/bBDwAVAbRAB4G5ACGBIn/7gSYAIYHSQCIBk8AcARn/+AHKACYBgEAhgUMABwEYAAKB0IArAY2AJ0G7QCABeYAggkyAKMH+QCPBCAAKAPwADMFegBfBIgATwUaABAEDgAgBXoAXwSIAE8HRQCIBkQAdAdJAIgGTwBwBRoAZgRKAFwE/wBtAAD8ZgAA/HMAAP17AAD9pQAA+iQAAPpNBGf/4AUTAJQEhgB8BGoAjwOhAH4EtwCbBCAAfgUsAJAEqwCOBpUANAWkAD0H0ACUBaoAfghHAJsG9QB+BioAZwT/AGEHMQAtBXAAJgV0AIAEcwB0BYcAhQYkABYEw//LBSEAkAR4AI4FrwCbBIgAfgWIAFEEpgBbBKYAXQTHADQDUwAtBQcAUgbxAGgG3QBeBlMAPAUoAC8EewBIBD4AdAe+AEIGnQBAB/0AlAaeAHcFBABdBCwAVQWqACEFHQBEBVUAgQMsAGcEFAAACCkAAAQUAAAIKQAAArkAAAIKAAABXAAABH8AAAIwAAABogAAANEAAAAAAAACoQBHAqEARwUpAJ0GMACBA50ABAHAAGMBvAAzAc4AMgGoAEoDFABsAxsAQAMIADIEXQBABJkAXALLAIgD+gCKBaYAigFsAEcHpwBKAnIAbAJpAFQDnAAtAvYANQNcAGkEtQBfBnAAIQa4AJgIkwCUB4gANQaMAHwEjABeBfUAIQQ0ACgEogAhBV4ATwV9ACgF5ABwA+IATAguAJAFCQBtBRQAlgY1AFkG3QBUBtEAWwaiAFgEkQBiBZYApgTZAEAEgwCeBLIAOwhFAF4CLf+vBI4AZQR6AJEEEQA8BCoAgAQMACQCWwChApgAYwHxAEUFGwAtBKgAGAS8AC0HIwAtByMALQURAC0GtwBLAAAAAAgwAFkINQBcBDMAOgSTAE8CEP+wAbMAXAOhAHUDoQB1A6EAdQQLAHUECwB1BAv/TAQLAHoDoQB1AgUAlASeAAkEYAB2BIAATwR6AHYD4AB2A8UAdgSmAFQE3gB2AfwAhQPVACQEWwB2A7kAdgYGAHYE3QB2BMAATwRtAHYEwABMBFwAdgQ0AD4EOwAkBIQAZwR7AAkGBwAoBF4AFQQ8AAUEKgBBAvYASwL2AIAC9gA8AvYANwL2ADUC9gBPAvYATQL2ADYC9gBLAvYARgO5AJACsgCWBDsACgS7AFYFRACbBSgAmwQwAIEFOQCbBC0AgQQ0AD4EZgA4BE0ADgO5AHYEewAJBMAATwR7AAkDmABCBNgAdgQZAEQFnQBQBVQAUATkAF8FkQAkBIAATwdUACQHVwB2BZcAJATXAHYEcQB2BVkAJwY6ABoERgBCBOQAdgRcAHYEywAkBEYAHwVdAHYEjABBBoQAdgcKAHYFWgAKBiAAdgRnAHYEgAA8BpIAdgSIAEMEIgAKBpIAGgSdAHYFGgB2BW4AJAXwAE8EWgAFBMQAFQaVACQEjABBBIwAdgX+AAoE0gBPBEYAQgTAAE8EZgA4A/cARgg2AHYE6wAoBIgAfAQ9AFAEmABPA6QAWwShAEwElAB8BJ8ATwRLAFMEiQBRBXoAawWiAGsFhgCbBeAAawXiAGsEGwCXBIIAbgO5AHYEVwAPBL4ANQL2AEsC9gA1AvYATwL2AE0C9gA2AvYASwL2AEYEawBmBC4AQwaYAE8EtABzBOsAYgIm/7UCJv+1AhsAjwIb//sCGwCPBGAAdgH+AAACoABHBVj/9wVY//cEj//UBNsALQKp/+gFUwASBVMAEgVTABIFUwASBVMAEgVTABIFUwASBTkAZgSGAJQEhgCUBIYAlASGAJQCQv/IAkIAowJC/8sCQv+/Ba4AlAWGAGYFhgBmBYYAZgWGAGYFhgBmBTcAfQU3AH0FNwB9BTcAfQTgAAcEVABaBFQAWgRUAFoEVABaBFQAWgRUAFoEVABaBDAATwRLAFMESwBTBEsAUwRLAFMCGv+0AhoAjwIa/7cCGv+rBHMAeQSOAE8EjgBPBI4ATwSOAE8EjgBPBHIAdwRyAHcEcgB3BHIAdwPlAAwD5QAMBVMAEgRUAFoFUwASBFQAWgVTABIEVABaBTkAZgQwAE8FOQBmBDAATwU5AGYEMABPBTkAZgQwAE8FOgCUBRoATwSGAJQESwBTBIYAlARLAFMEhgCUBEsAUwSGAJQESwBTBIYAlARLAFMFcgBqBIkAUgVyAGoEiQBSBXIAagSJAFIFcgBqBIkAUgWvAJQEcQB5AkL/swIa/58CQv+5Ahr/pQJC/98CGv/LAkIAFwILAAACQgCdBrMAowQMAH0EcQAtAib/tQULAJQELQB9BFQAlAILAIoEVACUAgsAVQRUAJQCoQCMBFQAlALnAIwFrgCUBHMAeQWuAJQEcwB5Ba4AlARzAHkEc/+lBYYAZgSOAE8FhgBmBI4ATwWGAGYEjgBPBP4AlALQAHwE/gCUAtAATwT+AJQC0AA4BNQASgQhAEsE1ABKBCEASwTUAEoEIQBLBNQASgQhAEsE1ABKBCEASwTbAC0CqQAIBNsALQKpAAgE2wAtAtEACAU3AH0EcgB3BTcAfQRyAHcFNwB9BHIAdwU3AH0EcgB3BTcAfQRyAHcFNwB9BHIAdwcKADAF8gAhBOAABwPlAAwE4AAHBNEAUAQGAFIE0QBQBAYAUgTRAFAEBgBSB4X/9gbBAEgFhABpBIgATwR6/6YEev+mBDsAJASeAAkEngAJBJ4ACQSeAAkEngAJBJ4ACQSeAAkEgABPA+AAdgPgAHYD4AB2A+AAdgH8/6YB/ACDAfz/qQH8/50E3QB2BMAATwTAAE8EwABPBMAATwTAAE8EhABnBIQAZwSEAGcEhABnBDwABQSeAAkEngAJBJ4ACQSAAE8EgABPBIAATwSAAE8EegBqA+AAdgPgAHYD4AB2A+AAdgPgAHYEpgBUBKYAVASmAFQEpgBUBN4AdgH8/5EB/P+XAfz/vQH8ABUB/AB8A9UAJARbAHYDuQB2A7kAdgO5AHYDuQB2BN0AdgTdAHYE3QB2BMAATwTAAE8EwABPBFwAdgRcAHYEXAB2BDQAPgQ0AD4ENAA+BDQAPgQ7ACQEOwAkBDsAJASEAGcEhABnBIQAZwSEAGcEhABnBIQAZwYHACgEPAAFBDwABQQqAEEEKgBBBCoAQQVTABIE6v9KBhP/UwKm/1YFmv+nBUT+4QVv/7ICqv+HBVMAEgUMAJQEhgCUBNEAUAWvAJQCQgCjBQsAlAcBAJQFrgCUBYYAZgUdAJQE2wAtBOAABwUQACkCQv+/BOAABwSEAFYEYABgBIgAfgKqAKkEYACABJgAjgSOAE8EuwCSA/UAFgQGAB8Cqv/MBGAAgASOAE8EYACABpQAZgSGAJQEdQCbBNQASgJCAKMCQv+/BHEALQUoAJsFCwCUBQoAOQVTABIFDACUBHUAmwSGAJQFqACUBwEAlAWvAJQFhgBmBbEAmwUdAJQFOQBmBNsALQUQACkEVABaBEsAUwSYAIYEjgBPBIEAfAQwAE8D5QAMBAYAHwRLAFMDWgCFBCEASwILAH0CGv+rAgH/tQRuAI8D5QAMBwoAMAXyACEHCgAwBfIAIQcKADAF8gAhBOAABwPlAAwBWgBSApgAZQRKAI8CJv+xAbwAMwcBAJQG9gB8BVMAEgRUAFoEhgCUBagAlARLAFMEmACGBaoARAXJAE8FGgAQBA7/8QhzAE8JawBmBNYASQQWAE0FOQBmBDAATwTgAAcEDgAgAkIAoweiABYGdgAeAkIAowVTABIEVABaBVMAEgRUAFoHhf/2BsEASASGAJQESwBTBYgAUQQ8AFkEPABZB6IAFgZ2AB4E1gBJBBYATQWoAJQEmACGBagAlASYAIYFhgBmBI4ATwV6AF8EiABPBXoAXwSIAE8FUABrBDwAUQUKADkD5QAMBQoAOQPlAAwFCgA5A+UADAWJAI4EZgBfBvkAmwZvAI8FEAApBAYAHwSEAE8FqQAtBJoAIQVTABIEVABaBVMAEgRUAFoFUwASBFQAWgVTABAEVP+aBVMAEgRUAFoFUwASBFQAWgVTABIEVABaBVMAEgRUAFoFUwASBFQAWgVTABIEVABaBVMAEgRUAFoFUwASBFQAWgSGAJQESwBTBIYAlARLAFMEhgCUBEsAUwSGAJQESwBTBIb/1QRL/44EhgCUBEsAUwSGAJQESwBTBIYAlARLAFMCQgCjAhoAjwJCAJQCCwB4BYYAZgSOAE8FhgBmBI4ATwWGAGYEjgBPBYYAJwSO/6MFhgBmBI4ATwWGAGYEjgBPBYYAZgSOAE8FigBYBJ4ATwWKAFgEngBPBYoAWASeAE8FigBYBJ4ATwWKAFgEngBPBTcAfQRyAHcFNwB9BHIAdwWkAH0E8gB3BaQAfQTyAHcFpAB9BPIAdwWkAH0E8gB3BaQAfQTyAHcE4AAHA+UADATgAAcD5QAMBOAABwPlAAwEogBPBKIATwUoAJsEbgCPBa8AlASXAIYE2wAtA/UAIwUQACkEBgAfBYkAjgRmAF8FiQCOBGYAXwR1AJsDWgCFB6IAFgZ2AB4GJAAWBMP/ywRxAHkFB//QBQf/0AR1//ADWv/iBTz/4wRE/64FqACUBJgAhgWvAJQElwCGBwEAlAYDAI8FqQAtBJoAIQTgAAcEDgAgBRAAKQQGAB8EYABgBGUAAgYwAIEEjABRBIwATwSMADQEjACBBKAAXQS0AH0FcgBqBIkAUgWuAJQEcwB5BVMAEgRUAA0EhgBIBEsAAQJC/vYCGv7iBYYAZgSOABYE/gAyAtD/bgU3AHEEcgAPBN/+rAUMAJQEgQB8BToAlASEAE8FOgCUBIQATwWvAJQEcQB5BQsAlAQtAH0FCwCUBC0AfQRUAJQCCwB4BwEAlAb2AHwFrgCUBHMAeQUdAJQEgQB8BP4AlALQAHIE1ABKBCEASwTbAC0CqQAIBS0AEgP1ABYFLQASA/UAFgcKADAF8gAhBNEAUAQGAFIFzP4cBJ4ACQQc/yoFGv83Ajj/OQTK/5MEeP7oBO7/pASeAAkEYAB2A+AAdgQqAEEE3gB2AfwAhQRbAHYGBgB2BMAATwRtAHYEOwAkBDwABQReABUB/P+dBDwABQPgAHYDuQB2BDQAPgH8AIUB/P+dA9UAJARbAHYERgAfBJ4ACQRgAHYDuQB2A+AAdgTkAHYGBgB2BN4AdgTAAE8E2AB2BG0AdgSAAE8EOwAkBF4AFQRGAEIE3gB2BIAATwQ8AAUF/gAKBOQAdgRGAB8FnQBQBVMAEgRUAFoEhgCUBEsAUwIaAHgAAAABAAAE5AkLBAAAAgICAwYFBwYCAwMEBQIDAwQFBQUFBQUFBQUFAgIFBQUECAYGBgYFBQYGAwUGBQgGBgYGBgUFBgYIBgUFAgQCBAQDBQUFBQUDBQUCAgUCCAUFBQUDBQMFBAcFBAUDAgMGAgUFBgUCBgQHBAQFBwQDBQMDAwUEAwIDBAQHBwcECAUGBQYIBQUFBQYCBQUDBgUJCAIGAwYFBgYCBQQEBAQCAwMEBAMAAAAAAAADBQMFBgYGBQYFBwYGBQUFBQUFBQUDBQUGBQUFBQUHBwcFBQcHBgoKBwYGBwkFBgYGBwcGCQkHCAYGCAYFBQQGBwUFBQUHBQUEBwUFBwgGBwUFBwUFBQgIBQUIBwUIBwYFCAcIBwoJBQQGBQYFBgUIBwgHBgUGAAAAAAAABQYFBQQFBQYFBwYJBgkIBwYIBgYFBgcFBgUGBQYFBQUEBggIBwYFBQkHCQcGBQYGBgQFCQUJAwICBQICAQADAwYHBAICAgIDBAMFBQMEBgIJAwMEAwQFBwgKCAcFBwUFBgYHBAkGBgcICAcFBgUFBQkCBQUFBQUDAwIGBQUICAYIAAkJBQUCAgQEBAUFBQUEAgUFBQUEBAUFAgQFBAcFBQUFBQUFBQUHBQUFAwMDAwMDAwMDAwQDBQUGBgUGBQUFBQQFBQUEBQUGBgYGBQgIBgUFBgcFBgUFBQYFBwgGBwUFBwUFBwUGBgcFBQcFBQcFBQUFBAkGBQUFBAUFBQUFBgYGBwcFBQQFBQMDAwMDAwMFBQcFBgICAgICBQIDBgYFBQMGBgYGBgYGBgUFBQUDAwMDBgYGBgYGBgYGBgUFBQUFBQUFBQUFBQUCAgICBQUFBQUFBQUFBQQEBgUGBQYFBgUGBQYFBgUGBgUFBQUFBQUFBQUGBQYFBgUGBQYFAwIDAgMCAwIDCAUFAgYFBQIFAgUDBQMGBQYFBgUFBgUGBQYFBgMGAwYDBQUFBQUFBQUFBQUDBQMFAwYFBgUGBQYFBgUGBQgHBQQFBQUFBQUFCAgGBQUFBQUFBQUFBQUFBAQEBAICAgIFBQUF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AAADfwAABBsAAAQbAAAA3AAABBwAAAQiAAADhwAABCMAAAQkAAAA3QAABCUAAAQlAAADjgAABCYAAAQvAAAA3wAABDAAAAQwAAADjwAABDEAAAQ0AAAA6QAABDUAAAQ1AAADkAAABDYAAAQ4AAAA7QAABDkAAAQ5AAADkQAABDoAAAQ9AAAA8AAABD4AAAQ+AAADkgAABD8AAAQ/AAAA9AAABEAAAARBAAADkwAABEIAAARCAAAA9QAABEMAAARDAAADlQAABEQAAAREAAAA9gAABEUAAARFAAADlgAABEYAAARPAAAA9wAABFAAAARQAAADsgAABFEAAARRAAADlwAABFIAAARSAAABAQAABFMAAARTAAADmAAABFQAAARUAAABAgAABFUAAARYAAADmQAABFkAAARbAAABAwAABFwAAARcAAADnQAABF0AAARdAAADswAABF4AAAReAAADngAABF8AAARhAAABBgAABGIAAARiAAAEXAAABGMAAARvAAABCQAABHAAAARxAAADtAAABHIAAAR1AAABFgAABHYAAAR3AAADtgAABHgAAAR4AAADuQAABHkAAAR5AAADuAAABHoAAASGAAABGgAABIgAAASJAAABJwAABIoAAASLAAAEYQAABIwAAASMAAAEWwAABI0AAASRAAABKQAABJIAAASTAAAEXQAABJQAAASVAAABLgAABJYAAASXAAAEVgAABJgAAASZAAADugAABJoAAASbAAAESAAABJwAAASdAAABMAAABJ4AAASfAAAEXwAABKAAAAShAAABMgAABKIAAASjAAAESgAABKQAAASpAAABNAAABKoAAASrAAADvAAABKwAAAStAAAETAAABK4AAASvAAADvgAABLAAAASxAAAEaQAABLIAAASzAAAETgAABLQAAAS1AAABOgAABLYAAAS3AAAEUAAABLgAAAS6AAABPAAABLsAAAS7AAAEWgAABLwAAAS9AAABPwAABL4AAAS/AAAEWAAABMAAAATCAAADwAAABMMAAATEAAABQQAABMUAAATGAAAEZwAABMcAAATIAAABQwAABMkAAATKAAAEYwAABMsAAATMAAAEUgAABM0AAATOAAAEZQAABM8AAATXAAADwwAABNgAAATYAAABRQAABNkAAATZAAADzQAABNoAAATaAAADzAAABNsAAATfAAADzgAABOAAAAThAAABRgAABOIAAAT1AAAD0wAABPYAAAT3AAAEVAAABPgAAAT5AAAD5wAABPoAAAT7AAABSAAABPwAAAT9AAAD6QAABP4AAAT/AAAEawAABQAAAAUAAAABSgAABQEAAAUBAAAD6wAABQIAAAUQAAABSwAABREAAAURAAAEbQAABRIAAAUTAAAD7AAAHgAAAB4BAAADrgAAHj4AAB4/AAADrAAAHoAAAB6FAAADnwAAHqAAAB7xAAAD7gAAHvIAAB7zAAADpQAAHvQAAB75AAAEQAAAH00AAB9NAAAEqQAAIAAAACALAAABWwAAIBAAACARAAABZwAAIBMAACAUAAABaQAAIBUAACAVAAAEbwAAIBcAACAeAAABawAAICAAACAiAAABcwAAICUAACAnAAABdgAAIDAAACAwAAABeQAAIDIAACAzAAADpwAAIDkAACA6AAABegAAIDwAACA8AAADqQAAIEQAACBEAAABfAAAIHQAACB0AAABfQAAIH8AACB/AAABfgAAIKMAACCjAAAEbgAAIKQAACCkAAABfwAAIKYAACCqAAABgAAAIKsAACCrAAAERwAAIKwAACCsAAABhQAAILEAACCxAAABhgAAILkAACC6AAABhwAAILwAACC9AAABiQAAIQUAACEFAAABiwAAIRMAACETAAABjAAAIRYAACEWAAABjQAAISIAACEiAAABjgAAISYAACEmAAAAuQAAIS4AACEuAAABjwAAIVsAACFeAAABkAAAIgIAACICAAABlAAAIgYAACIGAAAAsQAAIg8AACIPAAABlQAAIhEAACISAAABlgAAIhoAACIaAAABmAAAIh4AACIeAAABmQAAIisAACIrAAABmgAAIkgAACJIAAABmwAAImAAACJgAAABnAAAImQAACJlAAABnQAAJcoAACXKAAABnwAA7gEAAO4CAAABoAAA9sMAAPbDAAABogAA+wEAAPsEAAABpAAA/v8AAP7/AAABqgAA//wAAP/9AAABq7AALEuwCVBYsQEBjlm4Af+FsIQdsQkDX14tsAEsICBFaUSwAWAtsAIssAEqIS2wAywgRrADJUZSWCNZIIogiklkiiBGIGhhZLAEJUYgaGFkUlgjZYpZLyCwAFNYaSCwAFRYIbBAWRtpILAAVFghsEBlWVk6LbAELCBGsAQlRlJY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seix/7IWsi6yRbJcsnOyi7KdsrSyy7LisvmzEbMoszqzUbNps4Czl7Ops7+z1bPstAS0ELQctDO0RbRbtHK0iLSetLW0zbTetPW1B7UdtS61RrVdtW+1hbWcta61xbXcte22BLYbtoW3J7c5t0u3Yrd4t4+3pre4t8m327fruAK4E7gquEC4V7huuNu5crmJuZq5sbnHud659LoLuiK6LrpAule6abqAupK6qbrAute67rr5uwS7G7snuzO7Srthu227ebuQu6e7s7u/u9S76bv1vAG8GLwqvDa8QrxZvGq8f7yWvKe8vrzVvO29Bb0XvSm9Nb1BvVO9ZL12vYi9n721vcG9zb3ZveW9974IvhS+IL4svji+T75bvnK+iL6avrC+x77evvG/BL8cvy+/jb/vwAbAHcA0wErAYsB5wJDAp8C+wNDA4cD4wQrBIcE4wWjBmMGowb/B1sHswf3CFcItwjnCRcJcwnPCicKgwrfCzcLkwvzDDsMlwzfDTcNew3bDjcOkw7rD0sPpw//EFsR9xI/EpcS8xM3E3sT0xQrFIcWOxaTFusXRxejF9MYKxhzGM8ZKxlXGa8aCxo7GpMawxsXG0cboxvTHC8ccxzPHRsdYx2THdceHx53Hqce6x8bH3Mfox/7ID8gmyDnITMityMTI2sjxyQjJH8k1yUDJTMlYyWTJcMl8yYjJo8mrybPJu8nDycvJ08nbyePJ68nzyfvKA8oLyhPKK8pDylXKZ8p5yorKpMqsyrTKvMrEyszK5Mr7yw3LH8sxy0nLYMvOy9bL7sv2y/7MFcwszDTMPMxEzEzMY8xrzHPMe8yDzIvMk8ybzKPMq8yzzMrM0szazS7NNs0+zVXNbM10zXzNlM2czbPNyc3gzffODs4lzjjOS85iznPOh86mzrLOxM7MzuPO9c8Bzw3PJM87z1LPac9xz3nPkc+pz7XPwc/Nz9nP5c/xz/nQAdAJ0CDQN9A/0FbQbdCF0JzQpNCs0MPQ2dDx0PnRENEo0UDRWNFv0YbRnNG00czR5NH80gTSDNIk0jvSU9Jq0nzSjdKl0rzS1NLs0wTTG9M301PTX9Nr03PTf9OL05fTo9O108fT4NPy1AvUHdQw1ELUVdRn1HfUhtSZ1KvUvtTQ1OPU9dUI1RrVKtU61UbVUtVk1XbViNWZ1bLVxNXd1e/WAtYU1ifWOdZJ1ljWatZ81ojWlNag1qzWvtbQ1uPW9dcI1xrXLdc/11LXZNd014PXj9eh163Xv9fL193X6df62AbYEtge2CrYPNhO2GDYctiE2JbYqNi62MzY3djp2PXZAdkN2R/ZMdlD2VTZztno2fTaANoM2hjaJNow2jzaSNpU2mDabNp42oTakNqc2qjatNrA2sjbLduS29DcD9xt3Mzc590C3Q7dGt0m3TLdPt1K3ZXd5N4+3pbent6q3rTevN7E3sze1N7c3uTe9t8I3x/fNt9O32bfft+W367fxt/e3/bgDuAm4D7gVuBi4G7geuCG4JLgnuCq4LbgwuDU4Obg8uD+4QrhFuEi4S7hOuFG4VjhauF24YLhjuGa4abhsuHE4dXh4eHt4fniBeIR4h3iKeI14kHiTeJZ4mXiceJ94oXijeKV4p3ipeKt4rXiveLF4s3i1eLd4uXi/eMU4yvjPeNF403jZeNt43/jleOd46XjreO148zj1OPc4+Tj7OP04/zkBOQM5JnlCuVr5XPlf+WR5aLlquW25cLlzuXa5eYAAAAFAGQAAAMoBbAAAwAGAAkADAAPAG+yDBARERI5sAwQsADQsAwQsAbQsAwQsAnQsAwQsA3QALAARViwAi8bsQIfPlmwAEVYsAAvG7EADz5ZsgQCABESObIFAgAREjmyBwIAERI5sggCABESObAK3LIMAgAREjmyDQIAERI5sAIQsA7cMDEhIREhAxEBAREBAyEBNQEhAyj9PALENv7u/roBDOQCA/7+AQL9/QWw+qQFB/19Anf7EQJ4/V4CXogCXgACAI//8gGjBbAAAwANADuyBg4PERI5sAYQsAHQALAARViwAi8bsQIfPlmwAEVYsAwvG7EMDz5ZsgYNCitYIdgb9FmwAdCwAS8wMQEjAyEBNDYyFhUUBiImAX7RFwEA/vlKgEpIhEgBrQQD+sM5S0s5N0pKAAIAZQP0AkAGAAAEAAkAJQCwAEVYsAMvG7EDIT5ZsALQsAIvsAfQsAcvsAMQsAjQsAgvMDEBAyMRMwUDIxEzARMji64BLSOLrgV3/n0CDIn+fQIMAAIAYAAABLwFsAAbAB8AjQCwAEVYsAwvG7EMHz5ZsABFWLAQLxuxEB8+WbAARViwAi8bsQIPPlmwAEVYsBovG7EaDz5Zsh0MAhESObAdL7IAAworWCHYG/RZsATQsB0QsAbQsB0QsAvQsAsvsggDCitYIdgb9FmwCxCwDtCwCxCwEtCwCBCwFNCwHRCwFtCwABCwGNCwCBCwHtAwMQEjAyMTIzUhEyM1IRMzAzMTMwMzFSMDMxUjAyMDMxMjAs/gTKhM5wEFOvMBEU6nTuFOp07Q7jrd+0ynduA64AGa/mYBmp4BOZ8BoP5gAaD+YJ/+x57+ZgI4ATkAAQBk/y0EJgabACwAfbIqLS4REjkAsABFWLAMLxuxDB8+WbAARViwCS8bsQkfPlmwAEVYsCMvG7EjDz5ZsABFWLAgLxuxIA8+WbIZDCAREjmwGRCyAgEKK1gh2Bv0WbIPCSMREjmwDBCyEwEKK1gh2Bv0WbInIwkREjmwIxCyKgEKK1gh2Bv0WTAxATQmJicmNTQ2NzUzFRYWFSM0JiMiBhUUFgQeAhUUBgcVIzUmJjUzFBYzMjYDM2z8RunKraCuvvJxYWBsawEAkmQ2z7mfxtXzf3RydwF8VW9ZJn31ptYU2twZ9cR+kWhhV2leUGeGWqnSE8PCFvDGfopuAAAFAGP/7AWJBcUADQAaACcANQA5AImyBTo7ERI5sAUQsBPQsAUQsBvQsAUQsCjQsAUQsDbQALA2L7A4L7AARViwAy8bsQMfPlmwAEVYsCUvG7ElDz5ZsAMQsArQsAovshECCitYIdgb9FmwAxCyGAIKK1gh2Bv0WbAlELAe0LAeL7AlELIrAgorWCHYG/RZsB4QsjICCitYIdgb9FkwMRM0NjMyFhUVFAYjIiY1FxQWMzI2NTU0JiIGFQE0NjMyFhUVFAYgJjUXFBYzMjY1NTQmIyIGFQUnARdjqoqMqamKh6+qTT8+TE1+SwISroeIraf+6KuqTz5ASU49Pk3+An0Cx30EmISpqYlIg6iljAZFVVVJSUVWV0f80Iampo1HgqmniQVEV1NLS0ZUVEr0SARySAADAFb/7AURBcQAHAAlADEAmLIuMjMREjmwLhCwENCwLhCwHtAAsABFWLAJLxuxCR8+WbAARViwGy8bsRsPPlmwAEVYsBgvG7EYDz5ZsiAbCRESObIoCRsREjmyAyAoERI5shAoIBESObITGwkREjmyERMYERI5shkYExESObIWERkREjmwGxCyHQEKK1gh2Bv0WbIfHREREjmwCRCyLwEKK1gh2Bv0WTAxEzQ2NyYmNTQ2MzIWFRQGBwcBNjUzEAcXIScGICQFMjcBBwYVFBYDFBc3NzY1NCYjIgZWbqJVQ9Cwn8tcaWMBGT3Tftb+5lKc/lD+/QHie2v+wh94ghlnbx8+VkJHVAGJZal0a5ZGq8e7iluZTEj+tHiT/vOs/WF15SNSAXcWW3VlfgOqVH9MGTdWOVFgAAABAFID/AELBgAABAAWALAARViwAy8bsQMhPlmwAtCwAi8wMQEDIxEzAQsan7kFg/55AgQAAQCA/jECogZfABAAELIHERIREjkAsAQvsA0vMDETNBISNxcGAgMHEBIXByYCAoB88IYwja8IAauaMIbxewJQ5wGfAUdCjmv+Sf7lVv7R/iV8h0IBSQGdAAEAKP4xAlEGXwASABCyBxMUERI5ALAEL7AOLzAxARQCAgcnNhIRNRACJyc3FhISFwJReviHMJavmI4fMIDwgAgCQN7+Y/6tQYd0Ad0BMhcBFgHJihyIPv7E/nnQAAABABsCTQN0BbAADgAgALAARViwBC8bsQQfPlmwANAZsAAvGLAJ0BmwCS8YMDEBJTcFAzMDJRcFEwcDAycBTP7PNwEuD7MPASk2/srIkbSykgPMWKl1AVj+onOsWP72agEg/ulmAAABAEQAkgQqBLYACwAaALAJL7AA0LAJELIGAQorWCHYG/RZsAPQMDEBIRUhESMRITUhETMCrgF8/oTs/oIBfuwDId7+TwGx3gGVAAEAHP64AV0A6wAJABiyCQoLERI5ALAKL7IFDQorWCHYG/RZMDETJzY2NzUzBwYGn4M6KwHbAQFp/rhOW4dGva9q1QAAAQBHAgkCVALNAAMAEQCwAi+yAQEKK1gh2Bv0WTAxASE1IQJU/fMCDQIJxAABAIf/9QGiAQAACgAisgALDBESOQCwAEVYsAYvG7EGDz5ZsgANCitYIdgb9FkwMQEyFhUUBiMiJjQ2ARRESkpEQUxKAQBNOjlLSnRNAAABAAL/gwL+BbAAAwATALAAL7AARViwAi8bsQIfPlkwMRcjATPBvwI9v30GLQAAAgBp/+wEIgXEAA0AGwBGsgMcHRESObADELAR0ACwAEVYsAovG7EKHz5ZsABFWLADLxuxAw8+WbAKELIRAQorWCHYG/RZsAMQshgBCitYIdgb9FkwMQEQAiMiAgM1EBIzMhITJzQmIyIGBxEUFjMyNjcEIuvw7O8D6/Hv6wPzcHp3cANyenVwAwJl/sb+wQE3ATH8AToBOv7O/s8Uzb+1wP62zMi5xQAAAQCoAAAC/wW1AAYAOQCwAEVYsAUvG7EFHz5ZsABFWLAALxuxAA8+WbIEAAUREjmwBC+yAwEKK1gh2Bv0WbICAwUREjkwMSEjEQU1JTMC//L+mwI4HwSRes3RAAABAFEAAARABcQAGQBOshEaGxESOQCwAEVYsBEvG7ERHz5ZsABFWLAALxuxAA8+WbIDEQAREjmwERCyCQEKK1gh2Bv0WbIWEQAREjmwABCyGAEKK1gh2Bv0WTAxISE1ATY2NTQmIyIGFSM0NjYzMhYVFAYHASEEQPwtAeVpWXVjdoLzeeGT1PV7jP6cAqSnAhF1nU9ogJB9hdV21bxt75j+gwABAE//7AQVBcQAKQBusgcqKxESOQCwAEVYsA8vG7EPHz5ZsABFWLAbLxuxGw8+WbIBDxsREjmwAS+yHwEBcbKfAQFdsj8BAXGwDxCyBwEKK1gh2Bv0WbABELIoAQorWCHYG/RZshUoARESObAbELIiAQorWCHYG/RZMDEBMzY2NTQmIyIGFSM0NjYzMhYVFAYHFhYVFAQjIiQ1MxQWMzI2NTQmIyMBhpRwg21wYn7zd9WE2vl9Y3h9/vPb0v7084FtcYKIho8DRwFybGhzcVtwuGfbw2KtLCmwesTo4LpgeHhyc3wAAAIANAAABFgFsAAKAA4ASQCwAEVYsAkvG7EJHz5ZsABFWLAELxuxBA8+WbIBCQQREjmwAS+yAgEKK1gh2Bv0WbAG0LABELAL0LIIBgsREjmyDQkEERI5MDEBMxUjESMRIScBMwEhEQcDo7W18/2LBwJ0+/2QAX0SAgfD/rwBRJQD2PxXAmAgAAABAIH/7AQ6BbAAHQBqshoeHxESOQCwAEVYsAEvG7EBHz5ZsABFWLANLxuxDQ8+WbABELIDAQorWCHYG/RZsgcBDRESObAHL7IaAQorWCHYG/RZsgUHGhESObANELIUAQorWCHYG/RZshEUGhESObIdGhQREjkwMRMTIRUhAzYzMhIVFAAjIiQnMxYWMzI2NTQmIyIGB65PAw79vChlf9Dn/wDfyP75C+sOfGRwfYp5Qlw2AtIC3tL+pDr+9uHe/vnjumpxoIqFmyMzAAACAHX/7AQ3BbcAFAAfAGKyFSAhERI5sBUQsA3QALAARViwAC8bsQAfPlmwAEVYsA0vG7ENDz5ZsAAQsgEBCitYIdgb9FmyBwANERI5sAcvsgUHDRESObIVAQorWCHYG/RZsA0QshsBCitYIdgb9FkwMQEVIwYGBzYzMhIVFAAjIgARNRAAIQMiBgcVFBYyNhAmA2EezPQXdbbB3/771Nr+8QF1AV7sUIUfiNh+gAW3yQPayHv+8Nfe/u0BQgEFUwF/AbL9SVpLSqK/ogEIpgAAAQBFAAAENgWwAAYAMgCwAEVYsAUvG7EFHz5ZsABFWLABLxuxAQ8+WbAFELIDAQorWCHYG/RZsgADBRESOTAxAQEjASE1IQQ2/br/AkX9DwPxBSn61wTtwwAAAwBo/+wEIgXEABcAIQArAHSyCSwtERI5sAkQsBrQsAkQsCTQALAARViwFS8bsRUfPlmwAEVYsAkvG7EJDz5ZsikJFRESObApL7IfKQFxshoBCitYIdgb9FmyAxopERI5sg8pGhESObAJELIfAQorWCHYG/RZsBUQsiUBCitYIdgb9FkwMQEUBgcWFhUUBCMiJDU0NjcmJjU0NjMyFgM0JiIGFRQWMjYDNCYiBhUUFjI2BAJuX3J7/vzY2f77fHBebfDMzfDTgdR/fdx7H266bG26bQQwa6cwNbh0wOHiv3W6MjCna7ra2vyvbIWEbWuAfAL9X3t1ZWR2dgAAAgBd//oEEgXEABUAIQBksgkiIxESObAJELAW0ACwAEVYsAkvG7EJHz5ZsABFWLARLxuxEQ8+WbIWEQkREjl8sBYvGLICAQorWCHYG/RZsgACCRESObARELISAQorWCHYG/RZsAkQsh0BCitYIdgb9FkwMQEGIyICNTQ2NjMyABEVEAAFIzUzNjYDMjY3NTQmIgYVFBYDHnqjwOR01o3cAQL+nP6fHSPX5txJgCOE0n1+AmGBAQ3bkOqC/rj+7UT+dv5iA8kDyQEPVEpfocSthImoAP//AIL/9QGdBFEAJgAS+wAABwAS//sDUf//AC7+uAGIBFEAJwAS/+YDUQAGABASAAABAD8ApAOEBE4ABgAXsgAHCBESOQCwAEVYsAUvG7EFGz5ZMDEBBRUBNQEVATYCTvy7A0UCd+DzAXXBAXTzAAIAkQFkA+8D1gADAAcAJQCwBy+wA9CwAy+yAAEKK1gh2Bv0WbAHELIEAQorWCHYG/RZMDEBITUhESE1IQPv/KIDXvyiA14DDMr9jskAAAEAgAClA+AETgAGABeyAAcIERI5ALAARViwAi8bsQIbPlkwMQElNQEVATUC6v2WA2D8oAJ84+/+jMH+jO8AAgA8//QDmAXEABgAIwBesgkkJRESObAJELAc0ACwAEVYsBAvG7EQHz5ZsABFWLAiLxuxIg8+WbIcDQorWCHYG/RZsADQsAAvsgQAEBESObAQELIJAQorWCHYG/RZsgwQABESObIVABAREjkwMQE0NjY3NjU0JiMiBhUjNjYzMhYVFAcHBgcDNDYzMhYVFAYiJgFeQsMaKF1aVmnzAu3DyeGYe0IC9Eo/QEpIhEcBrIWevSg9R15jYVOxzsy3o555S5D+yTtJSzk3SkoAAgBb/jsG2QWQADYAQgB8sjtDRBESObA7ELAj0ACwKi+wMy+wAEVYsAMvG7EDDz5ZsABFWLAILxuxCA8+WbIFMwgREjmyDzMIERI5sA8vsAgQsjoCCitYIdgb9FmwFdCwMxCyGwIKK1gh2Bv0WbAqELIjAgorWCHYG/RZsA8QskACCitYIdgb9FkwMQEGAiMiJwYGIyImNzYSNjMyFhcDBjMyNjcSACEiBAIHBhIEMzI2NxcGBiMiJCcmExISJDMyBBIBBhYzMjY3EyYjIgYGzQzevrU9M4dKkpcSEH/DblSBVzQThWaDBhH+wf7AxP7RsgkMiwEfz1S3QCY9z2n+/pRbXgsM3gGB9vkBZ7L8Aw1KUTZgHi0yL2+MAgb6/t+aTEzwyaMBBo8qQv3NxtuuAXEBiMT+je3x/qO2KCKJKDHXzNMBJgESAbXy2/5l/oyIjV9TAe0T0QACABIAAAVCBbAABwAKAEYAsABFWLAELxuxBB8+WbAARViwAi8bsQIPPlmwAEVYsAYvG7EGDz5ZsgkEAhESObAJL7IAAQorWCHYG/RZsgoEAhESOTAxASEDIQEzASEBIQMDw/3Mdv75AibjAif++P2cAabTAVP+rQWw+lACHwJcAAMAlAAABKMFsAAOABYAHwBtsgIgIRESObACELAR0LACELAe0ACwAEVYsAEvG7EBHz5ZsABFWLAALxuxAA8+WbIXAAEREjmwFy+yHxcBcbIPAQorWCHYG/RZsggPFxESObAAELIQAQorWCHYG/RZsAEQsh4BCitYIdgb9FkwMTMRITIEFRQGBxYWFRQEIwERITI2NTQnJTMyNjU0JiMjlAHz9wECbGh2gf759f7qARl3huj+0vh2hXuC9gWwxsRkoCwgsXzN3AKR/jl2aeMFumtibGAAAQBm/+wE6wXEAB0AQLIDHh8REjkAsABFWLAMLxuxDB8+WbAARViwAy8bsQMPPlmwDBCyEwEKK1gh2Bv0WbADELIaAQorWCHYG/RZMDEBBgAjIiQCJzU0EiQzMgAXIyYmIyIGBxUUFjMyNjcE6xb+1Pmu/veQA5IBEbPxASYY/BKTjqWxAqmjlZYUAdrp/vulATDJiM4BOqr++u+di/Hpgez4hpwAAAIAlAAABNIFsAALABUARrICFhcREjmwAhCwFdAAsABFWLABLxuxAR8+WbAARViwAC8bsQAPPlmwARCyDAEKK1gh2Bv0WbAAELINAQorWCHYG/RZMDEzESEyBBIVFRQCBCMDETMyNjc1NCYjlAGuwQErpKX+z8WmpcfVAs7EBbCs/sTMSc/+xqoE5Pvm+elR7foAAQCUAAAETAWwAAsATgCwAEVYsAYvG7EGHz5ZsABFWLAELxuxBA8+WbILBgQREjmwCy+yAAEKK1gh2Bv0WbAEELICAQorWCHYG/RZsAYQsggBCitYIdgb9FkwMQEhESEVIREhFSERIQPn/aoCu/xIA7H9TAJWAor+QMoFsMz+bgABAJQAAAQxBbAACQBAALAARViwBC8bsQQfPlmwAEVYsAIvG7ECDz5ZsgkEAhESObAJL7IAAQorWCHYG/RZsAQQsgYBCitYIdgb9FkwMQEhESMRIRUhESED2/22/QOd/WACSgJp/ZcFsMz+TwABAGr/7ATwBcQAHgBVsgsfIBESOQCwAEVYsAsvG7ELHz5ZsABFWLADLxuxAw8+WbALELIRAQorWCHYG/RZsAMQshgBCitYIdgb9FmyHgsDERI5sB4vshsBCitYIdgb9FkwMSUGBCMiJAInNRAAITIEFyMCISIGBxUUEjMyNxEhNSEE8E/+6LK3/uaZAwE8ARvzAR4d+Cr++aqxA8exwlL+1AIovWdqpgE1znIBSgFz8OIBB/XtcOz++1gBHcAAAQCUAAAFGAWwAAsATACwAEVYsAYvG7EGHz5ZsABFWLAKLxuxCh8+WbAARViwAC8bsQAPPlmwAEVYsAQvG7EEDz5ZsgkGABESObAJL7ICAQorWCHYG/RZMDEhIxEhESMRMxEhETMFGPz9df39Aov8Aof9eQWw/aICXgABAKMAAAGfBbAAAwAdALAARViwAi8bsQIfPlmwAEVYsAAvG7EADz5ZMDEhIxEzAZ/8/AWwAAABAC3/7APkBbAADwAvsgUQERESOQCwAEVYsAAvG7EAHz5ZsABFWLAFLxuxBQ8+WbIMAQorWCHYG/RZMDEBMxEUBCMiJjUzFBYzMjY1Auj8/vvW5Pj8c21meQWw/APR9ubNdHWHdwABAJQAAAUYBbAADABTALAARViwBC8bsQQfPlmwAEVYsAgvG7EIHz5ZsABFWLACLxuxAg8+WbAARViwCy8bsQsPPlmyAAQCERI5tGoAegACXbIGBAIREjm0ZQZ1BgJdMDEBBxEjETMRNwEhAQEhAjal/f2MAaoBMv3jAjz+1AJ1r/46BbD9Va0B/v17/NUAAQCUAAAEJgWwAAUAKACwAEVYsAQvG7EEHz5ZsABFWLACLxuxAg8+WbIAAQorWCHYG/RZMDElIRUhETMBkQKV/G79ysoFsAAAAQCUAAAGagWwAA4AbgCwAEVYsAAvG7EAHz5ZsABFWLACLxuxAh8+WbAARViwBC8bsQQPPlmwAEVYsAgvG7EIDz5ZsABFWLAMLxuxDA8+WbIBAAQREjm0ZQF1AQJdsgcABBESObRqB3oHAl2yCgAEERI5tGoKegoCXTAxCQIhESMREwEjARMRIxEB3AGkAaMBR/wZ/lK1/lMZ/AWw+6QEXPpQAeACgvueBGH9f/4gBbAAAAEAlAAABRcFsAAJAEyyAQoLERI5ALAARViwBS8bsQUfPlmwAEVYsAgvG7EIHz5ZsABFWLAALxuxAA8+WbAARViwAy8bsQMPPlmyAgUAERI5sgcFABESOTAxISMBESMRMwERMwUX/f13/f0Ci/sECfv3BbD78wQNAAIAZv/sBR4FxAAQAB4ARrIEHyAREjmwBBCwFNAAsABFWLAMLxuxDB8+WbAARViwBC8bsQQPPlmwDBCyFAEKK1gh2Bv0WbAEELIbAQorWCHYG/RZMDEBFAIEIyIkAic1NBIkIAQSFwc0AiMiAgcVFBIzMhI1BR6U/u2zsf7rlwGXARMBZAETlgH9t6ikuQK7pqi1ArLW/r2trQFA0VLVAUatq/6/1QXyAQL+/+tU8P76AQD2AAIAlAAABNQFsAAKABMATbIKFBUREjmwChCwDNAAsABFWLADLxuxAx8+WbAARViwAS8bsQEPPlmyCwEDERI5sAsvsgABCitYIdgb9FmwAxCyEwEKK1gh2Bv0WTAxAREjESEyBBUUBCMlITI2NTQmJyEBkf0CLfQBH/7n/f7TATCHjpB+/skCHf3jBbD+0dbuy394do0CAAIAYP8EBRoFxAAVACMARrIIJCUREjmwCBCwINAAsABFWLARLxuxER8+WbAARViwCC8bsQgPPlmwERCyGQEKK1gh2Bv0WbAIELIgAQorWCHYG/RZMDEBFAIHFwclBiMiJAInNTQSJDMyBBIXBzQmIyICBxUUEjMyEjUFGYN2+qT+yj1GsP7rlwGXAROxtAETlgH+uKijuQK5p6m1ArLP/tFZw5T1Da0BQNFS1QFGrav+v9UF9v7+/+pV7P72AQD2AAIAlAAABN4FsAAOABcAWrIFGBkREjmwBRCwENAAsABFWLAELxuxBB8+WbAARViwAi8bsQIPPlmyDwIEERI5sA8vsgEBCitYIdgb9FmyCwEPERI5sAIQsA7QsAQQshcBCitYIdgb9FkwMQEhESMRITIEFRQGBwEVIQEhMjY1NCYnIQKr/ub9AgD8ARKNfgFH/vH9wgEEgJCFhP71AjH9zwWw4taSxTX9oQ0C/IFwdYACAAABAEr/7ASKBcQAJwBjshEoKRESOQCwAEVYsAkvG7EJHz5ZsABFWLAdLxuxHQ8+WbICHQkREjmyDgkdERI5sAkQshEBCitYIdgb9FmwAhCyFwEKK1gh2Bv0WbIiHQkREjmwHRCyJQEKK1gh2Bv0WTAxATQmJCcmNTQkMzIWFhUjNCYjIgYVFBYEFhYVFAQjIiQmNTMUFjMyNgONh/6gaMcBH+WY7oj8j4V8iZQBVM5g/unvnv73k/2kmYSFAXdgaGpBfcmw5HDPfnKBal9Qa2WBp3C213XOiXyIawAAAQAtAAAEsAWwAAcALgCwAEVYsAYvG7EGHz5ZsABFWLACLxuxAg8+WbAGELIAAQorWCHYG/RZsATQMDEBIREjESE1IQSw/jr7/j4EgwTk+xwE5MwAAQB9/+wEvQWwABAAPLIEERIREjkAsABFWLAJLxuxCR8+WbAARViwEC8bsRAfPlmwAEVYsAQvG7EEDz5Zsg0BCitYIdgb9FkwMQERFAAjIgA1ETMRFBYzIBERBL3+1/f6/tr8lJABJAWw/DPo/vEBC+0DzPwykpoBNAPGAAEAEgAABR0FsAAGADiyAAcIERI5ALAARViwAS8bsQEfPlmwAEVYsAUvG7EFHz5ZsABFWLADLxuxAw8+WbIAAQMREjkwMQEBIQEjASEClQFyARb99PX99gEVAT0Ec/pQBbAAAQAwAAAG5QWwAAwAYLIFDQ4REjkAsABFWLABLxuxAR8+WbAARViwCC8bsQgfPlmwAEVYsAsvG7ELHz5ZsABFWLADLxuxAw8+WbAARViwBi8bsQYPPlmyAAEDERI5sgUBAxESObIKAQMREjkwMQETMwEjAQEjATMTATMFCuD7/rDy/uv+5fP+sPviARbUAWgESPpQBCf72QWw+7oERgABACkAAATpBbAACwBTALAARViwAS8bsQEfPlmwAEVYsAovG7EKHz5ZsABFWLAELxuxBA8+WbAARViwBy8bsQcPPlmyAAEEERI5sgYBBBESObIDAAYREjmyCQYAERI5MDEBASEBASEBASEBASECiQEyAST+SAHC/tn+x/7G/toBw/5HASQDogIO/S79IgIW/eoC3gLSAAABAAcAAATWBbAACAAxALAARViwAS8bsQEfPlmwAEVYsAcvG7EHHz5ZsABFWLAELxuxBA8+WbIAAQQREjkwMQEBIQERIxEBIQJvAU8BGP4Y/v4XARkC/gKy/Gj96AIYA5gAAAEAUAAABIwFsAAJAEQAsABFWLAHLxuxBx8+WbAARViwAi8bsQIPPlmyAAEKK1gh2Bv0WbIEAAIREjmwBxCyBQEKK1gh2Bv0WbIJBQcREjkwMSUhFSE1ASE1IRUBggMK+8QC8f0UBB/KyqQEQMygAAABAIT+vAIcBo4ABwAiALAEL7AHL7IAAQorWCHYG/RZsAQQsgMBCitYIdgb9FkwMQEjETMVIREhAhylpf5oAZgF0PmpvQfSAAABABT/gwNkBbAAAwATALACL7AARViwAC8bsQAfPlkwMRMzASMU8AJg8AWw+dMAAQAM/rwBpgaOAAcAJQCwAi+wAS+wAhCyBQEKK1gh2Bv0WbABELIGAQorWCHYG/RZMDETIREhNTMRIwwBmv5mp6cGjvguvQZXAAABADUC2QM1BbAABgAnsgAHCBESOQCwAEVYsAMvG7EDHz5ZsADQsgEHAxESObABL7AF0DAxAQMjATMBIwG1ss4BK6sBKs0Epv4zAtf9KQABAAP/QQOYAAAAAwAbALAARViwAy8bsQMPPlmyAAEKK1gh2Bv0WTAxBSE1IQOY/GsDlb+/AAABADEE0QIJBgAAAwAkALABL7IPAQFdsAPQsAMvtA8DHwMCXbIAAQMREjkZsAAvGDAxASMBIQIJyv7yARUE0QEvAAACAFr/7AP7BE4AHgApAIWyFyorERI5sBcQsCDQALAARViwFy8bsRcbPlmwAEVYsAQvG7EEDz5ZsABFWLAALxuxAA8+WbICFwQREjmyCxcEERI5sAsvsBcQsg8BCitYIdgb9FmyEgsPERI5QAkMEhwSLBI8EgRdsAQQsh8BCitYIdgb9FmwCxCyIwcKK1gh2Bv0WTAxISYnBiMiJjU0JDMzNTQmIyIGFSM0NjYzMhYXERQXFSUyNjc1IyIGFRQWAwMQDHSoo84BAe+VXmBTavN2y32+4gMp/f1IfyCDh4hdH0Z5uomtuUdUZVNAWZtYv63+GJJXEa9GO8xeVkZTAAIAfP/sBDIGAAAPABsAZLITHB0REjmwExCwDNAAsAkvsABFWLAMLxuxDBs+WbAARViwAy8bsQMPPlmwAEVYsAYvG7EGDz5ZsgUMAxESObIKDAMREjmwDBCyEwEKK1gh2Bv0WbADELIYAQorWCHYG/RZMDEBFAIjIicHIxEzETYzMhIRJzQmIyIHERYzMjY3BDLhxb5qDNzzabLG4vN8dp5AQZ9yfAICEvz+1ol1BgD90nz+2v74B7Cwiv5CjaqsAAEAT//sA/UETgAcAEuyAB0eERI5ALAARViwDy8bsQ8bPlmwAEVYsAgvG7EIDz5ZsgABCitYIdgb9FmyAwgPERI5shMPCBESObAPELIWAQorWCHYG/RZMDElMjY3Mw4CIyIAETU0ADMyFhcjJiYjIgYHFRQWAjlbeATlBHbKdeP+9gEI5MHzBuUEd1x2gAF/rmpOZa9mASYBAxn3ASnht114q64nsK0AAAIAT//sBAMGAAAOABkAZLIXGhsREjmwFxCwA9AAsAYvsABFWLADLxuxAxs+WbAARViwDC8bsQwPPlmwAEVYsAgvG7EIDz5ZsgUDDBESObIKAwwREjmwDBCyEgEKK1gh2Bv0WbADELIXAQorWCHYG/RZMDETNBIzMhcRMxEjJwYjIgI3FBYzMjcRJiMiBk/ow6xq89wMbba+6/N/dZVFQ5V2gAIl+gEveAIq+gBwhAEy8qW5hQHOgrsAAAIAU//sBAsETgAVAB0Ag7IWHh8REjmwFhCwCNAAsABFWLAILxuxCBs+WbAARViwAC8bsQAPPlmyGgAIERI5sBovtL8azxoCXbRfGm8aAnG0HxovGgJxtO8a/xoCcbKMGgFdsgwHCitYIdgb9FmwABCyEAEKK1gh2Bv0WbISCAAREjmwCBCyFgEKK1gh2Bv0WTAxBSIANTU0NjYzMhIRFSEWFjMyNxcGBgMiBgchNSYmAlnn/uF94ovd8f09C513p2mDQdmkZHsRAc8IchQBI/Ieov+O/ub+/mKGnId9YWsDn4x9Enp9AAABAC0AAALWBhUAFABTsgcVFhESOQCwAEVYsAgvG7EIIT5ZsABFWLAELxuxBBs+WbAARViwAC8bsQAPPlmwBBCwENCyEwEKK1gh2Bv0WbAB0LAIELINAQorWCHYG/RZMDEzESM1MzU0NjMyFwcmIyIVFTMVIxHSpaXItEBIBig1rtzcA4a0Y7TEEr4Is2C0/HoAAAIAUv5WBAwETgAZACQAg7IiJSYREjmwIhCwC9AAsABFWLADLxuxAxs+WbAARViwBi8bsQYbPlmwAEVYsAsvG7ELET5ZsABFWLAXLxuxFw8+WbIFAxcREjmwCxCyEQEKK1gh2Bv0WbIPERcREjmyFQMXERI5sBcQsh0BCitYIdgb9FmwAxCyIgEKK1gh2Bv0WTAxEzQSMzIXNzMRFAQjIiYnNxYzMjY1NQYjIgI3FBYzMjcRJiMiBlLtxLlqC9v+9+F34ztzcKR5jGmvvvHyhXaTR0WTeIUCJfwBLYFt++fV9mNQkoWDf0l1AS72o7t+Adx7vgABAHkAAAP4BgAAEABCsgoREhESOQCwEC+wAEVYsAIvG7ECGz5ZsABFWLANLxuxDQ8+WbAARViwBi8bsQYPPlmwAhCyCgEKK1gh2Bv0WTAxATYzIBMRIxE0JiMiBxEjETMBbHe2AVoF82Fekkjz8wPEiv51/T0CunBdgvz7BgAAAAIAfQAAAZAF1QADAA0APrIGDg8REjmwBhCwAdAAsABFWLACLxuxAhs+WbAARViwAS8bsQEPPlmwAhCwDNCwDC+yBg0KK1gh2Bv0WTAxISMRMwE0NjIWFRQGIiYBf/Pz/v5HhEhIhEcEOgEZOEpKODdJSQAAAv+1/ksBhQXVAAwAFgBJsgMXGBESObADELAQ0ACwAEVYsAwvG7EMGz5ZsABFWLAELxuxBBE+WbIJAQorWCHYG/RZsAwQsBXQsBUvsg8NCitYIdgb9FkwMQERFAYjIic1FjMyNxEDNDYyFhUUBiImAXqln0M+JjB5AxVHhEhIhEcEOvtmpq8RwAmEBKMBGThKSjg3SUkAAQB9AAAENgYAAAwAUwCwAEVYsAQvG7EEIT5ZsABFWLAILxuxCBs+WbAARViwAi8bsQIPPlmwAEVYsAsvG7ELDz5ZsgAIAhESObRqAHoAAl2yBggCERI5tGUGdQYCXTAxAQcRIxEzETcBIQEBIQHcbPPzTAErAST+bgG9/ucB0G/+nwYA/IpfAVH+Pf2JAAEAjAAAAX8GAAADAB0AsABFWLACLxuxAiE+WbAARViwAC8bsQAPPlkwMSEjETMBf/PzBgAAAAEAfAAABnkETgAdAHeyBB4fERI5ALAARViwAy8bsQMbPlmwAEVYsAcvG7EHGz5ZsABFWLAALxuxABs+WbAARViwGy8bsRsPPlmwAEVYsBUvG7EVDz5ZsABFWLAMLxuxDA8+WbIBAxsREjmyBQcVERI5sAcQshABCitYIdgb9FmwGNAwMQEXNjMyFzYzMhYXESMRNCYjIgYHEyMRJiMiBxEjEQFhB3LG2VB21rOvAvNaaFNpFQHzBb6SPfMEOnGFpqbGwf05AsBnYFlI/RoCyL93/PAEOgABAHkAAAP4BE4AEABTsgsREhESOQCwAEVYsAMvG7EDGz5ZsABFWLAALxuxABs+WbAARViwDi8bsQ4PPlmwAEVYsAcvG7EHDz5ZsgEOAxESObADELILAQorWCHYG/RZMDEBFzYzIBMRIxE0JiMiBxEjEQFeB3jDAVIG81llk0jzBDp9kf59/TUCvWdjhfz+BDoAAAIAT//sBD0ETgAPABoAQ7IMGxwREjmwDBCwGNAAsABFWLAELxuxBBs+WbAARViwDC8bsQwPPlmyEgEKK1gh2Bv0WbAEELIYAQorWCHYG/RZMDETNDY2MzIAFxcUBgYjIgA1FxQWMjY1NCYjIgZPfuSU2wERCwF75Zbl/u3zivaJjXl3jAInn/+J/ubpOaD8igEx/gmnvcC5pMC9AAIAfP5gBDAETgAPABoAbrITGxwREjmwExCwDNAAsABFWLAMLxuxDBs+WbAARViwCS8bsQkbPlmwAEVYsAYvG7EGET5ZsABFWLADLxuxAw8+WbIFDAMREjmyCgwDERI5sAwQshMBCitYIdgb9FmwAxCyGAEKK1gh2Bv0WTAxARQCIyInESMRMxc2MzISESc0JiMiBxEWMzI2BDDkwLJr8+AKa7jG4fKBeJVBQpZ0gwIS+/7Vdf3/Bdpugv7Z/voGor57/iB+uwAAAgBP/mAEAgROAA4AGQBrshcaGxESObAXELAD0ACwAEVYsAMvG7EDGz5ZsABFWLAGLxuxBhs+WbAARViwCC8bsQgRPlmwAEVYsAwvG7EMDz5ZsgUDDBESObIKAwwREjmyEgEKK1gh2Bv0WbADELIXAQorWCHYG/RZMDETNBIzMhc3MxEjEQYjIgI3FBYzMjcRJiMiBk/oxrVqDtjzaqrC6vODdJBGRo50hQIm/gEqf2v6JgH8cAEv9qa9ewHsdroAAQB8AAACtAROAA0ARrIJDg8REjkAsABFWLAILxuxCBs+WbAARViwCy8bsQsbPlmwAEVYsAUvG7EFDz5ZsAsQsgIBCitYIdgb9FmyCQsFERI5MDEBJiMiBxEjETMXNjMyFwKzMDOnOvPoBlicNCIDXAiA/RwEOnmNDgABAEv/7APKBE4AJgBpsgknKBESOQCwAEVYsAkvG7EJGz5ZsABFWLAcLxuxHA8+WbICHAkREjmwAhCwFtCwCRCyEAEKK1gh2Bv0WbINFhAREjm0DA0cDQJdsBwQsiQBCitYIdgb9FmyISQCERI5tAMhEyECXTAxATQmJicmNTQ2MzIWFSM0JiMiBhUUFgQWFhUUBiMiJiY1MxYWMzI2Attr+FO27LbC7/NoVlBlXgEeo0/yxIXQdOwFeGNgZAEmQUQ0KFinjLzAmUZdSj44Pj9XeleStWCoYVZdSQAAAQAI/+wCcgVBABQAUrIAFRYREjkAsABFWLATLxuxExs+WbAARViwDS8bsQ0PPlmwExCwAdCwANCwAC+wARCyBAEKK1gh2Bv0WbANELIIAQorWCHYG/RZsAQQsBDQMDEBETMVIxEUFjMyNxUGIyARESM1MxEBrb+/MT8qK1NN/uiysgVB/vm0/aQ+Nwq8FwE1AmW0AQcAAQB3/+wD9wQ6ABAAU7IKERIREjkAsABFWLAHLxuxBxs+WbAARViwDS8bsQ0bPlmwAEVYsAIvG7ECDz5ZsABFWLAPLxuxDw8+WbIAAg0REjmwAhCyCgEKK1gh2Bv0WTAxJQYjIiY1ETMRFDMyNxEzESMDDGvFsLXzq7E+8+Vqfs7DAr39Rs5/Awn7xgABABYAAAPaBDoABgA4sgAHCBESOQCwAEVYsAEvG7EBGz5ZsABFWLAFLxuxBRs+WbAARViwAy8bsQMPPlmyAAUDERI5MDEBEzMBIwEzAfrl+/6J0/6G/AE0Awb7xgQ6AAABACEAAAXMBDoADABgsgUNDhESOQCwAEVYsAEvG7EBGz5ZsABFWLAILxuxCBs+WbAARViwCy8bsQsbPlmwAEVYsAMvG7EDDz5ZsABFWLAGLxuxBg8+WbIACwMREjmyBQsDERI5sgoLAxESOTAxARMzASMDAyMBMxMTMwQzrO3+2cjo5Mj+2O2v3rcBTwLr+8YC5/0ZBDr9HQLjAAABAB8AAAPoBDoACwBTALAARViwAS8bsQEbPlmwAEVYsAovG7EKGz5ZsABFWLAELxuxBA8+WbAARViwBy8bsQcPPlmyAAoEERI5sgYKBBESObIDAAYREjmyCQYAERI5MDEBEyEBASEDAyEBASECAc4BDv61AVb+9NjX/vIBVv62AQwC1gFk/ev92wFy/o4CJQIVAAEADP5LA9YEOgAPAD+yABARERI5ALAARViwDy8bsQ8bPlmwAEVYsAUvG7EFET5ZsgAFDxESObAPELAB0LAFELIJAQorWCHYG/RZMDEBEyEBAiMiJzUXMjY3NwEhAffcAQP+UmPtNUAuXF0bI/6EAQYBXALe+yL+7xK8A0NPXQQ1AAABAFIAAAPABDoACQBEALAARViwBy8bsQcbPlmwAEVYsAIvG7ECDz5ZsgABCitYIdgb9FmyBAACERI5sAcQsgUBCitYIdgb9FmyCQUHERI5MDElIRUhNQEhNSEVAYACQPySAiX95QNPwsKfAtfEmgAAAQA4/pgCkQY9ABcANrISGBkREjkAsAwvsABFWLAALxuxABc+WbIGAAwREjmwBi+yBQcKK1gh2Bv0WbISBQYREjkwMQEkAzU0IzUyNTU2NjcXBgcVFAcWFRUWFwJh/p8HwcEDtbAwrQatrQat/phjAWDV4bLi1LTeMow4+tjhW1zj1fo4AAABAK7+8gFVBbAAAwATALAAL7AARViwAi8bsQIfPlkwMQEjETMBVaen/vIGvgAAAQAb/pgCdQY9ABgANrIFGRoREjkAsAsvsABFWLAYLxuxGBc+WbIRGAsREjmwES+yEgcKK1gh2Bv0WbIFEhEREjkwMRc2NzU0NyY1NSYnNxYWFRUUMxUiFRUUBgcbsAS2tgSwMLaywsKztds5/9DnVlbqz/85jDPlucjhsuHFu+UzAAEAdQGDBNwDLwAXAD+yERgZERI5ALAPL7IDGA8REjmwAy+wDxCyCAEKK1gh2Bv0WbADELAL0LADELIUAQorWCHYG/RZsA8QsBfQMDEBFAYjIi4CIyIGFSM0NjMyHgIzMjY1BNy+jkp9mkMmQ03BtpRKhZFDJ0NUAxKw3ziJIWhUq9s7hCJwVAACAIb+lAGZBE0AAwAPAD6yBxARERI5sAcQsADQALAARViwDS8bsQ0bPlmwAEVYsAMvG7EDFz5ZsA0QsgcNCitYIdgb9FmwANCwAC8wMRMzEyEBFAYjIiY1NDYzMhaq0Rj+/wEHSEFCSEhCQUgClvv+BTc4S0s4N0tLAAEAZP8LBAoFJgAgAF2yGyEiERI5ALAARViwES8bsREbPlmwAEVYsAovG7EKDz5ZsgABCitYIdgb9FmyAwoRERI5sAoQsAfQsAcvsBEQsBTQsBQvshgRChESObARELIbAQorWCHYG/RZMDElMjY3MwYGBxUjNSYCNTU0Ejc1MxUWFhcjJiYjIgMHFBYCT1l4BuQExZLIt8zMt8ieuQTkB3Zb5hABf65oUIjNHOrqIgEf3BzVASAi4eAc2Jxgdf7ISLCtAAABAF4AAAR8BcMAHwBlshogIRESOQCwAEVYsBIvG7ESHz5ZsABFWLAFLxuxBQ8+WbIEAQorWCHYG/RZsAjQsh4FEhESObAeL7IfAQorWCHYG/RZsAzQsB4QsA/QshYFEhESObASELIZAQorWCHYG/RZMDEBFxQHIQchNTM2NjUnIzUzJzQ2IBYVIzQmIyIGFRchFQH9B0ACuAH751InKwehmwj6AZbo9WleWWcJATcCVrCHVcrKCW9bucfyyurauF9pgmjyxwACAF3/5QVPBPEAGwAoAD+yAikqERI5sAIQsB/QALAARViwAi8bsQIPPlmwENCwEC+wAhCyIAcKK1gh2Bv0WbAQELImBworWCHYG/RZMDElBiMiJwcnNyY1NDcnNxc2MzIXNxcHFhUUBxcHARQWFjI2NjQmJiIGBgQ9n8vKnoGNh2RtkI2Om8DCm5GOlGtii478eG6+3L5tbb3evm1rf36EkImcxcilk5CRc3WUkZefysGcjZECe3jOdXbO7sx1dcwAAAEAGQAABMAFsAAWAHIAsABFWLAWLxuxFh8+WbAARViwDC8bsQwPPlmyAAwWERI5sBYQsAHQsg8MFhESObAPL7AT0LATL7QPEx8TAl2wBNCwBC+wExCyEgQKK1gh2Bv0WbAG0LAPELAH0LAHL7APELIOBAorWCHYG/RZsArQMDEBASEBIRUhFSEVIREjESE1ITUhNSEBIQJtATsBGP53AQ3+owFd/qP8/p4BYv6eARn+dwEZAzQCfP02mIqX/tMBLZeKmALKAAIAiP7yAW0FsAADAAcAGACwAC+wAEVYsAYvG7EGHz5ZsgUBAyswMRMRMxERIxEziOXl5f7yAxv85QPIAvYAAgBa/iYEjAXEAC8APQCCsiA+PxESObAgELAw0ACwBy+wAEVYsCAvG7EgHz5ZsjkgBxESObA5ELITAQorWCHYG/RZsgI5ExESObAHELIOAQorWCHYG/RZsgsOExESObIyIAcREjmwMhCyLAEKK1gh2Bv0WbIaMiwREjmwIBCyJwEKK1gh2Bv0WbIkLCcREjkwMQEUBxYVFAQjIiQ1NxQWMzI2NTQmJy4CNTQ3JiY1NCQzMgQVIzQmIyIGFRQWBBYWJSYnBhUUFh8CNjU0JgSMq4f+8ur2/uDynIh5jYa7vL5dqUFEARPm8AEM85F4e4t4AYPCWv3NUUxsY5WzLnOIAce4WWS5rcbZzwFueF9PTVs3M26abbhaMohkqszhzGqAX1JUV2hxmW4VHCh8UVYvNRAvdVFhAAIAXQTfAyMFzAAIABEAIgCwBy+yDwcBXbICBQorWCHYG/RZsAvQsAcQsBDQsBAvMDETNDYyFhQGIiYlNDYyFhQGIiZdQ3ZERHZDAchEdkREdkQFVjJERGRERDEyRERkREQAAwBX/+wF4gXEABoAKAA2AI6yHzc4ERI5sB8QsAnQsB8QsDPQALAARViwMy8bsTMPPlmwLdCwLS+yAjMtERI5sAIvtA8CHwICXbIJLTMREjmwCS+0AAkQCQJdsg0JAhESObIQAgorWCHYG/RZsAIQshcCCitYIdgb9FmyGgIJERI5sC0Qsh8ICitYIdgb9FmwMxCyJQgKK1gh2Bv0WTAxARQGICY1NTQ2MzIWFSM0JiMiBhUVFBYzMjY1JTQCJCMiBAIQEgQgJBIlNBIkIAQSEAIEIyIkAgRer/7Avb+eo62cXFhcZ2hbWVoBppb+7qOf/u+cmwERAUABE5j677sBSwGAAUq7u/64wsH+t7wCVJii1bRxrtWllWBTiHZ1doZRYoWmAR2rpP7g/qz+4KeqASCnygFax8f+pv5s/qbJyAFaAAIAjQKzAxEFxAAaACQAj7INJSYREjmwDRCwHNAAsABFWLAULxuxFB8+WbIDJRQREjmwAy+wANCwAC+yAQMUERI5sgoDFBESObAKL7AUELINAgorWCHYG/RZshAKDRESObLMEAFdQBMMEBwQLBA8EEwQXBBsEHwQjBAJXbK6EAFxsAMQshsCCitYIdgb9FmwChCyHwIKK1gh2Bv0WTAxAScGIyImNTQ2MzM1NCMiBhUnNDYzMhYVERQXJTI2NzUjBgYVFAJgEU18doOorWZ0QUmtr4iJmhr+oChUG2pMVgLBRFJ7aW55M38zMA5ogZGE/sRhUYIkGYkBPDFY//8AVwCKA4UDqQAmAXrrAAAHAXoBUgAAAAEAfwF2A8IDJQAFABoAsAQvsAHQsAEvsAQQsgIBCitYIdgb9FkwMQEjESE1IQPCyP2FA0MBdgEEqwAEAFf/7AXiBcQADQAbADEAOgCdsgo7PBESObAKELAS0LAKELAx0LAKELAz0ACwAEVYsAMvG7EDHz5ZsABFWLAKLxuxCg8+WbADELISCAorWCHYG/RZsAoQshgICitYIdgb9FmyHQoDERI5sB0vsh8DChESObAfL7QAHxAfAl2yMh0fERI5sDIvshwICitYIdgb9FmyJRwyERI5sB0QsCzQsB8QsjoICitYIdgb9FkwMRM0EiQgBBIQAgQjIiQCJTQCJCMiBAIQEgQgJBIlESMRITIWFRQHFhYUFhcVIyY1NCYjJzMyNjU0JicjV7sBSwGAAUq7u/64wsH+t7wFEZb+7qOf/u+cmwERAUABE5j9JZcBGZmseEE0BwqbDUJNno9FXUddjQLZygFax8f+pv5s/qbJyAFay6YBHauk/uD+rP7gp6oBIFv+rwNSh311Px1vo0QXECKgTEOGPjZGOwEAAQCHBRIDXgWwAAMAEQCwAS+yAgMKK1gh2Bv0WTAxASE1IQNe/SkC1wUSngACAH8DrwKLBcQACQATADmyABQVERI5sArQALAARViwAC8bsQAfPlmwCtCwCi+yBQIKK1gh2Bv0WbAAELIQAgorWCHYG/RZMDEBMhYUBiMiJjQ2EzI2NTQmIgYUFgGHapqYbG2bnWs1RUVqSEkFxJ7cm5vcnv54RzU0TExoSAACAF8AAQPzBPwACwAPAEYAsAkvsABFWLANLxuxDQ8+WbAJELAA0LAJELIGAQorWCHYG/RZsAPQsA0Qsg4BCitYIdgb9FmyBQ4GERI5tAsFGwUCXTAxASEVIREjESE1IREzASE1IQKcAVf+qdj+mwFl2AEy/K8DUQODx/58AYTHAXn7BcQAAAEAPAKbArIFuwAXAFmyCBgZERI5ALAARViwDy8bsQ8fPlmwAEVYsAAvG7EAEz5ZshYCCitYIdgb9FmyAgAWERI5sgMPABESObAPELIIAgorWCHYG/RZsgwPABESObITDwAREjkwMQEhNQE2NTQmIyIGFSM0NjMyFhUUDwIhArL9nAEdcTY0OkK6qYePnGpijAFzApt9AQVnQyo1QjZ0mYBza2ZXcQABADcCjwKpBboAJAB9sh4lJhESOQCwAEVYsA0vG7ENHz5ZsABFWLAXLxuxFxM+WbIBFw0REjl8sAEvGLZAAVABYAEDcbKQAQFdsA0QsgYCCitYIdgb9FmyCQENERI5sAEQsiMCCitYIdgb9FmyEiMBERI5shsXDRESObAXELIeAgorWCHYG/RZMDEBMzI1NCYjIgYVIzQ2MzIWFRQHFhUUBiMiJjUzFBYzMjY1NCcjAQxRhDY+MEG6pYKPo4eVsY+Hq7pFPD89hlwEbGEjNScjY3x5aXczKY5qfn9xJjU3KmUBAAABAHAE0QJIBgAAAwAjALACL7IPAgFdsADQsAAvtA8AHwACXbACELAD0BmwAy8YMDEBIQEjATMBFf7rwwYA/tEAAQCS/mAEHwQ6ABIAYLINExQREjkAsABFWLAALxuxABs+WbAARViwBy8bsQcbPlmwAEVYsBAvG7EQET5ZsABFWLANLxuxDQ8+WbAARViwCi8bsQoPPlmwDRCyBAEKK1gh2Bv0WbILDQcREjkwMQERFhYzMjcRMxEjJwYjIicRIxEBhAJZaqg7898HXJN5TfIEOv2EjYJ5AxL7xlZrN/4+BdoAAQBFAAADVgWwAAoAK7ICCwwREjkAsABFWLAILxuxCB8+WbAARViwAC8bsQAPPlmyAQAIERI5MDEhESMiJDU0JDMhEQKEUOb+9wEK5gEhAgj+1tX/+lAAAAEAjgJFAakDUgAKABayCAsMERI5ALACL7EICitY2BvcWTAxEzQ2MhYVFAYjIiaOSoZLTkBBTALKOk5OOjtKSgABAG3+QQHJAAMADgA0sgkPEBESOQCwBi+wAEVYsA4vG7EODz5ZsAYQsQcKK1jYG9xZsg0HDhESObIBDQ4REjkwMSUHFhUUBiMnMjY1NCYnNwE+C5asmwdCR0dQIAM2G5JpdokvKi0jBYsAAQCAAqACAgWzAAYAObIBBwgREjkAsABFWLAFLxuxBR8+WbAARViwAC8bsQATPlmyBAUAERI5sAQQsgMCCitYIdgb9FkwMQEjEQc1JTMCArnJAW8TAqACOjCSdwACAHcCsgMsBcQADAAaAECyCRscERI5sAkQsBDQALAARViwAi8bsQIfPlmyCRsCERI5sAkvshACCitYIdgb9FmwAhCyFwIKK1gh2Bv0WTAxEzQ2IBYVFRQGIyImNRcUFjMyNjc1NCYjIgYVd78BNsC8nZ6+r11QTlsBXU9OXQRhoMPCpkifw8SjBWJubGFQYW5tZgD//wBdAIoDmQOpACYBewkAAAcBewF+AAD//wBZAAAFgwWrACcB1f/ZApgAJwF8ARsACAEHAdgCxQAAABAAsABFWLAFLxuxBR8+WTAx//8AUAAABcwFrgAnAXwA8AAIACcB1f/QApsBBwHWAxoAAAAQALAARViwCS8bsQkfPlkwMf//AGcAAAX8BbsAJwF8AagACAAnAdgDPgAAAQcB1wAwApsAEACwAEVYsCAvG7EgHz5ZMDEAAgBC/n8DpQROABkAIwBhshAkJRESObAQELAd0ACwAEVYsCEvG7EhGz5ZsABFWLAQLxuxEBc+WbAhELIdDQorWCHYG/RZsADQsAAvsgMAEBESObAQELIJAQorWCHYG/RZsgwQABESObIWEAAREjkwMQEGBgcHBhUUFjMyNjUzBgYjIiY1NDc3Njc3ExQGIiY1NDYyFgJ2AjVJZ1piWVhq8wLvws7im1xOCgL3R4RISIRHApV8kU9qYWpeXWRTsdDJuKWjXUhzNQE3OEtLODdLSwAAAv/2AAAHVwWwAA8AEgB3ALAARViwBi8bsQYfPlmwAEVYsAAvG7EADz5ZsABFWLAELxuxBA8+WbIRBgAREjmwES+yAgEKK1gh2Bv0WbAGELIIAQorWCHYG/RZsgsGABESObALL7IMAQorWCHYG/RZsAAQsg4BCitYIdgb9FmyEgYAERI5MDEhIQMhAyEBIRUhEyEVIRMhASEDB1f8fg/+Crj+3gNDA+D9ehECJP3kFAKX+u0BeRsBVP6sBbDF/mjF/jYBZwKIAAABAE0A1gPsBIYACwA4ALADL7IJDAMREjmwCS+yCgkDERI5sgQDCRESObIBCgQREjmwAxCwBdCyBwQKERI5sAkQsAvQMDETAQE3AQEXAQEHAQFNATz+xJQBOwE8lP7EATyU/sT+xQFsAUIBQpb+vgFClv6+/r6WAUH+vwAAAwBp/6EFIgXuABcAIAApAGayECorERI5sBAQsB3QsBAQsCbQALAARViwEC8bsRAfPlmwAEVYsAQvG7EEDz5ZshoQBBESObIjEAQREjmwIxCwG9CwEBCyHQEKK1gh2Bv0WbAaELAk0LAEELImAQorWCHYG/RZMDEBFAIEIyInByM3JhE1NBIkMzIXNzMHFhMFFBcBJiMiAgcFNCcBFjMyEjUFIpT+7bSkhFupkcOWARSyxY9Xp5OdAfxERwH2V4ekuQICvyz+F05pqbUCstb+va1Llu7DAWdD1QFEr2WP88H+w0vPgAM6Vf7/6wimcvzcNgEA9gAAAgCUAAAEfgWwAAwAFABXsgIVFhESObACELAP0ACwAEVYsAAvG7EAHz5ZsABFWLAKLxuxCg8+WbIBCgAREjmwAS+yDgoAERI5sA4vsgkBCitYIdgb9FmwARCyDQEKK1gh2Bv0WTAxAREzMgQVFAQjIxEjERMRMzI2NCYnAYfx9AES/u7z8vPz9n2RjHoFsP7o7sjH7/7UBbD+Jf4agt6EAgAAAQCI/+wEmwYVACwAW7IjLS4REjkAsABFWLAFLxuxBSE+WbAARViwFS8bsRUPPlmwAEVYsAAvG7EADz5Zsg4FFRESObAVELIcAQorWCHYG/RZsiIVBRESObAFELIqAQorWCHYG/RZMDEhIxE0NjMyFhUUDgIVFB4CFRQGIyImJzcWFjMyNjU0LgI1NDY1NCYjIgcBevLlzrvXG0UWQbJR2cZQqyYxLX82YVpGrlF+XFC4BARR1u67qT5icUEnLFSUiUuruScZwxwlVkMxW4iIUFjJTVFh9wAAAwBI/+wGhARQACkANAA8AMqyAj0+ERI5sAIQsC3QsAIQsDjQALAARViwFy8bsRcbPlmwAEVYsAUvG7EFDz5ZsADQsAAvsgwFFxESObAML7KPDAFdsBcQshABCitYIdgb9FmwFxCwG9CwGy+yOAAbERI5sDgvtB84LzgCcbTvOP84AnG0XzhvOAJxtL84zzgCXbKMOAFdsiAHCitYIdgb9FmwABCyIwEKK1gh2Bv0WbAFELIqAQorWCHYG/RZsAwQsi8HCitYIdgb9FmwGxCyNQEKK1gh2Bv0WTAxBSInBgYjIiY1NDYzMzU0JiMiBhUnNDYzMhc2FzISFRUhFhYzMjc3FwYGJTI2NzUjBgYVFBYBIgYHITU0JgTm/YxB1oawyO7pv19YW3Py/cXfb4PI1O79SQmYholrPUlG0fyYOogtxGh4XQMrY38QAcRtFKFNVLCcnqxHW2dZQhOSuYWHAv7964mLnjoipjhAuDsr0QJfRkFPAueKfx5xegACAGf/7ARABiwAHQArAGWyBywtERI5sAcQsCjQALAARViwGS8bsRkhPlmwAEVYsAcvG7EHDz5Zsg8HGRESObAPL7IRDwcREjmwGRCyGAEKK1gh2Bv0WbAPELIiAQorWCHYG/RZsAcQsigBCitYIdgb9FkwMQESERUUAgYjIiYmNTQ2NjMyFyYnByc3Jic3Fhc3FwMnJiYjIgYVFBYzMjY1A0L+fuWMiuJ+cc6EknExfsxOrH6iS+6xtE6PASB7Tn6LjW5viQUX/vf+b1Km/vmSfuKIled9W6l6h21yUirDMod4bf0ZEjA4qJV+qMitAAADAEMAkwQ3BMwAAwANABkAUrIEGhsREjmwBBCwANCwBBCwEdAAsAMvsgABCitYIdgb9FmwAxCxCQorWNgb3FmyBA0KK1gh2Bv0WbAAELERCitY2BvcWbIXDQorWCHYG/RZMDEBITUhATIWFAYjIiY0NgM0NjMyFhUUBiMiJgQ3/AwD9P4JREpKRENKSkpKQ0RKSkRDSgJG1AGyTHJLS3JM/Eo6TEw6OUpKAAMAT/93BD0EuwAVAB0AJQBmsgQmJxESObAEELAb0LAEELAj0ACwAEVYsAQvG7EEGz5ZsABFWLAPLxuxDw8+WbIYBA8REjmyIAQPERI5sCAQsBnQsAQQshsBCitYIdgb9FmwGBCwIdCwDxCyIwEKK1gh2Bv0WTAxEzQ2NjMyFzczBxYRFAYGIyInByM3JhMUFwEmIyIGBTQnARYzMjZPfuSUalhHkWbEe+WWXVpIkWbO80ABKy85d4wCCTr+2Csze4kCJ5//iSKP0Jn+wKD8ih6Tz5YBNpxiAmEWvaeUXf2nEcAAAAIAgv5gBDcGAAAPABoAZLITGxwREjmwExCwDNAAsAkvsABFWLAMLxuxDBs+WbAARViwBi8bsQYRPlmwAEVYsAMvG7EDDz5ZsgUMAxESObIKDAMREjmwDBCyEwEKK1gh2Bv0WbADELIYAQorWCHYG/RZMDEBFAIjIicRIxEzETYzMhIRJzQmIyIHERYzMjYEN+PCsmvz82qwxePzg3aVQUKWdIMCEvf+0XX9/weg/dd3/tr++gWmunv+IH67AAACAB8AAAWdBbAAEwAXAGsAsABFWLAPLxuxDx8+WbAARViwCC8bsQgPPlmyFAgPERI5sBQvshAUDxESObAQL7AA0LAQELIXBworWCHYG/RZsAPQsAgQsAXQsBQQsgcBCitYIdgb9FmwFxCwCtCwEBCwDdCwDxCwEtAwMQEzFSMRIxEhESMRIzUzETMRIREzASE1IQUef3/8/XX8fHz8Aov8/HkCi/11BK6i+/QCh/15BAyiAQL+/gEC/aK6AAEAjwAAAYIEOgADAB0AsABFWLACLxuxAhs+WbAARViwAC8bsQAPPlkwMSEjETMBgvPzBDoAAAEAjgAABGsEOgAMAF8AsABFWLAELxuxBBs+WbAARViwCC8bsQgbPlmwAEVYsAIvG7ECDz5ZsABFWLALLxuxCw8+WbIGAgQREjmwBi+0HwYvBgJxso8GAV2yAQEKK1gh2Bv0WbIKAQYREjkwMQEjESMRMxEzASEBASEB72/y8lUBUAEs/mEBuf7LAaz+VAQ6/lABsP3z/dMAAQAiAAAENgWwAA0AWwCwAEVYsAwvG7EMHz5ZsABFWLAGLxuxBg8+WbIBDAYREjmwAS+wANCwARCyAgcKK1gh2Bv0WbAD0LAGELIEAQorWCHYG/RZsAMQsAjQsAnQsAAQsAvQsArQMDEBNxUHESEVIREHNTcRMwGh6uoClfxugoL9A2dHk0f99soChyeTJwKWAAABACEAAAIuBgAACwBKALAARViwCi8bsQohPlmwAEVYsAQvG7EEDz5ZsgEEChESObABL7AA0LABELICBworWCHYG/RZsAPQsAbQsAfQsAAQsAnQsAjQMDEBNxUHESMRBzU3ETMBmpSU84aG8wN5NZI1/RkCkC+SLwLeAAEAkP5LBQkFsAATAGeyBhQVERI5ALAARViwAC8bsQAfPlmwAEVYsBAvG7EQHz5ZsABFWLAELxuxBBE+WbAARViwDC8bsQwPPlmwAEVYsA4vG7EODz5ZsAQQsgkBCitYIdgb9FmyDQAMERI5shIOABESOTAxAREUBiMiJzcWMzI1NQERIxEzAREFCb6pRjwOKDp7/YH8/AJ/BbD6GLfGEccMuDEEFfvrBbD77AQUAAEAfv5LBAYETgAaAGGyFRscERI5ALAARViwAy8bsQMbPlmwAEVYsAAvG7EAGz5ZsABFWLAKLxuxChE+WbAARViwGC8bsRgPPlmyARgDERI5sAoQsg8BCitYIdgb9FmwAxCyFQEKK1gh2Bv0WTAxARc2MzIWFxEUBiMiJzcWMzI1ETQmIyIHESMRAVwNc8SwtQG7pkU6Dig7fF1pkUvzBDqWqtbS/Ru0whHGDLAC2XhwZ/zgBDoAAgBk/+wHLQXEABcAIwCRsgEkJRESObABELAa0ACwAEVYsAwvG7EMHz5ZsABFWLAOLxuxDh8+WbAARViwAy8bsQMPPlmwAEVYsAAvG7EADz5ZsA4QshABCitYIdgb9FmyEgAOERI5sBIvshUBCitYIdgb9FmwABCyFwEKK1gh2Bv0WbADELIYAQorWCHYG/RZsAwQsh0BCitYIdgb9FkwMSEhBiMiJAInETQSJDMyFyEVIREhFSERIQUyNxEmIyIGBxEUFgct/J2neaf+95QCkQELqHunA1z9TAJW/aoCu/t9Y2hyW6GvAbIUkwENqgE6rAESlhTM/m7I/kAcDQQ4Ds+8/srB0QAAAwBb/+wG8gRPAB4AKgAyAJuyGTM0ERI5sBkQsCTQsBkQsC7QALAARViwAy8bsQMbPlmwAEVYsAgvG7EIGz5ZsABFWLAXLxuxFw8+WbAARViwGy8bsRsPPlmyBQgXERI5si8XCBESObAvL7QfLy8vAnGyjC8BXbIMBworWCHYG/RZsBcQshABCitYIdgb9FmyGQgXERI5sCLQsAMQsigBCitYIdgb9FmwK9AwMRM0ADMyFzY2FzISFRUhFhYzMjY3FwYGIyInBiMiABEXFBYzMjY1NCYjIgYlIgYHITU0JlsBD+D5hkG3bdbu/VYLkXVZj0dPR81494yG9uP+8vKGeXeGh3h1iAPhVXgUAbVxAif4AS+xVF4B/v3siIueKjKeP0GurgEtAQIJqrq5wKa+urqJeRlvegAAAQCLAAAClQYVAAwAMrIDDQ4REjkAsABFWLAELxuxBCE+WbAARViwAC8bsQAPPlmwBBCyCQEKK1gh2Bv0WTAxMxE0NjMyFwcmIyIVEYvCsD9ZGSoyowSctsMVuQu6+2gAAgBR/+wFHgXEABYAHgBbsgAfIBESObAX0ACwAEVYsA8vG7EPHz5ZsABFWLAALxuxAA8+WbIFDwAREjmwBS+wDxCyCAEKK1gh2Bv0WbAAELIXAQorWCHYG/RZsAUQshoBCitYIdgb9FkwMQUgABE1ISYmIyIHByc3NjMgABEVFAIEJzI2NyEVFBYCuP7c/r0D0AXfzKeXNDEhsNoBOgFrov7lqZa+Ev0vuhQBYAFJieDwNBPGD0j+i/63a8P+w6/U2r0fub8AAf/k/ksC0wYVAB4AcbIUHyAREjkAsABFWLAVLxuxFSE+WbAARViwEC8bsRAbPlmwAEVYsB0vG7EdGz5ZsABFWLAFLxuxBRE+WbAdELIAAQorWCHYG/RZsAUQsgsBCitYIdgb9FmwABCwDtCwD9CwFRCyGgEKK1gh2Bv0WTAxASMRFAYjIic3FhYzMjURIzUzNTQ2MzIXByYjIgcVMwKEybWkSDYPB0QSeKWlwrE9WxkmO50ByQOG/DWwwBG/AwquA8q0YrbDFbwKrWcAAgBY/+wFqgYuABgAJgBbsgQnKBESObAEELAj0ACwAEVYsA0vG7ENHz5ZsABFWLAELxuxBA8+WbIPDQQREjmwDy+yFggKK1gh2Bv0WbANELIcAQorWCHYG/RZsAQQsiMBCitYIdgb9FkwMQEUAgQjIiQCJzU0EiQzMhc2NjUzFAYHFhcHNCYjIgIHFRQSMzISNQUQlP7ttLD+65cBlwETsf+iT0y7eXxXBP24qKS5ArmoqbUCstb+va2tAUDRUtUBRq2oDYOCpNEjp98S9v7+/+tU7P72AQD2AAACAE//7AS7BKgAFwAiAFuyFCMkERI5sBQQsCDQALAARViwBC8bsQQbPlmwAEVYsBQvG7EUDz5ZsgYEFBESObAGL7INCAorWCHYG/RZsBQQshoBCitYIdgb9FmwBBCyIAEKK1gh2Bv0WTAxEzQ2NjMyFzY2NTMUBgcWFxUUBgYjIgARFxQWMjY1NCYjIgZPfeSU4Yo1MKdYZz8Ce+eV4/7s8or2iY15d4wCJ6H9iZUTanKGsyV9nh2g/IoBLgEBCae9wLmnvb0AAAEAff/sBj0GAQAYAFSyDBkaERI5ALAARViwGC8bsRgfPlmwAEVYsBEvG7ERHz5ZsABFWLAMLxuxDA8+WbIBDBgREjmwAS+yCAgKK1gh2Bv0WbAMELIVAQorWCHYG/RZMDEBFTY2NTMUBgcRFAAjIgA1ETMRFBYzIBERBL1tXrW7xf7X9/r+2vyUkAEkBbDcCoKh5NYJ/aXo/vEBC+0DzPwykpoBNAPGAAEAd//sBSgEkwAZAGGyBxobERI5ALAARViwDS8bsQ0bPlmwAEVYsAgvG7EIDz5ZsABFWLAELxuxBA8+WbANELAT0LIVEwgREjmwFS+yAwgKK1gh2Bv0WbIGFQgREjmwCBCyEAEKK1gh2Bv0WTAxARQGBxEjJwYjIiY1ETMRFDMyNxEzFTY2NzcFKI+i5QZrxbC186uxPvNIQQUCBJOypQv8z2p+zsMCvf1Gzn8DCYgHQkxMAAH/tf5LAZMEOgAMAC+yAw0OERI5ALAARViwDC8bsQwbPlmwAEVYsAQvG7EEET5ZsgkBCitYIdgb9FkwMQERBgYjIic3FjMyNREBkwG4p0Y4Dyc6fAQ6+4WywhG/DcAEbAAAAgBZ/+wD+ARPABYAHgBesggfIBESObAIELAX0ACwAEVYsAAvG7EAGz5ZsABFWLAILxuxCA8+WbIMAAgREjmwDC+wABCyEAEKK1gh2Bv0WbAIELIXAQorWCHYG/RZsAwQshoHCitYIdgb9FkwMQEyABUVFAYGJyICNTUhJiYjIgYHJzY2EzI2NyEVFBYCAOQBFHvahtXvAqoLj3dWi05PRtKRVngT/ktxBE/+1PYfmvuNAQEB7YiIoSc1nj5D/GCOdBlvegAAAQCUBOADQwYBAAgARQCwBC+yDwQBXbJQBAFdsnAEAV2wAtCwAi+wAdAZsAEvGLAEELAH0LAHL7QPBx8HAl2yAwcEERI5sAEQsAXQGbAFLxgwMQEVIycHIzUBMwNDw5aVwQEPjwTrC5ycDQEUAAABAHIE4AM0BgEACAAlALAEL7IPBAFdsAHQsAEvtA8BHwECXbIABAEREjmwCNCwCC8wMQE3MxUBIwE1MwHSktD+6Zb+684FZpsK/ukBGAkA//8AhwUSA14FsAAGAHAAAAABAHUEzAL7BeYACwAvALADL7IPAwFdsAbQsAYvtA8GHwYCXbADELIIAgorWCHYG/RZsAYQsAvQsAsvMDEBFAYgJjUzFBYyNjUC+7D+2rC2S4RKBeZ+nJx+QklJQgAAAQCBBN8BhwXVAAkAHbIDCgsREjkAsAgvsg8IAV2yAgUKK1gh2Bv0WTAxEzQ2MhYVFAYiJoFEfkREfkQFWTVHRzU0RkYAAAIAeASNAjMGKgAJABQAKgCwBS+yDwUBXbAT0LATL7IACgorWCHYG/RZsAUQsg0KCitYIdgb9FkwMQEyFhQGIyImNDYHFBYzMjY1NCYiBgFWXYB9YGF9fxFCLi9BP2I/Bip7qnh4qnvQL0FAMC5DQwABACn+UgGhADwADwAisg8QERESOQCwAEVYsAovG7EKET5ZsgUDCitYIdgb9FkwMSEGBhUUMzI3FwYjIiY1NDcBjFdKRywuFUlcX3T0OF4xRBeOLG5btWwAAQB6BNsDVwX1ABUAQACwAy+wCNCwCC+2DwgfCC8IA12wAxCwC9CwCy+wCBCyDwMKK1gh2Bv0WbADELISAworWCHYG/RZsA8QsBXQMDEBFAYjIi4CIyIGFSc0NjMyFjMyNjUDV39gJzlpKxomNZV/XzmhNCY2BelukhE8DDkuCG6WWjkvAAACAEkE0QNWBf8AAwAHAEAAsAIvsg8CAV2wANCwAC+0DwAfAAJdsAIQsAPQGbADLxiwABCwBdCwBS+wAhCwBtCwBi+wAxCwB9AZsAcvGDAxATMBIwMzAyMCaO7+9sWQ6d65Bf/+0gEu/tIAAgCC/moB7P++AAsAFwA9ALAYL7AD0LADL0APAAMQAyADMANAA1ADYAMHXbAP0LAPL7IJCQorWCHYG/RZsAMQshUJCitYIdgb9FkwMRc0NjMyFhUUBiMiJjcUFjMyNjU0JiMiBoJpTklqaklOaWUwIiEtLSEiMO5JY2FLSl5gSCEuLSIkMDAAAAH8jgTR/mYGAAADACMAsAEvsg8BAV2wANAZsAAvGLABELAC0LACL7QPAh8CAl0wMQEjASH+Zsr+8gEVBNEBLwAB/V4E0f82BgAAAwAjALACL7IPAgFdsAHQsAEvtA8BHwECXbACELAD0BmwAy8YMDEBIQEj/iEBFf7rwwYA/tH///xzBNv/UAX1AAcApPv5AAAAAf0+BOb+mQZ/AA4AJQCwAC+wBtCwBi+yAQAGERI5sgcICitYIdgb9FmyDQEAERI5MDEBJzY2NTQjNzIWFRQGBxX9UQdJQZYHqatOSATmkgUcI0h7aFg8TgpFAAAC/AwE5P80Be4AAwAHADcAsAEvsADQGbAALxiwARCwBdCwBS+wBtCwBi+2DwYfBi8GA12wA9CwAy+wABCwBNAZsAQvGDAxASMBIQEjAzP+B9D+1QEGAiLD9foE5AEK/vYBCgAAAf0c/pT+L/+LAAgAEQCwAi+yBgUKK1gh2Bv0WTAxBTQ2MhYUBiIm/RxHhEhIhEfxNUdHakZGAAABAMYE6QHiBkEAAwAXALACL7AA0LAAL7ACELAD0BmwAy8YMDEBMwMjAQPfjJAGQf6oAAMAZwTfA7oGrwADAAwAFQA7ALAUL7AC0LACL7AB0LABL7QPAR8BAl2wAhCwA9AZsAMvGLAUELAL0LALL7IGBQorWCHYG/RZsA/QMDEBMwMjBTQ2MhYUBiImJTQ2MhYUBiImAe7lgpL+qER2Q0N2RAJWQ3ZERHZDBq/+1i8yRERkREQxMkREZERE//8AjgJFAakDUgIGAHgAAAABAJsAAAQ3BbAABQArALAARViwBC8bsQQfPlmwAEVYsAIvG7ECDz5ZsAQQsgABCitYIdgb9FkwMQEhESMRIQQ3/WD8A5wE5PscBbAAAgAZAAAFoAWwAAMABgAvALAARViwAC8bsQAfPlmwAEVYsAIvG7ECDz5ZsgQBCitYIdgb9FmyBgIAERI5MDEBMwEhJSEBAm/zAj76eQFVAuD+mAWw+lDKA7sAAwBb/+wFEwXEAAMAFAAiAHayCCMkERI5sAgQsAHQsAgQsB/QALAARViwEC8bsRAfPlmwAEVYsAgvG7EIDz5ZsgIIEBESOXywAi8YtGACcAICXbQwAkACAl2yAAIBcbIBAQorWCHYG/RZsBAQshgBCitYIdgb9FmwCBCyHwEKK1gh2Bv0WTAxASE1IQUUAgQjIiQCJzU0EiQgBBIXBzQCIyICBxUUEjMyEjUDo/5AAcABcJT+7bOw/u6ZA5YBFAFkAROWAfy3qaS5ArumqbUCecKJ1v69raoBPM1d1QFEr6v+v9UF7wEF/v/rVPD++gEA9gABACAAAAUSBbAABgAxALAARViwAy8bsQMfPlmwAEVYsAEvG7EBDz5ZsABFWLAFLxuxBQ8+WbIAAwEREjkwMQEBIQEzASECmP6X/vEB/vUB//7wBET7vAWw+lAAAAMAbAAABC4FsAADAAcACwBLALAARViwCC8bsQgfPlmwAEVYsAIvG7ECDz5ZsgABCitYIdgb9FmyBQgCERI5sAUvsgYBCitYIdgb9FmwCBCyCgEKK1gh2Bv0WTAxNyEVIRMhFSEDIRUhbAPC/D5kAvb9ClcDmfxnysoDTcYDKcwAAQCbAAAFFAWwAAcAOACwAEVYsAYvG7EGHz5ZsABFWLAALxuxAA8+WbAARViwBC8bsQQPPlmwBhCyAgEKK1gh2Bv0WTAxISMRIREjESEFFPz9f/wEeQTk+xwFsAABAEcAAARNBbAADAA8ALAARViwCC8bsQgfPlmwAEVYsAMvG7EDDz5ZsgEBCitYIdgb9FmwBdCwCBCyCgEKK1gh2Bv0WbAH0DAxAQEhFSE1AQE1IRUhAQMc/nUCvPv6Acn+NwPi/WsBiALQ/frKlwJCAj+YzP3/AAADAEoAAAWuBbAAFQAcACMAbLILJCUREjmwCxCwGdCwCxCwINAAsABFWLAULxuxFB8+WbAARViwCi8bsQoPPlmyExQKERI5sBMvsADQsgkKFBESObAJL7AM0LAJELIhAQorWCHYG/RZsBnQsBMQshoBCitYIdgb9FmwINAwMQEWBBYVFAYHBgcVIzUmJCYQNiQ3NTMBFBYXEQYGBTQmJxE2NgN8oQEDjoh8han9ov78j44BA6T9/caqk5anA3SmlJGpBP8Dj/6emvZITQOpqQGM+gE+/48Dsf0foLACAq4Et5+gtgT9UgKzAAABAEQAAAVcBbAAFwBcsgAYGRESOQCwAEVYsBEvG7ERHz5ZsABFWLAWLxuxFh8+WbAARViwBC8bsQQfPlmwAEVYsAsvG7ELDz5ZshULFhESObAVL7AA0LAVELIMAQorWCHYG/RZsAnQMDEBNjY1ETMRBgAHESMRJgAnETMRFhYXETMDTIOQ/QP+6fb88P7oBPwBj4D8AkMXvqcB8f4G9v7PGf6KAXUXATD1Af/+C53CGANsAAABAGsAAATdBcMAJQBcsgcmJxESOQCwAEVYsBovG7EaHz5ZsABFWLAPLxuxDw8+WbAARViwJC8bsSQPPlmwDxCyEQEKK1gh2Bv0WbAO0LAA0LAaELIHAQorWCHYG/RZsBEQsCLQsCPQMDElNhI3NTQmIyIGFRUUEhcVITUzJgI1NTQSJDMyBBIVFRQCBzMVIQLfdHsBnZCOm393/gfYa3iOAQWkpQEGkHdr1P4QzyABEOdtytrZzWTr/usez8tnAR+eYrYBHZ+e/uK1ZZf+3GfLAAACAFb/6wR5BE4AFgAhAHmyHyIjERI5sB8QsBPQALAARViwEy8bsRMbPlmwAEVYsAAvG7EAGz5ZsABFWLAMLxuxDA8+WbAARViwCC8bsQgPPlmyAwEKK1gh2Bv0WbIKEwwREjmyFRMMERI5sAwQshoBCitYIdgb9FmwExCyHwEKK1gh2Bv0WTAxAREWMzI3FwYjIicGIyICNTUQEjMyFzcBFBYzMjcRJiMiBgP9A0YRChgzTKI1ZsHD4+TEtWcT/hx6doxGRopzfwQ6/Pp7BLQeo6IBHfgNAQoBNpeD/b+erYgBx47FAAIAlv53BGoFxAAUACgAZbInKSoREjmwJxCwANAAsA8vsABFWLAALxuxAB8+WbAARViwDC8bsQwPPlmyJwAMERI5sCcvsiQBCitYIdgb9FmyBiQnERI5sAAQshgBCitYIdgb9FmwDBCyHgEKK1gh2Bv0WTAxATIWFRQGBxYWFRQGIyInESMRNDY2ATQmIyIGFREWMzI2NTQmJyM1MzICac/yY1h5gvLRpXryfNkBTHFdYIFYnXGJemd7SNQFxNiyX5swLL2CzexT/jgFqXPBcP5tWnZ+aPzlUolubZEBuQAAAQAg/l8D9QQ6AAgAOLIACQoREjkAsABFWLABLxuxARs+WbAARViwBy8bsQcbPlmwAEVYsAQvG7EEET5ZsgAHBBESOTAxARMzAREjEQEzAg7s+/6P8/6P+wE7Av/78P41AdAECwAAAgBU/+wEOAYgAB8AKwBishYsLRESObAWELAj0ACwAEVYsAMvG7EDIT5ZsABFWLAWLxuxFg8+WbADELIJAQorWCHYG/RZsg4WAxESObAOL7IpAQorWCHYG/RZsh0pDhESObAWELIjAQorWCHYG/RZMDETNDYzMhYXFSYjIgYVFBcWEhcVFAYGIyIAETQ2NycmJhMUFjMyNjU0JiciBtDUt0lxT5dpTlq84N4CeuGV4v7uuIkCW2h2iXl3h5FteYkE6pGlFhvDNT00XUJP/urMHJv2hwEjAQOl/yIFKIn9faK8vLZ4yxe+AAEAYP/sBAwETQAnAIuyFigpERI5ALAARViwCS8bsQkbPlmwAEVYsCUvG7ElDz5ZshcJJRESOXywFy8YtEAXUBcCXbTQF+AXAl2yGAcKK1gh2Bv0WbIDGBcREjmwCRCyEAEKK1gh2Bv0WbINFxAREjmyHA0BXbILDQFdsCUQsh4BCitYIdgb9FmyIR4YERI5tAQhFCECXTAxEzQ2NyYmNTQ2MzIWFSM0JiMiBhUUFjMzFSMGFRQWMzI2NTMUBCMiJGBpYldh+NK///J6WV5yYGnH0dJ9ZmKC8v78y9X++AEyXH8gJHlIlqW1kTxPTT88S60Dkz9XWUKburIAAAEAYf5+A8oFsAAeAEqyCB8gERI5ALAPL7AARViwAC8bsQAfPlmwAEVYsBUvG7EVDz5ZsAAQshwBCitYIdgb9FmyARwAERI5sBUQsggBCitYIdgb9FkwMQEVAQYGFRQWFxcWFhUUBgcnNjU2JycmJyY1EAE3ITUDyv5gVkY9S91hT3pSfV0CbmjESjkBJdz9xAWwkf4KbbprVFoYQh9iUUe6PmVnRj0hGzJpUIsBIAFR/cMAAAEAfv5hBAYETgARAFOyDBITERI5ALAARViwAy8bsQMbPlmwAEVYsAAvG7EAGz5ZsABFWLAHLxuxBxE+WbAARViwDy8bsQ8PPlmyAQMPERI5sAMQsgwBCitYIdgb9FkwMQEXNjMyFhcRIxE0JiMiBxEjEQFcDHfBtq0D815olkbzBDqDl8TF+5wEU25pevzvBDoAAwBz/+wELAXEAA0AFgAeAHmyAx8gERI5sAMQsBPQsAMQsBvQALAARViwCi8bsQofPlmwAEVYsAMvG7EDDz5Zsg4DChESOXywDi8YtGAOcA4CXbQwDkAOAl2yAA4BcbAKELITAQorWCHYG/RZsA4QshgBCitYIdgb9FmwAxCyGwEKK1gh2Bv0WTAxARACIyICAzUQEjMyEhMFITU0JiMiBhUFIRUUFjI2NwQs+OPf+gX25uL2Bf06AdR6cW96AdT+LHvgdwICcv7E/rYBQQEt6QE1AUz+xP7TIzDOy8vO7yrQ0crKAAABAKn/9AJhBDoADAAoALAARViwAC8bsQAbPlmwAEVYsAkvG7EJDz5ZsgQBCitYIdgb9FkwMQERFBYzMjcVBiMgEREBnDI+KitKVv7oBDr89j02CrwXATUDEQABABb/7gRKBfsAGQBQsgMaGxESOQCwAC+wAEVYsAsvG7ELDz5ZsABFWLAQLxuxEA8+WbALELIHAQorWCHYG/RZsg8ACxESObAPELAS0LAAELIVAQorWCHYG/RZMDEBMhYXARYXFzcXBiMiJicDAyEBJyYnIwcnNgESbHgfAaskMSARBCo0bXUryvb+9wGBWyJJIhsDOwX7VVD7v1YHAQHAClhvAhT9NwQP2ksDArYQAAEAZP52A9QFxAAsAFayAy0uERI5ALAWL7AARViwKi8bsSofPlmyAgEKK1gh2Bv0WbIILSoREjmwCC+yCQEKK1gh2Bv0WbIdLSoREjmwHRCyDgEKK1gh2Bv0WbIkCQgREjkwMQEmIyIGFRQhMxUjIBEUFgQWFxYVBgYHJzY2NTQmJCcmJjU0NjcmJjU0JDMyFwODild6iAEciYz+noEBGW8jUQJ7UIM1Lj/+/Ux/dqOQbnwBAuOZfQTaJFZLuMb+42KIQiUYOG1IuztkOVApIy1EIDW3lJHELSiOYabFLAAAAQAt//QEzwQ6ABQAXLILFRYREjkAsABFWLATLxuxExs+WbAARViwCi8bsQoPPlmwAEVYsA8vG7EPDz5ZsBMQsgAHCitYIdgb9FmwChCyBQEKK1gh2Bv0WbAAELAN0LAO0LAR0LAS0DAxASMRFBYzMjcVBiMgEREhESMRIzUhBKmfMT8mL0pW/uj+tPOrBHwDfP22PjcKvBcBNQJT/IQDfL4AAgCA/mAEMQROAA4AGgBXshEbHBESObARELAA0ACwAEVYsAAvG7EAGz5ZsABFWLAKLxuxChE+WbAARViwBy8bsQcPPlmyCQAHERI5shEBCitYIdgb9FmwABCyFwEKK1gh2Bv0WTAxATISERUUAiMiJxEjETQAAxYzMjY1NCYjIgYVAlbg++DBs2rzAQMQQ5V2fXxyZncETv7L/u8P8v7ld/39A9vyASH81XWts7jFwaAAAAEAUv6KA+kETgAiAE2yGyMkERI5ALAARViwAC8bsQAbPlmwAEVYsBQvG7EUFz5ZsAAQsATQsAAQsgcBCitYIdgb9FmyHCMAERI5sBwQsg0BCitYIdgb9FkwMQEyFhUjNCYjIgYVFRQWBBYWFxQGByc2NjU0JicmJic1NDY2AjjE7eRtYHGDlAEuYDEBf0x/Myo8Qe7tAXjcBE7du2F0vKoag5tWOVNCSL84ZTdOLCgqDzf+0Sed+okAAAIAUv/sBH4EOgAPABsATLIHHB0REjmwBxCwE9AAsABFWLAOLxuxDhs+WbAARViwBy8bsQcPPlmwDhCyAAEKK1gh2Bv0WbAHELITAQorWCHYG/RZsAAQsBnQMDEBIRYVFAYGIyIAETU0ADchARQWMzI2NTQmIyIGBH7+9bp63pHi/vABDN8CQfzHhXp1gYN1docDdpL7juyDASwBAwzuASMC/dipu7y9nLOwAAABAD//7APsBDoAEABJsgEREhESOQCwAEVYsA8vG7EPGz5ZsABFWLAKLxuxCg8+WbAPELIAAQorWCHYG/RZsAoQsgUBCitYIdgb9FmwABCwDdCwDtAwMQEhERQWMzI3FwYjIAMRITUhA+z+mCszJzcmUGz+7AX+rgOtA3n9sDs7FrEsATkCVMEAAQCA/+sECAQ6ABIAOLIOExQREjkAsABFWLAALxuxABs+WbAARViwDi8bsQ4PPlmyAwEKK1gh2Bv0WbAAELAI0LAILzAxAREQMzI2NSYDMxYREAAjIiYnEQFyoXGRA27xc/7858vRAQQ6/Xb+/emg5wEd5v7i/vT+weLYApUAAgBE/iIFhQRBABoAIwBfshAkJRESObAQELAb0ACwGS+wAEVYsBEvG7ERGz5ZsABFWLAGLxuxBhs+WbAARViwAC8bsQAPPlmyDQEKK1gh2Bv0WbAAELAY0LANELAb0LARELIhAQorWCHYG/RZMDEFJAA1NBI3FwYGBxQWFxE0NjMyFhYVFAAFESMTNjY1JiYjIhUCZf78/uN+c5hITAKalJ58k+yH/t7+9fPzlaUCjXQ3DhwBN/+kAQVTkka8aKHNHgKAd5KN+5Lz/tca/jEClBnBl5e/PgAAAQBP/iIFfgQ6ABgARLIAGRoREjkAsA0vsABFWLAULxuxFBs+WbAARViwDy8bsQ8PPlmyFwEKK1gh2Bv0WbAB0LAUELAY0LAG0LAPELAM0DAxARE2NjUmAzMWERAABREjESQAAxEzERAFEQNSk6cFcO55/uH+8/P+/P71AfMBHQQ6/H0bzqTiARTj/u3+/P7KGv4yAdAeATMBCgHt/hj+ojwDggABAGb/7AYtBDoAIABWshohIhESOQCwAEVYsAAvG7EAGz5ZsABFWLAYLxuxGA8+WbAARViwHC8bsRwPPlmyBQEKK1gh2Bv0WbIJABwREjmwDtCwABCwE9CwEy+yGgUYERI5MDEBAgcUFjMyNjURMxEWFjMyNjUmAzMWEAIjIicGIyICEDcB5YYHYVhbYPsCX1pYYQeF8Y3Vy+hcXObL1o0EOv7p7b3LnZQBRv6vjpjLve8BFej9yP7S3t4BLgI46AACAHb/7ASYBcQAIAApAGuyDyorERI5sA8QsCHQALAARViwGi8bsRofPlmwAEVYsAYvG7EGDz5ZsiQaBhESObAkL7ITAQorWCHYG/RZsALQsgsaBhESObAGELIPAQorWCHYG/RZsCQQsB7QsBoQsicBCitYIdgb9FkwMQEGBxUUBiMiADURNxEUFjMyNjU1JgAnNTQ2MzIWFRE2NwEUFhcRJiMiBgSYOkT61dP+/uyCbmJt0f8AA8Wlp7xLKv2qfWsEbTRDAlcUC3Xa/QEF1AEdAv7efY+Gg3wmARPAG6nM0Lv+zgwLASNsoiABRZpJAAAB/+EAAASeBcMAGgBCsgAbHBESOQCwAEVYsAQvG7EEHz5ZsABFWLANLxuxDQ8+WbIABA0REjmwBBCyCQEKK1gh2Bv0WbAS0LAEELAX0DAxARM2NjMyFwcmIyIHAREjEQEmIyIHJzYzMhYXAj/SK3pgRkImDShBH/7Z/P7bIUArCiQ8Smd9LAMHAfhkYBrCBUX9a/3uAhACl0UFwRtkbAAAAgAz/+wGVAQ6ABIAJgBwsggnKBESObAIELAe0ACwAEVYsBEvG7ERGz5ZsABFWLAGLxuxBg8+WbAARViwCi8bsQoPPlmwERCyAAEKK1gh2Bv0WbIIEQYREjmwD9CwENCwFdCwFtCwChCyGwEKK1gh2Bv0WbIfEAoREjmwJNAwMQEjFhUQAiMiJwYjIgIRNDcjNSEBJichBgcUFjMyNjc1MxUWFjMyNgZUgDfKvO5cXO69yDZvBiH+xQQ9/MY8BFNLXGYB+gJjXUtTA4Oer/7i/tTi4gEuARyxnLf9/KCtsZy+ypeV6O6Pl8oAAQAi//IFvAWwABgAbrIRGRoREjkAsABFWLAXLxuxFx8+WbAARViwCS8bsQkPPlmwAEVYsBMvG7ETDz5ZsBcQsgABCitYIdgb9FmyBBcJERI5sAQvsAkQsgoBCitYIdgb9FmwBBCyEAEKK1gh2Bv0WbAAELAV0LAW0DAxASERNjMyBBAEIycyNjUmJiMiBxEjESE1IQSQ/hOUcvsBGP7u/gGJjAGPj4Z4/f58BG4E5P50JvD+UOy/eYR3hyD9dATkzAABAGj/7ATvBcQAHwBxsgMgIRESOQCwAEVYsAwvG7EMHz5ZsABFWLADLxuxAw8+WbAMELITAQorWCHYG/RZshcMAxESOXywFy8YtDAXQBcCXbRgF3AXAl200BfgFwJdsgAXAXGyGAEKK1gh2Bv0WbADELIcAQorWCHYG/RZMDEBBgAjIiQCJzU0EiQzMgAXIyYmIyIGByEVIRYWMzI2NwTuFv7U+K/+9ZEBkgERtPMBJRj8EpSOobAIAfv+BAernZOWFAHZ6P77pQE2z3vPATqq/vbsnI7l0srd5YedAAACAC0AAAhBBbAAGQAiAHSyCSMkERI5sAkQsBrQALAARViwGC8bsRgfPlmwAEVYsAgvG7EIDz5ZsABFWLAQLxuxEA8+WbIAGAgREjmwAC+wGBCyCgEKK1gh2Bv0WbAQELISAQorWCHYG/RZsAAQshoBCitYIdgb9FmwEhCwG9CwHNAwMQEhHgIVFAQHIREhAwICBiMjNTc+AjcTIRERITI2NTQmJwUNATGZ63/+6+X9yv5CGg9jvJ5AKFdfMQocA6sBKX6Rj3oDoQF11IfO/QUE5P3N/vj+3YbKAwhq19ECyf0m/fSTdXOPAgACAJsAAAhHBbAAEwAcAIeyAR0eERI5sAEQsBTQALAARViwAi8bsQIfPlmwAEVYsBMvG7ETHz5ZsABFWLAQLxuxEA8+WbAARViwDS8bsQ0PPlmyABATERI5sAAvsp8AAV2yBA0CERI5sAQvsAAQsg8BCitYIdgb9FmwBBCyFAEKK1gh2Bv0WbANELIVAQorWCHYG/RZMDEBIREzESEyFhYVFAQjIREhESMRMwERITI2NTQmIwGXAoD8ASuc7n/+4/P94P2A/PwDfAEpfpKUfANFAmv90m7Lhc33Anr9hgWw/Qj+GIZwb4MAAQAxAAAFyAWwABUAVgCwAEVYsBQvG7EUHz5ZsABFWLAILxuxCA8+WbAARViwEC8bsRAPPlmwFBCyAAEKK1gh2Bv0WbIEEBQREjmwBC+yDQEKK1gh2Bv0WbAAELAS0LAT0DAxASERNjMgBBURIxE0JiMiBxEjESE1IQSS/hGDjwEMAQf8fZqMhvz+igRhBOT+mxvs5f43AcqLehz9TQTkzAAAAQCS/pgFDQWwAAsASACwCS+wAEVYsAAvG7EAHz5ZsABFWLAELxuxBB8+WbAARViwBi8bsQYPPlmwAEVYsAovG7EKDz5ZsgIBCitYIdgb9FmwA9AwMRMzESERMxEhESMRIZL9AoH9/kv9/jcFsPsaBOb6UP6YAWgAAgCQAAAEwQWwAA0AFgBbshAXGBESObAQELAD0ACwAEVYsAwvG7EMHz5ZsABFWLAKLxuxCg8+WbAMELIAAQorWCHYG/RZsgIMChESObACL7IOAQorWCHYG/RZsAoQsg8BCitYIdgb9FkwMQEhESEyFhYVFAQHIREhAREhMjY1NCYnBCz9YQEqoO58/uvv/dMDnP1hASmAj4x8BOT+n27Khcz4AgWw/Qj+EotzboACAAACACT+mgXcBbAADgAUAGWyEhUWERI5sBIQsAvQALAARViwCy8bsQsfPlmwAEVYsAQvG7EEFz5ZsABFWLACLxuxAg8+WbAEELAB0LACELIGAQorWCHYG/RZsA3QsA7QsA/QsBDQsAsQshEBCitYIdgb9FkwMQEjESERIwMzNhI3EyERMyEhESEDAgXP8PxB9Ah1V2gPJgOWufvbAnD+Vxgb/poBZv6aAjBUAUHLAob7GgQa/mb+ZQAAAQAWAAAHmwWwABUAfQCwAEVYsAkvG7EJHz5ZsABFWLANLxuxDR8+WbAARViwES8bsREfPlmwAEVYsAIvG7ECDz5ZsABFWLAGLxuxBg8+WbAARViwFC8bsRQPPlmyEAkCERI5sBAvsgABCitYIdgb9FmwBNCyCBAAERI5sBAQsAvQshMAEBESOTAxASMRIxEjASEBASEBMxEzETMBIQEBIQT/o/yq/pv+xQHV/koBMgFcnfyWAVkBMf5OAdH+xgJ0/YwCdP2MAwcCqf2gAmD9oAJg/Vn89wAAAQBJ/+0EfwXDACkAhrIlKisREjkAsABFWLALLxuxCx8+WbAARViwFy8bsRcPPlmwCxCyAwEKK1gh2Bv0WbIoCxcREjl8sCgvGLIQKAFdtDAoQCgCXbRgKHAoAl20oCiwKAJdsgYoAxESObIlAQorWCHYG/RZshElKBESObAXELIfAQorWCHYG/RZshwlHxESOTAxATQmIyIGFSM0NjYzMgQVFAYHFhYVFAQjIiYmNTMUFjMyNjU0JiMjNTMgA2yUf22S/ITqjfoBFXhseoH+1Pqa+X38nHiGo4+Kq6IBDAQjYnRzW3e6Z9rEY6YwKqt/xOduvntegX5le2/IAAABAJQAAAUNBbAACQBFALAARViwAC8bsQAfPlmwAEVYsAcvG7EHHz5ZsABFWLACLxuxAg8+WbAARViwBS8bsQUPPlmyBAACERI5sgkAAhESOTAxATMRIxEBIxEzEQQQ/f39gf39BbD6UAQN+/MFsPvyAAABAC0AAAUNBbAAEQBNsgQSExESOQCwAEVYsAAvG7EAHz5ZsABFWLABLxuxAQ8+WbAARViwCS8bsQkPPlmwABCyAwEKK1gh2Bv0WbAJELILAQorWCHYG/RZMDEBESMRIQMCAgYjIzU3PgI3EwUN/P5CGg9jvJ5AKFdfMQocBbD6UATk/c3++P7dhsoDCGrX0QLJAAEAOf/rBN0FsAAPAEmyABARERI5ALAARViwDy8bsQ8fPlmwAEVYsAYvG7EGDz5ZsgAPBhESObAPELAB0LABL7AGELIKAQorWCHYG/RZsg0GDxESOTAxAQEhAQcGIyc3FjMyNzcBIQKgASQBGf4FLmTgaAIYPWwsNP4OARQCtwL5+0hbsgbIBFx7BCQAAwBP/8QGGAXsABYAHwAoAFWyCikqERI5sAoQsB7QsAoQsCDQALAKL7AVL7IUFQoREjmwFC+wANCyCwoVERI5sAsvsAjQsiEBCitYIdgb9FmwHtCwFBCyHwEKK1gh2Bv0WbAg0DAxATIEEhUUAgQjFSM1IyYkAjU0EiQzNTMBIgYVFBYXMxEzETMyNjU0JiMDrrsBFpmZ/uu88xep/uyYmgEUvvP++6rBu6sX8xGrv7+tBSaY/vCsqv7xl76+AZYBDaqtARKXxv5vz7y0zQIDDvzyz7a50AAAAQCS/qEFvQWwAAsAOwCwCS+wAEVYsAAvG7EAHz5ZsABFWLAELxuxBB8+WbAARViwCi8bsQoPPlmyAgEKK1gh2Bv0WbAG0DAxEzMRIREzETMDIxEhkv0Cgf2wFOj70QWw+xoE5vsc/dUBXwAAAQCOAAAE7gWwABEAPwCwAEVYsAAvG7EAHz5ZsABFWLAJLxuxCR8+WbAARViwAS8bsQEPPlmyDgEJERI5sA4vsgUBCitYIdgb9FkwMQERIxEGIyAkJxEzERYWMzI3EQTu/KKw/vv+9AH8AX6XrqQFsPpQAj0p5ugBzv4wi3YqAqcAAAEAmAAABwMFsAALAEgAsABFWLAALxuxAB8+WbAARViwAy8bsQMfPlmwAEVYsAcvG7EHHz5ZsABFWLAJLxuxCQ8+WbIBAQorWCHYG/RZsAXQsAbQMDEBESERMxEhETMRIREBlgG8/AG5/PmVBbD7GgTm+xoE5vpQBbAAAQCY/qIHrQWwAA8AVACwCy+wAEVYsAAvG7EAHz5ZsABFWLADLxuxAx8+WbAARViwBy8bsQcfPlmwAEVYsA0vG7ENDz5ZsgEBCitYIdgb9FmwBdCwBtCwCdCwCtCwAtAwMQERIREzESERMxEzAyMRIREBlgG8/AG5/KoU3vndBbD7GgTm+xoE5vsS/eABXgWwAAACABgAAAXUBbAADQAWAF6yARcYERI5sAEQsA7QALAARViwAC8bsQAfPlmwAEVYsAovG7EKDz5ZsgIAChESObACL7AAELIMAQorWCHYG/RZsAIQsg4BCitYIdgb9FmwChCyDwEKK1gh2Bv0WTAxEyERITIWFhUUBAchESEBESEyNjU0JicYAocBKqDuff7p7v3U/nUChwEpgI+MfAWw/dNuyYbN9wIE7f3L/hKLc26AAgAAAwCbAAAGWAWwAAsADwAYAG2yAhkaERI5sAIQsA3QsAIQsBfQALAARViwCy8bsQsfPlmwAEVYsA4vG7EOHz5ZsABFWLAILxuxCA8+WbAARViwDC8bsQwPPlmyAAgLERI5sAAvshABCitYIdgb9FmwCBCyEQEKK1gh2Bv0WTAxASEyFhYVFAQHIREzASMRMwERITI2NTQmJwGYASqg7nz+6+/90/0EwPz8+0ABKYCPjHwDg27Khcz4AgWw+lAFsP0I/hKLc26AAgACAJAAAATBBbAACwAUAE2yDhUWERI5sA4QsAHQALAARViwCy8bsQsfPlmwAEVYsAkvG7EJDz5ZsgAJCxESObAAL7IMAQorWCHYG/RZsAkQsg0BCitYIdgb9FkwMQEhMhYWFRQEByERMxERITI2NTQmJwGNASqg7nz+6+/90/0BKYCPjHwDg27Khcz4AgWw/Qj+EotzboACAAEAa//sBPEFxAAfAH+yAyAhERI5ALAARViwEy8bsRMfPlmwAEVYsBwvG7EcDz5ZsgkTHBESOXywCS8YtGAJcAkCXbTQCeAJAl20MAlACQJdsgAJAXGyBgEKK1gh2Bv0WbAcELIDAQorWCHYG/RZsgAGAxESObATELIMAQorWCHYG/RZsg8JDBESOTAxARYWMzI2NyE1ISYmIyIGByM2ADMyBBIXFRQCBCMiACcBaBSXk5yrBv3+AgIIsaCMlRL8GAEl8rMBEJMBj/70sPj+1BYB2Z6G5NfM2OSMnu4BCKj+yM17z/7HqAEF6AAAAgCg/+wHBwXEABcAJQB+shImJxESObASELAd0ACwAEVYsBMvG7ETHz5ZsABFWLANLxuxDR8+WbAARViwBC8bsQQPPlmwAEVYsAovG7EKDz5Zsg4KDRESOXywDi8YtGAOcA4CXbIIAQorWCHYG/RZsBMQshsBCitYIdgb9FmwBBCyIgEKK1gh2Bv0WTAxARQCBCMiJAInIxEjETMRMzYSJDMyBBIXBzQCIyICBxUUEjMyEjUHB5T+7bOn/vieDrb8/LMGmgEPrbIBE5YB/beopLkCu6aotQKy1v69rZgBHL39owWw/XHJATWlq/6/1QXyAQL+/+tU8P76AQD2AAACACAAAARfBbAADAAVAGGyEBYXERI5sBAQsArQALAARViwCi8bsQofPlmwAEVYsAAvG7EADz5ZsABFWLADLxuxAw8+WbIRCgAREjmwES+yAQEKK1gh2Bv0WbIFAREREjmwChCyEgEKK1gh2Bv0WTAxIREhASEBJhE0JDchEQEUFjMzESMiBgNi/ub+5/7xAUX+ARP2Ae/9BIqK6+uMiAIg/eACa3gBEdHpAvpQA+l7igIAhgACAFv/6wQ8BhMAGgAmAFSyDicoERI5sA4QsBvQALAARViwES8bsREhPlmwAEVYsAcvG7EHDz5ZsgARBxESObAAL7IZAAcREjmyGwEKK1gh2Bv0WbAHELIhAQorWCHYG/RZMDEBMhIVFRQAIyIAETUQEjc2NjUzFAYGBwYGBzYXIgYVFBYzMjY1NCYCesz2/vXl3/7u+PaKUcRCiKaYnxuRk3aGhHp5hYUD/v7v6gzq/t4BKAEARgFeAZgzHD82ZX5PIyCkkZXDn6Wcrq+wjKMAAwCPAAAEOgQ6AA4AFQAcAHiyAh0eERI5sAIQsBXQsAIQsBfQALAARViwAS8bsQEbPlmwAEVYsAAvG7EADz5ZshYBABESOXywFi8YtEAWUBYCXbTQFuAWAl2yDwcKK1gh2Bv0WbIIDxYREjmwABCyEAEKK1gh2Bv0WbABELIbAQorWCHYG/RZMDEzESEyFhUUBgcWFhUUBiMBESEyNTQjJTMyNTQnI48Bt97oXVtqfN/R/vgBCru+/vnIz8TTBDqbkUt3IBaGW5eeAc3+84aHrnqABAABAIUAAANNBDoABQArALAARViwBC8bsQQbPlmwAEVYsAIvG7ECDz5ZsAQQsgABCitYIdgb9FkwMQEhESMRIQNN/iryAsgDdvyKBDoAAgAn/r4ExQQ6AA4AFABbshIVFhESObASELAE0ACwDC+wAEVYsAQvG7EEGz5ZsABFWLAKLxuxCg8+WbIAAQorWCHYG/RZsAbQsAfQsAwQsAnQsAcQsA/QsBDQsAQQshEBCitYIdgb9FkwMTc2NjcTIREzESMRIREjEyEhESEHAoFlRQcOAu+W8v1K9gEBdgGf/u8HDsJxy54BnvyI/fwBQv6+AgQCp8/+1gABAB4AAAZcBDoAFQCCALAARViwCS8bsQkbPlmwAEVYsA0vG7ENGz5ZsABFWLARLxuxERs+WbAARViwAi8bsQIPPlmwAEVYsAYvG7EGDz5ZsABFWLAULxuxFA8+WbIQEQIREjmwEC+yjxABXbIAAQorWCHYG/RZsATQsggQABESObAQELAL0LITABAREjkwMQEjESMRIwMhAQEhEzMRMxEzEyEBASEENYHzgPn+1gFn/qwBKfVy83P2ASn+rQFp/tIBs/5NAbP+TQIzAgf+VwGp/lcBqf38/coAAAEATf/sA8QETQAnAI2yHigpERI5ALAARViwJS8bsSUbPlmwAEVYsAgvG7EIDz5ZshklCBESOXywGS8YtEAZUBkCXbTQGeAZAl2yFgcKK1gh2Bv0WbIDFhkREjmwCBCyEAcKK1gh2Bv0WbINFhAREjm0Aw0TDQJdsCUQsh4HCitYIdgb9FmyIRkeERI5QAkLIRshKyE7IQRdMDEBFAYHFhUUBiMiJiY1MxQWMzI2NTQmIyM1MzY1NCYjIgYVIzQ2MzIWA7BXT7ryy3zMcvJ2WllpXGCutKNeUlBu8vC5yeADEkh5JEG6lbFTmWlCWVNDT0avAoRCSk88j7ekAAEAhgAABBIEOgAJAEUAsABFWLAALxuxABs+WbAARViwBy8bsQcbPlmwAEVYsAIvG7ECDz5ZsABFWLAFLxuxBQ8+WbIEBwIREjmyCQcCERI5MDEBMxEjEQEjETMRAyDy8v5Y8vIEOvvGAtL9LgQ6/S4AAAEAjwAABGUEOgAMAGgAsABFWLAELxuxBBs+WbAARViwCC8bsQgbPlmwAEVYsAIvG7ECDz5ZsABFWLALLxuxCw8+WbIGAgQREjl8sAYvGLTTBuMGAl20QwZTBgJdshMGAXGyAQEKK1gh2Bv0WbIKAQYREjkwMQEjESMRMxEzASEBASEB/Xvz82sBKwEs/nkBqP7EAaz+VAQ6/lABsP36/cwAAAEAIQAABBQEOgAPAE2yBBARERI5ALAARViwAC8bsQAbPlmwAEVYsAEvG7EBDz5ZsABFWLAILxuxCA8+WbAAELIDAQorWCHYG/RZsAgQsgoBCitYIdgb9FkwMQERIxEhAwIGIyMnNzY2NxMEFPP+zhQTq7BLATJQSQoUBDr7xgN2/of+8O3KBQut5QHOAAABAI8AAAVvBDoADABZALAARViwAS8bsQEbPlmwAEVYsAsvG7ELGz5ZsABFWLADLxuxAw8+WbAARViwBi8bsQYPPlmwAEVYsAkvG7EJDz5ZsgALAxESObIFCwMREjmyCAsDERI5MDEBASERIxEBIwERIxEhAv8BQAEw8/7Wpf7V8wEyASsDD/vGAsz9NALQ/TAEOgAAAQCGAAAEEQQ6AAsAfgCwAEVYsAYvG7EGGz5ZsABFWLAKLxuxChs+WbAARViwAC8bsQAPPlmwAEVYsAQvG7EEDz5ZsgkKABESObAJL7S/Cc8JAl2yvwkBcbQvCT8JAnKyXwkBcrTvCf8JAnG0HwkvCQJxso8JAV20jwmfCQJysgIBCitYIdgb9FkwMSEjESERIxEzESERMwQR8/5b8/MBpfMBtf5LBDr+PQHDAAEAhgAABBIEOgAHADgAsABFWLAGLxuxBhs+WbAARViwAC8bsQAPPlmwAEVYsAQvG7EEDz5ZsAYQsgIBCitYIdgb9FkwMSEjESERIxEhBBLz/lrzA4wDdvyKBDoAAQAjAAAD0AQ6AAcAMQCwAEVYsAYvG7EGGz5ZsABFWLACLxuxAg8+WbAGELIAAQorWCHYG/RZsATQsAXQMDEBIREjESE1IQPQ/qHz/qUDrQN5/IcDecEAAAMAVP5gBX8GAAAaACQALwB/sgcwMRESObAHELAg0LAHELAq0ACwBi+wAEVYsAMvG7EDGz5ZsABFWLAKLxuxChs+WbAARViwEy8bsRMRPlmwAEVYsBAvG7EQDz5ZsABFWLAXLxuxFw8+WbAKELIeAQorWCHYG/RZsBAQsiMBCitYIdgb9FmwKNCwHhCwLdAwMRMQEjMyFxEzETYzMhIRFAIjIicRIxEGIyICJyU0JiMiBxEWMzIBFBYzMjcRJiMiBlTRu0w+8kBWutPUt1NF8j1Pr9EJBDd0ai0lITPc/Lpsai0hIipocAIOAQkBNxwBzv4uIP7L/uDz/uYe/lYBphoBA+M8tscN/ToKAUuiqQoCyQrBAAEAhv6/BKUEOgALADsAsAgvsABFWLAALxuxABs+WbAARViwBC8bsQQbPlmwAEVYsAovG7EKDz5ZsgIBCitYIdgb9FmwBtAwMRMzESERMxEzAyMRIYbzAabzkxTd/NIEOvyIA3j8iP39AUEAAAEAXwAAA+AEOwARAEiyBBITERI5ALAARViwCS8bsQkbPlmwAEVYsBAvG7EQGz5ZsABFWLABLxuxAQ8+WbINAQkREjl8sA0vGLIEAQorWCHYG/RZMDEhIxEGIyImNREzERQWMzI3ETMD4PNeaN7q82lsYmTzAWkW1ccBTP60dmIXAgwAAAEAhgAABgMEOgALAEgAsABFWLAALxuxABs+WbAARViwAy8bsQMbPlmwAEVYsAcvG7EHGz5ZsABFWLAJLxuxCQ8+WbIBAQorWCHYG/RZsAXQsAbQMDEBESERMxEhETMRIREBeQFS8wFT8vqDBDr8iAN4/IgDePvGBDoAAQB+/r8GtAQ6AA8ASwCwDC+wAEVYsAAvG7EAGz5ZsABFWLADLxuxAxs+WbAARViwBy8bsQcbPlmwAEVYsA0vG7ENDz5ZsgEBCitYIdgb9FmwBdCwCdAwMQERIREzESERMxEzAyMRIREBcQFS8wFT8rkU3fq7BDr8iAN4/IgDePyI/f0BQQQ6AAIAHwAABOoEOgANABUAW7IAFhcREjmwDtAAsABFWLAMLxuxDBs+WbAARViwCC8bsQgPPlmyAAwIERI5sAAvsAwQsgoBCitYIdgb9FmwABCyDgEKK1gh2Bv0WbAIELIPAQorWCHYG/RZMDEBMzIWFhUUBgchESE1IRERMzI2NCYnAkruhcZn7MT+Hf7IAivtWWdlVgLiXKZup8oBA3bE/eX+o1mkXwEAAAMAjwAABckEOgALAA8AFwBtsgcYGRESObAHELAN0LAHELAU0ACwAEVYsAovG7EKGz5ZsABFWLAOLxuxDhs+WbAARViwCC8bsQgPPlmwAEVYsAwvG7EMDz5ZsgAOCBESObAAL7IQAQorWCHYG/RZsAgQshEBCitYIdgb9FkwMQEzMhYWFRQGByERMwEjETMBETMyNjQmJwGC7oXGZ+zE/h3zBEfz8/u57VlnZVYC4lymbqfKAQQ6+8YEOv3l/qNZpF8BAAACAI8AAAQiBDoACwATAE2yDhQVERI5sA4QsAHQALAARViwCi8bsQobPlmwAEVYsAgvG7EIDz5ZsgAKCBESObAAL7IMAQorWCHYG/RZsAgQsg0BCitYIdgb9FkwMQEzMhYWFRQGByERMxERMzI2NCYnAYLuhcZn7MT+HfPtWWdlVgLiXKZup8oBBDr95f6jWaRfAQAAAQBR/+wD6AROACAAfbIQISIREjkAsABFWLAILxuxCBs+WbAARViwEC8bsRAPPlmwCBCyAAEKK1gh2Bv0WbIeCBAREjl8sB4vGLRAHlAeAl2yAx4AERI5shwDAV2yCwMBXbIbBworWCHYG/RZsBAQshgBCitYIdgb9FmyFRsYERI5tAQVFBUCXTAxASIGFSM0NjYzMgAVFRQGBiMiJiY1MxQWMzI2NyE1ISYmAgFVduV0ynLcAQt53JF7yG7ldlZmfgz+rAFTDn4Di2lPZK9o/tL8GZv8iGe6dV13mYmohI8AAAIAkf/sBjgETgAUAB8AhbIVICEREjmwFRCwDdAAsABFWLAELxuxBBs+WbAARViwEy8bsRMbPlmwAEVYsBEvG7ERDz5ZsABFWLAMLxuxDA8+WbIBERMREjl8sAEvGLTQAeABAl20QAFQAQJdsg8BCitYIdgb9FmwDBCyFwEKK1gh2Bv0WbAEELIdAQorWCHYG/RZMDEBMzYkMzIAFxcUBgYjIgAnIxEjETMBFBYyNjU0JiMiBgGEzBsBCsvbARELAXvlltL+8xXK8/MBuYr2iI14d4wCh8/4/ubpOaD8igEE1P48BDr92Ke9wLmnvb0AAAIAJwAAA98EOgANABYAYbIUFxgREjmwFBCwBNAAsABFWLAALxuxABs+WbAARViwAS8bsQEPPlmwAEVYsAUvG7EFDz5ZshIAARESObASL7IDAQorWCHYG/RZsgcDEhESObAAELITAQorWCHYG/RZMDEBESMRIwMjEyYmNTQ2NwMUFjMzESMiBgPf8uPn/P9ka+nGvGVP7+BZagQ6+8YBjf5zAbUqnGWXwQL+oERVAThaAAAB/9v+SwP4BgAAIQCLshUiIxESOQCwHi+wAEVYsAQvG7EEGz5ZsABFWLAKLxuxChE+WbAARViwGC8bsRgPPlm2nx6vHr8eA12yLx4BXbIPHgFdsiEYHhESObAhL7IABworWCHYG/RZsgIYBBESObAKELIPAQorWCHYG/RZsAQQshUBCitYIdgb9FmwABCwGtCwIRCwHNAwMQEhFTYzIBMRFAYjIic3FjMyNRE0JiMiBxEjESM1MzUzFSECd/71d7YBWgW5pkY6Dyc7e2Fekkjznp7zAQsEremK/nX8/rLEEb8NvwLtcF2C/PsErauoqAABAFT/7AP5BE4AHQB6shYeHxESOQCwAEVYsA8vG7EPGz5ZsABFWLAILxuxCA8+WbIAAQorWCHYG/RZshkPCBESOXywGS8YtB8ZLxkCcbIbBworWCHYG/RZsgMAGxESObQEAxQDAl2wDxCyFgEKK1gh2Bv0WbITGRYREjmyHBMBXbILEwFdMDElMjY3Mw4CIyIAETU0ADMyFhcjJiYjIgYHIRUhEgI+WXgG5AN4ynTk/vgBCOTA9QTkB3Zbbn0KAVv+phmuaFBmsGQBJwECGfcBKeK2YHWUjaj+7AAAAgAeAAAGmgQ6ABYAHwB5sgkgIRESObAJELAX0ACwAEVYsAAvG7EAGz5ZsABFWLAILxuxCA8+WbAARViwDy8bsQ8PPlmyAQAIERI5sAEvsAAQsgoBCitYIdgb9FmwDxCyEQEKK1gh2Bv0WbABELIXAQorWCHYG/RZsAgQshgBCitYIdgb9FkwMQERMxYWFRQGByERIQMCBgcjJzc2NjcTAREzMjY1NCYnA/r4w+Xpw/4Z/uYVE6ivTgIyUkcKFALz7VhoZFYEOv6HA7yfoMECA3b+h/7y7gHKBQuv4wHO/cX+wVhNSFEBAAIAhgAABrEEOgASABsAgrIBHB0REjmwARCwE9AAsABFWLACLxuxAhs+WbAARViwES8bsREbPlmwAEVYsAsvG7ELDz5ZsABFWLAPLxuxDw8+WbIBEQsREjmwAS+yBBELERI5sAQvsAEQsg0BCitYIdgb9FmwBBCyEwEKK1gh2Bv0WbALELIUAQorWCHYG/RZMDEBIREzETMWFhUUBgchESERIxEzAREzMjY1NCYjAXkBpfP4w+Xpw/4Z/lvz8wKY7VpmZFsCnwGb/ocDvJ+gwQIB3f4jBDr9xf7BWktGVAAAAf/uAAAD+AYAABgAebIMGRoREjkAsBUvsABFWLAELxuxBBs+WbAARViwBy8bsQcPPlmwAEVYsA8vG7EPDz5Zsr8VAV2yLxUBXbIPFQFdshgPFRESObAYL7IABworWCHYG/RZsgIEBxESObAEELIMAQorWCHYG/RZsAAQsBHQsBgQsBPQMDEBIRU2MyATESMRNCYjIgcRIxEjNTM1MxUhAov+4Xe2AVoF82Fekkjzi4vzAR8EtfGK/nX9PQK6cF2C/PsEtaqhoQABAIb+mgQSBDoACwBFALAIL7AARViwAC8bsQAbPlmwAEVYsAMvG7EDGz5ZsABFWLAFLxuxBQ8+WbAARViwCS8bsQkPPlmyAQEKK1gh2Bv0WTAxAREhETMRIREjESERAXkBpvP+tfP+sgQ6/IgDePvG/poBZgQ6AAABAIj/6wbBBbAAHgBgsgYfIBESOQCwAEVYsAAvG7EAHz5ZsABFWLAMLxuxDB8+WbAARViwFS8bsRUfPlmwAEVYsAQvG7EEDz5ZsABFWLAILxuxCA8+WbIGAAQREjmyEQEKK1gh2Bv0WbAa0DAxAREUBiMiJwYjIiY1ETMRFBYzMjY1ESERFBYzMjY1EQbB+dLlbXHpz/P9Z15pcgEBbWNhbgWw+//W7qWl79UEAfv8dYKBdwQD+/x0g395BAMAAQBw/+sF7QQ6AB4AYLIGHyAREjkAsABFWLAALxuxABs+WbAARViwDC8bsQwbPlmwAEVYsBUvG7EVGz5ZsABFWLAELxuxBA8+WbAARViwCC8bsQgPPlmyBhUEERI5shEBCitYIdgb9FmwGtAwMQERBgYjIicGIyImNREzERQWMzI2NREzERQWMzI2NREF7QHavcdgZsu41fNURlNm9FxPSlsEOv1OwdyOjt3DAq/9UXJsbHICr/1RcmxscgKvAAL/4AAABCEGGAASABsAcbIVHB0REjmwFRCwA9AAsABFWLAPLxuxDyE+WbAARViwCS8bsQkPPlmyEg8JERI5sBIvsgAHCitYIdgb9FmyAg8JERI5sAIvsAAQsAvQsBIQsA3QsAIQshMBCitYIdgb9FmwCRCyFAEKK1gh2Bv0WTAxASERMxYWFRQGByERIzUzETMRIQERMzI2NTQmJwKj/t73xOXlwP4Srq7zASL+3u1bZWNXBDr+yQPOrq3TBAQ6qwEz/s39W/6CZVlVaQIAAQCY/+0GzQXFACUAjrIOJicREjkAsABFWLAkLxuxJB8+WbAARViwBS8bsQUfPlmwAEVYsBwvG7EcDz5ZsABFWLAiLxuxIg8+WbIAIiQREjmwAC+yHwABcbIIJBwREjmwBRCyDAEKK1gh2Bv0WbAAELAP0LAAELIhAQorWCHYG/RZsBLQsBwQshUBCitYIdgb9FmyGCQcERI5MDEBMzYSJDMyABcjJiYjIgYHIRUhFhYzMjY3MwYAIyIkAicjESMRMwGUtQuWAQmr8QEmGPwSk46hqwsB6f4WAqiilZYU/Bb+0/is/viTA7T8/ANPvgEdm/76752L3czD4fKGnOn++6EBNMr9dAWwAAABAIb/7AW6BE4AIwCSsg0kJRESOQCwAEVYsAQvG7EEGz5ZsABFWLAjLxuxIxs+WbAARViwGy8bsRsPPlmwAEVYsCAvG7EgDz5Zsg4EGxESOXywDi8YtEAOUA4CXbAA0LAEELILAQorWCHYG/RZsggOCxESObAOELIPBworWCHYG/RZsBsQshMBCitYIdgb9FmyFhMPERI5sA8QsB7QMDEBMzYkMzIWFyMmJiMiAyEVIRYWMzI2NzMOAiMiJCcjESMRMwF5nRQBBNLB9QTkB3Zb2xoBfP6FCn1uWXgG5AN4ynTT/v0UnvPzAnHe/+K2YHX+5quKjmhQZrBk/tz+OgQ6AAACABwAAAUXBbAACwAOAFYAsABFWLAILxuxCB8+WbAARViwAi8bsQIPPlmwAEVYsAYvG7EGDz5ZsABFWLAKLxuxCg8+WbINCAIREjmwDS+yAAEKK1gh2Bv0WbAE0LIOCAIREjkwMQEjESMRIwMhATMBIQEhAwODfuFzj/76Agb1AgD++v3gAVOoAar+VgGq/lYFsPpQAmgB+AAAAgAKAAAERQQ6AAsAEABWALAARViwCC8bsQgbPlmwAEVYsAIvG7ECDz5ZsABFWLAGLxuxBg8+WbAARViwCi8bsQoPPlmyDQIIERI5sA0vsgEBCitYIdgb9FmwBNCyDwgCERI5MDEBIxEjESMDIwEzASMBMwMnBwLkXcNbaPcBqecBq/f+XPhkGRkBF/7pARf+6QQ6+8YBxAEGZGQAAgCsAAAHMAWwABMAFgB8ALAARViwAi8bsQIfPlmwAEVYsBIvG7ESHz5ZsABFWLAELxuxBA8+WbAARViwCC8bsQgPPlmwAEVYsAwvG7EMDz5ZsABFWLAQLxuxEA8+WbIVAgQREjmwFS+wANCwFRCyBgEKK1gh2Bv0WbAK0LAGELAO0LIWAgQREjkwMQEhATMBIQMjESMRIwMhEyERIxEzASEDAagBaAEr9QIA/vqOfuJyj/76mP7b/PwCYgFTqQJnA0n6UAGq/lYBqv5WAav+VQWw/LgB+QAAAgCdAAAGGAQ6ABMAGAB/ALAARViwAi8bsQIbPlmwAEVYsBIvG7ESGz5ZsABFWLAELxuxBA8+WbAARViwCC8bsQgPPlmwAEVYsAwvG7EMDz5ZsABFWLAQLxuxEA8+WbIAEBIREjmwAC+wAdCyDgEKK1gh2Bv0WbAL0LAH0LABELAU0LAV0LIXEgQREjkwMQEzEzMBIwMjESMRIwMjEyMRIxEzATMDJwcBkP745wGr92pdw1to92268/MB7fhkGRkBxAJ2+8YBF/7pARf+6QEX/ukEOv2KAQZkZAACAIAAAAZuBbAAGgAdAHqyGx4fERI5sBsQsA3QALAARViwGS8bsRkfPlmwAEVYsAQvG7EEDz5ZsABFWLAMLxuxDA8+WbAARViwEy8bsRMPPlmyABkEERI5sAAvsgkBCitYIdgb9FmwDtCwD9CwABCwGNCyGxkEERI5sBkQshwBCitYIdgb9FkwMQEWFhcRIxEmJiMjBxEjESMiBgcRIxE2NiEBIQETIQR6/vEF/AJ2j2gG/H6PdQP8A/oBD/6FBOT9jun+LwMoBNnY/o0BbIFvC/2vAlxufv6QAWzh2wKI/YoBqQACAIIAAAVkBDoAGgAdAHqyGx4fERI5sBsQsBTQALAARViwBS8bsQUbPlmwAEVYsAAvG7EADz5ZsABFWLALLxuxCw8+WbAARViwEy8bsRMPPlmyBAUAERI5sAQvsAfQsAQQshAHCitYIdgb9FmwFdCwFtCyGwUAERI5sAUQshwBCitYIdgb9FkwMTM1NjY3ASEBFhYXFSM1JiYnIwcRIxEjIgYHFQETIYICxcz+6wP0/urGvgLzAV5yLwHyLXlgAwGFlf7Wss7SDQHb/iQR08ezsX9yAgP+XwGkbny6AmkBIgAAAgCjAAAIswWwACAAIwCXshwkJRESObAcELAj0ACwAEVYsAcvG7EHHz5ZsABFWLALLxuxCx8+WbAARViwAC8bsQAPPlmwAEVYsAUvG7EFDz5ZsABFWLARLxuxEQ8+WbAARViwGS8bsRkPPlmyCQcAERI5sAkvsgMBCitYIdgb9FmwCRCwDdCwAxCwHNCwF9CyIQcAERI5sAsQsiIBCitYIdgb9FkwMSERNDchESMRMxEhASEBFhYXESMRJiYjIwcRIxEjIgYHEQETIQLFO/6f/PwDMP6HBOX+hP7xBfwCdo9oBfx/kXMDAgjp/i4BYKFl/ZoFsP17AoX9eATZ2P6NAWyBbwn9rQJccXz+kQM5AaoAAAIAjwAAB3YEOgAgACMAl7IdJCUREjmwHRCwI9AAsABFWLAHLxuxBxs+WbAARViwCy8bsQsbPlmwAEVYsAAvG7EADz5ZsABFWLAFLxuxBQ8+WbAARViwES8bsREPPlmwAEVYsBkvG7EZDz5ZsgkLABESObAJL7IDBworWCHYG/RZsAkQsA3QsAMQsBzQsBfQsiELABESObALELIiAQorWCHYG/RZMDEhNTY3IREjETMRIQEhARYWFxUjNSYmJyMHESMRIyIGBxUBEyEClQE1/rfz8wKl/uwD9P7qxb4C8gFecy4B8i15YAMBhZX+1rCUZP5YBDr+JwHZ/iQR1MazsX9yAgP+XwGkbny6AmkBIgAAAgAo/kADqgeIACcAMACnsgIxMhESObACELAo0ACwLC+wAEVYsAUvG7EFHz5ZsABFWLAXLxuxFxE+WbAARViwES8bsREPPlmwBRCyAwEKK1gh2Bv0WbImBREREjl8sCYvGLIQJgFdskAmAV20YCZwJgJdsiMBCitYIdgb9FmyDCMmERI5sBEQsh0BCitYIdgb9FmyDywBXbAsELAp0LApL7QPKR8pAl2yKCwpERI5sDDQsDAvMDEBNCYjITUhMgQVFAYHBBUUBCMjBhUUFwcmJic0NjczNjY1NCEjNTMgAzczFQEjATUzApaFev7lARXtAQt9bgEM/vfoNXqYUoSiArGkP3KJ/s+JiQEQlJPP/uqX/uvOBCFeasfPtXCjLFf+xegDY2tBmSi3f4aLAgF9ZfPHA5+bCv7pARgJAAIAM/5IA4gGHAAnADAAlbICMTIREjmwAhCwKNAAsCwvsABFWLAFLxuxBRs+WbAARViwFy8bsRcRPlmwAEVYsBIvG7ESDz5ZsAUQsgQBCitYIdgb9FmyJRIFERI5fLAlLxi0QCVQJQJdsiQHCitYIdgb9FmyDCQlERI5sBIQsh0BCitYIdgb9FmwLBCwKdCwKS+0DykfKQJdsigpLBESObAw0DAxATQmIyE1ITIWFRQGBxYVFAYjIwYVFBcHJiYnNDY3MzI2NTQhIzUzMgM3MxUBIwE1MwJ0c2n+5AEX3PhhV9n20DZ+kFGClgKpoTVsd/75kZXioJLQ/umW/uvNAv48R7mljU93JEKslq8EYmtBkTC2cH2HAVA/lKkDEpsL/uoBFwoAAAMAX//sBRcFxAAQABcAHgBmsgQfIBESObAEELAR0LAEELAY0ACwAEVYsAwvG7EMHz5ZsABFWLAELxuxBA8+WbAMELIRAQorWCHYG/RZshQEDBESOXywFC8YsAQQshgBCitYIdgb9FmwFBCyHAcKK1gh2Bv0WTAxARQCBCMiJAInNTQSJCAEEhcBIgYHISYmAzI2NyEWFgUXlP7ts7D+7pkDlgEUAWQBE5YB/aSgtggCvAi0oJ+zCv1ECrgCstb+va2qATzNXdUBRK+r/r/VAe/w2dvu+8rl3tnqAAADAE//7AQ9BE4ADwAWAB0AZ7IEHh8REjmwBBCwENCwBBCwF9AAsABFWLAELxuxBBs+WbAARViwDC8bsQwPPlmyEAEKK1gh2Bv0WbIbBAwREjl8sBsvGLRAG1AbAl2yEwcKK1gh2Bv0WbAEELIXAQorWCHYG/RZMDETNDY2MzIAFxcUBgYjIgARATI2NyEWFhMiBgchJiZPfeSU2gETCwF755Xj/uwB92uFEP3/EIRraoUQAgAQhQInof2J/ufqOaD8igEuAQH+k5KJiJMC3ZWCgpUAAAEAEAAABPMFwgAPAEayAhARERI5ALAARViwBi8bsQYfPlmwAEVYsA8vG7EPHz5ZsABFWLAMLxuxDA8+WbIBDA8REjmwBhCyCAEKK1gh2Bv0WTAxARc3EzY2MxcHIwYHASMBIQJhGxvkNZx6LQIYVCf+mPT+DgENAYtybwL3rJcB1wJ8+5QFsAABACAAAAQYBE4AEQBGsgISExESOQCwAEVYsAUvG7EFGz5ZsABFWLARLxuxERs+WbAARViwDi8bsQ4PPlmyAQUOERI5sAUQsgoBCitYIdgb9FkwMQEXNxMSMzIXByYjIgYHASMBMwHjFBR6Ws9DJxcMICI7Df720/6S+wFuYWEBvgEiFsAGNir84gQ6AAIAX/92BRcGLgATACcAVbIFKCkREjmwBRCwIdAAsABFWLANLxuxDR8+WbAARViwAy8bsQMPPlmwBtCwDRCwENCwDRCyGgEKK1gh2Bv0WbAX0LADELIkAQorWCHYG/RZsCHQMDEBEAAHFSM1JgADNRAANzUzFRYAESc0JicVIzUGBhUVFBYXNTMVNjY1BRf+8+nG6P7vAwES6cbqAQ39gnjGeYWEe8Z5gAKy/tr+iyN+fiMBcwEdVQEkAXojcXIj/ob+2QbO9SNgYSP1z0zH/SVgXyP2zwACAE//iAQ9BLQAEwAlAFiyAyYnERI5sAMQsBTQALAARViwAy8bsQMbPlmwAEVYsBAvG7EQDz5ZsAMQsAbQsBAQsA3QsBAQsiMBCitYIdgb9FmwFNCwAxCyHQEKK1gh2Bv0WbAa0DAxEzQSNzUzFRYSFRUUAgcVIzUmAjUBNjY1NCYnFSM1BgYVFBYXNTNP3b24v93fv7i73QJQUlpaULhPWFZPuAIn2gEmH25tH/7Y3RHb/tkda2wfASbd/qcetZeCsh9gYCGylYOuIWgAAAMAiP/rBrUHPwAqAD0ARgC6sjBHSBESObAwELAJ0LAwELBF0ACwAEVYsAAvG7EAHz5ZsABFWLASLxuxEh8+WbAARViwBy8bsQcPPlmwAEVYsAsvG7ELDz5ZsgkABxESObASELITAQorWCHYG/RZsAsQshoBCitYIdgb9FmyHgsSERI5sCPQsBMQsCrQsBIQsDbQsDYvsCzQsCwvsisICitYIdgb9FmwLBCwMtCwMi+yOQgKK1gh2Bv0WbAsELBC0LBCL7BG0LBGLzAxATIWFxEUBiMiJwYjIiYnETQ2MxUiBhURFBYzMjY1ETMRFhYzMjY1ETQmIxMVIyIuAiMiFRUjNTQzMh4CATY3NTMVFAYHBPTO8gHx0ONycuPO8ATzz19mZl9pcvUBcWhfZmZfaiFTir8wFGiG6yVGyW/+KUEDqWA7BbD63f3q3fuenvbVAiDd/cyOgP3tgI6BdwGC/nlzgI6AAhOAjgHjhiNLCmgQItwPTxr+h1I8aGcxeB8AAAMAdP/rBdEF4wAqAD0ARgCvsglHSBESObAJELA60LAJELBG0ACwAEVYsBIvG7ESGz5ZsABFWLALLxuxCw8+WbASELAA0LAAL7ALELAH0LIJEgsREjmwEhCyEwEKK1gh2Bv0WbALELIaAQorWCHYG/RZsh4LEhESObAj0LATELAq0LASELA20LA2L7At0LAtL7IrCAorWCHYG/RZsC0QsDLQsDIvsjkICitYIdgb9FmwNhCwQdCwQS+wRtCwRi8wMQEyFhcVFAYjIicGIyImJxE0NjMVIgYVFRQWMzI2NzUzFRYWMzI2NTU0JiMTFSMiLgIjIhUVIzU0MzIeAgE2NzUzFRQGBwQ6utwB1LXFYWPCstME3LtJW1NDUF4B7AFeUUJUW0m9JFOKwSwVaIfrJUbFcP4wQQOpYDsER+XM+MznkZHgxQEDzefDdXz1fHVwasrKanB1fPV8dQHnhiNMCWgQItwPThv+hVI8aGcxeB8AAgCI/+sGwQcRAB4AJgB9sgYnKBESObAGELAj0ACwAEVYsA0vG7ENHz5ZsABFWLAILxuxCA8+WbAE0LIGCA0REjmwCBCyEQEKK1gh2Bv0WbANELAV0LAVL7ARELAa0LAVELAe0LAeL7ANELAl0LAlL7Am0LAmL7IgCAorWCHYG/RZsCYQsCPQsCMvMDEBERQGIyInBiMiJjURMxEUFjMyNjURIREUFjMyNjURJTUhFyEVIzUGwfnS5W1x6c/z/WdeaXIBAW1jYW78OQNVAf6mtQWw+//W7qWl79UEAfv8dYKBdwQD+/x0g395BAPnenp/fwACAHD/6wXtBbEAHgAmAImyBicoERI5sAYQsCXQALAARViwDS8bsQ0bPlmwAEVYsBUvG7EVGz5ZsABFWLAeLxuxHhs+WbAARViwBC8bsQQPPlmwAEVYsAgvG7EIDz5ZsgYIFRESObIRAQorWCHYG/RZsBrQsA0QsCXQsCUvsB/QsB8vsiAICitYIdgb9FmwHxCwItCwI9AwMQERBgYjIicGIyImNREzERQWMzI2NREzERQWMzI2NRElNSEXIRUjNQXtAdq9x2Bmy7jV81RGU2b0XE9KW/ydAzgE/rK1BDr9TsHcjo7dwwKv/VFybGxyAq/9UXJsbHICr/x7e39/AAEAZv6MBLYFxQAYAFOyFxkaERI5ALAARViwCi8bsQofPlmwAEVYsAAvG7EAFz5ZsABFWLACLxuxAg8+WbAKELAO0LAKELIQAQorWCHYG/RZsAIQshcBCitYIdgb9FkwMQEjESYANRE0EiQzIAAVIxAhIgYVERQWFzMDNPvT/wCNAQGjAQABH/z+3YypqYqf/owBZiABR/kBEa8BGJv+9+kBJt+8/u223wEAAQBc/okD8wROABoAU7IZGxwREjkAsABFWLAKLxuxChs+WbAARViwAC8bsQAXPlmwAEVYsAIvG7ECDz5ZsAoQsA/QsAoQshIBCitYIdgb9FmwAhCyGQEKK1gh2Bv0WTAxASMRJgI1NTQ2NjMyFhYVIzQmIyIGFRUUFhczAtXzs9N525J8xm/ldFhxgn5wmP6JAWogASPcHJv8iWe7dlt6vagbobsCAAEAbQAABJMFPgATABMAsA4vsABFWLAELxuxBA8+WTAxAQUHJQMjEyU3BRMlNwUTMwMFByUCWwEhSP7dta/h/t9HASXK/t5JASO5rOQBJUz+4AHBrICq/sEBjquAqwFoq4KrAUb+a6t/qgAB/GYEov85Bf0ABwARALAAL7IDBgorWCHYG/RZMDEBFSc3IScXFf0XsQECIgGxBSB+Ae5sAdwAAAH8cwUX/20GFQAPAC4AsAsvsAfQsAcvsgAICitYIdgb9FmwCxCwBNCwBC+wCxCyDAgKK1gh2Bv0WTAxATIVFSM1NCMiBAcjNTM2JP5/7ohqNv7iiykneQEYBhXcIhBodwGGAXcAAAH9ewUW/nIGYAAFAAwAsAEvsAXQsAUvMDEBNTMHFwf9e70BO1IF3ISWcEQAAf2lBRb+nAZgAAUADACwAy+wANCwAC8wMQEnNyczFf33UjsBvQUWRHCWhAAI+iT+xAG/Ba8ADAAaACcANQBCAE8AXABqAHoAsEUvsFMvsGAvsDgvsABFWLACLxuxAh8+WbIJCQorWCHYG/RZsEUQsBDQsEUQskwJCitYIdgb9FmwF9CwUxCwHtCwUxCyWgkKK1gh2Bv0WbAl0LBgELAr0LBgELJnCQorWCHYG/RZsDLQsDgQsj8JCitYIdgb9FkwMQE0NjIWFSM0JiMiBhUBNDYzMhYVIzQmIyIGFRM0NjMyFhUjNCYiBhUBNDYzMhYVIzQmIyIGFQE0NjIWFSM0JiMiBhUBNDYyFhUjNCYjIgYVATQ2MzIWFSM0JiIGFRM0NjMyFhUjNCYjIgYV/RFzvnRwMzAuMwHedF1fdXE1LiwzSHVdX3RwNVwz/st0XV90cDUuLTP9T3O+dHAzMC4z/U10vnRwMzAuM/7edV1fdHA1XDM1dV1fdXE1Li0zBPNUaGhULjc1MP7rVGhnVTE0NTD+CVVnaFQxNDcu/flUaGhUMTQ3Lv7kVGhoVC43Ny4FGlRoaFQuNzUw/glVZ2hUMTQ3Lv35VWdnVTE0NTAACPpN/mMBjAXGAAQACQAOABMAGAAdACIAJwAvALAhL7AWL7ASL7ALL7AbL7AmL7AARViwBy8bsQcfPlmwAEVYsAIvG7ECET5ZMDEFFwMjEwMnEzMDATcFFSUFByU1BQE3JRcFAQcFJyUDJwM3EwEXEwcD/lALemBGOgx6YEYCHQ0BTf6m+3UN/rMBWgOcAgFARP7b/PMC/sBFASYrEZRBxgNgEZRCxDwO/q0BYQSiDgFS/qD+EQx8Ykc7DHxiRwGuEJlEyPyOEZlFyALkAgFGRf7V/OMC/rtHASsAAAL/4AAABCEGYgASABsAdLIVHB0REjmwFRCwA9AAsABFWLANLxuxDR8+WbAARViwES8bsREfPlmwAEVYsAkvG7EJDz5ZsBEQsgAHCitYIdgb9FmyAg0JERI5sAIvsAAQsAvQsAzQsAIQshMBCitYIdgb9FmwCRCyFAEKK1gh2Bv0WTAxASERMxYWFRQGByERIzUzNTMVIQERMzI2NTQmJwKj/t73xOXlwP4Srq7zASL+3u1bZWNXBQX9/gPOrq3TBAUFq7Ky/JD+gmVZVWkCAAACAJQAAATZBbAADgAbAE2yBBwdERI5sAQQsBfQALAARViwAy8bsQMfPlmwAEVYsAEvG7EBDz5ZshYDARESObAWL7IAAQorWCHYG/RZsAMQshQBCitYIdgb9FkwMQERIxEhMgQVFAcXBycGIxM2NTQmJyERITI3JzcBkf0CLfQBH3V6bYh5qvkckH7+yQEwTzpzbgId/eMFsP7RwXeHZJY3AUM1SnaNAv4EFoBkAAACAHz+YAQwBE4AEwAiAG6yFyMkERI5sBcQsBDQALAARViwEC8bsRAbPlmwAEVYsA0vG7ENGz5ZsABFWLAKLxuxChE+WbAARViwBy8bsQcPPlmyCRAHERI5sg4QBxESObAQELIXAQorWCHYG/RZsAcQshwBCitYIdgb9FkwMQEUBxcHJwYjIicRIxEzFzYzMhIRJzQmIyIHERYzMjcnNxc2BDBuam9oWXCya/PgCmu4xuHygXiVQUKWRjJqblkiAhL0l3pjeDZ1/f8F2m6C/tn++gaivnv+IH4he2RnWAABAI8AAAQ0BxAABwAysgEICRESOQCwAEVYsAQvG7EEHz5ZsABFWLACLxuxAg8+WbAEELIAAQorWCHYG/RZMDEBIREjESERMwQ0/Vj9ArLzBOT7HAWwAWAAAQB+AAADWwVzAAcAKwCwAEVYsAQvG7EEGz5ZsABFWLACLxuxAg8+WbAEELIAAQorWCHYG/RZMDEBIREjESERMwNb/hbzAevyA3b8igQ6ATkAAAEAm/7GBJ0FsAAUAFuyDxUWERI5ALAJL7AARViwEy8bsRMfPlmwAEVYsBEvG7ERDz5ZsBMQsgABCitYIdgb9FmyAxMJERI5sAMvsAkQsgoHCitYIdgb9FmwAxCyDwEKK1gh2Bv0WTAxASERMyAAERAAIycyNjUCJSMRIxEhBDf9YKgBIgE8/vbzAYOIAv6rvPwDnATk/l/+zf7s/vT+1rqzwgF7Cf2HBbAAAQB+/uID2wQ6ABUASrILFhcREjkAsAovsABFWLAULxuxFBs+WbAARViwEi8bsRIPPlmwFBCyAAEKK1gh2Bv0WbIDFAoREjmwAy+yEAEKK1gh2Bv0WTAxASEVMyAAFRQGBgcnNjU0JiMjESMRIQNG/itJAQEBIF6rc1Xem45O8wLIA3bl/vrdYMKNHa5K1IGX/joEOgAAAQCQAAAFNgWwABQAYQCwAEVYsAAvG7EAHz5ZsABFWLAMLxuxDB8+WbAARViwAi8bsQIPPlmwAEVYsAovG7EKDz5Zsg8KDBESObAPL7KfDwFdsggBCitYIdgb9FmyAQgPERI5sAXQsA8QsBLQMDEJAiEBIxUjNSMRIxEzETM1MxUzAQUN/nwBrf7B/tNBo1n9/VmjNwEbBbD9W/z1Am3p6f2TBbD9mv7+AmYAAAEAjgAABK4EOgAUAFwAsABFWLANLxuxDRs+WbAARViwFC8bsRQbPlmwAEVYsAovG7EKDz5ZsABFWLADLxuxAw8+WbIOCg0REjmwDi+yCQEKK1gh2Bv0WbIBCQ4REjmwBdCwDhCwEtAwMQkCIQMjFSM1IxEjETMRMzUzFTMTBJT+xAFW/svYL5tX8vJXmyfPBDr9/v3IAayysv5UBDr+UMfHAbAAAQA0AAAGogWwAA4AYQCwAEVYsAYvG7EGHz5ZsABFWLAKLxuxCh8+WbAARViwAi8bsQIPPlmwAEVYsA0vG7ENDz5ZsggGAhESObAIL7IBAQorWCHYG/RZsAYQsgQBCitYIdgb9FmyDAEIERI5MDEBIxEjESE1IREzASEBASEDtq38/icC1YsBrQE2/gwCH/7QAnD9kATsxP2cAmT9R/0JAAEAPQAABagEOgAOAGsAsABFWLAGLxuxBhs+WbAARViwCi8bsQobPlmwAEVYsAIvG7ECDz5ZsABFWLANLxuxDQ8+WbIJCgIREjmwCS+yLwkBcbKMCQFdsgABCitYIdgb9FmwBhCyBAEKK1gh2Bv0WbIMAAkREjkwMQEjESMRITUhETMBIQEBIQNAe/L+agKIbAEqAS3+eAGo/sUBrP5UA3bE/lABsP35/c0AAQCUAAAHgwWwAA0AhwCwAEVYsAIvG7ECHz5ZsABFWLAMLxuxDB8+WbAARViwBi8bsQYPPlmwAEVYsAovG7EKDz5ZsgECBhESObABL7KfAQFdsm8BAXGy3wEBcbIPAQFysp8BAXGyPwEBcbQvAT8BAnKyfAEBXbACELIEAQorWCHYG/RZsAEQsggBCitYIdgb9FkwMQEhESEVIREjESERIxEzAZECiwNn/ZX8/XX9/QNSAl7D+xMCh/15BbAAAAEAfgAABWYEOgANAGYAsABFWLACLxuxAhs+WbAARViwDC8bsQwbPlmwAEVYsAYvG7EGDz5ZsABFWLAKLxuxCg8+WbIBDAYREjl8sAEvGLRAAVABAl2wAhCyBAEKK1gh2Bv0WbABELIIAQorWCHYG/RZMDEBIREhFSERIxEhESMRMwFxAaUCUP6j8/5b8/MCdwHDxPyKAbX+SwQ6AAEAm/7EB+8FsAAWAGiyEBcYERI5ALAHL7AARViwFS8bsRUfPlmwAEVYsBMvG7ETDz5ZsABFWLAQLxuxEA8+WbIBFQcREjmwAS+wBxCyCAcKK1gh2Bv0WbABELINAQorWCHYG/RZsBUQshEBCitYIdgb9FkwMQEzIAAREAAjJzI2NQIlIxEjESERIxEhBRR9ASIBPP728wGDiAL+q5H8/X/8BHkDQf7N/uz+9P7WurPCAXsJ/YkE5PscBbAAAQB+/uYGugQ6ABgAV7ISGRoREjkAsAgvsABFWLAXLxuxFxs+WbAARViwFS8bsRUPPlmwAEVYsBIvG7ESDz5ZsgEXCBESObABL7IPAQorWCHYG/RZsBcQshMBCitYIdgb9FkwMQEzIAAVFAYGByc2NjU0JiMjESMRIREjESEECn0BBwEsXatzVXVppZp/8/5a8wOMApT++95hv44drSiPZ4KX/jYDdvyKBDoAAAIAZ//rBdcFxQAlADIAhbIWMzQREjmwFhCwJtAAsABFWLANLxuxDR8+WbAARViwHS8bsR0fPlmwAEVYsAQvG7EEDz5ZsADQsAAvsgIEHRESObACL7ANELIOAQorWCHYG/RZsAQQshUBCitYIdgb9FmwABCyJQEKK1gh2Bv0WbACELAp0LAdELIvAQorWCHYG/RZMDEFIicGIyIkAic1NBI2MxUiBhUVFBIzMjcmETU0EjMyEhEVEAcWMwEUFhc2ETU0JiMiBhUF19+zlLe7/tSpA33hjGZ+27IxKeLtuMLzu1xq/Y5lY6JgWFReFUdHrgE2v8mvAR6h1OG9uNf++QfLAUTL8AE1/r/++sb+2soUAhmE1UiPAQnVrquvoQACAGH/6wTJBE4AIgAuAIyyBC8wERI5sAQQsCPQALAARViwCy8bsQsbPlmwAEVYsBovG7EaGz5ZsABFWLAELxuxBA8+WbAARViwAC8bsQAPPlmyAgQaERI5sAIvsAsQsgwBCitYIdgb9FmwBBCyEwEKK1gh2Bv0WbAAELIiAworWCHYG/RZsAIQsCXQsBoQsisBCitYIdgb9FkwMQUiJwYjIgARNTQSMxUGBhUVFBYzNyY1NTQ2MzIWFRUUBxYzARQXNjU1NCYjIgYVBMm6k3qQ5f7U26pAS5p9JY+2lJa9gU1Y/g54Yz0xMjsSNjkBQgEEQs8BDMoElHtJpswCleJ6u+r/zXfTlBEBj6psY6l7a4d4agABAC3+oQa3BbAADwBPALANL7AARViwCC8bsQgfPlmwAEVYsAIvG7ECHz5ZsABFWLAOLxuxDg8+WbACELIAAQorWCHYG/RZsAXQsA4QsgYBCitYIdgb9FmwCtAwMQEhNSEVIREhETMRMwMjESEBjf6gA77+nwKB/LAU5/vRBOzExPveBOb7HP3VAV8AAAEAJv6/BToEOgAPAEsAsA0vsABFWLADLxuxAxs+WbAARViwDy8bsQ8PPlmwAxCyBAEKK1gh2Bv0WbAA0LAPELIGAQorWCHYG/RZsAMQsAjQsAYQsArQMDEBIzUhFSMRIREzETMDIxEhARv1AsPbAabzkxTd/NIDd8PD/UsDePyI/f0BQQAAAQCAAAAE4QWwABgAT7IFGRoREjkAsABFWLAALxuxAB8+WbAARViwCy8bsQsfPlmwAEVYsA4vG7EODz5ZsgUOABESObAFL7AI0LAFELIUAQorWCHYG/RZsBHQMDEBERYXFhcRMxE2NxEzESMRBgcVIzUmJicRAX0CTzVuo2xk/f1gcKP2+gEFsP4smDknBQEr/twKGQKn+lACPBgK6+UG6t8BzQABAHQAAAP1BDsAFgBRsgYXGBESOQCwAEVYsBUvG7EVGz5ZsABFWLAMLxuxDBs+WbAARViwAS8bsQEPPlmyDwEMERI5fLAPLxiyBwEKK1gh2Bv0WbAE0LAPELAS0DAxISMRBgcVIzUmJicRMxEWFxEzETY3ETMD9fNFMaO2vgHyAYKjOzvzAWkOBYqLE9CxAVD+sKwfAQv+7wYOAgwAAAEAhQAABOUFsAARAEayBRITERI5ALAARViwAS8bsQEfPlmwAEVYsAAvG7EADz5ZsABFWLAJLxuxCQ8+WbIFAQAREjmwBS+yDgEKK1gh2Bv0WTAxMxEzETYzIAQXESMRJiYjIgcRhfygsgEFAQwB/AF+l66kBbD9wynm6f4zAdCLdir9WQAAAgAW/+kFvAXEABwAJABkshYlJhESObAWELAj0ACwAEVYsA4vG7EOHz5ZsABFWLAALxuxAA8+WbIeAA4REjmwHi+yEgEKK1gh2Bv0WbAE0LAeELAK0LAAELIXAQorWCHYG/RZsA4QsiIBCitYIdgb9FkwMQUgABE1JiY1MxQXNBIkFyAAERUhFRQWMzI3FwYGASE1NCYjIgYD3P7S/qqbp7WNlAEIngEIASL8mMu9sawxQ9j+BQJsmpSOsBcBVAErPBjUqrYqrgEcoAH+nP65hDXK10bFKC4DbB+4wN0AAv/L/+wEiwROABoAIQCMsiAiIxESObAgELAU0ACwAEVYsA0vG7ENGz5ZsABFWLAALxuxAA8+WbIcAA0REjmwHC+0vxzPHAJdtF8cbxwCcbQfHC8cAnGyjxwBXbTvHP8cAnGyEQcKK1gh2Bv0WbAE0LAcELAK0LAAELIVAQorWCHYG/RZshcADRESObANELIgAQorWCHYG/RZMDEFIiQnJyYmNTMUFzYkMzISERUhFhYzMjcXBgYBITUmJiIGAtjU/uYUA4KGqWgfAQe73fH9PQudd6hnhEHa/m0BzwhyynoU+9EyHcGTlTDF8/7m/v5ihpyHfWFrApYSen2MAAABAJD+vwTtBbAAFgBmshUXGBESOQCwEC+wAEVYsAQvG7EEHz5ZsABFWLAILxuxCB8+WbAARViwAi8bsQIPPlmyBwQCERI5fLAHLxi0AAcQBwJdsArQsBAQshEBCitYIdgb9FmwBxCyFgEKK1gh2Bv0WTAxASMRIxEzETMBIQEWABUQACMnIBECJSEBlQj9/XEBsgEy/iLpAQD+8PQBAQkC/q7++AJx/Y8FsP2kAlz9ih/+1/n+8/7TwgFvAXoGAAABAI7+6gRDBDoAFgBZsg0XGBESOQCwBy+wAEVYsBEvG7ERGz5ZsABFWLAVLxuxFRs+WbAARViwDy8bsQ8PPlmyFBUPERI5fLAULxi0QBRQFAJdsg4BCitYIdgb9FmyABQOERI5MDEBFhYVFAYGByc2JzQmJyMRIxEzETMBIQLNr7xeqnNV4AKNi67y8lUBQQEtAmEp461guogcrUfKdoUJ/lQEOv5QAbAAAAEAm/5LBRMFsAAUAHSyChUWERI5ALAARViwAC8bsQAfPlmwAEVYsAMvG7EDHz5ZsABFWLASLxuxEg8+WbAARViwCC8bsQgRPlmyAgASERI5fLACLxi0YAJwAgJdtDACQAICXbAIELINAQorWCHYG/RZsAIQshABCitYIdgb9FkwMQERIREzERQGIyInNxYzMjURIREjEQGXAn/9vqlFPA4kPnv9gfwFsP2DAn36GLfGEccMugKY/ZcFsAAAAQB+/ksECQQ6ABQAbbILFRYREjkAsABFWLAALxuxABs+WbAARViwAy8bsQMbPlmwAEVYsBIvG7ESDz5ZsABFWLAILxuxCBE+WbICAxIREjl8sAIvGLRAAlACAl2wCBCyDQEKK1gh2Bv0WbACELIQAQorWCHYG/RZMDEBESERMxEGBiMiJzcWMzI1ESERIxEBcQGl8wG6pkU6Dyc7fP5b8wQ6/j0Bw/uFs8ERvw3AAef+SwQ6AAACAFH/6wUeBcQAFgAeAF6yCB8gERI5sAgQsBfQALAARViwAC8bsQAfPlmwAEVYsAgvG7EIDz5Zsg0ACBESObANL7AAELIQAQorWCHYG/RZsAgQshcBCitYIdgb9FmwDRCyGgEKK1gh2Bv0WTAxASAAERUUAgQnIAARNSEmJiMiBwcnNzYBMjY3IRUUFgJxAUABbaD+46n+3P69A9AF38ynlzQxG6YBKZa+Ev0vugXE/oz+tmvB/sKxAQFgAUmJ4PA0E8YNSvr82r0fub8AAAEAW//rBEsFsAAbAGuyCxwdERI5ALAARViwAi8bsQIfPlmwAEVYsAsvG7ELDz5ZsAIQsgABCitYIdgb9FmyBAIAERI5shsLAhESOXywGy8YsAXQshALAhESObALELITAQorWCHYG/RZsBsQshkHCitYIdgb9FkwMQEhNSEXARYWFRQEIyImJjUzFBYzMjY1NCYjIzUC//2SA5EB/obI2v7l6ovifvyHaHmQmZGMBOTMo/5PGOrCxehnv4NfgH9klIWsAAABAF3+dQRGBDoAGwBcsgscHRESOQCwCy+wAEVYsAIvG7ECGz5ZsgABCitYIdgb9FmyBAACERI5shsLAhESObAbL7AF0LIQCwIREjmwCxCyEwEKK1gh2Bv0WbAbELIZBworWCHYG/RZMDEBITUhFwEWFhUUBCMiJiY1MxQWMzI2NTQmIyM1AvT9mwOMAf6Iy9f+6uuJ5HvziWx6lJqTjwN2xJv+Qxnpv8LqaL+BYIWAaZaDq///ADT+SwSJBbAAJgCwUgAAJgHepCkABwGvATUAAP//AC3+SQOiBDoAJgDrVQAAJwHe/53/egAHAa8BC//+AAIAUgAABIMFsAALABQAULIEFRYREjmwBBCwDtAAsABFWLABLxuxAR8+WbAARViwAy8bsQMPPlmyAAEDERI5sAAvsAMQsgwBCitYIdgb9FmwABCyDQEKK1gh2Bv0WTAxAREzESEiJiY1NCQ3AREhIgYVFBYXA4b9/dqd7oABFesBNP7XfJKLeQObAhX6UHTUiMz8A/0vAgaJdXSRAwAAAgBoAAAGsAWwABgAIQBgsgciIxESObAHELAZ0ACwAEVYsAgvG7EIHz5ZsABFWLAALxuxAA8+WbIHCAAREjmwBy+wABCyCgEKK1gh2Bv0WbIRCAAREjmwGdCwBxCyGgEKK1gh2Bv0WbAZELAh0DAxISIkNTQkNyERMxEzNjY3NiYnMxYWBwYGByURISIGFRQWFwJy7P7iARXrATT8S15sBQIhHfUfJgIE88z+sf7WfZCOev3TzvoDAhX7GgKKfUrZTF7MRdT8A8oCBop0dZIBAAIAXv/nBn8GGAAfACsAg7IZLC0REjmwGRCwKtAAsABFWLAGLxuxBiE+WbAARViwAy8bsQMbPlmwAEVYsBgvG7EYDz5ZsABFWLAcLxuxHA8+WbIFAxgREjmwGBCyCwEKK1gh2Bv0WbIQAxgREjmyGgMYERI5sAMQsiIBCitYIdgb9FmwHBCyKAEKK1gh2Bv0WTAxExASMzIXETMRBhYzNjY3NiczFxYHDgIjBCcGIyICJwEmIyIGFRQWMzI3J17kw6Nl8wJOQ3SCBARA7BcvAwJ94oz+/1Vry7ngCwKuR4Nzf3p2jUUGAg4BCgE2eAJC+09PaQK3qb7VWbeDqPmFBLezAQXeAVFowc2eqnJEAAEAPP/nBeMFsAApAGOyIyorERI5ALAARViwCS8bsQkfPlmwAEVYsCIvG7EiDz5ZsgEqCRESObABL7IAAQorWCHYG/RZsAkQsgcBCitYIdgb9FmyDwABERI5sCIQshUBCitYIdgb9FmyGiIJERI5MDETNTM2NjU0ISE1IRYEFRQHFhMVBhYzNjY3NiczFhYHDgIjBiYnNTQmI+ank4T+8/6lAWT6AQb/9gUBPDNlcgQEQPUaKwICetqKp7IIfGcCYs0BbXXRzQHTzOZkP/7+TTlJArajvtViymep+IUEp6o+bn4AAAEAL//iBP4EOgAkAGCyDyUmERI5ALAARViwHS8bsR0bPlmwAEVYsA4vG7EODz5ZsgIBCitYIdgb9FmyBw4dERI5shYlHRESObAWL7IUBworWCHYG/RZsB0QshsBCitYIdgb9FmyIhQWERI5MDElBjM2Njc2JzMWFgcGBiMGJic1NCMjJzM2NTQjIychFhYQBxYXAwECTlpgAwRB7C0YAQTpvJ6gCKLmAsK5y/8GARTL5LC5ButYAo9/lqmGgDnM8gNxg0h/vQSDlsMCpv7KSjCsAAEASP66BDcFsAAiAF+yCyMkERI5ALAXL7AARViwCS8bsQkfPlmwAEVYsBsvG7EbDz5ZsgEJGxESObABL7IAAQorWCHYG/RZsAkQsgcBCitYIdgb9FmyDwABERI5sBsQshIBCitYIdgb9FkwMRMnMzY2NTQhISchFgQVFAcWExUzFRQGByc2NjcjJic1NCYjlwHOkYH+6/7qAwEu7wED5OMDzWRagyQ4CKM8A350AlzDAXNv68MD3MnfZkf+9oasY9hLTTl3STGxhHGFAAEAdP6pBBoEOgAiAF+yBiMkERI5ALAYL7AARViwCS8bsQkbPlmwAEVYsBwvG7EcDz5ZsgEJHBESObABL7IABworWCHYG/RZsAkQsgcBCitYIdgb9FmyEAABERI5sBwQshMBCitYIdgb9FkwMRMnMzI1NCYjISchMhcWFRQHFhcVMxUUBgcnNjY3IyYnNTQjswHh0mtj/uEEASDjeGqtsQK7aFWDJjgGpisBwwGbs45KU8FkWZKeTzzDJKxl2kdNPX5PHoNUpgAAAQBC/+sHfwWwACIAYrIAIyQREjkAsABFWLANLxuxDR8+WbAARViwHy8bsR8PPlmwAEVYsAYvG7EGDz5ZsA0QsgABCitYIdgb9FmwBhCyCAEKK1gh2Bv0WbAfELISAQorWCHYG/RZshcfDRESOTAxASEDAgIGByM1NzY2ExMhERQWMzI2NzYnMxYWBw4CIyImNQQH/mEYDmG5nEooemgPHAOOTD9ufwQEQfYcKQICf+CMw8YE4/3g/vb+04oCygMJ3wEcAt/7vFJktKe72GbHZqf7hMG9AAEAQP/rBloEOgAhAGKyICIjERI5ALAARViwDC8bsQwbPlmwAEVYsB4vG7EeDz5ZsABFWLAFLxuxBQ8+WbAMELIAAQorWCHYG/RZsAUQsgcBCitYIdgb9FmwHhCyEQEKK1gh2Bv0WbIWHgwREjkwMQEhAwIGByMnNzY2NxMhERYWMzI2NzYnMxcWBw4CIyImJwMX/vcTEaitUwIyUEkKFALhAVFFWGcEBEDsFjADAnDHfcLHAQN0/pr+6fQDygULreUBzv0rUmSgmbXIULF8m+Z8vrkAAQCU/+cHhgWwAB0AZbIUHh8REjkAsABFWLAALxuxAB8+WbAARViwGS8bsRkfPlmwAEVYsBcvG7EXDz5ZsABFWLARLxuxEQ8+WbIEAQorWCHYG/RZsgkAFxESObIcABcREjmwHC+yFQEKK1gh2Bv0WTAxAREUFjM2Njc2JzMXFgcOAiMGJic1IREjETMRIREFCk0+cH4EBEH2Fy8DAnzijrvDCf2C/PwCfgWw+7xWYAKzprvYWbeDqPeHBMDD//2XBbD9gwJ9AAABAHf/4wZcBDoAHAB4shsdHhESOQCwAEVYsAQvG7EEGz5ZsABFWLAILxuxCBs+WbAARViwAi8bsQIPPlmwAEVYsBovG7EaDz5ZsgcIAhESOXywBy8YtNAH4AcCXbRAB1AHAl2yAAEKK1gh2Bv0WbAaELINAQorWCHYG/RZshIIAhESOTAxASERIxEzESERMxEGFjM2Njc2JzMWFgcOAiMEAwMa/lDz8wGw8wJSRl5kAwRA6xorAgJwx37+ihMBuv5GBDr+QwG9/S1SZgKmka/OXb9hm+Z8CAGEAAEAXf/rBLsFxQAhAEeyACIjERI5ALAARViwCS8bsQkfPlmwAEVYsAAvG7EADz5ZsAkQsg4BCitYIdgb9FmwABCyFQEKK1gh2Bv0WbIaAAkREjkwMQUiJAInETQSJDMyFwcmIyIGFREUFjM2Njc2JzMXFgcOAgK7rP7rmwKaARet34g/hqKdxcSefYMDAzX1JxMBAoHqFZwBGK0BD68BHZ5ZuETnvP8AtukChXSVzLFYWIvNbgAAAQBV/+sD5wROAB4ARLITHyAREjkAsABFWLATLxuxExs+WbAARViwCy8bsQsPPlmyAAEKK1gh2Bv0WbIFCxMREjmwExCyGAEKK1gh2Bv0WTAxJTY2NzQnMxYHBgYjIgA1NTQ2NjMyFwcmIyIGFRUUFgJaUUUCE+sdAgTStef+4nzikrtgLmOKcouUrwJDR3dnjFKgsAEx+B6X+otCvTq9pCCavwABACH/5wVaBbAAGQBNsgUaGxESOQCwAEVYsAIvG7ECHz5ZsABFWLAWLxuxFg8+WbACELIAAQorWCHYG/RZsATQsAXQsBYQsgkBCitYIdgb9FmyDhYCERI5MDEBITUhFSERFBYzNjY3NiczFhYHDgIjBiYnAeP+PgSA/j5NPnB+BARB9RsrAwJ94oy7wwkE483N/IdUYAK2o7vYYspnqPmFBMDDAAEARP/jBMsEOgAXAE2yBRgZERI5ALAARViwAi8bsQIbPlmwAEVYsBUvG7EVDz5ZsAIQsgABCitYIdgb9FmwBNCwBdCwFRCyCQEKK1gh2Bv0WbIOFQIREjkwMQEhNSEVIREUFjM2Njc2JzMWFgcGBiMEAwGJ/rsDi/6tUkVeYwMEQOssGQEE8cL+iRMDd8PD/fBUZAKEdJOefH43zPIIAYQAAAEAgf/rBP8FxQAoAHOyJikqERI5ALAARViwFi8bsRYfPlmwAEVYsAsvG7ELDz5ZsgMBCitYIdgb9FmyJBYLERI5fLAkLxiycyQBXbJgJAFdsiUBCitYIdgb9FmyBgMlERI5shAlJBESObAWELIeAQorWCHYG/RZshskHhESOTAxARQWMzI2NTMUBgQjICQ1NCUmJjU0JCEyFhYVIzQmIyIGFRQhMxUjIgYBf7eZhq78jf79oP7z/r8BDnaCAS8BCZf6i/2jfJCqATO2v52jAZhlfoFegr5p6cT9VzGmYsXbabp3WXVzY9nIcAAAAgBnBG8C1gXXAAUADQAbALALL7AH0LAHL7AB0LABL7ALELAE0LAELzAxARMzFQMjATMVFhcHJjUBk3DT5l3+1LEDTFCwBJgBPxX+wQFUX3tGSFq+AP//AEcCCQJUAs0ABgARAAD//wBHAgkCVALNAAYAEQAA//8AnQJtBJkDMQBGAZfgAEzNQAD//wCBAm0F0QMxAEYBl4UAZmZAAP//AAT+PwOZAAAAJwBDAAH+/gEGAEMBAAAcALYAAhACIAIDXbQQAiACAnG2gAKQAqACA10wMQABAGMEIAGWBhoACAAdsggJChESOQCwAEVYsAAvG7EAIT5ZsATQsAQvMDEBFwYHFSM1NjYBGnxbA9UBZwYaTYWQmIpg0QAAAQAzBAABZQYAAAgAHbIICQoREjkAsABFWLAELxuxBCE+WbAA0LAALzAxEyc2NzUzFRQGr3xaA9VpBABNg5KeimfRAAABADL+1gFkAMoACAAYsggJChESOQCwCS+yBA0KK1gh2Bv0WTAxEyc2NzUzFQYGrXtVA9oBZv7WTn+Uk4Vd0AAAAQBKBAABfAYAAAgAFgCwAEVYsAgvG7EIIT5ZsATQsAQvMDEBFRYXByYmNTUBHwNafE1pBgCej4ZNPtFniv//AGwEIALvBhoAJgFsCQAABwFsAVkAAP//AEAEAALABgAAJgFtDQAABwFtAVsAAAACADL+wgKqAP8ACQASACGyCxMUERI5sAsQsAXQALATL7IEDQorWCHYG/RZsA7QMDETJzY3NTMVBgcGFyc2NzUzFRQGsX9VA9oBNzH4f1gE2mb+wk6Jncm6bHJkQU6Olsu2Y90AAQBAAAAEHgWwAAsASwCwAEVYsAgvG7EIHz5ZsABFWLAGLxuxBhs+WbAARViwCi8bsQobPlmwAEVYsAIvG7ECDz5ZsAoQsgABCitYIdgb9FmwBNCwBdAwMQEhESMRITUhETMRIQQe/ojz/o0Bc/MBeANy/I4DcsgBdv6KAAEAXP5gBDkFsAATAHwAsABFWLAMLxuxDB8+WbAARViwCi8bsQobPlmwAEVYsA4vG7EOGz5ZsABFWLACLxuxAhE+WbAARViwAC8bsQAPPlmwAEVYsAQvG7EEDz5ZsgYBCitYIdgb9FmwDhCyCAEKK1gh2Bv0WbAJ0LAQ0LAR0LAGELAS0LAT0DAxISERIxEhNSERITUhETMRIRUhESEEOf6I8/6OAXL+jgFy8wF4/ogBeP5gAaDCArTEAXb+isT9TAAAAQCIAgYCRAPbAA0AFrIDDg8REjkAsAMvsQoKK1jYG9xZMDETNDYzMhYVFRQGIyImJ4h5ZGd4d2djeQIDA195eWIlXndzXQD//wCK//UDbwEAACYAEgMAAAcAEgHNAAD//wCK//UFKAEAACYAEgMAACcAEgHNAAAABwASA4YAAAABAEcCCQEhAs0AAwAYsgAEBRESOQCwAy+yAAEKK1gh2Bv0WTAxASM1MwEh2toCCcQAAAYASv/sB18FxAAVACMAJwA0AEEATgC4sihPUBESObAoELAC0LAoELAb0LAoELAm0LAoELA10LAoELBH0ACwJC+wJi+wAEVYsBkvG7EZHz5ZsABFWLASLxuxEg8+WbAD0LADL7IFAxIREjmwB9CwBy+wEhCwDtCwDi+yEBIDERI5sBkQsCDQsCAvsBIQsisCCitYIdgb9FmwAxCyMgIKK1gh2Bv0WbArELA40LAyELA/0LAgELJFAgorWCHYG/RZsBkQskwCCitYIdgb9FkwMQE0NjMyFzYzMhYVFRQGIyInBiMiJjUBNDYzMhYVFRQGIyImNQEnARcDFBYzMjY1NTQmIgYVBRQWMzI2NTU0JiIGFQEUFjMyNjU1NCYiBhUDL6yIlk5OlYavqYqXTk6Uiqz9G6iFiquriIWqAXd9Asd9sE8+QEpOfE0Bx08+QEpOfE37Tk0/PkxNfksBZYKqb2+njEeBqm5uqoYDe4OqqolGgqmpifwbSARySPw4RFdSTEtGVFRKSkRXUkxLRlRUSgLqRVVVSUhGVldJAAABAGwAigIzA6kABgAQALAFL7ICBwUREjmwAi8wMQETIwE1ATMBPPen/uABIKcCGf5xAYYTAYYAAAEAVACKAhsDqQAGABAAsAAvsgMHABESObADLzAxEwEVASMTA/sBIP7gp/f3A6n+ehP+egGPAZAAAQAtAG0DcQUnAAMACQCwAC+wAi8wMTcnAReqfQLHfW1IBHJIAP//ADUCkwK+BagDBwHYAAACkwATALAARViwCS8bsQkfPlmwDdAwMQAAAQBpAowC/wW6AA8AU7IKEBEREjkAsABFWLAALxuxAB8+WbAARViwAy8bsQMfPlmwAEVYsA0vG7ENEz5ZsABFWLAHLxuxBxM+WbIBAw0REjmwAxCyCgMKK1gh2Bv0WTAxARc2MyARESMRJiMiBxEjEQEBIEuQAQPFBX1jJ8UFrHmH/sn+CQHarVn90gMgAAEAXwAABHwFwwAnAI6yHygpERI5ALAARViwFy8bsRcfPlmwAEVYsAYvG7EGDz5ZsicGFxESObAnL7INAgorWCHYG/RZsAHQsAYQsgUBCitYIdgb9FmwCdCwJxCwENCwJxCwI9CwIy+2DyMfIy8jA12yJQIKK1gh2Bv0WbAR0LAjELAU0LAXELIeAQorWCHYG/RZshsjHhESOTAxASEXFAchByE1MzY2NScjNTMnIzUzJzQ2IBYVIzQmIyIGFRchFSEXIQMy/tACQAK4AfvnUicrAqWgBJyXBfoBluj1aV9YZwYBP/7GBQE1AdQuh1XKyglvWzeReZChyurauF9pgmihkHkABQAhAAAGTwWwABsAHwAjACYAKQC9sgoqKxESObAKELAf0LAKELAh0LAKELAm0LAKELAo0ACwAEVYsBovG7EaHz5ZsABFWLAXLxuxFx8+WbAARViwDC8bsQwPPlmwAEVYsAkvG7EJDz5ZsgUJGhESObAFL7AB0LABL7IPAQFdsgMDCitYIdgb9FmwBRCyBwMKK1gh2Bv0WbAl0LAK0LAO0LAFELAd0LAh0LAR0LADELAe0LAi0LAS0LABELAZ0LAn0LAV0LAJELAk0LAXELAp0DAxATMVIxUzFSMRIwEhESMRIzUzNSM1MxEzASERMwEzNSMFMycjATUjATMnBXfY2NjY/f7J/q3809PT0/wBNQFX+/5xlPP+Z+5fjwKML/2jKysDxaCXoP4SAe7+EgHuoJegAev+FQHr/N6Xl5f+fksB10QAAgCY/+wGOgWwAB4AJQCisiEmJxESObAhELAQ0ACwAEVYsBUvG7EVHz5ZsABFWLAZLxuxGRs+WbAARViwHS8bsR0bPlmwAEVYsAovG7EKDz5ZsABFWLATLxuxEw8+WbAdELIAAQorWCHYG/RZsAoQsgUBCitYIdgb9FmwABCwDdCwDtCyIBMVERI5sCAvshEBCitYIdgb9FmwHRCwHNCwHC+wFRCyJAEKK1gh2Bv0WTAxASMRFBYzMjcVBiMgEREjBgYHIxEjESEyFhczETMRMwEzMhE0JyMGM78yPyYvU03+6Hgc9Mqe+gGM1P0YdfK/+1+S9OagA4b9pD04CrwXATUCZa27A/3lBbDDswEH/vn+rQEA9wYA//8AlP/sCDwFsAAmADYAAAAHAFcEcgAAAAcANQAAB1MFsAAfACMAJwArAC4AMQA0AOuyMjU2ERI5sDIQsB7QsDIQsCLQsDIQsCfQsDIQsCrQsDIQsC7QsDIQsDDQALAARViwAi8bsQIfPlmwAEVYsB8vG7EfHz5ZsABFWLAbLxuxGx8+WbAARViwEC8bsRAPPlmwAEVYsA0vG7ENDz5ZsgkQAhESObAJL7AF0LAFL7IPBQFdsAHQsAUQsgcDCitYIdgb9FmwCRCyCgMKK1gh2Bv0WbAt0LAO0LAw0LAS0LAJELAl0LAp0LAh0LAV0LAHELAm0LAq0LAi0LAW0LABELAd0LAZ0LAQELAv0LAs0LAfELAy0LABELA00DAxASETMwMzFSMHMxUhAyMDIQMjAyE1MycjNTMDMxMhEzMBMzcjBTM3IwUzJyMBNyMFNyMBBzMEmAExV/timr8l5P73fvOQ/vKS8n/+/d4luZRi+1gBNGzU/c6fKuoDDp8h6f6muiplAbAmVv0yL1UBpwgQBAcBqf5XoKKg/dsCJf3bAiWgoqABqf5XAan9FaKioqKi/gC+ubkCAR8AAgB8AAAGEAQ6AA0AGwBrsggcHRESObAIELAQ0ACwAEVYsAAvG7EAGz5ZsABFWLAWLxuxFhs+WbAARViwCy8bsQsPPlmwAEVYsA4vG7EODz5ZshEBCitYIdgb9FmwABCyCQEKK1gh2Bv0WbIFEQkREjmyEAkRERI5MDEBMhYXESMRNCYjIREjEQERMxEhMjY3ETMRBgYjAwy7rgLzWmn+rvMBmfMBUGpZAfQB79wEOsDL/rUBQm1j/IoEOvvGAtb97WFoAq79V7zVAAEAXv/tBDAFwwAjAIqyFSQlERI5ALAARViwFi8bsRYfPlmwAEVYsAkvG7EJDz5ZsiMWCRESObAjL7IAAgorWCHYG/RZsAkQsgQBCitYIdgb9FmwABCwDNCwIxCwDtCwIxCwE9CwEy+2DxMfEy8TA12yEAIKK1gh2Bv0WbAWELIbAQorWCHYG/RZsBMQsB7QsBAQsCDQMDEBIRYWMzI3FwYjIAADIzUzNSM1MzYAMzIXByYjIgYHIRUhFSEDav6cBqOYbl8ceID/AP7aCKysrK0NASz9aoUcZmWXogkBY/6cAWQCD66sIcwdASABAo2Ajf8BGx/NIqykjYAAAAQAIQAABdQFsAAaAB8AJAApAOOyDCorERI5sAwQsBzQsAwQsCPQsAwQsCjQALAARViwCy8bsQsfPlmwAEVYsAEvG7EBDz5ZsAsQsiQBCitYIdgb9FmwINCwIC9AEwAgECAgIDAgQCBQIGAgcCCAIAldsB7QsB4vtrAewB7QHgNdQAsAHhAeIB4wHkAeBV2yJgMKK1gh2Bv0WbAn0LAnL0APMCdAJ1AnYCdwJ4AnkCcHXbIAAQorWCHYG/RZsCYQsAPQsB4QsAbQsCAQsA/QshIDCitYIdgb9FmwHNCwHdCwB9CwIBCwCtCwHhCwFNCwJhCwF9AwMQERIxEjNTM1IzUzESEyBBczFSMXBzMVIwYGIwEnIRUhJSEmJyEBIRUhMgHW/bi4uLgCLa0BATzkvQIBvOE2+r0BFQP9vgJD/b0B8EZy/sgB9P4MATF7Ah394wMfoEigAQmIgaAmIqB9hQHCKEjoOwL+OzcAAQAoAAAEDAWwABoAbbIWGxwREjkAsABFWLAZLxuxGR8+WbAARViwDC8bsQwPPlmwGRCyGAEKK1gh2Bv0WbAB0LAZELAU0LAUL7AD0LAUELITBworWCHYG/RZsAbQsBQQsA7QsA4vsgkHCitYIdgb9FmyDQkOERI5MDEBIxYXMwcjBgYHARUhASczMjY3ITchJiMhNyED2dozD8oylxbcyQHS/uH+AwH9cIMW/eYzAeMx2P7zNgOuBPlLZbalrxH93w0CUZldTLabzAAAAQAh/+wEUQWwAB4AkbIbHyAREjkAsABFWLARLxuxER8+WbAARViwBS8bsQUPPlmyExEFERI5sBMvsBfQsBcvsgAXAV2yGAEKK1gh2Bv0WbAZ0LAI0LAJ0LAXELAW0LAL0LAK0LATELIUAQorWCHYG/RZsBXQsAzQsA3QsBMQsBLQsA/QsA7QsAUQshoBCitYIdgb9FmyHgURERI5MDEBFQYCBCMiJxEHNTc1BzU3ETMVNxUHFTcVBxE2NjU1BFEClv7tsmuM3Nzc3Pzh4eHhqrIC/1nS/sOrFAJdV8dXiVfIVwE711rIWolayFn9+wL8+E0AAAEATwAABQ8EOgAXAFyyABgZERI5ALAARViwFy8bsRcbPlmwAEVYsBAvG7EQDz5ZsABFWLALLxuxCw8+WbAARViwBS8bsQUPPlmyFQsXERI5sBUvsADQsBUQsgwBCitYIdgb9FmwCdAwMQEWABMVIzUmJicRIxEGBhUVIzUSADc1MwMo4AEDBPMBgXLzcYLzAwEE3/MDain+kv7sv7jF7yr9agKVKvPHsboBFAFwK9EAAgAoAAAFMwWwABYAHwB4shggIRESObAYELAN0ACwAEVYsAwvG7EMHz5ZsABFWLACLxuxAg8+WbIGAgwREjmwBi+yBQEKK1gh2Bv0WbAB0LAGELAK0LAKL7IPCgFdsgkBCitYIdgb9FmwFNCwBhCwFdCwChCwF9CwDBCyHwEKK1gh2Bv0WTAxJSEVIzUjNTM1IzUzESEyBBUUBAchFSEBITI2NTQmJyEDM/6+/M3Nzc0CLfEBIP7u9P7EAUL+vgEtiJCNfP7E5+fny2vLAsj70NTxA2sBNn59cI4DAAQAcP/sBYkFxQAZACYANAA4AJSyGjk6ERI5sBoQsADQsBoQsCfQsBoQsDfQALA1L7A3L7AARViwCS8bsQkfPlmwAEVYsCQvG7EkDz5ZsAkQsAPQsAMvsg0JAxESObAJELIQAgorWCHYG/RZsAMQshYCCitYIdgb9FmyGQMJERI5sCQQsB3QsB0vsCQQsioCCitYIdgb9FmwHRCyMQIKK1gh2Bv0WTAxARQGICY1NTQ2MzIWFSM0JiMiBhUVFBYyNjUBNDYzMhYVFRQGICY1FxQWMzI2NTU0JiMiBhUFJwEXArGf/wCinoKAoapBNjRCQ2pAARiuh4itp/7oq6pPPkBJTj0+Tf37fgLHfgQlc5KnikeCq5RzNUBUSkpFVUMx/UCGpqaNR4Kpp4kFRFdTS0tGVFRK9EgEckgAAgBM/+sDkAX5ABcAIQBasgEiIxESObABELAY0ACwDC+wAEVYsAAvG7EADz5ZsgYMABESObAGL7IFBworWCHYG/RZsBPQsAAQshcBCitYIdgb9FmwBhCwGNCwDBCyHwEKK1gh2Bv0WTAxBSImNQYjNTI3ETY2MzIWFRUUAgcVFBYzAzY2NTU0JiMiBwLb4e1hYGFgA7KaiKzXsmhs1E1XKyBWAxXr5RO7GAHpv9a0myat/qlnTY56AkRLzGYpP0CyAAAEAJAAAAfCBcAAAwAPAB0AJwCmsh4oKRESObAeELAB0LAeELAE0LAeELAQ0ACwAEVYsCYvG7EmHz5ZsABFWLAkLxuxJB8+WbAARViwBi8bsQYfPlmwAEVYsCEvG7EhDz5ZsABFWLAfLxuxHw8+WbAGELAN0LANL7AC0LACL7IAAgFdsgECCitYIdgb9FmwDRCyEwIKK1gh2Bv0WbAGELIaAgorWCHYG/RZsiAkIRESObIlHyYREjkwMQEhNSEBNDYgFhUVFAYgJjUXFBYzMjY1NTQmIyIGFQEhAREjESEBETMHl/2fAmH9dr4BOL+6/sK9r1xRT1tcUE9c/sf+9P4N9AELAfbyAZyVAi+fwcCmTpzCwqIGYGxsY1FfbW1i+6MECvv2BbD78wQNAAACAG0DlARXBbAADAAUAG0AsABFWLAGLxuxBh8+WbAARViwCS8bsQkfPlmwAEVYsBMvG7ETHz5ZsgEVBhESObABL7IACQEREjmyAwEGERI5sATQsggBCRESObABELAL0LAGELENCitY2BvcWbABELAP0LANELAR0LAS0DAxAQMjAxEjETMTEzMRIwEjESMRIzUhA+h8PnxviYGFhW/+EYp1jQGMBQn+iwF0/owCHP6DAX395AG9/kUBu18AAAIAlv/sBJEETgAVABwAYrICHR4REjmwAhCwFtAAsABFWLAKLxuxChs+WbAARViwAi8bsQIPPlmyGQoCERI5sBkvsg8KCitYIdgb9FmwAhCyEwwKK1gh2Bv0WbIVCgIREjmwChCyFgoKK1gh2Bv0WTAxJQYjIiYCNTQSNjMyFhYXFSERFjMyNwEiBxEhESYEFLe7kfSHkPiEheOEA/0Ad5rErP6Ql3oCHHNecp0BAZOPAQOfi/OQPv64bnoDKnr+6wEecf//AFn/9QXLBZkAJwHV/9kChgAnAXwA+wAAAQcB3AMhAAAAEACwAEVYsAYvG7EGHz5ZMDH//wBU//UGaAW0ACcB1wAdApQAJwF8AagAAAEHAdwDvgAAABAAsABFWLANLxuxDR8+WTAx//8AW//1BlwFqAAnAdkADAKTACcBfAGMAAABBwHcA7IAAAAQALAARViwAS8bsQEfPlkwMf//AFj/9QYaBaMAJwHbACICjgAnAXwBMwAAAQcB3ANwAAAAEACwAEVYsAUvG7EFHz5ZMDEAAgBi/+sEQwX1ABkAJgBbshMnKBESObATELAg0ACwCy+wAEVYsBMvG7ETDz5ZsgALExESObAAL7ICCxMREjmwCxCyBQEKK1gh2Bv0WbAAELIaAQorWCHYG/RZsBMQsiABCitYIdgb9FkwMQEyFyYmIyIHJzc2MyAAERUUAgYjIgA1NTQSFyIGFRQWMzI2NTUmJgI4rncaxYR8ix08bo8BDQEneuOU4/7z/vR7hYR6eYUWiwQEfcLlNbcZLP5O/nI1wf7TpwEk9w3fARLCp6SasNDFVUxfAAEApv8bBPQFsAAHACcAsAQvsABFWLAGLxuxBh8+WbAEELAB0LAGELICAQorWCHYG/RZMDEFIxEhESMRIQT09P2Z8wRO5QXU+iwGlQABAED+8wTBBbAADAA1ALADL7AARViwCC8bsQgfPlmwAxCyAgEKK1gh2Bv0WbAF0LAIELIKAQorWCHYG/RZsAfQMDEBASEVITUBATUhFSEBA4/97gNE+38CT/2xBEf89gISAkP9c8OXAsgCxpjD/XMAAQCeAm0D7wMxAAMAEQCwAi+yAQEKK1gh2Bv0WTAxASE1IQPv/K8DUQJtxAABADsAAASSBbAACAA8sgAJChESOQCwBy+wAEVYsAEvG7EBHz5ZsABFWLADLxuxAw8+WbIAAQMREjmwBxCyBgEKK1gh2Bv0WTAxAQEzASMDIzUhAkEBeNn+F8XY0QFnASsEhfpQAkHFAAMAXv/sB98ETgAaACoAOQBysgc6OxESObAHELAi0LAHELAy0ACwAEVYsAQvG7EEDz5ZsABFWLAJLxuxCQ8+WbAEELAW0LAWL7IHFgQREjmwEtCwEi+yFBYEERI5sBYQsh4BCitYIdgb9FmwBBCyJwEKK1gh2Bv0WbAu0LAeELA30DAxARQGBiMiJicCISImJjU1NBI2MyATEiEyFhYXBzQmIyIHBgcVFhcWMzI2NQUUFjMyNjc3NSYnJiMiBgffgOaQjelVqv7fj+WBgeSOASSpqQEkjuSBAe+SeqRuKA8PLmufeZX6XZJ7aawrBw8obqR5kgIRmP2Qo6f+to7/mRWYAQCP/rkBR4/9lwSaxslKQiRFVcPDogWdw7OQGiRCSsnDAAAB/6/+SwKoBhUAFQA9sgIWFxESOQCwAEVYsA4vG7EOIT5ZsABFWLADLxuxAxE+WbIIAQorWCHYG/RZsA4QshMBCitYIdgb9FkwMQUUBiMiJzcWMzI3ETQ2MzIXByYjIhUBkLaqQj8SLCWKAsCyP1kZKjKjT7C2E70NnQT0s8MVuQu4AAACAGUBAQQVA/oAFQArAHiyECwtERI5sBAQsBzQALAZL7AD0LADL7AI0LAIL7ADELAK0LAIELINAQorWCHYG/RZsAMQshIBCitYIdgb9FmwDRCwFdCwGRCwHtCwHi+wGRCwINCwHhCyIwEKK1gh2Bv0WbAZELIoAQorWCHYG/RZsCMQsCvQMDETNjYzNhcXFjMyNxUGIyInJyYHIgYHFTY2MzYXFxYzMjcVBiMiJycmByIGB2UwhEJSTJxGUYRlZn9RRphPVEKHMDCAQlRPmEZRh2Vmg1FGnExSQoQwA44yOAIiTiB+2WogTCQCQjzLMjgCJEwgftlqIE4iAkI8AAEAkQCAA+8EwwATADcAsBMvsgABCitYIdgb9FmwBNCwExCwB9CwExCwD9CwDy+yEAEKK1gh2Bv0WbAI0LAPELAL0DAxASEHJzcjNSE3ITUhNxcHMxUhByED7/3igG1dsAEhfv5hAhCGbmO9/tF9AawBZOQ+psnfyu0+r8rf//8APAATA40EawBnACAAAACLQAA5mgAHAZf/nv2m//8AgAATA+AEawBnACIAAACLQAA5mgAHAZf/4v2mAAIAJAAAA+sFsAAFAAkAOLIGCgsREjmwBhCwBNAAsABFWLAALxuxAB8+WbAARViwAy8bsQMPPlmyBgADERI5sggAAxESOTAxATMBASMBAQMTEwGkxAGD/oDF/n4B4e3y7AWw/Sf9KQLXAdb+Kv4pAdcA//8AoQCrAbwFBwAnABIAGgC2AQcAEgAaBAcACQCwAC+wEdwwMQAAAgBjAn8CPgQ5AAMABwAqsgAICRESObAF0ACwAi+wAEVYsAYvG7EGGz5ZsgAIAhESObAAL7AE0DAxASMRMwEjETMBAJ2dAT6dnQJ/Abr+RgG6AAEARf9nAVoBBgAIAAwAsAQvsADQsAAvMDEXJzY3NTMVBgbFgEkDyQFTmU1ze2RPXbr//wAtAAAFGgYVACYASgAAAAcASgJEAAAAAgAYAAAEFwYVABcAGwBzsgkcHRESObAJELAZ0ACwAEVYsAkvG7EJIT5ZsABFWLAELxuxBBs+WbAARViwGi8bsRobPlmwAEVYsBcvG7EXDz5ZsABFWLAZLxuxGQ8+WbAEELAT0LIWAQorWCHYG/RZsAHQsAkQsg8BCitYIdgb9FkwMTMRIzUzNT4CMzIWFwcmIyIGFRUzFSMRISMRM72lpQFqwohQk08linJvZNXVAmfz8wOGtEp/tlwiGskwYWFEtPx6BDoAAQAtAAAELAYVABYAY7ISFxgREjkAsABFWLASLxuxEiE+WbAARViwDi8bsQ4bPlmwAEVYsAkvG7EJDz5ZsABFWLAWLxuxFg8+WbASELICAQorWCHYG/RZsA4QsAXQsA4QsgsBCitYIdgb9FmwCNAwMQEmIyIVFTMVIxEjESM1MzU2NjMyBREjAzlmSsTc3POlpQHXxHoBRPMFPw64W7T8egOGtGG3wzD6GwACAC0AAAaTBhUAKAAsALWyFC0uERI5sBQQsCrQALAARViwCC8bsQghPlmwAEVYsBYvG7EWIT5ZsABFWLArLxuxKxs+WbAARViwIS8bsSEbPlmwAEVYsBEvG7ERGz5ZsABFWLAELxuxBBs+WbAARViwKC8bsSgPPlmwAEVYsCUvG7ElDz5ZsABFWLAqLxuxKg8+WbAhELIiAQorWCHYG/RZsCbQsAHQsAgQsg0BCitYIdgb9FmwFhCyHAEKK1gh2Bv0WTAxMxEjNTM1NDYzMhcHJiMiFRUhNT4CMzIWFwcmIyIGFRUzFSMRIxEhESEjETPSpaXItEBIBig1rgF0AWrCiFCTTyaIc29k1dXz/owEzvPzA4a0Y7TEEr4Is2BKf7ZcIhrJMGFhRLT8egOG/HoEOgABAC0AAAaTBhUAJwClshMoKRESOQCwAEVYsBUvG7EVIT5ZsABFWLAILxuxCCE+WbAARViwBC8bsQQbPlmwAEVYsBAvG7EQGz5ZsABFWLAfLxuxHxs+WbAARViwJy8bsScPPlmwAEVYsCQvG7EkDz5ZsABFWLAZLxuxGQ8+WbAEELIBAQorWCHYG/RZsAgQsg0BCitYIdgb9FmwFRCyHAEKK1gh2Bv0WbABELAm0LAi0DAxMxEjNTM1NDYzMhcHJiMiFRUhNTY2MzIFESMRJiMiFRUzFSMRIxEhEdKlpci0QEgGKDWuAXQB18R6AUTzZkrE3Nzz/owDhrRjtMQSvgizYGG3wzD6GwU/DrhbtPx6A4b8egABAC3/7ATRBhUAJACFshMlJhESOQCwAEVYsA8vG7EPGz5ZsABFWLAaLxuxGhs+WbAARViwIy8bsSMbPlmwAEVYsAovG7EKDz5ZsCMQsgAHCitYIdgb9FmwChCyBQEKK1gh2Bv0WbAAELAN0LAO0LAjELIfAQorWCHYG/RZshMBCitYIdgb9FmwDhCwGNCwGdAwMQEjERQWMzI3FQYjIBERIzUzNSYjIhURIxEjNTM1NDYzMhYXETMEy78xPyYvU03+6LKyRWyj86WlwrBl8XK/A4b9pD43CrwXATUCZbT4ILn7ZwOGtGK2wzgx/o4AAQBL/+wGgAYYAEwAp7JGTU4REjkAsABFWLBHLxuxRyE+WbAARViwQC8bsUAbPlmwAEVYsA8vG7EPGz5ZsABFWLBLLxuxSxs+WbAARViwCS8bsQkPPlmwAEVYsCwvG7EsDz5ZsEsQsgAHCitYIdgb9FmwCRCyBAEKK1gh2Bv0WbAAELAN0LAO0LBHELIUBworWCHYG/RZsEAQsiAHCitYIdgb9FmwLBCyNAcKK1gh2Bv0WTAxASMRFDMyNxUGIyImJxEjNTM1NCYjIgYVFB4CFSM0JiMiBhUUFgQWFhUUBiMiJiY1MxYWMzI2NTQmJicmNTQ2MzIXJjU0NjMyFhUVMwZ5v3EmL1NNh5ABrKxgWE9YHSEc9GhWUGVeAR6jT/LEhdB07AV4Y2Bka/hTtuy2W00t2a7J3r8Dhv23iAq8F6qiAk60WGJpVEU6aWZ5TUZdSj44Pj9XeleStWCoYVZdSTtBRDQoWKeMvBdsT4GlysVPABYAWf5yB+wFrgANABoAKAA3AD0AQwBJAE8AVgBaAF4AYgBmAGoAbgB2AHoAfgCCAIYAigCOAcCyEI+QERI5sBAQsADQsBAQsBvQsBAQsDDQsBAQsDzQsBAQsD7QsBAQsEbQsBAQsErQsBAQsFDQsBAQsFfQsBAQsFvQsBAQsGHQsBAQsGPQsBAQsGfQsBAQsG3QsBAQsHDQsBAQsHfQsBAQsHvQsBAQsH/QsBAQsITQsBAQsIjQsBAQsIzQALA9L7AARViwRi8bsUYfPlmyfUQDK7J8eQMrsniBAyuygDkDK7IKRj0REjmwCi+wA9CwAy+wDtCwDi+wChCwD9CwDy+ybw4PERI5fLBvLxiyUAsKK1gh2Bv0WbIVUG8REjmwChCyHgsKK1gh2Bv0WbADELIlCworWCHYG/RZsA8QsCnQsCkvsA4QsC7QsC4vsjQLCitYIdgb9FmwPRCwa9CwZ9CwY9CwPtCyPwwKK1gh2Bv0WbBl0LBp0LBt0LA80LA5ELBB0LBGELJHDAorWCHYG/RZsFvQsFfQsErQsEYQsGDQsFzQsFjQsEvQsEQQsE7QsA4QslELCitYIdgb9FmwRxCwX9CwDxCydgsKK1gh2Bv0WbB4ELCE0LB5ELCF0LB8ELCI0LB9ELCJ0LCAELCM0LCBELCN0DAxARQGIyImJzU0NjMyFhcTETMyFhUUBxYWFRQjATQmIyIGFRUUFjMyNjUBMxEUBiMiJjUzFDMyNjUBETMVMxUhNTM1MxEBESEVIxUlNSERIzUBFTMyNTQnEzUhFSE1IRUhNSEVATUhFSE1IRUhNSEVEzMyNTQmIyMBIzUzNSM1MxEjNTMlIzUzNSM1MxEjNTMDN4FkZoACfmhlgAJDvGJyVDI00P6PSkFASkpCQEkDulxpUlhtXWgpNvnEccQFKMdv+G0BNcQF7AE2b/xcfmdiywEW/VsBFf1cARQCCgEW/VsBFf1cARS8XXY6PF388XFxcXFxcQcib29vb29vAdRieXhedV98eF7+swIlSU1UIA1GLZsBSEVOTkVwRU5ORQFP/oZOXVFTWzYs/MkBO8pxccr+xQYfAR10qal0/uOp/LapU1IEA0p0dHR0dHT5OHFxcXFxcQPEUCke/tP8fvr8Ffl+/H76/BX5AAUAXP3VB9cIcwADABwAIAAkACgATACwIS+wJS+wANCwAC+wIRCwAtCwAi+yIAIAERI5sCAvsB3QsB0vsATQsAQvsg0AAhESObANL7AU0LAUL7IHBBQREjmyGRQEERI5MDEJAwU0Njc2NjU0JiMiBgczNjYzMhYVFAcGBhUXIxUzAzMVIwMzFSMEGAO//EH8RAQPHiRKXKeVkKACywI6Kzk4XVsvysrKSwQEAgQEBlL8MfwxA8/xOjoYJ4dKgJeLfzM0QDRfPEFcTFuq/UwECp4EAAEAOgAAA+oFsAAGADIAsABFWLAFLxuxBR8+WbAARViwAS8bsQEPPlmwBRCyAwEKK1gh2Bv0WbIAAwUREjkwMQEBIwEhNSED6v3U9AIs/UQDsAUp+tcE7cMAAAIAT/5WBBcETgAbACYAg7IfJygREjmwHxCwDNAAsABFWLAELxuxBBs+WbAARViwBy8bsQcbPlmwAEVYsAwvG7EMET5ZsABFWLAYLxuxGA8+WbIGBBgREjmwDBCyEgEKK1gh2Bv0WbIQEhgREjmyFgQYERI5sBgQsh8BCitYIdgb9FmwBBCyJAEKK1gh2Bv0WTAxEzQ2NjMyFzczERQAIyImJzcWMzI2NTUGIyImJjcUFjMyNxEmIyIGT23Nhb9pENH+++9VuUk1gpCOg2quf8xy8494lUZFlHyNAiag+42Gcvwc9v72Ly2wTJybFneM/J2fwIEB2XvBAAAB/7D+SwGOAM0ADQAusgMODxESOQCwDi+wAEVYsAUvG7EFET5ZsgoBCitYIdgb9FmwDhCwDdCwDS8wMSURFAcGIyInNxYzMjURAY5wW5VGOA4kPXzN/vfIYk8RxgyyAQUAAAEAXP6aAU8AtQADABIAsAQvsALQsAIvsAHQsAEvMDEBIxEzAU/z8/6aAhsAAgB1BNAC9wbcAAwAIAB7ALADL7AG0LAGL0ALDwYfBi8GPwZPBgVdsAMQsgkGCitYIdgb9FmwBhCwDNCwDC+wBhCwENCwEC+wE9CwEy9ADQ8THxMvEz8TTxNfEwZdsBAQsBbQsBYvsBMQshoICitYIdgb9FmwEBCyHQgKK1gh2Bv0WbAaELAg0DAxARQGICY1MxQWMzI2NRMUBiMiJiMiBhUnNDYzMhYzMjY1Avew/t6wr0xGSEqQX0c4gSofKmhhRS+ILB4sBbBle3tlNTo8MwEPS2tHMiUbTWxHMiQAAgB1BNUC9gcIAA0AHABZALADL7AH0LAHL0ALDwcfBy8HPwdPBwVdsAMQsgoGCitYIdgb9FmwBxCwDdCwDS+wBxCwDtCwDi+wFNCwFC+yDw4UERI5shUMCitYIdgb9FmyGw4PERI5MDEBFAYjIiY1MxQWMzI2NScnNjY1NCM3MhYVFAYHBwL2r5GSr61QREVN3whIP5IHnp9ORAEFsGJ5eWI0OTozGXYCFxo2YFBELzoIOgAAAgB1BNMDAAZ+AA0AEQBdALADL7AG0LAGL0ALDwYfBi8GPwZPBgVdsAMQsgoGCitYIdgb9FmwBhCwDdCwDS+wBhCwENCwEC+wDtCwDi9ADw8OHw4vDj8OTw5fDm8OB12wEBCwEdAZsBEvGDAxARQGIyImNTMUFjMyNjUnMwcjAwCvlpWxsUxJR0xltqmABbBhfHpjNDw8NM7AAAIAdQTnA1wG0QAGABoAjQCwAS+wA9CwAy+wBNAZsAQvGLAA0BmwAC8YsAMQsAXQsAUvQAkPBR8FLwU/BQRdsgIFAxESObAK0LAKL0AJPwpPCl8KbwoEXbAN0LANL0APDw0fDS8NPw1PDV8Nbw0HXbAKELAQ0LAQL7ANELIUBgorWCHYG/RZsAoQshcGCitYIdgb9FmwFBCwGtAwMQEjJwcjJTM3FAYjIiYjIgYVJzQ2MzIWMzI2NQNcwbOywQEqk7pZPTF7JBspWlk8Kn8mGiwE546O7d8+X0IsGxhAYEEtHAACAHUE5wQKBssABgAVAGAAsAEvsAPQsAMvsATQGbAELxiwANAZsAAvGLADELAF0LAFL0AJDwUfBS8FPwUEXbICAwUREjmwARCwB9CwBy+wDdCwDS+yCAcNERI5sg4GCitYIdgb9FmyFAgHERI5MDEBIycHIyUzFyc2NjU0IzcyFhUUBgcHA1zBs7LBARa7uQc/OIEHiYxJOAEE56Ki+nR9BRgdPmlZSzdBBzsAAv9MBNoDXAaDAAYACgBbALADL7AE0BmwBC8YsADQGbAALxiwAxCwAdCwAS+wBtCwBi9ACQ8GHwYvBj8GBF2yAgMGERI5sAMQsAjQsAgvsAfQGbAHLxiwCBCwCtCwCi+2DwofCi8KA10wMQEjJwcjJTMFIwMzA1zVn5/UASOh/oed190E2o6O+lwBCwACAHoE5wSLBpAABgAKAFsAsAMvsAXQsAUvsADQsAAvQAkPAB8ALwA/AARdsAMQsALQGbACLxiyBAMAERI5sAbQGbAGLxiwAxCwCdCwCS+wB9CwBy+2DwcfBy8HA12wCRCwCtAZsAovGDAxATMFIycHIwEzAyMBnaEBI9Sfn9UDM97YnQXh+o6OAan+9QAAAgB1BNQDAAZ+AA0AEQBdALADL7AG0LAGL0ALDwYfBi8GPwZPBgVdsAMQsgoGCitYIdgb9FmwBhCwDdCwDS+wBhCwEdCwES+wDtCwDi9ADw8OHw4vDj8OTw5fDm8OB12wERCwENAZsBAvGDAxARQGIyImNTMUFjMyNjUlMxcjAwCvlpWxsUxJR0z+lLdygAWxYXx6YzQ8PDTNwAAAAQCUBGkBqQYrAAgAHbIICQoREjkAsABFWLAALxuxACE+WbAE0LAELzAxARcGBwcjNTQ2ASaDPwIB01UGK1NtfIaFWbYAAAIACQAABJQEjQAHAAoARgCwAEVYsAQvG7EEHT5ZsABFWLACLxuxAg8+WbAARViwBi8bsQYPPlmyCQQCERI5sAkvsgABCitYIdgb9FmyCgQCERI5MDElIQcjATMBIwEhAwM//h5f9QHX3wHV9v4GAVSq+fkEjftzAbIBugADAHYAAAQKBI0ADgAWAB8ApLIeICEREjmwHhCwAtCwHhCwEdAAsABFWLABLxuxAR0+WbAARViwAC8bsQAPPlmyFwEAERI5sBcvtK8XvxcCXbRvF38XAnGy/xcBcbIPFwFytI8XnxcCcrJfFwFyss8XAXGyPxcBcbQfFy8XAl20vxfPFwJysg8BCitYIdgb9FmyCA8XERI5sAAQshABCitYIdgb9FmwARCyHgEKK1gh2Bv0WTAxMxEhMhYVFAYHFhYVFAYjAxEzMjY1NCcnMzY2NTQmIyN2Aa/e61lbYHDi3eLkZmS0+tRbY2dlxgSNpZxPgyMXj2OjqwH7/sdVQZ4FqgJIRU9GAAABAE//8ARDBJ0AGwBOsgMcHRESOQCwAEVYsAsvG7ELHT5ZsABFWLADLxuxAw8+WbIPCwMREjmwCxCyEgEKK1gh2Bv0WbADELIYAQorWCHYG/RZshsDCxESOTAxAQYEIyIAETU0NjYzMgQXIyYmIyARFRQWMzI2NwRCEf732ez+7H7snNYBBBTzDH1y/u2Gh3h8DQGEv9UBLAELRKn/itrCcGn+jki5tWJwAAIAdgAABCoEjQALABMARrITFBUREjmwExCwAtAAsABFWLABLxuxAR0+WbAARViwAC8bsQAPPlmwARCyDAEKK1gh2Bv0WbAAELINAQorWCHYG/RZMDEzESEyBBYXFRQGBCMDETMgEzUQJXYBe6QBA5ACj/75qIOCAUcG/skEjYr7nz2j/osDyfz5AVxDAWAIAAEAdgAAA7UEjQALAE4AsABFWLAGLxuxBh0+WbAARViwBC8bsQQPPlmyCwYEERI5sAsvsgABCitYIdgb9FmwBBCyAgEKK1gh2Bv0WbAGELIIAQorWCHYG/RZMDEBIREhFSERIRUhESEDX/4KAkz8wQM8/bcB9gH4/srCBI3E/vIAAQB2AAADngSNAAkAQACwAEVYsAQvG7EEHT5ZsABFWLACLxuxAg8+WbIJBAIREjmwCS+yAAEKK1gh2Bv0WbAEELIGAQorWCHYG/RZMDEBIREjESEVIREhA1v+DvMDKP3LAfIB2/4lBI3E/tUAAQBU//AESASdABwAXLIaHR4REjkAsABFWLAKLxuxCh0+WbAARViwAy8bsQMPPlmyDgMKERI5sAoQshEBCitYIdgb9FmwAxCyFwEKK1gh2Bv0WbIbAwoREjmwGy+yGQcKK1gh2Bv0WTAxJQcGISIAETUQADMyFhcjJiYjIBEVFBYgNzUjNSEESBeW/tX4/twBFvTX+hntEnls/uSgAShG+QHrkxiLAS4BCUEBCQEsw8BkXP6JQLe6OcixAAABAHYAAARoBI0ACwCGALAARViwBi8bsQYdPlmwAEVYsAovG7EKHT5ZsABFWLAALxuxAA8+WbAARViwBC8bsQQPPlmyCQYAERI5sAkvtK8JvwkCXbI/CQFxss8JAXGyPwkBcrL/CQFxsg8JAXK0bwl/CQJxtN8J7wkCXbJfCQFytBwJLAkCXbICAQorWCHYG/RZMDEhIxEhESMRMxEhETMEaPP99PPzAgzzAdv+JQSN/hEB7wABAIUAAAF3BI0AAwAdALAARViwAi8bsQIdPlmwAEVYsAAvG7EADz5ZMDEhIxEzAXfy8gSNAAABACT/8ANkBI0ADgAisgUPEBESOQCwAEVYsAUvG7EFDz5ZsgsBCitYIdgb9FkwMQEzERQGIyImNTMUMzI2NQJx8+OyyuH0t0tXBI384K7PwK+tXl0AAAEAdgAABGgEjQAMAEsAsABFWLAELxuxBB0+WbAARViwCC8bsQgdPlmwAEVYsAIvG7ECDz5ZsABFWLALLxuxCw8+WbIGAgQREjmwBhCwAdCyCgEGERI5MDEBBxEjETMRNwEhAQEhAfCH8/NuAU8BLP5DAdP+3gHbg/6oBI39/YYBff33/XwAAQB2AAADlASNAAUAKACwAEVYsAQvG7EEHT5ZsABFWLACLxuxAg8+WbIAAQorWCHYG/RZMDElIRUhETMBaQIr/OLzwsIEjQAAAQB2AAAFjwSNAA4AYLIBDxAREjkAsABFWLAALxuxAB0+WbAARViwAi8bsQIdPlmwAEVYsAQvG7EEDz5ZsABFWLAILxuxCA8+WbAARViwDC8bsQwPPlmyAQAEERI5sgcABBESObIKAAQREjkwMQkCIREjERMBIwETESMRAbIBUQFOAT7yGf6gqP6hGfIEjfy1A0v7cwE7Ajr8iwNw/cv+xQSNAAABAHYAAARnBI0ACQBFALAARViwBS8bsQUdPlmwAEVYsAgvG7EIHT5ZsABFWLAALxuxAA8+WbAARViwAy8bsQMPPlmyAgUAERI5sgcFABESOTAxISMBESMRMwERMwRn8v308/MCDPIDG/zlBI385AMcAAACAE//8ARvBJ0ADgAcAEayAx0eERI5sAMQsBLQALAARViwCy8bsQsdPlmwAEVYsAMvG7EDDz5ZsAsQshIBCitYIdgb9FmwAxCyGQEKK1gh2Bv0WTAxARAAIyIAETU0EjYzMgARJzQmIyIGFRUUFjMyNjUEb/7f7ez+2oXwm/ABIPKWiIaYmYeIlAIs/vj+zAE1AQwurAEHi/7H/vUIt8DAtzWyx8O2AAACAHYAAAQsBI0ACgATAE2yBBQVERI5sAQQsAzQALAARViwAy8bsQMdPlmwAEVYsAEvG7EBDz5ZsgsBAxESObALL7IAAQorWCHYG/RZsAMQshIBCitYIdgb9FkwMQERIxEhMhYVFAYHJzMyNjU0JiMjAWnzAeXU/fHU/vJod3ll8wGZ/mcEjdWtqcYDxFhUV2kAAAIATP8wBGwEnQAUACIARrIIIyQREjmwCBCwH9AAsABFWLARLxuxER0+WbAARViwCC8bsQgPPlmwERCyGAEKK1gh2Bv0WbAIELIfAQorWCHYG/RZMDEBFAYHFwclBiMiJgInNTQSNjMyABEnNCYjIgYVFRQWMzI2NQRsbmPPnf72MjSa8oQBgvGc7wEi8ZeJhpeXiImVAiyj8UiYiMkJiwEBqjmrAQWO/sj+9Ai3wMO2M7DJw7YAAgB2AAAEOQSNAA0AFgBhsgUXGBESObAFELAP0ACwAEVYsAQvG7EEHT5ZsABFWLACLxuxAg8+WbAARViwDS8bsQ0PPlmyDgIEERI5sA4vsgABCitYIdgb9FmyCgAOERI5sAQQshUBCitYIdgb9FkwMQEjESMRITIWFRQHARUhATMyNjU0JiMjAkjf8wHI2vDhARL+/P401WxsaW/VAan+VwSNt6rrW/4lCwJrX05RYAABAD7/8APvBJ0AJQBjsgkmJxESOQCwAEVYsAkvG7EJHT5ZsABFWLAcLxuxHA8+WbIDHAkREjmyDQkcERI5sAkQshABCitYIdgb9FmwAxCyFQEKK1gh2Bv0WbIhHAkREjmwHBCyIwEKK1gh2Bv0WTAxATQmJCYmNTQ2MzIWFSM0JiMiBhUUFhcWFhUUBiMiJiY1MxQhMjYDAmj+z7BT9sPS/vN4ZV9ucY/dwPjMiuV+9AEAYW8BMkJPTGKDXJK7yKBRXU1AOkwjNrKOma5dqnHASgABACQAAAQWBI0ABwAuALAARViwBi8bsQYdPlmwAEVYsAIvG7ECDz5ZsAYQsgABCitYIdgb9FmwBNAwMQEhESMRITUhBBb+fvP+gwPyA8n8NwPJxAABAGf/8AQeBI0ADwA1sgwQERESOQCwAEVYsAgvG7EIHT5ZsABFWLAELxuxBA8+WbIMAQorWCHYG/RZsAgQsA/QMDEBERQEICQ1ETMRFBYzMjcRBB7+//5K/wDxfmzlBASN/QG+4N3BAv/9AHNo1AMHAAABAAkAAARyBI0ACAAxALAARViwAy8bsQMdPlmwAEVYsAcvG7EHHT5ZsABFWLAFLxuxBQ8+WbIBAwUREjkwMQEXNwEhASMBIQIqExIBIgEB/kb2/kcBAQE4TUsDV/tzBI0AAAEAKAAABeUEjQAMAFkAsABFWLABLxuxAR0+WbAARViwCC8bsQgdPlmwAEVYsAsvG7ELHT5ZsABFWLADLxuxAw8+WbAARViwBi8bsQYPPlmyAAEDERI5sgUBAxESObIKAQMREjkwMQETMwEjAwMjATMTEzMESq/s/ubr2Nvr/ubssdjWASsDYvtzA0H8vwSN/JwDZAABABUAAARKBI0ACwBTALAARViwAS8bsQEdPlmwAEVYsAovG7EKHT5ZsABFWLAELxuxBA8+WbAARViwBy8bsQcPPlmyAAEEERI5sgYBBBESObIDAAYREjmyCQYAERI5MDEBEyEBASEDAyEBASECJ/IBHP6JAYz+4P/6/uQBgf6IARoC+gGT/b79tQGZ/mcCSwJCAAEABQAABDYEjQAIADEAsABFWLABLxuxAR0+WbAARViwBy8bsQcdPlmwAEVYsAQvG7EEDz5ZsgABBBESOTAxAQEhAREjEQEhAh0BDgEL/l3y/mQBCwJ6AhP9B/5sAaEC7AAAAQBBAAAD8wSNAAkARACwAEVYsAcvG7EHHT5ZsABFWLACLxuxAg8+WbIAAQorWCHYG/RZsgQAAhESObAHELIFAQorWCHYG/RZsgkFBxESOTAxJSEVITUBITUhFQF4Anv8TgJs/ZUDoMLCjQM8xIoAAAIAS//1AqoDIAANABcARrIDGBkREjmwAxCwENAAsABFWLAKLxuxChk+WbAARViwAy8bsQMPPlmwChCyEAIKK1gh2Bv0WbADELIVAgorWCHYG/RZMDEBFAYjIiY1NTQ2MzIWFSc0IyIHFRQzMjcCqp6Qkp+ekZCgu3VyA3dvBAE+n6qqnpidrq2eDKmfuKmaAAEAgAAAAgIDEwAGADEAsABFWLAFLxuxBRk+WbAARViwAS8bsQEPPlmwBRCwBNCwBC+yAwIKK1gh2Bv0WTAxISMRBzUlMwICuckBbxMCOjCSdwABADwAAAKyAyAAFwBZsggYGRESOQCwAEVYsA8vG7EPGT5ZsABFWLAALxuxAA8+WbIWAgorWCHYG/RZsgIWABESObIDDwAREjmwDxCyCAIKK1gh2Bv0WbIMAA8REjmyFQAPERI5MDEhITUBNjU0JiMiBhUjNDYzMhYVFA8CIQKy/ZwBHXE2NDpCuqmHj5xqYowBc30BBWdDKjVCNnSZgHNrZldxAAEAN//1AqkDIAAkAH+yHiUmERI5ALAARViwDS8bsQ0ZPlmwAEVYsBcvG7EXDz5ZsgAXDRESOXywAC8YtFAAYAACcbaAAJAAoAADXbANELIGAgorWCHYG/RZsgoABhESObAAELIkAgorWCHYG/RZshIkABESObAXELIeAgorWCHYG/RZshskHhESOTAxATMyNTQmIyIGFSM0NjMyFhUUBxYVFAYjIiY1MxQWMzI2NTQnIwEMUYQ2PjBBuqWCj6OHlbGPh6u6RTw/PYZcAdJhIzUnI2N8eWl3MymOan5/cSY1NyplAQAAAgA1AAACvgMVAAoADgBJALAARViwCS8bsQkZPlmwAEVYsAQvG7EEDz5ZsgEJBBESObABL7ICAgorWCHYG/RZsAbQsAEQsAvQsggLBhESObINCQQREjkwMQEzFSMVIzUhJwEzATM1BwJfX1+7/poJAW29/ou6DgE6l6OjeQH5/iXyFgAAAQBP//UCrgMVABoAarINGxwREjkAsABFWLACLxuxAhk+WbAARViwDS8bsQ0PPlmwAhCyAwIKK1gh2Bv0WbIHAg0REjmwBy+yGAIKK1gh2Bv0WbIFGAcREjmwDRCyEwIKK1gh2Bv0WbIRExgREjmyGhgTERI5MDETEyEVIQc2MzIWFRQGIyImJzMWMzI1NCYjIgdiNAHs/qwUPkeDjKOMga0CuQVydUNCQzUBfwGWlpQbhnp4mYRjUn04RCgAAAIATf/1ArkDIgATAB4AW7IUHyAREjmwFBCwDNAAsABFWLAALxuxABk+WbAARViwDC8bsQwPPlmwABCyAQIKK1gh2Bv0WbIGDAAREjmwBi+yFAIKK1gh2Bv0WbAMELIaAgorWCHYG/RZMDEBFSIGBzYzMhYVFAYjIiY1NTQ2MwMiBgcVFDMyNjU0AjKRiQ1Ha3WHqIaTq/Deli1CD381RAMimV9iRY56d5mnmzHS6P5XJBckkUY2dAABADYAAAKuAxUABgAyALAARViwBS8bsQUZPlmwAEVYsAIvG7ECDz5ZsAUQsgQCCitYIdgb9FmyAAQFERI5MDEBASMBITUhAq7+rcQBU/5MAngCrP1UAn+WAAADAEv/9QKqAyAAEwAcACQAlrIHJSYREjmwBxCwFNCwBxCwItAAsABFWLARLxuxERk+WbAARViwBy8bsQcPPlmyIgcRERI5fLAiLxi2gCKQIqAiA120UCJgIgJxtAAiECICcbRAIlAiAl200CLgIgJxshkCCitYIdgb9FmyAiIZERI5sgwZIhESObAHELIUAgorWCHYG/RZsBEQsh8CCitYIdgb9FkwMQEUBxYVFAYjIiY1NDcmNTQ2MzIWATI2NCYiBhQWEzQiFRQWMjYCl3GEoY6MpIRxm4GCm/7kNUBBakBAl8QzYDECQXQ3PYBqenlrgD03dGl2dv3gM1owMFozAatWVicwMAACAEb/9wKjAyAAEwAfAGCyFCAhERI5sBQQsAjQALAARViwCC8bsQgZPlmwAEVYsBAvG7EQDz5ZsgIQCBESOXywAi8YsBAQshECCitYIdgb9FmwAhCyFAIKK1gh2Bv0WbAIELIaAgorWCHYG/RZMDEBBiMiJjU0NjMyFhcVFAYHIzUyNicyNzU0JiMiBhUUFgHnQlp+h6qEi6IC3OATj3ljTiNCNDNBPAE2OYp9eKSmlzvX2QGTUqw0RUhBTjk3RAABAJAChwMtAzEAAwARALACL7IBAQorWCHYG/RZMDEBITUhAy39YwKdAoeqAAMAlgRIAqIGlQADAA8AGwBOALANL7AZ0LAZL7IHCQorWCHYG/RZsALQsAIvsADQsAAvQA8PAB8ALwA/AE8AXwBvAAddsAIQsAPQGbADLxiwDRCyEwkKK1gh2Bv0WTAxATMHIwc0NjMyFhUUBiMiJjcUFjMyNjU0JiMiBgG85vWVgm5OTGxpT1FrYzQlJDAwJCU0BpXC3k5kZU1KY2JLJTExJSczMwADAAr+SgQbBE4AKQA2AEMAm7IIREUREjmwCBCwMNCwCBCwOtAAsABFWLAmLxuxJhs+WbAARViwFi8bsRYRPlmwJhCwKNCwKC+yAAMKK1gh2Bv0WbIIFiYREjmwCC+yDxYIERI5sA8vsjUBCitYIdgb9FmyGzUPERI5sh8IJhESObAWELIwAQorWCHYG/RZsAgQsjoBCitYIdgb9FmwJhCyQQEKK1gh2Bv0WTAxASMWFRUUBgYjIicGFRQXMxYWFRQGBiMiJDU0NyY1NDcmJjU1NDYzMhchAQYGFRQWMzI2NTQnJQMUFjMyNjU1NCYiBhUEG4o6c86AUUUlc8LDyo/6mtn+9bYydVpk/MdVSwFx/TAkMYhyhqyT/upAellYd3W4dQOgVWkWZKlfEiMvSgMBmo5YpmKbeaVZMkh3UTGeXxaiyhT75RNIMEJNXkBrCQICs0tmZ04SSmZmTQACAFb/6wRfBE4AEAAdAG6yGx4fERI5sBsQsAnQALAARViwCS8bsQkbPlmwAEVYsAwvG7EMGz5ZsABFWLACLxuxAg8+WbAARViwEC8bsRAPPlmyAAkCERI5sgsJAhESObACELIUAQorWCHYG/RZsAkQshsBCitYIdgb9FkwMSUGIyICNTUQEjMyFzczAxMjARQWMzI2NzUmJiMiBgNjbvLH5ujH6XEc3Wxz3f3HfHRgfBcRfWNzf8TZASD0DwEKATbXw/3i/eQB+aCsq6YvpbnFAAACAJsAAATyBbAAFgAeAGGyGB8gERI5sBgQsATQALAARViwAy8bsQMfPlmwAEVYsAEvG7EBDz5ZsABFWLAPLxuxDw8+WbIXAwEREjmwFy+yAAEKK1gh2Bv0WbIJABcREjmwAxCyHQEKK1gh2Bv0WTAxAREjESEyFhUUBxYTFRQXFSEmJzU0JiMlITI2NTQhIQGX/AIp9f/35QVH/vw7BHtw/tMBFJCB/vj+4wJW/aoFsNnN42VF/vZzqT0aMbh5dIDKcW3mAAABAJsAAAUwBbAADABYALAARViwBC8bsQQfPlmwAEVYsAgvG7EIHz5ZsABFWLACLxuxAg8+WbAARViwCy8bsQsPPlmyBgIEERI5sAYvsh8GAXGyAQEKK1gh2Bv0WbIKAQYREjkwMQEjESMRMxEzASEBASECQ6z8/IsBrAE2/gwCIP7QAnD9kAWw/ZwCZP1H/QkAAAEAgQAABDUGAAAMAFMAsABFWLAELxuxBCE+WbAARViwCC8bsQgbPlmwAEVYsAIvG7ECDz5ZsABFWLALLxuxCw8+WbIHCAIREjmwBy+yAAEKK1gh2Bv0WbIKAAcREjkwMQEjESMRMxEzASEBASEB4m/y8mkBDwEc/p8Bj/7mAdn+JwYA/JwBnv4R/bUAAQCbAAAFEgWwAAsATACwAEVYsAMvG7EDHz5ZsABFWLAHLxuxBx8+WbAARViwAS8bsQEPPlmwAEVYsAovG7EKDz5ZsgADARESObIFAwEREjmyCQAFERI5MDEBESMRMxEzASEBASEBl/z8BgIZATj9pQJ//sgCmv1mBbD9fwKB/TX9GwAAAQCBAAAEIgYYAAoATACwAEVYsAMvG7EDIT5ZsABFWLAGLxuxBhs+WbAARViwAS8bsQEPPlmwAEVYsAkvG7EJDz5ZsgAGARESObIFBgEREjmyCAAFERI5MDEBESMRMxEBIQEBIQFz8vIBWQEq/lAB3P7bAev+FQYY/IQBnv4M/boAAAEAPv8TA+8FcwAqAG+yEyssERI5ALAARViwCS8bsQkdPlmwAEVYsCIvG7EiDz5ZsgMiCRESObAJELAM0LADELIYAQorWCHYG/RZsAkQshMBCitYIdgb9FmyEBgTERI5sCIQsB/QsCIQsigBCitYIdgb9FmyJgMoERI5MDEBNCYkJiY1NDY3NTMVFhYVIzQmIyIGFRQWFxYWFRQGBxUjNSYmNTMUITI2AwJo/s+wU8+poKbL83hlX25xj93Aw66gveP0AQBhbwEyQk9MYoNchrQQ2dwVwI1RXU1AOkwjNrKOhqwR4eETx5rASgAAAQA4AAAEGgSdAB8AbrIbICEREjkAsABFWLATLxuxEx0+WbAARViwBS8bsQUPPlmyHxMFERI5sB8vsgACCitYIdgb9FmwBRCyAwEKK1gh2Bv0WbAH0LAI0LAAELAM0LAfELAO0LATELIaAQorWCHYG/RZshcfGhESOTAxASEWByEHITUzNjYnJyM1MycmNjMyFhUjNCYjIgYXFyEDR/6FBlACmAH8ZQopKwMBoJsDBti/wtnzV1BNVwUEAYAB5bJww8MLk30Hk2nO7tS8YWp+eWkAAQAOAAAEPwSNABgAlbIAGRoREjkAsABFWLABLxuxAR0+WbAARViwGC8bsRgdPlmwAEVYsAwvG7EMDz5ZsgAMGBESObIJDAEREjmwCS+wBNCwBC9ADQ8EHwQvBD8ETwRfBAZdts8E3wTvBANdsgYCCitYIdgb9FmwCRCyCgIKK1gh2Bv0WbAO0LAJELAQ0LAQL7AGELAT0LAEELAW0LAWLzAxAQEhATMVIQcVIRUhFSM1ITUhNSchNTMBIQIlAQ8BC/6+1f7aEAE2/sry/soBNgn+09z+vgELAnoCE/23kx0qkdnZkTYRkwJJAAABAHYAAAOXBI0ABQAysgEGBxESOQCwAEVYsAQvG7EEHT5ZsABFWLADLxuxAw8+WbAEELIAAQorWCHYG/RZMDEBIREjESEDl/3S8wMhA8n8NwSNAAACAAkAAARyBI0AAwAIADyyBQkKERI5sAUQsALQALAARViwAi8bsQIdPlmwAEVYsAAvG7EADz5ZsgUAAhESObIHAQorWCHYG/RZMDEhIQEzAycHAyEEcvuXAbn2aRIT3gHjBI3+yUtN/W8AAwBP//AEbwSdAAMAEgAgAHayByEiERI5sAcQsAHQsAcQsBbQALAARViwDy8bsQ8dPlmwAEVYsAcvG7EHDz5ZsgMPBxESOXywAy8YtGADcAMCXbQwA0ADAl2yAAMBcbIAAQorWCHYG/RZsA8QshYBCitYIdgb9FmwBxCyHQEKK1gh2Bv0WTAxASE1IQUQACMiABE1NBI2MzIAESc0JiMiBhUVFBYzMjY1Azj+WgGmATf+3+3s/tqF8JvwASDyloiGmJmHiJQB38N2/vj+zAE1AQwurAEHi/7H/vUIt8DAtzWyx8O2AAABAAkAAARyBI0ACAA4sgcJChESOQCwAEVYsAIvG7ECHT5ZsABFWLAALxuxAA8+WbAARViwBC8bsQQPPlmyBwIAERI5MDEhIQEzASEBJwcBCv7/Abn2Abr+//7eEhMEjftzA1ZLTQADAEIAAANVBI0AAwAHAAsAXrIEDA0REjmwBBCwANCwBBCwCNAAsABFWLAKLxuxCh0+WbAARViwAC8bsQAPPlmyAgEKK1gh2Bv0WbIHCgAREjmwBy+yBAEKK1gh2Bv0WbAKELIIAQorWCHYG/RZMDEhITUhAyE1IRMhNSEDVfztAxNJ/X4Cgkn87QMTwwE4xAEKxAAAAQB2AAAEYgSNAAcAP7IBCAkREjkAsABFWLAGLxuxBh0+WbAARViwBC8bsQQPPlmwAEVYsAEvG7EBDz5ZsAYQsgIBCitYIdgb9FkwMSEjESERIxEhBGL0/fvzA+wDyfw3BI0AAAEARAAAA+YEjQAMAEuyAA0OERI5ALAARViwCC8bsQgdPlmwAEVYsAMvG7EDDz5ZsgEBCitYIdgb9FmyBQEDERI5sAgQsgoBCitYIdgb9FmyBwoIERI5MDEBASEVITUBATUhFSEBApD+5gJw/F4BP/7BA3z9ugEWAkX+f8SYAbcBppjE/o8AAwBQAAAFTQSNABEAFgAcAG+yCB0eERI5sAgQsBTQsAgQsBrQALAARViwEC8bsRAdPlmwAEVYsAgvG7EIDz5Zsg8QCBESObAPL7AA0LIJCBAREjmwCS+wBtCwCRCyFAEKK1gh2Bv0WbAPELIVAQorWCHYG/RZsBrQsBQQsBvQMDEBFgQVFAQHFSM1JiQ1NCQ3NTMBAgURBAU0JicRJANJ8AEU/unt8/D+6gEX7/P9+QQBGP7sAxmQggESBBUP9srQ+g9tbA/50M33DXj9t/79FQIqFfuFgQr91hUAAAEAUAAABQMEjQAYAEuyABkaERI5ALAARViwEi8bsRIdPlmwAEVYsAwvG7EMDz5ZshYMEhESObAWL7AA0LASELAX0LAE0LAWELINAQorWCHYG/RZsArQMDEBNjY1ETMRBgcGBxEjESYCAxEzERQWFxEzAyN/bvMBaH368+P7AvNwffMB3RjCpwEv/s3jk68d/ugBFxYBKgEAATb+0ajAGAKvAAEAXwAABIQEnQAjAFyyByQlERI5ALAARViwGS8bsRkdPlmwAEVYsA8vG7EPDz5ZsABFWLAiLxuxIg8+WbAPELIRAQorWCHYG/RZsA7QsADQsBkQsgcBCitYIdgb9FmwERCwINCwIdAwMSU2NjU1NCYjIgYVFRQWFxUhNTMmETU0NjYzMgAVFRQGBzMVIQKteGyUjYqUdnT+MLC9g/Kc6gEqY1m2/i/IIsmwK56sqaQosccjyMSbAScWkeyE/uPtGY3fSsQAAAEAJP/sBVIEjQAZAGuyFhobERI5ALAARViwAi8bsQIdPlmwAEVYsA4vG7EODz5ZsABFWLAYLxuxGA8+WbACELIAAQorWCHYG/RZsATQsAXQsggCDhESObAIL7AOELIPBworWCHYG/RZsAgQshUBCitYIdgb9FkwMQEhNSEVIRU2MzIWFRQGIzUyNjU0JiMiBxEjAX7+pgOt/qCKjdrw8OtzdnR1gYXzA8nExO4n1Ma8wL1UaXJnJv3nAAEAT//wBEMEnQAdAI+yAx4fERI5ALAARViwCy8bsQsdPlmwAEVYsAMvG7EDDz5Zsg8LAxESObALELISAQorWCHYG/RZshULAxESObAVL7L/FQFxsg8VAXKyPxUBcbLPFQFxtG8VfxUCcbSvFb8VAl2yXxUBcrKPFQFyshYBCitYIdgb9FmwAxCyGgEKK1gh2Bv0WbIdAwsREjkwMQEGBCMiABE1NDY2MzIEFyMmJiMiAyEVIRYWMzI2NwRCEf732ez+7H7snNYBBBTzDH1y+xYBgP6ACn6DeHwNAYS/1QEsAQtEqf+K2sJwaf7PxJSfYnAAAgAkAAAHFQSNABcAIAB2sgQhIhESObAEELAY0ACwAEVYsBIvG7ESHT5ZsABFWLADLxuxAw8+WbAARViwCy8bsQsPPlmwEhCyBQEKK1gh2Bv0WbALELIOAQorWCHYG/RZshQSAxESObAUL7IYAQorWCHYG/RZsAMQshkBCitYIdgb9FkwMQEUBgchESEDBgIGIyM3NzY2NxMhETMyFiURMzI2NTQmIwcV+c/+Ff6kDgtYrJE0ASZgTgwVAzvs2vr9QPFndXZmAX+r0gIDyf6c7/7/dc0CB5/tAiv+bNAM/o5rU1FjAAACAHYAAAcYBI0AEwAcAMGyAR0eERI5sAEQsBTQALAARViwEy8bsRMdPlmwAEVYsAIvG7ECHT5ZsABFWLAQLxuxEA8+WbAARViwDS8bsQ0PPlmyABATERI5sAAvtK8AvwACXbI/AAFxss8AAXGyPwABcrJfAAFysv8AAXGyDwABcrRvAH8AAnG03wDvAAJdtB8ALwACXbKfAAFysgQNAhESObAEL7AAELIPAQorWCHYG/RZsAQQshQBCitYIdgb9FmwDRCyFQEKK1gh2Bv0WTAxASERMxEzMhYWFRQGIyERIREjETMBETMyNjU0JiMBaQH98/KM0m//0v4f/gPz8wLw8Wd1dmYCngHv/mxfq3Cv0AHb/iUEjf2o/o5rU1FjAAABACQAAAVSBI0AFQBXshIWFxESOQCwAEVYsAMvG7EDHT5ZsABFWLAULxuxFA8+WbAARViwDS8bsQ0PPlmwAxCyBAEKK1gh2Bv0WbAA0LIIFAMREjmwCC+yEQEKK1gh2Bv0WTAxASE1IRUhFTYzMhYXESMRNCYjIgcRIwF+/qYDrf6gho7e6wTzdHSBhfMDycTE7SbPy/6YAVp8aSb95wAAAQB2/p8EYQSNAAsAT7IDDA0REjkAsAIvsABFWLAGLxuxBh0+WbAARViwCi8bsQodPlmwAEVYsAAvG7EADz5ZsABFWLAELxuxBA8+WbIIAQorWCHYG/RZsAnQMDEhIREjESERMxEhETMEYf6K8/5+8wIF8/6fAWEEjfw2A8oAAgB2AAAEKASNAAsAFABesggVFhESObAIELAM0ACwAEVYsAovG7EKHT5ZsABFWLAILxuxCA8+WbAKELIAAQorWCHYG/RZsgMKCBESObADL7AIELIMAQorWCHYG/RZsAMQshIBCitYIdgb9FkwMQEhFTMWFhAGIyERIQEyNjU0JicjEQOy/bf8z/T42f4fAzz+qGhzcGb2A8vgA8T+qMwEjfw2Y1RPXQH+nAACACf+rwUVBI0ADwAVAFuyExYXERI5sBMQsAXQALANL7AARViwBS8bsQUdPlmwAEVYsAsvG7ELDz5ZsgABCitYIdgb9FmwB9CwCNCwDRCwCtCwCBCwENCwEdCwBRCyEgEKK1gh2Bv0WTAxNz4CNxMhETMRIxEhESMTISERIQcCgkpCIwUMAz2W8vz38wEBdAHw/qEHDcNRhrR+AcH8Nv3sAVH+rwIUAwb8/q4AAQAaAAAGHwSNABUAnrIBFhcREjkAsABFWLARLxuxER0+WbAARViwDi8bsQ4dPlmwAEVYsAovG7EKHT5ZsABFWLAGLxuxBg8+WbAARViwAy8bsQMPPlmwAEVYsBUvG7EVDz5ZsgwDDhESObAML7I/DAFxsl8MAXKyzwwBcbSvDL8MAl20jwyfDAJysA/QsgEBCitYIdgb9FmwBNCyCA8EERI5shMBDxESOTAxASMRIxEjAyEBASETMxEzETMTIQEBIQP1X/Ng/P7TAVz+xAEe91TzVPcBHv7CAV7+0wHV/isB1f4rAlQCOf4gAeD+IAHg/dD9owAAAQBC//AD5wSdACcAirImKCkREjkAsABFWLAKLxuxCh0+WbAARViwFi8bsRYPPlmwChCyAwEKK1gh2Bv0WbIGChYREjmyJgoWERI5sCYvss8mAXGyPyYBcbSvJr8mAl2y/yYBcbIPJgFysl8mAXKyIwEKK1gh2Bv0WbIQIyYREjmyHBYKERI5sBYQsh4BCitYIdgb9FkwMQE0JiMiBhUjNDYzMhYVFAYHFhYVFAQjIiYnJjUzFjMyNjU0JyM1MzYC4nBrW2bz88PY9G5db27+/txdrz988wvKd3TglJrHA0NGT0Y8lLOnlluKJySRW5+1LS9bn5NXSKYDsAQAAQB2AAAEbgSNAAkATLIACgsREjkAsABFWLAALxuxAB0+WbAARViwCC8bsQgdPlmwAEVYsAUvG7EFDz5ZsABFWLADLxuxAw8+WbIEAwAREjmyCQUIERI5MDEBMxEjEQEjETMRA3vz8/3u8/MEjftzAyP83QSN/OAAAQB2AAAEQASNAAwAd7IADQ4REjkAsABFWLAILxuxCB0+WbAARViwBS8bsQUdPlmwAEVYsAIvG7ECDz5ZsABFWLAMLxuxDA8+WbIGAgUREjmwBi+yPwYBcbJfBgFyss8GAXG0rwa/BgJdtI8GnwYCcrIBAQorWCHYG/RZsgoBBhESOTAxASMRIxEzETMBIQEBIQHTavPzYwE4AR3+cgGt/tEB1f4rBI3+IAHg/cX9rgABACQAAARVBI0AEABNsgQREhESOQCwAEVYsAAvG7EAHT5ZsABFWLABLxuxAQ8+WbAARViwCS8bsQkPPlmwABCyAwEKK1gh2Bv0WbAJELIMAQorWCHYG/RZMDEBESMRIQMGAgYHIzc3NjY3EwRV8/6kDwxXqow6ASdiSgwWBI37cwPJ/p/t/v54Ac0EC6DmAisAAAEAH//sBDkEjQAPAEOyABARERI5ALAARViwDy8bsQ8dPlmwAEVYsAIvG7ECHT5ZsABFWLAILxuxCA8+WbIBCA8REjmyCwEKK1gh2Bv0WTAxARcTIQEOAiMnNxcyNwEhAikT8wEK/nA4Wn5aZgFXYDP+WwEOAks3Ann8fn5pOAXABGEDfwAAAQB2/q8FJASNAAsAQrIJDA0REjkAsAMvsABFWLAHLxuxBx0+WbAARViwCi8bsQodPlmwAEVYsAUvG7EFDz5ZsggBCitYIdgb9FmwANAwMSUzAyMRIREzESERMwRiwhTd/EPzAgX0w/3sAVEEjfw2A8oAAQBBAAAEFgSNABEARrIEEhMREjkAsABFWLAJLxuxCR0+WbAARViwEC8bsRAdPlmwAEVYsAEvG7EBDz5Zsg0BCRESObANL7IEAQorWCHYG/RZMDEhIxEGIyImJxEzERQWMzI3ETMEFvOGgerwAfNveYKF8wGqJtLRAWb+nndsJgIfAAEAdgAABg4EjQALAEGyBwwNERI5ALAARViwAy8bsQMdPlmwAEVYsAEvG7EBDz5ZsgQBCitYIdgb9FmwAxCwBtCwBBCwCNCwBhCwCtAwMSEhETMRIREzESERMwYO+mjzAV/zAWDzBI38NgPK/DYDygABAHb+rwbRBI0ADwBBsgsQERESOQCwAy+wAEVYsAcvG7EHHT5ZsABFWLAELxuxBA8+WbIAAQorWCHYG/RZsA3QsAnQsAcQsArQsA7QMDElMwMjESERMxEhETMRIREzBg/CFN36lvMBX/MBYPTD/ewBUQSN/DYDyvw2A8oAAgAKAAAFGwSNAAwAFQBesggWFxESObAIELAU0ACwAEVYsAcvG7EHHT5ZsABFWLADLxuxAw8+WbAHELIFAQorWCHYG/RZsgoHAxESObAKL7ADELINAQorWCHYG/RZsAoQshMBCitYIdgb9FkwMQEUBgchESE1IREzMhYBMjY1NCYnIxEFG/nP/hX+ogJS69v5/jJmdXFi+QF/q9ICA8nE/mzQ/pprU09jAv6O//8AdgAABakEjQAmAggAAAAHAcIEMgAAAAIAdgAABCgEjQALABQATbIDFRYREjmwAxCwDNAAsABFWLAGLxuxBh0+WbAARViwBC8bsQQPPlmyBwQGERI5sAcvshMBCitYIdgb9FmwBBCyFAEKK1gh2Bv0WTAxARQGIyERMxEzMhYWATI2NTQmJyMRBCj/0v4f8/KM0m/+MmZ1cWL5AX+v0ASN/mxfq/7Ua1NPYwL+jgAAAQA8//AEMASdAB0Ah7IDHh8REjkAsABFWLASLxuxEh0+WbAARViwGi8bsRoPPlmyABoSERI5sgMBCitYIdgb9FmyCRIaERI5sAkvss8JAXGyPwkBcbRvCX8JAnG0rwm/CQJdsv8JAXGyDwkBcrJfCQFysgYBCitYIdgb9FmwEhCyCwEKK1gh2Bv0WbIOEhoREjkwMQEWFjMyNjchNSECIyIGByM2JDMyABcXFAYGIyIkJwEvDXx4goAK/n8BgBb7cn0M8xQBBNbiARcMAXvqm9z++A8BhHBin5TEATFpcMLa/ujwdan/iNq6AAACAHb/8AZBBJ0AEwAhAK+yBCIjERI5sAQQsBnQALAARViwEC8bsRAdPlmwAEVYsAsvG7ELHT5ZsABFWLADLxuxAw8+WbAARViwCC8bsQgPPlmyDQgLERI5sA0vtK8Nvw0CXbRvDX8NAnGy/w0BcbIPDQFytI8Nnw0CcrJfDQFyss8NAXGyPw0BcbQfDS8NAl2yzw0BcrIGAQorWCHYG/RZsBAQshcBCitYIdgb9FmwAxCyHgEKK1gh2Bv0WTAxARAAIyIAJyMRIxEzETM2ADMyABEnNCYjIgYVFRQWMzI2NQZB/t/t3v7iE7zy8rwUAR3c8AEg8paIhpiZh4iUAiz++P7MARDi/h4Ejf4Y6QEP/sf+9Qi3wMC3NbLHw7YAAgBDAAAEEgSNAAwAFQBasgYWFxESObAGELAQ0ACwAEVYsAcvG7EHHT5ZsABFWLAJLxuxCQ8+WbIRCQcREjmwES+yCgEKK1gh2Bv0WbIBChEREjmwCRCwDNCwBxCyEgEKK1gh2Bv0WTAxMwEmNTQ2MyERIxEjAxMUFjMzESMiBkMBFtbw0wHM8/HmLmFr3d1hawIKVtGjuftzAbz+RAMiSlkBSlcAAAEACgAAA/8EjQANAFCyAQ4PERI5ALAARViwCC8bsQgdPlmwAEVYsAIvG7ECDz5ZsgcCCBESObAHL7IEBworWCHYG/RZsAHQsAgQsgsBCitYIdgb9FmwBxCwDNAwMQEjESMRIzUzESEVIREzAqfW89TUAyH90tYB5v4aAeaqAf3E/scAAAEAGv6vBm0EjQAZAKSyCBobERI5ALADL7AARViwES8bsREdPlmwAEVYsAUvG7EFDz5ZsABFWLAJLxuxCQ8+WbAARViwDS8bsQ0PPlmyFwkRERI5sBcvsj8XAXGyXxcBcrLPFwFxtK8XvxcCXbSPF58XAnKyBwEKK1gh2Bv0WbIABxcREjmwBRCyAQEKK1gh2Bv0WbAHELAL0LIPFwcREjmwFxCwEtCwERCwFNCwGNAwMQETMxEjESMDIxEjESMDIQEBIRMzETMRMxMhBMHuvtCr/V/zYPz+0wFc/sQBHvdU81T3AR4CXf5l/e0BUQHV/isB1f4rAlQCOf4gAeD+IAHgAAEAdv6vBHwEjQAQAIiyABESERI5ALAEL7AARViwDC8bsQwdPlmwAEVYsA8vG7EPHT5ZsABFWLAJLxuxCQ8+WbAARViwBi8bsQYPPlmyDQkMERI5sA0vsj8NAXGyXw0BcrLPDQFxtK8Nvw0CXbSPDZ8NAnKyCAEKK1gh2Bv0WbIACA0REjmwBhCyAQEKK1gh2Bv0WTAxAQEzESMRIwEjESMRMxEzASECkwEhyNCb/sJq8/NjATgBHQJS/nD97QFRAdX+KwSN/iAB4AABAHYAAAT+BI0AFACAsgUVFhESOQCwAEVYsBQvG7EUHT5ZsABFWLAGLxuxBh0+WbAARViwES8bsREPPlmwAEVYsAovG7EKDz5ZsgARFBESObAAL7I/AAFxsl8AAXKyzwABcbSvAL8AAl20jwCfAAJysATQsAAQshABCitYIdgb9FmwDNCyCAwAERI5MDEBMzUzFTMBIQEBIQEjFSM1IxEjETMBaUejNwE4ARz+cgGu/tH+wj6jR/PzAq3e3gHg/cT9rwHVy8v+KwSNAAABACQAAAVOBI0ADgCFsgkPEBESOQCwAEVYsAcvG7EHHT5ZsABFWLAKLxuxCh0+WbAARViwAi8bsQIPPlmwAEVYsA4vG7EODz5ZsggCBxESObAIL7I/CAFxsl8IAXKyzwgBcbSvCL8IAl20jwifCAJysgEBCitYIdgb9FmwBxCyBAEKK1gh2Bv0WbIMAQgREjkwMQEjESMRITUhETMBIQEBIQLhavP+oAJTYwE4AR3+cgGt/tEB1f4rA8rD/iAB4P3E/a8AAgBP/+sFmASlACMALgCMshUvMBESObAVELAk0ACwAEVYsBsvG7EbHT5ZsABFWLALLxuxCx0+WbAARViwBC8bsQQPPlmwAEVYsAAvG7EADz5ZsgIEGxESObACL7ALELIMAQorWCHYG/RZsAQQshMBCitYIdgb9FmwABCyIwEKK1gh2Bv0WbACELAm0LAbELIsAQorWCHYG/RZMDEFIicGIyAAAzU0ADMVIgYVFRQWMzM3JgM1NBIzMhIXFRAHFjMBEBc2NzU0JiMiEQWY466Rqf7a/qwEAQjbcX/LwBsbwALcv8bdAaNfXP2UvqIBU1uzEDk+ATwBGDr+AS7MtLEmy80CqgEeLOoBDf787Ej+/60LAdL+9G948zWgkP7S//8ABQAABDYEjQAmAdIAAAAHAd4AO/7VAAEAFf6vBIsEjQAPAFqyChARERI5ALAHL7AARViwAS8bsQEdPlmwAEVYsA8vG7EPHT5ZsABFWLALLxuxCw8+WbAARViwCS8bsQkPPlmyAA8LERI5sgQBCitYIdgb9FmyCgsPERI5MDEBEyEBATMRIxEjAwMhAQEhAifyARz+iQEJxM+S//r+5AGB/ogBGgL6AZP9vv53/e0BUQGZ/mcCSwJCAAEAJP6vBi4EjQAPAFyyCRARERI5ALACL7AARViwCC8bsQgdPlmwAEVYsA4vG7EOHT5ZsABFWLAELxuxBA8+WbIAAQorWCHYG/RZsAgQsgYBCitYIdgb9FmwCtCwC9CwABCwDNCwDdAwMSUzAyMRIREhNSEVIREhETMFasQU3vxE/qQDov6sAgbyw/3sAVEDycTE/PoDygAAAQBBAAAEFgSNABcAT7IEGBkREjkAsABFWLAMLxuxDB0+WbAARViwFi8bsRYdPlmwAEVYsAEvG7EBDz5ZshABDBESObAQL7IHAQorWCHYG/RZsATQsBAQsBPQMDEhIxEGBxUjNSYmJxEzERQWFzUzFTY3ETMEFvNMVqPMzwLzVFajSljzAaoWCszIDdG/AWr+n2tpDPPyCRgCHwAAAQB2AAAESwSNABEARrIEEhMREjkAsABFWLABLxuxAR0+WbAARViwEC8bsRAPPlmwAEVYsAkvG7EJDz5ZsgQQARESObAEL7INAQorWCHYG/RZMDETMxE2MzIWFREjETQmIyIHESN284aA7e/zdXSBhfMEjf5WJtbR/p4BYXxpJv3gAAIACv/wBagEowAbACMAZLINJCUREjmwDRCwHdAAsABFWLAOLxuxDh0+WbAARViwAC8bsQAPPlmyIA4AERI5sCAvshIBCitYIdgb9FmwA9CwIBCwCtCwABCyFQEKK1gh2Bv0WbAOELIcAQorWCHYG/RZMDEFIAAnJiY1MxQWFz4CMyAAERUhEiEyNzcXBgYDIgYHITU0JgPJ/vr+wAyuv8FUWAmP8ZEBAAEX/MASAU+Gcy9BO8WhgKAIAkyVEAER6gvdu112DJLkfv7l/veV/tArErohLAPupYwWhpUAAAIAT//wBIEEowAWAB4AXrIIHyAREjmwCBCwF9AAsABFWLAALxuxAB0+WbAARViwCC8bsQgPPlmyDQAIERI5sA0vsAAQshABCitYIdgb9FmwCBCyFwEKK1gh2Bv0WbANELIaAQorWCHYG/RZMDEBIAAXFRQGBiMgABE1ISYmIyIHByc2NhMyNjchFRQWAjkBCwE7Aoz5lv7+/usDPwezpoZ2LUFAyZiBngr9tJQEo/7c+Xqb+YgBHAEIlZaaLBG6Iiv8EqOOFoaVAAABAEL/7APoBI0AGQBpshIaGxESOQCwAEVYsAIvG7ECHT5ZsABFWLALLxuxCw8+WbACELIAAQorWCHYG/RZsgQCABESObIZCwIREjmwGS+wBdCyDwsCERI5sAsQshIBCitYIdgb9FmwGRCyGAcKK1gh2Bv0WTAxASE1IRcBFhYVFAQjIiY1MxYWMzI2NTQjIzUCjf3eA1IB/saiwv8A39D38wRxZXNz8X0DycSb/sAUv4uowLmhSVBaU7C7AAMAT//wBG8EnQAOABUAHAB+sgMdHhESObADELAP0LADELAW0ACwAEVYsAsvG7ELHT5ZsABFWLADLxuxAw8+WbALELIPAQorWCHYG/RZshMLAxESOXywEy8YtGATcBMCXbQwE0ATAl2y8BMBXbIAEwFxsAMQshYBCitYIdgb9FmwExCyGQEKK1gh2Bv0WTAxARAAIyIAETU0EjYzMgARASIGByEmJgMyNjchFhYEb/7f7ez+2oXwm/ABIP3weZQOAjYOk3h5kQ79zA+VAiz++P7MATUBDC6sAQeL/sf+9QF/nZWVnfzbnZOTnQAAAQA4AAAEGgSdACcArrIlKCkREjkAsABFWLAdLxuxHR0+WbAARViwDC8bsQwPPlmyBh0MERI5sAYvsg8GAV2wAdCwAS+yzwEBXUAJHwEvAT8BTwEEXbIAAQFdsgICCitYIdgb9FmwBhCyBwIKK1gh2Bv0WbAMELIKAQorWCHYG/RZsA7QsA/QsAcQsBHQsAYQsBPQsAIQsBbQsAEQsBjQsB0QsiQBCitYIdgb9FmyISQBERI5sgwhAV0wMQEhFSEXFSEVIQYHIQchNTM2NyM1MzUnIzUzJyY2MzIWFSM0JiMiBhcBxAGD/oIDAXv+cxImApgB/GUKNBKWoQOemQEG2L/E1/NUU01XBQK6kkIWk0U1w8MObJMOSpInzu7QtlpnfnkAAAEARv/wA7AEngAiAKCyCiMkERI5ALAARViwFi8bsRYdPlmwAEVYsAkvG7EJDz5ZsiIWCRESObAiL7IPIgFdtBAiICICXbIAAgorWCHYG/RZsAkQsgQBCitYIdgb9FmwABCwDNCwIhCwDtCwIhCwE9CwEy+yzxMBXbYfEy8TPxMDXbIAEwFdshACCitYIdgb9FmwFhCyGwEKK1gh2Bv0WbATELAd0LAQELAf0DAxASEWFjMyNxcGIyIkJyM1MzUjNTM2NjMyFwcmIyIHIRUhFSEDTv6DEXtvUHkbdm7U/v8al5KSmBr/02x6Flt11iIBfP59AYMBhGpoHL8f0MSSXJPD1iC/HNaTXAAABAB2AAAHxwSeAAMADwAdACcAqrIeKCkREjmwHhCwAdCwHhCwBNCwHhCwENAAsABFWLAmLxuxJh0+WbAARViwJC8bsSQdPlmwAEVYsAYvG7EGHT5ZsABFWLAhLxuxIQ8+WbAARViwHy8bsR8PPlmwBhCwDdCwDS+wAtCwAi+2AAIQAiACA12yAQIKK1gh2Bv0WbANELITAgorWCHYG/RZsAYQshoCCitYIdgb9FmyICQhERI5siUfJhESOTAxJSE1IQE0NiAWFRUUBiAmNRcUFjMyNjc1NCYjIgYVASMBESMRMwERMweI/cUCO/2KvwE2wL7+ysGvWlNQWAJdT05d/qby/fTz8wIM8siVAfKWubicSJa4uJsFV2ViVFNXZGNb/LQDG/zlBI385AMcAAACACgAAASqBI0AFQAeAIyyDR8gERI5sA0QsBfQALAARViwDC8bsQwdPlmwAEVYsAMvG7EDDz5ZsgYDDBESObAGL7IFAQorWCHYG/RZsAHQsAYQsArQsAovtg8KHwovCgNdto8KnwqvCgNdtB8KLwoCcbIJAQorWCHYG/RZsBPQsAYQsBTQsAoQsBbQsAwQsh4BCitYIdgb9FkwMSUhFSM1IzUzNSM1MxEhMhYQBgchFSEBMzI2NTQmIyMC9v7189DQ0NAB69H27cj+9gEL/vX4YXN1XvmZmZm2TbcCOtP+tM0FTQEEZ1VWZQACAHz/7ARGBgAADwAaAGSyExscERI5sBMQsAzQALAJL7AARViwDC8bsQwbPlmwAEVYsAMvG7EDDz5ZsABFWLAGLxuxBg8+WbIFDAMREjmyCgwDERI5sAwQshMBCitYIdgb9FmwAxCyGAEKK1gh2Bv0WTAxARQCIyInByMRMxE2MzISESc0JiMiBxEWMzI2BEbzx8BtEdLzabLM8POLe5pER5l6igIR9P7PjnoGAP3SfP7W/voIpruF/jeHvAAAAQBQ/+wEAAROAB0AS7IXHh8REjkAsABFWLAQLxuxEBs+WbAARViwCC8bsQgPPlmyAAEKK1gh2Bv0WbIDCBAREjmyFBAIERI5sBAQshcBCitYIdgb9FkwMSUyNjczDgIjIgA1NTQ2NjMyFhcjJiYjIgYVFRQWAkJaegbkBHrKdOb+8nrhmMP0BuQHeFx5hYWuaU9msGQBK/4ZnvuH5LRfdrOyG62wAAIAT//sBBcGAAARABwAZLIaHR4REjmwGhCwBNAAsAcvsABFWLAELxuxBBs+WbAARViwDS8bsQ0PPlmwAEVYsAkvG7EJDz5ZsgYEDRESObILBA0REjmwDRCyFQEKK1gh2Bv0WbAEELIaAQorWCHYG/RZMDETNDY2MzIXETMRIycGIyImJjU3FBYzMjcRJiMiBk9wzYKsavPTEWy7fst08417lEZGkn2NAiaf/Yx3Ain6AHWJjP2bAZ3CgQHXfcEA//8AWwAAArIFtQAGABWzAAACAEz/7ARVBE4ADwAZAEOyBBobERI5sAQQsBfQALAARViwBC8bsQQbPlmwAEVYsAwvG7EMDz5ZshIBCitYIdgb9FmwBBCyFwEKK1gh2Bv0WTAxEzQ2NjMyABUVFAYGIyIANRcUFjI2NTQmIgZMguuW5gEgf+2Y5v7h8pX8k5f4lQInn/2L/s38DZ38jQEx/gmgxMS1n8XGAAIAfP5gBEQETgAQABsAbrIZHB0REjmwGRCwDdAAsABFWLANLxuxDRs+WbAARViwCi8bsQobPlmwAEVYsAcvG7EHET5ZsABFWLAELxuxBA8+WbIGDQQREjmyCw0EERI5sA0QshQBCitYIdgb9FmwBBCyGQEKK1gh2Bv0WTAxARQGBiMiJxEjETMXNjMyEhcHNCYjIgcRFjMyNgREb8iBsWzz2Q5susHvCvGRfJJERZN4kwIRnv2KdP4ABdpxhf7r7Cefwnj+F3jDAAACAE/+YAQWBE4AEAAbAGuyGRwdERI5sBkQsATQALAARViwBC8bsQQbPlmwAEVYsAcvG7EHGz5ZsABFWLAJLxuxCRE+WbAARViwDS8bsQ0PPlmyBgQNERI5sgsEDRESObIUAQorWCHYG/RZsAQQshkBCitYIdgb9FkwMRM0NjYzMhc3MxEjEQYjIgInNxQWMzI3ESYjIgZPb82Gt2sR0vNqqr72C/KTeJBGSIx+jwImovyKgm76JgH8cAEc4ieexXYB9HPGAAACAFP/7AQLBE4AFgAeAHyyCB8gERI5sAgQsBfQALAARViwCC8bsQgbPlmwAEVYsAAvG7EADz5ZshsIABESObAbL7S/G88bAl20XxtvGwJxtB8bLxsCcbKPGwFdtO8b/xsCcbIMBworWCHYG/RZsAAQshABCitYIdgb9FmwCBCyFwEKK1gh2Bv0WTAxBSIANTU0NjYzMhIVFSEWFjMyNjcXBgYDIgYHITU0JgJ28v7PfeKL3fH9Pg+pjVWSMTo/vadmfBAB0HMUASj3IZ75i/7093uFnS8gpjI5A5+NfBpwfwAAAgBR/lYEBAROABkAJACDsiIlJhESObAiELAL0ACwAEVYsAMvG7EDGz5ZsABFWLAGLxuxBhs+WbAARViwCy8bsQsRPlmwAEVYsBcvG7EXDz5ZsgUDFxESObALELIRAQorWCHYG/RZsg8RFxESObIVAxcREjmwFxCyHQEKK1gh2Bv0WbADELIiAQorWCHYG/RZMDETNBIzMhc3MxEUACMiJic3FjMyNjU1BiMiAjcUFjMyNxEmIyIGUefDvWsR0P767VevNzV1g46Caq6+6vKBc5dDRJR2gAIm/QErhnL8EPL+/i4hsD+WlCJ2AS/2qLeFAdF/tQAAAQBr/+sFJgXFAB0AQLIMHh8REjkAsABFWLAMLxuxDB8+WbAARViwAy8bsQMPPlmwDBCyEwEKK1gh2Bv0WbADELIaAQorWCHYG/RZMDEBBgAjIiQCJzU0EiQzMgAXIyYmIyICFRUUEjMyNjcFJBf+0vm2/tygAZ4BILf7ATQX/RajkKzM0qyRmxYB2un++rQBRdI81QFKtP7z6ZiS/ubvNOv+5I+WAAEAa//rBSYFxQAgAFWyDCEiERI5ALAARViwDC8bsQwfPlmwAEVYsAMvG7EDDz5ZsAwQshIBCitYIdgb9FmwAxCyGQEKK1gh2Bv0WbIgDAMREjmwIC+yHQEKK1gh2Bv0WTAxJQYEIyIkAic1NBIkMzIEFyMCISICBxUUEjMyNjcRITUhBSZG/tywwP7OrQKfASO3+AErH/ku/umq0wPovGSbH/7dAh+8X3KyAUjRMdkBT7bw4wEH/uXpM+z+3zAkARvAAAACAJsAAAUXBbAACwAVAEayAxYXERI5sAMQsA/QALAARViwAS8bsQEfPlmwAEVYsAAvG7EADz5ZsAEQsgwBCitYIdgb9FmwABCyDQEKK1gh2Bv0WTAxMxEhMgQSFxUUAgQHAxEzMhI1NTQCI5sBvsgBQbIDsP7AzMSu3Pjx2gWwsf7DyDjM/r+yAwTk++YBDvAm6gEMAAACAGv/6wVyBcUAEQAgAEayBCEiERI5sAQQsB3QALAARViwDS8bsQ0fPlmwAEVYsAQvG7EEDz5ZsA0QshUBCitYIdgb9FmwBBCyHQEKK1gh2Bv0WTAxARQCBCMiJAInNTQSJDMyBBIXBzQCIyICFRUUFhYzMhI3BXKm/ti0sv7YqgGlASq0sgEmqAT73K2p32a2bqTYCgLDzv6wuroBTskxywFNwLf+ucYS5AEi/tvoJZPxhgEJ2gAAAgBr/wMFcgXFABQAIwBGsggkJRESObAIELAg0ACwAEVYsBAvG7EQHz5ZsABFWLAILxuxCA8+WbAQELIYAQorWCHYG/RZsAgQsiABCitYIdgb9FkwMQEUAgcXByUGIyIkAic1NBIkIAQSFwc0AiMiAhUVFBYWMzISNQVyl4nvpf7VQz6z/tqqAqcBKAFoASeoAfvcrareZrVvrtkCxsr+vWLAlPUNtwFNyy7QAVK7t/6vzgXsAR/+3e8dl/KEASD1AAABAJcAAALvBIwABgAyALAARViwBS8bsQUdPlmwAEVYsAAvG7EADz5ZsgQABRESObAEL7IDAQorWCHYG/RZMDEhIxEFNSUzAu/z/psCOR8DaXrN0AABAG4AAAQsBJ4AGQBZsgkaGxESOQCwAEVYsBEvG7ERHT5ZsABFWLAALxuxAA8+WbIYAQorWCHYG/RZsgIYABESObIDABEREjmwERCyCQEKK1gh2Bv0WbIMABEREjmyFxEAERI5MDEhITUBNjY1NCYjIgYVIzQ2NjMyFhUUBgcBIQQs/GAB+0Y5aVpne/N514XK6ldu/rECSZ8Buj9jQEhaeGBzvGq3nFqfZv7WAAABAHYAAAOXBcQABwAysgMICRESOQCwAEVYsAYvG7EGHT5ZsABFWLAFLxuxBQ8+WbAGELICAQorWCHYG/RZMDEBMxEhESMRIQKk8/3S8wIuBcT+Bfw3BI0AAQAP/qMD8gSNABkAWbISGhsREjkAsAwvsABFWLACLxuxAh0+WbIAAQorWCHYG/RZsgQAAhESObIFDAIREjmwBS+wDBCyEQEKK1gh2Bv0WbAFELIXAworWCHYG/RZshkXBRESOTAxASE1IRUBFhYVFAYEIyInNxYzMjY1NCYjIzUCnv26A3f+navbkP7ysMfOOZ2tpMSqt0gDycSP/oAa97Cj84Rntli4kpaSewAAAgA1/sQEiwSMAAoADgBSALAARViwCS8bsQkdPlmwAEVYsAIvG7ECDz5ZsABFWLAGLxuxBg8+WbIAAQorWCHYG/RZsAYQsAXQsAUvsggGABESObAAELAM0LINCQIREjkwMSUzFSMRIxEhJwEzASERBwPVtrby/VgGAqb6/WQBqhfCw/7FATuUA/n8NgKAKgD//wBLAo0CqgW4AwcB1AAAApgAEwCwAEVYsAovG7EKHz5ZsBDQMDEA//8ANQKYAr4FrQMHAdgAAAKYABMAsABFWLAJLxuxCR8+WbAN0DAxAP//AE8CjQKuBa0DBwHZAAACmAAQALAARViwAS8bsQEfPlkwMf//AE0CjQK5BboDBwHaAAACmAATALAARViwAC8bsQAfPlmwFNAwMQD//wA2ApgCrgWtAwcB2wAAApgAEACwAEVYsAUvG7EFHz5ZMDH//wBLAo0CqgW4AwcB3AAAApgAGQCwAEVYsBEvG7ERHz5ZsBnQsBEQsB/QMDEA//8ARgKPAqMFuAMHAd0AAAKYABMAsABFWLAILxuxCB8+WbAa0DAxAAABAGb+oAQeBIwAHABdshkdHhESOQCwDi+wAEVYsAEvG7EBHT5ZsgMBCitYIdgb9FmyBwEOERI5sAcvshkBCitYIdgb9FmyBQcZERI5sA4QshMBCitYIdgb9FmyERMZERI5shwZExESOTAxExMhFSEDNjc2EhUUBgYjIic3FjMyNjU0JiMiBgeHWgMp/ZotZYbP7YX1peS1SoS9j6uOeFNmGwF1AxfS/qoyAgL+9+SY84J1smOzlIeiNTsAAAEAQ/7EBBAEjAAGACUAsAEvsABFWLAFLxuxBR0+WbIDAQorWCHYG/RZsgADBRESOTAxAQEjASE1IQQQ/bbzAj79MgPNBAb6vgUFwwACAE//8AZtBJ0AFAAeAJGyFh8gERI5sBYQsAvQALAARViwCi8bsQodPlmwAEVYsAsvG7ELHT5ZsABFWLAALxuxAA8+WbAARViwAi8bsQIPPlmwCxCyDQEKK1gh2Bv0WbIQAAsREjmwEC+yEQEKK1gh2Bv0WbAAELITAQorWCHYG/RZsAIQshUBCitYIdgb9FmwChCyGAEKK1gh2Bv0WTAxISEFIgARNTQSNjMFIRUhESEVIREhBTcRJyIGFRUUFgZt/Uf+rez+2oXwmwFTArj9twH2/goCTPv0zc+GmJkQATUBDC6sAQeLEMT+8sP+yg8IAxQJwLc1sscAAgBz/rQEVASgABgAJABTsh8lJhESObAfELAM0ACwFC+wAEVYsAwvG7EMHT5ZsBQQsgABCitYIdgb9FmyGRQMERI5fLAZLxiyBQEKK1gh2Bv0WbAMELIfAQorWCHYG/RZMDEFMjY3BiMiAjU0NjYzMgARFRQCBCMiJzcWEzI3NTQmIyIGFRQWAemYvRlyqtH3e9qH8QEUkf7zsp6EL33RsFKIf22HionIvloBEuWZ7YD+0f72zuX+srI8ti8B6XispbSxkoqwAAACAGL/6wSFBKAADQAaAEayAxscERI5sAMQsBfQALAARViwCi8bsQodPlmwAEVYsAMvG7EDDz5ZsAoQshEBCitYIdgb9FmwAxCyFgEKK1gh2Bv0WTAxARAAIyImAjUQADMyFhIHNCYgBhUVFBYzMjY3BIX+4/Oe84IBH/Kf8oHym/72mZqGhZcCAj7+6f7EjgEMxwEWAT6O/vOnuMfIuiy1zcW0////tf5LAZMEOgIGAJsAAP///7X+SwGTBDoCBgCbAAD//wCPAAABggQ6AAYAjAAA////+/5cAYIEOgAmAIwAAAAGAKPSCv//AI8AAAGCBDoABgCMAAAAAQB2/+sEFgScACEAZbIBIiMREjkAsABFWLAVLxuxFR0+WbAARViwHy8bsR8PPlmwAEVYsBAvG7EQDz5ZsB8QsgIBCitYIdgb9FmyCh8VERI5sAovsBnQsggDCitYIdgb9FmwFRCyDQEKK1gh2Bv0WTAxJRYzMjY1NCYjIzUTJiMiFREjETY2MzIWFwMWFhUUBiMiJwHrS0hNXHx0VMpGUbHvAdHPeM1o+aGq2a98bNsxZVJYR6MBATn5/RwC8NfVYW/+1Bekga/KNgD//wBHAgkCVALNAgYAEQAAAAL/9wAABPAFsAAPAB0AgrIQHh8REjmwEBCwBtAAsABFWLAFLxuxBR8+WbAARViwAC8bsQAPPlmyAwAFERI5sAMvss8DAV2yPwMBcbJvAwFxsh8DAXGynwMBXbIPAwFysgIHCitYIdgb9FmwEdCwABCyEgEKK1gh2Bv0WbAFELIbAQorWCHYG/RZsAMQsB3QMDEzESM1MxEhMgQSFRUUAgQjEyMRMzI2NTU0JiMjETOyu7sBrsEBK6Sl/s/FP+Wjy9XOxLHlAoyqAnqs/sTMSc/+xqoCjP4+/fBG7fr+UgAAAv/3AAAE8AWwAA8AHQCCshAeHxESObAQELAG0ACwAEVYsAUvG7EFHz5ZsABFWLAALxuxAA8+WbIDAAUREjmwAy+yzwMBXbI/AwFxsm8DAXGyHwMBcbKfAwFdsg8DAXKyAgcKK1gh2Bv0WbAR0LAAELISAQorWCHYG/RZsAUQshsBCitYIdgb9FmwAxCwHdAwMTMRIzUzESEyBBIVFRQCBCMTIxEzMjY1NTQmIyMRM7K7uwGuwQErpKX+z8U/5aPL1c7EseUCjKoCeqz+xMxJz/7GqgKM/j798Ebt+v5SAAAB/9QAAAQWBgAAGAB0sgwZGhESOQCwFS+wAEVYsAQvG7EEGz5ZsABFWLAHLxuxBw8+WbAARViwDy8bsQ8PPlmyLxUBXbIPFQFdshgPFRESObAYL7IABworWCHYG/RZsgIEDxESObAEELIMAQorWCHYG/RZsAAQsBHQsBgQsBPQMDEBIxE2MyATESMRNCYjIgcRIxEjNTM1MxUzAnHnd7YBWgXzYV6SSPPDw/PnBMf+/Yr+df09ArpwXYL8+wTHqo+PAAEALQAABLAFsAAPAEwAsABFWLAKLxuxCh8+WbAARViwAi8bsQIPPlmyDwoCERI5sA8vsgAHCitYIdgb9FmwBNCwDxCwBtCwChCyCAEKK1gh2Bv0WbAM0DAxASMRIxEjNTMRITUhFSERMwO5z/vT0/4+BIP+Os8DEvzuAxKqASjMzP7YAAH/6P/sAoUFQQAcAHKyAB0eERI5ALAARViwGy8bsRsbPlmwAEVYsBEvG7ERDz5ZsBsQsAHQsBsQshgBCitYIdgb9FmwBNCwGxCwF9CwFy+wBdCwBS+wFxCyFAcKK1gh2Bv0WbAI0LARELIMAQorWCHYG/RZsBsQsBzQsBwvMDEBETMVIxUzFSMRFBYzMjcVBiMgEREjNTM1IzUzEQGtv7/Y2DE/KitTTf7o0tKysgVB/vm0par+8z43CrwXATUBFqqltAEH//8AEgAABUIHNgImACUAAAEHAEQBIwE2ABMAsABFWLAELxuxBB8+WbAM3DAxAP//ABIAAAVCBzYCJgAlAAABBwB1AcIBNgATALAARViwBS8bsQUfPlmwDdwwMQD//wASAAAFQgc3AiYAJQAAAQcAnQDDATYAEwCwAEVYsAQvG7EEHz5ZsA/cMDEA//8AEgAABUIHLAImACUAAAEHAKQAxQE3AAkAsAQvsBbcMDEA//8AEgAABUIHAgImACUAAAEHAGoA7gE2ABYAsABFWLAELxuxBB8+WbAS3LAb0DAx//8AEgAABUIHlAImACUAAAEHAKIBWAFqAAwAsAQvsBDcsBXQMDH//wASAAAFQgexAiYAJQAAAAcB3wFeARz//wBm/jwE6wXEAiYAJwAAAAcAeQHJ//v//wCUAAAETAc9AiYAKQAAAQcARADoAT0AEwCwAEVYsAYvG7EGHz5ZsA3cMDEA//8AlAAABEwHPQImACkAAAEHAHUBhwE9ABMAsABFWLAGLxuxBh8+WbAO3DAxAP//AJQAAARMBz4CJgApAAABBwCdAIgBPQATALAARViwBi8bsQYfPlmwENwwMQD//wCUAAAETAcJAiYAKQAAAQcAagCzAT0AFgCwAEVYsAYvG7EGHz5ZsBPcsBzQMDH////IAAABoAc9AiYALQAAAQcARP+XAT0AEwCwAEVYsAIvG7ECHz5ZsAXcMDEA//8AowAAAn0HPQImAC0AAAEHAHUANQE9ABMAsABFWLADLxuxAx8+WbAG3DAxAP///8sAAAJ6Bz4CJgAtAAABBwCd/zcBPQATALAARViwAi8bsQIfPlmwCNwwMQD///+/AAAChQcJAiYALQAAAQcAav9iAT0AFgCwAEVYsAIvG7ECHz5ZsAvcsBTQMDH//wCUAAAFFwcsAiYAMgAAAQcApADuATcACQCwBS+wFdwwMQD//wBm/+wFHgc2AiYAMwAAAQcARAE6ATYAEwCwAEVYsAwvG7EMHz5ZsCDcMDEA//8AZv/sBR4HNgImADMAAAEHAHUB2QE2ABMAsABFWLANLxuxDR8+WbAh3DAxAP//AGb/7AUeBzcCJgAzAAABBwCdANoBNgATALAARViwDC8bsQwfPlmwI9wwMQD//wBm/+wFHgcsAiYAMwAAAQcApADcATcAEwCwAEVYsA0vG7ENHz5ZsCLcMDEA//8AZv/sBR4HAgImADMAAAEHAGoBBQE2ABYAsABFWLAMLxuxDB8+WbAm3LAv0DAx//8Aff/sBL0HNgImADkAAAEHAEQBEQE2ABMAsABFWLAJLxuxCR8+WbAS3DAxAP//AH3/7AS9BzYCJgA5AAABBwB1AbABNgAJALAAL7AT3DAxAP//AH3/7AS9BzcCJgA5AAABBwCdALEBNgATALAARViwCS8bsQkfPlmwFdwwMQD//wB9/+wEvQcCAiYAOQAAAQcAagDcATYAFgCwAEVYsAkvG7EJHz5ZsBjcsCHQMDH//wAHAAAE1gc2AiYAPQAAAQcAdQGHATYAEwCwAEVYsAEvG7EBHz5ZsAvcMDEA//8AWv/sA/sGAAImAEUAAAEHAEQArQAAABMAsABFWLAXLxuxFxs+WbAr3DAxAP//AFr/7AP7BgACJgBFAAABBwB1AUwAAAAJALAXL7As3DAxAP//AFr/7AP7BgECJgBFAAABBgCdTQAAEwCwAEVYsBcvG7EXGz5ZsC7cMDEA//8AWv/sA/sF9gImAEUAAAEGAKRPAQATALAARViwFy8bsRcbPlmwLdwwMQD//wBa/+wD+wXMAiYARQAAAQYAangAABYAsABFWLAXLxuxFxs+WbAx3LA60DAx//8AWv/sA/sGXgImAEUAAAEHAKIA4gA0ABYAsABFWLAXLxuxFxs+WbAv3LA30DAx//8AWv/sA/sGfAImAEUAAAAHAd8A6P/n//8AT/48A/UETgImAEcAAAAHAHkBPf/7//8AU//sBAsGAAImAEkAAAEHAEQAoQAAABMAsABFWLAILxuxCBs+WbAf3DAxAP//AFP/7AQLBgACJgBJAAABBwB1AUAAAAAJALAIL7Ag3DAxAP//AFP/7AQLBgECJgBJAAABBgCdQQAAEwCwAEVYsAgvG7EIGz5ZsCLcMDEA//8AU//sBAsFzAImAEkAAAEGAGpsAAAWALAARViwCC8bsQgbPlmwJdywLtAwMf///7QAAAGMBfkCJgCMAAABBgBEg/kAEwCwAEVYsAIvG7ECGz5ZsAXcMDEA//8AjwAAAmkF+QImAIwAAAEGAHUh+QATALAARViwAy8bsQMbPlmwBtwwMQD///+3AAACZgX6AiYAjAAAAQcAnf8j//kAEwCwAEVYsAIvG7ECGz5ZsAjcMDEA////qwAAAnEFxQImAIwAAAEHAGr/Tv/5ABYAsABFWLACLxuxAhs+WbAL3LAU0DAx//8AeQAAA/gF9gImAFIAAAEGAKRVAQAJALADL7Ac3DAxAP//AE//7AQ9BgACJgBTAAABBwBEALYAAAATALAARViwBC8bsQQbPlmwHNwwMQD//wBP/+wEPQYAAiYAUwAAAQcAdQFVAAAACQCwBC+wHdwwMQD//wBP/+wEPQYBAiYAUwAAAQYAnVYAABMAsABFWLAELxuxBBs+WbAf3DAxAP//AE//7AQ9BfYCJgBTAAABBgCkWAEACQCwBC+wJtwwMQD//wBP/+wEPQXMAiYAUwAAAQcAagCBAAAAFgCwAEVYsAQvG7EEGz5ZsCLcsCvQMDH//wB3/+wD9wYAAiYAWQAAAQcARACvAAAAEwCwAEVYsAcvG7EHGz5ZsBLcMDEA//8Ad//sA/cGAAImAFkAAAEHAHUBTgAAAAkAsAYvsBPcMDEA//8Ad//sA/cGAQImAFkAAAEGAJ1PAAATALAARViwBy8bsQcbPlmwFdwwMQD//wB3/+wD9wXMAiYAWQAAAQYAanoAABYAsABFWLAHLxuxBxs+WbAY3LAh0DAx//8ADP5LA9YGAAImAF0AAAEHAHUBFgAAAAkAsAEvsBLcMDEA//8ADP5LA9YFzAImAF0AAAEGAGpCAAAWALAARViwDy8bsQ8bPlmwF9ywINAwMf//ABIAAAVCBuoCJgAlAAABBwBwAL4BOgATALAARViwBC8bsQQfPlmwDNwwMQD//wBa/+wD+wW0AiYARQAAAQYAcEgEAAkAsBcvsCrcMDEA//8AEgAABUIHHAImACUAAAEHAKAA9gE2ABMAsABFWLAELxuxBB8+WbAO3DAxAP//AFr/7AP7BeYCJgBFAAABBwCgAIAAAAATALAARViwFy8bsRcbPlmwLdwwMQAAAgAS/lIFQgWwABYAGQB0shkaGxESObAZELAW0ACwAEVYsBYvG7EWHz5ZsABFWLAULxuxFA8+WbAARViwAS8bsQEPPlmwAEVYsAwvG7EMET5ZsgcDCitYIdgb9FmwARCwEdCwES+yFxQWERI5sBcvshMBCitYIdgb9FmyGRYUERI5MDEBASMGBhUUMzI3FwYjIiY1NDcDIQMhAQMhAwMbAic+V0pHLC4VSVxfdJVz/cx2/vkCJmIBptMFsPpQOF4xRBeOLG5bjWIBSf6tBbD8bwJcAAACAFr+UgP7BE4ALQA4AKayFzk6ERI5sBcQsC/QALAARViwFy8bsRcbPlmwAEVYsCkvG7EpET5ZsABFWLAELxuxBA8+WbAARViwHi8bsR4PPlmwANCwAC+yAhcEERI5sgsXBBESObALL7AXELIPAQorWCHYG/RZshILDxESOUAJDBIcEiwSPBIEXbApELIkAworWCHYG/RZsAQQsi4BCitYIdgb9FmwCxCyMgEKK1gh2Bv0WTAxJSYnBiMiJjU0JDMzNTQmIyIGFSM0NjYzMhYXERQXFSMGBhUUMzI3FwYjIiY1NAMyNjc1IyIGFRQWAv8LDXSoo84BAe+VXmBTavN2y32+4gMpKldKRywuFUlcX3R2SH8gg4eIXQcZRXm6ia25R1RlU0BZm1i/rf4YklcROF4xRBeOLG5bjAEIRjvMXlZGU///AGb/7ATrB0sCJgAnAAABBwB1AcABSwAJALAML7Ag3DAxAP//AE//7AP1BgACJgBHAAABBwB1ASkAAAAJALAPL7Af3DAxAP//AGb/7ATrB0wCJgAnAAABBwCdAMEBSwATALAARViwDC8bsQwfPlmwINwwMQD//wBP/+wD9QYBAiYARwAAAQYAnSoAABMAsABFWLAPLxuxDxs+WbAf3DAxAP//AGb/7ATrBykCJgAnAAABBwChAacBVAATALAARViwDC8bsQwfPlmwJtwwMQD//wBP/+wD9QXeAiYARwAAAQcAoQEQAAkAEwCwAEVYsA8vG7EPGz5ZsCXcMDEA//8AZv/sBOsHTAImACcAAAEHAJ4A2AFLAAkAsAwvsCLcMDEA//8AT//sA/UGAQImAEcAAAEGAJ5BAAAJALAPL7Ah3DAxAP//AJQAAATSBz4CJgAoAAABBwCeAGcBPQAJALABL7Aa3DAxAP//AE//7AVbBgIAJgBIAAABBwGiBAEE/AAGALAeLzAx//8AlAAABEwG8QImACkAAAEHAHAAgwFBABMAsABFWLAGLxuxBh8+WbAN3DAxAP//AFP/7AQLBbQCJgBJAAABBgBwPAQACQCwCC+wHtwwMQD//wCUAAAETAcjAiYAKQAAAQcAoAC7AT0AEwCwAEVYsAYvG7EGHz5ZsA/cMDEA//8AU//sBAsF5gImAEkAAAEGAKB0AAATALAARViwCC8bsQgbPlmwIdwwMQD//wCUAAAETAcbAiYAKQAAAQcAoQFuAUYAEwCwAEVYsAYvG7EGHz5ZsBTcMDEA//8AU//sBAsF3gImAEkAAAEHAKEBJwAJABMAsABFWLAILxuxCBs+WbAm3DAxAAABAJT+UgRMBbAAGwCAshEcHRESOQCwAEVYsBYvG7EWHz5ZsABFWLAPLxuxDxE+WbAARViwBC8bsQQPPlmwAEVYsBQvG7EUDz5ZshoUFhESObAaL7IBAQorWCHYG/RZsBQQsgIBCitYIdgb9FmwA9CwDxCyCgMKK1gh2Bv0WbAWELIYAQorWCHYG/RZMDEBIREhFSMGBhUUMzI3FwYjIiY1NDchESEVIREhA+f9qgK7b1dKRywuFUlcX3SH/ZMDsf1MAlYCiv5AyjheMUQXjixuW4ZfBbDM/m4AAAIAU/5tBAsETgAjACsApbIRLC0REjmwERCwJNAAsABFWLAZLxuxGRs+WbAARViwDC8bsQwRPlmwAEVYsBEvG7ERDz5ZsgIRGRESObAMELIHAworWCHYG/RZsigZERESObAoL7QfKC8oAnG0vyjPKAJdso8oAV20XyhvKAJxtO8o/ygCcbIdBworWCHYG/RZsBEQsiEBCitYIdgb9FmyIxkRERI5sBkQsiQBCitYIdgb9FkwMSUGBwYGFRQzMjcXBiMiJjU0NyYAJzU0NjYzMhIRFSEWFjMyNwEiBgchNSYmA/pJcVdKRywuFUlcX3RQz/77Bn3ii93x/T0LnXenaf7FZHsRAc8IcrhqMzheMUQXjixuW2ZSDQET1zqi/47+5v7+YoachwJWjH0Sen3//wCUAAAETAc+AiYAKQAAAQcAngCfAT0AEwCwAEVYsAYvG7EGHz5ZsBHcMDEA//8AU//sBAsGAQImAEkAAAEGAJ5YAAAJALAIL7Ai3DAxAP//AGr/7ATwB0wCJgArAAABBwCdAL4BSwATALAARViwCy8bsQsfPlmwIdwwMQD//wBS/lYEDAYBAiYASwAAAQYAnUAAABMAsABFWLADLxuxAxs+WbAn3DAxAP//AGr/7ATwBzECJgArAAABBwCgAPEBSwATALAARViwCy8bsQsfPlmwItwwMQD//wBS/lYEDAXmAiYASwAAAQYAoHMAABMAsABFWLADLxuxAxs+WbAo3DAxAP//AGr/7ATwBykCJgArAAABBwChAaQBVAATALAARViwCy8bsQsfPlmwJ9wwMQD//wBS/lYEDAXeAiYASwAAAQcAoQEmAAkAEwCwAEVYsAMvG7EDGz5ZsC3cMDEA//8Aav35BPAFxAImACsAAAAHAaIBu/6S//8AUv5WBAwGqQImAEsAAAEHAbkBJwB+AAkAsAMvsCncMDEA//8AlAAABRgHPgImACwAAAEHAJ0A4gE9ABMAsABFWLAHLxuxBx8+WbAQ3DAxAP//AHkAAAP4B14CJgBMAAABBwCdABcBXQAJALAQL7AT3DAxAP///7MAAAKQBzMCJgAtAAABBwCk/zkBPgATALAARViwAy8bsQMfPlmwB9wwMQD///+fAAACfAXvAiYAjAAAAQcApP8l//oACQCwAi+wD9wwMQD///+5AAACkAbxAiYALQAAAQcAcP8yAUEAEwCwAEVYsAIvG7ECHz5ZsAXcMDEA////pQAAAnwFrQImAIwAAAEHAHD/Hv/9ABMAsABFWLACLxuxAhs+WbAF3DAxAP///98AAAJlByMCJgAtAAABBwCg/2oBPQATALAARViwAi8bsQIfPlmwB9wwMQD////LAAACUQXfAiYAjAAAAQcAoP9W//kAEwCwAEVYsAIvG7ECGz5ZsAfcMDEA//8AF/5YAZ8FsAImAC0AAAAGAKPuBv//AAD+UgGQBdUCJgBNAAAABgCj1wD//wCdAAABowcbAiYALQAAAQcAoQAcAUYAEwCwAEVYsAIvG7ECHz5ZsAzcMDEA//8Ao//sBiYFsAAmAC0AAAAHAC4CQgAA//8Aff5LA5AF1QAmAE0AAAAHAE4CCwAA//8ALf/sBKsHNwImAC4AAAEHAJ0BaAE2ABMAsABFWLAALxuxAB8+WbAU3DAxAP///7X+SwJrBd8CJgCbAAABBwCd/yj/3gATALAARViwDC8bsQwbPlmwEdwwMQD//wCU/fkFGAWwAiYALwAAAAcBogGd/pL//wB9/fkENgYAAiYATwAAAAcBogEt/pL//wCUAAAEJgc2AiYAMAAAAQcAdQApATYAEwCwAEVYsAUvG7EFHz5ZsAjcMDEA//8AigAAAmIHkQImAFAAAAEHAHUAGgGRABMAsABFWLADLxuxAyE+WbAG3DAxAP//AJT9+QQmBbACJgAwAAAABwGiAW3+kv//AFX9+QF/BgACJgBQAAAABwGiABD+kv//AJQAAAQmBbECJgAwAAABBwGiAgoEqwAQALAARViwCi8bsQofPlkwMf//AIwAAALnBgIAJgBQAAABBwGiAY0E/AAQALAARViwCC8bsQghPlkwMf//AJQAAAQmBbACJgAwAAAABwChAcr91P//AIwAAALrBgAAJgBQAAAABwChAWT9r///AJQAAAUXBzYCJgAyAAABBwB1AesBNgATALAARViwCC8bsQgfPlmwDNwwMQD//wB5AAAD+AYAAiYAUgAAAQcAdQFSAAAACQCwAy+wE9wwMQD//wCU/fkFFwWwAiYAMgAAAAcBogHc/pL//wB5/fkD+AROAiYAUgAAAAcBogFB/pL//wCUAAAFFwc3AiYAMgAAAQcAngEDATYAEwCwAEVYsAYvG7EGHz5ZsA/cMDEA//8AeQAAA/gGAQImAFIAAAEGAJ5qAAAJALADL7AV3DAxAP///6UAAAP4BgMCJgBSAAABBwGi/2AE/QAQALAARViwFS8bsRUhPlkwMf//AGb/7AUeBuoCJgAzAAABBwBwANUBOgATALAARViwDC8bsQwfPlmwINwwMQD//wBP/+wEPQW0AiYAUwAAAQYAcFEEAAkAsAQvsBvcMDEA//8AZv/sBR4HHAImADMAAAEHAKABDQE2ABMAsABFWLAMLxuxDB8+WbAi3DAxAP//AE//7AQ9BeYCJgBTAAABBwCgAIkAAAATALAARViwBC8bsQQbPlmwHtwwMQD//wBm/+wFHgc1AiYAMwAAAQcApQFjATYAFgCwAEVYsA0vG7ENHz5ZsCHcsCXQMDH//wBP/+wEPQX/AiYAUwAAAQcApQDfAAAAFgCwAEVYsAQvG7EEGz5ZsB3csCHQMDH//wCUAAAE3gc2AiYANgAAAQcAdQFxATYACQCwBC+wGtwwMQD//wB8AAAC9QYAAiYAVgAAAQcAdQCtAAAACQCwCy+wENwwMQD//wCU/fkE3gWwAiYANgAAAAcBogFu/pL//wBP/fkCtAROAiYAVgAAAAcBogAK/pL//wCUAAAE3gc3AiYANgAAAQcAngCJATYACQCwBC+wHNwwMQD//wA4AAAC+gYBAiYAVgAAAQYAnsYAAAkAsAsvsBLcMDEA//8ASv/sBIoHNgImADcAAAEHAHUBjgE2AAkAsAkvsCrcMDEA//8AS//sA8oGAAImAFcAAAEHAHUBOgAAAAkAsAkvsCncMDEA//8ASv/sBIoHNwImADcAAAEHAJ0AjwE2ABMAsABFWLAJLxuxCR8+WbAq3DAxAP//AEv/7APKBgECJgBXAAABBgCdOwAAEwCwAEVYsAkvG7EJGz5ZsCncMDEA//8ASv5BBIoFxAImADcAAAAHAHkBnQAA//8AS/44A8oETgImAFcAAAAHAHkBRP/3//8ASv35BIoFxAImADcAAAAHAaIBif6S//8AS/35A8oETgImAFcAAAAHAaIBMP6S//8ASv/sBIoHNwImADcAAAEHAJ4ApgE2AAkAsAkvsCzcMDEA//8AS//sA8oGAQImAFcAAAEGAJ5SAAAJALAJL7Ar3DAxAP//AC39+QSwBbACJgA4AAAABwGiAXf+kv//AAj9+QJyBUECJgBYAAAABwGiAMj+kv//AC3+RASwBbACJgA4AAAABwB5AYsAA///AAj+QQKlBUECJgBYAAAABwB5ANwAAP//AC0AAASwBzcCJgA4AAABBwCeAJgBNgATALAARViwBi8bsQYfPlmwDdwwMQD//wAI/+wDJwaDACYAWAAAAAcBogHNBX3//wB9/+wEvQcsAiYAOQAAAQcApACzATcAEwCwAEVYsBAvG7EQHz5ZsBTcMDEA//8Ad//sA/cF9gImAFkAAAEGAKRRAQATALAARViwDS8bsQ0bPlmwFNwwMQD//wB9/+wEvQbqAiYAOQAAAQcAcACsAToACQCwAC+wEdwwMQD//wB3/+wD9wW0AiYAWQAAAQYAcEoEABMAsABFWLAGLxuxBhs+WbAS3DAxAP//AH3/7AS9BxwCJgA5AAABBwCgAOQBNgATALAARViwCS8bsQkfPlmwFNwwMQD//wB3/+wD9wXmAiYAWQAAAQcAoACCAAAAEwCwAEVYsAcvG7EHGz5ZsBTcMDEA//8Aff/sBL0HlAImADkAAAEHAKIBRgFqAAwAsAAvsBbcsBvQMDH//wB3/+wD9wZeAiYAWQAAAQcAogDkADQADACwBi+wFtywG9AwMf//AH3/7AS9BzUCJgA5AAABBwClAToBNgAWALAARViwEC8bsRAfPlmwE9ywF9AwMf//AHf/7AQuBf8CJgBZAAABBwClANgAAAAMALAGL7AT3LAV0DAxAAEAff6JBL0FsAAfAFeyHCAhERI5ALAARViwGC8bsRgfPlmwAEVYsBMvG7ETDz5ZsABFWLAOLxuxDhc+WbIEExgREjmyCQMKK1gh2Bv0WbATELIcAQorWCHYG/RZsBgQsB/QMDEBERQGBwYGFRQzMjcXBiMiJjU0NyAANREzERQWMyAREQS9hX49T0csLhVJXF90Nv8A/tv8lJABJAWw/DKY5D0pWTdEF44sbltVRQEM6wPN/DKSmgE0A8YAAQB3/lID9wQ6AB8AZrIaICEREjkAsABFWLAXLxuxFxs+WbAARViwEi8bsRIPPlmwAEVYsB8vG7EfDz5ZsABFWLAKLxuxChE+WbIFAworWCHYG/RZsB8QsA/QsA8vsBIQshoBCitYIdgb9FmwFxCwHdAwMSEGBhUUMzI3FwYjIiY1NDcnBiMiJjURMxEUMzI3ETMRA+JXSkcsLhVJXF90kgVrxbC186uxPvM4XjFEF44sbluMYWJ+zsMCvf1Gzn8DCfvG//8AMAAABuUHNwImADsAAAEHAJ0BqAE2ABMAsABFWLAMLxuxDB8+WbAP3DAxAP//ACEAAAXMBgECJgBbAAABBwCdAQoAAAATALAARViwCy8bsQsbPlmwEdwwMQD//wAHAAAE1gc3AiYAPQAAAQcAnQCIATYAEwCwAEVYsAEvG7EBHz5ZsAvcMDEA//8ADP5LA9YGAQImAF0AAAEGAJ0XAAATALAARViwDy8bsQ8bPlmwFNwwMQD//wAHAAAE1gcCAiYAPQAAAQcAagCzATYAFgCwAEVYsAgvG7EIHz5ZsBDcsBnQMDH//wBQAAAEjAc2AiYAPgAAAQcAdQGDATYAEwCwAEVYsAcvG7EHHz5ZsAzcMDEA//8AUgAAA8AGAAImAF4AAAEHAHUBGwAAABMAsABFWLAHLxuxBxs+WbAM3DAxAP//AFAAAASMBxQCJgA+AAABBwChAWoBPwATALAARViwBy8bsQcfPlmwEtwwMQD//wBSAAADwAXeAiYAXgAAAQcAoQECAAkAEwCwAEVYsAcvG7EHGz5ZsBLcMDEA//8AUAAABIwHNwImAD4AAAEHAJ4AmwE2AAkAsAcvsA7cMDEA//8AUgAAA8AGAQImAF4AAAEGAJ4zAAAJALAHL7AO3DAxAP////YAAAdXB0ICJgCBAAABBwB1ArsBQgATALAARViwBi8bsQYfPlmwFdwwMQD//wBI/+wGhAYBAiYAhgAAAQcAdQJxAAEACQCwFy+wP9wwMQD//wBp/6EFIgeAAiYAgwAAAQcAdQHgAYAAEwCwAEVYsBAvG7EQHz5ZsCzcMDEA//8AT/93BD0F/gImAIkAAAEHAHUBMP/+ABMAsABFWLAELxuxBBs+WbAo3DAxAP///6YAAAQqBI0CJgG9AAABBwHe/xb/bgBGALIfFwFxsm8XAXGy/xcBcbIPFwFytq8XvxfPFwNysv8XAXKyXxcBcra/F88X3xcDcbI/FwFxtN8X7xcCXbQfFy8XAl0wMf///6YAAAQqBI0CJgG9AAABBwHe/xb/bgBGALIfFwFxsm8XAXGy/xcBcbIPFwFytq8XvxfPFwNysv8XAXKyXxcBcra/F88X3xcDcbI/FwFxtN8X7xcCXbQfFy8XAl0wMf//ACQAAAQWBI0CJgHNAAABBgHeMr4ACACyAAsBXTAx//8ACQAABJQGHgImAboAAAEHAEQAxwAeABMAsABFWLAELxuxBB0+WbAM3DAxAP//AAkAAASUBh4CJgG6AAABBwB1AWYAHgATALAARViwBS8bsQUdPlmwDdwwMQD//wAJAAAElAYfAiYBugAAAQYAnWceABMAsABFWLAELxuxBB0+WbAP3DAxAP//AAkAAASUBhQCJgG6AAABBgCkaR8ACQCwBC+wFtwwMQD//wAJAAAElAXqAiYBugAAAQcAagCSAB4AFgCwAEVYsAQvG7EEHT5ZsBLcsBvQMDH//wAJAAAElAZ8AiYBugAAAQcAogD8AFIAFgCwAEVYsAQvG7EEHT5ZsBDcsBjQMDH//wAJAAAElAaZAiYBugAAAAcB3wECAAT//wBP/kEEQwSdAiYBvAAAAAcAeQFrAAD//wB2AAADtQYeAiYBvgAAAQcARACWAB4AEwCwAEVYsAYvG7EGHT5ZsA3cMDEA//8AdgAAA7UGHgImAb4AAAEHAHUBNQAeABMAsABFWLAHLxuxBx0+WbAO3DAxAP//AHYAAAO1Bh8CJgG+AAABBgCdNh4AEwCwAEVYsAYvG7EGHT5ZsBDcMDEA//8AdgAAA7UF6gImAb4AAAEGAGphHgAWALAARViwBi8bsQYdPlmwE9ywHNAwMf///6YAAAF+Bh4CJgHCAAABBwBE/3UAHgATALAARViwAi8bsQIdPlmwBdwwMQD//wCDAAACWwYeAiYBwgAAAQYAdRMeABMAsABFWLADLxuxAx0+WbAG3DAxAP///6kAAAJYBh8CJgHCAAABBwCd/xUAHgATALAARViwAi8bsQIdPlmwCNwwMQD///+dAAACYwXqAiYBwgAAAQcAav9AAB4AFgCwAEVYsAIvG7ECHT5ZsAvcsBTQMDH//wB2AAAEZwYUAiYBxwAAAQcApACIAB8ACQCwBS+wFdwwMQD//wBP//AEbwYeAiYByAAAAQcARADVAB4AEwCwAEVYsAsvG7ELHT5ZsB7cMDEA//8AT//wBG8GHgImAcgAAAEHAHUBdAAeAAkAsAsvsB/cMDEA//8AT//wBG8GHwImAcgAAAEGAJ11HgATALAARViwCy8bsQsdPlmwIdwwMQD//wBP//AEbwYUAiYByAAAAQYApHcfAAkAsAsvsCjcMDEA//8AT//wBG8F6gImAcgAAAEHAGoAoAAeABYAsABFWLALLxuxCx0+WbAk3LAt0DAx//8AZ//wBB4GHgImAc4AAAEHAEQAtQAeABMAsABFWLAILxuxCB0+WbAR3DAxAP//AGf/8AQeBh4CJgHOAAABBwB1AVQAHgATALAARViwDy8bsQ8dPlmwEtwwMQD//wBn//AEHgYfAiYBzgAAAQYAnVUeABMAsABFWLAILxuxCB0+WbAU3DAxAP//AGf/8AQeBeoCJgHOAAABBwBqAIAAHgAWALAARViwCC8bsQgdPlmwF9ywINAwMf//AAUAAAQ2Bh4CJgHSAAABBwB1AS0AHgATALAARViwAS8bsQEdPlmwC9wwMQD//wAJAAAElAXSAiYBugAAAQYAcGIiABMAsABFWLAELxuxBB0+WbAM3DAxAP//AAkAAASUBgQCJgG6AAABBwCgAJoAHgATALAARViwBC8bsQQdPlmwDtwwMQAAAgAJ/lIElASNABYAGQBxshkaGxESObAZELAW0ACwAEVYsAAvG7EAHT5ZsABFWLAULxuxFA8+WbAARViwAS8bsQEPPlmwAEVYsAwvG7EMET5ZsgcDCitYIdgb9FmwARCwEdCyFxQAERI5sBcvshMBCitYIdgb9FmyGQAUERI5MDEBASMGBhUUMzI3FwYjIiY1NDcnIQcjAQMhAwK/AdU2V0pHLC4VSVxfdJ1Z/h5f9QHXPAFUqgSN+3M4XjFEF44sbluSYev5BI39JQG6AP//AE//8ARDBh4CJgG8AAABBwB1AWMAHgAJALALL7Ae3DAxAP//AE//8ARDBh8CJgG8AAABBgCdZB4AEwCwAEVYsAsvG7ELHT5ZsCDcMDEA//8AT//wBEMF/AImAbwAAAEHAKEBSgAnABMAsABFWLALLxuxCx0+WbAk3DAxAP//AE//8ARDBh8CJgG8AAABBgCeex4ACQCwCy+wINwwMQD//wBqAAAEKgYfAiYBvQAAAQYAnvgeAAkAsAEvsBjcMDEA//8AdgAAA7UF0gImAb4AAAEGAHAxIgATALAARViwBi8bsQYdPlmwDdwwMQD//wB2AAADtQYEAiYBvgAAAQYAoGkeABMAsABFWLAGLxuxBh0+WbAP3DAxAP//AHYAAAO1BfwCJgG+AAABBwChARwAJwATALAARViwBi8bsQYdPlmwFNwwMQAAAQB2/lIDtQSNABsAgLIRHB0REjkAsABFWLAWLxuxFh0+WbAARViwDy8bsQ8RPlmwAEVYsAQvG7EEDz5ZsABFWLAULxuxFA8+WbIbFgQREjmwGy+yAAEKK1gh2Bv0WbAUELICAQorWCHYG/RZsAPQsA8QsgoDCitYIdgb9FmwFhCyGAEKK1gh2Bv0WTAxASERIRUjBgYVFDMyNxcGIyImNTQ3IREhFSERIQNf/goCTF5XSkcsLhVJXF90h/37Azz9twH2Afj+ysI4XjFEF44sbluGXwSNxP7yAP//AHYAAAO1Bh8CJgG+AAABBgCeTR4AEwCwAEVYsAYvG7EGHT5ZsBHcMDEA//8AVP/wBEgGHwImAcAAAAEGAJ1oHgATALAARViwCi8bsQodPlmwIdwwMQD//wBU//AESAYEAiYBwAAAAQcAoACbAB4AEwCwAEVYsAovG7EKHT5ZsCDcMDEA//8AVP/wBEgF/AImAcAAAAEHAKEBTgAnABMAsABFWLAKLxuxCh0+WbAl3DAxAP//AFT9+QRIBJ0CJgHAAAAABwGiAWr+kv//AHYAAARoBh8CJgHBAAABBgCdex4AEwCwAEVYsAcvG7EHHT5ZsBDcMDEA////kQAAAm4GFAImAcIAAAEHAKT/FwAfAAkAsAIvsA/cMDEA////lwAAAm4F0gImAcIAAAEHAHD/EAAiABMAsABFWLACLxuxAh0+WbAF3DAxAP///70AAAJDBgQCJgHCAAABBwCg/0gAHgATALAARViwAi8bsQIdPlmwB9wwMQD//wAV/lIBjQSNAiYBwgAAAAYAo+wA//8AfAAAAYIF/AImAcIAAAEGAKH7JwATALAARViwAi8bsQIdPlmwDNwwMQD//wAk//AENwYfAiYBwwAAAQcAnQD0AB4AEwCwAEVYsAAvG7EAHT5ZsBPcMDEA//8Adv35BGgEjQImAcQAAAAHAaIBEv6S//8AdgAAA5QGHgImAcUAAAEGAHUKHgATALAARViwBS8bsQUdPlmwCNwwMQD//wB2/fkDlASNAiYBxQAAAAcBogEQ/pL//wB2AAADlASQAiYBxQAAAQcBogGVA4oAEACwAEVYsAovG7EKHT5ZMDH//wB2AAADlASNAiYBxQAAAAcAoQFy/Ub//wB2AAAEZwYeAiYBxwAAAQcAdQGFAB4AEwCwAEVYsAgvG7EIHT5ZsAzcMDEA//8Adv35BGcEjQImAccAAAAHAaIBeP6S//8AdgAABGcGHwImAccAAAEHAJ4AnQAeABMAsABFWLAGLxuxBh0+WbAP3DAxAP//AE//8ARvBdICJgHIAAABBgBwcCIACQCwCy+wHdwwMQD//wBP//AEbwYEAiYByAAAAQcAoACoAB4AEwCwAEVYsAsvG7ELHT5ZsCDcMDEA//8AT//wBG8GHQImAcgAAAEHAKUA/gAeAAwAsAsvsB/csCHQMDH//wB2AAAEOQYeAiYBywAAAQcAdQEXAB4ACQCwBC+wGdwwMQD//wB2/fkEOQSNAiYBywAAAAcBogEY/pL//wB2AAAEOQYfAiYBywAAAQYAni8eAAkAsAQvsBvcMDEA//8APv/wA+8GHgImAcwAAAEHAHUBQQAeAAkAsAkvsCjcMDEA//8APv/wA+8GHwImAcwAAAEGAJ1CHgATALAARViwCS8bsQkdPlmwKtwwMQD//wA+/kED7wSdAiYBzAAAAAcAeQFPAAD//wA+//AD7wYfAiYBzAAAAQYAnlkeAAkAsAkvsCrcMDEA//8AJP35BBYEjQImAc0AAAAHAaIBJf6S//8AJAAABBYGHwImAc0AAAEGAJ5HHgATALAARViwBi8bsQYdPlmwDdwwMQD//wAk/kcEFgSNAiYBzQAAAAcAeQE5AAb//wBn//AEHgYUAiYBzgAAAQYApFcfABMAsABFWLAPLxuxDx0+WbAT3DAxAP//AGf/8AQeBdICJgHOAAABBgBwUCIACQCwAC+wENwwMQD//wBn//AEHgYEAiYBzgAAAQcAoACIAB4AEwCwAEVYsAgvG7EIHT5ZsBPcMDEA//8AZ//wBB4GfAImAc4AAAEHAKIA6gBSAAwAsAAvsBXcsBrQMDH//wBn//AENAYdAiYBzgAAAQcApQDeAB4ADACwAC+wEtywFNAwMQABAGf+ggQeBI0AHgBhshsfIBESOQCwAEVYsBcvG7EXHT5ZsABFWLAALxuxAB0+WbAARViwDS8bsQ0XPlmwAEVYsBIvG7ESDz5ZsgQSABESObANELIIAworWCHYG/RZsBIQshsBCitYIdgb9FkwMQERBgYHBhUUMzI3FwYjIiY1NDcmJicRMxEUFjMyNxEEHgF9d39HLC4VSVxfdEDN8gLxfmzlBASN/PyBvTJWWkQXjixuW11JBta7AwX9AHNo1AMH//8AKAAABeUGHwImAdAAAAEHAJ0BGQAeABMAsABFWLABLxuxAR0+WbAP3DAxAP//AAUAAAQ2Bh8CJgHSAAABBgCdLh4AEwCwAEVYsAgvG7EIHT5ZsA3cMDEA//8ABQAABDYF6gImAdIAAAEGAGpZHgAWALAARViwCC8bsQgdPlmwENywGdAwMf//AEEAAAPzBh4CJgHTAAABBwB1ATAAHgATALAARViwCC8bsQgdPlmwDNwwMQD//wBBAAAD8wX8AiYB0wAAAQcAoQEXACcAEwCwAEVYsAcvG7EHHT5ZsBLcMDEA//8AQQAAA/MGHwImAdMAAAEGAJ5IHgATALAARViwBy8bsQcdPlmwD9wwMQD//wASAAAFQgZBAiYAJQAAAAYArb8A////SgAABLAGQQAmAClkAAAHAK3+hAAA////UwAABXwGQQAmACxkAAAHAK3+jQAA////VgAAAgMGQwAmAC1kAAAHAK3+kAAC////p//sBTIGQQAmADMUAAAHAK3+4QAA///+4QAABToGQQAmAD1kAAAHAK3+GwAA////sgAABPEGQQAmALkUAAAHAK3+7AAA////h//0AtoGmgImAMIAAAEHAK7/IP/rABwAsABFWLAMLxuxDBs+WbAY3LAQ0LAYELAh0DAx//8AEgAABUIFsAIGACUAAP//AJQAAASjBbACBgAmAAD//wCUAAAETAWwAgYAKQAA//8AUAAABIwFsAIGAD4AAP//AJQAAAUYBbACBgAsAAD//wCjAAABnwWwAgYALQAA//8AlAAABRgFsAIGAC8AAP//AJQAAAZqBbACBgAxAAD//wCUAAAFFwWwAgYAMgAA//8AZv/sBR4FxAIGADMAAP//AJQAAATUBbACBgA0AAD//wAtAAAEsAWwAgYAOAAA//8ABwAABNYFsAIGAD0AAP//ACkAAATpBbACBgA8AAD///+/AAAChQcJAiYALQAAAQcAav9iAT0AFgCwAEVYsAIvG7ECHz5ZsAvcsBTQMDH//wAHAAAE1gcCAiYAPQAAAQcAagCzATYAFgCwAEVYsAgvG7EIHz5ZsBDcsBnQMDH//wBW/+sEeQZBAiYAugAAAQcArQFQAAAACQCwEy+wJNwwMQD//wBg/+wEDAZBAiYAvgAAAQcArQEZAAAACQCwCS+wKtwwMQD//wB+/mEEBgZBAiYAwAAAAQcArQEjAAAACQCwAy+wFNwwMQD//wCp//QCYQYsAiYAwgAAAQYArQ/rAAkAsAAvsA/cMDEA//8AgP/rBAgGogImAMoAAAEGAK4d8wAcALAARViwAC8bsQAbPlmwHtywFdCwHhCwJ9AwMf//AI4AAARrBDoCBgCNAAD//wBP/+wEPQROAgYAUwAA//8Akv5gBB8EOgIGAHYAAP//ABYAAAPaBDoCBgBaAAD//wAfAAAD6AQ6AgYAXAAA////zP/0ApIFtwImAMIAAAEHAGr/b//rABYAsABFWLAMLxuxDBs+WbAU3LAd0DAx//8AgP/rBAgFvwImAMoAAAEGAGps8wAWALAARViwAC8bsQAbPlmwGtywI9AwMf//AE//7AQ9BkECJgBTAAABBwCtASIAAAAJALAEL7Ad3DAxAP//AID/6wQIBjQCJgDKAAABBwCtAQ3/8wAJALAAL7AV3DAxAP//AGb/7AYtBjICJgDNAAABBwCtAiz/8QAJALAAL7Aj3DAxAP//AJQAAARMBwkCJgApAAABBwBqALMBPQAWALAARViwBi8bsQYfPlmwE9ywHNAwMf//AJsAAAQ3Bz0CJgCwAAABBwB1AYIBPQATALAARViwBC8bsQQfPlmwCNwwMQAAAQBK/+wEigXEACcAY7IRKCkREjkAsABFWLAJLxuxCR8+WbAARViwHS8bsR0PPlmyAh0JERI5sg4JHRESObAJELIRAQorWCHYG/RZsAIQshcBCitYIdgb9FmyIh0JERI5sB0QsiUBCitYIdgb9FkwMQE0JiQnJjU0JDMyFhYVIzQmIyIGFRQWBBYWFRQEIyIkJjUzFBYzMjYDjYf+oGjHAR/lmO6I/I+FfImUAVTOYP7p757+95P9pJmEhQF3YGhqQX3JsORwz35ygWpfUGtlgadwttd1zol8iGsA//8AowAAAZ8FsAIGAC0AAP///78AAAKFBwkCJgAtAAABBwBq/2IBPQAWALAARViwAi8bsQIfPlmwC9ywFNAwMf//AC3/7APkBbACBgAuAAD//wCbAAAFMAWwAgYB4wAA//8AlAAABRgHNgImAC8AAAEHAHUBbgE2ABMAsABFWLAFLxuxBR8+WbAP3DAxAP//ADn/6wTdByMCJgDdAAABBwCgANkBPQATALAARViwDy8bsQ8fPlmwE9wwMQD//wASAAAFQgWwAgYAJQAA//8AlAAABKMFsAIGACYAAP//AJsAAAQ3BbACBgCwAAD//wCUAAAETAWwAgYAKQAA//8AlAAABQ0HIwImANsAAAEHAKABHQE9ABMAsABFWLAILxuxCB8+WbAN3DAxAP//AJQAAAZqBbACBgAxAAD//wCUAAAFGAWwAgYALAAA//8AZv/sBR4FxAIGADMAAP//AJsAAAUUBbACBgC1AAD//wCUAAAE1AWwAgYANAAA//8AZv/sBOsFxAIGACcAAP//AC0AAASwBbACBgA4AAD//wApAAAE6QWwAgYAPAAA//8AWv/sA/sETgIGAEUAAP//AFP/7AQLBE4CBgBJAAD//wCGAAAEEgXZAiYA7wAAAQcAoACX//MAEwCwAEVYsAgvG7EIGz5ZsA3cMDEA//8AT//sBD0ETgIGAFMAAP//AHz+YAQwBE4CBgBUAAAAAQBP/+wD9QROABwAS7IAHR4REjkAsABFWLAPLxuxDxs+WbAARViwCC8bsQgPPlmyAAEKK1gh2Bv0WbIDCA8REjmyEw8IERI5sA8QshYBCitYIdgb9FkwMSUyNjczDgIjIgARNTQAMzIWFyMmJiMiBgcVFBYCOVt4BOUEdsp14/72AQjkwfMG5QR3XHaAAX+uak5lr2YBJgEDGfcBKeG3XXirriewrQD//wAM/ksD1gQ6AgYAXQAA//8AHwAAA+gEOgIGAFwAAP//AFP/7AQLBcwCJgBJAAABBgBqbAAAFgCwAEVYsAgvG7EIGz5ZsCXcsC7QMDH//wCFAAADTQXzAiYA6wAAAQcAdQDC//MAEwCwAEVYsAQvG7EEGz5ZsAjcMDEA//8AS//sA8oETgIGAFcAAP//AH0AAAGQBdUCBgBNAAD///+rAAACcQXFAiYAjAAAAQcAav9O//kAFgCwAEVYsAIvG7ECGz5ZsAvcsBTQMDH///+1/ksBhQXVAgYATgAA//8AjwAABGUF8gImAPAAAAEHAHUBRP/yABMAsABFWLAELxuxBBs+WbAP3DAxAP//AAz+SwPWBeYCJgBdAAABBgCgSgAAEwCwAEVYsA8vG7EPGz5ZsBPcMDEA//8AMAAABuUHNgImADsAAAEHAEQCCAE2ABMAsABFWLALLxuxCx8+WbAO3DAxAP//ACEAAAXMBgACJgBbAAABBwBEAWoAAAATALAARViwCy8bsQsbPlmwDtwwMQD//wAwAAAG5Qc2AiYAOwAAAQcAdQKnATYAEwCwAEVYsAwvG7EMHz5ZsA/cMDEA//8AIQAABcwGAAImAFsAAAEHAHUCCQAAABMAsABFWLAMLxuxDBs+WbAP3DAxAP//ADAAAAblBwICJgA7AAABBwBqAdMBNgAMALABL7AW3LAN0DAx//8AIQAABcwFzAImAFsAAAEHAGoBNQAAAAwAsAEvsBbcsA3QMDH//wAHAAAE1gc2AiYAPQAAAQcARADoATYAEwCwAEVYsAgvG7EIHz5ZsArcMDEA//8ADP5LA9YGAAImAF0AAAEGAER3AAAJALABL7AQ3DAxAP//AFID/AELBgADBgALAAAAFgCwAEVYsAQvG7EEIT5ZsAHQsAEvMDH//wBlA/QCQAYAAwYABgAAACwAsABFWLAJLxuxCSE+WbAARViwBC8bsQQhPlmwCRCwBtCwBi+wAdCwAS8wMf//AI//8gPIBbAAJgAFAAAABwAFAiUAAP///7H+SwJzBd8CJgCbAAABBwCe/z//3gAJALAAL7AR3DAxAP//ADMEAAFlBgACBgFtAAD//wCUAAAGagc2AiYAMQAAAQcAdQKQATYAEwCwAEVYsAIvG7ECHz5ZsBHcMDEA//8AfAAABnkGAAImAFEAAAEHAHUCoAAAAAkAsAMvsCDcMDEA//8AEv5tBUIFsAImACUAAAAHAKYBegAD//8AWv5xA/sETgImAEUAAAAHAKYArQAH//8AlAAABEwHPQImACkAAAEHAEQA6AE9ABMAsABFWLAGLxuxBh8+WbAN3DAxAP//AJQAAAUNBz0CJgDbAAABBwBEAUoBPQATALAARViwCC8bsQgfPlmwC9wwMQD//wBT/+wECwYAAiYASQAAAQcARAChAAAAEwCwAEVYsAgvG7EIGz5ZsB/cMDEA//8AhgAABBIF8wImAO8AAAEHAEQAxP/zABMAsABFWLAILxuxCBs+WbAL3DAxAP//AEQAAAVcBbACBgC4AAD//wBP/iIFfgQ6AgYAzAAA//8AEAAABPMG/AImARgAAAEHAKsESQEOABYAsABFWLAPLxuxDx8+WbAR3LAV0DAx////8QAABBgF0AImARkAAAEHAKsD5f/iABYAsABFWLARLxuxERs+WbAT3LAX0DAx//8AT/5LCGQETgAmAFMAAAAHAF0EjgAA//8AZv5LCVwFxAAmADMAAAAHAF0FhgAA//8ASf46BH8FwwImANoAAAAHAbABkv+g//8ATf47A8QETQImAO4AAAAHAbABOf+h//8AZv4+BOsFxAImACcAAAAHAbAB1v+k//8AT/4+A/UETgImAEcAAAAHAbABSv+k//8ABwAABNYFsAIGAD0AAP//ACD+XwP1BDoCBgC8AAD//wCjAAABnwWwAgYALQAA//8AFgAAB5sHIwImANkAAAEHAKACHQE9ABMAsABFWLANLxuxDR8+WbAZ3DAxAP//AB4AAAZcBdkCJgDtAAABBwCgAYf/8wATALAARViwDS8bsQ0bPlmwGdwwMQD//wCjAAABnwWwAgYALQAA//8AEgAABUIHHAImACUAAAEHAKAA9gE2ABMAsABFWLAELxuxBB8+WbAO3DAxAP//AFr/7AP7BeYCJgBFAAABBwCg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ALAARViwBy8bsQcfPlmxDwn0sBXQMDEA//8AU//sBMgGfAImAEkAAAEGAbc97AAMALAIL7Ag3LAl0DAx////1QAABEwHtQImACkAAAEHAbYAiQEyABcAsABFWLAGLxuxBh8+WbEPCfSwFNAwMQD///+O/+wECwZ5AiYASQAAAQYBtkL2AAwAsAgvsB7csCXQMDH//wCUAAAEkgflAiYAKQAAAQcBtQCIARoADACwBi+wDNywE9AwMf//AFP/7ARLBqkCJgBJAAABBgG1Qd4ADACwCC+wHtywJdAwMf//AJQAAARMB90CJgApAAABBwG0AIkBDAAMALAGL7AM3LAT0DAx//8AU//sBAsGoQImAEkAAAEGAbRC0AAMALAIL7Ae3LAl0DAx//8AlP6eBEwHPgImACkAAAAnAJ0AiAE9AAcArATLAAr//wBT/pQECwYBAiYASQAAACYAnUEAAAcArASPAAD//wCjAAACEQfCAiYALQAAAQcAqgN4AUMACQCwAi+wBNwwMQD//wCPAAAB/QZ+AiYAjAAAAQcAqgNk//8ACQCwAi+wBNwwMQD//wCU/poBpwWwAiYALQAAAAcArAN4AAb//wB4/p4BkAXVAiYATQAAAAcArANcAAr//wBm/pQFHgXEAiYAMwAAAAcArAUdAAD//wBP/pIEPQROAiYAUwAAAAcArASd//7//wBm/+wFHge7AiYAMwAAAQcAqgUcATwACQCwFC+wH9wwMQD//wBP/+wEPQaFAiYAUwAAAQcAqgSYAAYACQCwBC+wG9wwMQD//wBm/+wFYQexAiYAMwAAAQcBtwDWASEADACwFC+wIdywJtAwMf//AE//7ATdBnwCJgBTAAABBgG3UuwADACwBC+wHdywItAwMf//ACf/7AUeB64CJgAzAAABBwG2ANsBKwAMALAUL7Af3LAm0DAx////o//sBD0GeQImAFMAAAEGAbZX9gAMALAEL7Ab3LAi0DAx//8AZv/sBR4H3gImADMAAAEHAbUA2gETAAwAsBQvsB/csCbQMDH//wBP/+wEYAapAiYAUwAAAQYBtVbeAAwAsAQvsBvcsCLQMDH//wBm/+wFHgfWAiYAMwAAAQcBtADbAQUADACwFC+wH9ywJtAwMf//AE//7AQ9BqECJgBTAAABBgG0V9AADACwBC+wG9ywItAwMf//AGb+lAUe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GzIcqB5aIBg63iFOIuA5MiUuOt463jb2Ot463iX4J5I5oChwKTIpwCoeKvg5KCuCOZAsTCx2Ldw23DBiMKAx0jOQNtwyVDLaMwQzWjOQN0A3+DakOCQztjbcOco5KDqMOow5KDaeM+A2njaeNp41UjV4NYI1jDWqNbw1zjXgNso7ijuKO4o7ijg+N0A3QDdAN0A3QDdAN0A2yjfYN9g32DfYOt463jreOt463juKO4o7ijuKO4o4HjgeOB44HjsAN7Y3tje2N7Y3tje2N7Y37jfuN+437jmWN/g3+Df4N/g3+DgkOCQ3QDe2N0A3tjdAN7Y2yjbKNso2yjuKN9g37jfYN+432DfuN9g37jfYN+463jmWOt463jreOt463jgeOow16jXqNeo16jreOZY63jmWOt45ljmWO4o3+DuKN/g7ijf4Nhg2GDYYOD44Pjg+OB44HjgeOB44HjgeNng7ADgkOwA2KjYqNio3QDfYOt463juKOwA3QDZMN9g2KjreOt46jDreOt47ijZWOD47ADkyOt47ADmWN/g4JDf4N9g5yjreOt44HjqMOow29jdANkw5yjfYOt463juKNlY2yjg+OTI3tjfuN/g23DgkOZA37jkoOCQ2eDZ4Nng7ADgkNp42njaeOt45ljdAN7Y32DfuNqQ4JDbKOwA4JDreOTI5kDreN0A3tjdAN7Y32DfuN+437jkyOZA7ijf4N/g23Db2OCQ29jgkNvY4JDkyOZA3QDe2N0A3tjdAN7Y3QDe2N0A3tjdAN7Y3QDe2N0A3tjdAN7Y3QDe2N0A3tjdAN7Y32DfuN9g37jfYN+432DfuN9g37jfYN+432DfuN9g37jreOt47ijf4O4o3+DuKN/g7ijf4O4o3+DuKN/g7ijf4N/g4HjgeOwA4JDsAOCQ7ADgkOow63jg+OTI5kDnKOSg5MjmQOZY5oDnKOow63jreOwA7igACAIsABAAEAAAABgAGAAEACwAMAAIAEwATAAQAJQAqAAUALAA2AAsAOAA/ABYARQBGAB4ASQBKACAATABMACIATwBPACMAUQBUACQAVgBWACgAWABYACkAWgBdACoAXwBfAC4AigCKAC8AnACcADAAsAC0ADEAtgC4ADYAugC6ADkAvAC8ADoAvwDAADsAwgDCAD0AxADEAD4AxgDNAD8A0QDRAEcA0wDdAEgA3wDfAFMA4QDjAFQA5QDuAFcA8ADwAGEA9QD3AGIA+gD7AGUA/QD/AGcBAgEEAGoBCQEJAG0BDAEMAG4BFwEZAG8BIQEhAHIBKwEtAHMBMAEwAHYBMgEyAHcBSQFJAHgBbAFtAHkBbwFxAHsBugG6AH4BvQG9AH8BxAHFAIAByAHIAIIBygHLAIMBzQHNAIUCKAIoAIYCKgIrAIcCRgJHAIkCSQJJAIsCSwJsAIwCbgJxAK4CdgJ7ALICgAKIALgCigKKAMECjAKMAMICjgKOAMMCkAKQAMQCkgKbAMUCpAKmAM8CqAKoANICqgKqANMCrAKsANQCrgKuANUCsQKxANYCswKzANcCtQK1ANgCtwK3ANkCuQK5ANoCuwK7ANsCvQLJANwCywLLAOkCzQLNAOoCzwLPAOsC2gLaAOwC3ALcAO0C3gLeAO4C4ALgAO8C4gLiAPAC5ALkAPEC5gLmAPIC6ALoAPMC6gLqAPQC7ALsAPUC7gLxAPYC8wLzAPoC9QL1APsDUgNXAPwDWgNpAQIDbANsARIDcANwARMDcgNyARQDdgN2ARUDeQN6ARYDfAOFARgDhwOJASIDiwOQASUDkgOTASsDlQOYAS0DngOfATEDoQOhATMDowOjATQDpQOoATUDqwOwATkDsgOyAT8DtgO3AUADvAO8AUIDvgPHAUMDygPLAU0DzQPQAU8D1wPYAVMD3APcAVUD3gPkAVYD6QPqAV0D7gQWAV8EGAQYAYgEGgQnAYkELwQvAZcEMgQyAZgENAQ0AZkEQARFAZoESARIAaAESgRKAaEETARMAaIETgRPAaMEVARXAaUEWgRaAakEXARdAaoEXwRfAawEYwRjAa0EZQRlAa4EaQRpAa8EqQSpAbAACgA4/8QA0f/EANX/xAEy/8QBOv/EAtr/xALc/8QC3v/EA43/xARM/8QAFQA6ABQAOwAmAD0AFgEYABQCZQAWAuwAJgLuABYC8AAWA1cAFgNmABYDaQAWA58AJgOhACYDowAmA6UAFgO2ABQDvgAWBEAAFgRCABYERAAWBGkAFgABABP/CADOABD+7gAS/u4AJf9AAC7/MAA4ABQARf/eAEf/6wBI/+sASf/rAEv/6wBT/+sAVf/rAFb/5gBZ/+oAWv/oAF3/6ACT/+sAmP/rAJr/6gCx/0AAs/9AALr/6wC8/+gAx//rAMj/6wDK/+oA0QAUANUAFAD2/+sBAv/rAQz/QAEX/+sBGf/oAR3/6wEh/+sBMgAUATn/6wE6ABQBS//rAUz/6wFW/+sBbv7uAXL+7gF2/u4Bd/7uAbr/wAJL/0ACTP9AAk3/QAJO/0ACT/9AAlD/QAJR/0ACZv/eAmf/3gJo/94Caf/eAmr/3gJr/94CbP/eAm3/6wJu/+sCb//rAnD/6wJx/+sCd//rAnj/6wJ5/+sCev/rAnv/6wJ8/+oCff/qAn7/6gJ//+oCgP/oAoH/6AKC/0ACg//eAoT/QAKF/94Chv9AAof/3gKJ/+sCi//rAo3/6wKP/+sCkf/rApP/6wKV/+sCl//rApn/6wKb/+sCnf/rAp//6wKh/+sCo//rArH/MALF/+sCx//rAsn/6wLaABQC3AAUAt4AFALh/+oC4//qAuX/6gLn/+oC6f/qAuv/6gLv/+gDUv9AA1r/QANq/+sDbv/qA3D/6wNy/+gDdf/qA3b/6wN3/+oDfv8wA4L/QAONABQDj//eA5D/6wOS/+sDlP/rA5X/6AOX/+sDnv/oA6b/6AOu/0ADr//eA7L/6wO3/+gDuP/rA73/6wO//+gDxP9AA8X/3gPG/0ADx//eA8v/6wPN/+sDzv/rA9j/6wPa/+sD3P/rA+D/6APi/+gD5P/oA+v/6wPu/0AD7//eA/D/QAPx/94D8v9AA/P/3gP0/0AD9f/eA/b/QAP3/94D+P9AA/n/3gP6/0AD+//eA/z/QAP9/94D/v9AA///3gQA/0AEAf/eBAL/QAQD/94EBP9ABAX/3gQH/+sECf/rBAv/6wQN/+sED//rBBH/6wQT/+sEFf/rBBv/6wQd/+sEH//rBCH/6wQj/+sEJf/rBCf/6wQp/+sEK//rBC3/6wQv/+sEMf/rBDP/6gQ1/+oEN//qBDn/6gQ7/+oEPf/qBD//6gRB/+gEQ//oBEX/6ARMABQAIAA4/98AOv/kADv/7AA9/90A0f/fANX/3wEY/+QBMv/fATr/3wG6AA4CZf/dAtr/3wLc/98C3v/fAuz/7ALu/90C8P/dA1f/3QNm/90Daf/dA43/3wOf/+wDof/sA6P/7AOl/90Dtv/kA77/3QRA/90EQv/dBET/3QRM/98Eaf/dABoAOP/OADr/7QA9/9AA0f/OANX/zgEY/+0BMv/OATr/zgJl/9AC2v/OAtz/zgLe/84C7v/QAvD/0ANX/9ADZv/QA2n/0AON/84Dpf/QA7b/7QO+/9AEQP/QBEL/0ARE/9AETP/OBGn/0AAQAC7/7gA5/+4CYf/uAmL/7gJj/+4CZP/uArH/7gLg/+4C4v/uAuT/7gLm/+4C6P/uAur/7gN+/+4EMv/uBDT/7gBKAAYAEAALABAADQAUAEEAEgBH/+gASP/oAEn/6ABL/+gAVf/oAGEAEwCT/+gAmP/oALr/6ADH/+gAyP/oAPb/6AEC/+gBHf/oASH/6AE5/+gBS//oAUz/6AFW/+gBbAAQAW0AEAFvABABcAAQAXEAEAJt/+gCbv/oAm//6AJw/+gCcf/oAon/6AKL/+gCjf/oAo//6AKR/+gCk//oApX/6AKX/+gCmf/oApv/6AKd/+gCn//oAqH/6AKj/+gDav/oA5D/6AOU/+gDl//oA6cAEAOoABADqwAQA7L/6AO4/+gDvf/oA8v/6APN/+gDzv/oA9r/6APr/+gEB//oBAn/6AQL/+gEDf/oBA//6AQR/+gEE//oBBX/6AQp/+gEK//oBC3/6AQx/+gAAgD1/9YBbf+YAD0AR//sAEj/7ABJ/+wAS//sAFX/7ACT/+wAmP/sALr/7ADH/+wAyP/sAPb/7AEC/+wBHf/sASH/7AE5/+wBS//sAUz/7AFW/+wCbf/sAm7/7AJv/+wCcP/sAnH/7AKJ/+wCi//sAo3/7AKP/+wCkf/sApP/7AKV/+wCl//sApn/7AKb/+wCnf/sAp//7AKh/+wCo//sA2r/7AOQ/+wDlP/sA5f/7AOy/+wDuP/sA73/7APL/+wDzf/sA87/7APa/+wD6//sBAf/7AQJ/+wEC//sBA3/7AQP/+wEEf/sBBP/7AQV/+wEKf/sBCv/7AQt/+wEMf/sABgAU//iARf/4gFtABgCd//iAnj/4gJ5/+ICev/iAnv/4gLF/+ICx//iAsn/4gNw/+IDdv/iA5L/4gPY/+ID3P/iBBv/4gQd/+IEH//iBCH/4gQj/+IEJf/iBCf/4gQv/+IABgAQ/4QAEv+EAW7/hAFy/4QBdv+EAXf/hAAQAC7/7AA5/+wCYf/sAmL/7AJj/+wCZP/sArH/7ALg/+wC4v/sAuT/7ALm/+wC6P/sAur/7AN+/+wEMv/sBDT/7AAeAAb/8gAL//IAWv/zAF3/8wC8//MA9f/1ARn/8wFs//IBbf/yAW//8gFw//IBcf/yAoD/8wKB//MC7//zA3L/8wOV//MDnv/zA6b/8wOn//IDqP/yA6v/8gO3//MDv//zA+D/8wPi//MD5P/zBEH/8wRD//MERf/zAD4AJ//zACv/8wAz//MANf/zAIP/8wCS//MAl//zALL/8wDDAA0A0v/zAQf/8wEW//MBGv/zARz/8wEe//MBIP/zATj/8wFV//MCKP/zAin/8wIr//MCLP/zAlL/8wJc//MCXf/zAl7/8wJf//MCYP/zAoj/8wKK//MCjP/zAo7/8wKc//MCnv/zAqD/8wKi//MCxP/zAsb/8wLI//MC+f/zA1b/8wNj//MDif/zA4z/8wO5//MDvP/zA9f/8wPZ//MD2//zBBr/8wQc//MEHv/zBCD/8wQi//MEJP/zBCb/8wQo//MEKv/zBCz/8wQu//MEMP/zBKn/8wA/ACf/5gAr/+YAM//mADX/5gCD/+YAkv/mAJf/5gCy/+YAt//CAMMAEADS/+YBB//mARb/5gEa/+YBHP/mAR7/5gEg/+YBOP/mAVX/5gIo/+YCKf/mAiv/5gIs/+YCUv/mAlz/5gJd/+YCXv/mAl//5gJg/+YCiP/mAor/5gKM/+YCjv/mApz/5gKe/+YCoP/mAqL/5gLE/+YCxv/mAsj/5gL5/+YDVv/mA2P/5gOJ/+YDjP/mA7n/5gO8/+YD1//mA9n/5gPb/+YEGv/mBBz/5gQe/+YEIP/mBCL/5gQk/+YEJv/mBCj/5gQq/+YELP/mBC7/5gQw/+YEqf/mADcAJf/kADz/0gA9/9MAsf/kALP/5ADD/+IA2f/SAQz/5AJL/+QCTP/kAk3/5AJO/+QCT//kAlD/5AJR/+QCZf/TAoL/5AKE/+QChv/kAu7/0wLw/9MDUv/kA1f/0wNa/+QDZv/TA2f/0gNp/9MDgv/kA47/0gOl/9MDrv/kA77/0wPB/9IDxP/kA8b/5APP/9ID6f/SA+7/5APw/+QD8v/kA/T/5AP2/+QD+P/kA/r/5AP8/+QD/v/kBAD/5AQC/+QEBP/kBED/0wRC/9MERP/TBE7/0gRW/9IEaf/TACcAEP9GABL/RgAl/80Asf/NALP/zQDG//IBDP/NAW7/RgFy/0YBdv9GAXf/RgJL/80CTP/NAk3/zQJO/80CT//NAlD/zQJR/80Cgv/NAoT/zQKG/80DUv/NA1r/zQOC/80Drv/NA8T/zQPG/80D7v/NA/D/zQPy/80D9P/NA/b/zQP4/80D+v/NA/z/zQP+/80EAP/NBAL/zQQE/80AAQDDAA4ArwBH/9wASP/cAEn/3ABL/9wAUf/BAFL/wQBT/9YAVP/BAFX/3ABZ/90AWv/hAF3/4QCT/9wAmP/cAJr/3QC6/9wAvP/hAL7/5gDA/8EAwf/rAML/6QDE//AAxf/nAMf/3ADI/9wAyf/jAMr/3QDL/84AzP/UAM3/2wDr/8EA7//BAPD/wQDy/8EA8//BAPT/wQD2/9wA9//BAPn/wQD6/8EA/f/BAP//wQEC/9wBBP/BARf/1gEZ/+EBHf/cASH/3AE1/8EBOf/cAUT/wQFJ/8EBS//cAUz/3AFW/9wCbf/cAm7/3AJv/9wCcP/cAnH/3AJ2/8ECd//WAnj/1gJ5/9YCev/WAnv/1gJ8/90Cff/dAn7/3QJ//90CgP/hAoH/4QKJ/9wCi//cAo3/3AKP/9wCkf/cApP/3AKV/9wCl//cApn/3AKb/9wCnf/cAp//3AKh/9wCo//cAr7/wQLA/8ECwv/BAsP/wQLF/9YCx//WAsn/1gLh/90C4//dAuX/3QLn/90C6f/dAuv/3QLv/+EDav/cA2z/wQNu/90DcP/WA3L/4QN1/90Ddv/WA3f/3QOQ/9wDkf/BA5L/1gOT/8EDlP/cA5X/4QOX/9wDmP/BA53/wQOe/+EDpv/hA63/wQOy/9wDs//BA7f/4QO4/9wDvf/cA7//4QPL/9wDzf/cA87/3APU/8ED1v/BA9j/1gPa/9wD3P/WA+D/4QPi/+ED5P/hA+j/wQPr/9wEB//cBAn/3AQL/9wEDf/cBA//3AQR/9wEE//cBBX/3AQb/9YEHf/WBB//1gQh/9YEI//WBCX/1gQn/9YEKf/cBCv/3AQt/9wEL//WBDH/3AQz/90ENf/dBDf/3QQ5/90EO//dBD3/3QQ//90EQf/hBEP/4QRF/+EESf/BBEv/wQRV/8EEYv/BBGT/wQRm/8EAdgAG/9oAC//aAEf/8ABI//AASf/wAEv/8ABV//AAWf/vAFr/3ABd/9wAk//wAJj/8ACa/+8Auv/wALz/3ADB/+wAwwAPAMX/6gDH//AAyP/wAMn/zgDK/+8Ay//nAPb/8AEC//ABGf/cAR3/8AEh//ABOf/wAUv/8AFM//ABVv/wAWz/2gFt/9oBb//aAXD/2gFx/9oCbf/wAm7/8AJv//ACcP/wAnH/8AJ8/+8Cff/vAn7/7wJ//+8CgP/cAoH/3AKJ//ACi//wAo3/8AKP//ACkf/wApP/8AKV//ACl//wApn/8AKb//ACnf/wAp//8AKh//ACo//wAuH/7wLj/+8C5f/vAuf/7wLp/+8C6//vAu//3ANq//ADbv/vA3L/3AN1/+8Dd//vA5D/8AOU//ADlf/cA5f/8AOe/9wDpv/cA6f/2gOo/9oDq//aA7L/8AO3/9wDuP/wA73/8AO//9wDy//wA83/8APO//AD2v/wA+D/3APi/9wD5P/cA+v/8AQH//AECf/wBAv/8AQN//AED//wBBH/8AQT//AEFf/wBCn/8AQr//AELf/wBDH/8AQz/+8ENf/vBDf/7wQ5/+8EO//vBD3/7wQ//+8EQf/cBEP/3ARF/9wARAAQAAwAEgAMAEf/5wBI/+cASf/nAEv/5wBV/+cAk//nAJj/5wC6/+cAwwAPAMf/5wDI/+cA9v/nAQL/5wEd/+cBIf/nATn/5wFL/+cBTP/nAVb/5wFuAAwBcgAMAXYADAF3AAwCbf/nAm7/5wJv/+cCcP/nAnH/5wKJ/+cCi//nAo3/5wKP/+cCkf/nApP/5wKV/+cCl//nApn/5wKb/+cCnf/nAp//5wKh/+cCo//nA2r/5wOQ/+cDlP/nA5f/5wOy/+cDuP/nA73/5wPL/+cDzf/nA87/5wPa/+cD6//nBAf/5wQJ/+cEC//nBA3/5wQP/+cEEf/nBBP/5wQV/+cEKf/nBCv/5wQt/+cEMf/nAAYAyf/qAOz/7gD1/9UA/f/tATP/7AFY/+wAAQD1/8AAAQDJACAAfgAGAAwACwAMAEf/6ABI/+gASf/oAEoADABL/+gAU//qAFX/6ABaAAsAXQALAJP/6ACY/+gAuv/oALwACwDD/5AAxQALAMf/6ADI/+gAyQAMAPb/6AEC/+gBF//qARkACwEd/+gBIf/oATn/6AFL/+gBTP/oAVb/6AFsAAwBbQAMAW8ADAFwAAwBcQAMAbr/vwG8/+4BwP/sAcj/7QHK/+wBzP/1Ac0ADgHPAA0B0gANAm3/6AJu/+gCb//oAnD/6AJx/+gCd//qAnj/6gJ5/+oCev/qAnv/6gKAAAsCgQALAon/6AKL/+gCjf/oAo//6AKR/+gCk//oApX/6AKX/+gCmf/oApv/6AKd/+gCn//oAqH/6AKj/+gCxf/qAsf/6gLJ/+oC7wALA2r/6ANw/+oDcgALA3b/6gOQ/+gDkv/qA5T/6AOVAAsDl//oA54ACwOmAAsDpwAMA6gADAOrAAwDsv/oA7cACwO4/+gDvf/oA78ACwPL/+gDzf/oA87/6APY/+oD2v/oA9z/6gPgAAsD4gALA+QACwPr/+gEB//oBAn/6AQL/+gEDf/oBA//6AQR/+gEE//oBBX/6AQb/+oEHf/qBB//6gQh/+oEI//qBCX/6gQn/+oEKf/oBCv/6AQt/+gEL//qBDH/6ARBAAsEQwALBEUACwABAPX/4gANAFz/7QBe/+0A7f/tAPX/wALy/+0C9P/tAvb/7QOW/+0Dwv/tA9D/7QPq/+0ET//tBFf/7QAMAFz/8gBe//IA7f/yAvL/8gL0//IC9v/yA5b/8gPC//ID0P/yA+r/8gRP//IEV//yAB8AWv/0AFz/8gBd//QAXv/zALz/9ADt//IBGf/0AoD/9AKB//QC7//0AvL/8wL0//MC9v/zA3L/9AOV//QDlv/yA57/9AOm//QDt//0A7//9APC//ID0P/yA+D/9APi//QD5P/0A+r/8gRB//QEQ//0BEX/9ARP//IEV//yAF0ABv/KAAv/ygA4/9IAOv/UADz/9AA9/9MAWv/mAFz/7wBd/+YAvP/mANH/0gDV/9IA2f/0AN3/7QDg/+EA5f/UAO3/7wD1/8kA/f/RAQj/5QEY/9QBGf/mAR//4wEy/9IBM//EATr/0gE8/+EBTf/UAU7/9QFP/+cBV/9kAVj/yQFs/8oBbf/KAW//ygFw/8oBcf/KAmX/0wKA/+YCgf/mAtr/0gLc/9IC3v/SAu7/0wLv/+YC8P/TA1f/0wNm/9MDZ//0A2n/0wNy/+YDgf/tA43/0gOO//QDlf/mA5b/7wOe/+YDpf/TA6b/5gOn/8oDqP/KA6v/ygO2/9QDt//mA77/0wO//+YDwf/0A8L/7wPP//QD0P/vA9//7QPg/+YD4f/tA+L/5gPj/+0D5P/mA+X/4QPp//QD6v/vBED/0wRB/+YEQv/TBEP/5gRE/9MERf/mBEz/0gRO//QET//vBFD/4QRS/+EEVv/0BFf/7wRp/9MAbAAG/8AAC//AADj/nQA6/8cAPP/wAD3/qwBR/9IAUv/SAFT/0gDA/9IA0f+dANP/9QDV/50A2f/wANz/9QDd/+oA4P/lAOX/wQDr/9IA7//SAPD/0gDy/9IA8//SAPT/0gD1/80A9//SAPn/0gD6/9IA/f/SAP//0gEE/9IBGP/HATL/nQEz/8wBNf/SATr/nQE8/+UBP//fAUT/0gFJ/9IBTf/OAU//6gFR//UBV/+eAVj/zgFs/8ABbf/AAW//wAFw/8ABcf/AAmX/qwJ2/9ICvv/SAsD/0gLC/9ICw//SAtr/nQLc/50C3v+dAu7/qwLw/6sDV/+rA2b/qwNn//ADaf+rA2z/0gOB/+oDjf+dA47/8AOR/9IDk//SA5j/0gOd/9IDpf+rA6f/wAOo/8ADq//AA63/0gOz/9IDtv/HA77/qwPB//ADz//wA9T/0gPW/9ID3//qA+H/6gPj/+oD5f/lA+j/0gPp//AD7P/1BED/qwRC/6sERP+rBEn/0gRL/9IETP+dBE7/8ARQ/+UEUv/lBFX/0gRW//AEYv/SBGT/0gRm/9IEZ//1BGn/qwBvAAb/sQAL/7EAOP+eADr/xQA8//IAPf+oAFH/zwBS/88AVP/PAFz/7wDA/88A0f+eANX/ngDZ//IA3f/sAOD/4QDl/8IA6//PAO3/7wDv/88A8P/PAPL/zwDz/88A9P/PAPX/xgD3/88A+f/PAPr/zwD9/88A///PAQT/zwEY/8UBMv+eATP/wAE1/88BOv+eATz/4QE//98BRP/PAUn/zwFN/80BT//oAVf/nwFY/8YBbP+xAW3/sQFv/7EBcP+xAXH/sQJl/6gCdv/PAr7/zwLA/88Cwv/PAsP/zwLa/54C3P+eAt7/ngLu/6gC8P+oA1f/qANm/6gDZ//yA2n/qANs/88Dgf/sA43/ngOO//IDkf/PA5P/zwOW/+8DmP/PA53/zwOl/6gDp/+xA6j/sQOr/7EDrf/PA7P/zwO2/8UDvv+oA8H/8gPC/+8Dz//yA9D/7wPU/88D1v/PA9//7APh/+wD4//sA+X/4QPo/88D6f/yA+r/7wRA/6gEQv+oBET/qARJ/88ES//PBEz/ngRO//IET//vBFD/4QRS/+EEVf/PBFb/8gRX/+8EYv/PBGT/zwRm/88Eaf+oAE0AOP++AFH/4QBS/+EAVP/hAFr/7wBd/+8AvP/vAMD/4QDR/74A1f++AOX/yQDr/+EA7//hAPD/4QDy/+EA8//hAPT/4QD1/98A9//hAPn/4QD6/+EA/f/hAP//4QEE/+EBCP/tARn/7wEf/+sBMv++ATP/3wE1/+EBOv++AT//6QFE/+EBSf/hAU7/9QFY/+ACdv/hAoD/7wKB/+8Cvv/hAsD/4QLC/+ECw//hAtr/vgLc/74C3v++Au//7wNs/+EDcv/vA43/vgOR/+EDk//hA5X/7wOY/+EDnf/hA57/7wOm/+8Drf/hA7P/4QO3/+8Dv//vA9T/4QPW/+ED4P/vA+L/7wPk/+8D6P/hBEH/7wRD/+8ERf/vBEn/4QRL/+EETP++BFX/4QRi/+EEZP/hBGb/4QBkADj/5gA6/+cAPP/yAD3/5wBR/9YAUv/WAFT/1gBc//EAwP/WANH/5gDV/+YA2f/yAN3/7gDg/+gA5f/mAOv/1gDt//EA7//WAPD/1gDy/9YA8//WAPT/1gD1/9AA9//WAPn/1gD6/9YA/f/WAP//1gEE/9YBGP/nATL/5gEz/84BNf/WATr/5gE8/+gBRP/WAUn/1gFN/+cBT//tAVf/5gFY/9ACZf/nAnb/1gK+/9YCwP/WAsL/1gLD/9YC2v/mAtz/5gLe/+YC7v/nAvD/5wNX/+cDZv/nA2f/8gNp/+cDbP/WA4H/7gON/+YDjv/yA5H/1gOT/9YDlv/xA5j/1gOd/9YDpf/nA63/1gOz/9YDtv/nA77/5wPB//IDwv/xA8//8gPQ//ED1P/WA9b/1gPf/+4D4f/uA+P/7gPl/+gD6P/WA+n/8gPq//EEQP/nBEL/5wRE/+cESf/WBEv/1gRM/+YETv/yBE//8QRQ/+gEUv/oBFX/1gRW//IEV//xBGL/1gRk/9YEZv/WBGn/5wCTACUAEAAn/+gAK//oADP/6AA1/+gAOP/gADr/4AA9/98Ag//oAJL/6ACX/+gAsQAQALL/6ACzABAA0f/gANL/6ADTABAA1f/gANgAFADcABAA4P/hAOX/4ADsABMA8QAQAPj/4AEDABABB//oAQwAEAEW/+gBGP/gARr/6AEc/+gBHv/oASD/6AEy/+ABOP/oATr/4AE8/+EBPf/gAUD/4QFF/+kBTf/fAU//3gFRABABVf/oAVf/3wFZ//ICKP/oAin/6AIr/+gCLP/oAksAEAJMABACTQAQAk4AEAJPABACUAAQAlEAEAJS/+gCXP/oAl3/6AJe/+gCX//oAmD/6AJl/98CggAQAoQAEAKGABACiP/oAor/6AKM/+gCjv/oApz/6AKe/+gCoP/oAqL/6ALE/+gCxv/oAsj/6ALa/+AC3P/gAt7/4ALu/98C8P/fAvn/6ANSABADVv/oA1f/3wNaABADY//oA2b/3wNp/98DggAQA4n/6AOM/+gDjf/gA6X/3wOuABADtv/gA7n/6AO8/+gDvv/fA8QAEAPGABAD1//oA9n/6APb/+gD5f/hA+b/4APsABAD7QAQA+4AEAPwABAD8gAQA/QAEAP2ABAD+AAQA/oAEAP8ABAD/gAQBAAAEAQCABAEBAAQBBr/6AQc/+gEHv/oBCD/6AQi/+gEJP/oBCb/6AQo/+gEKv/oBCz/6AQu/+gEMP/oBED/3wRC/98ERP/fBEz/4ARQ/+EEUf/gBFL/4QRT/+AEZwAQBGgAEARp/98Eqf/oADIAG//yADj/8QA6//QAPP/0AD3/8ADR//EA0//1ANX/8QDZ//QA3P/1AN3/8wDl//EBGP/0ATL/8QE6//EBTf/yAU//8gFR//UBV//yAmX/8ALa//EC3P/xAt7/8QLu//AC8P/wA1f/8ANm//ADZ//0A2n/8AOB//MDjf/xA47/9AOl//ADtv/0A77/8APB//QDz//0A9//8wPh//MD4//zA+n/9APs//UEQP/wBEL/8ARE//AETP/xBE7/9ARW//QEZ//1BGn/8ABmACUADwA4/+YAOv/mADwADgA9/+YAsQAPALMADwDR/+YA0wAOANX/5gDYABMA2QAOANwADgDdAAsA4P/lAOX/5gDm//QA7AASAPEADwD1/+cA+P/oAP3/5wEDAA8BDAAPARj/5gEy/+YBM//nATr/5gE8/+UBPf/oAU3/5gFP/+YBUQAOAVf/5gFY/+cCSwAPAkwADwJNAA8CTgAPAk8ADwJQAA8CUQAPAmX/5gKCAA8ChAAPAoYADwLa/+YC3P/mAt7/5gLu/+YC8P/mA1IADwNX/+YDWgAPA2b/5gNnAA4Daf/mA4EACwOCAA8Djf/mA44ADgOl/+YDrgAPA7b/5gO+/+YDwQAOA8QADwPGAA8DzwAOA98ACwPhAAsD4wALA+X/5QPm/+gD6QAOA+wADgPtAA8D7gAPA/AADwPyAA8D9AAPA/YADwP4AA8D+gAPA/wADwP+AA8EAAAPBAIADwQEAA8EQP/mBEL/5gRE/+YETP/mBE4ADgRQ/+UEUf/oBFL/5QRT/+gEVgAOBGcADgRoAA8Eaf/mADcABv+/AAv/vwA4/58AOv/JAD3/rQDR/58A1f+fAN3/7ADg/+YA5f/EAPX/zQD9/9UBGP/JATL/nwEz/8wBOv+fATz/5gE//98BTf/RAU//7AFX/6EBWP/PAWz/vwFt/78Bb/+/AXD/vwFx/78CZf+tAtr/nwLc/58C3v+fAu7/rQLw/60DV/+tA2b/rQNp/60Dgf/sA43/nwOl/60Dp/+/A6j/vwOr/78Dtv/JA77/rQPf/+wD4f/sA+P/7APl/+YEQP+tBEL/rQRE/60ETP+fBFD/5gRS/+YEaf+tADAAOP/jADz/5QA9/+QA0f/jANP/5QDV/+MA2P/iANn/5QDc/+UA3f/pAPH/6gED/+oBMv/jATr/4wFR/+UBV//kAmX/5ALa/+MC3P/jAt7/4wLu/+QC8P/kA1f/5ANm/+QDZ//lA2n/5AOB/+kDjf/jA47/5QOl/+QDvv/kA8H/5QPP/+UD3//pA+H/6QPj/+kD6f/lA+z/5QPt/+oEQP/kBEL/5ARE/+QETP/jBE7/5QRW/+UEZ//lBGj/6gRp/+QAIwA4/+IAPP/kANH/4gDT/+QA1f/iANj/4QDZ/+QA3P/kAN3/6QDs/+QA8f/rAQP/6wEy/+IBOv/iAVH/5ALa/+IC3P/iAt7/4gNn/+QDgf/pA43/4gOO/+QDwf/kA8//5APf/+kD4f/pA+P/6QPp/+QD7P/kA+3/6wRM/+IETv/kBFb/5ARn/+QEaP/rABcAOP/rAD3/8wDR/+sA1f/rATL/6wE6/+sCZf/zAtr/6wLc/+sC3v/rAu7/8wLw//MDV//zA2b/8wNp//MDjf/rA6X/8wO+//MEQP/zBEL/8wRE//METP/rBGn/8wA2AFH/7wBS/+8AVP/vAFz/8ADA/+8A6//vAOz/7gDt//AA7//vAPD/7wDy/+8A8//vAPT/7wD1/+4A9//vAPn/7wD6/+8A/f/vAP//7wEE/+8BCP/0AR//8QEz/+8BNf/vAUT/7wFJ/+8BWP/vAnb/7wK+/+8CwP/vAsL/7wLD/+8DbP/vA5H/7wOT/+8Dlv/wA5j/7wOd/+8Drf/vA7P/7wPC//AD0P/wA9T/7wPW/+8D6P/vA+r/8ARJ/+8ES//vBE//8ARV/+8EV//wBGL/7wRk/+8EZv/vACIABv/yAAv/8gBa//UAXf/1ALz/9QD1//QA/f/0AQj/9QEZ//UBM//1AVj/9QFs//IBbf/yAW//8gFw//IBcf/yAoD/9QKB//UC7//1A3L/9QOV//UDnv/1A6b/9QOn//IDqP/yA6v/8gO3//UDv//1A+D/9QPi//UD5P/1BEH/9QRD//UERf/1ADIAUf/uAFL/7gBU/+4AwP/uAOv/7gDsABQA7//uAPD/7gDy/+4A8//uAPT/7gD1/+0A9//uAPj/7QD5/+4A+v/uAPv/0AD9/+4A///uAQT/7gEz/+0BNf/uAT3/7QFE/+4BSf/uAVj/7QJ2/+4Cvv/uAsD/7gLC/+4Cw//uA2z/7gOR/+4Dk//uA5j/7gOd/+4Drf/uA7P/7gPU/+4D1v/uA+b/7QPo/+4ESf/uBEv/7gRR/+0EU//tBFX/7gRi/+4EZP/uBGb/7gAKAAb/9QAL//UBbP/1AW3/9QFv//UBcP/1AXH/9QOn//UDqP/1A6v/9QBZAEf/8ABI//AASf/wAEv/8ABT/8cAVf/wAJP/8ACY//AAuv/wAMf/8ADI//AA9v/wAQL/8AEX/8cBG//rAR3/8AEh//ABOf/wAUv/8AFM//ABVv/wAbz/6wHA/+kByP/rAcr/6wJt//ACbv/wAm//8AJw//ACcf/wAnf/xwJ4/8cCef/HAnr/xwJ7/8cCif/wAov/8AKN//ACj//wApH/8AKT//AClf/wApf/8AKZ//ACm//wAp3/8AKf//ACof/wAqP/8ALF/8cCx//HAsn/xwNq//ADcP/HA3b/xwOQ//ADkv/HA5T/8AOX//ADsv/wA7j/8AO9//ADy//wA83/8APO//AD2P/HA9r/8APc/8cD6//wBAf/8AQJ//AEC//wBA3/8AQP//AEEf/wBBP/8AQV//AEG//HBB3/xwQf/8cEIf/HBCP/xwQl/8cEJ//HBCn/8AQr//AELf/wBC//xwQx//AAoQAGAA0ACwANAEX/8ABH/8AASP/AAEn/wABKAA0AS//AAFP/4gBV/8AAWgALAF0ACwCT/8AAmP/AALr/wAC8AAsAxv/WAMf/wADI/8AAy//VAOz/yADx/9cA9v/AAQL/wAED/9cBF//iARkACwEb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AD4AEgBFAEcAGQBJAEkAHABMAEwAHQBRAFQAHgBWAFYAIgBaAFoAIwBcAF4AJACKAIoAJwCwALMAKAC8ALwALADAAMAALQDGAMYALgDTANQALwDWANYAMQDZANkAMgDbAN0AMwDfAN8ANgDhAOEANwDjAOMAOADlAOUAOQDrAOsAOgDtAO0AOwD2APYAPAD7APsAPQD9AP4APgEDAQQAQAEJAQkAQgEMAQwAQwEXARkARAErAS0ARwEwATAASgEyATIASwFJAUkATAFsAXIATQF2AXcAVAIoAigAVgIqAisAVwJGAkcAWQJJAkkAWwJLAnEAXAJ2AnsAgwKAApAAiQKSApsAmgKkAqYApAKoAqgApwKqAqoAqAKsAqwAqQKuAq4AqgKxArEAqwKzArMArAK1ArUArQK3ArcArgK5ArkArwK7ArsAsAK9AskAsQLLAssAvgLNAs0AvwLPAs8AwALaAtoAwQLcAtwAwgLeAt4AwwLgAuAAxALiAuIAxQLkAuQAxgLmAuYAxwLoAugAyALqAuoAyQLsAuwAygLuAvYAywNSA1cA1ANaA2kA2gNsA2wA6gNwA3AA6wNyA3IA7AN2A3YA7QN5A3oA7gN8A4UA8AOHA4kA+gOLA5AA/QOSA5gBAwOeA58BCgOhA6EBDAOjA6MBDQOlA6gBDgOrA7ABEgOyA7IBGAO2A7cBGQO8A8cBGwPKA8sBJwPNA9ABKQPXA9gBLQPcA9wBLwPeA+QBMAPpA+oBNwPuBBYBOQQYBBgBYgQaBCcBYwQvBC8BcQQyBDIBcgQ0BDQBcwRABEUBdARIBEgBegRKBEoBewRMBEwBfAROBE8BfQRUBFcBfwRaBFoBgwRcBF0BhARfBF8BhgRjBGMBhwRlBGUBiARpBGkBiQSpBKkBigACAU4AEAAQAAEAEgASAAEAJQAlAAIAJgAmAAMAJwAnAAQAKAAoAAUAKQApAAYALAAtAAcALgAuAAgALwAvAAkAMAAwAAoAMQAyAAcAMwAzAAUANAA0AAsAOAA4AAwAOQA5AAgAOgA6AA0AOwA7AA4APAA8AA8APQA9ABAAPgA+ABEARQBFABIARgBGABMARwBHABQASQBJABUATABMABYAUQBSABYAUwBTABcAVABUABMAVgBWABgAWgBaABkAXABcABoAXQBdABkAXgBeABsAigCKABMAsACwABwAsQCxAAIAsgCyAAUAswCzAAIAvAC8ABkAwADAABYAxgDGABMA0wDUAB0A1gDWAAcA2QDZAA8A2wDcAAcA3QDdAB4A3wDfAAcA4QDhAAcA4wDjAB0A5QDlAB0A6wDrAB8A7QDtABoA9gD2ABMA+wD7ACAA/QD9ACAA/gD+ABMBAwEEACABCQEJACABDAEMAAIBFwEXABcBGAEYAA0BGQEZABkBKwErABMBLAEsABwBLQEtAB8BMAEwAAkBMgEyAAkBSQFJAB8BbgFuAAEBcgFyAAEBdgF3AAECKAIoAAQCKgIrAAUCRgJHAAUCSQJJAAwCSwJRAAICUgJSAAQCUwJWAAYCVwJbAAcCXAJgAAUCYQJkAAgCZQJlABACZgJsABICbQJtABQCbgJxABUCdgJ2ABYCdwJ7ABcCgAKBABkCggKCAAICgwKDABIChAKEAAIChQKFABIChgKGAAIChwKHABICiAKIAAQCiQKJABQCigKKAAQCiwKLABQCjAKMAAQCjQKNABQCjgKOAAQCjwKPABQCkAKQAAUCkgKSAAYCkwKTABUClAKUAAYClQKVABUClgKWAAYClwKXABUCmAKYAAYCmQKZABUCmgKaAAYCmwKbABUCpAKkAAcCpQKlABYCpgKmAAcCqAKoAAcCqgKqAAcCrAKsAAcCrgKuAAcCsQKxAAgCswKzAAkCtQK1AAoCtwK3AAoCuQK5AAoCuwK7AAoCvQK9AAcCvgK+ABYCvwK/AAcCwALAABYCwQLBAAcCwgLDABYCxALEAAUCxQLFABcCxgLGAAUCxwLHABcCyALIAAUCyQLJABcCywLLABgCzQLNABgCzwLPABgC2gLaAAwC3ALcAAwC3gLeAAwC4ALgAAgC4gLiAAgC5ALkAAgC5gLmAAgC6ALoAAgC6gLqAAgC7ALsAA4C7gLuABAC7wLvABkC8ALwABAC8QLxABEC8gLyABsC8wLzABEC9AL0ABsC9QL1ABEC9gL2ABsDUgNSAAIDUwNTAAYDVANVAAcDVgNWAAUDVwNXABADWgNaAAIDWwNbAAMDXANcAAYDXQNdABEDXgNfAAcDYANgAAkDYQNiAAcDYwNjAAUDZANkAAsDZQNlAAwDZgNmABADZwNnAA8DaANoAAcDaQNpABADbANsABYDcANwABcDcgNyABkDdgN2ABcDeQN5AAYDegN6ABwDfAN9AAcDfgN+AAgDfwOAAAkDgQOBAB4DggOCAAIDgwODAAMDhAOEABwDhQOFAAYDhwOIAAcDiQOJAAUDiwOLAAsDjAOMAAQDjQONAAwDjgOOAA8DjwOPABIDkAOQABUDkgOSABcDkwOTABMDlAOUABQDlQOVABkDlgOWABoDlwOXABUDmAOYAB8DngOeABkDnwOfAA4DoQOhAA4DowOjAA4DpQOlABADpgOmABkDrAOsAAcDrQOtABYDrgOuAAIDrwOvABIDsAOwAAYDsgOyABUDtgO2AA0DtwO3ABkDvAO8AAQDvQO9ABQDvgO+ABADvwO/ABkDwAPAAAcDwQPBAA8DwgPCABoDwwPDAAcDxAPEAAIDxQPFABIDxgPGAAIDxwPHABIDygPKAAYDywPLABUDzQPOABUDzwPPAA8D0APQABoD1wPXAAUD2APYABcD3APcABcD3gPeABMD3wPfAB4D4APgABkD4QPhAB4D4gPiABkD4wPjAB4D5APkABkD6QPpAA8D6gPqABoD7gPuAAID7wPvABID8APwAAID8QPxABID8gPyAAID8wPzABID9AP0AAID9QP1ABID9gP2AAID9wP3ABID+AP4AAID+QP5ABID+gP6AAID+wP7ABID/AP8AAID/QP9ABID/gP+AAID/wP/ABIEAAQAAAIEAQQBABIEAgQCAAIEAwQDABIEBAQEAAIEBQQFABIEBgQGAAYEBwQHABUECAQIAAYECQQJABUECgQKAAYECwQLABUEDAQMAAYEDQQNABUEDgQOAAYEDwQPABUEEAQQAAYEEQQRABUEEgQSAAYEEwQTABUEFAQUAAYEFQQVABUEFgQWAAcEGAQYAAcEGgQaAAUEGwQbABcEHAQcAAUEHQQdABcEHgQeAAUEHwQfABcEIAQgAAUEIQQhABcEIgQiAAUEIwQjABcEJAQkAAUEJQQlABcEJgQmAAUEJwQnABcELwQvABcEMgQyAAgENAQ0AAgEQARAABAEQQRBABkEQgRCABAEQwRDABkERAREABAERQRFABkESARIAAkESgRKAAcETARMAAwETgROAA8ETwRPABoEVARUABwEVQRVAB8EVgRWAA8EVwRXABoEWgRaABYEXARcAB0EXQRdABwEXwRfAAkEYwRjAAcEZQRlAAcEaQRpABAEqQSpAAUAAgFtAAYABgABAAsACwABABAAEAAWABEAEQAZABIAEgAWACUAJQACACcAJwAIACsAKwAIAC4ALgAaADMAMwAIADUANQAIADcANwAbADgAOAAJADkAOQAKADoAOgALADsAOwAMADwAPAAXAD0APQANAD4APgAYAEUARQADAEcASQAEAEsASwAEAFEAUgAFAFMAUwAGAFQAVAAFAFUAVQAEAFcAVwAHAFkAWQAOAFoAWgAPAFwAXAAcAF0AXQAPAF4AXgAQAIMAgwAIAJIAkgAIAJMAkwAEAJcAlwAIAJgAmAAEAJoAmgAOALEAsQACALIAsgAIALMAswACALoAugAEALwAvAAPAMAAwAAFAMcAyAAEAMoAygAOANEA0QAJANIA0gAIANMA0wARANUA1QAJANkA2QAXANwA3AARAN0A3QAVAOAA4AASAOsA6wAFAO0A7QAcAO8A8AAFAPEA8QATAPIA9AAFAPYA9gAEAPcA9wAFAPgA+AAUAPkA+gAFAP0A/QAFAP8A/wAFAQIBAgAEAQMBAwATAQQBBAAFAQcBBwAIAQwBDAACARYBFgAIARcBFwAGARgBGAALARkBGQAPARoBGgAIARwBHAAIAR0BHQAEAR4BHgAIASABIAAIASEBIQAEATIBMgAJATUBNQAFATgBOAAIATkBOQAEAToBOgAJAUQBRAAFAUkBSQAFAUsBTAAEAVEBUQARAVUBVQAIAVYBVgAEAWkBagAZAWwBbQABAW4BbgAWAW8BcQABAXIBcgAWAXYBdwAWAigCKQAIAisCLAAIAkUCRQAZAksCUQACAlICUgAIAlwCYAAIAmECZAAKAmUCZQANAmYCbAADAm0CcQAEAnYCdgAFAncCewAGAnwCfwAOAoACgQAPAoICggACAoMCgwADAoQChAACAoUChQADAoYChgACAocChwADAogCiAAIAokCiQAEAooCigAIAosCiwAEAowCjAAIAo0CjQAEAo4CjgAIAo8CjwAEApECkQAEApMCkwAEApUClQAEApcClwAEApkCmQAEApsCmwAEApwCnAAIAp0CnQAEAp4CngAIAp8CnwAEAqACoAAIAqECoQAEAqICogAIAqMCowAEArECsQAaAr4CvgAFAsACwAAFAsICwwAFAsQCxAAIAsUCxQAGAsYCxgAIAscCxwAGAsgCyAAIAskCyQAGAtAC0AAbAtEC0QAH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ALgAuWMyc2MEWGMyc2MEXmMyc2MEZGMyc2MEamMyc2MEamMyc2MEamMyc2MEamMyc2MEamMyc2MEamMyc2MEamNjbXAEcGNjbXAEcGNjbXAEcGNjbXAEcGNjbXAEcGNjbXAEcGNjbXAEcGNjbXAEcGNjbXAEcGNjbXAEcGRsaWcEeGRsaWcEfmRsaWcEhGRsaWcEimRsaWcEimRsaWcEimRsaWcEimRsaWcEimRsaWcEimRsaWcEimRub20EkGRub20ElmRub20EnGRub20EomRub20EomRub20EomRub20EomRub20EomRub20EomRub20EomZyYWMEqGZyYWMEqGZyYWMEqGZyYWMEqGZyYWMEqGZyYWMEqGZyYWMEqGZyYWMEqGZyYWMEqGZyYWMEqGxpZ2EEsmxpZ2EEumxudW0EwGxudW0ExmxudW0EzGxudW0E0mxudW0E0mxudW0E0mxudW0E0mxudW0E0mxudW0E0mxudW0E0mxvY2wE2GxvY2wE3mxvY2wE5G51bXIE6m51bXIE8G51bXIE9m51bXIE/G51bXIE/G51bXIE/G51bXIE/G51bXIE/G51bXIE/G51bXIE/G9udW0FAm9udW0FCG9udW0FDm9udW0FFG9udW0FFG9udW0FFG9udW0FFG9udW0FFG9udW0FFG9udW0FFHBudW0FGnBudW0FIHBudW0FJnBudW0FLHBudW0FLHBudW0FLHBudW0FLHBudW0FLHBudW0FLHBudW0FLHNtY3AFMnNtY3AFOHNtY3AFPnNtY3AFRHNtY3AFRHNtY3AFRHNtY3AFRHNtY3AFRHNtY3AFRHNtY3AFRHNzMDEFSnNzMDEFUHNzMDEFVnNzMDEFXHNzMDEFXHNzMDEFXHNzMDEFXHNzMDEFXHNzMDEFXHNzMDEFXHNzMDIFYnNzMDIFaHNzMDIFbnNzMDIFdHNzMDIFdHNzMDIFdHNzMDIFdHNzMDIFdHNzMDIFdHNzMDIFdHNzMDMFenNzMDMFgHNzMDMFhnNzMDMFjHNzMDMFjHNzMDMFjHNzMDMFjHNzMDMFjHNzMDMFjHNzMDMFjHNzMDQFknNzMDQFmHNzMDQFnnNzMDQFpHNzMDQFpHNzMDQFpHNzMDQFpHNzMDQFpHNzMDQFpHNzMDQFpHNzMDUFqnNzMDUFsHNzMDUFtnNzMDUFvHNzMDUFvHNzMDUFvHNzMDUFvHNzMDUFvHNzMDUFvHNzMDUFvHNzMDYFwnNzMDYFyHNzMDYFznNzMDYF1HNzMDYF1HNzMDYF1HNzMDYF1HNzMDYF1HNzMDYF1HNzMDYF1HNzMDcF2nNzMDcF4HNzMDcF5nNzMDcF7HNzMDcF7HNzMDcF7HNzMDcF7HNzMDcF7HNzMDcF7HNzMDcF7HRudW0F8nRudW0F+HRudW0F/nRudW0GBHRudW0GBHRudW0GBHRudW0GBHRudW0GBHRudW0GBHRudW0GBAAAAAEAAQAAAAEAAwAAAAEAAgAAAAEAAAAAAAIACAAJAAAAAQAOAAAAAQAQAAAAAQAPAAAAAQANAAAAAQBDAAAAAQBFAAAAAQBEAAAAAQBCAAAAAwA/AEAAQQAAAAIAEQASAAAAAQASAAAAAQA8AAAAAQA+AAAAAQA9AAAAAQA7AAAAAQAKAAAAAQAMAAAAAQALAAAAAQBHAAAAAQBJAAAAAQBIAAAAAQBGAAAAAQAwAAAAAQAyAAAAAQAxAAAAAQAvAAAAAQA4AAAAAQA6AAAAAQA5AAAAAQA3AAAAAQAFAAAAAQAHAAAAAQAGAAAAAQAEAAAAAQAUAAAAAQAWAAAAAQAVAAAAAQATAAAAAQAYAAAAAQAaAAAAAQAZAAAAAQAXAAAAAQAcAAAAAQAeAAAAAQAdAAAAAQAbAAAAAQAgAAAAAQAiAAAAAQAhAAAAAQAfAAAAAQAkAAAAAQAmAAAAAQAlAAAAAQAjAAAAAQAoAAAAAQAqAAAAAQApAAAAAQAnAAAAAQAsAAAAAQAuAAAAAQAtAAAAAQArAAAAAQA0AAAAAQA2AAAAAQA1AAAAAQAzAEsAmACYAJgAmAQmBCYEJgQmBxQHwA5QDlAOZg6IDogOiA6IDr4O5A8SDxIPEg8SDyYPJg8mDyYPOg86DzoPOg9OD04PTg9OD2APYA9gD2APeg96D3oPeg+8D7wPvA+8D9oP2g/aD9oP+A/4D/gP+BAqECoQKhAqEFwQXBBcEFwQjhCiENoQzBDMEMwQzBDaENoQ2hDaEQYAAQAAAAEACAACAcQA3wHnAboBuwG8Ab0BvgG/AcABwQHCAcMBxAHFAcYBxwHIAckBygHLAcwBzQHOAc8B0AHRAdIB0wHoAekCQwI7AeoB6wHsAe0B7gHvAfAB8QHyAfMB9AH1AfYB9wH4AfkB+gH7AfwB/QH+AgACAQTcAgICAwIEAgUCBgIHAggCCQIKAgsCLwIPAhACEQIUAhUCFgIXAhgCGQIbAhwCHgIdAvsC/AL9Av4C/wMAAwEDAgMDAwQDBQMGAwcDCAMJAwoDCwMMAw0DDgMPAxADEQMSAxMDFAMVAxYDFwMYAxkDGgMbAxwDHQMeAx8DIAMhAyIDIwMkAyUDJgMnAygDKQMqAysDLAMtAy4DLwMwAzEDMgMzAzQDNQM2AzcDOAM5AzoDOwM8Az0DPgM/A0ADQQNCA0MDRQNEA0YDRwNIA0kDSgNLA0wDTQNOA08DUANRBKoEqwSsBK0ErgSvBLAEsQSyBLMEtAS1BLYEtwS4BLkEugS7BLwEvQS+BL8EwATBBMIEwwTEBMUB/wTGBMcEyATJBMoEywTMBM0EzgTPBNAE0QTSBNME1ATVBNcE2ATaAhoE2wIOBNYCEwINBNkCDAISAAEA3wAIACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgBlAGcAhQCSALAAsQCyALMAtAC1ALYAtwC4ALkA0QDSANMA1ADVANYA1wDYANkA2gDbANwA3QDeAN8A4ADhAOIA4wDkAOUA5gDnAOgBLAEwATIBOAE6ATwBPgE/AUUBRgF/AYUBigGNAkYCRwJJAksCTAJNAk4CTwJQAlECUgJTAlQCVQJWAlcCWAJZAloCWwJcAl0CXgJfAmACYQJiAmMCZAJlAoIChAKGAogCigKMAo4CkAKSApQClgKYApoCnAKeAqACogKkAqYCqAKqAqwCrgKxArMCtQK3ArkCuwK9Ar8CwQLEAsYCyALKAswCzgLQAtIC1ALYAtoC3ALeAuAC4gLkAuYC6ALqAuwC7gLwAvEC8wL1A1IDUwNUA1UDVgNXA1gDWgNbA1wDXQNeA18DYANhA2MDZANlA2YDZwNoA2kDeQN6A3sDfAN9A34DfwOAA4EDggODA4QDhQOGA4cDiAOJA4oDiwOMA40DjgO6A7wDvgPTA9kD3wRIBEoETgRWBFgEXQRpAAEAAAABAAgAAgF0ALcBugG7AbwBvQG+Ab8BwAHBAcIBwwHEAcUBxgHHAcgByQHKAcsBzAHNAc4BzwHQAdEB0gHTAvwDLwI7AfoEyQTKAfsB/AH9Af4B/wIABM0EzgTQBNME3AICAgMCBAIFAgYCBwIIAgkCCgILAfQB9QH2AfcB+AH5Ai8CDwIQAhECFAIVAhcCGQL9Av4C/wMAAwEDAgMDAwQDBQMGAwcDCAMJAwoDCwMMAw0DDgMPAxADEQMSAxMDFAMVAxYDFwMYA04DGQMaAxsDHAMdAx4DHwMgAyEDIgMjAyQDJQMmAycDKAMpAyoDKwMsAy0DLgMwAzEDMgMzAzQDNQM2AzcDOAM5AzoDOwM8Az0DPgM/A0ADQQNCA0MDRQNEA0YDRwNIA0kDSgNLA0wDTQNPA1ADUQTIBMsEzATPBNEE0gIBBNQEwATBBMIEwwTEBMUExgTHBNUE1wTYAhgE2gIaBNsC+wIOBNYCEwINBNkCFgIMAhIAAQC3AEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0AXgCHAIwAkwDpAOoA6wDsAO0A7gDvAPAA8QDyAPMA9AD1APYA9wD4APkA+gD7APwA/QD+AP8BAAEBAQIBAwEEAQUBBgEtATEBMwE5ATsBPQFAAUcCSgJmAmcCaAJpAmoCawJsAm0CbgJvAnACcQJyAnMCdAJ1AnYCdwJ4AnkCegJ7AnwCfQJ+An8CgAKBAoMChQKHAokCiwKNAo8CkQKTApUClwKZApsCnQKfAqECowKlAqcCqQKrAq0CsgK0ArYCuAK6ArwCvgLAAsICxQLHAskCywLNAs8C0QLTAtUC2QLbAt0C3wLhAuMC5QLnAukC6wLtAu8C8gL0AvYDjwOQA5EDkgOTA5QDlQOWA5cDmAOZA5oDmwOcA50DngO7A70DvwPNA9QD2gPgBEYESQRLBE8EVwRZBFoEXgRqAAYAAAAGABIAKgBCAFoAcgCKAAMAAAABABIAAQCQAAEAAABKAAEAAQBNAAMAAAABABIAAQB4AAEAAABKAAEAAQBOAAMAAAABABIAAQBgAAEAAABKAAEAAQKtAAMAAAABABIAAQBIAAEAAABKAAEAAQOaAAMAAAABABIAAQAwAAEAAABKAAEAAQOcAAMAAAABABIAAQAYAAEAAABKAAEAAQQZAAIAAQCnAKsAAAAEAAAAAQAIAAEGHgA2AHIApACuALgAygD8AQ4BGAFKAWQBfgGQAboB7AH2AhgCMgJEAnYCiAKiAswC3gMQAxoDJAM2A2gDcgN8A4YDoAO6A8wD9gQoBDIEVARuBIAEsgTEBN4FCAUaBSQFLgU4BUIFbAWWBcAF6gYUAAYADgAUABoAIAAmACwCSwACAKcCTAACAKgCTgACAKkD8AACAKoEegACAKsD7gACAKwAAQAEBIcAAgCsAAEABAKIAAIAqAACAAYADASJAAIArASLAAIBogAGAA4AFAAaACAAJgAsAlMAAgCnAlQAAgCoBAoAAgCpBAgAAgCqBHwAAgCrBAYAAgCsAAIABgAMBHYAAgCoAqIAAgGiAAEABASNAAIArAAGAA4AFAAaACAAJgAsAlcAAgCnAlgAAgCoAqYAAgCpBBYAAgCqBH4AAgCrBBgAAgCsAAMACAAOABQEjwACAKgEkQACAKwCswACAaIAAwAIAA4AFAK1AAIAqASTAAIArAK3AAIBogACAAYADAOsAAIAqASVAAIArAAFAAwAEgAYAB4AJAR4AAIApwK9AAIAqAJbAAIAqQSXAAIArAK/AAIBogAGAA4AFAAaACAAJgAsAlwAAgCnAl0AAgCoAl8AAgCpBBwAAgCqBIAAAgCrBBoAAgCsAAEABASZAAIAqAAEAAoAEAAWABwCygACAKgEggACAKsEmwACAKwCzAACAaIAAwAIAA4AFALQAAIAqASdAAIArALWAAIBogACAAYADASfAAIArALaAAIBogAGAA4AFAAaACAAJgAsAmEAAgCnAmIAAgCoAuAAAgCpBDQAAgCqBIQAAgCrBDIAAgCsAAIABgAMBKEAAgCpBKMAAgCsAAMACAAOABQDnwACAKcDoQACAKgEpQACAKwABQAMABIAGAAeACQDpQACAKcCZQACAKgERAACAKkEQgACAKoEQAACAKwAAgAGAAwC8QACAKgEpwACAKwABgAOABQAGgAgACYALAJmAAIApwJnAAIAqAJpAAIAqQPxAAIAqgR7AAIAqwPvAAIArAABAAQEiAACAKwAAQAEAokAAgCoAAIABgAMBIoAAgCsBIwAAgGiAAYADgAUABoAIAAmACwCbgACAKcCbwACAKgECwACAKkECQACAKoEfQACAKsEBwACAKwAAQAEBHcAAgCoAAEABASOAAIArAABAAQEGQACAKwAAwAIAA4AFASQAAIAqASSAAIArAK0AAIBogADAAgADgAUArYAAgCoBJQAAgCsArgAAgGiAAIABgAMA60AAgCoBJYAAgCsAAUADAASABgAHgAkBHkAAgCnAr4AAgCoAnYAAgCpBJgAAgCsAsAAAgGiAAYADgAUABoAIAAmACwCdwACAKcCeAACAKgCegACAKkEHQACAKoEgQACAKsEGwACAKwAAQAEBJoAAgCoAAQACgAQABYAHALLAAIAqASDAAIAqwScAAIArALNAAIBogADAAgADgAUAtEAAgCoBJ4AAgCsAtcAAgGiAAIABgAMBKAAAgCsAtsAAgGiAAYADgAUABoAIAAmACwCfAACAKcCfQACAKgC4QACAKkENQACAKoEhQACAKsEMwACAKwAAgAGAAwEogACAKkEpAACAKwAAwAIAA4AFAOgAAIApwOiAAIAqASmAAIArAAFAAwAEgAYAB4AJAOmAAIApwKAAAIAqARFAAIAqQRDAAIAqgRBAAIArAACAAYADALyAAIAqASoAAIArAABAAQC9wACAKgAAQAEAvkAAgCoAAEABAL4AAIAqAABAAQC+gACAKgABQAMABIAGAAeACQCcgACAKcCcwACAKgCpwACAKkEFwACAKoEfwACAKsABQAMABIAGAAeACQEKgACAKcEKAACAKgELgACAKkELAACAKoEMAACAKwABQAMABIAGAAeACQEKwACAKcEKQACAKgELwACAKkELQACAKoEMQACAKwABQAMABIAGAAeACQEOAACAKcENgACAKgEPAACAKkEOgACAKoEPgACAKwABQAMABIAGAAeACQEOQACAKcENwACAKgEPQACAKkEOwACAKoEPwACAKwAAQAEBIYAAgCoAAIAEQAlACkAAAArAC0ABQAvADQACAA2ADsADgA9AD4AFABFAEkAFgBLAE0AGwBPAFQAHgBWAFsAJABdAF4AKgCBAIEALACDAIMALQCGAIYALgCJAIkALwCMAIwAMACXAJoAMQDPAM8ANQABAAAAAQAIAAEABgACAAEAAgLUAtUAAQAAAAEACAACAA4ABATdBN4E3wTgAAEABAKGAocCmAKZAAQAAAABAAgAAQAmAAIACgAcAAIABgAMAaMAAgBKAagAAgBYAAEABAGpAAIAWAABAAIASgBXAAQAAAABAAgAAQBEAAIACgAUAAEABAGkAAIATQABAAQBpgACAE0ABAAAAAEACAABAB4AAgAKABQAAQAEAaUAAgBQAAEABAGnAAIAUAABAAIASgGjAAEAAAABAAgAAQAGAZUAAQABAEsAAQAAAAEACAABAAYBJwABAAEAugABAAAAAQAIAAEABgGsAAEAAQA2AAEAAAABAAgAAgAcAAIB4wHkAAEAAAABAAgAAgAKAAIB5QHmAAEAAgAvAE8AAQAAAAEACAACAB4ADAIoAioCKQIrAiwCHwIgAiEBrgIjAiQCJQABAAwAJwAoACsAMwA1AEYARwBIAEsAUwBUAFUAAQAAAAEACAACAAwAAwImAicCJwABAAMASQBLAa4AAQAAAAEACAACAGYACAI9Ai0CLgIwAjECOQI6AjwAAQAAAAEACAACABYACAAbABUAFgAXABgAGQAdABQAAQAIAa0CIgRwBHEEcgRzBHQEdQABAAAAAQAIAAIAFgAIBHUCIgRwBHEEcgRzAa0EdAABAAgAFAAVABYAFwAYABkAGwAdAAEAAAABAAgAAgAWAAgAFQAWABcAGAAZABsAHQAUAAEACAItAi4CMAIxAjkCOgI8Aj0AAQAAAAEACAABAAYBaQABAAEAEwAGAAAAAQAIAAMAAQASAAEAUgAAAAEAAABKAAIAAgF8AXwAAAHUAd0AAQABAAAAAQAIAAEAKAHAAAEAAAABAAgAAgAaAAoCMgB6AHMAdAIzAjQCNQI2AjcCOAACAAEAFAAdAAAAAQAAAAEACAACACYAEAHUAdUB1gHXAdgB2QHaAdsB3AHdAkACPgJBAkICPwThAAEAEAAUABUAFgAXABgAGQAaABsAHAAdAE0ATgKtA5oDnAQZ\",\n  \"Roboto-MediumItalic.ttf\": \"AAEAAAARAQAABAAQR1BPUyEcbY8AAhQcAABZakdTVULEnLdcAAJtiAAAGXxPUy8yoQuw+wAAAZgAAABgY21hcNhuDxIAABpsAAAGXGN2dCAElytKAAAjUAAAAFZmcGdte/lhqwAAIMgAAAG8Z2FzcAAIABMAAhQQAAAADGdseWZgubUGAAAtcAAB42poZG14LxpP7wAAFYAAAATsaGVhZPi2qwsAAAEcAAAANmhoZWEM2xKRAAABVAAAACRobXR4rRqYNAAAAfgAABOIbG9jYSKZqcwAACOoAAAJxm1heHAHEgLZAAABeAAAACBuYW1lRuRz4wACENwAAAMUcG9zdP9hAGQAAhPwAAAAIHByZXAbsfg2AAAihAAAAMwAAQAAAAIAALDh6v1fDzz1ABsIAAAAAADE8BEuAAAAANDbTpf6Qf3VCXgIcwACAAkAAgAAAAAAAAABAAAHbP4MAAAJN/pB/mwJeAgAAbMAAAAAAAAAAAAAAAAE4gABAAAE4gCPABYAVgAFAAEAAAAAAA4AAAIAAfIABgABAAMEGQH0AAUAAAWaBTMAAAEfBZoFMwAAA9EAZgIAAAACAAAAAAAAAAAA4AAK/1AAIX8AAAAhAAAAAEdPT0cAAQAA//0GAP4AAGYHmgIAIAABnwAAAAAEOgWwACAAIAACA5YAZAAKAAAACgAAAfkAAAH5AAACHwA3Ao4AoQTHADsEcwBCBb0AtQUAAC0BWgCQAr8AaALG/5QDeABnBF0APQG//4kClgA2AjUAMAMc/38EcwBgBHMA7wRzAAsEcwAmBHMACQRzAFoEcwBjBHMAhgRzADsEcwCOAhkAKwHi/5oD/AAyBGIAYgQUAC8D0ACVBvsAMgU0/6QE7wAnBRsAZQUcACcEbQAnBE0AJwVSAGsFjQAnAjsANQRZAAME7gAnBD0AJwbVACcFjAAnBWYAawUAACcFZgBkBOIAJwS5ACQEwACcBRkAWwUPAJsG3gC3BPP/wwTFAKEEtv/lAir/7wNIAKwCKv96A1sARAOK/3kCigDKBD0AIgRoABAEGgA4BGsAOwQ0ADsCygBfBHD/9wRZAA0CBQAfAfz/DAQXABECBQAfBssAEARbAA0EdQA5BGj/xwRyADsCxAAQBAsAHAKfADsEWgBKA+EAZAXOAHcD8f+5A9H/tQPx/+cCpAAwAf0AIAKk/5kFMgBbAfkAAAIY/+YEZQBMBJv/9gV8AAgExQBQAff/7ATc/9wDdADRBh4AXgOAAL4DzgBJBFUAgAKWADYGHgBeA8cA7wL9AOQEMwAbAukAVgLpAGcCkQDIBKH/3QPZAH0COwCeAgr/0wLpAOEDlQC+A84AAgWtALkGBgCxBjAAlgPQ/9IFNP+kBTT/pAU0/6QFNP+kBTT/pAU0/6QHVf+HBRsAZQRtACcEbQAnBG0AJwRtACcCOwA1AjsANQI7ADUCOwA1BTr//wWMACcFZgBrBWYAawVmAGsFZgBrBWYAawQtACMFZAAVBRkAWwUZAFsFGQBbBRkAWwTFAKEErwAnBMsAGwQ9ACIEPQAiBD0AIgQ9ACIEPQAiBD0AIgaXAA8EGgA4BDQAOwQ0ADsENAA7BDQAOwIUACICFAAiAhQAIgIUACIEjQBGBFsADQR1ADkEdQA5BHUAOQR1ADkEdQA5BHgAPQRvACoEWgBKBFoASgRaAEoEWgBKA9H/tQR+/80D0f+1BTT/pAQ9ACIFNP+kBD0AIgU0/6QEPQAiBRsAZQQaADgFGwBlBBoAOAUbAGUEGgA4BRsAZQQaADgFHAAnBQEAOwU6//8EiQA7BG0AJwQ0ADsEbQAnBDQAOwRtACcENAA7BG0AJwQ0ADwEbQAnBDQAOwVSAGsEcP/3BVIAawRw//cFUgBrBHD/9wVSAGsEcP/3BY0AJwRZAA0FjgAuBHcAKwI7ADUCFAAUAjsANQIUAB8COwA1AhQAIgI7/44CBf92AjsANQIUACIGlAA1BAEAHwRZAAMCIP8PBO4AJwQXABEEfwAhBD0AJwIFAB8EPQAnAgX/ogQ9ACcCmwAfBD0AJwLhAB8ETAAhAkcAHwWMACcEWwANBYwAJwRbAA0FjAAnBFsADQRbAA0FcgAjBG8AEQVmAGsEdQA5BWYAawR1ADkFZgBrBHUAOQeDAFAHDQBCBOIAJwLEABAE4gAnAsT/nATiACcCxAAQBLkAJAQLABwEuQAkBAsAHAS5ACQECwAcBLkAJAQLABwEwACcAp8AOwTAAJwCxwA7BMAAnAKf/+IFGQBbBFoASgUZAFsEWgBKBRkAWwRaAEoFGQBbBFoASgUZAFsEWgBKBRkAWwRaAEoG3gC3Bc4AdwTFAKED0f+1BMUAoQS2/+UD8f/nBLb/5QPx/+cEtv/lA/H/5wIGAB4FaABOAsT/SgVpAFsEhQA2BYMAWwTWAEoCIP8PBVIAawRw//cFjAAnBFsADQU0/6QEPQAiB1X/hwaXAA8FZAAVBG8AKgU0/6QEPQAiBG0AJwQ0ADsCO//JAhT/fgVmAGsEdQA5BOIAJwLEAAcFGQBbBFoASgS5ACQECwAcBMAAnAKfADsCIP8PBCUANgG5AIoD0gECA54BDQPIAO8DawD+AgUBAgKnAPoCRf+oA8QA3gMRAKwCY//uAAr9VAAK/dcACvz2AAr91gAK/L8ACvygAlUBLgQlAOgFNP+kAjsAngTR/74F8f/GAp//ygV6ABgFKf9YBVAAHQKgAAsFNP+kBO8AJwRdAC4Fnf+qBG0AJwS2/+UFjQAnBVoAXgI7ADUE7gAnBRr/sgbVACcFjAAnBHcAAAVmAGsFjwAuBQAAJwR3/9wEwACcBMUAoQXLAFIE8//DBYkAdQU8AAkCOwA1BMUAoQRrAD4ESAAoBG8AEQKgAG4ESABXBGsAPgSr/+UD+QB3BG8AOARIACgEBQBmBG8AEQSHAGwCoABuBH8AIQRS/6gEof/dA+EAZAP+AD4EdQA5BNcAXQRv/8sEIQA7BHcAOAQXAG4ESABXBa0AMgPx/7kFpwA/BmsAVAKgAEwESABXBHUAOQRIAFcGawBUBJkAUARjAG0Ex/8kBkoAVwRtACcEbQAnBdoAkQRdAC4FOgBnBLkAJAI7ADUCOwA1BFkAAwhQ/8oIVwAuBjQAoATuACcFhwAnBO0AmwWJACUFNP+kBOsAIwTvACcEXQAuBeL/hARtACcHcf+lBLsAHgWHACcFhwAnBQoALgWI/8oG1QAnBY0AJwVmAGsFjwAuBQAAJwUbAGUEwACcBO0AmwY4AFYE8//DBdUAJQVoAMUHawArB8YAKwX1AIkGzQAuBOoAIwUxAE8HJgAyBNv/sAQ9ACIEZQBDBHYAIgNKABgE2v+FBDQAOwZO/60EAQAWBH8AGQR/ABkEVgAiBIH/vwXfACIEfgAZBHUAOQR/ABkEaP/HBBoAOAPhAFMD0f+1BbAAPQPx/7kEuAAZBE4AcAZmABkGwQASBPoATwZIACIEUAAiBCUAIwZcACQEWP+2BDQAOwQ0ADsEWQANA0oAGAQlADsECwAcAgUAHwIUACIB/P8MBqf/vQa5ABkEcAANBFYAIgR/ABkD0f+1BH8AGQcbAGAGKQBEBOoAIwRPACEG+wArBd0AGQTv/64ESP+cBxQAPgYQADAGwgAUBcMAFgj1ADUHxgAiBAr/qgPc/7UFiQB1BacAPwVaAGIEbwA2BP0AqAP5AHcE/QCoA/kAdwk3AGsIRgA5BVoAZgRvADgHFwBiBh4ASwcbAGAGKQBEBP0AVgQzAEUE4wA4AAr85gAK/Q4ACv4rAAr+PAAK+kEACvpvBYcAJwR/ABkE6gAjBE8AIQT2ACcEbf/HBFIAIgOPABEEXf/8A0r/ywSdAC4ECgARB3H/pQZO/60EuwAeBAEAFgUKAC4EVgAiBQ4AIwSRACEFHgA3BC4AGQZsAKQFgwBsBY0AJwR+ABkHngAnBYkAEQgRAC4GygARBgUAZQTjAEsFGwBlBBoAOATAAJwD4QBTBMUAoQP5AHcExQChA/kAVATz/8MD8f+5BwQAnQVQAFYFaADFBE4AcAVUALkEWwCFBWcA5wRZAA0F/wBiBKj/9AX/AGIEqP/0AjsANQdx/6UGTv+tBQQAIwRgACEFiP/KBIH/vwWNAC4EbwARBY0AJwR+ABkFaADFBE4AcAbVACcF3wAiAjsANQU0/6QEPQAiBTT/pAQ9ACIHVf+HBpcADwRtACcENAA7BWgASAQlADYFaABIBCUANgdx/6UGTv+tBLsAHgQBABYEjAAvBIz/8AWHACcEfwAZBYcAJwR/ABkFZgBrBHUAOQVaAGIEbwA2BVoAYgRvADYFMQBPBCUAIwTtAJsD0f+1BO0AmwPR/7UE7QCbA9H/tQVoAMUETgBwBF0ALgNKABgGzQAuBkgAIgSsADMDQwAJBPP/wwPx/7kE8//DA/H/uQTqADAEawA7BsYARQayAEcGLACqBQoAYQRjAJIEJwCMB43/3gZ0/94HygAnBnUACwTnAEwEFgA9BYkAkAUAAHMFNgBWBEgAKAWI/8oEgf+/BTT/pAQ9ACIE7wAnBGgAEAUcACcEawA7BRwAJwRrADsFjQAnBFkADQTuACcEFwARBO4AJwQXABEEPQAnAgX/5AbVACcGywAQBtUAJwbLABAFjAAnBFsADQUAACcEaP/HBOIAJwLE/94EuQAkBAsAHATAAJwCnwA7BQ8AmwPhAGQFDwCbA+EAZAbeALcFzgB3Bt4AtwXOAHcG3gC3Bc4AdwbeALcFzgB3BLb/5QPx/+cFNP+kBD0AIgU0/6QEPQAiBTT/pAQ9ACIFNP+kBD0AIgU0/6QEPQAiBTT/pAQ9ACIFNP+kBD0AIgU0/6QEPQAiBTT/pAQ9ACIFNP+kBD0AIgU0/6QEPQAiBTT/pAQ9ACIEbQAnBDQAOwRtACcENAA7BG0AJwQ0ADsEbQAnBDQAOwRtACcENAA7BG0AJwQ0ADsEbQAnBDQAOwRtACcENAA7AjsANQIUACICO///AgX/5AVmAGsEdQA5BWYAawR1ADkFZgBrBHUAOQVmAGsEdQA5BWYAawR1ADkFZgBrBHUAOQVmAGsEdQA5BWkAWwSFADYFaQBbBIUANgVpAFsEhQA2BWkAWwSFADYFaQBbBIUANgUZAFsEWgBKBRkAWwRaAEoFgwBbBNYASgWDAFsE1gBKBYMAWwTWAEoFgwBbBNYASgWDAFsE1gBKBMUAoQPR/7UExQChA9H/tQTFAKED0f+1BMUAoQPR/7UFrP6zAx4A7AP/AAAH9AAAA/8AAAf0AAACrgAAAgQAAAFcAAAEZgAAAikAAAGfAAAA1QAAAAoAAAKXADYClwA2BQsAnAYKAIIGCgCCA4v/TgG9AK4BuQCKAcr/pAGlAM0DBgC3Aw0AlwL7/6EERQBpBID/+wLAAJ4D5QAzBYUAMwFrADYHdgCdAVoAkAKOAKECaQBdAmD/+QQ+ADcDiv/hAukAYwNMAG4ETf/DBJv/9gZJAA0GjgArCFsAJwdYACoGZAAQBIn/9ARzAE4F0QBCBB4AOwSIABAFP//kBV3/5gXBAMIDzgAxB/kAIwTsAO0E9wB9Bg8AtgayAIIGpwCIBnkAtQR4AEUFdQAfBL7/pwRqAJwEmAA0CA8ASQIm/xcEdQAwBGIAYgP8/9UEFAAXA/cAOgJTAGkCjgBmAez/zwT+AF8EjgBLBKIAXwb2AF8G9gBfBPQAXwaNABcACgAAB/v/qQg1AFwDhv/XBGP/pwSmADoEY/+nA6YACgQ2AC0ETgARBB4ADgQXABQFGwAuBBoAFAUKAC4FJgAuBKEAOwQl/4cCpwEGBL0ACgLpADMC6QAIAukAIwLpABYC6QAKAun/8QLp//QC6f/jAukAbQLpABcEBP/ZBXwAQwU1AHAEyAAAA6YAkwXjAIwEYwBwBGsAOQQlAGIEHgAOBEUACgSmADcEVQAKBKYAOgTCAAoF4gAKA6YACgREAAoDwv/yAfcAGATDAAoEjAA/A7IACgPMAAoEYgAKBGcAOQRIAAoEhf+bAf8A6wOPAQQD9gDcA/YAEwP2ANgD9gDXA48BBAOPAQUDjwEEBEb/pAQlAG0EZwA5BXAAYgQdAFUEegAqAgr/BwGw/7IEFP/WByb/wQcpAAoFdgBiBLwACgRZAAsFOv+DBhT/qQQvAAwEyAALBEUACgSw/8EELwByBT4ACgRzAF0GXAAKBt4ACgU7AEoF+wALBE8ACwRnABMGagAKBG//0gQM//UGav+pBIQACgT9AAoFTgBiBcwAQARDAG0Eqf+kBmwAYgRzAF0EcwAKBdoANwS3ADQELwAMBKYAOgROAAQD4wAeCAEACgTP/9kEbwAQBCYANwR/ADsDkgCkBIcANAR7/8cEhgA7BDQAOwRwADAFWgBvBYEAcQVmAC4FvQByBb8AcgQFAKsEaQAfA6YACgRA/38EpP/RAukAigLpAGQC6QB9AukAiQLpAJYC6QB7AukApgRT/9QEGAAnBm8AOgSaAEcEzwBOAiD/DwIg/w8CFQAiAhX/fQIVACIESAAKBGL/lwRi/5cEJQBiBIX/mwSF/5sEhf+bBIX/mwSF/5sEhf+bBIX/mwRnADkDzAAKA8wACgPMAAoDzAAKAfcAGAH3ABgB9wAYAfcAGATCAAoEpgA6BKYAOgSmADoEpgA6BKYAOgRrADkEmwB0BIcAjgRzAFoEcwAJBHMAJgRzAAsEawA5BGsAOQRrADkEJQBtBIX/mwSF/5sEhf+bBGcAOQRnADkEZwA5BGcAOQRiAAoDzAAKA8wACgPMAAoDzAAKA8wACgSMAD8EjAA/BIwAPwSMAD8EwwAKAfcADQH3ABgB9wAYAff/igH3ABgDwv/yBEQACgOmAAoDpgAKA6YACgOmAAoEwgAKBMIACgTCAAoEpgA6BKYAOgSmADoERQAKBEUACgRFAAoEHgAOBB4ADgQeAA4EHgAOBCUAYgQlAGIEJQBiBGsAOQRrADkEawA5BGsAOQRrADkEawA6BeMAjAQlAG0EJQBtBBT/1gQU/9YEFP/WBIX/mwQI/20E//94AjP/ewSw/9IEYf8sBNL/4gSF/5sESAAKA8wACgQU/9YEwwAKAfcAGAREAAoF4gAKBKYAOgRVAAoEJQBiBCUAbQRG/6QB9wAYBCUAbQPMAAoDpgAKBB4ADgH3ABgB9wAYA8L/8gREAAoELwByBIX/mwRIAAoDpgAKA8wACgTIAAsF4gAKBMMACgSmADoEvQAKBFUACgRnADkEJQBiBEb/pAQvAA0EwwAKBGcAOgQlAG0F2gA3BMgACwQvAHIFfABDBTT/pAQ9ACIEbQAnBDQAOwIU/+QAAAABAAAE5AkKBAAAAgICAwUFBgYCAwMEBQIDAgQFBQUFBQUFBQUFAgIEBQUECAYGBgYFBQYGAwUGBQgGBgYGBgUFBgYIBgUFAgQCBAQDBQUFBQUDBQUCAgUCCAUFBQUDBQMFBAcEBAQDAgMGAgIFBQYFAgUEBwQEBQMHBAMFAwMDBQQDAgMEBAYHBwQGBgYGBgYIBgUFBQUDAwMDBgYGBgYGBgUGBgYGBgUFBQUFBQUFBQcFBQUFBQICAgIFBQUFBQUFBQUFBQUFBAUEBgUGBQYFBgUGBQYFBgUGBgYFBQUFBQUFBQUFBQYFBgUGBQYFBgUGBQMCAwIDAgMCAwIHBQUCBgUFBQIFAgUDBQMFAwYFBgUGBQUGBQYFBgUGBQgIBgMGAwYDBQUFBQUFBQUFAwUDBQMGBQYFBgUGBQYFBgUIBwUEBQUEBQQFBAIGAwYFBgUCBgUGBQYFCAcGBQYFBQUDAgYFBgMGBQUFBQMCBQIEBAQEAgMDBAMDAAAAAAAAAwUGAwUHAwYGBgMGBgUGBQUGBgMGBggGBQYGBgUFBQcGBgYDBQUFBQMFBQUEBQUFBQUDBQUFBAQFBQUFBQUFBgQGBwMFBQUHBQUFBwUFBwUGBQMDBQkJBwYGBgYGBgYFBwUIBQYGBgYIBgYGBgYFBgcGBwYICQcIBgYIBQUFBQQFBQcFBQUFBQcFBQUFBQQEBgQFBQcIBgcFBQcFBQUFBAUFAgICBwgFBQUEBQgHBgUIBwYFCAcIBgoJBQQGBgYFBgQGBAoJBgUIBwgHBgUGAAAAAAAABgUGBQYFBQQFBAUFCAcFBQYFBgUGBQcGBgUJBgkIBwYGBQUEBQQFBAYECAYGBQYFBgUHBQcFAwgHBgUGBQYFBgUGBQgHAwYFBgUIBwUFBgUGBQgHBQUFBQYFBgUGBQYFBgUGBQYEBgQGBAYFBQQIBwUEBgQGBAYFCAgHBgUFCQcJBwYFBgYGBQYFBgUGBQYFBgUGBQYFBgUFAggICAgGBQYFBgMFBQUDBgQGBAgHCAcIBwgHBQQGBQYFBgUGBQYFBgUGBQYF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RvpHAkcKRzFHXkdmR25HdkgASAhIEEg9SEVITUiPSJdIx0jPSQ1JFUkdSZtJo0oDSnJKhUqYSqpKvErOSt9K9Et+S/lMLUytTT5Nm03qTnFOok6qTwVPDU8VT4xPlE/sUE9Qt1EnUW9RulIqUjJSlFMPUyJTNFNGU1hTalPqVERUUFTPVOZU+VVhVXhV91ZtVnVWiFaQVw5XhVfgV/dYDlggWF9YZ1jDWMtY01ksWTRZoVopWmRadlp+Wspa0lraWuJa6lryWvpbAltHW8JbylwCXElciVzVXTBdmF3pXmle9V9VX11f22BcYINg3GDkYVNh6WIkYjZiiGLRYxxjdWN9Y61jtWQLZDhkQGTgZOhlIGVoZahl8GZLZrFnAGdzZ/5oXWh0aIZpBWkcaYVpjWmVaahpsGopaqBrCmshazhrSWuIa/lsZWzSbUBty25YbqVu9G9hb9BwSHC6cUxx3HJ5cyhzMHM4c7V0JXRpdK50xnTedOp09nVqddh2s3eIeBh4qHkFeV95k3mweel6AHoXevJ7YXt8e5d8BHxzfM99S317faV95n4ofoR+037ffut+938Dfw9/G391f8yALICKgNyBM4E/gUuBmIHpgk+CqYNUg++D+4QHhBOEH4QnhC+Ee4TLhNeE44UshXKFfoWKheGGMYZ2hn6HAIeNh5mHpYeth7+H0YgziI6ImoimiQmJZ4lziX+Ji4mXiaOJr4m3icmJ24nuigGKCYoRiiOKNIqniq+KworUiueK+osNix+Lhovni/6MFIwnjDqMTYxfjGeMb4yCjJSMp4y5jMuM3IzvjQGNFI0sjT+NUY1djWmNhY2hjbCNwI3MjdiOMo6JjtyO5I9Oj+eQY5DakU2Ru5Iukp2TEJOCk+OUOpSTlOqVb5V3lYOVj5WblaeVs5W/lcuV15Xjle+V+5YHlhmWK5Y3lkOWT5ZblnKWhJaQlpyWqJa0lsaW2JbklvCW/JcIlxSXIJcyl0OXT5dbl3KXiZegl7eXypfdl+mX9ZgBmA2YGZglmDeYSZhhmHiYkJinmL+Y1pjumQWZIJk6mVKZaZl8mY6ZoZmzmcaZ2Jnzmg6aGpommjiaSppcmm2ahZqcmrSay5rjmvqbEpspm0SbXptwm4Kbjpuam6abspvEm9ab7pwFnB2cNJxMnGOce5ySnK2cx5zenPWdDJ0jnTqdUZ1o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A/wDXgAA////pP5sBK4FsAImACUAAAAHAXABbwAD//8AIv5wA9wEUAImAEUAAAAHAXAAqQAH//8AJ/6bBLwFsAImACYAAAAHAXYElwAK//8AEP6IBA8GAAImAEYAAAAHAXYEpf/3//8AJ/6bBOAFsAImACgAAAAHAXYEcwAK//8AO/6RBIgGAAImAEgAAAAHAXYEkAAA//8AJ/35BOAFsAImACgAAAAHA6sBAf6S//8AO/35BIgGAAImAEgAAAAHA6sBHv6S//8AJ/6bBYcFsAImACwAAAAHAXYFAAAK//8ADf6bA/kGAAImAEwAAAAHAXYEfwAK//8AJwAABXEHNgImAC8AAAEHAHcBpQE2AAkAsAQvsA/cMDEA//8AEQAABHUHPQImAE8AAAEHAHcBowE9AAkAsAQvsA/cMDEA//8AJ/7cBXEFsAImAC8AAAAHAXYE0QBL//8AEf7HBEoGAAImAE8AAAAHAXYEYAA2//8AJ/6bA8MFsAImADAAAAAHAXYElwAK////5P6bAhcGAAImAFAAAAAHAXYDRAAK//8AJwAABs4HNgImADEAAAEHAHcCvgE2ABMAsABFWLACLxuxAh8+WbAR3DAxAP//ABAAAAZoBgACJgBRAAABBwB3ApgAAAAJALADL7Ak3DAxAP//ACf+mwbOBbACJgAxAAAABwF2BasACv//ABD+mwZoBFICJgBRAAAABwF2Ba4ACv//ACf+lwWGBbACJgAyAAAABwF2BQIABv//AA3+mwP6BFICJgBSAAAABwF2BGwACv//ACcAAAUEB0ICJgA0AAABBwB3AasBQgAJALADL7AW3DAxAP///8f+YARtBfcCJgBUAAABBwB3AZv/9wAJALANL7Ah3DAxAP//ACf+mwTYBbACJgA2AAAABwF2BJgACv///97+mwLvBFMCJgBWAAAABwF2Az4ACv//ACT+kQS7BccCJgA3AAAABwF2BLAAAP//ABz+iAPEBFACJgBXAAAABwF2BGL/9///AJz+lAUiBbACJgA4AAAABwF2BJ8AA///ADv+kQKuBUECJgBYAAAABwF2A/UAAP//AJsAAAWBBzcCJgA6AAABBwFuAN0BQwAJALABL7AR3DAxAP//AGQAAAQNBewCJgBaAAABBgFuFvgACQCwAS+wEdwwMQD//wCb/psFgQWwAiYAOgAAAAcBdgTV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AesB7AHtAe4B7wHwAfEB8gJSAlQCWAJaAlwCXgJiAmQCagJsAnACcgJ0AnYCegJ8An4CgAKaAqICpAKqArADhwOOA5MDlgACAAAAAgAKO9oAAQNsAAQAAAGxBtI6+jr6BvwHUjfeI2I7mDuqOHYHWDiWOJY43jTeDqg4ljiWO6omhAqSCxQ1MDjeNI43uDdKOOQPYgt+OFQ2GjiMC8AM6gz0N643rji4NhoO1g3qOW4OTDeoOW4OZjfeN9433jfeN9433juYOHY4djh2OHY4ljiWOJY4ljuqOJY7qjuqO6o7qjuqON443jjeON445DhUOFQ4VDhUOFQ4VDiMOIw4jDiMN644uDi4OLg4uDi4OW42GjluN944VDfeOFQ33jhUO5g7mDuYO5g7qjuqOHY4jDh2OIw4djiMOHY4jDh2OIw4ljeuOJY4ljiWOJY4ljjeNN4OqA6oDqgOqDiWN644ljeuOJY3rjeuO6o4uDuqOLg7qji4DtYO1g7WNTA1MDUwON443jjeON443jjeN7g45DluOOQPYg9iD2I33jhUNTAO6Dr6N944djiWOJY7qjjkN94jYjZ+N944dg9iOJY7qjiWNN433jiWOJYPhDuqJoQQfjUwOOQRfDdKElo4ljjkN64S+DluEv43rhW8OW4Xlji4GKgYwhjIGM4ayBrOGwQbNji4OHY4dhu0Nn44ljiWON4dKh7cIJo03jY0OJY33iHQI2I2fiNsOHY3SiW6OJY03jiWOJY4ljuqJoQ7mDUwNjQ3SjiWOJYmpihAND4pHingKm44VCrMK6Y3QCwwOIw3qCz6LSQ4uDYaLoo5bjYaN6gxEDFOMoA0aDYaMwI4jDiMN0AziDOyNAg5bjQ+NGg33ji4NI45bjSOOW40tDYaNn43QDZ+N0o3qDTeNN403jTeOJY7mDUwOOQ5bjjkN0o3qDeuOJY3SjeoOJY4ljiWN944VDfeOFQ4djiMOIw4jDdKN6g7qji4OLg2GjY0OW42NDluNjQ5bjZ+N0A3QDdKN6g33jhUOJY3rje4N7g3uDfeOFQ33jhUN944VDfeOFQ33jhUN944VDfeOFQ33jhUN944VDfeOFQ33jhUN944VDh2OIw4djiMOHY4jDh2OIw4djiMOHY4jDh2OIw4djiMOJY4ljuqOLg7qji4O6o4uDuqOLg7qji4O6o4uDuqOLg4uDjeON445DluOOQ5bjjkOW445DluO6o6+jmIOvo6+jr6Ovo6+jsAOwo7HDsuO0A7XjtoO3I7mDuqO6oAAQGxAAQABgALAAwAEwAlACYAJwAoACkAKgAsAC0ALgAvADAAMQAyADMANAA1ADYAOAA5ADoAOwA8AD0APgA/AEUARgBJAEoATABPAFEAUgBTAFQAVgBYAFoAWwBcAF0AXwCDAIQAhQCGAIcAiACKAIsAjACNAI4AjwCQAJEAkgCTAJQAlQCWAJcAmACZAJwAnQCeAJ8AoACjAKQApQCmAKcAqACrAKwArQCuALQAtQC2ALcAuAC5AMAAwQDCAMMAxADFAMYAxwDIAMkAywDNAM8A0QDTANUA1gDXANgA2QDaANsA3ADdAN4A5wDoAOsA7QDvAPEA8wD3APkA/AD+AQABAgEGAQcBCAEJAQoBCwEMAQ8BEAERARIBEwEUARgBGgEcASUBJwEpASsBLQEvATEBMwE1ATcBOQE6ATsBPAE+AUABTgFPAWIBZQFmAXkBewF8AX0BfgF/AYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZIBkwGUAZUBlgGXAZgBmgGbAZ4BoQGjAaYBpwGpAa0BrgGvAbEBsgGzAbQBtQG2AbgBuQG8AcMBxAHFAcYByQHKAcsBzAHNAc4BzwHRAdIB0wHUAdUB1gHXAdgB2QHaAdsB3QHeAd8B4AHhAeMB5AHlAeYB6AHpAesB7AHtAe8B8AHxAfIB8wH0AfUB9gH3AfgB+QH6Af0CAQIDAgUCBgIHAggCCQIMAg0CDwIQAhECEwIUAhYCFwIcAh0CIQIlAiYCKQI2AjcCOAI5AjoCRAJRAlICUwJUAlgCWQJcAl4CYAJiAmQCbAJuAnACcQJyAnQCdQJ9AoICgwKEAosCjwKRApICkwKUApUCmAKZApsCnQKeAp8CqAKpAq0CrwKwArECsgKzArQCtQK4ArkCvQK+Ar8C1gLXAuYC5wL4AvoC/AMCAwMDBAMFAwYDBwMIAwkDCgMLAwwDDQMOAw8DEAMRAxIDEwMUAxUDFgMXAxgDGQMaAxsDHAMdAx4DHwMgAyEDIgMjAyQDJQMmAycDKAMpAyoDLAMuAy8DMAMxAzIDMwM0AzUDNgM3AzgDOQM6AzsDQwNGA0gDVANVA1YDVwNYA1kDWgNbA1wDcANxA3MDdAN1A34DfwPZA9sD3APeA+ED4gPpA+wEMQQzBDQACgA4/8QBJf/EASf/xAFi/8QBxf/EAc7/xAHl/8QCYv/EAm7/xAJ2/8QAFQA6ABQAOwAmAD0AFgCgABYBNwAmATkAFgE7ABYBfwAWAZUAFgGbABYCNwAUAjkAFAJwABYCcgAWAvgAJgL6ACYC/AAmA1QAFgNWABYDWAAWA1oAFgABABP/CADOABD+7gAS/u4AJf9AAC7/MAA4ABQARf/eAEf/6wBI/+sASf/rAEv/6wBT/+sAVf/rAFb/5gBZ/+oAWv/oAF3/6ACD/0AAhP9AAIX/QACG/0AAh/9AAIj/QACj/94ApP/eAKX/3gCm/94Ap//eAKj/3gCq/+sAq//rAKz/6wCt/+sArv/rALX/6wC2/+sAt//rALj/6wC5/+sAvP/qAL3/6gC+/+oAv//qAMD/6ADC/+gAw/9AAMT/3gDF/0AAxv/eAMf/QADI/94Ayv/rAMz/6wDO/+sA0P/rANL/6wDW/+sA2P/rANr/6wDc/+sA3v/rAOD/6wDi/+sA5P/rAOb/6wD3/zABEP/rARL/6wEU/+sBFv/rASUAFAEnABQBLP/qAS7/6gEw/+oBMv/qATT/6gE2/+oBOv/oAUb/6wFI/+oBTv9AAU//3gFiABQBef9AAYL/QAGF/0ABjP9AAZz/6wGg/+oBof/rAaP/6AGt/+gBr//rAbL/6wGz/+sBtf/qAbv/6gG8/+sBvf/qAcUAFAHL/zABzgAUAdP/QAHlABQB8//eAfj/6wIB/+sCBP/rAgb/6AIH/+sCE//rAhT/6wIX/+sCIf/oAin/QAI2/+sCOP/oAjr/6AI8/+sCQP/rAkT/6wJiABQCa//rAm3/6wJuABQCcf/oAnYAFAKS/0ACk//eApT/QAKV/94Cmf/rApv/6wKd/+sCqf/rAqv/6wKt/+sCsf/oArP/6AK1/+gCw//rAsT/6wLF/+sCz//rAtb/QALX/94DAv9AAwP/3gME/0ADBf/eAwb/QAMH/94DCP9AAwn/3gMK/0ADC//eAwz/QAMN/94DDv9AAw//3gMQ/0ADEf/eAxL/QAMT/94DFP9AAxX/3gMW/0ADF//eAxj/QAMZ/94DG//rAx3/6wMf/+sDIf/rAyP/6wMl/+sDJ//rAyn/6wMv/+sDMf/rAzP/6wM1/+sDN//rAzn/6wM7/+sDPf/rAz//6wNB/+sDQ//rA0X/6wNH/+oDSf/qA0v/6gNN/+oDT//qA1H/6gNT/+oDVf/oA1f/6ANZ/+gDW//oA3L+7gN2/u4Dev7uA3v+7gPs/8AAIAA4/98AOv/kADv/7AA9/90AoP/dASX/3wEn/98BN//sATn/3QE7/90BYv/fAX//3QGV/90Bm//dAcX/3wHO/98B5f/fAjf/5AI5/+QCYv/fAm7/3wJw/90Ccv/dAnb/3wL4/+wC+v/sAvz/7ANU/90DVv/dA1j/3QNa/90D7AAOABoAOP/OADr/7QA9/9AAoP/QASX/zgEn/84BOf/QATv/0AFi/84Bf//QAZX/0AGb/9ABxf/OAc7/zgHl/84CN//tAjn/7QJi/84Cbv/OAnD/0AJy/9ACdv/OA1T/0ANW/9ADWP/QA1r/0AAQAC7/7gA5/+4AnP/uAJ3/7gCe/+4An//uAPf/7gEr/+4BLf/uAS//7gEx/+4BM//uATX/7gHL/+4DRv/uA0j/7gBKAAYAEAALABAADQAUAEEAEgBH/+gASP/oAEn/6ABL/+gAVf/oAGEAEwCq/+gAq//oAKz/6ACt/+gArv/oAMr/6ADM/+gAzv/oAND/6ADS/+gA1v/oANj/6ADa/+gA3P/oAN7/6ADg/+gA4v/oAOT/6ADm/+gBFv/oAUb/6AFmABABnP/oAaH/6AGy/+gBs//oAfj/6AIE/+gCB//oAhP/6AIU/+gCF//oAjz/6AJA/+gCRP/oAmv/6AJt/+gCmf/oApv/6AKd/+gCq//oAsP/6ALE/+gCxf/oAs//6AMb/+gDHf/oAx//6AMh/+gDI//oAyX/6AMn/+gDKf/oAz3/6AM//+gDQf/oA0X/6ANwABADcQAQA3MAEAN0ABADdQAQA34AEAN/ABAAAgIF/9YDcf+YAD0AR//sAEj/7ABJ/+wAS//sAFX/7ACq/+wAq//sAKz/7ACt/+wArv/sAMr/7ADM/+wAzv/sAND/7ADS/+wA1v/sANj/7ADa/+wA3P/sAN7/7ADg/+wA4v/sAOT/7ADm/+wBFv/sAUb/7AGc/+wBof/sAbL/7AGz/+wB+P/sAgT/7AIH/+wCE//sAhT/7AIX/+wCPP/sAkD/7AJE/+wCa//sAm3/7AKZ/+wCm//sAp3/7AKr/+wCw//sAsT/7ALF/+wCz//sAxv/7AMd/+wDH//sAyH/7AMj/+wDJf/sAyf/7AMp/+wDPf/sAz//7ANB/+wDRf/sABgAU//iALX/4gC2/+IAt//iALj/4gC5/+IBEP/iARL/4gEU/+IBr//iAbz/4gIB/+ICNv/iAqn/4gKt/+IDL//iAzH/4gMz/+IDNf/iAzf/4gM5/+IDO//iA0P/4gNxABgABgAQ/4QAEv+EA3L/hAN2/4QDev+EA3v/hAAQAC7/7AA5/+wAnP/sAJ3/7ACe/+wAn//sAPf/7AEr/+wBLf/sAS//7AEx/+wBM//sATX/7AHL/+wDRv/sA0j/7AALAFv/zAPW/9cD1/+4A9j/7gPZ/70D3P/yA97/8gPm//ED6v/zA+wAEwP3/7cABABKABQAWAAyAFsAEQNxABAAHgAG//IAC//yAFr/8wBd//MAwP/zAML/8wE6//MBZv/yAaP/8wGt//MCBf/1Agb/8wIh//MCOP/zAjr/8wJx//MCsf/zArP/8wK1//MDVf/zA1f/8wNZ//MDW//zA3D/8gNx//IDc//yA3T/8gN1//IDfv/yA3//8gAIAFv/5QGW/8sBuP/kA9z/7APe/+wD5v/rA+r/7QPsAA0APgAn//MAK//zADP/8wA1//MAiv/zAJX/8wCW//MAl//zAJj/8wCZ//MAm//zAMn/8wDL//MAzf/zAM//8wDf//MA4f/zAOP/8wDl//MBD//zARH/8wET//MBFf/zAUX/8wFS//MBfv/zAYn/8wGQ//MBqwANAcf/8wHh//MB5P/zAiP/8wI1//MCO//zAj3/8wI///MCQf/zAkP/8wJq//MCbP/zAqj/8wKq//MCrP/zAs7/8wMu//MDMP/zAzL/8wM0//MDNv/zAzj/8wM6//MDPP/zAz7/8wNA//MDQv/zA0T/8wNc//MEMf/zBDL/8wQ0//MENf/zAD8AJ//mACv/5gAz/+YANf/mAIr/5gCV/+YAlv/mAJf/5gCY/+YAmf/mAJv/5gDJ/+YAy//mAM3/5gDP/+YA3//mAOH/5gDj/+YA5f/mAQ//5gER/+YBE//mARX/5gFF/+YBUv/mAX7/5gGJ/+YBkP/mAZb/wgGrABABx//mAeH/5gHk/+YCI//mAjX/5gI7/+YCPf/mAj//5gJB/+YCQ//mAmr/5gJs/+YCqP/mAqr/5gKs/+YCzv/mAy7/5gMw/+YDMv/mAzT/5gM2/+YDOP/mAzr/5gM8/+YDPv/mA0D/5gNC/+YDRP/mA1z/5gQx/+YEMv/mBDT/5gQ1/+YANwAl/+QAPP/SAD3/0wCD/+QAhP/kAIX/5ACG/+QAh//kAIj/5ACg/9MAw//kAMX/5ADH/+QBOf/TATv/0wFO/+QBef/kAX//0wGC/+QBhf/kAYz/5AGV/9MBl//SAZv/0wGr/+IB0//kAdn/0gHo/9ICKf/kAlj/0gJw/9MCcv/TAnT/0gKD/9ICkv/kApT/5AKe/9ICvv/SAtb/5AMC/+QDBP/kAwb/5AMI/+QDCv/kAwz/5AMO/+QDEP/kAxL/5AMU/+QDFv/kAxj/5ANU/9MDVv/TA1j/0wNa/9MAJwAQ/0YAEv9GACX/zQCD/80AhP/NAIX/zQCG/80Ah//NAIj/zQDD/80Axf/NAMf/zQFO/80Bef/NAYL/zQGF/80BjP/NAbH/8gHT/80CKf/NApL/zQKU/80C1v/NAwL/zQME/80DBv/NAwj/zQMK/80DDP/NAw7/zQMQ/80DEv/NAxT/zQMW/80DGP/NA3L/RgN2/0YDev9GA3v/RgABAasADgCvAEf/3ABI/9wASf/cAEv/3ABR/8EAUv/BAFP/1gBU/8EAVf/cAFn/3QBa/+EAXf/hAKr/3ACr/9wArP/cAK3/3ACu/9wAtP/BALX/1gC2/9YAt//WALj/1gC5/9YAvP/dAL3/3QC+/90Av//dAMD/4QDC/+EAyv/cAMz/3ADO/9wA0P/cANL/3ADW/9wA2P/cANr/3ADc/9wA3v/cAOD/3ADi/9wA5P/cAOb/3AEH/8EBCf/BAQv/wQEM/8EBEP/WARL/1gEU/9YBFv/cASz/3QEu/90BMP/dATL/3QE0/90BNv/dATr/4QFG/9wBSP/dAZz/3AGe/8EBoP/dAaH/3AGj/+EBpf/mAaf/wQGo/+sBqf/pAa3/4QGu//ABr//WAbD/5wGy/9wBs//cAbT/4wG1/90Btv/OAbj/1AG5/9sBu//dAbz/1gG9/90B9v/BAfj/3AH7/8EB/P/BAf3/wQH//8ECAP/BAgH/1gIC/8ECA//BAgT/3AIG/+ECB//cAgn/wQIL/8ECDP/BAg//wQIR/8ECE//cAhT/3AIW/8ECF//cAh3/wQIf/8ECIP/BAiH/4QI2/9YCOP/hAjr/4QI8/9wCQP/cAkT/3AJN/8ECXf/BAmX/wQJn/8ECa//cAm3/3AJx/+ECiv/BAoz/wQKQ/8ECmf/cApv/3AKd/9wCpf/BAqf/wQKp/9YCq//cAq3/1gKx/+ECs//hArX/4QK5/8ECu//BAr3/wQLD/9wCxP/cAsX/3ALP/9wC5//BAxv/3AMd/9wDH//cAyH/3AMj/9wDJf/cAyf/3AMp/9wDL//WAzH/1gMz/9YDNf/WAzf/1gM5/9YDO//WAz3/3AM//9wDQf/cA0P/1gNF/9wDR//dA0n/3QNL/90DTf/dA0//3QNR/90DU//dA1X/4QNX/+EDWf/hA1v/4QB2AAb/2gAL/9oAR//wAEj/8ABJ//AAS//wAFX/8ABZ/+8AWv/cAF3/3ACq//AAq//wAKz/8ACt//AArv/wALz/7wC9/+8Avv/vAL//7wDA/9wAwv/cAMr/8ADM//AAzv/wAND/8ADS//AA1v/wANj/8ADa//AA3P/wAN7/8ADg//AA4v/wAOT/8ADm//ABFv/wASz/7wEu/+8BMP/vATL/7wE0/+8BNv/vATr/3AFG//ABSP/vAWb/2gGc//ABoP/vAaH/8AGj/9wBqP/sAasADwGt/9wBsP/qAbL/8AGz//ABtP/OAbX/7wG2/+cBu//vAb3/7wH4//ACBP/wAgb/3AIH//ACE//wAhT/8AIX//ACIf/cAjj/3AI6/9wCPP/wAkD/8AJE//ACa//wAm3/8AJx/9wCmf/wApv/8AKd//ACq//wArH/3AKz/9wCtf/cAsP/8ALE//ACxf/wAs//8AMb//ADHf/wAx//8AMh//ADI//wAyX/8AMn//ADKf/wAz3/8AM///ADQf/wA0X/8ANH/+8DSf/vA0v/7wNN/+8DT//vA1H/7wNT/+8DVf/cA1f/3ANZ/9wDW//cA3D/2gNx/9oDc//aA3T/2gN1/9oDfv/aA3//2gBEABAADAASAAwAR//nAEj/5wBJ/+cAS//nAFX/5wCq/+cAq//nAKz/5wCt/+cArv/nAMr/5wDM/+cAzv/nAND/5wDS/+cA1v/nANj/5wDa/+cA3P/nAN7/5wDg/+cA4v/nAOT/5wDm/+cBFv/nAUb/5wGc/+cBof/nAasADwGy/+cBs//nAfj/5wIE/+cCB//nAhP/5wIU/+cCF//nAjz/5wJA/+cCRP/nAmv/5wJt/+cCmf/nApv/5wKd/+cCq//nAsP/5wLE/+cCxf/nAs//5wMb/+cDHf/nAx//5wMh/+cDI//nAyX/5wMn/+cDKf/nAz3/5wM//+cDQf/nA0X/5wNyAAwDdgAMA3oADAN7AAwABgG0/+oB9//uAgX/1QIP/+0CY//sAtH/7AABAgX/wAABAbQAIAB+AAYADAALAAwAR//oAEj/6ABJ/+gASgAMAEv/6ABT/+oAVf/oAFoACwBdAAsAqv/oAKv/6ACs/+gArf/oAK7/6AC1/+oAtv/qALf/6gC4/+oAuf/qAMAACwDCAAsAyv/oAMz/6ADO/+gA0P/oANL/6ADW/+gA2P/oANr/6ADc/+gA3v/oAOD/6ADi/+gA5P/oAOb/6AEQ/+oBEv/qART/6gEW/+gBOgALAUb/6AFmAAwBnP/oAaH/6AGjAAsBq/+QAa0ACwGv/+oBsAALAbL/6AGz/+gBtAAMAbz/6gH4/+gCAf/qAgT/6AIGAAsCB//oAhP/6AIU/+gCF//oAiEACwI2/+oCOAALAjoACwI8/+gCQP/oAkT/6AJr/+gCbf/oAnEACwKZ/+gCm//oAp3/6AKp/+oCq//oAq3/6gKxAAsCswALArUACwLD/+gCxP/oAsX/6ALP/+gDG//oAx3/6AMf/+gDIf/oAyP/6AMl/+gDJ//oAyn/6AMv/+oDMf/qAzP/6gM1/+oDN//qAzn/6gM7/+oDPf/oAz//6ANB/+gDQ//qA0X/6ANVAAsDVwALA1kACwNbAAsDcAAMA3EADANzAAwDdAAMA3UADAN+AAwDfwAMA9cADQPZAA4D2v/1A9z/7APe/+0D5v/sA+r/7gPs/78D9wANAAECBf/iAA0AXP/tAF7/7QE9/+0BP//tAUH/7QH5/+0CBf/AAgj/7QJZ/+0Cdf/tAoT/7QKf/+0Cv//tAAwAXP/yAF7/8gE9//IBP//yAUH/8gH5//ICCP/yAln/8gJ1//IChP/yAp//8gK///IAHwBa//QAXP/yAF3/9ABe//MAwP/0AML/9AE6//QBPf/zAT//8wFB//MBo//0Aa3/9AH5//ICBv/0Agj/8gIh//QCOP/0Ajr/9AJZ//ICcf/0AnX/8gKE//ICn//yArH/9AKz//QCtf/0Ar//8gNV//QDV//0A1n/9ANb//QAXQAG/8oAC//KADj/0gA6/9QAPP/0AD3/0wBa/+YAXP/vAF3/5gCg/9MAwP/mAML/5gEl/9IBJ//SATn/0wE6/+YBO//TAWL/0gFm/8oBf//TAZX/0wGX//QBm//TAaP/5gGt/+YBxf/SAc7/0gHR/+0B2f/0AeX/0gHm/+0B6P/0Aer/4QHv/9QB+f/vAgX/yQIG/+YCCP/vAg//0QIh/+YCJP/lAjf/1AI4/+YCOf/UAjr/5gJC/+MCWP/0Aln/7wJi/9ICY//EAm7/0gJw/9MCcf/mAnL/0wJ0//QCdf/vAnb/0gJ4/+ECev/hAoP/9AKE/+8Cjf/hAp7/9AKf/+8CsP/tArH/5gKy/+0Cs//mArT/7QK1/+YCtv/hAr7/9AK//+8Cxv/UAsf/9QLI/+cC0P9kAtH/yQNU/9MDVf/mA1b/0wNX/+YDWP/TA1n/5gNa/9MDW//mA3D/ygNx/8oDc//KA3T/ygN1/8oDfv/KA3//ygBsAAb/wAAL/8AAOP+dADr/xwA8//AAPf+rAFH/0gBS/9IAVP/SAKD/qwC0/9IBB//SAQn/0gEL/9IBDP/SASX/nQEn/50BOf+rATv/qwFi/50BZv/AAX//qwGV/6sBl//wAZv/qwGe/9IBp//SAcX/nQHM//UBzv+dAdH/6gHZ//AB3v/1AeX/nQHm/+oB6P/wAer/5QHv/8EB9v/SAfv/0gH8/9IB/f/SAf//0gIA/9ICAv/SAgP/0gIF/80CCf/SAgv/0gIM/9ICD//SAhH/0gIW/9ICHf/SAh//0gIg/9ICN//HAjn/xwJN/9ICWP/wAl3/0gJi/50CY//MAmX/0gJn/9ICbv+dAnD/qwJy/6sCdP/wAnb/nQJ4/+UCev/lAn7/3wKD//ACh//1Aor/0gKM/9ICjf/lApD/0gKe//ACpf/SAqf/0gKw/+oCsv/qArT/6gK2/+UCuf/SArv/0gK9/9ICvv/wAsb/zgLI/+oCyv/1AtD/ngLR/84C1P/1Auf/0gNU/6sDVv+rA1j/qwNa/6sDcP/AA3H/wANz/8ADdP/AA3X/wAN+/8ADf//AAG8ABv+xAAv/sQA4/54AOv/FADz/8gA9/6gAUf/PAFL/zwBU/88AXP/vAKD/qAC0/88BB//PAQn/zwEL/88BDP/PASX/ngEn/54BOf+oATv/qAFi/54BZv+xAX//qAGV/6gBl//yAZv/qAGe/88Bp//PAcX/ngHO/54B0f/sAdn/8gHl/54B5v/sAej/8gHq/+EB7//CAfb/zwH5/+8B+//PAfz/zwH9/88B///PAgD/zwIC/88CA//PAgX/xgII/+8CCf/PAgv/zwIM/88CD//PAhH/zwIW/88CHf/PAh//zwIg/88CN//FAjn/xQJN/88CWP/yAln/7wJd/88CYv+eAmP/wAJl/88CZ//PAm7/ngJw/6gCcv+oAnT/8gJ1/+8Cdv+eAnj/4QJ6/+ECfv/fAoP/8gKE/+8Civ/PAoz/zwKN/+ECkP/PAp7/8gKf/+8Cpf/PAqf/zwKw/+wCsv/sArT/7AK2/+ECuf/PArv/zwK9/88Cvv/yAr//7wLG/80CyP/oAtD/nwLR/8YC5//PA1T/qANW/6gDWP+oA1r/qANw/7EDcf+xA3P/sQN0/7EDdf+xA37/sQN//7EATQA4/74AUf/hAFL/4QBU/+EAWv/vAF3/7wC0/+EAwP/vAML/7wEH/+EBCf/hAQv/4QEM/+EBJf++ASf/vgE6/+8BYv++AZ7/4QGj/+8Bp//hAa3/7wHF/74Bzv++AeX/vgHv/8kB9v/hAfv/4QH8/+EB/f/hAf//4QIA/+ECAv/hAgP/4QIF/98CBv/vAgn/4QIL/+ECDP/hAg//4QIR/+ECFv/hAh3/4QIf/+ECIP/hAiH/7wIk/+0COP/vAjr/7wJC/+sCTf/hAl3/4QJi/74CY//fAmX/4QJn/+ECbv++AnH/7wJ2/74Cfv/pAor/4QKM/+ECkP/hAqX/4QKn/+ECsf/vArP/7wK1/+8Cuf/hArv/4QK9/+ECx//1AtH/4ALn/+EDVf/vA1f/7wNZ/+8DW//vAGQAOP/mADr/5wA8//IAPf/nAFH/1gBS/9YAVP/WAFz/8QCg/+cAtP/WAQf/1gEJ/9YBC//WAQz/1gEl/+YBJ//mATn/5wE7/+cBYv/mAX//5wGV/+cBl//yAZv/5wGe/9YBp//WAcX/5gHO/+YB0f/uAdn/8gHl/+YB5v/uAej/8gHq/+gB7//mAfb/1gH5//EB+//WAfz/1gH9/9YB///WAgD/1gIC/9YCA//WAgX/0AII//ECCf/WAgv/1gIM/9YCD//WAhH/1gIW/9YCHf/WAh//1gIg/9YCN//nAjn/5wJN/9YCWP/yAln/8QJd/9YCYv/mAmP/zgJl/9YCZ//WAm7/5gJw/+cCcv/nAnT/8gJ1//ECdv/mAnj/6AJ6/+gCg//yAoT/8QKK/9YCjP/WAo3/6AKQ/9YCnv/yAp//8QKl/9YCp//WArD/7gKy/+4CtP/uArb/6AK5/9YCu//WAr3/1gK+//ICv//xAsb/5wLI/+0C0P/mAtH/0ALn/9YDVP/nA1b/5wNY/+cDWv/nAAICLQALAtD/5gCTACUAEAAn/+gAK//oADP/6AA1/+gAOP/gADr/4AA9/98AgwAQAIQAEACFABAAhgAQAIcAEACIABAAiv/oAJX/6ACW/+gAl//oAJj/6ACZ/+gAm//oAKD/3wDDABAAxQAQAMcAEADJ/+gAy//oAM3/6ADP/+gA3//oAOH/6ADj/+gA5f/oAQ//6AER/+gBE//oARX/6AEl/+ABJ//gATn/3wE7/98BRf/oAU4AEAFS/+gBYv/gAXkAEAF+/+gBf//fAYIAEAGFABABif/oAYwAEAGQ/+gBlf/fAZv/3wHF/+ABx//oAcwAEAHO/+AB0wAQAdcAFAHeABAB4f/oAeT/6AHl/+AB6v/hAe//4AH3ABMB/gAQAgr/4AIcABACI//oAikAEAI1/+gCN//gAjn/4AI7/+gCPf/oAj//6AJB/+gCQ//oAmL/4AJq/+gCbP/oAm7/4AJw/98Ccv/fAnb/4AJ4/+ECef/gAnr/4QJ7/+ACf//hAocAEAKIABACjf/hAo7/4AKSABAClAAQApr/6QKo/+gCqv/oAqz/6AK2/+ECt//gAsb/3wLI/94CygAQAs7/6ALQ/98C0v/yAtQAEALVABAC1gAQAwIAEAMEABADBgAQAwgAEAMKABADDAAQAw4AEAMQABADEgAQAxQAEAMWABADGAAQAy7/6AMw/+gDMv/oAzT/6AM2/+gDOP/oAzr/6AM8/+gDPv/oA0D/6ANC/+gDRP/oA1T/3wNW/98DWP/fA1r/3wNc/+gEMf/oBDL/6AQ0/+gENf/oADIAG//yADj/8QA6//QAPP/0AD3/8ACg//ABJf/xASf/8QE5//ABO//wAWL/8QF///ABlf/wAZf/9AGb//ABxf/xAcz/9QHO//EB0f/zAdn/9AHe//UB5f/xAeb/8wHo//QB7//xAjf/9AI5//QCWP/0AmL/8QJu//ECcP/wAnL/8AJ0//QCdv/xAoP/9AKH//UCnv/0ArD/8wKy//MCtP/zAr7/9ALG//ICyP/yAsr/9QLQ//IC1P/1A1T/8ANW//ADWP/wA1r/8AAIAFgADgCJ/tcBq/+YAbH/xwHX/xIB9/9SAsL/zwPs/4AAZgAlAA8AOP/mADr/5gA8AA4APf/mAIMADwCEAA8AhQAPAIYADwCHAA8AiAAPAKD/5gDDAA8AxQAPAMcADwEl/+YBJ//mATn/5gE7/+YBTgAPAWL/5gF5AA8Bf//mAYIADwGFAA8BjAAPAZX/5gGXAA4Bm//mAcX/5gHMAA4Bzv/mAdEACwHTAA8B1wATAdkADgHeAA4B5f/mAeYACwHoAA4B6v/lAe//5gHw//QB9wASAf4ADwIF/+cCCv/oAg//5wIcAA8CKQAPAjf/5gI5/+YCWAAOAmL/5gJj/+cCbv/mAnD/5gJy/+YCdAAOAnb/5gJ4/+UCef/oAnr/5QJ7/+gCgwAOAocADgKIAA8Cjf/lAo7/6AKSAA8ClAAPAp4ADgKwAAsCsgALArQACwK2/+UCt//oAr4ADgLG/+YCyP/mAsoADgLQ/+YC0f/nAtQADgLVAA8C1gAPAwIADwMEAA8DBgAPAwgADwMKAA8DDAAPAw4ADwMQAA8DEgAPAxQADwMWAA8DGAAPA1T/5gNW/+YDWP/mA1r/5gA3AAb/vwAL/78AOP+fADr/yQA9/60AoP+tASX/nwEn/58BOf+tATv/rQFi/58BZv+/AX//rQGV/60Bm/+tAcX/nwHO/58B0f/sAeX/nwHm/+wB6v/mAe//xAIF/80CD//VAjf/yQI5/8kCYv+fAmP/zAJu/58CcP+tAnL/rQJ2/58CeP/mAnr/5gJ+/98Cjf/mArD/7AKy/+wCtP/sArb/5gLG/9ECyP/sAtD/oQLR/88DVP+tA1b/rQNY/60DWv+tA3D/vwNx/78Dc/+/A3T/vwN1/78Dfv+/A3//vwAwADj/4wA8/+UAPf/kAKD/5AEl/+MBJ//jATn/5AE7/+QBYv/jAX//5AGV/+QBl//lAZv/5AHF/+MBzP/lAc7/4wHR/+kB1//iAdn/5QHe/+UB5f/jAeb/6QHo/+UB/v/qAhz/6gJY/+UCYv/jAm7/4wJw/+QCcv/kAnT/5QJ2/+MCg//lAof/5QKI/+oCnv/lArD/6QKy/+kCtP/pAr7/5QLK/+UC0P/kAtT/5QLV/+oDVP/kA1b/5ANY/+QDWv/kACMAOP/iADz/5AEl/+IBJ//iAWL/4gGX/+QBxf/iAcz/5AHO/+IB0f/pAdf/4QHZ/+QB3v/kAeX/4gHm/+kB6P/kAff/5AH+/+sCHP/rAlj/5AJi/+ICbv/iAnT/5AJ2/+ICg//kAof/5AKI/+sCnv/kArD/6QKy/+kCtP/pAr7/5ALK/+QC1P/kAtX/6wAXADj/6wA9//MAoP/zASX/6wEn/+sBOf/zATv/8wFi/+sBf//zAZX/8wGb//MBxf/rAc7/6wHl/+sCYv/rAm7/6wJw//MCcv/zAnb/6wNU//MDVv/zA1j/8wNa//MANgBR/+8AUv/vAFT/7wBc//AAtP/vAQf/7wEJ/+8BC//vAQz/7wGe/+8Bp//vAfb/7wH3/+4B+f/wAfv/7wH8/+8B/f/vAf//7wIA/+8CAv/vAgP/7wIF/+4CCP/wAgn/7wIL/+8CDP/vAg//7wIR/+8CFv/vAh3/7wIf/+8CIP/vAiT/9AJC//ECTf/vAln/8AJd/+8CY//vAmX/7wJn/+8Cdf/wAoT/8AKK/+8CjP/vApD/7wKf//ACpf/vAqf/7wK5/+8Cu//vAr3/7wK///AC0f/vAuf/7wAiAAb/8gAL//IAWv/1AF3/9QDA//UAwv/1ATr/9QFm//IBo//1Aa3/9QIF//QCBv/1Ag//9AIh//UCJP/1Ajj/9QI6//UCY//1AnH/9QKx//UCs//1ArX/9QLR//UDVf/1A1f/9QNZ//UDW//1A3D/8gNx//IDc//yA3T/8gN1//IDfv/yA3//8gAyAFH/7gBS/+4AVP/uALT/7gEH/+4BCf/uAQv/7gEM/+4Bnv/uAaf/7gH2/+4B9wAUAfv/7gH8/+4B/f/uAf//7gIA/+4CAv/uAgP/7gIF/+0CCf/uAgr/7QIL/+4CDP/uAg3/0AIP/+4CEf/uAhb/7gId/+4CH//uAiD/7gJN/+4CXf/uAmP/7QJl/+4CZ//uAnn/7QJ7/+0Civ/uAoz/7gKO/+0CkP/uAqX/7gKn/+4Ct//tArn/7gK7/+4Cvf/uAtH/7QLn/+4ACgAG//UAC//1AWb/9QNw//UDcf/1A3P/9QN0//UDdf/1A37/9QN///UAWQBH//AASP/wAEn/8ABL//AAU//HAFX/8ACq//AAq//wAKz/8ACt//AArv/wALX/xwC2/8cAt//HALj/xwC5/8cAyv/wAMz/8ADO//AA0P/wANL/8ADW//AA2P/wANr/8ADc//AA3v/wAOD/8ADi//AA5P/wAOb/8AEQ/8cBEv/HART/xwEW//ABRv/wAZz/8AGh//ABr//HAbL/8AGz//ABvP/HAfj/8AIB/8cCBP/wAgf/8AIT//ACFP/wAhf/8AI2/8cCPP/wAj7/6wJA//ACRP/wAmv/8AJt//ACmf/wApv/8AKd//ACqf/HAqv/8AKt/8cCw//wAsT/8ALF//ACz//wAxv/8AMd//ADH//wAyH/8AMj//ADJf/wAyf/8AMp//ADL//HAzH/xwMz/8cDNf/HAzf/xwM5/8cDO//HAz3/8AM///ADQf/wA0P/xwNF//AD3P/rA97/6wPm/+kD6v/rAKEABgANAAsADQBF//AAR//AAEj/wABJ/8AASgANAEv/wABT/+IAVf/AAFoACwBdAAsAo//wAKT/8ACl//AApv/wAKf/8ACo//AAqv/AAKv/wACs/8AArf/AAK7/wAC1/+IAtv/iALf/4gC4/+IAuf/iAMAACwDCAAsAxP/wAMb/8ADI//AAyv/AAMz/wADO/8AA0P/AANL/wADW/8AA2P/AANr/wADc/8AA3v/AAOD/wADi/8AA5P/AAOb/wAEQ/+IBEv/iART/4gEW/8ABOgALAUb/wAFP//ABZgANAZz/wAGh/8ABowALAa0ACwGv/+IBsf/WAbL/wAGz/8ABtv/VAbz/4gHz//AB9//IAfj/wAH+/9cCAf/iAgT/wAIGAAsCB//AAhP/wAIU/8ACF//AAhz/1wIhAAsCNv/iAjgACwI6AAsCPP/AAj7/7AJA/8ACQgAMAkT/wAJr/8ACbf/AAnEACwKI/9cCk//wApX/8AKZ/8ACm//AAp3/wAKp/+ICq//AAq3/4gKxAAsCswALArUACwLD/8ACxP/AAsX/wALHAAsCyQALAs//wALV/9cC1//wAwP/8AMF//ADB//wAwn/8AML//ADDf/wAw//8AMR//ADE//wAxX/8AMX//ADGf/wAxv/wAMd/8ADH//AAyH/wAMj/8ADJf/AAyf/wAMp/8ADL//iAzH/4gMz/+IDNf/iAzf/4gM5/+IDO//iAz3/wAM//8ADQf/AA0P/4gNF/8ADVQALA1cACwNZAAsDWwALA3AADQNxAA0DcwANA3QADQN1AA0DfgANA38ADQPXAA0D2QAOA9r/9QPc/+wD3v/tA+b/7APq/+4D7P+/A/cADQAPAfcAFAH+ABACBf/wAgr/8AIP//ACEgAWAhwAEAJj/+YCef/wAnv/3AKIABACjv/wArf/8ALR//AC1QAQAEwAR//uAEj/7gBJ/+4AS//uAFX/7gCq/+4Aq//uAKz/7gCt/+4Arv/uAMr/7gDM/+4Azv/uAND/7gDS/+4A1v/uANj/7gDa/+4A3P/uAN7/7gDg/+4A4v/uAOT/7gDm/+4BFv/uAUb/7gGc/+4Bof/uAbL/7gGz/+4B9wASAfj/7gH+AA4CBP/uAgX/4wIH/+4CCv/jAg3/uAIP/+MCE//uAhT/7gIX/+4CHAAOAjz/7gJA/+4CRP/uAmP/ugJr/+4Cbf/uAnn/4wJ7/9kCiAAOAo7/4wKZ/+4Cm//uAp3/7gKr/+4Ct//jAsP/7gLE/+4Cxf/uAs//7gLR/+MC1QAOAxv/7gMd/+4DH//uAyH/7gMj/+4DJf/uAyf/7gMp/+4DPf/uAz//7gNB/+4DRf/uACAAWv/AAF3/wADA/8AAwv/AATr/wAGj/8ABrf/AAgX/gAIG/8ACCv/uAg//8AIh/8ACJP/bAjj/wAI6/8ACQv/cAmP/RwJx/8ACef/uAnv/7gKO/+4Csf/AArP/wAK1/8ACt//uAscABwLJ//QC0f9/A1X/wANX/8ADWf/AA1v/wAAhAFr/9ABc//AAXf/0AMD/9ADC//QBOv/0AaP/9AGt//QB9//vAfn/8AH+//MCBv/0Agj/8AIP/+4CHP/zAiH/9AI4//QCOv/0Aln/8AJx//QCdf/wAoT/8AKI//MCn//wArH/9AKz//QCtf/0Ar//8ALV//MDVf/0A1f/9ANZ//QDW//0AAoABv/WAAv/1gFm/9YDcP/WA3H/1gNz/9YDdP/WA3X/1gN+/9YDf//WABUAXP/gAfn/4AIF/3YCCP/gAgr/wgIP/9MCJP/ZAkL/2wJZ/+ACY/8eAnX/4AJ5/8ICe//tAoT/4AKO/8ICn//gArf/wgK//+ACx//wAsn/8gLR/1YADQIF/2QCCv/SAg//2QIk/9kCQv/bAmP/HgJ5/9ICe//tAo7/0gK3/9ICx//wAsn/8gLR/1YACgHv/8MCBf/PAg//1AJj/84Cev/nAn7/3wLG/9ECyP/sAtD/oALR/9EACQIF/2oCD//GAiT/2QJC/9sCY/8eAnv/7QLH//ACyf/yAtH/VgAJAA0AFABBABEAVv/iAGEAEwPc/9kD3v/ZA+b/2QPq/9kD7P+0AAoABv/XAAv/1wFm/9cDcP/XA3H/1wNz/9cDdP/XA3X/1wN+/9cDf//XABQAW//BAZb/xQG0/7QB9P/XAgX/uQIP/+kCJP+yAj7/0gJC/8gCY/+gAnv/xQKa/+QCx//MAsn/zALR/8sC0v/vA9z/5wPe/+cD5v/mA+r/6AA6AAT/xABW/78AW//RAG7/bAB+/24Aif9DAKn/rAC7/6EBlv+4AaX/fgGp/3sBsP+bAbH/eQG0/7IBtv9+Abj/fQG5/3wB1/+vAe8ADwH0/+QB9f+gAff/dAH6/4ACBf+yAg7/fQIP/7ICEP+AAhL/eQIVACgCIv99AiT/fwI+/2YCQv/aAlH/gQJT/5gCX/99AmP/swJp/6ACe/98An7/mgJ//2wCmv/mAsL/awLH/5ICyf+tAs3/ewLQAA8C0f+RAtL/8gPW//ED2f/xA9r/vAPc/7kD3v+5A+b/uQPq/7kD7P+vA/b/7QAGAbT/6gH3/+4CBf/WAg//7QJj/+wC0f/sABIB1/+uAe8AEgH1/+AB9/+tAfr/1gIO/98CEv/SAiL/4AI+/84CUf/dAlP/4gJf/+ACaf/gAnv/6QJ//9oCwv+9As3/3wLQABEAMABW/34AW/+dAG7+8QB+/vQAif6rAKn/XgC7/0sBlv9yAaX/DwGp/woBsP9BAbH/BwG0/2gBtv8PAbj/DgG5/wwB1/9jAe8ABQH0/70B9f9JAff+/gH6/xMCBf9oAg7/DgIP/2gCEP8TAhL/BwIVADACIv8OAiT/EQI+/ucCQv+sAlH/FQJT/zwCX/8OAmP/agJp/0kCe/8MAn7/PwJ//vECmv/AAsL+7wLH/zECyf9fAs3/CgLQAAUC0f8wAtL/1QACAff/aAI+/+4AFwGW/9QBqP/tAasAEQG0/+ABtv/nAbj/5QG5/+4B1wASAfT/6QIF/9cCY//XAnv/0wJ+/9YCf//FApr/5wLGAA0CyAAMAtH/1gLS//ID3P/pA97/5wPm/+cD6v/pAAECPv/xAAICBf/WA3H/iAAJAA0ADwBBAAwAVv/rAGEADgPc/+cD3v/nA+b/5wPq/+kD7P/LAB0AI/+vAFj/7wBb/98BR//u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AX4BfgAFAX8BfwAQAYIBggACAYMBgwADAYQBhAAcAYUBhQACAYYBhgAGAYcBhwARAYgBiAAHAYkBiQAFAYoBigAHAYsBiwAJAYwBjAACAY0BjgAHAZABkAAFAZIBkgALAZQBlAAMAZUBlQAQAZcBlwAPAZoBmgAHAZsBmwAQAZ4BngAWAaMBowAZAacBpwAWAa0BrQAZAa8BrwAXAbEBsQATAbwBvAAXAcMBxAAGAcYBxgAcAckBygAHAcsBywAIAcwBzQAdAc8BzwAJAdEB0QAeAdIB0gAHAdMB0wACAdUB1QADAdYB1gAcAdgB2AAGAdkB2QAPAdsB2wAHAd0B3QAJAd4B4AAHAeEB4QAFAeMB4wALAeQB5AAEAeUB5QAMAeYB5gAeAegB6AAPAekB6QAHAesB6wAHAe0B7QAdAe8B7wAdAfMB8wASAfYB9gAfAfgB+AAVAfkB+QAaAgECAQAXAgMCAwATAgQCBAAUAgYCBgAZAgcCBwATAggCCAAaAg0CDQAgAg8CDwAgAhACEAATAhMCFAAVAhYCFgAfAhwCHQAgAiECIQAZAiUCJQAdAiYCJgAgAikCKQACAjYCNgAXAjcCNwANAjgCOAAZAjkCOQANAjoCOgAZAlECUQATAlICUgAcAlMCUwAfAlQCVAAcAlgCWAAPAlkCWQAaAlwCXAAJAl4CXgAJAmACYAAJAmICYgAJAmQCZAAHAmwCbAAEAm0CbQAUAm4CbgAMAnACcAAQAnECcQAZAnICcgAQAnQCdAAPAnUCdQAaAn0CfQAWAoICggAHAoMCgwAPAoQChAAaAosCiwAHAo8CjwAHApECkQAHApICkgACApMCkwASApQClAACApUClQASApgCmAAGApkCmQAVApsCmwAVAp0CnQAVAp4CngAPAp8CnwAaAqgCqAAFAqkCqQAXAq0CrQAXAq8CrwATArACsAAeArECsQAZArICsgAeArMCswAZArQCtAAeArUCtQAZArgCuAAcArkCuQAfAr0CvQAfAr4CvgAPAr8CvwAaAtYC1gACAtcC1wASAuYC5gAHAucC5wAWAvgC+AAOAvoC+gAOAvwC/AAOAwIDAgACAwMDAwASAwQDBAACAwUDBQASAwYDBgACAwcDBwASAwgDCAACAwkDCQASAwoDCgACAwsDCwASAwwDDAACAw0DDQASAw4DDgACAw8DDwASAxADEAACAxEDEQASAxIDEgACAxMDEwASAxQDFAACAxUDFQASAxYDFgACAxcDFwASAxgDGAACAxkDGQASAxoDGgAGAxsDGwAVAxwDHAAGAx0DHQAVAx4DHgAGAx8DHwAVAyADIAAGAyEDIQAVAyIDIgAGAyMDIwAVAyQDJAAGAyUDJQAVAyYDJgAGAycDJwAVAygDKAAGAykDKQAVAyoDKgAHAywDLAAHAy4DLgAFAy8DLwAXAzADMAAFAzEDMQAXAzIDMgAFAzMDMwAXAzQDNAAFAzUDNQAXAzYDNgAFAzcDNwAXAzgDOAAFAzkDOQAXAzoDOgAFAzsDOwAXA0MDQwAXA0YDRgAIA0gDSAAIA1QDVAAQA1UDVQAZA1YDVgAQA1cDVwAZA1gDWAAQA1kDWQAZA1oDWgAQA1sDWwAZA1wDXAAFA3IDcgABA3YDdgABA3oDewABBDEEMQAEBDMENAAFAAEABgQwAAEAAAAAAAAAAAABAAAAAAAAAAAAFgAZABYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAgAAAAAAAAACAAAAAAAGgAAAAAAAAAAAAgAAAAIAAAAGwAJAAoACwAMABcADQAYAAAAAAAAAAAAAAAAAAMAAAAEAAQABAAAAAQAAAAAAAAAAAAAAAUABQAGAAUABAAAAAcAAAAOAA8AAAAcAA8AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAIAAgACAAIAAgAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgACAAIAAgAAAAIAAoACgAKAAoADQAAAAAAAwADAAMAAwADAAMAAAAEAAQABAAEAAQAAAAAAAAAAAAAAAUABgAGAAYABgAGAAAAAAAOAA4ADgAOAA8AAAAPAAIAAwACAAMAAgADAAgABAAIAAQACAAEAAgABAAAAAQAAAAAAAAABAAAAAQAAAAEAAAABAAAAAQACAAEAAgABAAIAAQACAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAABQAAAAUABQAAAAAACAAGAAgABgAIAAYACAAEAAAAAAAAAAAAAAAAABsABwAbAAcAGwAHABsABwAJAAAACQAAAAAAAAAKAA4ACgAOAAoADgAKAA4ACgAOAAoADgAMAAAADQAPAA0AGAAQABgAEAAYABAAAAAAAAAACAAEAAAADgAAAAAAAAAAAAAAAgADAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGwAHAAkAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAACAANAAAAAAACAAAAAAACAAAAGAAAAAgAAAAAAAIAAAAAAAAACAAAAAAAAAAAAA0AAAAXAAAAAAAAAA0ABAAAAAUAAAAOAAQAAAAPAAAAAAAAAAUAAAAAAAAAAAAAAA8AAAAGAAAAAAAEAAQAAAAOAAAAAAAAAAAAAAAOAAYADgAAAAAAAAAAAAAAAAAAAAkAAAAIAAAAAAAAABoAEQAAAAkAAAAAABUAAAACAAAAAAAAAAAAAAAXAAAAAAAAAAAAEQAAAAAACAAAAAAACAAJABUAAAAXAAAAEgAAAAAAAAAAAAAAAAAAAAAAAwAAAAAABQAAAAQAHAAAAAUABQAFABMABQAFAAYABQAFAAQAAAAPAAQAHAAFABQABQAFAAAAAAAFAAAABQAAAAQABAAAAAUABAAHAAAAAAAAABMABQAAAAUABQAPAAAACAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAGAAsADwALAA8ACAAEAAgAAAAIAAQACAAAAAgABAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAABcAHAAAAAAAAAAFAAAAAAAAAAAACQAAAAAABQAAAAUAAAAAAAgABAAIAAQACQAAAA0ADwANAAAAFwAcAAkAAAASABQAAAAAAAAAAAAAAAAAAAAAAAAAFwAcAAAAAAARABMAAAAFAAAABQASABQAAAAFAAAAAgADAAIAAwAAAAAAAAAEAAAABAAAAAQAFwAcAAAAAAAAAAAAAAAFAAAABQAIAAYACAAEAAgABgAAAAAAFQAPABUADwAVAA8AEgAUAAAABQAAAAUAAAAFABcAHAAAAAAAAAAEAAQABAAAAAAAAAAAABEAAAAAAAAACAAEAAAAAAAAAAAAEQATAAIAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAwAAAAMAAAAAAAAAAAAAAACAAMAAgADAAIAAwACAAMAAgADAAIAAwACAAMAAgADAAIAAwACAAMAAgADAAIAAwAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAAAAAAAAACAAGAAgABgAIAAYACAAGAAgABgAIAAYACAAGAAgABAAIAAQACAAEAAgABgAIAAQACgAOAAoADgAAAA4AAAAOAAAADgAAAA4AAAAOAA0ADwANAA8ADQAPAA0ADwAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkAGQAZAAAAAQABABYAAQABAAEAFgAAAAAAAAAWABYAAAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAgAAAAIAAgAAAABAAAACgIGCBAABERGTFQAGmN5cmwASGdyZWsAdmxhdG4ApAAEAAAAAP//ABIAAAAKABQAHgAoADQAQQBLAFUAXwBpAHMAfQCHAJEAmwClAK8ABAAAAAD//wASAAEACwAVAB8AKQA1AEIATABWAGAAagB0AH4AiACSAJwApgCwAAQAAAAA//8AEgACAAwAFgAgACoANgBDAE0AVwBhAGsAdQB/AIkAkwCdAKcAsQAoAAZBWkUgAFRDUlQgAH5NT0wgAKhOQVYgANRST00gAQBUVVIgASwAAP//ABMAAwANABcAIQArADIANwBEAE4AWABiAGwAdgCAAIoAlACeAKgAsgAA//8AEgAEAA4AGAAiACwAOABFAE8AWQBjAG0AdwCBAIsAlQCfAKkAswAA//8AEgAFAA8AGQAjAC0AOQBGAFAAWgBkAG4AeACCAIwAlgCgAKoAtAAA//8AEwAGABAAGgAkAC4AOgA+AEcAUQBbAGUAbwB5AIMAjQCXAKEAqwC1AAD//wATAAcAEQAbACUALwA7AD8ASABSAFwAZgBwAHoAhACOAJgAogCsALYAAP//ABMACAASABwAJgAwADwAQABJAFMAXQBnAHEAewCFAI8AmQCjAK0AtwAA//8AEwAJABMAHQAnADEAMwA9AEoAVABeAGgAcgB8AIYAkACaAKQArgC4ALljMnNjBFhjMnNjBF5jMnNjBGRjMnNjBGpjMnNjBGpjMnNjBGpjMnNjBGpjMnNjBGpjMnNjBGpjMnNjBGpjY21wBHBjY21wBHBjY21wBHBjY21wBHBjY21wBHBjY21wBHBjY21wBHBjY21wBHBjY21wBHBjY21wBHBkbGlnBHhkbGlnBH5kbGlnBIRkbGlnBIpkbGlnBIpkbGlnBIpkbGlnBIpkbGlnBIpkbGlnBIpkbGlnBIpkbm9tBJBkbm9tBJZkbm9tBJxkbm9tBKJkbm9tBKJkbm9tBKJkbm9tBKJkbm9tBKJkbm9tBKJkbm9tBKJmcmFjBKhmcmFjBKhmcmFjBKhmcmFjBKhmcmFjBKhmcmFjBKhmcmFjBKhmcmFjBKhmcmFjBKhmcmFjBKhsaWdhBLJsaWdhBLpsbnVtBMBsbnVtBMZsbnVtBMxsbnVtBNJsbnVtBNJsbnVtBNJsbnVtBNJsbnVtBNJsbnVtBNJsbnVtBNJsb2NsBNhsb2NsBN5sb2NsBORudW1yBOpudW1yBPBudW1yBPZudW1yBPxudW1yBPxudW1yBPxudW1yBPxudW1yBPxudW1yBPxudW1yBPxvbnVtBQJvbnVtBQhvbnVtBQ5vbnVtBRRvbnVtBRRvbnVtBRRvbnVtBRRvbnVtBRRvbnVtBRRvbnVtBRRwbnVtBRpwbnVtBSBwbnVtBSZwbnVtBSxwbnVtBSxwbnVtBSxwbnVtBSxwbnVtBSxwbnVtBSxwbnVtBSxzbWNwBTJzbWNwBThzbWNwBT5zbWNwBURzbWNwBURzbWNwBURzbWNwBURzbWNwBURzbWNwBURzbWNwBURzczAxBUpzczAxBVBzczAxBVZzczAxBVxzczAxBVxzczAxBVxzczAxBVxzczAxBVxzczAxBVxzczAxBVxzczAyBWJzczAyBWhzczAyBW5zczAyBXRzczAyBXRzczAyBXRzczAyBXRzczAyBXRzczAyBXRzczAyBXRzczAzBXpzczAzBYBzczAzBYZzczAzBYxzczAzBYxzczAzBYxzczAzBYxzczAzBYxzczAzBYxzczAzBYxzczA0BZJzczA0BZhzczA0BZ5zczA0BaRzczA0BaRzczA0BaRzczA0BaRzczA0BaRzczA0BaRzczA0BaRzczA1BapzczA1BbBzczA1BbZzczA1BbxzczA1BbxzczA1BbxzczA1BbxzczA1BbxzczA1BbxzczA1BbxzczA2BcJzczA2BchzczA2Bc5zczA2BdRzczA2BdRzczA2BdRzczA2BdRzczA2BdRzczA2BdRzczA2BdRzczA3BdpzczA3BeBzczA3BeZzczA3BexzczA3BexzczA3BexzczA3BexzczA3BexzczA3BexzczA3Bex0bnVtBfJ0bnVtBfh0bnVtBf50bnVtBgR0bnVtBgR0bnVtBgR0bnVtBgR0bnVtBgR0bnVtBgR0bnVtBgQAAAABAAEAAAABAAMAAAABAAIAAAABAAAAAAACAAgACQAAAAEADgAAAAEAEAAAAAEADwAAAAEADQAAAAEAQwAAAAEARQAAAAEARAAAAAEAQgAAAAMAPwBAAEEAAAACABEAEgAAAAEAEgAAAAEAPAAAAAEAPgAAAAEAPQAAAAEAOwAAAAEACgAAAAEADAAAAAEACwAAAAEARwAAAAEASQAAAAEASAAAAAEARgAAAAEAMAAAAAEAMgAAAAEAMQAAAAEALwAAAAEAOAAAAAEAOgAAAAEAOQAAAAEANwAAAAEABQAAAAEABwAAAAEABgAAAAEABAAAAAEAFAAAAAEAFgAAAAEAFQAAAAEAEwAAAAEAGAAAAAEAGgAAAAEAGQAAAAEAFwAAAAEAHAAAAAEAHgAAAAEAHQAAAAEAGwAAAAEAIAAAAAEAIgAAAAEAIQAAAAEAHwAAAAEAJAAAAAEAJgAAAAEAJQAAAAEAIwAAAAEAKAAAAAEAKgAAAAEAKQAAAAEAJwAAAAEALAAAAAEALgAAAAEALQAAAAEAKwAAAAEANAAAAAEANgAAAAEANQAAAAEAMwBLAJgAmACYAJgEJgQmBCYEJgcUB8AOUA5QDmYOiA6IDogOiA6+DuQPEg8SDxIPEg8mDyYPJg8mDzoPOg86DzoPTg9OD04PTg9gD2APYA9gD3oPeg96D3oPvA+8D7wPvA/aD9oP2g/aD/gP+A/4D/gQKhAqECoQKhBcEFwQXBBcEI4QohDuEMwQzBDMEMwQ7hDuEO4Q7hEaAAEAAAABAAgAAgHEAN8DvQPsA+sD6gPpA+gD5wPmA+UD5APjA+ID4QPgA98D3gPdA9wD2wPaA9kD2APXA9YD9gP3BKkDvAO7BFAEUQRSBFMEVARVBFcEWARZBFoEWwRcBF0EXgRfBE4EYARhBGIEYwRkBGUEZgRtBG4EbwRwBEwEcQRyBHMEdAR1BHYEdwR4BE0EeQR6BHsEfAR9BH4EfwSABIEEggSDBIQEhQSGBIcEiASJBIoEiwSMBI0EjgSPBJAEkQSSBJMERASUBJUElgSXBJgEmQSaBJ0EnARPBJ4EnwSgBKEEogSjBKQEpQSmBKcEqAP+BFYEmwSqBKsErAStBK4ErwSwBLEEsgO6A7kEswS0BLUDuAS2BLcDtwS4A7YEuQPGBLoD0QS7BLwD0gS9A9MD1AS+BL8EwAP5BMED+ATCBMMExATFA/8EAAQBBMYExwQCBMgEAwTJBMoEBATLBAUEBgQHBMwECAQJBM0EzgTPBNAE0QTSBNMECgTcBNQECwQMBA0EDgQPBBAEEQQSBBMEFAQ4BBUEFgTVBBcEGAQZBNYEGgTXBNgEGwQcBB0EHgQfBCAE2QQhBCIE2gQjBNsEJAQlBCcEJgABAN8ACAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AD4AZgBoAIMAhACFAIYAhwCIAIoAiwCMAI0AjgCPAJAAkQCSAJMAlACVAJYAlwCYAJkAnACdAJ4AnwCgAKIAwwDFAMcAyQDLAM0AzwDRANMA1QDXANkA2wDdAN8A4QDjAOUA5wDrAO0A7wDxAPMA9wD5APwA/gEAAQIBBgEIAQoBDwERARMBFQEXARkBGwEdAR8BIQEjASUBJwEpASsBLQEvATEBMwE1ATcBOQE7ATwBPgFAAU4BYgF5AXsBfAF9AX4BfwGAAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY8BkAGRAZIBkwGUAZUBlgGXAZgBmQGaAZsBxAHFAcYBxwHIAckBygHLAcwBzQHOAc8B0QHSAdMB1AHVAdYB1wHYAdkB2gHbAdwB3QHeAd8B4AHhAeIB4wHkAeUB5gHnAegB6QHqAesB7AHtAe4B7wHwAfEB8gJSAlQCWAJaAlwCXgJiAmQCagJsAnACcgJ0AnYCegJ8An4CgAKaAqICpAKqArADhwOOA5MDlgABAAAAAQAIAAIBdAC3A+wD6wPqA+kD6APnA+YD5QPkA+MD4gPhA+AD3wPeA90D3APbA9oD2QPYA9cD1gP2A/cEqQRQBFEEUgRTBFQEVQRXBFgEWQRaBFsEXARdBF4EXwROBGAEYQRiBGMEZARlBGYEbQRuBG8EcASmBHEEcgRzBHQEdQR2BHcEeARNBHkEegR7BHwEfQR+BH8EgASBBIIEgwSEBIUEhgSHBIgEiQSKBIsEjASNBI4EjwSQBJEEkgSTBEQElASVBJYElwSYBJkEmgSdBJwETwSeBJ8EoAShBKIEowSkBKUEpwSoA/4EVgSbBMgEAwTJBMoEBATLBAUEBgQHBMwECAQJBM0EzgTPBNAE0QTSBNMECgTcBNQECwQMBA0EDgQPBBAEEQQSBBMEFATAA/kEwQP4BMIEwwTEBMUD/wQABAEExgTHBAIEOAQVBBYE1QQXBBgEGQTWBBoE1wTYBBsEHAQdBB4EHwQgBNkEIQQiBNoEIwTbAAEAtwBFAEYARwBIAEkASgBLAEwATQBOAE8AUABRAFIAUwBUAFUAVgBXAFgAWQBaAFsAXABdAF4AowCkAKUApgCnAKgAqgCrAKwArQCuAK8AsACxALIAswC0ALUAtgC3ALgAuQC8AL0AvgC/AMAAwgDEAMYAyADKAMwAzgDQANIA1ADWANgA2gDcAN4A4ADiAOQA5gDoAOwA7gDwAPIA9AD4APoA/QD/AQEBAwEHAQkBCwEQARIBFAEWARgBGgEcAR4BIAEiASQBJgEoASoBLAEuATABMgE0ATYBOAE6AT0BPwFBAU8BYwHzAfQB9QH2AfcB+AH5AfoB+wH8Af0B/gH/AgACAQICAgMCBAIFAgYCBwIIAgkCCgILAgwCDQIOAg8CEAIRAhICFAIVAhYCFwIYAhkCGgIbAhwCHQIeAh8CIQIiAlMCVQJZAlsCXQJfAmMCZQJrAm0CcQJzAnUCdwJ7An0CfwKBApsCowKlAqsCsQAGAAAABgASACoAQgBaAHIAigADAAAAAQASAAEAkAABAAAASgABAAEATQADAAAAAQASAAEAeAABAAAASgABAAEATgADAAAAAQASAAEAYAABAAAASgABAAEA8gADAAAAAQASAAEASAABAAAASgABAAECGQADAAAAAQASAAEAMAABAAAASgABAAECGwADAAAAAQASAAEAGAABAAAASgABAAEDLQACAAEBcQF1AAAABAAAAAEACAABBh4ANgByAKQArgC4AMoA/AEOARgBSgFkAX4BkAG6AewB9gIYAjICRAJ2AogCogLMAt4DEAMaAyQDNgNoA3IDfAOGA6ADugPMA/YEKAQyBFQEbgSABLIExATeBQgFGgUkBS4FOAVCBWwFlgXABeoGFAAGAA4AFAAaACAAJgAsAIMAAgFxAIQAAgFyAIYAAgFzAwQAAgF0AVQAAgF1AwIAAgF2AAEABALYAAIBdgABAAQAyQACAXIAAgAGAAwC2gACAXYC3AACA6sABgAOABQAGgAgACYALACLAAIBcQCMAAIBcgMeAAIBcwMcAAIBdAFWAAIBdQMaAAIBdgACAAYADAFKAAIBcgDlAAIDqwABAAQC3gACAXYABgAOABQAGgAgACYALACPAAIBcQCQAAIBcgDrAAIBcwMqAAIBdAFYAAIBdQMsAAIBdgADAAgADgAUAuAAAgFyAuIAAgF2APkAAgOrAAMACAAOABQA/AACAXIC5AACAXYA/gACA6sAAgAGAAwC5gACAXIC6AACAXYABQAMABIAGAAeACQBTAACAXEBBgACAXIAlAACAXMC6gACAXYBCAACA6sABgAOABQAGgAgACYALACVAAIBcQCWAAIBcgCYAAIBcwMwAAIBdAFaAAIBdQMuAAIBdgABAAQC7AACAXIABAAKABAAFgAcARcAAgFyAVwAAgF1Au4AAgF2ARkAAgOrAAMACAAOABQBHQACAXIC8AACAXYBYAACA6sAAgAGAAwC8gACAXYBYgACA6sABgAOABQAGgAgACYALACcAAIBcQCdAAIBcgErAAIBcwNIAAIBdAFeAAIBdQNGAAIBdgACAAYADAL0AAIBcwL2AAIBdgADAAgADgAUAvgAAgFxAvoAAgFyAv4AAgF2AAUADAASABgAHgAkA1QAAgFxAKAAAgFyA1oAAgFzA1gAAgF0A1YAAgF2AAIABgAMATwAAgFyAwAAAgF2AAYADgAUABoAIAAmACwAowACAXEApAACAXIApgACAXMDBQACAXQBVQACAXUDAwACAXYAAQAEAtkAAgF2AAEABADKAAIBcgACAAYADALbAAIBdgLdAAIDqwAGAA4AFAAaACAAJgAsAKsAAgFxAKwAAgFyAx8AAgFzAx0AAgF0AVcAAgF1AxsAAgF2AAEABAFLAAIBcgABAAQC3wACAXYAAQAEAy0AAgF2AAMACAAOABQC4QACAXIC4wACAXYA+gACA6sAAwAIAA4AFAD9AAIBcgLlAAIBdgD/AAIDqwACAAYADALnAAIBcgLpAAIBdgAFAAwAEgAYAB4AJAFNAAIBcQEHAAIBcgC0AAIBcwLrAAIBdgEJAAIDqwAGAA4AFAAaACAAJgAsALUAAgFxALYAAgFyALgAAgFzAzEAAgF0AVsAAgF1Ay8AAgF2AAEABALtAAIBcgAEAAoAEAAWABwBGAACAXIBXQACAXUC7wACAXYBGgACA6sAAwAIAA4AFAEeAAIBcgLxAAIBdgFhAAIDqwACAAYADALzAAIBdgFjAAIDqwAGAA4AFAAaACAAJgAsALwAAgFxAL0AAgFyASwAAgFzA0kAAgF0AV8AAgF1A0cAAgF2AAIABgAMAvUAAgFzAvcAAgF2AAMACAAOABQC+QACAXEC+wACAXIC/wACAXYABQAMABIAGAAeACQDVQACAXEAwAACAXIDWwACAXMDWQACAXQDVwACAXYAAgAGAAwBPQACAXIDAQACAXYAAQAEAVAAAgFyAAEABAFSAAIBcgABAAQBUQACAXIAAQAEAVMAAgFyAAUADAASABgAHgAkAK8AAgFxALAAAgFyAOwAAgFzAysAAgF0AVkAAgF1AAUADAASABgAHgAkAz4AAgFxAzwAAgFyA0IAAgFzA0AAAgF0A0QAAgF2AAUADAASABgAHgAkAz8AAgFxAz0AAgFyA0MAAgFzA0EAAgF0A0UAAgF2AAUADAASABgAHgAkA0wAAgFxA0oAAgFyA1AAAgFzA04AAgF0A1IAAgF2AAUADAASABgAHgAkA00AAgFxA0sAAgFyA1EAAgFzA08AAgF0A1MAAgF2AAEABAHBAAIBcgACABEAJQApAAAAKwAtAAUALwA0AAgANgA7AA4APQA+ABQARQBJABYASwBNABsATwBUAB4AVgBbACQAXQBeACoAiQCJACwAmwCbAC0AqQCpAC4AuwC7AC8A9AD0ADABRQFIADEBwAHAADUAAQAAAAEACAABAAYAPwABAAIBIQEiAAEAAAABAAgAAgAOAAQE3QTeBN8E4AABAAQAxwDIANsA3AAEAAAAAQAIAAEAJgACAAoAHAACAAYADAOsAAIASgOxAAIAWAABAAQDsgACAFgAAQACAEoAVwAEAAAAAQAIAAEARAACAAoAFAABAAQDrQACAE0AAQAEA68AAgBNAAQAAAABAAgAAQAeAAIACgAUAAEABAOuAAIAUAABAAQDsAACAFAAAQACAEoDrAABAAAAAQAIAAEABgN5AAEAAQBLAAEAAAABAAgAAQAGAiIAAQABAaEAAQAAAAEACAABAAYDjAABAAEANgABAAAAAQAIAAIAHAACA8EDwAABAAAAAQAIAAIACgACA78DvgABAAIALwBPAAEAAAABAAgAAgAeAAwEMQQzBDIENAQ1BCgEKQQqA/sELAQtBC4AAQAMACcAKAArADMANQBGAEcASABLAFMAVABVAAEAAAABAAgAAgAMAAMELwQwBDAAAQADAEkASwP7AAEAAAABAAgAAgBmAAgERgQ2BDcEOQQ6BEIEQwRFAAEAAAABAAgAAgAWAAgAGwAVABQAHQAZABgAFwAWAAEACAP6BCsEZwRoBGkEagRrBGwAAQAAAAEACAACABYACARnBCsEbARrBGoEaQP6BGgAAQAIABQAFQAWABcAGAAZABsAHQABAAAAAQAIAAIAFgAIABUAFgAXABgAGQAbAB0AFAABAAgENgQ3BDkEOgRCBEMERQRGAAEAAAABAAgAAQAGA3AAAQABABMABgAAAAEACAADAAEAEgABAGYAAAABAAAASgACAAIDgwODAAADxwPQAAEAAQAAAAEACAACADwACgPQA88DzgPNA8wDywPKA8kDyAPHAAEAAAABAAgAAgAaAAoEOwB8AHUAdgQ8BD0EPgQ/BEAEQQACAAEAFAAdAAAAAQAAAAEACAACACYAEAPQA88DzgPNA8wDywPKA8kDyAPHBEkERwRKBEsESAThAAEAEAAUABUAFgAXABgAGQAaABsAHAAdAE0ATgDyAhkCGwMt\",\n  \"Roboto-Regular.ttf\": \"AAEAAAASAQAABAAgR0RFRtRX1FkAAg/sAAACREdQT1NKcuCzAAISMAAAUiRHU1VCw4aZEQACZFQAABfoT1MvMqCnsaYAAAGoAAAAYGNtYXBAmkl2AAAafAAAEshjdnQgJEEG5QAAL9wAAABMZnBnbWf0XKsAAC1EAAABvGdhc3AACAATAAIP4AAAAAxnbHlmHN2bBQAAOfAAAdM2aGRteDc4ERcAABWQAAAE7GhlYWT4RqsOAAABLAAAADZoaGVhCroKggAAAWQAAAAkaG10eOiEiIgAAAIIAAATiGxvY2HgyGepAAAwKAAACcZtYXhwBxIC+QAAAYgAAAAgbmFtZTVTY1kAAg0oAAACmHBvc3T/bQBkAAIPwAAAACBwcmVwdKCP7AAALwAAAADbAAEAAAACAACEKlnoXw889QAbCAAAAAAAxPARLgAAAADQ206a+hv91QkwCHMAAAAJAAIAAAAAAAAAAQAAB2z+DAAACUn6G/5KCTAAAQAAAAAAAAAAAAAAAAAABOIAAQAABOIAjwAWAFQABQABAAAAAAAOAAACAAIUAAYAAQADBIUBkAAFAAAFmgUzAAABHwWaBTMAAAPRAGYCAAAAAgAAAAAAAAAAAOAACv9QACF/AAAAIQAAAABHT09HAEAAAP/9BgD+AABmB5oCACAAAZ8AAAAABDoFsAAgACAAAgOMAGQAAAAAAAAAAAH7AAAB+wAAAg8AoAKPAIgE7QB3BH4AbgXcAGkE+QBlAWUAZwK8AIUCyAAmA3IAHASJAE4BkgAdAjUAJQIbAJADTAASBH4AcwR+AKoEfgBdBH4AXgR+ADUEfgCaBH4AhAR+AE0EfgBwBH4AZAHwAIYBsQApBBEASARkAJgELgCGA8cASwcvAGoFOAAcBPsAqQU1AHcFPwCpBIwAqQRsAKkFcwB6BbQAqQItALcEagA1BQQAqQROAKkG/ACpBbQAqQWAAHYFDACpBYAAbQTtAKgEvwBQBMYAMQUwAIwFFwAcBxkAPQUEADkEzgAPBMoAVgIfAJIDSAAoAh8ACQNYAEADnAAEAnkAOQRaAG0EfQCMBDAAXASDAF8EPQBdAscAPAR9AGAEaACMAfEAjQHp/78EDgCNAfEAnAcDAIsEagCMBJAAWwR9AIwEjABfArUAjAQgAF8CnQAJBGkAiAPgACEGAwArA/cAKQPJABYD9wBYArUAQAHzAK8CtQATBXEAgwHzAIsEYABpBKYAWwW0AGkE2AAfAesAkwToAFoDWABmBkkAWwOTAJMDwQBmBG4AfwZKAFoDqgB4Av0AggRGAGEC7wBCAu8APgKCAHsEiACaA+kAQwIWAJMB+wB0Au8AegOjAHoDwABmBdwAVQY1AFAGOQBvA8kARAd6//IERABZBYAAdgS6AKYEwgCLBsEATgSwAH4EkQBHBIgAWwScAJUFmgAdAfoAmwRzAJoETwAiAikAIgWLAKIEiACRB6EAaAdEAGEB/ACgBYcAXQK5/+QFfgBlBJIAWwWQAIwE8wCIAgP/tAQ3AGIDxACpA40AjAOrAHgDagCBAfEAjQKtAHkCKgAyA8YAewL8AF4CWgB+AAD8pwAA/W8AAPyLAAD9XgAA/CcB7/04Ag0AtwQLAHECFwCTBHMAsQWkAB8FcQBnBT4AMgSRAHgFtQCyBJEARQW7AE0FiQBaBVIAcQSFAGQEvQCgBAIALgSIAGAEUABjBCUAbQSIAJEEjgB6ApcAwwRuACUD7ABlBMQAKQSIAJEETQBlBIgAYAQsAFEEXQCPBaMAVwWaAF8GlwB6BKEAeQRC/9oGSABKBf8AKgVkAHsIkQAxCKQAsQaCAD4FtACwBQsAogYEADIHQwAbBL8AUAW0ALEFqQAvBQcATQYsAFMF2QCvBXoAlgeHALAHwACwBhIAEAbrALIFBQCjBWQAkwcnALcFGABZBGwAYQSSAJ0DWwCaBNQALgYgABUEEABYBJ4AnARSAJwEoAAsBe8AnQSdAJwEngCcA9gAKAXNAGQEvQCcBFkAZwZ4AJwGngCRBPcAHgY2AJ0EWACdBE0AZAaHAJ0EZAAvBGj/6ARNAGcGyQAnBuQAnASJ//0EngCcBwgAnAYrAIEEVv/cBysAtwX4AJkE0gAoBEYADwcLAMkGCwC8BtEAkwXhAJYJBAC2B9EAmwQjAFAD2wBMBXEAZwSLAFsFCgAWBAMALgVxAGcEiABbBwEAnAYkAH4HCACcBisAgQUyAHUERwBkBP0AdAAA/GcAAPxxAAD9ZgAA/aQAAPobAAD6LARW/9wFGwCoBIkAjARjAKIDkACRBNsAsQQFAJEFCQCjBH4AmgaMAEQFgwA+B88AqAW0AJEIMQCwBvQAkQXuAHEE0wBtBywANAVcAB8FbwCWBGoAgwVwAIoGLwA/BL3/3gUJAKMEWgCaBbIAsQSIAJEFhwBdBKgAaASoAGkEtwA6A0kAOwT2AFcGlABZBuQAZAZWADYFKwAxBEkAUgQHAHkHwQBEBnUAPwf7AKkGoQCQBPYAdgQdAGUFrQAjBSAARgVkAJYDIABvBBQAAAgpAAAEFAAACCkAAAK5AAACCgAAAVwAAAR/AAACMAAAAaIAAADRAAAAAAAAAjQAJQI0ACUFQACiBj8AkAOmAA0BmQBgAZkAMAGXACQBmQBPAtQAaALbADwCwQAkBGkARgSPAFcCsgCKA8QAlAVaAJQA9gAmB6oARAJmAGwCZgBZA6MAOwLvADYDYAB6BKYAWwZVAB8GkACnCHYAqAdjADkGKwCMBH4AXwXaAB8EIgAqBHQAIAVIAF0FTwAfBecAegPOAGgIOgCiBQEAZwUXAJgGJgBUBtcAZAbPAGMGagBZBI8AagWOAKkErwBFBJIAqATFAD8IOgBiAgz/sASCAGUEZACYBBEAPgQvAIUECAArAkwAtQKPAG4CAwBcBPMAPARuAB8EiwA8BtQAPAbUADwE7gA8BpsAXwAAAAAIMwBbCDUAXAQgADsEngBaAfz/tgGRAGcDpACDA54AgQOfAIED9ABpBA4AaQPz/14D7wBuA6QAgQH9AJ8EhQATBFAAigR8AGAEgACKA+YAigPLAIoErABjBOMAigHoAJcDzwArBFQAigO0AIoGAgCKBOMAigS7AGAEXACKBLsAWQRKAIoEIABDBCYAKAR8AHQEZwAUBhUAMQRUACYEKwANBCMARwLvAFAC7wB6Au8AQgLvAD4C7wA2Au8AWwLvAFYC7wA6Au8ATwLvAEkDlgCPArUAngQ6AB4EwwBkBUwAsQUkALIEEwCSBT0AsgQPAJIEIABDBDMAMAQ8ABYDrwCKBGcAFAS7AGAEZwAUA4kAPgTOAIoD7wA/BWcAYAUXAGAE8gB1BXIAJgR8AGAHQQAnB08AigV0ACgEzQCKBFkAigUkAC4GCwAfBD8ARwTsAIoETgCLBMEAJwQfACIFKACKBGoAPQZRAIoGrACKBR0ACAXxAIoETgCKBHsASwZ2AIoEhwBQBBEACwZHAB8EeQCLBQkAiwU3ACMFwgBgBF8ADQSoACYGYQAmBGoAPQRqAIoFwwACBMoAXgQ/AEcEuwBgBDMAMAPjAEIIIgCKBKsAKAR9AIwEMgBcBJMAWwSMAFsDeQBXBI0AjAScAFsEPQBdBH0AYAWBAH4FrgB+BZMAsgXgAH4F4wB+A9UAoASCAIMDrwCKBFgADwTPAD4C7wBQAu8ANgLvAFsC7wBWAu8AOgLvAE8C7wBJBGsAZQQuAEoGpABgBLkAggUAAHgCBv+0AgT/tAH7AJsB+//6AfsAmwH7AIYEUACKAfsAAAI1ACUFXQAlBV0AJQSGAAAExgAxAp3/9AU4ABwFOAAcBTgAHAU4ABwFOAAcBTgAHAU4ABwFNQB3BIwAqQSMAKkEjACpBIwAqQIt/+ACLQCwAi3/6QIt/9YFtACpBYAAdgWAAHYFgAB2BYAAdgWAAHYFMACMBTAAjAUwAIwFMACMBM4ADwRaAG0EWgBtBFoAbQRaAG0EWgBtBFoAbQRaAG0EMABcBD0AXQQ9AF0EPQBdBD0AXQH6/8YB+gCWAfr/zwH6/7wEagCMBJAAWwSQAFsEkABbBJAAWwSQAFsEaQCIBGkAiARpAIgEaQCIA8kAFgPJABYFOAAcBFoAbQU4ABwEWgBtBTgAHARaAG0FNQB3BDAAXAU1AHcEMABcBTUAdwQwAFwFNQB3BDAAXAU/AKkFGQBfBIwAqQQ9AF0EjACpBD0AXQSMAKkEPQBdBIwAqQQ9AF0EjACpBD0AXQVzAHoEfQBgBXMAegR9AGAFcwB6BH0AYAVzAHoEfQBgBbQAqQRoAIwCLf+3Afr/nQIt/7YB+v+cAi3/7AH6/9ICLQAYAfH/+wItAKoGlwC3A9oAjQRqADUCA/+0BQQAqQQOAI0ETgChAfEAkwROAKkB8QBXBE4AqQKHAJwETgCpAs0AnAW0AKkEagCMBbQAqQRqAIwFtACpBGoAjARq/7wFgAB2BJAAWwWAAHYEkABbBYAAdgSQAFsE7QCoArUAjATtAKgCtQBTBO0AqAK1AGMEvwBQBCAAXwS/AFAEIABfBL8AUAQgAF8EvwBQBCAAXwS/AFAEIABfBMYAMQKdAAkExgAxAp0ACQTGADECxQAJBTAAjARpAIgFMACMBGkAiAUwAIwEaQCIBTAAjARpAIgFMACMBGkAiAUwAIwEaQCIBxkAPQYDACsEzgAPA8kAFgTOAA8EygBWA/cAWATKAFYD9wBYBMoAVgP3AFgHev/yBsEATgWAAHYEiABbBID/vgSA/74EJgAoBIUAEwSFABMEhQATBIUAEwSFABMEhQATBIUAEwR8AGAD5gCKA+YAigPmAIoD5gCKAej/vgHoAI4B6P/HAej/tATjAIoEuwBgBLsAYAS7AGAEuwBgBLsAYAR8AHQEfAB0BHwAdAR8AHQEKwANBIUAEwSFABMEhQATBHwAYAR8AGAEfABgBHwAYASAAIoD5gCKA+YAigPmAIoD5gCKA+YAigSsAGMErABjBKwAYwSsAGME4wCKAej/lQHo/5QB6P/KAegABgHoAIkDzwArBFQAigO0AIIDtACKA7QAigO0AIoE4wCKBOMAigTjAIoEuwBgBLsAYAS7AGAESgCKBEoAigRKAIoEIABDBCAAQwQgAEMEIABDBCYAKAQmACgEJgAoBHwAdAR8AHQEfAB0BHwAdAR8AHQEfAB0BhUAMQQrAA0EKwANBCMARwQjAEcEIwBHBTgAHATw//AGGP/+ApEABAWU//oFMv94BWb//QKX/5sFOAAcBPsAqQSMAKkEygBWBbQAqQItALcFBACpBvwAqQW0AKkFgAB2BQwAqQTGADEEzgAPBQQAOQIt/9YEzgAPBIUAZARQAGMEiACRApcAwwRdAI8EcwCaBJAAWwSIAJoD4AAhA/cAKQKX/+YEXQCPBJAAWwRdAI8GlwB6BIwAqQRzALEEvwBQAi0AtwIt/9YEagA1BSQAsgUEAKkFBwBNBTgAHAT7AKkEcwCxBIwAqQW0ALEG/ACpBbQAqQWAAHYFtQCyBQwAqQU1AHcExgAxBQQAOQRaAG0EPQBdBJ4AnASQAFsEfQCMBDAAXAPJABYD9wApBD0AXQNbAJoEIABfAfEAjQH6/7wB6f+/BFIAnAPJABYHGQA9BgMAKwcZAD0GAwArBxkAPQYDACsEzgAPA8kAFgFlAGcCjwCIBB4AoAID/7QBmQAwBvwAqQcDAIsFOAAcBFoAbQSMAKkFtACxBD0AXQSeAJwFiQBaBZoAXwUKABYEA//7CFkAWwlJAHYEvwBQBBAAWAU1AHcEMABcBM4ADwQCAC4CLQC3B0MAGwYgABUCLQC3BTgAHARaAG0FOAAcBFoAbQd6//IGwQBOBIwAqQQ9AF0FhwBdBDcAYgQ3AGIHQwAbBiAAFQS/AFAEEABYBbQAsQSeAJwFtACxBJ4AnAWAAHYEkABbBXEAZwSLAFsFcQBnBIsAWwVkAJMETQBkBQcATQPJABYFBwBNA8kAFgUHAE0DyQAWBXoAlgRZAGcG6wCyBjYAnQUEADkD9wApBIMAXwWpAC8EoAAsBTgAHARaAG0FOAAcBFoAbQU4ABwEWgBtBTgAHARa/8oFOAAcBFoAbQU4ABwEWgBtBTgAHARaAG0FOAAcBFoAbQU4ABwEWgBtBTgAHARaAG0FOAAcBFoAbQU4ABwEWgBtBIwAqQQ9AF0EjACpBD0AXQSMAKkEPQBdBIwAqQQ9AF0EjP/wBD3/ugSMAKkEPQBdBIwAqQQ9AF0EjACpBD0AXQItALcB+gCbAi0AowHxAIUFgAB2BJAAWwWAAHYEkABbBYAAdgSQAFsFgABHBJD/xAWAAHYEkABbBYAAdgSQAFsFgAB2BJAAWwV+AGUEkgBbBX4AZQSSAFsFfgBlBJIAWwV+AGUEkgBbBX4AZQSSAFsFMACMBGkAiAUwAIwEaQCIBZAAjATzAIgFkACMBPMAiAWQAIwE8wCIBZAAjATzAIgFkACMBPMAiATOAA8DyQAWBM4ADwPJABYEzgAPA8kAFgShAF8EoQBfBSQAsgRSAJwFtACpBJ0AnATGADED2AAoBQQAOQP3ACkFegCWBFkAZwV6AJYEWQBnBHMAsQNbAJoHQwAbBiAAFQYvAD8Evf/eBGgAjAUF/9QFBf/UBHMAAwNb//wFOAALBCf/0wW0ALEEngCcBbQAqQSdAJwG/ACpBe8AnQWpAC8EoAAsBM4ADwQCAC4FBAA5A/cAKQRQAGMEbAASBj8AkAR+AF0EfgBeBH4ANQR+AJoEkgBkBKYAhwVzAHoEfQBgBbQAqQRqAIwFOAAcBFoAOQSMAF8EPQApAi3/CgH6/vAFgAB2BJAAMwTtAFUCtf+LBTAAjARpACsEpv86BPsAqQR9AIwFPwCpBIMAXwU/AKkEgwBfBbQAqQRoAIwFBACpBA4AjQUEAKkEDgCNBE4AqQHxAIYG/ACpBwMAiwW0AKkEagCMBQwAqQR9AIwE7QCoArUAggS/AFAEIABfBMYAMQKdAAkFFwAcA+AAIQUXABwD4AAhBxkAPQYDACsEygBWA/cAWAXG/ngEhQATBCL/nwUf/7wCJP/ABMX/3wRn/1cE/P/4BIUAEwRQAIoD5gCKBCMARwTjAIoB6ACXBFQAigYCAIoEuwBgBFwAigQmACgEKwANBFQAJgHo/7QEKwANA+YAigOvAIoEIABDAegAlwHo/7QDzwArBFQAigQfACIEhQATBFAAigOvAIoD5gCKBOwAigYCAIoE4wCKBLsAYATOAIoEXACKBHwAYAQmACgEVAAmBD8ARwTjAIoEfABgBCsADQXDAAIE7ACKBB8AIgVnAGAFOAAcBFoAbQSMAKkEPQBdAAAAAQAABOQJCgQAAAICAgMGBQcGAgMDBAUCAgIEBQUFBQUFBQUFBQICBQUFBAgGBgYGBQUGBgIFBgUIBgYGBgYFBQYGCAYFBQIEAgQEAwUFBQUFAwUFAgIFAggFBQUFAwUDBQQHBAQEAwIDBgIFBQYFAgYEBwQEBQcEAwUDAwMFBAICAwQEBwcHBAgFBgUFCAUFBQUGAgUFAgYFCQgCBgMGBQYGAgUEBAQEAgMCBAMDAAAAAAACAgUCBQYGBgUGBQYGBgUFBQUFBQUFAwUEBQUFBQUFBgYHBQUHBwYKCgcGBgcIBQYGBgcHBggJBwgGBggGBQUEBQcFBQUFBwUFBAcFBQcHBgcFBQcFBQUICAUFCAcFCAcFBQgHCAcKCQUEBgUGBQYFCAcIBwYFBgAAAAAAAAUGBQUEBQUGBQcGCQYJCAcFCAYGBQYHBQYFBgUGBQUFBAYHCAcGBQUJBwkHBgUGBgYEBQkFCQMCAgUCAgEAAgIGBwQCAgICAwMDBQUDBAYBCQMDBAMEBQcHCggHBQcFBQYGBwQJBgYHCAgHBQYFBQUJAgUFBQUFAwMCBgUFCAgGBwAJCQUFAgIEBAQEBQQEBAIFBQUFBAQFBgIEBQQHBgUFBQUFBQUFBwUFBQMDAwMDAwMDAwMEAwUFBgYFBgUFBQUEBQUFBAUEBgYGBgUICAYFBQYHBQYFBQUGBQcIBgcFBQcFBQcFBgYGBQUHBQUGBQUFBQQJBQUFBQUEBQUFBQYGBgcHBAUEBQUDAwMDAwMDBQUHBQYCAgICAgIFAgIGBgUFAwYGBgYGBgYGBQUFBQICAgIGBgYGBgYGBgYGBQUFBQUFBQUFBQUFBQICAgIFBQUFBQUFBQUFBAQGBQYFBgUGBQYFBgUGBQYGBQUFBQUFBQUFBQYFBgUGBQYFBgUCAgICAgICAgIHBAUCBgUFAgUCBQMFAwYFBgUGBQUGBQYFBgUGAwYDBgMFBQUFBQUFBQUFBQMFAwUDBgUGBQYFBgUGBQYFCAcFBAUFBAUEBQQICAYFBQUFBQUF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sRCxUrG2sc2x5LH7shKyK7JEslCyXLJzsoqyobK6stGy6LL/sxizL7NGs12zdLOLs6Szu7PSs+m0ArQZtDC0R7RdtHO0jLSltLG0vbTUtOu1AbUatTC1RrVdtXa1jLWjtbq10LXmtf+2FrYttkO2XLZztou2ora4ts+25rdJt9+39rgNuCS4OrhRuGi4f7iVuKy43bj0uQq5Ibk4uU+5ZrnOulK6abp/upa6rLrDutq68bsIuxS7K7tCu1S7a7uCu5m7sLvHu9676bv0vAu8F7wjvDq8UbxdvGm8gLyXvKO8r7zEvPm9Bb0RvSi9P71LvVe9br2EvZS9q73Bvdi9774IviG+OL5Pvlu+Z75+vpS+q77Cvtm+7777vwe/E78fvza/TL9Yv2S/cL98v5O/n7+2v8y/47/5wBDAJ8BAwFnAcsCLwOjBTsFlwXzBk8GpwcLB2cHwwgfCHsI1wkvCYsJ5wpDCp8LKwvLDBcMcwzPDScNfw3jDkcOdw6nDwMPXw+3EBcQbxDHESMRhxHjEj8SmxL3E1MTtxQTFG8UxxUrFYcV3xY7F8cYIxh7GNcZMxmLGeMaOxqXHDsckxzrHUcdox3THi8eix7nH0Mfbx/HICMgUyCrINshLyFfIbsh6yJHIqMi/yNjI78j7yRHJKMk+yUrJYMlsyYLJjsmkybrJ0cnqygPKX8p2yozKpMq7ytLK6Mrzyv/LC8sXyyPLL8s7y1fLX8tny2/Ld8t/y4fLj8uXy5/Lp8uvy7fLv8vHy+DL+cwQzCfMPsxUzG/Md8x/zIfMj8yXzK/Mx8zezPXNDM0lzTzNp82vzcjN0M3Yze/OBs4OzhbOHs4mzj3ORc5NzlXOXc5lzm3Odc59zoXOjc6kzqzOtM8Hzw/PF88wz0fPT89Xz3DPeM+Pz6XPvM/Tz+rQAdAa0DPQStBh0GnQcdB90JTQnNCz0MrQ1tDi0PnRENEn0T7RRtFO0WfRgNGM0ZjRpNGw0bzRyNHQ0djR4NH30g7SFtIt0kTSW9J00nzShNKb0rLSy9LT0uzTBdMe0zfTT9Nm03zTldOu08fT4NPo0/DUCdQi1DvUU9Rq1IDUmdSx1MrU49T81RTVMdVO1VrVZtVu1XrVhtWS1Z7VtdXM1eXV/dYW1i7WR9Zf1njWkNar1sXW3tb31xDXKddC11vXdNeN16jXw9fP19vX8tgJ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AAUAJABIAAEA3gAIACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgBlAGcAkgCwALEAsgCzALQAtQC2ALcAuAC5ANEA0gDTANQA1QDWANcA2ADZANoA2wDcAN0A3gDfAOAA4QDiAOMA5ADlAOYA5wDoASwBMAEyATgBOgE8AT4BPwFFAUYBfwGFAYoBjQJHAkgCSgJMAk0CTgJPAlACUQJSAlMCVAJVAlYCVwJYAlkCWgJbAlwCXQJeAl8CYAJhAmICYwJkAmUCZgKDAoUChwKJAosCjQKPApECkwKVApcCmQKbAp0CnwKhAqMCpQKnAqkCqwKtAq8CsgK0ArYCuAK6ArwCvgLAAsICxQLHAskCywLNAs8C0QLTAtUC2QLbAt0C3wLhAuMC5QLnAukC6wLtAu8C8QLyAvQC9gNTA1QDVQNWA1cDWANZA1sDXANdA14DXwNgA2EDYgNkA2UDZgNnA2gDaQNqA3oDewN8A30DfgN/A4ADgQOCA4MDhAOFA4YDhwOIA4kDigOLA4wDjQOOA48DuwO9A78D1APaA+AESQRLBE8EVwRZBF4EagACAAAABAAOD84V8jViAAEDVAAEAAABpQrSCtIGggtwCoAK/g+aDAAGiA7uDu4MRg6gCiIO7g7uD5oKigaSDGYMRgrYCqwNUg8QCl4L4gsQDBYGmA22DbYNtgwgCxAKUAxMDbAMTAsQBqYN5gtwD5oLcAasBrIGvAbCBsgMTAbOBtgNtgb+BxQHKgcwB0YHTAdSB4QHigeQDcANwAe+Du4H4AgCDVIIMA7uDu4LJg7uDu4IRg3ADcAIeAiCCIwIpg1ICLgNsAjSCOgLEAkyCUwJaAloCxAJYgloCWgJaAtwDCAK2AxMCxAN5g1IDqAOoA1ICtIK0grSCtIK0gmKCbAJugnECeIJ9AoGChgK/g+aD5oPmg+aDGYLcAtwC3ALcAtwC3ALcAr+DAAMAAwADAAO7g7uDu4O7g7uD5oPmg+aD5oPmgxGDEYMRgxGDxAL4gviC+IL4gviC+IL4gwWDBYMFgwWDbYMIAwgDCAMIAwgDEwMTAtwC+ILcAviC3AL4gr+Cv4K/gr+D5oMAAwWDAAMFgwADBYMAAwWDAAMFg7uDbYO7g7uDu4O7g7uDEYOoAoiCiIKIgoiDu4Ntg7uDbYO7g22DbYPmgwgD5oMIA+aDCAKUApQClAMZgxmDGYMRgxGDEYMRgxGDEYKrA8QDEwPEApeCl4KXgtwDAAO7g7uD5oPEAtwCoAMAApeDu4O7g6gDu4O7g+aCooMZg8QDVIO7g8QDbYMIAxMDCAMAA3mDu4O7gxGDqAOoAsmC3AKgA3mDAAO7g7uD5oKigr+DGYNUgviDBYMIAsQDEwNsAwWDUgMTAqsCqwKrA8QDEwK0grSCtIO7g22C3AL4gwADBYK2AxMCv4PEAxMDu4NUg2wDu4LcAviC3AL4gwADBYMFgwWDVINsA+aDCAMIAsQCyYMTAsmDEwLJgxMDVINsAtwC+ILcAviC3AL4gtwC+ILcAviC3AL4gtwC+ILcAviC3AL4gtwC+ILcAviC3AL4gwADBYMAAwWDAAMFgwADBYMAAwWDAAMFgwADBYMAAwWDu4O7g+aDCAPmgwgD5oMIA+aDCAPmgwgD5oMIA+aDCAMIAxGDEYPEAxMDxAMTA8QDEwOoA7uDGYNUg2wDeYNSA1SDbANtg3ADeYOoA7uDu4PEA+aAAIAhwAGAAYAAAALAAsAAQATABMAAgAlACoAAwAsADUACQA4AD4AEwBFAEYAGgBJAEoAHABMAEwAHgBRAFQAHwBWAFYAIwBaAFoAJABcAF0AJQCKAIoAJwCcAJwAKACwALQAKQC2ALgALgC6ALoAMQC8AL0AMgC/AMAANADCAMQANgDGAMsAOQDRANEAPwDTAN0AQADfAN8ASwDhAOMATADlAOcATwDpAO0AUgDwAPAAVwD1APcAWAD6APsAWwD9AP8AXQEDAQQAYAEJAQkAYgEMAQwAYwEXARkAZAErAS0AZwEwATAAagEyATIAawFJAUkAbAFsAW0AbQFvAXEAbwG6AboAcgG9Ab0AcwHEAcUAdAHIAcgAdgHKAcsAdwHNAc0AeQIoAigAegIqAisAewJHAkgAfQJKAkoAfwJMAm0AgAJvAnIAogJ3AnwApgKBAokArAKLAosAtQKNAo0AtgKPAo8AtwKRApEAuAKTApwAuQKlAqcAwwKpAqkAxgKrAqsAxwKtAq0AyAKvAq8AyQKyArIAygK0ArQAywK2ArYAzAK4ArgAzQK6AroAzgK8ArwAzwK+AsoA0ALMAswA3QLOAs4A3gLQAtAA3wLbAtsA4ALdAt0A4QLfAt8A4gLh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BB7/6wQg/+sEIv/rBCT/6wQm/+sEKP/rBCr/6wQs/+sELv/rBDD/6wQy/+sENP/qBDb/6gQ4/+oEOv/qBDz/6gQ+/+oEQP/qBEL/6ARE/+gERv/oBE0AFAAfADj/1QA6/+QAO//sAD3/3QDR/9UA1f/VARj/5AEy/9UBOv/VAmb/3QLb/9UC3f/VAt//1QLt/+wC7//dAvH/3QNY/90DZ//dA2r/3QOO/9UDoP/sA6L/7AOk/+wDpv/dA7f/5AO//90EQf/dBEP/3QRF/90ETf/VBGr/3QAaADj/sAA6/+0APf/QANH/sADV/7ABGP/tATL/sAE6/7ACZv/QAtv/sALd/7AC3/+wAu//0ALx/9ADWP/QA2f/0ANq/9ADjv+wA6b/0AO3/+0Dv//QBEH/0ARD/9AERf/QBE3/sARq/9AAEAAu/+4AOf/uAmL/7gJj/+4CZP/uAmX/7gKy/+4C4f/uAuP/7gLl/+4C5//uAun/7gLr/+4Df//uBDP/7gQ1/+4ARwAGABAACwAQAEf/6ABI/+gASf/oAEv/6ABV/+gAk//oAJj/6AC6/+gAx//oAMj/6AD2/+gBAv/oAR3/6AEh/+gBOf/oAUv/6AFM/+gBVv/oAWwAEAFtABABbwAQAXAAEAFxABACbv/oAm//6AJw/+gCcf/oAnL/6AKK/+gCjP/oAo7/6AKQ/+gCkv/oApT/6AKW/+gCmP/oApr/6AKc/+gCnv/oAqD/6AKi/+gCpP/oA2v/6AOR/+gDlf/oA5j/6AOoABADqQAQA6wAEAOz/+gDuf/oA77/6APM/+gDzv/oA8//6APb/+gD7P/oBAj/6AQK/+gEDP/oBA7/6AQQ/+gEEv/oBBT/6AQW/+gEKv/oBCz/6AQu/+gEMv/oAAEAVgAEAAAAJgCmAZwB+gIUAlYCzAPCBLgFkgYsCMYKjAteDFQOGg5MDn4O/BDiEVgSKhRMFQIWaBciF6gYBhjIGT4ewBlQGqIc4B0CHhgelh7AHuoAAQAmAE8AWABbAF8AnAC0ALYAtwC4AL8AwgDDAMQAyQDLAMwAzQDRANUA1wDYANoA4gDmAOcA6ADpAOoA7ADuAPAA9QD3APoA/wECASEBbQA9AEf/7ABI/+wASf/sAEv/7ABV/+wAk//sAJj/7AC6/+wAx//sAMj/7AD2/+wBAv/sAR3/7AEh/+wBOf/sAUv/7AFM/+wBVv/sAm7/7AJv/+wCcP/sAnH/7AJy/+wCiv/sAoz/7AKO/+wCkP/sApL/7AKU/+wClv/sApj/7AKa/+wCnP/sAp7/7AKg/+wCov/sAqT/7ANr/+wDkf/sA5X/7AOY/+wDs//sA7n/7AO+/+wDzP/sA87/7APP/+wD2//sA+z/7AQI/+wECv/sBAz/7AQO/+wEEP/sBBL/7AQU/+wEFv/sBCr/7AQs/+wELv/sBDL/7AAXAFP/7AEX/+wCeP/sAnn/7AJ6/+wCe//sAnz/7ALG/+wCyP/sAsr/7ANx/+wDd//sA5P/7APZ/+wD3f/sBBz/7AQe/+wEIP/sBCL/7AQk/+wEJv/sBCj/7AQw/+wABgAQ/4QAEv+EAW7/hAFy/4QBdv+EAXf/hAAQAC7/7AA5/+wCYv/sAmP/7AJk/+wCZf/sArL/7ALh/+wC4//sAuX/7ALn/+wC6f/sAuv/7AN//+wEM//sBDX/7AAdAAb/8gAL//IAWv/zAF3/8wC8//MBGf/zAWz/8gFt//IBb//yAXD/8gFx//ICgf/zAoL/8wLw//MDc//zA5b/8wOf//MDp//zA6j/8gOp//IDrP/yA7j/8wPA//MD4f/zA+P/8wPl//MEQv/zBET/8wRG//MAPQAn//MAK//zADP/8wA1//MAg//zAJL/8wCX//MAsv/zANL/8wEH//MBFv/zARr/8wEc//MBHv/zASD/8wE4//MBVf/zAij/8wIp//MCK//zAiz/8wJT//MCXf/zAl7/8wJf//MCYP/zAmH/8wKJ//MCi//zAo3/8wKP//MCnf/zAp//8wKh//MCo//zAsX/8wLH//MCyf/zAvr/8wNX//MDZP/zA4r/8wON//MDuv/zA73/8wPY//MD2v/zA9z/8wQb//MEHf/zBB//8wQh//MEI//zBCX/8wQn//MEKf/zBCv/8wQt//MEL//zBDH/8wSq//MAPQAn/+YAK//mADP/5gA1/+YAg//mAJL/5gCX/+YAsv/mANL/5gEH/+YBFv/mARr/5gEc/+YBHv/mASD/5gE4/+YBVf/mAij/5gIp/+YCK//mAiz/5gJT/+YCXf/mAl7/5gJf/+YCYP/mAmH/5gKJ/+YCi//mAo3/5gKP/+YCnf/mAp//5gKh/+YCo//mAsX/5gLH/+YCyf/mAvr/5gNX/+YDZP/mA4r/5gON/+YDuv/mA73/5gPY/+YD2v/mA9z/5gQb/+YEHf/mBB//5gQh/+YEI//mBCX/5gQn/+YEKf/mBCv/5gQt/+YEL//mBDH/5gSq/+YANgAl/+QAPP/SAD3/0wCx/+QAs//kANn/0gEM/+QCTP/kAk3/5AJO/+QCT//kAlD/5AJR/+QCUv/kAmb/0wKD/+QChf/kAof/5ALv/9MC8f/TA1P/5ANY/9MDW//kA2f/0wNo/9IDav/TA4P/5AOP/9IDpv/TA6//5AO//9MDwv/SA8X/5APH/+QD0P/SA+r/0gPv/+QD8f/kA/P/5AP1/+QD9//kA/n/5AP7/+QD/f/kA///5AQB/+QEA//kBAX/5ARB/9MEQ//TBEX/0wRP/9IEV//SBGr/0wAmABD/HgAS/x4AJf/NALH/zQCz/80BDP/NAW7/HgFy/x4Bdv8eAXf/HgJM/80CTf/NAk7/zQJP/80CUP/NAlH/zQJS/80Cg//NAoX/zQKH/80DU//NA1v/zQOD/80Dr//NA8X/zQPH/80D7//NA/H/zQPz/80D9f/NA/f/zQP5/80D+//NA/3/zQP//80EAf/NBAP/zQQF/80ApgBH/9wASP/cAEn/3ABL/9wAUf/zAFL/8wBT/9YAVP/zAFX/3ABZ/90AWv/hAF3/4QCT/9wAmP/cAJr/3QC6/9wAvP/hAMD/8wDH/9wAyP/cAMr/3QDr//MA7//zAPD/8wDy//MA8//zAPT/8wD2/9wA9//zAPn/8wD6//MA/f/zAP//8wEC/9wBBP/zARf/1gEZ/+EBHf/cASH/3AE1//MBOf/cAUT/8wFJ//MBS//cAUz/3AFW/9wCbv/cAm//3AJw/9wCcf/cAnL/3AJ3//MCeP/WAnn/1gJ6/9YCe//WAnz/1gJ9/90Cfv/dAn//3QKA/90Cgf/hAoL/4QKK/9wCjP/cAo7/3AKQ/9wCkv/cApT/3AKW/9wCmP/cApr/3AKc/9wCnv/cAqD/3AKi/9wCpP/cAr//8wLB//MCw//zAsT/8wLG/9YCyP/WAsr/1gLi/90C5P/dAub/3QLo/90C6v/dAuz/3QLw/+EDa//cA23/8wNv/90Dcf/WA3P/4QN2/90Dd//WA3j/3QOR/9wDkv/zA5P/1gOU//MDlf/cA5b/4QOY/9wDmf/zA57/8wOf/+EDp//hA67/8wOz/9wDtP/zA7j/4QO5/9wDvv/cA8D/4QPM/9wDzv/cA8//3APV//MD1//zA9n/1gPb/9wD3f/WA+H/4QPj/+ED5f/hA+n/8wPs/9wECP/cBAr/3AQM/9wEDv/cBBD/3AQS/9wEFP/cBBb/3AQc/9YEHv/WBCD/1gQi/9YEJP/WBCb/1gQo/9YEKv/cBCz/3AQu/9wEMP/WBDL/3AQ0/90ENv/dBDj/3QQ6/90EPP/dBD7/3QRA/90EQv/hBET/4QRG/+EESv/zBEz/8wRW//MEY//zBGX/8wRn//MAcQAG/9oAC//aAEf/8ABI//AASf/wAEv/8ABV//AAWf/vAFr/3ABd/9wAk//wAJj/8ACa/+8Auv/wALz/3ADH//AAyP/wAMr/7wD2//ABAv/wARn/3AEd//ABIf/wATn/8AFL//ABTP/wAVb/8AFs/9oBbf/aAW//2gFw/9oBcf/aAm7/8AJv//ACcP/wAnH/8AJy//ACff/vAn7/7wJ//+8CgP/vAoH/3AKC/9wCiv/wAoz/8AKO//ACkP/wApL/8AKU//AClv/wApj/8AKa//ACnP/wAp7/8AKg//ACov/wAqT/8ALi/+8C5P/vAub/7wLo/+8C6v/vAuz/7wLw/9wDa//wA2//7wNz/9wDdv/vA3j/7wOR//ADlf/wA5b/3AOY//ADn//cA6f/3AOo/9oDqf/aA6z/2gOz//ADuP/cA7n/8AO+//ADwP/cA8z/8APO//ADz//wA9v/8APh/9wD4//cA+X/3APs//AECP/wBAr/8AQM//AEDv/wBBD/8AQS//AEFP/wBBb/8AQq//AELP/wBC7/8AQy//AENP/vBDb/7wQ4/+8EOv/vBDz/7wQ+/+8EQP/vBEL/3ARE/9wERv/cADQABv+gAAv/oABZ//EAWv/FAF3/xQCa//EAvP/FAMr/8QEZ/8UBbP+gAW3/oAFv/6ABcP+gAXH/oAJ9//ECfv/xAn//8QKA//ECgf/FAoL/xQLi//EC5P/xAub/8QLo//EC6v/xAuz/8QLw/8UDb//xA3P/xQN2//EDeP/xA5b/xQOf/8UDp//FA6j/oAOp/6ADrP+gA7j/xQPA/8UD4f/FA+P/xQPl/8UENP/xBDb/8QQ4//EEOv/xBDz/8QQ+//EEQP/xBEL/xQRE/8UERv/FAD0AR//nAEj/5wBJ/+cAS//nAFX/5wCT/+cAmP/nALr/5wDH/+cAyP/nAPb/5wEC/+cBHf/nASH/5wE5/+cBS//nAUz/5wFW/+cCbv/nAm//5wJw/+cCcf/nAnL/5wKK/+cCjP/nAo7/5wKQ/+cCkv/nApT/5wKW/+cCmP/nApr/5wKc/+cCnv/nAqD/5wKi/+cCpP/nA2v/5wOR/+cDlf/nA5j/5wOz/+cDuf/nA77/5wPM/+cDzv/nA8//5wPb/+cD7P/nBAj/5wQK/+cEDP/nBA7/5wQQ/+cEEv/nBBT/5wQW/+cEKv/nBCz/5wQu/+cEMv/nAHEABgAMAAsADABH/+gASP/oAEn/6ABL/+gAU//qAFX/6ABaAAsAXQALAJP/6ACY/+gAuv/oALwACwDH/+gAyP/oAPb/6AEC/+gBF//qARkACwEd/+gBIf/oATn/6AFL/+gBTP/oAVb/6AFsAAwBbQAMAW8ADAFwAAwBcQAMAm7/6AJv/+gCcP/oAnH/6AJy/+gCeP/qAnn/6gJ6/+oCe//qAnz/6gKBAAsCggALAor/6AKM/+gCjv/oApD/6AKS/+gClP/oApb/6AKY/+gCmv/oApz/6AKe/+gCoP/oAqL/6AKk/+gCxv/qAsj/6gLK/+oC8AALA2v/6ANx/+oDcwALA3f/6gOR/+gDk//qA5X/6AOWAAsDmP/oA58ACwOnAAsDqAAMA6kADAOsAAwDs//oA7gACwO5/+gDvv/oA8AACwPM/+gDzv/oA8//6APZ/+oD2//oA93/6gPhAAsD4wALA+UACwPs/+gECP/oBAr/6AQM/+gEDv/oBBD/6AQS/+gEFP/oBBb/6AQc/+oEHv/qBCD/6gQi/+oEJP/qBCb/6gQo/+oEKv/oBCz/6AQu/+gEMP/qBDL/6ARCAAsERAALBEYACwAMAFz/7QBe/+0A7f/tAvP/7QL1/+0C9//tA5f/7QPD/+0D0f/tA+v/7QRQ/+0EWP/tAAwAXP/yAF7/8gDt//IC8//yAvX/8gL3//IDl//yA8P/8gPR//ID6//yBFD/8gRY//IAHwBa//QAXP/yAF3/9ABe//MAvP/0AO3/8gEZ//QCgf/0AoL/9ALw//QC8//zAvX/8wL3//MDc//0A5b/9AOX//IDn//0A6f/9AO4//QDwP/0A8P/8gPR//ID4f/0A+P/9APl//QD6//yBEL/9ARE//QERv/0BFD/8gRY//IAeQAG/8oAC//KADj/0gA6/9QAPP/0AD3/0wBR/9EAUv/RAFT/0QBa/+YAXP/vAF3/5gC8/+YAwP/RANH/0gDV/9IA2f/0AN3/7QDg/+EA6//RAO3/7wDv/9EA8P/RAPL/0QDz/9EA9P/RAPf/0QD5/9EA+v/RAP3/0QD//9EBBP/RARj/1AEZ/+YBMv/SATX/0QE6/9IBRP/RAUn/0QFs/8oBbf/KAW//ygFw/8oBcf/KAmb/0wJ3/9ECgf/mAoL/5gK//9ECwf/RAsP/0QLE/9EC2//SAt3/0gLf/9IC7//TAvD/5gLx/9MDWP/TA2f/0wNo//QDav/TA23/0QNz/+YDgv/tA47/0gOP//QDkv/RA5T/0QOW/+YDl//vA5n/0QOe/9EDn//mA6b/0wOn/+YDqP/KA6n/ygOs/8oDrv/RA7T/0QO3/9QDuP/mA7//0wPA/+YDwv/0A8P/7wPQ//QD0f/vA9X/0QPX/9ED4P/tA+H/5gPi/+0D4//mA+T/7QPl/+YD5v/hA+n/0QPq//QD6//vBEH/0wRC/+YEQ//TBET/5gRF/9MERv/mBEr/0QRM/9EETf/SBE//9ARQ/+8EUf/hBFP/4QRW/9EEV//0BFj/7wRj/9EEZf/RBGf/0QRq/9MAHQA4/74AWv/vAF3/7wC8/+8A0f++ANX/vgEZ/+8BMv++ATr/vgKB/+8Cgv/vAtv/vgLd/74C3/++AvD/7wNz/+8Djv++A5b/7wOf/+8Dp//vA7j/7wPA/+8D4f/vA+P/7wPl/+8EQv/vBET/7wRG/+8ETf++ADQAOP/mADr/5wA8//IAPf/nAFz/8QDR/+YA1f/mANn/8gDd/+4A4P/oAO3/8QEY/+cBMv/mATr/5gJm/+cC2//mAt3/5gLf/+YC7//nAvH/5wNY/+cDZ//nA2j/8gNq/+cDgv/uA47/5gOP//IDl//xA6b/5wO3/+cDv//nA8L/8gPD//ED0P/yA9H/8QPg/+4D4v/uA+T/7gPm/+gD6v/yA+v/8QRB/+cEQ//nBEX/5wRN/+YET//yBFD/8QRR/+gEU//oBFf/8gRY//EEav/nAIgAJQAQACf/6AAr/+gAM//oADX/6AA4/+AAOv/gAD3/3wCD/+gAkv/oAJf/6ACxABAAsv/oALMAEADR/+AA0v/oANMAEADV/+AA3AAQAOD/4QDxABAA+P/gAQMAEAEH/+gBDAAQARb/6AEY/+ABGv/oARz/6AEe/+gBIP/oATL/4AE4/+gBOv/gAVEAEAFV/+gCKP/oAin/6AIr/+gCLP/oAkwAEAJNABACTgAQAk8AEAJQABACUQAQAlIAEAJT/+gCXf/oAl7/6AJf/+gCYP/oAmH/6AJm/98CgwAQAoUAEAKHABACif/oAov/6AKN/+gCj//oAp3/6AKf/+gCof/oAqP/6ALF/+gCx//oAsn/6ALb/+AC3f/gAt//4ALv/98C8f/fAvr/6ANTABADV//oA1j/3wNbABADZP/oA2f/3wNq/98DgwAQA4r/6AON/+gDjv/gA6b/3wOvABADt//gA7r/6AO9/+gDv//fA8UAEAPHABAD2P/oA9r/6APc/+gD5v/hA+f/4APtABAD7gAQA+8AEAPxABAD8wAQA/UAEAP3ABAD+QAQA/sAEAP9ABAD/wAQBAEAEAQDABAEBQAQBBv/6AQd/+gEH//oBCH/6AQj/+gEJf/oBCf/6AQp/+gEK//oBC3/6AQv/+gEMf/oBEH/3wRD/98ERf/fBE3/4ARR/+EEUv/gBFP/4QRU/+AEaAAQBGkAEARq/98Eqv/oAC0AOP/xADr/9AA8//QAPf/wANH/8QDT//UA1f/xANn/9ADc//UA3f/zARj/9AEy//EBOv/xAVH/9QJm//AC2//xAt3/8QLf//EC7//wAvH/8ANY//ADZ//wA2j/9ANq//ADgv/zA47/8QOP//QDpv/wA7f/9AO///ADwv/0A9D/9APg//MD4v/zA+T/8wPq//QD7f/1BEH/8ARD//AERf/wBE3/8QRP//QEV//0BGj/9QRq//AAWQAlAA8AOP/mADr/5gA8AA4APf/mALEADwCzAA8A0f/mANMADgDV/+YA2QAOANwADgDdAAsA4P/lAPEADwD4/+gBAwAPAQwADwEY/+YBMv/mATr/5gFRAA4CTAAPAk0ADwJOAA8CTwAPAlAADwJRAA8CUgAPAmb/5gKDAA8ChQAPAocADwLb/+YC3f/mAt//5gLv/+YC8f/mA1MADwNY/+YDWwAPA2f/5gNoAA4Dav/mA4IACwODAA8Djv/mA48ADgOm/+YDrwAPA7f/5gO//+YDwgAOA8UADwPHAA8D0AAOA+AACwPiAAsD5AALA+b/5QPn/+gD6gAO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ABADogOiABADpAOkABADpgOmAA8DpwOnABkDqAOpAB0DrAOsAB0DrQOtAAIDrgOuABcDsAOwABMDsQOxAAUDswOzABYDtwO3AA0DuAO4ABkDvQO9AAQDvgO+ABQDvwO/AA8DwAPAABkDwQPBAAIDwgPCAA4DwwPDABsDxAPEAAIDxgPGABMDyAPIABMDywPLAAUDzAPMABYDzgPPABYD0APQAA4D0QPRABsD2APYAAMD2QPZABgD3QPdABgD3wPfABUD4APgABID4QPhABkD4gPiABID4wPjABkD5APkABID5QPlABkD6gPqAA4D6wPrABsD8APwABMD8gPyABMD9AP0ABMD9gP2ABMD+AP4ABMD+gP6ABMD/AP8ABMD/gP+ABMEAAQAABMEAgQCABMEBAQEABMEBgQGABMEBwQHAAUECAQIABYECQQJAAUECgQKABYECwQLAAUEDAQMABYEDQQNAAUEDgQOABYEDwQPAAUEEAQQABYEEQQRAAUEEgQSABYEEwQTAAUEFAQUABYEFQQVAAUEFgQWABYEFwQXAAIEGQQZAAIEGwQbAAMEHAQcABgEHQQdAAMEHgQeABgEHwQfAAMEIAQgABgEIQQhAAMEIgQiABgEIwQjAAMEJAQkABgEJQQlAAMEJgQmABgEJwQnAAMEKAQoABgEMAQwABgEMwQzAAwENQQ1AAwEQQRBAA8EQgRCABkEQwRDAA8ERAREABkERQRFAA8ERgRGABkESQRJAAkESwRLAAIETQRNAAYETwRPAA4EUARQABsEVQRVAAcEVgRWAAgEVwRXAA4EWARYABsEWwRbABcEXQRdAB8EXgReAAcEYARgAAkEZARkAAIEZgRmAAIEagRqAA8EqgSqAAMAAgFtAAYABgAHAAsACwAHABAAEAATABEAEQAXABIAEgATACUAJQARACcAJwAFACsAKwAFAC4ALgAcADMAMwAFADUANQAFADcANwAZADgAOAAKADkAOQAGADoAOgANADsAOwAJADwAPAASAD0APQAOAD4APgAUAEUARQAaAEcASQAVAEsASwAVAFEAUgAYAFMAUwAIAFQAVAAYAFUAVQAVAFcAVwAbAFkAWQALAFoAWgACAFwAXAAWAF0AXQACAF4AXgAMAIMAgwAFAJIAkgAFAJMAkwAVAJcAlwAFAJgAmAAVAJoAmgALALEAsQAR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b20EbGRub20EbGRub20EbGZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmZyYWMEcmxpZ2EEfGxpZ2EEhGxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxudW0EimxvY2wEkGxvY2wElmxvY2wEnG51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom51bXIEom9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqG9udW0EqHBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnBudW0ErnNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNtY3AEtHNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDEEunNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDIEwHNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDMExnNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDQEzHNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDUE0nNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDYE2HNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nNzMDcE3nRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5HRudW0E5AAAAAEAAAAAAAIAAgADAAAAAQAHAAAAAQAYAAAAAwAVABYAFwAAAAIACAAJAAAAAQAJAAAAAQAUAAAAAQAEAAAAAQAGAAAAAQAFAAAAAQAZAAAAAQARAAAAAQATAAAAAQABAAAAAQAKAAAAAQALAAAAAQAMAAAAAQANAAAAAQAOAAAAAQAPAAAAAQAQAAAAAQASABsAOAPGBrQHYA3wDfAOBg4oDl4OhA6yDsYO2g7uDwAPGg9cD3oPmA/KD/wQLhBCEHoQbBB6EKYAAQAAAAEACAACAcQA3wHnAboBuwG8Ab0BvgG/AcABwQHCAcMBxAHFAcYBxwHIAckBygHLAcwBzQHOAc8B0AHRAdIB0wHoAekCRAI7AeoB6wHsAe0B7gHvAfAB8QHyAfMB9AH1AfYB9wH4AfkB+gH7AfwB/QH+AgACAQTdAgICAwIEAgUCBgIHAggCCQIKAgsCLwIPAhACEQIUAhUCFgIXAhgCGQIbAhwCHgIdAvwC/QL+Av8DAAMBAwIDAwMEAwUDBgMHAwgDCQMKAwsDDAMNAw4DDwMQAxEDEgMTAxQDFQMWAxcDGAMZAxoDGwMcAx0DHgMfAyADIQMiAyMDJAMlAyYDJwMoAykDKgMrAywDLQMuAy8DMAMxAzIDMwM0AzUDNgM3AzgDOQM6AzsDPAM9Az4DPwNAA0EDQgNDA0QDRgNFA0cDSANJA0oDSwNMA00DTgNPA1ADUQNSBKsErAStBK4ErwSwBLEEsgSzBLQEtQS2BLcEuAS5BLoEuwS8BL0EvgS/BMAEwQTCBMMExATFBMYB/wTHBMgEyQTKBMsEzATNBM4EzwTQBNEE0gTTBNQE1QTWBNgE2QTbAhoE3AIOBNcCEwINBNoCDAISAAEA3wAIACUAJgAnACgAKQAqACsALAAtAC4ALwAwADEAMgAzADQANQA2ADcAOAA5ADoAOwA8AD0APgBlAGcAhQCSALAAsQCyALMAtAC1ALYAtwC4ALkA0QDSANMA1ADVANYA1wDYANkA2gDbANwA3QDeAN8A4ADhAOIA4wDkAOUA5gDnAOgBLAEwATIBOAE6ATwBPgE/AUUBRgF/AYUBigGNAkcCSAJKAkwCTQJOAk8CUAJRAlICUwJUAlUCVgJXAlgCWQJaAlsCXAJdAl4CXwJgAmECYgJjAmQCZQJmAoMChQKHAokCiwKNAo8CkQKTApUClwKZApsCnQKfAqECowKlAqcCqQKrAq0CrwKyArQCtgK4AroCvAK+AsACwgLFAscCyQLLAs0CzwLRAtMC1QLZAtsC3QLfAuEC4wLlAucC6QLrAu0C7wLxAvIC9AL2A1MDVANVA1YDVwNYA1kDWwNcA10DXgNfA2ADYQNiA2QDZQNmA2cDaANpA2oDegN7A3wDfQN+A38DgAOBA4IDgwOEA4UDhgOHA4gDiQOKA4sDjAONA44DjwO7A70DvwPUA9oD4ARJBEsETwRXBFkEXgRqAAEAAAABAAgAAgF0ALcBugG7AbwBvQG+Ab8BwAHBAcIBwwHEAcUBxgHHAcgByQHKAcsBzAHNAc4BzwHQAdEB0gHTAv0DMAI7AfoEygTLAfsB/AH9Af4B/wIABM4EzwTRBNQE3QICAgMCBAIFAgYCBwIIAgkCCgILAfQB9QH2AfcB+AH5Ai8CDwIQAhECFAIVAhcCGQL+Av8DAAMBAwIDAwMEAwUDBgMHAwgDCQMKAwsDDAMNAw4DDwMQAxEDEgMTAxQDFQMWAxcDGAMZA08DGgMbAxwDHQMeAx8DIAMhAyIDIwMkAyUDJgMnAygDKQMqAysDLAMtAy4DLwMxAzIDMwM0AzUDNgM3AzgDOQM6AzsDPAM9Az4DPwNAA0EDQgNDA0QDRgNFA0cDSANJA0oDSwNMA00DTgNQA1EDUgTJBMwEzQTQBNIE0wIBBNUEwQTCBMMExATFBMYExwTIBNYE2ATZAhgE2wIaBNwC/AIOBNcCEwINBNoCFgIMAhIAAQC3AEUARgBHAEgASQBKAEsATABNAE4ATwBQAFEAUgBTAFQAVQBWAFcAWABZAFoAWwBcAF0AXgCHAIwAkwDpAOoA6wDsAO0A7gDvAPAA8QDyAPMA9AD1APYA9wD4APkA+gD7APwA/QD+AP8BAAEBAQIBAwEEAQUBBgEtATEBMwE5ATsBPQFAAUcCSwJnAmgCaQJqAmsCbAJtAm4CbwJwAnECcgJzAnQCdQJ2AncCeAJ5AnoCewJ8An0CfgJ/AoACgQKCAoQChgKIAooCjAKOApACkgKUApYCmAKaApwCngKgAqICpAKmAqgCqgKsAq4CswK1ArcCuQK7Ar0CvwLBAsMCxgLIAsoCzALOAtAC0gLUAtYC2gLcAt4C4ALiAuQC5gLoAuoC7ALuAvAC8wL1AvcDkAORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwO8A74DwAPOA9UD2wPhBEcESgRMBFAEWARaBFsEXwRrAAYAAAAGABIAKgBCAFoAcgCKAAMAAAABABIAAQCQAAEAAAAaAAEAAQBNAAMAAAABABIAAQB4AAEAAAAaAAEAAQBOAAMAAAABABIAAQBgAAEAAAAaAAEAAQKuAAMAAAABABIAAQBIAAEAAAAaAAEAAQObAAMAAAABABIAAQAwAAEAAAAaAAEAAQOdAAMAAAABABIAAQAYAAEAAAAaAAEAAQQaAAIAAQCnAKsAAAAEAAAAAQAIAAEGHgA2AHIApACuALgAygD8AQ4BGAFKAWQBfgGQAboB7AH2AhgCMgJEAnYCiAKiAswC3gMQAxoDJAM2A2gDcgN8A4YDoAO6A8wD9gQoBDIEVARuBIAEsgTEBN4FCAUaBSQFLgU4BUIFbAWWBcAF6gYUAAYADgAUABoAIAAmACwCTAACAKcCTQACAKgCTwACAKkD8QACAKoEewACAKsD7wACAKwAAQAEBIgAAgCsAAEABAKJAAIAqAACAAYADASKAAIArASMAAIBogAGAA4AFAAaACAAJgAsAlQAAgCnAlUAAgCoBAsAAgCpBAkAAgCqBH0AAgCrBAcAAgCsAAIABgAMBHcAAgCoAqMAAgGiAAEABASOAAIArAAGAA4AFAAaACAAJgAsAlgAAgCnAlkAAgCoAqcAAgCpBBcAAgCqBH8AAgCrBBkAAgCsAAMACAAOABQEkAACAKgEkgACAKwCtAACAaIAAwAIAA4AFAK2AAIAqASUAAIArAK4AAIBogACAAYADAOtAAIAqASWAAIArAAFAAwAEgAYAB4AJAR5AAIApwK+AAIAqAJcAAIAqQSYAAIArALAAAIBogAGAA4AFAAaACAAJgAsAl0AAgCnAl4AAgCoAmAAAgCpBB0AAgCqBIEAAgCrBBsAAgCsAAEABASaAAIAqAAEAAoAEAAWABwCywACAKgEgwACAKsEnAACAKwCzQACAaIAAwAIAA4AFALRAAIAqASeAAIArALXAAIBogACAAYADASgAAIArALbAAIBogAGAA4AFAAaACAAJgAsAmIAAgCnAmMAAgCoAuEAAgCpBDUAAgCqBIUAAgCrBDMAAgCsAAIABgAMBKIAAgCpBKQAAgCsAAMACAAOABQDoAACAKcDogACAKgEpgACAKwABQAMABIAGAAeACQDpgACAKcCZgACAKgERQACAKkEQwACAKoEQQACAKwAAgAGAAwC8gACAKgEqAACAKwABgAOABQAGgAgACYALAJnAAIApwJoAAIAqAJqAAIAqQPyAAIAqgR8AAIAqwPwAAIArAABAAQEiQACAKwAAQAEAooAAgCoAAIABgAMBIsAAgCsBI0AAgGiAAYADgAUABoAIAAmACwCbwACAKcCcAACAKgEDAACAKkECgACAKoEfgACAKsECAACAKwAAQAEBHgAAgCoAAEABASPAAIArAABAAQEGgACAKwAAwAIAA4AFASRAAIAqASTAAIArAK1AAIBogADAAgADgAUArcAAgCoBJUAAgCsArkAAgGiAAIABgAMA64AAgCoBJcAAgCsAAUADAASABgAHgAkBHoAAgCnAr8AAgCoAncAAgCpBJkAAgCsAsEAAgGiAAYADgAUABoAIAAmACwCeAACAKcCeQACAKgCewACAKkEHgACAKoEggACAKsEHAACAKwAAQAEBJsAAgCoAAQACgAQABYAHALMAAIAqASEAAIAqwSdAAIArALOAAIBogADAAgADgAUAtIAAgCoBJ8AAgCsAtgAAgGiAAIABgAMBKEAAgCsAtwAAgGiAAYADgAUABoAIAAmACwCfQACAKcCfgACAKgC4gACAKkENgACAKoEhgACAKsENAACAKwAAgAGAAwEowACAKkEpQACAKwAAwAIAA4AFAOhAAIApwOjAAIAqASnAAIArAAFAAwAEgAYAB4AJAOnAAIApwKBAAIAqARGAAIAqQREAAIAqgRCAAIArAACAAYADALzAAIAqASpAAIArAABAAQC+AACAKgAAQAEAvoAAgCoAAEABAL5AAIAqAABAAQC+wACAKgABQAMABIAGAAeACQCcwACAKcCdAACAKgCqAACAKkEGAACAKoEgAACAKsABQAMABIAGAAeACQEKwACAKcEKQACAKgELwACAKkELQACAKoEMQACAKwABQAMABIAGAAeACQELAACAKcEKgACAKgEMAACAKkELgACAKoEMgACAKwABQAMABIAGAAeACQEOQACAKcENwACAKgEPQACAKkEOwACAKoEPwACAKwABQAMABIAGAAeACQEOgACAKcEOAACAKgEPgACAKkEPAACAKoEQAACAKwAAQAEBIcAAgCoAAIAEQAlACkAAAArAC0ABQAvADQACAA2ADsADgA9AD4AFABFAEkAFgBLAE0AGwBPAFQAHgBWAFsAJABdAF4AKgCBAIEALACDAIMALQCGAIYALgCJAIkALwCMAIwAMACXAJoAMQDPAM8ANQABAAAAAQAIAAEABgACAAEAAgLVAtYAAQAAAAEACAACAA4ABATeBN8E4AThAAEABAKHAogCmQKaAAQAAAABAAgAAQAmAAIACgAcAAIABgAMAaMAAgBKAagAAgBYAAEABAGpAAIAWAABAAIASgBXAAQAAAABAAgAAQBEAAIACgAUAAEABAGkAAIATQABAAQBpgACAE0ABAAAAAEACAABAB4AAgAKABQAAQAEAaUAAgBQAAEABAGnAAIAUAABAAIASgGjAAEAAAABAAgAAQAGAZUAAQABAEsAAQAAAAEACAABAAYBJwABAAEAugABAAAAAQAIAAEABgGsAAEAAQA2AAEAAAABAAgAAgAcAAIB4wHkAAEAAAABAAgAAgAKAAIB5QHmAAEAAgAvAE8AAQAAAAEACAACAB4ADAIoAioCKQIrAiwCHwIgAiECIgGuAiQCJQABAAwAJwAoACsAMwA1AEYARwBIAEsAUwBUAFUAAQAAAAEACAACAAwAAwImAicCJwABAAMASQBLAiIAAQAAAAEACAACAGYACAI9Ai0CLgIwAjECOQI6AjwAAQAAAAEACAACABYACAAbABUAFgAXABgAGQAdABQAAQAIAa0CIwRxBHIEcwR0BHUEdgABAAAAAQAIAAIAFgAIBHYCIwRxBHIEcwR0Aa0EdQABAAgAFAAVABYAFwAYABkAGwAdAAEAAAABAAgAAgAWAAgAFQAWABcAGAAZABsAHQAUAAEACAItAi4CMAIxAjkCOgI8Aj0AAQAAAAEACAABAAYBaQABAAEAEwAGAAAAAQAIAAMAAQASAAEAUgAAAAEAAAAaAAIAAgF8AXwAAAHUAd0AAQABAAAAAQAIAAEAKAHAAAEAAAABAAgAAgAaAAoCMgB6AHMAdAIzAjQCNQI2AjcCOAACAAEAFAAdAAAAAQAAAAEACAACACYAEAHUAdUB1gHXAdgB2QHaAdsB3AHdAkACPgJBAkICPwJDAAEAEAAUABUAFgAXABgAGQAaABsAHAAdAE0ATgKuA5sDnQQa\"\n};"
  },
  {
    "path": "static/js/Echarts/echarts-en.common.js",
    "content": "(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n\ttypeof define === 'function' && define.amd ? define(['exports'], factory) :\n\t(factory((global.echarts = {})));\n}(this, (function (exports) { 'use strict';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (1) The code `if (__DEV__) ...` can be removed by build tool.\n// (2) If intend to use `__DEV__`, this module should be imported. Use a global\n// variable `__DEV__` may cause that miss the declaration (see #6535), or the\n// declaration is behind of the using position (for example in `Model.extent`,\n// And tools like rollup can not analysis the dependency if not import).\n\nvar dev;\n\n// In browser\nif (typeof window !== 'undefined') {\n    dev = window.__DEV__;\n}\n// In node\nelse if (typeof global !== 'undefined') {\n    dev = global.__DEV__;\n}\n\nif (typeof dev === 'undefined') {\n    dev = true;\n}\n\nvar __DEV__ = dev;\n\n/**\n * zrender: 生成唯一id\n *\n * @author errorrik (errorrik@gmail.com)\n */\n\nvar idStart = 0x0907;\n\nvar guid = function () {\n    return idStart++;\n};\n\n/**\n * echarts设备环境识别\n *\n * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。\n * @author firede[firede@firede.us]\n * @desc thanks zepto.\n */\n\nvar env = {};\n\nif (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') {\n    // In Weixin Application\n    env = {\n        browser: {},\n        os: {},\n        node: false,\n        wxa: true, // Weixin Application\n        canvasSupported: true,\n        svgSupported: false,\n        touchEventsSupported: true,\n        domSupported: false\n    };\n}\nelse if (typeof document === 'undefined' && typeof self !== 'undefined') {\n    // In worker\n    env = {\n        browser: {},\n        os: {},\n        node: false,\n        worker: true,\n        canvasSupported: true,\n        domSupported: false\n    };\n}\nelse if (typeof navigator === 'undefined') {\n    // In node\n    env = {\n        browser: {},\n        os: {},\n        node: true,\n        worker: false,\n        // Assume canvas is supported\n        canvasSupported: true,\n        svgSupported: true,\n        domSupported: false\n    };\n}\nelse {\n    env = detect(navigator.userAgent);\n}\n\nvar env$1 = env;\n\n// Zepto.js\n// (c) 2010-2013 Thomas Fuchs\n// Zepto.js may be freely distributed under the MIT license.\n\nfunction detect(ua) {\n    var os = {};\n    var browser = {};\n    // var webkit = ua.match(/Web[kK]it[\\/]{0,1}([\\d.]+)/);\n    // var android = ua.match(/(Android);?[\\s\\/]+([\\d.]+)?/);\n    // var ipad = ua.match(/(iPad).*OS\\s([\\d_]+)/);\n    // var ipod = ua.match(/(iPod)(.*OS\\s([\\d_]+))?/);\n    // var iphone = !ipad && ua.match(/(iPhone\\sOS)\\s([\\d_]+)/);\n    // var webos = ua.match(/(webOS|hpwOS)[\\s\\/]([\\d.]+)/);\n    // var touchpad = webos && ua.match(/TouchPad/);\n    // var kindle = ua.match(/Kindle\\/([\\d.]+)/);\n    // var silk = ua.match(/Silk\\/([\\d._]+)/);\n    // var blackberry = ua.match(/(BlackBerry).*Version\\/([\\d.]+)/);\n    // var bb10 = ua.match(/(BB10).*Version\\/([\\d.]+)/);\n    // var rimtabletos = ua.match(/(RIM\\sTablet\\sOS)\\s([\\d.]+)/);\n    // var playbook = ua.match(/PlayBook/);\n    // var chrome = ua.match(/Chrome\\/([\\d.]+)/) || ua.match(/CriOS\\/([\\d.]+)/);\n    var firefox = ua.match(/Firefox\\/([\\d.]+)/);\n    // var safari = webkit && ua.match(/Mobile\\//) && !chrome;\n    // var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome;\n    var ie = ua.match(/MSIE\\s([\\d.]+)/)\n        // IE 11 Trident/7.0; rv:11.0\n        || ua.match(/Trident\\/.+?rv:(([\\d.]+))/);\n    var edge = ua.match(/Edge\\/([\\d.]+)/); // IE 12 and 12+\n\n    var weChat = (/micromessenger/i).test(ua);\n\n    // Todo: clean this up with a better OS/browser seperation:\n    // - discern (more) between multiple browsers on android\n    // - decide if kindle fire in silk mode is android or not\n    // - Firefox on Android doesn't specify the Android version\n    // - possibly devide in os, device and browser hashes\n\n    // if (browser.webkit = !!webkit) browser.version = webkit[1];\n\n    // if (android) os.android = true, os.version = android[2];\n    // if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.');\n    // if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.');\n    // if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null;\n    // if (webos) os.webos = true, os.version = webos[2];\n    // if (touchpad) os.touchpad = true;\n    // if (blackberry) os.blackberry = true, os.version = blackberry[2];\n    // if (bb10) os.bb10 = true, os.version = bb10[2];\n    // if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2];\n    // if (playbook) browser.playbook = true;\n    // if (kindle) os.kindle = true, os.version = kindle[1];\n    // if (silk) browser.silk = true, browser.version = silk[1];\n    // if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true;\n    // if (chrome) browser.chrome = true, browser.version = chrome[1];\n    if (firefox) {\n        browser.firefox = true;\n        browser.version = firefox[1];\n    }\n    // if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true;\n    // if (webview) browser.webview = true;\n\n    if (ie) {\n        browser.ie = true;\n        browser.version = ie[1];\n    }\n\n    if (edge) {\n        browser.edge = true;\n        browser.version = edge[1];\n    }\n\n    // It is difficult to detect WeChat in Win Phone precisely, because ua can\n    // not be set on win phone. So we do not consider Win Phone.\n    if (weChat) {\n        browser.weChat = true;\n    }\n\n    // os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) ||\n    //     (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/)));\n    // os.phone  = !!(!os.tablet && !os.ipod && (android || iphone || webos ||\n    //     (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\\/([\\d.]+)/)) ||\n    //     (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/))));\n\n    return {\n        browser: browser,\n        os: os,\n        node: false,\n        // 原生canvas支持，改极端点了\n        // canvasSupported : !(browser.ie && parseFloat(browser.version) < 9)\n        canvasSupported: !!document.createElement('canvas').getContext,\n        svgSupported: typeof SVGRect !== 'undefined',\n        // works on most browsers\n        // IE10/11 does not support touch event, and MS Edge supports them but not by\n        // default, so we dont check navigator.maxTouchPoints for them here.\n        touchEventsSupported: 'ontouchstart' in window && !browser.ie && !browser.edge,\n        // <http://caniuse.com/#search=pointer%20event>.\n        pointerEventsSupported: 'onpointerdown' in window\n            // Firefox supports pointer but not by default, only MS browsers are reliable on pointer\n            // events currently. So we dont use that on other browsers unless tested sufficiently.\n            // Although IE 10 supports pointer event, it use old style and is different from the\n            // standard. So we exclude that. (IE 10 is hardly used on touch device)\n            && (browser.edge || (browser.ie && browser.version >= 11)),\n        // passiveSupported: detectPassiveSupport()\n        domSupported: typeof document !== 'undefined'\n    };\n}\n\n// See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection\n// function detectPassiveSupport() {\n//     // Test via a getter in the options object to see if the passive property is accessed\n//     var supportsPassive = false;\n//     try {\n//         var opts = Object.defineProperty({}, 'passive', {\n//             get: function() {\n//                 supportsPassive = true;\n//             }\n//         });\n//         window.addEventListener('testPassive', function() {}, opts);\n//     } catch (e) {\n//     }\n//     return supportsPassive;\n// }\n\n/**\n * @module zrender/core/util\n */\n\n// 用于处理merge时无法遍历Date等对象的问题\nvar BUILTIN_OBJECT = {\n    '[object Function]': 1,\n    '[object RegExp]': 1,\n    '[object Date]': 1,\n    '[object Error]': 1,\n    '[object CanvasGradient]': 1,\n    '[object CanvasPattern]': 1,\n    // For node-canvas\n    '[object Image]': 1,\n    '[object Canvas]': 1\n};\n\nvar TYPED_ARRAY = {\n    '[object Int8Array]': 1,\n    '[object Uint8Array]': 1,\n    '[object Uint8ClampedArray]': 1,\n    '[object Int16Array]': 1,\n    '[object Uint16Array]': 1,\n    '[object Int32Array]': 1,\n    '[object Uint32Array]': 1,\n    '[object Float32Array]': 1,\n    '[object Float64Array]': 1\n};\n\nvar objToString = Object.prototype.toString;\n\nvar arrayProto = Array.prototype;\nvar nativeForEach = arrayProto.forEach;\nvar nativeFilter = arrayProto.filter;\nvar nativeSlice = arrayProto.slice;\nvar nativeMap = arrayProto.map;\nvar nativeReduce = arrayProto.reduce;\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar methods = {};\n\nfunction $override(name, fn) {\n    // Clear ctx instance for different environment\n    if (name === 'createCanvas') {\n        _ctx = null;\n    }\n\n    methods[name] = fn;\n}\n\n/**\n * Those data types can be cloned:\n *     Plain object, Array, TypedArray, number, string, null, undefined.\n * Those data types will be assgined using the orginal data:\n *     BUILTIN_OBJECT\n * Instance of user defined class will be cloned to a plain object, without\n * properties in prototype.\n * Other data types is not supported (not sure what will happen).\n *\n * Caution: do not support clone Date, for performance consideration.\n * (There might be a large number of date in `series.data`).\n * So date should not be modified in and out of echarts.\n *\n * @param {*} source\n * @return {*} new\n */\nfunction clone(source) {\n    if (source == null || typeof source !== 'object') {\n        return source;\n    }\n\n    var result = source;\n    var typeStr = objToString.call(source);\n\n    if (typeStr === '[object Array]') {\n        if (!isPrimitive(source)) {\n            result = [];\n            for (var i = 0, len = source.length; i < len; i++) {\n                result[i] = clone(source[i]);\n            }\n        }\n    }\n    else if (TYPED_ARRAY[typeStr]) {\n        if (!isPrimitive(source)) {\n            var Ctor = source.constructor;\n            if (source.constructor.from) {\n                result = Ctor.from(source);\n            }\n            else {\n                result = new Ctor(source.length);\n                for (var i = 0, len = source.length; i < len; i++) {\n                    result[i] = clone(source[i]);\n                }\n            }\n        }\n    }\n    else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) {\n        result = {};\n        for (var key in source) {\n            if (source.hasOwnProperty(key)) {\n                result[key] = clone(source[key]);\n            }\n        }\n    }\n\n    return result;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overwrite=false]\n */\nfunction merge(target, source, overwrite) {\n    // We should escapse that source is string\n    // and enter for ... in ...\n    if (!isObject$1(source) || !isObject$1(target)) {\n        return overwrite ? clone(source) : target;\n    }\n\n    for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n            var targetProp = target[key];\n            var sourceProp = source[key];\n\n            if (isObject$1(sourceProp)\n                && isObject$1(targetProp)\n                && !isArray(sourceProp)\n                && !isArray(targetProp)\n                && !isDom(sourceProp)\n                && !isDom(targetProp)\n                && !isBuiltInObject(sourceProp)\n                && !isBuiltInObject(targetProp)\n                && !isPrimitive(sourceProp)\n                && !isPrimitive(targetProp)\n            ) {\n                // 如果需要递归覆盖，就递归调用merge\n                merge(targetProp, sourceProp, overwrite);\n            }\n            else if (overwrite || !(key in target)) {\n                // 否则只处理overwrite为true，或者在目标对象中没有此属性的情况\n                // NOTE，在 target[key] 不存在的时候也是直接覆盖\n                target[key] = clone(source[key], true);\n            }\n        }\n    }\n\n    return target;\n}\n\n/**\n * @param {Array} targetAndSources The first item is target, and the rests are source.\n * @param {boolean} [overwrite=false]\n * @return {*} target\n */\nfunction mergeAll(targetAndSources, overwrite) {\n    var result = targetAndSources[0];\n    for (var i = 1, len = targetAndSources.length; i < len; i++) {\n        result = merge(result, targetAndSources[i], overwrite);\n    }\n    return result;\n}\n\n/**\n * @param {*} target\n * @param {*} source\n * @memberOf module:zrender/core/util\n */\nfunction extend(target, source) {\n    for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n            target[key] = source[key];\n        }\n    }\n    return target;\n}\n\n/**\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overlay=false]\n * @memberOf module:zrender/core/util\n */\nfunction defaults(target, source, overlay) {\n    for (var key in source) {\n        if (source.hasOwnProperty(key)\n            && (overlay ? source[key] != null : target[key] == null)\n        ) {\n            target[key] = source[key];\n        }\n    }\n    return target;\n}\n\nvar createCanvas = function () {\n    return methods.createCanvas();\n};\n\nmethods.createCanvas = function () {\n    return document.createElement('canvas');\n};\n\n// FIXME\nvar _ctx;\n\nfunction getContext() {\n    if (!_ctx) {\n        // Use util.createCanvas instead of createCanvas\n        // because createCanvas may be overwritten in different environment\n        _ctx = createCanvas().getContext('2d');\n    }\n    return _ctx;\n}\n\n/**\n * 查询数组中元素的index\n * @memberOf module:zrender/core/util\n */\nfunction indexOf(array, value) {\n    if (array) {\n        if (array.indexOf) {\n            return array.indexOf(value);\n        }\n        for (var i = 0, len = array.length; i < len; i++) {\n            if (array[i] === value) {\n                return i;\n            }\n        }\n    }\n    return -1;\n}\n\n/**\n * 构造类继承关系\n *\n * @memberOf module:zrender/core/util\n * @param {Function} clazz 源类\n * @param {Function} baseClazz 基类\n */\nfunction inherits(clazz, baseClazz) {\n    var clazzPrototype = clazz.prototype;\n    function F() {}\n    F.prototype = baseClazz.prototype;\n    clazz.prototype = new F();\n\n    for (var prop in clazzPrototype) {\n        clazz.prototype[prop] = clazzPrototype[prop];\n    }\n    clazz.prototype.constructor = clazz;\n    clazz.superClass = baseClazz;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Object|Function} target\n * @param {Object|Function} sorce\n * @param {boolean} overlay\n */\nfunction mixin(target, source, overlay) {\n    target = 'prototype' in target ? target.prototype : target;\n    source = 'prototype' in source ? source.prototype : source;\n\n    defaults(target, source, overlay);\n}\n\n/**\n * Consider typed array.\n * @param {Array|TypedArray} data\n */\nfunction isArrayLike(data) {\n    if (!data) {\n        return;\n    }\n    if (typeof data === 'string') {\n        return false;\n    }\n    return typeof data.length === 'number';\n}\n\n/**\n * 数组或对象遍历\n * @memberOf module:zrender/core/util\n * @param {Object|Array} obj\n * @param {Function} cb\n * @param {*} [context]\n */\nfunction each$1(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.forEach && obj.forEach === nativeForEach) {\n        obj.forEach(cb, context);\n    }\n    else if (obj.length === +obj.length) {\n        for (var i = 0, len = obj.length; i < len; i++) {\n            cb.call(context, obj[i], i, obj);\n        }\n    }\n    else {\n        for (var key in obj) {\n            if (obj.hasOwnProperty(key)) {\n                cb.call(context, obj[key], key, obj);\n            }\n        }\n    }\n}\n\n/**\n * 数组映射\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction map(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.map && obj.map === nativeMap) {\n        return obj.map(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            result.push(cb.call(context, obj[i], i, obj));\n        }\n        return result;\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {Object} [memo]\n * @param {*} [context]\n * @return {Array}\n */\nfunction reduce(obj, cb, memo, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.reduce && obj.reduce === nativeReduce) {\n        return obj.reduce(cb, memo, context);\n    }\n    else {\n        for (var i = 0, len = obj.length; i < len; i++) {\n            memo = cb.call(context, memo, obj[i], i, obj);\n        }\n        return memo;\n    }\n}\n\n/**\n * 数组过滤\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction filter(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.filter && obj.filter === nativeFilter) {\n        return obj.filter(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            if (cb.call(context, obj[i], i, obj)) {\n                result.push(obj[i]);\n            }\n        }\n        return result;\n    }\n}\n\n/**\n * 数组项查找\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {*}\n */\nfunction find(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    for (var i = 0, len = obj.length; i < len; i++) {\n        if (cb.call(context, obj[i], i, obj)) {\n            return obj[i];\n        }\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @param {*} context\n * @return {Function}\n */\nfunction bind(func, context) {\n    var args = nativeSlice.call(arguments, 2);\n    return function () {\n        return func.apply(context, args.concat(nativeSlice.call(arguments)));\n    };\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @return {Function}\n */\nfunction curry(func) {\n    var args = nativeSlice.call(arguments, 1);\n    return function () {\n        return func.apply(this, args.concat(nativeSlice.call(arguments)));\n    };\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isArray(value) {\n    return objToString.call(value) === '[object Array]';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isFunction$1(value) {\n    return typeof value === 'function';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isString(value) {\n    return objToString.call(value) === '[object String]';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isObject$1(value) {\n    // Avoid a V8 JIT bug in Chrome 19-20.\n    // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.\n    var type = typeof value;\n    return type === 'function' || (!!value && type === 'object');\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isBuiltInObject(value) {\n    return !!BUILTIN_OBJECT[objToString.call(value)];\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isTypedArray(value) {\n    return !!TYPED_ARRAY[objToString.call(value)];\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isDom(value) {\n    return typeof value === 'object'\n        && typeof value.nodeType === 'number'\n        && typeof value.ownerDocument === 'object';\n}\n\n/**\n * Whether is exactly NaN. Notice isNaN('a') returns true.\n * @param {*} value\n * @return {boolean}\n */\nfunction eqNaN(value) {\n    return value !== value;\n}\n\n/**\n * If value1 is not null, then return value1, otherwise judget rest of values.\n * Low performance.\n * @memberOf module:zrender/core/util\n * @return {*} Final value\n */\nfunction retrieve(values) {\n    for (var i = 0, len = arguments.length; i < len; i++) {\n        if (arguments[i] != null) {\n            return arguments[i];\n        }\n    }\n}\n\nfunction retrieve2(value0, value1) {\n    return value0 != null\n        ? value0\n        : value1;\n}\n\nfunction retrieve3(value0, value1, value2) {\n    return value0 != null\n        ? value0\n        : value1 != null\n        ? value1\n        : value2;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} arr\n * @param {number} startIndex\n * @param {number} endIndex\n * @return {Array}\n */\nfunction slice() {\n    return Function.call.apply(nativeSlice, arguments);\n}\n\n/**\n * Normalize css liked array configuration\n * e.g.\n *  3 => [3, 3, 3, 3]\n *  [4, 2] => [4, 2, 4, 2]\n *  [4, 3, 2] => [4, 3, 2, 3]\n * @param {number|Array.<number>} val\n * @return {Array.<number>}\n */\nfunction normalizeCssArray(val) {\n    if (typeof (val) === 'number') {\n        return [val, val, val, val];\n    }\n    var len = val.length;\n    if (len === 2) {\n        // vertical | horizontal\n        return [val[0], val[1], val[0], val[1]];\n    }\n    else if (len === 3) {\n        // top | horizontal | bottom\n        return [val[0], val[1], val[2], val[1]];\n    }\n    return val;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {boolean} condition\n * @param {string} message\n */\nfunction assert$1(condition, message) {\n    if (!condition) {\n        throw new Error(message);\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {string} str string to be trimed\n * @return {string} trimed string\n */\nfunction trim(str) {\n    if (str == null) {\n        return null;\n    }\n    else if (typeof str.trim === 'function') {\n        return str.trim();\n    }\n    else {\n        return str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n    }\n}\n\nvar primitiveKey = '__ec_primitive__';\n/**\n * Set an object as primitive to be ignored traversing children in clone or merge\n */\nfunction setAsPrimitive(obj) {\n    obj[primitiveKey] = true;\n}\n\nfunction isPrimitive(obj) {\n    return obj[primitiveKey];\n}\n\n/**\n * @constructor\n * @param {Object} obj Only apply `ownProperty`.\n */\nfunction HashMap(obj) {\n    var isArr = isArray(obj);\n    // Key should not be set on this, otherwise\n    // methods get/set/... may be overrided.\n    this.data = {};\n    var thisMap = this;\n\n    (obj instanceof HashMap)\n        ? obj.each(visit)\n        : (obj && each$1(obj, visit));\n\n    function visit(value, key) {\n        isArr ? thisMap.set(value, key) : thisMap.set(key, value);\n    }\n}\n\nHashMap.prototype = {\n    constructor: HashMap,\n    // Do not provide `has` method to avoid defining what is `has`.\n    // (We usually treat `null` and `undefined` as the same, different\n    // from ES6 Map).\n    get: function (key) {\n        return this.data.hasOwnProperty(key) ? this.data[key] : null;\n    },\n    set: function (key, value) {\n        // Comparing with invocation chaining, `return value` is more commonly\n        // used in this case: `var someVal = map.set('a', genVal());`\n        return (this.data[key] = value);\n    },\n    // Although util.each can be performed on this hashMap directly, user\n    // should not use the exposed keys, who are prefixed.\n    each: function (cb, context) {\n        context !== void 0 && (cb = bind(cb, context));\n        for (var key in this.data) {\n            this.data.hasOwnProperty(key) && cb(this.data[key], key);\n        }\n    },\n    // Do not use this method if performance sensitive.\n    removeKey: function (key) {\n        delete this.data[key];\n    }\n};\n\nfunction createHashMap(obj) {\n    return new HashMap(obj);\n}\n\nfunction concatArray(a, b) {\n    var newArray = new a.constructor(a.length + b.length);\n    for (var i = 0; i < a.length; i++) {\n        newArray[i] = a[i];\n    }\n    var offset = a.length;\n    for (i = 0; i < b.length; i++) {\n        newArray[i + offset] = b[i];\n    }\n    return newArray;\n}\n\n\nfunction noop() {}\n\n\nvar zrUtil = (Object.freeze || Object)({\n\t$override: $override,\n\tclone: clone,\n\tmerge: merge,\n\tmergeAll: mergeAll,\n\textend: extend,\n\tdefaults: defaults,\n\tcreateCanvas: createCanvas,\n\tgetContext: getContext,\n\tindexOf: indexOf,\n\tinherits: inherits,\n\tmixin: mixin,\n\tisArrayLike: isArrayLike,\n\teach: each$1,\n\tmap: map,\n\treduce: reduce,\n\tfilter: filter,\n\tfind: find,\n\tbind: bind,\n\tcurry: curry,\n\tisArray: isArray,\n\tisFunction: isFunction$1,\n\tisString: isString,\n\tisObject: isObject$1,\n\tisBuiltInObject: isBuiltInObject,\n\tisTypedArray: isTypedArray,\n\tisDom: isDom,\n\teqNaN: eqNaN,\n\tretrieve: retrieve,\n\tretrieve2: retrieve2,\n\tretrieve3: retrieve3,\n\tslice: slice,\n\tnormalizeCssArray: normalizeCssArray,\n\tassert: assert$1,\n\ttrim: trim,\n\tsetAsPrimitive: setAsPrimitive,\n\tisPrimitive: isPrimitive,\n\tcreateHashMap: createHashMap,\n\tconcatArray: concatArray,\n\tnoop: noop\n});\n\nvar ArrayCtor = typeof Float32Array === 'undefined'\n    ? Array\n    : Float32Array;\n\n/**\n * 创建一个向量\n * @param {number} [x=0]\n * @param {number} [y=0]\n * @return {Vector2}\n */\nfunction create(x, y) {\n    var out = new ArrayCtor(2);\n    if (x == null) {\n        x = 0;\n    }\n    if (y == null) {\n        y = 0;\n    }\n    out[0] = x;\n    out[1] = y;\n    return out;\n}\n\n/**\n * 复制向量数据\n * @param {Vector2} out\n * @param {Vector2} v\n * @return {Vector2}\n */\nfunction copy(out, v) {\n    out[0] = v[0];\n    out[1] = v[1];\n    return out;\n}\n\n/**\n * 克隆一个向量\n * @param {Vector2} v\n * @return {Vector2}\n */\nfunction clone$1(v) {\n    var out = new ArrayCtor(2);\n    out[0] = v[0];\n    out[1] = v[1];\n    return out;\n}\n\n/**\n * 设置向量的两个项\n * @param {Vector2} out\n * @param {number} a\n * @param {number} b\n * @return {Vector2} 结果\n */\nfunction set(out, a, b) {\n    out[0] = a;\n    out[1] = b;\n    return out;\n}\n\n/**\n * 向量相加\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction add(out, v1, v2) {\n    out[0] = v1[0] + v2[0];\n    out[1] = v1[1] + v2[1];\n    return out;\n}\n\n/**\n * 向量缩放后相加\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @param {number} a\n */\nfunction scaleAndAdd(out, v1, v2, a) {\n    out[0] = v1[0] + v2[0] * a;\n    out[1] = v1[1] + v2[1] * a;\n    return out;\n}\n\n/**\n * 向量相减\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction sub(out, v1, v2) {\n    out[0] = v1[0] - v2[0];\n    out[1] = v1[1] - v2[1];\n    return out;\n}\n\n/**\n * 向量长度\n * @param {Vector2} v\n * @return {number}\n */\nfunction len(v) {\n    return Math.sqrt(lenSquare(v));\n}\nvar length = len; // jshint ignore:line\n\n/**\n * 向量长度平方\n * @param {Vector2} v\n * @return {number}\n */\nfunction lenSquare(v) {\n    return v[0] * v[0] + v[1] * v[1];\n}\nvar lengthSquare = lenSquare;\n\n/**\n * 向量乘法\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction mul(out, v1, v2) {\n    out[0] = v1[0] * v2[0];\n    out[1] = v1[1] * v2[1];\n    return out;\n}\n\n/**\n * 向量除法\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction div(out, v1, v2) {\n    out[0] = v1[0] / v2[0];\n    out[1] = v1[1] / v2[1];\n    return out;\n}\n\n/**\n * 向量点乘\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction dot(v1, v2) {\n    return v1[0] * v2[0] + v1[1] * v2[1];\n}\n\n/**\n * 向量缩放\n * @param {Vector2} out\n * @param {Vector2} v\n * @param {number} s\n */\nfunction scale(out, v, s) {\n    out[0] = v[0] * s;\n    out[1] = v[1] * s;\n    return out;\n}\n\n/**\n * 向量归一化\n * @param {Vector2} out\n * @param {Vector2} v\n */\nfunction normalize(out, v) {\n    var d = len(v);\n    if (d === 0) {\n        out[0] = 0;\n        out[1] = 0;\n    }\n    else {\n        out[0] = v[0] / d;\n        out[1] = v[1] / d;\n    }\n    return out;\n}\n\n/**\n * 计算向量间距离\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction distance(v1, v2) {\n    return Math.sqrt(\n        (v1[0] - v2[0]) * (v1[0] - v2[0])\n        + (v1[1] - v2[1]) * (v1[1] - v2[1])\n    );\n}\nvar dist = distance;\n\n/**\n * 向量距离平方\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction distanceSquare(v1, v2) {\n    return (v1[0] - v2[0]) * (v1[0] - v2[0])\n        + (v1[1] - v2[1]) * (v1[1] - v2[1]);\n}\nvar distSquare = distanceSquare;\n\n/**\n * 求负向量\n * @param {Vector2} out\n * @param {Vector2} v\n */\nfunction negate(out, v) {\n    out[0] = -v[0];\n    out[1] = -v[1];\n    return out;\n}\n\n/**\n * 插值两个点\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @param {number} t\n */\nfunction lerp(out, v1, v2, t) {\n    out[0] = v1[0] + t * (v2[0] - v1[0]);\n    out[1] = v1[1] + t * (v2[1] - v1[1]);\n    return out;\n}\n\n/**\n * 矩阵左乘向量\n * @param {Vector2} out\n * @param {Vector2} v\n * @param {Vector2} m\n */\nfunction applyTransform(out, v, m) {\n    var x = v[0];\n    var y = v[1];\n    out[0] = m[0] * x + m[2] * y + m[4];\n    out[1] = m[1] * x + m[3] * y + m[5];\n    return out;\n}\n\n/**\n * 求两个向量最小值\n * @param  {Vector2} out\n * @param  {Vector2} v1\n * @param  {Vector2} v2\n */\nfunction min(out, v1, v2) {\n    out[0] = Math.min(v1[0], v2[0]);\n    out[1] = Math.min(v1[1], v2[1]);\n    return out;\n}\n\n/**\n * 求两个向量最大值\n * @param  {Vector2} out\n * @param  {Vector2} v1\n * @param  {Vector2} v2\n */\nfunction max(out, v1, v2) {\n    out[0] = Math.max(v1[0], v2[0]);\n    out[1] = Math.max(v1[1], v2[1]);\n    return out;\n}\n\n\nvar vector = (Object.freeze || Object)({\n\tcreate: create,\n\tcopy: copy,\n\tclone: clone$1,\n\tset: set,\n\tadd: add,\n\tscaleAndAdd: scaleAndAdd,\n\tsub: sub,\n\tlen: len,\n\tlength: length,\n\tlenSquare: lenSquare,\n\tlengthSquare: lengthSquare,\n\tmul: mul,\n\tdiv: div,\n\tdot: dot,\n\tscale: scale,\n\tnormalize: normalize,\n\tdistance: distance,\n\tdist: dist,\n\tdistanceSquare: distanceSquare,\n\tdistSquare: distSquare,\n\tnegate: negate,\n\tlerp: lerp,\n\tapplyTransform: applyTransform,\n\tmin: min,\n\tmax: max\n});\n\n// TODO Draggable for group\n// FIXME Draggable on element which has parent rotation or scale\nfunction Draggable() {\n\n    this.on('mousedown', this._dragStart, this);\n    this.on('mousemove', this._drag, this);\n    this.on('mouseup', this._dragEnd, this);\n    this.on('globalout', this._dragEnd, this);\n    // this._dropTarget = null;\n    // this._draggingTarget = null;\n\n    // this._x = 0;\n    // this._y = 0;\n}\n\nDraggable.prototype = {\n\n    constructor: Draggable,\n\n    _dragStart: function (e) {\n        var draggingTarget = e.target;\n        if (draggingTarget && draggingTarget.draggable) {\n            this._draggingTarget = draggingTarget;\n            draggingTarget.dragging = true;\n            this._x = e.offsetX;\n            this._y = e.offsetY;\n\n            this.dispatchToElement(param(draggingTarget, e), 'dragstart', e.event);\n        }\n    },\n\n    _drag: function (e) {\n        var draggingTarget = this._draggingTarget;\n        if (draggingTarget) {\n\n            var x = e.offsetX;\n            var y = e.offsetY;\n\n            var dx = x - this._x;\n            var dy = y - this._y;\n            this._x = x;\n            this._y = y;\n\n            draggingTarget.drift(dx, dy, e);\n            this.dispatchToElement(param(draggingTarget, e), 'drag', e.event);\n\n            var dropTarget = this.findHover(x, y, draggingTarget).target;\n            var lastDropTarget = this._dropTarget;\n            this._dropTarget = dropTarget;\n\n            if (draggingTarget !== dropTarget) {\n                if (lastDropTarget && dropTarget !== lastDropTarget) {\n                    this.dispatchToElement(param(lastDropTarget, e), 'dragleave', e.event);\n                }\n                if (dropTarget && dropTarget !== lastDropTarget) {\n                    this.dispatchToElement(param(dropTarget, e), 'dragenter', e.event);\n                }\n            }\n        }\n    },\n\n    _dragEnd: function (e) {\n        var draggingTarget = this._draggingTarget;\n\n        if (draggingTarget) {\n            draggingTarget.dragging = false;\n        }\n\n        this.dispatchToElement(param(draggingTarget, e), 'dragend', e.event);\n\n        if (this._dropTarget) {\n            this.dispatchToElement(param(this._dropTarget, e), 'drop', e.event);\n        }\n\n        this._draggingTarget = null;\n        this._dropTarget = null;\n    }\n\n};\n\nfunction param(target, e) {\n    return {target: target, topTarget: e && e.topTarget};\n}\n\n/**\n * Event Mixin\n * @module zrender/mixin/Eventful\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         pissang (https://www.github.com/pissang)\n */\n\nvar arrySlice = Array.prototype.slice;\n\n/**\n * Event dispatcher.\n *\n * @alias module:zrender/mixin/Eventful\n * @constructor\n * @param {Object} [eventProcessor] The object eventProcessor is the scope when\n *        `eventProcessor.xxx` called.\n * @param {Function} [eventProcessor.normalizeQuery]\n *        param: {string|Object} Raw query.\n *        return: {string|Object} Normalized query.\n * @param {Function} [eventProcessor.filter] Event will be dispatched only\n *        if it returns `true`.\n *        param: {string} eventType\n *        param: {string|Object} query\n *        return: {boolean}\n * @param {Function} [eventProcessor.afterTrigger] Call after all handlers called.\n *        param: {string} eventType\n */\nvar Eventful = function (eventProcessor) {\n    this._$handlers = {};\n    this._$eventProcessor = eventProcessor;\n};\n\nEventful.prototype = {\n\n    constructor: Eventful,\n\n    /**\n     * The handler can only be triggered once, then removed.\n     *\n     * @param {string} event The event name.\n     * @param {string|Object} [query] Condition used on event filter.\n     * @param {Function} handler The event handler.\n     * @param {Object} context\n     */\n    one: function (event, query, handler, context) {\n        return on(this, event, query, handler, context, true);\n    },\n\n    /**\n     * Bind a handler.\n     *\n     * @param {string} event The event name.\n     * @param {string|Object} [query] Condition used on event filter.\n     * @param {Function} handler The event handler.\n     * @param {Object} [context]\n     */\n    on: function (event, query, handler, context) {\n        return on(this, event, query, handler, context, false);\n    },\n\n    /**\n     * Whether any handler has bound.\n     *\n     * @param  {string}  event\n     * @return {boolean}\n     */\n    isSilent: function (event) {\n        var _h = this._$handlers;\n        return !_h[event] || !_h[event].length;\n    },\n\n    /**\n     * Unbind a event.\n     *\n     * @param {string} event The event name.\n     * @param {Function} [handler] The event handler.\n     */\n    off: function (event, handler) {\n        var _h = this._$handlers;\n\n        if (!event) {\n            this._$handlers = {};\n            return this;\n        }\n\n        if (handler) {\n            if (_h[event]) {\n                var newList = [];\n                for (var i = 0, l = _h[event].length; i < l; i++) {\n                    if (_h[event][i].h !== handler) {\n                        newList.push(_h[event][i]);\n                    }\n                }\n                _h[event] = newList;\n            }\n\n            if (_h[event] && _h[event].length === 0) {\n                delete _h[event];\n            }\n        }\n        else {\n            delete _h[event];\n        }\n\n        return this;\n    },\n\n    /**\n     * Dispatch a event.\n     *\n     * @param {string} type The event name.\n     */\n    trigger: function (type) {\n        var _h = this._$handlers[type];\n        var eventProcessor = this._$eventProcessor;\n\n        if (_h) {\n            var args = arguments;\n            var argLen = args.length;\n\n            if (argLen > 3) {\n                args = arrySlice.call(args, 1);\n            }\n\n            var len = _h.length;\n            for (var i = 0; i < len;) {\n                var hItem = _h[i];\n                if (eventProcessor\n                    && eventProcessor.filter\n                    && hItem.query != null\n                    && !eventProcessor.filter(type, hItem.query)\n                ) {\n                    i++;\n                    continue;\n                }\n\n                // Optimize advise from backbone\n                switch (argLen) {\n                    case 1:\n                        hItem.h.call(hItem.ctx);\n                        break;\n                    case 2:\n                        hItem.h.call(hItem.ctx, args[1]);\n                        break;\n                    case 3:\n                        hItem.h.call(hItem.ctx, args[1], args[2]);\n                        break;\n                    default:\n                        // have more than 2 given arguments\n                        hItem.h.apply(hItem.ctx, args);\n                        break;\n                }\n\n                if (hItem.one) {\n                    _h.splice(i, 1);\n                    len--;\n                }\n                else {\n                    i++;\n                }\n            }\n        }\n\n        eventProcessor && eventProcessor.afterTrigger\n            && eventProcessor.afterTrigger(type);\n\n        return this;\n    },\n\n    /**\n     * Dispatch a event with context, which is specified at the last parameter.\n     *\n     * @param {string} type The event name.\n     */\n    triggerWithContext: function (type) {\n        var _h = this._$handlers[type];\n        var eventProcessor = this._$eventProcessor;\n\n        if (_h) {\n            var args = arguments;\n            var argLen = args.length;\n\n            if (argLen > 4) {\n                args = arrySlice.call(args, 1, args.length - 1);\n            }\n            var ctx = args[args.length - 1];\n\n            var len = _h.length;\n            for (var i = 0; i < len;) {\n                var hItem = _h[i];\n                if (eventProcessor\n                    && eventProcessor.filter\n                    && hItem.query != null\n                    && !eventProcessor.filter(type, hItem.query)\n                ) {\n                    i++;\n                    continue;\n                }\n\n                // Optimize advise from backbone\n                switch (argLen) {\n                    case 1:\n                        hItem.h.call(ctx);\n                        break;\n                    case 2:\n                        hItem.h.call(ctx, args[1]);\n                        break;\n                    case 3:\n                        hItem.h.call(ctx, args[1], args[2]);\n                        break;\n                    default:\n                        // have more than 2 given arguments\n                        hItem.h.apply(ctx, args);\n                        break;\n                }\n\n                if (hItem.one) {\n                    _h.splice(i, 1);\n                    len--;\n                }\n                else {\n                    i++;\n                }\n            }\n        }\n\n        eventProcessor && eventProcessor.afterTrigger\n            && eventProcessor.afterTrigger(type);\n\n        return this;\n    }\n};\n\nfunction normalizeQuery(host, query) {\n    var eventProcessor = host._$eventProcessor;\n    if (query != null && eventProcessor && eventProcessor.normalizeQuery) {\n        query = eventProcessor.normalizeQuery(query);\n    }\n    return query;\n}\n\nfunction on(eventful, event, query, handler, context, isOnce) {\n    var _h = eventful._$handlers;\n\n    if (typeof query === 'function') {\n        context = handler;\n        handler = query;\n        query = null;\n    }\n\n    if (!handler || !event) {\n        return eventful;\n    }\n\n    query = normalizeQuery(eventful, query);\n\n    if (!_h[event]) {\n        _h[event] = [];\n    }\n\n    for (var i = 0; i < _h[event].length; i++) {\n        if (_h[event][i].h === handler) {\n            return eventful;\n        }\n    }\n\n    var wrap = {\n        h: handler,\n        one: isOnce,\n        query: query,\n        ctx: context || eventful,\n        // FIXME\n        // Do not publish this feature util it is proved that it makes sense.\n        callAtLast: handler.zrEventfulCallAtLast\n    };\n\n    var lastIndex = _h[event].length - 1;\n    var lastWrap = _h[event][lastIndex];\n    (lastWrap && lastWrap.callAtLast)\n        ? _h[event].splice(lastIndex, 0, wrap)\n        : _h[event].push(wrap);\n\n    return eventful;\n}\n\n/**\n * 事件辅助类\n * @module zrender/core/event\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n */\n\nvar isDomLevel2 = (typeof window !== 'undefined') && !!window.addEventListener;\n\nvar MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;\n\nfunction getBoundingClientRect(el) {\n    // BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect\n    return el.getBoundingClientRect ? el.getBoundingClientRect() : {left: 0, top: 0};\n}\n\n// `calculate` is optional, default false\nfunction clientToLocal(el, e, out, calculate) {\n    out = out || {};\n\n    // According to the W3C Working Draft, offsetX and offsetY should be relative\n    // to the padding edge of the target element. The only browser using this convention\n    // is IE. Webkit uses the border edge, Opera uses the content edge, and FireFox does\n    // not support the properties.\n    // (see http://www.jacklmoore.com/notes/mouse-position/)\n    // In zr painter.dom, padding edge equals to border edge.\n\n    // FIXME\n    // When mousemove event triggered on ec tooltip, target is not zr painter.dom, and\n    // offsetX/Y is relative to e.target, where the calculation of zrX/Y via offsetX/Y\n    // is too complex. So css-transfrom dont support in this case temporarily.\n    if (calculate || !env$1.canvasSupported) {\n        defaultGetZrXY(el, e, out);\n    }\n    // Caution: In FireFox, layerX/layerY Mouse position relative to the closest positioned\n    // ancestor element, so we should make sure el is positioned (e.g., not position:static).\n    // BTW1, Webkit don't return the same results as FF in non-simple cases (like add\n    // zoom-factor, overflow / opacity layers, transforms ...)\n    // BTW2, (ev.offsetY || ev.pageY - $(ev.target).offset().top) is not correct in preserve-3d.\n    // <https://bugs.jquery.com/ticket/8523#comment:14>\n    // BTW3, In ff, offsetX/offsetY is always 0.\n    else if (env$1.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) {\n        out.zrX = e.layerX;\n        out.zrY = e.layerY;\n    }\n    // For IE6+, chrome, safari, opera. (When will ff support offsetX?)\n    else if (e.offsetX != null) {\n        out.zrX = e.offsetX;\n        out.zrY = e.offsetY;\n    }\n    // For some other device, e.g., IOS safari.\n    else {\n        defaultGetZrXY(el, e, out);\n    }\n\n    return out;\n}\n\nfunction defaultGetZrXY(el, e, out) {\n    // This well-known method below does not support css transform.\n    var box = getBoundingClientRect(el);\n    out.zrX = e.clientX - box.left;\n    out.zrY = e.clientY - box.top;\n}\n\n/**\n * 如果存在第三方嵌入的一些dom触发的事件，或touch事件，需要转换一下事件坐标.\n * `calculate` is optional, default false.\n */\nfunction normalizeEvent(el, e, calculate) {\n\n    e = e || window.event;\n\n    if (e.zrX != null) {\n        return e;\n    }\n\n    var eventType = e.type;\n    var isTouch = eventType && eventType.indexOf('touch') >= 0;\n\n    if (!isTouch) {\n        clientToLocal(el, e, e, calculate);\n        e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3;\n    }\n    else {\n        var touch = eventType !== 'touchend'\n            ? e.targetTouches[0]\n            : e.changedTouches[0];\n        touch && clientToLocal(el, touch, e, calculate);\n    }\n\n    // Add which for click: 1 === left; 2 === middle; 3 === right; otherwise: 0;\n    // See jQuery: https://github.com/jquery/jquery/blob/master/src/event.js\n    // If e.which has been defined, if may be readonly,\n    // see: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which\n    var button = e.button;\n    if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) {\n        e.which = (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));\n    }\n    // [Caution]: `e.which` from browser is not always reliable. For example,\n    // when press left button and `mousemove (pointermove)` in Edge, the `e.which`\n    // is 65536 and the `e.button` is -1. But the `mouseup (pointerup)` and\n    // `mousedown (pointerdown)` is the same as Chrome does.\n\n    return e;\n}\n\n/**\n * @param {HTMLElement} el\n * @param {string} name\n * @param {Function} handler\n */\nfunction addEventListener(el, name, handler) {\n    if (isDomLevel2) {\n        // Reproduct the console warning:\n        // [Violation] Added non-passive event listener to a scroll-blocking <some> event.\n        // Consider marking event handler as 'passive' to make the page more responsive.\n        // Just set console log level: verbose in chrome dev tool.\n        // then the warning log will be printed when addEventListener called.\n        // See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md\n        // We have not yet found a neat way to using passive. Because in zrender the dom event\n        // listener delegate all of the upper events of element. Some of those events need\n        // to prevent default. For example, the feature `preventDefaultMouseMove` of echarts.\n        // Before passive can be adopted, these issues should be considered:\n        // (1) Whether and how a zrender user specifies an event listener passive. And by default,\n        // passive or not.\n        // (2) How to tread that some zrender event listener is passive, and some is not. If\n        // we use other way but not preventDefault of mousewheel and touchmove, browser\n        // compatibility should be handled.\n\n        // var opts = (env.passiveSupported && name === 'mousewheel')\n        //     ? {passive: true}\n        //     // By default, the third param of el.addEventListener is `capture: false`.\n        //     : void 0;\n        // el.addEventListener(name, handler /* , opts */);\n        el.addEventListener(name, handler);\n    }\n    else {\n        el.attachEvent('on' + name, handler);\n    }\n}\n\nfunction removeEventListener(el, name, handler) {\n    if (isDomLevel2) {\n        el.removeEventListener(name, handler);\n    }\n    else {\n        el.detachEvent('on' + name, handler);\n    }\n}\n\n/**\n * preventDefault and stopPropagation.\n * Notice: do not do that in zrender. Upper application\n * do that if necessary.\n *\n * @memberOf module:zrender/core/event\n * @method\n * @param {Event} e : event对象\n */\nvar stop = isDomLevel2\n    ? function (e) {\n        e.preventDefault();\n        e.stopPropagation();\n        e.cancelBubble = true;\n    }\n    : function (e) {\n        e.returnValue = false;\n        e.cancelBubble = true;\n    };\n\n/**\n * This method only works for mouseup and mousedown. The functionality is restricted\n * for fault tolerance, See the `e.which` compatibility above.\n *\n * @param {MouseEvent} e\n * @return {boolean}\n */\nfunction isMiddleOrRightButtonOnMouseUpDown(e) {\n    return e.which === 2 || e.which === 3;\n}\n\n/**\n * To be removed.\n * @deprecated\n */\n\n/**\n * Only implements needed gestures for mobile.\n */\n\nvar GestureMgr = function () {\n\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    this._track = [];\n};\n\nGestureMgr.prototype = {\n\n    constructor: GestureMgr,\n\n    recognize: function (event, target, root) {\n        this._doTrack(event, target, root);\n        return this._recognize(event);\n    },\n\n    clear: function () {\n        this._track.length = 0;\n        return this;\n    },\n\n    _doTrack: function (event, target, root) {\n        var touches = event.touches;\n\n        if (!touches) {\n            return;\n        }\n\n        var trackItem = {\n            points: [],\n            touches: [],\n            target: target,\n            event: event\n        };\n\n        for (var i = 0, len = touches.length; i < len; i++) {\n            var touch = touches[i];\n            var pos = clientToLocal(root, touch, {});\n            trackItem.points.push([pos.zrX, pos.zrY]);\n            trackItem.touches.push(touch);\n        }\n\n        this._track.push(trackItem);\n    },\n\n    _recognize: function (event) {\n        for (var eventName in recognizers) {\n            if (recognizers.hasOwnProperty(eventName)) {\n                var gestureInfo = recognizers[eventName](this._track, event);\n                if (gestureInfo) {\n                    return gestureInfo;\n                }\n            }\n        }\n    }\n};\n\nfunction dist$1(pointPair) {\n    var dx = pointPair[1][0] - pointPair[0][0];\n    var dy = pointPair[1][1] - pointPair[0][1];\n\n    return Math.sqrt(dx * dx + dy * dy);\n}\n\nfunction center(pointPair) {\n    return [\n        (pointPair[0][0] + pointPair[1][0]) / 2,\n        (pointPair[0][1] + pointPair[1][1]) / 2\n    ];\n}\n\nvar recognizers = {\n\n    pinch: function (track, event) {\n        var trackLen = track.length;\n\n        if (!trackLen) {\n            return;\n        }\n\n        var pinchEnd = (track[trackLen - 1] || {}).points;\n        var pinchPre = (track[trackLen - 2] || {}).points || pinchEnd;\n\n        if (pinchPre\n            && pinchPre.length > 1\n            && pinchEnd\n            && pinchEnd.length > 1\n        ) {\n            var pinchScale = dist$1(pinchEnd) / dist$1(pinchPre);\n            !isFinite(pinchScale) && (pinchScale = 1);\n\n            event.pinchScale = pinchScale;\n\n            var pinchCenter = center(pinchEnd);\n            event.pinchX = pinchCenter[0];\n            event.pinchY = pinchCenter[1];\n\n            return {\n                type: 'pinch',\n                target: track[0].target,\n                event: event\n            };\n        }\n    }\n\n    // Only pinch currently.\n};\n\nvar SILENT = 'silent';\n\nfunction makeEventPacket(eveType, targetInfo, event) {\n    return {\n        type: eveType,\n        event: event,\n        // target can only be an element that is not silent.\n        target: targetInfo.target,\n        // topTarget can be a silent element.\n        topTarget: targetInfo.topTarget,\n        cancelBubble: false,\n        offsetX: event.zrX,\n        offsetY: event.zrY,\n        gestureEvent: event.gestureEvent,\n        pinchX: event.pinchX,\n        pinchY: event.pinchY,\n        pinchScale: event.pinchScale,\n        wheelDelta: event.zrDelta,\n        zrByTouch: event.zrByTouch,\n        which: event.which,\n        stop: stopEvent\n    };\n}\n\nfunction stopEvent(event) {\n    stop(this.event);\n}\n\nfunction EmptyProxy() {}\nEmptyProxy.prototype.dispose = function () {};\n\nvar handlerNames = [\n    'click', 'dblclick', 'mousewheel', 'mouseout',\n    'mouseup', 'mousedown', 'mousemove', 'contextmenu'\n];\n/**\n * @alias module:zrender/Handler\n * @constructor\n * @extends module:zrender/mixin/Eventful\n * @param {module:zrender/Storage} storage Storage instance.\n * @param {module:zrender/Painter} painter Painter instance.\n * @param {module:zrender/dom/HandlerProxy} proxy HandlerProxy instance.\n * @param {HTMLElement} painterRoot painter.root (not painter.getViewportRoot()).\n */\nvar Handler = function (storage, painter, proxy, painterRoot) {\n    Eventful.call(this);\n\n    this.storage = storage;\n\n    this.painter = painter;\n\n    this.painterRoot = painterRoot;\n\n    proxy = proxy || new EmptyProxy();\n\n    /**\n     * Proxy of event. can be Dom, WebGLSurface, etc.\n     */\n    this.proxy = null;\n\n    /**\n     * {target, topTarget, x, y}\n     * @private\n     * @type {Object}\n     */\n    this._hovered = {};\n\n    /**\n     * @private\n     * @type {Date}\n     */\n    this._lastTouchMoment;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._lastX;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._lastY;\n\n    /**\n     * @private\n     * @type {module:zrender/core/GestureMgr}\n     */\n    this._gestureMgr;\n\n\n    Draggable.call(this);\n\n    this.setHandlerProxy(proxy);\n};\n\nHandler.prototype = {\n\n    constructor: Handler,\n\n    setHandlerProxy: function (proxy) {\n        if (this.proxy) {\n            this.proxy.dispose();\n        }\n\n        if (proxy) {\n            each$1(handlerNames, function (name) {\n                proxy.on && proxy.on(name, this[name], this);\n            }, this);\n            // Attach handler\n            proxy.handler = this;\n        }\n        this.proxy = proxy;\n    },\n\n    mousemove: function (event) {\n        var x = event.zrX;\n        var y = event.zrY;\n\n        var lastHovered = this._hovered;\n        var lastHoveredTarget = lastHovered.target;\n\n        // If lastHoveredTarget is removed from zr (detected by '__zr') by some API call\n        // (like 'setOption' or 'dispatchAction') in event handlers, we should find\n        // lastHovered again here. Otherwise 'mouseout' can not be triggered normally.\n        // See #6198.\n        if (lastHoveredTarget && !lastHoveredTarget.__zr) {\n            lastHovered = this.findHover(lastHovered.x, lastHovered.y);\n            lastHoveredTarget = lastHovered.target;\n        }\n\n        var hovered = this._hovered = this.findHover(x, y);\n        var hoveredTarget = hovered.target;\n\n        var proxy = this.proxy;\n        proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default');\n\n        // Mouse out on previous hovered element\n        if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget) {\n            this.dispatchToElement(lastHovered, 'mouseout', event);\n        }\n\n        // Mouse moving on one element\n        this.dispatchToElement(hovered, 'mousemove', event);\n\n        // Mouse over on a new element\n        if (hoveredTarget && hoveredTarget !== lastHoveredTarget) {\n            this.dispatchToElement(hovered, 'mouseover', event);\n        }\n    },\n\n    mouseout: function (event) {\n        this.dispatchToElement(this._hovered, 'mouseout', event);\n\n        // There might be some doms created by upper layer application\n        // at the same level of painter.getViewportRoot() (e.g., tooltip\n        // dom created by echarts), where 'globalout' event should not\n        // be triggered when mouse enters these doms. (But 'mouseout'\n        // should be triggered at the original hovered element as usual).\n        var element = event.toElement || event.relatedTarget;\n        var innerDom;\n        do {\n            element = element && element.parentNode;\n        }\n        while (element && element.nodeType !== 9 && !(\n            innerDom = element === this.painterRoot\n        ));\n\n        !innerDom && this.trigger('globalout', {event: event});\n    },\n\n    /**\n     * Resize\n     */\n    resize: function (event) {\n        this._hovered = {};\n    },\n\n    /**\n     * Dispatch event\n     * @param {string} eventName\n     * @param {event=} eventArgs\n     */\n    dispatch: function (eventName, eventArgs) {\n        var handler = this[eventName];\n        handler && handler.call(this, eventArgs);\n    },\n\n    /**\n     * Dispose\n     */\n    dispose: function () {\n\n        this.proxy.dispose();\n\n        this.storage =\n        this.proxy =\n        this.painter = null;\n    },\n\n    /**\n     * 设置默认的cursor style\n     * @param {string} [cursorStyle='default'] 例如 crosshair\n     */\n    setCursorStyle: function (cursorStyle) {\n        var proxy = this.proxy;\n        proxy.setCursor && proxy.setCursor(cursorStyle);\n    },\n\n    /**\n     * 事件分发代理\n     *\n     * @private\n     * @param {Object} targetInfo {target, topTarget} 目标图形元素\n     * @param {string} eventName 事件名称\n     * @param {Object} event 事件对象\n     */\n    dispatchToElement: function (targetInfo, eventName, event) {\n        targetInfo = targetInfo || {};\n        var el = targetInfo.target;\n        if (el && el.silent) {\n            return;\n        }\n        var eventHandler = 'on' + eventName;\n        var eventPacket = makeEventPacket(eventName, targetInfo, event);\n\n        while (el) {\n            el[eventHandler]\n                && (eventPacket.cancelBubble = el[eventHandler].call(el, eventPacket));\n\n            el.trigger(eventName, eventPacket);\n\n            el = el.parent;\n\n            if (eventPacket.cancelBubble) {\n                break;\n            }\n        }\n\n        if (!eventPacket.cancelBubble) {\n            // 冒泡到顶级 zrender 对象\n            this.trigger(eventName, eventPacket);\n            // 分发事件到用户自定义层\n            // 用户有可能在全局 click 事件中 dispose，所以需要判断下 painter 是否存在\n            this.painter && this.painter.eachOtherLayer(function (layer) {\n                if (typeof (layer[eventHandler]) === 'function') {\n                    layer[eventHandler].call(layer, eventPacket);\n                }\n                if (layer.trigger) {\n                    layer.trigger(eventName, eventPacket);\n                }\n            });\n        }\n    },\n\n    /**\n     * @private\n     * @param {number} x\n     * @param {number} y\n     * @param {module:zrender/graphic/Displayable} exclude\n     * @return {model:zrender/Element}\n     * @method\n     */\n    findHover: function (x, y, exclude) {\n        var list = this.storage.getDisplayList();\n        var out = {x: x, y: y};\n\n        for (var i = list.length - 1; i >= 0; i--) {\n            var hoverCheckResult;\n            if (list[i] !== exclude\n                // getDisplayList may include ignored item in VML mode\n                && !list[i].ignore\n                && (hoverCheckResult = isHover(list[i], x, y))\n            ) {\n                !out.topTarget && (out.topTarget = list[i]);\n                if (hoverCheckResult !== SILENT) {\n                    out.target = list[i];\n                    break;\n                }\n            }\n        }\n\n        return out;\n    },\n\n    processGesture: function (event, stage) {\n        if (!this._gestureMgr) {\n            this._gestureMgr = new GestureMgr();\n        }\n        var gestureMgr = this._gestureMgr;\n\n        stage === 'start' && gestureMgr.clear();\n\n        var gestureInfo = gestureMgr.recognize(\n            event,\n            this.findHover(event.zrX, event.zrY, null).target,\n            this.proxy.dom\n        );\n\n        stage === 'end' && gestureMgr.clear();\n\n        // Do not do any preventDefault here. Upper application do that if necessary.\n        if (gestureInfo) {\n            var type = gestureInfo.type;\n            event.gestureEvent = type;\n\n            this.dispatchToElement({target: gestureInfo.target}, type, gestureInfo.event);\n        }\n    }\n};\n\n// Common handlers\neach$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {\n    Handler.prototype[name] = function (event) {\n        // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover\n        var hovered = this.findHover(event.zrX, event.zrY);\n        var hoveredTarget = hovered.target;\n\n        if (name === 'mousedown') {\n            this._downEl = hoveredTarget;\n            this._downPoint = [event.zrX, event.zrY];\n            // In case click triggered before mouseup\n            this._upEl = hoveredTarget;\n        }\n        else if (name === 'mouseup') {\n            this._upEl = hoveredTarget;\n        }\n        else if (name === 'click') {\n            if (this._downEl !== this._upEl\n                // Original click event is triggered on the whole canvas element,\n                // including the case that `mousedown` - `mousemove` - `mouseup`,\n                // which should be filtered, otherwise it will bring trouble to\n                // pan and zoom.\n                || !this._downPoint\n                // Arbitrary value\n                || dist(this._downPoint, [event.zrX, event.zrY]) > 4\n            ) {\n                return;\n            }\n            this._downPoint = null;\n        }\n\n        this.dispatchToElement(hovered, name, event);\n    };\n});\n\nfunction isHover(displayable, x, y) {\n    if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) {\n        var el = displayable;\n        var isSilent;\n        while (el) {\n            // If clipped by ancestor.\n            // FIXME: If clipPath has neither stroke nor fill,\n            // el.clipPath.contain(x, y) will always return false.\n            if (el.clipPath && !el.clipPath.contain(x, y)) {\n                return false;\n            }\n            if (el.silent) {\n                isSilent = true;\n            }\n            el = el.parent;\n        }\n        return isSilent ? SILENT : true;\n    }\n\n    return false;\n}\n\nmixin(Handler, Eventful);\nmixin(Handler, Draggable);\n\n/**\n * 3x2矩阵操作类\n * @exports zrender/tool/matrix\n */\n\nvar ArrayCtor$1 = typeof Float32Array === 'undefined'\n    ? Array\n    : Float32Array;\n\n/**\n * Create a identity matrix.\n * @return {Float32Array|Array.<number>}\n */\nfunction create$1() {\n    var out = new ArrayCtor$1(6);\n    identity(out);\n\n    return out;\n}\n\n/**\n * 设置矩阵为单位矩阵\n * @param {Float32Array|Array.<number>} out\n */\nfunction identity(out) {\n    out[0] = 1;\n    out[1] = 0;\n    out[2] = 0;\n    out[3] = 1;\n    out[4] = 0;\n    out[5] = 0;\n    return out;\n}\n\n/**\n * 复制矩阵\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} m\n */\nfunction copy$1(out, m) {\n    out[0] = m[0];\n    out[1] = m[1];\n    out[2] = m[2];\n    out[3] = m[3];\n    out[4] = m[4];\n    out[5] = m[5];\n    return out;\n}\n\n/**\n * 矩阵相乘\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} m1\n * @param {Float32Array|Array.<number>} m2\n */\nfunction mul$1(out, m1, m2) {\n    // Consider matrix.mul(m, m2, m);\n    // where out is the same as m2.\n    // So use temp variable to escape error.\n    var out0 = m1[0] * m2[0] + m1[2] * m2[1];\n    var out1 = m1[1] * m2[0] + m1[3] * m2[1];\n    var out2 = m1[0] * m2[2] + m1[2] * m2[3];\n    var out3 = m1[1] * m2[2] + m1[3] * m2[3];\n    var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];\n    var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];\n    out[0] = out0;\n    out[1] = out1;\n    out[2] = out2;\n    out[3] = out3;\n    out[4] = out4;\n    out[5] = out5;\n    return out;\n}\n\n/**\n * 平移变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {Float32Array|Array.<number>} v\n */\nfunction translate(out, a, v) {\n    out[0] = a[0];\n    out[1] = a[1];\n    out[2] = a[2];\n    out[3] = a[3];\n    out[4] = a[4] + v[0];\n    out[5] = a[5] + v[1];\n    return out;\n}\n\n/**\n * 旋转变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {number} rad\n */\nfunction rotate(out, a, rad) {\n    var aa = a[0];\n    var ac = a[2];\n    var atx = a[4];\n    var ab = a[1];\n    var ad = a[3];\n    var aty = a[5];\n    var st = Math.sin(rad);\n    var ct = Math.cos(rad);\n\n    out[0] = aa * ct + ab * st;\n    out[1] = -aa * st + ab * ct;\n    out[2] = ac * ct + ad * st;\n    out[3] = -ac * st + ct * ad;\n    out[4] = ct * atx + st * aty;\n    out[5] = ct * aty - st * atx;\n    return out;\n}\n\n/**\n * 缩放变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {Float32Array|Array.<number>} v\n */\nfunction scale$1(out, a, v) {\n    var vx = v[0];\n    var vy = v[1];\n    out[0] = a[0] * vx;\n    out[1] = a[1] * vy;\n    out[2] = a[2] * vx;\n    out[3] = a[3] * vy;\n    out[4] = a[4] * vx;\n    out[5] = a[5] * vy;\n    return out;\n}\n\n/**\n * 求逆矩阵\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n */\nfunction invert(out, a) {\n\n    var aa = a[0];\n    var ac = a[2];\n    var atx = a[4];\n    var ab = a[1];\n    var ad = a[3];\n    var aty = a[5];\n\n    var det = aa * ad - ab * ac;\n    if (!det) {\n        return null;\n    }\n    det = 1.0 / det;\n\n    out[0] = ad * det;\n    out[1] = -ab * det;\n    out[2] = -ac * det;\n    out[3] = aa * det;\n    out[4] = (ac * aty - ad * atx) * det;\n    out[5] = (ab * atx - aa * aty) * det;\n    return out;\n}\n\n/**\n * Clone a new matrix.\n * @param {Float32Array|Array.<number>} a\n */\nfunction clone$2(a) {\n    var b = create$1();\n    copy$1(b, a);\n    return b;\n}\n\nvar matrix = (Object.freeze || Object)({\n\tcreate: create$1,\n\tidentity: identity,\n\tcopy: copy$1,\n\tmul: mul$1,\n\ttranslate: translate,\n\trotate: rotate,\n\tscale: scale$1,\n\tinvert: invert,\n\tclone: clone$2\n});\n\n/**\n * 提供变换扩展\n * @module zrender/mixin/Transformable\n * @author pissang (https://www.github.com/pissang)\n */\n\nvar mIdentity = identity;\n\nvar EPSILON = 5e-5;\n\nfunction isNotAroundZero(val) {\n    return val > EPSILON || val < -EPSILON;\n}\n\n/**\n * @alias module:zrender/mixin/Transformable\n * @constructor\n */\nvar Transformable = function (opts) {\n    opts = opts || {};\n    // If there are no given position, rotation, scale\n    if (!opts.position) {\n        /**\n         * 平移\n         * @type {Array.<number>}\n         * @default [0, 0]\n         */\n        this.position = [0, 0];\n    }\n    if (opts.rotation == null) {\n        /**\n         * 旋转\n         * @type {Array.<number>}\n         * @default 0\n         */\n        this.rotation = 0;\n    }\n    if (!opts.scale) {\n        /**\n         * 缩放\n         * @type {Array.<number>}\n         * @default [1, 1]\n         */\n        this.scale = [1, 1];\n    }\n    /**\n     * 旋转和缩放的原点\n     * @type {Array.<number>}\n     * @default null\n     */\n    this.origin = this.origin || null;\n};\n\nvar transformableProto = Transformable.prototype;\ntransformableProto.transform = null;\n\n/**\n * 判断是否需要有坐标变换\n * 如果有坐标变换, 则从position, rotation, scale以及父节点的transform计算出自身的transform矩阵\n */\ntransformableProto.needLocalTransform = function () {\n    return isNotAroundZero(this.rotation)\n        || isNotAroundZero(this.position[0])\n        || isNotAroundZero(this.position[1])\n        || isNotAroundZero(this.scale[0] - 1)\n        || isNotAroundZero(this.scale[1] - 1);\n};\n\nvar scaleTmp = [];\ntransformableProto.updateTransform = function () {\n    var parent = this.parent;\n    var parentHasTransform = parent && parent.transform;\n    var needLocalTransform = this.needLocalTransform();\n\n    var m = this.transform;\n    if (!(needLocalTransform || parentHasTransform)) {\n        m && mIdentity(m);\n        return;\n    }\n\n    m = m || create$1();\n\n    if (needLocalTransform) {\n        this.getLocalTransform(m);\n    }\n    else {\n        mIdentity(m);\n    }\n\n    // 应用父节点变换\n    if (parentHasTransform) {\n        if (needLocalTransform) {\n            mul$1(m, parent.transform, m);\n        }\n        else {\n            copy$1(m, parent.transform);\n        }\n    }\n    // 保存这个变换矩阵\n    this.transform = m;\n\n    var globalScaleRatio = this.globalScaleRatio;\n    if (globalScaleRatio != null && globalScaleRatio !== 1) {\n        this.getGlobalScale(scaleTmp);\n        var relX = scaleTmp[0] < 0 ? -1 : 1;\n        var relY = scaleTmp[1] < 0 ? -1 : 1;\n        var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0;\n        var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0;\n\n        m[0] *= sx;\n        m[1] *= sx;\n        m[2] *= sy;\n        m[3] *= sy;\n    }\n\n    this.invTransform = this.invTransform || create$1();\n    invert(this.invTransform, m);\n};\n\ntransformableProto.getLocalTransform = function (m) {\n    return Transformable.getLocalTransform(this, m);\n};\n\n/**\n * 将自己的transform应用到context上\n * @param {CanvasRenderingContext2D} ctx\n */\ntransformableProto.setTransform = function (ctx) {\n    var m = this.transform;\n    var dpr = ctx.dpr || 1;\n    if (m) {\n        ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]);\n    }\n    else {\n        ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    }\n};\n\ntransformableProto.restoreTransform = function (ctx) {\n    var dpr = ctx.dpr || 1;\n    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n};\n\nvar tmpTransform = [];\nvar originTransform = create$1();\n\ntransformableProto.setLocalTransform = function (m) {\n    if (!m) {\n        // TODO return or set identity?\n        return;\n    }\n    var sx = m[0] * m[0] + m[1] * m[1];\n    var sy = m[2] * m[2] + m[3] * m[3];\n    var position = this.position;\n    var scale$$1 = this.scale;\n    if (isNotAroundZero(sx - 1)) {\n        sx = Math.sqrt(sx);\n    }\n    if (isNotAroundZero(sy - 1)) {\n        sy = Math.sqrt(sy);\n    }\n    if (m[0] < 0) {\n        sx = -sx;\n    }\n    if (m[3] < 0) {\n        sy = -sy;\n    }\n\n    position[0] = m[4];\n    position[1] = m[5];\n    scale$$1[0] = sx;\n    scale$$1[1] = sy;\n    this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);\n};\n/**\n * 分解`transform`矩阵到`position`, `rotation`, `scale`\n */\ntransformableProto.decomposeTransform = function () {\n    if (!this.transform) {\n        return;\n    }\n    var parent = this.parent;\n    var m = this.transform;\n    if (parent && parent.transform) {\n        // Get local transform and decompose them to position, scale, rotation\n        mul$1(tmpTransform, parent.invTransform, m);\n        m = tmpTransform;\n    }\n    var origin = this.origin;\n    if (origin && (origin[0] || origin[1])) {\n        originTransform[4] = origin[0];\n        originTransform[5] = origin[1];\n        mul$1(tmpTransform, m, originTransform);\n        tmpTransform[4] -= origin[0];\n        tmpTransform[5] -= origin[1];\n        m = tmpTransform;\n    }\n\n    this.setLocalTransform(m);\n};\n\n/**\n * Get global scale\n * @return {Array.<number>}\n */\ntransformableProto.getGlobalScale = function (out) {\n    var m = this.transform;\n    out = out || [];\n    if (!m) {\n        out[0] = 1;\n        out[1] = 1;\n        return out;\n    }\n    out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]);\n    out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]);\n    if (m[0] < 0) {\n        out[0] = -out[0];\n    }\n    if (m[3] < 0) {\n        out[1] = -out[1];\n    }\n    return out;\n};\n/**\n * 变换坐标位置到 shape 的局部坐标空间\n * @method\n * @param {number} x\n * @param {number} y\n * @return {Array.<number>}\n */\ntransformableProto.transformCoordToLocal = function (x, y) {\n    var v2 = [x, y];\n    var invTransform = this.invTransform;\n    if (invTransform) {\n        applyTransform(v2, v2, invTransform);\n    }\n    return v2;\n};\n\n/**\n * 变换局部坐标位置到全局坐标空间\n * @method\n * @param {number} x\n * @param {number} y\n * @return {Array.<number>}\n */\ntransformableProto.transformCoordToGlobal = function (x, y) {\n    var v2 = [x, y];\n    var transform = this.transform;\n    if (transform) {\n        applyTransform(v2, v2, transform);\n    }\n    return v2;\n};\n\n/**\n * @static\n * @param {Object} target\n * @param {Array.<number>} target.origin\n * @param {number} target.rotation\n * @param {Array.<number>} target.position\n * @param {Array.<number>} [m]\n */\nTransformable.getLocalTransform = function (target, m) {\n    m = m || [];\n    mIdentity(m);\n\n    var origin = target.origin;\n    var scale$$1 = target.scale || [1, 1];\n    var rotation = target.rotation || 0;\n    var position = target.position || [0, 0];\n\n    if (origin) {\n        // Translate to origin\n        m[4] -= origin[0];\n        m[5] -= origin[1];\n    }\n    scale$1(m, m, scale$$1);\n    if (rotation) {\n        rotate(m, m, rotation);\n    }\n    if (origin) {\n        // Translate back from origin\n        m[4] += origin[0];\n        m[5] += origin[1];\n    }\n\n    m[4] += position[0];\n    m[5] += position[1];\n\n    return m;\n};\n\n/**\n * 缓动代码来自 https://github.com/sole/tween.js/blob/master/src/Tween.js\n * @see http://sole.github.io/tween.js/examples/03_graphs.html\n * @exports zrender/animation/easing\n */\nvar easing = {\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    linear: function (k) {\n        return k;\n    },\n\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticIn: function (k) {\n        return k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticOut: function (k) {\n        return k * (2 - k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k;\n        }\n        return -0.5 * (--k * (k - 2) - 1);\n    },\n\n    // 三次方的缓动（t^3）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicIn: function (k) {\n        return k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicOut: function (k) {\n        return --k * k * k + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k;\n        }\n        return 0.5 * ((k -= 2) * k * k + 2);\n    },\n\n    // 四次方的缓动（t^4）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticIn: function (k) {\n        return k * k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticOut: function (k) {\n        return 1 - (--k * k * k * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k * k;\n        }\n        return -0.5 * ((k -= 2) * k * k * k - 2);\n    },\n\n    // 五次方的缓动（t^5）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticIn: function (k) {\n        return k * k * k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticOut: function (k) {\n        return --k * k * k * k * k + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k * k * k;\n        }\n        return 0.5 * ((k -= 2) * k * k * k * k + 2);\n    },\n\n    // 正弦曲线的缓动（sin(t)）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalIn: function (k) {\n        return 1 - Math.cos(k * Math.PI / 2);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalOut: function (k) {\n        return Math.sin(k * Math.PI / 2);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalInOut: function (k) {\n        return 0.5 * (1 - Math.cos(Math.PI * k));\n    },\n\n    // 指数曲线的缓动（2^t）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialIn: function (k) {\n        return k === 0 ? 0 : Math.pow(1024, k - 1);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialOut: function (k) {\n        return k === 1 ? 1 : 1 - Math.pow(2, -10 * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialInOut: function (k) {\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if ((k *= 2) < 1) {\n            return 0.5 * Math.pow(1024, k - 1);\n        }\n        return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);\n    },\n\n    // 圆形曲线的缓动（sqrt(1-t^2)）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularIn: function (k) {\n        return 1 - Math.sqrt(1 - k * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularOut: function (k) {\n        return Math.sqrt(1 - (--k * k));\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return -0.5 * (Math.sqrt(1 - k * k) - 1);\n        }\n        return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);\n    },\n\n    // 创建类似于弹簧在停止前来回振荡的动画\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticIn: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        return -(a * Math.pow(2, 10 * (k -= 1))\n                    * Math.sin((k - s) * (2 * Math.PI) / p));\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticOut: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        return (a * Math.pow(2, -10 * k)\n                    * Math.sin((k - s) * (2 * Math.PI) / p) + 1);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticInOut: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        if ((k *= 2) < 1) {\n            return -0.5 * (a * Math.pow(2, 10 * (k -= 1))\n                * Math.sin((k - s) * (2 * Math.PI) / p));\n        }\n        return a * Math.pow(2, -10 * (k -= 1))\n                * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;\n\n    },\n\n    // 在某一动画开始沿指示的路径进行动画处理前稍稍收回该动画的移动\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backIn: function (k) {\n        var s = 1.70158;\n        return k * k * ((s + 1) * k - s);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backOut: function (k) {\n        var s = 1.70158;\n        return --k * k * ((s + 1) * k + s) + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backInOut: function (k) {\n        var s = 1.70158 * 1.525;\n        if ((k *= 2) < 1) {\n            return 0.5 * (k * k * ((s + 1) * k - s));\n        }\n        return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);\n    },\n\n    // 创建弹跳效果\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceIn: function (k) {\n        return 1 - easing.bounceOut(1 - k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceOut: function (k) {\n        if (k < (1 / 2.75)) {\n            return 7.5625 * k * k;\n        }\n        else if (k < (2 / 2.75)) {\n            return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;\n        }\n        else if (k < (2.5 / 2.75)) {\n            return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;\n        }\n        else {\n            return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;\n        }\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceInOut: function (k) {\n        if (k < 0.5) {\n            return easing.bounceIn(k * 2) * 0.5;\n        }\n        return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;\n    }\n};\n\n/**\n * 动画主控制器\n * @config target 动画对象，可以是数组，如果是数组的话会批量分发onframe等事件\n * @config life(1000) 动画时长\n * @config delay(0) 动画延迟时间\n * @config loop(true)\n * @config gap(0) 循环的间隔时间\n * @config onframe\n * @config easing(optional)\n * @config ondestroy(optional)\n * @config onrestart(optional)\n *\n * TODO pause\n */\n\nfunction Clip(options) {\n\n    this._target = options.target;\n\n    // 生命周期\n    this._life = options.life || 1000;\n    // 延时\n    this._delay = options.delay || 0;\n    // 开始时间\n    // this._startTime = new Date().getTime() + this._delay;// 单位毫秒\n    this._initialized = false;\n\n    // 是否循环\n    this.loop = options.loop == null ? false : options.loop;\n\n    this.gap = options.gap || 0;\n\n    this.easing = options.easing || 'Linear';\n\n    this.onframe = options.onframe;\n    this.ondestroy = options.ondestroy;\n    this.onrestart = options.onrestart;\n\n    this._pausedTime = 0;\n    this._paused = false;\n}\n\nClip.prototype = {\n\n    constructor: Clip,\n\n    step: function (globalTime, deltaTime) {\n        // Set startTime on first step, or _startTime may has milleseconds different between clips\n        // PENDING\n        if (!this._initialized) {\n            this._startTime = globalTime + this._delay;\n            this._initialized = true;\n        }\n\n        if (this._paused) {\n            this._pausedTime += deltaTime;\n            return;\n        }\n\n        var percent = (globalTime - this._startTime - this._pausedTime) / this._life;\n\n        // 还没开始\n        if (percent < 0) {\n            return;\n        }\n\n        percent = Math.min(percent, 1);\n\n        var easing$$1 = this.easing;\n        var easingFunc = typeof easing$$1 === 'string' ? easing[easing$$1] : easing$$1;\n        var schedule = typeof easingFunc === 'function'\n            ? easingFunc(percent)\n            : percent;\n\n        this.fire('frame', schedule);\n\n        // 结束\n        if (percent === 1) {\n            if (this.loop) {\n                this.restart(globalTime);\n                // 重新开始周期\n                // 抛出而不是直接调用事件直到 stage.update 后再统一调用这些事件\n                return 'restart';\n            }\n\n            // 动画完成将这个控制器标识为待删除\n            // 在Animation.update中进行批量删除\n            this._needsRemove = true;\n            return 'destroy';\n        }\n\n        return null;\n    },\n\n    restart: function (globalTime) {\n        var remainder = (globalTime - this._startTime - this._pausedTime) % this._life;\n        this._startTime = globalTime - remainder + this.gap;\n        this._pausedTime = 0;\n\n        this._needsRemove = false;\n    },\n\n    fire: function (eventType, arg) {\n        eventType = 'on' + eventType;\n        if (this[eventType]) {\n            this[eventType](this._target, arg);\n        }\n    },\n\n    pause: function () {\n        this._paused = true;\n    },\n\n    resume: function () {\n        this._paused = false;\n    }\n};\n\n// Simple LRU cache use doubly linked list\n// @module zrender/core/LRU\n\n/**\n * Simple double linked list. Compared with array, it has O(1) remove operation.\n * @constructor\n */\nvar LinkedList = function () {\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.head = null;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.tail = null;\n\n    this._len = 0;\n};\n\nvar linkedListProto = LinkedList.prototype;\n/**\n * Insert a new value at the tail\n * @param  {} val\n * @return {module:zrender/core/LRU~Entry}\n */\nlinkedListProto.insert = function (val) {\n    var entry = new Entry(val);\n    this.insertEntry(entry);\n    return entry;\n};\n\n/**\n * Insert an entry at the tail\n * @param  {module:zrender/core/LRU~Entry} entry\n */\nlinkedListProto.insertEntry = function (entry) {\n    if (!this.head) {\n        this.head = this.tail = entry;\n    }\n    else {\n        this.tail.next = entry;\n        entry.prev = this.tail;\n        entry.next = null;\n        this.tail = entry;\n    }\n    this._len++;\n};\n\n/**\n * Remove entry.\n * @param  {module:zrender/core/LRU~Entry} entry\n */\nlinkedListProto.remove = function (entry) {\n    var prev = entry.prev;\n    var next = entry.next;\n    if (prev) {\n        prev.next = next;\n    }\n    else {\n        // Is head\n        this.head = next;\n    }\n    if (next) {\n        next.prev = prev;\n    }\n    else {\n        // Is tail\n        this.tail = prev;\n    }\n    entry.next = entry.prev = null;\n    this._len--;\n};\n\n/**\n * @return {number}\n */\nlinkedListProto.len = function () {\n    return this._len;\n};\n\n/**\n * Clear list\n */\nlinkedListProto.clear = function () {\n    this.head = this.tail = null;\n    this._len = 0;\n};\n\n/**\n * @constructor\n * @param {} val\n */\nvar Entry = function (val) {\n    /**\n     * @type {}\n     */\n    this.value = val;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.next;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.prev;\n};\n\n/**\n * LRU Cache\n * @constructor\n * @alias module:zrender/core/LRU\n */\nvar LRU = function (maxSize) {\n\n    this._list = new LinkedList();\n\n    this._map = {};\n\n    this._maxSize = maxSize || 10;\n\n    this._lastRemovedEntry = null;\n};\n\nvar LRUProto = LRU.prototype;\n\n/**\n * @param  {string} key\n * @param  {} value\n * @return {} Removed value\n */\nLRUProto.put = function (key, value) {\n    var list = this._list;\n    var map = this._map;\n    var removed = null;\n    if (map[key] == null) {\n        var len = list.len();\n        // Reuse last removed entry\n        var entry = this._lastRemovedEntry;\n\n        if (len >= this._maxSize && len > 0) {\n            // Remove the least recently used\n            var leastUsedEntry = list.head;\n            list.remove(leastUsedEntry);\n            delete map[leastUsedEntry.key];\n\n            removed = leastUsedEntry.value;\n            this._lastRemovedEntry = leastUsedEntry;\n        }\n\n        if (entry) {\n            entry.value = value;\n        }\n        else {\n            entry = new Entry(value);\n        }\n        entry.key = key;\n        list.insertEntry(entry);\n        map[key] = entry;\n    }\n\n    return removed;\n};\n\n/**\n * @param  {string} key\n * @return {}\n */\nLRUProto.get = function (key) {\n    var entry = this._map[key];\n    var list = this._list;\n    if (entry != null) {\n        // Put the latest used entry in the tail\n        if (entry !== list.tail) {\n            list.remove(entry);\n            list.insertEntry(entry);\n        }\n\n        return entry.value;\n    }\n};\n\n/**\n * Clear the cache\n */\nLRUProto.clear = function () {\n    this._list.clear();\n    this._map = {};\n};\n\nvar kCSSColorTable = {\n    'transparent': [0, 0, 0, 0], 'aliceblue': [240, 248, 255, 1],\n    'antiquewhite': [250, 235, 215, 1], 'aqua': [0, 255, 255, 1],\n    'aquamarine': [127, 255, 212, 1], 'azure': [240, 255, 255, 1],\n    'beige': [245, 245, 220, 1], 'bisque': [255, 228, 196, 1],\n    'black': [0, 0, 0, 1], 'blanchedalmond': [255, 235, 205, 1],\n    'blue': [0, 0, 255, 1], 'blueviolet': [138, 43, 226, 1],\n    'brown': [165, 42, 42, 1], 'burlywood': [222, 184, 135, 1],\n    'cadetblue': [95, 158, 160, 1], 'chartreuse': [127, 255, 0, 1],\n    'chocolate': [210, 105, 30, 1], 'coral': [255, 127, 80, 1],\n    'cornflowerblue': [100, 149, 237, 1], 'cornsilk': [255, 248, 220, 1],\n    'crimson': [220, 20, 60, 1], 'cyan': [0, 255, 255, 1],\n    'darkblue': [0, 0, 139, 1], 'darkcyan': [0, 139, 139, 1],\n    'darkgoldenrod': [184, 134, 11, 1], 'darkgray': [169, 169, 169, 1],\n    'darkgreen': [0, 100, 0, 1], 'darkgrey': [169, 169, 169, 1],\n    'darkkhaki': [189, 183, 107, 1], 'darkmagenta': [139, 0, 139, 1],\n    'darkolivegreen': [85, 107, 47, 1], 'darkorange': [255, 140, 0, 1],\n    'darkorchid': [153, 50, 204, 1], 'darkred': [139, 0, 0, 1],\n    'darksalmon': [233, 150, 122, 1], 'darkseagreen': [143, 188, 143, 1],\n    'darkslateblue': [72, 61, 139, 1], 'darkslategray': [47, 79, 79, 1],\n    'darkslategrey': [47, 79, 79, 1], 'darkturquoise': [0, 206, 209, 1],\n    'darkviolet': [148, 0, 211, 1], 'deeppink': [255, 20, 147, 1],\n    'deepskyblue': [0, 191, 255, 1], 'dimgray': [105, 105, 105, 1],\n    'dimgrey': [105, 105, 105, 1], 'dodgerblue': [30, 144, 255, 1],\n    'firebrick': [178, 34, 34, 1], 'floralwhite': [255, 250, 240, 1],\n    'forestgreen': [34, 139, 34, 1], 'fuchsia': [255, 0, 255, 1],\n    'gainsboro': [220, 220, 220, 1], 'ghostwhite': [248, 248, 255, 1],\n    'gold': [255, 215, 0, 1], 'goldenrod': [218, 165, 32, 1],\n    'gray': [128, 128, 128, 1], 'green': [0, 128, 0, 1],\n    'greenyellow': [173, 255, 47, 1], 'grey': [128, 128, 128, 1],\n    'honeydew': [240, 255, 240, 1], 'hotpink': [255, 105, 180, 1],\n    'indianred': [205, 92, 92, 1], 'indigo': [75, 0, 130, 1],\n    'ivory': [255, 255, 240, 1], 'khaki': [240, 230, 140, 1],\n    'lavender': [230, 230, 250, 1], 'lavenderblush': [255, 240, 245, 1],\n    'lawngreen': [124, 252, 0, 1], 'lemonchiffon': [255, 250, 205, 1],\n    'lightblue': [173, 216, 230, 1], 'lightcoral': [240, 128, 128, 1],\n    'lightcyan': [224, 255, 255, 1], 'lightgoldenrodyellow': [250, 250, 210, 1],\n    'lightgray': [211, 211, 211, 1], 'lightgreen': [144, 238, 144, 1],\n    'lightgrey': [211, 211, 211, 1], 'lightpink': [255, 182, 193, 1],\n    'lightsalmon': [255, 160, 122, 1], 'lightseagreen': [32, 178, 170, 1],\n    'lightskyblue': [135, 206, 250, 1], 'lightslategray': [119, 136, 153, 1],\n    'lightslategrey': [119, 136, 153, 1], 'lightsteelblue': [176, 196, 222, 1],\n    'lightyellow': [255, 255, 224, 1], 'lime': [0, 255, 0, 1],\n    'limegreen': [50, 205, 50, 1], 'linen': [250, 240, 230, 1],\n    'magenta': [255, 0, 255, 1], 'maroon': [128, 0, 0, 1],\n    'mediumaquamarine': [102, 205, 170, 1], 'mediumblue': [0, 0, 205, 1],\n    'mediumorchid': [186, 85, 211, 1], 'mediumpurple': [147, 112, 219, 1],\n    'mediumseagreen': [60, 179, 113, 1], 'mediumslateblue': [123, 104, 238, 1],\n    'mediumspringgreen': [0, 250, 154, 1], 'mediumturquoise': [72, 209, 204, 1],\n    'mediumvioletred': [199, 21, 133, 1], 'midnightblue': [25, 25, 112, 1],\n    'mintcream': [245, 255, 250, 1], 'mistyrose': [255, 228, 225, 1],\n    'moccasin': [255, 228, 181, 1], 'navajowhite': [255, 222, 173, 1],\n    'navy': [0, 0, 128, 1], 'oldlace': [253, 245, 230, 1],\n    'olive': [128, 128, 0, 1], 'olivedrab': [107, 142, 35, 1],\n    'orange': [255, 165, 0, 1], 'orangered': [255, 69, 0, 1],\n    'orchid': [218, 112, 214, 1], 'palegoldenrod': [238, 232, 170, 1],\n    'palegreen': [152, 251, 152, 1], 'paleturquoise': [175, 238, 238, 1],\n    'palevioletred': [219, 112, 147, 1], 'papayawhip': [255, 239, 213, 1],\n    'peachpuff': [255, 218, 185, 1], 'peru': [205, 133, 63, 1],\n    'pink': [255, 192, 203, 1], 'plum': [221, 160, 221, 1],\n    'powderblue': [176, 224, 230, 1], 'purple': [128, 0, 128, 1],\n    'red': [255, 0, 0, 1], 'rosybrown': [188, 143, 143, 1],\n    'royalblue': [65, 105, 225, 1], 'saddlebrown': [139, 69, 19, 1],\n    'salmon': [250, 128, 114, 1], 'sandybrown': [244, 164, 96, 1],\n    'seagreen': [46, 139, 87, 1], 'seashell': [255, 245, 238, 1],\n    'sienna': [160, 82, 45, 1], 'silver': [192, 192, 192, 1],\n    'skyblue': [135, 206, 235, 1], 'slateblue': [106, 90, 205, 1],\n    'slategray': [112, 128, 144, 1], 'slategrey': [112, 128, 144, 1],\n    'snow': [255, 250, 250, 1], 'springgreen': [0, 255, 127, 1],\n    'steelblue': [70, 130, 180, 1], 'tan': [210, 180, 140, 1],\n    'teal': [0, 128, 128, 1], 'thistle': [216, 191, 216, 1],\n    'tomato': [255, 99, 71, 1], 'turquoise': [64, 224, 208, 1],\n    'violet': [238, 130, 238, 1], 'wheat': [245, 222, 179, 1],\n    'white': [255, 255, 255, 1], 'whitesmoke': [245, 245, 245, 1],\n    'yellow': [255, 255, 0, 1], 'yellowgreen': [154, 205, 50, 1]\n};\n\nfunction clampCssByte(i) {  // Clamp to integer 0 .. 255.\n    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).\n    return i < 0 ? 0 : i > 255 ? 255 : i;\n}\n\nfunction clampCssAngle(i) {  // Clamp to integer 0 .. 360.\n    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).\n    return i < 0 ? 0 : i > 360 ? 360 : i;\n}\n\nfunction clampCssFloat(f) {  // Clamp to float 0.0 .. 1.0.\n    return f < 0 ? 0 : f > 1 ? 1 : f;\n}\n\nfunction parseCssInt(str) {  // int or percentage.\n    if (str.length && str.charAt(str.length - 1) === '%') {\n        return clampCssByte(parseFloat(str) / 100 * 255);\n    }\n    return clampCssByte(parseInt(str, 10));\n}\n\nfunction parseCssFloat(str) {  // float or percentage.\n    if (str.length && str.charAt(str.length - 1) === '%') {\n        return clampCssFloat(parseFloat(str) / 100);\n    }\n    return clampCssFloat(parseFloat(str));\n}\n\nfunction cssHueToRgb(m1, m2, h) {\n    if (h < 0) {\n        h += 1;\n    }\n    else if (h > 1) {\n        h -= 1;\n    }\n\n    if (h * 6 < 1) {\n        return m1 + (m2 - m1) * h * 6;\n    }\n    if (h * 2 < 1) {\n        return m2;\n    }\n    if (h * 3 < 2) {\n        return m1 + (m2 - m1) * (2 / 3 - h) * 6;\n    }\n    return m1;\n}\n\nfunction lerpNumber(a, b, p) {\n    return a + (b - a) * p;\n}\n\nfunction setRgba(out, r, g, b, a) {\n    out[0] = r; out[1] = g; out[2] = b; out[3] = a;\n    return out;\n}\nfunction copyRgba(out, a) {\n    out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3];\n    return out;\n}\n\nvar colorCache = new LRU(20);\nvar lastRemovedArr = null;\n\nfunction putToCache(colorStr, rgbaArr) {\n    // Reuse removed array\n    if (lastRemovedArr) {\n        copyRgba(lastRemovedArr, rgbaArr);\n    }\n    lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice()));\n}\n\n/**\n * @param {string} colorStr\n * @param {Array.<number>} out\n * @return {Array.<number>}\n * @memberOf module:zrender/util/color\n */\nfunction parse(colorStr, rgbaArr) {\n    if (!colorStr) {\n        return;\n    }\n    rgbaArr = rgbaArr || [];\n\n    var cached = colorCache.get(colorStr);\n    if (cached) {\n        return copyRgba(rgbaArr, cached);\n    }\n\n    // colorStr may be not string\n    colorStr = colorStr + '';\n    // Remove all whitespace, not compliant, but should just be more accepting.\n    var str = colorStr.replace(/ /g, '').toLowerCase();\n\n    // Color keywords (and transparent) lookup.\n    if (str in kCSSColorTable) {\n        copyRgba(rgbaArr, kCSSColorTable[str]);\n        putToCache(colorStr, rgbaArr);\n        return rgbaArr;\n    }\n\n    // #abc and #abc123 syntax.\n    if (str.charAt(0) === '#') {\n        if (str.length === 4) {\n            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n            if (!(iv >= 0 && iv <= 0xfff)) {\n                setRgba(rgbaArr, 0, 0, 0, 1);\n                return;  // Covers NaN.\n            }\n            setRgba(rgbaArr,\n                ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8),\n                (iv & 0xf0) | ((iv & 0xf0) >> 4),\n                (iv & 0xf) | ((iv & 0xf) << 4),\n                1\n            );\n            putToCache(colorStr, rgbaArr);\n            return rgbaArr;\n        }\n        else if (str.length === 7) {\n            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n            if (!(iv >= 0 && iv <= 0xffffff)) {\n                setRgba(rgbaArr, 0, 0, 0, 1);\n                return;  // Covers NaN.\n            }\n            setRgba(rgbaArr,\n                (iv & 0xff0000) >> 16,\n                (iv & 0xff00) >> 8,\n                iv & 0xff,\n                1\n            );\n            putToCache(colorStr, rgbaArr);\n            return rgbaArr;\n        }\n\n        return;\n    }\n    var op = str.indexOf('(');\n    var ep = str.indexOf(')');\n    if (op !== -1 && ep + 1 === str.length) {\n        var fname = str.substr(0, op);\n        var params = str.substr(op + 1, ep - (op + 1)).split(',');\n        var alpha = 1;  // To allow case fallthrough.\n        switch (fname) {\n            case 'rgba':\n                if (params.length !== 4) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                alpha = parseCssFloat(params.pop()); // jshint ignore:line\n            // Fall through.\n            case 'rgb':\n                if (params.length !== 3) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                setRgba(rgbaArr,\n                    parseCssInt(params[0]),\n                    parseCssInt(params[1]),\n                    parseCssInt(params[2]),\n                    alpha\n                );\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            case 'hsla':\n                if (params.length !== 4) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                params[3] = parseCssFloat(params[3]);\n                hsla2rgba(params, rgbaArr);\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            case 'hsl':\n                if (params.length !== 3) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                hsla2rgba(params, rgbaArr);\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            default:\n                return;\n        }\n    }\n\n    setRgba(rgbaArr, 0, 0, 0, 1);\n    return;\n}\n\n/**\n * @param {Array.<number>} hsla\n * @param {Array.<number>} rgba\n * @return {Array.<number>} rgba\n */\nfunction hsla2rgba(hsla, rgba) {\n    var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360;  // 0 .. 1\n    // NOTE(deanm): According to the CSS spec s/l should only be\n    // percentages, but we don't bother and let float or percentage.\n    var s = parseCssFloat(hsla[1]);\n    var l = parseCssFloat(hsla[2]);\n    var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;\n    var m1 = l * 2 - m2;\n\n    rgba = rgba || [];\n    setRgba(rgba,\n        clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255),\n        clampCssByte(cssHueToRgb(m1, m2, h) * 255),\n        clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255),\n        1\n    );\n\n    if (hsla.length === 4) {\n        rgba[3] = hsla[3];\n    }\n\n    return rgba;\n}\n\n/**\n * @param {Array.<number>} rgba\n * @return {Array.<number>} hsla\n */\nfunction rgba2hsla(rgba) {\n    if (!rgba) {\n        return;\n    }\n\n    // RGB from 0 to 255\n    var R = rgba[0] / 255;\n    var G = rgba[1] / 255;\n    var B = rgba[2] / 255;\n\n    var vMin = Math.min(R, G, B); // Min. value of RGB\n    var vMax = Math.max(R, G, B); // Max. value of RGB\n    var delta = vMax - vMin; // Delta RGB value\n\n    var L = (vMax + vMin) / 2;\n    var H;\n    var S;\n    // HSL results from 0 to 1\n    if (delta === 0) {\n        H = 0;\n        S = 0;\n    }\n    else {\n        if (L < 0.5) {\n            S = delta / (vMax + vMin);\n        }\n        else {\n            S = delta / (2 - vMax - vMin);\n        }\n\n        var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta;\n        var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta;\n        var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta;\n\n        if (R === vMax) {\n            H = deltaB - deltaG;\n        }\n        else if (G === vMax) {\n            H = (1 / 3) + deltaR - deltaB;\n        }\n        else if (B === vMax) {\n            H = (2 / 3) + deltaG - deltaR;\n        }\n\n        if (H < 0) {\n            H += 1;\n        }\n\n        if (H > 1) {\n            H -= 1;\n        }\n    }\n\n    var hsla = [H * 360, S, L];\n\n    if (rgba[3] != null) {\n        hsla.push(rgba[3]);\n    }\n\n    return hsla;\n}\n\n/**\n * @param {string} color\n * @param {number} level\n * @return {string}\n * @memberOf module:zrender/util/color\n */\nfunction lift(color, level) {\n    var colorArr = parse(color);\n    if (colorArr) {\n        for (var i = 0; i < 3; i++) {\n            if (level < 0) {\n                colorArr[i] = colorArr[i] * (1 - level) | 0;\n            }\n            else {\n                colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0;\n            }\n            if (colorArr[i] > 255) {\n                colorArr[i] = 255;\n            }\n            else if (color[i] < 0) {\n                colorArr[i] = 0;\n            }\n        }\n        return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');\n    }\n}\n\n/**\n * @param {string} color\n * @return {string}\n * @memberOf module:zrender/util/color\n */\nfunction toHex(color) {\n    var colorArr = parse(color);\n    if (colorArr) {\n        return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1);\n    }\n}\n\n/**\n * Map value to color. Faster than lerp methods because color is represented by rgba array.\n * @param {number} normalizedValue A float between 0 and 1.\n * @param {Array.<Array.<number>>} colors List of rgba color array\n * @param {Array.<number>} [out] Mapped gba color array\n * @return {Array.<number>} will be null/undefined if input illegal.\n */\nfunction fastLerp(normalizedValue, colors, out) {\n    if (!(colors && colors.length)\n        || !(normalizedValue >= 0 && normalizedValue <= 1)\n    ) {\n        return;\n    }\n\n    out = out || [];\n\n    var value = normalizedValue * (colors.length - 1);\n    var leftIndex = Math.floor(value);\n    var rightIndex = Math.ceil(value);\n    var leftColor = colors[leftIndex];\n    var rightColor = colors[rightIndex];\n    var dv = value - leftIndex;\n    out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv));\n    out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv));\n    out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv));\n    out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv));\n\n    return out;\n}\n\n/**\n * @deprecated\n */\nvar fastMapToColor = fastLerp;\n\n/**\n * @param {number} normalizedValue A float between 0 and 1.\n * @param {Array.<string>} colors Color list.\n * @param {boolean=} fullOutput Default false.\n * @return {(string|Object)} Result color. If fullOutput,\n *                           return {color: ..., leftIndex: ..., rightIndex: ..., value: ...},\n * @memberOf module:zrender/util/color\n */\nfunction lerp$1(normalizedValue, colors, fullOutput) {\n    if (!(colors && colors.length)\n        || !(normalizedValue >= 0 && normalizedValue <= 1)\n    ) {\n        return;\n    }\n\n    var value = normalizedValue * (colors.length - 1);\n    var leftIndex = Math.floor(value);\n    var rightIndex = Math.ceil(value);\n    var leftColor = parse(colors[leftIndex]);\n    var rightColor = parse(colors[rightIndex]);\n    var dv = value - leftIndex;\n\n    var color = stringify(\n        [\n            clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)),\n            clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)),\n            clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)),\n            clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv))\n        ],\n        'rgba'\n    );\n\n    return fullOutput\n        ? {\n            color: color,\n            leftIndex: leftIndex,\n            rightIndex: rightIndex,\n            value: value\n        }\n        : color;\n}\n\n/**\n * @deprecated\n */\nvar mapToColor = lerp$1;\n\n/**\n * @param {string} color\n * @param {number=} h 0 ~ 360, ignore when null.\n * @param {number=} s 0 ~ 1, ignore when null.\n * @param {number=} l 0 ~ 1, ignore when null.\n * @return {string} Color string in rgba format.\n * @memberOf module:zrender/util/color\n */\nfunction modifyHSL(color, h, s, l) {\n    color = parse(color);\n\n    if (color) {\n        color = rgba2hsla(color);\n        h != null && (color[0] = clampCssAngle(h));\n        s != null && (color[1] = parseCssFloat(s));\n        l != null && (color[2] = parseCssFloat(l));\n\n        return stringify(hsla2rgba(color), 'rgba');\n    }\n}\n\n/**\n * @param {string} color\n * @param {number=} alpha 0 ~ 1\n * @return {string} Color string in rgba format.\n * @memberOf module:zrender/util/color\n */\nfunction modifyAlpha(color, alpha) {\n    color = parse(color);\n\n    if (color && alpha != null) {\n        color[3] = clampCssFloat(alpha);\n        return stringify(color, 'rgba');\n    }\n}\n\n/**\n * @param {Array.<number>} arrColor like [12,33,44,0.4]\n * @param {string} type 'rgba', 'hsva', ...\n * @return {string} Result color. (If input illegal, return undefined).\n */\nfunction stringify(arrColor, type) {\n    if (!arrColor || !arrColor.length) {\n        return;\n    }\n    var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];\n    if (type === 'rgba' || type === 'hsva' || type === 'hsla') {\n        colorStr += ',' + arrColor[3];\n    }\n    return type + '(' + colorStr + ')';\n}\n\n\nvar color = (Object.freeze || Object)({\n\tparse: parse,\n\tlift: lift,\n\ttoHex: toHex,\n\tfastLerp: fastLerp,\n\tfastMapToColor: fastMapToColor,\n\tlerp: lerp$1,\n\tmapToColor: mapToColor,\n\tmodifyHSL: modifyHSL,\n\tmodifyAlpha: modifyAlpha,\n\tstringify: stringify\n});\n\n/**\n * @module echarts/animation/Animator\n */\n\nvar arraySlice = Array.prototype.slice;\n\nfunction defaultGetter(target, key) {\n    return target[key];\n}\n\nfunction defaultSetter(target, key, value) {\n    target[key] = value;\n}\n\n/**\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} percent\n * @return {number}\n */\nfunction interpolateNumber(p0, p1, percent) {\n    return (p1 - p0) * percent + p0;\n}\n\n/**\n * @param  {string} p0\n * @param  {string} p1\n * @param  {number} percent\n * @return {string}\n */\nfunction interpolateString(p0, p1, percent) {\n    return percent > 0.5 ? p1 : p0;\n}\n\n/**\n * @param  {Array} p0\n * @param  {Array} p1\n * @param  {number} percent\n * @param  {Array} out\n * @param  {number} arrDim\n */\nfunction interpolateArray(p0, p1, percent, out, arrDim) {\n    var len = p0.length;\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            out[i] = interpolateNumber(p0[i], p1[i], percent);\n        }\n    }\n    else {\n        var len2 = len && p0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                out[i][j] = interpolateNumber(\n                    p0[i][j], p1[i][j], percent\n                );\n            }\n        }\n    }\n}\n\n// arr0 is source array, arr1 is target array.\n// Do some preprocess to avoid error happened when interpolating from arr0 to arr1\nfunction fillArr(arr0, arr1, arrDim) {\n    var arr0Len = arr0.length;\n    var arr1Len = arr1.length;\n    if (arr0Len !== arr1Len) {\n        // FIXME Not work for TypedArray\n        var isPreviousLarger = arr0Len > arr1Len;\n        if (isPreviousLarger) {\n            // Cut the previous\n            arr0.length = arr1Len;\n        }\n        else {\n            // Fill the previous\n            for (var i = arr0Len; i < arr1Len; i++) {\n                arr0.push(\n                    arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i])\n                );\n            }\n        }\n    }\n    // Handling NaN value\n    var len2 = arr0[0] && arr0[0].length;\n    for (var i = 0; i < arr0.length; i++) {\n        if (arrDim === 1) {\n            if (isNaN(arr0[i])) {\n                arr0[i] = arr1[i];\n            }\n        }\n        else {\n            for (var j = 0; j < len2; j++) {\n                if (isNaN(arr0[i][j])) {\n                    arr0[i][j] = arr1[i][j];\n                }\n            }\n        }\n    }\n}\n\n/**\n * @param  {Array} arr0\n * @param  {Array} arr1\n * @param  {number} arrDim\n * @return {boolean}\n */\nfunction isArraySame(arr0, arr1, arrDim) {\n    if (arr0 === arr1) {\n        return true;\n    }\n    var len = arr0.length;\n    if (len !== arr1.length) {\n        return false;\n    }\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            if (arr0[i] !== arr1[i]) {\n                return false;\n            }\n        }\n    }\n    else {\n        var len2 = arr0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                if (arr0[i][j] !== arr1[i][j]) {\n                    return false;\n                }\n            }\n        }\n    }\n    return true;\n}\n\n/**\n * Catmull Rom interpolate array\n * @param  {Array} p0\n * @param  {Array} p1\n * @param  {Array} p2\n * @param  {Array} p3\n * @param  {number} t\n * @param  {number} t2\n * @param  {number} t3\n * @param  {Array} out\n * @param  {number} arrDim\n */\nfunction catmullRomInterpolateArray(\n    p0, p1, p2, p3, t, t2, t3, out, arrDim\n) {\n    var len = p0.length;\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            out[i] = catmullRomInterpolate(\n                p0[i], p1[i], p2[i], p3[i], t, t2, t3\n            );\n        }\n    }\n    else {\n        var len2 = p0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                out[i][j] = catmullRomInterpolate(\n                    p0[i][j], p1[i][j], p2[i][j], p3[i][j],\n                    t, t2, t3\n                );\n            }\n        }\n    }\n}\n\n/**\n * Catmull Rom interpolate number\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @param  {number} t2\n * @param  {number} t3\n * @return {number}\n */\nfunction catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {\n    var v0 = (p2 - p0) * 0.5;\n    var v1 = (p3 - p1) * 0.5;\n    return (2 * (p1 - p2) + v0 + v1) * t3\n            + (-3 * (p1 - p2) - 2 * v0 - v1) * t2\n            + v0 * t + p1;\n}\n\nfunction cloneValue(value) {\n    if (isArrayLike(value)) {\n        var len = value.length;\n        if (isArrayLike(value[0])) {\n            var ret = [];\n            for (var i = 0; i < len; i++) {\n                ret.push(arraySlice.call(value[i]));\n            }\n            return ret;\n        }\n\n        return arraySlice.call(value);\n    }\n\n    return value;\n}\n\nfunction rgba2String(rgba) {\n    rgba[0] = Math.floor(rgba[0]);\n    rgba[1] = Math.floor(rgba[1]);\n    rgba[2] = Math.floor(rgba[2]);\n\n    return 'rgba(' + rgba.join(',') + ')';\n}\n\nfunction getArrayDim(keyframes) {\n    var lastValue = keyframes[keyframes.length - 1].value;\n    return isArrayLike(lastValue && lastValue[0]) ? 2 : 1;\n}\n\nfunction createTrackClip(animator, easing, oneTrackDone, keyframes, propName, forceAnimate) {\n    var getter = animator._getter;\n    var setter = animator._setter;\n    var useSpline = easing === 'spline';\n\n    var trackLen = keyframes.length;\n    if (!trackLen) {\n        return;\n    }\n    // Guess data type\n    var firstVal = keyframes[0].value;\n    var isValueArray = isArrayLike(firstVal);\n    var isValueColor = false;\n    var isValueString = false;\n\n    // For vertices morphing\n    var arrDim = isValueArray ? getArrayDim(keyframes) : 0;\n\n    var trackMaxTime;\n    // Sort keyframe as ascending\n    keyframes.sort(function (a, b) {\n        return a.time - b.time;\n    });\n\n    trackMaxTime = keyframes[trackLen - 1].time;\n    // Percents of each keyframe\n    var kfPercents = [];\n    // Value of each keyframe\n    var kfValues = [];\n    var prevValue = keyframes[0].value;\n    var isAllValueEqual = true;\n    for (var i = 0; i < trackLen; i++) {\n        kfPercents.push(keyframes[i].time / trackMaxTime);\n        // Assume value is a color when it is a string\n        var value = keyframes[i].value;\n\n        // Check if value is equal, deep check if value is array\n        if (!((isValueArray && isArraySame(value, prevValue, arrDim))\n            || (!isValueArray && value === prevValue))) {\n            isAllValueEqual = false;\n        }\n        prevValue = value;\n\n        // Try converting a string to a color array\n        if (typeof value === 'string') {\n            var colorArray = parse(value);\n            if (colorArray) {\n                value = colorArray;\n                isValueColor = true;\n            }\n            else {\n                isValueString = true;\n            }\n        }\n        kfValues.push(value);\n    }\n    if (!forceAnimate && isAllValueEqual) {\n        return;\n    }\n\n    var lastValue = kfValues[trackLen - 1];\n    // Polyfill array and NaN value\n    for (var i = 0; i < trackLen - 1; i++) {\n        if (isValueArray) {\n            fillArr(kfValues[i], lastValue, arrDim);\n        }\n        else {\n            if (isNaN(kfValues[i]) && !isNaN(lastValue) && !isValueString && !isValueColor) {\n                kfValues[i] = lastValue;\n            }\n        }\n    }\n    isValueArray && fillArr(getter(animator._target, propName), lastValue, arrDim);\n\n    // Cache the key of last frame to speed up when\n    // animation playback is sequency\n    var lastFrame = 0;\n    var lastFramePercent = 0;\n    var start;\n    var w;\n    var p0;\n    var p1;\n    var p2;\n    var p3;\n\n    if (isValueColor) {\n        var rgba = [0, 0, 0, 0];\n    }\n\n    var onframe = function (target, percent) {\n        // Find the range keyframes\n        // kf1-----kf2---------current--------kf3\n        // find kf2 and kf3 and do interpolation\n        var frame;\n        // In the easing function like elasticOut, percent may less than 0\n        if (percent < 0) {\n            frame = 0;\n        }\n        else if (percent < lastFramePercent) {\n            // Start from next key\n            // PENDING start from lastFrame ?\n            start = Math.min(lastFrame + 1, trackLen - 1);\n            for (frame = start; frame >= 0; frame--) {\n                if (kfPercents[frame] <= percent) {\n                    break;\n                }\n            }\n            // PENDING really need to do this ?\n            frame = Math.min(frame, trackLen - 2);\n        }\n        else {\n            for (frame = lastFrame; frame < trackLen; frame++) {\n                if (kfPercents[frame] > percent) {\n                    break;\n                }\n            }\n            frame = Math.min(frame - 1, trackLen - 2);\n        }\n        lastFrame = frame;\n        lastFramePercent = percent;\n\n        var range = (kfPercents[frame + 1] - kfPercents[frame]);\n        if (range === 0) {\n            return;\n        }\n        else {\n            w = (percent - kfPercents[frame]) / range;\n        }\n        if (useSpline) {\n            p1 = kfValues[frame];\n            p0 = kfValues[frame === 0 ? frame : frame - 1];\n            p2 = kfValues[frame > trackLen - 2 ? trackLen - 1 : frame + 1];\n            p3 = kfValues[frame > trackLen - 3 ? trackLen - 1 : frame + 2];\n            if (isValueArray) {\n                catmullRomInterpolateArray(\n                    p0, p1, p2, p3, w, w * w, w * w * w,\n                    getter(target, propName),\n                    arrDim\n                );\n            }\n            else {\n                var value;\n                if (isValueColor) {\n                    value = catmullRomInterpolateArray(\n                        p0, p1, p2, p3, w, w * w, w * w * w,\n                        rgba, 1\n                    );\n                    value = rgba2String(rgba);\n                }\n                else if (isValueString) {\n                    // String is step(0.5)\n                    return interpolateString(p1, p2, w);\n                }\n                else {\n                    value = catmullRomInterpolate(\n                        p0, p1, p2, p3, w, w * w, w * w * w\n                    );\n                }\n                setter(\n                    target,\n                    propName,\n                    value\n                );\n            }\n        }\n        else {\n            if (isValueArray) {\n                interpolateArray(\n                    kfValues[frame], kfValues[frame + 1], w,\n                    getter(target, propName),\n                    arrDim\n                );\n            }\n            else {\n                var value;\n                if (isValueColor) {\n                    interpolateArray(\n                        kfValues[frame], kfValues[frame + 1], w,\n                        rgba, 1\n                    );\n                    value = rgba2String(rgba);\n                }\n                else if (isValueString) {\n                    // String is step(0.5)\n                    return interpolateString(kfValues[frame], kfValues[frame + 1], w);\n                }\n                else {\n                    value = interpolateNumber(kfValues[frame], kfValues[frame + 1], w);\n                }\n                setter(\n                    target,\n                    propName,\n                    value\n                );\n            }\n        }\n    };\n\n    var clip = new Clip({\n        target: animator._target,\n        life: trackMaxTime,\n        loop: animator._loop,\n        delay: animator._delay,\n        onframe: onframe,\n        ondestroy: oneTrackDone\n    });\n\n    if (easing && easing !== 'spline') {\n        clip.easing = easing;\n    }\n\n    return clip;\n}\n\n/**\n * @alias module:zrender/animation/Animator\n * @constructor\n * @param {Object} target\n * @param {boolean} loop\n * @param {Function} getter\n * @param {Function} setter\n */\nvar Animator = function (target, loop, getter, setter) {\n    this._tracks = {};\n    this._target = target;\n\n    this._loop = loop || false;\n\n    this._getter = getter || defaultGetter;\n    this._setter = setter || defaultSetter;\n\n    this._clipCount = 0;\n\n    this._delay = 0;\n\n    this._doneList = [];\n\n    this._onframeList = [];\n\n    this._clipList = [];\n};\n\nAnimator.prototype = {\n    /**\n     * 设置动画关键帧\n     * @param  {number} time 关键帧时间，单位是ms\n     * @param  {Object} props 关键帧的属性值，key-value表示\n     * @return {module:zrender/animation/Animator}\n     */\n    when: function (time /* ms */, props) {\n        var tracks = this._tracks;\n        for (var propName in props) {\n            if (!props.hasOwnProperty(propName)) {\n                continue;\n            }\n\n            if (!tracks[propName]) {\n                tracks[propName] = [];\n                // Invalid value\n                var value = this._getter(this._target, propName);\n                if (value == null) {\n                    // zrLog('Invalid property ' + propName);\n                    continue;\n                }\n                // If time is 0\n                //  Then props is given initialize value\n                // Else\n                //  Initialize value from current prop value\n                if (time !== 0) {\n                    tracks[propName].push({\n                        time: 0,\n                        value: cloneValue(value)\n                    });\n                }\n            }\n            tracks[propName].push({\n                time: time,\n                value: props[propName]\n            });\n        }\n        return this;\n    },\n    /**\n     * 添加动画每一帧的回调函数\n     * @param  {Function} callback\n     * @return {module:zrender/animation/Animator}\n     */\n    during: function (callback) {\n        this._onframeList.push(callback);\n        return this;\n    },\n\n    pause: function () {\n        for (var i = 0; i < this._clipList.length; i++) {\n            this._clipList[i].pause();\n        }\n        this._paused = true;\n    },\n\n    resume: function () {\n        for (var i = 0; i < this._clipList.length; i++) {\n            this._clipList[i].resume();\n        }\n        this._paused = false;\n    },\n\n    isPaused: function () {\n        return !!this._paused;\n    },\n\n    _doneCallback: function () {\n        // Clear all tracks\n        this._tracks = {};\n        // Clear all clips\n        this._clipList.length = 0;\n\n        var doneList = this._doneList;\n        var len = doneList.length;\n        for (var i = 0; i < len; i++) {\n            doneList[i].call(this);\n        }\n    },\n    /**\n     * 开始执行动画\n     * @param  {string|Function} [easing]\n     *         动画缓动函数，详见{@link module:zrender/animation/easing}\n     * @param  {boolean} forceAnimate\n     * @return {module:zrender/animation/Animator}\n     */\n    start: function (easing, forceAnimate) {\n\n        var self = this;\n        var clipCount = 0;\n\n        var oneTrackDone = function () {\n            clipCount--;\n            if (!clipCount) {\n                self._doneCallback();\n            }\n        };\n\n        var lastClip;\n        for (var propName in this._tracks) {\n            if (!this._tracks.hasOwnProperty(propName)) {\n                continue;\n            }\n            var clip = createTrackClip(\n                this, easing, oneTrackDone,\n                this._tracks[propName], propName, forceAnimate\n            );\n            if (clip) {\n                this._clipList.push(clip);\n                clipCount++;\n\n                // If start after added to animation\n                if (this.animation) {\n                    this.animation.addClip(clip);\n                }\n\n                lastClip = clip;\n            }\n        }\n\n        // Add during callback on the last clip\n        if (lastClip) {\n            var oldOnFrame = lastClip.onframe;\n            lastClip.onframe = function (target, percent) {\n                oldOnFrame(target, percent);\n\n                for (var i = 0; i < self._onframeList.length; i++) {\n                    self._onframeList[i](target, percent);\n                }\n            };\n        }\n\n        // This optimization will help the case that in the upper application\n        // the view may be refreshed frequently, where animation will be\n        // called repeatly but nothing changed.\n        if (!clipCount) {\n            this._doneCallback();\n        }\n        return this;\n    },\n    /**\n     * 停止动画\n     * @param {boolean} forwardToLast If move to last frame before stop\n     */\n    stop: function (forwardToLast) {\n        var clipList = this._clipList;\n        var animation = this.animation;\n        for (var i = 0; i < clipList.length; i++) {\n            var clip = clipList[i];\n            if (forwardToLast) {\n                // Move to last frame before stop\n                clip.onframe(this._target, 1);\n            }\n            animation && animation.removeClip(clip);\n        }\n        clipList.length = 0;\n    },\n    /**\n     * 设置动画延迟开始的时间\n     * @param  {number} time 单位ms\n     * @return {module:zrender/animation/Animator}\n     */\n    delay: function (time) {\n        this._delay = time;\n        return this;\n    },\n    /**\n     * 添加动画结束的回调\n     * @param  {Function} cb\n     * @return {module:zrender/animation/Animator}\n     */\n    done: function (cb) {\n        if (cb) {\n            this._doneList.push(cb);\n        }\n        return this;\n    },\n\n    /**\n     * @return {Array.<module:zrender/animation/Clip>}\n     */\n    getClips: function () {\n        return this._clipList;\n    }\n};\n\nvar dpr = 1;\n\n// If in browser environment\nif (typeof window !== 'undefined') {\n    dpr = Math.max(window.devicePixelRatio || 1, 1);\n}\n\n/**\n * config默认配置项\n * @exports zrender/config\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n */\n\n/**\n * debug日志选项：catchBrushException为true下有效\n * 0 : 不生成debug数据，发布用\n * 1 : 异常抛出，调试用\n * 2 : 控制台输出，调试用\n */\nvar debugMode = 0;\n\n// retina 屏幕优化\nvar devicePixelRatio = dpr;\n\nvar log = function () {\n};\n\nif (debugMode === 1) {\n    log = function () {\n        for (var k in arguments) {\n            throw new Error(arguments[k]);\n        }\n    };\n}\nelse if (debugMode > 1) {\n    log = function () {\n        for (var k in arguments) {\n            console.log(arguments[k]);\n        }\n    };\n}\n\nvar zrLog = log;\n\n/**\n * @alias modue:zrender/mixin/Animatable\n * @constructor\n */\nvar Animatable = function () {\n\n    /**\n     * @type {Array.<module:zrender/animation/Animator>}\n     * @readOnly\n     */\n    this.animators = [];\n};\n\nAnimatable.prototype = {\n\n    constructor: Animatable,\n\n    /**\n     * 动画\n     *\n     * @param {string} path The path to fetch value from object, like 'a.b.c'.\n     * @param {boolean} [loop] Whether to loop animation.\n     * @return {module:zrender/animation/Animator}\n     * @example:\n     *     el.animate('style', false)\n     *         .when(1000, {x: 10} )\n     *         .done(function(){ // Animation done })\n     *         .start()\n     */\n    animate: function (path, loop) {\n        var target;\n        var animatingShape = false;\n        var el = this;\n        var zr = this.__zr;\n        if (path) {\n            var pathSplitted = path.split('.');\n            var prop = el;\n            // If animating shape\n            animatingShape = pathSplitted[0] === 'shape';\n            for (var i = 0, l = pathSplitted.length; i < l; i++) {\n                if (!prop) {\n                    continue;\n                }\n                prop = prop[pathSplitted[i]];\n            }\n            if (prop) {\n                target = prop;\n            }\n        }\n        else {\n            target = el;\n        }\n\n        if (!target) {\n            zrLog(\n                'Property \"'\n                + path\n                + '\" is not existed in element '\n                + el.id\n            );\n            return;\n        }\n\n        var animators = el.animators;\n\n        var animator = new Animator(target, loop);\n\n        animator.during(function (target) {\n            el.dirty(animatingShape);\n        })\n        .done(function () {\n            // FIXME Animator will not be removed if use `Animator#stop` to stop animation\n            animators.splice(indexOf(animators, animator), 1);\n        });\n\n        animators.push(animator);\n\n        // If animate after added to the zrender\n        if (zr) {\n            zr.animation.addAnimator(animator);\n        }\n\n        return animator;\n    },\n\n    /**\n     * 停止动画\n     * @param {boolean} forwardToLast If move to last frame before stop\n     */\n    stopAnimation: function (forwardToLast) {\n        var animators = this.animators;\n        var len = animators.length;\n        for (var i = 0; i < len; i++) {\n            animators[i].stop(forwardToLast);\n        }\n        animators.length = 0;\n\n        return this;\n    },\n\n    /**\n     * Caution: this method will stop previous animation.\n     * So do not use this method to one element twice before\n     * animation starts, unless you know what you are doing.\n     * @param {Object} target\n     * @param {number} [time=500] Time in ms\n     * @param {string} [easing='linear']\n     * @param {number} [delay=0]\n     * @param {Function} [callback]\n     * @param {Function} [forceAnimate] Prevent stop animation and callback\n     *        immediently when target values are the same as current values.\n     *\n     * @example\n     *  // Animate position\n     *  el.animateTo({\n     *      position: [10, 10]\n     *  }, function () { // done })\n     *\n     *  // Animate shape, style and position in 100ms, delayed 100ms, with cubicOut easing\n     *  el.animateTo({\n     *      shape: {\n     *          width: 500\n     *      },\n     *      style: {\n     *          fill: 'red'\n     *      }\n     *      position: [10, 10]\n     *  }, 100, 100, 'cubicOut', function () { // done })\n     */\n    // TODO Return animation key\n    animateTo: function (target, time, delay, easing, callback, forceAnimate) {\n        animateTo(this, target, time, delay, easing, callback, forceAnimate);\n    },\n\n    /**\n     * Animate from the target state to current state.\n     * The params and the return value are the same as `this.animateTo`.\n     */\n    animateFrom: function (target, time, delay, easing, callback, forceAnimate) {\n        animateTo(this, target, time, delay, easing, callback, forceAnimate, true);\n    }\n};\n\nfunction animateTo(animatable, target, time, delay, easing, callback, forceAnimate, reverse) {\n    // animateTo(target, time, easing, callback);\n    if (isString(delay)) {\n        callback = easing;\n        easing = delay;\n        delay = 0;\n    }\n    // animateTo(target, time, delay, callback);\n    else if (isFunction$1(easing)) {\n        callback = easing;\n        easing = 'linear';\n        delay = 0;\n    }\n    // animateTo(target, time, callback);\n    else if (isFunction$1(delay)) {\n        callback = delay;\n        delay = 0;\n    }\n    // animateTo(target, callback)\n    else if (isFunction$1(time)) {\n        callback = time;\n        time = 500;\n    }\n    // animateTo(target)\n    else if (!time) {\n        time = 500;\n    }\n    // Stop all previous animations\n    animatable.stopAnimation();\n    animateToShallow(animatable, '', animatable, target, time, delay, reverse);\n\n    // Animators may be removed immediately after start\n    // if there is nothing to animate\n    var animators = animatable.animators.slice();\n    var count = animators.length;\n    function done() {\n        count--;\n        if (!count) {\n            callback && callback();\n        }\n    }\n\n    // No animators. This should be checked before animators[i].start(),\n    // because 'done' may be executed immediately if no need to animate.\n    if (!count) {\n        callback && callback();\n    }\n    // Start after all animators created\n    // Incase any animator is done immediately when all animation properties are not changed\n    for (var i = 0; i < animators.length; i++) {\n        animators[i]\n            .done(done)\n            .start(easing, forceAnimate);\n    }\n}\n\n/**\n * @param {string} path=''\n * @param {Object} source=animatable\n * @param {Object} target\n * @param {number} [time=500]\n * @param {number} [delay=0]\n * @param {boolean} [reverse] If `true`, animate\n *        from the `target` to current state.\n *\n * @example\n *  // Animate position\n *  el._animateToShallow({\n *      position: [10, 10]\n *  })\n *\n *  // Animate shape, style and position in 100ms, delayed 100ms\n *  el._animateToShallow({\n *      shape: {\n *          width: 500\n *      },\n *      style: {\n *          fill: 'red'\n *      }\n *      position: [10, 10]\n *  }, 100, 100)\n */\nfunction animateToShallow(animatable, path, source, target, time, delay, reverse) {\n    var objShallow = {};\n    var propertyCount = 0;\n    for (var name in target) {\n        if (!target.hasOwnProperty(name)) {\n            continue;\n        }\n\n        if (source[name] != null) {\n            if (isObject$1(target[name]) && !isArrayLike(target[name])) {\n                animateToShallow(\n                    animatable,\n                    path ? path + '.' + name : name,\n                    source[name],\n                    target[name],\n                    time,\n                    delay,\n                    reverse\n                );\n            }\n            else {\n                if (reverse) {\n                    objShallow[name] = source[name];\n                    setAttrByPath(animatable, path, name, target[name]);\n                }\n                else {\n                    objShallow[name] = target[name];\n                }\n                propertyCount++;\n            }\n        }\n        else if (target[name] != null && !reverse) {\n            setAttrByPath(animatable, path, name, target[name]);\n        }\n    }\n\n    if (propertyCount > 0) {\n        animatable.animate(path, false)\n            .when(time == null ? 500 : time, objShallow)\n            .delay(delay || 0);\n    }\n}\n\nfunction setAttrByPath(el, path, name, value) {\n    // Attr directly if not has property\n    // FIXME, if some property not needed for element ?\n    if (!path) {\n        el.attr(name, value);\n    }\n    else {\n        // Only support set shape or style\n        var props = {};\n        props[path] = {};\n        props[path][name] = value;\n        el.attr(props);\n    }\n}\n\n/**\n * @alias module:zrender/Element\n * @constructor\n * @extends {module:zrender/mixin/Animatable}\n * @extends {module:zrender/mixin/Transformable}\n * @extends {module:zrender/mixin/Eventful}\n */\nvar Element = function (opts) { // jshint ignore:line\n\n    Transformable.call(this, opts);\n    Eventful.call(this, opts);\n    Animatable.call(this, opts);\n\n    /**\n     * 画布元素ID\n     * @type {string}\n     */\n    this.id = opts.id || guid();\n};\n\nElement.prototype = {\n\n    /**\n     * 元素类型\n     * Element type\n     * @type {string}\n     */\n    type: 'element',\n\n    /**\n     * 元素名字\n     * Element name\n     * @type {string}\n     */\n    name: '',\n\n    /**\n     * ZRender 实例对象，会在 element 添加到 zrender 实例中后自动赋值\n     * ZRender instance will be assigned when element is associated with zrender\n     * @name module:/zrender/Element#__zr\n     * @type {module:zrender/ZRender}\n     */\n    __zr: null,\n\n    /**\n     * 图形是否忽略，为true时忽略图形的绘制以及事件触发\n     * If ignore drawing and events of the element object\n     * @name module:/zrender/Element#ignore\n     * @type {boolean}\n     * @default false\n     */\n    ignore: false,\n\n    /**\n     * 用于裁剪的路径(shape)，所有 Group 内的路径在绘制时都会被这个路径裁剪\n     * 该路径会继承被裁减对象的变换\n     * @type {module:zrender/graphic/Path}\n     * @see http://www.w3.org/TR/2dcontext/#clipping-region\n     * @readOnly\n     */\n    clipPath: null,\n\n    /**\n     * 是否是 Group\n     * @type {boolean}\n     */\n    isGroup: false,\n\n    /**\n     * Drift element\n     * @param  {number} dx dx on the global space\n     * @param  {number} dy dy on the global space\n     */\n    drift: function (dx, dy) {\n        switch (this.draggable) {\n            case 'horizontal':\n                dy = 0;\n                break;\n            case 'vertical':\n                dx = 0;\n                break;\n        }\n\n        var m = this.transform;\n        if (!m) {\n            m = this.transform = [1, 0, 0, 1, 0, 0];\n        }\n        m[4] += dx;\n        m[5] += dy;\n\n        this.decomposeTransform();\n        this.dirty(false);\n    },\n\n    /**\n     * Hook before update\n     */\n    beforeUpdate: function () {},\n    /**\n     * Hook after update\n     */\n    afterUpdate: function () {},\n    /**\n     * Update each frame\n     */\n    update: function () {\n        this.updateTransform();\n    },\n\n    /**\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {},\n\n    /**\n     * @protected\n     */\n    attrKV: function (key, value) {\n        if (key === 'position' || key === 'scale' || key === 'origin') {\n            // Copy the array\n            if (value) {\n                var target = this[key];\n                if (!target) {\n                    target = this[key] = [];\n                }\n                target[0] = value[0];\n                target[1] = value[1];\n            }\n        }\n        else {\n            this[key] = value;\n        }\n    },\n\n    /**\n     * Hide the element\n     */\n    hide: function () {\n        this.ignore = true;\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * Show the element\n     */\n    show: function () {\n        this.ignore = false;\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * @param {string|Object} key\n     * @param {*} value\n     */\n    attr: function (key, value) {\n        if (typeof key === 'string') {\n            this.attrKV(key, value);\n        }\n        else if (isObject$1(key)) {\n            for (var name in key) {\n                if (key.hasOwnProperty(name)) {\n                    this.attrKV(name, key[name]);\n                }\n            }\n        }\n\n        this.dirty(false);\n\n        return this;\n    },\n\n    /**\n     * @param {module:zrender/graphic/Path} clipPath\n     */\n    setClipPath: function (clipPath) {\n        var zr = this.__zr;\n        if (zr) {\n            clipPath.addSelfToZr(zr);\n        }\n\n        // Remove previous clip path\n        if (this.clipPath && this.clipPath !== clipPath) {\n            this.removeClipPath();\n        }\n\n        this.clipPath = clipPath;\n        clipPath.__zr = zr;\n        clipPath.__clipTarget = this;\n\n        this.dirty(false);\n    },\n\n    /**\n     */\n    removeClipPath: function () {\n        var clipPath = this.clipPath;\n        if (clipPath) {\n            if (clipPath.__zr) {\n                clipPath.removeSelfFromZr(clipPath.__zr);\n            }\n\n            clipPath.__zr = null;\n            clipPath.__clipTarget = null;\n            this.clipPath = null;\n\n            this.dirty(false);\n        }\n    },\n\n    /**\n     * Add self from zrender instance.\n     * Not recursively because it will be invoked when element added to storage.\n     * @param {module:zrender/ZRender} zr\n     */\n    addSelfToZr: function (zr) {\n        this.__zr = zr;\n        // 添加动画\n        var animators = this.animators;\n        if (animators) {\n            for (var i = 0; i < animators.length; i++) {\n                zr.animation.addAnimator(animators[i]);\n            }\n        }\n\n        if (this.clipPath) {\n            this.clipPath.addSelfToZr(zr);\n        }\n    },\n\n    /**\n     * Remove self from zrender instance.\n     * Not recursively because it will be invoked when element added to storage.\n     * @param {module:zrender/ZRender} zr\n     */\n    removeSelfFromZr: function (zr) {\n        this.__zr = null;\n        // 移除动画\n        var animators = this.animators;\n        if (animators) {\n            for (var i = 0; i < animators.length; i++) {\n                zr.animation.removeAnimator(animators[i]);\n            }\n        }\n\n        if (this.clipPath) {\n            this.clipPath.removeSelfFromZr(zr);\n        }\n    }\n};\n\nmixin(Element, Animatable);\nmixin(Element, Transformable);\nmixin(Element, Eventful);\n\n/**\n * @module echarts/core/BoundingRect\n */\n\nvar v2ApplyTransform = applyTransform;\nvar mathMin = Math.min;\nvar mathMax = Math.max;\n\n/**\n * @alias module:echarts/core/BoundingRect\n */\nfunction BoundingRect(x, y, width, height) {\n\n    if (width < 0) {\n        x = x + width;\n        width = -width;\n    }\n    if (height < 0) {\n        y = y + height;\n        height = -height;\n    }\n\n    /**\n     * @type {number}\n     */\n    this.x = x;\n    /**\n     * @type {number}\n     */\n    this.y = y;\n    /**\n     * @type {number}\n     */\n    this.width = width;\n    /**\n     * @type {number}\n     */\n    this.height = height;\n}\n\nBoundingRect.prototype = {\n\n    constructor: BoundingRect,\n\n    /**\n     * @param {module:echarts/core/BoundingRect} other\n     */\n    union: function (other) {\n        var x = mathMin(other.x, this.x);\n        var y = mathMin(other.y, this.y);\n\n        this.width = mathMax(\n                other.x + other.width,\n                this.x + this.width\n            ) - x;\n        this.height = mathMax(\n                other.y + other.height,\n                this.y + this.height\n            ) - y;\n        this.x = x;\n        this.y = y;\n    },\n\n    /**\n     * @param {Array.<number>} m\n     * @methods\n     */\n    applyTransform: (function () {\n        var lt = [];\n        var rb = [];\n        var lb = [];\n        var rt = [];\n        return function (m) {\n            // In case usage like this\n            // el.getBoundingRect().applyTransform(el.transform)\n            // And element has no transform\n            if (!m) {\n                return;\n            }\n            lt[0] = lb[0] = this.x;\n            lt[1] = rt[1] = this.y;\n            rb[0] = rt[0] = this.x + this.width;\n            rb[1] = lb[1] = this.y + this.height;\n\n            v2ApplyTransform(lt, lt, m);\n            v2ApplyTransform(rb, rb, m);\n            v2ApplyTransform(lb, lb, m);\n            v2ApplyTransform(rt, rt, m);\n\n            this.x = mathMin(lt[0], rb[0], lb[0], rt[0]);\n            this.y = mathMin(lt[1], rb[1], lb[1], rt[1]);\n            var maxX = mathMax(lt[0], rb[0], lb[0], rt[0]);\n            var maxY = mathMax(lt[1], rb[1], lb[1], rt[1]);\n            this.width = maxX - this.x;\n            this.height = maxY - this.y;\n        };\n    })(),\n\n    /**\n     * Calculate matrix of transforming from self to target rect\n     * @param  {module:zrender/core/BoundingRect} b\n     * @return {Array.<number>}\n     */\n    calculateTransform: function (b) {\n        var a = this;\n        var sx = b.width / a.width;\n        var sy = b.height / a.height;\n\n        var m = create$1();\n\n        // 矩阵右乘\n        translate(m, m, [-a.x, -a.y]);\n        scale$1(m, m, [sx, sy]);\n        translate(m, m, [b.x, b.y]);\n\n        return m;\n    },\n\n    /**\n     * @param {(module:echarts/core/BoundingRect|Object)} b\n     * @return {boolean}\n     */\n    intersect: function (b) {\n        if (!b) {\n            return false;\n        }\n\n        if (!(b instanceof BoundingRect)) {\n            // Normalize negative width/height.\n            b = BoundingRect.create(b);\n        }\n\n        var a = this;\n        var ax0 = a.x;\n        var ax1 = a.x + a.width;\n        var ay0 = a.y;\n        var ay1 = a.y + a.height;\n\n        var bx0 = b.x;\n        var bx1 = b.x + b.width;\n        var by0 = b.y;\n        var by1 = b.y + b.height;\n\n        return !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);\n    },\n\n    contain: function (x, y) {\n        var rect = this;\n        return x >= rect.x\n            && x <= (rect.x + rect.width)\n            && y >= rect.y\n            && y <= (rect.y + rect.height);\n    },\n\n    /**\n     * @return {module:echarts/core/BoundingRect}\n     */\n    clone: function () {\n        return new BoundingRect(this.x, this.y, this.width, this.height);\n    },\n\n    /**\n     * Copy from another rect\n     */\n    copy: function (other) {\n        this.x = other.x;\n        this.y = other.y;\n        this.width = other.width;\n        this.height = other.height;\n    },\n\n    plain: function () {\n        return {\n            x: this.x,\n            y: this.y,\n            width: this.width,\n            height: this.height\n        };\n    }\n};\n\n/**\n * @param {Object|module:zrender/core/BoundingRect} rect\n * @param {number} rect.x\n * @param {number} rect.y\n * @param {number} rect.width\n * @param {number} rect.height\n * @return {module:zrender/core/BoundingRect}\n */\nBoundingRect.create = function (rect) {\n    return new BoundingRect(rect.x, rect.y, rect.width, rect.height);\n};\n\n/**\n * Group是一个容器，可以插入子节点，Group的变换也会被应用到子节点上\n * @module zrender/graphic/Group\n * @example\n *     var Group = require('zrender/container/Group');\n *     var Circle = require('zrender/graphic/shape/Circle');\n *     var g = new Group();\n *     g.position[0] = 100;\n *     g.position[1] = 100;\n *     g.add(new Circle({\n *         style: {\n *             x: 100,\n *             y: 100,\n *             r: 20,\n *         }\n *     }));\n *     zr.add(g);\n */\n\n/**\n * @alias module:zrender/graphic/Group\n * @constructor\n * @extends module:zrender/mixin/Transformable\n * @extends module:zrender/mixin/Eventful\n */\nvar Group = function (opts) {\n\n    opts = opts || {};\n\n    Element.call(this, opts);\n\n    for (var key in opts) {\n        if (opts.hasOwnProperty(key)) {\n            this[key] = opts[key];\n        }\n    }\n\n    this._children = [];\n\n    this.__storage = null;\n\n    this.__dirty = true;\n};\n\nGroup.prototype = {\n\n    constructor: Group,\n\n    isGroup: true,\n\n    /**\n     * @type {string}\n     */\n    type: 'group',\n\n    /**\n     * 所有子孙元素是否响应鼠标事件\n     * @name module:/zrender/container/Group#silent\n     * @type {boolean}\n     * @default false\n     */\n    silent: false,\n\n    /**\n     * @return {Array.<module:zrender/Element>}\n     */\n    children: function () {\n        return this._children.slice();\n    },\n\n    /**\n     * 获取指定 index 的儿子节点\n     * @param  {number} idx\n     * @return {module:zrender/Element}\n     */\n    childAt: function (idx) {\n        return this._children[idx];\n    },\n\n    /**\n     * 获取指定名字的儿子节点\n     * @param  {string} name\n     * @return {module:zrender/Element}\n     */\n    childOfName: function (name) {\n        var children = this._children;\n        for (var i = 0; i < children.length; i++) {\n            if (children[i].name === name) {\n                return children[i];\n            }\n            }\n    },\n\n    /**\n     * @return {number}\n     */\n    childCount: function () {\n        return this._children.length;\n    },\n\n    /**\n     * 添加子节点到最后\n     * @param {module:zrender/Element} child\n     */\n    add: function (child) {\n        if (child && child !== this && child.parent !== this) {\n\n            this._children.push(child);\n\n            this._doAdd(child);\n        }\n\n        return this;\n    },\n\n    /**\n     * 添加子节点在 nextSibling 之前\n     * @param {module:zrender/Element} child\n     * @param {module:zrender/Element} nextSibling\n     */\n    addBefore: function (child, nextSibling) {\n        if (child && child !== this && child.parent !== this\n            && nextSibling && nextSibling.parent === this) {\n\n            var children = this._children;\n            var idx = children.indexOf(nextSibling);\n\n            if (idx >= 0) {\n                children.splice(idx, 0, child);\n                this._doAdd(child);\n            }\n        }\n\n        return this;\n    },\n\n    _doAdd: function (child) {\n        if (child.parent) {\n            child.parent.remove(child);\n        }\n\n        child.parent = this;\n\n        var storage = this.__storage;\n        var zr = this.__zr;\n        if (storage && storage !== child.__storage) {\n\n            storage.addToStorage(child);\n\n            if (child instanceof Group) {\n                child.addChildrenToStorage(storage);\n            }\n        }\n\n        zr && zr.refresh();\n    },\n\n    /**\n     * 移除子节点\n     * @param {module:zrender/Element} child\n     */\n    remove: function (child) {\n        var zr = this.__zr;\n        var storage = this.__storage;\n        var children = this._children;\n\n        var idx = indexOf(children, child);\n        if (idx < 0) {\n            return this;\n        }\n        children.splice(idx, 1);\n\n        child.parent = null;\n\n        if (storage) {\n\n            storage.delFromStorage(child);\n\n            if (child instanceof Group) {\n                child.delChildrenFromStorage(storage);\n            }\n        }\n\n        zr && zr.refresh();\n\n        return this;\n    },\n\n    /**\n     * 移除所有子节点\n     */\n    removeAll: function () {\n        var children = this._children;\n        var storage = this.__storage;\n        var child;\n        var i;\n        for (i = 0; i < children.length; i++) {\n            child = children[i];\n            if (storage) {\n                storage.delFromStorage(child);\n                if (child instanceof Group) {\n                    child.delChildrenFromStorage(storage);\n                }\n            }\n            child.parent = null;\n        }\n        children.length = 0;\n\n        return this;\n    },\n\n    /**\n     * 遍历所有子节点\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    eachChild: function (cb, context) {\n        var children = this._children;\n        for (var i = 0; i < children.length; i++) {\n            var child = children[i];\n            cb.call(context, child, i);\n        }\n        return this;\n    },\n\n    /**\n     * 深度优先遍历所有子孙节点\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            cb.call(context, child);\n\n            if (child.type === 'group') {\n                child.traverse(cb, context);\n            }\n        }\n        return this;\n    },\n\n    addChildrenToStorage: function (storage) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            storage.addToStorage(child);\n            if (child instanceof Group) {\n                child.addChildrenToStorage(storage);\n            }\n        }\n    },\n\n    delChildrenFromStorage: function (storage) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            storage.delFromStorage(child);\n            if (child instanceof Group) {\n                child.delChildrenFromStorage(storage);\n            }\n        }\n    },\n\n    dirty: function () {\n        this.__dirty = true;\n        this.__zr && this.__zr.refresh();\n        return this;\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function (includeChildren) {\n        // TODO Caching\n        var rect = null;\n        var tmpRect = new BoundingRect(0, 0, 0, 0);\n        var children = includeChildren || this._children;\n        var tmpMat = [];\n\n        for (var i = 0; i < children.length; i++) {\n            var child = children[i];\n            if (child.ignore || child.invisible) {\n                continue;\n            }\n\n            var childRect = child.getBoundingRect();\n            var transform = child.getLocalTransform(tmpMat);\n            // TODO\n            // The boundingRect cacluated by transforming original\n            // rect may be bigger than the actual bundingRect when rotation\n            // is used. (Consider a circle rotated aginst its center, where\n            // the actual boundingRect should be the same as that not be\n            // rotated.) But we can not find better approach to calculate\n            // actual boundingRect yet, considering performance.\n            if (transform) {\n                tmpRect.copy(childRect);\n                tmpRect.applyTransform(transform);\n                rect = rect || tmpRect.clone();\n                rect.union(tmpRect);\n            }\n            else {\n                rect = rect || childRect.clone();\n                rect.union(childRect);\n            }\n        }\n        return rect || tmpRect;\n    }\n};\n\ninherits(Group, Element);\n\n// https://github.com/mziccard/node-timsort\nvar DEFAULT_MIN_MERGE = 32;\n\nvar DEFAULT_MIN_GALLOPING = 7;\n\nfunction minRunLength(n) {\n    var r = 0;\n\n    while (n >= DEFAULT_MIN_MERGE) {\n        r |= n & 1;\n        n >>= 1;\n    }\n\n    return n + r;\n}\n\nfunction makeAscendingRun(array, lo, hi, compare) {\n    var runHi = lo + 1;\n\n    if (runHi === hi) {\n        return 1;\n    }\n\n    if (compare(array[runHi++], array[lo]) < 0) {\n        while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {\n            runHi++;\n        }\n\n        reverseRun(array, lo, runHi);\n    }\n    else {\n        while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {\n            runHi++;\n        }\n    }\n\n    return runHi - lo;\n}\n\nfunction reverseRun(array, lo, hi) {\n    hi--;\n\n    while (lo < hi) {\n        var t = array[lo];\n        array[lo++] = array[hi];\n        array[hi--] = t;\n    }\n}\n\nfunction binaryInsertionSort(array, lo, hi, start, compare) {\n    if (start === lo) {\n        start++;\n    }\n\n    for (; start < hi; start++) {\n        var pivot = array[start];\n\n        var left = lo;\n        var right = start;\n        var mid;\n\n        while (left < right) {\n            mid = left + right >>> 1;\n\n            if (compare(pivot, array[mid]) < 0) {\n                right = mid;\n            }\n            else {\n                left = mid + 1;\n            }\n        }\n\n        var n = start - left;\n\n        switch (n) {\n            case 3:\n                array[left + 3] = array[left + 2];\n\n            case 2:\n                array[left + 2] = array[left + 1];\n\n            case 1:\n                array[left + 1] = array[left];\n                break;\n            default:\n                while (n > 0) {\n                    array[left + n] = array[left + n - 1];\n                    n--;\n                }\n        }\n\n        array[left] = pivot;\n    }\n}\n\nfunction gallopLeft(value, array, start, length, hint, compare) {\n    var lastOffset = 0;\n    var maxOffset = 0;\n    var offset = 1;\n\n    if (compare(value, array[start + hint]) > 0) {\n        maxOffset = length - hint;\n\n        while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        lastOffset += hint;\n        offset += hint;\n    }\n    else {\n        maxOffset = hint + 1;\n        while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        var tmp = lastOffset;\n        lastOffset = hint - offset;\n        offset = hint - tmp;\n    }\n\n    lastOffset++;\n    while (lastOffset < offset) {\n        var m = lastOffset + (offset - lastOffset >>> 1);\n\n        if (compare(value, array[start + m]) > 0) {\n            lastOffset = m + 1;\n        }\n        else {\n            offset = m;\n        }\n    }\n    return offset;\n}\n\nfunction gallopRight(value, array, start, length, hint, compare) {\n    var lastOffset = 0;\n    var maxOffset = 0;\n    var offset = 1;\n\n    if (compare(value, array[start + hint]) < 0) {\n        maxOffset = hint + 1;\n\n        while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        var tmp = lastOffset;\n        lastOffset = hint - offset;\n        offset = hint - tmp;\n    }\n    else {\n        maxOffset = length - hint;\n\n        while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        lastOffset += hint;\n        offset += hint;\n    }\n\n    lastOffset++;\n\n    while (lastOffset < offset) {\n        var m = lastOffset + (offset - lastOffset >>> 1);\n\n        if (compare(value, array[start + m]) < 0) {\n            offset = m;\n        }\n        else {\n            lastOffset = m + 1;\n        }\n    }\n\n    return offset;\n}\n\nfunction TimSort(array, compare) {\n    var minGallop = DEFAULT_MIN_GALLOPING;\n    var runStart;\n    var runLength;\n    var stackSize = 0;\n\n    var tmp = [];\n\n    runStart = [];\n    runLength = [];\n\n    function pushRun(_runStart, _runLength) {\n        runStart[stackSize] = _runStart;\n        runLength[stackSize] = _runLength;\n        stackSize += 1;\n    }\n\n    function mergeRuns() {\n        while (stackSize > 1) {\n            var n = stackSize - 2;\n\n            if (n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1] || n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1]) {\n                if (runLength[n - 1] < runLength[n + 1]) {\n                    n--;\n                }\n            }\n            else if (runLength[n] > runLength[n + 1]) {\n                break;\n            }\n            mergeAt(n);\n        }\n    }\n\n    function forceMergeRuns() {\n        while (stackSize > 1) {\n            var n = stackSize - 2;\n\n            if (n > 0 && runLength[n - 1] < runLength[n + 1]) {\n                n--;\n            }\n\n            mergeAt(n);\n        }\n    }\n\n    function mergeAt(i) {\n        var start1 = runStart[i];\n        var length1 = runLength[i];\n        var start2 = runStart[i + 1];\n        var length2 = runLength[i + 1];\n\n        runLength[i] = length1 + length2;\n\n        if (i === stackSize - 3) {\n            runStart[i + 1] = runStart[i + 2];\n            runLength[i + 1] = runLength[i + 2];\n        }\n\n        stackSize--;\n\n        var k = gallopRight(array[start2], array, start1, length1, 0, compare);\n        start1 += k;\n        length1 -= k;\n\n        if (length1 === 0) {\n            return;\n        }\n\n        length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);\n\n        if (length2 === 0) {\n            return;\n        }\n\n        if (length1 <= length2) {\n            mergeLow(start1, length1, start2, length2);\n        }\n        else {\n            mergeHigh(start1, length1, start2, length2);\n        }\n    }\n\n    function mergeLow(start1, length1, start2, length2) {\n        var i = 0;\n\n        for (i = 0; i < length1; i++) {\n            tmp[i] = array[start1 + i];\n        }\n\n        var cursor1 = 0;\n        var cursor2 = start2;\n        var dest = start1;\n\n        array[dest++] = array[cursor2++];\n\n        if (--length2 === 0) {\n            for (i = 0; i < length1; i++) {\n                array[dest + i] = tmp[cursor1 + i];\n            }\n            return;\n        }\n\n        if (length1 === 1) {\n            for (i = 0; i < length2; i++) {\n                array[dest + i] = array[cursor2 + i];\n            }\n            array[dest + length2] = tmp[cursor1];\n            return;\n        }\n\n        var _minGallop = minGallop;\n        var count1, count2, exit;\n\n        while (1) {\n            count1 = 0;\n            count2 = 0;\n            exit = false;\n\n            do {\n                if (compare(array[cursor2], tmp[cursor1]) < 0) {\n                    array[dest++] = array[cursor2++];\n                    count2++;\n                    count1 = 0;\n\n                    if (--length2 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                else {\n                    array[dest++] = tmp[cursor1++];\n                    count1++;\n                    count2 = 0;\n                    if (--length1 === 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n            } while ((count1 | count2) < _minGallop);\n\n            if (exit) {\n                break;\n            }\n\n            do {\n                count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);\n\n                if (count1 !== 0) {\n                    for (i = 0; i < count1; i++) {\n                        array[dest + i] = tmp[cursor1 + i];\n                    }\n\n                    dest += count1;\n                    cursor1 += count1;\n                    length1 -= count1;\n                    if (length1 <= 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest++] = array[cursor2++];\n\n                if (--length2 === 0) {\n                    exit = true;\n                    break;\n                }\n\n                count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);\n\n                if (count2 !== 0) {\n                    for (i = 0; i < count2; i++) {\n                        array[dest + i] = array[cursor2 + i];\n                    }\n\n                    dest += count2;\n                    cursor2 += count2;\n                    length2 -= count2;\n\n                    if (length2 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                array[dest++] = tmp[cursor1++];\n\n                if (--length1 === 1) {\n                    exit = true;\n                    break;\n                }\n\n                _minGallop--;\n            } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);\n\n            if (exit) {\n                break;\n            }\n\n            if (_minGallop < 0) {\n                _minGallop = 0;\n            }\n\n            _minGallop += 2;\n        }\n\n        minGallop = _minGallop;\n\n        minGallop < 1 && (minGallop = 1);\n\n        if (length1 === 1) {\n            for (i = 0; i < length2; i++) {\n                array[dest + i] = array[cursor2 + i];\n            }\n            array[dest + length2] = tmp[cursor1];\n        }\n        else if (length1 === 0) {\n            throw new Error();\n            // throw new Error('mergeLow preconditions were not respected');\n        }\n        else {\n            for (i = 0; i < length1; i++) {\n                array[dest + i] = tmp[cursor1 + i];\n            }\n        }\n    }\n\n    function mergeHigh(start1, length1, start2, length2) {\n        var i = 0;\n\n        for (i = 0; i < length2; i++) {\n            tmp[i] = array[start2 + i];\n        }\n\n        var cursor1 = start1 + length1 - 1;\n        var cursor2 = length2 - 1;\n        var dest = start2 + length2 - 1;\n        var customCursor = 0;\n        var customDest = 0;\n\n        array[dest--] = array[cursor1--];\n\n        if (--length1 === 0) {\n            customCursor = dest - (length2 - 1);\n\n            for (i = 0; i < length2; i++) {\n                array[customCursor + i] = tmp[i];\n            }\n\n            return;\n        }\n\n        if (length2 === 1) {\n            dest -= length1;\n            cursor1 -= length1;\n            customDest = dest + 1;\n            customCursor = cursor1 + 1;\n\n            for (i = length1 - 1; i >= 0; i--) {\n                array[customDest + i] = array[customCursor + i];\n            }\n\n            array[dest] = tmp[cursor2];\n            return;\n        }\n\n        var _minGallop = minGallop;\n\n        while (true) {\n            var count1 = 0;\n            var count2 = 0;\n            var exit = false;\n\n            do {\n                if (compare(tmp[cursor2], array[cursor1]) < 0) {\n                    array[dest--] = array[cursor1--];\n                    count1++;\n                    count2 = 0;\n                    if (--length1 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                else {\n                    array[dest--] = tmp[cursor2--];\n                    count2++;\n                    count1 = 0;\n                    if (--length2 === 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n            } while ((count1 | count2) < _minGallop);\n\n            if (exit) {\n                break;\n            }\n\n            do {\n                count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);\n\n                if (count1 !== 0) {\n                    dest -= count1;\n                    cursor1 -= count1;\n                    length1 -= count1;\n                    customDest = dest + 1;\n                    customCursor = cursor1 + 1;\n\n                    for (i = count1 - 1; i >= 0; i--) {\n                        array[customDest + i] = array[customCursor + i];\n                    }\n\n                    if (length1 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest--] = tmp[cursor2--];\n\n                if (--length2 === 1) {\n                    exit = true;\n                    break;\n                }\n\n                count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);\n\n                if (count2 !== 0) {\n                    dest -= count2;\n                    cursor2 -= count2;\n                    length2 -= count2;\n                    customDest = dest + 1;\n                    customCursor = cursor2 + 1;\n\n                    for (i = 0; i < count2; i++) {\n                        array[customDest + i] = tmp[customCursor + i];\n                    }\n\n                    if (length2 <= 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest--] = array[cursor1--];\n\n                if (--length1 === 0) {\n                    exit = true;\n                    break;\n                }\n\n                _minGallop--;\n            } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);\n\n            if (exit) {\n                break;\n            }\n\n            if (_minGallop < 0) {\n                _minGallop = 0;\n            }\n\n            _minGallop += 2;\n        }\n\n        minGallop = _minGallop;\n\n        if (minGallop < 1) {\n            minGallop = 1;\n        }\n\n        if (length2 === 1) {\n            dest -= length1;\n            cursor1 -= length1;\n            customDest = dest + 1;\n            customCursor = cursor1 + 1;\n\n            for (i = length1 - 1; i >= 0; i--) {\n                array[customDest + i] = array[customCursor + i];\n            }\n\n            array[dest] = tmp[cursor2];\n        }\n        else if (length2 === 0) {\n            throw new Error();\n            // throw new Error('mergeHigh preconditions were not respected');\n        }\n        else {\n            customCursor = dest - (length2 - 1);\n            for (i = 0; i < length2; i++) {\n                array[customCursor + i] = tmp[i];\n            }\n        }\n    }\n\n    this.mergeRuns = mergeRuns;\n    this.forceMergeRuns = forceMergeRuns;\n    this.pushRun = pushRun;\n}\n\nfunction sort(array, compare, lo, hi) {\n    if (!lo) {\n        lo = 0;\n    }\n    if (!hi) {\n        hi = array.length;\n    }\n\n    var remaining = hi - lo;\n\n    if (remaining < 2) {\n        return;\n    }\n\n    var runLength = 0;\n\n    if (remaining < DEFAULT_MIN_MERGE) {\n        runLength = makeAscendingRun(array, lo, hi, compare);\n        binaryInsertionSort(array, lo, hi, lo + runLength, compare);\n        return;\n    }\n\n    var ts = new TimSort(array, compare);\n\n    var minRun = minRunLength(remaining);\n\n    do {\n        runLength = makeAscendingRun(array, lo, hi, compare);\n        if (runLength < minRun) {\n            var force = remaining;\n            if (force > minRun) {\n                force = minRun;\n            }\n\n            binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);\n            runLength = force;\n        }\n\n        ts.pushRun(lo, runLength);\n        ts.mergeRuns();\n\n        remaining -= runLength;\n        lo += runLength;\n    } while (remaining !== 0);\n\n    ts.forceMergeRuns();\n}\n\n// Use timsort because in most case elements are partially sorted\n// https://jsfiddle.net/pissang/jr4x7mdm/8/\nfunction shapeCompareFunc(a, b) {\n    if (a.zlevel === b.zlevel) {\n        if (a.z === b.z) {\n            // if (a.z2 === b.z2) {\n            //     // FIXME Slow has renderidx compare\n            //     // http://stackoverflow.com/questions/20883421/sorting-in-javascript-should-every-compare-function-have-a-return-0-statement\n            //     // https://github.com/v8/v8/blob/47cce544a31ed5577ffe2963f67acb4144ee0232/src/js/array.js#L1012\n            //     return a.__renderidx - b.__renderidx;\n            // }\n            return a.z2 - b.z2;\n        }\n        return a.z - b.z;\n    }\n    return a.zlevel - b.zlevel;\n}\n/**\n * 内容仓库 (M)\n * @alias module:zrender/Storage\n * @constructor\n */\nvar Storage = function () { // jshint ignore:line\n    this._roots = [];\n\n    this._displayList = [];\n\n    this._displayListLen = 0;\n};\n\nStorage.prototype = {\n\n    constructor: Storage,\n\n    /**\n     * @param  {Function} cb\n     *\n     */\n    traverse: function (cb, context) {\n        for (var i = 0; i < this._roots.length; i++) {\n            this._roots[i].traverse(cb, context);\n        }\n    },\n\n    /**\n     * 返回所有图形的绘制队列\n     * @param {boolean} [update=false] 是否在返回前更新该数组\n     * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组, 在 update 为 true 的时候有效\n     *\n     * 详见{@link module:zrender/graphic/Displayable.prototype.updateDisplayList}\n     * @return {Array.<module:zrender/graphic/Displayable>}\n     */\n    getDisplayList: function (update, includeIgnore) {\n        includeIgnore = includeIgnore || false;\n        if (update) {\n            this.updateDisplayList(includeIgnore);\n        }\n        return this._displayList;\n    },\n\n    /**\n     * 更新图形的绘制队列。\n     * 每次绘制前都会调用，该方法会先深度优先遍历整个树，更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中，\n     * 最后根据绘制的优先级（zlevel > z > 插入顺序）排序得到绘制队列\n     * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组\n     */\n    updateDisplayList: function (includeIgnore) {\n        this._displayListLen = 0;\n\n        var roots = this._roots;\n        var displayList = this._displayList;\n        for (var i = 0, len = roots.length; i < len; i++) {\n            this._updateAndAddDisplayable(roots[i], null, includeIgnore);\n        }\n\n        displayList.length = this._displayListLen;\n\n        env$1.canvasSupported && sort(displayList, shapeCompareFunc);\n    },\n\n    _updateAndAddDisplayable: function (el, clipPaths, includeIgnore) {\n\n        if (el.ignore && !includeIgnore) {\n            return;\n        }\n\n        el.beforeUpdate();\n\n        if (el.__dirty) {\n\n            el.update();\n\n        }\n\n        el.afterUpdate();\n\n        var userSetClipPath = el.clipPath;\n        if (userSetClipPath) {\n\n            // FIXME 效率影响\n            if (clipPaths) {\n                clipPaths = clipPaths.slice();\n            }\n            else {\n                clipPaths = [];\n            }\n\n            var currentClipPath = userSetClipPath;\n            var parentClipPath = el;\n            // Recursively add clip path\n            while (currentClipPath) {\n                // clipPath 的变换是基于使用这个 clipPath 的元素\n                currentClipPath.parent = parentClipPath;\n                currentClipPath.updateTransform();\n\n                clipPaths.push(currentClipPath);\n\n                parentClipPath = currentClipPath;\n                currentClipPath = currentClipPath.clipPath;\n            }\n        }\n\n        if (el.isGroup) {\n            var children = el._children;\n\n            for (var i = 0; i < children.length; i++) {\n                var child = children[i];\n\n                // Force to mark as dirty if group is dirty\n                // FIXME __dirtyPath ?\n                if (el.__dirty) {\n                    child.__dirty = true;\n                }\n\n                this._updateAndAddDisplayable(child, clipPaths, includeIgnore);\n            }\n\n            // Mark group clean here\n            el.__dirty = false;\n\n        }\n        else {\n            el.__clipPaths = clipPaths;\n\n            this._displayList[this._displayListLen++] = el;\n        }\n    },\n\n    /**\n     * 添加图形(Shape)或者组(Group)到根节点\n     * @param {module:zrender/Element} el\n     */\n    addRoot: function (el) {\n        if (el.__storage === this) {\n            return;\n        }\n\n        if (el instanceof Group) {\n            el.addChildrenToStorage(this);\n        }\n\n        this.addToStorage(el);\n        this._roots.push(el);\n    },\n\n    /**\n     * 删除指定的图形(Shape)或者组(Group)\n     * @param {string|Array.<string>} [el] 如果为空清空整个Storage\n     */\n    delRoot: function (el) {\n        if (el == null) {\n            // 不指定el清空\n            for (var i = 0; i < this._roots.length; i++) {\n                var root = this._roots[i];\n                if (root instanceof Group) {\n                    root.delChildrenFromStorage(this);\n                }\n            }\n\n            this._roots = [];\n            this._displayList = [];\n            this._displayListLen = 0;\n\n            return;\n        }\n\n        if (el instanceof Array) {\n            for (var i = 0, l = el.length; i < l; i++) {\n                this.delRoot(el[i]);\n            }\n            return;\n        }\n\n\n        var idx = indexOf(this._roots, el);\n        if (idx >= 0) {\n            this.delFromStorage(el);\n            this._roots.splice(idx, 1);\n            if (el instanceof Group) {\n                el.delChildrenFromStorage(this);\n            }\n        }\n    },\n\n    addToStorage: function (el) {\n        if (el) {\n            el.__storage = this;\n            el.dirty(false);\n        }\n        return this;\n    },\n\n    delFromStorage: function (el) {\n        if (el) {\n            el.__storage = null;\n        }\n\n        return this;\n    },\n\n    /**\n     * 清空并且释放Storage\n     */\n    dispose: function () {\n        this._renderList =\n        this._roots = null;\n    },\n\n    displayableSortFunc: shapeCompareFunc\n};\n\nvar SHADOW_PROPS = {\n    'shadowBlur': 1,\n    'shadowOffsetX': 1,\n    'shadowOffsetY': 1,\n    'textShadowBlur': 1,\n    'textShadowOffsetX': 1,\n    'textShadowOffsetY': 1,\n    'textBoxShadowBlur': 1,\n    'textBoxShadowOffsetX': 1,\n    'textBoxShadowOffsetY': 1\n};\n\nvar fixShadow = function (ctx, propName, value) {\n    if (SHADOW_PROPS.hasOwnProperty(propName)) {\n        return value *= ctx.dpr;\n    }\n    return value;\n};\n\nvar ContextCachedBy = {\n    NONE: 0,\n    STYLE_BIND: 1,\n    PLAIN_TEXT: 2\n};\n\n// Avoid confused with 0/false.\nvar WILL_BE_RESTORED = 9;\n\nvar STYLE_COMMON_PROPS = [\n    ['shadowBlur', 0], ['shadowOffsetX', 0], ['shadowOffsetY', 0], ['shadowColor', '#000'],\n    ['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]\n];\n\n// var SHADOW_PROPS = STYLE_COMMON_PROPS.slice(0, 4);\n// var LINE_PROPS = STYLE_COMMON_PROPS.slice(4);\n\nvar Style = function (opts) {\n    this.extendFrom(opts, false);\n};\n\nfunction createLinearGradient(ctx, obj, rect) {\n    var x = obj.x == null ? 0 : obj.x;\n    var x2 = obj.x2 == null ? 1 : obj.x2;\n    var y = obj.y == null ? 0 : obj.y;\n    var y2 = obj.y2 == null ? 0 : obj.y2;\n\n    if (!obj.global) {\n        x = x * rect.width + rect.x;\n        x2 = x2 * rect.width + rect.x;\n        y = y * rect.height + rect.y;\n        y2 = y2 * rect.height + rect.y;\n    }\n\n    // Fix NaN when rect is Infinity\n    x = isNaN(x) ? 0 : x;\n    x2 = isNaN(x2) ? 1 : x2;\n    y = isNaN(y) ? 0 : y;\n    y2 = isNaN(y2) ? 0 : y2;\n\n    var canvasGradient = ctx.createLinearGradient(x, y, x2, y2);\n\n    return canvasGradient;\n}\n\nfunction createRadialGradient(ctx, obj, rect) {\n    var width = rect.width;\n    var height = rect.height;\n    var min = Math.min(width, height);\n\n    var x = obj.x == null ? 0.5 : obj.x;\n    var y = obj.y == null ? 0.5 : obj.y;\n    var r = obj.r == null ? 0.5 : obj.r;\n    if (!obj.global) {\n        x = x * width + rect.x;\n        y = y * height + rect.y;\n        r = r * min;\n    }\n\n    var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r);\n\n    return canvasGradient;\n}\n\n\nStyle.prototype = {\n\n    constructor: Style,\n\n    /**\n     * @type {string}\n     */\n    fill: '#000',\n\n    /**\n     * @type {string}\n     */\n    stroke: null,\n\n    /**\n     * @type {number}\n     */\n    opacity: 1,\n\n    /**\n     * @type {number}\n     */\n    fillOpacity: null,\n\n    /**\n     * @type {number}\n     */\n    strokeOpacity: null,\n\n    /**\n     * @type {Array.<number>}\n     */\n    lineDash: null,\n\n    /**\n     * @type {number}\n     */\n    lineDashOffset: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowOffsetY: 0,\n\n    /**\n     * @type {number}\n     */\n    lineWidth: 1,\n\n    /**\n     * If stroke ignore scale\n     * @type {Boolean}\n     */\n    strokeNoScale: false,\n\n    // Bounding rect text configuration\n    // Not affected by element transform\n    /**\n     * @type {string}\n     */\n    text: null,\n\n    /**\n     * If `fontSize` or `fontFamily` exists, `font` will be reset by\n     * `fontSize`, `fontStyle`, `fontWeight`, `fontFamily`.\n     * So do not visit it directly in upper application (like echarts),\n     * but use `contain/text#makeFont` instead.\n     * @type {string}\n     */\n    font: null,\n\n    /**\n     * The same as font. Use font please.\n     * @deprecated\n     * @type {string}\n     */\n    textFont: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontStyle: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontWeight: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * Should be 12 but not '12px'.\n     * @type {number}\n     */\n    fontSize: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontFamily: null,\n\n    /**\n     * Reserved for special functinality, like 'hr'.\n     * @type {string}\n     */\n    textTag: null,\n\n    /**\n     * @type {string}\n     */\n    textFill: '#000',\n\n    /**\n     * @type {string}\n     */\n    textStroke: null,\n\n    /**\n     * @type {number}\n     */\n    textWidth: null,\n\n    /**\n     * Only for textBackground.\n     * @type {number}\n     */\n    textHeight: null,\n\n    /**\n     * textStroke may be set as some color as a default\n     * value in upper applicaion, where the default value\n     * of textStrokeWidth should be 0 to make sure that\n     * user can choose to do not use text stroke.\n     * @type {number}\n     */\n    textStrokeWidth: 0,\n\n    /**\n     * @type {number}\n     */\n    textLineHeight: null,\n\n    /**\n     * 'inside', 'left', 'right', 'top', 'bottom'\n     * [x, y]\n     * Based on x, y of rect.\n     * @type {string|Array.<number>}\n     * @default 'inside'\n     */\n    textPosition: 'inside',\n\n    /**\n     * If not specified, use the boundingRect of a `displayable`.\n     * @type {Object}\n     */\n    textRect: null,\n\n    /**\n     * [x, y]\n     * @type {Array.<number>}\n     */\n    textOffset: null,\n\n    /**\n     * @type {string}\n     */\n    textAlign: null,\n\n    /**\n     * @type {string}\n     */\n    textVerticalAlign: null,\n\n    /**\n     * @type {number}\n     */\n    textDistance: 5,\n\n    /**\n     * @type {string}\n     */\n    textShadowColor: 'transparent',\n\n    /**\n     * @type {number}\n     */\n    textShadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    textShadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    textShadowOffsetY: 0,\n\n    /**\n     * @type {string}\n     */\n    textBoxShadowColor: 'transparent',\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowOffsetY: 0,\n\n    /**\n     * Whether transform text.\n     * Only useful in Path and Image element\n     * @type {boolean}\n     */\n    transformText: false,\n\n    /**\n     * Text rotate around position of Path or Image\n     * Only useful in Path and Image element and transformText is false.\n     */\n    textRotation: 0,\n\n    /**\n     * Text origin of text rotation, like [10, 40].\n     * Based on x, y of rect.\n     * Useful in label rotation of circular symbol.\n     * By default, this origin is textPosition.\n     * Can be 'center'.\n     * @type {string|Array.<number>}\n     */\n    textOrigin: null,\n\n    /**\n     * @type {string}\n     */\n    textBackgroundColor: null,\n\n    /**\n     * @type {string}\n     */\n    textBorderColor: null,\n\n    /**\n     * @type {number}\n     */\n    textBorderWidth: 0,\n\n    /**\n     * @type {number}\n     */\n    textBorderRadius: 0,\n\n    /**\n     * Can be `2` or `[2, 4]` or `[2, 3, 4, 5]`\n     * @type {number|Array.<number>}\n     */\n    textPadding: null,\n\n    /**\n     * Text styles for rich text.\n     * @type {Object}\n     */\n    rich: null,\n\n    /**\n     * {outerWidth, outerHeight, ellipsis, placeholder}\n     * @type {Object}\n     */\n    truncate: null,\n\n    /**\n     * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation\n     * @type {string}\n     */\n    blend: null,\n\n    /**\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    bind: function (ctx, el, prevEl) {\n        var style = this;\n        var prevStyle = prevEl && prevEl.style;\n        // If no prevStyle, it means first draw.\n        // Only apply cache if the last time cachced by this function.\n        var notCheckCache = !prevStyle || ctx.__attrCachedBy !== ContextCachedBy.STYLE_BIND;\n\n        ctx.__attrCachedBy = ContextCachedBy.STYLE_BIND;\n\n        for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {\n            var prop = STYLE_COMMON_PROPS[i];\n            var styleName = prop[0];\n\n            if (notCheckCache || style[styleName] !== prevStyle[styleName]) {\n                // FIXME Invalid property value will cause style leak from previous element.\n                ctx[styleName] =\n                    fixShadow(ctx, styleName, style[styleName] || prop[1]);\n            }\n        }\n\n        if ((notCheckCache || style.fill !== prevStyle.fill)) {\n            ctx.fillStyle = style.fill;\n        }\n        if ((notCheckCache || style.stroke !== prevStyle.stroke)) {\n            ctx.strokeStyle = style.stroke;\n        }\n        if ((notCheckCache || style.opacity !== prevStyle.opacity)) {\n            ctx.globalAlpha = style.opacity == null ? 1 : style.opacity;\n        }\n\n        if ((notCheckCache || style.blend !== prevStyle.blend)) {\n            ctx.globalCompositeOperation = style.blend || 'source-over';\n        }\n        if (this.hasStroke()) {\n            var lineWidth = style.lineWidth;\n            ctx.lineWidth = lineWidth / (\n                (this.strokeNoScale && el && el.getLineScale) ? el.getLineScale() : 1\n            );\n        }\n    },\n\n    hasFill: function () {\n        var fill = this.fill;\n        return fill != null && fill !== 'none';\n    },\n\n    hasStroke: function () {\n        var stroke = this.stroke;\n        return stroke != null && stroke !== 'none' && this.lineWidth > 0;\n    },\n\n    /**\n     * Extend from other style\n     * @param {zrender/graphic/Style} otherStyle\n     * @param {boolean} overwrite true: overwrirte any way.\n     *                            false: overwrite only when !target.hasOwnProperty\n     *                            others: overwrite when property is not null/undefined.\n     */\n    extendFrom: function (otherStyle, overwrite) {\n        if (otherStyle) {\n            for (var name in otherStyle) {\n                if (otherStyle.hasOwnProperty(name)\n                    && (overwrite === true\n                        || (\n                            overwrite === false\n                                ? !this.hasOwnProperty(name)\n                                : otherStyle[name] != null\n                        )\n                    )\n                ) {\n                    this[name] = otherStyle[name];\n                }\n            }\n        }\n    },\n\n    /**\n     * Batch setting style with a given object\n     * @param {Object|string} obj\n     * @param {*} [obj]\n     */\n    set: function (obj, value) {\n        if (typeof obj === 'string') {\n            this[obj] = value;\n        }\n        else {\n            this.extendFrom(obj, true);\n        }\n    },\n\n    /**\n     * Clone\n     * @return {zrender/graphic/Style} [description]\n     */\n    clone: function () {\n        var newStyle = new this.constructor();\n        newStyle.extendFrom(this, true);\n        return newStyle;\n    },\n\n    getGradient: function (ctx, obj, rect) {\n        var method = obj.type === 'radial' ? createRadialGradient : createLinearGradient;\n        var canvasGradient = method(ctx, obj, rect);\n        var colorStops = obj.colorStops;\n        for (var i = 0; i < colorStops.length; i++) {\n            canvasGradient.addColorStop(\n                colorStops[i].offset, colorStops[i].color\n            );\n        }\n        return canvasGradient;\n    }\n\n};\n\nvar styleProto = Style.prototype;\nfor (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {\n    var prop = STYLE_COMMON_PROPS[i];\n    if (!(prop[0] in styleProto)) {\n        styleProto[prop[0]] = prop[1];\n    }\n}\n\n// Provide for others\nStyle.getGradient = styleProto.getGradient;\n\nvar Pattern = function (image, repeat) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {image: ...}`, where this constructor will not be called.\n\n    this.image = image;\n    this.repeat = repeat;\n\n    // Can be cloned\n    this.type = 'pattern';\n};\n\nPattern.prototype.getCanvasPattern = function (ctx) {\n    return ctx.createPattern(this.image, this.repeat || 'repeat');\n};\n\n/**\n * @module zrender/Layer\n * @author pissang(https://www.github.com/pissang)\n */\n\nfunction returnFalse() {\n    return false;\n}\n\n/**\n * 创建dom\n *\n * @inner\n * @param {string} id dom id 待用\n * @param {Painter} painter painter instance\n * @param {number} number\n */\nfunction createDom(id, painter, dpr) {\n    var newDom = createCanvas();\n    var width = painter.getWidth();\n    var height = painter.getHeight();\n\n    var newDomStyle = newDom.style;\n    if (newDomStyle) {  // In node or some other non-browser environment\n        newDomStyle.position = 'absolute';\n        newDomStyle.left = 0;\n        newDomStyle.top = 0;\n        newDomStyle.width = width + 'px';\n        newDomStyle.height = height + 'px';\n\n        newDom.setAttribute('data-zr-dom-id', id);\n    }\n\n    newDom.width = width * dpr;\n    newDom.height = height * dpr;\n\n    return newDom;\n}\n\n/**\n * @alias module:zrender/Layer\n * @constructor\n * @extends module:zrender/mixin/Transformable\n * @param {string} id\n * @param {module:zrender/Painter} painter\n * @param {number} [dpr]\n */\nvar Layer = function (id, painter, dpr) {\n    var dom;\n    dpr = dpr || devicePixelRatio;\n    if (typeof id === 'string') {\n        dom = createDom(id, painter, dpr);\n    }\n    // Not using isDom because in node it will return false\n    else if (isObject$1(id)) {\n        dom = id;\n        id = dom.id;\n    }\n    this.id = id;\n    this.dom = dom;\n\n    var domStyle = dom.style;\n    if (domStyle) { // Not in node\n        dom.onselectstart = returnFalse; // 避免页面选中的尴尬\n        domStyle['-webkit-user-select'] = 'none';\n        domStyle['user-select'] = 'none';\n        domStyle['-webkit-touch-callout'] = 'none';\n        domStyle['-webkit-tap-highlight-color'] = 'rgba(0,0,0,0)';\n        domStyle['padding'] = 0;\n        domStyle['margin'] = 0;\n        domStyle['border-width'] = 0;\n    }\n\n    this.domBack = null;\n    this.ctxBack = null;\n\n    this.painter = painter;\n\n    this.config = null;\n\n    // Configs\n    /**\n     * 每次清空画布的颜色\n     * @type {string}\n     * @default 0\n     */\n    this.clearColor = 0;\n    /**\n     * 是否开启动态模糊\n     * @type {boolean}\n     * @default false\n     */\n    this.motionBlur = false;\n    /**\n     * 在开启动态模糊的时候使用，与上一帧混合的alpha值，值越大尾迹越明显\n     * @type {number}\n     * @default 0.7\n     */\n    this.lastFrameAlpha = 0.7;\n\n    /**\n     * Layer dpr\n     * @type {number}\n     */\n    this.dpr = dpr;\n};\n\nLayer.prototype = {\n\n    constructor: Layer,\n\n    __dirty: true,\n\n    __used: false,\n\n    __drawIndex: 0,\n    __startIndex: 0,\n    __endIndex: 0,\n\n    incremental: false,\n\n    getElementCount: function () {\n        return this.__endIndex - this.__startIndex;\n    },\n\n    initContext: function () {\n        this.ctx = this.dom.getContext('2d');\n        this.ctx.dpr = this.dpr;\n    },\n\n    createBackBuffer: function () {\n        var dpr = this.dpr;\n\n        this.domBack = createDom('back-' + this.id, this.painter, dpr);\n        this.ctxBack = this.domBack.getContext('2d');\n\n        if (dpr !== 1) {\n            this.ctxBack.scale(dpr, dpr);\n        }\n    },\n\n    /**\n     * @param  {number} width\n     * @param  {number} height\n     */\n    resize: function (width, height) {\n        var dpr = this.dpr;\n\n        var dom = this.dom;\n        var domStyle = dom.style;\n        var domBack = this.domBack;\n\n        if (domStyle) {\n            domStyle.width = width + 'px';\n            domStyle.height = height + 'px';\n        }\n\n        dom.width = width * dpr;\n        dom.height = height * dpr;\n\n        if (domBack) {\n            domBack.width = width * dpr;\n            domBack.height = height * dpr;\n\n            if (dpr !== 1) {\n                this.ctxBack.scale(dpr, dpr);\n            }\n        }\n    },\n\n    /**\n     * 清空该层画布\n     * @param {boolean} [clearAll]=false Clear all with out motion blur\n     * @param {Color} [clearColor]\n     */\n    clear: function (clearAll, clearColor) {\n        var dom = this.dom;\n        var ctx = this.ctx;\n        var width = dom.width;\n        var height = dom.height;\n\n        var clearColor = clearColor || this.clearColor;\n        var haveMotionBLur = this.motionBlur && !clearAll;\n        var lastFrameAlpha = this.lastFrameAlpha;\n\n        var dpr = this.dpr;\n\n        if (haveMotionBLur) {\n            if (!this.domBack) {\n                this.createBackBuffer();\n            }\n\n            this.ctxBack.globalCompositeOperation = 'copy';\n            this.ctxBack.drawImage(\n                dom, 0, 0,\n                width / dpr,\n                height / dpr\n            );\n        }\n\n        ctx.clearRect(0, 0, width, height);\n        if (clearColor && clearColor !== 'transparent') {\n            var clearColorGradientOrPattern;\n            // Gradient\n            if (clearColor.colorStops) {\n                // Cache canvas gradient\n                clearColorGradientOrPattern = clearColor.__canvasGradient || Style.getGradient(ctx, clearColor, {\n                    x: 0,\n                    y: 0,\n                    width: width,\n                    height: height\n                });\n\n                clearColor.__canvasGradient = clearColorGradientOrPattern;\n            }\n            // Pattern\n            else if (clearColor.image) {\n                clearColorGradientOrPattern = Pattern.prototype.getCanvasPattern.call(clearColor, ctx);\n            }\n            ctx.save();\n            ctx.fillStyle = clearColorGradientOrPattern || clearColor;\n            ctx.fillRect(0, 0, width, height);\n            ctx.restore();\n        }\n\n        if (haveMotionBLur) {\n            var domBack = this.domBack;\n            ctx.save();\n            ctx.globalAlpha = lastFrameAlpha;\n            ctx.drawImage(domBack, 0, 0, width, height);\n            ctx.restore();\n        }\n    }\n};\n\nvar requestAnimationFrame = (\n    typeof window !== 'undefined'\n    && (\n        (window.requestAnimationFrame && window.requestAnimationFrame.bind(window))\n        // https://github.com/ecomfe/zrender/issues/189#issuecomment-224919809\n        || (window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window))\n        || window.mozRequestAnimationFrame\n        || window.webkitRequestAnimationFrame\n    )\n) || function (func) {\n    setTimeout(func, 16);\n};\n\nvar globalImageCache = new LRU(50);\n\n/**\n * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc\n * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image\n */\nfunction findExistImage(newImageOrSrc) {\n    if (typeof newImageOrSrc === 'string') {\n        var cachedImgObj = globalImageCache.get(newImageOrSrc);\n        return cachedImgObj && cachedImgObj.image;\n    }\n    else {\n        return newImageOrSrc;\n    }\n}\n\n/**\n * Caution: User should cache loaded images, but not just count on LRU.\n * Consider if required images more than LRU size, will dead loop occur?\n *\n * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc\n * @param {HTMLImageElement|HTMLCanvasElement|Canvas} image Existent image.\n * @param {module:zrender/Element} [hostEl] For calling `dirty`.\n * @param {Function} [cb] params: (image, cbPayload)\n * @param {Object} [cbPayload] Payload on cb calling.\n * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image\n */\nfunction createOrUpdateImage(newImageOrSrc, image, hostEl, cb, cbPayload) {\n    if (!newImageOrSrc) {\n        return image;\n    }\n    else if (typeof newImageOrSrc === 'string') {\n\n        // Image should not be loaded repeatly.\n        if ((image && image.__zrImageSrc === newImageOrSrc) || !hostEl) {\n            return image;\n        }\n\n        // Only when there is no existent image or existent image src\n        // is different, this method is responsible for load.\n        var cachedImgObj = globalImageCache.get(newImageOrSrc);\n\n        var pendingWrap = {hostEl: hostEl, cb: cb, cbPayload: cbPayload};\n\n        if (cachedImgObj) {\n            image = cachedImgObj.image;\n            !isImageReady(image) && cachedImgObj.pending.push(pendingWrap);\n        }\n        else {\n            image = new Image();\n            image.onload = image.onerror = imageOnLoad;\n\n            globalImageCache.put(\n                newImageOrSrc,\n                image.__cachedImgObj = {\n                    image: image,\n                    pending: [pendingWrap]\n                }\n            );\n\n            image.src = image.__zrImageSrc = newImageOrSrc;\n        }\n\n        return image;\n    }\n    // newImageOrSrc is an HTMLImageElement or HTMLCanvasElement or Canvas\n    else {\n        return newImageOrSrc;\n    }\n}\n\nfunction imageOnLoad() {\n    var cachedImgObj = this.__cachedImgObj;\n    this.onload = this.onerror = this.__cachedImgObj = null;\n\n    for (var i = 0; i < cachedImgObj.pending.length; i++) {\n        var pendingWrap = cachedImgObj.pending[i];\n        var cb = pendingWrap.cb;\n        cb && cb(this, pendingWrap.cbPayload);\n        pendingWrap.hostEl.dirty();\n    }\n    cachedImgObj.pending.length = 0;\n}\n\nfunction isImageReady(image) {\n    return image && image.width && image.height;\n}\n\nvar textWidthCache = {};\nvar textWidthCacheCounter = 0;\n\nvar TEXT_CACHE_MAX = 5000;\nvar STYLE_REG = /\\{([a-zA-Z0-9_]+)\\|([^}]*)\\}/g;\n\nvar DEFAULT_FONT$1 = '12px sans-serif';\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar methods$1 = {};\n\nfunction $override$1(name, fn) {\n    methods$1[name] = fn;\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @return {number} width\n */\nfunction getWidth(text, font) {\n    font = font || DEFAULT_FONT$1;\n    var key = text + ':' + font;\n    if (textWidthCache[key]) {\n        return textWidthCache[key];\n    }\n\n    var textLines = (text + '').split('\\n');\n    var width = 0;\n\n    for (var i = 0, l = textLines.length; i < l; i++) {\n        // textContain.measureText may be overrided in SVG or VML\n        width = Math.max(measureText(textLines[i], font).width, width);\n    }\n\n    if (textWidthCacheCounter > TEXT_CACHE_MAX) {\n        textWidthCacheCounter = 0;\n        textWidthCache = {};\n    }\n    textWidthCacheCounter++;\n    textWidthCache[key] = width;\n\n    return width;\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @param {string} [textAlign='left']\n * @param {string} [textVerticalAlign='top']\n * @param {Array.<number>} [textPadding]\n * @param {Object} [rich]\n * @param {Object} [truncate]\n * @return {Object} {x, y, width, height, lineHeight}\n */\nfunction getBoundingRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) {\n    return rich\n        ? getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate)\n        : getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate);\n}\n\nfunction getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate) {\n    var contentBlock = parsePlainText(text, font, textPadding, textLineHeight, truncate);\n    var outerWidth = getWidth(text, font);\n    if (textPadding) {\n        outerWidth += textPadding[1] + textPadding[3];\n    }\n    var outerHeight = contentBlock.outerHeight;\n\n    var x = adjustTextX(0, outerWidth, textAlign);\n    var y = adjustTextY(0, outerHeight, textVerticalAlign);\n\n    var rect = new BoundingRect(x, y, outerWidth, outerHeight);\n    rect.lineHeight = contentBlock.lineHeight;\n\n    return rect;\n}\n\nfunction getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) {\n    var contentBlock = parseRichText(text, {\n        rich: rich,\n        truncate: truncate,\n        font: font,\n        textAlign: textAlign,\n        textPadding: textPadding,\n        textLineHeight: textLineHeight\n    });\n    var outerWidth = contentBlock.outerWidth;\n    var outerHeight = contentBlock.outerHeight;\n\n    var x = adjustTextX(0, outerWidth, textAlign);\n    var y = adjustTextY(0, outerHeight, textVerticalAlign);\n\n    return new BoundingRect(x, y, outerWidth, outerHeight);\n}\n\n/**\n * @public\n * @param {number} x\n * @param {number} width\n * @param {string} [textAlign='left']\n * @return {number} Adjusted x.\n */\nfunction adjustTextX(x, width, textAlign) {\n    // FIXME Right to left language\n    if (textAlign === 'right') {\n        x -= width;\n    }\n    else if (textAlign === 'center') {\n        x -= width / 2;\n    }\n    return x;\n}\n\n/**\n * @public\n * @param {number} y\n * @param {number} height\n * @param {string} [textVerticalAlign='top']\n * @return {number} Adjusted y.\n */\nfunction adjustTextY(y, height, textVerticalAlign) {\n    if (textVerticalAlign === 'middle') {\n        y -= height / 2;\n    }\n    else if (textVerticalAlign === 'bottom') {\n        y -= height;\n    }\n    return y;\n}\n\n/**\n * @public\n * @param {stirng} textPosition\n * @param {Object} rect {x, y, width, height}\n * @param {number} distance\n * @return {Object} {x, y, textAlign, textVerticalAlign}\n */\nfunction adjustTextPositionOnRect(textPosition, rect, distance) {\n\n    var x = rect.x;\n    var y = rect.y;\n\n    var height = rect.height;\n    var width = rect.width;\n    var halfHeight = height / 2;\n\n    var textAlign = 'left';\n    var textVerticalAlign = 'top';\n\n    switch (textPosition) {\n        case 'left':\n            x -= distance;\n            y += halfHeight;\n            textAlign = 'right';\n            textVerticalAlign = 'middle';\n            break;\n        case 'right':\n            x += distance + width;\n            y += halfHeight;\n            textVerticalAlign = 'middle';\n            break;\n        case 'top':\n            x += width / 2;\n            y -= distance;\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            break;\n        case 'bottom':\n            x += width / 2;\n            y += height + distance;\n            textAlign = 'center';\n            break;\n        case 'inside':\n            x += width / 2;\n            y += halfHeight;\n            textAlign = 'center';\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideLeft':\n            x += distance;\n            y += halfHeight;\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideRight':\n            x += width - distance;\n            y += halfHeight;\n            textAlign = 'right';\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideTop':\n            x += width / 2;\n            y += distance;\n            textAlign = 'center';\n            break;\n        case 'insideBottom':\n            x += width / 2;\n            y += height - distance;\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            break;\n        case 'insideTopLeft':\n            x += distance;\n            y += distance;\n            break;\n        case 'insideTopRight':\n            x += width - distance;\n            y += distance;\n            textAlign = 'right';\n            break;\n        case 'insideBottomLeft':\n            x += distance;\n            y += height - distance;\n            textVerticalAlign = 'bottom';\n            break;\n        case 'insideBottomRight':\n            x += width - distance;\n            y += height - distance;\n            textAlign = 'right';\n            textVerticalAlign = 'bottom';\n            break;\n    }\n\n    return {\n        x: x,\n        y: y,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\n/**\n * Show ellipsis if overflow.\n *\n * @public\n * @param  {string} text\n * @param  {string} containerWidth\n * @param  {string} font\n * @param  {number} [ellipsis='...']\n * @param  {Object} [options]\n * @param  {number} [options.maxIterations=3]\n * @param  {number} [options.minChar=0] If truncate result are less\n *                  then minChar, ellipsis will not show, which is\n *                  better for user hint in some cases.\n * @param  {number} [options.placeholder=''] When all truncated, use the placeholder.\n * @return {string}\n */\nfunction truncateText(text, containerWidth, font, ellipsis, options) {\n    if (!containerWidth) {\n        return '';\n    }\n\n    var textLines = (text + '').split('\\n');\n    options = prepareTruncateOptions(containerWidth, font, ellipsis, options);\n\n    // FIXME\n    // It is not appropriate that every line has '...' when truncate multiple lines.\n    for (var i = 0, len = textLines.length; i < len; i++) {\n        textLines[i] = truncateSingleLine(textLines[i], options);\n    }\n\n    return textLines.join('\\n');\n}\n\nfunction prepareTruncateOptions(containerWidth, font, ellipsis, options) {\n    options = extend({}, options);\n\n    options.font = font;\n    var ellipsis = retrieve2(ellipsis, '...');\n    options.maxIterations = retrieve2(options.maxIterations, 2);\n    var minChar = options.minChar = retrieve2(options.minChar, 0);\n    // FIXME\n    // Other languages?\n    options.cnCharWidth = getWidth('国', font);\n    // FIXME\n    // Consider proportional font?\n    var ascCharWidth = options.ascCharWidth = getWidth('a', font);\n    options.placeholder = retrieve2(options.placeholder, '');\n\n    // Example 1: minChar: 3, text: 'asdfzxcv', truncate result: 'asdf', but not: 'a...'.\n    // Example 2: minChar: 3, text: '维度', truncate result: '维', but not: '...'.\n    var contentWidth = containerWidth = Math.max(0, containerWidth - 1); // Reserve some gap.\n    for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) {\n        contentWidth -= ascCharWidth;\n    }\n\n    var ellipsisWidth = getWidth(ellipsis, font);\n    if (ellipsisWidth > contentWidth) {\n        ellipsis = '';\n        ellipsisWidth = 0;\n    }\n\n    contentWidth = containerWidth - ellipsisWidth;\n\n    options.ellipsis = ellipsis;\n    options.ellipsisWidth = ellipsisWidth;\n    options.contentWidth = contentWidth;\n    options.containerWidth = containerWidth;\n\n    return options;\n}\n\nfunction truncateSingleLine(textLine, options) {\n    var containerWidth = options.containerWidth;\n    var font = options.font;\n    var contentWidth = options.contentWidth;\n\n    if (!containerWidth) {\n        return '';\n    }\n\n    var lineWidth = getWidth(textLine, font);\n\n    if (lineWidth <= containerWidth) {\n        return textLine;\n    }\n\n    for (var j = 0; ; j++) {\n        if (lineWidth <= contentWidth || j >= options.maxIterations) {\n            textLine += options.ellipsis;\n            break;\n        }\n\n        var subLength = j === 0\n            ? estimateLength(textLine, contentWidth, options.ascCharWidth, options.cnCharWidth)\n            : lineWidth > 0\n            ? Math.floor(textLine.length * contentWidth / lineWidth)\n            : 0;\n\n        textLine = textLine.substr(0, subLength);\n        lineWidth = getWidth(textLine, font);\n    }\n\n    if (textLine === '') {\n        textLine = options.placeholder;\n    }\n\n    return textLine;\n}\n\nfunction estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) {\n    var width = 0;\n    var i = 0;\n    for (var len = text.length; i < len && width < contentWidth; i++) {\n        var charCode = text.charCodeAt(i);\n        width += (0 <= charCode && charCode <= 127) ? ascCharWidth : cnCharWidth;\n    }\n    return i;\n}\n\n/**\n * @public\n * @param {string} font\n * @return {number} line height\n */\nfunction getLineHeight(font) {\n    // FIXME A rough approach.\n    return getWidth('国', font);\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @return {Object} width\n */\nfunction measureText(text, font) {\n    return methods$1.measureText(text, font);\n}\n\n// Avoid assign to an exported variable, for transforming to cjs.\nmethods$1.measureText = function (text, font) {\n    var ctx = getContext();\n    ctx.font = font || DEFAULT_FONT$1;\n    return ctx.measureText(text);\n};\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @param {Object} [truncate]\n * @return {Object} block: {lineHeight, lines, height, outerHeight}\n *  Notice: for performance, do not calculate outerWidth util needed.\n */\nfunction parsePlainText(text, font, padding, textLineHeight, truncate) {\n    text != null && (text += '');\n\n    var lineHeight = retrieve2(textLineHeight, getLineHeight(font));\n    var lines = text ? text.split('\\n') : [];\n    var height = lines.length * lineHeight;\n    var outerHeight = height;\n\n    if (padding) {\n        outerHeight += padding[0] + padding[2];\n    }\n\n    if (text && truncate) {\n        var truncOuterHeight = truncate.outerHeight;\n        var truncOuterWidth = truncate.outerWidth;\n        if (truncOuterHeight != null && outerHeight > truncOuterHeight) {\n            text = '';\n            lines = [];\n        }\n        else if (truncOuterWidth != null) {\n            var options = prepareTruncateOptions(\n                truncOuterWidth - (padding ? padding[1] + padding[3] : 0),\n                font,\n                truncate.ellipsis,\n                {minChar: truncate.minChar, placeholder: truncate.placeholder}\n            );\n\n            // FIXME\n            // It is not appropriate that every line has '...' when truncate multiple lines.\n            for (var i = 0, len = lines.length; i < len; i++) {\n                lines[i] = truncateSingleLine(lines[i], options);\n            }\n        }\n    }\n\n    return {\n        lines: lines,\n        height: height,\n        outerHeight: outerHeight,\n        lineHeight: lineHeight\n    };\n}\n\n/**\n * For example: 'some text {a|some text}other text{b|some text}xxx{c|}xxx'\n * Also consider 'bbbb{a|xxx\\nzzz}xxxx\\naaaa'.\n *\n * @public\n * @param {string} text\n * @param {Object} style\n * @return {Object} block\n * {\n *      width,\n *      height,\n *      lines: [{\n *          lineHeight,\n *          width,\n *          tokens: [[{\n *              styleName,\n *              text,\n *              width,      // include textPadding\n *              height,     // include textPadding\n *              textWidth, // pure text width\n *              textHeight, // pure text height\n *              lineHeihgt,\n *              font,\n *              textAlign,\n *              textVerticalAlign\n *          }], [...], ...]\n *      }, ...]\n * }\n * If styleName is undefined, it is plain text.\n */\nfunction parseRichText(text, style) {\n    var contentBlock = {lines: [], width: 0, height: 0};\n\n    text != null && (text += '');\n    if (!text) {\n        return contentBlock;\n    }\n\n    var lastIndex = STYLE_REG.lastIndex = 0;\n    var result;\n    while ((result = STYLE_REG.exec(text)) != null) {\n        var matchedIndex = result.index;\n        if (matchedIndex > lastIndex) {\n            pushTokens(contentBlock, text.substring(lastIndex, matchedIndex));\n        }\n        pushTokens(contentBlock, result[2], result[1]);\n        lastIndex = STYLE_REG.lastIndex;\n    }\n\n    if (lastIndex < text.length) {\n        pushTokens(contentBlock, text.substring(lastIndex, text.length));\n    }\n\n    var lines = contentBlock.lines;\n    var contentHeight = 0;\n    var contentWidth = 0;\n    // For `textWidth: 100%`\n    var pendingList = [];\n\n    var stlPadding = style.textPadding;\n\n    var truncate = style.truncate;\n    var truncateWidth = truncate && truncate.outerWidth;\n    var truncateHeight = truncate && truncate.outerHeight;\n    if (stlPadding) {\n        truncateWidth != null && (truncateWidth -= stlPadding[1] + stlPadding[3]);\n        truncateHeight != null && (truncateHeight -= stlPadding[0] + stlPadding[2]);\n    }\n\n    // Calculate layout info of tokens.\n    for (var i = 0; i < lines.length; i++) {\n        var line = lines[i];\n        var lineHeight = 0;\n        var lineWidth = 0;\n\n        for (var j = 0; j < line.tokens.length; j++) {\n            var token = line.tokens[j];\n            var tokenStyle = token.styleName && style.rich[token.styleName] || {};\n            // textPadding should not inherit from style.\n            var textPadding = token.textPadding = tokenStyle.textPadding;\n\n            // textFont has been asigned to font by `normalizeStyle`.\n            var font = token.font = tokenStyle.font || style.font;\n\n            // textHeight can be used when textVerticalAlign is specified in token.\n            var tokenHeight = token.textHeight = retrieve2(\n                // textHeight should not be inherited, consider it can be specified\n                // as box height of the block.\n                tokenStyle.textHeight, getLineHeight(font)\n            );\n            textPadding && (tokenHeight += textPadding[0] + textPadding[2]);\n            token.height = tokenHeight;\n            token.lineHeight = retrieve3(\n                tokenStyle.textLineHeight, style.textLineHeight, tokenHeight\n            );\n\n            token.textAlign = tokenStyle && tokenStyle.textAlign || style.textAlign;\n            token.textVerticalAlign = tokenStyle && tokenStyle.textVerticalAlign || 'middle';\n\n            if (truncateHeight != null && contentHeight + token.lineHeight > truncateHeight) {\n                return {lines: [], width: 0, height: 0};\n            }\n\n            token.textWidth = getWidth(token.text, font);\n            var tokenWidth = tokenStyle.textWidth;\n            var tokenWidthNotSpecified = tokenWidth == null || tokenWidth === 'auto';\n\n            // Percent width, can be `100%`, can be used in drawing separate\n            // line when box width is needed to be auto.\n            if (typeof tokenWidth === 'string' && tokenWidth.charAt(tokenWidth.length - 1) === '%') {\n                token.percentWidth = tokenWidth;\n                pendingList.push(token);\n                tokenWidth = 0;\n                // Do not truncate in this case, because there is no user case\n                // and it is too complicated.\n            }\n            else {\n                if (tokenWidthNotSpecified) {\n                    tokenWidth = token.textWidth;\n\n                    // FIXME: If image is not loaded and textWidth is not specified, calling\n                    // `getBoundingRect()` will not get correct result.\n                    var textBackgroundColor = tokenStyle.textBackgroundColor;\n                    var bgImg = textBackgroundColor && textBackgroundColor.image;\n\n                    // Use cases:\n                    // (1) If image is not loaded, it will be loaded at render phase and call\n                    // `dirty()` and `textBackgroundColor.image` will be replaced with the loaded\n                    // image, and then the right size will be calculated here at the next tick.\n                    // See `graphic/helper/text.js`.\n                    // (2) If image loaded, and `textBackgroundColor.image` is image src string,\n                    // use `imageHelper.findExistImage` to find cached image.\n                    // `imageHelper.findExistImage` will always be called here before\n                    // `imageHelper.createOrUpdateImage` in `graphic/helper/text.js#renderRichText`\n                    // which ensures that image will not be rendered before correct size calcualted.\n                    if (bgImg) {\n                        bgImg = findExistImage(bgImg);\n                        if (isImageReady(bgImg)) {\n                            tokenWidth = Math.max(tokenWidth, bgImg.width * tokenHeight / bgImg.height);\n                        }\n                    }\n                }\n\n                var paddingW = textPadding ? textPadding[1] + textPadding[3] : 0;\n                tokenWidth += paddingW;\n\n                var remianTruncWidth = truncateWidth != null ? truncateWidth - lineWidth : null;\n\n                if (remianTruncWidth != null && remianTruncWidth < tokenWidth) {\n                    if (!tokenWidthNotSpecified || remianTruncWidth < paddingW) {\n                        token.text = '';\n                        token.textWidth = tokenWidth = 0;\n                    }\n                    else {\n                        token.text = truncateText(\n                            token.text, remianTruncWidth - paddingW, font, truncate.ellipsis,\n                            {minChar: truncate.minChar}\n                        );\n                        token.textWidth = getWidth(token.text, font);\n                        tokenWidth = token.textWidth + paddingW;\n                    }\n                }\n            }\n\n            lineWidth += (token.width = tokenWidth);\n            tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight));\n        }\n\n        line.width = lineWidth;\n        line.lineHeight = lineHeight;\n        contentHeight += lineHeight;\n        contentWidth = Math.max(contentWidth, lineWidth);\n    }\n\n    contentBlock.outerWidth = contentBlock.width = retrieve2(style.textWidth, contentWidth);\n    contentBlock.outerHeight = contentBlock.height = retrieve2(style.textHeight, contentHeight);\n\n    if (stlPadding) {\n        contentBlock.outerWidth += stlPadding[1] + stlPadding[3];\n        contentBlock.outerHeight += stlPadding[0] + stlPadding[2];\n    }\n\n    for (var i = 0; i < pendingList.length; i++) {\n        var token = pendingList[i];\n        var percentWidth = token.percentWidth;\n        // Should not base on outerWidth, because token can not be placed out of padding.\n        token.width = parseInt(percentWidth, 10) / 100 * contentWidth;\n    }\n\n    return contentBlock;\n}\n\nfunction pushTokens(block, str, styleName) {\n    var isEmptyStr = str === '';\n    var strs = str.split('\\n');\n    var lines = block.lines;\n\n    for (var i = 0; i < strs.length; i++) {\n        var text = strs[i];\n        var token = {\n            styleName: styleName,\n            text: text,\n            isLineHolder: !text && !isEmptyStr\n        };\n\n        // The first token should be appended to the last line.\n        if (!i) {\n            var tokens = (lines[lines.length - 1] || (lines[0] = {tokens: []})).tokens;\n\n            // Consider cases:\n            // (1) ''.split('\\n') => ['', '\\n', ''], the '' at the first item\n            // (which is a placeholder) should be replaced by new token.\n            // (2) A image backage, where token likes {a|}.\n            // (3) A redundant '' will affect textAlign in line.\n            // (4) tokens with the same tplName should not be merged, because\n            // they should be displayed in different box (with border and padding).\n            var tokensLen = tokens.length;\n            (tokensLen === 1 && tokens[0].isLineHolder)\n                ? (tokens[0] = token)\n                // Consider text is '', only insert when it is the \"lineHolder\" or\n                // \"emptyStr\". Otherwise a redundant '' will affect textAlign in line.\n                : ((text || !tokensLen || isEmptyStr) && tokens.push(token));\n        }\n        // Other tokens always start a new line.\n        else {\n            // If there is '', insert it as a placeholder.\n            lines.push({tokens: [token]});\n        }\n    }\n}\n\nfunction makeFont(style) {\n    // FIXME in node-canvas fontWeight is before fontStyle\n    // Use `fontSize` `fontFamily` to check whether font properties are defined.\n    var font = (style.fontSize || style.fontFamily) && [\n        style.fontStyle,\n        style.fontWeight,\n        (style.fontSize || 12) + 'px',\n        // If font properties are defined, `fontFamily` should not be ignored.\n        style.fontFamily || 'sans-serif'\n    ].join(' ');\n    return font && trim(font) || style.textFont || style.font;\n}\n\n/**\n * @param {Object} ctx\n * @param {Object} shape\n * @param {number} shape.x\n * @param {number} shape.y\n * @param {number} shape.width\n * @param {number} shape.height\n * @param {number} shape.r\n */\nfunction buildPath(ctx, shape) {\n    var x = shape.x;\n    var y = shape.y;\n    var width = shape.width;\n    var height = shape.height;\n    var r = shape.r;\n    var r1;\n    var r2;\n    var r3;\n    var r4;\n\n    // Convert width and height to positive for better borderRadius\n    if (width < 0) {\n        x = x + width;\n        width = -width;\n    }\n    if (height < 0) {\n        y = y + height;\n        height = -height;\n    }\n\n    if (typeof r === 'number') {\n        r1 = r2 = r3 = r4 = r;\n    }\n    else if (r instanceof Array) {\n        if (r.length === 1) {\n            r1 = r2 = r3 = r4 = r[0];\n        }\n        else if (r.length === 2) {\n            r1 = r3 = r[0];\n            r2 = r4 = r[1];\n        }\n        else if (r.length === 3) {\n            r1 = r[0];\n            r2 = r4 = r[1];\n            r3 = r[2];\n        }\n        else {\n            r1 = r[0];\n            r2 = r[1];\n            r3 = r[2];\n            r4 = r[3];\n        }\n    }\n    else {\n        r1 = r2 = r3 = r4 = 0;\n    }\n\n    var total;\n    if (r1 + r2 > width) {\n        total = r1 + r2;\n        r1 *= width / total;\n        r2 *= width / total;\n    }\n    if (r3 + r4 > width) {\n        total = r3 + r4;\n        r3 *= width / total;\n        r4 *= width / total;\n    }\n    if (r2 + r3 > height) {\n        total = r2 + r3;\n        r2 *= height / total;\n        r3 *= height / total;\n    }\n    if (r1 + r4 > height) {\n        total = r1 + r4;\n        r1 *= height / total;\n        r4 *= height / total;\n    }\n    ctx.moveTo(x + r1, y);\n    ctx.lineTo(x + width - r2, y);\n    r2 !== 0 && ctx.arc(x + width - r2, y + r2, r2, -Math.PI / 2, 0);\n    ctx.lineTo(x + width, y + height - r3);\n    r3 !== 0 && ctx.arc(x + width - r3, y + height - r3, r3, 0, Math.PI / 2);\n    ctx.lineTo(x + r4, y + height);\n    r4 !== 0 && ctx.arc(x + r4, y + height - r4, r4, Math.PI / 2, Math.PI);\n    ctx.lineTo(x, y + r1);\n    r1 !== 0 && ctx.arc(x + r1, y + r1, r1, Math.PI, Math.PI * 1.5);\n}\n\nvar DEFAULT_FONT = DEFAULT_FONT$1;\n\n// TODO: Have not support 'start', 'end' yet.\nvar VALID_TEXT_ALIGN = {left: 1, right: 1, center: 1};\nvar VALID_TEXT_VERTICAL_ALIGN = {top: 1, bottom: 1, middle: 1};\n// Different from `STYLE_COMMON_PROPS` of `graphic/Style`,\n// the default value of shadowColor is `'transparent'`.\nvar SHADOW_STYLE_COMMON_PROPS = [\n    ['textShadowBlur', 'shadowBlur', 0],\n    ['textShadowOffsetX', 'shadowOffsetX', 0],\n    ['textShadowOffsetY', 'shadowOffsetY', 0],\n    ['textShadowColor', 'shadowColor', 'transparent']\n];\n\n/**\n * @param {module:zrender/graphic/Style} style\n * @return {module:zrender/graphic/Style} The input style.\n */\nfunction normalizeTextStyle(style) {\n    normalizeStyle(style);\n    each$1(style.rich, normalizeStyle);\n    return style;\n}\n\nfunction normalizeStyle(style) {\n    if (style) {\n\n        style.font = makeFont(style);\n\n        var textAlign = style.textAlign;\n        textAlign === 'middle' && (textAlign = 'center');\n        style.textAlign = (\n            textAlign == null || VALID_TEXT_ALIGN[textAlign]\n        ) ? textAlign : 'left';\n\n        // Compatible with textBaseline.\n        var textVerticalAlign = style.textVerticalAlign || style.textBaseline;\n        textVerticalAlign === 'center' && (textVerticalAlign = 'middle');\n        style.textVerticalAlign = (\n            textVerticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[textVerticalAlign]\n        ) ? textVerticalAlign : 'top';\n\n        var textPadding = style.textPadding;\n        if (textPadding) {\n            style.textPadding = normalizeCssArray(style.textPadding);\n        }\n    }\n}\n\n/**\n * @param {CanvasRenderingContext2D} ctx\n * @param {string} text\n * @param {module:zrender/graphic/Style} style\n * @param {Object|boolean} [rect] {x, y, width, height}\n *                  If set false, rect text is not used.\n * @param {Element|module:zrender/graphic/helper/constant.WILL_BE_RESTORED} [prevEl] For ctx prop cache.\n */\nfunction renderText(hostEl, ctx, text, style, rect, prevEl) {\n    style.rich\n        ? renderRichText(hostEl, ctx, text, style, rect, prevEl)\n        : renderPlainText(hostEl, ctx, text, style, rect, prevEl);\n}\n\n// Avoid setting to ctx according to prevEl if possible for\n// performance in scenarios of large amount text.\nfunction renderPlainText(hostEl, ctx, text, style, rect, prevEl) {\n    'use strict';\n\n    var needDrawBg = needDrawBackground(style);\n\n    var prevStyle;\n    var checkCache = false;\n    var cachedByMe = ctx.__attrCachedBy === ContextCachedBy.PLAIN_TEXT;\n\n    // Only take and check cache for `Text` el, but not RectText.\n    if (prevEl !== WILL_BE_RESTORED) {\n        if (prevEl) {\n            prevStyle = prevEl.style;\n            checkCache = !needDrawBg && cachedByMe && prevStyle;\n        }\n\n        // Prevent from using cache in `Style::bind`, because of the case:\n        // ctx property is modified by other properties than `Style::bind`\n        // used, and Style::bind is called next.\n        ctx.__attrCachedBy = needDrawBg ? ContextCachedBy.NONE : ContextCachedBy.PLAIN_TEXT;\n    }\n    // Since this will be restored, prevent from using these props to check cache in the next\n    // entering of this method. But do not need to clear other cache like `Style::bind`.\n    else if (cachedByMe) {\n        ctx.__attrCachedBy = ContextCachedBy.NONE;\n    }\n\n    var styleFont = style.font || DEFAULT_FONT;\n    // PENDING\n    // Only `Text` el set `font` and keep it (`RectText` will restore). So theoretically\n    // we can make font cache on ctx, which can cache for text el that are discontinuous.\n    // But layer save/restore needed to be considered.\n    // if (styleFont !== ctx.__fontCache) {\n    //     ctx.font = styleFont;\n    //     if (prevEl !== WILL_BE_RESTORED) {\n    //         ctx.__fontCache = styleFont;\n    //     }\n    // }\n    if (!checkCache || styleFont !== (prevStyle.font || DEFAULT_FONT)) {\n        ctx.font = styleFont;\n    }\n\n    // Use the final font from context-2d, because the final\n    // font might not be the style.font when it is illegal.\n    // But get `ctx.font` might be time consuming.\n    var computedFont = hostEl.__computedFont;\n    if (hostEl.__styleFont !== styleFont) {\n        hostEl.__styleFont = styleFont;\n        computedFont = hostEl.__computedFont = ctx.font;\n    }\n\n    var textPadding = style.textPadding;\n    var textLineHeight = style.textLineHeight;\n\n    var contentBlock = hostEl.__textCotentBlock;\n    if (!contentBlock || hostEl.__dirtyText) {\n        contentBlock = hostEl.__textCotentBlock = parsePlainText(\n            text, computedFont, textPadding, textLineHeight, style.truncate\n        );\n    }\n\n    var outerHeight = contentBlock.outerHeight;\n\n    var textLines = contentBlock.lines;\n    var lineHeight = contentBlock.lineHeight;\n\n    var boxPos = getBoxPosition(outerHeight, style, rect);\n    var baseX = boxPos.baseX;\n    var baseY = boxPos.baseY;\n    var textAlign = boxPos.textAlign || 'left';\n    var textVerticalAlign = boxPos.textVerticalAlign;\n\n    // Origin of textRotation should be the base point of text drawing.\n    applyTextRotation(ctx, style, rect, baseX, baseY);\n\n    var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);\n    var textX = baseX;\n    var textY = boxY;\n\n    if (needDrawBg || textPadding) {\n        // Consider performance, do not call getTextWidth util necessary.\n        var textWidth = getWidth(text, computedFont);\n        var outerWidth = textWidth;\n        textPadding && (outerWidth += textPadding[1] + textPadding[3]);\n        var boxX = adjustTextX(baseX, outerWidth, textAlign);\n\n        needDrawBg && drawBackground(hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight);\n\n        if (textPadding) {\n            textX = getTextXForPadding(baseX, textAlign, textPadding);\n            textY += textPadding[0];\n        }\n    }\n\n    // Always set textAlign and textBase line, because it is difficute to calculate\n    // textAlign from prevEl, and we dont sure whether textAlign will be reset if\n    // font set happened.\n    ctx.textAlign = textAlign;\n    // Force baseline to be \"middle\". Otherwise, if using \"top\", the\n    // text will offset downward a little bit in font \"Microsoft YaHei\".\n    ctx.textBaseline = 'middle';\n    // Set text opacity\n    ctx.globalAlpha = style.opacity || 1;\n\n    // Always set shadowBlur and shadowOffset to avoid leak from displayable.\n    for (var i = 0; i < SHADOW_STYLE_COMMON_PROPS.length; i++) {\n        var propItem = SHADOW_STYLE_COMMON_PROPS[i];\n        var styleProp = propItem[0];\n        var ctxProp = propItem[1];\n        var val = style[styleProp];\n        if (!checkCache || val !== prevStyle[styleProp]) {\n            ctx[ctxProp] = fixShadow(ctx, ctxProp, val || propItem[2]);\n        }\n    }\n\n    // `textBaseline` is set as 'middle'.\n    textY += lineHeight / 2;\n\n    var textStrokeWidth = style.textStrokeWidth;\n    var textStrokeWidthPrev = checkCache ? prevStyle.textStrokeWidth : null;\n    var strokeWidthChanged = !checkCache || textStrokeWidth !== textStrokeWidthPrev;\n    var strokeChanged = !checkCache || strokeWidthChanged || style.textStroke !== prevStyle.textStroke;\n    var textStroke = getStroke(style.textStroke, textStrokeWidth);\n    var textFill = getFill(style.textFill);\n\n    if (textStroke) {\n        if (strokeWidthChanged) {\n            ctx.lineWidth = textStrokeWidth;\n        }\n        if (strokeChanged) {\n            ctx.strokeStyle = textStroke;\n        }\n    }\n    if (textFill) {\n        if (!checkCache || style.textFill !== prevStyle.textFill) {\n            ctx.fillStyle = textFill;\n        }\n    }\n\n    // Optimize simply, in most cases only one line exists.\n    if (textLines.length === 1) {\n        // Fill after stroke so the outline will not cover the main part.\n        textStroke && ctx.strokeText(textLines[0], textX, textY);\n        textFill && ctx.fillText(textLines[0], textX, textY);\n    }\n    else {\n        for (var i = 0; i < textLines.length; i++) {\n            // Fill after stroke so the outline will not cover the main part.\n            textStroke && ctx.strokeText(textLines[i], textX, textY);\n            textFill && ctx.fillText(textLines[i], textX, textY);\n            textY += lineHeight;\n        }\n    }\n}\n\nfunction renderRichText(hostEl, ctx, text, style, rect, prevEl) {\n    // Do not do cache for rich text because of the complexity.\n    // But `RectText` this will be restored, do not need to clear other cache like `Style::bind`.\n    if (prevEl !== WILL_BE_RESTORED) {\n        ctx.__attrCachedBy = ContextCachedBy.NONE;\n    }\n\n    var contentBlock = hostEl.__textCotentBlock;\n\n    if (!contentBlock || hostEl.__dirtyText) {\n        contentBlock = hostEl.__textCotentBlock = parseRichText(text, style);\n    }\n\n    drawRichText(hostEl, ctx, contentBlock, style, rect);\n}\n\nfunction drawRichText(hostEl, ctx, contentBlock, style, rect) {\n    var contentWidth = contentBlock.width;\n    var outerWidth = contentBlock.outerWidth;\n    var outerHeight = contentBlock.outerHeight;\n    var textPadding = style.textPadding;\n\n    var boxPos = getBoxPosition(outerHeight, style, rect);\n    var baseX = boxPos.baseX;\n    var baseY = boxPos.baseY;\n    var textAlign = boxPos.textAlign;\n    var textVerticalAlign = boxPos.textVerticalAlign;\n\n    // Origin of textRotation should be the base point of text drawing.\n    applyTextRotation(ctx, style, rect, baseX, baseY);\n\n    var boxX = adjustTextX(baseX, outerWidth, textAlign);\n    var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);\n    var xLeft = boxX;\n    var lineTop = boxY;\n    if (textPadding) {\n        xLeft += textPadding[3];\n        lineTop += textPadding[0];\n    }\n    var xRight = xLeft + contentWidth;\n\n    needDrawBackground(style) && drawBackground(\n        hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight\n    );\n\n    for (var i = 0; i < contentBlock.lines.length; i++) {\n        var line = contentBlock.lines[i];\n        var tokens = line.tokens;\n        var tokenCount = tokens.length;\n        var lineHeight = line.lineHeight;\n        var usedWidth = line.width;\n\n        var leftIndex = 0;\n        var lineXLeft = xLeft;\n        var lineXRight = xRight;\n        var rightIndex = tokenCount - 1;\n        var token;\n\n        while (\n            leftIndex < tokenCount\n            && (token = tokens[leftIndex], !token.textAlign || token.textAlign === 'left')\n        ) {\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft, 'left');\n            usedWidth -= token.width;\n            lineXLeft += token.width;\n            leftIndex++;\n        }\n\n        while (\n            rightIndex >= 0\n            && (token = tokens[rightIndex], token.textAlign === 'right')\n        ) {\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXRight, 'right');\n            usedWidth -= token.width;\n            lineXRight -= token.width;\n            rightIndex--;\n        }\n\n        // The other tokens are placed as textAlign 'center' if there is enough space.\n        lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - usedWidth) / 2;\n        while (leftIndex <= rightIndex) {\n            token = tokens[leftIndex];\n            // Consider width specified by user, use 'center' rather than 'left'.\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center');\n            lineXLeft += token.width;\n            leftIndex++;\n        }\n\n        lineTop += lineHeight;\n    }\n}\n\nfunction applyTextRotation(ctx, style, rect, x, y) {\n    // textRotation only apply in RectText.\n    if (rect && style.textRotation) {\n        var origin = style.textOrigin;\n        if (origin === 'center') {\n            x = rect.width / 2 + rect.x;\n            y = rect.height / 2 + rect.y;\n        }\n        else if (origin) {\n            x = origin[0] + rect.x;\n            y = origin[1] + rect.y;\n        }\n\n        ctx.translate(x, y);\n        // Positive: anticlockwise\n        ctx.rotate(-style.textRotation);\n        ctx.translate(-x, -y);\n    }\n}\n\nfunction placeToken(hostEl, ctx, token, style, lineHeight, lineTop, x, textAlign) {\n    var tokenStyle = style.rich[token.styleName] || {};\n    tokenStyle.text = token.text;\n\n    // 'ctx.textBaseline' is always set as 'middle', for sake of\n    // the bias of \"Microsoft YaHei\".\n    var textVerticalAlign = token.textVerticalAlign;\n    var y = lineTop + lineHeight / 2;\n    if (textVerticalAlign === 'top') {\n        y = lineTop + token.height / 2;\n    }\n    else if (textVerticalAlign === 'bottom') {\n        y = lineTop + lineHeight - token.height / 2;\n    }\n\n    !token.isLineHolder && needDrawBackground(tokenStyle) && drawBackground(\n        hostEl,\n        ctx,\n        tokenStyle,\n        textAlign === 'right'\n            ? x - token.width\n            : textAlign === 'center'\n            ? x - token.width / 2\n            : x,\n        y - token.height / 2,\n        token.width,\n        token.height\n    );\n\n    var textPadding = token.textPadding;\n    if (textPadding) {\n        x = getTextXForPadding(x, textAlign, textPadding);\n        y -= token.height / 2 - textPadding[2] - token.textHeight / 2;\n    }\n\n    setCtx(ctx, 'shadowBlur', retrieve3(tokenStyle.textShadowBlur, style.textShadowBlur, 0));\n    setCtx(ctx, 'shadowColor', tokenStyle.textShadowColor || style.textShadowColor || 'transparent');\n    setCtx(ctx, 'shadowOffsetX', retrieve3(tokenStyle.textShadowOffsetX, style.textShadowOffsetX, 0));\n    setCtx(ctx, 'shadowOffsetY', retrieve3(tokenStyle.textShadowOffsetY, style.textShadowOffsetY, 0));\n\n    setCtx(ctx, 'textAlign', textAlign);\n    // Force baseline to be \"middle\". Otherwise, if using \"top\", the\n    // text will offset downward a little bit in font \"Microsoft YaHei\".\n    setCtx(ctx, 'textBaseline', 'middle');\n\n    setCtx(ctx, 'font', token.font || DEFAULT_FONT);\n\n    var textStroke = getStroke(tokenStyle.textStroke || style.textStroke, textStrokeWidth);\n    var textFill = getFill(tokenStyle.textFill || style.textFill);\n    var textStrokeWidth = retrieve2(tokenStyle.textStrokeWidth, style.textStrokeWidth);\n\n    // Fill after stroke so the outline will not cover the main part.\n    if (textStroke) {\n        setCtx(ctx, 'lineWidth', textStrokeWidth);\n        setCtx(ctx, 'strokeStyle', textStroke);\n        ctx.strokeText(token.text, x, y);\n    }\n    if (textFill) {\n        setCtx(ctx, 'fillStyle', textFill);\n        ctx.fillText(token.text, x, y);\n    }\n}\n\nfunction needDrawBackground(style) {\n    return !!(\n        style.textBackgroundColor\n        || (style.textBorderWidth && style.textBorderColor)\n    );\n}\n\n// style: {textBackgroundColor, textBorderWidth, textBorderColor, textBorderRadius, text}\n// shape: {x, y, width, height}\nfunction drawBackground(hostEl, ctx, style, x, y, width, height) {\n    var textBackgroundColor = style.textBackgroundColor;\n    var textBorderWidth = style.textBorderWidth;\n    var textBorderColor = style.textBorderColor;\n    var isPlainBg = isString(textBackgroundColor);\n\n    setCtx(ctx, 'shadowBlur', style.textBoxShadowBlur || 0);\n    setCtx(ctx, 'shadowColor', style.textBoxShadowColor || 'transparent');\n    setCtx(ctx, 'shadowOffsetX', style.textBoxShadowOffsetX || 0);\n    setCtx(ctx, 'shadowOffsetY', style.textBoxShadowOffsetY || 0);\n\n    if (isPlainBg || (textBorderWidth && textBorderColor)) {\n        ctx.beginPath();\n        var textBorderRadius = style.textBorderRadius;\n        if (!textBorderRadius) {\n            ctx.rect(x, y, width, height);\n        }\n        else {\n            buildPath(ctx, {\n                x: x, y: y, width: width, height: height, r: textBorderRadius\n            });\n        }\n        ctx.closePath();\n    }\n\n    if (isPlainBg) {\n        setCtx(ctx, 'fillStyle', textBackgroundColor);\n\n        if (style.fillOpacity != null) {\n            var originalGlobalAlpha = ctx.globalAlpha;\n            ctx.globalAlpha = style.fillOpacity * style.opacity;\n            ctx.fill();\n            ctx.globalAlpha = originalGlobalAlpha;\n        }\n        else {\n            ctx.fill();\n        }\n    }\n    else if (isObject$1(textBackgroundColor)) {\n        var image = textBackgroundColor.image;\n\n        image = createOrUpdateImage(\n            image, null, hostEl, onBgImageLoaded, textBackgroundColor\n        );\n        if (image && isImageReady(image)) {\n            ctx.drawImage(image, x, y, width, height);\n        }\n    }\n\n    if (textBorderWidth && textBorderColor) {\n        setCtx(ctx, 'lineWidth', textBorderWidth);\n        setCtx(ctx, 'strokeStyle', textBorderColor);\n\n        if (style.strokeOpacity != null) {\n            var originalGlobalAlpha = ctx.globalAlpha;\n            ctx.globalAlpha = style.strokeOpacity * style.opacity;\n            ctx.stroke();\n            ctx.globalAlpha = originalGlobalAlpha;\n        }\n        else {\n            ctx.stroke();\n        }\n    }\n}\n\nfunction onBgImageLoaded(image, textBackgroundColor) {\n    // Replace image, so that `contain/text.js#parseRichText`\n    // will get correct result in next tick.\n    textBackgroundColor.image = image;\n}\n\nfunction getBoxPosition(blockHeiht, style, rect) {\n    var baseX = style.x || 0;\n    var baseY = style.y || 0;\n    var textAlign = style.textAlign;\n    var textVerticalAlign = style.textVerticalAlign;\n\n    // Text position represented by coord\n    if (rect) {\n        var textPosition = style.textPosition;\n        if (textPosition instanceof Array) {\n            // Percent\n            baseX = rect.x + parsePercent(textPosition[0], rect.width);\n            baseY = rect.y + parsePercent(textPosition[1], rect.height);\n        }\n        else {\n            var res = adjustTextPositionOnRect(\n                textPosition, rect, style.textDistance\n            );\n            baseX = res.x;\n            baseY = res.y;\n            // Default align and baseline when has textPosition\n            textAlign = textAlign || res.textAlign;\n            textVerticalAlign = textVerticalAlign || res.textVerticalAlign;\n        }\n\n        // textOffset is only support in RectText, otherwise\n        // we have to adjust boundingRect for textOffset.\n        var textOffset = style.textOffset;\n        if (textOffset) {\n            baseX += textOffset[0];\n            baseY += textOffset[1];\n        }\n    }\n\n    return {\n        baseX: baseX,\n        baseY: baseY,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\nfunction setCtx(ctx, prop, value) {\n    ctx[prop] = fixShadow(ctx, prop, value);\n    return ctx[prop];\n}\n\n/**\n * @param {string} [stroke] If specified, do not check style.textStroke.\n * @param {string} [lineWidth] If specified, do not check style.textStroke.\n * @param {number} style\n */\nfunction getStroke(stroke, lineWidth) {\n    return (stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none')\n        ? null\n        // TODO pattern and gradient?\n        : (stroke.image || stroke.colorStops)\n        ? '#000'\n        : stroke;\n}\n\nfunction getFill(fill) {\n    return (fill == null || fill === 'none')\n        ? null\n        // TODO pattern and gradient?\n        : (fill.image || fill.colorStops)\n        ? '#000'\n        : fill;\n}\n\nfunction parsePercent(value, maxValue) {\n    if (typeof value === 'string') {\n        if (value.lastIndexOf('%') >= 0) {\n            return parseFloat(value) / 100 * maxValue;\n        }\n        return parseFloat(value);\n    }\n    return value;\n}\n\nfunction getTextXForPadding(x, textAlign, textPadding) {\n    return textAlign === 'right'\n        ? (x - textPadding[1])\n        : textAlign === 'center'\n        ? (x + textPadding[3] / 2 - textPadding[1] / 2)\n        : (x + textPadding[3]);\n}\n\n/**\n * @param {string} text\n * @param {module:zrender/Style} style\n * @return {boolean}\n */\nfunction needDrawText(text, style) {\n    return text != null\n        && (text\n            || style.textBackgroundColor\n            || (style.textBorderWidth && style.textBorderColor)\n            || style.textPadding\n        );\n}\n\n/**\n * Mixin for drawing text in a element bounding rect\n * @module zrender/mixin/RectText\n */\n\nvar tmpRect$1 = new BoundingRect();\n\nvar RectText = function () {};\n\nRectText.prototype = {\n\n    constructor: RectText,\n\n    /**\n     * Draw text in a rect with specified position.\n     * @param  {CanvasRenderingContext2D} ctx\n     * @param  {Object} rect Displayable rect\n     */\n    drawRectText: function (ctx, rect) {\n        var style = this.style;\n\n        rect = style.textRect || rect;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        var text = style.text;\n\n        // Convert to string\n        text != null && (text += '');\n\n        if (!needDrawText(text, style)) {\n            return;\n        }\n\n        // FIXME\n        // Do not provide prevEl to `textHelper.renderText` for ctx prop cache,\n        // but use `ctx.save()` and `ctx.restore()`. Because the cache for rect\n        // text propably break the cache for its host elements.\n        ctx.save();\n\n        // Transform rect to view space\n        var transform = this.transform;\n        if (!style.transformText) {\n            if (transform) {\n                tmpRect$1.copy(rect);\n                tmpRect$1.applyTransform(transform);\n                rect = tmpRect$1;\n            }\n        }\n        else {\n            this.setTransform(ctx);\n        }\n\n        // transformText and textRotation can not be used at the same time.\n        renderText(this, ctx, text, style, rect, WILL_BE_RESTORED);\n\n        ctx.restore();\n    }\n};\n\n/**\n * 可绘制的图形基类\n * Base class of all displayable graphic objects\n * @module zrender/graphic/Displayable\n */\n\n\n/**\n * @alias module:zrender/graphic/Displayable\n * @extends module:zrender/Element\n * @extends module:zrender/graphic/mixin/RectText\n */\nfunction Displayable(opts) {\n\n    opts = opts || {};\n\n    Element.call(this, opts);\n\n    // Extend properties\n    for (var name in opts) {\n        if (\n            opts.hasOwnProperty(name)\n                && name !== 'style'\n        ) {\n            this[name] = opts[name];\n        }\n    }\n\n    /**\n     * @type {module:zrender/graphic/Style}\n     */\n    this.style = new Style(opts.style, this);\n\n    this._rect = null;\n    // Shapes for cascade clipping.\n    this.__clipPaths = [];\n\n    // FIXME Stateful must be mixined after style is setted\n    // Stateful.call(this, opts);\n}\n\nDisplayable.prototype = {\n\n    constructor: Displayable,\n\n    type: 'displayable',\n\n    /**\n     * Displayable 是否为脏，Painter 中会根据该标记判断是否需要是否需要重新绘制\n     * Dirty flag. From which painter will determine if this displayable object needs brush\n     * @name module:zrender/graphic/Displayable#__dirty\n     * @type {boolean}\n     */\n    __dirty: true,\n\n    /**\n     * 图形是否可见，为true时不绘制图形，但是仍能触发鼠标事件\n     * If ignore drawing of the displayable object. Mouse event will still be triggered\n     * @name module:/zrender/graphic/Displayable#invisible\n     * @type {boolean}\n     * @default false\n     */\n    invisible: false,\n\n    /**\n     * @name module:/zrender/graphic/Displayable#z\n     * @type {number}\n     * @default 0\n     */\n    z: 0,\n\n    /**\n     * @name module:/zrender/graphic/Displayable#z\n     * @type {number}\n     * @default 0\n     */\n    z2: 0,\n\n    /**\n     * z层level，决定绘画在哪层canvas中\n     * @name module:/zrender/graphic/Displayable#zlevel\n     * @type {number}\n     * @default 0\n     */\n    zlevel: 0,\n\n    /**\n     * 是否可拖拽\n     * @name module:/zrender/graphic/Displayable#draggable\n     * @type {boolean}\n     * @default false\n     */\n    draggable: false,\n\n    /**\n     * 是否正在拖拽\n     * @name module:/zrender/graphic/Displayable#draggable\n     * @type {boolean}\n     * @default false\n     */\n    dragging: false,\n\n    /**\n     * 是否相应鼠标事件\n     * @name module:/zrender/graphic/Displayable#silent\n     * @type {boolean}\n     * @default false\n     */\n    silent: false,\n\n    /**\n     * If enable culling\n     * @type {boolean}\n     * @default false\n     */\n    culling: false,\n\n    /**\n     * Mouse cursor when hovered\n     * @name module:/zrender/graphic/Displayable#cursor\n     * @type {string}\n     */\n    cursor: 'pointer',\n\n    /**\n     * If hover area is bounding rect\n     * @name module:/zrender/graphic/Displayable#rectHover\n     * @type {string}\n     */\n    rectHover: false,\n\n    /**\n     * Render the element progressively when the value >= 0,\n     * usefull for large data.\n     * @type {boolean}\n     */\n    progressive: false,\n\n    /**\n     * @type {boolean}\n     */\n    incremental: false,\n    /**\n     * Scale ratio for global scale.\n     * @type {boolean}\n     */\n    globalScaleRatio: 1,\n\n    beforeBrush: function (ctx) {},\n\n    afterBrush: function (ctx) {},\n\n    /**\n     * 图形绘制方法\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    // Interface\n    brush: function (ctx, prevEl) {},\n\n    /**\n     * 获取最小包围盒\n     * @return {module:zrender/core/BoundingRect}\n     */\n    // Interface\n    getBoundingRect: function () {},\n\n    /**\n     * 判断坐标 x, y 是否在图形上\n     * If displayable element contain coord x, y\n     * @param  {number} x\n     * @param  {number} y\n     * @return {boolean}\n     */\n    contain: function (x, y) {\n        return this.rectContain(x, y);\n    },\n\n    /**\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {\n        cb.call(context, this);\n    },\n\n    /**\n     * 判断坐标 x, y 是否在图形的包围盒上\n     * If bounding rect of element contain coord x, y\n     * @param  {number} x\n     * @param  {number} y\n     * @return {boolean}\n     */\n    rectContain: function (x, y) {\n        var coord = this.transformCoordToLocal(x, y);\n        var rect = this.getBoundingRect();\n        return rect.contain(coord[0], coord[1]);\n    },\n\n    /**\n     * 标记图形元素为脏，并且在下一帧重绘\n     * Mark displayable element dirty and refresh next frame\n     */\n    dirty: function () {\n        this.__dirty = this.__dirtyText = true;\n\n        this._rect = null;\n\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * 图形是否会触发事件\n     * If displayable object binded any event\n     * @return {boolean}\n     */\n    // TODO, 通过 bind 绑定的事件\n    // isSilent: function () {\n    //     return !(\n    //         this.hoverable || this.draggable\n    //         || this.onmousemove || this.onmouseover || this.onmouseout\n    //         || this.onmousedown || this.onmouseup || this.onclick\n    //         || this.ondragenter || this.ondragover || this.ondragleave\n    //         || this.ondrop\n    //     );\n    // },\n    /**\n     * Alias for animate('style')\n     * @param {boolean} loop\n     */\n    animateStyle: function (loop) {\n        return this.animate('style', loop);\n    },\n\n    attrKV: function (key, value) {\n        if (key !== 'style') {\n            Element.prototype.attrKV.call(this, key, value);\n        }\n        else {\n            this.style.set(value);\n        }\n    },\n\n    /**\n     * @param {Object|string} key\n     * @param {*} value\n     */\n    setStyle: function (key, value) {\n        this.style.set(key, value);\n        this.dirty(false);\n        return this;\n    },\n\n    /**\n     * Use given style object\n     * @param  {Object} obj\n     */\n    useStyle: function (obj) {\n        this.style = new Style(obj, this);\n        this.dirty(false);\n        return this;\n    }\n};\n\ninherits(Displayable, Element);\n\nmixin(Displayable, RectText);\n\n/**\n * @alias zrender/graphic/Image\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nfunction ZImage(opts) {\n    Displayable.call(this, opts);\n}\n\nZImage.prototype = {\n\n    constructor: ZImage,\n\n    type: 'image',\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n        var src = style.image;\n\n        // Must bind each time\n        style.bind(ctx, this, prevEl);\n\n        var image = this._image = createOrUpdateImage(\n            src,\n            this._image,\n            this,\n            this.onload\n        );\n\n        if (!image || !isImageReady(image)) {\n            return;\n        }\n\n        // 图片已经加载完成\n        // if (image.nodeName.toUpperCase() == 'IMG') {\n        //     if (!image.complete) {\n        //         return;\n        //     }\n        // }\n        // Else is canvas\n\n        var x = style.x || 0;\n        var y = style.y || 0;\n        var width = style.width;\n        var height = style.height;\n        var aspect = image.width / image.height;\n        if (width == null && height != null) {\n            // Keep image/height ratio\n            width = height * aspect;\n        }\n        else if (height == null && width != null) {\n            height = width / aspect;\n        }\n        else if (width == null && height == null) {\n            width = image.width;\n            height = image.height;\n        }\n\n        // 设置transform\n        this.setTransform(ctx);\n\n        if (style.sWidth && style.sHeight) {\n            var sx = style.sx || 0;\n            var sy = style.sy || 0;\n            ctx.drawImage(\n                image,\n                sx, sy, style.sWidth, style.sHeight,\n                x, y, width, height\n            );\n        }\n        else if (style.sx && style.sy) {\n            var sx = style.sx;\n            var sy = style.sy;\n            var sWidth = width - sx;\n            var sHeight = height - sy;\n            ctx.drawImage(\n                image,\n                sx, sy, sWidth, sHeight,\n                x, y, width, height\n            );\n        }\n        else {\n            ctx.drawImage(image, x, y, width, height);\n        }\n\n        // Draw rect text\n        if (style.text != null) {\n            // Only restore transform when needs draw text.\n            this.restoreTransform(ctx);\n            this.drawRectText(ctx, this.getBoundingRect());\n        }\n    },\n\n    getBoundingRect: function () {\n        var style = this.style;\n        if (!this._rect) {\n            this._rect = new BoundingRect(\n                style.x || 0, style.y || 0, style.width || 0, style.height || 0\n            );\n        }\n        return this._rect;\n    }\n};\n\ninherits(ZImage, Displayable);\n\nvar HOVER_LAYER_ZLEVEL = 1e5;\nvar CANVAS_ZLEVEL = 314159;\n\nvar EL_AFTER_INCREMENTAL_INC = 0.01;\nvar INCREMENTAL_INC = 0.001;\n\nfunction parseInt10(val) {\n    return parseInt(val, 10);\n}\n\nfunction isLayerValid(layer) {\n    if (!layer) {\n        return false;\n    }\n\n    if (layer.__builtin__) {\n        return true;\n    }\n\n    if (typeof (layer.resize) !== 'function'\n        || typeof (layer.refresh) !== 'function'\n    ) {\n        return false;\n    }\n\n    return true;\n}\n\nvar tmpRect = new BoundingRect(0, 0, 0, 0);\nvar viewRect = new BoundingRect(0, 0, 0, 0);\nfunction isDisplayableCulled(el, width, height) {\n    tmpRect.copy(el.getBoundingRect());\n    if (el.transform) {\n        tmpRect.applyTransform(el.transform);\n    }\n    viewRect.width = width;\n    viewRect.height = height;\n    return !tmpRect.intersect(viewRect);\n}\n\nfunction isClipPathChanged(clipPaths, prevClipPaths) {\n    if (clipPaths === prevClipPaths) { // Can both be null or undefined\n        return false;\n    }\n\n    if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) {\n        return true;\n    }\n    for (var i = 0; i < clipPaths.length; i++) {\n        if (clipPaths[i] !== prevClipPaths[i]) {\n            return true;\n        }\n    }\n}\n\nfunction doClip(clipPaths, ctx) {\n    for (var i = 0; i < clipPaths.length; i++) {\n        var clipPath = clipPaths[i];\n\n        clipPath.setTransform(ctx);\n        ctx.beginPath();\n        clipPath.buildPath(ctx, clipPath.shape);\n        ctx.clip();\n        // Transform back\n        clipPath.restoreTransform(ctx);\n    }\n}\n\nfunction createRoot(width, height) {\n    var domRoot = document.createElement('div');\n\n    // domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬\n    domRoot.style.cssText = [\n        'position:relative',\n        'overflow:hidden',\n        'width:' + width + 'px',\n        'height:' + height + 'px',\n        'padding:0',\n        'margin:0',\n        'border-width:0'\n    ].join(';') + ';';\n\n    return domRoot;\n}\n\n\n/**\n * @alias module:zrender/Painter\n * @constructor\n * @param {HTMLElement} root 绘图容器\n * @param {module:zrender/Storage} storage\n * @param {Object} opts\n */\nvar Painter = function (root, storage, opts) {\n\n    this.type = 'canvas';\n\n    // In node environment using node-canvas\n    var singleCanvas = !root.nodeName // In node ?\n        || root.nodeName.toUpperCase() === 'CANVAS';\n\n    this._opts = opts = extend({}, opts || {});\n\n    /**\n     * @type {number}\n     */\n    this.dpr = opts.devicePixelRatio || devicePixelRatio;\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._singleCanvas = singleCanvas;\n    /**\n     * 绘图容器\n     * @type {HTMLElement}\n     */\n    this.root = root;\n\n    var rootStyle = root.style;\n\n    if (rootStyle) {\n        rootStyle['-webkit-tap-highlight-color'] = 'transparent';\n        rootStyle['-webkit-user-select'] =\n        rootStyle['user-select'] =\n        rootStyle['-webkit-touch-callout'] = 'none';\n\n        root.innerHTML = '';\n    }\n\n    /**\n     * @type {module:zrender/Storage}\n     */\n    this.storage = storage;\n\n    /**\n     * @type {Array.<number>}\n     * @private\n     */\n    var zlevelList = this._zlevelList = [];\n\n    /**\n     * @type {Object.<string, module:zrender/Layer>}\n     * @private\n     */\n    var layers = this._layers = {};\n\n    /**\n     * @type {Object.<string, Object>}\n     * @private\n     */\n    this._layerConfig = {};\n\n    /**\n     * zrender will do compositing when root is a canvas and have multiple zlevels.\n     */\n    this._needsManuallyCompositing = false;\n\n    if (!singleCanvas) {\n        this._width = this._getSize(0);\n        this._height = this._getSize(1);\n\n        var domRoot = this._domRoot = createRoot(\n            this._width, this._height\n        );\n        root.appendChild(domRoot);\n    }\n    else {\n        var width = root.width;\n        var height = root.height;\n\n        if (opts.width != null) {\n            width = opts.width;\n        }\n        if (opts.height != null) {\n            height = opts.height;\n        }\n        this.dpr = opts.devicePixelRatio || 1;\n\n        // Use canvas width and height directly\n        root.width = width * this.dpr;\n        root.height = height * this.dpr;\n\n        this._width = width;\n        this._height = height;\n\n        // Create layer if only one given canvas\n        // Device can be specified to create a high dpi image.\n        var mainLayer = new Layer(root, this, this.dpr);\n        mainLayer.__builtin__ = true;\n        mainLayer.initContext();\n        // FIXME Use canvas width and height\n        // mainLayer.resize(width, height);\n        layers[CANVAS_ZLEVEL] = mainLayer;\n        mainLayer.zlevel = CANVAS_ZLEVEL;\n        // Not use common zlevel.\n        zlevelList.push(CANVAS_ZLEVEL);\n\n        this._domRoot = root;\n    }\n\n    /**\n     * @type {module:zrender/Layer}\n     * @private\n     */\n    this._hoverlayer = null;\n\n    this._hoverElements = [];\n};\n\nPainter.prototype = {\n\n    constructor: Painter,\n\n    getType: function () {\n        return 'canvas';\n    },\n\n    /**\n     * If painter use a single canvas\n     * @return {boolean}\n     */\n    isSingleCanvas: function () {\n        return this._singleCanvas;\n    },\n    /**\n     * @return {HTMLDivElement}\n     */\n    getViewportRoot: function () {\n        return this._domRoot;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    /**\n     * 刷新\n     * @param {boolean} [paintAll=false] 强制绘制所有displayable\n     */\n    refresh: function (paintAll) {\n\n        var list = this.storage.getDisplayList(true);\n\n        var zlevelList = this._zlevelList;\n\n        this._redrawId = Math.random();\n\n        this._paintList(list, paintAll, this._redrawId);\n\n        // Paint custum layers\n        for (var i = 0; i < zlevelList.length; i++) {\n            var z = zlevelList[i];\n            var layer = this._layers[z];\n            if (!layer.__builtin__ && layer.refresh) {\n                var clearColor = i === 0 ? this._backgroundColor : null;\n                layer.refresh(clearColor);\n            }\n        }\n\n        this.refreshHover();\n\n        return this;\n    },\n\n    addHover: function (el, hoverStyle) {\n        if (el.__hoverMir) {\n            return;\n        }\n        var elMirror = new el.constructor({\n            style: el.style,\n            shape: el.shape,\n            z: el.z,\n            z2: el.z2,\n            silent: el.silent\n        });\n        elMirror.__from = el;\n        el.__hoverMir = elMirror;\n        hoverStyle && elMirror.setStyle(hoverStyle);\n        this._hoverElements.push(elMirror);\n\n        return elMirror;\n    },\n\n    removeHover: function (el) {\n        var elMirror = el.__hoverMir;\n        var hoverElements = this._hoverElements;\n        var idx = indexOf(hoverElements, elMirror);\n        if (idx >= 0) {\n            hoverElements.splice(idx, 1);\n        }\n        el.__hoverMir = null;\n    },\n\n    clearHover: function (el) {\n        var hoverElements = this._hoverElements;\n        for (var i = 0; i < hoverElements.length; i++) {\n            var from = hoverElements[i].__from;\n            if (from) {\n                from.__hoverMir = null;\n            }\n        }\n        hoverElements.length = 0;\n    },\n\n    refreshHover: function () {\n        var hoverElements = this._hoverElements;\n        var len = hoverElements.length;\n        var hoverLayer = this._hoverlayer;\n        hoverLayer && hoverLayer.clear();\n\n        if (!len) {\n            return;\n        }\n        sort(hoverElements, this.storage.displayableSortFunc);\n\n        // Use a extream large zlevel\n        // FIXME?\n        if (!hoverLayer) {\n            hoverLayer = this._hoverlayer = this.getLayer(HOVER_LAYER_ZLEVEL);\n        }\n\n        var scope = {};\n        hoverLayer.ctx.save();\n        for (var i = 0; i < len;) {\n            var el = hoverElements[i];\n            var originalEl = el.__from;\n            // Original el is removed\n            // PENDING\n            if (!(originalEl && originalEl.__zr)) {\n                hoverElements.splice(i, 1);\n                originalEl.__hoverMir = null;\n                len--;\n                continue;\n            }\n            i++;\n\n            // Use transform\n            // FIXME style and shape ?\n            if (!originalEl.invisible) {\n                el.transform = originalEl.transform;\n                el.invTransform = originalEl.invTransform;\n                el.__clipPaths = originalEl.__clipPaths;\n                // el.\n                this._doPaintEl(el, hoverLayer, true, scope);\n            }\n        }\n\n        hoverLayer.ctx.restore();\n    },\n\n    getHoverLayer: function () {\n        return this.getLayer(HOVER_LAYER_ZLEVEL);\n    },\n\n    _paintList: function (list, paintAll, redrawId) {\n        if (this._redrawId !== redrawId) {\n            return;\n        }\n\n        paintAll = paintAll || false;\n\n        this._updateLayerStatus(list);\n\n        var finished = this._doPaintList(list, paintAll);\n\n        if (this._needsManuallyCompositing) {\n            this._compositeManually();\n        }\n\n        if (!finished) {\n            var self = this;\n            requestAnimationFrame(function () {\n                self._paintList(list, paintAll, redrawId);\n            });\n        }\n    },\n\n    _compositeManually: function () {\n        var ctx = this.getLayer(CANVAS_ZLEVEL).ctx;\n        var width = this._domRoot.width;\n        var height = this._domRoot.height;\n        ctx.clearRect(0, 0, width, height);\n        // PENDING, If only builtin layer?\n        this.eachBuiltinLayer(function (layer) {\n            if (layer.virtual) {\n                ctx.drawImage(layer.dom, 0, 0, width, height);\n            }\n        });\n    },\n\n    _doPaintList: function (list, paintAll) {\n        var layerList = [];\n        for (var zi = 0; zi < this._zlevelList.length; zi++) {\n            var zlevel = this._zlevelList[zi];\n            var layer = this._layers[zlevel];\n            if (layer.__builtin__\n                && layer !== this._hoverlayer\n                && (layer.__dirty || paintAll)\n            ) {\n                layerList.push(layer);\n            }\n        }\n\n        var finished = true;\n\n        for (var k = 0; k < layerList.length; k++) {\n            var layer = layerList[k];\n            var ctx = layer.ctx;\n            var scope = {};\n            ctx.save();\n\n            var start = paintAll ? layer.__startIndex : layer.__drawIndex;\n\n            var useTimer = !paintAll && layer.incremental && Date.now;\n            var startTime = useTimer && Date.now();\n\n            var clearColor = layer.zlevel === this._zlevelList[0]\n                ? this._backgroundColor : null;\n            // All elements in this layer are cleared.\n            if (layer.__startIndex === layer.__endIndex) {\n                layer.clear(false, clearColor);\n            }\n            else if (start === layer.__startIndex) {\n                var firstEl = list[start];\n                if (!firstEl.incremental || !firstEl.notClear || paintAll) {\n                    layer.clear(false, clearColor);\n                }\n            }\n            if (start === -1) {\n                console.error('For some unknown reason. drawIndex is -1');\n                start = layer.__startIndex;\n            }\n            for (var i = start; i < layer.__endIndex; i++) {\n                var el = list[i];\n                this._doPaintEl(el, layer, paintAll, scope);\n                el.__dirty = el.__dirtyText = false;\n\n                if (useTimer) {\n                    // Date.now can be executed in 13,025,305 ops/second.\n                    var dTime = Date.now() - startTime;\n                    // Give 15 millisecond to draw.\n                    // The rest elements will be drawn in the next frame.\n                    if (dTime > 15) {\n                        break;\n                    }\n                }\n            }\n\n            layer.__drawIndex = i;\n\n            if (layer.__drawIndex < layer.__endIndex) {\n                finished = false;\n            }\n\n            if (scope.prevElClipPaths) {\n                // Needs restore the state. If last drawn element is in the clipping area.\n                ctx.restore();\n            }\n\n            ctx.restore();\n        }\n\n        if (env$1.wxa) {\n            // Flush for weixin application\n            each$1(this._layers, function (layer) {\n                if (layer && layer.ctx && layer.ctx.draw) {\n                    layer.ctx.draw();\n                }\n            });\n        }\n\n        return finished;\n    },\n\n    _doPaintEl: function (el, currentLayer, forcePaint, scope) {\n        var ctx = currentLayer.ctx;\n        var m = el.transform;\n        if (\n            (currentLayer.__dirty || forcePaint)\n            // Ignore invisible element\n            && !el.invisible\n            // Ignore transparent element\n            && el.style.opacity !== 0\n            // Ignore scale 0 element, in some environment like node-canvas\n            // Draw a scale 0 element can cause all following draw wrong\n            // And setTransform with scale 0 will cause set back transform failed.\n            && !(m && !m[0] && !m[3])\n            // Ignore culled element\n            && !(el.culling && isDisplayableCulled(el, this._width, this._height))\n        ) {\n\n            var clipPaths = el.__clipPaths;\n\n            // Optimize when clipping on group with several elements\n            if (!scope.prevElClipPaths\n                || isClipPathChanged(clipPaths, scope.prevElClipPaths)\n            ) {\n                // If has previous clipping state, restore from it\n                if (scope.prevElClipPaths) {\n                    currentLayer.ctx.restore();\n                    scope.prevElClipPaths = null;\n\n                    // Reset prevEl since context has been restored\n                    scope.prevEl = null;\n                }\n                // New clipping state\n                if (clipPaths) {\n                    ctx.save();\n                    doClip(clipPaths, ctx);\n                    scope.prevElClipPaths = clipPaths;\n                }\n            }\n            el.beforeBrush && el.beforeBrush(ctx);\n\n            el.brush(ctx, scope.prevEl || null);\n            scope.prevEl = el;\n\n            el.afterBrush && el.afterBrush(ctx);\n        }\n    },\n\n    /**\n     * 获取 zlevel 所在层，如果不存在则会创建一个新的层\n     * @param {number} zlevel\n     * @param {boolean} virtual Virtual layer will not be inserted into dom.\n     * @return {module:zrender/Layer}\n     */\n    getLayer: function (zlevel, virtual) {\n        if (this._singleCanvas && !this._needsManuallyCompositing) {\n            zlevel = CANVAS_ZLEVEL;\n        }\n        var layer = this._layers[zlevel];\n        if (!layer) {\n            // Create a new layer\n            layer = new Layer('zr_' + zlevel, this, this.dpr);\n            layer.zlevel = zlevel;\n            layer.__builtin__ = true;\n\n            if (this._layerConfig[zlevel]) {\n                merge(layer, this._layerConfig[zlevel], true);\n            }\n\n            if (virtual) {\n                layer.virtual = virtual;\n            }\n\n            this.insertLayer(zlevel, layer);\n\n            // Context is created after dom inserted to document\n            // Or excanvas will get 0px clientWidth and clientHeight\n            layer.initContext();\n        }\n\n        return layer;\n    },\n\n    insertLayer: function (zlevel, layer) {\n\n        var layersMap = this._layers;\n        var zlevelList = this._zlevelList;\n        var len = zlevelList.length;\n        var prevLayer = null;\n        var i = -1;\n        var domRoot = this._domRoot;\n\n        if (layersMap[zlevel]) {\n            zrLog('ZLevel ' + zlevel + ' has been used already');\n            return;\n        }\n        // Check if is a valid layer\n        if (!isLayerValid(layer)) {\n            zrLog('Layer of zlevel ' + zlevel + ' is not valid');\n            return;\n        }\n\n        if (len > 0 && zlevel > zlevelList[0]) {\n            for (i = 0; i < len - 1; i++) {\n                if (\n                    zlevelList[i] < zlevel\n                    && zlevelList[i + 1] > zlevel\n                ) {\n                    break;\n                }\n            }\n            prevLayer = layersMap[zlevelList[i]];\n        }\n        zlevelList.splice(i + 1, 0, zlevel);\n\n        layersMap[zlevel] = layer;\n\n        // Vitual layer will not directly show on the screen.\n        // (It can be a WebGL layer and assigned to a ZImage element)\n        // But it still under management of zrender.\n        if (!layer.virtual) {\n            if (prevLayer) {\n                var prevDom = prevLayer.dom;\n                if (prevDom.nextSibling) {\n                    domRoot.insertBefore(\n                        layer.dom,\n                        prevDom.nextSibling\n                    );\n                }\n                else {\n                    domRoot.appendChild(layer.dom);\n                }\n            }\n            else {\n                if (domRoot.firstChild) {\n                    domRoot.insertBefore(layer.dom, domRoot.firstChild);\n                }\n                else {\n                    domRoot.appendChild(layer.dom);\n                }\n            }\n        }\n    },\n\n    // Iterate each layer\n    eachLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            cb.call(context, this._layers[z], z);\n        }\n    },\n\n    // Iterate each buildin layer\n    eachBuiltinLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var layer;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            layer = this._layers[z];\n            if (layer.__builtin__) {\n                cb.call(context, layer, z);\n            }\n        }\n    },\n\n    // Iterate each other layer except buildin layer\n    eachOtherLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var layer;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            layer = this._layers[z];\n            if (!layer.__builtin__) {\n                cb.call(context, layer, z);\n            }\n        }\n    },\n\n    /**\n     * 获取所有已创建的层\n     * @param {Array.<module:zrender/Layer>} [prevLayer]\n     */\n    getLayers: function () {\n        return this._layers;\n    },\n\n    _updateLayerStatus: function (list) {\n\n        this.eachBuiltinLayer(function (layer, z) {\n            layer.__dirty = layer.__used = false;\n        });\n\n        function updatePrevLayer(idx) {\n            if (prevLayer) {\n                if (prevLayer.__endIndex !== idx) {\n                    prevLayer.__dirty = true;\n                }\n                prevLayer.__endIndex = idx;\n            }\n        }\n\n        if (this._singleCanvas) {\n            for (var i = 1; i < list.length; i++) {\n                var el = list[i];\n                if (el.zlevel !== list[i - 1].zlevel || el.incremental) {\n                    this._needsManuallyCompositing = true;\n                    break;\n                }\n            }\n        }\n\n        var prevLayer = null;\n        var incrementalLayerCount = 0;\n        for (var i = 0; i < list.length; i++) {\n            var el = list[i];\n            var zlevel = el.zlevel;\n            var layer;\n            // PENDING If change one incremental element style ?\n            // TODO Where there are non-incremental elements between incremental elements.\n            if (el.incremental) {\n                layer = this.getLayer(zlevel + INCREMENTAL_INC, this._needsManuallyCompositing);\n                layer.incremental = true;\n                incrementalLayerCount = 1;\n            }\n            else {\n                layer = this.getLayer(zlevel + (incrementalLayerCount > 0 ? EL_AFTER_INCREMENTAL_INC : 0), this._needsManuallyCompositing);\n            }\n\n            if (!layer.__builtin__) {\n                zrLog('ZLevel ' + zlevel + ' has been used by unkown layer ' + layer.id);\n            }\n\n            if (layer !== prevLayer) {\n                layer.__used = true;\n                if (layer.__startIndex !== i) {\n                    layer.__dirty = true;\n                }\n                layer.__startIndex = i;\n                if (!layer.incremental) {\n                    layer.__drawIndex = i;\n                }\n                else {\n                    // Mark layer draw index needs to update.\n                    layer.__drawIndex = -1;\n                }\n                updatePrevLayer(i);\n                prevLayer = layer;\n            }\n            if (el.__dirty) {\n                layer.__dirty = true;\n                if (layer.incremental && layer.__drawIndex < 0) {\n                    // Start draw from the first dirty element.\n                    layer.__drawIndex = i;\n                }\n            }\n        }\n\n        updatePrevLayer(i);\n\n        this.eachBuiltinLayer(function (layer, z) {\n            // Used in last frame but not in this frame. Needs clear\n            if (!layer.__used && layer.getElementCount() > 0) {\n                layer.__dirty = true;\n                layer.__startIndex = layer.__endIndex = layer.__drawIndex = 0;\n            }\n            // For incremental layer. In case start index changed and no elements are dirty.\n            if (layer.__dirty && layer.__drawIndex < 0) {\n                layer.__drawIndex = layer.__startIndex;\n            }\n        });\n    },\n\n    /**\n     * 清除hover层外所有内容\n     */\n    clear: function () {\n        this.eachBuiltinLayer(this._clearLayer);\n        return this;\n    },\n\n    _clearLayer: function (layer) {\n        layer.clear();\n    },\n\n    setBackgroundColor: function (backgroundColor) {\n        this._backgroundColor = backgroundColor;\n    },\n\n    /**\n     * 修改指定zlevel的绘制参数\n     *\n     * @param {string} zlevel\n     * @param {Object} config 配置对象\n     * @param {string} [config.clearColor=0] 每次清空画布的颜色\n     * @param {string} [config.motionBlur=false] 是否开启动态模糊\n     * @param {number} [config.lastFrameAlpha=0.7]\n     *                 在开启动态模糊的时候使用，与上一帧混合的alpha值，值越大尾迹越明显\n     */\n    configLayer: function (zlevel, config) {\n        if (config) {\n            var layerConfig = this._layerConfig;\n            if (!layerConfig[zlevel]) {\n                layerConfig[zlevel] = config;\n            }\n            else {\n                merge(layerConfig[zlevel], config, true);\n            }\n\n            for (var i = 0; i < this._zlevelList.length; i++) {\n                var _zlevel = this._zlevelList[i];\n                if (_zlevel === zlevel || _zlevel === zlevel + EL_AFTER_INCREMENTAL_INC) {\n                    var layer = this._layers[_zlevel];\n                    merge(layer, layerConfig[zlevel], true);\n                }\n            }\n        }\n    },\n\n    /**\n     * 删除指定层\n     * @param {number} zlevel 层所在的zlevel\n     */\n    delLayer: function (zlevel) {\n        var layers = this._layers;\n        var zlevelList = this._zlevelList;\n        var layer = layers[zlevel];\n        if (!layer) {\n            return;\n        }\n        layer.dom.parentNode.removeChild(layer.dom);\n        delete layers[zlevel];\n\n        zlevelList.splice(indexOf(zlevelList, zlevel), 1);\n    },\n\n    /**\n     * 区域大小变化后重绘\n     */\n    resize: function (width, height) {\n        if (!this._domRoot.style) { // Maybe in node or worker\n            if (width == null || height == null) {\n                return;\n            }\n            this._width = width;\n            this._height = height;\n\n            this.getLayer(CANVAS_ZLEVEL).resize(width, height);\n        }\n        else {\n            var domRoot = this._domRoot;\n            // FIXME Why ?\n            domRoot.style.display = 'none';\n\n            // Save input w/h\n            var opts = this._opts;\n            width != null && (opts.width = width);\n            height != null && (opts.height = height);\n\n            width = this._getSize(0);\n            height = this._getSize(1);\n\n            domRoot.style.display = '';\n\n            // 优化没有实际改变的resize\n            if (this._width !== width || height !== this._height) {\n                domRoot.style.width = width + 'px';\n                domRoot.style.height = height + 'px';\n\n                for (var id in this._layers) {\n                    if (this._layers.hasOwnProperty(id)) {\n                        this._layers[id].resize(width, height);\n                    }\n                }\n                each$1(this._progressiveLayers, function (layer) {\n                    layer.resize(width, height);\n                });\n\n                this.refresh(true);\n            }\n\n            this._width = width;\n            this._height = height;\n\n        }\n        return this;\n    },\n\n    /**\n     * 清除单独的一个层\n     * @param {number} zlevel\n     */\n    clearLayer: function (zlevel) {\n        var layer = this._layers[zlevel];\n        if (layer) {\n            layer.clear();\n        }\n    },\n\n    /**\n     * 释放\n     */\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this.root =\n        this.storage =\n\n        this._domRoot =\n        this._layers = null;\n    },\n\n    /**\n     * Get canvas which has all thing rendered\n     * @param {Object} opts\n     * @param {string} [opts.backgroundColor]\n     * @param {number} [opts.pixelRatio]\n     */\n    getRenderedCanvas: function (opts) {\n        opts = opts || {};\n        if (this._singleCanvas && !this._compositeManually) {\n            return this._layers[CANVAS_ZLEVEL].dom;\n        }\n\n        var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr);\n        imageLayer.initContext();\n        imageLayer.clear(false, opts.backgroundColor || this._backgroundColor);\n\n        if (opts.pixelRatio <= this.dpr) {\n            this.refresh();\n\n            var width = imageLayer.dom.width;\n            var height = imageLayer.dom.height;\n            var ctx = imageLayer.ctx;\n            this.eachLayer(function (layer) {\n                if (layer.__builtin__) {\n                    ctx.drawImage(layer.dom, 0, 0, width, height);\n                }\n                else if (layer.renderToCanvas) {\n                    imageLayer.ctx.save();\n                    layer.renderToCanvas(imageLayer.ctx);\n                    imageLayer.ctx.restore();\n                }\n            });\n        }\n        else {\n            // PENDING, echarts-gl and incremental rendering.\n            var scope = {};\n            var displayList = this.storage.getDisplayList(true);\n            for (var i = 0; i < displayList.length; i++) {\n                var el = displayList[i];\n                this._doPaintEl(el, imageLayer, true, scope);\n            }\n        }\n\n        return imageLayer.dom;\n    },\n    /**\n     * 获取绘图区域宽度\n     */\n    getWidth: function () {\n        return this._width;\n    },\n\n    /**\n     * 获取绘图区域高度\n     */\n    getHeight: function () {\n        return this._height;\n    },\n\n    _getSize: function (whIdx) {\n        var opts = this._opts;\n        var wh = ['width', 'height'][whIdx];\n        var cwh = ['clientWidth', 'clientHeight'][whIdx];\n        var plt = ['paddingLeft', 'paddingTop'][whIdx];\n        var prb = ['paddingRight', 'paddingBottom'][whIdx];\n\n        if (opts[wh] != null && opts[wh] !== 'auto') {\n            return parseFloat(opts[wh]);\n        }\n\n        var root = this.root;\n        // IE8 does not support getComputedStyle, but it use VML.\n        var stl = document.defaultView.getComputedStyle(root);\n\n        return (\n            (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh]))\n            - (parseInt10(stl[plt]) || 0)\n            - (parseInt10(stl[prb]) || 0)\n        ) | 0;\n    },\n\n    pathToImage: function (path, dpr) {\n        dpr = dpr || this.dpr;\n\n        var canvas = document.createElement('canvas');\n        var ctx = canvas.getContext('2d');\n        var rect = path.getBoundingRect();\n        var style = path.style;\n        var shadowBlurSize = style.shadowBlur * dpr;\n        var shadowOffsetX = style.shadowOffsetX * dpr;\n        var shadowOffsetY = style.shadowOffsetY * dpr;\n        var lineWidth = style.hasStroke() ? style.lineWidth : 0;\n\n        var leftMargin = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize);\n        var rightMargin = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize);\n        var topMargin = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize);\n        var bottomMargin = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize);\n        var width = rect.width + leftMargin + rightMargin;\n        var height = rect.height + topMargin + bottomMargin;\n\n        canvas.width = width * dpr;\n        canvas.height = height * dpr;\n\n        ctx.scale(dpr, dpr);\n        ctx.clearRect(0, 0, width, height);\n        ctx.dpr = dpr;\n\n        var pathTransform = {\n            position: path.position,\n            rotation: path.rotation,\n            scale: path.scale\n        };\n        path.position = [leftMargin - rect.x, topMargin - rect.y];\n        path.rotation = 0;\n        path.scale = [1, 1];\n        path.updateTransform();\n        if (path) {\n            path.brush(ctx);\n        }\n\n        var ImageShape = ZImage;\n        var imgShape = new ImageShape({\n            style: {\n                x: 0,\n                y: 0,\n                image: canvas\n            }\n        });\n\n        if (pathTransform.position != null) {\n            imgShape.position = path.position = pathTransform.position;\n        }\n\n        if (pathTransform.rotation != null) {\n            imgShape.rotation = path.rotation = pathTransform.rotation;\n        }\n\n        if (pathTransform.scale != null) {\n            imgShape.scale = path.scale = pathTransform.scale;\n        }\n\n        return imgShape;\n    }\n};\n\n/**\n * 动画主类, 调度和管理所有动画控制器\n *\n * @module zrender/animation/Animation\n * @author pissang(https://github.com/pissang)\n */\n// TODO Additive animation\n// http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/\n// https://developer.apple.com/videos/wwdc2014/#236\n\n/**\n * @typedef {Object} IZRenderStage\n * @property {Function} update\n */\n\n/**\n * @alias module:zrender/animation/Animation\n * @constructor\n * @param {Object} [options]\n * @param {Function} [options.onframe]\n * @param {IZRenderStage} [options.stage]\n * @example\n *     var animation = new Animation();\n *     var obj = {\n *         x: 100,\n *         y: 100\n *     };\n *     animation.animate(node.position)\n *         .when(1000, {\n *             x: 500,\n *             y: 500\n *         })\n *         .when(2000, {\n *             x: 100,\n *             y: 100\n *         })\n *         .start('spline');\n */\nvar Animation = function (options) {\n\n    options = options || {};\n\n    this.stage = options.stage || {};\n\n    this.onframe = options.onframe || function () {};\n\n    // private properties\n    this._clips = [];\n\n    this._running = false;\n\n    this._time;\n\n    this._pausedTime;\n\n    this._pauseStart;\n\n    this._paused = false;\n\n    Eventful.call(this);\n};\n\nAnimation.prototype = {\n\n    constructor: Animation,\n    /**\n     * 添加 clip\n     * @param {module:zrender/animation/Clip} clip\n     */\n    addClip: function (clip) {\n        this._clips.push(clip);\n    },\n    /**\n     * 添加 animator\n     * @param {module:zrender/animation/Animator} animator\n     */\n    addAnimator: function (animator) {\n        animator.animation = this;\n        var clips = animator.getClips();\n        for (var i = 0; i < clips.length; i++) {\n            this.addClip(clips[i]);\n        }\n    },\n    /**\n     * 删除动画片段\n     * @param {module:zrender/animation/Clip} clip\n     */\n    removeClip: function (clip) {\n        var idx = indexOf(this._clips, clip);\n        if (idx >= 0) {\n            this._clips.splice(idx, 1);\n        }\n    },\n\n    /**\n     * 删除动画片段\n     * @param {module:zrender/animation/Animator} animator\n     */\n    removeAnimator: function (animator) {\n        var clips = animator.getClips();\n        for (var i = 0; i < clips.length; i++) {\n            this.removeClip(clips[i]);\n        }\n        animator.animation = null;\n    },\n\n    _update: function () {\n        var time = new Date().getTime() - this._pausedTime;\n        var delta = time - this._time;\n        var clips = this._clips;\n        var len = clips.length;\n\n        var deferredEvents = [];\n        var deferredClips = [];\n        for (var i = 0; i < len; i++) {\n            var clip = clips[i];\n            var e = clip.step(time, delta);\n            // Throw out the events need to be called after\n            // stage.update, like destroy\n            if (e) {\n                deferredEvents.push(e);\n                deferredClips.push(clip);\n            }\n        }\n\n        // Remove the finished clip\n        for (var i = 0; i < len;) {\n            if (clips[i]._needsRemove) {\n                clips[i] = clips[len - 1];\n                clips.pop();\n                len--;\n            }\n            else {\n                i++;\n            }\n        }\n\n        len = deferredEvents.length;\n        for (var i = 0; i < len; i++) {\n            deferredClips[i].fire(deferredEvents[i]);\n        }\n\n        this._time = time;\n\n        this.onframe(delta);\n\n        // 'frame' should be triggered before stage, because upper application\n        // depends on the sequence (e.g., echarts-stream and finish\n        // event judge)\n        this.trigger('frame', delta);\n\n        if (this.stage.update) {\n            this.stage.update();\n        }\n    },\n\n    _startLoop: function () {\n        var self = this;\n\n        this._running = true;\n\n        function step() {\n            if (self._running) {\n\n                requestAnimationFrame(step);\n\n                !self._paused && self._update();\n            }\n        }\n\n        requestAnimationFrame(step);\n    },\n\n    /**\n     * Start animation.\n     */\n    start: function () {\n\n        this._time = new Date().getTime();\n        this._pausedTime = 0;\n\n        this._startLoop();\n    },\n\n    /**\n     * Stop animation.\n     */\n    stop: function () {\n        this._running = false;\n    },\n\n    /**\n     * Pause animation.\n     */\n    pause: function () {\n        if (!this._paused) {\n            this._pauseStart = new Date().getTime();\n            this._paused = true;\n        }\n    },\n\n    /**\n     * Resume animation.\n     */\n    resume: function () {\n        if (this._paused) {\n            this._pausedTime += (new Date().getTime()) - this._pauseStart;\n            this._paused = false;\n        }\n    },\n\n    /**\n     * Clear animation.\n     */\n    clear: function () {\n        this._clips = [];\n    },\n\n    /**\n     * Whether animation finished.\n     */\n    isFinished: function () {\n        return !this._clips.length;\n    },\n\n    /**\n     * Creat animator for a target, whose props can be animated.\n     *\n     * @param  {Object} target\n     * @param  {Object} options\n     * @param  {boolean} [options.loop=false] Whether loop animation.\n     * @param  {Function} [options.getter=null] Get value from target.\n     * @param  {Function} [options.setter=null] Set value to target.\n     * @return {module:zrender/animation/Animation~Animator}\n     */\n    // TODO Gap\n    animate: function (target, options) {\n        options = options || {};\n\n        var animator = new Animator(\n            target,\n            options.loop,\n            options.getter,\n            options.setter\n        );\n\n        this.addAnimator(animator);\n\n        return animator;\n    }\n};\n\nmixin(Animation, Eventful);\n\nvar TOUCH_CLICK_DELAY = 300;\n\nvar mouseHandlerNames = [\n    'click', 'dblclick', 'mousewheel', 'mouseout',\n    'mouseup', 'mousedown', 'mousemove', 'contextmenu'\n];\n\nvar touchHandlerNames = [\n    'touchstart', 'touchend', 'touchmove'\n];\n\nvar pointerEventNames = {\n    pointerdown: 1, pointerup: 1, pointermove: 1, pointerout: 1\n};\n\nvar pointerHandlerNames = map(mouseHandlerNames, function (name) {\n    var nm = name.replace('mouse', 'pointer');\n    return pointerEventNames[nm] ? nm : name;\n});\n\nfunction eventNameFix(name) {\n    return (name === 'mousewheel' && env$1.browser.firefox) ? 'DOMMouseScroll' : name;\n}\n\n// function onMSGestureChange(proxy, event) {\n//     if (event.translationX || event.translationY) {\n//         // mousemove is carried by MSGesture to reduce the sensitivity.\n//         proxy.handler.dispatchToElement(event.target, 'mousemove', event);\n//     }\n//     if (event.scale !== 1) {\n//         event.pinchX = event.offsetX;\n//         event.pinchY = event.offsetY;\n//         event.pinchScale = event.scale;\n//         proxy.handler.dispatchToElement(event.target, 'pinch', event);\n//     }\n// }\n\n/**\n * Prevent mouse event from being dispatched after Touch Events action\n * @see <https://github.com/deltakosh/handjs/blob/master/src/hand.base.js>\n * 1. Mobile browsers dispatch mouse events 300ms after touchend.\n * 2. Chrome for Android dispatch mousedown for long-touch about 650ms\n * Result: Blocking Mouse Events for 700ms.\n */\nfunction setTouchTimer(instance) {\n    instance._touching = true;\n    clearTimeout(instance._touchTimer);\n    instance._touchTimer = setTimeout(function () {\n        instance._touching = false;\n    }, 700);\n}\n\n\nvar domHandlers = {\n    /**\n     * Mouse move handler\n     * @inner\n     * @param {Event} event\n     */\n    mousemove: function (event) {\n        event = normalizeEvent(this.dom, event);\n\n        this.trigger('mousemove', event);\n    },\n\n    /**\n     * Mouse out handler\n     * @inner\n     * @param {Event} event\n     */\n    mouseout: function (event) {\n        event = normalizeEvent(this.dom, event);\n\n        var element = event.toElement || event.relatedTarget;\n        if (element !== this.dom) {\n            while (element && element.nodeType !== 9) {\n                // 忽略包含在root中的dom引起的mouseOut\n                if (element === this.dom) {\n                    return;\n                }\n\n                element = element.parentNode;\n            }\n        }\n\n        this.trigger('mouseout', event);\n    },\n\n    /**\n     * Touch开始响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchstart: function (event) {\n        // Default mouse behaviour should not be disabled here.\n        // For example, page may needs to be slided.\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this._lastTouchMoment = new Date();\n\n        this.handler.processGesture(this, event, 'start');\n\n        // In touch device, trigger `mousemove`(`mouseover`) should\n        // be triggered, and must before `mousedown` triggered.\n        domHandlers.mousemove.call(this, event);\n\n        domHandlers.mousedown.call(this, event);\n\n        setTouchTimer(this);\n    },\n\n    /**\n     * Touch移动响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchmove: function (event) {\n\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this.handler.processGesture(this, event, 'change');\n\n        // Mouse move should always be triggered no matter whether\n        // there is gestrue event, because mouse move and pinch may\n        // be used at the same time.\n        domHandlers.mousemove.call(this, event);\n\n        setTouchTimer(this);\n    },\n\n    /**\n     * Touch结束响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchend: function (event) {\n\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this.handler.processGesture(this, event, 'end');\n\n        domHandlers.mouseup.call(this, event);\n\n        // Do not trigger `mouseout` here, in spite of `mousemove`(`mouseover`) is\n        // triggered in `touchstart`. This seems to be illogical, but by this mechanism,\n        // we can conveniently implement \"hover style\" in both PC and touch device just\n        // by listening to `mouseover` to add \"hover style\" and listening to `mouseout`\n        // to remove \"hover style\" on an element, without any additional code for\n        // compatibility. (`mouseout` will not be triggered in `touchend`, so \"hover\n        // style\" will remain for user view)\n\n        // click event should always be triggered no matter whether\n        // there is gestrue event. System click can not be prevented.\n        if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) {\n            domHandlers.click.call(this, event);\n        }\n\n        setTouchTimer(this);\n    },\n\n    pointerdown: function (event) {\n        domHandlers.mousedown.call(this, event);\n\n        // if (useMSGuesture(this, event)) {\n        //     this._msGesture.addPointer(event.pointerId);\n        // }\n    },\n\n    pointermove: function (event) {\n        // FIXME\n        // pointermove is so sensitive that it always triggered when\n        // tap(click) on touch screen, which affect some judgement in\n        // upper application. So, we dont support mousemove on MS touch\n        // device yet.\n        if (!isPointerFromTouch(event)) {\n            domHandlers.mousemove.call(this, event);\n        }\n    },\n\n    pointerup: function (event) {\n        domHandlers.mouseup.call(this, event);\n    },\n\n    pointerout: function (event) {\n        // pointerout will be triggered when tap on touch screen\n        // (IE11+/Edge on MS Surface) after click event triggered,\n        // which is inconsistent with the mousout behavior we defined\n        // in touchend. So we unify them.\n        // (check domHandlers.touchend for detailed explanation)\n        if (!isPointerFromTouch(event)) {\n            domHandlers.mouseout.call(this, event);\n        }\n    }\n};\n\nfunction isPointerFromTouch(event) {\n    var pointerType = event.pointerType;\n    return pointerType === 'pen' || pointerType === 'touch';\n}\n\n// function useMSGuesture(handlerProxy, event) {\n//     return isPointerFromTouch(event) && !!handlerProxy._msGesture;\n// }\n\n// Common handlers\neach$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {\n    domHandlers[name] = function (event) {\n        event = normalizeEvent(this.dom, event);\n        this.trigger(name, event);\n    };\n});\n\n/**\n * 为控制类实例初始化dom 事件处理函数\n *\n * @inner\n * @param {module:zrender/Handler} instance 控制类实例\n */\nfunction initDomHandler(instance) {\n    each$1(touchHandlerNames, function (name) {\n        instance._handlers[name] = bind(domHandlers[name], instance);\n    });\n\n    each$1(pointerHandlerNames, function (name) {\n        instance._handlers[name] = bind(domHandlers[name], instance);\n    });\n\n    each$1(mouseHandlerNames, function (name) {\n        instance._handlers[name] = makeMouseHandler(domHandlers[name], instance);\n    });\n\n    function makeMouseHandler(fn, instance) {\n        return function () {\n            if (instance._touching) {\n                return;\n            }\n            return fn.apply(instance, arguments);\n        };\n    }\n}\n\n\nfunction HandlerDomProxy(dom) {\n    Eventful.call(this);\n\n    this.dom = dom;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._touching = false;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._touchTimer;\n\n    this._handlers = {};\n\n    initDomHandler(this);\n\n    if (env$1.pointerEventsSupported) { // Only IE11+/Edge\n        // 1. On devices that both enable touch and mouse (e.g., MS Surface and lenovo X240),\n        // IE11+/Edge do not trigger touch event, but trigger pointer event and mouse event\n        // at the same time.\n        // 2. On MS Surface, it probablely only trigger mousedown but no mouseup when tap on\n        // screen, which do not occurs in pointer event.\n        // So we use pointer event to both detect touch gesture and mouse behavior.\n        mountHandlers(pointerHandlerNames, this);\n\n        // FIXME\n        // Note: MS Gesture require CSS touch-action set. But touch-action is not reliable,\n        // which does not prevent defuault behavior occasionally (which may cause view port\n        // zoomed in but use can not zoom it back). And event.preventDefault() does not work.\n        // So we have to not to use MSGesture and not to support touchmove and pinch on MS\n        // touch screen. And we only support click behavior on MS touch screen now.\n\n        // MS Gesture Event is only supported on IE11+/Edge and on Windows 8+.\n        // We dont support touch on IE on win7.\n        // See <https://msdn.microsoft.com/en-us/library/dn433243(v=vs.85).aspx>\n        // if (typeof MSGesture === 'function') {\n        //     (this._msGesture = new MSGesture()).target = dom; // jshint ignore:line\n        //     dom.addEventListener('MSGestureChange', onMSGestureChange);\n        // }\n    }\n    else {\n        if (env$1.touchEventsSupported) {\n            mountHandlers(touchHandlerNames, this);\n            // Handler of 'mouseout' event is needed in touch mode, which will be mounted below.\n            // addEventListener(root, 'mouseout', this._mouseoutHandler);\n        }\n\n        // 1. Considering some devices that both enable touch and mouse event (like on MS Surface\n        // and lenovo X240, @see #2350), we make mouse event be always listened, otherwise\n        // mouse event can not be handle in those devices.\n        // 2. On MS Surface, Chrome will trigger both touch event and mouse event. How to prevent\n        // mouseevent after touch event triggered, see `setTouchTimer`.\n        mountHandlers(mouseHandlerNames, this);\n    }\n\n    function mountHandlers(handlerNames, instance) {\n        each$1(handlerNames, function (name) {\n            addEventListener(dom, eventNameFix(name), instance._handlers[name]);\n        }, instance);\n    }\n}\n\nvar handlerDomProxyProto = HandlerDomProxy.prototype;\nhandlerDomProxyProto.dispose = function () {\n    var handlerNames = mouseHandlerNames.concat(touchHandlerNames);\n\n    for (var i = 0; i < handlerNames.length; i++) {\n        var name = handlerNames[i];\n        removeEventListener(this.dom, eventNameFix(name), this._handlers[name]);\n    }\n};\n\nhandlerDomProxyProto.setCursor = function (cursorStyle) {\n    this.dom.style && (this.dom.style.cursor = cursorStyle || 'default');\n};\n\nmixin(HandlerDomProxy, Eventful);\n\n/*!\n* ZRender, a high performance 2d drawing library.\n*\n* Copyright (c) 2013, Baidu Inc.\n* All rights reserved.\n*\n* LICENSE\n* https://github.com/ecomfe/zrender/blob/master/LICENSE.txt\n*/\n\nvar useVML = !env$1.canvasSupported;\n\nvar painterCtors = {\n    canvas: Painter\n};\n\nvar instances$1 = {};    // ZRender实例map索引\n\n/**\n * @type {string}\n */\nvar version$1 = '4.0.7';\n\n/**\n * Initializing a zrender instance\n * @param {HTMLElement} dom\n * @param {Object} [opts]\n * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'\n * @param {number} [opts.devicePixelRatio]\n * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)\n * @return {module:zrender/ZRender}\n */\nfunction init$1(dom, opts) {\n    var zr = new ZRender(guid(), dom, opts);\n    instances$1[zr.id] = zr;\n    return zr;\n}\n\n/**\n * Dispose zrender instance\n * @param {module:zrender/ZRender} zr\n */\nfunction dispose$1(zr) {\n    if (zr) {\n        zr.dispose();\n    }\n    else {\n        for (var key in instances$1) {\n            if (instances$1.hasOwnProperty(key)) {\n                instances$1[key].dispose();\n            }\n        }\n        instances$1 = {};\n    }\n\n    return this;\n}\n\n/**\n * Get zrender instance by id\n * @param {string} id zrender instance id\n * @return {module:zrender/ZRender}\n */\nfunction getInstance(id) {\n    return instances$1[id];\n}\n\nfunction registerPainter(name, Ctor) {\n    painterCtors[name] = Ctor;\n}\n\nfunction delInstance(id) {\n    delete instances$1[id];\n}\n\n/**\n * @module zrender/ZRender\n */\n/**\n * @constructor\n * @alias module:zrender/ZRender\n * @param {string} id\n * @param {HTMLElement} dom\n * @param {Object} opts\n * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'\n * @param {number} [opts.devicePixelRatio]\n * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)\n */\nvar ZRender = function (id, dom, opts) {\n\n    opts = opts || {};\n\n    /**\n     * @type {HTMLDomElement}\n     */\n    this.dom = dom;\n\n    /**\n     * @type {string}\n     */\n    this.id = id;\n\n    var self = this;\n    var storage = new Storage();\n\n    var rendererType = opts.renderer;\n    // TODO WebGL\n    if (useVML) {\n        if (!painterCtors.vml) {\n            throw new Error('You need to require \\'zrender/vml/vml\\' to support IE8');\n        }\n        rendererType = 'vml';\n    }\n    else if (!rendererType || !painterCtors[rendererType]) {\n        rendererType = 'canvas';\n    }\n    var painter = new painterCtors[rendererType](dom, storage, opts, id);\n\n    this.storage = storage;\n    this.painter = painter;\n\n    var handerProxy = (!env$1.node && !env$1.worker) ? new HandlerDomProxy(painter.getViewportRoot()) : null;\n    this.handler = new Handler(storage, painter, handerProxy, painter.root);\n\n    /**\n     * @type {module:zrender/animation/Animation}\n     */\n    this.animation = new Animation({\n        stage: {\n            update: bind(this.flush, this)\n        }\n    });\n    this.animation.start();\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._needsRefresh;\n\n    // 修改 storage.delFromStorage, 每次删除元素之前删除动画\n    // FIXME 有点ugly\n    var oldDelFromStorage = storage.delFromStorage;\n    var oldAddToStorage = storage.addToStorage;\n\n    storage.delFromStorage = function (el) {\n        oldDelFromStorage.call(storage, el);\n\n        el && el.removeSelfFromZr(self);\n    };\n\n    storage.addToStorage = function (el) {\n        oldAddToStorage.call(storage, el);\n\n        el.addSelfToZr(self);\n    };\n};\n\nZRender.prototype = {\n\n    constructor: ZRender,\n    /**\n     * 获取实例唯一标识\n     * @return {string}\n     */\n    getId: function () {\n        return this.id;\n    },\n\n    /**\n     * 添加元素\n     * @param  {module:zrender/Element} el\n     */\n    add: function (el) {\n        this.storage.addRoot(el);\n        this._needsRefresh = true;\n    },\n\n    /**\n     * 删除元素\n     * @param  {module:zrender/Element} el\n     */\n    remove: function (el) {\n        this.storage.delRoot(el);\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Change configuration of layer\n     * @param {string} zLevel\n     * @param {Object} config\n     * @param {string} [config.clearColor=0] Clear color\n     * @param {string} [config.motionBlur=false] If enable motion blur\n     * @param {number} [config.lastFrameAlpha=0.7] Motion blur factor. Larger value cause longer trailer\n    */\n    configLayer: function (zLevel, config) {\n        if (this.painter.configLayer) {\n            this.painter.configLayer(zLevel, config);\n        }\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Set background color\n     * @param {string} backgroundColor\n     */\n    setBackgroundColor: function (backgroundColor) {\n        if (this.painter.setBackgroundColor) {\n            this.painter.setBackgroundColor(backgroundColor);\n        }\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Repaint the canvas immediately\n     */\n    refreshImmediately: function () {\n        // var start = new Date();\n        // Clear needsRefresh ahead to avoid something wrong happens in refresh\n        // Or it will cause zrender refreshes again and again.\n        this._needsRefresh = false;\n        this.painter.refresh();\n        /**\n         * Avoid trigger zr.refresh in Element#beforeUpdate hook\n         */\n        this._needsRefresh = false;\n        // var end = new Date();\n        // var log = document.getElementById('log');\n        // if (log) {\n        //     log.innerHTML = log.innerHTML + '<br>' + (end - start);\n        // }\n    },\n\n    /**\n     * Mark and repaint the canvas in the next frame of browser\n     */\n    refresh: function () {\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Perform all refresh\n     */\n    flush: function () {\n        var triggerRendered;\n\n        if (this._needsRefresh) {\n            triggerRendered = true;\n            this.refreshImmediately();\n        }\n        if (this._needsRefreshHover) {\n            triggerRendered = true;\n            this.refreshHoverImmediately();\n        }\n\n        triggerRendered && this.trigger('rendered');\n    },\n\n    /**\n     * Add element to hover layer\n     * @param  {module:zrender/Element} el\n     * @param {Object} style\n     */\n    addHover: function (el, style) {\n        if (this.painter.addHover) {\n            var elMirror = this.painter.addHover(el, style);\n            this.refreshHover();\n            return elMirror;\n        }\n    },\n\n    /**\n     * Add element from hover layer\n     * @param  {module:zrender/Element} el\n     */\n    removeHover: function (el) {\n        if (this.painter.removeHover) {\n            this.painter.removeHover(el);\n            this.refreshHover();\n        }\n    },\n\n    /**\n     * Clear all hover elements in hover layer\n     * @param  {module:zrender/Element} el\n     */\n    clearHover: function () {\n        if (this.painter.clearHover) {\n            this.painter.clearHover();\n            this.refreshHover();\n        }\n    },\n\n    /**\n     * Refresh hover in next frame\n     */\n    refreshHover: function () {\n        this._needsRefreshHover = true;\n    },\n\n    /**\n     * Refresh hover immediately\n     */\n    refreshHoverImmediately: function () {\n        this._needsRefreshHover = false;\n        this.painter.refreshHover && this.painter.refreshHover();\n    },\n\n    /**\n     * Resize the canvas.\n     * Should be invoked when container size is changed\n     * @param {Object} [opts]\n     * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)\n     * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)\n     */\n    resize: function (opts) {\n        opts = opts || {};\n        this.painter.resize(opts.width, opts.height);\n        this.handler.resize();\n    },\n\n    /**\n     * Stop and clear all animation immediately\n     */\n    clearAnimation: function () {\n        this.animation.clear();\n    },\n\n    /**\n     * Get container width\n     */\n    getWidth: function () {\n        return this.painter.getWidth();\n    },\n\n    /**\n     * Get container height\n     */\n    getHeight: function () {\n        return this.painter.getHeight();\n    },\n\n    /**\n     * Export the canvas as Base64 URL\n     * @param {string} type\n     * @param {string} [backgroundColor='#fff']\n     * @return {string} Base64 URL\n     */\n    // toDataURL: function(type, backgroundColor) {\n    //     return this.painter.getRenderedCanvas({\n    //         backgroundColor: backgroundColor\n    //     }).toDataURL(type);\n    // },\n\n    /**\n     * Converting a path to image.\n     * It has much better performance of drawing image rather than drawing a vector path.\n     * @param {module:zrender/graphic/Path} e\n     * @param {number} width\n     * @param {number} height\n     */\n    pathToImage: function (e, dpr) {\n        return this.painter.pathToImage(e, dpr);\n    },\n\n    /**\n     * Set default cursor\n     * @param {string} [cursorStyle='default'] 例如 crosshair\n     */\n    setCursorStyle: function (cursorStyle) {\n        this.handler.setCursorStyle(cursorStyle);\n    },\n\n    /**\n     * Find hovered element\n     * @param {number} x\n     * @param {number} y\n     * @return {Object} {target, topTarget}\n     */\n    findHover: function (x, y) {\n        return this.handler.findHover(x, y);\n    },\n\n    /**\n     * Bind event\n     *\n     * @param {string} eventName Event name\n     * @param {Function} eventHandler Handler function\n     * @param {Object} [context] Context object\n     */\n    on: function (eventName, eventHandler, context) {\n        this.handler.on(eventName, eventHandler, context);\n    },\n\n    /**\n     * Unbind event\n     * @param {string} eventName Event name\n     * @param {Function} [eventHandler] Handler function\n     */\n    off: function (eventName, eventHandler) {\n        this.handler.off(eventName, eventHandler);\n    },\n\n    /**\n     * Trigger event manually\n     *\n     * @param {string} eventName Event name\n     * @param {event=} event Event object\n     */\n    trigger: function (eventName, event) {\n        this.handler.trigger(eventName, event);\n    },\n\n\n    /**\n     * Clear all objects and the canvas.\n     */\n    clear: function () {\n        this.storage.delRoot();\n        this.painter.clear();\n    },\n\n    /**\n     * Dispose self.\n     */\n    dispose: function () {\n        this.animation.stop();\n\n        this.clear();\n        this.storage.dispose();\n        this.painter.dispose();\n        this.handler.dispose();\n\n        this.animation =\n        this.storage =\n        this.painter =\n        this.handler = null;\n\n        delInstance(this.id);\n    }\n};\n\n\n\nvar zrender = (Object.freeze || Object)({\n\tversion: version$1,\n\tinit: init$1,\n\tdispose: dispose$1,\n\tgetInstance: getInstance,\n\tregisterPainter: registerPainter\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$2 = each$1;\nvar isObject$2 = isObject$1;\nvar isArray$1 = isArray;\n\n/**\n * Make the name displayable. But we should\n * make sure it is not duplicated with user\n * specified name, so use '\\0';\n */\nvar DUMMY_COMPONENT_NAME_PREFIX = 'series\\0';\n\n/**\n * If value is not array, then translate it to array.\n * @param  {*} value\n * @return {Array} [value] or value\n */\nfunction normalizeToArray(value) {\n    return value instanceof Array\n        ? value\n        : value == null\n        ? []\n        : [value];\n}\n\n/**\n * Sync default option between normal and emphasis like `position` and `show`\n * In case some one will write code like\n *     label: {\n *          show: false,\n *          position: 'outside',\n *          fontSize: 18\n *     },\n *     emphasis: {\n *          label: { show: true }\n *     }\n * @param {Object} opt\n * @param {string} key\n * @param {Array.<string>} subOpts\n */\nfunction defaultEmphasis(opt, key, subOpts) {\n    // Caution: performance sensitive.\n    if (opt) {\n        opt[key] = opt[key] || {};\n        opt.emphasis = opt.emphasis || {};\n        opt.emphasis[key] = opt.emphasis[key] || {};\n\n        // Default emphasis option from normal\n        for (var i = 0, len = subOpts.length; i < len; i++) {\n            var subOptName = subOpts[i];\n            if (!opt.emphasis[key].hasOwnProperty(subOptName)\n                && opt[key].hasOwnProperty(subOptName)\n            ) {\n                opt.emphasis[key][subOptName] = opt[key][subOptName];\n            }\n        }\n    }\n}\n\nvar TEXT_STYLE_OPTIONS = [\n    'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',\n    'rich', 'tag', 'color', 'textBorderColor', 'textBorderWidth',\n    'width', 'height', 'lineHeight', 'align', 'verticalAlign', 'baseline',\n    'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY',\n    'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY',\n    'backgroundColor', 'borderColor', 'borderWidth', 'borderRadius', 'padding'\n];\n\n// modelUtil.LABEL_OPTIONS = modelUtil.TEXT_STYLE_OPTIONS.concat([\n//     'position', 'offset', 'rotate', 'origin', 'show', 'distance', 'formatter',\n//     'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',\n//     // FIXME: deprecated, check and remove it.\n//     'textStyle'\n// ]);\n\n/**\n * The method do not ensure performance.\n * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]\n * This helper method retieves value from data.\n * @param {string|number|Date|Array|Object} dataItem\n * @return {number|string|Date|Array.<number|string|Date>}\n */\nfunction getDataItemValue(dataItem) {\n    return (isObject$2(dataItem) && !isArray$1(dataItem) && !(dataItem instanceof Date))\n        ? dataItem.value : dataItem;\n}\n\n/**\n * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]\n * This helper method determine if dataItem has extra option besides value\n * @param {string|number|Date|Array|Object} dataItem\n */\nfunction isDataItemOption(dataItem) {\n    return isObject$2(dataItem)\n        && !(dataItem instanceof Array);\n        // // markLine data can be array\n        // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array));\n}\n\n/**\n * Mapping to exists for merge.\n *\n * @public\n * @param {Array.<Object>|Array.<module:echarts/model/Component>} exists\n * @param {Object|Array.<Object>} newCptOptions\n * @return {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],\n *                          index of which is the same as exists.\n */\nfunction mappingToExists(exists, newCptOptions) {\n    // Mapping by the order by original option (but not order of\n    // new option) in merge mode. Because we should ensure\n    // some specified index (like xAxisIndex) is consistent with\n    // original option, which is easy to understand, espatially in\n    // media query. And in most case, merge option is used to\n    // update partial option but not be expected to change order.\n    newCptOptions = (newCptOptions || []).slice();\n\n    var result = map(exists || [], function (obj, index) {\n        return {exist: obj};\n    });\n\n    // Mapping by id or name if specified.\n    each$2(newCptOptions, function (cptOption, index) {\n        if (!isObject$2(cptOption)) {\n            return;\n        }\n\n        // id has highest priority.\n        for (var i = 0; i < result.length; i++) {\n            if (!result[i].option // Consider name: two map to one.\n                && cptOption.id != null\n                && result[i].exist.id === cptOption.id + ''\n            ) {\n                result[i].option = cptOption;\n                newCptOptions[index] = null;\n                return;\n            }\n        }\n\n        for (var i = 0; i < result.length; i++) {\n            var exist = result[i].exist;\n            if (!result[i].option // Consider name: two map to one.\n                // Can not match when both ids exist but different.\n                && (exist.id == null || cptOption.id == null)\n                && cptOption.name != null\n                && !isIdInner(cptOption)\n                && !isIdInner(exist)\n                && exist.name === cptOption.name + ''\n            ) {\n                result[i].option = cptOption;\n                newCptOptions[index] = null;\n                return;\n            }\n        }\n    });\n\n    // Otherwise mapping by index.\n    each$2(newCptOptions, function (cptOption, index) {\n        if (!isObject$2(cptOption)) {\n            return;\n        }\n\n        var i = 0;\n        for (; i < result.length; i++) {\n            var exist = result[i].exist;\n            if (!result[i].option\n                // Existing model that already has id should be able to\n                // mapped to (because after mapping performed model may\n                // be assigned with a id, whish should not affect next\n                // mapping), except those has inner id.\n                && !isIdInner(exist)\n                // Caution:\n                // Do not overwrite id. But name can be overwritten,\n                // because axis use name as 'show label text'.\n                // 'exist' always has id and name and we dont\n                // need to check it.\n                && cptOption.id == null\n            ) {\n                result[i].option = cptOption;\n                break;\n            }\n        }\n\n        if (i >= result.length) {\n            result.push({option: cptOption});\n        }\n    });\n\n    return result;\n}\n\n/**\n * Make id and name for mapping result (result of mappingToExists)\n * into `keyInfo` field.\n *\n * @public\n * @param {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],\n *                          which order is the same as exists.\n * @return {Array.<Object>} The input.\n */\nfunction makeIdAndName(mapResult) {\n    // We use this id to hash component models and view instances\n    // in echarts. id can be specified by user, or auto generated.\n\n    // The id generation rule ensures new view instance are able\n    // to mapped to old instance when setOption are called in\n    // no-merge mode. So we generate model id by name and plus\n    // type in view id.\n\n    // name can be duplicated among components, which is convenient\n    // to specify multi components (like series) by one name.\n\n    // Ensure that each id is distinct.\n    var idMap = createHashMap();\n\n    each$2(mapResult, function (item, index) {\n        var existCpt = item.exist;\n        existCpt && idMap.set(existCpt.id, item);\n    });\n\n    each$2(mapResult, function (item, index) {\n        var opt = item.option;\n\n        assert$1(\n            !opt || opt.id == null || !idMap.get(opt.id) || idMap.get(opt.id) === item,\n            'id duplicates: ' + (opt && opt.id)\n        );\n\n        opt && opt.id != null && idMap.set(opt.id, item);\n        !item.keyInfo && (item.keyInfo = {});\n    });\n\n    // Make name and id.\n    each$2(mapResult, function (item, index) {\n        var existCpt = item.exist;\n        var opt = item.option;\n        var keyInfo = item.keyInfo;\n\n        if (!isObject$2(opt)) {\n            return;\n        }\n\n        // name can be overwitten. Consider case: axis.name = '20km'.\n        // But id generated by name will not be changed, which affect\n        // only in that case: setOption with 'not merge mode' and view\n        // instance will be recreated, which can be accepted.\n        keyInfo.name = opt.name != null\n            ? opt.name + ''\n            : existCpt\n            ? existCpt.name\n            // Avoid diffferent series has the same name,\n            // because name may be used like in color pallet.\n            : DUMMY_COMPONENT_NAME_PREFIX + index;\n\n        if (existCpt) {\n            keyInfo.id = existCpt.id;\n        }\n        else if (opt.id != null) {\n            keyInfo.id = opt.id + '';\n        }\n        else {\n            // Consider this situatoin:\n            //  optionA: [{name: 'a'}, {name: 'a'}, {..}]\n            //  optionB [{..}, {name: 'a'}, {name: 'a'}]\n            // Series with the same name between optionA and optionB\n            // should be mapped.\n            var idNum = 0;\n            do {\n                keyInfo.id = '\\0' + keyInfo.name + '\\0' + idNum++;\n            }\n            while (idMap.get(keyInfo.id));\n        }\n\n        idMap.set(keyInfo.id, item);\n    });\n}\n\nfunction isNameSpecified(componentModel) {\n    var name = componentModel.name;\n    // Is specified when `indexOf` get -1 or > 0.\n    return !!(name && name.indexOf(DUMMY_COMPONENT_NAME_PREFIX));\n}\n\n/**\n * @public\n * @param {Object} cptOption\n * @return {boolean}\n */\nfunction isIdInner(cptOption) {\n    return isObject$2(cptOption)\n        && cptOption.id\n        && (cptOption.id + '').indexOf('\\0_ec_\\0') === 0;\n}\n\n/**\n * A helper for removing duplicate items between batchA and batchB,\n * and in themselves, and categorize by series.\n *\n * @param {Array.<Object>} batchA Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]\n * @param {Array.<Object>} batchB Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]\n * @return {Array.<Array.<Object>, Array.<Object>>} result: [resultBatchA, resultBatchB]\n */\n\n\n/**\n * @param {module:echarts/data/List} data\n * @param {Object} payload Contains dataIndex (means rawIndex) / dataIndexInside / name\n *                         each of which can be Array or primary type.\n * @return {number|Array.<number>} dataIndex If not found, return undefined/null.\n */\nfunction queryDataIndex(data, payload) {\n    if (payload.dataIndexInside != null) {\n        return payload.dataIndexInside;\n    }\n    else if (payload.dataIndex != null) {\n        return isArray(payload.dataIndex)\n            ? map(payload.dataIndex, function (value) {\n                return data.indexOfRawIndex(value);\n            })\n            : data.indexOfRawIndex(payload.dataIndex);\n    }\n    else if (payload.name != null) {\n        return isArray(payload.name)\n            ? map(payload.name, function (value) {\n                return data.indexOfName(value);\n            })\n            : data.indexOfName(payload.name);\n    }\n}\n\n/**\n * Enable property storage to any host object.\n * Notice: Serialization is not supported.\n *\n * For example:\n * var inner = zrUitl.makeInner();\n *\n * function some1(hostObj) {\n *      inner(hostObj).someProperty = 1212;\n *      ...\n * }\n * function some2() {\n *      var fields = inner(this);\n *      fields.someProperty1 = 1212;\n *      fields.someProperty2 = 'xx';\n *      ...\n * }\n *\n * @return {Function}\n */\nfunction makeInner() {\n    // Consider different scope by es module import.\n    var key = '__\\0ec_inner_' + innerUniqueIndex++ + '_' + Math.random().toFixed(5);\n    return function (hostObj) {\n        return hostObj[key] || (hostObj[key] = {});\n    };\n}\nvar innerUniqueIndex = 0;\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex, seriesId, seriesName,\n *            geoIndex, geoId, geoName,\n *            bmapIndex, bmapId, bmapName,\n *            xAxisIndex, xAxisId, xAxisName,\n *            yAxisIndex, yAxisId, yAxisName,\n *            gridIndex, gridId, gridName,\n *            ... (can be extended)\n *        }\n *        Each properties can be number|string|Array.<number>|Array.<string>\n *        For example, a finder could be\n *        {\n *            seriesIndex: 3,\n *            geoId: ['aa', 'cc'],\n *            gridName: ['xx', 'rr']\n *        }\n *        xxxIndex can be set as 'all' (means all xxx) or 'none' (means not specify)\n *        If nothing or null/undefined specified, return nothing.\n * @param {Object} [opt]\n * @param {string} [opt.defaultMainType]\n * @param {Array.<string>} [opt.includeMainTypes]\n * @return {Object} result like:\n *        {\n *            seriesModels: [seriesModel1, seriesModel2],\n *            seriesModel: seriesModel1, // The first model\n *            geoModels: [geoModel1, geoModel2],\n *            geoModel: geoModel1, // The first model\n *            ...\n *        }\n */\nfunction parseFinder(ecModel, finder, opt) {\n    if (isString(finder)) {\n        var obj = {};\n        obj[finder + 'Index'] = 0;\n        finder = obj;\n    }\n\n    var defaultMainType = opt && opt.defaultMainType;\n    if (defaultMainType\n        && !has(finder, defaultMainType + 'Index')\n        && !has(finder, defaultMainType + 'Id')\n        && !has(finder, defaultMainType + 'Name')\n    ) {\n        finder[defaultMainType + 'Index'] = 0;\n    }\n\n    var result = {};\n\n    each$2(finder, function (value, key) {\n        var value = finder[key];\n\n        // Exclude 'dataIndex' and other illgal keys.\n        if (key === 'dataIndex' || key === 'dataIndexInside') {\n            result[key] = value;\n            return;\n        }\n\n        var parsedKey = key.match(/^(\\w+)(Index|Id|Name)$/) || [];\n        var mainType = parsedKey[1];\n        var queryType = (parsedKey[2] || '').toLowerCase();\n\n        if (!mainType\n            || !queryType\n            || value == null\n            || (queryType === 'index' && value === 'none')\n            || (opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0)\n        ) {\n            return;\n        }\n\n        var queryParam = {mainType: mainType};\n        if (queryType !== 'index' || value !== 'all') {\n            queryParam[queryType] = value;\n        }\n\n        var models = ecModel.queryComponents(queryParam);\n        result[mainType + 'Models'] = models;\n        result[mainType + 'Model'] = models[0];\n    });\n\n    return result;\n}\n\nfunction has(obj, prop) {\n    return obj && obj.hasOwnProperty(prop);\n}\n\nfunction setAttribute(dom, key, value) {\n    dom.setAttribute\n        ? dom.setAttribute(key, value)\n        : (dom[key] = value);\n}\n\nfunction getAttribute(dom, key) {\n    return dom.getAttribute\n        ? dom.getAttribute(key)\n        : dom[key];\n}\n\nfunction getTooltipRenderMode(renderModeOption) {\n    if (renderModeOption === 'auto') {\n        // Using html when `document` exists, use richText otherwise\n        return env$1.domSupported ? 'html' : 'richText';\n    }\n    else {\n        return renderModeOption || 'html';\n    }\n}\n\n/**\n * Group a list by key.\n *\n * @param {Array} array\n * @param {Function} getKey\n *        param {*} Array item\n *        return {string} key\n * @return {Object} Result\n *        {Array}: keys,\n *        {module:zrender/core/util/HashMap} buckets: {key -> Array}\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TYPE_DELIMITER = '.';\nvar IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';\n\n/**\n * Notice, parseClassType('') should returns {main: '', sub: ''}\n * @public\n */\nfunction parseClassType$1(componentType) {\n    var ret = {main: '', sub: ''};\n    if (componentType) {\n        componentType = componentType.split(TYPE_DELIMITER);\n        ret.main = componentType[0] || '';\n        ret.sub = componentType[1] || '';\n    }\n    return ret;\n}\n\n/**\n * @public\n */\nfunction checkClassType(componentType) {\n    assert$1(\n        /^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType),\n        'componentType \"' + componentType + '\" illegal'\n    );\n}\n\n/**\n * @public\n */\nfunction enableClassExtend(RootClass, mandatoryMethods) {\n\n    RootClass.$constructor = RootClass;\n    RootClass.extend = function (proto) {\n\n        if (__DEV__) {\n            each$1(mandatoryMethods, function (method) {\n                if (!proto[method]) {\n                    console.warn(\n                        'Method `' + method + '` should be implemented'\n                        + (proto.type ? ' in ' + proto.type : '') + '.'\n                    );\n                }\n            });\n        }\n\n        var superClass = this;\n        var ExtendedClass = function () {\n            if (!proto.$constructor) {\n                superClass.apply(this, arguments);\n            }\n            else {\n                proto.$constructor.apply(this, arguments);\n            }\n        };\n\n        extend(ExtendedClass.prototype, proto);\n\n        ExtendedClass.extend = this.extend;\n        ExtendedClass.superCall = superCall;\n        ExtendedClass.superApply = superApply;\n        inherits(ExtendedClass, this);\n        ExtendedClass.superClass = superClass;\n\n        return ExtendedClass;\n    };\n}\n\nvar classBase = 0;\n\n/**\n * Can not use instanceof, consider different scope by\n * cross domain or es module import in ec extensions.\n * Mount a method \"isInstance()\" to Clz.\n */\nfunction enableClassCheck(Clz) {\n    var classAttr = ['__\\0is_clz', classBase++, Math.random().toFixed(3)].join('_');\n    Clz.prototype[classAttr] = true;\n\n    if (__DEV__) {\n        assert$1(!Clz.isInstance, 'The method \"is\" can not be defined.');\n    }\n\n    Clz.isInstance = function (obj) {\n        return !!(obj && obj[classAttr]);\n    };\n}\n\n// superCall should have class info, which can not be fetch from 'this'.\n// Consider this case:\n// class A has method f,\n// class B inherits class A, overrides method f, f call superApply('f'),\n// class C inherits class B, do not overrides method f,\n// then when method of class C is called, dead loop occured.\nfunction superCall(context, methodName) {\n    var args = slice(arguments, 2);\n    return this.superClass.prototype[methodName].apply(context, args);\n}\n\nfunction superApply(context, methodName, args) {\n    return this.superClass.prototype[methodName].apply(context, args);\n}\n\n/**\n * @param {Object} entity\n * @param {Object} options\n * @param {boolean} [options.registerWhenExtend]\n * @public\n */\nfunction enableClassManagement(entity, options) {\n    options = options || {};\n\n    /**\n     * Component model classes\n     * key: componentType,\n     * value:\n     *     componentClass, when componentType is 'xxx'\n     *     or Object.<subKey, componentClass>, when componentType is 'xxx.yy'\n     * @type {Object}\n     */\n    var storage = {};\n\n    entity.registerClass = function (Clazz, componentType) {\n        if (componentType) {\n            checkClassType(componentType);\n            componentType = parseClassType$1(componentType);\n\n            if (!componentType.sub) {\n                if (__DEV__) {\n                    if (storage[componentType.main]) {\n                        console.warn(componentType.main + ' exists.');\n                    }\n                }\n                storage[componentType.main] = Clazz;\n            }\n            else if (componentType.sub !== IS_CONTAINER) {\n                var container = makeContainer(componentType);\n                container[componentType.sub] = Clazz;\n            }\n        }\n        return Clazz;\n    };\n\n    entity.getClass = function (componentMainType, subType, throwWhenNotFound) {\n        var Clazz = storage[componentMainType];\n\n        if (Clazz && Clazz[IS_CONTAINER]) {\n            Clazz = subType ? Clazz[subType] : null;\n        }\n\n        if (throwWhenNotFound && !Clazz) {\n            throw new Error(\n                !subType\n                    ? componentMainType + '.' + 'type should be specified.'\n                    : 'Component ' + componentMainType + '.' + (subType || '') + ' not exists. Load it first.'\n            );\n        }\n\n        return Clazz;\n    };\n\n    entity.getClassesByMainType = function (componentType) {\n        componentType = parseClassType$1(componentType);\n\n        var result = [];\n        var obj = storage[componentType.main];\n\n        if (obj && obj[IS_CONTAINER]) {\n            each$1(obj, function (o, type) {\n                type !== IS_CONTAINER && result.push(o);\n            });\n        }\n        else {\n            result.push(obj);\n        }\n\n        return result;\n    };\n\n    entity.hasClass = function (componentType) {\n        // Just consider componentType.main.\n        componentType = parseClassType$1(componentType);\n        return !!storage[componentType.main];\n    };\n\n    /**\n     * @return {Array.<string>} Like ['aa', 'bb'], but can not be ['aa.xx']\n     */\n    entity.getAllClassMainTypes = function () {\n        var types = [];\n        each$1(storage, function (obj, type) {\n            types.push(type);\n        });\n        return types;\n    };\n\n    /**\n     * If a main type is container and has sub types\n     * @param  {string}  mainType\n     * @return {boolean}\n     */\n    entity.hasSubTypes = function (componentType) {\n        componentType = parseClassType$1(componentType);\n        var obj = storage[componentType.main];\n        return obj && obj[IS_CONTAINER];\n    };\n\n    entity.parseClassType = parseClassType$1;\n\n    function makeContainer(componentType) {\n        var container = storage[componentType.main];\n        if (!container || !container[IS_CONTAINER]) {\n            container = storage[componentType.main] = {};\n            container[IS_CONTAINER] = true;\n        }\n        return container;\n    }\n\n    if (options.registerWhenExtend) {\n        var originalExtend = entity.extend;\n        if (originalExtend) {\n            entity.extend = function (proto) {\n                var ExtendedClass = originalExtend.call(this, proto);\n                return entity.registerClass(ExtendedClass, proto.type);\n            };\n        }\n    }\n\n    return entity;\n}\n\n/**\n * @param {string|Array.<string>} properties\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Parse shadow style\n// TODO Only shallow path support\nvar makeStyleMapper = function (properties) {\n    // Normalize\n    for (var i = 0; i < properties.length; i++) {\n        if (!properties[i][1]) {\n            properties[i][1] = properties[i][0];\n        }\n    }\n    return function (model, excludes, includes) {\n        var style = {};\n        for (var i = 0; i < properties.length; i++) {\n            var propName = properties[i][1];\n            if ((excludes && indexOf(excludes, propName) >= 0)\n                || (includes && indexOf(includes, propName) < 0)\n            ) {\n                continue;\n            }\n            var val = model.getShallow(propName);\n            if (val != null) {\n                style[properties[i][0]] = val;\n            }\n        }\n        return style;\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getLineStyle = makeStyleMapper(\n    [\n        ['lineWidth', 'width'],\n        ['stroke', 'color'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor']\n    ]\n);\n\nvar lineStyleMixin = {\n    getLineStyle: function (excludes) {\n        var style = getLineStyle(this, excludes);\n        var lineDash = this.getLineDash(style.lineWidth);\n        lineDash && (style.lineDash = lineDash);\n        return style;\n    },\n\n    getLineDash: function (lineWidth) {\n        if (lineWidth == null) {\n            lineWidth = 1;\n        }\n        var lineType = this.get('type');\n        var dotSize = Math.max(lineWidth, 2);\n        var dashSize = lineWidth * 4;\n        return (lineType === 'solid' || lineType == null) ? null\n            : (lineType === 'dashed' ? [dashSize, dashSize] : [dotSize, dotSize]);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getAreaStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['opacity'],\n        ['shadowColor']\n    ]\n);\n\nvar areaStyleMixin = {\n    getAreaStyle: function (excludes, includes) {\n        return getAreaStyle(this, excludes, includes);\n    }\n};\n\n/**\n * 曲线辅助模块\n * @module zrender/core/curve\n * @author pissang(https://www.github.com/pissang)\n */\n\nvar mathPow = Math.pow;\nvar mathSqrt$2 = Math.sqrt;\n\nvar EPSILON$1 = 1e-8;\nvar EPSILON_NUMERIC = 1e-4;\n\nvar THREE_SQRT = mathSqrt$2(3);\nvar ONE_THIRD = 1 / 3;\n\n// 临时变量\nvar _v0 = create();\nvar _v1 = create();\nvar _v2 = create();\n\nfunction isAroundZero(val) {\n    return val > -EPSILON$1 && val < EPSILON$1;\n}\nfunction isNotAroundZero$1(val) {\n    return val > EPSILON$1 || val < -EPSILON$1;\n}\n/**\n * 计算三次贝塞尔值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @return {number}\n */\nfunction cubicAt(p0, p1, p2, p3, t) {\n    var onet = 1 - t;\n    return onet * onet * (onet * p0 + 3 * t * p1)\n            + t * t * (t * p3 + 3 * onet * p2);\n}\n\n/**\n * 计算三次贝塞尔导数值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @return {number}\n */\nfunction cubicDerivativeAt(p0, p1, p2, p3, t) {\n    var onet = 1 - t;\n    return 3 * (\n        ((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet\n        + (p3 - p2) * t * t\n    );\n}\n\n/**\n * 计算三次贝塞尔方程根，使用盛金公式\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} val\n * @param  {Array.<number>} roots\n * @return {number} 有效根数目\n */\nfunction cubicRootAt(p0, p1, p2, p3, val, roots) {\n    // Evaluate roots of cubic functions\n    var a = p3 + 3 * (p1 - p2) - p0;\n    var b = 3 * (p2 - p1 * 2 + p0);\n    var c = 3 * (p1 - p0);\n    var d = p0 - val;\n\n    var A = b * b - 3 * a * c;\n    var B = b * c - 9 * a * d;\n    var C = c * c - 3 * b * d;\n\n    var n = 0;\n\n    if (isAroundZero(A) && isAroundZero(B)) {\n        if (isAroundZero(b)) {\n            roots[0] = 0;\n        }\n        else {\n            var t1 = -c / b;  //t1, t2, t3, b is not zero\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = B * B - 4 * A * C;\n\n        if (isAroundZero(disc)) {\n            var K = B / A;\n            var t1 = -b / a + K;  // t1, a is not zero\n            var t2 = -K / 2;  // t2, t3\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var Y1 = A * b + 1.5 * a * (-B + discSqrt);\n            var Y2 = A * b + 1.5 * a * (-B - discSqrt);\n            if (Y1 < 0) {\n                Y1 = -mathPow(-Y1, ONE_THIRD);\n            }\n            else {\n                Y1 = mathPow(Y1, ONE_THIRD);\n            }\n            if (Y2 < 0) {\n                Y2 = -mathPow(-Y2, ONE_THIRD);\n            }\n            else {\n                Y2 = mathPow(Y2, ONE_THIRD);\n            }\n            var t1 = (-b - (Y1 + Y2)) / (3 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n        else {\n            var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt$2(A * A * A));\n            var theta = Math.acos(T) / 3;\n            var ASqrt = mathSqrt$2(A);\n            var tmp = Math.cos(theta);\n\n            var t1 = (-b - 2 * ASqrt * tmp) / (3 * a);\n            var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a);\n            var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n            if (t3 >= 0 && t3 <= 1) {\n                roots[n++] = t3;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 计算三次贝塞尔方程极限值的位置\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {Array.<number>} extrema\n * @return {number} 有效数目\n */\nfunction cubicExtrema(p0, p1, p2, p3, extrema) {\n    var b = 6 * p2 - 12 * p1 + 6 * p0;\n    var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2;\n    var c = 3 * p1 - 3 * p0;\n\n    var n = 0;\n    if (isAroundZero(a)) {\n        if (isNotAroundZero$1(b)) {\n            var t1 = -c / b;\n            if (t1 >= 0 && t1 <= 1) {\n                extrema[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = b * b - 4 * a * c;\n        if (isAroundZero(disc)) {\n            extrema[0] = -b / (2 * a);\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var t1 = (-b + discSqrt) / (2 * a);\n            var t2 = (-b - discSqrt) / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                extrema[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                extrema[n++] = t2;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 细分三次贝塞尔曲线\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @param  {Array.<number>} out\n */\nfunction cubicSubdivide(p0, p1, p2, p3, t, out) {\n    var p01 = (p1 - p0) * t + p0;\n    var p12 = (p2 - p1) * t + p1;\n    var p23 = (p3 - p2) * t + p2;\n\n    var p012 = (p12 - p01) * t + p01;\n    var p123 = (p23 - p12) * t + p12;\n\n    var p0123 = (p123 - p012) * t + p012;\n    // Seg0\n    out[0] = p0;\n    out[1] = p01;\n    out[2] = p012;\n    out[3] = p0123;\n    // Seg1\n    out[4] = p0123;\n    out[5] = p123;\n    out[6] = p23;\n    out[7] = p3;\n}\n\n/**\n * 投射点到三次贝塞尔曲线上，返回投射距离。\n * 投射点有可能会有一个或者多个，这里只返回其中距离最短的一个。\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x3\n * @param {number} y3\n * @param {number} x\n * @param {number} y\n * @param {Array.<number>} [out] 投射点\n * @return {number}\n */\nfunction cubicProjectPoint(\n    x0, y0, x1, y1, x2, y2, x3, y3,\n    x, y, out\n) {\n    // http://pomax.github.io/bezierinfo/#projections\n    var t;\n    var interval = 0.005;\n    var d = Infinity;\n    var prev;\n    var next;\n    var d1;\n    var d2;\n\n    _v0[0] = x;\n    _v0[1] = y;\n\n    // 先粗略估计一下可能的最小距离的 t 值\n    // PENDING\n    for (var _t = 0; _t < 1; _t += 0.05) {\n        _v1[0] = cubicAt(x0, x1, x2, x3, _t);\n        _v1[1] = cubicAt(y0, y1, y2, y3, _t);\n        d1 = distSquare(_v0, _v1);\n        if (d1 < d) {\n            t = _t;\n            d = d1;\n        }\n    }\n    d = Infinity;\n\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        if (interval < EPSILON_NUMERIC) {\n            break;\n        }\n        prev = t - interval;\n        next = t + interval;\n        // t - interval\n        _v1[0] = cubicAt(x0, x1, x2, x3, prev);\n        _v1[1] = cubicAt(y0, y1, y2, y3, prev);\n\n        d1 = distSquare(_v1, _v0);\n\n        if (prev >= 0 && d1 < d) {\n            t = prev;\n            d = d1;\n        }\n        else {\n            // t + interval\n            _v2[0] = cubicAt(x0, x1, x2, x3, next);\n            _v2[1] = cubicAt(y0, y1, y2, y3, next);\n            d2 = distSquare(_v2, _v0);\n\n            if (next <= 1 && d2 < d) {\n                t = next;\n                d = d2;\n            }\n            else {\n                interval *= 0.5;\n            }\n        }\n    }\n    // t\n    if (out) {\n        out[0] = cubicAt(x0, x1, x2, x3, t);\n        out[1] = cubicAt(y0, y1, y2, y3, t);\n    }\n    // console.log(interval, i);\n    return mathSqrt$2(d);\n}\n\n/**\n * 计算二次方贝塞尔值\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @return {number}\n */\nfunction quadraticAt(p0, p1, p2, t) {\n    var onet = 1 - t;\n    return onet * (onet * p0 + 2 * t * p1) + t * t * p2;\n}\n\n/**\n * 计算二次方贝塞尔导数值\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @return {number}\n */\nfunction quadraticDerivativeAt(p0, p1, p2, t) {\n    return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1));\n}\n\n/**\n * 计算二次方贝塞尔方程根\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @param  {Array.<number>} roots\n * @return {number} 有效根数目\n */\nfunction quadraticRootAt(p0, p1, p2, val, roots) {\n    var a = p0 - 2 * p1 + p2;\n    var b = 2 * (p1 - p0);\n    var c = p0 - val;\n\n    var n = 0;\n    if (isAroundZero(a)) {\n        if (isNotAroundZero$1(b)) {\n            var t1 = -c / b;\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = b * b - 4 * a * c;\n        if (isAroundZero(disc)) {\n            var t1 = -b / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var t1 = (-b + discSqrt) / (2 * a);\n            var t2 = (-b - discSqrt) / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 计算二次贝塞尔方程极限值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @return {number}\n */\nfunction quadraticExtremum(p0, p1, p2) {\n    var divider = p0 + p2 - 2 * p1;\n    if (divider === 0) {\n        // p1 is center of p0 and p2\n        return 0.5;\n    }\n    else {\n        return (p0 - p1) / divider;\n    }\n}\n\n/**\n * 细分二次贝塞尔曲线\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @param  {Array.<number>} out\n */\nfunction quadraticSubdivide(p0, p1, p2, t, out) {\n    var p01 = (p1 - p0) * t + p0;\n    var p12 = (p2 - p1) * t + p1;\n    var p012 = (p12 - p01) * t + p01;\n\n    // Seg0\n    out[0] = p0;\n    out[1] = p01;\n    out[2] = p012;\n\n    // Seg1\n    out[3] = p012;\n    out[4] = p12;\n    out[5] = p2;\n}\n\n/**\n * 投射点到二次贝塞尔曲线上，返回投射距离。\n * 投射点有可能会有一个或者多个，这里只返回其中距离最短的一个。\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x\n * @param {number} y\n * @param {Array.<number>} out 投射点\n * @return {number}\n */\nfunction quadraticProjectPoint(\n    x0, y0, x1, y1, x2, y2,\n    x, y, out\n) {\n    // http://pomax.github.io/bezierinfo/#projections\n    var t;\n    var interval = 0.005;\n    var d = Infinity;\n\n    _v0[0] = x;\n    _v0[1] = y;\n\n    // 先粗略估计一下可能的最小距离的 t 值\n    // PENDING\n    for (var _t = 0; _t < 1; _t += 0.05) {\n        _v1[0] = quadraticAt(x0, x1, x2, _t);\n        _v1[1] = quadraticAt(y0, y1, y2, _t);\n        var d1 = distSquare(_v0, _v1);\n        if (d1 < d) {\n            t = _t;\n            d = d1;\n        }\n    }\n    d = Infinity;\n\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        if (interval < EPSILON_NUMERIC) {\n            break;\n        }\n        var prev = t - interval;\n        var next = t + interval;\n        // t - interval\n        _v1[0] = quadraticAt(x0, x1, x2, prev);\n        _v1[1] = quadraticAt(y0, y1, y2, prev);\n\n        var d1 = distSquare(_v1, _v0);\n\n        if (prev >= 0 && d1 < d) {\n            t = prev;\n            d = d1;\n        }\n        else {\n            // t + interval\n            _v2[0] = quadraticAt(x0, x1, x2, next);\n            _v2[1] = quadraticAt(y0, y1, y2, next);\n            var d2 = distSquare(_v2, _v0);\n            if (next <= 1 && d2 < d) {\n                t = next;\n                d = d2;\n            }\n            else {\n                interval *= 0.5;\n            }\n        }\n    }\n    // t\n    if (out) {\n        out[0] = quadraticAt(x0, x1, x2, t);\n        out[1] = quadraticAt(y0, y1, y2, t);\n    }\n    // console.log(interval, i);\n    return mathSqrt$2(d);\n}\n\n/**\n * @author Yi Shen(https://github.com/pissang)\n */\n\nvar mathMin$3 = Math.min;\nvar mathMax$3 = Math.max;\nvar mathSin$2 = Math.sin;\nvar mathCos$2 = Math.cos;\nvar PI2 = Math.PI * 2;\n\nvar start = create();\nvar end = create();\nvar extremity = create();\n\n/**\n * 从顶点数组中计算出最小包围盒，写入`min`和`max`中\n * @module zrender/core/bbox\n * @param {Array<Object>} points 顶点数组\n * @param {number} min\n * @param {number} max\n */\nfunction fromPoints(points, min$$1, max$$1) {\n    if (points.length === 0) {\n        return;\n    }\n    var p = points[0];\n    var left = p[0];\n    var right = p[0];\n    var top = p[1];\n    var bottom = p[1];\n    var i;\n\n    for (i = 1; i < points.length; i++) {\n        p = points[i];\n        left = mathMin$3(left, p[0]);\n        right = mathMax$3(right, p[0]);\n        top = mathMin$3(top, p[1]);\n        bottom = mathMax$3(bottom, p[1]);\n    }\n\n    min$$1[0] = left;\n    min$$1[1] = top;\n    max$$1[0] = right;\n    max$$1[1] = bottom;\n}\n\n/**\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromLine(x0, y0, x1, y1, min$$1, max$$1) {\n    min$$1[0] = mathMin$3(x0, x1);\n    min$$1[1] = mathMin$3(y0, y1);\n    max$$1[0] = mathMax$3(x0, x1);\n    max$$1[1] = mathMax$3(y0, y1);\n}\n\nvar xDim = [];\nvar yDim = [];\n/**\n * 从三阶贝塞尔曲线(p0, p1, p2, p3)中计算出最小包围盒，写入`min`和`max`中\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x3\n * @param {number} y3\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromCubic(\n    x0, y0, x1, y1, x2, y2, x3, y3, min$$1, max$$1\n) {\n    var cubicExtrema$$1 = cubicExtrema;\n    var cubicAt$$1 = cubicAt;\n    var i;\n    var n = cubicExtrema$$1(x0, x1, x2, x3, xDim);\n    min$$1[0] = Infinity;\n    min$$1[1] = Infinity;\n    max$$1[0] = -Infinity;\n    max$$1[1] = -Infinity;\n\n    for (i = 0; i < n; i++) {\n        var x = cubicAt$$1(x0, x1, x2, x3, xDim[i]);\n        min$$1[0] = mathMin$3(x, min$$1[0]);\n        max$$1[0] = mathMax$3(x, max$$1[0]);\n    }\n    n = cubicExtrema$$1(y0, y1, y2, y3, yDim);\n    for (i = 0; i < n; i++) {\n        var y = cubicAt$$1(y0, y1, y2, y3, yDim[i]);\n        min$$1[1] = mathMin$3(y, min$$1[1]);\n        max$$1[1] = mathMax$3(y, max$$1[1]);\n    }\n\n    min$$1[0] = mathMin$3(x0, min$$1[0]);\n    max$$1[0] = mathMax$3(x0, max$$1[0]);\n    min$$1[0] = mathMin$3(x3, min$$1[0]);\n    max$$1[0] = mathMax$3(x3, max$$1[0]);\n\n    min$$1[1] = mathMin$3(y0, min$$1[1]);\n    max$$1[1] = mathMax$3(y0, max$$1[1]);\n    min$$1[1] = mathMin$3(y3, min$$1[1]);\n    max$$1[1] = mathMax$3(y3, max$$1[1]);\n}\n\n/**\n * 从二阶贝塞尔曲线(p0, p1, p2)中计算出最小包围盒，写入`min`和`max`中\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromQuadratic(x0, y0, x1, y1, x2, y2, min$$1, max$$1) {\n    var quadraticExtremum$$1 = quadraticExtremum;\n    var quadraticAt$$1 = quadraticAt;\n    // Find extremities, where derivative in x dim or y dim is zero\n    var tx =\n        mathMax$3(\n            mathMin$3(quadraticExtremum$$1(x0, x1, x2), 1), 0\n        );\n    var ty =\n        mathMax$3(\n            mathMin$3(quadraticExtremum$$1(y0, y1, y2), 1), 0\n        );\n\n    var x = quadraticAt$$1(x0, x1, x2, tx);\n    var y = quadraticAt$$1(y0, y1, y2, ty);\n\n    min$$1[0] = mathMin$3(x0, x2, x);\n    min$$1[1] = mathMin$3(y0, y2, y);\n    max$$1[0] = mathMax$3(x0, x2, x);\n    max$$1[1] = mathMax$3(y0, y2, y);\n}\n\n/**\n * 从圆弧中计算出最小包围盒，写入`min`和`max`中\n * @method\n * @memberOf module:zrender/core/bbox\n * @param {number} x\n * @param {number} y\n * @param {number} rx\n * @param {number} ry\n * @param {number} startAngle\n * @param {number} endAngle\n * @param {number} anticlockwise\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromArc(\n    x, y, rx, ry, startAngle, endAngle, anticlockwise, min$$1, max$$1\n) {\n    var vec2Min = min;\n    var vec2Max = max;\n\n    var diff = Math.abs(startAngle - endAngle);\n\n\n    if (diff % PI2 < 1e-4 && diff > 1e-4) {\n        // Is a circle\n        min$$1[0] = x - rx;\n        min$$1[1] = y - ry;\n        max$$1[0] = x + rx;\n        max$$1[1] = y + ry;\n        return;\n    }\n\n    start[0] = mathCos$2(startAngle) * rx + x;\n    start[1] = mathSin$2(startAngle) * ry + y;\n\n    end[0] = mathCos$2(endAngle) * rx + x;\n    end[1] = mathSin$2(endAngle) * ry + y;\n\n    vec2Min(min$$1, start, end);\n    vec2Max(max$$1, start, end);\n\n    // Thresh to [0, Math.PI * 2]\n    startAngle = startAngle % (PI2);\n    if (startAngle < 0) {\n        startAngle = startAngle + PI2;\n    }\n    endAngle = endAngle % (PI2);\n    if (endAngle < 0) {\n        endAngle = endAngle + PI2;\n    }\n\n    if (startAngle > endAngle && !anticlockwise) {\n        endAngle += PI2;\n    }\n    else if (startAngle < endAngle && anticlockwise) {\n        startAngle += PI2;\n    }\n    if (anticlockwise) {\n        var tmp = endAngle;\n        endAngle = startAngle;\n        startAngle = tmp;\n    }\n\n    // var number = 0;\n    // var step = (anticlockwise ? -Math.PI : Math.PI) / 2;\n    for (var angle = 0; angle < endAngle; angle += Math.PI / 2) {\n        if (angle > startAngle) {\n            extremity[0] = mathCos$2(angle) * rx + x;\n            extremity[1] = mathSin$2(angle) * ry + y;\n\n            vec2Min(min$$1, extremity, min$$1);\n            vec2Max(max$$1, extremity, max$$1);\n        }\n    }\n}\n\n/**\n * Path 代理，可以在`buildPath`中用于替代`ctx`, 会保存每个path操作的命令到pathCommands属性中\n * 可以用于 isInsidePath 判断以及获取boundingRect\n *\n * @module zrender/core/PathProxy\n * @author Yi Shen (http://www.github.com/pissang)\n */\n\n// TODO getTotalLength, getPointAtLength\n\nvar CMD = {\n    M: 1,\n    L: 2,\n    C: 3,\n    Q: 4,\n    A: 5,\n    Z: 6,\n    // Rect\n    R: 7\n};\n\n// var CMD_MEM_SIZE = {\n//     M: 3,\n//     L: 3,\n//     C: 7,\n//     Q: 5,\n//     A: 9,\n//     R: 5,\n//     Z: 1\n// };\n\nvar min$1 = [];\nvar max$1 = [];\nvar min2 = [];\nvar max2 = [];\nvar mathMin$2 = Math.min;\nvar mathMax$2 = Math.max;\nvar mathCos$1 = Math.cos;\nvar mathSin$1 = Math.sin;\nvar mathSqrt$1 = Math.sqrt;\nvar mathAbs = Math.abs;\n\nvar hasTypedArray = typeof Float32Array !== 'undefined';\n\n/**\n * @alias module:zrender/core/PathProxy\n * @constructor\n */\nvar PathProxy = function (notSaveData) {\n\n    this._saveData = !(notSaveData || false);\n\n    if (this._saveData) {\n        /**\n         * Path data. Stored as flat array\n         * @type {Array.<Object>}\n         */\n        this.data = [];\n    }\n\n    this._ctx = null;\n};\n\n/**\n * 快速计算Path包围盒（并不是最小包围盒）\n * @return {Object}\n */\nPathProxy.prototype = {\n\n    constructor: PathProxy,\n\n    _xi: 0,\n    _yi: 0,\n\n    _x0: 0,\n    _y0: 0,\n    // Unit x, Unit y. Provide for avoiding drawing that too short line segment\n    _ux: 0,\n    _uy: 0,\n\n    _len: 0,\n\n    _lineDash: null,\n\n    _dashOffset: 0,\n\n    _dashIdx: 0,\n\n    _dashSum: 0,\n\n    /**\n     * @readOnly\n     */\n    setScale: function (sx, sy) {\n        this._ux = mathAbs(1 / devicePixelRatio / sx) || 0;\n        this._uy = mathAbs(1 / devicePixelRatio / sy) || 0;\n    },\n\n    getContext: function () {\n        return this._ctx;\n    },\n\n    /**\n     * @param  {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    beginPath: function (ctx) {\n\n        this._ctx = ctx;\n\n        ctx && ctx.beginPath();\n\n        ctx && (this.dpr = ctx.dpr);\n\n        // Reset\n        if (this._saveData) {\n            this._len = 0;\n        }\n\n        if (this._lineDash) {\n            this._lineDash = null;\n\n            this._dashOffset = 0;\n        }\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x\n     * @param  {number} y\n     * @return {module:zrender/core/PathProxy}\n     */\n    moveTo: function (x, y) {\n        this.addData(CMD.M, x, y);\n        this._ctx && this._ctx.moveTo(x, y);\n\n        // x0, y0, xi, yi 是记录在 _dashedXXXXTo 方法中使用\n        // xi, yi 记录当前点, x0, y0 在 closePath 的时候回到起始点。\n        // 有可能在 beginPath 之后直接调用 lineTo，这时候 x0, y0 需要\n        // 在 lineTo 方法中记录，这里先不考虑这种情况，dashed line 也只在 IE10- 中不支持\n        this._x0 = x;\n        this._y0 = y;\n\n        this._xi = x;\n        this._yi = y;\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x\n     * @param  {number} y\n     * @return {module:zrender/core/PathProxy}\n     */\n    lineTo: function (x, y) {\n        var exceedUnit = mathAbs(x - this._xi) > this._ux\n            || mathAbs(y - this._yi) > this._uy\n            // Force draw the first segment\n            || this._len < 5;\n\n        this.addData(CMD.L, x, y);\n\n        if (this._ctx && exceedUnit) {\n            this._needsDash() ? this._dashedLineTo(x, y)\n                : this._ctx.lineTo(x, y);\n        }\n        if (exceedUnit) {\n            this._xi = x;\n            this._yi = y;\n        }\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x1\n     * @param  {number} y1\n     * @param  {number} x2\n     * @param  {number} y2\n     * @param  {number} x3\n     * @param  {number} y3\n     * @return {module:zrender/core/PathProxy}\n     */\n    bezierCurveTo: function (x1, y1, x2, y2, x3, y3) {\n        this.addData(CMD.C, x1, y1, x2, y2, x3, y3);\n        if (this._ctx) {\n            this._needsDash() ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3)\n                : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);\n        }\n        this._xi = x3;\n        this._yi = y3;\n        return this;\n    },\n\n    /**\n     * @param  {number} x1\n     * @param  {number} y1\n     * @param  {number} x2\n     * @param  {number} y2\n     * @return {module:zrender/core/PathProxy}\n     */\n    quadraticCurveTo: function (x1, y1, x2, y2) {\n        this.addData(CMD.Q, x1, y1, x2, y2);\n        if (this._ctx) {\n            this._needsDash() ? this._dashedQuadraticTo(x1, y1, x2, y2)\n                : this._ctx.quadraticCurveTo(x1, y1, x2, y2);\n        }\n        this._xi = x2;\n        this._yi = y2;\n        return this;\n    },\n\n    /**\n     * @param  {number} cx\n     * @param  {number} cy\n     * @param  {number} r\n     * @param  {number} startAngle\n     * @param  {number} endAngle\n     * @param  {boolean} anticlockwise\n     * @return {module:zrender/core/PathProxy}\n     */\n    arc: function (cx, cy, r, startAngle, endAngle, anticlockwise) {\n        this.addData(\n            CMD.A, cx, cy, r, r, startAngle, endAngle - startAngle, 0, anticlockwise ? 0 : 1\n        );\n        this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);\n\n        this._xi = mathCos$1(endAngle) * r + cx;\n        this._yi = mathSin$1(endAngle) * r + cy;\n        return this;\n    },\n\n    // TODO\n    arcTo: function (x1, y1, x2, y2, radius) {\n        if (this._ctx) {\n            this._ctx.arcTo(x1, y1, x2, y2, radius);\n        }\n        return this;\n    },\n\n    // TODO\n    rect: function (x, y, w, h) {\n        this._ctx && this._ctx.rect(x, y, w, h);\n        this.addData(CMD.R, x, y, w, h);\n        return this;\n    },\n\n    /**\n     * @return {module:zrender/core/PathProxy}\n     */\n    closePath: function () {\n        this.addData(CMD.Z);\n\n        var ctx = this._ctx;\n        var x0 = this._x0;\n        var y0 = this._y0;\n        if (ctx) {\n            this._needsDash() && this._dashedLineTo(x0, y0);\n            ctx.closePath();\n        }\n\n        this._xi = x0;\n        this._yi = y0;\n        return this;\n    },\n\n    /**\n     * Context 从外部传入，因为有可能是 rebuildPath 完之后再 fill。\n     * stroke 同样\n     * @param {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    fill: function (ctx) {\n        ctx && ctx.fill();\n        this.toStatic();\n    },\n\n    /**\n     * @param {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    stroke: function (ctx) {\n        ctx && ctx.stroke();\n        this.toStatic();\n    },\n\n    /**\n     * 必须在其它绘制命令前调用\n     * Must be invoked before all other path drawing methods\n     * @return {module:zrender/core/PathProxy}\n     */\n    setLineDash: function (lineDash) {\n        if (lineDash instanceof Array) {\n            this._lineDash = lineDash;\n\n            this._dashIdx = 0;\n\n            var lineDashSum = 0;\n            for (var i = 0; i < lineDash.length; i++) {\n                lineDashSum += lineDash[i];\n            }\n            this._dashSum = lineDashSum;\n        }\n        return this;\n    },\n\n    /**\n     * 必须在其它绘制命令前调用\n     * Must be invoked before all other path drawing methods\n     * @return {module:zrender/core/PathProxy}\n     */\n    setLineDashOffset: function (offset) {\n        this._dashOffset = offset;\n        return this;\n    },\n\n    /**\n     *\n     * @return {boolean}\n     */\n    len: function () {\n        return this._len;\n    },\n\n    /**\n     * 直接设置 Path 数据\n     */\n    setData: function (data) {\n\n        var len$$1 = data.length;\n\n        if (!(this.data && this.data.length === len$$1) && hasTypedArray) {\n            this.data = new Float32Array(len$$1);\n        }\n\n        for (var i = 0; i < len$$1; i++) {\n            this.data[i] = data[i];\n        }\n\n        this._len = len$$1;\n    },\n\n    /**\n     * 添加子路径\n     * @param {module:zrender/core/PathProxy|Array.<module:zrender/core/PathProxy>} path\n     */\n    appendPath: function (path) {\n        if (!(path instanceof Array)) {\n            path = [path];\n        }\n        var len$$1 = path.length;\n        var appendSize = 0;\n        var offset = this._len;\n        for (var i = 0; i < len$$1; i++) {\n            appendSize += path[i].len();\n        }\n        if (hasTypedArray && (this.data instanceof Float32Array)) {\n            this.data = new Float32Array(offset + appendSize);\n        }\n        for (var i = 0; i < len$$1; i++) {\n            var appendPathData = path[i].data;\n            for (var k = 0; k < appendPathData.length; k++) {\n                this.data[offset++] = appendPathData[k];\n            }\n        }\n        this._len = offset;\n    },\n\n    /**\n     * 填充 Path 数据。\n     * 尽量复用而不申明新的数组。大部分图形重绘的指令数据长度都是不变的。\n     */\n    addData: function (cmd) {\n        if (!this._saveData) {\n            return;\n        }\n\n        var data = this.data;\n        if (this._len + arguments.length > data.length) {\n            // 因为之前的数组已经转换成静态的 Float32Array\n            // 所以不够用时需要扩展一个新的动态数组\n            this._expandData();\n            data = this.data;\n        }\n        for (var i = 0; i < arguments.length; i++) {\n            data[this._len++] = arguments[i];\n        }\n\n        this._prevCmd = cmd;\n    },\n\n    _expandData: function () {\n        // Only if data is Float32Array\n        if (!(this.data instanceof Array)) {\n            var newData = [];\n            for (var i = 0; i < this._len; i++) {\n                newData[i] = this.data[i];\n            }\n            this.data = newData;\n        }\n    },\n\n    /**\n     * If needs js implemented dashed line\n     * @return {boolean}\n     * @private\n     */\n    _needsDash: function () {\n        return this._lineDash;\n    },\n\n    _dashedLineTo: function (x1, y1) {\n        var dashSum = this._dashSum;\n        var offset = this._dashOffset;\n        var lineDash = this._lineDash;\n        var ctx = this._ctx;\n\n        var x0 = this._xi;\n        var y0 = this._yi;\n        var dx = x1 - x0;\n        var dy = y1 - y0;\n        var dist$$1 = mathSqrt$1(dx * dx + dy * dy);\n        var x = x0;\n        var y = y0;\n        var dash;\n        var nDash = lineDash.length;\n        var idx;\n        dx /= dist$$1;\n        dy /= dist$$1;\n\n        if (offset < 0) {\n            // Convert to positive offset\n            offset = dashSum + offset;\n        }\n        offset %= dashSum;\n        x -= offset * dx;\n        y -= offset * dy;\n\n        while ((dx > 0 && x <= x1) || (dx < 0 && x >= x1)\n        || (dx === 0 && ((dy > 0 && y <= y1) || (dy < 0 && y >= y1)))) {\n            idx = this._dashIdx;\n            dash = lineDash[idx];\n            x += dx * dash;\n            y += dy * dash;\n            this._dashIdx = (idx + 1) % nDash;\n            // Skip positive offset\n            if ((dx > 0 && x < x0) || (dx < 0 && x > x0) || (dy > 0 && y < y0) || (dy < 0 && y > y0)) {\n                continue;\n            }\n            ctx[idx % 2 ? 'moveTo' : 'lineTo'](\n                dx >= 0 ? mathMin$2(x, x1) : mathMax$2(x, x1),\n                dy >= 0 ? mathMin$2(y, y1) : mathMax$2(y, y1)\n            );\n        }\n        // Offset for next lineTo\n        dx = x - x1;\n        dy = y - y1;\n        this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);\n    },\n\n    // Not accurate dashed line to\n    _dashedBezierTo: function (x1, y1, x2, y2, x3, y3) {\n        var dashSum = this._dashSum;\n        var offset = this._dashOffset;\n        var lineDash = this._lineDash;\n        var ctx = this._ctx;\n\n        var x0 = this._xi;\n        var y0 = this._yi;\n        var t;\n        var dx;\n        var dy;\n        var cubicAt$$1 = cubicAt;\n        var bezierLen = 0;\n        var idx = this._dashIdx;\n        var nDash = lineDash.length;\n\n        var x;\n        var y;\n\n        var tmpLen = 0;\n\n        if (offset < 0) {\n            // Convert to positive offset\n            offset = dashSum + offset;\n        }\n        offset %= dashSum;\n        // Bezier approx length\n        for (t = 0; t < 1; t += 0.1) {\n            dx = cubicAt$$1(x0, x1, x2, x3, t + 0.1)\n                - cubicAt$$1(x0, x1, x2, x3, t);\n            dy = cubicAt$$1(y0, y1, y2, y3, t + 0.1)\n                - cubicAt$$1(y0, y1, y2, y3, t);\n            bezierLen += mathSqrt$1(dx * dx + dy * dy);\n        }\n\n        // Find idx after add offset\n        for (; idx < nDash; idx++) {\n            tmpLen += lineDash[idx];\n            if (tmpLen > offset) {\n                break;\n            }\n        }\n        t = (tmpLen - offset) / bezierLen;\n\n        while (t <= 1) {\n\n            x = cubicAt$$1(x0, x1, x2, x3, t);\n            y = cubicAt$$1(y0, y1, y2, y3, t);\n\n            // Use line to approximate dashed bezier\n            // Bad result if dash is long\n            idx % 2 ? ctx.moveTo(x, y)\n                : ctx.lineTo(x, y);\n\n            t += lineDash[idx] / bezierLen;\n\n            idx = (idx + 1) % nDash;\n        }\n\n        // Finish the last segment and calculate the new offset\n        (idx % 2 !== 0) && ctx.lineTo(x3, y3);\n        dx = x3 - x;\n        dy = y3 - y;\n        this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);\n    },\n\n    _dashedQuadraticTo: function (x1, y1, x2, y2) {\n        // Convert quadratic to cubic using degree elevation\n        var x3 = x2;\n        var y3 = y2;\n        x2 = (x2 + 2 * x1) / 3;\n        y2 = (y2 + 2 * y1) / 3;\n        x1 = (this._xi + 2 * x1) / 3;\n        y1 = (this._yi + 2 * y1) / 3;\n\n        this._dashedBezierTo(x1, y1, x2, y2, x3, y3);\n    },\n\n    /**\n     * 转成静态的 Float32Array 减少堆内存占用\n     * Convert dynamic array to static Float32Array\n     */\n    toStatic: function () {\n        var data = this.data;\n        if (data instanceof Array) {\n            data.length = this._len;\n            if (hasTypedArray) {\n                this.data = new Float32Array(data);\n            }\n        }\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function () {\n        min$1[0] = min$1[1] = min2[0] = min2[1] = Number.MAX_VALUE;\n        max$1[0] = max$1[1] = max2[0] = max2[1] = -Number.MAX_VALUE;\n\n        var data = this.data;\n        var xi = 0;\n        var yi = 0;\n        var x0 = 0;\n        var y0 = 0;\n\n        for (var i = 0; i < data.length;) {\n            var cmd = data[i++];\n\n            if (i === 1) {\n                // 如果第一个命令是 L, C, Q\n                // 则 previous point 同绘制命令的第一个 point\n                //\n                // 第一个命令为 Arc 的情况下会在后面特殊处理\n                xi = data[i];\n                yi = data[i + 1];\n\n                x0 = xi;\n                y0 = yi;\n            }\n\n            switch (cmd) {\n                case CMD.M:\n                    // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点\n                    // 在 closePath 的时候使用\n                    x0 = data[i++];\n                    y0 = data[i++];\n                    xi = x0;\n                    yi = y0;\n                    min2[0] = x0;\n                    min2[1] = y0;\n                    max2[0] = x0;\n                    max2[1] = y0;\n                    break;\n                case CMD.L:\n                    fromLine(xi, yi, data[i], data[i + 1], min2, max2);\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.C:\n                    fromCubic(\n                        xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        min2, max2\n                    );\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.Q:\n                    fromQuadratic(\n                        xi, yi, data[i++], data[i++], data[i], data[i + 1],\n                        min2, max2\n                    );\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.A:\n                    // TODO Arc 判断的开销比较大\n                    var cx = data[i++];\n                    var cy = data[i++];\n                    var rx = data[i++];\n                    var ry = data[i++];\n                    var startAngle = data[i++];\n                    var endAngle = data[i++] + startAngle;\n                    // TODO Arc 旋转\n                    i += 1;\n                    var anticlockwise = 1 - data[i++];\n\n                    if (i === 1) {\n                        // 直接使用 arc 命令\n                        // 第一个命令起点还未定义\n                        x0 = mathCos$1(startAngle) * rx + cx;\n                        y0 = mathSin$1(startAngle) * ry + cy;\n                    }\n\n                    fromArc(\n                        cx, cy, rx, ry, startAngle, endAngle,\n                        anticlockwise, min2, max2\n                    );\n\n                    xi = mathCos$1(endAngle) * rx + cx;\n                    yi = mathSin$1(endAngle) * ry + cy;\n                    break;\n                case CMD.R:\n                    x0 = xi = data[i++];\n                    y0 = yi = data[i++];\n                    var width = data[i++];\n                    var height = data[i++];\n                    // Use fromLine\n                    fromLine(x0, y0, x0 + width, y0 + height, min2, max2);\n                    break;\n                case CMD.Z:\n                    xi = x0;\n                    yi = y0;\n                    break;\n            }\n\n            // Union\n            min(min$1, min$1, min2);\n            max(max$1, max$1, max2);\n        }\n\n        // No data\n        if (i === 0) {\n            min$1[0] = min$1[1] = max$1[0] = max$1[1] = 0;\n        }\n\n        return new BoundingRect(\n            min$1[0], min$1[1], max$1[0] - min$1[0], max$1[1] - min$1[1]\n        );\n    },\n\n    /**\n     * Rebuild path from current data\n     * Rebuild path will not consider javascript implemented line dash.\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    rebuildPath: function (ctx) {\n        var d = this.data;\n        var x0, y0;\n        var xi, yi;\n        var x, y;\n        var ux = this._ux;\n        var uy = this._uy;\n        var len$$1 = this._len;\n        for (var i = 0; i < len$$1;) {\n            var cmd = d[i++];\n\n            if (i === 1) {\n                // 如果第一个命令是 L, C, Q\n                // 则 previous point 同绘制命令的第一个 point\n                //\n                // 第一个命令为 Arc 的情况下会在后面特殊处理\n                xi = d[i];\n                yi = d[i + 1];\n\n                x0 = xi;\n                y0 = yi;\n            }\n            switch (cmd) {\n                case CMD.M:\n                    x0 = xi = d[i++];\n                    y0 = yi = d[i++];\n                    ctx.moveTo(xi, yi);\n                    break;\n                case CMD.L:\n                    x = d[i++];\n                    y = d[i++];\n                    // Not draw too small seg between\n                    if (mathAbs(x - xi) > ux || mathAbs(y - yi) > uy || i === len$$1 - 1) {\n                        ctx.lineTo(x, y);\n                        xi = x;\n                        yi = y;\n                    }\n                    break;\n                case CMD.C:\n                    ctx.bezierCurveTo(\n                        d[i++], d[i++], d[i++], d[i++], d[i++], d[i++]\n                    );\n                    xi = d[i - 2];\n                    yi = d[i - 1];\n                    break;\n                case CMD.Q:\n                    ctx.quadraticCurveTo(d[i++], d[i++], d[i++], d[i++]);\n                    xi = d[i - 2];\n                    yi = d[i - 1];\n                    break;\n                case CMD.A:\n                    var cx = d[i++];\n                    var cy = d[i++];\n                    var rx = d[i++];\n                    var ry = d[i++];\n                    var theta = d[i++];\n                    var dTheta = d[i++];\n                    var psi = d[i++];\n                    var fs = d[i++];\n                    var r = (rx > ry) ? rx : ry;\n                    var scaleX = (rx > ry) ? 1 : rx / ry;\n                    var scaleY = (rx > ry) ? ry / rx : 1;\n                    var isEllipse = Math.abs(rx - ry) > 1e-3;\n                    var endAngle = theta + dTheta;\n                    if (isEllipse) {\n                        ctx.translate(cx, cy);\n                        ctx.rotate(psi);\n                        ctx.scale(scaleX, scaleY);\n                        ctx.arc(0, 0, r, theta, endAngle, 1 - fs);\n                        ctx.scale(1 / scaleX, 1 / scaleY);\n                        ctx.rotate(-psi);\n                        ctx.translate(-cx, -cy);\n                    }\n                    else {\n                        ctx.arc(cx, cy, r, theta, endAngle, 1 - fs);\n                    }\n\n                    if (i === 1) {\n                        // 直接使用 arc 命令\n                        // 第一个命令起点还未定义\n                        x0 = mathCos$1(theta) * rx + cx;\n                        y0 = mathSin$1(theta) * ry + cy;\n                    }\n                    xi = mathCos$1(endAngle) * rx + cx;\n                    yi = mathSin$1(endAngle) * ry + cy;\n                    break;\n                case CMD.R:\n                    x0 = xi = d[i];\n                    y0 = yi = d[i + 1];\n                    ctx.rect(d[i++], d[i++], d[i++], d[i++]);\n                    break;\n                case CMD.Z:\n                    ctx.closePath();\n                    xi = x0;\n                    yi = y0;\n            }\n        }\n    }\n};\n\nPathProxy.CMD = CMD;\n\n/**\n * 线段包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$1(x0, y0, x1, y1, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    var _a = 0;\n    var _b = x0;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l)\n        || (y < y0 - _l && y < y1 - _l)\n        || (x > x0 + _l && x > x1 + _l)\n        || (x < x0 - _l && x < x1 - _l)\n    ) {\n        return false;\n    }\n\n    if (x0 !== x1) {\n        _a = (y0 - y1) / (x0 - x1);\n        _b = (x0 * y1 - x1 * y0) / (x0 - x1);\n    }\n    else {\n        return Math.abs(x - x0) <= _l / 2;\n    }\n    var tmp = _a * x - y + _b;\n    var _s = tmp * tmp / (_a * _a + 1);\n    return _s <= _l / 2 * _l / 2;\n}\n\n/**\n * 三次贝塞尔曲线描边包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  x2\n * @param  {number}  y2\n * @param  {number}  x3\n * @param  {number}  y3\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$2(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l)\n        || (y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l)\n        || (x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l)\n        || (x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l)\n    ) {\n        return false;\n    }\n    var d = cubicProjectPoint(\n        x0, y0, x1, y1, x2, y2, x3, y3,\n        x, y, null\n    );\n    return d <= _l / 2;\n}\n\n/**\n * 二次贝塞尔曲线描边包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  x2\n * @param  {number}  y2\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$3(x0, y0, x1, y1, x2, y2, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l && y > y2 + _l)\n        || (y < y0 - _l && y < y1 - _l && y < y2 - _l)\n        || (x > x0 + _l && x > x1 + _l && x > x2 + _l)\n        || (x < x0 - _l && x < x1 - _l && x < x2 - _l)\n    ) {\n        return false;\n    }\n    var d = quadraticProjectPoint(\n        x0, y0, x1, y1, x2, y2,\n        x, y, null\n    );\n    return d <= _l / 2;\n}\n\nvar PI2$3 = Math.PI * 2;\n\nfunction normalizeRadian(angle) {\n    angle %= PI2$3;\n    if (angle < 0) {\n        angle += PI2$3;\n    }\n    return angle;\n}\n\nvar PI2$2 = Math.PI * 2;\n\n/**\n * 圆弧描边包含判断\n * @param  {number}  cx\n * @param  {number}  cy\n * @param  {number}  r\n * @param  {number}  startAngle\n * @param  {number}  endAngle\n * @param  {boolean}  anticlockwise\n * @param  {number} lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {Boolean}\n */\nfunction containStroke$4(\n    cx, cy, r, startAngle, endAngle, anticlockwise,\n    lineWidth, x, y\n) {\n\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n\n    x -= cx;\n    y -= cy;\n    var d = Math.sqrt(x * x + y * y);\n\n    if ((d - _l > r) || (d + _l < r)) {\n        return false;\n    }\n    if (Math.abs(startAngle - endAngle) % PI2$2 < 1e-4) {\n        // Is a circle\n        return true;\n    }\n    if (anticlockwise) {\n        var tmp = startAngle;\n        startAngle = normalizeRadian(endAngle);\n        endAngle = normalizeRadian(tmp);\n    }\n    else {\n        startAngle = normalizeRadian(startAngle);\n        endAngle = normalizeRadian(endAngle);\n    }\n    if (startAngle > endAngle) {\n        endAngle += PI2$2;\n    }\n\n    var angle = Math.atan2(y, x);\n    if (angle < 0) {\n        angle += PI2$2;\n    }\n    return (angle >= startAngle && angle <= endAngle)\n        || (angle + PI2$2 >= startAngle && angle + PI2$2 <= endAngle);\n}\n\nfunction windingLine(x0, y0, x1, y1, x, y) {\n    if ((y > y0 && y > y1) || (y < y0 && y < y1)) {\n        return 0;\n    }\n    // Ignore horizontal line\n    if (y1 === y0) {\n        return 0;\n    }\n    var dir = y1 < y0 ? 1 : -1;\n    var t = (y - y0) / (y1 - y0);\n\n    // Avoid winding error when intersection point is the connect point of two line of polygon\n    if (t === 1 || t === 0) {\n        dir = y1 < y0 ? 0.5 : -0.5;\n    }\n\n    var x_ = t * (x1 - x0) + x0;\n\n    // If (x, y) on the line, considered as \"contain\".\n    return x_ === x ? Infinity : x_ > x ? dir : 0;\n}\n\nvar CMD$1 = PathProxy.CMD;\nvar PI2$1 = Math.PI * 2;\n\nvar EPSILON$2 = 1e-4;\n\nfunction isAroundEqual(a, b) {\n    return Math.abs(a - b) < EPSILON$2;\n}\n\n// 临时数组\nvar roots = [-1, -1, -1];\nvar extrema = [-1, -1];\n\nfunction swapExtrema() {\n    var tmp = extrema[0];\n    extrema[0] = extrema[1];\n    extrema[1] = tmp;\n}\n\nfunction windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {\n    // Quick reject\n    if (\n        (y > y0 && y > y1 && y > y2 && y > y3)\n        || (y < y0 && y < y1 && y < y2 && y < y3)\n    ) {\n        return 0;\n    }\n    var nRoots = cubicRootAt(y0, y1, y2, y3, y, roots);\n    if (nRoots === 0) {\n        return 0;\n    }\n    else {\n        var w = 0;\n        var nExtrema = -1;\n        var y0_;\n        var y1_;\n        for (var i = 0; i < nRoots; i++) {\n            var t = roots[i];\n\n            // Avoid winding error when intersection point is the connect point of two line of polygon\n            var unit = (t === 0 || t === 1) ? 0.5 : 1;\n\n            var x_ = cubicAt(x0, x1, x2, x3, t);\n            if (x_ < x) { // Quick reject\n                continue;\n            }\n            if (nExtrema < 0) {\n                nExtrema = cubicExtrema(y0, y1, y2, y3, extrema);\n                if (extrema[1] < extrema[0] && nExtrema > 1) {\n                    swapExtrema();\n                }\n                y0_ = cubicAt(y0, y1, y2, y3, extrema[0]);\n                if (nExtrema > 1) {\n                    y1_ = cubicAt(y0, y1, y2, y3, extrema[1]);\n                }\n            }\n            if (nExtrema === 2) {\n                // 分成三段单调函数\n                if (t < extrema[0]) {\n                    w += y0_ < y0 ? unit : -unit;\n                }\n                else if (t < extrema[1]) {\n                    w += y1_ < y0_ ? unit : -unit;\n                }\n                else {\n                    w += y3 < y1_ ? unit : -unit;\n                }\n            }\n            else {\n                // 分成两段单调函数\n                if (t < extrema[0]) {\n                    w += y0_ < y0 ? unit : -unit;\n                }\n                else {\n                    w += y3 < y0_ ? unit : -unit;\n                }\n            }\n        }\n        return w;\n    }\n}\n\nfunction windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {\n    // Quick reject\n    if (\n        (y > y0 && y > y1 && y > y2)\n        || (y < y0 && y < y1 && y < y2)\n    ) {\n        return 0;\n    }\n    var nRoots = quadraticRootAt(y0, y1, y2, y, roots);\n    if (nRoots === 0) {\n        return 0;\n    }\n    else {\n        var t = quadraticExtremum(y0, y1, y2);\n        if (t >= 0 && t <= 1) {\n            var w = 0;\n            var y_ = quadraticAt(y0, y1, y2, t);\n            for (var i = 0; i < nRoots; i++) {\n                // Remove one endpoint.\n                var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1;\n\n                var x_ = quadraticAt(x0, x1, x2, roots[i]);\n                if (x_ < x) {   // Quick reject\n                    continue;\n                }\n                if (roots[i] < t) {\n                    w += y_ < y0 ? unit : -unit;\n                }\n                else {\n                    w += y2 < y_ ? unit : -unit;\n                }\n            }\n            return w;\n        }\n        else {\n            // Remove one endpoint.\n            var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1;\n\n            var x_ = quadraticAt(x0, x1, x2, roots[0]);\n            if (x_ < x) {   // Quick reject\n                return 0;\n            }\n            return y2 < y0 ? unit : -unit;\n        }\n    }\n}\n\n// TODO\n// Arc 旋转\nfunction windingArc(\n    cx, cy, r, startAngle, endAngle, anticlockwise, x, y\n) {\n    y -= cy;\n    if (y > r || y < -r) {\n        return 0;\n    }\n    var tmp = Math.sqrt(r * r - y * y);\n    roots[0] = -tmp;\n    roots[1] = tmp;\n\n    var diff = Math.abs(startAngle - endAngle);\n    if (diff < 1e-4) {\n        return 0;\n    }\n    if (diff % PI2$1 < 1e-4) {\n        // Is a circle\n        startAngle = 0;\n        endAngle = PI2$1;\n        var dir = anticlockwise ? 1 : -1;\n        if (x >= roots[0] + cx && x <= roots[1] + cx) {\n            return dir;\n        }\n        else {\n            return 0;\n        }\n    }\n\n    if (anticlockwise) {\n        var tmp = startAngle;\n        startAngle = normalizeRadian(endAngle);\n        endAngle = normalizeRadian(tmp);\n    }\n    else {\n        startAngle = normalizeRadian(startAngle);\n        endAngle = normalizeRadian(endAngle);\n    }\n    if (startAngle > endAngle) {\n        endAngle += PI2$1;\n    }\n\n    var w = 0;\n    for (var i = 0; i < 2; i++) {\n        var x_ = roots[i];\n        if (x_ + cx > x) {\n            var angle = Math.atan2(y, x_);\n            var dir = anticlockwise ? 1 : -1;\n            if (angle < 0) {\n                angle = PI2$1 + angle;\n            }\n            if (\n                (angle >= startAngle && angle <= endAngle)\n                || (angle + PI2$1 >= startAngle && angle + PI2$1 <= endAngle)\n            ) {\n                if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {\n                    dir = -dir;\n                }\n                w += dir;\n            }\n        }\n    }\n    return w;\n}\n\nfunction containPath(data, lineWidth, isStroke, x, y) {\n    var w = 0;\n    var xi = 0;\n    var yi = 0;\n    var x0 = 0;\n    var y0 = 0;\n\n    for (var i = 0; i < data.length;) {\n        var cmd = data[i++];\n        // Begin a new subpath\n        if (cmd === CMD$1.M && i > 1) {\n            // Close previous subpath\n            if (!isStroke) {\n                w += windingLine(xi, yi, x0, y0, x, y);\n            }\n            // 如果被任何一个 subpath 包含\n            // if (w !== 0) {\n            //     return true;\n            // }\n        }\n\n        if (i === 1) {\n            // 如果第一个命令是 L, C, Q\n            // 则 previous point 同绘制命令的第一个 point\n            //\n            // 第一个命令为 Arc 的情况下会在后面特殊处理\n            xi = data[i];\n            yi = data[i + 1];\n\n            x0 = xi;\n            y0 = yi;\n        }\n\n        switch (cmd) {\n            case CMD$1.M:\n                // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点\n                // 在 closePath 的时候使用\n                x0 = data[i++];\n                y0 = data[i++];\n                xi = x0;\n                yi = y0;\n                break;\n            case CMD$1.L:\n                if (isStroke) {\n                    if (containStroke$1(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {\n                        return true;\n                    }\n                }\n                else {\n                    // NOTE 在第一个命令为 L, C, Q 的时候会计算出 NaN\n                    w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.C:\n                if (isStroke) {\n                    if (containStroke$2(xi, yi,\n                        data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingCubic(\n                        xi, yi,\n                        data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        x, y\n                    ) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.Q:\n                if (isStroke) {\n                    if (containStroke$3(xi, yi,\n                        data[i++], data[i++], data[i], data[i + 1],\n                        lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingQuadratic(\n                        xi, yi,\n                        data[i++], data[i++], data[i], data[i + 1],\n                        x, y\n                    ) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.A:\n                // TODO Arc 判断的开销比较大\n                var cx = data[i++];\n                var cy = data[i++];\n                var rx = data[i++];\n                var ry = data[i++];\n                var theta = data[i++];\n                var dTheta = data[i++];\n                // TODO Arc 旋转\n                i += 1;\n                var anticlockwise = 1 - data[i++];\n                var x1 = Math.cos(theta) * rx + cx;\n                var y1 = Math.sin(theta) * ry + cy;\n                // 不是直接使用 arc 命令\n                if (i > 1) {\n                    w += windingLine(xi, yi, x1, y1, x, y);\n                }\n                else {\n                    // 第一个命令起点还未定义\n                    x0 = x1;\n                    y0 = y1;\n                }\n                // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放\n                var _x = (x - cx) * ry / rx + cx;\n                if (isStroke) {\n                    if (containStroke$4(\n                        cx, cy, ry, theta, theta + dTheta, anticlockwise,\n                        lineWidth, _x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingArc(\n                        cx, cy, ry, theta, theta + dTheta, anticlockwise,\n                        _x, y\n                    );\n                }\n                xi = Math.cos(theta + dTheta) * rx + cx;\n                yi = Math.sin(theta + dTheta) * ry + cy;\n                break;\n            case CMD$1.R:\n                x0 = xi = data[i++];\n                y0 = yi = data[i++];\n                var width = data[i++];\n                var height = data[i++];\n                var x1 = x0 + width;\n                var y1 = y0 + height;\n                if (isStroke) {\n                    if (containStroke$1(x0, y0, x1, y0, lineWidth, x, y)\n                        || containStroke$1(x1, y0, x1, y1, lineWidth, x, y)\n                        || containStroke$1(x1, y1, x0, y1, lineWidth, x, y)\n                        || containStroke$1(x0, y1, x0, y0, lineWidth, x, y)\n                    ) {\n                        return true;\n                    }\n                }\n                else {\n                    // FIXME Clockwise ?\n                    w += windingLine(x1, y0, x1, y1, x, y);\n                    w += windingLine(x0, y1, x0, y0, x, y);\n                }\n                break;\n            case CMD$1.Z:\n                if (isStroke) {\n                    if (containStroke$1(\n                        xi, yi, x0, y0, lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    // Close a subpath\n                    w += windingLine(xi, yi, x0, y0, x, y);\n                    // 如果被任何一个 subpath 包含\n                    // FIXME subpaths may overlap\n                    // if (w !== 0) {\n                    //     return true;\n                    // }\n                }\n                xi = x0;\n                yi = y0;\n                break;\n        }\n    }\n    if (!isStroke && !isAroundEqual(yi, y0)) {\n        w += windingLine(xi, yi, x0, y0, x, y) || 0;\n    }\n    return w !== 0;\n}\n\nfunction contain(pathData, x, y) {\n    return containPath(pathData, 0, false, x, y);\n}\n\nfunction containStroke(pathData, lineWidth, x, y) {\n    return containPath(pathData, lineWidth, true, x, y);\n}\n\nvar getCanvasPattern = Pattern.prototype.getCanvasPattern;\n\nvar abs = Math.abs;\n\nvar pathProxyForDraw = new PathProxy(true);\n/**\n * @alias module:zrender/graphic/Path\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nfunction Path(opts) {\n    Displayable.call(this, opts);\n\n    /**\n     * @type {module:zrender/core/PathProxy}\n     * @readOnly\n     */\n    this.path = null;\n}\n\nPath.prototype = {\n\n    constructor: Path,\n\n    type: 'path',\n\n    __dirtyPath: true,\n\n    strokeContainThreshold: 5,\n\n    /**\n     * See `module:zrender/src/graphic/helper/subPixelOptimize`.\n     * @type {boolean}\n     */\n    subPixelOptimize: false,\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n        var path = this.path || pathProxyForDraw;\n        var hasStroke = style.hasStroke();\n        var hasFill = style.hasFill();\n        var fill = style.fill;\n        var stroke = style.stroke;\n        var hasFillGradient = hasFill && !!(fill.colorStops);\n        var hasStrokeGradient = hasStroke && !!(stroke.colorStops);\n        var hasFillPattern = hasFill && !!(fill.image);\n        var hasStrokePattern = hasStroke && !!(stroke.image);\n\n        style.bind(ctx, this, prevEl);\n        this.setTransform(ctx);\n\n        if (this.__dirty) {\n            var rect;\n            // Update gradient because bounding rect may changed\n            if (hasFillGradient) {\n                rect = rect || this.getBoundingRect();\n                this._fillGradient = style.getGradient(ctx, fill, rect);\n            }\n            if (hasStrokeGradient) {\n                rect = rect || this.getBoundingRect();\n                this._strokeGradient = style.getGradient(ctx, stroke, rect);\n            }\n        }\n        // Use the gradient or pattern\n        if (hasFillGradient) {\n            // PENDING If may have affect the state\n            ctx.fillStyle = this._fillGradient;\n        }\n        else if (hasFillPattern) {\n            ctx.fillStyle = getCanvasPattern.call(fill, ctx);\n        }\n        if (hasStrokeGradient) {\n            ctx.strokeStyle = this._strokeGradient;\n        }\n        else if (hasStrokePattern) {\n            ctx.strokeStyle = getCanvasPattern.call(stroke, ctx);\n        }\n\n        var lineDash = style.lineDash;\n        var lineDashOffset = style.lineDashOffset;\n\n        var ctxLineDash = !!ctx.setLineDash;\n\n        // Update path sx, sy\n        var scale = this.getGlobalScale();\n        path.setScale(scale[0], scale[1]);\n\n        // Proxy context\n        // Rebuild path in following 2 cases\n        // 1. Path is dirty\n        // 2. Path needs javascript implemented lineDash stroking.\n        //    In this case, lineDash information will not be saved in PathProxy\n        if (this.__dirtyPath\n            || (lineDash && !ctxLineDash && hasStroke)\n        ) {\n            path.beginPath(ctx);\n\n            // Setting line dash before build path\n            if (lineDash && !ctxLineDash) {\n                path.setLineDash(lineDash);\n                path.setLineDashOffset(lineDashOffset);\n            }\n\n            this.buildPath(path, this.shape, false);\n\n            // Clear path dirty flag\n            if (this.path) {\n                this.__dirtyPath = false;\n            }\n        }\n        else {\n            // Replay path building\n            ctx.beginPath();\n            this.path.rebuildPath(ctx);\n        }\n\n        if (hasFill) {\n            if (style.fillOpacity != null) {\n                var originalGlobalAlpha = ctx.globalAlpha;\n                ctx.globalAlpha = style.fillOpacity * style.opacity;\n                path.fill(ctx);\n                ctx.globalAlpha = originalGlobalAlpha;\n            }\n            else {\n                path.fill(ctx);\n            }\n        }\n\n        if (lineDash && ctxLineDash) {\n            ctx.setLineDash(lineDash);\n            ctx.lineDashOffset = lineDashOffset;\n        }\n\n        if (hasStroke) {\n            if (style.strokeOpacity != null) {\n                var originalGlobalAlpha = ctx.globalAlpha;\n                ctx.globalAlpha = style.strokeOpacity * style.opacity;\n                path.stroke(ctx);\n                ctx.globalAlpha = originalGlobalAlpha;\n            }\n            else {\n                path.stroke(ctx);\n            }\n        }\n\n        if (lineDash && ctxLineDash) {\n            // PENDING\n            // Remove lineDash\n            ctx.setLineDash([]);\n        }\n\n        // Draw rect text\n        if (style.text != null) {\n            // Only restore transform when needs draw text.\n            this.restoreTransform(ctx);\n            this.drawRectText(ctx, this.getBoundingRect());\n        }\n    },\n\n    // When bundling path, some shape may decide if use moveTo to begin a new subpath or closePath\n    // Like in circle\n    buildPath: function (ctx, shapeCfg, inBundle) {},\n\n    createPathProxy: function () {\n        this.path = new PathProxy();\n    },\n\n    getBoundingRect: function () {\n        var rect = this._rect;\n        var style = this.style;\n        var needsUpdateRect = !rect;\n        if (needsUpdateRect) {\n            var path = this.path;\n            if (!path) {\n                // Create path on demand.\n                path = this.path = new PathProxy();\n            }\n            if (this.__dirtyPath) {\n                path.beginPath();\n                this.buildPath(path, this.shape, false);\n            }\n            rect = path.getBoundingRect();\n        }\n        this._rect = rect;\n\n        if (style.hasStroke()) {\n            // Needs update rect with stroke lineWidth when\n            // 1. Element changes scale or lineWidth\n            // 2. Shape is changed\n            var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone());\n            if (this.__dirty || needsUpdateRect) {\n                rectWithStroke.copy(rect);\n                // FIXME Must after updateTransform\n                var w = style.lineWidth;\n                // PENDING, Min line width is needed when line is horizontal or vertical\n                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;\n\n                // Only add extra hover lineWidth when there are no fill\n                if (!style.hasFill()) {\n                    w = Math.max(w, this.strokeContainThreshold || 4);\n                }\n                // Consider line width\n                // Line scale can't be 0;\n                if (lineScale > 1e-10) {\n                    rectWithStroke.width += w / lineScale;\n                    rectWithStroke.height += w / lineScale;\n                    rectWithStroke.x -= w / lineScale / 2;\n                    rectWithStroke.y -= w / lineScale / 2;\n                }\n            }\n\n            // Return rect with stroke\n            return rectWithStroke;\n        }\n\n        return rect;\n    },\n\n    contain: function (x, y) {\n        var localPos = this.transformCoordToLocal(x, y);\n        var rect = this.getBoundingRect();\n        var style = this.style;\n        x = localPos[0];\n        y = localPos[1];\n\n        if (rect.contain(x, y)) {\n            var pathData = this.path.data;\n            if (style.hasStroke()) {\n                var lineWidth = style.lineWidth;\n                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;\n                // Line scale can't be 0;\n                if (lineScale > 1e-10) {\n                    // Only add extra hover lineWidth when there are no fill\n                    if (!style.hasFill()) {\n                        lineWidth = Math.max(lineWidth, this.strokeContainThreshold);\n                    }\n                    if (containStroke(\n                        pathData, lineWidth / lineScale, x, y\n                    )) {\n                        return true;\n                    }\n                }\n            }\n            if (style.hasFill()) {\n                return contain(pathData, x, y);\n            }\n        }\n        return false;\n    },\n\n    /**\n     * @param  {boolean} dirtyPath\n     */\n    dirty: function (dirtyPath) {\n        if (dirtyPath == null) {\n            dirtyPath = true;\n        }\n        // Only mark dirty, not mark clean\n        if (dirtyPath) {\n            this.__dirtyPath = dirtyPath;\n            this._rect = null;\n        }\n\n        this.__dirty = this.__dirtyText = true;\n\n        this.__zr && this.__zr.refresh();\n\n        // Used as a clipping path\n        if (this.__clipTarget) {\n            this.__clipTarget.dirty();\n        }\n    },\n\n    /**\n     * Alias for animate('shape')\n     * @param {boolean} loop\n     */\n    animateShape: function (loop) {\n        return this.animate('shape', loop);\n    },\n\n    // Overwrite attrKV\n    attrKV: function (key, value) {\n        // FIXME\n        if (key === 'shape') {\n            this.setShape(value);\n            this.__dirtyPath = true;\n            this._rect = null;\n        }\n        else {\n            Displayable.prototype.attrKV.call(this, key, value);\n        }\n    },\n\n    /**\n     * @param {Object|string} key\n     * @param {*} value\n     */\n    setShape: function (key, value) {\n        var shape = this.shape;\n        // Path from string may not have shape\n        if (shape) {\n            if (isObject$1(key)) {\n                for (var name in key) {\n                    if (key.hasOwnProperty(name)) {\n                        shape[name] = key[name];\n                    }\n                }\n            }\n            else {\n                shape[key] = value;\n            }\n            this.dirty(true);\n        }\n        return this;\n    },\n\n    getLineScale: function () {\n        var m = this.transform;\n        // Get the line scale.\n        // Determinant of `m` means how much the area is enlarged by the\n        // transformation. So its square root can be used as a scale factor\n        // for width.\n        return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10\n            ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1]))\n            : 1;\n    }\n};\n\n/**\n * 扩展一个 Path element, 比如星形，圆等。\n * Extend a path element\n * @param {Object} props\n * @param {string} props.type Path type\n * @param {Function} props.init Initialize\n * @param {Function} props.buildPath Overwrite buildPath method\n * @param {Object} [props.style] Extended default style config\n * @param {Object} [props.shape] Extended default shape config\n */\nPath.extend = function (defaults$$1) {\n    var Sub = function (opts) {\n        Path.call(this, opts);\n\n        if (defaults$$1.style) {\n            // Extend default style\n            this.style.extendFrom(defaults$$1.style, false);\n        }\n\n        // Extend default shape\n        var defaultShape = defaults$$1.shape;\n        if (defaultShape) {\n            this.shape = this.shape || {};\n            var thisShape = this.shape;\n            for (var name in defaultShape) {\n                if (\n                    !thisShape.hasOwnProperty(name)\n                    && defaultShape.hasOwnProperty(name)\n                ) {\n                    thisShape[name] = defaultShape[name];\n                }\n            }\n        }\n\n        defaults$$1.init && defaults$$1.init.call(this, opts);\n    };\n\n    inherits(Sub, Path);\n\n    // FIXME 不能 extend position, rotation 等引用对象\n    for (var name in defaults$$1) {\n        // Extending prototype values and methods\n        if (name !== 'style' && name !== 'shape') {\n            Sub.prototype[name] = defaults$$1[name];\n        }\n    }\n\n    return Sub;\n};\n\ninherits(Path, Displayable);\n\nvar CMD$2 = PathProxy.CMD;\n\nvar points = [[], [], []];\nvar mathSqrt$3 = Math.sqrt;\nvar mathAtan2 = Math.atan2;\n\nvar transformPath = function (path, m) {\n    var data = path.data;\n    var cmd;\n    var nPoint;\n    var i;\n    var j;\n    var k;\n    var p;\n\n    var M = CMD$2.M;\n    var C = CMD$2.C;\n    var L = CMD$2.L;\n    var R = CMD$2.R;\n    var A = CMD$2.A;\n    var Q = CMD$2.Q;\n\n    for (i = 0, j = 0; i < data.length;) {\n        cmd = data[i++];\n        j = i;\n        nPoint = 0;\n\n        switch (cmd) {\n            case M:\n                nPoint = 1;\n                break;\n            case L:\n                nPoint = 1;\n                break;\n            case C:\n                nPoint = 3;\n                break;\n            case Q:\n                nPoint = 2;\n                break;\n            case A:\n                var x = m[4];\n                var y = m[5];\n                var sx = mathSqrt$3(m[0] * m[0] + m[1] * m[1]);\n                var sy = mathSqrt$3(m[2] * m[2] + m[3] * m[3]);\n                var angle = mathAtan2(-m[1] / sy, m[0] / sx);\n                // cx\n                data[i] *= sx;\n                data[i++] += x;\n                // cy\n                data[i] *= sy;\n                data[i++] += y;\n                // Scale rx and ry\n                // FIXME Assume psi is 0 here\n                data[i++] *= sx;\n                data[i++] *= sy;\n\n                // Start angle\n                data[i++] += angle;\n                // end angle\n                data[i++] += angle;\n                // FIXME psi\n                i += 2;\n                j = i;\n                break;\n            case R:\n                // x0, y0\n                p[0] = data[i++];\n                p[1] = data[i++];\n                applyTransform(p, p, m);\n                data[j++] = p[0];\n                data[j++] = p[1];\n                // x1, y1\n                p[0] += data[i++];\n                p[1] += data[i++];\n                applyTransform(p, p, m);\n                data[j++] = p[0];\n                data[j++] = p[1];\n        }\n\n        for (k = 0; k < nPoint; k++) {\n            var p = points[k];\n            p[0] = data[i++];\n            p[1] = data[i++];\n\n            applyTransform(p, p, m);\n            // Write back\n            data[j++] = p[0];\n            data[j++] = p[1];\n        }\n    }\n};\n\n// command chars\n// var cc = [\n//     'm', 'M', 'l', 'L', 'v', 'V', 'h', 'H', 'z', 'Z',\n//     'c', 'C', 'q', 'Q', 't', 'T', 's', 'S', 'a', 'A'\n// ];\n\nvar mathSqrt = Math.sqrt;\nvar mathSin = Math.sin;\nvar mathCos = Math.cos;\nvar PI = Math.PI;\n\nvar vMag = function (v) {\n    return Math.sqrt(v[0] * v[0] + v[1] * v[1]);\n};\nvar vRatio = function (u, v) {\n    return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));\n};\nvar vAngle = function (u, v) {\n    return (u[0] * v[1] < u[1] * v[0] ? -1 : 1)\n            * Math.acos(vRatio(u, v));\n};\n\nfunction processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) {\n    var psi = psiDeg * (PI / 180.0);\n    var xp = mathCos(psi) * (x1 - x2) / 2.0\n                + mathSin(psi) * (y1 - y2) / 2.0;\n    var yp = -1 * mathSin(psi) * (x1 - x2) / 2.0\n                + mathCos(psi) * (y1 - y2) / 2.0;\n\n    var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);\n\n    if (lambda > 1) {\n        rx *= mathSqrt(lambda);\n        ry *= mathSqrt(lambda);\n    }\n\n    var f = (fa === fs ? -1 : 1)\n        * mathSqrt((((rx * rx) * (ry * ry))\n                - ((rx * rx) * (yp * yp))\n                - ((ry * ry) * (xp * xp))) / ((rx * rx) * (yp * yp)\n                + (ry * ry) * (xp * xp))\n            ) || 0;\n\n    var cxp = f * rx * yp / ry;\n    var cyp = f * -ry * xp / rx;\n\n    var cx = (x1 + x2) / 2.0\n                + mathCos(psi) * cxp\n                - mathSin(psi) * cyp;\n    var cy = (y1 + y2) / 2.0\n            + mathSin(psi) * cxp\n            + mathCos(psi) * cyp;\n\n    var theta = vAngle([ 1, 0 ], [ (xp - cxp) / rx, (yp - cyp) / ry ]);\n    var u = [ (xp - cxp) / rx, (yp - cyp) / ry ];\n    var v = [ (-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry ];\n    var dTheta = vAngle(u, v);\n\n    if (vRatio(u, v) <= -1) {\n        dTheta = PI;\n    }\n    if (vRatio(u, v) >= 1) {\n        dTheta = 0;\n    }\n    if (fs === 0 && dTheta > 0) {\n        dTheta = dTheta - 2 * PI;\n    }\n    if (fs === 1 && dTheta < 0) {\n        dTheta = dTheta + 2 * PI;\n    }\n\n    path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs);\n}\n\n\nvar commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig;\n// Consider case:\n// (1) delimiter can be comma or space, where continuous commas\n// or spaces should be seen as one comma.\n// (2) value can be like:\n// '2e-4', 'l.5.9' (ignore 0), 'M-10-10', 'l-2.43e-1,34.9983',\n// 'l-.5E1,54', '121-23-44-11' (no delimiter)\nvar numberReg = /-?([0-9]*\\.)?[0-9]+([eE]-?[0-9]+)?/g;\n// var valueSplitReg = /[\\s,]+/;\n\nfunction createPathProxyFromString(data) {\n    if (!data) {\n        return new PathProxy();\n    }\n\n    // var data = data.replace(/-/g, ' -')\n    //     .replace(/  /g, ' ')\n    //     .replace(/ /g, ',')\n    //     .replace(/,,/g, ',');\n\n    // var n;\n    // create pipes so that we can split the data\n    // for (n = 0; n < cc.length; n++) {\n    //     cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]);\n    // }\n\n    // data = data.replace(/-/g, ',-');\n\n    // create array\n    // var arr = cs.split('|');\n    // init context point\n    var cpx = 0;\n    var cpy = 0;\n    var subpathX = cpx;\n    var subpathY = cpy;\n    var prevCmd;\n\n    var path = new PathProxy();\n    var CMD = PathProxy.CMD;\n\n    // commandReg.lastIndex = 0;\n    // var cmdResult;\n    // while ((cmdResult = commandReg.exec(data)) != null) {\n    //     var cmdStr = cmdResult[1];\n    //     var cmdContent = cmdResult[2];\n\n    var cmdList = data.match(commandReg);\n    for (var l = 0; l < cmdList.length; l++) {\n        var cmdText = cmdList[l];\n        var cmdStr = cmdText.charAt(0);\n\n        var cmd;\n\n        // String#split is faster a little bit than String#replace or RegExp#exec.\n        // var p = cmdContent.split(valueSplitReg);\n        // var pLen = 0;\n        // for (var i = 0; i < p.length; i++) {\n        //     // '' and other invalid str => NaN\n        //     var val = parseFloat(p[i]);\n        //     !isNaN(val) && (p[pLen++] = val);\n        // }\n\n        var p = cmdText.match(numberReg) || [];\n        var pLen = p.length;\n        for (var i = 0; i < pLen; i++) {\n            p[i] = parseFloat(p[i]);\n        }\n\n        var off = 0;\n        while (off < pLen) {\n            var ctlPtx;\n            var ctlPty;\n\n            var rx;\n            var ry;\n            var psi;\n            var fa;\n            var fs;\n\n            var x1 = cpx;\n            var y1 = cpy;\n\n            // convert l, H, h, V, and v to L\n            switch (cmdStr) {\n                case 'l':\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'L':\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'm':\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.M;\n                    path.addData(cmd, cpx, cpy);\n                    subpathX = cpx;\n                    subpathY = cpy;\n                    cmdStr = 'l';\n                    break;\n                case 'M':\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.M;\n                    path.addData(cmd, cpx, cpy);\n                    subpathX = cpx;\n                    subpathY = cpy;\n                    cmdStr = 'L';\n                    break;\n                case 'h':\n                    cpx += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'H':\n                    cpx = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'v':\n                    cpy += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'V':\n                    cpy = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'C':\n                    cmd = CMD.C;\n                    path.addData(\n                        cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]\n                    );\n                    cpx = p[off - 2];\n                    cpy = p[off - 1];\n                    break;\n                case 'c':\n                    cmd = CMD.C;\n                    path.addData(\n                        cmd,\n                        p[off++] + cpx, p[off++] + cpy,\n                        p[off++] + cpx, p[off++] + cpy,\n                        p[off++] + cpx, p[off++] + cpy\n                    );\n                    cpx += p[off - 2];\n                    cpy += p[off - 1];\n                    break;\n                case 'S':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.C) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cmd = CMD.C;\n                    x1 = p[off++];\n                    y1 = p[off++];\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);\n                    break;\n                case 's':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.C) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cmd = CMD.C;\n                    x1 = cpx + p[off++];\n                    y1 = cpy + p[off++];\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);\n                    break;\n                case 'Q':\n                    x1 = p[off++];\n                    y1 = p[off++];\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, x1, y1, cpx, cpy);\n                    break;\n                case 'q':\n                    x1 = p[off++] + cpx;\n                    y1 = p[off++] + cpy;\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, x1, y1, cpx, cpy);\n                    break;\n                case 'T':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.Q) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);\n                    break;\n                case 't':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.Q) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);\n                    break;\n                case 'A':\n                    rx = p[off++];\n                    ry = p[off++];\n                    psi = p[off++];\n                    fa = p[off++];\n                    fs = p[off++];\n\n                    x1 = cpx, y1 = cpy;\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.A;\n                    processArc(\n                        x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path\n                    );\n                    break;\n                case 'a':\n                    rx = p[off++];\n                    ry = p[off++];\n                    psi = p[off++];\n                    fa = p[off++];\n                    fs = p[off++];\n\n                    x1 = cpx, y1 = cpy;\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.A;\n                    processArc(\n                        x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path\n                    );\n                    break;\n            }\n        }\n\n        if (cmdStr === 'z' || cmdStr === 'Z') {\n            cmd = CMD.Z;\n            path.addData(cmd);\n            // z may be in the middle of the path.\n            cpx = subpathX;\n            cpy = subpathY;\n        }\n\n        prevCmd = cmd;\n    }\n\n    path.toStatic();\n\n    return path;\n}\n\n// TODO Optimize double memory cost problem\nfunction createPathOptions(str, opts) {\n    var pathProxy = createPathProxyFromString(str);\n    opts = opts || {};\n    opts.buildPath = function (path) {\n        if (path.setData) {\n            path.setData(pathProxy.data);\n            // Svg and vml renderer don't have context\n            var ctx = path.getContext();\n            if (ctx) {\n                path.rebuildPath(ctx);\n            }\n        }\n        else {\n            var ctx = path;\n            pathProxy.rebuildPath(ctx);\n        }\n    };\n\n    opts.applyTransform = function (m) {\n        transformPath(pathProxy, m);\n        this.dirty(true);\n    };\n\n    return opts;\n}\n\n/**\n * Create a Path object from path string data\n * http://www.w3.org/TR/SVG/paths.html#PathData\n * @param  {Object} opts Other options\n */\nfunction createFromString(str, opts) {\n    return new Path(createPathOptions(str, opts));\n}\n\n/**\n * Create a Path class from path string data\n * @param  {string} str\n * @param  {Object} opts Other options\n */\nfunction extendFromString(str, opts) {\n    return Path.extend(createPathOptions(str, opts));\n}\n\n/**\n * Merge multiple paths\n */\n// TODO Apply transform\n// TODO stroke dash\n// TODO Optimize double memory cost problem\nfunction mergePath$1(pathEls, opts) {\n    var pathList = [];\n    var len = pathEls.length;\n    for (var i = 0; i < len; i++) {\n        var pathEl = pathEls[i];\n        if (!pathEl.path) {\n            pathEl.createPathProxy();\n        }\n        if (pathEl.__dirtyPath) {\n            pathEl.buildPath(pathEl.path, pathEl.shape, true);\n        }\n        pathList.push(pathEl.path);\n    }\n\n    var pathBundle = new Path(opts);\n    // Need path proxy.\n    pathBundle.createPathProxy();\n    pathBundle.buildPath = function (path) {\n        path.appendPath(pathList);\n        // Svg and vml renderer don't have context\n        var ctx = path.getContext();\n        if (ctx) {\n            path.rebuildPath(ctx);\n        }\n    };\n\n    return pathBundle;\n}\n\n/**\n * @alias zrender/graphic/Text\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nvar Text = function (opts) { // jshint ignore:line\n    Displayable.call(this, opts);\n};\n\nText.prototype = {\n\n    constructor: Text,\n\n    type: 'text',\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        // Use props with prefix 'text'.\n        style.fill = style.stroke = style.shadowBlur = style.shadowColor =\n            style.shadowOffsetX = style.shadowOffsetY = null;\n\n        var text = style.text;\n        // Convert to string\n        text != null && (text += '');\n\n        // Do not apply style.bind in Text node. Because the real bind job\n        // is in textHelper.renderText, and performance of text render should\n        // be considered.\n        // style.bind(ctx, this, prevEl);\n\n        if (!needDrawText(text, style)) {\n            // The current el.style is not applied\n            // and should not be used as cache.\n            ctx.__attrCachedBy = ContextCachedBy.NONE;\n            return;\n        }\n\n        this.setTransform(ctx);\n\n        renderText(this, ctx, text, style, null, prevEl);\n\n        this.restoreTransform(ctx);\n    },\n\n    getBoundingRect: function () {\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        if (!this._rect) {\n            var text = style.text;\n            text != null ? (text += '') : (text = '');\n\n            var rect = getBoundingRect(\n                style.text + '',\n                style.font,\n                style.textAlign,\n                style.textVerticalAlign,\n                style.textPadding,\n                style.textLineHeight,\n                style.rich\n            );\n\n            rect.x += style.x || 0;\n            rect.y += style.y || 0;\n\n            if (getStroke(style.textStroke, style.textStrokeWidth)) {\n                var w = style.textStrokeWidth;\n                rect.x -= w / 2;\n                rect.y -= w / 2;\n                rect.width += w;\n                rect.height += w;\n            }\n\n            this._rect = rect;\n        }\n\n        return this._rect;\n    }\n};\n\ninherits(Text, Displayable);\n\n/**\n * 圆形\n * @module zrender/shape/Circle\n */\n\nvar Circle = Path.extend({\n\n    type: 'circle',\n\n    shape: {\n        cx: 0,\n        cy: 0,\n        r: 0\n    },\n\n\n    buildPath: function (ctx, shape, inBundle) {\n        // Better stroking in ShapeBundle\n        // Always do it may have performence issue ( fill may be 2x more cost)\n        if (inBundle) {\n            ctx.moveTo(shape.cx + shape.r, shape.cy);\n        }\n        // else {\n        //     if (ctx.allocate && !ctx.data.length) {\n        //         ctx.allocate(ctx.CMD_MEM_SIZE.A);\n        //     }\n        // }\n        // Better stroking in ShapeBundle\n        // ctx.moveTo(shape.cx + shape.r, shape.cy);\n        ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true);\n    }\n});\n\n// Fix weird bug in some version of IE11 (like 11.0.9600.178**),\n// where exception \"unexpected call to method or property access\"\n// might be thrown when calling ctx.fill or ctx.stroke after a path\n// whose area size is zero is drawn and ctx.clip() is called and\n// shadowBlur is set. See #4572, #3112, #5777.\n// (e.g.,\n//  ctx.moveTo(10, 10);\n//  ctx.lineTo(20, 10);\n//  ctx.closePath();\n//  ctx.clip();\n//  ctx.shadowBlur = 10;\n//  ...\n//  ctx.fill();\n// )\n\nvar shadowTemp = [\n    ['shadowBlur', 0],\n    ['shadowColor', '#000'],\n    ['shadowOffsetX', 0],\n    ['shadowOffsetY', 0]\n];\n\nvar fixClipWithShadow = function (orignalBrush) {\n\n    // version string can be: '11.0'\n    return (env$1.browser.ie && env$1.browser.version >= 11)\n\n        ? function () {\n            var clipPaths = this.__clipPaths;\n            var style = this.style;\n            var modified;\n\n            if (clipPaths) {\n                for (var i = 0; i < clipPaths.length; i++) {\n                    var clipPath = clipPaths[i];\n                    var shape = clipPath && clipPath.shape;\n                    var type = clipPath && clipPath.type;\n\n                    if (shape && (\n                        (type === 'sector' && shape.startAngle === shape.endAngle)\n                        || (type === 'rect' && (!shape.width || !shape.height))\n                    )) {\n                        for (var j = 0; j < shadowTemp.length; j++) {\n                            // It is save to put shadowTemp static, because shadowTemp\n                            // will be all modified each item brush called.\n                            shadowTemp[j][2] = style[shadowTemp[j][0]];\n                            style[shadowTemp[j][0]] = shadowTemp[j][1];\n                        }\n                        modified = true;\n                        break;\n                    }\n                }\n            }\n\n            orignalBrush.apply(this, arguments);\n\n            if (modified) {\n                for (var j = 0; j < shadowTemp.length; j++) {\n                    style[shadowTemp[j][0]] = shadowTemp[j][2];\n                }\n            }\n        }\n\n        : orignalBrush;\n};\n\n/**\n * 扇形\n * @module zrender/graphic/shape/Sector\n */\n\nvar Sector = Path.extend({\n\n    type: 'sector',\n\n    shape: {\n\n        cx: 0,\n\n        cy: 0,\n\n        r0: 0,\n\n        r: 0,\n\n        startAngle: 0,\n\n        endAngle: Math.PI * 2,\n\n        clockwise: true\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n\n        var x = shape.cx;\n        var y = shape.cy;\n        var r0 = Math.max(shape.r0 || 0, 0);\n        var r = Math.max(shape.r, 0);\n        var startAngle = shape.startAngle;\n        var endAngle = shape.endAngle;\n        var clockwise = shape.clockwise;\n\n        var unitX = Math.cos(startAngle);\n        var unitY = Math.sin(startAngle);\n\n        ctx.moveTo(unitX * r0 + x, unitY * r0 + y);\n\n        ctx.lineTo(unitX * r + x, unitY * r + y);\n\n        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);\n\n        ctx.lineTo(\n            Math.cos(endAngle) * r0 + x,\n            Math.sin(endAngle) * r0 + y\n        );\n\n        if (r0 !== 0) {\n            ctx.arc(x, y, r0, endAngle, startAngle, clockwise);\n        }\n\n        ctx.closePath();\n    }\n});\n\n/**\n * 圆环\n * @module zrender/graphic/shape/Ring\n */\n\nvar Ring = Path.extend({\n\n    type: 'ring',\n\n    shape: {\n        cx: 0,\n        cy: 0,\n        r: 0,\n        r0: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var x = shape.cx;\n        var y = shape.cy;\n        var PI2 = Math.PI * 2;\n        ctx.moveTo(x + shape.r, y);\n        ctx.arc(x, y, shape.r, 0, PI2, false);\n        ctx.moveTo(x + shape.r0, y);\n        ctx.arc(x, y, shape.r0, 0, PI2, true);\n    }\n});\n\n/**\n * Catmull-Rom spline 插值折线\n * @module zrender/shape/util/smoothSpline\n * @author pissang (https://www.github.com/pissang)\n *         Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         errorrik (errorrik@gmail.com)\n */\n\n/**\n * @inner\n */\nfunction interpolate(p0, p1, p2, p3, t, t2, t3) {\n    var v0 = (p2 - p0) * 0.5;\n    var v1 = (p3 - p1) * 0.5;\n    return (2 * (p1 - p2) + v0 + v1) * t3\n            + (-3 * (p1 - p2) - 2 * v0 - v1) * t2\n            + v0 * t + p1;\n}\n\n/**\n * @alias module:zrender/shape/util/smoothSpline\n * @param {Array} points 线段顶点数组\n * @param {boolean} isLoop\n * @return {Array}\n */\nvar smoothSpline = function (points, isLoop) {\n    var len$$1 = points.length;\n    var ret = [];\n\n    var distance$$1 = 0;\n    for (var i = 1; i < len$$1; i++) {\n        distance$$1 += distance(points[i - 1], points[i]);\n    }\n\n    var segs = distance$$1 / 2;\n    segs = segs < len$$1 ? len$$1 : segs;\n    for (var i = 0; i < segs; i++) {\n        var pos = i / (segs - 1) * (isLoop ? len$$1 : len$$1 - 1);\n        var idx = Math.floor(pos);\n\n        var w = pos - idx;\n\n        var p0;\n        var p1 = points[idx % len$$1];\n        var p2;\n        var p3;\n        if (!isLoop) {\n            p0 = points[idx === 0 ? idx : idx - 1];\n            p2 = points[idx > len$$1 - 2 ? len$$1 - 1 : idx + 1];\n            p3 = points[idx > len$$1 - 3 ? len$$1 - 1 : idx + 2];\n        }\n        else {\n            p0 = points[(idx - 1 + len$$1) % len$$1];\n            p2 = points[(idx + 1) % len$$1];\n            p3 = points[(idx + 2) % len$$1];\n        }\n\n        var w2 = w * w;\n        var w3 = w * w2;\n\n        ret.push([\n            interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3),\n            interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3)\n        ]);\n    }\n    return ret;\n};\n\n/**\n * 贝塞尔平滑曲线\n * @module zrender/shape/util/smoothBezier\n * @author pissang (https://www.github.com/pissang)\n *         Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         errorrik (errorrik@gmail.com)\n */\n\n/**\n * 贝塞尔平滑曲线\n * @alias module:zrender/shape/util/smoothBezier\n * @param {Array} points 线段顶点数组\n * @param {number} smooth 平滑等级, 0-1\n * @param {boolean} isLoop\n * @param {Array} constraint 将计算出来的控制点约束在一个包围盒内\n *                           比如 [[0, 0], [100, 100]], 这个包围盒会与\n *                           整个折线的包围盒做一个并集用来约束控制点。\n * @param {Array} 计算出来的控制点数组\n */\nvar smoothBezier = function (points, smooth, isLoop, constraint) {\n    var cps = [];\n\n    var v = [];\n    var v1 = [];\n    var v2 = [];\n    var prevPoint;\n    var nextPoint;\n\n    var min$$1;\n    var max$$1;\n    if (constraint) {\n        min$$1 = [Infinity, Infinity];\n        max$$1 = [-Infinity, -Infinity];\n        for (var i = 0, len$$1 = points.length; i < len$$1; i++) {\n            min(min$$1, min$$1, points[i]);\n            max(max$$1, max$$1, points[i]);\n        }\n        // 与指定的包围盒做并集\n        min(min$$1, min$$1, constraint[0]);\n        max(max$$1, max$$1, constraint[1]);\n    }\n\n    for (var i = 0, len$$1 = points.length; i < len$$1; i++) {\n        var point = points[i];\n\n        if (isLoop) {\n            prevPoint = points[i ? i - 1 : len$$1 - 1];\n            nextPoint = points[(i + 1) % len$$1];\n        }\n        else {\n            if (i === 0 || i === len$$1 - 1) {\n                cps.push(clone$1(points[i]));\n                continue;\n            }\n            else {\n                prevPoint = points[i - 1];\n                nextPoint = points[i + 1];\n            }\n        }\n\n        sub(v, nextPoint, prevPoint);\n\n        // use degree to scale the handle length\n        scale(v, v, smooth);\n\n        var d0 = distance(point, prevPoint);\n        var d1 = distance(point, nextPoint);\n        var sum = d0 + d1;\n        if (sum !== 0) {\n            d0 /= sum;\n            d1 /= sum;\n        }\n\n        scale(v1, v, -d0);\n        scale(v2, v, d1);\n        var cp0 = add([], point, v1);\n        var cp1 = add([], point, v2);\n        if (constraint) {\n            max(cp0, cp0, min$$1);\n            min(cp0, cp0, max$$1);\n            max(cp1, cp1, min$$1);\n            min(cp1, cp1, max$$1);\n        }\n        cps.push(cp0);\n        cps.push(cp1);\n    }\n\n    if (isLoop) {\n        cps.push(cps.shift());\n    }\n\n    return cps;\n};\n\nfunction buildPath$1(ctx, shape, closePath) {\n    var points = shape.points;\n    var smooth = shape.smooth;\n    if (points && points.length >= 2) {\n        if (smooth && smooth !== 'spline') {\n            var controlPoints = smoothBezier(\n                points, smooth, closePath, shape.smoothConstraint\n            );\n\n            ctx.moveTo(points[0][0], points[0][1]);\n            var len = points.length;\n            for (var i = 0; i < (closePath ? len : len - 1); i++) {\n                var cp1 = controlPoints[i * 2];\n                var cp2 = controlPoints[i * 2 + 1];\n                var p = points[(i + 1) % len];\n                ctx.bezierCurveTo(\n                    cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]\n                );\n            }\n        }\n        else {\n            if (smooth === 'spline') {\n                points = smoothSpline(points, closePath);\n            }\n\n            ctx.moveTo(points[0][0], points[0][1]);\n            for (var i = 1, l = points.length; i < l; i++) {\n                ctx.lineTo(points[i][0], points[i][1]);\n            }\n        }\n\n        closePath && ctx.closePath();\n    }\n}\n\n/**\n * 多边形\n * @module zrender/shape/Polygon\n */\n\nvar Polygon = Path.extend({\n\n    type: 'polygon',\n\n    shape: {\n        points: null,\n\n        smooth: false,\n\n        smoothConstraint: null\n    },\n\n    buildPath: function (ctx, shape) {\n        buildPath$1(ctx, shape, true);\n    }\n});\n\n/**\n * @module zrender/graphic/shape/Polyline\n */\n\nvar Polyline = Path.extend({\n\n    type: 'polyline',\n\n    shape: {\n        points: null,\n\n        smooth: false,\n\n        smoothConstraint: null\n    },\n\n    style: {\n        stroke: '#000',\n\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        buildPath$1(ctx, shape, false);\n    }\n});\n\n/**\n * Sub-pixel optimize for canvas rendering, prevent from blur\n * when rendering a thin vertical/horizontal line.\n */\n\nvar round$1 = Math.round;\n\n/**\n * Sub pixel optimize line for canvas\n *\n * @param {Object} outputShape The modification will be performed on `outputShape`.\n *                 `outputShape` and `inputShape` can be the same object.\n *                 `outputShape` object can be used repeatly, because all of\n *                 the `x1`, `x2`, `y1`, `y2` will be assigned in this method.\n * @param {Object} [inputShape]\n * @param {number} [inputShape.x1]\n * @param {number} [inputShape.y1]\n * @param {number} [inputShape.x2]\n * @param {number} [inputShape.y2]\n * @param {Object} [style]\n * @param {number} [style.lineWidth]\n */\nfunction subPixelOptimizeLine$1(outputShape, inputShape, style) {\n    var lineWidth = style && style.lineWidth;\n\n    if (!inputShape || !lineWidth) {\n        return;\n    }\n\n    var x1 = inputShape.x1;\n    var x2 = inputShape.x2;\n    var y1 = inputShape.y1;\n    var y2 = inputShape.y2;\n\n    if (round$1(x1 * 2) === round$1(x2 * 2)) {\n        outputShape.x1 = outputShape.x2 = subPixelOptimize$1(x1, lineWidth, true);\n    }\n    else {\n        outputShape.x1 = x1;\n        outputShape.x2 = x2;\n    }\n    if (round$1(y1 * 2) === round$1(y2 * 2)) {\n        outputShape.y1 = outputShape.y2 = subPixelOptimize$1(y1, lineWidth, true);\n    }\n    else {\n        outputShape.y1 = y1;\n        outputShape.y2 = y2;\n    }\n}\n\n/**\n * Sub pixel optimize rect for canvas\n *\n * @param {Object} outputShape The modification will be performed on `outputShape`.\n *                 `outputShape` and `inputShape` can be the same object.\n *                 `outputShape` object can be used repeatly, because all of\n *                 the `x`, `y`, `width`, `height` will be assigned in this method.\n * @param {Object} [inputShape]\n * @param {number} [inputShape.x]\n * @param {number} [inputShape.y]\n * @param {number} [inputShape.width]\n * @param {number} [inputShape.height]\n * @param {Object} [style]\n * @param {number} [style.lineWidth]\n */\nfunction subPixelOptimizeRect$1(outputShape, inputShape, style) {\n    var lineWidth = style && style.lineWidth;\n\n    if (!inputShape || !lineWidth) {\n        return;\n    }\n\n    var originX = inputShape.x;\n    var originY = inputShape.y;\n    var originWidth = inputShape.width;\n    var originHeight = inputShape.height;\n\n    outputShape.x = subPixelOptimize$1(originX, lineWidth, true);\n    outputShape.y = subPixelOptimize$1(originY, lineWidth, true);\n    outputShape.width = Math.max(\n        subPixelOptimize$1(originX + originWidth, lineWidth, false) - outputShape.x,\n        originWidth === 0 ? 0 : 1\n    );\n    outputShape.height = Math.max(\n        subPixelOptimize$1(originY + originHeight, lineWidth, false) - outputShape.y,\n        originHeight === 0 ? 0 : 1\n    );\n}\n\n/**\n * Sub pixel optimize for canvas\n *\n * @param {number} position Coordinate, such as x, y\n * @param {number} lineWidth Should be nonnegative integer.\n * @param {boolean=} positiveOrNegative Default false (negative).\n * @return {number} Optimized position.\n */\nfunction subPixelOptimize$1(position, lineWidth, positiveOrNegative) {\n    // Assure that (position + lineWidth / 2) is near integer edge,\n    // otherwise line will be fuzzy in canvas.\n    var doubledPosition = round$1(position * 2);\n    return (doubledPosition + round$1(lineWidth)) % 2 === 0\n        ? doubledPosition / 2\n        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;\n}\n\n/**\n * 矩形\n * @module zrender/graphic/shape/Rect\n */\n\n// Avoid create repeatly.\nvar subPixelOptimizeOutputShape = {};\n\nvar Rect = Path.extend({\n\n    type: 'rect',\n\n    shape: {\n        // 左上、右上、右下、左下角的半径依次为r1、r2、r3、r4\n        // r缩写为1         相当于 [1, 1, 1, 1]\n        // r缩写为[1]       相当于 [1, 1, 1, 1]\n        // r缩写为[1, 2]    相当于 [1, 2, 1, 2]\n        // r缩写为[1, 2, 3] 相当于 [1, 2, 3, 2]\n        r: 0,\n\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var x;\n        var y;\n        var width;\n        var height;\n\n        if (this.subPixelOptimize) {\n            subPixelOptimizeRect$1(subPixelOptimizeOutputShape, shape, this.style);\n            x = subPixelOptimizeOutputShape.x;\n            y = subPixelOptimizeOutputShape.y;\n            width = subPixelOptimizeOutputShape.width;\n            height = subPixelOptimizeOutputShape.height;\n            subPixelOptimizeOutputShape.r = shape.r;\n            shape = subPixelOptimizeOutputShape;\n        }\n        else {\n            x = shape.x;\n            y = shape.y;\n            width = shape.width;\n            height = shape.height;\n        }\n\n        if (!shape.r) {\n            ctx.rect(x, y, width, height);\n        }\n        else {\n            buildPath(ctx, shape);\n        }\n        ctx.closePath();\n        return;\n    }\n});\n\n/**\n * 直线\n * @module zrender/graphic/shape/Line\n */\n\n// Avoid create repeatly.\nvar subPixelOptimizeOutputShape$1 = {};\n\nvar Line = Path.extend({\n\n    type: 'line',\n\n    shape: {\n        // Start point\n        x1: 0,\n        y1: 0,\n        // End point\n        x2: 0,\n        y2: 0,\n\n        percent: 1\n    },\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        var x1;\n        var y1;\n        var x2;\n        var y2;\n\n        if (this.subPixelOptimize) {\n            subPixelOptimizeLine$1(subPixelOptimizeOutputShape$1, shape, this.style);\n            x1 = subPixelOptimizeOutputShape$1.x1;\n            y1 = subPixelOptimizeOutputShape$1.y1;\n            x2 = subPixelOptimizeOutputShape$1.x2;\n            y2 = subPixelOptimizeOutputShape$1.y2;\n        }\n        else {\n            x1 = shape.x1;\n            y1 = shape.y1;\n            x2 = shape.x2;\n            y2 = shape.y2;\n        }\n\n        var percent = shape.percent;\n\n        if (percent === 0) {\n            return;\n        }\n\n        ctx.moveTo(x1, y1);\n\n        if (percent < 1) {\n            x2 = x1 * (1 - percent) + x2 * percent;\n            y2 = y1 * (1 - percent) + y2 * percent;\n        }\n        ctx.lineTo(x2, y2);\n    },\n\n    /**\n     * Get point at percent\n     * @param  {number} percent\n     * @return {Array.<number>}\n     */\n    pointAt: function (p) {\n        var shape = this.shape;\n        return [\n            shape.x1 * (1 - p) + shape.x2 * p,\n            shape.y1 * (1 - p) + shape.y2 * p\n        ];\n    }\n});\n\n/**\n * 贝塞尔曲线\n * @module zrender/shape/BezierCurve\n */\n\nvar out = [];\n\nfunction someVectorAt(shape, t, isTangent) {\n    var cpx2 = shape.cpx2;\n    var cpy2 = shape.cpy2;\n    if (cpx2 === null || cpy2 === null) {\n        return [\n            (isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t),\n            (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t)\n        ];\n    }\n    else {\n        return [\n            (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t),\n            (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t)\n        ];\n    }\n}\n\nvar BezierCurve = Path.extend({\n\n    type: 'bezier-curve',\n\n    shape: {\n        x1: 0,\n        y1: 0,\n        x2: 0,\n        y2: 0,\n        cpx1: 0,\n        cpy1: 0,\n        // cpx2: 0,\n        // cpy2: 0\n\n        // Curve show percent, for animating\n        percent: 1\n    },\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        var x1 = shape.x1;\n        var y1 = shape.y1;\n        var x2 = shape.x2;\n        var y2 = shape.y2;\n        var cpx1 = shape.cpx1;\n        var cpy1 = shape.cpy1;\n        var cpx2 = shape.cpx2;\n        var cpy2 = shape.cpy2;\n        var percent = shape.percent;\n        if (percent === 0) {\n            return;\n        }\n\n        ctx.moveTo(x1, y1);\n\n        if (cpx2 == null || cpy2 == null) {\n            if (percent < 1) {\n                quadraticSubdivide(\n                    x1, cpx1, x2, percent, out\n                );\n                cpx1 = out[1];\n                x2 = out[2];\n                quadraticSubdivide(\n                    y1, cpy1, y2, percent, out\n                );\n                cpy1 = out[1];\n                y2 = out[2];\n            }\n\n            ctx.quadraticCurveTo(\n                cpx1, cpy1,\n                x2, y2\n            );\n        }\n        else {\n            if (percent < 1) {\n                cubicSubdivide(\n                    x1, cpx1, cpx2, x2, percent, out\n                );\n                cpx1 = out[1];\n                cpx2 = out[2];\n                x2 = out[3];\n                cubicSubdivide(\n                    y1, cpy1, cpy2, y2, percent, out\n                );\n                cpy1 = out[1];\n                cpy2 = out[2];\n                y2 = out[3];\n            }\n            ctx.bezierCurveTo(\n                cpx1, cpy1,\n                cpx2, cpy2,\n                x2, y2\n            );\n        }\n    },\n\n    /**\n     * Get point at percent\n     * @param  {number} t\n     * @return {Array.<number>}\n     */\n    pointAt: function (t) {\n        return someVectorAt(this.shape, t, false);\n    },\n\n    /**\n     * Get tangent at percent\n     * @param  {number} t\n     * @return {Array.<number>}\n     */\n    tangentAt: function (t) {\n        var p = someVectorAt(this.shape, t, true);\n        return normalize(p, p);\n    }\n});\n\n/**\n * 圆弧\n * @module zrender/graphic/shape/Arc\n */\n\nvar Arc = Path.extend({\n\n    type: 'arc',\n\n    shape: {\n\n        cx: 0,\n\n        cy: 0,\n\n        r: 0,\n\n        startAngle: 0,\n\n        endAngle: Math.PI * 2,\n\n        clockwise: true\n    },\n\n    style: {\n\n        stroke: '#000',\n\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n\n        var x = shape.cx;\n        var y = shape.cy;\n        var r = Math.max(shape.r, 0);\n        var startAngle = shape.startAngle;\n        var endAngle = shape.endAngle;\n        var clockwise = shape.clockwise;\n\n        var unitX = Math.cos(startAngle);\n        var unitY = Math.sin(startAngle);\n\n        ctx.moveTo(unitX * r + x, unitY * r + y);\n        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);\n    }\n});\n\n// CompoundPath to improve performance\n\nvar CompoundPath = Path.extend({\n\n    type: 'compound',\n\n    shape: {\n\n        paths: null\n    },\n\n    _updatePathDirty: function () {\n        var dirtyPath = this.__dirtyPath;\n        var paths = this.shape.paths;\n        for (var i = 0; i < paths.length; i++) {\n            // Mark as dirty if any subpath is dirty\n            dirtyPath = dirtyPath || paths[i].__dirtyPath;\n        }\n        this.__dirtyPath = dirtyPath;\n        this.__dirty = this.__dirty || dirtyPath;\n    },\n\n    beforeBrush: function () {\n        this._updatePathDirty();\n        var paths = this.shape.paths || [];\n        var scale = this.getGlobalScale();\n        // Update path scale\n        for (var i = 0; i < paths.length; i++) {\n            if (!paths[i].path) {\n                paths[i].createPathProxy();\n            }\n            paths[i].path.setScale(scale[0], scale[1]);\n        }\n    },\n\n    buildPath: function (ctx, shape) {\n        var paths = shape.paths || [];\n        for (var i = 0; i < paths.length; i++) {\n            paths[i].buildPath(ctx, paths[i].shape, true);\n        }\n    },\n\n    afterBrush: function () {\n        var paths = this.shape.paths || [];\n        for (var i = 0; i < paths.length; i++) {\n            paths[i].__dirtyPath = false;\n        }\n    },\n\n    getBoundingRect: function () {\n        this._updatePathDirty();\n        return Path.prototype.getBoundingRect.call(this);\n    }\n});\n\n/**\n * @param {Array.<Object>} colorStops\n */\nvar Gradient = function (colorStops) {\n\n    this.colorStops = colorStops || [];\n\n};\n\nGradient.prototype = {\n\n    constructor: Gradient,\n\n    addColorStop: function (offset, color) {\n        this.colorStops.push({\n\n            offset: offset,\n\n            color: color\n        });\n    }\n\n};\n\n/**\n * x, y, x2, y2 are all percent from 0 to 1\n * @param {number} [x=0]\n * @param {number} [y=0]\n * @param {number} [x2=1]\n * @param {number} [y2=0]\n * @param {Array.<Object>} colorStops\n * @param {boolean} [globalCoord=false]\n */\nvar LinearGradient = function (x, y, x2, y2, colorStops, globalCoord) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {type: 'linear', colorStops: ...}`, where\n    // this constructor will not be called.\n\n    this.x = x == null ? 0 : x;\n\n    this.y = y == null ? 0 : y;\n\n    this.x2 = x2 == null ? 1 : x2;\n\n    this.y2 = y2 == null ? 0 : y2;\n\n    // Can be cloned\n    this.type = 'linear';\n\n    // If use global coord\n    this.global = globalCoord || false;\n\n    Gradient.call(this, colorStops);\n};\n\nLinearGradient.prototype = {\n\n    constructor: LinearGradient\n};\n\ninherits(LinearGradient, Gradient);\n\n/**\n * x, y, r are all percent from 0 to 1\n * @param {number} [x=0.5]\n * @param {number} [y=0.5]\n * @param {number} [r=0.5]\n * @param {Array.<Object>} [colorStops]\n * @param {boolean} [globalCoord=false]\n */\nvar RadialGradient = function (x, y, r, colorStops, globalCoord) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {type: 'radial', colorStops: ...}`, where\n    // this constructor will not be called.\n\n    this.x = x == null ? 0.5 : x;\n\n    this.y = y == null ? 0.5 : y;\n\n    this.r = r == null ? 0.5 : r;\n\n    // Can be cloned\n    this.type = 'radial';\n\n    // If use global coord\n    this.global = globalCoord || false;\n\n    Gradient.call(this, colorStops);\n};\n\nRadialGradient.prototype = {\n\n    constructor: RadialGradient\n};\n\ninherits(RadialGradient, Gradient);\n\n/**\n * Displayable for incremental rendering. It will be rendered in a separate layer\n * IncrementalDisplay have two main methods. `clearDisplayables` and `addDisplayables`\n * addDisplayables will render the added displayables incremetally.\n *\n * It use a not clearFlag to tell the painter don't clear the layer if it's the first element.\n */\n// TODO Style override ?\nfunction IncrementalDisplayble(opts) {\n\n    Displayable.call(this, opts);\n\n    this._displayables = [];\n\n    this._temporaryDisplayables = [];\n\n    this._cursor = 0;\n\n    this.notClear = true;\n}\n\nIncrementalDisplayble.prototype.incremental = true;\n\nIncrementalDisplayble.prototype.clearDisplaybles = function () {\n    this._displayables = [];\n    this._temporaryDisplayables = [];\n    this._cursor = 0;\n    this.dirty();\n\n    this.notClear = false;\n};\n\nIncrementalDisplayble.prototype.addDisplayable = function (displayable, notPersistent) {\n    if (notPersistent) {\n        this._temporaryDisplayables.push(displayable);\n    }\n    else {\n        this._displayables.push(displayable);\n    }\n    this.dirty();\n};\n\nIncrementalDisplayble.prototype.addDisplayables = function (displayables, notPersistent) {\n    notPersistent = notPersistent || false;\n    for (var i = 0; i < displayables.length; i++) {\n        this.addDisplayable(displayables[i], notPersistent);\n    }\n};\n\nIncrementalDisplayble.prototype.eachPendingDisplayable = function (cb) {\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        cb && cb(this._displayables[i]);\n    }\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        cb && cb(this._temporaryDisplayables[i]);\n    }\n};\n\nIncrementalDisplayble.prototype.update = function () {\n    this.updateTransform();\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        var displayable = this._displayables[i];\n        // PENDING\n        displayable.parent = this;\n        displayable.update();\n        displayable.parent = null;\n    }\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        var displayable = this._temporaryDisplayables[i];\n        // PENDING\n        displayable.parent = this;\n        displayable.update();\n        displayable.parent = null;\n    }\n};\n\nIncrementalDisplayble.prototype.brush = function (ctx, prevEl) {\n    // Render persistant displayables.\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        var displayable = this._displayables[i];\n        displayable.beforeBrush && displayable.beforeBrush(ctx);\n        displayable.brush(ctx, i === this._cursor ? null : this._displayables[i - 1]);\n        displayable.afterBrush && displayable.afterBrush(ctx);\n    }\n    this._cursor = i;\n    // Render temporary displayables.\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        var displayable = this._temporaryDisplayables[i];\n        displayable.beforeBrush && displayable.beforeBrush(ctx);\n        displayable.brush(ctx, i === 0 ? null : this._temporaryDisplayables[i - 1]);\n        displayable.afterBrush && displayable.afterBrush(ctx);\n    }\n\n    this._temporaryDisplayables = [];\n\n    this.notClear = true;\n};\n\nvar m = [];\nIncrementalDisplayble.prototype.getBoundingRect = function () {\n    if (!this._rect) {\n        var rect = new BoundingRect(Infinity, Infinity, -Infinity, -Infinity);\n        for (var i = 0; i < this._displayables.length; i++) {\n            var displayable = this._displayables[i];\n            var childRect = displayable.getBoundingRect().clone();\n            if (displayable.needLocalTransform()) {\n                childRect.applyTransform(displayable.getLocalTransform(m));\n            }\n            rect.union(childRect);\n        }\n        this._rect = rect;\n    }\n    return this._rect;\n};\n\nIncrementalDisplayble.prototype.contain = function (x, y) {\n    var localPos = this.transformCoordToLocal(x, y);\n    var rect = this.getBoundingRect();\n\n    if (rect.contain(localPos[0], localPos[1])) {\n        for (var i = 0; i < this._displayables.length; i++) {\n            var displayable = this._displayables[i];\n            if (displayable.contain(x, y)) {\n                return true;\n            }\n        }\n    }\n    return false;\n};\n\ninherits(IncrementalDisplayble, Displayable);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar round = Math.round;\nvar mathMax$1 = Math.max;\nvar mathMin$1 = Math.min;\n\nvar EMPTY_OBJ = {};\n\nvar Z2_EMPHASIS_LIFT = 1;\n\n/**\n * Extend shape with parameters\n */\nfunction extendShape(opts) {\n    return Path.extend(opts);\n}\n\n/**\n * Extend path\n */\nfunction extendPath(pathData, opts) {\n    return extendFromString(pathData, opts);\n}\n\n/**\n * Create a path element from path data string\n * @param {string} pathData\n * @param {Object} opts\n * @param {module:zrender/core/BoundingRect} rect\n * @param {string} [layout=cover] 'center' or 'cover'\n */\nfunction makePath(pathData, opts, rect, layout) {\n    var path = createFromString(pathData, opts);\n    if (rect) {\n        if (layout === 'center') {\n            rect = centerGraphic(rect, path.getBoundingRect());\n        }\n        resizePath(path, rect);\n    }\n    return path;\n}\n\n/**\n * Create a image element from image url\n * @param {string} imageUrl image url\n * @param {Object} opts options\n * @param {module:zrender/core/BoundingRect} rect constrain rect\n * @param {string} [layout=cover] 'center' or 'cover'\n */\nfunction makeImage(imageUrl, rect, layout) {\n    var path = new ZImage({\n        style: {\n            image: imageUrl,\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        },\n        onload: function (img) {\n            if (layout === 'center') {\n                var boundingRect = {\n                    width: img.width,\n                    height: img.height\n                };\n                path.setStyle(centerGraphic(rect, boundingRect));\n            }\n        }\n    });\n    return path;\n}\n\n/**\n * Get position of centered element in bounding box.\n *\n * @param  {Object} rect         element local bounding box\n * @param  {Object} boundingRect constraint bounding box\n * @return {Object} element position containing x, y, width, and height\n */\nfunction centerGraphic(rect, boundingRect) {\n    // Set rect to center, keep width / height ratio.\n    var aspect = boundingRect.width / boundingRect.height;\n    var width = rect.height * aspect;\n    var height;\n    if (width <= rect.width) {\n        height = rect.height;\n    }\n    else {\n        width = rect.width;\n        height = width / aspect;\n    }\n    var cx = rect.x + rect.width / 2;\n    var cy = rect.y + rect.height / 2;\n\n    return {\n        x: cx - width / 2,\n        y: cy - height / 2,\n        width: width,\n        height: height\n    };\n}\n\nvar mergePath = mergePath$1;\n\n/**\n * Resize a path to fit the rect\n * @param {module:zrender/graphic/Path} path\n * @param {Object} rect\n */\nfunction resizePath(path, rect) {\n    if (!path.applyTransform) {\n        return;\n    }\n\n    var pathRect = path.getBoundingRect();\n\n    var m = pathRect.calculateTransform(rect);\n\n    path.applyTransform(m);\n}\n\n/**\n * Sub pixel optimize line for canvas\n *\n * @param {Object} param\n * @param {Object} [param.shape]\n * @param {number} [param.shape.x1]\n * @param {number} [param.shape.y1]\n * @param {number} [param.shape.x2]\n * @param {number} [param.shape.y2]\n * @param {Object} [param.style]\n * @param {number} [param.style.lineWidth]\n * @return {Object} Modified param\n */\nfunction subPixelOptimizeLine(param) {\n    var shape = param.shape;\n    var lineWidth = param.style.lineWidth;\n\n    if (round(shape.x1 * 2) === round(shape.x2 * 2)) {\n        shape.x1 = shape.x2 = subPixelOptimize(shape.x1, lineWidth, true);\n    }\n    if (round(shape.y1 * 2) === round(shape.y2 * 2)) {\n        shape.y1 = shape.y2 = subPixelOptimize(shape.y1, lineWidth, true);\n    }\n    return param;\n}\n\n/**\n * Sub pixel optimize rect for canvas\n *\n * @param {Object} param\n * @param {Object} [param.shape]\n * @param {number} [param.shape.x]\n * @param {number} [param.shape.y]\n * @param {number} [param.shape.width]\n * @param {number} [param.shape.height]\n * @param {Object} [param.style]\n * @param {number} [param.style.lineWidth]\n * @return {Object} Modified param\n */\nfunction subPixelOptimizeRect(param) {\n    var shape = param.shape;\n    var lineWidth = param.style.lineWidth;\n    var originX = shape.x;\n    var originY = shape.y;\n    var originWidth = shape.width;\n    var originHeight = shape.height;\n    shape.x = subPixelOptimize(shape.x, lineWidth, true);\n    shape.y = subPixelOptimize(shape.y, lineWidth, true);\n    shape.width = Math.max(\n        subPixelOptimize(originX + originWidth, lineWidth, false) - shape.x,\n        originWidth === 0 ? 0 : 1\n    );\n    shape.height = Math.max(\n        subPixelOptimize(originY + originHeight, lineWidth, false) - shape.y,\n        originHeight === 0 ? 0 : 1\n    );\n    return param;\n}\n\n/**\n * Sub pixel optimize for canvas\n *\n * @param {number} position Coordinate, such as x, y\n * @param {number} lineWidth Should be nonnegative integer.\n * @param {boolean=} positiveOrNegative Default false (negative).\n * @return {number} Optimized position.\n */\nfunction subPixelOptimize(position, lineWidth, positiveOrNegative) {\n    // Assure that (position + lineWidth / 2) is near integer edge,\n    // otherwise line will be fuzzy in canvas.\n    var doubledPosition = round(position * 2);\n    return (doubledPosition + round(lineWidth)) % 2 === 0\n        ? doubledPosition / 2\n        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;\n}\n\nfunction hasFillOrStroke(fillOrStroke) {\n    return fillOrStroke != null && fillOrStroke !== 'none';\n}\n\n// Most lifted color are duplicated.\nvar liftedColorMap = createHashMap();\nvar liftedColorCount = 0;\n\nfunction liftColor(color) {\n    if (typeof color !== 'string') {\n        return color;\n    }\n    var liftedColor = liftedColorMap.get(color);\n    if (!liftedColor) {\n        liftedColor = lift(color, -0.1);\n        if (liftedColorCount < 10000) {\n            liftedColorMap.set(color, liftedColor);\n            liftedColorCount++;\n        }\n    }\n    return liftedColor;\n}\n\nfunction cacheElementStl(el) {\n    if (!el.__hoverStlDirty) {\n        return;\n    }\n    el.__hoverStlDirty = false;\n\n    var hoverStyle = el.__hoverStl;\n    if (!hoverStyle) {\n        el.__cachedNormalStl = el.__cachedNormalZ2 = null;\n        return;\n    }\n\n    var normalStyle = el.__cachedNormalStl = {};\n    el.__cachedNormalZ2 = el.z2;\n    var elStyle = el.style;\n\n    for (var name in hoverStyle) {\n        // See comment in `doSingleEnterHover`.\n        if (hoverStyle[name] != null) {\n            normalStyle[name] = elStyle[name];\n        }\n    }\n\n    // Always cache fill and stroke to normalStyle for lifting color.\n    normalStyle.fill = elStyle.fill;\n    normalStyle.stroke = elStyle.stroke;\n}\n\nfunction doSingleEnterHover(el) {\n    var hoverStl = el.__hoverStl;\n\n    if (!hoverStl || el.__highlighted) {\n        return;\n    }\n\n    var useHoverLayer = el.useHoverLayer;\n    el.__highlighted = useHoverLayer ? 'layer' : 'plain';\n\n    var zr = el.__zr;\n    if (!zr && useHoverLayer) {\n        return;\n    }\n\n    var elTarget = el;\n    var targetStyle = el.style;\n\n    if (useHoverLayer) {\n        elTarget = zr.addHover(el);\n        targetStyle = elTarget.style;\n    }\n\n    rollbackDefaultTextStyle(targetStyle);\n\n    if (!useHoverLayer) {\n        cacheElementStl(elTarget);\n    }\n\n    // styles can be:\n    // {\n    //    label: {\n    //        show: false,\n    //        position: 'outside',\n    //        fontSize: 18\n    //    },\n    //    emphasis: {\n    //        label: {\n    //            show: true\n    //        }\n    //    }\n    // },\n    // where properties of `emphasis` may not appear in `normal`. We previously use\n    // module:echarts/util/model#defaultEmphasis to merge `normal` to `emphasis`.\n    // But consider rich text and setOption in merge mode, it is impossible to cover\n    // all properties in merge. So we use merge mode when setting style here, where\n    // only properties that is not `null/undefined` can be set. The disadventage:\n    // null/undefined can not be used to remove style any more in `emphasis`.\n    targetStyle.extendFrom(hoverStl);\n\n    setDefaultHoverFillStroke(targetStyle, hoverStl, 'fill');\n    setDefaultHoverFillStroke(targetStyle, hoverStl, 'stroke');\n\n    applyDefaultTextStyle(targetStyle);\n\n    if (!useHoverLayer) {\n        el.dirty(false);\n        el.z2 += Z2_EMPHASIS_LIFT;\n    }\n}\n\nfunction setDefaultHoverFillStroke(targetStyle, hoverStyle, prop) {\n    if (!hasFillOrStroke(hoverStyle[prop]) && hasFillOrStroke(targetStyle[prop])) {\n        targetStyle[prop] = liftColor(targetStyle[prop]);\n    }\n}\n\nfunction doSingleLeaveHover(el) {\n    var highlighted = el.__highlighted;\n\n    if (!highlighted) {\n        return;\n    }\n\n    el.__highlighted = false;\n\n    if (highlighted === 'layer') {\n        el.__zr && el.__zr.removeHover(el);\n    }\n    else if (highlighted) {\n        var style = el.style;\n\n        var normalStl = el.__cachedNormalStl;\n        if (normalStl) {\n            rollbackDefaultTextStyle(style);\n            // Consider null/undefined value, should use\n            // `setStyle` but not `extendFrom(stl, true)`.\n            el.setStyle(normalStl);\n            applyDefaultTextStyle(style);\n        }\n        // `__cachedNormalZ2` will not be reset if calling `setElementHoverStyle`\n        // when `el` is on emphasis state. So here by comparing with 1, we try\n        // hard to make the bug case rare.\n        var normalZ2 = el.__cachedNormalZ2;\n        if (normalZ2 != null && el.z2 - normalZ2 === Z2_EMPHASIS_LIFT) {\n            el.z2 = normalZ2;\n        }\n    }\n}\n\nfunction traverseCall(el, method) {\n    el.isGroup\n        ? el.traverse(function (child) {\n            !child.isGroup && method(child);\n        })\n        : method(el);\n}\n\n/**\n * Set hover style (namely \"emphasis style\") of element, based on the current\n * style of the given `el`.\n * This method should be called after all of the normal styles have been adopted\n * to the `el`. See the reason on `setHoverStyle`.\n *\n * @param {module:zrender/Element} el Should not be `zrender/container/Group`.\n * @param {Object|boolean} [hoverStl] The specified hover style.\n *        If set as `false`, disable the hover style.\n *        Similarly, The `el.hoverStyle` can alse be set\n *        as `false` to disable the hover style.\n *        Otherwise, use the default hover style if not provided.\n * @param {Object} [opt]\n * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`\n */\nfunction setElementHoverStyle(el, hoverStl) {\n    // For performance consideration, it might be better to make the \"hover style\" only the\n    // difference properties from the \"normal style\", but not a entire copy of all styles.\n    hoverStl = el.__hoverStl = hoverStl !== false && (hoverStl || {});\n    el.__hoverStlDirty = true;\n\n    // FIXME\n    // It is not completely right to save \"normal\"/\"emphasis\" flag on elements.\n    // It probably should be saved on `data` of series. Consider the cases:\n    // (1) A highlighted elements are moved out of the view port and re-enter\n    // again by dataZoom.\n    // (2) call `setOption` and replace elements totally when they are highlighted.\n    if (el.__highlighted) {\n        // Consider the case:\n        // The styles of a highlighted `el` is being updated. The new \"emphasis style\"\n        // should be adapted to the `el`. Notice here new \"normal styles\" should have\n        // been set outside and the cached \"normal style\" is out of date.\n        el.__cachedNormalStl = null;\n        // Do not clear `__cachedNormalZ2` here, because setting `z2` is not a constraint\n        // of this method. In most cases, `z2` is not set and hover style should be able\n        // to rollback. Of course, that would bring bug, but only in a rare case, see\n        // `doSingleLeaveHover` for details.\n        doSingleLeaveHover(el);\n\n        doSingleEnterHover(el);\n    }\n}\n\n/**\n * Emphasis (called by API) has higher priority than `mouseover`.\n * When element has been called to be entered emphasis, mouse over\n * should not trigger the highlight effect (for example, animation\n * scale) again, and `mouseout` should not downplay the highlight\n * effect. So the listener of `mouseover` and `mouseout` should\n * check `isInEmphasis`.\n *\n * @param {module:zrender/Element} el\n * @return {boolean}\n */\nfunction isInEmphasis(el) {\n    return el && el.__isEmphasisEntered;\n}\n\nfunction onElementMouseOver(e) {\n    if (this.__hoverSilentOnTouch && e.zrByTouch) {\n        return;\n    }\n\n    // Only if element is not in emphasis status\n    !this.__isEmphasisEntered && traverseCall(this, doSingleEnterHover);\n}\n\nfunction onElementMouseOut(e) {\n    if (this.__hoverSilentOnTouch && e.zrByTouch) {\n        return;\n    }\n\n    // Only if element is not in emphasis status\n    !this.__isEmphasisEntered && traverseCall(this, doSingleLeaveHover);\n}\n\nfunction enterEmphasis() {\n    this.__isEmphasisEntered = true;\n    traverseCall(this, doSingleEnterHover);\n}\n\nfunction leaveEmphasis() {\n    this.__isEmphasisEntered = false;\n    traverseCall(this, doSingleLeaveHover);\n}\n\n/**\n * Set hover style (namely \"emphasis style\") of element,\n * based on the current style of the given `el`.\n *\n * (1)\n * **CONSTRAINTS** for this method:\n * <A> This method MUST be called after all of the normal styles having been adopted\n * to the `el`.\n * <B> The input `hoverStyle` (that is, \"emphasis style\") MUST be the subset of the\n * \"normal style\" having been set to the el.\n * <C> `color` MUST be one of the \"normal styles\" (because color might be lifted as\n * a default hover style).\n *\n * The reason: this method treat the current style of the `el` as the \"normal style\"\n * and cache them when enter/update the \"emphasis style\". Consider the case: the `el`\n * is in \"emphasis\" state and `setOption`/`dispatchAction` trigger the style updating\n * logic, where the el should shift from the original emphasis style to the new\n * \"emphasis style\" and should be able to \"downplay\" back to the new \"normal style\".\n *\n * Indeed, it is error-prone to make a interface has so many constraints, but I have\n * not found a better solution yet to fit the backward compatibility, performance and\n * the current programming style.\n *\n * (2)\n * Call the method for a \"root\" element once. Do not call it for each descendants.\n * If the descendants elemenets of a group has itself hover style different from the\n * root group, we can simply mount the style on `el.hoverStyle` for them, but should\n * not call this method for them.\n *\n * @param {module:zrender/Element} el\n * @param {Object|boolean} [hoverStyle] See `graphic.setElementHoverStyle`.\n * @param {Object} [opt]\n * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`.\n */\nfunction setHoverStyle(el, hoverStyle, opt) {\n    el.isGroup\n        ? el.traverse(function (child) {\n            // If element has sepcified hoverStyle, then use it instead of given hoverStyle\n            // Often used when item group has a label element and it's hoverStyle is different\n            !child.isGroup && setElementHoverStyle(child, child.hoverStyle || hoverStyle);\n        })\n        : setElementHoverStyle(el, el.hoverStyle || hoverStyle);\n\n    setAsHoverStyleTrigger(el, opt);\n}\n\n/**\n * @param {Object|boolean} [opt] If `false`, means disable trigger.\n * @param {boolean} [opt.hoverSilentOnTouch=false]\n *        In touch device, mouseover event will be trigger on touchstart event\n *        (see module:zrender/dom/HandlerProxy). By this mechanism, we can\n *        conveniently use hoverStyle when tap on touch screen without additional\n *        code for compatibility.\n *        But if the chart/component has select feature, which usually also use\n *        hoverStyle, there might be conflict between 'select-highlight' and\n *        'hover-highlight' especially when roam is enabled (see geo for example).\n *        In this case, hoverSilentOnTouch should be used to disable hover-highlight\n *        on touch device.\n */\nfunction setAsHoverStyleTrigger(el, opt) {\n    var disable = opt === false;\n    el.__hoverSilentOnTouch = opt != null && opt.hoverSilentOnTouch;\n\n    // Simple optimize, since this method might be\n    // called for each elements of a group in some cases.\n    if (!disable || el.__hoverStyleTrigger) {\n        var method = disable ? 'off' : 'on';\n\n        // Duplicated function will be auto-ignored, see Eventful.js.\n        el[method]('mouseover', onElementMouseOver)[method]('mouseout', onElementMouseOut);\n        // Emphasis, normal can be triggered manually\n        el[method]('emphasis', enterEmphasis)[method]('normal', leaveEmphasis);\n\n        el.__hoverStyleTrigger = !disable;\n    }\n}\n\n/**\n * See more info in `setTextStyleCommon`.\n * @param {Object|module:zrender/graphic/Style} normalStyle\n * @param {Object} emphasisStyle\n * @param {module:echarts/model/Model} normalModel\n * @param {module:echarts/model/Model} emphasisModel\n * @param {Object} opt Check `opt` of `setTextStyleCommon` to find other props.\n * @param {string|Function} [opt.defaultText]\n * @param {module:echarts/model/Model} [opt.labelFetcher] Fetch text by\n *      `opt.labelFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {module:echarts/model/Model} [opt.labelDataIndex] Fetch text by\n *      `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {module:echarts/model/Model} [opt.labelDimIndex] Fetch text by\n *      `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {Object} [normalSpecified]\n * @param {Object} [emphasisSpecified]\n */\nfunction setLabelStyle(\n    normalStyle, emphasisStyle,\n    normalModel, emphasisModel,\n    opt,\n    normalSpecified, emphasisSpecified\n) {\n    opt = opt || EMPTY_OBJ;\n    var labelFetcher = opt.labelFetcher;\n    var labelDataIndex = opt.labelDataIndex;\n    var labelDimIndex = opt.labelDimIndex;\n\n    // This scenario, `label.normal.show = true; label.emphasis.show = false`,\n    // is not supported util someone requests.\n\n    var showNormal = normalModel.getShallow('show');\n    var showEmphasis = emphasisModel.getShallow('show');\n\n    // Consider performance, only fetch label when necessary.\n    // If `normal.show` is `false` and `emphasis.show` is `true` and `emphasis.formatter` is not set,\n    // label should be displayed, where text is fetched by `normal.formatter` or `opt.defaultText`.\n    var baseText;\n    if (showNormal || showEmphasis) {\n        if (labelFetcher) {\n            baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex);\n        }\n        if (baseText == null) {\n            baseText = isFunction$1(opt.defaultText) ? opt.defaultText(labelDataIndex, opt) : opt.defaultText;\n        }\n    }\n    var normalStyleText = showNormal ? baseText : null;\n    var emphasisStyleText = showEmphasis\n        ? retrieve2(\n            labelFetcher\n                ? labelFetcher.getFormattedLabel(labelDataIndex, 'emphasis', null, labelDimIndex)\n                : null,\n            baseText\n        )\n        : null;\n\n    // Optimize: If style.text is null, text will not be drawn.\n    if (normalStyleText != null || emphasisStyleText != null) {\n        // Always set `textStyle` even if `normalStyle.text` is null, because default\n        // values have to be set on `normalStyle`.\n        // If we set default values on `emphasisStyle`, consider case:\n        // Firstly, `setOption(... label: {normal: {text: null}, emphasis: {show: true}} ...);`\n        // Secondly, `setOption(... label: {noraml: {show: true, text: 'abc', color: 'red'} ...);`\n        // Then the 'red' will not work on emphasis.\n        setTextStyle(normalStyle, normalModel, normalSpecified, opt);\n        setTextStyle(emphasisStyle, emphasisModel, emphasisSpecified, opt, true);\n    }\n\n    normalStyle.text = normalStyleText;\n    emphasisStyle.text = emphasisStyleText;\n}\n\n/**\n * Set basic textStyle properties.\n * See more info in `setTextStyleCommon`.\n * @param {Object|module:zrender/graphic/Style} textStyle\n * @param {module:echarts/model/Model} model\n * @param {Object} [specifiedTextStyle] Can be overrided by settings in model.\n * @param {Object} [opt] See `opt` of `setTextStyleCommon`.\n * @param {boolean} [isEmphasis]\n */\nfunction setTextStyle(\n    textStyle, textStyleModel, specifiedTextStyle, opt, isEmphasis\n) {\n    setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis);\n    specifiedTextStyle && extend(textStyle, specifiedTextStyle);\n    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);\n\n    return textStyle;\n}\n\n/**\n * Set text option in the style.\n * See more info in `setTextStyleCommon`.\n * @deprecated\n * @param {Object} textStyle\n * @param {module:echarts/model/Model} labelModel\n * @param {string|boolean} defaultColor Default text color.\n *        If set as false, it will be processed as a emphasis style.\n */\nfunction setText(textStyle, labelModel, defaultColor) {\n    var opt = {isRectText: true};\n    var isEmphasis;\n\n    if (defaultColor === false) {\n        isEmphasis = true;\n    }\n    else {\n        // Support setting color as 'auto' to get visual color.\n        opt.autoColor = defaultColor;\n    }\n    setTextStyleCommon(textStyle, labelModel, opt, isEmphasis);\n    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);\n}\n\n/**\n * The uniform entry of set text style, that is, retrieve style definitions\n * from `model` and set to `textStyle` object.\n *\n * Never in merge mode, but in overwrite mode, that is, all of the text style\n * properties will be set. (Consider the states of normal and emphasis and\n * default value can be adopted, merge would make the logic too complicated\n * to manage.)\n *\n * The `textStyle` object can either be a plain object or an instance of\n * `zrender/src/graphic/Style`, and either be the style of normal or emphasis.\n * After this mothod called, the `textStyle` object can then be used in\n * `el.setStyle(textStyle)` or `el.hoverStyle = textStyle`.\n *\n * Default value will be adopted and `insideRollbackOpt` will be created.\n * See `applyDefaultTextStyle` `rollbackDefaultTextStyle` for more details.\n *\n * opt: {\n *      disableBox: boolean, Whether diable drawing box of block (outer most).\n *      isRectText: boolean,\n *      autoColor: string, specify a color when color is 'auto',\n *              for textFill, textStroke, textBackgroundColor, and textBorderColor.\n *              If autoColor specified, it is used as default textFill.\n *      useInsideStyle:\n *              `true`: Use inside style (textFill, textStroke, textStrokeWidth)\n *                  if `textFill` is not specified.\n *              `false`: Do not use inside style.\n *              `null/undefined`: use inside style if `isRectText` is true and\n *                  `textFill` is not specified and textPosition contains `'inside'`.\n *      forceRich: boolean\n * }\n */\nfunction setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis) {\n    // Consider there will be abnormal when merge hover style to normal style if given default value.\n    opt = opt || EMPTY_OBJ;\n\n    if (opt.isRectText) {\n        var textPosition = textStyleModel.getShallow('position')\n            || (isEmphasis ? null : 'inside');\n        // 'outside' is not a valid zr textPostion value, but used\n        // in bar series, and magric type should be considered.\n        textPosition === 'outside' && (textPosition = 'top');\n        textStyle.textPosition = textPosition;\n        textStyle.textOffset = textStyleModel.getShallow('offset');\n        var labelRotate = textStyleModel.getShallow('rotate');\n        labelRotate != null && (labelRotate *= Math.PI / 180);\n        textStyle.textRotation = labelRotate;\n        textStyle.textDistance = retrieve2(\n            textStyleModel.getShallow('distance'), isEmphasis ? null : 5\n        );\n    }\n\n    var ecModel = textStyleModel.ecModel;\n    var globalTextStyle = ecModel && ecModel.option.textStyle;\n\n    // Consider case:\n    // {\n    //     data: [{\n    //         value: 12,\n    //         label: {\n    //             rich: {\n    //                 // no 'a' here but using parent 'a'.\n    //             }\n    //         }\n    //     }],\n    //     rich: {\n    //         a: { ... }\n    //     }\n    // }\n    var richItemNames = getRichItemNames(textStyleModel);\n    var richResult;\n    if (richItemNames) {\n        richResult = {};\n        for (var name in richItemNames) {\n            if (richItemNames.hasOwnProperty(name)) {\n                // Cascade is supported in rich.\n                var richTextStyle = textStyleModel.getModel(['rich', name]);\n                // In rich, never `disableBox`.\n                setTokenTextStyle(richResult[name] = {}, richTextStyle, globalTextStyle, opt, isEmphasis);\n            }\n        }\n    }\n    textStyle.rich = richResult;\n\n    setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, true);\n\n    if (opt.forceRich && !opt.textStyle) {\n        opt.textStyle = {};\n    }\n\n    return textStyle;\n}\n\n// Consider case:\n// {\n//     data: [{\n//         value: 12,\n//         label: {\n//             rich: {\n//                 // no 'a' here but using parent 'a'.\n//             }\n//         }\n//     }],\n//     rich: {\n//         a: { ... }\n//     }\n// }\nfunction getRichItemNames(textStyleModel) {\n    // Use object to remove duplicated names.\n    var richItemNameMap;\n    while (textStyleModel && textStyleModel !== textStyleModel.ecModel) {\n        var rich = (textStyleModel.option || EMPTY_OBJ).rich;\n        if (rich) {\n            richItemNameMap = richItemNameMap || {};\n            for (var name in rich) {\n                if (rich.hasOwnProperty(name)) {\n                    richItemNameMap[name] = 1;\n                }\n            }\n        }\n        textStyleModel = textStyleModel.parentModel;\n    }\n    return richItemNameMap;\n}\n\nfunction setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, isBlock) {\n    // In merge mode, default value should not be given.\n    globalTextStyle = !isEmphasis && globalTextStyle || EMPTY_OBJ;\n\n    textStyle.textFill = getAutoColor(textStyleModel.getShallow('color'), opt)\n        || globalTextStyle.color;\n    textStyle.textStroke = getAutoColor(textStyleModel.getShallow('textBorderColor'), opt)\n        || globalTextStyle.textBorderColor;\n    textStyle.textStrokeWidth = retrieve2(\n        textStyleModel.getShallow('textBorderWidth'),\n        globalTextStyle.textBorderWidth\n    );\n\n    // Save original textPosition, because style.textPosition will be repalced by\n    // real location (like [10, 30]) in zrender.\n    textStyle.insideRawTextPosition = textStyle.textPosition;\n\n    if (!isEmphasis) {\n        if (isBlock) {\n            textStyle.insideRollbackOpt = opt;\n            applyDefaultTextStyle(textStyle);\n        }\n\n        // Set default finally.\n        if (textStyle.textFill == null) {\n            textStyle.textFill = opt.autoColor;\n        }\n    }\n\n    // Do not use `getFont` here, because merge should be supported, where\n    // part of these properties may be changed in emphasis style, and the\n    // others should remain their original value got from normal style.\n    textStyle.fontStyle = textStyleModel.getShallow('fontStyle') || globalTextStyle.fontStyle;\n    textStyle.fontWeight = textStyleModel.getShallow('fontWeight') || globalTextStyle.fontWeight;\n    textStyle.fontSize = textStyleModel.getShallow('fontSize') || globalTextStyle.fontSize;\n    textStyle.fontFamily = textStyleModel.getShallow('fontFamily') || globalTextStyle.fontFamily;\n\n    textStyle.textAlign = textStyleModel.getShallow('align');\n    textStyle.textVerticalAlign = textStyleModel.getShallow('verticalAlign')\n        || textStyleModel.getShallow('baseline');\n\n    textStyle.textLineHeight = textStyleModel.getShallow('lineHeight');\n    textStyle.textWidth = textStyleModel.getShallow('width');\n    textStyle.textHeight = textStyleModel.getShallow('height');\n    textStyle.textTag = textStyleModel.getShallow('tag');\n\n    if (!isBlock || !opt.disableBox) {\n        textStyle.textBackgroundColor = getAutoColor(textStyleModel.getShallow('backgroundColor'), opt);\n        textStyle.textPadding = textStyleModel.getShallow('padding');\n        textStyle.textBorderColor = getAutoColor(textStyleModel.getShallow('borderColor'), opt);\n        textStyle.textBorderWidth = textStyleModel.getShallow('borderWidth');\n        textStyle.textBorderRadius = textStyleModel.getShallow('borderRadius');\n\n        textStyle.textBoxShadowColor = textStyleModel.getShallow('shadowColor');\n        textStyle.textBoxShadowBlur = textStyleModel.getShallow('shadowBlur');\n        textStyle.textBoxShadowOffsetX = textStyleModel.getShallow('shadowOffsetX');\n        textStyle.textBoxShadowOffsetY = textStyleModel.getShallow('shadowOffsetY');\n    }\n\n    textStyle.textShadowColor = textStyleModel.getShallow('textShadowColor')\n        || globalTextStyle.textShadowColor;\n    textStyle.textShadowBlur = textStyleModel.getShallow('textShadowBlur')\n        || globalTextStyle.textShadowBlur;\n    textStyle.textShadowOffsetX = textStyleModel.getShallow('textShadowOffsetX')\n        || globalTextStyle.textShadowOffsetX;\n    textStyle.textShadowOffsetY = textStyleModel.getShallow('textShadowOffsetY')\n        || globalTextStyle.textShadowOffsetY;\n}\n\nfunction getAutoColor(color, opt) {\n    return color !== 'auto' ? color : (opt && opt.autoColor) ? opt.autoColor : null;\n}\n\n/**\n * Give some default value to the input `textStyle` object, based on the current settings\n * in this `textStyle` object.\n *\n * The Scenario:\n * when text position is `inside` and `textFill` is not specified, we show\n * text border by default for better view. But it should be considered that text position\n * might be changed when hovering or being emphasis, where the `insideRollback` is used to\n * restore the style.\n *\n * Usage (& NOTICE):\n * When a style object (eithor plain object or instance of `zrender/src/graphic/Style`) is\n * about to be modified on its text related properties, `rollbackDefaultTextStyle` should\n * be called before the modification and `applyDefaultTextStyle` should be called after that.\n * (For the case that all of the text related properties is reset, like `setTextStyleCommon`\n * does, `rollbackDefaultTextStyle` is not needed to be called).\n */\nfunction applyDefaultTextStyle(textStyle) {\n    var opt = textStyle.insideRollbackOpt;\n\n    // Only `insideRollbackOpt` created (in `setTextStyleCommon`),\n    // applyDefaultTextStyle works.\n    if (!opt || textStyle.textFill != null) {\n        return;\n    }\n\n    var useInsideStyle = opt.useInsideStyle;\n    var textPosition = textStyle.insideRawTextPosition;\n    var insideRollback;\n    var autoColor = opt.autoColor;\n\n    if (useInsideStyle !== false\n        && (useInsideStyle === true\n            || (opt.isRectText\n                && textPosition\n                // textPosition can be [10, 30]\n                && typeof textPosition === 'string'\n                && textPosition.indexOf('inside') >= 0\n            )\n        )\n    ) {\n        insideRollback = {\n            textFill: null,\n            textStroke: textStyle.textStroke,\n            textStrokeWidth: textStyle.textStrokeWidth\n        };\n        textStyle.textFill = '#fff';\n        // Consider text with #fff overflow its container.\n        if (textStyle.textStroke == null) {\n            textStyle.textStroke = autoColor;\n            textStyle.textStrokeWidth == null && (textStyle.textStrokeWidth = 2);\n        }\n    }\n    else if (autoColor != null) {\n        insideRollback = {textFill: null};\n        textStyle.textFill = autoColor;\n    }\n\n    // Always set `insideRollback`, for clearing previous.\n    if (insideRollback) {\n        textStyle.insideRollback = insideRollback;\n    }\n}\n\n/**\n * Consider the case: in a scatter,\n * label: {\n *     normal: {position: 'inside'},\n *     emphasis: {position: 'top'}\n * }\n * In the normal state, the `textFill` will be set as '#fff' for pretty view (see\n * `applyDefaultTextStyle`), but when switching to emphasis state, the `textFill`\n * should be retured to 'autoColor', but not keep '#fff'.\n */\nfunction rollbackDefaultTextStyle(style) {\n    var insideRollback = style.insideRollback;\n    if (insideRollback) {\n        style.textFill = insideRollback.textFill;\n        style.textStroke = insideRollback.textStroke;\n        style.textStrokeWidth = insideRollback.textStrokeWidth;\n        style.insideRollback = null;\n    }\n}\n\nfunction getFont(opt, ecModel) {\n    // ecModel or default text style model.\n    var gTextStyleModel = ecModel || ecModel.getModel('textStyle');\n    return trim([\n        // FIXME in node-canvas fontWeight is before fontStyle\n        opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '',\n        opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '',\n        (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px',\n        opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'\n    ].join(' '));\n}\n\nfunction animateOrSetProps(isUpdate, el, props, animatableModel, dataIndex, cb) {\n    if (typeof dataIndex === 'function') {\n        cb = dataIndex;\n        dataIndex = null;\n    }\n    // Do not check 'animation' property directly here. Consider this case:\n    // animation model is an `itemModel`, whose does not have `isAnimationEnabled`\n    // but its parent model (`seriesModel`) does.\n    var animationEnabled = animatableModel && animatableModel.isAnimationEnabled();\n\n    if (animationEnabled) {\n        var postfix = isUpdate ? 'Update' : '';\n        var duration = animatableModel.getShallow('animationDuration' + postfix);\n        var animationEasing = animatableModel.getShallow('animationEasing' + postfix);\n        var animationDelay = animatableModel.getShallow('animationDelay' + postfix);\n        if (typeof animationDelay === 'function') {\n            animationDelay = animationDelay(\n                dataIndex,\n                animatableModel.getAnimationDelayParams\n                    ? animatableModel.getAnimationDelayParams(el, dataIndex)\n                    : null\n            );\n        }\n        if (typeof duration === 'function') {\n            duration = duration(dataIndex);\n        }\n\n        duration > 0\n            ? el.animateTo(props, duration, animationDelay || 0, animationEasing, cb, !!cb)\n            : (el.stopAnimation(), el.attr(props), cb && cb());\n    }\n    else {\n        el.stopAnimation();\n        el.attr(props);\n        cb && cb();\n    }\n}\n\n/**\n * Update graphic element properties with or without animation according to the\n * configuration in series.\n *\n * Caution: this method will stop previous animation.\n * So if do not use this method to one element twice before\n * animation starts, unless you know what you are doing.\n *\n * @param {module:zrender/Element} el\n * @param {Object} props\n * @param {module:echarts/model/Model} [animatableModel]\n * @param {number} [dataIndex]\n * @param {Function} [cb]\n * @example\n *     graphic.updateProps(el, {\n *         position: [100, 100]\n *     }, seriesModel, dataIndex, function () { console.log('Animation done!'); });\n *     // Or\n *     graphic.updateProps(el, {\n *         position: [100, 100]\n *     }, seriesModel, function () { console.log('Animation done!'); });\n */\nfunction updateProps(el, props, animatableModel, dataIndex, cb) {\n    animateOrSetProps(true, el, props, animatableModel, dataIndex, cb);\n}\n\n/**\n * Init graphic element properties with or without animation according to the\n * configuration in series.\n *\n * Caution: this method will stop previous animation.\n * So if do not use this method to one element twice before\n * animation starts, unless you know what you are doing.\n *\n * @param {module:zrender/Element} el\n * @param {Object} props\n * @param {module:echarts/model/Model} [animatableModel]\n * @param {number} [dataIndex]\n * @param {Function} cb\n */\nfunction initProps(el, props, animatableModel, dataIndex, cb) {\n    animateOrSetProps(false, el, props, animatableModel, dataIndex, cb);\n}\n\n/**\n * Get transform matrix of target (param target),\n * in coordinate of its ancestor (param ancestor)\n *\n * @param {module:zrender/mixin/Transformable} target\n * @param {module:zrender/mixin/Transformable} [ancestor]\n */\nfunction getTransform(target, ancestor) {\n    var mat = identity([]);\n\n    while (target && target !== ancestor) {\n        mul$1(mat, target.getLocalTransform(), mat);\n        target = target.parent;\n    }\n\n    return mat;\n}\n\n/**\n * Apply transform to an vertex.\n * @param {Array.<number>} target [x, y]\n * @param {Array.<number>|TypedArray.<number>|Object} transform Can be:\n *      + Transform matrix: like [1, 0, 0, 1, 0, 0]\n *      + {position, rotation, scale}, the same as `zrender/Transformable`.\n * @param {boolean=} invert Whether use invert matrix.\n * @return {Array.<number>} [x, y]\n */\nfunction applyTransform$1(target, transform, invert$$1) {\n    if (transform && !isArrayLike(transform)) {\n        transform = Transformable.getLocalTransform(transform);\n    }\n\n    if (invert$$1) {\n        transform = invert([], transform);\n    }\n    return applyTransform([], target, transform);\n}\n\n/**\n * @param {string} direction 'left' 'right' 'top' 'bottom'\n * @param {Array.<number>} transform Transform matrix: like [1, 0, 0, 1, 0, 0]\n * @param {boolean=} invert Whether use invert matrix.\n * @return {string} Transformed direction. 'left' 'right' 'top' 'bottom'\n */\nfunction transformDirection(direction, transform, invert$$1) {\n\n    // Pick a base, ensure that transform result will not be (0, 0).\n    var hBase = (transform[4] === 0 || transform[5] === 0 || transform[0] === 0)\n        ? 1 : Math.abs(2 * transform[4] / transform[0]);\n    var vBase = (transform[4] === 0 || transform[5] === 0 || transform[2] === 0)\n        ? 1 : Math.abs(2 * transform[4] / transform[2]);\n\n    var vertex = [\n        direction === 'left' ? -hBase : direction === 'right' ? hBase : 0,\n        direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0\n    ];\n\n    vertex = applyTransform$1(vertex, transform, invert$$1);\n\n    return Math.abs(vertex[0]) > Math.abs(vertex[1])\n        ? (vertex[0] > 0 ? 'right' : 'left')\n        : (vertex[1] > 0 ? 'bottom' : 'top');\n}\n\n/**\n * Apply group transition animation from g1 to g2.\n * If no animatableModel, no animation.\n */\nfunction groupTransition(g1, g2, animatableModel, cb) {\n    if (!g1 || !g2) {\n        return;\n    }\n\n    function getElMap(g) {\n        var elMap = {};\n        g.traverse(function (el) {\n            if (!el.isGroup && el.anid) {\n                elMap[el.anid] = el;\n            }\n        });\n        return elMap;\n    }\n    function getAnimatableProps(el) {\n        var obj = {\n            position: clone$1(el.position),\n            rotation: el.rotation\n        };\n        if (el.shape) {\n            obj.shape = extend({}, el.shape);\n        }\n        return obj;\n    }\n    var elMap1 = getElMap(g1);\n\n    g2.traverse(function (el) {\n        if (!el.isGroup && el.anid) {\n            var oldEl = elMap1[el.anid];\n            if (oldEl) {\n                var newProp = getAnimatableProps(el);\n                el.attr(getAnimatableProps(oldEl));\n                updateProps(el, newProp, animatableModel, el.dataIndex);\n            }\n            // else {\n            //     if (el.previousProps) {\n            //         graphic.updateProps\n            //     }\n            // }\n        }\n    });\n}\n\n/**\n * @param {Array.<Array.<number>>} points Like: [[23, 44], [53, 66], ...]\n * @param {Object} rect {x, y, width, height}\n * @return {Array.<Array.<number>>} A new clipped points.\n */\nfunction clipPointsByRect(points, rect) {\n    // FIXME: this way migth be incorrect when grpahic clipped by a corner.\n    // and when element have border.\n    return map(points, function (point) {\n        var x = point[0];\n        x = mathMax$1(x, rect.x);\n        x = mathMin$1(x, rect.x + rect.width);\n        var y = point[1];\n        y = mathMax$1(y, rect.y);\n        y = mathMin$1(y, rect.y + rect.height);\n        return [x, y];\n    });\n}\n\n/**\n * @param {Object} targetRect {x, y, width, height}\n * @param {Object} rect {x, y, width, height}\n * @return {Object} A new clipped rect. If rect size are negative, return undefined.\n */\nfunction clipRectByRect(targetRect, rect) {\n    var x = mathMax$1(targetRect.x, rect.x);\n    var x2 = mathMin$1(targetRect.x + targetRect.width, rect.x + rect.width);\n    var y = mathMax$1(targetRect.y, rect.y);\n    var y2 = mathMin$1(targetRect.y + targetRect.height, rect.y + rect.height);\n\n    // If the total rect is cliped, nothing, including the border,\n    // should be painted. So return undefined.\n    if (x2 >= x && y2 >= y) {\n        return {\n            x: x,\n            y: y,\n            width: x2 - x,\n            height: y2 - y\n        };\n    }\n}\n\n/**\n * @param {string} iconStr Support 'image://' or 'path://' or direct svg path.\n * @param {Object} [opt] Properties of `module:zrender/Element`, except `style`.\n * @param {Object} [rect] {x, y, width, height}\n * @return {module:zrender/Element} Icon path or image element.\n */\nfunction createIcon(iconStr, opt, rect) {\n    opt = extend({rectHover: true}, opt);\n    var style = opt.style = {strokeNoScale: true};\n    rect = rect || {x: -1, y: -1, width: 2, height: 2};\n\n    if (iconStr) {\n        return iconStr.indexOf('image://') === 0\n            ? (\n                style.image = iconStr.slice(8),\n                defaults(style, rect),\n                new ZImage(opt)\n            )\n            : (\n                makePath(\n                    iconStr.replace('path://', ''),\n                    opt,\n                    rect,\n                    'center'\n                )\n            );\n    }\n}\n\n\n\n\nvar graphic = (Object.freeze || Object)({\n\tZ2_EMPHASIS_LIFT: Z2_EMPHASIS_LIFT,\n\textendShape: extendShape,\n\textendPath: extendPath,\n\tmakePath: makePath,\n\tmakeImage: makeImage,\n\tmergePath: mergePath,\n\tresizePath: resizePath,\n\tsubPixelOptimizeLine: subPixelOptimizeLine,\n\tsubPixelOptimizeRect: subPixelOptimizeRect,\n\tsubPixelOptimize: subPixelOptimize,\n\tsetElementHoverStyle: setElementHoverStyle,\n\tisInEmphasis: isInEmphasis,\n\tsetHoverStyle: setHoverStyle,\n\tsetAsHoverStyleTrigger: setAsHoverStyleTrigger,\n\tsetLabelStyle: setLabelStyle,\n\tsetTextStyle: setTextStyle,\n\tsetText: setText,\n\tgetFont: getFont,\n\tupdateProps: updateProps,\n\tinitProps: initProps,\n\tgetTransform: getTransform,\n\tapplyTransform: applyTransform$1,\n\ttransformDirection: transformDirection,\n\tgroupTransition: groupTransition,\n\tclipPointsByRect: clipPointsByRect,\n\tclipRectByRect: clipRectByRect,\n\tcreateIcon: createIcon,\n\tGroup: Group,\n\tImage: ZImage,\n\tText: Text,\n\tCircle: Circle,\n\tSector: Sector,\n\tRing: Ring,\n\tPolygon: Polygon,\n\tPolyline: Polyline,\n\tRect: Rect,\n\tLine: Line,\n\tBezierCurve: BezierCurve,\n\tArc: Arc,\n\tIncrementalDisplayable: IncrementalDisplayble,\n\tCompoundPath: CompoundPath,\n\tLinearGradient: LinearGradient,\n\tRadialGradient: RadialGradient,\n\tBoundingRect: BoundingRect\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PATH_COLOR = ['textStyle', 'color'];\n\nvar textStyleMixin = {\n    /**\n     * Get color property or get color from option.textStyle.color\n     * @param {boolean} [isEmphasis]\n     * @return {string}\n     */\n    getTextColor: function (isEmphasis) {\n        var ecModel = this.ecModel;\n        return this.getShallow('color')\n            || (\n                (!isEmphasis && ecModel) ? ecModel.get(PATH_COLOR) : null\n            );\n    },\n\n    /**\n     * Create font string from fontStyle, fontWeight, fontSize, fontFamily\n     * @return {string}\n     */\n    getFont: function () {\n        return getFont({\n            fontStyle: this.getShallow('fontStyle'),\n            fontWeight: this.getShallow('fontWeight'),\n            fontSize: this.getShallow('fontSize'),\n            fontFamily: this.getShallow('fontFamily')\n        }, this.ecModel);\n    },\n\n    getTextRect: function (text) {\n        return getBoundingRect(\n            text,\n            this.getFont(),\n            this.getShallow('align'),\n            this.getShallow('verticalAlign') || this.getShallow('baseline'),\n            this.getShallow('padding'),\n            this.getShallow('lineHeight'),\n            this.getShallow('rich'),\n            this.getShallow('truncateText')\n        );\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getItemStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['stroke', 'borderColor'],\n        ['lineWidth', 'borderWidth'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor'],\n        ['textPosition'],\n        ['textAlign']\n    ]\n);\n\nvar itemStyleMixin = {\n    getItemStyle: function (excludes, includes) {\n        var style = getItemStyle(this, excludes, includes);\n        var lineDash = this.getBorderLineDash();\n        lineDash && (style.lineDash = lineDash);\n        return style;\n    },\n\n    getBorderLineDash: function () {\n        var lineType = this.get('borderType');\n        return (lineType === 'solid' || lineType == null) ? null\n            : (lineType === 'dashed' ? [5, 5] : [1, 1]);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/model/Model\n */\n\nvar mixin$1 = mixin;\nvar inner = makeInner();\n\n/**\n * @alias module:echarts/model/Model\n * @constructor\n * @param {Object} [option]\n * @param {module:echarts/model/Model} [parentModel]\n * @param {module:echarts/model/Global} [ecModel]\n */\nfunction Model(option, parentModel, ecModel) {\n    /**\n     * @type {module:echarts/model/Model}\n     * @readOnly\n     */\n    this.parentModel = parentModel;\n\n    /**\n     * @type {module:echarts/model/Global}\n     * @readOnly\n     */\n    this.ecModel = ecModel;\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    this.option = option;\n\n    // Simple optimization\n    // if (this.init) {\n    //     if (arguments.length <= 4) {\n    //         this.init(option, parentModel, ecModel, extraOpt);\n    //     }\n    //     else {\n    //         this.init.apply(this, arguments);\n    //     }\n    // }\n}\n\nModel.prototype = {\n\n    constructor: Model,\n\n    /**\n     * Model 的初始化函数\n     * @param {Object} option\n     */\n    init: null,\n\n    /**\n     * 从新的 Option merge\n     */\n    mergeOption: function (option) {\n        merge(this.option, option, true);\n    },\n\n    /**\n     * @param {string|Array.<string>} path\n     * @param {boolean} [ignoreParent=false]\n     * @return {*}\n     */\n    get: function (path, ignoreParent) {\n        if (path == null) {\n            return this.option;\n        }\n\n        return doGet(\n            this.option,\n            this.parsePath(path),\n            !ignoreParent && getParent(this, path)\n        );\n    },\n\n    /**\n     * @param {string} key\n     * @param {boolean} [ignoreParent=false]\n     * @return {*}\n     */\n    getShallow: function (key, ignoreParent) {\n        var option = this.option;\n\n        var val = option == null ? option : option[key];\n        var parentModel = !ignoreParent && getParent(this, key);\n        if (val == null && parentModel) {\n            val = parentModel.getShallow(key);\n        }\n        return val;\n    },\n\n    /**\n     * @param {string|Array.<string>} [path]\n     * @param {module:echarts/model/Model} [parentModel]\n     * @return {module:echarts/model/Model}\n     */\n    getModel: function (path, parentModel) {\n        var obj = path == null\n            ? this.option\n            : doGet(this.option, path = this.parsePath(path));\n\n        var thisParentModel;\n        parentModel = parentModel || (\n            (thisParentModel = getParent(this, path))\n                && thisParentModel.getModel(path)\n        );\n\n        return new Model(obj, parentModel, this.ecModel);\n    },\n\n    /**\n     * If model has option\n     */\n    isEmpty: function () {\n        return this.option == null;\n    },\n\n    restoreData: function () {},\n\n    // Pending\n    clone: function () {\n        var Ctor = this.constructor;\n        return new Ctor(clone(this.option));\n    },\n\n    setReadOnly: function (properties) {\n        // clazzUtil.setReadOnly(this, properties);\n    },\n\n    // If path is null/undefined, return null/undefined.\n    parsePath: function (path) {\n        if (typeof path === 'string') {\n            path = path.split('.');\n        }\n        return path;\n    },\n\n    /**\n     * @param {Function} getParentMethod\n     *        param {Array.<string>|string} path\n     *        return {module:echarts/model/Model}\n     */\n    customizeGetParent: function (getParentMethod) {\n        inner(this).getParent = getParentMethod;\n    },\n\n    isAnimationEnabled: function () {\n        if (!env$1.node) {\n            if (this.option.animation != null) {\n                return !!this.option.animation;\n            }\n            else if (this.parentModel) {\n                return this.parentModel.isAnimationEnabled();\n            }\n        }\n    }\n\n};\n\nfunction doGet(obj, pathArr, parentModel) {\n    for (var i = 0; i < pathArr.length; i++) {\n        // Ignore empty\n        if (!pathArr[i]) {\n            continue;\n        }\n        // obj could be number/string/... (like 0)\n        obj = (obj && typeof obj === 'object') ? obj[pathArr[i]] : null;\n        if (obj == null) {\n            break;\n        }\n    }\n    if (obj == null && parentModel) {\n        obj = parentModel.get(pathArr);\n    }\n    return obj;\n}\n\n// `path` can be null/undefined\nfunction getParent(model, path) {\n    var getParentMethod = inner(model).getParent;\n    return getParentMethod ? getParentMethod.call(model, path) : model.parentModel;\n}\n\n// Enable Model.extend.\nenableClassExtend(Model);\nenableClassCheck(Model);\n\nmixin$1(Model, lineStyleMixin);\nmixin$1(Model, areaStyleMixin);\nmixin$1(Model, textStyleMixin);\nmixin$1(Model, itemStyleMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar base = 0;\n\n/**\n * @public\n * @param {string} type\n * @return {string}\n */\nfunction getUID(type) {\n    // Considering the case of crossing js context,\n    // use Math.random to make id as unique as possible.\n    return [(type || ''), base++, Math.random().toFixed(5)].join('_');\n}\n\n/**\n * @inner\n */\nfunction enableSubTypeDefaulter(entity) {\n\n    var subTypeDefaulters = {};\n\n    entity.registerSubTypeDefaulter = function (componentType, defaulter) {\n        componentType = parseClassType$1(componentType);\n        subTypeDefaulters[componentType.main] = defaulter;\n    };\n\n    entity.determineSubType = function (componentType, option) {\n        var type = option.type;\n        if (!type) {\n            var componentTypeMain = parseClassType$1(componentType).main;\n            if (entity.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) {\n                type = subTypeDefaulters[componentTypeMain](option);\n            }\n        }\n        return type;\n    };\n\n    return entity;\n}\n\n/**\n * Topological travel on Activity Network (Activity On Vertices).\n * Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis'].\n *\n * If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology.\n *\n * If there is circle dependencey, Error will be thrown.\n *\n */\nfunction enableTopologicalTravel(entity, dependencyGetter) {\n\n    /**\n     * @public\n     * @param {Array.<string>} targetNameList Target Component type list.\n     *                                           Can be ['aa', 'bb', 'aa.xx']\n     * @param {Array.<string>} fullNameList By which we can build dependency graph.\n     * @param {Function} callback Params: componentType, dependencies.\n     * @param {Object} context Scope of callback.\n     */\n    entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) {\n        if (!targetNameList.length) {\n            return;\n        }\n\n        var result = makeDepndencyGraph(fullNameList);\n        var graph = result.graph;\n        var stack = result.noEntryList;\n\n        var targetNameSet = {};\n        each$1(targetNameList, function (name) {\n            targetNameSet[name] = true;\n        });\n\n        while (stack.length) {\n            var currComponentType = stack.pop();\n            var currVertex = graph[currComponentType];\n            var isInTargetNameSet = !!targetNameSet[currComponentType];\n            if (isInTargetNameSet) {\n                callback.call(context, currComponentType, currVertex.originalDeps.slice());\n                delete targetNameSet[currComponentType];\n            }\n            each$1(\n                currVertex.successor,\n                isInTargetNameSet ? removeEdgeAndAdd : removeEdge\n            );\n        }\n\n        each$1(targetNameSet, function () {\n            throw new Error('Circle dependency may exists');\n        });\n\n        function removeEdge(succComponentType) {\n            graph[succComponentType].entryCount--;\n            if (graph[succComponentType].entryCount === 0) {\n                stack.push(succComponentType);\n            }\n        }\n\n        // Consider this case: legend depends on series, and we call\n        // chart.setOption({series: [...]}), where only series is in option.\n        // If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will\n        // not be called, but only sereis.mergeOption is called. Thus legend\n        // have no chance to update its local record about series (like which\n        // name of series is available in legend).\n        function removeEdgeAndAdd(succComponentType) {\n            targetNameSet[succComponentType] = true;\n            removeEdge(succComponentType);\n        }\n    };\n\n    /**\n     * DepndencyGraph: {Object}\n     * key: conponentType,\n     * value: {\n     *     successor: [conponentTypes...],\n     *     originalDeps: [conponentTypes...],\n     *     entryCount: {number}\n     * }\n     */\n    function makeDepndencyGraph(fullNameList) {\n        var graph = {};\n        var noEntryList = [];\n\n        each$1(fullNameList, function (name) {\n\n            var thisItem = createDependencyGraphItem(graph, name);\n            var originalDeps = thisItem.originalDeps = dependencyGetter(name);\n\n            var availableDeps = getAvailableDependencies(originalDeps, fullNameList);\n            thisItem.entryCount = availableDeps.length;\n            if (thisItem.entryCount === 0) {\n                noEntryList.push(name);\n            }\n\n            each$1(availableDeps, function (dependentName) {\n                if (indexOf(thisItem.predecessor, dependentName) < 0) {\n                    thisItem.predecessor.push(dependentName);\n                }\n                var thatItem = createDependencyGraphItem(graph, dependentName);\n                if (indexOf(thatItem.successor, dependentName) < 0) {\n                    thatItem.successor.push(name);\n                }\n            });\n        });\n\n        return {graph: graph, noEntryList: noEntryList};\n    }\n\n    function createDependencyGraphItem(graph, name) {\n        if (!graph[name]) {\n            graph[name] = {predecessor: [], successor: []};\n        }\n        return graph[name];\n    }\n\n    function getAvailableDependencies(originalDeps, fullNameList) {\n        var availableDeps = [];\n        each$1(originalDeps, function (dep) {\n            indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep);\n        });\n        return availableDeps;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The method \"quantile\" was copied from \"d3.js\".\n* (See more details in the comment of the method below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\nvar RADIAN_EPSILON = 1e-4;\n\nfunction _trim(str) {\n    return str.replace(/^\\s+/, '').replace(/\\s+$/, '');\n}\n\n/**\n * Linear mapping a value from domain to range\n * @memberOf module:echarts/util/number\n * @param  {(number|Array.<number>)} val\n * @param  {Array.<number>} domain Domain extent domain[0] can be bigger than domain[1]\n * @param  {Array.<number>} range  Range extent range[0] can be bigger than range[1]\n * @param  {boolean} clamp\n * @return {(number|Array.<number>}\n */\nfunction linearMap(val, domain, range, clamp) {\n    var subDomain = domain[1] - domain[0];\n    var subRange = range[1] - range[0];\n\n    if (subDomain === 0) {\n        return subRange === 0\n            ? range[0]\n            : (range[0] + range[1]) / 2;\n    }\n\n    // Avoid accuracy problem in edge, such as\n    // 146.39 - 62.83 === 83.55999999999999.\n    // See echarts/test/ut/spec/util/number.js#linearMap#accuracyError\n    // It is a little verbose for efficiency considering this method\n    // is a hotspot.\n    if (clamp) {\n        if (subDomain > 0) {\n            if (val <= domain[0]) {\n                return range[0];\n            }\n            else if (val >= domain[1]) {\n                return range[1];\n            }\n        }\n        else {\n            if (val >= domain[0]) {\n                return range[0];\n            }\n            else if (val <= domain[1]) {\n                return range[1];\n            }\n        }\n    }\n    else {\n        if (val === domain[0]) {\n            return range[0];\n        }\n        if (val === domain[1]) {\n            return range[1];\n        }\n    }\n\n    return (val - domain[0]) / subDomain * subRange + range[0];\n}\n\n/**\n * Convert a percent string to absolute number.\n * Returns NaN if percent is not a valid string or number\n * @memberOf module:echarts/util/number\n * @param {string|number} percent\n * @param {number} all\n * @return {number}\n */\nfunction parsePercent$1(percent, all) {\n    switch (percent) {\n        case 'center':\n        case 'middle':\n            percent = '50%';\n            break;\n        case 'left':\n        case 'top':\n            percent = '0%';\n            break;\n        case 'right':\n        case 'bottom':\n            percent = '100%';\n            break;\n    }\n    if (typeof percent === 'string') {\n        if (_trim(percent).match(/%$/)) {\n            return parseFloat(percent) / 100 * all;\n        }\n\n        return parseFloat(percent);\n    }\n\n    return percent == null ? NaN : +percent;\n}\n\n/**\n * (1) Fix rounding error of float numbers.\n * (2) Support return string to avoid scientific notation like '3.5e-7'.\n *\n * @param {number} x\n * @param {number} [precision]\n * @param {boolean} [returnStr]\n * @return {number|string}\n */\nfunction round$2(x, precision, returnStr) {\n    if (precision == null) {\n        precision = 10;\n    }\n    // Avoid range error\n    precision = Math.min(Math.max(0, precision), 20);\n    x = (+x).toFixed(precision);\n    return returnStr ? x : +x;\n}\n\nfunction asc(arr) {\n    arr.sort(function (a, b) {\n        return a - b;\n    });\n    return arr;\n}\n\n/**\n * Get precision\n * @param {number} val\n */\nfunction getPrecision(val) {\n    val = +val;\n    if (isNaN(val)) {\n        return 0;\n    }\n    // It is much faster than methods converting number to string as follows\n    //      var tmp = val.toString();\n    //      return tmp.length - 1 - tmp.indexOf('.');\n    // especially when precision is low\n    var e = 1;\n    var count = 0;\n    while (Math.round(val * e) / e !== val) {\n        e *= 10;\n        count++;\n    }\n    return count;\n}\n\n/**\n * @param {string|number} val\n * @return {number}\n */\nfunction getPrecisionSafe(val) {\n    var str = val.toString();\n\n    // Consider scientific notation: '3.4e-12' '3.4e+12'\n    var eIndex = str.indexOf('e');\n    if (eIndex > 0) {\n        var precision = +str.slice(eIndex + 1);\n        return precision < 0 ? -precision : 0;\n    }\n    else {\n        var dotIndex = str.indexOf('.');\n        return dotIndex < 0 ? 0 : str.length - 1 - dotIndex;\n    }\n}\n\n/**\n * Minimal dicernible data precisioin according to a single pixel.\n *\n * @param {Array.<number>} dataExtent\n * @param {Array.<number>} pixelExtent\n * @return {number} precision\n */\nfunction getPixelPrecision(dataExtent, pixelExtent) {\n    var log = Math.log;\n    var LN10 = Math.LN10;\n    var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10);\n    var sizeQuantity = Math.round(log(Math.abs(pixelExtent[1] - pixelExtent[0])) / LN10);\n    // toFixed() digits argument must be between 0 and 20.\n    var precision = Math.min(Math.max(-dataQuantity + sizeQuantity, 0), 20);\n    return !isFinite(precision) ? 20 : precision;\n}\n\n/**\n * Get a data of given precision, assuring the sum of percentages\n * in valueList is 1.\n * The largest remainer method is used.\n * https://en.wikipedia.org/wiki/Largest_remainder_method\n *\n * @param {Array.<number>} valueList a list of all data\n * @param {number} idx index of the data to be processed in valueList\n * @param {number} precision integer number showing digits of precision\n * @return {number} percent ranging from 0 to 100\n */\nfunction getPercentWithPrecision(valueList, idx, precision) {\n    if (!valueList[idx]) {\n        return 0;\n    }\n\n    var sum = reduce(valueList, function (acc, val) {\n        return acc + (isNaN(val) ? 0 : val);\n    }, 0);\n    if (sum === 0) {\n        return 0;\n    }\n\n    var digits = Math.pow(10, precision);\n    var votesPerQuota = map(valueList, function (val) {\n        return (isNaN(val) ? 0 : val) / sum * digits * 100;\n    });\n    var targetSeats = digits * 100;\n\n    var seats = map(votesPerQuota, function (votes) {\n        // Assign automatic seats.\n        return Math.floor(votes);\n    });\n    var currentSum = reduce(seats, function (acc, val) {\n        return acc + val;\n    }, 0);\n\n    var remainder = map(votesPerQuota, function (votes, idx) {\n        return votes - seats[idx];\n    });\n\n    // Has remainding votes.\n    while (currentSum < targetSeats) {\n        // Find next largest remainder.\n        var max = Number.NEGATIVE_INFINITY;\n        var maxId = null;\n        for (var i = 0, len = remainder.length; i < len; ++i) {\n            if (remainder[i] > max) {\n                max = remainder[i];\n                maxId = i;\n            }\n        }\n\n        // Add a vote to max remainder.\n        ++seats[maxId];\n        remainder[maxId] = 0;\n        ++currentSum;\n    }\n\n    return seats[idx] / digits;\n}\n\n// Number.MAX_SAFE_INTEGER, ie do not support.\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * To 0 - 2 * PI, considering negative radian.\n * @param {number} radian\n * @return {number}\n */\nfunction remRadian(radian) {\n    var pi2 = Math.PI * 2;\n    return (radian % pi2 + pi2) % pi2;\n}\n\n/**\n * @param {type} radian\n * @return {boolean}\n */\nfunction isRadianAroundZero(val) {\n    return val > -RADIAN_EPSILON && val < RADIAN_EPSILON;\n}\n\n/* eslint-disable */\nvar TIME_REG = /^(?:(\\d{4})(?:[-\\/](\\d{1,2})(?:[-\\/](\\d{1,2})(?:[T ](\\d{1,2})(?::(\\d\\d)(?::(\\d\\d)(?:[.,](\\d+))?)?)?(Z|[\\+\\-]\\d\\d:?\\d\\d)?)?)?)?)?$/; // jshint ignore:line\n/* eslint-enable */\n\n/**\n * @param {string|Date|number} value These values can be accepted:\n *   + An instance of Date, represent a time in its own time zone.\n *   + Or string in a subset of ISO 8601, only including:\n *     + only year, month, date: '2012-03', '2012-03-01', '2012-03-01 05', '2012-03-01 05:06',\n *     + separated with T or space: '2012-03-01T12:22:33.123', '2012-03-01 12:22:33.123',\n *     + time zone: '2012-03-01T12:22:33Z', '2012-03-01T12:22:33+8000', '2012-03-01T12:22:33-05:00',\n *     all of which will be treated as local time if time zone is not specified\n *     (see <https://momentjs.com/>).\n *   + Or other string format, including (all of which will be treated as loacal time):\n *     '2012', '2012-3-1', '2012/3/1', '2012/03/01',\n *     '2009/6/12 2:00', '2009/6/12 2:05:08', '2009/6/12 2:05:08.123'\n *   + a timestamp, which represent a time in UTC.\n * @return {Date} date\n */\nfunction parseDate(value) {\n    if (value instanceof Date) {\n        return value;\n    }\n    else if (typeof value === 'string') {\n        // Different browsers parse date in different way, so we parse it manually.\n        // Some other issues:\n        // new Date('1970-01-01') is UTC,\n        // new Date('1970/01/01') and new Date('1970-1-01') is local.\n        // See issue #3623\n        var match = TIME_REG.exec(value);\n\n        if (!match) {\n            // return Invalid Date.\n            return new Date(NaN);\n        }\n\n        // Use local time when no timezone offset specifed.\n        if (!match[8]) {\n            // match[n] can only be string or undefined.\n            // But take care of '12' + 1 => '121'.\n            return new Date(\n                +match[1],\n                +(match[2] || 1) - 1,\n                +match[3] || 1,\n                +match[4] || 0,\n                +(match[5] || 0),\n                +match[6] || 0,\n                +match[7] || 0\n            );\n        }\n        // Timezoneoffset of Javascript Date has considered DST (Daylight Saving Time,\n        // https://tc39.github.io/ecma262/#sec-daylight-saving-time-adjustment).\n        // For example, system timezone is set as \"Time Zone: America/Toronto\",\n        // then these code will get different result:\n        // `new Date(1478411999999).getTimezoneOffset();  // get 240`\n        // `new Date(1478412000000).getTimezoneOffset();  // get 300`\n        // So we should not use `new Date`, but use `Date.UTC`.\n        else {\n            var hour = +match[4] || 0;\n            if (match[8].toUpperCase() !== 'Z') {\n                hour -= match[8].slice(0, 3);\n            }\n            return new Date(Date.UTC(\n                +match[1],\n                +(match[2] || 1) - 1,\n                +match[3] || 1,\n                hour,\n                +(match[5] || 0),\n                +match[6] || 0,\n                +match[7] || 0\n            ));\n        }\n    }\n    else if (value == null) {\n        return new Date(NaN);\n    }\n\n    return new Date(Math.round(value));\n}\n\n/**\n * Quantity of a number. e.g. 0.1, 1, 10, 100\n *\n * @param  {number} val\n * @return {number}\n */\nfunction quantity(val) {\n    return Math.pow(10, quantityExponent(val));\n}\n\nfunction quantityExponent(val) {\n    return Math.floor(Math.log(val) / Math.LN10);\n}\n\n/**\n * find a “nice” number approximately equal to x. Round the number if round = true,\n * take ceiling if round = false. The primary observation is that the “nicest”\n * numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers.\n *\n * See \"Nice Numbers for Graph Labels\" of Graphic Gems.\n *\n * @param  {number} val Non-negative value.\n * @param  {boolean} round\n * @return {number}\n */\nfunction nice(val, round) {\n    var exponent = quantityExponent(val);\n    var exp10 = Math.pow(10, exponent);\n    var f = val / exp10; // 1 <= f < 10\n    var nf;\n    if (round) {\n        if (f < 1.5) {\n            nf = 1;\n        }\n        else if (f < 2.5) {\n            nf = 2;\n        }\n        else if (f < 4) {\n            nf = 3;\n        }\n        else if (f < 7) {\n            nf = 5;\n        }\n        else {\n            nf = 10;\n        }\n    }\n    else {\n        if (f < 1) {\n            nf = 1;\n        }\n        else if (f < 2) {\n            nf = 2;\n        }\n        else if (f < 3) {\n            nf = 3;\n        }\n        else if (f < 5) {\n            nf = 5;\n        }\n        else {\n            nf = 10;\n        }\n    }\n    val = nf * exp10;\n\n    // Fix 3 * 0.1 === 0.30000000000000004 issue (see IEEE 754).\n    // 20 is the uppper bound of toFixed.\n    return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val;\n}\n\n/**\n * This code was copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/9cc9a875e636a1dcf36cc1e07bdf77e1ad6e2c74/src/arrays/quantile.js>.\n * See the license statement at the head of this file.\n * @param {Array.<number>} ascArr\n */\nfunction quantile(ascArr, p) {\n    var H = (ascArr.length - 1) * p + 1;\n    var h = Math.floor(H);\n    var v = +ascArr[h - 1];\n    var e = H - h;\n    return e ? v + e * (ascArr[h] - v) : v;\n}\n\n/**\n * Order intervals asc, and split them when overlap.\n * expect(numberUtil.reformIntervals([\n *     {interval: [18, 62], close: [1, 1]},\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [1, 1]},\n *     {interval: [62, 150], close: [1, 1]},\n *     {interval: [106, 150], close: [1, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ])).toEqual([\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [0, 1]},\n *     {interval: [18, 62], close: [0, 1]},\n *     {interval: [62, 150], close: [0, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ]);\n * @param {Array.<Object>} list, where `close` mean open or close\n *        of the interval, and Infinity can be used.\n * @return {Array.<Object>} The origin list, which has been reformed.\n */\nfunction reformIntervals(list) {\n    list.sort(function (a, b) {\n        return littleThan(a, b, 0) ? -1 : 1;\n    });\n\n    var curr = -Infinity;\n    var currClose = 1;\n    for (var i = 0; i < list.length;) {\n        var interval = list[i].interval;\n        var close = list[i].close;\n\n        for (var lg = 0; lg < 2; lg++) {\n            if (interval[lg] <= curr) {\n                interval[lg] = curr;\n                close[lg] = !lg ? 1 - currClose : 1;\n            }\n            curr = interval[lg];\n            currClose = close[lg];\n        }\n\n        if (interval[0] === interval[1] && close[0] * close[1] !== 1) {\n            list.splice(i, 1);\n        }\n        else {\n            i++;\n        }\n    }\n\n    return list;\n\n    function littleThan(a, b, lg) {\n        return a.interval[lg] < b.interval[lg]\n            || (\n                a.interval[lg] === b.interval[lg]\n                && (\n                    (a.close[lg] - b.close[lg] === (!lg ? 1 : -1))\n                    || (!lg && littleThan(a, b, 1))\n                )\n            );\n    }\n}\n\n/**\n * parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n * ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n * subtraction forces infinities to NaN\n *\n * @param {*} v\n * @return {boolean}\n */\nfunction isNumeric(v) {\n    return v - parseFloat(v) >= 0;\n}\n\n\nvar number = (Object.freeze || Object)({\n\tlinearMap: linearMap,\n\tparsePercent: parsePercent$1,\n\tround: round$2,\n\tasc: asc,\n\tgetPrecision: getPrecision,\n\tgetPrecisionSafe: getPrecisionSafe,\n\tgetPixelPrecision: getPixelPrecision,\n\tgetPercentWithPrecision: getPercentWithPrecision,\n\tMAX_SAFE_INTEGER: MAX_SAFE_INTEGER,\n\tremRadian: remRadian,\n\tisRadianAroundZero: isRadianAroundZero,\n\tparseDate: parseDate,\n\tquantity: quantity,\n\tnice: nice,\n\tquantile: quantile,\n\treformIntervals: reformIntervals,\n\tisNumeric: isNumeric\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import Text from 'zrender/src/graphic/Text';\n\n/**\n * 每三位默认加,格式化\n * @param {string|number} x\n * @return {string}\n */\nfunction addCommas(x) {\n    if (isNaN(x)) {\n        return '-';\n    }\n    x = (x + '').split('.');\n    return x[0].replace(/(\\d{1,3})(?=(?:\\d{3})+(?!\\d))/g, '$1,')\n            + (x.length > 1 ? ('.' + x[1]) : '');\n}\n\n/**\n * @param {string} str\n * @param {boolean} [upperCaseFirst=false]\n * @return {string} str\n */\nfunction toCamelCase(str, upperCaseFirst) {\n    str = (str || '').toLowerCase().replace(/-(.)/g, function (match, group1) {\n        return group1.toUpperCase();\n    });\n\n    if (upperCaseFirst && str) {\n        str = str.charAt(0).toUpperCase() + str.slice(1);\n    }\n\n    return str;\n}\n\nvar normalizeCssArray$1 = normalizeCssArray;\n\n\nvar replaceReg = /([&<>\"'])/g;\nvar replaceMap = {\n    '&': '&amp;',\n    '<': '&lt;',\n    '>': '&gt;',\n    '\"': '&quot;',\n    '\\'': '&#39;'\n};\n\nfunction encodeHTML(source) {\n    return source == null\n        ? ''\n        : (source + '').replace(replaceReg, function (str, c) {\n            return replaceMap[c];\n        });\n}\n\nvar TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];\n\nvar wrapVar = function (varName, seriesIdx) {\n    return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}';\n};\n\n/**\n * Template formatter\n * @param {string} tpl\n * @param {Array.<Object>|Object} paramsList\n * @param {boolean} [encode=false]\n * @return {string}\n */\nfunction formatTpl(tpl, paramsList, encode) {\n    if (!isArray(paramsList)) {\n        paramsList = [paramsList];\n    }\n    var seriesLen = paramsList.length;\n    if (!seriesLen) {\n        return '';\n    }\n\n    var $vars = paramsList[0].$vars || [];\n    for (var i = 0; i < $vars.length; i++) {\n        var alias = TPL_VAR_ALIAS[i];\n        tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0));\n    }\n    for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) {\n        for (var k = 0; k < $vars.length; k++) {\n            var val = paramsList[seriesIdx][$vars[k]];\n            tpl = tpl.replace(\n                wrapVar(TPL_VAR_ALIAS[k], seriesIdx),\n                encode ? encodeHTML(val) : val\n            );\n        }\n    }\n\n    return tpl;\n}\n\n/**\n * simple Template formatter\n *\n * @param {string} tpl\n * @param {Object} param\n * @param {boolean} [encode=false]\n * @return {string}\n */\nfunction formatTplSimple(tpl, param, encode) {\n    each$1(param, function (value, key) {\n        tpl = tpl.replace(\n            '{' + key + '}',\n            encode ? encodeHTML(value) : value\n        );\n    });\n    return tpl;\n}\n\n/**\n * @param {Object|string} [opt] If string, means color.\n * @param {string} [opt.color]\n * @param {string} [opt.extraCssText]\n * @param {string} [opt.type='item'] 'item' or 'subItem'\n * @param {string} [opt.renderMode='html'] render mode of tooltip, 'html' or 'richText'\n * @param {string} [opt.markerId='X'] id name for marker. If only one marker is in a rich text, this can be omitted.\n * @return {string}\n */\nfunction getTooltipMarker(opt, extraCssText) {\n    opt = isString(opt) ? {color: opt, extraCssText: extraCssText} : (opt || {});\n    var color = opt.color;\n    var type = opt.type;\n    var extraCssText = opt.extraCssText;\n    var renderMode = opt.renderMode || 'html';\n    var markerId = opt.markerId || 'X';\n\n    if (!color) {\n        return '';\n    }\n\n    if (renderMode === 'html') {\n        return type === 'subItem'\n        ? '<span style=\"display:inline-block;vertical-align:middle;margin-right:8px;margin-left:3px;'\n            + 'border-radius:4px;width:4px;height:4px;background-color:'\n            + encodeHTML(color) + ';' + (extraCssText || '') + '\"></span>'\n        : '<span style=\"display:inline-block;margin-right:5px;'\n            + 'border-radius:10px;width:10px;height:10px;background-color:'\n            + encodeHTML(color) + ';' + (extraCssText || '') + '\"></span>';\n    }\n    else {\n        // Space for rich element marker\n        return {\n            renderMode: renderMode,\n            content: '{marker' + markerId + '|}  ',\n            style: {\n                color: color\n            }\n        };\n    }\n}\n\nfunction pad(str, len) {\n    str += '';\n    return '0000'.substr(0, len - str.length) + str;\n}\n\n\n/**\n * ISO Date format\n * @param {string} tpl\n * @param {number} value\n * @param {boolean} [isUTC=false] Default in local time.\n *           see `module:echarts/scale/Time`\n *           and `module:echarts/util/number#parseDate`.\n * @inner\n */\nfunction formatTime(tpl, value, isUTC) {\n    if (tpl === 'week'\n        || tpl === 'month'\n        || tpl === 'quarter'\n        || tpl === 'half-year'\n        || tpl === 'year'\n    ) {\n        tpl = 'MM-dd\\nyyyy';\n    }\n\n    var date = parseDate(value);\n    var utc = isUTC ? 'UTC' : '';\n    var y = date['get' + utc + 'FullYear']();\n    var M = date['get' + utc + 'Month']() + 1;\n    var d = date['get' + utc + 'Date']();\n    var h = date['get' + utc + 'Hours']();\n    var m = date['get' + utc + 'Minutes']();\n    var s = date['get' + utc + 'Seconds']();\n    var S = date['get' + utc + 'Milliseconds']();\n\n    tpl = tpl.replace('MM', pad(M, 2))\n        .replace('M', M)\n        .replace('yyyy', y)\n        .replace('yy', y % 100)\n        .replace('dd', pad(d, 2))\n        .replace('d', d)\n        .replace('hh', pad(h, 2))\n        .replace('h', h)\n        .replace('mm', pad(m, 2))\n        .replace('m', m)\n        .replace('ss', pad(s, 2))\n        .replace('s', s)\n        .replace('SSS', pad(S, 3));\n\n    return tpl;\n}\n\n/**\n * Capital first\n * @param {string} str\n * @return {string}\n */\nfunction capitalFirst(str) {\n    return str ? str.charAt(0).toUpperCase() + str.substr(1) : str;\n}\n\nvar truncateText$1 = truncateText;\n\n/**\n * @public\n * @param {Object} opt\n * @param {string} opt.text\n * @param {string} opt.font\n * @param {string} [opt.textAlign='left']\n * @param {string} [opt.textVerticalAlign='top']\n * @param {Array.<number>} [opt.textPadding]\n * @param {number} [opt.textLineHeight]\n * @param {Object} [opt.rich]\n * @param {Object} [opt.truncate]\n * @return {Object} {x, y, width, height, lineHeight}\n */\nfunction getTextBoundingRect(opt) {\n    return getBoundingRect(\n        opt.text,\n        opt.font,\n        opt.textAlign,\n        opt.textVerticalAlign,\n        opt.textPadding,\n        opt.textLineHeight,\n        opt.rich,\n        opt.truncate\n    );\n}\n\n/**\n * @deprecated\n * the `textLineHeight` was added later.\n * For backward compatiblility, put it as the last parameter.\n * But deprecated this interface. Please use `getTextBoundingRect` instead.\n */\nfunction getTextRect(\n    text, font, textAlign, textVerticalAlign, textPadding, rich, truncate, textLineHeight\n) {\n    return getBoundingRect(\n        text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate\n    );\n}\n\n\nvar format = (Object.freeze || Object)({\n\taddCommas: addCommas,\n\ttoCamelCase: toCamelCase,\n\tnormalizeCssArray: normalizeCssArray$1,\n\tencodeHTML: encodeHTML,\n\tformatTpl: formatTpl,\n\tformatTplSimple: formatTplSimple,\n\tgetTooltipMarker: getTooltipMarker,\n\tformatTime: formatTime,\n\tcapitalFirst: capitalFirst,\n\ttruncateText: truncateText$1,\n\tgetTextBoundingRect: getTextBoundingRect,\n\tgetTextRect: getTextRect\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Layout helpers for each component positioning\n\nvar each$3 = each$1;\n\n/**\n * @public\n */\nvar LOCATION_PARAMS = [\n    'left', 'right', 'top', 'bottom', 'width', 'height'\n];\n\n/**\n * @public\n */\nvar HV_NAMES = [\n    ['width', 'left', 'right'],\n    ['height', 'top', 'bottom']\n];\n\nfunction boxLayout(orient, group, gap, maxWidth, maxHeight) {\n    var x = 0;\n    var y = 0;\n\n    if (maxWidth == null) {\n        maxWidth = Infinity;\n    }\n    if (maxHeight == null) {\n        maxHeight = Infinity;\n    }\n    var currentLineMaxSize = 0;\n\n    group.eachChild(function (child, idx) {\n        var position = child.position;\n        var rect = child.getBoundingRect();\n        var nextChild = group.childAt(idx + 1);\n        var nextChildRect = nextChild && nextChild.getBoundingRect();\n        var nextX;\n        var nextY;\n\n        if (orient === 'horizontal') {\n            var moveX = rect.width + (nextChildRect ? (-nextChildRect.x + rect.x) : 0);\n            nextX = x + moveX;\n            // Wrap when width exceeds maxWidth or meet a `newline` group\n            // FIXME compare before adding gap?\n            if (nextX > maxWidth || child.newline) {\n                x = 0;\n                nextX = moveX;\n                y += currentLineMaxSize + gap;\n                currentLineMaxSize = rect.height;\n            }\n            else {\n                // FIXME: consider rect.y is not `0`?\n                currentLineMaxSize = Math.max(currentLineMaxSize, rect.height);\n            }\n        }\n        else {\n            var moveY = rect.height + (nextChildRect ? (-nextChildRect.y + rect.y) : 0);\n            nextY = y + moveY;\n            // Wrap when width exceeds maxHeight or meet a `newline` group\n            if (nextY > maxHeight || child.newline) {\n                x += currentLineMaxSize + gap;\n                y = 0;\n                nextY = moveY;\n                currentLineMaxSize = rect.width;\n            }\n            else {\n                currentLineMaxSize = Math.max(currentLineMaxSize, rect.width);\n            }\n        }\n\n        if (child.newline) {\n            return;\n        }\n\n        position[0] = x;\n        position[1] = y;\n\n        orient === 'horizontal'\n            ? (x = nextX + gap)\n            : (y = nextY + gap);\n    });\n}\n\n/**\n * VBox or HBox layouting\n * @param {string} orient\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar box = boxLayout;\n\n/**\n * VBox layouting\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar vbox = curry(boxLayout, 'vertical');\n\n/**\n * HBox layouting\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar hbox = curry(boxLayout, 'horizontal');\n\n/**\n * If x or x2 is not specified or 'center' 'left' 'right',\n * the width would be as long as possible.\n * If y or y2 is not specified or 'middle' 'top' 'bottom',\n * the height would be as long as possible.\n *\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.x]\n * @param {number|string} [positionInfo.y]\n * @param {number|string} [positionInfo.x2]\n * @param {number|string} [positionInfo.y2]\n * @param {Object} containerRect {width, height}\n * @param {string|number} margin\n * @return {Object} {width, height}\n */\n\n\n/**\n * Parse position info.\n *\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.left]\n * @param {number|string} [positionInfo.top]\n * @param {number|string} [positionInfo.right]\n * @param {number|string} [positionInfo.bottom]\n * @param {number|string} [positionInfo.width]\n * @param {number|string} [positionInfo.height]\n * @param {number|string} [positionInfo.aspect] Aspect is width / height\n * @param {Object} containerRect\n * @param {string|number} [margin]\n *\n * @return {module:zrender/core/BoundingRect}\n */\nfunction getLayoutRect(\n    positionInfo, containerRect, margin\n) {\n    margin = normalizeCssArray$1(margin || 0);\n\n    var containerWidth = containerRect.width;\n    var containerHeight = containerRect.height;\n\n    var left = parsePercent$1(positionInfo.left, containerWidth);\n    var top = parsePercent$1(positionInfo.top, containerHeight);\n    var right = parsePercent$1(positionInfo.right, containerWidth);\n    var bottom = parsePercent$1(positionInfo.bottom, containerHeight);\n    var width = parsePercent$1(positionInfo.width, containerWidth);\n    var height = parsePercent$1(positionInfo.height, containerHeight);\n\n    var verticalMargin = margin[2] + margin[0];\n    var horizontalMargin = margin[1] + margin[3];\n    var aspect = positionInfo.aspect;\n\n    // If width is not specified, calculate width from left and right\n    if (isNaN(width)) {\n        width = containerWidth - right - horizontalMargin - left;\n    }\n    if (isNaN(height)) {\n        height = containerHeight - bottom - verticalMargin - top;\n    }\n\n    if (aspect != null) {\n        // If width and height are not given\n        // 1. Graph should not exceeds the container\n        // 2. Aspect must be keeped\n        // 3. Graph should take the space as more as possible\n        // FIXME\n        // Margin is not considered, because there is no case that both\n        // using margin and aspect so far.\n        if (isNaN(width) && isNaN(height)) {\n            if (aspect > containerWidth / containerHeight) {\n                width = containerWidth * 0.8;\n            }\n            else {\n                height = containerHeight * 0.8;\n            }\n        }\n\n        // Calculate width or height with given aspect\n        if (isNaN(width)) {\n            width = aspect * height;\n        }\n        if (isNaN(height)) {\n            height = width / aspect;\n        }\n    }\n\n    // If left is not specified, calculate left from right and width\n    if (isNaN(left)) {\n        left = containerWidth - right - width - horizontalMargin;\n    }\n    if (isNaN(top)) {\n        top = containerHeight - bottom - height - verticalMargin;\n    }\n\n    // Align left and top\n    switch (positionInfo.left || positionInfo.right) {\n        case 'center':\n            left = containerWidth / 2 - width / 2 - margin[3];\n            break;\n        case 'right':\n            left = containerWidth - width - horizontalMargin;\n            break;\n    }\n    switch (positionInfo.top || positionInfo.bottom) {\n        case 'middle':\n        case 'center':\n            top = containerHeight / 2 - height / 2 - margin[0];\n            break;\n        case 'bottom':\n            top = containerHeight - height - verticalMargin;\n            break;\n    }\n    // If something is wrong and left, top, width, height are calculated as NaN\n    left = left || 0;\n    top = top || 0;\n    if (isNaN(width)) {\n        // Width may be NaN if only one value is given except width\n        width = containerWidth - horizontalMargin - left - (right || 0);\n    }\n    if (isNaN(height)) {\n        // Height may be NaN if only one value is given except height\n        height = containerHeight - verticalMargin - top - (bottom || 0);\n    }\n\n    var rect = new BoundingRect(left + margin[3], top + margin[0], width, height);\n    rect.margin = margin;\n    return rect;\n}\n\n\n/**\n * Position a zr element in viewport\n *  Group position is specified by either\n *  {left, top}, {right, bottom}\n *  If all properties exists, right and bottom will be igonred.\n *\n * Logic:\n *     1. Scale (against origin point in parent coord)\n *     2. Rotate (against origin point in parent coord)\n *     3. Traslate (with el.position by this method)\n * So this method only fixes the last step 'Traslate', which does not affect\n * scaling and rotating.\n *\n * If be called repeatly with the same input el, the same result will be gotten.\n *\n * @param {module:zrender/Element} el Should have `getBoundingRect` method.\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.left]\n * @param {number|string} [positionInfo.top]\n * @param {number|string} [positionInfo.right]\n * @param {number|string} [positionInfo.bottom]\n * @param {number|string} [positionInfo.width] Only for opt.boundingModel: 'raw'\n * @param {number|string} [positionInfo.height] Only for opt.boundingModel: 'raw'\n * @param {Object} containerRect\n * @param {string|number} margin\n * @param {Object} [opt]\n * @param {Array.<number>} [opt.hv=[1,1]] Only horizontal or only vertical.\n * @param {Array.<number>} [opt.boundingMode='all']\n *        Specify how to calculate boundingRect when locating.\n *        'all': Position the boundingRect that is transformed and uioned\n *               both itself and its descendants.\n *               This mode simplies confine the elements in the bounding\n *               of their container (e.g., using 'right: 0').\n *        'raw': Position the boundingRect that is not transformed and only itself.\n *               This mode is useful when you want a element can overflow its\n *               container. (Consider a rotated circle needs to be located in a corner.)\n *               In this mode positionInfo.width/height can only be number.\n */\nfunction positionElement(el, positionInfo, containerRect, margin, opt) {\n    var h = !opt || !opt.hv || opt.hv[0];\n    var v = !opt || !opt.hv || opt.hv[1];\n    var boundingMode = opt && opt.boundingMode || 'all';\n\n    if (!h && !v) {\n        return;\n    }\n\n    var rect;\n    if (boundingMode === 'raw') {\n        rect = el.type === 'group'\n            ? new BoundingRect(0, 0, +positionInfo.width || 0, +positionInfo.height || 0)\n            : el.getBoundingRect();\n    }\n    else {\n        rect = el.getBoundingRect();\n        if (el.needLocalTransform()) {\n            var transform = el.getLocalTransform();\n            // Notice: raw rect may be inner object of el,\n            // which should not be modified.\n            rect = rect.clone();\n            rect.applyTransform(transform);\n        }\n    }\n\n    // The real width and height can not be specified but calculated by the given el.\n    positionInfo = getLayoutRect(\n        defaults(\n            {width: rect.width, height: rect.height},\n            positionInfo\n        ),\n        containerRect,\n        margin\n    );\n\n    // Because 'tranlate' is the last step in transform\n    // (see zrender/core/Transformable#getLocalTransform),\n    // we can just only modify el.position to get final result.\n    var elPos = el.position;\n    var dx = h ? positionInfo.x - rect.x : 0;\n    var dy = v ? positionInfo.y - rect.y : 0;\n\n    el.attr('position', boundingMode === 'raw' ? [dx, dy] : [elPos[0] + dx, elPos[1] + dy]);\n}\n\n/**\n * @param {Object} option Contains some of the properties in HV_NAMES.\n * @param {number} hvIdx 0: horizontal; 1: vertical.\n */\n\n\n/**\n * Consider Case:\n * When defulat option has {left: 0, width: 100}, and we set {right: 0}\n * through setOption or media query, using normal zrUtil.merge will cause\n * {right: 0} does not take effect.\n *\n * @example\n * ComponentModel.extend({\n *     init: function () {\n *         ...\n *         var inputPositionParams = layout.getLayoutParams(option);\n *         this.mergeOption(inputPositionParams);\n *     },\n *     mergeOption: function (newOption) {\n *         newOption && zrUtil.merge(thisOption, newOption, true);\n *         layout.mergeLayoutParam(thisOption, newOption);\n *     }\n * });\n *\n * @param {Object} targetOption\n * @param {Object} newOption\n * @param {Object|string} [opt]\n * @param {boolean|Array.<boolean>} [opt.ignoreSize=false] Used for the components\n *  that width (or height) should not be calculated by left and right (or top and bottom).\n */\nfunction mergeLayoutParam(targetOption, newOption, opt) {\n    !isObject$1(opt) && (opt = {});\n\n    var ignoreSize = opt.ignoreSize;\n    !isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]);\n\n    var hResult = merge$$1(HV_NAMES[0], 0);\n    var vResult = merge$$1(HV_NAMES[1], 1);\n\n    copy(HV_NAMES[0], targetOption, hResult);\n    copy(HV_NAMES[1], targetOption, vResult);\n\n    function merge$$1(names, hvIdx) {\n        var newParams = {};\n        var newValueCount = 0;\n        var merged = {};\n        var mergedValueCount = 0;\n        var enoughParamNumber = 2;\n\n        each$3(names, function (name) {\n            merged[name] = targetOption[name];\n        });\n        each$3(names, function (name) {\n            // Consider case: newOption.width is null, which is\n            // set by user for removing width setting.\n            hasProp(newOption, name) && (newParams[name] = merged[name] = newOption[name]);\n            hasValue(newParams, name) && newValueCount++;\n            hasValue(merged, name) && mergedValueCount++;\n        });\n\n        if (ignoreSize[hvIdx]) {\n            // Only one of left/right is premitted to exist.\n            if (hasValue(newOption, names[1])) {\n                merged[names[2]] = null;\n            }\n            else if (hasValue(newOption, names[2])) {\n                merged[names[1]] = null;\n            }\n            return merged;\n        }\n\n        // Case: newOption: {width: ..., right: ...},\n        // or targetOption: {right: ...} and newOption: {width: ...},\n        // There is no conflict when merged only has params count\n        // little than enoughParamNumber.\n        if (mergedValueCount === enoughParamNumber || !newValueCount) {\n            return merged;\n        }\n        // Case: newOption: {width: ..., right: ...},\n        // Than we can make sure user only want those two, and ignore\n        // all origin params in targetOption.\n        else if (newValueCount >= enoughParamNumber) {\n            return newParams;\n        }\n        else {\n            // Chose another param from targetOption by priority.\n            for (var i = 0; i < names.length; i++) {\n                var name = names[i];\n                if (!hasProp(newParams, name) && hasProp(targetOption, name)) {\n                    newParams[name] = targetOption[name];\n                    break;\n                }\n            }\n            return newParams;\n        }\n    }\n\n    function hasProp(obj, name) {\n        return obj.hasOwnProperty(name);\n    }\n\n    function hasValue(obj, name) {\n        return obj[name] != null && obj[name] !== 'auto';\n    }\n\n    function copy(names, target, source) {\n        each$3(names, function (name) {\n            target[name] = source[name];\n        });\n    }\n}\n\n/**\n * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.\n * @param {Object} source\n * @return {Object} Result contains those props.\n */\nfunction getLayoutParams(source) {\n    return copyLayoutParams({}, source);\n}\n\n/**\n * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.\n * @param {Object} source\n * @return {Object} Result contains those props.\n */\nfunction copyLayoutParams(target, source) {\n    source && target && each$3(LOCATION_PARAMS, function (name) {\n        source.hasOwnProperty(name) && (target[name] = source[name]);\n    });\n    return target;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar boxLayoutMixin = {\n    getBoxLayoutParams: function () {\n        return {\n            left: this.get('left'),\n            top: this.get('top'),\n            right: this.get('right'),\n            bottom: this.get('bottom'),\n            width: this.get('width'),\n            height: this.get('height')\n        };\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Component model\n *\n * @module echarts/model/Component\n */\n\nvar inner$1 = makeInner();\n\n/**\n * @alias module:echarts/model/Component\n * @constructor\n * @param {Object} option\n * @param {module:echarts/model/Model} parentModel\n * @param {module:echarts/model/Model} ecModel\n */\nvar ComponentModel = Model.extend({\n\n    type: 'component',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    id: '',\n\n    /**\n     * Because simplified concept is probably better, series.name (or component.name)\n     * has been having too many resposibilities:\n     * (1) Generating id (which requires name in option should not be modified).\n     * (2) As an index to mapping series when merging option or calling API (a name\n     * can refer to more then one components, which is convinient is some case).\n     * (3) Display.\n     * @readOnly\n     */\n    name: '',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    mainType: '',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    subType: '',\n\n    /**\n     * @readOnly\n     * @type {number}\n     */\n    componentIndex: 0,\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    defaultOption: null,\n\n    /**\n     * @type {module:echarts/model/Global}\n     * @readOnly\n     */\n    ecModel: null,\n\n    /**\n     * key: componentType\n     * value:  Component model list, can not be null.\n     * @type {Object.<string, Array.<module:echarts/model/Model>>}\n     * @readOnly\n     */\n    dependentModels: [],\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    uid: null,\n\n    /**\n     * Support merge layout params.\n     * Only support 'box' now (left/right/top/bottom/width/height).\n     * @type {string|Object} Object can be {ignoreSize: true}\n     * @readOnly\n     */\n    layoutMode: null,\n\n    $constructor: function (option, parentModel, ecModel, extraOpt) {\n        Model.call(this, option, parentModel, ecModel, extraOpt);\n\n        this.uid = getUID('ec_cpt_model');\n    },\n\n    init: function (option, parentModel, ecModel, extraOpt) {\n        this.mergeDefaultAndTheme(option, ecModel);\n    },\n\n    mergeDefaultAndTheme: function (option, ecModel) {\n        var layoutMode = this.layoutMode;\n        var inputPositionParams = layoutMode\n            ? getLayoutParams(option) : {};\n\n        var themeModel = ecModel.getTheme();\n        merge(option, themeModel.get(this.mainType));\n        merge(option, this.getDefaultOption());\n\n        if (layoutMode) {\n            mergeLayoutParam(option, inputPositionParams, layoutMode);\n        }\n    },\n\n    mergeOption: function (option, extraOpt) {\n        merge(this.option, option, true);\n\n        var layoutMode = this.layoutMode;\n        if (layoutMode) {\n            mergeLayoutParam(this.option, option, layoutMode);\n        }\n    },\n\n    // Hooker after init or mergeOption\n    optionUpdated: function (newCptOption, isInit) {},\n\n    getDefaultOption: function () {\n        var fields = inner$1(this);\n        if (!fields.defaultOption) {\n            var optList = [];\n            var Class = this.constructor;\n            while (Class) {\n                var opt = Class.prototype.defaultOption;\n                opt && optList.push(opt);\n                Class = Class.superClass;\n            }\n\n            var defaultOption = {};\n            for (var i = optList.length - 1; i >= 0; i--) {\n                defaultOption = merge(defaultOption, optList[i], true);\n            }\n            fields.defaultOption = defaultOption;\n        }\n        return fields.defaultOption;\n    },\n\n    getReferringComponents: function (mainType) {\n        return this.ecModel.queryComponents({\n            mainType: mainType,\n            index: this.get(mainType + 'Index', true),\n            id: this.get(mainType + 'Id', true)\n        });\n    }\n\n});\n\n// Reset ComponentModel.extend, add preConstruct.\n// clazzUtil.enableClassExtend(\n//     ComponentModel,\n//     function (option, parentModel, ecModel, extraOpt) {\n//         // Set dependentModels, componentIndex, name, id, mainType, subType.\n//         zrUtil.extend(this, extraOpt);\n\n//         this.uid = componentUtil.getUID('componentModel');\n\n//         // this.setReadOnly([\n//         //     'type', 'id', 'uid', 'name', 'mainType', 'subType',\n//         //     'dependentModels', 'componentIndex'\n//         // ]);\n//     }\n// );\n\n// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(\n    ComponentModel, {registerWhenExtend: true}\n);\nenableSubTypeDefaulter(ComponentModel);\n\n// Add capability of ComponentModel.topologicalTravel.\nenableTopologicalTravel(ComponentModel, getDependencies);\n\nfunction getDependencies(componentType) {\n    var deps = [];\n    each$1(ComponentModel.getClassesByMainType(componentType), function (Clazz) {\n        deps = deps.concat(Clazz.prototype.dependencies || []);\n    });\n\n    // Ensure main type.\n    deps = map(deps, function (type) {\n        return parseClassType$1(type).main;\n    });\n\n    // Hack dataset for convenience.\n    if (componentType !== 'dataset' && indexOf(deps, 'dataset') <= 0) {\n        deps.unshift('dataset');\n    }\n\n    return deps;\n}\n\nmixin(ComponentModel, boxLayoutMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar platform = '';\n// Navigator not exists in node\nif (typeof navigator !== 'undefined') {\n    platform = navigator.platform || '';\n}\n\nvar globalDefault = {\n    // backgroundColor: 'rgba(0,0,0,0)',\n\n    // https://dribbble.com/shots/1065960-Infographic-Pie-chart-visualization\n    // color: ['#5793f3', '#d14a61', '#fd9c35', '#675bba', '#fec42c', '#dd4444', '#d4df5a', '#cd4870'],\n    // Light colors:\n    // color: ['#bcd3bb', '#e88f70', '#edc1a5', '#9dc5c8', '#e1e8c8', '#7b7c68', '#e5b5b5', '#f0b489', '#928ea8', '#bda29a'],\n    // color: ['#cc5664', '#9bd6ec', '#ea946e', '#8acaaa', '#f1ec64', '#ee8686', '#a48dc1', '#5da6bc', '#b9dcae'],\n    // Dark colors:\n    color: [\n        '#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83',\n        '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'\n    ],\n\n    gradientColor: ['#f6efa6', '#d88273', '#bf444c'],\n\n    // If xAxis and yAxis declared, grid is created by default.\n    // grid: {},\n\n    textStyle: {\n        // color: '#000',\n        // decoration: 'none',\n        // PENDING\n        fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif',\n        // fontFamily: 'Arial, Verdana, sans-serif',\n        fontSize: 12,\n        fontStyle: 'normal',\n        fontWeight: 'normal'\n    },\n\n    // http://blogs.adobe.com/webplatform/2014/02/24/using-blend-modes-in-html-canvas/\n    // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation\n    // Default is source-over\n    blendMode: null,\n\n    animation: 'auto',\n    animationDuration: 1000,\n    animationDurationUpdate: 300,\n    animationEasing: 'exponentialOut',\n    animationEasingUpdate: 'cubicOut',\n\n    animationThreshold: 2000,\n    // Configuration for progressive/incremental rendering\n    progressiveThreshold: 3000,\n    progressive: 400,\n\n    // Threshold of if use single hover layer to optimize.\n    // It is recommended that `hoverLayerThreshold` is equivalent to or less than\n    // `progressiveThreshold`, otherwise hover will cause restart of progressive,\n    // which is unexpected.\n    // see example <echarts/test/heatmap-large.html>.\n    hoverLayerThreshold: 3000,\n\n    // See: module:echarts/scale/Time\n    useUTC: false\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$2 = makeInner();\n\nfunction getNearestColorPalette(colors, requestColorNum) {\n    var paletteNum = colors.length;\n    // TODO colors must be in order\n    for (var i = 0; i < paletteNum; i++) {\n        if (colors[i].length > requestColorNum) {\n            return colors[i];\n        }\n    }\n    return colors[paletteNum - 1];\n}\n\nvar colorPaletteMixin = {\n    clearColorPalette: function () {\n        inner$2(this).colorIdx = 0;\n        inner$2(this).colorNameMap = {};\n    },\n\n    /**\n     * @param {string} name MUST NOT be null/undefined. Otherwise call this function\n     *                 twise with the same parameters will get different result.\n     * @param {Object} [scope=this]\n     * @param {Object} [requestColorNum]\n     * @return {string} color string.\n     */\n    getColorFromPalette: function (name, scope, requestColorNum) {\n        scope = scope || this;\n        var scopeFields = inner$2(scope);\n        var colorIdx = scopeFields.colorIdx || 0;\n        var colorNameMap = scopeFields.colorNameMap = scopeFields.colorNameMap || {};\n        // Use `hasOwnProperty` to avoid conflict with Object.prototype.\n        if (colorNameMap.hasOwnProperty(name)) {\n            return colorNameMap[name];\n        }\n        var defaultColorPalette = normalizeToArray(this.get('color', true));\n        var layeredColorPalette = this.get('colorLayer', true);\n        var colorPalette = ((requestColorNum == null || !layeredColorPalette)\n            ? defaultColorPalette : getNearestColorPalette(layeredColorPalette, requestColorNum));\n\n        // In case can't find in layered color palette.\n        colorPalette = colorPalette || defaultColorPalette;\n\n        if (!colorPalette || !colorPalette.length) {\n            return;\n        }\n\n        var color = colorPalette[colorIdx];\n        if (name) {\n            colorNameMap[name] = color;\n        }\n        scopeFields.colorIdx = (colorIdx + 1) % colorPalette.length;\n\n        return color;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Helper for model references.\n * There are many manners to refer axis/coordSys.\n */\n\n// TODO\n// merge relevant logic to this file?\n// check: \"modelHelper\" of tooltip and \"BrushTargetManager\".\n\n/**\n * @return {Object} For example:\n * {\n *     coordSysName: 'cartesian2d',\n *     coordSysDims: ['x', 'y', ...],\n *     axisMap: HashMap({\n *         x: xAxisModel,\n *         y: yAxisModel\n *     }),\n *     categoryAxisMap: HashMap({\n *         x: xAxisModel,\n *         y: undefined\n *     }),\n *     // It also indicate that whether there is category axis.\n *     firstCategoryDimIndex: 1,\n *     // To replace user specified encode.\n * }\n */\nfunction getCoordSysDefineBySeries(seriesModel) {\n    var coordSysName = seriesModel.get('coordinateSystem');\n    var result = {\n        coordSysName: coordSysName,\n        coordSysDims: [],\n        axisMap: createHashMap(),\n        categoryAxisMap: createHashMap()\n    };\n    var fetch = fetchers[coordSysName];\n    if (fetch) {\n        fetch(seriesModel, result, result.axisMap, result.categoryAxisMap);\n        return result;\n    }\n}\n\nvar fetchers = {\n\n    cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var xAxisModel = seriesModel.getReferringComponents('xAxis')[0];\n        var yAxisModel = seriesModel.getReferringComponents('yAxis')[0];\n\n        if (__DEV__) {\n            if (!xAxisModel) {\n                throw new Error('xAxis \"' + retrieve(\n                    seriesModel.get('xAxisIndex'),\n                    seriesModel.get('xAxisId'),\n                    0\n                ) + '\" not found');\n            }\n            if (!yAxisModel) {\n                throw new Error('yAxis \"' + retrieve(\n                    seriesModel.get('xAxisIndex'),\n                    seriesModel.get('yAxisId'),\n                    0\n                ) + '\" not found');\n            }\n        }\n\n        result.coordSysDims = ['x', 'y'];\n        axisMap.set('x', xAxisModel);\n        axisMap.set('y', yAxisModel);\n\n        if (isCategory(xAxisModel)) {\n            categoryAxisMap.set('x', xAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n        if (isCategory(yAxisModel)) {\n            categoryAxisMap.set('y', yAxisModel);\n            result.firstCategoryDimIndex = 1;\n        }\n    },\n\n    singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var singleAxisModel = seriesModel.getReferringComponents('singleAxis')[0];\n\n        if (__DEV__) {\n            if (!singleAxisModel) {\n                throw new Error('singleAxis should be specified.');\n            }\n        }\n\n        result.coordSysDims = ['single'];\n        axisMap.set('single', singleAxisModel);\n\n        if (isCategory(singleAxisModel)) {\n            categoryAxisMap.set('single', singleAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n    },\n\n    polar: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var polarModel = seriesModel.getReferringComponents('polar')[0];\n        var radiusAxisModel = polarModel.findAxisModel('radiusAxis');\n        var angleAxisModel = polarModel.findAxisModel('angleAxis');\n\n        if (__DEV__) {\n            if (!angleAxisModel) {\n                throw new Error('angleAxis option not found');\n            }\n            if (!radiusAxisModel) {\n                throw new Error('radiusAxis option not found');\n            }\n        }\n\n        result.coordSysDims = ['radius', 'angle'];\n        axisMap.set('radius', radiusAxisModel);\n        axisMap.set('angle', angleAxisModel);\n\n        if (isCategory(radiusAxisModel)) {\n            categoryAxisMap.set('radius', radiusAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n        if (isCategory(angleAxisModel)) {\n            categoryAxisMap.set('angle', angleAxisModel);\n            result.firstCategoryDimIndex = 1;\n        }\n    },\n\n    geo: function (seriesModel, result, axisMap, categoryAxisMap) {\n        result.coordSysDims = ['lng', 'lat'];\n    },\n\n    parallel: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var ecModel = seriesModel.ecModel;\n        var parallelModel = ecModel.getComponent(\n            'parallel', seriesModel.get('parallelIndex')\n        );\n        var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice();\n\n        each$1(parallelModel.parallelAxisIndex, function (axisIndex, index) {\n            var axisModel = ecModel.getComponent('parallelAxis', axisIndex);\n            var axisDim = coordSysDims[index];\n            axisMap.set(axisDim, axisModel);\n\n            if (isCategory(axisModel) && result.firstCategoryDimIndex == null) {\n                categoryAxisMap.set(axisDim, axisModel);\n                result.firstCategoryDimIndex = index;\n            }\n        });\n    }\n};\n\nfunction isCategory(axisModel) {\n    return axisModel.get('type') === 'category';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Avoid typo.\nvar SOURCE_FORMAT_ORIGINAL = 'original';\nvar SOURCE_FORMAT_ARRAY_ROWS = 'arrayRows';\nvar SOURCE_FORMAT_OBJECT_ROWS = 'objectRows';\nvar SOURCE_FORMAT_KEYED_COLUMNS = 'keyedColumns';\nvar SOURCE_FORMAT_UNKNOWN = 'unknown';\n// ??? CHANGE A NAME\nvar SOURCE_FORMAT_TYPED_ARRAY = 'typedArray';\n\nvar SERIES_LAYOUT_BY_COLUMN = 'column';\nvar SERIES_LAYOUT_BY_ROW = 'row';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * [sourceFormat]\n *\n * + \"original\":\n * This format is only used in series.data, where\n * itemStyle can be specified in data item.\n *\n * + \"arrayRows\":\n * [\n *     ['product', 'score', 'amount'],\n *     ['Matcha Latte', 89.3, 95.8],\n *     ['Milk Tea', 92.1, 89.4],\n *     ['Cheese Cocoa', 94.4, 91.2],\n *     ['Walnut Brownie', 85.4, 76.9]\n * ]\n *\n * + \"objectRows\":\n * [\n *     {product: 'Matcha Latte', score: 89.3, amount: 95.8},\n *     {product: 'Milk Tea', score: 92.1, amount: 89.4},\n *     {product: 'Cheese Cocoa', score: 94.4, amount: 91.2},\n *     {product: 'Walnut Brownie', score: 85.4, amount: 76.9}\n * ]\n *\n * + \"keyedColumns\":\n * {\n *     'product': ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie'],\n *     'count': [823, 235, 1042, 988],\n *     'score': [95.8, 81.4, 91.2, 76.9]\n * }\n *\n * + \"typedArray\"\n *\n * + \"unknown\"\n */\n\n/**\n * @constructor\n * @param {Object} fields\n * @param {string} fields.sourceFormat\n * @param {Array|Object} fields.fromDataset\n * @param {Array|Object} [fields.data]\n * @param {string} [seriesLayoutBy='column']\n * @param {Array.<Object|string>} [dimensionsDefine]\n * @param {Objet|HashMap} [encodeDefine]\n * @param {number} [startIndex=0]\n * @param {number} [dimensionsDetectCount]\n */\nfunction Source(fields) {\n\n    /**\n     * @type {boolean}\n     */\n    this.fromDataset = fields.fromDataset;\n\n    /**\n     * Not null/undefined.\n     * @type {Array|Object}\n     */\n    this.data = fields.data || (\n        fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []\n    );\n\n    /**\n     * See also \"detectSourceFormat\".\n     * Not null/undefined.\n     * @type {string}\n     */\n    this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN;\n\n    /**\n     * 'row' or 'column'\n     * Not null/undefined.\n     * @type {string} seriesLayoutBy\n     */\n    this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN;\n\n    /**\n     * dimensions definition in option.\n     * can be null/undefined.\n     * @type {Array.<Object|string>}\n     */\n    this.dimensionsDefine = fields.dimensionsDefine;\n\n    /**\n     * encode definition in option.\n     * can be null/undefined.\n     * @type {Objet|HashMap}\n     */\n    this.encodeDefine = fields.encodeDefine && createHashMap(fields.encodeDefine);\n\n    /**\n     * Not null/undefined, uint.\n     * @type {number}\n     */\n    this.startIndex = fields.startIndex || 0;\n\n    /**\n     * Can be null/undefined (when unknown), uint.\n     * @type {number}\n     */\n    this.dimensionsDetectCount = fields.dimensionsDetectCount;\n}\n\n/**\n * Wrap original series data for some compatibility cases.\n */\nSource.seriesDataToSource = function (data) {\n    return new Source({\n        data: data,\n        sourceFormat: isTypedArray(data)\n            ? SOURCE_FORMAT_TYPED_ARRAY\n            : SOURCE_FORMAT_ORIGINAL,\n        fromDataset: false\n    });\n};\n\nenableClassCheck(Source);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$3 = makeInner();\n\n/**\n * @see {module:echarts/data/Source}\n * @param {module:echarts/component/dataset/DatasetModel} datasetModel\n * @return {string} sourceFormat\n */\nfunction detectSourceFormat(datasetModel) {\n    var data = datasetModel.option.source;\n    var sourceFormat = SOURCE_FORMAT_UNKNOWN;\n\n    if (isTypedArray(data)) {\n        sourceFormat = SOURCE_FORMAT_TYPED_ARRAY;\n    }\n    else if (isArray(data)) {\n        // FIXME Whether tolerate null in top level array?\n        if (data.length === 0) {\n            sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;\n        }\n\n        for (var i = 0, len = data.length; i < len; i++) {\n            var item = data[i];\n\n            if (item == null) {\n                continue;\n            }\n            else if (isArray(item)) {\n                sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;\n                break;\n            }\n            else if (isObject$1(item)) {\n                sourceFormat = SOURCE_FORMAT_OBJECT_ROWS;\n                break;\n            }\n        }\n    }\n    else if (isObject$1(data)) {\n        for (var key in data) {\n            if (data.hasOwnProperty(key) && isArrayLike(data[key])) {\n                sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS;\n                break;\n            }\n        }\n    }\n    else if (data != null) {\n        throw new Error('Invalid data');\n    }\n\n    inner$3(datasetModel).sourceFormat = sourceFormat;\n}\n\n/**\n * [Scenarios]:\n * (1) Provide source data directly:\n *     series: {\n *         encode: {...},\n *         dimensions: [...]\n *         seriesLayoutBy: 'row',\n *         data: [[...]]\n *     }\n * (2) Refer to datasetModel.\n *     series: [{\n *         encode: {...}\n *         // Ignore datasetIndex means `datasetIndex: 0`\n *         // and the dimensions defination in dataset is used\n *     }, {\n *         encode: {...},\n *         seriesLayoutBy: 'column',\n *         datasetIndex: 1\n *     }]\n *\n * Get data from series itself or datset.\n * @return {module:echarts/data/Source} source\n */\nfunction getSource(seriesModel) {\n    return inner$3(seriesModel).source;\n}\n\n/**\n * MUST be called before mergeOption of all series.\n * @param {module:echarts/model/Global} ecModel\n */\nfunction resetSourceDefaulter(ecModel) {\n    // `datasetMap` is used to make default encode.\n    inner$3(ecModel).datasetMap = createHashMap();\n}\n\n/**\n * [Caution]:\n * MUST be called after series option merged and\n * before \"series.getInitailData()\" called.\n *\n * [The rule of making default encode]:\n * Category axis (if exists) alway map to the first dimension.\n * Each other axis occupies a subsequent dimension.\n *\n * [Why make default encode]:\n * Simplify the typing of encode in option, avoiding the case like that:\n * series: [{encode: {x: 0, y: 1}}, {encode: {x: 0, y: 2}}, {encode: {x: 0, y: 3}}],\n * where the \"y\" have to be manually typed as \"1, 2, 3, ...\".\n *\n * @param {module:echarts/model/Series} seriesModel\n */\nfunction prepareSource(seriesModel) {\n    var seriesOption = seriesModel.option;\n\n    var data = seriesOption.data;\n    var sourceFormat = isTypedArray(data)\n        ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL;\n    var fromDataset = false;\n\n    var seriesLayoutBy = seriesOption.seriesLayoutBy;\n    var sourceHeader = seriesOption.sourceHeader;\n    var dimensionsDefine = seriesOption.dimensions;\n\n    var datasetModel = getDatasetModel(seriesModel);\n    if (datasetModel) {\n        var datasetOption = datasetModel.option;\n\n        data = datasetOption.source;\n        sourceFormat = inner$3(datasetModel).sourceFormat;\n        fromDataset = true;\n\n        // These settings from series has higher priority.\n        seriesLayoutBy = seriesLayoutBy || datasetOption.seriesLayoutBy;\n        sourceHeader == null && (sourceHeader = datasetOption.sourceHeader);\n        dimensionsDefine = dimensionsDefine || datasetOption.dimensions;\n    }\n\n    var completeResult = completeBySourceData(\n        data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine\n    );\n\n    // Note: dataset option does not have `encode`.\n    var encodeDefine = seriesOption.encode;\n    if (!encodeDefine && datasetModel) {\n        encodeDefine = makeDefaultEncode(\n            seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult\n        );\n    }\n\n    inner$3(seriesModel).source = new Source({\n        data: data,\n        fromDataset: fromDataset,\n        seriesLayoutBy: seriesLayoutBy,\n        sourceFormat: sourceFormat,\n        dimensionsDefine: completeResult.dimensionsDefine,\n        startIndex: completeResult.startIndex,\n        dimensionsDetectCount: completeResult.dimensionsDetectCount,\n        encodeDefine: encodeDefine\n    });\n}\n\n// return {startIndex, dimensionsDefine, dimensionsCount}\nfunction completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine) {\n    if (!data) {\n        return {dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine)};\n    }\n\n    var dimensionsDetectCount;\n    var startIndex;\n    var findPotentialName;\n\n    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {\n        // Rule: Most of the first line are string: it is header.\n        // Caution: consider a line with 5 string and 1 number,\n        // it still can not be sure it is a head, because the\n        // 5 string may be 5 values of category columns.\n        if (sourceHeader === 'auto' || sourceHeader == null) {\n            arrayRowsTravelFirst(function (val) {\n                // '-' is regarded as null/undefined.\n                if (val != null && val !== '-') {\n                    if (isString(val)) {\n                        startIndex == null && (startIndex = 1);\n                    }\n                    else {\n                        startIndex = 0;\n                    }\n                }\n            // 10 is an experience number, avoid long loop.\n            }, seriesLayoutBy, data, 10);\n        }\n        else {\n            startIndex = sourceHeader ? 1 : 0;\n        }\n\n        if (!dimensionsDefine && startIndex === 1) {\n            dimensionsDefine = [];\n            arrayRowsTravelFirst(function (val, index) {\n                dimensionsDefine[index] = val != null ? val : '';\n            }, seriesLayoutBy, data);\n        }\n\n        dimensionsDetectCount = dimensionsDefine\n            ? dimensionsDefine.length\n            : seriesLayoutBy === SERIES_LAYOUT_BY_ROW\n            ? data.length\n            : data[0]\n            ? data[0].length\n            : null;\n    }\n    else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {\n        if (!dimensionsDefine) {\n            dimensionsDefine = objectRowsCollectDimensions(data);\n            findPotentialName = true;\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {\n        if (!dimensionsDefine) {\n            dimensionsDefine = [];\n            findPotentialName = true;\n            each$1(data, function (colArr, key) {\n                dimensionsDefine.push(key);\n            });\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        var value0 = getDataItemValue(data[0]);\n        dimensionsDetectCount = isArray(value0) && value0.length || 1;\n    }\n    else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {\n        if (__DEV__) {\n            assert$1(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.');\n        }\n    }\n\n    var potentialNameDimIndex;\n    if (findPotentialName) {\n        each$1(dimensionsDefine, function (dim, idx) {\n            if ((isObject$1(dim) ? dim.name : dim) === 'name') {\n                potentialNameDimIndex = idx;\n            }\n        });\n    }\n\n    return {\n        startIndex: startIndex,\n        dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine),\n        dimensionsDetectCount: dimensionsDetectCount,\n        potentialNameDimIndex: potentialNameDimIndex\n        // TODO: potentialIdDimIdx\n    };\n}\n\n// Consider dimensions defined like ['A', 'price', 'B', 'price', 'C', 'price'],\n// which is reasonable. But dimension name is duplicated.\n// Returns undefined or an array contains only object without null/undefiend or string.\nfunction normalizeDimensionsDefine(dimensionsDefine) {\n    if (!dimensionsDefine) {\n        // The meaning of null/undefined is different from empty array.\n        return;\n    }\n    var nameMap = createHashMap();\n    return map(dimensionsDefine, function (item, index) {\n        item = extend({}, isObject$1(item) ? item : {name: item});\n\n        // User can set null in dimensions.\n        // We dont auto specify name, othewise a given name may\n        // cause it be refered unexpectedly.\n        if (item.name == null) {\n            return item;\n        }\n\n        // Also consider number form like 2012.\n        item.name += '';\n        // User may also specify displayName.\n        // displayName will always exists except user not\n        // specified or dim name is not specified or detected.\n        // (A auto generated dim name will not be used as\n        // displayName).\n        if (item.displayName == null) {\n            item.displayName = item.name;\n        }\n\n        var exist = nameMap.get(item.name);\n        if (!exist) {\n            nameMap.set(item.name, {count: 1});\n        }\n        else {\n            item.name += '-' + exist.count++;\n        }\n\n        return item;\n    });\n}\n\nfunction arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) {\n    maxLoop == null && (maxLoop = Infinity);\n    if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            cb(data[i] ? data[i][0] : null, i);\n        }\n    }\n    else {\n        var value0 = data[0] || [];\n        for (var i = 0; i < value0.length && i < maxLoop; i++) {\n            cb(value0[i], i);\n        }\n    }\n}\n\nfunction objectRowsCollectDimensions(data) {\n    var firstIndex = 0;\n    var obj;\n    while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line\n    if (obj) {\n        var dimensions = [];\n        each$1(obj, function (value, key) {\n            dimensions.push(key);\n        });\n        return dimensions;\n    }\n}\n\n// ??? TODO merge to completedimensions, where also has\n// default encode making logic. And the default rule\n// should depends on series? consider 'map'.\nfunction makeDefaultEncode(\n    seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult\n) {\n    var coordSysDefine = getCoordSysDefineBySeries(seriesModel);\n    var encode = {};\n    // var encodeTooltip = [];\n    // var encodeLabel = [];\n    var encodeItemName = [];\n    var encodeSeriesName = [];\n    var seriesType = seriesModel.subType;\n\n    // ??? TODO refactor: provide by series itself.\n    // Consider the case: 'map' series is based on geo coordSys,\n    // 'graph', 'heatmap' can be based on cartesian. But can not\n    // give default rule simply here.\n    var nSeriesMap = createHashMap(['pie', 'map', 'funnel']);\n    var cSeriesMap = createHashMap([\n        'line', 'bar', 'pictorialBar', 'scatter', 'effectScatter', 'candlestick', 'boxplot'\n    ]);\n\n    // Usually in this case series will use the first data\n    // dimension as the \"value\" dimension, or other default\n    // processes respectively.\n    if (coordSysDefine && cSeriesMap.get(seriesType) != null) {\n        var ecModel = seriesModel.ecModel;\n        var datasetMap = inner$3(ecModel).datasetMap;\n        var key = datasetModel.uid + '_' + seriesLayoutBy;\n        var datasetRecord = datasetMap.get(key)\n            || datasetMap.set(key, {categoryWayDim: 1, valueWayDim: 0});\n\n        // TODO\n        // Auto detect first time axis and do arrangement.\n        each$1(coordSysDefine.coordSysDims, function (coordDim) {\n            // In value way.\n            if (coordSysDefine.firstCategoryDimIndex == null) {\n                var dataDim = datasetRecord.valueWayDim++;\n                encode[coordDim] = dataDim;\n\n                // ??? TODO give a better default series name rule?\n                // especially when encode x y specified.\n                // consider: when mutiple series share one dimension\n                // category axis, series name should better use\n                // the other dimsion name. On the other hand, use\n                // both dimensions name.\n\n                encodeSeriesName.push(dataDim);\n                // encodeTooltip.push(dataDim);\n                // encodeLabel.push(dataDim);\n            }\n            // In category way, category axis.\n            else if (coordSysDefine.categoryAxisMap.get(coordDim)) {\n                encode[coordDim] = 0;\n                encodeItemName.push(0);\n            }\n            // In category way, non-category axis.\n            else {\n                var dataDim = datasetRecord.categoryWayDim++;\n                encode[coordDim] = dataDim;\n                // encodeTooltip.push(dataDim);\n                // encodeLabel.push(dataDim);\n                encodeSeriesName.push(dataDim);\n            }\n        });\n    }\n    // Do not make a complex rule! Hard to code maintain and not necessary.\n    // ??? TODO refactor: provide by series itself.\n    // [{name: ..., value: ...}, ...] like:\n    else if (nSeriesMap.get(seriesType) != null) {\n        // Find the first not ordinal. (5 is an experience value)\n        var firstNotOrdinal;\n        for (var i = 0; i < 5 && firstNotOrdinal == null; i++) {\n            if (!doGuessOrdinal(\n                data, sourceFormat, seriesLayoutBy,\n                completeResult.dimensionsDefine, completeResult.startIndex, i\n            )) {\n                firstNotOrdinal = i;\n            }\n        }\n        if (firstNotOrdinal != null) {\n            encode.value = firstNotOrdinal;\n            var nameDimIndex = completeResult.potentialNameDimIndex\n                || Math.max(firstNotOrdinal - 1, 0);\n            // By default, label use itemName in charts.\n            // So we dont set encodeLabel here.\n            encodeSeriesName.push(nameDimIndex);\n            encodeItemName.push(nameDimIndex);\n            // encodeTooltip.push(firstNotOrdinal);\n        }\n    }\n\n    // encodeTooltip.length && (encode.tooltip = encodeTooltip);\n    // encodeLabel.length && (encode.label = encodeLabel);\n    encodeItemName.length && (encode.itemName = encodeItemName);\n    encodeSeriesName.length && (encode.seriesName = encodeSeriesName);\n\n    return encode;\n}\n\n/**\n * If return null/undefined, indicate that should not use datasetModel.\n */\nfunction getDatasetModel(seriesModel) {\n    var option = seriesModel.option;\n    // Caution: consider the scenario:\n    // A dataset is declared and a series is not expected to use the dataset,\n    // and at the beginning `setOption({series: { noData })` (just prepare other\n    // option but no data), then `setOption({series: {data: [...]}); In this case,\n    // the user should set an empty array to avoid that dataset is used by default.\n    var thisData = option.data;\n    if (!thisData) {\n        return seriesModel.ecModel.getComponent('dataset', option.datasetIndex || 0);\n    }\n}\n\n/**\n * The rule should not be complex, otherwise user might not\n * be able to known where the data is wrong.\n * The code is ugly, but how to make it neat?\n *\n * @param {module:echars/data/Source} source\n * @param {number} dimIndex\n * @return {boolean} Whether ordinal.\n */\nfunction guessOrdinal(source, dimIndex) {\n    return doGuessOrdinal(\n        source.data,\n        source.sourceFormat,\n        source.seriesLayoutBy,\n        source.dimensionsDefine,\n        source.startIndex,\n        dimIndex\n    );\n}\n\n// dimIndex may be overflow source data.\nfunction doGuessOrdinal(\n    data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex\n) {\n    var result;\n    // Experience value.\n    var maxLoop = 5;\n\n    if (isTypedArray(data)) {\n        return false;\n    }\n\n    // When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine\n    // always exists in source.\n    var dimName;\n    if (dimensionsDefine) {\n        dimName = dimensionsDefine[dimIndex];\n        dimName = isObject$1(dimName) ? dimName.name : dimName;\n    }\n\n    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {\n        if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {\n            var sample = data[dimIndex];\n            for (var i = 0; i < (sample || []).length && i < maxLoop; i++) {\n                if ((result = detectValue(sample[startIndex + i])) != null) {\n                    return result;\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < data.length && i < maxLoop; i++) {\n                var row = data[startIndex + i];\n                if (row && (result = detectValue(row[dimIndex])) != null) {\n                    return result;\n                }\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {\n        if (!dimName) {\n            return;\n        }\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            var item = data[i];\n            if (item && (result = detectValue(item[dimName])) != null) {\n                return result;\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {\n        if (!dimName) {\n            return;\n        }\n        var sample = data[dimName];\n        if (!sample || isTypedArray(sample)) {\n            return false;\n        }\n        for (var i = 0; i < sample.length && i < maxLoop; i++) {\n            if ((result = detectValue(sample[i])) != null) {\n                return result;\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            var item = data[i];\n            var val = getDataItemValue(item);\n            if (!isArray(val)) {\n                return false;\n            }\n            if ((result = detectValue(val[dimIndex])) != null) {\n                return result;\n            }\n        }\n    }\n\n    function detectValue(val) {\n        // Consider usage convenience, '1', '2' will be treated as \"number\".\n        // `isFinit('')` get `true`.\n        if (val != null && isFinite(val) && val !== '') {\n            return false;\n        }\n        else if (isString(val) && val !== '-') {\n            return true;\n        }\n    }\n\n    return false;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * ECharts global model\n *\n * @module {echarts/model/Global}\n */\n\n\n/**\n * Caution: If the mechanism should be changed some day, these cases\n * should be considered:\n *\n * (1) In `merge option` mode, if using the same option to call `setOption`\n * many times, the result should be the same (try our best to ensure that).\n * (2) In `merge option` mode, if a component has no id/name specified, it\n * will be merged by index, and the result sequence of the components is\n * consistent to the original sequence.\n * (3) `reset` feature (in toolbox). Find detailed info in comments about\n * `mergeOption` in module:echarts/model/OptionManager.\n */\n\nvar OPTION_INNER_KEY = '\\0_ec_inner';\n\n/**\n * @alias module:echarts/model/Global\n *\n * @param {Object} option\n * @param {module:echarts/model/Model} parentModel\n * @param {Object} theme\n */\nvar GlobalModel = Model.extend({\n\n    init: function (option, parentModel, theme, optionManager) {\n        theme = theme || {};\n\n        this.option = null; // Mark as not initialized.\n\n        /**\n         * @type {module:echarts/model/Model}\n         * @private\n         */\n        this._theme = new Model(theme);\n\n        /**\n         * @type {module:echarts/model/OptionManager}\n         */\n        this._optionManager = optionManager;\n    },\n\n    setOption: function (option, optionPreprocessorFuncs) {\n        assert$1(\n            !(OPTION_INNER_KEY in option),\n            'please use chart.getOption()'\n        );\n\n        this._optionManager.setOption(option, optionPreprocessorFuncs);\n\n        this.resetOption(null);\n    },\n\n    /**\n     * @param {string} type null/undefined: reset all.\n     *                      'recreate': force recreate all.\n     *                      'timeline': only reset timeline option\n     *                      'media': only reset media query option\n     * @return {boolean} Whether option changed.\n     */\n    resetOption: function (type) {\n        var optionChanged = false;\n        var optionManager = this._optionManager;\n\n        if (!type || type === 'recreate') {\n            var baseOption = optionManager.mountOption(type === 'recreate');\n\n            if (!this.option || type === 'recreate') {\n                initBase.call(this, baseOption);\n            }\n            else {\n                this.restoreData();\n                this.mergeOption(baseOption);\n            }\n            optionChanged = true;\n        }\n\n        if (type === 'timeline' || type === 'media') {\n            this.restoreData();\n        }\n\n        if (!type || type === 'recreate' || type === 'timeline') {\n            var timelineOption = optionManager.getTimelineOption(this);\n            timelineOption && (this.mergeOption(timelineOption), optionChanged = true);\n        }\n\n        if (!type || type === 'recreate' || type === 'media') {\n            var mediaOptions = optionManager.getMediaOption(this, this._api);\n            if (mediaOptions.length) {\n                each$1(mediaOptions, function (mediaOption) {\n                    this.mergeOption(mediaOption, optionChanged = true);\n                }, this);\n            }\n        }\n\n        return optionChanged;\n    },\n\n    /**\n     * @protected\n     */\n    mergeOption: function (newOption) {\n        var option = this.option;\n        var componentsMap = this._componentsMap;\n        var newCptTypes = [];\n\n        resetSourceDefaulter(this);\n\n        // If no component class, merge directly.\n        // For example: color, animaiton options, etc.\n        each$1(newOption, function (componentOption, mainType) {\n            if (componentOption == null) {\n                return;\n            }\n\n            if (!ComponentModel.hasClass(mainType)) {\n                // globalSettingTask.dirty();\n                option[mainType] = option[mainType] == null\n                    ? clone(componentOption)\n                    : merge(option[mainType], componentOption, true);\n            }\n            else if (mainType) {\n                newCptTypes.push(mainType);\n            }\n        });\n\n        ComponentModel.topologicalTravel(\n            newCptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this\n        );\n\n        function visitComponent(mainType, dependencies) {\n\n            var newCptOptionList = normalizeToArray(newOption[mainType]);\n\n            var mapResult = mappingToExists(\n                componentsMap.get(mainType), newCptOptionList\n            );\n\n            makeIdAndName(mapResult);\n\n            // Set mainType and complete subType.\n            each$1(mapResult, function (item, index) {\n                var opt = item.option;\n                if (isObject$1(opt)) {\n                    item.keyInfo.mainType = mainType;\n                    item.keyInfo.subType = determineSubType(mainType, opt, item.exist);\n                }\n            });\n\n            var dependentModels = getComponentsByTypes(\n                componentsMap, dependencies\n            );\n\n            option[mainType] = [];\n            componentsMap.set(mainType, []);\n\n            each$1(mapResult, function (resultItem, index) {\n                var componentModel = resultItem.exist;\n                var newCptOption = resultItem.option;\n\n                assert$1(\n                    isObject$1(newCptOption) || componentModel,\n                    'Empty component definition'\n                );\n\n                // Consider where is no new option and should be merged using {},\n                // see removeEdgeAndAdd in topologicalTravel and\n                // ComponentModel.getAllClassMainTypes.\n                if (!newCptOption) {\n                    componentModel.mergeOption({}, this);\n                    componentModel.optionUpdated({}, false);\n                }\n                else {\n                    var ComponentModelClass = ComponentModel.getClass(\n                        mainType, resultItem.keyInfo.subType, true\n                    );\n\n                    if (componentModel && componentModel instanceof ComponentModelClass) {\n                        componentModel.name = resultItem.keyInfo.name;\n                        // componentModel.settingTask && componentModel.settingTask.dirty();\n                        componentModel.mergeOption(newCptOption, this);\n                        componentModel.optionUpdated(newCptOption, false);\n                    }\n                    else {\n                        // PENDING Global as parent ?\n                        var extraOpt = extend(\n                            {\n                                dependentModels: dependentModels,\n                                componentIndex: index\n                            },\n                            resultItem.keyInfo\n                        );\n                        componentModel = new ComponentModelClass(\n                            newCptOption, this, this, extraOpt\n                        );\n                        extend(componentModel, extraOpt);\n                        componentModel.init(newCptOption, this, this, extraOpt);\n\n                        // Call optionUpdated after init.\n                        // newCptOption has been used as componentModel.option\n                        // and may be merged with theme and default, so pass null\n                        // to avoid confusion.\n                        componentModel.optionUpdated(null, true);\n                    }\n                }\n\n                componentsMap.get(mainType)[index] = componentModel;\n                option[mainType][index] = componentModel.option;\n            }, this);\n\n            // Backup series for filtering.\n            if (mainType === 'series') {\n                createSeriesIndices(this, componentsMap.get('series'));\n            }\n        }\n\n        this._seriesIndicesMap = createHashMap(\n            this._seriesIndices = this._seriesIndices || []\n        );\n    },\n\n    /**\n     * Get option for output (cloned option and inner info removed)\n     * @public\n     * @return {Object}\n     */\n    getOption: function () {\n        var option = clone(this.option);\n\n        each$1(option, function (opts, mainType) {\n            if (ComponentModel.hasClass(mainType)) {\n                var opts = normalizeToArray(opts);\n                for (var i = opts.length - 1; i >= 0; i--) {\n                    // Remove options with inner id.\n                    if (isIdInner(opts[i])) {\n                        opts.splice(i, 1);\n                    }\n                }\n                option[mainType] = opts;\n            }\n        });\n\n        delete option[OPTION_INNER_KEY];\n\n        return option;\n    },\n\n    /**\n     * @return {module:echarts/model/Model}\n     */\n    getTheme: function () {\n        return this._theme;\n    },\n\n    /**\n     * @param {string} mainType\n     * @param {number} [idx=0]\n     * @return {module:echarts/model/Component}\n     */\n    getComponent: function (mainType, idx) {\n        var list = this._componentsMap.get(mainType);\n        if (list) {\n            return list[idx || 0];\n        }\n    },\n\n    /**\n     * If none of index and id and name used, return all components with mainType.\n     * @param {Object} condition\n     * @param {string} condition.mainType\n     * @param {string} [condition.subType] If ignore, only query by mainType\n     * @param {number|Array.<number>} [condition.index] Either input index or id or name.\n     * @param {string|Array.<string>} [condition.id] Either input index or id or name.\n     * @param {string|Array.<string>} [condition.name] Either input index or id or name.\n     * @return {Array.<module:echarts/model/Component>}\n     */\n    queryComponents: function (condition) {\n        var mainType = condition.mainType;\n        if (!mainType) {\n            return [];\n        }\n\n        var index = condition.index;\n        var id = condition.id;\n        var name = condition.name;\n\n        var cpts = this._componentsMap.get(mainType);\n\n        if (!cpts || !cpts.length) {\n            return [];\n        }\n\n        var result;\n\n        if (index != null) {\n            if (!isArray(index)) {\n                index = [index];\n            }\n            result = filter(map(index, function (idx) {\n                return cpts[idx];\n            }), function (val) {\n                return !!val;\n            });\n        }\n        else if (id != null) {\n            var isIdArray = isArray(id);\n            result = filter(cpts, function (cpt) {\n                return (isIdArray && indexOf(id, cpt.id) >= 0)\n                    || (!isIdArray && cpt.id === id);\n            });\n        }\n        else if (name != null) {\n            var isNameArray = isArray(name);\n            result = filter(cpts, function (cpt) {\n                return (isNameArray && indexOf(name, cpt.name) >= 0)\n                    || (!isNameArray && cpt.name === name);\n            });\n        }\n        else {\n            // Return all components with mainType\n            result = cpts.slice();\n        }\n\n        return filterBySubType(result, condition);\n    },\n\n    /**\n     * The interface is different from queryComponents,\n     * which is convenient for inner usage.\n     *\n     * @usage\n     * var result = findComponents(\n     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}}\n     * );\n     * var result = findComponents(\n     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}}\n     * );\n     * var result = findComponents(\n     *     {mainType: 'series'},\n     *     function (model, index) {...}\n     * );\n     * // result like [component0, componnet1, ...]\n     *\n     * @param {Object} condition\n     * @param {string} condition.mainType Mandatory.\n     * @param {string} [condition.subType] Optional.\n     * @param {Object} [condition.query] like {xxxIndex, xxxId, xxxName},\n     *        where xxx is mainType.\n     *        If query attribute is null/undefined or has no index/id/name,\n     *        do not filtering by query conditions, which is convenient for\n     *        no-payload situations or when target of action is global.\n     * @param {Function} [condition.filter] parameter: component, return boolean.\n     * @return {Array.<module:echarts/model/Component>}\n     */\n    findComponents: function (condition) {\n        var query = condition.query;\n        var mainType = condition.mainType;\n\n        var queryCond = getQueryCond(query);\n        var result = queryCond\n            ? this.queryComponents(queryCond)\n            : this._componentsMap.get(mainType);\n\n        return doFilter(filterBySubType(result, condition));\n\n        function getQueryCond(q) {\n            var indexAttr = mainType + 'Index';\n            var idAttr = mainType + 'Id';\n            var nameAttr = mainType + 'Name';\n            return q && (\n                    q[indexAttr] != null\n                    || q[idAttr] != null\n                    || q[nameAttr] != null\n                )\n                ? {\n                    mainType: mainType,\n                    // subType will be filtered finally.\n                    index: q[indexAttr],\n                    id: q[idAttr],\n                    name: q[nameAttr]\n                }\n                : null;\n        }\n\n        function doFilter(res) {\n            return condition.filter\n                    ? filter(res, condition.filter)\n                    : res;\n        }\n    },\n\n    /**\n     * @usage\n     * eachComponent('legend', function (legendModel, index) {\n     *     ...\n     * });\n     * eachComponent(function (componentType, model, index) {\n     *     // componentType does not include subType\n     *     // (componentType is 'xxx' but not 'xxx.aa')\n     * });\n     * eachComponent(\n     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}},\n     *     function (model, index) {...}\n     * );\n     * eachComponent(\n     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}},\n     *     function (model, index) {...}\n     * );\n     *\n     * @param {string|Object=} mainType When mainType is object, the definition\n     *                                  is the same as the method 'findComponents'.\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachComponent: function (mainType, cb, context) {\n        var componentsMap = this._componentsMap;\n\n        if (typeof mainType === 'function') {\n            context = cb;\n            cb = mainType;\n            componentsMap.each(function (components, componentType) {\n                each$1(components, function (component, index) {\n                    cb.call(context, componentType, component, index);\n                });\n            });\n        }\n        else if (isString(mainType)) {\n            each$1(componentsMap.get(mainType), cb, context);\n        }\n        else if (isObject$1(mainType)) {\n            var queryResult = this.findComponents(mainType);\n            each$1(queryResult, cb, context);\n        }\n    },\n\n    /**\n     * @param {string} name\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeriesByName: function (name) {\n        var series = this._componentsMap.get('series');\n        return filter(series, function (oneSeries) {\n            return oneSeries.name === name;\n        });\n    },\n\n    /**\n     * @param {number} seriesIndex\n     * @return {module:echarts/model/Series}\n     */\n    getSeriesByIndex: function (seriesIndex) {\n        return this._componentsMap.get('series')[seriesIndex];\n    },\n\n    /**\n     * Get series list before filtered by type.\n     * FIXME: rename to getRawSeriesByType?\n     *\n     * @param {string} subType\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeriesByType: function (subType) {\n        var series = this._componentsMap.get('series');\n        return filter(series, function (oneSeries) {\n            return oneSeries.subType === subType;\n        });\n    },\n\n    /**\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeries: function () {\n        return this._componentsMap.get('series').slice();\n    },\n\n    /**\n     * @return {number}\n     */\n    getSeriesCount: function () {\n        return this._componentsMap.get('series').length;\n    },\n\n    /**\n     * After filtering, series may be different\n     * frome raw series.\n     *\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachSeries: function (cb, context) {\n        assertSeriesInitialized(this);\n        each$1(this._seriesIndices, function (rawSeriesIndex) {\n            var series = this._componentsMap.get('series')[rawSeriesIndex];\n            cb.call(context, series, rawSeriesIndex);\n        }, this);\n    },\n\n    /**\n     * Iterate raw series before filtered.\n     *\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachRawSeries: function (cb, context) {\n        each$1(this._componentsMap.get('series'), cb, context);\n    },\n\n    /**\n     * After filtering, series may be different.\n     * frome raw series.\n     *\n     * @parma {string} subType\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachSeriesByType: function (subType, cb, context) {\n        assertSeriesInitialized(this);\n        each$1(this._seriesIndices, function (rawSeriesIndex) {\n            var series = this._componentsMap.get('series')[rawSeriesIndex];\n            if (series.subType === subType) {\n                cb.call(context, series, rawSeriesIndex);\n            }\n        }, this);\n    },\n\n    /**\n     * Iterate raw series before filtered of given type.\n     *\n     * @parma {string} subType\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachRawSeriesByType: function (subType, cb, context) {\n        return each$1(this.getSeriesByType(subType), cb, context);\n    },\n\n    /**\n     * @param {module:echarts/model/Series} seriesModel\n     */\n    isSeriesFiltered: function (seriesModel) {\n        assertSeriesInitialized(this);\n        return this._seriesIndicesMap.get(seriesModel.componentIndex) == null;\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getCurrentSeriesIndices: function () {\n        return (this._seriesIndices || []).slice();\n    },\n\n    /**\n     * @param {Function} cb\n     * @param {*} context\n     */\n    filterSeries: function (cb, context) {\n        assertSeriesInitialized(this);\n        var filteredSeries = filter(\n            this._componentsMap.get('series'), cb, context\n        );\n        createSeriesIndices(this, filteredSeries);\n    },\n\n    restoreData: function (payload) {\n        var componentsMap = this._componentsMap;\n\n        createSeriesIndices(this, componentsMap.get('series'));\n\n        var componentTypes = [];\n        componentsMap.each(function (components, componentType) {\n            componentTypes.push(componentType);\n        });\n\n        ComponentModel.topologicalTravel(\n            componentTypes,\n            ComponentModel.getAllClassMainTypes(),\n            function (componentType, dependencies) {\n                each$1(componentsMap.get(componentType), function (component) {\n                    (componentType !== 'series' || !isNotTargetSeries(component, payload))\n                        && component.restoreData();\n                });\n            }\n        );\n    }\n\n});\n\nfunction isNotTargetSeries(seriesModel, payload) {\n    if (payload) {\n        var index = payload.seiresIndex;\n        var id = payload.seriesId;\n        var name = payload.seriesName;\n        return (index != null && seriesModel.componentIndex !== index)\n            || (id != null && seriesModel.id !== id)\n            || (name != null && seriesModel.name !== name);\n    }\n}\n\n/**\n * @inner\n */\nfunction mergeTheme(option, theme) {\n    // PENDING\n    // NOT use `colorLayer` in theme if option has `color`\n    var notMergeColorLayer = option.color && !option.colorLayer;\n\n    each$1(theme, function (themeItem, name) {\n        if (name === 'colorLayer' && notMergeColorLayer) {\n            return;\n        }\n        // 如果有 component model 则把具体的 merge 逻辑交给该 model 处理\n        if (!ComponentModel.hasClass(name)) {\n            if (typeof themeItem === 'object') {\n                option[name] = !option[name]\n                    ? clone(themeItem)\n                    : merge(option[name], themeItem, false);\n            }\n            else {\n                if (option[name] == null) {\n                    option[name] = themeItem;\n                }\n            }\n        }\n    });\n}\n\nfunction initBase(baseOption) {\n    baseOption = baseOption;\n\n    // Using OPTION_INNER_KEY to mark that this option can not be used outside,\n    // i.e. `chart.setOption(chart.getModel().option);` is forbiden.\n    this.option = {};\n    this.option[OPTION_INNER_KEY] = 1;\n\n    /**\n     * Init with series: [], in case of calling findSeries method\n     * before series initialized.\n     * @type {Object.<string, Array.<module:echarts/model/Model>>}\n     * @private\n     */\n    this._componentsMap = createHashMap({series: []});\n\n    /**\n     * Mapping between filtered series list and raw series list.\n     * key: filtered series indices, value: raw series indices.\n     * @type {Array.<nubmer>}\n     * @private\n     */\n    this._seriesIndices;\n\n    this._seriesIndicesMap;\n\n    mergeTheme(baseOption, this._theme.option);\n\n    // TODO Needs clone when merging to the unexisted property\n    merge(baseOption, globalDefault, false);\n\n    this.mergeOption(baseOption);\n}\n\n/**\n * @inner\n * @param {Array.<string>|string} types model types\n * @return {Object} key: {string} type, value: {Array.<Object>} models\n */\nfunction getComponentsByTypes(componentsMap, types) {\n    if (!isArray(types)) {\n        types = types ? [types] : [];\n    }\n\n    var ret = {};\n    each$1(types, function (type) {\n        ret[type] = (componentsMap.get(type) || []).slice();\n    });\n\n    return ret;\n}\n\n/**\n * @inner\n */\nfunction determineSubType(mainType, newCptOption, existComponent) {\n    var subType = newCptOption.type\n        ? newCptOption.type\n        : existComponent\n        ? existComponent.subType\n        // Use determineSubType only when there is no existComponent.\n        : ComponentModel.determineSubType(mainType, newCptOption);\n\n    // tooltip, markline, markpoint may always has no subType\n    return subType;\n}\n\n/**\n * @inner\n */\nfunction createSeriesIndices(ecModel, seriesModels) {\n    ecModel._seriesIndicesMap = createHashMap(\n        ecModel._seriesIndices = map(seriesModels, function (series) {\n            return series.componentIndex;\n        }) || []\n    );\n}\n\n/**\n * @inner\n */\nfunction filterBySubType(components, condition) {\n    // Using hasOwnProperty for restrict. Consider\n    // subType is undefined in user payload.\n    return condition.hasOwnProperty('subType')\n        ? filter(components, function (cpt) {\n            return cpt.subType === condition.subType;\n        })\n        : components;\n}\n\n/**\n * @inner\n */\nfunction assertSeriesInitialized(ecModel) {\n    // Components that use _seriesIndices should depends on series component,\n    // which make sure that their initialization is after series.\n    if (__DEV__) {\n        if (!ecModel._seriesIndices) {\n            throw new Error('Option should contains series.');\n        }\n    }\n}\n\nmixin(GlobalModel, colorPaletteMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar echartsAPIList = [\n    'getDom', 'getZr', 'getWidth', 'getHeight', 'getDevicePixelRatio', 'dispatchAction', 'isDisposed',\n    'on', 'off', 'getDataURL', 'getConnectedDataURL', 'getModel', 'getOption',\n    'getViewOfComponentModel', 'getViewOfSeriesModel'\n];\n// And `getCoordinateSystems` and `getComponentByElement` will be injected in echarts.js\n\nfunction ExtensionAPI(chartInstance) {\n    each$1(echartsAPIList, function (name) {\n        this[name] = bind(chartInstance[name], chartInstance);\n    }, this);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar coordinateSystemCreators = {};\n\nfunction CoordinateSystemManager() {\n\n    this._coordinateSystems = [];\n}\n\nCoordinateSystemManager.prototype = {\n\n    constructor: CoordinateSystemManager,\n\n    create: function (ecModel, api) {\n        var coordinateSystems = [];\n        each$1(coordinateSystemCreators, function (creater, type) {\n            var list = creater.create(ecModel, api);\n            coordinateSystems = coordinateSystems.concat(list || []);\n        });\n\n        this._coordinateSystems = coordinateSystems;\n    },\n\n    update: function (ecModel, api) {\n        each$1(this._coordinateSystems, function (coordSys) {\n            coordSys.update && coordSys.update(ecModel, api);\n        });\n    },\n\n    getCoordinateSystems: function () {\n        return this._coordinateSystems.slice();\n    }\n};\n\nCoordinateSystemManager.register = function (type, coordinateSystemCreator) {\n    coordinateSystemCreators[type] = coordinateSystemCreator;\n};\n\nCoordinateSystemManager.get = function (type) {\n    return coordinateSystemCreators[type];\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * ECharts option manager\n *\n * @module {echarts/model/OptionManager}\n */\n\n\nvar each$4 = each$1;\nvar clone$3 = clone;\nvar map$1 = map;\nvar merge$1 = merge;\n\nvar QUERY_REG = /^(min|max)?(.+)$/;\n\n/**\n * TERM EXPLANATIONS:\n *\n * [option]:\n *\n *     An object that contains definitions of components. For example:\n *     var option = {\n *         title: {...},\n *         legend: {...},\n *         visualMap: {...},\n *         series: [\n *             {data: [...]},\n *             {data: [...]},\n *             ...\n *         ]\n *     };\n *\n * [rawOption]:\n *\n *     An object input to echarts.setOption. 'rawOption' may be an\n *     'option', or may be an object contains multi-options. For example:\n *     var option = {\n *         baseOption: {\n *             title: {...},\n *             legend: {...},\n *             series: [\n *                 {data: [...]},\n *                 {data: [...]},\n *                 ...\n *             ]\n *         },\n *         timeline: {...},\n *         options: [\n *             {title: {...}, series: {data: [...]}},\n *             {title: {...}, series: {data: [...]}},\n *             ...\n *         ],\n *         media: [\n *             {\n *                 query: {maxWidth: 320},\n *                 option: {series: {x: 20}, visualMap: {show: false}}\n *             },\n *             {\n *                 query: {minWidth: 320, maxWidth: 720},\n *                 option: {series: {x: 500}, visualMap: {show: true}}\n *             },\n *             {\n *                 option: {series: {x: 1200}, visualMap: {show: true}}\n *             }\n *         ]\n *     };\n *\n * @alias module:echarts/model/OptionManager\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction OptionManager(api) {\n\n    /**\n     * @private\n     * @type {module:echarts/ExtensionAPI}\n     */\n    this._api = api;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._timelineOptions = [];\n\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    this._mediaList = [];\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._mediaDefault;\n\n    /**\n     * -1, means default.\n     * empty means no media.\n     * @private\n     * @type {Array.<number>}\n     */\n    this._currentMediaIndices = [];\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._optionBackup;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._newBaseOption;\n}\n\n// timeline.notMerge is not supported in ec3. Firstly there is rearly\n// case that notMerge is needed. Secondly supporting 'notMerge' requires\n// rawOption cloned and backuped when timeline changed, which does no\n// good to performance. What's more, that both timeline and setOption\n// method supply 'notMerge' brings complex and some problems.\n// Consider this case:\n// (step1) chart.setOption({timeline: {notMerge: false}, ...}, false);\n// (step2) chart.setOption({timeline: {notMerge: true}, ...}, false);\n\nOptionManager.prototype = {\n\n    constructor: OptionManager,\n\n    /**\n     * @public\n     * @param {Object} rawOption Raw option.\n     * @param {module:echarts/model/Global} ecModel\n     * @param {Array.<Function>} optionPreprocessorFuncs\n     * @return {Object} Init option\n     */\n    setOption: function (rawOption, optionPreprocessorFuncs) {\n        if (rawOption) {\n            // That set dat primitive is dangerous if user reuse the data when setOption again.\n            each$1(normalizeToArray(rawOption.series), function (series) {\n                series && series.data && isTypedArray(series.data) && setAsPrimitive(series.data);\n            });\n        }\n\n        // Caution: some series modify option data, if do not clone,\n        // it should ensure that the repeat modify correctly\n        // (create a new object when modify itself).\n        rawOption = clone$3(rawOption, true);\n\n        // FIXME\n        // 如果 timeline options 或者 media 中设置了某个属性，而baseOption中没有设置，则进行警告。\n\n        var oldOptionBackup = this._optionBackup;\n        var newParsedOption = parseRawOption.call(\n            this, rawOption, optionPreprocessorFuncs, !oldOptionBackup\n        );\n        this._newBaseOption = newParsedOption.baseOption;\n\n        // For setOption at second time (using merge mode);\n        if (oldOptionBackup) {\n            // Only baseOption can be merged.\n            mergeOption(oldOptionBackup.baseOption, newParsedOption.baseOption);\n\n            // For simplicity, timeline options and media options do not support merge,\n            // that is, if you `setOption` twice and both has timeline options, the latter\n            // timeline opitons will not be merged to the formers, but just substitude them.\n            if (newParsedOption.timelineOptions.length) {\n                oldOptionBackup.timelineOptions = newParsedOption.timelineOptions;\n            }\n            if (newParsedOption.mediaList.length) {\n                oldOptionBackup.mediaList = newParsedOption.mediaList;\n            }\n            if (newParsedOption.mediaDefault) {\n                oldOptionBackup.mediaDefault = newParsedOption.mediaDefault;\n            }\n        }\n        else {\n            this._optionBackup = newParsedOption;\n        }\n    },\n\n    /**\n     * @param {boolean} isRecreate\n     * @return {Object}\n     */\n    mountOption: function (isRecreate) {\n        var optionBackup = this._optionBackup;\n\n        // TODO\n        // 如果没有reset功能则不clone。\n\n        this._timelineOptions = map$1(optionBackup.timelineOptions, clone$3);\n        this._mediaList = map$1(optionBackup.mediaList, clone$3);\n        this._mediaDefault = clone$3(optionBackup.mediaDefault);\n        this._currentMediaIndices = [];\n\n        return clone$3(isRecreate\n            // this._optionBackup.baseOption, which is created at the first `setOption`\n            // called, and is merged into every new option by inner method `mergeOption`\n            // each time `setOption` called, can be only used in `isRecreate`, because\n            // its reliability is under suspicion. In other cases option merge is\n            // performed by `model.mergeOption`.\n            ? optionBackup.baseOption : this._newBaseOption\n        );\n    },\n\n    /**\n     * @param {module:echarts/model/Global} ecModel\n     * @return {Object}\n     */\n    getTimelineOption: function (ecModel) {\n        var option;\n        var timelineOptions = this._timelineOptions;\n\n        if (timelineOptions.length) {\n            // getTimelineOption can only be called after ecModel inited,\n            // so we can get currentIndex from timelineModel.\n            var timelineModel = ecModel.getComponent('timeline');\n            if (timelineModel) {\n                option = clone$3(\n                    timelineOptions[timelineModel.getCurrentIndex()],\n                    true\n                );\n            }\n        }\n\n        return option;\n    },\n\n    /**\n     * @param {module:echarts/model/Global} ecModel\n     * @return {Array.<Object>}\n     */\n    getMediaOption: function (ecModel) {\n        var ecWidth = this._api.getWidth();\n        var ecHeight = this._api.getHeight();\n        var mediaList = this._mediaList;\n        var mediaDefault = this._mediaDefault;\n        var indices = [];\n        var result = [];\n\n        // No media defined.\n        if (!mediaList.length && !mediaDefault) {\n            return result;\n        }\n\n        // Multi media may be applied, the latter defined media has higher priority.\n        for (var i = 0, len = mediaList.length; i < len; i++) {\n            if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) {\n                indices.push(i);\n            }\n        }\n\n        // FIXME\n        // 是否mediaDefault应该强制用户设置，否则可能修改不能回归。\n        if (!indices.length && mediaDefault) {\n            indices = [-1];\n        }\n\n        if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) {\n            result = map$1(indices, function (index) {\n                return clone$3(\n                    index === -1 ? mediaDefault.option : mediaList[index].option\n                );\n            });\n        }\n        // Otherwise return nothing.\n\n        this._currentMediaIndices = indices;\n\n        return result;\n    }\n};\n\nfunction parseRawOption(rawOption, optionPreprocessorFuncs, isNew) {\n    var timelineOptions = [];\n    var mediaList = [];\n    var mediaDefault;\n    var baseOption;\n\n    // Compatible with ec2.\n    var timelineOpt = rawOption.timeline;\n\n    if (rawOption.baseOption) {\n        baseOption = rawOption.baseOption;\n    }\n\n    // For timeline\n    if (timelineOpt || rawOption.options) {\n        baseOption = baseOption || {};\n        timelineOptions = (rawOption.options || []).slice();\n    }\n\n    // For media query\n    if (rawOption.media) {\n        baseOption = baseOption || {};\n        var media = rawOption.media;\n        each$4(media, function (singleMedia) {\n            if (singleMedia && singleMedia.option) {\n                if (singleMedia.query) {\n                    mediaList.push(singleMedia);\n                }\n                else if (!mediaDefault) {\n                    // Use the first media default.\n                    mediaDefault = singleMedia;\n                }\n            }\n        });\n    }\n\n    // For normal option\n    if (!baseOption) {\n        baseOption = rawOption;\n    }\n\n    // Set timelineOpt to baseOption in ec3,\n    // which is convenient for merge option.\n    if (!baseOption.timeline) {\n        baseOption.timeline = timelineOpt;\n    }\n\n    // Preprocess.\n    each$4([baseOption].concat(timelineOptions)\n        .concat(map(mediaList, function (media) {\n            return media.option;\n        })),\n        function (option) {\n            each$4(optionPreprocessorFuncs, function (preProcess) {\n                preProcess(option, isNew);\n            });\n        }\n    );\n\n    return {\n        baseOption: baseOption,\n        timelineOptions: timelineOptions,\n        mediaDefault: mediaDefault,\n        mediaList: mediaList\n    };\n}\n\n/**\n * @see <http://www.w3.org/TR/css3-mediaqueries/#media1>\n * Support: width, height, aspectRatio\n * Can use max or min as prefix.\n */\nfunction applyMediaQuery(query, ecWidth, ecHeight) {\n    var realMap = {\n        width: ecWidth,\n        height: ecHeight,\n        aspectratio: ecWidth / ecHeight // lowser case for convenientce.\n    };\n\n    var applicatable = true;\n\n    each$1(query, function (value, attr) {\n        var matched = attr.match(QUERY_REG);\n\n        if (!matched || !matched[1] || !matched[2]) {\n            return;\n        }\n\n        var operator = matched[1];\n        var realAttr = matched[2].toLowerCase();\n\n        if (!compare(realMap[realAttr], value, operator)) {\n            applicatable = false;\n        }\n    });\n\n    return applicatable;\n}\n\nfunction compare(real, expect, operator) {\n    if (operator === 'min') {\n        return real >= expect;\n    }\n    else if (operator === 'max') {\n        return real <= expect;\n    }\n    else { // Equals\n        return real === expect;\n    }\n}\n\nfunction indicesEquals(indices1, indices2) {\n    // indices is always order by asc and has only finite number.\n    return indices1.join(',') === indices2.join(',');\n}\n\n/**\n * Consider case:\n * `chart.setOption(opt1);`\n * Then user do some interaction like dataZoom, dataView changing.\n * `chart.setOption(opt2);`\n * Then user press 'reset button' in toolbox.\n *\n * After doing that all of the interaction effects should be reset, the\n * chart should be the same as the result of invoke\n * `chart.setOption(opt1); chart.setOption(opt2);`.\n *\n * Although it is not able ensure that\n * `chart.setOption(opt1); chart.setOption(opt2);` is equivalents to\n * `chart.setOption(merge(opt1, opt2));` exactly,\n * this might be the only simple way to implement that feature.\n *\n * MEMO: We've considered some other approaches:\n * 1. Each model handle its self restoration but not uniform treatment.\n *     (Too complex in logic and error-prone)\n * 2. Use a shadow ecModel. (Performace expensive)\n */\nfunction mergeOption(oldOption, newOption) {\n    newOption = newOption || {};\n\n    each$4(newOption, function (newCptOpt, mainType) {\n        if (newCptOpt == null) {\n            return;\n        }\n\n        var oldCptOpt = oldOption[mainType];\n\n        if (!ComponentModel.hasClass(mainType)) {\n            oldOption[mainType] = merge$1(oldCptOpt, newCptOpt, true);\n        }\n        else {\n            newCptOpt = normalizeToArray(newCptOpt);\n            oldCptOpt = normalizeToArray(oldCptOpt);\n\n            var mapResult = mappingToExists(oldCptOpt, newCptOpt);\n\n            oldOption[mainType] = map$1(mapResult, function (item) {\n                return (item.option && item.exist)\n                    ? merge$1(item.exist, item.option, true)\n                    : (item.exist || item.option);\n            });\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$5 = each$1;\nvar isObject$3 = isObject$1;\n\nvar POSSIBLE_STYLES = [\n    'areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle',\n    'chordStyle', 'label', 'labelLine'\n];\n\nfunction compatEC2ItemStyle(opt) {\n    var itemStyleOpt = opt && opt.itemStyle;\n    if (!itemStyleOpt) {\n        return;\n    }\n    for (var i = 0, len = POSSIBLE_STYLES.length; i < len; i++) {\n        var styleName = POSSIBLE_STYLES[i];\n        var normalItemStyleOpt = itemStyleOpt.normal;\n        var emphasisItemStyleOpt = itemStyleOpt.emphasis;\n        if (normalItemStyleOpt && normalItemStyleOpt[styleName]) {\n            opt[styleName] = opt[styleName] || {};\n            if (!opt[styleName].normal) {\n                opt[styleName].normal = normalItemStyleOpt[styleName];\n            }\n            else {\n                merge(opt[styleName].normal, normalItemStyleOpt[styleName]);\n            }\n            normalItemStyleOpt[styleName] = null;\n        }\n        if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) {\n            opt[styleName] = opt[styleName] || {};\n            if (!opt[styleName].emphasis) {\n                opt[styleName].emphasis = emphasisItemStyleOpt[styleName];\n            }\n            else {\n                merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]);\n            }\n            emphasisItemStyleOpt[styleName] = null;\n        }\n    }\n}\n\nfunction convertNormalEmphasis(opt, optType, useExtend) {\n    if (opt && opt[optType] && (opt[optType].normal || opt[optType].emphasis)) {\n        var normalOpt = opt[optType].normal;\n        var emphasisOpt = opt[optType].emphasis;\n\n        if (normalOpt) {\n            // Timeline controlStyle has other properties besides normal and emphasis\n            if (useExtend) {\n                opt[optType].normal = opt[optType].emphasis = null;\n                defaults(opt[optType], normalOpt);\n            }\n            else {\n                opt[optType] = normalOpt;\n            }\n        }\n        if (emphasisOpt) {\n            opt.emphasis = opt.emphasis || {};\n            opt.emphasis[optType] = emphasisOpt;\n        }\n    }\n}\nfunction removeEC3NormalStatus(opt) {\n    convertNormalEmphasis(opt, 'itemStyle');\n    convertNormalEmphasis(opt, 'lineStyle');\n    convertNormalEmphasis(opt, 'areaStyle');\n    convertNormalEmphasis(opt, 'label');\n    convertNormalEmphasis(opt, 'labelLine');\n    // treemap\n    convertNormalEmphasis(opt, 'upperLabel');\n    // graph\n    convertNormalEmphasis(opt, 'edgeLabel');\n}\n\nfunction compatTextStyle(opt, propName) {\n    // Check whether is not object (string\\null\\undefined ...)\n    var labelOptSingle = isObject$3(opt) && opt[propName];\n    var textStyle = isObject$3(labelOptSingle) && labelOptSingle.textStyle;\n    if (textStyle) {\n        for (var i = 0, len = TEXT_STYLE_OPTIONS.length; i < len; i++) {\n            var propName = TEXT_STYLE_OPTIONS[i];\n            if (textStyle.hasOwnProperty(propName)) {\n                labelOptSingle[propName] = textStyle[propName];\n            }\n        }\n    }\n}\n\nfunction compatEC3CommonStyles(opt) {\n    if (opt) {\n        removeEC3NormalStatus(opt);\n        compatTextStyle(opt, 'label');\n        opt.emphasis && compatTextStyle(opt.emphasis, 'label');\n    }\n}\n\nfunction processSeries(seriesOpt) {\n    if (!isObject$3(seriesOpt)) {\n        return;\n    }\n\n    compatEC2ItemStyle(seriesOpt);\n    removeEC3NormalStatus(seriesOpt);\n\n    compatTextStyle(seriesOpt, 'label');\n    // treemap\n    compatTextStyle(seriesOpt, 'upperLabel');\n    // graph\n    compatTextStyle(seriesOpt, 'edgeLabel');\n    if (seriesOpt.emphasis) {\n        compatTextStyle(seriesOpt.emphasis, 'label');\n        // treemap\n        compatTextStyle(seriesOpt.emphasis, 'upperLabel');\n        // graph\n        compatTextStyle(seriesOpt.emphasis, 'edgeLabel');\n    }\n\n    var markPoint = seriesOpt.markPoint;\n    if (markPoint) {\n        compatEC2ItemStyle(markPoint);\n        compatEC3CommonStyles(markPoint);\n    }\n\n    var markLine = seriesOpt.markLine;\n    if (markLine) {\n        compatEC2ItemStyle(markLine);\n        compatEC3CommonStyles(markLine);\n    }\n\n    var markArea = seriesOpt.markArea;\n    if (markArea) {\n        compatEC3CommonStyles(markArea);\n    }\n\n    var data = seriesOpt.data;\n\n    // Break with ec3: if `setOption` again, there may be no `type` in option,\n    // then the backward compat based on option type will not be performed.\n\n    if (seriesOpt.type === 'graph') {\n        data = data || seriesOpt.nodes;\n        var edgeData = seriesOpt.links || seriesOpt.edges;\n        if (edgeData && !isTypedArray(edgeData)) {\n            for (var i = 0; i < edgeData.length; i++) {\n                compatEC3CommonStyles(edgeData[i]);\n            }\n        }\n        each$1(seriesOpt.categories, function (opt) {\n            removeEC3NormalStatus(opt);\n        });\n    }\n\n    if (data && !isTypedArray(data)) {\n        for (var i = 0; i < data.length; i++) {\n            compatEC3CommonStyles(data[i]);\n        }\n    }\n\n    // mark point data\n    var markPoint = seriesOpt.markPoint;\n    if (markPoint && markPoint.data) {\n        var mpData = markPoint.data;\n        for (var i = 0; i < mpData.length; i++) {\n            compatEC3CommonStyles(mpData[i]);\n        }\n    }\n    // mark line data\n    var markLine = seriesOpt.markLine;\n    if (markLine && markLine.data) {\n        var mlData = markLine.data;\n        for (var i = 0; i < mlData.length; i++) {\n            if (isArray(mlData[i])) {\n                compatEC3CommonStyles(mlData[i][0]);\n                compatEC3CommonStyles(mlData[i][1]);\n            }\n            else {\n                compatEC3CommonStyles(mlData[i]);\n            }\n        }\n    }\n\n    // Series\n    if (seriesOpt.type === 'gauge') {\n        compatTextStyle(seriesOpt, 'axisLabel');\n        compatTextStyle(seriesOpt, 'title');\n        compatTextStyle(seriesOpt, 'detail');\n    }\n    else if (seriesOpt.type === 'treemap') {\n        convertNormalEmphasis(seriesOpt.breadcrumb, 'itemStyle');\n        each$1(seriesOpt.levels, function (opt) {\n            removeEC3NormalStatus(opt);\n        });\n    }\n    else if (seriesOpt.type === 'tree') {\n        removeEC3NormalStatus(seriesOpt.leaves);\n    }\n    // sunburst starts from ec4, so it does not need to compat levels.\n}\n\nfunction toArr(o) {\n    return isArray(o) ? o : o ? [o] : [];\n}\n\nfunction toObj(o) {\n    return (isArray(o) ? o[0] : o) || {};\n}\n\nvar compatStyle = function (option, isTheme) {\n    each$5(toArr(option.series), function (seriesOpt) {\n        isObject$3(seriesOpt) && processSeries(seriesOpt);\n    });\n\n    var axes = ['xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'parallelAxis', 'radar'];\n    isTheme && axes.push('valueAxis', 'categoryAxis', 'logAxis', 'timeAxis');\n\n    each$5(\n        axes,\n        function (axisName) {\n            each$5(toArr(option[axisName]), function (axisOpt) {\n                if (axisOpt) {\n                    compatTextStyle(axisOpt, 'axisLabel');\n                    compatTextStyle(axisOpt.axisPointer, 'label');\n                }\n            });\n        }\n    );\n\n    each$5(toArr(option.parallel), function (parallelOpt) {\n        var parallelAxisDefault = parallelOpt && parallelOpt.parallelAxisDefault;\n        compatTextStyle(parallelAxisDefault, 'axisLabel');\n        compatTextStyle(parallelAxisDefault && parallelAxisDefault.axisPointer, 'label');\n    });\n\n    each$5(toArr(option.calendar), function (calendarOpt) {\n        convertNormalEmphasis(calendarOpt, 'itemStyle');\n        compatTextStyle(calendarOpt, 'dayLabel');\n        compatTextStyle(calendarOpt, 'monthLabel');\n        compatTextStyle(calendarOpt, 'yearLabel');\n    });\n\n    // radar.name.textStyle\n    each$5(toArr(option.radar), function (radarOpt) {\n        compatTextStyle(radarOpt, 'name');\n    });\n\n    each$5(toArr(option.geo), function (geoOpt) {\n        if (isObject$3(geoOpt)) {\n            compatEC3CommonStyles(geoOpt);\n            each$5(toArr(geoOpt.regions), function (regionObj) {\n                compatEC3CommonStyles(regionObj);\n            });\n        }\n    });\n\n    each$5(toArr(option.timeline), function (timelineOpt) {\n        compatEC3CommonStyles(timelineOpt);\n        convertNormalEmphasis(timelineOpt, 'label');\n        convertNormalEmphasis(timelineOpt, 'itemStyle');\n        convertNormalEmphasis(timelineOpt, 'controlStyle', true);\n\n        var data = timelineOpt.data;\n        isArray(data) && each$1(data, function (item) {\n            if (isObject$1(item)) {\n                convertNormalEmphasis(item, 'label');\n                convertNormalEmphasis(item, 'itemStyle');\n            }\n        });\n    });\n\n    each$5(toArr(option.toolbox), function (toolboxOpt) {\n        convertNormalEmphasis(toolboxOpt, 'iconStyle');\n        each$5(toolboxOpt.feature, function (featureOpt) {\n            convertNormalEmphasis(featureOpt, 'iconStyle');\n        });\n    });\n\n    compatTextStyle(toObj(option.axisPointer), 'label');\n    compatTextStyle(toObj(option.tooltip).axisPointer, 'label');\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Compatitable with 2.0\n\nfunction get(opt, path) {\n    path = path.split(',');\n    var obj = opt;\n    for (var i = 0; i < path.length; i++) {\n        obj = obj && obj[path[i]];\n        if (obj == null) {\n            break;\n        }\n    }\n    return obj;\n}\n\nfunction set$1(opt, path, val, overwrite) {\n    path = path.split(',');\n    var obj = opt;\n    var key;\n    for (var i = 0; i < path.length - 1; i++) {\n        key = path[i];\n        if (obj[key] == null) {\n            obj[key] = {};\n        }\n        obj = obj[key];\n    }\n    if (overwrite || obj[path[i]] == null) {\n        obj[path[i]] = val;\n    }\n}\n\nfunction compatLayoutProperties(option) {\n    each$1(LAYOUT_PROPERTIES, function (prop) {\n        if (prop[0] in option && !(prop[1] in option)) {\n            option[prop[1]] = option[prop[0]];\n        }\n    });\n}\n\nvar LAYOUT_PROPERTIES = [\n    ['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom']\n];\n\nvar COMPATITABLE_COMPONENTS = [\n    'grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline'\n];\n\nvar backwardCompat = function (option, isTheme) {\n    compatStyle(option, isTheme);\n\n    // Make sure series array for model initialization.\n    option.series = normalizeToArray(option.series);\n\n    each$1(option.series, function (seriesOpt) {\n        if (!isObject$1(seriesOpt)) {\n            return;\n        }\n\n        var seriesType = seriesOpt.type;\n\n        if (seriesType === 'pie' || seriesType === 'gauge') {\n            if (seriesOpt.clockWise != null) {\n                seriesOpt.clockwise = seriesOpt.clockWise;\n            }\n        }\n        if (seriesType === 'gauge') {\n            var pointerColor = get(seriesOpt, 'pointer.color');\n            pointerColor != null\n                && set$1(seriesOpt, 'itemStyle.normal.color', pointerColor);\n        }\n\n        compatLayoutProperties(seriesOpt);\n    });\n\n    // dataRange has changed to visualMap\n    if (option.dataRange) {\n        option.visualMap = option.dataRange;\n    }\n\n    each$1(COMPATITABLE_COMPONENTS, function (componentName) {\n        var options = option[componentName];\n        if (options) {\n            if (!isArray(options)) {\n                options = [options];\n            }\n            each$1(options, function (option) {\n                compatLayoutProperties(option);\n            });\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (1) [Caution]: the logic is correct based on the premises:\n//     data processing stage is blocked in stream.\n//     See <module:echarts/stream/Scheduler#performDataProcessorTasks>\n// (2) Only register once when import repeatly.\n//     Should be executed before after series filtered and before stack calculation.\nvar dataStack = function (ecModel) {\n    var stackInfoMap = createHashMap();\n    ecModel.eachSeries(function (seriesModel) {\n        var stack = seriesModel.get('stack');\n        // Compatibal: when `stack` is set as '', do not stack.\n        if (stack) {\n            var stackInfoList = stackInfoMap.get(stack) || stackInfoMap.set(stack, []);\n            var data = seriesModel.getData();\n\n            var stackInfo = {\n                // Used for calculate axis extent automatically.\n                stackResultDimension: data.getCalculationInfo('stackResultDimension'),\n                stackedOverDimension: data.getCalculationInfo('stackedOverDimension'),\n                stackedDimension: data.getCalculationInfo('stackedDimension'),\n                stackedByDimension: data.getCalculationInfo('stackedByDimension'),\n                isStackedByIndex: data.getCalculationInfo('isStackedByIndex'),\n                data: data,\n                seriesModel: seriesModel\n            };\n\n            // If stacked on axis that do not support data stack.\n            if (!stackInfo.stackedDimension\n                || !(stackInfo.isStackedByIndex || stackInfo.stackedByDimension)\n            ) {\n                return;\n            }\n\n            stackInfoList.length && data.setCalculationInfo(\n                'stackedOnSeries', stackInfoList[stackInfoList.length - 1].seriesModel\n            );\n\n            stackInfoList.push(stackInfo);\n        }\n    });\n\n    stackInfoMap.each(calculateStack);\n};\n\nfunction calculateStack(stackInfoList) {\n    each$1(stackInfoList, function (targetStackInfo, idxInStack) {\n        var resultVal = [];\n        var resultNaN = [NaN, NaN];\n        var dims = [targetStackInfo.stackResultDimension, targetStackInfo.stackedOverDimension];\n        var targetData = targetStackInfo.data;\n        var isStackedByIndex = targetStackInfo.isStackedByIndex;\n\n        // Should not write on raw data, because stack series model list changes\n        // depending on legend selection.\n        var newData = targetData.map(dims, function (v0, v1, dataIndex) {\n            var sum = targetData.get(targetStackInfo.stackedDimension, dataIndex);\n\n            // Consider `connectNulls` of line area, if value is NaN, stackedOver\n            // should also be NaN, to draw a appropriate belt area.\n            if (isNaN(sum)) {\n                return resultNaN;\n            }\n\n            var byValue;\n            var stackedDataRawIndex;\n\n            if (isStackedByIndex) {\n                stackedDataRawIndex = targetData.getRawIndex(dataIndex);\n            }\n            else {\n                byValue = targetData.get(targetStackInfo.stackedByDimension, dataIndex);\n            }\n\n            // If stackOver is NaN, chart view will render point on value start.\n            var stackedOver = NaN;\n\n            for (var j = idxInStack - 1; j >= 0; j--) {\n                var stackInfo = stackInfoList[j];\n\n                // Has been optimized by inverted indices on `stackedByDimension`.\n                if (!isStackedByIndex) {\n                    stackedDataRawIndex = stackInfo.data.rawIndexOf(stackInfo.stackedByDimension, byValue);\n                }\n\n                if (stackedDataRawIndex >= 0) {\n                    var val = stackInfo.data.getByRawIndex(stackInfo.stackResultDimension, stackedDataRawIndex);\n\n                    // Considering positive stack, negative stack and empty data\n                    if ((sum >= 0 && val > 0) // Positive stack\n                        || (sum <= 0 && val < 0) // Negative stack\n                    ) {\n                        sum += val;\n                        stackedOver = val;\n                        break;\n                    }\n                }\n            }\n\n            resultVal[0] = sum;\n            resultVal[1] = stackedOver;\n\n            return resultVal;\n        });\n\n        targetData.hostModel.setData(newData);\n        // Update for consequent calculation\n        targetStackInfo.data = newData;\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO\n// ??? refactor? check the outer usage of data provider.\n// merge with defaultDimValueGetter?\n\n/**\n * If normal array used, mutable chunk size is supported.\n * If typed array used, chunk size must be fixed.\n */\nfunction DefaultDataProvider(source, dimSize) {\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n    this._source = source;\n\n    var data = this._data = source.data;\n    var sourceFormat = source.sourceFormat;\n\n    // Typed array. TODO IE10+?\n    if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {\n        if (__DEV__) {\n            if (dimSize == null) {\n                throw new Error('Typed array data must specify dimension size');\n            }\n        }\n        this._offset = 0;\n        this._dimSize = dimSize;\n        this._data = data;\n    }\n\n    var methods = providerMethods[\n        sourceFormat === SOURCE_FORMAT_ARRAY_ROWS\n        ? sourceFormat + '_' + source.seriesLayoutBy\n        : sourceFormat\n    ];\n\n    if (__DEV__) {\n        assert$1(methods, 'Invalide sourceFormat: ' + sourceFormat);\n    }\n\n    extend(this, methods);\n}\n\nvar providerProto = DefaultDataProvider.prototype;\n// If data is pure without style configuration\nproviderProto.pure = false;\n// If data is persistent and will not be released after use.\nproviderProto.persistent = true;\n\n// ???! FIXME legacy data provider do not has method getSource\nproviderProto.getSource = function () {\n    return this._source;\n};\n\nvar providerMethods = {\n\n    'arrayRows_column': {\n        pure: true,\n        count: function () {\n            return Math.max(0, this._data.length - this._source.startIndex);\n        },\n        getItem: function (idx) {\n            return this._data[idx + this._source.startIndex];\n        },\n        appendData: appendDataSimply\n    },\n\n    'arrayRows_row': {\n        pure: true,\n        count: function () {\n            var row = this._data[0];\n            return row ? Math.max(0, row.length - this._source.startIndex) : 0;\n        },\n        getItem: function (idx) {\n            idx += this._source.startIndex;\n            var item = [];\n            var data = this._data;\n            for (var i = 0; i < data.length; i++) {\n                var row = data[i];\n                item.push(row ? row[idx] : null);\n            }\n            return item;\n        },\n        appendData: function () {\n            throw new Error('Do not support appendData when set seriesLayoutBy: \"row\".');\n        }\n    },\n\n    'objectRows': {\n        pure: true,\n        count: countSimply,\n        getItem: getItemSimply,\n        appendData: appendDataSimply\n    },\n\n    'keyedColumns': {\n        pure: true,\n        count: function () {\n            var dimName = this._source.dimensionsDefine[0].name;\n            var col = this._data[dimName];\n            return col ? col.length : 0;\n        },\n        getItem: function (idx) {\n            var item = [];\n            var dims = this._source.dimensionsDefine;\n            for (var i = 0; i < dims.length; i++) {\n                var col = this._data[dims[i].name];\n                item.push(col ? col[idx] : null);\n            }\n            return item;\n        },\n        appendData: function (newData) {\n            var data = this._data;\n            each$1(newData, function (newCol, key) {\n                var oldCol = data[key] || (data[key] = []);\n                for (var i = 0; i < (newCol || []).length; i++) {\n                    oldCol.push(newCol[i]);\n                }\n            });\n        }\n    },\n\n    'original': {\n        count: countSimply,\n        getItem: getItemSimply,\n        appendData: appendDataSimply\n    },\n\n    'typedArray': {\n        persistent: false,\n        pure: true,\n        count: function () {\n            return this._data ? (this._data.length / this._dimSize) : 0;\n        },\n        getItem: function (idx, out) {\n            idx = idx - this._offset;\n            out = out || [];\n            var offset = this._dimSize * idx;\n            for (var i = 0; i < this._dimSize; i++) {\n                out[i] = this._data[offset + i];\n            }\n            return out;\n        },\n        appendData: function (newData) {\n            if (__DEV__) {\n                assert$1(\n                    isTypedArray(newData),\n                    'Added data must be TypedArray if data in initialization is TypedArray'\n                );\n            }\n\n            this._data = newData;\n        },\n\n        // Clean self if data is already used.\n        clean: function () {\n            // PENDING\n            this._offset += this.count();\n            this._data = null;\n        }\n    }\n};\n\nfunction countSimply() {\n    return this._data.length;\n}\nfunction getItemSimply(idx) {\n    return this._data[idx];\n}\nfunction appendDataSimply(newData) {\n    for (var i = 0; i < newData.length; i++) {\n        this._data.push(newData[i]);\n    }\n}\n\n\n\nvar rawValueGetters = {\n\n    arrayRows: getRawValueSimply,\n\n    objectRows: function (dataItem, dataIndex, dimIndex, dimName) {\n        return dimIndex != null ? dataItem[dimName] : dataItem;\n    },\n\n    keyedColumns: getRawValueSimply,\n\n    original: function (dataItem, dataIndex, dimIndex, dimName) {\n        // FIXME\n        // In some case (markpoint in geo (geo-map.html)), dataItem\n        // is {coord: [...]}\n        var value = getDataItemValue(dataItem);\n        return (dimIndex == null || !(value instanceof Array))\n            ? value\n            : value[dimIndex];\n    },\n\n    typedArray: getRawValueSimply\n};\n\nfunction getRawValueSimply(dataItem, dataIndex, dimIndex, dimName) {\n    return dimIndex != null ? dataItem[dimIndex] : dataItem;\n}\n\n\nvar defaultDimValueGetters = {\n\n    arrayRows: getDimValueSimply,\n\n    objectRows: function (dataItem, dimName, dataIndex, dimIndex) {\n        return converDataValue(dataItem[dimName], this._dimensionInfos[dimName]);\n    },\n\n    keyedColumns: getDimValueSimply,\n\n    original: function (dataItem, dimName, dataIndex, dimIndex) {\n        // Performance sensitive, do not use modelUtil.getDataItemValue.\n        // If dataItem is an plain object with no value field, the var `value`\n        // will be assigned with the object, but it will be tread correctly\n        // in the `convertDataValue`.\n        var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value);\n\n        // If any dataItem is like { value: 10 }\n        if (!this._rawData.pure && isDataItemOption(dataItem)) {\n            this.hasItemOption = true;\n        }\n        return converDataValue(\n            (value instanceof Array)\n                ? value[dimIndex]\n                // If value is a single number or something else not array.\n                : value,\n            this._dimensionInfos[dimName]\n        );\n    },\n\n    typedArray: function (dataItem, dimName, dataIndex, dimIndex) {\n        return dataItem[dimIndex];\n    }\n\n};\n\nfunction getDimValueSimply(dataItem, dimName, dataIndex, dimIndex) {\n    return converDataValue(dataItem[dimIndex], this._dimensionInfos[dimName]);\n}\n\n/**\n * This helper method convert value in data.\n * @param {string|number|Date} value\n * @param {Object|string} [dimInfo] If string (like 'x'), dimType defaults 'number'.\n *        If \"dimInfo.ordinalParseAndSave\", ordinal value can be parsed.\n */\nfunction converDataValue(value, dimInfo) {\n    // Performance sensitive.\n    var dimType = dimInfo && dimInfo.type;\n    if (dimType === 'ordinal') {\n        // If given value is a category string\n        var ordinalMeta = dimInfo && dimInfo.ordinalMeta;\n        return ordinalMeta\n            ? ordinalMeta.parseAndCollect(value)\n            : value;\n    }\n\n    if (dimType === 'time'\n        // spead up when using timestamp\n        && typeof value !== 'number'\n        && value != null\n        && value !== '-'\n    ) {\n        value = +parseDate(value);\n    }\n\n    // dimType defaults 'number'.\n    // If dimType is not ordinal and value is null or undefined or NaN or '-',\n    // parse to NaN.\n    return (value == null || value === '')\n        ? NaN\n        // If string (like '-'), using '+' parse to NaN\n        // If object, also parse to NaN\n        : +value;\n}\n\n// ??? FIXME can these logic be more neat: getRawValue, getRawDataItem,\n// Consider persistent.\n// Caution: why use raw value to display on label or tooltip?\n// A reason is to avoid format. For example time value we do not know\n// how to format is expected. More over, if stack is used, calculated\n// value may be 0.91000000001, which have brings trouble to display.\n// TODO: consider how to treat null/undefined/NaN when display?\n/**\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @param {string|number} [dim] dimName or dimIndex\n * @return {Array.<number>|string|number} can be null/undefined.\n */\nfunction retrieveRawValue(data, dataIndex, dim) {\n    if (!data) {\n        return;\n    }\n\n    // Consider data may be not persistent.\n    var dataItem = data.getRawDataItem(dataIndex);\n\n    if (dataItem == null) {\n        return;\n    }\n\n    var sourceFormat = data.getProvider().getSource().sourceFormat;\n    var dimName;\n    var dimIndex;\n\n    var dimInfo = data.getDimensionInfo(dim);\n    if (dimInfo) {\n        dimName = dimInfo.name;\n        dimIndex = dimInfo.index;\n    }\n\n    return rawValueGetters[sourceFormat](dataItem, dataIndex, dimIndex, dimName);\n}\n\n/**\n * Compatible with some cases (in pie, map) like:\n * data: [{name: 'xx', value: 5, selected: true}, ...]\n * where only sourceFormat is 'original' and 'objectRows' supported.\n *\n * ??? TODO\n * Supported detail options in data item when using 'arrayRows'.\n *\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @param {string} attr like 'selected'\n */\nfunction retrieveRawAttr(data, dataIndex, attr) {\n    if (!data) {\n        return;\n    }\n\n    var sourceFormat = data.getProvider().getSource().sourceFormat;\n\n    if (sourceFormat !== SOURCE_FORMAT_ORIGINAL\n        && sourceFormat !== SOURCE_FORMAT_OBJECT_ROWS\n    ) {\n        return;\n    }\n\n    var dataItem = data.getRawDataItem(dataIndex);\n    if (sourceFormat === SOURCE_FORMAT_ORIGINAL && !isObject$1(dataItem)) {\n        dataItem = null;\n    }\n    if (dataItem) {\n        return dataItem[attr];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DIMENSION_LABEL_REG = /\\{@(.+?)\\}/g;\n\n// PENDING A little ugly\nvar dataFormatMixin = {\n    /**\n     * Get params for formatter\n     * @param {number} dataIndex\n     * @param {string} [dataType]\n     * @return {Object}\n     */\n    getDataParams: function (dataIndex, dataType) {\n        var data = this.getData(dataType);\n        var rawValue = this.getRawValue(dataIndex, dataType);\n        var rawDataIndex = data.getRawIndex(dataIndex);\n        var name = data.getName(dataIndex);\n        var itemOpt = data.getRawDataItem(dataIndex);\n        var color = data.getItemVisual(dataIndex, 'color');\n        var tooltipModel = this.ecModel.getComponent('tooltip');\n        var renderModeOption = tooltipModel && tooltipModel.get('renderMode');\n        var renderMode = getTooltipRenderMode(renderModeOption);\n        var mainType = this.mainType;\n        var isSeries = mainType === 'series';\n\n        return {\n            componentType: mainType,\n            componentSubType: this.subType,\n            componentIndex: this.componentIndex,\n            seriesType: isSeries ? this.subType : null,\n            seriesIndex: this.seriesIndex,\n            seriesId: isSeries ? this.id : null,\n            seriesName: isSeries ? this.name : null,\n            name: name,\n            dataIndex: rawDataIndex,\n            data: itemOpt,\n            dataType: dataType,\n            value: rawValue,\n            color: color,\n            marker: getTooltipMarker({\n                color: color,\n                renderMode: renderMode\n            }),\n\n            // Param name list for mapping `a`, `b`, `c`, `d`, `e`\n            $vars: ['seriesName', 'name', 'value']\n        };\n    },\n\n    /**\n     * Format label\n     * @param {number} dataIndex\n     * @param {string} [status='normal'] 'normal' or 'emphasis'\n     * @param {string} [dataType]\n     * @param {number} [dimIndex]\n     * @param {string} [labelProp='label']\n     * @return {string} If not formatter, return null/undefined\n     */\n    getFormattedLabel: function (dataIndex, status, dataType, dimIndex, labelProp) {\n        status = status || 'normal';\n        var data = this.getData(dataType);\n        var itemModel = data.getItemModel(dataIndex);\n\n        var params = this.getDataParams(dataIndex, dataType);\n        if (dimIndex != null && (params.value instanceof Array)) {\n            params.value = params.value[dimIndex];\n        }\n\n        var formatter = itemModel.get(\n            status === 'normal'\n            ? [labelProp || 'label', 'formatter']\n            : [status, labelProp || 'label', 'formatter']\n        );\n\n        if (typeof formatter === 'function') {\n            params.status = status;\n            return formatter(params);\n        }\n        else if (typeof formatter === 'string') {\n            var str = formatTpl(formatter, params);\n\n            // Support 'aaa{@[3]}bbb{@product}ccc'.\n            // Do not support '}' in dim name util have to.\n            return str.replace(DIMENSION_LABEL_REG, function (origin, dim) {\n                var len = dim.length;\n                if (dim.charAt(0) === '[' && dim.charAt(len - 1) === ']') {\n                    dim = +dim.slice(1, len - 1); // Also: '[]' => 0\n                }\n                return retrieveRawValue(data, dataIndex, dim);\n            });\n        }\n    },\n\n    /**\n     * Get raw value in option\n     * @param {number} idx\n     * @param {string} [dataType]\n     * @return {Array|number|string}\n     */\n    getRawValue: function (idx, dataType) {\n        return retrieveRawValue(this.getData(dataType), idx);\n    },\n\n    /**\n     * Should be implemented.\n     * @param {number} dataIndex\n     * @param {boolean} [multipleSeries=false]\n     * @param {number} [dataType]\n     * @return {string} tooltip string\n     */\n    formatTooltip: function () {\n        // Empty function\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} define\n * @return See the return of `createTask`.\n */\nfunction createTask(define) {\n    return new Task(define);\n}\n\n/**\n * @constructor\n * @param {Object} define\n * @param {Function} define.reset Custom reset\n * @param {Function} [define.plan] Returns 'reset' indicate reset immediately.\n * @param {Function} [define.count] count is used to determin data task.\n * @param {Function} [define.onDirty] count is used to determin data task.\n */\nfunction Task(define) {\n    define = define || {};\n\n    this._reset = define.reset;\n    this._plan = define.plan;\n    this._count = define.count;\n    this._onDirty = define.onDirty;\n\n    this._dirty = true;\n\n    // Context must be specified implicitly, to\n    // avoid miss update context when model changed.\n    this.context;\n}\n\nvar taskProto = Task.prototype;\n\n/**\n * @param {Object} performArgs\n * @param {number} [performArgs.step] Specified step.\n * @param {number} [performArgs.skip] Skip customer perform call.\n * @param {number} [performArgs.modBy] Sampling window size.\n * @param {number} [performArgs.modDataCount] Sampling count.\n */\ntaskProto.perform = function (performArgs) {\n    var upTask = this._upstream;\n    var skip = performArgs && performArgs.skip;\n\n    // TODO some refactor.\n    // Pull data. Must pull data each time, because context.data\n    // may be updated by Series.setData.\n    if (this._dirty && upTask) {\n        var context = this.context;\n        context.data = context.outputData = upTask.context.outputData;\n    }\n\n    if (this.__pipeline) {\n        this.__pipeline.currentTask = this;\n    }\n\n    var planResult;\n    if (this._plan && !skip) {\n        planResult = this._plan(this.context);\n    }\n\n    // Support sharding by mod, which changes the render sequence and makes the rendered graphic\n    // elements uniformed distributed when progress, especially when moving or zooming.\n    var lastModBy = normalizeModBy(this._modBy);\n    var lastModDataCount = this._modDataCount || 0;\n    var modBy = normalizeModBy(performArgs && performArgs.modBy);\n    var modDataCount = performArgs && performArgs.modDataCount || 0;\n    if (lastModBy !== modBy || lastModDataCount !== modDataCount) {\n        planResult = 'reset';\n    }\n\n    function normalizeModBy(val) {\n        !(val >= 1) && (val = 1); // jshint ignore:line\n        return val;\n    }\n\n    var forceFirstProgress;\n    if (this._dirty || planResult === 'reset') {\n        this._dirty = false;\n        forceFirstProgress = reset(this, skip);\n    }\n\n    this._modBy = modBy;\n    this._modDataCount = modDataCount;\n\n    var step = performArgs && performArgs.step;\n\n    if (upTask) {\n\n        if (__DEV__) {\n            assert$1(upTask._outputDueEnd != null);\n        }\n        this._dueEnd = upTask._outputDueEnd;\n    }\n    // DataTask or overallTask\n    else {\n        if (__DEV__) {\n            assert$1(!this._progress || this._count);\n        }\n        this._dueEnd = this._count ? this._count(this.context) : Infinity;\n    }\n\n    // Note: Stubs, that its host overall task let it has progress, has progress.\n    // If no progress, pass index from upstream to downstream each time plan called.\n    if (this._progress) {\n        var start = this._dueIndex;\n        var end = Math.min(\n            step != null ? this._dueIndex + step : Infinity,\n            this._dueEnd\n        );\n\n        if (!skip && (forceFirstProgress || start < end)) {\n            var progress = this._progress;\n            if (isArray(progress)) {\n                for (var i = 0; i < progress.length; i++) {\n                    doProgress(this, progress[i], start, end, modBy, modDataCount);\n                }\n            }\n            else {\n                doProgress(this, progress, start, end, modBy, modDataCount);\n            }\n        }\n\n        this._dueIndex = end;\n        // If no `outputDueEnd`, assume that output data and\n        // input data is the same, so use `dueIndex` as `outputDueEnd`.\n        var outputDueEnd = this._settedOutputEnd != null\n            ? this._settedOutputEnd : end;\n\n        if (__DEV__) {\n            // ??? Can not rollback.\n            assert$1(outputDueEnd >= this._outputDueEnd);\n        }\n\n        this._outputDueEnd = outputDueEnd;\n    }\n    else {\n        // (1) Some overall task has no progress.\n        // (2) Stubs, that its host overall task do not let it has progress, has no progress.\n        // This should always be performed so it can be passed to downstream.\n        this._dueIndex = this._outputDueEnd = this._settedOutputEnd != null\n            ? this._settedOutputEnd : this._dueEnd;\n    }\n\n    return this.unfinished();\n};\n\nvar iterator = (function () {\n\n    var end;\n    var current;\n    var modBy;\n    var modDataCount;\n    var winCount;\n\n    var it = {\n        reset: function (s, e, sStep, sCount) {\n            current = s;\n            end = e;\n\n            modBy = sStep;\n            modDataCount = sCount;\n            winCount = Math.ceil(modDataCount / modBy);\n\n            it.next = (modBy > 1 && modDataCount > 0) ? modNext : sequentialNext;\n        }\n    };\n\n    return it;\n\n    function sequentialNext() {\n        return current < end ? current++ : null;\n    }\n\n    function modNext() {\n        var dataIndex = (current % winCount) * modBy + Math.ceil(current / winCount);\n        var result = current >= end\n            ? null\n            : dataIndex < modDataCount\n            ? dataIndex\n            // If modDataCount is smaller than data.count() (consider `appendData` case),\n            // Use normal linear rendering mode.\n            : current;\n        current++;\n        return result;\n    }\n})();\n\ntaskProto.dirty = function () {\n    this._dirty = true;\n    this._onDirty && this._onDirty(this.context);\n};\n\nfunction doProgress(taskIns, progress, start, end, modBy, modDataCount) {\n    iterator.reset(start, end, modBy, modDataCount);\n    taskIns._callingProgress = progress;\n    taskIns._callingProgress({\n        start: start, end: end, count: end - start, next: iterator.next\n    }, taskIns.context);\n}\n\nfunction reset(taskIns, skip) {\n    taskIns._dueIndex = taskIns._outputDueEnd = taskIns._dueEnd = 0;\n    taskIns._settedOutputEnd = null;\n\n    var progress;\n    var forceFirstProgress;\n\n    if (!skip && taskIns._reset) {\n        progress = taskIns._reset(taskIns.context);\n        if (progress && progress.progress) {\n            forceFirstProgress = progress.forceFirstProgress;\n            progress = progress.progress;\n        }\n        // To simplify no progress checking, array must has item.\n        if (isArray(progress) && !progress.length) {\n            progress = null;\n        }\n    }\n\n    taskIns._progress = progress;\n    taskIns._modBy = taskIns._modDataCount = null;\n\n    var downstream = taskIns._downstream;\n    downstream && downstream.dirty();\n\n    return forceFirstProgress;\n}\n\n/**\n * @return {boolean}\n */\ntaskProto.unfinished = function () {\n    return this._progress && this._dueIndex < this._dueEnd;\n};\n\n/**\n * @param {Object} downTask The downstream task.\n * @return {Object} The downstream task.\n */\ntaskProto.pipe = function (downTask) {\n    if (__DEV__) {\n        assert$1(downTask && !downTask._disposed && downTask !== this);\n    }\n\n    // If already downstream, do not dirty downTask.\n    if (this._downstream !== downTask || this._dirty) {\n        this._downstream = downTask;\n        downTask._upstream = this;\n        downTask.dirty();\n    }\n};\n\ntaskProto.dispose = function () {\n    if (this._disposed) {\n        return;\n    }\n\n    this._upstream && (this._upstream._downstream = null);\n    this._downstream && (this._downstream._upstream = null);\n\n    this._dirty = false;\n    this._disposed = true;\n};\n\ntaskProto.getUpstream = function () {\n    return this._upstream;\n};\n\ntaskProto.getDownstream = function () {\n    return this._downstream;\n};\n\ntaskProto.setOutputEnd = function (end) {\n    // This only happend in dataTask, dataZoom, map, currently.\n    // where dataZoom do not set end each time, but only set\n    // when reset. So we should record the setted end, in case\n    // that the stub of dataZoom perform again and earse the\n    // setted end by upstream.\n    this._outputDueEnd = this._settedOutputEnd = end;\n};\n\n\n///////////////////////////////////////////////////////////\n// For stream debug (Should be commented out after used!)\n// Usage: printTask(this, 'begin');\n// Usage: printTask(this, null, {someExtraProp});\n// function printTask(task, prefix, extra) {\n//     window.ecTaskUID == null && (window.ecTaskUID = 0);\n//     task.uidDebug == null && (task.uidDebug = `task_${window.ecTaskUID++}`);\n//     task.agent && task.agent.uidDebug == null && (task.agent.uidDebug = `task_${window.ecTaskUID++}`);\n//     var props = [];\n//     if (task.__pipeline) {\n//         var val = `${task.__idxInPipeline}/${task.__pipeline.tail.__idxInPipeline} ${task.agent ? '(stub)' : ''}`;\n//         props.push({text: 'idx', value: val});\n//     } else {\n//         var stubCount = 0;\n//         task.agentStubMap.each(() => stubCount++);\n//         props.push({text: 'idx', value: `overall (stubs: ${stubCount})`});\n//     }\n//     props.push({text: 'uid', value: task.uidDebug});\n//     if (task.__pipeline) {\n//         props.push({text: 'pid', value: task.__pipeline.id});\n//         task.agent && props.push(\n//             {text: 'stubFor', value: task.agent.uidDebug}\n//         );\n//     }\n//     props.push(\n//         {text: 'dirty', value: task._dirty},\n//         {text: 'dueIndex', value: task._dueIndex},\n//         {text: 'dueEnd', value: task._dueEnd},\n//         {text: 'outputDueEnd', value: task._outputDueEnd}\n//     );\n//     if (extra) {\n//         Object.keys(extra).forEach(key => {\n//             props.push({text: key, value: extra[key]});\n//         });\n//     }\n//     var args = ['color: blue'];\n//     var msg = `%c[${prefix || 'T'}] %c` + props.map(item => (\n//         args.push('color: black', 'color: red'),\n//         `${item.text}: %c${item.value}`\n//     )).join('%c, ');\n//     console.log.apply(console, [msg].concat(args));\n//     // console.log(this);\n// }\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$4 = makeInner();\n\nvar SeriesModel = ComponentModel.extend({\n\n    type: 'series.__base__',\n\n    /**\n     * @readOnly\n     */\n    seriesIndex: 0,\n\n    // coodinateSystem will be injected in the echarts/CoordinateSystem\n    coordinateSystem: null,\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    defaultOption: null,\n\n    /**\n     * Data provided for legend\n     * @type {Function}\n     */\n    // PENDING\n    legendDataProvider: null,\n\n    /**\n     * Access path of color for visual\n     */\n    visualColorAccessPath: 'itemStyle.color',\n\n    /**\n     * Support merge layout params.\n     * Only support 'box' now (left/right/top/bottom/width/height).\n     * @type {string|Object} Object can be {ignoreSize: true}\n     * @readOnly\n     */\n    layoutMode: null,\n\n    init: function (option, parentModel, ecModel, extraOpt) {\n\n        /**\n         * @type {number}\n         * @readOnly\n         */\n        this.seriesIndex = this.componentIndex;\n\n        this.dataTask = createTask({\n            count: dataTaskCount,\n            reset: dataTaskReset\n        });\n        this.dataTask.context = {model: this};\n\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        prepareSource(this);\n\n\n        var data = this.getInitialData(option, ecModel);\n        wrapData(data, this);\n        this.dataTask.context.data = data;\n\n        if (__DEV__) {\n            assert$1(data, 'getInitialData returned invalid data.');\n        }\n\n        /**\n         * @type {module:echarts/data/List|module:echarts/data/Tree|module:echarts/data/Graph}\n         * @private\n         */\n        inner$4(this).dataBeforeProcessed = data;\n\n        // If we reverse the order (make data firstly, and then make\n        // dataBeforeProcessed by cloneShallow), cloneShallow will\n        // cause data.graph.data !== data when using\n        // module:echarts/data/Graph or module:echarts/data/Tree.\n        // See module:echarts/data/helper/linkList\n\n        // Theoretically, it is unreasonable to call `seriesModel.getData()` in the model\n        // init or merge stage, because the data can be restored. So we do not `restoreData`\n        // and `setData` here, which forbids calling `seriesModel.getData()` in this stage.\n        // Call `seriesModel.getRawData()` instead.\n        // this.restoreData();\n\n        autoSeriesName(this);\n    },\n\n    /**\n     * Util for merge default and theme to option\n     * @param  {Object} option\n     * @param  {module:echarts/model/Global} ecModel\n     */\n    mergeDefaultAndTheme: function (option, ecModel) {\n        var layoutMode = this.layoutMode;\n        var inputPositionParams = layoutMode\n            ? getLayoutParams(option) : {};\n\n        // Backward compat: using subType on theme.\n        // But if name duplicate between series subType\n        // (for example: parallel) add component mainType,\n        // add suffix 'Series'.\n        var themeSubType = this.subType;\n        if (ComponentModel.hasClass(themeSubType)) {\n            themeSubType += 'Series';\n        }\n        merge(\n            option,\n            ecModel.getTheme().get(this.subType)\n        );\n        merge(option, this.getDefaultOption());\n\n        // Default label emphasis `show`\n        defaultEmphasis(option, 'label', ['show']);\n\n        this.fillDataTextStyle(option.data);\n\n        if (layoutMode) {\n            mergeLayoutParam(option, inputPositionParams, layoutMode);\n        }\n    },\n\n    mergeOption: function (newSeriesOption, ecModel) {\n        // this.settingTask.dirty();\n\n        newSeriesOption = merge(this.option, newSeriesOption, true);\n        this.fillDataTextStyle(newSeriesOption.data);\n\n        var layoutMode = this.layoutMode;\n        if (layoutMode) {\n            mergeLayoutParam(this.option, newSeriesOption, layoutMode);\n        }\n\n        prepareSource(this);\n\n        var data = this.getInitialData(newSeriesOption, ecModel);\n        wrapData(data, this);\n        this.dataTask.dirty();\n        this.dataTask.context.data = data;\n\n        inner$4(this).dataBeforeProcessed = data;\n\n        autoSeriesName(this);\n    },\n\n    fillDataTextStyle: function (data) {\n        // Default data label emphasis `show`\n        // FIXME Tree structure data ?\n        // FIXME Performance ?\n        if (data && !isTypedArray(data)) {\n            var props = ['show'];\n            for (var i = 0; i < data.length; i++) {\n                if (data[i] && data[i].label) {\n                    defaultEmphasis(data[i], 'label', props);\n                }\n            }\n        }\n    },\n\n    /**\n     * Init a data structure from data related option in series\n     * Must be overwritten\n     */\n    getInitialData: function () {},\n\n    /**\n     * Append data to list\n     * @param {Object} params\n     * @param {Array|TypedArray} params.data\n     */\n    appendData: function (params) {\n        // FIXME ???\n        // (1) If data from dataset, forbidden append.\n        // (2) support append data of dataset.\n        var data = this.getRawData();\n        data.appendData(params.data);\n    },\n\n    /**\n     * Consider some method like `filter`, `map` need make new data,\n     * We should make sure that `seriesModel.getData()` get correct\n     * data in the stream procedure. So we fetch data from upstream\n     * each time `task.perform` called.\n     * @param {string} [dataType]\n     * @return {module:echarts/data/List}\n     */\n    getData: function (dataType) {\n        var task = getCurrentTask(this);\n        if (task) {\n            var data = task.context.data;\n            return dataType == null ? data : data.getLinkedData(dataType);\n        }\n        else {\n            // When series is not alive (that may happen when click toolbox\n            // restore or setOption with not merge mode), series data may\n            // be still need to judge animation or something when graphic\n            // elements want to know whether fade out.\n            return inner$4(this).data;\n        }\n    },\n\n    /**\n     * @param {module:echarts/data/List} data\n     */\n    setData: function (data) {\n        var task = getCurrentTask(this);\n        if (task) {\n            var context = task.context;\n            // Consider case: filter, data sample.\n            if (context.data !== data && task.modifyOutputEnd) {\n                task.setOutputEnd(data.count());\n            }\n            context.outputData = data;\n            // Caution: setData should update context.data,\n            // Because getData may be called multiply in a\n            // single stage and expect to get the data just\n            // set. (For example, AxisProxy, x y both call\n            // getData and setDate sequentially).\n            // So the context.data should be fetched from\n            // upstream each time when a stage starts to be\n            // performed.\n            if (task !== this.dataTask) {\n                context.data = data;\n            }\n        }\n        inner$4(this).data = data;\n    },\n\n    /**\n     * @see {module:echarts/data/helper/sourceHelper#getSource}\n     * @return {module:echarts/data/Source} source\n     */\n    getSource: function () {\n        return getSource(this);\n    },\n\n    /**\n     * Get data before processed\n     * @return {module:echarts/data/List}\n     */\n    getRawData: function () {\n        return inner$4(this).dataBeforeProcessed;\n    },\n\n    /**\n     * Get base axis if has coordinate system and has axis.\n     * By default use coordSys.getBaseAxis();\n     * Can be overrided for some chart.\n     * @return {type} description\n     */\n    getBaseAxis: function () {\n        var coordSys = this.coordinateSystem;\n        return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis();\n    },\n\n    // FIXME\n    /**\n     * Default tooltip formatter\n     *\n     * @param {number} dataIndex\n     * @param {boolean} [multipleSeries=false]\n     * @param {number} [dataType]\n     * @param {string} [renderMode='html'] valid values: 'html' and 'richText'.\n     *                                     'html' is used for rendering tooltip in extra DOM form, and the result\n     *                                     string is used as DOM HTML content.\n     *                                     'richText' is used for rendering tooltip in rich text form, for those where\n     *                                     DOM operation is not supported.\n     * @return {Object} formatted tooltip with `html` and `markers`\n     */\n    formatTooltip: function (dataIndex, multipleSeries, dataType, renderMode) {\n\n        var series = this;\n        renderMode = renderMode || 'html';\n        var newLine = renderMode === 'html' ? '<br/>' : '\\n';\n        var isRichText = renderMode === 'richText';\n        var markers = {};\n        var markerId = 0;\n\n        function formatArrayValue(value) {\n            // ??? TODO refactor these logic.\n            // check: category-no-encode-has-axis-data in dataset.html\n            var vertially = reduce(value, function (vertially, val, idx) {\n                var dimItem = data.getDimensionInfo(idx);\n                return vertially |= dimItem && dimItem.tooltip !== false && dimItem.displayName != null;\n            }, 0);\n\n            var result = [];\n\n            tooltipDims.length\n                ? each$1(tooltipDims, function (dim) {\n                    setEachItem(retrieveRawValue(data, dataIndex, dim), dim);\n                })\n                // By default, all dims is used on tooltip.\n                : each$1(value, setEachItem);\n\n            function setEachItem(val, dim) {\n                var dimInfo = data.getDimensionInfo(dim);\n                // If `dimInfo.tooltip` is not set, show tooltip.\n                if (!dimInfo || dimInfo.otherDims.tooltip === false) {\n                    return;\n                }\n                var dimType = dimInfo.type;\n                var markName = 'sub' + series.seriesIndex + 'at' + markerId;\n                var dimHead = getTooltipMarker({\n                    color: color,\n                    type: 'subItem',\n                    renderMode: renderMode,\n                    markerId: markName\n                });\n\n                var dimHeadStr = typeof dimHead === 'string' ? dimHead : dimHead.content;\n                var valStr = (vertially\n                        ? dimHeadStr + encodeHTML(dimInfo.displayName || '-') + ': '\n                        : ''\n                    )\n                    // FIXME should not format time for raw data?\n                    + encodeHTML(dimType === 'ordinal'\n                        ? val + ''\n                        : dimType === 'time'\n                        ? (multipleSeries ? '' : formatTime('yyyy/MM/dd hh:mm:ss', val))\n                        : addCommas(val)\n                    );\n                valStr && result.push(valStr);\n\n                if (isRichText) {\n                    markers[markName] = color;\n                    ++markerId;\n                }\n            }\n\n            var newLine = vertially ? (isRichText ? '\\n' : '<br/>') : '';\n            var content = newLine + result.join(newLine || ', ');\n            return {\n                renderMode: renderMode,\n                content: content,\n                style: markers\n            };\n        }\n\n        function formatSingleValue(val) {\n            // return encodeHTML(addCommas(val));\n            return {\n                renderMode: renderMode,\n                content: encodeHTML(addCommas(val)),\n                style: markers\n            };\n        }\n\n        var data = this.getData();\n        var tooltipDims = data.mapDimension('defaultedTooltip', true);\n        var tooltipDimLen = tooltipDims.length;\n        var value = this.getRawValue(dataIndex);\n        var isValueArr = isArray(value);\n\n        var color = data.getItemVisual(dataIndex, 'color');\n        if (isObject$1(color) && color.colorStops) {\n            color = (color.colorStops[0] || {}).color;\n        }\n        color = color || 'transparent';\n\n        // Complicated rule for pretty tooltip.\n        var formattedValue = (tooltipDimLen > 1 || (isValueArr && !tooltipDimLen))\n            ? formatArrayValue(value)\n            : tooltipDimLen\n            ? formatSingleValue(retrieveRawValue(data, dataIndex, tooltipDims[0]))\n            : formatSingleValue(isValueArr ? value[0] : value);\n        var content = formattedValue.content;\n\n        var markName = series.seriesIndex + 'at' + markerId;\n        var colorEl = getTooltipMarker({\n            color: color,\n            type: 'item',\n            renderMode: renderMode,\n            markerId: markName\n        });\n        markers[markName] = color;\n        ++markerId;\n\n        var name = data.getName(dataIndex);\n\n        var seriesName = this.name;\n        if (!isNameSpecified(this)) {\n            seriesName = '';\n        }\n        seriesName = seriesName\n            ? encodeHTML(seriesName) + (!multipleSeries ? newLine : ': ')\n            : '';\n\n        var colorStr = typeof colorEl === 'string' ? colorEl : colorEl.content;\n        var html = !multipleSeries\n            ? seriesName + colorStr\n                + (name\n                    ? encodeHTML(name) + ': ' + content\n                    : content\n                )\n            : colorStr + seriesName + content;\n\n        return {\n            html: html,\n            markers: markers\n        };\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isAnimationEnabled: function () {\n        if (env$1.node) {\n            return false;\n        }\n\n        var animationEnabled = this.getShallow('animation');\n        if (animationEnabled) {\n            if (this.getData().count() > this.getShallow('animationThreshold')) {\n                animationEnabled = false;\n            }\n        }\n        return animationEnabled;\n    },\n\n    restoreData: function () {\n        this.dataTask.dirty();\n    },\n\n    getColorFromPalette: function (name, scope, requestColorNum) {\n        var ecModel = this.ecModel;\n        // PENDING\n        var color = colorPaletteMixin.getColorFromPalette.call(this, name, scope, requestColorNum);\n        if (!color) {\n            color = ecModel.getColorFromPalette(name, scope, requestColorNum);\n        }\n        return color;\n    },\n\n    /**\n     * Use `data.mapDimension(coordDim, true)` instead.\n     * @deprecated\n     */\n    coordDimToDataDim: function (coordDim) {\n        return this.getRawData().mapDimension(coordDim, true);\n    },\n\n    /**\n     * Get progressive rendering count each step\n     * @return {number}\n     */\n    getProgressive: function () {\n        return this.get('progressive');\n    },\n\n    /**\n     * Get progressive rendering count each step\n     * @return {number}\n     */\n    getProgressiveThreshold: function () {\n        return this.get('progressiveThreshold');\n    },\n\n    /**\n     * Get data indices for show tooltip content. See tooltip.\n     * @abstract\n     * @param {Array.<string>|string} dim\n     * @param {Array.<number>} value\n     * @param {module:echarts/coord/single/SingleAxis} baseAxis\n     * @return {Object} {dataIndices, nestestValue}.\n     */\n    getAxisTooltipData: null,\n\n    /**\n     * See tooltip.\n     * @abstract\n     * @param {number} dataIndex\n     * @return {Array.<number>} Point of tooltip. null/undefined can be returned.\n     */\n    getTooltipPosition: null,\n\n    /**\n     * @see {module:echarts/stream/Scheduler}\n     */\n    pipeTask: null,\n\n    /**\n     * Convinient for override in extended class.\n     * @protected\n     * @type {Function}\n     */\n    preventIncremental: null,\n\n    /**\n     * @public\n     * @readOnly\n     * @type {Object}\n     */\n    pipelineContext: null\n\n});\n\n\nmixin(SeriesModel, dataFormatMixin);\nmixin(SeriesModel, colorPaletteMixin);\n\n/**\n * MUST be called after `prepareSource` called\n * Here we need to make auto series, especially for auto legend. But we\n * do not modify series.name in option to avoid side effects.\n */\nfunction autoSeriesName(seriesModel) {\n    // User specified name has higher priority, otherwise it may cause\n    // series can not be queried unexpectedly.\n    var name = seriesModel.name;\n    if (!isNameSpecified(seriesModel)) {\n        seriesModel.name = getSeriesAutoName(seriesModel) || name;\n    }\n}\n\nfunction getSeriesAutoName(seriesModel) {\n    var data = seriesModel.getRawData();\n    var dataDims = data.mapDimension('seriesName', true);\n    var nameArr = [];\n    each$1(dataDims, function (dataDim) {\n        var dimInfo = data.getDimensionInfo(dataDim);\n        dimInfo.displayName && nameArr.push(dimInfo.displayName);\n    });\n    return nameArr.join(' ');\n}\n\nfunction dataTaskCount(context) {\n    return context.model.getRawData().count();\n}\n\nfunction dataTaskReset(context) {\n    var seriesModel = context.model;\n    seriesModel.setData(seriesModel.getRawData().cloneShallow());\n    return dataTaskProgress;\n}\n\nfunction dataTaskProgress(param, context) {\n    // Avoid repead cloneShallow when data just created in reset.\n    if (param.end > context.outputData.count()) {\n        context.model.getRawData().cloneShallow(context.outputData);\n    }\n}\n\n// TODO refactor\nfunction wrapData(data, seriesModel) {\n    each$1(data.CHANGABLE_METHODS, function (methodName) {\n        data.wrapMethod(methodName, curry(onDataSelfChange, seriesModel));\n    });\n}\n\nfunction onDataSelfChange(seriesModel) {\n    var task = getCurrentTask(seriesModel);\n    if (task) {\n        // Consider case: filter, selectRange\n        task.setOutputEnd(this.count());\n    }\n}\n\nfunction getCurrentTask(seriesModel) {\n    var scheduler = (seriesModel.ecModel || {}).scheduler;\n    var pipeline = scheduler && scheduler.getPipeline(seriesModel.uid);\n\n    if (pipeline) {\n        // When pipline finished, the currrentTask keep the last\n        // task (renderTask).\n        var task = pipeline.currentTask;\n        if (task) {\n            var agentStubMap = task.agentStubMap;\n            if (agentStubMap) {\n                task = agentStubMap.get(seriesModel.uid);\n            }\n        }\n        return task;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar Component$1 = function () {\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.uid = getUID('viewComponent');\n};\n\nComponent$1.prototype = {\n\n    constructor: Component$1,\n\n    init: function (ecModel, api) {},\n\n    render: function (componentModel, ecModel, api, payload) {},\n\n    dispose: function () {},\n\n    /**\n     * @param {string} eventType\n     * @param {Object} query\n     * @param {module:zrender/Element} targetEl\n     * @param {Object} packedEvent\n     * @return {boolen} Pass only when return `true`.\n     */\n    filterForExposedEvent: null\n\n};\n\nvar componentProto = Component$1.prototype;\ncomponentProto.updateView\n    = componentProto.updateLayout\n    = componentProto.updateVisual\n    = function (seriesModel, ecModel, api, payload) {\n        // Do nothing;\n    };\n// Enable Component.extend.\nenableClassExtend(Component$1);\n\n// Enable capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(Component$1, {registerWhenExtend: true});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @return {string} If large mode changed, return string 'reset';\n */\nvar createRenderPlanner = function () {\n    var inner = makeInner();\n\n    return function (seriesModel) {\n        var fields = inner(seriesModel);\n        var pipelineContext = seriesModel.pipelineContext;\n\n        var originalLarge = fields.large;\n        var originalProgressive = fields.progressiveRender;\n\n        var large = fields.large = pipelineContext.large;\n        var progressive = fields.progressiveRender = pipelineContext.progressiveRender;\n\n        return !!((originalLarge ^ large) || (originalProgressive ^ progressive)) && 'reset';\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$5 = makeInner();\nvar renderPlanner = createRenderPlanner();\n\nfunction Chart() {\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.uid = getUID('viewChart');\n\n    this.renderTask = createTask({\n        plan: renderTaskPlan,\n        reset: renderTaskReset\n    });\n    this.renderTask.context = {view: this};\n}\n\nChart.prototype = {\n\n    type: 'chart',\n\n    /**\n     * Init the chart.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    init: function (ecModel, api) {},\n\n    /**\n     * Render the chart.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    render: function (seriesModel, ecModel, api, payload) {},\n\n    /**\n     * Highlight series or specified data item.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    highlight: function (seriesModel, ecModel, api, payload) {\n        toggleHighlight(seriesModel.getData(), payload, 'emphasis');\n    },\n\n    /**\n     * Downplay series or specified data item.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    downplay: function (seriesModel, ecModel, api, payload) {\n        toggleHighlight(seriesModel.getData(), payload, 'normal');\n    },\n\n    /**\n     * Remove self.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    remove: function (ecModel, api) {\n        this.group.removeAll();\n    },\n\n    /**\n     * Dispose self.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    dispose: function () {},\n\n    /**\n     * Rendering preparation in progressive mode.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    incrementalPrepareRender: null,\n\n    /**\n     * Render in progressive mode.\n     * @param  {Object} params See taskParams in `stream/task.js`\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    incrementalRender: null,\n\n    /**\n     * Update transform directly.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     * @return {Object} {update: true}\n     */\n    updateTransform: null,\n\n    /**\n     * The view contains the given point.\n     * @interface\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    // containPoint: function () {}\n\n    /**\n     * @param {string} eventType\n     * @param {Object} query\n     * @param {module:zrender/Element} targetEl\n     * @param {Object} packedEvent\n     * @return {boolen} Pass only when return `true`.\n     */\n    filterForExposedEvent: null\n\n};\n\nvar chartProto = Chart.prototype;\nchartProto.updateView\n    = chartProto.updateLayout\n    = chartProto.updateVisual\n    = function (seriesModel, ecModel, api, payload) {\n        this.render(seriesModel, ecModel, api, payload);\n    };\n\n/**\n * Set state of single element\n * @param  {module:zrender/Element} el\n * @param  {string} state\n */\nfunction elSetState(el, state) {\n    if (el) {\n        el.trigger(state);\n        if (el.type === 'group') {\n            for (var i = 0; i < el.childCount(); i++) {\n                elSetState(el.childAt(i), state);\n            }\n        }\n    }\n}\n/**\n * @param  {module:echarts/data/List} data\n * @param  {Object} payload\n * @param  {string} state 'normal'|'emphasis'\n */\nfunction toggleHighlight(data, payload, state) {\n    var dataIndex = queryDataIndex(data, payload);\n\n    if (dataIndex != null) {\n        each$1(normalizeToArray(dataIndex), function (dataIdx) {\n            elSetState(data.getItemGraphicEl(dataIdx), state);\n        });\n    }\n    else {\n        data.eachItemGraphicEl(function (el) {\n            elSetState(el, state);\n        });\n    }\n}\n\n// Enable Chart.extend.\nenableClassExtend(Chart, ['dispose']);\n\n// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(Chart, {registerWhenExtend: true});\n\nChart.markUpdateMethod = function (payload, methodName) {\n    inner$5(payload).updateMethod = methodName;\n};\n\nfunction renderTaskPlan(context) {\n    return renderPlanner(context.model);\n}\n\nfunction renderTaskReset(context) {\n    var seriesModel = context.model;\n    var ecModel = context.ecModel;\n    var api = context.api;\n    var payload = context.payload;\n    // ???! remove updateView updateVisual\n    var progressiveRender = seriesModel.pipelineContext.progressiveRender;\n    var view = context.view;\n\n    var updateMethod = payload && inner$5(payload).updateMethod;\n    var methodName = progressiveRender\n        ? 'incrementalPrepareRender'\n        : (updateMethod && view[updateMethod])\n        ? updateMethod\n        // `appendData` is also supported when data amount\n        // is less than progressive threshold.\n        : 'render';\n\n    if (methodName !== 'render') {\n        view[methodName](seriesModel, ecModel, api, payload);\n    }\n\n    return progressMethodMap[methodName];\n}\n\nvar progressMethodMap = {\n    incrementalPrepareRender: {\n        progress: function (params, context) {\n            context.view.incrementalRender(\n                params, context.model, context.ecModel, context.api, context.payload\n            );\n        }\n    },\n    render: {\n        // Put view.render in `progress` to support appendData. But in this case\n        // view.render should not be called in reset, otherwise it will be called\n        // twise. Use `forceFirstProgress` to make sure that view.render is called\n        // in any cases.\n        forceFirstProgress: true,\n        progress: function (params, context) {\n            context.view.render(\n                context.model, context.ecModel, context.api, context.payload\n            );\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar ORIGIN_METHOD = '\\0__throttleOriginMethod';\nvar RATE = '\\0__throttleRate';\nvar THROTTLE_TYPE = '\\0__throttleType';\n\n/**\n * @public\n * @param {(Function)} fn\n * @param {number} [delay=0] Unit: ms.\n * @param {boolean} [debounce=false]\n *        true: If call interval less than `delay`, only the last call works.\n *        false: If call interval less than `delay, call works on fixed rate.\n * @return {(Function)} throttled fn.\n */\nfunction throttle(fn, delay, debounce) {\n\n    var currCall;\n    var lastCall = 0;\n    var lastExec = 0;\n    var timer = null;\n    var diff;\n    var scope;\n    var args;\n    var debounceNextCall;\n\n    delay = delay || 0;\n\n    function exec() {\n        lastExec = (new Date()).getTime();\n        timer = null;\n        fn.apply(scope, args || []);\n    }\n\n    var cb = function () {\n        currCall = (new Date()).getTime();\n        scope = this;\n        args = arguments;\n        var thisDelay = debounceNextCall || delay;\n        var thisDebounce = debounceNextCall || debounce;\n        debounceNextCall = null;\n        diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay;\n\n        clearTimeout(timer);\n\n        // Here we should make sure that: the `exec` SHOULD NOT be called later\n        // than a new call of `cb`, that is, preserving the command order. Consider\n        // calculating \"scale rate\" when roaming as an example. When a call of `cb`\n        // happens, either the `exec` is called dierectly, or the call is delayed.\n        // But the delayed call should never be later than next call of `cb`. Under\n        // this assurance, we can simply update view state each time `dispatchAction`\n        // triggered by user roaming, but not need to add extra code to avoid the\n        // state being \"rolled-back\".\n        if (thisDebounce) {\n            timer = setTimeout(exec, thisDelay);\n        }\n        else {\n            if (diff >= 0) {\n                exec();\n            }\n            else {\n                timer = setTimeout(exec, -diff);\n            }\n        }\n\n        lastCall = currCall;\n    };\n\n    /**\n     * Clear throttle.\n     * @public\n     */\n    cb.clear = function () {\n        if (timer) {\n            clearTimeout(timer);\n            timer = null;\n        }\n    };\n\n    /**\n     * Enable debounce once.\n     */\n    cb.debounceNextCall = function (debounceDelay) {\n        debounceNextCall = debounceDelay;\n    };\n\n    return cb;\n}\n\n/**\n * Create throttle method or update throttle rate.\n *\n * @example\n * ComponentView.prototype.render = function () {\n *     ...\n *     throttle.createOrUpdate(\n *         this,\n *         '_dispatchAction',\n *         this.model.get('throttle'),\n *         'fixRate'\n *     );\n * };\n * ComponentView.prototype.remove = function () {\n *     throttle.clear(this, '_dispatchAction');\n * };\n * ComponentView.prototype.dispose = function () {\n *     throttle.clear(this, '_dispatchAction');\n * };\n *\n * @public\n * @param {Object} obj\n * @param {string} fnAttr\n * @param {number} [rate]\n * @param {string} [throttleType='fixRate'] 'fixRate' or 'debounce'\n * @return {Function} throttled function.\n */\nfunction createOrUpdate(obj, fnAttr, rate, throttleType) {\n    var fn = obj[fnAttr];\n\n    if (!fn) {\n        return;\n    }\n\n    var originFn = fn[ORIGIN_METHOD] || fn;\n    var lastThrottleType = fn[THROTTLE_TYPE];\n    var lastRate = fn[RATE];\n\n    if (lastRate !== rate || lastThrottleType !== throttleType) {\n        if (rate == null || !throttleType) {\n            return (obj[fnAttr] = originFn);\n        }\n\n        fn = obj[fnAttr] = throttle(\n            originFn, rate, throttleType === 'debounce'\n        );\n        fn[ORIGIN_METHOD] = originFn;\n        fn[THROTTLE_TYPE] = throttleType;\n        fn[RATE] = rate;\n    }\n\n    return fn;\n}\n\n/**\n * Clear throttle. Example see throttle.createOrUpdate.\n *\n * @public\n * @param {Object} obj\n * @param {string} fnAttr\n */\nfunction clear(obj, fnAttr) {\n    var fn = obj[fnAttr];\n    if (fn && fn[ORIGIN_METHOD]) {\n        obj[fnAttr] = fn[ORIGIN_METHOD];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar seriesColor = {\n    createOnAllSeries: true,\n    performRawSeries: true,\n    reset: function (seriesModel, ecModel) {\n        var data = seriesModel.getData();\n        var colorAccessPath = (seriesModel.visualColorAccessPath || 'itemStyle.color').split('.');\n        var color = seriesModel.get(colorAccessPath) // Set in itemStyle\n            || seriesModel.getColorFromPalette(\n                // TODO series count changed.\n                seriesModel.name, null, ecModel.getSeriesCount()\n            );  // Default color\n\n        // FIXME Set color function or use the platte color\n        data.setVisual('color', color);\n\n        // Only visible series has each data be visual encoded\n        if (!ecModel.isSeriesFiltered(seriesModel)) {\n            if (typeof color === 'function' && !(color instanceof Gradient)) {\n                data.each(function (idx) {\n                    data.setItemVisual(\n                        idx, 'color', color(seriesModel.getDataParams(idx))\n                    );\n                });\n            }\n\n            // itemStyle in each data item\n            var dataEach = function (data, idx) {\n                var itemModel = data.getItemModel(idx);\n                var color = itemModel.get(colorAccessPath, true);\n                if (color != null) {\n                    data.setItemVisual(idx, 'color', color);\n                }\n            };\n\n            return { dataEach: data.hasItemOption ? dataEach : null };\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar lang = {\n    toolbox: {\n        brush: {\n            title: {\n                rect: 'Box Select',\n                polygon: 'Lasso Select',\n                lineX: 'Horizontally Select',\n                lineY: 'Vertically Select',\n                keep: 'Keep Selections',\n                clear: 'Clear Selections'\n            }\n        },\n        dataView: {\n            title: 'Data View',\n            lang: ['Data View', 'Close', 'Refresh']\n        },\n        dataZoom: {\n            title: {\n                zoom: 'Zoom',\n                back: 'Zoom Reset'\n            }\n        },\n        magicType: {\n            title: {\n                line: 'Switch to Line Chart',\n                bar: 'Switch to Bar Chart',\n                stack: 'Stack',\n                tiled: 'Tile'\n            }\n        },\n        restore: {\n            title: 'Restore'\n        },\n        saveAsImage: {\n            title: 'Save as Image',\n            lang: ['Right Click to Save Image']\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar aria = function (dom, ecModel) {\n    var ariaModel = ecModel.getModel('aria');\n    if (!ariaModel.get('show')) {\n        return;\n    }\n    else if (ariaModel.get('description')) {\n        dom.setAttribute('aria-label', ariaModel.get('description'));\n        return;\n    }\n\n    var seriesCnt = 0;\n    ecModel.eachSeries(function (seriesModel, idx) {\n        ++seriesCnt;\n    }, this);\n\n    var maxDataCnt = ariaModel.get('data.maxCount') || 10;\n    var maxSeriesCnt = ariaModel.get('series.maxCount') || 10;\n    var displaySeriesCnt = Math.min(seriesCnt, maxSeriesCnt);\n\n    var ariaLabel;\n    if (seriesCnt < 1) {\n        // No series, no aria label\n        return;\n    }\n    else {\n        var title = getTitle();\n        if (title) {\n            ariaLabel = replace(getConfig('general.withTitle'), {\n                title: title\n            });\n        }\n        else {\n            ariaLabel = getConfig('general.withoutTitle');\n        }\n\n        var seriesLabels = [];\n        var prefix = seriesCnt > 1\n            ? 'series.multiple.prefix'\n            : 'series.single.prefix';\n        ariaLabel += replace(getConfig(prefix), { seriesCount: seriesCnt });\n\n        ecModel.eachSeries(function (seriesModel, idx) {\n            if (idx < displaySeriesCnt) {\n                var seriesLabel;\n\n                var seriesName = seriesModel.get('name');\n                var seriesTpl = 'series.'\n                    + (seriesCnt > 1 ? 'multiple' : 'single') + '.';\n                seriesLabel = getConfig(seriesName\n                    ? seriesTpl + 'withName'\n                    : seriesTpl + 'withoutName');\n\n                seriesLabel = replace(seriesLabel, {\n                    seriesId: seriesModel.seriesIndex,\n                    seriesName: seriesModel.get('name'),\n                    seriesType: getSeriesTypeName(seriesModel.subType)\n                });\n\n                var data = seriesModel.getData();\n                window.data = data;\n                if (data.count() > maxDataCnt) {\n                    // Show part of data\n                    seriesLabel += replace(getConfig('data.partialData'), {\n                        displayCnt: maxDataCnt\n                    });\n                }\n                else {\n                    seriesLabel += getConfig('data.allData');\n                }\n\n                var dataLabels = [];\n                for (var i = 0; i < data.count(); i++) {\n                    if (i < maxDataCnt) {\n                        var name = data.getName(i);\n                        var value = retrieveRawValue(data, i);\n                        dataLabels.push(\n                            replace(\n                                name\n                                    ? getConfig('data.withName')\n                                    : getConfig('data.withoutName'),\n                                {\n                                    name: name,\n                                    value: value\n                                }\n                            )\n                        );\n                    }\n                }\n                seriesLabel += dataLabels\n                    .join(getConfig('data.separator.middle'))\n                    + getConfig('data.separator.end');\n\n                seriesLabels.push(seriesLabel);\n            }\n        });\n\n        ariaLabel += seriesLabels\n            .join(getConfig('series.multiple.separator.middle'))\n            + getConfig('series.multiple.separator.end');\n\n        dom.setAttribute('aria-label', ariaLabel);\n    }\n\n    function replace(str, keyValues) {\n        if (typeof str !== 'string') {\n            return str;\n        }\n\n        var result = str;\n        each$1(keyValues, function (value, key) {\n            result = result.replace(\n                new RegExp('\\\\{\\\\s*' + key + '\\\\s*\\\\}', 'g'),\n                value\n            );\n        });\n        return result;\n    }\n\n    function getConfig(path) {\n        var userConfig = ariaModel.get(path);\n        if (userConfig == null) {\n            var pathArr = path.split('.');\n            var result = lang.aria;\n            for (var i = 0; i < pathArr.length; ++i) {\n                result = result[pathArr[i]];\n            }\n            return result;\n        }\n        else {\n            return userConfig;\n        }\n    }\n\n    function getTitle() {\n        var title = ecModel.getModel('title').option;\n        if (title && title.length) {\n            title = title[0];\n        }\n        return title && title.text;\n    }\n\n    function getSeriesTypeName(type) {\n        return lang.series.typeNames[type] || '自定义图';\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PI$1 = Math.PI;\n\n/**\n * @param {module:echarts/ExtensionAPI} api\n * @param {Object} [opts]\n * @param {string} [opts.text]\n * @param {string} [opts.color]\n * @param {string} [opts.textColor]\n * @return {module:zrender/Element}\n */\nvar loadingDefault = function (api, opts) {\n    opts = opts || {};\n    defaults(opts, {\n        text: 'loading',\n        color: '#c23531',\n        textColor: '#000',\n        maskColor: 'rgba(255, 255, 255, 0.8)',\n        zlevel: 0\n    });\n    var mask = new Rect({\n        style: {\n            fill: opts.maskColor\n        },\n        zlevel: opts.zlevel,\n        z: 10000\n    });\n    var arc = new Arc({\n        shape: {\n            startAngle: -PI$1 / 2,\n            endAngle: -PI$1 / 2 + 0.1,\n            r: 10\n        },\n        style: {\n            stroke: opts.color,\n            lineCap: 'round',\n            lineWidth: 5\n        },\n        zlevel: opts.zlevel,\n        z: 10001\n    });\n    var labelRect = new Rect({\n        style: {\n            fill: 'none',\n            text: opts.text,\n            textPosition: 'right',\n            textDistance: 10,\n            textFill: opts.textColor\n        },\n        zlevel: opts.zlevel,\n        z: 10001\n    });\n\n    arc.animateShape(true)\n        .when(1000, {\n            endAngle: PI$1 * 3 / 2\n        })\n        .start('circularInOut');\n    arc.animateShape(true)\n        .when(1000, {\n            startAngle: PI$1 * 3 / 2\n        })\n        .delay(300)\n        .start('circularInOut');\n\n    var group = new Group();\n    group.add(arc);\n    group.add(labelRect);\n    group.add(mask);\n    // Inject resize\n    group.resize = function () {\n        var cx = api.getWidth() / 2;\n        var cy = api.getHeight() / 2;\n        arc.setShape({\n            cx: cx,\n            cy: cy\n        });\n        var r = arc.shape.r;\n        labelRect.setShape({\n            x: cx - r,\n            y: cy - r,\n            width: r * 2,\n            height: r * 2\n        });\n\n        mask.setShape({\n            x: 0,\n            y: 0,\n            width: api.getWidth(),\n            height: api.getHeight()\n        });\n    };\n    group.resize();\n    return group;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/stream/Scheduler\n */\n\n/**\n * @constructor\n */\nfunction Scheduler(ecInstance, api, dataProcessorHandlers, visualHandlers) {\n    this.ecInstance = ecInstance;\n    this.api = api;\n    this.unfinished;\n\n    // Fix current processors in case that in some rear cases that\n    // processors might be registered after echarts instance created.\n    // Register processors incrementally for a echarts instance is\n    // not supported by this stream architecture.\n    var dataProcessorHandlers = this._dataProcessorHandlers = dataProcessorHandlers.slice();\n    var visualHandlers = this._visualHandlers = visualHandlers.slice();\n    this._allHandlers = dataProcessorHandlers.concat(visualHandlers);\n\n    /**\n     * @private\n     * @type {\n     *     [handlerUID: string]: {\n     *         seriesTaskMap?: {\n     *             [seriesUID: string]: Task\n     *         },\n     *         overallTask?: Task\n     *     }\n     * }\n     */\n    this._stageTaskMap = createHashMap();\n}\n\nvar proto = Scheduler.prototype;\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} payload\n */\nproto.restoreData = function (ecModel, payload) {\n    // TODO: Only restroe needed series and components, but not all components.\n    // Currently `restoreData` of all of the series and component will be called.\n    // But some independent components like `title`, `legend`, `graphic`, `toolbox`,\n    // `tooltip`, `axisPointer`, etc, do not need series refresh when `setOption`,\n    // and some components like coordinate system, axes, dataZoom, visualMap only\n    // need their target series refresh.\n    // (1) If we are implementing this feature some day, we should consider these cases:\n    // if a data processor depends on a component (e.g., dataZoomProcessor depends\n    // on the settings of `dataZoom`), it should be re-performed if the component\n    // is modified by `setOption`.\n    // (2) If a processor depends on sevral series, speicified by its `getTargetSeries`,\n    // it should be re-performed when the result array of `getTargetSeries` changed.\n    // We use `dependencies` to cover these issues.\n    // (3) How to update target series when coordinate system related components modified.\n\n    // TODO: simply the dirty mechanism? Check whether only the case here can set tasks dirty,\n    // and this case all of the tasks will be set as dirty.\n\n    ecModel.restoreData(payload);\n\n    // Theoretically an overall task not only depends on each of its target series, but also\n    // depends on all of the series.\n    // The overall task is not in pipeline, and `ecModel.restoreData` only set pipeline tasks\n    // dirty. If `getTargetSeries` of an overall task returns nothing, we should also ensure\n    // that the overall task is set as dirty and to be performed, otherwise it probably cause\n    // state chaos. So we have to set dirty of all of the overall tasks manually, otherwise it\n    // probably cause state chaos (consider `dataZoomProcessor`).\n    this._stageTaskMap.each(function (taskRecord) {\n        var overallTask = taskRecord.overallTask;\n        overallTask && overallTask.dirty();\n    });\n};\n\n// If seriesModel provided, incremental threshold is check by series data.\nproto.getPerformArgs = function (task, isBlock) {\n    // For overall task\n    if (!task.__pipeline) {\n        return;\n    }\n\n    var pipeline = this._pipelineMap.get(task.__pipeline.id);\n    var pCtx = pipeline.context;\n    var incremental = !isBlock\n        && pipeline.progressiveEnabled\n        && (!pCtx || pCtx.progressiveRender)\n        && task.__idxInPipeline > pipeline.blockIndex;\n\n    var step = incremental ? pipeline.step : null;\n    var modDataCount = pCtx && pCtx.modDataCount;\n    var modBy = modDataCount != null ? Math.ceil(modDataCount / step) : null;\n\n    return {step: step, modBy: modBy, modDataCount: modDataCount};\n};\n\nproto.getPipeline = function (pipelineId) {\n    return this._pipelineMap.get(pipelineId);\n};\n\n/**\n * Current, progressive rendering starts from visual and layout.\n * Always detect render mode in the same stage, avoiding that incorrect\n * detection caused by data filtering.\n * Caution:\n * `updateStreamModes` use `seriesModel.getData()`.\n */\nproto.updateStreamModes = function (seriesModel, view) {\n    var pipeline = this._pipelineMap.get(seriesModel.uid);\n    var data = seriesModel.getData();\n    var dataLen = data.count();\n\n    // `progressiveRender` means that can render progressively in each\n    // animation frame. Note that some types of series do not provide\n    // `view.incrementalPrepareRender` but support `chart.appendData`. We\n    // use the term `incremental` but not `progressive` to describe the\n    // case that `chart.appendData`.\n    var progressiveRender = pipeline.progressiveEnabled\n        && view.incrementalPrepareRender\n        && dataLen >= pipeline.threshold;\n\n    var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold');\n\n    // TODO: modDataCount should not updated if `appendData`, otherwise cause whole repaint.\n    // see `test/candlestick-large3.html`\n    var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null;\n\n    seriesModel.pipelineContext = pipeline.context = {\n        progressiveRender: progressiveRender,\n        modDataCount: modDataCount,\n        large: large\n    };\n};\n\nproto.restorePipelines = function (ecModel) {\n    var scheduler = this;\n    var pipelineMap = scheduler._pipelineMap = createHashMap();\n\n    ecModel.eachSeries(function (seriesModel) {\n        var progressive = seriesModel.getProgressive();\n        var pipelineId = seriesModel.uid;\n\n        pipelineMap.set(pipelineId, {\n            id: pipelineId,\n            head: null,\n            tail: null,\n            threshold: seriesModel.getProgressiveThreshold(),\n            progressiveEnabled: progressive\n                && !(seriesModel.preventIncremental && seriesModel.preventIncremental()),\n            blockIndex: -1,\n            step: Math.round(progressive || 700),\n            count: 0\n        });\n\n        pipe(scheduler, seriesModel, seriesModel.dataTask);\n    });\n};\n\nproto.prepareStageTasks = function () {\n    var stageTaskMap = this._stageTaskMap;\n    var ecModel = this.ecInstance.getModel();\n    var api = this.api;\n\n    each$1(this._allHandlers, function (handler) {\n        var record = stageTaskMap.get(handler.uid) || stageTaskMap.set(handler.uid, []);\n\n        handler.reset && createSeriesStageTask(this, handler, record, ecModel, api);\n        handler.overallReset && createOverallStageTask(this, handler, record, ecModel, api);\n    }, this);\n};\n\nproto.prepareView = function (view, model, ecModel, api) {\n    var renderTask = view.renderTask;\n    var context = renderTask.context;\n\n    context.model = model;\n    context.ecModel = ecModel;\n    context.api = api;\n\n    renderTask.__block = !view.incrementalPrepareRender;\n\n    pipe(this, model, renderTask);\n};\n\n\nproto.performDataProcessorTasks = function (ecModel, payload) {\n    // If we do not use `block` here, it should be considered when to update modes.\n    performStageTasks(this, this._dataProcessorHandlers, ecModel, payload, {block: true});\n};\n\n// opt\n// opt.visualType: 'visual' or 'layout'\n// opt.setDirty\nproto.performVisualTasks = function (ecModel, payload, opt) {\n    performStageTasks(this, this._visualHandlers, ecModel, payload, opt);\n};\n\nfunction performStageTasks(scheduler, stageHandlers, ecModel, payload, opt) {\n    opt = opt || {};\n    var unfinished;\n\n    each$1(stageHandlers, function (stageHandler, idx) {\n        if (opt.visualType && opt.visualType !== stageHandler.visualType) {\n            return;\n        }\n\n        var stageHandlerRecord = scheduler._stageTaskMap.get(stageHandler.uid);\n        var seriesTaskMap = stageHandlerRecord.seriesTaskMap;\n        var overallTask = stageHandlerRecord.overallTask;\n\n        if (overallTask) {\n            var overallNeedDirty;\n            var agentStubMap = overallTask.agentStubMap;\n            agentStubMap.each(function (stub) {\n                if (needSetDirty(opt, stub)) {\n                    stub.dirty();\n                    overallNeedDirty = true;\n                }\n            });\n            overallNeedDirty && overallTask.dirty();\n            updatePayload(overallTask, payload);\n            var performArgs = scheduler.getPerformArgs(overallTask, opt.block);\n            // Execute stubs firstly, which may set the overall task dirty,\n            // then execute the overall task. And stub will call seriesModel.setData,\n            // which ensures that in the overallTask seriesModel.getData() will not\n            // return incorrect data.\n            agentStubMap.each(function (stub) {\n                stub.perform(performArgs);\n            });\n            unfinished |= overallTask.perform(performArgs);\n        }\n        else if (seriesTaskMap) {\n            seriesTaskMap.each(function (task, pipelineId) {\n                if (needSetDirty(opt, task)) {\n                    task.dirty();\n                }\n                var performArgs = scheduler.getPerformArgs(task, opt.block);\n                performArgs.skip = !stageHandler.performRawSeries\n                    && ecModel.isSeriesFiltered(task.context.model);\n                updatePayload(task, payload);\n                unfinished |= task.perform(performArgs);\n            });\n        }\n    });\n\n    function needSetDirty(opt, task) {\n        return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id));\n    }\n\n    scheduler.unfinished |= unfinished;\n}\n\nproto.performSeriesTasks = function (ecModel) {\n    var unfinished;\n\n    ecModel.eachSeries(function (seriesModel) {\n        // Progress to the end for dataInit and dataRestore.\n        unfinished |= seriesModel.dataTask.perform();\n    });\n\n    this.unfinished |= unfinished;\n};\n\nproto.plan = function () {\n    // Travel pipelines, check block.\n    this._pipelineMap.each(function (pipeline) {\n        var task = pipeline.tail;\n        do {\n            if (task.__block) {\n                pipeline.blockIndex = task.__idxInPipeline;\n                break;\n            }\n            task = task.getUpstream();\n        }\n        while (task);\n    });\n};\n\nvar updatePayload = proto.updatePayload = function (task, payload) {\n    payload !== 'remain' && (task.context.payload = payload);\n};\n\nfunction createSeriesStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) {\n    var seriesTaskMap = stageHandlerRecord.seriesTaskMap\n        || (stageHandlerRecord.seriesTaskMap = createHashMap());\n    var seriesType = stageHandler.seriesType;\n    var getTargetSeries = stageHandler.getTargetSeries;\n\n    // If a stageHandler should cover all series, `createOnAllSeries` should be declared mandatorily,\n    // to avoid some typo or abuse. Otherwise if an extension do not specify a `seriesType`,\n    // it works but it may cause other irrelevant charts blocked.\n    if (stageHandler.createOnAllSeries) {\n        ecModel.eachRawSeries(create);\n    }\n    else if (seriesType) {\n        ecModel.eachRawSeriesByType(seriesType, create);\n    }\n    else if (getTargetSeries) {\n        getTargetSeries(ecModel, api).each(create);\n    }\n\n    function create(seriesModel) {\n        var pipelineId = seriesModel.uid;\n\n        // Init tasks for each seriesModel only once.\n        // Reuse original task instance.\n        var task = seriesTaskMap.get(pipelineId)\n            || seriesTaskMap.set(pipelineId, createTask({\n                plan: seriesTaskPlan,\n                reset: seriesTaskReset,\n                count: seriesTaskCount\n            }));\n        task.context = {\n            model: seriesModel,\n            ecModel: ecModel,\n            api: api,\n            useClearVisual: stageHandler.isVisual && !stageHandler.isLayout,\n            plan: stageHandler.plan,\n            reset: stageHandler.reset,\n            scheduler: scheduler\n        };\n        pipe(scheduler, seriesModel, task);\n    }\n\n    // Clear unused series tasks.\n    var pipelineMap = scheduler._pipelineMap;\n    seriesTaskMap.each(function (task, pipelineId) {\n        if (!pipelineMap.get(pipelineId)) {\n            task.dispose();\n            seriesTaskMap.removeKey(pipelineId);\n        }\n    });\n}\n\nfunction createOverallStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) {\n    var overallTask = stageHandlerRecord.overallTask = stageHandlerRecord.overallTask\n        // For overall task, the function only be called on reset stage.\n        || createTask({reset: overallTaskReset});\n\n    overallTask.context = {\n        ecModel: ecModel,\n        api: api,\n        overallReset: stageHandler.overallReset,\n        scheduler: scheduler\n    };\n\n    // Reuse orignal stubs.\n    var agentStubMap = overallTask.agentStubMap = overallTask.agentStubMap || createHashMap();\n\n    var seriesType = stageHandler.seriesType;\n    var getTargetSeries = stageHandler.getTargetSeries;\n    var overallProgress = true;\n    var modifyOutputEnd = stageHandler.modifyOutputEnd;\n\n    // An overall task with seriesType detected or has `getTargetSeries`, we add\n    // stub in each pipelines, it will set the overall task dirty when the pipeline\n    // progress. Moreover, to avoid call the overall task each frame (too frequent),\n    // we set the pipeline block.\n    if (seriesType) {\n        ecModel.eachRawSeriesByType(seriesType, createStub);\n    }\n    else if (getTargetSeries) {\n        getTargetSeries(ecModel, api).each(createStub);\n    }\n    // Otherwise, (usually it is legancy case), the overall task will only be\n    // executed when upstream dirty. Otherwise the progressive rendering of all\n    // pipelines will be disabled unexpectedly. But it still needs stubs to receive\n    // dirty info from upsteam.\n    else {\n        overallProgress = false;\n        each$1(ecModel.getSeries(), createStub);\n    }\n\n    function createStub(seriesModel) {\n        var pipelineId = seriesModel.uid;\n        var stub = agentStubMap.get(pipelineId);\n        if (!stub) {\n            stub = agentStubMap.set(pipelineId, createTask(\n                {reset: stubReset, onDirty: stubOnDirty}\n            ));\n            // When the result of `getTargetSeries` changed, the overallTask\n            // should be set as dirty and re-performed.\n            overallTask.dirty();\n        }\n        stub.context = {\n            model: seriesModel,\n            overallProgress: overallProgress,\n            modifyOutputEnd: modifyOutputEnd\n        };\n        stub.agent = overallTask;\n        stub.__block = overallProgress;\n\n        pipe(scheduler, seriesModel, stub);\n    }\n\n    // Clear unused stubs.\n    var pipelineMap = scheduler._pipelineMap;\n    agentStubMap.each(function (stub, pipelineId) {\n        if (!pipelineMap.get(pipelineId)) {\n            stub.dispose();\n            // When the result of `getTargetSeries` changed, the overallTask\n            // should be set as dirty and re-performed.\n            overallTask.dirty();\n            agentStubMap.removeKey(pipelineId);\n        }\n    });\n}\n\nfunction overallTaskReset(context) {\n    context.overallReset(\n        context.ecModel, context.api, context.payload\n    );\n}\n\nfunction stubReset(context, upstreamContext) {\n    return context.overallProgress && stubProgress;\n}\n\nfunction stubProgress() {\n    this.agent.dirty();\n    this.getDownstream().dirty();\n}\n\nfunction stubOnDirty() {\n    this.agent && this.agent.dirty();\n}\n\nfunction seriesTaskPlan(context) {\n    return context.plan && context.plan(\n        context.model, context.ecModel, context.api, context.payload\n    );\n}\n\nfunction seriesTaskReset(context) {\n    if (context.useClearVisual) {\n        context.data.clearAllVisual();\n    }\n    var resetDefines = context.resetDefines = normalizeToArray(context.reset(\n        context.model, context.ecModel, context.api, context.payload\n    ));\n    return resetDefines.length > 1\n        ? map(resetDefines, function (v, idx) {\n            return makeSeriesTaskProgress(idx);\n        })\n        : singleSeriesTaskProgress;\n}\n\nvar singleSeriesTaskProgress = makeSeriesTaskProgress(0);\n\nfunction makeSeriesTaskProgress(resetDefineIdx) {\n    return function (params, context) {\n        var data = context.data;\n        var resetDefine = context.resetDefines[resetDefineIdx];\n\n        if (resetDefine && resetDefine.dataEach) {\n            for (var i = params.start; i < params.end; i++) {\n                resetDefine.dataEach(data, i);\n            }\n        }\n        else if (resetDefine && resetDefine.progress) {\n            resetDefine.progress(params, data);\n        }\n    };\n}\n\nfunction seriesTaskCount(context) {\n    return context.data.count();\n}\n\nfunction pipe(scheduler, seriesModel, task) {\n    var pipelineId = seriesModel.uid;\n    var pipeline = scheduler._pipelineMap.get(pipelineId);\n    !pipeline.head && (pipeline.head = task);\n    pipeline.tail && pipeline.tail.pipe(task);\n    pipeline.tail = task;\n    task.__idxInPipeline = pipeline.count++;\n    task.__pipeline = pipeline;\n}\n\nScheduler.wrapStageHandler = function (stageHandler, visualType) {\n    if (isFunction$1(stageHandler)) {\n        stageHandler = {\n            overallReset: stageHandler,\n            seriesType: detectSeriseType(stageHandler)\n        };\n    }\n\n    stageHandler.uid = getUID('stageHandler');\n    visualType && (stageHandler.visualType = visualType);\n\n    return stageHandler;\n};\n\n\n\n/**\n * Only some legacy stage handlers (usually in echarts extensions) are pure function.\n * To ensure that they can work normally, they should work in block mode, that is,\n * they should not be started util the previous tasks finished. So they cause the\n * progressive rendering disabled. We try to detect the series type, to narrow down\n * the block range to only the series type they concern, but not all series.\n */\nfunction detectSeriseType(legacyFunc) {\n    seriesType = null;\n    try {\n        // Assume there is no async when calling `eachSeriesByType`.\n        legacyFunc(ecModelMock, apiMock);\n    }\n    catch (e) {\n    }\n    return seriesType;\n}\n\nvar ecModelMock = {};\nvar apiMock = {};\nvar seriesType;\n\nmockMethods(ecModelMock, GlobalModel);\nmockMethods(apiMock, ExtensionAPI);\necModelMock.eachSeriesByType = ecModelMock.eachRawSeriesByType = function (type) {\n    seriesType = type;\n};\necModelMock.eachComponent = function (cond) {\n    if (cond.mainType === 'series' && cond.subType) {\n        seriesType = cond.subType;\n    }\n};\n\nfunction mockMethods(target, Clz) {\n    /* eslint-disable */\n    for (var name in Clz.prototype) {\n        // Do not use hasOwnProperty\n        target[name] = noop;\n    }\n    /* eslint-enable */\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar colorAll = [\n    '#37A2DA', '#32C5E9', '#67E0E3', '#9FE6B8', '#FFDB5C', '#ff9f7f',\n    '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF'\n];\n\nvar lightTheme = {\n\n    color: colorAll,\n\n    colorLayer: [\n        ['#37A2DA', '#ffd85c', '#fd7b5f'],\n        ['#37A2DA', '#67E0E3', '#FFDB5C', '#ff9f7f', '#E062AE', '#9d96f5'],\n        ['#37A2DA', '#32C5E9', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#e7bcf3', '#8378EA', '#96BFFF'],\n        colorAll\n    ]\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar contrastColor = '#eee';\nvar axisCommon = function () {\n    return {\n        axisLine: {\n            lineStyle: {\n                color: contrastColor\n            }\n        },\n        axisTick: {\n            lineStyle: {\n                color: contrastColor\n            }\n        },\n        axisLabel: {\n            textStyle: {\n                color: contrastColor\n            }\n        },\n        splitLine: {\n            lineStyle: {\n                type: 'dashed',\n                color: '#aaa'\n            }\n        },\n        splitArea: {\n            areaStyle: {\n                color: contrastColor\n            }\n        }\n    };\n};\n\nvar colorPalette = [\n    '#dd6b66', '#759aa0', '#e69d87', '#8dc1a9', '#ea7e53',\n    '#eedd78', '#73a373', '#73b9bc', '#7289ab', '#91ca8c', '#f49f42'\n];\nvar theme = {\n    color: colorPalette,\n    backgroundColor: '#333',\n    tooltip: {\n        axisPointer: {\n            lineStyle: {\n                color: contrastColor\n            },\n            crossStyle: {\n                color: contrastColor\n            }\n        }\n    },\n    legend: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    textStyle: {\n        color: contrastColor\n    },\n    title: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    toolbox: {\n        iconStyle: {\n            normal: {\n                borderColor: contrastColor\n            }\n        }\n    },\n    dataZoom: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    visualMap: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    timeline: {\n        lineStyle: {\n            color: contrastColor\n        },\n        itemStyle: {\n            normal: {\n                color: colorPalette[1]\n            }\n        },\n        label: {\n            normal: {\n                textStyle: {\n                    color: contrastColor\n                }\n            }\n        },\n        controlStyle: {\n            normal: {\n                color: contrastColor,\n                borderColor: contrastColor\n            }\n        }\n    },\n    timeAxis: axisCommon(),\n    logAxis: axisCommon(),\n    valueAxis: axisCommon(),\n    categoryAxis: axisCommon(),\n\n    line: {\n        symbol: 'circle'\n    },\n    graph: {\n        color: colorPalette\n    },\n    gauge: {\n        title: {\n            textStyle: {\n                color: contrastColor\n            }\n        }\n    },\n    candlestick: {\n        itemStyle: {\n            normal: {\n                color: '#FD1050',\n                color0: '#0CF49B',\n                borderColor: '#FD1050',\n                borderColor0: '#0CF49B'\n            }\n        }\n    }\n};\ntheme.categoryAxis.splitLine.show = false;\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * This module is imported by echarts directly.\n *\n * Notice:\n * Always keep this file exists for backward compatibility.\n * Because before 4.1.0, dataset is an optional component,\n * some users may import this module manually.\n */\n\nComponentModel.extend({\n\n    type: 'dataset',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n\n        // 'row', 'column'\n        seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN,\n\n        // null/'auto': auto detect header, see \"module:echarts/data/helper/sourceHelper\"\n        sourceHeader: null,\n\n        dimensions: null,\n\n        source: null\n    },\n\n    optionUpdated: function () {\n        detectSourceFormat(this);\n    }\n\n});\n\nComponent$1.extend({\n\n    type: 'dataset'\n\n});\n\n/**\n * 椭圆形状\n * @module zrender/graphic/shape/Ellipse\n */\n\nvar Ellipse = Path.extend({\n\n    type: 'ellipse',\n\n    shape: {\n        cx: 0, cy: 0,\n        rx: 0, ry: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var k = 0.5522848;\n        var x = shape.cx;\n        var y = shape.cy;\n        var a = shape.rx;\n        var b = shape.ry;\n        var ox = a * k; // 水平控制点偏移量\n        var oy = b * k; // 垂直控制点偏移量\n        // 从椭圆的左端点开始顺时针绘制四条三次贝塞尔曲线\n        ctx.moveTo(x - a, y);\n        ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b);\n        ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y);\n        ctx.bezierCurveTo(x + a, y + oy, x + ox, y + b, x, y + b);\n        ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y);\n        ctx.closePath();\n    }\n});\n\n// import RadialGradient from '../graphic/RadialGradient';\n// import Pattern from '../graphic/Pattern';\n// import * as vector from '../core/vector';\n// Most of the values can be separated by comma and/or white space.\nvar DILIMITER_REG = /[\\s,]+/;\n\n/**\n * For big svg string, this method might be time consuming.\n *\n * @param {string} svg xml string\n * @return {Object} xml root.\n */\nfunction parseXML(svg) {\n    if (isString(svg)) {\n        var parser = new DOMParser();\n        svg = parser.parseFromString(svg, 'text/xml');\n    }\n\n    // Document node. If using $.get, doc node may be input.\n    if (svg.nodeType === 9) {\n        svg = svg.firstChild;\n    }\n    // nodeName of <!DOCTYPE svg> is also 'svg'.\n    while (svg.nodeName.toLowerCase() !== 'svg' || svg.nodeType !== 1) {\n        svg = svg.nextSibling;\n    }\n\n    return svg;\n}\n\nfunction SVGParser() {\n    this._defs = {};\n    this._root = null;\n\n    this._isDefine = false;\n    this._isText = false;\n}\n\nSVGParser.prototype.parse = function (xml, opt) {\n    opt = opt || {};\n\n    var svg = parseXML(xml);\n\n    if (!svg) {\n        throw new Error('Illegal svg');\n    }\n\n    var root = new Group();\n    this._root = root;\n    // parse view port\n    var viewBox = svg.getAttribute('viewBox') || '';\n\n    // If width/height not specified, means \"100%\" of `opt.width/height`.\n    // TODO: Other percent value not supported yet.\n    var width = parseFloat(svg.getAttribute('width') || opt.width);\n    var height = parseFloat(svg.getAttribute('height') || opt.height);\n    // If width/height not specified, set as null for output.\n    isNaN(width) && (width = null);\n    isNaN(height) && (height = null);\n\n    // Apply inline style on svg element.\n    parseAttributes(svg, root, null, true);\n\n    var child = svg.firstChild;\n    while (child) {\n        this._parseNode(child, root);\n        child = child.nextSibling;\n    }\n\n    var viewBoxRect;\n    var viewBoxTransform;\n\n    if (viewBox) {\n        var viewBoxArr = trim(viewBox).split(DILIMITER_REG);\n        // Some invalid case like viewBox: 'none'.\n        if (viewBoxArr.length >= 4) {\n            viewBoxRect = {\n                x: parseFloat(viewBoxArr[0] || 0),\n                y: parseFloat(viewBoxArr[1] || 0),\n                width: parseFloat(viewBoxArr[2]),\n                height: parseFloat(viewBoxArr[3])\n            };\n        }\n    }\n\n    if (viewBoxRect && width != null && height != null) {\n        viewBoxTransform = makeViewBoxTransform(viewBoxRect, width, height);\n\n        if (!opt.ignoreViewBox) {\n            // If set transform on the output group, it probably bring trouble when\n            // some users only intend to show the clipped content inside the viewBox,\n            // but not intend to transform the output group. So we keep the output\n            // group no transform. If the user intend to use the viewBox as a\n            // camera, just set `opt.ignoreViewBox` as `true` and set transfrom\n            // manually according to the viewBox info in the output of this method.\n            var elRoot = root;\n            root = new Group();\n            root.add(elRoot);\n            elRoot.scale = viewBoxTransform.scale.slice();\n            elRoot.position = viewBoxTransform.position.slice();\n        }\n    }\n\n    // Some shapes might be overflow the viewport, which should be\n    // clipped despite whether the viewBox is used, as the SVG does.\n    if (!opt.ignoreRootClip && width != null && height != null) {\n        root.setClipPath(new Rect({\n            shape: {x: 0, y: 0, width: width, height: height}\n        }));\n    }\n\n    // Set width/height on group just for output the viewport size.\n    return {\n        root: root,\n        width: width,\n        height: height,\n        viewBoxRect: viewBoxRect,\n        viewBoxTransform: viewBoxTransform\n    };\n};\n\nSVGParser.prototype._parseNode = function (xmlNode, parentGroup) {\n\n    var nodeName = xmlNode.nodeName.toLowerCase();\n\n    // TODO\n    // support <style>...</style> in svg, where nodeName is 'style',\n    // CSS classes is defined globally wherever the style tags are declared.\n\n    if (nodeName === 'defs') {\n        // define flag\n        this._isDefine = true;\n    }\n    else if (nodeName === 'text') {\n        this._isText = true;\n    }\n\n    var el;\n    if (this._isDefine) {\n        var parser = defineParsers[nodeName];\n        if (parser) {\n            var def = parser.call(this, xmlNode);\n            var id = xmlNode.getAttribute('id');\n            if (id) {\n                this._defs[id] = def;\n            }\n        }\n    }\n    else {\n        var parser = nodeParsers[nodeName];\n        if (parser) {\n            el = parser.call(this, xmlNode, parentGroup);\n            parentGroup.add(el);\n        }\n    }\n\n    var child = xmlNode.firstChild;\n    while (child) {\n        if (child.nodeType === 1) {\n            this._parseNode(child, el);\n        }\n        // Is text\n        if (child.nodeType === 3 && this._isText) {\n            this._parseText(child, el);\n        }\n        child = child.nextSibling;\n    }\n\n    // Quit define\n    if (nodeName === 'defs') {\n        this._isDefine = false;\n    }\n    else if (nodeName === 'text') {\n        this._isText = false;\n    }\n};\n\nSVGParser.prototype._parseText = function (xmlNode, parentGroup) {\n    if (xmlNode.nodeType === 1) {\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n        this._textX += parseFloat(dx);\n        this._textY += parseFloat(dy);\n    }\n\n    var text = new Text({\n        style: {\n            text: xmlNode.textContent,\n            transformText: true\n        },\n        position: [this._textX || 0, this._textY || 0]\n    });\n\n    inheritStyle(parentGroup, text);\n    parseAttributes(xmlNode, text, this._defs);\n\n    var fontSize = text.style.fontSize;\n    if (fontSize && fontSize < 9) {\n        // PENDING\n        text.style.fontSize = 9;\n        text.scale = text.scale || [1, 1];\n        text.scale[0] *= fontSize / 9;\n        text.scale[1] *= fontSize / 9;\n    }\n\n    var rect = text.getBoundingRect();\n    this._textX += rect.width;\n\n    parentGroup.add(text);\n\n    return text;\n};\n\nvar nodeParsers = {\n    'g': function (xmlNode, parentGroup) {\n        var g = new Group();\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n        return g;\n    },\n    'rect': function (xmlNode, parentGroup) {\n        var rect = new Rect();\n        inheritStyle(parentGroup, rect);\n        parseAttributes(xmlNode, rect, this._defs);\n\n        rect.setShape({\n            x: parseFloat(xmlNode.getAttribute('x') || 0),\n            y: parseFloat(xmlNode.getAttribute('y') || 0),\n            width: parseFloat(xmlNode.getAttribute('width') || 0),\n            height: parseFloat(xmlNode.getAttribute('height') || 0)\n        });\n\n        // console.log(xmlNode.getAttribute('transform'));\n        // console.log(rect.transform);\n\n        return rect;\n    },\n    'circle': function (xmlNode, parentGroup) {\n        var circle = new Circle();\n        inheritStyle(parentGroup, circle);\n        parseAttributes(xmlNode, circle, this._defs);\n\n        circle.setShape({\n            cx: parseFloat(xmlNode.getAttribute('cx') || 0),\n            cy: parseFloat(xmlNode.getAttribute('cy') || 0),\n            r: parseFloat(xmlNode.getAttribute('r') || 0)\n        });\n\n        return circle;\n    },\n    'line': function (xmlNode, parentGroup) {\n        var line = new Line();\n        inheritStyle(parentGroup, line);\n        parseAttributes(xmlNode, line, this._defs);\n\n        line.setShape({\n            x1: parseFloat(xmlNode.getAttribute('x1') || 0),\n            y1: parseFloat(xmlNode.getAttribute('y1') || 0),\n            x2: parseFloat(xmlNode.getAttribute('x2') || 0),\n            y2: parseFloat(xmlNode.getAttribute('y2') || 0)\n        });\n\n        return line;\n    },\n    'ellipse': function (xmlNode, parentGroup) {\n        var ellipse = new Ellipse();\n        inheritStyle(parentGroup, ellipse);\n        parseAttributes(xmlNode, ellipse, this._defs);\n\n        ellipse.setShape({\n            cx: parseFloat(xmlNode.getAttribute('cx') || 0),\n            cy: parseFloat(xmlNode.getAttribute('cy') || 0),\n            rx: parseFloat(xmlNode.getAttribute('rx') || 0),\n            ry: parseFloat(xmlNode.getAttribute('ry') || 0)\n        });\n        return ellipse;\n    },\n    'polygon': function (xmlNode, parentGroup) {\n        var points = xmlNode.getAttribute('points');\n        if (points) {\n            points = parsePoints(points);\n        }\n        var polygon = new Polygon({\n            shape: {\n                points: points || []\n            }\n        });\n\n        inheritStyle(parentGroup, polygon);\n        parseAttributes(xmlNode, polygon, this._defs);\n\n        return polygon;\n    },\n    'polyline': function (xmlNode, parentGroup) {\n        var path = new Path();\n        inheritStyle(parentGroup, path);\n        parseAttributes(xmlNode, path, this._defs);\n\n        var points = xmlNode.getAttribute('points');\n        if (points) {\n            points = parsePoints(points);\n        }\n        var polyline = new Polyline({\n            shape: {\n                points: points || []\n            }\n        });\n\n        return polyline;\n    },\n    'image': function (xmlNode, parentGroup) {\n        var img = new ZImage();\n        inheritStyle(parentGroup, img);\n        parseAttributes(xmlNode, img, this._defs);\n\n        img.setStyle({\n            image: xmlNode.getAttribute('xlink:href'),\n            x: xmlNode.getAttribute('x'),\n            y: xmlNode.getAttribute('y'),\n            width: xmlNode.getAttribute('width'),\n            height: xmlNode.getAttribute('height')\n        });\n\n        return img;\n    },\n    'text': function (xmlNode, parentGroup) {\n        var x = xmlNode.getAttribute('x') || 0;\n        var y = xmlNode.getAttribute('y') || 0;\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n\n        this._textX = parseFloat(x) + parseFloat(dx);\n        this._textY = parseFloat(y) + parseFloat(dy);\n\n        var g = new Group();\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n        return g;\n    },\n    'tspan': function (xmlNode, parentGroup) {\n        var x = xmlNode.getAttribute('x');\n        var y = xmlNode.getAttribute('y');\n        if (x != null) {\n            // new offset x\n            this._textX = parseFloat(x);\n        }\n        if (y != null) {\n            // new offset y\n            this._textY = parseFloat(y);\n        }\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n\n        var g = new Group();\n\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n\n        this._textX += dx;\n        this._textY += dy;\n\n        return g;\n    },\n    'path': function (xmlNode, parentGroup) {\n        // TODO svg fill rule\n        // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule\n        // path.style.globalCompositeOperation = 'xor';\n        var d = xmlNode.getAttribute('d') || '';\n\n        // Performance sensitive.\n\n        var path = createFromString(d);\n\n        inheritStyle(parentGroup, path);\n        parseAttributes(xmlNode, path, this._defs);\n\n        return path;\n    }\n};\n\nvar defineParsers = {\n\n    'lineargradient': function (xmlNode) {\n        var x1 = parseInt(xmlNode.getAttribute('x1') || 0, 10);\n        var y1 = parseInt(xmlNode.getAttribute('y1') || 0, 10);\n        var x2 = parseInt(xmlNode.getAttribute('x2') || 10, 10);\n        var y2 = parseInt(xmlNode.getAttribute('y2') || 0, 10);\n\n        var gradient = new LinearGradient(x1, y1, x2, y2);\n\n        _parseGradientColorStops(xmlNode, gradient);\n\n        return gradient;\n    },\n\n    'radialgradient': function (xmlNode) {\n\n    }\n};\n\nfunction _parseGradientColorStops(xmlNode, gradient) {\n\n    var stop = xmlNode.firstChild;\n\n    while (stop) {\n        if (stop.nodeType === 1) {\n            var offset = stop.getAttribute('offset');\n            if (offset.indexOf('%') > 0) {  // percentage\n                offset = parseInt(offset, 10) / 100;\n            }\n            else if (offset) {    // number from 0 to 1\n                offset = parseFloat(offset);\n            }\n            else {\n                offset = 0;\n            }\n\n            var stopColor = stop.getAttribute('stop-color') || '#000000';\n\n            gradient.addColorStop(offset, stopColor);\n        }\n        stop = stop.nextSibling;\n    }\n}\n\nfunction inheritStyle(parent, child) {\n    if (parent && parent.__inheritedStyle) {\n        if (!child.__inheritedStyle) {\n            child.__inheritedStyle = {};\n        }\n        defaults(child.__inheritedStyle, parent.__inheritedStyle);\n    }\n}\n\nfunction parsePoints(pointsString) {\n    var list = trim(pointsString).split(DILIMITER_REG);\n    var points = [];\n\n    for (var i = 0; i < list.length; i += 2) {\n        var x = parseFloat(list[i]);\n        var y = parseFloat(list[i + 1]);\n        points.push([x, y]);\n    }\n    return points;\n}\n\nvar attributesMap = {\n    'fill': 'fill',\n    'stroke': 'stroke',\n    'stroke-width': 'lineWidth',\n    'opacity': 'opacity',\n    'fill-opacity': 'fillOpacity',\n    'stroke-opacity': 'strokeOpacity',\n    'stroke-dasharray': 'lineDash',\n    'stroke-dashoffset': 'lineDashOffset',\n    'stroke-linecap': 'lineCap',\n    'stroke-linejoin': 'lineJoin',\n    'stroke-miterlimit': 'miterLimit',\n    'font-family': 'fontFamily',\n    'font-size': 'fontSize',\n    'font-style': 'fontStyle',\n    'font-weight': 'fontWeight',\n\n    'text-align': 'textAlign',\n    'alignment-baseline': 'textBaseline'\n};\n\nfunction parseAttributes(xmlNode, el, defs, onlyInlineStyle) {\n    var zrStyle = el.__inheritedStyle || {};\n    var isTextEl = el.type === 'text';\n\n    // TODO Shadow\n    if (xmlNode.nodeType === 1) {\n        parseTransformAttribute(xmlNode, el);\n\n        extend(zrStyle, parseStyleAttribute(xmlNode));\n\n        if (!onlyInlineStyle) {\n            for (var svgAttrName in attributesMap) {\n                if (attributesMap.hasOwnProperty(svgAttrName)) {\n                    var attrValue = xmlNode.getAttribute(svgAttrName);\n                    if (attrValue != null) {\n                        zrStyle[attributesMap[svgAttrName]] = attrValue;\n                    }\n                }\n            }\n        }\n    }\n\n    var elFillProp = isTextEl ? 'textFill' : 'fill';\n    var elStrokeProp = isTextEl ? 'textStroke' : 'stroke';\n\n    el.style = el.style || new Style();\n    var elStyle = el.style;\n\n    zrStyle.fill != null && elStyle.set(elFillProp, getPaint(zrStyle.fill, defs));\n    zrStyle.stroke != null && elStyle.set(elStrokeProp, getPaint(zrStyle.stroke, defs));\n\n    each$1([\n        'lineWidth', 'opacity', 'fillOpacity', 'strokeOpacity', 'miterLimit', 'fontSize'\n    ], function (propName) {\n        var elPropName = (propName === 'lineWidth' && isTextEl) ? 'textStrokeWidth' : propName;\n        zrStyle[propName] != null && elStyle.set(elPropName, parseFloat(zrStyle[propName]));\n    });\n\n    if (!zrStyle.textBaseline || zrStyle.textBaseline === 'auto') {\n        zrStyle.textBaseline = 'alphabetic';\n    }\n    if (zrStyle.textBaseline === 'alphabetic') {\n        zrStyle.textBaseline = 'bottom';\n    }\n    if (zrStyle.textAlign === 'start') {\n        zrStyle.textAlign = 'left';\n    }\n    if (zrStyle.textAlign === 'end') {\n        zrStyle.textAlign = 'right';\n    }\n\n    each$1(['lineDashOffset', 'lineCap', 'lineJoin',\n        'fontWeight', 'fontFamily', 'fontStyle', 'textAlign', 'textBaseline'\n    ], function (propName) {\n        zrStyle[propName] != null && elStyle.set(propName, zrStyle[propName]);\n    });\n\n    if (zrStyle.lineDash) {\n        el.style.lineDash = trim(zrStyle.lineDash).split(DILIMITER_REG);\n    }\n\n    if (elStyle[elStrokeProp] && elStyle[elStrokeProp] !== 'none') {\n        // enable stroke\n        el[elStrokeProp] = true;\n    }\n\n    el.__inheritedStyle = zrStyle;\n}\n\n\nvar urlRegex = /url\\(\\s*#(.*?)\\)/;\nfunction getPaint(str, defs) {\n    // if (str === 'none') {\n    //     return;\n    // }\n    var urlMatch = defs && str && str.match(urlRegex);\n    if (urlMatch) {\n        var url = trim(urlMatch[1]);\n        var def = defs[url];\n        return def;\n    }\n    return str;\n}\n\nvar transformRegex = /(translate|scale|rotate|skewX|skewY|matrix)\\(([\\-\\s0-9\\.e,]*)\\)/g;\n\nfunction parseTransformAttribute(xmlNode, node) {\n    var transform = xmlNode.getAttribute('transform');\n    if (transform) {\n        transform = transform.replace(/,/g, ' ');\n        var m = null;\n        var transformOps = [];\n        transform.replace(transformRegex, function (str, type, value) {\n            transformOps.push(type, value);\n        });\n        for (var i = transformOps.length - 1; i > 0; i -= 2) {\n            var value = transformOps[i];\n            var type = transformOps[i - 1];\n            m = m || create$1();\n            switch (type) {\n                case 'translate':\n                    value = trim(value).split(DILIMITER_REG);\n                    translate(m, m, [parseFloat(value[0]), parseFloat(value[1] || 0)]);\n                    break;\n                case 'scale':\n                    value = trim(value).split(DILIMITER_REG);\n                    scale$1(m, m, [parseFloat(value[0]), parseFloat(value[1] || value[0])]);\n                    break;\n                case 'rotate':\n                    value = trim(value).split(DILIMITER_REG);\n                    rotate(m, m, parseFloat(value[0]));\n                    break;\n                case 'skew':\n                    value = trim(value).split(DILIMITER_REG);\n                    console.warn('Skew transform is not supported yet');\n                    break;\n                case 'matrix':\n                    var value = trim(value).split(DILIMITER_REG);\n                    m[0] = parseFloat(value[0]);\n                    m[1] = parseFloat(value[1]);\n                    m[2] = parseFloat(value[2]);\n                    m[3] = parseFloat(value[3]);\n                    m[4] = parseFloat(value[4]);\n                    m[5] = parseFloat(value[5]);\n                    break;\n            }\n        }\n        node.setLocalTransform(m);\n    }\n}\n\n// Value may contain space.\nvar styleRegex = /([^\\s:;]+)\\s*:\\s*([^:;]+)/g;\nfunction parseStyleAttribute(xmlNode) {\n    var style = xmlNode.getAttribute('style');\n    var result = {};\n\n    if (!style) {\n        return result;\n    }\n\n    var styleList = {};\n    styleRegex.lastIndex = 0;\n    var styleRegResult;\n    while ((styleRegResult = styleRegex.exec(style)) != null) {\n        styleList[styleRegResult[1]] = styleRegResult[2];\n    }\n\n    for (var svgAttrName in attributesMap) {\n        if (attributesMap.hasOwnProperty(svgAttrName) && styleList[svgAttrName] != null) {\n            result[attributesMap[svgAttrName]] = styleList[svgAttrName];\n        }\n    }\n\n    return result;\n}\n\n/**\n * @param {Array.<number>} viewBoxRect\n * @param {number} width\n * @param {number} height\n * @return {Object} {scale, position}\n */\nfunction makeViewBoxTransform(viewBoxRect, width, height) {\n    var scaleX = width / viewBoxRect.width;\n    var scaleY = height / viewBoxRect.height;\n    var scale = Math.min(scaleX, scaleY);\n    // preserveAspectRatio 'xMidYMid'\n    var viewBoxScale = [scale, scale];\n    var viewBoxPosition = [\n        -(viewBoxRect.x + viewBoxRect.width / 2) * scale + width / 2,\n        -(viewBoxRect.y + viewBoxRect.height / 2) * scale + height / 2\n    ];\n\n    return {\n        scale: viewBoxScale,\n        position: viewBoxPosition\n    };\n}\n\n/**\n * @param {string|XMLElement} xml\n * @param {Object} [opt]\n * @param {number} [opt.width] Default width if svg width not specified or is a percent value.\n * @param {number} [opt.height] Default height if svg height not specified or is a percent value.\n * @param {boolean} [opt.ignoreViewBox]\n * @param {boolean} [opt.ignoreRootClip]\n * @return {Object} result:\n * {\n *     root: Group, The root of the the result tree of zrender shapes,\n *     width: number, the viewport width of the SVG,\n *     height: number, the viewport height of the SVG,\n *     viewBoxRect: {x, y, width, height}, the declared viewBox rect of the SVG, if exists,\n *     viewBoxTransform: the {scale, position} calculated by viewBox and viewport, is exists.\n * }\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar storage = createHashMap();\n\n// For minimize the code size of common echarts package,\n// do not put too much logic in this module.\n\nvar mapDataStorage = {\n\n    // The format of record: see `echarts.registerMap`.\n    // Compatible with previous `echarts.registerMap`.\n    registerMap: function (mapName, rawGeoJson, rawSpecialAreas) {\n\n        var records;\n\n        if (isArray(rawGeoJson)) {\n            records = rawGeoJson;\n        }\n        else if (rawGeoJson.svg) {\n            records = [{\n                type: 'svg',\n                source: rawGeoJson.svg,\n                specialAreas: rawGeoJson.specialAreas\n            }];\n        }\n        else {\n            // Backward compatibility.\n            if (rawGeoJson.geoJson && !rawGeoJson.features) {\n                rawSpecialAreas = rawGeoJson.specialAreas;\n                rawGeoJson = rawGeoJson.geoJson;\n            }\n            records = [{\n                type: 'geoJSON',\n                source: rawGeoJson,\n                specialAreas: rawSpecialAreas\n            }];\n        }\n\n        each$1(records, function (record) {\n            var type = record.type;\n            type === 'geoJson' && (type = record.type = 'geoJSON');\n\n            var parse = parsers[type];\n\n            if (__DEV__) {\n                assert$1(parse, 'Illegal map type: ' + type);\n            }\n\n            parse(record);\n        });\n\n        return storage.set(mapName, records);\n    },\n\n    retrieveMap: function (mapName) {\n        return storage.get(mapName);\n    }\n\n};\n\nvar parsers = {\n\n    geoJSON: function (record) {\n        var source = record.source;\n        record.geoJSON = !isString(source)\n            ? source\n            : (typeof JSON !== 'undefined' && JSON.parse)\n            ? JSON.parse(source)\n            : (new Function('return (' + source + ');'))();\n    },\n\n    // Only perform parse to XML object here, which might be time\n    // consiming for large SVG.\n    // Although convert XML to zrender element is also time consiming,\n    // if we do it here, the clone of zrender elements has to be\n    // required. So we do it once for each geo instance, util real\n    // performance issues call for optimizing it.\n    svg: function (record) {\n        record.svgXML = parseXML(record.source);\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\nvar assert = assert$1;\nvar each = each$1;\nvar isFunction = isFunction$1;\nvar isObject = isObject$1;\nvar parseClassType = ComponentModel.parseClassType;\n\nvar version = '4.2.1';\n\nvar dependencies = {\n    zrender: '4.0.6'\n};\n\nvar TEST_FRAME_REMAIN_TIME = 1;\n\nvar PRIORITY_PROCESSOR_FILTER = 1000;\nvar PRIORITY_PROCESSOR_STATISTIC = 5000;\n\nvar PRIORITY_VISUAL_LAYOUT = 1000;\nvar PRIORITY_VISUAL_GLOBAL = 2000;\nvar PRIORITY_VISUAL_CHART = 3000;\nvar PRIORITY_VISUAL_COMPONENT = 4000;\n// FIXME\n// necessary?\nvar PRIORITY_VISUAL_BRUSH = 5000;\n\nvar PRIORITY = {\n    PROCESSOR: {\n        FILTER: PRIORITY_PROCESSOR_FILTER,\n        STATISTIC: PRIORITY_PROCESSOR_STATISTIC\n    },\n    VISUAL: {\n        LAYOUT: PRIORITY_VISUAL_LAYOUT,\n        GLOBAL: PRIORITY_VISUAL_GLOBAL,\n        CHART: PRIORITY_VISUAL_CHART,\n        COMPONENT: PRIORITY_VISUAL_COMPONENT,\n        BRUSH: PRIORITY_VISUAL_BRUSH\n    }\n};\n\n// Main process have three entries: `setOption`, `dispatchAction` and `resize`,\n// where they must not be invoked nestedly, except the only case: invoke\n// dispatchAction with updateMethod \"none\" in main process.\n// This flag is used to carry out this rule.\n// All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]).\nvar IN_MAIN_PROCESS = '__flagInMainProcess';\nvar OPTION_UPDATED = '__optionUpdated';\nvar ACTION_REG = /^[a-zA-Z0-9_]+$/;\n\n\nfunction createRegisterEventWithLowercaseName(method) {\n    return function (eventName, handler, context) {\n        // Event name is all lowercase\n        eventName = eventName && eventName.toLowerCase();\n        Eventful.prototype[method].call(this, eventName, handler, context);\n    };\n}\n\n/**\n * @module echarts~MessageCenter\n */\nfunction MessageCenter() {\n    Eventful.call(this);\n}\nMessageCenter.prototype.on = createRegisterEventWithLowercaseName('on');\nMessageCenter.prototype.off = createRegisterEventWithLowercaseName('off');\nMessageCenter.prototype.one = createRegisterEventWithLowercaseName('one');\nmixin(MessageCenter, Eventful);\n\n/**\n * @module echarts~ECharts\n */\nfunction ECharts(dom, theme$$1, opts) {\n    opts = opts || {};\n\n    // Get theme by name\n    if (typeof theme$$1 === 'string') {\n        theme$$1 = themeStorage[theme$$1];\n    }\n\n    /**\n     * @type {string}\n     */\n    this.id;\n\n    /**\n     * Group id\n     * @type {string}\n     */\n    this.group;\n\n    /**\n     * @type {HTMLElement}\n     * @private\n     */\n    this._dom = dom;\n\n    var defaultRenderer = 'canvas';\n    if (__DEV__) {\n        defaultRenderer = (\n            typeof window === 'undefined' ? global : window\n        ).__ECHARTS__DEFAULT__RENDERER__ || defaultRenderer;\n    }\n\n    /**\n     * @type {module:zrender/ZRender}\n     * @private\n     */\n    var zr = this._zr = init$1(dom, {\n        renderer: opts.renderer || defaultRenderer,\n        devicePixelRatio: opts.devicePixelRatio,\n        width: opts.width,\n        height: opts.height\n    });\n\n    /**\n     * Expect 60 pfs.\n     * @type {Function}\n     * @private\n     */\n    this._throttledZrFlush = throttle(bind(zr.flush, zr), 17);\n\n    var theme$$1 = clone(theme$$1);\n    theme$$1 && backwardCompat(theme$$1, true);\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._theme = theme$$1;\n\n    /**\n     * @type {Array.<module:echarts/view/Chart>}\n     * @private\n     */\n    this._chartsViews = [];\n\n    /**\n     * @type {Object.<string, module:echarts/view/Chart>}\n     * @private\n     */\n    this._chartsMap = {};\n\n    /**\n     * @type {Array.<module:echarts/view/Component>}\n     * @private\n     */\n    this._componentsViews = [];\n\n    /**\n     * @type {Object.<string, module:echarts/view/Component>}\n     * @private\n     */\n    this._componentsMap = {};\n\n    /**\n     * @type {module:echarts/CoordinateSystem}\n     * @private\n     */\n    this._coordSysMgr = new CoordinateSystemManager();\n\n    /**\n     * @type {module:echarts/ExtensionAPI}\n     * @private\n     */\n    var api = this._api = createExtensionAPI(this);\n\n    // Sort on demand\n    function prioritySortFunc(a, b) {\n        return a.__prio - b.__prio;\n    }\n    sort(visualFuncs, prioritySortFunc);\n    sort(dataProcessorFuncs, prioritySortFunc);\n\n    /**\n     * @type {module:echarts/stream/Scheduler}\n     */\n    this._scheduler = new Scheduler(this, api, dataProcessorFuncs, visualFuncs);\n\n    Eventful.call(this, this._ecEventProcessor = new EventProcessor());\n\n    /**\n     * @type {module:echarts~MessageCenter}\n     * @private\n     */\n    this._messageCenter = new MessageCenter();\n\n    // Init mouse events\n    this._initEvents();\n\n    // In case some people write `window.onresize = chart.resize`\n    this.resize = bind(this.resize, this);\n\n    // Can't dispatch action during rendering procedure\n    this._pendingActions = [];\n\n    zr.animation.on('frame', this._onframe, this);\n\n    bindRenderedEvent(zr, this);\n\n    // ECharts instance can be used as value.\n    setAsPrimitive(this);\n}\n\nvar echartsProto = ECharts.prototype;\n\nechartsProto._onframe = function () {\n    if (this._disposed) {\n        return;\n    }\n\n    var scheduler = this._scheduler;\n\n    // Lazy update\n    if (this[OPTION_UPDATED]) {\n        var silent = this[OPTION_UPDATED].silent;\n\n        this[IN_MAIN_PROCESS] = true;\n\n        prepare(this);\n        updateMethods.update.call(this);\n\n        this[IN_MAIN_PROCESS] = false;\n\n        this[OPTION_UPDATED] = false;\n\n        flushPendingActions.call(this, silent);\n\n        triggerUpdatedEvent.call(this, silent);\n    }\n    // Avoid do both lazy update and progress in one frame.\n    else if (scheduler.unfinished) {\n        // Stream progress.\n        var remainTime = TEST_FRAME_REMAIN_TIME;\n        var ecModel = this._model;\n        var api = this._api;\n        scheduler.unfinished = false;\n        do {\n            var startTime = +new Date();\n\n            scheduler.performSeriesTasks(ecModel);\n\n            // Currently dataProcessorFuncs do not check threshold.\n            scheduler.performDataProcessorTasks(ecModel);\n\n            updateStreamModes(this, ecModel);\n\n            // Do not update coordinate system here. Because that coord system update in\n            // each frame is not a good user experience. So we follow the rule that\n            // the extent of the coordinate system is determin in the first frame (the\n            // frame is executed immedietely after task reset.\n            // this._coordSysMgr.update(ecModel, api);\n\n            // console.log('--- ec frame visual ---', remainTime);\n            scheduler.performVisualTasks(ecModel);\n\n            renderSeries(this, this._model, api, 'remain');\n\n            remainTime -= (+new Date() - startTime);\n        }\n        while (remainTime > 0 && scheduler.unfinished);\n\n        // Call flush explicitly for trigger finished event.\n        if (!scheduler.unfinished) {\n            this._zr.flush();\n        }\n        // Else, zr flushing be ensue within the same frame,\n        // because zr flushing is after onframe event.\n    }\n};\n\n/**\n * @return {HTMLElement}\n */\nechartsProto.getDom = function () {\n    return this._dom;\n};\n\n/**\n * @return {module:zrender~ZRender}\n */\nechartsProto.getZr = function () {\n    return this._zr;\n};\n\n/**\n * Usage:\n * chart.setOption(option, notMerge, lazyUpdate);\n * chart.setOption(option, {\n *     notMerge: ...,\n *     lazyUpdate: ...,\n *     silent: ...\n * });\n *\n * @param {Object} option\n * @param {Object|boolean} [opts] opts or notMerge.\n * @param {boolean} [opts.notMerge=false]\n * @param {boolean} [opts.lazyUpdate=false] Useful when setOption frequently.\n */\nechartsProto.setOption = function (option, notMerge, lazyUpdate) {\n    if (__DEV__) {\n        assert(!this[IN_MAIN_PROCESS], '`setOption` should not be called during main process.');\n    }\n\n    var silent;\n    if (isObject(notMerge)) {\n        lazyUpdate = notMerge.lazyUpdate;\n        silent = notMerge.silent;\n        notMerge = notMerge.notMerge;\n    }\n\n    this[IN_MAIN_PROCESS] = true;\n\n    if (!this._model || notMerge) {\n        var optionManager = new OptionManager(this._api);\n        var theme$$1 = this._theme;\n        var ecModel = this._model = new GlobalModel(null, null, theme$$1, optionManager);\n        ecModel.scheduler = this._scheduler;\n        ecModel.init(null, null, theme$$1, optionManager);\n    }\n\n    this._model.setOption(option, optionPreprocessorFuncs);\n\n    if (lazyUpdate) {\n        this[OPTION_UPDATED] = {silent: silent};\n        this[IN_MAIN_PROCESS] = false;\n    }\n    else {\n        prepare(this);\n\n        updateMethods.update.call(this);\n\n        // Ensure zr refresh sychronously, and then pixel in canvas can be\n        // fetched after `setOption`.\n        this._zr.flush();\n\n        this[OPTION_UPDATED] = false;\n        this[IN_MAIN_PROCESS] = false;\n\n        flushPendingActions.call(this, silent);\n        triggerUpdatedEvent.call(this, silent);\n    }\n};\n\n/**\n * @DEPRECATED\n */\nechartsProto.setTheme = function () {\n    console.error('ECharts#setTheme() is DEPRECATED in ECharts 3.0');\n};\n\n/**\n * @return {module:echarts/model/Global}\n */\nechartsProto.getModel = function () {\n    return this._model;\n};\n\n/**\n * @return {Object}\n */\nechartsProto.getOption = function () {\n    return this._model && this._model.getOption();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getWidth = function () {\n    return this._zr.getWidth();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getHeight = function () {\n    return this._zr.getHeight();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getDevicePixelRatio = function () {\n    return this._zr.painter.dpr || window.devicePixelRatio || 1;\n};\n\n/**\n * Get canvas which has all thing rendered\n * @param {Object} opts\n * @param {string} [opts.backgroundColor]\n * @return {string}\n */\nechartsProto.getRenderedCanvas = function (opts) {\n    if (!env$1.canvasSupported) {\n        return;\n    }\n    opts = opts || {};\n    opts.pixelRatio = opts.pixelRatio || 1;\n    opts.backgroundColor = opts.backgroundColor\n        || this._model.get('backgroundColor');\n    var zr = this._zr;\n    // var list = zr.storage.getDisplayList();\n    // Stop animations\n    // Never works before in init animation, so remove it.\n    // zrUtil.each(list, function (el) {\n    //     el.stopAnimation(true);\n    // });\n    return zr.painter.getRenderedCanvas(opts);\n};\n\n/**\n * Get svg data url\n * @return {string}\n */\nechartsProto.getSvgDataUrl = function () {\n    if (!env$1.svgSupported) {\n        return;\n    }\n\n    var zr = this._zr;\n    var list = zr.storage.getDisplayList();\n    // Stop animations\n    each$1(list, function (el) {\n        el.stopAnimation(true);\n    });\n\n    return zr.painter.pathToDataUrl();\n};\n\n/**\n * @return {string}\n * @param {Object} opts\n * @param {string} [opts.type='png']\n * @param {string} [opts.pixelRatio=1]\n * @param {string} [opts.backgroundColor]\n * @param {string} [opts.excludeComponents]\n */\nechartsProto.getDataURL = function (opts) {\n    opts = opts || {};\n    var excludeComponents = opts.excludeComponents;\n    var ecModel = this._model;\n    var excludesComponentViews = [];\n    var self = this;\n\n    each(excludeComponents, function (componentType) {\n        ecModel.eachComponent({\n            mainType: componentType\n        }, function (component) {\n            var view = self._componentsMap[component.__viewId];\n            if (!view.group.ignore) {\n                excludesComponentViews.push(view);\n                view.group.ignore = true;\n            }\n        });\n    });\n\n    var url = this._zr.painter.getType() === 'svg'\n        ? this.getSvgDataUrl()\n        : this.getRenderedCanvas(opts).toDataURL(\n            'image/' + (opts && opts.type || 'png')\n        );\n\n    each(excludesComponentViews, function (view) {\n        view.group.ignore = false;\n    });\n\n    return url;\n};\n\n\n/**\n * @return {string}\n * @param {Object} opts\n * @param {string} [opts.type='png']\n * @param {string} [opts.pixelRatio=1]\n * @param {string} [opts.backgroundColor]\n */\nechartsProto.getConnectedDataURL = function (opts) {\n    if (!env$1.canvasSupported) {\n        return;\n    }\n    var groupId = this.group;\n    var mathMin = Math.min;\n    var mathMax = Math.max;\n    var MAX_NUMBER = Infinity;\n    if (connectedGroups[groupId]) {\n        var left = MAX_NUMBER;\n        var top = MAX_NUMBER;\n        var right = -MAX_NUMBER;\n        var bottom = -MAX_NUMBER;\n        var canvasList = [];\n        var dpr = (opts && opts.pixelRatio) || 1;\n\n        each$1(instances, function (chart, id) {\n            if (chart.group === groupId) {\n                var canvas = chart.getRenderedCanvas(\n                    clone(opts)\n                );\n                var boundingRect = chart.getDom().getBoundingClientRect();\n                left = mathMin(boundingRect.left, left);\n                top = mathMin(boundingRect.top, top);\n                right = mathMax(boundingRect.right, right);\n                bottom = mathMax(boundingRect.bottom, bottom);\n                canvasList.push({\n                    dom: canvas,\n                    left: boundingRect.left,\n                    top: boundingRect.top\n                });\n            }\n        });\n\n        left *= dpr;\n        top *= dpr;\n        right *= dpr;\n        bottom *= dpr;\n        var width = right - left;\n        var height = bottom - top;\n        var targetCanvas = createCanvas();\n        targetCanvas.width = width;\n        targetCanvas.height = height;\n        var zr = init$1(targetCanvas);\n\n        each(canvasList, function (item) {\n            var img = new ZImage({\n                style: {\n                    x: item.left * dpr - left,\n                    y: item.top * dpr - top,\n                    image: item.dom\n                }\n            });\n            zr.add(img);\n        });\n        zr.refreshImmediately();\n\n        return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png'));\n    }\n    else {\n        return this.getDataURL(opts);\n    }\n};\n\n/**\n * Convert from logical coordinate system to pixel coordinate system.\n * See CoordinateSystem#convertToPixel.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId, geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName,\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {Array|number} result\n */\nechartsProto.convertToPixel = curry(doConvertPixel, 'convertToPixel');\n\n/**\n * Convert from pixel coordinate system to logical coordinate system.\n * See CoordinateSystem#convertFromPixel.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId / geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {Array|number} result\n */\nechartsProto.convertFromPixel = curry(doConvertPixel, 'convertFromPixel');\n\nfunction doConvertPixel(methodName, finder, value) {\n    var ecModel = this._model;\n    var coordSysList = this._coordSysMgr.getCoordinateSystems();\n    var result;\n\n    finder = parseFinder(ecModel, finder);\n\n    for (var i = 0; i < coordSysList.length; i++) {\n        var coordSys = coordSysList[i];\n        if (coordSys[methodName]\n            && (result = coordSys[methodName](ecModel, finder, value)) != null\n        ) {\n            return result;\n        }\n    }\n\n    if (__DEV__) {\n        console.warn(\n            'No coordinate system that supports ' + methodName + ' found by the given finder.'\n        );\n    }\n}\n\n/**\n * Is the specified coordinate systems or components contain the given pixel point.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId / geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName,\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {boolean} result\n */\nechartsProto.containPixel = function (finder, value) {\n    var ecModel = this._model;\n    var result;\n\n    finder = parseFinder(ecModel, finder);\n\n    each$1(finder, function (models, key) {\n        key.indexOf('Models') >= 0 && each$1(models, function (model) {\n            var coordSys = model.coordinateSystem;\n            if (coordSys && coordSys.containPoint) {\n                result |= !!coordSys.containPoint(value);\n            }\n            else if (key === 'seriesModels') {\n                var view = this._chartsMap[model.__viewId];\n                if (view && view.containPoint) {\n                    result |= view.containPoint(value, model);\n                }\n                else {\n                    if (__DEV__) {\n                        console.warn(key + ': ' + (view\n                            ? 'The found component do not support containPoint.'\n                            : 'No view mapping to the found component.'\n                        ));\n                    }\n                }\n            }\n            else {\n                if (__DEV__) {\n                    console.warn(key + ': containPoint is not supported');\n                }\n            }\n        }, this);\n    }, this);\n\n    return !!result;\n};\n\n/**\n * Get visual from series or data.\n * @param {string|Object} finder\n *        If string, e.g., 'series', means {seriesIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            dataIndex / dataIndexInside\n *        }\n *        If dataIndex is not specified, series visual will be fetched,\n *        but not data item visual.\n *        If all of seriesIndex, seriesId, seriesName are not specified,\n *        visual will be fetched from first series.\n * @param {string} visualType 'color', 'symbol', 'symbolSize'\n */\nechartsProto.getVisual = function (finder, visualType) {\n    var ecModel = this._model;\n\n    finder = parseFinder(ecModel, finder, {defaultMainType: 'series'});\n\n    var seriesModel = finder.seriesModel;\n\n    if (__DEV__) {\n        if (!seriesModel) {\n            console.warn('There is no specified seires model');\n        }\n    }\n\n    var data = seriesModel.getData();\n\n    var dataIndexInside = finder.hasOwnProperty('dataIndexInside')\n        ? finder.dataIndexInside\n        : finder.hasOwnProperty('dataIndex')\n        ? data.indexOfRawIndex(finder.dataIndex)\n        : null;\n\n    return dataIndexInside != null\n        ? data.getItemVisual(dataIndexInside, visualType)\n        : data.getVisual(visualType);\n};\n\n/**\n * Get view of corresponding component model\n * @param  {module:echarts/model/Component} componentModel\n * @return {module:echarts/view/Component}\n */\nechartsProto.getViewOfComponentModel = function (componentModel) {\n    return this._componentsMap[componentModel.__viewId];\n};\n\n/**\n * Get view of corresponding series model\n * @param  {module:echarts/model/Series} seriesModel\n * @return {module:echarts/view/Chart}\n */\nechartsProto.getViewOfSeriesModel = function (seriesModel) {\n    return this._chartsMap[seriesModel.__viewId];\n};\n\nvar updateMethods = {\n\n    prepareAndUpdate: function (payload) {\n        prepare(this);\n        updateMethods.update.call(this, payload);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    update: function (payload) {\n        // console.profile && console.profile('update');\n\n        var ecModel = this._model;\n        var api = this._api;\n        var zr = this._zr;\n        var coordSysMgr = this._coordSysMgr;\n        var scheduler = this._scheduler;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        scheduler.restoreData(ecModel, payload);\n\n        scheduler.performSeriesTasks(ecModel);\n\n        // TODO\n        // Save total ecModel here for undo/redo (after restoring data and before processing data).\n        // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call.\n\n        // Create new coordinate system each update\n        // In LineView may save the old coordinate system and use it to get the orignal point\n        coordSysMgr.create(ecModel, api);\n\n        scheduler.performDataProcessorTasks(ecModel, payload);\n\n        // Current stream render is not supported in data process. So we can update\n        // stream modes after data processing, where the filtered data is used to\n        // deteming whether use progressive rendering.\n        updateStreamModes(this, ecModel);\n\n        // We update stream modes before coordinate system updated, then the modes info\n        // can be fetched when coord sys updating (consider the barGrid extent fix). But\n        // the drawback is the full coord info can not be fetched. Fortunately this full\n        // coord is not requied in stream mode updater currently.\n        coordSysMgr.update(ecModel, api);\n\n        clearColorPalette(ecModel);\n        scheduler.performVisualTasks(ecModel, payload);\n\n        render(this, ecModel, api, payload);\n\n        // Set background\n        var backgroundColor = ecModel.get('backgroundColor') || 'transparent';\n\n        // In IE8\n        if (!env$1.canvasSupported) {\n            var colorArr = parse(backgroundColor);\n            backgroundColor = stringify(colorArr, 'rgb');\n            if (colorArr[3] === 0) {\n                backgroundColor = 'transparent';\n            }\n        }\n        else {\n            zr.setBackgroundColor(backgroundColor);\n        }\n\n        performPostUpdateFuncs(ecModel, api);\n\n        // console.profile && console.profileEnd('update');\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateTransform: function (payload) {\n        var ecModel = this._model;\n        var ecIns = this;\n        var api = this._api;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        // ChartView.markUpdateMethod(payload, 'updateTransform');\n\n        var componentDirtyList = [];\n        ecModel.eachComponent(function (componentType, componentModel) {\n            var componentView = ecIns.getViewOfComponentModel(componentModel);\n            if (componentView && componentView.__alive) {\n                if (componentView.updateTransform) {\n                    var result = componentView.updateTransform(componentModel, ecModel, api, payload);\n                    result && result.update && componentDirtyList.push(componentView);\n                }\n                else {\n                    componentDirtyList.push(componentView);\n                }\n            }\n        });\n\n        var seriesDirtyMap = createHashMap();\n        ecModel.eachSeries(function (seriesModel) {\n            var chartView = ecIns._chartsMap[seriesModel.__viewId];\n            if (chartView.updateTransform) {\n                var result = chartView.updateTransform(seriesModel, ecModel, api, payload);\n                result && result.update && seriesDirtyMap.set(seriesModel.uid, 1);\n            }\n            else {\n                seriesDirtyMap.set(seriesModel.uid, 1);\n            }\n        });\n\n        clearColorPalette(ecModel);\n        // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);\n        this._scheduler.performVisualTasks(\n            ecModel, payload, {setDirty: true, dirtyMap: seriesDirtyMap}\n        );\n\n        // Currently, not call render of components. Geo render cost a lot.\n        // renderComponents(ecIns, ecModel, api, payload, componentDirtyList);\n        renderSeries(ecIns, ecModel, api, payload, seriesDirtyMap);\n\n        performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateView: function (payload) {\n        var ecModel = this._model;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        Chart.markUpdateMethod(payload, 'updateView');\n\n        clearColorPalette(ecModel);\n\n        // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});\n\n        render(this, this._model, this._api, payload);\n\n        performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateVisual: function (payload) {\n        updateMethods.update.call(this, payload);\n\n        // var ecModel = this._model;\n\n        // // update before setOption\n        // if (!ecModel) {\n        //     return;\n        // }\n\n        // ChartView.markUpdateMethod(payload, 'updateVisual');\n\n        // clearColorPalette(ecModel);\n\n        // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // this._scheduler.performVisualTasks(ecModel, payload, {visualType: 'visual', setDirty: true});\n\n        // render(this, this._model, this._api, payload);\n\n        // performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateLayout: function (payload) {\n        updateMethods.update.call(this, payload);\n\n        // var ecModel = this._model;\n\n        // // update before setOption\n        // if (!ecModel) {\n        //     return;\n        // }\n\n        // ChartView.markUpdateMethod(payload, 'updateLayout');\n\n        // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);\n        // this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});\n\n        // render(this, this._model, this._api, payload);\n\n        // performPostUpdateFuncs(ecModel, this._api);\n    }\n};\n\nfunction prepare(ecIns) {\n    var ecModel = ecIns._model;\n    var scheduler = ecIns._scheduler;\n\n    scheduler.restorePipelines(ecModel);\n\n    scheduler.prepareStageTasks();\n\n    prepareView(ecIns, 'component', ecModel, scheduler);\n\n    prepareView(ecIns, 'chart', ecModel, scheduler);\n\n    scheduler.plan();\n}\n\n/**\n * @private\n */\nfunction updateDirectly(ecIns, method, payload, mainType, subType) {\n    var ecModel = ecIns._model;\n\n    // broadcast\n    if (!mainType) {\n        // FIXME\n        // Chart will not be update directly here, except set dirty.\n        // But there is no such scenario now.\n        each(ecIns._componentsViews.concat(ecIns._chartsViews), callView);\n        return;\n    }\n\n    var query = {};\n    query[mainType + 'Id'] = payload[mainType + 'Id'];\n    query[mainType + 'Index'] = payload[mainType + 'Index'];\n    query[mainType + 'Name'] = payload[mainType + 'Name'];\n\n    var condition = {mainType: mainType, query: query};\n    subType && (condition.subType = subType); // subType may be '' by parseClassType;\n\n    var excludeSeriesId = payload.excludeSeriesId;\n    if (excludeSeriesId != null) {\n        excludeSeriesId = createHashMap(normalizeToArray(excludeSeriesId));\n    }\n\n    // If dispatchAction before setOption, do nothing.\n    ecModel && ecModel.eachComponent(condition, function (model) {\n        if (!excludeSeriesId || excludeSeriesId.get(model.id) == null) {\n            callView(ecIns[\n                mainType === 'series' ? '_chartsMap' : '_componentsMap'\n            ][model.__viewId]);\n        }\n    }, ecIns);\n\n    function callView(view) {\n        view && view.__alive && view[method] && view[method](\n            view.__model, ecModel, ecIns._api, payload\n        );\n    }\n}\n\n/**\n * Resize the chart\n * @param {Object} opts\n * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)\n * @param {boolean} [opts.silent=false]\n */\nechartsProto.resize = function (opts) {\n    if (__DEV__) {\n        assert(!this[IN_MAIN_PROCESS], '`resize` should not be called during main process.');\n    }\n\n    this._zr.resize(opts);\n\n    var ecModel = this._model;\n\n    // Resize loading effect\n    this._loadingFX && this._loadingFX.resize();\n\n    if (!ecModel) {\n        return;\n    }\n\n    var optionChanged = ecModel.resetOption('media');\n\n    var silent = opts && opts.silent;\n\n    this[IN_MAIN_PROCESS] = true;\n\n    optionChanged && prepare(this);\n    updateMethods.update.call(this);\n\n    this[IN_MAIN_PROCESS] = false;\n\n    flushPendingActions.call(this, silent);\n\n    triggerUpdatedEvent.call(this, silent);\n};\n\nfunction updateStreamModes(ecIns, ecModel) {\n    var chartsMap = ecIns._chartsMap;\n    var scheduler = ecIns._scheduler;\n    ecModel.eachSeries(function (seriesModel) {\n        scheduler.updateStreamModes(seriesModel, chartsMap[seriesModel.__viewId]);\n    });\n}\n\n/**\n * Show loading effect\n * @param  {string} [name='default']\n * @param  {Object} [cfg]\n */\nechartsProto.showLoading = function (name, cfg) {\n    if (isObject(name)) {\n        cfg = name;\n        name = '';\n    }\n    name = name || 'default';\n\n    this.hideLoading();\n    if (!loadingEffects[name]) {\n        if (__DEV__) {\n            console.warn('Loading effects ' + name + ' not exists.');\n        }\n        return;\n    }\n    var el = loadingEffects[name](this._api, cfg);\n    var zr = this._zr;\n    this._loadingFX = el;\n\n    zr.add(el);\n};\n\n/**\n * Hide loading effect\n */\nechartsProto.hideLoading = function () {\n    this._loadingFX && this._zr.remove(this._loadingFX);\n    this._loadingFX = null;\n};\n\n/**\n * @param {Object} eventObj\n * @return {Object}\n */\nechartsProto.makeActionFromEvent = function (eventObj) {\n    var payload = extend({}, eventObj);\n    payload.type = eventActionMap[eventObj.type];\n    return payload;\n};\n\n/**\n * @pubilc\n * @param {Object} payload\n * @param {string} [payload.type] Action type\n * @param {Object|boolean} [opt] If pass boolean, means opt.silent\n * @param {boolean} [opt.silent=false] Whether trigger events.\n * @param {boolean} [opt.flush=undefined]\n *                  true: Flush immediately, and then pixel in canvas can be fetched\n *                      immediately. Caution: it might affect performance.\n *                  false: Not not flush.\n *                  undefined: Auto decide whether perform flush.\n */\nechartsProto.dispatchAction = function (payload, opt) {\n    if (!isObject(opt)) {\n        opt = {silent: !!opt};\n    }\n\n    if (!actions[payload.type]) {\n        return;\n    }\n\n    // Avoid dispatch action before setOption. Especially in `connect`.\n    if (!this._model) {\n        return;\n    }\n\n    // May dispatchAction in rendering procedure\n    if (this[IN_MAIN_PROCESS]) {\n        this._pendingActions.push(payload);\n        return;\n    }\n\n    doDispatchAction.call(this, payload, opt.silent);\n\n    if (opt.flush) {\n        this._zr.flush(true);\n    }\n    else if (opt.flush !== false && env$1.browser.weChat) {\n        // In WeChat embeded browser, `requestAnimationFrame` and `setInterval`\n        // hang when sliding page (on touch event), which cause that zr does not\n        // refresh util user interaction finished, which is not expected.\n        // But `dispatchAction` may be called too frequently when pan on touch\n        // screen, which impacts performance if do not throttle them.\n        this._throttledZrFlush();\n    }\n\n    flushPendingActions.call(this, opt.silent);\n\n    triggerUpdatedEvent.call(this, opt.silent);\n};\n\nfunction doDispatchAction(payload, silent) {\n    var payloadType = payload.type;\n    var escapeConnect = payload.escapeConnect;\n    var actionWrap = actions[payloadType];\n    var actionInfo = actionWrap.actionInfo;\n\n    var cptType = (actionInfo.update || 'update').split(':');\n    var updateMethod = cptType.pop();\n    cptType = cptType[0] != null && parseClassType(cptType[0]);\n\n    this[IN_MAIN_PROCESS] = true;\n\n    var payloads = [payload];\n    var batched = false;\n    // Batch action\n    if (payload.batch) {\n        batched = true;\n        payloads = map(payload.batch, function (item) {\n            item = defaults(extend({}, item), payload);\n            item.batch = null;\n            return item;\n        });\n    }\n\n    var eventObjBatch = [];\n    var eventObj;\n    var isHighDown = payloadType === 'highlight' || payloadType === 'downplay';\n\n    each(payloads, function (batchItem) {\n        // Action can specify the event by return it.\n        eventObj = actionWrap.action(batchItem, this._model, this._api);\n        // Emit event outside\n        eventObj = eventObj || extend({}, batchItem);\n        // Convert type to eventType\n        eventObj.type = actionInfo.event || eventObj.type;\n        eventObjBatch.push(eventObj);\n\n        // light update does not perform data process, layout and visual.\n        if (isHighDown) {\n            // method, payload, mainType, subType\n            updateDirectly(this, updateMethod, batchItem, 'series');\n        }\n        else if (cptType) {\n            updateDirectly(this, updateMethod, batchItem, cptType.main, cptType.sub);\n        }\n    }, this);\n\n    if (updateMethod !== 'none' && !isHighDown && !cptType) {\n        // Still dirty\n        if (this[OPTION_UPDATED]) {\n            // FIXME Pass payload ?\n            prepare(this);\n            updateMethods.update.call(this, payload);\n            this[OPTION_UPDATED] = false;\n        }\n        else {\n            updateMethods[updateMethod].call(this, payload);\n        }\n    }\n\n    // Follow the rule of action batch\n    if (batched) {\n        eventObj = {\n            type: actionInfo.event || payloadType,\n            escapeConnect: escapeConnect,\n            batch: eventObjBatch\n        };\n    }\n    else {\n        eventObj = eventObjBatch[0];\n    }\n\n    this[IN_MAIN_PROCESS] = false;\n\n    !silent && this._messageCenter.trigger(eventObj.type, eventObj);\n}\n\nfunction flushPendingActions(silent) {\n    var pendingActions = this._pendingActions;\n    while (pendingActions.length) {\n        var payload = pendingActions.shift();\n        doDispatchAction.call(this, payload, silent);\n    }\n}\n\nfunction triggerUpdatedEvent(silent) {\n    !silent && this.trigger('updated');\n}\n\n/**\n * Event `rendered` is triggered when zr\n * rendered. It is useful for realtime\n * snapshot (reflect animation).\n *\n * Event `finished` is triggered when:\n * (1) zrender rendering finished.\n * (2) initial animation finished.\n * (3) progressive rendering finished.\n * (4) no pending action.\n * (5) no delayed setOption needs to be processed.\n */\nfunction bindRenderedEvent(zr, ecIns) {\n    zr.on('rendered', function () {\n\n        ecIns.trigger('rendered');\n\n        // The `finished` event should not be triggered repeatly,\n        // so it should only be triggered when rendering indeed happend\n        // in zrender. (Consider the case that dipatchAction is keep\n        // triggering when mouse move).\n        if (\n            // Although zr is dirty if initial animation is not finished\n            // and this checking is called on frame, we also check\n            // animation finished for robustness.\n            zr.animation.isFinished()\n            && !ecIns[OPTION_UPDATED]\n            && !ecIns._scheduler.unfinished\n            && !ecIns._pendingActions.length\n        ) {\n            ecIns.trigger('finished');\n        }\n    });\n}\n\n/**\n * @param {Object} params\n * @param {number} params.seriesIndex\n * @param {Array|TypedArray} params.data\n */\nechartsProto.appendData = function (params) {\n    var seriesIndex = params.seriesIndex;\n    var ecModel = this.getModel();\n    var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n\n    if (__DEV__) {\n        assert(params.data && seriesModel);\n    }\n\n    seriesModel.appendData(params);\n\n    // Note: `appendData` does not support that update extent of coordinate\n    // system, util some scenario require that. In the expected usage of\n    // `appendData`, the initial extent of coordinate system should better\n    // be fixed by axis `min`/`max` setting or initial data, otherwise if\n    // the extent changed while `appendData`, the location of the painted\n    // graphic elements have to be changed, which make the usage of\n    // `appendData` meaningless.\n\n    this._scheduler.unfinished = true;\n};\n\n/**\n * Register event\n * @method\n */\nechartsProto.on = createRegisterEventWithLowercaseName('on');\nechartsProto.off = createRegisterEventWithLowercaseName('off');\nechartsProto.one = createRegisterEventWithLowercaseName('one');\n\n/**\n * Prepare view instances of charts and components\n * @param  {module:echarts/model/Global} ecModel\n * @private\n */\nfunction prepareView(ecIns, type, ecModel, scheduler) {\n    var isComponent = type === 'component';\n    var viewList = isComponent ? ecIns._componentsViews : ecIns._chartsViews;\n    var viewMap = isComponent ? ecIns._componentsMap : ecIns._chartsMap;\n    var zr = ecIns._zr;\n    var api = ecIns._api;\n\n    for (var i = 0; i < viewList.length; i++) {\n        viewList[i].__alive = false;\n    }\n\n    isComponent\n        ? ecModel.eachComponent(function (componentType, model) {\n            componentType !== 'series' && doPrepare(model);\n        })\n        : ecModel.eachSeries(doPrepare);\n\n    function doPrepare(model) {\n        // Consider: id same and type changed.\n        var viewId = '_ec_' + model.id + '_' + model.type;\n        var view = viewMap[viewId];\n        if (!view) {\n            var classType = parseClassType(model.type);\n            var Clazz = isComponent\n                ? Component$1.getClass(classType.main, classType.sub)\n                : Chart.getClass(classType.sub);\n\n            if (__DEV__) {\n                assert(Clazz, classType.sub + ' does not exist.');\n            }\n\n            view = new Clazz();\n            view.init(ecModel, api);\n            viewMap[viewId] = view;\n            viewList.push(view);\n            zr.add(view.group);\n        }\n\n        model.__viewId = view.__id = viewId;\n        view.__alive = true;\n        view.__model = model;\n        view.group.__ecComponentInfo = {\n            mainType: model.mainType,\n            index: model.componentIndex\n        };\n        !isComponent && scheduler.prepareView(view, model, ecModel, api);\n    }\n\n    for (var i = 0; i < viewList.length;) {\n        var view = viewList[i];\n        if (!view.__alive) {\n            !isComponent && view.renderTask.dispose();\n            zr.remove(view.group);\n            view.dispose(ecModel, api);\n            viewList.splice(i, 1);\n            delete viewMap[view.__id];\n            view.__id = view.group.__ecComponentInfo = null;\n        }\n        else {\n            i++;\n        }\n    }\n}\n\n// /**\n//  * Encode visual infomation from data after data processing\n//  *\n//  * @param {module:echarts/model/Global} ecModel\n//  * @param {object} layout\n//  * @param {boolean} [layoutFilter] `true`: only layout,\n//  *                                 `false`: only not layout,\n//  *                                 `null`/`undefined`: all.\n//  * @param {string} taskBaseTag\n//  * @private\n//  */\n// function startVisualEncoding(ecIns, ecModel, api, payload, layoutFilter) {\n//     each(visualFuncs, function (visual, index) {\n//         var isLayout = visual.isLayout;\n//         if (layoutFilter == null\n//             || (layoutFilter === false && !isLayout)\n//             || (layoutFilter === true && isLayout)\n//         ) {\n//             visual.func(ecModel, api, payload);\n//         }\n//     });\n// }\n\nfunction clearColorPalette(ecModel) {\n    ecModel.clearColorPalette();\n    ecModel.eachSeries(function (seriesModel) {\n        seriesModel.clearColorPalette();\n    });\n}\n\nfunction render(ecIns, ecModel, api, payload) {\n\n    renderComponents(ecIns, ecModel, api, payload);\n\n    each(ecIns._chartsViews, function (chart) {\n        chart.__alive = false;\n    });\n\n    renderSeries(ecIns, ecModel, api, payload);\n\n    // Remove groups of unrendered charts\n    each(ecIns._chartsViews, function (chart) {\n        if (!chart.__alive) {\n            chart.remove(ecModel, api);\n        }\n    });\n}\n\nfunction renderComponents(ecIns, ecModel, api, payload, dirtyList) {\n    each(dirtyList || ecIns._componentsViews, function (componentView) {\n        var componentModel = componentView.__model;\n        componentView.render(componentModel, ecModel, api, payload);\n\n        updateZ(componentModel, componentView);\n    });\n}\n\n/**\n * Render each chart and component\n * @private\n */\nfunction renderSeries(ecIns, ecModel, api, payload, dirtyMap) {\n    // Render all charts\n    var scheduler = ecIns._scheduler;\n    var unfinished;\n    ecModel.eachSeries(function (seriesModel) {\n        var chartView = ecIns._chartsMap[seriesModel.__viewId];\n        chartView.__alive = true;\n\n        var renderTask = chartView.renderTask;\n        scheduler.updatePayload(renderTask, payload);\n\n        if (dirtyMap && dirtyMap.get(seriesModel.uid)) {\n            renderTask.dirty();\n        }\n\n        unfinished |= renderTask.perform(scheduler.getPerformArgs(renderTask));\n\n        chartView.group.silent = !!seriesModel.get('silent');\n\n        updateZ(seriesModel, chartView);\n\n        updateBlend(seriesModel, chartView);\n    });\n    scheduler.unfinished |= unfinished;\n\n    // If use hover layer\n    updateHoverLayerStatus(ecIns._zr, ecModel);\n\n    // Add aria\n    aria(ecIns._zr.dom, ecModel);\n}\n\nfunction performPostUpdateFuncs(ecModel, api) {\n    each(postUpdateFuncs, function (func) {\n        func(ecModel, api);\n    });\n}\n\n\nvar MOUSE_EVENT_NAMES = [\n    'click', 'dblclick', 'mouseover', 'mouseout', 'mousemove',\n    'mousedown', 'mouseup', 'globalout', 'contextmenu'\n];\n\n/**\n * @private\n */\nechartsProto._initEvents = function () {\n    each(MOUSE_EVENT_NAMES, function (eveName) {\n        var handler = function (e) {\n            var ecModel = this.getModel();\n            var el = e.target;\n            var params;\n            var isGlobalOut = eveName === 'globalout';\n\n            // no e.target when 'globalout'.\n            if (isGlobalOut) {\n                params = {};\n            }\n            else if (el && el.dataIndex != null) {\n                var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex);\n                params = dataModel && dataModel.getDataParams(el.dataIndex, el.dataType, el) || {};\n            }\n            // If element has custom eventData of components\n            else if (el && el.eventData) {\n                params = extend({}, el.eventData);\n            }\n\n            // Contract: if params prepared in mouse event,\n            // these properties must be specified:\n            // {\n            //    componentType: string (component main type)\n            //    componentIndex: number\n            // }\n            // Otherwise event query can not work.\n\n            if (params) {\n                var componentType = params.componentType;\n                var componentIndex = params.componentIndex;\n                // Special handling for historic reason: when trigger by\n                // markLine/markPoint/markArea, the componentType is\n                // 'markLine'/'markPoint'/'markArea', but we should better\n                // enable them to be queried by seriesIndex, since their\n                // option is set in each series.\n                if (componentType === 'markLine'\n                    || componentType === 'markPoint'\n                    || componentType === 'markArea'\n                ) {\n                    componentType = 'series';\n                    componentIndex = params.seriesIndex;\n                }\n                var model = componentType && componentIndex != null\n                    && ecModel.getComponent(componentType, componentIndex);\n                var view = model && this[\n                    model.mainType === 'series' ? '_chartsMap' : '_componentsMap'\n                ][model.__viewId];\n\n                if (__DEV__) {\n                    // `event.componentType` and `event[componentTpype + 'Index']` must not\n                    // be missed, otherwise there is no way to distinguish source component.\n                    // See `dataFormat.getDataParams`.\n                    if (!isGlobalOut && !(model && view)) {\n                        console.warn('model or view can not be found by params');\n                    }\n                }\n\n                params.event = e;\n                params.type = eveName;\n\n                this._ecEventProcessor.eventInfo = {\n                    targetEl: el,\n                    packedEvent: params,\n                    model: model,\n                    view: view\n                };\n\n                this.trigger(eveName, params);\n            }\n        };\n        // Consider that some component (like tooltip, brush, ...)\n        // register zr event handler, but user event handler might\n        // do anything, such as call `setOption` or `dispatchAction`,\n        // which probably update any of the content and probably\n        // cause problem if it is called previous other inner handlers.\n        handler.zrEventfulCallAtLast = true;\n        this._zr.on(eveName, handler, this);\n    }, this);\n\n    each(eventActionMap, function (actionType, eventType) {\n        this._messageCenter.on(eventType, function (event) {\n            this.trigger(eventType, event);\n        }, this);\n    }, this);\n};\n\n/**\n * @return {boolean}\n */\nechartsProto.isDisposed = function () {\n    return this._disposed;\n};\n\n/**\n * Clear\n */\nechartsProto.clear = function () {\n    this.setOption({ series: [] }, true);\n};\n\n/**\n * Dispose instance\n */\nechartsProto.dispose = function () {\n    if (this._disposed) {\n        if (__DEV__) {\n            console.warn('Instance ' + this.id + ' has been disposed');\n        }\n        return;\n    }\n    this._disposed = true;\n\n    setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, '');\n\n    var api = this._api;\n    var ecModel = this._model;\n\n    each(this._componentsViews, function (component) {\n        component.dispose(ecModel, api);\n    });\n    each(this._chartsViews, function (chart) {\n        chart.dispose(ecModel, api);\n    });\n\n    // Dispose after all views disposed\n    this._zr.dispose();\n\n    delete instances[this.id];\n};\n\nmixin(ECharts, Eventful);\n\nfunction updateHoverLayerStatus(zr, ecModel) {\n    var storage = zr.storage;\n    var elCount = 0;\n    storage.traverse(function (el) {\n        if (!el.isGroup) {\n            elCount++;\n        }\n    });\n    if (elCount > ecModel.get('hoverLayerThreshold') && !env$1.node) {\n        storage.traverse(function (el) {\n            if (!el.isGroup) {\n                // Don't switch back.\n                el.useHoverLayer = true;\n            }\n        });\n    }\n}\n\n/**\n * Update chart progressive and blend.\n * @param {module:echarts/model/Series|module:echarts/model/Component} model\n * @param {module:echarts/view/Component|module:echarts/view/Chart} view\n */\nfunction updateBlend(seriesModel, chartView) {\n    var blendMode = seriesModel.get('blendMode') || null;\n    if (__DEV__) {\n        if (!env$1.canvasSupported && blendMode && blendMode !== 'source-over') {\n            console.warn('Only canvas support blendMode');\n        }\n    }\n    chartView.group.traverse(function (el) {\n        // FIXME marker and other components\n        if (!el.isGroup) {\n            // Only set if blendMode is changed. In case element is incremental and don't wan't to rerender.\n            if (el.style.blend !== blendMode) {\n                el.setStyle('blend', blendMode);\n            }\n        }\n        if (el.eachPendingDisplayable) {\n            el.eachPendingDisplayable(function (displayable) {\n                displayable.setStyle('blend', blendMode);\n            });\n        }\n    });\n}\n\n/**\n * @param {module:echarts/model/Series|module:echarts/model/Component} model\n * @param {module:echarts/view/Component|module:echarts/view/Chart} view\n */\nfunction updateZ(model, view) {\n    var z = model.get('z');\n    var zlevel = model.get('zlevel');\n    // Set z and zlevel\n    view.group.traverse(function (el) {\n        if (el.type !== 'group') {\n            z != null && (el.z = z);\n            zlevel != null && (el.zlevel = zlevel);\n        }\n    });\n}\n\nfunction createExtensionAPI(ecInstance) {\n    var coordSysMgr = ecInstance._coordSysMgr;\n    return extend(new ExtensionAPI(ecInstance), {\n        // Inject methods\n        getCoordinateSystems: bind(\n            coordSysMgr.getCoordinateSystems, coordSysMgr\n        ),\n        getComponentByElement: function (el) {\n            while (el) {\n                var modelInfo = el.__ecComponentInfo;\n                if (modelInfo != null) {\n                    return ecInstance._model.getComponent(modelInfo.mainType, modelInfo.index);\n                }\n                el = el.parent;\n            }\n        }\n    });\n}\n\n\n/**\n * @class\n * Usage of query:\n * `chart.on('click', query, handler);`\n * The `query` can be:\n * + The component type query string, only `mainType` or `mainType.subType`,\n *   like: 'xAxis', 'series', 'xAxis.category' or 'series.line'.\n * + The component query object, like:\n *   `{seriesIndex: 2}`, `{seriesName: 'xx'}`, `{seriesId: 'some'}`,\n *   `{xAxisIndex: 2}`, `{xAxisName: 'xx'}`, `{xAxisId: 'some'}`.\n * + The data query object, like:\n *   `{dataIndex: 123}`, `{dataType: 'link'}`, `{name: 'some'}`.\n * + The other query object (cmponent customized query), like:\n *   `{element: 'some'}` (only available in custom series).\n *\n * Caveat: If a prop in the `query` object is `null/undefined`, it is the\n * same as there is no such prop in the `query` object.\n */\nfunction EventProcessor() {\n    // These info required: targetEl, packedEvent, model, view\n    this.eventInfo;\n}\nEventProcessor.prototype = {\n    constructor: EventProcessor,\n\n    normalizeQuery: function (query) {\n        var cptQuery = {};\n        var dataQuery = {};\n        var otherQuery = {};\n\n        // `query` is `mainType` or `mainType.subType` of component.\n        if (isString(query)) {\n            var condCptType = parseClassType(query);\n            // `.main` and `.sub` may be ''.\n            cptQuery.mainType = condCptType.main || null;\n            cptQuery.subType = condCptType.sub || null;\n        }\n        // `query` is an object, convert to {mainType, index, name, id}.\n        else {\n            // `xxxIndex`, `xxxName`, `xxxId`, `name`, `dataIndex`, `dataType` is reserved,\n            // can not be used in `compomentModel.filterForExposedEvent`.\n            var suffixes = ['Index', 'Name', 'Id'];\n            var dataKeys = {name: 1, dataIndex: 1, dataType: 1};\n            each$1(query, function (val, key) {\n                var reserved = false;\n                for (var i = 0; i < suffixes.length; i++) {\n                    var propSuffix = suffixes[i];\n                    var suffixPos = key.lastIndexOf(propSuffix);\n                    if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) {\n                        var mainType = key.slice(0, suffixPos);\n                        // Consider `dataIndex`.\n                        if (mainType !== 'data') {\n                            cptQuery.mainType = mainType;\n                            cptQuery[propSuffix.toLowerCase()] = val;\n                            reserved = true;\n                        }\n                    }\n                }\n                if (dataKeys.hasOwnProperty(key)) {\n                    dataQuery[key] = val;\n                    reserved = true;\n                }\n                if (!reserved) {\n                    otherQuery[key] = val;\n                }\n            });\n        }\n\n        return {\n            cptQuery: cptQuery,\n            dataQuery: dataQuery,\n            otherQuery: otherQuery\n        };\n    },\n\n    filter: function (eventType, query, args) {\n        // They should be assigned before each trigger call.\n        var eventInfo = this.eventInfo;\n\n        if (!eventInfo) {\n            return true;\n        }\n\n        var targetEl = eventInfo.targetEl;\n        var packedEvent = eventInfo.packedEvent;\n        var model = eventInfo.model;\n        var view = eventInfo.view;\n\n        // For event like 'globalout'.\n        if (!model || !view) {\n            return true;\n        }\n\n        var cptQuery = query.cptQuery;\n        var dataQuery = query.dataQuery;\n\n        return check(cptQuery, model, 'mainType')\n            && check(cptQuery, model, 'subType')\n            && check(cptQuery, model, 'index', 'componentIndex')\n            && check(cptQuery, model, 'name')\n            && check(cptQuery, model, 'id')\n            && check(dataQuery, packedEvent, 'name')\n            && check(dataQuery, packedEvent, 'dataIndex')\n            && check(dataQuery, packedEvent, 'dataType')\n            && (!view.filterForExposedEvent || view.filterForExposedEvent(\n                eventType, query.otherQuery, targetEl, packedEvent\n            ));\n\n        function check(query, host, prop, propOnHost) {\n            return query[prop] == null || host[propOnHost || prop] === query[prop];\n        }\n    },\n\n    afterTrigger: function () {\n        // Make sure the eventInfo wont be used in next trigger.\n        this.eventInfo = null;\n    }\n};\n\n\n/**\n * @type {Object} key: actionType.\n * @inner\n */\nvar actions = {};\n\n/**\n * Map eventType to actionType\n * @type {Object}\n */\nvar eventActionMap = {};\n\n/**\n * Data processor functions of each stage\n * @type {Array.<Object.<string, Function>>}\n * @inner\n */\nvar dataProcessorFuncs = [];\n\n/**\n * @type {Array.<Function>}\n * @inner\n */\nvar optionPreprocessorFuncs = [];\n\n/**\n * @type {Array.<Function>}\n * @inner\n */\nvar postUpdateFuncs = [];\n\n/**\n * Visual encoding functions of each stage\n * @type {Array.<Object.<string, Function>>}\n */\nvar visualFuncs = [];\n\n/**\n * Theme storage\n * @type {Object.<key, Object>}\n */\nvar themeStorage = {};\n/**\n * Loading effects\n */\nvar loadingEffects = {};\n\nvar instances = {};\nvar connectedGroups = {};\n\nvar idBase = new Date() - 0;\nvar groupIdBase = new Date() - 0;\nvar DOM_ATTRIBUTE_KEY = '_echarts_instance_';\n\nfunction enableConnect(chart) {\n    var STATUS_PENDING = 0;\n    var STATUS_UPDATING = 1;\n    var STATUS_UPDATED = 2;\n    var STATUS_KEY = '__connectUpdateStatus';\n\n    function updateConnectedChartsStatus(charts, status) {\n        for (var i = 0; i < charts.length; i++) {\n            var otherChart = charts[i];\n            otherChart[STATUS_KEY] = status;\n        }\n    }\n\n    each(eventActionMap, function (actionType, eventType) {\n        chart._messageCenter.on(eventType, function (event) {\n            if (connectedGroups[chart.group] && chart[STATUS_KEY] !== STATUS_PENDING) {\n                if (event && event.escapeConnect) {\n                    return;\n                }\n\n                var action = chart.makeActionFromEvent(event);\n                var otherCharts = [];\n\n                each(instances, function (otherChart) {\n                    if (otherChart !== chart && otherChart.group === chart.group) {\n                        otherCharts.push(otherChart);\n                    }\n                });\n\n                updateConnectedChartsStatus(otherCharts, STATUS_PENDING);\n                each(otherCharts, function (otherChart) {\n                    if (otherChart[STATUS_KEY] !== STATUS_UPDATING) {\n                        otherChart.dispatchAction(action);\n                    }\n                });\n                updateConnectedChartsStatus(otherCharts, STATUS_UPDATED);\n            }\n        });\n    });\n}\n\n/**\n * @param {HTMLElement} dom\n * @param {Object} [theme]\n * @param {Object} opts\n * @param {number} [opts.devicePixelRatio] Use window.devicePixelRatio by default\n * @param {string} [opts.renderer] Currently only 'canvas' is supported.\n * @param {number} [opts.width] Use clientWidth of the input `dom` by default.\n *                              Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Use clientHeight of the input `dom` by default.\n *                               Can be 'auto' (the same as null/undefined)\n */\nfunction init(dom, theme$$1, opts) {\n    if (__DEV__) {\n        // Check version\n        if ((version$1.replace('.', '') - 0) < (dependencies.zrender.replace('.', '') - 0)) {\n            throw new Error(\n                'zrender/src ' + version$1\n                + ' is too old for ECharts ' + version\n                + '. Current version need ZRender '\n                + dependencies.zrender + '+'\n            );\n        }\n\n        if (!dom) {\n            throw new Error('Initialize failed: invalid dom.');\n        }\n    }\n\n    var existInstance = getInstanceByDom(dom);\n    if (existInstance) {\n        if (__DEV__) {\n            console.warn('There is a chart instance already initialized on the dom.');\n        }\n        return existInstance;\n    }\n\n    if (__DEV__) {\n        if (isDom(dom)\n            && dom.nodeName.toUpperCase() !== 'CANVAS'\n            && (\n                (!dom.clientWidth && (!opts || opts.width == null))\n                || (!dom.clientHeight && (!opts || opts.height == null))\n            )\n        ) {\n            console.warn('Can\\'t get dom width or height');\n        }\n    }\n\n    var chart = new ECharts(dom, theme$$1, opts);\n    chart.id = 'ec_' + idBase++;\n    instances[chart.id] = chart;\n\n    setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id);\n\n    enableConnect(chart);\n\n    return chart;\n}\n\n/**\n * @return {string|Array.<module:echarts~ECharts>} groupId\n */\nfunction connect(groupId) {\n    // Is array of charts\n    if (isArray(groupId)) {\n        var charts = groupId;\n        groupId = null;\n        // If any chart has group\n        each(charts, function (chart) {\n            if (chart.group != null) {\n                groupId = chart.group;\n            }\n        });\n        groupId = groupId || ('g_' + groupIdBase++);\n        each(charts, function (chart) {\n            chart.group = groupId;\n        });\n    }\n    connectedGroups[groupId] = true;\n    return groupId;\n}\n\n/**\n * @DEPRECATED\n * @return {string} groupId\n */\nfunction disConnect(groupId) {\n    connectedGroups[groupId] = false;\n}\n\n/**\n * @return {string} groupId\n */\nvar disconnect = disConnect;\n\n/**\n * Dispose a chart instance\n * @param  {module:echarts~ECharts|HTMLDomElement|string} chart\n */\nfunction dispose(chart) {\n    if (typeof chart === 'string') {\n        chart = instances[chart];\n    }\n    else if (!(chart instanceof ECharts)) {\n        // Try to treat as dom\n        chart = getInstanceByDom(chart);\n    }\n    if ((chart instanceof ECharts) && !chart.isDisposed()) {\n        chart.dispose();\n    }\n}\n\n/**\n * @param  {HTMLElement} dom\n * @return {echarts~ECharts}\n */\nfunction getInstanceByDom(dom) {\n    return instances[getAttribute(dom, DOM_ATTRIBUTE_KEY)];\n}\n\n/**\n * @param {string} key\n * @return {echarts~ECharts}\n */\nfunction getInstanceById(key) {\n    return instances[key];\n}\n\n/**\n * Register theme\n */\nfunction registerTheme(name, theme$$1) {\n    themeStorage[name] = theme$$1;\n}\n\n/**\n * Register option preprocessor\n * @param {Function} preprocessorFunc\n */\nfunction registerPreprocessor(preprocessorFunc) {\n    optionPreprocessorFuncs.push(preprocessorFunc);\n}\n\n/**\n * @param {number} [priority=1000]\n * @param {Object|Function} processor\n */\nfunction registerProcessor(priority, processor) {\n    normalizeRegister(dataProcessorFuncs, priority, processor, PRIORITY_PROCESSOR_FILTER);\n}\n\n/**\n * Register postUpdater\n * @param {Function} postUpdateFunc\n */\nfunction registerPostUpdate(postUpdateFunc) {\n    postUpdateFuncs.push(postUpdateFunc);\n}\n\n/**\n * Usage:\n * registerAction('someAction', 'someEvent', function () { ... });\n * registerAction('someAction', function () { ... });\n * registerAction(\n *     {type: 'someAction', event: 'someEvent', update: 'updateView'},\n *     function () { ... }\n * );\n *\n * @param {(string|Object)} actionInfo\n * @param {string} actionInfo.type\n * @param {string} [actionInfo.event]\n * @param {string} [actionInfo.update]\n * @param {string} [eventName]\n * @param {Function} action\n */\nfunction registerAction(actionInfo, eventName, action) {\n    if (typeof eventName === 'function') {\n        action = eventName;\n        eventName = '';\n    }\n    var actionType = isObject(actionInfo)\n        ? actionInfo.type\n        : ([actionInfo, actionInfo = {\n            event: eventName\n        }][0]);\n\n    // Event name is all lowercase\n    actionInfo.event = (actionInfo.event || actionType).toLowerCase();\n    eventName = actionInfo.event;\n\n    // Validate action type and event name.\n    assert(ACTION_REG.test(actionType) && ACTION_REG.test(eventName));\n\n    if (!actions[actionType]) {\n        actions[actionType] = {action: action, actionInfo: actionInfo};\n    }\n    eventActionMap[eventName] = actionType;\n}\n\n/**\n * @param {string} type\n * @param {*} CoordinateSystem\n */\nfunction registerCoordinateSystem(type, CoordinateSystem$$1) {\n    CoordinateSystemManager.register(type, CoordinateSystem$$1);\n}\n\n/**\n * Get dimensions of specified coordinate system.\n * @param {string} type\n * @return {Array.<string|Object>}\n */\nfunction getCoordinateSystemDimensions(type) {\n    var coordSysCreator = CoordinateSystemManager.get(type);\n    if (coordSysCreator) {\n        return coordSysCreator.getDimensionsInfo\n                ? coordSysCreator.getDimensionsInfo()\n                : coordSysCreator.dimensions.slice();\n    }\n}\n\n/**\n * Layout is a special stage of visual encoding\n * Most visual encoding like color are common for different chart\n * But each chart has it's own layout algorithm\n *\n * @param {number} [priority=1000]\n * @param {Function} layoutTask\n */\nfunction registerLayout(priority, layoutTask) {\n    normalizeRegister(visualFuncs, priority, layoutTask, PRIORITY_VISUAL_LAYOUT, 'layout');\n}\n\n/**\n * @param {number} [priority=3000]\n * @param {module:echarts/stream/Task} visualTask\n */\nfunction registerVisual(priority, visualTask) {\n    normalizeRegister(visualFuncs, priority, visualTask, PRIORITY_VISUAL_CHART, 'visual');\n}\n\n/**\n * @param {Object|Function} fn: {seriesType, createOnAllSeries, performRawSeries, reset}\n */\nfunction normalizeRegister(targetList, priority, fn, defaultPriority, visualType) {\n    if (isFunction(priority) || isObject(priority)) {\n        fn = priority;\n        priority = defaultPriority;\n    }\n\n    if (__DEV__) {\n        if (isNaN(priority) || priority == null) {\n            throw new Error('Illegal priority');\n        }\n        // Check duplicate\n        each(targetList, function (wrap) {\n            assert(wrap.__raw !== fn);\n        });\n    }\n\n    var stageHandler = Scheduler.wrapStageHandler(fn, visualType);\n\n    stageHandler.__prio = priority;\n    stageHandler.__raw = fn;\n    targetList.push(stageHandler);\n\n    return stageHandler;\n}\n\n/**\n * @param {string} name\n */\nfunction registerLoading(name, loadingFx) {\n    loadingEffects[name] = loadingFx;\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendComponentModel(opts/*, superClass*/) {\n    // var Clazz = ComponentModel;\n    // if (superClass) {\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentModel.getClass(classType.main, classType.sub, true);\n    // }\n    return ComponentModel.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendComponentView(opts/*, superClass*/) {\n    // var Clazz = ComponentView;\n    // if (superClass) {\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentView.getClass(classType.main, classType.sub, true);\n    // }\n    return Component$1.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendSeriesModel(opts/*, superClass*/) {\n    // var Clazz = SeriesModel;\n    // if (superClass) {\n    //     superClass = 'series.' + superClass.replace('series.', '');\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentModel.getClass(classType.main, classType.sub, true);\n    // }\n    return SeriesModel.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendChartView(opts/*, superClass*/) {\n    // var Clazz = ChartView;\n    // if (superClass) {\n    //     superClass = superClass.replace('series.', '');\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ChartView.getClass(classType.main, true);\n    // }\n    return Chart.extend(opts);\n}\n\n/**\n * ZRender need a canvas context to do measureText.\n * But in node environment canvas may be created by node-canvas.\n * So we need to specify how to create a canvas instead of using document.createElement('canvas')\n *\n * Be careful of using it in the browser.\n *\n * @param {Function} creator\n * @example\n *     var Canvas = require('canvas');\n *     var echarts = require('echarts');\n *     echarts.setCanvasCreator(function () {\n *         // Small size is enough.\n *         return new Canvas(32, 32);\n *     });\n */\nfunction setCanvasCreator(creator) {\n    $override('createCanvas', creator);\n}\n\n/**\n * @param {string} mapName\n * @param {Array.<Object>|Object|string} geoJson\n * @param {Object} [specialAreas]\n *\n * @example GeoJSON\n *     $.get('USA.json', function (geoJson) {\n *         echarts.registerMap('USA', geoJson);\n *         // Or\n *         echarts.registerMap('USA', {\n *             geoJson: geoJson,\n *             specialAreas: {}\n *         })\n *     });\n *\n *     $.get('airport.svg', function (svg) {\n *         echarts.registerMap('airport', {\n *             svg: svg\n *         }\n *     });\n *\n *     echarts.registerMap('eu', [\n *         {svg: eu-topographic.svg},\n *         {geoJSON: eu.json}\n *     ])\n */\nfunction registerMap(mapName, geoJson, specialAreas) {\n    mapDataStorage.registerMap(mapName, geoJson, specialAreas);\n}\n\n/**\n * @param {string} mapName\n * @return {Object}\n */\nfunction getMap(mapName) {\n    // For backward compatibility, only return the first one.\n    var records = mapDataStorage.retrieveMap(mapName);\n    return records && records[0] && {\n        geoJson: records[0].geoJSON,\n        specialAreas: records[0].specialAreas\n    };\n}\n\nregisterVisual(PRIORITY_VISUAL_GLOBAL, seriesColor);\nregisterPreprocessor(backwardCompat);\nregisterProcessor(PRIORITY_PROCESSOR_STATISTIC, dataStack);\nregisterLoading('default', loadingDefault);\n\n// Default actions\n\nregisterAction({\n    type: 'highlight',\n    event: 'highlight',\n    update: 'highlight'\n}, noop);\n\nregisterAction({\n    type: 'downplay',\n    event: 'downplay',\n    update: 'downplay'\n}, noop);\n\n// Default theme\nregisterTheme('light', lightTheme);\nregisterTheme('dark', theme);\n\n// For backward compatibility, where the namespace `dataTool` will\n// be mounted on `echarts` is the extension `dataTool` is imported.\nvar dataTool = {};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction defaultKeyGetter(item) {\n    return item;\n}\n\n/**\n * @param {Array} oldArr\n * @param {Array} newArr\n * @param {Function} oldKeyGetter\n * @param {Function} newKeyGetter\n * @param {Object} [context] Can be visited by this.context in callback.\n */\nfunction DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter, context) {\n    this._old = oldArr;\n    this._new = newArr;\n\n    this._oldKeyGetter = oldKeyGetter || defaultKeyGetter;\n    this._newKeyGetter = newKeyGetter || defaultKeyGetter;\n\n    this.context = context;\n}\n\nDataDiffer.prototype = {\n\n    constructor: DataDiffer,\n\n    /**\n     * Callback function when add a data\n     */\n    add: function (func) {\n        this._add = func;\n        return this;\n    },\n\n    /**\n     * Callback function when update a data\n     */\n    update: function (func) {\n        this._update = func;\n        return this;\n    },\n\n    /**\n     * Callback function when remove a data\n     */\n    remove: function (func) {\n        this._remove = func;\n        return this;\n    },\n\n    execute: function () {\n        var oldArr = this._old;\n        var newArr = this._new;\n\n        var oldDataIndexMap = {};\n        var newDataIndexMap = {};\n        var oldDataKeyArr = [];\n        var newDataKeyArr = [];\n        var i;\n\n        initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, '_oldKeyGetter', this);\n        initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter', this);\n\n        // Travel by inverted order to make sure order consistency\n        // when duplicate keys exists (consider newDataIndex.pop() below).\n        // For performance consideration, these code below do not look neat.\n        for (i = 0; i < oldArr.length; i++) {\n            var key = oldDataKeyArr[i];\n            var idx = newDataIndexMap[key];\n\n            // idx can never be empty array here. see 'set null' logic below.\n            if (idx != null) {\n                // Consider there is duplicate key (for example, use dataItem.name as key).\n                // We should make sure every item in newArr and oldArr can be visited.\n                var len = idx.length;\n                if (len) {\n                    len === 1 && (newDataIndexMap[key] = null);\n                    idx = idx.unshift();\n                }\n                else {\n                    newDataIndexMap[key] = null;\n                }\n                this._update && this._update(idx, i);\n            }\n            else {\n                this._remove && this._remove(i);\n            }\n        }\n\n        for (var i = 0; i < newDataKeyArr.length; i++) {\n            var key = newDataKeyArr[i];\n            if (newDataIndexMap.hasOwnProperty(key)) {\n                var idx = newDataIndexMap[key];\n                if (idx == null) {\n                    continue;\n                }\n                // idx can never be empty array here. see 'set null' logic above.\n                if (!idx.length) {\n                    this._add && this._add(idx);\n                }\n                else {\n                    for (var j = 0, len = idx.length; j < len; j++) {\n                        this._add && this._add(idx[j]);\n                    }\n                }\n            }\n        }\n    }\n};\n\nfunction initIndexMap(arr, map, keyArr, keyGetterName, dataDiffer) {\n    for (var i = 0; i < arr.length; i++) {\n        // Add prefix to avoid conflict with Object.prototype.\n        var key = '_ec_' + dataDiffer[keyGetterName](arr[i], i);\n        var existence = map[key];\n        if (existence == null) {\n            keyArr.push(key);\n            map[key] = i;\n        }\n        else {\n            if (!existence.length) {\n                map[key] = existence = [existence];\n            }\n            existence.push(i);\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar OTHER_DIMENSIONS = createHashMap([\n    'tooltip', 'label', 'itemName', 'itemId', 'seriesName'\n]);\n\nfunction summarizeDimensions(data) {\n    var summary = {};\n    var encode = summary.encode = {};\n    var notExtraCoordDimMap = createHashMap();\n    var defaultedLabel = [];\n    var defaultedTooltip = [];\n\n    each$1(data.dimensions, function (dimName) {\n        var dimItem = data.getDimensionInfo(dimName);\n\n        var coordDim = dimItem.coordDim;\n        if (coordDim) {\n            if (__DEV__) {\n                assert$1(OTHER_DIMENSIONS.get(coordDim) == null);\n            }\n            var coordDimArr = encode[coordDim];\n            if (!encode.hasOwnProperty(coordDim)) {\n                coordDimArr = encode[coordDim] = [];\n            }\n            coordDimArr[dimItem.coordDimIndex] = dimName;\n\n            if (!dimItem.isExtraCoord) {\n                notExtraCoordDimMap.set(coordDim, 1);\n\n                // Use the last coord dim (and label friendly) as default label,\n                // because when dataset is used, it is hard to guess which dimension\n                // can be value dimension. If both show x, y on label is not look good,\n                // and conventionally y axis is focused more.\n                if (mayLabelDimType(dimItem.type)) {\n                    defaultedLabel[0] = dimName;\n                }\n            }\n            if (dimItem.defaultTooltip) {\n                defaultedTooltip.push(dimName);\n            }\n        }\n\n        OTHER_DIMENSIONS.each(function (v, otherDim) {\n            var otherDimArr = encode[otherDim];\n            if (!encode.hasOwnProperty(otherDim)) {\n                otherDimArr = encode[otherDim] = [];\n            }\n\n            var dimIndex = dimItem.otherDims[otherDim];\n            if (dimIndex != null && dimIndex !== false) {\n                otherDimArr[dimIndex] = dimItem.name;\n            }\n        });\n    });\n\n    var dataDimsOnCoord = [];\n    var encodeFirstDimNotExtra = {};\n\n    notExtraCoordDimMap.each(function (v, coordDim) {\n        var dimArr = encode[coordDim];\n        // ??? FIXME extra coord should not be set in dataDimsOnCoord.\n        // But should fix the case that radar axes: simplify the logic\n        // of `completeDimension`, remove `extraPrefix`.\n        encodeFirstDimNotExtra[coordDim] = dimArr[0];\n        // Not necessary to remove duplicate, because a data\n        // dim canot on more than one coordDim.\n        dataDimsOnCoord = dataDimsOnCoord.concat(dimArr);\n    });\n\n    summary.dataDimsOnCoord = dataDimsOnCoord;\n    summary.encodeFirstDimNotExtra = encodeFirstDimNotExtra;\n\n    var encodeLabel = encode.label;\n    // FIXME `encode.label` is not recommanded, because formatter can not be set\n    // in this way. Use label.formatter instead. May be remove this approach someday.\n    if (encodeLabel && encodeLabel.length) {\n        defaultedLabel = encodeLabel.slice();\n    }\n\n    var encodeTooltip = encode.tooltip;\n    if (encodeTooltip && encodeTooltip.length) {\n        defaultedTooltip = encodeTooltip.slice();\n    }\n    else if (!defaultedTooltip.length) {\n        defaultedTooltip = defaultedLabel.slice();\n    }\n\n    encode.defaultedLabel = defaultedLabel;\n    encode.defaultedTooltip = defaultedTooltip;\n\n    return summary;\n}\n\nfunction getDimensionTypeByAxis(axisType) {\n    return axisType === 'category'\n        ? 'ordinal'\n        : axisType === 'time'\n        ? 'time'\n        : 'float';\n}\n\nfunction mayLabelDimType(dimType) {\n    // In most cases, ordinal and time do not suitable for label.\n    // Ordinal info can be displayed on axis. Time is too long.\n    return !(dimType === 'ordinal' || dimType === 'time');\n}\n\n// function findTheLastDimMayLabel(data) {\n//     // Get last value dim\n//     var dimensions = data.dimensions.slice();\n//     var valueType;\n//     var valueDim;\n//     while (dimensions.length && (\n//         valueDim = dimensions.pop(),\n//         valueType = data.getDimensionInfo(valueDim).type,\n//         valueType === 'ordinal' || valueType === 'time'\n//     )) {} // jshint ignore:line\n//     return valueDim;\n// }\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float64Array, Int32Array, Uint32Array, Uint16Array */\n\n/**\n * List for data storage\n * @module echarts/data/List\n */\n\nvar isObject$4 = isObject$1;\n\nvar UNDEFINED = 'undefined';\nvar INDEX_NOT_FOUND = -1;\n\n// Use prefix to avoid index to be the same as otherIdList[idx],\n// which will cause weird udpate animation.\nvar ID_PREFIX = 'e\\0\\0';\n\nvar dataCtors = {\n    'float': typeof Float64Array === UNDEFINED\n        ? Array : Float64Array,\n    'int': typeof Int32Array === UNDEFINED\n        ? Array : Int32Array,\n    // Ordinal data type can be string or int\n    'ordinal': Array,\n    'number': Array,\n    'time': Array\n};\n\n// Caution: MUST not use `new CtorUint32Array(arr, 0, len)`, because the Ctor of array is\n// different from the Ctor of typed array.\nvar CtorUint32Array = typeof Uint32Array === UNDEFINED ? Array : Uint32Array;\nvar CtorInt32Array = typeof Int32Array === UNDEFINED ? Array : Int32Array;\nvar CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array;\n\nfunction getIndicesCtor(list) {\n    // The possible max value in this._indicies is always this._rawCount despite of filtering.\n    return list._rawCount > 65535 ? CtorUint32Array : CtorUint16Array;\n}\n\nfunction cloneChunk(originalChunk) {\n    var Ctor = originalChunk.constructor;\n    // Only shallow clone is enough when Array.\n    return Ctor === Array ? originalChunk.slice() : new Ctor(originalChunk);\n}\n\nvar TRANSFERABLE_PROPERTIES = [\n    'hasItemOption', '_nameList', '_idList', '_invertedIndicesMap',\n    '_rawData', '_chunkSize', '_chunkCount', '_dimValueGetter',\n    '_count', '_rawCount', '_nameDimIdx', '_idDimIdx'\n];\nvar CLONE_PROPERTIES = [\n    '_extent', '_approximateExtent', '_rawExtent'\n];\n\nfunction transferProperties(target, source) {\n    each$1(TRANSFERABLE_PROPERTIES.concat(source.__wrappedMethods || []), function (propName) {\n        if (source.hasOwnProperty(propName)) {\n            target[propName] = source[propName];\n        }\n    });\n\n    target.__wrappedMethods = source.__wrappedMethods;\n\n    each$1(CLONE_PROPERTIES, function (propName) {\n        target[propName] = clone(source[propName]);\n    });\n\n    target._calculationInfo = extend(source._calculationInfo);\n}\n\n\n\n\n\n/**\n * @constructor\n * @alias module:echarts/data/List\n *\n * @param {Array.<string|Object>} dimensions\n *      For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...].\n *      Dimensions should be concrete names like x, y, z, lng, lat, angle, radius\n *      Spetial fields: {\n *          ordinalMeta: <module:echarts/data/OrdinalMeta>\n *          createInvertedIndices: <boolean>\n *      }\n * @param {module:echarts/model/Model} hostModel\n */\nvar List = function (dimensions, hostModel) {\n\n    dimensions = dimensions || ['x', 'y'];\n\n    var dimensionInfos = {};\n    var dimensionNames = [];\n    var invertedIndicesMap = {};\n\n    for (var i = 0; i < dimensions.length; i++) {\n        // Use the original dimensions[i], where other flag props may exists.\n        var dimensionInfo = dimensions[i];\n\n        if (isString(dimensionInfo)) {\n            dimensionInfo = {name: dimensionInfo};\n        }\n\n        var dimensionName = dimensionInfo.name;\n        dimensionInfo.type = dimensionInfo.type || 'float';\n        if (!dimensionInfo.coordDim) {\n            dimensionInfo.coordDim = dimensionName;\n            dimensionInfo.coordDimIndex = 0;\n        }\n\n        dimensionInfo.otherDims = dimensionInfo.otherDims || {};\n        dimensionNames.push(dimensionName);\n        dimensionInfos[dimensionName] = dimensionInfo;\n\n        dimensionInfo.index = i;\n\n        if (dimensionInfo.createInvertedIndices) {\n            invertedIndicesMap[dimensionName] = [];\n        }\n    }\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    this.dimensions = dimensionNames;\n\n    /**\n     * Infomation of each data dimension, like data type.\n     * @type {Object}\n     */\n    this._dimensionInfos = dimensionInfos;\n\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.hostModel = hostModel;\n\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.dataType;\n\n    /**\n     * Indices stores the indices of data subset after filtered.\n     * This data subset will be used in chart.\n     * @type {Array.<number>}\n     * @readOnly\n     */\n    this._indices = null;\n\n    this._count = 0;\n    this._rawCount = 0;\n\n    /**\n     * Data storage\n     * @type {Object.<key, Array.<TypedArray|Array>>}\n     * @private\n     */\n    this._storage = {};\n\n    /**\n     * @type {Array.<string>}\n     */\n    this._nameList = [];\n    /**\n     * @type {Array.<string>}\n     */\n    this._idList = [];\n\n    /**\n     * Models of data option is stored sparse for optimizing memory cost\n     * @type {Array.<module:echarts/model/Model>}\n     * @private\n     */\n    this._optionModels = [];\n\n    /**\n     * Global visual properties after visual coding\n     * @type {Object}\n     * @private\n     */\n    this._visual = {};\n\n    /**\n     * Globel layout properties.\n     * @type {Object}\n     * @private\n     */\n    this._layout = {};\n\n    /**\n     * Item visual properties after visual coding\n     * @type {Array.<Object>}\n     * @private\n     */\n    this._itemVisuals = [];\n\n    /**\n     * Key: visual type, Value: boolean\n     * @type {Object}\n     * @readOnly\n     */\n    this.hasItemVisual = {};\n\n    /**\n     * Item layout properties after layout\n     * @type {Array.<Object>}\n     * @private\n     */\n    this._itemLayouts = [];\n\n    /**\n     * Graphic elemnents\n     * @type {Array.<module:zrender/Element>}\n     * @private\n     */\n    this._graphicEls = [];\n\n    /**\n     * Max size of each chunk.\n     * @type {number}\n     * @private\n     */\n    this._chunkSize = 1e5;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    this._chunkCount = 0;\n\n    /**\n     * @type {Array.<Array|Object>}\n     * @private\n     */\n    this._rawData;\n\n    /**\n     * Raw extent will not be cloned, but only transfered.\n     * It will not be calculated util needed.\n     * key: dim,\n     * value: {end: number, extent: Array.<number>}\n     * @type {Object}\n     * @private\n     */\n    this._rawExtent = {};\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._extent = {};\n\n    /**\n     * key: dim\n     * value: extent\n     * @type {Object}\n     * @private\n     */\n    this._approximateExtent = {};\n\n    /**\n     * Cache summary info for fast visit. See \"dimensionHelper\".\n     * @type {Object}\n     * @private\n     */\n    this._dimensionsSummary = summarizeDimensions(this);\n\n    /**\n     * @type {Object.<Array|TypedArray>}\n     * @private\n     */\n    this._invertedIndicesMap = invertedIndicesMap;\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._calculationInfo = {};\n};\n\nvar listProto = List.prototype;\n\nlistProto.type = 'list';\n\n/**\n * If each data item has it's own option\n * @type {boolean}\n */\nlistProto.hasItemOption = true;\n\n/**\n * Get dimension name\n * @param {string|number} dim\n *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius\n *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'\n * @return {string} Concrete dim name.\n */\nlistProto.getDimension = function (dim) {\n    if (!isNaN(dim)) {\n        dim = this.dimensions[dim] || dim;\n    }\n    return dim;\n};\n\n/**\n * Get type and calculation info of particular dimension\n * @param {string|number} dim\n *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius\n *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'\n */\nlistProto.getDimensionInfo = function (dim) {\n    // Do not clone, because there may be categories in dimInfo.\n    return this._dimensionInfos[this.getDimension(dim)];\n};\n\n/**\n * @return {Array.<string>} concrete dimension name list on coord.\n */\nlistProto.getDimensionsOnCoord = function () {\n    return this._dimensionsSummary.dataDimsOnCoord.slice();\n};\n\n/**\n * @param {string} coordDim\n * @param {number} [idx] A coordDim may map to more than one data dim.\n *        If idx is `true`, return a array of all mapped dims.\n *        If idx is not specified, return the first dim not extra.\n * @return {string|Array.<string>} concrete data dim.\n *        If idx is number, and not found, return null/undefined.\n *        If idx is `true`, and not found, return empty array (always return array).\n */\nlistProto.mapDimension = function (coordDim, idx) {\n    var dimensionsSummary = this._dimensionsSummary;\n\n    if (idx == null) {\n        return dimensionsSummary.encodeFirstDimNotExtra[coordDim];\n    }\n\n    var dims = dimensionsSummary.encode[coordDim];\n    return idx === true\n        // always return array if idx is `true`\n        ? (dims || []).slice()\n        : (dims && dims[idx]);\n};\n\n/**\n * Initialize from data\n * @param {Array.<Object|number|Array>} data source or data or data provider.\n * @param {Array.<string>} [nameLIst] The name of a datum is used on data diff and\n *        defualt label/tooltip.\n *        A name can be specified in encode.itemName,\n *        or dataItem.name (only for series option data),\n *        or provided in nameList from outside.\n * @param {Function} [dimValueGetter] (dataItem, dimName, dataIndex, dimIndex) => number\n */\nlistProto.initData = function (data, nameList, dimValueGetter) {\n\n    var notProvider = Source.isInstance(data) || isArrayLike(data);\n    if (notProvider) {\n        data = new DefaultDataProvider(data, this.dimensions.length);\n    }\n\n    if (__DEV__) {\n        if (!notProvider && (typeof data.getItem !== 'function' || typeof data.count !== 'function')) {\n            throw new Error('Inavlid data provider.');\n        }\n    }\n\n    this._rawData = data;\n\n    // Clear\n    this._storage = {};\n    this._indices = null;\n\n    this._nameList = nameList || [];\n\n    this._idList = [];\n\n    this._nameRepeatCount = {};\n\n    if (!dimValueGetter) {\n        this.hasItemOption = false;\n    }\n\n    /**\n     * @readOnly\n     */\n    this.defaultDimValueGetter = defaultDimValueGetters[\n        this._rawData.getSource().sourceFormat\n    ];\n    // Default dim value getter\n    this._dimValueGetter = dimValueGetter = dimValueGetter\n        || this.defaultDimValueGetter;\n    this._dimValueGetterArrayRows = defaultDimValueGetters.arrayRows;\n\n    // Reset raw extent.\n    this._rawExtent = {};\n\n    this._initDataFromProvider(0, data.count());\n\n    // If data has no item option.\n    if (data.pure) {\n        this.hasItemOption = false;\n    }\n};\n\nlistProto.getProvider = function () {\n    return this._rawData;\n};\n\n/**\n * Caution: Can be only called on raw data (before `this._indices` created).\n */\nlistProto.appendData = function (data) {\n    if (__DEV__) {\n        assert$1(!this._indices, 'appendData can only be called on raw data.');\n    }\n\n    var rawData = this._rawData;\n    var start = this.count();\n    rawData.appendData(data);\n    var end = rawData.count();\n    if (!rawData.persistent) {\n        end += start;\n    }\n    this._initDataFromProvider(start, end);\n};\n\n/**\n * Caution: Can be only called on raw data (before `this._indices` created).\n * This method does not modify `rawData` (`dataProvider`), but only\n * add values to storage.\n *\n * The final count will be increased by `Math.max(values.length, names.length)`.\n *\n * @param {Array.<Array.<*>>} values That is the SourceType: 'arrayRows', like\n *        [\n *            [12, 33, 44],\n *            [NaN, 43, 1],\n *            ['-', 'asdf', 0]\n *        ]\n *        Each item is exaclty cooresponding to a dimension.\n * @param {Array.<string>} [names]\n */\nlistProto.appendValues = function (values, names) {\n    var chunkSize = this._chunkSize;\n    var storage = this._storage;\n    var dimensions = this.dimensions;\n    var dimLen = dimensions.length;\n    var rawExtent = this._rawExtent;\n\n    var start = this.count();\n    var end = start + Math.max(values.length, names ? names.length : 0);\n    var originalChunkCount = this._chunkCount;\n\n    for (var i = 0; i < dimLen; i++) {\n        var dim = dimensions[i];\n        if (!rawExtent[dim]) {\n            rawExtent[dim] = getInitialExtent();\n        }\n        if (!storage[dim]) {\n            storage[dim] = [];\n        }\n        prepareChunks(storage, this._dimensionInfos[dim], chunkSize, originalChunkCount, end);\n        this._chunkCount = storage[dim].length;\n    }\n\n    var emptyDataItem = new Array(dimLen);\n    for (var idx = start; idx < end; idx++) {\n        var sourceIdx = idx - start;\n        var chunkIndex = Math.floor(idx / chunkSize);\n        var chunkOffset = idx % chunkSize;\n\n        // Store the data by dimensions\n        for (var k = 0; k < dimLen; k++) {\n            var dim = dimensions[k];\n            var val = this._dimValueGetterArrayRows(\n                values[sourceIdx] || emptyDataItem, dim, sourceIdx, k\n            );\n            storage[dim][chunkIndex][chunkOffset] = val;\n\n            var dimRawExtent = rawExtent[dim];\n            val < dimRawExtent[0] && (dimRawExtent[0] = val);\n            val > dimRawExtent[1] && (dimRawExtent[1] = val);\n        }\n\n        if (names) {\n            this._nameList[idx] = names[sourceIdx];\n        }\n    }\n\n    this._rawCount = this._count = end;\n\n    // Reset data extent\n    this._extent = {};\n\n    prepareInvertedIndex(this);\n};\n\nlistProto._initDataFromProvider = function (start, end) {\n    // Optimize.\n    if (start >= end) {\n        return;\n    }\n\n    var chunkSize = this._chunkSize;\n    var rawData = this._rawData;\n    var storage = this._storage;\n    var dimensions = this.dimensions;\n    var dimLen = dimensions.length;\n    var dimensionInfoMap = this._dimensionInfos;\n    var nameList = this._nameList;\n    var idList = this._idList;\n    var rawExtent = this._rawExtent;\n    var nameRepeatCount = this._nameRepeatCount = {};\n    var nameDimIdx;\n\n    var originalChunkCount = this._chunkCount;\n    for (var i = 0; i < dimLen; i++) {\n        var dim = dimensions[i];\n        if (!rawExtent[dim]) {\n            rawExtent[dim] = getInitialExtent();\n        }\n\n        var dimInfo = dimensionInfoMap[dim];\n        if (dimInfo.otherDims.itemName === 0) {\n            nameDimIdx = this._nameDimIdx = i;\n        }\n        if (dimInfo.otherDims.itemId === 0) {\n            this._idDimIdx = i;\n        }\n\n        if (!storage[dim]) {\n            storage[dim] = [];\n        }\n\n        prepareChunks(storage, dimInfo, chunkSize, originalChunkCount, end);\n\n        this._chunkCount = storage[dim].length;\n    }\n\n    var dataItem = new Array(dimLen);\n    for (var idx = start; idx < end; idx++) {\n        // NOTICE: Try not to write things into dataItem\n        dataItem = rawData.getItem(idx, dataItem);\n        // Each data item is value\n        // [1, 2]\n        // 2\n        // Bar chart, line chart which uses category axis\n        // only gives the 'y' value. 'x' value is the indices of category\n        // Use a tempValue to normalize the value to be a (x, y) value\n        var chunkIndex = Math.floor(idx / chunkSize);\n        var chunkOffset = idx % chunkSize;\n\n        // Store the data by dimensions\n        for (var k = 0; k < dimLen; k++) {\n            var dim = dimensions[k];\n            var dimStorage = storage[dim][chunkIndex];\n            // PENDING NULL is empty or zero\n            var val = this._dimValueGetter(dataItem, dim, idx, k);\n            dimStorage[chunkOffset] = val;\n\n            var dimRawExtent = rawExtent[dim];\n            val < dimRawExtent[0] && (dimRawExtent[0] = val);\n            val > dimRawExtent[1] && (dimRawExtent[1] = val);\n        }\n\n        // ??? FIXME not check by pure but sourceFormat?\n        // TODO refactor these logic.\n        if (!rawData.pure) {\n            var name = nameList[idx];\n\n            if (dataItem && name == null) {\n                // If dataItem is {name: ...}, it has highest priority.\n                // That is appropriate for many common cases.\n                if (dataItem.name != null) {\n                    // There is no other place to persistent dataItem.name,\n                    // so save it to nameList.\n                    nameList[idx] = name = dataItem.name;\n                }\n                else if (nameDimIdx != null) {\n                    var nameDim = dimensions[nameDimIdx];\n                    var nameDimChunk = storage[nameDim][chunkIndex];\n                    if (nameDimChunk) {\n                        name = nameDimChunk[chunkOffset];\n                        var ordinalMeta = dimensionInfoMap[nameDim].ordinalMeta;\n                        if (ordinalMeta && ordinalMeta.categories.length) {\n                            name = ordinalMeta.categories[name];\n                        }\n                    }\n                }\n            }\n\n            // Try using the id in option\n            // id or name is used on dynamical data, mapping old and new items.\n            var id = dataItem == null ? null : dataItem.id;\n\n            if (id == null && name != null) {\n                // Use name as id and add counter to avoid same name\n                nameRepeatCount[name] = nameRepeatCount[name] || 0;\n                id = name;\n                if (nameRepeatCount[name] > 0) {\n                    id += '__ec__' + nameRepeatCount[name];\n                }\n                nameRepeatCount[name]++;\n            }\n            id != null && (idList[idx] = id);\n        }\n    }\n\n    if (!rawData.persistent && rawData.clean) {\n        // Clean unused data if data source is typed array.\n        rawData.clean();\n    }\n\n    this._rawCount = this._count = end;\n\n    // Reset data extent\n    this._extent = {};\n\n    prepareInvertedIndex(this);\n};\n\nfunction prepareChunks(storage, dimInfo, chunkSize, chunkCount, end) {\n    var DataCtor = dataCtors[dimInfo.type];\n    var lastChunkIndex = chunkCount - 1;\n    var dim = dimInfo.name;\n    var resizeChunkArray = storage[dim][lastChunkIndex];\n    if (resizeChunkArray && resizeChunkArray.length < chunkSize) {\n        var newStore = new DataCtor(Math.min(end - lastChunkIndex * chunkSize, chunkSize));\n        // The cost of the copy is probably inconsiderable\n        // within the initial chunkSize.\n        for (var j = 0; j < resizeChunkArray.length; j++) {\n            newStore[j] = resizeChunkArray[j];\n        }\n        storage[dim][lastChunkIndex] = newStore;\n    }\n\n    // Create new chunks.\n    for (var k = chunkCount * chunkSize; k < end; k += chunkSize) {\n        storage[dim].push(new DataCtor(Math.min(end - k, chunkSize)));\n    }\n}\n\nfunction prepareInvertedIndex(list) {\n    var invertedIndicesMap = list._invertedIndicesMap;\n    each$1(invertedIndicesMap, function (invertedIndices, dim) {\n        var dimInfo = list._dimensionInfos[dim];\n\n        // Currently, only dimensions that has ordinalMeta can create inverted indices.\n        var ordinalMeta = dimInfo.ordinalMeta;\n        if (ordinalMeta) {\n            invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array(\n                ordinalMeta.categories.length\n            );\n            // The default value of TypedArray is 0. To avoid miss\n            // mapping to 0, we should set it as INDEX_NOT_FOUND.\n            for (var i = 0; i < invertedIndices.length; i++) {\n                invertedIndices[i] = INDEX_NOT_FOUND;\n            }\n            for (var i = 0; i < list._count; i++) {\n                // Only support the case that all values are distinct.\n                invertedIndices[list.get(dim, i)] = i;\n            }\n        }\n    });\n}\n\nfunction getRawValueFromStore(list, dimIndex, rawIndex) {\n    var val;\n    if (dimIndex != null) {\n        var chunkSize = list._chunkSize;\n        var chunkIndex = Math.floor(rawIndex / chunkSize);\n        var chunkOffset = rawIndex % chunkSize;\n        var dim = list.dimensions[dimIndex];\n        var chunk = list._storage[dim][chunkIndex];\n        if (chunk) {\n            val = chunk[chunkOffset];\n            var ordinalMeta = list._dimensionInfos[dim].ordinalMeta;\n            if (ordinalMeta && ordinalMeta.categories.length) {\n                val = ordinalMeta.categories[val];\n            }\n        }\n    }\n    return val;\n}\n\n/**\n * @return {number}\n */\nlistProto.count = function () {\n    return this._count;\n};\n\nlistProto.getIndices = function () {\n    var newIndices;\n\n    var indices = this._indices;\n    if (indices) {\n        var Ctor = indices.constructor;\n        var thisCount = this._count;\n        // `new Array(a, b, c)` is different from `new Uint32Array(a, b, c)`.\n        if (Ctor === Array) {\n            newIndices = new Ctor(thisCount);\n            for (var i = 0; i < thisCount; i++) {\n                newIndices[i] = indices[i];\n            }\n        }\n        else {\n            newIndices = new Ctor(indices.buffer, 0, thisCount);\n        }\n    }\n    else {\n        var Ctor = getIndicesCtor(this);\n        var newIndices = new Ctor(this.count());\n        for (var i = 0; i < newIndices.length; i++) {\n            newIndices[i] = i;\n        }\n    }\n\n    return newIndices;\n};\n\n/**\n * Get value. Return NaN if idx is out of range.\n * @param {string} dim Dim must be concrete name.\n * @param {number} idx\n * @param {boolean} stack\n * @return {number}\n */\nlistProto.get = function (dim, idx /*, stack */) {\n    if (!(idx >= 0 && idx < this._count)) {\n        return NaN;\n    }\n    var storage = this._storage;\n    if (!storage[dim]) {\n        // TODO Warn ?\n        return NaN;\n    }\n\n    idx = this.getRawIndex(idx);\n\n    var chunkIndex = Math.floor(idx / this._chunkSize);\n    var chunkOffset = idx % this._chunkSize;\n\n    var chunkStore = storage[dim][chunkIndex];\n    var value = chunkStore[chunkOffset];\n    // FIXME ordinal data type is not stackable\n    // if (stack) {\n    //     var dimensionInfo = this._dimensionInfos[dim];\n    //     if (dimensionInfo && dimensionInfo.stackable) {\n    //         var stackedOn = this.stackedOn;\n    //         while (stackedOn) {\n    //             // Get no stacked data of stacked on\n    //             var stackedValue = stackedOn.get(dim, idx);\n    //             // Considering positive stack, negative stack and empty data\n    //             if ((value >= 0 && stackedValue > 0)  // Positive stack\n    //                 || (value <= 0 && stackedValue < 0) // Negative stack\n    //             ) {\n    //                 value += stackedValue;\n    //             }\n    //             stackedOn = stackedOn.stackedOn;\n    //         }\n    //     }\n    // }\n\n    return value;\n};\n\n/**\n * @param {string} dim concrete dim\n * @param {number} rawIndex\n * @return {number|string}\n */\nlistProto.getByRawIndex = function (dim, rawIdx) {\n    if (!(rawIdx >= 0 && rawIdx < this._rawCount)) {\n        return NaN;\n    }\n    var dimStore = this._storage[dim];\n    if (!dimStore) {\n        // TODO Warn ?\n        return NaN;\n    }\n\n    var chunkIndex = Math.floor(rawIdx / this._chunkSize);\n    var chunkOffset = rawIdx % this._chunkSize;\n    var chunkStore = dimStore[chunkIndex];\n    return chunkStore[chunkOffset];\n};\n\n/**\n * FIXME Use `get` on chrome maybe slow(in filterSelf and selectRange).\n * Hack a much simpler _getFast\n * @private\n */\nlistProto._getFast = function (dim, rawIdx) {\n    var chunkIndex = Math.floor(rawIdx / this._chunkSize);\n    var chunkOffset = rawIdx % this._chunkSize;\n    var chunkStore = this._storage[dim][chunkIndex];\n    return chunkStore[chunkOffset];\n};\n\n/**\n * Get value for multi dimensions.\n * @param {Array.<string>} [dimensions] If ignored, using all dimensions.\n * @param {number} idx\n * @return {number}\n */\nlistProto.getValues = function (dimensions, idx /*, stack */) {\n    var values = [];\n\n    if (!isArray(dimensions)) {\n        // stack = idx;\n        idx = dimensions;\n        dimensions = this.dimensions;\n    }\n\n    for (var i = 0, len = dimensions.length; i < len; i++) {\n        values.push(this.get(dimensions[i], idx /*, stack */));\n    }\n\n    return values;\n};\n\n/**\n * If value is NaN. Inlcuding '-'\n * Only check the coord dimensions.\n * @param {string} dim\n * @param {number} idx\n * @return {number}\n */\nlistProto.hasValue = function (idx) {\n    var dataDimsOnCoord = this._dimensionsSummary.dataDimsOnCoord;\n    var dimensionInfos = this._dimensionInfos;\n    for (var i = 0, len = dataDimsOnCoord.length; i < len; i++) {\n        if (\n            // Ordinal type can be string or number\n            dimensionInfos[dataDimsOnCoord[i]].type !== 'ordinal'\n            // FIXME check ordinal when using index?\n            && isNaN(this.get(dataDimsOnCoord[i], idx))\n        ) {\n            return false;\n        }\n    }\n    return true;\n};\n\n/**\n * Get extent of data in one dimension\n * @param {string} dim\n * @param {boolean} stack\n */\nlistProto.getDataExtent = function (dim /*, stack */) {\n    // Make sure use concrete dim as cache name.\n    dim = this.getDimension(dim);\n    var dimData = this._storage[dim];\n    var initialExtent = getInitialExtent();\n\n    // stack = !!((stack || false) && this.getCalculationInfo(dim));\n\n    if (!dimData) {\n        return initialExtent;\n    }\n\n    // Make more strict checkings to ensure hitting cache.\n    var currEnd = this.count();\n    // var cacheName = [dim, !!stack].join('_');\n    // var cacheName = dim;\n\n    // Consider the most cases when using data zoom, `getDataExtent`\n    // happened before filtering. We cache raw extent, which is not\n    // necessary to be cleared and recalculated when restore data.\n    var useRaw = !this._indices; // && !stack;\n    var dimExtent;\n\n    if (useRaw) {\n        return this._rawExtent[dim].slice();\n    }\n    dimExtent = this._extent[dim];\n    if (dimExtent) {\n        return dimExtent.slice();\n    }\n    dimExtent = initialExtent;\n\n    var min = dimExtent[0];\n    var max = dimExtent[1];\n\n    for (var i = 0; i < currEnd; i++) {\n        // var value = stack ? this.get(dim, i, true) : this._getFast(dim, this.getRawIndex(i));\n        var value = this._getFast(dim, this.getRawIndex(i));\n        value < min && (min = value);\n        value > max && (max = value);\n    }\n\n    dimExtent = [min, max];\n\n    this._extent[dim] = dimExtent;\n\n    return dimExtent;\n};\n\n/**\n * Optimize for the scenario that data is filtered by a given extent.\n * Consider that if data amount is more than hundreds of thousand,\n * extent calculation will cost more than 10ms and the cache will\n * be erased because of the filtering.\n */\nlistProto.getApproximateExtent = function (dim /*, stack */) {\n    dim = this.getDimension(dim);\n    return this._approximateExtent[dim] || this.getDataExtent(dim /*, stack */);\n};\n\nlistProto.setApproximateExtent = function (extent, dim /*, stack */) {\n    dim = this.getDimension(dim);\n    this._approximateExtent[dim] = extent.slice();\n};\n\n/**\n * @param {string} key\n * @return {*}\n */\nlistProto.getCalculationInfo = function (key) {\n    return this._calculationInfo[key];\n};\n\n/**\n * @param {string|Object} key or k-v object\n * @param {*} [value]\n */\nlistProto.setCalculationInfo = function (key, value) {\n    isObject$4(key)\n        ? extend(this._calculationInfo, key)\n        : (this._calculationInfo[key] = value);\n};\n\n/**\n * Get sum of data in one dimension\n * @param {string} dim\n */\nlistProto.getSum = function (dim /*, stack */) {\n    var dimData = this._storage[dim];\n    var sum = 0;\n    if (dimData) {\n        for (var i = 0, len = this.count(); i < len; i++) {\n            var value = this.get(dim, i /*, stack */);\n            if (!isNaN(value)) {\n                sum += value;\n            }\n        }\n    }\n    return sum;\n};\n\n/**\n * Get median of data in one dimension\n * @param {string} dim\n */\nlistProto.getMedian = function (dim /*, stack */) {\n    var dimDataArray = [];\n    // map all data of one dimension\n    this.each(dim, function (val, idx) {\n        if (!isNaN(val)) {\n            dimDataArray.push(val);\n        }\n    });\n\n    // TODO\n    // Use quick select?\n\n    // immutability & sort\n    var sortedDimDataArray = [].concat(dimDataArray).sort(function (a, b) {\n        return a - b;\n    });\n    var len = this.count();\n    // calculate median\n    return len === 0\n        ? 0\n        : len % 2 === 1\n        ? sortedDimDataArray[(len - 1) / 2]\n        : (sortedDimDataArray[len / 2] + sortedDimDataArray[len / 2 - 1]) / 2;\n};\n\n// /**\n//  * Retreive the index with given value\n//  * @param {string} dim Concrete dimension.\n//  * @param {number} value\n//  * @return {number}\n//  */\n// Currently incorrect: should return dataIndex but not rawIndex.\n// Do not fix it until this method is to be used somewhere.\n// FIXME Precision of float value\n// listProto.indexOf = function (dim, value) {\n//     var storage = this._storage;\n//     var dimData = storage[dim];\n//     var chunkSize = this._chunkSize;\n//     if (dimData) {\n//         for (var i = 0, len = this.count(); i < len; i++) {\n//             var chunkIndex = Math.floor(i / chunkSize);\n//             var chunkOffset = i % chunkSize;\n//             if (dimData[chunkIndex][chunkOffset] === value) {\n//                 return i;\n//             }\n//         }\n//     }\n//     return -1;\n// };\n\n/**\n * Only support the dimension which inverted index created.\n * Do not support other cases until required.\n * @param {string} concrete dim\n * @param {number|string} value\n * @return {number} rawIndex\n */\nlistProto.rawIndexOf = function (dim, value) {\n    var invertedIndices = dim && this._invertedIndicesMap[dim];\n    if (__DEV__) {\n        if (!invertedIndices) {\n            throw new Error('Do not supported yet');\n        }\n    }\n    var rawIndex = invertedIndices[value];\n    if (rawIndex == null || isNaN(rawIndex)) {\n        return INDEX_NOT_FOUND;\n    }\n    return rawIndex;\n};\n\n/**\n * Retreive the index with given name\n * @param {number} idx\n * @param {number} name\n * @return {number}\n */\nlistProto.indexOfName = function (name) {\n    for (var i = 0, len = this.count(); i < len; i++) {\n        if (this.getName(i) === name) {\n            return i;\n        }\n    }\n\n    return -1;\n};\n\n/**\n * Retreive the index with given raw data index\n * @param {number} idx\n * @param {number} name\n * @return {number}\n */\nlistProto.indexOfRawIndex = function (rawIndex) {\n    if (!this._indices) {\n        return rawIndex;\n    }\n\n    if (rawIndex >= this._rawCount || rawIndex < 0) {\n        return -1;\n    }\n\n    // Indices are ascending\n    var indices = this._indices;\n\n    // If rawIndex === dataIndex\n    var rawDataIndex = indices[rawIndex];\n    if (rawDataIndex != null && rawDataIndex < this._count && rawDataIndex === rawIndex) {\n        return rawIndex;\n    }\n\n    var left = 0;\n    var right = this._count - 1;\n    while (left <= right) {\n        var mid = (left + right) / 2 | 0;\n        if (indices[mid] < rawIndex) {\n            left = mid + 1;\n        }\n        else if (indices[mid] > rawIndex) {\n            right = mid - 1;\n        }\n        else {\n            return mid;\n        }\n    }\n    return -1;\n};\n\n/**\n * Retreive the index of nearest value\n * @param {string} dim\n * @param {number} value\n * @param {number} [maxDistance=Infinity]\n * @return {Array.<number>} Considere multiple points has the same value.\n */\nlistProto.indicesOfNearest = function (dim, value, maxDistance) {\n    var storage = this._storage;\n    var dimData = storage[dim];\n    var nearestIndices = [];\n\n    if (!dimData) {\n        return nearestIndices;\n    }\n\n    if (maxDistance == null) {\n        maxDistance = Infinity;\n    }\n\n    var minDist = Number.MAX_VALUE;\n    var minDiff = -1;\n    for (var i = 0, len = this.count(); i < len; i++) {\n        var diff = value - this.get(dim, i /*, stack */);\n        var dist = Math.abs(diff);\n        if (diff <= maxDistance && dist <= minDist) {\n            // For the case of two data are same on xAxis, which has sequence data.\n            // Show the nearest index\n            // https://github.com/ecomfe/echarts/issues/2869\n            if (dist < minDist || (diff >= 0 && minDiff < 0)) {\n                minDist = dist;\n                minDiff = diff;\n                nearestIndices.length = 0;\n            }\n            nearestIndices.push(i);\n        }\n    }\n    return nearestIndices;\n};\n\n/**\n * Get raw data index\n * @param {number} idx\n * @return {number}\n */\nlistProto.getRawIndex = getRawIndexWithoutIndices;\n\nfunction getRawIndexWithoutIndices(idx) {\n    return idx;\n}\n\nfunction getRawIndexWithIndices(idx) {\n    if (idx < this._count && idx >= 0) {\n        return this._indices[idx];\n    }\n    return -1;\n}\n\n/**\n * Get raw data item\n * @param {number} idx\n * @return {number}\n */\nlistProto.getRawDataItem = function (idx) {\n    if (!this._rawData.persistent) {\n        var val = [];\n        for (var i = 0; i < this.dimensions.length; i++) {\n            var dim = this.dimensions[i];\n            val.push(this.get(dim, idx));\n        }\n        return val;\n    }\n    else {\n        return this._rawData.getItem(this.getRawIndex(idx));\n    }\n};\n\n/**\n * @param {number} idx\n * @param {boolean} [notDefaultIdx=false]\n * @return {string}\n */\nlistProto.getName = function (idx) {\n    var rawIndex = this.getRawIndex(idx);\n    return this._nameList[rawIndex]\n        || getRawValueFromStore(this, this._nameDimIdx, rawIndex)\n        || '';\n};\n\n/**\n * @param {number} idx\n * @param {boolean} [notDefaultIdx=false]\n * @return {string}\n */\nlistProto.getId = function (idx) {\n    return getId(this, this.getRawIndex(idx));\n};\n\nfunction getId(list, rawIndex) {\n    var id = list._idList[rawIndex];\n    if (id == null) {\n        id = getRawValueFromStore(list, list._idDimIdx, rawIndex);\n    }\n    if (id == null) {\n        // FIXME Check the usage in graph, should not use prefix.\n        id = ID_PREFIX + rawIndex;\n    }\n    return id;\n}\n\nfunction normalizeDimensions(dimensions) {\n    if (!isArray(dimensions)) {\n        dimensions = [dimensions];\n    }\n    return dimensions;\n}\n\nfunction validateDimensions(list, dims) {\n    for (var i = 0; i < dims.length; i++) {\n        // stroage may be empty when no data, so use\n        // dimensionInfos to check.\n        if (!list._dimensionInfos[dims[i]]) {\n            console.error('Unkown dimension ' + dims[i]);\n        }\n    }\n}\n\n/**\n * Data iteration\n * @param {string|Array.<string>}\n * @param {Function} cb\n * @param {*} [context=this]\n *\n * @example\n *  list.each('x', function (x, idx) {});\n *  list.each(['x', 'y'], function (x, y, idx) {});\n *  list.each(function (idx) {})\n */\nlistProto.each = function (dims, cb, context, contextCompat) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    if (typeof dims === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dims;\n        dims = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dims = map(normalizeDimensions(dims), this.getDimension, this);\n\n    if (__DEV__) {\n        validateDimensions(this, dims);\n    }\n\n    var dimSize = dims.length;\n\n    for (var i = 0; i < this.count(); i++) {\n        // Simple optimization\n        switch (dimSize) {\n            case 0:\n                cb.call(context, i);\n                break;\n            case 1:\n                cb.call(context, this.get(dims[0], i), i);\n                break;\n            case 2:\n                cb.call(context, this.get(dims[0], i), this.get(dims[1], i), i);\n                break;\n            default:\n                var k = 0;\n                var value = [];\n                for (; k < dimSize; k++) {\n                    value[k] = this.get(dims[k], i);\n                }\n                // Index\n                value[k] = i;\n                cb.apply(context, value);\n        }\n    }\n};\n\n/**\n * Data filter\n * @param {string|Array.<string>}\n * @param {Function} cb\n * @param {*} [context=this]\n */\nlistProto.filterSelf = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    if (typeof dimensions === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dimensions;\n        dimensions = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dimensions = map(\n        normalizeDimensions(dimensions), this.getDimension, this\n    );\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n\n    var count = this.count();\n    var Ctor = getIndicesCtor(this);\n    var newIndices = new Ctor(count);\n    var value = [];\n    var dimSize = dimensions.length;\n\n    var offset = 0;\n    var dim0 = dimensions[0];\n\n    for (var i = 0; i < count; i++) {\n        var keep;\n        var rawIdx = this.getRawIndex(i);\n        // Simple optimization\n        if (dimSize === 0) {\n            keep = cb.call(context, i);\n        }\n        else if (dimSize === 1) {\n            var val = this._getFast(dim0, rawIdx);\n            keep = cb.call(context, val, i);\n        }\n        else {\n            for (var k = 0; k < dimSize; k++) {\n                value[k] = this._getFast(dim0, rawIdx);\n            }\n            value[k] = i;\n            keep = cb.apply(context, value);\n        }\n        if (keep) {\n            newIndices[offset++] = rawIdx;\n        }\n    }\n\n    // Set indices after filtered.\n    if (offset < count) {\n        this._indices = newIndices;\n    }\n    this._count = offset;\n    // Reset data extent\n    this._extent = {};\n\n    this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return this;\n};\n\n/**\n * Select data in range. (For optimization of filter)\n * (Manually inline code, support 5 million data filtering in data zoom.)\n */\nlistProto.selectRange = function (range) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    var dimensions = [];\n    for (var dim in range) {\n        if (range.hasOwnProperty(dim)) {\n            dimensions.push(dim);\n        }\n    }\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n    var dimSize = dimensions.length;\n    if (!dimSize) {\n        return;\n    }\n\n    var originalCount = this.count();\n    var Ctor = getIndicesCtor(this);\n    var newIndices = new Ctor(originalCount);\n\n    var offset = 0;\n    var dim0 = dimensions[0];\n\n    var min = range[dim0][0];\n    var max = range[dim0][1];\n\n    var quickFinished = false;\n    if (!this._indices) {\n        // Extreme optimization for common case. About 2x faster in chrome.\n        var idx = 0;\n        if (dimSize === 1) {\n            var dimStorage = this._storage[dimensions[0]];\n            for (var k = 0; k < this._chunkCount; k++) {\n                var chunkStorage = dimStorage[k];\n                var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);\n                for (var i = 0; i < len; i++) {\n                    var val = chunkStorage[i];\n                    // NaN will not be filtered. Consider the case, in line chart, empty\n                    // value indicates the line should be broken. But for the case like\n                    // scatter plot, a data item with empty value will not be rendered,\n                    // but the axis extent may be effected if some other dim of the data\n                    // item has value. Fortunately it is not a significant negative effect.\n                    if (\n                        (val >= min && val <= max) || isNaN(val)\n                    ) {\n                        newIndices[offset++] = idx;\n                    }\n                    idx++;\n                }\n            }\n            quickFinished = true;\n        }\n        else if (dimSize === 2) {\n            var dimStorage = this._storage[dim0];\n            var dimStorage2 = this._storage[dimensions[1]];\n            var min2 = range[dimensions[1]][0];\n            var max2 = range[dimensions[1]][1];\n            for (var k = 0; k < this._chunkCount; k++) {\n                var chunkStorage = dimStorage[k];\n                var chunkStorage2 = dimStorage2[k];\n                var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);\n                for (var i = 0; i < len; i++) {\n                    var val = chunkStorage[i];\n                    var val2 = chunkStorage2[i];\n                    // Do not filter NaN, see comment above.\n                    if ((\n                            (val >= min && val <= max) || isNaN(val)\n                        )\n                        && (\n                            (val2 >= min2 && val2 <= max2) || isNaN(val2)\n                        )\n                    ) {\n                        newIndices[offset++] = idx;\n                    }\n                    idx++;\n                }\n            }\n            quickFinished = true;\n        }\n    }\n    if (!quickFinished) {\n        if (dimSize === 1) {\n            for (var i = 0; i < originalCount; i++) {\n                var rawIndex = this.getRawIndex(i);\n                var val = this._getFast(dim0, rawIndex);\n                // Do not filter NaN, see comment above.\n                if (\n                    (val >= min && val <= max) || isNaN(val)\n                ) {\n                    newIndices[offset++] = rawIndex;\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < originalCount; i++) {\n                var keep = true;\n                var rawIndex = this.getRawIndex(i);\n                for (var k = 0; k < dimSize; k++) {\n                    var dimk = dimensions[k];\n                    var val = this._getFast(dim, rawIndex);\n                    // Do not filter NaN, see comment above.\n                    if (val < range[dimk][0] || val > range[dimk][1]) {\n                        keep = false;\n                    }\n                }\n                if (keep) {\n                    newIndices[offset++] = this.getRawIndex(i);\n                }\n            }\n        }\n    }\n\n    // Set indices after filtered.\n    if (offset < originalCount) {\n        this._indices = newIndices;\n    }\n    this._count = offset;\n    // Reset data extent\n    this._extent = {};\n\n    this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return this;\n};\n\n/**\n * Data mapping to a plain array\n * @param {string|Array.<string>} [dimensions]\n * @param {Function} cb\n * @param {*} [context=this]\n * @return {Array}\n */\nlistProto.mapArray = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    if (typeof dimensions === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dimensions;\n        dimensions = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    var result = [];\n    this.each(dimensions, function () {\n        result.push(cb && cb.apply(this, arguments));\n    }, context);\n    return result;\n};\n\n// Data in excludeDimensions is copied, otherwise transfered.\nfunction cloneListForMapAndSample(original, excludeDimensions) {\n    var allDimensions = original.dimensions;\n    var list = new List(\n        map(allDimensions, original.getDimensionInfo, original),\n        original.hostModel\n    );\n    // FIXME If needs stackedOn, value may already been stacked\n    transferProperties(list, original);\n\n    var storage = list._storage = {};\n    var originalStorage = original._storage;\n\n    // Init storage\n    for (var i = 0; i < allDimensions.length; i++) {\n        var dim = allDimensions[i];\n        if (originalStorage[dim]) {\n            // Notice that we do not reset invertedIndicesMap here, becuase\n            // there is no scenario of mapping or sampling ordinal dimension.\n            if (indexOf(excludeDimensions, dim) >= 0) {\n                storage[dim] = cloneDimStore(originalStorage[dim]);\n                list._rawExtent[dim] = getInitialExtent();\n                list._extent[dim] = null;\n            }\n            else {\n                // Direct reference for other dimensions\n                storage[dim] = originalStorage[dim];\n            }\n        }\n    }\n    return list;\n}\n\nfunction cloneDimStore(originalDimStore) {\n    var newDimStore = new Array(originalDimStore.length);\n    for (var j = 0; j < originalDimStore.length; j++) {\n        newDimStore[j] = cloneChunk(originalDimStore[j]);\n    }\n    return newDimStore;\n}\n\nfunction getInitialExtent() {\n    return [Infinity, -Infinity];\n}\n\n/**\n * Data mapping to a new List with given dimensions\n * @param {string|Array.<string>} dimensions\n * @param {Function} cb\n * @param {*} [context=this]\n * @return {Array}\n */\nlistProto.map = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dimensions = map(\n        normalizeDimensions(dimensions), this.getDimension, this\n    );\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n    var list = cloneListForMapAndSample(this, dimensions);\n\n    // Following properties are all immutable.\n    // So we can reference to the same value\n    list._indices = this._indices;\n    list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    var storage = list._storage;\n\n    var tmpRetValue = [];\n    var chunkSize = this._chunkSize;\n    var dimSize = dimensions.length;\n    var dataCount = this.count();\n    var values = [];\n    var rawExtent = list._rawExtent;\n\n    for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) {\n        for (var dimIndex = 0; dimIndex < dimSize; dimIndex++) {\n            values[dimIndex] = this.get(dimensions[dimIndex], dataIndex /*, stack */);\n        }\n        values[dimSize] = dataIndex;\n\n        var retValue = cb && cb.apply(context, values);\n        if (retValue != null) {\n            // a number or string (in oridinal dimension)?\n            if (typeof retValue !== 'object') {\n                tmpRetValue[0] = retValue;\n                retValue = tmpRetValue;\n            }\n\n            var rawIndex = this.getRawIndex(dataIndex);\n            var chunkIndex = Math.floor(rawIndex / chunkSize);\n            var chunkOffset = rawIndex % chunkSize;\n\n            for (var i = 0; i < retValue.length; i++) {\n                var dim = dimensions[i];\n                var val = retValue[i];\n                var rawExtentOnDim = rawExtent[dim];\n\n                var dimStore = storage[dim];\n                if (dimStore) {\n                    dimStore[chunkIndex][chunkOffset] = val;\n                }\n\n                if (val < rawExtentOnDim[0]) {\n                    rawExtentOnDim[0] = val;\n                }\n                if (val > rawExtentOnDim[1]) {\n                    rawExtentOnDim[1] = val;\n                }\n            }\n        }\n    }\n\n    return list;\n};\n\n/**\n * Large data down sampling on given dimension\n * @param {string} dimension\n * @param {number} rate\n * @param {Function} sampleValue\n * @param {Function} sampleIndex Sample index for name and id\n */\nlistProto.downSample = function (dimension, rate, sampleValue, sampleIndex) {\n    var list = cloneListForMapAndSample(this, [dimension]);\n    var targetStorage = list._storage;\n\n    var frameValues = [];\n    var frameSize = Math.floor(1 / rate);\n\n    var dimStore = targetStorage[dimension];\n    var len = this.count();\n    var chunkSize = this._chunkSize;\n    var rawExtentOnDim = list._rawExtent[dimension];\n\n    var newIndices = new (getIndicesCtor(this))(len);\n\n    var offset = 0;\n    for (var i = 0; i < len; i += frameSize) {\n        // Last frame\n        if (frameSize > len - i) {\n            frameSize = len - i;\n            frameValues.length = frameSize;\n        }\n        for (var k = 0; k < frameSize; k++) {\n            var dataIdx = this.getRawIndex(i + k);\n            var originalChunkIndex = Math.floor(dataIdx / chunkSize);\n            var originalChunkOffset = dataIdx % chunkSize;\n            frameValues[k] = dimStore[originalChunkIndex][originalChunkOffset];\n        }\n        var value = sampleValue(frameValues);\n        var sampleFrameIdx = this.getRawIndex(\n            Math.min(i + sampleIndex(frameValues, value) || 0, len - 1)\n        );\n        var sampleChunkIndex = Math.floor(sampleFrameIdx / chunkSize);\n        var sampleChunkOffset = sampleFrameIdx % chunkSize;\n        // Only write value on the filtered data\n        dimStore[sampleChunkIndex][sampleChunkOffset] = value;\n\n        if (value < rawExtentOnDim[0]) {\n            rawExtentOnDim[0] = value;\n        }\n        if (value > rawExtentOnDim[1]) {\n            rawExtentOnDim[1] = value;\n        }\n\n        newIndices[offset++] = sampleFrameIdx;\n    }\n\n    list._count = offset;\n    list._indices = newIndices;\n\n    list.getRawIndex = getRawIndexWithIndices;\n\n    return list;\n};\n\n/**\n * Get model of one data item.\n *\n * @param {number} idx\n */\n// FIXME Model proxy ?\nlistProto.getItemModel = function (idx) {\n    var hostModel = this.hostModel;\n    return new Model(this.getRawDataItem(idx), hostModel, hostModel && hostModel.ecModel);\n};\n\n/**\n * Create a data differ\n * @param {module:echarts/data/List} otherList\n * @return {module:echarts/data/DataDiffer}\n */\nlistProto.diff = function (otherList) {\n    var thisList = this;\n\n    return new DataDiffer(\n        otherList ? otherList.getIndices() : [],\n        this.getIndices(),\n        function (idx) {\n            return getId(otherList, idx);\n        },\n        function (idx) {\n            return getId(thisList, idx);\n        }\n    );\n};\n/**\n * Get visual property.\n * @param {string} key\n */\nlistProto.getVisual = function (key) {\n    var visual = this._visual;\n    return visual && visual[key];\n};\n\n/**\n * Set visual property\n * @param {string|Object} key\n * @param {*} [value]\n *\n * @example\n *  setVisual('color', color);\n *  setVisual({\n *      'color': color\n *  });\n */\nlistProto.setVisual = function (key, val) {\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                this.setVisual(name, key[name]);\n            }\n        }\n        return;\n    }\n    this._visual = this._visual || {};\n    this._visual[key] = val;\n};\n\n/**\n * Set layout property.\n * @param {string|Object} key\n * @param {*} [val]\n */\nlistProto.setLayout = function (key, val) {\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                this.setLayout(name, key[name]);\n            }\n        }\n        return;\n    }\n    this._layout[key] = val;\n};\n\n/**\n * Get layout property.\n * @param  {string} key.\n * @return {*}\n */\nlistProto.getLayout = function (key) {\n    return this._layout[key];\n};\n\n/**\n * Get layout of single data item\n * @param {number} idx\n */\nlistProto.getItemLayout = function (idx) {\n    return this._itemLayouts[idx];\n};\n\n/**\n * Set layout of single data item\n * @param {number} idx\n * @param {Object} layout\n * @param {boolean=} [merge=false]\n */\nlistProto.setItemLayout = function (idx, layout, merge$$1) {\n    this._itemLayouts[idx] = merge$$1\n        ? extend(this._itemLayouts[idx] || {}, layout)\n        : layout;\n};\n\n/**\n * Clear all layout of single data item\n */\nlistProto.clearItemLayouts = function () {\n    this._itemLayouts.length = 0;\n};\n\n/**\n * Get visual property of single data item\n * @param {number} idx\n * @param {string} key\n * @param {boolean} [ignoreParent=false]\n */\nlistProto.getItemVisual = function (idx, key, ignoreParent) {\n    var itemVisual = this._itemVisuals[idx];\n    var val = itemVisual && itemVisual[key];\n    if (val == null && !ignoreParent) {\n        // Use global visual property\n        return this.getVisual(key);\n    }\n    return val;\n};\n\n/**\n * Set visual property of single data item\n *\n * @param {number} idx\n * @param {string|Object} key\n * @param {*} [value]\n *\n * @example\n *  setItemVisual(0, 'color', color);\n *  setItemVisual(0, {\n *      'color': color\n *  });\n */\nlistProto.setItemVisual = function (idx, key, value) {\n    var itemVisual = this._itemVisuals[idx] || {};\n    var hasItemVisual = this.hasItemVisual;\n    this._itemVisuals[idx] = itemVisual;\n\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                itemVisual[name] = key[name];\n                hasItemVisual[name] = true;\n            }\n        }\n        return;\n    }\n    itemVisual[key] = value;\n    hasItemVisual[key] = true;\n};\n\n/**\n * Clear itemVisuals and list visual.\n */\nlistProto.clearAllVisual = function () {\n    this._visual = {};\n    this._itemVisuals = [];\n    this.hasItemVisual = {};\n};\n\nvar setItemDataAndSeriesIndex = function (child) {\n    child.seriesIndex = this.seriesIndex;\n    child.dataIndex = this.dataIndex;\n    child.dataType = this.dataType;\n};\n/**\n * Set graphic element relative to data. It can be set as null\n * @param {number} idx\n * @param {module:zrender/Element} [el]\n */\nlistProto.setItemGraphicEl = function (idx, el) {\n    var hostModel = this.hostModel;\n\n    if (el) {\n        // Add data index and series index for indexing the data by element\n        // Useful in tooltip\n        el.dataIndex = idx;\n        el.dataType = this.dataType;\n        el.seriesIndex = hostModel && hostModel.seriesIndex;\n        if (el.type === 'group') {\n            el.traverse(setItemDataAndSeriesIndex, el);\n        }\n    }\n\n    this._graphicEls[idx] = el;\n};\n\n/**\n * @param {number} idx\n * @return {module:zrender/Element}\n */\nlistProto.getItemGraphicEl = function (idx) {\n    return this._graphicEls[idx];\n};\n\n/**\n * @param {Function} cb\n * @param {*} context\n */\nlistProto.eachItemGraphicEl = function (cb, context) {\n    each$1(this._graphicEls, function (el, idx) {\n        if (el) {\n            cb && cb.call(context, el, idx);\n        }\n    });\n};\n\n/**\n * Shallow clone a new list except visual and layout properties, and graph elements.\n * New list only change the indices.\n */\nlistProto.cloneShallow = function (list) {\n    if (!list) {\n        var dimensionInfoList = map(this.dimensions, this.getDimensionInfo, this);\n        list = new List(dimensionInfoList, this.hostModel);\n    }\n\n    // FIXME\n    list._storage = this._storage;\n\n    transferProperties(list, this);\n\n    // Clone will not change the data extent and indices\n    if (this._indices) {\n        var Ctor = this._indices.constructor;\n        list._indices = new Ctor(this._indices);\n    }\n    else {\n        list._indices = null;\n    }\n    list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return list;\n};\n\n/**\n * Wrap some method to add more feature\n * @param {string} methodName\n * @param {Function} injectFunction\n */\nlistProto.wrapMethod = function (methodName, injectFunction) {\n    var originalMethod = this[methodName];\n    if (typeof originalMethod !== 'function') {\n        return;\n    }\n    this.__wrappedMethods = this.__wrappedMethods || [];\n    this.__wrappedMethods.push(methodName);\n    this[methodName] = function () {\n        var res = originalMethod.apply(this, arguments);\n        return injectFunction.apply(this, [res].concat(slice(arguments)));\n    };\n};\n\n// Methods that create a new list based on this list should be listed here.\n// Notice that those method should `RETURN` the new list.\nlistProto.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'map'];\n// Methods that change indices of this list should be listed here.\nlistProto.CHANGABLE_METHODS = ['filterSelf', 'selectRange'];\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @deprecated\n * Use `echarts/data/helper/createDimensions` instead.\n */\n\n/**\n * @see {module:echarts/test/ut/spec/data/completeDimensions}\n *\n * Complete the dimensions array, by user defined `dimension` and `encode`,\n * and guessing from the data structure.\n * If no 'value' dimension specified, the first no-named dimension will be\n * named as 'value'.\n *\n * @param {Array.<string>} sysDims Necessary dimensions, like ['x', 'y'], which\n *      provides not only dim template, but also default order.\n *      properties: 'name', 'type', 'displayName'.\n *      `name` of each item provides default coord name.\n *      [{dimsDef: [string|Object, ...]}, ...] dimsDef of sysDim item provides default dim name, and\n *                                    provide dims count that the sysDim required.\n *      [{ordinalMeta}] can be specified.\n * @param {module:echarts/data/Source|Array|Object} source or data (for compatibal with pervious)\n * @param {Object} [opt]\n * @param {Array.<Object|string>} [opt.dimsDef] option.series.dimensions User defined dimensions\n *      For example: ['asdf', {name, type}, ...].\n * @param {Object|HashMap} [opt.encodeDef] option.series.encode {x: 2, y: [3, 1], tooltip: [1, 2], label: 3}\n * @param {string} [opt.generateCoord] Generate coord dim with the given name.\n *                 If not specified, extra dim names will be:\n *                 'value', 'value0', 'value1', ...\n * @param {number} [opt.generateCoordCount] By default, the generated dim name is `generateCoord`.\n *                 If `generateCoordCount` specified, the generated dim names will be:\n *                 `generateCoord` + 0, `generateCoord` + 1, ...\n *                 can be Infinity, indicate that use all of the remain columns.\n * @param {number} [opt.dimCount] If not specified, guess by the first data item.\n * @param {number} [opt.encodeDefaulter] If not specified, auto find the next available data dim.\n * @return {Array.<Object>} [{\n *      name: string mandatory,\n *      displayName: string, the origin name in dimsDef, see source helper.\n *                 If displayName given, the tooltip will displayed vertically.\n *      coordDim: string mandatory,\n *      coordDimIndex: number mandatory,\n *      type: string optional,\n *      otherDims: { never null/undefined\n *          tooltip: number optional,\n *          label: number optional,\n *          itemName: number optional,\n *          seriesName: number optional,\n *      },\n *      isExtraCoord: boolean true if coord is generated\n *          (not specified in encode and not series specified)\n *      other props ...\n * }]\n */\nfunction completeDimensions(sysDims, source, opt) {\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n\n    opt = opt || {};\n    sysDims = (sysDims || []).slice();\n    var dimsDef = (opt.dimsDef || []).slice();\n    var encodeDef = createHashMap(opt.encodeDef);\n    var dataDimNameMap = createHashMap();\n    var coordDimNameMap = createHashMap();\n    // var valueCandidate;\n    var result = [];\n\n    var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimCount);\n\n    // Apply user defined dims (`name` and `type`) and init result.\n    for (var i = 0; i < dimCount; i++) {\n        var dimDefItem = dimsDef[i] = extend(\n            {}, isObject$1(dimsDef[i]) ? dimsDef[i] : {name: dimsDef[i]}\n        );\n        var userDimName = dimDefItem.name;\n        var resultItem = result[i] = {otherDims: {}};\n        // Name will be applied later for avoiding duplication.\n        if (userDimName != null && dataDimNameMap.get(userDimName) == null) {\n            // Only if `series.dimensions` is defined in option\n            // displayName, will be set, and dimension will be diplayed vertically in\n            // tooltip by default.\n            resultItem.name = resultItem.displayName = userDimName;\n            dataDimNameMap.set(userDimName, i);\n        }\n        dimDefItem.type != null && (resultItem.type = dimDefItem.type);\n        dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);\n    }\n\n    // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.\n    encodeDef.each(function (dataDims, coordDim) {\n        dataDims = normalizeToArray(dataDims).slice();\n\n        // Note: It is allowed that `dataDims.length` is `0`, e.g., options is\n        // `{encode: {x: -1, y: 1}}`. Should not filter anything in\n        // this case.\n        if (dataDims.length === 1 && dataDims[0] < 0) {\n            encodeDef.set(coordDim, false);\n            return;\n        }\n\n        var validDataDims = encodeDef.set(coordDim, []);\n        each$1(dataDims, function (resultDimIdx, idx) {\n            // The input resultDimIdx can be dim name or index.\n            isString(resultDimIdx) && (resultDimIdx = dataDimNameMap.get(resultDimIdx));\n            if (resultDimIdx != null && resultDimIdx < dimCount) {\n                validDataDims[idx] = resultDimIdx;\n                applyDim(result[resultDimIdx], coordDim, idx);\n            }\n        });\n    });\n\n    // Apply templetes and default order from `sysDims`.\n    var availDimIdx = 0;\n    each$1(sysDims, function (sysDimItem, sysDimIndex) {\n        var coordDim;\n        var sysDimItem;\n        var sysDimItemDimsDef;\n        var sysDimItemOtherDims;\n        if (isString(sysDimItem)) {\n            coordDim = sysDimItem;\n            sysDimItem = {};\n        }\n        else {\n            coordDim = sysDimItem.name;\n            var ordinalMeta = sysDimItem.ordinalMeta;\n            sysDimItem.ordinalMeta = null;\n            sysDimItem = clone(sysDimItem);\n            sysDimItem.ordinalMeta = ordinalMeta;\n            // `coordDimIndex` should not be set directly.\n            sysDimItemDimsDef = sysDimItem.dimsDef;\n            sysDimItemOtherDims = sysDimItem.otherDims;\n            sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex\n                = sysDimItem.dimsDef = sysDimItem.otherDims = null;\n        }\n\n        var dataDims = encodeDef.get(coordDim);\n\n        // negative resultDimIdx means no need to mapping.\n        if (dataDims === false) {\n            return;\n        }\n\n        var dataDims = normalizeToArray(dataDims);\n\n        // dimensions provides default dim sequences.\n        if (!dataDims.length) {\n            for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {\n                while (availDimIdx < result.length && result[availDimIdx].coordDim != null) {\n                    availDimIdx++;\n                }\n                availDimIdx < result.length && dataDims.push(availDimIdx++);\n            }\n        }\n\n        // Apply templates.\n        each$1(dataDims, function (resultDimIdx, coordDimIndex) {\n            var resultItem = result[resultDimIdx];\n            applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);\n            if (resultItem.name == null && sysDimItemDimsDef) {\n                var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];\n                !isObject$1(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {name: sysDimItemDimsDefItem});\n                resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;\n                resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;\n            }\n            // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}\n            sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);\n        });\n    });\n\n    function applyDim(resultItem, coordDim, coordDimIndex) {\n        if (OTHER_DIMENSIONS.get(coordDim) != null) {\n            resultItem.otherDims[coordDim] = coordDimIndex;\n        }\n        else {\n            resultItem.coordDim = coordDim;\n            resultItem.coordDimIndex = coordDimIndex;\n            coordDimNameMap.set(coordDim, true);\n        }\n    }\n\n    // Make sure the first extra dim is 'value'.\n    var generateCoord = opt.generateCoord;\n    var generateCoordCount = opt.generateCoordCount;\n    var fromZero = generateCoordCount != null;\n    generateCoordCount = generateCoord ? (generateCoordCount || 1) : 0;\n    var extra = generateCoord || 'value';\n\n    // Set dim `name` and other `coordDim` and other props.\n    for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {\n        var resultItem = result[resultDimIdx] = result[resultDimIdx] || {};\n        var coordDim = resultItem.coordDim;\n\n        if (coordDim == null) {\n            resultItem.coordDim = genName(\n                extra, coordDimNameMap, fromZero\n            );\n            resultItem.coordDimIndex = 0;\n            if (!generateCoord || generateCoordCount <= 0) {\n                resultItem.isExtraCoord = true;\n            }\n            generateCoordCount--;\n        }\n\n        resultItem.name == null && (resultItem.name = genName(\n            resultItem.coordDim,\n            dataDimNameMap\n        ));\n\n        if (resultItem.type == null && guessOrdinal(source, resultDimIdx, resultItem.name)) {\n            resultItem.type = 'ordinal';\n        }\n    }\n\n    return result;\n}\n\n// ??? TODO\n// Originally detect dimCount by data[0]. Should we\n// optimize it to only by sysDims and dimensions and encode.\n// So only necessary dims will be initialized.\n// But\n// (1) custom series should be considered. where other dims\n// may be visited.\n// (2) sometimes user need to calcualte bubble size or use visualMap\n// on other dimensions besides coordSys needed.\n// So, dims that is not used by system, should be shared in storage?\nfunction getDimCount(source, sysDims, dimsDef, optDimCount) {\n    // Note that the result dimCount should not small than columns count\n    // of data, otherwise `dataDimNameMap` checking will be incorrect.\n    var dimCount = Math.max(\n        source.dimensionsDetectCount || 1,\n        sysDims.length,\n        dimsDef.length,\n        optDimCount || 0\n    );\n    each$1(sysDims, function (sysDimItem) {\n        var sysDimItemDimsDef = sysDimItem.dimsDef;\n        sysDimItemDimsDef && (dimCount = Math.max(dimCount, sysDimItemDimsDef.length));\n    });\n    return dimCount;\n}\n\nfunction genName(name, map$$1, fromZero) {\n    if (fromZero || map$$1.get(name) != null) {\n        var i = 0;\n        while (map$$1.get(name + i) != null) {\n            i++;\n        }\n        name += i;\n    }\n    map$$1.set(name, true);\n    return name;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Substitute `completeDimensions`.\n * `completeDimensions` is to be deprecated.\n */\n/**\n * @param {module:echarts/data/Source|module:echarts/data/List} source or data.\n * @param {Object|Array} [opt]\n * @param {Array.<string|Object>} [opt.coordDimensions=[]]\n * @param {number} [opt.dimensionsCount]\n * @param {string} [opt.generateCoord]\n * @param {string} [opt.generateCoordCount]\n * @param {Array.<string|Object>} [opt.dimensionsDefine=source.dimensionsDefine] Overwrite source define.\n * @param {Object|HashMap} [opt.encodeDefine=source.encodeDefine] Overwrite source define.\n * @return {Array.<Object>} dimensionsInfo\n */\nvar createDimensions = function (source, opt) {\n    opt = opt || {};\n    return completeDimensions(opt.coordDimensions || [], source, {\n        dimsDef: opt.dimensionsDefine || source.dimensionsDefine,\n        encodeDef: opt.encodeDefine || source.encodeDefine,\n        dimCount: opt.dimensionsCount,\n        generateCoord: opt.generateCoord,\n        generateCoordCount: opt.generateCoordCount\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Note that it is too complicated to support 3d stack by value\n * (have to create two-dimension inverted index), so in 3d case\n * we just support that stacked by index.\n *\n * @param {module:echarts/model/Series} seriesModel\n * @param {Array.<string|Object>} dimensionInfoList The same as the input of <module:echarts/data/List>.\n *        The input dimensionInfoList will be modified.\n * @param {Object} [opt]\n * @param {boolean} [opt.stackedCoordDimension=''] Specify a coord dimension if needed.\n * @param {boolean} [opt.byIndex=false]\n * @return {Object} calculationInfo\n * {\n *     stackedDimension: string\n *     stackedByDimension: string\n *     isStackedByIndex: boolean\n *     stackedOverDimension: string\n *     stackResultDimension: string\n * }\n */\nfunction enableDataStack(seriesModel, dimensionInfoList, opt) {\n    opt = opt || {};\n    var byIndex = opt.byIndex;\n    var stackedCoordDimension = opt.stackedCoordDimension;\n\n    // Compatibal: when `stack` is set as '', do not stack.\n    var mayStack = !!(seriesModel && seriesModel.get('stack'));\n    var stackedByDimInfo;\n    var stackedDimInfo;\n    var stackResultDimension;\n    var stackedOverDimension;\n\n    each$1(dimensionInfoList, function (dimensionInfo, index) {\n        if (isString(dimensionInfo)) {\n            dimensionInfoList[index] = dimensionInfo = {name: dimensionInfo};\n        }\n\n        if (mayStack && !dimensionInfo.isExtraCoord) {\n            // Find the first ordinal dimension as the stackedByDimInfo.\n            if (!byIndex && !stackedByDimInfo && dimensionInfo.ordinalMeta) {\n                stackedByDimInfo = dimensionInfo;\n            }\n            // Find the first stackable dimension as the stackedDimInfo.\n            if (!stackedDimInfo\n                && dimensionInfo.type !== 'ordinal'\n                && dimensionInfo.type !== 'time'\n                && (!stackedCoordDimension || stackedCoordDimension === dimensionInfo.coordDim)\n            ) {\n                stackedDimInfo = dimensionInfo;\n            }\n        }\n    });\n\n    if (stackedDimInfo && !byIndex && !stackedByDimInfo) {\n        // Compatible with previous design, value axis (time axis) only stack by index.\n        // It may make sense if the user provides elaborately constructed data.\n        byIndex = true;\n    }\n\n    // Add stack dimension, they can be both calculated by coordinate system in `unionExtent`.\n    // That put stack logic in List is for using conveniently in echarts extensions, but it\n    // might not be a good way.\n    if (stackedDimInfo) {\n        // Use a weird name that not duplicated with other names.\n        stackResultDimension = '__\\0ecstackresult';\n        stackedOverDimension = '__\\0ecstackedover';\n\n        // Create inverted index to fast query index by value.\n        if (stackedByDimInfo) {\n            stackedByDimInfo.createInvertedIndices = true;\n        }\n\n        var stackedDimCoordDim = stackedDimInfo.coordDim;\n        var stackedDimType = stackedDimInfo.type;\n        var stackedDimCoordIndex = 0;\n\n        each$1(dimensionInfoList, function (dimensionInfo) {\n            if (dimensionInfo.coordDim === stackedDimCoordDim) {\n                stackedDimCoordIndex++;\n            }\n        });\n\n        dimensionInfoList.push({\n            name: stackResultDimension,\n            coordDim: stackedDimCoordDim,\n            coordDimIndex: stackedDimCoordIndex,\n            type: stackedDimType,\n            isExtraCoord: true,\n            isCalculationCoord: true\n        });\n\n        stackedDimCoordIndex++;\n\n        dimensionInfoList.push({\n            name: stackedOverDimension,\n            // This dimension contains stack base (generally, 0), so do not set it as\n            // `stackedDimCoordDim` to avoid extent calculation, consider log scale.\n            coordDim: stackedOverDimension,\n            coordDimIndex: stackedDimCoordIndex,\n            type: stackedDimType,\n            isExtraCoord: true,\n            isCalculationCoord: true\n        });\n    }\n\n    return {\n        stackedDimension: stackedDimInfo && stackedDimInfo.name,\n        stackedByDimension: stackedByDimInfo && stackedByDimInfo.name,\n        isStackedByIndex: byIndex,\n        stackedOverDimension: stackedOverDimension,\n        stackResultDimension: stackResultDimension\n    };\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {string} stackedDim\n */\nfunction isDimensionStacked(data, stackedDim /*, stackedByDim*/) {\n    // Each single series only maps to one pair of axis. So we do not need to\n    // check stackByDim, whatever stacked by a dimension or stacked by index.\n    return !!stackedDim && stackedDim === data.getCalculationInfo('stackedDimension');\n        // && (\n        //     stackedByDim != null\n        //         ? stackedByDim === data.getCalculationInfo('stackedByDimension')\n        //         : data.getCalculationInfo('isStackedByIndex')\n        // );\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {string} targetDim\n * @param {string} [stackedByDim] If not input this parameter, check whether\n *                                stacked by index.\n * @return {string} dimension\n */\nfunction getStackedDimension(data, targetDim) {\n    return isDimensionStacked(data, targetDim)\n        ? data.getCalculationInfo('stackResultDimension')\n        : targetDim;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/data/Source|Array} source Or raw data.\n * @param {module:echarts/model/Series} seriesModel\n * @param {Object} [opt]\n * @param {string} [opt.generateCoord]\n */\nfunction createListFromArray(source, seriesModel, opt) {\n    opt = opt || {};\n\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n\n    var coordSysName = seriesModel.get('coordinateSystem');\n    var registeredCoordSys = CoordinateSystemManager.get(coordSysName);\n\n    var coordSysDefine = getCoordSysDefineBySeries(seriesModel);\n\n    var coordSysDimDefs;\n\n    if (coordSysDefine) {\n        coordSysDimDefs = map(coordSysDefine.coordSysDims, function (dim) {\n            var dimInfo = {name: dim};\n            var axisModel = coordSysDefine.axisMap.get(dim);\n            if (axisModel) {\n                var axisType = axisModel.get('type');\n                dimInfo.type = getDimensionTypeByAxis(axisType);\n                // dimInfo.stackable = isStackable(axisType);\n            }\n            return dimInfo;\n        });\n    }\n\n    if (!coordSysDimDefs) {\n        // Get dimensions from registered coordinate system\n        coordSysDimDefs = (registeredCoordSys && (\n            registeredCoordSys.getDimensionsInfo\n                ? registeredCoordSys.getDimensionsInfo()\n                : registeredCoordSys.dimensions.slice()\n        )) || ['x', 'y'];\n    }\n\n    var dimInfoList = createDimensions(source, {\n        coordDimensions: coordSysDimDefs,\n        generateCoord: opt.generateCoord\n    });\n\n    var firstCategoryDimIndex;\n    var hasNameEncode;\n    coordSysDefine && each$1(dimInfoList, function (dimInfo, dimIndex) {\n        var coordDim = dimInfo.coordDim;\n        var categoryAxisModel = coordSysDefine.categoryAxisMap.get(coordDim);\n        if (categoryAxisModel) {\n            if (firstCategoryDimIndex == null) {\n                firstCategoryDimIndex = dimIndex;\n            }\n            dimInfo.ordinalMeta = categoryAxisModel.getOrdinalMeta();\n        }\n        if (dimInfo.otherDims.itemName != null) {\n            hasNameEncode = true;\n        }\n    });\n    if (!hasNameEncode && firstCategoryDimIndex != null) {\n        dimInfoList[firstCategoryDimIndex].otherDims.itemName = 0;\n    }\n\n    var stackCalculationInfo = enableDataStack(seriesModel, dimInfoList);\n\n    var list = new List(dimInfoList, seriesModel);\n\n    list.setCalculationInfo(stackCalculationInfo);\n\n    var dimValueGetter = (firstCategoryDimIndex != null && isNeedCompleteOrdinalData(source))\n        ? function (itemOpt, dimName, dataIndex, dimIndex) {\n            // Use dataIndex as ordinal value in categoryAxis\n            return dimIndex === firstCategoryDimIndex\n                ? dataIndex\n                : this.defaultDimValueGetter(itemOpt, dimName, dataIndex, dimIndex);\n        }\n        : null;\n\n    list.hasItemOption = false;\n    list.initData(source, null, dimValueGetter);\n\n    return list;\n}\n\nfunction isNeedCompleteOrdinalData(source) {\n    if (source.sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        var sampleItem = firstDataNotNull(source.data || []);\n        return sampleItem != null\n            && !isArray(getDataItemValue(sampleItem));\n    }\n}\n\nfunction firstDataNotNull(data) {\n    var i = 0;\n    while (i < data.length && data[i] == null) {\n        i++;\n    }\n    return data[i];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * // Scale class management\n * @module echarts/scale/Scale\n */\n\n/**\n * @param {Object} [setting]\n */\nfunction Scale(setting) {\n    this._setting = setting || {};\n\n    /**\n     * Extent\n     * @type {Array.<number>}\n     * @protected\n     */\n    this._extent = [Infinity, -Infinity];\n\n    /**\n     * Step is calculated in adjustExtent\n     * @type {Array.<number>}\n     * @protected\n     */\n    this._interval = 0;\n\n    this.init && this.init.apply(this, arguments);\n}\n\n/**\n * Parse input val to valid inner number.\n * @param {*} val\n * @return {number}\n */\nScale.prototype.parse = function (val) {\n    // Notice: This would be a trap here, If the implementation\n    // of this method depends on extent, and this method is used\n    // before extent set (like in dataZoom), it would be wrong.\n    // Nevertheless, parse does not depend on extent generally.\n    return val;\n};\n\nScale.prototype.getSetting = function (name) {\n    return this._setting[name];\n};\n\nScale.prototype.contain = function (val) {\n    var extent = this._extent;\n    return val >= extent[0] && val <= extent[1];\n};\n\n/**\n * Normalize value to linear [0, 1], return 0.5 if extent span is 0\n * @param {number} val\n * @return {number}\n */\nScale.prototype.normalize = function (val) {\n    var extent = this._extent;\n    if (extent[1] === extent[0]) {\n        return 0.5;\n    }\n    return (val - extent[0]) / (extent[1] - extent[0]);\n};\n\n/**\n * Scale normalized value\n * @param {number} val\n * @return {number}\n */\nScale.prototype.scale = function (val) {\n    var extent = this._extent;\n    return val * (extent[1] - extent[0]) + extent[0];\n};\n\n/**\n * Set extent from data\n * @param {Array.<number>} other\n */\nScale.prototype.unionExtent = function (other) {\n    var extent = this._extent;\n    other[0] < extent[0] && (extent[0] = other[0]);\n    other[1] > extent[1] && (extent[1] = other[1]);\n    // not setExtent because in log axis it may transformed to power\n    // this.setExtent(extent[0], extent[1]);\n};\n\n/**\n * Set extent from data\n * @param {module:echarts/data/List} data\n * @param {string} dim\n */\nScale.prototype.unionExtentFromData = function (data, dim) {\n    this.unionExtent(data.getApproximateExtent(dim));\n};\n\n/**\n * Get extent\n * @return {Array.<number>}\n */\nScale.prototype.getExtent = function () {\n    return this._extent.slice();\n};\n\n/**\n * Set extent\n * @param {number} start\n * @param {number} end\n */\nScale.prototype.setExtent = function (start, end) {\n    var thisExtent = this._extent;\n    if (!isNaN(start)) {\n        thisExtent[0] = start;\n    }\n    if (!isNaN(end)) {\n        thisExtent[1] = end;\n    }\n};\n\n/**\n * When axis extent depends on data and no data exists,\n * axis ticks should not be drawn, which is named 'blank'.\n */\nScale.prototype.isBlank = function () {\n    return this._isBlank;\n},\n\n/**\n * When axis extent depends on data and no data exists,\n * axis ticks should not be drawn, which is named 'blank'.\n */\nScale.prototype.setBlank = function (isBlank) {\n    this._isBlank = isBlank;\n};\n\n/**\n * @abstract\n * @param {*} tick\n * @return {string} label of the tick.\n */\nScale.prototype.getLabel = null;\n\n\nenableClassExtend(Scale);\nenableClassManagement(Scale, {\n    registerWhenExtend: true\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @constructor\n * @param {Object} [opt]\n * @param {Object} [opt.categories=[]]\n * @param {Object} [opt.needCollect=false]\n * @param {Object} [opt.deduplication=false]\n */\nfunction OrdinalMeta(opt) {\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    this.categories = opt.categories || [];\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._needCollect = opt.needCollect;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._deduplication = opt.deduplication;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._map;\n}\n\n/**\n * @param {module:echarts/model/Model} axisModel\n * @return {module:echarts/data/OrdinalMeta}\n */\nOrdinalMeta.createByAxisModel = function (axisModel) {\n    var option = axisModel.option;\n    var data = option.data;\n    var categories = data && map(data, getName);\n\n    return new OrdinalMeta({\n        categories: categories,\n        needCollect: !categories,\n        // deduplication is default in axis.\n        deduplication: option.dedplication !== false\n    });\n};\n\nvar proto$1 = OrdinalMeta.prototype;\n\n/**\n * @param {string} category\n * @return {number} ordinal\n */\nproto$1.getOrdinal = function (category) {\n    return getOrCreateMap(this).get(category);\n};\n\n/**\n * @param {*} category\n * @return {number} The ordinal. If not found, return NaN.\n */\nproto$1.parseAndCollect = function (category) {\n    var index;\n    var needCollect = this._needCollect;\n\n    // The value of category dim can be the index of the given category set.\n    // This feature is only supported when !needCollect, because we should\n    // consider a common case: a value is 2017, which is a number but is\n    // expected to be tread as a category. This case usually happen in dataset,\n    // where it happent to be no need of the index feature.\n    if (typeof category !== 'string' && !needCollect) {\n        return category;\n    }\n\n    // Optimize for the scenario:\n    // category is ['2012-01-01', '2012-01-02', ...], where the input\n    // data has been ensured not duplicate and is large data.\n    // Notice, if a dataset dimension provide categroies, usually echarts\n    // should remove duplication except user tell echarts dont do that\n    // (set axis.deduplication = false), because echarts do not know whether\n    // the values in the category dimension has duplication (consider the\n    // parallel-aqi example)\n    if (needCollect && !this._deduplication) {\n        index = this.categories.length;\n        this.categories[index] = category;\n        return index;\n    }\n\n    var map$$1 = getOrCreateMap(this);\n    index = map$$1.get(category);\n\n    if (index == null) {\n        if (needCollect) {\n            index = this.categories.length;\n            this.categories[index] = category;\n            map$$1.set(category, index);\n        }\n        else {\n            index = NaN;\n        }\n    }\n\n    return index;\n};\n\n// Consider big data, do not create map until needed.\nfunction getOrCreateMap(ordinalMeta) {\n    return ordinalMeta._map || (\n        ordinalMeta._map = createHashMap(ordinalMeta.categories)\n    );\n}\n\nfunction getName(obj) {\n    if (isObject$1(obj) && obj.value != null) {\n        return obj.value;\n    }\n    else {\n        return obj + '';\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Linear continuous scale\n * @module echarts/coord/scale/Ordinal\n *\n * http://en.wikipedia.org/wiki/Level_of_measurement\n */\n\n// FIXME only one data\n\nvar scaleProto = Scale.prototype;\n\nvar OrdinalScale = Scale.extend({\n\n    type: 'ordinal',\n\n    /**\n     * @param {module:echarts/data/OrdianlMeta|Array.<string>} ordinalMeta\n     */\n    init: function (ordinalMeta, extent) {\n        // Caution: Should not use instanceof, consider ec-extensions using\n        // import approach to get OrdinalMeta class.\n        if (!ordinalMeta || isArray(ordinalMeta)) {\n            ordinalMeta = new OrdinalMeta({categories: ordinalMeta});\n        }\n        this._ordinalMeta = ordinalMeta;\n        this._extent = extent || [0, ordinalMeta.categories.length - 1];\n    },\n\n    parse: function (val) {\n        return typeof val === 'string'\n            ? this._ordinalMeta.getOrdinal(val)\n            // val might be float.\n            : Math.round(val);\n    },\n\n    contain: function (rank) {\n        rank = this.parse(rank);\n        return scaleProto.contain.call(this, rank)\n            && this._ordinalMeta.categories[rank] != null;\n    },\n\n    /**\n     * Normalize given rank or name to linear [0, 1]\n     * @param {number|string} [val]\n     * @return {number}\n     */\n    normalize: function (val) {\n        return scaleProto.normalize.call(this, this.parse(val));\n    },\n\n    scale: function (val) {\n        return Math.round(scaleProto.scale.call(this, val));\n    },\n\n    /**\n     * @return {Array}\n     */\n    getTicks: function () {\n        var ticks = [];\n        var extent = this._extent;\n        var rank = extent[0];\n\n        while (rank <= extent[1]) {\n            ticks.push(rank);\n            rank++;\n        }\n\n        return ticks;\n    },\n\n    /**\n     * Get item on rank n\n     * @param {number} n\n     * @return {string}\n     */\n    getLabel: function (n) {\n        if (!this.isBlank()) {\n            // Note that if no data, ordinalMeta.categories is an empty array.\n            return this._ordinalMeta.categories[n];\n        }\n    },\n\n    /**\n     * @return {number}\n     */\n    count: function () {\n        return this._extent[1] - this._extent[0] + 1;\n    },\n\n    /**\n     * @override\n     */\n    unionExtentFromData: function (data, dim) {\n        this.unionExtent(data.getApproximateExtent(dim));\n    },\n\n    getOrdinalMeta: function () {\n        return this._ordinalMeta;\n    },\n\n    niceTicks: noop,\n    niceExtent: noop\n});\n\n/**\n * @return {module:echarts/scale/Time}\n */\nOrdinalScale.create = function () {\n    return new OrdinalScale();\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * For testable.\n */\n\nvar roundNumber$1 = round$2;\n\n/**\n * @param {Array.<number>} extent Both extent[0] and extent[1] should be valid number.\n *                                Should be extent[0] < extent[1].\n * @param {number} splitNumber splitNumber should be >= 1.\n * @param {number} [minInterval]\n * @param {number} [maxInterval]\n * @return {Object} {interval, intervalPrecision, niceTickExtent}\n */\nfunction intervalScaleNiceTicks(extent, splitNumber, minInterval, maxInterval) {\n    var result = {};\n    var span = extent[1] - extent[0];\n\n    var interval = result.interval = nice(span / splitNumber, true);\n    if (minInterval != null && interval < minInterval) {\n        interval = result.interval = minInterval;\n    }\n    if (maxInterval != null && interval > maxInterval) {\n        interval = result.interval = maxInterval;\n    }\n    // Tow more digital for tick.\n    var precision = result.intervalPrecision = getIntervalPrecision(interval);\n    // Niced extent inside original extent\n    var niceTickExtent = result.niceTickExtent = [\n        roundNumber$1(Math.ceil(extent[0] / interval) * interval, precision),\n        roundNumber$1(Math.floor(extent[1] / interval) * interval, precision)\n    ];\n\n    fixExtent(niceTickExtent, extent);\n\n    return result;\n}\n\n/**\n * @param {number} interval\n * @return {number} interval precision\n */\nfunction getIntervalPrecision(interval) {\n    // Tow more digital for tick.\n    return getPrecisionSafe(interval) + 2;\n}\n\nfunction clamp(niceTickExtent, idx, extent) {\n    niceTickExtent[idx] = Math.max(Math.min(niceTickExtent[idx], extent[1]), extent[0]);\n}\n\n// In some cases (e.g., splitNumber is 1), niceTickExtent may be out of extent.\nfunction fixExtent(niceTickExtent, extent) {\n    !isFinite(niceTickExtent[0]) && (niceTickExtent[0] = extent[0]);\n    !isFinite(niceTickExtent[1]) && (niceTickExtent[1] = extent[1]);\n    clamp(niceTickExtent, 0, extent);\n    clamp(niceTickExtent, 1, extent);\n    if (niceTickExtent[0] > niceTickExtent[1]) {\n        niceTickExtent[0] = niceTickExtent[1];\n    }\n}\n\nfunction intervalScaleGetTicks(interval, extent, niceTickExtent, intervalPrecision) {\n    var ticks = [];\n\n    // If interval is 0, return [];\n    if (!interval) {\n        return ticks;\n    }\n\n    // Consider this case: using dataZoom toolbox, zoom and zoom.\n    var safeLimit = 10000;\n\n    if (extent[0] < niceTickExtent[0]) {\n        ticks.push(extent[0]);\n    }\n    var tick = niceTickExtent[0];\n\n    while (tick <= niceTickExtent[1]) {\n        ticks.push(tick);\n        // Avoid rounding error\n        tick = roundNumber$1(tick + interval, intervalPrecision);\n        if (tick === ticks[ticks.length - 1]) {\n            // Consider out of safe float point, e.g.,\n            // -3711126.9907707 + 2e-10 === -3711126.9907707\n            break;\n        }\n        if (ticks.length > safeLimit) {\n            return [];\n        }\n    }\n    // Consider this case: the last item of ticks is smaller\n    // than niceTickExtent[1] and niceTickExtent[1] === extent[1].\n    if (extent[1] > (ticks.length ? ticks[ticks.length - 1] : niceTickExtent[1])) {\n        ticks.push(extent[1]);\n    }\n\n    return ticks;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Interval scale\n * @module echarts/scale/Interval\n */\n\n\nvar roundNumber = round$2;\n\n/**\n * @alias module:echarts/coord/scale/Interval\n * @constructor\n */\nvar IntervalScale = Scale.extend({\n\n    type: 'interval',\n\n    _interval: 0,\n\n    _intervalPrecision: 2,\n\n    setExtent: function (start, end) {\n        var thisExtent = this._extent;\n        //start,end may be a Number like '25',so...\n        if (!isNaN(start)) {\n            thisExtent[0] = parseFloat(start);\n        }\n        if (!isNaN(end)) {\n            thisExtent[1] = parseFloat(end);\n        }\n    },\n\n    unionExtent: function (other) {\n        var extent = this._extent;\n        other[0] < extent[0] && (extent[0] = other[0]);\n        other[1] > extent[1] && (extent[1] = other[1]);\n\n        // unionExtent may called by it's sub classes\n        IntervalScale.prototype.setExtent.call(this, extent[0], extent[1]);\n    },\n    /**\n     * Get interval\n     */\n    getInterval: function () {\n        return this._interval;\n    },\n\n    /**\n     * Set interval\n     */\n    setInterval: function (interval) {\n        this._interval = interval;\n        // Dropped auto calculated niceExtent and use user setted extent\n        // We assume user wan't to set both interval, min, max to get a better result\n        this._niceExtent = this._extent.slice();\n\n        this._intervalPrecision = getIntervalPrecision(interval);\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getTicks: function () {\n        return intervalScaleGetTicks(\n            this._interval, this._extent, this._niceExtent, this._intervalPrecision\n        );\n    },\n\n    /**\n     * @param {number} data\n     * @param {Object} [opt]\n     * @param {number|string} [opt.precision] If 'auto', use nice presision.\n     * @param {boolean} [opt.pad] returns 1.50 but not 1.5 if precision is 2.\n     * @return {string}\n     */\n    getLabel: function (data, opt) {\n        if (data == null) {\n            return '';\n        }\n\n        var precision = opt && opt.precision;\n\n        if (precision == null) {\n            precision = getPrecisionSafe(data) || 0;\n        }\n        else if (precision === 'auto') {\n            // Should be more precise then tick.\n            precision = this._intervalPrecision;\n        }\n\n        // (1) If `precision` is set, 12.005 should be display as '12.00500'.\n        // (2) Use roundNumber (toFixed) to avoid scientific notation like '3.5e-7'.\n        data = roundNumber(data, precision, true);\n\n        return addCommas(data);\n    },\n\n    /**\n     * Update interval and extent of intervals for nice ticks\n     *\n     * @param {number} [splitNumber = 5] Desired number of ticks\n     * @param {number} [minInterval]\n     * @param {number} [maxInterval]\n     */\n    niceTicks: function (splitNumber, minInterval, maxInterval) {\n        splitNumber = splitNumber || 5;\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        if (!isFinite(span)) {\n            return;\n        }\n        // User may set axis min 0 and data are all negative\n        // FIXME If it needs to reverse ?\n        if (span < 0) {\n            span = -span;\n            extent.reverse();\n        }\n\n        var result = intervalScaleNiceTicks(\n            extent, splitNumber, minInterval, maxInterval\n        );\n\n        this._intervalPrecision = result.intervalPrecision;\n        this._interval = result.interval;\n        this._niceExtent = result.niceTickExtent;\n    },\n\n    /**\n     * Nice extent.\n     * @param {Object} opt\n     * @param {number} [opt.splitNumber = 5] Given approx tick number\n     * @param {boolean} [opt.fixMin=false]\n     * @param {boolean} [opt.fixMax=false]\n     * @param {boolean} [opt.minInterval]\n     * @param {boolean} [opt.maxInterval]\n     */\n    niceExtent: function (opt) {\n        var extent = this._extent;\n        // If extent start and end are same, expand them\n        if (extent[0] === extent[1]) {\n            if (extent[0] !== 0) {\n                // Expand extent\n                var expandSize = extent[0];\n                // In the fowllowing case\n                //      Axis has been fixed max 100\n                //      Plus data are all 100 and axis extent are [100, 100].\n                // Extend to the both side will cause expanded max is larger than fixed max.\n                // So only expand to the smaller side.\n                if (!opt.fixMax) {\n                    extent[1] += expandSize / 2;\n                    extent[0] -= expandSize / 2;\n                }\n                else {\n                    extent[0] -= expandSize / 2;\n                }\n            }\n            else {\n                extent[1] = 1;\n            }\n        }\n        var span = extent[1] - extent[0];\n        // If there are no data and extent are [Infinity, -Infinity]\n        if (!isFinite(span)) {\n            extent[0] = 0;\n            extent[1] = 1;\n        }\n\n        this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);\n\n        // var extent = this._extent;\n        var interval = this._interval;\n\n        if (!opt.fixMin) {\n            extent[0] = roundNumber(Math.floor(extent[0] / interval) * interval);\n        }\n        if (!opt.fixMax) {\n            extent[1] = roundNumber(Math.ceil(extent[1] / interval) * interval);\n        }\n    }\n});\n\n/**\n * @return {module:echarts/scale/Time}\n */\nIntervalScale.create = function () {\n    return new IntervalScale();\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar STACK_PREFIX = '__ec_stack_';\nvar LARGE_BAR_MIN_WIDTH = 0.5;\n\nvar LargeArr = typeof Float32Array !== 'undefined' ? Float32Array : Array;\n\nfunction getSeriesStackId(seriesModel) {\n    return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex;\n}\n\nfunction getAxisKey(axis) {\n    return axis.dim + axis.index;\n}\n\n/**\n * @param {Object} opt\n * @param {module:echarts/coord/Axis} opt.axis Only support category axis currently.\n * @param {number} opt.count Positive interger.\n * @param {number} [opt.barWidth]\n * @param {number} [opt.barMaxWidth]\n * @param {number} [opt.barGap]\n * @param {number} [opt.barCategoryGap]\n * @return {Object} {width, offset, offsetCenter} If axis.type is not 'category', return undefined.\n */\n\n\nfunction prepareLayoutBarSeries(seriesType, ecModel) {\n    var seriesModels = [];\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        // Check series coordinate, do layout for cartesian2d only\n        if (isOnCartesian(seriesModel) && !isInLargeMode(seriesModel)) {\n            seriesModels.push(seriesModel);\n        }\n    });\n    return seriesModels;\n}\n\nfunction makeColumnLayout(barSeries) {\n    var seriesInfoList = [];\n    each$1(barSeries, function (seriesModel) {\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var axisExtent = baseAxis.getExtent();\n        var bandWidth = baseAxis.type === 'category'\n            ? baseAxis.getBandWidth()\n            : (Math.abs(axisExtent[1] - axisExtent[0]) / data.count());\n\n        var barWidth = parsePercent$1(\n            seriesModel.get('barWidth'), bandWidth\n        );\n        var barMaxWidth = parsePercent$1(\n            seriesModel.get('barMaxWidth'), bandWidth\n        );\n        var barGap = seriesModel.get('barGap');\n        var barCategoryGap = seriesModel.get('barCategoryGap');\n\n        seriesInfoList.push({\n            bandWidth: bandWidth,\n            barWidth: barWidth,\n            barMaxWidth: barMaxWidth,\n            barGap: barGap,\n            barCategoryGap: barCategoryGap,\n            axisKey: getAxisKey(baseAxis),\n            stackId: getSeriesStackId(seriesModel)\n        });\n    });\n\n    return doCalBarWidthAndOffset(seriesInfoList);\n}\n\nfunction doCalBarWidthAndOffset(seriesInfoList) {\n    // Columns info on each category axis. Key is cartesian name\n    var columnsMap = {};\n\n    each$1(seriesInfoList, function (seriesInfo, idx) {\n        var axisKey = seriesInfo.axisKey;\n        var bandWidth = seriesInfo.bandWidth;\n        var columnsOnAxis = columnsMap[axisKey] || {\n            bandWidth: bandWidth,\n            remainedWidth: bandWidth,\n            autoWidthCount: 0,\n            categoryGap: '20%',\n            gap: '30%',\n            stacks: {}\n        };\n        var stacks = columnsOnAxis.stacks;\n        columnsMap[axisKey] = columnsOnAxis;\n\n        var stackId = seriesInfo.stackId;\n\n        if (!stacks[stackId]) {\n            columnsOnAxis.autoWidthCount++;\n        }\n        stacks[stackId] = stacks[stackId] || {\n            width: 0,\n            maxWidth: 0\n        };\n\n        // Caution: In a single coordinate system, these barGrid attributes\n        // will be shared by series. Consider that they have default values,\n        // only the attributes set on the last series will work.\n        // Do not change this fact unless there will be a break change.\n\n        // TODO\n        var barWidth = seriesInfo.barWidth;\n        if (barWidth && !stacks[stackId].width) {\n            // See #6312, do not restrict width.\n            stacks[stackId].width = barWidth;\n            barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);\n            columnsOnAxis.remainedWidth -= barWidth;\n        }\n\n        var barMaxWidth = seriesInfo.barMaxWidth;\n        barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);\n        var barGap = seriesInfo.barGap;\n        (barGap != null) && (columnsOnAxis.gap = barGap);\n        var barCategoryGap = seriesInfo.barCategoryGap;\n        (barCategoryGap != null) && (columnsOnAxis.categoryGap = barCategoryGap);\n    });\n\n    var result = {};\n\n    each$1(columnsMap, function (columnsOnAxis, coordSysName) {\n\n        result[coordSysName] = {};\n\n        var stacks = columnsOnAxis.stacks;\n        var bandWidth = columnsOnAxis.bandWidth;\n        var categoryGap = parsePercent$1(columnsOnAxis.categoryGap, bandWidth);\n        var barGapPercent = parsePercent$1(columnsOnAxis.gap, 1);\n\n        var remainedWidth = columnsOnAxis.remainedWidth;\n        var autoWidthCount = columnsOnAxis.autoWidthCount;\n        var autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        // Find if any auto calculated bar exceeded maxBarWidth\n        each$1(stacks, function (column, stack) {\n            var maxWidth = column.maxWidth;\n            if (maxWidth && maxWidth < autoWidth) {\n                maxWidth = Math.min(maxWidth, remainedWidth);\n                if (column.width) {\n                    maxWidth = Math.min(maxWidth, column.width);\n                }\n                remainedWidth -= maxWidth;\n                column.width = maxWidth;\n                autoWidthCount--;\n            }\n        });\n\n        // Recalculate width again\n        autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        var widthSum = 0;\n        var lastColumn;\n        each$1(stacks, function (column, idx) {\n            if (!column.width) {\n                column.width = autoWidth;\n            }\n            lastColumn = column;\n            widthSum += column.width * (1 + barGapPercent);\n        });\n        if (lastColumn) {\n            widthSum -= lastColumn.width * barGapPercent;\n        }\n\n        var offset = -widthSum / 2;\n        each$1(stacks, function (column, stackId) {\n            result[coordSysName][stackId] = result[coordSysName][stackId] || {\n                offset: offset,\n                width: column.width\n            };\n\n            offset += column.width * (1 + barGapPercent);\n        });\n    });\n\n    return result;\n}\n\n/**\n * @param {Object} barWidthAndOffset The result of makeColumnLayout\n * @param {module:echarts/coord/Axis} axis\n * @param {module:echarts/model/Series} [seriesModel] If not provided, return all.\n * @return {Object} {stackId: {offset, width}} or {offset, width} if seriesModel provided.\n */\nfunction retrieveColumnLayout(barWidthAndOffset, axis, seriesModel) {\n    if (barWidthAndOffset && axis) {\n        var result = barWidthAndOffset[getAxisKey(axis)];\n        if (result != null && seriesModel != null) {\n            result = result[getSeriesStackId(seriesModel)];\n        }\n        return result;\n    }\n}\n\n/**\n * @param {string} seriesType\n * @param {module:echarts/model/Global} ecModel\n */\nfunction layout(seriesType, ecModel) {\n\n    var seriesModels = prepareLayoutBarSeries(seriesType, ecModel);\n    var barWidthAndOffset = makeColumnLayout(seriesModels);\n\n    var lastStackCoords = {};\n    each$1(seriesModels, function (seriesModel) {\n\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n\n        var stackId = getSeriesStackId(seriesModel);\n        var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId];\n        var columnOffset = columnLayoutInfo.offset;\n        var columnWidth = columnLayoutInfo.width;\n        var valueAxis = cartesian.getOtherAxis(baseAxis);\n\n        var barMinHeight = seriesModel.get('barMinHeight') || 0;\n\n        lastStackCoords[stackId] = lastStackCoords[stackId] || [];\n        data.setLayout({\n            offset: columnOffset,\n            size: columnWidth\n        });\n\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var stacked = isDimensionStacked(data, valueDim /*, baseDim*/);\n        var isValueAxisH = valueAxis.isHorizontal();\n\n        var valueAxisStart = getValueAxisStart(baseAxis, valueAxis, stacked);\n\n        for (var idx = 0, len = data.count(); idx < len; idx++) {\n            var value = data.get(valueDim, idx);\n            var baseValue = data.get(baseDim, idx);\n\n            if (isNaN(value)) {\n                continue;\n            }\n\n            var sign = value >= 0 ? 'p' : 'n';\n            var baseCoord = valueAxisStart;\n\n            // Because of the barMinHeight, we can not use the value in\n            // stackResultDimension directly.\n            if (stacked) {\n                // Only ordinal axis can be stacked.\n                if (!lastStackCoords[stackId][baseValue]) {\n                    lastStackCoords[stackId][baseValue] = {\n                        p: valueAxisStart, // Positive stack\n                        n: valueAxisStart  // Negative stack\n                    };\n                }\n                // Should also consider #4243\n                baseCoord = lastStackCoords[stackId][baseValue][sign];\n            }\n\n            var x;\n            var y;\n            var width;\n            var height;\n\n            if (isValueAxisH) {\n                var coord = cartesian.dataToPoint([value, baseValue]);\n                x = baseCoord;\n                y = coord[1] + columnOffset;\n                width = coord[0] - valueAxisStart;\n                height = columnWidth;\n\n                if (Math.abs(width) < barMinHeight) {\n                    width = (width < 0 ? -1 : 1) * barMinHeight;\n                }\n                stacked && (lastStackCoords[stackId][baseValue][sign] += width);\n            }\n            else {\n                var coord = cartesian.dataToPoint([baseValue, value]);\n                x = coord[0] + columnOffset;\n                y = baseCoord;\n                width = columnWidth;\n                height = coord[1] - valueAxisStart;\n\n                if (Math.abs(height) < barMinHeight) {\n                    // Include zero to has a positive bar\n                    height = (height <= 0 ? -1 : 1) * barMinHeight;\n                }\n                stacked && (lastStackCoords[stackId][baseValue][sign] += height);\n            }\n\n            data.setItemLayout(idx, {\n                x: x,\n                y: y,\n                width: width,\n                height: height\n            });\n        }\n\n    }, this);\n}\n\n// TODO: Do not support stack in large mode yet.\nvar largeLayout = {\n\n    seriesType: 'bar',\n\n    plan: createRenderPlanner(),\n\n    reset: function (seriesModel) {\n        if (!isOnCartesian(seriesModel) || !isInLargeMode(seriesModel)) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var valueAxis = cartesian.getOtherAxis(baseAxis);\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var valueAxisHorizontal = valueAxis.isHorizontal();\n        var valueDimIdx = valueAxisHorizontal ? 0 : 1;\n\n        var barWidth = retrieveColumnLayout(\n            makeColumnLayout([seriesModel]), baseAxis, seriesModel\n        ).width;\n        if (!(barWidth > LARGE_BAR_MIN_WIDTH)) { // jshint ignore:line\n            barWidth = LARGE_BAR_MIN_WIDTH;\n        }\n\n        return {progress: progress};\n\n        function progress(params, data) {\n            var largePoints = new LargeArr(params.count * 2);\n            var dataIndex;\n            var coord = [];\n            var valuePair = [];\n            var offset = 0;\n\n            while ((dataIndex = params.next()) != null) {\n                valuePair[valueDimIdx] = data.get(valueDim, dataIndex);\n                valuePair[1 - valueDimIdx] = data.get(baseDim, dataIndex);\n\n                coord = cartesian.dataToPoint(valuePair, null, coord);\n                largePoints[offset++] = coord[0];\n                largePoints[offset++] = coord[1];\n            }\n\n            data.setLayout({\n                largePoints: largePoints,\n                barWidth: barWidth,\n                valueAxisStart: getValueAxisStart(baseAxis, valueAxis, false),\n                valueAxisHorizontal: valueAxisHorizontal\n            });\n        }\n    }\n};\n\nfunction isOnCartesian(seriesModel) {\n    return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d';\n}\n\nfunction isInLargeMode(seriesModel) {\n    return seriesModel.pipelineContext && seriesModel.pipelineContext.large;\n}\n\n// See cases in `test/bar-start.html` and `#7412`, `#8747`.\nfunction getValueAxisStart(baseAxis, valueAxis, stacked) {\n    var extent = valueAxis.getGlobalExtent();\n    var min;\n    var max;\n    if (extent[0] > extent[1]) {\n        min = extent[1];\n        max = extent[0];\n    }\n    else {\n        min = extent[0];\n        max = extent[1];\n    }\n\n    var valueStart = valueAxis.toGlobalCoord(valueAxis.dataToCoord(0));\n    valueStart < min && (valueStart = min);\n    valueStart > max && (valueStart = max);\n\n    return valueStart;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The \"scaleLevels\" was originally copied from \"d3.js\" with some\n* modifications made for this project.\n* (See more details in the comment on the definition of \"scaleLevels\" below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\n\n// [About UTC and local time zone]:\n// In most cases, `number.parseDate` will treat input data string as local time\n// (except time zone is specified in time string). And `format.formateTime` returns\n// local time by default. option.useUTC is false by default. This design have\n// concidered these common case:\n// (1) Time that is persistent in server is in UTC, but it is needed to be diplayed\n// in local time by default.\n// (2) By default, the input data string (e.g., '2011-01-02') should be displayed\n// as its original time, without any time difference.\n\nvar intervalScaleProto = IntervalScale.prototype;\n\nvar mathCeil = Math.ceil;\nvar mathFloor = Math.floor;\nvar ONE_SECOND = 1000;\nvar ONE_MINUTE = ONE_SECOND * 60;\nvar ONE_HOUR = ONE_MINUTE * 60;\nvar ONE_DAY = ONE_HOUR * 24;\n\n// FIXME 公用？\nvar bisect = function (a, x, lo, hi) {\n    while (lo < hi) {\n        var mid = lo + hi >>> 1;\n        if (a[mid][1] < x) {\n            lo = mid + 1;\n        }\n        else {\n            hi = mid;\n        }\n    }\n    return lo;\n};\n\n/**\n * @alias module:echarts/coord/scale/Time\n * @constructor\n */\nvar TimeScale = IntervalScale.extend({\n    type: 'time',\n\n    /**\n     * @override\n     */\n    getLabel: function (val) {\n        var stepLvl = this._stepLvl;\n\n        var date = new Date(val);\n\n        return formatTime(stepLvl[0], date, this.getSetting('useUTC'));\n    },\n\n    /**\n     * @override\n     */\n    niceExtent: function (opt) {\n        var extent = this._extent;\n        // If extent start and end are same, expand them\n        if (extent[0] === extent[1]) {\n            // Expand extent\n            extent[0] -= ONE_DAY;\n            extent[1] += ONE_DAY;\n        }\n        // If there are no data and extent are [Infinity, -Infinity]\n        if (extent[1] === -Infinity && extent[0] === Infinity) {\n            var d = new Date();\n            extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate());\n            extent[0] = extent[1] - ONE_DAY;\n        }\n\n        this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);\n\n        // var extent = this._extent;\n        var interval = this._interval;\n\n        if (!opt.fixMin) {\n            extent[0] = round$2(mathFloor(extent[0] / interval) * interval);\n        }\n        if (!opt.fixMax) {\n            extent[1] = round$2(mathCeil(extent[1] / interval) * interval);\n        }\n    },\n\n    /**\n     * @override\n     */\n    niceTicks: function (approxTickNum, minInterval, maxInterval) {\n        approxTickNum = approxTickNum || 10;\n\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        var approxInterval = span / approxTickNum;\n\n        if (minInterval != null && approxInterval < minInterval) {\n            approxInterval = minInterval;\n        }\n        if (maxInterval != null && approxInterval > maxInterval) {\n            approxInterval = maxInterval;\n        }\n\n        var scaleLevelsLen = scaleLevels.length;\n        var idx = bisect(scaleLevels, approxInterval, 0, scaleLevelsLen);\n\n        var level = scaleLevels[Math.min(idx, scaleLevelsLen - 1)];\n        var interval = level[1];\n        // Same with interval scale if span is much larger than 1 year\n        if (level[0] === 'year') {\n            var yearSpan = span / interval;\n\n            // From \"Nice Numbers for Graph Labels\" of Graphic Gems\n            // var niceYearSpan = numberUtil.nice(yearSpan, false);\n            var yearStep = nice(yearSpan / approxTickNum, true);\n\n            interval *= yearStep;\n        }\n\n        var timezoneOffset = this.getSetting('useUTC')\n            ? 0 : (new Date(+extent[0] || +extent[1])).getTimezoneOffset() * 60 * 1000;\n        var niceExtent = [\n            Math.round(mathCeil((extent[0] - timezoneOffset) / interval) * interval + timezoneOffset),\n            Math.round(mathFloor((extent[1] - timezoneOffset) / interval) * interval + timezoneOffset)\n        ];\n\n        fixExtent(niceExtent, extent);\n\n        this._stepLvl = level;\n        // Interval will be used in getTicks\n        this._interval = interval;\n        this._niceExtent = niceExtent;\n    },\n\n    parse: function (val) {\n        // val might be float.\n        return +parseDate(val);\n    }\n});\n\neach$1(['contain', 'normalize'], function (methodName) {\n    TimeScale.prototype[methodName] = function (val) {\n        return intervalScaleProto[methodName].call(this, this.parse(val));\n    };\n});\n\n/**\n * This implementation was originally copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/b516d77fb8566b576088e73410437494717ada26/src/time/scale.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n */\nvar scaleLevels = [\n    // Format              interval\n    ['hh:mm:ss', ONE_SECOND],          // 1s\n    ['hh:mm:ss', ONE_SECOND * 5],      // 5s\n    ['hh:mm:ss', ONE_SECOND * 10],     // 10s\n    ['hh:mm:ss', ONE_SECOND * 15],     // 15s\n    ['hh:mm:ss', ONE_SECOND * 30],     // 30s\n    ['hh:mm\\nMM-dd', ONE_MINUTE],      // 1m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 5],  // 5m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 10], // 10m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 15], // 15m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 30], // 30m\n    ['hh:mm\\nMM-dd', ONE_HOUR],        // 1h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 2],    // 2h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 6],    // 6h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 12],   // 12h\n    ['MM-dd\\nyyyy', ONE_DAY],          // 1d\n    ['MM-dd\\nyyyy', ONE_DAY * 2],      // 2d\n    ['MM-dd\\nyyyy', ONE_DAY * 3],      // 3d\n    ['MM-dd\\nyyyy', ONE_DAY * 4],      // 4d\n    ['MM-dd\\nyyyy', ONE_DAY * 5],      // 5d\n    ['MM-dd\\nyyyy', ONE_DAY * 6],      // 6d\n    ['week', ONE_DAY * 7],             // 7d\n    ['MM-dd\\nyyyy', ONE_DAY * 10],     // 10d\n    ['week', ONE_DAY * 14],            // 2w\n    ['week', ONE_DAY * 21],            // 3w\n    ['month', ONE_DAY * 31],           // 1M\n    ['week', ONE_DAY * 42],            // 6w\n    ['month', ONE_DAY * 62],           // 2M\n    ['week', ONE_DAY * 70],            // 10w\n    ['quarter', ONE_DAY * 95],         // 3M\n    ['month', ONE_DAY * 31 * 4],       // 4M\n    ['month', ONE_DAY * 31 * 5],       // 5M\n    ['half-year', ONE_DAY * 380 / 2],  // 6M\n    ['month', ONE_DAY * 31 * 8],       // 8M\n    ['month', ONE_DAY * 31 * 10],      // 10M\n    ['year', ONE_DAY * 380]            // 1Y\n];\n\n/**\n * @param {module:echarts/model/Model}\n * @return {module:echarts/scale/Time}\n */\nTimeScale.create = function (model) {\n    return new TimeScale({useUTC: model.ecModel.get('useUTC')});\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Log scale\n * @module echarts/scale/Log\n */\n\n// Use some method of IntervalScale\nvar scaleProto$1 = Scale.prototype;\nvar intervalScaleProto$1 = IntervalScale.prototype;\n\nvar getPrecisionSafe$1 = getPrecisionSafe;\nvar roundingErrorFix = round$2;\n\nvar mathFloor$1 = Math.floor;\nvar mathCeil$1 = Math.ceil;\nvar mathPow$1 = Math.pow;\n\nvar mathLog = Math.log;\n\nvar LogScale = Scale.extend({\n\n    type: 'log',\n\n    base: 10,\n\n    $constructor: function () {\n        Scale.apply(this, arguments);\n        this._originalScale = new IntervalScale();\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getTicks: function () {\n        var originalScale = this._originalScale;\n        var extent = this._extent;\n        var originalExtent = originalScale.getExtent();\n\n        return map(intervalScaleProto$1.getTicks.call(this), function (val) {\n            var powVal = round$2(mathPow$1(this.base, val));\n\n            // Fix #4158\n            powVal = (val === extent[0] && originalScale.__fixMin)\n                ? fixRoundingError(powVal, originalExtent[0])\n                : powVal;\n            powVal = (val === extent[1] && originalScale.__fixMax)\n                ? fixRoundingError(powVal, originalExtent[1])\n                : powVal;\n\n            return powVal;\n        }, this);\n    },\n\n    /**\n     * @param {number} val\n     * @return {string}\n     */\n    getLabel: intervalScaleProto$1.getLabel,\n\n    /**\n     * @param  {number} val\n     * @return {number}\n     */\n    scale: function (val) {\n        val = scaleProto$1.scale.call(this, val);\n        return mathPow$1(this.base, val);\n    },\n\n    /**\n     * @param {number} start\n     * @param {number} end\n     */\n    setExtent: function (start, end) {\n        var base = this.base;\n        start = mathLog(start) / mathLog(base);\n        end = mathLog(end) / mathLog(base);\n        intervalScaleProto$1.setExtent.call(this, start, end);\n    },\n\n    /**\n     * @return {number} end\n     */\n    getExtent: function () {\n        var base = this.base;\n        var extent = scaleProto$1.getExtent.call(this);\n        extent[0] = mathPow$1(base, extent[0]);\n        extent[1] = mathPow$1(base, extent[1]);\n\n        // Fix #4158\n        var originalScale = this._originalScale;\n        var originalExtent = originalScale.getExtent();\n        originalScale.__fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0]));\n        originalScale.__fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1]));\n\n        return extent;\n    },\n\n    /**\n     * @param  {Array.<number>} extent\n     */\n    unionExtent: function (extent) {\n        this._originalScale.unionExtent(extent);\n\n        var base = this.base;\n        extent[0] = mathLog(extent[0]) / mathLog(base);\n        extent[1] = mathLog(extent[1]) / mathLog(base);\n        scaleProto$1.unionExtent.call(this, extent);\n    },\n\n    /**\n     * @override\n     */\n    unionExtentFromData: function (data, dim) {\n        // TODO\n        // filter value that <= 0\n        this.unionExtent(data.getApproximateExtent(dim));\n    },\n\n    /**\n     * Update interval and extent of intervals for nice ticks\n     * @param  {number} [approxTickNum = 10] Given approx tick number\n     */\n    niceTicks: function (approxTickNum) {\n        approxTickNum = approxTickNum || 10;\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        if (span === Infinity || span <= 0) {\n            return;\n        }\n\n        var interval = quantity(span);\n        var err = approxTickNum / span * interval;\n\n        // Filter ticks to get closer to the desired count.\n        if (err <= 0.5) {\n            interval *= 10;\n        }\n\n        // Interval should be integer\n        while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) {\n            interval *= 10;\n        }\n\n        var niceExtent = [\n            round$2(mathCeil$1(extent[0] / interval) * interval),\n            round$2(mathFloor$1(extent[1] / interval) * interval)\n        ];\n\n        this._interval = interval;\n        this._niceExtent = niceExtent;\n    },\n\n    /**\n     * Nice extent.\n     * @override\n     */\n    niceExtent: function (opt) {\n        intervalScaleProto$1.niceExtent.call(this, opt);\n\n        var originalScale = this._originalScale;\n        originalScale.__fixMin = opt.fixMin;\n        originalScale.__fixMax = opt.fixMax;\n    }\n\n});\n\neach$1(['contain', 'normalize'], function (methodName) {\n    LogScale.prototype[methodName] = function (val) {\n        val = mathLog(val) / mathLog(this.base);\n        return scaleProto$1[methodName].call(this, val);\n    };\n});\n\nLogScale.create = function () {\n    return new LogScale();\n};\n\nfunction fixRoundingError(val, originalVal) {\n    return roundingErrorFix(val, getPrecisionSafe$1(originalVal));\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Get axis scale extent before niced.\n * Item of returned array can only be number (including Infinity and NaN).\n */\nfunction getScaleExtent(scale, model) {\n    var scaleType = scale.type;\n\n    var min = model.getMin();\n    var max = model.getMax();\n    var fixMin = min != null;\n    var fixMax = max != null;\n    var originalExtent = scale.getExtent();\n\n    var axisDataLen;\n    var boundaryGap;\n    var span;\n    if (scaleType === 'ordinal') {\n        axisDataLen = model.getCategories().length;\n    }\n    else {\n        boundaryGap = model.get('boundaryGap');\n        if (!isArray(boundaryGap)) {\n            boundaryGap = [boundaryGap || 0, boundaryGap || 0];\n        }\n        if (typeof boundaryGap[0] === 'boolean') {\n            if (__DEV__) {\n                console.warn('Boolean type for boundaryGap is only '\n                    + 'allowed for ordinal axis. Please use string in '\n                    + 'percentage instead, e.g., \"20%\". Currently, '\n                    + 'boundaryGap is set to be 0.');\n            }\n            boundaryGap = [0, 0];\n        }\n        boundaryGap[0] = parsePercent$1(boundaryGap[0], 1);\n        boundaryGap[1] = parsePercent$1(boundaryGap[1], 1);\n        span = (originalExtent[1] - originalExtent[0])\n            || Math.abs(originalExtent[0]);\n    }\n\n    // Notice: When min/max is not set (that is, when there are null/undefined,\n    // which is the most common case), these cases should be ensured:\n    // (1) For 'ordinal', show all axis.data.\n    // (2) For others:\n    //      + `boundaryGap` is applied (if min/max set, boundaryGap is\n    //      disabled).\n    //      + If `needCrossZero`, min/max should be zero, otherwise, min/max should\n    //      be the result that originalExtent enlarged by boundaryGap.\n    // (3) If no data, it should be ensured that `scale.setBlank` is set.\n\n    // FIXME\n    // (1) When min/max is 'dataMin' or 'dataMax', should boundaryGap be able to used?\n    // (2) When `needCrossZero` and all data is positive/negative, should it be ensured\n    // that the results processed by boundaryGap are positive/negative?\n\n    if (min == null) {\n        min = scaleType === 'ordinal'\n            ? (axisDataLen ? 0 : NaN)\n            : originalExtent[0] - boundaryGap[0] * span;\n    }\n    if (max == null) {\n        max = scaleType === 'ordinal'\n            ? (axisDataLen ? axisDataLen - 1 : NaN)\n            : originalExtent[1] + boundaryGap[1] * span;\n    }\n\n    if (min === 'dataMin') {\n        min = originalExtent[0];\n    }\n    else if (typeof min === 'function') {\n        min = min({\n            min: originalExtent[0],\n            max: originalExtent[1]\n        });\n    }\n\n    if (max === 'dataMax') {\n        max = originalExtent[1];\n    }\n    else if (typeof max === 'function') {\n        max = max({\n            min: originalExtent[0],\n            max: originalExtent[1]\n        });\n    }\n\n    (min == null || !isFinite(min)) && (min = NaN);\n    (max == null || !isFinite(max)) && (max = NaN);\n\n    scale.setBlank(\n        eqNaN(min)\n        || eqNaN(max)\n        || (scaleType === 'ordinal' && !scale.getOrdinalMeta().categories.length)\n    );\n\n    // Evaluate if axis needs cross zero\n    if (model.getNeedCrossZero()) {\n        // Axis is over zero and min is not set\n        if (min > 0 && max > 0 && !fixMin) {\n            min = 0;\n        }\n        // Axis is under zero and max is not set\n        if (min < 0 && max < 0 && !fixMax) {\n            max = 0;\n        }\n    }\n\n    // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis\n    // is base axis\n    // FIXME\n    // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly.\n    // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent?\n    //     Should not depend on series type `bar`?\n    // (3) Fix that might overlap when using dataZoom.\n    // (4) Consider other chart types using `barGrid`?\n    // See #6728, #4862, `test/bar-overflow-time-plot.html`\n    var ecModel = model.ecModel;\n    if (ecModel && (scaleType === 'time' /*|| scaleType === 'interval' */)) {\n        var barSeriesModels = prepareLayoutBarSeries('bar', ecModel);\n        var isBaseAxisAndHasBarSeries;\n\n        each$1(barSeriesModels, function (seriesModel) {\n            isBaseAxisAndHasBarSeries |= seriesModel.getBaseAxis() === model.axis;\n        });\n\n        if (isBaseAxisAndHasBarSeries) {\n            // Calculate placement of bars on axis\n            var barWidthAndOffset = makeColumnLayout(barSeriesModels);\n\n            // Adjust axis min and max to account for overflow\n            var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset);\n            min = adjustedScale.min;\n            max = adjustedScale.max;\n        }\n    }\n\n    return [min, max];\n}\n\nfunction adjustScaleForOverflow(min, max, model, barWidthAndOffset) {\n\n    // Get Axis Length\n    var axisExtent = model.axis.getExtent();\n    var axisLength = axisExtent[1] - axisExtent[0];\n\n    // Get bars on current base axis and calculate min and max overflow\n    var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis);\n    if (barsOnCurrentAxis === undefined) {\n        return {min: min, max: max};\n    }\n\n    var minOverflow = Infinity;\n    each$1(barsOnCurrentAxis, function (item) {\n        minOverflow = Math.min(item.offset, minOverflow);\n    });\n    var maxOverflow = -Infinity;\n    each$1(barsOnCurrentAxis, function (item) {\n        maxOverflow = Math.max(item.offset + item.width, maxOverflow);\n    });\n    minOverflow = Math.abs(minOverflow);\n    maxOverflow = Math.abs(maxOverflow);\n    var totalOverFlow = minOverflow + maxOverflow;\n\n    // Calulate required buffer based on old range and overflow\n    var oldRange = max - min;\n    var oldRangePercentOfNew = (1 - (minOverflow + maxOverflow) / axisLength);\n    var overflowBuffer = ((oldRange / oldRangePercentOfNew) - oldRange);\n\n    max += overflowBuffer * (maxOverflow / totalOverFlow);\n    min -= overflowBuffer * (minOverflow / totalOverFlow);\n\n    return {min: min, max: max};\n}\n\nfunction niceScaleExtent(scale, model) {\n    var extent = getScaleExtent(scale, model);\n    var fixMin = model.getMin() != null;\n    var fixMax = model.getMax() != null;\n    var splitNumber = model.get('splitNumber');\n\n    if (scale.type === 'log') {\n        scale.base = model.get('logBase');\n    }\n\n    var scaleType = scale.type;\n    scale.setExtent(extent[0], extent[1]);\n    scale.niceExtent({\n        splitNumber: splitNumber,\n        fixMin: fixMin,\n        fixMax: fixMax,\n        minInterval: (scaleType === 'interval' || scaleType === 'time')\n            ? model.get('minInterval') : null,\n        maxInterval: (scaleType === 'interval' || scaleType === 'time')\n            ? model.get('maxInterval') : null\n    });\n\n    // If some one specified the min, max. And the default calculated interval\n    // is not good enough. He can specify the interval. It is often appeared\n    // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard\n    // to be 60.\n    // FIXME\n    var interval = model.get('interval');\n    if (interval != null) {\n        scale.setInterval && scale.setInterval(interval);\n    }\n}\n\n/**\n * @param {module:echarts/model/Model} model\n * @param {string} [axisType] Default retrieve from model.type\n * @return {module:echarts/scale/*}\n */\nfunction createScaleByModel(model, axisType) {\n    axisType = axisType || model.get('type');\n    if (axisType) {\n        switch (axisType) {\n            // Buildin scale\n            case 'category':\n                return new OrdinalScale(\n                    model.getOrdinalMeta\n                        ? model.getOrdinalMeta()\n                        : model.getCategories(),\n                    [Infinity, -Infinity]\n                );\n            case 'value':\n                return new IntervalScale();\n            // Extended scale, like time and log\n            default:\n                return (Scale.getClass(axisType) || IntervalScale).create(model);\n        }\n    }\n}\n\n/**\n * Check if the axis corss 0\n */\nfunction ifAxisCrossZero(axis) {\n    var dataExtent = axis.scale.getExtent();\n    var min = dataExtent[0];\n    var max = dataExtent[1];\n    return !((min > 0 && max > 0) || (min < 0 && max < 0));\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @return {Function} Label formatter function.\n *         param: {number} tickValue,\n *         param: {number} idx, the index in all ticks.\n *                         If category axis, this param is not requied.\n *         return: {string} label string.\n */\nfunction makeLabelFormatter(axis) {\n    var labelFormatter = axis.getLabelModel().get('formatter');\n    var categoryTickStart = axis.type === 'category' ? axis.scale.getExtent()[0] : null;\n\n    if (typeof labelFormatter === 'string') {\n        labelFormatter = (function (tpl) {\n            return function (val) {\n                // For category axis, get raw value; for numeric axis,\n                // get foramtted label like '1,333,444'.\n                val = axis.scale.getLabel(val);\n                return tpl.replace('{value}', val != null ? val : '');\n            };\n        })(labelFormatter);\n        // Consider empty array\n        return labelFormatter;\n    }\n    else if (typeof labelFormatter === 'function') {\n        return function (tickValue, idx) {\n            // The original intention of `idx` is \"the index of the tick in all ticks\".\n            // But the previous implementation of category axis do not consider the\n            // `axisLabel.interval`, which cause that, for example, the `interval` is\n            // `1`, then the ticks \"name5\", \"name7\", \"name9\" are displayed, where the\n            // corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep\n            // the definition here for back compatibility.\n            if (categoryTickStart != null) {\n                idx = tickValue - categoryTickStart;\n            }\n            return labelFormatter(getAxisRawValue(axis, tickValue), idx);\n        };\n    }\n    else {\n        return function (tick) {\n            return axis.scale.getLabel(tick);\n        };\n    }\n}\n\nfunction getAxisRawValue(axis, value) {\n    // In category axis with data zoom, tick is not the original\n    // index of axis.data. So tick should not be exposed to user\n    // in category axis.\n    return axis.type === 'category' ? axis.scale.getLabel(value) : value;\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @return {module:zrender/core/BoundingRect} Be null/undefined if no labels.\n */\nfunction estimateLabelUnionRect(axis) {\n    var axisModel = axis.model;\n    var scale = axis.scale;\n\n    if (!axisModel.get('axisLabel.show') || scale.isBlank()) {\n        return;\n    }\n\n    var isCategory = axis.type === 'category';\n\n    var realNumberScaleTicks;\n    var tickCount;\n    var categoryScaleExtent = scale.getExtent();\n\n    // Optimize for large category data, avoid call `getTicks()`.\n    if (isCategory) {\n        tickCount = scale.count();\n    }\n    else {\n        realNumberScaleTicks = scale.getTicks();\n        tickCount = realNumberScaleTicks.length;\n    }\n\n    var axisLabelModel = axis.getLabelModel();\n    var labelFormatter = makeLabelFormatter(axis);\n\n    var rect;\n    var step = 1;\n    // Simple optimization for large amount of labels\n    if (tickCount > 40) {\n        step = Math.ceil(tickCount / 40);\n    }\n    for (var i = 0; i < tickCount; i += step) {\n        var tickValue = realNumberScaleTicks ? realNumberScaleTicks[i] : categoryScaleExtent[0] + i;\n        var label = labelFormatter(tickValue);\n        var unrotatedSingleRect = axisLabelModel.getTextRect(label);\n        var singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0);\n\n        rect ? rect.union(singleRect) : (rect = singleRect);\n    }\n\n    return rect;\n}\n\nfunction rotateTextRect(textRect, rotate) {\n    var rotateRadians = rotate * Math.PI / 180;\n    var boundingBox = textRect.plain();\n    var beforeWidth = boundingBox.width;\n    var beforeHeight = boundingBox.height;\n    var afterWidth = beforeWidth * Math.cos(rotateRadians) + beforeHeight * Math.sin(rotateRadians);\n    var afterHeight = beforeWidth * Math.sin(rotateRadians) + beforeHeight * Math.cos(rotateRadians);\n    var rotatedRect = new BoundingRect(boundingBox.x, boundingBox.y, afterWidth, afterHeight);\n\n    return rotatedRect;\n}\n\n/**\n * @param {module:echarts/src/model/Model} model axisLabelModel or axisTickModel\n * @return {number|String} Can be null|'auto'|number|function\n */\nfunction getOptionCategoryInterval(model) {\n    var interval = model.get('interval');\n    return interval == null ? 'auto' : interval;\n}\n\n/**\n * Set `categoryInterval` as 0 implicitly indicates that\n * show all labels reguardless of overlap.\n * @param {Object} axis axisModel.axis\n * @return {boolean}\n */\nfunction shouldShowAllLabels(axis) {\n    return axis.type === 'category'\n        && getOptionCategoryInterval(axis.getLabelModel()) === 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import * as axisHelper from './axisHelper';\n\nvar axisModelCommonMixin = {\n\n    /**\n     * @param {boolean} origin\n     * @return {number|string} min value or 'dataMin' or null/undefined (means auto) or NaN\n     */\n    getMin: function (origin) {\n        var option = this.option;\n        var min = (!origin && option.rangeStart != null)\n            ? option.rangeStart : option.min;\n\n        if (this.axis\n            && min != null\n            && min !== 'dataMin'\n            && typeof min !== 'function'\n            && !eqNaN(min)\n        ) {\n            min = this.axis.scale.parse(min);\n        }\n        return min;\n    },\n\n    /**\n     * @param {boolean} origin\n     * @return {number|string} max value or 'dataMax' or null/undefined (means auto) or NaN\n     */\n    getMax: function (origin) {\n        var option = this.option;\n        var max = (!origin && option.rangeEnd != null)\n            ? option.rangeEnd : option.max;\n\n        if (this.axis\n            && max != null\n            && max !== 'dataMax'\n            && typeof max !== 'function'\n            && !eqNaN(max)\n        ) {\n            max = this.axis.scale.parse(max);\n        }\n        return max;\n    },\n\n    /**\n     * @return {boolean}\n     */\n    getNeedCrossZero: function () {\n        var option = this.option;\n        return (option.rangeStart != null || option.rangeEnd != null)\n            ? false : !option.scale;\n    },\n\n    /**\n     * Should be implemented by each axis model if necessary.\n     * @return {module:echarts/model/Component} coordinate system model\n     */\n    getCoordSysModel: noop,\n\n    /**\n     * @param {number} rangeStart Can only be finite number or null/undefined or NaN.\n     * @param {number} rangeEnd Can only be finite number or null/undefined or NaN.\n     */\n    setRange: function (rangeStart, rangeEnd) {\n        this.option.rangeStart = rangeStart;\n        this.option.rangeEnd = rangeEnd;\n    },\n\n    /**\n     * Reset range\n     */\n    resetRange: function () {\n        // rangeStart and rangeEnd is readonly.\n        this.option.rangeStart = this.option.rangeEnd = null;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Symbol factory\n\n/**\n * Triangle shape\n * @inner\n */\nvar Triangle = extendShape({\n    type: 'triangle',\n    shape: {\n        cx: 0,\n        cy: 0,\n        width: 0,\n        height: 0\n    },\n    buildPath: function (path, shape) {\n        var cx = shape.cx;\n        var cy = shape.cy;\n        var width = shape.width / 2;\n        var height = shape.height / 2;\n        path.moveTo(cx, cy - height);\n        path.lineTo(cx + width, cy + height);\n        path.lineTo(cx - width, cy + height);\n        path.closePath();\n    }\n});\n\n/**\n * Diamond shape\n * @inner\n */\nvar Diamond = extendShape({\n    type: 'diamond',\n    shape: {\n        cx: 0,\n        cy: 0,\n        width: 0,\n        height: 0\n    },\n    buildPath: function (path, shape) {\n        var cx = shape.cx;\n        var cy = shape.cy;\n        var width = shape.width / 2;\n        var height = shape.height / 2;\n        path.moveTo(cx, cy - height);\n        path.lineTo(cx + width, cy);\n        path.lineTo(cx, cy + height);\n        path.lineTo(cx - width, cy);\n        path.closePath();\n    }\n});\n\n/**\n * Pin shape\n * @inner\n */\nvar Pin = extendShape({\n    type: 'pin',\n    shape: {\n        // x, y on the cusp\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (path, shape) {\n        var x = shape.x;\n        var y = shape.y;\n        var w = shape.width / 5 * 3;\n        // Height must be larger than width\n        var h = Math.max(w, shape.height);\n        var r = w / 2;\n\n        // Dist on y with tangent point and circle center\n        var dy = r * r / (h - r);\n        var cy = y - h + r + dy;\n        var angle = Math.asin(dy / r);\n        // Dist on x with tangent point and circle center\n        var dx = Math.cos(angle) * r;\n\n        var tanX = Math.sin(angle);\n        var tanY = Math.cos(angle);\n\n        var cpLen = r * 0.6;\n        var cpLen2 = r * 0.7;\n\n        path.moveTo(x - dx, cy + dy);\n\n        path.arc(\n            x, cy, r,\n            Math.PI - angle,\n            Math.PI * 2 + angle\n        );\n        path.bezierCurveTo(\n            x + dx - tanX * cpLen, cy + dy + tanY * cpLen,\n            x, y - cpLen2,\n            x, y\n        );\n        path.bezierCurveTo(\n            x, y - cpLen2,\n            x - dx + tanX * cpLen, cy + dy + tanY * cpLen,\n            x - dx, cy + dy\n        );\n        path.closePath();\n    }\n});\n\n/**\n * Arrow shape\n * @inner\n */\nvar Arrow = extendShape({\n\n    type: 'arrow',\n\n    shape: {\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var height = shape.height;\n        var width = shape.width;\n        var x = shape.x;\n        var y = shape.y;\n        var dx = width / 3 * 2;\n        ctx.moveTo(x, y);\n        ctx.lineTo(x + dx, y + height);\n        ctx.lineTo(x, y + height / 4 * 3);\n        ctx.lineTo(x - dx, y + height);\n        ctx.lineTo(x, y);\n        ctx.closePath();\n    }\n});\n\n/**\n * Map of path contructors\n * @type {Object.<string, module:zrender/graphic/Path>}\n */\nvar symbolCtors = {\n\n    line: Line,\n\n    rect: Rect,\n\n    roundRect: Rect,\n\n    square: Rect,\n\n    circle: Circle,\n\n    diamond: Diamond,\n\n    pin: Pin,\n\n    arrow: Arrow,\n\n    triangle: Triangle\n};\n\nvar symbolShapeMakers = {\n\n    line: function (x, y, w, h, shape) {\n        // FIXME\n        shape.x1 = x;\n        shape.y1 = y + h / 2;\n        shape.x2 = x + w;\n        shape.y2 = y + h / 2;\n    },\n\n    rect: function (x, y, w, h, shape) {\n        shape.x = x;\n        shape.y = y;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    roundRect: function (x, y, w, h, shape) {\n        shape.x = x;\n        shape.y = y;\n        shape.width = w;\n        shape.height = h;\n        shape.r = Math.min(w, h) / 4;\n    },\n\n    square: function (x, y, w, h, shape) {\n        var size = Math.min(w, h);\n        shape.x = x;\n        shape.y = y;\n        shape.width = size;\n        shape.height = size;\n    },\n\n    circle: function (x, y, w, h, shape) {\n        // Put circle in the center of square\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.r = Math.min(w, h) / 2;\n    },\n\n    diamond: function (x, y, w, h, shape) {\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    pin: function (x, y, w, h, shape) {\n        shape.x = x + w / 2;\n        shape.y = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    arrow: function (x, y, w, h, shape) {\n        shape.x = x + w / 2;\n        shape.y = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    triangle: function (x, y, w, h, shape) {\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    }\n};\n\nvar symbolBuildProxies = {};\neach$1(symbolCtors, function (Ctor, name) {\n    symbolBuildProxies[name] = new Ctor();\n});\n\nvar SymbolClz = extendShape({\n\n    type: 'symbol',\n\n    shape: {\n        symbolType: '',\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    beforeBrush: function () {\n        var style = this.style;\n        var shape = this.shape;\n        // FIXME\n        if (shape.symbolType === 'pin' && style.textPosition === 'inside') {\n            style.textPosition = ['50%', '40%'];\n            style.textAlign = 'center';\n            style.textVerticalAlign = 'middle';\n        }\n    },\n\n    buildPath: function (ctx, shape, inBundle) {\n        var symbolType = shape.symbolType;\n        var proxySymbol = symbolBuildProxies[symbolType];\n        if (shape.symbolType !== 'none') {\n            if (!proxySymbol) {\n                // Default rect\n                symbolType = 'rect';\n                proxySymbol = symbolBuildProxies[symbolType];\n            }\n            symbolShapeMakers[symbolType](\n                shape.x, shape.y, shape.width, shape.height, proxySymbol.shape\n            );\n            proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle);\n        }\n    }\n});\n\n// Provide setColor helper method to avoid determine if set the fill or stroke outside\nfunction symbolPathSetColor(color, innerColor) {\n    if (this.type !== 'image') {\n        var symbolStyle = this.style;\n        var symbolShape = this.shape;\n        if (symbolShape && symbolShape.symbolType === 'line') {\n            symbolStyle.stroke = color;\n        }\n        else if (this.__isEmptyBrush) {\n            symbolStyle.stroke = color;\n            symbolStyle.fill = innerColor || '#fff';\n        }\n        else {\n            // FIXME 判断图形默认是填充还是描边，使用 onlyStroke ?\n            symbolStyle.fill && (symbolStyle.fill = color);\n            symbolStyle.stroke && (symbolStyle.stroke = color);\n        }\n        this.dirty(false);\n    }\n}\n\n/**\n * Create a symbol element with given symbol configuration: shape, x, y, width, height, color\n * @param {string} symbolType\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n * @param {string} color\n * @param {boolean} [keepAspect=false] whether to keep the ratio of w/h,\n *                            for path and image only.\n */\nfunction createSymbol(symbolType, x, y, w, h, color, keepAspect) {\n    // TODO Support image object, DynamicImage.\n\n    var isEmpty = symbolType.indexOf('empty') === 0;\n    if (isEmpty) {\n        symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6);\n    }\n    var symbolPath;\n\n    if (symbolType.indexOf('image://') === 0) {\n        symbolPath = makeImage(\n            symbolType.slice(8),\n            new BoundingRect(x, y, w, h),\n            keepAspect ? 'center' : 'cover'\n        );\n    }\n    else if (symbolType.indexOf('path://') === 0) {\n        symbolPath = makePath(\n            symbolType.slice(7),\n            {},\n            new BoundingRect(x, y, w, h),\n            keepAspect ? 'center' : 'cover'\n        );\n    }\n    else {\n        symbolPath = new SymbolClz({\n            shape: {\n                symbolType: symbolType,\n                x: x,\n                y: y,\n                width: w,\n                height: h\n            }\n        });\n    }\n\n    symbolPath.__isEmptyBrush = isEmpty;\n\n    symbolPath.setColor = symbolPathSetColor;\n\n    symbolPath.setColor(color);\n\n    return symbolPath;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import createGraphFromNodeEdge from './chart/helper/createGraphFromNodeEdge';\n/**\n * Create a muti dimension List structure from seriesModel.\n * @param  {module:echarts/model/Model} seriesModel\n * @return {module:echarts/data/List} list\n */\nfunction createList(seriesModel) {\n    return createListFromArray(seriesModel.getSource(), seriesModel);\n}\n\nvar dataStack$1 = {\n    isDimensionStacked: isDimensionStacked,\n    enableDataStack: enableDataStack,\n    getStackedDimension: getStackedDimension\n};\n\n/**\n * Create scale\n * @param {Array.<number>} dataExtent\n * @param {Object|module:echarts/Model} option\n */\nfunction createScale(dataExtent, option) {\n    var axisModel = option;\n    if (!Model.isInstance(option)) {\n        axisModel = new Model(option);\n        mixin(axisModel, axisModelCommonMixin);\n    }\n\n    var scale = createScaleByModel(axisModel);\n    scale.setExtent(dataExtent[0], dataExtent[1]);\n\n    niceScaleExtent(scale, axisModel);\n    return scale;\n}\n\n/**\n * Mixin common methods to axis model,\n *\n * Inlcude methods\n * `getFormattedLabels() => Array.<string>`\n * `getCategories() => Array.<string>`\n * `getMin(origin: boolean) => number`\n * `getMax(origin: boolean) => number`\n * `getNeedCrossZero() => boolean`\n * `setRange(start: number, end: number)`\n * `resetRange()`\n */\nfunction mixinAxisModelCommonMethods(Model$$1) {\n    mixin(Model$$1, axisModelCommonMixin);\n}\n\nvar helper = (Object.freeze || Object)({\n\tcreateList: createList,\n\tgetLayoutRect: getLayoutRect,\n\tdataStack: dataStack$1,\n\tcreateScale: createScale,\n\tmixinAxisModelCommonMethods: mixinAxisModelCommonMethods,\n\tcompleteDimensions: completeDimensions,\n\tcreateDimensions: createDimensions,\n\tcreateSymbol: createSymbol\n});\n\nvar EPSILON$3 = 1e-8;\n\nfunction isAroundEqual$1(a, b) {\n    return Math.abs(a - b) < EPSILON$3;\n}\n\nfunction contain$1(points, x, y) {\n    var w = 0;\n    var p = points[0];\n\n    if (!p) {\n        return false;\n    }\n\n    for (var i = 1; i < points.length; i++) {\n        var p2 = points[i];\n        w += windingLine(p[0], p[1], p2[0], p2[1], x, y);\n        p = p2;\n    }\n\n    // Close polygon\n    var p0 = points[0];\n    if (!isAroundEqual$1(p[0], p0[0]) || !isAroundEqual$1(p[1], p0[1])) {\n        w += windingLine(p[0], p[1], p0[0], p0[1], x, y);\n    }\n\n    return w !== 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/coord/geo/Region\n */\n\n/**\n * @param {string|Region} name\n * @param {Array} geometries\n * @param {Array.<number>} cp\n */\nfunction Region(name, geometries, cp) {\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.name = name;\n\n    /**\n     * @type {Array.<Array>}\n     * @readOnly\n     */\n    this.geometries = geometries;\n\n    if (!cp) {\n        var rect = this.getBoundingRect();\n        cp = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    }\n    else {\n        cp = [cp[0], cp[1]];\n    }\n    /**\n     * @type {Array.<number>}\n     */\n    this.center = cp;\n}\n\nRegion.prototype = {\n\n    constructor: Region,\n\n    properties: null,\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function () {\n        var rect = this._rect;\n        if (rect) {\n            return rect;\n        }\n\n        var MAX_NUMBER = Number.MAX_VALUE;\n        var min$$1 = [MAX_NUMBER, MAX_NUMBER];\n        var max$$1 = [-MAX_NUMBER, -MAX_NUMBER];\n        var min2 = [];\n        var max2 = [];\n        var geometries = this.geometries;\n        for (var i = 0; i < geometries.length; i++) {\n            // Only support polygon\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            // Doesn't consider hole\n            var exterior = geometries[i].exterior;\n            fromPoints(exterior, min2, max2);\n            min(min$$1, min$$1, min2);\n            max(max$$1, max$$1, max2);\n        }\n        // No data\n        if (i === 0) {\n            min$$1[0] = min$$1[1] = max$$1[0] = max$$1[1] = 0;\n        }\n\n        return (this._rect = new BoundingRect(\n            min$$1[0], min$$1[1], max$$1[0] - min$$1[0], max$$1[1] - min$$1[1]\n        ));\n    },\n\n    /**\n     * @param {<Array.<number>} coord\n     * @return {boolean}\n     */\n    contain: function (coord) {\n        var rect = this.getBoundingRect();\n        var geometries = this.geometries;\n        if (!rect.contain(coord[0], coord[1])) {\n            return false;\n        }\n        loopGeo: for (var i = 0, len$$1 = geometries.length; i < len$$1; i++) {\n            // Only support polygon.\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            var exterior = geometries[i].exterior;\n            var interiors = geometries[i].interiors;\n            if (contain$1(exterior, coord[0], coord[1])) {\n                // Not in the region if point is in the hole.\n                for (var k = 0; k < (interiors ? interiors.length : 0); k++) {\n                    if (contain$1(interiors[k])) {\n                        continue loopGeo;\n                    }\n                }\n                return true;\n            }\n        }\n        return false;\n    },\n\n    transformTo: function (x, y, width, height) {\n        var rect = this.getBoundingRect();\n        var aspect = rect.width / rect.height;\n        if (!width) {\n            width = aspect * height;\n        }\n        else if (!height) {\n            height = width / aspect;\n        }\n        var target = new BoundingRect(x, y, width, height);\n        var transform = rect.calculateTransform(target);\n        var geometries = this.geometries;\n        for (var i = 0; i < geometries.length; i++) {\n            // Only support polygon.\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            var exterior = geometries[i].exterior;\n            var interiors = geometries[i].interiors;\n            for (var p = 0; p < exterior.length; p++) {\n                applyTransform(exterior[p], exterior[p], transform);\n            }\n            for (var h = 0; h < (interiors ? interiors.length : 0); h++) {\n                for (var p = 0; p < interiors[h].length; p++) {\n                    applyTransform(interiors[h][p], interiors[h][p], transform);\n                }\n            }\n        }\n        rect = this._rect;\n        rect.copy(target);\n        // Update center\n        this.center = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    },\n\n    cloneShallow: function (name) {\n        name == null && (name = this.name);\n        var newRegion = new Region(name, this.geometries, this.center);\n        newRegion._rect = this._rect;\n        newRegion.transformTo = null; // Simply avoid to be called.\n        return newRegion;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Parse and decode geo json\n * @module echarts/coord/geo/parseGeoJson\n */\n\nfunction decode(json) {\n    if (!json.UTF8Encoding) {\n        return json;\n    }\n    var encodeScale = json.UTF8Scale;\n    if (encodeScale == null) {\n        encodeScale = 1024;\n    }\n\n    var features = json.features;\n\n    for (var f = 0; f < features.length; f++) {\n        var feature = features[f];\n        var geometry = feature.geometry;\n        var coordinates = geometry.coordinates;\n        var encodeOffsets = geometry.encodeOffsets;\n\n        for (var c = 0; c < coordinates.length; c++) {\n            var coordinate = coordinates[c];\n\n            if (geometry.type === 'Polygon') {\n                coordinates[c] = decodePolygon(\n                    coordinate,\n                    encodeOffsets[c],\n                    encodeScale\n                );\n            }\n            else if (geometry.type === 'MultiPolygon') {\n                for (var c2 = 0; c2 < coordinate.length; c2++) {\n                    var polygon = coordinate[c2];\n                    coordinate[c2] = decodePolygon(\n                        polygon,\n                        encodeOffsets[c][c2],\n                        encodeScale\n                    );\n                }\n            }\n        }\n    }\n    // Has been decoded\n    json.UTF8Encoding = false;\n    return json;\n}\n\nfunction decodePolygon(coordinate, encodeOffsets, encodeScale) {\n    var result = [];\n    var prevX = encodeOffsets[0];\n    var prevY = encodeOffsets[1];\n\n    for (var i = 0; i < coordinate.length; i += 2) {\n        var x = coordinate.charCodeAt(i) - 64;\n        var y = coordinate.charCodeAt(i + 1) - 64;\n        // ZigZag decoding\n        x = (x >> 1) ^ (-(x & 1));\n        y = (y >> 1) ^ (-(y & 1));\n        // Delta deocding\n        x += prevX;\n        y += prevY;\n\n        prevX = x;\n        prevY = y;\n        // Dequantize\n        result.push([x / encodeScale, y / encodeScale]);\n    }\n\n    return result;\n}\n\n/**\n * @alias module:echarts/coord/geo/parseGeoJson\n * @param {Object} geoJson\n * @return {module:zrender/container/Group}\n */\nvar parseGeoJSON = function (geoJson) {\n\n    decode(geoJson);\n\n    return map(filter(geoJson.features, function (featureObj) {\n        // Output of mapshaper may have geometry null\n        return featureObj.geometry\n            && featureObj.properties\n            && featureObj.geometry.coordinates.length > 0;\n    }), function (featureObj) {\n        var properties = featureObj.properties;\n        var geo = featureObj.geometry;\n\n        var coordinates = geo.coordinates;\n\n        var geometries = [];\n        if (geo.type === 'Polygon') {\n            geometries.push({\n                type: 'polygon',\n                // According to the GeoJSON specification.\n                // First must be exterior, and the rest are all interior(holes).\n                exterior: coordinates[0],\n                interiors: coordinates.slice(1)\n            });\n        }\n        if (geo.type === 'MultiPolygon') {\n            each$1(coordinates, function (item) {\n                if (item[0]) {\n                    geometries.push({\n                        type: 'polygon',\n                        exterior: item[0],\n                        interiors: item.slice(1)\n                    });\n                }\n            });\n        }\n\n        var region = new Region(\n            properties.name,\n            geometries,\n            properties.cp\n        );\n        region.properties = properties;\n        return region;\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$6 = makeInner();\n\n/**\n * @param {module:echats/coord/Axis} axis\n * @return {Object} {\n *     labels: [{\n *         formattedLabel: string,\n *         rawLabel: string,\n *         tickValue: number\n *     }, ...],\n *     labelCategoryInterval: number\n * }\n */\nfunction createAxisLabels(axis) {\n    // Only ordinal scale support tick interval\n    return axis.type === 'category'\n        ? makeCategoryLabels(axis)\n        : makeRealNumberLabels(axis);\n}\n\n/**\n * @param {module:echats/coord/Axis} axis\n * @param {module:echarts/model/Model} tickModel For example, can be axisTick, splitLine, splitArea.\n * @return {Object} {\n *     ticks: Array.<number>\n *     tickCategoryInterval: number\n * }\n */\nfunction createAxisTicks(axis, tickModel) {\n    // Only ordinal scale support tick interval\n    return axis.type === 'category'\n        ? makeCategoryTicks(axis, tickModel)\n        : {ticks: axis.scale.getTicks()};\n}\n\nfunction makeCategoryLabels(axis) {\n    var labelModel = axis.getLabelModel();\n    var result = makeCategoryLabelsActually(axis, labelModel);\n\n    return (!labelModel.get('show') || axis.scale.isBlank())\n        ? {labels: [], labelCategoryInterval: result.labelCategoryInterval}\n        : result;\n}\n\nfunction makeCategoryLabelsActually(axis, labelModel) {\n    var labelsCache = getListCache(axis, 'labels');\n    var optionLabelInterval = getOptionCategoryInterval(labelModel);\n    var result = listCacheGet(labelsCache, optionLabelInterval);\n\n    if (result) {\n        return result;\n    }\n\n    var labels;\n    var numericLabelInterval;\n\n    if (isFunction$1(optionLabelInterval)) {\n        labels = makeLabelsByCustomizedCategoryInterval(axis, optionLabelInterval);\n    }\n    else {\n        numericLabelInterval = optionLabelInterval === 'auto'\n            ? makeAutoCategoryInterval(axis) : optionLabelInterval;\n        labels = makeLabelsByNumericCategoryInterval(axis, numericLabelInterval);\n    }\n\n    // Cache to avoid calling interval function repeatly.\n    return listCacheSet(labelsCache, optionLabelInterval, {\n        labels: labels, labelCategoryInterval: numericLabelInterval\n    });\n}\n\nfunction makeCategoryTicks(axis, tickModel) {\n    var ticksCache = getListCache(axis, 'ticks');\n    var optionTickInterval = getOptionCategoryInterval(tickModel);\n    var result = listCacheGet(ticksCache, optionTickInterval);\n\n    if (result) {\n        return result;\n    }\n\n    var ticks;\n    var tickCategoryInterval;\n\n    // Optimize for the case that large category data and no label displayed,\n    // we should not return all ticks.\n    if (!tickModel.get('show') || axis.scale.isBlank()) {\n        ticks = [];\n    }\n\n    if (isFunction$1(optionTickInterval)) {\n        ticks = makeLabelsByCustomizedCategoryInterval(axis, optionTickInterval, true);\n    }\n    // Always use label interval by default despite label show. Consider this\n    // scenario, Use multiple grid with the xAxis sync, and only one xAxis shows\n    // labels. `splitLine` and `axisTick` should be consistent in this case.\n    else if (optionTickInterval === 'auto') {\n        var labelsResult = makeCategoryLabelsActually(axis, axis.getLabelModel());\n        tickCategoryInterval = labelsResult.labelCategoryInterval;\n        ticks = map(labelsResult.labels, function (labelItem) {\n            return labelItem.tickValue;\n        });\n    }\n    else {\n        tickCategoryInterval = optionTickInterval;\n        ticks = makeLabelsByNumericCategoryInterval(axis, tickCategoryInterval, true);\n    }\n\n    // Cache to avoid calling interval function repeatly.\n    return listCacheSet(ticksCache, optionTickInterval, {\n        ticks: ticks, tickCategoryInterval: tickCategoryInterval\n    });\n}\n\nfunction makeRealNumberLabels(axis) {\n    var ticks = axis.scale.getTicks();\n    var labelFormatter = makeLabelFormatter(axis);\n    return {\n        labels: map(ticks, function (tickValue, idx) {\n            return {\n                formattedLabel: labelFormatter(tickValue, idx),\n                rawLabel: axis.scale.getLabel(tickValue),\n                tickValue: tickValue\n            };\n        })\n    };\n}\n\n// Large category data calculation is performence sensitive, and ticks and label\n// probably be fetched by multiple times. So we cache the result.\n// axis is created each time during a ec process, so we do not need to clear cache.\nfunction getListCache(axis, prop) {\n    // Because key can be funciton, and cache size always be small, we use array cache.\n    return inner$6(axis)[prop] || (inner$6(axis)[prop] = []);\n}\n\nfunction listCacheGet(cache, key) {\n    for (var i = 0; i < cache.length; i++) {\n        if (cache[i].key === key) {\n            return cache[i].value;\n        }\n    }\n}\n\nfunction listCacheSet(cache, key, value) {\n    cache.push({key: key, value: value});\n    return value;\n}\n\nfunction makeAutoCategoryInterval(axis) {\n    var result = inner$6(axis).autoInterval;\n    return result != null\n        ? result\n        : (inner$6(axis).autoInterval = axis.calculateCategoryInterval());\n}\n\n/**\n * Calculate interval for category axis ticks and labels.\n * To get precise result, at least one of `getRotate` and `isHorizontal`\n * should be implemented in axis.\n */\nfunction calculateCategoryInterval(axis) {\n    var params = fetchAutoCategoryIntervalCalculationParams(axis);\n    var labelFormatter = makeLabelFormatter(axis);\n    var rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI;\n\n    var ordinalScale = axis.scale;\n    var ordinalExtent = ordinalScale.getExtent();\n    // Providing this method is for optimization:\n    // avoid generating a long array by `getTicks`\n    // in large category data case.\n    var tickCount = ordinalScale.count();\n\n    if (ordinalExtent[1] - ordinalExtent[0] < 1) {\n        return 0;\n    }\n\n    var step = 1;\n    // Simple optimization. Empirical value: tick count should less than 40.\n    if (tickCount > 40) {\n        step = Math.max(1, Math.floor(tickCount / 40));\n    }\n    var tickValue = ordinalExtent[0];\n    var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue);\n    var unitW = Math.abs(unitSpan * Math.cos(rotation));\n    var unitH = Math.abs(unitSpan * Math.sin(rotation));\n\n    var maxW = 0;\n    var maxH = 0;\n\n    // Caution: Performance sensitive for large category data.\n    // Consider dataZoom, we should make appropriate step to avoid O(n) loop.\n    for (; tickValue <= ordinalExtent[1]; tickValue += step) {\n        var width = 0;\n        var height = 0;\n\n        // Not precise, do not consider align and vertical align\n        // and each distance from axis line yet.\n        var rect = getBoundingRect(\n            labelFormatter(tickValue), params.font, 'center', 'top'\n        );\n        // Magic number\n        width = rect.width * 1.3;\n        height = rect.height * 1.3;\n\n        // Min size, void long loop.\n        maxW = Math.max(maxW, width, 7);\n        maxH = Math.max(maxH, height, 7);\n    }\n\n    var dw = maxW / unitW;\n    var dh = maxH / unitH;\n    // 0/0 is NaN, 1/0 is Infinity.\n    isNaN(dw) && (dw = Infinity);\n    isNaN(dh) && (dh = Infinity);\n    var interval = Math.max(0, Math.floor(Math.min(dw, dh)));\n\n    var cache = inner$6(axis.model);\n    var lastAutoInterval = cache.lastAutoInterval;\n    var lastTickCount = cache.lastTickCount;\n\n    // Use cache to keep interval stable while moving zoom window,\n    // otherwise the calculated interval might jitter when the zoom\n    // window size is close to the interval-changing size.\n    if (lastAutoInterval != null\n        && lastTickCount != null\n        && Math.abs(lastAutoInterval - interval) <= 1\n        && Math.abs(lastTickCount - tickCount) <= 1\n        // Always choose the bigger one, otherwise the critical\n        // point is not the same when zooming in or zooming out.\n        && lastAutoInterval > interval\n    ) {\n        interval = lastAutoInterval;\n    }\n    // Only update cache if cache not used, otherwise the\n    // changing of interval is too insensitive.\n    else {\n        cache.lastTickCount = tickCount;\n        cache.lastAutoInterval = interval;\n    }\n\n    return interval;\n}\n\nfunction fetchAutoCategoryIntervalCalculationParams(axis) {\n    var labelModel = axis.getLabelModel();\n    return {\n        axisRotate: axis.getRotate\n            ? axis.getRotate()\n            : (axis.isHorizontal && !axis.isHorizontal())\n            ? 90\n            : 0,\n        labelRotate: labelModel.get('rotate') || 0,\n        font: labelModel.getFont()\n    };\n}\n\nfunction makeLabelsByNumericCategoryInterval(axis, categoryInterval, onlyTick) {\n    var labelFormatter = makeLabelFormatter(axis);\n    var ordinalScale = axis.scale;\n    var ordinalExtent = ordinalScale.getExtent();\n    var labelModel = axis.getLabelModel();\n    var result = [];\n\n    // TODO: axisType: ordinalTime, pick the tick from each month/day/year/...\n\n    var step = Math.max((categoryInterval || 0) + 1, 1);\n    var startTick = ordinalExtent[0];\n    var tickCount = ordinalScale.count();\n\n    // Calculate start tick based on zero if possible to keep label consistent\n    // while zooming and moving while interval > 0. Otherwise the selection\n    // of displayable ticks and symbols probably keep changing.\n    // 3 is empirical value.\n    if (startTick !== 0 && step > 1 && tickCount / step > 2) {\n        startTick = Math.round(Math.ceil(startTick / step) * step);\n    }\n\n    // (1) Only add min max label here but leave overlap checking\n    // to render stage, which also ensure the returned list\n    // suitable for splitLine and splitArea rendering.\n    // (2) Scales except category always contain min max label so\n    // do not need to perform this process.\n    var showAllLabel = shouldShowAllLabels(axis);\n    var includeMinLabel = labelModel.get('showMinLabel') || showAllLabel;\n    var includeMaxLabel = labelModel.get('showMaxLabel') || showAllLabel;\n\n    if (includeMinLabel && startTick !== ordinalExtent[0]) {\n        addItem(ordinalExtent[0]);\n    }\n\n    // Optimize: avoid generating large array by `ordinalScale.getTicks()`.\n    var tickValue = startTick;\n    for (; tickValue <= ordinalExtent[1]; tickValue += step) {\n        addItem(tickValue);\n    }\n\n    if (includeMaxLabel && tickValue !== ordinalExtent[1]) {\n        addItem(ordinalExtent[1]);\n    }\n\n    function addItem(tVal) {\n        result.push(onlyTick\n            ? tVal\n            : {\n                formattedLabel: labelFormatter(tVal),\n                rawLabel: ordinalScale.getLabel(tVal),\n                tickValue: tVal\n            }\n        );\n    }\n\n    return result;\n}\n\n// When interval is function, the result `false` means ignore the tick.\n// It is time consuming for large category data.\nfunction makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) {\n    var ordinalScale = axis.scale;\n    var labelFormatter = makeLabelFormatter(axis);\n    var result = [];\n\n    each$1(ordinalScale.getTicks(), function (tickValue) {\n        var rawLabel = ordinalScale.getLabel(tickValue);\n        if (categoryInterval(tickValue, rawLabel)) {\n            result.push(onlyTick\n                ? tickValue\n                : {\n                    formattedLabel: labelFormatter(tickValue),\n                    rawLabel: rawLabel,\n                    tickValue: tickValue\n                }\n            );\n        }\n    });\n\n    return result;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar NORMALIZED_EXTENT = [0, 1];\n\n/**\n * Base class of Axis.\n * @constructor\n */\nvar Axis = function (dim, scale, extent) {\n\n    /**\n     * Axis dimension. Such as 'x', 'y', 'z', 'angle', 'radius'.\n     * @type {string}\n     */\n    this.dim = dim;\n\n    /**\n     * Axis scale\n     * @type {module:echarts/coord/scale/*}\n     */\n    this.scale = scale;\n\n    /**\n     * @type {Array.<number>}\n     * @private\n     */\n    this._extent = extent || [0, 0];\n\n    /**\n     * @type {boolean}\n     */\n    this.inverse = false;\n\n    /**\n     * Usually true when axis has a ordinal scale\n     * @type {boolean}\n     */\n    this.onBand = false;\n};\n\nAxis.prototype = {\n\n    constructor: Axis,\n\n    /**\n     * If axis extent contain given coord\n     * @param {number} coord\n     * @return {boolean}\n     */\n    contain: function (coord) {\n        var extent = this._extent;\n        var min = Math.min(extent[0], extent[1]);\n        var max = Math.max(extent[0], extent[1]);\n        return coord >= min && coord <= max;\n    },\n\n    /**\n     * If axis extent contain given data\n     * @param {number} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this.contain(this.dataToCoord(data));\n    },\n\n    /**\n     * Get coord extent.\n     * @return {Array.<number>}\n     */\n    getExtent: function () {\n        return this._extent.slice();\n    },\n\n    /**\n     * Get precision used for formatting\n     * @param {Array.<number>} [dataExtent]\n     * @return {number}\n     */\n    getPixelPrecision: function (dataExtent) {\n        return getPixelPrecision(\n            dataExtent || this.scale.getExtent(),\n            this._extent\n        );\n    },\n\n    /**\n     * Set coord extent\n     * @param {number} start\n     * @param {number} end\n     */\n    setExtent: function (start, end) {\n        var extent = this._extent;\n        extent[0] = start;\n        extent[1] = end;\n    },\n\n    /**\n     * Convert data to coord. Data is the rank if it has an ordinal scale\n     * @param {number} data\n     * @param  {boolean} clamp\n     * @return {number}\n     */\n    dataToCoord: function (data, clamp) {\n        var extent = this._extent;\n        var scale = this.scale;\n        data = scale.normalize(data);\n\n        if (this.onBand && scale.type === 'ordinal') {\n            extent = extent.slice();\n            fixExtentWithBands(extent, scale.count());\n        }\n\n        return linearMap(data, NORMALIZED_EXTENT, extent, clamp);\n    },\n\n    /**\n     * Convert coord to data. Data is the rank if it has an ordinal scale\n     * @param {number} coord\n     * @param  {boolean} clamp\n     * @return {number}\n     */\n    coordToData: function (coord, clamp) {\n        var extent = this._extent;\n        var scale = this.scale;\n\n        if (this.onBand && scale.type === 'ordinal') {\n            extent = extent.slice();\n            fixExtentWithBands(extent, scale.count());\n        }\n\n        var t = linearMap(coord, extent, NORMALIZED_EXTENT, clamp);\n\n        return this.scale.scale(t);\n    },\n\n    /**\n     * Convert pixel point to data in axis\n     * @param {Array.<number>} point\n     * @param  {boolean} clamp\n     * @return {number} data\n     */\n    pointToData: function (point, clamp) {\n        // Should be implemented in derived class if necessary.\n    },\n\n    /**\n     * Different from `zrUtil.map(axis.getTicks(), axis.dataToCoord, axis)`,\n     * `axis.getTicksCoords` considers `onBand`, which is used by\n     * `boundaryGap:true` of category axis and splitLine and splitArea.\n     * @param {Object} [opt]\n     * @param {number} [opt.tickModel=axis.model.getModel('axisTick')]\n     * @param {boolean} [opt.clamp] If `true`, the first and the last\n     *        tick must be at the axis end points. Otherwise, clip ticks\n     *        that outside the axis extent.\n     * @return {Array.<Object>} [{\n     *     coord: ...,\n     *     tickValue: ...\n     * }, ...]\n     */\n    getTicksCoords: function (opt) {\n        opt = opt || {};\n\n        var tickModel = opt.tickModel || this.getTickModel();\n\n        var result = createAxisTicks(this, tickModel);\n        var ticks = result.ticks;\n\n        var ticksCoords = map(ticks, function (tickValue) {\n            return {\n                coord: this.dataToCoord(tickValue),\n                tickValue: tickValue\n            };\n        }, this);\n\n        var alignWithLabel = tickModel.get('alignWithLabel');\n        fixOnBandTicksCoords(\n            this, ticksCoords, result.tickCategoryInterval, alignWithLabel, opt.clamp\n        );\n\n        return ticksCoords;\n    },\n\n    /**\n     * @return {Array.<Object>} [{\n     *     formattedLabel: string,\n     *     rawLabel: axis.scale.getLabel(tickValue)\n     *     tickValue: number\n     * }, ...]\n     */\n    getViewLabels: function () {\n        return createAxisLabels(this).labels;\n    },\n\n    /**\n     * @return {module:echarts/coord/model/Model}\n     */\n    getLabelModel: function () {\n        return this.model.getModel('axisLabel');\n    },\n\n    /**\n     * Notice here we only get the default tick model. For splitLine\n     * or splitArea, we should pass the splitLineModel or splitAreaModel\n     * manually when calling `getTicksCoords`.\n     * In GL, this method may be overrided to:\n     * `axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));`\n     * @return {module:echarts/coord/model/Model}\n     */\n    getTickModel: function () {\n        return this.model.getModel('axisTick');\n    },\n\n    /**\n     * Get width of band\n     * @return {number}\n     */\n    getBandWidth: function () {\n        var axisExtent = this._extent;\n        var dataExtent = this.scale.getExtent();\n\n        var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0);\n        // Fix #2728, avoid NaN when only one data.\n        len === 0 && (len = 1);\n\n        var size = Math.abs(axisExtent[1] - axisExtent[0]);\n\n        return Math.abs(size) / len;\n    },\n\n    /**\n     * @abstract\n     * @return {boolean} Is horizontal\n     */\n    isHorizontal: null,\n\n    /**\n     * @abstract\n     * @return {number} Get axis rotate, by degree.\n     */\n    getRotate: null,\n\n    /**\n     * Only be called in category axis.\n     * Can be overrided, consider other axes like in 3D.\n     * @return {number} Auto interval for cateogry axis tick and label\n     */\n    calculateCategoryInterval: function () {\n        return calculateCategoryInterval(this);\n    }\n\n};\n\nfunction fixExtentWithBands(extent, nTick) {\n    var size = extent[1] - extent[0];\n    var len = nTick;\n    var margin = size / len / 2;\n    extent[0] += margin;\n    extent[1] -= margin;\n}\n\n// If axis has labels [1, 2, 3, 4]. Bands on the axis are\n// |---1---|---2---|---3---|---4---|.\n// So the displayed ticks and splitLine/splitArea should between\n// each data item, otherwise cause misleading (e.g., split tow bars\n// of a single data item when there are two bar series).\n// Also consider if tickCategoryInterval > 0 and onBand, ticks and\n// splitLine/spliteArea should layout appropriately corresponding\n// to displayed labels. (So we should not use `getBandWidth` in this\n// case).\nfunction fixOnBandTicksCoords(axis, ticksCoords, tickCategoryInterval, alignWithLabel, clamp) {\n    var ticksLen = ticksCoords.length;\n\n    if (!axis.onBand || alignWithLabel || !ticksLen) {\n        return;\n    }\n\n    var axisExtent = axis.getExtent();\n    var last;\n    if (ticksLen === 1) {\n        ticksCoords[0].coord = axisExtent[0];\n        last = ticksCoords[1] = {coord: axisExtent[0]};\n    }\n    else {\n        var shift = (ticksCoords[1].coord - ticksCoords[0].coord);\n        each$1(ticksCoords, function (ticksItem) {\n            ticksItem.coord -= shift / 2;\n            var tickCategoryInterval = tickCategoryInterval || 0;\n            // Avoid split a single data item when odd interval.\n            if (tickCategoryInterval % 2 > 0) {\n                ticksItem.coord -= shift / ((tickCategoryInterval + 1) * 2);\n            }\n        });\n        last = {coord: ticksCoords[ticksLen - 1].coord + shift};\n        ticksCoords.push(last);\n    }\n\n    var inverse = axisExtent[0] > axisExtent[1];\n\n    if (littleThan(ticksCoords[0].coord, axisExtent[0])) {\n        clamp ? (ticksCoords[0].coord = axisExtent[0]) : ticksCoords.shift();\n    }\n    if (clamp && littleThan(axisExtent[0], ticksCoords[0].coord)) {\n        ticksCoords.unshift({coord: axisExtent[0]});\n    }\n    if (littleThan(axisExtent[1], last.coord)) {\n        clamp ? (last.coord = axisExtent[1]) : ticksCoords.pop();\n    }\n    if (clamp && littleThan(last.coord, axisExtent[1])) {\n        ticksCoords.push({coord: axisExtent[1]});\n    }\n\n    function littleThan(a, b) {\n        return inverse ? a > b : a < b;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Do not mount those modules on 'src/echarts' for better tree shaking.\n */\n\nvar parseGeoJson = parseGeoJSON;\n\nvar ecUtil = {};\neach$1(\n    [\n        'map', 'each', 'filter', 'indexOf', 'inherits', 'reduce', 'filter',\n        'bind', 'curry', 'isArray', 'isString', 'isObject', 'isFunction',\n        'extend', 'defaults', 'clone', 'merge'\n    ],\n    function (name) {\n        ecUtil[name] = zrUtil[name];\n    }\n);\nvar graphic$1 = {};\neach$1(\n    [\n        'extendShape', 'extendPath', 'makePath', 'makeImage',\n        'mergePath', 'resizePath', 'createIcon',\n        'setHoverStyle', 'setLabelStyle', 'setTextStyle', 'setText',\n        'getFont', 'updateProps', 'initProps', 'getTransform',\n        'clipPointsByRect', 'clipRectByRect',\n        'Group',\n        'Image',\n        'Text',\n        'Circle',\n        'Sector',\n        'Ring',\n        'Polygon',\n        'Polyline',\n        'Rect',\n        'Line',\n        'BezierCurve',\n        'Arc',\n        'IncrementalDisplayable',\n        'CompoundPath',\n        'LinearGradient',\n        'RadialGradient',\n        'BoundingRect'\n    ],\n    function (name) {\n        graphic$1[name] = graphic[name];\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.line',\n\n    dependencies: ['grid', 'polar'],\n\n    getInitialData: function (option, ecModel) {\n        if (__DEV__) {\n            var coordSys = option.coordinateSystem;\n            if (coordSys !== 'polar' && coordSys !== 'cartesian2d') {\n                throw new Error('Line not support coordinateSystem besides cartesian and polar');\n            }\n        }\n        return createListFromArray(this.getSource(), this);\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // stack: null\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // polarIndex: 0,\n\n        // If clip the overflow value\n        clipOverflow: true,\n        // cursor: null,\n\n        label: {\n            position: 'top'\n        },\n        // itemStyle: {\n        // },\n\n        lineStyle: {\n            width: 2,\n            type: 'solid'\n        },\n        // areaStyle: {\n            // origin of areaStyle. Valid values:\n            // `'auto'/null/undefined`: from axisLine to data\n            // `'start'`: from min to data\n            // `'end'`: from data to max\n            // origin: 'auto'\n        // },\n        // false, 'start', 'end', 'middle'\n        step: false,\n\n        // Disabled if step is true\n        smooth: false,\n        smoothMonotone: null,\n        symbol: 'emptyCircle',\n        symbolSize: 4,\n        symbolRotate: null,\n\n        showSymbol: true,\n        // `false`: follow the label interval strategy.\n        // `true`: show all symbols.\n        // `'auto'`: If possible, show all symbols, otherwise\n        //           follow the label interval strategy.\n        showAllSymbol: 'auto',\n\n        // Whether to connect break point.\n        connectNulls: false,\n\n        // Sampling for large data. Can be: 'average', 'max', 'min', 'sum'.\n        sampling: 'none',\n\n        animationEasing: 'linear',\n\n        // Disable progressive\n        progressive: 0,\n        hoverLayerThreshold: Infinity\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @return {string} label string. Not null/undefined\n */\nfunction getDefaultLabel(data, dataIndex) {\n    var labelDims = data.mapDimension('defaultedLabel', true);\n    var len = labelDims.length;\n\n    // Simple optimization (in lots of cases, label dims length is 1)\n    if (len === 1) {\n        return retrieveRawValue(data, dataIndex, labelDims[0]);\n    }\n    else if (len) {\n        var vals = [];\n        for (var i = 0; i < labelDims.length; i++) {\n            var val = retrieveRawValue(data, dataIndex, labelDims[i]);\n            vals.push(val);\n        }\n        return vals.join(' ');\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Symbol\n */\n\n/**\n * @constructor\n * @alias {module:echarts/chart/helper/Symbol}\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @extends {module:zrender/graphic/Group}\n */\nfunction SymbolClz$1(data, idx, seriesScope) {\n    Group.call(this);\n    this.updateData(data, idx, seriesScope);\n}\n\nvar symbolProto = SymbolClz$1.prototype;\n\n/**\n * @public\n * @static\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @return {Array.<number>} [width, height]\n */\nvar getSymbolSize = SymbolClz$1.getSymbolSize = function (data, idx) {\n    var symbolSize = data.getItemVisual(idx, 'symbolSize');\n    return symbolSize instanceof Array\n        ? symbolSize.slice()\n        : [+symbolSize, +symbolSize];\n};\n\nfunction getScale(symbolSize) {\n    return [symbolSize[0] / 2, symbolSize[1] / 2];\n}\n\nfunction driftSymbol(dx, dy) {\n    this.parent.drift(dx, dy);\n}\n\nsymbolProto._createSymbol = function (\n    symbolType,\n    data,\n    idx,\n    symbolSize,\n    keepAspect\n) {\n    // Remove paths created before\n    this.removeAll();\n\n    var color = data.getItemVisual(idx, 'color');\n\n    // var symbolPath = createSymbol(\n    //     symbolType, -0.5, -0.5, 1, 1, color\n    // );\n    // If width/height are set too small (e.g., set to 1) on ios10\n    // and macOS Sierra, a circle stroke become a rect, no matter what\n    // the scale is set. So we set width/height as 2. See #4150.\n    var symbolPath = createSymbol(\n        symbolType, -1, -1, 2, 2, color, keepAspect\n    );\n\n    symbolPath.attr({\n        z2: 100,\n        culling: true,\n        scale: getScale(symbolSize)\n    });\n    // Rewrite drift method\n    symbolPath.drift = driftSymbol;\n\n    this._symbolType = symbolType;\n\n    this.add(symbolPath);\n};\n\n/**\n * Stop animation\n * @param {boolean} toLastFrame\n */\nsymbolProto.stopSymbolAnimation = function (toLastFrame) {\n    this.childAt(0).stopAnimation(toLastFrame);\n};\n\n/**\n * FIXME:\n * Caution: This method breaks the encapsulation of this module,\n * but it indeed brings convenience. So do not use the method\n * unless you detailedly know all the implements of `Symbol`,\n * especially animation.\n *\n * Get symbol path element.\n */\nsymbolProto.getSymbolPath = function () {\n    return this.childAt(0);\n};\n\n/**\n * Get scale(aka, current symbol size).\n * Including the change caused by animation\n */\nsymbolProto.getScale = function () {\n    return this.childAt(0).scale;\n};\n\n/**\n * Highlight symbol\n */\nsymbolProto.highlight = function () {\n    this.childAt(0).trigger('emphasis');\n};\n\n/**\n * Downplay symbol\n */\nsymbolProto.downplay = function () {\n    this.childAt(0).trigger('normal');\n};\n\n/**\n * @param {number} zlevel\n * @param {number} z\n */\nsymbolProto.setZ = function (zlevel, z) {\n    var symbolPath = this.childAt(0);\n    symbolPath.zlevel = zlevel;\n    symbolPath.z = z;\n};\n\nsymbolProto.setDraggable = function (draggable) {\n    var symbolPath = this.childAt(0);\n    symbolPath.draggable = draggable;\n    symbolPath.cursor = draggable ? 'move' : 'pointer';\n};\n\n/**\n * Update symbol properties\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @param {Object} [seriesScope]\n * @param {Object} [seriesScope.itemStyle]\n * @param {Object} [seriesScope.hoverItemStyle]\n * @param {Object} [seriesScope.symbolRotate]\n * @param {Object} [seriesScope.symbolOffset]\n * @param {module:echarts/model/Model} [seriesScope.labelModel]\n * @param {module:echarts/model/Model} [seriesScope.hoverLabelModel]\n * @param {boolean} [seriesScope.hoverAnimation]\n * @param {Object} [seriesScope.cursorStyle]\n * @param {module:echarts/model/Model} [seriesScope.itemModel]\n * @param {string} [seriesScope.symbolInnerColor]\n * @param {Object} [seriesScope.fadeIn=false]\n */\nsymbolProto.updateData = function (data, idx, seriesScope) {\n    this.silent = false;\n\n    var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';\n    var seriesModel = data.hostModel;\n    var symbolSize = getSymbolSize(data, idx);\n    var isInit = symbolType !== this._symbolType;\n\n    if (isInit) {\n        var keepAspect = data.getItemVisual(idx, 'symbolKeepAspect');\n        this._createSymbol(symbolType, data, idx, symbolSize, keepAspect);\n    }\n    else {\n        var symbolPath = this.childAt(0);\n        symbolPath.silent = false;\n        updateProps(symbolPath, {\n            scale: getScale(symbolSize)\n        }, seriesModel, idx);\n    }\n\n    this._updateCommon(data, idx, symbolSize, seriesScope);\n\n    if (isInit) {\n        var symbolPath = this.childAt(0);\n        var fadeIn = seriesScope && seriesScope.fadeIn;\n\n        var target = {scale: symbolPath.scale.slice()};\n        fadeIn && (target.style = {opacity: symbolPath.style.opacity});\n\n        symbolPath.scale = [0, 0];\n        fadeIn && (symbolPath.style.opacity = 0);\n\n        initProps(symbolPath, target, seriesModel, idx);\n    }\n\n    this._seriesModel = seriesModel;\n};\n\n// Update common properties\nvar normalStyleAccessPath = ['itemStyle'];\nvar emphasisStyleAccessPath = ['emphasis', 'itemStyle'];\nvar normalLabelAccessPath = ['label'];\nvar emphasisLabelAccessPath = ['emphasis', 'label'];\n\n/**\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @param {Array.<number>} symbolSize\n * @param {Object} [seriesScope]\n */\nsymbolProto._updateCommon = function (data, idx, symbolSize, seriesScope) {\n    var symbolPath = this.childAt(0);\n    var seriesModel = data.hostModel;\n    var color = data.getItemVisual(idx, 'color');\n\n    // Reset style\n    if (symbolPath.type !== 'image') {\n        symbolPath.useStyle({\n            strokeNoScale: true\n        });\n    }\n\n    var itemStyle = seriesScope && seriesScope.itemStyle;\n    var hoverItemStyle = seriesScope && seriesScope.hoverItemStyle;\n    var symbolRotate = seriesScope && seriesScope.symbolRotate;\n    var symbolOffset = seriesScope && seriesScope.symbolOffset;\n    var labelModel = seriesScope && seriesScope.labelModel;\n    var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;\n    var hoverAnimation = seriesScope && seriesScope.hoverAnimation;\n    var cursorStyle = seriesScope && seriesScope.cursorStyle;\n\n    if (!seriesScope || data.hasItemOption) {\n        var itemModel = (seriesScope && seriesScope.itemModel)\n            ? seriesScope.itemModel : data.getItemModel(idx);\n\n        // Color must be excluded.\n        // Because symbol provide setColor individually to set fill and stroke\n        itemStyle = itemModel.getModel(normalStyleAccessPath).getItemStyle(['color']);\n        hoverItemStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();\n\n        symbolRotate = itemModel.getShallow('symbolRotate');\n        symbolOffset = itemModel.getShallow('symbolOffset');\n\n        labelModel = itemModel.getModel(normalLabelAccessPath);\n        hoverLabelModel = itemModel.getModel(emphasisLabelAccessPath);\n        hoverAnimation = itemModel.getShallow('hoverAnimation');\n        cursorStyle = itemModel.getShallow('cursor');\n    }\n    else {\n        hoverItemStyle = extend({}, hoverItemStyle);\n    }\n\n    var elStyle = symbolPath.style;\n\n    symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0);\n\n    if (symbolOffset) {\n        symbolPath.attr('position', [\n            parsePercent$1(symbolOffset[0], symbolSize[0]),\n            parsePercent$1(symbolOffset[1], symbolSize[1])\n        ]);\n    }\n\n    cursorStyle && symbolPath.attr('cursor', cursorStyle);\n\n    // PENDING setColor before setStyle!!!\n    symbolPath.setColor(color, seriesScope && seriesScope.symbolInnerColor);\n\n    symbolPath.setStyle(itemStyle);\n\n    var opacity = data.getItemVisual(idx, 'opacity');\n    if (opacity != null) {\n        elStyle.opacity = opacity;\n    }\n\n    var liftZ = data.getItemVisual(idx, 'liftZ');\n    var z2Origin = symbolPath.__z2Origin;\n    if (liftZ != null) {\n        if (z2Origin == null) {\n            symbolPath.__z2Origin = symbolPath.z2;\n            symbolPath.z2 += liftZ;\n        }\n    }\n    else if (z2Origin != null) {\n        symbolPath.z2 = z2Origin;\n        symbolPath.__z2Origin = null;\n    }\n\n    var useNameLabel = seriesScope && seriesScope.useNameLabel;\n\n    setLabelStyle(\n        elStyle, hoverItemStyle, labelModel, hoverLabelModel,\n        {\n            labelFetcher: seriesModel,\n            labelDataIndex: idx,\n            defaultText: getLabelDefaultText,\n            isRectText: true,\n            autoColor: color\n        }\n    );\n\n    // Do not execute util needed.\n    function getLabelDefaultText(idx, opt) {\n        return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx);\n    }\n\n    symbolPath.off('mouseover')\n        .off('mouseout')\n        .off('emphasis')\n        .off('normal');\n\n    symbolPath.hoverStyle = hoverItemStyle;\n\n    // FIXME\n    // Do not use symbol.trigger('emphasis'), but use symbol.highlight() instead.\n    setHoverStyle(symbolPath);\n\n    symbolPath.__symbolOriginalScale = getScale(symbolSize);\n\n    if (hoverAnimation && seriesModel.isAnimationEnabled()) {\n        // Note: consider `off`, should use static function here.\n        symbolPath.on('mouseover', onMouseOver)\n            .on('mouseout', onMouseOut)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal);\n    }\n};\n\nfunction onMouseOver() {\n    // see comment in `graphic.isInEmphasis`\n    !isInEmphasis(this) && onEmphasis.call(this);\n}\n\nfunction onMouseOut() {\n    // see comment in `graphic.isInEmphasis`\n    !isInEmphasis(this) && onNormal.call(this);\n}\n\nfunction onEmphasis() {\n    // Do not support this hover animation util some scenario required.\n    // Animation can only be supported in hover layer when using `el.incremetal`.\n    if (this.incremental || this.useHoverLayer) {\n        return;\n    }\n    var scale = this.__symbolOriginalScale;\n    var ratio = scale[1] / scale[0];\n    this.animateTo({\n        scale: [\n            Math.max(scale[0] * 1.1, scale[0] + 3),\n            Math.max(scale[1] * 1.1, scale[1] + 3 * ratio)\n        ]\n    }, 400, 'elasticOut');\n}\n\nfunction onNormal() {\n    if (this.incremental || this.useHoverLayer) {\n        return;\n    }\n    this.animateTo({\n        scale: this.__symbolOriginalScale\n    }, 400, 'elasticOut');\n}\n\n\n/**\n * @param {Function} cb\n * @param {Object} [opt]\n * @param {Object} [opt.keepLabel=true]\n */\nsymbolProto.fadeOut = function (cb, opt) {\n    var symbolPath = this.childAt(0);\n    // Avoid mistaken hover when fading out\n    this.silent = symbolPath.silent = true;\n    // Not show text when animating\n    !(opt && opt.keepLabel) && (symbolPath.style.text = null);\n\n    updateProps(\n        symbolPath,\n        {\n            style: {opacity: 0},\n            scale: [0, 0]\n        },\n        this._seriesModel,\n        this.dataIndex,\n        cb\n    );\n};\n\ninherits(SymbolClz$1, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/SymbolDraw\n */\n\n/**\n * @constructor\n * @alias module:echarts/chart/helper/SymbolDraw\n * @param {module:zrender/graphic/Group} [symbolCtor]\n */\nfunction SymbolDraw(symbolCtor) {\n    this.group = new Group();\n\n    this._symbolCtor = symbolCtor || SymbolClz$1;\n}\n\nvar symbolDrawProto = SymbolDraw.prototype;\n\nfunction symbolNeedsDraw(data, point, idx, opt) {\n    return point && !isNaN(point[0]) && !isNaN(point[1])\n        && !(opt.isIgnore && opt.isIgnore(idx))\n        // We do not set clipShape on group, because it will cut part of\n        // the symbol element shape. We use the same clip shape here as\n        // the line clip.\n        && !(opt.clipShape && !opt.clipShape.contain(point[0], point[1]))\n        && data.getItemVisual(idx, 'symbol') !== 'none';\n}\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n * @param {Object} [opt] Or isIgnore\n * @param {Function} [opt.isIgnore]\n * @param {Object} [opt.clipShape]\n */\nsymbolDrawProto.updateData = function (data, opt) {\n    opt = normalizeUpdateOpt(opt);\n\n    var group = this.group;\n    var seriesModel = data.hostModel;\n    var oldData = this._data;\n    var SymbolCtor = this._symbolCtor;\n\n    var seriesScope = makeSeriesScope(data);\n\n    // There is no oldLineData only when first rendering or switching from\n    // stream mode to normal mode, where previous elements should be removed.\n    if (!oldData) {\n        group.removeAll();\n    }\n\n    data.diff(oldData)\n        .add(function (newIdx) {\n            var point = data.getItemLayout(newIdx);\n            if (symbolNeedsDraw(data, point, newIdx, opt)) {\n                var symbolEl = new SymbolCtor(data, newIdx, seriesScope);\n                symbolEl.attr('position', point);\n                data.setItemGraphicEl(newIdx, symbolEl);\n                group.add(symbolEl);\n            }\n        })\n        .update(function (newIdx, oldIdx) {\n            var symbolEl = oldData.getItemGraphicEl(oldIdx);\n            var point = data.getItemLayout(newIdx);\n            if (!symbolNeedsDraw(data, point, newIdx, opt)) {\n                group.remove(symbolEl);\n                return;\n            }\n            if (!symbolEl) {\n                symbolEl = new SymbolCtor(data, newIdx);\n                symbolEl.attr('position', point);\n            }\n            else {\n                symbolEl.updateData(data, newIdx, seriesScope);\n                updateProps(symbolEl, {\n                    position: point\n                }, seriesModel);\n            }\n\n            // Add back\n            group.add(symbolEl);\n\n            data.setItemGraphicEl(newIdx, symbolEl);\n        })\n        .remove(function (oldIdx) {\n            var el = oldData.getItemGraphicEl(oldIdx);\n            el && el.fadeOut(function () {\n                group.remove(el);\n            });\n        })\n        .execute();\n\n    this._data = data;\n};\n\nsymbolDrawProto.isPersistent = function () {\n    return true;\n};\n\nsymbolDrawProto.updateLayout = function () {\n    var data = this._data;\n    if (data) {\n        // Not use animation\n        data.eachItemGraphicEl(function (el, idx) {\n            var point = data.getItemLayout(idx);\n            el.attr('position', point);\n        });\n    }\n};\n\nsymbolDrawProto.incrementalPrepareUpdate = function (data) {\n    this._seriesScope = makeSeriesScope(data);\n    this._data = null;\n    this.group.removeAll();\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n * @param {Object} [opt] Or isIgnore\n * @param {Function} [opt.isIgnore]\n * @param {Object} [opt.clipShape]\n */\nsymbolDrawProto.incrementalUpdate = function (taskParams, data, opt) {\n    opt = normalizeUpdateOpt(opt);\n\n    function updateIncrementalAndHover(el) {\n        if (!el.isGroup) {\n            el.incremental = el.useHoverLayer = true;\n        }\n    }\n    for (var idx = taskParams.start; idx < taskParams.end; idx++) {\n        var point = data.getItemLayout(idx);\n        if (symbolNeedsDraw(data, point, idx, opt)) {\n            var el = new this._symbolCtor(data, idx, this._seriesScope);\n            el.traverse(updateIncrementalAndHover);\n            el.attr('position', point);\n            this.group.add(el);\n            data.setItemGraphicEl(idx, el);\n        }\n    }\n};\n\nfunction normalizeUpdateOpt(opt) {\n    if (opt != null && !isObject$1(opt)) {\n        opt = {isIgnore: opt};\n    }\n    return opt || {};\n}\n\nsymbolDrawProto.remove = function (enableAnimation) {\n    var group = this.group;\n    var data = this._data;\n    // Incremental model do not have this._data.\n    if (data && enableAnimation) {\n        data.eachItemGraphicEl(function (el) {\n            el.fadeOut(function () {\n                group.remove(el);\n            });\n        });\n    }\n    else {\n        group.removeAll();\n    }\n};\n\nfunction makeSeriesScope(data) {\n    var seriesModel = data.hostModel;\n    return {\n        itemStyle: seriesModel.getModel('itemStyle').getItemStyle(['color']),\n        hoverItemStyle: seriesModel.getModel('emphasis.itemStyle').getItemStyle(),\n        symbolRotate: seriesModel.get('symbolRotate'),\n        symbolOffset: seriesModel.get('symbolOffset'),\n        hoverAnimation: seriesModel.get('hoverAnimation'),\n        labelModel: seriesModel.getModel('label'),\n        hoverLabelModel: seriesModel.getModel('emphasis.label'),\n        cursorStyle: seriesModel.get('cursor')\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} coordSys\n * @param {module:echarts/data/List} data\n * @param {string} valueOrigin lineSeries.option.areaStyle.origin\n */\nfunction prepareDataCoordInfo(coordSys, data, valueOrigin) {\n    var baseAxis = coordSys.getBaseAxis();\n    var valueAxis = coordSys.getOtherAxis(baseAxis);\n    var valueStart = getValueStart(valueAxis, valueOrigin);\n\n    var baseAxisDim = baseAxis.dim;\n    var valueAxisDim = valueAxis.dim;\n    var valueDim = data.mapDimension(valueAxisDim);\n    var baseDim = data.mapDimension(baseAxisDim);\n    var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0;\n\n    var dims = map(coordSys.dimensions, function (coordDim) {\n        return data.mapDimension(coordDim);\n    });\n\n    var stacked;\n    var stackResultDim = data.getCalculationInfo('stackResultDimension');\n    if (stacked |= isDimensionStacked(data, dims[0] /*, dims[1]*/)) { // jshint ignore:line\n        dims[0] = stackResultDim;\n    }\n    if (stacked |= isDimensionStacked(data, dims[1] /*, dims[0]*/)) { // jshint ignore:line\n        dims[1] = stackResultDim;\n    }\n\n    return {\n        dataDimsForPoint: dims,\n        valueStart: valueStart,\n        valueAxisDim: valueAxisDim,\n        baseAxisDim: baseAxisDim,\n        stacked: !!stacked,\n        valueDim: valueDim,\n        baseDim: baseDim,\n        baseDataOffset: baseDataOffset,\n        stackedOverDimension: data.getCalculationInfo('stackedOverDimension')\n    };\n}\n\nfunction getValueStart(valueAxis, valueOrigin) {\n    var valueStart = 0;\n    var extent = valueAxis.scale.getExtent();\n\n    if (valueOrigin === 'start') {\n        valueStart = extent[0];\n    }\n    else if (valueOrigin === 'end') {\n        valueStart = extent[1];\n    }\n    // auto\n    else {\n        // Both positive\n        if (extent[0] > 0) {\n            valueStart = extent[0];\n        }\n        // Both negative\n        else if (extent[1] < 0) {\n            valueStart = extent[1];\n        }\n        // If is one positive, and one negative, onZero shall be true\n    }\n\n    return valueStart;\n}\n\nfunction getStackedOnPoint(dataCoordInfo, coordSys, data, idx) {\n    var value = NaN;\n    if (dataCoordInfo.stacked) {\n        value = data.get(data.getCalculationInfo('stackedOverDimension'), idx);\n    }\n    if (isNaN(value)) {\n        value = dataCoordInfo.valueStart;\n    }\n\n    var baseDataOffset = dataCoordInfo.baseDataOffset;\n    var stackedData = [];\n    stackedData[baseDataOffset] = data.get(dataCoordInfo.baseDim, idx);\n    stackedData[1 - baseDataOffset] = value;\n\n    return coordSys.dataToPoint(stackedData);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// var arrayDiff = require('zrender/src/core/arrayDiff');\n// 'zrender/src/core/arrayDiff' has been used before, but it did\n// not do well in performance when roam with fixed dataZoom window.\n\n// function convertToIntId(newIdList, oldIdList) {\n//     // Generate int id instead of string id.\n//     // Compare string maybe slow in score function of arrDiff\n\n//     // Assume id in idList are all unique\n//     var idIndicesMap = {};\n//     var idx = 0;\n//     for (var i = 0; i < newIdList.length; i++) {\n//         idIndicesMap[newIdList[i]] = idx;\n//         newIdList[i] = idx++;\n//     }\n//     for (var i = 0; i < oldIdList.length; i++) {\n//         var oldId = oldIdList[i];\n//         // Same with newIdList\n//         if (idIndicesMap[oldId]) {\n//             oldIdList[i] = idIndicesMap[oldId];\n//         }\n//         else {\n//             oldIdList[i] = idx++;\n//         }\n//     }\n// }\n\nfunction diffData(oldData, newData) {\n    var diffResult = [];\n\n    newData.diff(oldData)\n        .add(function (idx) {\n            diffResult.push({cmd: '+', idx: idx});\n        })\n        .update(function (newIdx, oldIdx) {\n            diffResult.push({cmd: '=', idx: oldIdx, idx1: newIdx});\n        })\n        .remove(function (idx) {\n            diffResult.push({cmd: '-', idx: idx});\n        })\n        .execute();\n\n    return diffResult;\n}\n\nvar lineAnimationDiff = function (\n    oldData, newData,\n    oldStackedOnPoints, newStackedOnPoints,\n    oldCoordSys, newCoordSys,\n    oldValueOrigin, newValueOrigin\n) {\n    var diff = diffData(oldData, newData);\n\n    // var newIdList = newData.mapArray(newData.getId);\n    // var oldIdList = oldData.mapArray(oldData.getId);\n\n    // convertToIntId(newIdList, oldIdList);\n\n    // // FIXME One data ?\n    // diff = arrayDiff(oldIdList, newIdList);\n\n    var currPoints = [];\n    var nextPoints = [];\n    // Points for stacking base line\n    var currStackedPoints = [];\n    var nextStackedPoints = [];\n\n    var status = [];\n    var sortedIndices = [];\n    var rawIndices = [];\n\n    var newDataOldCoordInfo = prepareDataCoordInfo(oldCoordSys, newData, oldValueOrigin);\n    var oldDataNewCoordInfo = prepareDataCoordInfo(newCoordSys, oldData, newValueOrigin);\n\n    for (var i = 0; i < diff.length; i++) {\n        var diffItem = diff[i];\n        var pointAdded = true;\n\n        // FIXME, animation is not so perfect when dataZoom window moves fast\n        // Which is in case remvoing or add more than one data in the tail or head\n        switch (diffItem.cmd) {\n            case '=':\n                var currentPt = oldData.getItemLayout(diffItem.idx);\n                var nextPt = newData.getItemLayout(diffItem.idx1);\n                // If previous data is NaN, use next point directly\n                if (isNaN(currentPt[0]) || isNaN(currentPt[1])) {\n                    currentPt = nextPt.slice();\n                }\n                currPoints.push(currentPt);\n                nextPoints.push(nextPt);\n\n                currStackedPoints.push(oldStackedOnPoints[diffItem.idx]);\n                nextStackedPoints.push(newStackedOnPoints[diffItem.idx1]);\n\n                rawIndices.push(newData.getRawIndex(diffItem.idx1));\n                break;\n            case '+':\n                var idx = diffItem.idx;\n                currPoints.push(\n                    oldCoordSys.dataToPoint([\n                        newData.get(newDataOldCoordInfo.dataDimsForPoint[0], idx),\n                        newData.get(newDataOldCoordInfo.dataDimsForPoint[1], idx)\n                    ])\n                );\n\n                nextPoints.push(newData.getItemLayout(idx).slice());\n\n                currStackedPoints.push(\n                    getStackedOnPoint(newDataOldCoordInfo, oldCoordSys, newData, idx)\n                );\n                nextStackedPoints.push(newStackedOnPoints[idx]);\n\n                rawIndices.push(newData.getRawIndex(idx));\n                break;\n            case '-':\n                var idx = diffItem.idx;\n                var rawIndex = oldData.getRawIndex(idx);\n                // Data is replaced. In the case of dynamic data queue\n                // FIXME FIXME FIXME\n                if (rawIndex !== idx) {\n                    currPoints.push(oldData.getItemLayout(idx));\n                    nextPoints.push(newCoordSys.dataToPoint([\n                        oldData.get(oldDataNewCoordInfo.dataDimsForPoint[0], idx),\n                        oldData.get(oldDataNewCoordInfo.dataDimsForPoint[1], idx)\n                    ]));\n\n                    currStackedPoints.push(oldStackedOnPoints[idx]);\n                    nextStackedPoints.push(\n                        getStackedOnPoint(oldDataNewCoordInfo, newCoordSys, oldData, idx)\n                    );\n\n                    rawIndices.push(rawIndex);\n                }\n                else {\n                    pointAdded = false;\n                }\n        }\n\n        // Original indices\n        if (pointAdded) {\n            status.push(diffItem);\n            sortedIndices.push(sortedIndices.length);\n        }\n    }\n\n    // Diff result may be crossed if all items are changed\n    // Sort by data index\n    sortedIndices.sort(function (a, b) {\n        return rawIndices[a] - rawIndices[b];\n    });\n\n    var sortedCurrPoints = [];\n    var sortedNextPoints = [];\n\n    var sortedCurrStackedPoints = [];\n    var sortedNextStackedPoints = [];\n\n    var sortedStatus = [];\n    for (var i = 0; i < sortedIndices.length; i++) {\n        var idx = sortedIndices[i];\n        sortedCurrPoints[i] = currPoints[idx];\n        sortedNextPoints[i] = nextPoints[idx];\n\n        sortedCurrStackedPoints[i] = currStackedPoints[idx];\n        sortedNextStackedPoints[i] = nextStackedPoints[idx];\n\n        sortedStatus[i] = status[idx];\n    }\n\n    return {\n        current: sortedCurrPoints,\n        next: sortedNextPoints,\n\n        stackedOnCurrent: sortedCurrStackedPoints,\n        stackedOnNext: sortedNextStackedPoints,\n\n        status: sortedStatus\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Poly path support NaN point\n\nvar vec2Min = min;\nvar vec2Max = max;\n\nvar scaleAndAdd$1 = scaleAndAdd;\nvar v2Copy = copy;\n\n// Temporary variable\nvar v = [];\nvar cp0 = [];\nvar cp1 = [];\n\nfunction isPointNull(p) {\n    return isNaN(p[0]) || isNaN(p[1]);\n}\n\nfunction drawSegment(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    // if (smoothMonotone == null) {\n    //     if (isMono(points, 'x')) {\n    //         return drawMono(ctx, points, start, segLen, allLen,\n    //             dir, smoothMin, smoothMax, smooth, 'x', connectNulls);\n    //     }\n    //     else if (isMono(points, 'y')) {\n    //         return drawMono(ctx, points, start, segLen, allLen,\n    //             dir, smoothMin, smoothMax, smooth, 'y', connectNulls);\n    //     }\n    //     else {\n    //         return drawNonMono.apply(this, arguments);\n    //     }\n    // }\n    // else if (smoothMonotone !== 'none' && isMono(points, smoothMonotone)) {\n    //     return drawMono.apply(this, arguments);\n    // }\n    // else {\n    //     return drawNonMono.apply(this, arguments);\n    // }\n    if (smoothMonotone === 'none' || !smoothMonotone) {\n        return drawNonMono.apply(this, arguments);\n    }\n    else {\n        return drawMono.apply(this, arguments);\n    }\n}\n\n/**\n * Check if points is in monotone.\n *\n * @param {number[][]} points         Array of points which is in [x, y] form\n * @param {string}     smoothMonotone 'x', 'y', or 'none', stating for which\n *                                    dimension that is checking.\n *                                    If is 'none', `drawNonMono` should be\n *                                    called.\n *                                    If is undefined, either being monotone\n *                                    in 'x' or 'y' will call `drawMono`.\n */\n// function isMono(points, smoothMonotone) {\n//     if (points.length <= 1) {\n//         return true;\n//     }\n\n//     var dim = smoothMonotone === 'x' ? 0 : 1;\n//     var last = points[0][dim];\n//     var lastDiff = 0;\n//     for (var i = 1; i < points.length; ++i) {\n//         var diff = points[i][dim] - last;\n//         if (!isNaN(diff) && !isNaN(lastDiff)\n//             && diff !== 0 && lastDiff !== 0\n//             && ((diff >= 0) !== (lastDiff >= 0))\n//         ) {\n//             return false;\n//         }\n//         if (!isNaN(diff) && diff !== 0) {\n//             lastDiff = diff;\n//             last = points[i][dim];\n//         }\n//     }\n//     return true;\n// }\n\n/**\n * Draw smoothed line in monotone, in which only vertical or horizontal bezier\n * control points will be used. This should be used when points are monotone\n * either in x or y dimension.\n */\nfunction drawMono(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    var prevIdx = 0;\n    var idx = start;\n    for (var k = 0; k < segLen; k++) {\n        var p = points[idx];\n        if (idx >= allLen || idx < 0) {\n            break;\n        }\n        if (isPointNull(p)) {\n            if (connectNulls) {\n                idx += dir;\n                continue;\n            }\n            break;\n        }\n\n        if (idx === start) {\n            ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);\n        }\n        else {\n            if (smooth > 0) {\n                var prevP = points[prevIdx];\n                var dim = smoothMonotone === 'y' ? 1 : 0;\n\n                // Length of control point to p, either in x or y, but not both\n                var ctrlLen = (p[dim] - prevP[dim]) * smooth;\n\n                v2Copy(cp0, prevP);\n                cp0[dim] = prevP[dim] + ctrlLen;\n\n                v2Copy(cp1, p);\n                cp1[dim] = p[dim] - ctrlLen;\n\n                ctx.bezierCurveTo(\n                    cp0[0], cp0[1],\n                    cp1[0], cp1[1],\n                    p[0], p[1]\n                );\n            }\n            else {\n                ctx.lineTo(p[0], p[1]);\n            }\n        }\n\n        prevIdx = idx;\n        idx += dir;\n    }\n\n    return k;\n}\n\n/**\n * Draw smoothed line in non-monotone, in may cause undesired curve in extreme\n * situations. This should be used when points are non-monotone neither in x or\n * y dimension.\n */\nfunction drawNonMono(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    var prevIdx = 0;\n    var idx = start;\n    for (var k = 0; k < segLen; k++) {\n        var p = points[idx];\n        if (idx >= allLen || idx < 0) {\n            break;\n        }\n        if (isPointNull(p)) {\n            if (connectNulls) {\n                idx += dir;\n                continue;\n            }\n            break;\n        }\n\n        if (idx === start) {\n            ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);\n            v2Copy(cp0, p);\n        }\n        else {\n            if (smooth > 0) {\n                var nextIdx = idx + dir;\n                var nextP = points[nextIdx];\n                if (connectNulls) {\n                    // Find next point not null\n                    while (nextP && isPointNull(points[nextIdx])) {\n                        nextIdx += dir;\n                        nextP = points[nextIdx];\n                    }\n                }\n\n                var ratioNextSeg = 0.5;\n                var prevP = points[prevIdx];\n                var nextP = points[nextIdx];\n                // Last point\n                if (!nextP || isPointNull(nextP)) {\n                    v2Copy(cp1, p);\n                }\n                else {\n                    // If next data is null in not connect case\n                    if (isPointNull(nextP) && !connectNulls) {\n                        nextP = p;\n                    }\n\n                    sub(v, nextP, prevP);\n\n                    var lenPrevSeg;\n                    var lenNextSeg;\n                    if (smoothMonotone === 'x' || smoothMonotone === 'y') {\n                        var dim = smoothMonotone === 'x' ? 0 : 1;\n                        lenPrevSeg = Math.abs(p[dim] - prevP[dim]);\n                        lenNextSeg = Math.abs(p[dim] - nextP[dim]);\n                    }\n                    else {\n                        lenPrevSeg = dist(p, prevP);\n                        lenNextSeg = dist(p, nextP);\n                    }\n\n                    // Use ratio of seg length\n                    ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg);\n\n                    scaleAndAdd$1(cp1, p, v, -smooth * (1 - ratioNextSeg));\n                }\n                // Smooth constraint\n                vec2Min(cp0, cp0, smoothMax);\n                vec2Max(cp0, cp0, smoothMin);\n                vec2Min(cp1, cp1, smoothMax);\n                vec2Max(cp1, cp1, smoothMin);\n\n                ctx.bezierCurveTo(\n                    cp0[0], cp0[1],\n                    cp1[0], cp1[1],\n                    p[0], p[1]\n                );\n                // cp0 of next segment\n                scaleAndAdd$1(cp0, p, v, smooth * ratioNextSeg);\n            }\n            else {\n                ctx.lineTo(p[0], p[1]);\n            }\n        }\n\n        prevIdx = idx;\n        idx += dir;\n    }\n\n    return k;\n}\n\nfunction getBoundingBox(points, smoothConstraint) {\n    var ptMin = [Infinity, Infinity];\n    var ptMax = [-Infinity, -Infinity];\n    if (smoothConstraint) {\n        for (var i = 0; i < points.length; i++) {\n            var pt = points[i];\n            if (pt[0] < ptMin[0]) {\n                ptMin[0] = pt[0];\n            }\n            if (pt[1] < ptMin[1]) {\n                ptMin[1] = pt[1];\n            }\n            if (pt[0] > ptMax[0]) {\n                ptMax[0] = pt[0];\n            }\n            if (pt[1] > ptMax[1]) {\n                ptMax[1] = pt[1];\n            }\n        }\n    }\n    return {\n        min: smoothConstraint ? ptMin : ptMax,\n        max: smoothConstraint ? ptMax : ptMin\n    };\n}\n\nvar Polyline$1 = Path.extend({\n\n    type: 'ec-polyline',\n\n    shape: {\n        points: [],\n\n        smooth: 0,\n\n        smoothConstraint: true,\n\n        smoothMonotone: null,\n\n        connectNulls: false\n    },\n\n    style: {\n        fill: null,\n\n        stroke: '#000'\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n        var points = shape.points;\n\n        var i = 0;\n        var len$$1 = points.length;\n\n        var result = getBoundingBox(points, shape.smoothConstraint);\n\n        if (shape.connectNulls) {\n            // Must remove first and last null values avoid draw error in polygon\n            for (; len$$1 > 0; len$$1--) {\n                if (!isPointNull(points[len$$1 - 1])) {\n                    break;\n                }\n            }\n            for (; i < len$$1; i++) {\n                if (!isPointNull(points[i])) {\n                    break;\n                }\n            }\n        }\n        while (i < len$$1) {\n            i += drawSegment(\n                ctx, points, i, len$$1, len$$1,\n                1, result.min, result.max, shape.smooth,\n                shape.smoothMonotone, shape.connectNulls\n            ) + 1;\n        }\n    }\n});\n\nvar Polygon$1 = Path.extend({\n\n    type: 'ec-polygon',\n\n    shape: {\n        points: [],\n\n        // Offset between stacked base points and points\n        stackedOnPoints: [],\n\n        smooth: 0,\n\n        stackedOnSmooth: 0,\n\n        smoothConstraint: true,\n\n        smoothMonotone: null,\n\n        connectNulls: false\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n        var points = shape.points;\n        var stackedOnPoints = shape.stackedOnPoints;\n\n        var i = 0;\n        var len$$1 = points.length;\n        var smoothMonotone = shape.smoothMonotone;\n        var bbox = getBoundingBox(points, shape.smoothConstraint);\n        var stackedOnBBox = getBoundingBox(stackedOnPoints, shape.smoothConstraint);\n\n        if (shape.connectNulls) {\n            // Must remove first and last null values avoid draw error in polygon\n            for (; len$$1 > 0; len$$1--) {\n                if (!isPointNull(points[len$$1 - 1])) {\n                    break;\n                }\n            }\n            for (; i < len$$1; i++) {\n                if (!isPointNull(points[i])) {\n                    break;\n                }\n            }\n        }\n        while (i < len$$1) {\n            var k = drawSegment(\n                ctx, points, i, len$$1, len$$1,\n                1, bbox.min, bbox.max, shape.smooth,\n                smoothMonotone, shape.connectNulls\n            );\n            drawSegment(\n                ctx, stackedOnPoints, i + k - 1, k, len$$1,\n                -1, stackedOnBBox.min, stackedOnBBox.max, shape.stackedOnSmooth,\n                smoothMonotone, shape.connectNulls\n            );\n            i += k + 1;\n\n            ctx.closePath();\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME step not support polar\n\nfunction isPointsSame(points1, points2) {\n    if (points1.length !== points2.length) {\n        return;\n    }\n    for (var i = 0; i < points1.length; i++) {\n        var p1 = points1[i];\n        var p2 = points2[i];\n        if (p1[0] !== p2[0] || p1[1] !== p2[1]) {\n            return;\n        }\n    }\n    return true;\n}\n\nfunction getSmooth(smooth) {\n    return typeof (smooth) === 'number' ? smooth : (smooth ? 0.5 : 0);\n}\n\nfunction getAxisExtentWithGap(axis) {\n    var extent = axis.getGlobalExtent();\n    if (axis.onBand) {\n        // Remove extra 1px to avoid line miter in clipped edge\n        var halfBandWidth = axis.getBandWidth() / 2 - 1;\n        var dir = extent[1] > extent[0] ? 1 : -1;\n        extent[0] += dir * halfBandWidth;\n        extent[1] -= dir * halfBandWidth;\n    }\n    return extent;\n}\n\n/**\n * @param {module:echarts/coord/cartesian/Cartesian2D|module:echarts/coord/polar/Polar} coordSys\n * @param {module:echarts/data/List} data\n * @param {Object} dataCoordInfo\n * @param {Array.<Array.<number>>} points\n */\nfunction getStackedOnPoints(coordSys, data, dataCoordInfo) {\n    if (!dataCoordInfo.valueDim) {\n        return [];\n    }\n\n    var points = [];\n    for (var idx = 0, len = data.count(); idx < len; idx++) {\n        points.push(getStackedOnPoint(dataCoordInfo, coordSys, data, idx));\n    }\n\n    return points;\n}\n\nfunction createGridClipShape(cartesian, hasAnimation, forSymbol, seriesModel) {\n    var xExtent = getAxisExtentWithGap(cartesian.getAxis('x'));\n    var yExtent = getAxisExtentWithGap(cartesian.getAxis('y'));\n    var isHorizontal = cartesian.getBaseAxis().isHorizontal();\n\n    var x = Math.min(xExtent[0], xExtent[1]);\n    var y = Math.min(yExtent[0], yExtent[1]);\n    var width = Math.max(xExtent[0], xExtent[1]) - x;\n    var height = Math.max(yExtent[0], yExtent[1]) - y;\n\n    // Avoid float number rounding error for symbol on the edge of axis extent.\n    // See #7913 and `test/dataZoom-clip.html`.\n    if (forSymbol) {\n        x -= 0.5;\n        width += 0.5;\n        y -= 0.5;\n        height += 0.5;\n    }\n    else {\n        var lineWidth = seriesModel.get('lineStyle.width') || 2;\n        // Expand clip shape to avoid clipping when line value exceeds axis\n        var expandSize = seriesModel.get('clipOverflow') ? lineWidth / 2 : Math.max(width, height);\n        if (isHorizontal) {\n            y -= expandSize;\n            height += expandSize * 2;\n        }\n        else {\n            x -= expandSize;\n            width += expandSize * 2;\n        }\n    }\n\n    var clipPath = new Rect({\n        shape: {\n            x: x,\n            y: y,\n            width: width,\n            height: height\n        }\n    });\n\n    if (hasAnimation) {\n        clipPath.shape[isHorizontal ? 'width' : 'height'] = 0;\n        initProps(clipPath, {\n            shape: {\n                width: width,\n                height: height\n            }\n        }, seriesModel);\n    }\n\n    return clipPath;\n}\n\nfunction createPolarClipShape(polar, hasAnimation, forSymbol, seriesModel) {\n    var angleAxis = polar.getAngleAxis();\n    var radiusAxis = polar.getRadiusAxis();\n\n    var radiusExtent = radiusAxis.getExtent().slice();\n    radiusExtent[0] > radiusExtent[1] && radiusExtent.reverse();\n    var angleExtent = angleAxis.getExtent();\n\n    var RADIAN = Math.PI / 180;\n\n    // Avoid float number rounding error for symbol on the edge of axis extent.\n    if (forSymbol) {\n        radiusExtent[0] -= 0.5;\n        radiusExtent[1] += 0.5;\n    }\n\n    var clipPath = new Sector({\n        shape: {\n            cx: round$2(polar.cx, 1),\n            cy: round$2(polar.cy, 1),\n            r0: round$2(radiusExtent[0], 1),\n            r: round$2(radiusExtent[1], 1),\n            startAngle: -angleExtent[0] * RADIAN,\n            endAngle: -angleExtent[1] * RADIAN,\n            clockwise: angleAxis.inverse\n        }\n    });\n\n    if (hasAnimation) {\n        clipPath.shape.endAngle = -angleExtent[0] * RADIAN;\n        initProps(clipPath, {\n            shape: {\n                endAngle: -angleExtent[1] * RADIAN\n            }\n        }, seriesModel);\n    }\n\n    return clipPath;\n}\n\nfunction createClipShape(coordSys, hasAnimation, forSymbol, seriesModel) {\n    return coordSys.type === 'polar'\n        ? createPolarClipShape(coordSys, hasAnimation, forSymbol, seriesModel)\n        : createGridClipShape(coordSys, hasAnimation, forSymbol, seriesModel);\n}\n\nfunction turnPointsIntoStep(points, coordSys, stepTurnAt) {\n    var baseAxis = coordSys.getBaseAxis();\n    var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1;\n\n    var stepPoints = [];\n    for (var i = 0; i < points.length - 1; i++) {\n        var nextPt = points[i + 1];\n        var pt = points[i];\n        stepPoints.push(pt);\n\n        var stepPt = [];\n        switch (stepTurnAt) {\n            case 'end':\n                stepPt[baseIndex] = nextPt[baseIndex];\n                stepPt[1 - baseIndex] = pt[1 - baseIndex];\n                // default is start\n                stepPoints.push(stepPt);\n                break;\n            case 'middle':\n                // default is start\n                var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2;\n                var stepPt2 = [];\n                stepPt[baseIndex] = stepPt2[baseIndex] = middle;\n                stepPt[1 - baseIndex] = pt[1 - baseIndex];\n                stepPt2[1 - baseIndex] = nextPt[1 - baseIndex];\n                stepPoints.push(stepPt);\n                stepPoints.push(stepPt2);\n                break;\n            default:\n                stepPt[baseIndex] = pt[baseIndex];\n                stepPt[1 - baseIndex] = nextPt[1 - baseIndex];\n                // default is start\n                stepPoints.push(stepPt);\n        }\n    }\n    // Last points\n    points[i] && stepPoints.push(points[i]);\n    return stepPoints;\n}\n\nfunction getVisualGradient(data, coordSys) {\n    var visualMetaList = data.getVisual('visualMeta');\n    if (!visualMetaList || !visualMetaList.length || !data.count()) {\n        // When data.count() is 0, gradient range can not be calculated.\n        return;\n    }\n\n    if (coordSys.type !== 'cartesian2d') {\n        if (__DEV__) {\n            console.warn('Visual map on line style is only supported on cartesian2d.');\n        }\n        return;\n    }\n\n    var coordDim;\n    var visualMeta;\n\n    for (var i = visualMetaList.length - 1; i >= 0; i--) {\n        var dimIndex = visualMetaList[i].dimension;\n        var dimName = data.dimensions[dimIndex];\n        var dimInfo = data.getDimensionInfo(dimName);\n        coordDim = dimInfo && dimInfo.coordDim;\n        // Can only be x or y\n        if (coordDim === 'x' || coordDim === 'y') {\n            visualMeta = visualMetaList[i];\n            break;\n        }\n    }\n\n    if (!visualMeta) {\n        if (__DEV__) {\n            console.warn('Visual map on line style only support x or y dimension.');\n        }\n        return;\n    }\n\n    // If the area to be rendered is bigger than area defined by LinearGradient,\n    // the canvas spec prescribes that the color of the first stop and the last\n    // stop should be used. But if two stops are added at offset 0, in effect\n    // browsers use the color of the second stop to render area outside\n    // LinearGradient. So we can only infinitesimally extend area defined in\n    // LinearGradient to render `outerColors`.\n\n    var axis = coordSys.getAxis(coordDim);\n\n    // dataToCoor mapping may not be linear, but must be monotonic.\n    var colorStops = map(visualMeta.stops, function (stop) {\n        return {\n            coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)),\n            color: stop.color\n        };\n    });\n    var stopLen = colorStops.length;\n    var outerColors = visualMeta.outerColors.slice();\n\n    if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) {\n        colorStops.reverse();\n        outerColors.reverse();\n    }\n\n    var tinyExtent = 10; // Arbitrary value: 10px\n    var minCoord = colorStops[0].coord - tinyExtent;\n    var maxCoord = colorStops[stopLen - 1].coord + tinyExtent;\n    var coordSpan = maxCoord - minCoord;\n\n    if (coordSpan < 1e-3) {\n        return 'transparent';\n    }\n\n    each$1(colorStops, function (stop) {\n        stop.offset = (stop.coord - minCoord) / coordSpan;\n    });\n    colorStops.push({\n        offset: stopLen ? colorStops[stopLen - 1].offset : 0.5,\n        color: outerColors[1] || 'transparent'\n    });\n    colorStops.unshift({ // notice colorStops.length have been changed.\n        offset: stopLen ? colorStops[0].offset : 0.5,\n        color: outerColors[0] || 'transparent'\n    });\n\n    // zrUtil.each(colorStops, function (colorStop) {\n    //     // Make sure each offset has rounded px to avoid not sharp edge\n    //     colorStop.offset = (Math.round(colorStop.offset * (end - start) + start) - start) / (end - start);\n    // });\n\n    var gradient = new LinearGradient(0, 0, 0, 0, colorStops, true);\n    gradient[coordDim] = minCoord;\n    gradient[coordDim + '2'] = maxCoord;\n\n    return gradient;\n}\n\nfunction getIsIgnoreFunc(seriesModel, data, coordSys) {\n    var showAllSymbol = seriesModel.get('showAllSymbol');\n    var isAuto = showAllSymbol === 'auto';\n\n    if (showAllSymbol && !isAuto) {\n        return;\n    }\n\n    var categoryAxis = coordSys.getAxesByScale('ordinal')[0];\n    if (!categoryAxis) {\n        return;\n    }\n\n    // Note that category label interval strategy might bring some weird effect\n    // in some scenario: users may wonder why some of the symbols are not\n    // displayed. So we show all symbols as possible as we can.\n    if (isAuto\n        // Simplify the logic, do not determine label overlap here.\n        && canShowAllSymbolForCategory(categoryAxis, data)\n    ) {\n        return;\n    }\n\n    // Otherwise follow the label interval strategy on category axis.\n    var categoryDataDim = data.mapDimension(categoryAxis.dim);\n    var labelMap = {};\n\n    each$1(categoryAxis.getViewLabels(), function (labelItem) {\n        labelMap[labelItem.tickValue] = 1;\n    });\n\n    return function (dataIndex) {\n        return !labelMap.hasOwnProperty(data.get(categoryDataDim, dataIndex));\n    };\n}\n\nfunction canShowAllSymbolForCategory(categoryAxis, data) {\n    // In mose cases, line is monotonous on category axis, and the label size\n    // is close with each other. So we check the symbol size and some of the\n    // label size alone with the category axis to estimate whether all symbol\n    // can be shown without overlap.\n    var axisExtent = categoryAxis.getExtent();\n    var availSize = Math.abs(axisExtent[1] - axisExtent[0]) / categoryAxis.scale.count();\n    isNaN(availSize) && (availSize = 0); // 0/0 is NaN.\n\n    // Sampling some points, max 5.\n    var dataLen = data.count();\n    var step = Math.max(1, Math.round(dataLen / 5));\n    for (var dataIndex = 0; dataIndex < dataLen; dataIndex += step) {\n        if (SymbolClz$1.getSymbolSize(\n                data, dataIndex\n            // Only for cartesian, where `isHorizontal` exists.\n            )[categoryAxis.isHorizontal() ? 1 : 0]\n            // Empirical number\n            * 1.5 > availSize\n        ) {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nChart.extend({\n\n    type: 'line',\n\n    init: function () {\n        var lineGroup = new Group();\n\n        var symbolDraw = new SymbolDraw();\n        this.group.add(symbolDraw.group);\n\n        this._symbolDraw = symbolDraw;\n        this._lineGroup = lineGroup;\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var group = this.group;\n        var data = seriesModel.getData();\n        var lineStyleModel = seriesModel.getModel('lineStyle');\n        var areaStyleModel = seriesModel.getModel('areaStyle');\n\n        var points = data.mapArray(data.getItemLayout);\n\n        var isCoordSysPolar = coordSys.type === 'polar';\n        var prevCoordSys = this._coordSys;\n\n        var symbolDraw = this._symbolDraw;\n        var polyline = this._polyline;\n        var polygon = this._polygon;\n\n        var lineGroup = this._lineGroup;\n\n        var hasAnimation = seriesModel.get('animation');\n\n        var isAreaChart = !areaStyleModel.isEmpty();\n\n        var valueOrigin = areaStyleModel.get('origin');\n        var dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin);\n\n        var stackedOnPoints = getStackedOnPoints(coordSys, data, dataCoordInfo);\n\n        var showSymbol = seriesModel.get('showSymbol');\n\n        var isIgnoreFunc = showSymbol && !isCoordSysPolar\n            && getIsIgnoreFunc(seriesModel, data, coordSys);\n\n        // Remove temporary symbols\n        var oldData = this._data;\n        oldData && oldData.eachItemGraphicEl(function (el, idx) {\n            if (el.__temp) {\n                group.remove(el);\n                oldData.setItemGraphicEl(idx, null);\n            }\n        });\n\n        // Remove previous created symbols if showSymbol changed to false\n        if (!showSymbol) {\n            symbolDraw.remove();\n        }\n\n        group.add(lineGroup);\n\n        // FIXME step not support polar\n        var step = !isCoordSysPolar && seriesModel.get('step');\n        // Initialization animation or coordinate system changed\n        if (\n            !(polyline && prevCoordSys.type === coordSys.type && step === this._step)\n        ) {\n            showSymbol && symbolDraw.updateData(data, {\n                isIgnore: isIgnoreFunc,\n                clipShape: createClipShape(coordSys, false, true, seriesModel)\n            });\n\n            if (step) {\n                // TODO If stacked series is not step\n                points = turnPointsIntoStep(points, coordSys, step);\n                stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);\n            }\n\n            polyline = this._newPolyline(points, coordSys, hasAnimation);\n            if (isAreaChart) {\n                polygon = this._newPolygon(\n                    points, stackedOnPoints,\n                    coordSys, hasAnimation\n                );\n            }\n            lineGroup.setClipPath(createClipShape(coordSys, true, false, seriesModel));\n        }\n        else {\n            if (isAreaChart && !polygon) {\n                // If areaStyle is added\n                polygon = this._newPolygon(\n                    points, stackedOnPoints,\n                    coordSys, hasAnimation\n                );\n            }\n            else if (polygon && !isAreaChart) {\n                // If areaStyle is removed\n                lineGroup.remove(polygon);\n                polygon = this._polygon = null;\n            }\n\n            // Update clipPath\n            lineGroup.setClipPath(createClipShape(coordSys, false, false, seriesModel));\n\n            // Always update, or it is wrong in the case turning on legend\n            // because points are not changed\n            showSymbol && symbolDraw.updateData(data, {\n                isIgnore: isIgnoreFunc,\n                clipShape: createClipShape(coordSys, false, true, seriesModel)\n            });\n\n            // Stop symbol animation and sync with line points\n            // FIXME performance?\n            data.eachItemGraphicEl(function (el) {\n                el.stopAnimation(true);\n            });\n\n            // In the case data zoom triggerred refreshing frequently\n            // Data may not change if line has a category axis. So it should animate nothing\n            if (!isPointsSame(this._stackedOnPoints, stackedOnPoints)\n                || !isPointsSame(this._points, points)\n            ) {\n                if (hasAnimation) {\n                    this._updateAnimation(\n                        data, stackedOnPoints, coordSys, api, step, valueOrigin\n                    );\n                }\n                else {\n                    // Not do it in update with animation\n                    if (step) {\n                        // TODO If stacked series is not step\n                        points = turnPointsIntoStep(points, coordSys, step);\n                        stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);\n                    }\n\n                    polyline.setShape({\n                        points: points\n                    });\n                    polygon && polygon.setShape({\n                        points: points,\n                        stackedOnPoints: stackedOnPoints\n                    });\n                }\n            }\n        }\n\n        var visualColor = getVisualGradient(data, coordSys) || data.getVisual('color');\n\n        polyline.useStyle(defaults(\n            // Use color in lineStyle first\n            lineStyleModel.getLineStyle(),\n            {\n                fill: 'none',\n                stroke: visualColor,\n                lineJoin: 'bevel'\n            }\n        ));\n\n        var smooth = seriesModel.get('smooth');\n        smooth = getSmooth(seriesModel.get('smooth'));\n        polyline.setShape({\n            smooth: smooth,\n            smoothMonotone: seriesModel.get('smoothMonotone'),\n            connectNulls: seriesModel.get('connectNulls')\n        });\n\n        if (polygon) {\n            var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');\n            var stackedOnSmooth = 0;\n\n            polygon.useStyle(defaults(\n                areaStyleModel.getAreaStyle(),\n                {\n                    fill: visualColor,\n                    opacity: 0.7,\n                    lineJoin: 'bevel'\n                }\n            ));\n\n            if (stackedOnSeries) {\n                stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth'));\n            }\n\n            polygon.setShape({\n                smooth: smooth,\n                stackedOnSmooth: stackedOnSmooth,\n                smoothMonotone: seriesModel.get('smoothMonotone'),\n                connectNulls: seriesModel.get('connectNulls')\n            });\n        }\n\n        this._data = data;\n        // Save the coordinate system for transition animation when data changed\n        this._coordSys = coordSys;\n        this._stackedOnPoints = stackedOnPoints;\n        this._points = points;\n        this._step = step;\n        this._valueOrigin = valueOrigin;\n    },\n\n    dispose: function () {},\n\n    highlight: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n        var dataIndex = queryDataIndex(data, payload);\n\n        if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) {\n            var symbol = data.getItemGraphicEl(dataIndex);\n            if (!symbol) {\n                // Create a temporary symbol if it is not exists\n                var pt = data.getItemLayout(dataIndex);\n                if (!pt) {\n                    // Null data\n                    return;\n                }\n                symbol = new SymbolClz$1(data, dataIndex);\n                symbol.position = pt;\n                symbol.setZ(\n                    seriesModel.get('zlevel'),\n                    seriesModel.get('z')\n                );\n                symbol.ignore = isNaN(pt[0]) || isNaN(pt[1]);\n                symbol.__temp = true;\n                data.setItemGraphicEl(dataIndex, symbol);\n\n                // Stop scale animation\n                symbol.stopSymbolAnimation(true);\n\n                this.group.add(symbol);\n            }\n            symbol.highlight();\n        }\n        else {\n            // Highlight whole series\n            Chart.prototype.highlight.call(\n                this, seriesModel, ecModel, api, payload\n            );\n        }\n    },\n\n    downplay: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n        var dataIndex = queryDataIndex(data, payload);\n        if (dataIndex != null && dataIndex >= 0) {\n            var symbol = data.getItemGraphicEl(dataIndex);\n            if (symbol) {\n                if (symbol.__temp) {\n                    data.setItemGraphicEl(dataIndex, null);\n                    this.group.remove(symbol);\n                }\n                else {\n                    symbol.downplay();\n                }\n            }\n        }\n        else {\n            // FIXME\n            // can not downplay completely.\n            // Downplay whole series\n            Chart.prototype.downplay.call(\n                this, seriesModel, ecModel, api, payload\n            );\n        }\n    },\n\n    /**\n     * @param {module:zrender/container/Group} group\n     * @param {Array.<Array.<number>>} points\n     * @private\n     */\n    _newPolyline: function (points) {\n        var polyline = this._polyline;\n        // Remove previous created polyline\n        if (polyline) {\n            this._lineGroup.remove(polyline);\n        }\n\n        polyline = new Polyline$1({\n            shape: {\n                points: points\n            },\n            silent: true,\n            z2: 10\n        });\n\n        this._lineGroup.add(polyline);\n\n        this._polyline = polyline;\n\n        return polyline;\n    },\n\n    /**\n     * @param {module:zrender/container/Group} group\n     * @param {Array.<Array.<number>>} stackedOnPoints\n     * @param {Array.<Array.<number>>} points\n     * @private\n     */\n    _newPolygon: function (points, stackedOnPoints) {\n        var polygon = this._polygon;\n        // Remove previous created polygon\n        if (polygon) {\n            this._lineGroup.remove(polygon);\n        }\n\n        polygon = new Polygon$1({\n            shape: {\n                points: points,\n                stackedOnPoints: stackedOnPoints\n            },\n            silent: true\n        });\n\n        this._lineGroup.add(polygon);\n\n        this._polygon = polygon;\n        return polygon;\n    },\n\n    /**\n     * @private\n     */\n    // FIXME Two value axis\n    _updateAnimation: function (data, stackedOnPoints, coordSys, api, step, valueOrigin) {\n        var polyline = this._polyline;\n        var polygon = this._polygon;\n        var seriesModel = data.hostModel;\n\n        var diff = lineAnimationDiff(\n            this._data, data,\n            this._stackedOnPoints, stackedOnPoints,\n            this._coordSys, coordSys,\n            this._valueOrigin, valueOrigin\n        );\n\n        var current = diff.current;\n        var stackedOnCurrent = diff.stackedOnCurrent;\n        var next = diff.next;\n        var stackedOnNext = diff.stackedOnNext;\n        if (step) {\n            // TODO If stacked series is not step\n            current = turnPointsIntoStep(diff.current, coordSys, step);\n            stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step);\n            next = turnPointsIntoStep(diff.next, coordSys, step);\n            stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step);\n        }\n        // `diff.current` is subset of `current` (which should be ensured by\n        // turnPointsIntoStep), so points in `__points` can be updated when\n        // points in `current` are update during animation.\n        polyline.shape.__points = diff.current;\n        polyline.shape.points = current;\n\n        updateProps(polyline, {\n            shape: {\n                points: next\n            }\n        }, seriesModel);\n\n        if (polygon) {\n            polygon.setShape({\n                points: current,\n                stackedOnPoints: stackedOnCurrent\n            });\n            updateProps(polygon, {\n                shape: {\n                    points: next,\n                    stackedOnPoints: stackedOnNext\n                }\n            }, seriesModel);\n        }\n\n        var updatedDataInfo = [];\n        var diffStatus = diff.status;\n\n        for (var i = 0; i < diffStatus.length; i++) {\n            var cmd = diffStatus[i].cmd;\n            if (cmd === '=') {\n                var el = data.getItemGraphicEl(diffStatus[i].idx1);\n                if (el) {\n                    updatedDataInfo.push({\n                        el: el,\n                        ptIdx: i    // Index of points\n                    });\n                }\n            }\n        }\n\n        if (polyline.animators && polyline.animators.length) {\n            polyline.animators[0].during(function () {\n                for (var i = 0; i < updatedDataInfo.length; i++) {\n                    var el = updatedDataInfo[i].el;\n                    el.attr('position', polyline.shape.__points[updatedDataInfo[i].ptIdx]);\n                }\n            });\n        }\n    },\n\n    remove: function (ecModel) {\n        var group = this.group;\n        var oldData = this._data;\n        this._lineGroup.removeAll();\n        this._symbolDraw.remove(true);\n        // Remove temporary created elements when highlighting\n        oldData && oldData.eachItemGraphicEl(function (el, idx) {\n            if (el.__temp) {\n                group.remove(el);\n                oldData.setItemGraphicEl(idx, null);\n            }\n        });\n\n        this._polyline\n            = this._polygon\n            = this._coordSys\n            = this._points\n            = this._stackedOnPoints\n            = this._data = null;\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar visualSymbol = function (seriesType, defaultSymbolType, legendSymbol) {\n    // Encoding visual for all series include which is filtered for legend drawing\n    return {\n        seriesType: seriesType,\n\n        // For legend.\n        performRawSeries: true,\n\n        reset: function (seriesModel, ecModel, api) {\n            var data = seriesModel.getData();\n\n            var symbolType = seriesModel.get('symbol') || defaultSymbolType;\n            var symbolSize = seriesModel.get('symbolSize');\n            var keepAspect = seriesModel.get('symbolKeepAspect');\n\n            data.setVisual({\n                legendSymbol: legendSymbol || symbolType,\n                symbol: symbolType,\n                symbolSize: symbolSize,\n                symbolKeepAspect: keepAspect\n            });\n\n            // Only visible series has each data be visual encoded\n            if (ecModel.isSeriesFiltered(seriesModel)) {\n                return;\n            }\n\n            var hasCallback = typeof symbolSize === 'function';\n\n            function dataEach(data, idx) {\n                if (typeof symbolSize === 'function') {\n                    var rawValue = seriesModel.getRawValue(idx);\n                    // FIXME\n                    var params = seriesModel.getDataParams(idx);\n                    data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params));\n                }\n\n                if (data.hasItemOption) {\n                    var itemModel = data.getItemModel(idx);\n                    var itemSymbolType = itemModel.getShallow('symbol', true);\n                    var itemSymbolSize = itemModel.getShallow('symbolSize',\n                        true);\n                    var itemSymbolKeepAspect\n                        = itemModel.getShallow('symbolKeepAspect', true);\n\n                    // If has item symbol\n                    if (itemSymbolType != null) {\n                        data.setItemVisual(idx, 'symbol', itemSymbolType);\n                    }\n                    if (itemSymbolSize != null) {\n                        // PENDING Transform symbolSize ?\n                        data.setItemVisual(idx, 'symbolSize', itemSymbolSize);\n                    }\n                    if (itemSymbolKeepAspect != null) {\n                        data.setItemVisual(idx, 'symbolKeepAspect',\n                            itemSymbolKeepAspect);\n                    }\n                }\n            }\n\n            return { dataEach: (data.hasItemOption || hasCallback) ? dataEach : null };\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar pointsLayout = function (seriesType) {\n    return {\n        seriesType: seriesType,\n\n        plan: createRenderPlanner(),\n\n        reset: function (seriesModel) {\n            var data = seriesModel.getData();\n            var coordSys = seriesModel.coordinateSystem;\n            var pipelineContext = seriesModel.pipelineContext;\n            var isLargeRender = pipelineContext.large;\n\n            if (!coordSys) {\n                return;\n            }\n\n            var dims = map(coordSys.dimensions, function (dim) {\n                return data.mapDimension(dim);\n            }).slice(0, 2);\n            var dimLen = dims.length;\n\n            var stackResultDim = data.getCalculationInfo('stackResultDimension');\n            if (isDimensionStacked(data, dims[0] /*, dims[1]*/)) {\n                dims[0] = stackResultDim;\n            }\n            if (isDimensionStacked(data, dims[1] /*, dims[0]*/)) {\n                dims[1] = stackResultDim;\n            }\n\n            function progress(params, data) {\n                var segCount = params.end - params.start;\n                var points = isLargeRender && new Float32Array(segCount * dimLen);\n\n                for (var i = params.start, offset = 0, tmpIn = [], tmpOut = []; i < params.end; i++) {\n                    var point;\n\n                    if (dimLen === 1) {\n                        var x = data.get(dims[0], i);\n                        point = !isNaN(x) && coordSys.dataToPoint(x, null, tmpOut);\n                    }\n                    else {\n                        var x = tmpIn[0] = data.get(dims[0], i);\n                        var y = tmpIn[1] = data.get(dims[1], i);\n                        // Also {Array.<number>}, not undefined to avoid if...else... statement\n                        point = !isNaN(x) && !isNaN(y) && coordSys.dataToPoint(tmpIn, null, tmpOut);\n                    }\n\n                    if (isLargeRender) {\n                        points[offset++] = point ? point[0] : NaN;\n                        points[offset++] = point ? point[1] : NaN;\n                    }\n                    else {\n                        data.setItemLayout(i, (point && point.slice()) || [NaN, NaN]);\n                    }\n                }\n\n                isLargeRender && data.setLayout('symbolPoints', points);\n            }\n\n            return dimLen && {progress: progress};\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar samplers = {\n    average: function (frame) {\n        var sum = 0;\n        var count = 0;\n        for (var i = 0; i < frame.length; i++) {\n            if (!isNaN(frame[i])) {\n                sum += frame[i];\n                count++;\n            }\n        }\n        // Return NaN if count is 0\n        return count === 0 ? NaN : sum / count;\n    },\n    sum: function (frame) {\n        var sum = 0;\n        for (var i = 0; i < frame.length; i++) {\n            // Ignore NaN\n            sum += frame[i] || 0;\n        }\n        return sum;\n    },\n    max: function (frame) {\n        var max = -Infinity;\n        for (var i = 0; i < frame.length; i++) {\n            frame[i] > max && (max = frame[i]);\n        }\n        // NaN will cause illegal axis extent.\n        return isFinite(max) ? max : NaN;\n    },\n    min: function (frame) {\n        var min = Infinity;\n        for (var i = 0; i < frame.length; i++) {\n            frame[i] < min && (min = frame[i]);\n        }\n        // NaN will cause illegal axis extent.\n        return isFinite(min) ? min : NaN;\n    },\n    // TODO\n    // Median\n    nearest: function (frame) {\n        return frame[0];\n    }\n};\n\nvar indexSampler = function (frame, value) {\n    return Math.round(frame.length / 2);\n};\n\nvar dataSample = function (seriesType) {\n    return {\n\n        seriesType: seriesType,\n\n        modifyOutputEnd: true,\n\n        reset: function (seriesModel, ecModel, api) {\n            var data = seriesModel.getData();\n            var sampling = seriesModel.get('sampling');\n            var coordSys = seriesModel.coordinateSystem;\n            // Only cartesian2d support down sampling\n            if (coordSys.type === 'cartesian2d' && sampling) {\n                var baseAxis = coordSys.getBaseAxis();\n                var valueAxis = coordSys.getOtherAxis(baseAxis);\n                var extent = baseAxis.getExtent();\n                // Coordinste system has been resized\n                var size = extent[1] - extent[0];\n                var rate = Math.round(data.count() / size);\n                if (rate > 1) {\n                    var sampler;\n                    if (typeof sampling === 'string') {\n                        sampler = samplers[sampling];\n                    }\n                    else if (typeof sampling === 'function') {\n                        sampler = sampling;\n                    }\n                    if (sampler) {\n                        // Only support sample the first dim mapped from value axis.\n                        seriesModel.setData(data.downSample(\n                            data.mapDimension(valueAxis.dim), 1 / rate, sampler, indexSampler\n                        ));\n                    }\n                }\n            }\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Cartesian coordinate system\n * @module  echarts/coord/Cartesian\n *\n */\n\nfunction dimAxisMapper(dim) {\n    return this._axes[dim];\n}\n\n/**\n * @alias module:echarts/coord/Cartesian\n * @constructor\n */\nvar Cartesian = function (name) {\n    this._axes = {};\n\n    this._dimList = [];\n\n    /**\n     * @type {string}\n     */\n    this.name = name || '';\n};\n\nCartesian.prototype = {\n\n    constructor: Cartesian,\n\n    type: 'cartesian',\n\n    /**\n     * Get axis\n     * @param  {number|string} dim\n     * @return {module:echarts/coord/Cartesian~Axis}\n     */\n    getAxis: function (dim) {\n        return this._axes[dim];\n    },\n\n    /**\n     * Get axes list\n     * @return {Array.<module:echarts/coord/Cartesian~Axis>}\n     */\n    getAxes: function () {\n        return map(this._dimList, dimAxisMapper, this);\n    },\n\n    /**\n     * Get axes list by given scale type\n     */\n    getAxesByScale: function (scaleType) {\n        scaleType = scaleType.toLowerCase();\n        return filter(\n            this.getAxes(),\n            function (axis) {\n                return axis.scale.type === scaleType;\n            }\n        );\n    },\n\n    /**\n     * Add axis\n     * @param {module:echarts/coord/Cartesian.Axis}\n     */\n    addAxis: function (axis) {\n        var dim = axis.dim;\n\n        this._axes[dim] = axis;\n\n        this._dimList.push(dim);\n    },\n\n    /**\n     * Convert data to coord in nd space\n     * @param {Array.<number>|Object.<string, number>} val\n     * @return {Array.<number>|Object.<string, number>}\n     */\n    dataToCoord: function (val) {\n        return this._dataCoordConvert(val, 'dataToCoord');\n    },\n\n    /**\n     * Convert coord in nd space to data\n     * @param  {Array.<number>|Object.<string, number>} val\n     * @return {Array.<number>|Object.<string, number>}\n     */\n    coordToData: function (val) {\n        return this._dataCoordConvert(val, 'coordToData');\n    },\n\n    _dataCoordConvert: function (input, method) {\n        var dimList = this._dimList;\n\n        var output = input instanceof Array ? [] : {};\n\n        for (var i = 0; i < dimList.length; i++) {\n            var dim = dimList[i];\n            var axis = this._axes[dim];\n\n            output[dim] = axis[method](input[dim]);\n        }\n\n        return output;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction Cartesian2D(name) {\n\n    Cartesian.call(this, name);\n}\n\nCartesian2D.prototype = {\n\n    constructor: Cartesian2D,\n\n    type: 'cartesian2d',\n\n    /**\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['x', 'y'],\n\n    /**\n     * Base axis will be used on stacking.\n     *\n     * @return {module:echarts/coord/cartesian/Axis2D}\n     */\n    getBaseAxis: function () {\n        return this.getAxesByScale('ordinal')[0]\n            || this.getAxesByScale('time')[0]\n            || this.getAxis('x');\n    },\n\n    /**\n     * If contain point\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    containPoint: function (point) {\n        var axisX = this.getAxis('x');\n        var axisY = this.getAxis('y');\n        return axisX.contain(axisX.toLocalCoord(point[0]))\n            && axisY.contain(axisY.toLocalCoord(point[1]));\n    },\n\n    /**\n     * If contain data\n     * @param {Array.<number>} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this.getAxis('x').containData(data[0])\n            && this.getAxis('y').containData(data[1]);\n    },\n\n    /**\n     * @param {Array.<number>} data\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, reserved, out) {\n        var xAxis = this.getAxis('x');\n        var yAxis = this.getAxis('y');\n        out = out || [];\n        out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(data[0]));\n        out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(data[1]));\n        return out;\n    },\n\n    /**\n     * @param {Array.<number>} data\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    clampData: function (data, out) {\n        var xScale = this.getAxis('x').scale;\n        var yScale = this.getAxis('y').scale;\n        var xAxisExtent = xScale.getExtent();\n        var yAxisExtent = yScale.getExtent();\n        var x = xScale.parse(data[0]);\n        var y = yScale.parse(data[1]);\n        out = out || [];\n        out[0] = Math.min(\n            Math.max(Math.min(xAxisExtent[0], xAxisExtent[1]), x),\n            Math.max(xAxisExtent[0], xAxisExtent[1])\n        );\n        out[1] = Math.min(\n            Math.max(Math.min(yAxisExtent[0], yAxisExtent[1]), y),\n            Math.max(yAxisExtent[0], yAxisExtent[1])\n        );\n\n        return out;\n    },\n\n    /**\n     * @param {Array.<number>} point\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    pointToData: function (point, out) {\n        var xAxis = this.getAxis('x');\n        var yAxis = this.getAxis('y');\n        out = out || [];\n        out[0] = xAxis.coordToData(xAxis.toLocalCoord(point[0]));\n        out[1] = yAxis.coordToData(yAxis.toLocalCoord(point[1]));\n        return out;\n    },\n\n    /**\n     * Get other axis\n     * @param {module:echarts/coord/cartesian/Axis2D} axis\n     */\n    getOtherAxis: function (axis) {\n        return this.getAxis(axis.dim === 'x' ? 'y' : 'x');\n    }\n\n};\n\ninherits(Cartesian2D, Cartesian);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Extend axis 2d\n * @constructor module:echarts/coord/cartesian/Axis2D\n * @extends {module:echarts/coord/cartesian/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n * @param {string} position\n */\nvar Axis2D = function (dim, scale, coordExtent, axisType, position) {\n    Axis.call(this, dim, scale, coordExtent);\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * Axis position\n     *  - 'top'\n     *  - 'bottom'\n     *  - 'left'\n     *  - 'right'\n     */\n    this.position = position || 'bottom';\n};\n\nAxis2D.prototype = {\n\n    constructor: Axis2D,\n\n    /**\n     * Index of axis, can be used as key\n     */\n    index: 0,\n\n    /**\n     * Implemented in <module:echarts/coord/cartesian/Grid>.\n     * @return {Array.<module:echarts/coord/cartesian/Axis2D>}\n     *         If not on zero of other axis, return null/undefined.\n     *         If no axes, return an empty array.\n     */\n    getAxesOnZeroOf: null,\n\n    /**\n     * Axis model\n     * @param {module:echarts/coord/cartesian/AxisModel}\n     */\n    model: null,\n\n    isHorizontal: function () {\n        var position = this.position;\n        return position === 'top' || position === 'bottom';\n    },\n\n    /**\n     * Each item cooresponds to this.getExtent(), which\n     * means globalExtent[0] may greater than globalExtent[1],\n     * unless `asc` is input.\n     *\n     * @param {boolean} [asc]\n     * @return {Array.<number>}\n     */\n    getGlobalExtent: function (asc) {\n        var ret = this.getExtent();\n        ret[0] = this.toGlobalCoord(ret[0]);\n        ret[1] = this.toGlobalCoord(ret[1]);\n        asc && ret[0] > ret[1] && ret.reverse();\n        return ret;\n    },\n\n    getOtherAxis: function () {\n        this.grid.getOtherAxis();\n    },\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.coordToData(this.toLocalCoord(point[this.dim === 'x' ? 0 : 1]), clamp);\n    },\n\n    /**\n     * Transform global coord to local coord,\n     * i.e. var localCoord = axis.toLocalCoord(80);\n     * designate by module:echarts/coord/cartesian/Grid.\n     * @type {Function}\n     */\n    toLocalCoord: null,\n\n    /**\n     * Transform global coord to local coord,\n     * i.e. var globalCoord = axis.toLocalCoord(40);\n     * designate by module:echarts/coord/cartesian/Grid.\n     * @type {Function}\n     */\n    toGlobalCoord: null\n\n};\n\ninherits(Axis2D, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar defaultOption = {\n    show: true,\n    zlevel: 0,\n    z: 0,\n    // Inverse the axis.\n    inverse: false,\n\n    // Axis name displayed.\n    name: '',\n    // 'start' | 'middle' | 'end'\n    nameLocation: 'end',\n    // By degree. By defualt auto rotate by nameLocation.\n    nameRotate: null,\n    nameTruncate: {\n        maxWidth: null,\n        ellipsis: '...',\n        placeholder: '.'\n    },\n    // Use global text style by default.\n    nameTextStyle: {},\n    // The gap between axisName and axisLine.\n    nameGap: 15,\n\n    // Default `false` to support tooltip.\n    silent: false,\n    // Default `false` to avoid legacy user event listener fail.\n    triggerEvent: false,\n\n    tooltip: {\n        show: false\n    },\n\n    axisPointer: {},\n\n    axisLine: {\n        show: true,\n        onZero: true,\n        onZeroAxisIndex: null,\n        lineStyle: {\n            color: '#333',\n            width: 1,\n            type: 'solid'\n        },\n        // The arrow at both ends the the axis.\n        symbol: ['none', 'none'],\n        symbolSize: [10, 15]\n    },\n    axisTick: {\n        show: true,\n        // Whether axisTick is inside the grid or outside the grid.\n        inside: false,\n        // The length of axisTick.\n        length: 5,\n        lineStyle: {\n            width: 1\n        }\n    },\n    axisLabel: {\n        show: true,\n        // Whether axisLabel is inside the grid or outside the grid.\n        inside: false,\n        rotate: 0,\n        // true | false | null/undefined (auto)\n        showMinLabel: null,\n        // true | false | null/undefined (auto)\n        showMaxLabel: null,\n        margin: 8,\n        // formatter: null,\n        fontSize: 12\n    },\n    splitLine: {\n        show: true,\n        lineStyle: {\n            color: ['#ccc'],\n            width: 1,\n            type: 'solid'\n        }\n    },\n    splitArea: {\n        show: false,\n        areaStyle: {\n            color: ['rgba(250,250,250,0.3)', 'rgba(200,200,200,0.3)']\n        }\n    }\n};\n\nvar axisDefault = {};\n\naxisDefault.categoryAxis = merge({\n    // The gap at both ends of the axis. For categoryAxis, boolean.\n    boundaryGap: true,\n    // Set false to faster category collection.\n    // Only usefull in the case like: category is\n    // ['2012-01-01', '2012-01-02', ...], where the input\n    // data has been ensured not duplicate and is large data.\n    // null means \"auto\":\n    // if axis.data provided, do not deduplication,\n    // else do deduplication.\n    deduplication: null,\n    // splitArea: {\n        // show: false\n    // },\n    splitLine: {\n        show: false\n    },\n    axisTick: {\n        // If tick is align with label when boundaryGap is true\n        alignWithLabel: false,\n        interval: 'auto'\n    },\n    axisLabel: {\n        interval: 'auto'\n    }\n}, defaultOption);\n\naxisDefault.valueAxis = merge({\n    // The gap at both ends of the axis. For value axis, [GAP, GAP], where\n    // `GAP` can be an absolute pixel number (like `35`), or percent (like `'30%'`)\n    boundaryGap: [0, 0],\n\n    // TODO\n    // min/max: [30, datamin, 60] or [20, datamin] or [datamin, 60]\n\n    // Min value of the axis. can be:\n    // + a number\n    // + 'dataMin': use the min value in data.\n    // + null/undefined: auto decide min value (consider pretty look and boundaryGap).\n    // min: null,\n\n    // Max value of the axis. can be:\n    // + a number\n    // + 'dataMax': use the max value in data.\n    // + null/undefined: auto decide max value (consider pretty look and boundaryGap).\n    // max: null,\n\n    // Readonly prop, specifies start value of the range when using data zoom.\n    // rangeStart: null\n\n    // Readonly prop, specifies end value of the range when using data zoom.\n    // rangeEnd: null\n\n    // Optional value can be:\n    // + `false`: always include value 0.\n    // + `true`: the extent do not consider value 0.\n    // scale: false,\n\n    // AxisTick and axisLabel and splitLine are caculated based on splitNumber.\n    splitNumber: 5\n\n    // Interval specifies the span of the ticks is mandatorily.\n    // interval: null\n\n    // Specify min interval when auto calculate tick interval.\n    // minInterval: null\n\n    // Specify max interval when auto calculate tick interval.\n    // maxInterval: null\n\n}, defaultOption);\n\naxisDefault.timeAxis = defaults({\n    scale: true,\n    min: 'dataMin',\n    max: 'dataMax'\n}, axisDefault.valueAxis);\n\naxisDefault.logAxis = defaults({\n    scale: true,\n    logBase: 10\n}, axisDefault.valueAxis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME axisType is fixed ?\nvar AXIS_TYPES = ['value', 'category', 'time', 'log'];\n\n/**\n * Generate sub axis model class\n * @param {string} axisName 'x' 'y' 'radius' 'angle' 'parallel'\n * @param {module:echarts/model/Component} BaseAxisModelClass\n * @param {Function} axisTypeDefaulter\n * @param {Object} [extraDefaultOption]\n */\nvar axisModelCreator = function (axisName, BaseAxisModelClass, axisTypeDefaulter, extraDefaultOption) {\n\n    each$1(AXIS_TYPES, function (axisType) {\n\n        BaseAxisModelClass.extend({\n\n            /**\n             * @readOnly\n             */\n            type: axisName + 'Axis.' + axisType,\n\n            mergeDefaultAndTheme: function (option, ecModel) {\n                var layoutMode = this.layoutMode;\n                var inputPositionParams = layoutMode\n                    ? getLayoutParams(option) : {};\n\n                var themeModel = ecModel.getTheme();\n                merge(option, themeModel.get(axisType + 'Axis'));\n                merge(option, this.getDefaultOption());\n\n                option.type = axisTypeDefaulter(axisName, option);\n\n                if (layoutMode) {\n                    mergeLayoutParam(option, inputPositionParams, layoutMode);\n                }\n            },\n\n            /**\n             * @override\n             */\n            optionUpdated: function () {\n                var thisOption = this.option;\n                if (thisOption.type === 'category') {\n                    this.__ordinalMeta = OrdinalMeta.createByAxisModel(this);\n                }\n            },\n\n            /**\n             * Should not be called before all of 'getInitailData' finished.\n             * Because categories are collected during initializing data.\n             */\n            getCategories: function (rawData) {\n                var option = this.option;\n                // FIXME\n                // warning if called before all of 'getInitailData' finished.\n                if (option.type === 'category') {\n                    if (rawData) {\n                        return option.data;\n                    }\n                    return this.__ordinalMeta.categories;\n                }\n            },\n\n            getOrdinalMeta: function () {\n                return this.__ordinalMeta;\n            },\n\n            defaultOption: mergeAll(\n                [\n                    {},\n                    axisDefault[axisType + 'Axis'],\n                    extraDefaultOption\n                ],\n                true\n            )\n        });\n    });\n\n    ComponentModel.registerSubTypeDefaulter(\n        axisName + 'Axis',\n        curry(axisTypeDefaulter, axisName)\n    );\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisModel = ComponentModel.extend({\n\n    type: 'cartesian2dAxis',\n\n    /**\n     * @type {module:echarts/coord/cartesian/Axis2D}\n     */\n    axis: null,\n\n    /**\n     * @override\n     */\n    init: function () {\n        AxisModel.superApply(this, 'init', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function () {\n        AxisModel.superApply(this, 'mergeOption', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     */\n    restoreData: function () {\n        AxisModel.superApply(this, 'restoreData', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     * @return {module:echarts/model/Component}\n     */\n    getCoordSysModel: function () {\n        return this.ecModel.queryComponents({\n            mainType: 'grid',\n            index: this.option.gridIndex,\n            id: this.option.gridId\n        })[0];\n    }\n\n});\n\nfunction getAxisType(axisDim, option) {\n    // Default axis with data is category axis\n    return option.type || (option.data ? 'category' : 'value');\n}\n\nmerge(AxisModel.prototype, axisModelCommonMixin);\n\nvar extraOption = {\n    // gridIndex: 0,\n    // gridId: '',\n\n    // Offset is for multiple axis on the same position\n    offset: 0\n};\n\naxisModelCreator('x', AxisModel, getAxisType, extraOption);\naxisModelCreator('y', AxisModel, getAxisType, extraOption);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Grid 是在有直角坐标系的时候必须要存在的\n// 所以这里也要被 Cartesian2D 依赖\n\nComponentModel.extend({\n\n    type: 'grid',\n\n    dependencies: ['xAxis', 'yAxis'],\n\n    layoutMode: 'box',\n\n    /**\n     * @type {module:echarts/coord/cartesian/Grid}\n     */\n    coordinateSystem: null,\n\n    defaultOption: {\n        show: false,\n        zlevel: 0,\n        z: 0,\n        left: '10%',\n        top: 60,\n        right: '10%',\n        bottom: 60,\n        // If grid size contain label\n        containLabel: false,\n        // width: {totalWidth} - left - right,\n        // height: {totalHeight} - top - bottom,\n        backgroundColor: 'rgba(0,0,0,0)',\n        borderWidth: 1,\n        borderColor: '#ccc'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Grid is a region which contains at most 4 cartesian systems\n *\n * TODO Default cartesian\n */\n\n// Depends on GridModel, AxisModel, which performs preprocess.\n/**\n * Check if the axis is used in the specified grid\n * @inner\n */\nfunction isAxisUsedInTheGrid(axisModel, gridModel, ecModel) {\n    return axisModel.getCoordSysModel() === gridModel;\n}\n\nfunction Grid(gridModel, ecModel, api) {\n    /**\n     * @type {Object.<string, module:echarts/coord/cartesian/Cartesian2D>}\n     * @private\n     */\n    this._coordsMap = {};\n\n    /**\n     * @type {Array.<module:echarts/coord/cartesian/Cartesian>}\n     * @private\n     */\n    this._coordsList = [];\n\n    /**\n     * @type {Object.<string, module:echarts/coord/cartesian/Axis2D>}\n     * @private\n     */\n    this._axesMap = {};\n\n    /**\n     * @type {Array.<module:echarts/coord/cartesian/Axis2D>}\n     * @private\n     */\n    this._axesList = [];\n\n    this._initCartesian(gridModel, ecModel, api);\n\n    this.model = gridModel;\n}\n\nvar gridProto = Grid.prototype;\n\ngridProto.type = 'grid';\n\ngridProto.axisPointerEnabled = true;\n\ngridProto.getRect = function () {\n    return this._rect;\n};\n\ngridProto.update = function (ecModel, api) {\n\n    var axesMap = this._axesMap;\n\n    this._updateScale(ecModel, this.model);\n\n    each$1(axesMap.x, function (xAxis) {\n        niceScaleExtent(xAxis.scale, xAxis.model);\n    });\n    each$1(axesMap.y, function (yAxis) {\n        niceScaleExtent(yAxis.scale, yAxis.model);\n    });\n\n    // Key: axisDim_axisIndex, value: boolean, whether onZero target.\n    var onZeroRecords = {};\n\n    each$1(axesMap.x, function (xAxis) {\n        fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords);\n    });\n    each$1(axesMap.y, function (yAxis) {\n        fixAxisOnZero(axesMap, 'x', yAxis, onZeroRecords);\n    });\n\n    // Resize again if containLabel is enabled\n    // FIXME It may cause getting wrong grid size in data processing stage\n    this.resize(this.model, api);\n};\n\nfunction fixAxisOnZero(axesMap, otherAxisDim, axis, onZeroRecords) {\n\n    axis.getAxesOnZeroOf = function () {\n        // TODO: onZero of multiple axes.\n        return otherAxisOnZeroOf ? [otherAxisOnZeroOf] : [];\n    };\n\n    // onZero can not be enabled in these two situations:\n    // 1. When any other axis is a category axis.\n    // 2. When no axis is cross 0 point.\n    var otherAxes = axesMap[otherAxisDim];\n\n    var otherAxisOnZeroOf;\n    var axisModel = axis.model;\n    var onZero = axisModel.get('axisLine.onZero');\n    var onZeroAxisIndex = axisModel.get('axisLine.onZeroAxisIndex');\n\n    if (!onZero) {\n        return;\n    }\n\n    // If target axis is specified.\n    if (onZeroAxisIndex != null) {\n        if (canOnZeroToAxis(otherAxes[onZeroAxisIndex])) {\n            otherAxisOnZeroOf = otherAxes[onZeroAxisIndex];\n        }\n    }\n    else {\n        // Find the first available other axis.\n        for (var idx in otherAxes) {\n            if (otherAxes.hasOwnProperty(idx)\n                && canOnZeroToAxis(otherAxes[idx])\n                // Consider that two Y axes on one value axis,\n                // if both onZero, the two Y axes overlap.\n                && !onZeroRecords[getOnZeroRecordKey(otherAxes[idx])]\n            ) {\n                otherAxisOnZeroOf = otherAxes[idx];\n                break;\n            }\n        }\n    }\n\n    if (otherAxisOnZeroOf) {\n        onZeroRecords[getOnZeroRecordKey(otherAxisOnZeroOf)] = true;\n    }\n\n    function getOnZeroRecordKey(axis) {\n        return axis.dim + '_' + axis.index;\n    }\n}\n\nfunction canOnZeroToAxis(axis) {\n    return axis && axis.type !== 'category' && axis.type !== 'time' && ifAxisCrossZero(axis);\n}\n\n/**\n * Resize the grid\n * @param {module:echarts/coord/cartesian/GridModel} gridModel\n * @param {module:echarts/ExtensionAPI} api\n */\ngridProto.resize = function (gridModel, api, ignoreContainLabel) {\n\n    var gridRect = getLayoutRect(\n        gridModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        });\n\n    this._rect = gridRect;\n\n    var axesList = this._axesList;\n\n    adjustAxes();\n\n    // Minus label size\n    if (!ignoreContainLabel && gridModel.get('containLabel')) {\n        each$1(axesList, function (axis) {\n            if (!axis.model.get('axisLabel.inside')) {\n                var labelUnionRect = estimateLabelUnionRect(axis);\n                if (labelUnionRect) {\n                    var dim = axis.isHorizontal() ? 'height' : 'width';\n                    var margin = axis.model.get('axisLabel.margin');\n                    gridRect[dim] -= labelUnionRect[dim] + margin;\n                    if (axis.position === 'top') {\n                        gridRect.y += labelUnionRect.height + margin;\n                    }\n                    else if (axis.position === 'left') {\n                        gridRect.x += labelUnionRect.width + margin;\n                    }\n                }\n            }\n        });\n\n        adjustAxes();\n    }\n\n    function adjustAxes() {\n        each$1(axesList, function (axis) {\n            var isHorizontal = axis.isHorizontal();\n            var extent = isHorizontal ? [0, gridRect.width] : [0, gridRect.height];\n            var idx = axis.inverse ? 1 : 0;\n            axis.setExtent(extent[idx], extent[1 - idx]);\n            updateAxisTransform(axis, isHorizontal ? gridRect.x : gridRect.y);\n        });\n    }\n};\n\n/**\n * @param {string} axisType\n * @param {number} [axisIndex]\n */\ngridProto.getAxis = function (axisType, axisIndex) {\n    var axesMapOnDim = this._axesMap[axisType];\n    if (axesMapOnDim != null) {\n        if (axisIndex == null) {\n            // Find first axis\n            for (var name in axesMapOnDim) {\n                if (axesMapOnDim.hasOwnProperty(name)) {\n                    return axesMapOnDim[name];\n                }\n            }\n        }\n        return axesMapOnDim[axisIndex];\n    }\n};\n\n/**\n * @return {Array.<module:echarts/coord/Axis>}\n */\ngridProto.getAxes = function () {\n    return this._axesList.slice();\n};\n\n/**\n * Usage:\n *      grid.getCartesian(xAxisIndex, yAxisIndex);\n *      grid.getCartesian(xAxisIndex);\n *      grid.getCartesian(null, yAxisIndex);\n *      grid.getCartesian({xAxisIndex: ..., yAxisIndex: ...});\n *\n * @param {number|Object} [xAxisIndex]\n * @param {number} [yAxisIndex]\n */\ngridProto.getCartesian = function (xAxisIndex, yAxisIndex) {\n    if (xAxisIndex != null && yAxisIndex != null) {\n        var key = 'x' + xAxisIndex + 'y' + yAxisIndex;\n        return this._coordsMap[key];\n    }\n\n    if (isObject$1(xAxisIndex)) {\n        yAxisIndex = xAxisIndex.yAxisIndex;\n        xAxisIndex = xAxisIndex.xAxisIndex;\n    }\n    // When only xAxisIndex or yAxisIndex given, find its first cartesian.\n    for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) {\n        if (coordList[i].getAxis('x').index === xAxisIndex\n            || coordList[i].getAxis('y').index === yAxisIndex\n        ) {\n            return coordList[i];\n        }\n    }\n};\n\ngridProto.getCartesians = function () {\n    return this._coordsList.slice();\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.convertToPixel = function (ecModel, finder, value) {\n    var target = this._findConvertTarget(ecModel, finder);\n\n    return target.cartesian\n        ? target.cartesian.dataToPoint(value)\n        : target.axis\n        ? target.axis.toGlobalCoord(target.axis.dataToCoord(value))\n        : null;\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.convertFromPixel = function (ecModel, finder, value) {\n    var target = this._findConvertTarget(ecModel, finder);\n\n    return target.cartesian\n        ? target.cartesian.pointToData(value)\n        : target.axis\n        ? target.axis.coordToData(target.axis.toLocalCoord(value))\n        : null;\n};\n\n/**\n * @inner\n */\ngridProto._findConvertTarget = function (ecModel, finder) {\n    var seriesModel = finder.seriesModel;\n    var xAxisModel = finder.xAxisModel\n        || (seriesModel && seriesModel.getReferringComponents('xAxis')[0]);\n    var yAxisModel = finder.yAxisModel\n        || (seriesModel && seriesModel.getReferringComponents('yAxis')[0]);\n    var gridModel = finder.gridModel;\n    var coordsList = this._coordsList;\n    var cartesian;\n    var axis;\n\n    if (seriesModel) {\n        cartesian = seriesModel.coordinateSystem;\n        indexOf(coordsList, cartesian) < 0 && (cartesian = null);\n    }\n    else if (xAxisModel && yAxisModel) {\n        cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);\n    }\n    else if (xAxisModel) {\n        axis = this.getAxis('x', xAxisModel.componentIndex);\n    }\n    else if (yAxisModel) {\n        axis = this.getAxis('y', yAxisModel.componentIndex);\n    }\n    // Lowest priority.\n    else if (gridModel) {\n        var grid = gridModel.coordinateSystem;\n        if (grid === this) {\n            cartesian = this._coordsList[0];\n        }\n    }\n\n    return {cartesian: cartesian, axis: axis};\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.containPoint = function (point) {\n    var coord = this._coordsList[0];\n    if (coord) {\n        return coord.containPoint(point);\n    }\n};\n\n/**\n * Initialize cartesian coordinate systems\n * @private\n */\ngridProto._initCartesian = function (gridModel, ecModel, api) {\n    var axisPositionUsed = {\n        left: false,\n        right: false,\n        top: false,\n        bottom: false\n    };\n\n    var axesMap = {\n        x: {},\n        y: {}\n    };\n    var axesCount = {\n        x: 0,\n        y: 0\n    };\n\n    /// Create axis\n    ecModel.eachComponent('xAxis', createAxisCreator('x'), this);\n    ecModel.eachComponent('yAxis', createAxisCreator('y'), this);\n\n    if (!axesCount.x || !axesCount.y) {\n        // Roll back when there no either x or y axis\n        this._axesMap = {};\n        this._axesList = [];\n        return;\n    }\n\n    this._axesMap = axesMap;\n\n    /// Create cartesian2d\n    each$1(axesMap.x, function (xAxis, xAxisIndex) {\n        each$1(axesMap.y, function (yAxis, yAxisIndex) {\n            var key = 'x' + xAxisIndex + 'y' + yAxisIndex;\n            var cartesian = new Cartesian2D(key);\n\n            cartesian.grid = this;\n            cartesian.model = gridModel;\n\n            this._coordsMap[key] = cartesian;\n            this._coordsList.push(cartesian);\n\n            cartesian.addAxis(xAxis);\n            cartesian.addAxis(yAxis);\n        }, this);\n    }, this);\n\n    function createAxisCreator(axisType) {\n        return function (axisModel, idx) {\n            if (!isAxisUsedInTheGrid(axisModel, gridModel, ecModel)) {\n                return;\n            }\n\n            var axisPosition = axisModel.get('position');\n            if (axisType === 'x') {\n                // Fix position\n                if (axisPosition !== 'top' && axisPosition !== 'bottom') {\n                    // Default bottom of X\n                    axisPosition = 'bottom';\n                    if (axisPositionUsed[axisPosition]) {\n                        axisPosition = axisPosition === 'top' ? 'bottom' : 'top';\n                    }\n                }\n            }\n            else {\n                // Fix position\n                if (axisPosition !== 'left' && axisPosition !== 'right') {\n                    // Default left of Y\n                    axisPosition = 'left';\n                    if (axisPositionUsed[axisPosition]) {\n                        axisPosition = axisPosition === 'left' ? 'right' : 'left';\n                    }\n                }\n            }\n            axisPositionUsed[axisPosition] = true;\n\n            var axis = new Axis2D(\n                axisType, createScaleByModel(axisModel),\n                [0, 0],\n                axisModel.get('type'),\n                axisPosition\n            );\n\n            var isCategory = axis.type === 'category';\n            axis.onBand = isCategory && axisModel.get('boundaryGap');\n            axis.inverse = axisModel.get('inverse');\n\n            // Inject axis into axisModel\n            axisModel.axis = axis;\n\n            // Inject axisModel into axis\n            axis.model = axisModel;\n\n            // Inject grid info axis\n            axis.grid = this;\n\n            // Index of axis, can be used as key\n            axis.index = idx;\n\n            this._axesList.push(axis);\n\n            axesMap[axisType][idx] = axis;\n            axesCount[axisType]++;\n        };\n    }\n};\n\n/**\n * Update cartesian properties from series\n * @param  {module:echarts/model/Option} option\n * @private\n */\ngridProto._updateScale = function (ecModel, gridModel) {\n    // Reset scale\n    each$1(this._axesList, function (axis) {\n        axis.scale.setExtent(Infinity, -Infinity);\n    });\n    ecModel.eachSeries(function (seriesModel) {\n        if (isCartesian2D(seriesModel)) {\n            var axesModels = findAxesModels(seriesModel, ecModel);\n            var xAxisModel = axesModels[0];\n            var yAxisModel = axesModels[1];\n\n            if (!isAxisUsedInTheGrid(xAxisModel, gridModel, ecModel)\n                || !isAxisUsedInTheGrid(yAxisModel, gridModel, ecModel)\n            ) {\n                return;\n            }\n\n            var cartesian = this.getCartesian(\n                xAxisModel.componentIndex, yAxisModel.componentIndex\n            );\n            var data = seriesModel.getData();\n            var xAxis = cartesian.getAxis('x');\n            var yAxis = cartesian.getAxis('y');\n\n            if (data.type === 'list') {\n                unionExtent(data, xAxis, seriesModel);\n                unionExtent(data, yAxis, seriesModel);\n            }\n        }\n    }, this);\n\n    function unionExtent(data, axis, seriesModel) {\n        each$1(data.mapDimension(axis.dim, true), function (dim) {\n            axis.scale.unionExtentFromData(\n                // For example, the extent of the orginal dimension\n                // is [0.1, 0.5], the extent of the `stackResultDimension`\n                // is [7, 9], the final extent should not include [0.1, 0.5].\n                data, getStackedDimension(data, dim)\n            );\n        });\n    }\n};\n\n/**\n * @param {string} [dim] 'x' or 'y' or 'auto' or null/undefined\n * @return {Object} {baseAxes: [], otherAxes: []}\n */\ngridProto.getTooltipAxes = function (dim) {\n    var baseAxes = [];\n    var otherAxes = [];\n\n    each$1(this.getCartesians(), function (cartesian) {\n        var baseAxis = (dim != null && dim !== 'auto')\n            ? cartesian.getAxis(dim) : cartesian.getBaseAxis();\n        var otherAxis = cartesian.getOtherAxis(baseAxis);\n        indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis);\n        indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis);\n    });\n\n    return {baseAxes: baseAxes, otherAxes: otherAxes};\n};\n\n/**\n * @inner\n */\nfunction updateAxisTransform(axis, coordBase) {\n    var axisExtent = axis.getExtent();\n    var axisExtentSum = axisExtent[0] + axisExtent[1];\n\n    // Fast transform\n    axis.toGlobalCoord = axis.dim === 'x'\n        ? function (coord) {\n            return coord + coordBase;\n        }\n        : function (coord) {\n            return axisExtentSum - coord + coordBase;\n        };\n    axis.toLocalCoord = axis.dim === 'x'\n        ? function (coord) {\n            return coord - coordBase;\n        }\n        : function (coord) {\n            return axisExtentSum - coord + coordBase;\n        };\n}\n\nvar axesTypes = ['xAxis', 'yAxis'];\n/**\n * @inner\n */\nfunction findAxesModels(seriesModel, ecModel) {\n    return map(axesTypes, function (axisType) {\n        var axisModel = seriesModel.getReferringComponents(axisType)[0];\n\n        if (__DEV__) {\n            if (!axisModel) {\n                throw new Error(axisType + ' \"' + retrieve(\n                    seriesModel.get(axisType + 'Index'),\n                    seriesModel.get(axisType + 'Id'),\n                    0\n                ) + '\" not found');\n            }\n        }\n        return axisModel;\n    });\n}\n\n/**\n * @inner\n */\nfunction isCartesian2D(seriesModel) {\n    return seriesModel.get('coordinateSystem') === 'cartesian2d';\n}\n\nGrid.create = function (ecModel, api) {\n    var grids = [];\n    ecModel.eachComponent('grid', function (gridModel, idx) {\n        var grid = new Grid(gridModel, ecModel, api);\n        grid.name = 'grid_' + idx;\n        // dataSampling requires axis extent, so resize\n        // should be performed in create stage.\n        grid.resize(gridModel, api, true);\n\n        gridModel.coordinateSystem = grid;\n\n        grids.push(grid);\n    });\n\n    // Inject the coordinateSystems into seriesModel\n    ecModel.eachSeries(function (seriesModel) {\n        if (!isCartesian2D(seriesModel)) {\n            return;\n        }\n\n        var axesModels = findAxesModels(seriesModel, ecModel);\n        var xAxisModel = axesModels[0];\n        var yAxisModel = axesModels[1];\n\n        var gridModel = xAxisModel.getCoordSysModel();\n\n        if (__DEV__) {\n            if (!gridModel) {\n                throw new Error(\n                    'Grid \"' + retrieve(\n                        xAxisModel.get('gridIndex'),\n                        xAxisModel.get('gridId'),\n                        0\n                    ) + '\" not found'\n                );\n            }\n            if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) {\n                throw new Error('xAxis and yAxis must use the same grid');\n            }\n        }\n\n        var grid = gridModel.coordinateSystem;\n\n        seriesModel.coordinateSystem = grid.getCartesian(\n            xAxisModel.componentIndex, yAxisModel.componentIndex\n        );\n    });\n\n    return grids;\n};\n\n// For deciding which dimensions to use when creating list data\nGrid.dimensions = Grid.prototype.dimensions = Cartesian2D.prototype.dimensions;\n\nCoordinateSystemManager.register('cartesian2d', Grid);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PI$2 = Math.PI;\n\nfunction makeAxisEventDataBase(axisModel) {\n    var eventData = {\n        componentType: axisModel.mainType,\n        componentIndex: axisModel.componentIndex\n    };\n    eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex;\n    return eventData;\n}\n\n/**\n * A final axis is translated and rotated from a \"standard axis\".\n * So opt.position and opt.rotation is required.\n *\n * A standard axis is and axis from [0, 0] to [0, axisExtent[1]],\n * for example: (0, 0) ------------> (0, 50)\n *\n * nameDirection or tickDirection or labelDirection is 1 means tick\n * or label is below the standard axis, whereas is -1 means above\n * the standard axis. labelOffset means offset between label and axis,\n * which is useful when 'onZero', where axisLabel is in the grid and\n * label in outside grid.\n *\n * Tips: like always,\n * positive rotation represents anticlockwise, and negative rotation\n * represents clockwise.\n * The direction of position coordinate is the same as the direction\n * of screen coordinate.\n *\n * Do not need to consider axis 'inverse', which is auto processed by\n * axis extent.\n *\n * @param {module:zrender/container/Group} group\n * @param {Object} axisModel\n * @param {Object} opt Standard axis parameters.\n * @param {Array.<number>} opt.position [x, y]\n * @param {number} opt.rotation by radian\n * @param {number} [opt.nameDirection=1] 1 or -1 Used when nameLocation is 'middle' or 'center'.\n * @param {number} [opt.tickDirection=1] 1 or -1\n * @param {number} [opt.labelDirection=1] 1 or -1\n * @param {number} [opt.labelOffset=0] Usefull when onZero.\n * @param {string} [opt.axisLabelShow] default get from axisModel.\n * @param {string} [opt.axisName] default get from axisModel.\n * @param {number} [opt.axisNameAvailableWidth]\n * @param {number} [opt.labelRotate] by degree, default get from axisModel.\n * @param {number} [opt.strokeContainThreshold] Default label interval when label\n * @param {number} [opt.nameTruncateMaxWidth]\n */\nvar AxisBuilder = function (axisModel, opt) {\n\n    /**\n     * @readOnly\n     */\n    this.opt = opt;\n\n    /**\n     * @readOnly\n     */\n    this.axisModel = axisModel;\n\n    // Default value\n    defaults(\n        opt,\n        {\n            labelOffset: 0,\n            nameDirection: 1,\n            tickDirection: 1,\n            labelDirection: 1,\n            silent: true\n        }\n    );\n\n    /**\n     * @readOnly\n     */\n    this.group = new Group();\n\n    // FIXME Not use a seperate text group?\n    var dumbGroup = new Group({\n        position: opt.position.slice(),\n        rotation: opt.rotation\n    });\n\n    // this.group.add(dumbGroup);\n    // this._dumbGroup = dumbGroup;\n\n    dumbGroup.updateTransform();\n    this._transform = dumbGroup.transform;\n\n    this._dumbGroup = dumbGroup;\n};\n\nAxisBuilder.prototype = {\n\n    constructor: AxisBuilder,\n\n    hasBuilder: function (name) {\n        return !!builders[name];\n    },\n\n    add: function (name) {\n        builders[name].call(this);\n    },\n\n    getGroup: function () {\n        return this.group;\n    }\n\n};\n\nvar builders = {\n\n    /**\n     * @private\n     */\n    axisLine: function () {\n        var opt = this.opt;\n        var axisModel = this.axisModel;\n\n        if (!axisModel.get('axisLine.show')) {\n            return;\n        }\n\n        var extent = this.axisModel.axis.getExtent();\n\n        var matrix = this._transform;\n        var pt1 = [extent[0], 0];\n        var pt2 = [extent[1], 0];\n        if (matrix) {\n            applyTransform(pt1, pt1, matrix);\n            applyTransform(pt2, pt2, matrix);\n        }\n\n        var lineStyle = extend(\n            {\n                lineCap: 'round'\n            },\n            axisModel.getModel('axisLine.lineStyle').getLineStyle()\n        );\n\n        this.group.add(new Line(subPixelOptimizeLine({\n            // Id for animation\n            anid: 'line',\n\n            shape: {\n                x1: pt1[0],\n                y1: pt1[1],\n                x2: pt2[0],\n                y2: pt2[1]\n            },\n            style: lineStyle,\n            strokeContainThreshold: opt.strokeContainThreshold || 5,\n            silent: true,\n            z2: 1\n        })));\n\n        var arrows = axisModel.get('axisLine.symbol');\n        var arrowSize = axisModel.get('axisLine.symbolSize');\n\n        var arrowOffset = axisModel.get('axisLine.symbolOffset') || 0;\n        if (typeof arrowOffset === 'number') {\n            arrowOffset = [arrowOffset, arrowOffset];\n        }\n\n        if (arrows != null) {\n            if (typeof arrows === 'string') {\n                // Use the same arrow for start and end point\n                arrows = [arrows, arrows];\n            }\n            if (typeof arrowSize === 'string'\n                || typeof arrowSize === 'number'\n            ) {\n                // Use the same size for width and height\n                arrowSize = [arrowSize, arrowSize];\n            }\n\n            var symbolWidth = arrowSize[0];\n            var symbolHeight = arrowSize[1];\n\n            each$1([{\n                rotate: opt.rotation + Math.PI / 2,\n                offset: arrowOffset[0],\n                r: 0\n            }, {\n                rotate: opt.rotation - Math.PI / 2,\n                offset: arrowOffset[1],\n                r: Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0])\n                    + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1]))\n            }], function (point, index) {\n                if (arrows[index] !== 'none' && arrows[index] != null) {\n                    var symbol = createSymbol(\n                        arrows[index],\n                        -symbolWidth / 2,\n                        -symbolHeight / 2,\n                        symbolWidth,\n                        symbolHeight,\n                        lineStyle.stroke,\n                        true\n                    );\n\n                    // Calculate arrow position with offset\n                    var r = point.r + point.offset;\n                    var pos = [\n                        pt1[0] + r * Math.cos(opt.rotation),\n                        pt1[1] - r * Math.sin(opt.rotation)\n                    ];\n\n                    symbol.attr({\n                        rotation: point.rotate,\n                        position: pos,\n                        silent: true,\n                        z2: 11\n                    });\n                    this.group.add(symbol);\n                }\n            }, this);\n        }\n    },\n\n    /**\n     * @private\n     */\n    axisTickLabel: function () {\n        var axisModel = this.axisModel;\n        var opt = this.opt;\n\n        var tickEls = buildAxisTick(this, axisModel, opt);\n        var labelEls = buildAxisLabel(this, axisModel, opt);\n\n        fixMinMaxLabelShow(axisModel, labelEls, tickEls);\n    },\n\n    /**\n     * @private\n     */\n    axisName: function () {\n        var opt = this.opt;\n        var axisModel = this.axisModel;\n        var name = retrieve(opt.axisName, axisModel.get('name'));\n\n        if (!name) {\n            return;\n        }\n\n        var nameLocation = axisModel.get('nameLocation');\n        var nameDirection = opt.nameDirection;\n        var textStyleModel = axisModel.getModel('nameTextStyle');\n        var gap = axisModel.get('nameGap') || 0;\n\n        var extent = this.axisModel.axis.getExtent();\n        var gapSignal = extent[0] > extent[1] ? -1 : 1;\n        var pos = [\n            nameLocation === 'start'\n                ? extent[0] - gapSignal * gap\n                : nameLocation === 'end'\n                ? extent[1] + gapSignal * gap\n                : (extent[0] + extent[1]) / 2, // 'middle'\n            // Reuse labelOffset.\n            isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * gap : 0\n        ];\n\n        var labelLayout;\n\n        var nameRotation = axisModel.get('nameRotate');\n        if (nameRotation != null) {\n            nameRotation = nameRotation * PI$2 / 180; // To radian.\n        }\n\n        var axisNameAvailableWidth;\n\n        if (isNameLocationCenter(nameLocation)) {\n            labelLayout = innerTextLayout(\n                opt.rotation,\n                nameRotation != null ? nameRotation : opt.rotation, // Adapt to axis.\n                nameDirection\n            );\n        }\n        else {\n            labelLayout = endTextLayout(\n                opt, nameLocation, nameRotation || 0, extent\n            );\n\n            axisNameAvailableWidth = opt.axisNameAvailableWidth;\n            if (axisNameAvailableWidth != null) {\n                axisNameAvailableWidth = Math.abs(\n                    axisNameAvailableWidth / Math.sin(labelLayout.rotation)\n                );\n                !isFinite(axisNameAvailableWidth) && (axisNameAvailableWidth = null);\n            }\n        }\n\n        var textFont = textStyleModel.getFont();\n\n        var truncateOpt = axisModel.get('nameTruncate', true) || {};\n        var ellipsis = truncateOpt.ellipsis;\n        var maxWidth = retrieve(\n            opt.nameTruncateMaxWidth, truncateOpt.maxWidth, axisNameAvailableWidth\n        );\n        // FIXME\n        // truncate rich text? (consider performance)\n        var truncatedText = (ellipsis != null && maxWidth != null)\n            ? truncateText$1(\n                name, maxWidth, textFont, ellipsis,\n                {minChar: 2, placeholder: truncateOpt.placeholder}\n            )\n            : name;\n\n        var tooltipOpt = axisModel.get('tooltip', true);\n\n        var mainType = axisModel.mainType;\n        var formatterParams = {\n            componentType: mainType,\n            name: name,\n            $vars: ['name']\n        };\n        formatterParams[mainType + 'Index'] = axisModel.componentIndex;\n\n        var textEl = new Text({\n            // Id for animation\n            anid: 'name',\n\n            __fullText: name,\n            __truncatedText: truncatedText,\n\n            position: pos,\n            rotation: labelLayout.rotation,\n            silent: isSilent(axisModel),\n            z2: 1,\n            tooltip: (tooltipOpt && tooltipOpt.show)\n                ? extend({\n                    content: name,\n                    formatter: function () {\n                        return name;\n                    },\n                    formatterParams: formatterParams\n                }, tooltipOpt)\n                : null\n        });\n\n        setTextStyle(textEl.style, textStyleModel, {\n            text: truncatedText,\n            textFont: textFont,\n            textFill: textStyleModel.getTextColor()\n                || axisModel.get('axisLine.lineStyle.color'),\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.textVerticalAlign\n        });\n\n        if (axisModel.get('triggerEvent')) {\n            textEl.eventData = makeAxisEventDataBase(axisModel);\n            textEl.eventData.targetType = 'axisName';\n            textEl.eventData.name = name;\n        }\n\n        // FIXME\n        this._dumbGroup.add(textEl);\n        textEl.updateTransform();\n\n        this.group.add(textEl);\n\n        textEl.decomposeTransform();\n    }\n\n};\n\n/**\n * @public\n * @static\n * @param {Object} opt\n * @param {number} axisRotation in radian\n * @param {number} textRotation in radian\n * @param {number} direction\n * @return {Object} {\n *  rotation, // according to axis\n *  textAlign,\n *  textVerticalAlign\n * }\n */\nvar innerTextLayout = AxisBuilder.innerTextLayout = function (axisRotation, textRotation, direction) {\n    var rotationDiff = remRadian(textRotation - axisRotation);\n    var textAlign;\n    var textVerticalAlign;\n\n    if (isRadianAroundZero(rotationDiff)) { // Label is parallel with axis line.\n        textVerticalAlign = direction > 0 ? 'top' : 'bottom';\n        textAlign = 'center';\n    }\n    else if (isRadianAroundZero(rotationDiff - PI$2)) { // Label is inverse parallel with axis line.\n        textVerticalAlign = direction > 0 ? 'bottom' : 'top';\n        textAlign = 'center';\n    }\n    else {\n        textVerticalAlign = 'middle';\n\n        if (rotationDiff > 0 && rotationDiff < PI$2) {\n            textAlign = direction > 0 ? 'right' : 'left';\n        }\n        else {\n            textAlign = direction > 0 ? 'left' : 'right';\n        }\n    }\n\n    return {\n        rotation: rotationDiff,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n};\n\nfunction endTextLayout(opt, textPosition, textRotate, extent) {\n    var rotationDiff = remRadian(textRotate - opt.rotation);\n    var textAlign;\n    var textVerticalAlign;\n    var inverse = extent[0] > extent[1];\n    var onLeft = (textPosition === 'start' && !inverse)\n        || (textPosition !== 'start' && inverse);\n\n    if (isRadianAroundZero(rotationDiff - PI$2 / 2)) {\n        textVerticalAlign = onLeft ? 'bottom' : 'top';\n        textAlign = 'center';\n    }\n    else if (isRadianAroundZero(rotationDiff - PI$2 * 1.5)) {\n        textVerticalAlign = onLeft ? 'top' : 'bottom';\n        textAlign = 'center';\n    }\n    else {\n        textVerticalAlign = 'middle';\n        if (rotationDiff < PI$2 * 1.5 && rotationDiff > PI$2 / 2) {\n            textAlign = onLeft ? 'left' : 'right';\n        }\n        else {\n            textAlign = onLeft ? 'right' : 'left';\n        }\n    }\n\n    return {\n        rotation: rotationDiff,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\nfunction isSilent(axisModel) {\n    var tooltipOpt = axisModel.get('tooltip');\n    return axisModel.get('silent')\n        // Consider mouse cursor, add these restrictions.\n        || !(\n            axisModel.get('triggerEvent') || (tooltipOpt && tooltipOpt.show)\n        );\n}\n\nfunction fixMinMaxLabelShow(axisModel, labelEls, tickEls) {\n    if (shouldShowAllLabels(axisModel.axis)) {\n        return;\n    }\n\n    // If min or max are user set, we need to check\n    // If the tick on min(max) are overlap on their neighbour tick\n    // If they are overlapped, we need to hide the min(max) tick label\n    var showMinLabel = axisModel.get('axisLabel.showMinLabel');\n    var showMaxLabel = axisModel.get('axisLabel.showMaxLabel');\n\n    // FIXME\n    // Have not consider onBand yet, where tick els is more than label els.\n\n    labelEls = labelEls || [];\n    tickEls = tickEls || [];\n\n    var firstLabel = labelEls[0];\n    var nextLabel = labelEls[1];\n    var lastLabel = labelEls[labelEls.length - 1];\n    var prevLabel = labelEls[labelEls.length - 2];\n\n    var firstTick = tickEls[0];\n    var nextTick = tickEls[1];\n    var lastTick = tickEls[tickEls.length - 1];\n    var prevTick = tickEls[tickEls.length - 2];\n\n    if (showMinLabel === false) {\n        ignoreEl(firstLabel);\n        ignoreEl(firstTick);\n    }\n    else if (isTwoLabelOverlapped(firstLabel, nextLabel)) {\n        if (showMinLabel) {\n            ignoreEl(nextLabel);\n            ignoreEl(nextTick);\n        }\n        else {\n            ignoreEl(firstLabel);\n            ignoreEl(firstTick);\n        }\n    }\n\n    if (showMaxLabel === false) {\n        ignoreEl(lastLabel);\n        ignoreEl(lastTick);\n    }\n    else if (isTwoLabelOverlapped(prevLabel, lastLabel)) {\n        if (showMaxLabel) {\n            ignoreEl(prevLabel);\n            ignoreEl(prevTick);\n        }\n        else {\n            ignoreEl(lastLabel);\n            ignoreEl(lastTick);\n        }\n    }\n}\n\nfunction ignoreEl(el) {\n    el && (el.ignore = true);\n}\n\nfunction isTwoLabelOverlapped(current, next, labelLayout) {\n    // current and next has the same rotation.\n    var firstRect = current && current.getBoundingRect().clone();\n    var nextRect = next && next.getBoundingRect().clone();\n\n    if (!firstRect || !nextRect) {\n        return;\n    }\n\n    // When checking intersect of two rotated labels, we use mRotationBack\n    // to avoid that boundingRect is enlarge when using `boundingRect.applyTransform`.\n    var mRotationBack = identity([]);\n    rotate(mRotationBack, mRotationBack, -current.rotation);\n\n    firstRect.applyTransform(mul$1([], mRotationBack, current.getLocalTransform()));\n    nextRect.applyTransform(mul$1([], mRotationBack, next.getLocalTransform()));\n\n    return firstRect.intersect(nextRect);\n}\n\nfunction isNameLocationCenter(nameLocation) {\n    return nameLocation === 'middle' || nameLocation === 'center';\n}\n\nfunction buildAxisTick(axisBuilder, axisModel, opt) {\n    var axis = axisModel.axis;\n\n    if (!axisModel.get('axisTick.show') || axis.scale.isBlank()) {\n        return;\n    }\n\n    var tickModel = axisModel.getModel('axisTick');\n\n    var lineStyleModel = tickModel.getModel('lineStyle');\n    var tickLen = tickModel.get('length');\n\n    var ticksCoords = axis.getTicksCoords();\n\n    var pt1 = [];\n    var pt2 = [];\n    var matrix = axisBuilder._transform;\n\n    var tickEls = [];\n\n    for (var i = 0; i < ticksCoords.length; i++) {\n        var tickCoord = ticksCoords[i].coord;\n\n        pt1[0] = tickCoord;\n        pt1[1] = 0;\n        pt2[0] = tickCoord;\n        pt2[1] = opt.tickDirection * tickLen;\n\n        if (matrix) {\n            applyTransform(pt1, pt1, matrix);\n            applyTransform(pt2, pt2, matrix);\n        }\n        // Tick line, Not use group transform to have better line draw\n        var tickEl = new Line(subPixelOptimizeLine({\n            // Id for animation\n            anid: 'tick_' + ticksCoords[i].tickValue,\n\n            shape: {\n                x1: pt1[0],\n                y1: pt1[1],\n                x2: pt2[0],\n                y2: pt2[1]\n            },\n            style: defaults(\n                lineStyleModel.getLineStyle(),\n                {\n                    stroke: axisModel.get('axisLine.lineStyle.color')\n                }\n            ),\n            z2: 2,\n            silent: true\n        }));\n        axisBuilder.group.add(tickEl);\n        tickEls.push(tickEl);\n    }\n\n    return tickEls;\n}\n\nfunction buildAxisLabel(axisBuilder, axisModel, opt) {\n    var axis = axisModel.axis;\n    var show = retrieve(opt.axisLabelShow, axisModel.get('axisLabel.show'));\n\n    if (!show || axis.scale.isBlank()) {\n        return;\n    }\n\n    var labelModel = axisModel.getModel('axisLabel');\n    var labelMargin = labelModel.get('margin');\n    var labels = axis.getViewLabels();\n\n    // Special label rotate.\n    var labelRotation = (\n        retrieve(opt.labelRotate, labelModel.get('rotate')) || 0\n    ) * PI$2 / 180;\n\n    var labelLayout = innerTextLayout(opt.rotation, labelRotation, opt.labelDirection);\n    var rawCategoryData = axisModel.getCategories(true);\n\n    var labelEls = [];\n    var silent = isSilent(axisModel);\n    var triggerEvent = axisModel.get('triggerEvent');\n\n    each$1(labels, function (labelItem, index) {\n        var tickValue = labelItem.tickValue;\n        var formattedLabel = labelItem.formattedLabel;\n        var rawLabel = labelItem.rawLabel;\n\n        var itemLabelModel = labelModel;\n        if (rawCategoryData && rawCategoryData[tickValue] && rawCategoryData[tickValue].textStyle) {\n            itemLabelModel = new Model(\n                rawCategoryData[tickValue].textStyle, labelModel, axisModel.ecModel\n            );\n        }\n\n        var textColor = itemLabelModel.getTextColor()\n            || axisModel.get('axisLine.lineStyle.color');\n\n        var tickCoord = axis.dataToCoord(tickValue);\n        var pos = [\n            tickCoord,\n            opt.labelOffset + opt.labelDirection * labelMargin\n        ];\n\n        var textEl = new Text({\n            // Id for animation\n            anid: 'label_' + tickValue,\n            position: pos,\n            rotation: labelLayout.rotation,\n            silent: silent,\n            z2: 10\n        });\n\n        setTextStyle(textEl.style, itemLabelModel, {\n            text: formattedLabel,\n            textAlign: itemLabelModel.getShallow('align', true)\n                || labelLayout.textAlign,\n            textVerticalAlign: itemLabelModel.getShallow('verticalAlign', true)\n                || itemLabelModel.getShallow('baseline', true)\n                || labelLayout.textVerticalAlign,\n            textFill: typeof textColor === 'function'\n                ? textColor(\n                    // (1) In category axis with data zoom, tick is not the original\n                    // index of axis.data. So tick should not be exposed to user\n                    // in category axis.\n                    // (2) Compatible with previous version, which always use formatted label as\n                    // input. But in interval scale the formatted label is like '223,445', which\n                    // maked user repalce ','. So we modify it to return original val but remain\n                    // it as 'string' to avoid error in replacing.\n                    axis.type === 'category'\n                        ? rawLabel\n                        : axis.type === 'value'\n                        ? tickValue + ''\n                        : tickValue,\n                    index\n                )\n                : textColor\n        });\n\n        // Pack data for mouse event\n        if (triggerEvent) {\n            textEl.eventData = makeAxisEventDataBase(axisModel);\n            textEl.eventData.targetType = 'axisLabel';\n            textEl.eventData.value = rawLabel;\n        }\n\n        // FIXME\n        axisBuilder._dumbGroup.add(textEl);\n        textEl.updateTransform();\n\n        labelEls.push(textEl);\n        axisBuilder.group.add(textEl);\n\n        textEl.decomposeTransform();\n\n    });\n\n    return labelEls;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$6 = each$1;\nvar curry$1 = curry;\n\n// Build axisPointerModel, mergin tooltip.axisPointer model for each axis.\n// allAxesInfo should be updated when setOption performed.\nfunction collect(ecModel, api) {\n    var result = {\n        /**\n         * key: makeKey(axis.model)\n         * value: {\n         *      axis,\n         *      coordSys,\n         *      axisPointerModel,\n         *      triggerTooltip,\n         *      involveSeries,\n         *      snap,\n         *      seriesModels,\n         *      seriesDataCount\n         * }\n         */\n        axesInfo: {},\n        seriesInvolved: false,\n        /**\n         * key: makeKey(coordSys.model)\n         * value: Object: key makeKey(axis.model), value: axisInfo\n         */\n        coordSysAxesInfo: {},\n        coordSysMap: {}\n    };\n\n    collectAxesInfo(result, ecModel, api);\n\n    // Check seriesInvolved for performance, in case too many series in some chart.\n    result.seriesInvolved && collectSeriesInfo(result, ecModel);\n\n    return result;\n}\n\nfunction collectAxesInfo(result, ecModel, api) {\n    var globalTooltipModel = ecModel.getComponent('tooltip');\n    var globalAxisPointerModel = ecModel.getComponent('axisPointer');\n    // links can only be set on global.\n    var linksOption = globalAxisPointerModel.get('link', true) || [];\n    var linkGroups = [];\n\n    // Collect axes info.\n    each$6(api.getCoordinateSystems(), function (coordSys) {\n        // Some coordinate system do not support axes, like geo.\n        if (!coordSys.axisPointerEnabled) {\n            return;\n        }\n\n        var coordSysKey = makeKey(coordSys.model);\n        var axesInfoInCoordSys = result.coordSysAxesInfo[coordSysKey] = {};\n        result.coordSysMap[coordSysKey] = coordSys;\n\n        // Set tooltip (like 'cross') is a convienent way to show axisPointer\n        // for user. So we enable seting tooltip on coordSys model.\n        var coordSysModel = coordSys.model;\n        var baseTooltipModel = coordSysModel.getModel('tooltip', globalTooltipModel);\n\n        each$6(coordSys.getAxes(), curry$1(saveTooltipAxisInfo, false, null));\n\n        // If axis tooltip used, choose tooltip axis for each coordSys.\n        // Notice this case: coordSys is `grid` but not `cartesian2D` here.\n        if (coordSys.getTooltipAxes\n            && globalTooltipModel\n            // If tooltip.showContent is set as false, tooltip will not\n            // show but axisPointer will show as normal.\n            && baseTooltipModel.get('show')\n        ) {\n            // Compatible with previous logic. But series.tooltip.trigger: 'axis'\n            // or series.data[n].tooltip.trigger: 'axis' are not support any more.\n            var triggerAxis = baseTooltipModel.get('trigger') === 'axis';\n            var cross = baseTooltipModel.get('axisPointer.type') === 'cross';\n            var tooltipAxes = coordSys.getTooltipAxes(baseTooltipModel.get('axisPointer.axis'));\n            if (triggerAxis || cross) {\n                each$6(tooltipAxes.baseAxes, curry$1(\n                    saveTooltipAxisInfo, cross ? 'cross' : true, triggerAxis\n                ));\n            }\n            if (cross) {\n                each$6(tooltipAxes.otherAxes, curry$1(saveTooltipAxisInfo, 'cross', false));\n            }\n        }\n\n        // fromTooltip: true | false | 'cross'\n        // triggerTooltip: true | false | null\n        function saveTooltipAxisInfo(fromTooltip, triggerTooltip, axis) {\n            var axisPointerModel = axis.model.getModel('axisPointer', globalAxisPointerModel);\n\n            var axisPointerShow = axisPointerModel.get('show');\n            if (!axisPointerShow || (\n                axisPointerShow === 'auto'\n                && !fromTooltip\n                && !isHandleTrigger(axisPointerModel)\n            )) {\n                return;\n            }\n\n            if (triggerTooltip == null) {\n                triggerTooltip = axisPointerModel.get('triggerTooltip');\n            }\n\n            axisPointerModel = fromTooltip\n                ? makeAxisPointerModel(\n                    axis, baseTooltipModel, globalAxisPointerModel, ecModel,\n                    fromTooltip, triggerTooltip\n                )\n                : axisPointerModel;\n\n            var snap = axisPointerModel.get('snap');\n            var key = makeKey(axis.model);\n            var involveSeries = triggerTooltip || snap || axis.type === 'category';\n\n            // If result.axesInfo[key] exist, override it (tooltip has higher priority).\n            var axisInfo = result.axesInfo[key] = {\n                key: key,\n                axis: axis,\n                coordSys: coordSys,\n                axisPointerModel: axisPointerModel,\n                triggerTooltip: triggerTooltip,\n                involveSeries: involveSeries,\n                snap: snap,\n                useHandle: isHandleTrigger(axisPointerModel),\n                seriesModels: []\n            };\n            axesInfoInCoordSys[key] = axisInfo;\n            result.seriesInvolved |= involveSeries;\n\n            var groupIndex = getLinkGroupIndex(linksOption, axis);\n            if (groupIndex != null) {\n                var linkGroup = linkGroups[groupIndex] || (linkGroups[groupIndex] = {axesInfo: {}});\n                linkGroup.axesInfo[key] = axisInfo;\n                linkGroup.mapper = linksOption[groupIndex].mapper;\n                axisInfo.linkGroup = linkGroup;\n            }\n        }\n    });\n}\n\nfunction makeAxisPointerModel(\n    axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip\n) {\n    var tooltipAxisPointerModel = baseTooltipModel.getModel('axisPointer');\n    var volatileOption = {};\n\n    each$6(\n        [\n            'type', 'snap', 'lineStyle', 'shadowStyle', 'label',\n            'animation', 'animationDurationUpdate', 'animationEasingUpdate', 'z'\n        ],\n        function (field) {\n            volatileOption[field] = clone(tooltipAxisPointerModel.get(field));\n        }\n    );\n\n    // category axis do not auto snap, otherwise some tick that do not\n    // has value can not be hovered. value/time/log axis default snap if\n    // triggered from tooltip and trigger tooltip.\n    volatileOption.snap = axis.type !== 'category' && !!triggerTooltip;\n\n    // Compatibel with previous behavior, tooltip axis do not show label by default.\n    // Only these properties can be overrided from tooltip to axisPointer.\n    if (tooltipAxisPointerModel.get('type') === 'cross') {\n        volatileOption.type = 'line';\n    }\n    var labelOption = volatileOption.label || (volatileOption.label = {});\n    // Follow the convention, do not show label when triggered by tooltip by default.\n    labelOption.show == null && (labelOption.show = false);\n\n    if (fromTooltip === 'cross') {\n        // When 'cross', both axes show labels.\n        var tooltipAxisPointerLabelShow = tooltipAxisPointerModel.get('label.show');\n        labelOption.show = tooltipAxisPointerLabelShow != null ? tooltipAxisPointerLabelShow : true;\n        // If triggerTooltip, this is a base axis, which should better not use cross style\n        // (cross style is dashed by default)\n        if (!triggerTooltip) {\n            var crossStyle = volatileOption.lineStyle = tooltipAxisPointerModel.get('crossStyle');\n            crossStyle && defaults(labelOption, crossStyle.textStyle);\n        }\n    }\n\n    return axis.model.getModel(\n        'axisPointer',\n        new Model(volatileOption, globalAxisPointerModel, ecModel)\n    );\n}\n\nfunction collectSeriesInfo(result, ecModel) {\n    // Prepare data for axis trigger\n    ecModel.eachSeries(function (seriesModel) {\n\n        // Notice this case: this coordSys is `cartesian2D` but not `grid`.\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesTooltipTrigger = seriesModel.get('tooltip.trigger', true);\n        var seriesTooltipShow = seriesModel.get('tooltip.show', true);\n        if (!coordSys\n            || seriesTooltipTrigger === 'none'\n            || seriesTooltipTrigger === false\n            || seriesTooltipTrigger === 'item'\n            || seriesTooltipShow === false\n            || seriesModel.get('axisPointer.show', true) === false\n        ) {\n            return;\n        }\n\n        each$6(result.coordSysAxesInfo[makeKey(coordSys.model)], function (axisInfo) {\n            var axis = axisInfo.axis;\n            if (coordSys.getAxis(axis.dim) === axis) {\n                axisInfo.seriesModels.push(seriesModel);\n                axisInfo.seriesDataCount == null && (axisInfo.seriesDataCount = 0);\n                axisInfo.seriesDataCount += seriesModel.getData().count();\n            }\n        });\n\n    }, this);\n}\n\n/**\n * For example:\n * {\n *     axisPointer: {\n *         links: [{\n *             xAxisIndex: [2, 4],\n *             yAxisIndex: 'all'\n *         }, {\n *             xAxisId: ['a5', 'a7'],\n *             xAxisName: 'xxx'\n *         }]\n *     }\n * }\n */\nfunction getLinkGroupIndex(linksOption, axis) {\n    var axisModel = axis.model;\n    var dim = axis.dim;\n    for (var i = 0; i < linksOption.length; i++) {\n        var linkOption = linksOption[i] || {};\n        if (checkPropInLink(linkOption[dim + 'AxisId'], axisModel.id)\n            || checkPropInLink(linkOption[dim + 'AxisIndex'], axisModel.componentIndex)\n            || checkPropInLink(linkOption[dim + 'AxisName'], axisModel.name)\n        ) {\n            return i;\n        }\n    }\n}\n\nfunction checkPropInLink(linkPropValue, axisPropValue) {\n    return linkPropValue === 'all'\n        || (isArray(linkPropValue) && indexOf(linkPropValue, axisPropValue) >= 0)\n        || linkPropValue === axisPropValue;\n}\n\nfunction fixValue(axisModel) {\n    var axisInfo = getAxisInfo(axisModel);\n    if (!axisInfo) {\n        return;\n    }\n\n    var axisPointerModel = axisInfo.axisPointerModel;\n    var scale = axisInfo.axis.scale;\n    var option = axisPointerModel.option;\n    var status = axisPointerModel.get('status');\n    var value = axisPointerModel.get('value');\n\n    // Parse init value for category and time axis.\n    if (value != null) {\n        value = scale.parse(value);\n    }\n\n    var useHandle = isHandleTrigger(axisPointerModel);\n    // If `handle` used, `axisPointer` will always be displayed, so value\n    // and status should be initialized.\n    if (status == null) {\n        option.status = useHandle ? 'show' : 'hide';\n    }\n\n    var extent = scale.getExtent().slice();\n    extent[0] > extent[1] && extent.reverse();\n\n    if (// Pick a value on axis when initializing.\n        value == null\n        // If both `handle` and `dataZoom` are used, value may be out of axis extent,\n        // where we should re-pick a value to keep `handle` displaying normally.\n        || value > extent[1]\n    ) {\n        // Make handle displayed on the end of the axis when init, which looks better.\n        value = extent[1];\n    }\n    if (value < extent[0]) {\n        value = extent[0];\n    }\n\n    option.value = value;\n\n    if (useHandle) {\n        option.status = axisInfo.axis.scale.isBlank() ? 'hide' : 'show';\n    }\n}\n\nfunction getAxisInfo(axisModel) {\n    var coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') || {}).coordSysAxesInfo;\n    return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)];\n}\n\nfunction getAxisPointerModel(axisModel) {\n    var axisInfo = getAxisInfo(axisModel);\n    return axisInfo && axisInfo.axisPointerModel;\n}\n\nfunction isHandleTrigger(axisPointerModel) {\n    return !!axisPointerModel.get('handle.show');\n}\n\n/**\n * @param {module:echarts/model/Model} model\n * @return {string} unique key\n */\nfunction makeKey(model) {\n    return model.type + '||' + model.id;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Base class of AxisView.\n */\nvar AxisView = extendComponentView({\n\n    type: 'axis',\n\n    /**\n     * @private\n     */\n    _axisPointer: null,\n\n    /**\n     * @protected\n     * @type {string}\n     */\n    axisPointerClass: null,\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n        // FIXME\n        // This process should proformed after coordinate systems updated\n        // (axis scale updated), and should be performed each time update.\n        // So put it here temporarily, although it is not appropriate to\n        // put a model-writing procedure in `view`.\n        this.axisPointerClass && fixValue(axisModel);\n\n        AxisView.superApply(this, 'render', arguments);\n\n        updateAxisPointer(this, axisModel, ecModel, api, payload, true);\n    },\n\n    /**\n     * Action handler.\n     * @public\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/model/Global} ecModel\n     * @param {module:echarts/ExtensionAPI} api\n     * @param {Object} payload\n     */\n    updateAxisPointer: function (axisModel, ecModel, api, payload, force) {\n        updateAxisPointer(this, axisModel, ecModel, api, payload, false);\n    },\n\n    /**\n     * @override\n     */\n    remove: function (ecModel, api) {\n        var axisPointer = this._axisPointer;\n        axisPointer && axisPointer.remove(api);\n        AxisView.superApply(this, 'remove', arguments);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function (ecModel, api) {\n        disposeAxisPointer(this, api);\n        AxisView.superApply(this, 'dispose', arguments);\n    }\n\n});\n\nfunction updateAxisPointer(axisView, axisModel, ecModel, api, payload, forceRender) {\n    var Clazz = AxisView.getAxisPointerClass(axisView.axisPointerClass);\n    if (!Clazz) {\n        return;\n    }\n    var axisPointerModel = getAxisPointerModel(axisModel);\n    axisPointerModel\n        ? (axisView._axisPointer || (axisView._axisPointer = new Clazz()))\n            .render(axisModel, axisPointerModel, api, forceRender)\n        : disposeAxisPointer(axisView, api);\n}\n\nfunction disposeAxisPointer(axisView, ecModel, api) {\n    var axisPointer = axisView._axisPointer;\n    axisPointer && axisPointer.dispose(ecModel, api);\n    axisView._axisPointer = null;\n}\n\nvar axisPointerClazz = [];\n\nAxisView.registerAxisPointerClass = function (type, clazz) {\n    if (__DEV__) {\n        if (axisPointerClazz[type]) {\n            throw new Error('axisPointer ' + type + ' exists');\n        }\n    }\n    axisPointerClazz[type] = clazz;\n};\n\nAxisView.getAxisPointerClass = function (type) {\n    return type && axisPointerClazz[type];\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Can only be called after coordinate system creation stage.\n * (Can be called before coordinate system update stage).\n *\n * @param {Object} opt {labelInside}\n * @return {Object} {\n *  position, rotation, labelDirection, labelOffset,\n *  tickDirection, labelRotate, z2\n * }\n */\nfunction layout$1(gridModel, axisModel, opt) {\n    opt = opt || {};\n    var grid = gridModel.coordinateSystem;\n    var axis = axisModel.axis;\n    var layout = {};\n    var otherAxisOnZeroOf = axis.getAxesOnZeroOf()[0];\n\n    var rawAxisPosition = axis.position;\n    var axisPosition = otherAxisOnZeroOf ? 'onZero' : rawAxisPosition;\n    var axisDim = axis.dim;\n\n    var rect = grid.getRect();\n    var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];\n    var idx = {left: 0, right: 1, top: 0, bottom: 1, onZero: 2};\n    var axisOffset = axisModel.get('offset') || 0;\n\n    var posBound = axisDim === 'x'\n        ? [rectBound[2] - axisOffset, rectBound[3] + axisOffset]\n        : [rectBound[0] - axisOffset, rectBound[1] + axisOffset];\n\n    if (otherAxisOnZeroOf) {\n        var onZeroCoord = otherAxisOnZeroOf.toGlobalCoord(otherAxisOnZeroOf.dataToCoord(0));\n        posBound[idx.onZero] = Math.max(Math.min(onZeroCoord, posBound[1]), posBound[0]);\n    }\n\n    // Axis position\n    layout.position = [\n        axisDim === 'y' ? posBound[idx[axisPosition]] : rectBound[0],\n        axisDim === 'x' ? posBound[idx[axisPosition]] : rectBound[3]\n    ];\n\n    // Axis rotation\n    layout.rotation = Math.PI / 2 * (axisDim === 'x' ? 0 : 1);\n\n    // Tick and label direction, x y is axisDim\n    var dirMap = {top: -1, bottom: 1, left: -1, right: 1};\n\n    layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition];\n    layout.labelOffset = otherAxisOnZeroOf ? posBound[idx[rawAxisPosition]] - posBound[idx.onZero] : 0;\n\n    if (axisModel.get('axisTick.inside')) {\n        layout.tickDirection = -layout.tickDirection;\n    }\n    if (retrieve(opt.labelInside, axisModel.get('axisLabel.inside'))) {\n        layout.labelDirection = -layout.labelDirection;\n    }\n\n    // Special label rotation\n    var labelRotate = axisModel.get('axisLabel.rotate');\n    layout.labelRotate = axisPosition === 'top' ? -labelRotate : labelRotate;\n\n    // Over splitLine and splitArea\n    layout.z2 = 1;\n\n    return layout;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar axisBuilderAttrs = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\nvar selfBuilderAttrs = [\n    'splitArea', 'splitLine'\n];\n\n// function getAlignWithLabel(model, axisModel) {\n//     var alignWithLabel = model.get('alignWithLabel');\n//     if (alignWithLabel === 'auto') {\n//         alignWithLabel = axisModel.get('axisTick.alignWithLabel');\n//     }\n//     return alignWithLabel;\n// }\n\nvar CartesianAxisView = AxisView.extend({\n\n    type: 'cartesianAxis',\n\n    axisPointerClass: 'CartesianAxisPointer',\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n\n        this.group.removeAll();\n\n        var oldAxisGroup = this._axisGroup;\n        this._axisGroup = new Group();\n\n        this.group.add(this._axisGroup);\n\n        if (!axisModel.get('show')) {\n            return;\n        }\n\n        var gridModel = axisModel.getCoordSysModel();\n\n        var layout = layout$1(gridModel, axisModel);\n\n        var axisBuilder = new AxisBuilder(axisModel, layout);\n\n        each$1(axisBuilderAttrs, axisBuilder.add, axisBuilder);\n\n        this._axisGroup.add(axisBuilder.getGroup());\n\n        each$1(selfBuilderAttrs, function (name) {\n            if (axisModel.get(name + '.show')) {\n                this['_' + name](axisModel, gridModel);\n            }\n        }, this);\n\n        groupTransition(oldAxisGroup, this._axisGroup, axisModel);\n\n        CartesianAxisView.superCall(this, 'render', axisModel, ecModel, api, payload);\n    },\n\n    remove: function () {\n        this._splitAreaColors = null;\n    },\n\n    /**\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/coord/cartesian/GridModel} gridModel\n     * @private\n     */\n    _splitLine: function (axisModel, gridModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitLineModel = axisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineColors = lineStyleModel.get('color');\n\n        lineColors = isArray(lineColors) ? lineColors : [lineColors];\n\n        var gridRect = gridModel.coordinateSystem.getRect();\n        var isHorizontal = axis.isHorizontal();\n\n        var lineCount = 0;\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitLineModel\n        });\n\n        var p1 = [];\n        var p2 = [];\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        var lineStyle = lineStyleModel.getLineStyle();\n        for (var i = 0; i < ticksCoords.length; i++) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n\n            if (isHorizontal) {\n                p1[0] = tickCoord;\n                p1[1] = gridRect.y;\n                p2[0] = tickCoord;\n                p2[1] = gridRect.y + gridRect.height;\n            }\n            else {\n                p1[0] = gridRect.x;\n                p1[1] = tickCoord;\n                p2[0] = gridRect.x + gridRect.width;\n                p2[1] = tickCoord;\n            }\n\n            var colorIndex = (lineCount++) % lineColors.length;\n            var tickValue = ticksCoords[i].tickValue;\n            this._axisGroup.add(new Line(subPixelOptimizeLine({\n                anid: tickValue != null ? 'line_' + ticksCoords[i].tickValue : null,\n                shape: {\n                    x1: p1[0],\n                    y1: p1[1],\n                    x2: p2[0],\n                    y2: p2[1]\n                },\n                style: defaults({\n                    stroke: lineColors[colorIndex]\n                }, lineStyle),\n                silent: true\n            })));\n        }\n    },\n\n    /**\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/coord/cartesian/GridModel} gridModel\n     * @private\n     */\n    _splitArea: function (axisModel, gridModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitAreaModel = axisModel.getModel('splitArea');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n        var areaColors = areaStyleModel.get('color');\n\n        var gridRect = gridModel.coordinateSystem.getRect();\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitAreaModel,\n            clamp: true\n        });\n\n        if (!ticksCoords.length) {\n            return;\n        }\n\n        // For Making appropriate splitArea animation, the color and anid\n        // should be corresponding to previous one if possible.\n        var areaColorsLen = areaColors.length;\n        var lastSplitAreaColors = this._splitAreaColors;\n        var newSplitAreaColors = createHashMap();\n        var colorIndex = 0;\n        if (lastSplitAreaColors) {\n            for (var i = 0; i < ticksCoords.length; i++) {\n                var cIndex = lastSplitAreaColors.get(ticksCoords[i].tickValue);\n                if (cIndex != null) {\n                    colorIndex = (cIndex + (areaColorsLen - 1) * i) % areaColorsLen;\n                    break;\n                }\n            }\n        }\n\n        var prev = axis.toGlobalCoord(ticksCoords[0].coord);\n\n        var areaStyle = areaStyleModel.getAreaStyle();\n        areaColors = isArray(areaColors) ? areaColors : [areaColors];\n\n        for (var i = 1; i < ticksCoords.length; i++) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n\n            var x;\n            var y;\n            var width;\n            var height;\n            if (axis.isHorizontal()) {\n                x = prev;\n                y = gridRect.y;\n                width = tickCoord - x;\n                height = gridRect.height;\n                prev = x + width;\n            }\n            else {\n                x = gridRect.x;\n                y = prev;\n                width = gridRect.width;\n                height = tickCoord - y;\n                prev = y + height;\n            }\n\n            var tickValue = ticksCoords[i - 1].tickValue;\n            tickValue != null && newSplitAreaColors.set(tickValue, colorIndex);\n\n            this._axisGroup.add(new Rect({\n                anid: tickValue != null ? 'area_' + tickValue : null,\n                shape: {\n                    x: x,\n                    y: y,\n                    width: width,\n                    height: height\n                },\n                style: defaults({\n                    fill: areaColors[colorIndex]\n                }, areaStyle),\n                silent: true\n            }));\n\n            colorIndex = (colorIndex + 1) % areaColorsLen;\n        }\n\n        this._splitAreaColors = newSplitAreaColors;\n    }\n});\n\nCartesianAxisView.extend({\n    type: 'xAxis'\n});\nCartesianAxisView.extend({\n    type: 'yAxis'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Grid view\nextendComponentView({\n\n    type: 'grid',\n\n    render: function (gridModel, ecModel) {\n        this.group.removeAll();\n        if (gridModel.get('show')) {\n            this.group.add(new Rect({\n                shape: gridModel.coordinateSystem.getRect(),\n                style: defaults({\n                    fill: gridModel.get('backgroundColor')\n                }, gridModel.getItemStyle()),\n                silent: true,\n                z2: -1\n            }));\n        }\n    }\n\n});\n\nregisterPreprocessor(function (option) {\n    // Only create grid when need\n    if (option.xAxis && option.yAxis && !option.grid) {\n        option.grid = {};\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterVisual(visualSymbol('line', 'circle', 'line'));\nregisterLayout(pointsLayout('line'));\n\n// Down sample after filter\nregisterProcessor(\n    PRIORITY.PROCESSOR.STATISTIC,\n    dataSample('line')\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BaseBarSeries = SeriesModel.extend({\n\n    type: 'series.__base_bar__',\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    getMarkerPosition: function (value) {\n        var coordSys = this.coordinateSystem;\n        if (coordSys) {\n            // PENDING if clamp ?\n            var pt = coordSys.dataToPoint(coordSys.clampData(value));\n            var data = this.getData();\n            var offset = data.getLayout('offset');\n            var size = data.getLayout('size');\n            var offsetIndex = coordSys.getBaseAxis().isHorizontal() ? 0 : 1;\n            pt[offsetIndex] += offset + size / 2;\n            return pt;\n        }\n        return [NaN, NaN];\n    },\n\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n        // stack: null\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // 最小高度改为0\n        barMinHeight: 0,\n        // 最小角度为0，仅对极坐标系下的柱状图有效\n        barMinAngle: 0,\n        // cursor: null,\n\n        large: false,\n        largeThreshold: 400,\n        progressive: 3e3,\n        progressiveChunkMode: 'mod',\n\n        // barMaxWidth: null,\n        // 默认自适应\n        // barWidth: null,\n        // 柱间距离，默认为柱形宽度的30%，可设固定值\n        // barGap: '30%',\n        // 类目间柱形距离，默认为类目间距的20%，可设固定值\n        // barCategoryGap: '20%',\n        // label: {\n        //      show: false\n        // },\n        itemStyle: {},\n        emphasis: {}\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nBaseBarSeries.extend({\n\n    type: 'series.bar',\n\n    dependencies: ['grid', 'polar'],\n\n    brushSelector: 'rect',\n\n    /**\n     * @override\n     */\n    getProgressive: function () {\n        // Do not support progressive in normal mode.\n        return this.get('large')\n            ? this.get('progressive')\n            : false;\n    },\n\n    /**\n     * @override\n     */\n    getProgressiveThreshold: function () {\n        // Do not support progressive in normal mode.\n        var progressiveThreshold = this.get('progressiveThreshold');\n        var largeThreshold = this.get('largeThreshold');\n        if (largeThreshold > progressiveThreshold) {\n            progressiveThreshold = largeThreshold;\n        }\n        return progressiveThreshold;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction setLabel(\n    normalStyle, hoverStyle, itemModel, color, seriesModel, dataIndex, labelPositionOutside\n) {\n    var labelModel = itemModel.getModel('label');\n    var hoverLabelModel = itemModel.getModel('emphasis.label');\n\n    setLabelStyle(\n        normalStyle, hoverStyle, labelModel, hoverLabelModel,\n        {\n            labelFetcher: seriesModel,\n            labelDataIndex: dataIndex,\n            defaultText: getDefaultLabel(seriesModel.getData(), dataIndex),\n            isRectText: true,\n            autoColor: color\n        }\n    );\n\n    fixPosition(normalStyle);\n    fixPosition(hoverStyle);\n}\n\nfunction fixPosition(style, labelPositionOutside) {\n    if (style.textPosition === 'outside') {\n        style.textPosition = labelPositionOutside;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getBarItemStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['stroke', 'borderColor'],\n        ['lineWidth', 'borderWidth'],\n        // Compatitable with 2\n        ['stroke', 'barBorderColor'],\n        ['lineWidth', 'barBorderWidth'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor']\n    ]\n);\n\nvar barItemStyle = {\n    getBarItemStyle: function (excludes) {\n        var style = getBarItemStyle(this, excludes);\n        if (this.getBorderLineDash) {\n            var lineDash = this.getBorderLineDash();\n            lineDash && (style.lineDash = lineDash);\n        }\n        return style;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'barBorderWidth'];\n\n// FIXME\n// Just for compatible with ec2.\nextend(Model.prototype, barItemStyle);\n\nextendChartView({\n\n    type: 'bar',\n\n    render: function (seriesModel, ecModel, api) {\n        this._updateDrawMode(seriesModel);\n\n        var coordinateSystemType = seriesModel.get('coordinateSystem');\n\n        if (coordinateSystemType === 'cartesian2d'\n            || coordinateSystemType === 'polar'\n        ) {\n            this._isLargeDraw\n                ? this._renderLarge(seriesModel, ecModel, api)\n                : this._renderNormal(seriesModel, ecModel, api);\n        }\n        else if (__DEV__) {\n            console.warn('Only cartesian2d and polar supported for bar.');\n        }\n\n        return this.group;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this._clear();\n        this._updateDrawMode(seriesModel);\n    },\n\n    incrementalRender: function (params, seriesModel, ecModel, api) {\n        // Do not support progressive in normal mode.\n        this._incrementalRenderLarge(params, seriesModel);\n    },\n\n    _updateDrawMode: function (seriesModel) {\n        var isLargeDraw = seriesModel.pipelineContext.large;\n        if (this._isLargeDraw == null || isLargeDraw ^ this._isLargeDraw) {\n            this._isLargeDraw = isLargeDraw;\n            this._clear();\n        }\n    },\n\n    _renderNormal: function (seriesModel, ecModel, api) {\n        var group = this.group;\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        var coord = seriesModel.coordinateSystem;\n        var baseAxis = coord.getBaseAxis();\n        var isHorizontalOrRadial;\n\n        if (coord.type === 'cartesian2d') {\n            isHorizontalOrRadial = baseAxis.isHorizontal();\n        }\n        else if (coord.type === 'polar') {\n            isHorizontalOrRadial = baseAxis.dim === 'angle';\n        }\n\n        var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null;\n\n        data.diff(oldData)\n            .add(function (dataIndex) {\n                if (!data.hasValue(dataIndex)) {\n                    return;\n                }\n\n                var itemModel = data.getItemModel(dataIndex);\n                var layout = getLayout[coord.type](data, dataIndex, itemModel);\n                var el = elementCreator[coord.type](\n                    data, dataIndex, itemModel, layout, isHorizontalOrRadial, animationModel\n                );\n                data.setItemGraphicEl(dataIndex, el);\n                group.add(el);\n\n                updateStyle(\n                    el, data, dataIndex, itemModel, layout,\n                    seriesModel, isHorizontalOrRadial, coord.type === 'polar'\n                );\n            })\n            .update(function (newIndex, oldIndex) {\n                var el = oldData.getItemGraphicEl(oldIndex);\n\n                if (!data.hasValue(newIndex)) {\n                    group.remove(el);\n                    return;\n                }\n\n                var itemModel = data.getItemModel(newIndex);\n                var layout = getLayout[coord.type](data, newIndex, itemModel);\n\n                if (el) {\n                    updateProps(el, {shape: layout}, animationModel, newIndex);\n                }\n                else {\n                    el = elementCreator[coord.type](\n                        data, newIndex, itemModel, layout, isHorizontalOrRadial, animationModel, true\n                    );\n                }\n\n                data.setItemGraphicEl(newIndex, el);\n                // Add back\n                group.add(el);\n\n                updateStyle(\n                    el, data, newIndex, itemModel, layout,\n                    seriesModel, isHorizontalOrRadial, coord.type === 'polar'\n                );\n            })\n            .remove(function (dataIndex) {\n                var el = oldData.getItemGraphicEl(dataIndex);\n                if (coord.type === 'cartesian2d') {\n                    el && removeRect(dataIndex, animationModel, el);\n                }\n                else {\n                    el && removeSector(dataIndex, animationModel, el);\n                }\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    _renderLarge: function (seriesModel, ecModel, api) {\n        this._clear();\n        createLarge(seriesModel, this.group);\n    },\n\n    _incrementalRenderLarge: function (params, seriesModel) {\n        createLarge(seriesModel, this.group, true);\n    },\n\n    dispose: noop,\n\n    remove: function (ecModel) {\n        this._clear(ecModel);\n    },\n\n    _clear: function (ecModel) {\n        var group = this.group;\n        var data = this._data;\n        if (ecModel && ecModel.get('animation') && data && !this._isLargeDraw) {\n            data.eachItemGraphicEl(function (el) {\n                if (el.type === 'sector') {\n                    removeSector(el.dataIndex, ecModel, el);\n                }\n                else {\n                    removeRect(el.dataIndex, ecModel, el);\n                }\n            });\n        }\n        else {\n            group.removeAll();\n        }\n        this._data = null;\n    }\n\n});\n\nvar elementCreator = {\n\n    cartesian2d: function (\n        data, dataIndex, itemModel, layout, isHorizontal,\n        animationModel, isUpdate\n    ) {\n        var rect = new Rect({shape: extend({}, layout)});\n\n        // Animation\n        if (animationModel) {\n            var rectShape = rect.shape;\n            var animateProperty = isHorizontal ? 'height' : 'width';\n            var animateTarget = {};\n            rectShape[animateProperty] = 0;\n            animateTarget[animateProperty] = layout[animateProperty];\n            graphic[isUpdate ? 'updateProps' : 'initProps'](rect, {\n                shape: animateTarget\n            }, animationModel, dataIndex);\n        }\n\n        return rect;\n    },\n\n    polar: function (\n        data, dataIndex, itemModel, layout, isRadial,\n        animationModel, isUpdate\n    ) {\n        // Keep the same logic with bar in catesion: use end value to control\n        // direction. Notice that if clockwise is true (by default), the sector\n        // will always draw clockwisely, no matter whether endAngle is greater\n        // or less than startAngle.\n        var clockwise = layout.startAngle < layout.endAngle;\n        var sector = new Sector({\n            shape: defaults({clockwise: clockwise}, layout)\n        });\n\n        // Animation\n        if (animationModel) {\n            var sectorShape = sector.shape;\n            var animateProperty = isRadial ? 'r' : 'endAngle';\n            var animateTarget = {};\n            sectorShape[animateProperty] = isRadial ? 0 : layout.startAngle;\n            animateTarget[animateProperty] = layout[animateProperty];\n            graphic[isUpdate ? 'updateProps' : 'initProps'](sector, {\n                shape: animateTarget\n            }, animationModel, dataIndex);\n        }\n\n        return sector;\n    }\n};\n\nfunction removeRect(dataIndex, animationModel, el) {\n    // Not show text when animating\n    el.style.text = null;\n    updateProps(el, {\n        shape: {\n            width: 0\n        }\n    }, animationModel, dataIndex, function () {\n        el.parent && el.parent.remove(el);\n    });\n}\n\nfunction removeSector(dataIndex, animationModel, el) {\n    // Not show text when animating\n    el.style.text = null;\n    updateProps(el, {\n        shape: {\n            r: el.shape.r0\n        }\n    }, animationModel, dataIndex, function () {\n        el.parent && el.parent.remove(el);\n    });\n}\n\nvar getLayout = {\n    cartesian2d: function (data, dataIndex, itemModel) {\n        var layout = data.getItemLayout(dataIndex);\n        var fixedLineWidth = getLineWidth(itemModel, layout);\n\n        // fix layout with lineWidth\n        var signX = layout.width > 0 ? 1 : -1;\n        var signY = layout.height > 0 ? 1 : -1;\n        return {\n            x: layout.x + signX * fixedLineWidth / 2,\n            y: layout.y + signY * fixedLineWidth / 2,\n            width: layout.width - signX * fixedLineWidth,\n            height: layout.height - signY * fixedLineWidth\n        };\n    },\n\n    polar: function (data, dataIndex, itemModel) {\n        var layout = data.getItemLayout(dataIndex);\n        return {\n            cx: layout.cx,\n            cy: layout.cy,\n            r0: layout.r0,\n            r: layout.r,\n            startAngle: layout.startAngle,\n            endAngle: layout.endAngle\n        };\n    }\n};\n\nfunction updateStyle(\n    el, data, dataIndex, itemModel, layout, seriesModel, isHorizontal, isPolar\n) {\n    var color = data.getItemVisual(dataIndex, 'color');\n    var opacity = data.getItemVisual(dataIndex, 'opacity');\n    var itemStyleModel = itemModel.getModel('itemStyle');\n    var hoverStyle = itemModel.getModel('emphasis.itemStyle').getBarItemStyle();\n\n    if (!isPolar) {\n        el.setShape('r', itemStyleModel.get('barBorderRadius') || 0);\n    }\n\n    el.useStyle(defaults(\n        {\n            fill: color,\n            opacity: opacity\n        },\n        itemStyleModel.getBarItemStyle()\n    ));\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && el.attr('cursor', cursorStyle);\n\n    var labelPositionOutside = isHorizontal\n        ? (layout.height > 0 ? 'bottom' : 'top')\n        : (layout.width > 0 ? 'left' : 'right');\n\n    if (!isPolar) {\n        setLabel(\n            el.style, hoverStyle, itemModel, color,\n            seriesModel, dataIndex, labelPositionOutside\n        );\n    }\n\n    setHoverStyle(el, hoverStyle);\n}\n\n// In case width or height are too small.\nfunction getLineWidth(itemModel, rawLayout) {\n    var lineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY) || 0;\n    return Math.min(lineWidth, Math.abs(rawLayout.width), Math.abs(rawLayout.height));\n}\n\n\nvar LargePath = Path.extend({\n\n    type: 'largeBar',\n\n    shape: {points: []},\n\n    buildPath: function (ctx, shape) {\n        // Drawing lines is more efficient than drawing\n        // a whole line or drawing rects.\n        var points = shape.points;\n        var startPoint = this.__startPoint;\n        var valueIdx = this.__valueIdx;\n\n        for (var i = 0; i < points.length; i += 2) {\n            startPoint[this.__valueIdx] = points[i + valueIdx];\n            ctx.moveTo(startPoint[0], startPoint[1]);\n            ctx.lineTo(points[i], points[i + 1]);\n        }\n    }\n});\n\nfunction createLarge(seriesModel, group, incremental) {\n    // TODO support polar\n    var data = seriesModel.getData();\n    var startPoint = [];\n    var valueIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0;\n    startPoint[1 - valueIdx] = data.getLayout('valueAxisStart');\n\n    var el = new LargePath({\n        shape: {points: data.getLayout('largePoints')},\n        incremental: !!incremental,\n        __startPoint: startPoint,\n        __valueIdx: valueIdx\n    });\n    group.add(el);\n    setLargeStyle(el, seriesModel, data);\n}\n\nfunction setLargeStyle(el, seriesModel, data) {\n    var borderColor = data.getVisual('borderColor') || data.getVisual('color');\n    var itemStyle = seriesModel.getModel('itemStyle').getItemStyle(['color', 'borderColor']);\n\n    el.useStyle(itemStyle);\n    el.style.fill = null;\n    el.style.stroke = borderColor;\n    el.style.lineWidth = data.getLayout('barWidth');\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterLayout(curry(layout, 'bar'));\n// Should after normal bar layout, otherwise it is blocked by normal bar layout.\nregisterLayout(largeLayout);\n\nregisterVisual({\n    seriesType: 'bar',\n    reset: function (seriesModel) {\n        // Visual coding for legend\n        seriesModel.getData().setVisual('legendSymbol', 'roundRect');\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * [Usage]:\n * (1)\n * createListSimply(seriesModel, ['value']);\n * (2)\n * createListSimply(seriesModel, {\n *     coordDimensions: ['value'],\n *     dimensionsCount: 5\n * });\n *\n * @param {module:echarts/model/Series} seriesModel\n * @param {Object|Array.<string|Object>} opt opt or coordDimensions\n *        The options in opt, see `echarts/data/helper/createDimensions`\n * @param {Array.<string>} [nameList]\n * @return {module:echarts/data/List}\n */\nvar createListSimply = function (seriesModel, opt, nameList) {\n    opt = isArray(opt) && {coordDimensions: opt} || extend({}, opt);\n\n    var source = seriesModel.getSource();\n\n    var dimensionsInfo = createDimensions(source, opt);\n\n    var list = new List(dimensionsInfo, seriesModel);\n    list.initData(source, nameList);\n\n    return list;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Data selectable mixin for chart series.\n * To eanble data select, option of series must have `selectedMode`.\n * And each data item will use `selected` to toggle itself selected status\n */\n\nvar dataSelectableMixin = {\n\n    /**\n     * @param {Array.<Object>} targetList [{name, value, selected}, ...]\n     *        If targetList is an array, it should like [{name: ..., value: ...}, ...].\n     *        If targetList is a \"List\", it must have coordDim: 'value' dimension and name.\n     */\n    updateSelectedMap: function (targetList) {\n        this._targetList = isArray(targetList) ? targetList.slice() : [];\n\n        this._selectTargetMap = reduce(targetList || [], function (targetMap, target) {\n            targetMap.set(target.name, target);\n            return targetMap;\n        }, createHashMap());\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    // PENGING If selectedMode is null ?\n    select: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        var selectedMode = this.get('selectedMode');\n        if (selectedMode === 'single') {\n            this._selectTargetMap.each(function (target) {\n                target.selected = false;\n            });\n        }\n        target && (target.selected = true);\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    unSelect: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        // var selectedMode = this.get('selectedMode');\n        // selectedMode !== 'single' && target && (target.selected = false);\n        target && (target.selected = false);\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    toggleSelected: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        if (target != null) {\n            this[target.selected ? 'unSelect' : 'select'](name, id);\n            return target.selected;\n        }\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    isSelected: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        return target && target.selected;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PieSeries = extendSeriesModel({\n\n    type: 'series.pie',\n\n    // Overwrite\n    init: function (option) {\n        PieSeries.superApply(this, 'init', arguments);\n\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n\n        this.updateSelectedMap(this._createSelectableList());\n\n        this._defaultLabelLine(option);\n    },\n\n    // Overwrite\n    mergeOption: function (newOption) {\n        PieSeries.superCall(this, 'mergeOption', newOption);\n\n        this.updateSelectedMap(this._createSelectableList());\n    },\n\n    getInitialData: function (option, ecModel) {\n        return createListSimply(this, ['value']);\n    },\n\n    _createSelectableList: function () {\n        var data = this.getRawData();\n        var valueDim = data.mapDimension('value');\n        var targetList = [];\n        for (var i = 0, len = data.count(); i < len; i++) {\n            targetList.push({\n                name: data.getName(i),\n                value: data.get(valueDim, i),\n                selected: retrieveRawAttr(data, i, 'selected')\n            });\n        }\n        return targetList;\n    },\n\n    // Overwrite\n    getDataParams: function (dataIndex) {\n        var data = this.getData();\n        var params = PieSeries.superCall(this, 'getDataParams', dataIndex);\n        // FIXME toFixed?\n\n        var valueList = [];\n        data.each(data.mapDimension('value'), function (value) {\n            valueList.push(value);\n        });\n\n        params.percent = getPercentWithPrecision(\n            valueList,\n            dataIndex,\n            data.hostModel.get('percentPrecision')\n        );\n\n        params.$vars.push('percent');\n        return params;\n    },\n\n    _defaultLabelLine: function (option) {\n        // Extend labelLine emphasis\n        defaultEmphasis(option, 'labelLine', ['show']);\n\n        var labelLineNormalOpt = option.labelLine;\n        var labelLineEmphasisOpt = option.emphasis.labelLine;\n        // Not show label line if `label.normal.show = false`\n        labelLineNormalOpt.show = labelLineNormalOpt.show\n            && option.label.show;\n        labelLineEmphasisOpt.show = labelLineEmphasisOpt.show\n            && option.emphasis.label.show;\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // 默认全局居中\n        center: ['50%', '50%'],\n        radius: [0, '75%'],\n        // 默认顺时针\n        clockwise: true,\n        startAngle: 90,\n        // 最小角度改为0\n        minAngle: 0,\n        // 选中时扇区偏移量\n        selectedOffset: 10,\n        // 高亮扇区偏移量\n        hoverOffset: 10,\n\n        // If use strategy to avoid label overlapping\n        avoidLabelOverlap: true,\n        // 选择模式，默认关闭，可选single，multiple\n        // selectedMode: false,\n        // 南丁格尔玫瑰图模式，'radius'（半径） | 'area'（面积）\n        // roseType: null,\n\n        percentPrecision: 2,\n\n        // If still show when all data zero.\n        stillShowZeroSum: true,\n\n        // cursor: null,\n\n        label: {\n            // If rotate around circle\n            rotate: false,\n            show: true,\n            // 'outer', 'inside', 'center'\n            position: 'outer'\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n            // 默认使用全局文本样式，详见TEXTSTYLE\n            // distance: 当position为inner时有效，为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数\n        },\n        // Enabled when label.normal.position is 'outer'\n        labelLine: {\n            show: true,\n            // 引导线两段中的第一段长度\n            length: 15,\n            // 引导线两段中的第二段长度\n            length2: 15,\n            smooth: false,\n            lineStyle: {\n                // color: 各异,\n                width: 1,\n                type: 'solid'\n            }\n        },\n        itemStyle: {\n            borderWidth: 1\n        },\n\n        // Animation type canbe expansion, scale\n        animationType: 'expansion',\n\n        animationEasing: 'cubicOut'\n    }\n});\n\nmixin(PieSeries, dataSelectableMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/model/Series} seriesModel\n * @param {boolean} hasAnimation\n * @inner\n */\nfunction updateDataSelected(uid, seriesModel, hasAnimation, api) {\n    var data = seriesModel.getData();\n    var dataIndex = this.dataIndex;\n    var name = data.getName(dataIndex);\n    var selectedOffset = seriesModel.get('selectedOffset');\n\n    api.dispatchAction({\n        type: 'pieToggleSelect',\n        from: uid,\n        name: name,\n        seriesId: seriesModel.id\n    });\n\n    data.each(function (idx) {\n        toggleItemSelected(\n            data.getItemGraphicEl(idx),\n            data.getItemLayout(idx),\n            seriesModel.isSelected(data.getName(idx)),\n            selectedOffset,\n            hasAnimation\n        );\n    });\n}\n\n/**\n * @param {module:zrender/graphic/Sector} el\n * @param {Object} layout\n * @param {boolean} isSelected\n * @param {number} selectedOffset\n * @param {boolean} hasAnimation\n * @inner\n */\nfunction toggleItemSelected(el, layout, isSelected, selectedOffset, hasAnimation) {\n    var midAngle = (layout.startAngle + layout.endAngle) / 2;\n\n    var dx = Math.cos(midAngle);\n    var dy = Math.sin(midAngle);\n\n    var offset = isSelected ? selectedOffset : 0;\n    var position = [dx * offset, dy * offset];\n\n    hasAnimation\n        // animateTo will stop revious animation like update transition\n        ? el.animate()\n            .when(200, {\n                position: position\n            })\n            .start('bounceOut')\n        : el.attr('position', position);\n}\n\n/**\n * Piece of pie including Sector, Label, LabelLine\n * @constructor\n * @extends {module:zrender/graphic/Group}\n */\nfunction PiePiece(data, idx) {\n\n    Group.call(this);\n\n    var sector = new Sector({\n        z2: 2\n    });\n    var polyline = new Polyline();\n    var text = new Text();\n    this.add(sector);\n    this.add(polyline);\n    this.add(text);\n\n    this.updateData(data, idx, true);\n\n    // Hover to change label and labelLine\n    function onEmphasis() {\n        polyline.ignore = polyline.hoverIgnore;\n        text.ignore = text.hoverIgnore;\n    }\n    function onNormal() {\n        polyline.ignore = polyline.normalIgnore;\n        text.ignore = text.normalIgnore;\n    }\n    this.on('emphasis', onEmphasis)\n        .on('normal', onNormal)\n        .on('mouseover', onEmphasis)\n        .on('mouseout', onNormal);\n}\n\nvar piePieceProto = PiePiece.prototype;\n\npiePieceProto.updateData = function (data, idx, firstCreate) {\n\n    var sector = this.childAt(0);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var sectorShape = extend({}, layout);\n    sectorShape.label = null;\n\n    if (firstCreate) {\n        sector.setShape(sectorShape);\n\n        var animationType = seriesModel.getShallow('animationType');\n        if (animationType === 'scale') {\n            sector.shape.r = layout.r0;\n            initProps(sector, {\n                shape: {\n                    r: layout.r\n                }\n            }, seriesModel, idx);\n        }\n        // Expansion\n        else {\n            sector.shape.endAngle = layout.startAngle;\n            updateProps(sector, {\n                shape: {\n                    endAngle: layout.endAngle\n                }\n            }, seriesModel, idx);\n        }\n\n    }\n    else {\n        updateProps(sector, {\n            shape: sectorShape\n        }, seriesModel, idx);\n    }\n\n    // Update common style\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    sector.useStyle(\n        defaults(\n            {\n                lineJoin: 'bevel',\n                fill: visualColor\n            },\n            itemModel.getModel('itemStyle').getItemStyle()\n        )\n    );\n    sector.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && sector.attr('cursor', cursorStyle);\n\n    // Toggle selected\n    toggleItemSelected(\n        this,\n        data.getItemLayout(idx),\n        seriesModel.isSelected(null, idx),\n        seriesModel.get('selectedOffset'),\n        seriesModel.get('animation')\n    );\n\n    function onEmphasis() {\n        // Sector may has animation of updating data. Force to move to the last frame\n        // Or it may stopped on the wrong shape\n        sector.stopAnimation(true);\n        sector.animateTo({\n            shape: {\n                r: layout.r + seriesModel.get('hoverOffset')\n            }\n        }, 300, 'elasticOut');\n    }\n    function onNormal() {\n        sector.stopAnimation(true);\n        sector.animateTo({\n            shape: {\n                r: layout.r\n            }\n        }, 300, 'elasticOut');\n    }\n    sector.off('mouseover').off('mouseout').off('emphasis').off('normal');\n    if (itemModel.get('hoverAnimation') && seriesModel.isAnimationEnabled()) {\n        sector\n            .on('mouseover', onEmphasis)\n            .on('mouseout', onNormal)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal);\n    }\n\n    this._updateLabel(data, idx);\n\n    setHoverStyle(this);\n};\n\npiePieceProto._updateLabel = function (data, idx) {\n\n    var labelLine = this.childAt(1);\n    var labelText = this.childAt(2);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var labelLayout = layout.label;\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    updateProps(labelLine, {\n        shape: {\n            points: labelLayout.linePoints || [\n                [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y]\n            ]\n        }\n    }, seriesModel, idx);\n\n    updateProps(labelText, {\n        style: {\n            x: labelLayout.x,\n            y: labelLayout.y\n        }\n    }, seriesModel, idx);\n    labelText.attr({\n        rotation: labelLayout.rotation,\n        origin: [labelLayout.x, labelLayout.y],\n        z2: 10\n    });\n\n    var labelModel = itemModel.getModel('label');\n    var labelHoverModel = itemModel.getModel('emphasis.label');\n    var labelLineModel = itemModel.getModel('labelLine');\n    var labelLineHoverModel = itemModel.getModel('emphasis.labelLine');\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    setLabelStyle(\n        labelText.style, labelText.hoverStyle = {}, labelModel, labelHoverModel,\n        {\n            labelFetcher: data.hostModel,\n            labelDataIndex: idx,\n            defaultText: data.getName(idx),\n            autoColor: visualColor,\n            useInsideStyle: !!labelLayout.inside\n        },\n        {\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.verticalAlign,\n            opacity: data.getItemVisual(idx, 'opacity')\n        }\n    );\n\n    labelText.ignore = labelText.normalIgnore = !labelModel.get('show');\n    labelText.hoverIgnore = !labelHoverModel.get('show');\n\n    labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show');\n    labelLine.hoverIgnore = !labelLineHoverModel.get('show');\n\n    // Default use item visual color\n    labelLine.setStyle({\n        stroke: visualColor,\n        opacity: data.getItemVisual(idx, 'opacity')\n    });\n    labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());\n\n    labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();\n\n    var smooth = labelLineModel.get('smooth');\n    if (smooth && smooth === true) {\n        smooth = 0.4;\n    }\n    labelLine.setShape({\n        smooth: smooth\n    });\n};\n\ninherits(PiePiece, Group);\n\n\n// Pie view\nvar PieView = Chart.extend({\n\n    type: 'pie',\n\n    init: function () {\n        var sectorGroup = new Group();\n        this._sectorGroup = sectorGroup;\n    },\n\n    render: function (seriesModel, ecModel, api, payload) {\n        if (payload && (payload.from === this.uid)) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var oldData = this._data;\n        var group = this.group;\n\n        var hasAnimation = ecModel.get('animation');\n        var isFirstRender = !oldData;\n        var animationType = seriesModel.get('animationType');\n\n        var onSectorClick = curry(\n            updateDataSelected, this.uid, seriesModel, hasAnimation, api\n        );\n\n        var selectedMode = seriesModel.get('selectedMode');\n\n        data.diff(oldData)\n            .add(function (idx) {\n                var piePiece = new PiePiece(data, idx);\n                // Default expansion animation\n                if (isFirstRender && animationType !== 'scale') {\n                    piePiece.eachChild(function (child) {\n                        child.stopAnimation(true);\n                    });\n                }\n\n                selectedMode && piePiece.on('click', onSectorClick);\n\n                data.setItemGraphicEl(idx, piePiece);\n\n                group.add(piePiece);\n            })\n            .update(function (newIdx, oldIdx) {\n                var piePiece = oldData.getItemGraphicEl(oldIdx);\n\n                piePiece.updateData(data, newIdx);\n\n                piePiece.off('click');\n                selectedMode && piePiece.on('click', onSectorClick);\n                group.add(piePiece);\n                data.setItemGraphicEl(newIdx, piePiece);\n            })\n            .remove(function (idx) {\n                var piePiece = oldData.getItemGraphicEl(idx);\n                group.remove(piePiece);\n            })\n            .execute();\n\n        if (\n            hasAnimation && isFirstRender && data.count() > 0\n            // Default expansion animation\n            && animationType !== 'scale'\n        ) {\n            var shape = data.getItemLayout(0);\n            var r = Math.max(api.getWidth(), api.getHeight()) / 2;\n\n            var removeClipPath = bind(group.removeClipPath, group);\n            group.setClipPath(this._createClipPath(\n                shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel\n            ));\n        }\n        else {\n            // clipPath is used in first-time animation, so remove it when otherwise. See: #8994\n            group.removeClipPath();\n        }\n\n        this._data = data;\n    },\n\n    dispose: function () {},\n\n    _createClipPath: function (\n        cx, cy, r, startAngle, clockwise, cb, seriesModel\n    ) {\n        var clipPath = new Sector({\n            shape: {\n                cx: cx,\n                cy: cy,\n                r0: 0,\n                r: r,\n                startAngle: startAngle,\n                endAngle: startAngle,\n                clockwise: clockwise\n            }\n        });\n\n        initProps(clipPath, {\n            shape: {\n                endAngle: startAngle + (clockwise ? 1 : -1) * Math.PI * 2\n            }\n        }, seriesModel, cb);\n\n        return clipPath;\n    },\n\n    /**\n     * @implement\n     */\n    containPoint: function (point, seriesModel) {\n        var data = seriesModel.getData();\n        var itemLayout = data.getItemLayout(0);\n        if (itemLayout) {\n            var dx = point[0] - itemLayout.cx;\n            var dy = point[1] - itemLayout.cy;\n            var radius = Math.sqrt(dx * dx + dy * dy);\n            return radius <= itemLayout.r && radius >= itemLayout.r0;\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar createDataSelectAction = function (seriesType, actionInfos) {\n    each$1(actionInfos, function (actionInfo) {\n        actionInfo.update = 'updateView';\n        /**\n         * @payload\n         * @property {string} seriesName\n         * @property {string} name\n         */\n        registerAction(actionInfo, function (payload, ecModel) {\n            var selected = {};\n            ecModel.eachComponent(\n                {mainType: 'series', subType: seriesType, query: payload},\n                function (seriesModel) {\n                    if (seriesModel[actionInfo.method]) {\n                        seriesModel[actionInfo.method](\n                            payload.name,\n                            payload.dataIndex\n                        );\n                    }\n                    var data = seriesModel.getData();\n                    // Create selected map\n                    data.each(function (idx) {\n                        var name = data.getName(idx);\n                        selected[name] = seriesModel.isSelected(name)\n                            || false;\n                    });\n                }\n            );\n            return {\n                name: payload.name,\n                selected: selected\n            };\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Pick color from palette for each data item.\n// Applicable for charts that require applying color palette\n// in data level (like pie, funnel, chord).\nvar dataColor = function (seriesType) {\n    return {\n        getTargetSeries: function (ecModel) {\n            // Pie and funnel may use diferrent scope\n            var paletteScope = {};\n            var seiresModelMap = createHashMap();\n\n            ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n                seriesModel.__paletteScope = paletteScope;\n                seiresModelMap.set(seriesModel.uid, seriesModel);\n            });\n\n            return seiresModelMap;\n        },\n        reset: function (seriesModel, ecModel) {\n            var dataAll = seriesModel.getRawData();\n            var idxMap = {};\n            var data = seriesModel.getData();\n\n            data.each(function (idx) {\n                var rawIdx = data.getRawIndex(idx);\n                idxMap[rawIdx] = idx;\n            });\n\n            dataAll.each(function (rawIdx) {\n                var filteredIdx = idxMap[rawIdx];\n\n                // If series.itemStyle.normal.color is a function. itemVisual may be encoded\n                var singleDataColor = filteredIdx != null\n                    && data.getItemVisual(filteredIdx, 'color', true);\n\n                if (!singleDataColor) {\n                    // FIXME Performance\n                    var itemModel = dataAll.getItemModel(rawIdx);\n\n                    var color = itemModel.get('itemStyle.color')\n                        || seriesModel.getColorFromPalette(\n                            dataAll.getName(rawIdx) || (rawIdx + ''), seriesModel.__paletteScope,\n                            dataAll.count()\n                        );\n                    // Legend may use the visual info in data before processed\n                    dataAll.setItemVisual(rawIdx, 'color', color);\n\n                    // Data is not filtered\n                    if (filteredIdx != null) {\n                        data.setItemVisual(filteredIdx, 'color', color);\n                    }\n                }\n                else {\n                    // Set data all color for legend\n                    dataAll.setItemVisual(rawIdx, 'color', singleDataColor);\n                }\n            });\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME emphasis label position is not same with normal label position\n\nfunction adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {\n    list.sort(function (a, b) {\n        return a.y - b.y;\n    });\n\n    function shiftDown(start, end, delta, dir) {\n        for (var j = start; j < end; j++) {\n            list[j].y += delta;\n            if (j > start\n                && j + 1 < end\n                && list[j + 1].y > list[j].y + list[j].height\n            ) {\n                shiftUp(j, delta / 2);\n                return;\n            }\n        }\n\n        shiftUp(end - 1, delta / 2);\n    }\n\n    function shiftUp(end, delta) {\n        for (var j = end; j >= 0; j--) {\n            list[j].y -= delta;\n            if (j > 0\n                && list[j].y > list[j - 1].y + list[j - 1].height\n            ) {\n                break;\n            }\n        }\n    }\n\n    function changeX(list, isDownList, cx, cy, r, dir) {\n        var lastDeltaX = dir > 0\n            ? isDownList                // right-side\n                ? Number.MAX_VALUE      // down\n                : 0                     // up\n            : isDownList                // left-side\n                ? Number.MAX_VALUE      // down\n                : 0;                    // up\n\n        for (var i = 0, l = list.length; i < l; i++) {\n            var deltaY = Math.abs(list[i].y - cy);\n            var length = list[i].len;\n            var length2 = list[i].len2;\n            var deltaX = (deltaY < r + length)\n                ? Math.sqrt(\n                        (r + length + length2) * (r + length + length2)\n                        - deltaY * deltaY\n                    )\n                : Math.abs(list[i].x - cx);\n            if (isDownList && deltaX >= lastDeltaX) {\n                // right-down, left-down\n                deltaX = lastDeltaX - 10;\n            }\n            if (!isDownList && deltaX <= lastDeltaX) {\n                // right-up, left-up\n                deltaX = lastDeltaX + 10;\n            }\n\n            list[i].x = cx + deltaX * dir;\n            lastDeltaX = deltaX;\n        }\n    }\n\n    var lastY = 0;\n    var delta;\n    var len = list.length;\n    var upList = [];\n    var downList = [];\n    for (var i = 0; i < len; i++) {\n        delta = list[i].y - lastY;\n        if (delta < 0) {\n            shiftDown(i, len, -delta, dir);\n        }\n        lastY = list[i].y + list[i].height;\n    }\n    if (viewHeight - lastY < 0) {\n        shiftUp(len - 1, lastY - viewHeight);\n    }\n    for (var i = 0; i < len; i++) {\n        if (list[i].y >= cy) {\n            downList.push(list[i]);\n        }\n        else {\n            upList.push(list[i]);\n        }\n    }\n    changeX(upList, false, cx, cy, r, dir);\n    changeX(downList, true, cx, cy, r, dir);\n}\n\nfunction avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) {\n    var leftList = [];\n    var rightList = [];\n    for (var i = 0; i < labelLayoutList.length; i++) {\n        if (isPositionCenter(labelLayoutList[i])) {\n            continue;\n        }\n        if (labelLayoutList[i].x < cx) {\n            leftList.push(labelLayoutList[i]);\n        }\n        else {\n            rightList.push(labelLayoutList[i]);\n        }\n    }\n\n    adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight);\n    adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight);\n\n    for (var i = 0; i < labelLayoutList.length; i++) {\n        if (isPositionCenter(labelLayoutList[i])) {\n            continue;\n        }\n        var linePoints = labelLayoutList[i].linePoints;\n        if (linePoints) {\n            var dist = linePoints[1][0] - linePoints[2][0];\n            if (labelLayoutList[i].x < cx) {\n                linePoints[2][0] = labelLayoutList[i].x + 3;\n            }\n            else {\n                linePoints[2][0] = labelLayoutList[i].x - 3;\n            }\n            linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y;\n            linePoints[1][0] = linePoints[2][0] + dist;\n        }\n    }\n}\n\nfunction isPositionCenter(layout) {\n    // Not change x for center label\n    return layout.position === 'center';\n}\n\nvar labelLayout = function (seriesModel, r, viewWidth, viewHeight) {\n    var data = seriesModel.getData();\n    var labelLayoutList = [];\n    var cx;\n    var cy;\n    var hasLabelRotate = false;\n\n    data.each(function (idx) {\n        var layout = data.getItemLayout(idx);\n\n        var itemModel = data.getItemModel(idx);\n        var labelModel = itemModel.getModel('label');\n        // Use position in normal or emphasis\n        var labelPosition = labelModel.get('position') || itemModel.get('emphasis.label.position');\n\n        var labelLineModel = itemModel.getModel('labelLine');\n        var labelLineLen = labelLineModel.get('length');\n        var labelLineLen2 = labelLineModel.get('length2');\n\n        var midAngle = (layout.startAngle + layout.endAngle) / 2;\n        var dx = Math.cos(midAngle);\n        var dy = Math.sin(midAngle);\n\n        var textX;\n        var textY;\n        var linePoints;\n        var textAlign;\n\n        cx = layout.cx;\n        cy = layout.cy;\n\n        var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';\n        if (labelPosition === 'center') {\n            textX = layout.cx;\n            textY = layout.cy;\n            textAlign = 'center';\n        }\n        else {\n            var x1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dx : layout.r * dx) + cx;\n            var y1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dy : layout.r * dy) + cy;\n\n            textX = x1 + dx * 3;\n            textY = y1 + dy * 3;\n\n            if (!isLabelInside) {\n                // For roseType\n                var x2 = x1 + dx * (labelLineLen + r - layout.r);\n                var y2 = y1 + dy * (labelLineLen + r - layout.r);\n                var x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2);\n                var y3 = y2;\n\n                textX = x3 + (dx < 0 ? -5 : 5);\n                textY = y3;\n                linePoints = [[x1, y1], [x2, y2], [x3, y3]];\n            }\n\n            textAlign = isLabelInside ? 'center' : (dx > 0 ? 'left' : 'right');\n        }\n        var font = labelModel.getFont();\n\n        var labelRotate = labelModel.get('rotate')\n            ? (dx < 0 ? -midAngle + Math.PI : -midAngle) : 0;\n        var text = seriesModel.getFormattedLabel(idx, 'normal')\n                    || data.getName(idx);\n        var textRect = getBoundingRect(\n            text, font, textAlign, 'top'\n        );\n        hasLabelRotate = !!labelRotate;\n        layout.label = {\n            x: textX,\n            y: textY,\n            position: labelPosition,\n            height: textRect.height,\n            len: labelLineLen,\n            len2: labelLineLen2,\n            linePoints: linePoints,\n            textAlign: textAlign,\n            verticalAlign: 'middle',\n            rotation: labelRotate,\n            inside: isLabelInside\n        };\n\n        // Not layout the inside label\n        if (!isLabelInside) {\n            labelLayoutList.push(layout.label);\n        }\n    });\n    if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {\n        avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar PI2$4 = Math.PI * 2;\nvar RADIAN = Math.PI / 180;\n\nvar pieLayout = function (seriesType, ecModel, api, payload) {\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n\n        var center = seriesModel.get('center');\n        var radius = seriesModel.get('radius');\n\n        if (!isArray(radius)) {\n            radius = [0, radius];\n        }\n        if (!isArray(center)) {\n            center = [center, center];\n        }\n\n        var width = api.getWidth();\n        var height = api.getHeight();\n        var size = Math.min(width, height);\n        var cx = parsePercent$1(center[0], width);\n        var cy = parsePercent$1(center[1], height);\n        var r0 = parsePercent$1(radius[0], size / 2);\n        var r = parsePercent$1(radius[1], size / 2);\n\n        var startAngle = -seriesModel.get('startAngle') * RADIAN;\n\n        var minAngle = seriesModel.get('minAngle') * RADIAN;\n\n        var validDataCount = 0;\n        data.each(valueDim, function (value) {\n            !isNaN(value) && validDataCount++;\n        });\n\n        var sum = data.getSum(valueDim);\n        // Sum may be 0\n        var unitRadian = Math.PI / (sum || validDataCount) * 2;\n\n        var clockwise = seriesModel.get('clockwise');\n\n        var roseType = seriesModel.get('roseType');\n        var stillShowZeroSum = seriesModel.get('stillShowZeroSum');\n\n        // [0...max]\n        var extent = data.getDataExtent(valueDim);\n        extent[0] = 0;\n\n        // In the case some sector angle is smaller than minAngle\n        var restAngle = PI2$4;\n        var valueSumLargerThanMinAngle = 0;\n\n        var currentAngle = startAngle;\n        var dir = clockwise ? 1 : -1;\n\n        data.each(valueDim, function (value, idx) {\n            var angle;\n            if (isNaN(value)) {\n                data.setItemLayout(idx, {\n                    angle: NaN,\n                    startAngle: NaN,\n                    endAngle: NaN,\n                    clockwise: clockwise,\n                    cx: cx,\n                    cy: cy,\n                    r0: r0,\n                    r: roseType\n                        ? NaN\n                        : r\n                });\n                return;\n            }\n\n            // FIXME 兼容 2.0 但是 roseType 是 area 的时候才是这样？\n            if (roseType !== 'area') {\n                angle = (sum === 0 && stillShowZeroSum)\n                    ? unitRadian : (value * unitRadian);\n            }\n            else {\n                angle = PI2$4 / validDataCount;\n            }\n\n            if (angle < minAngle) {\n                angle = minAngle;\n                restAngle -= minAngle;\n            }\n            else {\n                valueSumLargerThanMinAngle += value;\n            }\n\n            var endAngle = currentAngle + dir * angle;\n            data.setItemLayout(idx, {\n                angle: angle,\n                startAngle: currentAngle,\n                endAngle: endAngle,\n                clockwise: clockwise,\n                cx: cx,\n                cy: cy,\n                r0: r0,\n                r: roseType\n                    ? linearMap(value, extent, [r0, r])\n                    : r\n            });\n\n            currentAngle = endAngle;\n        });\n\n        // Some sector is constrained by minAngle\n        // Rest sectors needs recalculate angle\n        if (restAngle < PI2$4 && validDataCount) {\n            // Average the angle if rest angle is not enough after all angles is\n            // Constrained by minAngle\n            if (restAngle <= 1e-3) {\n                var angle = PI2$4 / validDataCount;\n                data.each(valueDim, function (value, idx) {\n                    if (!isNaN(value)) {\n                        var layout = data.getItemLayout(idx);\n                        layout.angle = angle;\n                        layout.startAngle = startAngle + dir * idx * angle;\n                        layout.endAngle = startAngle + dir * (idx + 1) * angle;\n                    }\n                });\n            }\n            else {\n                unitRadian = restAngle / valueSumLargerThanMinAngle;\n                currentAngle = startAngle;\n                data.each(valueDim, function (value, idx) {\n                    if (!isNaN(value)) {\n                        var layout = data.getItemLayout(idx);\n                        var angle = layout.angle === minAngle\n                            ? minAngle : value * unitRadian;\n                        layout.startAngle = currentAngle;\n                        layout.endAngle = currentAngle + dir * angle;\n                        currentAngle += dir * angle;\n                    }\n                });\n            }\n        }\n\n        labelLayout(seriesModel, r, width, height);\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar dataFilter = function (seriesType) {\n    return {\n        seriesType: seriesType,\n        reset: function (seriesModel, ecModel) {\n            var legendModels = ecModel.findComponents({\n                mainType: 'legend'\n            });\n            if (!legendModels || !legendModels.length) {\n                return;\n            }\n            var data = seriesModel.getData();\n            data.filterSelf(function (idx) {\n                var name = data.getName(idx);\n                // If in any legend component the status is not selected.\n                for (var i = 0; i < legendModels.length; i++) {\n                    if (!legendModels[i].isSelected(name)) {\n                        return false;\n                    }\n                }\n                return true;\n            });\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\ncreateDataSelectAction('pie', [{\n    type: 'pieToggleSelect',\n    event: 'pieselectchanged',\n    method: 'toggleSelected'\n}, {\n    type: 'pieSelect',\n    event: 'pieselected',\n    method: 'select'\n}, {\n    type: 'pieUnSelect',\n    event: 'pieunselected',\n    method: 'unSelect'\n}]);\n\nregisterVisual(dataColor('pie'));\nregisterLayout(curry(pieLayout, 'pie'));\nregisterProcessor(dataFilter('pie'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.scatter',\n\n    dependencies: ['grid', 'polar', 'geo', 'singleAxis', 'calendar'],\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    brushSelector: 'point',\n\n    getProgressive: function () {\n        var progressive = this.option.progressive;\n        if (progressive == null) {\n            // PENDING\n            return this.option.large ? 5e3 : this.get('progressive');\n        }\n        return progressive;\n    },\n\n    getProgressiveThreshold: function () {\n        var progressiveThreshold = this.option.progressiveThreshold;\n        if (progressiveThreshold == null) {\n            // PENDING\n            return this.option.large ? 1e4 : this.get('progressiveThreshold');\n        }\n        return progressiveThreshold;\n    },\n\n    defaultOption: {\n        coordinateSystem: 'cartesian2d',\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // Polar coordinate system\n        // polarIndex: 0,\n\n        // Geo coordinate system\n        // geoIndex: 0,\n\n        // symbol: null,        // 图形类型\n        symbolSize: 10,          // 图形大小，半宽（半径）参数，当图形为方向或菱形则总宽度为symbolSize * 2\n        // symbolRotate: null,  // 图形旋转控制\n\n        large: false,\n        // Available when large is true\n        largeThreshold: 2000,\n        // cursor: null,\n\n        // label: {\n            // show: false\n            // distance: 5,\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n            // position: 默认自适应，水平布局为'top'，垂直布局为'right'，可选为\n            //           'inside'|'left'|'right'|'top'|'bottom'\n            // 默认使用全局文本样式，详见TEXTSTYLE\n        // },\n        itemStyle: {\n            opacity: 0.8\n            // color: 各异\n        }\n\n        // progressive: null\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\n// TODO Batch by color\n\nvar BOOST_SIZE_THRESHOLD = 4;\n\nvar LargeSymbolPath = extendShape({\n\n    shape: {\n        points: null\n    },\n\n    symbolProxy: null,\n\n    buildPath: function (path, shape) {\n        var points = shape.points;\n        var size = shape.size;\n\n        var symbolProxy = this.symbolProxy;\n        var symbolProxyShape = symbolProxy.shape;\n        var ctx = path.getContext ? path.getContext() : path;\n        var canBoost = ctx && size[0] < BOOST_SIZE_THRESHOLD;\n\n        // Do draw in afterBrush.\n        if (canBoost) {\n            return;\n        }\n\n        for (var i = 0; i < points.length;) {\n            var x = points[i++];\n            var y = points[i++];\n\n            if (isNaN(x) || isNaN(y)) {\n                continue;\n            }\n\n            symbolProxyShape.x = x - size[0] / 2;\n            symbolProxyShape.y = y - size[1] / 2;\n            symbolProxyShape.width = size[0];\n            symbolProxyShape.height = size[1];\n\n            symbolProxy.buildPath(path, symbolProxyShape, true);\n        }\n    },\n\n    afterBrush: function (ctx) {\n        var shape = this.shape;\n        var points = shape.points;\n        var size = shape.size;\n        var canBoost = size[0] < BOOST_SIZE_THRESHOLD;\n\n        if (!canBoost) {\n            return;\n        }\n\n        this.setTransform(ctx);\n        // PENDING If style or other canvas status changed?\n        for (var i = 0; i < points.length;) {\n            var x = points[i++];\n            var y = points[i++];\n            if (isNaN(x) || isNaN(y)) {\n                continue;\n            }\n            // fillRect is faster than building a rect path and draw.\n            // And it support light globalCompositeOperation.\n            ctx.fillRect(\n                x - size[0] / 2, y - size[1] / 2,\n                size[0], size[1]\n            );\n        }\n\n        this.restoreTransform(ctx);\n    },\n\n    findDataIndex: function (x, y) {\n        // TODO ???\n        // Consider transform\n\n        var shape = this.shape;\n        var points = shape.points;\n        var size = shape.size;\n\n        var w = Math.max(size[0], 4);\n        var h = Math.max(size[1], 4);\n\n        // Not consider transform\n        // Treat each element as a rect\n        // top down traverse\n        for (var idx = points.length / 2 - 1; idx >= 0; idx--) {\n            var i = idx * 2;\n            var x0 = points[i] - w / 2;\n            var y0 = points[i + 1] - h / 2;\n            if (x >= x0 && y >= y0 && x <= x0 + w && y <= y0 + h) {\n                return idx;\n            }\n        }\n\n        return -1;\n    }\n});\n\nfunction LargeSymbolDraw() {\n    this.group = new Group();\n}\n\nvar largeSymbolProto = LargeSymbolDraw.prototype;\n\nlargeSymbolProto.isPersistent = function () {\n    return !this._incremental;\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n */\nlargeSymbolProto.updateData = function (data) {\n    this.group.removeAll();\n    var symbolEl = new LargeSymbolPath({\n        rectHover: true,\n        cursor: 'default'\n    });\n\n    symbolEl.setShape({\n        points: data.getLayout('symbolPoints')\n    });\n    this._setCommon(symbolEl, data);\n    this.group.add(symbolEl);\n\n    this._incremental = null;\n};\n\nlargeSymbolProto.updateLayout = function (data) {\n    if (this._incremental) {\n        return;\n    }\n\n    var points = data.getLayout('symbolPoints');\n    this.group.eachChild(function (child) {\n        if (child.startIndex != null) {\n            var len = (child.endIndex - child.startIndex) * 2;\n            var byteOffset = child.startIndex * 4 * 2;\n            points = new Float32Array(points.buffer, byteOffset, len);\n        }\n        child.setShape('points', points);\n    });\n};\n\nlargeSymbolProto.incrementalPrepareUpdate = function (data) {\n    this.group.removeAll();\n\n    this._clearIncremental();\n    // Only use incremental displayables when data amount is larger than 2 million.\n    // PENDING Incremental data?\n    if (data.count() > 2e6) {\n        if (!this._incremental) {\n            this._incremental = new IncrementalDisplayble({\n                silent: true\n            });\n        }\n        this.group.add(this._incremental);\n    }\n    else {\n        this._incremental = null;\n    }\n};\n\nlargeSymbolProto.incrementalUpdate = function (taskParams, data) {\n    var symbolEl;\n    if (this._incremental) {\n        symbolEl = new LargeSymbolPath();\n        this._incremental.addDisplayable(symbolEl, true);\n    }\n    else {\n        symbolEl = new LargeSymbolPath({\n            rectHover: true,\n            cursor: 'default',\n            startIndex: taskParams.start,\n            endIndex: taskParams.end\n        });\n        symbolEl.incremental = true;\n        this.group.add(symbolEl);\n    }\n\n    symbolEl.setShape({\n        points: data.getLayout('symbolPoints')\n    });\n    this._setCommon(symbolEl, data, !!this._incremental);\n};\n\nlargeSymbolProto._setCommon = function (symbolEl, data, isIncremental) {\n    var hostModel = data.hostModel;\n\n    // TODO\n    // if (data.hasItemVisual.symbolSize) {\n    //     // TODO typed array?\n    //     symbolEl.setShape('sizes', data.mapArray(\n    //         function (idx) {\n    //             var size = data.getItemVisual(idx, 'symbolSize');\n    //             return (size instanceof Array) ? size : [size, size];\n    //         }\n    //     ));\n    // }\n    // else {\n    var size = data.getVisual('symbolSize');\n    symbolEl.setShape('size', (size instanceof Array) ? size : [size, size]);\n    // }\n\n    // Create symbolProxy to build path for each data\n    symbolEl.symbolProxy = createSymbol(\n        data.getVisual('symbol'), 0, 0, 0, 0\n    );\n    // Use symbolProxy setColor method\n    symbolEl.setColor = symbolEl.symbolProxy.setColor;\n\n    var extrudeShadow = symbolEl.shape.size[0] < BOOST_SIZE_THRESHOLD;\n    symbolEl.useStyle(\n        // Draw shadow when doing fillRect is extremely slow.\n        hostModel.getModel('itemStyle').getItemStyle(extrudeShadow ? ['color', 'shadowBlur', 'shadowColor'] : ['color'])\n    );\n\n    var visualColor = data.getVisual('color');\n    if (visualColor) {\n        symbolEl.setColor(visualColor);\n    }\n\n    if (!isIncremental) {\n        // Enable tooltip\n        // PENDING May have performance issue when path is extremely large\n        symbolEl.seriesIndex = hostModel.seriesIndex;\n        symbolEl.on('mousemove', function (e) {\n            symbolEl.dataIndex = null;\n            var dataIndex = symbolEl.findDataIndex(e.offsetX, e.offsetY);\n            if (dataIndex >= 0) {\n                // Provide dataIndex for tooltip\n                symbolEl.dataIndex = dataIndex + (symbolEl.startIndex || 0);\n            }\n        });\n    }\n};\n\nlargeSymbolProto.remove = function () {\n    this._clearIncremental();\n    this._incremental = null;\n    this.group.removeAll();\n};\n\nlargeSymbolProto._clearIncremental = function () {\n    var incremental = this._incremental;\n    if (incremental) {\n        incremental.clearDisplaybles();\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendChartView({\n\n    type: 'scatter',\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        var symbolDraw = this._updateSymbolDraw(data, seriesModel);\n        symbolDraw.updateData(data);\n\n        this._finished = true;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var symbolDraw = this._updateSymbolDraw(data, seriesModel);\n\n        symbolDraw.incrementalPrepareUpdate(data);\n\n        this._finished = false;\n    },\n\n    incrementalRender: function (taskParams, seriesModel, ecModel) {\n        this._symbolDraw.incrementalUpdate(taskParams, seriesModel.getData());\n\n        this._finished = taskParams.end === seriesModel.getData().count();\n    },\n\n    updateTransform: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        // Must mark group dirty and make sure the incremental layer will be cleared\n        // PENDING\n        this.group.dirty();\n\n        if (!this._finished || data.count() > 1e4 || !this._symbolDraw.isPersistent()) {\n            return {\n                update: true\n            };\n        }\n        else {\n            var res = pointsLayout().reset(seriesModel);\n            if (res.progress) {\n                res.progress({ start: 0, end: data.count() }, data);\n            }\n\n            this._symbolDraw.updateLayout(data);\n        }\n    },\n\n    _updateSymbolDraw: function (data, seriesModel) {\n        var symbolDraw = this._symbolDraw;\n        var pipelineContext = seriesModel.pipelineContext;\n        var isLargeDraw = pipelineContext.large;\n\n        if (!symbolDraw || isLargeDraw !== this._isLargeDraw) {\n            symbolDraw && symbolDraw.remove();\n            symbolDraw = this._symbolDraw = isLargeDraw\n                ? new LargeSymbolDraw()\n                : new SymbolDraw();\n            this._isLargeDraw = isLargeDraw;\n            this.group.removeAll();\n        }\n\n        this.group.add(symbolDraw.group);\n\n        return symbolDraw;\n    },\n\n    remove: function (ecModel, api) {\n        this._symbolDraw && this._symbolDraw.remove(true);\n        this._symbolDraw = null;\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import * as zrUtil from 'zrender/src/core/util';\n\n// In case developer forget to include grid component\nregisterVisual(visualSymbol('scatter', 'circle'));\nregisterLayout(pointsLayout('scatter'));\n\n// echarts.registerProcessor(function (ecModel, api) {\n//     ecModel.eachSeriesByType('scatter', function (seriesModel) {\n//         var data = seriesModel.getData();\n//         var coordSys = seriesModel.coordinateSystem;\n//         if (coordSys.type !== 'geo') {\n//             return;\n//         }\n//         var startPt = coordSys.pointToData([0, 0]);\n//         var endPt = coordSys.pointToData([api.getWidth(), api.getHeight()]);\n\n//         var dims = zrUtil.map(coordSys.dimensions, function (dim) {\n//             return data.mapDimension(dim);\n//         });\n//         var range = {};\n//         range[dims[0]] = [Math.min(startPt[0], endPt[0]), Math.max(startPt[0], endPt[0])];\n//         range[dims[1]] = [Math.min(startPt[1], endPt[1]), Math.max(startPt[1], endPt[1])];\n\n//         data.selectRange(range);\n//     });\n// });\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// -------------\n// Preprocessor\n// -------------\n\nregisterPreprocessor(function (option) {\n    var graphicOption = option.graphic;\n\n    // Convert\n    // {graphic: [{left: 10, type: 'circle'}, ...]}\n    // or\n    // {graphic: {left: 10, type: 'circle'}}\n    // to\n    // {graphic: [{elements: [{left: 10, type: 'circle'}, ...]}]}\n    if (isArray(graphicOption)) {\n        if (!graphicOption[0] || !graphicOption[0].elements) {\n            option.graphic = [{elements: graphicOption}];\n        }\n        else {\n            // Only one graphic instance can be instantiated. (We dont\n            // want that too many views are created in echarts._viewMap)\n            option.graphic = [option.graphic[0]];\n        }\n    }\n    else if (graphicOption && !graphicOption.elements) {\n        option.graphic = [{elements: [graphicOption]}];\n    }\n});\n\n// ------\n// Model\n// ------\n\nvar GraphicModel = extendComponentModel({\n\n    type: 'graphic',\n\n    defaultOption: {\n\n        // Extra properties for each elements:\n        //\n        // left/right/top/bottom: (like 12, '22%', 'center', default undefined)\n        //      If left/rigth is set, shape.x/shape.cx/position will not be used.\n        //      If top/bottom is set, shape.y/shape.cy/position will not be used.\n        //      This mechanism is useful when you want to position a group/element\n        //      against the right side or the center of this container.\n        //\n        // width/height: (can only be pixel value, default 0)\n        //      Only be used to specify contianer(group) size, if needed. And\n        //      can not be percentage value (like '33%'). See the reason in the\n        //      layout algorithm below.\n        //\n        // bounding: (enum: 'all' (default) | 'raw')\n        //      Specify how to calculate boundingRect when locating.\n        //      'all': Get uioned and transformed boundingRect\n        //          from both itself and its descendants.\n        //          This mode simplies confining a group of elements in the bounding\n        //          of their ancester container (e.g., using 'right: 0').\n        //      'raw': Only use the boundingRect of itself and before transformed.\n        //          This mode is similar to css behavior, which is useful when you\n        //          want an element to be able to overflow its container. (Consider\n        //          a rotated circle needs to be located in a corner.)\n        // info: custom info. enables user to mount some info on elements and use them\n        //      in event handlers. Update them only when user specified, otherwise, remain.\n\n        // Note: elements is always behind its ancestors in this elements array.\n        elements: [],\n        parentId: null\n    },\n\n    /**\n     * Save el options for the sake of the performance (only update modified graphics).\n     * The order is the same as those in option. (ancesters -> descendants)\n     *\n     * @private\n     * @type {Array.<Object>}\n     */\n    _elOptionsToUpdate: null,\n\n    /**\n     * @override\n     */\n    mergeOption: function (option) {\n        // Prevent default merge to elements\n        var elements = this.option.elements;\n        this.option.elements = null;\n\n        GraphicModel.superApply(this, 'mergeOption', arguments);\n\n        this.option.elements = elements;\n    },\n\n    /**\n     * @override\n     */\n    optionUpdated: function (newOption, isInit) {\n        var thisOption = this.option;\n        var newList = (isInit ? thisOption : newOption).elements;\n        var existList = thisOption.elements = isInit ? [] : thisOption.elements;\n\n        var flattenedList = [];\n        this._flatten(newList, flattenedList);\n\n        var mappingResult = mappingToExists(existList, flattenedList);\n        makeIdAndName(mappingResult);\n\n        // Clear elOptionsToUpdate\n        var elOptionsToUpdate = this._elOptionsToUpdate = [];\n\n        each$1(mappingResult, function (resultItem, index) {\n            var newElOption = resultItem.option;\n\n            if (__DEV__) {\n                assert$1(\n                    isObject$1(newElOption) || resultItem.exist,\n                    'Empty graphic option definition'\n                );\n            }\n\n            if (!newElOption) {\n                return;\n            }\n\n            elOptionsToUpdate.push(newElOption);\n\n            setKeyInfoToNewElOption(resultItem, newElOption);\n\n            mergeNewElOptionToExist(existList, index, newElOption);\n\n            setLayoutInfoToExist(existList[index], newElOption);\n\n        }, this);\n\n        // Clean\n        for (var i = existList.length - 1; i >= 0; i--) {\n            if (existList[i] == null) {\n                existList.splice(i, 1);\n            }\n            else {\n                // $action should be volatile, otherwise option gotten from\n                // `getOption` will contain unexpected $action.\n                delete existList[i].$action;\n            }\n        }\n    },\n\n    /**\n     * Convert\n     * [{\n     *  type: 'group',\n     *  id: 'xx',\n     *  children: [{type: 'circle'}, {type: 'polygon'}]\n     * }]\n     * to\n     * [\n     *  {type: 'group', id: 'xx'},\n     *  {type: 'circle', parentId: 'xx'},\n     *  {type: 'polygon', parentId: 'xx'}\n     * ]\n     *\n     * @private\n     * @param {Array.<Object>} optionList option list\n     * @param {Array.<Object>} result result of flatten\n     * @param {Object} parentOption parent option\n     */\n    _flatten: function (optionList, result, parentOption) {\n        each$1(optionList, function (option) {\n            if (!option) {\n                return;\n            }\n\n            if (parentOption) {\n                option.parentOption = parentOption;\n            }\n\n            result.push(option);\n\n            var children = option.children;\n            if (option.type === 'group' && children) {\n                this._flatten(children, result, option);\n            }\n            // Deleting for JSON output, and for not affecting group creation.\n            delete option.children;\n        }, this);\n    },\n\n    // FIXME\n    // Pass to view using payload? setOption has a payload?\n    useElOptionsToUpdate: function () {\n        var els = this._elOptionsToUpdate;\n        // Clear to avoid render duplicately when zooming.\n        this._elOptionsToUpdate = null;\n        return els;\n    }\n});\n\n// -----\n// View\n// -----\n\nextendComponentView({\n\n    type: 'graphic',\n\n    /**\n     * @override\n     */\n    init: function (ecModel, api) {\n\n        /**\n         * @private\n         * @type {module:zrender/core/util.HashMap}\n         */\n        this._elMap = createHashMap();\n\n        /**\n         * @private\n         * @type {module:echarts/graphic/GraphicModel}\n         */\n        this._lastGraphicModel;\n    },\n\n    /**\n     * @override\n     */\n    render: function (graphicModel, ecModel, api) {\n\n        // Having leveraged between use cases and algorithm complexity, a very\n        // simple layout mechanism is used:\n        // The size(width/height) can be determined by itself or its parent (not\n        // implemented yet), but can not by its children. (Top-down travel)\n        // The location(x/y) can be determined by the bounding rect of itself\n        // (can including its descendants or not) and the size of its parent.\n        // (Bottom-up travel)\n\n        // When `chart.clear()` or `chart.setOption({...}, true)` with the same id,\n        // view will be reused.\n        if (graphicModel !== this._lastGraphicModel) {\n            this._clear();\n        }\n        this._lastGraphicModel = graphicModel;\n\n        this._updateElements(graphicModel);\n        this._relocate(graphicModel, api);\n    },\n\n    /**\n     * Update graphic elements.\n     *\n     * @private\n     * @param {Object} graphicModel graphic model\n     */\n    _updateElements: function (graphicModel) {\n        var elOptionsToUpdate = graphicModel.useElOptionsToUpdate();\n\n        if (!elOptionsToUpdate) {\n            return;\n        }\n\n        var elMap = this._elMap;\n        var rootGroup = this.group;\n\n        // Top-down tranverse to assign graphic settings to each elements.\n        each$1(elOptionsToUpdate, function (elOption) {\n            var $action = elOption.$action;\n            var id = elOption.id;\n            var existEl = elMap.get(id);\n            var parentId = elOption.parentId;\n            var targetElParent = parentId != null ? elMap.get(parentId) : rootGroup;\n\n            var elOptionStyle = elOption.style;\n            if (elOption.type === 'text' && elOptionStyle) {\n                // In top/bottom mode, textVerticalAlign should not be used, which cause\n                // inaccurately locating.\n                if (elOption.hv && elOption.hv[1]) {\n                    elOptionStyle.textVerticalAlign = elOptionStyle.textBaseline = null;\n                }\n\n                // Compatible with previous setting: both support fill and textFill,\n                // stroke and textStroke.\n                !elOptionStyle.hasOwnProperty('textFill') && elOptionStyle.fill && (\n                    elOptionStyle.textFill = elOptionStyle.fill\n                );\n                !elOptionStyle.hasOwnProperty('textStroke') && elOptionStyle.stroke && (\n                    elOptionStyle.textStroke = elOptionStyle.stroke\n                );\n            }\n\n            // Remove unnecessary props to avoid potential problems.\n            var elOptionCleaned = getCleanedElOption(elOption);\n\n            // For simple, do not support parent change, otherwise reorder is needed.\n            if (__DEV__) {\n                existEl && assert$1(\n                    targetElParent === existEl.parent,\n                    'Changing parent is not supported.'\n                );\n            }\n\n            if (!$action || $action === 'merge') {\n                existEl\n                    ? existEl.attr(elOptionCleaned)\n                    : createEl(id, targetElParent, elOptionCleaned, elMap);\n            }\n            else if ($action === 'replace') {\n                removeEl(existEl, elMap);\n                createEl(id, targetElParent, elOptionCleaned, elMap);\n            }\n            else if ($action === 'remove') {\n                removeEl(existEl, elMap);\n            }\n\n            var el = elMap.get(id);\n            if (el) {\n                el.__ecGraphicWidth = elOption.width;\n                el.__ecGraphicHeight = elOption.height;\n                setEventData(el, graphicModel, elOption);\n            }\n        });\n    },\n\n    /**\n     * Locate graphic elements.\n     *\n     * @private\n     * @param {Object} graphicModel graphic model\n     * @param {module:echarts/ExtensionAPI} api extension API\n     */\n    _relocate: function (graphicModel, api) {\n        var elOptions = graphicModel.option.elements;\n        var rootGroup = this.group;\n        var elMap = this._elMap;\n\n        // Bottom-up tranvese all elements (consider ec resize) to locate elements.\n        for (var i = elOptions.length - 1; i >= 0; i--) {\n            var elOption = elOptions[i];\n            var el = elMap.get(elOption.id);\n\n            if (!el) {\n                continue;\n            }\n\n            var parentEl = el.parent;\n            var containerInfo = parentEl === rootGroup\n                ? {\n                    width: api.getWidth(),\n                    height: api.getHeight()\n                }\n                : { // Like 'position:absolut' in css, default 0.\n                    width: parentEl.__ecGraphicWidth || 0,\n                    height: parentEl.__ecGraphicHeight || 0\n                };\n\n            positionElement(\n                el, elOption, containerInfo, null,\n                {hv: elOption.hv, boundingMode: elOption.bounding}\n            );\n        }\n    },\n\n    /**\n     * Clear all elements.\n     *\n     * @private\n     */\n    _clear: function () {\n        var elMap = this._elMap;\n        elMap.each(function (el) {\n            removeEl(el, elMap);\n        });\n        this._elMap = createHashMap();\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._clear();\n    }\n});\n\nfunction createEl(id, targetElParent, elOption, elMap) {\n    var graphicType = elOption.type;\n\n    if (__DEV__) {\n        assert$1(graphicType, 'graphic type MUST be set');\n    }\n\n    var Clz = graphic[graphicType.charAt(0).toUpperCase() + graphicType.slice(1)];\n\n    if (__DEV__) {\n        assert$1(Clz, 'graphic type can not be found');\n    }\n\n    var el = new Clz(elOption);\n    targetElParent.add(el);\n    elMap.set(id, el);\n    el.__ecGraphicId = id;\n}\n\nfunction removeEl(existEl, elMap) {\n    var existElParent = existEl && existEl.parent;\n    if (existElParent) {\n        existEl.type === 'group' && existEl.traverse(function (el) {\n            removeEl(el, elMap);\n        });\n        elMap.removeKey(existEl.__ecGraphicId);\n        existElParent.remove(existEl);\n    }\n}\n\n// Remove unnecessary props to avoid potential problems.\nfunction getCleanedElOption(elOption) {\n    elOption = extend({}, elOption);\n    each$1(\n        ['id', 'parentId', '$action', 'hv', 'bounding'].concat(LOCATION_PARAMS),\n        function (name) {\n            delete elOption[name];\n        }\n    );\n    return elOption;\n}\n\nfunction isSetLoc(obj, props) {\n    var isSet;\n    each$1(props, function (prop) {\n        obj[prop] != null && obj[prop] !== 'auto' && (isSet = true);\n    });\n    return isSet;\n}\n\nfunction setKeyInfoToNewElOption(resultItem, newElOption) {\n    var existElOption = resultItem.exist;\n\n    // Set id and type after id assigned.\n    newElOption.id = resultItem.keyInfo.id;\n    !newElOption.type && existElOption && (newElOption.type = existElOption.type);\n\n    // Set parent id if not specified\n    if (newElOption.parentId == null) {\n        var newElParentOption = newElOption.parentOption;\n        if (newElParentOption) {\n            newElOption.parentId = newElParentOption.id;\n        }\n        else if (existElOption) {\n            newElOption.parentId = existElOption.parentId;\n        }\n    }\n\n    // Clear\n    newElOption.parentOption = null;\n}\n\nfunction mergeNewElOptionToExist(existList, index, newElOption) {\n    // Update existing options, for `getOption` feature.\n    var newElOptCopy = extend({}, newElOption);\n    var existElOption = existList[index];\n\n    var $action = newElOption.$action || 'merge';\n    if ($action === 'merge') {\n        if (existElOption) {\n\n            if (__DEV__) {\n                var newType = newElOption.type;\n                assert$1(\n                    !newType || existElOption.type === newType,\n                    'Please set $action: \"replace\" to change `type`'\n                );\n            }\n\n            // We can ensure that newElOptCopy and existElOption are not\n            // the same object, so `merge` will not change newElOptCopy.\n            merge(existElOption, newElOptCopy, true);\n            // Rigid body, use ignoreSize.\n            mergeLayoutParam(existElOption, newElOptCopy, {ignoreSize: true});\n            // Will be used in render.\n            copyLayoutParams(newElOption, existElOption);\n        }\n        else {\n            existList[index] = newElOptCopy;\n        }\n    }\n    else if ($action === 'replace') {\n        existList[index] = newElOptCopy;\n    }\n    else if ($action === 'remove') {\n        // null will be cleaned later.\n        existElOption && (existList[index] = null);\n    }\n}\n\nfunction setLayoutInfoToExist(existItem, newElOption) {\n    if (!existItem) {\n        return;\n    }\n    existItem.hv = newElOption.hv = [\n        // Rigid body, dont care `width`.\n        isSetLoc(newElOption, ['left', 'right']),\n        // Rigid body, dont care `height`.\n        isSetLoc(newElOption, ['top', 'bottom'])\n    ];\n    // Give default group size. Otherwise layout error may occur.\n    if (existItem.type === 'group') {\n        existItem.width == null && (existItem.width = newElOption.width = 0);\n        existItem.height == null && (existItem.height = newElOption.height = 0);\n    }\n}\n\nfunction setEventData(el, graphicModel, elOption) {\n    var eventData = el.eventData;\n    // Simple optimize for large amount of elements that no need event.\n    if (!el.silent && !el.ignore && !eventData) {\n        eventData = el.eventData = {\n            componentType: 'graphic',\n            componentIndex: graphicModel.componentIndex,\n            name: el.name\n        };\n    }\n\n    // `elOption.info` enables user to mount some info on\n    // elements and use them in event handlers.\n    if (eventData) {\n        eventData.info = el.info;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} finder contains {seriesIndex, dataIndex, dataIndexInside}\n * @param {module:echarts/model/Global} ecModel\n * @return {Object} {point: [x, y], el: ...} point Will not be null.\n */\nvar findPointFromSeries = function (finder, ecModel) {\n    var point = [];\n    var seriesIndex = finder.seriesIndex;\n    var seriesModel;\n    if (seriesIndex == null || !(\n        seriesModel = ecModel.getSeriesByIndex(seriesIndex)\n    )) {\n        return {point: []};\n    }\n\n    var data = seriesModel.getData();\n    var dataIndex = queryDataIndex(data, finder);\n    if (dataIndex == null || dataIndex < 0 || isArray(dataIndex)) {\n        return {point: []};\n    }\n\n    var el = data.getItemGraphicEl(dataIndex);\n    var coordSys = seriesModel.coordinateSystem;\n\n    if (seriesModel.getTooltipPosition) {\n        point = seriesModel.getTooltipPosition(dataIndex) || [];\n    }\n    else if (coordSys && coordSys.dataToPoint) {\n        point = coordSys.dataToPoint(\n            data.getValues(\n                map(coordSys.dimensions, function (dim) {\n                    return data.mapDimension(dim);\n                }), dataIndex, true\n            )\n        ) || [];\n    }\n    else if (el) {\n        // Use graphic bounding rect\n        var rect = el.getBoundingRect().clone();\n        rect.applyTransform(el.transform);\n        point = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    }\n\n    return {point: point, el: el};\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$7 = each$1;\nvar curry$2 = curry;\nvar inner$7 = makeInner();\n\n/**\n * Basic logic: check all axis, if they do not demand show/highlight,\n * then hide/downplay them.\n *\n * @param {Object} coordSysAxesInfo\n * @param {Object} payload\n * @param {string} [payload.currTrigger] 'click' | 'mousemove' | 'leave'\n * @param {Array.<number>} [payload.x] x and y, which are mandatory, specify a point to\n *              trigger axisPointer and tooltip.\n * @param {Array.<number>} [payload.y] x and y, which are mandatory, specify a point to\n *              trigger axisPointer and tooltip.\n * @param {Object} [payload.seriesIndex] finder, optional, restrict target axes.\n * @param {Object} [payload.dataIndex] finder, restrict target axes.\n * @param {Object} [payload.axesInfo] finder, restrict target axes.\n *        [{\n *          axisDim: 'x'|'y'|'angle'|...,\n *          axisIndex: ...,\n *          value: ...\n *        }, ...]\n * @param {Function} [payload.dispatchAction]\n * @param {Object} [payload.tooltipOption]\n * @param {Object|Array.<number>|Function} [payload.position] Tooltip position,\n *        which can be specified in dispatchAction\n * @param {module:echarts/model/Global} ecModel\n * @param {module:echarts/ExtensionAPI} api\n * @return {Object} content of event obj for echarts.connect.\n */\nvar axisTrigger = function (payload, ecModel, api) {\n    var currTrigger = payload.currTrigger;\n    var point = [payload.x, payload.y];\n    var finder = payload;\n    var dispatchAction = payload.dispatchAction || bind(api.dispatchAction, api);\n    var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo;\n\n    // Pending\n    // See #6121. But we are not able to reproduce it yet.\n    if (!coordSysAxesInfo) {\n        return;\n    }\n\n    if (illegalPoint(point)) {\n        // Used in the default behavior of `connection`: use the sample seriesIndex\n        // and dataIndex. And also used in the tooltipView trigger.\n        point = findPointFromSeries({\n            seriesIndex: finder.seriesIndex,\n            // Do not use dataIndexInside from other ec instance.\n            // FIXME: auto detect it?\n            dataIndex: finder.dataIndex\n        }, ecModel).point;\n    }\n    var isIllegalPoint = illegalPoint(point);\n\n    // Axis and value can be specified when calling dispatchAction({type: 'updateAxisPointer'}).\n    // Notice: In this case, it is difficult to get the `point` (which is necessary to show\n    // tooltip, so if point is not given, we just use the point found by sample seriesIndex\n    // and dataIndex.\n    var inputAxesInfo = finder.axesInfo;\n\n    var axesInfo = coordSysAxesInfo.axesInfo;\n    var shouldHide = currTrigger === 'leave' || illegalPoint(point);\n    var outputFinder = {};\n\n    var showValueMap = {};\n    var dataByCoordSys = {list: [], map: {}};\n    var updaters = {\n        showPointer: curry$2(showPointer, showValueMap),\n        showTooltip: curry$2(showTooltip, dataByCoordSys)\n    };\n\n    // Process for triggered axes.\n    each$7(coordSysAxesInfo.coordSysMap, function (coordSys, coordSysKey) {\n        // If a point given, it must be contained by the coordinate system.\n        var coordSysContainsPoint = isIllegalPoint || coordSys.containPoint(point);\n\n        each$7(coordSysAxesInfo.coordSysAxesInfo[coordSysKey], function (axisInfo, key) {\n            var axis = axisInfo.axis;\n            var inputAxisInfo = findInputAxisInfo(inputAxesInfo, axisInfo);\n            // If no inputAxesInfo, no axis is restricted.\n            if (!shouldHide && coordSysContainsPoint && (!inputAxesInfo || inputAxisInfo)) {\n                var val = inputAxisInfo && inputAxisInfo.value;\n                if (val == null && !isIllegalPoint) {\n                    val = axis.pointToData(point);\n                }\n                val != null && processOnAxis(axisInfo, val, updaters, false, outputFinder);\n            }\n        });\n    });\n\n    // Process for linked axes.\n    var linkTriggers = {};\n    each$7(axesInfo, function (tarAxisInfo, tarKey) {\n        var linkGroup = tarAxisInfo.linkGroup;\n\n        // If axis has been triggered in the previous stage, it should not be triggered by link.\n        if (linkGroup && !showValueMap[tarKey]) {\n            each$7(linkGroup.axesInfo, function (srcAxisInfo, srcKey) {\n                var srcValItem = showValueMap[srcKey];\n                // If srcValItem exist, source axis is triggered, so link to target axis.\n                if (srcAxisInfo !== tarAxisInfo && srcValItem) {\n                    var val = srcValItem.value;\n                    linkGroup.mapper && (val = tarAxisInfo.axis.scale.parse(linkGroup.mapper(\n                        val, makeMapperParam(srcAxisInfo), makeMapperParam(tarAxisInfo)\n                    )));\n                    linkTriggers[tarAxisInfo.key] = val;\n                }\n            });\n        }\n    });\n    each$7(linkTriggers, function (val, tarKey) {\n        processOnAxis(axesInfo[tarKey], val, updaters, true, outputFinder);\n    });\n\n    updateModelActually(showValueMap, axesInfo, outputFinder);\n    dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction);\n    dispatchHighDownActually(axesInfo, dispatchAction, api);\n\n    return outputFinder;\n};\n\nfunction processOnAxis(axisInfo, newValue, updaters, dontSnap, outputFinder) {\n    var axis = axisInfo.axis;\n\n    if (axis.scale.isBlank() || !axis.containData(newValue)) {\n        return;\n    }\n\n    if (!axisInfo.involveSeries) {\n        updaters.showPointer(axisInfo, newValue);\n        return;\n    }\n\n    // Heavy calculation. So put it after axis.containData checking.\n    var payloadInfo = buildPayloadsBySeries(newValue, axisInfo);\n    var payloadBatch = payloadInfo.payloadBatch;\n    var snapToValue = payloadInfo.snapToValue;\n\n    // Fill content of event obj for echarts.connect.\n    // By defualt use the first involved series data as a sample to connect.\n    if (payloadBatch[0] && outputFinder.seriesIndex == null) {\n        extend(outputFinder, payloadBatch[0]);\n    }\n\n    // If no linkSource input, this process is for collecting link\n    // target, where snap should not be accepted.\n    if (!dontSnap && axisInfo.snap) {\n        if (axis.containData(snapToValue) && snapToValue != null) {\n            newValue = snapToValue;\n        }\n    }\n\n    updaters.showPointer(axisInfo, newValue, payloadBatch, outputFinder);\n    // Tooltip should always be snapToValue, otherwise there will be\n    // incorrect \"axis value ~ series value\" mapping displayed in tooltip.\n    updaters.showTooltip(axisInfo, payloadInfo, snapToValue);\n}\n\nfunction buildPayloadsBySeries(value, axisInfo) {\n    var axis = axisInfo.axis;\n    var dim = axis.dim;\n    var snapToValue = value;\n    var payloadBatch = [];\n    var minDist = Number.MAX_VALUE;\n    var minDiff = -1;\n\n    each$7(axisInfo.seriesModels, function (series, idx) {\n        var dataDim = series.getData().mapDimension(dim, true);\n        var seriesNestestValue;\n        var dataIndices;\n\n        if (series.getAxisTooltipData) {\n            var result = series.getAxisTooltipData(dataDim, value, axis);\n            dataIndices = result.dataIndices;\n            seriesNestestValue = result.nestestValue;\n        }\n        else {\n            dataIndices = series.getData().indicesOfNearest(\n                dataDim[0],\n                value,\n                // Add a threshold to avoid find the wrong dataIndex\n                // when data length is not same.\n                // false,\n                axis.type === 'category' ? 0.5 : null\n            );\n            if (!dataIndices.length) {\n                return;\n            }\n            seriesNestestValue = series.getData().get(dataDim[0], dataIndices[0]);\n        }\n\n        if (seriesNestestValue == null || !isFinite(seriesNestestValue)) {\n            return;\n        }\n\n        var diff = value - seriesNestestValue;\n        var dist = Math.abs(diff);\n        // Consider category case\n        if (dist <= minDist) {\n            if (dist < minDist || (diff >= 0 && minDiff < 0)) {\n                minDist = dist;\n                minDiff = diff;\n                snapToValue = seriesNestestValue;\n                payloadBatch.length = 0;\n            }\n            each$7(dataIndices, function (dataIndex) {\n                payloadBatch.push({\n                    seriesIndex: series.seriesIndex,\n                    dataIndexInside: dataIndex,\n                    dataIndex: series.getData().getRawIndex(dataIndex)\n                });\n            });\n        }\n    });\n\n    return {\n        payloadBatch: payloadBatch,\n        snapToValue: snapToValue\n    };\n}\n\nfunction showPointer(showValueMap, axisInfo, value, payloadBatch) {\n    showValueMap[axisInfo.key] = {value: value, payloadBatch: payloadBatch};\n}\n\nfunction showTooltip(dataByCoordSys, axisInfo, payloadInfo, value) {\n    var payloadBatch = payloadInfo.payloadBatch;\n    var axis = axisInfo.axis;\n    var axisModel = axis.model;\n    var axisPointerModel = axisInfo.axisPointerModel;\n\n    // If no data, do not create anything in dataByCoordSys,\n    // whose length will be used to judge whether dispatch action.\n    if (!axisInfo.triggerTooltip || !payloadBatch.length) {\n        return;\n    }\n\n    var coordSysModel = axisInfo.coordSys.model;\n    var coordSysKey = makeKey(coordSysModel);\n    var coordSysItem = dataByCoordSys.map[coordSysKey];\n    if (!coordSysItem) {\n        coordSysItem = dataByCoordSys.map[coordSysKey] = {\n            coordSysId: coordSysModel.id,\n            coordSysIndex: coordSysModel.componentIndex,\n            coordSysType: coordSysModel.type,\n            coordSysMainType: coordSysModel.mainType,\n            dataByAxis: []\n        };\n        dataByCoordSys.list.push(coordSysItem);\n    }\n\n    coordSysItem.dataByAxis.push({\n        axisDim: axis.dim,\n        axisIndex: axisModel.componentIndex,\n        axisType: axisModel.type,\n        axisId: axisModel.id,\n        value: value,\n        // Caustion: viewHelper.getValueLabel is actually on \"view stage\", which\n        // depends that all models have been updated. So it should not be performed\n        // here. Considering axisPointerModel used here is volatile, which is hard\n        // to be retrieve in TooltipView, we prepare parameters here.\n        valueLabelOpt: {\n            precision: axisPointerModel.get('label.precision'),\n            formatter: axisPointerModel.get('label.formatter')\n        },\n        seriesDataIndices: payloadBatch.slice()\n    });\n}\n\nfunction updateModelActually(showValueMap, axesInfo, outputFinder) {\n    var outputAxesInfo = outputFinder.axesInfo = [];\n    // Basic logic: If no 'show' required, 'hide' this axisPointer.\n    each$7(axesInfo, function (axisInfo, key) {\n        var option = axisInfo.axisPointerModel.option;\n        var valItem = showValueMap[key];\n\n        if (valItem) {\n            !axisInfo.useHandle && (option.status = 'show');\n            option.value = valItem.value;\n            // For label formatter param and highlight.\n            option.seriesDataIndices = (valItem.payloadBatch || []).slice();\n        }\n        // When always show (e.g., handle used), remain\n        // original value and status.\n        else {\n            // If hide, value still need to be set, consider\n            // click legend to toggle axis blank.\n            !axisInfo.useHandle && (option.status = 'hide');\n        }\n\n        // If status is 'hide', should be no info in payload.\n        option.status === 'show' && outputAxesInfo.push({\n            axisDim: axisInfo.axis.dim,\n            axisIndex: axisInfo.axis.model.componentIndex,\n            value: option.value\n        });\n    });\n}\n\nfunction dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction) {\n    // Basic logic: If no showTip required, hideTip will be dispatched.\n    if (illegalPoint(point) || !dataByCoordSys.list.length) {\n        dispatchAction({type: 'hideTip'});\n        return;\n    }\n\n    // In most case only one axis (or event one series is used). It is\n    // convinient to fetch payload.seriesIndex and payload.dataIndex\n    // dirtectly. So put the first seriesIndex and dataIndex of the first\n    // axis on the payload.\n    var sampleItem = ((dataByCoordSys.list[0].dataByAxis[0] || {}).seriesDataIndices || [])[0] || {};\n\n    dispatchAction({\n        type: 'showTip',\n        escapeConnect: true,\n        x: point[0],\n        y: point[1],\n        tooltipOption: payload.tooltipOption,\n        position: payload.position,\n        dataIndexInside: sampleItem.dataIndexInside,\n        dataIndex: sampleItem.dataIndex,\n        seriesIndex: sampleItem.seriesIndex,\n        dataByCoordSys: dataByCoordSys.list\n    });\n}\n\nfunction dispatchHighDownActually(axesInfo, dispatchAction, api) {\n    // FIXME\n    // highlight status modification shoule be a stage of main process?\n    // (Consider confilct (e.g., legend and axisPointer) and setOption)\n\n    var zr = api.getZr();\n    var highDownKey = 'axisPointerLastHighlights';\n    var lastHighlights = inner$7(zr)[highDownKey] || {};\n    var newHighlights = inner$7(zr)[highDownKey] = {};\n\n    // Update highlight/downplay status according to axisPointer model.\n    // Build hash map and remove duplicate incidentally.\n    each$7(axesInfo, function (axisInfo, key) {\n        var option = axisInfo.axisPointerModel.option;\n        option.status === 'show' && each$7(option.seriesDataIndices, function (batchItem) {\n            var key = batchItem.seriesIndex + ' | ' + batchItem.dataIndex;\n            newHighlights[key] = batchItem;\n        });\n    });\n\n    // Diff.\n    var toHighlight = [];\n    var toDownplay = [];\n    each$1(lastHighlights, function (batchItem, key) {\n        !newHighlights[key] && toDownplay.push(batchItem);\n    });\n    each$1(newHighlights, function (batchItem, key) {\n        !lastHighlights[key] && toHighlight.push(batchItem);\n    });\n\n    toDownplay.length && api.dispatchAction({\n        type: 'downplay', escapeConnect: true, batch: toDownplay\n    });\n    toHighlight.length && api.dispatchAction({\n        type: 'highlight', escapeConnect: true, batch: toHighlight\n    });\n}\n\nfunction findInputAxisInfo(inputAxesInfo, axisInfo) {\n    for (var i = 0; i < (inputAxesInfo || []).length; i++) {\n        var inputAxisInfo = inputAxesInfo[i];\n        if (axisInfo.axis.dim === inputAxisInfo.axisDim\n            && axisInfo.axis.model.componentIndex === inputAxisInfo.axisIndex\n        ) {\n            return inputAxisInfo;\n        }\n    }\n}\n\nfunction makeMapperParam(axisInfo) {\n    var axisModel = axisInfo.axis.model;\n    var item = {};\n    var dim = item.axisDim = axisInfo.axis.dim;\n    item.axisIndex = item[dim + 'AxisIndex'] = axisModel.componentIndex;\n    item.axisName = item[dim + 'AxisName'] = axisModel.name;\n    item.axisId = item[dim + 'AxisId'] = axisModel.id;\n    return item;\n}\n\nfunction illegalPoint(point) {\n    return !point || point[0] == null || isNaN(point[0]) || point[1] == null || isNaN(point[1]);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisPointerModel = extendComponentModel({\n\n    type: 'axisPointer',\n\n    coordSysAxesInfo: null,\n\n    defaultOption: {\n        // 'auto' means that show when triggered by tooltip or handle.\n        show: 'auto',\n        // 'click' | 'mousemove' | 'none'\n        triggerOn: null, // set default in AxisPonterView.js\n\n        zlevel: 0,\n        z: 50,\n\n        type: 'line', // 'line' 'shadow' 'cross' 'none'.\n        // axispointer triggered by tootip determine snap automatically,\n        // see `modelHelper`.\n        snap: false,\n        triggerTooltip: true,\n\n        value: null,\n        status: null, // Init value depends on whether handle is used.\n\n        // [group0, group1, ...]\n        // Each group can be: {\n        //      mapper: function () {},\n        //      singleTooltip: 'multiple',  // 'multiple' or 'single'\n        //      xAxisId: ...,\n        //      yAxisName: ...,\n        //      angleAxisIndex: ...\n        // }\n        // mapper: can be ignored.\n        //      input: {axisInfo, value}\n        //      output: {axisInfo, value}\n        link: [],\n\n        // Do not set 'auto' here, otherwise global animation: false\n        // will not effect at this axispointer.\n        animation: null,\n        animationDurationUpdate: 200,\n\n        lineStyle: {\n            color: '#aaa',\n            width: 1,\n            type: 'solid'\n        },\n\n        shadowStyle: {\n            color: 'rgba(150,150,150,0.3)'\n        },\n\n        label: {\n            show: true,\n            formatter: null, // string | Function\n            precision: 'auto', // Or a number like 0, 1, 2 ...\n            margin: 3,\n            color: '#fff',\n            padding: [5, 7, 5, 7],\n            backgroundColor: 'auto', // default: axis line color\n            borderColor: null,\n            borderWidth: 0,\n            shadowBlur: 3,\n            shadowColor: '#aaa'\n            // Considering applicability, common style should\n            // better not have shadowOffset.\n            // shadowOffsetX: 0,\n            // shadowOffsetY: 2\n        },\n\n        handle: {\n            show: false,\n            /* eslint-disable */\n            icon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z', // jshint ignore:line\n            /* eslint-enable */\n            size: 45,\n            // handle margin is from symbol center to axis, which is stable when circular move.\n            margin: 50,\n            // color: '#1b8bbd'\n            // color: '#2f4554'\n            color: '#333',\n            shadowBlur: 3,\n            shadowColor: '#aaa',\n            shadowOffsetX: 0,\n            shadowOffsetY: 2,\n\n            // For mobile performance\n            throttle: 40\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$8 = makeInner();\nvar each$8 = each$1;\n\n/**\n * @param {string} key\n * @param {module:echarts/ExtensionAPI} api\n * @param {Function} handler\n *      param: {string} currTrigger\n *      param: {Array.<number>} point\n */\nfunction register(key, api, handler) {\n    if (env$1.node) {\n        return;\n    }\n\n    var zr = api.getZr();\n    inner$8(zr).records || (inner$8(zr).records = {});\n\n    initGlobalListeners(zr, api);\n\n    var record = inner$8(zr).records[key] || (inner$8(zr).records[key] = {});\n    record.handler = handler;\n}\n\nfunction initGlobalListeners(zr, api) {\n    if (inner$8(zr).initialized) {\n        return;\n    }\n\n    inner$8(zr).initialized = true;\n\n    useHandler('click', curry(doEnter, 'click'));\n    useHandler('mousemove', curry(doEnter, 'mousemove'));\n    // useHandler('mouseout', onLeave);\n    useHandler('globalout', onLeave);\n\n    function useHandler(eventType, cb) {\n        zr.on(eventType, function (e) {\n            var dis = makeDispatchAction(api);\n\n            each$8(inner$8(zr).records, function (record) {\n                record && cb(record, e, dis.dispatchAction);\n            });\n\n            dispatchTooltipFinally(dis.pendings, api);\n        });\n    }\n}\n\nfunction dispatchTooltipFinally(pendings, api) {\n    var showLen = pendings.showTip.length;\n    var hideLen = pendings.hideTip.length;\n\n    var actuallyPayload;\n    if (showLen) {\n        actuallyPayload = pendings.showTip[showLen - 1];\n    }\n    else if (hideLen) {\n        actuallyPayload = pendings.hideTip[hideLen - 1];\n    }\n    if (actuallyPayload) {\n        actuallyPayload.dispatchAction = null;\n        api.dispatchAction(actuallyPayload);\n    }\n}\n\nfunction onLeave(record, e, dispatchAction) {\n    record.handler('leave', null, dispatchAction);\n}\n\nfunction doEnter(currTrigger, record, e, dispatchAction) {\n    record.handler(currTrigger, e, dispatchAction);\n}\n\nfunction makeDispatchAction(api) {\n    var pendings = {\n        showTip: [],\n        hideTip: []\n    };\n    // FIXME\n    // better approach?\n    // 'showTip' and 'hideTip' can be triggered by axisPointer and tooltip,\n    // which may be conflict, (axisPointer call showTip but tooltip call hideTip);\n    // So we have to add \"final stage\" to merge those dispatched actions.\n    var dispatchAction = function (payload) {\n        var pendingList = pendings[payload.type];\n        if (pendingList) {\n            pendingList.push(payload);\n        }\n        else {\n            payload.dispatchAction = dispatchAction;\n            api.dispatchAction(payload);\n        }\n    };\n\n    return {\n        dispatchAction: dispatchAction,\n        pendings: pendings\n    };\n}\n\n/**\n * @param {string} key\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction unregister(key, api) {\n    if (env$1.node) {\n        return;\n    }\n    var zr = api.getZr();\n    var record = (inner$8(zr).records || {})[key];\n    if (record) {\n        inner$8(zr).records[key] = null;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisPointerView = extendComponentView({\n\n    type: 'axisPointer',\n\n    render: function (globalAxisPointerModel, ecModel, api) {\n        var globalTooltipModel = ecModel.getComponent('tooltip');\n        var triggerOn = globalAxisPointerModel.get('triggerOn')\n            || (globalTooltipModel && globalTooltipModel.get('triggerOn') || 'mousemove|click');\n\n        // Register global listener in AxisPointerView to enable\n        // AxisPointerView to be independent to Tooltip.\n        register(\n            'axisPointer',\n            api,\n            function (currTrigger, e, dispatchAction) {\n                // If 'none', it is not controlled by mouse totally.\n                if (triggerOn !== 'none'\n                    && (currTrigger === 'leave' || triggerOn.indexOf(currTrigger) >= 0)\n                ) {\n                    dispatchAction({\n                        type: 'updateAxisPointer',\n                        currTrigger: currTrigger,\n                        x: e && e.offsetX,\n                        y: e && e.offsetY\n                    });\n                }\n            }\n        );\n    },\n\n    /**\n     * @override\n     */\n    remove: function (ecModel, api) {\n        unregister(api.getZr(), 'axisPointer');\n        AxisPointerView.superApply(this._model, 'remove', arguments);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function (ecModel, api) {\n        unregister('axisPointer', api);\n        AxisPointerView.superApply(this._model, 'dispose', arguments);\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$9 = makeInner();\nvar clone$4 = clone;\nvar bind$1 = bind;\n\n/**\n * Base axis pointer class in 2D.\n * Implemenents {module:echarts/component/axis/IAxisPointer}.\n */\nfunction BaseAxisPointer() {\n}\n\nBaseAxisPointer.prototype = {\n\n    /**\n     * @private\n     */\n    _group: null,\n\n    /**\n     * @private\n     */\n    _lastGraphicKey: null,\n\n    /**\n     * @private\n     */\n    _handle: null,\n\n    /**\n     * @private\n     */\n    _dragging: false,\n\n    /**\n     * @private\n     */\n    _lastValue: null,\n\n    /**\n     * @private\n     */\n    _lastStatus: null,\n\n    /**\n     * @private\n     */\n    _payloadInfo: null,\n\n    /**\n     * In px, arbitrary value. Do not set too small,\n     * no animation is ok for most cases.\n     * @protected\n     */\n    animationThreshold: 15,\n\n    /**\n     * @implement\n     */\n    render: function (axisModel, axisPointerModel, api, forceRender) {\n        var value = axisPointerModel.get('value');\n        var status = axisPointerModel.get('status');\n\n        // Bind them to `this`, not in closure, otherwise they will not\n        // be replaced when user calling setOption in not merge mode.\n        this._axisModel = axisModel;\n        this._axisPointerModel = axisPointerModel;\n        this._api = api;\n\n        // Optimize: `render` will be called repeatly during mouse move.\n        // So it is power consuming if performing `render` each time,\n        // especially on mobile device.\n        if (!forceRender\n            && this._lastValue === value\n            && this._lastStatus === status\n        ) {\n            return;\n        }\n        this._lastValue = value;\n        this._lastStatus = status;\n\n        var group = this._group;\n        var handle = this._handle;\n\n        if (!status || status === 'hide') {\n            // Do not clear here, for animation better.\n            group && group.hide();\n            handle && handle.hide();\n            return;\n        }\n        group && group.show();\n        handle && handle.show();\n\n        // Otherwise status is 'show'\n        var elOption = {};\n        this.makeElOption(elOption, value, axisModel, axisPointerModel, api);\n\n        // Enable change axis pointer type.\n        var graphicKey = elOption.graphicKey;\n        if (graphicKey !== this._lastGraphicKey) {\n            this.clear(api);\n        }\n        this._lastGraphicKey = graphicKey;\n\n        var moveAnimation = this._moveAnimation\n            = this.determineAnimation(axisModel, axisPointerModel);\n\n        if (!group) {\n            group = this._group = new Group();\n            this.createPointerEl(group, elOption, axisModel, axisPointerModel);\n            this.createLabelEl(group, elOption, axisModel, axisPointerModel);\n            api.getZr().add(group);\n        }\n        else {\n            var doUpdateProps = curry(updateProps$1, axisPointerModel, moveAnimation);\n            this.updatePointerEl(group, elOption, doUpdateProps, axisPointerModel);\n            this.updateLabelEl(group, elOption, doUpdateProps, axisPointerModel);\n        }\n\n        updateMandatoryProps(group, axisPointerModel, true);\n\n        this._renderHandle(value);\n    },\n\n    /**\n     * @implement\n     */\n    remove: function (api) {\n        this.clear(api);\n    },\n\n    /**\n     * @implement\n     */\n    dispose: function (api) {\n        this.clear(api);\n    },\n\n    /**\n     * @protected\n     */\n    determineAnimation: function (axisModel, axisPointerModel) {\n        var animation = axisPointerModel.get('animation');\n        var axis = axisModel.axis;\n        var isCategoryAxis = axis.type === 'category';\n        var useSnap = axisPointerModel.get('snap');\n\n        // Value axis without snap always do not snap.\n        if (!useSnap && !isCategoryAxis) {\n            return false;\n        }\n\n        if (animation === 'auto' || animation == null) {\n            var animationThreshold = this.animationThreshold;\n            if (isCategoryAxis && axis.getBandWidth() > animationThreshold) {\n                return true;\n            }\n\n            // It is important to auto animation when snap used. Consider if there is\n            // a dataZoom, animation will be disabled when too many points exist, while\n            // it will be enabled for better visual effect when little points exist.\n            if (useSnap) {\n                var seriesDataCount = getAxisInfo(axisModel).seriesDataCount;\n                var axisExtent = axis.getExtent();\n                // Approximate band width\n                return Math.abs(axisExtent[0] - axisExtent[1]) / seriesDataCount > animationThreshold;\n            }\n\n            return false;\n        }\n\n        return animation === true;\n    },\n\n    /**\n     * add {pointer, label, graphicKey} to elOption\n     * @protected\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        // Shoule be implemenented by sub-class.\n    },\n\n    /**\n     * @protected\n     */\n    createPointerEl: function (group, elOption, axisModel, axisPointerModel) {\n        var pointerOption = elOption.pointer;\n        if (pointerOption) {\n            var pointerEl = inner$9(group).pointerEl = new graphic[pointerOption.type](\n                clone$4(elOption.pointer)\n            );\n            group.add(pointerEl);\n        }\n    },\n\n    /**\n     * @protected\n     */\n    createLabelEl: function (group, elOption, axisModel, axisPointerModel) {\n        if (elOption.label) {\n            var labelEl = inner$9(group).labelEl = new Rect(\n                clone$4(elOption.label)\n            );\n\n            group.add(labelEl);\n            updateLabelShowHide(labelEl, axisPointerModel);\n        }\n    },\n\n    /**\n     * @protected\n     */\n    updatePointerEl: function (group, elOption, updateProps$$1) {\n        var pointerEl = inner$9(group).pointerEl;\n        if (pointerEl) {\n            pointerEl.setStyle(elOption.pointer.style);\n            updateProps$$1(pointerEl, {shape: elOption.pointer.shape});\n        }\n    },\n\n    /**\n     * @protected\n     */\n    updateLabelEl: function (group, elOption, updateProps$$1, axisPointerModel) {\n        var labelEl = inner$9(group).labelEl;\n        if (labelEl) {\n            labelEl.setStyle(elOption.label.style);\n            updateProps$$1(labelEl, {\n                // Consider text length change in vertical axis, animation should\n                // be used on shape, otherwise the effect will be weird.\n                shape: elOption.label.shape,\n                position: elOption.label.position\n            });\n\n            updateLabelShowHide(labelEl, axisPointerModel);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _renderHandle: function (value) {\n        if (this._dragging || !this.updateHandleTransform) {\n            return;\n        }\n\n        var axisPointerModel = this._axisPointerModel;\n        var zr = this._api.getZr();\n        var handle = this._handle;\n        var handleModel = axisPointerModel.getModel('handle');\n\n        var status = axisPointerModel.get('status');\n        if (!handleModel.get('show') || !status || status === 'hide') {\n            handle && zr.remove(handle);\n            this._handle = null;\n            return;\n        }\n\n        var isInit;\n        if (!this._handle) {\n            isInit = true;\n            handle = this._handle = createIcon(\n                handleModel.get('icon'),\n                {\n                    cursor: 'move',\n                    draggable: true,\n                    onmousemove: function (e) {\n                        // Fot mobile devicem, prevent screen slider on the button.\n                        stop(e.event);\n                    },\n                    onmousedown: bind$1(this._onHandleDragMove, this, 0, 0),\n                    drift: bind$1(this._onHandleDragMove, this),\n                    ondragend: bind$1(this._onHandleDragEnd, this)\n                }\n            );\n            zr.add(handle);\n        }\n\n        updateMandatoryProps(handle, axisPointerModel, false);\n\n        // update style\n        var includeStyles = [\n            'color', 'borderColor', 'borderWidth', 'opacity',\n            'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'\n        ];\n        handle.setStyle(handleModel.getItemStyle(null, includeStyles));\n\n        // update position\n        var handleSize = handleModel.get('size');\n        if (!isArray(handleSize)) {\n            handleSize = [handleSize, handleSize];\n        }\n        handle.attr('scale', [handleSize[0] / 2, handleSize[1] / 2]);\n\n        createOrUpdate(\n            this,\n            '_doDispatchAxisPointer',\n            handleModel.get('throttle') || 0,\n            'fixRate'\n        );\n\n        this._moveHandleToValue(value, isInit);\n    },\n\n    /**\n     * @private\n     */\n    _moveHandleToValue: function (value, isInit) {\n        updateProps$1(\n            this._axisPointerModel,\n            !isInit && this._moveAnimation,\n            this._handle,\n            getHandleTransProps(this.getHandleTransform(\n                value, this._axisModel, this._axisPointerModel\n            ))\n        );\n    },\n\n    /**\n     * @private\n     */\n    _onHandleDragMove: function (dx, dy) {\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        this._dragging = true;\n\n        // Persistent for throttle.\n        var trans = this.updateHandleTransform(\n            getHandleTransProps(handle),\n            [dx, dy],\n            this._axisModel,\n            this._axisPointerModel\n        );\n        this._payloadInfo = trans;\n\n        handle.stopAnimation();\n        handle.attr(getHandleTransProps(trans));\n        inner$9(handle).lastProp = null;\n\n        this._doDispatchAxisPointer();\n    },\n\n    /**\n     * Throttled method.\n     * @private\n     */\n    _doDispatchAxisPointer: function () {\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        var payloadInfo = this._payloadInfo;\n        var axisModel = this._axisModel;\n        this._api.dispatchAction({\n            type: 'updateAxisPointer',\n            x: payloadInfo.cursorPoint[0],\n            y: payloadInfo.cursorPoint[1],\n            tooltipOption: payloadInfo.tooltipOption,\n            axesInfo: [{\n                axisDim: axisModel.axis.dim,\n                axisIndex: axisModel.componentIndex\n            }]\n        });\n    },\n\n    /**\n     * @private\n     */\n    _onHandleDragEnd: function (moveAnimation) {\n        this._dragging = false;\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        var value = this._axisPointerModel.get('value');\n        // Consider snap or categroy axis, handle may be not consistent with\n        // axisPointer. So move handle to align the exact value position when\n        // drag ended.\n        this._moveHandleToValue(value);\n\n        // For the effect: tooltip will be shown when finger holding on handle\n        // button, and will be hidden after finger left handle button.\n        this._api.dispatchAction({\n            type: 'hideTip'\n        });\n    },\n\n    /**\n     * Should be implemenented by sub-class if support `handle`.\n     * @protected\n     * @param {number} value\n     * @param {module:echarts/model/Model} axisModel\n     * @param {module:echarts/model/Model} axisPointerModel\n     * @return {Object} {position: [x, y], rotation: 0}\n     */\n    getHandleTransform: null,\n\n    /**\n     * * Should be implemenented by sub-class if support `handle`.\n     * @protected\n     * @param {Object} transform {position, rotation}\n     * @param {Array.<number>} delta [dx, dy]\n     * @param {module:echarts/model/Model} axisModel\n     * @param {module:echarts/model/Model} axisPointerModel\n     * @return {Object} {position: [x, y], rotation: 0, cursorPoint: [x, y]}\n     */\n    updateHandleTransform: null,\n\n    /**\n     * @private\n     */\n    clear: function (api) {\n        this._lastValue = null;\n        this._lastStatus = null;\n\n        var zr = api.getZr();\n        var group = this._group;\n        var handle = this._handle;\n        if (zr && group) {\n            this._lastGraphicKey = null;\n            group && zr.remove(group);\n            handle && zr.remove(handle);\n            this._group = null;\n            this._handle = null;\n            this._payloadInfo = null;\n        }\n    },\n\n    /**\n     * @protected\n     */\n    doClear: function () {\n        // Implemented by sub-class if necessary.\n    },\n\n    /**\n     * @protected\n     * @param {Array.<number>} xy\n     * @param {Array.<number>} wh\n     * @param {number} [xDimIndex=0] or 1\n     */\n    buildLabel: function (xy, wh, xDimIndex) {\n        xDimIndex = xDimIndex || 0;\n        return {\n            x: xy[xDimIndex],\n            y: xy[1 - xDimIndex],\n            width: wh[xDimIndex],\n            height: wh[1 - xDimIndex]\n        };\n    }\n};\n\nBaseAxisPointer.prototype.constructor = BaseAxisPointer;\n\n\nfunction updateProps$1(animationModel, moveAnimation, el, props) {\n    // Animation optimize.\n    if (!propsEqual(inner$9(el).lastProp, props)) {\n        inner$9(el).lastProp = props;\n        moveAnimation\n            ? updateProps(el, props, animationModel)\n            : (el.stopAnimation(), el.attr(props));\n    }\n}\n\nfunction propsEqual(lastProps, newProps) {\n    if (isObject$1(lastProps) && isObject$1(newProps)) {\n        var equals = true;\n        each$1(newProps, function (item, key) {\n            equals = equals && propsEqual(lastProps[key], item);\n        });\n        return !!equals;\n    }\n    else {\n        return lastProps === newProps;\n    }\n}\n\nfunction updateLabelShowHide(labelEl, axisPointerModel) {\n    labelEl[axisPointerModel.get('label.show') ? 'show' : 'hide']();\n}\n\nfunction getHandleTransProps(trans) {\n    return {\n        position: trans.position.slice(),\n        rotation: trans.rotation || 0\n    };\n}\n\nfunction updateMandatoryProps(group, axisPointerModel, silent) {\n    var z = axisPointerModel.get('z');\n    var zlevel = axisPointerModel.get('zlevel');\n\n    group && group.traverse(function (el) {\n        if (el.type !== 'group') {\n            z != null && (el.z = z);\n            zlevel != null && (el.zlevel = zlevel);\n            el.silent = silent;\n        }\n    });\n}\n\nenableClassExtend(BaseAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/model/Model} axisPointerModel\n */\nfunction buildElStyle(axisPointerModel) {\n    var axisPointerType = axisPointerModel.get('type');\n    var styleModel = axisPointerModel.getModel(axisPointerType + 'Style');\n    var style;\n    if (axisPointerType === 'line') {\n        style = styleModel.getLineStyle();\n        style.fill = null;\n    }\n    else if (axisPointerType === 'shadow') {\n        style = styleModel.getAreaStyle();\n        style.stroke = null;\n    }\n    return style;\n}\n\n/**\n * @param {Function} labelPos {align, verticalAlign, position}\n */\nfunction buildLabelElOption(\n    elOption, axisModel, axisPointerModel, api, labelPos\n) {\n    var value = axisPointerModel.get('value');\n    var text = getValueLabel(\n        value, axisModel.axis, axisModel.ecModel,\n        axisPointerModel.get('seriesDataIndices'),\n        {\n            precision: axisPointerModel.get('label.precision'),\n            formatter: axisPointerModel.get('label.formatter')\n        }\n    );\n    var labelModel = axisPointerModel.getModel('label');\n    var paddings = normalizeCssArray$1(labelModel.get('padding') || 0);\n\n    var font = labelModel.getFont();\n    var textRect = getBoundingRect(text, font);\n\n    var position = labelPos.position;\n    var width = textRect.width + paddings[1] + paddings[3];\n    var height = textRect.height + paddings[0] + paddings[2];\n\n    // Adjust by align.\n    var align = labelPos.align;\n    align === 'right' && (position[0] -= width);\n    align === 'center' && (position[0] -= width / 2);\n    var verticalAlign = labelPos.verticalAlign;\n    verticalAlign === 'bottom' && (position[1] -= height);\n    verticalAlign === 'middle' && (position[1] -= height / 2);\n\n    // Not overflow ec container\n    confineInContainer(position, width, height, api);\n\n    var bgColor = labelModel.get('backgroundColor');\n    if (!bgColor || bgColor === 'auto') {\n        bgColor = axisModel.get('axisLine.lineStyle.color');\n    }\n\n    elOption.label = {\n        shape: {x: 0, y: 0, width: width, height: height, r: labelModel.get('borderRadius')},\n        position: position.slice(),\n        // TODO: rich\n        style: {\n            text: text,\n            textFont: font,\n            textFill: labelModel.getTextColor(),\n            textPosition: 'inside',\n            fill: bgColor,\n            stroke: labelModel.get('borderColor') || 'transparent',\n            lineWidth: labelModel.get('borderWidth') || 0,\n            shadowBlur: labelModel.get('shadowBlur'),\n            shadowColor: labelModel.get('shadowColor'),\n            shadowOffsetX: labelModel.get('shadowOffsetX'),\n            shadowOffsetY: labelModel.get('shadowOffsetY')\n        },\n        // Lable should be over axisPointer.\n        z2: 10\n    };\n}\n\n// Do not overflow ec container\nfunction confineInContainer(position, width, height, api) {\n    var viewWidth = api.getWidth();\n    var viewHeight = api.getHeight();\n    position[0] = Math.min(position[0] + width, viewWidth) - width;\n    position[1] = Math.min(position[1] + height, viewHeight) - height;\n    position[0] = Math.max(position[0], 0);\n    position[1] = Math.max(position[1], 0);\n}\n\n/**\n * @param {number} value\n * @param {module:echarts/coord/Axis} axis\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} opt\n * @param {Array.<Object>} seriesDataIndices\n * @param {number|string} opt.precision 'auto' or a number\n * @param {string|Function} opt.formatter label formatter\n */\nfunction getValueLabel(value, axis, ecModel, seriesDataIndices, opt) {\n    value = axis.scale.parse(value);\n    var text = axis.scale.getLabel(\n        // If `precision` is set, width can be fixed (like '12.00500'), which\n        // helps to debounce when when moving label.\n        value, {precision: opt.precision}\n    );\n    var formatter = opt.formatter;\n\n    if (formatter) {\n        var params = {\n            value: getAxisRawValue(axis, value),\n            seriesData: []\n        };\n        each$1(seriesDataIndices, function (idxItem) {\n            var series = ecModel.getSeriesByIndex(idxItem.seriesIndex);\n            var dataIndex = idxItem.dataIndexInside;\n            var dataParams = series && series.getDataParams(dataIndex);\n            dataParams && params.seriesData.push(dataParams);\n        });\n\n        if (isString(formatter)) {\n            text = formatter.replace('{value}', text);\n        }\n        else if (isFunction$1(formatter)) {\n            text = formatter(params);\n        }\n    }\n\n    return text;\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @param {number} value\n * @param {Object} layoutInfo {\n *  rotation, position, labelOffset, labelDirection, labelMargin\n * }\n */\nfunction getTransformedPosition(axis, value, layoutInfo) {\n    var transform = create$1();\n    rotate(transform, transform, layoutInfo.rotation);\n    translate(transform, transform, layoutInfo.position);\n\n    return applyTransform$1([\n        axis.dataToCoord(value),\n        (layoutInfo.labelOffset || 0)\n            + (layoutInfo.labelDirection || 1) * (layoutInfo.labelMargin || 0)\n    ], transform);\n}\n\nfunction buildCartesianSingleLabelElOption(\n    value, elOption, layoutInfo, axisModel, axisPointerModel, api\n) {\n    var textLayout = AxisBuilder.innerTextLayout(\n        layoutInfo.rotation, 0, layoutInfo.labelDirection\n    );\n    layoutInfo.labelMargin = axisPointerModel.get('label.margin');\n    buildLabelElOption(elOption, axisModel, axisPointerModel, api, {\n        position: getTransformedPosition(axisModel.axis, value, layoutInfo),\n        align: textLayout.textAlign,\n        verticalAlign: textLayout.textVerticalAlign\n    });\n}\n\n/**\n * @param {Array.<number>} p1\n * @param {Array.<number>} p2\n * @param {number} [xDimIndex=0] or 1\n */\nfunction makeLineShape(p1, p2, xDimIndex) {\n    xDimIndex = xDimIndex || 0;\n    return {\n        x1: p1[xDimIndex],\n        y1: p1[1 - xDimIndex],\n        x2: p2[xDimIndex],\n        y2: p2[1 - xDimIndex]\n    };\n}\n\n/**\n * @param {Array.<number>} xy\n * @param {Array.<number>} wh\n * @param {number} [xDimIndex=0] or 1\n */\nfunction makeRectShape(xy, wh, xDimIndex) {\n    xDimIndex = xDimIndex || 0;\n    return {\n        x: xy[xDimIndex],\n        y: xy[1 - xDimIndex],\n        width: wh[xDimIndex],\n        height: wh[1 - xDimIndex]\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar CartesianAxisPointer = BaseAxisPointer.extend({\n\n    /**\n     * @override\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        var axis = axisModel.axis;\n        var grid = axis.grid;\n        var axisPointerType = axisPointerModel.get('type');\n        var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent();\n        var pixelValue = axis.toGlobalCoord(axis.dataToCoord(value, true));\n\n        if (axisPointerType && axisPointerType !== 'none') {\n            var elStyle = buildElStyle(axisPointerModel);\n            var pointerOption = pointerShapeBuilder[axisPointerType](\n                axis, pixelValue, otherExtent, elStyle\n            );\n            pointerOption.style = elStyle;\n            elOption.graphicKey = pointerOption.type;\n            elOption.pointer = pointerOption;\n        }\n\n        var layoutInfo = layout$1(grid.model, axisModel);\n        buildCartesianSingleLabelElOption(\n            value, elOption, layoutInfo, axisModel, axisPointerModel, api\n        );\n    },\n\n    /**\n     * @override\n     */\n    getHandleTransform: function (value, axisModel, axisPointerModel) {\n        var layoutInfo = layout$1(axisModel.axis.grid.model, axisModel, {\n            labelInside: false\n        });\n        layoutInfo.labelMargin = axisPointerModel.get('handle.margin');\n        return {\n            position: getTransformedPosition(axisModel.axis, value, layoutInfo),\n            rotation: layoutInfo.rotation + (layoutInfo.labelDirection < 0 ? Math.PI : 0)\n        };\n    },\n\n    /**\n     * @override\n     */\n    updateHandleTransform: function (transform, delta, axisModel, axisPointerModel) {\n        var axis = axisModel.axis;\n        var grid = axis.grid;\n        var axisExtent = axis.getGlobalExtent(true);\n        var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent();\n        var dimIndex = axis.dim === 'x' ? 0 : 1;\n\n        var currPosition = transform.position;\n        currPosition[dimIndex] += delta[dimIndex];\n        currPosition[dimIndex] = Math.min(axisExtent[1], currPosition[dimIndex]);\n        currPosition[dimIndex] = Math.max(axisExtent[0], currPosition[dimIndex]);\n\n        var cursorOtherValue = (otherExtent[1] + otherExtent[0]) / 2;\n        var cursorPoint = [cursorOtherValue, cursorOtherValue];\n        cursorPoint[dimIndex] = currPosition[dimIndex];\n\n        // Make tooltip do not overlap axisPointer and in the middle of the grid.\n        var tooltipOptions = [{verticalAlign: 'middle'}, {align: 'center'}];\n\n        return {\n            position: currPosition,\n            rotation: transform.rotation,\n            cursorPoint: cursorPoint,\n            tooltipOption: tooltipOptions[dimIndex]\n        };\n    }\n\n});\n\nfunction getCartesian(grid, axis) {\n    var opt = {};\n    opt[axis.dim + 'AxisIndex'] = axis.index;\n    return grid.getCartesian(opt);\n}\n\nvar pointerShapeBuilder = {\n\n    line: function (axis, pixelValue, otherExtent, elStyle) {\n        var targetShape = makeLineShape(\n            [pixelValue, otherExtent[0]],\n            [pixelValue, otherExtent[1]],\n            getAxisDimIndex(axis)\n        );\n        subPixelOptimizeLine({\n            shape: targetShape,\n            style: elStyle\n        });\n        return {\n            type: 'Line',\n            shape: targetShape\n        };\n    },\n\n    shadow: function (axis, pixelValue, otherExtent, elStyle) {\n        var bandWidth = Math.max(1, axis.getBandWidth());\n        var span = otherExtent[1] - otherExtent[0];\n        return {\n            type: 'Rect',\n            shape: makeRectShape(\n                [pixelValue - bandWidth / 2, otherExtent[0]],\n                [bandWidth, span],\n                getAxisDimIndex(axis)\n            )\n        };\n    }\n};\n\nfunction getAxisDimIndex(axis) {\n    return axis.dim === 'x' ? 0 : 1;\n}\n\nAxisView.registerAxisPointerClass('CartesianAxisPointer', CartesianAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// CartesianAxisPointer is not supposed to be required here. But consider\n// echarts.simple.js and online build tooltip, which only require gridSimple,\n// CartesianAxisPointer should be able to required somewhere.\nregisterPreprocessor(function (option) {\n    // Always has a global axisPointerModel for default setting.\n    if (option) {\n        (!option.axisPointer || option.axisPointer.length === 0)\n            && (option.axisPointer = {});\n\n        var link = option.axisPointer.link;\n        // Normalize to array to avoid object mergin. But if link\n        // is not set, remain null/undefined, otherwise it will\n        // override existent link setting.\n        if (link && !isArray(link)) {\n            option.axisPointer.link = [link];\n        }\n    }\n});\n\n// This process should proformed after coordinate systems created\n// and series data processed. So put it on statistic processing stage.\nregisterProcessor(PRIORITY.PROCESSOR.STATISTIC, function (ecModel, api) {\n    // Build axisPointerModel, mergin tooltip.axisPointer model for each axis.\n    // allAxesInfo should be updated when setOption performed.\n    ecModel.getComponent('axisPointer').coordSysAxesInfo\n        = collect(ecModel, api);\n});\n\n// Broadcast to all views.\nregisterAction({\n    type: 'updateAxisPointer',\n    event: 'updateAxisPointer',\n    update: ':updateAxisPointer'\n}, axisTrigger);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentModel({\n\n    type: 'tooltip',\n\n    dependencies: ['axisPointer'],\n\n    defaultOption: {\n        zlevel: 0,\n\n        z: 60,\n\n        show: true,\n\n        // tooltip主体内容\n        showContent: true,\n\n        // 'trigger' only works on coordinate system.\n        // 'item' | 'axis' | 'none'\n        trigger: 'item',\n\n        // 'click' | 'mousemove' | 'none'\n        triggerOn: 'mousemove|click',\n\n        alwaysShowContent: false,\n\n        displayMode: 'single', // 'single' | 'multipleByCoordSys'\n\n        renderMode: 'auto', // 'auto' | 'html' | 'richText'\n        // 'auto': use html by default, and use non-html if `document` is not defined\n        // 'html': use html for tooltip\n        // 'richText': use canvas, svg, and etc. for tooltip\n\n        // 位置 {Array} | {Function}\n        // position: null\n        // Consider triggered from axisPointer handle, verticalAlign should be 'middle'\n        // align: null,\n        // verticalAlign: null,\n\n        // 是否约束 content 在 viewRect 中。默认 false 是为了兼容以前版本。\n        confine: false,\n\n        // 内容格式器：{string}（Template） ¦ {Function}\n        // formatter: null\n\n        showDelay: 0,\n\n        // 隐藏延迟，单位ms\n        hideDelay: 100,\n\n        // 动画变换时间，单位s\n        transitionDuration: 0.4,\n\n        enterable: false,\n\n        // 提示背景颜色，默认为透明度为0.7的黑色\n        backgroundColor: 'rgba(50,50,50,0.7)',\n\n        // 提示边框颜色\n        borderColor: '#333',\n\n        // 提示边框圆角，单位px，默认为4\n        borderRadius: 4,\n\n        // 提示边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n\n        // 提示内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n\n        // Extra css text\n        extraCssText: '',\n\n        // 坐标轴指示器，坐标轴触发有效\n        axisPointer: {\n            // 默认为直线\n            // 可选为：'line' | 'shadow' | 'cross'\n            type: 'line',\n\n            // type 为 line 的时候有效，指定 tooltip line 所在的轴，可选\n            // 可选 'x' | 'y' | 'angle' | 'radius' | 'auto'\n            // 默认 'auto'，会选择类型为 category 的轴，对于双数值轴，笛卡尔坐标系会默认选择 x 轴\n            // 极坐标系会默认选择 angle 轴\n            axis: 'auto',\n\n            animation: 'auto',\n            animationDurationUpdate: 200,\n            animationEasingUpdate: 'exponentialOut',\n\n            crossStyle: {\n                color: '#999',\n                width: 1,\n                type: 'dashed',\n\n                // TODO formatter\n                textStyle: {}\n            }\n\n            // lineStyle and shadowStyle should not be specified here,\n            // otherwise it will always override those styles on option.axisPointer.\n        },\n        textStyle: {\n            color: '#fff',\n            fontSize: 14\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$10 = each$1;\nvar toCamelCase$1 = toCamelCase;\n\nvar vendors = ['', '-webkit-', '-moz-', '-o-'];\n\nvar gCssText = 'position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;';\n\n/**\n * @param {number} duration\n * @return {string}\n * @inner\n */\nfunction assembleTransition(duration) {\n    var transitionCurve = 'cubic-bezier(0.23, 1, 0.32, 1)';\n    var transitionText = 'left ' + duration + 's ' + transitionCurve + ','\n                        + 'top ' + duration + 's ' + transitionCurve;\n    return map(vendors, function (vendorPrefix) {\n        return vendorPrefix + 'transition:' + transitionText;\n    }).join(';');\n}\n\n/**\n * @param {Object} textStyle\n * @return {string}\n * @inner\n */\nfunction assembleFont(textStyleModel) {\n    var cssText = [];\n\n    var fontSize = textStyleModel.get('fontSize');\n    var color = textStyleModel.getTextColor();\n\n    color && cssText.push('color:' + color);\n\n    cssText.push('font:' + textStyleModel.getFont());\n\n    fontSize\n        && cssText.push('line-height:' + Math.round(fontSize * 3 / 2) + 'px');\n\n    each$10(['decoration', 'align'], function (name) {\n        var val = textStyleModel.get(name);\n        val && cssText.push('text-' + name + ':' + val);\n    });\n\n    return cssText.join(';');\n}\n\n/**\n * @param {Object} tooltipModel\n * @return {string}\n * @inner\n */\nfunction assembleCssText(tooltipModel) {\n\n    var cssText = [];\n\n    var transitionDuration = tooltipModel.get('transitionDuration');\n    var backgroundColor = tooltipModel.get('backgroundColor');\n    var textStyleModel = tooltipModel.getModel('textStyle');\n    var padding = tooltipModel.get('padding');\n\n    // Animation transition. Do not animate when transitionDuration is 0.\n    transitionDuration\n        && cssText.push(assembleTransition(transitionDuration));\n\n    if (backgroundColor) {\n        if (env$1.canvasSupported) {\n            cssText.push('background-Color:' + backgroundColor);\n        }\n        else {\n            // for ie\n            cssText.push(\n                'background-Color:#' + toHex(backgroundColor)\n            );\n            cssText.push('filter:alpha(opacity=70)');\n        }\n    }\n\n    // Border style\n    each$10(['width', 'color', 'radius'], function (name) {\n        var borderName = 'border-' + name;\n        var camelCase = toCamelCase$1(borderName);\n        var val = tooltipModel.get(camelCase);\n        val != null\n            && cssText.push(borderName + ':' + val + (name === 'color' ? '' : 'px'));\n    });\n\n    // Text style\n    cssText.push(assembleFont(textStyleModel));\n\n    // Padding\n    if (padding != null) {\n        cssText.push('padding:' + normalizeCssArray$1(padding).join('px ') + 'px');\n    }\n\n    return cssText.join(';') + ';';\n}\n\n/**\n * @alias module:echarts/component/tooltip/TooltipContent\n * @constructor\n */\nfunction TooltipContent(container, api) {\n    if (env$1.wxa) {\n        return null;\n    }\n\n    var el = document.createElement('div');\n    var zr = this._zr = api.getZr();\n\n    this.el = el;\n\n    this._x = api.getWidth() / 2;\n    this._y = api.getHeight() / 2;\n\n    container.appendChild(el);\n\n    this._container = container;\n\n    this._show = false;\n\n    /**\n     * @private\n     */\n    this._hideTimeout;\n\n    var self = this;\n    el.onmouseenter = function () {\n        // clear the timeout in hideLater and keep showing tooltip\n        if (self._enterable) {\n            clearTimeout(self._hideTimeout);\n            self._show = true;\n        }\n        self._inContent = true;\n    };\n    el.onmousemove = function (e) {\n        e = e || window.event;\n        if (!self._enterable) {\n            // Try trigger zrender event to avoid mouse\n            // in and out shape too frequently\n            var handler = zr.handler;\n            normalizeEvent(container, e, true);\n            handler.dispatch('mousemove', e);\n        }\n    };\n    el.onmouseleave = function () {\n        if (self._enterable) {\n            if (self._show) {\n                self.hideLater(self._hideDelay);\n            }\n        }\n        self._inContent = false;\n    };\n}\n\nTooltipContent.prototype = {\n\n    constructor: TooltipContent,\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    _enterable: true,\n\n    /**\n     * Update when tooltip is rendered\n     */\n    update: function () {\n        // FIXME\n        // Move this logic to ec main?\n        var container = this._container;\n        var stl = container.currentStyle\n            || document.defaultView.getComputedStyle(container);\n        var domStyle = container.style;\n        if (domStyle.position !== 'absolute' && stl.position !== 'absolute') {\n            domStyle.position = 'relative';\n        }\n        // Hide the tooltip\n        // PENDING\n        // this.hide();\n    },\n\n    show: function (tooltipModel) {\n        clearTimeout(this._hideTimeout);\n        var el = this.el;\n\n        el.style.cssText = gCssText + assembleCssText(tooltipModel)\n            // http://stackoverflow.com/questions/21125587/css3-transition-not-working-in-chrome-anymore\n            + ';left:' + this._x + 'px;top:' + this._y + 'px;'\n            + (tooltipModel.get('extraCssText') || '');\n\n        el.style.display = el.innerHTML ? 'block' : 'none';\n\n        // If mouse occsionally move over the tooltip, a mouseout event will be\n        // triggered by canvas, and cuase some unexpectable result like dragging\n        // stop, \"unfocusAdjacency\". Here `pointer-events: none` is used to solve\n        // it. Although it is not suppored by IE8~IE10, fortunately it is a rare\n        // scenario.\n        el.style.pointerEvents = this._enterable ? 'auto' : 'none';\n\n        this._show = true;\n    },\n\n    setContent: function (content) {\n        this.el.innerHTML = content == null ? '' : content;\n    },\n\n    setEnterable: function (enterable) {\n        this._enterable = enterable;\n    },\n\n    getSize: function () {\n        var el = this.el;\n        return [el.clientWidth, el.clientHeight];\n    },\n\n    moveTo: function (x, y) {\n        // xy should be based on canvas root. But tooltipContent is\n        // the sibling of canvas root. So padding of ec container\n        // should be considered here.\n        var zr = this._zr;\n        var viewportRootOffset;\n        if (zr && zr.painter && (viewportRootOffset = zr.painter.getViewportRootOffset())) {\n            x += viewportRootOffset.offsetLeft;\n            y += viewportRootOffset.offsetTop;\n        }\n\n        var style = this.el.style;\n        style.left = x + 'px';\n        style.top = y + 'px';\n\n        this._x = x;\n        this._y = y;\n    },\n\n    hide: function () {\n        this.el.style.display = 'none';\n        this._show = false;\n    },\n\n    hideLater: function (time) {\n        if (this._show && !(this._inContent && this._enterable)) {\n            if (time) {\n                this._hideDelay = time;\n                // Set show false to avoid invoke hideLater mutiple times\n                this._show = false;\n                this._hideTimeout = setTimeout(bind(this.hide, this), time);\n            }\n            else {\n                this.hide();\n            }\n        }\n    },\n\n    isShow: function () {\n        return this._show;\n    },\n\n    getOuterSize: function () {\n        var width = this.el.clientWidth;\n        var height = this.el.clientHeight;\n\n        // Consider browser compatibility.\n        // IE8 does not support getComputedStyle.\n        if (document.defaultView && document.defaultView.getComputedStyle) {\n            var stl = document.defaultView.getComputedStyle(this.el);\n            if (stl) {\n                width += parseInt(stl.paddingLeft, 10) + parseInt(stl.paddingRight, 10)\n                    + parseInt(stl.borderLeftWidth, 10) + parseInt(stl.borderRightWidth, 10);\n                height += parseInt(stl.paddingTop, 10) + parseInt(stl.paddingBottom, 10)\n                    + parseInt(stl.borderTopWidth, 10) + parseInt(stl.borderBottomWidth, 10);\n            }\n        }\n\n        return {width: width, height: height};\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import Group from 'zrender/src/container/Group';\n/**\n * @alias module:echarts/component/tooltip/TooltipRichContent\n * @constructor\n */\nfunction TooltipRichContent(api) {\n\n    this._zr = api.getZr();\n\n    this._show = false;\n\n    /**\n     * @private\n     */\n    this._hideTimeout;\n}\n\nTooltipRichContent.prototype = {\n\n    constructor: TooltipRichContent,\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    _enterable: true,\n\n    /**\n     * Update when tooltip is rendered\n     */\n    update: function () {\n        // noop\n    },\n\n    show: function (tooltipModel) {\n        if (this._hideTimeout) {\n            clearTimeout(this._hideTimeout);\n        }\n\n        this.el.attr('show', true);\n        this._show = true;\n    },\n\n    /**\n     * Set tooltip content\n     *\n     * @param {string} content rich text string of content\n     * @param {Object} markerRich rich text style\n     * @param {Object} tooltipModel tooltip model\n     */\n    setContent: function (content, markerRich, tooltipModel) {\n        if (this.el) {\n            this._zr.remove(this.el);\n        }\n\n        var markers = {};\n        var text = content;\n        var prefix = '{marker';\n        var suffix = '|}';\n        var startId = text.indexOf(prefix);\n        while (startId >= 0) {\n            var endId = text.indexOf(suffix);\n            var name = text.substr(startId + prefix.length, endId - startId - prefix.length);\n            if (name.indexOf('sub') > -1) {\n                markers['marker' + name] = {\n                    textWidth: 4,\n                    textHeight: 4,\n                    textBorderRadius: 2,\n                    textBackgroundColor: markerRich[name],\n                    // TODO: textOffset is not implemented for rich text\n                    textOffset: [3, 0]\n                };\n            }\n            else {\n                markers['marker' + name] = {\n                    textWidth: 10,\n                    textHeight: 10,\n                    textBorderRadius: 5,\n                    textBackgroundColor: markerRich[name]\n                };\n            }\n\n            text = text.substr(endId + 1);\n            startId = text.indexOf('{marker');\n        }\n\n        this.el = new Text({\n            style: {\n                rich: markers,\n                text: content,\n                textLineHeight: 20,\n                textBackgroundColor: tooltipModel.get('backgroundColor'),\n                textBorderRadius: tooltipModel.get('borderRadius'),\n                textFill: tooltipModel.get('textStyle.color'),\n                textPadding: tooltipModel.get('padding')\n            },\n            z: tooltipModel.get('z')\n        });\n        this._zr.add(this.el);\n\n        var self = this;\n        this.el.on('mouseover', function () {\n            // clear the timeout in hideLater and keep showing tooltip\n            if (self._enterable) {\n                clearTimeout(self._hideTimeout);\n                self._show = true;\n            }\n            self._inContent = true;\n        });\n        this.el.on('mouseout', function () {\n            if (self._enterable) {\n                if (self._show) {\n                    self.hideLater(self._hideDelay);\n                }\n            }\n            self._inContent = false;\n        });\n    },\n\n    setEnterable: function (enterable) {\n        this._enterable = enterable;\n    },\n\n    getSize: function () {\n        var bounding = this.el.getBoundingRect();\n        return [bounding.width, bounding.height];\n    },\n\n    moveTo: function (x, y) {\n        if (this.el) {\n            this.el.attr('position', [x, y]);\n        }\n    },\n\n    hide: function () {\n        this.el.hide();\n        this._show = false;\n    },\n\n    hideLater: function (time) {\n        if (this._show && !(this._inContent && this._enterable)) {\n            if (time) {\n                this._hideDelay = time;\n                // Set show false to avoid invoke hideLater mutiple times\n                this._show = false;\n                this._hideTimeout = setTimeout(bind(this.hide, this), time);\n            }\n            else {\n                this.hide();\n            }\n        }\n    },\n\n    isShow: function () {\n        return this._show;\n    },\n\n    getOuterSize: function () {\n        return this.getSize();\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$2 = bind;\nvar each$9 = each$1;\nvar parsePercent$2 = parsePercent$1;\n\nvar proxyRect = new Rect({\n    shape: {x: -1, y: -1, width: 2, height: 2}\n});\n\nextendComponentView({\n\n    type: 'tooltip',\n\n    init: function (ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n\n        var tooltipModel = ecModel.getComponent('tooltip');\n        var renderMode = tooltipModel.get('renderMode');\n        this._renderMode = getTooltipRenderMode(renderMode);\n\n        var tooltipContent;\n        if (this._renderMode === 'html') {\n            tooltipContent = new TooltipContent(api.getDom(), api);\n            this._newLine = '<br/>';\n        }\n        else {\n            tooltipContent = new TooltipRichContent(api);\n            this._newLine = '\\n';\n        }\n\n        this._tooltipContent = tooltipContent;\n    },\n\n    render: function (tooltipModel, ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n\n        // Reset\n        this.group.removeAll();\n\n        /**\n         * @private\n         * @type {module:echarts/component/tooltip/TooltipModel}\n         */\n        this._tooltipModel = tooltipModel;\n\n        /**\n         * @private\n         * @type {module:echarts/model/Global}\n         */\n        this._ecModel = ecModel;\n\n        /**\n         * @private\n         * @type {module:echarts/ExtensionAPI}\n         */\n        this._api = api;\n\n        /**\n         * Should be cleaned when render.\n         * @private\n         * @type {Array.<Array.<Object>>}\n         */\n        this._lastDataByCoordSys = null;\n\n        /**\n         * @private\n         * @type {boolean}\n         */\n        this._alwaysShowContent = tooltipModel.get('alwaysShowContent');\n\n        var tooltipContent = this._tooltipContent;\n        tooltipContent.update();\n        tooltipContent.setEnterable(tooltipModel.get('enterable'));\n\n        this._initGlobalListener();\n\n        this._keepShow();\n    },\n\n    _initGlobalListener: function () {\n        var tooltipModel = this._tooltipModel;\n        var triggerOn = tooltipModel.get('triggerOn');\n\n        register(\n            'itemTooltip',\n            this._api,\n            bind$2(function (currTrigger, e, dispatchAction) {\n                // If 'none', it is not controlled by mouse totally.\n                if (triggerOn !== 'none') {\n                    if (triggerOn.indexOf(currTrigger) >= 0) {\n                        this._tryShow(e, dispatchAction);\n                    }\n                    else if (currTrigger === 'leave') {\n                        this._hide(dispatchAction);\n                    }\n                }\n            }, this)\n        );\n    },\n\n    _keepShow: function () {\n        var tooltipModel = this._tooltipModel;\n        var ecModel = this._ecModel;\n        var api = this._api;\n\n        // Try to keep the tooltip show when refreshing\n        if (this._lastX != null\n            && this._lastY != null\n            // When user is willing to control tooltip totally using API,\n            // self.manuallyShowTip({x, y}) might cause tooltip hide,\n            // which is not expected.\n            && tooltipModel.get('triggerOn') !== 'none'\n        ) {\n            var self = this;\n            clearTimeout(this._refreshUpdateTimeout);\n            this._refreshUpdateTimeout = setTimeout(function () {\n                // Show tip next tick after other charts are rendered\n                // In case highlight action has wrong result\n                // FIXME\n                self.manuallyShowTip(tooltipModel, ecModel, api, {\n                    x: self._lastX,\n                    y: self._lastY\n                });\n            });\n        }\n    },\n\n    /**\n     * Show tip manually by\n     * dispatchAction({\n     *     type: 'showTip',\n     *     x: 10,\n     *     y: 10\n     * });\n     * Or\n     * dispatchAction({\n     *      type: 'showTip',\n     *      seriesIndex: 0,\n     *      dataIndex or dataIndexInside or name\n     * });\n     *\n     *  TODO Batch\n     */\n    manuallyShowTip: function (tooltipModel, ecModel, api, payload) {\n        if (payload.from === this.uid || env$1.node) {\n            return;\n        }\n\n        var dispatchAction = makeDispatchAction$1(payload, api);\n\n        // Reset ticket\n        this._ticket = '';\n\n        // When triggered from axisPointer.\n        var dataByCoordSys = payload.dataByCoordSys;\n\n        if (payload.tooltip && payload.x != null && payload.y != null) {\n            var el = proxyRect;\n            el.position = [payload.x, payload.y];\n            el.update();\n            el.tooltip = payload.tooltip;\n            // Manually show tooltip while view is not using zrender elements.\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                target: el\n            }, dispatchAction);\n        }\n        else if (dataByCoordSys) {\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                position: payload.position,\n                event: {},\n                dataByCoordSys: payload.dataByCoordSys,\n                tooltipOption: payload.tooltipOption\n            }, dispatchAction);\n        }\n        else if (payload.seriesIndex != null) {\n\n            if (this._manuallyAxisShowTip(tooltipModel, ecModel, api, payload)) {\n                return;\n            }\n\n            var pointInfo = findPointFromSeries(payload, ecModel);\n            var cx = pointInfo.point[0];\n            var cy = pointInfo.point[1];\n            if (cx != null && cy != null) {\n                this._tryShow({\n                    offsetX: cx,\n                    offsetY: cy,\n                    position: payload.position,\n                    target: pointInfo.el,\n                    event: {}\n                }, dispatchAction);\n            }\n        }\n        else if (payload.x != null && payload.y != null) {\n            // FIXME\n            // should wrap dispatchAction like `axisPointer/globalListener` ?\n            api.dispatchAction({\n                type: 'updateAxisPointer',\n                x: payload.x,\n                y: payload.y\n            });\n\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                position: payload.position,\n                target: api.getZr().findHover(payload.x, payload.y).target,\n                event: {}\n            }, dispatchAction);\n        }\n    },\n\n    manuallyHideTip: function (tooltipModel, ecModel, api, payload) {\n        var tooltipContent = this._tooltipContent;\n\n        if (!this._alwaysShowContent && this._tooltipModel) {\n            tooltipContent.hideLater(this._tooltipModel.get('hideDelay'));\n        }\n\n        this._lastX = this._lastY = null;\n\n        if (payload.from !== this.uid) {\n            this._hide(makeDispatchAction$1(payload, api));\n        }\n    },\n\n    // Be compatible with previous design, that is, when tooltip.type is 'axis' and\n    // dispatchAction 'showTip' with seriesIndex and dataIndex will trigger axis pointer\n    // and tooltip.\n    _manuallyAxisShowTip: function (tooltipModel, ecModel, api, payload) {\n        var seriesIndex = payload.seriesIndex;\n        var dataIndex = payload.dataIndex;\n        var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo;\n\n        if (seriesIndex == null || dataIndex == null || coordSysAxesInfo == null) {\n            return;\n        }\n\n        var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n        if (!seriesModel) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var tooltipModel = buildTooltipModel([\n            data.getItemModel(dataIndex),\n            seriesModel,\n            (seriesModel.coordinateSystem || {}).model,\n            tooltipModel\n        ]);\n\n        if (tooltipModel.get('trigger') !== 'axis') {\n            return;\n        }\n\n        api.dispatchAction({\n            type: 'updateAxisPointer',\n            seriesIndex: seriesIndex,\n            dataIndex: dataIndex,\n            position: payload.position\n        });\n\n        return true;\n    },\n\n    _tryShow: function (e, dispatchAction) {\n        var el = e.target;\n        var tooltipModel = this._tooltipModel;\n\n        if (!tooltipModel) {\n            return;\n        }\n\n        // Save mouse x, mouse y. So we can try to keep showing the tip if chart is refreshed\n        this._lastX = e.offsetX;\n        this._lastY = e.offsetY;\n\n        var dataByCoordSys = e.dataByCoordSys;\n        if (dataByCoordSys && dataByCoordSys.length) {\n            this._showAxisTooltip(dataByCoordSys, e);\n        }\n        // Always show item tooltip if mouse is on the element with dataIndex\n        else if (el && el.dataIndex != null) {\n            this._lastDataByCoordSys = null;\n            this._showSeriesItemTooltip(e, el, dispatchAction);\n        }\n        // Tooltip provided directly. Like legend.\n        else if (el && el.tooltip) {\n            this._lastDataByCoordSys = null;\n            this._showComponentItemTooltip(e, el, dispatchAction);\n        }\n        else {\n            this._lastDataByCoordSys = null;\n            this._hide(dispatchAction);\n        }\n    },\n\n    _showOrMove: function (tooltipModel, cb) {\n        // showDelay is used in this case: tooltip.enterable is set\n        // as true. User intent to move mouse into tooltip and click\n        // something. `showDelay` makes it easyer to enter the content\n        // but tooltip do not move immediately.\n        var delay = tooltipModel.get('showDelay');\n        cb = bind(cb, this);\n        clearTimeout(this._showTimout);\n        delay > 0\n            ? (this._showTimout = setTimeout(cb, delay))\n            : cb();\n    },\n\n    _showAxisTooltip: function (dataByCoordSys, e) {\n        var ecModel = this._ecModel;\n        var globalTooltipModel = this._tooltipModel;\n        var point = [e.offsetX, e.offsetY];\n        var singleDefaultHTML = [];\n        var singleParamsList = [];\n        var singleTooltipModel = buildTooltipModel([\n            e.tooltipOption,\n            globalTooltipModel\n        ]);\n\n        var renderMode = this._renderMode;\n        var newLine = this._newLine;\n\n        var markers = {};\n\n        each$9(dataByCoordSys, function (itemCoordSys) {\n            // var coordParamList = [];\n            // var coordDefaultHTML = [];\n            // var coordTooltipModel = buildTooltipModel([\n            //     e.tooltipOption,\n            //     itemCoordSys.tooltipOption,\n            //     ecModel.getComponent(itemCoordSys.coordSysMainType, itemCoordSys.coordSysIndex),\n            //     globalTooltipModel\n            // ]);\n            // var displayMode = coordTooltipModel.get('displayMode');\n            // var paramsList = displayMode === 'single' ? singleParamsList : [];\n\n            each$9(itemCoordSys.dataByAxis, function (item) {\n                var axisModel = ecModel.getComponent(item.axisDim + 'Axis', item.axisIndex);\n                var axisValue = item.value;\n                var seriesDefaultHTML = [];\n\n                if (!axisModel || axisValue == null) {\n                    return;\n                }\n\n                var valueLabel = getValueLabel(\n                    axisValue, axisModel.axis, ecModel,\n                    item.seriesDataIndices,\n                    item.valueLabelOpt\n                );\n\n                each$1(item.seriesDataIndices, function (idxItem) {\n                    var series = ecModel.getSeriesByIndex(idxItem.seriesIndex);\n                    var dataIndex = idxItem.dataIndexInside;\n                    var dataParams = series && series.getDataParams(dataIndex);\n                    dataParams.axisDim = item.axisDim;\n                    dataParams.axisIndex = item.axisIndex;\n                    dataParams.axisType = item.axisType;\n                    dataParams.axisId = item.axisId;\n                    dataParams.axisValue = getAxisRawValue(axisModel.axis, axisValue);\n                    dataParams.axisValueLabel = valueLabel;\n\n                    if (dataParams) {\n                        singleParamsList.push(dataParams);\n                        var seriesTooltip = series.formatTooltip(dataIndex, true, null, renderMode);\n\n                        var html;\n                        if (isObject$1(seriesTooltip)) {\n                            html = seriesTooltip.html;\n                            var newMarkers = seriesTooltip.markers;\n                            merge(markers, newMarkers);\n                        }\n                        else {\n                            html = seriesTooltip;\n                        }\n                        seriesDefaultHTML.push(html);\n                    }\n                });\n\n                // Default tooltip content\n                // FIXME\n                // (1) shold be the first data which has name?\n                // (2) themeRiver, firstDataIndex is array, and first line is unnecessary.\n                var firstLine = valueLabel;\n                if (renderMode !== 'html') {\n                    singleDefaultHTML.push(seriesDefaultHTML.join(newLine));\n                }\n                else {\n                    singleDefaultHTML.push(\n                        (firstLine ? encodeHTML(firstLine) + newLine : '')\n                        + seriesDefaultHTML.join(newLine)\n                    );\n                }\n            });\n        }, this);\n\n        // In most case, the second axis is shown upper than the first one.\n        singleDefaultHTML.reverse();\n        singleDefaultHTML = singleDefaultHTML.join(this._newLine + this._newLine);\n\n        var positionExpr = e.position;\n        this._showOrMove(singleTooltipModel, function () {\n            if (this._updateContentNotChangedOnAxis(dataByCoordSys)) {\n                this._updatePosition(\n                    singleTooltipModel,\n                    positionExpr,\n                    point[0], point[1],\n                    this._tooltipContent,\n                    singleParamsList\n                );\n            }\n            else {\n                this._showTooltipContent(\n                    singleTooltipModel, singleDefaultHTML, singleParamsList, Math.random(),\n                    point[0], point[1], positionExpr, undefined, markers\n                );\n            }\n        });\n\n        // Do not trigger events here, because this branch only be entered\n        // from dispatchAction.\n    },\n\n    _showSeriesItemTooltip: function (e, el, dispatchAction) {\n        var ecModel = this._ecModel;\n        // Use dataModel in element if possible\n        // Used when mouseover on a element like markPoint or edge\n        // In which case, the data is not main data in series.\n        var seriesIndex = el.seriesIndex;\n        var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n\n        // For example, graph link.\n        var dataModel = el.dataModel || seriesModel;\n        var dataIndex = el.dataIndex;\n        var dataType = el.dataType;\n        var data = dataModel.getData();\n\n        var tooltipModel = buildTooltipModel([\n            data.getItemModel(dataIndex),\n            dataModel,\n            seriesModel && (seriesModel.coordinateSystem || {}).model,\n            this._tooltipModel\n        ]);\n\n        var tooltipTrigger = tooltipModel.get('trigger');\n        if (tooltipTrigger != null && tooltipTrigger !== 'item') {\n            return;\n        }\n\n        var params = dataModel.getDataParams(dataIndex, dataType);\n        var seriesTooltip = dataModel.formatTooltip(dataIndex, false, dataType, this._renderMode);\n        var defaultHtml;\n        var markers;\n        if (isObject$1(seriesTooltip)) {\n            defaultHtml = seriesTooltip.html;\n            markers = seriesTooltip.markers;\n        }\n        else {\n            defaultHtml = seriesTooltip;\n            markers = null;\n        }\n\n        var asyncTicket = 'item_' + dataModel.name + '_' + dataIndex;\n\n        this._showOrMove(tooltipModel, function () {\n            this._showTooltipContent(\n                tooltipModel, defaultHtml, params, asyncTicket,\n                e.offsetX, e.offsetY, e.position, e.target, markers\n            );\n        });\n\n        // FIXME\n        // duplicated showtip if manuallyShowTip is called from dispatchAction.\n        dispatchAction({\n            type: 'showTip',\n            dataIndexInside: dataIndex,\n            dataIndex: data.getRawIndex(dataIndex),\n            seriesIndex: seriesIndex,\n            from: this.uid\n        });\n    },\n\n    _showComponentItemTooltip: function (e, el, dispatchAction) {\n        var tooltipOpt = el.tooltip;\n        if (typeof tooltipOpt === 'string') {\n            var content = tooltipOpt;\n            tooltipOpt = {\n                content: content,\n                // Fixed formatter\n                formatter: content\n            };\n        }\n        var subTooltipModel = new Model(tooltipOpt, this._tooltipModel, this._ecModel);\n        var defaultHtml = subTooltipModel.get('content');\n        var asyncTicket = Math.random();\n\n        // Do not check whether `trigger` is 'none' here, because `trigger`\n        // only works on cooridinate system. In fact, we have not found case\n        // that requires setting `trigger` nothing on component yet.\n\n        this._showOrMove(subTooltipModel, function () {\n            this._showTooltipContent(\n                subTooltipModel, defaultHtml, subTooltipModel.get('formatterParams') || {},\n                asyncTicket, e.offsetX, e.offsetY, e.position, el\n            );\n        });\n\n        // If not dispatch showTip, tip may be hide triggered by axis.\n        dispatchAction({\n            type: 'showTip',\n            from: this.uid\n        });\n    },\n\n    _showTooltipContent: function (\n        tooltipModel, defaultHtml, params, asyncTicket, x, y, positionExpr, el, markers\n    ) {\n        // Reset ticket\n        this._ticket = '';\n\n        if (!tooltipModel.get('showContent') || !tooltipModel.get('show')) {\n            return;\n        }\n\n        var tooltipContent = this._tooltipContent;\n\n        var formatter = tooltipModel.get('formatter');\n        positionExpr = positionExpr || tooltipModel.get('position');\n        var html = defaultHtml;\n\n        if (formatter && typeof formatter === 'string') {\n            html = formatTpl(formatter, params, true);\n        }\n        else if (typeof formatter === 'function') {\n            var callback = bind$2(function (cbTicket, html) {\n                if (cbTicket === this._ticket) {\n                    tooltipContent.setContent(html, markers, tooltipModel);\n                    this._updatePosition(\n                        tooltipModel, positionExpr, x, y, tooltipContent, params, el\n                    );\n                }\n            }, this);\n            this._ticket = asyncTicket;\n            html = formatter(params, asyncTicket, callback);\n        }\n\n        tooltipContent.setContent(html, markers, tooltipModel);\n        tooltipContent.show(tooltipModel);\n\n        this._updatePosition(\n            tooltipModel, positionExpr, x, y, tooltipContent, params, el\n        );\n    },\n\n    /**\n     * @param  {string|Function|Array.<number>|Object} positionExpr\n     * @param  {number} x Mouse x\n     * @param  {number} y Mouse y\n     * @param  {boolean} confine Whether confine tooltip content in view rect.\n     * @param  {Object|<Array.<Object>} params\n     * @param  {module:zrender/Element} el target element\n     * @param  {module:echarts/ExtensionAPI} api\n     * @return {Array.<number>}\n     */\n    _updatePosition: function (tooltipModel, positionExpr, x, y, content, params, el) {\n        var viewWidth = this._api.getWidth();\n        var viewHeight = this._api.getHeight();\n        positionExpr = positionExpr || tooltipModel.get('position');\n\n        var contentSize = content.getSize();\n        var align = tooltipModel.get('align');\n        var vAlign = tooltipModel.get('verticalAlign');\n        var rect = el && el.getBoundingRect().clone();\n        el && rect.applyTransform(el.transform);\n\n        if (typeof positionExpr === 'function') {\n            // Callback of position can be an array or a string specify the position\n            positionExpr = positionExpr([x, y], params, content.el, rect, {\n                viewSize: [viewWidth, viewHeight],\n                contentSize: contentSize.slice()\n            });\n        }\n\n        if (isArray(positionExpr)) {\n            x = parsePercent$2(positionExpr[0], viewWidth);\n            y = parsePercent$2(positionExpr[1], viewHeight);\n        }\n        else if (isObject$1(positionExpr)) {\n            positionExpr.width = contentSize[0];\n            positionExpr.height = contentSize[1];\n            var layoutRect = getLayoutRect(\n                positionExpr, {width: viewWidth, height: viewHeight}\n            );\n            x = layoutRect.x;\n            y = layoutRect.y;\n            align = null;\n            // When positionExpr is left/top/right/bottom,\n            // align and verticalAlign will not work.\n            vAlign = null;\n        }\n        // Specify tooltip position by string 'top' 'bottom' 'left' 'right' around graphic element\n        else if (typeof positionExpr === 'string' && el) {\n            var pos = calcTooltipPosition(\n                positionExpr, rect, contentSize\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n        else {\n            var pos = refixTooltipPosition(\n                x, y, content, viewWidth, viewHeight, align ? null : 20, vAlign ? null : 20\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n\n        align && (x -= isCenterAlign(align) ? contentSize[0] / 2 : align === 'right' ? contentSize[0] : 0);\n        vAlign && (y -= isCenterAlign(vAlign) ? contentSize[1] / 2 : vAlign === 'bottom' ? contentSize[1] : 0);\n\n        if (tooltipModel.get('confine')) {\n            var pos = confineTooltipPosition(\n                x, y, content, viewWidth, viewHeight\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n\n        content.moveTo(x, y);\n    },\n\n    // FIXME\n    // Should we remove this but leave this to user?\n    _updateContentNotChangedOnAxis: function (dataByCoordSys) {\n        var lastCoordSys = this._lastDataByCoordSys;\n        var contentNotChanged = !!lastCoordSys\n            && lastCoordSys.length === dataByCoordSys.length;\n\n        contentNotChanged && each$9(lastCoordSys, function (lastItemCoordSys, indexCoordSys) {\n            var lastDataByAxis = lastItemCoordSys.dataByAxis || {};\n            var thisItemCoordSys = dataByCoordSys[indexCoordSys] || {};\n            var thisDataByAxis = thisItemCoordSys.dataByAxis || [];\n            contentNotChanged &= lastDataByAxis.length === thisDataByAxis.length;\n\n            contentNotChanged && each$9(lastDataByAxis, function (lastItem, indexAxis) {\n                var thisItem = thisDataByAxis[indexAxis] || {};\n                var lastIndices = lastItem.seriesDataIndices || [];\n                var newIndices = thisItem.seriesDataIndices || [];\n\n                contentNotChanged\n                    &= lastItem.value === thisItem.value\n                    && lastItem.axisType === thisItem.axisType\n                    && lastItem.axisId === thisItem.axisId\n                    && lastIndices.length === newIndices.length;\n\n                contentNotChanged && each$9(lastIndices, function (lastIdxItem, j) {\n                    var newIdxItem = newIndices[j];\n                    contentNotChanged\n                        &= lastIdxItem.seriesIndex === newIdxItem.seriesIndex\n                        && lastIdxItem.dataIndex === newIdxItem.dataIndex;\n                });\n            });\n        });\n\n        this._lastDataByCoordSys = dataByCoordSys;\n\n        return !!contentNotChanged;\n    },\n\n    _hide: function (dispatchAction) {\n        // Do not directly hideLater here, because this behavior may be prevented\n        // in dispatchAction when showTip is dispatched.\n\n        // FIXME\n        // duplicated hideTip if manuallyHideTip is called from dispatchAction.\n        this._lastDataByCoordSys = null;\n        dispatchAction({\n            type: 'hideTip',\n            from: this.uid\n        });\n    },\n\n    dispose: function (ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n        this._tooltipContent.hide();\n        unregister('itemTooltip', api);\n    }\n});\n\n\n/**\n * @param {Array.<Object|module:echarts/model/Model>} modelCascade\n * From top to bottom. (the last one should be globalTooltipModel);\n */\nfunction buildTooltipModel(modelCascade) {\n    var resultModel = modelCascade.pop();\n    while (modelCascade.length) {\n        var tooltipOpt = modelCascade.pop();\n        if (tooltipOpt) {\n            if (Model.isInstance(tooltipOpt)) {\n                tooltipOpt = tooltipOpt.get('tooltip', true);\n            }\n            // In each data item tooltip can be simply write:\n            // {\n            //  value: 10,\n            //  tooltip: 'Something you need to know'\n            // }\n            if (typeof tooltipOpt === 'string') {\n                tooltipOpt = {formatter: tooltipOpt};\n            }\n            resultModel = new Model(tooltipOpt, resultModel, resultModel.ecModel);\n        }\n    }\n    return resultModel;\n}\n\nfunction makeDispatchAction$1(payload, api) {\n    return payload.dispatchAction || bind(api.dispatchAction, api);\n}\n\nfunction refixTooltipPosition(x, y, content, viewWidth, viewHeight, gapH, gapV) {\n    var size = content.getOuterSize();\n    var width = size.width;\n    var height = size.height;\n\n    if (gapH != null) {\n        if (x + width + gapH > viewWidth) {\n            x -= width + gapH;\n        }\n        else {\n            x += gapH;\n        }\n    }\n    if (gapV != null) {\n        if (y + height + gapV > viewHeight) {\n            y -= height + gapV;\n        }\n        else {\n            y += gapV;\n        }\n    }\n    return [x, y];\n}\n\nfunction confineTooltipPosition(x, y, content, viewWidth, viewHeight) {\n    var size = content.getOuterSize();\n    var width = size.width;\n    var height = size.height;\n\n    x = Math.min(x + width, viewWidth) - width;\n    y = Math.min(y + height, viewHeight) - height;\n    x = Math.max(x, 0);\n    y = Math.max(y, 0);\n\n    return [x, y];\n}\n\nfunction calcTooltipPosition(position, rect, contentSize) {\n    var domWidth = contentSize[0];\n    var domHeight = contentSize[1];\n    var gap = 5;\n    var x = 0;\n    var y = 0;\n    var rectWidth = rect.width;\n    var rectHeight = rect.height;\n    switch (position) {\n        case 'inside':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n            break;\n        case 'top':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y - domHeight - gap;\n            break;\n        case 'bottom':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y + rectHeight + gap;\n            break;\n        case 'left':\n            x = rect.x - domWidth - gap;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n            break;\n        case 'right':\n            x = rect.x + rectWidth + gap;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n    }\n    return [x, y];\n}\n\nfunction isCenterAlign(align) {\n    return align === 'center' || align === 'middle';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME Better way to pack data in graphic element\n\n/**\n * @action\n * @property {string} type\n * @property {number} seriesIndex\n * @property {number} dataIndex\n * @property {number} [x]\n * @property {number} [y]\n */\nregisterAction(\n    {\n        type: 'showTip',\n        event: 'showTip',\n        update: 'tooltip:manuallyShowTip'\n    },\n    // noop\n    function () {}\n);\n\nregisterAction(\n    {\n        type: 'hideTip',\n        event: 'hideTip',\n        update: 'tooltip:manuallyHideTip'\n    },\n    // noop\n    function () {}\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar LegendModel = extendComponentModel({\n\n    type: 'legend.plain',\n\n    dependencies: ['series'],\n\n    layoutMode: {\n        type: 'box',\n        // legend.width/height are maxWidth/maxHeight actually,\n        // whereas realy width/height is calculated by its content.\n        // (Setting {left: 10, right: 10} does not make sense).\n        // So consider the case:\n        // `setOption({legend: {left: 10});`\n        // then `setOption({legend: {right: 10});`\n        // The previous `left` should be cleared by setting `ignoreSize`.\n        ignoreSize: true\n    },\n\n    init: function (option, parentModel, ecModel) {\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        option.selected = option.selected || {};\n    },\n\n    mergeOption: function (option) {\n        LegendModel.superCall(this, 'mergeOption', option);\n    },\n\n    optionUpdated: function () {\n        this._updateData(this.ecModel);\n\n        var legendData = this._data;\n\n        // If selectedMode is single, try to select one\n        if (legendData[0] && this.get('selectedMode') === 'single') {\n            var hasSelected = false;\n            // If has any selected in option.selected\n            for (var i = 0; i < legendData.length; i++) {\n                var name = legendData[i].get('name');\n                if (this.isSelected(name)) {\n                    // Force to unselect others\n                    this.select(name);\n                    hasSelected = true;\n                    break;\n                }\n            }\n            // Try select the first if selectedMode is single\n            !hasSelected && this.select(legendData[0].get('name'));\n        }\n    },\n\n    _updateData: function (ecModel) {\n        var potentialData = [];\n        var availableNames = [];\n\n        ecModel.eachRawSeries(function (seriesModel) {\n            var seriesName = seriesModel.name;\n            availableNames.push(seriesName);\n            var isPotential;\n\n            if (seriesModel.legendDataProvider) {\n                var data = seriesModel.legendDataProvider();\n                var names = data.mapArray(data.getName);\n\n                if (!ecModel.isSeriesFiltered(seriesModel)) {\n                    availableNames = availableNames.concat(names);\n                }\n\n                if (names.length) {\n                    potentialData = potentialData.concat(names);\n                }\n                else {\n                    isPotential = true;\n                }\n            }\n            else {\n                isPotential = true;\n            }\n\n            if (isPotential && isNameSpecified(seriesModel)) {\n                potentialData.push(seriesModel.name);\n            }\n        });\n\n        /**\n         * @type {Array.<string>}\n         * @private\n         */\n        this._availableNames = availableNames;\n\n        // If legend.data not specified in option, use availableNames as data,\n        // which is convinient for user preparing option.\n        var rawData = this.get('data') || potentialData;\n\n        var legendData = map(rawData, function (dataItem) {\n            // Can be string or number\n            if (typeof dataItem === 'string' || typeof dataItem === 'number') {\n                dataItem = {\n                    name: dataItem\n                };\n            }\n            return new Model(dataItem, this, this.ecModel);\n        }, this);\n\n        /**\n         * @type {Array.<module:echarts/model/Model>}\n         * @private\n         */\n        this._data = legendData;\n    },\n\n    /**\n     * @return {Array.<module:echarts/model/Model>}\n     */\n    getData: function () {\n        return this._data;\n    },\n\n    /**\n     * @param {string} name\n     */\n    select: function (name) {\n        var selected = this.option.selected;\n        var selectedMode = this.get('selectedMode');\n        if (selectedMode === 'single') {\n            var data = this._data;\n            each$1(data, function (dataItem) {\n                selected[dataItem.get('name')] = false;\n            });\n        }\n        selected[name] = true;\n    },\n\n    /**\n     * @param {string} name\n     */\n    unSelect: function (name) {\n        if (this.get('selectedMode') !== 'single') {\n            this.option.selected[name] = false;\n        }\n    },\n\n    /**\n     * @param {string} name\n     */\n    toggleSelected: function (name) {\n        var selected = this.option.selected;\n        // Default is true\n        if (!selected.hasOwnProperty(name)) {\n            selected[name] = true;\n        }\n        this[selected[name] ? 'unSelect' : 'select'](name);\n    },\n\n    /**\n     * @param {string} name\n     */\n    isSelected: function (name) {\n        var selected = this.option.selected;\n        return !(selected.hasOwnProperty(name) && !selected[name])\n            && indexOf(this._availableNames, name) >= 0;\n    },\n\n    defaultOption: {\n        // 一级层叠\n        zlevel: 0,\n        // 二级层叠\n        z: 4,\n        show: true,\n\n        // 布局方式，默认为水平布局，可选为：\n        // 'horizontal' | 'vertical'\n        orient: 'horizontal',\n\n        left: 'center',\n        // right: 'center',\n\n        top: 0,\n        // bottom: null,\n\n        // 水平对齐\n        // 'auto' | 'left' | 'right'\n        // 默认为 'auto', 根据 x 的位置判断是左对齐还是右对齐\n        align: 'auto',\n\n        backgroundColor: 'rgba(0,0,0,0)',\n        // 图例边框颜色\n        borderColor: '#ccc',\n        borderRadius: 0,\n        // 图例边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n        // 图例内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n        // 各个item之间的间隔，单位px，默认为10，\n        // 横向布局时为水平间隔，纵向布局时为纵向间隔\n        itemGap: 10,\n        // 图例图形宽度\n        itemWidth: 25,\n        // 图例图形高度\n        itemHeight: 14,\n\n        // 图例关闭时候的颜色\n        inactiveColor: '#ccc',\n\n        textStyle: {\n            // 图例文字颜色\n            color: '#333'\n        },\n        // formatter: '',\n        // 选择模式，默认开启图例开关\n        selectedMode: true,\n        // 配置默认选中状态，可配合LEGEND.SELECTED事件做动态数据载入\n        // selected: null,\n        // 图例内容（详见legend.data，数组中每一项代表一个item\n        // data: [],\n\n        // Tooltip 相关配置\n        tooltip: {\n            show: false\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction legendSelectActionHandler(methodName, payload, ecModel) {\n    var selectedMap = {};\n    var isToggleSelect = methodName === 'toggleSelected';\n    var isSelected;\n    // Update all legend components\n    ecModel.eachComponent('legend', function (legendModel) {\n        if (isToggleSelect && isSelected != null) {\n            // Force other legend has same selected status\n            // Or the first is toggled to true and other are toggled to false\n            // In the case one legend has some item unSelected in option. And if other legend\n            // doesn't has the item, they will assume it is selected.\n            legendModel[isSelected ? 'select' : 'unSelect'](payload.name);\n        }\n        else {\n            legendModel[methodName](payload.name);\n            isSelected = legendModel.isSelected(payload.name);\n        }\n        var legendData = legendModel.getData();\n        each$1(legendData, function (model) {\n            var name = model.get('name');\n            // Wrap element\n            if (name === '\\n' || name === '') {\n                return;\n            }\n            var isItemSelected = legendModel.isSelected(name);\n            if (selectedMap.hasOwnProperty(name)) {\n                // Unselected if any legend is unselected\n                selectedMap[name] = selectedMap[name] && isItemSelected;\n            }\n            else {\n                selectedMap[name] = isItemSelected;\n            }\n        });\n    });\n    // Return the event explicitly\n    return {\n        name: payload.name,\n        selected: selectedMap\n    };\n}\n/**\n * @event legendToggleSelect\n * @type {Object}\n * @property {string} type 'legendToggleSelect'\n * @property {string} [from]\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendToggleSelect', 'legendselectchanged',\n    curry(legendSelectActionHandler, 'toggleSelected')\n);\n\n/**\n * @event legendSelect\n * @type {Object}\n * @property {string} type 'legendSelect'\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendSelect', 'legendselected',\n    curry(legendSelectActionHandler, 'select')\n);\n\n/**\n * @event legendUnSelect\n * @type {Object}\n * @property {string} type 'legendUnSelect'\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendUnSelect', 'legendunselected',\n    curry(legendSelectActionHandler, 'unSelect')\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Layout list like component.\n * It will box layout each items in group of component and then position the whole group in the viewport\n * @param {module:zrender/group/Group} group\n * @param {module:echarts/model/Component} componentModel\n * @param {module:echarts/ExtensionAPI}\n */\nfunction layout$2(group, componentModel, api) {\n    var boxLayoutParams = componentModel.getBoxLayoutParams();\n    var padding = componentModel.get('padding');\n    var viewportSize = {width: api.getWidth(), height: api.getHeight()};\n\n    var rect = getLayoutRect(\n        boxLayoutParams,\n        viewportSize,\n        padding\n    );\n\n    box(\n        componentModel.get('orient'),\n        group,\n        componentModel.get('itemGap'),\n        rect.width,\n        rect.height\n    );\n\n    positionElement(\n        group,\n        boxLayoutParams,\n        viewportSize,\n        padding\n    );\n}\n\nfunction makeBackground(rect, componentModel) {\n    var padding = normalizeCssArray$1(\n        componentModel.get('padding')\n    );\n    var style = componentModel.getItemStyle(['color', 'opacity']);\n    style.fill = componentModel.get('backgroundColor');\n    var rect = new Rect({\n        shape: {\n            x: rect.x - padding[3],\n            y: rect.y - padding[0],\n            width: rect.width + padding[1] + padding[3],\n            height: rect.height + padding[0] + padding[2],\n            r: componentModel.get('borderRadius')\n        },\n        style: style,\n        silent: true,\n        z2: -1\n    });\n    // FIXME\n    // `subPixelOptimizeRect` may bring some gap between edge of viewpart\n    // and background rect when setting like `left: 0`, `top: 0`.\n    // graphic.subPixelOptimizeRect(rect);\n\n    return rect;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar curry$3 = curry;\nvar each$11 = each$1;\nvar Group$2 = Group;\n\nvar LegendView = extendComponentView({\n\n    type: 'legend.plain',\n\n    newlineDisabled: false,\n\n    /**\n     * @override\n     */\n    init: function () {\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._contentGroup = new Group$2());\n\n        /**\n         * @private\n         * @type {module:zrender/Element}\n         */\n        this._backgroundEl;\n\n        /**\n         * If first rendering, `contentGroup.position` is [0, 0], which\n         * does not make sense and may cause unexepcted animation if adopted.\n         * @private\n         * @type {boolean}\n         */\n        this._isFirstRender = true;\n    },\n\n    /**\n     * @protected\n     */\n    getContentGroup: function () {\n        return this._contentGroup;\n    },\n\n    /**\n     * @override\n     */\n    render: function (legendModel, ecModel, api) {\n        var isFirstRender = this._isFirstRender;\n        this._isFirstRender = false;\n\n        this.resetInner();\n\n        if (!legendModel.get('show', true)) {\n            return;\n        }\n\n        var itemAlign = legendModel.get('align');\n        if (!itemAlign || itemAlign === 'auto') {\n            itemAlign = (\n                legendModel.get('left') === 'right'\n                && legendModel.get('orient') === 'vertical'\n            ) ? 'right' : 'left';\n        }\n\n        this.renderInner(itemAlign, legendModel, ecModel, api);\n\n        // Perform layout.\n        var positionInfo = legendModel.getBoxLayoutParams();\n        var viewportSize = {width: api.getWidth(), height: api.getHeight()};\n        var padding = legendModel.get('padding');\n\n        var maxSize = getLayoutRect(positionInfo, viewportSize, padding);\n\n        var mainRect = this.layoutInner(legendModel, itemAlign, maxSize, isFirstRender);\n\n        // Place mainGroup, based on the calculated `mainRect`.\n        var layoutRect = getLayoutRect(\n            defaults({width: mainRect.width, height: mainRect.height}, positionInfo),\n            viewportSize,\n            padding\n        );\n        this.group.attr('position', [layoutRect.x - mainRect.x, layoutRect.y - mainRect.y]);\n\n        // Render background after group is layout.\n        this.group.add(\n            this._backgroundEl = makeBackground(mainRect, legendModel)\n        );\n    },\n\n    /**\n     * @protected\n     */\n    resetInner: function () {\n        this.getContentGroup().removeAll();\n        this._backgroundEl && this.group.remove(this._backgroundEl);\n    },\n\n    /**\n     * @protected\n     */\n    renderInner: function (itemAlign, legendModel, ecModel, api) {\n        var contentGroup = this.getContentGroup();\n        var legendDrawnMap = createHashMap();\n        var selectMode = legendModel.get('selectedMode');\n\n        var excludeSeriesId = [];\n        ecModel.eachRawSeries(function (seriesModel) {\n            !seriesModel.get('legendHoverLink') && excludeSeriesId.push(seriesModel.id);\n        });\n\n        each$11(legendModel.getData(), function (itemModel, dataIndex) {\n            var name = itemModel.get('name');\n\n            // Use empty string or \\n as a newline string\n            if (!this.newlineDisabled && (name === '' || name === '\\n')) {\n                contentGroup.add(new Group$2({\n                    newline: true\n                }));\n                return;\n            }\n\n            // Representitive series.\n            var seriesModel = ecModel.getSeriesByName(name)[0];\n\n            if (legendDrawnMap.get(name)) {\n                // Have been drawed\n                return;\n            }\n\n            // Series legend\n            if (seriesModel) {\n                var data = seriesModel.getData();\n                var color = data.getVisual('color');\n\n                // If color is a callback function\n                if (typeof color === 'function') {\n                    // Use the first data\n                    color = color(seriesModel.getDataParams(0));\n                }\n\n                // Using rect symbol defaultly\n                var legendSymbolType = data.getVisual('legendSymbol') || 'roundRect';\n                var symbolType = data.getVisual('symbol');\n\n                var itemGroup = this._createItem(\n                    name, dataIndex, itemModel, legendModel,\n                    legendSymbolType, symbolType,\n                    itemAlign, color,\n                    selectMode\n                );\n\n                itemGroup.on('click', curry$3(dispatchSelectAction, name, api))\n                    .on('mouseover', curry$3(dispatchHighlightAction, seriesModel.name, null, api, excludeSeriesId))\n                    .on('mouseout', curry$3(dispatchDownplayAction, seriesModel.name, null, api, excludeSeriesId));\n\n                legendDrawnMap.set(name, true);\n            }\n            else {\n                // Data legend of pie, funnel\n                ecModel.eachRawSeries(function (seriesModel) {\n                    // In case multiple series has same data name\n                    if (legendDrawnMap.get(name)) {\n                        return;\n                    }\n\n                    if (seriesModel.legendDataProvider) {\n                        var data = seriesModel.legendDataProvider();\n                        var idx = data.indexOfName(name);\n                        if (idx < 0) {\n                            return;\n                        }\n\n                        var color = data.getItemVisual(idx, 'color');\n\n                        var legendSymbolType = 'roundRect';\n\n                        var itemGroup = this._createItem(\n                            name, dataIndex, itemModel, legendModel,\n                            legendSymbolType, null,\n                            itemAlign, color,\n                            selectMode\n                        );\n\n                        // FIXME: consider different series has items with the same name.\n                        itemGroup.on('click', curry$3(dispatchSelectAction, name, api))\n                            // Should not specify the series name, consider legend controls\n                            // more than one pie series.\n                            .on('mouseover', curry$3(dispatchHighlightAction, null, name, api, excludeSeriesId))\n                            .on('mouseout', curry$3(dispatchDownplayAction, null, name, api, excludeSeriesId));\n\n                        legendDrawnMap.set(name, true);\n                    }\n\n                }, this);\n            }\n\n            if (__DEV__) {\n                if (!legendDrawnMap.get(name)) {\n                    console.warn(\n                        name + ' series not exists. Legend data should be same with series name or data name.'\n                    );\n                }\n            }\n        }, this);\n    },\n\n    _createItem: function (\n        name, dataIndex, itemModel, legendModel,\n        legendSymbolType, symbolType,\n        itemAlign, color, selectMode\n    ) {\n        var itemWidth = legendModel.get('itemWidth');\n        var itemHeight = legendModel.get('itemHeight');\n        var inactiveColor = legendModel.get('inactiveColor');\n        var symbolKeepAspect = legendModel.get('symbolKeepAspect');\n\n        var isSelected = legendModel.isSelected(name);\n        var itemGroup = new Group$2();\n\n        var textStyleModel = itemModel.getModel('textStyle');\n\n        var itemIcon = itemModel.get('icon');\n\n        var tooltipModel = itemModel.getModel('tooltip');\n        var legendGlobalTooltipModel = tooltipModel.parentModel;\n\n        // Use user given icon first\n        legendSymbolType = itemIcon || legendSymbolType;\n        itemGroup.add(createSymbol(\n            legendSymbolType,\n            0,\n            0,\n            itemWidth,\n            itemHeight,\n            isSelected ? color : inactiveColor,\n            // symbolKeepAspect default true for legend\n            symbolKeepAspect == null ? true : symbolKeepAspect\n        ));\n\n        // Compose symbols\n        // PENDING\n        if (!itemIcon && symbolType\n            // At least show one symbol, can't be all none\n            && ((symbolType !== legendSymbolType) || symbolType === 'none')\n        ) {\n            var size = itemHeight * 0.8;\n            if (symbolType === 'none') {\n                symbolType = 'circle';\n            }\n            // Put symbol in the center\n            itemGroup.add(createSymbol(\n                symbolType,\n                (itemWidth - size) / 2,\n                (itemHeight - size) / 2,\n                size,\n                size,\n                isSelected ? color : inactiveColor,\n                // symbolKeepAspect default true for legend\n                symbolKeepAspect == null ? true : symbolKeepAspect\n            ));\n        }\n\n        var textX = itemAlign === 'left' ? itemWidth + 5 : -5;\n        var textAlign = itemAlign;\n\n        var formatter = legendModel.get('formatter');\n        var content = name;\n        if (typeof formatter === 'string' && formatter) {\n            content = formatter.replace('{name}', name != null ? name : '');\n        }\n        else if (typeof formatter === 'function') {\n            content = formatter(name);\n        }\n\n        itemGroup.add(new Text({\n            style: setTextStyle({}, textStyleModel, {\n                text: content,\n                x: textX,\n                y: itemHeight / 2,\n                textFill: isSelected ? textStyleModel.getTextColor() : inactiveColor,\n                textAlign: textAlign,\n                textVerticalAlign: 'middle'\n            })\n        }));\n\n        // Add a invisible rect to increase the area of mouse hover\n        var hitRect = new Rect({\n            shape: itemGroup.getBoundingRect(),\n            invisible: true,\n            tooltip: tooltipModel.get('show') ? extend({\n                content: name,\n                // Defaul formatter\n                formatter: legendGlobalTooltipModel.get('formatter', true) || function () {\n                    return name;\n                },\n                formatterParams: {\n                    componentType: 'legend',\n                    legendIndex: legendModel.componentIndex,\n                    name: name,\n                    $vars: ['name']\n                }\n            }, tooltipModel.option) : null\n        });\n        itemGroup.add(hitRect);\n\n        itemGroup.eachChild(function (child) {\n            child.silent = true;\n        });\n\n        hitRect.silent = !selectMode;\n\n        this.getContentGroup().add(itemGroup);\n\n        setHoverStyle(itemGroup);\n\n        itemGroup.__legendDataIndex = dataIndex;\n\n        return itemGroup;\n    },\n\n    /**\n     * @protected\n     */\n    layoutInner: function (legendModel, itemAlign, maxSize) {\n        var contentGroup = this.getContentGroup();\n\n        // Place items in contentGroup.\n        box(\n            legendModel.get('orient'),\n            contentGroup,\n            legendModel.get('itemGap'),\n            maxSize.width,\n            maxSize.height\n        );\n\n        var contentRect = contentGroup.getBoundingRect();\n        contentGroup.attr('position', [-contentRect.x, -contentRect.y]);\n\n        return this.group.getBoundingRect();\n    },\n\n    /**\n     * @protected\n     */\n    remove: function () {\n        this.getContentGroup().removeAll();\n        this._isFirstRender = true;\n    }\n\n});\n\nfunction dispatchSelectAction(name, api) {\n    api.dispatchAction({\n        type: 'legendToggleSelect',\n        name: name\n    });\n}\n\nfunction dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId) {\n    // If element hover will move to a hoverLayer.\n    var el = api.getZr().storage.getDisplayList()[0];\n    if (!(el && el.useHoverLayer)) {\n        api.dispatchAction({\n            type: 'highlight',\n            seriesName: seriesName,\n            name: dataName,\n            excludeSeriesId: excludeSeriesId\n        });\n    }\n}\n\nfunction dispatchDownplayAction(seriesName, dataName, api, excludeSeriesId) {\n    // If element hover will move to a hoverLayer.\n    var el = api.getZr().storage.getDisplayList()[0];\n    if (!(el && el.useHoverLayer)) {\n        api.dispatchAction({\n            type: 'downplay',\n            seriesName: seriesName,\n            name: dataName,\n            excludeSeriesId: excludeSeriesId\n        });\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar legendFilter = function (ecModel) {\n\n    var legendModels = ecModel.findComponents({\n        mainType: 'legend'\n    });\n    if (legendModels && legendModels.length) {\n        ecModel.filterSeries(function (series) {\n            // If in any legend component the status is not selected.\n            // Because in legend series is assumed selected when it is not in the legend data.\n            for (var i = 0; i < legendModels.length; i++) {\n                if (!legendModels[i].isSelected(series.name)) {\n                    return false;\n                }\n            }\n            return true;\n        });\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n// Do not contain scrollable legend, for sake of file size.\n\n// Series Filter\nregisterProcessor(legendFilter);\n\nComponentModel.registerSubTypeDefaulter('legend', function () {\n    // Default 'plain' when no type specified.\n    return 'plain';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ScrollableLegendModel = LegendModel.extend({\n\n    type: 'legend.scroll',\n\n    /**\n     * @param {number} scrollDataIndex\n     */\n    setScrollDataIndex: function (scrollDataIndex) {\n        this.option.scrollDataIndex = scrollDataIndex;\n    },\n\n    defaultOption: {\n        scrollDataIndex: 0,\n        pageButtonItemGap: 5,\n        pageButtonGap: null,\n        pageButtonPosition: 'end', // 'start' or 'end'\n        pageFormatter: '{current}/{total}', // If null/undefined, do not show page.\n        pageIcons: {\n            horizontal: ['M0,0L12,-10L12,10z', 'M0,0L-12,-10L-12,10z'],\n            vertical: ['M0,0L20,0L10,-20z', 'M0,0L20,0L10,20z']\n        },\n        pageIconColor: '#2f4554',\n        pageIconInactiveColor: '#aaa',\n        pageIconSize: 15, // Can be [10, 3], which represents [width, height]\n        pageTextStyle: {\n            color: '#333'\n        },\n\n        animationDurationUpdate: 800\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel, extraOpt) {\n        var inputPositionParams = getLayoutParams(option);\n\n        ScrollableLegendModel.superCall(this, 'init', option, parentModel, ecModel, extraOpt);\n\n        mergeAndNormalizeLayoutParams(this, option, inputPositionParams);\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (option, extraOpt) {\n        ScrollableLegendModel.superCall(this, 'mergeOption', option, extraOpt);\n\n        mergeAndNormalizeLayoutParams(this, this.option, option);\n    },\n\n    getOrient: function () {\n        return this.get('orient') === 'vertical'\n            ? {index: 1, name: 'vertical'}\n            : {index: 0, name: 'horizontal'};\n    }\n\n});\n\n// Do not `ignoreSize` to enable setting {left: 10, right: 10}.\nfunction mergeAndNormalizeLayoutParams(legendModel, target, raw) {\n    var orient = legendModel.getOrient();\n    var ignoreSize = [1, 1];\n    ignoreSize[orient.index] = 0;\n    mergeLayoutParam(target, raw, {\n        type: 'box', ignoreSize: ignoreSize\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Separate legend and scrollable legend to reduce package size.\n */\n\nvar Group$3 = Group;\n\nvar WH = ['width', 'height'];\nvar XY = ['x', 'y'];\n\nvar ScrollableLegendView = LegendView.extend({\n\n    type: 'legend.scroll',\n\n    newlineDisabled: true,\n\n    init: function () {\n\n        ScrollableLegendView.superCall(this, 'init');\n\n        /**\n         * @private\n         * @type {number} For `scroll`.\n         */\n        this._currentIndex = 0;\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._containerGroup = new Group$3());\n        this._containerGroup.add(this.getContentGroup());\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._controllerGroup = new Group$3());\n\n        /**\n         *\n         * @private\n         */\n        this._showController;\n    },\n\n    /**\n     * @override\n     */\n    resetInner: function () {\n        ScrollableLegendView.superCall(this, 'resetInner');\n\n        this._controllerGroup.removeAll();\n        this._containerGroup.removeClipPath();\n        this._containerGroup.__rectSize = null;\n    },\n\n    /**\n     * @override\n     */\n    renderInner: function (itemAlign, legendModel, ecModel, api) {\n        var me = this;\n\n        // Render content items.\n        ScrollableLegendView.superCall(this, 'renderInner', itemAlign, legendModel, ecModel, api);\n\n        var controllerGroup = this._controllerGroup;\n\n        // FIXME: support be 'auto' adapt to size number text length,\n        // e.g., '3/12345' should not overlap with the control arrow button.\n        var pageIconSize = legendModel.get('pageIconSize', true);\n        if (!isArray(pageIconSize)) {\n            pageIconSize = [pageIconSize, pageIconSize];\n        }\n\n        createPageButton('pagePrev', 0);\n\n        var pageTextStyleModel = legendModel.getModel('pageTextStyle');\n        controllerGroup.add(new Text({\n            name: 'pageText',\n            style: {\n                textFill: pageTextStyleModel.getTextColor(),\n                font: pageTextStyleModel.getFont(),\n                textVerticalAlign: 'middle',\n                textAlign: 'center'\n            },\n            silent: true\n        }));\n\n        createPageButton('pageNext', 1);\n\n        function createPageButton(name, iconIdx) {\n            var pageDataIndexName = name + 'DataIndex';\n            var icon = createIcon(\n                legendModel.get('pageIcons', true)[legendModel.getOrient().name][iconIdx],\n                {\n                    // Buttons will be created in each render, so we do not need\n                    // to worry about avoiding using legendModel kept in scope.\n                    onclick: bind(\n                        me._pageGo, me, pageDataIndexName, legendModel, api\n                    )\n                },\n                {\n                    x: -pageIconSize[0] / 2,\n                    y: -pageIconSize[1] / 2,\n                    width: pageIconSize[0],\n                    height: pageIconSize[1]\n                }\n            );\n            icon.name = name;\n            controllerGroup.add(icon);\n        }\n    },\n\n    /**\n     * @override\n     */\n    layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender) {\n        var contentGroup = this.getContentGroup();\n        var containerGroup = this._containerGroup;\n        var controllerGroup = this._controllerGroup;\n\n        var orientIdx = legendModel.getOrient().index;\n        var wh = WH[orientIdx];\n        var hw = WH[1 - orientIdx];\n        var yx = XY[1 - orientIdx];\n\n        // Place items in contentGroup.\n        box(\n            legendModel.get('orient'),\n            contentGroup,\n            legendModel.get('itemGap'),\n            !orientIdx ? null : maxSize.width,\n            orientIdx ? null : maxSize.height\n        );\n\n        box(\n            // Buttons in controller are layout always horizontally.\n            'horizontal',\n            controllerGroup,\n            legendModel.get('pageButtonItemGap', true)\n        );\n\n        var contentRect = contentGroup.getBoundingRect();\n        var controllerRect = controllerGroup.getBoundingRect();\n        var showController = this._showController = contentRect[wh] > maxSize[wh];\n\n        var contentPos = [-contentRect.x, -contentRect.y];\n        // Remain contentPos when scroll animation perfroming.\n        // If first rendering, `contentGroup.position` is [0, 0], which\n        // does not make sense and may cause unexepcted animation if adopted.\n        if (!isFirstRender) {\n            contentPos[orientIdx] = contentGroup.position[orientIdx];\n        }\n\n        // Layout container group based on 0.\n        var containerPos = [0, 0];\n        var controllerPos = [-controllerRect.x, -controllerRect.y];\n        var pageButtonGap = retrieve2(\n            legendModel.get('pageButtonGap', true), legendModel.get('itemGap', true)\n        );\n\n        // Place containerGroup and controllerGroup and contentGroup.\n        if (showController) {\n            var pageButtonPosition = legendModel.get('pageButtonPosition', true);\n            // controller is on the right / bottom.\n            if (pageButtonPosition === 'end') {\n                controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh];\n            }\n            // controller is on the left / top.\n            else {\n                containerPos[orientIdx] += controllerRect[wh] + pageButtonGap;\n            }\n        }\n\n        // Always align controller to content as 'middle'.\n        controllerPos[1 - orientIdx] += contentRect[hw] / 2 - controllerRect[hw] / 2;\n\n        contentGroup.attr('position', contentPos);\n        containerGroup.attr('position', containerPos);\n        controllerGroup.attr('position', controllerPos);\n\n        // Calculate `mainRect` and set `clipPath`.\n        // mainRect should not be calculated by `this.group.getBoundingRect()`\n        // for sake of the overflow.\n        var mainRect = this.group.getBoundingRect();\n        var mainRect = {x: 0, y: 0};\n        // Consider content may be overflow (should be clipped).\n        mainRect[wh] = showController ? maxSize[wh] : contentRect[wh];\n        mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw]);\n        // `containerRect[yx] + containerPos[1 - orientIdx]` is 0.\n        mainRect[yx] = Math.min(0, controllerRect[yx] + controllerPos[1 - orientIdx]);\n\n        containerGroup.__rectSize = maxSize[wh];\n        if (showController) {\n            var clipShape = {x: 0, y: 0};\n            clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap, 0);\n            clipShape[hw] = mainRect[hw];\n            containerGroup.setClipPath(new Rect({shape: clipShape}));\n            // Consider content may be larger than container, container rect\n            // can not be obtained from `containerGroup.getBoundingRect()`.\n            containerGroup.__rectSize = clipShape[wh];\n        }\n        else {\n            // Do not remove or ignore controller. Keep them set as place holders.\n            controllerGroup.eachChild(function (child) {\n                child.attr({invisible: true, silent: true});\n            });\n        }\n\n        // Content translate animation.\n        var pageInfo = this._getPageInfo(legendModel);\n        pageInfo.pageIndex != null && updateProps(\n            contentGroup,\n            {position: pageInfo.contentPosition},\n            // When switch from \"show controller\" to \"not show controller\", view should be\n            // updated immediately without animation, otherwise causes weird efffect.\n            showController ? legendModel : false\n        );\n\n        this._updatePageInfoView(legendModel, pageInfo);\n\n        return mainRect;\n    },\n\n    _pageGo: function (to, legendModel, api) {\n        var scrollDataIndex = this._getPageInfo(legendModel)[to];\n\n        scrollDataIndex != null && api.dispatchAction({\n            type: 'legendScroll',\n            scrollDataIndex: scrollDataIndex,\n            legendId: legendModel.id\n        });\n    },\n\n    _updatePageInfoView: function (legendModel, pageInfo) {\n        var controllerGroup = this._controllerGroup;\n\n        each$1(['pagePrev', 'pageNext'], function (name) {\n            var canJump = pageInfo[name + 'DataIndex'] != null;\n            var icon = controllerGroup.childOfName(name);\n            if (icon) {\n                icon.setStyle(\n                    'fill',\n                    canJump\n                        ? legendModel.get('pageIconColor', true)\n                        : legendModel.get('pageIconInactiveColor', true)\n                );\n                icon.cursor = canJump ? 'pointer' : 'default';\n            }\n        });\n\n        var pageText = controllerGroup.childOfName('pageText');\n        var pageFormatter = legendModel.get('pageFormatter');\n        var pageIndex = pageInfo.pageIndex;\n        var current = pageIndex != null ? pageIndex + 1 : 0;\n        var total = pageInfo.pageCount;\n\n        pageText && pageFormatter && pageText.setStyle(\n            'text',\n            isString(pageFormatter)\n                ? pageFormatter.replace('{current}', current).replace('{total}', total)\n                : pageFormatter({current: current, total: total})\n        );\n    },\n\n    /**\n     * @param {module:echarts/model/Model} legendModel\n     * @return {Object} {\n     *  contentPosition: Array.<number>, null when data item not found.\n     *  pageIndex: number, null when data item not found.\n     *  pageCount: number, always be a number, can be 0.\n     *  pagePrevDataIndex: number, null when no next page.\n     *  pageNextDataIndex: number, null when no previous page.\n     * }\n     */\n    _getPageInfo: function (legendModel) {\n        var scrollDataIndex = legendModel.get('scrollDataIndex', true);\n        var contentGroup = this.getContentGroup();\n        var containerRectSize = this._containerGroup.__rectSize;\n        var orientIdx = legendModel.getOrient().index;\n        var wh = WH[orientIdx];\n        var xy = XY[orientIdx];\n        var targetItemIndex = this._findTargetItemIndex(scrollDataIndex);\n        var children = contentGroup.children();\n        var targetItem = children[targetItemIndex];\n        var itemCount = children.length;\n        var pCount = !itemCount ? 0 : 1;\n\n        var result = {\n            contentPosition: contentGroup.position.slice(),\n            pageCount: pCount,\n            pageIndex: pCount - 1,\n            pagePrevDataIndex: null,\n            pageNextDataIndex: null\n        };\n\n        if (!targetItem) {\n            return result;\n        }\n\n        var targetItemInfo = getItemInfo(targetItem);\n        result.contentPosition[orientIdx] = -targetItemInfo.s;\n\n        // Strategy:\n        // (1) Always align based on the left/top most item.\n        // (2) It is user-friendly that the last item shown in the\n        // current window is shown at the begining of next window.\n        // Otherwise if half of the last item is cut by the window,\n        // it will have no chance to display entirely.\n        // (3) Consider that item size probably be different, we\n        // have calculate pageIndex by size rather than item index,\n        // and we can not get page index directly by division.\n        // (4) The window is to narrow to contain more than\n        // one item, we should make sure that the page can be fliped.\n\n        for (var i = targetItemIndex + 1,\n            winStartItemInfo = targetItemInfo,\n            winEndItemInfo = targetItemInfo,\n            currItemInfo = null;\n            i <= itemCount;\n            ++i\n        ) {\n            currItemInfo = getItemInfo(children[i]);\n            if (\n                // Half of the last item is out of the window.\n                (!currItemInfo && winEndItemInfo.e > winStartItemInfo.s + containerRectSize)\n                // If the current item does not intersect with the window, the new page\n                // can be started at the current item or the last item.\n                || (currItemInfo && !intersect(currItemInfo, winStartItemInfo.s))\n            ) {\n                if (winEndItemInfo.i > winStartItemInfo.i) {\n                    winStartItemInfo = winEndItemInfo;\n                }\n                else { // e.g., when page size is smaller than item size.\n                    winStartItemInfo = currItemInfo;\n                }\n                if (winStartItemInfo) {\n                    if (result.pageNextDataIndex == null) {\n                        result.pageNextDataIndex = winStartItemInfo.i;\n                    }\n                    ++result.pageCount;\n                }\n            }\n            winEndItemInfo = currItemInfo;\n        }\n\n        for (var i = targetItemIndex - 1,\n            winStartItemInfo = targetItemInfo,\n            winEndItemInfo = targetItemInfo,\n            currItemInfo = null;\n            i >= -1;\n            --i\n        ) {\n            currItemInfo = getItemInfo(children[i]);\n            if (\n                // If the the end item does not intersect with the window started\n                // from the current item, a page can be settled.\n                (!currItemInfo || !intersect(winEndItemInfo, currItemInfo.s))\n                // e.g., when page size is smaller than item size.\n                && winStartItemInfo.i < winEndItemInfo.i\n            ) {\n                winEndItemInfo = winStartItemInfo;\n                if (result.pagePrevDataIndex == null) {\n                    result.pagePrevDataIndex = winStartItemInfo.i;\n                }\n                ++result.pageCount;\n                ++result.pageIndex;\n            }\n            winStartItemInfo = currItemInfo;\n        }\n\n        return result;\n\n        function getItemInfo(el) {\n            if (el) {\n                var itemRect = el.getBoundingRect();\n                var start = itemRect[xy] + el.position[orientIdx];\n                return {\n                    s: start,\n                    e: start + itemRect[wh],\n                    i: el.__legendDataIndex\n                };\n            }\n        }\n\n        function intersect(itemInfo, winStart) {\n            return itemInfo.e >= winStart && itemInfo.s <= winStart + containerRectSize;\n        }\n    },\n\n    _findTargetItemIndex: function (targetDataIndex) {\n        var index;\n        var contentGroup = this.getContentGroup();\n        if (this._showController) {\n            contentGroup.eachChild(function (child, idx) {\n                if (child.__legendDataIndex === targetDataIndex) {\n                    index = idx;\n                }\n            });\n        }\n        else {\n            index = 0;\n        }\n        return index;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @event legendScroll\n * @type {Object}\n * @property {string} type 'legendScroll'\n * @property {string} scrollDataIndex\n */\nregisterAction(\n    'legendScroll', 'legendscroll',\n    function (payload, ecModel) {\n        var scrollDataIndex = payload.scrollDataIndex;\n\n        scrollDataIndex != null && ecModel.eachComponent(\n            {mainType: 'legend', subType: 'scroll', query: payload},\n            function (legendModel) {\n                legendModel.setScrollDataIndex(scrollDataIndex);\n            }\n        );\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Legend component entry file8\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Model\nextendComponentModel({\n\n    type: 'title',\n\n    layoutMode: {type: 'box', ignoreSize: true},\n\n    defaultOption: {\n        // 一级层叠\n        zlevel: 0,\n        // 二级层叠\n        z: 6,\n        show: true,\n\n        text: '',\n        // 超链接跳转\n        // link: null,\n        // 仅支持self | blank\n        target: 'blank',\n        subtext: '',\n\n        // 超链接跳转\n        // sublink: null,\n        // 仅支持self | blank\n        subtarget: 'blank',\n\n        // 'center' ¦ 'left' ¦ 'right'\n        // ¦ {number}（x坐标，单位px）\n        left: 0,\n        // 'top' ¦ 'bottom' ¦ 'center'\n        // ¦ {number}（y坐标，单位px）\n        top: 0,\n\n        // 水平对齐\n        // 'auto' | 'left' | 'right' | 'center'\n        // 默认根据 left 的位置判断是左对齐还是右对齐\n        // textAlign: null\n        //\n        // 垂直对齐\n        // 'auto' | 'top' | 'bottom' | 'middle'\n        // 默认根据 top 位置判断是上对齐还是下对齐\n        // textBaseline: null\n\n        backgroundColor: 'rgba(0,0,0,0)',\n\n        // 标题边框颜色\n        borderColor: '#ccc',\n\n        // 标题边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n\n        // 标题内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n\n        // 主副标题纵向间隔，单位px，默认为10，\n        itemGap: 10,\n        textStyle: {\n            fontSize: 18,\n            fontWeight: 'bolder',\n            color: '#333'\n        },\n        subtextStyle: {\n            color: '#aaa'\n        }\n    }\n});\n\n// View\nextendComponentView({\n\n    type: 'title',\n\n    render: function (titleModel, ecModel, api) {\n        this.group.removeAll();\n\n        if (!titleModel.get('show')) {\n            return;\n        }\n\n        var group = this.group;\n\n        var textStyleModel = titleModel.getModel('textStyle');\n        var subtextStyleModel = titleModel.getModel('subtextStyle');\n\n        var textAlign = titleModel.get('textAlign');\n        var textBaseline = titleModel.get('textBaseline');\n\n        var textEl = new Text({\n            style: setTextStyle({}, textStyleModel, {\n                text: titleModel.get('text'),\n                textFill: textStyleModel.getTextColor()\n            }, {disableBox: true}),\n            z2: 10\n        });\n\n        var textRect = textEl.getBoundingRect();\n\n        var subText = titleModel.get('subtext');\n        var subTextEl = new Text({\n            style: setTextStyle({}, subtextStyleModel, {\n                text: subText,\n                textFill: subtextStyleModel.getTextColor(),\n                y: textRect.height + titleModel.get('itemGap'),\n                textVerticalAlign: 'top'\n            }, {disableBox: true}),\n            z2: 10\n        });\n\n        var link = titleModel.get('link');\n        var sublink = titleModel.get('sublink');\n        var triggerEvent = titleModel.get('triggerEvent', true);\n\n        textEl.silent = !link && !triggerEvent;\n        subTextEl.silent = !sublink && !triggerEvent;\n\n        if (link) {\n            textEl.on('click', function () {\n                window.open(link, '_' + titleModel.get('target'));\n            });\n        }\n        if (sublink) {\n            subTextEl.on('click', function () {\n                window.open(sublink, '_' + titleModel.get('subtarget'));\n            });\n        }\n\n        textEl.eventData = subTextEl.eventData = triggerEvent\n            ? {\n                componentType: 'title',\n                componentIndex: titleModel.componentIndex\n            }\n            : null;\n\n        group.add(textEl);\n        subText && group.add(subTextEl);\n        // If no subText, but add subTextEl, there will be an empty line.\n\n        var groupRect = group.getBoundingRect();\n        var layoutOption = titleModel.getBoxLayoutParams();\n        layoutOption.width = groupRect.width;\n        layoutOption.height = groupRect.height;\n        var layoutRect = getLayoutRect(\n            layoutOption, {\n                width: api.getWidth(),\n                height: api.getHeight()\n            }, titleModel.get('padding')\n        );\n        // Adjust text align based on position\n        if (!textAlign) {\n            // Align left if title is on the left. center and right is same\n            textAlign = titleModel.get('left') || titleModel.get('right');\n            if (textAlign === 'middle') {\n                textAlign = 'center';\n            }\n            // Adjust layout by text align\n            if (textAlign === 'right') {\n                layoutRect.x += layoutRect.width;\n            }\n            else if (textAlign === 'center') {\n                layoutRect.x += layoutRect.width / 2;\n            }\n        }\n        if (!textBaseline) {\n            textBaseline = titleModel.get('top') || titleModel.get('bottom');\n            if (textBaseline === 'center') {\n                textBaseline = 'middle';\n            }\n            if (textBaseline === 'bottom') {\n                layoutRect.y += layoutRect.height;\n            }\n            else if (textBaseline === 'middle') {\n                layoutRect.y += layoutRect.height / 2;\n            }\n\n            textBaseline = textBaseline || 'top';\n        }\n\n        group.attr('position', [layoutRect.x, layoutRect.y]);\n        var alignStyle = {\n            textAlign: textAlign,\n            textVerticalAlign: textBaseline\n        };\n        textEl.setStyle(alignStyle);\n        subTextEl.setStyle(alignStyle);\n\n        // Render background\n        // Get groupRect again because textAlign has been changed\n        groupRect = group.getBoundingRect();\n        var padding = layoutRect.margin;\n        var style = titleModel.getItemStyle(['color', 'opacity']);\n        style.fill = titleModel.get('backgroundColor');\n        var rect = new Rect({\n            shape: {\n                x: groupRect.x - padding[3],\n                y: groupRect.y - padding[0],\n                width: groupRect.width + padding[1] + padding[3],\n                height: groupRect.height + padding[0] + padding[2],\n                r: titleModel.get('borderRadius')\n            },\n            style: style,\n            silent: true\n        });\n        subPixelOptimizeRect(rect);\n\n        group.add(rect);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar addCommas$1 = addCommas;\nvar encodeHTML$1 = encodeHTML;\n\nfunction fillLabel(opt) {\n    defaultEmphasis(opt, 'label', ['show']);\n}\nvar MarkerModel = extendComponentModel({\n\n    type: 'marker',\n\n    dependencies: ['series', 'grid', 'polar', 'geo'],\n\n    /**\n     * @overrite\n     */\n    init: function (option, parentModel, ecModel, extraOpt) {\n\n        if (__DEV__) {\n            if (this.type === 'marker') {\n                throw new Error('Marker component is abstract component. Use markLine, markPoint, markArea instead.');\n            }\n        }\n        this.mergeDefaultAndTheme(option, ecModel);\n        this.mergeOption(option, ecModel, extraOpt.createdBySelf, true);\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isAnimationEnabled: function () {\n        if (env$1.node) {\n            return false;\n        }\n\n        var hostSeries = this.__hostSeries;\n        return this.getShallow('animation') && hostSeries && hostSeries.isAnimationEnabled();\n    },\n\n    mergeOption: function (newOpt, ecModel, createdBySelf, isInit) {\n        var MarkerModel = this.constructor;\n        var modelPropName = this.mainType + 'Model';\n        if (!createdBySelf) {\n            ecModel.eachSeries(function (seriesModel) {\n\n                var markerOpt = seriesModel.get(this.mainType, true);\n\n                var markerModel = seriesModel[modelPropName];\n                if (!markerOpt || !markerOpt.data) {\n                    seriesModel[modelPropName] = null;\n                    return;\n                }\n                if (!markerModel) {\n                    if (isInit) {\n                        // Default label emphasis `position` and `show`\n                        fillLabel(markerOpt);\n                    }\n                    each$1(markerOpt.data, function (item) {\n                        // FIXME Overwrite fillLabel method ?\n                        if (item instanceof Array) {\n                            fillLabel(item[0]);\n                            fillLabel(item[1]);\n                        }\n                        else {\n                            fillLabel(item);\n                        }\n                    });\n\n                    markerModel = new MarkerModel(\n                        markerOpt, this, ecModel\n                    );\n\n                    extend(markerModel, {\n                        mainType: this.mainType,\n                        // Use the same series index and name\n                        seriesIndex: seriesModel.seriesIndex,\n                        name: seriesModel.name,\n                        createdBySelf: true\n                    });\n\n                    markerModel.__hostSeries = seriesModel;\n                }\n                else {\n                    markerModel.mergeOption(markerOpt, ecModel, true);\n                }\n                seriesModel[modelPropName] = markerModel;\n            }, this);\n        }\n    },\n\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var value = this.getRawValue(dataIndex);\n        var formattedValue = isArray(value)\n            ? map(value, addCommas$1).join(', ') : addCommas$1(value);\n        var name = data.getName(dataIndex);\n        var html = encodeHTML$1(this.name);\n        if (value != null || name) {\n            html += '<br />';\n        }\n        if (name) {\n            html += encodeHTML$1(name);\n            if (value != null) {\n                html += ' : ';\n            }\n        }\n        if (value != null) {\n            html += encodeHTML$1(formattedValue);\n        }\n        return html;\n    },\n\n    getData: function () {\n        return this._data;\n    },\n\n    setData: function (data) {\n        this._data = data;\n    }\n});\n\nmixin(MarkerModel, dataFormatMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markPoint',\n\n    defaultOption: {\n        zlevel: 0,\n        z: 5,\n        symbol: 'pin',\n        symbolSize: 50,\n        //symbolRotate: 0,\n        //symbolOffset: [0, 0]\n        tooltip: {\n            trigger: 'item'\n        },\n        label: {\n            show: true,\n            position: 'inside'\n        },\n        itemStyle: {\n            borderWidth: 2\n        },\n        emphasis: {\n            label: {\n                show: true\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar indexOf$1 = indexOf;\n\nfunction hasXOrY(item) {\n    return !(isNaN(parseFloat(item.x)) && isNaN(parseFloat(item.y)));\n}\n\nfunction hasXAndY(item) {\n    return !isNaN(parseFloat(item.x)) && !isNaN(parseFloat(item.y));\n}\n\n// Make it simple, do not visit all stacked value to count precision.\n// function getPrecision(data, valueAxisDim, dataIndex) {\n//     var precision = -1;\n//     var stackedDim = data.mapDimension(valueAxisDim);\n//     do {\n//         precision = Math.max(\n//             numberUtil.getPrecision(data.get(stackedDim, dataIndex)),\n//             precision\n//         );\n//         var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');\n//         if (stackedOnSeries) {\n//             var byValue = data.get(data.getCalculationInfo('stackedByDimension'), dataIndex);\n//             data = stackedOnSeries.getData();\n//             dataIndex = data.indexOf(data.getCalculationInfo('stackedByDimension'), byValue);\n//             stackedDim = data.getCalculationInfo('stackedDimension');\n//         }\n//         else {\n//             data = null;\n//         }\n//     } while (data);\n\n//     return precision;\n// }\n\nfunction markerTypeCalculatorWithExtent(\n    mlType, data, otherDataDim, targetDataDim, otherCoordIndex, targetCoordIndex\n) {\n    var coordArr = [];\n\n    var stacked = isDimensionStacked(data, targetDataDim /*, otherDataDim*/);\n    var calcDataDim = stacked\n        ? data.getCalculationInfo('stackResultDimension')\n        : targetDataDim;\n\n    var value = numCalculate(data, calcDataDim, mlType);\n\n    var dataIndex = data.indicesOfNearest(calcDataDim, value)[0];\n    coordArr[otherCoordIndex] = data.get(otherDataDim, dataIndex);\n    coordArr[targetCoordIndex] = data.get(targetDataDim, dataIndex);\n\n    // Make it simple, do not visit all stacked value to count precision.\n    var precision = getPrecision(data.get(targetDataDim, dataIndex));\n    precision = Math.min(precision, 20);\n    if (precision >= 0) {\n        coordArr[targetCoordIndex] = +coordArr[targetCoordIndex].toFixed(precision);\n    }\n\n    return coordArr;\n}\n\nvar curry$4 = curry;\n// TODO Specified percent\nvar markerTypeCalculator = {\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    min: curry$4(markerTypeCalculatorWithExtent, 'min'),\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    max: curry$4(markerTypeCalculatorWithExtent, 'max'),\n\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    average: curry$4(markerTypeCalculatorWithExtent, 'average')\n};\n\n/**\n * Transform markPoint data item to format used in List by do the following\n * 1. Calculate statistic like `max`, `min`, `average`\n * 2. Convert `item.xAxis`, `item.yAxis` to `item.coord` array\n * @param  {module:echarts/model/Series} seriesModel\n * @param  {module:echarts/coord/*} [coordSys]\n * @param  {Object} item\n * @return {Object}\n */\nfunction dataTransform(seriesModel, item) {\n    var data = seriesModel.getData();\n    var coordSys = seriesModel.coordinateSystem;\n\n    // 1. If not specify the position with pixel directly\n    // 2. If `coord` is not a data array. Which uses `xAxis`,\n    // `yAxis` to specify the coord on each dimension\n\n    // parseFloat first because item.x and item.y can be percent string like '20%'\n    if (item && !hasXAndY(item) && !isArray(item.coord) && coordSys) {\n        var dims = coordSys.dimensions;\n        var axisInfo = getAxisInfo$1(item, data, coordSys, seriesModel);\n\n        // Clone the option\n        // Transform the properties xAxis, yAxis, radiusAxis, angleAxis, geoCoord to value\n        item = clone(item);\n\n        if (item.type\n            && markerTypeCalculator[item.type]\n            && axisInfo.baseAxis && axisInfo.valueAxis\n        ) {\n            var otherCoordIndex = indexOf$1(dims, axisInfo.baseAxis.dim);\n            var targetCoordIndex = indexOf$1(dims, axisInfo.valueAxis.dim);\n\n            item.coord = markerTypeCalculator[item.type](\n                data, axisInfo.baseDataDim, axisInfo.valueDataDim,\n                otherCoordIndex, targetCoordIndex\n            );\n            // Force to use the value of calculated value.\n            item.value = item.coord[targetCoordIndex];\n        }\n        else {\n            // FIXME Only has one of xAxis and yAxis.\n            var coord = [\n                item.xAxis != null ? item.xAxis : item.radiusAxis,\n                item.yAxis != null ? item.yAxis : item.angleAxis\n            ];\n            // Each coord support max, min, average\n            for (var i = 0; i < 2; i++) {\n                if (markerTypeCalculator[coord[i]]) {\n                    coord[i] = numCalculate(data, data.mapDimension(dims[i]), coord[i]);\n                }\n            }\n            item.coord = coord;\n        }\n    }\n    return item;\n}\n\nfunction getAxisInfo$1(item, data, coordSys, seriesModel) {\n    var ret = {};\n\n    if (item.valueIndex != null || item.valueDim != null) {\n        ret.valueDataDim = item.valueIndex != null\n            ? data.getDimension(item.valueIndex) : item.valueDim;\n        ret.valueAxis = coordSys.getAxis(dataDimToCoordDim(seriesModel, ret.valueDataDim));\n        ret.baseAxis = coordSys.getOtherAxis(ret.valueAxis);\n        ret.baseDataDim = data.mapDimension(ret.baseAxis.dim);\n    }\n    else {\n        ret.baseAxis = seriesModel.getBaseAxis();\n        ret.valueAxis = coordSys.getOtherAxis(ret.baseAxis);\n        ret.baseDataDim = data.mapDimension(ret.baseAxis.dim);\n        ret.valueDataDim = data.mapDimension(ret.valueAxis.dim);\n    }\n\n    return ret;\n}\n\nfunction dataDimToCoordDim(seriesModel, dataDim) {\n    var data = seriesModel.getData();\n    var dimensions = data.dimensions;\n    dataDim = data.getDimension(dataDim);\n    for (var i = 0; i < dimensions.length; i++) {\n        var dimItem = data.getDimensionInfo(dimensions[i]);\n        if (dimItem.name === dataDim) {\n            return dimItem.coordDim;\n        }\n    }\n}\n\n/**\n * Filter data which is out of coordinateSystem range\n * [dataFilter description]\n * @param  {module:echarts/coord/*} [coordSys]\n * @param  {Object} item\n * @return {boolean}\n */\nfunction dataFilter$1(coordSys, item) {\n    // Alwalys return true if there is no coordSys\n    return (coordSys && coordSys.containData && item.coord && !hasXOrY(item))\n        ? coordSys.containData(item.coord) : true;\n}\n\nfunction dimValueGetter(item, dimName, dataIndex, dimIndex) {\n    // x, y, radius, angle\n    if (dimIndex < 2) {\n        return item.coord && item.coord[dimIndex];\n    }\n    return item.value;\n}\n\nfunction numCalculate(data, valueDataDim, type) {\n    if (type === 'average') {\n        var sum = 0;\n        var count = 0;\n        data.each(valueDataDim, function (val, idx) {\n            if (!isNaN(val)) {\n                sum += val;\n                count++;\n            }\n        });\n        return sum / count;\n    }\n    else if (type === 'median') {\n        return data.getMedian(valueDataDim);\n    }\n    else {\n        // max & min\n        return data.getDataExtent(valueDataDim, true)[type === 'max' ? 1 : 0];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar MarkerView = extendComponentView({\n\n    type: 'marker',\n\n    init: function () {\n        /**\n         * Markline grouped by series\n         * @private\n         * @type {module:zrender/core/util.HashMap}\n         */\n        this.markerGroupMap = createHashMap();\n    },\n\n    render: function (markerModel, ecModel, api) {\n        var markerGroupMap = this.markerGroupMap;\n        markerGroupMap.each(function (item) {\n            item.__keep = false;\n        });\n\n        var markerModelKey = this.type + 'Model';\n        ecModel.eachSeries(function (seriesModel) {\n            var markerModel = seriesModel[markerModelKey];\n            markerModel && this.renderSeries(seriesModel, markerModel, ecModel, api);\n        }, this);\n\n        markerGroupMap.each(function (item) {\n            !item.__keep && this.group.remove(item.group);\n        }, this);\n    },\n\n    renderSeries: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction updateMarkerLayout(mpData, seriesModel, api) {\n    var coordSys = seriesModel.coordinateSystem;\n    mpData.each(function (idx) {\n        var itemModel = mpData.getItemModel(idx);\n        var point;\n        var xPx = parsePercent$1(itemModel.get('x'), api.getWidth());\n        var yPx = parsePercent$1(itemModel.get('y'), api.getHeight());\n        if (!isNaN(xPx) && !isNaN(yPx)) {\n            point = [xPx, yPx];\n        }\n        // Chart like bar may have there own marker positioning logic\n        else if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                mpData.getValues(mpData.dimensions, idx)\n            );\n        }\n        else if (coordSys) {\n            var x = mpData.get(coordSys.dimensions[0], idx);\n            var y = mpData.get(coordSys.dimensions[1], idx);\n            point = coordSys.dataToPoint([x, y]);\n\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n\n        mpData.setItemLayout(idx, point);\n    });\n}\n\nMarkerView.extend({\n\n    type: 'markPoint',\n\n    // updateLayout: function (markPointModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var mpModel = seriesModel.markPointModel;\n    //         if (mpModel) {\n    //             updateMarkerLayout(mpModel.getData(), seriesModel, api);\n    //             this.markerGroupMap.get(seriesModel.id).updateLayout(mpModel);\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markPointModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var mpModel = seriesModel.markPointModel;\n            if (mpModel) {\n                updateMarkerLayout(mpModel.getData(), seriesModel, api);\n                this.markerGroupMap.get(seriesModel.id).updateLayout(mpModel);\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, mpModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var symbolDrawMap = this.markerGroupMap;\n        var symbolDraw = symbolDrawMap.get(seriesId)\n            || symbolDrawMap.set(seriesId, new SymbolDraw());\n\n        var mpData = createList$1(coordSys, seriesModel, mpModel);\n\n        // FIXME\n        mpModel.setData(mpData);\n\n        updateMarkerLayout(mpModel.getData(), seriesModel, api);\n\n        mpData.each(function (idx) {\n            var itemModel = mpData.getItemModel(idx);\n            var symbolSize = itemModel.getShallow('symbolSize');\n            if (typeof symbolSize === 'function') {\n                // FIXME 这里不兼容 ECharts 2.x，2.x 貌似参数是整个数据？\n                symbolSize = symbolSize(\n                    mpModel.getRawValue(idx), mpModel.getDataParams(idx)\n                );\n            }\n            mpData.setItemVisual(idx, {\n                symbolSize: symbolSize,\n                color: itemModel.get('itemStyle.color')\n                    || seriesData.getVisual('color'),\n                symbol: itemModel.getShallow('symbol')\n            });\n        });\n\n        // TODO Text are wrong\n        symbolDraw.updateData(mpData);\n        this.group.add(symbolDraw.group);\n\n        // Set host model for tooltip\n        // FIXME\n        mpData.eachItemGraphicEl(function (el) {\n            el.traverse(function (child) {\n                child.dataModel = mpModel;\n            });\n        });\n\n        symbolDraw.__keep = true;\n\n        symbolDraw.group.silent = mpModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} [coordSys]\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$1(coordSys, seriesModel, mpModel) {\n    var coordDimsInfos;\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var info = seriesModel.getData().getDimensionInfo(\n                seriesModel.getData().mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n    }\n\n    var mpData = new List(coordDimsInfos, mpModel);\n    var dataOpt = map(mpModel.get('data'), curry(\n            dataTransform, seriesModel\n        ));\n    if (coordSys) {\n        dataOpt = filter(\n            dataOpt, curry(dataFilter$1, coordSys)\n        );\n    }\n\n    mpData.initData(dataOpt, null,\n        coordSys ? dimValueGetter : function (item) {\n            return item.value;\n        }\n    );\n\n    return mpData;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// HINT Markpoint can't be used too much\nregisterPreprocessor(function (opt) {\n    // Make sure markPoint component is enabled\n    opt.markPoint = opt.markPoint || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markLine',\n\n    defaultOption: {\n        zlevel: 0,\n        z: 5,\n\n        symbol: ['circle', 'arrow'],\n        symbolSize: [8, 16],\n\n        //symbolRotate: 0,\n\n        precision: 2,\n        tooltip: {\n            trigger: 'item'\n        },\n        label: {\n            show: true,\n            position: 'end'\n        },\n        lineStyle: {\n            type: 'dashed'\n        },\n        emphasis: {\n            label: {\n                show: true\n            },\n            lineStyle: {\n                width: 3\n            }\n        },\n        animationEasing: 'linear'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Line path for bezier and straight line draw\n */\n\nvar straightLineProto = Line.prototype;\nvar bezierCurveProto = BezierCurve.prototype;\n\nfunction isLine(shape) {\n    return isNaN(+shape.cpx1) || isNaN(+shape.cpy1);\n}\n\nvar LinePath = extendShape({\n\n    type: 'ec-line',\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    shape: {\n        x1: 0,\n        y1: 0,\n        x2: 0,\n        y2: 0,\n        percent: 1,\n        cpx1: null,\n        cpy1: null\n    },\n\n    buildPath: function (ctx, shape) {\n        (isLine(shape) ? straightLineProto : bezierCurveProto).buildPath(ctx, shape);\n    },\n\n    pointAt: function (t) {\n        return isLine(this.shape)\n            ? straightLineProto.pointAt.call(this, t)\n            : bezierCurveProto.pointAt.call(this, t);\n    },\n\n    tangentAt: function (t) {\n        var shape = this.shape;\n        var p = isLine(shape)\n            ? [shape.x2 - shape.x1, shape.y2 - shape.y1]\n            : bezierCurveProto.tangentAt.call(this, t);\n        return normalize(p, p);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Line\n */\n\nvar SYMBOL_CATEGORIES = ['fromSymbol', 'toSymbol'];\n\nfunction makeSymbolTypeKey(symbolCategory) {\n    return '_' + symbolCategory + 'Type';\n}\n/**\n * @inner\n */\nfunction createSymbol$1(name, lineData, idx) {\n    var color = lineData.getItemVisual(idx, 'color');\n    var symbolType = lineData.getItemVisual(idx, name);\n    var symbolSize = lineData.getItemVisual(idx, name + 'Size');\n\n    if (!symbolType || symbolType === 'none') {\n        return;\n    }\n\n    if (!isArray(symbolSize)) {\n        symbolSize = [symbolSize, symbolSize];\n    }\n    var symbolPath = createSymbol(\n        symbolType, -symbolSize[0] / 2, -symbolSize[1] / 2,\n        symbolSize[0], symbolSize[1], color\n    );\n\n    symbolPath.name = name;\n\n    return symbolPath;\n}\n\nfunction createLine(points) {\n    var line = new LinePath({\n        name: 'line'\n    });\n    setLinePoints(line.shape, points);\n    return line;\n}\n\nfunction setLinePoints(targetShape, points) {\n    var p1 = points[0];\n    var p2 = points[1];\n    var cp1 = points[2];\n    targetShape.x1 = p1[0];\n    targetShape.y1 = p1[1];\n    targetShape.x2 = p2[0];\n    targetShape.y2 = p2[1];\n    targetShape.percent = 1;\n\n    if (cp1) {\n        targetShape.cpx1 = cp1[0];\n        targetShape.cpy1 = cp1[1];\n    }\n    else {\n        targetShape.cpx1 = NaN;\n        targetShape.cpy1 = NaN;\n    }\n}\n\nfunction updateSymbolAndLabelBeforeLineUpdate() {\n    var lineGroup = this;\n    var symbolFrom = lineGroup.childOfName('fromSymbol');\n    var symbolTo = lineGroup.childOfName('toSymbol');\n    var label = lineGroup.childOfName('label');\n    // Quick reject\n    if (!symbolFrom && !symbolTo && label.ignore) {\n        return;\n    }\n\n    var invScale = 1;\n    var parentNode = this.parent;\n    while (parentNode) {\n        if (parentNode.scale) {\n            invScale /= parentNode.scale[0];\n        }\n        parentNode = parentNode.parent;\n    }\n\n    var line = lineGroup.childOfName('line');\n    // If line not changed\n    // FIXME Parent scale changed\n    if (!this.__dirty && !line.__dirty) {\n        return;\n    }\n\n    var percent = line.shape.percent;\n    var fromPos = line.pointAt(0);\n    var toPos = line.pointAt(percent);\n\n    var d = sub([], toPos, fromPos);\n    normalize(d, d);\n\n    if (symbolFrom) {\n        symbolFrom.attr('position', fromPos);\n        var tangent = line.tangentAt(0);\n        symbolFrom.attr('rotation', Math.PI / 2 - Math.atan2(\n            tangent[1], tangent[0]\n        ));\n        symbolFrom.attr('scale', [invScale * percent, invScale * percent]);\n    }\n    if (symbolTo) {\n        symbolTo.attr('position', toPos);\n        var tangent = line.tangentAt(1);\n        symbolTo.attr('rotation', -Math.PI / 2 - Math.atan2(\n            tangent[1], tangent[0]\n        ));\n        symbolTo.attr('scale', [invScale * percent, invScale * percent]);\n    }\n\n    if (!label.ignore) {\n        label.attr('position', toPos);\n\n        var textPosition;\n        var textAlign;\n        var textVerticalAlign;\n\n        var distance$$1 = 5 * invScale;\n        // End\n        if (label.__position === 'end') {\n            textPosition = [d[0] * distance$$1 + toPos[0], d[1] * distance$$1 + toPos[1]];\n            textAlign = d[0] > 0.8 ? 'left' : (d[0] < -0.8 ? 'right' : 'center');\n            textVerticalAlign = d[1] > 0.8 ? 'top' : (d[1] < -0.8 ? 'bottom' : 'middle');\n        }\n        // Middle\n        else if (label.__position === 'middle') {\n            var halfPercent = percent / 2;\n            var tangent = line.tangentAt(halfPercent);\n            var n = [tangent[1], -tangent[0]];\n            var cp = line.pointAt(halfPercent);\n            if (n[1] > 0) {\n                n[0] = -n[0];\n                n[1] = -n[1];\n            }\n            textPosition = [cp[0] + n[0] * distance$$1, cp[1] + n[1] * distance$$1];\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            var rotation = -Math.atan2(tangent[1], tangent[0]);\n            if (toPos[0] < fromPos[0]) {\n                rotation = Math.PI + rotation;\n            }\n            label.attr('rotation', rotation);\n        }\n        // Start\n        else {\n            textPosition = [-d[0] * distance$$1 + fromPos[0], -d[1] * distance$$1 + fromPos[1]];\n            textAlign = d[0] > 0.8 ? 'right' : (d[0] < -0.8 ? 'left' : 'center');\n            textVerticalAlign = d[1] > 0.8 ? 'bottom' : (d[1] < -0.8 ? 'top' : 'middle');\n        }\n        label.attr({\n            style: {\n                // Use the user specified text align and baseline first\n                textVerticalAlign: label.__verticalAlign || textVerticalAlign,\n                textAlign: label.__textAlign || textAlign\n            },\n            position: textPosition,\n            scale: [invScale, invScale]\n        });\n    }\n}\n\n/**\n * @constructor\n * @extends {module:zrender/graphic/Group}\n * @alias {module:echarts/chart/helper/Line}\n */\nfunction Line$1(lineData, idx, seriesScope) {\n    Group.call(this);\n\n    this._createLine(lineData, idx, seriesScope);\n}\n\nvar lineProto = Line$1.prototype;\n\n// Update symbol position and rotation\nlineProto.beforeUpdate = updateSymbolAndLabelBeforeLineUpdate;\n\nlineProto._createLine = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n    var linePoints = lineData.getItemLayout(idx);\n\n    var line = createLine(linePoints);\n    line.shape.percent = 0;\n    initProps(line, {\n        shape: {\n            percent: 1\n        }\n    }, seriesModel, idx);\n\n    this.add(line);\n\n    var label = new Text({\n        name: 'label',\n        // FIXME\n        // Temporary solution for `focusNodeAdjacency`.\n        // line label do not use the opacity of lineStyle.\n        lineLabelOriginalOpacity: 1\n    });\n    this.add(label);\n\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbol = createSymbol$1(symbolCategory, lineData, idx);\n        // symbols must added after line to make sure\n        // it will be updated after line#update.\n        // Or symbol position and rotation update in line#beforeUpdate will be one frame slow\n        this.add(symbol);\n        this[makeSymbolTypeKey(symbolCategory)] = lineData.getItemVisual(idx, symbolCategory);\n    }, this);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\nlineProto.updateData = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n\n    var line = this.childOfName('line');\n    var linePoints = lineData.getItemLayout(idx);\n    var target = {\n        shape: {}\n    };\n    setLinePoints(target.shape, linePoints);\n    updateProps(line, target, seriesModel, idx);\n\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbolType = lineData.getItemVisual(idx, symbolCategory);\n        var key = makeSymbolTypeKey(symbolCategory);\n        // Symbol changed\n        if (this[key] !== symbolType) {\n            this.remove(this.childOfName(symbolCategory));\n            var symbol = createSymbol$1(symbolCategory, lineData, idx);\n            this.add(symbol);\n        }\n        this[key] = symbolType;\n    }, this);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\nlineProto._updateCommonStl = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n\n    var line = this.childOfName('line');\n\n    var lineStyle = seriesScope && seriesScope.lineStyle;\n    var hoverLineStyle = seriesScope && seriesScope.hoverLineStyle;\n    var labelModel = seriesScope && seriesScope.labelModel;\n    var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;\n\n    // Optimization for large dataset\n    if (!seriesScope || lineData.hasItemOption) {\n        var itemModel = lineData.getItemModel(idx);\n\n        lineStyle = itemModel.getModel('lineStyle').getLineStyle();\n        hoverLineStyle = itemModel.getModel('emphasis.lineStyle').getLineStyle();\n\n        labelModel = itemModel.getModel('label');\n        hoverLabelModel = itemModel.getModel('emphasis.label');\n    }\n\n    var visualColor = lineData.getItemVisual(idx, 'color');\n    var visualOpacity = retrieve3(\n        lineData.getItemVisual(idx, 'opacity'),\n        lineStyle.opacity,\n        1\n    );\n\n    line.useStyle(defaults(\n        {\n            strokeNoScale: true,\n            fill: 'none',\n            stroke: visualColor,\n            opacity: visualOpacity\n        },\n        lineStyle\n    ));\n    line.hoverStyle = hoverLineStyle;\n\n    // Update symbol\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbol = this.childOfName(symbolCategory);\n        if (symbol) {\n            symbol.setColor(visualColor);\n            symbol.setStyle({\n                opacity: visualOpacity\n            });\n        }\n    }, this);\n\n    var showLabel = labelModel.getShallow('show');\n    var hoverShowLabel = hoverLabelModel.getShallow('show');\n\n    var label = this.childOfName('label');\n    var defaultLabelColor;\n    var baseText;\n\n    // FIXME: the logic below probably should be merged to `graphic.setLabelStyle`.\n    if (showLabel || hoverShowLabel) {\n        defaultLabelColor = visualColor || '#000';\n\n        baseText = seriesModel.getFormattedLabel(idx, 'normal', lineData.dataType);\n        if (baseText == null) {\n            var rawVal = seriesModel.getRawValue(idx);\n            baseText = rawVal == null\n                ? lineData.getName(idx)\n                : isFinite(rawVal)\n                ? round$2(rawVal)\n                : rawVal;\n        }\n    }\n    var normalText = showLabel ? baseText : null;\n    var emphasisText = hoverShowLabel\n        ? retrieve2(\n            seriesModel.getFormattedLabel(idx, 'emphasis', lineData.dataType),\n            baseText\n        )\n        : null;\n\n    var labelStyle = label.style;\n\n    // Always set `textStyle` even if `normalStyle.text` is null, because default\n    // values have to be set on `normalStyle`.\n    if (normalText != null || emphasisText != null) {\n        setTextStyle(label.style, labelModel, {\n            text: normalText\n        }, {\n            autoColor: defaultLabelColor\n        });\n\n        label.__textAlign = labelStyle.textAlign;\n        label.__verticalAlign = labelStyle.textVerticalAlign;\n        // 'start', 'middle', 'end'\n        label.__position = labelModel.get('position') || 'middle';\n    }\n\n    if (emphasisText != null) {\n        // Only these properties supported in this emphasis style here.\n        label.hoverStyle = {\n            text: emphasisText,\n            textFill: hoverLabelModel.getTextColor(true),\n            // For merging hover style to normal style, do not use\n            // `hoverLabelModel.getFont()` here.\n            fontStyle: hoverLabelModel.getShallow('fontStyle'),\n            fontWeight: hoverLabelModel.getShallow('fontWeight'),\n            fontSize: hoverLabelModel.getShallow('fontSize'),\n            fontFamily: hoverLabelModel.getShallow('fontFamily')\n        };\n    }\n    else {\n        label.hoverStyle = {\n            text: null\n        };\n    }\n\n    label.ignore = !showLabel && !hoverShowLabel;\n\n    setHoverStyle(this);\n};\n\nlineProto.highlight = function () {\n    this.trigger('emphasis');\n};\n\nlineProto.downplay = function () {\n    this.trigger('normal');\n};\n\nlineProto.updateLayout = function (lineData, idx) {\n    this.setLinePoints(lineData.getItemLayout(idx));\n};\n\nlineProto.setLinePoints = function (points) {\n    var linePath = this.childOfName('line');\n    setLinePoints(linePath.shape, points);\n    linePath.dirty();\n};\n\ninherits(Line$1, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/LineDraw\n */\n\n// import IncrementalDisplayable from 'zrender/src/graphic/IncrementalDisplayable';\n\n/**\n * @alias module:echarts/component/marker/LineDraw\n * @constructor\n */\nfunction LineDraw(ctor) {\n    this._ctor = ctor || Line$1;\n\n    this.group = new Group();\n}\n\nvar lineDrawProto = LineDraw.prototype;\n\nlineDrawProto.isPersistent = function () {\n    return true;\n};\n\n/**\n * @param {module:echarts/data/List} lineData\n */\nlineDrawProto.updateData = function (lineData) {\n    var lineDraw = this;\n    var group = lineDraw.group;\n\n    var oldLineData = lineDraw._lineData;\n    lineDraw._lineData = lineData;\n\n    // There is no oldLineData only when first rendering or switching from\n    // stream mode to normal mode, where previous elements should be removed.\n    if (!oldLineData) {\n        group.removeAll();\n    }\n\n    var seriesScope = makeSeriesScope$1(lineData);\n\n    lineData.diff(oldLineData)\n        .add(function (idx) {\n            doAdd(lineDraw, lineData, idx, seriesScope);\n        })\n        .update(function (newIdx, oldIdx) {\n            doUpdate(lineDraw, oldLineData, lineData, oldIdx, newIdx, seriesScope);\n        })\n        .remove(function (idx) {\n            group.remove(oldLineData.getItemGraphicEl(idx));\n        })\n        .execute();\n};\n\nfunction doAdd(lineDraw, lineData, idx, seriesScope) {\n    var itemLayout = lineData.getItemLayout(idx);\n\n    if (!lineNeedsDraw(itemLayout)) {\n        return;\n    }\n\n    var el = new lineDraw._ctor(lineData, idx, seriesScope);\n    lineData.setItemGraphicEl(idx, el);\n    lineDraw.group.add(el);\n}\n\nfunction doUpdate(lineDraw, oldLineData, newLineData, oldIdx, newIdx, seriesScope) {\n    var itemEl = oldLineData.getItemGraphicEl(oldIdx);\n\n    if (!lineNeedsDraw(newLineData.getItemLayout(newIdx))) {\n        lineDraw.group.remove(itemEl);\n        return;\n    }\n\n    if (!itemEl) {\n        itemEl = new lineDraw._ctor(newLineData, newIdx, seriesScope);\n    }\n    else {\n        itemEl.updateData(newLineData, newIdx, seriesScope);\n    }\n\n    newLineData.setItemGraphicEl(newIdx, itemEl);\n\n    lineDraw.group.add(itemEl);\n}\n\nlineDrawProto.updateLayout = function () {\n    var lineData = this._lineData;\n\n    // Do not support update layout in incremental mode.\n    if (!lineData) {\n        return;\n    }\n\n    lineData.eachItemGraphicEl(function (el, idx) {\n        el.updateLayout(lineData, idx);\n    }, this);\n};\n\nlineDrawProto.incrementalPrepareUpdate = function (lineData) {\n    this._seriesScope = makeSeriesScope$1(lineData);\n    this._lineData = null;\n    this.group.removeAll();\n};\n\nlineDrawProto.incrementalUpdate = function (taskParams, lineData) {\n    function updateIncrementalAndHover(el) {\n        if (!el.isGroup) {\n            el.incremental = el.useHoverLayer = true;\n        }\n    }\n\n    for (var idx = taskParams.start; idx < taskParams.end; idx++) {\n        var itemLayout = lineData.getItemLayout(idx);\n\n        if (lineNeedsDraw(itemLayout)) {\n            var el = new this._ctor(lineData, idx, this._seriesScope);\n            el.traverse(updateIncrementalAndHover);\n\n            this.group.add(el);\n            lineData.setItemGraphicEl(idx, el);\n        }\n    }\n};\n\nfunction makeSeriesScope$1(lineData) {\n    var hostModel = lineData.hostModel;\n    return {\n        lineStyle: hostModel.getModel('lineStyle').getLineStyle(),\n        hoverLineStyle: hostModel.getModel('emphasis.lineStyle').getLineStyle(),\n        labelModel: hostModel.getModel('label'),\n        hoverLabelModel: hostModel.getModel('emphasis.label')\n    };\n}\n\nlineDrawProto.remove = function () {\n    this._clearIncremental();\n    this._incremental = null;\n    this.group.removeAll();\n};\n\nlineDrawProto._clearIncremental = function () {\n    var incremental = this._incremental;\n    if (incremental) {\n        incremental.clearDisplaybles();\n    }\n};\n\nfunction isPointNaN(pt) {\n    return isNaN(pt[0]) || isNaN(pt[1]);\n}\n\nfunction lineNeedsDraw(pts) {\n    return !isPointNaN(pts[0]) && !isPointNaN(pts[1]);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar markLineTransform = function (seriesModel, coordSys, mlModel, item) {\n    var data = seriesModel.getData();\n    // Special type markLine like 'min', 'max', 'average', 'median'\n    var mlType = item.type;\n\n    if (!isArray(item)\n        && (\n            mlType === 'min' || mlType === 'max' || mlType === 'average' || mlType === 'median'\n            // In case\n            // data: [{\n            //   yAxis: 10\n            // }]\n            || (item.xAxis != null || item.yAxis != null)\n        )\n    ) {\n        var valueAxis;\n        var valueDataDim;\n        var value;\n\n        if (item.yAxis != null || item.xAxis != null) {\n            valueDataDim = item.yAxis != null ? 'y' : 'x';\n            valueAxis = coordSys.getAxis(valueDataDim);\n\n            value = retrieve(item.yAxis, item.xAxis);\n        }\n        else {\n            var axisInfo = getAxisInfo$1(item, data, coordSys, seriesModel);\n            valueDataDim = axisInfo.valueDataDim;\n            valueAxis = axisInfo.valueAxis;\n            value = numCalculate(data, valueDataDim, mlType);\n        }\n        var valueIndex = valueDataDim === 'x' ? 0 : 1;\n        var baseIndex = 1 - valueIndex;\n\n        var mlFrom = clone(item);\n        var mlTo = {};\n\n        mlFrom.type = null;\n\n        mlFrom.coord = [];\n        mlTo.coord = [];\n        mlFrom.coord[baseIndex] = -Infinity;\n        mlTo.coord[baseIndex] = Infinity;\n\n        var precision = mlModel.get('precision');\n        if (precision >= 0 && typeof value === 'number') {\n            value = +value.toFixed(Math.min(precision, 20));\n        }\n\n        mlFrom.coord[valueIndex] = mlTo.coord[valueIndex] = value;\n\n        item = [mlFrom, mlTo, { // Extra option for tooltip and label\n            type: mlType,\n            valueIndex: item.valueIndex,\n            // Force to use the value of calculated value.\n            value: value\n        }];\n    }\n\n    item = [\n        dataTransform(seriesModel, item[0]),\n        dataTransform(seriesModel, item[1]),\n        extend({}, item[2])\n    ];\n\n    // Avoid line data type is extended by from(to) data type\n    item[2].type = item[2].type || '';\n\n    // Merge from option and to option into line option\n    merge(item[2], item[0]);\n    merge(item[2], item[1]);\n\n    return item;\n};\n\nfunction isInifinity(val) {\n    return !isNaN(val) && !isFinite(val);\n}\n\n// If a markLine has one dim\nfunction ifMarkLineHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) {\n    var otherDimIndex = 1 - dimIndex;\n    var dimName = coordSys.dimensions[dimIndex];\n    return isInifinity(fromCoord[otherDimIndex]) && isInifinity(toCoord[otherDimIndex])\n        && fromCoord[dimIndex] === toCoord[dimIndex] && coordSys.getAxis(dimName).containData(fromCoord[dimIndex]);\n}\n\nfunction markLineFilter(coordSys, item) {\n    if (coordSys.type === 'cartesian2d') {\n        var fromCoord = item[0].coord;\n        var toCoord = item[1].coord;\n        // In case\n        // {\n        //  markLine: {\n        //    data: [{ yAxis: 2 }]\n        //  }\n        // }\n        if (\n            fromCoord && toCoord\n            && (ifMarkLineHasOnlyDim(1, fromCoord, toCoord, coordSys)\n            || ifMarkLineHasOnlyDim(0, fromCoord, toCoord, coordSys))\n        ) {\n            return true;\n        }\n    }\n    return dataFilter$1(coordSys, item[0])\n        && dataFilter$1(coordSys, item[1]);\n}\n\nfunction updateSingleMarkerEndLayout(\n    data, idx, isFrom, seriesModel, api\n) {\n    var coordSys = seriesModel.coordinateSystem;\n    var itemModel = data.getItemModel(idx);\n\n    var point;\n    var xPx = parsePercent$1(itemModel.get('x'), api.getWidth());\n    var yPx = parsePercent$1(itemModel.get('y'), api.getHeight());\n    if (!isNaN(xPx) && !isNaN(yPx)) {\n        point = [xPx, yPx];\n    }\n    else {\n        // Chart like bar may have there own marker positioning logic\n        if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                data.getValues(data.dimensions, idx)\n            );\n        }\n        else {\n            var dims = coordSys.dimensions;\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            point = coordSys.dataToPoint([x, y]);\n        }\n        // Expand line to the edge of grid if value on one axis is Inifnity\n        // In case\n        //  markLine: {\n        //    data: [{\n        //      yAxis: 2\n        //      // or\n        //      type: 'average'\n        //    }]\n        //  }\n        if (coordSys.type === 'cartesian2d') {\n            var xAxis = coordSys.getAxis('x');\n            var yAxis = coordSys.getAxis('y');\n            var dims = coordSys.dimensions;\n            if (isInifinity(data.get(dims[0], idx))) {\n                point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[isFrom ? 0 : 1]);\n            }\n            else if (isInifinity(data.get(dims[1], idx))) {\n                point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[isFrom ? 0 : 1]);\n            }\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n    }\n\n    data.setItemLayout(idx, point);\n}\n\nMarkerView.extend({\n\n    type: 'markLine',\n\n    // updateLayout: function (markLineModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var mlModel = seriesModel.markLineModel;\n    //         if (mlModel) {\n    //             var mlData = mlModel.getData();\n    //             var fromData = mlModel.__from;\n    //             var toData = mlModel.__to;\n    //             // Update visual and layout of from symbol and to symbol\n    //             fromData.each(function (idx) {\n    //                 updateSingleMarkerEndLayout(fromData, idx, true, seriesModel, api);\n    //                 updateSingleMarkerEndLayout(toData, idx, false, seriesModel, api);\n    //             });\n    //             // Update layout of line\n    //             mlData.each(function (idx) {\n    //                 mlData.setItemLayout(idx, [\n    //                     fromData.getItemLayout(idx),\n    //                     toData.getItemLayout(idx)\n    //                 ]);\n    //             });\n\n    //             this.markerGroupMap.get(seriesModel.id).updateLayout();\n\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markLineModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var mlModel = seriesModel.markLineModel;\n            if (mlModel) {\n                var mlData = mlModel.getData();\n                var fromData = mlModel.__from;\n                var toData = mlModel.__to;\n                // Update visual and layout of from symbol and to symbol\n                fromData.each(function (idx) {\n                    updateSingleMarkerEndLayout(fromData, idx, true, seriesModel, api);\n                    updateSingleMarkerEndLayout(toData, idx, false, seriesModel, api);\n                });\n                // Update layout of line\n                mlData.each(function (idx) {\n                    mlData.setItemLayout(idx, [\n                        fromData.getItemLayout(idx),\n                        toData.getItemLayout(idx)\n                    ]);\n                });\n\n                this.markerGroupMap.get(seriesModel.id).updateLayout();\n\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, mlModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var lineDrawMap = this.markerGroupMap;\n        var lineDraw = lineDrawMap.get(seriesId)\n            || lineDrawMap.set(seriesId, new LineDraw());\n        this.group.add(lineDraw.group);\n\n        var mlData = createList$2(coordSys, seriesModel, mlModel);\n\n        var fromData = mlData.from;\n        var toData = mlData.to;\n        var lineData = mlData.line;\n\n        mlModel.__from = fromData;\n        mlModel.__to = toData;\n        // Line data for tooltip and formatter\n        mlModel.setData(lineData);\n\n        var symbolType = mlModel.get('symbol');\n        var symbolSize = mlModel.get('symbolSize');\n        if (!isArray(symbolType)) {\n            symbolType = [symbolType, symbolType];\n        }\n        if (typeof symbolSize === 'number') {\n            symbolSize = [symbolSize, symbolSize];\n        }\n\n        // Update visual and layout of from symbol and to symbol\n        mlData.from.each(function (idx) {\n            updateDataVisualAndLayout(fromData, idx, true);\n            updateDataVisualAndLayout(toData, idx, false);\n        });\n\n        // Update visual and layout of line\n        lineData.each(function (idx) {\n            var lineColor = lineData.getItemModel(idx).get('lineStyle.color');\n            lineData.setItemVisual(idx, {\n                color: lineColor || fromData.getItemVisual(idx, 'color')\n            });\n            lineData.setItemLayout(idx, [\n                fromData.getItemLayout(idx),\n                toData.getItemLayout(idx)\n            ]);\n\n            lineData.setItemVisual(idx, {\n                'fromSymbolSize': fromData.getItemVisual(idx, 'symbolSize'),\n                'fromSymbol': fromData.getItemVisual(idx, 'symbol'),\n                'toSymbolSize': toData.getItemVisual(idx, 'symbolSize'),\n                'toSymbol': toData.getItemVisual(idx, 'symbol')\n            });\n        });\n\n        lineDraw.updateData(lineData);\n\n        // Set host model for tooltip\n        // FIXME\n        mlData.line.eachItemGraphicEl(function (el, idx) {\n            el.traverse(function (child) {\n                child.dataModel = mlModel;\n            });\n        });\n\n        function updateDataVisualAndLayout(data, idx, isFrom) {\n            var itemModel = data.getItemModel(idx);\n\n            updateSingleMarkerEndLayout(\n                data, idx, isFrom, seriesModel, api\n            );\n\n            data.setItemVisual(idx, {\n                symbolSize: itemModel.get('symbolSize') || symbolSize[isFrom ? 0 : 1],\n                symbol: itemModel.get('symbol', true) || symbolType[isFrom ? 0 : 1],\n                color: itemModel.get('itemStyle.color') || seriesData.getVisual('color')\n            });\n        }\n\n        lineDraw.__keep = true;\n\n        lineDraw.group.silent = mlModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} coordSys\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$2(coordSys, seriesModel, mlModel) {\n\n    var coordDimsInfos;\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var info = seriesModel.getData().getDimensionInfo(\n                seriesModel.getData().mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n    }\n\n    var fromData = new List(coordDimsInfos, mlModel);\n    var toData = new List(coordDimsInfos, mlModel);\n    // No dimensions\n    var lineData = new List([], mlModel);\n\n    var optData = map(mlModel.get('data'), curry(\n        markLineTransform, seriesModel, coordSys, mlModel\n    ));\n    if (coordSys) {\n        optData = filter(\n            optData, curry(markLineFilter, coordSys)\n        );\n    }\n    var dimValueGetter$$1 = coordSys ? dimValueGetter : function (item) {\n        return item.value;\n    };\n    fromData.initData(\n        map(optData, function (item) {\n            return item[0];\n        }),\n        null,\n        dimValueGetter$$1\n    );\n    toData.initData(\n        map(optData, function (item) {\n            return item[1];\n        }),\n        null,\n        dimValueGetter$$1\n    );\n    lineData.initData(\n        map(optData, function (item) {\n            return item[2];\n        })\n    );\n    lineData.hasItemOption = true;\n\n    return {\n        from: fromData,\n        to: toData,\n        line: lineData\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterPreprocessor(function (opt) {\n    // Make sure markLine component is enabled\n    opt.markLine = opt.markLine || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markArea',\n\n    defaultOption: {\n        zlevel: 0,\n        // PENDING\n        z: 1,\n        tooltip: {\n            trigger: 'item'\n        },\n        // markArea should fixed on the coordinate system\n        animation: false,\n        label: {\n            show: true,\n            position: 'top'\n        },\n        itemStyle: {\n            // color and borderColor default to use color from series\n            // color: 'auto'\n            // borderColor: 'auto'\n            borderWidth: 0\n        },\n\n        emphasis: {\n            label: {\n                show: true,\n                position: 'top'\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Better on polar\n\nvar markAreaTransform = function (seriesModel, coordSys, maModel, item) {\n    var lt = dataTransform(seriesModel, item[0]);\n    var rb = dataTransform(seriesModel, item[1]);\n    var retrieve$$1 = retrieve;\n\n    // FIXME make sure lt is less than rb\n    var ltCoord = lt.coord;\n    var rbCoord = rb.coord;\n    ltCoord[0] = retrieve$$1(ltCoord[0], -Infinity);\n    ltCoord[1] = retrieve$$1(ltCoord[1], -Infinity);\n\n    rbCoord[0] = retrieve$$1(rbCoord[0], Infinity);\n    rbCoord[1] = retrieve$$1(rbCoord[1], Infinity);\n\n    // Merge option into one\n    var result = mergeAll([{}, lt, rb]);\n\n    result.coord = [\n        lt.coord, rb.coord\n    ];\n    result.x0 = lt.x;\n    result.y0 = lt.y;\n    result.x1 = rb.x;\n    result.y1 = rb.y;\n    return result;\n};\n\nfunction isInifinity$1(val) {\n    return !isNaN(val) && !isFinite(val);\n}\n\n// If a markArea has one dim\nfunction ifMarkLineHasOnlyDim$1(dimIndex, fromCoord, toCoord, coordSys) {\n    var otherDimIndex = 1 - dimIndex;\n    return isInifinity$1(fromCoord[otherDimIndex]) && isInifinity$1(toCoord[otherDimIndex]);\n}\n\nfunction markAreaFilter(coordSys, item) {\n    var fromCoord = item.coord[0];\n    var toCoord = item.coord[1];\n    if (coordSys.type === 'cartesian2d') {\n        // In case\n        // {\n        //  markArea: {\n        //    data: [{ yAxis: 2 }]\n        //  }\n        // }\n        if (\n            fromCoord && toCoord\n            && (ifMarkLineHasOnlyDim$1(1, fromCoord, toCoord, coordSys)\n            || ifMarkLineHasOnlyDim$1(0, fromCoord, toCoord, coordSys))\n        ) {\n            return true;\n        }\n    }\n    return dataFilter$1(coordSys, {\n            coord: fromCoord,\n            x: item.x0,\n            y: item.y0\n        })\n        || dataFilter$1(coordSys, {\n            coord: toCoord,\n            x: item.x1,\n            y: item.y1\n        });\n}\n\n// dims can be ['x0', 'y0'], ['x1', 'y1'], ['x0', 'y1'], ['x1', 'y0']\nfunction getSingleMarkerEndPoint(data, idx, dims, seriesModel, api) {\n    var coordSys = seriesModel.coordinateSystem;\n    var itemModel = data.getItemModel(idx);\n\n    var point;\n    var xPx = parsePercent$1(itemModel.get(dims[0]), api.getWidth());\n    var yPx = parsePercent$1(itemModel.get(dims[1]), api.getHeight());\n    if (!isNaN(xPx) && !isNaN(yPx)) {\n        point = [xPx, yPx];\n    }\n    else {\n        // Chart like bar may have there own marker positioning logic\n        if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                data.getValues(dims, idx)\n            );\n        }\n        else {\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            var pt = [x, y];\n            coordSys.clampData && coordSys.clampData(pt, pt);\n            point = coordSys.dataToPoint(pt, true);\n        }\n        if (coordSys.type === 'cartesian2d') {\n            var xAxis = coordSys.getAxis('x');\n            var yAxis = coordSys.getAxis('y');\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            if (isInifinity$1(x)) {\n                point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[dims[0] === 'x0' ? 0 : 1]);\n            }\n            else if (isInifinity$1(y)) {\n                point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[dims[1] === 'y0' ? 0 : 1]);\n            }\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n    }\n\n    return point;\n}\n\nvar dimPermutations = [['x0', 'y0'], ['x1', 'y0'], ['x1', 'y1'], ['x0', 'y1']];\n\nMarkerView.extend({\n\n    type: 'markArea',\n\n    // updateLayout: function (markAreaModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var maModel = seriesModel.markAreaModel;\n    //         if (maModel) {\n    //             var areaData = maModel.getData();\n    //             areaData.each(function (idx) {\n    //                 var points = zrUtil.map(dimPermutations, function (dim) {\n    //                     return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n    //                 });\n    //                 // Layout\n    //                 areaData.setItemLayout(idx, points);\n    //                 var el = areaData.getItemGraphicEl(idx);\n    //                 el.setShape('points', points);\n    //             });\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markAreaModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var maModel = seriesModel.markAreaModel;\n            if (maModel) {\n                var areaData = maModel.getData();\n                areaData.each(function (idx) {\n                    var points = map(dimPermutations, function (dim) {\n                        return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n                    });\n                    // Layout\n                    areaData.setItemLayout(idx, points);\n                    var el = areaData.getItemGraphicEl(idx);\n                    el.setShape('points', points);\n                });\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, maModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var areaGroupMap = this.markerGroupMap;\n        var polygonGroup = areaGroupMap.get(seriesId)\n            || areaGroupMap.set(seriesId, {group: new Group()});\n\n        this.group.add(polygonGroup.group);\n        polygonGroup.__keep = true;\n\n        var areaData = createList$3(coordSys, seriesModel, maModel);\n\n        // Line data for tooltip and formatter\n        maModel.setData(areaData);\n\n        // Update visual and layout of line\n        areaData.each(function (idx) {\n            // Layout\n            areaData.setItemLayout(idx, map(dimPermutations, function (dim) {\n                return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n            }));\n\n            // Visual\n            areaData.setItemVisual(idx, {\n                color: seriesData.getVisual('color')\n            });\n        });\n\n\n        areaData.diff(polygonGroup.__data)\n            .add(function (idx) {\n                var polygon = new Polygon({\n                    shape: {\n                        points: areaData.getItemLayout(idx)\n                    }\n                });\n                areaData.setItemGraphicEl(idx, polygon);\n                polygonGroup.group.add(polygon);\n            })\n            .update(function (newIdx, oldIdx) {\n                var polygon = polygonGroup.__data.getItemGraphicEl(oldIdx);\n                updateProps(polygon, {\n                    shape: {\n                        points: areaData.getItemLayout(newIdx)\n                    }\n                }, maModel, newIdx);\n                polygonGroup.group.add(polygon);\n                areaData.setItemGraphicEl(newIdx, polygon);\n            })\n            .remove(function (idx) {\n                var polygon = polygonGroup.__data.getItemGraphicEl(idx);\n                polygonGroup.group.remove(polygon);\n            })\n            .execute();\n\n        areaData.eachItemGraphicEl(function (polygon, idx) {\n            var itemModel = areaData.getItemModel(idx);\n            var labelModel = itemModel.getModel('label');\n            var labelHoverModel = itemModel.getModel('emphasis.label');\n            var color = areaData.getItemVisual(idx, 'color');\n            polygon.useStyle(\n                defaults(\n                    itemModel.getModel('itemStyle').getItemStyle(),\n                    {\n                        fill: modifyAlpha(color, 0.4),\n                        stroke: color\n                    }\n                )\n            );\n\n            polygon.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n\n            setLabelStyle(\n                polygon.style, polygon.hoverStyle, labelModel, labelHoverModel,\n                {\n                    labelFetcher: maModel,\n                    labelDataIndex: idx,\n                    defaultText: areaData.getName(idx) || '',\n                    isRectText: true,\n                    autoColor: color\n                }\n            );\n\n            setHoverStyle(polygon, {});\n\n            polygon.dataModel = maModel;\n        });\n\n        polygonGroup.__data = areaData;\n\n        polygonGroup.group.silent = maModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} coordSys\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$3(coordSys, seriesModel, maModel) {\n\n    var coordDimsInfos;\n    var areaData;\n    var dims = ['x0', 'y0', 'x1', 'y1'];\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var data = seriesModel.getData();\n            var info = data.getDimensionInfo(\n                data.mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n        areaData = new List(map(dims, function (dim, idx) {\n            return {\n                name: dim,\n                type: coordDimsInfos[idx % 2].type\n            };\n        }), maModel);\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n        areaData = new List(coordDimsInfos, maModel);\n    }\n\n    var optData = map(maModel.get('data'), curry(\n        markAreaTransform, seriesModel, coordSys, maModel\n    ));\n    if (coordSys) {\n        optData = filter(\n            optData, curry(markAreaFilter, coordSys)\n        );\n    }\n\n    var dimValueGetter$$1 = coordSys ? function (item, dimName, dataIndex, dimIndex) {\n        return item.coord[Math.floor(dimIndex / 2)][dimIndex % 2];\n    } : function (item) {\n        return item.value;\n    };\n    areaData.initData(optData, null, dimValueGetter$$1);\n    areaData.hasItemOption = true;\n    return areaData;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterPreprocessor(function (opt) {\n    // Make sure markArea component is enabled\n    opt.markArea = opt.markArea || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nComponentModel.registerSubTypeDefaulter('dataZoom', function () {\n    // Default 'slider' when no type specified.\n    return 'slider';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AXIS_DIMS = ['x', 'y', 'z', 'radius', 'angle', 'single'];\n// Supported coords.\nvar COORDS = ['cartesian2d', 'polar', 'singleAxis'];\n\n/**\n * @param {string} coordType\n * @return {boolean}\n */\nfunction isCoordSupported(coordType) {\n    return indexOf(COORDS, coordType) >= 0;\n}\n\n/**\n * Create \"each\" method to iterate names.\n *\n * @pubilc\n * @param  {Array.<string>} names\n * @param  {Array.<string>=} attrs\n * @return {Function}\n */\nfunction createNameEach(names, attrs) {\n    names = names.slice();\n    var capitalNames = map(names, capitalFirst);\n    attrs = (attrs || []).slice();\n    var capitalAttrs = map(attrs, capitalFirst);\n\n    return function (callback, context) {\n        each$1(names, function (name, index) {\n            var nameObj = {name: name, capital: capitalNames[index]};\n\n            for (var j = 0; j < attrs.length; j++) {\n                nameObj[attrs[j]] = name + capitalAttrs[j];\n            }\n\n            callback.call(context, nameObj);\n        });\n    };\n}\n\n/**\n * Iterate each dimension name.\n *\n * @public\n * @param {Function} callback The parameter is like:\n *                            {\n *                                name: 'angle',\n *                                capital: 'Angle',\n *                                axis: 'angleAxis',\n *                                axisIndex: 'angleAixs',\n *                                index: 'angleIndex'\n *                            }\n * @param {Object} context\n */\nvar eachAxisDim$1 = createNameEach(AXIS_DIMS, ['axisIndex', 'axis', 'index', 'id']);\n\n/**\n * If tow dataZoomModels has the same axis controlled, we say that they are 'linked'.\n * dataZoomModels and 'links' make up one or more graphics.\n * This function finds the graphic where the source dataZoomModel is in.\n *\n * @public\n * @param {Function} forEachNode Node iterator.\n * @param {Function} forEachEdgeType edgeType iterator\n * @param {Function} edgeIdGetter Giving node and edgeType, return an array of edge id.\n * @return {Function} Input: sourceNode, Output: Like {nodes: [], dims: {}}\n */\nfunction createLinkedNodesFinder(forEachNode, forEachEdgeType, edgeIdGetter) {\n\n    return function (sourceNode) {\n        var result = {\n            nodes: [],\n            records: {} // key: edgeType.name, value: Object (key: edge id, value: boolean).\n        };\n\n        forEachEdgeType(function (edgeType) {\n            result.records[edgeType.name] = {};\n        });\n\n        if (!sourceNode) {\n            return result;\n        }\n\n        absorb(sourceNode, result);\n\n        var existsLink;\n        do {\n            existsLink = false;\n            forEachNode(processSingleNode);\n        }\n        while (existsLink);\n\n        function processSingleNode(node) {\n            if (!isNodeAbsorded(node, result) && isLinked(node, result)) {\n                absorb(node, result);\n                existsLink = true;\n            }\n        }\n\n        return result;\n    };\n\n    function isNodeAbsorded(node, result) {\n        return indexOf(result.nodes, node) >= 0;\n    }\n\n    function isLinked(node, result) {\n        var hasLink = false;\n        forEachEdgeType(function (edgeType) {\n            each$1(edgeIdGetter(node, edgeType) || [], function (edgeId) {\n                result.records[edgeType.name][edgeId] && (hasLink = true);\n            });\n        });\n        return hasLink;\n    }\n\n    function absorb(node, result) {\n        result.nodes.push(node);\n        forEachEdgeType(function (edgeType) {\n            each$1(edgeIdGetter(node, edgeType) || [], function (edgeId) {\n                result.records[edgeType.name][edgeId] = true;\n            });\n        });\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$13 = each$1;\nvar asc$1 = asc;\n\n/**\n * Operate single axis.\n * One axis can only operated by one axis operator.\n * Different dataZoomModels may be defined to operate the same axis.\n * (i.e. 'inside' data zoom and 'slider' data zoom components)\n * So dataZoomModels share one axisProxy in that case.\n *\n * @class\n */\nvar AxisProxy = function (dimName, axisIndex, dataZoomModel, ecModel) {\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._dimName = dimName;\n\n    /**\n     * @private\n     */\n    this._axisIndex = axisIndex;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._valueWindow;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._percentWindow;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._dataExtent;\n\n    /**\n     * {minSpan, maxSpan, minValueSpan, maxValueSpan}\n     * @private\n     * @type {Object}\n     */\n    this._minMaxSpan;\n\n    /**\n     * @readOnly\n     * @type {module: echarts/model/Global}\n     */\n    this.ecModel = ecModel;\n\n    /**\n     * @private\n     * @type {module: echarts/component/dataZoom/DataZoomModel}\n     */\n    this._dataZoomModel = dataZoomModel;\n\n    // /**\n    //  * @readOnly\n    //  * @private\n    //  */\n    // this.hasSeriesStacked;\n};\n\nAxisProxy.prototype = {\n\n    constructor: AxisProxy,\n\n    /**\n     * Whether the axisProxy is hosted by dataZoomModel.\n     *\n     * @public\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     * @return {boolean}\n     */\n    hostedBy: function (dataZoomModel) {\n        return this._dataZoomModel === dataZoomModel;\n    },\n\n    /**\n     * @return {Array.<number>} Value can only be NaN or finite value.\n     */\n    getDataValueWindow: function () {\n        return this._valueWindow.slice();\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getDataPercentWindow: function () {\n        return this._percentWindow.slice();\n    },\n\n    /**\n     * @public\n     * @param {number} axisIndex\n     * @return {Array} seriesModels\n     */\n    getTargetSeriesModels: function () {\n        var seriesModels = [];\n        var ecModel = this.ecModel;\n\n        ecModel.eachSeries(function (seriesModel) {\n            if (isCoordSupported(seriesModel.get('coordinateSystem'))) {\n                var dimName = this._dimName;\n                var axisModel = ecModel.queryComponents({\n                    mainType: dimName + 'Axis',\n                    index: seriesModel.get(dimName + 'AxisIndex'),\n                    id: seriesModel.get(dimName + 'AxisId')\n                })[0];\n                if (this._axisIndex === (axisModel && axisModel.componentIndex)) {\n                    seriesModels.push(seriesModel);\n                }\n            }\n        }, this);\n\n        return seriesModels;\n    },\n\n    getAxisModel: function () {\n        return this.ecModel.getComponent(this._dimName + 'Axis', this._axisIndex);\n    },\n\n    getOtherAxisModel: function () {\n        var axisDim = this._dimName;\n        var ecModel = this.ecModel;\n        var axisModel = this.getAxisModel();\n        var isCartesian = axisDim === 'x' || axisDim === 'y';\n        var otherAxisDim;\n        var coordSysIndexName;\n        if (isCartesian) {\n            coordSysIndexName = 'gridIndex';\n            otherAxisDim = axisDim === 'x' ? 'y' : 'x';\n        }\n        else {\n            coordSysIndexName = 'polarIndex';\n            otherAxisDim = axisDim === 'angle' ? 'radius' : 'angle';\n        }\n        var foundOtherAxisModel;\n        ecModel.eachComponent(otherAxisDim + 'Axis', function (otherAxisModel) {\n            if ((otherAxisModel.get(coordSysIndexName) || 0)\n                === (axisModel.get(coordSysIndexName) || 0)\n            ) {\n                foundOtherAxisModel = otherAxisModel;\n            }\n        });\n        return foundOtherAxisModel;\n    },\n\n    getMinMaxSpan: function () {\n        return clone(this._minMaxSpan);\n    },\n\n    /**\n     * Only calculate by given range and this._dataExtent, do not change anything.\n     *\n     * @param {Object} opt\n     * @param {number} [opt.start]\n     * @param {number} [opt.end]\n     * @param {number} [opt.startValue]\n     * @param {number} [opt.endValue]\n     */\n    calculateDataWindow: function (opt) {\n        var dataExtent = this._dataExtent;\n        var axisModel = this.getAxisModel();\n        var scale = axisModel.axis.scale;\n        var rangePropMode = this._dataZoomModel.getRangePropMode();\n        var percentExtent = [0, 100];\n        var percentWindow = [\n            opt.start,\n            opt.end\n        ];\n        var valueWindow = [];\n\n        each$13(['startValue', 'endValue'], function (prop) {\n            valueWindow.push(opt[prop] != null ? scale.parse(opt[prop]) : null);\n        });\n\n        // Normalize bound.\n        each$13([0, 1], function (idx) {\n            var boundValue = valueWindow[idx];\n            var boundPercent = percentWindow[idx];\n\n            // Notice: dataZoom is based either on `percentProp` ('start', 'end') or\n            // on `valueProp` ('startValue', 'endValue'). The former one is suitable\n            // for cases that a dataZoom component controls multiple axes with different\n            // unit or extent, and the latter one is suitable for accurate zoom by pixel\n            // (e.g., in dataZoomSelect). `valueProp` can be calculated from `percentProp`,\n            // but it is awkward that `percentProp` can not be obtained from `valueProp`\n            // accurately (because all of values that are overflow the `dataExtent` will\n            // be calculated to percent '100%'). So we have to use\n            // `dataZoom.getRangePropMode()` to mark which prop is used.\n            // `rangePropMode` is updated only when setOption or dispatchAction, otherwise\n            // it remains its original value.\n\n            if (rangePropMode[idx] === 'percent') {\n                if (boundPercent == null) {\n                    boundPercent = percentExtent[idx];\n                }\n                // Use scale.parse to math round for category or time axis.\n                boundValue = scale.parse(linearMap(\n                    boundPercent, percentExtent, dataExtent, true\n                ));\n            }\n            else {\n                // Calculating `percent` from `value` may be not accurate, because\n                // This calculation can not be inversed, because all of values that\n                // are overflow the `dataExtent` will be calculated to percent '100%'\n                boundPercent = linearMap(\n                    boundValue, dataExtent, percentExtent, true\n                );\n            }\n\n            // valueWindow[idx] = round(boundValue);\n            // percentWindow[idx] = round(boundPercent);\n            valueWindow[idx] = boundValue;\n            percentWindow[idx] = boundPercent;\n        });\n\n        return {\n            valueWindow: asc$1(valueWindow),\n            percentWindow: asc$1(percentWindow)\n        };\n    },\n\n    /**\n     * Notice: reset should not be called before series.restoreData() called,\n     * so it is recommanded to be called in \"process stage\" but not \"model init\n     * stage\".\n     *\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    reset: function (dataZoomModel) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        var targetSeries = this.getTargetSeriesModels();\n        // Culculate data window and data extent, and record them.\n        this._dataExtent = calculateDataExtent(this, this._dimName, targetSeries);\n\n        // this.hasSeriesStacked = false;\n        // each(targetSeries, function (series) {\n            // var data = series.getData();\n            // var dataDim = data.mapDimension(this._dimName);\n            // var stackedDimension = data.getCalculationInfo('stackedDimension');\n            // if (stackedDimension && stackedDimension === dataDim) {\n                // this.hasSeriesStacked = true;\n            // }\n        // }, this);\n\n        var dataWindow = this.calculateDataWindow(dataZoomModel.option);\n\n        this._valueWindow = dataWindow.valueWindow;\n        this._percentWindow = dataWindow.percentWindow;\n\n        setMinMaxSpan(this);\n\n        // Update axis setting then.\n        setAxisModel(this);\n    },\n\n    /**\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    restore: function (dataZoomModel) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        this._valueWindow = this._percentWindow = null;\n        setAxisModel(this, true);\n    },\n\n    /**\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    filterData: function (dataZoomModel, api) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        var axisDim = this._dimName;\n        var seriesModels = this.getTargetSeriesModels();\n        var filterMode = dataZoomModel.get('filterMode');\n        var valueWindow = this._valueWindow;\n\n        if (filterMode === 'none') {\n            return;\n        }\n\n        // FIXME\n        // Toolbox may has dataZoom injected. And if there are stacked bar chart\n        // with NaN data, NaN will be filtered and stack will be wrong.\n        // So we need to force the mode to be set empty.\n        // In fect, it is not a big deal that do not support filterMode-'filter'\n        // when using toolbox#dataZoom, utill tooltip#dataZoom support \"single axis\n        // selection\" some day, which might need \"adapt to data extent on the\n        // otherAxis\", which is disabled by filterMode-'empty'.\n        // But currently, stack has been fixed to based on value but not index,\n        // so this is not an issue any more.\n        // var otherAxisModel = this.getOtherAxisModel();\n        // if (dataZoomModel.get('$fromToolbox')\n        //     && otherAxisModel\n        //     && otherAxisModel.hasSeriesStacked\n        // ) {\n        //     filterMode = 'empty';\n        // }\n\n        // TODO\n        // filterMode 'weakFilter' and 'empty' is not optimized for huge data yet.\n\n        each$13(seriesModels, function (seriesModel) {\n            var seriesData = seriesModel.getData();\n            var dataDims = seriesData.mapDimension(axisDim, true);\n\n            if (!dataDims.length) {\n                return;\n            }\n\n            if (filterMode === 'weakFilter') {\n                seriesData.filterSelf(function (dataIndex) {\n                    var leftOut;\n                    var rightOut;\n                    var hasValue;\n                    for (var i = 0; i < dataDims.length; i++) {\n                        var value = seriesData.get(dataDims[i], dataIndex);\n                        var thisHasValue = !isNaN(value);\n                        var thisLeftOut = value < valueWindow[0];\n                        var thisRightOut = value > valueWindow[1];\n                        if (thisHasValue && !thisLeftOut && !thisRightOut) {\n                            return true;\n                        }\n                        thisHasValue && (hasValue = true);\n                        thisLeftOut && (leftOut = true);\n                        thisRightOut && (rightOut = true);\n                    }\n                    // If both left out and right out, do not filter.\n                    return hasValue && leftOut && rightOut;\n                });\n            }\n            else {\n                each$13(dataDims, function (dim) {\n                    if (filterMode === 'empty') {\n                        seriesModel.setData(\n                            seriesData.map(dim, function (value) {\n                                return !isInWindow(value) ? NaN : value;\n                            })\n                        );\n                    }\n                    else {\n                        var range = {};\n                        range[dim] = valueWindow;\n\n                        // console.time('select');\n                        seriesData.selectRange(range);\n                        // console.timeEnd('select');\n                    }\n                });\n            }\n\n            each$13(dataDims, function (dim) {\n                seriesData.setApproximateExtent(valueWindow, dim);\n            });\n        });\n\n        function isInWindow(value) {\n            return value >= valueWindow[0] && value <= valueWindow[1];\n        }\n    }\n};\n\nfunction calculateDataExtent(axisProxy, axisDim, seriesModels) {\n    var dataExtent = [Infinity, -Infinity];\n\n    each$13(seriesModels, function (seriesModel) {\n        var seriesData = seriesModel.getData();\n        if (seriesData) {\n            each$13(seriesData.mapDimension(axisDim, true), function (dim) {\n                var seriesExtent = seriesData.getApproximateExtent(dim);\n                seriesExtent[0] < dataExtent[0] && (dataExtent[0] = seriesExtent[0]);\n                seriesExtent[1] > dataExtent[1] && (dataExtent[1] = seriesExtent[1]);\n            });\n        }\n    });\n\n    if (dataExtent[1] < dataExtent[0]) {\n        dataExtent = [NaN, NaN];\n    }\n\n    // It is important to get \"consistent\" extent when more then one axes is\n    // controlled by a `dataZoom`, otherwise those axes will not be synchronized\n    // when zooming. But it is difficult to know what is \"consistent\", considering\n    // axes have different type or even different meanings (For example, two\n    // time axes are used to compare data of the same date in different years).\n    // So basically dataZoom just obtains extent by series.data (in category axis\n    // extent can be obtained from axis.data).\n    // Nevertheless, user can set min/max/scale on axes to make extent of axes\n    // consistent.\n    fixExtentByAxis(axisProxy, dataExtent);\n\n    return dataExtent;\n}\n\nfunction fixExtentByAxis(axisProxy, dataExtent) {\n    var axisModel = axisProxy.getAxisModel();\n    var min = axisModel.getMin(true);\n\n    // For category axis, if min/max/scale are not set, extent is determined\n    // by axis.data by default.\n    var isCategoryAxis = axisModel.get('type') === 'category';\n    var axisDataLen = isCategoryAxis && axisModel.getCategories().length;\n\n    if (min != null && min !== 'dataMin' && typeof min !== 'function') {\n        dataExtent[0] = min;\n    }\n    else if (isCategoryAxis) {\n        dataExtent[0] = axisDataLen > 0 ? 0 : NaN;\n    }\n\n    var max = axisModel.getMax(true);\n    if (max != null && max !== 'dataMax' && typeof max !== 'function') {\n        dataExtent[1] = max;\n    }\n    else if (isCategoryAxis) {\n        dataExtent[1] = axisDataLen > 0 ? axisDataLen - 1 : NaN;\n    }\n\n    if (!axisModel.get('scale', true)) {\n        dataExtent[0] > 0 && (dataExtent[0] = 0);\n        dataExtent[1] < 0 && (dataExtent[1] = 0);\n    }\n\n    // For value axis, if min/max/scale are not set, we just use the extent obtained\n    // by series data, which may be a little different from the extent calculated by\n    // `axisHelper.getScaleExtent`. But the different just affects the experience a\n    // little when zooming. So it will not be fixed until some users require it strongly.\n\n    return dataExtent;\n}\n\nfunction setAxisModel(axisProxy, isRestore) {\n    var axisModel = axisProxy.getAxisModel();\n\n    var percentWindow = axisProxy._percentWindow;\n    var valueWindow = axisProxy._valueWindow;\n\n    if (!percentWindow) {\n        return;\n    }\n\n    // [0, 500]: arbitrary value, guess axis extent.\n    var precision = getPixelPrecision(valueWindow, [0, 500]);\n    precision = Math.min(precision, 20);\n    // isRestore or isFull\n    var useOrigin = isRestore || (percentWindow[0] === 0 && percentWindow[1] === 100);\n\n    axisModel.setRange(\n        useOrigin ? null : +valueWindow[0].toFixed(precision),\n        useOrigin ? null : +valueWindow[1].toFixed(precision)\n    );\n}\n\nfunction setMinMaxSpan(axisProxy) {\n    var minMaxSpan = axisProxy._minMaxSpan = {};\n    var dataZoomModel = axisProxy._dataZoomModel;\n\n    each$13(['min', 'max'], function (minMax) {\n        minMaxSpan[minMax + 'Span'] = dataZoomModel.get(minMax + 'Span');\n\n        // minValueSpan and maxValueSpan has higher priority than minSpan and maxSpan\n        var valueSpan = dataZoomModel.get(minMax + 'ValueSpan');\n\n        if (valueSpan != null) {\n            minMaxSpan[minMax + 'ValueSpan'] = valueSpan;\n            valueSpan = axisProxy.getAxisModel().axis.scale.parse(valueSpan);\n\n            if (valueSpan != null) {\n                var dataExtent = axisProxy._dataExtent;\n                minMaxSpan[minMax + 'Span'] = linearMap(\n                    dataExtent[0] + valueSpan, dataExtent, [0, 100], true\n                );\n            }\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$12 = each$1;\nvar eachAxisDim = eachAxisDim$1;\n\nvar DataZoomModel = extendComponentModel({\n\n    type: 'dataZoom',\n\n    dependencies: [\n        'xAxis', 'yAxis', 'zAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'series'\n    ],\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        zlevel: 0,\n        z: 4,                   // Higher than normal component (z: 2).\n        orient: null,           // Default auto by axisIndex. Possible value: 'horizontal', 'vertical'.\n        xAxisIndex: null,       // Default the first horizontal category axis.\n        yAxisIndex: null,       // Default the first vertical category axis.\n\n        filterMode: 'filter',   // Possible values: 'filter' or 'empty' or 'weakFilter'.\n                                // 'filter': data items which are out of window will be removed. This option is\n                                //          applicable when filtering outliers. For each data item, it will be\n                                //          filtered if one of the relevant dimensions is out of the window.\n                                // 'weakFilter': data items which are out of window will be removed. This option\n                                //          is applicable when filtering outliers. For each data item, it will be\n                                //          filtered only if all  of the relevant dimensions are out of the same\n                                //          side of the window.\n                                // 'empty': data items which are out of window will be set to empty.\n                                //          This option is applicable when user should not neglect\n                                //          that there are some data items out of window.\n                                // 'none': Do not filter.\n                                // Taking line chart as an example, line will be broken in\n                                // the filtered points when filterModel is set to 'empty', but\n                                // be connected when set to 'filter'.\n\n        throttle: null,         // Dispatch action by the fixed rate, avoid frequency.\n                                // default 100. Do not throttle when use null/undefined.\n                                // If animation === true and animationDurationUpdate > 0,\n                                // default value is 100, otherwise 20.\n        start: 0,               // Start percent. 0 ~ 100\n        end: 100,               // End percent. 0 ~ 100\n        startValue: null,       // Start value. If startValue specified, start is ignored.\n        endValue: null,         // End value. If endValue specified, end is ignored.\n        minSpan: null,          // 0 ~ 100\n        maxSpan: null,          // 0 ~ 100\n        minValueSpan: null,     // The range of dataZoom can not be smaller than that.\n        maxValueSpan: null,     // The range of dataZoom can not be larger than that.\n        rangeMode: null         // Array, can be 'value' or 'percent'.\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel) {\n\n        /**\n         * key like x_0, y_1\n         * @private\n         * @type {Object}\n         */\n        this._dataIntervalByAxis = {};\n\n        /**\n         * @private\n         */\n        this._dataInfo = {};\n\n        /**\n         * key like x_0, y_1\n         * @private\n         */\n        this._axisProxies = {};\n\n        /**\n         * @readOnly\n         */\n        this.textStyleModel;\n\n        /**\n         * @private\n         */\n        this._autoThrottle = true;\n\n        /**\n         * 'percent' or 'value'\n         * @private\n         */\n        this._rangePropMode = ['percent', 'percent'];\n\n        var rawOption = retrieveRaw(option);\n\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        this.doInit(rawOption);\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (newOption) {\n        var rawOption = retrieveRaw(newOption);\n\n        //FIX #2591\n        merge(this.option, newOption, true);\n\n        this.doInit(rawOption);\n    },\n\n    /**\n     * @protected\n     */\n    doInit: function (rawOption) {\n        var thisOption = this.option;\n\n        // Disable realtime view update if canvas is not supported.\n        if (!env$1.canvasSupported) {\n            thisOption.realtime = false;\n        }\n\n        this._setDefaultThrottle(rawOption);\n\n        updateRangeUse(this, rawOption);\n\n        each$12([['start', 'startValue'], ['end', 'endValue']], function (names, index) {\n            // start/end has higher priority over startValue/endValue if they\n            // both set, but we should make chart.setOption({endValue: 1000})\n            // effective, rather than chart.setOption({endValue: 1000, end: null}).\n            if (this._rangePropMode[index] === 'value') {\n                thisOption[names[0]] = null;\n            }\n            // Otherwise do nothing and use the merge result.\n        }, this);\n\n        this.textStyleModel = this.getModel('textStyle');\n\n        this._resetTarget();\n\n        this._giveAxisProxies();\n    },\n\n    /**\n     * @private\n     */\n    _giveAxisProxies: function () {\n        var axisProxies = this._axisProxies;\n\n        this.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel, ecModel) {\n            var axisModel = this.dependentModels[dimNames.axis][axisIndex];\n\n            // If exists, share axisProxy with other dataZoomModels.\n            var axisProxy = axisModel.__dzAxisProxy || (\n                // Use the first dataZoomModel as the main model of axisProxy.\n                axisModel.__dzAxisProxy = new AxisProxy(\n                    dimNames.name, axisIndex, this, ecModel\n                )\n            );\n            // FIXME\n            // dispose __dzAxisProxy\n\n            axisProxies[dimNames.name + '_' + axisIndex] = axisProxy;\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _resetTarget: function () {\n        var thisOption = this.option;\n\n        var autoMode = this._judgeAutoMode();\n\n        eachAxisDim(function (dimNames) {\n            var axisIndexName = dimNames.axisIndex;\n            thisOption[axisIndexName] = normalizeToArray(\n                thisOption[axisIndexName]\n            );\n        }, this);\n\n        if (autoMode === 'axisIndex') {\n            this._autoSetAxisIndex();\n        }\n        else if (autoMode === 'orient') {\n            this._autoSetOrient();\n        }\n    },\n\n    /**\n     * @private\n     */\n    _judgeAutoMode: function () {\n        // Auto set only works for setOption at the first time.\n        // The following is user's reponsibility. So using merged\n        // option is OK.\n        var thisOption = this.option;\n\n        var hasIndexSpecified = false;\n        eachAxisDim(function (dimNames) {\n            // When user set axisIndex as a empty array, we think that user specify axisIndex\n            // but do not want use auto mode. Because empty array may be encountered when\n            // some error occured.\n            if (thisOption[dimNames.axisIndex] != null) {\n                hasIndexSpecified = true;\n            }\n        }, this);\n\n        var orient = thisOption.orient;\n\n        if (orient == null && hasIndexSpecified) {\n            return 'orient';\n        }\n        else if (!hasIndexSpecified) {\n            if (orient == null) {\n                thisOption.orient = 'horizontal';\n            }\n            return 'axisIndex';\n        }\n    },\n\n    /**\n     * @private\n     */\n    _autoSetAxisIndex: function () {\n        var autoAxisIndex = true;\n        var orient = this.get('orient', true);\n        var thisOption = this.option;\n        var dependentModels = this.dependentModels;\n\n        if (autoAxisIndex) {\n            // Find axis that parallel to dataZoom as default.\n            var dimName = orient === 'vertical' ? 'y' : 'x';\n\n            if (dependentModels[dimName + 'Axis'].length) {\n                thisOption[dimName + 'AxisIndex'] = [0];\n                autoAxisIndex = false;\n            }\n            else {\n                each$12(dependentModels.singleAxis, function (singleAxisModel) {\n                    if (autoAxisIndex && singleAxisModel.get('orient', true) === orient) {\n                        thisOption.singleAxisIndex = [singleAxisModel.componentIndex];\n                        autoAxisIndex = false;\n                    }\n                });\n            }\n        }\n\n        if (autoAxisIndex) {\n            // Find the first category axis as default. (consider polar)\n            eachAxisDim(function (dimNames) {\n                if (!autoAxisIndex) {\n                    return;\n                }\n                var axisIndices = [];\n                var axisModels = this.dependentModels[dimNames.axis];\n                if (axisModels.length && !axisIndices.length) {\n                    for (var i = 0, len = axisModels.length; i < len; i++) {\n                        if (axisModels[i].get('type') === 'category') {\n                            axisIndices.push(i);\n                        }\n                    }\n                }\n                thisOption[dimNames.axisIndex] = axisIndices;\n                if (axisIndices.length) {\n                    autoAxisIndex = false;\n                }\n            }, this);\n        }\n\n        if (autoAxisIndex) {\n            // FIXME\n            // 这里是兼容ec2的写法（没指定xAxisIndex和yAxisIndex时把scatter和双数值轴折柱纳入dataZoom控制），\n            // 但是实际是否需要Grid.js#getScaleByOption来判断（考虑time，log等axis type）？\n\n            // If both dataZoom.xAxisIndex and dataZoom.yAxisIndex is not specified,\n            // dataZoom component auto adopts series that reference to\n            // both xAxis and yAxis which type is 'value'.\n            this.ecModel.eachSeries(function (seriesModel) {\n                if (this._isSeriesHasAllAxesTypeOf(seriesModel, 'value')) {\n                    eachAxisDim(function (dimNames) {\n                        var axisIndices = thisOption[dimNames.axisIndex];\n\n                        var axisIndex = seriesModel.get(dimNames.axisIndex);\n                        var axisId = seriesModel.get(dimNames.axisId);\n\n                        var axisModel = seriesModel.ecModel.queryComponents({\n                            mainType: dimNames.axis,\n                            index: axisIndex,\n                            id: axisId\n                        })[0];\n\n                        if (__DEV__) {\n                            if (!axisModel) {\n                                throw new Error(\n                                    dimNames.axis + ' \"' + retrieve(\n                                        axisIndex,\n                                        axisId,\n                                        0\n                                    ) + '\" not found'\n                                );\n                            }\n                        }\n                        axisIndex = axisModel.componentIndex;\n\n                        if (indexOf(axisIndices, axisIndex) < 0) {\n                            axisIndices.push(axisIndex);\n                        }\n                    });\n                }\n            }, this);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _autoSetOrient: function () {\n        var dim;\n\n        // Find the first axis\n        this.eachTargetAxis(function (dimNames) {\n            !dim && (dim = dimNames.name);\n        }, this);\n\n        this.option.orient = dim === 'y' ? 'vertical' : 'horizontal';\n    },\n\n    /**\n     * @private\n     */\n    _isSeriesHasAllAxesTypeOf: function (seriesModel, axisType) {\n        // FIXME\n        // 需要series的xAxisIndex和yAxisIndex都首先自动设置上。\n        // 例如series.type === scatter时。\n\n        var is = true;\n        eachAxisDim(function (dimNames) {\n            var seriesAxisIndex = seriesModel.get(dimNames.axisIndex);\n            var axisModel = this.dependentModels[dimNames.axis][seriesAxisIndex];\n\n            if (!axisModel || axisModel.get('type') !== axisType) {\n                is = false;\n            }\n        }, this);\n        return is;\n    },\n\n    /**\n     * @private\n     */\n    _setDefaultThrottle: function (rawOption) {\n        // When first time user set throttle, auto throttle ends.\n        if (rawOption.hasOwnProperty('throttle')) {\n            this._autoThrottle = false;\n        }\n        if (this._autoThrottle) {\n            var globalOption = this.ecModel.option;\n            this.option.throttle\n                = (globalOption.animation && globalOption.animationDurationUpdate > 0)\n                ? 100 : 20;\n        }\n    },\n\n    /**\n     * @public\n     */\n    getFirstTargetAxisModel: function () {\n        var firstAxisModel;\n        eachAxisDim(function (dimNames) {\n            if (firstAxisModel == null) {\n                var indices = this.get(dimNames.axisIndex);\n                if (indices.length) {\n                    firstAxisModel = this.dependentModels[dimNames.axis][indices[0]];\n                }\n            }\n        }, this);\n\n        return firstAxisModel;\n    },\n\n    /**\n     * @public\n     * @param {Function} callback param: axisModel, dimNames, axisIndex, dataZoomModel, ecModel\n     */\n    eachTargetAxis: function (callback, context) {\n        var ecModel = this.ecModel;\n        eachAxisDim(function (dimNames) {\n            each$12(\n                this.get(dimNames.axisIndex),\n                function (axisIndex) {\n                    callback.call(context, dimNames, axisIndex, this, ecModel);\n                },\n                this\n            );\n        }, this);\n    },\n\n    /**\n     * @param {string} dimName\n     * @param {number} axisIndex\n     * @return {module:echarts/component/dataZoom/AxisProxy} If not found, return null/undefined.\n     */\n    getAxisProxy: function (dimName, axisIndex) {\n        return this._axisProxies[dimName + '_' + axisIndex];\n    },\n\n    /**\n     * @param {string} dimName\n     * @param {number} axisIndex\n     * @return {module:echarts/model/Model} If not found, return null/undefined.\n     */\n    getAxisModel: function (dimName, axisIndex) {\n        var axisProxy = this.getAxisProxy(dimName, axisIndex);\n        return axisProxy && axisProxy.getAxisModel();\n    },\n\n    /**\n     * If not specified, set to undefined.\n     *\n     * @public\n     * @param {Object} opt\n     * @param {number} [opt.start]\n     * @param {number} [opt.end]\n     * @param {number} [opt.startValue]\n     * @param {number} [opt.endValue]\n     * @param {boolean} [ignoreUpdateRangeUsg=false]\n     */\n    setRawRange: function (opt, ignoreUpdateRangeUsg) {\n        var option = this.option;\n        each$12([['start', 'startValue'], ['end', 'endValue']], function (names) {\n            // If only one of 'start' and 'startValue' is not null/undefined, the other\n            // should be cleared, which enable clear the option.\n            // If both of them are not set, keep option with the original value, which\n            // enable use only set start but not set end when calling `dispatchAction`.\n            // The same as 'end' and 'endValue'.\n            if (opt[names[0]] != null || opt[names[1]] != null) {\n                option[names[0]] = opt[names[0]];\n                option[names[1]] = opt[names[1]];\n            }\n        }, this);\n\n        !ignoreUpdateRangeUsg && updateRangeUse(this, opt);\n    },\n\n    /**\n     * @public\n     * @return {Array.<number>} [startPercent, endPercent]\n     */\n    getPercentRange: function () {\n        var axisProxy = this.findRepresentativeAxisProxy();\n        if (axisProxy) {\n            return axisProxy.getDataPercentWindow();\n        }\n    },\n\n    /**\n     * @public\n     * For example, chart.getModel().getComponent('dataZoom').getValueRange('y', 0);\n     *\n     * @param {string} [axisDimName]\n     * @param {number} [axisIndex]\n     * @return {Array.<number>} [startValue, endValue] value can only be '-' or finite number.\n     */\n    getValueRange: function (axisDimName, axisIndex) {\n        if (axisDimName == null && axisIndex == null) {\n            var axisProxy = this.findRepresentativeAxisProxy();\n            if (axisProxy) {\n                return axisProxy.getDataValueWindow();\n            }\n        }\n        else {\n            return this.getAxisProxy(axisDimName, axisIndex).getDataValueWindow();\n        }\n    },\n\n    /**\n     * @public\n     * @param {module:echarts/model/Model} [axisModel] If axisModel given, find axisProxy\n     *      corresponding to the axisModel\n     * @return {module:echarts/component/dataZoom/AxisProxy}\n     */\n    findRepresentativeAxisProxy: function (axisModel) {\n        if (axisModel) {\n            return axisModel.__dzAxisProxy;\n        }\n\n        // Find the first hosted axisProxy\n        var axisProxies = this._axisProxies;\n        for (var key in axisProxies) {\n            if (axisProxies.hasOwnProperty(key) && axisProxies[key].hostedBy(this)) {\n                return axisProxies[key];\n            }\n        }\n\n        // If no hosted axis find not hosted axisProxy.\n        // Consider this case: dataZoomModel1 and dataZoomModel2 control the same axis,\n        // and the option.start or option.end settings are different. The percentRange\n        // should follow axisProxy.\n        // (We encounter this problem in toolbox data zoom.)\n        for (var key in axisProxies) {\n            if (axisProxies.hasOwnProperty(key) && !axisProxies[key].hostedBy(this)) {\n                return axisProxies[key];\n            }\n        }\n    },\n\n    /**\n     * @return {Array.<string>}\n     */\n    getRangePropMode: function () {\n        return this._rangePropMode.slice();\n    }\n\n});\n\nfunction retrieveRaw(option) {\n    var ret = {};\n    each$12(\n        ['start', 'end', 'startValue', 'endValue', 'throttle'],\n        function (name) {\n            option.hasOwnProperty(name) && (ret[name] = option[name]);\n        }\n    );\n    return ret;\n}\n\nfunction updateRangeUse(dataZoomModel, rawOption) {\n    var rangePropMode = dataZoomModel._rangePropMode;\n    var rangeModeInOption = dataZoomModel.get('rangeMode');\n\n    each$12([['start', 'startValue'], ['end', 'endValue']], function (names, index) {\n        var percentSpecified = rawOption[names[0]] != null;\n        var valueSpecified = rawOption[names[1]] != null;\n        if (percentSpecified && !valueSpecified) {\n            rangePropMode[index] = 'percent';\n        }\n        else if (!percentSpecified && valueSpecified) {\n            rangePropMode[index] = 'value';\n        }\n        else if (rangeModeInOption) {\n            rangePropMode[index] = rangeModeInOption[index];\n        }\n        else if (percentSpecified) { // percentSpecified && valueSpecified\n            rangePropMode[index] = 'percent';\n        }\n        // else remain its original setting.\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DataZoomView = Component$1.extend({\n\n    type: 'dataZoom',\n\n    render: function (dataZoomModel, ecModel, api, payload) {\n        this.dataZoomModel = dataZoomModel;\n        this.ecModel = ecModel;\n        this.api = api;\n    },\n\n    /**\n     * Find the first target coordinate system.\n     *\n     * @protected\n     * @return {Object} {\n     *                   grid: [\n     *                       {model: coord0, axisModels: [axis1, axis3], coordIndex: 1},\n     *                       {model: coord1, axisModels: [axis0, axis2], coordIndex: 0},\n     *                       ...\n     *                   ],  // cartesians must not be null/undefined.\n     *                   polar: [\n     *                       {model: coord0, axisModels: [axis4], coordIndex: 0},\n     *                       ...\n     *                   ],  // polars must not be null/undefined.\n     *                   singleAxis: [\n     *                       {model: coord0, axisModels: [], coordIndex: 0}\n     *                   ]\n     */\n    getTargetCoordInfo: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var ecModel = this.ecModel;\n        var coordSysLists = {};\n\n        dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {\n            var axisModel = ecModel.getComponent(dimNames.axis, axisIndex);\n            if (axisModel) {\n                var coordModel = axisModel.getCoordSysModel();\n                coordModel && save(\n                    coordModel,\n                    axisModel,\n                    coordSysLists[coordModel.mainType] || (coordSysLists[coordModel.mainType] = []),\n                    coordModel.componentIndex\n                );\n            }\n        }, this);\n\n        function save(coordModel, axisModel, store, coordIndex) {\n            var item;\n            for (var i = 0; i < store.length; i++) {\n                if (store[i].model === coordModel) {\n                    item = store[i];\n                    break;\n                }\n            }\n            if (!item) {\n                store.push(item = {\n                    model: coordModel, axisModels: [], coordIndex: coordIndex\n                });\n            }\n            item.axisModels.push(axisModel);\n        }\n\n        return coordSysLists;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar SliderZoomModel = DataZoomModel.extend({\n\n    type: 'dataZoom.slider',\n\n    layoutMode: 'box',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        show: true,\n\n        // ph => placeholder. Using placehoder here because\n        // deault value can only be drived in view stage.\n        right: 'ph',  // Default align to grid rect.\n        top: 'ph',    // Default align to grid rect.\n        width: 'ph',  // Default align to grid rect.\n        height: 'ph', // Default align to grid rect.\n        left: null,   // Default align to grid rect.\n        bottom: null, // Default align to grid rect.\n\n        backgroundColor: 'rgba(47,69,84,0)',    // Background of slider zoom component.\n        // dataBackgroundColor: '#ddd',         // Background coor of data shadow and border of box,\n                                                // highest priority, remain for compatibility of\n                                                // previous version, but not recommended any more.\n        dataBackground: {\n            lineStyle: {\n                color: '#2f4554',\n                width: 0.5,\n                opacity: 0.3\n            },\n            areaStyle: {\n                color: 'rgba(47,69,84,0.3)',\n                opacity: 0.3\n            }\n        },\n        borderColor: '#ddd',                    // border color of the box. For compatibility,\n                                                // if dataBackgroundColor is set, borderColor\n                                                // is ignored.\n\n        fillerColor: 'rgba(167,183,204,0.4)',     // Color of selected area.\n        // handleColor: 'rgba(89,170,216,0.95)',     // Color of handle.\n        // handleIcon: 'path://M4.9,17.8c0-1.4,4.5-10.5,5.5-12.4c0-0.1,0.6-1.1,0.9-1.1c0.4,0,0.9,1,0.9,1.1c1.1,2.2,5.4,11,5.4,12.4v17.8c0,1.5-0.6,2.1-1.3,2.1H6.1c-0.7,0-1.3-0.6-1.3-2.1V17.8z',\n        /* eslint-disable */\n        handleIcon: 'M8.2,13.6V3.9H6.3v9.7H3.1v14.9h3.3v9.7h1.8v-9.7h3.3V13.6H8.2z M9.7,24.4H4.8v-1.4h4.9V24.4z M9.7,19.1H4.8v-1.4h4.9V19.1z',\n        /* eslint-enable */\n        // Percent of the slider height\n        handleSize: '100%',\n\n        handleStyle: {\n            color: '#a7b7cc'\n        },\n\n        labelPrecision: null,\n        labelFormatter: null,\n        showDetail: true,\n        showDataShadow: 'auto',                 // Default auto decision.\n        realtime: true,\n        zoomLock: false,                        // Whether disable zoom.\n        textStyle: {\n            color: '#333'\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Calculate slider move result.\n * Usage:\n * (1) If both handle0 and handle1 are needed to be moved, set minSpan the same as\n * maxSpan and the same as `Math.abs(handleEnd[1] - handleEnds[0])`.\n * (2) If handle0 is forbidden to cross handle1, set minSpan as `0`.\n *\n * @param {number} delta Move length.\n * @param {Array.<number>} handleEnds handleEnds[0] can be bigger then handleEnds[1].\n *              handleEnds will be modified in this method.\n * @param {Array.<number>} extent handleEnds is restricted by extent.\n *              extent[0] should less or equals than extent[1].\n * @param {number|string} handleIndex Can be 'all', means that both move the two handleEnds,\n *              where the input minSpan and maxSpan will not work.\n * @param {number} [minSpan] The range of dataZoom can not be smaller than that.\n *              If not set, handle0 and cross handle1. If set as a non-negative\n *              number (including `0`), handles will push each other when reaching\n *              the minSpan.\n * @param {number} [maxSpan] The range of dataZoom can not be larger than that.\n * @return {Array.<number>} The input handleEnds.\n */\nvar sliderMove = function (delta, handleEnds, extent, handleIndex, minSpan, maxSpan) {\n    // Normalize firstly.\n    handleEnds[0] = restrict(handleEnds[0], extent);\n    handleEnds[1] = restrict(handleEnds[1], extent);\n\n    delta = delta || 0;\n\n    var extentSpan = extent[1] - extent[0];\n\n    // Notice maxSpan and minSpan can be null/undefined.\n    if (minSpan != null) {\n        minSpan = restrict(minSpan, [0, extentSpan]);\n    }\n    if (maxSpan != null) {\n        maxSpan = Math.max(maxSpan, minSpan != null ? minSpan : 0);\n    }\n    if (handleIndex === 'all') {\n        minSpan = maxSpan = Math.abs(handleEnds[1] - handleEnds[0]);\n        handleIndex = 0;\n    }\n\n    var originalDistSign = getSpanSign(handleEnds, handleIndex);\n\n    handleEnds[handleIndex] += delta;\n\n    // Restrict in extent.\n    var extentMinSpan = minSpan || 0;\n    var realExtent = extent.slice();\n    originalDistSign.sign < 0 ? (realExtent[0] += extentMinSpan) : (realExtent[1] -= extentMinSpan);\n    handleEnds[handleIndex] = restrict(handleEnds[handleIndex], realExtent);\n\n    // Expand span.\n    var currDistSign = getSpanSign(handleEnds, handleIndex);\n    if (minSpan != null && (\n        currDistSign.sign !== originalDistSign.sign || currDistSign.span < minSpan\n    )) {\n        // If minSpan exists, 'cross' is forbinden.\n        handleEnds[1 - handleIndex] = handleEnds[handleIndex] + originalDistSign.sign * minSpan;\n    }\n\n    // Shrink span.\n    var currDistSign = getSpanSign(handleEnds, handleIndex);\n    if (maxSpan != null && currDistSign.span > maxSpan) {\n        handleEnds[1 - handleIndex] = handleEnds[handleIndex] + currDistSign.sign * maxSpan;\n    }\n\n    return handleEnds;\n};\n\nfunction getSpanSign(handleEnds, handleIndex) {\n    var dist = handleEnds[handleIndex] - handleEnds[1 - handleIndex];\n    // If `handleEnds[0] === handleEnds[1]`, always believe that handleEnd[0]\n    // is at left of handleEnds[1] for non-cross case.\n    return {span: Math.abs(dist), sign: dist > 0 ? -1 : dist < 0 ? 1 : handleIndex ? -1 : 1};\n}\n\nfunction restrict(value, extend) {\n    return Math.min(extend[1], Math.max(extend[0], value));\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar Rect$1 = Rect;\nvar linearMap$1 = linearMap;\nvar asc$2 = asc;\nvar bind$3 = bind;\nvar each$14 = each$1;\n\n// Constants\nvar DEFAULT_LOCATION_EDGE_GAP = 7;\nvar DEFAULT_FRAME_BORDER_WIDTH = 1;\nvar DEFAULT_FILLER_SIZE = 30;\nvar HORIZONTAL = 'horizontal';\nvar VERTICAL = 'vertical';\nvar LABEL_GAP = 5;\nvar SHOW_DATA_SHADOW_SERIES_TYPE = ['line', 'bar', 'candlestick', 'scatter'];\n\nvar SliderZoomView = DataZoomView.extend({\n\n    type: 'dataZoom.slider',\n\n    init: function (ecModel, api) {\n\n        /**\n         * @private\n         * @type {Object}\n         */\n        this._displayables = {};\n\n        /**\n         * @private\n         * @type {string}\n         */\n        this._orient;\n\n        /**\n         * [0, 100]\n         * @private\n         */\n        this._range;\n\n        /**\n         * [coord of the first handle, coord of the second handle]\n         * @private\n         */\n        this._handleEnds;\n\n        /**\n         * [length, thick]\n         * @private\n         * @type {Array.<number>}\n         */\n        this._size;\n\n        /**\n         * @private\n         * @type {number}\n         */\n        this._handleWidth;\n\n        /**\n         * @private\n         * @type {number}\n         */\n        this._handleHeight;\n\n        /**\n         * @private\n         */\n        this._location;\n\n        /**\n         * @private\n         */\n        this._dragging;\n\n        /**\n         * @private\n         */\n        this._dataShadowInfo;\n\n        this.api = api;\n    },\n\n    /**\n     * @override\n     */\n    render: function (dataZoomModel, ecModel, api, payload) {\n        SliderZoomView.superApply(this, 'render', arguments);\n\n        createOrUpdate(\n            this,\n            '_dispatchZoomAction',\n            this.dataZoomModel.get('throttle'),\n            'fixRate'\n        );\n\n        this._orient = dataZoomModel.get('orient');\n\n        if (this.dataZoomModel.get('show') === false) {\n            this.group.removeAll();\n            return;\n        }\n\n        // Notice: this._resetInterval() should not be executed when payload.type\n        // is 'dataZoom', origin this._range should be maintained, otherwise 'pan'\n        // or 'zoom' info will be missed because of 'throttle' of this.dispatchAction,\n        if (!payload || payload.type !== 'dataZoom' || payload.from !== this.uid) {\n            this._buildView();\n        }\n\n        this._updateView();\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        SliderZoomView.superApply(this, 'remove', arguments);\n        clear(this, '_dispatchZoomAction');\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        SliderZoomView.superApply(this, 'dispose', arguments);\n        clear(this, '_dispatchZoomAction');\n    },\n\n    _buildView: function () {\n        var thisGroup = this.group;\n\n        thisGroup.removeAll();\n\n        this._resetLocation();\n        this._resetInterval();\n\n        var barGroup = this._displayables.barGroup = new Group();\n\n        this._renderBackground();\n\n        this._renderHandle();\n\n        this._renderDataShadow();\n\n        thisGroup.add(barGroup);\n\n        this._positionGroup();\n    },\n\n    /**\n     * @private\n     */\n    _resetLocation: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var api = this.api;\n\n        // If some of x/y/width/height are not specified,\n        // auto-adapt according to target grid.\n        var coordRect = this._findCoordRect();\n        var ecSize = {width: api.getWidth(), height: api.getHeight()};\n        // Default align by coordinate system rect.\n        var positionInfo = this._orient === HORIZONTAL\n            ? {\n                // Why using 'right', because right should be used in vertical,\n                // and it is better to be consistent for dealing with position param merge.\n                right: ecSize.width - coordRect.x - coordRect.width,\n                top: (ecSize.height - DEFAULT_FILLER_SIZE - DEFAULT_LOCATION_EDGE_GAP),\n                width: coordRect.width,\n                height: DEFAULT_FILLER_SIZE\n            }\n            : { // vertical\n                right: DEFAULT_LOCATION_EDGE_GAP,\n                top: coordRect.y,\n                width: DEFAULT_FILLER_SIZE,\n                height: coordRect.height\n            };\n\n        // Do not write back to option and replace value 'ph', because\n        // the 'ph' value should be recalculated when resize.\n        var layoutParams = getLayoutParams(dataZoomModel.option);\n\n        // Replace the placeholder value.\n        each$1(['right', 'top', 'width', 'height'], function (name) {\n            if (layoutParams[name] === 'ph') {\n                layoutParams[name] = positionInfo[name];\n            }\n        });\n\n        var layoutRect = getLayoutRect(\n            layoutParams,\n            ecSize,\n            dataZoomModel.padding\n        );\n\n        this._location = {x: layoutRect.x, y: layoutRect.y};\n        this._size = [layoutRect.width, layoutRect.height];\n        this._orient === VERTICAL && this._size.reverse();\n    },\n\n    /**\n     * @private\n     */\n    _positionGroup: function () {\n        var thisGroup = this.group;\n        var location = this._location;\n        var orient = this._orient;\n\n        // Just use the first axis to determine mapping.\n        var targetAxisModel = this.dataZoomModel.getFirstTargetAxisModel();\n        var inverse = targetAxisModel && targetAxisModel.get('inverse');\n\n        var barGroup = this._displayables.barGroup;\n        var otherAxisInverse = (this._dataShadowInfo || {}).otherAxisInverse;\n\n        // Transform barGroup.\n        barGroup.attr(\n            (orient === HORIZONTAL && !inverse)\n            ? {scale: otherAxisInverse ? [1, 1] : [1, -1]}\n            : (orient === HORIZONTAL && inverse)\n            ? {scale: otherAxisInverse ? [-1, 1] : [-1, -1]}\n            : (orient === VERTICAL && !inverse)\n            ? {scale: otherAxisInverse ? [1, -1] : [1, 1], rotation: Math.PI / 2}\n            // Dont use Math.PI, considering shadow direction.\n            : {scale: otherAxisInverse ? [-1, -1] : [-1, 1], rotation: Math.PI / 2}\n        );\n\n        // Position barGroup\n        var rect = thisGroup.getBoundingRect([barGroup]);\n        thisGroup.attr('position', [location.x - rect.x, location.y - rect.y]);\n    },\n\n    /**\n     * @private\n     */\n    _getViewExtent: function () {\n        return [0, this._size[0]];\n    },\n\n    _renderBackground: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var size = this._size;\n        var barGroup = this._displayables.barGroup;\n\n        barGroup.add(new Rect$1({\n            silent: true,\n            shape: {\n                x: 0, y: 0, width: size[0], height: size[1]\n            },\n            style: {\n                fill: dataZoomModel.get('backgroundColor')\n            },\n            z2: -40\n        }));\n\n        // Click panel, over shadow, below handles.\n        barGroup.add(new Rect$1({\n            shape: {\n                x: 0, y: 0, width: size[0], height: size[1]\n            },\n            style: {\n                fill: 'transparent'\n            },\n            z2: 0,\n            onclick: bind(this._onClickPanelClick, this)\n        }));\n    },\n\n    _renderDataShadow: function () {\n        var info = this._dataShadowInfo = this._prepareDataShadowInfo();\n\n        if (!info) {\n            return;\n        }\n\n        var size = this._size;\n        var seriesModel = info.series;\n        var data = seriesModel.getRawData();\n\n        var otherDim = seriesModel.getShadowDim\n            ? seriesModel.getShadowDim() // @see candlestick\n            : info.otherDim;\n\n        if (otherDim == null) {\n            return;\n        }\n\n        var otherDataExtent = data.getDataExtent(otherDim);\n        // Nice extent.\n        var otherOffset = (otherDataExtent[1] - otherDataExtent[0]) * 0.3;\n        otherDataExtent = [\n            otherDataExtent[0] - otherOffset,\n            otherDataExtent[1] + otherOffset\n        ];\n        var otherShadowExtent = [0, size[1]];\n\n        var thisShadowExtent = [0, size[0]];\n\n        var areaPoints = [[size[0], 0], [0, 0]];\n        var linePoints = [];\n        var step = thisShadowExtent[1] / (data.count() - 1);\n        var thisCoord = 0;\n\n        // Optimize for large data shadow\n        var stride = Math.round(data.count() / size[0]);\n        var lastIsEmpty;\n        data.each([otherDim], function (value, index) {\n            if (stride > 0 && (index % stride)) {\n                thisCoord += step;\n                return;\n            }\n\n            // FIXME\n            // Should consider axis.min/axis.max when drawing dataShadow.\n\n            // FIXME\n            // 应该使用统一的空判断？还是在list里进行空判断？\n            var isEmpty = value == null || isNaN(value) || value === '';\n            // See #4235.\n            var otherCoord = isEmpty\n                ? 0 : linearMap$1(value, otherDataExtent, otherShadowExtent, true);\n\n            // Attempt to draw data shadow precisely when there are empty value.\n            if (isEmpty && !lastIsEmpty && index) {\n                areaPoints.push([areaPoints[areaPoints.length - 1][0], 0]);\n                linePoints.push([linePoints[linePoints.length - 1][0], 0]);\n            }\n            else if (!isEmpty && lastIsEmpty) {\n                areaPoints.push([thisCoord, 0]);\n                linePoints.push([thisCoord, 0]);\n            }\n\n            areaPoints.push([thisCoord, otherCoord]);\n            linePoints.push([thisCoord, otherCoord]);\n\n            thisCoord += step;\n            lastIsEmpty = isEmpty;\n        });\n\n        var dataZoomModel = this.dataZoomModel;\n        // var dataBackgroundModel = dataZoomModel.getModel('dataBackground');\n        this._displayables.barGroup.add(new Polygon({\n            shape: {points: areaPoints},\n            style: defaults(\n                {fill: dataZoomModel.get('dataBackgroundColor')},\n                dataZoomModel.getModel('dataBackground.areaStyle').getAreaStyle()\n            ),\n            silent: true,\n            z2: -20\n        }));\n        this._displayables.barGroup.add(new Polyline({\n            shape: {points: linePoints},\n            style: dataZoomModel.getModel('dataBackground.lineStyle').getLineStyle(),\n            silent: true,\n            z2: -19\n        }));\n    },\n\n    _prepareDataShadowInfo: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var showDataShadow = dataZoomModel.get('showDataShadow');\n\n        if (showDataShadow === false) {\n            return;\n        }\n\n        // Find a representative series.\n        var result;\n        var ecModel = this.ecModel;\n\n        dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {\n            var seriesModels = dataZoomModel\n                .getAxisProxy(dimNames.name, axisIndex)\n                .getTargetSeriesModels();\n\n            each$1(seriesModels, function (seriesModel) {\n                if (result) {\n                    return;\n                }\n\n                if (showDataShadow !== true && indexOf(\n                        SHOW_DATA_SHADOW_SERIES_TYPE, seriesModel.get('type')\n                    ) < 0\n                ) {\n                    return;\n                }\n\n                var thisAxis = ecModel.getComponent(dimNames.axis, axisIndex).axis;\n                var otherDim = getOtherDim(dimNames.name);\n                var otherAxisInverse;\n                var coordSys = seriesModel.coordinateSystem;\n\n                if (otherDim != null && coordSys.getOtherAxis) {\n                    otherAxisInverse = coordSys.getOtherAxis(thisAxis).inverse;\n                }\n\n                otherDim = seriesModel.getData().mapDimension(otherDim);\n\n                result = {\n                    thisAxis: thisAxis,\n                    series: seriesModel,\n                    thisDim: dimNames.name,\n                    otherDim: otherDim,\n                    otherAxisInverse: otherAxisInverse\n                };\n\n            }, this);\n\n        }, this);\n\n        return result;\n    },\n\n    _renderHandle: function () {\n        var displaybles = this._displayables;\n        var handles = displaybles.handles = [];\n        var handleLabels = displaybles.handleLabels = [];\n        var barGroup = this._displayables.barGroup;\n        var size = this._size;\n        var dataZoomModel = this.dataZoomModel;\n\n        barGroup.add(displaybles.filler = new Rect$1({\n            draggable: true,\n            cursor: getCursor(this._orient),\n            drift: bind$3(this._onDragMove, this, 'all'),\n            onmousemove: function (e) {\n                // Fot mobile devicem, prevent screen slider on the button.\n                stop(e.event);\n            },\n            ondragstart: bind$3(this._showDataInfo, this, true),\n            ondragend: bind$3(this._onDragEnd, this),\n            onmouseover: bind$3(this._showDataInfo, this, true),\n            onmouseout: bind$3(this._showDataInfo, this, false),\n            style: {\n                fill: dataZoomModel.get('fillerColor'),\n                textPosition: 'inside'\n            }\n        }));\n\n        // Frame border.\n        barGroup.add(new Rect$1(subPixelOptimizeRect({\n            silent: true,\n            shape: {\n                x: 0,\n                y: 0,\n                width: size[0],\n                height: size[1]\n            },\n            style: {\n                stroke: dataZoomModel.get('dataBackgroundColor')\n                    || dataZoomModel.get('borderColor'),\n                lineWidth: DEFAULT_FRAME_BORDER_WIDTH,\n                fill: 'rgba(0,0,0,0)'\n            }\n        })));\n\n        each$14([0, 1], function (handleIndex) {\n            var path = createIcon(\n                dataZoomModel.get('handleIcon'),\n                {\n                    cursor: getCursor(this._orient),\n                    draggable: true,\n                    drift: bind$3(this._onDragMove, this, handleIndex),\n                    onmousemove: function (e) {\n                        // Fot mobile devicem, prevent screen slider on the button.\n                        stop(e.event);\n                    },\n                    ondragend: bind$3(this._onDragEnd, this),\n                    onmouseover: bind$3(this._showDataInfo, this, true),\n                    onmouseout: bind$3(this._showDataInfo, this, false)\n                },\n                {x: -1, y: 0, width: 2, height: 2}\n            );\n\n            var bRect = path.getBoundingRect();\n            this._handleHeight = parsePercent$1(dataZoomModel.get('handleSize'), this._size[1]);\n            this._handleWidth = bRect.width / bRect.height * this._handleHeight;\n\n            path.setStyle(dataZoomModel.getModel('handleStyle').getItemStyle());\n            var handleColor = dataZoomModel.get('handleColor');\n            // Compatitable with previous version\n            if (handleColor != null) {\n                path.style.fill = handleColor;\n            }\n\n            barGroup.add(handles[handleIndex] = path);\n\n            var textStyleModel = dataZoomModel.textStyleModel;\n\n            this.group.add(\n                handleLabels[handleIndex] = new Text({\n                silent: true,\n                invisible: true,\n                style: {\n                    x: 0, y: 0, text: '',\n                    textVerticalAlign: 'middle',\n                    textAlign: 'center',\n                    textFill: textStyleModel.getTextColor(),\n                    textFont: textStyleModel.getFont()\n                },\n                z2: 10\n            }));\n\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _resetInterval: function () {\n        var range = this._range = this.dataZoomModel.getPercentRange();\n        var viewExtent = this._getViewExtent();\n\n        this._handleEnds = [\n            linearMap$1(range[0], [0, 100], viewExtent, true),\n            linearMap$1(range[1], [0, 100], viewExtent, true)\n        ];\n    },\n\n    /**\n     * @private\n     * @param {(number|string)} handleIndex 0 or 1 or 'all'\n     * @param {number} delta\n     * @return {boolean} changed\n     */\n    _updateInterval: function (handleIndex, delta) {\n        var dataZoomModel = this.dataZoomModel;\n        var handleEnds = this._handleEnds;\n        var viewExtend = this._getViewExtent();\n        var minMaxSpan = dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan();\n        var percentExtent = [0, 100];\n\n        sliderMove(\n            delta,\n            handleEnds,\n            viewExtend,\n            dataZoomModel.get('zoomLock') ? 'all' : handleIndex,\n            minMaxSpan.minSpan != null\n                ? linearMap$1(minMaxSpan.minSpan, percentExtent, viewExtend, true) : null,\n            minMaxSpan.maxSpan != null\n                ? linearMap$1(minMaxSpan.maxSpan, percentExtent, viewExtend, true) : null\n        );\n\n        var lastRange = this._range;\n        var range = this._range = asc$2([\n            linearMap$1(handleEnds[0], viewExtend, percentExtent, true),\n            linearMap$1(handleEnds[1], viewExtend, percentExtent, true)\n        ]);\n\n        return !lastRange || lastRange[0] !== range[0] || lastRange[1] !== range[1];\n    },\n\n    /**\n     * @private\n     */\n    _updateView: function (nonRealtime) {\n        var displaybles = this._displayables;\n        var handleEnds = this._handleEnds;\n        var handleInterval = asc$2(handleEnds.slice());\n        var size = this._size;\n\n        each$14([0, 1], function (handleIndex) {\n            // Handles\n            var handle = displaybles.handles[handleIndex];\n            var handleHeight = this._handleHeight;\n            handle.attr({\n                scale: [handleHeight / 2, handleHeight / 2],\n                position: [handleEnds[handleIndex], size[1] / 2 - handleHeight / 2]\n            });\n        }, this);\n\n        // Filler\n        displaybles.filler.setShape({\n            x: handleInterval[0],\n            y: 0,\n            width: handleInterval[1] - handleInterval[0],\n            height: size[1]\n        });\n\n        this._updateDataInfo(nonRealtime);\n    },\n\n    /**\n     * @private\n     */\n    _updateDataInfo: function (nonRealtime) {\n        var dataZoomModel = this.dataZoomModel;\n        var displaybles = this._displayables;\n        var handleLabels = displaybles.handleLabels;\n        var orient = this._orient;\n        var labelTexts = ['', ''];\n\n        // FIXME\n        // date型，支持formatter，autoformatter（ec2 date.getAutoFormatter）\n        if (dataZoomModel.get('showDetail')) {\n            var axisProxy = dataZoomModel.findRepresentativeAxisProxy();\n\n            if (axisProxy) {\n                var axis = axisProxy.getAxisModel().axis;\n                var range = this._range;\n\n                var dataInterval = nonRealtime\n                    // See #4434, data and axis are not processed and reset yet in non-realtime mode.\n                    ? axisProxy.calculateDataWindow({\n                        start: range[0], end: range[1]\n                    }).valueWindow\n                    : axisProxy.getDataValueWindow();\n\n                labelTexts = [\n                    this._formatLabel(dataInterval[0], axis),\n                    this._formatLabel(dataInterval[1], axis)\n                ];\n            }\n        }\n\n        var orderedHandleEnds = asc$2(this._handleEnds.slice());\n\n        setLabel.call(this, 0);\n        setLabel.call(this, 1);\n\n        function setLabel(handleIndex) {\n            // Label\n            // Text should not transform by barGroup.\n            // Ignore handlers transform\n            var barTransform = getTransform(\n                displaybles.handles[handleIndex].parent, this.group\n            );\n            var direction = transformDirection(\n                handleIndex === 0 ? 'right' : 'left', barTransform\n            );\n            var offset = this._handleWidth / 2 + LABEL_GAP;\n            var textPoint = applyTransform$1(\n                [\n                    orderedHandleEnds[handleIndex] + (handleIndex === 0 ? -offset : offset),\n                    this._size[1] / 2\n                ],\n                barTransform\n            );\n            handleLabels[handleIndex].setStyle({\n                x: textPoint[0],\n                y: textPoint[1],\n                textVerticalAlign: orient === HORIZONTAL ? 'middle' : direction,\n                textAlign: orient === HORIZONTAL ? direction : 'center',\n                text: labelTexts[handleIndex]\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _formatLabel: function (value, axis) {\n        var dataZoomModel = this.dataZoomModel;\n        var labelFormatter = dataZoomModel.get('labelFormatter');\n\n        var labelPrecision = dataZoomModel.get('labelPrecision');\n        if (labelPrecision == null || labelPrecision === 'auto') {\n            labelPrecision = axis.getPixelPrecision();\n        }\n\n        var valueStr = (value == null || isNaN(value))\n            ? ''\n            // FIXME Glue code\n            : (axis.type === 'category' || axis.type === 'time')\n                ? axis.scale.getLabel(Math.round(value))\n                // param of toFixed should less then 20.\n                : value.toFixed(Math.min(labelPrecision, 20));\n\n        return isFunction$1(labelFormatter)\n            ? labelFormatter(value, valueStr)\n            : isString(labelFormatter)\n            ? labelFormatter.replace('{value}', valueStr)\n            : valueStr;\n    },\n\n    /**\n     * @private\n     * @param {boolean} showOrHide true: show, false: hide\n     */\n    _showDataInfo: function (showOrHide) {\n        // Always show when drgging.\n        showOrHide = this._dragging || showOrHide;\n\n        var handleLabels = this._displayables.handleLabels;\n        handleLabels[0].attr('invisible', !showOrHide);\n        handleLabels[1].attr('invisible', !showOrHide);\n    },\n\n    _onDragMove: function (handleIndex, dx, dy) {\n        this._dragging = true;\n\n        // Transform dx, dy to bar coordination.\n        var barTransform = this._displayables.barGroup.getLocalTransform();\n        var vertex = applyTransform$1([dx, dy], barTransform, true);\n\n        var changed = this._updateInterval(handleIndex, vertex[0]);\n\n        var realtime = this.dataZoomModel.get('realtime');\n\n        this._updateView(!realtime);\n\n        // Avoid dispatch dataZoom repeatly but range not changed,\n        // which cause bad visual effect when progressive enabled.\n        changed && realtime && this._dispatchZoomAction();\n    },\n\n    _onDragEnd: function () {\n        this._dragging = false;\n        this._showDataInfo(false);\n\n        // While in realtime mode and stream mode, dispatch action when\n        // drag end will cause the whole view rerender, which is unnecessary.\n        var realtime = this.dataZoomModel.get('realtime');\n        !realtime && this._dispatchZoomAction();\n    },\n\n    _onClickPanelClick: function (e) {\n        var size = this._size;\n        var localPoint = this._displayables.barGroup.transformCoordToLocal(e.offsetX, e.offsetY);\n\n        if (localPoint[0] < 0 || localPoint[0] > size[0]\n            || localPoint[1] < 0 || localPoint[1] > size[1]\n        ) {\n            return;\n        }\n\n        var handleEnds = this._handleEnds;\n        var center = (handleEnds[0] + handleEnds[1]) / 2;\n\n        var changed = this._updateInterval('all', localPoint[0] - center);\n        this._updateView();\n        changed && this._dispatchZoomAction();\n    },\n\n    /**\n     * This action will be throttled.\n     * @private\n     */\n    _dispatchZoomAction: function () {\n        var range = this._range;\n\n        this.api.dispatchAction({\n            type: 'dataZoom',\n            from: this.uid,\n            dataZoomId: this.dataZoomModel.id,\n            start: range[0],\n            end: range[1]\n        });\n    },\n\n    /**\n     * @private\n     */\n    _findCoordRect: function () {\n        // Find the grid coresponding to the first axis referred by dataZoom.\n        var rect;\n        each$14(this.getTargetCoordInfo(), function (coordInfoList) {\n            if (!rect && coordInfoList.length) {\n                var coordSys = coordInfoList[0].model.coordinateSystem;\n                rect = coordSys.getRect && coordSys.getRect();\n            }\n        });\n        if (!rect) {\n            var width = this.api.getWidth();\n            var height = this.api.getHeight();\n            rect = {\n                x: width * 0.2,\n                y: height * 0.2,\n                width: width * 0.6,\n                height: height * 0.6\n            };\n        }\n\n        return rect;\n    }\n\n});\n\nfunction getOtherDim(thisDim) {\n    // FIXME\n    // 这个逻辑和getOtherAxis里一致，但是写在这里是否不好\n    var map$$1 = {x: 'y', y: 'x', radius: 'angle', angle: 'radius'};\n    return map$$1[thisDim];\n}\n\nfunction getCursor(orient) {\n    return orient === 'vertical' ? 'ns-resize' : 'ew-resize';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomModel.extend({\n\n    type: 'dataZoom.inside',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        disabled: false,   // Whether disable this inside zoom.\n        zoomLock: false,   // Whether disable zoom but only pan.\n        zoomOnMouseWheel: true, // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        moveOnMouseMove: true,   // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        moveOnMouseWheel: false, // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        preventDefaultMouseMove: true\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ATTR$1 = '\\0_ec_interaction_mutex';\n\nfunction take(zr, resourceKey, userKey) {\n    var store = getStore(zr);\n    store[resourceKey] = userKey;\n}\n\nfunction release(zr, resourceKey, userKey) {\n    var store = getStore(zr);\n    var uKey = store[resourceKey];\n\n    if (uKey === userKey) {\n        store[resourceKey] = null;\n    }\n}\n\nfunction isTaken(zr, resourceKey) {\n    return !!getStore(zr)[resourceKey];\n}\n\nfunction getStore(zr) {\n    return zr[ATTR$1] || (zr[ATTR$1] = {});\n}\n\n/**\n * payload: {\n *     type: 'takeGlobalCursor',\n *     key: 'dataZoomSelect', or 'brush', or ...,\n *         If no userKey, release global cursor.\n * }\n */\nregisterAction(\n    {type: 'takeGlobalCursor', event: 'globalCursorTaken', update: 'update'},\n    function () {}\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @alias module:echarts/component/helper/RoamController\n * @constructor\n * @mixin {module:zrender/mixin/Eventful}\n *\n * @param {module:zrender/zrender~ZRender} zr\n */\nfunction RoamController(zr) {\n\n    /**\n     * @type {Function}\n     */\n    this.pointerChecker;\n\n    /**\n     * @type {module:zrender}\n     */\n    this._zr = zr;\n\n    /**\n     * @type {Object}\n     */\n    this._opt = {};\n\n    // Avoid two roamController bind the same handler\n    var bind$$1 = bind;\n    var mousedownHandler = bind$$1(mousedown, this);\n    var mousemoveHandler = bind$$1(mousemove, this);\n    var mouseupHandler = bind$$1(mouseup, this);\n    var mousewheelHandler = bind$$1(mousewheel, this);\n    var pinchHandler = bind$$1(pinch, this);\n\n    Eventful.call(this);\n\n    /**\n     * @param {Function} pointerChecker\n     *                   input: x, y\n     *                   output: boolean\n     */\n    this.setPointerChecker = function (pointerChecker) {\n        this.pointerChecker = pointerChecker;\n    };\n\n    /**\n     * Notice: only enable needed types. For example, if 'zoom'\n     * is not needed, 'zoom' should not be enabled, otherwise\n     * default mousewheel behaviour (scroll page) will be disabled.\n     *\n     * @param  {boolean|string} [controlType=true] Specify the control type,\n     *                          which can be null/undefined or true/false\n     *                          or 'pan/move' or 'zoom'/'scale'\n     * @param {Object} [opt]\n     * @param {Object} [opt.zoomOnMouseWheel=true] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.moveOnMouseMove=true] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.moveOnMouseWheel=false] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.preventDefaultMouseMove=true] When pan.\n     */\n    this.enable = function (controlType, opt) {\n\n        // Disable previous first\n        this.disable();\n\n        this._opt = defaults(clone(opt) || {}, {\n            zoomOnMouseWheel: true,\n            moveOnMouseMove: true,\n            // By default, wheel do not trigger move.\n            moveOnMouseWheel: false,\n            preventDefaultMouseMove: true\n        });\n\n        if (controlType == null) {\n            controlType = true;\n        }\n\n        if (controlType === true || (controlType === 'move' || controlType === 'pan')) {\n            zr.on('mousedown', mousedownHandler);\n            zr.on('mousemove', mousemoveHandler);\n            zr.on('mouseup', mouseupHandler);\n        }\n        if (controlType === true || (controlType === 'scale' || controlType === 'zoom')) {\n            zr.on('mousewheel', mousewheelHandler);\n            zr.on('pinch', pinchHandler);\n        }\n    };\n\n    this.disable = function () {\n        zr.off('mousedown', mousedownHandler);\n        zr.off('mousemove', mousemoveHandler);\n        zr.off('mouseup', mouseupHandler);\n        zr.off('mousewheel', mousewheelHandler);\n        zr.off('pinch', pinchHandler);\n    };\n\n    this.dispose = this.disable;\n\n    this.isDragging = function () {\n        return this._dragging;\n    };\n\n    this.isPinching = function () {\n        return this._pinching;\n    };\n}\n\nmixin(RoamController, Eventful);\n\n\nfunction mousedown(e) {\n    if (isMiddleOrRightButtonOnMouseUpDown(e)\n        || (e.target && e.target.draggable)\n    ) {\n        return;\n    }\n\n    var x = e.offsetX;\n    var y = e.offsetY;\n\n    // Only check on mosedown, but not mousemove.\n    // Mouse can be out of target when mouse moving.\n    if (this.pointerChecker && this.pointerChecker(e, x, y)) {\n        this._x = x;\n        this._y = y;\n        this._dragging = true;\n    }\n}\n\nfunction mousemove(e) {\n    if (!this._dragging\n        || !isAvailableBehavior('moveOnMouseMove', e, this._opt)\n        || e.gestureEvent === 'pinch'\n        || isTaken(this._zr, 'globalPan')\n    ) {\n        return;\n    }\n\n    var x = e.offsetX;\n    var y = e.offsetY;\n\n    var oldX = this._x;\n    var oldY = this._y;\n\n    var dx = x - oldX;\n    var dy = y - oldY;\n\n    this._x = x;\n    this._y = y;\n\n    this._opt.preventDefaultMouseMove && stop(e.event);\n\n    trigger(this, 'pan', 'moveOnMouseMove', e, {\n        dx: dx, dy: dy, oldX: oldX, oldY: oldY, newX: x, newY: y\n    });\n}\n\nfunction mouseup(e) {\n    if (!isMiddleOrRightButtonOnMouseUpDown(e)) {\n        this._dragging = false;\n    }\n}\n\nfunction mousewheel(e) {\n    var shouldZoom = isAvailableBehavior('zoomOnMouseWheel', e, this._opt);\n    var shouldMove = isAvailableBehavior('moveOnMouseWheel', e, this._opt);\n    var wheelDelta = e.wheelDelta;\n    var absWheelDeltaDelta = Math.abs(wheelDelta);\n    var originX = e.offsetX;\n    var originY = e.offsetY;\n\n    // wheelDelta maybe -0 in chrome mac.\n    if (wheelDelta === 0 || (!shouldZoom && !shouldMove)) {\n        return;\n    }\n\n    // If both `shouldZoom` and `shouldMove` is true, trigger\n    // their event both, and the final behavior is determined\n    // by event listener themselves.\n\n    if (shouldZoom) {\n        // Convenience:\n        // Mac and VM Windows on Mac: scroll up: zoom out.\n        // Windows: scroll up: zoom in.\n\n        // FIXME: Should do more test in different environment.\n        // wheelDelta is too complicated in difference nvironment\n        // (https://developer.mozilla.org/en-US/docs/Web/Events/mousewheel),\n        // although it has been normallized by zrender.\n        // wheelDelta of mouse wheel is bigger than touch pad.\n        var factor = absWheelDeltaDelta > 3 ? 1.4 : absWheelDeltaDelta > 1 ? 1.2 : 1.1;\n        var scale = wheelDelta > 0 ? factor : 1 / factor;\n        checkPointerAndTrigger(this, 'zoom', 'zoomOnMouseWheel', e, {\n            scale: scale, originX: originX, originY: originY\n        });\n    }\n\n    if (shouldMove) {\n        // FIXME: Should do more test in different environment.\n        var absDelta = Math.abs(wheelDelta);\n        // wheelDelta of mouse wheel is bigger than touch pad.\n        var scrollDelta = (wheelDelta > 0 ? 1 : -1) * (absDelta > 3 ? 0.4 : absDelta > 1 ? 0.15 : 0.05);\n        checkPointerAndTrigger(this, 'scrollMove', 'moveOnMouseWheel', e, {\n            scrollDelta: scrollDelta, originX: originX, originY: originY\n        });\n    }\n}\n\nfunction pinch(e) {\n    if (isTaken(this._zr, 'globalPan')) {\n        return;\n    }\n    var scale = e.pinchScale > 1 ? 1.1 : 1 / 1.1;\n    checkPointerAndTrigger(this, 'zoom', null, e, {\n        scale: scale, originX: e.pinchX, originY: e.pinchY\n    });\n}\n\nfunction checkPointerAndTrigger(controller, eventName, behaviorToCheck, e, contollerEvent) {\n    if (controller.pointerChecker\n        && controller.pointerChecker(e, contollerEvent.originX, contollerEvent.originY)\n    ) {\n        // When mouse is out of roamController rect,\n        // default befavoius should not be be disabled, otherwise\n        // page sliding is disabled, contrary to expectation.\n        stop(e.event);\n\n        trigger(controller, eventName, behaviorToCheck, e, contollerEvent);\n    }\n}\n\nfunction trigger(controller, eventName, behaviorToCheck, e, contollerEvent) {\n    // Also provide behavior checker for event listener, for some case that\n    // multiple components share one listener.\n    contollerEvent.isAvailableBehavior = bind(isAvailableBehavior, null, behaviorToCheck, e);\n    controller.trigger(eventName, contollerEvent);\n}\n\n// settings: {\n//     zoomOnMouseWheel\n//     moveOnMouseMove\n//     moveOnMouseWheel\n// }\n// The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\nfunction isAvailableBehavior(behaviorToCheck, e, settings) {\n    var setting = settings[behaviorToCheck];\n    return !behaviorToCheck || (\n        setting && (!isString(setting) || e.event[setting + 'Key'])\n    );\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Only create one roam controller for each coordinate system.\n// one roam controller might be refered by two inside data zoom\n// components (for example, one for x and one for y). When user\n// pan or zoom, only dispatch one action for those data zoom\n// components.\n\nvar ATTR = '\\0_ec_dataZoom_roams';\n\n\n/**\n * @public\n * @param {module:echarts/ExtensionAPI} api\n * @param {Object} dataZoomInfo\n * @param {string} dataZoomInfo.coordId\n * @param {Function} dataZoomInfo.containsPoint\n * @param {Array.<string>} dataZoomInfo.allCoordIds\n * @param {string} dataZoomInfo.dataZoomId\n * @param {Object} dataZoomInfo.getRange\n * @param {Function} dataZoomInfo.getRange.pan\n * @param {Function} dataZoomInfo.getRange.zoom\n * @param {Function} dataZoomInfo.getRange.scrollMove\n * @param {boolean} dataZoomInfo.dataZoomModel\n */\nfunction register$1(api, dataZoomInfo) {\n    var store = giveStore(api);\n    var theDataZoomId = dataZoomInfo.dataZoomId;\n    var theCoordId = dataZoomInfo.coordId;\n\n    // Do clean when a dataZoom changes its target coordnate system.\n    // Avoid memory leak, dispose all not-used-registered.\n    each$1(store, function (record, coordId) {\n        var dataZoomInfos = record.dataZoomInfos;\n        if (dataZoomInfos[theDataZoomId]\n            && indexOf(dataZoomInfo.allCoordIds, theCoordId) < 0\n        ) {\n            delete dataZoomInfos[theDataZoomId];\n            record.count--;\n        }\n    });\n\n    cleanStore(store);\n\n    var record = store[theCoordId];\n    // Create if needed.\n    if (!record) {\n        record = store[theCoordId] = {\n            coordId: theCoordId,\n            dataZoomInfos: {},\n            count: 0\n        };\n        record.controller = createController(api, record);\n        record.dispatchAction = curry(dispatchAction, api);\n    }\n\n    // Update reference of dataZoom.\n    !(record.dataZoomInfos[theDataZoomId]) && record.count++;\n    record.dataZoomInfos[theDataZoomId] = dataZoomInfo;\n\n    var controllerParams = mergeControllerParams(record.dataZoomInfos);\n    record.controller.enable(controllerParams.controlType, controllerParams.opt);\n\n    // Consider resize, area should be always updated.\n    record.controller.setPointerChecker(dataZoomInfo.containsPoint);\n\n    // Update throttle.\n    createOrUpdate(\n        record,\n        'dispatchAction',\n        dataZoomInfo.dataZoomModel.get('throttle', true),\n        'fixRate'\n    );\n}\n\n/**\n * @public\n * @param {module:echarts/ExtensionAPI} api\n * @param {string} dataZoomId\n */\nfunction unregister$1(api, dataZoomId) {\n    var store = giveStore(api);\n\n    each$1(store, function (record) {\n        record.controller.dispose();\n        var dataZoomInfos = record.dataZoomInfos;\n        if (dataZoomInfos[dataZoomId]) {\n            delete dataZoomInfos[dataZoomId];\n            record.count--;\n        }\n    });\n\n    cleanStore(store);\n}\n\n/**\n * @public\n */\nfunction generateCoordId(coordModel) {\n    return coordModel.type + '\\0_' + coordModel.id;\n}\n\n/**\n * Key: coordId, value: {dataZoomInfos: [], count, controller}\n * @type {Array.<Object>}\n */\nfunction giveStore(api) {\n    // Mount store on zrender instance, so that we do not\n    // need to worry about dispose.\n    var zr = api.getZr();\n    return zr[ATTR] || (zr[ATTR] = {});\n}\n\nfunction createController(api, newRecord) {\n    var controller = new RoamController(api.getZr());\n\n    each$1(['pan', 'zoom', 'scrollMove'], function (eventName) {\n        controller.on(eventName, function (event) {\n            var batch = [];\n\n            each$1(newRecord.dataZoomInfos, function (info) {\n                // Check whether the behaviors (zoomOnMouseWheel, moveOnMouseMove,\n                // moveOnMouseWheel, ...) enabled.\n                if (!event.isAvailableBehavior(info.dataZoomModel.option)) {\n                    return;\n                }\n\n                var method = (info.getRange || {})[eventName];\n                var range = method && method(newRecord.controller, event);\n\n                !info.dataZoomModel.get('disabled', true) && range && batch.push({\n                    dataZoomId: info.dataZoomId,\n                    start: range[0],\n                    end: range[1]\n                });\n            });\n\n            batch.length && newRecord.dispatchAction(batch);\n        });\n    });\n\n    return controller;\n}\n\nfunction cleanStore(store) {\n    each$1(store, function (record, coordId) {\n        if (!record.count) {\n            record.controller.dispose();\n            delete store[coordId];\n        }\n    });\n}\n\n/**\n * This action will be throttled.\n */\nfunction dispatchAction(api, batch) {\n    api.dispatchAction({\n        type: 'dataZoom',\n        batch: batch\n    });\n}\n\n/**\n * Merge roamController settings when multiple dataZooms share one roamController.\n */\nfunction mergeControllerParams(dataZoomInfos) {\n    var controlType;\n    // DO NOT use reserved word (true, false, undefined) as key literally. Even if encapsulated\n    // as string, it is probably revert to reserved word by compress tool. See #7411.\n    var prefix = 'type_';\n    var typePriority = {\n        'type_true': 2,\n        'type_move': 1,\n        'type_false': 0,\n        'type_undefined': -1\n    };\n    var preventDefaultMouseMove = true;\n\n    each$1(dataZoomInfos, function (dataZoomInfo) {\n        var dataZoomModel = dataZoomInfo.dataZoomModel;\n        var oneType = dataZoomModel.get('disabled', true)\n            ? false\n            : dataZoomModel.get('zoomLock', true)\n            ? 'move'\n            : true;\n        if (typePriority[prefix + oneType] > typePriority[prefix + controlType]) {\n            controlType = oneType;\n        }\n\n        // Prevent default move event by default. If one false, do not prevent. Otherwise\n        // users may be confused why it does not work when multiple insideZooms exist.\n        preventDefaultMouseMove &= dataZoomModel.get('preventDefaultMouseMove', true);\n    });\n\n    return {\n        controlType: controlType,\n        opt: {\n            // RoamController will enable all of these functionalities,\n            // and the final behavior is determined by its event listener\n            // provided by each inside zoom.\n            zoomOnMouseWheel: true,\n            moveOnMouseMove: true,\n            moveOnMouseWheel: true,\n            preventDefaultMouseMove: !!preventDefaultMouseMove\n        }\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$4 = bind;\n\nvar InsideZoomView = DataZoomView.extend({\n\n    type: 'dataZoom.inside',\n\n    /**\n     * @override\n     */\n    init: function (ecModel, api) {\n        /**\n         * 'throttle' is used in this.dispatchAction, so we save range\n         * to avoid missing some 'pan' info.\n         * @private\n         * @type {Array.<number>}\n         */\n        this._range;\n    },\n\n    /**\n     * @override\n     */\n    render: function (dataZoomModel, ecModel, api, payload) {\n        InsideZoomView.superApply(this, 'render', arguments);\n\n        // Hance the `throttle` util ensures to preserve command order,\n        // here simply updating range all the time will not cause missing\n        // any of the the roam change.\n        this._range = dataZoomModel.getPercentRange();\n\n        // Reset controllers.\n        each$1(this.getTargetCoordInfo(), function (coordInfoList, coordSysName) {\n\n            var allCoordIds = map(coordInfoList, function (coordInfo) {\n                return generateCoordId(coordInfo.model);\n            });\n\n            each$1(coordInfoList, function (coordInfo) {\n                var coordModel = coordInfo.model;\n\n                var getRange = {};\n                each$1(['pan', 'zoom', 'scrollMove'], function (eventName) {\n                    getRange[eventName] = bind$4(roamHandlers[eventName], this, coordInfo, coordSysName);\n                }, this);\n\n                register$1(\n                    api,\n                    {\n                        coordId: generateCoordId(coordModel),\n                        allCoordIds: allCoordIds,\n                        containsPoint: function (e, x, y) {\n                            return coordModel.coordinateSystem.containPoint([x, y]);\n                        },\n                        dataZoomId: dataZoomModel.id,\n                        dataZoomModel: dataZoomModel,\n                        getRange: getRange\n                    }\n                );\n            }, this);\n\n        }, this);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        unregister$1(this.api, this.dataZoomModel.id);\n        InsideZoomView.superApply(this, 'dispose', arguments);\n        this._range = null;\n    }\n\n});\n\nvar roamHandlers = {\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    zoom: function (coordInfo, coordSysName, controller, e) {\n        var lastRange = this._range;\n        var range = lastRange.slice();\n\n        // Calculate transform by the first axis.\n        var axisModel = coordInfo.axisModels[0];\n        if (!axisModel) {\n            return;\n        }\n\n        var directionInfo = getDirectionInfo[coordSysName](\n            null, [e.originX, e.originY], axisModel, controller, coordInfo\n        );\n        var percentPoint = (\n            directionInfo.signal > 0\n                ? (directionInfo.pixelStart + directionInfo.pixelLength - directionInfo.pixel)\n                : (directionInfo.pixel - directionInfo.pixelStart)\n            ) / directionInfo.pixelLength * (range[1] - range[0]) + range[0];\n\n        var scale = Math.max(1 / e.scale, 0);\n        range[0] = (range[0] - percentPoint) * scale + percentPoint;\n        range[1] = (range[1] - percentPoint) * scale + percentPoint;\n\n        // Restrict range.\n        var minMaxSpan = this.dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan();\n\n        sliderMove(0, range, [0, 100], 0, minMaxSpan.minSpan, minMaxSpan.maxSpan);\n\n        this._range = range;\n\n        if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) {\n            return range;\n        }\n    },\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    pan: makeMover(function (range, axisModel, coordInfo, coordSysName, controller, e) {\n        var directionInfo = getDirectionInfo[coordSysName](\n            [e.oldX, e.oldY], [e.newX, e.newY], axisModel, controller, coordInfo\n        );\n\n        return directionInfo.signal\n            * (range[1] - range[0])\n            * directionInfo.pixel / directionInfo.pixelLength;\n    }),\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    scrollMove: makeMover(function (range, axisModel, coordInfo, coordSysName, controller, e) {\n        var directionInfo = getDirectionInfo[coordSysName](\n            [0, 0], [e.scrollDelta, e.scrollDelta], axisModel, controller, coordInfo\n        );\n        return directionInfo.signal * (range[1] - range[0]) * e.scrollDelta;\n    })\n};\n\nfunction makeMover(getPercentDelta) {\n    return function (coordInfo, coordSysName, controller, e) {\n        var lastRange = this._range;\n        var range = lastRange.slice();\n\n        // Calculate transform by the first axis.\n        var axisModel = coordInfo.axisModels[0];\n        if (!axisModel) {\n            return;\n        }\n\n        var percentDelta = getPercentDelta(\n            range, axisModel, coordInfo, coordSysName, controller, e\n        );\n\n        sliderMove(percentDelta, range, [0, 100], 'all');\n\n        this._range = range;\n\n        if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) {\n            return range;\n        }\n    };\n}\n\nvar getDirectionInfo = {\n\n    grid: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var ret = {};\n        var rect = coordInfo.model.coordinateSystem.getRect();\n        oldPoint = oldPoint || [0, 0];\n\n        if (axis.dim === 'x') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            ret.pixelLength = rect.width;\n            ret.pixelStart = rect.x;\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // axis.dim === 'y'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            ret.pixelLength = rect.height;\n            ret.pixelStart = rect.y;\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    },\n\n    polar: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var ret = {};\n        var polar = coordInfo.model.coordinateSystem;\n        var radiusExtent = polar.getRadiusAxis().getExtent();\n        var angleExtent = polar.getAngleAxis().getExtent();\n\n        oldPoint = oldPoint ? polar.pointToCoord(oldPoint) : [0, 0];\n        newPoint = polar.pointToCoord(newPoint);\n\n        if (axisModel.mainType === 'radiusAxis') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            // ret.pixelLength = Math.abs(radiusExtent[1] - radiusExtent[0]);\n            // ret.pixelStart = Math.min(radiusExtent[0], radiusExtent[1]);\n            ret.pixelLength = radiusExtent[1] - radiusExtent[0];\n            ret.pixelStart = radiusExtent[0];\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // 'angleAxis'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            // ret.pixelLength = Math.abs(angleExtent[1] - angleExtent[0]);\n            // ret.pixelStart = Math.min(angleExtent[0], angleExtent[1]);\n            ret.pixelLength = angleExtent[1] - angleExtent[0];\n            ret.pixelStart = angleExtent[0];\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    },\n\n    singleAxis: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var rect = coordInfo.model.coordinateSystem.getRect();\n        var ret = {};\n\n        oldPoint = oldPoint || [0, 0];\n\n        if (axis.orient === 'horizontal') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            ret.pixelLength = rect.width;\n            ret.pixelStart = rect.x;\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // 'vertical'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            ret.pixelLength = rect.height;\n            ret.pixelStart = rect.y;\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterProcessor({\n\n    // `dataZoomProcessor` will only be performed in needed series. Consider if\n    // there is a line series and a pie series, it is better not to update the\n    // line series if only pie series is needed to be updated.\n    getTargetSeries: function (ecModel) {\n        var seriesModelMap = createHashMap();\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                var axisProxy = dataZoomModel.getAxisProxy(dimNames.name, axisIndex);\n                each$1(axisProxy.getTargetSeriesModels(), function (seriesModel) {\n                    seriesModelMap.set(seriesModel.uid, seriesModel);\n                });\n            });\n        });\n\n        return seriesModelMap;\n    },\n\n    modifyOutputEnd: true,\n\n    // Consider appendData, where filter should be performed. Because data process is\n    // in block mode currently, it is not need to worry about that the overallProgress\n    // execute every frame.\n    overallReset: function (ecModel, api) {\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            // We calculate window and reset axis here but not in model\n            // init stage and not after action dispatch handler, because\n            // reset should be called after seriesData.restoreData.\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                dataZoomModel.getAxisProxy(dimNames.name, axisIndex).reset(dataZoomModel, api);\n            });\n\n            // Caution: data zoom filtering is order sensitive when using\n            // percent range and no min/max/scale set on axis.\n            // For example, we have dataZoom definition:\n            // [\n            //      {xAxisIndex: 0, start: 30, end: 70},\n            //      {yAxisIndex: 0, start: 20, end: 80}\n            // ]\n            // In this case, [20, 80] of y-dataZoom should be based on data\n            // that have filtered by x-dataZoom using range of [30, 70],\n            // but should not be based on full raw data. Thus sliding\n            // x-dataZoom will change both ranges of xAxis and yAxis,\n            // while sliding y-dataZoom will only change the range of yAxis.\n            // So we should filter x-axis after reset x-axis immediately,\n            // and then reset y-axis and filter y-axis.\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                dataZoomModel.getAxisProxy(dimNames.name, axisIndex).filterData(dataZoomModel, api);\n            });\n        });\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            // Fullfill all of the range props so that user\n            // is able to get them from chart.getOption().\n            var axisProxy = dataZoomModel.findRepresentativeAxisProxy();\n            var percentRange = axisProxy.getDataPercentWindow();\n            var valueRange = axisProxy.getDataValueWindow();\n\n            dataZoomModel.setRawRange({\n                start: percentRange[0],\n                end: percentRange[1],\n                startValue: valueRange[0],\n                endValue: valueRange[1]\n            }, true);\n        });\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterAction('dataZoom', function (payload, ecModel) {\n\n    var linkedNodesFinder = createLinkedNodesFinder(\n        bind(ecModel.eachComponent, ecModel, 'dataZoom'),\n        eachAxisDim$1,\n        function (model, dimNames) {\n            return model.get(dimNames.axisIndex);\n        }\n    );\n\n    var effectedModels = [];\n\n    ecModel.eachComponent(\n        {mainType: 'dataZoom', query: payload},\n        function (model, index) {\n            effectedModels.push.apply(\n                effectedModels, linkedNodesFinder(model).nodes\n            );\n        }\n    );\n\n    each$1(effectedModels, function (dataZoomModel, index) {\n        dataZoomModel.setRawRange({\n            start: payload.start,\n            end: payload.end,\n            startValue: payload.startValue,\n            endValue: payload.endValue\n        });\n    });\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar features = {};\n\nfunction register$2(name, ctor) {\n    features[name] = ctor;\n}\n\nfunction get$1(name) {\n    return features[name];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ToolboxModel = extendComponentModel({\n\n    type: 'toolbox',\n\n    layoutMode: {\n        type: 'box',\n        ignoreSize: true\n    },\n\n    optionUpdated: function () {\n        ToolboxModel.superApply(this, 'optionUpdated', arguments);\n\n        each$1(this.option.feature, function (featureOpt, featureName) {\n            var Feature = get$1(featureName);\n            Feature && merge(featureOpt, Feature.defaultOption);\n        });\n    },\n\n    defaultOption: {\n\n        show: true,\n\n        z: 6,\n\n        zlevel: 0,\n\n        orient: 'horizontal',\n\n        left: 'right',\n\n        top: 'top',\n\n        // right\n        // bottom\n\n        backgroundColor: 'transparent',\n\n        borderColor: '#ccc',\n\n        borderRadius: 0,\n\n        borderWidth: 0,\n\n        padding: 5,\n\n        itemSize: 15,\n\n        itemGap: 8,\n\n        showTitle: true,\n\n        iconStyle: {\n            borderColor: '#666',\n            color: 'none'\n        },\n        emphasis: {\n            iconStyle: {\n                borderColor: '#3E98C5'\n            }\n        }\n        // textStyle: {},\n\n        // feature\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentView({\n\n    type: 'toolbox',\n\n    render: function (toolboxModel, ecModel, api, payload) {\n        var group = this.group;\n        group.removeAll();\n\n        if (!toolboxModel.get('show')) {\n            return;\n        }\n\n        var itemSize = +toolboxModel.get('itemSize');\n        var featureOpts = toolboxModel.get('feature') || {};\n        var features = this._features || (this._features = {});\n\n        var featureNames = [];\n        each$1(featureOpts, function (opt, name) {\n            featureNames.push(name);\n        });\n\n        (new DataDiffer(this._featureNames || [], featureNames))\n            .add(processFeature)\n            .update(processFeature)\n            .remove(curry(processFeature, null))\n            .execute();\n\n        // Keep for diff.\n        this._featureNames = featureNames;\n\n        function processFeature(newIndex, oldIndex) {\n            var featureName = featureNames[newIndex];\n            var oldName = featureNames[oldIndex];\n            var featureOpt = featureOpts[featureName];\n            var featureModel = new Model(featureOpt, toolboxModel, toolboxModel.ecModel);\n            var feature;\n\n            if (featureName && !oldName) { // Create\n                if (isUserFeatureName(featureName)) {\n                    feature = {\n                        model: featureModel,\n                        onclick: featureModel.option.onclick,\n                        featureName: featureName\n                    };\n                }\n                else {\n                    var Feature = get$1(featureName);\n                    if (!Feature) {\n                        return;\n                    }\n                    feature = new Feature(featureModel, ecModel, api);\n                }\n                features[featureName] = feature;\n            }\n            else {\n                feature = features[oldName];\n                // If feature does not exsit.\n                if (!feature) {\n                    return;\n                }\n                feature.model = featureModel;\n                feature.ecModel = ecModel;\n                feature.api = api;\n            }\n\n            if (!featureName && oldName) {\n                feature.dispose && feature.dispose(ecModel, api);\n                return;\n            }\n\n            if (!featureModel.get('show') || feature.unusable) {\n                feature.remove && feature.remove(ecModel, api);\n                return;\n            }\n\n            createIconPaths(featureModel, feature, featureName);\n\n            featureModel.setIconStatus = function (iconName, status) {\n                var option = this.option;\n                var iconPaths = this.iconPaths;\n                option.iconStatus = option.iconStatus || {};\n                option.iconStatus[iconName] = status;\n                // FIXME\n                iconPaths[iconName] && iconPaths[iconName].trigger(status);\n            };\n\n            if (feature.render) {\n                feature.render(featureModel, ecModel, api, payload);\n            }\n        }\n\n        function createIconPaths(featureModel, feature, featureName) {\n            var iconStyleModel = featureModel.getModel('iconStyle');\n            var iconStyleEmphasisModel = featureModel.getModel('emphasis.iconStyle');\n\n            // If one feature has mutiple icon. they are orginaized as\n            // {\n            //     icon: {\n            //         foo: '',\n            //         bar: ''\n            //     },\n            //     title: {\n            //         foo: '',\n            //         bar: ''\n            //     }\n            // }\n            var icons = feature.getIcons ? feature.getIcons() : featureModel.get('icon');\n            var titles = featureModel.get('title') || {};\n            if (typeof icons === 'string') {\n                var icon = icons;\n                var title = titles;\n                icons = {};\n                titles = {};\n                icons[featureName] = icon;\n                titles[featureName] = title;\n            }\n            var iconPaths = featureModel.iconPaths = {};\n            each$1(icons, function (iconStr, iconName) {\n                var path = createIcon(\n                    iconStr,\n                    {},\n                    {\n                        x: -itemSize / 2,\n                        y: -itemSize / 2,\n                        width: itemSize,\n                        height: itemSize\n                    }\n                );\n                path.setStyle(iconStyleModel.getItemStyle());\n                path.hoverStyle = iconStyleEmphasisModel.getItemStyle();\n\n                setHoverStyle(path);\n\n                if (toolboxModel.get('showTitle')) {\n                    path.__title = titles[iconName];\n                    path.on('mouseover', function () {\n                            // Should not reuse above hoverStyle, which might be modified.\n                            var hoverStyle = iconStyleEmphasisModel.getItemStyle();\n                            path.setStyle({\n                                text: titles[iconName],\n                                textPosition: hoverStyle.textPosition || 'bottom',\n                                textFill: hoverStyle.fill || hoverStyle.stroke || '#000',\n                                textAlign: hoverStyle.textAlign || 'center'\n                            });\n                        })\n                        .on('mouseout', function () {\n                            path.setStyle({\n                                textFill: null\n                            });\n                        });\n                }\n                path.trigger(featureModel.get('iconStatus.' + iconName) || 'normal');\n\n                group.add(path);\n                path.on('click', bind(\n                    feature.onclick, feature, ecModel, api, iconName\n                ));\n\n                iconPaths[iconName] = path;\n            });\n        }\n\n        layout$2(group, toolboxModel, api);\n        // Render background after group is layout\n        // FIXME\n        group.add(makeBackground(group.getBoundingRect(), toolboxModel));\n\n        // Adjust icon title positions to avoid them out of screen\n        group.eachChild(function (icon) {\n            var titleText = icon.__title;\n            var hoverStyle = icon.hoverStyle;\n            // May be background element\n            if (hoverStyle && titleText) {\n                var rect = getBoundingRect(\n                    titleText, makeFont(hoverStyle)\n                );\n                var offsetX = icon.position[0] + group.position[0];\n                var offsetY = icon.position[1] + group.position[1] + itemSize;\n\n                var needPutOnTop = false;\n                if (offsetY + rect.height > api.getHeight()) {\n                    hoverStyle.textPosition = 'top';\n                    needPutOnTop = true;\n                }\n                var topOffset = needPutOnTop ? (-5 - rect.height) : (itemSize + 8);\n                if (offsetX + rect.width / 2 > api.getWidth()) {\n                    hoverStyle.textPosition = ['100%', topOffset];\n                    hoverStyle.textAlign = 'right';\n                }\n                else if (offsetX - rect.width / 2 < 0) {\n                    hoverStyle.textPosition = [0, topOffset];\n                    hoverStyle.textAlign = 'left';\n                }\n            }\n        });\n    },\n\n    updateView: function (toolboxModel, ecModel, api, payload) {\n        each$1(this._features, function (feature) {\n            feature.updateView && feature.updateView(feature.model, ecModel, api, payload);\n        });\n    },\n\n    // updateLayout: function (toolboxModel, ecModel, api, payload) {\n    //     zrUtil.each(this._features, function (feature) {\n    //         feature.updateLayout && feature.updateLayout(feature.model, ecModel, api, payload);\n    //     });\n    // },\n\n    remove: function (ecModel, api) {\n        each$1(this._features, function (feature) {\n            feature.remove && feature.remove(ecModel, api);\n        });\n        this.group.removeAll();\n    },\n\n    dispose: function (ecModel, api) {\n        each$1(this._features, function (feature) {\n            feature.dispose && feature.dispose(ecModel, api);\n        });\n    }\n});\n\nfunction isUserFeatureName(featureName) {\n    return featureName.indexOf('my') === 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Uint8Array */\n\nvar saveAsImageLang = lang.toolbox.saveAsImage;\n\nfunction SaveAsImage(model) {\n    this.model = model;\n}\n\nSaveAsImage.defaultOption = {\n    show: true,\n    icon: 'M4.7,22.9L29.3,45.5L54.7,23.4M4.6,43.6L4.6,58L53.8,58L53.8,43.6M29.2,45.1L29.2,0',\n    title: saveAsImageLang.title,\n    type: 'png',\n    // Default use option.backgroundColor\n    // backgroundColor: '#fff',\n    name: '',\n    excludeComponents: ['toolbox'],\n    pixelRatio: 1,\n    lang: saveAsImageLang.lang.slice()\n};\n\nSaveAsImage.prototype.unusable = !env$1.canvasSupported;\n\nvar proto$2 = SaveAsImage.prototype;\n\nproto$2.onclick = function (ecModel, api) {\n    var model = this.model;\n    var title = model.get('name') || ecModel.get('title.0.text') || 'echarts';\n    var $a = document.createElement('a');\n    var type = model.get('type', true) || 'png';\n    $a.download = title + '.' + type;\n    $a.target = '_blank';\n    var url = api.getConnectedDataURL({\n        type: type,\n        backgroundColor: model.get('backgroundColor', true)\n            || ecModel.get('backgroundColor') || '#fff',\n        excludeComponents: model.get('excludeComponents'),\n        pixelRatio: model.get('pixelRatio')\n    });\n    $a.href = url;\n    // Chrome and Firefox\n    if (typeof MouseEvent === 'function' && !env$1.browser.ie && !env$1.browser.edge) {\n        var evt = new MouseEvent('click', {\n            view: window,\n            bubbles: true,\n            cancelable: false\n        });\n        $a.dispatchEvent(evt);\n    }\n    // IE\n    else {\n        if (window.navigator.msSaveOrOpenBlob) {\n            var bstr = atob(url.split(',')[1]);\n            var n = bstr.length;\n            var u8arr = new Uint8Array(n);\n            while (n--) {\n                u8arr[n] = bstr.charCodeAt(n);\n            }\n            var blob = new Blob([u8arr]);\n            window.navigator.msSaveOrOpenBlob(blob, title + '.' + type);\n        }\n        else {\n            var lang$$1 = model.get('lang');\n            var html = ''\n                + '<body style=\"margin:0;\">'\n                + '<img src=\"' + url + '\" style=\"max-width:100%;\" title=\"' + ((lang$$1 && lang$$1[0]) || '') + '\" />'\n                + '</body>';\n            var tab = window.open();\n            tab.document.write(html);\n        }\n    }\n};\n\nregister$2(\n    'saveAsImage', SaveAsImage\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar magicTypeLang = lang.toolbox.magicType;\n\nfunction MagicType(model) {\n    this.model = model;\n}\n\nMagicType.defaultOption = {\n    show: true,\n    type: [],\n    // Icon group\n    icon: {\n        /* eslint-disable */\n        line: 'M4.1,28.9h7.1l9.3-22l7.4,38l9.7-19.7l3,12.8h14.9M4.1,58h51.4',\n        bar: 'M6.7,22.9h10V48h-10V22.9zM24.9,13h10v35h-10V13zM43.2,2h10v46h-10V2zM3.1,58h53.7',\n        stack: 'M8.2,38.4l-8.4,4.1l30.6,15.3L60,42.5l-8.1-4.1l-21.5,11L8.2,38.4z M51.9,30l-8.1,4.2l-13.4,6.9l-13.9-6.9L8.2,30l-8.4,4.2l8.4,4.2l22.2,11l21.5-11l8.1-4.2L51.9,30z M51.9,21.7l-8.1,4.2L35.7,30l-5.3,2.8L24.9,30l-8.4-4.1l-8.3-4.2l-8.4,4.2L8.2,30l8.3,4.2l13.9,6.9l13.4-6.9l8.1-4.2l8.1-4.1L51.9,21.7zM30.4,2.2L-0.2,17.5l8.4,4.1l8.3,4.2l8.4,4.2l5.5,2.7l5.3-2.7l8.1-4.2l8.1-4.2l8.1-4.1L30.4,2.2z', // jshint ignore:line\n        tiled: 'M2.3,2.2h22.8V25H2.3V2.2z M35,2.2h22.8V25H35V2.2zM2.3,35h22.8v22.8H2.3V35z M35,35h22.8v22.8H35V35z'\n        /* eslint-enable */\n    },\n    // `line`, `bar`, `stack`, `tiled`\n    title: clone(magicTypeLang.title),\n    option: {},\n    seriesIndex: {}\n};\n\nvar proto$3 = MagicType.prototype;\n\nproto$3.getIcons = function () {\n    var model = this.model;\n    var availableIcons = model.get('icon');\n    var icons = {};\n    each$1(model.get('type'), function (type) {\n        if (availableIcons[type]) {\n            icons[type] = availableIcons[type];\n        }\n    });\n    return icons;\n};\n\nvar seriesOptGenreator = {\n    'line': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                type: 'line',\n                // Preserve data related option\n                data: seriesModel.get('data'),\n                stack: seriesModel.get('stack'),\n                markPoint: seriesModel.get('markPoint'),\n                markLine: seriesModel.get('markLine')\n            }, model.get('option.line') || {}, true);\n        }\n    },\n    'bar': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line') {\n            return merge({\n                id: seriesId,\n                type: 'bar',\n                // Preserve data related option\n                data: seriesModel.get('data'),\n                stack: seriesModel.get('stack'),\n                markPoint: seriesModel.get('markPoint'),\n                markLine: seriesModel.get('markLine')\n            }, model.get('option.bar') || {}, true);\n        }\n    },\n    'stack': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line' || seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                stack: '__ec_magicType_stack__'\n            }, model.get('option.stack') || {}, true);\n        }\n    },\n    'tiled': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line' || seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                stack: ''\n            }, model.get('option.tiled') || {}, true);\n        }\n    }\n};\n\nvar radioTypes = [\n    ['line', 'bar'],\n    ['stack', 'tiled']\n];\n\nproto$3.onclick = function (ecModel, api, type) {\n    var model = this.model;\n    var seriesIndex = model.get('seriesIndex.' + type);\n    // Not supported magicType\n    if (!seriesOptGenreator[type]) {\n        return;\n    }\n    var newOption = {\n        series: []\n    };\n    var generateNewSeriesTypes = function (seriesModel) {\n        var seriesType = seriesModel.subType;\n        var seriesId = seriesModel.id;\n        var newSeriesOpt = seriesOptGenreator[type](\n            seriesType, seriesId, seriesModel, model\n        );\n        if (newSeriesOpt) {\n            // PENDING If merge original option?\n            defaults(newSeriesOpt, seriesModel.option);\n            newOption.series.push(newSeriesOpt);\n        }\n        // Modify boundaryGap\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys && coordSys.type === 'cartesian2d' && (type === 'line' || type === 'bar')) {\n            var categoryAxis = coordSys.getAxesByScale('ordinal')[0];\n            if (categoryAxis) {\n                var axisDim = categoryAxis.dim;\n                var axisType = axisDim + 'Axis';\n                var axisModel = ecModel.queryComponents({\n                    mainType: axisType,\n                    index: seriesModel.get(name + 'Index'),\n                    id: seriesModel.get(name + 'Id')\n                })[0];\n                var axisIndex = axisModel.componentIndex;\n\n                newOption[axisType] = newOption[axisType] || [];\n                for (var i = 0; i <= axisIndex; i++) {\n                    newOption[axisType][axisIndex] = newOption[axisType][axisIndex] || {};\n                }\n                newOption[axisType][axisIndex].boundaryGap = type === 'bar';\n            }\n        }\n    };\n\n    each$1(radioTypes, function (radio) {\n        if (indexOf(radio, type) >= 0) {\n            each$1(radio, function (item) {\n                model.setIconStatus(item, 'normal');\n            });\n        }\n    });\n\n    model.setIconStatus(type, 'emphasis');\n\n    ecModel.eachComponent(\n        {\n            mainType: 'series',\n            query: seriesIndex == null ? null : {\n                seriesIndex: seriesIndex\n            }\n        }, generateNewSeriesTypes\n    );\n    api.dispatchAction({\n        type: 'changeMagicType',\n        currentType: type,\n        newOption: newOption\n    });\n};\n\nregisterAction({\n    type: 'changeMagicType',\n    event: 'magicTypeChanged',\n    update: 'prepareAndUpdate'\n}, function (payload, ecModel) {\n    ecModel.mergeOption(payload.newOption);\n});\n\nregister$2('magicType', MagicType);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar dataViewLang = lang.toolbox.dataView;\n\nvar BLOCK_SPLITER = new Array(60).join('-');\nvar ITEM_SPLITER = '\\t';\n/**\n * Group series into two types\n *  1. on category axis, like line, bar\n *  2. others, like scatter, pie\n * @param {module:echarts/model/Global} ecModel\n * @return {Object}\n * @inner\n */\nfunction groupSeries(ecModel) {\n    var seriesGroupByCategoryAxis = {};\n    var otherSeries = [];\n    var meta = [];\n    ecModel.eachRawSeries(function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n\n        if (coordSys && (coordSys.type === 'cartesian2d' || coordSys.type === 'polar')) {\n            var baseAxis = coordSys.getBaseAxis();\n            if (baseAxis.type === 'category') {\n                var key = baseAxis.dim + '_' + baseAxis.index;\n                if (!seriesGroupByCategoryAxis[key]) {\n                    seriesGroupByCategoryAxis[key] = {\n                        categoryAxis: baseAxis,\n                        valueAxis: coordSys.getOtherAxis(baseAxis),\n                        series: []\n                    };\n                    meta.push({\n                        axisDim: baseAxis.dim,\n                        axisIndex: baseAxis.index\n                    });\n                }\n                seriesGroupByCategoryAxis[key].series.push(seriesModel);\n            }\n            else {\n                otherSeries.push(seriesModel);\n            }\n        }\n        else {\n            otherSeries.push(seriesModel);\n        }\n    });\n\n    return {\n        seriesGroupByCategoryAxis: seriesGroupByCategoryAxis,\n        other: otherSeries,\n        meta: meta\n    };\n}\n\n/**\n * Assemble content of series on cateogory axis\n * @param {Array.<module:echarts/model/Series>} series\n * @return {string}\n * @inner\n */\nfunction assembleSeriesWithCategoryAxis(series) {\n    var tables = [];\n    each$1(series, function (group, key) {\n        var categoryAxis = group.categoryAxis;\n        var valueAxis = group.valueAxis;\n        var valueAxisDim = valueAxis.dim;\n\n        var headers = [' '].concat(map(group.series, function (series) {\n            return series.name;\n        }));\n        var columns = [categoryAxis.model.getCategories()];\n        each$1(group.series, function (series) {\n            columns.push(series.getRawData().mapArray(valueAxisDim, function (val) {\n                return val;\n            }));\n        });\n        // Assemble table content\n        var lines = [headers.join(ITEM_SPLITER)];\n        for (var i = 0; i < columns[0].length; i++) {\n            var items = [];\n            for (var j = 0; j < columns.length; j++) {\n                items.push(columns[j][i]);\n            }\n            lines.push(items.join(ITEM_SPLITER));\n        }\n        tables.push(lines.join('\\n'));\n    });\n    return tables.join('\\n\\n' + BLOCK_SPLITER + '\\n\\n');\n}\n\n/**\n * Assemble content of other series\n * @param {Array.<module:echarts/model/Series>} series\n * @return {string}\n * @inner\n */\nfunction assembleOtherSeries(series) {\n    return map(series, function (series) {\n        var data = series.getRawData();\n        var lines = [series.name];\n        var vals = [];\n        data.each(data.dimensions, function () {\n            var argLen = arguments.length;\n            var dataIndex = arguments[argLen - 1];\n            var name = data.getName(dataIndex);\n            for (var i = 0; i < argLen - 1; i++) {\n                vals[i] = arguments[i];\n            }\n            lines.push((name ? (name + ITEM_SPLITER) : '') + vals.join(ITEM_SPLITER));\n        });\n        return lines.join('\\n');\n    }).join('\\n\\n' + BLOCK_SPLITER + '\\n\\n');\n}\n\n/**\n * @param {module:echarts/model/Global}\n * @return {Object}\n * @inner\n */\nfunction getContentFromModel(ecModel) {\n\n    var result = groupSeries(ecModel);\n\n    return {\n        value: filter([\n                assembleSeriesWithCategoryAxis(result.seriesGroupByCategoryAxis),\n                assembleOtherSeries(result.other)\n            ], function (str) {\n                return str.replace(/[\\n\\t\\s]/g, '');\n            }).join('\\n\\n' + BLOCK_SPLITER + '\\n\\n'),\n\n        meta: result.meta\n    };\n}\n\n\nfunction trim$1(str) {\n    return str.replace(/^\\s\\s*/, '').replace(/\\s\\s*$/, '');\n}\n/**\n * If a block is tsv format\n */\nfunction isTSVFormat(block) {\n    // Simple method to find out if a block is tsv format\n    var firstLine = block.slice(0, block.indexOf('\\n'));\n    if (firstLine.indexOf(ITEM_SPLITER) >= 0) {\n        return true;\n    }\n}\n\nvar itemSplitRegex = new RegExp('[' + ITEM_SPLITER + ']+', 'g');\n/**\n * @param {string} tsv\n * @return {Object}\n */\nfunction parseTSVContents(tsv) {\n    var tsvLines = tsv.split(/\\n+/g);\n    var headers = trim$1(tsvLines.shift()).split(itemSplitRegex);\n\n    var categories = [];\n    var series = map(headers, function (header) {\n        return {\n            name: header,\n            data: []\n        };\n    });\n    for (var i = 0; i < tsvLines.length; i++) {\n        var items = trim$1(tsvLines[i]).split(itemSplitRegex);\n        categories.push(items.shift());\n        for (var j = 0; j < items.length; j++) {\n            series[j] && (series[j].data[i] = items[j]);\n        }\n    }\n    return {\n        series: series,\n        categories: categories\n    };\n}\n\n/**\n * @param {string} str\n * @return {Array.<Object>}\n * @inner\n */\nfunction parseListContents(str) {\n    var lines = str.split(/\\n+/g);\n    var seriesName = trim$1(lines.shift());\n\n    var data = [];\n    for (var i = 0; i < lines.length; i++) {\n        var items = trim$1(lines[i]).split(itemSplitRegex);\n        var name = '';\n        var value;\n        var hasName = false;\n        if (isNaN(items[0])) { // First item is name\n            hasName = true;\n            name = items[0];\n            items = items.slice(1);\n            data[i] = {\n                name: name,\n                value: []\n            };\n            value = data[i].value;\n        }\n        else {\n            value = data[i] = [];\n        }\n        for (var j = 0; j < items.length; j++) {\n            value.push(+items[j]);\n        }\n        if (value.length === 1) {\n            hasName ? (data[i].value = value[0]) : (data[i] = value[0]);\n        }\n    }\n\n    return {\n        name: seriesName,\n        data: data\n    };\n}\n\n/**\n * @param {string} str\n * @param {Array.<Object>} blockMetaList\n * @return {Object}\n * @inner\n */\nfunction parseContents(str, blockMetaList) {\n    var blocks = str.split(new RegExp('\\n*' + BLOCK_SPLITER + '\\n*', 'g'));\n    var newOption = {\n        series: []\n    };\n    each$1(blocks, function (block, idx) {\n        if (isTSVFormat(block)) {\n            var result = parseTSVContents(block);\n            var blockMeta = blockMetaList[idx];\n            var axisKey = blockMeta.axisDim + 'Axis';\n\n            if (blockMeta) {\n                newOption[axisKey] = newOption[axisKey] || [];\n                newOption[axisKey][blockMeta.axisIndex] = {\n                    data: result.categories\n                };\n                newOption.series = newOption.series.concat(result.series);\n            }\n        }\n        else {\n            var result = parseListContents(block);\n            newOption.series.push(result);\n        }\n    });\n    return newOption;\n}\n\n/**\n * @alias {module:echarts/component/toolbox/feature/DataView}\n * @constructor\n * @param {module:echarts/model/Model} model\n */\nfunction DataView(model) {\n\n    this._dom = null;\n\n    this.model = model;\n}\n\nDataView.defaultOption = {\n    show: true,\n    readOnly: false,\n    optionToContent: null,\n    contentToOption: null,\n\n    icon: 'M17.5,17.3H33 M17.5,17.3H33 M45.4,29.5h-28 M11.5,2v56H51V14.8L38.4,2H11.5z M38.4,2.2v12.7H51 M45.4,41.7h-28',\n    title: clone(dataViewLang.title),\n    lang: clone(dataViewLang.lang),\n    backgroundColor: '#fff',\n    textColor: '#000',\n    textareaColor: '#fff',\n    textareaBorderColor: '#333',\n    buttonColor: '#c23531',\n    buttonTextColor: '#fff'\n};\n\nDataView.prototype.onclick = function (ecModel, api) {\n    var container = api.getDom();\n    var model = this.model;\n    if (this._dom) {\n        container.removeChild(this._dom);\n    }\n    var root = document.createElement('div');\n    root.style.cssText = 'position:absolute;left:5px;top:5px;bottom:5px;right:5px;';\n    root.style.backgroundColor = model.get('backgroundColor') || '#fff';\n\n    // Create elements\n    var header = document.createElement('h4');\n    var lang$$1 = model.get('lang') || [];\n    header.innerHTML = lang$$1[0] || model.get('title');\n    header.style.cssText = 'margin: 10px 20px;';\n    header.style.color = model.get('textColor');\n\n    var viewMain = document.createElement('div');\n    var textarea = document.createElement('textarea');\n    viewMain.style.cssText = 'display:block;width:100%;overflow:auto;';\n\n    var optionToContent = model.get('optionToContent');\n    var contentToOption = model.get('contentToOption');\n    var result = getContentFromModel(ecModel);\n    if (typeof optionToContent === 'function') {\n        var htmlOrDom = optionToContent(api.getOption());\n        if (typeof htmlOrDom === 'string') {\n            viewMain.innerHTML = htmlOrDom;\n        }\n        else if (isDom(htmlOrDom)) {\n            viewMain.appendChild(htmlOrDom);\n        }\n    }\n    else {\n        // Use default textarea\n        viewMain.appendChild(textarea);\n        textarea.readOnly = model.get('readOnly');\n        textarea.style.cssText = 'width:100%;height:100%;font-family:monospace;font-size:14px;line-height:1.6rem;';\n        textarea.style.color = model.get('textColor');\n        textarea.style.borderColor = model.get('textareaBorderColor');\n        textarea.style.backgroundColor = model.get('textareaColor');\n        textarea.value = result.value;\n    }\n\n    var blockMetaList = result.meta;\n\n    var buttonContainer = document.createElement('div');\n    buttonContainer.style.cssText = 'position:absolute;bottom:0;left:0;right:0;';\n\n    var buttonStyle = 'float:right;margin-right:20px;border:none;'\n        + 'cursor:pointer;padding:2px 5px;font-size:12px;border-radius:3px';\n    var closeButton = document.createElement('div');\n    var refreshButton = document.createElement('div');\n\n    buttonStyle += ';background-color:' + model.get('buttonColor');\n    buttonStyle += ';color:' + model.get('buttonTextColor');\n\n    var self = this;\n\n    function close() {\n        container.removeChild(root);\n        self._dom = null;\n    }\n    addEventListener(closeButton, 'click', close);\n\n    addEventListener(refreshButton, 'click', function () {\n        var newOption;\n        try {\n            if (typeof contentToOption === 'function') {\n                newOption = contentToOption(viewMain, api.getOption());\n            }\n            else {\n                newOption = parseContents(textarea.value, blockMetaList);\n            }\n        }\n        catch (e) {\n            close();\n            throw new Error('Data view format error ' + e);\n        }\n        if (newOption) {\n            api.dispatchAction({\n                type: 'changeDataView',\n                newOption: newOption\n            });\n        }\n\n        close();\n    });\n\n    closeButton.innerHTML = lang$$1[1];\n    refreshButton.innerHTML = lang$$1[2];\n    refreshButton.style.cssText = buttonStyle;\n    closeButton.style.cssText = buttonStyle;\n\n    !model.get('readOnly') && buttonContainer.appendChild(refreshButton);\n    buttonContainer.appendChild(closeButton);\n\n    // http://stackoverflow.com/questions/6637341/use-tab-to-indent-in-textarea\n    addEventListener(textarea, 'keydown', function (e) {\n        if ((e.keyCode || e.which) === 9) {\n            // get caret position/selection\n            var val = this.value;\n            var start = this.selectionStart;\n            var end = this.selectionEnd;\n\n            // set textarea value to: text before caret + tab + text after caret\n            this.value = val.substring(0, start) + ITEM_SPLITER + val.substring(end);\n\n            // put caret at right position again\n            this.selectionStart = this.selectionEnd = start + 1;\n\n            // prevent the focus lose\n            stop(e);\n        }\n    });\n\n    root.appendChild(header);\n    root.appendChild(viewMain);\n    root.appendChild(buttonContainer);\n\n    viewMain.style.height = (container.clientHeight - 80) + 'px';\n\n    container.appendChild(root);\n    this._dom = root;\n};\n\nDataView.prototype.remove = function (ecModel, api) {\n    this._dom && api.getDom().removeChild(this._dom);\n};\n\nDataView.prototype.dispose = function (ecModel, api) {\n    this.remove(ecModel, api);\n};\n\n/**\n * @inner\n */\nfunction tryMergeDataOption(newData, originalData) {\n    return map(newData, function (newVal, idx) {\n        var original = originalData && originalData[idx];\n        if (isObject$1(original) && !isArray(original)) {\n            if (isObject$1(newVal) && !isArray(newVal)) {\n                newVal = newVal.value;\n            }\n            // Original data has option\n            return defaults({\n                value: newVal\n            }, original);\n        }\n        else {\n            return newVal;\n        }\n    });\n}\n\nregister$2('dataView', DataView);\n\nregisterAction({\n    type: 'changeDataView',\n    event: 'dataViewChanged',\n    update: 'prepareAndUpdate'\n}, function (payload, ecModel) {\n    var newSeriesOptList = [];\n    each$1(payload.newOption.series, function (seriesOpt) {\n        var seriesModel = ecModel.getSeriesByName(seriesOpt.name)[0];\n        if (!seriesModel) {\n            // New created series\n            // Geuss the series type\n            newSeriesOptList.push(extend({\n                // Default is scatter\n                type: 'scatter'\n            }, seriesOpt));\n        }\n        else {\n            var originalData = seriesModel.get('data');\n            newSeriesOptList.push({\n                name: seriesOpt.name,\n                data: tryMergeDataOption(seriesOpt.data, originalData)\n            });\n        }\n    });\n\n    ecModel.mergeOption(defaults({\n        series: newSeriesOptList\n    }, payload.newOption));\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar curry$5 = curry;\nvar each$16 = each$1;\nvar map$2 = map;\nvar mathMin$4 = Math.min;\nvar mathMax$4 = Math.max;\nvar mathPow$2 = Math.pow;\n\nvar COVER_Z = 10000;\nvar UNSELECT_THRESHOLD = 6;\nvar MIN_RESIZE_LINE_WIDTH = 6;\nvar MUTEX_RESOURCE_KEY = 'globalPan';\n\nvar DIRECTION_MAP = {\n    w: [0, 0],\n    e: [0, 1],\n    n: [1, 0],\n    s: [1, 1]\n};\nvar CURSOR_MAP = {\n    w: 'ew',\n    e: 'ew',\n    n: 'ns',\n    s: 'ns',\n    ne: 'nesw',\n    sw: 'nesw',\n    nw: 'nwse',\n    se: 'nwse'\n};\nvar DEFAULT_BRUSH_OPT = {\n    brushStyle: {\n        lineWidth: 2,\n        stroke: 'rgba(0,0,0,0.3)',\n        fill: 'rgba(0,0,0,0.1)'\n    },\n    transformable: true,\n    brushMode: 'single',\n    removeOnClick: false\n};\n\nvar baseUID = 0;\n\n/**\n * @alias module:echarts/component/helper/BrushController\n * @constructor\n * @mixin {module:zrender/mixin/Eventful}\n * @event module:echarts/component/helper/BrushController#brush\n *        params:\n *            areas: Array.<Array>, coord relates to container group,\n *                                    If no container specified, to global.\n *            opt {\n *                isEnd: boolean,\n *                removeOnClick: boolean\n *            }\n *\n * @param {module:zrender/zrender~ZRender} zr\n */\nfunction BrushController(zr) {\n\n    if (__DEV__) {\n        assert$1(zr);\n    }\n\n    Eventful.call(this);\n\n    /**\n     * @type {module:zrender/zrender~ZRender}\n     * @private\n     */\n    this._zr = zr;\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * Only for drawing (after enabledBrush).\n     *     'line', 'rect', 'polygon' or false\n     *     If passing false/null/undefined, disable brush.\n     *     If passing 'auto', determined by panel.defaultBrushType\n     * @private\n     * @type {string}\n     */\n    this._brushType;\n\n    /**\n     * Only for drawing (after enabledBrush).\n     *\n     * @private\n     * @type {Object}\n     */\n    this._brushOption;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._panels;\n\n    /**\n     * @private\n     * @type {Array.<nubmer>}\n     */\n    this._track = [];\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._dragging;\n\n    /**\n     * @private\n     * @type {Array}\n     */\n    this._covers = [];\n\n    /**\n     * @private\n     * @type {moudule:zrender/container/Group}\n     */\n    this._creatingCover;\n\n    /**\n     * `true` means global panel\n     * @private\n     * @type {module:zrender/container/Group|boolean}\n     */\n    this._creatingPanel;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._enableGlobalPan;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    if (__DEV__) {\n        this._mounted;\n    }\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._uid = 'brushController_' + baseUID++;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._handlers = {};\n    each$16(mouseHandlers, function (handler, eventName) {\n        this._handlers[eventName] = bind(handler, this);\n    }, this);\n}\n\nBrushController.prototype = {\n\n    constructor: BrushController,\n\n    /**\n     * If set to null/undefined/false, select disabled.\n     * @param {Object} brushOption\n     * @param {string|boolean} brushOption.brushType 'line', 'rect', 'polygon' or false\n     *                          If passing false/null/undefined, disable brush.\n     *                          If passing 'auto', determined by panel.defaultBrushType.\n     *                              ('auto' can not be used in global panel)\n     * @param {number} [brushOption.brushMode='single'] 'single' or 'multiple'\n     * @param {boolean} [brushOption.transformable=true]\n     * @param {boolean} [brushOption.removeOnClick=false]\n     * @param {Object} [brushOption.brushStyle]\n     * @param {number} [brushOption.brushStyle.width]\n     * @param {number} [brushOption.brushStyle.lineWidth]\n     * @param {string} [brushOption.brushStyle.stroke]\n     * @param {string} [brushOption.brushStyle.fill]\n     * @param {number} [brushOption.z]\n     */\n    enableBrush: function (brushOption) {\n        if (__DEV__) {\n            assert$1(this._mounted);\n        }\n\n        this._brushType && doDisableBrush(this);\n        brushOption.brushType && doEnableBrush(this, brushOption);\n\n        return this;\n    },\n\n    /**\n     * @param {Array.<Object>} panelOpts If not pass, it is global brush.\n     *        Each items: {\n     *            panelId, // mandatory.\n     *            clipPath, // mandatory. function.\n     *            isTargetByCursor, // mandatory. function.\n     *            defaultBrushType, // optional, only used when brushType is 'auto'.\n     *            getLinearBrushOtherExtent, // optional. function.\n     *        }\n     */\n    setPanels: function (panelOpts) {\n        if (panelOpts && panelOpts.length) {\n            var panels = this._panels = {};\n            each$1(panelOpts, function (panelOpts) {\n                panels[panelOpts.panelId] = clone(panelOpts);\n            });\n        }\n        else {\n            this._panels = null;\n        }\n        return this;\n    },\n\n    /**\n     * @param {Object} [opt]\n     * @return {boolean} [opt.enableGlobalPan=false]\n     */\n    mount: function (opt) {\n        opt = opt || {};\n\n        if (__DEV__) {\n            this._mounted = true; // should be at first.\n        }\n\n        this._enableGlobalPan = opt.enableGlobalPan;\n\n        var thisGroup = this.group;\n        this._zr.add(thisGroup);\n\n        thisGroup.attr({\n            position: opt.position || [0, 0],\n            rotation: opt.rotation || 0,\n            scale: opt.scale || [1, 1]\n        });\n        this._transform = thisGroup.getLocalTransform();\n\n        return this;\n    },\n\n    eachCover: function (cb, context) {\n        each$16(this._covers, cb, context);\n    },\n\n    /**\n     * Update covers.\n     * @param {Array.<Object>} brushOptionList Like:\n     *        [\n     *            {id: 'xx', brushType: 'line', range: [23, 44], brushStyle, transformable},\n     *            {id: 'yy', brushType: 'rect', range: [[23, 44], [23, 54]]},\n     *            ...\n     *        ]\n     *        `brushType` is required in each cover info. (can not be 'auto')\n     *        `id` is not mandatory.\n     *        `brushStyle`, `transformable` is not mandatory, use DEFAULT_BRUSH_OPT by default.\n     *        If brushOptionList is null/undefined, all covers removed.\n     */\n    updateCovers: function (brushOptionList) {\n        if (__DEV__) {\n            assert$1(this._mounted);\n        }\n\n        brushOptionList = map(brushOptionList, function (brushOption) {\n            return merge(clone(DEFAULT_BRUSH_OPT), brushOption, true);\n        });\n\n        var tmpIdPrefix = '\\0-brush-index-';\n        var oldCovers = this._covers;\n        var newCovers = this._covers = [];\n        var controller = this;\n        var creatingCover = this._creatingCover;\n\n        (new DataDiffer(oldCovers, brushOptionList, oldGetKey, getKey))\n            .add(addOrUpdate)\n            .update(addOrUpdate)\n            .remove(remove)\n            .execute();\n\n        return this;\n\n        function getKey(brushOption, index) {\n            return (brushOption.id != null ? brushOption.id : tmpIdPrefix + index)\n                + '-' + brushOption.brushType;\n        }\n\n        function oldGetKey(cover, index) {\n            return getKey(cover.__brushOption, index);\n        }\n\n        function addOrUpdate(newIndex, oldIndex) {\n            var newBrushOption = brushOptionList[newIndex];\n            // Consider setOption in event listener of brushSelect,\n            // where updating cover when creating should be forbiden.\n            if (oldIndex != null && oldCovers[oldIndex] === creatingCover) {\n                newCovers[newIndex] = oldCovers[oldIndex];\n            }\n            else {\n                var cover = newCovers[newIndex] = oldIndex != null\n                    ? (\n                        oldCovers[oldIndex].__brushOption = newBrushOption,\n                        oldCovers[oldIndex]\n                    )\n                    : endCreating(controller, createCover(controller, newBrushOption));\n                updateCoverAfterCreation(controller, cover);\n            }\n        }\n\n        function remove(oldIndex) {\n            if (oldCovers[oldIndex] !== creatingCover) {\n                controller.group.remove(oldCovers[oldIndex]);\n            }\n        }\n    },\n\n    unmount: function () {\n        if (__DEV__) {\n            if (!this._mounted) {\n                return;\n            }\n        }\n\n        this.enableBrush(false);\n\n        // container may 'removeAll' outside.\n        clearCovers(this);\n        this._zr.remove(this.group);\n\n        if (__DEV__) {\n            this._mounted = false; // should be at last.\n        }\n\n        return this;\n    },\n\n    dispose: function () {\n        this.unmount();\n        this.off();\n    }\n};\n\nmixin(BrushController, Eventful);\n\nfunction doEnableBrush(controller, brushOption) {\n    var zr = controller._zr;\n\n    // Consider roam, which takes globalPan too.\n    if (!controller._enableGlobalPan) {\n        take(zr, MUTEX_RESOURCE_KEY, controller._uid);\n    }\n\n    each$16(controller._handlers, function (handler, eventName) {\n        zr.on(eventName, handler);\n    });\n\n    controller._brushType = brushOption.brushType;\n    controller._brushOption = merge(clone(DEFAULT_BRUSH_OPT), brushOption, true);\n}\n\nfunction doDisableBrush(controller) {\n    var zr = controller._zr;\n\n    release(zr, MUTEX_RESOURCE_KEY, controller._uid);\n\n    each$16(controller._handlers, function (handler, eventName) {\n        zr.off(eventName, handler);\n    });\n\n    controller._brushType = controller._brushOption = null;\n}\n\nfunction createCover(controller, brushOption) {\n    var cover = coverRenderers[brushOption.brushType].createCover(controller, brushOption);\n    cover.__brushOption = brushOption;\n    updateZ$1(cover, brushOption);\n    controller.group.add(cover);\n    return cover;\n}\n\nfunction endCreating(controller, creatingCover) {\n    var coverRenderer = getCoverRenderer(creatingCover);\n    if (coverRenderer.endCreating) {\n        coverRenderer.endCreating(controller, creatingCover);\n        updateZ$1(creatingCover, creatingCover.__brushOption);\n    }\n    return creatingCover;\n}\n\nfunction updateCoverShape(controller, cover) {\n    var brushOption = cover.__brushOption;\n    getCoverRenderer(cover).updateCoverShape(\n        controller, cover, brushOption.range, brushOption\n    );\n}\n\nfunction updateZ$1(cover, brushOption) {\n    var z = brushOption.z;\n    z == null && (z = COVER_Z);\n    cover.traverse(function (el) {\n        el.z = z;\n        el.z2 = z; // Consider in given container.\n    });\n}\n\nfunction updateCoverAfterCreation(controller, cover) {\n    getCoverRenderer(cover).updateCommon(controller, cover);\n    updateCoverShape(controller, cover);\n}\n\nfunction getCoverRenderer(cover) {\n    return coverRenderers[cover.__brushOption.brushType];\n}\n\n// return target panel or `true` (means global panel)\nfunction getPanelByPoint(controller, e, localCursorPoint) {\n    var panels = controller._panels;\n    if (!panels) {\n        return true; // Global panel\n    }\n    var panel;\n    var transform = controller._transform;\n    each$16(panels, function (pn) {\n        pn.isTargetByCursor(e, localCursorPoint, transform) && (panel = pn);\n    });\n    return panel;\n}\n\n// Return a panel or true\nfunction getPanelByCover(controller, cover) {\n    var panels = controller._panels;\n    if (!panels) {\n        return true; // Global panel\n    }\n    var panelId = cover.__brushOption.panelId;\n    // User may give cover without coord sys info,\n    // which is then treated as global panel.\n    return panelId != null ? panels[panelId] : true;\n}\n\nfunction clearCovers(controller) {\n    var covers = controller._covers;\n    var originalLength = covers.length;\n    each$16(covers, function (cover) {\n        controller.group.remove(cover);\n    }, controller);\n    covers.length = 0;\n\n    return !!originalLength;\n}\n\nfunction trigger$1(controller, opt) {\n    var areas = map$2(controller._covers, function (cover) {\n        var brushOption = cover.__brushOption;\n        var range = clone(brushOption.range);\n        return {\n            brushType: brushOption.brushType,\n            panelId: brushOption.panelId,\n            range: range\n        };\n    });\n\n    controller.trigger('brush', areas, {\n        isEnd: !!opt.isEnd,\n        removeOnClick: !!opt.removeOnClick\n    });\n}\n\nfunction shouldShowCover(controller) {\n    var track = controller._track;\n\n    if (!track.length) {\n        return false;\n    }\n\n    var p2 = track[track.length - 1];\n    var p1 = track[0];\n    var dx = p2[0] - p1[0];\n    var dy = p2[1] - p1[1];\n    var dist = mathPow$2(dx * dx + dy * dy, 0.5);\n\n    return dist > UNSELECT_THRESHOLD;\n}\n\nfunction getTrackEnds(track) {\n    var tail = track.length - 1;\n    tail < 0 && (tail = 0);\n    return [track[0], track[tail]];\n}\n\nfunction createBaseRectCover(doDrift, controller, brushOption, edgeNames) {\n    var cover = new Group();\n\n    cover.add(new Rect({\n        name: 'main',\n        style: makeStyle(brushOption),\n        silent: true,\n        draggable: true,\n        cursor: 'move',\n        drift: curry$5(doDrift, controller, cover, 'nswe'),\n        ondragend: curry$5(trigger$1, controller, {isEnd: true})\n    }));\n\n    each$16(\n        edgeNames,\n        function (name) {\n            cover.add(new Rect({\n                name: name,\n                style: {opacity: 0},\n                draggable: true,\n                silent: true,\n                invisible: true,\n                drift: curry$5(doDrift, controller, cover, name),\n                ondragend: curry$5(trigger$1, controller, {isEnd: true})\n            }));\n        }\n    );\n\n    return cover;\n}\n\nfunction updateBaseRect(controller, cover, localRange, brushOption) {\n    var lineWidth = brushOption.brushStyle.lineWidth || 0;\n    var handleSize = mathMax$4(lineWidth, MIN_RESIZE_LINE_WIDTH);\n    var x = localRange[0][0];\n    var y = localRange[1][0];\n    var xa = x - lineWidth / 2;\n    var ya = y - lineWidth / 2;\n    var x2 = localRange[0][1];\n    var y2 = localRange[1][1];\n    var x2a = x2 - handleSize + lineWidth / 2;\n    var y2a = y2 - handleSize + lineWidth / 2;\n    var width = x2 - x;\n    var height = y2 - y;\n    var widtha = width + lineWidth;\n    var heighta = height + lineWidth;\n\n    updateRectShape(controller, cover, 'main', x, y, width, height);\n\n    if (brushOption.transformable) {\n        updateRectShape(controller, cover, 'w', xa, ya, handleSize, heighta);\n        updateRectShape(controller, cover, 'e', x2a, ya, handleSize, heighta);\n        updateRectShape(controller, cover, 'n', xa, ya, widtha, handleSize);\n        updateRectShape(controller, cover, 's', xa, y2a, widtha, handleSize);\n\n        updateRectShape(controller, cover, 'nw', xa, ya, handleSize, handleSize);\n        updateRectShape(controller, cover, 'ne', x2a, ya, handleSize, handleSize);\n        updateRectShape(controller, cover, 'sw', xa, y2a, handleSize, handleSize);\n        updateRectShape(controller, cover, 'se', x2a, y2a, handleSize, handleSize);\n    }\n}\n\nfunction updateCommon(controller, cover) {\n    var brushOption = cover.__brushOption;\n    var transformable = brushOption.transformable;\n\n    var mainEl = cover.childAt(0);\n    mainEl.useStyle(makeStyle(brushOption));\n    mainEl.attr({\n        silent: !transformable,\n        cursor: transformable ? 'move' : 'default'\n    });\n\n    each$16(\n        ['w', 'e', 'n', 's', 'se', 'sw', 'ne', 'nw'],\n        function (name) {\n            var el = cover.childOfName(name);\n            var globalDir = getGlobalDirection(controller, name);\n\n            el && el.attr({\n                silent: !transformable,\n                invisible: !transformable,\n                cursor: transformable ? CURSOR_MAP[globalDir] + '-resize' : null\n            });\n        }\n    );\n}\n\nfunction updateRectShape(controller, cover, name, x, y, w, h) {\n    var el = cover.childOfName(name);\n    el && el.setShape(pointsToRect(\n        clipByPanel(controller, cover, [[x, y], [x + w, y + h]])\n    ));\n}\n\nfunction makeStyle(brushOption) {\n    return defaults({strokeNoScale: true}, brushOption.brushStyle);\n}\n\nfunction formatRectRange(x, y, x2, y2) {\n    var min = [mathMin$4(x, x2), mathMin$4(y, y2)];\n    var max = [mathMax$4(x, x2), mathMax$4(y, y2)];\n\n    return [\n        [min[0], max[0]], // x range\n        [min[1], max[1]] // y range\n    ];\n}\n\nfunction getTransform$1(controller) {\n    return getTransform(controller.group);\n}\n\nfunction getGlobalDirection(controller, localDirection) {\n    if (localDirection.length > 1) {\n        localDirection = localDirection.split('');\n        var globalDir = [\n            getGlobalDirection(controller, localDirection[0]),\n            getGlobalDirection(controller, localDirection[1])\n        ];\n        (globalDir[0] === 'e' || globalDir[0] === 'w') && globalDir.reverse();\n        return globalDir.join('');\n    }\n    else {\n        var map$$1 = {w: 'left', e: 'right', n: 'top', s: 'bottom'};\n        var inverseMap = {left: 'w', right: 'e', top: 'n', bottom: 's'};\n        var globalDir = transformDirection(\n            map$$1[localDirection], getTransform$1(controller)\n        );\n        return inverseMap[globalDir];\n    }\n}\n\nfunction driftRect(toRectRange, fromRectRange, controller, cover, name, dx, dy, e) {\n    var brushOption = cover.__brushOption;\n    var rectRange = toRectRange(brushOption.range);\n    var localDelta = toLocalDelta(controller, dx, dy);\n\n    each$16(name.split(''), function (namePart) {\n        var ind = DIRECTION_MAP[namePart];\n        rectRange[ind[0]][ind[1]] += localDelta[ind[0]];\n    });\n\n    brushOption.range = fromRectRange(formatRectRange(\n        rectRange[0][0], rectRange[1][0], rectRange[0][1], rectRange[1][1]\n    ));\n\n    updateCoverAfterCreation(controller, cover);\n    trigger$1(controller, {isEnd: false});\n}\n\nfunction driftPolygon(controller, cover, dx, dy, e) {\n    var range = cover.__brushOption.range;\n    var localDelta = toLocalDelta(controller, dx, dy);\n\n    each$16(range, function (point) {\n        point[0] += localDelta[0];\n        point[1] += localDelta[1];\n    });\n\n    updateCoverAfterCreation(controller, cover);\n    trigger$1(controller, {isEnd: false});\n}\n\nfunction toLocalDelta(controller, dx, dy) {\n    var thisGroup = controller.group;\n    var localD = thisGroup.transformCoordToLocal(dx, dy);\n    var localZero = thisGroup.transformCoordToLocal(0, 0);\n\n    return [localD[0] - localZero[0], localD[1] - localZero[1]];\n}\n\nfunction clipByPanel(controller, cover, data) {\n    var panel = getPanelByCover(controller, cover);\n\n    return (panel && panel !== true)\n        ? panel.clipPath(data, controller._transform)\n        : clone(data);\n}\n\nfunction pointsToRect(points) {\n    var xmin = mathMin$4(points[0][0], points[1][0]);\n    var ymin = mathMin$4(points[0][1], points[1][1]);\n    var xmax = mathMax$4(points[0][0], points[1][0]);\n    var ymax = mathMax$4(points[0][1], points[1][1]);\n\n    return {\n        x: xmin,\n        y: ymin,\n        width: xmax - xmin,\n        height: ymax - ymin\n    };\n}\n\nfunction resetCursor(controller, e, localCursorPoint) {\n    // Check active\n    if (!controller._brushType) {\n        return;\n    }\n\n    var zr = controller._zr;\n    var covers = controller._covers;\n    var currPanel = getPanelByPoint(controller, e, localCursorPoint);\n\n    // Check whether in covers.\n    if (!controller._dragging) {\n        for (var i = 0; i < covers.length; i++) {\n            var brushOption = covers[i].__brushOption;\n            if (currPanel\n                && (currPanel === true || brushOption.panelId === currPanel.panelId)\n                && coverRenderers[brushOption.brushType].contain(\n                    covers[i], localCursorPoint[0], localCursorPoint[1]\n                )\n            ) {\n                // Use cursor style set on cover.\n                return;\n            }\n        }\n    }\n\n    currPanel && zr.setCursorStyle('crosshair');\n}\n\nfunction preventDefault(e) {\n    var rawE = e.event;\n    rawE.preventDefault && rawE.preventDefault();\n}\n\nfunction mainShapeContain(cover, x, y) {\n    return cover.childOfName('main').contain(x, y);\n}\n\nfunction updateCoverByMouse(controller, e, localCursorPoint, isEnd) {\n    var creatingCover = controller._creatingCover;\n    var panel = controller._creatingPanel;\n    var thisBrushOption = controller._brushOption;\n    var eventParams;\n\n    controller._track.push(localCursorPoint.slice());\n\n    if (shouldShowCover(controller) || creatingCover) {\n\n        if (panel && !creatingCover) {\n            thisBrushOption.brushMode === 'single' && clearCovers(controller);\n            var brushOption = clone(thisBrushOption);\n            brushOption.brushType = determineBrushType(brushOption.brushType, panel);\n            brushOption.panelId = panel === true ? null : panel.panelId;\n            creatingCover = controller._creatingCover = createCover(controller, brushOption);\n            controller._covers.push(creatingCover);\n        }\n\n        if (creatingCover) {\n            var coverRenderer = coverRenderers[determineBrushType(controller._brushType, panel)];\n            var coverBrushOption = creatingCover.__brushOption;\n\n            coverBrushOption.range = coverRenderer.getCreatingRange(\n                clipByPanel(controller, creatingCover, controller._track)\n            );\n\n            if (isEnd) {\n                endCreating(controller, creatingCover);\n                coverRenderer.updateCommon(controller, creatingCover);\n            }\n\n            updateCoverShape(controller, creatingCover);\n\n            eventParams = {isEnd: isEnd};\n        }\n    }\n    else if (\n        isEnd\n        && thisBrushOption.brushMode === 'single'\n        && thisBrushOption.removeOnClick\n    ) {\n        // Help user to remove covers easily, only by a tiny drag, in 'single' mode.\n        // But a single click do not clear covers, because user may have casual\n        // clicks (for example, click on other component and do not expect covers\n        // disappear).\n        // Only some cover removed, trigger action, but not every click trigger action.\n        if (getPanelByPoint(controller, e, localCursorPoint) && clearCovers(controller)) {\n            eventParams = {isEnd: isEnd, removeOnClick: true};\n        }\n    }\n\n    return eventParams;\n}\n\nfunction determineBrushType(brushType, panel) {\n    if (brushType === 'auto') {\n        if (__DEV__) {\n            assert$1(\n                panel && panel.defaultBrushType,\n                'MUST have defaultBrushType when brushType is \"atuo\"'\n            );\n        }\n        return panel.defaultBrushType;\n    }\n    return brushType;\n}\n\nvar mouseHandlers = {\n\n    mousedown: function (e) {\n        if (this._dragging) {\n            // In case some browser do not support globalOut,\n            // and release mose out side the browser.\n            handleDragEnd.call(this, e);\n        }\n        else if (!e.target || !e.target.draggable) {\n\n            preventDefault(e);\n\n            var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n\n            this._creatingCover = null;\n            var panel = this._creatingPanel = getPanelByPoint(this, e, localCursorPoint);\n\n            if (panel) {\n                this._dragging = true;\n                this._track = [localCursorPoint.slice()];\n            }\n        }\n    },\n\n    mousemove: function (e) {\n        var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n\n        resetCursor(this, e, localCursorPoint);\n\n        if (this._dragging) {\n\n            preventDefault(e);\n\n            var eventParams = updateCoverByMouse(this, e, localCursorPoint, false);\n\n            eventParams && trigger$1(this, eventParams);\n        }\n    },\n\n    mouseup: handleDragEnd //,\n\n    // FIXME\n    // in tooltip, globalout should not be triggered.\n    // globalout: handleDragEnd\n};\n\nfunction handleDragEnd(e) {\n    if (this._dragging) {\n\n        preventDefault(e);\n\n        var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n        var eventParams = updateCoverByMouse(this, e, localCursorPoint, true);\n\n        this._dragging = false;\n        this._track = [];\n        this._creatingCover = null;\n\n        // trigger event shoule be at final, after procedure will be nested.\n        eventParams && trigger$1(this, eventParams);\n    }\n}\n\n/**\n * key: brushType\n * @type {Object}\n */\nvar coverRenderers = {\n\n    lineX: getLineRenderer(0),\n\n    lineY: getLineRenderer(1),\n\n    rect: {\n        createCover: function (controller, brushOption) {\n            return createBaseRectCover(\n                curry$5(\n                    driftRect,\n                    function (range) {\n                        return range;\n                    },\n                    function (range) {\n                        return range;\n                    }\n                ),\n                controller,\n                brushOption,\n                ['w', 'e', 'n', 's', 'se', 'sw', 'ne', 'nw']\n            );\n        },\n        getCreatingRange: function (localTrack) {\n            var ends = getTrackEnds(localTrack);\n            return formatRectRange(ends[1][0], ends[1][1], ends[0][0], ends[0][1]);\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            updateBaseRect(controller, cover, localRange, brushOption);\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    },\n\n    polygon: {\n        createCover: function (controller, brushOption) {\n            var cover = new Group();\n\n            // Do not use graphic.Polygon because graphic.Polyline do not close the\n            // border of the shape when drawing, which is a better experience for user.\n            cover.add(new Polyline({\n                name: 'main',\n                style: makeStyle(brushOption),\n                silent: true\n            }));\n\n            return cover;\n        },\n        getCreatingRange: function (localTrack) {\n            return localTrack;\n        },\n        endCreating: function (controller, cover) {\n            cover.remove(cover.childAt(0));\n            // Use graphic.Polygon close the shape.\n            cover.add(new Polygon({\n                name: 'main',\n                draggable: true,\n                drift: curry$5(driftPolygon, controller, cover),\n                ondragend: curry$5(trigger$1, controller, {isEnd: true})\n            }));\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            cover.childAt(0).setShape({\n                points: clipByPanel(controller, cover, localRange)\n            });\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    }\n};\n\nfunction getLineRenderer(xyIndex) {\n    return {\n        createCover: function (controller, brushOption) {\n            return createBaseRectCover(\n                curry$5(\n                    driftRect,\n                    function (range) {\n                        var rectRange = [range, [0, 100]];\n                        xyIndex && rectRange.reverse();\n                        return rectRange;\n                    },\n                    function (rectRange) {\n                        return rectRange[xyIndex];\n                    }\n                ),\n                controller,\n                brushOption,\n                [['w', 'e'], ['n', 's']][xyIndex]\n            );\n        },\n        getCreatingRange: function (localTrack) {\n            var ends = getTrackEnds(localTrack);\n            var min = mathMin$4(ends[0][xyIndex], ends[1][xyIndex]);\n            var max = mathMax$4(ends[0][xyIndex], ends[1][xyIndex]);\n\n            return [min, max];\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            var otherExtent;\n            // If brushWidth not specified, fit the panel.\n            var panel = getPanelByCover(controller, cover);\n            if (panel !== true && panel.getLinearBrushOtherExtent) {\n                otherExtent = panel.getLinearBrushOtherExtent(\n                    xyIndex, controller._transform\n                );\n            }\n            else {\n                var zr = controller._zr;\n                otherExtent = [0, [zr.getWidth(), zr.getHeight()][1 - xyIndex]];\n            }\n            var rectRange = [localRange, otherExtent];\n            xyIndex && rectRange.reverse();\n\n            updateBaseRect(controller, cover, rectRange, brushOption);\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar IRRELEVANT_EXCLUDES = {'axisPointer': 1, 'tooltip': 1, 'brush': 1};\n\n/**\n * Avoid that: mouse click on a elements that is over geo or graph,\n * but roam is triggered.\n */\nfunction onIrrelevantElement(e, api, targetCoordSysModel) {\n    var model = api.getComponentByElement(e.topTarget);\n    // If model is axisModel, it works only if it is injected with coordinateSystem.\n    var coordSys = model && model.coordinateSystem;\n    return model\n        && model !== targetCoordSysModel\n        && !IRRELEVANT_EXCLUDES[model.mainType]\n        && (coordSys && coordSys.model !== targetCoordSysModel);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction makeRectPanelClipPath(rect) {\n    rect = normalizeRect(rect);\n    return function (localPoints, transform) {\n        return clipPointsByRect(localPoints, rect);\n    };\n}\n\nfunction makeLinearBrushOtherExtent(rect, specifiedXYIndex) {\n    rect = normalizeRect(rect);\n    return function (xyIndex) {\n        var idx = specifiedXYIndex != null ? specifiedXYIndex : xyIndex;\n        var brushWidth = idx ? rect.width : rect.height;\n        var base = idx ? rect.x : rect.y;\n        return [base, base + (brushWidth || 0)];\n    };\n}\n\nfunction makeRectIsTargetByCursor(rect, api, targetModel) {\n    rect = normalizeRect(rect);\n    return function (e, localCursorPoint, transform) {\n        return rect.contain(localCursorPoint[0], localCursorPoint[1])\n            && !onIrrelevantElement(e, api, targetModel);\n    };\n}\n\n// Consider width/height is negative.\nfunction normalizeRect(rect) {\n    return BoundingRect.create(rect);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$17 = each$1;\nvar indexOf$2 = indexOf;\nvar curry$6 = curry;\n\nvar COORD_CONVERTS = ['dataToPoint', 'pointToData'];\n\n// FIXME\n// how to genarialize to more coordinate systems.\nvar INCLUDE_FINDER_MAIN_TYPES = [\n    'grid', 'xAxis', 'yAxis', 'geo', 'graph',\n    'polar', 'radiusAxis', 'angleAxis', 'bmap'\n];\n\n/**\n * [option in constructor]:\n * {\n *     Index/Id/Name of geo, xAxis, yAxis, grid: See util/model#parseFinder.\n * }\n *\n *\n * [targetInfo]:\n *\n * There can be multiple axes in a single targetInfo. Consider the case\n * of `grid` component, a targetInfo represents a grid which contains one or more\n * cartesian and one or more axes. And consider the case of parallel system,\n * which has multiple axes in a coordinate system.\n * Can be {\n *     panelId: ...,\n *     coordSys: <a representitive cartesian in grid (first cartesian by default)>,\n *     coordSyses: all cartesians.\n *     gridModel: <grid component>\n *     xAxes: correspond to coordSyses on index\n *     yAxes: correspond to coordSyses on index\n * }\n * or {\n *     panelId: ...,\n *     coordSys: <geo coord sys>\n *     coordSyses: [<geo coord sys>]\n *     geoModel: <geo component>\n * }\n *\n *\n * [panelOpt]:\n *\n * Make from targetInfo. Input to BrushController.\n * {\n *     panelId: ...,\n *     rect: ...\n * }\n *\n *\n * [area]:\n *\n * Generated by BrushController or user input.\n * {\n *     panelId: Used to locate coordInfo directly. If user inpput, no panelId.\n *     brushType: determine how to convert to/from coord('rect' or 'polygon' or 'lineX/Y').\n *     Index/Id/Name of geo, xAxis, yAxis, grid: See util/model#parseFinder.\n *     range: pixel range.\n *     coordRange: representitive coord range (the first one of coordRanges).\n *     coordRanges: <Array> coord ranges, used in multiple cartesian in one grid.\n * }\n */\n\n/**\n * @param {Object} option contains Index/Id/Name of xAxis/yAxis/geo/grid\n *        Each can be {number|Array.<number>}. like: {xAxisIndex: [3, 4]}\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} [opt]\n * @param {Array.<string>} [opt.include] include coordinate system types.\n */\nfunction BrushTargetManager(option, ecModel, opt) {\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    var targetInfoList = this._targetInfoList = [];\n    var info = {};\n    var foundCpts = parseFinder$1(ecModel, option);\n\n    each$17(targetInfoBuilders, function (builder, type) {\n        if (!opt || !opt.include || indexOf$2(opt.include, type) >= 0) {\n            builder(foundCpts, targetInfoList, info);\n        }\n    });\n}\n\nvar proto$5 = BrushTargetManager.prototype;\n\nproto$5.setOutputRanges = function (areas, ecModel) {\n    this.matchOutputRanges(areas, ecModel, function (area, coordRange, coordSys) {\n        (area.coordRanges || (area.coordRanges = [])).push(coordRange);\n        // area.coordRange is the first of area.coordRanges\n        if (!area.coordRange) {\n            area.coordRange = coordRange;\n            // In 'category' axis, coord to pixel is not reversible, so we can not\n            // rebuild range by coordRange accrately, which may bring trouble when\n            // brushing only one item. So we use __rangeOffset to rebuilding range\n            // by coordRange. And this it only used in brush component so it is no\n            // need to be adapted to coordRanges.\n            var result = coordConvert[area.brushType](0, coordSys, coordRange);\n            area.__rangeOffset = {\n                offset: diffProcessor[area.brushType](result.values, area.range, [1, 1]),\n                xyMinMax: result.xyMinMax\n            };\n        }\n    });\n};\n\nproto$5.matchOutputRanges = function (areas, ecModel, cb) {\n    each$17(areas, function (area) {\n        var targetInfo = this.findTargetInfo(area, ecModel);\n\n        if (targetInfo && targetInfo !== true) {\n            each$1(\n                targetInfo.coordSyses,\n                function (coordSys) {\n                    var result = coordConvert[area.brushType](1, coordSys, area.range);\n                    cb(area, result.values, coordSys, ecModel);\n                }\n            );\n        }\n    }, this);\n};\n\nproto$5.setInputRanges = function (areas, ecModel) {\n    each$17(areas, function (area) {\n        var targetInfo = this.findTargetInfo(area, ecModel);\n\n        if (__DEV__) {\n            assert$1(\n                !targetInfo || targetInfo === true || area.coordRange,\n                'coordRange must be specified when coord index specified.'\n            );\n            assert$1(\n                !targetInfo || targetInfo !== true || area.range,\n                'range must be specified in global brush.'\n            );\n        }\n\n        area.range = area.range || [];\n\n        // convert coordRange to global range and set panelId.\n        if (targetInfo && targetInfo !== true) {\n            area.panelId = targetInfo.panelId;\n            // (1) area.range shoule always be calculate from coordRange but does\n            // not keep its original value, for the sake of the dataZoom scenario,\n            // where area.coordRange remains unchanged but area.range may be changed.\n            // (2) Only support converting one coordRange to pixel range in brush\n            // component. So do not consider `coordRanges`.\n            // (3) About __rangeOffset, see comment above.\n            var result = coordConvert[area.brushType](0, targetInfo.coordSys, area.coordRange);\n            var rangeOffset = area.__rangeOffset;\n            area.range = rangeOffset\n                ? diffProcessor[area.brushType](\n                    result.values,\n                    rangeOffset.offset,\n                    getScales(result.xyMinMax, rangeOffset.xyMinMax)\n                )\n                : result.values;\n        }\n    }, this);\n};\n\nproto$5.makePanelOpts = function (api, getDefaultBrushType) {\n    return map(this._targetInfoList, function (targetInfo) {\n        var rect = targetInfo.getPanelRect();\n        return {\n            panelId: targetInfo.panelId,\n            defaultBrushType: getDefaultBrushType && getDefaultBrushType(targetInfo),\n            clipPath: makeRectPanelClipPath(rect),\n            isTargetByCursor: makeRectIsTargetByCursor(\n                rect, api, targetInfo.coordSysModel\n            ),\n            getLinearBrushOtherExtent: makeLinearBrushOtherExtent(rect)\n        };\n    });\n};\n\nproto$5.controlSeries = function (area, seriesModel, ecModel) {\n    // Check whether area is bound in coord, and series do not belong to that coord.\n    // If do not do this check, some brush (like lineX) will controll all axes.\n    var targetInfo = this.findTargetInfo(area, ecModel);\n    return targetInfo === true || (\n        targetInfo && indexOf$2(targetInfo.coordSyses, seriesModel.coordinateSystem) >= 0\n    );\n};\n\n/**\n * If return Object, a coord found.\n * If reutrn true, global found.\n * Otherwise nothing found.\n *\n * @param {Object} area\n * @param {Array} targetInfoList\n * @return {Object|boolean}\n */\nproto$5.findTargetInfo = function (area, ecModel) {\n    var targetInfoList = this._targetInfoList;\n    var foundCpts = parseFinder$1(ecModel, area);\n\n    for (var i = 0; i < targetInfoList.length; i++) {\n        var targetInfo = targetInfoList[i];\n        var areaPanelId = area.panelId;\n        if (areaPanelId) {\n            if (targetInfo.panelId === areaPanelId) {\n                return targetInfo;\n            }\n        }\n        else {\n            for (var i = 0; i < targetInfoMatchers.length; i++) {\n                if (targetInfoMatchers[i](foundCpts, targetInfo)) {\n                    return targetInfo;\n                }\n            }\n        }\n    }\n\n    return true;\n};\n\nfunction formatMinMax(minMax) {\n    minMax[0] > minMax[1] && minMax.reverse();\n    return minMax;\n}\n\nfunction parseFinder$1(ecModel, option) {\n    return parseFinder(\n        ecModel, option, {includeMainTypes: INCLUDE_FINDER_MAIN_TYPES}\n    );\n}\n\nvar targetInfoBuilders = {\n\n    grid: function (foundCpts, targetInfoList) {\n        var xAxisModels = foundCpts.xAxisModels;\n        var yAxisModels = foundCpts.yAxisModels;\n        var gridModels = foundCpts.gridModels;\n        // Remove duplicated.\n        var gridModelMap = createHashMap();\n        var xAxesHas = {};\n        var yAxesHas = {};\n\n        if (!xAxisModels && !yAxisModels && !gridModels) {\n            return;\n        }\n\n        each$17(xAxisModels, function (axisModel) {\n            var gridModel = axisModel.axis.grid.model;\n            gridModelMap.set(gridModel.id, gridModel);\n            xAxesHas[gridModel.id] = true;\n        });\n        each$17(yAxisModels, function (axisModel) {\n            var gridModel = axisModel.axis.grid.model;\n            gridModelMap.set(gridModel.id, gridModel);\n            yAxesHas[gridModel.id] = true;\n        });\n        each$17(gridModels, function (gridModel) {\n            gridModelMap.set(gridModel.id, gridModel);\n            xAxesHas[gridModel.id] = true;\n            yAxesHas[gridModel.id] = true;\n        });\n\n        gridModelMap.each(function (gridModel) {\n            var grid = gridModel.coordinateSystem;\n            var cartesians = [];\n\n            each$17(grid.getCartesians(), function (cartesian, index) {\n                if (indexOf$2(xAxisModels, cartesian.getAxis('x').model) >= 0\n                    || indexOf$2(yAxisModels, cartesian.getAxis('y').model) >= 0\n                ) {\n                    cartesians.push(cartesian);\n                }\n            });\n            targetInfoList.push({\n                panelId: 'grid--' + gridModel.id,\n                gridModel: gridModel,\n                coordSysModel: gridModel,\n                // Use the first one as the representitive coordSys.\n                coordSys: cartesians[0],\n                coordSyses: cartesians,\n                getPanelRect: panelRectBuilder.grid,\n                xAxisDeclared: xAxesHas[gridModel.id],\n                yAxisDeclared: yAxesHas[gridModel.id]\n            });\n        });\n    },\n\n    geo: function (foundCpts, targetInfoList) {\n        each$17(foundCpts.geoModels, function (geoModel) {\n            var coordSys = geoModel.coordinateSystem;\n            targetInfoList.push({\n                panelId: 'geo--' + geoModel.id,\n                geoModel: geoModel,\n                coordSysModel: geoModel,\n                coordSys: coordSys,\n                coordSyses: [coordSys],\n                getPanelRect: panelRectBuilder.geo\n            });\n        });\n    }\n};\n\nvar targetInfoMatchers = [\n\n    // grid\n    function (foundCpts, targetInfo) {\n        var xAxisModel = foundCpts.xAxisModel;\n        var yAxisModel = foundCpts.yAxisModel;\n        var gridModel = foundCpts.gridModel;\n\n        !gridModel && xAxisModel && (gridModel = xAxisModel.axis.grid.model);\n        !gridModel && yAxisModel && (gridModel = yAxisModel.axis.grid.model);\n\n        return gridModel && gridModel === targetInfo.gridModel;\n    },\n\n    // geo\n    function (foundCpts, targetInfo) {\n        var geoModel = foundCpts.geoModel;\n        return geoModel && geoModel === targetInfo.geoModel;\n    }\n];\n\nvar panelRectBuilder = {\n\n    grid: function () {\n        // grid is not Transformable.\n        return this.coordSys.grid.getRect().clone();\n    },\n\n    geo: function () {\n        var coordSys = this.coordSys;\n        var rect = coordSys.getBoundingRect().clone();\n        // geo roam and zoom transform\n        rect.applyTransform(getTransform(coordSys));\n        return rect;\n    }\n};\n\nvar coordConvert = {\n\n    lineX: curry$6(axisConvert, 0),\n\n    lineY: curry$6(axisConvert, 1),\n\n    rect: function (to, coordSys, rangeOrCoordRange) {\n        var xminymin = coordSys[COORD_CONVERTS[to]]([rangeOrCoordRange[0][0], rangeOrCoordRange[1][0]]);\n        var xmaxymax = coordSys[COORD_CONVERTS[to]]([rangeOrCoordRange[0][1], rangeOrCoordRange[1][1]]);\n        var values = [\n            formatMinMax([xminymin[0], xmaxymax[0]]),\n            formatMinMax([xminymin[1], xmaxymax[1]])\n        ];\n        return {values: values, xyMinMax: values};\n    },\n\n    polygon: function (to, coordSys, rangeOrCoordRange) {\n        var xyMinMax = [[Infinity, -Infinity], [Infinity, -Infinity]];\n        var values = map(rangeOrCoordRange, function (item) {\n            var p = coordSys[COORD_CONVERTS[to]](item);\n            xyMinMax[0][0] = Math.min(xyMinMax[0][0], p[0]);\n            xyMinMax[1][0] = Math.min(xyMinMax[1][0], p[1]);\n            xyMinMax[0][1] = Math.max(xyMinMax[0][1], p[0]);\n            xyMinMax[1][1] = Math.max(xyMinMax[1][1], p[1]);\n            return p;\n        });\n        return {values: values, xyMinMax: xyMinMax};\n    }\n};\n\nfunction axisConvert(axisNameIndex, to, coordSys, rangeOrCoordRange) {\n    if (__DEV__) {\n        assert$1(\n            coordSys.type === 'cartesian2d',\n            'lineX/lineY brush is available only in cartesian2d.'\n        );\n    }\n\n    var axis = coordSys.getAxis(['x', 'y'][axisNameIndex]);\n    var values = formatMinMax(map([0, 1], function (i) {\n        return to\n            ? axis.coordToData(axis.toLocalCoord(rangeOrCoordRange[i]))\n            : axis.toGlobalCoord(axis.dataToCoord(rangeOrCoordRange[i]));\n    }));\n    var xyMinMax = [];\n    xyMinMax[axisNameIndex] = values;\n    xyMinMax[1 - axisNameIndex] = [NaN, NaN];\n\n    return {values: values, xyMinMax: xyMinMax};\n}\n\nvar diffProcessor = {\n    lineX: curry$6(axisDiffProcessor, 0),\n\n    lineY: curry$6(axisDiffProcessor, 1),\n\n    rect: function (values, refer, scales) {\n        return [\n            [values[0][0] - scales[0] * refer[0][0], values[0][1] - scales[0] * refer[0][1]],\n            [values[1][0] - scales[1] * refer[1][0], values[1][1] - scales[1] * refer[1][1]]\n        ];\n    },\n\n    polygon: function (values, refer, scales) {\n        return map(values, function (item, idx) {\n            return [item[0] - scales[0] * refer[idx][0], item[1] - scales[1] * refer[idx][1]];\n        });\n    }\n};\n\nfunction axisDiffProcessor(axisNameIndex, values, refer, scales) {\n    return [\n        values[0] - scales[axisNameIndex] * refer[0],\n        values[1] - scales[axisNameIndex] * refer[1]\n    ];\n}\n\n// We have to process scale caused by dataZoom manually,\n// although it might be not accurate.\nfunction getScales(xyMinMaxCurr, xyMinMaxOrigin) {\n    var sizeCurr = getSize(xyMinMaxCurr);\n    var sizeOrigin = getSize(xyMinMaxOrigin);\n    var scales = [sizeCurr[0] / sizeOrigin[0], sizeCurr[1] / sizeOrigin[1]];\n    isNaN(scales[0]) && (scales[0] = 1);\n    isNaN(scales[1]) && (scales[1] = 1);\n    return scales;\n}\n\nfunction getSize(xyMinMax) {\n    return xyMinMax\n        ? [xyMinMax[0][1] - xyMinMax[0][0], xyMinMax[1][1] - xyMinMax[1][0]]\n        : [NaN, NaN];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$18 = each$1;\n\nvar ATTR$2 = '\\0_ec_hist_store';\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} newSnapshot {dataZoomId, batch: [payloadInfo, ...]}\n */\nfunction push(ecModel, newSnapshot) {\n    var store = giveStore$1(ecModel);\n\n    // If previous dataZoom can not be found,\n    // complete an range with current range.\n    each$18(newSnapshot, function (batchItem, dataZoomId) {\n        var i = store.length - 1;\n        for (; i >= 0; i--) {\n            var snapshot = store[i];\n            if (snapshot[dataZoomId]) {\n                break;\n            }\n        }\n        if (i < 0) {\n            // No origin range set, create one by current range.\n            var dataZoomModel = ecModel.queryComponents(\n                {mainType: 'dataZoom', subType: 'select', id: dataZoomId}\n            )[0];\n            if (dataZoomModel) {\n                var percentRange = dataZoomModel.getPercentRange();\n                store[0][dataZoomId] = {\n                    dataZoomId: dataZoomId,\n                    start: percentRange[0],\n                    end: percentRange[1]\n                };\n            }\n        }\n    });\n\n    store.push(newSnapshot);\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @return {Object} snapshot\n */\nfunction pop(ecModel) {\n    var store = giveStore$1(ecModel);\n    var head = store[store.length - 1];\n    store.length > 1 && store.pop();\n\n    // Find top for all dataZoom.\n    var snapshot = {};\n    each$18(head, function (batchItem, dataZoomId) {\n        for (var i = store.length - 1; i >= 0; i--) {\n            var batchItem = store[i][dataZoomId];\n            if (batchItem) {\n                snapshot[dataZoomId] = batchItem;\n                break;\n            }\n        }\n    });\n\n    return snapshot;\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n */\nfunction clear$1(ecModel) {\n    ecModel[ATTR$2] = null;\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @return {number} records. always >= 1.\n */\nfunction count(ecModel) {\n    return giveStore$1(ecModel).length;\n}\n\n/**\n * [{key: dataZoomId, value: {dataZoomId, range}}, ...]\n * History length of each dataZoom may be different.\n * this._history[0] is used to store origin range.\n * @type {Array.<Object>}\n */\nfunction giveStore$1(ecModel) {\n    var store = ecModel[ATTR$2];\n    if (!store) {\n        store = ecModel[ATTR$2] = [{}];\n    }\n    return store;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomModel.extend({\n    type: 'dataZoom.select'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomView.extend({\n    type: 'dataZoom.select'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Use dataZoomSelect\nvar dataZoomLang = lang.toolbox.dataZoom;\nvar each$15 = each$1;\n\n// Spectial component id start with \\0ec\\0, see echarts/model/Global.js~hasInnerId\nvar DATA_ZOOM_ID_BASE = '\\0_ec_\\0toolbox-dataZoom_';\n\nfunction DataZoom(model, ecModel, api) {\n\n    /**\n     * @private\n     * @type {module:echarts/component/helper/BrushController}\n     */\n    (this._brushController = new BrushController(api.getZr()))\n        .on('brush', bind(this._onBrush, this))\n        .mount();\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._isZoomActive;\n}\n\nDataZoom.defaultOption = {\n    show: true,\n    // Icon group\n    icon: {\n        zoom: 'M0,13.5h26.9 M13.5,26.9V0 M32.1,13.5H58V58H13.5 V32.1',\n        back: 'M22,1.4L9.9,13.5l12.3,12.3 M10.3,13.5H54.9v44.6 H10.3v-26'\n    },\n    // `zoom`, `back`\n    title: clone(dataZoomLang.title)\n};\n\nvar proto$4 = DataZoom.prototype;\n\nproto$4.render = function (featureModel, ecModel, api, payload) {\n    this.model = featureModel;\n    this.ecModel = ecModel;\n    this.api = api;\n\n    updateZoomBtnStatus(featureModel, ecModel, this, payload, api);\n    updateBackBtnStatus(featureModel, ecModel);\n};\n\nproto$4.onclick = function (ecModel, api, type) {\n    handlers[type].call(this);\n};\n\nproto$4.remove = function (ecModel, api) {\n    this._brushController.unmount();\n};\n\nproto$4.dispose = function (ecModel, api) {\n    this._brushController.dispose();\n};\n\n/**\n * @private\n */\nvar handlers = {\n\n    zoom: function () {\n        var nextActive = !this._isZoomActive;\n\n        this.api.dispatchAction({\n            type: 'takeGlobalCursor',\n            key: 'dataZoomSelect',\n            dataZoomSelectActive: nextActive\n        });\n    },\n\n    back: function () {\n        this._dispatchZoomAction(pop(this.ecModel));\n    }\n};\n\n/**\n * @private\n */\nproto$4._onBrush = function (areas, opt) {\n    if (!opt.isEnd || !areas.length) {\n        return;\n    }\n    var snapshot = {};\n    var ecModel = this.ecModel;\n\n    this._brushController.updateCovers([]); // remove cover\n\n    var brushTargetManager = new BrushTargetManager(\n        retrieveAxisSetting(this.model.option), ecModel, {include: ['grid']}\n    );\n    brushTargetManager.matchOutputRanges(areas, ecModel, function (area, coordRange, coordSys) {\n        if (coordSys.type !== 'cartesian2d') {\n            return;\n        }\n\n        var brushType = area.brushType;\n        if (brushType === 'rect') {\n            setBatch('x', coordSys, coordRange[0]);\n            setBatch('y', coordSys, coordRange[1]);\n        }\n        else {\n            setBatch(({lineX: 'x', lineY: 'y'})[brushType], coordSys, coordRange);\n        }\n    });\n\n    push(ecModel, snapshot);\n\n    this._dispatchZoomAction(snapshot);\n\n    function setBatch(dimName, coordSys, minMax) {\n        var axis = coordSys.getAxis(dimName);\n        var axisModel = axis.model;\n        var dataZoomModel = findDataZoom(dimName, axisModel, ecModel);\n\n        // Restrict range.\n        var minMaxSpan = dataZoomModel.findRepresentativeAxisProxy(axisModel).getMinMaxSpan();\n        if (minMaxSpan.minValueSpan != null || minMaxSpan.maxValueSpan != null) {\n            minMax = sliderMove(\n                0, minMax.slice(), axis.scale.getExtent(), 0,\n                minMaxSpan.minValueSpan, minMaxSpan.maxValueSpan\n            );\n        }\n\n        dataZoomModel && (snapshot[dataZoomModel.id] = {\n            dataZoomId: dataZoomModel.id,\n            startValue: minMax[0],\n            endValue: minMax[1]\n        });\n    }\n\n    function findDataZoom(dimName, axisModel, ecModel) {\n        var found;\n        ecModel.eachComponent({mainType: 'dataZoom', subType: 'select'}, function (dzModel) {\n            var has = dzModel.getAxisModel(dimName, axisModel.componentIndex);\n            has && (found = dzModel);\n        });\n        return found;\n    }\n};\n\n/**\n * @private\n */\nproto$4._dispatchZoomAction = function (snapshot) {\n    var batch = [];\n\n    // Convert from hash map to array.\n    each$15(snapshot, function (batchItem, dataZoomId) {\n        batch.push(clone(batchItem));\n    });\n\n    batch.length && this.api.dispatchAction({\n        type: 'dataZoom',\n        from: this.uid,\n        batch: batch\n    });\n};\n\nfunction retrieveAxisSetting(option) {\n    var setting = {};\n    // Compatible with previous setting: null => all axis, false => no axis.\n    each$1(['xAxisIndex', 'yAxisIndex'], function (name) {\n        setting[name] = option[name];\n        setting[name] == null && (setting[name] = 'all');\n        (setting[name] === false || setting[name] === 'none') && (setting[name] = []);\n    });\n    return setting;\n}\n\nfunction updateBackBtnStatus(featureModel, ecModel) {\n    featureModel.setIconStatus(\n        'back',\n        count(ecModel) > 1 ? 'emphasis' : 'normal'\n    );\n}\n\nfunction updateZoomBtnStatus(featureModel, ecModel, view, payload, api) {\n    var zoomActive = view._isZoomActive;\n\n    if (payload && payload.type === 'takeGlobalCursor') {\n        zoomActive = payload.key === 'dataZoomSelect'\n            ? payload.dataZoomSelectActive : false;\n    }\n\n    view._isZoomActive = zoomActive;\n\n    featureModel.setIconStatus('zoom', zoomActive ? 'emphasis' : 'normal');\n\n    var brushTargetManager = new BrushTargetManager(\n        retrieveAxisSetting(featureModel.option), ecModel, {include: ['grid']}\n    );\n\n    view._brushController\n        .setPanels(brushTargetManager.makePanelOpts(api, function (targetInfo) {\n            return (targetInfo.xAxisDeclared && !targetInfo.yAxisDeclared)\n                ? 'lineX'\n                : (!targetInfo.xAxisDeclared && targetInfo.yAxisDeclared)\n                ? 'lineY'\n                : 'rect';\n        }))\n        .enableBrush(\n            zoomActive\n            ? {\n                brushType: 'auto',\n                brushStyle: {\n                    // FIXME user customized?\n                    lineWidth: 0,\n                    fill: 'rgba(0,0,0,0.2)'\n                }\n            }\n            : false\n        );\n}\n\n\nregister$2('dataZoom', DataZoom);\n\n\n// Create special dataZoom option for select\n// FIXME consider the case of merge option, where axes options are not exists.\nregisterPreprocessor(function (option) {\n    if (!option) {\n        return;\n    }\n\n    var dataZoomOpts = option.dataZoom || (option.dataZoom = []);\n    if (!isArray(dataZoomOpts)) {\n        option.dataZoom = dataZoomOpts = [dataZoomOpts];\n    }\n\n    var toolboxOpt = option.toolbox;\n    if (toolboxOpt) {\n        // Assume there is only one toolbox\n        if (isArray(toolboxOpt)) {\n            toolboxOpt = toolboxOpt[0];\n        }\n\n        if (toolboxOpt && toolboxOpt.feature) {\n            var dataZoomOpt = toolboxOpt.feature.dataZoom;\n            // FIXME: If add dataZoom when setOption in merge mode,\n            // no axis info to be added. See `test/dataZoom-extreme.html`\n            addForAxis('xAxis', dataZoomOpt);\n            addForAxis('yAxis', dataZoomOpt);\n        }\n    }\n\n    function addForAxis(axisName, dataZoomOpt) {\n        if (!dataZoomOpt) {\n            return;\n        }\n\n        // Try not to modify model, because it is not merged yet.\n        var axisIndicesName = axisName + 'Index';\n        var givenAxisIndices = dataZoomOpt[axisIndicesName];\n        if (givenAxisIndices != null\n            && givenAxisIndices !== 'all'\n            && !isArray(givenAxisIndices)\n        ) {\n            givenAxisIndices = (givenAxisIndices === false || givenAxisIndices === 'none') ? [] : [givenAxisIndices];\n        }\n\n        forEachComponent(axisName, function (axisOpt, axisIndex) {\n            if (givenAxisIndices != null\n                && givenAxisIndices !== 'all'\n                && indexOf(givenAxisIndices, axisIndex) === -1\n            ) {\n                return;\n            }\n            var newOpt = {\n                type: 'select',\n                $fromToolbox: true,\n                // Id for merge mapping.\n                id: DATA_ZOOM_ID_BASE + axisName + axisIndex\n            };\n            // FIXME\n            // Only support one axis now.\n            newOpt[axisIndicesName] = axisIndex;\n            dataZoomOpts.push(newOpt);\n        });\n    }\n\n    function forEachComponent(mainType, cb) {\n        var opts = option[mainType];\n        if (!isArray(opts)) {\n            opts = opts ? [opts] : [];\n        }\n        each$15(opts, cb);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar restoreLang = lang.toolbox.restore;\n\nfunction Restore(model) {\n    this.model = model;\n}\n\nRestore.defaultOption = {\n    show: true,\n    /* eslint-disable */\n    icon: 'M3.8,33.4 M47,18.9h9.8V8.7 M56.3,20.1 C52.1,9,40.5,0.6,26.8,2.1C12.6,3.7,1.6,16.2,2.1,30.6 M13,41.1H3.1v10.2 M3.7,39.9c4.2,11.1,15.8,19.5,29.5,18 c14.2-1.6,25.2-14.1,24.7-28.5',\n    /* eslint-enable */\n    title: restoreLang.title\n};\n\nvar proto$6 = Restore.prototype;\n\nproto$6.onclick = function (ecModel, api, type) {\n    clear$1(ecModel);\n\n    api.dispatchAction({\n        type: 'restore',\n        from: this.uid\n    });\n};\n\nregister$2('restore', Restore);\n\nregisterAction(\n    {type: 'restore', event: 'restore', update: 'prepareAndUpdate'},\n    function (payload, ecModel) {\n        ecModel.resetOption('recreate');\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar urn = 'urn:schemas-microsoft-com:vml';\nvar win = typeof window === 'undefined' ? null : window;\n\nvar vmlInited = false;\n\nvar doc = win && win.document;\n\nfunction createNode(tagName) {\n    return doCreateNode(tagName);\n}\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar doCreateNode;\n\nif (doc && !env$1.canvasSupported) {\n    try {\n        !doc.namespaces.zrvml && doc.namespaces.add('zrvml', urn);\n        doCreateNode = function (tagName) {\n            return doc.createElement('<zrvml:' + tagName + ' class=\"zrvml\">');\n        };\n    }\n    catch (e) {\n        doCreateNode = function (tagName) {\n            return doc.createElement('<' + tagName + ' xmlns=\"' + urn + '\" class=\"zrvml\">');\n        };\n    }\n}\n\n// From raphael\nfunction initVML() {\n    if (vmlInited || !doc) {\n        return;\n    }\n    vmlInited = true;\n\n    var styleSheets = doc.styleSheets;\n    if (styleSheets.length < 31) {\n        doc.createStyleSheet().addRule('.zrvml', 'behavior:url(#default#VML)');\n    }\n    else {\n        // http://msdn.microsoft.com/en-us/library/ms531194%28VS.85%29.aspx\n        styleSheets[0].addRule('.zrvml', 'behavior:url(#default#VML)');\n    }\n}\n\n// http://www.w3.org/TR/NOTE-VML\n// TODO Use proxy like svg instead of overwrite brush methods\n\nvar CMD$3 = PathProxy.CMD;\nvar round$3 = Math.round;\nvar sqrt = Math.sqrt;\nvar abs$1 = Math.abs;\nvar cos = Math.cos;\nvar sin = Math.sin;\nvar mathMax$5 = Math.max;\n\nif (!env$1.canvasSupported) {\n\n    var comma = ',';\n    var imageTransformPrefix = 'progid:DXImageTransform.Microsoft';\n\n    var Z = 21600;\n    var Z2 = Z / 2;\n\n    var ZLEVEL_BASE = 100000;\n    var Z_BASE = 1000;\n\n    var initRootElStyle = function (el) {\n        el.style.cssText = 'position:absolute;left:0;top:0;width:1px;height:1px;';\n        el.coordsize = Z + ',' + Z;\n        el.coordorigin = '0,0';\n    };\n\n    var encodeHtmlAttribute = function (s) {\n        return String(s).replace(/&/g, '&amp;').replace(/\"/g, '&quot;');\n    };\n\n    var rgb2Str = function (r, g, b) {\n        return 'rgb(' + [r, g, b].join(',') + ')';\n    };\n\n    var append = function (parent, child) {\n        if (child && parent && child.parentNode !== parent) {\n            parent.appendChild(child);\n        }\n    };\n\n    var remove = function (parent, child) {\n        if (child && parent && child.parentNode === parent) {\n            parent.removeChild(child);\n        }\n    };\n\n    var getZIndex = function (zlevel, z, z2) {\n        // z 的取值范围为 [0, 1000]\n        return (parseFloat(zlevel) || 0) * ZLEVEL_BASE + (parseFloat(z) || 0) * Z_BASE + z2;\n    };\n\n    var parsePercent$3 = function (value, maxValue) {\n        if (typeof value === 'string') {\n            if (value.lastIndexOf('%') >= 0) {\n                return parseFloat(value) / 100 * maxValue;\n            }\n            return parseFloat(value);\n        }\n        return value;\n    };\n\n    /***************************************************\n     * PATH\n     **************************************************/\n\n    var setColorAndOpacity = function (el, color, opacity) {\n        var colorArr = parse(color);\n        opacity = +opacity;\n        if (isNaN(opacity)) {\n            opacity = 1;\n        }\n        if (colorArr) {\n            el.color = rgb2Str(colorArr[0], colorArr[1], colorArr[2]);\n            el.opacity = opacity * colorArr[3];\n        }\n    };\n\n    var getColorAndAlpha = function (color) {\n        var colorArr = parse(color);\n        return [\n            rgb2Str(colorArr[0], colorArr[1], colorArr[2]),\n            colorArr[3]\n        ];\n    };\n\n    var updateFillNode = function (el, style, zrEl) {\n        // TODO pattern\n        var fill = style.fill;\n        if (fill != null) {\n            // Modified from excanvas\n            if (fill instanceof Gradient) {\n                var gradientType;\n                var angle = 0;\n                var focus = [0, 0];\n                // additional offset\n                var shift = 0;\n                // scale factor for offset\n                var expansion = 1;\n                var rect = zrEl.getBoundingRect();\n                var rectWidth = rect.width;\n                var rectHeight = rect.height;\n                if (fill.type === 'linear') {\n                    gradientType = 'gradient';\n                    var transform = zrEl.transform;\n                    var p0 = [fill.x * rectWidth, fill.y * rectHeight];\n                    var p1 = [fill.x2 * rectWidth, fill.y2 * rectHeight];\n                    if (transform) {\n                        applyTransform(p0, p0, transform);\n                        applyTransform(p1, p1, transform);\n                    }\n                    var dx = p1[0] - p0[0];\n                    var dy = p1[1] - p0[1];\n                    angle = Math.atan2(dx, dy) * 180 / Math.PI;\n                    // The angle should be a non-negative number.\n                    if (angle < 0) {\n                        angle += 360;\n                    }\n\n                    // Very small angles produce an unexpected result because they are\n                    // converted to a scientific notation string.\n                    if (angle < 1e-6) {\n                        angle = 0;\n                    }\n                }\n                else {\n                    gradientType = 'gradientradial';\n                    var p0 = [fill.x * rectWidth, fill.y * rectHeight];\n                    var transform = zrEl.transform;\n                    var scale$$1 = zrEl.scale;\n                    var width = rectWidth;\n                    var height = rectHeight;\n                    focus = [\n                        // Percent in bounding rect\n                        (p0[0] - rect.x) / width,\n                        (p0[1] - rect.y) / height\n                    ];\n                    if (transform) {\n                        applyTransform(p0, p0, transform);\n                    }\n\n                    width /= scale$$1[0] * Z;\n                    height /= scale$$1[1] * Z;\n                    var dimension = mathMax$5(width, height);\n                    shift = 2 * 0 / dimension;\n                    expansion = 2 * fill.r / dimension - shift;\n                }\n\n                // We need to sort the color stops in ascending order by offset,\n                // otherwise IE won't interpret it correctly.\n                var stops = fill.colorStops.slice();\n                stops.sort(function (cs1, cs2) {\n                    return cs1.offset - cs2.offset;\n                });\n\n                var length$$1 = stops.length;\n                // Color and alpha list of first and last stop\n                var colorAndAlphaList = [];\n                var colors = [];\n                for (var i = 0; i < length$$1; i++) {\n                    var stop = stops[i];\n                    var colorAndAlpha = getColorAndAlpha(stop.color);\n                    colors.push(stop.offset * expansion + shift + ' ' + colorAndAlpha[0]);\n                    if (i === 0 || i === length$$1 - 1) {\n                        colorAndAlphaList.push(colorAndAlpha);\n                    }\n                }\n\n                if (length$$1 >= 2) {\n                    var color1 = colorAndAlphaList[0][0];\n                    var color2 = colorAndAlphaList[1][0];\n                    var opacity1 = colorAndAlphaList[0][1] * style.opacity;\n                    var opacity2 = colorAndAlphaList[1][1] * style.opacity;\n\n                    el.type = gradientType;\n                    el.method = 'none';\n                    el.focus = '100%';\n                    el.angle = angle;\n                    el.color = color1;\n                    el.color2 = color2;\n                    el.colors = colors.join(',');\n                    // When colors attribute is used, the meanings of opacity and o:opacity2\n                    // are reversed.\n                    el.opacity = opacity2;\n                    // FIXME g_o_:opacity ?\n                    el.opacity2 = opacity1;\n                }\n                if (gradientType === 'radial') {\n                    el.focusposition = focus.join(',');\n                }\n            }\n            else {\n                // FIXME Change from Gradient fill to color fill\n                setColorAndOpacity(el, fill, style.opacity);\n            }\n        }\n    };\n\n    var updateStrokeNode = function (el, style) {\n        // if (style.lineJoin != null) {\n        //     el.joinstyle = style.lineJoin;\n        // }\n        // if (style.miterLimit != null) {\n        //     el.miterlimit = style.miterLimit * Z;\n        // }\n        // if (style.lineCap != null) {\n        //     el.endcap = style.lineCap;\n        // }\n        if (style.lineDash != null) {\n            el.dashstyle = style.lineDash.join(' ');\n        }\n        if (style.stroke != null && !(style.stroke instanceof Gradient)) {\n            setColorAndOpacity(el, style.stroke, style.opacity);\n        }\n    };\n\n    var updateFillAndStroke = function (vmlEl, type, style, zrEl) {\n        var isFill = type === 'fill';\n        var el = vmlEl.getElementsByTagName(type)[0];\n        // Stroke must have lineWidth\n        if (style[type] != null && style[type] !== 'none' && (isFill || (!isFill && style.lineWidth))) {\n            vmlEl[isFill ? 'filled' : 'stroked'] = 'true';\n            // FIXME Remove before updating, or set `colors` will throw error\n            if (style[type] instanceof Gradient) {\n                remove(vmlEl, el);\n            }\n            if (!el) {\n                el = createNode(type);\n            }\n\n            isFill ? updateFillNode(el, style, zrEl) : updateStrokeNode(el, style);\n            append(vmlEl, el);\n        }\n        else {\n            vmlEl[isFill ? 'filled' : 'stroked'] = 'false';\n            remove(vmlEl, el);\n        }\n    };\n\n    var points$1 = [[], [], []];\n    var pathDataToString = function (path, m) {\n        var M = CMD$3.M;\n        var C = CMD$3.C;\n        var L = CMD$3.L;\n        var A = CMD$3.A;\n        var Q = CMD$3.Q;\n\n        var str = [];\n        var nPoint;\n        var cmdStr;\n        var cmd;\n        var i;\n        var xi;\n        var yi;\n        var data = path.data;\n        var dataLength = path.len();\n        for (i = 0; i < dataLength;) {\n            cmd = data[i++];\n            cmdStr = '';\n            nPoint = 0;\n            switch (cmd) {\n                case M:\n                    cmdStr = ' m ';\n                    nPoint = 1;\n                    xi = data[i++];\n                    yi = data[i++];\n                    points$1[0][0] = xi;\n                    points$1[0][1] = yi;\n                    break;\n                case L:\n                    cmdStr = ' l ';\n                    nPoint = 1;\n                    xi = data[i++];\n                    yi = data[i++];\n                    points$1[0][0] = xi;\n                    points$1[0][1] = yi;\n                    break;\n                case Q:\n                case C:\n                    cmdStr = ' c ';\n                    nPoint = 3;\n                    var x1 = data[i++];\n                    var y1 = data[i++];\n                    var x2 = data[i++];\n                    var y2 = data[i++];\n                    var x3;\n                    var y3;\n                    if (cmd === Q) {\n                        // Convert quadratic to cubic using degree elevation\n                        x3 = x2;\n                        y3 = y2;\n                        x2 = (x2 + 2 * x1) / 3;\n                        y2 = (y2 + 2 * y1) / 3;\n                        x1 = (xi + 2 * x1) / 3;\n                        y1 = (yi + 2 * y1) / 3;\n                    }\n                    else {\n                        x3 = data[i++];\n                        y3 = data[i++];\n                    }\n                    points$1[0][0] = x1;\n                    points$1[0][1] = y1;\n                    points$1[1][0] = x2;\n                    points$1[1][1] = y2;\n                    points$1[2][0] = x3;\n                    points$1[2][1] = y3;\n\n                    xi = x3;\n                    yi = y3;\n                    break;\n                case A:\n                    var x = 0;\n                    var y = 0;\n                    var sx = 1;\n                    var sy = 1;\n                    var angle = 0;\n                    if (m) {\n                        // Extract SRT from matrix\n                        x = m[4];\n                        y = m[5];\n                        sx = sqrt(m[0] * m[0] + m[1] * m[1]);\n                        sy = sqrt(m[2] * m[2] + m[3] * m[3]);\n                        angle = Math.atan2(-m[1] / sy, m[0] / sx);\n                    }\n\n                    var cx = data[i++];\n                    var cy = data[i++];\n                    var rx = data[i++];\n                    var ry = data[i++];\n                    var startAngle = data[i++] + angle;\n                    var endAngle = data[i++] + startAngle + angle;\n                    // FIXME\n                    // var psi = data[i++];\n                    i++;\n                    var clockwise = data[i++];\n\n                    var x0 = cx + cos(startAngle) * rx;\n                    var y0 = cy + sin(startAngle) * ry;\n\n                    var x1 = cx + cos(endAngle) * rx;\n                    var y1 = cy + sin(endAngle) * ry;\n\n                    var type = clockwise ? ' wa ' : ' at ';\n                    if (Math.abs(x0 - x1) < 1e-4) {\n                        // IE won't render arches drawn counter clockwise if x0 == x1.\n                        if (Math.abs(endAngle - startAngle) > 1e-2) {\n                            // Offset x0 by 1/80 of a pixel. Use something\n                            // that can be represented in binary\n                            if (clockwise) {\n                                x0 += 270 / Z;\n                            }\n                        }\n                        else {\n                            // Avoid case draw full circle\n                            if (Math.abs(y0 - cy) < 1e-4) {\n                                if ((clockwise && x0 < cx) || (!clockwise && x0 > cx)) {\n                                    y1 -= 270 / Z;\n                                }\n                                else {\n                                    y1 += 270 / Z;\n                                }\n                            }\n                            else if ((clockwise && y0 < cy) || (!clockwise && y0 > cy)) {\n                                x1 += 270 / Z;\n                            }\n                            else {\n                                x1 -= 270 / Z;\n                            }\n                        }\n                    }\n                    str.push(\n                        type,\n                        round$3(((cx - rx) * sx + x) * Z - Z2), comma,\n                        round$3(((cy - ry) * sy + y) * Z - Z2), comma,\n                        round$3(((cx + rx) * sx + x) * Z - Z2), comma,\n                        round$3(((cy + ry) * sy + y) * Z - Z2), comma,\n                        round$3((x0 * sx + x) * Z - Z2), comma,\n                        round$3((y0 * sy + y) * Z - Z2), comma,\n                        round$3((x1 * sx + x) * Z - Z2), comma,\n                        round$3((y1 * sy + y) * Z - Z2)\n                    );\n\n                    xi = x1;\n                    yi = y1;\n                    break;\n                case CMD$3.R:\n                    var p0 = points$1[0];\n                    var p1 = points$1[1];\n                    // x0, y0\n                    p0[0] = data[i++];\n                    p0[1] = data[i++];\n                    // x1, y1\n                    p1[0] = p0[0] + data[i++];\n                    p1[1] = p0[1] + data[i++];\n\n                    if (m) {\n                        applyTransform(p0, p0, m);\n                        applyTransform(p1, p1, m);\n                    }\n\n                    p0[0] = round$3(p0[0] * Z - Z2);\n                    p1[0] = round$3(p1[0] * Z - Z2);\n                    p0[1] = round$3(p0[1] * Z - Z2);\n                    p1[1] = round$3(p1[1] * Z - Z2);\n                    str.push(\n                        // x0, y0\n                        ' m ', p0[0], comma, p0[1],\n                        // x1, y0\n                        ' l ', p1[0], comma, p0[1],\n                        // x1, y1\n                        ' l ', p1[0], comma, p1[1],\n                        // x0, y1\n                        ' l ', p0[0], comma, p1[1]\n                    );\n                    break;\n                case CMD$3.Z:\n                    // FIXME Update xi, yi\n                    str.push(' x ');\n            }\n\n            if (nPoint > 0) {\n                str.push(cmdStr);\n                for (var k = 0; k < nPoint; k++) {\n                    var p = points$1[k];\n\n                    m && applyTransform(p, p, m);\n                    // 不 round 会非常慢\n                    str.push(\n                        round$3(p[0] * Z - Z2), comma, round$3(p[1] * Z - Z2),\n                        k < nPoint - 1 ? comma : ''\n                    );\n                }\n            }\n        }\n\n        return str.join('');\n    };\n\n    // Rewrite the original path method\n    Path.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n\n        var vmlEl = this._vmlEl;\n        if (!vmlEl) {\n            vmlEl = createNode('shape');\n            initRootElStyle(vmlEl);\n\n            this._vmlEl = vmlEl;\n        }\n\n        updateFillAndStroke(vmlEl, 'fill', style, this);\n        updateFillAndStroke(vmlEl, 'stroke', style, this);\n\n        var m = this.transform;\n        var needTransform = m != null;\n        var strokeEl = vmlEl.getElementsByTagName('stroke')[0];\n        if (strokeEl) {\n            var lineWidth = style.lineWidth;\n            // Get the line scale.\n            // Determinant of this.m_ means how much the area is enlarged by the\n            // transformation. So its square root can be used as a scale factor\n            // for width.\n            if (needTransform && !style.strokeNoScale) {\n                var det = m[0] * m[3] - m[1] * m[2];\n                lineWidth *= sqrt(abs$1(det));\n            }\n            strokeEl.weight = lineWidth + 'px';\n        }\n\n        var path = this.path || (this.path = new PathProxy());\n        if (this.__dirtyPath) {\n            path.beginPath();\n            path.subPixelOptimize = false;\n            this.buildPath(path, this.shape);\n            path.toStatic();\n            this.__dirtyPath = false;\n        }\n\n        vmlEl.path = pathDataToString(path, this.transform);\n\n        vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Append to root\n        append(vmlRoot, vmlEl);\n\n        // Text\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, this.getBoundingRect());\n        }\n        else {\n            this.removeRectText(vmlRoot);\n        }\n    };\n\n    Path.prototype.onRemove = function (vmlRoot) {\n        remove(vmlRoot, this._vmlEl);\n        this.removeRectText(vmlRoot);\n    };\n\n    Path.prototype.onAdd = function (vmlRoot) {\n        append(vmlRoot, this._vmlEl);\n        this.appendRectText(vmlRoot);\n    };\n\n    /***************************************************\n     * IMAGE\n     **************************************************/\n    var isImage = function (img) {\n        // FIXME img instanceof Image 如果 img 是一个字符串的时候，IE8 下会报错\n        return (typeof img === 'object') && img.tagName && img.tagName.toUpperCase() === 'IMG';\n        // return img instanceof Image;\n    };\n\n    // Rewrite the original path method\n    ZImage.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n        var image = style.image;\n\n        // Image original width, height\n        var ow;\n        var oh;\n\n        if (isImage(image)) {\n            var src = image.src;\n            if (src === this._imageSrc) {\n                ow = this._imageWidth;\n                oh = this._imageHeight;\n            }\n            else {\n                var imageRuntimeStyle = image.runtimeStyle;\n                var oldRuntimeWidth = imageRuntimeStyle.width;\n                var oldRuntimeHeight = imageRuntimeStyle.height;\n                imageRuntimeStyle.width = 'auto';\n                imageRuntimeStyle.height = 'auto';\n\n                // get the original size\n                ow = image.width;\n                oh = image.height;\n\n                // and remove overides\n                imageRuntimeStyle.width = oldRuntimeWidth;\n                imageRuntimeStyle.height = oldRuntimeHeight;\n\n                // Caching image original width, height and src\n                this._imageSrc = src;\n                this._imageWidth = ow;\n                this._imageHeight = oh;\n            }\n            image = src;\n        }\n        else {\n            if (image === this._imageSrc) {\n                ow = this._imageWidth;\n                oh = this._imageHeight;\n            }\n        }\n        if (!image) {\n            return;\n        }\n\n        var x = style.x || 0;\n        var y = style.y || 0;\n\n        var dw = style.width;\n        var dh = style.height;\n\n        var sw = style.sWidth;\n        var sh = style.sHeight;\n        var sx = style.sx || 0;\n        var sy = style.sy || 0;\n\n        var hasCrop = sw && sh;\n\n        var vmlEl = this._vmlEl;\n        if (!vmlEl) {\n            // FIXME 使用 group 在 left, top 都不是 0 的时候就无法显示了。\n            // vmlEl = vmlCore.createNode('group');\n            vmlEl = doc.createElement('div');\n            initRootElStyle(vmlEl);\n\n            this._vmlEl = vmlEl;\n        }\n\n        var vmlElStyle = vmlEl.style;\n        var hasRotation = false;\n        var m;\n        var scaleX = 1;\n        var scaleY = 1;\n        if (this.transform) {\n            m = this.transform;\n            scaleX = sqrt(m[0] * m[0] + m[1] * m[1]);\n            scaleY = sqrt(m[2] * m[2] + m[3] * m[3]);\n\n            hasRotation = m[1] || m[2];\n        }\n        if (hasRotation) {\n            // If filters are necessary (rotation exists), create them\n            // filters are bog-slow, so only create them if abbsolutely necessary\n            // The following check doesn't account for skews (which don't exist\n            // in the canvas spec (yet) anyway.\n            // From excanvas\n            var p0 = [x, y];\n            var p1 = [x + dw, y];\n            var p2 = [x, y + dh];\n            var p3 = [x + dw, y + dh];\n            applyTransform(p0, p0, m);\n            applyTransform(p1, p1, m);\n            applyTransform(p2, p2, m);\n            applyTransform(p3, p3, m);\n\n            var maxX = mathMax$5(p0[0], p1[0], p2[0], p3[0]);\n            var maxY = mathMax$5(p0[1], p1[1], p2[1], p3[1]);\n\n            var transformFilter = [];\n            transformFilter.push('M11=', m[0] / scaleX, comma,\n                        'M12=', m[2] / scaleY, comma,\n                        'M21=', m[1] / scaleX, comma,\n                        'M22=', m[3] / scaleY, comma,\n                        'Dx=', round$3(x * scaleX + m[4]), comma,\n                        'Dy=', round$3(y * scaleY + m[5]));\n\n            vmlElStyle.padding = '0 ' + round$3(maxX) + 'px ' + round$3(maxY) + 'px 0';\n            // FIXME DXImageTransform 在 IE11 的兼容模式下不起作用\n            vmlElStyle.filter = imageTransformPrefix + '.Matrix('\n                + transformFilter.join('') + ', SizingMethod=clip)';\n\n        }\n        else {\n            if (m) {\n                x = x * scaleX + m[4];\n                y = y * scaleY + m[5];\n            }\n            vmlElStyle.filter = '';\n            vmlElStyle.left = round$3(x) + 'px';\n            vmlElStyle.top = round$3(y) + 'px';\n        }\n\n        var imageEl = this._imageEl;\n        var cropEl = this._cropEl;\n\n        if (!imageEl) {\n            imageEl = doc.createElement('div');\n            this._imageEl = imageEl;\n        }\n        var imageELStyle = imageEl.style;\n        if (hasCrop) {\n            // Needs know image original width and height\n            if (!(ow && oh)) {\n                var tmpImage = new Image();\n                var self = this;\n                tmpImage.onload = function () {\n                    tmpImage.onload = null;\n                    ow = tmpImage.width;\n                    oh = tmpImage.height;\n                    // Adjust image width and height to fit the ratio destinationSize / sourceSize\n                    imageELStyle.width = round$3(scaleX * ow * dw / sw) + 'px';\n                    imageELStyle.height = round$3(scaleY * oh * dh / sh) + 'px';\n\n                    // Caching image original width, height and src\n                    self._imageWidth = ow;\n                    self._imageHeight = oh;\n                    self._imageSrc = image;\n                };\n                tmpImage.src = image;\n            }\n            else {\n                imageELStyle.width = round$3(scaleX * ow * dw / sw) + 'px';\n                imageELStyle.height = round$3(scaleY * oh * dh / sh) + 'px';\n            }\n\n            if (!cropEl) {\n                cropEl = doc.createElement('div');\n                cropEl.style.overflow = 'hidden';\n                this._cropEl = cropEl;\n            }\n            var cropElStyle = cropEl.style;\n            cropElStyle.width = round$3((dw + sx * dw / sw) * scaleX);\n            cropElStyle.height = round$3((dh + sy * dh / sh) * scaleY);\n            cropElStyle.filter = imageTransformPrefix + '.Matrix(Dx='\n                    + (-sx * dw / sw * scaleX) + ',Dy=' + (-sy * dh / sh * scaleY) + ')';\n\n            if (!cropEl.parentNode) {\n                vmlEl.appendChild(cropEl);\n            }\n            if (imageEl.parentNode !== cropEl) {\n                cropEl.appendChild(imageEl);\n            }\n        }\n        else {\n            imageELStyle.width = round$3(scaleX * dw) + 'px';\n            imageELStyle.height = round$3(scaleY * dh) + 'px';\n\n            vmlEl.appendChild(imageEl);\n\n            if (cropEl && cropEl.parentNode) {\n                vmlEl.removeChild(cropEl);\n                this._cropEl = null;\n            }\n        }\n\n        var filterStr = '';\n        var alpha = style.opacity;\n        if (alpha < 1) {\n            filterStr += '.Alpha(opacity=' + round$3(alpha * 100) + ') ';\n        }\n        filterStr += imageTransformPrefix + '.AlphaImageLoader(src=' + image + ', SizingMethod=scale)';\n\n        imageELStyle.filter = filterStr;\n\n        vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Append to root\n        append(vmlRoot, vmlEl);\n\n        // Text\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, this.getBoundingRect());\n        }\n    };\n\n    ZImage.prototype.onRemove = function (vmlRoot) {\n        remove(vmlRoot, this._vmlEl);\n\n        this._vmlEl = null;\n        this._cropEl = null;\n        this._imageEl = null;\n\n        this.removeRectText(vmlRoot);\n    };\n\n    ZImage.prototype.onAdd = function (vmlRoot) {\n        append(vmlRoot, this._vmlEl);\n        this.appendRectText(vmlRoot);\n    };\n\n\n    /***************************************************\n     * TEXT\n     **************************************************/\n\n    var DEFAULT_STYLE_NORMAL = 'normal';\n\n    var fontStyleCache = {};\n    var fontStyleCacheCount = 0;\n    var MAX_FONT_CACHE_SIZE = 100;\n    var fontEl = document.createElement('div');\n\n    var getFontStyle = function (fontString) {\n        var fontStyle = fontStyleCache[fontString];\n        if (!fontStyle) {\n            // Clear cache\n            if (fontStyleCacheCount > MAX_FONT_CACHE_SIZE) {\n                fontStyleCacheCount = 0;\n                fontStyleCache = {};\n            }\n\n            var style = fontEl.style;\n            var fontFamily;\n            try {\n                style.font = fontString;\n                fontFamily = style.fontFamily.split(',')[0];\n            }\n            catch (e) {\n            }\n\n            fontStyle = {\n                style: style.fontStyle || DEFAULT_STYLE_NORMAL,\n                variant: style.fontVariant || DEFAULT_STYLE_NORMAL,\n                weight: style.fontWeight || DEFAULT_STYLE_NORMAL,\n                size: parseFloat(style.fontSize || 12) | 0,\n                family: fontFamily || 'Microsoft YaHei'\n            };\n\n            fontStyleCache[fontString] = fontStyle;\n            fontStyleCacheCount++;\n        }\n        return fontStyle;\n    };\n\n    var textMeasureEl;\n    // Overwrite measure text method\n    $override$1('measureText', function (text, textFont) {\n        var doc$$1 = doc;\n        if (!textMeasureEl) {\n            textMeasureEl = doc$$1.createElement('div');\n            textMeasureEl.style.cssText = 'position:absolute;top:-20000px;left:0;'\n                + 'padding:0;margin:0;border:none;white-space:pre;';\n            doc.body.appendChild(textMeasureEl);\n        }\n\n        try {\n            textMeasureEl.style.font = textFont;\n        }\n        catch (ex) {\n            // Ignore failures to set to invalid font.\n        }\n        textMeasureEl.innerHTML = '';\n        // Don't use innerHTML or innerText because they allow markup/whitespace.\n        textMeasureEl.appendChild(doc$$1.createTextNode(text));\n        return {\n            width: textMeasureEl.offsetWidth\n        };\n    });\n\n    var tmpRect$2 = new BoundingRect();\n\n    var drawRectText = function (vmlRoot, rect, textRect, fromTextEl) {\n\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        var text = style.text;\n        // Convert to string\n        text != null && (text += '');\n        if (!text) {\n            return;\n        }\n\n        // Convert rich text to plain text. Rich text is not supported in\n        // IE8-, but tags in rich text template will be removed.\n        if (style.rich) {\n            var contentBlock = parseRichText(text, style);\n            text = [];\n            for (var i = 0; i < contentBlock.lines.length; i++) {\n                var tokens = contentBlock.lines[i].tokens;\n                var textLine = [];\n                for (var j = 0; j < tokens.length; j++) {\n                    textLine.push(tokens[j].text);\n                }\n                text.push(textLine.join(''));\n            }\n            text = text.join('\\n');\n        }\n\n        var x;\n        var y;\n        var align = style.textAlign;\n        var verticalAlign = style.textVerticalAlign;\n\n        var fontStyle = getFontStyle(style.font);\n        // FIXME encodeHtmlAttribute ?\n        var font = fontStyle.style + ' ' + fontStyle.variant + ' ' + fontStyle.weight + ' '\n            + fontStyle.size + 'px \"' + fontStyle.family + '\"';\n\n        textRect = textRect || getBoundingRect(\n            text, font, align, verticalAlign, style.textPadding, style.textLineHeight\n        );\n\n        // Transform rect to view space\n        var m = this.transform;\n        // Ignore transform for text in other element\n        if (m && !fromTextEl) {\n            tmpRect$2.copy(rect);\n            tmpRect$2.applyTransform(m);\n            rect = tmpRect$2;\n        }\n\n        if (!fromTextEl) {\n            var textPosition = style.textPosition;\n            var distance$$1 = style.textDistance;\n            // Text position represented by coord\n            if (textPosition instanceof Array) {\n                x = rect.x + parsePercent$3(textPosition[0], rect.width);\n                y = rect.y + parsePercent$3(textPosition[1], rect.height);\n\n                align = align || 'left';\n            }\n            else {\n                var res = adjustTextPositionOnRect(\n                    textPosition, rect, distance$$1\n                );\n                x = res.x;\n                y = res.y;\n\n                // Default align and baseline when has textPosition\n                align = align || res.textAlign;\n                verticalAlign = verticalAlign || res.textVerticalAlign;\n            }\n        }\n        else {\n            x = rect.x;\n            y = rect.y;\n        }\n\n        x = adjustTextX(x, textRect.width, align);\n        y = adjustTextY(y, textRect.height, verticalAlign);\n\n        // Force baseline 'middle'\n        y += textRect.height / 2;\n\n        // var fontSize = fontStyle.size;\n        // 1.75 is an arbitrary number, as there is no info about the text baseline\n        // switch (baseline) {\n            // case 'hanging':\n            // case 'top':\n            //     y += fontSize / 1.75;\n            //     break;\n        //     case 'middle':\n        //         break;\n        //     default:\n        //     // case null:\n        //     // case 'alphabetic':\n        //     // case 'ideographic':\n        //     // case 'bottom':\n        //         y -= fontSize / 2.25;\n        //         break;\n        // }\n\n        // switch (align) {\n        //     case 'left':\n        //         break;\n        //     case 'center':\n        //         x -= textRect.width / 2;\n        //         break;\n        //     case 'right':\n        //         x -= textRect.width;\n        //         break;\n            // case 'end':\n                // align = elementStyle.direction == 'ltr' ? 'right' : 'left';\n                // break;\n            // case 'start':\n                // align = elementStyle.direction == 'rtl' ? 'right' : 'left';\n                // break;\n            // default:\n            //     align = 'left';\n        // }\n\n        var createNode$$1 = createNode;\n\n        var textVmlEl = this._textVmlEl;\n        var pathEl;\n        var textPathEl;\n        var skewEl;\n        if (!textVmlEl) {\n            textVmlEl = createNode$$1('line');\n            pathEl = createNode$$1('path');\n            textPathEl = createNode$$1('textpath');\n            skewEl = createNode$$1('skew');\n\n            // FIXME Why here is not cammel case\n            // Align 'center' seems wrong\n            textPathEl.style['v-text-align'] = 'left';\n\n            initRootElStyle(textVmlEl);\n\n            pathEl.textpathok = true;\n            textPathEl.on = true;\n\n            textVmlEl.from = '0 0';\n            textVmlEl.to = '1000 0.05';\n\n            append(textVmlEl, skewEl);\n            append(textVmlEl, pathEl);\n            append(textVmlEl, textPathEl);\n\n            this._textVmlEl = textVmlEl;\n        }\n        else {\n            // 这里是在前面 appendChild 保证顺序的前提下\n            skewEl = textVmlEl.firstChild;\n            pathEl = skewEl.nextSibling;\n            textPathEl = pathEl.nextSibling;\n        }\n\n        var coords = [x, y];\n        var textVmlElStyle = textVmlEl.style;\n        // Ignore transform for text in other element\n        if (m && fromTextEl) {\n            applyTransform(coords, coords, m);\n\n            skewEl.on = true;\n\n            skewEl.matrix = m[0].toFixed(3) + comma + m[2].toFixed(3) + comma\n                            + m[1].toFixed(3) + comma + m[3].toFixed(3) + ',0,0';\n\n            // Text position\n            skewEl.offset = (round$3(coords[0]) || 0) + ',' + (round$3(coords[1]) || 0);\n            // Left top point as origin\n            skewEl.origin = '0 0';\n\n            textVmlElStyle.left = '0px';\n            textVmlElStyle.top = '0px';\n        }\n        else {\n            skewEl.on = false;\n            textVmlElStyle.left = round$3(x) + 'px';\n            textVmlElStyle.top = round$3(y) + 'px';\n        }\n\n        textPathEl.string = encodeHtmlAttribute(text);\n        // TODO\n        try {\n            textPathEl.style.font = font;\n        }\n        // Error font format\n        catch (e) {}\n\n        updateFillAndStroke(textVmlEl, 'fill', {\n            fill: style.textFill,\n            opacity: style.opacity\n        }, this);\n        updateFillAndStroke(textVmlEl, 'stroke', {\n            stroke: style.textStroke,\n            opacity: style.opacity,\n            lineDash: style.lineDash\n        }, this);\n\n        textVmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Attached to root\n        append(vmlRoot, textVmlEl);\n    };\n\n    var removeRectText = function (vmlRoot) {\n        remove(vmlRoot, this._textVmlEl);\n        this._textVmlEl = null;\n    };\n\n    var appendRectText = function (vmlRoot) {\n        append(vmlRoot, this._textVmlEl);\n    };\n\n    var list = [RectText, Displayable, ZImage, Path, Text];\n\n    // In case Displayable has been mixed in RectText\n    for (var i$1 = 0; i$1 < list.length; i$1++) {\n        var proto$7 = list[i$1].prototype;\n        proto$7.drawRectText = drawRectText;\n        proto$7.removeRectText = removeRectText;\n        proto$7.appendRectText = appendRectText;\n    }\n\n    Text.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, {\n                x: style.x || 0, y: style.y || 0,\n                width: 0, height: 0\n            }, this.getBoundingRect(), true);\n        }\n        else {\n            this.removeRectText(vmlRoot);\n        }\n    };\n\n    Text.prototype.onRemove = function (vmlRoot) {\n        this.removeRectText(vmlRoot);\n    };\n\n    Text.prototype.onAdd = function (vmlRoot) {\n        this.appendRectText(vmlRoot);\n    };\n}\n\n/**\n * VML Painter.\n *\n * @module zrender/vml/Painter\n */\n\nfunction parseInt10$1(val) {\n    return parseInt(val, 10);\n}\n\n/**\n * @alias module:zrender/vml/Painter\n */\nfunction VMLPainter(root, storage) {\n\n    initVML();\n\n    this.root = root;\n\n    this.storage = storage;\n\n    var vmlViewport = document.createElement('div');\n\n    var vmlRoot = document.createElement('div');\n\n    vmlViewport.style.cssText = 'display:inline-block;overflow:hidden;position:relative;width:300px;height:150px;';\n\n    vmlRoot.style.cssText = 'position:absolute;left:0;top:0;';\n\n    root.appendChild(vmlViewport);\n\n    this._vmlRoot = vmlRoot;\n    this._vmlViewport = vmlViewport;\n\n    this.resize();\n\n    // Modify storage\n    var oldDelFromStorage = storage.delFromStorage;\n    var oldAddToStorage = storage.addToStorage;\n    storage.delFromStorage = function (el) {\n        oldDelFromStorage.call(storage, el);\n\n        if (el) {\n            el.onRemove && el.onRemove(vmlRoot);\n        }\n    };\n\n    storage.addToStorage = function (el) {\n        // Displayable already has a vml node\n        el.onAdd && el.onAdd(vmlRoot);\n\n        oldAddToStorage.call(storage, el);\n    };\n\n    this._firstPaint = true;\n}\n\nVMLPainter.prototype = {\n\n    constructor: VMLPainter,\n\n    getType: function () {\n        return 'vml';\n    },\n\n    /**\n     * @return {HTMLDivElement}\n     */\n    getViewportRoot: function () {\n        return this._vmlViewport;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    /**\n     * 刷新\n     */\n    refresh: function () {\n\n        var list = this.storage.getDisplayList(true, true);\n\n        this._paintList(list);\n    },\n\n    _paintList: function (list) {\n        var vmlRoot = this._vmlRoot;\n        for (var i = 0; i < list.length; i++) {\n            var el = list[i];\n            if (el.invisible || el.ignore) {\n                if (!el.__alreadyNotVisible) {\n                    el.onRemove(vmlRoot);\n                }\n                // Set as already invisible\n                el.__alreadyNotVisible = true;\n            }\n            else {\n                if (el.__alreadyNotVisible) {\n                    el.onAdd(vmlRoot);\n                }\n                el.__alreadyNotVisible = false;\n                if (el.__dirty) {\n                    el.beforeBrush && el.beforeBrush();\n                    (el.brushVML || el.brush).call(el, vmlRoot);\n                    el.afterBrush && el.afterBrush();\n                }\n            }\n            el.__dirty = false;\n        }\n\n        if (this._firstPaint) {\n            // Detached from document at first time\n            // to avoid page refreshing too many times\n\n            // FIXME 如果每次都先 removeChild 可能会导致一些填充和描边的效果改变\n            this._vmlViewport.appendChild(vmlRoot);\n            this._firstPaint = false;\n        }\n    },\n\n    resize: function (width, height) {\n        var width = width == null ? this._getWidth() : width;\n        var height = height == null ? this._getHeight() : height;\n\n        if (this._width !== width || this._height !== height) {\n            this._width = width;\n            this._height = height;\n\n            var vmlViewportStyle = this._vmlViewport.style;\n            vmlViewportStyle.width = width + 'px';\n            vmlViewportStyle.height = height + 'px';\n        }\n    },\n\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this._vmlRoot =\n        this._vmlViewport =\n        this.storage = null;\n    },\n\n    getWidth: function () {\n        return this._width;\n    },\n\n    getHeight: function () {\n        return this._height;\n    },\n\n    clear: function () {\n        if (this._vmlViewport) {\n            this.root.removeChild(this._vmlViewport);\n        }\n    },\n\n    _getWidth: function () {\n        var root = this.root;\n        var stl = root.currentStyle;\n\n        return ((root.clientWidth || parseInt10$1(stl.width))\n                - parseInt10$1(stl.paddingLeft)\n                - parseInt10$1(stl.paddingRight)) | 0;\n    },\n\n    _getHeight: function () {\n        var root = this.root;\n        var stl = root.currentStyle;\n\n        return ((root.clientHeight || parseInt10$1(stl.height))\n                - parseInt10$1(stl.paddingTop)\n                - parseInt10$1(stl.paddingBottom)) | 0;\n    }\n};\n\n// Not supported methods\nfunction createMethodNotSupport(method) {\n    return function () {\n        zrLog('In IE8.0 VML mode painter not support method \"' + method + '\"');\n    };\n}\n\n// Unsupported methods\neach$1([\n    'getLayer', 'insertLayer', 'eachLayer', 'eachBuiltinLayer', 'eachOtherLayer', 'getLayers',\n    'modLayer', 'delLayer', 'clearLayer', 'toDataURL', 'pathToImage'\n], function (name) {\n    VMLPainter.prototype[name] = createMethodNotSupport(name);\n});\n\nregisterPainter('vml', VMLPainter);\n\nvar svgURI = 'http://www.w3.org/2000/svg';\n\nfunction createElement(name) {\n    return document.createElementNS(svgURI, name);\n}\n\n// TODO\n// 1. shadow\n// 2. Image: sx, sy, sw, sh\n\nvar CMD$4 = PathProxy.CMD;\nvar arrayJoin = Array.prototype.join;\n\nvar NONE = 'none';\nvar mathRound = Math.round;\nvar mathSin$3 = Math.sin;\nvar mathCos$3 = Math.cos;\nvar PI$3 = Math.PI;\nvar PI2$5 = Math.PI * 2;\nvar degree = 180 / PI$3;\n\nvar EPSILON$4 = 1e-4;\n\nfunction round4(val) {\n    return mathRound(val * 1e4) / 1e4;\n}\n\nfunction isAroundZero$1(val) {\n    return val < EPSILON$4 && val > -EPSILON$4;\n}\n\nfunction pathHasFill(style, isText) {\n    var fill = isText ? style.textFill : style.fill;\n    return fill != null && fill !== NONE;\n}\n\nfunction pathHasStroke(style, isText) {\n    var stroke = isText ? style.textStroke : style.stroke;\n    return stroke != null && stroke !== NONE;\n}\n\nfunction setTransform(svgEl, m) {\n    if (m) {\n        attr(svgEl, 'transform', 'matrix(' + arrayJoin.call(m, ',') + ')');\n    }\n}\n\nfunction attr(el, key, val) {\n    if (!val || val.type !== 'linear' && val.type !== 'radial') {\n        // Don't set attribute for gradient, since it need new dom nodes\n        el.setAttribute(key, val);\n    }\n}\n\nfunction attrXLink(el, key, val) {\n    el.setAttributeNS('http://www.w3.org/1999/xlink', key, val);\n}\n\nfunction bindStyle(svgEl, style, isText, el) {\n    if (pathHasFill(style, isText)) {\n        var fill = isText ? style.textFill : style.fill;\n        fill = fill === 'transparent' ? NONE : fill;\n\n        /**\n         * FIXME:\n         * This is a temporary fix for Chrome's clipping bug\n         * that happens when a clip-path is referring another one.\n         * This fix should be used before Chrome's bug is fixed.\n         * For an element that has clip-path, and fill is none,\n         * set it to be \"rgba(0, 0, 0, 0.002)\" will hide the element.\n         * Otherwise, it will show black fill color.\n         * 0.002 is used because this won't work for alpha values smaller\n         * than 0.002.\n         *\n         * See\n         * https://bugs.chromium.org/p/chromium/issues/detail?id=659790\n         * for more information.\n         */\n        if (svgEl.getAttribute('clip-path') !== 'none' && fill === NONE) {\n            fill = 'rgba(0, 0, 0, 0.002)';\n        }\n\n        attr(svgEl, 'fill', fill);\n        attr(svgEl, 'fill-opacity', style.fillOpacity != null ? style.fillOpacity * style.opacity : style.opacity);\n    }\n    else {\n        attr(svgEl, 'fill', NONE);\n    }\n\n    if (pathHasStroke(style, isText)) {\n        var stroke = isText ? style.textStroke : style.stroke;\n        stroke = stroke === 'transparent' ? NONE : stroke;\n        attr(svgEl, 'stroke', stroke);\n        var strokeWidth = isText\n            ? style.textStrokeWidth\n            : style.lineWidth;\n        var strokeScale = !isText && style.strokeNoScale\n            ? el.getLineScale()\n            : 1;\n        attr(svgEl, 'stroke-width', strokeWidth / strokeScale);\n        // stroke then fill for text; fill then stroke for others\n        attr(svgEl, 'paint-order', isText ? 'stroke' : 'fill');\n        attr(svgEl, 'stroke-opacity', style.strokeOpacity != null ? style.strokeOpacity : style.opacity);\n        var lineDash = style.lineDash;\n        if (lineDash) {\n            attr(svgEl, 'stroke-dasharray', style.lineDash.join(','));\n            attr(svgEl, 'stroke-dashoffset', mathRound(style.lineDashOffset || 0));\n        }\n        else {\n            attr(svgEl, 'stroke-dasharray', '');\n        }\n\n        // PENDING\n        style.lineCap && attr(svgEl, 'stroke-linecap', style.lineCap);\n        style.lineJoin && attr(svgEl, 'stroke-linejoin', style.lineJoin);\n        style.miterLimit && attr(svgEl, 'stroke-miterlimit', style.miterLimit);\n    }\n    else {\n        attr(svgEl, 'stroke', NONE);\n    }\n}\n\n/***************************************************\n * PATH\n **************************************************/\nfunction pathDataToString$1(path) {\n    var str = [];\n    var data = path.data;\n    var dataLength = path.len();\n    for (var i = 0; i < dataLength;) {\n        var cmd = data[i++];\n        var cmdStr = '';\n        var nData = 0;\n        switch (cmd) {\n            case CMD$4.M:\n                cmdStr = 'M';\n                nData = 2;\n                break;\n            case CMD$4.L:\n                cmdStr = 'L';\n                nData = 2;\n                break;\n            case CMD$4.Q:\n                cmdStr = 'Q';\n                nData = 4;\n                break;\n            case CMD$4.C:\n                cmdStr = 'C';\n                nData = 6;\n                break;\n            case CMD$4.A:\n                var cx = data[i++];\n                var cy = data[i++];\n                var rx = data[i++];\n                var ry = data[i++];\n                var theta = data[i++];\n                var dTheta = data[i++];\n                var psi = data[i++];\n                var clockwise = data[i++];\n\n                var dThetaPositive = Math.abs(dTheta);\n                var isCircle = isAroundZero$1(dThetaPositive - PI2$5)\n                    && !isAroundZero$1(dThetaPositive);\n\n                var large = false;\n                if (dThetaPositive >= PI2$5) {\n                    large = true;\n                }\n                else if (isAroundZero$1(dThetaPositive)) {\n                    large = false;\n                }\n                else {\n                    large = (dTheta > -PI$3 && dTheta < 0 || dTheta > PI$3)\n                        === !!clockwise;\n                }\n\n                var x0 = round4(cx + rx * mathCos$3(theta));\n                var y0 = round4(cy + ry * mathSin$3(theta));\n\n                // It will not draw if start point and end point are exactly the same\n                // We need to shift the end point with a small value\n                // FIXME A better way to draw circle ?\n                if (isCircle) {\n                    if (clockwise) {\n                        dTheta = PI2$5 - 1e-4;\n                    }\n                    else {\n                        dTheta = -PI2$5 + 1e-4;\n                    }\n\n                    large = true;\n\n                    if (i === 9) {\n                        // Move to (x0, y0) only when CMD.A comes at the\n                        // first position of a shape.\n                        // For instance, when drawing a ring, CMD.A comes\n                        // after CMD.M, so it's unnecessary to move to\n                        // (x0, y0).\n                        str.push('M', x0, y0);\n                    }\n                }\n\n                var x = round4(cx + rx * mathCos$3(theta + dTheta));\n                var y = round4(cy + ry * mathSin$3(theta + dTheta));\n\n                // FIXME Ellipse\n                str.push('A', round4(rx), round4(ry),\n                    mathRound(psi * degree), +large, +clockwise, x, y);\n                break;\n            case CMD$4.Z:\n                cmdStr = 'Z';\n                break;\n            case CMD$4.R:\n                var x = round4(data[i++]);\n                var y = round4(data[i++]);\n                var w = round4(data[i++]);\n                var h = round4(data[i++]);\n                str.push(\n                    'M', x, y,\n                    'L', x + w, y,\n                    'L', x + w, y + h,\n                    'L', x, y + h,\n                    'L', x, y\n                );\n                break;\n        }\n        cmdStr && str.push(cmdStr);\n        for (var j = 0; j < nData; j++) {\n            // PENDING With scale\n            str.push(round4(data[i++]));\n        }\n    }\n    return str.join(' ');\n}\n\nvar svgPath = {};\nsvgPath.brush = function (el) {\n    var style = el.style;\n\n    var svgEl = el.__svgEl;\n    if (!svgEl) {\n        svgEl = createElement('path');\n        el.__svgEl = svgEl;\n    }\n\n    if (!el.path) {\n        el.createPathProxy();\n    }\n    var path = el.path;\n\n    if (el.__dirtyPath) {\n        path.beginPath();\n        path.subPixelOptimize = false;\n        el.buildPath(path, el.shape);\n        el.__dirtyPath = false;\n\n        var pathStr = pathDataToString$1(path);\n        if (pathStr.indexOf('NaN') < 0) {\n            // Ignore illegal path, which may happen such in out-of-range\n            // data in Calendar series.\n            attr(svgEl, 'd', pathStr);\n        }\n    }\n\n    bindStyle(svgEl, style, false, el);\n    setTransform(svgEl, el.transform);\n\n    if (style.text != null) {\n        svgTextDrawRectText(el, el.getBoundingRect());\n    }\n};\n\n/***************************************************\n * IMAGE\n **************************************************/\nvar svgImage = {};\nsvgImage.brush = function (el) {\n    var style = el.style;\n    var image = style.image;\n\n    if (image instanceof HTMLImageElement) {\n        var src = image.src;\n        image = src;\n    }\n    if (!image) {\n        return;\n    }\n\n    var x = style.x || 0;\n    var y = style.y || 0;\n\n    var dw = style.width;\n    var dh = style.height;\n\n    var svgEl = el.__svgEl;\n    if (!svgEl) {\n        svgEl = createElement('image');\n        el.__svgEl = svgEl;\n    }\n\n    if (image !== el.__imageSrc) {\n        attrXLink(svgEl, 'href', image);\n        // Caching image src\n        el.__imageSrc = image;\n    }\n\n    attr(svgEl, 'width', dw);\n    attr(svgEl, 'height', dh);\n\n    attr(svgEl, 'x', x);\n    attr(svgEl, 'y', y);\n\n    setTransform(svgEl, el.transform);\n\n    if (style.text != null) {\n        svgTextDrawRectText(el, el.getBoundingRect());\n    }\n};\n\n/***************************************************\n * TEXT\n **************************************************/\nvar svgText = {};\nvar tmpRect$3 = new BoundingRect();\n\nvar svgTextDrawRectText = function (el, rect, textRect) {\n    var style = el.style;\n\n    el.__dirty && normalizeTextStyle(style, true);\n\n    var text = style.text;\n    // Convert to string\n    if (text == null) {\n        // Draw no text only when text is set to null, but not ''\n        return;\n    }\n    else {\n        text += '';\n    }\n\n    var textSvgEl = el.__textSvgEl;\n    if (!textSvgEl) {\n        textSvgEl = createElement('text');\n        el.__textSvgEl = textSvgEl;\n    }\n\n    var x;\n    var y;\n    var textPosition = style.textPosition;\n    var distance = style.textDistance;\n    var align = style.textAlign || 'left';\n\n    if (typeof style.fontSize === 'number') {\n        style.fontSize += 'px';\n    }\n    var font = style.font\n        || [\n            style.fontStyle || '',\n            style.fontWeight || '',\n            style.fontSize || '',\n            style.fontFamily || ''\n        ].join(' ')\n        || DEFAULT_FONT$1;\n\n    var verticalAlign = getVerticalAlignForSvg(style.textVerticalAlign);\n\n    textRect = getBoundingRect(\n        text, font, align,\n        verticalAlign, style.textPadding, style.textLineHeight\n    );\n\n    var lineHeight = textRect.lineHeight;\n    // Text position represented by coord\n    if (textPosition instanceof Array) {\n        x = rect.x + textPosition[0];\n        y = rect.y + textPosition[1];\n    }\n    else {\n        var newPos = adjustTextPositionOnRect(\n            textPosition, rect, distance\n        );\n        x = newPos.x;\n        y = newPos.y;\n        verticalAlign = getVerticalAlignForSvg(newPos.textVerticalAlign);\n        align = newPos.textAlign;\n    }\n\n    attr(textSvgEl, 'alignment-baseline', verticalAlign);\n\n    if (font) {\n        textSvgEl.style.font = font;\n    }\n\n    var textPadding = style.textPadding;\n\n    // Make baseline top\n    attr(textSvgEl, 'x', x);\n    attr(textSvgEl, 'y', y);\n\n    bindStyle(textSvgEl, style, true, el);\n    if (el instanceof Text || el.style.transformText) {\n        // Transform text with element\n        setTransform(textSvgEl, el.transform);\n    }\n    else {\n        if (el.transform) {\n            tmpRect$3.copy(rect);\n            tmpRect$3.applyTransform(el.transform);\n            rect = tmpRect$3;\n        }\n        else {\n            var pos = el.transformCoordToGlobal(rect.x, rect.y);\n            rect.x = pos[0];\n            rect.y = pos[1];\n            el.transform = identity(create$1());\n        }\n\n        // Text rotation, but no element transform\n        var origin = style.textOrigin;\n        if (origin === 'center') {\n            x = textRect.width / 2 + x;\n            y = textRect.height / 2 + y;\n        }\n        else if (origin) {\n            x = origin[0] + x;\n            y = origin[1] + y;\n        }\n        var rotate$$1 = -style.textRotation || 0;\n        var transform = create$1();\n        // Apply textRotate to element matrix\n        rotate(transform, transform, rotate$$1);\n\n        var pos = [el.transform[4], el.transform[5]];\n        translate(transform, transform, pos);\n        setTransform(textSvgEl, transform);\n    }\n\n    var textLines = text.split('\\n');\n    var nTextLines = textLines.length;\n    var textAnchor = align;\n    // PENDING\n    if (textAnchor === 'left') {\n        textAnchor = 'start';\n        textPadding && (x += textPadding[3]);\n    }\n    else if (textAnchor === 'right') {\n        textAnchor = 'end';\n        textPadding && (x -= textPadding[1]);\n    }\n    else if (textAnchor === 'center') {\n        textAnchor = 'middle';\n        textPadding && (x += (textPadding[3] - textPadding[1]) / 2);\n    }\n\n    var dy = 0;\n    if (verticalAlign === 'after-edge') {\n        dy = -textRect.height + lineHeight;\n        textPadding && (dy -= textPadding[2]);\n    }\n    else if (verticalAlign === 'middle') {\n        dy = (-textRect.height + lineHeight) / 2;\n        textPadding && (y += (textPadding[0] - textPadding[2]) / 2);\n    }\n    else {\n        textPadding && (dy += textPadding[0]);\n    }\n\n    // Font may affect position of each tspan elements\n    if (el.__text !== text || el.__textFont !== font) {\n        var tspanList = el.__tspanList || [];\n        el.__tspanList = tspanList;\n        for (var i = 0; i < nTextLines; i++) {\n            // Using cached tspan elements\n            var tspan = tspanList[i];\n            if (!tspan) {\n                tspan = tspanList[i] = createElement('tspan');\n                textSvgEl.appendChild(tspan);\n                attr(tspan, 'alignment-baseline', verticalAlign);\n                attr(tspan, 'text-anchor', textAnchor);\n            }\n            else {\n                tspan.innerHTML = '';\n            }\n            attr(tspan, 'x', x);\n            attr(tspan, 'y', y + i * lineHeight + dy);\n            tspan.appendChild(document.createTextNode(textLines[i]));\n        }\n        // Remove unsed tspan elements\n        for (; i < tspanList.length; i++) {\n            textSvgEl.removeChild(tspanList[i]);\n        }\n        tspanList.length = nTextLines;\n\n        el.__text = text;\n        el.__textFont = font;\n    }\n    else if (el.__tspanList.length) {\n        // Update span x and y\n        var len = el.__tspanList.length;\n        for (var i = 0; i < len; ++i) {\n            var tspan = el.__tspanList[i];\n            if (tspan) {\n                attr(tspan, 'x', x);\n                attr(tspan, 'y', y + i * lineHeight + dy);\n            }\n        }\n    }\n};\n\nfunction getVerticalAlignForSvg(verticalAlign) {\n    if (verticalAlign === 'middle') {\n        return 'middle';\n    }\n    else if (verticalAlign === 'bottom') {\n        return 'after-edge';\n    }\n    else {\n        return 'hanging';\n    }\n}\n\nsvgText.drawRectText = svgTextDrawRectText;\n\nsvgText.brush = function (el) {\n    var style = el.style;\n    if (style.text != null) {\n        // 强制设置 textPosition\n        style.textPosition = [0, 0];\n        svgTextDrawRectText(el, {\n            x: style.x || 0, y: style.y || 0,\n            width: 0, height: 0\n        }, el.getBoundingRect());\n    }\n};\n\n// Myers' Diff Algorithm\n// Modified from https://github.com/kpdecker/jsdiff/blob/master/src/diff/base.js\n\nfunction Diff() {}\n\nDiff.prototype = {\n    diff: function (oldArr, newArr, equals) {\n        if (!equals) {\n            equals = function (a, b) {\n                return a === b;\n            };\n        }\n        this.equals = equals;\n\n        var self = this;\n\n        oldArr = oldArr.slice();\n        newArr = newArr.slice();\n        // Allow subclasses to massage the input prior to running\n        var newLen = newArr.length;\n        var oldLen = oldArr.length;\n        var editLength = 1;\n        var maxEditLength = newLen + oldLen;\n        var bestPath = [{ newPos: -1, components: [] }];\n\n        // Seed editLength = 0, i.e. the content starts with the same values\n        var oldPos = this.extractCommon(bestPath[0], newArr, oldArr, 0);\n        if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) {\n            var indices = [];\n            for (var i = 0; i < newArr.length; i++) {\n                indices.push(i);\n            }\n            // Identity per the equality and tokenizer\n            return [{\n                indices: indices, count: newArr.length\n            }];\n        }\n\n        // Main worker method. checks all permutations of a given edit length for acceptance.\n        function execEditLength() {\n            for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) {\n                var basePath;\n                var addPath = bestPath[diagonalPath - 1];\n                var removePath = bestPath[diagonalPath + 1];\n                var oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;\n                if (addPath) {\n                    // No one else is going to attempt to use this value, clear it\n                    bestPath[diagonalPath - 1] = undefined;\n                }\n\n                var canAdd = addPath && addPath.newPos + 1 < newLen;\n                var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;\n                if (!canAdd && !canRemove) {\n                    // If this path is a terminal then prune\n                    bestPath[diagonalPath] = undefined;\n                    continue;\n                }\n\n                // Select the diagonal that we want to branch from. We select the prior\n                // path whose position in the new string is the farthest from the origin\n                // and does not pass the bounds of the diff graph\n                if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {\n                    basePath = clonePath(removePath);\n                    self.pushComponent(basePath.components, undefined, true);\n                }\n                else {\n                    basePath = addPath;   // No need to clone, we've pulled it from the list\n                    basePath.newPos++;\n                    self.pushComponent(basePath.components, true, undefined);\n                }\n\n                oldPos = self.extractCommon(basePath, newArr, oldArr, diagonalPath);\n\n                // If we have hit the end of both strings, then we are done\n                if (basePath.newPos + 1 >= newLen && oldPos + 1 >= oldLen) {\n                    return buildValues(self, basePath.components, newArr, oldArr);\n                }\n                else {\n                    // Otherwise track this path as a potential candidate and continue.\n                    bestPath[diagonalPath] = basePath;\n                }\n            }\n\n            editLength++;\n        }\n\n        while (editLength <= maxEditLength) {\n            var ret = execEditLength();\n            if (ret) {\n                return ret;\n            }\n        }\n    },\n\n    pushComponent: function (components, added, removed) {\n        var last = components[components.length - 1];\n        if (last && last.added === added && last.removed === removed) {\n            // We need to clone here as the component clone operation is just\n            // as shallow array clone\n            components[components.length - 1] = {count: last.count + 1, added: added, removed: removed };\n        }\n        else {\n            components.push({count: 1, added: added, removed: removed });\n        }\n    },\n    extractCommon: function (basePath, newArr, oldArr, diagonalPath) {\n        var newLen = newArr.length;\n        var oldLen = oldArr.length;\n        var newPos = basePath.newPos;\n        var oldPos = newPos - diagonalPath;\n        var commonCount = 0;\n\n        while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newArr[newPos + 1], oldArr[oldPos + 1])) {\n            newPos++;\n            oldPos++;\n            commonCount++;\n        }\n\n        if (commonCount) {\n            basePath.components.push({count: commonCount});\n        }\n\n        basePath.newPos = newPos;\n        return oldPos;\n    },\n    tokenize: function (value) {\n        return value.slice();\n    },\n    join: function (value) {\n        return value.slice();\n    }\n};\n\nfunction buildValues(diff, components, newArr, oldArr) {\n    var componentPos = 0;\n    var componentLen = components.length;\n    var newPos = 0;\n    var oldPos = 0;\n\n    for (; componentPos < componentLen; componentPos++) {\n        var component = components[componentPos];\n        if (!component.removed) {\n            var indices = [];\n            for (var i = newPos; i < newPos + component.count; i++) {\n                indices.push(i);\n            }\n            component.indices = indices;\n            newPos += component.count;\n            // Common case\n            if (!component.added) {\n                oldPos += component.count;\n            }\n        }\n        else {\n            var indices = [];\n            for (var i = oldPos; i < oldPos + component.count; i++) {\n                indices.push(i);\n            }\n            component.indices = indices;\n            oldPos += component.count;\n        }\n    }\n\n    return components;\n}\n\nfunction clonePath(path) {\n    return { newPos: path.newPos, components: path.components.slice(0) };\n}\n\nvar arrayDiff = new Diff();\n\nvar arrayDiff$1 = function (oldArr, newArr, callback) {\n    return arrayDiff.diff(oldArr, newArr, callback);\n};\n\n/**\n * @file Manages elements that can be defined in <defs> in SVG,\n *       e.g., gradients, clip path, etc.\n * @author Zhang Wenli\n */\n\nvar MARK_UNUSED = '0';\nvar MARK_USED = '1';\n\n/**\n * Manages elements that can be defined in <defs> in SVG,\n * e.g., gradients, clip path, etc.\n *\n * @class\n * @param {number}          zrId      zrender instance id\n * @param {SVGElement}      svgRoot   root of SVG document\n * @param {string|string[]} tagNames  possible tag names\n * @param {string}          markLabel label name to make if the element\n *                                    is used\n */\nfunction Definable(\n    zrId,\n    svgRoot,\n    tagNames,\n    markLabel,\n    domName\n) {\n    this._zrId = zrId;\n    this._svgRoot = svgRoot;\n    this._tagNames = typeof tagNames === 'string' ? [tagNames] : tagNames;\n    this._markLabel = markLabel;\n    this._domName = domName || '_dom';\n\n    this.nextId = 0;\n}\n\n\nDefinable.prototype.createElement = createElement;\n\n\n/**\n * Get the <defs> tag for svgRoot; optionally creates one if not exists.\n *\n * @param {boolean} isForceCreating if need to create when not exists\n * @return {SVGDefsElement} SVG <defs> element, null if it doesn't\n * exist and isForceCreating is false\n */\nDefinable.prototype.getDefs = function (isForceCreating) {\n    var svgRoot = this._svgRoot;\n    var defs = this._svgRoot.getElementsByTagName('defs');\n    if (defs.length === 0) {\n        // Not exist\n        if (isForceCreating) {\n            defs = svgRoot.insertBefore(\n                this.createElement('defs'), // Create new tag\n                svgRoot.firstChild // Insert in the front of svg\n            );\n            if (!defs.contains) {\n                // IE doesn't support contains method\n                defs.contains = function (el) {\n                    var children = defs.children;\n                    if (!children) {\n                        return false;\n                    }\n                    for (var i = children.length - 1; i >= 0; --i) {\n                        if (children[i] === el) {\n                            return true;\n                        }\n                    }\n                    return false;\n                };\n            }\n            return defs;\n        }\n        else {\n            return null;\n        }\n    }\n    else {\n        return defs[0];\n    }\n};\n\n\n/**\n * Update DOM element if necessary.\n *\n * @param {Object|string} element style element. e.g., for gradient,\n *                                it may be '#ccc' or {type: 'linear', ...}\n * @param {Function|undefined} onUpdate update callback\n */\nDefinable.prototype.update = function (element, onUpdate) {\n    if (!element) {\n        return;\n    }\n\n    var defs = this.getDefs(false);\n    if (element[this._domName] && defs.contains(element[this._domName])) {\n        // Update DOM\n        if (typeof onUpdate === 'function') {\n            onUpdate(element);\n        }\n    }\n    else {\n        // No previous dom, create new\n        var dom = this.add(element);\n        if (dom) {\n            element[this._domName] = dom;\n        }\n    }\n};\n\n\n/**\n * Add gradient dom to defs\n *\n * @param {SVGElement} dom DOM to be added to <defs>\n */\nDefinable.prototype.addDom = function (dom) {\n    var defs = this.getDefs(true);\n    defs.appendChild(dom);\n};\n\n\n/**\n * Remove DOM of a given element.\n *\n * @param {SVGElement} element element to remove dom\n */\nDefinable.prototype.removeDom = function (element) {\n    var defs = this.getDefs(false);\n    if (defs && element[this._domName]) {\n        defs.removeChild(element[this._domName]);\n        element[this._domName] = null;\n    }\n};\n\n\n/**\n * Get DOMs of this element.\n *\n * @return {HTMLDomElement} doms of this defineable elements in <defs>\n */\nDefinable.prototype.getDoms = function () {\n    var defs = this.getDefs(false);\n    if (!defs) {\n        // No dom when defs is not defined\n        return [];\n    }\n\n    var doms = [];\n    each$1(this._tagNames, function (tagName) {\n        var tags = defs.getElementsByTagName(tagName);\n        // Note that tags is HTMLCollection, which is array-like\n        // rather than real array.\n        // So `doms.concat(tags)` add tags as one object.\n        doms = doms.concat([].slice.call(tags));\n    });\n\n    return doms;\n};\n\n\n/**\n * Mark DOMs to be unused before painting, and clear unused ones at the end\n * of the painting.\n */\nDefinable.prototype.markAllUnused = function () {\n    var doms = this.getDoms();\n    var that = this;\n    each$1(doms, function (dom) {\n        dom[that._markLabel] = MARK_UNUSED;\n    });\n};\n\n\n/**\n * Mark a single DOM to be used.\n *\n * @param {SVGElement} dom DOM to mark\n */\nDefinable.prototype.markUsed = function (dom) {\n    if (dom) {\n        dom[this._markLabel] = MARK_USED;\n    }\n};\n\n\n/**\n * Remove unused DOMs defined in <defs>\n */\nDefinable.prototype.removeUnused = function () {\n    var defs = this.getDefs(false);\n    if (!defs) {\n        // Nothing to remove\n        return;\n    }\n\n    var doms = this.getDoms();\n    var that = this;\n    each$1(doms, function (dom) {\n        if (dom[that._markLabel] !== MARK_USED) {\n            // Remove gradient\n            defs.removeChild(dom);\n        }\n    });\n};\n\n\n/**\n * Get SVG proxy.\n *\n * @param {Displayable} displayable displayable element\n * @return {Path|Image|Text} svg proxy of given element\n */\nDefinable.prototype.getSvgProxy = function (displayable) {\n    if (displayable instanceof Path) {\n        return svgPath;\n    }\n    else if (displayable instanceof ZImage) {\n        return svgImage;\n    }\n    else if (displayable instanceof Text) {\n        return svgText;\n    }\n    else {\n        return svgPath;\n    }\n};\n\n\n/**\n * Get text SVG element.\n *\n * @param {Displayable} displayable displayable element\n * @return {SVGElement} SVG element of text\n */\nDefinable.prototype.getTextSvgElement = function (displayable) {\n    return displayable.__textSvgEl;\n};\n\n\n/**\n * Get SVG element.\n *\n * @param {Displayable} displayable displayable element\n * @return {SVGElement} SVG element\n */\nDefinable.prototype.getSvgElement = function (displayable) {\n    return displayable.__svgEl;\n};\n\n/**\n * @file Manages SVG gradient elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG gradient elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction GradientManager(zrId, svgRoot) {\n    Definable.call(\n        this,\n        zrId,\n        svgRoot,\n        ['linearGradient', 'radialGradient'],\n        '__gradient_in_use__'\n    );\n}\n\n\ninherits(GradientManager, Definable);\n\n\n/**\n * Create new gradient DOM for fill or stroke if not exist,\n * but will not update gradient if exists.\n *\n * @param {SvgElement}  svgElement   SVG element to paint\n * @param {Displayable} displayable  zrender displayable element\n */\nGradientManager.prototype.addWithoutUpdate = function (\n    svgElement,\n    displayable\n) {\n    if (displayable && displayable.style) {\n        var that = this;\n        each$1(['fill', 'stroke'], function (fillOrStroke) {\n            if (displayable.style[fillOrStroke]\n                && (displayable.style[fillOrStroke].type === 'linear'\n                || displayable.style[fillOrStroke].type === 'radial')\n            ) {\n                var gradient = displayable.style[fillOrStroke];\n                var defs = that.getDefs(true);\n\n                // Create dom in <defs> if not exists\n                var dom;\n                if (gradient._dom) {\n                    // Gradient exists\n                    dom = gradient._dom;\n                    if (!defs.contains(gradient._dom)) {\n                        // _dom is no longer in defs, recreate\n                        that.addDom(dom);\n                    }\n                }\n                else {\n                    // New dom\n                    dom = that.add(gradient);\n                }\n\n                that.markUsed(displayable);\n\n                var id = dom.getAttribute('id');\n                svgElement.setAttribute(fillOrStroke, 'url(#' + id + ')');\n            }\n        });\n    }\n};\n\n\n/**\n * Add a new gradient tag in <defs>\n *\n * @param   {Gradient} gradient zr gradient instance\n * @return {SVGLinearGradientElement | SVGRadialGradientElement}\n *                            created DOM\n */\nGradientManager.prototype.add = function (gradient) {\n    var dom;\n    if (gradient.type === 'linear') {\n        dom = this.createElement('linearGradient');\n    }\n    else if (gradient.type === 'radial') {\n        dom = this.createElement('radialGradient');\n    }\n    else {\n        zrLog('Illegal gradient type.');\n        return null;\n    }\n\n    // Set dom id with gradient id, since each gradient instance\n    // will have no more than one dom element.\n    // id may exists before for those dirty elements, in which case\n    // id should remain the same, and other attributes should be\n    // updated.\n    gradient.id = gradient.id || this.nextId++;\n    dom.setAttribute('id', 'zr' + this._zrId\n        + '-gradient-' + gradient.id);\n\n    this.updateDom(gradient, dom);\n    this.addDom(dom);\n\n    return dom;\n};\n\n\n/**\n * Update gradient.\n *\n * @param {Gradient} gradient zr gradient instance\n */\nGradientManager.prototype.update = function (gradient) {\n    var that = this;\n    Definable.prototype.update.call(this, gradient, function () {\n        var type = gradient.type;\n        var tagName = gradient._dom.tagName;\n        if (type === 'linear' && tagName === 'linearGradient'\n            || type === 'radial' && tagName === 'radialGradient'\n        ) {\n            // Gradient type is not changed, update gradient\n            that.updateDom(gradient, gradient._dom);\n        }\n        else {\n            // Remove and re-create if type is changed\n            that.removeDom(gradient);\n            that.add(gradient);\n        }\n    });\n};\n\n\n/**\n * Update gradient dom\n *\n * @param {Gradient} gradient zr gradient instance\n * @param {SVGLinearGradientElement | SVGRadialGradientElement} dom\n *                            DOM to update\n */\nGradientManager.prototype.updateDom = function (gradient, dom) {\n    if (gradient.type === 'linear') {\n        dom.setAttribute('x1', gradient.x);\n        dom.setAttribute('y1', gradient.y);\n        dom.setAttribute('x2', gradient.x2);\n        dom.setAttribute('y2', gradient.y2);\n    }\n    else if (gradient.type === 'radial') {\n        dom.setAttribute('cx', gradient.x);\n        dom.setAttribute('cy', gradient.y);\n        dom.setAttribute('r', gradient.r);\n    }\n    else {\n        zrLog('Illegal gradient type.');\n        return;\n    }\n\n    if (gradient.global) {\n        // x1, x2, y1, y2 in range of 0 to canvas width or height\n        dom.setAttribute('gradientUnits', 'userSpaceOnUse');\n    }\n    else {\n        // x1, x2, y1, y2 in range of 0 to 1\n        dom.setAttribute('gradientUnits', 'objectBoundingBox');\n    }\n\n    // Remove color stops if exists\n    dom.innerHTML = '';\n\n    // Add color stops\n    var colors = gradient.colorStops;\n    for (var i = 0, len = colors.length; i < len; ++i) {\n        var stop = this.createElement('stop');\n        stop.setAttribute('offset', colors[i].offset * 100 + '%');\n\n        var color = colors[i].color;\n        if (color.indexOf('rgba' > -1)) {\n            // Fix Safari bug that stop-color not recognizing alpha #9014\n            var opacity = parse(color)[3];\n            var hex = toHex(color);\n\n            // stop-color cannot be color, since:\n            // The opacity value used for the gradient calculation is the\n            // *product* of the value of stop-opacity and the opacity of the\n            // value of stop-color.\n            // See https://www.w3.org/TR/SVG2/pservers.html#StopOpacityProperty\n            stop.setAttribute('stop-color', '#' + hex);\n            stop.setAttribute('stop-opacity', opacity);\n        }\n        else {\n            stop.setAttribute('stop-color', colors[i].color);\n        }\n\n        dom.appendChild(stop);\n    }\n\n    // Store dom element in gradient, to avoid creating multiple\n    // dom instances for the same gradient element\n    gradient._dom = dom;\n};\n\n/**\n * Mark a single gradient to be used\n *\n * @param {Displayable} displayable displayable element\n */\nGradientManager.prototype.markUsed = function (displayable) {\n    if (displayable.style) {\n        var gradient = displayable.style.fill;\n        if (gradient && gradient._dom) {\n            Definable.prototype.markUsed.call(this, gradient._dom);\n        }\n\n        gradient = displayable.style.stroke;\n        if (gradient && gradient._dom) {\n            Definable.prototype.markUsed.call(this, gradient._dom);\n        }\n    }\n};\n\n/**\n * @file Manages SVG clipPath elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG clipPath elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction ClippathManager(zrId, svgRoot) {\n    Definable.call(this, zrId, svgRoot, 'clipPath', '__clippath_in_use__');\n}\n\n\ninherits(ClippathManager, Definable);\n\n\n/**\n * Update clipPath.\n *\n * @param {Displayable} displayable displayable element\n */\nClippathManager.prototype.update = function (displayable) {\n    var svgEl = this.getSvgElement(displayable);\n    if (svgEl) {\n        this.updateDom(svgEl, displayable.__clipPaths, false);\n    }\n\n    var textEl = this.getTextSvgElement(displayable);\n    if (textEl) {\n        // Make another clipPath for text, since it's transform\n        // matrix is not the same with svgElement\n        this.updateDom(textEl, displayable.__clipPaths, true);\n    }\n\n    this.markUsed(displayable);\n};\n\n\n/**\n * Create an SVGElement of displayable and create a <clipPath> of its\n * clipPath\n *\n * @param {Displayable} parentEl  parent element\n * @param {ClipPath[]}  clipPaths clipPaths of parent element\n * @param {boolean}     isText    if parent element is Text\n */\nClippathManager.prototype.updateDom = function (\n    parentEl,\n    clipPaths,\n    isText\n) {\n    if (clipPaths && clipPaths.length > 0) {\n        // Has clipPath, create <clipPath> with the first clipPath\n        var defs = this.getDefs(true);\n        var clipPath = clipPaths[0];\n        var clipPathEl;\n        var id;\n\n        var dom = isText ? '_textDom' : '_dom';\n\n        if (clipPath[dom]) {\n            // Use a dom that is already in <defs>\n            id = clipPath[dom].getAttribute('id');\n            clipPathEl = clipPath[dom];\n\n            // Use a dom that is already in <defs>\n            if (!defs.contains(clipPathEl)) {\n                // This happens when set old clipPath that has\n                // been previously removed\n                defs.appendChild(clipPathEl);\n            }\n        }\n        else {\n            // New <clipPath>\n            id = 'zr' + this._zrId + '-clip-' + this.nextId;\n            ++this.nextId;\n            clipPathEl = this.createElement('clipPath');\n            clipPathEl.setAttribute('id', id);\n            defs.appendChild(clipPathEl);\n\n            clipPath[dom] = clipPathEl;\n        }\n\n        // Build path and add to <clipPath>\n        var svgProxy = this.getSvgProxy(clipPath);\n        if (clipPath.transform\n            && clipPath.parent.invTransform\n            && !isText\n        ) {\n            /**\n             * If a clipPath has a parent with transform, the transform\n             * of parent should not be considered when setting transform\n             * of clipPath. So we need to transform back from parent's\n             * transform, which is done by multiplying parent's inverse\n             * transform.\n             */\n            // Store old transform\n            var transform = Array.prototype.slice.call(\n                clipPath.transform\n            );\n\n            // Transform back from parent, and brush path\n            mul$1(\n                clipPath.transform,\n                clipPath.parent.invTransform,\n                clipPath.transform\n            );\n            svgProxy.brush(clipPath);\n\n            // Set back transform of clipPath\n            clipPath.transform = transform;\n        }\n        else {\n            svgProxy.brush(clipPath);\n        }\n\n        var pathEl = this.getSvgElement(clipPath);\n\n        clipPathEl.innerHTML = '';\n        /**\n         * Use `cloneNode()` here to appendChild to multiple parents,\n         * which may happend when Text and other shapes are using the same\n         * clipPath. Since Text will create an extra clipPath DOM due to\n         * different transform rules.\n         */\n        clipPathEl.appendChild(pathEl.cloneNode());\n\n        parentEl.setAttribute('clip-path', 'url(#' + id + ')');\n\n        if (clipPaths.length > 1) {\n            // Make the other clipPaths recursively\n            this.updateDom(clipPathEl, clipPaths.slice(1), isText);\n        }\n    }\n    else {\n        // No clipPath\n        if (parentEl) {\n            parentEl.setAttribute('clip-path', 'none');\n        }\n    }\n};\n\n/**\n * Mark a single clipPath to be used\n *\n * @param {Displayable} displayable displayable element\n */\nClippathManager.prototype.markUsed = function (displayable) {\n    var that = this;\n    if (displayable.__clipPaths && displayable.__clipPaths.length > 0) {\n        each$1(displayable.__clipPaths, function (clipPath) {\n            if (clipPath._dom) {\n                Definable.prototype.markUsed.call(that, clipPath._dom);\n            }\n            if (clipPath._textDom) {\n                Definable.prototype.markUsed.call(that, clipPath._textDom);\n            }\n        });\n    }\n};\n\n/**\n * @file Manages SVG shadow elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG shadow elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction ShadowManager(zrId, svgRoot) {\n    Definable.call(\n        this,\n        zrId,\n        svgRoot,\n        ['filter'],\n        '__filter_in_use__',\n        '_shadowDom'\n    );\n}\n\n\ninherits(ShadowManager, Definable);\n\n\n/**\n * Create new shadow DOM for fill or stroke if not exist,\n * but will not update shadow if exists.\n *\n * @param {SvgElement}  svgElement   SVG element to paint\n * @param {Displayable} displayable  zrender displayable element\n */\nShadowManager.prototype.addWithoutUpdate = function (\n    svgElement,\n    displayable\n) {\n    if (displayable && hasShadow(displayable.style)) {\n        var style = displayable.style;\n\n        // Create dom in <defs> if not exists\n        var dom;\n        if (style._shadowDom) {\n            // Gradient exists\n            dom = style._shadowDom;\n\n            var defs = this.getDefs(true);\n            if (!defs.contains(style._shadowDom)) {\n                // _shadowDom is no longer in defs, recreate\n                this.addDom(dom);\n            }\n        }\n        else {\n            // New dom\n            dom = this.add(displayable);\n        }\n\n        this.markUsed(displayable);\n\n        var id = dom.getAttribute('id');\n        svgElement.style.filter = 'url(#' + id + ')';\n    }\n};\n\n\n/**\n * Add a new shadow tag in <defs>\n *\n * @param {Displayable} displayable  zrender displayable element\n * @return {SVGFilterElement} created DOM\n */\nShadowManager.prototype.add = function (displayable) {\n    var dom = this.createElement('filter');\n    var style = displayable.style;\n\n    // Set dom id with shadow id, since each shadow instance\n    // will have no more than one dom element.\n    // id may exists before for those dirty elements, in which case\n    // id should remain the same, and other attributes should be\n    // updated.\n    style._shadowDomId = style._shadowDomId || this.nextId++;\n    dom.setAttribute('id', 'zr' + this._zrId\n        + '-shadow-' + style._shadowDomId);\n\n    this.updateDom(displayable, dom);\n    this.addDom(dom);\n\n    return dom;\n};\n\n\n/**\n * Update shadow.\n *\n * @param {Displayable} displayable  zrender displayable element\n */\nShadowManager.prototype.update = function (svgElement, displayable) {\n    var style = displayable.style;\n    if (hasShadow(style)) {\n        var that = this;\n        Definable.prototype.update.call(this, displayable, function (style) {\n            that.updateDom(displayable, style._shadowDom);\n        });\n    }\n    else {\n        // Remove shadow\n        this.remove(svgElement, style);\n    }\n};\n\n\n/**\n * Remove DOM and clear parent filter\n */\nShadowManager.prototype.remove = function (svgElement, style) {\n    if (style._shadowDomId != null) {\n        this.removeDom(style);\n        svgElement.style.filter = '';\n    }\n};\n\n\n/**\n * Update shadow dom\n *\n * @param {Displayable} displayable  zrender displayable element\n * @param {SVGFilterElement} dom DOM to update\n */\nShadowManager.prototype.updateDom = function (displayable, dom) {\n    var domChild = dom.getElementsByTagName('feDropShadow');\n    if (domChild.length === 0) {\n        domChild = this.createElement('feDropShadow');\n    }\n    else {\n        domChild = domChild[0];\n    }\n\n    var style = displayable.style;\n    var scaleX = displayable.scale ? (displayable.scale[0] || 1) : 1;\n    var scaleY = displayable.scale ? (displayable.scale[1] || 1) : 1;\n\n    // TODO: textBoxShadowBlur is not supported yet\n    var offsetX, offsetY, blur, color;\n    if (style.shadowBlur || style.shadowOffsetX || style.shadowOffsetY) {\n        offsetX = style.shadowOffsetX || 0;\n        offsetY = style.shadowOffsetY || 0;\n        blur = style.shadowBlur;\n        color = style.shadowColor;\n    }\n    else if (style.textShadowBlur) {\n        offsetX = style.textShadowOffsetX || 0;\n        offsetY = style.textShadowOffsetY || 0;\n        blur = style.textShadowBlur;\n        color = style.textShadowColor;\n    }\n    else {\n        // Remove shadow\n        this.removeDom(dom, style);\n        return;\n    }\n\n    domChild.setAttribute('dx', offsetX / scaleX);\n    domChild.setAttribute('dy', offsetY / scaleY);\n    domChild.setAttribute('flood-color', color);\n\n    // Divide by two here so that it looks the same as in canvas\n    // See: https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-shadowblur\n    var stdDx = blur / 2 / scaleX;\n    var stdDy = blur / 2 / scaleY;\n    var stdDeviation = stdDx + ' ' + stdDy;\n    domChild.setAttribute('stdDeviation', stdDeviation);\n\n    // Fix filter clipping problem\n    dom.setAttribute('x', '-100%');\n    dom.setAttribute('y', '-100%');\n    dom.setAttribute('width', Math.ceil(blur / 2 * 200) + '%');\n    dom.setAttribute('height', Math.ceil(blur / 2 * 200) + '%');\n\n    dom.appendChild(domChild);\n\n    // Store dom element in shadow, to avoid creating multiple\n    // dom instances for the same shadow element\n    style._shadowDom = dom;\n};\n\n/**\n * Mark a single shadow to be used\n *\n * @param {Displayable} displayable displayable element\n */\nShadowManager.prototype.markUsed = function (displayable) {\n    var style = displayable.style;\n    if (style && style._shadowDom) {\n        Definable.prototype.markUsed.call(this, style._shadowDom);\n    }\n};\n\nfunction hasShadow(style) {\n    // TODO: textBoxShadowBlur is not supported yet\n    return style\n        && (style.shadowBlur || style.shadowOffsetX || style.shadowOffsetY\n            || style.textShadowBlur || style.textShadowOffsetX\n            || style.textShadowOffsetY);\n}\n\n/**\n * SVG Painter\n * @module zrender/svg/Painter\n */\n\nfunction parseInt10$2(val) {\n    return parseInt(val, 10);\n}\n\nfunction getSvgProxy(el) {\n    if (el instanceof Path) {\n        return svgPath;\n    }\n    else if (el instanceof ZImage) {\n        return svgImage;\n    }\n    else if (el instanceof Text) {\n        return svgText;\n    }\n    else {\n        return svgPath;\n    }\n}\n\nfunction checkParentAvailable(parent, child) {\n    return child && parent && child.parentNode !== parent;\n}\n\nfunction insertAfter(parent, child, prevSibling) {\n    if (checkParentAvailable(parent, child) && prevSibling) {\n        var nextSibling = prevSibling.nextSibling;\n        nextSibling ? parent.insertBefore(child, nextSibling)\n            : parent.appendChild(child);\n    }\n}\n\nfunction prepend(parent, child) {\n    if (checkParentAvailable(parent, child)) {\n        var firstChild = parent.firstChild;\n        firstChild ? parent.insertBefore(child, firstChild)\n            : parent.appendChild(child);\n    }\n}\n\nfunction remove$1(parent, child) {\n    if (child && parent && child.parentNode === parent) {\n        parent.removeChild(child);\n    }\n}\n\nfunction getTextSvgElement(displayable) {\n    return displayable.__textSvgEl;\n}\n\nfunction getSvgElement(displayable) {\n    return displayable.__svgEl;\n}\n\n/**\n * @alias module:zrender/svg/Painter\n * @constructor\n * @param {HTMLElement} root 绘图容器\n * @param {module:zrender/Storage} storage\n * @param {Object} opts\n */\nvar SVGPainter = function (root, storage, opts, zrId) {\n\n    this.root = root;\n    this.storage = storage;\n    this._opts = opts = extend({}, opts || {});\n\n    var svgRoot = createElement('svg');\n    svgRoot.setAttribute('xmlns', 'http://www.w3.org/2000/svg');\n    svgRoot.setAttribute('version', '1.1');\n    svgRoot.setAttribute('baseProfile', 'full');\n    svgRoot.style.cssText = 'user-select:none;position:absolute;left:0;top:0;';\n\n    this.gradientManager = new GradientManager(zrId, svgRoot);\n    this.clipPathManager = new ClippathManager(zrId, svgRoot);\n    this.shadowManager = new ShadowManager(zrId, svgRoot);\n\n    var viewport = document.createElement('div');\n    viewport.style.cssText = 'overflow:hidden;position:relative';\n\n    this._svgRoot = svgRoot;\n    this._viewport = viewport;\n\n    root.appendChild(viewport);\n    viewport.appendChild(svgRoot);\n\n    this.resize(opts.width, opts.height);\n\n    this._visibleList = [];\n};\n\nSVGPainter.prototype = {\n\n    constructor: SVGPainter,\n\n    getType: function () {\n        return 'svg';\n    },\n\n    getViewportRoot: function () {\n        return this._viewport;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    refresh: function () {\n\n        var list = this.storage.getDisplayList(true);\n\n        this._paintList(list);\n    },\n\n    setBackgroundColor: function (backgroundColor) {\n        // TODO gradient\n        this._viewport.style.background = backgroundColor;\n    },\n\n    _paintList: function (list) {\n        this.gradientManager.markAllUnused();\n        this.clipPathManager.markAllUnused();\n        this.shadowManager.markAllUnused();\n\n        var svgRoot = this._svgRoot;\n        var visibleList = this._visibleList;\n        var listLen = list.length;\n\n        var newVisibleList = [];\n        var i;\n        for (i = 0; i < listLen; i++) {\n            var displayable = list[i];\n            var svgProxy = getSvgProxy(displayable);\n            var svgElement = getSvgElement(displayable)\n                || getTextSvgElement(displayable);\n            if (!displayable.invisible) {\n                if (displayable.__dirty) {\n                    svgProxy && svgProxy.brush(displayable);\n\n                    // Update clipPath\n                    this.clipPathManager.update(displayable);\n\n                    // Update gradient and shadow\n                    if (displayable.style) {\n                        this.gradientManager\n                            .update(displayable.style.fill);\n                        this.gradientManager\n                            .update(displayable.style.stroke);\n\n                        this.shadowManager\n                            .update(svgElement, displayable);\n                    }\n\n                    displayable.__dirty = false;\n                }\n                newVisibleList.push(displayable);\n            }\n        }\n\n        var diff = arrayDiff$1(visibleList, newVisibleList);\n        var prevSvgElement;\n\n        // First do remove, in case element moved to the head and do remove\n        // after add\n        for (i = 0; i < diff.length; i++) {\n            var item = diff[i];\n            if (item.removed) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = visibleList[item.indices[k]];\n                    var svgElement = getSvgElement(displayable);\n                    var textSvgElement = getTextSvgElement(displayable);\n                    remove$1(svgRoot, svgElement);\n                    remove$1(svgRoot, textSvgElement);\n                }\n            }\n        }\n        for (i = 0; i < diff.length; i++) {\n            var item = diff[i];\n            if (item.added) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = newVisibleList[item.indices[k]];\n                    var svgElement = getSvgElement(displayable);\n                    var textSvgElement = getTextSvgElement(displayable);\n                    prevSvgElement\n                        ? insertAfter(svgRoot, svgElement, prevSvgElement)\n                        : prepend(svgRoot, svgElement);\n                    if (svgElement) {\n                        insertAfter(svgRoot, textSvgElement, svgElement);\n                    }\n                    else if (prevSvgElement) {\n                        insertAfter(\n                            svgRoot, textSvgElement, prevSvgElement\n                        );\n                    }\n                    else {\n                        prepend(svgRoot, textSvgElement);\n                    }\n                    // Insert text\n                    insertAfter(svgRoot, textSvgElement, svgElement);\n                    prevSvgElement = textSvgElement || svgElement\n                        || prevSvgElement;\n\n                    this.gradientManager\n                        .addWithoutUpdate(svgElement, displayable);\n                    this.shadowManager\n                        .addWithoutUpdate(prevSvgElement, displayable);\n                    this.clipPathManager.markUsed(displayable);\n                }\n            }\n            else if (!item.removed) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = newVisibleList[item.indices[k]];\n                    prevSvgElement =\n                        svgElement =\n                        getTextSvgElement(displayable)\n                        || getSvgElement(displayable)\n                        || prevSvgElement;\n\n                    this.gradientManager.markUsed(displayable);\n                    this.gradientManager\n                        .addWithoutUpdate(svgElement, displayable);\n\n                    this.shadowManager.markUsed(displayable);\n                    this.shadowManager\n                        .addWithoutUpdate(svgElement, displayable);\n\n                    this.clipPathManager.markUsed(displayable);\n                }\n            }\n        }\n\n        this.gradientManager.removeUnused();\n        this.clipPathManager.removeUnused();\n        this.shadowManager.removeUnused();\n\n        this._visibleList = newVisibleList;\n    },\n\n    _getDefs: function (isForceCreating) {\n        var svgRoot = this._svgRoot;\n        var defs = this._svgRoot.getElementsByTagName('defs');\n        if (defs.length === 0) {\n            // Not exist\n            if (isForceCreating) {\n                var defs = svgRoot.insertBefore(\n                    createElement('defs'), // Create new tag\n                    svgRoot.firstChild // Insert in the front of svg\n                );\n                if (!defs.contains) {\n                    // IE doesn't support contains method\n                    defs.contains = function (el) {\n                        var children = defs.children;\n                        if (!children) {\n                            return false;\n                        }\n                        for (var i = children.length - 1; i >= 0; --i) {\n                            if (children[i] === el) {\n                                return true;\n                            }\n                        }\n                        return false;\n                    };\n                }\n                return defs;\n            }\n            else {\n                return null;\n            }\n        }\n        else {\n            return defs[0];\n        }\n    },\n\n    resize: function (width, height) {\n        var viewport = this._viewport;\n        // FIXME Why ?\n        viewport.style.display = 'none';\n\n        // Save input w/h\n        var opts = this._opts;\n        width != null && (opts.width = width);\n        height != null && (opts.height = height);\n\n        width = this._getSize(0);\n        height = this._getSize(1);\n\n        viewport.style.display = '';\n\n        if (this._width !== width || this._height !== height) {\n            this._width = width;\n            this._height = height;\n\n            var viewportStyle = viewport.style;\n            viewportStyle.width = width + 'px';\n            viewportStyle.height = height + 'px';\n\n            var svgRoot = this._svgRoot;\n            // Set width by 'svgRoot.width = width' is invalid\n            svgRoot.setAttribute('width', width);\n            svgRoot.setAttribute('height', height);\n        }\n    },\n\n    /**\n     * 获取绘图区域宽度\n     */\n    getWidth: function () {\n        return this._width;\n    },\n\n    /**\n     * 获取绘图区域高度\n     */\n    getHeight: function () {\n        return this._height;\n    },\n\n    _getSize: function (whIdx) {\n        var opts = this._opts;\n        var wh = ['width', 'height'][whIdx];\n        var cwh = ['clientWidth', 'clientHeight'][whIdx];\n        var plt = ['paddingLeft', 'paddingTop'][whIdx];\n        var prb = ['paddingRight', 'paddingBottom'][whIdx];\n\n        if (opts[wh] != null && opts[wh] !== 'auto') {\n            return parseFloat(opts[wh]);\n        }\n\n        var root = this.root;\n        // IE8 does not support getComputedStyle, but it use VML.\n        var stl = document.defaultView.getComputedStyle(root);\n\n        return (\n            (root[cwh] || parseInt10$2(stl[wh]) || parseInt10$2(root.style[wh]))\n            - (parseInt10$2(stl[plt]) || 0)\n            - (parseInt10$2(stl[prb]) || 0)\n        ) | 0;\n    },\n\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this._svgRoot =\n            this._viewport =\n            this.storage =\n            null;\n    },\n\n    clear: function () {\n        if (this._viewport) {\n            this.root.removeChild(this._viewport);\n        }\n    },\n\n    pathToDataUrl: function () {\n        this.refresh();\n        var html = this._svgRoot.outerHTML;\n        return 'data:image/svg+xml;charset=UTF-8,' + html;\n    }\n};\n\n// Not supported methods\nfunction createMethodNotSupport$1(method) {\n    return function () {\n        zrLog('In SVG mode painter not support method \"' + method + '\"');\n    };\n}\n\n// Unsuppoted methods\neach$1([\n    'getLayer', 'insertLayer', 'eachLayer', 'eachBuiltinLayer',\n    'eachOtherLayer', 'getLayers', 'modLayer', 'delLayer', 'clearLayer',\n    'toDataURL', 'pathToImage'\n], function (name) {\n    SVGPainter.prototype[name] = createMethodNotSupport$1(name);\n});\n\nregisterPainter('svg', SVGPainter);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nexports.version = version;\nexports.dependencies = dependencies;\nexports.PRIORITY = PRIORITY;\nexports.init = init;\nexports.connect = connect;\nexports.disConnect = disConnect;\nexports.disconnect = disconnect;\nexports.dispose = dispose;\nexports.getInstanceByDom = getInstanceByDom;\nexports.getInstanceById = getInstanceById;\nexports.registerTheme = registerTheme;\nexports.registerPreprocessor = registerPreprocessor;\nexports.registerProcessor = registerProcessor;\nexports.registerPostUpdate = registerPostUpdate;\nexports.registerAction = registerAction;\nexports.registerCoordinateSystem = registerCoordinateSystem;\nexports.getCoordinateSystemDimensions = getCoordinateSystemDimensions;\nexports.registerLayout = registerLayout;\nexports.registerVisual = registerVisual;\nexports.registerLoading = registerLoading;\nexports.extendComponentModel = extendComponentModel;\nexports.extendComponentView = extendComponentView;\nexports.extendSeriesModel = extendSeriesModel;\nexports.extendChartView = extendChartView;\nexports.setCanvasCreator = setCanvasCreator;\nexports.registerMap = registerMap;\nexports.getMap = getMap;\nexports.dataTool = dataTool;\nexports.zrender = zrender;\nexports.number = number;\nexports.format = format;\nexports.throttle = throttle;\nexports.helper = helper;\nexports.matrix = matrix;\nexports.vector = vector;\nexports.color = color;\nexports.parseGeoJSON = parseGeoJSON;\nexports.parseGeoJson = parseGeoJson;\nexports.util = ecUtil;\nexports.graphic = graphic$1;\nexports.List = List;\nexports.Model = Model;\nexports.Axis = Axis;\nexports.env = env$1;\n\n})));\n"
  },
  {
    "path": "static/js/Echarts/echarts-en.js",
    "content": "(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n\ttypeof define === 'function' && define.amd ? define(['exports'], factory) :\n\t(factory((global.echarts = {})));\n}(this, (function (exports) { 'use strict';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (1) The code `if (__DEV__) ...` can be removed by build tool.\n// (2) If intend to use `__DEV__`, this module should be imported. Use a global\n// variable `__DEV__` may cause that miss the declaration (see #6535), or the\n// declaration is behind of the using position (for example in `Model.extent`,\n// And tools like rollup can not analysis the dependency if not import).\n\nvar dev;\n\n// In browser\nif (typeof window !== 'undefined') {\n    dev = window.__DEV__;\n}\n// In node\nelse if (typeof global !== 'undefined') {\n    dev = global.__DEV__;\n}\n\nif (typeof dev === 'undefined') {\n    dev = true;\n}\n\nvar __DEV__ = dev;\n\n/**\n * zrender: 生成唯一id\n *\n * @author errorrik (errorrik@gmail.com)\n */\n\nvar idStart = 0x0907;\n\nvar guid = function () {\n    return idStart++;\n};\n\n/**\n * echarts设备环境识别\n *\n * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。\n * @author firede[firede@firede.us]\n * @desc thanks zepto.\n */\n\nvar env = {};\n\nif (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') {\n    // In Weixin Application\n    env = {\n        browser: {},\n        os: {},\n        node: false,\n        wxa: true, // Weixin Application\n        canvasSupported: true,\n        svgSupported: false,\n        touchEventsSupported: true,\n        domSupported: false\n    };\n}\nelse if (typeof document === 'undefined' && typeof self !== 'undefined') {\n    // In worker\n    env = {\n        browser: {},\n        os: {},\n        node: false,\n        worker: true,\n        canvasSupported: true,\n        domSupported: false\n    };\n}\nelse if (typeof navigator === 'undefined') {\n    // In node\n    env = {\n        browser: {},\n        os: {},\n        node: true,\n        worker: false,\n        // Assume canvas is supported\n        canvasSupported: true,\n        svgSupported: true,\n        domSupported: false\n    };\n}\nelse {\n    env = detect(navigator.userAgent);\n}\n\nvar env$1 = env;\n\n// Zepto.js\n// (c) 2010-2013 Thomas Fuchs\n// Zepto.js may be freely distributed under the MIT license.\n\nfunction detect(ua) {\n    var os = {};\n    var browser = {};\n    // var webkit = ua.match(/Web[kK]it[\\/]{0,1}([\\d.]+)/);\n    // var android = ua.match(/(Android);?[\\s\\/]+([\\d.]+)?/);\n    // var ipad = ua.match(/(iPad).*OS\\s([\\d_]+)/);\n    // var ipod = ua.match(/(iPod)(.*OS\\s([\\d_]+))?/);\n    // var iphone = !ipad && ua.match(/(iPhone\\sOS)\\s([\\d_]+)/);\n    // var webos = ua.match(/(webOS|hpwOS)[\\s\\/]([\\d.]+)/);\n    // var touchpad = webos && ua.match(/TouchPad/);\n    // var kindle = ua.match(/Kindle\\/([\\d.]+)/);\n    // var silk = ua.match(/Silk\\/([\\d._]+)/);\n    // var blackberry = ua.match(/(BlackBerry).*Version\\/([\\d.]+)/);\n    // var bb10 = ua.match(/(BB10).*Version\\/([\\d.]+)/);\n    // var rimtabletos = ua.match(/(RIM\\sTablet\\sOS)\\s([\\d.]+)/);\n    // var playbook = ua.match(/PlayBook/);\n    // var chrome = ua.match(/Chrome\\/([\\d.]+)/) || ua.match(/CriOS\\/([\\d.]+)/);\n    var firefox = ua.match(/Firefox\\/([\\d.]+)/);\n    // var safari = webkit && ua.match(/Mobile\\//) && !chrome;\n    // var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome;\n    var ie = ua.match(/MSIE\\s([\\d.]+)/)\n        // IE 11 Trident/7.0; rv:11.0\n        || ua.match(/Trident\\/.+?rv:(([\\d.]+))/);\n    var edge = ua.match(/Edge\\/([\\d.]+)/); // IE 12 and 12+\n\n    var weChat = (/micromessenger/i).test(ua);\n\n    // Todo: clean this up with a better OS/browser seperation:\n    // - discern (more) between multiple browsers on android\n    // - decide if kindle fire in silk mode is android or not\n    // - Firefox on Android doesn't specify the Android version\n    // - possibly devide in os, device and browser hashes\n\n    // if (browser.webkit = !!webkit) browser.version = webkit[1];\n\n    // if (android) os.android = true, os.version = android[2];\n    // if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.');\n    // if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.');\n    // if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null;\n    // if (webos) os.webos = true, os.version = webos[2];\n    // if (touchpad) os.touchpad = true;\n    // if (blackberry) os.blackberry = true, os.version = blackberry[2];\n    // if (bb10) os.bb10 = true, os.version = bb10[2];\n    // if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2];\n    // if (playbook) browser.playbook = true;\n    // if (kindle) os.kindle = true, os.version = kindle[1];\n    // if (silk) browser.silk = true, browser.version = silk[1];\n    // if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true;\n    // if (chrome) browser.chrome = true, browser.version = chrome[1];\n    if (firefox) {\n        browser.firefox = true;\n        browser.version = firefox[1];\n    }\n    // if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true;\n    // if (webview) browser.webview = true;\n\n    if (ie) {\n        browser.ie = true;\n        browser.version = ie[1];\n    }\n\n    if (edge) {\n        browser.edge = true;\n        browser.version = edge[1];\n    }\n\n    // It is difficult to detect WeChat in Win Phone precisely, because ua can\n    // not be set on win phone. So we do not consider Win Phone.\n    if (weChat) {\n        browser.weChat = true;\n    }\n\n    // os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) ||\n    //     (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/)));\n    // os.phone  = !!(!os.tablet && !os.ipod && (android || iphone || webos ||\n    //     (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\\/([\\d.]+)/)) ||\n    //     (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/))));\n\n    return {\n        browser: browser,\n        os: os,\n        node: false,\n        // 原生canvas支持，改极端点了\n        // canvasSupported : !(browser.ie && parseFloat(browser.version) < 9)\n        canvasSupported: !!document.createElement('canvas').getContext,\n        svgSupported: typeof SVGRect !== 'undefined',\n        // works on most browsers\n        // IE10/11 does not support touch event, and MS Edge supports them but not by\n        // default, so we dont check navigator.maxTouchPoints for them here.\n        touchEventsSupported: 'ontouchstart' in window && !browser.ie && !browser.edge,\n        // <http://caniuse.com/#search=pointer%20event>.\n        pointerEventsSupported: 'onpointerdown' in window\n            // Firefox supports pointer but not by default, only MS browsers are reliable on pointer\n            // events currently. So we dont use that on other browsers unless tested sufficiently.\n            // Although IE 10 supports pointer event, it use old style and is different from the\n            // standard. So we exclude that. (IE 10 is hardly used on touch device)\n            && (browser.edge || (browser.ie && browser.version >= 11)),\n        // passiveSupported: detectPassiveSupport()\n        domSupported: typeof document !== 'undefined'\n    };\n}\n\n// See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection\n// function detectPassiveSupport() {\n//     // Test via a getter in the options object to see if the passive property is accessed\n//     var supportsPassive = false;\n//     try {\n//         var opts = Object.defineProperty({}, 'passive', {\n//             get: function() {\n//                 supportsPassive = true;\n//             }\n//         });\n//         window.addEventListener('testPassive', function() {}, opts);\n//     } catch (e) {\n//     }\n//     return supportsPassive;\n// }\n\n/**\n * @module zrender/core/util\n */\n\n// 用于处理merge时无法遍历Date等对象的问题\nvar BUILTIN_OBJECT = {\n    '[object Function]': 1,\n    '[object RegExp]': 1,\n    '[object Date]': 1,\n    '[object Error]': 1,\n    '[object CanvasGradient]': 1,\n    '[object CanvasPattern]': 1,\n    // For node-canvas\n    '[object Image]': 1,\n    '[object Canvas]': 1\n};\n\nvar TYPED_ARRAY = {\n    '[object Int8Array]': 1,\n    '[object Uint8Array]': 1,\n    '[object Uint8ClampedArray]': 1,\n    '[object Int16Array]': 1,\n    '[object Uint16Array]': 1,\n    '[object Int32Array]': 1,\n    '[object Uint32Array]': 1,\n    '[object Float32Array]': 1,\n    '[object Float64Array]': 1\n};\n\nvar objToString = Object.prototype.toString;\n\nvar arrayProto = Array.prototype;\nvar nativeForEach = arrayProto.forEach;\nvar nativeFilter = arrayProto.filter;\nvar nativeSlice = arrayProto.slice;\nvar nativeMap = arrayProto.map;\nvar nativeReduce = arrayProto.reduce;\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar methods = {};\n\nfunction $override(name, fn) {\n    // Clear ctx instance for different environment\n    if (name === 'createCanvas') {\n        _ctx = null;\n    }\n\n    methods[name] = fn;\n}\n\n/**\n * Those data types can be cloned:\n *     Plain object, Array, TypedArray, number, string, null, undefined.\n * Those data types will be assgined using the orginal data:\n *     BUILTIN_OBJECT\n * Instance of user defined class will be cloned to a plain object, without\n * properties in prototype.\n * Other data types is not supported (not sure what will happen).\n *\n * Caution: do not support clone Date, for performance consideration.\n * (There might be a large number of date in `series.data`).\n * So date should not be modified in and out of echarts.\n *\n * @param {*} source\n * @return {*} new\n */\nfunction clone(source) {\n    if (source == null || typeof source !== 'object') {\n        return source;\n    }\n\n    var result = source;\n    var typeStr = objToString.call(source);\n\n    if (typeStr === '[object Array]') {\n        if (!isPrimitive(source)) {\n            result = [];\n            for (var i = 0, len = source.length; i < len; i++) {\n                result[i] = clone(source[i]);\n            }\n        }\n    }\n    else if (TYPED_ARRAY[typeStr]) {\n        if (!isPrimitive(source)) {\n            var Ctor = source.constructor;\n            if (source.constructor.from) {\n                result = Ctor.from(source);\n            }\n            else {\n                result = new Ctor(source.length);\n                for (var i = 0, len = source.length; i < len; i++) {\n                    result[i] = clone(source[i]);\n                }\n            }\n        }\n    }\n    else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) {\n        result = {};\n        for (var key in source) {\n            if (source.hasOwnProperty(key)) {\n                result[key] = clone(source[key]);\n            }\n        }\n    }\n\n    return result;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overwrite=false]\n */\nfunction merge(target, source, overwrite) {\n    // We should escapse that source is string\n    // and enter for ... in ...\n    if (!isObject$1(source) || !isObject$1(target)) {\n        return overwrite ? clone(source) : target;\n    }\n\n    for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n            var targetProp = target[key];\n            var sourceProp = source[key];\n\n            if (isObject$1(sourceProp)\n                && isObject$1(targetProp)\n                && !isArray(sourceProp)\n                && !isArray(targetProp)\n                && !isDom(sourceProp)\n                && !isDom(targetProp)\n                && !isBuiltInObject(sourceProp)\n                && !isBuiltInObject(targetProp)\n                && !isPrimitive(sourceProp)\n                && !isPrimitive(targetProp)\n            ) {\n                // 如果需要递归覆盖，就递归调用merge\n                merge(targetProp, sourceProp, overwrite);\n            }\n            else if (overwrite || !(key in target)) {\n                // 否则只处理overwrite为true，或者在目标对象中没有此属性的情况\n                // NOTE，在 target[key] 不存在的时候也是直接覆盖\n                target[key] = clone(source[key], true);\n            }\n        }\n    }\n\n    return target;\n}\n\n/**\n * @param {Array} targetAndSources The first item is target, and the rests are source.\n * @param {boolean} [overwrite=false]\n * @return {*} target\n */\nfunction mergeAll(targetAndSources, overwrite) {\n    var result = targetAndSources[0];\n    for (var i = 1, len = targetAndSources.length; i < len; i++) {\n        result = merge(result, targetAndSources[i], overwrite);\n    }\n    return result;\n}\n\n/**\n * @param {*} target\n * @param {*} source\n * @memberOf module:zrender/core/util\n */\nfunction extend(target, source) {\n    for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n            target[key] = source[key];\n        }\n    }\n    return target;\n}\n\n/**\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overlay=false]\n * @memberOf module:zrender/core/util\n */\nfunction defaults(target, source, overlay) {\n    for (var key in source) {\n        if (source.hasOwnProperty(key)\n            && (overlay ? source[key] != null : target[key] == null)\n        ) {\n            target[key] = source[key];\n        }\n    }\n    return target;\n}\n\nvar createCanvas = function () {\n    return methods.createCanvas();\n};\n\nmethods.createCanvas = function () {\n    return document.createElement('canvas');\n};\n\n// FIXME\nvar _ctx;\n\nfunction getContext() {\n    if (!_ctx) {\n        // Use util.createCanvas instead of createCanvas\n        // because createCanvas may be overwritten in different environment\n        _ctx = createCanvas().getContext('2d');\n    }\n    return _ctx;\n}\n\n/**\n * 查询数组中元素的index\n * @memberOf module:zrender/core/util\n */\nfunction indexOf(array, value) {\n    if (array) {\n        if (array.indexOf) {\n            return array.indexOf(value);\n        }\n        for (var i = 0, len = array.length; i < len; i++) {\n            if (array[i] === value) {\n                return i;\n            }\n        }\n    }\n    return -1;\n}\n\n/**\n * 构造类继承关系\n *\n * @memberOf module:zrender/core/util\n * @param {Function} clazz 源类\n * @param {Function} baseClazz 基类\n */\nfunction inherits(clazz, baseClazz) {\n    var clazzPrototype = clazz.prototype;\n    function F() {}\n    F.prototype = baseClazz.prototype;\n    clazz.prototype = new F();\n\n    for (var prop in clazzPrototype) {\n        clazz.prototype[prop] = clazzPrototype[prop];\n    }\n    clazz.prototype.constructor = clazz;\n    clazz.superClass = baseClazz;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Object|Function} target\n * @param {Object|Function} sorce\n * @param {boolean} overlay\n */\nfunction mixin(target, source, overlay) {\n    target = 'prototype' in target ? target.prototype : target;\n    source = 'prototype' in source ? source.prototype : source;\n\n    defaults(target, source, overlay);\n}\n\n/**\n * Consider typed array.\n * @param {Array|TypedArray} data\n */\nfunction isArrayLike(data) {\n    if (!data) {\n        return;\n    }\n    if (typeof data === 'string') {\n        return false;\n    }\n    return typeof data.length === 'number';\n}\n\n/**\n * 数组或对象遍历\n * @memberOf module:zrender/core/util\n * @param {Object|Array} obj\n * @param {Function} cb\n * @param {*} [context]\n */\nfunction each$1(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.forEach && obj.forEach === nativeForEach) {\n        obj.forEach(cb, context);\n    }\n    else if (obj.length === +obj.length) {\n        for (var i = 0, len = obj.length; i < len; i++) {\n            cb.call(context, obj[i], i, obj);\n        }\n    }\n    else {\n        for (var key in obj) {\n            if (obj.hasOwnProperty(key)) {\n                cb.call(context, obj[key], key, obj);\n            }\n        }\n    }\n}\n\n/**\n * 数组映射\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction map(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.map && obj.map === nativeMap) {\n        return obj.map(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            result.push(cb.call(context, obj[i], i, obj));\n        }\n        return result;\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {Object} [memo]\n * @param {*} [context]\n * @return {Array}\n */\nfunction reduce(obj, cb, memo, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.reduce && obj.reduce === nativeReduce) {\n        return obj.reduce(cb, memo, context);\n    }\n    else {\n        for (var i = 0, len = obj.length; i < len; i++) {\n            memo = cb.call(context, memo, obj[i], i, obj);\n        }\n        return memo;\n    }\n}\n\n/**\n * 数组过滤\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction filter(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.filter && obj.filter === nativeFilter) {\n        return obj.filter(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            if (cb.call(context, obj[i], i, obj)) {\n                result.push(obj[i]);\n            }\n        }\n        return result;\n    }\n}\n\n/**\n * 数组项查找\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {*}\n */\nfunction find(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    for (var i = 0, len = obj.length; i < len; i++) {\n        if (cb.call(context, obj[i], i, obj)) {\n            return obj[i];\n        }\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @param {*} context\n * @return {Function}\n */\nfunction bind(func, context) {\n    var args = nativeSlice.call(arguments, 2);\n    return function () {\n        return func.apply(context, args.concat(nativeSlice.call(arguments)));\n    };\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @return {Function}\n */\nfunction curry(func) {\n    var args = nativeSlice.call(arguments, 1);\n    return function () {\n        return func.apply(this, args.concat(nativeSlice.call(arguments)));\n    };\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isArray(value) {\n    return objToString.call(value) === '[object Array]';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isFunction$1(value) {\n    return typeof value === 'function';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isString(value) {\n    return objToString.call(value) === '[object String]';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isObject$1(value) {\n    // Avoid a V8 JIT bug in Chrome 19-20.\n    // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.\n    var type = typeof value;\n    return type === 'function' || (!!value && type === 'object');\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isBuiltInObject(value) {\n    return !!BUILTIN_OBJECT[objToString.call(value)];\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isTypedArray(value) {\n    return !!TYPED_ARRAY[objToString.call(value)];\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isDom(value) {\n    return typeof value === 'object'\n        && typeof value.nodeType === 'number'\n        && typeof value.ownerDocument === 'object';\n}\n\n/**\n * Whether is exactly NaN. Notice isNaN('a') returns true.\n * @param {*} value\n * @return {boolean}\n */\nfunction eqNaN(value) {\n    return value !== value;\n}\n\n/**\n * If value1 is not null, then return value1, otherwise judget rest of values.\n * Low performance.\n * @memberOf module:zrender/core/util\n * @return {*} Final value\n */\nfunction retrieve(values) {\n    for (var i = 0, len = arguments.length; i < len; i++) {\n        if (arguments[i] != null) {\n            return arguments[i];\n        }\n    }\n}\n\nfunction retrieve2(value0, value1) {\n    return value0 != null\n        ? value0\n        : value1;\n}\n\nfunction retrieve3(value0, value1, value2) {\n    return value0 != null\n        ? value0\n        : value1 != null\n        ? value1\n        : value2;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} arr\n * @param {number} startIndex\n * @param {number} endIndex\n * @return {Array}\n */\nfunction slice() {\n    return Function.call.apply(nativeSlice, arguments);\n}\n\n/**\n * Normalize css liked array configuration\n * e.g.\n *  3 => [3, 3, 3, 3]\n *  [4, 2] => [4, 2, 4, 2]\n *  [4, 3, 2] => [4, 3, 2, 3]\n * @param {number|Array.<number>} val\n * @return {Array.<number>}\n */\nfunction normalizeCssArray(val) {\n    if (typeof (val) === 'number') {\n        return [val, val, val, val];\n    }\n    var len = val.length;\n    if (len === 2) {\n        // vertical | horizontal\n        return [val[0], val[1], val[0], val[1]];\n    }\n    else if (len === 3) {\n        // top | horizontal | bottom\n        return [val[0], val[1], val[2], val[1]];\n    }\n    return val;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {boolean} condition\n * @param {string} message\n */\nfunction assert$1(condition, message) {\n    if (!condition) {\n        throw new Error(message);\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {string} str string to be trimed\n * @return {string} trimed string\n */\nfunction trim(str) {\n    if (str == null) {\n        return null;\n    }\n    else if (typeof str.trim === 'function') {\n        return str.trim();\n    }\n    else {\n        return str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n    }\n}\n\nvar primitiveKey = '__ec_primitive__';\n/**\n * Set an object as primitive to be ignored traversing children in clone or merge\n */\nfunction setAsPrimitive(obj) {\n    obj[primitiveKey] = true;\n}\n\nfunction isPrimitive(obj) {\n    return obj[primitiveKey];\n}\n\n/**\n * @constructor\n * @param {Object} obj Only apply `ownProperty`.\n */\nfunction HashMap(obj) {\n    var isArr = isArray(obj);\n    // Key should not be set on this, otherwise\n    // methods get/set/... may be overrided.\n    this.data = {};\n    var thisMap = this;\n\n    (obj instanceof HashMap)\n        ? obj.each(visit)\n        : (obj && each$1(obj, visit));\n\n    function visit(value, key) {\n        isArr ? thisMap.set(value, key) : thisMap.set(key, value);\n    }\n}\n\nHashMap.prototype = {\n    constructor: HashMap,\n    // Do not provide `has` method to avoid defining what is `has`.\n    // (We usually treat `null` and `undefined` as the same, different\n    // from ES6 Map).\n    get: function (key) {\n        return this.data.hasOwnProperty(key) ? this.data[key] : null;\n    },\n    set: function (key, value) {\n        // Comparing with invocation chaining, `return value` is more commonly\n        // used in this case: `var someVal = map.set('a', genVal());`\n        return (this.data[key] = value);\n    },\n    // Although util.each can be performed on this hashMap directly, user\n    // should not use the exposed keys, who are prefixed.\n    each: function (cb, context) {\n        context !== void 0 && (cb = bind(cb, context));\n        for (var key in this.data) {\n            this.data.hasOwnProperty(key) && cb(this.data[key], key);\n        }\n    },\n    // Do not use this method if performance sensitive.\n    removeKey: function (key) {\n        delete this.data[key];\n    }\n};\n\nfunction createHashMap(obj) {\n    return new HashMap(obj);\n}\n\nfunction concatArray(a, b) {\n    var newArray = new a.constructor(a.length + b.length);\n    for (var i = 0; i < a.length; i++) {\n        newArray[i] = a[i];\n    }\n    var offset = a.length;\n    for (i = 0; i < b.length; i++) {\n        newArray[i + offset] = b[i];\n    }\n    return newArray;\n}\n\n\nfunction noop() {}\n\n\nvar zrUtil = (Object.freeze || Object)({\n\t$override: $override,\n\tclone: clone,\n\tmerge: merge,\n\tmergeAll: mergeAll,\n\textend: extend,\n\tdefaults: defaults,\n\tcreateCanvas: createCanvas,\n\tgetContext: getContext,\n\tindexOf: indexOf,\n\tinherits: inherits,\n\tmixin: mixin,\n\tisArrayLike: isArrayLike,\n\teach: each$1,\n\tmap: map,\n\treduce: reduce,\n\tfilter: filter,\n\tfind: find,\n\tbind: bind,\n\tcurry: curry,\n\tisArray: isArray,\n\tisFunction: isFunction$1,\n\tisString: isString,\n\tisObject: isObject$1,\n\tisBuiltInObject: isBuiltInObject,\n\tisTypedArray: isTypedArray,\n\tisDom: isDom,\n\teqNaN: eqNaN,\n\tretrieve: retrieve,\n\tretrieve2: retrieve2,\n\tretrieve3: retrieve3,\n\tslice: slice,\n\tnormalizeCssArray: normalizeCssArray,\n\tassert: assert$1,\n\ttrim: trim,\n\tsetAsPrimitive: setAsPrimitive,\n\tisPrimitive: isPrimitive,\n\tcreateHashMap: createHashMap,\n\tconcatArray: concatArray,\n\tnoop: noop\n});\n\nvar ArrayCtor = typeof Float32Array === 'undefined'\n    ? Array\n    : Float32Array;\n\n/**\n * 创建一个向量\n * @param {number} [x=0]\n * @param {number} [y=0]\n * @return {Vector2}\n */\nfunction create(x, y) {\n    var out = new ArrayCtor(2);\n    if (x == null) {\n        x = 0;\n    }\n    if (y == null) {\n        y = 0;\n    }\n    out[0] = x;\n    out[1] = y;\n    return out;\n}\n\n/**\n * 复制向量数据\n * @param {Vector2} out\n * @param {Vector2} v\n * @return {Vector2}\n */\nfunction copy(out, v) {\n    out[0] = v[0];\n    out[1] = v[1];\n    return out;\n}\n\n/**\n * 克隆一个向量\n * @param {Vector2} v\n * @return {Vector2}\n */\nfunction clone$1(v) {\n    var out = new ArrayCtor(2);\n    out[0] = v[0];\n    out[1] = v[1];\n    return out;\n}\n\n/**\n * 设置向量的两个项\n * @param {Vector2} out\n * @param {number} a\n * @param {number} b\n * @return {Vector2} 结果\n */\nfunction set(out, a, b) {\n    out[0] = a;\n    out[1] = b;\n    return out;\n}\n\n/**\n * 向量相加\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction add(out, v1, v2) {\n    out[0] = v1[0] + v2[0];\n    out[1] = v1[1] + v2[1];\n    return out;\n}\n\n/**\n * 向量缩放后相加\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @param {number} a\n */\nfunction scaleAndAdd(out, v1, v2, a) {\n    out[0] = v1[0] + v2[0] * a;\n    out[1] = v1[1] + v2[1] * a;\n    return out;\n}\n\n/**\n * 向量相减\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction sub(out, v1, v2) {\n    out[0] = v1[0] - v2[0];\n    out[1] = v1[1] - v2[1];\n    return out;\n}\n\n/**\n * 向量长度\n * @param {Vector2} v\n * @return {number}\n */\nfunction len(v) {\n    return Math.sqrt(lenSquare(v));\n}\nvar length = len; // jshint ignore:line\n\n/**\n * 向量长度平方\n * @param {Vector2} v\n * @return {number}\n */\nfunction lenSquare(v) {\n    return v[0] * v[0] + v[1] * v[1];\n}\nvar lengthSquare = lenSquare;\n\n/**\n * 向量乘法\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction mul(out, v1, v2) {\n    out[0] = v1[0] * v2[0];\n    out[1] = v1[1] * v2[1];\n    return out;\n}\n\n/**\n * 向量除法\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction div(out, v1, v2) {\n    out[0] = v1[0] / v2[0];\n    out[1] = v1[1] / v2[1];\n    return out;\n}\n\n/**\n * 向量点乘\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction dot(v1, v2) {\n    return v1[0] * v2[0] + v1[1] * v2[1];\n}\n\n/**\n * 向量缩放\n * @param {Vector2} out\n * @param {Vector2} v\n * @param {number} s\n */\nfunction scale(out, v, s) {\n    out[0] = v[0] * s;\n    out[1] = v[1] * s;\n    return out;\n}\n\n/**\n * 向量归一化\n * @param {Vector2} out\n * @param {Vector2} v\n */\nfunction normalize(out, v) {\n    var d = len(v);\n    if (d === 0) {\n        out[0] = 0;\n        out[1] = 0;\n    }\n    else {\n        out[0] = v[0] / d;\n        out[1] = v[1] / d;\n    }\n    return out;\n}\n\n/**\n * 计算向量间距离\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction distance(v1, v2) {\n    return Math.sqrt(\n        (v1[0] - v2[0]) * (v1[0] - v2[0])\n        + (v1[1] - v2[1]) * (v1[1] - v2[1])\n    );\n}\nvar dist = distance;\n\n/**\n * 向量距离平方\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction distanceSquare(v1, v2) {\n    return (v1[0] - v2[0]) * (v1[0] - v2[0])\n        + (v1[1] - v2[1]) * (v1[1] - v2[1]);\n}\nvar distSquare = distanceSquare;\n\n/**\n * 求负向量\n * @param {Vector2} out\n * @param {Vector2} v\n */\nfunction negate(out, v) {\n    out[0] = -v[0];\n    out[1] = -v[1];\n    return out;\n}\n\n/**\n * 插值两个点\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @param {number} t\n */\nfunction lerp(out, v1, v2, t) {\n    out[0] = v1[0] + t * (v2[0] - v1[0]);\n    out[1] = v1[1] + t * (v2[1] - v1[1]);\n    return out;\n}\n\n/**\n * 矩阵左乘向量\n * @param {Vector2} out\n * @param {Vector2} v\n * @param {Vector2} m\n */\nfunction applyTransform(out, v, m) {\n    var x = v[0];\n    var y = v[1];\n    out[0] = m[0] * x + m[2] * y + m[4];\n    out[1] = m[1] * x + m[3] * y + m[5];\n    return out;\n}\n\n/**\n * 求两个向量最小值\n * @param  {Vector2} out\n * @param  {Vector2} v1\n * @param  {Vector2} v2\n */\nfunction min(out, v1, v2) {\n    out[0] = Math.min(v1[0], v2[0]);\n    out[1] = Math.min(v1[1], v2[1]);\n    return out;\n}\n\n/**\n * 求两个向量最大值\n * @param  {Vector2} out\n * @param  {Vector2} v1\n * @param  {Vector2} v2\n */\nfunction max(out, v1, v2) {\n    out[0] = Math.max(v1[0], v2[0]);\n    out[1] = Math.max(v1[1], v2[1]);\n    return out;\n}\n\n\nvar vector = (Object.freeze || Object)({\n\tcreate: create,\n\tcopy: copy,\n\tclone: clone$1,\n\tset: set,\n\tadd: add,\n\tscaleAndAdd: scaleAndAdd,\n\tsub: sub,\n\tlen: len,\n\tlength: length,\n\tlenSquare: lenSquare,\n\tlengthSquare: lengthSquare,\n\tmul: mul,\n\tdiv: div,\n\tdot: dot,\n\tscale: scale,\n\tnormalize: normalize,\n\tdistance: distance,\n\tdist: dist,\n\tdistanceSquare: distanceSquare,\n\tdistSquare: distSquare,\n\tnegate: negate,\n\tlerp: lerp,\n\tapplyTransform: applyTransform,\n\tmin: min,\n\tmax: max\n});\n\n// TODO Draggable for group\n// FIXME Draggable on element which has parent rotation or scale\nfunction Draggable() {\n\n    this.on('mousedown', this._dragStart, this);\n    this.on('mousemove', this._drag, this);\n    this.on('mouseup', this._dragEnd, this);\n    this.on('globalout', this._dragEnd, this);\n    // this._dropTarget = null;\n    // this._draggingTarget = null;\n\n    // this._x = 0;\n    // this._y = 0;\n}\n\nDraggable.prototype = {\n\n    constructor: Draggable,\n\n    _dragStart: function (e) {\n        var draggingTarget = e.target;\n        if (draggingTarget && draggingTarget.draggable) {\n            this._draggingTarget = draggingTarget;\n            draggingTarget.dragging = true;\n            this._x = e.offsetX;\n            this._y = e.offsetY;\n\n            this.dispatchToElement(param(draggingTarget, e), 'dragstart', e.event);\n        }\n    },\n\n    _drag: function (e) {\n        var draggingTarget = this._draggingTarget;\n        if (draggingTarget) {\n\n            var x = e.offsetX;\n            var y = e.offsetY;\n\n            var dx = x - this._x;\n            var dy = y - this._y;\n            this._x = x;\n            this._y = y;\n\n            draggingTarget.drift(dx, dy, e);\n            this.dispatchToElement(param(draggingTarget, e), 'drag', e.event);\n\n            var dropTarget = this.findHover(x, y, draggingTarget).target;\n            var lastDropTarget = this._dropTarget;\n            this._dropTarget = dropTarget;\n\n            if (draggingTarget !== dropTarget) {\n                if (lastDropTarget && dropTarget !== lastDropTarget) {\n                    this.dispatchToElement(param(lastDropTarget, e), 'dragleave', e.event);\n                }\n                if (dropTarget && dropTarget !== lastDropTarget) {\n                    this.dispatchToElement(param(dropTarget, e), 'dragenter', e.event);\n                }\n            }\n        }\n    },\n\n    _dragEnd: function (e) {\n        var draggingTarget = this._draggingTarget;\n\n        if (draggingTarget) {\n            draggingTarget.dragging = false;\n        }\n\n        this.dispatchToElement(param(draggingTarget, e), 'dragend', e.event);\n\n        if (this._dropTarget) {\n            this.dispatchToElement(param(this._dropTarget, e), 'drop', e.event);\n        }\n\n        this._draggingTarget = null;\n        this._dropTarget = null;\n    }\n\n};\n\nfunction param(target, e) {\n    return {target: target, topTarget: e && e.topTarget};\n}\n\n/**\n * Event Mixin\n * @module zrender/mixin/Eventful\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         pissang (https://www.github.com/pissang)\n */\n\nvar arrySlice = Array.prototype.slice;\n\n/**\n * Event dispatcher.\n *\n * @alias module:zrender/mixin/Eventful\n * @constructor\n * @param {Object} [eventProcessor] The object eventProcessor is the scope when\n *        `eventProcessor.xxx` called.\n * @param {Function} [eventProcessor.normalizeQuery]\n *        param: {string|Object} Raw query.\n *        return: {string|Object} Normalized query.\n * @param {Function} [eventProcessor.filter] Event will be dispatched only\n *        if it returns `true`.\n *        param: {string} eventType\n *        param: {string|Object} query\n *        return: {boolean}\n * @param {Function} [eventProcessor.afterTrigger] Call after all handlers called.\n *        param: {string} eventType\n */\nvar Eventful = function (eventProcessor) {\n    this._$handlers = {};\n    this._$eventProcessor = eventProcessor;\n};\n\nEventful.prototype = {\n\n    constructor: Eventful,\n\n    /**\n     * The handler can only be triggered once, then removed.\n     *\n     * @param {string} event The event name.\n     * @param {string|Object} [query] Condition used on event filter.\n     * @param {Function} handler The event handler.\n     * @param {Object} context\n     */\n    one: function (event, query, handler, context) {\n        return on(this, event, query, handler, context, true);\n    },\n\n    /**\n     * Bind a handler.\n     *\n     * @param {string} event The event name.\n     * @param {string|Object} [query] Condition used on event filter.\n     * @param {Function} handler The event handler.\n     * @param {Object} [context]\n     */\n    on: function (event, query, handler, context) {\n        return on(this, event, query, handler, context, false);\n    },\n\n    /**\n     * Whether any handler has bound.\n     *\n     * @param  {string}  event\n     * @return {boolean}\n     */\n    isSilent: function (event) {\n        var _h = this._$handlers;\n        return !_h[event] || !_h[event].length;\n    },\n\n    /**\n     * Unbind a event.\n     *\n     * @param {string} event The event name.\n     * @param {Function} [handler] The event handler.\n     */\n    off: function (event, handler) {\n        var _h = this._$handlers;\n\n        if (!event) {\n            this._$handlers = {};\n            return this;\n        }\n\n        if (handler) {\n            if (_h[event]) {\n                var newList = [];\n                for (var i = 0, l = _h[event].length; i < l; i++) {\n                    if (_h[event][i].h !== handler) {\n                        newList.push(_h[event][i]);\n                    }\n                }\n                _h[event] = newList;\n            }\n\n            if (_h[event] && _h[event].length === 0) {\n                delete _h[event];\n            }\n        }\n        else {\n            delete _h[event];\n        }\n\n        return this;\n    },\n\n    /**\n     * Dispatch a event.\n     *\n     * @param {string} type The event name.\n     */\n    trigger: function (type) {\n        var _h = this._$handlers[type];\n        var eventProcessor = this._$eventProcessor;\n\n        if (_h) {\n            var args = arguments;\n            var argLen = args.length;\n\n            if (argLen > 3) {\n                args = arrySlice.call(args, 1);\n            }\n\n            var len = _h.length;\n            for (var i = 0; i < len;) {\n                var hItem = _h[i];\n                if (eventProcessor\n                    && eventProcessor.filter\n                    && hItem.query != null\n                    && !eventProcessor.filter(type, hItem.query)\n                ) {\n                    i++;\n                    continue;\n                }\n\n                // Optimize advise from backbone\n                switch (argLen) {\n                    case 1:\n                        hItem.h.call(hItem.ctx);\n                        break;\n                    case 2:\n                        hItem.h.call(hItem.ctx, args[1]);\n                        break;\n                    case 3:\n                        hItem.h.call(hItem.ctx, args[1], args[2]);\n                        break;\n                    default:\n                        // have more than 2 given arguments\n                        hItem.h.apply(hItem.ctx, args);\n                        break;\n                }\n\n                if (hItem.one) {\n                    _h.splice(i, 1);\n                    len--;\n                }\n                else {\n                    i++;\n                }\n            }\n        }\n\n        eventProcessor && eventProcessor.afterTrigger\n            && eventProcessor.afterTrigger(type);\n\n        return this;\n    },\n\n    /**\n     * Dispatch a event with context, which is specified at the last parameter.\n     *\n     * @param {string} type The event name.\n     */\n    triggerWithContext: function (type) {\n        var _h = this._$handlers[type];\n        var eventProcessor = this._$eventProcessor;\n\n        if (_h) {\n            var args = arguments;\n            var argLen = args.length;\n\n            if (argLen > 4) {\n                args = arrySlice.call(args, 1, args.length - 1);\n            }\n            var ctx = args[args.length - 1];\n\n            var len = _h.length;\n            for (var i = 0; i < len;) {\n                var hItem = _h[i];\n                if (eventProcessor\n                    && eventProcessor.filter\n                    && hItem.query != null\n                    && !eventProcessor.filter(type, hItem.query)\n                ) {\n                    i++;\n                    continue;\n                }\n\n                // Optimize advise from backbone\n                switch (argLen) {\n                    case 1:\n                        hItem.h.call(ctx);\n                        break;\n                    case 2:\n                        hItem.h.call(ctx, args[1]);\n                        break;\n                    case 3:\n                        hItem.h.call(ctx, args[1], args[2]);\n                        break;\n                    default:\n                        // have more than 2 given arguments\n                        hItem.h.apply(ctx, args);\n                        break;\n                }\n\n                if (hItem.one) {\n                    _h.splice(i, 1);\n                    len--;\n                }\n                else {\n                    i++;\n                }\n            }\n        }\n\n        eventProcessor && eventProcessor.afterTrigger\n            && eventProcessor.afterTrigger(type);\n\n        return this;\n    }\n};\n\nfunction normalizeQuery(host, query) {\n    var eventProcessor = host._$eventProcessor;\n    if (query != null && eventProcessor && eventProcessor.normalizeQuery) {\n        query = eventProcessor.normalizeQuery(query);\n    }\n    return query;\n}\n\nfunction on(eventful, event, query, handler, context, isOnce) {\n    var _h = eventful._$handlers;\n\n    if (typeof query === 'function') {\n        context = handler;\n        handler = query;\n        query = null;\n    }\n\n    if (!handler || !event) {\n        return eventful;\n    }\n\n    query = normalizeQuery(eventful, query);\n\n    if (!_h[event]) {\n        _h[event] = [];\n    }\n\n    for (var i = 0; i < _h[event].length; i++) {\n        if (_h[event][i].h === handler) {\n            return eventful;\n        }\n    }\n\n    var wrap = {\n        h: handler,\n        one: isOnce,\n        query: query,\n        ctx: context || eventful,\n        // FIXME\n        // Do not publish this feature util it is proved that it makes sense.\n        callAtLast: handler.zrEventfulCallAtLast\n    };\n\n    var lastIndex = _h[event].length - 1;\n    var lastWrap = _h[event][lastIndex];\n    (lastWrap && lastWrap.callAtLast)\n        ? _h[event].splice(lastIndex, 0, wrap)\n        : _h[event].push(wrap);\n\n    return eventful;\n}\n\n/**\n * 事件辅助类\n * @module zrender/core/event\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n */\n\nvar isDomLevel2 = (typeof window !== 'undefined') && !!window.addEventListener;\n\nvar MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;\n\nfunction getBoundingClientRect(el) {\n    // BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect\n    return el.getBoundingClientRect ? el.getBoundingClientRect() : {left: 0, top: 0};\n}\n\n// `calculate` is optional, default false\nfunction clientToLocal(el, e, out, calculate) {\n    out = out || {};\n\n    // According to the W3C Working Draft, offsetX and offsetY should be relative\n    // to the padding edge of the target element. The only browser using this convention\n    // is IE. Webkit uses the border edge, Opera uses the content edge, and FireFox does\n    // not support the properties.\n    // (see http://www.jacklmoore.com/notes/mouse-position/)\n    // In zr painter.dom, padding edge equals to border edge.\n\n    // FIXME\n    // When mousemove event triggered on ec tooltip, target is not zr painter.dom, and\n    // offsetX/Y is relative to e.target, where the calculation of zrX/Y via offsetX/Y\n    // is too complex. So css-transfrom dont support in this case temporarily.\n    if (calculate || !env$1.canvasSupported) {\n        defaultGetZrXY(el, e, out);\n    }\n    // Caution: In FireFox, layerX/layerY Mouse position relative to the closest positioned\n    // ancestor element, so we should make sure el is positioned (e.g., not position:static).\n    // BTW1, Webkit don't return the same results as FF in non-simple cases (like add\n    // zoom-factor, overflow / opacity layers, transforms ...)\n    // BTW2, (ev.offsetY || ev.pageY - $(ev.target).offset().top) is not correct in preserve-3d.\n    // <https://bugs.jquery.com/ticket/8523#comment:14>\n    // BTW3, In ff, offsetX/offsetY is always 0.\n    else if (env$1.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) {\n        out.zrX = e.layerX;\n        out.zrY = e.layerY;\n    }\n    // For IE6+, chrome, safari, opera. (When will ff support offsetX?)\n    else if (e.offsetX != null) {\n        out.zrX = e.offsetX;\n        out.zrY = e.offsetY;\n    }\n    // For some other device, e.g., IOS safari.\n    else {\n        defaultGetZrXY(el, e, out);\n    }\n\n    return out;\n}\n\nfunction defaultGetZrXY(el, e, out) {\n    // This well-known method below does not support css transform.\n    var box = getBoundingClientRect(el);\n    out.zrX = e.clientX - box.left;\n    out.zrY = e.clientY - box.top;\n}\n\n/**\n * 如果存在第三方嵌入的一些dom触发的事件，或touch事件，需要转换一下事件坐标.\n * `calculate` is optional, default false.\n */\nfunction normalizeEvent(el, e, calculate) {\n\n    e = e || window.event;\n\n    if (e.zrX != null) {\n        return e;\n    }\n\n    var eventType = e.type;\n    var isTouch = eventType && eventType.indexOf('touch') >= 0;\n\n    if (!isTouch) {\n        clientToLocal(el, e, e, calculate);\n        e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3;\n    }\n    else {\n        var touch = eventType !== 'touchend'\n            ? e.targetTouches[0]\n            : e.changedTouches[0];\n        touch && clientToLocal(el, touch, e, calculate);\n    }\n\n    // Add which for click: 1 === left; 2 === middle; 3 === right; otherwise: 0;\n    // See jQuery: https://github.com/jquery/jquery/blob/master/src/event.js\n    // If e.which has been defined, if may be readonly,\n    // see: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which\n    var button = e.button;\n    if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) {\n        e.which = (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));\n    }\n    // [Caution]: `e.which` from browser is not always reliable. For example,\n    // when press left button and `mousemove (pointermove)` in Edge, the `e.which`\n    // is 65536 and the `e.button` is -1. But the `mouseup (pointerup)` and\n    // `mousedown (pointerdown)` is the same as Chrome does.\n\n    return e;\n}\n\n/**\n * @param {HTMLElement} el\n * @param {string} name\n * @param {Function} handler\n */\nfunction addEventListener(el, name, handler) {\n    if (isDomLevel2) {\n        // Reproduct the console warning:\n        // [Violation] Added non-passive event listener to a scroll-blocking <some> event.\n        // Consider marking event handler as 'passive' to make the page more responsive.\n        // Just set console log level: verbose in chrome dev tool.\n        // then the warning log will be printed when addEventListener called.\n        // See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md\n        // We have not yet found a neat way to using passive. Because in zrender the dom event\n        // listener delegate all of the upper events of element. Some of those events need\n        // to prevent default. For example, the feature `preventDefaultMouseMove` of echarts.\n        // Before passive can be adopted, these issues should be considered:\n        // (1) Whether and how a zrender user specifies an event listener passive. And by default,\n        // passive or not.\n        // (2) How to tread that some zrender event listener is passive, and some is not. If\n        // we use other way but not preventDefault of mousewheel and touchmove, browser\n        // compatibility should be handled.\n\n        // var opts = (env.passiveSupported && name === 'mousewheel')\n        //     ? {passive: true}\n        //     // By default, the third param of el.addEventListener is `capture: false`.\n        //     : void 0;\n        // el.addEventListener(name, handler /* , opts */);\n        el.addEventListener(name, handler);\n    }\n    else {\n        el.attachEvent('on' + name, handler);\n    }\n}\n\nfunction removeEventListener(el, name, handler) {\n    if (isDomLevel2) {\n        el.removeEventListener(name, handler);\n    }\n    else {\n        el.detachEvent('on' + name, handler);\n    }\n}\n\n/**\n * preventDefault and stopPropagation.\n * Notice: do not do that in zrender. Upper application\n * do that if necessary.\n *\n * @memberOf module:zrender/core/event\n * @method\n * @param {Event} e : event对象\n */\nvar stop = isDomLevel2\n    ? function (e) {\n        e.preventDefault();\n        e.stopPropagation();\n        e.cancelBubble = true;\n    }\n    : function (e) {\n        e.returnValue = false;\n        e.cancelBubble = true;\n    };\n\n/**\n * This method only works for mouseup and mousedown. The functionality is restricted\n * for fault tolerance, See the `e.which` compatibility above.\n *\n * @param {MouseEvent} e\n * @return {boolean}\n */\nfunction isMiddleOrRightButtonOnMouseUpDown(e) {\n    return e.which === 2 || e.which === 3;\n}\n\n/**\n * To be removed.\n * @deprecated\n */\n\n/**\n * Only implements needed gestures for mobile.\n */\n\nvar GestureMgr = function () {\n\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    this._track = [];\n};\n\nGestureMgr.prototype = {\n\n    constructor: GestureMgr,\n\n    recognize: function (event, target, root) {\n        this._doTrack(event, target, root);\n        return this._recognize(event);\n    },\n\n    clear: function () {\n        this._track.length = 0;\n        return this;\n    },\n\n    _doTrack: function (event, target, root) {\n        var touches = event.touches;\n\n        if (!touches) {\n            return;\n        }\n\n        var trackItem = {\n            points: [],\n            touches: [],\n            target: target,\n            event: event\n        };\n\n        for (var i = 0, len = touches.length; i < len; i++) {\n            var touch = touches[i];\n            var pos = clientToLocal(root, touch, {});\n            trackItem.points.push([pos.zrX, pos.zrY]);\n            trackItem.touches.push(touch);\n        }\n\n        this._track.push(trackItem);\n    },\n\n    _recognize: function (event) {\n        for (var eventName in recognizers) {\n            if (recognizers.hasOwnProperty(eventName)) {\n                var gestureInfo = recognizers[eventName](this._track, event);\n                if (gestureInfo) {\n                    return gestureInfo;\n                }\n            }\n        }\n    }\n};\n\nfunction dist$1(pointPair) {\n    var dx = pointPair[1][0] - pointPair[0][0];\n    var dy = pointPair[1][1] - pointPair[0][1];\n\n    return Math.sqrt(dx * dx + dy * dy);\n}\n\nfunction center(pointPair) {\n    return [\n        (pointPair[0][0] + pointPair[1][0]) / 2,\n        (pointPair[0][1] + pointPair[1][1]) / 2\n    ];\n}\n\nvar recognizers = {\n\n    pinch: function (track, event) {\n        var trackLen = track.length;\n\n        if (!trackLen) {\n            return;\n        }\n\n        var pinchEnd = (track[trackLen - 1] || {}).points;\n        var pinchPre = (track[trackLen - 2] || {}).points || pinchEnd;\n\n        if (pinchPre\n            && pinchPre.length > 1\n            && pinchEnd\n            && pinchEnd.length > 1\n        ) {\n            var pinchScale = dist$1(pinchEnd) / dist$1(pinchPre);\n            !isFinite(pinchScale) && (pinchScale = 1);\n\n            event.pinchScale = pinchScale;\n\n            var pinchCenter = center(pinchEnd);\n            event.pinchX = pinchCenter[0];\n            event.pinchY = pinchCenter[1];\n\n            return {\n                type: 'pinch',\n                target: track[0].target,\n                event: event\n            };\n        }\n    }\n\n    // Only pinch currently.\n};\n\nvar SILENT = 'silent';\n\nfunction makeEventPacket(eveType, targetInfo, event) {\n    return {\n        type: eveType,\n        event: event,\n        // target can only be an element that is not silent.\n        target: targetInfo.target,\n        // topTarget can be a silent element.\n        topTarget: targetInfo.topTarget,\n        cancelBubble: false,\n        offsetX: event.zrX,\n        offsetY: event.zrY,\n        gestureEvent: event.gestureEvent,\n        pinchX: event.pinchX,\n        pinchY: event.pinchY,\n        pinchScale: event.pinchScale,\n        wheelDelta: event.zrDelta,\n        zrByTouch: event.zrByTouch,\n        which: event.which,\n        stop: stopEvent\n    };\n}\n\nfunction stopEvent(event) {\n    stop(this.event);\n}\n\nfunction EmptyProxy() {}\nEmptyProxy.prototype.dispose = function () {};\n\nvar handlerNames = [\n    'click', 'dblclick', 'mousewheel', 'mouseout',\n    'mouseup', 'mousedown', 'mousemove', 'contextmenu'\n];\n/**\n * @alias module:zrender/Handler\n * @constructor\n * @extends module:zrender/mixin/Eventful\n * @param {module:zrender/Storage} storage Storage instance.\n * @param {module:zrender/Painter} painter Painter instance.\n * @param {module:zrender/dom/HandlerProxy} proxy HandlerProxy instance.\n * @param {HTMLElement} painterRoot painter.root (not painter.getViewportRoot()).\n */\nvar Handler = function (storage, painter, proxy, painterRoot) {\n    Eventful.call(this);\n\n    this.storage = storage;\n\n    this.painter = painter;\n\n    this.painterRoot = painterRoot;\n\n    proxy = proxy || new EmptyProxy();\n\n    /**\n     * Proxy of event. can be Dom, WebGLSurface, etc.\n     */\n    this.proxy = null;\n\n    /**\n     * {target, topTarget, x, y}\n     * @private\n     * @type {Object}\n     */\n    this._hovered = {};\n\n    /**\n     * @private\n     * @type {Date}\n     */\n    this._lastTouchMoment;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._lastX;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._lastY;\n\n    /**\n     * @private\n     * @type {module:zrender/core/GestureMgr}\n     */\n    this._gestureMgr;\n\n\n    Draggable.call(this);\n\n    this.setHandlerProxy(proxy);\n};\n\nHandler.prototype = {\n\n    constructor: Handler,\n\n    setHandlerProxy: function (proxy) {\n        if (this.proxy) {\n            this.proxy.dispose();\n        }\n\n        if (proxy) {\n            each$1(handlerNames, function (name) {\n                proxy.on && proxy.on(name, this[name], this);\n            }, this);\n            // Attach handler\n            proxy.handler = this;\n        }\n        this.proxy = proxy;\n    },\n\n    mousemove: function (event) {\n        var x = event.zrX;\n        var y = event.zrY;\n\n        var lastHovered = this._hovered;\n        var lastHoveredTarget = lastHovered.target;\n\n        // If lastHoveredTarget is removed from zr (detected by '__zr') by some API call\n        // (like 'setOption' or 'dispatchAction') in event handlers, we should find\n        // lastHovered again here. Otherwise 'mouseout' can not be triggered normally.\n        // See #6198.\n        if (lastHoveredTarget && !lastHoveredTarget.__zr) {\n            lastHovered = this.findHover(lastHovered.x, lastHovered.y);\n            lastHoveredTarget = lastHovered.target;\n        }\n\n        var hovered = this._hovered = this.findHover(x, y);\n        var hoveredTarget = hovered.target;\n\n        var proxy = this.proxy;\n        proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default');\n\n        // Mouse out on previous hovered element\n        if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget) {\n            this.dispatchToElement(lastHovered, 'mouseout', event);\n        }\n\n        // Mouse moving on one element\n        this.dispatchToElement(hovered, 'mousemove', event);\n\n        // Mouse over on a new element\n        if (hoveredTarget && hoveredTarget !== lastHoveredTarget) {\n            this.dispatchToElement(hovered, 'mouseover', event);\n        }\n    },\n\n    mouseout: function (event) {\n        this.dispatchToElement(this._hovered, 'mouseout', event);\n\n        // There might be some doms created by upper layer application\n        // at the same level of painter.getViewportRoot() (e.g., tooltip\n        // dom created by echarts), where 'globalout' event should not\n        // be triggered when mouse enters these doms. (But 'mouseout'\n        // should be triggered at the original hovered element as usual).\n        var element = event.toElement || event.relatedTarget;\n        var innerDom;\n        do {\n            element = element && element.parentNode;\n        }\n        while (element && element.nodeType !== 9 && !(\n            innerDom = element === this.painterRoot\n        ));\n\n        !innerDom && this.trigger('globalout', {event: event});\n    },\n\n    /**\n     * Resize\n     */\n    resize: function (event) {\n        this._hovered = {};\n    },\n\n    /**\n     * Dispatch event\n     * @param {string} eventName\n     * @param {event=} eventArgs\n     */\n    dispatch: function (eventName, eventArgs) {\n        var handler = this[eventName];\n        handler && handler.call(this, eventArgs);\n    },\n\n    /**\n     * Dispose\n     */\n    dispose: function () {\n\n        this.proxy.dispose();\n\n        this.storage =\n        this.proxy =\n        this.painter = null;\n    },\n\n    /**\n     * 设置默认的cursor style\n     * @param {string} [cursorStyle='default'] 例如 crosshair\n     */\n    setCursorStyle: function (cursorStyle) {\n        var proxy = this.proxy;\n        proxy.setCursor && proxy.setCursor(cursorStyle);\n    },\n\n    /**\n     * 事件分发代理\n     *\n     * @private\n     * @param {Object} targetInfo {target, topTarget} 目标图形元素\n     * @param {string} eventName 事件名称\n     * @param {Object} event 事件对象\n     */\n    dispatchToElement: function (targetInfo, eventName, event) {\n        targetInfo = targetInfo || {};\n        var el = targetInfo.target;\n        if (el && el.silent) {\n            return;\n        }\n        var eventHandler = 'on' + eventName;\n        var eventPacket = makeEventPacket(eventName, targetInfo, event);\n\n        while (el) {\n            el[eventHandler]\n                && (eventPacket.cancelBubble = el[eventHandler].call(el, eventPacket));\n\n            el.trigger(eventName, eventPacket);\n\n            el = el.parent;\n\n            if (eventPacket.cancelBubble) {\n                break;\n            }\n        }\n\n        if (!eventPacket.cancelBubble) {\n            // 冒泡到顶级 zrender 对象\n            this.trigger(eventName, eventPacket);\n            // 分发事件到用户自定义层\n            // 用户有可能在全局 click 事件中 dispose，所以需要判断下 painter 是否存在\n            this.painter && this.painter.eachOtherLayer(function (layer) {\n                if (typeof (layer[eventHandler]) === 'function') {\n                    layer[eventHandler].call(layer, eventPacket);\n                }\n                if (layer.trigger) {\n                    layer.trigger(eventName, eventPacket);\n                }\n            });\n        }\n    },\n\n    /**\n     * @private\n     * @param {number} x\n     * @param {number} y\n     * @param {module:zrender/graphic/Displayable} exclude\n     * @return {model:zrender/Element}\n     * @method\n     */\n    findHover: function (x, y, exclude) {\n        var list = this.storage.getDisplayList();\n        var out = {x: x, y: y};\n\n        for (var i = list.length - 1; i >= 0; i--) {\n            var hoverCheckResult;\n            if (list[i] !== exclude\n                // getDisplayList may include ignored item in VML mode\n                && !list[i].ignore\n                && (hoverCheckResult = isHover(list[i], x, y))\n            ) {\n                !out.topTarget && (out.topTarget = list[i]);\n                if (hoverCheckResult !== SILENT) {\n                    out.target = list[i];\n                    break;\n                }\n            }\n        }\n\n        return out;\n    },\n\n    processGesture: function (event, stage) {\n        if (!this._gestureMgr) {\n            this._gestureMgr = new GestureMgr();\n        }\n        var gestureMgr = this._gestureMgr;\n\n        stage === 'start' && gestureMgr.clear();\n\n        var gestureInfo = gestureMgr.recognize(\n            event,\n            this.findHover(event.zrX, event.zrY, null).target,\n            this.proxy.dom\n        );\n\n        stage === 'end' && gestureMgr.clear();\n\n        // Do not do any preventDefault here. Upper application do that if necessary.\n        if (gestureInfo) {\n            var type = gestureInfo.type;\n            event.gestureEvent = type;\n\n            this.dispatchToElement({target: gestureInfo.target}, type, gestureInfo.event);\n        }\n    }\n};\n\n// Common handlers\neach$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {\n    Handler.prototype[name] = function (event) {\n        // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover\n        var hovered = this.findHover(event.zrX, event.zrY);\n        var hoveredTarget = hovered.target;\n\n        if (name === 'mousedown') {\n            this._downEl = hoveredTarget;\n            this._downPoint = [event.zrX, event.zrY];\n            // In case click triggered before mouseup\n            this._upEl = hoveredTarget;\n        }\n        else if (name === 'mouseup') {\n            this._upEl = hoveredTarget;\n        }\n        else if (name === 'click') {\n            if (this._downEl !== this._upEl\n                // Original click event is triggered on the whole canvas element,\n                // including the case that `mousedown` - `mousemove` - `mouseup`,\n                // which should be filtered, otherwise it will bring trouble to\n                // pan and zoom.\n                || !this._downPoint\n                // Arbitrary value\n                || dist(this._downPoint, [event.zrX, event.zrY]) > 4\n            ) {\n                return;\n            }\n            this._downPoint = null;\n        }\n\n        this.dispatchToElement(hovered, name, event);\n    };\n});\n\nfunction isHover(displayable, x, y) {\n    if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) {\n        var el = displayable;\n        var isSilent;\n        while (el) {\n            // If clipped by ancestor.\n            // FIXME: If clipPath has neither stroke nor fill,\n            // el.clipPath.contain(x, y) will always return false.\n            if (el.clipPath && !el.clipPath.contain(x, y)) {\n                return false;\n            }\n            if (el.silent) {\n                isSilent = true;\n            }\n            el = el.parent;\n        }\n        return isSilent ? SILENT : true;\n    }\n\n    return false;\n}\n\nmixin(Handler, Eventful);\nmixin(Handler, Draggable);\n\n/**\n * 3x2矩阵操作类\n * @exports zrender/tool/matrix\n */\n\nvar ArrayCtor$1 = typeof Float32Array === 'undefined'\n    ? Array\n    : Float32Array;\n\n/**\n * Create a identity matrix.\n * @return {Float32Array|Array.<number>}\n */\nfunction create$1() {\n    var out = new ArrayCtor$1(6);\n    identity(out);\n\n    return out;\n}\n\n/**\n * 设置矩阵为单位矩阵\n * @param {Float32Array|Array.<number>} out\n */\nfunction identity(out) {\n    out[0] = 1;\n    out[1] = 0;\n    out[2] = 0;\n    out[3] = 1;\n    out[4] = 0;\n    out[5] = 0;\n    return out;\n}\n\n/**\n * 复制矩阵\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} m\n */\nfunction copy$1(out, m) {\n    out[0] = m[0];\n    out[1] = m[1];\n    out[2] = m[2];\n    out[3] = m[3];\n    out[4] = m[4];\n    out[5] = m[5];\n    return out;\n}\n\n/**\n * 矩阵相乘\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} m1\n * @param {Float32Array|Array.<number>} m2\n */\nfunction mul$1(out, m1, m2) {\n    // Consider matrix.mul(m, m2, m);\n    // where out is the same as m2.\n    // So use temp variable to escape error.\n    var out0 = m1[0] * m2[0] + m1[2] * m2[1];\n    var out1 = m1[1] * m2[0] + m1[3] * m2[1];\n    var out2 = m1[0] * m2[2] + m1[2] * m2[3];\n    var out3 = m1[1] * m2[2] + m1[3] * m2[3];\n    var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];\n    var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];\n    out[0] = out0;\n    out[1] = out1;\n    out[2] = out2;\n    out[3] = out3;\n    out[4] = out4;\n    out[5] = out5;\n    return out;\n}\n\n/**\n * 平移变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {Float32Array|Array.<number>} v\n */\nfunction translate(out, a, v) {\n    out[0] = a[0];\n    out[1] = a[1];\n    out[2] = a[2];\n    out[3] = a[3];\n    out[4] = a[4] + v[0];\n    out[5] = a[5] + v[1];\n    return out;\n}\n\n/**\n * 旋转变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {number} rad\n */\nfunction rotate(out, a, rad) {\n    var aa = a[0];\n    var ac = a[2];\n    var atx = a[4];\n    var ab = a[1];\n    var ad = a[3];\n    var aty = a[5];\n    var st = Math.sin(rad);\n    var ct = Math.cos(rad);\n\n    out[0] = aa * ct + ab * st;\n    out[1] = -aa * st + ab * ct;\n    out[2] = ac * ct + ad * st;\n    out[3] = -ac * st + ct * ad;\n    out[4] = ct * atx + st * aty;\n    out[5] = ct * aty - st * atx;\n    return out;\n}\n\n/**\n * 缩放变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {Float32Array|Array.<number>} v\n */\nfunction scale$1(out, a, v) {\n    var vx = v[0];\n    var vy = v[1];\n    out[0] = a[0] * vx;\n    out[1] = a[1] * vy;\n    out[2] = a[2] * vx;\n    out[3] = a[3] * vy;\n    out[4] = a[4] * vx;\n    out[5] = a[5] * vy;\n    return out;\n}\n\n/**\n * 求逆矩阵\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n */\nfunction invert(out, a) {\n\n    var aa = a[0];\n    var ac = a[2];\n    var atx = a[4];\n    var ab = a[1];\n    var ad = a[3];\n    var aty = a[5];\n\n    var det = aa * ad - ab * ac;\n    if (!det) {\n        return null;\n    }\n    det = 1.0 / det;\n\n    out[0] = ad * det;\n    out[1] = -ab * det;\n    out[2] = -ac * det;\n    out[3] = aa * det;\n    out[4] = (ac * aty - ad * atx) * det;\n    out[5] = (ab * atx - aa * aty) * det;\n    return out;\n}\n\n/**\n * Clone a new matrix.\n * @param {Float32Array|Array.<number>} a\n */\nfunction clone$2(a) {\n    var b = create$1();\n    copy$1(b, a);\n    return b;\n}\n\nvar matrix = (Object.freeze || Object)({\n\tcreate: create$1,\n\tidentity: identity,\n\tcopy: copy$1,\n\tmul: mul$1,\n\ttranslate: translate,\n\trotate: rotate,\n\tscale: scale$1,\n\tinvert: invert,\n\tclone: clone$2\n});\n\n/**\n * 提供变换扩展\n * @module zrender/mixin/Transformable\n * @author pissang (https://www.github.com/pissang)\n */\n\nvar mIdentity = identity;\n\nvar EPSILON = 5e-5;\n\nfunction isNotAroundZero(val) {\n    return val > EPSILON || val < -EPSILON;\n}\n\n/**\n * @alias module:zrender/mixin/Transformable\n * @constructor\n */\nvar Transformable = function (opts) {\n    opts = opts || {};\n    // If there are no given position, rotation, scale\n    if (!opts.position) {\n        /**\n         * 平移\n         * @type {Array.<number>}\n         * @default [0, 0]\n         */\n        this.position = [0, 0];\n    }\n    if (opts.rotation == null) {\n        /**\n         * 旋转\n         * @type {Array.<number>}\n         * @default 0\n         */\n        this.rotation = 0;\n    }\n    if (!opts.scale) {\n        /**\n         * 缩放\n         * @type {Array.<number>}\n         * @default [1, 1]\n         */\n        this.scale = [1, 1];\n    }\n    /**\n     * 旋转和缩放的原点\n     * @type {Array.<number>}\n     * @default null\n     */\n    this.origin = this.origin || null;\n};\n\nvar transformableProto = Transformable.prototype;\ntransformableProto.transform = null;\n\n/**\n * 判断是否需要有坐标变换\n * 如果有坐标变换, 则从position, rotation, scale以及父节点的transform计算出自身的transform矩阵\n */\ntransformableProto.needLocalTransform = function () {\n    return isNotAroundZero(this.rotation)\n        || isNotAroundZero(this.position[0])\n        || isNotAroundZero(this.position[1])\n        || isNotAroundZero(this.scale[0] - 1)\n        || isNotAroundZero(this.scale[1] - 1);\n};\n\nvar scaleTmp = [];\ntransformableProto.updateTransform = function () {\n    var parent = this.parent;\n    var parentHasTransform = parent && parent.transform;\n    var needLocalTransform = this.needLocalTransform();\n\n    var m = this.transform;\n    if (!(needLocalTransform || parentHasTransform)) {\n        m && mIdentity(m);\n        return;\n    }\n\n    m = m || create$1();\n\n    if (needLocalTransform) {\n        this.getLocalTransform(m);\n    }\n    else {\n        mIdentity(m);\n    }\n\n    // 应用父节点变换\n    if (parentHasTransform) {\n        if (needLocalTransform) {\n            mul$1(m, parent.transform, m);\n        }\n        else {\n            copy$1(m, parent.transform);\n        }\n    }\n    // 保存这个变换矩阵\n    this.transform = m;\n\n    var globalScaleRatio = this.globalScaleRatio;\n    if (globalScaleRatio != null && globalScaleRatio !== 1) {\n        this.getGlobalScale(scaleTmp);\n        var relX = scaleTmp[0] < 0 ? -1 : 1;\n        var relY = scaleTmp[1] < 0 ? -1 : 1;\n        var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0;\n        var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0;\n\n        m[0] *= sx;\n        m[1] *= sx;\n        m[2] *= sy;\n        m[3] *= sy;\n    }\n\n    this.invTransform = this.invTransform || create$1();\n    invert(this.invTransform, m);\n};\n\ntransformableProto.getLocalTransform = function (m) {\n    return Transformable.getLocalTransform(this, m);\n};\n\n/**\n * 将自己的transform应用到context上\n * @param {CanvasRenderingContext2D} ctx\n */\ntransformableProto.setTransform = function (ctx) {\n    var m = this.transform;\n    var dpr = ctx.dpr || 1;\n    if (m) {\n        ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]);\n    }\n    else {\n        ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    }\n};\n\ntransformableProto.restoreTransform = function (ctx) {\n    var dpr = ctx.dpr || 1;\n    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n};\n\nvar tmpTransform = [];\nvar originTransform = create$1();\n\ntransformableProto.setLocalTransform = function (m) {\n    if (!m) {\n        // TODO return or set identity?\n        return;\n    }\n    var sx = m[0] * m[0] + m[1] * m[1];\n    var sy = m[2] * m[2] + m[3] * m[3];\n    var position = this.position;\n    var scale$$1 = this.scale;\n    if (isNotAroundZero(sx - 1)) {\n        sx = Math.sqrt(sx);\n    }\n    if (isNotAroundZero(sy - 1)) {\n        sy = Math.sqrt(sy);\n    }\n    if (m[0] < 0) {\n        sx = -sx;\n    }\n    if (m[3] < 0) {\n        sy = -sy;\n    }\n\n    position[0] = m[4];\n    position[1] = m[5];\n    scale$$1[0] = sx;\n    scale$$1[1] = sy;\n    this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);\n};\n/**\n * 分解`transform`矩阵到`position`, `rotation`, `scale`\n */\ntransformableProto.decomposeTransform = function () {\n    if (!this.transform) {\n        return;\n    }\n    var parent = this.parent;\n    var m = this.transform;\n    if (parent && parent.transform) {\n        // Get local transform and decompose them to position, scale, rotation\n        mul$1(tmpTransform, parent.invTransform, m);\n        m = tmpTransform;\n    }\n    var origin = this.origin;\n    if (origin && (origin[0] || origin[1])) {\n        originTransform[4] = origin[0];\n        originTransform[5] = origin[1];\n        mul$1(tmpTransform, m, originTransform);\n        tmpTransform[4] -= origin[0];\n        tmpTransform[5] -= origin[1];\n        m = tmpTransform;\n    }\n\n    this.setLocalTransform(m);\n};\n\n/**\n * Get global scale\n * @return {Array.<number>}\n */\ntransformableProto.getGlobalScale = function (out) {\n    var m = this.transform;\n    out = out || [];\n    if (!m) {\n        out[0] = 1;\n        out[1] = 1;\n        return out;\n    }\n    out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]);\n    out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]);\n    if (m[0] < 0) {\n        out[0] = -out[0];\n    }\n    if (m[3] < 0) {\n        out[1] = -out[1];\n    }\n    return out;\n};\n/**\n * 变换坐标位置到 shape 的局部坐标空间\n * @method\n * @param {number} x\n * @param {number} y\n * @return {Array.<number>}\n */\ntransformableProto.transformCoordToLocal = function (x, y) {\n    var v2 = [x, y];\n    var invTransform = this.invTransform;\n    if (invTransform) {\n        applyTransform(v2, v2, invTransform);\n    }\n    return v2;\n};\n\n/**\n * 变换局部坐标位置到全局坐标空间\n * @method\n * @param {number} x\n * @param {number} y\n * @return {Array.<number>}\n */\ntransformableProto.transformCoordToGlobal = function (x, y) {\n    var v2 = [x, y];\n    var transform = this.transform;\n    if (transform) {\n        applyTransform(v2, v2, transform);\n    }\n    return v2;\n};\n\n/**\n * @static\n * @param {Object} target\n * @param {Array.<number>} target.origin\n * @param {number} target.rotation\n * @param {Array.<number>} target.position\n * @param {Array.<number>} [m]\n */\nTransformable.getLocalTransform = function (target, m) {\n    m = m || [];\n    mIdentity(m);\n\n    var origin = target.origin;\n    var scale$$1 = target.scale || [1, 1];\n    var rotation = target.rotation || 0;\n    var position = target.position || [0, 0];\n\n    if (origin) {\n        // Translate to origin\n        m[4] -= origin[0];\n        m[5] -= origin[1];\n    }\n    scale$1(m, m, scale$$1);\n    if (rotation) {\n        rotate(m, m, rotation);\n    }\n    if (origin) {\n        // Translate back from origin\n        m[4] += origin[0];\n        m[5] += origin[1];\n    }\n\n    m[4] += position[0];\n    m[5] += position[1];\n\n    return m;\n};\n\n/**\n * 缓动代码来自 https://github.com/sole/tween.js/blob/master/src/Tween.js\n * @see http://sole.github.io/tween.js/examples/03_graphs.html\n * @exports zrender/animation/easing\n */\nvar easing = {\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    linear: function (k) {\n        return k;\n    },\n\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticIn: function (k) {\n        return k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticOut: function (k) {\n        return k * (2 - k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k;\n        }\n        return -0.5 * (--k * (k - 2) - 1);\n    },\n\n    // 三次方的缓动（t^3）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicIn: function (k) {\n        return k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicOut: function (k) {\n        return --k * k * k + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k;\n        }\n        return 0.5 * ((k -= 2) * k * k + 2);\n    },\n\n    // 四次方的缓动（t^4）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticIn: function (k) {\n        return k * k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticOut: function (k) {\n        return 1 - (--k * k * k * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k * k;\n        }\n        return -0.5 * ((k -= 2) * k * k * k - 2);\n    },\n\n    // 五次方的缓动（t^5）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticIn: function (k) {\n        return k * k * k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticOut: function (k) {\n        return --k * k * k * k * k + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k * k * k;\n        }\n        return 0.5 * ((k -= 2) * k * k * k * k + 2);\n    },\n\n    // 正弦曲线的缓动（sin(t)）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalIn: function (k) {\n        return 1 - Math.cos(k * Math.PI / 2);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalOut: function (k) {\n        return Math.sin(k * Math.PI / 2);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalInOut: function (k) {\n        return 0.5 * (1 - Math.cos(Math.PI * k));\n    },\n\n    // 指数曲线的缓动（2^t）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialIn: function (k) {\n        return k === 0 ? 0 : Math.pow(1024, k - 1);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialOut: function (k) {\n        return k === 1 ? 1 : 1 - Math.pow(2, -10 * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialInOut: function (k) {\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if ((k *= 2) < 1) {\n            return 0.5 * Math.pow(1024, k - 1);\n        }\n        return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);\n    },\n\n    // 圆形曲线的缓动（sqrt(1-t^2)）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularIn: function (k) {\n        return 1 - Math.sqrt(1 - k * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularOut: function (k) {\n        return Math.sqrt(1 - (--k * k));\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return -0.5 * (Math.sqrt(1 - k * k) - 1);\n        }\n        return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);\n    },\n\n    // 创建类似于弹簧在停止前来回振荡的动画\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticIn: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        return -(a * Math.pow(2, 10 * (k -= 1))\n                    * Math.sin((k - s) * (2 * Math.PI) / p));\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticOut: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        return (a * Math.pow(2, -10 * k)\n                    * Math.sin((k - s) * (2 * Math.PI) / p) + 1);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticInOut: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        if ((k *= 2) < 1) {\n            return -0.5 * (a * Math.pow(2, 10 * (k -= 1))\n                * Math.sin((k - s) * (2 * Math.PI) / p));\n        }\n        return a * Math.pow(2, -10 * (k -= 1))\n                * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;\n\n    },\n\n    // 在某一动画开始沿指示的路径进行动画处理前稍稍收回该动画的移动\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backIn: function (k) {\n        var s = 1.70158;\n        return k * k * ((s + 1) * k - s);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backOut: function (k) {\n        var s = 1.70158;\n        return --k * k * ((s + 1) * k + s) + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backInOut: function (k) {\n        var s = 1.70158 * 1.525;\n        if ((k *= 2) < 1) {\n            return 0.5 * (k * k * ((s + 1) * k - s));\n        }\n        return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);\n    },\n\n    // 创建弹跳效果\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceIn: function (k) {\n        return 1 - easing.bounceOut(1 - k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceOut: function (k) {\n        if (k < (1 / 2.75)) {\n            return 7.5625 * k * k;\n        }\n        else if (k < (2 / 2.75)) {\n            return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;\n        }\n        else if (k < (2.5 / 2.75)) {\n            return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;\n        }\n        else {\n            return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;\n        }\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceInOut: function (k) {\n        if (k < 0.5) {\n            return easing.bounceIn(k * 2) * 0.5;\n        }\n        return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;\n    }\n};\n\n/**\n * 动画主控制器\n * @config target 动画对象，可以是数组，如果是数组的话会批量分发onframe等事件\n * @config life(1000) 动画时长\n * @config delay(0) 动画延迟时间\n * @config loop(true)\n * @config gap(0) 循环的间隔时间\n * @config onframe\n * @config easing(optional)\n * @config ondestroy(optional)\n * @config onrestart(optional)\n *\n * TODO pause\n */\n\nfunction Clip(options) {\n\n    this._target = options.target;\n\n    // 生命周期\n    this._life = options.life || 1000;\n    // 延时\n    this._delay = options.delay || 0;\n    // 开始时间\n    // this._startTime = new Date().getTime() + this._delay;// 单位毫秒\n    this._initialized = false;\n\n    // 是否循环\n    this.loop = options.loop == null ? false : options.loop;\n\n    this.gap = options.gap || 0;\n\n    this.easing = options.easing || 'Linear';\n\n    this.onframe = options.onframe;\n    this.ondestroy = options.ondestroy;\n    this.onrestart = options.onrestart;\n\n    this._pausedTime = 0;\n    this._paused = false;\n}\n\nClip.prototype = {\n\n    constructor: Clip,\n\n    step: function (globalTime, deltaTime) {\n        // Set startTime on first step, or _startTime may has milleseconds different between clips\n        // PENDING\n        if (!this._initialized) {\n            this._startTime = globalTime + this._delay;\n            this._initialized = true;\n        }\n\n        if (this._paused) {\n            this._pausedTime += deltaTime;\n            return;\n        }\n\n        var percent = (globalTime - this._startTime - this._pausedTime) / this._life;\n\n        // 还没开始\n        if (percent < 0) {\n            return;\n        }\n\n        percent = Math.min(percent, 1);\n\n        var easing$$1 = this.easing;\n        var easingFunc = typeof easing$$1 === 'string' ? easing[easing$$1] : easing$$1;\n        var schedule = typeof easingFunc === 'function'\n            ? easingFunc(percent)\n            : percent;\n\n        this.fire('frame', schedule);\n\n        // 结束\n        if (percent === 1) {\n            if (this.loop) {\n                this.restart(globalTime);\n                // 重新开始周期\n                // 抛出而不是直接调用事件直到 stage.update 后再统一调用这些事件\n                return 'restart';\n            }\n\n            // 动画完成将这个控制器标识为待删除\n            // 在Animation.update中进行批量删除\n            this._needsRemove = true;\n            return 'destroy';\n        }\n\n        return null;\n    },\n\n    restart: function (globalTime) {\n        var remainder = (globalTime - this._startTime - this._pausedTime) % this._life;\n        this._startTime = globalTime - remainder + this.gap;\n        this._pausedTime = 0;\n\n        this._needsRemove = false;\n    },\n\n    fire: function (eventType, arg) {\n        eventType = 'on' + eventType;\n        if (this[eventType]) {\n            this[eventType](this._target, arg);\n        }\n    },\n\n    pause: function () {\n        this._paused = true;\n    },\n\n    resume: function () {\n        this._paused = false;\n    }\n};\n\n// Simple LRU cache use doubly linked list\n// @module zrender/core/LRU\n\n/**\n * Simple double linked list. Compared with array, it has O(1) remove operation.\n * @constructor\n */\nvar LinkedList = function () {\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.head = null;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.tail = null;\n\n    this._len = 0;\n};\n\nvar linkedListProto = LinkedList.prototype;\n/**\n * Insert a new value at the tail\n * @param  {} val\n * @return {module:zrender/core/LRU~Entry}\n */\nlinkedListProto.insert = function (val) {\n    var entry = new Entry(val);\n    this.insertEntry(entry);\n    return entry;\n};\n\n/**\n * Insert an entry at the tail\n * @param  {module:zrender/core/LRU~Entry} entry\n */\nlinkedListProto.insertEntry = function (entry) {\n    if (!this.head) {\n        this.head = this.tail = entry;\n    }\n    else {\n        this.tail.next = entry;\n        entry.prev = this.tail;\n        entry.next = null;\n        this.tail = entry;\n    }\n    this._len++;\n};\n\n/**\n * Remove entry.\n * @param  {module:zrender/core/LRU~Entry} entry\n */\nlinkedListProto.remove = function (entry) {\n    var prev = entry.prev;\n    var next = entry.next;\n    if (prev) {\n        prev.next = next;\n    }\n    else {\n        // Is head\n        this.head = next;\n    }\n    if (next) {\n        next.prev = prev;\n    }\n    else {\n        // Is tail\n        this.tail = prev;\n    }\n    entry.next = entry.prev = null;\n    this._len--;\n};\n\n/**\n * @return {number}\n */\nlinkedListProto.len = function () {\n    return this._len;\n};\n\n/**\n * Clear list\n */\nlinkedListProto.clear = function () {\n    this.head = this.tail = null;\n    this._len = 0;\n};\n\n/**\n * @constructor\n * @param {} val\n */\nvar Entry = function (val) {\n    /**\n     * @type {}\n     */\n    this.value = val;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.next;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.prev;\n};\n\n/**\n * LRU Cache\n * @constructor\n * @alias module:zrender/core/LRU\n */\nvar LRU = function (maxSize) {\n\n    this._list = new LinkedList();\n\n    this._map = {};\n\n    this._maxSize = maxSize || 10;\n\n    this._lastRemovedEntry = null;\n};\n\nvar LRUProto = LRU.prototype;\n\n/**\n * @param  {string} key\n * @param  {} value\n * @return {} Removed value\n */\nLRUProto.put = function (key, value) {\n    var list = this._list;\n    var map = this._map;\n    var removed = null;\n    if (map[key] == null) {\n        var len = list.len();\n        // Reuse last removed entry\n        var entry = this._lastRemovedEntry;\n\n        if (len >= this._maxSize && len > 0) {\n            // Remove the least recently used\n            var leastUsedEntry = list.head;\n            list.remove(leastUsedEntry);\n            delete map[leastUsedEntry.key];\n\n            removed = leastUsedEntry.value;\n            this._lastRemovedEntry = leastUsedEntry;\n        }\n\n        if (entry) {\n            entry.value = value;\n        }\n        else {\n            entry = new Entry(value);\n        }\n        entry.key = key;\n        list.insertEntry(entry);\n        map[key] = entry;\n    }\n\n    return removed;\n};\n\n/**\n * @param  {string} key\n * @return {}\n */\nLRUProto.get = function (key) {\n    var entry = this._map[key];\n    var list = this._list;\n    if (entry != null) {\n        // Put the latest used entry in the tail\n        if (entry !== list.tail) {\n            list.remove(entry);\n            list.insertEntry(entry);\n        }\n\n        return entry.value;\n    }\n};\n\n/**\n * Clear the cache\n */\nLRUProto.clear = function () {\n    this._list.clear();\n    this._map = {};\n};\n\nvar kCSSColorTable = {\n    'transparent': [0, 0, 0, 0], 'aliceblue': [240, 248, 255, 1],\n    'antiquewhite': [250, 235, 215, 1], 'aqua': [0, 255, 255, 1],\n    'aquamarine': [127, 255, 212, 1], 'azure': [240, 255, 255, 1],\n    'beige': [245, 245, 220, 1], 'bisque': [255, 228, 196, 1],\n    'black': [0, 0, 0, 1], 'blanchedalmond': [255, 235, 205, 1],\n    'blue': [0, 0, 255, 1], 'blueviolet': [138, 43, 226, 1],\n    'brown': [165, 42, 42, 1], 'burlywood': [222, 184, 135, 1],\n    'cadetblue': [95, 158, 160, 1], 'chartreuse': [127, 255, 0, 1],\n    'chocolate': [210, 105, 30, 1], 'coral': [255, 127, 80, 1],\n    'cornflowerblue': [100, 149, 237, 1], 'cornsilk': [255, 248, 220, 1],\n    'crimson': [220, 20, 60, 1], 'cyan': [0, 255, 255, 1],\n    'darkblue': [0, 0, 139, 1], 'darkcyan': [0, 139, 139, 1],\n    'darkgoldenrod': [184, 134, 11, 1], 'darkgray': [169, 169, 169, 1],\n    'darkgreen': [0, 100, 0, 1], 'darkgrey': [169, 169, 169, 1],\n    'darkkhaki': [189, 183, 107, 1], 'darkmagenta': [139, 0, 139, 1],\n    'darkolivegreen': [85, 107, 47, 1], 'darkorange': [255, 140, 0, 1],\n    'darkorchid': [153, 50, 204, 1], 'darkred': [139, 0, 0, 1],\n    'darksalmon': [233, 150, 122, 1], 'darkseagreen': [143, 188, 143, 1],\n    'darkslateblue': [72, 61, 139, 1], 'darkslategray': [47, 79, 79, 1],\n    'darkslategrey': [47, 79, 79, 1], 'darkturquoise': [0, 206, 209, 1],\n    'darkviolet': [148, 0, 211, 1], 'deeppink': [255, 20, 147, 1],\n    'deepskyblue': [0, 191, 255, 1], 'dimgray': [105, 105, 105, 1],\n    'dimgrey': [105, 105, 105, 1], 'dodgerblue': [30, 144, 255, 1],\n    'firebrick': [178, 34, 34, 1], 'floralwhite': [255, 250, 240, 1],\n    'forestgreen': [34, 139, 34, 1], 'fuchsia': [255, 0, 255, 1],\n    'gainsboro': [220, 220, 220, 1], 'ghostwhite': [248, 248, 255, 1],\n    'gold': [255, 215, 0, 1], 'goldenrod': [218, 165, 32, 1],\n    'gray': [128, 128, 128, 1], 'green': [0, 128, 0, 1],\n    'greenyellow': [173, 255, 47, 1], 'grey': [128, 128, 128, 1],\n    'honeydew': [240, 255, 240, 1], 'hotpink': [255, 105, 180, 1],\n    'indianred': [205, 92, 92, 1], 'indigo': [75, 0, 130, 1],\n    'ivory': [255, 255, 240, 1], 'khaki': [240, 230, 140, 1],\n    'lavender': [230, 230, 250, 1], 'lavenderblush': [255, 240, 245, 1],\n    'lawngreen': [124, 252, 0, 1], 'lemonchiffon': [255, 250, 205, 1],\n    'lightblue': [173, 216, 230, 1], 'lightcoral': [240, 128, 128, 1],\n    'lightcyan': [224, 255, 255, 1], 'lightgoldenrodyellow': [250, 250, 210, 1],\n    'lightgray': [211, 211, 211, 1], 'lightgreen': [144, 238, 144, 1],\n    'lightgrey': [211, 211, 211, 1], 'lightpink': [255, 182, 193, 1],\n    'lightsalmon': [255, 160, 122, 1], 'lightseagreen': [32, 178, 170, 1],\n    'lightskyblue': [135, 206, 250, 1], 'lightslategray': [119, 136, 153, 1],\n    'lightslategrey': [119, 136, 153, 1], 'lightsteelblue': [176, 196, 222, 1],\n    'lightyellow': [255, 255, 224, 1], 'lime': [0, 255, 0, 1],\n    'limegreen': [50, 205, 50, 1], 'linen': [250, 240, 230, 1],\n    'magenta': [255, 0, 255, 1], 'maroon': [128, 0, 0, 1],\n    'mediumaquamarine': [102, 205, 170, 1], 'mediumblue': [0, 0, 205, 1],\n    'mediumorchid': [186, 85, 211, 1], 'mediumpurple': [147, 112, 219, 1],\n    'mediumseagreen': [60, 179, 113, 1], 'mediumslateblue': [123, 104, 238, 1],\n    'mediumspringgreen': [0, 250, 154, 1], 'mediumturquoise': [72, 209, 204, 1],\n    'mediumvioletred': [199, 21, 133, 1], 'midnightblue': [25, 25, 112, 1],\n    'mintcream': [245, 255, 250, 1], 'mistyrose': [255, 228, 225, 1],\n    'moccasin': [255, 228, 181, 1], 'navajowhite': [255, 222, 173, 1],\n    'navy': [0, 0, 128, 1], 'oldlace': [253, 245, 230, 1],\n    'olive': [128, 128, 0, 1], 'olivedrab': [107, 142, 35, 1],\n    'orange': [255, 165, 0, 1], 'orangered': [255, 69, 0, 1],\n    'orchid': [218, 112, 214, 1], 'palegoldenrod': [238, 232, 170, 1],\n    'palegreen': [152, 251, 152, 1], 'paleturquoise': [175, 238, 238, 1],\n    'palevioletred': [219, 112, 147, 1], 'papayawhip': [255, 239, 213, 1],\n    'peachpuff': [255, 218, 185, 1], 'peru': [205, 133, 63, 1],\n    'pink': [255, 192, 203, 1], 'plum': [221, 160, 221, 1],\n    'powderblue': [176, 224, 230, 1], 'purple': [128, 0, 128, 1],\n    'red': [255, 0, 0, 1], 'rosybrown': [188, 143, 143, 1],\n    'royalblue': [65, 105, 225, 1], 'saddlebrown': [139, 69, 19, 1],\n    'salmon': [250, 128, 114, 1], 'sandybrown': [244, 164, 96, 1],\n    'seagreen': [46, 139, 87, 1], 'seashell': [255, 245, 238, 1],\n    'sienna': [160, 82, 45, 1], 'silver': [192, 192, 192, 1],\n    'skyblue': [135, 206, 235, 1], 'slateblue': [106, 90, 205, 1],\n    'slategray': [112, 128, 144, 1], 'slategrey': [112, 128, 144, 1],\n    'snow': [255, 250, 250, 1], 'springgreen': [0, 255, 127, 1],\n    'steelblue': [70, 130, 180, 1], 'tan': [210, 180, 140, 1],\n    'teal': [0, 128, 128, 1], 'thistle': [216, 191, 216, 1],\n    'tomato': [255, 99, 71, 1], 'turquoise': [64, 224, 208, 1],\n    'violet': [238, 130, 238, 1], 'wheat': [245, 222, 179, 1],\n    'white': [255, 255, 255, 1], 'whitesmoke': [245, 245, 245, 1],\n    'yellow': [255, 255, 0, 1], 'yellowgreen': [154, 205, 50, 1]\n};\n\nfunction clampCssByte(i) {  // Clamp to integer 0 .. 255.\n    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).\n    return i < 0 ? 0 : i > 255 ? 255 : i;\n}\n\nfunction clampCssAngle(i) {  // Clamp to integer 0 .. 360.\n    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).\n    return i < 0 ? 0 : i > 360 ? 360 : i;\n}\n\nfunction clampCssFloat(f) {  // Clamp to float 0.0 .. 1.0.\n    return f < 0 ? 0 : f > 1 ? 1 : f;\n}\n\nfunction parseCssInt(str) {  // int or percentage.\n    if (str.length && str.charAt(str.length - 1) === '%') {\n        return clampCssByte(parseFloat(str) / 100 * 255);\n    }\n    return clampCssByte(parseInt(str, 10));\n}\n\nfunction parseCssFloat(str) {  // float or percentage.\n    if (str.length && str.charAt(str.length - 1) === '%') {\n        return clampCssFloat(parseFloat(str) / 100);\n    }\n    return clampCssFloat(parseFloat(str));\n}\n\nfunction cssHueToRgb(m1, m2, h) {\n    if (h < 0) {\n        h += 1;\n    }\n    else if (h > 1) {\n        h -= 1;\n    }\n\n    if (h * 6 < 1) {\n        return m1 + (m2 - m1) * h * 6;\n    }\n    if (h * 2 < 1) {\n        return m2;\n    }\n    if (h * 3 < 2) {\n        return m1 + (m2 - m1) * (2 / 3 - h) * 6;\n    }\n    return m1;\n}\n\nfunction lerpNumber(a, b, p) {\n    return a + (b - a) * p;\n}\n\nfunction setRgba(out, r, g, b, a) {\n    out[0] = r; out[1] = g; out[2] = b; out[3] = a;\n    return out;\n}\nfunction copyRgba(out, a) {\n    out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3];\n    return out;\n}\n\nvar colorCache = new LRU(20);\nvar lastRemovedArr = null;\n\nfunction putToCache(colorStr, rgbaArr) {\n    // Reuse removed array\n    if (lastRemovedArr) {\n        copyRgba(lastRemovedArr, rgbaArr);\n    }\n    lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice()));\n}\n\n/**\n * @param {string} colorStr\n * @param {Array.<number>} out\n * @return {Array.<number>}\n * @memberOf module:zrender/util/color\n */\nfunction parse(colorStr, rgbaArr) {\n    if (!colorStr) {\n        return;\n    }\n    rgbaArr = rgbaArr || [];\n\n    var cached = colorCache.get(colorStr);\n    if (cached) {\n        return copyRgba(rgbaArr, cached);\n    }\n\n    // colorStr may be not string\n    colorStr = colorStr + '';\n    // Remove all whitespace, not compliant, but should just be more accepting.\n    var str = colorStr.replace(/ /g, '').toLowerCase();\n\n    // Color keywords (and transparent) lookup.\n    if (str in kCSSColorTable) {\n        copyRgba(rgbaArr, kCSSColorTable[str]);\n        putToCache(colorStr, rgbaArr);\n        return rgbaArr;\n    }\n\n    // #abc and #abc123 syntax.\n    if (str.charAt(0) === '#') {\n        if (str.length === 4) {\n            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n            if (!(iv >= 0 && iv <= 0xfff)) {\n                setRgba(rgbaArr, 0, 0, 0, 1);\n                return;  // Covers NaN.\n            }\n            setRgba(rgbaArr,\n                ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8),\n                (iv & 0xf0) | ((iv & 0xf0) >> 4),\n                (iv & 0xf) | ((iv & 0xf) << 4),\n                1\n            );\n            putToCache(colorStr, rgbaArr);\n            return rgbaArr;\n        }\n        else if (str.length === 7) {\n            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n            if (!(iv >= 0 && iv <= 0xffffff)) {\n                setRgba(rgbaArr, 0, 0, 0, 1);\n                return;  // Covers NaN.\n            }\n            setRgba(rgbaArr,\n                (iv & 0xff0000) >> 16,\n                (iv & 0xff00) >> 8,\n                iv & 0xff,\n                1\n            );\n            putToCache(colorStr, rgbaArr);\n            return rgbaArr;\n        }\n\n        return;\n    }\n    var op = str.indexOf('(');\n    var ep = str.indexOf(')');\n    if (op !== -1 && ep + 1 === str.length) {\n        var fname = str.substr(0, op);\n        var params = str.substr(op + 1, ep - (op + 1)).split(',');\n        var alpha = 1;  // To allow case fallthrough.\n        switch (fname) {\n            case 'rgba':\n                if (params.length !== 4) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                alpha = parseCssFloat(params.pop()); // jshint ignore:line\n            // Fall through.\n            case 'rgb':\n                if (params.length !== 3) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                setRgba(rgbaArr,\n                    parseCssInt(params[0]),\n                    parseCssInt(params[1]),\n                    parseCssInt(params[2]),\n                    alpha\n                );\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            case 'hsla':\n                if (params.length !== 4) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                params[3] = parseCssFloat(params[3]);\n                hsla2rgba(params, rgbaArr);\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            case 'hsl':\n                if (params.length !== 3) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                hsla2rgba(params, rgbaArr);\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            default:\n                return;\n        }\n    }\n\n    setRgba(rgbaArr, 0, 0, 0, 1);\n    return;\n}\n\n/**\n * @param {Array.<number>} hsla\n * @param {Array.<number>} rgba\n * @return {Array.<number>} rgba\n */\nfunction hsla2rgba(hsla, rgba) {\n    var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360;  // 0 .. 1\n    // NOTE(deanm): According to the CSS spec s/l should only be\n    // percentages, but we don't bother and let float or percentage.\n    var s = parseCssFloat(hsla[1]);\n    var l = parseCssFloat(hsla[2]);\n    var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;\n    var m1 = l * 2 - m2;\n\n    rgba = rgba || [];\n    setRgba(rgba,\n        clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255),\n        clampCssByte(cssHueToRgb(m1, m2, h) * 255),\n        clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255),\n        1\n    );\n\n    if (hsla.length === 4) {\n        rgba[3] = hsla[3];\n    }\n\n    return rgba;\n}\n\n/**\n * @param {Array.<number>} rgba\n * @return {Array.<number>} hsla\n */\nfunction rgba2hsla(rgba) {\n    if (!rgba) {\n        return;\n    }\n\n    // RGB from 0 to 255\n    var R = rgba[0] / 255;\n    var G = rgba[1] / 255;\n    var B = rgba[2] / 255;\n\n    var vMin = Math.min(R, G, B); // Min. value of RGB\n    var vMax = Math.max(R, G, B); // Max. value of RGB\n    var delta = vMax - vMin; // Delta RGB value\n\n    var L = (vMax + vMin) / 2;\n    var H;\n    var S;\n    // HSL results from 0 to 1\n    if (delta === 0) {\n        H = 0;\n        S = 0;\n    }\n    else {\n        if (L < 0.5) {\n            S = delta / (vMax + vMin);\n        }\n        else {\n            S = delta / (2 - vMax - vMin);\n        }\n\n        var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta;\n        var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta;\n        var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta;\n\n        if (R === vMax) {\n            H = deltaB - deltaG;\n        }\n        else if (G === vMax) {\n            H = (1 / 3) + deltaR - deltaB;\n        }\n        else if (B === vMax) {\n            H = (2 / 3) + deltaG - deltaR;\n        }\n\n        if (H < 0) {\n            H += 1;\n        }\n\n        if (H > 1) {\n            H -= 1;\n        }\n    }\n\n    var hsla = [H * 360, S, L];\n\n    if (rgba[3] != null) {\n        hsla.push(rgba[3]);\n    }\n\n    return hsla;\n}\n\n/**\n * @param {string} color\n * @param {number} level\n * @return {string}\n * @memberOf module:zrender/util/color\n */\nfunction lift(color, level) {\n    var colorArr = parse(color);\n    if (colorArr) {\n        for (var i = 0; i < 3; i++) {\n            if (level < 0) {\n                colorArr[i] = colorArr[i] * (1 - level) | 0;\n            }\n            else {\n                colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0;\n            }\n            if (colorArr[i] > 255) {\n                colorArr[i] = 255;\n            }\n            else if (color[i] < 0) {\n                colorArr[i] = 0;\n            }\n        }\n        return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');\n    }\n}\n\n/**\n * @param {string} color\n * @return {string}\n * @memberOf module:zrender/util/color\n */\nfunction toHex(color) {\n    var colorArr = parse(color);\n    if (colorArr) {\n        return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1);\n    }\n}\n\n/**\n * Map value to color. Faster than lerp methods because color is represented by rgba array.\n * @param {number} normalizedValue A float between 0 and 1.\n * @param {Array.<Array.<number>>} colors List of rgba color array\n * @param {Array.<number>} [out] Mapped gba color array\n * @return {Array.<number>} will be null/undefined if input illegal.\n */\nfunction fastLerp(normalizedValue, colors, out) {\n    if (!(colors && colors.length)\n        || !(normalizedValue >= 0 && normalizedValue <= 1)\n    ) {\n        return;\n    }\n\n    out = out || [];\n\n    var value = normalizedValue * (colors.length - 1);\n    var leftIndex = Math.floor(value);\n    var rightIndex = Math.ceil(value);\n    var leftColor = colors[leftIndex];\n    var rightColor = colors[rightIndex];\n    var dv = value - leftIndex;\n    out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv));\n    out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv));\n    out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv));\n    out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv));\n\n    return out;\n}\n\n/**\n * @deprecated\n */\nvar fastMapToColor = fastLerp;\n\n/**\n * @param {number} normalizedValue A float between 0 and 1.\n * @param {Array.<string>} colors Color list.\n * @param {boolean=} fullOutput Default false.\n * @return {(string|Object)} Result color. If fullOutput,\n *                           return {color: ..., leftIndex: ..., rightIndex: ..., value: ...},\n * @memberOf module:zrender/util/color\n */\nfunction lerp$1(normalizedValue, colors, fullOutput) {\n    if (!(colors && colors.length)\n        || !(normalizedValue >= 0 && normalizedValue <= 1)\n    ) {\n        return;\n    }\n\n    var value = normalizedValue * (colors.length - 1);\n    var leftIndex = Math.floor(value);\n    var rightIndex = Math.ceil(value);\n    var leftColor = parse(colors[leftIndex]);\n    var rightColor = parse(colors[rightIndex]);\n    var dv = value - leftIndex;\n\n    var color = stringify(\n        [\n            clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)),\n            clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)),\n            clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)),\n            clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv))\n        ],\n        'rgba'\n    );\n\n    return fullOutput\n        ? {\n            color: color,\n            leftIndex: leftIndex,\n            rightIndex: rightIndex,\n            value: value\n        }\n        : color;\n}\n\n/**\n * @deprecated\n */\nvar mapToColor = lerp$1;\n\n/**\n * @param {string} color\n * @param {number=} h 0 ~ 360, ignore when null.\n * @param {number=} s 0 ~ 1, ignore when null.\n * @param {number=} l 0 ~ 1, ignore when null.\n * @return {string} Color string in rgba format.\n * @memberOf module:zrender/util/color\n */\nfunction modifyHSL(color, h, s, l) {\n    color = parse(color);\n\n    if (color) {\n        color = rgba2hsla(color);\n        h != null && (color[0] = clampCssAngle(h));\n        s != null && (color[1] = parseCssFloat(s));\n        l != null && (color[2] = parseCssFloat(l));\n\n        return stringify(hsla2rgba(color), 'rgba');\n    }\n}\n\n/**\n * @param {string} color\n * @param {number=} alpha 0 ~ 1\n * @return {string} Color string in rgba format.\n * @memberOf module:zrender/util/color\n */\nfunction modifyAlpha(color, alpha) {\n    color = parse(color);\n\n    if (color && alpha != null) {\n        color[3] = clampCssFloat(alpha);\n        return stringify(color, 'rgba');\n    }\n}\n\n/**\n * @param {Array.<number>} arrColor like [12,33,44,0.4]\n * @param {string} type 'rgba', 'hsva', ...\n * @return {string} Result color. (If input illegal, return undefined).\n */\nfunction stringify(arrColor, type) {\n    if (!arrColor || !arrColor.length) {\n        return;\n    }\n    var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];\n    if (type === 'rgba' || type === 'hsva' || type === 'hsla') {\n        colorStr += ',' + arrColor[3];\n    }\n    return type + '(' + colorStr + ')';\n}\n\n\nvar color = (Object.freeze || Object)({\n\tparse: parse,\n\tlift: lift,\n\ttoHex: toHex,\n\tfastLerp: fastLerp,\n\tfastMapToColor: fastMapToColor,\n\tlerp: lerp$1,\n\tmapToColor: mapToColor,\n\tmodifyHSL: modifyHSL,\n\tmodifyAlpha: modifyAlpha,\n\tstringify: stringify\n});\n\n/**\n * @module echarts/animation/Animator\n */\n\nvar arraySlice = Array.prototype.slice;\n\nfunction defaultGetter(target, key) {\n    return target[key];\n}\n\nfunction defaultSetter(target, key, value) {\n    target[key] = value;\n}\n\n/**\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} percent\n * @return {number}\n */\nfunction interpolateNumber(p0, p1, percent) {\n    return (p1 - p0) * percent + p0;\n}\n\n/**\n * @param  {string} p0\n * @param  {string} p1\n * @param  {number} percent\n * @return {string}\n */\nfunction interpolateString(p0, p1, percent) {\n    return percent > 0.5 ? p1 : p0;\n}\n\n/**\n * @param  {Array} p0\n * @param  {Array} p1\n * @param  {number} percent\n * @param  {Array} out\n * @param  {number} arrDim\n */\nfunction interpolateArray(p0, p1, percent, out, arrDim) {\n    var len = p0.length;\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            out[i] = interpolateNumber(p0[i], p1[i], percent);\n        }\n    }\n    else {\n        var len2 = len && p0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                out[i][j] = interpolateNumber(\n                    p0[i][j], p1[i][j], percent\n                );\n            }\n        }\n    }\n}\n\n// arr0 is source array, arr1 is target array.\n// Do some preprocess to avoid error happened when interpolating from arr0 to arr1\nfunction fillArr(arr0, arr1, arrDim) {\n    var arr0Len = arr0.length;\n    var arr1Len = arr1.length;\n    if (arr0Len !== arr1Len) {\n        // FIXME Not work for TypedArray\n        var isPreviousLarger = arr0Len > arr1Len;\n        if (isPreviousLarger) {\n            // Cut the previous\n            arr0.length = arr1Len;\n        }\n        else {\n            // Fill the previous\n            for (var i = arr0Len; i < arr1Len; i++) {\n                arr0.push(\n                    arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i])\n                );\n            }\n        }\n    }\n    // Handling NaN value\n    var len2 = arr0[0] && arr0[0].length;\n    for (var i = 0; i < arr0.length; i++) {\n        if (arrDim === 1) {\n            if (isNaN(arr0[i])) {\n                arr0[i] = arr1[i];\n            }\n        }\n        else {\n            for (var j = 0; j < len2; j++) {\n                if (isNaN(arr0[i][j])) {\n                    arr0[i][j] = arr1[i][j];\n                }\n            }\n        }\n    }\n}\n\n/**\n * @param  {Array} arr0\n * @param  {Array} arr1\n * @param  {number} arrDim\n * @return {boolean}\n */\nfunction isArraySame(arr0, arr1, arrDim) {\n    if (arr0 === arr1) {\n        return true;\n    }\n    var len = arr0.length;\n    if (len !== arr1.length) {\n        return false;\n    }\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            if (arr0[i] !== arr1[i]) {\n                return false;\n            }\n        }\n    }\n    else {\n        var len2 = arr0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                if (arr0[i][j] !== arr1[i][j]) {\n                    return false;\n                }\n            }\n        }\n    }\n    return true;\n}\n\n/**\n * Catmull Rom interpolate array\n * @param  {Array} p0\n * @param  {Array} p1\n * @param  {Array} p2\n * @param  {Array} p3\n * @param  {number} t\n * @param  {number} t2\n * @param  {number} t3\n * @param  {Array} out\n * @param  {number} arrDim\n */\nfunction catmullRomInterpolateArray(\n    p0, p1, p2, p3, t, t2, t3, out, arrDim\n) {\n    var len = p0.length;\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            out[i] = catmullRomInterpolate(\n                p0[i], p1[i], p2[i], p3[i], t, t2, t3\n            );\n        }\n    }\n    else {\n        var len2 = p0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                out[i][j] = catmullRomInterpolate(\n                    p0[i][j], p1[i][j], p2[i][j], p3[i][j],\n                    t, t2, t3\n                );\n            }\n        }\n    }\n}\n\n/**\n * Catmull Rom interpolate number\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @param  {number} t2\n * @param  {number} t3\n * @return {number}\n */\nfunction catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {\n    var v0 = (p2 - p0) * 0.5;\n    var v1 = (p3 - p1) * 0.5;\n    return (2 * (p1 - p2) + v0 + v1) * t3\n            + (-3 * (p1 - p2) - 2 * v0 - v1) * t2\n            + v0 * t + p1;\n}\n\nfunction cloneValue(value) {\n    if (isArrayLike(value)) {\n        var len = value.length;\n        if (isArrayLike(value[0])) {\n            var ret = [];\n            for (var i = 0; i < len; i++) {\n                ret.push(arraySlice.call(value[i]));\n            }\n            return ret;\n        }\n\n        return arraySlice.call(value);\n    }\n\n    return value;\n}\n\nfunction rgba2String(rgba) {\n    rgba[0] = Math.floor(rgba[0]);\n    rgba[1] = Math.floor(rgba[1]);\n    rgba[2] = Math.floor(rgba[2]);\n\n    return 'rgba(' + rgba.join(',') + ')';\n}\n\nfunction getArrayDim(keyframes) {\n    var lastValue = keyframes[keyframes.length - 1].value;\n    return isArrayLike(lastValue && lastValue[0]) ? 2 : 1;\n}\n\nfunction createTrackClip(animator, easing, oneTrackDone, keyframes, propName, forceAnimate) {\n    var getter = animator._getter;\n    var setter = animator._setter;\n    var useSpline = easing === 'spline';\n\n    var trackLen = keyframes.length;\n    if (!trackLen) {\n        return;\n    }\n    // Guess data type\n    var firstVal = keyframes[0].value;\n    var isValueArray = isArrayLike(firstVal);\n    var isValueColor = false;\n    var isValueString = false;\n\n    // For vertices morphing\n    var arrDim = isValueArray ? getArrayDim(keyframes) : 0;\n\n    var trackMaxTime;\n    // Sort keyframe as ascending\n    keyframes.sort(function (a, b) {\n        return a.time - b.time;\n    });\n\n    trackMaxTime = keyframes[trackLen - 1].time;\n    // Percents of each keyframe\n    var kfPercents = [];\n    // Value of each keyframe\n    var kfValues = [];\n    var prevValue = keyframes[0].value;\n    var isAllValueEqual = true;\n    for (var i = 0; i < trackLen; i++) {\n        kfPercents.push(keyframes[i].time / trackMaxTime);\n        // Assume value is a color when it is a string\n        var value = keyframes[i].value;\n\n        // Check if value is equal, deep check if value is array\n        if (!((isValueArray && isArraySame(value, prevValue, arrDim))\n            || (!isValueArray && value === prevValue))) {\n            isAllValueEqual = false;\n        }\n        prevValue = value;\n\n        // Try converting a string to a color array\n        if (typeof value === 'string') {\n            var colorArray = parse(value);\n            if (colorArray) {\n                value = colorArray;\n                isValueColor = true;\n            }\n            else {\n                isValueString = true;\n            }\n        }\n        kfValues.push(value);\n    }\n    if (!forceAnimate && isAllValueEqual) {\n        return;\n    }\n\n    var lastValue = kfValues[trackLen - 1];\n    // Polyfill array and NaN value\n    for (var i = 0; i < trackLen - 1; i++) {\n        if (isValueArray) {\n            fillArr(kfValues[i], lastValue, arrDim);\n        }\n        else {\n            if (isNaN(kfValues[i]) && !isNaN(lastValue) && !isValueString && !isValueColor) {\n                kfValues[i] = lastValue;\n            }\n        }\n    }\n    isValueArray && fillArr(getter(animator._target, propName), lastValue, arrDim);\n\n    // Cache the key of last frame to speed up when\n    // animation playback is sequency\n    var lastFrame = 0;\n    var lastFramePercent = 0;\n    var start;\n    var w;\n    var p0;\n    var p1;\n    var p2;\n    var p3;\n\n    if (isValueColor) {\n        var rgba = [0, 0, 0, 0];\n    }\n\n    var onframe = function (target, percent) {\n        // Find the range keyframes\n        // kf1-----kf2---------current--------kf3\n        // find kf2 and kf3 and do interpolation\n        var frame;\n        // In the easing function like elasticOut, percent may less than 0\n        if (percent < 0) {\n            frame = 0;\n        }\n        else if (percent < lastFramePercent) {\n            // Start from next key\n            // PENDING start from lastFrame ?\n            start = Math.min(lastFrame + 1, trackLen - 1);\n            for (frame = start; frame >= 0; frame--) {\n                if (kfPercents[frame] <= percent) {\n                    break;\n                }\n            }\n            // PENDING really need to do this ?\n            frame = Math.min(frame, trackLen - 2);\n        }\n        else {\n            for (frame = lastFrame; frame < trackLen; frame++) {\n                if (kfPercents[frame] > percent) {\n                    break;\n                }\n            }\n            frame = Math.min(frame - 1, trackLen - 2);\n        }\n        lastFrame = frame;\n        lastFramePercent = percent;\n\n        var range = (kfPercents[frame + 1] - kfPercents[frame]);\n        if (range === 0) {\n            return;\n        }\n        else {\n            w = (percent - kfPercents[frame]) / range;\n        }\n        if (useSpline) {\n            p1 = kfValues[frame];\n            p0 = kfValues[frame === 0 ? frame : frame - 1];\n            p2 = kfValues[frame > trackLen - 2 ? trackLen - 1 : frame + 1];\n            p3 = kfValues[frame > trackLen - 3 ? trackLen - 1 : frame + 2];\n            if (isValueArray) {\n                catmullRomInterpolateArray(\n                    p0, p1, p2, p3, w, w * w, w * w * w,\n                    getter(target, propName),\n                    arrDim\n                );\n            }\n            else {\n                var value;\n                if (isValueColor) {\n                    value = catmullRomInterpolateArray(\n                        p0, p1, p2, p3, w, w * w, w * w * w,\n                        rgba, 1\n                    );\n                    value = rgba2String(rgba);\n                }\n                else if (isValueString) {\n                    // String is step(0.5)\n                    return interpolateString(p1, p2, w);\n                }\n                else {\n                    value = catmullRomInterpolate(\n                        p0, p1, p2, p3, w, w * w, w * w * w\n                    );\n                }\n                setter(\n                    target,\n                    propName,\n                    value\n                );\n            }\n        }\n        else {\n            if (isValueArray) {\n                interpolateArray(\n                    kfValues[frame], kfValues[frame + 1], w,\n                    getter(target, propName),\n                    arrDim\n                );\n            }\n            else {\n                var value;\n                if (isValueColor) {\n                    interpolateArray(\n                        kfValues[frame], kfValues[frame + 1], w,\n                        rgba, 1\n                    );\n                    value = rgba2String(rgba);\n                }\n                else if (isValueString) {\n                    // String is step(0.5)\n                    return interpolateString(kfValues[frame], kfValues[frame + 1], w);\n                }\n                else {\n                    value = interpolateNumber(kfValues[frame], kfValues[frame + 1], w);\n                }\n                setter(\n                    target,\n                    propName,\n                    value\n                );\n            }\n        }\n    };\n\n    var clip = new Clip({\n        target: animator._target,\n        life: trackMaxTime,\n        loop: animator._loop,\n        delay: animator._delay,\n        onframe: onframe,\n        ondestroy: oneTrackDone\n    });\n\n    if (easing && easing !== 'spline') {\n        clip.easing = easing;\n    }\n\n    return clip;\n}\n\n/**\n * @alias module:zrender/animation/Animator\n * @constructor\n * @param {Object} target\n * @param {boolean} loop\n * @param {Function} getter\n * @param {Function} setter\n */\nvar Animator = function (target, loop, getter, setter) {\n    this._tracks = {};\n    this._target = target;\n\n    this._loop = loop || false;\n\n    this._getter = getter || defaultGetter;\n    this._setter = setter || defaultSetter;\n\n    this._clipCount = 0;\n\n    this._delay = 0;\n\n    this._doneList = [];\n\n    this._onframeList = [];\n\n    this._clipList = [];\n};\n\nAnimator.prototype = {\n    /**\n     * 设置动画关键帧\n     * @param  {number} time 关键帧时间，单位是ms\n     * @param  {Object} props 关键帧的属性值，key-value表示\n     * @return {module:zrender/animation/Animator}\n     */\n    when: function (time /* ms */, props) {\n        var tracks = this._tracks;\n        for (var propName in props) {\n            if (!props.hasOwnProperty(propName)) {\n                continue;\n            }\n\n            if (!tracks[propName]) {\n                tracks[propName] = [];\n                // Invalid value\n                var value = this._getter(this._target, propName);\n                if (value == null) {\n                    // zrLog('Invalid property ' + propName);\n                    continue;\n                }\n                // If time is 0\n                //  Then props is given initialize value\n                // Else\n                //  Initialize value from current prop value\n                if (time !== 0) {\n                    tracks[propName].push({\n                        time: 0,\n                        value: cloneValue(value)\n                    });\n                }\n            }\n            tracks[propName].push({\n                time: time,\n                value: props[propName]\n            });\n        }\n        return this;\n    },\n    /**\n     * 添加动画每一帧的回调函数\n     * @param  {Function} callback\n     * @return {module:zrender/animation/Animator}\n     */\n    during: function (callback) {\n        this._onframeList.push(callback);\n        return this;\n    },\n\n    pause: function () {\n        for (var i = 0; i < this._clipList.length; i++) {\n            this._clipList[i].pause();\n        }\n        this._paused = true;\n    },\n\n    resume: function () {\n        for (var i = 0; i < this._clipList.length; i++) {\n            this._clipList[i].resume();\n        }\n        this._paused = false;\n    },\n\n    isPaused: function () {\n        return !!this._paused;\n    },\n\n    _doneCallback: function () {\n        // Clear all tracks\n        this._tracks = {};\n        // Clear all clips\n        this._clipList.length = 0;\n\n        var doneList = this._doneList;\n        var len = doneList.length;\n        for (var i = 0; i < len; i++) {\n            doneList[i].call(this);\n        }\n    },\n    /**\n     * 开始执行动画\n     * @param  {string|Function} [easing]\n     *         动画缓动函数，详见{@link module:zrender/animation/easing}\n     * @param  {boolean} forceAnimate\n     * @return {module:zrender/animation/Animator}\n     */\n    start: function (easing, forceAnimate) {\n\n        var self = this;\n        var clipCount = 0;\n\n        var oneTrackDone = function () {\n            clipCount--;\n            if (!clipCount) {\n                self._doneCallback();\n            }\n        };\n\n        var lastClip;\n        for (var propName in this._tracks) {\n            if (!this._tracks.hasOwnProperty(propName)) {\n                continue;\n            }\n            var clip = createTrackClip(\n                this, easing, oneTrackDone,\n                this._tracks[propName], propName, forceAnimate\n            );\n            if (clip) {\n                this._clipList.push(clip);\n                clipCount++;\n\n                // If start after added to animation\n                if (this.animation) {\n                    this.animation.addClip(clip);\n                }\n\n                lastClip = clip;\n            }\n        }\n\n        // Add during callback on the last clip\n        if (lastClip) {\n            var oldOnFrame = lastClip.onframe;\n            lastClip.onframe = function (target, percent) {\n                oldOnFrame(target, percent);\n\n                for (var i = 0; i < self._onframeList.length; i++) {\n                    self._onframeList[i](target, percent);\n                }\n            };\n        }\n\n        // This optimization will help the case that in the upper application\n        // the view may be refreshed frequently, where animation will be\n        // called repeatly but nothing changed.\n        if (!clipCount) {\n            this._doneCallback();\n        }\n        return this;\n    },\n    /**\n     * 停止动画\n     * @param {boolean} forwardToLast If move to last frame before stop\n     */\n    stop: function (forwardToLast) {\n        var clipList = this._clipList;\n        var animation = this.animation;\n        for (var i = 0; i < clipList.length; i++) {\n            var clip = clipList[i];\n            if (forwardToLast) {\n                // Move to last frame before stop\n                clip.onframe(this._target, 1);\n            }\n            animation && animation.removeClip(clip);\n        }\n        clipList.length = 0;\n    },\n    /**\n     * 设置动画延迟开始的时间\n     * @param  {number} time 单位ms\n     * @return {module:zrender/animation/Animator}\n     */\n    delay: function (time) {\n        this._delay = time;\n        return this;\n    },\n    /**\n     * 添加动画结束的回调\n     * @param  {Function} cb\n     * @return {module:zrender/animation/Animator}\n     */\n    done: function (cb) {\n        if (cb) {\n            this._doneList.push(cb);\n        }\n        return this;\n    },\n\n    /**\n     * @return {Array.<module:zrender/animation/Clip>}\n     */\n    getClips: function () {\n        return this._clipList;\n    }\n};\n\nvar dpr = 1;\n\n// If in browser environment\nif (typeof window !== 'undefined') {\n    dpr = Math.max(window.devicePixelRatio || 1, 1);\n}\n\n/**\n * config默认配置项\n * @exports zrender/config\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n */\n\n/**\n * debug日志选项：catchBrushException为true下有效\n * 0 : 不生成debug数据，发布用\n * 1 : 异常抛出，调试用\n * 2 : 控制台输出，调试用\n */\nvar debugMode = 0;\n\n// retina 屏幕优化\nvar devicePixelRatio = dpr;\n\nvar log = function () {\n};\n\nif (debugMode === 1) {\n    log = function () {\n        for (var k in arguments) {\n            throw new Error(arguments[k]);\n        }\n    };\n}\nelse if (debugMode > 1) {\n    log = function () {\n        for (var k in arguments) {\n            console.log(arguments[k]);\n        }\n    };\n}\n\nvar zrLog = log;\n\n/**\n * @alias modue:zrender/mixin/Animatable\n * @constructor\n */\nvar Animatable = function () {\n\n    /**\n     * @type {Array.<module:zrender/animation/Animator>}\n     * @readOnly\n     */\n    this.animators = [];\n};\n\nAnimatable.prototype = {\n\n    constructor: Animatable,\n\n    /**\n     * 动画\n     *\n     * @param {string} path The path to fetch value from object, like 'a.b.c'.\n     * @param {boolean} [loop] Whether to loop animation.\n     * @return {module:zrender/animation/Animator}\n     * @example:\n     *     el.animate('style', false)\n     *         .when(1000, {x: 10} )\n     *         .done(function(){ // Animation done })\n     *         .start()\n     */\n    animate: function (path, loop) {\n        var target;\n        var animatingShape = false;\n        var el = this;\n        var zr = this.__zr;\n        if (path) {\n            var pathSplitted = path.split('.');\n            var prop = el;\n            // If animating shape\n            animatingShape = pathSplitted[0] === 'shape';\n            for (var i = 0, l = pathSplitted.length; i < l; i++) {\n                if (!prop) {\n                    continue;\n                }\n                prop = prop[pathSplitted[i]];\n            }\n            if (prop) {\n                target = prop;\n            }\n        }\n        else {\n            target = el;\n        }\n\n        if (!target) {\n            zrLog(\n                'Property \"'\n                + path\n                + '\" is not existed in element '\n                + el.id\n            );\n            return;\n        }\n\n        var animators = el.animators;\n\n        var animator = new Animator(target, loop);\n\n        animator.during(function (target) {\n            el.dirty(animatingShape);\n        })\n        .done(function () {\n            // FIXME Animator will not be removed if use `Animator#stop` to stop animation\n            animators.splice(indexOf(animators, animator), 1);\n        });\n\n        animators.push(animator);\n\n        // If animate after added to the zrender\n        if (zr) {\n            zr.animation.addAnimator(animator);\n        }\n\n        return animator;\n    },\n\n    /**\n     * 停止动画\n     * @param {boolean} forwardToLast If move to last frame before stop\n     */\n    stopAnimation: function (forwardToLast) {\n        var animators = this.animators;\n        var len = animators.length;\n        for (var i = 0; i < len; i++) {\n            animators[i].stop(forwardToLast);\n        }\n        animators.length = 0;\n\n        return this;\n    },\n\n    /**\n     * Caution: this method will stop previous animation.\n     * So do not use this method to one element twice before\n     * animation starts, unless you know what you are doing.\n     * @param {Object} target\n     * @param {number} [time=500] Time in ms\n     * @param {string} [easing='linear']\n     * @param {number} [delay=0]\n     * @param {Function} [callback]\n     * @param {Function} [forceAnimate] Prevent stop animation and callback\n     *        immediently when target values are the same as current values.\n     *\n     * @example\n     *  // Animate position\n     *  el.animateTo({\n     *      position: [10, 10]\n     *  }, function () { // done })\n     *\n     *  // Animate shape, style and position in 100ms, delayed 100ms, with cubicOut easing\n     *  el.animateTo({\n     *      shape: {\n     *          width: 500\n     *      },\n     *      style: {\n     *          fill: 'red'\n     *      }\n     *      position: [10, 10]\n     *  }, 100, 100, 'cubicOut', function () { // done })\n     */\n    // TODO Return animation key\n    animateTo: function (target, time, delay, easing, callback, forceAnimate) {\n        animateTo(this, target, time, delay, easing, callback, forceAnimate);\n    },\n\n    /**\n     * Animate from the target state to current state.\n     * The params and the return value are the same as `this.animateTo`.\n     */\n    animateFrom: function (target, time, delay, easing, callback, forceAnimate) {\n        animateTo(this, target, time, delay, easing, callback, forceAnimate, true);\n    }\n};\n\nfunction animateTo(animatable, target, time, delay, easing, callback, forceAnimate, reverse) {\n    // animateTo(target, time, easing, callback);\n    if (isString(delay)) {\n        callback = easing;\n        easing = delay;\n        delay = 0;\n    }\n    // animateTo(target, time, delay, callback);\n    else if (isFunction$1(easing)) {\n        callback = easing;\n        easing = 'linear';\n        delay = 0;\n    }\n    // animateTo(target, time, callback);\n    else if (isFunction$1(delay)) {\n        callback = delay;\n        delay = 0;\n    }\n    // animateTo(target, callback)\n    else if (isFunction$1(time)) {\n        callback = time;\n        time = 500;\n    }\n    // animateTo(target)\n    else if (!time) {\n        time = 500;\n    }\n    // Stop all previous animations\n    animatable.stopAnimation();\n    animateToShallow(animatable, '', animatable, target, time, delay, reverse);\n\n    // Animators may be removed immediately after start\n    // if there is nothing to animate\n    var animators = animatable.animators.slice();\n    var count = animators.length;\n    function done() {\n        count--;\n        if (!count) {\n            callback && callback();\n        }\n    }\n\n    // No animators. This should be checked before animators[i].start(),\n    // because 'done' may be executed immediately if no need to animate.\n    if (!count) {\n        callback && callback();\n    }\n    // Start after all animators created\n    // Incase any animator is done immediately when all animation properties are not changed\n    for (var i = 0; i < animators.length; i++) {\n        animators[i]\n            .done(done)\n            .start(easing, forceAnimate);\n    }\n}\n\n/**\n * @param {string} path=''\n * @param {Object} source=animatable\n * @param {Object} target\n * @param {number} [time=500]\n * @param {number} [delay=0]\n * @param {boolean} [reverse] If `true`, animate\n *        from the `target` to current state.\n *\n * @example\n *  // Animate position\n *  el._animateToShallow({\n *      position: [10, 10]\n *  })\n *\n *  // Animate shape, style and position in 100ms, delayed 100ms\n *  el._animateToShallow({\n *      shape: {\n *          width: 500\n *      },\n *      style: {\n *          fill: 'red'\n *      }\n *      position: [10, 10]\n *  }, 100, 100)\n */\nfunction animateToShallow(animatable, path, source, target, time, delay, reverse) {\n    var objShallow = {};\n    var propertyCount = 0;\n    for (var name in target) {\n        if (!target.hasOwnProperty(name)) {\n            continue;\n        }\n\n        if (source[name] != null) {\n            if (isObject$1(target[name]) && !isArrayLike(target[name])) {\n                animateToShallow(\n                    animatable,\n                    path ? path + '.' + name : name,\n                    source[name],\n                    target[name],\n                    time,\n                    delay,\n                    reverse\n                );\n            }\n            else {\n                if (reverse) {\n                    objShallow[name] = source[name];\n                    setAttrByPath(animatable, path, name, target[name]);\n                }\n                else {\n                    objShallow[name] = target[name];\n                }\n                propertyCount++;\n            }\n        }\n        else if (target[name] != null && !reverse) {\n            setAttrByPath(animatable, path, name, target[name]);\n        }\n    }\n\n    if (propertyCount > 0) {\n        animatable.animate(path, false)\n            .when(time == null ? 500 : time, objShallow)\n            .delay(delay || 0);\n    }\n}\n\nfunction setAttrByPath(el, path, name, value) {\n    // Attr directly if not has property\n    // FIXME, if some property not needed for element ?\n    if (!path) {\n        el.attr(name, value);\n    }\n    else {\n        // Only support set shape or style\n        var props = {};\n        props[path] = {};\n        props[path][name] = value;\n        el.attr(props);\n    }\n}\n\n/**\n * @alias module:zrender/Element\n * @constructor\n * @extends {module:zrender/mixin/Animatable}\n * @extends {module:zrender/mixin/Transformable}\n * @extends {module:zrender/mixin/Eventful}\n */\nvar Element = function (opts) { // jshint ignore:line\n\n    Transformable.call(this, opts);\n    Eventful.call(this, opts);\n    Animatable.call(this, opts);\n\n    /**\n     * 画布元素ID\n     * @type {string}\n     */\n    this.id = opts.id || guid();\n};\n\nElement.prototype = {\n\n    /**\n     * 元素类型\n     * Element type\n     * @type {string}\n     */\n    type: 'element',\n\n    /**\n     * 元素名字\n     * Element name\n     * @type {string}\n     */\n    name: '',\n\n    /**\n     * ZRender 实例对象，会在 element 添加到 zrender 实例中后自动赋值\n     * ZRender instance will be assigned when element is associated with zrender\n     * @name module:/zrender/Element#__zr\n     * @type {module:zrender/ZRender}\n     */\n    __zr: null,\n\n    /**\n     * 图形是否忽略，为true时忽略图形的绘制以及事件触发\n     * If ignore drawing and events of the element object\n     * @name module:/zrender/Element#ignore\n     * @type {boolean}\n     * @default false\n     */\n    ignore: false,\n\n    /**\n     * 用于裁剪的路径(shape)，所有 Group 内的路径在绘制时都会被这个路径裁剪\n     * 该路径会继承被裁减对象的变换\n     * @type {module:zrender/graphic/Path}\n     * @see http://www.w3.org/TR/2dcontext/#clipping-region\n     * @readOnly\n     */\n    clipPath: null,\n\n    /**\n     * 是否是 Group\n     * @type {boolean}\n     */\n    isGroup: false,\n\n    /**\n     * Drift element\n     * @param  {number} dx dx on the global space\n     * @param  {number} dy dy on the global space\n     */\n    drift: function (dx, dy) {\n        switch (this.draggable) {\n            case 'horizontal':\n                dy = 0;\n                break;\n            case 'vertical':\n                dx = 0;\n                break;\n        }\n\n        var m = this.transform;\n        if (!m) {\n            m = this.transform = [1, 0, 0, 1, 0, 0];\n        }\n        m[4] += dx;\n        m[5] += dy;\n\n        this.decomposeTransform();\n        this.dirty(false);\n    },\n\n    /**\n     * Hook before update\n     */\n    beforeUpdate: function () {},\n    /**\n     * Hook after update\n     */\n    afterUpdate: function () {},\n    /**\n     * Update each frame\n     */\n    update: function () {\n        this.updateTransform();\n    },\n\n    /**\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {},\n\n    /**\n     * @protected\n     */\n    attrKV: function (key, value) {\n        if (key === 'position' || key === 'scale' || key === 'origin') {\n            // Copy the array\n            if (value) {\n                var target = this[key];\n                if (!target) {\n                    target = this[key] = [];\n                }\n                target[0] = value[0];\n                target[1] = value[1];\n            }\n        }\n        else {\n            this[key] = value;\n        }\n    },\n\n    /**\n     * Hide the element\n     */\n    hide: function () {\n        this.ignore = true;\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * Show the element\n     */\n    show: function () {\n        this.ignore = false;\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * @param {string|Object} key\n     * @param {*} value\n     */\n    attr: function (key, value) {\n        if (typeof key === 'string') {\n            this.attrKV(key, value);\n        }\n        else if (isObject$1(key)) {\n            for (var name in key) {\n                if (key.hasOwnProperty(name)) {\n                    this.attrKV(name, key[name]);\n                }\n            }\n        }\n\n        this.dirty(false);\n\n        return this;\n    },\n\n    /**\n     * @param {module:zrender/graphic/Path} clipPath\n     */\n    setClipPath: function (clipPath) {\n        var zr = this.__zr;\n        if (zr) {\n            clipPath.addSelfToZr(zr);\n        }\n\n        // Remove previous clip path\n        if (this.clipPath && this.clipPath !== clipPath) {\n            this.removeClipPath();\n        }\n\n        this.clipPath = clipPath;\n        clipPath.__zr = zr;\n        clipPath.__clipTarget = this;\n\n        this.dirty(false);\n    },\n\n    /**\n     */\n    removeClipPath: function () {\n        var clipPath = this.clipPath;\n        if (clipPath) {\n            if (clipPath.__zr) {\n                clipPath.removeSelfFromZr(clipPath.__zr);\n            }\n\n            clipPath.__zr = null;\n            clipPath.__clipTarget = null;\n            this.clipPath = null;\n\n            this.dirty(false);\n        }\n    },\n\n    /**\n     * Add self from zrender instance.\n     * Not recursively because it will be invoked when element added to storage.\n     * @param {module:zrender/ZRender} zr\n     */\n    addSelfToZr: function (zr) {\n        this.__zr = zr;\n        // 添加动画\n        var animators = this.animators;\n        if (animators) {\n            for (var i = 0; i < animators.length; i++) {\n                zr.animation.addAnimator(animators[i]);\n            }\n        }\n\n        if (this.clipPath) {\n            this.clipPath.addSelfToZr(zr);\n        }\n    },\n\n    /**\n     * Remove self from zrender instance.\n     * Not recursively because it will be invoked when element added to storage.\n     * @param {module:zrender/ZRender} zr\n     */\n    removeSelfFromZr: function (zr) {\n        this.__zr = null;\n        // 移除动画\n        var animators = this.animators;\n        if (animators) {\n            for (var i = 0; i < animators.length; i++) {\n                zr.animation.removeAnimator(animators[i]);\n            }\n        }\n\n        if (this.clipPath) {\n            this.clipPath.removeSelfFromZr(zr);\n        }\n    }\n};\n\nmixin(Element, Animatable);\nmixin(Element, Transformable);\nmixin(Element, Eventful);\n\n/**\n * @module echarts/core/BoundingRect\n */\n\nvar v2ApplyTransform = applyTransform;\nvar mathMin = Math.min;\nvar mathMax = Math.max;\n\n/**\n * @alias module:echarts/core/BoundingRect\n */\nfunction BoundingRect(x, y, width, height) {\n\n    if (width < 0) {\n        x = x + width;\n        width = -width;\n    }\n    if (height < 0) {\n        y = y + height;\n        height = -height;\n    }\n\n    /**\n     * @type {number}\n     */\n    this.x = x;\n    /**\n     * @type {number}\n     */\n    this.y = y;\n    /**\n     * @type {number}\n     */\n    this.width = width;\n    /**\n     * @type {number}\n     */\n    this.height = height;\n}\n\nBoundingRect.prototype = {\n\n    constructor: BoundingRect,\n\n    /**\n     * @param {module:echarts/core/BoundingRect} other\n     */\n    union: function (other) {\n        var x = mathMin(other.x, this.x);\n        var y = mathMin(other.y, this.y);\n\n        this.width = mathMax(\n                other.x + other.width,\n                this.x + this.width\n            ) - x;\n        this.height = mathMax(\n                other.y + other.height,\n                this.y + this.height\n            ) - y;\n        this.x = x;\n        this.y = y;\n    },\n\n    /**\n     * @param {Array.<number>} m\n     * @methods\n     */\n    applyTransform: (function () {\n        var lt = [];\n        var rb = [];\n        var lb = [];\n        var rt = [];\n        return function (m) {\n            // In case usage like this\n            // el.getBoundingRect().applyTransform(el.transform)\n            // And element has no transform\n            if (!m) {\n                return;\n            }\n            lt[0] = lb[0] = this.x;\n            lt[1] = rt[1] = this.y;\n            rb[0] = rt[0] = this.x + this.width;\n            rb[1] = lb[1] = this.y + this.height;\n\n            v2ApplyTransform(lt, lt, m);\n            v2ApplyTransform(rb, rb, m);\n            v2ApplyTransform(lb, lb, m);\n            v2ApplyTransform(rt, rt, m);\n\n            this.x = mathMin(lt[0], rb[0], lb[0], rt[0]);\n            this.y = mathMin(lt[1], rb[1], lb[1], rt[1]);\n            var maxX = mathMax(lt[0], rb[0], lb[0], rt[0]);\n            var maxY = mathMax(lt[1], rb[1], lb[1], rt[1]);\n            this.width = maxX - this.x;\n            this.height = maxY - this.y;\n        };\n    })(),\n\n    /**\n     * Calculate matrix of transforming from self to target rect\n     * @param  {module:zrender/core/BoundingRect} b\n     * @return {Array.<number>}\n     */\n    calculateTransform: function (b) {\n        var a = this;\n        var sx = b.width / a.width;\n        var sy = b.height / a.height;\n\n        var m = create$1();\n\n        // 矩阵右乘\n        translate(m, m, [-a.x, -a.y]);\n        scale$1(m, m, [sx, sy]);\n        translate(m, m, [b.x, b.y]);\n\n        return m;\n    },\n\n    /**\n     * @param {(module:echarts/core/BoundingRect|Object)} b\n     * @return {boolean}\n     */\n    intersect: function (b) {\n        if (!b) {\n            return false;\n        }\n\n        if (!(b instanceof BoundingRect)) {\n            // Normalize negative width/height.\n            b = BoundingRect.create(b);\n        }\n\n        var a = this;\n        var ax0 = a.x;\n        var ax1 = a.x + a.width;\n        var ay0 = a.y;\n        var ay1 = a.y + a.height;\n\n        var bx0 = b.x;\n        var bx1 = b.x + b.width;\n        var by0 = b.y;\n        var by1 = b.y + b.height;\n\n        return !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);\n    },\n\n    contain: function (x, y) {\n        var rect = this;\n        return x >= rect.x\n            && x <= (rect.x + rect.width)\n            && y >= rect.y\n            && y <= (rect.y + rect.height);\n    },\n\n    /**\n     * @return {module:echarts/core/BoundingRect}\n     */\n    clone: function () {\n        return new BoundingRect(this.x, this.y, this.width, this.height);\n    },\n\n    /**\n     * Copy from another rect\n     */\n    copy: function (other) {\n        this.x = other.x;\n        this.y = other.y;\n        this.width = other.width;\n        this.height = other.height;\n    },\n\n    plain: function () {\n        return {\n            x: this.x,\n            y: this.y,\n            width: this.width,\n            height: this.height\n        };\n    }\n};\n\n/**\n * @param {Object|module:zrender/core/BoundingRect} rect\n * @param {number} rect.x\n * @param {number} rect.y\n * @param {number} rect.width\n * @param {number} rect.height\n * @return {module:zrender/core/BoundingRect}\n */\nBoundingRect.create = function (rect) {\n    return new BoundingRect(rect.x, rect.y, rect.width, rect.height);\n};\n\n/**\n * Group是一个容器，可以插入子节点，Group的变换也会被应用到子节点上\n * @module zrender/graphic/Group\n * @example\n *     var Group = require('zrender/container/Group');\n *     var Circle = require('zrender/graphic/shape/Circle');\n *     var g = new Group();\n *     g.position[0] = 100;\n *     g.position[1] = 100;\n *     g.add(new Circle({\n *         style: {\n *             x: 100,\n *             y: 100,\n *             r: 20,\n *         }\n *     }));\n *     zr.add(g);\n */\n\n/**\n * @alias module:zrender/graphic/Group\n * @constructor\n * @extends module:zrender/mixin/Transformable\n * @extends module:zrender/mixin/Eventful\n */\nvar Group = function (opts) {\n\n    opts = opts || {};\n\n    Element.call(this, opts);\n\n    for (var key in opts) {\n        if (opts.hasOwnProperty(key)) {\n            this[key] = opts[key];\n        }\n    }\n\n    this._children = [];\n\n    this.__storage = null;\n\n    this.__dirty = true;\n};\n\nGroup.prototype = {\n\n    constructor: Group,\n\n    isGroup: true,\n\n    /**\n     * @type {string}\n     */\n    type: 'group',\n\n    /**\n     * 所有子孙元素是否响应鼠标事件\n     * @name module:/zrender/container/Group#silent\n     * @type {boolean}\n     * @default false\n     */\n    silent: false,\n\n    /**\n     * @return {Array.<module:zrender/Element>}\n     */\n    children: function () {\n        return this._children.slice();\n    },\n\n    /**\n     * 获取指定 index 的儿子节点\n     * @param  {number} idx\n     * @return {module:zrender/Element}\n     */\n    childAt: function (idx) {\n        return this._children[idx];\n    },\n\n    /**\n     * 获取指定名字的儿子节点\n     * @param  {string} name\n     * @return {module:zrender/Element}\n     */\n    childOfName: function (name) {\n        var children = this._children;\n        for (var i = 0; i < children.length; i++) {\n            if (children[i].name === name) {\n                return children[i];\n            }\n            }\n    },\n\n    /**\n     * @return {number}\n     */\n    childCount: function () {\n        return this._children.length;\n    },\n\n    /**\n     * 添加子节点到最后\n     * @param {module:zrender/Element} child\n     */\n    add: function (child) {\n        if (child && child !== this && child.parent !== this) {\n\n            this._children.push(child);\n\n            this._doAdd(child);\n        }\n\n        return this;\n    },\n\n    /**\n     * 添加子节点在 nextSibling 之前\n     * @param {module:zrender/Element} child\n     * @param {module:zrender/Element} nextSibling\n     */\n    addBefore: function (child, nextSibling) {\n        if (child && child !== this && child.parent !== this\n            && nextSibling && nextSibling.parent === this) {\n\n            var children = this._children;\n            var idx = children.indexOf(nextSibling);\n\n            if (idx >= 0) {\n                children.splice(idx, 0, child);\n                this._doAdd(child);\n            }\n        }\n\n        return this;\n    },\n\n    _doAdd: function (child) {\n        if (child.parent) {\n            child.parent.remove(child);\n        }\n\n        child.parent = this;\n\n        var storage = this.__storage;\n        var zr = this.__zr;\n        if (storage && storage !== child.__storage) {\n\n            storage.addToStorage(child);\n\n            if (child instanceof Group) {\n                child.addChildrenToStorage(storage);\n            }\n        }\n\n        zr && zr.refresh();\n    },\n\n    /**\n     * 移除子节点\n     * @param {module:zrender/Element} child\n     */\n    remove: function (child) {\n        var zr = this.__zr;\n        var storage = this.__storage;\n        var children = this._children;\n\n        var idx = indexOf(children, child);\n        if (idx < 0) {\n            return this;\n        }\n        children.splice(idx, 1);\n\n        child.parent = null;\n\n        if (storage) {\n\n            storage.delFromStorage(child);\n\n            if (child instanceof Group) {\n                child.delChildrenFromStorage(storage);\n            }\n        }\n\n        zr && zr.refresh();\n\n        return this;\n    },\n\n    /**\n     * 移除所有子节点\n     */\n    removeAll: function () {\n        var children = this._children;\n        var storage = this.__storage;\n        var child;\n        var i;\n        for (i = 0; i < children.length; i++) {\n            child = children[i];\n            if (storage) {\n                storage.delFromStorage(child);\n                if (child instanceof Group) {\n                    child.delChildrenFromStorage(storage);\n                }\n            }\n            child.parent = null;\n        }\n        children.length = 0;\n\n        return this;\n    },\n\n    /**\n     * 遍历所有子节点\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    eachChild: function (cb, context) {\n        var children = this._children;\n        for (var i = 0; i < children.length; i++) {\n            var child = children[i];\n            cb.call(context, child, i);\n        }\n        return this;\n    },\n\n    /**\n     * 深度优先遍历所有子孙节点\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            cb.call(context, child);\n\n            if (child.type === 'group') {\n                child.traverse(cb, context);\n            }\n        }\n        return this;\n    },\n\n    addChildrenToStorage: function (storage) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            storage.addToStorage(child);\n            if (child instanceof Group) {\n                child.addChildrenToStorage(storage);\n            }\n        }\n    },\n\n    delChildrenFromStorage: function (storage) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            storage.delFromStorage(child);\n            if (child instanceof Group) {\n                child.delChildrenFromStorage(storage);\n            }\n        }\n    },\n\n    dirty: function () {\n        this.__dirty = true;\n        this.__zr && this.__zr.refresh();\n        return this;\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function (includeChildren) {\n        // TODO Caching\n        var rect = null;\n        var tmpRect = new BoundingRect(0, 0, 0, 0);\n        var children = includeChildren || this._children;\n        var tmpMat = [];\n\n        for (var i = 0; i < children.length; i++) {\n            var child = children[i];\n            if (child.ignore || child.invisible) {\n                continue;\n            }\n\n            var childRect = child.getBoundingRect();\n            var transform = child.getLocalTransform(tmpMat);\n            // TODO\n            // The boundingRect cacluated by transforming original\n            // rect may be bigger than the actual bundingRect when rotation\n            // is used. (Consider a circle rotated aginst its center, where\n            // the actual boundingRect should be the same as that not be\n            // rotated.) But we can not find better approach to calculate\n            // actual boundingRect yet, considering performance.\n            if (transform) {\n                tmpRect.copy(childRect);\n                tmpRect.applyTransform(transform);\n                rect = rect || tmpRect.clone();\n                rect.union(tmpRect);\n            }\n            else {\n                rect = rect || childRect.clone();\n                rect.union(childRect);\n            }\n        }\n        return rect || tmpRect;\n    }\n};\n\ninherits(Group, Element);\n\n// https://github.com/mziccard/node-timsort\nvar DEFAULT_MIN_MERGE = 32;\n\nvar DEFAULT_MIN_GALLOPING = 7;\n\nfunction minRunLength(n) {\n    var r = 0;\n\n    while (n >= DEFAULT_MIN_MERGE) {\n        r |= n & 1;\n        n >>= 1;\n    }\n\n    return n + r;\n}\n\nfunction makeAscendingRun(array, lo, hi, compare) {\n    var runHi = lo + 1;\n\n    if (runHi === hi) {\n        return 1;\n    }\n\n    if (compare(array[runHi++], array[lo]) < 0) {\n        while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {\n            runHi++;\n        }\n\n        reverseRun(array, lo, runHi);\n    }\n    else {\n        while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {\n            runHi++;\n        }\n    }\n\n    return runHi - lo;\n}\n\nfunction reverseRun(array, lo, hi) {\n    hi--;\n\n    while (lo < hi) {\n        var t = array[lo];\n        array[lo++] = array[hi];\n        array[hi--] = t;\n    }\n}\n\nfunction binaryInsertionSort(array, lo, hi, start, compare) {\n    if (start === lo) {\n        start++;\n    }\n\n    for (; start < hi; start++) {\n        var pivot = array[start];\n\n        var left = lo;\n        var right = start;\n        var mid;\n\n        while (left < right) {\n            mid = left + right >>> 1;\n\n            if (compare(pivot, array[mid]) < 0) {\n                right = mid;\n            }\n            else {\n                left = mid + 1;\n            }\n        }\n\n        var n = start - left;\n\n        switch (n) {\n            case 3:\n                array[left + 3] = array[left + 2];\n\n            case 2:\n                array[left + 2] = array[left + 1];\n\n            case 1:\n                array[left + 1] = array[left];\n                break;\n            default:\n                while (n > 0) {\n                    array[left + n] = array[left + n - 1];\n                    n--;\n                }\n        }\n\n        array[left] = pivot;\n    }\n}\n\nfunction gallopLeft(value, array, start, length, hint, compare) {\n    var lastOffset = 0;\n    var maxOffset = 0;\n    var offset = 1;\n\n    if (compare(value, array[start + hint]) > 0) {\n        maxOffset = length - hint;\n\n        while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        lastOffset += hint;\n        offset += hint;\n    }\n    else {\n        maxOffset = hint + 1;\n        while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        var tmp = lastOffset;\n        lastOffset = hint - offset;\n        offset = hint - tmp;\n    }\n\n    lastOffset++;\n    while (lastOffset < offset) {\n        var m = lastOffset + (offset - lastOffset >>> 1);\n\n        if (compare(value, array[start + m]) > 0) {\n            lastOffset = m + 1;\n        }\n        else {\n            offset = m;\n        }\n    }\n    return offset;\n}\n\nfunction gallopRight(value, array, start, length, hint, compare) {\n    var lastOffset = 0;\n    var maxOffset = 0;\n    var offset = 1;\n\n    if (compare(value, array[start + hint]) < 0) {\n        maxOffset = hint + 1;\n\n        while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        var tmp = lastOffset;\n        lastOffset = hint - offset;\n        offset = hint - tmp;\n    }\n    else {\n        maxOffset = length - hint;\n\n        while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        lastOffset += hint;\n        offset += hint;\n    }\n\n    lastOffset++;\n\n    while (lastOffset < offset) {\n        var m = lastOffset + (offset - lastOffset >>> 1);\n\n        if (compare(value, array[start + m]) < 0) {\n            offset = m;\n        }\n        else {\n            lastOffset = m + 1;\n        }\n    }\n\n    return offset;\n}\n\nfunction TimSort(array, compare) {\n    var minGallop = DEFAULT_MIN_GALLOPING;\n    var runStart;\n    var runLength;\n    var stackSize = 0;\n\n    var tmp = [];\n\n    runStart = [];\n    runLength = [];\n\n    function pushRun(_runStart, _runLength) {\n        runStart[stackSize] = _runStart;\n        runLength[stackSize] = _runLength;\n        stackSize += 1;\n    }\n\n    function mergeRuns() {\n        while (stackSize > 1) {\n            var n = stackSize - 2;\n\n            if (n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1] || n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1]) {\n                if (runLength[n - 1] < runLength[n + 1]) {\n                    n--;\n                }\n            }\n            else if (runLength[n] > runLength[n + 1]) {\n                break;\n            }\n            mergeAt(n);\n        }\n    }\n\n    function forceMergeRuns() {\n        while (stackSize > 1) {\n            var n = stackSize - 2;\n\n            if (n > 0 && runLength[n - 1] < runLength[n + 1]) {\n                n--;\n            }\n\n            mergeAt(n);\n        }\n    }\n\n    function mergeAt(i) {\n        var start1 = runStart[i];\n        var length1 = runLength[i];\n        var start2 = runStart[i + 1];\n        var length2 = runLength[i + 1];\n\n        runLength[i] = length1 + length2;\n\n        if (i === stackSize - 3) {\n            runStart[i + 1] = runStart[i + 2];\n            runLength[i + 1] = runLength[i + 2];\n        }\n\n        stackSize--;\n\n        var k = gallopRight(array[start2], array, start1, length1, 0, compare);\n        start1 += k;\n        length1 -= k;\n\n        if (length1 === 0) {\n            return;\n        }\n\n        length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);\n\n        if (length2 === 0) {\n            return;\n        }\n\n        if (length1 <= length2) {\n            mergeLow(start1, length1, start2, length2);\n        }\n        else {\n            mergeHigh(start1, length1, start2, length2);\n        }\n    }\n\n    function mergeLow(start1, length1, start2, length2) {\n        var i = 0;\n\n        for (i = 0; i < length1; i++) {\n            tmp[i] = array[start1 + i];\n        }\n\n        var cursor1 = 0;\n        var cursor2 = start2;\n        var dest = start1;\n\n        array[dest++] = array[cursor2++];\n\n        if (--length2 === 0) {\n            for (i = 0; i < length1; i++) {\n                array[dest + i] = tmp[cursor1 + i];\n            }\n            return;\n        }\n\n        if (length1 === 1) {\n            for (i = 0; i < length2; i++) {\n                array[dest + i] = array[cursor2 + i];\n            }\n            array[dest + length2] = tmp[cursor1];\n            return;\n        }\n\n        var _minGallop = minGallop;\n        var count1, count2, exit;\n\n        while (1) {\n            count1 = 0;\n            count2 = 0;\n            exit = false;\n\n            do {\n                if (compare(array[cursor2], tmp[cursor1]) < 0) {\n                    array[dest++] = array[cursor2++];\n                    count2++;\n                    count1 = 0;\n\n                    if (--length2 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                else {\n                    array[dest++] = tmp[cursor1++];\n                    count1++;\n                    count2 = 0;\n                    if (--length1 === 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n            } while ((count1 | count2) < _minGallop);\n\n            if (exit) {\n                break;\n            }\n\n            do {\n                count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);\n\n                if (count1 !== 0) {\n                    for (i = 0; i < count1; i++) {\n                        array[dest + i] = tmp[cursor1 + i];\n                    }\n\n                    dest += count1;\n                    cursor1 += count1;\n                    length1 -= count1;\n                    if (length1 <= 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest++] = array[cursor2++];\n\n                if (--length2 === 0) {\n                    exit = true;\n                    break;\n                }\n\n                count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);\n\n                if (count2 !== 0) {\n                    for (i = 0; i < count2; i++) {\n                        array[dest + i] = array[cursor2 + i];\n                    }\n\n                    dest += count2;\n                    cursor2 += count2;\n                    length2 -= count2;\n\n                    if (length2 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                array[dest++] = tmp[cursor1++];\n\n                if (--length1 === 1) {\n                    exit = true;\n                    break;\n                }\n\n                _minGallop--;\n            } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);\n\n            if (exit) {\n                break;\n            }\n\n            if (_minGallop < 0) {\n                _minGallop = 0;\n            }\n\n            _minGallop += 2;\n        }\n\n        minGallop = _minGallop;\n\n        minGallop < 1 && (minGallop = 1);\n\n        if (length1 === 1) {\n            for (i = 0; i < length2; i++) {\n                array[dest + i] = array[cursor2 + i];\n            }\n            array[dest + length2] = tmp[cursor1];\n        }\n        else if (length1 === 0) {\n            throw new Error();\n            // throw new Error('mergeLow preconditions were not respected');\n        }\n        else {\n            for (i = 0; i < length1; i++) {\n                array[dest + i] = tmp[cursor1 + i];\n            }\n        }\n    }\n\n    function mergeHigh(start1, length1, start2, length2) {\n        var i = 0;\n\n        for (i = 0; i < length2; i++) {\n            tmp[i] = array[start2 + i];\n        }\n\n        var cursor1 = start1 + length1 - 1;\n        var cursor2 = length2 - 1;\n        var dest = start2 + length2 - 1;\n        var customCursor = 0;\n        var customDest = 0;\n\n        array[dest--] = array[cursor1--];\n\n        if (--length1 === 0) {\n            customCursor = dest - (length2 - 1);\n\n            for (i = 0; i < length2; i++) {\n                array[customCursor + i] = tmp[i];\n            }\n\n            return;\n        }\n\n        if (length2 === 1) {\n            dest -= length1;\n            cursor1 -= length1;\n            customDest = dest + 1;\n            customCursor = cursor1 + 1;\n\n            for (i = length1 - 1; i >= 0; i--) {\n                array[customDest + i] = array[customCursor + i];\n            }\n\n            array[dest] = tmp[cursor2];\n            return;\n        }\n\n        var _minGallop = minGallop;\n\n        while (true) {\n            var count1 = 0;\n            var count2 = 0;\n            var exit = false;\n\n            do {\n                if (compare(tmp[cursor2], array[cursor1]) < 0) {\n                    array[dest--] = array[cursor1--];\n                    count1++;\n                    count2 = 0;\n                    if (--length1 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                else {\n                    array[dest--] = tmp[cursor2--];\n                    count2++;\n                    count1 = 0;\n                    if (--length2 === 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n            } while ((count1 | count2) < _minGallop);\n\n            if (exit) {\n                break;\n            }\n\n            do {\n                count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);\n\n                if (count1 !== 0) {\n                    dest -= count1;\n                    cursor1 -= count1;\n                    length1 -= count1;\n                    customDest = dest + 1;\n                    customCursor = cursor1 + 1;\n\n                    for (i = count1 - 1; i >= 0; i--) {\n                        array[customDest + i] = array[customCursor + i];\n                    }\n\n                    if (length1 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest--] = tmp[cursor2--];\n\n                if (--length2 === 1) {\n                    exit = true;\n                    break;\n                }\n\n                count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);\n\n                if (count2 !== 0) {\n                    dest -= count2;\n                    cursor2 -= count2;\n                    length2 -= count2;\n                    customDest = dest + 1;\n                    customCursor = cursor2 + 1;\n\n                    for (i = 0; i < count2; i++) {\n                        array[customDest + i] = tmp[customCursor + i];\n                    }\n\n                    if (length2 <= 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest--] = array[cursor1--];\n\n                if (--length1 === 0) {\n                    exit = true;\n                    break;\n                }\n\n                _minGallop--;\n            } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);\n\n            if (exit) {\n                break;\n            }\n\n            if (_minGallop < 0) {\n                _minGallop = 0;\n            }\n\n            _minGallop += 2;\n        }\n\n        minGallop = _minGallop;\n\n        if (minGallop < 1) {\n            minGallop = 1;\n        }\n\n        if (length2 === 1) {\n            dest -= length1;\n            cursor1 -= length1;\n            customDest = dest + 1;\n            customCursor = cursor1 + 1;\n\n            for (i = length1 - 1; i >= 0; i--) {\n                array[customDest + i] = array[customCursor + i];\n            }\n\n            array[dest] = tmp[cursor2];\n        }\n        else if (length2 === 0) {\n            throw new Error();\n            // throw new Error('mergeHigh preconditions were not respected');\n        }\n        else {\n            customCursor = dest - (length2 - 1);\n            for (i = 0; i < length2; i++) {\n                array[customCursor + i] = tmp[i];\n            }\n        }\n    }\n\n    this.mergeRuns = mergeRuns;\n    this.forceMergeRuns = forceMergeRuns;\n    this.pushRun = pushRun;\n}\n\nfunction sort(array, compare, lo, hi) {\n    if (!lo) {\n        lo = 0;\n    }\n    if (!hi) {\n        hi = array.length;\n    }\n\n    var remaining = hi - lo;\n\n    if (remaining < 2) {\n        return;\n    }\n\n    var runLength = 0;\n\n    if (remaining < DEFAULT_MIN_MERGE) {\n        runLength = makeAscendingRun(array, lo, hi, compare);\n        binaryInsertionSort(array, lo, hi, lo + runLength, compare);\n        return;\n    }\n\n    var ts = new TimSort(array, compare);\n\n    var minRun = minRunLength(remaining);\n\n    do {\n        runLength = makeAscendingRun(array, lo, hi, compare);\n        if (runLength < minRun) {\n            var force = remaining;\n            if (force > minRun) {\n                force = minRun;\n            }\n\n            binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);\n            runLength = force;\n        }\n\n        ts.pushRun(lo, runLength);\n        ts.mergeRuns();\n\n        remaining -= runLength;\n        lo += runLength;\n    } while (remaining !== 0);\n\n    ts.forceMergeRuns();\n}\n\n// Use timsort because in most case elements are partially sorted\n// https://jsfiddle.net/pissang/jr4x7mdm/8/\nfunction shapeCompareFunc(a, b) {\n    if (a.zlevel === b.zlevel) {\n        if (a.z === b.z) {\n            // if (a.z2 === b.z2) {\n            //     // FIXME Slow has renderidx compare\n            //     // http://stackoverflow.com/questions/20883421/sorting-in-javascript-should-every-compare-function-have-a-return-0-statement\n            //     // https://github.com/v8/v8/blob/47cce544a31ed5577ffe2963f67acb4144ee0232/src/js/array.js#L1012\n            //     return a.__renderidx - b.__renderidx;\n            // }\n            return a.z2 - b.z2;\n        }\n        return a.z - b.z;\n    }\n    return a.zlevel - b.zlevel;\n}\n/**\n * 内容仓库 (M)\n * @alias module:zrender/Storage\n * @constructor\n */\nvar Storage = function () { // jshint ignore:line\n    this._roots = [];\n\n    this._displayList = [];\n\n    this._displayListLen = 0;\n};\n\nStorage.prototype = {\n\n    constructor: Storage,\n\n    /**\n     * @param  {Function} cb\n     *\n     */\n    traverse: function (cb, context) {\n        for (var i = 0; i < this._roots.length; i++) {\n            this._roots[i].traverse(cb, context);\n        }\n    },\n\n    /**\n     * 返回所有图形的绘制队列\n     * @param {boolean} [update=false] 是否在返回前更新该数组\n     * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组, 在 update 为 true 的时候有效\n     *\n     * 详见{@link module:zrender/graphic/Displayable.prototype.updateDisplayList}\n     * @return {Array.<module:zrender/graphic/Displayable>}\n     */\n    getDisplayList: function (update, includeIgnore) {\n        includeIgnore = includeIgnore || false;\n        if (update) {\n            this.updateDisplayList(includeIgnore);\n        }\n        return this._displayList;\n    },\n\n    /**\n     * 更新图形的绘制队列。\n     * 每次绘制前都会调用，该方法会先深度优先遍历整个树，更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中，\n     * 最后根据绘制的优先级（zlevel > z > 插入顺序）排序得到绘制队列\n     * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组\n     */\n    updateDisplayList: function (includeIgnore) {\n        this._displayListLen = 0;\n\n        var roots = this._roots;\n        var displayList = this._displayList;\n        for (var i = 0, len = roots.length; i < len; i++) {\n            this._updateAndAddDisplayable(roots[i], null, includeIgnore);\n        }\n\n        displayList.length = this._displayListLen;\n\n        env$1.canvasSupported && sort(displayList, shapeCompareFunc);\n    },\n\n    _updateAndAddDisplayable: function (el, clipPaths, includeIgnore) {\n\n        if (el.ignore && !includeIgnore) {\n            return;\n        }\n\n        el.beforeUpdate();\n\n        if (el.__dirty) {\n\n            el.update();\n\n        }\n\n        el.afterUpdate();\n\n        var userSetClipPath = el.clipPath;\n        if (userSetClipPath) {\n\n            // FIXME 效率影响\n            if (clipPaths) {\n                clipPaths = clipPaths.slice();\n            }\n            else {\n                clipPaths = [];\n            }\n\n            var currentClipPath = userSetClipPath;\n            var parentClipPath = el;\n            // Recursively add clip path\n            while (currentClipPath) {\n                // clipPath 的变换是基于使用这个 clipPath 的元素\n                currentClipPath.parent = parentClipPath;\n                currentClipPath.updateTransform();\n\n                clipPaths.push(currentClipPath);\n\n                parentClipPath = currentClipPath;\n                currentClipPath = currentClipPath.clipPath;\n            }\n        }\n\n        if (el.isGroup) {\n            var children = el._children;\n\n            for (var i = 0; i < children.length; i++) {\n                var child = children[i];\n\n                // Force to mark as dirty if group is dirty\n                // FIXME __dirtyPath ?\n                if (el.__dirty) {\n                    child.__dirty = true;\n                }\n\n                this._updateAndAddDisplayable(child, clipPaths, includeIgnore);\n            }\n\n            // Mark group clean here\n            el.__dirty = false;\n\n        }\n        else {\n            el.__clipPaths = clipPaths;\n\n            this._displayList[this._displayListLen++] = el;\n        }\n    },\n\n    /**\n     * 添加图形(Shape)或者组(Group)到根节点\n     * @param {module:zrender/Element} el\n     */\n    addRoot: function (el) {\n        if (el.__storage === this) {\n            return;\n        }\n\n        if (el instanceof Group) {\n            el.addChildrenToStorage(this);\n        }\n\n        this.addToStorage(el);\n        this._roots.push(el);\n    },\n\n    /**\n     * 删除指定的图形(Shape)或者组(Group)\n     * @param {string|Array.<string>} [el] 如果为空清空整个Storage\n     */\n    delRoot: function (el) {\n        if (el == null) {\n            // 不指定el清空\n            for (var i = 0; i < this._roots.length; i++) {\n                var root = this._roots[i];\n                if (root instanceof Group) {\n                    root.delChildrenFromStorage(this);\n                }\n            }\n\n            this._roots = [];\n            this._displayList = [];\n            this._displayListLen = 0;\n\n            return;\n        }\n\n        if (el instanceof Array) {\n            for (var i = 0, l = el.length; i < l; i++) {\n                this.delRoot(el[i]);\n            }\n            return;\n        }\n\n\n        var idx = indexOf(this._roots, el);\n        if (idx >= 0) {\n            this.delFromStorage(el);\n            this._roots.splice(idx, 1);\n            if (el instanceof Group) {\n                el.delChildrenFromStorage(this);\n            }\n        }\n    },\n\n    addToStorage: function (el) {\n        if (el) {\n            el.__storage = this;\n            el.dirty(false);\n        }\n        return this;\n    },\n\n    delFromStorage: function (el) {\n        if (el) {\n            el.__storage = null;\n        }\n\n        return this;\n    },\n\n    /**\n     * 清空并且释放Storage\n     */\n    dispose: function () {\n        this._renderList =\n        this._roots = null;\n    },\n\n    displayableSortFunc: shapeCompareFunc\n};\n\nvar SHADOW_PROPS = {\n    'shadowBlur': 1,\n    'shadowOffsetX': 1,\n    'shadowOffsetY': 1,\n    'textShadowBlur': 1,\n    'textShadowOffsetX': 1,\n    'textShadowOffsetY': 1,\n    'textBoxShadowBlur': 1,\n    'textBoxShadowOffsetX': 1,\n    'textBoxShadowOffsetY': 1\n};\n\nvar fixShadow = function (ctx, propName, value) {\n    if (SHADOW_PROPS.hasOwnProperty(propName)) {\n        return value *= ctx.dpr;\n    }\n    return value;\n};\n\nvar ContextCachedBy = {\n    NONE: 0,\n    STYLE_BIND: 1,\n    PLAIN_TEXT: 2\n};\n\n// Avoid confused with 0/false.\nvar WILL_BE_RESTORED = 9;\n\nvar STYLE_COMMON_PROPS = [\n    ['shadowBlur', 0], ['shadowOffsetX', 0], ['shadowOffsetY', 0], ['shadowColor', '#000'],\n    ['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]\n];\n\n// var SHADOW_PROPS = STYLE_COMMON_PROPS.slice(0, 4);\n// var LINE_PROPS = STYLE_COMMON_PROPS.slice(4);\n\nvar Style = function (opts) {\n    this.extendFrom(opts, false);\n};\n\nfunction createLinearGradient(ctx, obj, rect) {\n    var x = obj.x == null ? 0 : obj.x;\n    var x2 = obj.x2 == null ? 1 : obj.x2;\n    var y = obj.y == null ? 0 : obj.y;\n    var y2 = obj.y2 == null ? 0 : obj.y2;\n\n    if (!obj.global) {\n        x = x * rect.width + rect.x;\n        x2 = x2 * rect.width + rect.x;\n        y = y * rect.height + rect.y;\n        y2 = y2 * rect.height + rect.y;\n    }\n\n    // Fix NaN when rect is Infinity\n    x = isNaN(x) ? 0 : x;\n    x2 = isNaN(x2) ? 1 : x2;\n    y = isNaN(y) ? 0 : y;\n    y2 = isNaN(y2) ? 0 : y2;\n\n    var canvasGradient = ctx.createLinearGradient(x, y, x2, y2);\n\n    return canvasGradient;\n}\n\nfunction createRadialGradient(ctx, obj, rect) {\n    var width = rect.width;\n    var height = rect.height;\n    var min = Math.min(width, height);\n\n    var x = obj.x == null ? 0.5 : obj.x;\n    var y = obj.y == null ? 0.5 : obj.y;\n    var r = obj.r == null ? 0.5 : obj.r;\n    if (!obj.global) {\n        x = x * width + rect.x;\n        y = y * height + rect.y;\n        r = r * min;\n    }\n\n    var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r);\n\n    return canvasGradient;\n}\n\n\nStyle.prototype = {\n\n    constructor: Style,\n\n    /**\n     * @type {string}\n     */\n    fill: '#000',\n\n    /**\n     * @type {string}\n     */\n    stroke: null,\n\n    /**\n     * @type {number}\n     */\n    opacity: 1,\n\n    /**\n     * @type {number}\n     */\n    fillOpacity: null,\n\n    /**\n     * @type {number}\n     */\n    strokeOpacity: null,\n\n    /**\n     * @type {Array.<number>}\n     */\n    lineDash: null,\n\n    /**\n     * @type {number}\n     */\n    lineDashOffset: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowOffsetY: 0,\n\n    /**\n     * @type {number}\n     */\n    lineWidth: 1,\n\n    /**\n     * If stroke ignore scale\n     * @type {Boolean}\n     */\n    strokeNoScale: false,\n\n    // Bounding rect text configuration\n    // Not affected by element transform\n    /**\n     * @type {string}\n     */\n    text: null,\n\n    /**\n     * If `fontSize` or `fontFamily` exists, `font` will be reset by\n     * `fontSize`, `fontStyle`, `fontWeight`, `fontFamily`.\n     * So do not visit it directly in upper application (like echarts),\n     * but use `contain/text#makeFont` instead.\n     * @type {string}\n     */\n    font: null,\n\n    /**\n     * The same as font. Use font please.\n     * @deprecated\n     * @type {string}\n     */\n    textFont: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontStyle: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontWeight: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * Should be 12 but not '12px'.\n     * @type {number}\n     */\n    fontSize: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontFamily: null,\n\n    /**\n     * Reserved for special functinality, like 'hr'.\n     * @type {string}\n     */\n    textTag: null,\n\n    /**\n     * @type {string}\n     */\n    textFill: '#000',\n\n    /**\n     * @type {string}\n     */\n    textStroke: null,\n\n    /**\n     * @type {number}\n     */\n    textWidth: null,\n\n    /**\n     * Only for textBackground.\n     * @type {number}\n     */\n    textHeight: null,\n\n    /**\n     * textStroke may be set as some color as a default\n     * value in upper applicaion, where the default value\n     * of textStrokeWidth should be 0 to make sure that\n     * user can choose to do not use text stroke.\n     * @type {number}\n     */\n    textStrokeWidth: 0,\n\n    /**\n     * @type {number}\n     */\n    textLineHeight: null,\n\n    /**\n     * 'inside', 'left', 'right', 'top', 'bottom'\n     * [x, y]\n     * Based on x, y of rect.\n     * @type {string|Array.<number>}\n     * @default 'inside'\n     */\n    textPosition: 'inside',\n\n    /**\n     * If not specified, use the boundingRect of a `displayable`.\n     * @type {Object}\n     */\n    textRect: null,\n\n    /**\n     * [x, y]\n     * @type {Array.<number>}\n     */\n    textOffset: null,\n\n    /**\n     * @type {string}\n     */\n    textAlign: null,\n\n    /**\n     * @type {string}\n     */\n    textVerticalAlign: null,\n\n    /**\n     * @type {number}\n     */\n    textDistance: 5,\n\n    /**\n     * @type {string}\n     */\n    textShadowColor: 'transparent',\n\n    /**\n     * @type {number}\n     */\n    textShadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    textShadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    textShadowOffsetY: 0,\n\n    /**\n     * @type {string}\n     */\n    textBoxShadowColor: 'transparent',\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowOffsetY: 0,\n\n    /**\n     * Whether transform text.\n     * Only useful in Path and Image element\n     * @type {boolean}\n     */\n    transformText: false,\n\n    /**\n     * Text rotate around position of Path or Image\n     * Only useful in Path and Image element and transformText is false.\n     */\n    textRotation: 0,\n\n    /**\n     * Text origin of text rotation, like [10, 40].\n     * Based on x, y of rect.\n     * Useful in label rotation of circular symbol.\n     * By default, this origin is textPosition.\n     * Can be 'center'.\n     * @type {string|Array.<number>}\n     */\n    textOrigin: null,\n\n    /**\n     * @type {string}\n     */\n    textBackgroundColor: null,\n\n    /**\n     * @type {string}\n     */\n    textBorderColor: null,\n\n    /**\n     * @type {number}\n     */\n    textBorderWidth: 0,\n\n    /**\n     * @type {number}\n     */\n    textBorderRadius: 0,\n\n    /**\n     * Can be `2` or `[2, 4]` or `[2, 3, 4, 5]`\n     * @type {number|Array.<number>}\n     */\n    textPadding: null,\n\n    /**\n     * Text styles for rich text.\n     * @type {Object}\n     */\n    rich: null,\n\n    /**\n     * {outerWidth, outerHeight, ellipsis, placeholder}\n     * @type {Object}\n     */\n    truncate: null,\n\n    /**\n     * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation\n     * @type {string}\n     */\n    blend: null,\n\n    /**\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    bind: function (ctx, el, prevEl) {\n        var style = this;\n        var prevStyle = prevEl && prevEl.style;\n        // If no prevStyle, it means first draw.\n        // Only apply cache if the last time cachced by this function.\n        var notCheckCache = !prevStyle || ctx.__attrCachedBy !== ContextCachedBy.STYLE_BIND;\n\n        ctx.__attrCachedBy = ContextCachedBy.STYLE_BIND;\n\n        for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {\n            var prop = STYLE_COMMON_PROPS[i];\n            var styleName = prop[0];\n\n            if (notCheckCache || style[styleName] !== prevStyle[styleName]) {\n                // FIXME Invalid property value will cause style leak from previous element.\n                ctx[styleName] =\n                    fixShadow(ctx, styleName, style[styleName] || prop[1]);\n            }\n        }\n\n        if ((notCheckCache || style.fill !== prevStyle.fill)) {\n            ctx.fillStyle = style.fill;\n        }\n        if ((notCheckCache || style.stroke !== prevStyle.stroke)) {\n            ctx.strokeStyle = style.stroke;\n        }\n        if ((notCheckCache || style.opacity !== prevStyle.opacity)) {\n            ctx.globalAlpha = style.opacity == null ? 1 : style.opacity;\n        }\n\n        if ((notCheckCache || style.blend !== prevStyle.blend)) {\n            ctx.globalCompositeOperation = style.blend || 'source-over';\n        }\n        if (this.hasStroke()) {\n            var lineWidth = style.lineWidth;\n            ctx.lineWidth = lineWidth / (\n                (this.strokeNoScale && el && el.getLineScale) ? el.getLineScale() : 1\n            );\n        }\n    },\n\n    hasFill: function () {\n        var fill = this.fill;\n        return fill != null && fill !== 'none';\n    },\n\n    hasStroke: function () {\n        var stroke = this.stroke;\n        return stroke != null && stroke !== 'none' && this.lineWidth > 0;\n    },\n\n    /**\n     * Extend from other style\n     * @param {zrender/graphic/Style} otherStyle\n     * @param {boolean} overwrite true: overwrirte any way.\n     *                            false: overwrite only when !target.hasOwnProperty\n     *                            others: overwrite when property is not null/undefined.\n     */\n    extendFrom: function (otherStyle, overwrite) {\n        if (otherStyle) {\n            for (var name in otherStyle) {\n                if (otherStyle.hasOwnProperty(name)\n                    && (overwrite === true\n                        || (\n                            overwrite === false\n                                ? !this.hasOwnProperty(name)\n                                : otherStyle[name] != null\n                        )\n                    )\n                ) {\n                    this[name] = otherStyle[name];\n                }\n            }\n        }\n    },\n\n    /**\n     * Batch setting style with a given object\n     * @param {Object|string} obj\n     * @param {*} [obj]\n     */\n    set: function (obj, value) {\n        if (typeof obj === 'string') {\n            this[obj] = value;\n        }\n        else {\n            this.extendFrom(obj, true);\n        }\n    },\n\n    /**\n     * Clone\n     * @return {zrender/graphic/Style} [description]\n     */\n    clone: function () {\n        var newStyle = new this.constructor();\n        newStyle.extendFrom(this, true);\n        return newStyle;\n    },\n\n    getGradient: function (ctx, obj, rect) {\n        var method = obj.type === 'radial' ? createRadialGradient : createLinearGradient;\n        var canvasGradient = method(ctx, obj, rect);\n        var colorStops = obj.colorStops;\n        for (var i = 0; i < colorStops.length; i++) {\n            canvasGradient.addColorStop(\n                colorStops[i].offset, colorStops[i].color\n            );\n        }\n        return canvasGradient;\n    }\n\n};\n\nvar styleProto = Style.prototype;\nfor (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {\n    var prop = STYLE_COMMON_PROPS[i];\n    if (!(prop[0] in styleProto)) {\n        styleProto[prop[0]] = prop[1];\n    }\n}\n\n// Provide for others\nStyle.getGradient = styleProto.getGradient;\n\nvar Pattern = function (image, repeat) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {image: ...}`, where this constructor will not be called.\n\n    this.image = image;\n    this.repeat = repeat;\n\n    // Can be cloned\n    this.type = 'pattern';\n};\n\nPattern.prototype.getCanvasPattern = function (ctx) {\n    return ctx.createPattern(this.image, this.repeat || 'repeat');\n};\n\n/**\n * @module zrender/Layer\n * @author pissang(https://www.github.com/pissang)\n */\n\nfunction returnFalse() {\n    return false;\n}\n\n/**\n * 创建dom\n *\n * @inner\n * @param {string} id dom id 待用\n * @param {Painter} painter painter instance\n * @param {number} number\n */\nfunction createDom(id, painter, dpr) {\n    var newDom = createCanvas();\n    var width = painter.getWidth();\n    var height = painter.getHeight();\n\n    var newDomStyle = newDom.style;\n    if (newDomStyle) {  // In node or some other non-browser environment\n        newDomStyle.position = 'absolute';\n        newDomStyle.left = 0;\n        newDomStyle.top = 0;\n        newDomStyle.width = width + 'px';\n        newDomStyle.height = height + 'px';\n\n        newDom.setAttribute('data-zr-dom-id', id);\n    }\n\n    newDom.width = width * dpr;\n    newDom.height = height * dpr;\n\n    return newDom;\n}\n\n/**\n * @alias module:zrender/Layer\n * @constructor\n * @extends module:zrender/mixin/Transformable\n * @param {string} id\n * @param {module:zrender/Painter} painter\n * @param {number} [dpr]\n */\nvar Layer = function (id, painter, dpr) {\n    var dom;\n    dpr = dpr || devicePixelRatio;\n    if (typeof id === 'string') {\n        dom = createDom(id, painter, dpr);\n    }\n    // Not using isDom because in node it will return false\n    else if (isObject$1(id)) {\n        dom = id;\n        id = dom.id;\n    }\n    this.id = id;\n    this.dom = dom;\n\n    var domStyle = dom.style;\n    if (domStyle) { // Not in node\n        dom.onselectstart = returnFalse; // 避免页面选中的尴尬\n        domStyle['-webkit-user-select'] = 'none';\n        domStyle['user-select'] = 'none';\n        domStyle['-webkit-touch-callout'] = 'none';\n        domStyle['-webkit-tap-highlight-color'] = 'rgba(0,0,0,0)';\n        domStyle['padding'] = 0;\n        domStyle['margin'] = 0;\n        domStyle['border-width'] = 0;\n    }\n\n    this.domBack = null;\n    this.ctxBack = null;\n\n    this.painter = painter;\n\n    this.config = null;\n\n    // Configs\n    /**\n     * 每次清空画布的颜色\n     * @type {string}\n     * @default 0\n     */\n    this.clearColor = 0;\n    /**\n     * 是否开启动态模糊\n     * @type {boolean}\n     * @default false\n     */\n    this.motionBlur = false;\n    /**\n     * 在开启动态模糊的时候使用，与上一帧混合的alpha值，值越大尾迹越明显\n     * @type {number}\n     * @default 0.7\n     */\n    this.lastFrameAlpha = 0.7;\n\n    /**\n     * Layer dpr\n     * @type {number}\n     */\n    this.dpr = dpr;\n};\n\nLayer.prototype = {\n\n    constructor: Layer,\n\n    __dirty: true,\n\n    __used: false,\n\n    __drawIndex: 0,\n    __startIndex: 0,\n    __endIndex: 0,\n\n    incremental: false,\n\n    getElementCount: function () {\n        return this.__endIndex - this.__startIndex;\n    },\n\n    initContext: function () {\n        this.ctx = this.dom.getContext('2d');\n        this.ctx.dpr = this.dpr;\n    },\n\n    createBackBuffer: function () {\n        var dpr = this.dpr;\n\n        this.domBack = createDom('back-' + this.id, this.painter, dpr);\n        this.ctxBack = this.domBack.getContext('2d');\n\n        if (dpr !== 1) {\n            this.ctxBack.scale(dpr, dpr);\n        }\n    },\n\n    /**\n     * @param  {number} width\n     * @param  {number} height\n     */\n    resize: function (width, height) {\n        var dpr = this.dpr;\n\n        var dom = this.dom;\n        var domStyle = dom.style;\n        var domBack = this.domBack;\n\n        if (domStyle) {\n            domStyle.width = width + 'px';\n            domStyle.height = height + 'px';\n        }\n\n        dom.width = width * dpr;\n        dom.height = height * dpr;\n\n        if (domBack) {\n            domBack.width = width * dpr;\n            domBack.height = height * dpr;\n\n            if (dpr !== 1) {\n                this.ctxBack.scale(dpr, dpr);\n            }\n        }\n    },\n\n    /**\n     * 清空该层画布\n     * @param {boolean} [clearAll]=false Clear all with out motion blur\n     * @param {Color} [clearColor]\n     */\n    clear: function (clearAll, clearColor) {\n        var dom = this.dom;\n        var ctx = this.ctx;\n        var width = dom.width;\n        var height = dom.height;\n\n        var clearColor = clearColor || this.clearColor;\n        var haveMotionBLur = this.motionBlur && !clearAll;\n        var lastFrameAlpha = this.lastFrameAlpha;\n\n        var dpr = this.dpr;\n\n        if (haveMotionBLur) {\n            if (!this.domBack) {\n                this.createBackBuffer();\n            }\n\n            this.ctxBack.globalCompositeOperation = 'copy';\n            this.ctxBack.drawImage(\n                dom, 0, 0,\n                width / dpr,\n                height / dpr\n            );\n        }\n\n        ctx.clearRect(0, 0, width, height);\n        if (clearColor && clearColor !== 'transparent') {\n            var clearColorGradientOrPattern;\n            // Gradient\n            if (clearColor.colorStops) {\n                // Cache canvas gradient\n                clearColorGradientOrPattern = clearColor.__canvasGradient || Style.getGradient(ctx, clearColor, {\n                    x: 0,\n                    y: 0,\n                    width: width,\n                    height: height\n                });\n\n                clearColor.__canvasGradient = clearColorGradientOrPattern;\n            }\n            // Pattern\n            else if (clearColor.image) {\n                clearColorGradientOrPattern = Pattern.prototype.getCanvasPattern.call(clearColor, ctx);\n            }\n            ctx.save();\n            ctx.fillStyle = clearColorGradientOrPattern || clearColor;\n            ctx.fillRect(0, 0, width, height);\n            ctx.restore();\n        }\n\n        if (haveMotionBLur) {\n            var domBack = this.domBack;\n            ctx.save();\n            ctx.globalAlpha = lastFrameAlpha;\n            ctx.drawImage(domBack, 0, 0, width, height);\n            ctx.restore();\n        }\n    }\n};\n\nvar requestAnimationFrame = (\n    typeof window !== 'undefined'\n    && (\n        (window.requestAnimationFrame && window.requestAnimationFrame.bind(window))\n        // https://github.com/ecomfe/zrender/issues/189#issuecomment-224919809\n        || (window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window))\n        || window.mozRequestAnimationFrame\n        || window.webkitRequestAnimationFrame\n    )\n) || function (func) {\n    setTimeout(func, 16);\n};\n\nvar globalImageCache = new LRU(50);\n\n/**\n * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc\n * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image\n */\nfunction findExistImage(newImageOrSrc) {\n    if (typeof newImageOrSrc === 'string') {\n        var cachedImgObj = globalImageCache.get(newImageOrSrc);\n        return cachedImgObj && cachedImgObj.image;\n    }\n    else {\n        return newImageOrSrc;\n    }\n}\n\n/**\n * Caution: User should cache loaded images, but not just count on LRU.\n * Consider if required images more than LRU size, will dead loop occur?\n *\n * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc\n * @param {HTMLImageElement|HTMLCanvasElement|Canvas} image Existent image.\n * @param {module:zrender/Element} [hostEl] For calling `dirty`.\n * @param {Function} [cb] params: (image, cbPayload)\n * @param {Object} [cbPayload] Payload on cb calling.\n * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image\n */\nfunction createOrUpdateImage(newImageOrSrc, image, hostEl, cb, cbPayload) {\n    if (!newImageOrSrc) {\n        return image;\n    }\n    else if (typeof newImageOrSrc === 'string') {\n\n        // Image should not be loaded repeatly.\n        if ((image && image.__zrImageSrc === newImageOrSrc) || !hostEl) {\n            return image;\n        }\n\n        // Only when there is no existent image or existent image src\n        // is different, this method is responsible for load.\n        var cachedImgObj = globalImageCache.get(newImageOrSrc);\n\n        var pendingWrap = {hostEl: hostEl, cb: cb, cbPayload: cbPayload};\n\n        if (cachedImgObj) {\n            image = cachedImgObj.image;\n            !isImageReady(image) && cachedImgObj.pending.push(pendingWrap);\n        }\n        else {\n            image = new Image();\n            image.onload = image.onerror = imageOnLoad;\n\n            globalImageCache.put(\n                newImageOrSrc,\n                image.__cachedImgObj = {\n                    image: image,\n                    pending: [pendingWrap]\n                }\n            );\n\n            image.src = image.__zrImageSrc = newImageOrSrc;\n        }\n\n        return image;\n    }\n    // newImageOrSrc is an HTMLImageElement or HTMLCanvasElement or Canvas\n    else {\n        return newImageOrSrc;\n    }\n}\n\nfunction imageOnLoad() {\n    var cachedImgObj = this.__cachedImgObj;\n    this.onload = this.onerror = this.__cachedImgObj = null;\n\n    for (var i = 0; i < cachedImgObj.pending.length; i++) {\n        var pendingWrap = cachedImgObj.pending[i];\n        var cb = pendingWrap.cb;\n        cb && cb(this, pendingWrap.cbPayload);\n        pendingWrap.hostEl.dirty();\n    }\n    cachedImgObj.pending.length = 0;\n}\n\nfunction isImageReady(image) {\n    return image && image.width && image.height;\n}\n\nvar textWidthCache = {};\nvar textWidthCacheCounter = 0;\n\nvar TEXT_CACHE_MAX = 5000;\nvar STYLE_REG = /\\{([a-zA-Z0-9_]+)\\|([^}]*)\\}/g;\n\nvar DEFAULT_FONT$1 = '12px sans-serif';\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar methods$1 = {};\n\nfunction $override$1(name, fn) {\n    methods$1[name] = fn;\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @return {number} width\n */\nfunction getWidth(text, font) {\n    font = font || DEFAULT_FONT$1;\n    var key = text + ':' + font;\n    if (textWidthCache[key]) {\n        return textWidthCache[key];\n    }\n\n    var textLines = (text + '').split('\\n');\n    var width = 0;\n\n    for (var i = 0, l = textLines.length; i < l; i++) {\n        // textContain.measureText may be overrided in SVG or VML\n        width = Math.max(measureText(textLines[i], font).width, width);\n    }\n\n    if (textWidthCacheCounter > TEXT_CACHE_MAX) {\n        textWidthCacheCounter = 0;\n        textWidthCache = {};\n    }\n    textWidthCacheCounter++;\n    textWidthCache[key] = width;\n\n    return width;\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @param {string} [textAlign='left']\n * @param {string} [textVerticalAlign='top']\n * @param {Array.<number>} [textPadding]\n * @param {Object} [rich]\n * @param {Object} [truncate]\n * @return {Object} {x, y, width, height, lineHeight}\n */\nfunction getBoundingRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) {\n    return rich\n        ? getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate)\n        : getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate);\n}\n\nfunction getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate) {\n    var contentBlock = parsePlainText(text, font, textPadding, textLineHeight, truncate);\n    var outerWidth = getWidth(text, font);\n    if (textPadding) {\n        outerWidth += textPadding[1] + textPadding[3];\n    }\n    var outerHeight = contentBlock.outerHeight;\n\n    var x = adjustTextX(0, outerWidth, textAlign);\n    var y = adjustTextY(0, outerHeight, textVerticalAlign);\n\n    var rect = new BoundingRect(x, y, outerWidth, outerHeight);\n    rect.lineHeight = contentBlock.lineHeight;\n\n    return rect;\n}\n\nfunction getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) {\n    var contentBlock = parseRichText(text, {\n        rich: rich,\n        truncate: truncate,\n        font: font,\n        textAlign: textAlign,\n        textPadding: textPadding,\n        textLineHeight: textLineHeight\n    });\n    var outerWidth = contentBlock.outerWidth;\n    var outerHeight = contentBlock.outerHeight;\n\n    var x = adjustTextX(0, outerWidth, textAlign);\n    var y = adjustTextY(0, outerHeight, textVerticalAlign);\n\n    return new BoundingRect(x, y, outerWidth, outerHeight);\n}\n\n/**\n * @public\n * @param {number} x\n * @param {number} width\n * @param {string} [textAlign='left']\n * @return {number} Adjusted x.\n */\nfunction adjustTextX(x, width, textAlign) {\n    // FIXME Right to left language\n    if (textAlign === 'right') {\n        x -= width;\n    }\n    else if (textAlign === 'center') {\n        x -= width / 2;\n    }\n    return x;\n}\n\n/**\n * @public\n * @param {number} y\n * @param {number} height\n * @param {string} [textVerticalAlign='top']\n * @return {number} Adjusted y.\n */\nfunction adjustTextY(y, height, textVerticalAlign) {\n    if (textVerticalAlign === 'middle') {\n        y -= height / 2;\n    }\n    else if (textVerticalAlign === 'bottom') {\n        y -= height;\n    }\n    return y;\n}\n\n/**\n * @public\n * @param {stirng} textPosition\n * @param {Object} rect {x, y, width, height}\n * @param {number} distance\n * @return {Object} {x, y, textAlign, textVerticalAlign}\n */\nfunction adjustTextPositionOnRect(textPosition, rect, distance) {\n\n    var x = rect.x;\n    var y = rect.y;\n\n    var height = rect.height;\n    var width = rect.width;\n    var halfHeight = height / 2;\n\n    var textAlign = 'left';\n    var textVerticalAlign = 'top';\n\n    switch (textPosition) {\n        case 'left':\n            x -= distance;\n            y += halfHeight;\n            textAlign = 'right';\n            textVerticalAlign = 'middle';\n            break;\n        case 'right':\n            x += distance + width;\n            y += halfHeight;\n            textVerticalAlign = 'middle';\n            break;\n        case 'top':\n            x += width / 2;\n            y -= distance;\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            break;\n        case 'bottom':\n            x += width / 2;\n            y += height + distance;\n            textAlign = 'center';\n            break;\n        case 'inside':\n            x += width / 2;\n            y += halfHeight;\n            textAlign = 'center';\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideLeft':\n            x += distance;\n            y += halfHeight;\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideRight':\n            x += width - distance;\n            y += halfHeight;\n            textAlign = 'right';\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideTop':\n            x += width / 2;\n            y += distance;\n            textAlign = 'center';\n            break;\n        case 'insideBottom':\n            x += width / 2;\n            y += height - distance;\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            break;\n        case 'insideTopLeft':\n            x += distance;\n            y += distance;\n            break;\n        case 'insideTopRight':\n            x += width - distance;\n            y += distance;\n            textAlign = 'right';\n            break;\n        case 'insideBottomLeft':\n            x += distance;\n            y += height - distance;\n            textVerticalAlign = 'bottom';\n            break;\n        case 'insideBottomRight':\n            x += width - distance;\n            y += height - distance;\n            textAlign = 'right';\n            textVerticalAlign = 'bottom';\n            break;\n    }\n\n    return {\n        x: x,\n        y: y,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\n/**\n * Show ellipsis if overflow.\n *\n * @public\n * @param  {string} text\n * @param  {string} containerWidth\n * @param  {string} font\n * @param  {number} [ellipsis='...']\n * @param  {Object} [options]\n * @param  {number} [options.maxIterations=3]\n * @param  {number} [options.minChar=0] If truncate result are less\n *                  then minChar, ellipsis will not show, which is\n *                  better for user hint in some cases.\n * @param  {number} [options.placeholder=''] When all truncated, use the placeholder.\n * @return {string}\n */\nfunction truncateText(text, containerWidth, font, ellipsis, options) {\n    if (!containerWidth) {\n        return '';\n    }\n\n    var textLines = (text + '').split('\\n');\n    options = prepareTruncateOptions(containerWidth, font, ellipsis, options);\n\n    // FIXME\n    // It is not appropriate that every line has '...' when truncate multiple lines.\n    for (var i = 0, len = textLines.length; i < len; i++) {\n        textLines[i] = truncateSingleLine(textLines[i], options);\n    }\n\n    return textLines.join('\\n');\n}\n\nfunction prepareTruncateOptions(containerWidth, font, ellipsis, options) {\n    options = extend({}, options);\n\n    options.font = font;\n    var ellipsis = retrieve2(ellipsis, '...');\n    options.maxIterations = retrieve2(options.maxIterations, 2);\n    var minChar = options.minChar = retrieve2(options.minChar, 0);\n    // FIXME\n    // Other languages?\n    options.cnCharWidth = getWidth('国', font);\n    // FIXME\n    // Consider proportional font?\n    var ascCharWidth = options.ascCharWidth = getWidth('a', font);\n    options.placeholder = retrieve2(options.placeholder, '');\n\n    // Example 1: minChar: 3, text: 'asdfzxcv', truncate result: 'asdf', but not: 'a...'.\n    // Example 2: minChar: 3, text: '维度', truncate result: '维', but not: '...'.\n    var contentWidth = containerWidth = Math.max(0, containerWidth - 1); // Reserve some gap.\n    for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) {\n        contentWidth -= ascCharWidth;\n    }\n\n    var ellipsisWidth = getWidth(ellipsis, font);\n    if (ellipsisWidth > contentWidth) {\n        ellipsis = '';\n        ellipsisWidth = 0;\n    }\n\n    contentWidth = containerWidth - ellipsisWidth;\n\n    options.ellipsis = ellipsis;\n    options.ellipsisWidth = ellipsisWidth;\n    options.contentWidth = contentWidth;\n    options.containerWidth = containerWidth;\n\n    return options;\n}\n\nfunction truncateSingleLine(textLine, options) {\n    var containerWidth = options.containerWidth;\n    var font = options.font;\n    var contentWidth = options.contentWidth;\n\n    if (!containerWidth) {\n        return '';\n    }\n\n    var lineWidth = getWidth(textLine, font);\n\n    if (lineWidth <= containerWidth) {\n        return textLine;\n    }\n\n    for (var j = 0; ; j++) {\n        if (lineWidth <= contentWidth || j >= options.maxIterations) {\n            textLine += options.ellipsis;\n            break;\n        }\n\n        var subLength = j === 0\n            ? estimateLength(textLine, contentWidth, options.ascCharWidth, options.cnCharWidth)\n            : lineWidth > 0\n            ? Math.floor(textLine.length * contentWidth / lineWidth)\n            : 0;\n\n        textLine = textLine.substr(0, subLength);\n        lineWidth = getWidth(textLine, font);\n    }\n\n    if (textLine === '') {\n        textLine = options.placeholder;\n    }\n\n    return textLine;\n}\n\nfunction estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) {\n    var width = 0;\n    var i = 0;\n    for (var len = text.length; i < len && width < contentWidth; i++) {\n        var charCode = text.charCodeAt(i);\n        width += (0 <= charCode && charCode <= 127) ? ascCharWidth : cnCharWidth;\n    }\n    return i;\n}\n\n/**\n * @public\n * @param {string} font\n * @return {number} line height\n */\nfunction getLineHeight(font) {\n    // FIXME A rough approach.\n    return getWidth('国', font);\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @return {Object} width\n */\nfunction measureText(text, font) {\n    return methods$1.measureText(text, font);\n}\n\n// Avoid assign to an exported variable, for transforming to cjs.\nmethods$1.measureText = function (text, font) {\n    var ctx = getContext();\n    ctx.font = font || DEFAULT_FONT$1;\n    return ctx.measureText(text);\n};\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @param {Object} [truncate]\n * @return {Object} block: {lineHeight, lines, height, outerHeight}\n *  Notice: for performance, do not calculate outerWidth util needed.\n */\nfunction parsePlainText(text, font, padding, textLineHeight, truncate) {\n    text != null && (text += '');\n\n    var lineHeight = retrieve2(textLineHeight, getLineHeight(font));\n    var lines = text ? text.split('\\n') : [];\n    var height = lines.length * lineHeight;\n    var outerHeight = height;\n\n    if (padding) {\n        outerHeight += padding[0] + padding[2];\n    }\n\n    if (text && truncate) {\n        var truncOuterHeight = truncate.outerHeight;\n        var truncOuterWidth = truncate.outerWidth;\n        if (truncOuterHeight != null && outerHeight > truncOuterHeight) {\n            text = '';\n            lines = [];\n        }\n        else if (truncOuterWidth != null) {\n            var options = prepareTruncateOptions(\n                truncOuterWidth - (padding ? padding[1] + padding[3] : 0),\n                font,\n                truncate.ellipsis,\n                {minChar: truncate.minChar, placeholder: truncate.placeholder}\n            );\n\n            // FIXME\n            // It is not appropriate that every line has '...' when truncate multiple lines.\n            for (var i = 0, len = lines.length; i < len; i++) {\n                lines[i] = truncateSingleLine(lines[i], options);\n            }\n        }\n    }\n\n    return {\n        lines: lines,\n        height: height,\n        outerHeight: outerHeight,\n        lineHeight: lineHeight\n    };\n}\n\n/**\n * For example: 'some text {a|some text}other text{b|some text}xxx{c|}xxx'\n * Also consider 'bbbb{a|xxx\\nzzz}xxxx\\naaaa'.\n *\n * @public\n * @param {string} text\n * @param {Object} style\n * @return {Object} block\n * {\n *      width,\n *      height,\n *      lines: [{\n *          lineHeight,\n *          width,\n *          tokens: [[{\n *              styleName,\n *              text,\n *              width,      // include textPadding\n *              height,     // include textPadding\n *              textWidth, // pure text width\n *              textHeight, // pure text height\n *              lineHeihgt,\n *              font,\n *              textAlign,\n *              textVerticalAlign\n *          }], [...], ...]\n *      }, ...]\n * }\n * If styleName is undefined, it is plain text.\n */\nfunction parseRichText(text, style) {\n    var contentBlock = {lines: [], width: 0, height: 0};\n\n    text != null && (text += '');\n    if (!text) {\n        return contentBlock;\n    }\n\n    var lastIndex = STYLE_REG.lastIndex = 0;\n    var result;\n    while ((result = STYLE_REG.exec(text)) != null) {\n        var matchedIndex = result.index;\n        if (matchedIndex > lastIndex) {\n            pushTokens(contentBlock, text.substring(lastIndex, matchedIndex));\n        }\n        pushTokens(contentBlock, result[2], result[1]);\n        lastIndex = STYLE_REG.lastIndex;\n    }\n\n    if (lastIndex < text.length) {\n        pushTokens(contentBlock, text.substring(lastIndex, text.length));\n    }\n\n    var lines = contentBlock.lines;\n    var contentHeight = 0;\n    var contentWidth = 0;\n    // For `textWidth: 100%`\n    var pendingList = [];\n\n    var stlPadding = style.textPadding;\n\n    var truncate = style.truncate;\n    var truncateWidth = truncate && truncate.outerWidth;\n    var truncateHeight = truncate && truncate.outerHeight;\n    if (stlPadding) {\n        truncateWidth != null && (truncateWidth -= stlPadding[1] + stlPadding[3]);\n        truncateHeight != null && (truncateHeight -= stlPadding[0] + stlPadding[2]);\n    }\n\n    // Calculate layout info of tokens.\n    for (var i = 0; i < lines.length; i++) {\n        var line = lines[i];\n        var lineHeight = 0;\n        var lineWidth = 0;\n\n        for (var j = 0; j < line.tokens.length; j++) {\n            var token = line.tokens[j];\n            var tokenStyle = token.styleName && style.rich[token.styleName] || {};\n            // textPadding should not inherit from style.\n            var textPadding = token.textPadding = tokenStyle.textPadding;\n\n            // textFont has been asigned to font by `normalizeStyle`.\n            var font = token.font = tokenStyle.font || style.font;\n\n            // textHeight can be used when textVerticalAlign is specified in token.\n            var tokenHeight = token.textHeight = retrieve2(\n                // textHeight should not be inherited, consider it can be specified\n                // as box height of the block.\n                tokenStyle.textHeight, getLineHeight(font)\n            );\n            textPadding && (tokenHeight += textPadding[0] + textPadding[2]);\n            token.height = tokenHeight;\n            token.lineHeight = retrieve3(\n                tokenStyle.textLineHeight, style.textLineHeight, tokenHeight\n            );\n\n            token.textAlign = tokenStyle && tokenStyle.textAlign || style.textAlign;\n            token.textVerticalAlign = tokenStyle && tokenStyle.textVerticalAlign || 'middle';\n\n            if (truncateHeight != null && contentHeight + token.lineHeight > truncateHeight) {\n                return {lines: [], width: 0, height: 0};\n            }\n\n            token.textWidth = getWidth(token.text, font);\n            var tokenWidth = tokenStyle.textWidth;\n            var tokenWidthNotSpecified = tokenWidth == null || tokenWidth === 'auto';\n\n            // Percent width, can be `100%`, can be used in drawing separate\n            // line when box width is needed to be auto.\n            if (typeof tokenWidth === 'string' && tokenWidth.charAt(tokenWidth.length - 1) === '%') {\n                token.percentWidth = tokenWidth;\n                pendingList.push(token);\n                tokenWidth = 0;\n                // Do not truncate in this case, because there is no user case\n                // and it is too complicated.\n            }\n            else {\n                if (tokenWidthNotSpecified) {\n                    tokenWidth = token.textWidth;\n\n                    // FIXME: If image is not loaded and textWidth is not specified, calling\n                    // `getBoundingRect()` will not get correct result.\n                    var textBackgroundColor = tokenStyle.textBackgroundColor;\n                    var bgImg = textBackgroundColor && textBackgroundColor.image;\n\n                    // Use cases:\n                    // (1) If image is not loaded, it will be loaded at render phase and call\n                    // `dirty()` and `textBackgroundColor.image` will be replaced with the loaded\n                    // image, and then the right size will be calculated here at the next tick.\n                    // See `graphic/helper/text.js`.\n                    // (2) If image loaded, and `textBackgroundColor.image` is image src string,\n                    // use `imageHelper.findExistImage` to find cached image.\n                    // `imageHelper.findExistImage` will always be called here before\n                    // `imageHelper.createOrUpdateImage` in `graphic/helper/text.js#renderRichText`\n                    // which ensures that image will not be rendered before correct size calcualted.\n                    if (bgImg) {\n                        bgImg = findExistImage(bgImg);\n                        if (isImageReady(bgImg)) {\n                            tokenWidth = Math.max(tokenWidth, bgImg.width * tokenHeight / bgImg.height);\n                        }\n                    }\n                }\n\n                var paddingW = textPadding ? textPadding[1] + textPadding[3] : 0;\n                tokenWidth += paddingW;\n\n                var remianTruncWidth = truncateWidth != null ? truncateWidth - lineWidth : null;\n\n                if (remianTruncWidth != null && remianTruncWidth < tokenWidth) {\n                    if (!tokenWidthNotSpecified || remianTruncWidth < paddingW) {\n                        token.text = '';\n                        token.textWidth = tokenWidth = 0;\n                    }\n                    else {\n                        token.text = truncateText(\n                            token.text, remianTruncWidth - paddingW, font, truncate.ellipsis,\n                            {minChar: truncate.minChar}\n                        );\n                        token.textWidth = getWidth(token.text, font);\n                        tokenWidth = token.textWidth + paddingW;\n                    }\n                }\n            }\n\n            lineWidth += (token.width = tokenWidth);\n            tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight));\n        }\n\n        line.width = lineWidth;\n        line.lineHeight = lineHeight;\n        contentHeight += lineHeight;\n        contentWidth = Math.max(contentWidth, lineWidth);\n    }\n\n    contentBlock.outerWidth = contentBlock.width = retrieve2(style.textWidth, contentWidth);\n    contentBlock.outerHeight = contentBlock.height = retrieve2(style.textHeight, contentHeight);\n\n    if (stlPadding) {\n        contentBlock.outerWidth += stlPadding[1] + stlPadding[3];\n        contentBlock.outerHeight += stlPadding[0] + stlPadding[2];\n    }\n\n    for (var i = 0; i < pendingList.length; i++) {\n        var token = pendingList[i];\n        var percentWidth = token.percentWidth;\n        // Should not base on outerWidth, because token can not be placed out of padding.\n        token.width = parseInt(percentWidth, 10) / 100 * contentWidth;\n    }\n\n    return contentBlock;\n}\n\nfunction pushTokens(block, str, styleName) {\n    var isEmptyStr = str === '';\n    var strs = str.split('\\n');\n    var lines = block.lines;\n\n    for (var i = 0; i < strs.length; i++) {\n        var text = strs[i];\n        var token = {\n            styleName: styleName,\n            text: text,\n            isLineHolder: !text && !isEmptyStr\n        };\n\n        // The first token should be appended to the last line.\n        if (!i) {\n            var tokens = (lines[lines.length - 1] || (lines[0] = {tokens: []})).tokens;\n\n            // Consider cases:\n            // (1) ''.split('\\n') => ['', '\\n', ''], the '' at the first item\n            // (which is a placeholder) should be replaced by new token.\n            // (2) A image backage, where token likes {a|}.\n            // (3) A redundant '' will affect textAlign in line.\n            // (4) tokens with the same tplName should not be merged, because\n            // they should be displayed in different box (with border and padding).\n            var tokensLen = tokens.length;\n            (tokensLen === 1 && tokens[0].isLineHolder)\n                ? (tokens[0] = token)\n                // Consider text is '', only insert when it is the \"lineHolder\" or\n                // \"emptyStr\". Otherwise a redundant '' will affect textAlign in line.\n                : ((text || !tokensLen || isEmptyStr) && tokens.push(token));\n        }\n        // Other tokens always start a new line.\n        else {\n            // If there is '', insert it as a placeholder.\n            lines.push({tokens: [token]});\n        }\n    }\n}\n\nfunction makeFont(style) {\n    // FIXME in node-canvas fontWeight is before fontStyle\n    // Use `fontSize` `fontFamily` to check whether font properties are defined.\n    var font = (style.fontSize || style.fontFamily) && [\n        style.fontStyle,\n        style.fontWeight,\n        (style.fontSize || 12) + 'px',\n        // If font properties are defined, `fontFamily` should not be ignored.\n        style.fontFamily || 'sans-serif'\n    ].join(' ');\n    return font && trim(font) || style.textFont || style.font;\n}\n\n/**\n * @param {Object} ctx\n * @param {Object} shape\n * @param {number} shape.x\n * @param {number} shape.y\n * @param {number} shape.width\n * @param {number} shape.height\n * @param {number} shape.r\n */\nfunction buildPath(ctx, shape) {\n    var x = shape.x;\n    var y = shape.y;\n    var width = shape.width;\n    var height = shape.height;\n    var r = shape.r;\n    var r1;\n    var r2;\n    var r3;\n    var r4;\n\n    // Convert width and height to positive for better borderRadius\n    if (width < 0) {\n        x = x + width;\n        width = -width;\n    }\n    if (height < 0) {\n        y = y + height;\n        height = -height;\n    }\n\n    if (typeof r === 'number') {\n        r1 = r2 = r3 = r4 = r;\n    }\n    else if (r instanceof Array) {\n        if (r.length === 1) {\n            r1 = r2 = r3 = r4 = r[0];\n        }\n        else if (r.length === 2) {\n            r1 = r3 = r[0];\n            r2 = r4 = r[1];\n        }\n        else if (r.length === 3) {\n            r1 = r[0];\n            r2 = r4 = r[1];\n            r3 = r[2];\n        }\n        else {\n            r1 = r[0];\n            r2 = r[1];\n            r3 = r[2];\n            r4 = r[3];\n        }\n    }\n    else {\n        r1 = r2 = r3 = r4 = 0;\n    }\n\n    var total;\n    if (r1 + r2 > width) {\n        total = r1 + r2;\n        r1 *= width / total;\n        r2 *= width / total;\n    }\n    if (r3 + r4 > width) {\n        total = r3 + r4;\n        r3 *= width / total;\n        r4 *= width / total;\n    }\n    if (r2 + r3 > height) {\n        total = r2 + r3;\n        r2 *= height / total;\n        r3 *= height / total;\n    }\n    if (r1 + r4 > height) {\n        total = r1 + r4;\n        r1 *= height / total;\n        r4 *= height / total;\n    }\n    ctx.moveTo(x + r1, y);\n    ctx.lineTo(x + width - r2, y);\n    r2 !== 0 && ctx.arc(x + width - r2, y + r2, r2, -Math.PI / 2, 0);\n    ctx.lineTo(x + width, y + height - r3);\n    r3 !== 0 && ctx.arc(x + width - r3, y + height - r3, r3, 0, Math.PI / 2);\n    ctx.lineTo(x + r4, y + height);\n    r4 !== 0 && ctx.arc(x + r4, y + height - r4, r4, Math.PI / 2, Math.PI);\n    ctx.lineTo(x, y + r1);\n    r1 !== 0 && ctx.arc(x + r1, y + r1, r1, Math.PI, Math.PI * 1.5);\n}\n\nvar DEFAULT_FONT = DEFAULT_FONT$1;\n\n// TODO: Have not support 'start', 'end' yet.\nvar VALID_TEXT_ALIGN = {left: 1, right: 1, center: 1};\nvar VALID_TEXT_VERTICAL_ALIGN = {top: 1, bottom: 1, middle: 1};\n// Different from `STYLE_COMMON_PROPS` of `graphic/Style`,\n// the default value of shadowColor is `'transparent'`.\nvar SHADOW_STYLE_COMMON_PROPS = [\n    ['textShadowBlur', 'shadowBlur', 0],\n    ['textShadowOffsetX', 'shadowOffsetX', 0],\n    ['textShadowOffsetY', 'shadowOffsetY', 0],\n    ['textShadowColor', 'shadowColor', 'transparent']\n];\n\n/**\n * @param {module:zrender/graphic/Style} style\n * @return {module:zrender/graphic/Style} The input style.\n */\nfunction normalizeTextStyle(style) {\n    normalizeStyle(style);\n    each$1(style.rich, normalizeStyle);\n    return style;\n}\n\nfunction normalizeStyle(style) {\n    if (style) {\n\n        style.font = makeFont(style);\n\n        var textAlign = style.textAlign;\n        textAlign === 'middle' && (textAlign = 'center');\n        style.textAlign = (\n            textAlign == null || VALID_TEXT_ALIGN[textAlign]\n        ) ? textAlign : 'left';\n\n        // Compatible with textBaseline.\n        var textVerticalAlign = style.textVerticalAlign || style.textBaseline;\n        textVerticalAlign === 'center' && (textVerticalAlign = 'middle');\n        style.textVerticalAlign = (\n            textVerticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[textVerticalAlign]\n        ) ? textVerticalAlign : 'top';\n\n        var textPadding = style.textPadding;\n        if (textPadding) {\n            style.textPadding = normalizeCssArray(style.textPadding);\n        }\n    }\n}\n\n/**\n * @param {CanvasRenderingContext2D} ctx\n * @param {string} text\n * @param {module:zrender/graphic/Style} style\n * @param {Object|boolean} [rect] {x, y, width, height}\n *                  If set false, rect text is not used.\n * @param {Element|module:zrender/graphic/helper/constant.WILL_BE_RESTORED} [prevEl] For ctx prop cache.\n */\nfunction renderText(hostEl, ctx, text, style, rect, prevEl) {\n    style.rich\n        ? renderRichText(hostEl, ctx, text, style, rect, prevEl)\n        : renderPlainText(hostEl, ctx, text, style, rect, prevEl);\n}\n\n// Avoid setting to ctx according to prevEl if possible for\n// performance in scenarios of large amount text.\nfunction renderPlainText(hostEl, ctx, text, style, rect, prevEl) {\n    'use strict';\n\n    var needDrawBg = needDrawBackground(style);\n\n    var prevStyle;\n    var checkCache = false;\n    var cachedByMe = ctx.__attrCachedBy === ContextCachedBy.PLAIN_TEXT;\n\n    // Only take and check cache for `Text` el, but not RectText.\n    if (prevEl !== WILL_BE_RESTORED) {\n        if (prevEl) {\n            prevStyle = prevEl.style;\n            checkCache = !needDrawBg && cachedByMe && prevStyle;\n        }\n\n        // Prevent from using cache in `Style::bind`, because of the case:\n        // ctx property is modified by other properties than `Style::bind`\n        // used, and Style::bind is called next.\n        ctx.__attrCachedBy = needDrawBg ? ContextCachedBy.NONE : ContextCachedBy.PLAIN_TEXT;\n    }\n    // Since this will be restored, prevent from using these props to check cache in the next\n    // entering of this method. But do not need to clear other cache like `Style::bind`.\n    else if (cachedByMe) {\n        ctx.__attrCachedBy = ContextCachedBy.NONE;\n    }\n\n    var styleFont = style.font || DEFAULT_FONT;\n    // PENDING\n    // Only `Text` el set `font` and keep it (`RectText` will restore). So theoretically\n    // we can make font cache on ctx, which can cache for text el that are discontinuous.\n    // But layer save/restore needed to be considered.\n    // if (styleFont !== ctx.__fontCache) {\n    //     ctx.font = styleFont;\n    //     if (prevEl !== WILL_BE_RESTORED) {\n    //         ctx.__fontCache = styleFont;\n    //     }\n    // }\n    if (!checkCache || styleFont !== (prevStyle.font || DEFAULT_FONT)) {\n        ctx.font = styleFont;\n    }\n\n    // Use the final font from context-2d, because the final\n    // font might not be the style.font when it is illegal.\n    // But get `ctx.font` might be time consuming.\n    var computedFont = hostEl.__computedFont;\n    if (hostEl.__styleFont !== styleFont) {\n        hostEl.__styleFont = styleFont;\n        computedFont = hostEl.__computedFont = ctx.font;\n    }\n\n    var textPadding = style.textPadding;\n    var textLineHeight = style.textLineHeight;\n\n    var contentBlock = hostEl.__textCotentBlock;\n    if (!contentBlock || hostEl.__dirtyText) {\n        contentBlock = hostEl.__textCotentBlock = parsePlainText(\n            text, computedFont, textPadding, textLineHeight, style.truncate\n        );\n    }\n\n    var outerHeight = contentBlock.outerHeight;\n\n    var textLines = contentBlock.lines;\n    var lineHeight = contentBlock.lineHeight;\n\n    var boxPos = getBoxPosition(outerHeight, style, rect);\n    var baseX = boxPos.baseX;\n    var baseY = boxPos.baseY;\n    var textAlign = boxPos.textAlign || 'left';\n    var textVerticalAlign = boxPos.textVerticalAlign;\n\n    // Origin of textRotation should be the base point of text drawing.\n    applyTextRotation(ctx, style, rect, baseX, baseY);\n\n    var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);\n    var textX = baseX;\n    var textY = boxY;\n\n    if (needDrawBg || textPadding) {\n        // Consider performance, do not call getTextWidth util necessary.\n        var textWidth = getWidth(text, computedFont);\n        var outerWidth = textWidth;\n        textPadding && (outerWidth += textPadding[1] + textPadding[3]);\n        var boxX = adjustTextX(baseX, outerWidth, textAlign);\n\n        needDrawBg && drawBackground(hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight);\n\n        if (textPadding) {\n            textX = getTextXForPadding(baseX, textAlign, textPadding);\n            textY += textPadding[0];\n        }\n    }\n\n    // Always set textAlign and textBase line, because it is difficute to calculate\n    // textAlign from prevEl, and we dont sure whether textAlign will be reset if\n    // font set happened.\n    ctx.textAlign = textAlign;\n    // Force baseline to be \"middle\". Otherwise, if using \"top\", the\n    // text will offset downward a little bit in font \"Microsoft YaHei\".\n    ctx.textBaseline = 'middle';\n    // Set text opacity\n    ctx.globalAlpha = style.opacity || 1;\n\n    // Always set shadowBlur and shadowOffset to avoid leak from displayable.\n    for (var i = 0; i < SHADOW_STYLE_COMMON_PROPS.length; i++) {\n        var propItem = SHADOW_STYLE_COMMON_PROPS[i];\n        var styleProp = propItem[0];\n        var ctxProp = propItem[1];\n        var val = style[styleProp];\n        if (!checkCache || val !== prevStyle[styleProp]) {\n            ctx[ctxProp] = fixShadow(ctx, ctxProp, val || propItem[2]);\n        }\n    }\n\n    // `textBaseline` is set as 'middle'.\n    textY += lineHeight / 2;\n\n    var textStrokeWidth = style.textStrokeWidth;\n    var textStrokeWidthPrev = checkCache ? prevStyle.textStrokeWidth : null;\n    var strokeWidthChanged = !checkCache || textStrokeWidth !== textStrokeWidthPrev;\n    var strokeChanged = !checkCache || strokeWidthChanged || style.textStroke !== prevStyle.textStroke;\n    var textStroke = getStroke(style.textStroke, textStrokeWidth);\n    var textFill = getFill(style.textFill);\n\n    if (textStroke) {\n        if (strokeWidthChanged) {\n            ctx.lineWidth = textStrokeWidth;\n        }\n        if (strokeChanged) {\n            ctx.strokeStyle = textStroke;\n        }\n    }\n    if (textFill) {\n        if (!checkCache || style.textFill !== prevStyle.textFill) {\n            ctx.fillStyle = textFill;\n        }\n    }\n\n    // Optimize simply, in most cases only one line exists.\n    if (textLines.length === 1) {\n        // Fill after stroke so the outline will not cover the main part.\n        textStroke && ctx.strokeText(textLines[0], textX, textY);\n        textFill && ctx.fillText(textLines[0], textX, textY);\n    }\n    else {\n        for (var i = 0; i < textLines.length; i++) {\n            // Fill after stroke so the outline will not cover the main part.\n            textStroke && ctx.strokeText(textLines[i], textX, textY);\n            textFill && ctx.fillText(textLines[i], textX, textY);\n            textY += lineHeight;\n        }\n    }\n}\n\nfunction renderRichText(hostEl, ctx, text, style, rect, prevEl) {\n    // Do not do cache for rich text because of the complexity.\n    // But `RectText` this will be restored, do not need to clear other cache like `Style::bind`.\n    if (prevEl !== WILL_BE_RESTORED) {\n        ctx.__attrCachedBy = ContextCachedBy.NONE;\n    }\n\n    var contentBlock = hostEl.__textCotentBlock;\n\n    if (!contentBlock || hostEl.__dirtyText) {\n        contentBlock = hostEl.__textCotentBlock = parseRichText(text, style);\n    }\n\n    drawRichText(hostEl, ctx, contentBlock, style, rect);\n}\n\nfunction drawRichText(hostEl, ctx, contentBlock, style, rect) {\n    var contentWidth = contentBlock.width;\n    var outerWidth = contentBlock.outerWidth;\n    var outerHeight = contentBlock.outerHeight;\n    var textPadding = style.textPadding;\n\n    var boxPos = getBoxPosition(outerHeight, style, rect);\n    var baseX = boxPos.baseX;\n    var baseY = boxPos.baseY;\n    var textAlign = boxPos.textAlign;\n    var textVerticalAlign = boxPos.textVerticalAlign;\n\n    // Origin of textRotation should be the base point of text drawing.\n    applyTextRotation(ctx, style, rect, baseX, baseY);\n\n    var boxX = adjustTextX(baseX, outerWidth, textAlign);\n    var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);\n    var xLeft = boxX;\n    var lineTop = boxY;\n    if (textPadding) {\n        xLeft += textPadding[3];\n        lineTop += textPadding[0];\n    }\n    var xRight = xLeft + contentWidth;\n\n    needDrawBackground(style) && drawBackground(\n        hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight\n    );\n\n    for (var i = 0; i < contentBlock.lines.length; i++) {\n        var line = contentBlock.lines[i];\n        var tokens = line.tokens;\n        var tokenCount = tokens.length;\n        var lineHeight = line.lineHeight;\n        var usedWidth = line.width;\n\n        var leftIndex = 0;\n        var lineXLeft = xLeft;\n        var lineXRight = xRight;\n        var rightIndex = tokenCount - 1;\n        var token;\n\n        while (\n            leftIndex < tokenCount\n            && (token = tokens[leftIndex], !token.textAlign || token.textAlign === 'left')\n        ) {\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft, 'left');\n            usedWidth -= token.width;\n            lineXLeft += token.width;\n            leftIndex++;\n        }\n\n        while (\n            rightIndex >= 0\n            && (token = tokens[rightIndex], token.textAlign === 'right')\n        ) {\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXRight, 'right');\n            usedWidth -= token.width;\n            lineXRight -= token.width;\n            rightIndex--;\n        }\n\n        // The other tokens are placed as textAlign 'center' if there is enough space.\n        lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - usedWidth) / 2;\n        while (leftIndex <= rightIndex) {\n            token = tokens[leftIndex];\n            // Consider width specified by user, use 'center' rather than 'left'.\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center');\n            lineXLeft += token.width;\n            leftIndex++;\n        }\n\n        lineTop += lineHeight;\n    }\n}\n\nfunction applyTextRotation(ctx, style, rect, x, y) {\n    // textRotation only apply in RectText.\n    if (rect && style.textRotation) {\n        var origin = style.textOrigin;\n        if (origin === 'center') {\n            x = rect.width / 2 + rect.x;\n            y = rect.height / 2 + rect.y;\n        }\n        else if (origin) {\n            x = origin[0] + rect.x;\n            y = origin[1] + rect.y;\n        }\n\n        ctx.translate(x, y);\n        // Positive: anticlockwise\n        ctx.rotate(-style.textRotation);\n        ctx.translate(-x, -y);\n    }\n}\n\nfunction placeToken(hostEl, ctx, token, style, lineHeight, lineTop, x, textAlign) {\n    var tokenStyle = style.rich[token.styleName] || {};\n    tokenStyle.text = token.text;\n\n    // 'ctx.textBaseline' is always set as 'middle', for sake of\n    // the bias of \"Microsoft YaHei\".\n    var textVerticalAlign = token.textVerticalAlign;\n    var y = lineTop + lineHeight / 2;\n    if (textVerticalAlign === 'top') {\n        y = lineTop + token.height / 2;\n    }\n    else if (textVerticalAlign === 'bottom') {\n        y = lineTop + lineHeight - token.height / 2;\n    }\n\n    !token.isLineHolder && needDrawBackground(tokenStyle) && drawBackground(\n        hostEl,\n        ctx,\n        tokenStyle,\n        textAlign === 'right'\n            ? x - token.width\n            : textAlign === 'center'\n            ? x - token.width / 2\n            : x,\n        y - token.height / 2,\n        token.width,\n        token.height\n    );\n\n    var textPadding = token.textPadding;\n    if (textPadding) {\n        x = getTextXForPadding(x, textAlign, textPadding);\n        y -= token.height / 2 - textPadding[2] - token.textHeight / 2;\n    }\n\n    setCtx(ctx, 'shadowBlur', retrieve3(tokenStyle.textShadowBlur, style.textShadowBlur, 0));\n    setCtx(ctx, 'shadowColor', tokenStyle.textShadowColor || style.textShadowColor || 'transparent');\n    setCtx(ctx, 'shadowOffsetX', retrieve3(tokenStyle.textShadowOffsetX, style.textShadowOffsetX, 0));\n    setCtx(ctx, 'shadowOffsetY', retrieve3(tokenStyle.textShadowOffsetY, style.textShadowOffsetY, 0));\n\n    setCtx(ctx, 'textAlign', textAlign);\n    // Force baseline to be \"middle\". Otherwise, if using \"top\", the\n    // text will offset downward a little bit in font \"Microsoft YaHei\".\n    setCtx(ctx, 'textBaseline', 'middle');\n\n    setCtx(ctx, 'font', token.font || DEFAULT_FONT);\n\n    var textStroke = getStroke(tokenStyle.textStroke || style.textStroke, textStrokeWidth);\n    var textFill = getFill(tokenStyle.textFill || style.textFill);\n    var textStrokeWidth = retrieve2(tokenStyle.textStrokeWidth, style.textStrokeWidth);\n\n    // Fill after stroke so the outline will not cover the main part.\n    if (textStroke) {\n        setCtx(ctx, 'lineWidth', textStrokeWidth);\n        setCtx(ctx, 'strokeStyle', textStroke);\n        ctx.strokeText(token.text, x, y);\n    }\n    if (textFill) {\n        setCtx(ctx, 'fillStyle', textFill);\n        ctx.fillText(token.text, x, y);\n    }\n}\n\nfunction needDrawBackground(style) {\n    return !!(\n        style.textBackgroundColor\n        || (style.textBorderWidth && style.textBorderColor)\n    );\n}\n\n// style: {textBackgroundColor, textBorderWidth, textBorderColor, textBorderRadius, text}\n// shape: {x, y, width, height}\nfunction drawBackground(hostEl, ctx, style, x, y, width, height) {\n    var textBackgroundColor = style.textBackgroundColor;\n    var textBorderWidth = style.textBorderWidth;\n    var textBorderColor = style.textBorderColor;\n    var isPlainBg = isString(textBackgroundColor);\n\n    setCtx(ctx, 'shadowBlur', style.textBoxShadowBlur || 0);\n    setCtx(ctx, 'shadowColor', style.textBoxShadowColor || 'transparent');\n    setCtx(ctx, 'shadowOffsetX', style.textBoxShadowOffsetX || 0);\n    setCtx(ctx, 'shadowOffsetY', style.textBoxShadowOffsetY || 0);\n\n    if (isPlainBg || (textBorderWidth && textBorderColor)) {\n        ctx.beginPath();\n        var textBorderRadius = style.textBorderRadius;\n        if (!textBorderRadius) {\n            ctx.rect(x, y, width, height);\n        }\n        else {\n            buildPath(ctx, {\n                x: x, y: y, width: width, height: height, r: textBorderRadius\n            });\n        }\n        ctx.closePath();\n    }\n\n    if (isPlainBg) {\n        setCtx(ctx, 'fillStyle', textBackgroundColor);\n\n        if (style.fillOpacity != null) {\n            var originalGlobalAlpha = ctx.globalAlpha;\n            ctx.globalAlpha = style.fillOpacity * style.opacity;\n            ctx.fill();\n            ctx.globalAlpha = originalGlobalAlpha;\n        }\n        else {\n            ctx.fill();\n        }\n    }\n    else if (isObject$1(textBackgroundColor)) {\n        var image = textBackgroundColor.image;\n\n        image = createOrUpdateImage(\n            image, null, hostEl, onBgImageLoaded, textBackgroundColor\n        );\n        if (image && isImageReady(image)) {\n            ctx.drawImage(image, x, y, width, height);\n        }\n    }\n\n    if (textBorderWidth && textBorderColor) {\n        setCtx(ctx, 'lineWidth', textBorderWidth);\n        setCtx(ctx, 'strokeStyle', textBorderColor);\n\n        if (style.strokeOpacity != null) {\n            var originalGlobalAlpha = ctx.globalAlpha;\n            ctx.globalAlpha = style.strokeOpacity * style.opacity;\n            ctx.stroke();\n            ctx.globalAlpha = originalGlobalAlpha;\n        }\n        else {\n            ctx.stroke();\n        }\n    }\n}\n\nfunction onBgImageLoaded(image, textBackgroundColor) {\n    // Replace image, so that `contain/text.js#parseRichText`\n    // will get correct result in next tick.\n    textBackgroundColor.image = image;\n}\n\nfunction getBoxPosition(blockHeiht, style, rect) {\n    var baseX = style.x || 0;\n    var baseY = style.y || 0;\n    var textAlign = style.textAlign;\n    var textVerticalAlign = style.textVerticalAlign;\n\n    // Text position represented by coord\n    if (rect) {\n        var textPosition = style.textPosition;\n        if (textPosition instanceof Array) {\n            // Percent\n            baseX = rect.x + parsePercent(textPosition[0], rect.width);\n            baseY = rect.y + parsePercent(textPosition[1], rect.height);\n        }\n        else {\n            var res = adjustTextPositionOnRect(\n                textPosition, rect, style.textDistance\n            );\n            baseX = res.x;\n            baseY = res.y;\n            // Default align and baseline when has textPosition\n            textAlign = textAlign || res.textAlign;\n            textVerticalAlign = textVerticalAlign || res.textVerticalAlign;\n        }\n\n        // textOffset is only support in RectText, otherwise\n        // we have to adjust boundingRect for textOffset.\n        var textOffset = style.textOffset;\n        if (textOffset) {\n            baseX += textOffset[0];\n            baseY += textOffset[1];\n        }\n    }\n\n    return {\n        baseX: baseX,\n        baseY: baseY,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\nfunction setCtx(ctx, prop, value) {\n    ctx[prop] = fixShadow(ctx, prop, value);\n    return ctx[prop];\n}\n\n/**\n * @param {string} [stroke] If specified, do not check style.textStroke.\n * @param {string} [lineWidth] If specified, do not check style.textStroke.\n * @param {number} style\n */\nfunction getStroke(stroke, lineWidth) {\n    return (stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none')\n        ? null\n        // TODO pattern and gradient?\n        : (stroke.image || stroke.colorStops)\n        ? '#000'\n        : stroke;\n}\n\nfunction getFill(fill) {\n    return (fill == null || fill === 'none')\n        ? null\n        // TODO pattern and gradient?\n        : (fill.image || fill.colorStops)\n        ? '#000'\n        : fill;\n}\n\nfunction parsePercent(value, maxValue) {\n    if (typeof value === 'string') {\n        if (value.lastIndexOf('%') >= 0) {\n            return parseFloat(value) / 100 * maxValue;\n        }\n        return parseFloat(value);\n    }\n    return value;\n}\n\nfunction getTextXForPadding(x, textAlign, textPadding) {\n    return textAlign === 'right'\n        ? (x - textPadding[1])\n        : textAlign === 'center'\n        ? (x + textPadding[3] / 2 - textPadding[1] / 2)\n        : (x + textPadding[3]);\n}\n\n/**\n * @param {string} text\n * @param {module:zrender/Style} style\n * @return {boolean}\n */\nfunction needDrawText(text, style) {\n    return text != null\n        && (text\n            || style.textBackgroundColor\n            || (style.textBorderWidth && style.textBorderColor)\n            || style.textPadding\n        );\n}\n\n/**\n * Mixin for drawing text in a element bounding rect\n * @module zrender/mixin/RectText\n */\n\nvar tmpRect$1 = new BoundingRect();\n\nvar RectText = function () {};\n\nRectText.prototype = {\n\n    constructor: RectText,\n\n    /**\n     * Draw text in a rect with specified position.\n     * @param  {CanvasRenderingContext2D} ctx\n     * @param  {Object} rect Displayable rect\n     */\n    drawRectText: function (ctx, rect) {\n        var style = this.style;\n\n        rect = style.textRect || rect;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        var text = style.text;\n\n        // Convert to string\n        text != null && (text += '');\n\n        if (!needDrawText(text, style)) {\n            return;\n        }\n\n        // FIXME\n        // Do not provide prevEl to `textHelper.renderText` for ctx prop cache,\n        // but use `ctx.save()` and `ctx.restore()`. Because the cache for rect\n        // text propably break the cache for its host elements.\n        ctx.save();\n\n        // Transform rect to view space\n        var transform = this.transform;\n        if (!style.transformText) {\n            if (transform) {\n                tmpRect$1.copy(rect);\n                tmpRect$1.applyTransform(transform);\n                rect = tmpRect$1;\n            }\n        }\n        else {\n            this.setTransform(ctx);\n        }\n\n        // transformText and textRotation can not be used at the same time.\n        renderText(this, ctx, text, style, rect, WILL_BE_RESTORED);\n\n        ctx.restore();\n    }\n};\n\n/**\n * 可绘制的图形基类\n * Base class of all displayable graphic objects\n * @module zrender/graphic/Displayable\n */\n\n\n/**\n * @alias module:zrender/graphic/Displayable\n * @extends module:zrender/Element\n * @extends module:zrender/graphic/mixin/RectText\n */\nfunction Displayable(opts) {\n\n    opts = opts || {};\n\n    Element.call(this, opts);\n\n    // Extend properties\n    for (var name in opts) {\n        if (\n            opts.hasOwnProperty(name)\n                && name !== 'style'\n        ) {\n            this[name] = opts[name];\n        }\n    }\n\n    /**\n     * @type {module:zrender/graphic/Style}\n     */\n    this.style = new Style(opts.style, this);\n\n    this._rect = null;\n    // Shapes for cascade clipping.\n    this.__clipPaths = [];\n\n    // FIXME Stateful must be mixined after style is setted\n    // Stateful.call(this, opts);\n}\n\nDisplayable.prototype = {\n\n    constructor: Displayable,\n\n    type: 'displayable',\n\n    /**\n     * Displayable 是否为脏，Painter 中会根据该标记判断是否需要是否需要重新绘制\n     * Dirty flag. From which painter will determine if this displayable object needs brush\n     * @name module:zrender/graphic/Displayable#__dirty\n     * @type {boolean}\n     */\n    __dirty: true,\n\n    /**\n     * 图形是否可见，为true时不绘制图形，但是仍能触发鼠标事件\n     * If ignore drawing of the displayable object. Mouse event will still be triggered\n     * @name module:/zrender/graphic/Displayable#invisible\n     * @type {boolean}\n     * @default false\n     */\n    invisible: false,\n\n    /**\n     * @name module:/zrender/graphic/Displayable#z\n     * @type {number}\n     * @default 0\n     */\n    z: 0,\n\n    /**\n     * @name module:/zrender/graphic/Displayable#z\n     * @type {number}\n     * @default 0\n     */\n    z2: 0,\n\n    /**\n     * z层level，决定绘画在哪层canvas中\n     * @name module:/zrender/graphic/Displayable#zlevel\n     * @type {number}\n     * @default 0\n     */\n    zlevel: 0,\n\n    /**\n     * 是否可拖拽\n     * @name module:/zrender/graphic/Displayable#draggable\n     * @type {boolean}\n     * @default false\n     */\n    draggable: false,\n\n    /**\n     * 是否正在拖拽\n     * @name module:/zrender/graphic/Displayable#draggable\n     * @type {boolean}\n     * @default false\n     */\n    dragging: false,\n\n    /**\n     * 是否相应鼠标事件\n     * @name module:/zrender/graphic/Displayable#silent\n     * @type {boolean}\n     * @default false\n     */\n    silent: false,\n\n    /**\n     * If enable culling\n     * @type {boolean}\n     * @default false\n     */\n    culling: false,\n\n    /**\n     * Mouse cursor when hovered\n     * @name module:/zrender/graphic/Displayable#cursor\n     * @type {string}\n     */\n    cursor: 'pointer',\n\n    /**\n     * If hover area is bounding rect\n     * @name module:/zrender/graphic/Displayable#rectHover\n     * @type {string}\n     */\n    rectHover: false,\n\n    /**\n     * Render the element progressively when the value >= 0,\n     * usefull for large data.\n     * @type {boolean}\n     */\n    progressive: false,\n\n    /**\n     * @type {boolean}\n     */\n    incremental: false,\n    /**\n     * Scale ratio for global scale.\n     * @type {boolean}\n     */\n    globalScaleRatio: 1,\n\n    beforeBrush: function (ctx) {},\n\n    afterBrush: function (ctx) {},\n\n    /**\n     * 图形绘制方法\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    // Interface\n    brush: function (ctx, prevEl) {},\n\n    /**\n     * 获取最小包围盒\n     * @return {module:zrender/core/BoundingRect}\n     */\n    // Interface\n    getBoundingRect: function () {},\n\n    /**\n     * 判断坐标 x, y 是否在图形上\n     * If displayable element contain coord x, y\n     * @param  {number} x\n     * @param  {number} y\n     * @return {boolean}\n     */\n    contain: function (x, y) {\n        return this.rectContain(x, y);\n    },\n\n    /**\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {\n        cb.call(context, this);\n    },\n\n    /**\n     * 判断坐标 x, y 是否在图形的包围盒上\n     * If bounding rect of element contain coord x, y\n     * @param  {number} x\n     * @param  {number} y\n     * @return {boolean}\n     */\n    rectContain: function (x, y) {\n        var coord = this.transformCoordToLocal(x, y);\n        var rect = this.getBoundingRect();\n        return rect.contain(coord[0], coord[1]);\n    },\n\n    /**\n     * 标记图形元素为脏，并且在下一帧重绘\n     * Mark displayable element dirty and refresh next frame\n     */\n    dirty: function () {\n        this.__dirty = this.__dirtyText = true;\n\n        this._rect = null;\n\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * 图形是否会触发事件\n     * If displayable object binded any event\n     * @return {boolean}\n     */\n    // TODO, 通过 bind 绑定的事件\n    // isSilent: function () {\n    //     return !(\n    //         this.hoverable || this.draggable\n    //         || this.onmousemove || this.onmouseover || this.onmouseout\n    //         || this.onmousedown || this.onmouseup || this.onclick\n    //         || this.ondragenter || this.ondragover || this.ondragleave\n    //         || this.ondrop\n    //     );\n    // },\n    /**\n     * Alias for animate('style')\n     * @param {boolean} loop\n     */\n    animateStyle: function (loop) {\n        return this.animate('style', loop);\n    },\n\n    attrKV: function (key, value) {\n        if (key !== 'style') {\n            Element.prototype.attrKV.call(this, key, value);\n        }\n        else {\n            this.style.set(value);\n        }\n    },\n\n    /**\n     * @param {Object|string} key\n     * @param {*} value\n     */\n    setStyle: function (key, value) {\n        this.style.set(key, value);\n        this.dirty(false);\n        return this;\n    },\n\n    /**\n     * Use given style object\n     * @param  {Object} obj\n     */\n    useStyle: function (obj) {\n        this.style = new Style(obj, this);\n        this.dirty(false);\n        return this;\n    }\n};\n\ninherits(Displayable, Element);\n\nmixin(Displayable, RectText);\n\n/**\n * @alias zrender/graphic/Image\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nfunction ZImage(opts) {\n    Displayable.call(this, opts);\n}\n\nZImage.prototype = {\n\n    constructor: ZImage,\n\n    type: 'image',\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n        var src = style.image;\n\n        // Must bind each time\n        style.bind(ctx, this, prevEl);\n\n        var image = this._image = createOrUpdateImage(\n            src,\n            this._image,\n            this,\n            this.onload\n        );\n\n        if (!image || !isImageReady(image)) {\n            return;\n        }\n\n        // 图片已经加载完成\n        // if (image.nodeName.toUpperCase() == 'IMG') {\n        //     if (!image.complete) {\n        //         return;\n        //     }\n        // }\n        // Else is canvas\n\n        var x = style.x || 0;\n        var y = style.y || 0;\n        var width = style.width;\n        var height = style.height;\n        var aspect = image.width / image.height;\n        if (width == null && height != null) {\n            // Keep image/height ratio\n            width = height * aspect;\n        }\n        else if (height == null && width != null) {\n            height = width / aspect;\n        }\n        else if (width == null && height == null) {\n            width = image.width;\n            height = image.height;\n        }\n\n        // 设置transform\n        this.setTransform(ctx);\n\n        if (style.sWidth && style.sHeight) {\n            var sx = style.sx || 0;\n            var sy = style.sy || 0;\n            ctx.drawImage(\n                image,\n                sx, sy, style.sWidth, style.sHeight,\n                x, y, width, height\n            );\n        }\n        else if (style.sx && style.sy) {\n            var sx = style.sx;\n            var sy = style.sy;\n            var sWidth = width - sx;\n            var sHeight = height - sy;\n            ctx.drawImage(\n                image,\n                sx, sy, sWidth, sHeight,\n                x, y, width, height\n            );\n        }\n        else {\n            ctx.drawImage(image, x, y, width, height);\n        }\n\n        // Draw rect text\n        if (style.text != null) {\n            // Only restore transform when needs draw text.\n            this.restoreTransform(ctx);\n            this.drawRectText(ctx, this.getBoundingRect());\n        }\n    },\n\n    getBoundingRect: function () {\n        var style = this.style;\n        if (!this._rect) {\n            this._rect = new BoundingRect(\n                style.x || 0, style.y || 0, style.width || 0, style.height || 0\n            );\n        }\n        return this._rect;\n    }\n};\n\ninherits(ZImage, Displayable);\n\nvar HOVER_LAYER_ZLEVEL = 1e5;\nvar CANVAS_ZLEVEL = 314159;\n\nvar EL_AFTER_INCREMENTAL_INC = 0.01;\nvar INCREMENTAL_INC = 0.001;\n\nfunction parseInt10(val) {\n    return parseInt(val, 10);\n}\n\nfunction isLayerValid(layer) {\n    if (!layer) {\n        return false;\n    }\n\n    if (layer.__builtin__) {\n        return true;\n    }\n\n    if (typeof (layer.resize) !== 'function'\n        || typeof (layer.refresh) !== 'function'\n    ) {\n        return false;\n    }\n\n    return true;\n}\n\nvar tmpRect = new BoundingRect(0, 0, 0, 0);\nvar viewRect = new BoundingRect(0, 0, 0, 0);\nfunction isDisplayableCulled(el, width, height) {\n    tmpRect.copy(el.getBoundingRect());\n    if (el.transform) {\n        tmpRect.applyTransform(el.transform);\n    }\n    viewRect.width = width;\n    viewRect.height = height;\n    return !tmpRect.intersect(viewRect);\n}\n\nfunction isClipPathChanged(clipPaths, prevClipPaths) {\n    if (clipPaths === prevClipPaths) { // Can both be null or undefined\n        return false;\n    }\n\n    if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) {\n        return true;\n    }\n    for (var i = 0; i < clipPaths.length; i++) {\n        if (clipPaths[i] !== prevClipPaths[i]) {\n            return true;\n        }\n    }\n}\n\nfunction doClip(clipPaths, ctx) {\n    for (var i = 0; i < clipPaths.length; i++) {\n        var clipPath = clipPaths[i];\n\n        clipPath.setTransform(ctx);\n        ctx.beginPath();\n        clipPath.buildPath(ctx, clipPath.shape);\n        ctx.clip();\n        // Transform back\n        clipPath.restoreTransform(ctx);\n    }\n}\n\nfunction createRoot(width, height) {\n    var domRoot = document.createElement('div');\n\n    // domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬\n    domRoot.style.cssText = [\n        'position:relative',\n        'overflow:hidden',\n        'width:' + width + 'px',\n        'height:' + height + 'px',\n        'padding:0',\n        'margin:0',\n        'border-width:0'\n    ].join(';') + ';';\n\n    return domRoot;\n}\n\n\n/**\n * @alias module:zrender/Painter\n * @constructor\n * @param {HTMLElement} root 绘图容器\n * @param {module:zrender/Storage} storage\n * @param {Object} opts\n */\nvar Painter = function (root, storage, opts) {\n\n    this.type = 'canvas';\n\n    // In node environment using node-canvas\n    var singleCanvas = !root.nodeName // In node ?\n        || root.nodeName.toUpperCase() === 'CANVAS';\n\n    this._opts = opts = extend({}, opts || {});\n\n    /**\n     * @type {number}\n     */\n    this.dpr = opts.devicePixelRatio || devicePixelRatio;\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._singleCanvas = singleCanvas;\n    /**\n     * 绘图容器\n     * @type {HTMLElement}\n     */\n    this.root = root;\n\n    var rootStyle = root.style;\n\n    if (rootStyle) {\n        rootStyle['-webkit-tap-highlight-color'] = 'transparent';\n        rootStyle['-webkit-user-select'] =\n        rootStyle['user-select'] =\n        rootStyle['-webkit-touch-callout'] = 'none';\n\n        root.innerHTML = '';\n    }\n\n    /**\n     * @type {module:zrender/Storage}\n     */\n    this.storage = storage;\n\n    /**\n     * @type {Array.<number>}\n     * @private\n     */\n    var zlevelList = this._zlevelList = [];\n\n    /**\n     * @type {Object.<string, module:zrender/Layer>}\n     * @private\n     */\n    var layers = this._layers = {};\n\n    /**\n     * @type {Object.<string, Object>}\n     * @private\n     */\n    this._layerConfig = {};\n\n    /**\n     * zrender will do compositing when root is a canvas and have multiple zlevels.\n     */\n    this._needsManuallyCompositing = false;\n\n    if (!singleCanvas) {\n        this._width = this._getSize(0);\n        this._height = this._getSize(1);\n\n        var domRoot = this._domRoot = createRoot(\n            this._width, this._height\n        );\n        root.appendChild(domRoot);\n    }\n    else {\n        var width = root.width;\n        var height = root.height;\n\n        if (opts.width != null) {\n            width = opts.width;\n        }\n        if (opts.height != null) {\n            height = opts.height;\n        }\n        this.dpr = opts.devicePixelRatio || 1;\n\n        // Use canvas width and height directly\n        root.width = width * this.dpr;\n        root.height = height * this.dpr;\n\n        this._width = width;\n        this._height = height;\n\n        // Create layer if only one given canvas\n        // Device can be specified to create a high dpi image.\n        var mainLayer = new Layer(root, this, this.dpr);\n        mainLayer.__builtin__ = true;\n        mainLayer.initContext();\n        // FIXME Use canvas width and height\n        // mainLayer.resize(width, height);\n        layers[CANVAS_ZLEVEL] = mainLayer;\n        mainLayer.zlevel = CANVAS_ZLEVEL;\n        // Not use common zlevel.\n        zlevelList.push(CANVAS_ZLEVEL);\n\n        this._domRoot = root;\n    }\n\n    /**\n     * @type {module:zrender/Layer}\n     * @private\n     */\n    this._hoverlayer = null;\n\n    this._hoverElements = [];\n};\n\nPainter.prototype = {\n\n    constructor: Painter,\n\n    getType: function () {\n        return 'canvas';\n    },\n\n    /**\n     * If painter use a single canvas\n     * @return {boolean}\n     */\n    isSingleCanvas: function () {\n        return this._singleCanvas;\n    },\n    /**\n     * @return {HTMLDivElement}\n     */\n    getViewportRoot: function () {\n        return this._domRoot;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    /**\n     * 刷新\n     * @param {boolean} [paintAll=false] 强制绘制所有displayable\n     */\n    refresh: function (paintAll) {\n\n        var list = this.storage.getDisplayList(true);\n\n        var zlevelList = this._zlevelList;\n\n        this._redrawId = Math.random();\n\n        this._paintList(list, paintAll, this._redrawId);\n\n        // Paint custum layers\n        for (var i = 0; i < zlevelList.length; i++) {\n            var z = zlevelList[i];\n            var layer = this._layers[z];\n            if (!layer.__builtin__ && layer.refresh) {\n                var clearColor = i === 0 ? this._backgroundColor : null;\n                layer.refresh(clearColor);\n            }\n        }\n\n        this.refreshHover();\n\n        return this;\n    },\n\n    addHover: function (el, hoverStyle) {\n        if (el.__hoverMir) {\n            return;\n        }\n        var elMirror = new el.constructor({\n            style: el.style,\n            shape: el.shape,\n            z: el.z,\n            z2: el.z2,\n            silent: el.silent\n        });\n        elMirror.__from = el;\n        el.__hoverMir = elMirror;\n        hoverStyle && elMirror.setStyle(hoverStyle);\n        this._hoverElements.push(elMirror);\n\n        return elMirror;\n    },\n\n    removeHover: function (el) {\n        var elMirror = el.__hoverMir;\n        var hoverElements = this._hoverElements;\n        var idx = indexOf(hoverElements, elMirror);\n        if (idx >= 0) {\n            hoverElements.splice(idx, 1);\n        }\n        el.__hoverMir = null;\n    },\n\n    clearHover: function (el) {\n        var hoverElements = this._hoverElements;\n        for (var i = 0; i < hoverElements.length; i++) {\n            var from = hoverElements[i].__from;\n            if (from) {\n                from.__hoverMir = null;\n            }\n        }\n        hoverElements.length = 0;\n    },\n\n    refreshHover: function () {\n        var hoverElements = this._hoverElements;\n        var len = hoverElements.length;\n        var hoverLayer = this._hoverlayer;\n        hoverLayer && hoverLayer.clear();\n\n        if (!len) {\n            return;\n        }\n        sort(hoverElements, this.storage.displayableSortFunc);\n\n        // Use a extream large zlevel\n        // FIXME?\n        if (!hoverLayer) {\n            hoverLayer = this._hoverlayer = this.getLayer(HOVER_LAYER_ZLEVEL);\n        }\n\n        var scope = {};\n        hoverLayer.ctx.save();\n        for (var i = 0; i < len;) {\n            var el = hoverElements[i];\n            var originalEl = el.__from;\n            // Original el is removed\n            // PENDING\n            if (!(originalEl && originalEl.__zr)) {\n                hoverElements.splice(i, 1);\n                originalEl.__hoverMir = null;\n                len--;\n                continue;\n            }\n            i++;\n\n            // Use transform\n            // FIXME style and shape ?\n            if (!originalEl.invisible) {\n                el.transform = originalEl.transform;\n                el.invTransform = originalEl.invTransform;\n                el.__clipPaths = originalEl.__clipPaths;\n                // el.\n                this._doPaintEl(el, hoverLayer, true, scope);\n            }\n        }\n\n        hoverLayer.ctx.restore();\n    },\n\n    getHoverLayer: function () {\n        return this.getLayer(HOVER_LAYER_ZLEVEL);\n    },\n\n    _paintList: function (list, paintAll, redrawId) {\n        if (this._redrawId !== redrawId) {\n            return;\n        }\n\n        paintAll = paintAll || false;\n\n        this._updateLayerStatus(list);\n\n        var finished = this._doPaintList(list, paintAll);\n\n        if (this._needsManuallyCompositing) {\n            this._compositeManually();\n        }\n\n        if (!finished) {\n            var self = this;\n            requestAnimationFrame(function () {\n                self._paintList(list, paintAll, redrawId);\n            });\n        }\n    },\n\n    _compositeManually: function () {\n        var ctx = this.getLayer(CANVAS_ZLEVEL).ctx;\n        var width = this._domRoot.width;\n        var height = this._domRoot.height;\n        ctx.clearRect(0, 0, width, height);\n        // PENDING, If only builtin layer?\n        this.eachBuiltinLayer(function (layer) {\n            if (layer.virtual) {\n                ctx.drawImage(layer.dom, 0, 0, width, height);\n            }\n        });\n    },\n\n    _doPaintList: function (list, paintAll) {\n        var layerList = [];\n        for (var zi = 0; zi < this._zlevelList.length; zi++) {\n            var zlevel = this._zlevelList[zi];\n            var layer = this._layers[zlevel];\n            if (layer.__builtin__\n                && layer !== this._hoverlayer\n                && (layer.__dirty || paintAll)\n            ) {\n                layerList.push(layer);\n            }\n        }\n\n        var finished = true;\n\n        for (var k = 0; k < layerList.length; k++) {\n            var layer = layerList[k];\n            var ctx = layer.ctx;\n            var scope = {};\n            ctx.save();\n\n            var start = paintAll ? layer.__startIndex : layer.__drawIndex;\n\n            var useTimer = !paintAll && layer.incremental && Date.now;\n            var startTime = useTimer && Date.now();\n\n            var clearColor = layer.zlevel === this._zlevelList[0]\n                ? this._backgroundColor : null;\n            // All elements in this layer are cleared.\n            if (layer.__startIndex === layer.__endIndex) {\n                layer.clear(false, clearColor);\n            }\n            else if (start === layer.__startIndex) {\n                var firstEl = list[start];\n                if (!firstEl.incremental || !firstEl.notClear || paintAll) {\n                    layer.clear(false, clearColor);\n                }\n            }\n            if (start === -1) {\n                console.error('For some unknown reason. drawIndex is -1');\n                start = layer.__startIndex;\n            }\n            for (var i = start; i < layer.__endIndex; i++) {\n                var el = list[i];\n                this._doPaintEl(el, layer, paintAll, scope);\n                el.__dirty = el.__dirtyText = false;\n\n                if (useTimer) {\n                    // Date.now can be executed in 13,025,305 ops/second.\n                    var dTime = Date.now() - startTime;\n                    // Give 15 millisecond to draw.\n                    // The rest elements will be drawn in the next frame.\n                    if (dTime > 15) {\n                        break;\n                    }\n                }\n            }\n\n            layer.__drawIndex = i;\n\n            if (layer.__drawIndex < layer.__endIndex) {\n                finished = false;\n            }\n\n            if (scope.prevElClipPaths) {\n                // Needs restore the state. If last drawn element is in the clipping area.\n                ctx.restore();\n            }\n\n            ctx.restore();\n        }\n\n        if (env$1.wxa) {\n            // Flush for weixin application\n            each$1(this._layers, function (layer) {\n                if (layer && layer.ctx && layer.ctx.draw) {\n                    layer.ctx.draw();\n                }\n            });\n        }\n\n        return finished;\n    },\n\n    _doPaintEl: function (el, currentLayer, forcePaint, scope) {\n        var ctx = currentLayer.ctx;\n        var m = el.transform;\n        if (\n            (currentLayer.__dirty || forcePaint)\n            // Ignore invisible element\n            && !el.invisible\n            // Ignore transparent element\n            && el.style.opacity !== 0\n            // Ignore scale 0 element, in some environment like node-canvas\n            // Draw a scale 0 element can cause all following draw wrong\n            // And setTransform with scale 0 will cause set back transform failed.\n            && !(m && !m[0] && !m[3])\n            // Ignore culled element\n            && !(el.culling && isDisplayableCulled(el, this._width, this._height))\n        ) {\n\n            var clipPaths = el.__clipPaths;\n\n            // Optimize when clipping on group with several elements\n            if (!scope.prevElClipPaths\n                || isClipPathChanged(clipPaths, scope.prevElClipPaths)\n            ) {\n                // If has previous clipping state, restore from it\n                if (scope.prevElClipPaths) {\n                    currentLayer.ctx.restore();\n                    scope.prevElClipPaths = null;\n\n                    // Reset prevEl since context has been restored\n                    scope.prevEl = null;\n                }\n                // New clipping state\n                if (clipPaths) {\n                    ctx.save();\n                    doClip(clipPaths, ctx);\n                    scope.prevElClipPaths = clipPaths;\n                }\n            }\n            el.beforeBrush && el.beforeBrush(ctx);\n\n            el.brush(ctx, scope.prevEl || null);\n            scope.prevEl = el;\n\n            el.afterBrush && el.afterBrush(ctx);\n        }\n    },\n\n    /**\n     * 获取 zlevel 所在层，如果不存在则会创建一个新的层\n     * @param {number} zlevel\n     * @param {boolean} virtual Virtual layer will not be inserted into dom.\n     * @return {module:zrender/Layer}\n     */\n    getLayer: function (zlevel, virtual) {\n        if (this._singleCanvas && !this._needsManuallyCompositing) {\n            zlevel = CANVAS_ZLEVEL;\n        }\n        var layer = this._layers[zlevel];\n        if (!layer) {\n            // Create a new layer\n            layer = new Layer('zr_' + zlevel, this, this.dpr);\n            layer.zlevel = zlevel;\n            layer.__builtin__ = true;\n\n            if (this._layerConfig[zlevel]) {\n                merge(layer, this._layerConfig[zlevel], true);\n            }\n\n            if (virtual) {\n                layer.virtual = virtual;\n            }\n\n            this.insertLayer(zlevel, layer);\n\n            // Context is created after dom inserted to document\n            // Or excanvas will get 0px clientWidth and clientHeight\n            layer.initContext();\n        }\n\n        return layer;\n    },\n\n    insertLayer: function (zlevel, layer) {\n\n        var layersMap = this._layers;\n        var zlevelList = this._zlevelList;\n        var len = zlevelList.length;\n        var prevLayer = null;\n        var i = -1;\n        var domRoot = this._domRoot;\n\n        if (layersMap[zlevel]) {\n            zrLog('ZLevel ' + zlevel + ' has been used already');\n            return;\n        }\n        // Check if is a valid layer\n        if (!isLayerValid(layer)) {\n            zrLog('Layer of zlevel ' + zlevel + ' is not valid');\n            return;\n        }\n\n        if (len > 0 && zlevel > zlevelList[0]) {\n            for (i = 0; i < len - 1; i++) {\n                if (\n                    zlevelList[i] < zlevel\n                    && zlevelList[i + 1] > zlevel\n                ) {\n                    break;\n                }\n            }\n            prevLayer = layersMap[zlevelList[i]];\n        }\n        zlevelList.splice(i + 1, 0, zlevel);\n\n        layersMap[zlevel] = layer;\n\n        // Vitual layer will not directly show on the screen.\n        // (It can be a WebGL layer and assigned to a ZImage element)\n        // But it still under management of zrender.\n        if (!layer.virtual) {\n            if (prevLayer) {\n                var prevDom = prevLayer.dom;\n                if (prevDom.nextSibling) {\n                    domRoot.insertBefore(\n                        layer.dom,\n                        prevDom.nextSibling\n                    );\n                }\n                else {\n                    domRoot.appendChild(layer.dom);\n                }\n            }\n            else {\n                if (domRoot.firstChild) {\n                    domRoot.insertBefore(layer.dom, domRoot.firstChild);\n                }\n                else {\n                    domRoot.appendChild(layer.dom);\n                }\n            }\n        }\n    },\n\n    // Iterate each layer\n    eachLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            cb.call(context, this._layers[z], z);\n        }\n    },\n\n    // Iterate each buildin layer\n    eachBuiltinLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var layer;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            layer = this._layers[z];\n            if (layer.__builtin__) {\n                cb.call(context, layer, z);\n            }\n        }\n    },\n\n    // Iterate each other layer except buildin layer\n    eachOtherLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var layer;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            layer = this._layers[z];\n            if (!layer.__builtin__) {\n                cb.call(context, layer, z);\n            }\n        }\n    },\n\n    /**\n     * 获取所有已创建的层\n     * @param {Array.<module:zrender/Layer>} [prevLayer]\n     */\n    getLayers: function () {\n        return this._layers;\n    },\n\n    _updateLayerStatus: function (list) {\n\n        this.eachBuiltinLayer(function (layer, z) {\n            layer.__dirty = layer.__used = false;\n        });\n\n        function updatePrevLayer(idx) {\n            if (prevLayer) {\n                if (prevLayer.__endIndex !== idx) {\n                    prevLayer.__dirty = true;\n                }\n                prevLayer.__endIndex = idx;\n            }\n        }\n\n        if (this._singleCanvas) {\n            for (var i = 1; i < list.length; i++) {\n                var el = list[i];\n                if (el.zlevel !== list[i - 1].zlevel || el.incremental) {\n                    this._needsManuallyCompositing = true;\n                    break;\n                }\n            }\n        }\n\n        var prevLayer = null;\n        var incrementalLayerCount = 0;\n        for (var i = 0; i < list.length; i++) {\n            var el = list[i];\n            var zlevel = el.zlevel;\n            var layer;\n            // PENDING If change one incremental element style ?\n            // TODO Where there are non-incremental elements between incremental elements.\n            if (el.incremental) {\n                layer = this.getLayer(zlevel + INCREMENTAL_INC, this._needsManuallyCompositing);\n                layer.incremental = true;\n                incrementalLayerCount = 1;\n            }\n            else {\n                layer = this.getLayer(zlevel + (incrementalLayerCount > 0 ? EL_AFTER_INCREMENTAL_INC : 0), this._needsManuallyCompositing);\n            }\n\n            if (!layer.__builtin__) {\n                zrLog('ZLevel ' + zlevel + ' has been used by unkown layer ' + layer.id);\n            }\n\n            if (layer !== prevLayer) {\n                layer.__used = true;\n                if (layer.__startIndex !== i) {\n                    layer.__dirty = true;\n                }\n                layer.__startIndex = i;\n                if (!layer.incremental) {\n                    layer.__drawIndex = i;\n                }\n                else {\n                    // Mark layer draw index needs to update.\n                    layer.__drawIndex = -1;\n                }\n                updatePrevLayer(i);\n                prevLayer = layer;\n            }\n            if (el.__dirty) {\n                layer.__dirty = true;\n                if (layer.incremental && layer.__drawIndex < 0) {\n                    // Start draw from the first dirty element.\n                    layer.__drawIndex = i;\n                }\n            }\n        }\n\n        updatePrevLayer(i);\n\n        this.eachBuiltinLayer(function (layer, z) {\n            // Used in last frame but not in this frame. Needs clear\n            if (!layer.__used && layer.getElementCount() > 0) {\n                layer.__dirty = true;\n                layer.__startIndex = layer.__endIndex = layer.__drawIndex = 0;\n            }\n            // For incremental layer. In case start index changed and no elements are dirty.\n            if (layer.__dirty && layer.__drawIndex < 0) {\n                layer.__drawIndex = layer.__startIndex;\n            }\n        });\n    },\n\n    /**\n     * 清除hover层外所有内容\n     */\n    clear: function () {\n        this.eachBuiltinLayer(this._clearLayer);\n        return this;\n    },\n\n    _clearLayer: function (layer) {\n        layer.clear();\n    },\n\n    setBackgroundColor: function (backgroundColor) {\n        this._backgroundColor = backgroundColor;\n    },\n\n    /**\n     * 修改指定zlevel的绘制参数\n     *\n     * @param {string} zlevel\n     * @param {Object} config 配置对象\n     * @param {string} [config.clearColor=0] 每次清空画布的颜色\n     * @param {string} [config.motionBlur=false] 是否开启动态模糊\n     * @param {number} [config.lastFrameAlpha=0.7]\n     *                 在开启动态模糊的时候使用，与上一帧混合的alpha值，值越大尾迹越明显\n     */\n    configLayer: function (zlevel, config) {\n        if (config) {\n            var layerConfig = this._layerConfig;\n            if (!layerConfig[zlevel]) {\n                layerConfig[zlevel] = config;\n            }\n            else {\n                merge(layerConfig[zlevel], config, true);\n            }\n\n            for (var i = 0; i < this._zlevelList.length; i++) {\n                var _zlevel = this._zlevelList[i];\n                if (_zlevel === zlevel || _zlevel === zlevel + EL_AFTER_INCREMENTAL_INC) {\n                    var layer = this._layers[_zlevel];\n                    merge(layer, layerConfig[zlevel], true);\n                }\n            }\n        }\n    },\n\n    /**\n     * 删除指定层\n     * @param {number} zlevel 层所在的zlevel\n     */\n    delLayer: function (zlevel) {\n        var layers = this._layers;\n        var zlevelList = this._zlevelList;\n        var layer = layers[zlevel];\n        if (!layer) {\n            return;\n        }\n        layer.dom.parentNode.removeChild(layer.dom);\n        delete layers[zlevel];\n\n        zlevelList.splice(indexOf(zlevelList, zlevel), 1);\n    },\n\n    /**\n     * 区域大小变化后重绘\n     */\n    resize: function (width, height) {\n        if (!this._domRoot.style) { // Maybe in node or worker\n            if (width == null || height == null) {\n                return;\n            }\n            this._width = width;\n            this._height = height;\n\n            this.getLayer(CANVAS_ZLEVEL).resize(width, height);\n        }\n        else {\n            var domRoot = this._domRoot;\n            // FIXME Why ?\n            domRoot.style.display = 'none';\n\n            // Save input w/h\n            var opts = this._opts;\n            width != null && (opts.width = width);\n            height != null && (opts.height = height);\n\n            width = this._getSize(0);\n            height = this._getSize(1);\n\n            domRoot.style.display = '';\n\n            // 优化没有实际改变的resize\n            if (this._width !== width || height !== this._height) {\n                domRoot.style.width = width + 'px';\n                domRoot.style.height = height + 'px';\n\n                for (var id in this._layers) {\n                    if (this._layers.hasOwnProperty(id)) {\n                        this._layers[id].resize(width, height);\n                    }\n                }\n                each$1(this._progressiveLayers, function (layer) {\n                    layer.resize(width, height);\n                });\n\n                this.refresh(true);\n            }\n\n            this._width = width;\n            this._height = height;\n\n        }\n        return this;\n    },\n\n    /**\n     * 清除单独的一个层\n     * @param {number} zlevel\n     */\n    clearLayer: function (zlevel) {\n        var layer = this._layers[zlevel];\n        if (layer) {\n            layer.clear();\n        }\n    },\n\n    /**\n     * 释放\n     */\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this.root =\n        this.storage =\n\n        this._domRoot =\n        this._layers = null;\n    },\n\n    /**\n     * Get canvas which has all thing rendered\n     * @param {Object} opts\n     * @param {string} [opts.backgroundColor]\n     * @param {number} [opts.pixelRatio]\n     */\n    getRenderedCanvas: function (opts) {\n        opts = opts || {};\n        if (this._singleCanvas && !this._compositeManually) {\n            return this._layers[CANVAS_ZLEVEL].dom;\n        }\n\n        var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr);\n        imageLayer.initContext();\n        imageLayer.clear(false, opts.backgroundColor || this._backgroundColor);\n\n        if (opts.pixelRatio <= this.dpr) {\n            this.refresh();\n\n            var width = imageLayer.dom.width;\n            var height = imageLayer.dom.height;\n            var ctx = imageLayer.ctx;\n            this.eachLayer(function (layer) {\n                if (layer.__builtin__) {\n                    ctx.drawImage(layer.dom, 0, 0, width, height);\n                }\n                else if (layer.renderToCanvas) {\n                    imageLayer.ctx.save();\n                    layer.renderToCanvas(imageLayer.ctx);\n                    imageLayer.ctx.restore();\n                }\n            });\n        }\n        else {\n            // PENDING, echarts-gl and incremental rendering.\n            var scope = {};\n            var displayList = this.storage.getDisplayList(true);\n            for (var i = 0; i < displayList.length; i++) {\n                var el = displayList[i];\n                this._doPaintEl(el, imageLayer, true, scope);\n            }\n        }\n\n        return imageLayer.dom;\n    },\n    /**\n     * 获取绘图区域宽度\n     */\n    getWidth: function () {\n        return this._width;\n    },\n\n    /**\n     * 获取绘图区域高度\n     */\n    getHeight: function () {\n        return this._height;\n    },\n\n    _getSize: function (whIdx) {\n        var opts = this._opts;\n        var wh = ['width', 'height'][whIdx];\n        var cwh = ['clientWidth', 'clientHeight'][whIdx];\n        var plt = ['paddingLeft', 'paddingTop'][whIdx];\n        var prb = ['paddingRight', 'paddingBottom'][whIdx];\n\n        if (opts[wh] != null && opts[wh] !== 'auto') {\n            return parseFloat(opts[wh]);\n        }\n\n        var root = this.root;\n        // IE8 does not support getComputedStyle, but it use VML.\n        var stl = document.defaultView.getComputedStyle(root);\n\n        return (\n            (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh]))\n            - (parseInt10(stl[plt]) || 0)\n            - (parseInt10(stl[prb]) || 0)\n        ) | 0;\n    },\n\n    pathToImage: function (path, dpr) {\n        dpr = dpr || this.dpr;\n\n        var canvas = document.createElement('canvas');\n        var ctx = canvas.getContext('2d');\n        var rect = path.getBoundingRect();\n        var style = path.style;\n        var shadowBlurSize = style.shadowBlur * dpr;\n        var shadowOffsetX = style.shadowOffsetX * dpr;\n        var shadowOffsetY = style.shadowOffsetY * dpr;\n        var lineWidth = style.hasStroke() ? style.lineWidth : 0;\n\n        var leftMargin = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize);\n        var rightMargin = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize);\n        var topMargin = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize);\n        var bottomMargin = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize);\n        var width = rect.width + leftMargin + rightMargin;\n        var height = rect.height + topMargin + bottomMargin;\n\n        canvas.width = width * dpr;\n        canvas.height = height * dpr;\n\n        ctx.scale(dpr, dpr);\n        ctx.clearRect(0, 0, width, height);\n        ctx.dpr = dpr;\n\n        var pathTransform = {\n            position: path.position,\n            rotation: path.rotation,\n            scale: path.scale\n        };\n        path.position = [leftMargin - rect.x, topMargin - rect.y];\n        path.rotation = 0;\n        path.scale = [1, 1];\n        path.updateTransform();\n        if (path) {\n            path.brush(ctx);\n        }\n\n        var ImageShape = ZImage;\n        var imgShape = new ImageShape({\n            style: {\n                x: 0,\n                y: 0,\n                image: canvas\n            }\n        });\n\n        if (pathTransform.position != null) {\n            imgShape.position = path.position = pathTransform.position;\n        }\n\n        if (pathTransform.rotation != null) {\n            imgShape.rotation = path.rotation = pathTransform.rotation;\n        }\n\n        if (pathTransform.scale != null) {\n            imgShape.scale = path.scale = pathTransform.scale;\n        }\n\n        return imgShape;\n    }\n};\n\n/**\n * 动画主类, 调度和管理所有动画控制器\n *\n * @module zrender/animation/Animation\n * @author pissang(https://github.com/pissang)\n */\n// TODO Additive animation\n// http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/\n// https://developer.apple.com/videos/wwdc2014/#236\n\n/**\n * @typedef {Object} IZRenderStage\n * @property {Function} update\n */\n\n/**\n * @alias module:zrender/animation/Animation\n * @constructor\n * @param {Object} [options]\n * @param {Function} [options.onframe]\n * @param {IZRenderStage} [options.stage]\n * @example\n *     var animation = new Animation();\n *     var obj = {\n *         x: 100,\n *         y: 100\n *     };\n *     animation.animate(node.position)\n *         .when(1000, {\n *             x: 500,\n *             y: 500\n *         })\n *         .when(2000, {\n *             x: 100,\n *             y: 100\n *         })\n *         .start('spline');\n */\nvar Animation = function (options) {\n\n    options = options || {};\n\n    this.stage = options.stage || {};\n\n    this.onframe = options.onframe || function () {};\n\n    // private properties\n    this._clips = [];\n\n    this._running = false;\n\n    this._time;\n\n    this._pausedTime;\n\n    this._pauseStart;\n\n    this._paused = false;\n\n    Eventful.call(this);\n};\n\nAnimation.prototype = {\n\n    constructor: Animation,\n    /**\n     * 添加 clip\n     * @param {module:zrender/animation/Clip} clip\n     */\n    addClip: function (clip) {\n        this._clips.push(clip);\n    },\n    /**\n     * 添加 animator\n     * @param {module:zrender/animation/Animator} animator\n     */\n    addAnimator: function (animator) {\n        animator.animation = this;\n        var clips = animator.getClips();\n        for (var i = 0; i < clips.length; i++) {\n            this.addClip(clips[i]);\n        }\n    },\n    /**\n     * 删除动画片段\n     * @param {module:zrender/animation/Clip} clip\n     */\n    removeClip: function (clip) {\n        var idx = indexOf(this._clips, clip);\n        if (idx >= 0) {\n            this._clips.splice(idx, 1);\n        }\n    },\n\n    /**\n     * 删除动画片段\n     * @param {module:zrender/animation/Animator} animator\n     */\n    removeAnimator: function (animator) {\n        var clips = animator.getClips();\n        for (var i = 0; i < clips.length; i++) {\n            this.removeClip(clips[i]);\n        }\n        animator.animation = null;\n    },\n\n    _update: function () {\n        var time = new Date().getTime() - this._pausedTime;\n        var delta = time - this._time;\n        var clips = this._clips;\n        var len = clips.length;\n\n        var deferredEvents = [];\n        var deferredClips = [];\n        for (var i = 0; i < len; i++) {\n            var clip = clips[i];\n            var e = clip.step(time, delta);\n            // Throw out the events need to be called after\n            // stage.update, like destroy\n            if (e) {\n                deferredEvents.push(e);\n                deferredClips.push(clip);\n            }\n        }\n\n        // Remove the finished clip\n        for (var i = 0; i < len;) {\n            if (clips[i]._needsRemove) {\n                clips[i] = clips[len - 1];\n                clips.pop();\n                len--;\n            }\n            else {\n                i++;\n            }\n        }\n\n        len = deferredEvents.length;\n        for (var i = 0; i < len; i++) {\n            deferredClips[i].fire(deferredEvents[i]);\n        }\n\n        this._time = time;\n\n        this.onframe(delta);\n\n        // 'frame' should be triggered before stage, because upper application\n        // depends on the sequence (e.g., echarts-stream and finish\n        // event judge)\n        this.trigger('frame', delta);\n\n        if (this.stage.update) {\n            this.stage.update();\n        }\n    },\n\n    _startLoop: function () {\n        var self = this;\n\n        this._running = true;\n\n        function step() {\n            if (self._running) {\n\n                requestAnimationFrame(step);\n\n                !self._paused && self._update();\n            }\n        }\n\n        requestAnimationFrame(step);\n    },\n\n    /**\n     * Start animation.\n     */\n    start: function () {\n\n        this._time = new Date().getTime();\n        this._pausedTime = 0;\n\n        this._startLoop();\n    },\n\n    /**\n     * Stop animation.\n     */\n    stop: function () {\n        this._running = false;\n    },\n\n    /**\n     * Pause animation.\n     */\n    pause: function () {\n        if (!this._paused) {\n            this._pauseStart = new Date().getTime();\n            this._paused = true;\n        }\n    },\n\n    /**\n     * Resume animation.\n     */\n    resume: function () {\n        if (this._paused) {\n            this._pausedTime += (new Date().getTime()) - this._pauseStart;\n            this._paused = false;\n        }\n    },\n\n    /**\n     * Clear animation.\n     */\n    clear: function () {\n        this._clips = [];\n    },\n\n    /**\n     * Whether animation finished.\n     */\n    isFinished: function () {\n        return !this._clips.length;\n    },\n\n    /**\n     * Creat animator for a target, whose props can be animated.\n     *\n     * @param  {Object} target\n     * @param  {Object} options\n     * @param  {boolean} [options.loop=false] Whether loop animation.\n     * @param  {Function} [options.getter=null] Get value from target.\n     * @param  {Function} [options.setter=null] Set value to target.\n     * @return {module:zrender/animation/Animation~Animator}\n     */\n    // TODO Gap\n    animate: function (target, options) {\n        options = options || {};\n\n        var animator = new Animator(\n            target,\n            options.loop,\n            options.getter,\n            options.setter\n        );\n\n        this.addAnimator(animator);\n\n        return animator;\n    }\n};\n\nmixin(Animation, Eventful);\n\nvar TOUCH_CLICK_DELAY = 300;\n\nvar mouseHandlerNames = [\n    'click', 'dblclick', 'mousewheel', 'mouseout',\n    'mouseup', 'mousedown', 'mousemove', 'contextmenu'\n];\n\nvar touchHandlerNames = [\n    'touchstart', 'touchend', 'touchmove'\n];\n\nvar pointerEventNames = {\n    pointerdown: 1, pointerup: 1, pointermove: 1, pointerout: 1\n};\n\nvar pointerHandlerNames = map(mouseHandlerNames, function (name) {\n    var nm = name.replace('mouse', 'pointer');\n    return pointerEventNames[nm] ? nm : name;\n});\n\nfunction eventNameFix(name) {\n    return (name === 'mousewheel' && env$1.browser.firefox) ? 'DOMMouseScroll' : name;\n}\n\n// function onMSGestureChange(proxy, event) {\n//     if (event.translationX || event.translationY) {\n//         // mousemove is carried by MSGesture to reduce the sensitivity.\n//         proxy.handler.dispatchToElement(event.target, 'mousemove', event);\n//     }\n//     if (event.scale !== 1) {\n//         event.pinchX = event.offsetX;\n//         event.pinchY = event.offsetY;\n//         event.pinchScale = event.scale;\n//         proxy.handler.dispatchToElement(event.target, 'pinch', event);\n//     }\n// }\n\n/**\n * Prevent mouse event from being dispatched after Touch Events action\n * @see <https://github.com/deltakosh/handjs/blob/master/src/hand.base.js>\n * 1. Mobile browsers dispatch mouse events 300ms after touchend.\n * 2. Chrome for Android dispatch mousedown for long-touch about 650ms\n * Result: Blocking Mouse Events for 700ms.\n */\nfunction setTouchTimer(instance) {\n    instance._touching = true;\n    clearTimeout(instance._touchTimer);\n    instance._touchTimer = setTimeout(function () {\n        instance._touching = false;\n    }, 700);\n}\n\n\nvar domHandlers = {\n    /**\n     * Mouse move handler\n     * @inner\n     * @param {Event} event\n     */\n    mousemove: function (event) {\n        event = normalizeEvent(this.dom, event);\n\n        this.trigger('mousemove', event);\n    },\n\n    /**\n     * Mouse out handler\n     * @inner\n     * @param {Event} event\n     */\n    mouseout: function (event) {\n        event = normalizeEvent(this.dom, event);\n\n        var element = event.toElement || event.relatedTarget;\n        if (element !== this.dom) {\n            while (element && element.nodeType !== 9) {\n                // 忽略包含在root中的dom引起的mouseOut\n                if (element === this.dom) {\n                    return;\n                }\n\n                element = element.parentNode;\n            }\n        }\n\n        this.trigger('mouseout', event);\n    },\n\n    /**\n     * Touch开始响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchstart: function (event) {\n        // Default mouse behaviour should not be disabled here.\n        // For example, page may needs to be slided.\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this._lastTouchMoment = new Date();\n\n        this.handler.processGesture(this, event, 'start');\n\n        // In touch device, trigger `mousemove`(`mouseover`) should\n        // be triggered, and must before `mousedown` triggered.\n        domHandlers.mousemove.call(this, event);\n\n        domHandlers.mousedown.call(this, event);\n\n        setTouchTimer(this);\n    },\n\n    /**\n     * Touch移动响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchmove: function (event) {\n\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this.handler.processGesture(this, event, 'change');\n\n        // Mouse move should always be triggered no matter whether\n        // there is gestrue event, because mouse move and pinch may\n        // be used at the same time.\n        domHandlers.mousemove.call(this, event);\n\n        setTouchTimer(this);\n    },\n\n    /**\n     * Touch结束响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchend: function (event) {\n\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this.handler.processGesture(this, event, 'end');\n\n        domHandlers.mouseup.call(this, event);\n\n        // Do not trigger `mouseout` here, in spite of `mousemove`(`mouseover`) is\n        // triggered in `touchstart`. This seems to be illogical, but by this mechanism,\n        // we can conveniently implement \"hover style\" in both PC and touch device just\n        // by listening to `mouseover` to add \"hover style\" and listening to `mouseout`\n        // to remove \"hover style\" on an element, without any additional code for\n        // compatibility. (`mouseout` will not be triggered in `touchend`, so \"hover\n        // style\" will remain for user view)\n\n        // click event should always be triggered no matter whether\n        // there is gestrue event. System click can not be prevented.\n        if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) {\n            domHandlers.click.call(this, event);\n        }\n\n        setTouchTimer(this);\n    },\n\n    pointerdown: function (event) {\n        domHandlers.mousedown.call(this, event);\n\n        // if (useMSGuesture(this, event)) {\n        //     this._msGesture.addPointer(event.pointerId);\n        // }\n    },\n\n    pointermove: function (event) {\n        // FIXME\n        // pointermove is so sensitive that it always triggered when\n        // tap(click) on touch screen, which affect some judgement in\n        // upper application. So, we dont support mousemove on MS touch\n        // device yet.\n        if (!isPointerFromTouch(event)) {\n            domHandlers.mousemove.call(this, event);\n        }\n    },\n\n    pointerup: function (event) {\n        domHandlers.mouseup.call(this, event);\n    },\n\n    pointerout: function (event) {\n        // pointerout will be triggered when tap on touch screen\n        // (IE11+/Edge on MS Surface) after click event triggered,\n        // which is inconsistent with the mousout behavior we defined\n        // in touchend. So we unify them.\n        // (check domHandlers.touchend for detailed explanation)\n        if (!isPointerFromTouch(event)) {\n            domHandlers.mouseout.call(this, event);\n        }\n    }\n};\n\nfunction isPointerFromTouch(event) {\n    var pointerType = event.pointerType;\n    return pointerType === 'pen' || pointerType === 'touch';\n}\n\n// function useMSGuesture(handlerProxy, event) {\n//     return isPointerFromTouch(event) && !!handlerProxy._msGesture;\n// }\n\n// Common handlers\neach$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {\n    domHandlers[name] = function (event) {\n        event = normalizeEvent(this.dom, event);\n        this.trigger(name, event);\n    };\n});\n\n/**\n * 为控制类实例初始化dom 事件处理函数\n *\n * @inner\n * @param {module:zrender/Handler} instance 控制类实例\n */\nfunction initDomHandler(instance) {\n    each$1(touchHandlerNames, function (name) {\n        instance._handlers[name] = bind(domHandlers[name], instance);\n    });\n\n    each$1(pointerHandlerNames, function (name) {\n        instance._handlers[name] = bind(domHandlers[name], instance);\n    });\n\n    each$1(mouseHandlerNames, function (name) {\n        instance._handlers[name] = makeMouseHandler(domHandlers[name], instance);\n    });\n\n    function makeMouseHandler(fn, instance) {\n        return function () {\n            if (instance._touching) {\n                return;\n            }\n            return fn.apply(instance, arguments);\n        };\n    }\n}\n\n\nfunction HandlerDomProxy(dom) {\n    Eventful.call(this);\n\n    this.dom = dom;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._touching = false;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._touchTimer;\n\n    this._handlers = {};\n\n    initDomHandler(this);\n\n    if (env$1.pointerEventsSupported) { // Only IE11+/Edge\n        // 1. On devices that both enable touch and mouse (e.g., MS Surface and lenovo X240),\n        // IE11+/Edge do not trigger touch event, but trigger pointer event and mouse event\n        // at the same time.\n        // 2. On MS Surface, it probablely only trigger mousedown but no mouseup when tap on\n        // screen, which do not occurs in pointer event.\n        // So we use pointer event to both detect touch gesture and mouse behavior.\n        mountHandlers(pointerHandlerNames, this);\n\n        // FIXME\n        // Note: MS Gesture require CSS touch-action set. But touch-action is not reliable,\n        // which does not prevent defuault behavior occasionally (which may cause view port\n        // zoomed in but use can not zoom it back). And event.preventDefault() does not work.\n        // So we have to not to use MSGesture and not to support touchmove and pinch on MS\n        // touch screen. And we only support click behavior on MS touch screen now.\n\n        // MS Gesture Event is only supported on IE11+/Edge and on Windows 8+.\n        // We dont support touch on IE on win7.\n        // See <https://msdn.microsoft.com/en-us/library/dn433243(v=vs.85).aspx>\n        // if (typeof MSGesture === 'function') {\n        //     (this._msGesture = new MSGesture()).target = dom; // jshint ignore:line\n        //     dom.addEventListener('MSGestureChange', onMSGestureChange);\n        // }\n    }\n    else {\n        if (env$1.touchEventsSupported) {\n            mountHandlers(touchHandlerNames, this);\n            // Handler of 'mouseout' event is needed in touch mode, which will be mounted below.\n            // addEventListener(root, 'mouseout', this._mouseoutHandler);\n        }\n\n        // 1. Considering some devices that both enable touch and mouse event (like on MS Surface\n        // and lenovo X240, @see #2350), we make mouse event be always listened, otherwise\n        // mouse event can not be handle in those devices.\n        // 2. On MS Surface, Chrome will trigger both touch event and mouse event. How to prevent\n        // mouseevent after touch event triggered, see `setTouchTimer`.\n        mountHandlers(mouseHandlerNames, this);\n    }\n\n    function mountHandlers(handlerNames, instance) {\n        each$1(handlerNames, function (name) {\n            addEventListener(dom, eventNameFix(name), instance._handlers[name]);\n        }, instance);\n    }\n}\n\nvar handlerDomProxyProto = HandlerDomProxy.prototype;\nhandlerDomProxyProto.dispose = function () {\n    var handlerNames = mouseHandlerNames.concat(touchHandlerNames);\n\n    for (var i = 0; i < handlerNames.length; i++) {\n        var name = handlerNames[i];\n        removeEventListener(this.dom, eventNameFix(name), this._handlers[name]);\n    }\n};\n\nhandlerDomProxyProto.setCursor = function (cursorStyle) {\n    this.dom.style && (this.dom.style.cursor = cursorStyle || 'default');\n};\n\nmixin(HandlerDomProxy, Eventful);\n\n/*!\n* ZRender, a high performance 2d drawing library.\n*\n* Copyright (c) 2013, Baidu Inc.\n* All rights reserved.\n*\n* LICENSE\n* https://github.com/ecomfe/zrender/blob/master/LICENSE.txt\n*/\n\nvar useVML = !env$1.canvasSupported;\n\nvar painterCtors = {\n    canvas: Painter\n};\n\nvar instances$1 = {};    // ZRender实例map索引\n\n/**\n * @type {string}\n */\nvar version$1 = '4.0.7';\n\n/**\n * Initializing a zrender instance\n * @param {HTMLElement} dom\n * @param {Object} [opts]\n * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'\n * @param {number} [opts.devicePixelRatio]\n * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)\n * @return {module:zrender/ZRender}\n */\nfunction init$1(dom, opts) {\n    var zr = new ZRender(guid(), dom, opts);\n    instances$1[zr.id] = zr;\n    return zr;\n}\n\n/**\n * Dispose zrender instance\n * @param {module:zrender/ZRender} zr\n */\nfunction dispose$1(zr) {\n    if (zr) {\n        zr.dispose();\n    }\n    else {\n        for (var key in instances$1) {\n            if (instances$1.hasOwnProperty(key)) {\n                instances$1[key].dispose();\n            }\n        }\n        instances$1 = {};\n    }\n\n    return this;\n}\n\n/**\n * Get zrender instance by id\n * @param {string} id zrender instance id\n * @return {module:zrender/ZRender}\n */\nfunction getInstance(id) {\n    return instances$1[id];\n}\n\nfunction registerPainter(name, Ctor) {\n    painterCtors[name] = Ctor;\n}\n\nfunction delInstance(id) {\n    delete instances$1[id];\n}\n\n/**\n * @module zrender/ZRender\n */\n/**\n * @constructor\n * @alias module:zrender/ZRender\n * @param {string} id\n * @param {HTMLElement} dom\n * @param {Object} opts\n * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'\n * @param {number} [opts.devicePixelRatio]\n * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)\n */\nvar ZRender = function (id, dom, opts) {\n\n    opts = opts || {};\n\n    /**\n     * @type {HTMLDomElement}\n     */\n    this.dom = dom;\n\n    /**\n     * @type {string}\n     */\n    this.id = id;\n\n    var self = this;\n    var storage = new Storage();\n\n    var rendererType = opts.renderer;\n    // TODO WebGL\n    if (useVML) {\n        if (!painterCtors.vml) {\n            throw new Error('You need to require \\'zrender/vml/vml\\' to support IE8');\n        }\n        rendererType = 'vml';\n    }\n    else if (!rendererType || !painterCtors[rendererType]) {\n        rendererType = 'canvas';\n    }\n    var painter = new painterCtors[rendererType](dom, storage, opts, id);\n\n    this.storage = storage;\n    this.painter = painter;\n\n    var handerProxy = (!env$1.node && !env$1.worker) ? new HandlerDomProxy(painter.getViewportRoot()) : null;\n    this.handler = new Handler(storage, painter, handerProxy, painter.root);\n\n    /**\n     * @type {module:zrender/animation/Animation}\n     */\n    this.animation = new Animation({\n        stage: {\n            update: bind(this.flush, this)\n        }\n    });\n    this.animation.start();\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._needsRefresh;\n\n    // 修改 storage.delFromStorage, 每次删除元素之前删除动画\n    // FIXME 有点ugly\n    var oldDelFromStorage = storage.delFromStorage;\n    var oldAddToStorage = storage.addToStorage;\n\n    storage.delFromStorage = function (el) {\n        oldDelFromStorage.call(storage, el);\n\n        el && el.removeSelfFromZr(self);\n    };\n\n    storage.addToStorage = function (el) {\n        oldAddToStorage.call(storage, el);\n\n        el.addSelfToZr(self);\n    };\n};\n\nZRender.prototype = {\n\n    constructor: ZRender,\n    /**\n     * 获取实例唯一标识\n     * @return {string}\n     */\n    getId: function () {\n        return this.id;\n    },\n\n    /**\n     * 添加元素\n     * @param  {module:zrender/Element} el\n     */\n    add: function (el) {\n        this.storage.addRoot(el);\n        this._needsRefresh = true;\n    },\n\n    /**\n     * 删除元素\n     * @param  {module:zrender/Element} el\n     */\n    remove: function (el) {\n        this.storage.delRoot(el);\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Change configuration of layer\n     * @param {string} zLevel\n     * @param {Object} config\n     * @param {string} [config.clearColor=0] Clear color\n     * @param {string} [config.motionBlur=false] If enable motion blur\n     * @param {number} [config.lastFrameAlpha=0.7] Motion blur factor. Larger value cause longer trailer\n    */\n    configLayer: function (zLevel, config) {\n        if (this.painter.configLayer) {\n            this.painter.configLayer(zLevel, config);\n        }\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Set background color\n     * @param {string} backgroundColor\n     */\n    setBackgroundColor: function (backgroundColor) {\n        if (this.painter.setBackgroundColor) {\n            this.painter.setBackgroundColor(backgroundColor);\n        }\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Repaint the canvas immediately\n     */\n    refreshImmediately: function () {\n        // var start = new Date();\n        // Clear needsRefresh ahead to avoid something wrong happens in refresh\n        // Or it will cause zrender refreshes again and again.\n        this._needsRefresh = false;\n        this.painter.refresh();\n        /**\n         * Avoid trigger zr.refresh in Element#beforeUpdate hook\n         */\n        this._needsRefresh = false;\n        // var end = new Date();\n        // var log = document.getElementById('log');\n        // if (log) {\n        //     log.innerHTML = log.innerHTML + '<br>' + (end - start);\n        // }\n    },\n\n    /**\n     * Mark and repaint the canvas in the next frame of browser\n     */\n    refresh: function () {\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Perform all refresh\n     */\n    flush: function () {\n        var triggerRendered;\n\n        if (this._needsRefresh) {\n            triggerRendered = true;\n            this.refreshImmediately();\n        }\n        if (this._needsRefreshHover) {\n            triggerRendered = true;\n            this.refreshHoverImmediately();\n        }\n\n        triggerRendered && this.trigger('rendered');\n    },\n\n    /**\n     * Add element to hover layer\n     * @param  {module:zrender/Element} el\n     * @param {Object} style\n     */\n    addHover: function (el, style) {\n        if (this.painter.addHover) {\n            var elMirror = this.painter.addHover(el, style);\n            this.refreshHover();\n            return elMirror;\n        }\n    },\n\n    /**\n     * Add element from hover layer\n     * @param  {module:zrender/Element} el\n     */\n    removeHover: function (el) {\n        if (this.painter.removeHover) {\n            this.painter.removeHover(el);\n            this.refreshHover();\n        }\n    },\n\n    /**\n     * Clear all hover elements in hover layer\n     * @param  {module:zrender/Element} el\n     */\n    clearHover: function () {\n        if (this.painter.clearHover) {\n            this.painter.clearHover();\n            this.refreshHover();\n        }\n    },\n\n    /**\n     * Refresh hover in next frame\n     */\n    refreshHover: function () {\n        this._needsRefreshHover = true;\n    },\n\n    /**\n     * Refresh hover immediately\n     */\n    refreshHoverImmediately: function () {\n        this._needsRefreshHover = false;\n        this.painter.refreshHover && this.painter.refreshHover();\n    },\n\n    /**\n     * Resize the canvas.\n     * Should be invoked when container size is changed\n     * @param {Object} [opts]\n     * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)\n     * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)\n     */\n    resize: function (opts) {\n        opts = opts || {};\n        this.painter.resize(opts.width, opts.height);\n        this.handler.resize();\n    },\n\n    /**\n     * Stop and clear all animation immediately\n     */\n    clearAnimation: function () {\n        this.animation.clear();\n    },\n\n    /**\n     * Get container width\n     */\n    getWidth: function () {\n        return this.painter.getWidth();\n    },\n\n    /**\n     * Get container height\n     */\n    getHeight: function () {\n        return this.painter.getHeight();\n    },\n\n    /**\n     * Export the canvas as Base64 URL\n     * @param {string} type\n     * @param {string} [backgroundColor='#fff']\n     * @return {string} Base64 URL\n     */\n    // toDataURL: function(type, backgroundColor) {\n    //     return this.painter.getRenderedCanvas({\n    //         backgroundColor: backgroundColor\n    //     }).toDataURL(type);\n    // },\n\n    /**\n     * Converting a path to image.\n     * It has much better performance of drawing image rather than drawing a vector path.\n     * @param {module:zrender/graphic/Path} e\n     * @param {number} width\n     * @param {number} height\n     */\n    pathToImage: function (e, dpr) {\n        return this.painter.pathToImage(e, dpr);\n    },\n\n    /**\n     * Set default cursor\n     * @param {string} [cursorStyle='default'] 例如 crosshair\n     */\n    setCursorStyle: function (cursorStyle) {\n        this.handler.setCursorStyle(cursorStyle);\n    },\n\n    /**\n     * Find hovered element\n     * @param {number} x\n     * @param {number} y\n     * @return {Object} {target, topTarget}\n     */\n    findHover: function (x, y) {\n        return this.handler.findHover(x, y);\n    },\n\n    /**\n     * Bind event\n     *\n     * @param {string} eventName Event name\n     * @param {Function} eventHandler Handler function\n     * @param {Object} [context] Context object\n     */\n    on: function (eventName, eventHandler, context) {\n        this.handler.on(eventName, eventHandler, context);\n    },\n\n    /**\n     * Unbind event\n     * @param {string} eventName Event name\n     * @param {Function} [eventHandler] Handler function\n     */\n    off: function (eventName, eventHandler) {\n        this.handler.off(eventName, eventHandler);\n    },\n\n    /**\n     * Trigger event manually\n     *\n     * @param {string} eventName Event name\n     * @param {event=} event Event object\n     */\n    trigger: function (eventName, event) {\n        this.handler.trigger(eventName, event);\n    },\n\n\n    /**\n     * Clear all objects and the canvas.\n     */\n    clear: function () {\n        this.storage.delRoot();\n        this.painter.clear();\n    },\n\n    /**\n     * Dispose self.\n     */\n    dispose: function () {\n        this.animation.stop();\n\n        this.clear();\n        this.storage.dispose();\n        this.painter.dispose();\n        this.handler.dispose();\n\n        this.animation =\n        this.storage =\n        this.painter =\n        this.handler = null;\n\n        delInstance(this.id);\n    }\n};\n\n\n\nvar zrender = (Object.freeze || Object)({\n\tversion: version$1,\n\tinit: init$1,\n\tdispose: dispose$1,\n\tgetInstance: getInstance,\n\tregisterPainter: registerPainter\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$2 = each$1;\nvar isObject$2 = isObject$1;\nvar isArray$1 = isArray;\n\n/**\n * Make the name displayable. But we should\n * make sure it is not duplicated with user\n * specified name, so use '\\0';\n */\nvar DUMMY_COMPONENT_NAME_PREFIX = 'series\\0';\n\n/**\n * If value is not array, then translate it to array.\n * @param  {*} value\n * @return {Array} [value] or value\n */\nfunction normalizeToArray(value) {\n    return value instanceof Array\n        ? value\n        : value == null\n        ? []\n        : [value];\n}\n\n/**\n * Sync default option between normal and emphasis like `position` and `show`\n * In case some one will write code like\n *     label: {\n *          show: false,\n *          position: 'outside',\n *          fontSize: 18\n *     },\n *     emphasis: {\n *          label: { show: true }\n *     }\n * @param {Object} opt\n * @param {string} key\n * @param {Array.<string>} subOpts\n */\nfunction defaultEmphasis(opt, key, subOpts) {\n    // Caution: performance sensitive.\n    if (opt) {\n        opt[key] = opt[key] || {};\n        opt.emphasis = opt.emphasis || {};\n        opt.emphasis[key] = opt.emphasis[key] || {};\n\n        // Default emphasis option from normal\n        for (var i = 0, len = subOpts.length; i < len; i++) {\n            var subOptName = subOpts[i];\n            if (!opt.emphasis[key].hasOwnProperty(subOptName)\n                && opt[key].hasOwnProperty(subOptName)\n            ) {\n                opt.emphasis[key][subOptName] = opt[key][subOptName];\n            }\n        }\n    }\n}\n\nvar TEXT_STYLE_OPTIONS = [\n    'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',\n    'rich', 'tag', 'color', 'textBorderColor', 'textBorderWidth',\n    'width', 'height', 'lineHeight', 'align', 'verticalAlign', 'baseline',\n    'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY',\n    'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY',\n    'backgroundColor', 'borderColor', 'borderWidth', 'borderRadius', 'padding'\n];\n\n// modelUtil.LABEL_OPTIONS = modelUtil.TEXT_STYLE_OPTIONS.concat([\n//     'position', 'offset', 'rotate', 'origin', 'show', 'distance', 'formatter',\n//     'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',\n//     // FIXME: deprecated, check and remove it.\n//     'textStyle'\n// ]);\n\n/**\n * The method do not ensure performance.\n * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]\n * This helper method retieves value from data.\n * @param {string|number|Date|Array|Object} dataItem\n * @return {number|string|Date|Array.<number|string|Date>}\n */\nfunction getDataItemValue(dataItem) {\n    return (isObject$2(dataItem) && !isArray$1(dataItem) && !(dataItem instanceof Date))\n        ? dataItem.value : dataItem;\n}\n\n/**\n * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]\n * This helper method determine if dataItem has extra option besides value\n * @param {string|number|Date|Array|Object} dataItem\n */\nfunction isDataItemOption(dataItem) {\n    return isObject$2(dataItem)\n        && !(dataItem instanceof Array);\n        // // markLine data can be array\n        // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array));\n}\n\n/**\n * Mapping to exists for merge.\n *\n * @public\n * @param {Array.<Object>|Array.<module:echarts/model/Component>} exists\n * @param {Object|Array.<Object>} newCptOptions\n * @return {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],\n *                          index of which is the same as exists.\n */\nfunction mappingToExists(exists, newCptOptions) {\n    // Mapping by the order by original option (but not order of\n    // new option) in merge mode. Because we should ensure\n    // some specified index (like xAxisIndex) is consistent with\n    // original option, which is easy to understand, espatially in\n    // media query. And in most case, merge option is used to\n    // update partial option but not be expected to change order.\n    newCptOptions = (newCptOptions || []).slice();\n\n    var result = map(exists || [], function (obj, index) {\n        return {exist: obj};\n    });\n\n    // Mapping by id or name if specified.\n    each$2(newCptOptions, function (cptOption, index) {\n        if (!isObject$2(cptOption)) {\n            return;\n        }\n\n        // id has highest priority.\n        for (var i = 0; i < result.length; i++) {\n            if (!result[i].option // Consider name: two map to one.\n                && cptOption.id != null\n                && result[i].exist.id === cptOption.id + ''\n            ) {\n                result[i].option = cptOption;\n                newCptOptions[index] = null;\n                return;\n            }\n        }\n\n        for (var i = 0; i < result.length; i++) {\n            var exist = result[i].exist;\n            if (!result[i].option // Consider name: two map to one.\n                // Can not match when both ids exist but different.\n                && (exist.id == null || cptOption.id == null)\n                && cptOption.name != null\n                && !isIdInner(cptOption)\n                && !isIdInner(exist)\n                && exist.name === cptOption.name + ''\n            ) {\n                result[i].option = cptOption;\n                newCptOptions[index] = null;\n                return;\n            }\n        }\n    });\n\n    // Otherwise mapping by index.\n    each$2(newCptOptions, function (cptOption, index) {\n        if (!isObject$2(cptOption)) {\n            return;\n        }\n\n        var i = 0;\n        for (; i < result.length; i++) {\n            var exist = result[i].exist;\n            if (!result[i].option\n                // Existing model that already has id should be able to\n                // mapped to (because after mapping performed model may\n                // be assigned with a id, whish should not affect next\n                // mapping), except those has inner id.\n                && !isIdInner(exist)\n                // Caution:\n                // Do not overwrite id. But name can be overwritten,\n                // because axis use name as 'show label text'.\n                // 'exist' always has id and name and we dont\n                // need to check it.\n                && cptOption.id == null\n            ) {\n                result[i].option = cptOption;\n                break;\n            }\n        }\n\n        if (i >= result.length) {\n            result.push({option: cptOption});\n        }\n    });\n\n    return result;\n}\n\n/**\n * Make id and name for mapping result (result of mappingToExists)\n * into `keyInfo` field.\n *\n * @public\n * @param {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],\n *                          which order is the same as exists.\n * @return {Array.<Object>} The input.\n */\nfunction makeIdAndName(mapResult) {\n    // We use this id to hash component models and view instances\n    // in echarts. id can be specified by user, or auto generated.\n\n    // The id generation rule ensures new view instance are able\n    // to mapped to old instance when setOption are called in\n    // no-merge mode. So we generate model id by name and plus\n    // type in view id.\n\n    // name can be duplicated among components, which is convenient\n    // to specify multi components (like series) by one name.\n\n    // Ensure that each id is distinct.\n    var idMap = createHashMap();\n\n    each$2(mapResult, function (item, index) {\n        var existCpt = item.exist;\n        existCpt && idMap.set(existCpt.id, item);\n    });\n\n    each$2(mapResult, function (item, index) {\n        var opt = item.option;\n\n        assert$1(\n            !opt || opt.id == null || !idMap.get(opt.id) || idMap.get(opt.id) === item,\n            'id duplicates: ' + (opt && opt.id)\n        );\n\n        opt && opt.id != null && idMap.set(opt.id, item);\n        !item.keyInfo && (item.keyInfo = {});\n    });\n\n    // Make name and id.\n    each$2(mapResult, function (item, index) {\n        var existCpt = item.exist;\n        var opt = item.option;\n        var keyInfo = item.keyInfo;\n\n        if (!isObject$2(opt)) {\n            return;\n        }\n\n        // name can be overwitten. Consider case: axis.name = '20km'.\n        // But id generated by name will not be changed, which affect\n        // only in that case: setOption with 'not merge mode' and view\n        // instance will be recreated, which can be accepted.\n        keyInfo.name = opt.name != null\n            ? opt.name + ''\n            : existCpt\n            ? existCpt.name\n            // Avoid diffferent series has the same name,\n            // because name may be used like in color pallet.\n            : DUMMY_COMPONENT_NAME_PREFIX + index;\n\n        if (existCpt) {\n            keyInfo.id = existCpt.id;\n        }\n        else if (opt.id != null) {\n            keyInfo.id = opt.id + '';\n        }\n        else {\n            // Consider this situatoin:\n            //  optionA: [{name: 'a'}, {name: 'a'}, {..}]\n            //  optionB [{..}, {name: 'a'}, {name: 'a'}]\n            // Series with the same name between optionA and optionB\n            // should be mapped.\n            var idNum = 0;\n            do {\n                keyInfo.id = '\\0' + keyInfo.name + '\\0' + idNum++;\n            }\n            while (idMap.get(keyInfo.id));\n        }\n\n        idMap.set(keyInfo.id, item);\n    });\n}\n\nfunction isNameSpecified(componentModel) {\n    var name = componentModel.name;\n    // Is specified when `indexOf` get -1 or > 0.\n    return !!(name && name.indexOf(DUMMY_COMPONENT_NAME_PREFIX));\n}\n\n/**\n * @public\n * @param {Object} cptOption\n * @return {boolean}\n */\nfunction isIdInner(cptOption) {\n    return isObject$2(cptOption)\n        && cptOption.id\n        && (cptOption.id + '').indexOf('\\0_ec_\\0') === 0;\n}\n\n/**\n * A helper for removing duplicate items between batchA and batchB,\n * and in themselves, and categorize by series.\n *\n * @param {Array.<Object>} batchA Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]\n * @param {Array.<Object>} batchB Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]\n * @return {Array.<Array.<Object>, Array.<Object>>} result: [resultBatchA, resultBatchB]\n */\nfunction compressBatches(batchA, batchB) {\n    var mapA = {};\n    var mapB = {};\n\n    makeMap(batchA || [], mapA);\n    makeMap(batchB || [], mapB, mapA);\n\n    return [mapToArray(mapA), mapToArray(mapB)];\n\n    function makeMap(sourceBatch, map$$1, otherMap) {\n        for (var i = 0, len = sourceBatch.length; i < len; i++) {\n            var seriesId = sourceBatch[i].seriesId;\n            var dataIndices = normalizeToArray(sourceBatch[i].dataIndex);\n            var otherDataIndices = otherMap && otherMap[seriesId];\n\n            for (var j = 0, lenj = dataIndices.length; j < lenj; j++) {\n                var dataIndex = dataIndices[j];\n\n                if (otherDataIndices && otherDataIndices[dataIndex]) {\n                    otherDataIndices[dataIndex] = null;\n                }\n                else {\n                    (map$$1[seriesId] || (map$$1[seriesId] = {}))[dataIndex] = 1;\n                }\n            }\n        }\n    }\n\n    function mapToArray(map$$1, isData) {\n        var result = [];\n        for (var i in map$$1) {\n            if (map$$1.hasOwnProperty(i) && map$$1[i] != null) {\n                if (isData) {\n                    result.push(+i);\n                }\n                else {\n                    var dataIndices = mapToArray(map$$1[i], true);\n                    dataIndices.length && result.push({seriesId: i, dataIndex: dataIndices});\n                }\n            }\n        }\n        return result;\n    }\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {Object} payload Contains dataIndex (means rawIndex) / dataIndexInside / name\n *                         each of which can be Array or primary type.\n * @return {number|Array.<number>} dataIndex If not found, return undefined/null.\n */\nfunction queryDataIndex(data, payload) {\n    if (payload.dataIndexInside != null) {\n        return payload.dataIndexInside;\n    }\n    else if (payload.dataIndex != null) {\n        return isArray(payload.dataIndex)\n            ? map(payload.dataIndex, function (value) {\n                return data.indexOfRawIndex(value);\n            })\n            : data.indexOfRawIndex(payload.dataIndex);\n    }\n    else if (payload.name != null) {\n        return isArray(payload.name)\n            ? map(payload.name, function (value) {\n                return data.indexOfName(value);\n            })\n            : data.indexOfName(payload.name);\n    }\n}\n\n/**\n * Enable property storage to any host object.\n * Notice: Serialization is not supported.\n *\n * For example:\n * var inner = zrUitl.makeInner();\n *\n * function some1(hostObj) {\n *      inner(hostObj).someProperty = 1212;\n *      ...\n * }\n * function some2() {\n *      var fields = inner(this);\n *      fields.someProperty1 = 1212;\n *      fields.someProperty2 = 'xx';\n *      ...\n * }\n *\n * @return {Function}\n */\nfunction makeInner() {\n    // Consider different scope by es module import.\n    var key = '__\\0ec_inner_' + innerUniqueIndex++ + '_' + Math.random().toFixed(5);\n    return function (hostObj) {\n        return hostObj[key] || (hostObj[key] = {});\n    };\n}\nvar innerUniqueIndex = 0;\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex, seriesId, seriesName,\n *            geoIndex, geoId, geoName,\n *            bmapIndex, bmapId, bmapName,\n *            xAxisIndex, xAxisId, xAxisName,\n *            yAxisIndex, yAxisId, yAxisName,\n *            gridIndex, gridId, gridName,\n *            ... (can be extended)\n *        }\n *        Each properties can be number|string|Array.<number>|Array.<string>\n *        For example, a finder could be\n *        {\n *            seriesIndex: 3,\n *            geoId: ['aa', 'cc'],\n *            gridName: ['xx', 'rr']\n *        }\n *        xxxIndex can be set as 'all' (means all xxx) or 'none' (means not specify)\n *        If nothing or null/undefined specified, return nothing.\n * @param {Object} [opt]\n * @param {string} [opt.defaultMainType]\n * @param {Array.<string>} [opt.includeMainTypes]\n * @return {Object} result like:\n *        {\n *            seriesModels: [seriesModel1, seriesModel2],\n *            seriesModel: seriesModel1, // The first model\n *            geoModels: [geoModel1, geoModel2],\n *            geoModel: geoModel1, // The first model\n *            ...\n *        }\n */\nfunction parseFinder(ecModel, finder, opt) {\n    if (isString(finder)) {\n        var obj = {};\n        obj[finder + 'Index'] = 0;\n        finder = obj;\n    }\n\n    var defaultMainType = opt && opt.defaultMainType;\n    if (defaultMainType\n        && !has(finder, defaultMainType + 'Index')\n        && !has(finder, defaultMainType + 'Id')\n        && !has(finder, defaultMainType + 'Name')\n    ) {\n        finder[defaultMainType + 'Index'] = 0;\n    }\n\n    var result = {};\n\n    each$2(finder, function (value, key) {\n        var value = finder[key];\n\n        // Exclude 'dataIndex' and other illgal keys.\n        if (key === 'dataIndex' || key === 'dataIndexInside') {\n            result[key] = value;\n            return;\n        }\n\n        var parsedKey = key.match(/^(\\w+)(Index|Id|Name)$/) || [];\n        var mainType = parsedKey[1];\n        var queryType = (parsedKey[2] || '').toLowerCase();\n\n        if (!mainType\n            || !queryType\n            || value == null\n            || (queryType === 'index' && value === 'none')\n            || (opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0)\n        ) {\n            return;\n        }\n\n        var queryParam = {mainType: mainType};\n        if (queryType !== 'index' || value !== 'all') {\n            queryParam[queryType] = value;\n        }\n\n        var models = ecModel.queryComponents(queryParam);\n        result[mainType + 'Models'] = models;\n        result[mainType + 'Model'] = models[0];\n    });\n\n    return result;\n}\n\nfunction has(obj, prop) {\n    return obj && obj.hasOwnProperty(prop);\n}\n\nfunction setAttribute(dom, key, value) {\n    dom.setAttribute\n        ? dom.setAttribute(key, value)\n        : (dom[key] = value);\n}\n\nfunction getAttribute(dom, key) {\n    return dom.getAttribute\n        ? dom.getAttribute(key)\n        : dom[key];\n}\n\nfunction getTooltipRenderMode(renderModeOption) {\n    if (renderModeOption === 'auto') {\n        // Using html when `document` exists, use richText otherwise\n        return env$1.domSupported ? 'html' : 'richText';\n    }\n    else {\n        return renderModeOption || 'html';\n    }\n}\n\n/**\n * Group a list by key.\n *\n * @param {Array} array\n * @param {Function} getKey\n *        param {*} Array item\n *        return {string} key\n * @return {Object} Result\n *        {Array}: keys,\n *        {module:zrender/core/util/HashMap} buckets: {key -> Array}\n */\nfunction groupData(array, getKey) {\n    var buckets = createHashMap();\n    var keys = [];\n\n    each$1(array, function (item) {\n        var key = getKey(item);\n        (buckets.get(key)\n            || (keys.push(key), buckets.set(key, []))\n        ).push(item);\n    });\n\n    return {keys: keys, buckets: buckets};\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TYPE_DELIMITER = '.';\nvar IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';\n\n/**\n * Notice, parseClassType('') should returns {main: '', sub: ''}\n * @public\n */\nfunction parseClassType$1(componentType) {\n    var ret = {main: '', sub: ''};\n    if (componentType) {\n        componentType = componentType.split(TYPE_DELIMITER);\n        ret.main = componentType[0] || '';\n        ret.sub = componentType[1] || '';\n    }\n    return ret;\n}\n\n/**\n * @public\n */\nfunction checkClassType(componentType) {\n    assert$1(\n        /^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType),\n        'componentType \"' + componentType + '\" illegal'\n    );\n}\n\n/**\n * @public\n */\nfunction enableClassExtend(RootClass, mandatoryMethods) {\n\n    RootClass.$constructor = RootClass;\n    RootClass.extend = function (proto) {\n\n        if (__DEV__) {\n            each$1(mandatoryMethods, function (method) {\n                if (!proto[method]) {\n                    console.warn(\n                        'Method `' + method + '` should be implemented'\n                        + (proto.type ? ' in ' + proto.type : '') + '.'\n                    );\n                }\n            });\n        }\n\n        var superClass = this;\n        var ExtendedClass = function () {\n            if (!proto.$constructor) {\n                superClass.apply(this, arguments);\n            }\n            else {\n                proto.$constructor.apply(this, arguments);\n            }\n        };\n\n        extend(ExtendedClass.prototype, proto);\n\n        ExtendedClass.extend = this.extend;\n        ExtendedClass.superCall = superCall;\n        ExtendedClass.superApply = superApply;\n        inherits(ExtendedClass, this);\n        ExtendedClass.superClass = superClass;\n\n        return ExtendedClass;\n    };\n}\n\nvar classBase = 0;\n\n/**\n * Can not use instanceof, consider different scope by\n * cross domain or es module import in ec extensions.\n * Mount a method \"isInstance()\" to Clz.\n */\nfunction enableClassCheck(Clz) {\n    var classAttr = ['__\\0is_clz', classBase++, Math.random().toFixed(3)].join('_');\n    Clz.prototype[classAttr] = true;\n\n    if (__DEV__) {\n        assert$1(!Clz.isInstance, 'The method \"is\" can not be defined.');\n    }\n\n    Clz.isInstance = function (obj) {\n        return !!(obj && obj[classAttr]);\n    };\n}\n\n// superCall should have class info, which can not be fetch from 'this'.\n// Consider this case:\n// class A has method f,\n// class B inherits class A, overrides method f, f call superApply('f'),\n// class C inherits class B, do not overrides method f,\n// then when method of class C is called, dead loop occured.\nfunction superCall(context, methodName) {\n    var args = slice(arguments, 2);\n    return this.superClass.prototype[methodName].apply(context, args);\n}\n\nfunction superApply(context, methodName, args) {\n    return this.superClass.prototype[methodName].apply(context, args);\n}\n\n/**\n * @param {Object} entity\n * @param {Object} options\n * @param {boolean} [options.registerWhenExtend]\n * @public\n */\nfunction enableClassManagement(entity, options) {\n    options = options || {};\n\n    /**\n     * Component model classes\n     * key: componentType,\n     * value:\n     *     componentClass, when componentType is 'xxx'\n     *     or Object.<subKey, componentClass>, when componentType is 'xxx.yy'\n     * @type {Object}\n     */\n    var storage = {};\n\n    entity.registerClass = function (Clazz, componentType) {\n        if (componentType) {\n            checkClassType(componentType);\n            componentType = parseClassType$1(componentType);\n\n            if (!componentType.sub) {\n                if (__DEV__) {\n                    if (storage[componentType.main]) {\n                        console.warn(componentType.main + ' exists.');\n                    }\n                }\n                storage[componentType.main] = Clazz;\n            }\n            else if (componentType.sub !== IS_CONTAINER) {\n                var container = makeContainer(componentType);\n                container[componentType.sub] = Clazz;\n            }\n        }\n        return Clazz;\n    };\n\n    entity.getClass = function (componentMainType, subType, throwWhenNotFound) {\n        var Clazz = storage[componentMainType];\n\n        if (Clazz && Clazz[IS_CONTAINER]) {\n            Clazz = subType ? Clazz[subType] : null;\n        }\n\n        if (throwWhenNotFound && !Clazz) {\n            throw new Error(\n                !subType\n                    ? componentMainType + '.' + 'type should be specified.'\n                    : 'Component ' + componentMainType + '.' + (subType || '') + ' not exists. Load it first.'\n            );\n        }\n\n        return Clazz;\n    };\n\n    entity.getClassesByMainType = function (componentType) {\n        componentType = parseClassType$1(componentType);\n\n        var result = [];\n        var obj = storage[componentType.main];\n\n        if (obj && obj[IS_CONTAINER]) {\n            each$1(obj, function (o, type) {\n                type !== IS_CONTAINER && result.push(o);\n            });\n        }\n        else {\n            result.push(obj);\n        }\n\n        return result;\n    };\n\n    entity.hasClass = function (componentType) {\n        // Just consider componentType.main.\n        componentType = parseClassType$1(componentType);\n        return !!storage[componentType.main];\n    };\n\n    /**\n     * @return {Array.<string>} Like ['aa', 'bb'], but can not be ['aa.xx']\n     */\n    entity.getAllClassMainTypes = function () {\n        var types = [];\n        each$1(storage, function (obj, type) {\n            types.push(type);\n        });\n        return types;\n    };\n\n    /**\n     * If a main type is container and has sub types\n     * @param  {string}  mainType\n     * @return {boolean}\n     */\n    entity.hasSubTypes = function (componentType) {\n        componentType = parseClassType$1(componentType);\n        var obj = storage[componentType.main];\n        return obj && obj[IS_CONTAINER];\n    };\n\n    entity.parseClassType = parseClassType$1;\n\n    function makeContainer(componentType) {\n        var container = storage[componentType.main];\n        if (!container || !container[IS_CONTAINER]) {\n            container = storage[componentType.main] = {};\n            container[IS_CONTAINER] = true;\n        }\n        return container;\n    }\n\n    if (options.registerWhenExtend) {\n        var originalExtend = entity.extend;\n        if (originalExtend) {\n            entity.extend = function (proto) {\n                var ExtendedClass = originalExtend.call(this, proto);\n                return entity.registerClass(ExtendedClass, proto.type);\n            };\n        }\n    }\n\n    return entity;\n}\n\n/**\n * @param {string|Array.<string>} properties\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Parse shadow style\n// TODO Only shallow path support\nvar makeStyleMapper = function (properties) {\n    // Normalize\n    for (var i = 0; i < properties.length; i++) {\n        if (!properties[i][1]) {\n            properties[i][1] = properties[i][0];\n        }\n    }\n    return function (model, excludes, includes) {\n        var style = {};\n        for (var i = 0; i < properties.length; i++) {\n            var propName = properties[i][1];\n            if ((excludes && indexOf(excludes, propName) >= 0)\n                || (includes && indexOf(includes, propName) < 0)\n            ) {\n                continue;\n            }\n            var val = model.getShallow(propName);\n            if (val != null) {\n                style[properties[i][0]] = val;\n            }\n        }\n        return style;\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getLineStyle = makeStyleMapper(\n    [\n        ['lineWidth', 'width'],\n        ['stroke', 'color'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor']\n    ]\n);\n\nvar lineStyleMixin = {\n    getLineStyle: function (excludes) {\n        var style = getLineStyle(this, excludes);\n        var lineDash = this.getLineDash(style.lineWidth);\n        lineDash && (style.lineDash = lineDash);\n        return style;\n    },\n\n    getLineDash: function (lineWidth) {\n        if (lineWidth == null) {\n            lineWidth = 1;\n        }\n        var lineType = this.get('type');\n        var dotSize = Math.max(lineWidth, 2);\n        var dashSize = lineWidth * 4;\n        return (lineType === 'solid' || lineType == null) ? null\n            : (lineType === 'dashed' ? [dashSize, dashSize] : [dotSize, dotSize]);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getAreaStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['opacity'],\n        ['shadowColor']\n    ]\n);\n\nvar areaStyleMixin = {\n    getAreaStyle: function (excludes, includes) {\n        return getAreaStyle(this, excludes, includes);\n    }\n};\n\n/**\n * 曲线辅助模块\n * @module zrender/core/curve\n * @author pissang(https://www.github.com/pissang)\n */\n\nvar mathPow = Math.pow;\nvar mathSqrt$2 = Math.sqrt;\n\nvar EPSILON$1 = 1e-8;\nvar EPSILON_NUMERIC = 1e-4;\n\nvar THREE_SQRT = mathSqrt$2(3);\nvar ONE_THIRD = 1 / 3;\n\n// 临时变量\nvar _v0 = create();\nvar _v1 = create();\nvar _v2 = create();\n\nfunction isAroundZero(val) {\n    return val > -EPSILON$1 && val < EPSILON$1;\n}\nfunction isNotAroundZero$1(val) {\n    return val > EPSILON$1 || val < -EPSILON$1;\n}\n/**\n * 计算三次贝塞尔值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @return {number}\n */\nfunction cubicAt(p0, p1, p2, p3, t) {\n    var onet = 1 - t;\n    return onet * onet * (onet * p0 + 3 * t * p1)\n            + t * t * (t * p3 + 3 * onet * p2);\n}\n\n/**\n * 计算三次贝塞尔导数值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @return {number}\n */\nfunction cubicDerivativeAt(p0, p1, p2, p3, t) {\n    var onet = 1 - t;\n    return 3 * (\n        ((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet\n        + (p3 - p2) * t * t\n    );\n}\n\n/**\n * 计算三次贝塞尔方程根，使用盛金公式\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} val\n * @param  {Array.<number>} roots\n * @return {number} 有效根数目\n */\nfunction cubicRootAt(p0, p1, p2, p3, val, roots) {\n    // Evaluate roots of cubic functions\n    var a = p3 + 3 * (p1 - p2) - p0;\n    var b = 3 * (p2 - p1 * 2 + p0);\n    var c = 3 * (p1 - p0);\n    var d = p0 - val;\n\n    var A = b * b - 3 * a * c;\n    var B = b * c - 9 * a * d;\n    var C = c * c - 3 * b * d;\n\n    var n = 0;\n\n    if (isAroundZero(A) && isAroundZero(B)) {\n        if (isAroundZero(b)) {\n            roots[0] = 0;\n        }\n        else {\n            var t1 = -c / b;  //t1, t2, t3, b is not zero\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = B * B - 4 * A * C;\n\n        if (isAroundZero(disc)) {\n            var K = B / A;\n            var t1 = -b / a + K;  // t1, a is not zero\n            var t2 = -K / 2;  // t2, t3\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var Y1 = A * b + 1.5 * a * (-B + discSqrt);\n            var Y2 = A * b + 1.5 * a * (-B - discSqrt);\n            if (Y1 < 0) {\n                Y1 = -mathPow(-Y1, ONE_THIRD);\n            }\n            else {\n                Y1 = mathPow(Y1, ONE_THIRD);\n            }\n            if (Y2 < 0) {\n                Y2 = -mathPow(-Y2, ONE_THIRD);\n            }\n            else {\n                Y2 = mathPow(Y2, ONE_THIRD);\n            }\n            var t1 = (-b - (Y1 + Y2)) / (3 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n        else {\n            var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt$2(A * A * A));\n            var theta = Math.acos(T) / 3;\n            var ASqrt = mathSqrt$2(A);\n            var tmp = Math.cos(theta);\n\n            var t1 = (-b - 2 * ASqrt * tmp) / (3 * a);\n            var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a);\n            var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n            if (t3 >= 0 && t3 <= 1) {\n                roots[n++] = t3;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 计算三次贝塞尔方程极限值的位置\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {Array.<number>} extrema\n * @return {number} 有效数目\n */\nfunction cubicExtrema(p0, p1, p2, p3, extrema) {\n    var b = 6 * p2 - 12 * p1 + 6 * p0;\n    var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2;\n    var c = 3 * p1 - 3 * p0;\n\n    var n = 0;\n    if (isAroundZero(a)) {\n        if (isNotAroundZero$1(b)) {\n            var t1 = -c / b;\n            if (t1 >= 0 && t1 <= 1) {\n                extrema[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = b * b - 4 * a * c;\n        if (isAroundZero(disc)) {\n            extrema[0] = -b / (2 * a);\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var t1 = (-b + discSqrt) / (2 * a);\n            var t2 = (-b - discSqrt) / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                extrema[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                extrema[n++] = t2;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 细分三次贝塞尔曲线\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @param  {Array.<number>} out\n */\nfunction cubicSubdivide(p0, p1, p2, p3, t, out) {\n    var p01 = (p1 - p0) * t + p0;\n    var p12 = (p2 - p1) * t + p1;\n    var p23 = (p3 - p2) * t + p2;\n\n    var p012 = (p12 - p01) * t + p01;\n    var p123 = (p23 - p12) * t + p12;\n\n    var p0123 = (p123 - p012) * t + p012;\n    // Seg0\n    out[0] = p0;\n    out[1] = p01;\n    out[2] = p012;\n    out[3] = p0123;\n    // Seg1\n    out[4] = p0123;\n    out[5] = p123;\n    out[6] = p23;\n    out[7] = p3;\n}\n\n/**\n * 投射点到三次贝塞尔曲线上，返回投射距离。\n * 投射点有可能会有一个或者多个，这里只返回其中距离最短的一个。\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x3\n * @param {number} y3\n * @param {number} x\n * @param {number} y\n * @param {Array.<number>} [out] 投射点\n * @return {number}\n */\nfunction cubicProjectPoint(\n    x0, y0, x1, y1, x2, y2, x3, y3,\n    x, y, out\n) {\n    // http://pomax.github.io/bezierinfo/#projections\n    var t;\n    var interval = 0.005;\n    var d = Infinity;\n    var prev;\n    var next;\n    var d1;\n    var d2;\n\n    _v0[0] = x;\n    _v0[1] = y;\n\n    // 先粗略估计一下可能的最小距离的 t 值\n    // PENDING\n    for (var _t = 0; _t < 1; _t += 0.05) {\n        _v1[0] = cubicAt(x0, x1, x2, x3, _t);\n        _v1[1] = cubicAt(y0, y1, y2, y3, _t);\n        d1 = distSquare(_v0, _v1);\n        if (d1 < d) {\n            t = _t;\n            d = d1;\n        }\n    }\n    d = Infinity;\n\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        if (interval < EPSILON_NUMERIC) {\n            break;\n        }\n        prev = t - interval;\n        next = t + interval;\n        // t - interval\n        _v1[0] = cubicAt(x0, x1, x2, x3, prev);\n        _v1[1] = cubicAt(y0, y1, y2, y3, prev);\n\n        d1 = distSquare(_v1, _v0);\n\n        if (prev >= 0 && d1 < d) {\n            t = prev;\n            d = d1;\n        }\n        else {\n            // t + interval\n            _v2[0] = cubicAt(x0, x1, x2, x3, next);\n            _v2[1] = cubicAt(y0, y1, y2, y3, next);\n            d2 = distSquare(_v2, _v0);\n\n            if (next <= 1 && d2 < d) {\n                t = next;\n                d = d2;\n            }\n            else {\n                interval *= 0.5;\n            }\n        }\n    }\n    // t\n    if (out) {\n        out[0] = cubicAt(x0, x1, x2, x3, t);\n        out[1] = cubicAt(y0, y1, y2, y3, t);\n    }\n    // console.log(interval, i);\n    return mathSqrt$2(d);\n}\n\n/**\n * 计算二次方贝塞尔值\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @return {number}\n */\nfunction quadraticAt(p0, p1, p2, t) {\n    var onet = 1 - t;\n    return onet * (onet * p0 + 2 * t * p1) + t * t * p2;\n}\n\n/**\n * 计算二次方贝塞尔导数值\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @return {number}\n */\nfunction quadraticDerivativeAt(p0, p1, p2, t) {\n    return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1));\n}\n\n/**\n * 计算二次方贝塞尔方程根\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @param  {Array.<number>} roots\n * @return {number} 有效根数目\n */\nfunction quadraticRootAt(p0, p1, p2, val, roots) {\n    var a = p0 - 2 * p1 + p2;\n    var b = 2 * (p1 - p0);\n    var c = p0 - val;\n\n    var n = 0;\n    if (isAroundZero(a)) {\n        if (isNotAroundZero$1(b)) {\n            var t1 = -c / b;\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = b * b - 4 * a * c;\n        if (isAroundZero(disc)) {\n            var t1 = -b / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var t1 = (-b + discSqrt) / (2 * a);\n            var t2 = (-b - discSqrt) / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 计算二次贝塞尔方程极限值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @return {number}\n */\nfunction quadraticExtremum(p0, p1, p2) {\n    var divider = p0 + p2 - 2 * p1;\n    if (divider === 0) {\n        // p1 is center of p0 and p2\n        return 0.5;\n    }\n    else {\n        return (p0 - p1) / divider;\n    }\n}\n\n/**\n * 细分二次贝塞尔曲线\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @param  {Array.<number>} out\n */\nfunction quadraticSubdivide(p0, p1, p2, t, out) {\n    var p01 = (p1 - p0) * t + p0;\n    var p12 = (p2 - p1) * t + p1;\n    var p012 = (p12 - p01) * t + p01;\n\n    // Seg0\n    out[0] = p0;\n    out[1] = p01;\n    out[2] = p012;\n\n    // Seg1\n    out[3] = p012;\n    out[4] = p12;\n    out[5] = p2;\n}\n\n/**\n * 投射点到二次贝塞尔曲线上，返回投射距离。\n * 投射点有可能会有一个或者多个，这里只返回其中距离最短的一个。\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x\n * @param {number} y\n * @param {Array.<number>} out 投射点\n * @return {number}\n */\nfunction quadraticProjectPoint(\n    x0, y0, x1, y1, x2, y2,\n    x, y, out\n) {\n    // http://pomax.github.io/bezierinfo/#projections\n    var t;\n    var interval = 0.005;\n    var d = Infinity;\n\n    _v0[0] = x;\n    _v0[1] = y;\n\n    // 先粗略估计一下可能的最小距离的 t 值\n    // PENDING\n    for (var _t = 0; _t < 1; _t += 0.05) {\n        _v1[0] = quadraticAt(x0, x1, x2, _t);\n        _v1[1] = quadraticAt(y0, y1, y2, _t);\n        var d1 = distSquare(_v0, _v1);\n        if (d1 < d) {\n            t = _t;\n            d = d1;\n        }\n    }\n    d = Infinity;\n\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        if (interval < EPSILON_NUMERIC) {\n            break;\n        }\n        var prev = t - interval;\n        var next = t + interval;\n        // t - interval\n        _v1[0] = quadraticAt(x0, x1, x2, prev);\n        _v1[1] = quadraticAt(y0, y1, y2, prev);\n\n        var d1 = distSquare(_v1, _v0);\n\n        if (prev >= 0 && d1 < d) {\n            t = prev;\n            d = d1;\n        }\n        else {\n            // t + interval\n            _v2[0] = quadraticAt(x0, x1, x2, next);\n            _v2[1] = quadraticAt(y0, y1, y2, next);\n            var d2 = distSquare(_v2, _v0);\n            if (next <= 1 && d2 < d) {\n                t = next;\n                d = d2;\n            }\n            else {\n                interval *= 0.5;\n            }\n        }\n    }\n    // t\n    if (out) {\n        out[0] = quadraticAt(x0, x1, x2, t);\n        out[1] = quadraticAt(y0, y1, y2, t);\n    }\n    // console.log(interval, i);\n    return mathSqrt$2(d);\n}\n\n/**\n * @author Yi Shen(https://github.com/pissang)\n */\n\nvar mathMin$3 = Math.min;\nvar mathMax$3 = Math.max;\nvar mathSin$2 = Math.sin;\nvar mathCos$2 = Math.cos;\nvar PI2 = Math.PI * 2;\n\nvar start = create();\nvar end = create();\nvar extremity = create();\n\n/**\n * 从顶点数组中计算出最小包围盒，写入`min`和`max`中\n * @module zrender/core/bbox\n * @param {Array<Object>} points 顶点数组\n * @param {number} min\n * @param {number} max\n */\nfunction fromPoints(points, min$$1, max$$1) {\n    if (points.length === 0) {\n        return;\n    }\n    var p = points[0];\n    var left = p[0];\n    var right = p[0];\n    var top = p[1];\n    var bottom = p[1];\n    var i;\n\n    for (i = 1; i < points.length; i++) {\n        p = points[i];\n        left = mathMin$3(left, p[0]);\n        right = mathMax$3(right, p[0]);\n        top = mathMin$3(top, p[1]);\n        bottom = mathMax$3(bottom, p[1]);\n    }\n\n    min$$1[0] = left;\n    min$$1[1] = top;\n    max$$1[0] = right;\n    max$$1[1] = bottom;\n}\n\n/**\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromLine(x0, y0, x1, y1, min$$1, max$$1) {\n    min$$1[0] = mathMin$3(x0, x1);\n    min$$1[1] = mathMin$3(y0, y1);\n    max$$1[0] = mathMax$3(x0, x1);\n    max$$1[1] = mathMax$3(y0, y1);\n}\n\nvar xDim = [];\nvar yDim = [];\n/**\n * 从三阶贝塞尔曲线(p0, p1, p2, p3)中计算出最小包围盒，写入`min`和`max`中\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x3\n * @param {number} y3\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromCubic(\n    x0, y0, x1, y1, x2, y2, x3, y3, min$$1, max$$1\n) {\n    var cubicExtrema$$1 = cubicExtrema;\n    var cubicAt$$1 = cubicAt;\n    var i;\n    var n = cubicExtrema$$1(x0, x1, x2, x3, xDim);\n    min$$1[0] = Infinity;\n    min$$1[1] = Infinity;\n    max$$1[0] = -Infinity;\n    max$$1[1] = -Infinity;\n\n    for (i = 0; i < n; i++) {\n        var x = cubicAt$$1(x0, x1, x2, x3, xDim[i]);\n        min$$1[0] = mathMin$3(x, min$$1[0]);\n        max$$1[0] = mathMax$3(x, max$$1[0]);\n    }\n    n = cubicExtrema$$1(y0, y1, y2, y3, yDim);\n    for (i = 0; i < n; i++) {\n        var y = cubicAt$$1(y0, y1, y2, y3, yDim[i]);\n        min$$1[1] = mathMin$3(y, min$$1[1]);\n        max$$1[1] = mathMax$3(y, max$$1[1]);\n    }\n\n    min$$1[0] = mathMin$3(x0, min$$1[0]);\n    max$$1[0] = mathMax$3(x0, max$$1[0]);\n    min$$1[0] = mathMin$3(x3, min$$1[0]);\n    max$$1[0] = mathMax$3(x3, max$$1[0]);\n\n    min$$1[1] = mathMin$3(y0, min$$1[1]);\n    max$$1[1] = mathMax$3(y0, max$$1[1]);\n    min$$1[1] = mathMin$3(y3, min$$1[1]);\n    max$$1[1] = mathMax$3(y3, max$$1[1]);\n}\n\n/**\n * 从二阶贝塞尔曲线(p0, p1, p2)中计算出最小包围盒，写入`min`和`max`中\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromQuadratic(x0, y0, x1, y1, x2, y2, min$$1, max$$1) {\n    var quadraticExtremum$$1 = quadraticExtremum;\n    var quadraticAt$$1 = quadraticAt;\n    // Find extremities, where derivative in x dim or y dim is zero\n    var tx =\n        mathMax$3(\n            mathMin$3(quadraticExtremum$$1(x0, x1, x2), 1), 0\n        );\n    var ty =\n        mathMax$3(\n            mathMin$3(quadraticExtremum$$1(y0, y1, y2), 1), 0\n        );\n\n    var x = quadraticAt$$1(x0, x1, x2, tx);\n    var y = quadraticAt$$1(y0, y1, y2, ty);\n\n    min$$1[0] = mathMin$3(x0, x2, x);\n    min$$1[1] = mathMin$3(y0, y2, y);\n    max$$1[0] = mathMax$3(x0, x2, x);\n    max$$1[1] = mathMax$3(y0, y2, y);\n}\n\n/**\n * 从圆弧中计算出最小包围盒，写入`min`和`max`中\n * @method\n * @memberOf module:zrender/core/bbox\n * @param {number} x\n * @param {number} y\n * @param {number} rx\n * @param {number} ry\n * @param {number} startAngle\n * @param {number} endAngle\n * @param {number} anticlockwise\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromArc(\n    x, y, rx, ry, startAngle, endAngle, anticlockwise, min$$1, max$$1\n) {\n    var vec2Min = min;\n    var vec2Max = max;\n\n    var diff = Math.abs(startAngle - endAngle);\n\n\n    if (diff % PI2 < 1e-4 && diff > 1e-4) {\n        // Is a circle\n        min$$1[0] = x - rx;\n        min$$1[1] = y - ry;\n        max$$1[0] = x + rx;\n        max$$1[1] = y + ry;\n        return;\n    }\n\n    start[0] = mathCos$2(startAngle) * rx + x;\n    start[1] = mathSin$2(startAngle) * ry + y;\n\n    end[0] = mathCos$2(endAngle) * rx + x;\n    end[1] = mathSin$2(endAngle) * ry + y;\n\n    vec2Min(min$$1, start, end);\n    vec2Max(max$$1, start, end);\n\n    // Thresh to [0, Math.PI * 2]\n    startAngle = startAngle % (PI2);\n    if (startAngle < 0) {\n        startAngle = startAngle + PI2;\n    }\n    endAngle = endAngle % (PI2);\n    if (endAngle < 0) {\n        endAngle = endAngle + PI2;\n    }\n\n    if (startAngle > endAngle && !anticlockwise) {\n        endAngle += PI2;\n    }\n    else if (startAngle < endAngle && anticlockwise) {\n        startAngle += PI2;\n    }\n    if (anticlockwise) {\n        var tmp = endAngle;\n        endAngle = startAngle;\n        startAngle = tmp;\n    }\n\n    // var number = 0;\n    // var step = (anticlockwise ? -Math.PI : Math.PI) / 2;\n    for (var angle = 0; angle < endAngle; angle += Math.PI / 2) {\n        if (angle > startAngle) {\n            extremity[0] = mathCos$2(angle) * rx + x;\n            extremity[1] = mathSin$2(angle) * ry + y;\n\n            vec2Min(min$$1, extremity, min$$1);\n            vec2Max(max$$1, extremity, max$$1);\n        }\n    }\n}\n\n/**\n * Path 代理，可以在`buildPath`中用于替代`ctx`, 会保存每个path操作的命令到pathCommands属性中\n * 可以用于 isInsidePath 判断以及获取boundingRect\n *\n * @module zrender/core/PathProxy\n * @author Yi Shen (http://www.github.com/pissang)\n */\n\n// TODO getTotalLength, getPointAtLength\n\nvar CMD = {\n    M: 1,\n    L: 2,\n    C: 3,\n    Q: 4,\n    A: 5,\n    Z: 6,\n    // Rect\n    R: 7\n};\n\n// var CMD_MEM_SIZE = {\n//     M: 3,\n//     L: 3,\n//     C: 7,\n//     Q: 5,\n//     A: 9,\n//     R: 5,\n//     Z: 1\n// };\n\nvar min$1 = [];\nvar max$1 = [];\nvar min2 = [];\nvar max2 = [];\nvar mathMin$2 = Math.min;\nvar mathMax$2 = Math.max;\nvar mathCos$1 = Math.cos;\nvar mathSin$1 = Math.sin;\nvar mathSqrt$1 = Math.sqrt;\nvar mathAbs = Math.abs;\n\nvar hasTypedArray = typeof Float32Array !== 'undefined';\n\n/**\n * @alias module:zrender/core/PathProxy\n * @constructor\n */\nvar PathProxy = function (notSaveData) {\n\n    this._saveData = !(notSaveData || false);\n\n    if (this._saveData) {\n        /**\n         * Path data. Stored as flat array\n         * @type {Array.<Object>}\n         */\n        this.data = [];\n    }\n\n    this._ctx = null;\n};\n\n/**\n * 快速计算Path包围盒（并不是最小包围盒）\n * @return {Object}\n */\nPathProxy.prototype = {\n\n    constructor: PathProxy,\n\n    _xi: 0,\n    _yi: 0,\n\n    _x0: 0,\n    _y0: 0,\n    // Unit x, Unit y. Provide for avoiding drawing that too short line segment\n    _ux: 0,\n    _uy: 0,\n\n    _len: 0,\n\n    _lineDash: null,\n\n    _dashOffset: 0,\n\n    _dashIdx: 0,\n\n    _dashSum: 0,\n\n    /**\n     * @readOnly\n     */\n    setScale: function (sx, sy) {\n        this._ux = mathAbs(1 / devicePixelRatio / sx) || 0;\n        this._uy = mathAbs(1 / devicePixelRatio / sy) || 0;\n    },\n\n    getContext: function () {\n        return this._ctx;\n    },\n\n    /**\n     * @param  {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    beginPath: function (ctx) {\n\n        this._ctx = ctx;\n\n        ctx && ctx.beginPath();\n\n        ctx && (this.dpr = ctx.dpr);\n\n        // Reset\n        if (this._saveData) {\n            this._len = 0;\n        }\n\n        if (this._lineDash) {\n            this._lineDash = null;\n\n            this._dashOffset = 0;\n        }\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x\n     * @param  {number} y\n     * @return {module:zrender/core/PathProxy}\n     */\n    moveTo: function (x, y) {\n        this.addData(CMD.M, x, y);\n        this._ctx && this._ctx.moveTo(x, y);\n\n        // x0, y0, xi, yi 是记录在 _dashedXXXXTo 方法中使用\n        // xi, yi 记录当前点, x0, y0 在 closePath 的时候回到起始点。\n        // 有可能在 beginPath 之后直接调用 lineTo，这时候 x0, y0 需要\n        // 在 lineTo 方法中记录，这里先不考虑这种情况，dashed line 也只在 IE10- 中不支持\n        this._x0 = x;\n        this._y0 = y;\n\n        this._xi = x;\n        this._yi = y;\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x\n     * @param  {number} y\n     * @return {module:zrender/core/PathProxy}\n     */\n    lineTo: function (x, y) {\n        var exceedUnit = mathAbs(x - this._xi) > this._ux\n            || mathAbs(y - this._yi) > this._uy\n            // Force draw the first segment\n            || this._len < 5;\n\n        this.addData(CMD.L, x, y);\n\n        if (this._ctx && exceedUnit) {\n            this._needsDash() ? this._dashedLineTo(x, y)\n                : this._ctx.lineTo(x, y);\n        }\n        if (exceedUnit) {\n            this._xi = x;\n            this._yi = y;\n        }\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x1\n     * @param  {number} y1\n     * @param  {number} x2\n     * @param  {number} y2\n     * @param  {number} x3\n     * @param  {number} y3\n     * @return {module:zrender/core/PathProxy}\n     */\n    bezierCurveTo: function (x1, y1, x2, y2, x3, y3) {\n        this.addData(CMD.C, x1, y1, x2, y2, x3, y3);\n        if (this._ctx) {\n            this._needsDash() ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3)\n                : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);\n        }\n        this._xi = x3;\n        this._yi = y3;\n        return this;\n    },\n\n    /**\n     * @param  {number} x1\n     * @param  {number} y1\n     * @param  {number} x2\n     * @param  {number} y2\n     * @return {module:zrender/core/PathProxy}\n     */\n    quadraticCurveTo: function (x1, y1, x2, y2) {\n        this.addData(CMD.Q, x1, y1, x2, y2);\n        if (this._ctx) {\n            this._needsDash() ? this._dashedQuadraticTo(x1, y1, x2, y2)\n                : this._ctx.quadraticCurveTo(x1, y1, x2, y2);\n        }\n        this._xi = x2;\n        this._yi = y2;\n        return this;\n    },\n\n    /**\n     * @param  {number} cx\n     * @param  {number} cy\n     * @param  {number} r\n     * @param  {number} startAngle\n     * @param  {number} endAngle\n     * @param  {boolean} anticlockwise\n     * @return {module:zrender/core/PathProxy}\n     */\n    arc: function (cx, cy, r, startAngle, endAngle, anticlockwise) {\n        this.addData(\n            CMD.A, cx, cy, r, r, startAngle, endAngle - startAngle, 0, anticlockwise ? 0 : 1\n        );\n        this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);\n\n        this._xi = mathCos$1(endAngle) * r + cx;\n        this._yi = mathSin$1(endAngle) * r + cy;\n        return this;\n    },\n\n    // TODO\n    arcTo: function (x1, y1, x2, y2, radius) {\n        if (this._ctx) {\n            this._ctx.arcTo(x1, y1, x2, y2, radius);\n        }\n        return this;\n    },\n\n    // TODO\n    rect: function (x, y, w, h) {\n        this._ctx && this._ctx.rect(x, y, w, h);\n        this.addData(CMD.R, x, y, w, h);\n        return this;\n    },\n\n    /**\n     * @return {module:zrender/core/PathProxy}\n     */\n    closePath: function () {\n        this.addData(CMD.Z);\n\n        var ctx = this._ctx;\n        var x0 = this._x0;\n        var y0 = this._y0;\n        if (ctx) {\n            this._needsDash() && this._dashedLineTo(x0, y0);\n            ctx.closePath();\n        }\n\n        this._xi = x0;\n        this._yi = y0;\n        return this;\n    },\n\n    /**\n     * Context 从外部传入，因为有可能是 rebuildPath 完之后再 fill。\n     * stroke 同样\n     * @param {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    fill: function (ctx) {\n        ctx && ctx.fill();\n        this.toStatic();\n    },\n\n    /**\n     * @param {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    stroke: function (ctx) {\n        ctx && ctx.stroke();\n        this.toStatic();\n    },\n\n    /**\n     * 必须在其它绘制命令前调用\n     * Must be invoked before all other path drawing methods\n     * @return {module:zrender/core/PathProxy}\n     */\n    setLineDash: function (lineDash) {\n        if (lineDash instanceof Array) {\n            this._lineDash = lineDash;\n\n            this._dashIdx = 0;\n\n            var lineDashSum = 0;\n            for (var i = 0; i < lineDash.length; i++) {\n                lineDashSum += lineDash[i];\n            }\n            this._dashSum = lineDashSum;\n        }\n        return this;\n    },\n\n    /**\n     * 必须在其它绘制命令前调用\n     * Must be invoked before all other path drawing methods\n     * @return {module:zrender/core/PathProxy}\n     */\n    setLineDashOffset: function (offset) {\n        this._dashOffset = offset;\n        return this;\n    },\n\n    /**\n     *\n     * @return {boolean}\n     */\n    len: function () {\n        return this._len;\n    },\n\n    /**\n     * 直接设置 Path 数据\n     */\n    setData: function (data) {\n\n        var len$$1 = data.length;\n\n        if (!(this.data && this.data.length === len$$1) && hasTypedArray) {\n            this.data = new Float32Array(len$$1);\n        }\n\n        for (var i = 0; i < len$$1; i++) {\n            this.data[i] = data[i];\n        }\n\n        this._len = len$$1;\n    },\n\n    /**\n     * 添加子路径\n     * @param {module:zrender/core/PathProxy|Array.<module:zrender/core/PathProxy>} path\n     */\n    appendPath: function (path) {\n        if (!(path instanceof Array)) {\n            path = [path];\n        }\n        var len$$1 = path.length;\n        var appendSize = 0;\n        var offset = this._len;\n        for (var i = 0; i < len$$1; i++) {\n            appendSize += path[i].len();\n        }\n        if (hasTypedArray && (this.data instanceof Float32Array)) {\n            this.data = new Float32Array(offset + appendSize);\n        }\n        for (var i = 0; i < len$$1; i++) {\n            var appendPathData = path[i].data;\n            for (var k = 0; k < appendPathData.length; k++) {\n                this.data[offset++] = appendPathData[k];\n            }\n        }\n        this._len = offset;\n    },\n\n    /**\n     * 填充 Path 数据。\n     * 尽量复用而不申明新的数组。大部分图形重绘的指令数据长度都是不变的。\n     */\n    addData: function (cmd) {\n        if (!this._saveData) {\n            return;\n        }\n\n        var data = this.data;\n        if (this._len + arguments.length > data.length) {\n            // 因为之前的数组已经转换成静态的 Float32Array\n            // 所以不够用时需要扩展一个新的动态数组\n            this._expandData();\n            data = this.data;\n        }\n        for (var i = 0; i < arguments.length; i++) {\n            data[this._len++] = arguments[i];\n        }\n\n        this._prevCmd = cmd;\n    },\n\n    _expandData: function () {\n        // Only if data is Float32Array\n        if (!(this.data instanceof Array)) {\n            var newData = [];\n            for (var i = 0; i < this._len; i++) {\n                newData[i] = this.data[i];\n            }\n            this.data = newData;\n        }\n    },\n\n    /**\n     * If needs js implemented dashed line\n     * @return {boolean}\n     * @private\n     */\n    _needsDash: function () {\n        return this._lineDash;\n    },\n\n    _dashedLineTo: function (x1, y1) {\n        var dashSum = this._dashSum;\n        var offset = this._dashOffset;\n        var lineDash = this._lineDash;\n        var ctx = this._ctx;\n\n        var x0 = this._xi;\n        var y0 = this._yi;\n        var dx = x1 - x0;\n        var dy = y1 - y0;\n        var dist$$1 = mathSqrt$1(dx * dx + dy * dy);\n        var x = x0;\n        var y = y0;\n        var dash;\n        var nDash = lineDash.length;\n        var idx;\n        dx /= dist$$1;\n        dy /= dist$$1;\n\n        if (offset < 0) {\n            // Convert to positive offset\n            offset = dashSum + offset;\n        }\n        offset %= dashSum;\n        x -= offset * dx;\n        y -= offset * dy;\n\n        while ((dx > 0 && x <= x1) || (dx < 0 && x >= x1)\n        || (dx === 0 && ((dy > 0 && y <= y1) || (dy < 0 && y >= y1)))) {\n            idx = this._dashIdx;\n            dash = lineDash[idx];\n            x += dx * dash;\n            y += dy * dash;\n            this._dashIdx = (idx + 1) % nDash;\n            // Skip positive offset\n            if ((dx > 0 && x < x0) || (dx < 0 && x > x0) || (dy > 0 && y < y0) || (dy < 0 && y > y0)) {\n                continue;\n            }\n            ctx[idx % 2 ? 'moveTo' : 'lineTo'](\n                dx >= 0 ? mathMin$2(x, x1) : mathMax$2(x, x1),\n                dy >= 0 ? mathMin$2(y, y1) : mathMax$2(y, y1)\n            );\n        }\n        // Offset for next lineTo\n        dx = x - x1;\n        dy = y - y1;\n        this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);\n    },\n\n    // Not accurate dashed line to\n    _dashedBezierTo: function (x1, y1, x2, y2, x3, y3) {\n        var dashSum = this._dashSum;\n        var offset = this._dashOffset;\n        var lineDash = this._lineDash;\n        var ctx = this._ctx;\n\n        var x0 = this._xi;\n        var y0 = this._yi;\n        var t;\n        var dx;\n        var dy;\n        var cubicAt$$1 = cubicAt;\n        var bezierLen = 0;\n        var idx = this._dashIdx;\n        var nDash = lineDash.length;\n\n        var x;\n        var y;\n\n        var tmpLen = 0;\n\n        if (offset < 0) {\n            // Convert to positive offset\n            offset = dashSum + offset;\n        }\n        offset %= dashSum;\n        // Bezier approx length\n        for (t = 0; t < 1; t += 0.1) {\n            dx = cubicAt$$1(x0, x1, x2, x3, t + 0.1)\n                - cubicAt$$1(x0, x1, x2, x3, t);\n            dy = cubicAt$$1(y0, y1, y2, y3, t + 0.1)\n                - cubicAt$$1(y0, y1, y2, y3, t);\n            bezierLen += mathSqrt$1(dx * dx + dy * dy);\n        }\n\n        // Find idx after add offset\n        for (; idx < nDash; idx++) {\n            tmpLen += lineDash[idx];\n            if (tmpLen > offset) {\n                break;\n            }\n        }\n        t = (tmpLen - offset) / bezierLen;\n\n        while (t <= 1) {\n\n            x = cubicAt$$1(x0, x1, x2, x3, t);\n            y = cubicAt$$1(y0, y1, y2, y3, t);\n\n            // Use line to approximate dashed bezier\n            // Bad result if dash is long\n            idx % 2 ? ctx.moveTo(x, y)\n                : ctx.lineTo(x, y);\n\n            t += lineDash[idx] / bezierLen;\n\n            idx = (idx + 1) % nDash;\n        }\n\n        // Finish the last segment and calculate the new offset\n        (idx % 2 !== 0) && ctx.lineTo(x3, y3);\n        dx = x3 - x;\n        dy = y3 - y;\n        this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);\n    },\n\n    _dashedQuadraticTo: function (x1, y1, x2, y2) {\n        // Convert quadratic to cubic using degree elevation\n        var x3 = x2;\n        var y3 = y2;\n        x2 = (x2 + 2 * x1) / 3;\n        y2 = (y2 + 2 * y1) / 3;\n        x1 = (this._xi + 2 * x1) / 3;\n        y1 = (this._yi + 2 * y1) / 3;\n\n        this._dashedBezierTo(x1, y1, x2, y2, x3, y3);\n    },\n\n    /**\n     * 转成静态的 Float32Array 减少堆内存占用\n     * Convert dynamic array to static Float32Array\n     */\n    toStatic: function () {\n        var data = this.data;\n        if (data instanceof Array) {\n            data.length = this._len;\n            if (hasTypedArray) {\n                this.data = new Float32Array(data);\n            }\n        }\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function () {\n        min$1[0] = min$1[1] = min2[0] = min2[1] = Number.MAX_VALUE;\n        max$1[0] = max$1[1] = max2[0] = max2[1] = -Number.MAX_VALUE;\n\n        var data = this.data;\n        var xi = 0;\n        var yi = 0;\n        var x0 = 0;\n        var y0 = 0;\n\n        for (var i = 0; i < data.length;) {\n            var cmd = data[i++];\n\n            if (i === 1) {\n                // 如果第一个命令是 L, C, Q\n                // 则 previous point 同绘制命令的第一个 point\n                //\n                // 第一个命令为 Arc 的情况下会在后面特殊处理\n                xi = data[i];\n                yi = data[i + 1];\n\n                x0 = xi;\n                y0 = yi;\n            }\n\n            switch (cmd) {\n                case CMD.M:\n                    // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点\n                    // 在 closePath 的时候使用\n                    x0 = data[i++];\n                    y0 = data[i++];\n                    xi = x0;\n                    yi = y0;\n                    min2[0] = x0;\n                    min2[1] = y0;\n                    max2[0] = x0;\n                    max2[1] = y0;\n                    break;\n                case CMD.L:\n                    fromLine(xi, yi, data[i], data[i + 1], min2, max2);\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.C:\n                    fromCubic(\n                        xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        min2, max2\n                    );\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.Q:\n                    fromQuadratic(\n                        xi, yi, data[i++], data[i++], data[i], data[i + 1],\n                        min2, max2\n                    );\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.A:\n                    // TODO Arc 判断的开销比较大\n                    var cx = data[i++];\n                    var cy = data[i++];\n                    var rx = data[i++];\n                    var ry = data[i++];\n                    var startAngle = data[i++];\n                    var endAngle = data[i++] + startAngle;\n                    // TODO Arc 旋转\n                    i += 1;\n                    var anticlockwise = 1 - data[i++];\n\n                    if (i === 1) {\n                        // 直接使用 arc 命令\n                        // 第一个命令起点还未定义\n                        x0 = mathCos$1(startAngle) * rx + cx;\n                        y0 = mathSin$1(startAngle) * ry + cy;\n                    }\n\n                    fromArc(\n                        cx, cy, rx, ry, startAngle, endAngle,\n                        anticlockwise, min2, max2\n                    );\n\n                    xi = mathCos$1(endAngle) * rx + cx;\n                    yi = mathSin$1(endAngle) * ry + cy;\n                    break;\n                case CMD.R:\n                    x0 = xi = data[i++];\n                    y0 = yi = data[i++];\n                    var width = data[i++];\n                    var height = data[i++];\n                    // Use fromLine\n                    fromLine(x0, y0, x0 + width, y0 + height, min2, max2);\n                    break;\n                case CMD.Z:\n                    xi = x0;\n                    yi = y0;\n                    break;\n            }\n\n            // Union\n            min(min$1, min$1, min2);\n            max(max$1, max$1, max2);\n        }\n\n        // No data\n        if (i === 0) {\n            min$1[0] = min$1[1] = max$1[0] = max$1[1] = 0;\n        }\n\n        return new BoundingRect(\n            min$1[0], min$1[1], max$1[0] - min$1[0], max$1[1] - min$1[1]\n        );\n    },\n\n    /**\n     * Rebuild path from current data\n     * Rebuild path will not consider javascript implemented line dash.\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    rebuildPath: function (ctx) {\n        var d = this.data;\n        var x0, y0;\n        var xi, yi;\n        var x, y;\n        var ux = this._ux;\n        var uy = this._uy;\n        var len$$1 = this._len;\n        for (var i = 0; i < len$$1;) {\n            var cmd = d[i++];\n\n            if (i === 1) {\n                // 如果第一个命令是 L, C, Q\n                // 则 previous point 同绘制命令的第一个 point\n                //\n                // 第一个命令为 Arc 的情况下会在后面特殊处理\n                xi = d[i];\n                yi = d[i + 1];\n\n                x0 = xi;\n                y0 = yi;\n            }\n            switch (cmd) {\n                case CMD.M:\n                    x0 = xi = d[i++];\n                    y0 = yi = d[i++];\n                    ctx.moveTo(xi, yi);\n                    break;\n                case CMD.L:\n                    x = d[i++];\n                    y = d[i++];\n                    // Not draw too small seg between\n                    if (mathAbs(x - xi) > ux || mathAbs(y - yi) > uy || i === len$$1 - 1) {\n                        ctx.lineTo(x, y);\n                        xi = x;\n                        yi = y;\n                    }\n                    break;\n                case CMD.C:\n                    ctx.bezierCurveTo(\n                        d[i++], d[i++], d[i++], d[i++], d[i++], d[i++]\n                    );\n                    xi = d[i - 2];\n                    yi = d[i - 1];\n                    break;\n                case CMD.Q:\n                    ctx.quadraticCurveTo(d[i++], d[i++], d[i++], d[i++]);\n                    xi = d[i - 2];\n                    yi = d[i - 1];\n                    break;\n                case CMD.A:\n                    var cx = d[i++];\n                    var cy = d[i++];\n                    var rx = d[i++];\n                    var ry = d[i++];\n                    var theta = d[i++];\n                    var dTheta = d[i++];\n                    var psi = d[i++];\n                    var fs = d[i++];\n                    var r = (rx > ry) ? rx : ry;\n                    var scaleX = (rx > ry) ? 1 : rx / ry;\n                    var scaleY = (rx > ry) ? ry / rx : 1;\n                    var isEllipse = Math.abs(rx - ry) > 1e-3;\n                    var endAngle = theta + dTheta;\n                    if (isEllipse) {\n                        ctx.translate(cx, cy);\n                        ctx.rotate(psi);\n                        ctx.scale(scaleX, scaleY);\n                        ctx.arc(0, 0, r, theta, endAngle, 1 - fs);\n                        ctx.scale(1 / scaleX, 1 / scaleY);\n                        ctx.rotate(-psi);\n                        ctx.translate(-cx, -cy);\n                    }\n                    else {\n                        ctx.arc(cx, cy, r, theta, endAngle, 1 - fs);\n                    }\n\n                    if (i === 1) {\n                        // 直接使用 arc 命令\n                        // 第一个命令起点还未定义\n                        x0 = mathCos$1(theta) * rx + cx;\n                        y0 = mathSin$1(theta) * ry + cy;\n                    }\n                    xi = mathCos$1(endAngle) * rx + cx;\n                    yi = mathSin$1(endAngle) * ry + cy;\n                    break;\n                case CMD.R:\n                    x0 = xi = d[i];\n                    y0 = yi = d[i + 1];\n                    ctx.rect(d[i++], d[i++], d[i++], d[i++]);\n                    break;\n                case CMD.Z:\n                    ctx.closePath();\n                    xi = x0;\n                    yi = y0;\n            }\n        }\n    }\n};\n\nPathProxy.CMD = CMD;\n\n/**\n * 线段包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$1(x0, y0, x1, y1, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    var _a = 0;\n    var _b = x0;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l)\n        || (y < y0 - _l && y < y1 - _l)\n        || (x > x0 + _l && x > x1 + _l)\n        || (x < x0 - _l && x < x1 - _l)\n    ) {\n        return false;\n    }\n\n    if (x0 !== x1) {\n        _a = (y0 - y1) / (x0 - x1);\n        _b = (x0 * y1 - x1 * y0) / (x0 - x1);\n    }\n    else {\n        return Math.abs(x - x0) <= _l / 2;\n    }\n    var tmp = _a * x - y + _b;\n    var _s = tmp * tmp / (_a * _a + 1);\n    return _s <= _l / 2 * _l / 2;\n}\n\n/**\n * 三次贝塞尔曲线描边包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  x2\n * @param  {number}  y2\n * @param  {number}  x3\n * @param  {number}  y3\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$2(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l)\n        || (y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l)\n        || (x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l)\n        || (x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l)\n    ) {\n        return false;\n    }\n    var d = cubicProjectPoint(\n        x0, y0, x1, y1, x2, y2, x3, y3,\n        x, y, null\n    );\n    return d <= _l / 2;\n}\n\n/**\n * 二次贝塞尔曲线描边包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  x2\n * @param  {number}  y2\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$3(x0, y0, x1, y1, x2, y2, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l && y > y2 + _l)\n        || (y < y0 - _l && y < y1 - _l && y < y2 - _l)\n        || (x > x0 + _l && x > x1 + _l && x > x2 + _l)\n        || (x < x0 - _l && x < x1 - _l && x < x2 - _l)\n    ) {\n        return false;\n    }\n    var d = quadraticProjectPoint(\n        x0, y0, x1, y1, x2, y2,\n        x, y, null\n    );\n    return d <= _l / 2;\n}\n\nvar PI2$3 = Math.PI * 2;\n\nfunction normalizeRadian(angle) {\n    angle %= PI2$3;\n    if (angle < 0) {\n        angle += PI2$3;\n    }\n    return angle;\n}\n\nvar PI2$2 = Math.PI * 2;\n\n/**\n * 圆弧描边包含判断\n * @param  {number}  cx\n * @param  {number}  cy\n * @param  {number}  r\n * @param  {number}  startAngle\n * @param  {number}  endAngle\n * @param  {boolean}  anticlockwise\n * @param  {number} lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {Boolean}\n */\nfunction containStroke$4(\n    cx, cy, r, startAngle, endAngle, anticlockwise,\n    lineWidth, x, y\n) {\n\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n\n    x -= cx;\n    y -= cy;\n    var d = Math.sqrt(x * x + y * y);\n\n    if ((d - _l > r) || (d + _l < r)) {\n        return false;\n    }\n    if (Math.abs(startAngle - endAngle) % PI2$2 < 1e-4) {\n        // Is a circle\n        return true;\n    }\n    if (anticlockwise) {\n        var tmp = startAngle;\n        startAngle = normalizeRadian(endAngle);\n        endAngle = normalizeRadian(tmp);\n    }\n    else {\n        startAngle = normalizeRadian(startAngle);\n        endAngle = normalizeRadian(endAngle);\n    }\n    if (startAngle > endAngle) {\n        endAngle += PI2$2;\n    }\n\n    var angle = Math.atan2(y, x);\n    if (angle < 0) {\n        angle += PI2$2;\n    }\n    return (angle >= startAngle && angle <= endAngle)\n        || (angle + PI2$2 >= startAngle && angle + PI2$2 <= endAngle);\n}\n\nfunction windingLine(x0, y0, x1, y1, x, y) {\n    if ((y > y0 && y > y1) || (y < y0 && y < y1)) {\n        return 0;\n    }\n    // Ignore horizontal line\n    if (y1 === y0) {\n        return 0;\n    }\n    var dir = y1 < y0 ? 1 : -1;\n    var t = (y - y0) / (y1 - y0);\n\n    // Avoid winding error when intersection point is the connect point of two line of polygon\n    if (t === 1 || t === 0) {\n        dir = y1 < y0 ? 0.5 : -0.5;\n    }\n\n    var x_ = t * (x1 - x0) + x0;\n\n    // If (x, y) on the line, considered as \"contain\".\n    return x_ === x ? Infinity : x_ > x ? dir : 0;\n}\n\nvar CMD$1 = PathProxy.CMD;\nvar PI2$1 = Math.PI * 2;\n\nvar EPSILON$2 = 1e-4;\n\nfunction isAroundEqual(a, b) {\n    return Math.abs(a - b) < EPSILON$2;\n}\n\n// 临时数组\nvar roots = [-1, -1, -1];\nvar extrema = [-1, -1];\n\nfunction swapExtrema() {\n    var tmp = extrema[0];\n    extrema[0] = extrema[1];\n    extrema[1] = tmp;\n}\n\nfunction windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {\n    // Quick reject\n    if (\n        (y > y0 && y > y1 && y > y2 && y > y3)\n        || (y < y0 && y < y1 && y < y2 && y < y3)\n    ) {\n        return 0;\n    }\n    var nRoots = cubicRootAt(y0, y1, y2, y3, y, roots);\n    if (nRoots === 0) {\n        return 0;\n    }\n    else {\n        var w = 0;\n        var nExtrema = -1;\n        var y0_;\n        var y1_;\n        for (var i = 0; i < nRoots; i++) {\n            var t = roots[i];\n\n            // Avoid winding error when intersection point is the connect point of two line of polygon\n            var unit = (t === 0 || t === 1) ? 0.5 : 1;\n\n            var x_ = cubicAt(x0, x1, x2, x3, t);\n            if (x_ < x) { // Quick reject\n                continue;\n            }\n            if (nExtrema < 0) {\n                nExtrema = cubicExtrema(y0, y1, y2, y3, extrema);\n                if (extrema[1] < extrema[0] && nExtrema > 1) {\n                    swapExtrema();\n                }\n                y0_ = cubicAt(y0, y1, y2, y3, extrema[0]);\n                if (nExtrema > 1) {\n                    y1_ = cubicAt(y0, y1, y2, y3, extrema[1]);\n                }\n            }\n            if (nExtrema === 2) {\n                // 分成三段单调函数\n                if (t < extrema[0]) {\n                    w += y0_ < y0 ? unit : -unit;\n                }\n                else if (t < extrema[1]) {\n                    w += y1_ < y0_ ? unit : -unit;\n                }\n                else {\n                    w += y3 < y1_ ? unit : -unit;\n                }\n            }\n            else {\n                // 分成两段单调函数\n                if (t < extrema[0]) {\n                    w += y0_ < y0 ? unit : -unit;\n                }\n                else {\n                    w += y3 < y0_ ? unit : -unit;\n                }\n            }\n        }\n        return w;\n    }\n}\n\nfunction windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {\n    // Quick reject\n    if (\n        (y > y0 && y > y1 && y > y2)\n        || (y < y0 && y < y1 && y < y2)\n    ) {\n        return 0;\n    }\n    var nRoots = quadraticRootAt(y0, y1, y2, y, roots);\n    if (nRoots === 0) {\n        return 0;\n    }\n    else {\n        var t = quadraticExtremum(y0, y1, y2);\n        if (t >= 0 && t <= 1) {\n            var w = 0;\n            var y_ = quadraticAt(y0, y1, y2, t);\n            for (var i = 0; i < nRoots; i++) {\n                // Remove one endpoint.\n                var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1;\n\n                var x_ = quadraticAt(x0, x1, x2, roots[i]);\n                if (x_ < x) {   // Quick reject\n                    continue;\n                }\n                if (roots[i] < t) {\n                    w += y_ < y0 ? unit : -unit;\n                }\n                else {\n                    w += y2 < y_ ? unit : -unit;\n                }\n            }\n            return w;\n        }\n        else {\n            // Remove one endpoint.\n            var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1;\n\n            var x_ = quadraticAt(x0, x1, x2, roots[0]);\n            if (x_ < x) {   // Quick reject\n                return 0;\n            }\n            return y2 < y0 ? unit : -unit;\n        }\n    }\n}\n\n// TODO\n// Arc 旋转\nfunction windingArc(\n    cx, cy, r, startAngle, endAngle, anticlockwise, x, y\n) {\n    y -= cy;\n    if (y > r || y < -r) {\n        return 0;\n    }\n    var tmp = Math.sqrt(r * r - y * y);\n    roots[0] = -tmp;\n    roots[1] = tmp;\n\n    var diff = Math.abs(startAngle - endAngle);\n    if (diff < 1e-4) {\n        return 0;\n    }\n    if (diff % PI2$1 < 1e-4) {\n        // Is a circle\n        startAngle = 0;\n        endAngle = PI2$1;\n        var dir = anticlockwise ? 1 : -1;\n        if (x >= roots[0] + cx && x <= roots[1] + cx) {\n            return dir;\n        }\n        else {\n            return 0;\n        }\n    }\n\n    if (anticlockwise) {\n        var tmp = startAngle;\n        startAngle = normalizeRadian(endAngle);\n        endAngle = normalizeRadian(tmp);\n    }\n    else {\n        startAngle = normalizeRadian(startAngle);\n        endAngle = normalizeRadian(endAngle);\n    }\n    if (startAngle > endAngle) {\n        endAngle += PI2$1;\n    }\n\n    var w = 0;\n    for (var i = 0; i < 2; i++) {\n        var x_ = roots[i];\n        if (x_ + cx > x) {\n            var angle = Math.atan2(y, x_);\n            var dir = anticlockwise ? 1 : -1;\n            if (angle < 0) {\n                angle = PI2$1 + angle;\n            }\n            if (\n                (angle >= startAngle && angle <= endAngle)\n                || (angle + PI2$1 >= startAngle && angle + PI2$1 <= endAngle)\n            ) {\n                if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {\n                    dir = -dir;\n                }\n                w += dir;\n            }\n        }\n    }\n    return w;\n}\n\nfunction containPath(data, lineWidth, isStroke, x, y) {\n    var w = 0;\n    var xi = 0;\n    var yi = 0;\n    var x0 = 0;\n    var y0 = 0;\n\n    for (var i = 0; i < data.length;) {\n        var cmd = data[i++];\n        // Begin a new subpath\n        if (cmd === CMD$1.M && i > 1) {\n            // Close previous subpath\n            if (!isStroke) {\n                w += windingLine(xi, yi, x0, y0, x, y);\n            }\n            // 如果被任何一个 subpath 包含\n            // if (w !== 0) {\n            //     return true;\n            // }\n        }\n\n        if (i === 1) {\n            // 如果第一个命令是 L, C, Q\n            // 则 previous point 同绘制命令的第一个 point\n            //\n            // 第一个命令为 Arc 的情况下会在后面特殊处理\n            xi = data[i];\n            yi = data[i + 1];\n\n            x0 = xi;\n            y0 = yi;\n        }\n\n        switch (cmd) {\n            case CMD$1.M:\n                // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点\n                // 在 closePath 的时候使用\n                x0 = data[i++];\n                y0 = data[i++];\n                xi = x0;\n                yi = y0;\n                break;\n            case CMD$1.L:\n                if (isStroke) {\n                    if (containStroke$1(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {\n                        return true;\n                    }\n                }\n                else {\n                    // NOTE 在第一个命令为 L, C, Q 的时候会计算出 NaN\n                    w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.C:\n                if (isStroke) {\n                    if (containStroke$2(xi, yi,\n                        data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingCubic(\n                        xi, yi,\n                        data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        x, y\n                    ) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.Q:\n                if (isStroke) {\n                    if (containStroke$3(xi, yi,\n                        data[i++], data[i++], data[i], data[i + 1],\n                        lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingQuadratic(\n                        xi, yi,\n                        data[i++], data[i++], data[i], data[i + 1],\n                        x, y\n                    ) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.A:\n                // TODO Arc 判断的开销比较大\n                var cx = data[i++];\n                var cy = data[i++];\n                var rx = data[i++];\n                var ry = data[i++];\n                var theta = data[i++];\n                var dTheta = data[i++];\n                // TODO Arc 旋转\n                i += 1;\n                var anticlockwise = 1 - data[i++];\n                var x1 = Math.cos(theta) * rx + cx;\n                var y1 = Math.sin(theta) * ry + cy;\n                // 不是直接使用 arc 命令\n                if (i > 1) {\n                    w += windingLine(xi, yi, x1, y1, x, y);\n                }\n                else {\n                    // 第一个命令起点还未定义\n                    x0 = x1;\n                    y0 = y1;\n                }\n                // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放\n                var _x = (x - cx) * ry / rx + cx;\n                if (isStroke) {\n                    if (containStroke$4(\n                        cx, cy, ry, theta, theta + dTheta, anticlockwise,\n                        lineWidth, _x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingArc(\n                        cx, cy, ry, theta, theta + dTheta, anticlockwise,\n                        _x, y\n                    );\n                }\n                xi = Math.cos(theta + dTheta) * rx + cx;\n                yi = Math.sin(theta + dTheta) * ry + cy;\n                break;\n            case CMD$1.R:\n                x0 = xi = data[i++];\n                y0 = yi = data[i++];\n                var width = data[i++];\n                var height = data[i++];\n                var x1 = x0 + width;\n                var y1 = y0 + height;\n                if (isStroke) {\n                    if (containStroke$1(x0, y0, x1, y0, lineWidth, x, y)\n                        || containStroke$1(x1, y0, x1, y1, lineWidth, x, y)\n                        || containStroke$1(x1, y1, x0, y1, lineWidth, x, y)\n                        || containStroke$1(x0, y1, x0, y0, lineWidth, x, y)\n                    ) {\n                        return true;\n                    }\n                }\n                else {\n                    // FIXME Clockwise ?\n                    w += windingLine(x1, y0, x1, y1, x, y);\n                    w += windingLine(x0, y1, x0, y0, x, y);\n                }\n                break;\n            case CMD$1.Z:\n                if (isStroke) {\n                    if (containStroke$1(\n                        xi, yi, x0, y0, lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    // Close a subpath\n                    w += windingLine(xi, yi, x0, y0, x, y);\n                    // 如果被任何一个 subpath 包含\n                    // FIXME subpaths may overlap\n                    // if (w !== 0) {\n                    //     return true;\n                    // }\n                }\n                xi = x0;\n                yi = y0;\n                break;\n        }\n    }\n    if (!isStroke && !isAroundEqual(yi, y0)) {\n        w += windingLine(xi, yi, x0, y0, x, y) || 0;\n    }\n    return w !== 0;\n}\n\nfunction contain(pathData, x, y) {\n    return containPath(pathData, 0, false, x, y);\n}\n\nfunction containStroke(pathData, lineWidth, x, y) {\n    return containPath(pathData, lineWidth, true, x, y);\n}\n\nvar getCanvasPattern = Pattern.prototype.getCanvasPattern;\n\nvar abs = Math.abs;\n\nvar pathProxyForDraw = new PathProxy(true);\n/**\n * @alias module:zrender/graphic/Path\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nfunction Path(opts) {\n    Displayable.call(this, opts);\n\n    /**\n     * @type {module:zrender/core/PathProxy}\n     * @readOnly\n     */\n    this.path = null;\n}\n\nPath.prototype = {\n\n    constructor: Path,\n\n    type: 'path',\n\n    __dirtyPath: true,\n\n    strokeContainThreshold: 5,\n\n    /**\n     * See `module:zrender/src/graphic/helper/subPixelOptimize`.\n     * @type {boolean}\n     */\n    subPixelOptimize: false,\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n        var path = this.path || pathProxyForDraw;\n        var hasStroke = style.hasStroke();\n        var hasFill = style.hasFill();\n        var fill = style.fill;\n        var stroke = style.stroke;\n        var hasFillGradient = hasFill && !!(fill.colorStops);\n        var hasStrokeGradient = hasStroke && !!(stroke.colorStops);\n        var hasFillPattern = hasFill && !!(fill.image);\n        var hasStrokePattern = hasStroke && !!(stroke.image);\n\n        style.bind(ctx, this, prevEl);\n        this.setTransform(ctx);\n\n        if (this.__dirty) {\n            var rect;\n            // Update gradient because bounding rect may changed\n            if (hasFillGradient) {\n                rect = rect || this.getBoundingRect();\n                this._fillGradient = style.getGradient(ctx, fill, rect);\n            }\n            if (hasStrokeGradient) {\n                rect = rect || this.getBoundingRect();\n                this._strokeGradient = style.getGradient(ctx, stroke, rect);\n            }\n        }\n        // Use the gradient or pattern\n        if (hasFillGradient) {\n            // PENDING If may have affect the state\n            ctx.fillStyle = this._fillGradient;\n        }\n        else if (hasFillPattern) {\n            ctx.fillStyle = getCanvasPattern.call(fill, ctx);\n        }\n        if (hasStrokeGradient) {\n            ctx.strokeStyle = this._strokeGradient;\n        }\n        else if (hasStrokePattern) {\n            ctx.strokeStyle = getCanvasPattern.call(stroke, ctx);\n        }\n\n        var lineDash = style.lineDash;\n        var lineDashOffset = style.lineDashOffset;\n\n        var ctxLineDash = !!ctx.setLineDash;\n\n        // Update path sx, sy\n        var scale = this.getGlobalScale();\n        path.setScale(scale[0], scale[1]);\n\n        // Proxy context\n        // Rebuild path in following 2 cases\n        // 1. Path is dirty\n        // 2. Path needs javascript implemented lineDash stroking.\n        //    In this case, lineDash information will not be saved in PathProxy\n        if (this.__dirtyPath\n            || (lineDash && !ctxLineDash && hasStroke)\n        ) {\n            path.beginPath(ctx);\n\n            // Setting line dash before build path\n            if (lineDash && !ctxLineDash) {\n                path.setLineDash(lineDash);\n                path.setLineDashOffset(lineDashOffset);\n            }\n\n            this.buildPath(path, this.shape, false);\n\n            // Clear path dirty flag\n            if (this.path) {\n                this.__dirtyPath = false;\n            }\n        }\n        else {\n            // Replay path building\n            ctx.beginPath();\n            this.path.rebuildPath(ctx);\n        }\n\n        if (hasFill) {\n            if (style.fillOpacity != null) {\n                var originalGlobalAlpha = ctx.globalAlpha;\n                ctx.globalAlpha = style.fillOpacity * style.opacity;\n                path.fill(ctx);\n                ctx.globalAlpha = originalGlobalAlpha;\n            }\n            else {\n                path.fill(ctx);\n            }\n        }\n\n        if (lineDash && ctxLineDash) {\n            ctx.setLineDash(lineDash);\n            ctx.lineDashOffset = lineDashOffset;\n        }\n\n        if (hasStroke) {\n            if (style.strokeOpacity != null) {\n                var originalGlobalAlpha = ctx.globalAlpha;\n                ctx.globalAlpha = style.strokeOpacity * style.opacity;\n                path.stroke(ctx);\n                ctx.globalAlpha = originalGlobalAlpha;\n            }\n            else {\n                path.stroke(ctx);\n            }\n        }\n\n        if (lineDash && ctxLineDash) {\n            // PENDING\n            // Remove lineDash\n            ctx.setLineDash([]);\n        }\n\n        // Draw rect text\n        if (style.text != null) {\n            // Only restore transform when needs draw text.\n            this.restoreTransform(ctx);\n            this.drawRectText(ctx, this.getBoundingRect());\n        }\n    },\n\n    // When bundling path, some shape may decide if use moveTo to begin a new subpath or closePath\n    // Like in circle\n    buildPath: function (ctx, shapeCfg, inBundle) {},\n\n    createPathProxy: function () {\n        this.path = new PathProxy();\n    },\n\n    getBoundingRect: function () {\n        var rect = this._rect;\n        var style = this.style;\n        var needsUpdateRect = !rect;\n        if (needsUpdateRect) {\n            var path = this.path;\n            if (!path) {\n                // Create path on demand.\n                path = this.path = new PathProxy();\n            }\n            if (this.__dirtyPath) {\n                path.beginPath();\n                this.buildPath(path, this.shape, false);\n            }\n            rect = path.getBoundingRect();\n        }\n        this._rect = rect;\n\n        if (style.hasStroke()) {\n            // Needs update rect with stroke lineWidth when\n            // 1. Element changes scale or lineWidth\n            // 2. Shape is changed\n            var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone());\n            if (this.__dirty || needsUpdateRect) {\n                rectWithStroke.copy(rect);\n                // FIXME Must after updateTransform\n                var w = style.lineWidth;\n                // PENDING, Min line width is needed when line is horizontal or vertical\n                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;\n\n                // Only add extra hover lineWidth when there are no fill\n                if (!style.hasFill()) {\n                    w = Math.max(w, this.strokeContainThreshold || 4);\n                }\n                // Consider line width\n                // Line scale can't be 0;\n                if (lineScale > 1e-10) {\n                    rectWithStroke.width += w / lineScale;\n                    rectWithStroke.height += w / lineScale;\n                    rectWithStroke.x -= w / lineScale / 2;\n                    rectWithStroke.y -= w / lineScale / 2;\n                }\n            }\n\n            // Return rect with stroke\n            return rectWithStroke;\n        }\n\n        return rect;\n    },\n\n    contain: function (x, y) {\n        var localPos = this.transformCoordToLocal(x, y);\n        var rect = this.getBoundingRect();\n        var style = this.style;\n        x = localPos[0];\n        y = localPos[1];\n\n        if (rect.contain(x, y)) {\n            var pathData = this.path.data;\n            if (style.hasStroke()) {\n                var lineWidth = style.lineWidth;\n                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;\n                // Line scale can't be 0;\n                if (lineScale > 1e-10) {\n                    // Only add extra hover lineWidth when there are no fill\n                    if (!style.hasFill()) {\n                        lineWidth = Math.max(lineWidth, this.strokeContainThreshold);\n                    }\n                    if (containStroke(\n                        pathData, lineWidth / lineScale, x, y\n                    )) {\n                        return true;\n                    }\n                }\n            }\n            if (style.hasFill()) {\n                return contain(pathData, x, y);\n            }\n        }\n        return false;\n    },\n\n    /**\n     * @param  {boolean} dirtyPath\n     */\n    dirty: function (dirtyPath) {\n        if (dirtyPath == null) {\n            dirtyPath = true;\n        }\n        // Only mark dirty, not mark clean\n        if (dirtyPath) {\n            this.__dirtyPath = dirtyPath;\n            this._rect = null;\n        }\n\n        this.__dirty = this.__dirtyText = true;\n\n        this.__zr && this.__zr.refresh();\n\n        // Used as a clipping path\n        if (this.__clipTarget) {\n            this.__clipTarget.dirty();\n        }\n    },\n\n    /**\n     * Alias for animate('shape')\n     * @param {boolean} loop\n     */\n    animateShape: function (loop) {\n        return this.animate('shape', loop);\n    },\n\n    // Overwrite attrKV\n    attrKV: function (key, value) {\n        // FIXME\n        if (key === 'shape') {\n            this.setShape(value);\n            this.__dirtyPath = true;\n            this._rect = null;\n        }\n        else {\n            Displayable.prototype.attrKV.call(this, key, value);\n        }\n    },\n\n    /**\n     * @param {Object|string} key\n     * @param {*} value\n     */\n    setShape: function (key, value) {\n        var shape = this.shape;\n        // Path from string may not have shape\n        if (shape) {\n            if (isObject$1(key)) {\n                for (var name in key) {\n                    if (key.hasOwnProperty(name)) {\n                        shape[name] = key[name];\n                    }\n                }\n            }\n            else {\n                shape[key] = value;\n            }\n            this.dirty(true);\n        }\n        return this;\n    },\n\n    getLineScale: function () {\n        var m = this.transform;\n        // Get the line scale.\n        // Determinant of `m` means how much the area is enlarged by the\n        // transformation. So its square root can be used as a scale factor\n        // for width.\n        return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10\n            ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1]))\n            : 1;\n    }\n};\n\n/**\n * 扩展一个 Path element, 比如星形，圆等。\n * Extend a path element\n * @param {Object} props\n * @param {string} props.type Path type\n * @param {Function} props.init Initialize\n * @param {Function} props.buildPath Overwrite buildPath method\n * @param {Object} [props.style] Extended default style config\n * @param {Object} [props.shape] Extended default shape config\n */\nPath.extend = function (defaults$$1) {\n    var Sub = function (opts) {\n        Path.call(this, opts);\n\n        if (defaults$$1.style) {\n            // Extend default style\n            this.style.extendFrom(defaults$$1.style, false);\n        }\n\n        // Extend default shape\n        var defaultShape = defaults$$1.shape;\n        if (defaultShape) {\n            this.shape = this.shape || {};\n            var thisShape = this.shape;\n            for (var name in defaultShape) {\n                if (\n                    !thisShape.hasOwnProperty(name)\n                    && defaultShape.hasOwnProperty(name)\n                ) {\n                    thisShape[name] = defaultShape[name];\n                }\n            }\n        }\n\n        defaults$$1.init && defaults$$1.init.call(this, opts);\n    };\n\n    inherits(Sub, Path);\n\n    // FIXME 不能 extend position, rotation 等引用对象\n    for (var name in defaults$$1) {\n        // Extending prototype values and methods\n        if (name !== 'style' && name !== 'shape') {\n            Sub.prototype[name] = defaults$$1[name];\n        }\n    }\n\n    return Sub;\n};\n\ninherits(Path, Displayable);\n\nvar CMD$2 = PathProxy.CMD;\n\nvar points = [[], [], []];\nvar mathSqrt$3 = Math.sqrt;\nvar mathAtan2 = Math.atan2;\n\nvar transformPath = function (path, m) {\n    var data = path.data;\n    var cmd;\n    var nPoint;\n    var i;\n    var j;\n    var k;\n    var p;\n\n    var M = CMD$2.M;\n    var C = CMD$2.C;\n    var L = CMD$2.L;\n    var R = CMD$2.R;\n    var A = CMD$2.A;\n    var Q = CMD$2.Q;\n\n    for (i = 0, j = 0; i < data.length;) {\n        cmd = data[i++];\n        j = i;\n        nPoint = 0;\n\n        switch (cmd) {\n            case M:\n                nPoint = 1;\n                break;\n            case L:\n                nPoint = 1;\n                break;\n            case C:\n                nPoint = 3;\n                break;\n            case Q:\n                nPoint = 2;\n                break;\n            case A:\n                var x = m[4];\n                var y = m[5];\n                var sx = mathSqrt$3(m[0] * m[0] + m[1] * m[1]);\n                var sy = mathSqrt$3(m[2] * m[2] + m[3] * m[3]);\n                var angle = mathAtan2(-m[1] / sy, m[0] / sx);\n                // cx\n                data[i] *= sx;\n                data[i++] += x;\n                // cy\n                data[i] *= sy;\n                data[i++] += y;\n                // Scale rx and ry\n                // FIXME Assume psi is 0 here\n                data[i++] *= sx;\n                data[i++] *= sy;\n\n                // Start angle\n                data[i++] += angle;\n                // end angle\n                data[i++] += angle;\n                // FIXME psi\n                i += 2;\n                j = i;\n                break;\n            case R:\n                // x0, y0\n                p[0] = data[i++];\n                p[1] = data[i++];\n                applyTransform(p, p, m);\n                data[j++] = p[0];\n                data[j++] = p[1];\n                // x1, y1\n                p[0] += data[i++];\n                p[1] += data[i++];\n                applyTransform(p, p, m);\n                data[j++] = p[0];\n                data[j++] = p[1];\n        }\n\n        for (k = 0; k < nPoint; k++) {\n            var p = points[k];\n            p[0] = data[i++];\n            p[1] = data[i++];\n\n            applyTransform(p, p, m);\n            // Write back\n            data[j++] = p[0];\n            data[j++] = p[1];\n        }\n    }\n};\n\n// command chars\n// var cc = [\n//     'm', 'M', 'l', 'L', 'v', 'V', 'h', 'H', 'z', 'Z',\n//     'c', 'C', 'q', 'Q', 't', 'T', 's', 'S', 'a', 'A'\n// ];\n\nvar mathSqrt = Math.sqrt;\nvar mathSin = Math.sin;\nvar mathCos = Math.cos;\nvar PI = Math.PI;\n\nvar vMag = function (v) {\n    return Math.sqrt(v[0] * v[0] + v[1] * v[1]);\n};\nvar vRatio = function (u, v) {\n    return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));\n};\nvar vAngle = function (u, v) {\n    return (u[0] * v[1] < u[1] * v[0] ? -1 : 1)\n            * Math.acos(vRatio(u, v));\n};\n\nfunction processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) {\n    var psi = psiDeg * (PI / 180.0);\n    var xp = mathCos(psi) * (x1 - x2) / 2.0\n                + mathSin(psi) * (y1 - y2) / 2.0;\n    var yp = -1 * mathSin(psi) * (x1 - x2) / 2.0\n                + mathCos(psi) * (y1 - y2) / 2.0;\n\n    var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);\n\n    if (lambda > 1) {\n        rx *= mathSqrt(lambda);\n        ry *= mathSqrt(lambda);\n    }\n\n    var f = (fa === fs ? -1 : 1)\n        * mathSqrt((((rx * rx) * (ry * ry))\n                - ((rx * rx) * (yp * yp))\n                - ((ry * ry) * (xp * xp))) / ((rx * rx) * (yp * yp)\n                + (ry * ry) * (xp * xp))\n            ) || 0;\n\n    var cxp = f * rx * yp / ry;\n    var cyp = f * -ry * xp / rx;\n\n    var cx = (x1 + x2) / 2.0\n                + mathCos(psi) * cxp\n                - mathSin(psi) * cyp;\n    var cy = (y1 + y2) / 2.0\n            + mathSin(psi) * cxp\n            + mathCos(psi) * cyp;\n\n    var theta = vAngle([ 1, 0 ], [ (xp - cxp) / rx, (yp - cyp) / ry ]);\n    var u = [ (xp - cxp) / rx, (yp - cyp) / ry ];\n    var v = [ (-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry ];\n    var dTheta = vAngle(u, v);\n\n    if (vRatio(u, v) <= -1) {\n        dTheta = PI;\n    }\n    if (vRatio(u, v) >= 1) {\n        dTheta = 0;\n    }\n    if (fs === 0 && dTheta > 0) {\n        dTheta = dTheta - 2 * PI;\n    }\n    if (fs === 1 && dTheta < 0) {\n        dTheta = dTheta + 2 * PI;\n    }\n\n    path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs);\n}\n\n\nvar commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig;\n// Consider case:\n// (1) delimiter can be comma or space, where continuous commas\n// or spaces should be seen as one comma.\n// (2) value can be like:\n// '2e-4', 'l.5.9' (ignore 0), 'M-10-10', 'l-2.43e-1,34.9983',\n// 'l-.5E1,54', '121-23-44-11' (no delimiter)\nvar numberReg = /-?([0-9]*\\.)?[0-9]+([eE]-?[0-9]+)?/g;\n// var valueSplitReg = /[\\s,]+/;\n\nfunction createPathProxyFromString(data) {\n    if (!data) {\n        return new PathProxy();\n    }\n\n    // var data = data.replace(/-/g, ' -')\n    //     .replace(/  /g, ' ')\n    //     .replace(/ /g, ',')\n    //     .replace(/,,/g, ',');\n\n    // var n;\n    // create pipes so that we can split the data\n    // for (n = 0; n < cc.length; n++) {\n    //     cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]);\n    // }\n\n    // data = data.replace(/-/g, ',-');\n\n    // create array\n    // var arr = cs.split('|');\n    // init context point\n    var cpx = 0;\n    var cpy = 0;\n    var subpathX = cpx;\n    var subpathY = cpy;\n    var prevCmd;\n\n    var path = new PathProxy();\n    var CMD = PathProxy.CMD;\n\n    // commandReg.lastIndex = 0;\n    // var cmdResult;\n    // while ((cmdResult = commandReg.exec(data)) != null) {\n    //     var cmdStr = cmdResult[1];\n    //     var cmdContent = cmdResult[2];\n\n    var cmdList = data.match(commandReg);\n    for (var l = 0; l < cmdList.length; l++) {\n        var cmdText = cmdList[l];\n        var cmdStr = cmdText.charAt(0);\n\n        var cmd;\n\n        // String#split is faster a little bit than String#replace or RegExp#exec.\n        // var p = cmdContent.split(valueSplitReg);\n        // var pLen = 0;\n        // for (var i = 0; i < p.length; i++) {\n        //     // '' and other invalid str => NaN\n        //     var val = parseFloat(p[i]);\n        //     !isNaN(val) && (p[pLen++] = val);\n        // }\n\n        var p = cmdText.match(numberReg) || [];\n        var pLen = p.length;\n        for (var i = 0; i < pLen; i++) {\n            p[i] = parseFloat(p[i]);\n        }\n\n        var off = 0;\n        while (off < pLen) {\n            var ctlPtx;\n            var ctlPty;\n\n            var rx;\n            var ry;\n            var psi;\n            var fa;\n            var fs;\n\n            var x1 = cpx;\n            var y1 = cpy;\n\n            // convert l, H, h, V, and v to L\n            switch (cmdStr) {\n                case 'l':\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'L':\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'm':\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.M;\n                    path.addData(cmd, cpx, cpy);\n                    subpathX = cpx;\n                    subpathY = cpy;\n                    cmdStr = 'l';\n                    break;\n                case 'M':\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.M;\n                    path.addData(cmd, cpx, cpy);\n                    subpathX = cpx;\n                    subpathY = cpy;\n                    cmdStr = 'L';\n                    break;\n                case 'h':\n                    cpx += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'H':\n                    cpx = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'v':\n                    cpy += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'V':\n                    cpy = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'C':\n                    cmd = CMD.C;\n                    path.addData(\n                        cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]\n                    );\n                    cpx = p[off - 2];\n                    cpy = p[off - 1];\n                    break;\n                case 'c':\n                    cmd = CMD.C;\n                    path.addData(\n                        cmd,\n                        p[off++] + cpx, p[off++] + cpy,\n                        p[off++] + cpx, p[off++] + cpy,\n                        p[off++] + cpx, p[off++] + cpy\n                    );\n                    cpx += p[off - 2];\n                    cpy += p[off - 1];\n                    break;\n                case 'S':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.C) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cmd = CMD.C;\n                    x1 = p[off++];\n                    y1 = p[off++];\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);\n                    break;\n                case 's':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.C) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cmd = CMD.C;\n                    x1 = cpx + p[off++];\n                    y1 = cpy + p[off++];\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);\n                    break;\n                case 'Q':\n                    x1 = p[off++];\n                    y1 = p[off++];\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, x1, y1, cpx, cpy);\n                    break;\n                case 'q':\n                    x1 = p[off++] + cpx;\n                    y1 = p[off++] + cpy;\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, x1, y1, cpx, cpy);\n                    break;\n                case 'T':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.Q) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);\n                    break;\n                case 't':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.Q) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);\n                    break;\n                case 'A':\n                    rx = p[off++];\n                    ry = p[off++];\n                    psi = p[off++];\n                    fa = p[off++];\n                    fs = p[off++];\n\n                    x1 = cpx, y1 = cpy;\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.A;\n                    processArc(\n                        x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path\n                    );\n                    break;\n                case 'a':\n                    rx = p[off++];\n                    ry = p[off++];\n                    psi = p[off++];\n                    fa = p[off++];\n                    fs = p[off++];\n\n                    x1 = cpx, y1 = cpy;\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.A;\n                    processArc(\n                        x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path\n                    );\n                    break;\n            }\n        }\n\n        if (cmdStr === 'z' || cmdStr === 'Z') {\n            cmd = CMD.Z;\n            path.addData(cmd);\n            // z may be in the middle of the path.\n            cpx = subpathX;\n            cpy = subpathY;\n        }\n\n        prevCmd = cmd;\n    }\n\n    path.toStatic();\n\n    return path;\n}\n\n// TODO Optimize double memory cost problem\nfunction createPathOptions(str, opts) {\n    var pathProxy = createPathProxyFromString(str);\n    opts = opts || {};\n    opts.buildPath = function (path) {\n        if (path.setData) {\n            path.setData(pathProxy.data);\n            // Svg and vml renderer don't have context\n            var ctx = path.getContext();\n            if (ctx) {\n                path.rebuildPath(ctx);\n            }\n        }\n        else {\n            var ctx = path;\n            pathProxy.rebuildPath(ctx);\n        }\n    };\n\n    opts.applyTransform = function (m) {\n        transformPath(pathProxy, m);\n        this.dirty(true);\n    };\n\n    return opts;\n}\n\n/**\n * Create a Path object from path string data\n * http://www.w3.org/TR/SVG/paths.html#PathData\n * @param  {Object} opts Other options\n */\nfunction createFromString(str, opts) {\n    return new Path(createPathOptions(str, opts));\n}\n\n/**\n * Create a Path class from path string data\n * @param  {string} str\n * @param  {Object} opts Other options\n */\nfunction extendFromString(str, opts) {\n    return Path.extend(createPathOptions(str, opts));\n}\n\n/**\n * Merge multiple paths\n */\n// TODO Apply transform\n// TODO stroke dash\n// TODO Optimize double memory cost problem\nfunction mergePath$1(pathEls, opts) {\n    var pathList = [];\n    var len = pathEls.length;\n    for (var i = 0; i < len; i++) {\n        var pathEl = pathEls[i];\n        if (!pathEl.path) {\n            pathEl.createPathProxy();\n        }\n        if (pathEl.__dirtyPath) {\n            pathEl.buildPath(pathEl.path, pathEl.shape, true);\n        }\n        pathList.push(pathEl.path);\n    }\n\n    var pathBundle = new Path(opts);\n    // Need path proxy.\n    pathBundle.createPathProxy();\n    pathBundle.buildPath = function (path) {\n        path.appendPath(pathList);\n        // Svg and vml renderer don't have context\n        var ctx = path.getContext();\n        if (ctx) {\n            path.rebuildPath(ctx);\n        }\n    };\n\n    return pathBundle;\n}\n\n/**\n * @alias zrender/graphic/Text\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nvar Text = function (opts) { // jshint ignore:line\n    Displayable.call(this, opts);\n};\n\nText.prototype = {\n\n    constructor: Text,\n\n    type: 'text',\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        // Use props with prefix 'text'.\n        style.fill = style.stroke = style.shadowBlur = style.shadowColor =\n            style.shadowOffsetX = style.shadowOffsetY = null;\n\n        var text = style.text;\n        // Convert to string\n        text != null && (text += '');\n\n        // Do not apply style.bind in Text node. Because the real bind job\n        // is in textHelper.renderText, and performance of text render should\n        // be considered.\n        // style.bind(ctx, this, prevEl);\n\n        if (!needDrawText(text, style)) {\n            // The current el.style is not applied\n            // and should not be used as cache.\n            ctx.__attrCachedBy = ContextCachedBy.NONE;\n            return;\n        }\n\n        this.setTransform(ctx);\n\n        renderText(this, ctx, text, style, null, prevEl);\n\n        this.restoreTransform(ctx);\n    },\n\n    getBoundingRect: function () {\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        if (!this._rect) {\n            var text = style.text;\n            text != null ? (text += '') : (text = '');\n\n            var rect = getBoundingRect(\n                style.text + '',\n                style.font,\n                style.textAlign,\n                style.textVerticalAlign,\n                style.textPadding,\n                style.textLineHeight,\n                style.rich\n            );\n\n            rect.x += style.x || 0;\n            rect.y += style.y || 0;\n\n            if (getStroke(style.textStroke, style.textStrokeWidth)) {\n                var w = style.textStrokeWidth;\n                rect.x -= w / 2;\n                rect.y -= w / 2;\n                rect.width += w;\n                rect.height += w;\n            }\n\n            this._rect = rect;\n        }\n\n        return this._rect;\n    }\n};\n\ninherits(Text, Displayable);\n\n/**\n * 圆形\n * @module zrender/shape/Circle\n */\n\nvar Circle = Path.extend({\n\n    type: 'circle',\n\n    shape: {\n        cx: 0,\n        cy: 0,\n        r: 0\n    },\n\n\n    buildPath: function (ctx, shape, inBundle) {\n        // Better stroking in ShapeBundle\n        // Always do it may have performence issue ( fill may be 2x more cost)\n        if (inBundle) {\n            ctx.moveTo(shape.cx + shape.r, shape.cy);\n        }\n        // else {\n        //     if (ctx.allocate && !ctx.data.length) {\n        //         ctx.allocate(ctx.CMD_MEM_SIZE.A);\n        //     }\n        // }\n        // Better stroking in ShapeBundle\n        // ctx.moveTo(shape.cx + shape.r, shape.cy);\n        ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true);\n    }\n});\n\n// Fix weird bug in some version of IE11 (like 11.0.9600.178**),\n// where exception \"unexpected call to method or property access\"\n// might be thrown when calling ctx.fill or ctx.stroke after a path\n// whose area size is zero is drawn and ctx.clip() is called and\n// shadowBlur is set. See #4572, #3112, #5777.\n// (e.g.,\n//  ctx.moveTo(10, 10);\n//  ctx.lineTo(20, 10);\n//  ctx.closePath();\n//  ctx.clip();\n//  ctx.shadowBlur = 10;\n//  ...\n//  ctx.fill();\n// )\n\nvar shadowTemp = [\n    ['shadowBlur', 0],\n    ['shadowColor', '#000'],\n    ['shadowOffsetX', 0],\n    ['shadowOffsetY', 0]\n];\n\nvar fixClipWithShadow = function (orignalBrush) {\n\n    // version string can be: '11.0'\n    return (env$1.browser.ie && env$1.browser.version >= 11)\n\n        ? function () {\n            var clipPaths = this.__clipPaths;\n            var style = this.style;\n            var modified;\n\n            if (clipPaths) {\n                for (var i = 0; i < clipPaths.length; i++) {\n                    var clipPath = clipPaths[i];\n                    var shape = clipPath && clipPath.shape;\n                    var type = clipPath && clipPath.type;\n\n                    if (shape && (\n                        (type === 'sector' && shape.startAngle === shape.endAngle)\n                        || (type === 'rect' && (!shape.width || !shape.height))\n                    )) {\n                        for (var j = 0; j < shadowTemp.length; j++) {\n                            // It is save to put shadowTemp static, because shadowTemp\n                            // will be all modified each item brush called.\n                            shadowTemp[j][2] = style[shadowTemp[j][0]];\n                            style[shadowTemp[j][0]] = shadowTemp[j][1];\n                        }\n                        modified = true;\n                        break;\n                    }\n                }\n            }\n\n            orignalBrush.apply(this, arguments);\n\n            if (modified) {\n                for (var j = 0; j < shadowTemp.length; j++) {\n                    style[shadowTemp[j][0]] = shadowTemp[j][2];\n                }\n            }\n        }\n\n        : orignalBrush;\n};\n\n/**\n * 扇形\n * @module zrender/graphic/shape/Sector\n */\n\nvar Sector = Path.extend({\n\n    type: 'sector',\n\n    shape: {\n\n        cx: 0,\n\n        cy: 0,\n\n        r0: 0,\n\n        r: 0,\n\n        startAngle: 0,\n\n        endAngle: Math.PI * 2,\n\n        clockwise: true\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n\n        var x = shape.cx;\n        var y = shape.cy;\n        var r0 = Math.max(shape.r0 || 0, 0);\n        var r = Math.max(shape.r, 0);\n        var startAngle = shape.startAngle;\n        var endAngle = shape.endAngle;\n        var clockwise = shape.clockwise;\n\n        var unitX = Math.cos(startAngle);\n        var unitY = Math.sin(startAngle);\n\n        ctx.moveTo(unitX * r0 + x, unitY * r0 + y);\n\n        ctx.lineTo(unitX * r + x, unitY * r + y);\n\n        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);\n\n        ctx.lineTo(\n            Math.cos(endAngle) * r0 + x,\n            Math.sin(endAngle) * r0 + y\n        );\n\n        if (r0 !== 0) {\n            ctx.arc(x, y, r0, endAngle, startAngle, clockwise);\n        }\n\n        ctx.closePath();\n    }\n});\n\n/**\n * 圆环\n * @module zrender/graphic/shape/Ring\n */\n\nvar Ring = Path.extend({\n\n    type: 'ring',\n\n    shape: {\n        cx: 0,\n        cy: 0,\n        r: 0,\n        r0: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var x = shape.cx;\n        var y = shape.cy;\n        var PI2 = Math.PI * 2;\n        ctx.moveTo(x + shape.r, y);\n        ctx.arc(x, y, shape.r, 0, PI2, false);\n        ctx.moveTo(x + shape.r0, y);\n        ctx.arc(x, y, shape.r0, 0, PI2, true);\n    }\n});\n\n/**\n * Catmull-Rom spline 插值折线\n * @module zrender/shape/util/smoothSpline\n * @author pissang (https://www.github.com/pissang)\n *         Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         errorrik (errorrik@gmail.com)\n */\n\n/**\n * @inner\n */\nfunction interpolate(p0, p1, p2, p3, t, t2, t3) {\n    var v0 = (p2 - p0) * 0.5;\n    var v1 = (p3 - p1) * 0.5;\n    return (2 * (p1 - p2) + v0 + v1) * t3\n            + (-3 * (p1 - p2) - 2 * v0 - v1) * t2\n            + v0 * t + p1;\n}\n\n/**\n * @alias module:zrender/shape/util/smoothSpline\n * @param {Array} points 线段顶点数组\n * @param {boolean} isLoop\n * @return {Array}\n */\nvar smoothSpline = function (points, isLoop) {\n    var len$$1 = points.length;\n    var ret = [];\n\n    var distance$$1 = 0;\n    for (var i = 1; i < len$$1; i++) {\n        distance$$1 += distance(points[i - 1], points[i]);\n    }\n\n    var segs = distance$$1 / 2;\n    segs = segs < len$$1 ? len$$1 : segs;\n    for (var i = 0; i < segs; i++) {\n        var pos = i / (segs - 1) * (isLoop ? len$$1 : len$$1 - 1);\n        var idx = Math.floor(pos);\n\n        var w = pos - idx;\n\n        var p0;\n        var p1 = points[idx % len$$1];\n        var p2;\n        var p3;\n        if (!isLoop) {\n            p0 = points[idx === 0 ? idx : idx - 1];\n            p2 = points[idx > len$$1 - 2 ? len$$1 - 1 : idx + 1];\n            p3 = points[idx > len$$1 - 3 ? len$$1 - 1 : idx + 2];\n        }\n        else {\n            p0 = points[(idx - 1 + len$$1) % len$$1];\n            p2 = points[(idx + 1) % len$$1];\n            p3 = points[(idx + 2) % len$$1];\n        }\n\n        var w2 = w * w;\n        var w3 = w * w2;\n\n        ret.push([\n            interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3),\n            interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3)\n        ]);\n    }\n    return ret;\n};\n\n/**\n * 贝塞尔平滑曲线\n * @module zrender/shape/util/smoothBezier\n * @author pissang (https://www.github.com/pissang)\n *         Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         errorrik (errorrik@gmail.com)\n */\n\n/**\n * 贝塞尔平滑曲线\n * @alias module:zrender/shape/util/smoothBezier\n * @param {Array} points 线段顶点数组\n * @param {number} smooth 平滑等级, 0-1\n * @param {boolean} isLoop\n * @param {Array} constraint 将计算出来的控制点约束在一个包围盒内\n *                           比如 [[0, 0], [100, 100]], 这个包围盒会与\n *                           整个折线的包围盒做一个并集用来约束控制点。\n * @param {Array} 计算出来的控制点数组\n */\nvar smoothBezier = function (points, smooth, isLoop, constraint) {\n    var cps = [];\n\n    var v = [];\n    var v1 = [];\n    var v2 = [];\n    var prevPoint;\n    var nextPoint;\n\n    var min$$1;\n    var max$$1;\n    if (constraint) {\n        min$$1 = [Infinity, Infinity];\n        max$$1 = [-Infinity, -Infinity];\n        for (var i = 0, len$$1 = points.length; i < len$$1; i++) {\n            min(min$$1, min$$1, points[i]);\n            max(max$$1, max$$1, points[i]);\n        }\n        // 与指定的包围盒做并集\n        min(min$$1, min$$1, constraint[0]);\n        max(max$$1, max$$1, constraint[1]);\n    }\n\n    for (var i = 0, len$$1 = points.length; i < len$$1; i++) {\n        var point = points[i];\n\n        if (isLoop) {\n            prevPoint = points[i ? i - 1 : len$$1 - 1];\n            nextPoint = points[(i + 1) % len$$1];\n        }\n        else {\n            if (i === 0 || i === len$$1 - 1) {\n                cps.push(clone$1(points[i]));\n                continue;\n            }\n            else {\n                prevPoint = points[i - 1];\n                nextPoint = points[i + 1];\n            }\n        }\n\n        sub(v, nextPoint, prevPoint);\n\n        // use degree to scale the handle length\n        scale(v, v, smooth);\n\n        var d0 = distance(point, prevPoint);\n        var d1 = distance(point, nextPoint);\n        var sum = d0 + d1;\n        if (sum !== 0) {\n            d0 /= sum;\n            d1 /= sum;\n        }\n\n        scale(v1, v, -d0);\n        scale(v2, v, d1);\n        var cp0 = add([], point, v1);\n        var cp1 = add([], point, v2);\n        if (constraint) {\n            max(cp0, cp0, min$$1);\n            min(cp0, cp0, max$$1);\n            max(cp1, cp1, min$$1);\n            min(cp1, cp1, max$$1);\n        }\n        cps.push(cp0);\n        cps.push(cp1);\n    }\n\n    if (isLoop) {\n        cps.push(cps.shift());\n    }\n\n    return cps;\n};\n\nfunction buildPath$1(ctx, shape, closePath) {\n    var points = shape.points;\n    var smooth = shape.smooth;\n    if (points && points.length >= 2) {\n        if (smooth && smooth !== 'spline') {\n            var controlPoints = smoothBezier(\n                points, smooth, closePath, shape.smoothConstraint\n            );\n\n            ctx.moveTo(points[0][0], points[0][1]);\n            var len = points.length;\n            for (var i = 0; i < (closePath ? len : len - 1); i++) {\n                var cp1 = controlPoints[i * 2];\n                var cp2 = controlPoints[i * 2 + 1];\n                var p = points[(i + 1) % len];\n                ctx.bezierCurveTo(\n                    cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]\n                );\n            }\n        }\n        else {\n            if (smooth === 'spline') {\n                points = smoothSpline(points, closePath);\n            }\n\n            ctx.moveTo(points[0][0], points[0][1]);\n            for (var i = 1, l = points.length; i < l; i++) {\n                ctx.lineTo(points[i][0], points[i][1]);\n            }\n        }\n\n        closePath && ctx.closePath();\n    }\n}\n\n/**\n * 多边形\n * @module zrender/shape/Polygon\n */\n\nvar Polygon = Path.extend({\n\n    type: 'polygon',\n\n    shape: {\n        points: null,\n\n        smooth: false,\n\n        smoothConstraint: null\n    },\n\n    buildPath: function (ctx, shape) {\n        buildPath$1(ctx, shape, true);\n    }\n});\n\n/**\n * @module zrender/graphic/shape/Polyline\n */\n\nvar Polyline = Path.extend({\n\n    type: 'polyline',\n\n    shape: {\n        points: null,\n\n        smooth: false,\n\n        smoothConstraint: null\n    },\n\n    style: {\n        stroke: '#000',\n\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        buildPath$1(ctx, shape, false);\n    }\n});\n\n/**\n * Sub-pixel optimize for canvas rendering, prevent from blur\n * when rendering a thin vertical/horizontal line.\n */\n\nvar round$1 = Math.round;\n\n/**\n * Sub pixel optimize line for canvas\n *\n * @param {Object} outputShape The modification will be performed on `outputShape`.\n *                 `outputShape` and `inputShape` can be the same object.\n *                 `outputShape` object can be used repeatly, because all of\n *                 the `x1`, `x2`, `y1`, `y2` will be assigned in this method.\n * @param {Object} [inputShape]\n * @param {number} [inputShape.x1]\n * @param {number} [inputShape.y1]\n * @param {number} [inputShape.x2]\n * @param {number} [inputShape.y2]\n * @param {Object} [style]\n * @param {number} [style.lineWidth]\n */\nfunction subPixelOptimizeLine$1(outputShape, inputShape, style) {\n    var lineWidth = style && style.lineWidth;\n\n    if (!inputShape || !lineWidth) {\n        return;\n    }\n\n    var x1 = inputShape.x1;\n    var x2 = inputShape.x2;\n    var y1 = inputShape.y1;\n    var y2 = inputShape.y2;\n\n    if (round$1(x1 * 2) === round$1(x2 * 2)) {\n        outputShape.x1 = outputShape.x2 = subPixelOptimize$1(x1, lineWidth, true);\n    }\n    else {\n        outputShape.x1 = x1;\n        outputShape.x2 = x2;\n    }\n    if (round$1(y1 * 2) === round$1(y2 * 2)) {\n        outputShape.y1 = outputShape.y2 = subPixelOptimize$1(y1, lineWidth, true);\n    }\n    else {\n        outputShape.y1 = y1;\n        outputShape.y2 = y2;\n    }\n}\n\n/**\n * Sub pixel optimize rect for canvas\n *\n * @param {Object} outputShape The modification will be performed on `outputShape`.\n *                 `outputShape` and `inputShape` can be the same object.\n *                 `outputShape` object can be used repeatly, because all of\n *                 the `x`, `y`, `width`, `height` will be assigned in this method.\n * @param {Object} [inputShape]\n * @param {number} [inputShape.x]\n * @param {number} [inputShape.y]\n * @param {number} [inputShape.width]\n * @param {number} [inputShape.height]\n * @param {Object} [style]\n * @param {number} [style.lineWidth]\n */\nfunction subPixelOptimizeRect$1(outputShape, inputShape, style) {\n    var lineWidth = style && style.lineWidth;\n\n    if (!inputShape || !lineWidth) {\n        return;\n    }\n\n    var originX = inputShape.x;\n    var originY = inputShape.y;\n    var originWidth = inputShape.width;\n    var originHeight = inputShape.height;\n\n    outputShape.x = subPixelOptimize$1(originX, lineWidth, true);\n    outputShape.y = subPixelOptimize$1(originY, lineWidth, true);\n    outputShape.width = Math.max(\n        subPixelOptimize$1(originX + originWidth, lineWidth, false) - outputShape.x,\n        originWidth === 0 ? 0 : 1\n    );\n    outputShape.height = Math.max(\n        subPixelOptimize$1(originY + originHeight, lineWidth, false) - outputShape.y,\n        originHeight === 0 ? 0 : 1\n    );\n}\n\n/**\n * Sub pixel optimize for canvas\n *\n * @param {number} position Coordinate, such as x, y\n * @param {number} lineWidth Should be nonnegative integer.\n * @param {boolean=} positiveOrNegative Default false (negative).\n * @return {number} Optimized position.\n */\nfunction subPixelOptimize$1(position, lineWidth, positiveOrNegative) {\n    // Assure that (position + lineWidth / 2) is near integer edge,\n    // otherwise line will be fuzzy in canvas.\n    var doubledPosition = round$1(position * 2);\n    return (doubledPosition + round$1(lineWidth)) % 2 === 0\n        ? doubledPosition / 2\n        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;\n}\n\n/**\n * 矩形\n * @module zrender/graphic/shape/Rect\n */\n\n// Avoid create repeatly.\nvar subPixelOptimizeOutputShape = {};\n\nvar Rect = Path.extend({\n\n    type: 'rect',\n\n    shape: {\n        // 左上、右上、右下、左下角的半径依次为r1、r2、r3、r4\n        // r缩写为1         相当于 [1, 1, 1, 1]\n        // r缩写为[1]       相当于 [1, 1, 1, 1]\n        // r缩写为[1, 2]    相当于 [1, 2, 1, 2]\n        // r缩写为[1, 2, 3] 相当于 [1, 2, 3, 2]\n        r: 0,\n\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var x;\n        var y;\n        var width;\n        var height;\n\n        if (this.subPixelOptimize) {\n            subPixelOptimizeRect$1(subPixelOptimizeOutputShape, shape, this.style);\n            x = subPixelOptimizeOutputShape.x;\n            y = subPixelOptimizeOutputShape.y;\n            width = subPixelOptimizeOutputShape.width;\n            height = subPixelOptimizeOutputShape.height;\n            subPixelOptimizeOutputShape.r = shape.r;\n            shape = subPixelOptimizeOutputShape;\n        }\n        else {\n            x = shape.x;\n            y = shape.y;\n            width = shape.width;\n            height = shape.height;\n        }\n\n        if (!shape.r) {\n            ctx.rect(x, y, width, height);\n        }\n        else {\n            buildPath(ctx, shape);\n        }\n        ctx.closePath();\n        return;\n    }\n});\n\n/**\n * 直线\n * @module zrender/graphic/shape/Line\n */\n\n// Avoid create repeatly.\nvar subPixelOptimizeOutputShape$1 = {};\n\nvar Line = Path.extend({\n\n    type: 'line',\n\n    shape: {\n        // Start point\n        x1: 0,\n        y1: 0,\n        // End point\n        x2: 0,\n        y2: 0,\n\n        percent: 1\n    },\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        var x1;\n        var y1;\n        var x2;\n        var y2;\n\n        if (this.subPixelOptimize) {\n            subPixelOptimizeLine$1(subPixelOptimizeOutputShape$1, shape, this.style);\n            x1 = subPixelOptimizeOutputShape$1.x1;\n            y1 = subPixelOptimizeOutputShape$1.y1;\n            x2 = subPixelOptimizeOutputShape$1.x2;\n            y2 = subPixelOptimizeOutputShape$1.y2;\n        }\n        else {\n            x1 = shape.x1;\n            y1 = shape.y1;\n            x2 = shape.x2;\n            y2 = shape.y2;\n        }\n\n        var percent = shape.percent;\n\n        if (percent === 0) {\n            return;\n        }\n\n        ctx.moveTo(x1, y1);\n\n        if (percent < 1) {\n            x2 = x1 * (1 - percent) + x2 * percent;\n            y2 = y1 * (1 - percent) + y2 * percent;\n        }\n        ctx.lineTo(x2, y2);\n    },\n\n    /**\n     * Get point at percent\n     * @param  {number} percent\n     * @return {Array.<number>}\n     */\n    pointAt: function (p) {\n        var shape = this.shape;\n        return [\n            shape.x1 * (1 - p) + shape.x2 * p,\n            shape.y1 * (1 - p) + shape.y2 * p\n        ];\n    }\n});\n\n/**\n * 贝塞尔曲线\n * @module zrender/shape/BezierCurve\n */\n\nvar out = [];\n\nfunction someVectorAt(shape, t, isTangent) {\n    var cpx2 = shape.cpx2;\n    var cpy2 = shape.cpy2;\n    if (cpx2 === null || cpy2 === null) {\n        return [\n            (isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t),\n            (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t)\n        ];\n    }\n    else {\n        return [\n            (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t),\n            (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t)\n        ];\n    }\n}\n\nvar BezierCurve = Path.extend({\n\n    type: 'bezier-curve',\n\n    shape: {\n        x1: 0,\n        y1: 0,\n        x2: 0,\n        y2: 0,\n        cpx1: 0,\n        cpy1: 0,\n        // cpx2: 0,\n        // cpy2: 0\n\n        // Curve show percent, for animating\n        percent: 1\n    },\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        var x1 = shape.x1;\n        var y1 = shape.y1;\n        var x2 = shape.x2;\n        var y2 = shape.y2;\n        var cpx1 = shape.cpx1;\n        var cpy1 = shape.cpy1;\n        var cpx2 = shape.cpx2;\n        var cpy2 = shape.cpy2;\n        var percent = shape.percent;\n        if (percent === 0) {\n            return;\n        }\n\n        ctx.moveTo(x1, y1);\n\n        if (cpx2 == null || cpy2 == null) {\n            if (percent < 1) {\n                quadraticSubdivide(\n                    x1, cpx1, x2, percent, out\n                );\n                cpx1 = out[1];\n                x2 = out[2];\n                quadraticSubdivide(\n                    y1, cpy1, y2, percent, out\n                );\n                cpy1 = out[1];\n                y2 = out[2];\n            }\n\n            ctx.quadraticCurveTo(\n                cpx1, cpy1,\n                x2, y2\n            );\n        }\n        else {\n            if (percent < 1) {\n                cubicSubdivide(\n                    x1, cpx1, cpx2, x2, percent, out\n                );\n                cpx1 = out[1];\n                cpx2 = out[2];\n                x2 = out[3];\n                cubicSubdivide(\n                    y1, cpy1, cpy2, y2, percent, out\n                );\n                cpy1 = out[1];\n                cpy2 = out[2];\n                y2 = out[3];\n            }\n            ctx.bezierCurveTo(\n                cpx1, cpy1,\n                cpx2, cpy2,\n                x2, y2\n            );\n        }\n    },\n\n    /**\n     * Get point at percent\n     * @param  {number} t\n     * @return {Array.<number>}\n     */\n    pointAt: function (t) {\n        return someVectorAt(this.shape, t, false);\n    },\n\n    /**\n     * Get tangent at percent\n     * @param  {number} t\n     * @return {Array.<number>}\n     */\n    tangentAt: function (t) {\n        var p = someVectorAt(this.shape, t, true);\n        return normalize(p, p);\n    }\n});\n\n/**\n * 圆弧\n * @module zrender/graphic/shape/Arc\n */\n\nvar Arc = Path.extend({\n\n    type: 'arc',\n\n    shape: {\n\n        cx: 0,\n\n        cy: 0,\n\n        r: 0,\n\n        startAngle: 0,\n\n        endAngle: Math.PI * 2,\n\n        clockwise: true\n    },\n\n    style: {\n\n        stroke: '#000',\n\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n\n        var x = shape.cx;\n        var y = shape.cy;\n        var r = Math.max(shape.r, 0);\n        var startAngle = shape.startAngle;\n        var endAngle = shape.endAngle;\n        var clockwise = shape.clockwise;\n\n        var unitX = Math.cos(startAngle);\n        var unitY = Math.sin(startAngle);\n\n        ctx.moveTo(unitX * r + x, unitY * r + y);\n        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);\n    }\n});\n\n// CompoundPath to improve performance\n\nvar CompoundPath = Path.extend({\n\n    type: 'compound',\n\n    shape: {\n\n        paths: null\n    },\n\n    _updatePathDirty: function () {\n        var dirtyPath = this.__dirtyPath;\n        var paths = this.shape.paths;\n        for (var i = 0; i < paths.length; i++) {\n            // Mark as dirty if any subpath is dirty\n            dirtyPath = dirtyPath || paths[i].__dirtyPath;\n        }\n        this.__dirtyPath = dirtyPath;\n        this.__dirty = this.__dirty || dirtyPath;\n    },\n\n    beforeBrush: function () {\n        this._updatePathDirty();\n        var paths = this.shape.paths || [];\n        var scale = this.getGlobalScale();\n        // Update path scale\n        for (var i = 0; i < paths.length; i++) {\n            if (!paths[i].path) {\n                paths[i].createPathProxy();\n            }\n            paths[i].path.setScale(scale[0], scale[1]);\n        }\n    },\n\n    buildPath: function (ctx, shape) {\n        var paths = shape.paths || [];\n        for (var i = 0; i < paths.length; i++) {\n            paths[i].buildPath(ctx, paths[i].shape, true);\n        }\n    },\n\n    afterBrush: function () {\n        var paths = this.shape.paths || [];\n        for (var i = 0; i < paths.length; i++) {\n            paths[i].__dirtyPath = false;\n        }\n    },\n\n    getBoundingRect: function () {\n        this._updatePathDirty();\n        return Path.prototype.getBoundingRect.call(this);\n    }\n});\n\n/**\n * @param {Array.<Object>} colorStops\n */\nvar Gradient = function (colorStops) {\n\n    this.colorStops = colorStops || [];\n\n};\n\nGradient.prototype = {\n\n    constructor: Gradient,\n\n    addColorStop: function (offset, color) {\n        this.colorStops.push({\n\n            offset: offset,\n\n            color: color\n        });\n    }\n\n};\n\n/**\n * x, y, x2, y2 are all percent from 0 to 1\n * @param {number} [x=0]\n * @param {number} [y=0]\n * @param {number} [x2=1]\n * @param {number} [y2=0]\n * @param {Array.<Object>} colorStops\n * @param {boolean} [globalCoord=false]\n */\nvar LinearGradient = function (x, y, x2, y2, colorStops, globalCoord) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {type: 'linear', colorStops: ...}`, where\n    // this constructor will not be called.\n\n    this.x = x == null ? 0 : x;\n\n    this.y = y == null ? 0 : y;\n\n    this.x2 = x2 == null ? 1 : x2;\n\n    this.y2 = y2 == null ? 0 : y2;\n\n    // Can be cloned\n    this.type = 'linear';\n\n    // If use global coord\n    this.global = globalCoord || false;\n\n    Gradient.call(this, colorStops);\n};\n\nLinearGradient.prototype = {\n\n    constructor: LinearGradient\n};\n\ninherits(LinearGradient, Gradient);\n\n/**\n * x, y, r are all percent from 0 to 1\n * @param {number} [x=0.5]\n * @param {number} [y=0.5]\n * @param {number} [r=0.5]\n * @param {Array.<Object>} [colorStops]\n * @param {boolean} [globalCoord=false]\n */\nvar RadialGradient = function (x, y, r, colorStops, globalCoord) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {type: 'radial', colorStops: ...}`, where\n    // this constructor will not be called.\n\n    this.x = x == null ? 0.5 : x;\n\n    this.y = y == null ? 0.5 : y;\n\n    this.r = r == null ? 0.5 : r;\n\n    // Can be cloned\n    this.type = 'radial';\n\n    // If use global coord\n    this.global = globalCoord || false;\n\n    Gradient.call(this, colorStops);\n};\n\nRadialGradient.prototype = {\n\n    constructor: RadialGradient\n};\n\ninherits(RadialGradient, Gradient);\n\n/**\n * Displayable for incremental rendering. It will be rendered in a separate layer\n * IncrementalDisplay have two main methods. `clearDisplayables` and `addDisplayables`\n * addDisplayables will render the added displayables incremetally.\n *\n * It use a not clearFlag to tell the painter don't clear the layer if it's the first element.\n */\n// TODO Style override ?\nfunction IncrementalDisplayble(opts) {\n\n    Displayable.call(this, opts);\n\n    this._displayables = [];\n\n    this._temporaryDisplayables = [];\n\n    this._cursor = 0;\n\n    this.notClear = true;\n}\n\nIncrementalDisplayble.prototype.incremental = true;\n\nIncrementalDisplayble.prototype.clearDisplaybles = function () {\n    this._displayables = [];\n    this._temporaryDisplayables = [];\n    this._cursor = 0;\n    this.dirty();\n\n    this.notClear = false;\n};\n\nIncrementalDisplayble.prototype.addDisplayable = function (displayable, notPersistent) {\n    if (notPersistent) {\n        this._temporaryDisplayables.push(displayable);\n    }\n    else {\n        this._displayables.push(displayable);\n    }\n    this.dirty();\n};\n\nIncrementalDisplayble.prototype.addDisplayables = function (displayables, notPersistent) {\n    notPersistent = notPersistent || false;\n    for (var i = 0; i < displayables.length; i++) {\n        this.addDisplayable(displayables[i], notPersistent);\n    }\n};\n\nIncrementalDisplayble.prototype.eachPendingDisplayable = function (cb) {\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        cb && cb(this._displayables[i]);\n    }\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        cb && cb(this._temporaryDisplayables[i]);\n    }\n};\n\nIncrementalDisplayble.prototype.update = function () {\n    this.updateTransform();\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        var displayable = this._displayables[i];\n        // PENDING\n        displayable.parent = this;\n        displayable.update();\n        displayable.parent = null;\n    }\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        var displayable = this._temporaryDisplayables[i];\n        // PENDING\n        displayable.parent = this;\n        displayable.update();\n        displayable.parent = null;\n    }\n};\n\nIncrementalDisplayble.prototype.brush = function (ctx, prevEl) {\n    // Render persistant displayables.\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        var displayable = this._displayables[i];\n        displayable.beforeBrush && displayable.beforeBrush(ctx);\n        displayable.brush(ctx, i === this._cursor ? null : this._displayables[i - 1]);\n        displayable.afterBrush && displayable.afterBrush(ctx);\n    }\n    this._cursor = i;\n    // Render temporary displayables.\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        var displayable = this._temporaryDisplayables[i];\n        displayable.beforeBrush && displayable.beforeBrush(ctx);\n        displayable.brush(ctx, i === 0 ? null : this._temporaryDisplayables[i - 1]);\n        displayable.afterBrush && displayable.afterBrush(ctx);\n    }\n\n    this._temporaryDisplayables = [];\n\n    this.notClear = true;\n};\n\nvar m = [];\nIncrementalDisplayble.prototype.getBoundingRect = function () {\n    if (!this._rect) {\n        var rect = new BoundingRect(Infinity, Infinity, -Infinity, -Infinity);\n        for (var i = 0; i < this._displayables.length; i++) {\n            var displayable = this._displayables[i];\n            var childRect = displayable.getBoundingRect().clone();\n            if (displayable.needLocalTransform()) {\n                childRect.applyTransform(displayable.getLocalTransform(m));\n            }\n            rect.union(childRect);\n        }\n        this._rect = rect;\n    }\n    return this._rect;\n};\n\nIncrementalDisplayble.prototype.contain = function (x, y) {\n    var localPos = this.transformCoordToLocal(x, y);\n    var rect = this.getBoundingRect();\n\n    if (rect.contain(localPos[0], localPos[1])) {\n        for (var i = 0; i < this._displayables.length; i++) {\n            var displayable = this._displayables[i];\n            if (displayable.contain(x, y)) {\n                return true;\n            }\n        }\n    }\n    return false;\n};\n\ninherits(IncrementalDisplayble, Displayable);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar round = Math.round;\nvar mathMax$1 = Math.max;\nvar mathMin$1 = Math.min;\n\nvar EMPTY_OBJ = {};\n\nvar Z2_EMPHASIS_LIFT = 1;\n\n/**\n * Extend shape with parameters\n */\nfunction extendShape(opts) {\n    return Path.extend(opts);\n}\n\n/**\n * Extend path\n */\nfunction extendPath(pathData, opts) {\n    return extendFromString(pathData, opts);\n}\n\n/**\n * Create a path element from path data string\n * @param {string} pathData\n * @param {Object} opts\n * @param {module:zrender/core/BoundingRect} rect\n * @param {string} [layout=cover] 'center' or 'cover'\n */\nfunction makePath(pathData, opts, rect, layout) {\n    var path = createFromString(pathData, opts);\n    if (rect) {\n        if (layout === 'center') {\n            rect = centerGraphic(rect, path.getBoundingRect());\n        }\n        resizePath(path, rect);\n    }\n    return path;\n}\n\n/**\n * Create a image element from image url\n * @param {string} imageUrl image url\n * @param {Object} opts options\n * @param {module:zrender/core/BoundingRect} rect constrain rect\n * @param {string} [layout=cover] 'center' or 'cover'\n */\nfunction makeImage(imageUrl, rect, layout) {\n    var path = new ZImage({\n        style: {\n            image: imageUrl,\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        },\n        onload: function (img) {\n            if (layout === 'center') {\n                var boundingRect = {\n                    width: img.width,\n                    height: img.height\n                };\n                path.setStyle(centerGraphic(rect, boundingRect));\n            }\n        }\n    });\n    return path;\n}\n\n/**\n * Get position of centered element in bounding box.\n *\n * @param  {Object} rect         element local bounding box\n * @param  {Object} boundingRect constraint bounding box\n * @return {Object} element position containing x, y, width, and height\n */\nfunction centerGraphic(rect, boundingRect) {\n    // Set rect to center, keep width / height ratio.\n    var aspect = boundingRect.width / boundingRect.height;\n    var width = rect.height * aspect;\n    var height;\n    if (width <= rect.width) {\n        height = rect.height;\n    }\n    else {\n        width = rect.width;\n        height = width / aspect;\n    }\n    var cx = rect.x + rect.width / 2;\n    var cy = rect.y + rect.height / 2;\n\n    return {\n        x: cx - width / 2,\n        y: cy - height / 2,\n        width: width,\n        height: height\n    };\n}\n\nvar mergePath = mergePath$1;\n\n/**\n * Resize a path to fit the rect\n * @param {module:zrender/graphic/Path} path\n * @param {Object} rect\n */\nfunction resizePath(path, rect) {\n    if (!path.applyTransform) {\n        return;\n    }\n\n    var pathRect = path.getBoundingRect();\n\n    var m = pathRect.calculateTransform(rect);\n\n    path.applyTransform(m);\n}\n\n/**\n * Sub pixel optimize line for canvas\n *\n * @param {Object} param\n * @param {Object} [param.shape]\n * @param {number} [param.shape.x1]\n * @param {number} [param.shape.y1]\n * @param {number} [param.shape.x2]\n * @param {number} [param.shape.y2]\n * @param {Object} [param.style]\n * @param {number} [param.style.lineWidth]\n * @return {Object} Modified param\n */\nfunction subPixelOptimizeLine(param) {\n    var shape = param.shape;\n    var lineWidth = param.style.lineWidth;\n\n    if (round(shape.x1 * 2) === round(shape.x2 * 2)) {\n        shape.x1 = shape.x2 = subPixelOptimize(shape.x1, lineWidth, true);\n    }\n    if (round(shape.y1 * 2) === round(shape.y2 * 2)) {\n        shape.y1 = shape.y2 = subPixelOptimize(shape.y1, lineWidth, true);\n    }\n    return param;\n}\n\n/**\n * Sub pixel optimize rect for canvas\n *\n * @param {Object} param\n * @param {Object} [param.shape]\n * @param {number} [param.shape.x]\n * @param {number} [param.shape.y]\n * @param {number} [param.shape.width]\n * @param {number} [param.shape.height]\n * @param {Object} [param.style]\n * @param {number} [param.style.lineWidth]\n * @return {Object} Modified param\n */\nfunction subPixelOptimizeRect(param) {\n    var shape = param.shape;\n    var lineWidth = param.style.lineWidth;\n    var originX = shape.x;\n    var originY = shape.y;\n    var originWidth = shape.width;\n    var originHeight = shape.height;\n    shape.x = subPixelOptimize(shape.x, lineWidth, true);\n    shape.y = subPixelOptimize(shape.y, lineWidth, true);\n    shape.width = Math.max(\n        subPixelOptimize(originX + originWidth, lineWidth, false) - shape.x,\n        originWidth === 0 ? 0 : 1\n    );\n    shape.height = Math.max(\n        subPixelOptimize(originY + originHeight, lineWidth, false) - shape.y,\n        originHeight === 0 ? 0 : 1\n    );\n    return param;\n}\n\n/**\n * Sub pixel optimize for canvas\n *\n * @param {number} position Coordinate, such as x, y\n * @param {number} lineWidth Should be nonnegative integer.\n * @param {boolean=} positiveOrNegative Default false (negative).\n * @return {number} Optimized position.\n */\nfunction subPixelOptimize(position, lineWidth, positiveOrNegative) {\n    // Assure that (position + lineWidth / 2) is near integer edge,\n    // otherwise line will be fuzzy in canvas.\n    var doubledPosition = round(position * 2);\n    return (doubledPosition + round(lineWidth)) % 2 === 0\n        ? doubledPosition / 2\n        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;\n}\n\nfunction hasFillOrStroke(fillOrStroke) {\n    return fillOrStroke != null && fillOrStroke !== 'none';\n}\n\n// Most lifted color are duplicated.\nvar liftedColorMap = createHashMap();\nvar liftedColorCount = 0;\n\nfunction liftColor(color) {\n    if (typeof color !== 'string') {\n        return color;\n    }\n    var liftedColor = liftedColorMap.get(color);\n    if (!liftedColor) {\n        liftedColor = lift(color, -0.1);\n        if (liftedColorCount < 10000) {\n            liftedColorMap.set(color, liftedColor);\n            liftedColorCount++;\n        }\n    }\n    return liftedColor;\n}\n\nfunction cacheElementStl(el) {\n    if (!el.__hoverStlDirty) {\n        return;\n    }\n    el.__hoverStlDirty = false;\n\n    var hoverStyle = el.__hoverStl;\n    if (!hoverStyle) {\n        el.__cachedNormalStl = el.__cachedNormalZ2 = null;\n        return;\n    }\n\n    var normalStyle = el.__cachedNormalStl = {};\n    el.__cachedNormalZ2 = el.z2;\n    var elStyle = el.style;\n\n    for (var name in hoverStyle) {\n        // See comment in `doSingleEnterHover`.\n        if (hoverStyle[name] != null) {\n            normalStyle[name] = elStyle[name];\n        }\n    }\n\n    // Always cache fill and stroke to normalStyle for lifting color.\n    normalStyle.fill = elStyle.fill;\n    normalStyle.stroke = elStyle.stroke;\n}\n\nfunction doSingleEnterHover(el) {\n    var hoverStl = el.__hoverStl;\n\n    if (!hoverStl || el.__highlighted) {\n        return;\n    }\n\n    var useHoverLayer = el.useHoverLayer;\n    el.__highlighted = useHoverLayer ? 'layer' : 'plain';\n\n    var zr = el.__zr;\n    if (!zr && useHoverLayer) {\n        return;\n    }\n\n    var elTarget = el;\n    var targetStyle = el.style;\n\n    if (useHoverLayer) {\n        elTarget = zr.addHover(el);\n        targetStyle = elTarget.style;\n    }\n\n    rollbackDefaultTextStyle(targetStyle);\n\n    if (!useHoverLayer) {\n        cacheElementStl(elTarget);\n    }\n\n    // styles can be:\n    // {\n    //    label: {\n    //        show: false,\n    //        position: 'outside',\n    //        fontSize: 18\n    //    },\n    //    emphasis: {\n    //        label: {\n    //            show: true\n    //        }\n    //    }\n    // },\n    // where properties of `emphasis` may not appear in `normal`. We previously use\n    // module:echarts/util/model#defaultEmphasis to merge `normal` to `emphasis`.\n    // But consider rich text and setOption in merge mode, it is impossible to cover\n    // all properties in merge. So we use merge mode when setting style here, where\n    // only properties that is not `null/undefined` can be set. The disadventage:\n    // null/undefined can not be used to remove style any more in `emphasis`.\n    targetStyle.extendFrom(hoverStl);\n\n    setDefaultHoverFillStroke(targetStyle, hoverStl, 'fill');\n    setDefaultHoverFillStroke(targetStyle, hoverStl, 'stroke');\n\n    applyDefaultTextStyle(targetStyle);\n\n    if (!useHoverLayer) {\n        el.dirty(false);\n        el.z2 += Z2_EMPHASIS_LIFT;\n    }\n}\n\nfunction setDefaultHoverFillStroke(targetStyle, hoverStyle, prop) {\n    if (!hasFillOrStroke(hoverStyle[prop]) && hasFillOrStroke(targetStyle[prop])) {\n        targetStyle[prop] = liftColor(targetStyle[prop]);\n    }\n}\n\nfunction doSingleLeaveHover(el) {\n    var highlighted = el.__highlighted;\n\n    if (!highlighted) {\n        return;\n    }\n\n    el.__highlighted = false;\n\n    if (highlighted === 'layer') {\n        el.__zr && el.__zr.removeHover(el);\n    }\n    else if (highlighted) {\n        var style = el.style;\n\n        var normalStl = el.__cachedNormalStl;\n        if (normalStl) {\n            rollbackDefaultTextStyle(style);\n            // Consider null/undefined value, should use\n            // `setStyle` but not `extendFrom(stl, true)`.\n            el.setStyle(normalStl);\n            applyDefaultTextStyle(style);\n        }\n        // `__cachedNormalZ2` will not be reset if calling `setElementHoverStyle`\n        // when `el` is on emphasis state. So here by comparing with 1, we try\n        // hard to make the bug case rare.\n        var normalZ2 = el.__cachedNormalZ2;\n        if (normalZ2 != null && el.z2 - normalZ2 === Z2_EMPHASIS_LIFT) {\n            el.z2 = normalZ2;\n        }\n    }\n}\n\nfunction traverseCall(el, method) {\n    el.isGroup\n        ? el.traverse(function (child) {\n            !child.isGroup && method(child);\n        })\n        : method(el);\n}\n\n/**\n * Set hover style (namely \"emphasis style\") of element, based on the current\n * style of the given `el`.\n * This method should be called after all of the normal styles have been adopted\n * to the `el`. See the reason on `setHoverStyle`.\n *\n * @param {module:zrender/Element} el Should not be `zrender/container/Group`.\n * @param {Object|boolean} [hoverStl] The specified hover style.\n *        If set as `false`, disable the hover style.\n *        Similarly, The `el.hoverStyle` can alse be set\n *        as `false` to disable the hover style.\n *        Otherwise, use the default hover style if not provided.\n * @param {Object} [opt]\n * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`\n */\nfunction setElementHoverStyle(el, hoverStl) {\n    // For performance consideration, it might be better to make the \"hover style\" only the\n    // difference properties from the \"normal style\", but not a entire copy of all styles.\n    hoverStl = el.__hoverStl = hoverStl !== false && (hoverStl || {});\n    el.__hoverStlDirty = true;\n\n    // FIXME\n    // It is not completely right to save \"normal\"/\"emphasis\" flag on elements.\n    // It probably should be saved on `data` of series. Consider the cases:\n    // (1) A highlighted elements are moved out of the view port and re-enter\n    // again by dataZoom.\n    // (2) call `setOption` and replace elements totally when they are highlighted.\n    if (el.__highlighted) {\n        // Consider the case:\n        // The styles of a highlighted `el` is being updated. The new \"emphasis style\"\n        // should be adapted to the `el`. Notice here new \"normal styles\" should have\n        // been set outside and the cached \"normal style\" is out of date.\n        el.__cachedNormalStl = null;\n        // Do not clear `__cachedNormalZ2` here, because setting `z2` is not a constraint\n        // of this method. In most cases, `z2` is not set and hover style should be able\n        // to rollback. Of course, that would bring bug, but only in a rare case, see\n        // `doSingleLeaveHover` for details.\n        doSingleLeaveHover(el);\n\n        doSingleEnterHover(el);\n    }\n}\n\n/**\n * Emphasis (called by API) has higher priority than `mouseover`.\n * When element has been called to be entered emphasis, mouse over\n * should not trigger the highlight effect (for example, animation\n * scale) again, and `mouseout` should not downplay the highlight\n * effect. So the listener of `mouseover` and `mouseout` should\n * check `isInEmphasis`.\n *\n * @param {module:zrender/Element} el\n * @return {boolean}\n */\nfunction isInEmphasis(el) {\n    return el && el.__isEmphasisEntered;\n}\n\nfunction onElementMouseOver(e) {\n    if (this.__hoverSilentOnTouch && e.zrByTouch) {\n        return;\n    }\n\n    // Only if element is not in emphasis status\n    !this.__isEmphasisEntered && traverseCall(this, doSingleEnterHover);\n}\n\nfunction onElementMouseOut(e) {\n    if (this.__hoverSilentOnTouch && e.zrByTouch) {\n        return;\n    }\n\n    // Only if element is not in emphasis status\n    !this.__isEmphasisEntered && traverseCall(this, doSingleLeaveHover);\n}\n\nfunction enterEmphasis() {\n    this.__isEmphasisEntered = true;\n    traverseCall(this, doSingleEnterHover);\n}\n\nfunction leaveEmphasis() {\n    this.__isEmphasisEntered = false;\n    traverseCall(this, doSingleLeaveHover);\n}\n\n/**\n * Set hover style (namely \"emphasis style\") of element,\n * based on the current style of the given `el`.\n *\n * (1)\n * **CONSTRAINTS** for this method:\n * <A> This method MUST be called after all of the normal styles having been adopted\n * to the `el`.\n * <B> The input `hoverStyle` (that is, \"emphasis style\") MUST be the subset of the\n * \"normal style\" having been set to the el.\n * <C> `color` MUST be one of the \"normal styles\" (because color might be lifted as\n * a default hover style).\n *\n * The reason: this method treat the current style of the `el` as the \"normal style\"\n * and cache them when enter/update the \"emphasis style\". Consider the case: the `el`\n * is in \"emphasis\" state and `setOption`/`dispatchAction` trigger the style updating\n * logic, where the el should shift from the original emphasis style to the new\n * \"emphasis style\" and should be able to \"downplay\" back to the new \"normal style\".\n *\n * Indeed, it is error-prone to make a interface has so many constraints, but I have\n * not found a better solution yet to fit the backward compatibility, performance and\n * the current programming style.\n *\n * (2)\n * Call the method for a \"root\" element once. Do not call it for each descendants.\n * If the descendants elemenets of a group has itself hover style different from the\n * root group, we can simply mount the style on `el.hoverStyle` for them, but should\n * not call this method for them.\n *\n * @param {module:zrender/Element} el\n * @param {Object|boolean} [hoverStyle] See `graphic.setElementHoverStyle`.\n * @param {Object} [opt]\n * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`.\n */\nfunction setHoverStyle(el, hoverStyle, opt) {\n    el.isGroup\n        ? el.traverse(function (child) {\n            // If element has sepcified hoverStyle, then use it instead of given hoverStyle\n            // Often used when item group has a label element and it's hoverStyle is different\n            !child.isGroup && setElementHoverStyle(child, child.hoverStyle || hoverStyle);\n        })\n        : setElementHoverStyle(el, el.hoverStyle || hoverStyle);\n\n    setAsHoverStyleTrigger(el, opt);\n}\n\n/**\n * @param {Object|boolean} [opt] If `false`, means disable trigger.\n * @param {boolean} [opt.hoverSilentOnTouch=false]\n *        In touch device, mouseover event will be trigger on touchstart event\n *        (see module:zrender/dom/HandlerProxy). By this mechanism, we can\n *        conveniently use hoverStyle when tap on touch screen without additional\n *        code for compatibility.\n *        But if the chart/component has select feature, which usually also use\n *        hoverStyle, there might be conflict between 'select-highlight' and\n *        'hover-highlight' especially when roam is enabled (see geo for example).\n *        In this case, hoverSilentOnTouch should be used to disable hover-highlight\n *        on touch device.\n */\nfunction setAsHoverStyleTrigger(el, opt) {\n    var disable = opt === false;\n    el.__hoverSilentOnTouch = opt != null && opt.hoverSilentOnTouch;\n\n    // Simple optimize, since this method might be\n    // called for each elements of a group in some cases.\n    if (!disable || el.__hoverStyleTrigger) {\n        var method = disable ? 'off' : 'on';\n\n        // Duplicated function will be auto-ignored, see Eventful.js.\n        el[method]('mouseover', onElementMouseOver)[method]('mouseout', onElementMouseOut);\n        // Emphasis, normal can be triggered manually\n        el[method]('emphasis', enterEmphasis)[method]('normal', leaveEmphasis);\n\n        el.__hoverStyleTrigger = !disable;\n    }\n}\n\n/**\n * See more info in `setTextStyleCommon`.\n * @param {Object|module:zrender/graphic/Style} normalStyle\n * @param {Object} emphasisStyle\n * @param {module:echarts/model/Model} normalModel\n * @param {module:echarts/model/Model} emphasisModel\n * @param {Object} opt Check `opt` of `setTextStyleCommon` to find other props.\n * @param {string|Function} [opt.defaultText]\n * @param {module:echarts/model/Model} [opt.labelFetcher] Fetch text by\n *      `opt.labelFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {module:echarts/model/Model} [opt.labelDataIndex] Fetch text by\n *      `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {module:echarts/model/Model} [opt.labelDimIndex] Fetch text by\n *      `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {Object} [normalSpecified]\n * @param {Object} [emphasisSpecified]\n */\nfunction setLabelStyle(\n    normalStyle, emphasisStyle,\n    normalModel, emphasisModel,\n    opt,\n    normalSpecified, emphasisSpecified\n) {\n    opt = opt || EMPTY_OBJ;\n    var labelFetcher = opt.labelFetcher;\n    var labelDataIndex = opt.labelDataIndex;\n    var labelDimIndex = opt.labelDimIndex;\n\n    // This scenario, `label.normal.show = true; label.emphasis.show = false`,\n    // is not supported util someone requests.\n\n    var showNormal = normalModel.getShallow('show');\n    var showEmphasis = emphasisModel.getShallow('show');\n\n    // Consider performance, only fetch label when necessary.\n    // If `normal.show` is `false` and `emphasis.show` is `true` and `emphasis.formatter` is not set,\n    // label should be displayed, where text is fetched by `normal.formatter` or `opt.defaultText`.\n    var baseText;\n    if (showNormal || showEmphasis) {\n        if (labelFetcher) {\n            baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex);\n        }\n        if (baseText == null) {\n            baseText = isFunction$1(opt.defaultText) ? opt.defaultText(labelDataIndex, opt) : opt.defaultText;\n        }\n    }\n    var normalStyleText = showNormal ? baseText : null;\n    var emphasisStyleText = showEmphasis\n        ? retrieve2(\n            labelFetcher\n                ? labelFetcher.getFormattedLabel(labelDataIndex, 'emphasis', null, labelDimIndex)\n                : null,\n            baseText\n        )\n        : null;\n\n    // Optimize: If style.text is null, text will not be drawn.\n    if (normalStyleText != null || emphasisStyleText != null) {\n        // Always set `textStyle` even if `normalStyle.text` is null, because default\n        // values have to be set on `normalStyle`.\n        // If we set default values on `emphasisStyle`, consider case:\n        // Firstly, `setOption(... label: {normal: {text: null}, emphasis: {show: true}} ...);`\n        // Secondly, `setOption(... label: {noraml: {show: true, text: 'abc', color: 'red'} ...);`\n        // Then the 'red' will not work on emphasis.\n        setTextStyle(normalStyle, normalModel, normalSpecified, opt);\n        setTextStyle(emphasisStyle, emphasisModel, emphasisSpecified, opt, true);\n    }\n\n    normalStyle.text = normalStyleText;\n    emphasisStyle.text = emphasisStyleText;\n}\n\n/**\n * Set basic textStyle properties.\n * See more info in `setTextStyleCommon`.\n * @param {Object|module:zrender/graphic/Style} textStyle\n * @param {module:echarts/model/Model} model\n * @param {Object} [specifiedTextStyle] Can be overrided by settings in model.\n * @param {Object} [opt] See `opt` of `setTextStyleCommon`.\n * @param {boolean} [isEmphasis]\n */\nfunction setTextStyle(\n    textStyle, textStyleModel, specifiedTextStyle, opt, isEmphasis\n) {\n    setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis);\n    specifiedTextStyle && extend(textStyle, specifiedTextStyle);\n    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);\n\n    return textStyle;\n}\n\n/**\n * Set text option in the style.\n * See more info in `setTextStyleCommon`.\n * @deprecated\n * @param {Object} textStyle\n * @param {module:echarts/model/Model} labelModel\n * @param {string|boolean} defaultColor Default text color.\n *        If set as false, it will be processed as a emphasis style.\n */\nfunction setText(textStyle, labelModel, defaultColor) {\n    var opt = {isRectText: true};\n    var isEmphasis;\n\n    if (defaultColor === false) {\n        isEmphasis = true;\n    }\n    else {\n        // Support setting color as 'auto' to get visual color.\n        opt.autoColor = defaultColor;\n    }\n    setTextStyleCommon(textStyle, labelModel, opt, isEmphasis);\n    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);\n}\n\n/**\n * The uniform entry of set text style, that is, retrieve style definitions\n * from `model` and set to `textStyle` object.\n *\n * Never in merge mode, but in overwrite mode, that is, all of the text style\n * properties will be set. (Consider the states of normal and emphasis and\n * default value can be adopted, merge would make the logic too complicated\n * to manage.)\n *\n * The `textStyle` object can either be a plain object or an instance of\n * `zrender/src/graphic/Style`, and either be the style of normal or emphasis.\n * After this mothod called, the `textStyle` object can then be used in\n * `el.setStyle(textStyle)` or `el.hoverStyle = textStyle`.\n *\n * Default value will be adopted and `insideRollbackOpt` will be created.\n * See `applyDefaultTextStyle` `rollbackDefaultTextStyle` for more details.\n *\n * opt: {\n *      disableBox: boolean, Whether diable drawing box of block (outer most).\n *      isRectText: boolean,\n *      autoColor: string, specify a color when color is 'auto',\n *              for textFill, textStroke, textBackgroundColor, and textBorderColor.\n *              If autoColor specified, it is used as default textFill.\n *      useInsideStyle:\n *              `true`: Use inside style (textFill, textStroke, textStrokeWidth)\n *                  if `textFill` is not specified.\n *              `false`: Do not use inside style.\n *              `null/undefined`: use inside style if `isRectText` is true and\n *                  `textFill` is not specified and textPosition contains `'inside'`.\n *      forceRich: boolean\n * }\n */\nfunction setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis) {\n    // Consider there will be abnormal when merge hover style to normal style if given default value.\n    opt = opt || EMPTY_OBJ;\n\n    if (opt.isRectText) {\n        var textPosition = textStyleModel.getShallow('position')\n            || (isEmphasis ? null : 'inside');\n        // 'outside' is not a valid zr textPostion value, but used\n        // in bar series, and magric type should be considered.\n        textPosition === 'outside' && (textPosition = 'top');\n        textStyle.textPosition = textPosition;\n        textStyle.textOffset = textStyleModel.getShallow('offset');\n        var labelRotate = textStyleModel.getShallow('rotate');\n        labelRotate != null && (labelRotate *= Math.PI / 180);\n        textStyle.textRotation = labelRotate;\n        textStyle.textDistance = retrieve2(\n            textStyleModel.getShallow('distance'), isEmphasis ? null : 5\n        );\n    }\n\n    var ecModel = textStyleModel.ecModel;\n    var globalTextStyle = ecModel && ecModel.option.textStyle;\n\n    // Consider case:\n    // {\n    //     data: [{\n    //         value: 12,\n    //         label: {\n    //             rich: {\n    //                 // no 'a' here but using parent 'a'.\n    //             }\n    //         }\n    //     }],\n    //     rich: {\n    //         a: { ... }\n    //     }\n    // }\n    var richItemNames = getRichItemNames(textStyleModel);\n    var richResult;\n    if (richItemNames) {\n        richResult = {};\n        for (var name in richItemNames) {\n            if (richItemNames.hasOwnProperty(name)) {\n                // Cascade is supported in rich.\n                var richTextStyle = textStyleModel.getModel(['rich', name]);\n                // In rich, never `disableBox`.\n                setTokenTextStyle(richResult[name] = {}, richTextStyle, globalTextStyle, opt, isEmphasis);\n            }\n        }\n    }\n    textStyle.rich = richResult;\n\n    setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, true);\n\n    if (opt.forceRich && !opt.textStyle) {\n        opt.textStyle = {};\n    }\n\n    return textStyle;\n}\n\n// Consider case:\n// {\n//     data: [{\n//         value: 12,\n//         label: {\n//             rich: {\n//                 // no 'a' here but using parent 'a'.\n//             }\n//         }\n//     }],\n//     rich: {\n//         a: { ... }\n//     }\n// }\nfunction getRichItemNames(textStyleModel) {\n    // Use object to remove duplicated names.\n    var richItemNameMap;\n    while (textStyleModel && textStyleModel !== textStyleModel.ecModel) {\n        var rich = (textStyleModel.option || EMPTY_OBJ).rich;\n        if (rich) {\n            richItemNameMap = richItemNameMap || {};\n            for (var name in rich) {\n                if (rich.hasOwnProperty(name)) {\n                    richItemNameMap[name] = 1;\n                }\n            }\n        }\n        textStyleModel = textStyleModel.parentModel;\n    }\n    return richItemNameMap;\n}\n\nfunction setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, isBlock) {\n    // In merge mode, default value should not be given.\n    globalTextStyle = !isEmphasis && globalTextStyle || EMPTY_OBJ;\n\n    textStyle.textFill = getAutoColor(textStyleModel.getShallow('color'), opt)\n        || globalTextStyle.color;\n    textStyle.textStroke = getAutoColor(textStyleModel.getShallow('textBorderColor'), opt)\n        || globalTextStyle.textBorderColor;\n    textStyle.textStrokeWidth = retrieve2(\n        textStyleModel.getShallow('textBorderWidth'),\n        globalTextStyle.textBorderWidth\n    );\n\n    // Save original textPosition, because style.textPosition will be repalced by\n    // real location (like [10, 30]) in zrender.\n    textStyle.insideRawTextPosition = textStyle.textPosition;\n\n    if (!isEmphasis) {\n        if (isBlock) {\n            textStyle.insideRollbackOpt = opt;\n            applyDefaultTextStyle(textStyle);\n        }\n\n        // Set default finally.\n        if (textStyle.textFill == null) {\n            textStyle.textFill = opt.autoColor;\n        }\n    }\n\n    // Do not use `getFont` here, because merge should be supported, where\n    // part of these properties may be changed in emphasis style, and the\n    // others should remain their original value got from normal style.\n    textStyle.fontStyle = textStyleModel.getShallow('fontStyle') || globalTextStyle.fontStyle;\n    textStyle.fontWeight = textStyleModel.getShallow('fontWeight') || globalTextStyle.fontWeight;\n    textStyle.fontSize = textStyleModel.getShallow('fontSize') || globalTextStyle.fontSize;\n    textStyle.fontFamily = textStyleModel.getShallow('fontFamily') || globalTextStyle.fontFamily;\n\n    textStyle.textAlign = textStyleModel.getShallow('align');\n    textStyle.textVerticalAlign = textStyleModel.getShallow('verticalAlign')\n        || textStyleModel.getShallow('baseline');\n\n    textStyle.textLineHeight = textStyleModel.getShallow('lineHeight');\n    textStyle.textWidth = textStyleModel.getShallow('width');\n    textStyle.textHeight = textStyleModel.getShallow('height');\n    textStyle.textTag = textStyleModel.getShallow('tag');\n\n    if (!isBlock || !opt.disableBox) {\n        textStyle.textBackgroundColor = getAutoColor(textStyleModel.getShallow('backgroundColor'), opt);\n        textStyle.textPadding = textStyleModel.getShallow('padding');\n        textStyle.textBorderColor = getAutoColor(textStyleModel.getShallow('borderColor'), opt);\n        textStyle.textBorderWidth = textStyleModel.getShallow('borderWidth');\n        textStyle.textBorderRadius = textStyleModel.getShallow('borderRadius');\n\n        textStyle.textBoxShadowColor = textStyleModel.getShallow('shadowColor');\n        textStyle.textBoxShadowBlur = textStyleModel.getShallow('shadowBlur');\n        textStyle.textBoxShadowOffsetX = textStyleModel.getShallow('shadowOffsetX');\n        textStyle.textBoxShadowOffsetY = textStyleModel.getShallow('shadowOffsetY');\n    }\n\n    textStyle.textShadowColor = textStyleModel.getShallow('textShadowColor')\n        || globalTextStyle.textShadowColor;\n    textStyle.textShadowBlur = textStyleModel.getShallow('textShadowBlur')\n        || globalTextStyle.textShadowBlur;\n    textStyle.textShadowOffsetX = textStyleModel.getShallow('textShadowOffsetX')\n        || globalTextStyle.textShadowOffsetX;\n    textStyle.textShadowOffsetY = textStyleModel.getShallow('textShadowOffsetY')\n        || globalTextStyle.textShadowOffsetY;\n}\n\nfunction getAutoColor(color, opt) {\n    return color !== 'auto' ? color : (opt && opt.autoColor) ? opt.autoColor : null;\n}\n\n/**\n * Give some default value to the input `textStyle` object, based on the current settings\n * in this `textStyle` object.\n *\n * The Scenario:\n * when text position is `inside` and `textFill` is not specified, we show\n * text border by default for better view. But it should be considered that text position\n * might be changed when hovering or being emphasis, where the `insideRollback` is used to\n * restore the style.\n *\n * Usage (& NOTICE):\n * When a style object (eithor plain object or instance of `zrender/src/graphic/Style`) is\n * about to be modified on its text related properties, `rollbackDefaultTextStyle` should\n * be called before the modification and `applyDefaultTextStyle` should be called after that.\n * (For the case that all of the text related properties is reset, like `setTextStyleCommon`\n * does, `rollbackDefaultTextStyle` is not needed to be called).\n */\nfunction applyDefaultTextStyle(textStyle) {\n    var opt = textStyle.insideRollbackOpt;\n\n    // Only `insideRollbackOpt` created (in `setTextStyleCommon`),\n    // applyDefaultTextStyle works.\n    if (!opt || textStyle.textFill != null) {\n        return;\n    }\n\n    var useInsideStyle = opt.useInsideStyle;\n    var textPosition = textStyle.insideRawTextPosition;\n    var insideRollback;\n    var autoColor = opt.autoColor;\n\n    if (useInsideStyle !== false\n        && (useInsideStyle === true\n            || (opt.isRectText\n                && textPosition\n                // textPosition can be [10, 30]\n                && typeof textPosition === 'string'\n                && textPosition.indexOf('inside') >= 0\n            )\n        )\n    ) {\n        insideRollback = {\n            textFill: null,\n            textStroke: textStyle.textStroke,\n            textStrokeWidth: textStyle.textStrokeWidth\n        };\n        textStyle.textFill = '#fff';\n        // Consider text with #fff overflow its container.\n        if (textStyle.textStroke == null) {\n            textStyle.textStroke = autoColor;\n            textStyle.textStrokeWidth == null && (textStyle.textStrokeWidth = 2);\n        }\n    }\n    else if (autoColor != null) {\n        insideRollback = {textFill: null};\n        textStyle.textFill = autoColor;\n    }\n\n    // Always set `insideRollback`, for clearing previous.\n    if (insideRollback) {\n        textStyle.insideRollback = insideRollback;\n    }\n}\n\n/**\n * Consider the case: in a scatter,\n * label: {\n *     normal: {position: 'inside'},\n *     emphasis: {position: 'top'}\n * }\n * In the normal state, the `textFill` will be set as '#fff' for pretty view (see\n * `applyDefaultTextStyle`), but when switching to emphasis state, the `textFill`\n * should be retured to 'autoColor', but not keep '#fff'.\n */\nfunction rollbackDefaultTextStyle(style) {\n    var insideRollback = style.insideRollback;\n    if (insideRollback) {\n        style.textFill = insideRollback.textFill;\n        style.textStroke = insideRollback.textStroke;\n        style.textStrokeWidth = insideRollback.textStrokeWidth;\n        style.insideRollback = null;\n    }\n}\n\nfunction getFont(opt, ecModel) {\n    // ecModel or default text style model.\n    var gTextStyleModel = ecModel || ecModel.getModel('textStyle');\n    return trim([\n        // FIXME in node-canvas fontWeight is before fontStyle\n        opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '',\n        opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '',\n        (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px',\n        opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'\n    ].join(' '));\n}\n\nfunction animateOrSetProps(isUpdate, el, props, animatableModel, dataIndex, cb) {\n    if (typeof dataIndex === 'function') {\n        cb = dataIndex;\n        dataIndex = null;\n    }\n    // Do not check 'animation' property directly here. Consider this case:\n    // animation model is an `itemModel`, whose does not have `isAnimationEnabled`\n    // but its parent model (`seriesModel`) does.\n    var animationEnabled = animatableModel && animatableModel.isAnimationEnabled();\n\n    if (animationEnabled) {\n        var postfix = isUpdate ? 'Update' : '';\n        var duration = animatableModel.getShallow('animationDuration' + postfix);\n        var animationEasing = animatableModel.getShallow('animationEasing' + postfix);\n        var animationDelay = animatableModel.getShallow('animationDelay' + postfix);\n        if (typeof animationDelay === 'function') {\n            animationDelay = animationDelay(\n                dataIndex,\n                animatableModel.getAnimationDelayParams\n                    ? animatableModel.getAnimationDelayParams(el, dataIndex)\n                    : null\n            );\n        }\n        if (typeof duration === 'function') {\n            duration = duration(dataIndex);\n        }\n\n        duration > 0\n            ? el.animateTo(props, duration, animationDelay || 0, animationEasing, cb, !!cb)\n            : (el.stopAnimation(), el.attr(props), cb && cb());\n    }\n    else {\n        el.stopAnimation();\n        el.attr(props);\n        cb && cb();\n    }\n}\n\n/**\n * Update graphic element properties with or without animation according to the\n * configuration in series.\n *\n * Caution: this method will stop previous animation.\n * So if do not use this method to one element twice before\n * animation starts, unless you know what you are doing.\n *\n * @param {module:zrender/Element} el\n * @param {Object} props\n * @param {module:echarts/model/Model} [animatableModel]\n * @param {number} [dataIndex]\n * @param {Function} [cb]\n * @example\n *     graphic.updateProps(el, {\n *         position: [100, 100]\n *     }, seriesModel, dataIndex, function () { console.log('Animation done!'); });\n *     // Or\n *     graphic.updateProps(el, {\n *         position: [100, 100]\n *     }, seriesModel, function () { console.log('Animation done!'); });\n */\nfunction updateProps(el, props, animatableModel, dataIndex, cb) {\n    animateOrSetProps(true, el, props, animatableModel, dataIndex, cb);\n}\n\n/**\n * Init graphic element properties with or without animation according to the\n * configuration in series.\n *\n * Caution: this method will stop previous animation.\n * So if do not use this method to one element twice before\n * animation starts, unless you know what you are doing.\n *\n * @param {module:zrender/Element} el\n * @param {Object} props\n * @param {module:echarts/model/Model} [animatableModel]\n * @param {number} [dataIndex]\n * @param {Function} cb\n */\nfunction initProps(el, props, animatableModel, dataIndex, cb) {\n    animateOrSetProps(false, el, props, animatableModel, dataIndex, cb);\n}\n\n/**\n * Get transform matrix of target (param target),\n * in coordinate of its ancestor (param ancestor)\n *\n * @param {module:zrender/mixin/Transformable} target\n * @param {module:zrender/mixin/Transformable} [ancestor]\n */\nfunction getTransform(target, ancestor) {\n    var mat = identity([]);\n\n    while (target && target !== ancestor) {\n        mul$1(mat, target.getLocalTransform(), mat);\n        target = target.parent;\n    }\n\n    return mat;\n}\n\n/**\n * Apply transform to an vertex.\n * @param {Array.<number>} target [x, y]\n * @param {Array.<number>|TypedArray.<number>|Object} transform Can be:\n *      + Transform matrix: like [1, 0, 0, 1, 0, 0]\n *      + {position, rotation, scale}, the same as `zrender/Transformable`.\n * @param {boolean=} invert Whether use invert matrix.\n * @return {Array.<number>} [x, y]\n */\nfunction applyTransform$1(target, transform, invert$$1) {\n    if (transform && !isArrayLike(transform)) {\n        transform = Transformable.getLocalTransform(transform);\n    }\n\n    if (invert$$1) {\n        transform = invert([], transform);\n    }\n    return applyTransform([], target, transform);\n}\n\n/**\n * @param {string} direction 'left' 'right' 'top' 'bottom'\n * @param {Array.<number>} transform Transform matrix: like [1, 0, 0, 1, 0, 0]\n * @param {boolean=} invert Whether use invert matrix.\n * @return {string} Transformed direction. 'left' 'right' 'top' 'bottom'\n */\nfunction transformDirection(direction, transform, invert$$1) {\n\n    // Pick a base, ensure that transform result will not be (0, 0).\n    var hBase = (transform[4] === 0 || transform[5] === 0 || transform[0] === 0)\n        ? 1 : Math.abs(2 * transform[4] / transform[0]);\n    var vBase = (transform[4] === 0 || transform[5] === 0 || transform[2] === 0)\n        ? 1 : Math.abs(2 * transform[4] / transform[2]);\n\n    var vertex = [\n        direction === 'left' ? -hBase : direction === 'right' ? hBase : 0,\n        direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0\n    ];\n\n    vertex = applyTransform$1(vertex, transform, invert$$1);\n\n    return Math.abs(vertex[0]) > Math.abs(vertex[1])\n        ? (vertex[0] > 0 ? 'right' : 'left')\n        : (vertex[1] > 0 ? 'bottom' : 'top');\n}\n\n/**\n * Apply group transition animation from g1 to g2.\n * If no animatableModel, no animation.\n */\nfunction groupTransition(g1, g2, animatableModel, cb) {\n    if (!g1 || !g2) {\n        return;\n    }\n\n    function getElMap(g) {\n        var elMap = {};\n        g.traverse(function (el) {\n            if (!el.isGroup && el.anid) {\n                elMap[el.anid] = el;\n            }\n        });\n        return elMap;\n    }\n    function getAnimatableProps(el) {\n        var obj = {\n            position: clone$1(el.position),\n            rotation: el.rotation\n        };\n        if (el.shape) {\n            obj.shape = extend({}, el.shape);\n        }\n        return obj;\n    }\n    var elMap1 = getElMap(g1);\n\n    g2.traverse(function (el) {\n        if (!el.isGroup && el.anid) {\n            var oldEl = elMap1[el.anid];\n            if (oldEl) {\n                var newProp = getAnimatableProps(el);\n                el.attr(getAnimatableProps(oldEl));\n                updateProps(el, newProp, animatableModel, el.dataIndex);\n            }\n            // else {\n            //     if (el.previousProps) {\n            //         graphic.updateProps\n            //     }\n            // }\n        }\n    });\n}\n\n/**\n * @param {Array.<Array.<number>>} points Like: [[23, 44], [53, 66], ...]\n * @param {Object} rect {x, y, width, height}\n * @return {Array.<Array.<number>>} A new clipped points.\n */\nfunction clipPointsByRect(points, rect) {\n    // FIXME: this way migth be incorrect when grpahic clipped by a corner.\n    // and when element have border.\n    return map(points, function (point) {\n        var x = point[0];\n        x = mathMax$1(x, rect.x);\n        x = mathMin$1(x, rect.x + rect.width);\n        var y = point[1];\n        y = mathMax$1(y, rect.y);\n        y = mathMin$1(y, rect.y + rect.height);\n        return [x, y];\n    });\n}\n\n/**\n * @param {Object} targetRect {x, y, width, height}\n * @param {Object} rect {x, y, width, height}\n * @return {Object} A new clipped rect. If rect size are negative, return undefined.\n */\nfunction clipRectByRect(targetRect, rect) {\n    var x = mathMax$1(targetRect.x, rect.x);\n    var x2 = mathMin$1(targetRect.x + targetRect.width, rect.x + rect.width);\n    var y = mathMax$1(targetRect.y, rect.y);\n    var y2 = mathMin$1(targetRect.y + targetRect.height, rect.y + rect.height);\n\n    // If the total rect is cliped, nothing, including the border,\n    // should be painted. So return undefined.\n    if (x2 >= x && y2 >= y) {\n        return {\n            x: x,\n            y: y,\n            width: x2 - x,\n            height: y2 - y\n        };\n    }\n}\n\n/**\n * @param {string} iconStr Support 'image://' or 'path://' or direct svg path.\n * @param {Object} [opt] Properties of `module:zrender/Element`, except `style`.\n * @param {Object} [rect] {x, y, width, height}\n * @return {module:zrender/Element} Icon path or image element.\n */\nfunction createIcon(iconStr, opt, rect) {\n    opt = extend({rectHover: true}, opt);\n    var style = opt.style = {strokeNoScale: true};\n    rect = rect || {x: -1, y: -1, width: 2, height: 2};\n\n    if (iconStr) {\n        return iconStr.indexOf('image://') === 0\n            ? (\n                style.image = iconStr.slice(8),\n                defaults(style, rect),\n                new ZImage(opt)\n            )\n            : (\n                makePath(\n                    iconStr.replace('path://', ''),\n                    opt,\n                    rect,\n                    'center'\n                )\n            );\n    }\n}\n\n\n\n\nvar graphic = (Object.freeze || Object)({\n\tZ2_EMPHASIS_LIFT: Z2_EMPHASIS_LIFT,\n\textendShape: extendShape,\n\textendPath: extendPath,\n\tmakePath: makePath,\n\tmakeImage: makeImage,\n\tmergePath: mergePath,\n\tresizePath: resizePath,\n\tsubPixelOptimizeLine: subPixelOptimizeLine,\n\tsubPixelOptimizeRect: subPixelOptimizeRect,\n\tsubPixelOptimize: subPixelOptimize,\n\tsetElementHoverStyle: setElementHoverStyle,\n\tisInEmphasis: isInEmphasis,\n\tsetHoverStyle: setHoverStyle,\n\tsetAsHoverStyleTrigger: setAsHoverStyleTrigger,\n\tsetLabelStyle: setLabelStyle,\n\tsetTextStyle: setTextStyle,\n\tsetText: setText,\n\tgetFont: getFont,\n\tupdateProps: updateProps,\n\tinitProps: initProps,\n\tgetTransform: getTransform,\n\tapplyTransform: applyTransform$1,\n\ttransformDirection: transformDirection,\n\tgroupTransition: groupTransition,\n\tclipPointsByRect: clipPointsByRect,\n\tclipRectByRect: clipRectByRect,\n\tcreateIcon: createIcon,\n\tGroup: Group,\n\tImage: ZImage,\n\tText: Text,\n\tCircle: Circle,\n\tSector: Sector,\n\tRing: Ring,\n\tPolygon: Polygon,\n\tPolyline: Polyline,\n\tRect: Rect,\n\tLine: Line,\n\tBezierCurve: BezierCurve,\n\tArc: Arc,\n\tIncrementalDisplayable: IncrementalDisplayble,\n\tCompoundPath: CompoundPath,\n\tLinearGradient: LinearGradient,\n\tRadialGradient: RadialGradient,\n\tBoundingRect: BoundingRect\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PATH_COLOR = ['textStyle', 'color'];\n\nvar textStyleMixin = {\n    /**\n     * Get color property or get color from option.textStyle.color\n     * @param {boolean} [isEmphasis]\n     * @return {string}\n     */\n    getTextColor: function (isEmphasis) {\n        var ecModel = this.ecModel;\n        return this.getShallow('color')\n            || (\n                (!isEmphasis && ecModel) ? ecModel.get(PATH_COLOR) : null\n            );\n    },\n\n    /**\n     * Create font string from fontStyle, fontWeight, fontSize, fontFamily\n     * @return {string}\n     */\n    getFont: function () {\n        return getFont({\n            fontStyle: this.getShallow('fontStyle'),\n            fontWeight: this.getShallow('fontWeight'),\n            fontSize: this.getShallow('fontSize'),\n            fontFamily: this.getShallow('fontFamily')\n        }, this.ecModel);\n    },\n\n    getTextRect: function (text) {\n        return getBoundingRect(\n            text,\n            this.getFont(),\n            this.getShallow('align'),\n            this.getShallow('verticalAlign') || this.getShallow('baseline'),\n            this.getShallow('padding'),\n            this.getShallow('lineHeight'),\n            this.getShallow('rich'),\n            this.getShallow('truncateText')\n        );\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getItemStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['stroke', 'borderColor'],\n        ['lineWidth', 'borderWidth'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor'],\n        ['textPosition'],\n        ['textAlign']\n    ]\n);\n\nvar itemStyleMixin = {\n    getItemStyle: function (excludes, includes) {\n        var style = getItemStyle(this, excludes, includes);\n        var lineDash = this.getBorderLineDash();\n        lineDash && (style.lineDash = lineDash);\n        return style;\n    },\n\n    getBorderLineDash: function () {\n        var lineType = this.get('borderType');\n        return (lineType === 'solid' || lineType == null) ? null\n            : (lineType === 'dashed' ? [5, 5] : [1, 1]);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/model/Model\n */\n\nvar mixin$1 = mixin;\nvar inner = makeInner();\n\n/**\n * @alias module:echarts/model/Model\n * @constructor\n * @param {Object} [option]\n * @param {module:echarts/model/Model} [parentModel]\n * @param {module:echarts/model/Global} [ecModel]\n */\nfunction Model(option, parentModel, ecModel) {\n    /**\n     * @type {module:echarts/model/Model}\n     * @readOnly\n     */\n    this.parentModel = parentModel;\n\n    /**\n     * @type {module:echarts/model/Global}\n     * @readOnly\n     */\n    this.ecModel = ecModel;\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    this.option = option;\n\n    // Simple optimization\n    // if (this.init) {\n    //     if (arguments.length <= 4) {\n    //         this.init(option, parentModel, ecModel, extraOpt);\n    //     }\n    //     else {\n    //         this.init.apply(this, arguments);\n    //     }\n    // }\n}\n\nModel.prototype = {\n\n    constructor: Model,\n\n    /**\n     * Model 的初始化函数\n     * @param {Object} option\n     */\n    init: null,\n\n    /**\n     * 从新的 Option merge\n     */\n    mergeOption: function (option) {\n        merge(this.option, option, true);\n    },\n\n    /**\n     * @param {string|Array.<string>} path\n     * @param {boolean} [ignoreParent=false]\n     * @return {*}\n     */\n    get: function (path, ignoreParent) {\n        if (path == null) {\n            return this.option;\n        }\n\n        return doGet(\n            this.option,\n            this.parsePath(path),\n            !ignoreParent && getParent(this, path)\n        );\n    },\n\n    /**\n     * @param {string} key\n     * @param {boolean} [ignoreParent=false]\n     * @return {*}\n     */\n    getShallow: function (key, ignoreParent) {\n        var option = this.option;\n\n        var val = option == null ? option : option[key];\n        var parentModel = !ignoreParent && getParent(this, key);\n        if (val == null && parentModel) {\n            val = parentModel.getShallow(key);\n        }\n        return val;\n    },\n\n    /**\n     * @param {string|Array.<string>} [path]\n     * @param {module:echarts/model/Model} [parentModel]\n     * @return {module:echarts/model/Model}\n     */\n    getModel: function (path, parentModel) {\n        var obj = path == null\n            ? this.option\n            : doGet(this.option, path = this.parsePath(path));\n\n        var thisParentModel;\n        parentModel = parentModel || (\n            (thisParentModel = getParent(this, path))\n                && thisParentModel.getModel(path)\n        );\n\n        return new Model(obj, parentModel, this.ecModel);\n    },\n\n    /**\n     * If model has option\n     */\n    isEmpty: function () {\n        return this.option == null;\n    },\n\n    restoreData: function () {},\n\n    // Pending\n    clone: function () {\n        var Ctor = this.constructor;\n        return new Ctor(clone(this.option));\n    },\n\n    setReadOnly: function (properties) {\n        // clazzUtil.setReadOnly(this, properties);\n    },\n\n    // If path is null/undefined, return null/undefined.\n    parsePath: function (path) {\n        if (typeof path === 'string') {\n            path = path.split('.');\n        }\n        return path;\n    },\n\n    /**\n     * @param {Function} getParentMethod\n     *        param {Array.<string>|string} path\n     *        return {module:echarts/model/Model}\n     */\n    customizeGetParent: function (getParentMethod) {\n        inner(this).getParent = getParentMethod;\n    },\n\n    isAnimationEnabled: function () {\n        if (!env$1.node) {\n            if (this.option.animation != null) {\n                return !!this.option.animation;\n            }\n            else if (this.parentModel) {\n                return this.parentModel.isAnimationEnabled();\n            }\n        }\n    }\n\n};\n\nfunction doGet(obj, pathArr, parentModel) {\n    for (var i = 0; i < pathArr.length; i++) {\n        // Ignore empty\n        if (!pathArr[i]) {\n            continue;\n        }\n        // obj could be number/string/... (like 0)\n        obj = (obj && typeof obj === 'object') ? obj[pathArr[i]] : null;\n        if (obj == null) {\n            break;\n        }\n    }\n    if (obj == null && parentModel) {\n        obj = parentModel.get(pathArr);\n    }\n    return obj;\n}\n\n// `path` can be null/undefined\nfunction getParent(model, path) {\n    var getParentMethod = inner(model).getParent;\n    return getParentMethod ? getParentMethod.call(model, path) : model.parentModel;\n}\n\n// Enable Model.extend.\nenableClassExtend(Model);\nenableClassCheck(Model);\n\nmixin$1(Model, lineStyleMixin);\nmixin$1(Model, areaStyleMixin);\nmixin$1(Model, textStyleMixin);\nmixin$1(Model, itemStyleMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar base = 0;\n\n/**\n * @public\n * @param {string} type\n * @return {string}\n */\nfunction getUID(type) {\n    // Considering the case of crossing js context,\n    // use Math.random to make id as unique as possible.\n    return [(type || ''), base++, Math.random().toFixed(5)].join('_');\n}\n\n/**\n * @inner\n */\nfunction enableSubTypeDefaulter(entity) {\n\n    var subTypeDefaulters = {};\n\n    entity.registerSubTypeDefaulter = function (componentType, defaulter) {\n        componentType = parseClassType$1(componentType);\n        subTypeDefaulters[componentType.main] = defaulter;\n    };\n\n    entity.determineSubType = function (componentType, option) {\n        var type = option.type;\n        if (!type) {\n            var componentTypeMain = parseClassType$1(componentType).main;\n            if (entity.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) {\n                type = subTypeDefaulters[componentTypeMain](option);\n            }\n        }\n        return type;\n    };\n\n    return entity;\n}\n\n/**\n * Topological travel on Activity Network (Activity On Vertices).\n * Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis'].\n *\n * If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology.\n *\n * If there is circle dependencey, Error will be thrown.\n *\n */\nfunction enableTopologicalTravel(entity, dependencyGetter) {\n\n    /**\n     * @public\n     * @param {Array.<string>} targetNameList Target Component type list.\n     *                                           Can be ['aa', 'bb', 'aa.xx']\n     * @param {Array.<string>} fullNameList By which we can build dependency graph.\n     * @param {Function} callback Params: componentType, dependencies.\n     * @param {Object} context Scope of callback.\n     */\n    entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) {\n        if (!targetNameList.length) {\n            return;\n        }\n\n        var result = makeDepndencyGraph(fullNameList);\n        var graph = result.graph;\n        var stack = result.noEntryList;\n\n        var targetNameSet = {};\n        each$1(targetNameList, function (name) {\n            targetNameSet[name] = true;\n        });\n\n        while (stack.length) {\n            var currComponentType = stack.pop();\n            var currVertex = graph[currComponentType];\n            var isInTargetNameSet = !!targetNameSet[currComponentType];\n            if (isInTargetNameSet) {\n                callback.call(context, currComponentType, currVertex.originalDeps.slice());\n                delete targetNameSet[currComponentType];\n            }\n            each$1(\n                currVertex.successor,\n                isInTargetNameSet ? removeEdgeAndAdd : removeEdge\n            );\n        }\n\n        each$1(targetNameSet, function () {\n            throw new Error('Circle dependency may exists');\n        });\n\n        function removeEdge(succComponentType) {\n            graph[succComponentType].entryCount--;\n            if (graph[succComponentType].entryCount === 0) {\n                stack.push(succComponentType);\n            }\n        }\n\n        // Consider this case: legend depends on series, and we call\n        // chart.setOption({series: [...]}), where only series is in option.\n        // If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will\n        // not be called, but only sereis.mergeOption is called. Thus legend\n        // have no chance to update its local record about series (like which\n        // name of series is available in legend).\n        function removeEdgeAndAdd(succComponentType) {\n            targetNameSet[succComponentType] = true;\n            removeEdge(succComponentType);\n        }\n    };\n\n    /**\n     * DepndencyGraph: {Object}\n     * key: conponentType,\n     * value: {\n     *     successor: [conponentTypes...],\n     *     originalDeps: [conponentTypes...],\n     *     entryCount: {number}\n     * }\n     */\n    function makeDepndencyGraph(fullNameList) {\n        var graph = {};\n        var noEntryList = [];\n\n        each$1(fullNameList, function (name) {\n\n            var thisItem = createDependencyGraphItem(graph, name);\n            var originalDeps = thisItem.originalDeps = dependencyGetter(name);\n\n            var availableDeps = getAvailableDependencies(originalDeps, fullNameList);\n            thisItem.entryCount = availableDeps.length;\n            if (thisItem.entryCount === 0) {\n                noEntryList.push(name);\n            }\n\n            each$1(availableDeps, function (dependentName) {\n                if (indexOf(thisItem.predecessor, dependentName) < 0) {\n                    thisItem.predecessor.push(dependentName);\n                }\n                var thatItem = createDependencyGraphItem(graph, dependentName);\n                if (indexOf(thatItem.successor, dependentName) < 0) {\n                    thatItem.successor.push(name);\n                }\n            });\n        });\n\n        return {graph: graph, noEntryList: noEntryList};\n    }\n\n    function createDependencyGraphItem(graph, name) {\n        if (!graph[name]) {\n            graph[name] = {predecessor: [], successor: []};\n        }\n        return graph[name];\n    }\n\n    function getAvailableDependencies(originalDeps, fullNameList) {\n        var availableDeps = [];\n        each$1(originalDeps, function (dep) {\n            indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep);\n        });\n        return availableDeps;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The method \"quantile\" was copied from \"d3.js\".\n* (See more details in the comment of the method below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\nvar RADIAN_EPSILON = 1e-4;\n\nfunction _trim(str) {\n    return str.replace(/^\\s+/, '').replace(/\\s+$/, '');\n}\n\n/**\n * Linear mapping a value from domain to range\n * @memberOf module:echarts/util/number\n * @param  {(number|Array.<number>)} val\n * @param  {Array.<number>} domain Domain extent domain[0] can be bigger than domain[1]\n * @param  {Array.<number>} range  Range extent range[0] can be bigger than range[1]\n * @param  {boolean} clamp\n * @return {(number|Array.<number>}\n */\nfunction linearMap(val, domain, range, clamp) {\n    var subDomain = domain[1] - domain[0];\n    var subRange = range[1] - range[0];\n\n    if (subDomain === 0) {\n        return subRange === 0\n            ? range[0]\n            : (range[0] + range[1]) / 2;\n    }\n\n    // Avoid accuracy problem in edge, such as\n    // 146.39 - 62.83 === 83.55999999999999.\n    // See echarts/test/ut/spec/util/number.js#linearMap#accuracyError\n    // It is a little verbose for efficiency considering this method\n    // is a hotspot.\n    if (clamp) {\n        if (subDomain > 0) {\n            if (val <= domain[0]) {\n                return range[0];\n            }\n            else if (val >= domain[1]) {\n                return range[1];\n            }\n        }\n        else {\n            if (val >= domain[0]) {\n                return range[0];\n            }\n            else if (val <= domain[1]) {\n                return range[1];\n            }\n        }\n    }\n    else {\n        if (val === domain[0]) {\n            return range[0];\n        }\n        if (val === domain[1]) {\n            return range[1];\n        }\n    }\n\n    return (val - domain[0]) / subDomain * subRange + range[0];\n}\n\n/**\n * Convert a percent string to absolute number.\n * Returns NaN if percent is not a valid string or number\n * @memberOf module:echarts/util/number\n * @param {string|number} percent\n * @param {number} all\n * @return {number}\n */\nfunction parsePercent$1(percent, all) {\n    switch (percent) {\n        case 'center':\n        case 'middle':\n            percent = '50%';\n            break;\n        case 'left':\n        case 'top':\n            percent = '0%';\n            break;\n        case 'right':\n        case 'bottom':\n            percent = '100%';\n            break;\n    }\n    if (typeof percent === 'string') {\n        if (_trim(percent).match(/%$/)) {\n            return parseFloat(percent) / 100 * all;\n        }\n\n        return parseFloat(percent);\n    }\n\n    return percent == null ? NaN : +percent;\n}\n\n/**\n * (1) Fix rounding error of float numbers.\n * (2) Support return string to avoid scientific notation like '3.5e-7'.\n *\n * @param {number} x\n * @param {number} [precision]\n * @param {boolean} [returnStr]\n * @return {number|string}\n */\nfunction round$2(x, precision, returnStr) {\n    if (precision == null) {\n        precision = 10;\n    }\n    // Avoid range error\n    precision = Math.min(Math.max(0, precision), 20);\n    x = (+x).toFixed(precision);\n    return returnStr ? x : +x;\n}\n\nfunction asc(arr) {\n    arr.sort(function (a, b) {\n        return a - b;\n    });\n    return arr;\n}\n\n/**\n * Get precision\n * @param {number} val\n */\nfunction getPrecision(val) {\n    val = +val;\n    if (isNaN(val)) {\n        return 0;\n    }\n    // It is much faster than methods converting number to string as follows\n    //      var tmp = val.toString();\n    //      return tmp.length - 1 - tmp.indexOf('.');\n    // especially when precision is low\n    var e = 1;\n    var count = 0;\n    while (Math.round(val * e) / e !== val) {\n        e *= 10;\n        count++;\n    }\n    return count;\n}\n\n/**\n * @param {string|number} val\n * @return {number}\n */\nfunction getPrecisionSafe(val) {\n    var str = val.toString();\n\n    // Consider scientific notation: '3.4e-12' '3.4e+12'\n    var eIndex = str.indexOf('e');\n    if (eIndex > 0) {\n        var precision = +str.slice(eIndex + 1);\n        return precision < 0 ? -precision : 0;\n    }\n    else {\n        var dotIndex = str.indexOf('.');\n        return dotIndex < 0 ? 0 : str.length - 1 - dotIndex;\n    }\n}\n\n/**\n * Minimal dicernible data precisioin according to a single pixel.\n *\n * @param {Array.<number>} dataExtent\n * @param {Array.<number>} pixelExtent\n * @return {number} precision\n */\nfunction getPixelPrecision(dataExtent, pixelExtent) {\n    var log = Math.log;\n    var LN10 = Math.LN10;\n    var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10);\n    var sizeQuantity = Math.round(log(Math.abs(pixelExtent[1] - pixelExtent[0])) / LN10);\n    // toFixed() digits argument must be between 0 and 20.\n    var precision = Math.min(Math.max(-dataQuantity + sizeQuantity, 0), 20);\n    return !isFinite(precision) ? 20 : precision;\n}\n\n/**\n * Get a data of given precision, assuring the sum of percentages\n * in valueList is 1.\n * The largest remainer method is used.\n * https://en.wikipedia.org/wiki/Largest_remainder_method\n *\n * @param {Array.<number>} valueList a list of all data\n * @param {number} idx index of the data to be processed in valueList\n * @param {number} precision integer number showing digits of precision\n * @return {number} percent ranging from 0 to 100\n */\nfunction getPercentWithPrecision(valueList, idx, precision) {\n    if (!valueList[idx]) {\n        return 0;\n    }\n\n    var sum = reduce(valueList, function (acc, val) {\n        return acc + (isNaN(val) ? 0 : val);\n    }, 0);\n    if (sum === 0) {\n        return 0;\n    }\n\n    var digits = Math.pow(10, precision);\n    var votesPerQuota = map(valueList, function (val) {\n        return (isNaN(val) ? 0 : val) / sum * digits * 100;\n    });\n    var targetSeats = digits * 100;\n\n    var seats = map(votesPerQuota, function (votes) {\n        // Assign automatic seats.\n        return Math.floor(votes);\n    });\n    var currentSum = reduce(seats, function (acc, val) {\n        return acc + val;\n    }, 0);\n\n    var remainder = map(votesPerQuota, function (votes, idx) {\n        return votes - seats[idx];\n    });\n\n    // Has remainding votes.\n    while (currentSum < targetSeats) {\n        // Find next largest remainder.\n        var max = Number.NEGATIVE_INFINITY;\n        var maxId = null;\n        for (var i = 0, len = remainder.length; i < len; ++i) {\n            if (remainder[i] > max) {\n                max = remainder[i];\n                maxId = i;\n            }\n        }\n\n        // Add a vote to max remainder.\n        ++seats[maxId];\n        remainder[maxId] = 0;\n        ++currentSum;\n    }\n\n    return seats[idx] / digits;\n}\n\n// Number.MAX_SAFE_INTEGER, ie do not support.\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * To 0 - 2 * PI, considering negative radian.\n * @param {number} radian\n * @return {number}\n */\nfunction remRadian(radian) {\n    var pi2 = Math.PI * 2;\n    return (radian % pi2 + pi2) % pi2;\n}\n\n/**\n * @param {type} radian\n * @return {boolean}\n */\nfunction isRadianAroundZero(val) {\n    return val > -RADIAN_EPSILON && val < RADIAN_EPSILON;\n}\n\n/* eslint-disable */\nvar TIME_REG = /^(?:(\\d{4})(?:[-\\/](\\d{1,2})(?:[-\\/](\\d{1,2})(?:[T ](\\d{1,2})(?::(\\d\\d)(?::(\\d\\d)(?:[.,](\\d+))?)?)?(Z|[\\+\\-]\\d\\d:?\\d\\d)?)?)?)?)?$/; // jshint ignore:line\n/* eslint-enable */\n\n/**\n * @param {string|Date|number} value These values can be accepted:\n *   + An instance of Date, represent a time in its own time zone.\n *   + Or string in a subset of ISO 8601, only including:\n *     + only year, month, date: '2012-03', '2012-03-01', '2012-03-01 05', '2012-03-01 05:06',\n *     + separated with T or space: '2012-03-01T12:22:33.123', '2012-03-01 12:22:33.123',\n *     + time zone: '2012-03-01T12:22:33Z', '2012-03-01T12:22:33+8000', '2012-03-01T12:22:33-05:00',\n *     all of which will be treated as local time if time zone is not specified\n *     (see <https://momentjs.com/>).\n *   + Or other string format, including (all of which will be treated as loacal time):\n *     '2012', '2012-3-1', '2012/3/1', '2012/03/01',\n *     '2009/6/12 2:00', '2009/6/12 2:05:08', '2009/6/12 2:05:08.123'\n *   + a timestamp, which represent a time in UTC.\n * @return {Date} date\n */\nfunction parseDate(value) {\n    if (value instanceof Date) {\n        return value;\n    }\n    else if (typeof value === 'string') {\n        // Different browsers parse date in different way, so we parse it manually.\n        // Some other issues:\n        // new Date('1970-01-01') is UTC,\n        // new Date('1970/01/01') and new Date('1970-1-01') is local.\n        // See issue #3623\n        var match = TIME_REG.exec(value);\n\n        if (!match) {\n            // return Invalid Date.\n            return new Date(NaN);\n        }\n\n        // Use local time when no timezone offset specifed.\n        if (!match[8]) {\n            // match[n] can only be string or undefined.\n            // But take care of '12' + 1 => '121'.\n            return new Date(\n                +match[1],\n                +(match[2] || 1) - 1,\n                +match[3] || 1,\n                +match[4] || 0,\n                +(match[5] || 0),\n                +match[6] || 0,\n                +match[7] || 0\n            );\n        }\n        // Timezoneoffset of Javascript Date has considered DST (Daylight Saving Time,\n        // https://tc39.github.io/ecma262/#sec-daylight-saving-time-adjustment).\n        // For example, system timezone is set as \"Time Zone: America/Toronto\",\n        // then these code will get different result:\n        // `new Date(1478411999999).getTimezoneOffset();  // get 240`\n        // `new Date(1478412000000).getTimezoneOffset();  // get 300`\n        // So we should not use `new Date`, but use `Date.UTC`.\n        else {\n            var hour = +match[4] || 0;\n            if (match[8].toUpperCase() !== 'Z') {\n                hour -= match[8].slice(0, 3);\n            }\n            return new Date(Date.UTC(\n                +match[1],\n                +(match[2] || 1) - 1,\n                +match[3] || 1,\n                hour,\n                +(match[5] || 0),\n                +match[6] || 0,\n                +match[7] || 0\n            ));\n        }\n    }\n    else if (value == null) {\n        return new Date(NaN);\n    }\n\n    return new Date(Math.round(value));\n}\n\n/**\n * Quantity of a number. e.g. 0.1, 1, 10, 100\n *\n * @param  {number} val\n * @return {number}\n */\nfunction quantity(val) {\n    return Math.pow(10, quantityExponent(val));\n}\n\nfunction quantityExponent(val) {\n    return Math.floor(Math.log(val) / Math.LN10);\n}\n\n/**\n * find a “nice” number approximately equal to x. Round the number if round = true,\n * take ceiling if round = false. The primary observation is that the “nicest”\n * numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers.\n *\n * See \"Nice Numbers for Graph Labels\" of Graphic Gems.\n *\n * @param  {number} val Non-negative value.\n * @param  {boolean} round\n * @return {number}\n */\nfunction nice(val, round) {\n    var exponent = quantityExponent(val);\n    var exp10 = Math.pow(10, exponent);\n    var f = val / exp10; // 1 <= f < 10\n    var nf;\n    if (round) {\n        if (f < 1.5) {\n            nf = 1;\n        }\n        else if (f < 2.5) {\n            nf = 2;\n        }\n        else if (f < 4) {\n            nf = 3;\n        }\n        else if (f < 7) {\n            nf = 5;\n        }\n        else {\n            nf = 10;\n        }\n    }\n    else {\n        if (f < 1) {\n            nf = 1;\n        }\n        else if (f < 2) {\n            nf = 2;\n        }\n        else if (f < 3) {\n            nf = 3;\n        }\n        else if (f < 5) {\n            nf = 5;\n        }\n        else {\n            nf = 10;\n        }\n    }\n    val = nf * exp10;\n\n    // Fix 3 * 0.1 === 0.30000000000000004 issue (see IEEE 754).\n    // 20 is the uppper bound of toFixed.\n    return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val;\n}\n\n/**\n * This code was copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/9cc9a875e636a1dcf36cc1e07bdf77e1ad6e2c74/src/arrays/quantile.js>.\n * See the license statement at the head of this file.\n * @param {Array.<number>} ascArr\n */\nfunction quantile(ascArr, p) {\n    var H = (ascArr.length - 1) * p + 1;\n    var h = Math.floor(H);\n    var v = +ascArr[h - 1];\n    var e = H - h;\n    return e ? v + e * (ascArr[h] - v) : v;\n}\n\n/**\n * Order intervals asc, and split them when overlap.\n * expect(numberUtil.reformIntervals([\n *     {interval: [18, 62], close: [1, 1]},\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [1, 1]},\n *     {interval: [62, 150], close: [1, 1]},\n *     {interval: [106, 150], close: [1, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ])).toEqual([\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [0, 1]},\n *     {interval: [18, 62], close: [0, 1]},\n *     {interval: [62, 150], close: [0, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ]);\n * @param {Array.<Object>} list, where `close` mean open or close\n *        of the interval, and Infinity can be used.\n * @return {Array.<Object>} The origin list, which has been reformed.\n */\nfunction reformIntervals(list) {\n    list.sort(function (a, b) {\n        return littleThan(a, b, 0) ? -1 : 1;\n    });\n\n    var curr = -Infinity;\n    var currClose = 1;\n    for (var i = 0; i < list.length;) {\n        var interval = list[i].interval;\n        var close = list[i].close;\n\n        for (var lg = 0; lg < 2; lg++) {\n            if (interval[lg] <= curr) {\n                interval[lg] = curr;\n                close[lg] = !lg ? 1 - currClose : 1;\n            }\n            curr = interval[lg];\n            currClose = close[lg];\n        }\n\n        if (interval[0] === interval[1] && close[0] * close[1] !== 1) {\n            list.splice(i, 1);\n        }\n        else {\n            i++;\n        }\n    }\n\n    return list;\n\n    function littleThan(a, b, lg) {\n        return a.interval[lg] < b.interval[lg]\n            || (\n                a.interval[lg] === b.interval[lg]\n                && (\n                    (a.close[lg] - b.close[lg] === (!lg ? 1 : -1))\n                    || (!lg && littleThan(a, b, 1))\n                )\n            );\n    }\n}\n\n/**\n * parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n * ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n * subtraction forces infinities to NaN\n *\n * @param {*} v\n * @return {boolean}\n */\nfunction isNumeric(v) {\n    return v - parseFloat(v) >= 0;\n}\n\n\nvar number = (Object.freeze || Object)({\n\tlinearMap: linearMap,\n\tparsePercent: parsePercent$1,\n\tround: round$2,\n\tasc: asc,\n\tgetPrecision: getPrecision,\n\tgetPrecisionSafe: getPrecisionSafe,\n\tgetPixelPrecision: getPixelPrecision,\n\tgetPercentWithPrecision: getPercentWithPrecision,\n\tMAX_SAFE_INTEGER: MAX_SAFE_INTEGER,\n\tremRadian: remRadian,\n\tisRadianAroundZero: isRadianAroundZero,\n\tparseDate: parseDate,\n\tquantity: quantity,\n\tnice: nice,\n\tquantile: quantile,\n\treformIntervals: reformIntervals,\n\tisNumeric: isNumeric\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import Text from 'zrender/src/graphic/Text';\n\n/**\n * 每三位默认加,格式化\n * @param {string|number} x\n * @return {string}\n */\nfunction addCommas(x) {\n    if (isNaN(x)) {\n        return '-';\n    }\n    x = (x + '').split('.');\n    return x[0].replace(/(\\d{1,3})(?=(?:\\d{3})+(?!\\d))/g, '$1,')\n            + (x.length > 1 ? ('.' + x[1]) : '');\n}\n\n/**\n * @param {string} str\n * @param {boolean} [upperCaseFirst=false]\n * @return {string} str\n */\nfunction toCamelCase(str, upperCaseFirst) {\n    str = (str || '').toLowerCase().replace(/-(.)/g, function (match, group1) {\n        return group1.toUpperCase();\n    });\n\n    if (upperCaseFirst && str) {\n        str = str.charAt(0).toUpperCase() + str.slice(1);\n    }\n\n    return str;\n}\n\nvar normalizeCssArray$1 = normalizeCssArray;\n\n\nvar replaceReg = /([&<>\"'])/g;\nvar replaceMap = {\n    '&': '&amp;',\n    '<': '&lt;',\n    '>': '&gt;',\n    '\"': '&quot;',\n    '\\'': '&#39;'\n};\n\nfunction encodeHTML(source) {\n    return source == null\n        ? ''\n        : (source + '').replace(replaceReg, function (str, c) {\n            return replaceMap[c];\n        });\n}\n\nvar TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];\n\nvar wrapVar = function (varName, seriesIdx) {\n    return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}';\n};\n\n/**\n * Template formatter\n * @param {string} tpl\n * @param {Array.<Object>|Object} paramsList\n * @param {boolean} [encode=false]\n * @return {string}\n */\nfunction formatTpl(tpl, paramsList, encode) {\n    if (!isArray(paramsList)) {\n        paramsList = [paramsList];\n    }\n    var seriesLen = paramsList.length;\n    if (!seriesLen) {\n        return '';\n    }\n\n    var $vars = paramsList[0].$vars || [];\n    for (var i = 0; i < $vars.length; i++) {\n        var alias = TPL_VAR_ALIAS[i];\n        tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0));\n    }\n    for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) {\n        for (var k = 0; k < $vars.length; k++) {\n            var val = paramsList[seriesIdx][$vars[k]];\n            tpl = tpl.replace(\n                wrapVar(TPL_VAR_ALIAS[k], seriesIdx),\n                encode ? encodeHTML(val) : val\n            );\n        }\n    }\n\n    return tpl;\n}\n\n/**\n * simple Template formatter\n *\n * @param {string} tpl\n * @param {Object} param\n * @param {boolean} [encode=false]\n * @return {string}\n */\nfunction formatTplSimple(tpl, param, encode) {\n    each$1(param, function (value, key) {\n        tpl = tpl.replace(\n            '{' + key + '}',\n            encode ? encodeHTML(value) : value\n        );\n    });\n    return tpl;\n}\n\n/**\n * @param {Object|string} [opt] If string, means color.\n * @param {string} [opt.color]\n * @param {string} [opt.extraCssText]\n * @param {string} [opt.type='item'] 'item' or 'subItem'\n * @param {string} [opt.renderMode='html'] render mode of tooltip, 'html' or 'richText'\n * @param {string} [opt.markerId='X'] id name for marker. If only one marker is in a rich text, this can be omitted.\n * @return {string}\n */\nfunction getTooltipMarker(opt, extraCssText) {\n    opt = isString(opt) ? {color: opt, extraCssText: extraCssText} : (opt || {});\n    var color = opt.color;\n    var type = opt.type;\n    var extraCssText = opt.extraCssText;\n    var renderMode = opt.renderMode || 'html';\n    var markerId = opt.markerId || 'X';\n\n    if (!color) {\n        return '';\n    }\n\n    if (renderMode === 'html') {\n        return type === 'subItem'\n        ? '<span style=\"display:inline-block;vertical-align:middle;margin-right:8px;margin-left:3px;'\n            + 'border-radius:4px;width:4px;height:4px;background-color:'\n            + encodeHTML(color) + ';' + (extraCssText || '') + '\"></span>'\n        : '<span style=\"display:inline-block;margin-right:5px;'\n            + 'border-radius:10px;width:10px;height:10px;background-color:'\n            + encodeHTML(color) + ';' + (extraCssText || '') + '\"></span>';\n    }\n    else {\n        // Space for rich element marker\n        return {\n            renderMode: renderMode,\n            content: '{marker' + markerId + '|}  ',\n            style: {\n                color: color\n            }\n        };\n    }\n}\n\nfunction pad(str, len) {\n    str += '';\n    return '0000'.substr(0, len - str.length) + str;\n}\n\n\n/**\n * ISO Date format\n * @param {string} tpl\n * @param {number} value\n * @param {boolean} [isUTC=false] Default in local time.\n *           see `module:echarts/scale/Time`\n *           and `module:echarts/util/number#parseDate`.\n * @inner\n */\nfunction formatTime(tpl, value, isUTC) {\n    if (tpl === 'week'\n        || tpl === 'month'\n        || tpl === 'quarter'\n        || tpl === 'half-year'\n        || tpl === 'year'\n    ) {\n        tpl = 'MM-dd\\nyyyy';\n    }\n\n    var date = parseDate(value);\n    var utc = isUTC ? 'UTC' : '';\n    var y = date['get' + utc + 'FullYear']();\n    var M = date['get' + utc + 'Month']() + 1;\n    var d = date['get' + utc + 'Date']();\n    var h = date['get' + utc + 'Hours']();\n    var m = date['get' + utc + 'Minutes']();\n    var s = date['get' + utc + 'Seconds']();\n    var S = date['get' + utc + 'Milliseconds']();\n\n    tpl = tpl.replace('MM', pad(M, 2))\n        .replace('M', M)\n        .replace('yyyy', y)\n        .replace('yy', y % 100)\n        .replace('dd', pad(d, 2))\n        .replace('d', d)\n        .replace('hh', pad(h, 2))\n        .replace('h', h)\n        .replace('mm', pad(m, 2))\n        .replace('m', m)\n        .replace('ss', pad(s, 2))\n        .replace('s', s)\n        .replace('SSS', pad(S, 3));\n\n    return tpl;\n}\n\n/**\n * Capital first\n * @param {string} str\n * @return {string}\n */\nfunction capitalFirst(str) {\n    return str ? str.charAt(0).toUpperCase() + str.substr(1) : str;\n}\n\nvar truncateText$1 = truncateText;\n\n/**\n * @public\n * @param {Object} opt\n * @param {string} opt.text\n * @param {string} opt.font\n * @param {string} [opt.textAlign='left']\n * @param {string} [opt.textVerticalAlign='top']\n * @param {Array.<number>} [opt.textPadding]\n * @param {number} [opt.textLineHeight]\n * @param {Object} [opt.rich]\n * @param {Object} [opt.truncate]\n * @return {Object} {x, y, width, height, lineHeight}\n */\nfunction getTextBoundingRect(opt) {\n    return getBoundingRect(\n        opt.text,\n        opt.font,\n        opt.textAlign,\n        opt.textVerticalAlign,\n        opt.textPadding,\n        opt.textLineHeight,\n        opt.rich,\n        opt.truncate\n    );\n}\n\n/**\n * @deprecated\n * the `textLineHeight` was added later.\n * For backward compatiblility, put it as the last parameter.\n * But deprecated this interface. Please use `getTextBoundingRect` instead.\n */\nfunction getTextRect(\n    text, font, textAlign, textVerticalAlign, textPadding, rich, truncate, textLineHeight\n) {\n    return getBoundingRect(\n        text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate\n    );\n}\n\n\nvar format = (Object.freeze || Object)({\n\taddCommas: addCommas,\n\ttoCamelCase: toCamelCase,\n\tnormalizeCssArray: normalizeCssArray$1,\n\tencodeHTML: encodeHTML,\n\tformatTpl: formatTpl,\n\tformatTplSimple: formatTplSimple,\n\tgetTooltipMarker: getTooltipMarker,\n\tformatTime: formatTime,\n\tcapitalFirst: capitalFirst,\n\ttruncateText: truncateText$1,\n\tgetTextBoundingRect: getTextBoundingRect,\n\tgetTextRect: getTextRect\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Layout helpers for each component positioning\n\nvar each$3 = each$1;\n\n/**\n * @public\n */\nvar LOCATION_PARAMS = [\n    'left', 'right', 'top', 'bottom', 'width', 'height'\n];\n\n/**\n * @public\n */\nvar HV_NAMES = [\n    ['width', 'left', 'right'],\n    ['height', 'top', 'bottom']\n];\n\nfunction boxLayout(orient, group, gap, maxWidth, maxHeight) {\n    var x = 0;\n    var y = 0;\n\n    if (maxWidth == null) {\n        maxWidth = Infinity;\n    }\n    if (maxHeight == null) {\n        maxHeight = Infinity;\n    }\n    var currentLineMaxSize = 0;\n\n    group.eachChild(function (child, idx) {\n        var position = child.position;\n        var rect = child.getBoundingRect();\n        var nextChild = group.childAt(idx + 1);\n        var nextChildRect = nextChild && nextChild.getBoundingRect();\n        var nextX;\n        var nextY;\n\n        if (orient === 'horizontal') {\n            var moveX = rect.width + (nextChildRect ? (-nextChildRect.x + rect.x) : 0);\n            nextX = x + moveX;\n            // Wrap when width exceeds maxWidth or meet a `newline` group\n            // FIXME compare before adding gap?\n            if (nextX > maxWidth || child.newline) {\n                x = 0;\n                nextX = moveX;\n                y += currentLineMaxSize + gap;\n                currentLineMaxSize = rect.height;\n            }\n            else {\n                // FIXME: consider rect.y is not `0`?\n                currentLineMaxSize = Math.max(currentLineMaxSize, rect.height);\n            }\n        }\n        else {\n            var moveY = rect.height + (nextChildRect ? (-nextChildRect.y + rect.y) : 0);\n            nextY = y + moveY;\n            // Wrap when width exceeds maxHeight or meet a `newline` group\n            if (nextY > maxHeight || child.newline) {\n                x += currentLineMaxSize + gap;\n                y = 0;\n                nextY = moveY;\n                currentLineMaxSize = rect.width;\n            }\n            else {\n                currentLineMaxSize = Math.max(currentLineMaxSize, rect.width);\n            }\n        }\n\n        if (child.newline) {\n            return;\n        }\n\n        position[0] = x;\n        position[1] = y;\n\n        orient === 'horizontal'\n            ? (x = nextX + gap)\n            : (y = nextY + gap);\n    });\n}\n\n/**\n * VBox or HBox layouting\n * @param {string} orient\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar box = boxLayout;\n\n/**\n * VBox layouting\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar vbox = curry(boxLayout, 'vertical');\n\n/**\n * HBox layouting\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar hbox = curry(boxLayout, 'horizontal');\n\n/**\n * If x or x2 is not specified or 'center' 'left' 'right',\n * the width would be as long as possible.\n * If y or y2 is not specified or 'middle' 'top' 'bottom',\n * the height would be as long as possible.\n *\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.x]\n * @param {number|string} [positionInfo.y]\n * @param {number|string} [positionInfo.x2]\n * @param {number|string} [positionInfo.y2]\n * @param {Object} containerRect {width, height}\n * @param {string|number} margin\n * @return {Object} {width, height}\n */\nfunction getAvailableSize(positionInfo, containerRect, margin) {\n    var containerWidth = containerRect.width;\n    var containerHeight = containerRect.height;\n\n    var x = parsePercent$1(positionInfo.x, containerWidth);\n    var y = parsePercent$1(positionInfo.y, containerHeight);\n    var x2 = parsePercent$1(positionInfo.x2, containerWidth);\n    var y2 = parsePercent$1(positionInfo.y2, containerHeight);\n\n    (isNaN(x) || isNaN(parseFloat(positionInfo.x))) && (x = 0);\n    (isNaN(x2) || isNaN(parseFloat(positionInfo.x2))) && (x2 = containerWidth);\n    (isNaN(y) || isNaN(parseFloat(positionInfo.y))) && (y = 0);\n    (isNaN(y2) || isNaN(parseFloat(positionInfo.y2))) && (y2 = containerHeight);\n\n    margin = normalizeCssArray$1(margin || 0);\n\n    return {\n        width: Math.max(x2 - x - margin[1] - margin[3], 0),\n        height: Math.max(y2 - y - margin[0] - margin[2], 0)\n    };\n}\n\n/**\n * Parse position info.\n *\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.left]\n * @param {number|string} [positionInfo.top]\n * @param {number|string} [positionInfo.right]\n * @param {number|string} [positionInfo.bottom]\n * @param {number|string} [positionInfo.width]\n * @param {number|string} [positionInfo.height]\n * @param {number|string} [positionInfo.aspect] Aspect is width / height\n * @param {Object} containerRect\n * @param {string|number} [margin]\n *\n * @return {module:zrender/core/BoundingRect}\n */\nfunction getLayoutRect(\n    positionInfo, containerRect, margin\n) {\n    margin = normalizeCssArray$1(margin || 0);\n\n    var containerWidth = containerRect.width;\n    var containerHeight = containerRect.height;\n\n    var left = parsePercent$1(positionInfo.left, containerWidth);\n    var top = parsePercent$1(positionInfo.top, containerHeight);\n    var right = parsePercent$1(positionInfo.right, containerWidth);\n    var bottom = parsePercent$1(positionInfo.bottom, containerHeight);\n    var width = parsePercent$1(positionInfo.width, containerWidth);\n    var height = parsePercent$1(positionInfo.height, containerHeight);\n\n    var verticalMargin = margin[2] + margin[0];\n    var horizontalMargin = margin[1] + margin[3];\n    var aspect = positionInfo.aspect;\n\n    // If width is not specified, calculate width from left and right\n    if (isNaN(width)) {\n        width = containerWidth - right - horizontalMargin - left;\n    }\n    if (isNaN(height)) {\n        height = containerHeight - bottom - verticalMargin - top;\n    }\n\n    if (aspect != null) {\n        // If width and height are not given\n        // 1. Graph should not exceeds the container\n        // 2. Aspect must be keeped\n        // 3. Graph should take the space as more as possible\n        // FIXME\n        // Margin is not considered, because there is no case that both\n        // using margin and aspect so far.\n        if (isNaN(width) && isNaN(height)) {\n            if (aspect > containerWidth / containerHeight) {\n                width = containerWidth * 0.8;\n            }\n            else {\n                height = containerHeight * 0.8;\n            }\n        }\n\n        // Calculate width or height with given aspect\n        if (isNaN(width)) {\n            width = aspect * height;\n        }\n        if (isNaN(height)) {\n            height = width / aspect;\n        }\n    }\n\n    // If left is not specified, calculate left from right and width\n    if (isNaN(left)) {\n        left = containerWidth - right - width - horizontalMargin;\n    }\n    if (isNaN(top)) {\n        top = containerHeight - bottom - height - verticalMargin;\n    }\n\n    // Align left and top\n    switch (positionInfo.left || positionInfo.right) {\n        case 'center':\n            left = containerWidth / 2 - width / 2 - margin[3];\n            break;\n        case 'right':\n            left = containerWidth - width - horizontalMargin;\n            break;\n    }\n    switch (positionInfo.top || positionInfo.bottom) {\n        case 'middle':\n        case 'center':\n            top = containerHeight / 2 - height / 2 - margin[0];\n            break;\n        case 'bottom':\n            top = containerHeight - height - verticalMargin;\n            break;\n    }\n    // If something is wrong and left, top, width, height are calculated as NaN\n    left = left || 0;\n    top = top || 0;\n    if (isNaN(width)) {\n        // Width may be NaN if only one value is given except width\n        width = containerWidth - horizontalMargin - left - (right || 0);\n    }\n    if (isNaN(height)) {\n        // Height may be NaN if only one value is given except height\n        height = containerHeight - verticalMargin - top - (bottom || 0);\n    }\n\n    var rect = new BoundingRect(left + margin[3], top + margin[0], width, height);\n    rect.margin = margin;\n    return rect;\n}\n\n\n/**\n * Position a zr element in viewport\n *  Group position is specified by either\n *  {left, top}, {right, bottom}\n *  If all properties exists, right and bottom will be igonred.\n *\n * Logic:\n *     1. Scale (against origin point in parent coord)\n *     2. Rotate (against origin point in parent coord)\n *     3. Traslate (with el.position by this method)\n * So this method only fixes the last step 'Traslate', which does not affect\n * scaling and rotating.\n *\n * If be called repeatly with the same input el, the same result will be gotten.\n *\n * @param {module:zrender/Element} el Should have `getBoundingRect` method.\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.left]\n * @param {number|string} [positionInfo.top]\n * @param {number|string} [positionInfo.right]\n * @param {number|string} [positionInfo.bottom]\n * @param {number|string} [positionInfo.width] Only for opt.boundingModel: 'raw'\n * @param {number|string} [positionInfo.height] Only for opt.boundingModel: 'raw'\n * @param {Object} containerRect\n * @param {string|number} margin\n * @param {Object} [opt]\n * @param {Array.<number>} [opt.hv=[1,1]] Only horizontal or only vertical.\n * @param {Array.<number>} [opt.boundingMode='all']\n *        Specify how to calculate boundingRect when locating.\n *        'all': Position the boundingRect that is transformed and uioned\n *               both itself and its descendants.\n *               This mode simplies confine the elements in the bounding\n *               of their container (e.g., using 'right: 0').\n *        'raw': Position the boundingRect that is not transformed and only itself.\n *               This mode is useful when you want a element can overflow its\n *               container. (Consider a rotated circle needs to be located in a corner.)\n *               In this mode positionInfo.width/height can only be number.\n */\nfunction positionElement(el, positionInfo, containerRect, margin, opt) {\n    var h = !opt || !opt.hv || opt.hv[0];\n    var v = !opt || !opt.hv || opt.hv[1];\n    var boundingMode = opt && opt.boundingMode || 'all';\n\n    if (!h && !v) {\n        return;\n    }\n\n    var rect;\n    if (boundingMode === 'raw') {\n        rect = el.type === 'group'\n            ? new BoundingRect(0, 0, +positionInfo.width || 0, +positionInfo.height || 0)\n            : el.getBoundingRect();\n    }\n    else {\n        rect = el.getBoundingRect();\n        if (el.needLocalTransform()) {\n            var transform = el.getLocalTransform();\n            // Notice: raw rect may be inner object of el,\n            // which should not be modified.\n            rect = rect.clone();\n            rect.applyTransform(transform);\n        }\n    }\n\n    // The real width and height can not be specified but calculated by the given el.\n    positionInfo = getLayoutRect(\n        defaults(\n            {width: rect.width, height: rect.height},\n            positionInfo\n        ),\n        containerRect,\n        margin\n    );\n\n    // Because 'tranlate' is the last step in transform\n    // (see zrender/core/Transformable#getLocalTransform),\n    // we can just only modify el.position to get final result.\n    var elPos = el.position;\n    var dx = h ? positionInfo.x - rect.x : 0;\n    var dy = v ? positionInfo.y - rect.y : 0;\n\n    el.attr('position', boundingMode === 'raw' ? [dx, dy] : [elPos[0] + dx, elPos[1] + dy]);\n}\n\n/**\n * @param {Object} option Contains some of the properties in HV_NAMES.\n * @param {number} hvIdx 0: horizontal; 1: vertical.\n */\nfunction sizeCalculable(option, hvIdx) {\n    return option[HV_NAMES[hvIdx][0]] != null\n        || (option[HV_NAMES[hvIdx][1]] != null && option[HV_NAMES[hvIdx][2]] != null);\n}\n\n/**\n * Consider Case:\n * When defulat option has {left: 0, width: 100}, and we set {right: 0}\n * through setOption or media query, using normal zrUtil.merge will cause\n * {right: 0} does not take effect.\n *\n * @example\n * ComponentModel.extend({\n *     init: function () {\n *         ...\n *         var inputPositionParams = layout.getLayoutParams(option);\n *         this.mergeOption(inputPositionParams);\n *     },\n *     mergeOption: function (newOption) {\n *         newOption && zrUtil.merge(thisOption, newOption, true);\n *         layout.mergeLayoutParam(thisOption, newOption);\n *     }\n * });\n *\n * @param {Object} targetOption\n * @param {Object} newOption\n * @param {Object|string} [opt]\n * @param {boolean|Array.<boolean>} [opt.ignoreSize=false] Used for the components\n *  that width (or height) should not be calculated by left and right (or top and bottom).\n */\nfunction mergeLayoutParam(targetOption, newOption, opt) {\n    !isObject$1(opt) && (opt = {});\n\n    var ignoreSize = opt.ignoreSize;\n    !isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]);\n\n    var hResult = merge$$1(HV_NAMES[0], 0);\n    var vResult = merge$$1(HV_NAMES[1], 1);\n\n    copy(HV_NAMES[0], targetOption, hResult);\n    copy(HV_NAMES[1], targetOption, vResult);\n\n    function merge$$1(names, hvIdx) {\n        var newParams = {};\n        var newValueCount = 0;\n        var merged = {};\n        var mergedValueCount = 0;\n        var enoughParamNumber = 2;\n\n        each$3(names, function (name) {\n            merged[name] = targetOption[name];\n        });\n        each$3(names, function (name) {\n            // Consider case: newOption.width is null, which is\n            // set by user for removing width setting.\n            hasProp(newOption, name) && (newParams[name] = merged[name] = newOption[name]);\n            hasValue(newParams, name) && newValueCount++;\n            hasValue(merged, name) && mergedValueCount++;\n        });\n\n        if (ignoreSize[hvIdx]) {\n            // Only one of left/right is premitted to exist.\n            if (hasValue(newOption, names[1])) {\n                merged[names[2]] = null;\n            }\n            else if (hasValue(newOption, names[2])) {\n                merged[names[1]] = null;\n            }\n            return merged;\n        }\n\n        // Case: newOption: {width: ..., right: ...},\n        // or targetOption: {right: ...} and newOption: {width: ...},\n        // There is no conflict when merged only has params count\n        // little than enoughParamNumber.\n        if (mergedValueCount === enoughParamNumber || !newValueCount) {\n            return merged;\n        }\n        // Case: newOption: {width: ..., right: ...},\n        // Than we can make sure user only want those two, and ignore\n        // all origin params in targetOption.\n        else if (newValueCount >= enoughParamNumber) {\n            return newParams;\n        }\n        else {\n            // Chose another param from targetOption by priority.\n            for (var i = 0; i < names.length; i++) {\n                var name = names[i];\n                if (!hasProp(newParams, name) && hasProp(targetOption, name)) {\n                    newParams[name] = targetOption[name];\n                    break;\n                }\n            }\n            return newParams;\n        }\n    }\n\n    function hasProp(obj, name) {\n        return obj.hasOwnProperty(name);\n    }\n\n    function hasValue(obj, name) {\n        return obj[name] != null && obj[name] !== 'auto';\n    }\n\n    function copy(names, target, source) {\n        each$3(names, function (name) {\n            target[name] = source[name];\n        });\n    }\n}\n\n/**\n * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.\n * @param {Object} source\n * @return {Object} Result contains those props.\n */\nfunction getLayoutParams(source) {\n    return copyLayoutParams({}, source);\n}\n\n/**\n * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.\n * @param {Object} source\n * @return {Object} Result contains those props.\n */\nfunction copyLayoutParams(target, source) {\n    source && target && each$3(LOCATION_PARAMS, function (name) {\n        source.hasOwnProperty(name) && (target[name] = source[name]);\n    });\n    return target;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar boxLayoutMixin = {\n    getBoxLayoutParams: function () {\n        return {\n            left: this.get('left'),\n            top: this.get('top'),\n            right: this.get('right'),\n            bottom: this.get('bottom'),\n            width: this.get('width'),\n            height: this.get('height')\n        };\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Component model\n *\n * @module echarts/model/Component\n */\n\nvar inner$1 = makeInner();\n\n/**\n * @alias module:echarts/model/Component\n * @constructor\n * @param {Object} option\n * @param {module:echarts/model/Model} parentModel\n * @param {module:echarts/model/Model} ecModel\n */\nvar ComponentModel = Model.extend({\n\n    type: 'component',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    id: '',\n\n    /**\n     * Because simplified concept is probably better, series.name (or component.name)\n     * has been having too many resposibilities:\n     * (1) Generating id (which requires name in option should not be modified).\n     * (2) As an index to mapping series when merging option or calling API (a name\n     * can refer to more then one components, which is convinient is some case).\n     * (3) Display.\n     * @readOnly\n     */\n    name: '',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    mainType: '',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    subType: '',\n\n    /**\n     * @readOnly\n     * @type {number}\n     */\n    componentIndex: 0,\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    defaultOption: null,\n\n    /**\n     * @type {module:echarts/model/Global}\n     * @readOnly\n     */\n    ecModel: null,\n\n    /**\n     * key: componentType\n     * value:  Component model list, can not be null.\n     * @type {Object.<string, Array.<module:echarts/model/Model>>}\n     * @readOnly\n     */\n    dependentModels: [],\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    uid: null,\n\n    /**\n     * Support merge layout params.\n     * Only support 'box' now (left/right/top/bottom/width/height).\n     * @type {string|Object} Object can be {ignoreSize: true}\n     * @readOnly\n     */\n    layoutMode: null,\n\n    $constructor: function (option, parentModel, ecModel, extraOpt) {\n        Model.call(this, option, parentModel, ecModel, extraOpt);\n\n        this.uid = getUID('ec_cpt_model');\n    },\n\n    init: function (option, parentModel, ecModel, extraOpt) {\n        this.mergeDefaultAndTheme(option, ecModel);\n    },\n\n    mergeDefaultAndTheme: function (option, ecModel) {\n        var layoutMode = this.layoutMode;\n        var inputPositionParams = layoutMode\n            ? getLayoutParams(option) : {};\n\n        var themeModel = ecModel.getTheme();\n        merge(option, themeModel.get(this.mainType));\n        merge(option, this.getDefaultOption());\n\n        if (layoutMode) {\n            mergeLayoutParam(option, inputPositionParams, layoutMode);\n        }\n    },\n\n    mergeOption: function (option, extraOpt) {\n        merge(this.option, option, true);\n\n        var layoutMode = this.layoutMode;\n        if (layoutMode) {\n            mergeLayoutParam(this.option, option, layoutMode);\n        }\n    },\n\n    // Hooker after init or mergeOption\n    optionUpdated: function (newCptOption, isInit) {},\n\n    getDefaultOption: function () {\n        var fields = inner$1(this);\n        if (!fields.defaultOption) {\n            var optList = [];\n            var Class = this.constructor;\n            while (Class) {\n                var opt = Class.prototype.defaultOption;\n                opt && optList.push(opt);\n                Class = Class.superClass;\n            }\n\n            var defaultOption = {};\n            for (var i = optList.length - 1; i >= 0; i--) {\n                defaultOption = merge(defaultOption, optList[i], true);\n            }\n            fields.defaultOption = defaultOption;\n        }\n        return fields.defaultOption;\n    },\n\n    getReferringComponents: function (mainType) {\n        return this.ecModel.queryComponents({\n            mainType: mainType,\n            index: this.get(mainType + 'Index', true),\n            id: this.get(mainType + 'Id', true)\n        });\n    }\n\n});\n\n// Reset ComponentModel.extend, add preConstruct.\n// clazzUtil.enableClassExtend(\n//     ComponentModel,\n//     function (option, parentModel, ecModel, extraOpt) {\n//         // Set dependentModels, componentIndex, name, id, mainType, subType.\n//         zrUtil.extend(this, extraOpt);\n\n//         this.uid = componentUtil.getUID('componentModel');\n\n//         // this.setReadOnly([\n//         //     'type', 'id', 'uid', 'name', 'mainType', 'subType',\n//         //     'dependentModels', 'componentIndex'\n//         // ]);\n//     }\n// );\n\n// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(\n    ComponentModel, {registerWhenExtend: true}\n);\nenableSubTypeDefaulter(ComponentModel);\n\n// Add capability of ComponentModel.topologicalTravel.\nenableTopologicalTravel(ComponentModel, getDependencies);\n\nfunction getDependencies(componentType) {\n    var deps = [];\n    each$1(ComponentModel.getClassesByMainType(componentType), function (Clazz) {\n        deps = deps.concat(Clazz.prototype.dependencies || []);\n    });\n\n    // Ensure main type.\n    deps = map(deps, function (type) {\n        return parseClassType$1(type).main;\n    });\n\n    // Hack dataset for convenience.\n    if (componentType !== 'dataset' && indexOf(deps, 'dataset') <= 0) {\n        deps.unshift('dataset');\n    }\n\n    return deps;\n}\n\nmixin(ComponentModel, boxLayoutMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar platform = '';\n// Navigator not exists in node\nif (typeof navigator !== 'undefined') {\n    platform = navigator.platform || '';\n}\n\nvar globalDefault = {\n    // backgroundColor: 'rgba(0,0,0,0)',\n\n    // https://dribbble.com/shots/1065960-Infographic-Pie-chart-visualization\n    // color: ['#5793f3', '#d14a61', '#fd9c35', '#675bba', '#fec42c', '#dd4444', '#d4df5a', '#cd4870'],\n    // Light colors:\n    // color: ['#bcd3bb', '#e88f70', '#edc1a5', '#9dc5c8', '#e1e8c8', '#7b7c68', '#e5b5b5', '#f0b489', '#928ea8', '#bda29a'],\n    // color: ['#cc5664', '#9bd6ec', '#ea946e', '#8acaaa', '#f1ec64', '#ee8686', '#a48dc1', '#5da6bc', '#b9dcae'],\n    // Dark colors:\n    color: [\n        '#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83',\n        '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'\n    ],\n\n    gradientColor: ['#f6efa6', '#d88273', '#bf444c'],\n\n    // If xAxis and yAxis declared, grid is created by default.\n    // grid: {},\n\n    textStyle: {\n        // color: '#000',\n        // decoration: 'none',\n        // PENDING\n        fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif',\n        // fontFamily: 'Arial, Verdana, sans-serif',\n        fontSize: 12,\n        fontStyle: 'normal',\n        fontWeight: 'normal'\n    },\n\n    // http://blogs.adobe.com/webplatform/2014/02/24/using-blend-modes-in-html-canvas/\n    // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation\n    // Default is source-over\n    blendMode: null,\n\n    animation: 'auto',\n    animationDuration: 1000,\n    animationDurationUpdate: 300,\n    animationEasing: 'exponentialOut',\n    animationEasingUpdate: 'cubicOut',\n\n    animationThreshold: 2000,\n    // Configuration for progressive/incremental rendering\n    progressiveThreshold: 3000,\n    progressive: 400,\n\n    // Threshold of if use single hover layer to optimize.\n    // It is recommended that `hoverLayerThreshold` is equivalent to or less than\n    // `progressiveThreshold`, otherwise hover will cause restart of progressive,\n    // which is unexpected.\n    // see example <echarts/test/heatmap-large.html>.\n    hoverLayerThreshold: 3000,\n\n    // See: module:echarts/scale/Time\n    useUTC: false\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$2 = makeInner();\n\nfunction getNearestColorPalette(colors, requestColorNum) {\n    var paletteNum = colors.length;\n    // TODO colors must be in order\n    for (var i = 0; i < paletteNum; i++) {\n        if (colors[i].length > requestColorNum) {\n            return colors[i];\n        }\n    }\n    return colors[paletteNum - 1];\n}\n\nvar colorPaletteMixin = {\n    clearColorPalette: function () {\n        inner$2(this).colorIdx = 0;\n        inner$2(this).colorNameMap = {};\n    },\n\n    /**\n     * @param {string} name MUST NOT be null/undefined. Otherwise call this function\n     *                 twise with the same parameters will get different result.\n     * @param {Object} [scope=this]\n     * @param {Object} [requestColorNum]\n     * @return {string} color string.\n     */\n    getColorFromPalette: function (name, scope, requestColorNum) {\n        scope = scope || this;\n        var scopeFields = inner$2(scope);\n        var colorIdx = scopeFields.colorIdx || 0;\n        var colorNameMap = scopeFields.colorNameMap = scopeFields.colorNameMap || {};\n        // Use `hasOwnProperty` to avoid conflict with Object.prototype.\n        if (colorNameMap.hasOwnProperty(name)) {\n            return colorNameMap[name];\n        }\n        var defaultColorPalette = normalizeToArray(this.get('color', true));\n        var layeredColorPalette = this.get('colorLayer', true);\n        var colorPalette = ((requestColorNum == null || !layeredColorPalette)\n            ? defaultColorPalette : getNearestColorPalette(layeredColorPalette, requestColorNum));\n\n        // In case can't find in layered color palette.\n        colorPalette = colorPalette || defaultColorPalette;\n\n        if (!colorPalette || !colorPalette.length) {\n            return;\n        }\n\n        var color = colorPalette[colorIdx];\n        if (name) {\n            colorNameMap[name] = color;\n        }\n        scopeFields.colorIdx = (colorIdx + 1) % colorPalette.length;\n\n        return color;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Helper for model references.\n * There are many manners to refer axis/coordSys.\n */\n\n// TODO\n// merge relevant logic to this file?\n// check: \"modelHelper\" of tooltip and \"BrushTargetManager\".\n\n/**\n * @return {Object} For example:\n * {\n *     coordSysName: 'cartesian2d',\n *     coordSysDims: ['x', 'y', ...],\n *     axisMap: HashMap({\n *         x: xAxisModel,\n *         y: yAxisModel\n *     }),\n *     categoryAxisMap: HashMap({\n *         x: xAxisModel,\n *         y: undefined\n *     }),\n *     // It also indicate that whether there is category axis.\n *     firstCategoryDimIndex: 1,\n *     // To replace user specified encode.\n * }\n */\nfunction getCoordSysDefineBySeries(seriesModel) {\n    var coordSysName = seriesModel.get('coordinateSystem');\n    var result = {\n        coordSysName: coordSysName,\n        coordSysDims: [],\n        axisMap: createHashMap(),\n        categoryAxisMap: createHashMap()\n    };\n    var fetch = fetchers[coordSysName];\n    if (fetch) {\n        fetch(seriesModel, result, result.axisMap, result.categoryAxisMap);\n        return result;\n    }\n}\n\nvar fetchers = {\n\n    cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var xAxisModel = seriesModel.getReferringComponents('xAxis')[0];\n        var yAxisModel = seriesModel.getReferringComponents('yAxis')[0];\n\n        if (__DEV__) {\n            if (!xAxisModel) {\n                throw new Error('xAxis \"' + retrieve(\n                    seriesModel.get('xAxisIndex'),\n                    seriesModel.get('xAxisId'),\n                    0\n                ) + '\" not found');\n            }\n            if (!yAxisModel) {\n                throw new Error('yAxis \"' + retrieve(\n                    seriesModel.get('xAxisIndex'),\n                    seriesModel.get('yAxisId'),\n                    0\n                ) + '\" not found');\n            }\n        }\n\n        result.coordSysDims = ['x', 'y'];\n        axisMap.set('x', xAxisModel);\n        axisMap.set('y', yAxisModel);\n\n        if (isCategory(xAxisModel)) {\n            categoryAxisMap.set('x', xAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n        if (isCategory(yAxisModel)) {\n            categoryAxisMap.set('y', yAxisModel);\n            result.firstCategoryDimIndex = 1;\n        }\n    },\n\n    singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var singleAxisModel = seriesModel.getReferringComponents('singleAxis')[0];\n\n        if (__DEV__) {\n            if (!singleAxisModel) {\n                throw new Error('singleAxis should be specified.');\n            }\n        }\n\n        result.coordSysDims = ['single'];\n        axisMap.set('single', singleAxisModel);\n\n        if (isCategory(singleAxisModel)) {\n            categoryAxisMap.set('single', singleAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n    },\n\n    polar: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var polarModel = seriesModel.getReferringComponents('polar')[0];\n        var radiusAxisModel = polarModel.findAxisModel('radiusAxis');\n        var angleAxisModel = polarModel.findAxisModel('angleAxis');\n\n        if (__DEV__) {\n            if (!angleAxisModel) {\n                throw new Error('angleAxis option not found');\n            }\n            if (!radiusAxisModel) {\n                throw new Error('radiusAxis option not found');\n            }\n        }\n\n        result.coordSysDims = ['radius', 'angle'];\n        axisMap.set('radius', radiusAxisModel);\n        axisMap.set('angle', angleAxisModel);\n\n        if (isCategory(radiusAxisModel)) {\n            categoryAxisMap.set('radius', radiusAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n        if (isCategory(angleAxisModel)) {\n            categoryAxisMap.set('angle', angleAxisModel);\n            result.firstCategoryDimIndex = 1;\n        }\n    },\n\n    geo: function (seriesModel, result, axisMap, categoryAxisMap) {\n        result.coordSysDims = ['lng', 'lat'];\n    },\n\n    parallel: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var ecModel = seriesModel.ecModel;\n        var parallelModel = ecModel.getComponent(\n            'parallel', seriesModel.get('parallelIndex')\n        );\n        var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice();\n\n        each$1(parallelModel.parallelAxisIndex, function (axisIndex, index) {\n            var axisModel = ecModel.getComponent('parallelAxis', axisIndex);\n            var axisDim = coordSysDims[index];\n            axisMap.set(axisDim, axisModel);\n\n            if (isCategory(axisModel) && result.firstCategoryDimIndex == null) {\n                categoryAxisMap.set(axisDim, axisModel);\n                result.firstCategoryDimIndex = index;\n            }\n        });\n    }\n};\n\nfunction isCategory(axisModel) {\n    return axisModel.get('type') === 'category';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Avoid typo.\nvar SOURCE_FORMAT_ORIGINAL = 'original';\nvar SOURCE_FORMAT_ARRAY_ROWS = 'arrayRows';\nvar SOURCE_FORMAT_OBJECT_ROWS = 'objectRows';\nvar SOURCE_FORMAT_KEYED_COLUMNS = 'keyedColumns';\nvar SOURCE_FORMAT_UNKNOWN = 'unknown';\n// ??? CHANGE A NAME\nvar SOURCE_FORMAT_TYPED_ARRAY = 'typedArray';\n\nvar SERIES_LAYOUT_BY_COLUMN = 'column';\nvar SERIES_LAYOUT_BY_ROW = 'row';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * [sourceFormat]\n *\n * + \"original\":\n * This format is only used in series.data, where\n * itemStyle can be specified in data item.\n *\n * + \"arrayRows\":\n * [\n *     ['product', 'score', 'amount'],\n *     ['Matcha Latte', 89.3, 95.8],\n *     ['Milk Tea', 92.1, 89.4],\n *     ['Cheese Cocoa', 94.4, 91.2],\n *     ['Walnut Brownie', 85.4, 76.9]\n * ]\n *\n * + \"objectRows\":\n * [\n *     {product: 'Matcha Latte', score: 89.3, amount: 95.8},\n *     {product: 'Milk Tea', score: 92.1, amount: 89.4},\n *     {product: 'Cheese Cocoa', score: 94.4, amount: 91.2},\n *     {product: 'Walnut Brownie', score: 85.4, amount: 76.9}\n * ]\n *\n * + \"keyedColumns\":\n * {\n *     'product': ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie'],\n *     'count': [823, 235, 1042, 988],\n *     'score': [95.8, 81.4, 91.2, 76.9]\n * }\n *\n * + \"typedArray\"\n *\n * + \"unknown\"\n */\n\n/**\n * @constructor\n * @param {Object} fields\n * @param {string} fields.sourceFormat\n * @param {Array|Object} fields.fromDataset\n * @param {Array|Object} [fields.data]\n * @param {string} [seriesLayoutBy='column']\n * @param {Array.<Object|string>} [dimensionsDefine]\n * @param {Objet|HashMap} [encodeDefine]\n * @param {number} [startIndex=0]\n * @param {number} [dimensionsDetectCount]\n */\nfunction Source(fields) {\n\n    /**\n     * @type {boolean}\n     */\n    this.fromDataset = fields.fromDataset;\n\n    /**\n     * Not null/undefined.\n     * @type {Array|Object}\n     */\n    this.data = fields.data || (\n        fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []\n    );\n\n    /**\n     * See also \"detectSourceFormat\".\n     * Not null/undefined.\n     * @type {string}\n     */\n    this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN;\n\n    /**\n     * 'row' or 'column'\n     * Not null/undefined.\n     * @type {string} seriesLayoutBy\n     */\n    this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN;\n\n    /**\n     * dimensions definition in option.\n     * can be null/undefined.\n     * @type {Array.<Object|string>}\n     */\n    this.dimensionsDefine = fields.dimensionsDefine;\n\n    /**\n     * encode definition in option.\n     * can be null/undefined.\n     * @type {Objet|HashMap}\n     */\n    this.encodeDefine = fields.encodeDefine && createHashMap(fields.encodeDefine);\n\n    /**\n     * Not null/undefined, uint.\n     * @type {number}\n     */\n    this.startIndex = fields.startIndex || 0;\n\n    /**\n     * Can be null/undefined (when unknown), uint.\n     * @type {number}\n     */\n    this.dimensionsDetectCount = fields.dimensionsDetectCount;\n}\n\n/**\n * Wrap original series data for some compatibility cases.\n */\nSource.seriesDataToSource = function (data) {\n    return new Source({\n        data: data,\n        sourceFormat: isTypedArray(data)\n            ? SOURCE_FORMAT_TYPED_ARRAY\n            : SOURCE_FORMAT_ORIGINAL,\n        fromDataset: false\n    });\n};\n\nenableClassCheck(Source);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$3 = makeInner();\n\n/**\n * @see {module:echarts/data/Source}\n * @param {module:echarts/component/dataset/DatasetModel} datasetModel\n * @return {string} sourceFormat\n */\nfunction detectSourceFormat(datasetModel) {\n    var data = datasetModel.option.source;\n    var sourceFormat = SOURCE_FORMAT_UNKNOWN;\n\n    if (isTypedArray(data)) {\n        sourceFormat = SOURCE_FORMAT_TYPED_ARRAY;\n    }\n    else if (isArray(data)) {\n        // FIXME Whether tolerate null in top level array?\n        if (data.length === 0) {\n            sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;\n        }\n\n        for (var i = 0, len = data.length; i < len; i++) {\n            var item = data[i];\n\n            if (item == null) {\n                continue;\n            }\n            else if (isArray(item)) {\n                sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;\n                break;\n            }\n            else if (isObject$1(item)) {\n                sourceFormat = SOURCE_FORMAT_OBJECT_ROWS;\n                break;\n            }\n        }\n    }\n    else if (isObject$1(data)) {\n        for (var key in data) {\n            if (data.hasOwnProperty(key) && isArrayLike(data[key])) {\n                sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS;\n                break;\n            }\n        }\n    }\n    else if (data != null) {\n        throw new Error('Invalid data');\n    }\n\n    inner$3(datasetModel).sourceFormat = sourceFormat;\n}\n\n/**\n * [Scenarios]:\n * (1) Provide source data directly:\n *     series: {\n *         encode: {...},\n *         dimensions: [...]\n *         seriesLayoutBy: 'row',\n *         data: [[...]]\n *     }\n * (2) Refer to datasetModel.\n *     series: [{\n *         encode: {...}\n *         // Ignore datasetIndex means `datasetIndex: 0`\n *         // and the dimensions defination in dataset is used\n *     }, {\n *         encode: {...},\n *         seriesLayoutBy: 'column',\n *         datasetIndex: 1\n *     }]\n *\n * Get data from series itself or datset.\n * @return {module:echarts/data/Source} source\n */\nfunction getSource(seriesModel) {\n    return inner$3(seriesModel).source;\n}\n\n/**\n * MUST be called before mergeOption of all series.\n * @param {module:echarts/model/Global} ecModel\n */\nfunction resetSourceDefaulter(ecModel) {\n    // `datasetMap` is used to make default encode.\n    inner$3(ecModel).datasetMap = createHashMap();\n}\n\n/**\n * [Caution]:\n * MUST be called after series option merged and\n * before \"series.getInitailData()\" called.\n *\n * [The rule of making default encode]:\n * Category axis (if exists) alway map to the first dimension.\n * Each other axis occupies a subsequent dimension.\n *\n * [Why make default encode]:\n * Simplify the typing of encode in option, avoiding the case like that:\n * series: [{encode: {x: 0, y: 1}}, {encode: {x: 0, y: 2}}, {encode: {x: 0, y: 3}}],\n * where the \"y\" have to be manually typed as \"1, 2, 3, ...\".\n *\n * @param {module:echarts/model/Series} seriesModel\n */\nfunction prepareSource(seriesModel) {\n    var seriesOption = seriesModel.option;\n\n    var data = seriesOption.data;\n    var sourceFormat = isTypedArray(data)\n        ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL;\n    var fromDataset = false;\n\n    var seriesLayoutBy = seriesOption.seriesLayoutBy;\n    var sourceHeader = seriesOption.sourceHeader;\n    var dimensionsDefine = seriesOption.dimensions;\n\n    var datasetModel = getDatasetModel(seriesModel);\n    if (datasetModel) {\n        var datasetOption = datasetModel.option;\n\n        data = datasetOption.source;\n        sourceFormat = inner$3(datasetModel).sourceFormat;\n        fromDataset = true;\n\n        // These settings from series has higher priority.\n        seriesLayoutBy = seriesLayoutBy || datasetOption.seriesLayoutBy;\n        sourceHeader == null && (sourceHeader = datasetOption.sourceHeader);\n        dimensionsDefine = dimensionsDefine || datasetOption.dimensions;\n    }\n\n    var completeResult = completeBySourceData(\n        data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine\n    );\n\n    // Note: dataset option does not have `encode`.\n    var encodeDefine = seriesOption.encode;\n    if (!encodeDefine && datasetModel) {\n        encodeDefine = makeDefaultEncode(\n            seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult\n        );\n    }\n\n    inner$3(seriesModel).source = new Source({\n        data: data,\n        fromDataset: fromDataset,\n        seriesLayoutBy: seriesLayoutBy,\n        sourceFormat: sourceFormat,\n        dimensionsDefine: completeResult.dimensionsDefine,\n        startIndex: completeResult.startIndex,\n        dimensionsDetectCount: completeResult.dimensionsDetectCount,\n        encodeDefine: encodeDefine\n    });\n}\n\n// return {startIndex, dimensionsDefine, dimensionsCount}\nfunction completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine) {\n    if (!data) {\n        return {dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine)};\n    }\n\n    var dimensionsDetectCount;\n    var startIndex;\n    var findPotentialName;\n\n    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {\n        // Rule: Most of the first line are string: it is header.\n        // Caution: consider a line with 5 string and 1 number,\n        // it still can not be sure it is a head, because the\n        // 5 string may be 5 values of category columns.\n        if (sourceHeader === 'auto' || sourceHeader == null) {\n            arrayRowsTravelFirst(function (val) {\n                // '-' is regarded as null/undefined.\n                if (val != null && val !== '-') {\n                    if (isString(val)) {\n                        startIndex == null && (startIndex = 1);\n                    }\n                    else {\n                        startIndex = 0;\n                    }\n                }\n            // 10 is an experience number, avoid long loop.\n            }, seriesLayoutBy, data, 10);\n        }\n        else {\n            startIndex = sourceHeader ? 1 : 0;\n        }\n\n        if (!dimensionsDefine && startIndex === 1) {\n            dimensionsDefine = [];\n            arrayRowsTravelFirst(function (val, index) {\n                dimensionsDefine[index] = val != null ? val : '';\n            }, seriesLayoutBy, data);\n        }\n\n        dimensionsDetectCount = dimensionsDefine\n            ? dimensionsDefine.length\n            : seriesLayoutBy === SERIES_LAYOUT_BY_ROW\n            ? data.length\n            : data[0]\n            ? data[0].length\n            : null;\n    }\n    else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {\n        if (!dimensionsDefine) {\n            dimensionsDefine = objectRowsCollectDimensions(data);\n            findPotentialName = true;\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {\n        if (!dimensionsDefine) {\n            dimensionsDefine = [];\n            findPotentialName = true;\n            each$1(data, function (colArr, key) {\n                dimensionsDefine.push(key);\n            });\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        var value0 = getDataItemValue(data[0]);\n        dimensionsDetectCount = isArray(value0) && value0.length || 1;\n    }\n    else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {\n        if (__DEV__) {\n            assert$1(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.');\n        }\n    }\n\n    var potentialNameDimIndex;\n    if (findPotentialName) {\n        each$1(dimensionsDefine, function (dim, idx) {\n            if ((isObject$1(dim) ? dim.name : dim) === 'name') {\n                potentialNameDimIndex = idx;\n            }\n        });\n    }\n\n    return {\n        startIndex: startIndex,\n        dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine),\n        dimensionsDetectCount: dimensionsDetectCount,\n        potentialNameDimIndex: potentialNameDimIndex\n        // TODO: potentialIdDimIdx\n    };\n}\n\n// Consider dimensions defined like ['A', 'price', 'B', 'price', 'C', 'price'],\n// which is reasonable. But dimension name is duplicated.\n// Returns undefined or an array contains only object without null/undefiend or string.\nfunction normalizeDimensionsDefine(dimensionsDefine) {\n    if (!dimensionsDefine) {\n        // The meaning of null/undefined is different from empty array.\n        return;\n    }\n    var nameMap = createHashMap();\n    return map(dimensionsDefine, function (item, index) {\n        item = extend({}, isObject$1(item) ? item : {name: item});\n\n        // User can set null in dimensions.\n        // We dont auto specify name, othewise a given name may\n        // cause it be refered unexpectedly.\n        if (item.name == null) {\n            return item;\n        }\n\n        // Also consider number form like 2012.\n        item.name += '';\n        // User may also specify displayName.\n        // displayName will always exists except user not\n        // specified or dim name is not specified or detected.\n        // (A auto generated dim name will not be used as\n        // displayName).\n        if (item.displayName == null) {\n            item.displayName = item.name;\n        }\n\n        var exist = nameMap.get(item.name);\n        if (!exist) {\n            nameMap.set(item.name, {count: 1});\n        }\n        else {\n            item.name += '-' + exist.count++;\n        }\n\n        return item;\n    });\n}\n\nfunction arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) {\n    maxLoop == null && (maxLoop = Infinity);\n    if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            cb(data[i] ? data[i][0] : null, i);\n        }\n    }\n    else {\n        var value0 = data[0] || [];\n        for (var i = 0; i < value0.length && i < maxLoop; i++) {\n            cb(value0[i], i);\n        }\n    }\n}\n\nfunction objectRowsCollectDimensions(data) {\n    var firstIndex = 0;\n    var obj;\n    while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line\n    if (obj) {\n        var dimensions = [];\n        each$1(obj, function (value, key) {\n            dimensions.push(key);\n        });\n        return dimensions;\n    }\n}\n\n// ??? TODO merge to completedimensions, where also has\n// default encode making logic. And the default rule\n// should depends on series? consider 'map'.\nfunction makeDefaultEncode(\n    seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult\n) {\n    var coordSysDefine = getCoordSysDefineBySeries(seriesModel);\n    var encode = {};\n    // var encodeTooltip = [];\n    // var encodeLabel = [];\n    var encodeItemName = [];\n    var encodeSeriesName = [];\n    var seriesType = seriesModel.subType;\n\n    // ??? TODO refactor: provide by series itself.\n    // Consider the case: 'map' series is based on geo coordSys,\n    // 'graph', 'heatmap' can be based on cartesian. But can not\n    // give default rule simply here.\n    var nSeriesMap = createHashMap(['pie', 'map', 'funnel']);\n    var cSeriesMap = createHashMap([\n        'line', 'bar', 'pictorialBar', 'scatter', 'effectScatter', 'candlestick', 'boxplot'\n    ]);\n\n    // Usually in this case series will use the first data\n    // dimension as the \"value\" dimension, or other default\n    // processes respectively.\n    if (coordSysDefine && cSeriesMap.get(seriesType) != null) {\n        var ecModel = seriesModel.ecModel;\n        var datasetMap = inner$3(ecModel).datasetMap;\n        var key = datasetModel.uid + '_' + seriesLayoutBy;\n        var datasetRecord = datasetMap.get(key)\n            || datasetMap.set(key, {categoryWayDim: 1, valueWayDim: 0});\n\n        // TODO\n        // Auto detect first time axis and do arrangement.\n        each$1(coordSysDefine.coordSysDims, function (coordDim) {\n            // In value way.\n            if (coordSysDefine.firstCategoryDimIndex == null) {\n                var dataDim = datasetRecord.valueWayDim++;\n                encode[coordDim] = dataDim;\n\n                // ??? TODO give a better default series name rule?\n                // especially when encode x y specified.\n                // consider: when mutiple series share one dimension\n                // category axis, series name should better use\n                // the other dimsion name. On the other hand, use\n                // both dimensions name.\n\n                encodeSeriesName.push(dataDim);\n                // encodeTooltip.push(dataDim);\n                // encodeLabel.push(dataDim);\n            }\n            // In category way, category axis.\n            else if (coordSysDefine.categoryAxisMap.get(coordDim)) {\n                encode[coordDim] = 0;\n                encodeItemName.push(0);\n            }\n            // In category way, non-category axis.\n            else {\n                var dataDim = datasetRecord.categoryWayDim++;\n                encode[coordDim] = dataDim;\n                // encodeTooltip.push(dataDim);\n                // encodeLabel.push(dataDim);\n                encodeSeriesName.push(dataDim);\n            }\n        });\n    }\n    // Do not make a complex rule! Hard to code maintain and not necessary.\n    // ??? TODO refactor: provide by series itself.\n    // [{name: ..., value: ...}, ...] like:\n    else if (nSeriesMap.get(seriesType) != null) {\n        // Find the first not ordinal. (5 is an experience value)\n        var firstNotOrdinal;\n        for (var i = 0; i < 5 && firstNotOrdinal == null; i++) {\n            if (!doGuessOrdinal(\n                data, sourceFormat, seriesLayoutBy,\n                completeResult.dimensionsDefine, completeResult.startIndex, i\n            )) {\n                firstNotOrdinal = i;\n            }\n        }\n        if (firstNotOrdinal != null) {\n            encode.value = firstNotOrdinal;\n            var nameDimIndex = completeResult.potentialNameDimIndex\n                || Math.max(firstNotOrdinal - 1, 0);\n            // By default, label use itemName in charts.\n            // So we dont set encodeLabel here.\n            encodeSeriesName.push(nameDimIndex);\n            encodeItemName.push(nameDimIndex);\n            // encodeTooltip.push(firstNotOrdinal);\n        }\n    }\n\n    // encodeTooltip.length && (encode.tooltip = encodeTooltip);\n    // encodeLabel.length && (encode.label = encodeLabel);\n    encodeItemName.length && (encode.itemName = encodeItemName);\n    encodeSeriesName.length && (encode.seriesName = encodeSeriesName);\n\n    return encode;\n}\n\n/**\n * If return null/undefined, indicate that should not use datasetModel.\n */\nfunction getDatasetModel(seriesModel) {\n    var option = seriesModel.option;\n    // Caution: consider the scenario:\n    // A dataset is declared and a series is not expected to use the dataset,\n    // and at the beginning `setOption({series: { noData })` (just prepare other\n    // option but no data), then `setOption({series: {data: [...]}); In this case,\n    // the user should set an empty array to avoid that dataset is used by default.\n    var thisData = option.data;\n    if (!thisData) {\n        return seriesModel.ecModel.getComponent('dataset', option.datasetIndex || 0);\n    }\n}\n\n/**\n * The rule should not be complex, otherwise user might not\n * be able to known where the data is wrong.\n * The code is ugly, but how to make it neat?\n *\n * @param {module:echars/data/Source} source\n * @param {number} dimIndex\n * @return {boolean} Whether ordinal.\n */\nfunction guessOrdinal(source, dimIndex) {\n    return doGuessOrdinal(\n        source.data,\n        source.sourceFormat,\n        source.seriesLayoutBy,\n        source.dimensionsDefine,\n        source.startIndex,\n        dimIndex\n    );\n}\n\n// dimIndex may be overflow source data.\nfunction doGuessOrdinal(\n    data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex\n) {\n    var result;\n    // Experience value.\n    var maxLoop = 5;\n\n    if (isTypedArray(data)) {\n        return false;\n    }\n\n    // When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine\n    // always exists in source.\n    var dimName;\n    if (dimensionsDefine) {\n        dimName = dimensionsDefine[dimIndex];\n        dimName = isObject$1(dimName) ? dimName.name : dimName;\n    }\n\n    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {\n        if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {\n            var sample = data[dimIndex];\n            for (var i = 0; i < (sample || []).length && i < maxLoop; i++) {\n                if ((result = detectValue(sample[startIndex + i])) != null) {\n                    return result;\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < data.length && i < maxLoop; i++) {\n                var row = data[startIndex + i];\n                if (row && (result = detectValue(row[dimIndex])) != null) {\n                    return result;\n                }\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {\n        if (!dimName) {\n            return;\n        }\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            var item = data[i];\n            if (item && (result = detectValue(item[dimName])) != null) {\n                return result;\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {\n        if (!dimName) {\n            return;\n        }\n        var sample = data[dimName];\n        if (!sample || isTypedArray(sample)) {\n            return false;\n        }\n        for (var i = 0; i < sample.length && i < maxLoop; i++) {\n            if ((result = detectValue(sample[i])) != null) {\n                return result;\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            var item = data[i];\n            var val = getDataItemValue(item);\n            if (!isArray(val)) {\n                return false;\n            }\n            if ((result = detectValue(val[dimIndex])) != null) {\n                return result;\n            }\n        }\n    }\n\n    function detectValue(val) {\n        // Consider usage convenience, '1', '2' will be treated as \"number\".\n        // `isFinit('')` get `true`.\n        if (val != null && isFinite(val) && val !== '') {\n            return false;\n        }\n        else if (isString(val) && val !== '-') {\n            return true;\n        }\n    }\n\n    return false;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * ECharts global model\n *\n * @module {echarts/model/Global}\n */\n\n\n/**\n * Caution: If the mechanism should be changed some day, these cases\n * should be considered:\n *\n * (1) In `merge option` mode, if using the same option to call `setOption`\n * many times, the result should be the same (try our best to ensure that).\n * (2) In `merge option` mode, if a component has no id/name specified, it\n * will be merged by index, and the result sequence of the components is\n * consistent to the original sequence.\n * (3) `reset` feature (in toolbox). Find detailed info in comments about\n * `mergeOption` in module:echarts/model/OptionManager.\n */\n\nvar OPTION_INNER_KEY = '\\0_ec_inner';\n\n/**\n * @alias module:echarts/model/Global\n *\n * @param {Object} option\n * @param {module:echarts/model/Model} parentModel\n * @param {Object} theme\n */\nvar GlobalModel = Model.extend({\n\n    init: function (option, parentModel, theme, optionManager) {\n        theme = theme || {};\n\n        this.option = null; // Mark as not initialized.\n\n        /**\n         * @type {module:echarts/model/Model}\n         * @private\n         */\n        this._theme = new Model(theme);\n\n        /**\n         * @type {module:echarts/model/OptionManager}\n         */\n        this._optionManager = optionManager;\n    },\n\n    setOption: function (option, optionPreprocessorFuncs) {\n        assert$1(\n            !(OPTION_INNER_KEY in option),\n            'please use chart.getOption()'\n        );\n\n        this._optionManager.setOption(option, optionPreprocessorFuncs);\n\n        this.resetOption(null);\n    },\n\n    /**\n     * @param {string} type null/undefined: reset all.\n     *                      'recreate': force recreate all.\n     *                      'timeline': only reset timeline option\n     *                      'media': only reset media query option\n     * @return {boolean} Whether option changed.\n     */\n    resetOption: function (type) {\n        var optionChanged = false;\n        var optionManager = this._optionManager;\n\n        if (!type || type === 'recreate') {\n            var baseOption = optionManager.mountOption(type === 'recreate');\n\n            if (!this.option || type === 'recreate') {\n                initBase.call(this, baseOption);\n            }\n            else {\n                this.restoreData();\n                this.mergeOption(baseOption);\n            }\n            optionChanged = true;\n        }\n\n        if (type === 'timeline' || type === 'media') {\n            this.restoreData();\n        }\n\n        if (!type || type === 'recreate' || type === 'timeline') {\n            var timelineOption = optionManager.getTimelineOption(this);\n            timelineOption && (this.mergeOption(timelineOption), optionChanged = true);\n        }\n\n        if (!type || type === 'recreate' || type === 'media') {\n            var mediaOptions = optionManager.getMediaOption(this, this._api);\n            if (mediaOptions.length) {\n                each$1(mediaOptions, function (mediaOption) {\n                    this.mergeOption(mediaOption, optionChanged = true);\n                }, this);\n            }\n        }\n\n        return optionChanged;\n    },\n\n    /**\n     * @protected\n     */\n    mergeOption: function (newOption) {\n        var option = this.option;\n        var componentsMap = this._componentsMap;\n        var newCptTypes = [];\n\n        resetSourceDefaulter(this);\n\n        // If no component class, merge directly.\n        // For example: color, animaiton options, etc.\n        each$1(newOption, function (componentOption, mainType) {\n            if (componentOption == null) {\n                return;\n            }\n\n            if (!ComponentModel.hasClass(mainType)) {\n                // globalSettingTask.dirty();\n                option[mainType] = option[mainType] == null\n                    ? clone(componentOption)\n                    : merge(option[mainType], componentOption, true);\n            }\n            else if (mainType) {\n                newCptTypes.push(mainType);\n            }\n        });\n\n        ComponentModel.topologicalTravel(\n            newCptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this\n        );\n\n        function visitComponent(mainType, dependencies) {\n\n            var newCptOptionList = normalizeToArray(newOption[mainType]);\n\n            var mapResult = mappingToExists(\n                componentsMap.get(mainType), newCptOptionList\n            );\n\n            makeIdAndName(mapResult);\n\n            // Set mainType and complete subType.\n            each$1(mapResult, function (item, index) {\n                var opt = item.option;\n                if (isObject$1(opt)) {\n                    item.keyInfo.mainType = mainType;\n                    item.keyInfo.subType = determineSubType(mainType, opt, item.exist);\n                }\n            });\n\n            var dependentModels = getComponentsByTypes(\n                componentsMap, dependencies\n            );\n\n            option[mainType] = [];\n            componentsMap.set(mainType, []);\n\n            each$1(mapResult, function (resultItem, index) {\n                var componentModel = resultItem.exist;\n                var newCptOption = resultItem.option;\n\n                assert$1(\n                    isObject$1(newCptOption) || componentModel,\n                    'Empty component definition'\n                );\n\n                // Consider where is no new option and should be merged using {},\n                // see removeEdgeAndAdd in topologicalTravel and\n                // ComponentModel.getAllClassMainTypes.\n                if (!newCptOption) {\n                    componentModel.mergeOption({}, this);\n                    componentModel.optionUpdated({}, false);\n                }\n                else {\n                    var ComponentModelClass = ComponentModel.getClass(\n                        mainType, resultItem.keyInfo.subType, true\n                    );\n\n                    if (componentModel && componentModel instanceof ComponentModelClass) {\n                        componentModel.name = resultItem.keyInfo.name;\n                        // componentModel.settingTask && componentModel.settingTask.dirty();\n                        componentModel.mergeOption(newCptOption, this);\n                        componentModel.optionUpdated(newCptOption, false);\n                    }\n                    else {\n                        // PENDING Global as parent ?\n                        var extraOpt = extend(\n                            {\n                                dependentModels: dependentModels,\n                                componentIndex: index\n                            },\n                            resultItem.keyInfo\n                        );\n                        componentModel = new ComponentModelClass(\n                            newCptOption, this, this, extraOpt\n                        );\n                        extend(componentModel, extraOpt);\n                        componentModel.init(newCptOption, this, this, extraOpt);\n\n                        // Call optionUpdated after init.\n                        // newCptOption has been used as componentModel.option\n                        // and may be merged with theme and default, so pass null\n                        // to avoid confusion.\n                        componentModel.optionUpdated(null, true);\n                    }\n                }\n\n                componentsMap.get(mainType)[index] = componentModel;\n                option[mainType][index] = componentModel.option;\n            }, this);\n\n            // Backup series for filtering.\n            if (mainType === 'series') {\n                createSeriesIndices(this, componentsMap.get('series'));\n            }\n        }\n\n        this._seriesIndicesMap = createHashMap(\n            this._seriesIndices = this._seriesIndices || []\n        );\n    },\n\n    /**\n     * Get option for output (cloned option and inner info removed)\n     * @public\n     * @return {Object}\n     */\n    getOption: function () {\n        var option = clone(this.option);\n\n        each$1(option, function (opts, mainType) {\n            if (ComponentModel.hasClass(mainType)) {\n                var opts = normalizeToArray(opts);\n                for (var i = opts.length - 1; i >= 0; i--) {\n                    // Remove options with inner id.\n                    if (isIdInner(opts[i])) {\n                        opts.splice(i, 1);\n                    }\n                }\n                option[mainType] = opts;\n            }\n        });\n\n        delete option[OPTION_INNER_KEY];\n\n        return option;\n    },\n\n    /**\n     * @return {module:echarts/model/Model}\n     */\n    getTheme: function () {\n        return this._theme;\n    },\n\n    /**\n     * @param {string} mainType\n     * @param {number} [idx=0]\n     * @return {module:echarts/model/Component}\n     */\n    getComponent: function (mainType, idx) {\n        var list = this._componentsMap.get(mainType);\n        if (list) {\n            return list[idx || 0];\n        }\n    },\n\n    /**\n     * If none of index and id and name used, return all components with mainType.\n     * @param {Object} condition\n     * @param {string} condition.mainType\n     * @param {string} [condition.subType] If ignore, only query by mainType\n     * @param {number|Array.<number>} [condition.index] Either input index or id or name.\n     * @param {string|Array.<string>} [condition.id] Either input index or id or name.\n     * @param {string|Array.<string>} [condition.name] Either input index or id or name.\n     * @return {Array.<module:echarts/model/Component>}\n     */\n    queryComponents: function (condition) {\n        var mainType = condition.mainType;\n        if (!mainType) {\n            return [];\n        }\n\n        var index = condition.index;\n        var id = condition.id;\n        var name = condition.name;\n\n        var cpts = this._componentsMap.get(mainType);\n\n        if (!cpts || !cpts.length) {\n            return [];\n        }\n\n        var result;\n\n        if (index != null) {\n            if (!isArray(index)) {\n                index = [index];\n            }\n            result = filter(map(index, function (idx) {\n                return cpts[idx];\n            }), function (val) {\n                return !!val;\n            });\n        }\n        else if (id != null) {\n            var isIdArray = isArray(id);\n            result = filter(cpts, function (cpt) {\n                return (isIdArray && indexOf(id, cpt.id) >= 0)\n                    || (!isIdArray && cpt.id === id);\n            });\n        }\n        else if (name != null) {\n            var isNameArray = isArray(name);\n            result = filter(cpts, function (cpt) {\n                return (isNameArray && indexOf(name, cpt.name) >= 0)\n                    || (!isNameArray && cpt.name === name);\n            });\n        }\n        else {\n            // Return all components with mainType\n            result = cpts.slice();\n        }\n\n        return filterBySubType(result, condition);\n    },\n\n    /**\n     * The interface is different from queryComponents,\n     * which is convenient for inner usage.\n     *\n     * @usage\n     * var result = findComponents(\n     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}}\n     * );\n     * var result = findComponents(\n     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}}\n     * );\n     * var result = findComponents(\n     *     {mainType: 'series'},\n     *     function (model, index) {...}\n     * );\n     * // result like [component0, componnet1, ...]\n     *\n     * @param {Object} condition\n     * @param {string} condition.mainType Mandatory.\n     * @param {string} [condition.subType] Optional.\n     * @param {Object} [condition.query] like {xxxIndex, xxxId, xxxName},\n     *        where xxx is mainType.\n     *        If query attribute is null/undefined or has no index/id/name,\n     *        do not filtering by query conditions, which is convenient for\n     *        no-payload situations or when target of action is global.\n     * @param {Function} [condition.filter] parameter: component, return boolean.\n     * @return {Array.<module:echarts/model/Component>}\n     */\n    findComponents: function (condition) {\n        var query = condition.query;\n        var mainType = condition.mainType;\n\n        var queryCond = getQueryCond(query);\n        var result = queryCond\n            ? this.queryComponents(queryCond)\n            : this._componentsMap.get(mainType);\n\n        return doFilter(filterBySubType(result, condition));\n\n        function getQueryCond(q) {\n            var indexAttr = mainType + 'Index';\n            var idAttr = mainType + 'Id';\n            var nameAttr = mainType + 'Name';\n            return q && (\n                    q[indexAttr] != null\n                    || q[idAttr] != null\n                    || q[nameAttr] != null\n                )\n                ? {\n                    mainType: mainType,\n                    // subType will be filtered finally.\n                    index: q[indexAttr],\n                    id: q[idAttr],\n                    name: q[nameAttr]\n                }\n                : null;\n        }\n\n        function doFilter(res) {\n            return condition.filter\n                    ? filter(res, condition.filter)\n                    : res;\n        }\n    },\n\n    /**\n     * @usage\n     * eachComponent('legend', function (legendModel, index) {\n     *     ...\n     * });\n     * eachComponent(function (componentType, model, index) {\n     *     // componentType does not include subType\n     *     // (componentType is 'xxx' but not 'xxx.aa')\n     * });\n     * eachComponent(\n     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}},\n     *     function (model, index) {...}\n     * );\n     * eachComponent(\n     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}},\n     *     function (model, index) {...}\n     * );\n     *\n     * @param {string|Object=} mainType When mainType is object, the definition\n     *                                  is the same as the method 'findComponents'.\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachComponent: function (mainType, cb, context) {\n        var componentsMap = this._componentsMap;\n\n        if (typeof mainType === 'function') {\n            context = cb;\n            cb = mainType;\n            componentsMap.each(function (components, componentType) {\n                each$1(components, function (component, index) {\n                    cb.call(context, componentType, component, index);\n                });\n            });\n        }\n        else if (isString(mainType)) {\n            each$1(componentsMap.get(mainType), cb, context);\n        }\n        else if (isObject$1(mainType)) {\n            var queryResult = this.findComponents(mainType);\n            each$1(queryResult, cb, context);\n        }\n    },\n\n    /**\n     * @param {string} name\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeriesByName: function (name) {\n        var series = this._componentsMap.get('series');\n        return filter(series, function (oneSeries) {\n            return oneSeries.name === name;\n        });\n    },\n\n    /**\n     * @param {number} seriesIndex\n     * @return {module:echarts/model/Series}\n     */\n    getSeriesByIndex: function (seriesIndex) {\n        return this._componentsMap.get('series')[seriesIndex];\n    },\n\n    /**\n     * Get series list before filtered by type.\n     * FIXME: rename to getRawSeriesByType?\n     *\n     * @param {string} subType\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeriesByType: function (subType) {\n        var series = this._componentsMap.get('series');\n        return filter(series, function (oneSeries) {\n            return oneSeries.subType === subType;\n        });\n    },\n\n    /**\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeries: function () {\n        return this._componentsMap.get('series').slice();\n    },\n\n    /**\n     * @return {number}\n     */\n    getSeriesCount: function () {\n        return this._componentsMap.get('series').length;\n    },\n\n    /**\n     * After filtering, series may be different\n     * frome raw series.\n     *\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachSeries: function (cb, context) {\n        assertSeriesInitialized(this);\n        each$1(this._seriesIndices, function (rawSeriesIndex) {\n            var series = this._componentsMap.get('series')[rawSeriesIndex];\n            cb.call(context, series, rawSeriesIndex);\n        }, this);\n    },\n\n    /**\n     * Iterate raw series before filtered.\n     *\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachRawSeries: function (cb, context) {\n        each$1(this._componentsMap.get('series'), cb, context);\n    },\n\n    /**\n     * After filtering, series may be different.\n     * frome raw series.\n     *\n     * @parma {string} subType\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachSeriesByType: function (subType, cb, context) {\n        assertSeriesInitialized(this);\n        each$1(this._seriesIndices, function (rawSeriesIndex) {\n            var series = this._componentsMap.get('series')[rawSeriesIndex];\n            if (series.subType === subType) {\n                cb.call(context, series, rawSeriesIndex);\n            }\n        }, this);\n    },\n\n    /**\n     * Iterate raw series before filtered of given type.\n     *\n     * @parma {string} subType\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachRawSeriesByType: function (subType, cb, context) {\n        return each$1(this.getSeriesByType(subType), cb, context);\n    },\n\n    /**\n     * @param {module:echarts/model/Series} seriesModel\n     */\n    isSeriesFiltered: function (seriesModel) {\n        assertSeriesInitialized(this);\n        return this._seriesIndicesMap.get(seriesModel.componentIndex) == null;\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getCurrentSeriesIndices: function () {\n        return (this._seriesIndices || []).slice();\n    },\n\n    /**\n     * @param {Function} cb\n     * @param {*} context\n     */\n    filterSeries: function (cb, context) {\n        assertSeriesInitialized(this);\n        var filteredSeries = filter(\n            this._componentsMap.get('series'), cb, context\n        );\n        createSeriesIndices(this, filteredSeries);\n    },\n\n    restoreData: function (payload) {\n        var componentsMap = this._componentsMap;\n\n        createSeriesIndices(this, componentsMap.get('series'));\n\n        var componentTypes = [];\n        componentsMap.each(function (components, componentType) {\n            componentTypes.push(componentType);\n        });\n\n        ComponentModel.topologicalTravel(\n            componentTypes,\n            ComponentModel.getAllClassMainTypes(),\n            function (componentType, dependencies) {\n                each$1(componentsMap.get(componentType), function (component) {\n                    (componentType !== 'series' || !isNotTargetSeries(component, payload))\n                        && component.restoreData();\n                });\n            }\n        );\n    }\n\n});\n\nfunction isNotTargetSeries(seriesModel, payload) {\n    if (payload) {\n        var index = payload.seiresIndex;\n        var id = payload.seriesId;\n        var name = payload.seriesName;\n        return (index != null && seriesModel.componentIndex !== index)\n            || (id != null && seriesModel.id !== id)\n            || (name != null && seriesModel.name !== name);\n    }\n}\n\n/**\n * @inner\n */\nfunction mergeTheme(option, theme) {\n    // PENDING\n    // NOT use `colorLayer` in theme if option has `color`\n    var notMergeColorLayer = option.color && !option.colorLayer;\n\n    each$1(theme, function (themeItem, name) {\n        if (name === 'colorLayer' && notMergeColorLayer) {\n            return;\n        }\n        // 如果有 component model 则把具体的 merge 逻辑交给该 model 处理\n        if (!ComponentModel.hasClass(name)) {\n            if (typeof themeItem === 'object') {\n                option[name] = !option[name]\n                    ? clone(themeItem)\n                    : merge(option[name], themeItem, false);\n            }\n            else {\n                if (option[name] == null) {\n                    option[name] = themeItem;\n                }\n            }\n        }\n    });\n}\n\nfunction initBase(baseOption) {\n    baseOption = baseOption;\n\n    // Using OPTION_INNER_KEY to mark that this option can not be used outside,\n    // i.e. `chart.setOption(chart.getModel().option);` is forbiden.\n    this.option = {};\n    this.option[OPTION_INNER_KEY] = 1;\n\n    /**\n     * Init with series: [], in case of calling findSeries method\n     * before series initialized.\n     * @type {Object.<string, Array.<module:echarts/model/Model>>}\n     * @private\n     */\n    this._componentsMap = createHashMap({series: []});\n\n    /**\n     * Mapping between filtered series list and raw series list.\n     * key: filtered series indices, value: raw series indices.\n     * @type {Array.<nubmer>}\n     * @private\n     */\n    this._seriesIndices;\n\n    this._seriesIndicesMap;\n\n    mergeTheme(baseOption, this._theme.option);\n\n    // TODO Needs clone when merging to the unexisted property\n    merge(baseOption, globalDefault, false);\n\n    this.mergeOption(baseOption);\n}\n\n/**\n * @inner\n * @param {Array.<string>|string} types model types\n * @return {Object} key: {string} type, value: {Array.<Object>} models\n */\nfunction getComponentsByTypes(componentsMap, types) {\n    if (!isArray(types)) {\n        types = types ? [types] : [];\n    }\n\n    var ret = {};\n    each$1(types, function (type) {\n        ret[type] = (componentsMap.get(type) || []).slice();\n    });\n\n    return ret;\n}\n\n/**\n * @inner\n */\nfunction determineSubType(mainType, newCptOption, existComponent) {\n    var subType = newCptOption.type\n        ? newCptOption.type\n        : existComponent\n        ? existComponent.subType\n        // Use determineSubType only when there is no existComponent.\n        : ComponentModel.determineSubType(mainType, newCptOption);\n\n    // tooltip, markline, markpoint may always has no subType\n    return subType;\n}\n\n/**\n * @inner\n */\nfunction createSeriesIndices(ecModel, seriesModels) {\n    ecModel._seriesIndicesMap = createHashMap(\n        ecModel._seriesIndices = map(seriesModels, function (series) {\n            return series.componentIndex;\n        }) || []\n    );\n}\n\n/**\n * @inner\n */\nfunction filterBySubType(components, condition) {\n    // Using hasOwnProperty for restrict. Consider\n    // subType is undefined in user payload.\n    return condition.hasOwnProperty('subType')\n        ? filter(components, function (cpt) {\n            return cpt.subType === condition.subType;\n        })\n        : components;\n}\n\n/**\n * @inner\n */\nfunction assertSeriesInitialized(ecModel) {\n    // Components that use _seriesIndices should depends on series component,\n    // which make sure that their initialization is after series.\n    if (__DEV__) {\n        if (!ecModel._seriesIndices) {\n            throw new Error('Option should contains series.');\n        }\n    }\n}\n\nmixin(GlobalModel, colorPaletteMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar echartsAPIList = [\n    'getDom', 'getZr', 'getWidth', 'getHeight', 'getDevicePixelRatio', 'dispatchAction', 'isDisposed',\n    'on', 'off', 'getDataURL', 'getConnectedDataURL', 'getModel', 'getOption',\n    'getViewOfComponentModel', 'getViewOfSeriesModel'\n];\n// And `getCoordinateSystems` and `getComponentByElement` will be injected in echarts.js\n\nfunction ExtensionAPI(chartInstance) {\n    each$1(echartsAPIList, function (name) {\n        this[name] = bind(chartInstance[name], chartInstance);\n    }, this);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar coordinateSystemCreators = {};\n\nfunction CoordinateSystemManager() {\n\n    this._coordinateSystems = [];\n}\n\nCoordinateSystemManager.prototype = {\n\n    constructor: CoordinateSystemManager,\n\n    create: function (ecModel, api) {\n        var coordinateSystems = [];\n        each$1(coordinateSystemCreators, function (creater, type) {\n            var list = creater.create(ecModel, api);\n            coordinateSystems = coordinateSystems.concat(list || []);\n        });\n\n        this._coordinateSystems = coordinateSystems;\n    },\n\n    update: function (ecModel, api) {\n        each$1(this._coordinateSystems, function (coordSys) {\n            coordSys.update && coordSys.update(ecModel, api);\n        });\n    },\n\n    getCoordinateSystems: function () {\n        return this._coordinateSystems.slice();\n    }\n};\n\nCoordinateSystemManager.register = function (type, coordinateSystemCreator) {\n    coordinateSystemCreators[type] = coordinateSystemCreator;\n};\n\nCoordinateSystemManager.get = function (type) {\n    return coordinateSystemCreators[type];\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * ECharts option manager\n *\n * @module {echarts/model/OptionManager}\n */\n\n\nvar each$4 = each$1;\nvar clone$3 = clone;\nvar map$1 = map;\nvar merge$1 = merge;\n\nvar QUERY_REG = /^(min|max)?(.+)$/;\n\n/**\n * TERM EXPLANATIONS:\n *\n * [option]:\n *\n *     An object that contains definitions of components. For example:\n *     var option = {\n *         title: {...},\n *         legend: {...},\n *         visualMap: {...},\n *         series: [\n *             {data: [...]},\n *             {data: [...]},\n *             ...\n *         ]\n *     };\n *\n * [rawOption]:\n *\n *     An object input to echarts.setOption. 'rawOption' may be an\n *     'option', or may be an object contains multi-options. For example:\n *     var option = {\n *         baseOption: {\n *             title: {...},\n *             legend: {...},\n *             series: [\n *                 {data: [...]},\n *                 {data: [...]},\n *                 ...\n *             ]\n *         },\n *         timeline: {...},\n *         options: [\n *             {title: {...}, series: {data: [...]}},\n *             {title: {...}, series: {data: [...]}},\n *             ...\n *         ],\n *         media: [\n *             {\n *                 query: {maxWidth: 320},\n *                 option: {series: {x: 20}, visualMap: {show: false}}\n *             },\n *             {\n *                 query: {minWidth: 320, maxWidth: 720},\n *                 option: {series: {x: 500}, visualMap: {show: true}}\n *             },\n *             {\n *                 option: {series: {x: 1200}, visualMap: {show: true}}\n *             }\n *         ]\n *     };\n *\n * @alias module:echarts/model/OptionManager\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction OptionManager(api) {\n\n    /**\n     * @private\n     * @type {module:echarts/ExtensionAPI}\n     */\n    this._api = api;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._timelineOptions = [];\n\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    this._mediaList = [];\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._mediaDefault;\n\n    /**\n     * -1, means default.\n     * empty means no media.\n     * @private\n     * @type {Array.<number>}\n     */\n    this._currentMediaIndices = [];\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._optionBackup;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._newBaseOption;\n}\n\n// timeline.notMerge is not supported in ec3. Firstly there is rearly\n// case that notMerge is needed. Secondly supporting 'notMerge' requires\n// rawOption cloned and backuped when timeline changed, which does no\n// good to performance. What's more, that both timeline and setOption\n// method supply 'notMerge' brings complex and some problems.\n// Consider this case:\n// (step1) chart.setOption({timeline: {notMerge: false}, ...}, false);\n// (step2) chart.setOption({timeline: {notMerge: true}, ...}, false);\n\nOptionManager.prototype = {\n\n    constructor: OptionManager,\n\n    /**\n     * @public\n     * @param {Object} rawOption Raw option.\n     * @param {module:echarts/model/Global} ecModel\n     * @param {Array.<Function>} optionPreprocessorFuncs\n     * @return {Object} Init option\n     */\n    setOption: function (rawOption, optionPreprocessorFuncs) {\n        if (rawOption) {\n            // That set dat primitive is dangerous if user reuse the data when setOption again.\n            each$1(normalizeToArray(rawOption.series), function (series) {\n                series && series.data && isTypedArray(series.data) && setAsPrimitive(series.data);\n            });\n        }\n\n        // Caution: some series modify option data, if do not clone,\n        // it should ensure that the repeat modify correctly\n        // (create a new object when modify itself).\n        rawOption = clone$3(rawOption, true);\n\n        // FIXME\n        // 如果 timeline options 或者 media 中设置了某个属性，而baseOption中没有设置，则进行警告。\n\n        var oldOptionBackup = this._optionBackup;\n        var newParsedOption = parseRawOption.call(\n            this, rawOption, optionPreprocessorFuncs, !oldOptionBackup\n        );\n        this._newBaseOption = newParsedOption.baseOption;\n\n        // For setOption at second time (using merge mode);\n        if (oldOptionBackup) {\n            // Only baseOption can be merged.\n            mergeOption(oldOptionBackup.baseOption, newParsedOption.baseOption);\n\n            // For simplicity, timeline options and media options do not support merge,\n            // that is, if you `setOption` twice and both has timeline options, the latter\n            // timeline opitons will not be merged to the formers, but just substitude them.\n            if (newParsedOption.timelineOptions.length) {\n                oldOptionBackup.timelineOptions = newParsedOption.timelineOptions;\n            }\n            if (newParsedOption.mediaList.length) {\n                oldOptionBackup.mediaList = newParsedOption.mediaList;\n            }\n            if (newParsedOption.mediaDefault) {\n                oldOptionBackup.mediaDefault = newParsedOption.mediaDefault;\n            }\n        }\n        else {\n            this._optionBackup = newParsedOption;\n        }\n    },\n\n    /**\n     * @param {boolean} isRecreate\n     * @return {Object}\n     */\n    mountOption: function (isRecreate) {\n        var optionBackup = this._optionBackup;\n\n        // TODO\n        // 如果没有reset功能则不clone。\n\n        this._timelineOptions = map$1(optionBackup.timelineOptions, clone$3);\n        this._mediaList = map$1(optionBackup.mediaList, clone$3);\n        this._mediaDefault = clone$3(optionBackup.mediaDefault);\n        this._currentMediaIndices = [];\n\n        return clone$3(isRecreate\n            // this._optionBackup.baseOption, which is created at the first `setOption`\n            // called, and is merged into every new option by inner method `mergeOption`\n            // each time `setOption` called, can be only used in `isRecreate`, because\n            // its reliability is under suspicion. In other cases option merge is\n            // performed by `model.mergeOption`.\n            ? optionBackup.baseOption : this._newBaseOption\n        );\n    },\n\n    /**\n     * @param {module:echarts/model/Global} ecModel\n     * @return {Object}\n     */\n    getTimelineOption: function (ecModel) {\n        var option;\n        var timelineOptions = this._timelineOptions;\n\n        if (timelineOptions.length) {\n            // getTimelineOption can only be called after ecModel inited,\n            // so we can get currentIndex from timelineModel.\n            var timelineModel = ecModel.getComponent('timeline');\n            if (timelineModel) {\n                option = clone$3(\n                    timelineOptions[timelineModel.getCurrentIndex()],\n                    true\n                );\n            }\n        }\n\n        return option;\n    },\n\n    /**\n     * @param {module:echarts/model/Global} ecModel\n     * @return {Array.<Object>}\n     */\n    getMediaOption: function (ecModel) {\n        var ecWidth = this._api.getWidth();\n        var ecHeight = this._api.getHeight();\n        var mediaList = this._mediaList;\n        var mediaDefault = this._mediaDefault;\n        var indices = [];\n        var result = [];\n\n        // No media defined.\n        if (!mediaList.length && !mediaDefault) {\n            return result;\n        }\n\n        // Multi media may be applied, the latter defined media has higher priority.\n        for (var i = 0, len = mediaList.length; i < len; i++) {\n            if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) {\n                indices.push(i);\n            }\n        }\n\n        // FIXME\n        // 是否mediaDefault应该强制用户设置，否则可能修改不能回归。\n        if (!indices.length && mediaDefault) {\n            indices = [-1];\n        }\n\n        if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) {\n            result = map$1(indices, function (index) {\n                return clone$3(\n                    index === -1 ? mediaDefault.option : mediaList[index].option\n                );\n            });\n        }\n        // Otherwise return nothing.\n\n        this._currentMediaIndices = indices;\n\n        return result;\n    }\n};\n\nfunction parseRawOption(rawOption, optionPreprocessorFuncs, isNew) {\n    var timelineOptions = [];\n    var mediaList = [];\n    var mediaDefault;\n    var baseOption;\n\n    // Compatible with ec2.\n    var timelineOpt = rawOption.timeline;\n\n    if (rawOption.baseOption) {\n        baseOption = rawOption.baseOption;\n    }\n\n    // For timeline\n    if (timelineOpt || rawOption.options) {\n        baseOption = baseOption || {};\n        timelineOptions = (rawOption.options || []).slice();\n    }\n\n    // For media query\n    if (rawOption.media) {\n        baseOption = baseOption || {};\n        var media = rawOption.media;\n        each$4(media, function (singleMedia) {\n            if (singleMedia && singleMedia.option) {\n                if (singleMedia.query) {\n                    mediaList.push(singleMedia);\n                }\n                else if (!mediaDefault) {\n                    // Use the first media default.\n                    mediaDefault = singleMedia;\n                }\n            }\n        });\n    }\n\n    // For normal option\n    if (!baseOption) {\n        baseOption = rawOption;\n    }\n\n    // Set timelineOpt to baseOption in ec3,\n    // which is convenient for merge option.\n    if (!baseOption.timeline) {\n        baseOption.timeline = timelineOpt;\n    }\n\n    // Preprocess.\n    each$4([baseOption].concat(timelineOptions)\n        .concat(map(mediaList, function (media) {\n            return media.option;\n        })),\n        function (option) {\n            each$4(optionPreprocessorFuncs, function (preProcess) {\n                preProcess(option, isNew);\n            });\n        }\n    );\n\n    return {\n        baseOption: baseOption,\n        timelineOptions: timelineOptions,\n        mediaDefault: mediaDefault,\n        mediaList: mediaList\n    };\n}\n\n/**\n * @see <http://www.w3.org/TR/css3-mediaqueries/#media1>\n * Support: width, height, aspectRatio\n * Can use max or min as prefix.\n */\nfunction applyMediaQuery(query, ecWidth, ecHeight) {\n    var realMap = {\n        width: ecWidth,\n        height: ecHeight,\n        aspectratio: ecWidth / ecHeight // lowser case for convenientce.\n    };\n\n    var applicatable = true;\n\n    each$1(query, function (value, attr) {\n        var matched = attr.match(QUERY_REG);\n\n        if (!matched || !matched[1] || !matched[2]) {\n            return;\n        }\n\n        var operator = matched[1];\n        var realAttr = matched[2].toLowerCase();\n\n        if (!compare(realMap[realAttr], value, operator)) {\n            applicatable = false;\n        }\n    });\n\n    return applicatable;\n}\n\nfunction compare(real, expect, operator) {\n    if (operator === 'min') {\n        return real >= expect;\n    }\n    else if (operator === 'max') {\n        return real <= expect;\n    }\n    else { // Equals\n        return real === expect;\n    }\n}\n\nfunction indicesEquals(indices1, indices2) {\n    // indices is always order by asc and has only finite number.\n    return indices1.join(',') === indices2.join(',');\n}\n\n/**\n * Consider case:\n * `chart.setOption(opt1);`\n * Then user do some interaction like dataZoom, dataView changing.\n * `chart.setOption(opt2);`\n * Then user press 'reset button' in toolbox.\n *\n * After doing that all of the interaction effects should be reset, the\n * chart should be the same as the result of invoke\n * `chart.setOption(opt1); chart.setOption(opt2);`.\n *\n * Although it is not able ensure that\n * `chart.setOption(opt1); chart.setOption(opt2);` is equivalents to\n * `chart.setOption(merge(opt1, opt2));` exactly,\n * this might be the only simple way to implement that feature.\n *\n * MEMO: We've considered some other approaches:\n * 1. Each model handle its self restoration but not uniform treatment.\n *     (Too complex in logic and error-prone)\n * 2. Use a shadow ecModel. (Performace expensive)\n */\nfunction mergeOption(oldOption, newOption) {\n    newOption = newOption || {};\n\n    each$4(newOption, function (newCptOpt, mainType) {\n        if (newCptOpt == null) {\n            return;\n        }\n\n        var oldCptOpt = oldOption[mainType];\n\n        if (!ComponentModel.hasClass(mainType)) {\n            oldOption[mainType] = merge$1(oldCptOpt, newCptOpt, true);\n        }\n        else {\n            newCptOpt = normalizeToArray(newCptOpt);\n            oldCptOpt = normalizeToArray(oldCptOpt);\n\n            var mapResult = mappingToExists(oldCptOpt, newCptOpt);\n\n            oldOption[mainType] = map$1(mapResult, function (item) {\n                return (item.option && item.exist)\n                    ? merge$1(item.exist, item.option, true)\n                    : (item.exist || item.option);\n            });\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$5 = each$1;\nvar isObject$3 = isObject$1;\n\nvar POSSIBLE_STYLES = [\n    'areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle',\n    'chordStyle', 'label', 'labelLine'\n];\n\nfunction compatEC2ItemStyle(opt) {\n    var itemStyleOpt = opt && opt.itemStyle;\n    if (!itemStyleOpt) {\n        return;\n    }\n    for (var i = 0, len = POSSIBLE_STYLES.length; i < len; i++) {\n        var styleName = POSSIBLE_STYLES[i];\n        var normalItemStyleOpt = itemStyleOpt.normal;\n        var emphasisItemStyleOpt = itemStyleOpt.emphasis;\n        if (normalItemStyleOpt && normalItemStyleOpt[styleName]) {\n            opt[styleName] = opt[styleName] || {};\n            if (!opt[styleName].normal) {\n                opt[styleName].normal = normalItemStyleOpt[styleName];\n            }\n            else {\n                merge(opt[styleName].normal, normalItemStyleOpt[styleName]);\n            }\n            normalItemStyleOpt[styleName] = null;\n        }\n        if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) {\n            opt[styleName] = opt[styleName] || {};\n            if (!opt[styleName].emphasis) {\n                opt[styleName].emphasis = emphasisItemStyleOpt[styleName];\n            }\n            else {\n                merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]);\n            }\n            emphasisItemStyleOpt[styleName] = null;\n        }\n    }\n}\n\nfunction convertNormalEmphasis(opt, optType, useExtend) {\n    if (opt && opt[optType] && (opt[optType].normal || opt[optType].emphasis)) {\n        var normalOpt = opt[optType].normal;\n        var emphasisOpt = opt[optType].emphasis;\n\n        if (normalOpt) {\n            // Timeline controlStyle has other properties besides normal and emphasis\n            if (useExtend) {\n                opt[optType].normal = opt[optType].emphasis = null;\n                defaults(opt[optType], normalOpt);\n            }\n            else {\n                opt[optType] = normalOpt;\n            }\n        }\n        if (emphasisOpt) {\n            opt.emphasis = opt.emphasis || {};\n            opt.emphasis[optType] = emphasisOpt;\n        }\n    }\n}\nfunction removeEC3NormalStatus(opt) {\n    convertNormalEmphasis(opt, 'itemStyle');\n    convertNormalEmphasis(opt, 'lineStyle');\n    convertNormalEmphasis(opt, 'areaStyle');\n    convertNormalEmphasis(opt, 'label');\n    convertNormalEmphasis(opt, 'labelLine');\n    // treemap\n    convertNormalEmphasis(opt, 'upperLabel');\n    // graph\n    convertNormalEmphasis(opt, 'edgeLabel');\n}\n\nfunction compatTextStyle(opt, propName) {\n    // Check whether is not object (string\\null\\undefined ...)\n    var labelOptSingle = isObject$3(opt) && opt[propName];\n    var textStyle = isObject$3(labelOptSingle) && labelOptSingle.textStyle;\n    if (textStyle) {\n        for (var i = 0, len = TEXT_STYLE_OPTIONS.length; i < len; i++) {\n            var propName = TEXT_STYLE_OPTIONS[i];\n            if (textStyle.hasOwnProperty(propName)) {\n                labelOptSingle[propName] = textStyle[propName];\n            }\n        }\n    }\n}\n\nfunction compatEC3CommonStyles(opt) {\n    if (opt) {\n        removeEC3NormalStatus(opt);\n        compatTextStyle(opt, 'label');\n        opt.emphasis && compatTextStyle(opt.emphasis, 'label');\n    }\n}\n\nfunction processSeries(seriesOpt) {\n    if (!isObject$3(seriesOpt)) {\n        return;\n    }\n\n    compatEC2ItemStyle(seriesOpt);\n    removeEC3NormalStatus(seriesOpt);\n\n    compatTextStyle(seriesOpt, 'label');\n    // treemap\n    compatTextStyle(seriesOpt, 'upperLabel');\n    // graph\n    compatTextStyle(seriesOpt, 'edgeLabel');\n    if (seriesOpt.emphasis) {\n        compatTextStyle(seriesOpt.emphasis, 'label');\n        // treemap\n        compatTextStyle(seriesOpt.emphasis, 'upperLabel');\n        // graph\n        compatTextStyle(seriesOpt.emphasis, 'edgeLabel');\n    }\n\n    var markPoint = seriesOpt.markPoint;\n    if (markPoint) {\n        compatEC2ItemStyle(markPoint);\n        compatEC3CommonStyles(markPoint);\n    }\n\n    var markLine = seriesOpt.markLine;\n    if (markLine) {\n        compatEC2ItemStyle(markLine);\n        compatEC3CommonStyles(markLine);\n    }\n\n    var markArea = seriesOpt.markArea;\n    if (markArea) {\n        compatEC3CommonStyles(markArea);\n    }\n\n    var data = seriesOpt.data;\n\n    // Break with ec3: if `setOption` again, there may be no `type` in option,\n    // then the backward compat based on option type will not be performed.\n\n    if (seriesOpt.type === 'graph') {\n        data = data || seriesOpt.nodes;\n        var edgeData = seriesOpt.links || seriesOpt.edges;\n        if (edgeData && !isTypedArray(edgeData)) {\n            for (var i = 0; i < edgeData.length; i++) {\n                compatEC3CommonStyles(edgeData[i]);\n            }\n        }\n        each$1(seriesOpt.categories, function (opt) {\n            removeEC3NormalStatus(opt);\n        });\n    }\n\n    if (data && !isTypedArray(data)) {\n        for (var i = 0; i < data.length; i++) {\n            compatEC3CommonStyles(data[i]);\n        }\n    }\n\n    // mark point data\n    var markPoint = seriesOpt.markPoint;\n    if (markPoint && markPoint.data) {\n        var mpData = markPoint.data;\n        for (var i = 0; i < mpData.length; i++) {\n            compatEC3CommonStyles(mpData[i]);\n        }\n    }\n    // mark line data\n    var markLine = seriesOpt.markLine;\n    if (markLine && markLine.data) {\n        var mlData = markLine.data;\n        for (var i = 0; i < mlData.length; i++) {\n            if (isArray(mlData[i])) {\n                compatEC3CommonStyles(mlData[i][0]);\n                compatEC3CommonStyles(mlData[i][1]);\n            }\n            else {\n                compatEC3CommonStyles(mlData[i]);\n            }\n        }\n    }\n\n    // Series\n    if (seriesOpt.type === 'gauge') {\n        compatTextStyle(seriesOpt, 'axisLabel');\n        compatTextStyle(seriesOpt, 'title');\n        compatTextStyle(seriesOpt, 'detail');\n    }\n    else if (seriesOpt.type === 'treemap') {\n        convertNormalEmphasis(seriesOpt.breadcrumb, 'itemStyle');\n        each$1(seriesOpt.levels, function (opt) {\n            removeEC3NormalStatus(opt);\n        });\n    }\n    else if (seriesOpt.type === 'tree') {\n        removeEC3NormalStatus(seriesOpt.leaves);\n    }\n    // sunburst starts from ec4, so it does not need to compat levels.\n}\n\nfunction toArr(o) {\n    return isArray(o) ? o : o ? [o] : [];\n}\n\nfunction toObj(o) {\n    return (isArray(o) ? o[0] : o) || {};\n}\n\nvar compatStyle = function (option, isTheme) {\n    each$5(toArr(option.series), function (seriesOpt) {\n        isObject$3(seriesOpt) && processSeries(seriesOpt);\n    });\n\n    var axes = ['xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'parallelAxis', 'radar'];\n    isTheme && axes.push('valueAxis', 'categoryAxis', 'logAxis', 'timeAxis');\n\n    each$5(\n        axes,\n        function (axisName) {\n            each$5(toArr(option[axisName]), function (axisOpt) {\n                if (axisOpt) {\n                    compatTextStyle(axisOpt, 'axisLabel');\n                    compatTextStyle(axisOpt.axisPointer, 'label');\n                }\n            });\n        }\n    );\n\n    each$5(toArr(option.parallel), function (parallelOpt) {\n        var parallelAxisDefault = parallelOpt && parallelOpt.parallelAxisDefault;\n        compatTextStyle(parallelAxisDefault, 'axisLabel');\n        compatTextStyle(parallelAxisDefault && parallelAxisDefault.axisPointer, 'label');\n    });\n\n    each$5(toArr(option.calendar), function (calendarOpt) {\n        convertNormalEmphasis(calendarOpt, 'itemStyle');\n        compatTextStyle(calendarOpt, 'dayLabel');\n        compatTextStyle(calendarOpt, 'monthLabel');\n        compatTextStyle(calendarOpt, 'yearLabel');\n    });\n\n    // radar.name.textStyle\n    each$5(toArr(option.radar), function (radarOpt) {\n        compatTextStyle(radarOpt, 'name');\n    });\n\n    each$5(toArr(option.geo), function (geoOpt) {\n        if (isObject$3(geoOpt)) {\n            compatEC3CommonStyles(geoOpt);\n            each$5(toArr(geoOpt.regions), function (regionObj) {\n                compatEC3CommonStyles(regionObj);\n            });\n        }\n    });\n\n    each$5(toArr(option.timeline), function (timelineOpt) {\n        compatEC3CommonStyles(timelineOpt);\n        convertNormalEmphasis(timelineOpt, 'label');\n        convertNormalEmphasis(timelineOpt, 'itemStyle');\n        convertNormalEmphasis(timelineOpt, 'controlStyle', true);\n\n        var data = timelineOpt.data;\n        isArray(data) && each$1(data, function (item) {\n            if (isObject$1(item)) {\n                convertNormalEmphasis(item, 'label');\n                convertNormalEmphasis(item, 'itemStyle');\n            }\n        });\n    });\n\n    each$5(toArr(option.toolbox), function (toolboxOpt) {\n        convertNormalEmphasis(toolboxOpt, 'iconStyle');\n        each$5(toolboxOpt.feature, function (featureOpt) {\n            convertNormalEmphasis(featureOpt, 'iconStyle');\n        });\n    });\n\n    compatTextStyle(toObj(option.axisPointer), 'label');\n    compatTextStyle(toObj(option.tooltip).axisPointer, 'label');\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Compatitable with 2.0\n\nfunction get(opt, path) {\n    path = path.split(',');\n    var obj = opt;\n    for (var i = 0; i < path.length; i++) {\n        obj = obj && obj[path[i]];\n        if (obj == null) {\n            break;\n        }\n    }\n    return obj;\n}\n\nfunction set$1(opt, path, val, overwrite) {\n    path = path.split(',');\n    var obj = opt;\n    var key;\n    for (var i = 0; i < path.length - 1; i++) {\n        key = path[i];\n        if (obj[key] == null) {\n            obj[key] = {};\n        }\n        obj = obj[key];\n    }\n    if (overwrite || obj[path[i]] == null) {\n        obj[path[i]] = val;\n    }\n}\n\nfunction compatLayoutProperties(option) {\n    each$1(LAYOUT_PROPERTIES, function (prop) {\n        if (prop[0] in option && !(prop[1] in option)) {\n            option[prop[1]] = option[prop[0]];\n        }\n    });\n}\n\nvar LAYOUT_PROPERTIES = [\n    ['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom']\n];\n\nvar COMPATITABLE_COMPONENTS = [\n    'grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline'\n];\n\nvar backwardCompat = function (option, isTheme) {\n    compatStyle(option, isTheme);\n\n    // Make sure series array for model initialization.\n    option.series = normalizeToArray(option.series);\n\n    each$1(option.series, function (seriesOpt) {\n        if (!isObject$1(seriesOpt)) {\n            return;\n        }\n\n        var seriesType = seriesOpt.type;\n\n        if (seriesType === 'pie' || seriesType === 'gauge') {\n            if (seriesOpt.clockWise != null) {\n                seriesOpt.clockwise = seriesOpt.clockWise;\n            }\n        }\n        if (seriesType === 'gauge') {\n            var pointerColor = get(seriesOpt, 'pointer.color');\n            pointerColor != null\n                && set$1(seriesOpt, 'itemStyle.normal.color', pointerColor);\n        }\n\n        compatLayoutProperties(seriesOpt);\n    });\n\n    // dataRange has changed to visualMap\n    if (option.dataRange) {\n        option.visualMap = option.dataRange;\n    }\n\n    each$1(COMPATITABLE_COMPONENTS, function (componentName) {\n        var options = option[componentName];\n        if (options) {\n            if (!isArray(options)) {\n                options = [options];\n            }\n            each$1(options, function (option) {\n                compatLayoutProperties(option);\n            });\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (1) [Caution]: the logic is correct based on the premises:\n//     data processing stage is blocked in stream.\n//     See <module:echarts/stream/Scheduler#performDataProcessorTasks>\n// (2) Only register once when import repeatly.\n//     Should be executed before after series filtered and before stack calculation.\nvar dataStack = function (ecModel) {\n    var stackInfoMap = createHashMap();\n    ecModel.eachSeries(function (seriesModel) {\n        var stack = seriesModel.get('stack');\n        // Compatibal: when `stack` is set as '', do not stack.\n        if (stack) {\n            var stackInfoList = stackInfoMap.get(stack) || stackInfoMap.set(stack, []);\n            var data = seriesModel.getData();\n\n            var stackInfo = {\n                // Used for calculate axis extent automatically.\n                stackResultDimension: data.getCalculationInfo('stackResultDimension'),\n                stackedOverDimension: data.getCalculationInfo('stackedOverDimension'),\n                stackedDimension: data.getCalculationInfo('stackedDimension'),\n                stackedByDimension: data.getCalculationInfo('stackedByDimension'),\n                isStackedByIndex: data.getCalculationInfo('isStackedByIndex'),\n                data: data,\n                seriesModel: seriesModel\n            };\n\n            // If stacked on axis that do not support data stack.\n            if (!stackInfo.stackedDimension\n                || !(stackInfo.isStackedByIndex || stackInfo.stackedByDimension)\n            ) {\n                return;\n            }\n\n            stackInfoList.length && data.setCalculationInfo(\n                'stackedOnSeries', stackInfoList[stackInfoList.length - 1].seriesModel\n            );\n\n            stackInfoList.push(stackInfo);\n        }\n    });\n\n    stackInfoMap.each(calculateStack);\n};\n\nfunction calculateStack(stackInfoList) {\n    each$1(stackInfoList, function (targetStackInfo, idxInStack) {\n        var resultVal = [];\n        var resultNaN = [NaN, NaN];\n        var dims = [targetStackInfo.stackResultDimension, targetStackInfo.stackedOverDimension];\n        var targetData = targetStackInfo.data;\n        var isStackedByIndex = targetStackInfo.isStackedByIndex;\n\n        // Should not write on raw data, because stack series model list changes\n        // depending on legend selection.\n        var newData = targetData.map(dims, function (v0, v1, dataIndex) {\n            var sum = targetData.get(targetStackInfo.stackedDimension, dataIndex);\n\n            // Consider `connectNulls` of line area, if value is NaN, stackedOver\n            // should also be NaN, to draw a appropriate belt area.\n            if (isNaN(sum)) {\n                return resultNaN;\n            }\n\n            var byValue;\n            var stackedDataRawIndex;\n\n            if (isStackedByIndex) {\n                stackedDataRawIndex = targetData.getRawIndex(dataIndex);\n            }\n            else {\n                byValue = targetData.get(targetStackInfo.stackedByDimension, dataIndex);\n            }\n\n            // If stackOver is NaN, chart view will render point on value start.\n            var stackedOver = NaN;\n\n            for (var j = idxInStack - 1; j >= 0; j--) {\n                var stackInfo = stackInfoList[j];\n\n                // Has been optimized by inverted indices on `stackedByDimension`.\n                if (!isStackedByIndex) {\n                    stackedDataRawIndex = stackInfo.data.rawIndexOf(stackInfo.stackedByDimension, byValue);\n                }\n\n                if (stackedDataRawIndex >= 0) {\n                    var val = stackInfo.data.getByRawIndex(stackInfo.stackResultDimension, stackedDataRawIndex);\n\n                    // Considering positive stack, negative stack and empty data\n                    if ((sum >= 0 && val > 0) // Positive stack\n                        || (sum <= 0 && val < 0) // Negative stack\n                    ) {\n                        sum += val;\n                        stackedOver = val;\n                        break;\n                    }\n                }\n            }\n\n            resultVal[0] = sum;\n            resultVal[1] = stackedOver;\n\n            return resultVal;\n        });\n\n        targetData.hostModel.setData(newData);\n        // Update for consequent calculation\n        targetStackInfo.data = newData;\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO\n// ??? refactor? check the outer usage of data provider.\n// merge with defaultDimValueGetter?\n\n/**\n * If normal array used, mutable chunk size is supported.\n * If typed array used, chunk size must be fixed.\n */\nfunction DefaultDataProvider(source, dimSize) {\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n    this._source = source;\n\n    var data = this._data = source.data;\n    var sourceFormat = source.sourceFormat;\n\n    // Typed array. TODO IE10+?\n    if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {\n        if (__DEV__) {\n            if (dimSize == null) {\n                throw new Error('Typed array data must specify dimension size');\n            }\n        }\n        this._offset = 0;\n        this._dimSize = dimSize;\n        this._data = data;\n    }\n\n    var methods = providerMethods[\n        sourceFormat === SOURCE_FORMAT_ARRAY_ROWS\n        ? sourceFormat + '_' + source.seriesLayoutBy\n        : sourceFormat\n    ];\n\n    if (__DEV__) {\n        assert$1(methods, 'Invalide sourceFormat: ' + sourceFormat);\n    }\n\n    extend(this, methods);\n}\n\nvar providerProto = DefaultDataProvider.prototype;\n// If data is pure without style configuration\nproviderProto.pure = false;\n// If data is persistent and will not be released after use.\nproviderProto.persistent = true;\n\n// ???! FIXME legacy data provider do not has method getSource\nproviderProto.getSource = function () {\n    return this._source;\n};\n\nvar providerMethods = {\n\n    'arrayRows_column': {\n        pure: true,\n        count: function () {\n            return Math.max(0, this._data.length - this._source.startIndex);\n        },\n        getItem: function (idx) {\n            return this._data[idx + this._source.startIndex];\n        },\n        appendData: appendDataSimply\n    },\n\n    'arrayRows_row': {\n        pure: true,\n        count: function () {\n            var row = this._data[0];\n            return row ? Math.max(0, row.length - this._source.startIndex) : 0;\n        },\n        getItem: function (idx) {\n            idx += this._source.startIndex;\n            var item = [];\n            var data = this._data;\n            for (var i = 0; i < data.length; i++) {\n                var row = data[i];\n                item.push(row ? row[idx] : null);\n            }\n            return item;\n        },\n        appendData: function () {\n            throw new Error('Do not support appendData when set seriesLayoutBy: \"row\".');\n        }\n    },\n\n    'objectRows': {\n        pure: true,\n        count: countSimply,\n        getItem: getItemSimply,\n        appendData: appendDataSimply\n    },\n\n    'keyedColumns': {\n        pure: true,\n        count: function () {\n            var dimName = this._source.dimensionsDefine[0].name;\n            var col = this._data[dimName];\n            return col ? col.length : 0;\n        },\n        getItem: function (idx) {\n            var item = [];\n            var dims = this._source.dimensionsDefine;\n            for (var i = 0; i < dims.length; i++) {\n                var col = this._data[dims[i].name];\n                item.push(col ? col[idx] : null);\n            }\n            return item;\n        },\n        appendData: function (newData) {\n            var data = this._data;\n            each$1(newData, function (newCol, key) {\n                var oldCol = data[key] || (data[key] = []);\n                for (var i = 0; i < (newCol || []).length; i++) {\n                    oldCol.push(newCol[i]);\n                }\n            });\n        }\n    },\n\n    'original': {\n        count: countSimply,\n        getItem: getItemSimply,\n        appendData: appendDataSimply\n    },\n\n    'typedArray': {\n        persistent: false,\n        pure: true,\n        count: function () {\n            return this._data ? (this._data.length / this._dimSize) : 0;\n        },\n        getItem: function (idx, out) {\n            idx = idx - this._offset;\n            out = out || [];\n            var offset = this._dimSize * idx;\n            for (var i = 0; i < this._dimSize; i++) {\n                out[i] = this._data[offset + i];\n            }\n            return out;\n        },\n        appendData: function (newData) {\n            if (__DEV__) {\n                assert$1(\n                    isTypedArray(newData),\n                    'Added data must be TypedArray if data in initialization is TypedArray'\n                );\n            }\n\n            this._data = newData;\n        },\n\n        // Clean self if data is already used.\n        clean: function () {\n            // PENDING\n            this._offset += this.count();\n            this._data = null;\n        }\n    }\n};\n\nfunction countSimply() {\n    return this._data.length;\n}\nfunction getItemSimply(idx) {\n    return this._data[idx];\n}\nfunction appendDataSimply(newData) {\n    for (var i = 0; i < newData.length; i++) {\n        this._data.push(newData[i]);\n    }\n}\n\n\n\nvar rawValueGetters = {\n\n    arrayRows: getRawValueSimply,\n\n    objectRows: function (dataItem, dataIndex, dimIndex, dimName) {\n        return dimIndex != null ? dataItem[dimName] : dataItem;\n    },\n\n    keyedColumns: getRawValueSimply,\n\n    original: function (dataItem, dataIndex, dimIndex, dimName) {\n        // FIXME\n        // In some case (markpoint in geo (geo-map.html)), dataItem\n        // is {coord: [...]}\n        var value = getDataItemValue(dataItem);\n        return (dimIndex == null || !(value instanceof Array))\n            ? value\n            : value[dimIndex];\n    },\n\n    typedArray: getRawValueSimply\n};\n\nfunction getRawValueSimply(dataItem, dataIndex, dimIndex, dimName) {\n    return dimIndex != null ? dataItem[dimIndex] : dataItem;\n}\n\n\nvar defaultDimValueGetters = {\n\n    arrayRows: getDimValueSimply,\n\n    objectRows: function (dataItem, dimName, dataIndex, dimIndex) {\n        return converDataValue(dataItem[dimName], this._dimensionInfos[dimName]);\n    },\n\n    keyedColumns: getDimValueSimply,\n\n    original: function (dataItem, dimName, dataIndex, dimIndex) {\n        // Performance sensitive, do not use modelUtil.getDataItemValue.\n        // If dataItem is an plain object with no value field, the var `value`\n        // will be assigned with the object, but it will be tread correctly\n        // in the `convertDataValue`.\n        var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value);\n\n        // If any dataItem is like { value: 10 }\n        if (!this._rawData.pure && isDataItemOption(dataItem)) {\n            this.hasItemOption = true;\n        }\n        return converDataValue(\n            (value instanceof Array)\n                ? value[dimIndex]\n                // If value is a single number or something else not array.\n                : value,\n            this._dimensionInfos[dimName]\n        );\n    },\n\n    typedArray: function (dataItem, dimName, dataIndex, dimIndex) {\n        return dataItem[dimIndex];\n    }\n\n};\n\nfunction getDimValueSimply(dataItem, dimName, dataIndex, dimIndex) {\n    return converDataValue(dataItem[dimIndex], this._dimensionInfos[dimName]);\n}\n\n/**\n * This helper method convert value in data.\n * @param {string|number|Date} value\n * @param {Object|string} [dimInfo] If string (like 'x'), dimType defaults 'number'.\n *        If \"dimInfo.ordinalParseAndSave\", ordinal value can be parsed.\n */\nfunction converDataValue(value, dimInfo) {\n    // Performance sensitive.\n    var dimType = dimInfo && dimInfo.type;\n    if (dimType === 'ordinal') {\n        // If given value is a category string\n        var ordinalMeta = dimInfo && dimInfo.ordinalMeta;\n        return ordinalMeta\n            ? ordinalMeta.parseAndCollect(value)\n            : value;\n    }\n\n    if (dimType === 'time'\n        // spead up when using timestamp\n        && typeof value !== 'number'\n        && value != null\n        && value !== '-'\n    ) {\n        value = +parseDate(value);\n    }\n\n    // dimType defaults 'number'.\n    // If dimType is not ordinal and value is null or undefined or NaN or '-',\n    // parse to NaN.\n    return (value == null || value === '')\n        ? NaN\n        // If string (like '-'), using '+' parse to NaN\n        // If object, also parse to NaN\n        : +value;\n}\n\n// ??? FIXME can these logic be more neat: getRawValue, getRawDataItem,\n// Consider persistent.\n// Caution: why use raw value to display on label or tooltip?\n// A reason is to avoid format. For example time value we do not know\n// how to format is expected. More over, if stack is used, calculated\n// value may be 0.91000000001, which have brings trouble to display.\n// TODO: consider how to treat null/undefined/NaN when display?\n/**\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @param {string|number} [dim] dimName or dimIndex\n * @return {Array.<number>|string|number} can be null/undefined.\n */\nfunction retrieveRawValue(data, dataIndex, dim) {\n    if (!data) {\n        return;\n    }\n\n    // Consider data may be not persistent.\n    var dataItem = data.getRawDataItem(dataIndex);\n\n    if (dataItem == null) {\n        return;\n    }\n\n    var sourceFormat = data.getProvider().getSource().sourceFormat;\n    var dimName;\n    var dimIndex;\n\n    var dimInfo = data.getDimensionInfo(dim);\n    if (dimInfo) {\n        dimName = dimInfo.name;\n        dimIndex = dimInfo.index;\n    }\n\n    return rawValueGetters[sourceFormat](dataItem, dataIndex, dimIndex, dimName);\n}\n\n/**\n * Compatible with some cases (in pie, map) like:\n * data: [{name: 'xx', value: 5, selected: true}, ...]\n * where only sourceFormat is 'original' and 'objectRows' supported.\n *\n * ??? TODO\n * Supported detail options in data item when using 'arrayRows'.\n *\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @param {string} attr like 'selected'\n */\nfunction retrieveRawAttr(data, dataIndex, attr) {\n    if (!data) {\n        return;\n    }\n\n    var sourceFormat = data.getProvider().getSource().sourceFormat;\n\n    if (sourceFormat !== SOURCE_FORMAT_ORIGINAL\n        && sourceFormat !== SOURCE_FORMAT_OBJECT_ROWS\n    ) {\n        return;\n    }\n\n    var dataItem = data.getRawDataItem(dataIndex);\n    if (sourceFormat === SOURCE_FORMAT_ORIGINAL && !isObject$1(dataItem)) {\n        dataItem = null;\n    }\n    if (dataItem) {\n        return dataItem[attr];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DIMENSION_LABEL_REG = /\\{@(.+?)\\}/g;\n\n// PENDING A little ugly\nvar dataFormatMixin = {\n    /**\n     * Get params for formatter\n     * @param {number} dataIndex\n     * @param {string} [dataType]\n     * @return {Object}\n     */\n    getDataParams: function (dataIndex, dataType) {\n        var data = this.getData(dataType);\n        var rawValue = this.getRawValue(dataIndex, dataType);\n        var rawDataIndex = data.getRawIndex(dataIndex);\n        var name = data.getName(dataIndex);\n        var itemOpt = data.getRawDataItem(dataIndex);\n        var color = data.getItemVisual(dataIndex, 'color');\n        var tooltipModel = this.ecModel.getComponent('tooltip');\n        var renderModeOption = tooltipModel && tooltipModel.get('renderMode');\n        var renderMode = getTooltipRenderMode(renderModeOption);\n        var mainType = this.mainType;\n        var isSeries = mainType === 'series';\n\n        return {\n            componentType: mainType,\n            componentSubType: this.subType,\n            componentIndex: this.componentIndex,\n            seriesType: isSeries ? this.subType : null,\n            seriesIndex: this.seriesIndex,\n            seriesId: isSeries ? this.id : null,\n            seriesName: isSeries ? this.name : null,\n            name: name,\n            dataIndex: rawDataIndex,\n            data: itemOpt,\n            dataType: dataType,\n            value: rawValue,\n            color: color,\n            marker: getTooltipMarker({\n                color: color,\n                renderMode: renderMode\n            }),\n\n            // Param name list for mapping `a`, `b`, `c`, `d`, `e`\n            $vars: ['seriesName', 'name', 'value']\n        };\n    },\n\n    /**\n     * Format label\n     * @param {number} dataIndex\n     * @param {string} [status='normal'] 'normal' or 'emphasis'\n     * @param {string} [dataType]\n     * @param {number} [dimIndex]\n     * @param {string} [labelProp='label']\n     * @return {string} If not formatter, return null/undefined\n     */\n    getFormattedLabel: function (dataIndex, status, dataType, dimIndex, labelProp) {\n        status = status || 'normal';\n        var data = this.getData(dataType);\n        var itemModel = data.getItemModel(dataIndex);\n\n        var params = this.getDataParams(dataIndex, dataType);\n        if (dimIndex != null && (params.value instanceof Array)) {\n            params.value = params.value[dimIndex];\n        }\n\n        var formatter = itemModel.get(\n            status === 'normal'\n            ? [labelProp || 'label', 'formatter']\n            : [status, labelProp || 'label', 'formatter']\n        );\n\n        if (typeof formatter === 'function') {\n            params.status = status;\n            return formatter(params);\n        }\n        else if (typeof formatter === 'string') {\n            var str = formatTpl(formatter, params);\n\n            // Support 'aaa{@[3]}bbb{@product}ccc'.\n            // Do not support '}' in dim name util have to.\n            return str.replace(DIMENSION_LABEL_REG, function (origin, dim) {\n                var len = dim.length;\n                if (dim.charAt(0) === '[' && dim.charAt(len - 1) === ']') {\n                    dim = +dim.slice(1, len - 1); // Also: '[]' => 0\n                }\n                return retrieveRawValue(data, dataIndex, dim);\n            });\n        }\n    },\n\n    /**\n     * Get raw value in option\n     * @param {number} idx\n     * @param {string} [dataType]\n     * @return {Array|number|string}\n     */\n    getRawValue: function (idx, dataType) {\n        return retrieveRawValue(this.getData(dataType), idx);\n    },\n\n    /**\n     * Should be implemented.\n     * @param {number} dataIndex\n     * @param {boolean} [multipleSeries=false]\n     * @param {number} [dataType]\n     * @return {string} tooltip string\n     */\n    formatTooltip: function () {\n        // Empty function\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} define\n * @return See the return of `createTask`.\n */\nfunction createTask(define) {\n    return new Task(define);\n}\n\n/**\n * @constructor\n * @param {Object} define\n * @param {Function} define.reset Custom reset\n * @param {Function} [define.plan] Returns 'reset' indicate reset immediately.\n * @param {Function} [define.count] count is used to determin data task.\n * @param {Function} [define.onDirty] count is used to determin data task.\n */\nfunction Task(define) {\n    define = define || {};\n\n    this._reset = define.reset;\n    this._plan = define.plan;\n    this._count = define.count;\n    this._onDirty = define.onDirty;\n\n    this._dirty = true;\n\n    // Context must be specified implicitly, to\n    // avoid miss update context when model changed.\n    this.context;\n}\n\nvar taskProto = Task.prototype;\n\n/**\n * @param {Object} performArgs\n * @param {number} [performArgs.step] Specified step.\n * @param {number} [performArgs.skip] Skip customer perform call.\n * @param {number} [performArgs.modBy] Sampling window size.\n * @param {number} [performArgs.modDataCount] Sampling count.\n */\ntaskProto.perform = function (performArgs) {\n    var upTask = this._upstream;\n    var skip = performArgs && performArgs.skip;\n\n    // TODO some refactor.\n    // Pull data. Must pull data each time, because context.data\n    // may be updated by Series.setData.\n    if (this._dirty && upTask) {\n        var context = this.context;\n        context.data = context.outputData = upTask.context.outputData;\n    }\n\n    if (this.__pipeline) {\n        this.__pipeline.currentTask = this;\n    }\n\n    var planResult;\n    if (this._plan && !skip) {\n        planResult = this._plan(this.context);\n    }\n\n    // Support sharding by mod, which changes the render sequence and makes the rendered graphic\n    // elements uniformed distributed when progress, especially when moving or zooming.\n    var lastModBy = normalizeModBy(this._modBy);\n    var lastModDataCount = this._modDataCount || 0;\n    var modBy = normalizeModBy(performArgs && performArgs.modBy);\n    var modDataCount = performArgs && performArgs.modDataCount || 0;\n    if (lastModBy !== modBy || lastModDataCount !== modDataCount) {\n        planResult = 'reset';\n    }\n\n    function normalizeModBy(val) {\n        !(val >= 1) && (val = 1); // jshint ignore:line\n        return val;\n    }\n\n    var forceFirstProgress;\n    if (this._dirty || planResult === 'reset') {\n        this._dirty = false;\n        forceFirstProgress = reset(this, skip);\n    }\n\n    this._modBy = modBy;\n    this._modDataCount = modDataCount;\n\n    var step = performArgs && performArgs.step;\n\n    if (upTask) {\n\n        if (__DEV__) {\n            assert$1(upTask._outputDueEnd != null);\n        }\n        this._dueEnd = upTask._outputDueEnd;\n    }\n    // DataTask or overallTask\n    else {\n        if (__DEV__) {\n            assert$1(!this._progress || this._count);\n        }\n        this._dueEnd = this._count ? this._count(this.context) : Infinity;\n    }\n\n    // Note: Stubs, that its host overall task let it has progress, has progress.\n    // If no progress, pass index from upstream to downstream each time plan called.\n    if (this._progress) {\n        var start = this._dueIndex;\n        var end = Math.min(\n            step != null ? this._dueIndex + step : Infinity,\n            this._dueEnd\n        );\n\n        if (!skip && (forceFirstProgress || start < end)) {\n            var progress = this._progress;\n            if (isArray(progress)) {\n                for (var i = 0; i < progress.length; i++) {\n                    doProgress(this, progress[i], start, end, modBy, modDataCount);\n                }\n            }\n            else {\n                doProgress(this, progress, start, end, modBy, modDataCount);\n            }\n        }\n\n        this._dueIndex = end;\n        // If no `outputDueEnd`, assume that output data and\n        // input data is the same, so use `dueIndex` as `outputDueEnd`.\n        var outputDueEnd = this._settedOutputEnd != null\n            ? this._settedOutputEnd : end;\n\n        if (__DEV__) {\n            // ??? Can not rollback.\n            assert$1(outputDueEnd >= this._outputDueEnd);\n        }\n\n        this._outputDueEnd = outputDueEnd;\n    }\n    else {\n        // (1) Some overall task has no progress.\n        // (2) Stubs, that its host overall task do not let it has progress, has no progress.\n        // This should always be performed so it can be passed to downstream.\n        this._dueIndex = this._outputDueEnd = this._settedOutputEnd != null\n            ? this._settedOutputEnd : this._dueEnd;\n    }\n\n    return this.unfinished();\n};\n\nvar iterator = (function () {\n\n    var end;\n    var current;\n    var modBy;\n    var modDataCount;\n    var winCount;\n\n    var it = {\n        reset: function (s, e, sStep, sCount) {\n            current = s;\n            end = e;\n\n            modBy = sStep;\n            modDataCount = sCount;\n            winCount = Math.ceil(modDataCount / modBy);\n\n            it.next = (modBy > 1 && modDataCount > 0) ? modNext : sequentialNext;\n        }\n    };\n\n    return it;\n\n    function sequentialNext() {\n        return current < end ? current++ : null;\n    }\n\n    function modNext() {\n        var dataIndex = (current % winCount) * modBy + Math.ceil(current / winCount);\n        var result = current >= end\n            ? null\n            : dataIndex < modDataCount\n            ? dataIndex\n            // If modDataCount is smaller than data.count() (consider `appendData` case),\n            // Use normal linear rendering mode.\n            : current;\n        current++;\n        return result;\n    }\n})();\n\ntaskProto.dirty = function () {\n    this._dirty = true;\n    this._onDirty && this._onDirty(this.context);\n};\n\nfunction doProgress(taskIns, progress, start, end, modBy, modDataCount) {\n    iterator.reset(start, end, modBy, modDataCount);\n    taskIns._callingProgress = progress;\n    taskIns._callingProgress({\n        start: start, end: end, count: end - start, next: iterator.next\n    }, taskIns.context);\n}\n\nfunction reset(taskIns, skip) {\n    taskIns._dueIndex = taskIns._outputDueEnd = taskIns._dueEnd = 0;\n    taskIns._settedOutputEnd = null;\n\n    var progress;\n    var forceFirstProgress;\n\n    if (!skip && taskIns._reset) {\n        progress = taskIns._reset(taskIns.context);\n        if (progress && progress.progress) {\n            forceFirstProgress = progress.forceFirstProgress;\n            progress = progress.progress;\n        }\n        // To simplify no progress checking, array must has item.\n        if (isArray(progress) && !progress.length) {\n            progress = null;\n        }\n    }\n\n    taskIns._progress = progress;\n    taskIns._modBy = taskIns._modDataCount = null;\n\n    var downstream = taskIns._downstream;\n    downstream && downstream.dirty();\n\n    return forceFirstProgress;\n}\n\n/**\n * @return {boolean}\n */\ntaskProto.unfinished = function () {\n    return this._progress && this._dueIndex < this._dueEnd;\n};\n\n/**\n * @param {Object} downTask The downstream task.\n * @return {Object} The downstream task.\n */\ntaskProto.pipe = function (downTask) {\n    if (__DEV__) {\n        assert$1(downTask && !downTask._disposed && downTask !== this);\n    }\n\n    // If already downstream, do not dirty downTask.\n    if (this._downstream !== downTask || this._dirty) {\n        this._downstream = downTask;\n        downTask._upstream = this;\n        downTask.dirty();\n    }\n};\n\ntaskProto.dispose = function () {\n    if (this._disposed) {\n        return;\n    }\n\n    this._upstream && (this._upstream._downstream = null);\n    this._downstream && (this._downstream._upstream = null);\n\n    this._dirty = false;\n    this._disposed = true;\n};\n\ntaskProto.getUpstream = function () {\n    return this._upstream;\n};\n\ntaskProto.getDownstream = function () {\n    return this._downstream;\n};\n\ntaskProto.setOutputEnd = function (end) {\n    // This only happend in dataTask, dataZoom, map, currently.\n    // where dataZoom do not set end each time, but only set\n    // when reset. So we should record the setted end, in case\n    // that the stub of dataZoom perform again and earse the\n    // setted end by upstream.\n    this._outputDueEnd = this._settedOutputEnd = end;\n};\n\n\n///////////////////////////////////////////////////////////\n// For stream debug (Should be commented out after used!)\n// Usage: printTask(this, 'begin');\n// Usage: printTask(this, null, {someExtraProp});\n// function printTask(task, prefix, extra) {\n//     window.ecTaskUID == null && (window.ecTaskUID = 0);\n//     task.uidDebug == null && (task.uidDebug = `task_${window.ecTaskUID++}`);\n//     task.agent && task.agent.uidDebug == null && (task.agent.uidDebug = `task_${window.ecTaskUID++}`);\n//     var props = [];\n//     if (task.__pipeline) {\n//         var val = `${task.__idxInPipeline}/${task.__pipeline.tail.__idxInPipeline} ${task.agent ? '(stub)' : ''}`;\n//         props.push({text: 'idx', value: val});\n//     } else {\n//         var stubCount = 0;\n//         task.agentStubMap.each(() => stubCount++);\n//         props.push({text: 'idx', value: `overall (stubs: ${stubCount})`});\n//     }\n//     props.push({text: 'uid', value: task.uidDebug});\n//     if (task.__pipeline) {\n//         props.push({text: 'pid', value: task.__pipeline.id});\n//         task.agent && props.push(\n//             {text: 'stubFor', value: task.agent.uidDebug}\n//         );\n//     }\n//     props.push(\n//         {text: 'dirty', value: task._dirty},\n//         {text: 'dueIndex', value: task._dueIndex},\n//         {text: 'dueEnd', value: task._dueEnd},\n//         {text: 'outputDueEnd', value: task._outputDueEnd}\n//     );\n//     if (extra) {\n//         Object.keys(extra).forEach(key => {\n//             props.push({text: key, value: extra[key]});\n//         });\n//     }\n//     var args = ['color: blue'];\n//     var msg = `%c[${prefix || 'T'}] %c` + props.map(item => (\n//         args.push('color: black', 'color: red'),\n//         `${item.text}: %c${item.value}`\n//     )).join('%c, ');\n//     console.log.apply(console, [msg].concat(args));\n//     // console.log(this);\n// }\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$4 = makeInner();\n\nvar SeriesModel = ComponentModel.extend({\n\n    type: 'series.__base__',\n\n    /**\n     * @readOnly\n     */\n    seriesIndex: 0,\n\n    // coodinateSystem will be injected in the echarts/CoordinateSystem\n    coordinateSystem: null,\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    defaultOption: null,\n\n    /**\n     * Data provided for legend\n     * @type {Function}\n     */\n    // PENDING\n    legendDataProvider: null,\n\n    /**\n     * Access path of color for visual\n     */\n    visualColorAccessPath: 'itemStyle.color',\n\n    /**\n     * Support merge layout params.\n     * Only support 'box' now (left/right/top/bottom/width/height).\n     * @type {string|Object} Object can be {ignoreSize: true}\n     * @readOnly\n     */\n    layoutMode: null,\n\n    init: function (option, parentModel, ecModel, extraOpt) {\n\n        /**\n         * @type {number}\n         * @readOnly\n         */\n        this.seriesIndex = this.componentIndex;\n\n        this.dataTask = createTask({\n            count: dataTaskCount,\n            reset: dataTaskReset\n        });\n        this.dataTask.context = {model: this};\n\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        prepareSource(this);\n\n\n        var data = this.getInitialData(option, ecModel);\n        wrapData(data, this);\n        this.dataTask.context.data = data;\n\n        if (__DEV__) {\n            assert$1(data, 'getInitialData returned invalid data.');\n        }\n\n        /**\n         * @type {module:echarts/data/List|module:echarts/data/Tree|module:echarts/data/Graph}\n         * @private\n         */\n        inner$4(this).dataBeforeProcessed = data;\n\n        // If we reverse the order (make data firstly, and then make\n        // dataBeforeProcessed by cloneShallow), cloneShallow will\n        // cause data.graph.data !== data when using\n        // module:echarts/data/Graph or module:echarts/data/Tree.\n        // See module:echarts/data/helper/linkList\n\n        // Theoretically, it is unreasonable to call `seriesModel.getData()` in the model\n        // init or merge stage, because the data can be restored. So we do not `restoreData`\n        // and `setData` here, which forbids calling `seriesModel.getData()` in this stage.\n        // Call `seriesModel.getRawData()` instead.\n        // this.restoreData();\n\n        autoSeriesName(this);\n    },\n\n    /**\n     * Util for merge default and theme to option\n     * @param  {Object} option\n     * @param  {module:echarts/model/Global} ecModel\n     */\n    mergeDefaultAndTheme: function (option, ecModel) {\n        var layoutMode = this.layoutMode;\n        var inputPositionParams = layoutMode\n            ? getLayoutParams(option) : {};\n\n        // Backward compat: using subType on theme.\n        // But if name duplicate between series subType\n        // (for example: parallel) add component mainType,\n        // add suffix 'Series'.\n        var themeSubType = this.subType;\n        if (ComponentModel.hasClass(themeSubType)) {\n            themeSubType += 'Series';\n        }\n        merge(\n            option,\n            ecModel.getTheme().get(this.subType)\n        );\n        merge(option, this.getDefaultOption());\n\n        // Default label emphasis `show`\n        defaultEmphasis(option, 'label', ['show']);\n\n        this.fillDataTextStyle(option.data);\n\n        if (layoutMode) {\n            mergeLayoutParam(option, inputPositionParams, layoutMode);\n        }\n    },\n\n    mergeOption: function (newSeriesOption, ecModel) {\n        // this.settingTask.dirty();\n\n        newSeriesOption = merge(this.option, newSeriesOption, true);\n        this.fillDataTextStyle(newSeriesOption.data);\n\n        var layoutMode = this.layoutMode;\n        if (layoutMode) {\n            mergeLayoutParam(this.option, newSeriesOption, layoutMode);\n        }\n\n        prepareSource(this);\n\n        var data = this.getInitialData(newSeriesOption, ecModel);\n        wrapData(data, this);\n        this.dataTask.dirty();\n        this.dataTask.context.data = data;\n\n        inner$4(this).dataBeforeProcessed = data;\n\n        autoSeriesName(this);\n    },\n\n    fillDataTextStyle: function (data) {\n        // Default data label emphasis `show`\n        // FIXME Tree structure data ?\n        // FIXME Performance ?\n        if (data && !isTypedArray(data)) {\n            var props = ['show'];\n            for (var i = 0; i < data.length; i++) {\n                if (data[i] && data[i].label) {\n                    defaultEmphasis(data[i], 'label', props);\n                }\n            }\n        }\n    },\n\n    /**\n     * Init a data structure from data related option in series\n     * Must be overwritten\n     */\n    getInitialData: function () {},\n\n    /**\n     * Append data to list\n     * @param {Object} params\n     * @param {Array|TypedArray} params.data\n     */\n    appendData: function (params) {\n        // FIXME ???\n        // (1) If data from dataset, forbidden append.\n        // (2) support append data of dataset.\n        var data = this.getRawData();\n        data.appendData(params.data);\n    },\n\n    /**\n     * Consider some method like `filter`, `map` need make new data,\n     * We should make sure that `seriesModel.getData()` get correct\n     * data in the stream procedure. So we fetch data from upstream\n     * each time `task.perform` called.\n     * @param {string} [dataType]\n     * @return {module:echarts/data/List}\n     */\n    getData: function (dataType) {\n        var task = getCurrentTask(this);\n        if (task) {\n            var data = task.context.data;\n            return dataType == null ? data : data.getLinkedData(dataType);\n        }\n        else {\n            // When series is not alive (that may happen when click toolbox\n            // restore or setOption with not merge mode), series data may\n            // be still need to judge animation or something when graphic\n            // elements want to know whether fade out.\n            return inner$4(this).data;\n        }\n    },\n\n    /**\n     * @param {module:echarts/data/List} data\n     */\n    setData: function (data) {\n        var task = getCurrentTask(this);\n        if (task) {\n            var context = task.context;\n            // Consider case: filter, data sample.\n            if (context.data !== data && task.modifyOutputEnd) {\n                task.setOutputEnd(data.count());\n            }\n            context.outputData = data;\n            // Caution: setData should update context.data,\n            // Because getData may be called multiply in a\n            // single stage and expect to get the data just\n            // set. (For example, AxisProxy, x y both call\n            // getData and setDate sequentially).\n            // So the context.data should be fetched from\n            // upstream each time when a stage starts to be\n            // performed.\n            if (task !== this.dataTask) {\n                context.data = data;\n            }\n        }\n        inner$4(this).data = data;\n    },\n\n    /**\n     * @see {module:echarts/data/helper/sourceHelper#getSource}\n     * @return {module:echarts/data/Source} source\n     */\n    getSource: function () {\n        return getSource(this);\n    },\n\n    /**\n     * Get data before processed\n     * @return {module:echarts/data/List}\n     */\n    getRawData: function () {\n        return inner$4(this).dataBeforeProcessed;\n    },\n\n    /**\n     * Get base axis if has coordinate system and has axis.\n     * By default use coordSys.getBaseAxis();\n     * Can be overrided for some chart.\n     * @return {type} description\n     */\n    getBaseAxis: function () {\n        var coordSys = this.coordinateSystem;\n        return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis();\n    },\n\n    // FIXME\n    /**\n     * Default tooltip formatter\n     *\n     * @param {number} dataIndex\n     * @param {boolean} [multipleSeries=false]\n     * @param {number} [dataType]\n     * @param {string} [renderMode='html'] valid values: 'html' and 'richText'.\n     *                                     'html' is used for rendering tooltip in extra DOM form, and the result\n     *                                     string is used as DOM HTML content.\n     *                                     'richText' is used for rendering tooltip in rich text form, for those where\n     *                                     DOM operation is not supported.\n     * @return {Object} formatted tooltip with `html` and `markers`\n     */\n    formatTooltip: function (dataIndex, multipleSeries, dataType, renderMode) {\n\n        var series = this;\n        renderMode = renderMode || 'html';\n        var newLine = renderMode === 'html' ? '<br/>' : '\\n';\n        var isRichText = renderMode === 'richText';\n        var markers = {};\n        var markerId = 0;\n\n        function formatArrayValue(value) {\n            // ??? TODO refactor these logic.\n            // check: category-no-encode-has-axis-data in dataset.html\n            var vertially = reduce(value, function (vertially, val, idx) {\n                var dimItem = data.getDimensionInfo(idx);\n                return vertially |= dimItem && dimItem.tooltip !== false && dimItem.displayName != null;\n            }, 0);\n\n            var result = [];\n\n            tooltipDims.length\n                ? each$1(tooltipDims, function (dim) {\n                    setEachItem(retrieveRawValue(data, dataIndex, dim), dim);\n                })\n                // By default, all dims is used on tooltip.\n                : each$1(value, setEachItem);\n\n            function setEachItem(val, dim) {\n                var dimInfo = data.getDimensionInfo(dim);\n                // If `dimInfo.tooltip` is not set, show tooltip.\n                if (!dimInfo || dimInfo.otherDims.tooltip === false) {\n                    return;\n                }\n                var dimType = dimInfo.type;\n                var markName = 'sub' + series.seriesIndex + 'at' + markerId;\n                var dimHead = getTooltipMarker({\n                    color: color,\n                    type: 'subItem',\n                    renderMode: renderMode,\n                    markerId: markName\n                });\n\n                var dimHeadStr = typeof dimHead === 'string' ? dimHead : dimHead.content;\n                var valStr = (vertially\n                        ? dimHeadStr + encodeHTML(dimInfo.displayName || '-') + ': '\n                        : ''\n                    )\n                    // FIXME should not format time for raw data?\n                    + encodeHTML(dimType === 'ordinal'\n                        ? val + ''\n                        : dimType === 'time'\n                        ? (multipleSeries ? '' : formatTime('yyyy/MM/dd hh:mm:ss', val))\n                        : addCommas(val)\n                    );\n                valStr && result.push(valStr);\n\n                if (isRichText) {\n                    markers[markName] = color;\n                    ++markerId;\n                }\n            }\n\n            var newLine = vertially ? (isRichText ? '\\n' : '<br/>') : '';\n            var content = newLine + result.join(newLine || ', ');\n            return {\n                renderMode: renderMode,\n                content: content,\n                style: markers\n            };\n        }\n\n        function formatSingleValue(val) {\n            // return encodeHTML(addCommas(val));\n            return {\n                renderMode: renderMode,\n                content: encodeHTML(addCommas(val)),\n                style: markers\n            };\n        }\n\n        var data = this.getData();\n        var tooltipDims = data.mapDimension('defaultedTooltip', true);\n        var tooltipDimLen = tooltipDims.length;\n        var value = this.getRawValue(dataIndex);\n        var isValueArr = isArray(value);\n\n        var color = data.getItemVisual(dataIndex, 'color');\n        if (isObject$1(color) && color.colorStops) {\n            color = (color.colorStops[0] || {}).color;\n        }\n        color = color || 'transparent';\n\n        // Complicated rule for pretty tooltip.\n        var formattedValue = (tooltipDimLen > 1 || (isValueArr && !tooltipDimLen))\n            ? formatArrayValue(value)\n            : tooltipDimLen\n            ? formatSingleValue(retrieveRawValue(data, dataIndex, tooltipDims[0]))\n            : formatSingleValue(isValueArr ? value[0] : value);\n        var content = formattedValue.content;\n\n        var markName = series.seriesIndex + 'at' + markerId;\n        var colorEl = getTooltipMarker({\n            color: color,\n            type: 'item',\n            renderMode: renderMode,\n            markerId: markName\n        });\n        markers[markName] = color;\n        ++markerId;\n\n        var name = data.getName(dataIndex);\n\n        var seriesName = this.name;\n        if (!isNameSpecified(this)) {\n            seriesName = '';\n        }\n        seriesName = seriesName\n            ? encodeHTML(seriesName) + (!multipleSeries ? newLine : ': ')\n            : '';\n\n        var colorStr = typeof colorEl === 'string' ? colorEl : colorEl.content;\n        var html = !multipleSeries\n            ? seriesName + colorStr\n                + (name\n                    ? encodeHTML(name) + ': ' + content\n                    : content\n                )\n            : colorStr + seriesName + content;\n\n        return {\n            html: html,\n            markers: markers\n        };\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isAnimationEnabled: function () {\n        if (env$1.node) {\n            return false;\n        }\n\n        var animationEnabled = this.getShallow('animation');\n        if (animationEnabled) {\n            if (this.getData().count() > this.getShallow('animationThreshold')) {\n                animationEnabled = false;\n            }\n        }\n        return animationEnabled;\n    },\n\n    restoreData: function () {\n        this.dataTask.dirty();\n    },\n\n    getColorFromPalette: function (name, scope, requestColorNum) {\n        var ecModel = this.ecModel;\n        // PENDING\n        var color = colorPaletteMixin.getColorFromPalette.call(this, name, scope, requestColorNum);\n        if (!color) {\n            color = ecModel.getColorFromPalette(name, scope, requestColorNum);\n        }\n        return color;\n    },\n\n    /**\n     * Use `data.mapDimension(coordDim, true)` instead.\n     * @deprecated\n     */\n    coordDimToDataDim: function (coordDim) {\n        return this.getRawData().mapDimension(coordDim, true);\n    },\n\n    /**\n     * Get progressive rendering count each step\n     * @return {number}\n     */\n    getProgressive: function () {\n        return this.get('progressive');\n    },\n\n    /**\n     * Get progressive rendering count each step\n     * @return {number}\n     */\n    getProgressiveThreshold: function () {\n        return this.get('progressiveThreshold');\n    },\n\n    /**\n     * Get data indices for show tooltip content. See tooltip.\n     * @abstract\n     * @param {Array.<string>|string} dim\n     * @param {Array.<number>} value\n     * @param {module:echarts/coord/single/SingleAxis} baseAxis\n     * @return {Object} {dataIndices, nestestValue}.\n     */\n    getAxisTooltipData: null,\n\n    /**\n     * See tooltip.\n     * @abstract\n     * @param {number} dataIndex\n     * @return {Array.<number>} Point of tooltip. null/undefined can be returned.\n     */\n    getTooltipPosition: null,\n\n    /**\n     * @see {module:echarts/stream/Scheduler}\n     */\n    pipeTask: null,\n\n    /**\n     * Convinient for override in extended class.\n     * @protected\n     * @type {Function}\n     */\n    preventIncremental: null,\n\n    /**\n     * @public\n     * @readOnly\n     * @type {Object}\n     */\n    pipelineContext: null\n\n});\n\n\nmixin(SeriesModel, dataFormatMixin);\nmixin(SeriesModel, colorPaletteMixin);\n\n/**\n * MUST be called after `prepareSource` called\n * Here we need to make auto series, especially for auto legend. But we\n * do not modify series.name in option to avoid side effects.\n */\nfunction autoSeriesName(seriesModel) {\n    // User specified name has higher priority, otherwise it may cause\n    // series can not be queried unexpectedly.\n    var name = seriesModel.name;\n    if (!isNameSpecified(seriesModel)) {\n        seriesModel.name = getSeriesAutoName(seriesModel) || name;\n    }\n}\n\nfunction getSeriesAutoName(seriesModel) {\n    var data = seriesModel.getRawData();\n    var dataDims = data.mapDimension('seriesName', true);\n    var nameArr = [];\n    each$1(dataDims, function (dataDim) {\n        var dimInfo = data.getDimensionInfo(dataDim);\n        dimInfo.displayName && nameArr.push(dimInfo.displayName);\n    });\n    return nameArr.join(' ');\n}\n\nfunction dataTaskCount(context) {\n    return context.model.getRawData().count();\n}\n\nfunction dataTaskReset(context) {\n    var seriesModel = context.model;\n    seriesModel.setData(seriesModel.getRawData().cloneShallow());\n    return dataTaskProgress;\n}\n\nfunction dataTaskProgress(param, context) {\n    // Avoid repead cloneShallow when data just created in reset.\n    if (param.end > context.outputData.count()) {\n        context.model.getRawData().cloneShallow(context.outputData);\n    }\n}\n\n// TODO refactor\nfunction wrapData(data, seriesModel) {\n    each$1(data.CHANGABLE_METHODS, function (methodName) {\n        data.wrapMethod(methodName, curry(onDataSelfChange, seriesModel));\n    });\n}\n\nfunction onDataSelfChange(seriesModel) {\n    var task = getCurrentTask(seriesModel);\n    if (task) {\n        // Consider case: filter, selectRange\n        task.setOutputEnd(this.count());\n    }\n}\n\nfunction getCurrentTask(seriesModel) {\n    var scheduler = (seriesModel.ecModel || {}).scheduler;\n    var pipeline = scheduler && scheduler.getPipeline(seriesModel.uid);\n\n    if (pipeline) {\n        // When pipline finished, the currrentTask keep the last\n        // task (renderTask).\n        var task = pipeline.currentTask;\n        if (task) {\n            var agentStubMap = task.agentStubMap;\n            if (agentStubMap) {\n                task = agentStubMap.get(seriesModel.uid);\n            }\n        }\n        return task;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar Component = function () {\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.uid = getUID('viewComponent');\n};\n\nComponent.prototype = {\n\n    constructor: Component,\n\n    init: function (ecModel, api) {},\n\n    render: function (componentModel, ecModel, api, payload) {},\n\n    dispose: function () {},\n\n    /**\n     * @param {string} eventType\n     * @param {Object} query\n     * @param {module:zrender/Element} targetEl\n     * @param {Object} packedEvent\n     * @return {boolen} Pass only when return `true`.\n     */\n    filterForExposedEvent: null\n\n};\n\nvar componentProto = Component.prototype;\ncomponentProto.updateView\n    = componentProto.updateLayout\n    = componentProto.updateVisual\n    = function (seriesModel, ecModel, api, payload) {\n        // Do nothing;\n    };\n// Enable Component.extend.\nenableClassExtend(Component);\n\n// Enable capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(Component, {registerWhenExtend: true});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @return {string} If large mode changed, return string 'reset';\n */\nvar createRenderPlanner = function () {\n    var inner = makeInner();\n\n    return function (seriesModel) {\n        var fields = inner(seriesModel);\n        var pipelineContext = seriesModel.pipelineContext;\n\n        var originalLarge = fields.large;\n        var originalProgressive = fields.progressiveRender;\n\n        var large = fields.large = pipelineContext.large;\n        var progressive = fields.progressiveRender = pipelineContext.progressiveRender;\n\n        return !!((originalLarge ^ large) || (originalProgressive ^ progressive)) && 'reset';\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$5 = makeInner();\nvar renderPlanner = createRenderPlanner();\n\nfunction Chart() {\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.uid = getUID('viewChart');\n\n    this.renderTask = createTask({\n        plan: renderTaskPlan,\n        reset: renderTaskReset\n    });\n    this.renderTask.context = {view: this};\n}\n\nChart.prototype = {\n\n    type: 'chart',\n\n    /**\n     * Init the chart.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    init: function (ecModel, api) {},\n\n    /**\n     * Render the chart.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    render: function (seriesModel, ecModel, api, payload) {},\n\n    /**\n     * Highlight series or specified data item.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    highlight: function (seriesModel, ecModel, api, payload) {\n        toggleHighlight(seriesModel.getData(), payload, 'emphasis');\n    },\n\n    /**\n     * Downplay series or specified data item.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    downplay: function (seriesModel, ecModel, api, payload) {\n        toggleHighlight(seriesModel.getData(), payload, 'normal');\n    },\n\n    /**\n     * Remove self.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    remove: function (ecModel, api) {\n        this.group.removeAll();\n    },\n\n    /**\n     * Dispose self.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    dispose: function () {},\n\n    /**\n     * Rendering preparation in progressive mode.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    incrementalPrepareRender: null,\n\n    /**\n     * Render in progressive mode.\n     * @param  {Object} params See taskParams in `stream/task.js`\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    incrementalRender: null,\n\n    /**\n     * Update transform directly.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     * @return {Object} {update: true}\n     */\n    updateTransform: null,\n\n    /**\n     * The view contains the given point.\n     * @interface\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    // containPoint: function () {}\n\n    /**\n     * @param {string} eventType\n     * @param {Object} query\n     * @param {module:zrender/Element} targetEl\n     * @param {Object} packedEvent\n     * @return {boolen} Pass only when return `true`.\n     */\n    filterForExposedEvent: null\n\n};\n\nvar chartProto = Chart.prototype;\nchartProto.updateView\n    = chartProto.updateLayout\n    = chartProto.updateVisual\n    = function (seriesModel, ecModel, api, payload) {\n        this.render(seriesModel, ecModel, api, payload);\n    };\n\n/**\n * Set state of single element\n * @param  {module:zrender/Element} el\n * @param  {string} state\n */\nfunction elSetState(el, state) {\n    if (el) {\n        el.trigger(state);\n        if (el.type === 'group') {\n            for (var i = 0; i < el.childCount(); i++) {\n                elSetState(el.childAt(i), state);\n            }\n        }\n    }\n}\n/**\n * @param  {module:echarts/data/List} data\n * @param  {Object} payload\n * @param  {string} state 'normal'|'emphasis'\n */\nfunction toggleHighlight(data, payload, state) {\n    var dataIndex = queryDataIndex(data, payload);\n\n    if (dataIndex != null) {\n        each$1(normalizeToArray(dataIndex), function (dataIdx) {\n            elSetState(data.getItemGraphicEl(dataIdx), state);\n        });\n    }\n    else {\n        data.eachItemGraphicEl(function (el) {\n            elSetState(el, state);\n        });\n    }\n}\n\n// Enable Chart.extend.\nenableClassExtend(Chart, ['dispose']);\n\n// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(Chart, {registerWhenExtend: true});\n\nChart.markUpdateMethod = function (payload, methodName) {\n    inner$5(payload).updateMethod = methodName;\n};\n\nfunction renderTaskPlan(context) {\n    return renderPlanner(context.model);\n}\n\nfunction renderTaskReset(context) {\n    var seriesModel = context.model;\n    var ecModel = context.ecModel;\n    var api = context.api;\n    var payload = context.payload;\n    // ???! remove updateView updateVisual\n    var progressiveRender = seriesModel.pipelineContext.progressiveRender;\n    var view = context.view;\n\n    var updateMethod = payload && inner$5(payload).updateMethod;\n    var methodName = progressiveRender\n        ? 'incrementalPrepareRender'\n        : (updateMethod && view[updateMethod])\n        ? updateMethod\n        // `appendData` is also supported when data amount\n        // is less than progressive threshold.\n        : 'render';\n\n    if (methodName !== 'render') {\n        view[methodName](seriesModel, ecModel, api, payload);\n    }\n\n    return progressMethodMap[methodName];\n}\n\nvar progressMethodMap = {\n    incrementalPrepareRender: {\n        progress: function (params, context) {\n            context.view.incrementalRender(\n                params, context.model, context.ecModel, context.api, context.payload\n            );\n        }\n    },\n    render: {\n        // Put view.render in `progress` to support appendData. But in this case\n        // view.render should not be called in reset, otherwise it will be called\n        // twise. Use `forceFirstProgress` to make sure that view.render is called\n        // in any cases.\n        forceFirstProgress: true,\n        progress: function (params, context) {\n            context.view.render(\n                context.model, context.ecModel, context.api, context.payload\n            );\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar ORIGIN_METHOD = '\\0__throttleOriginMethod';\nvar RATE = '\\0__throttleRate';\nvar THROTTLE_TYPE = '\\0__throttleType';\n\n/**\n * @public\n * @param {(Function)} fn\n * @param {number} [delay=0] Unit: ms.\n * @param {boolean} [debounce=false]\n *        true: If call interval less than `delay`, only the last call works.\n *        false: If call interval less than `delay, call works on fixed rate.\n * @return {(Function)} throttled fn.\n */\nfunction throttle(fn, delay, debounce) {\n\n    var currCall;\n    var lastCall = 0;\n    var lastExec = 0;\n    var timer = null;\n    var diff;\n    var scope;\n    var args;\n    var debounceNextCall;\n\n    delay = delay || 0;\n\n    function exec() {\n        lastExec = (new Date()).getTime();\n        timer = null;\n        fn.apply(scope, args || []);\n    }\n\n    var cb = function () {\n        currCall = (new Date()).getTime();\n        scope = this;\n        args = arguments;\n        var thisDelay = debounceNextCall || delay;\n        var thisDebounce = debounceNextCall || debounce;\n        debounceNextCall = null;\n        diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay;\n\n        clearTimeout(timer);\n\n        // Here we should make sure that: the `exec` SHOULD NOT be called later\n        // than a new call of `cb`, that is, preserving the command order. Consider\n        // calculating \"scale rate\" when roaming as an example. When a call of `cb`\n        // happens, either the `exec` is called dierectly, or the call is delayed.\n        // But the delayed call should never be later than next call of `cb`. Under\n        // this assurance, we can simply update view state each time `dispatchAction`\n        // triggered by user roaming, but not need to add extra code to avoid the\n        // state being \"rolled-back\".\n        if (thisDebounce) {\n            timer = setTimeout(exec, thisDelay);\n        }\n        else {\n            if (diff >= 0) {\n                exec();\n            }\n            else {\n                timer = setTimeout(exec, -diff);\n            }\n        }\n\n        lastCall = currCall;\n    };\n\n    /**\n     * Clear throttle.\n     * @public\n     */\n    cb.clear = function () {\n        if (timer) {\n            clearTimeout(timer);\n            timer = null;\n        }\n    };\n\n    /**\n     * Enable debounce once.\n     */\n    cb.debounceNextCall = function (debounceDelay) {\n        debounceNextCall = debounceDelay;\n    };\n\n    return cb;\n}\n\n/**\n * Create throttle method or update throttle rate.\n *\n * @example\n * ComponentView.prototype.render = function () {\n *     ...\n *     throttle.createOrUpdate(\n *         this,\n *         '_dispatchAction',\n *         this.model.get('throttle'),\n *         'fixRate'\n *     );\n * };\n * ComponentView.prototype.remove = function () {\n *     throttle.clear(this, '_dispatchAction');\n * };\n * ComponentView.prototype.dispose = function () {\n *     throttle.clear(this, '_dispatchAction');\n * };\n *\n * @public\n * @param {Object} obj\n * @param {string} fnAttr\n * @param {number} [rate]\n * @param {string} [throttleType='fixRate'] 'fixRate' or 'debounce'\n * @return {Function} throttled function.\n */\nfunction createOrUpdate(obj, fnAttr, rate, throttleType) {\n    var fn = obj[fnAttr];\n\n    if (!fn) {\n        return;\n    }\n\n    var originFn = fn[ORIGIN_METHOD] || fn;\n    var lastThrottleType = fn[THROTTLE_TYPE];\n    var lastRate = fn[RATE];\n\n    if (lastRate !== rate || lastThrottleType !== throttleType) {\n        if (rate == null || !throttleType) {\n            return (obj[fnAttr] = originFn);\n        }\n\n        fn = obj[fnAttr] = throttle(\n            originFn, rate, throttleType === 'debounce'\n        );\n        fn[ORIGIN_METHOD] = originFn;\n        fn[THROTTLE_TYPE] = throttleType;\n        fn[RATE] = rate;\n    }\n\n    return fn;\n}\n\n/**\n * Clear throttle. Example see throttle.createOrUpdate.\n *\n * @public\n * @param {Object} obj\n * @param {string} fnAttr\n */\nfunction clear(obj, fnAttr) {\n    var fn = obj[fnAttr];\n    if (fn && fn[ORIGIN_METHOD]) {\n        obj[fnAttr] = fn[ORIGIN_METHOD];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar seriesColor = {\n    createOnAllSeries: true,\n    performRawSeries: true,\n    reset: function (seriesModel, ecModel) {\n        var data = seriesModel.getData();\n        var colorAccessPath = (seriesModel.visualColorAccessPath || 'itemStyle.color').split('.');\n        var color = seriesModel.get(colorAccessPath) // Set in itemStyle\n            || seriesModel.getColorFromPalette(\n                // TODO series count changed.\n                seriesModel.name, null, ecModel.getSeriesCount()\n            );  // Default color\n\n        // FIXME Set color function or use the platte color\n        data.setVisual('color', color);\n\n        // Only visible series has each data be visual encoded\n        if (!ecModel.isSeriesFiltered(seriesModel)) {\n            if (typeof color === 'function' && !(color instanceof Gradient)) {\n                data.each(function (idx) {\n                    data.setItemVisual(\n                        idx, 'color', color(seriesModel.getDataParams(idx))\n                    );\n                });\n            }\n\n            // itemStyle in each data item\n            var dataEach = function (data, idx) {\n                var itemModel = data.getItemModel(idx);\n                var color = itemModel.get(colorAccessPath, true);\n                if (color != null) {\n                    data.setItemVisual(idx, 'color', color);\n                }\n            };\n\n            return { dataEach: data.hasItemOption ? dataEach : null };\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar lang = {\n    toolbox: {\n        brush: {\n            title: {\n                rect: 'Box Select',\n                polygon: 'Lasso Select',\n                lineX: 'Horizontally Select',\n                lineY: 'Vertically Select',\n                keep: 'Keep Selections',\n                clear: 'Clear Selections'\n            }\n        },\n        dataView: {\n            title: 'Data View',\n            lang: ['Data View', 'Close', 'Refresh']\n        },\n        dataZoom: {\n            title: {\n                zoom: 'Zoom',\n                back: 'Zoom Reset'\n            }\n        },\n        magicType: {\n            title: {\n                line: 'Switch to Line Chart',\n                bar: 'Switch to Bar Chart',\n                stack: 'Stack',\n                tiled: 'Tile'\n            }\n        },\n        restore: {\n            title: 'Restore'\n        },\n        saveAsImage: {\n            title: 'Save as Image',\n            lang: ['Right Click to Save Image']\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar aria = function (dom, ecModel) {\n    var ariaModel = ecModel.getModel('aria');\n    if (!ariaModel.get('show')) {\n        return;\n    }\n    else if (ariaModel.get('description')) {\n        dom.setAttribute('aria-label', ariaModel.get('description'));\n        return;\n    }\n\n    var seriesCnt = 0;\n    ecModel.eachSeries(function (seriesModel, idx) {\n        ++seriesCnt;\n    }, this);\n\n    var maxDataCnt = ariaModel.get('data.maxCount') || 10;\n    var maxSeriesCnt = ariaModel.get('series.maxCount') || 10;\n    var displaySeriesCnt = Math.min(seriesCnt, maxSeriesCnt);\n\n    var ariaLabel;\n    if (seriesCnt < 1) {\n        // No series, no aria label\n        return;\n    }\n    else {\n        var title = getTitle();\n        if (title) {\n            ariaLabel = replace(getConfig('general.withTitle'), {\n                title: title\n            });\n        }\n        else {\n            ariaLabel = getConfig('general.withoutTitle');\n        }\n\n        var seriesLabels = [];\n        var prefix = seriesCnt > 1\n            ? 'series.multiple.prefix'\n            : 'series.single.prefix';\n        ariaLabel += replace(getConfig(prefix), { seriesCount: seriesCnt });\n\n        ecModel.eachSeries(function (seriesModel, idx) {\n            if (idx < displaySeriesCnt) {\n                var seriesLabel;\n\n                var seriesName = seriesModel.get('name');\n                var seriesTpl = 'series.'\n                    + (seriesCnt > 1 ? 'multiple' : 'single') + '.';\n                seriesLabel = getConfig(seriesName\n                    ? seriesTpl + 'withName'\n                    : seriesTpl + 'withoutName');\n\n                seriesLabel = replace(seriesLabel, {\n                    seriesId: seriesModel.seriesIndex,\n                    seriesName: seriesModel.get('name'),\n                    seriesType: getSeriesTypeName(seriesModel.subType)\n                });\n\n                var data = seriesModel.getData();\n                window.data = data;\n                if (data.count() > maxDataCnt) {\n                    // Show part of data\n                    seriesLabel += replace(getConfig('data.partialData'), {\n                        displayCnt: maxDataCnt\n                    });\n                }\n                else {\n                    seriesLabel += getConfig('data.allData');\n                }\n\n                var dataLabels = [];\n                for (var i = 0; i < data.count(); i++) {\n                    if (i < maxDataCnt) {\n                        var name = data.getName(i);\n                        var value = retrieveRawValue(data, i);\n                        dataLabels.push(\n                            replace(\n                                name\n                                    ? getConfig('data.withName')\n                                    : getConfig('data.withoutName'),\n                                {\n                                    name: name,\n                                    value: value\n                                }\n                            )\n                        );\n                    }\n                }\n                seriesLabel += dataLabels\n                    .join(getConfig('data.separator.middle'))\n                    + getConfig('data.separator.end');\n\n                seriesLabels.push(seriesLabel);\n            }\n        });\n\n        ariaLabel += seriesLabels\n            .join(getConfig('series.multiple.separator.middle'))\n            + getConfig('series.multiple.separator.end');\n\n        dom.setAttribute('aria-label', ariaLabel);\n    }\n\n    function replace(str, keyValues) {\n        if (typeof str !== 'string') {\n            return str;\n        }\n\n        var result = str;\n        each$1(keyValues, function (value, key) {\n            result = result.replace(\n                new RegExp('\\\\{\\\\s*' + key + '\\\\s*\\\\}', 'g'),\n                value\n            );\n        });\n        return result;\n    }\n\n    function getConfig(path) {\n        var userConfig = ariaModel.get(path);\n        if (userConfig == null) {\n            var pathArr = path.split('.');\n            var result = lang.aria;\n            for (var i = 0; i < pathArr.length; ++i) {\n                result = result[pathArr[i]];\n            }\n            return result;\n        }\n        else {\n            return userConfig;\n        }\n    }\n\n    function getTitle() {\n        var title = ecModel.getModel('title').option;\n        if (title && title.length) {\n            title = title[0];\n        }\n        return title && title.text;\n    }\n\n    function getSeriesTypeName(type) {\n        return lang.series.typeNames[type] || '自定义图';\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PI$1 = Math.PI;\n\n/**\n * @param {module:echarts/ExtensionAPI} api\n * @param {Object} [opts]\n * @param {string} [opts.text]\n * @param {string} [opts.color]\n * @param {string} [opts.textColor]\n * @return {module:zrender/Element}\n */\nvar loadingDefault = function (api, opts) {\n    opts = opts || {};\n    defaults(opts, {\n        text: 'loading',\n        color: '#c23531',\n        textColor: '#000',\n        maskColor: 'rgba(255, 255, 255, 0.8)',\n        zlevel: 0\n    });\n    var mask = new Rect({\n        style: {\n            fill: opts.maskColor\n        },\n        zlevel: opts.zlevel,\n        z: 10000\n    });\n    var arc = new Arc({\n        shape: {\n            startAngle: -PI$1 / 2,\n            endAngle: -PI$1 / 2 + 0.1,\n            r: 10\n        },\n        style: {\n            stroke: opts.color,\n            lineCap: 'round',\n            lineWidth: 5\n        },\n        zlevel: opts.zlevel,\n        z: 10001\n    });\n    var labelRect = new Rect({\n        style: {\n            fill: 'none',\n            text: opts.text,\n            textPosition: 'right',\n            textDistance: 10,\n            textFill: opts.textColor\n        },\n        zlevel: opts.zlevel,\n        z: 10001\n    });\n\n    arc.animateShape(true)\n        .when(1000, {\n            endAngle: PI$1 * 3 / 2\n        })\n        .start('circularInOut');\n    arc.animateShape(true)\n        .when(1000, {\n            startAngle: PI$1 * 3 / 2\n        })\n        .delay(300)\n        .start('circularInOut');\n\n    var group = new Group();\n    group.add(arc);\n    group.add(labelRect);\n    group.add(mask);\n    // Inject resize\n    group.resize = function () {\n        var cx = api.getWidth() / 2;\n        var cy = api.getHeight() / 2;\n        arc.setShape({\n            cx: cx,\n            cy: cy\n        });\n        var r = arc.shape.r;\n        labelRect.setShape({\n            x: cx - r,\n            y: cy - r,\n            width: r * 2,\n            height: r * 2\n        });\n\n        mask.setShape({\n            x: 0,\n            y: 0,\n            width: api.getWidth(),\n            height: api.getHeight()\n        });\n    };\n    group.resize();\n    return group;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/stream/Scheduler\n */\n\n/**\n * @constructor\n */\nfunction Scheduler(ecInstance, api, dataProcessorHandlers, visualHandlers) {\n    this.ecInstance = ecInstance;\n    this.api = api;\n    this.unfinished;\n\n    // Fix current processors in case that in some rear cases that\n    // processors might be registered after echarts instance created.\n    // Register processors incrementally for a echarts instance is\n    // not supported by this stream architecture.\n    var dataProcessorHandlers = this._dataProcessorHandlers = dataProcessorHandlers.slice();\n    var visualHandlers = this._visualHandlers = visualHandlers.slice();\n    this._allHandlers = dataProcessorHandlers.concat(visualHandlers);\n\n    /**\n     * @private\n     * @type {\n     *     [handlerUID: string]: {\n     *         seriesTaskMap?: {\n     *             [seriesUID: string]: Task\n     *         },\n     *         overallTask?: Task\n     *     }\n     * }\n     */\n    this._stageTaskMap = createHashMap();\n}\n\nvar proto = Scheduler.prototype;\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} payload\n */\nproto.restoreData = function (ecModel, payload) {\n    // TODO: Only restroe needed series and components, but not all components.\n    // Currently `restoreData` of all of the series and component will be called.\n    // But some independent components like `title`, `legend`, `graphic`, `toolbox`,\n    // `tooltip`, `axisPointer`, etc, do not need series refresh when `setOption`,\n    // and some components like coordinate system, axes, dataZoom, visualMap only\n    // need their target series refresh.\n    // (1) If we are implementing this feature some day, we should consider these cases:\n    // if a data processor depends on a component (e.g., dataZoomProcessor depends\n    // on the settings of `dataZoom`), it should be re-performed if the component\n    // is modified by `setOption`.\n    // (2) If a processor depends on sevral series, speicified by its `getTargetSeries`,\n    // it should be re-performed when the result array of `getTargetSeries` changed.\n    // We use `dependencies` to cover these issues.\n    // (3) How to update target series when coordinate system related components modified.\n\n    // TODO: simply the dirty mechanism? Check whether only the case here can set tasks dirty,\n    // and this case all of the tasks will be set as dirty.\n\n    ecModel.restoreData(payload);\n\n    // Theoretically an overall task not only depends on each of its target series, but also\n    // depends on all of the series.\n    // The overall task is not in pipeline, and `ecModel.restoreData` only set pipeline tasks\n    // dirty. If `getTargetSeries` of an overall task returns nothing, we should also ensure\n    // that the overall task is set as dirty and to be performed, otherwise it probably cause\n    // state chaos. So we have to set dirty of all of the overall tasks manually, otherwise it\n    // probably cause state chaos (consider `dataZoomProcessor`).\n    this._stageTaskMap.each(function (taskRecord) {\n        var overallTask = taskRecord.overallTask;\n        overallTask && overallTask.dirty();\n    });\n};\n\n// If seriesModel provided, incremental threshold is check by series data.\nproto.getPerformArgs = function (task, isBlock) {\n    // For overall task\n    if (!task.__pipeline) {\n        return;\n    }\n\n    var pipeline = this._pipelineMap.get(task.__pipeline.id);\n    var pCtx = pipeline.context;\n    var incremental = !isBlock\n        && pipeline.progressiveEnabled\n        && (!pCtx || pCtx.progressiveRender)\n        && task.__idxInPipeline > pipeline.blockIndex;\n\n    var step = incremental ? pipeline.step : null;\n    var modDataCount = pCtx && pCtx.modDataCount;\n    var modBy = modDataCount != null ? Math.ceil(modDataCount / step) : null;\n\n    return {step: step, modBy: modBy, modDataCount: modDataCount};\n};\n\nproto.getPipeline = function (pipelineId) {\n    return this._pipelineMap.get(pipelineId);\n};\n\n/**\n * Current, progressive rendering starts from visual and layout.\n * Always detect render mode in the same stage, avoiding that incorrect\n * detection caused by data filtering.\n * Caution:\n * `updateStreamModes` use `seriesModel.getData()`.\n */\nproto.updateStreamModes = function (seriesModel, view) {\n    var pipeline = this._pipelineMap.get(seriesModel.uid);\n    var data = seriesModel.getData();\n    var dataLen = data.count();\n\n    // `progressiveRender` means that can render progressively in each\n    // animation frame. Note that some types of series do not provide\n    // `view.incrementalPrepareRender` but support `chart.appendData`. We\n    // use the term `incremental` but not `progressive` to describe the\n    // case that `chart.appendData`.\n    var progressiveRender = pipeline.progressiveEnabled\n        && view.incrementalPrepareRender\n        && dataLen >= pipeline.threshold;\n\n    var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold');\n\n    // TODO: modDataCount should not updated if `appendData`, otherwise cause whole repaint.\n    // see `test/candlestick-large3.html`\n    var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null;\n\n    seriesModel.pipelineContext = pipeline.context = {\n        progressiveRender: progressiveRender,\n        modDataCount: modDataCount,\n        large: large\n    };\n};\n\nproto.restorePipelines = function (ecModel) {\n    var scheduler = this;\n    var pipelineMap = scheduler._pipelineMap = createHashMap();\n\n    ecModel.eachSeries(function (seriesModel) {\n        var progressive = seriesModel.getProgressive();\n        var pipelineId = seriesModel.uid;\n\n        pipelineMap.set(pipelineId, {\n            id: pipelineId,\n            head: null,\n            tail: null,\n            threshold: seriesModel.getProgressiveThreshold(),\n            progressiveEnabled: progressive\n                && !(seriesModel.preventIncremental && seriesModel.preventIncremental()),\n            blockIndex: -1,\n            step: Math.round(progressive || 700),\n            count: 0\n        });\n\n        pipe(scheduler, seriesModel, seriesModel.dataTask);\n    });\n};\n\nproto.prepareStageTasks = function () {\n    var stageTaskMap = this._stageTaskMap;\n    var ecModel = this.ecInstance.getModel();\n    var api = this.api;\n\n    each$1(this._allHandlers, function (handler) {\n        var record = stageTaskMap.get(handler.uid) || stageTaskMap.set(handler.uid, []);\n\n        handler.reset && createSeriesStageTask(this, handler, record, ecModel, api);\n        handler.overallReset && createOverallStageTask(this, handler, record, ecModel, api);\n    }, this);\n};\n\nproto.prepareView = function (view, model, ecModel, api) {\n    var renderTask = view.renderTask;\n    var context = renderTask.context;\n\n    context.model = model;\n    context.ecModel = ecModel;\n    context.api = api;\n\n    renderTask.__block = !view.incrementalPrepareRender;\n\n    pipe(this, model, renderTask);\n};\n\n\nproto.performDataProcessorTasks = function (ecModel, payload) {\n    // If we do not use `block` here, it should be considered when to update modes.\n    performStageTasks(this, this._dataProcessorHandlers, ecModel, payload, {block: true});\n};\n\n// opt\n// opt.visualType: 'visual' or 'layout'\n// opt.setDirty\nproto.performVisualTasks = function (ecModel, payload, opt) {\n    performStageTasks(this, this._visualHandlers, ecModel, payload, opt);\n};\n\nfunction performStageTasks(scheduler, stageHandlers, ecModel, payload, opt) {\n    opt = opt || {};\n    var unfinished;\n\n    each$1(stageHandlers, function (stageHandler, idx) {\n        if (opt.visualType && opt.visualType !== stageHandler.visualType) {\n            return;\n        }\n\n        var stageHandlerRecord = scheduler._stageTaskMap.get(stageHandler.uid);\n        var seriesTaskMap = stageHandlerRecord.seriesTaskMap;\n        var overallTask = stageHandlerRecord.overallTask;\n\n        if (overallTask) {\n            var overallNeedDirty;\n            var agentStubMap = overallTask.agentStubMap;\n            agentStubMap.each(function (stub) {\n                if (needSetDirty(opt, stub)) {\n                    stub.dirty();\n                    overallNeedDirty = true;\n                }\n            });\n            overallNeedDirty && overallTask.dirty();\n            updatePayload(overallTask, payload);\n            var performArgs = scheduler.getPerformArgs(overallTask, opt.block);\n            // Execute stubs firstly, which may set the overall task dirty,\n            // then execute the overall task. And stub will call seriesModel.setData,\n            // which ensures that in the overallTask seriesModel.getData() will not\n            // return incorrect data.\n            agentStubMap.each(function (stub) {\n                stub.perform(performArgs);\n            });\n            unfinished |= overallTask.perform(performArgs);\n        }\n        else if (seriesTaskMap) {\n            seriesTaskMap.each(function (task, pipelineId) {\n                if (needSetDirty(opt, task)) {\n                    task.dirty();\n                }\n                var performArgs = scheduler.getPerformArgs(task, opt.block);\n                performArgs.skip = !stageHandler.performRawSeries\n                    && ecModel.isSeriesFiltered(task.context.model);\n                updatePayload(task, payload);\n                unfinished |= task.perform(performArgs);\n            });\n        }\n    });\n\n    function needSetDirty(opt, task) {\n        return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id));\n    }\n\n    scheduler.unfinished |= unfinished;\n}\n\nproto.performSeriesTasks = function (ecModel) {\n    var unfinished;\n\n    ecModel.eachSeries(function (seriesModel) {\n        // Progress to the end for dataInit and dataRestore.\n        unfinished |= seriesModel.dataTask.perform();\n    });\n\n    this.unfinished |= unfinished;\n};\n\nproto.plan = function () {\n    // Travel pipelines, check block.\n    this._pipelineMap.each(function (pipeline) {\n        var task = pipeline.tail;\n        do {\n            if (task.__block) {\n                pipeline.blockIndex = task.__idxInPipeline;\n                break;\n            }\n            task = task.getUpstream();\n        }\n        while (task);\n    });\n};\n\nvar updatePayload = proto.updatePayload = function (task, payload) {\n    payload !== 'remain' && (task.context.payload = payload);\n};\n\nfunction createSeriesStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) {\n    var seriesTaskMap = stageHandlerRecord.seriesTaskMap\n        || (stageHandlerRecord.seriesTaskMap = createHashMap());\n    var seriesType = stageHandler.seriesType;\n    var getTargetSeries = stageHandler.getTargetSeries;\n\n    // If a stageHandler should cover all series, `createOnAllSeries` should be declared mandatorily,\n    // to avoid some typo or abuse. Otherwise if an extension do not specify a `seriesType`,\n    // it works but it may cause other irrelevant charts blocked.\n    if (stageHandler.createOnAllSeries) {\n        ecModel.eachRawSeries(create);\n    }\n    else if (seriesType) {\n        ecModel.eachRawSeriesByType(seriesType, create);\n    }\n    else if (getTargetSeries) {\n        getTargetSeries(ecModel, api).each(create);\n    }\n\n    function create(seriesModel) {\n        var pipelineId = seriesModel.uid;\n\n        // Init tasks for each seriesModel only once.\n        // Reuse original task instance.\n        var task = seriesTaskMap.get(pipelineId)\n            || seriesTaskMap.set(pipelineId, createTask({\n                plan: seriesTaskPlan,\n                reset: seriesTaskReset,\n                count: seriesTaskCount\n            }));\n        task.context = {\n            model: seriesModel,\n            ecModel: ecModel,\n            api: api,\n            useClearVisual: stageHandler.isVisual && !stageHandler.isLayout,\n            plan: stageHandler.plan,\n            reset: stageHandler.reset,\n            scheduler: scheduler\n        };\n        pipe(scheduler, seriesModel, task);\n    }\n\n    // Clear unused series tasks.\n    var pipelineMap = scheduler._pipelineMap;\n    seriesTaskMap.each(function (task, pipelineId) {\n        if (!pipelineMap.get(pipelineId)) {\n            task.dispose();\n            seriesTaskMap.removeKey(pipelineId);\n        }\n    });\n}\n\nfunction createOverallStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) {\n    var overallTask = stageHandlerRecord.overallTask = stageHandlerRecord.overallTask\n        // For overall task, the function only be called on reset stage.\n        || createTask({reset: overallTaskReset});\n\n    overallTask.context = {\n        ecModel: ecModel,\n        api: api,\n        overallReset: stageHandler.overallReset,\n        scheduler: scheduler\n    };\n\n    // Reuse orignal stubs.\n    var agentStubMap = overallTask.agentStubMap = overallTask.agentStubMap || createHashMap();\n\n    var seriesType = stageHandler.seriesType;\n    var getTargetSeries = stageHandler.getTargetSeries;\n    var overallProgress = true;\n    var modifyOutputEnd = stageHandler.modifyOutputEnd;\n\n    // An overall task with seriesType detected or has `getTargetSeries`, we add\n    // stub in each pipelines, it will set the overall task dirty when the pipeline\n    // progress. Moreover, to avoid call the overall task each frame (too frequent),\n    // we set the pipeline block.\n    if (seriesType) {\n        ecModel.eachRawSeriesByType(seriesType, createStub);\n    }\n    else if (getTargetSeries) {\n        getTargetSeries(ecModel, api).each(createStub);\n    }\n    // Otherwise, (usually it is legancy case), the overall task will only be\n    // executed when upstream dirty. Otherwise the progressive rendering of all\n    // pipelines will be disabled unexpectedly. But it still needs stubs to receive\n    // dirty info from upsteam.\n    else {\n        overallProgress = false;\n        each$1(ecModel.getSeries(), createStub);\n    }\n\n    function createStub(seriesModel) {\n        var pipelineId = seriesModel.uid;\n        var stub = agentStubMap.get(pipelineId);\n        if (!stub) {\n            stub = agentStubMap.set(pipelineId, createTask(\n                {reset: stubReset, onDirty: stubOnDirty}\n            ));\n            // When the result of `getTargetSeries` changed, the overallTask\n            // should be set as dirty and re-performed.\n            overallTask.dirty();\n        }\n        stub.context = {\n            model: seriesModel,\n            overallProgress: overallProgress,\n            modifyOutputEnd: modifyOutputEnd\n        };\n        stub.agent = overallTask;\n        stub.__block = overallProgress;\n\n        pipe(scheduler, seriesModel, stub);\n    }\n\n    // Clear unused stubs.\n    var pipelineMap = scheduler._pipelineMap;\n    agentStubMap.each(function (stub, pipelineId) {\n        if (!pipelineMap.get(pipelineId)) {\n            stub.dispose();\n            // When the result of `getTargetSeries` changed, the overallTask\n            // should be set as dirty and re-performed.\n            overallTask.dirty();\n            agentStubMap.removeKey(pipelineId);\n        }\n    });\n}\n\nfunction overallTaskReset(context) {\n    context.overallReset(\n        context.ecModel, context.api, context.payload\n    );\n}\n\nfunction stubReset(context, upstreamContext) {\n    return context.overallProgress && stubProgress;\n}\n\nfunction stubProgress() {\n    this.agent.dirty();\n    this.getDownstream().dirty();\n}\n\nfunction stubOnDirty() {\n    this.agent && this.agent.dirty();\n}\n\nfunction seriesTaskPlan(context) {\n    return context.plan && context.plan(\n        context.model, context.ecModel, context.api, context.payload\n    );\n}\n\nfunction seriesTaskReset(context) {\n    if (context.useClearVisual) {\n        context.data.clearAllVisual();\n    }\n    var resetDefines = context.resetDefines = normalizeToArray(context.reset(\n        context.model, context.ecModel, context.api, context.payload\n    ));\n    return resetDefines.length > 1\n        ? map(resetDefines, function (v, idx) {\n            return makeSeriesTaskProgress(idx);\n        })\n        : singleSeriesTaskProgress;\n}\n\nvar singleSeriesTaskProgress = makeSeriesTaskProgress(0);\n\nfunction makeSeriesTaskProgress(resetDefineIdx) {\n    return function (params, context) {\n        var data = context.data;\n        var resetDefine = context.resetDefines[resetDefineIdx];\n\n        if (resetDefine && resetDefine.dataEach) {\n            for (var i = params.start; i < params.end; i++) {\n                resetDefine.dataEach(data, i);\n            }\n        }\n        else if (resetDefine && resetDefine.progress) {\n            resetDefine.progress(params, data);\n        }\n    };\n}\n\nfunction seriesTaskCount(context) {\n    return context.data.count();\n}\n\nfunction pipe(scheduler, seriesModel, task) {\n    var pipelineId = seriesModel.uid;\n    var pipeline = scheduler._pipelineMap.get(pipelineId);\n    !pipeline.head && (pipeline.head = task);\n    pipeline.tail && pipeline.tail.pipe(task);\n    pipeline.tail = task;\n    task.__idxInPipeline = pipeline.count++;\n    task.__pipeline = pipeline;\n}\n\nScheduler.wrapStageHandler = function (stageHandler, visualType) {\n    if (isFunction$1(stageHandler)) {\n        stageHandler = {\n            overallReset: stageHandler,\n            seriesType: detectSeriseType(stageHandler)\n        };\n    }\n\n    stageHandler.uid = getUID('stageHandler');\n    visualType && (stageHandler.visualType = visualType);\n\n    return stageHandler;\n};\n\n\n\n/**\n * Only some legacy stage handlers (usually in echarts extensions) are pure function.\n * To ensure that they can work normally, they should work in block mode, that is,\n * they should not be started util the previous tasks finished. So they cause the\n * progressive rendering disabled. We try to detect the series type, to narrow down\n * the block range to only the series type they concern, but not all series.\n */\nfunction detectSeriseType(legacyFunc) {\n    seriesType = null;\n    try {\n        // Assume there is no async when calling `eachSeriesByType`.\n        legacyFunc(ecModelMock, apiMock);\n    }\n    catch (e) {\n    }\n    return seriesType;\n}\n\nvar ecModelMock = {};\nvar apiMock = {};\nvar seriesType;\n\nmockMethods(ecModelMock, GlobalModel);\nmockMethods(apiMock, ExtensionAPI);\necModelMock.eachSeriesByType = ecModelMock.eachRawSeriesByType = function (type) {\n    seriesType = type;\n};\necModelMock.eachComponent = function (cond) {\n    if (cond.mainType === 'series' && cond.subType) {\n        seriesType = cond.subType;\n    }\n};\n\nfunction mockMethods(target, Clz) {\n    /* eslint-disable */\n    for (var name in Clz.prototype) {\n        // Do not use hasOwnProperty\n        target[name] = noop;\n    }\n    /* eslint-enable */\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar colorAll = [\n    '#37A2DA', '#32C5E9', '#67E0E3', '#9FE6B8', '#FFDB5C', '#ff9f7f',\n    '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF'\n];\n\nvar lightTheme = {\n\n    color: colorAll,\n\n    colorLayer: [\n        ['#37A2DA', '#ffd85c', '#fd7b5f'],\n        ['#37A2DA', '#67E0E3', '#FFDB5C', '#ff9f7f', '#E062AE', '#9d96f5'],\n        ['#37A2DA', '#32C5E9', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#e7bcf3', '#8378EA', '#96BFFF'],\n        colorAll\n    ]\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar contrastColor = '#eee';\nvar axisCommon = function () {\n    return {\n        axisLine: {\n            lineStyle: {\n                color: contrastColor\n            }\n        },\n        axisTick: {\n            lineStyle: {\n                color: contrastColor\n            }\n        },\n        axisLabel: {\n            textStyle: {\n                color: contrastColor\n            }\n        },\n        splitLine: {\n            lineStyle: {\n                type: 'dashed',\n                color: '#aaa'\n            }\n        },\n        splitArea: {\n            areaStyle: {\n                color: contrastColor\n            }\n        }\n    };\n};\n\nvar colorPalette = [\n    '#dd6b66', '#759aa0', '#e69d87', '#8dc1a9', '#ea7e53',\n    '#eedd78', '#73a373', '#73b9bc', '#7289ab', '#91ca8c', '#f49f42'\n];\nvar theme = {\n    color: colorPalette,\n    backgroundColor: '#333',\n    tooltip: {\n        axisPointer: {\n            lineStyle: {\n                color: contrastColor\n            },\n            crossStyle: {\n                color: contrastColor\n            }\n        }\n    },\n    legend: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    textStyle: {\n        color: contrastColor\n    },\n    title: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    toolbox: {\n        iconStyle: {\n            normal: {\n                borderColor: contrastColor\n            }\n        }\n    },\n    dataZoom: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    visualMap: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    timeline: {\n        lineStyle: {\n            color: contrastColor\n        },\n        itemStyle: {\n            normal: {\n                color: colorPalette[1]\n            }\n        },\n        label: {\n            normal: {\n                textStyle: {\n                    color: contrastColor\n                }\n            }\n        },\n        controlStyle: {\n            normal: {\n                color: contrastColor,\n                borderColor: contrastColor\n            }\n        }\n    },\n    timeAxis: axisCommon(),\n    logAxis: axisCommon(),\n    valueAxis: axisCommon(),\n    categoryAxis: axisCommon(),\n\n    line: {\n        symbol: 'circle'\n    },\n    graph: {\n        color: colorPalette\n    },\n    gauge: {\n        title: {\n            textStyle: {\n                color: contrastColor\n            }\n        }\n    },\n    candlestick: {\n        itemStyle: {\n            normal: {\n                color: '#FD1050',\n                color0: '#0CF49B',\n                borderColor: '#FD1050',\n                borderColor0: '#0CF49B'\n            }\n        }\n    }\n};\ntheme.categoryAxis.splitLine.show = false;\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * This module is imported by echarts directly.\n *\n * Notice:\n * Always keep this file exists for backward compatibility.\n * Because before 4.1.0, dataset is an optional component,\n * some users may import this module manually.\n */\n\nComponentModel.extend({\n\n    type: 'dataset',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n\n        // 'row', 'column'\n        seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN,\n\n        // null/'auto': auto detect header, see \"module:echarts/data/helper/sourceHelper\"\n        sourceHeader: null,\n\n        dimensions: null,\n\n        source: null\n    },\n\n    optionUpdated: function () {\n        detectSourceFormat(this);\n    }\n\n});\n\nComponent.extend({\n\n    type: 'dataset'\n\n});\n\n/**\n * 椭圆形状\n * @module zrender/graphic/shape/Ellipse\n */\n\nvar Ellipse = Path.extend({\n\n    type: 'ellipse',\n\n    shape: {\n        cx: 0, cy: 0,\n        rx: 0, ry: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var k = 0.5522848;\n        var x = shape.cx;\n        var y = shape.cy;\n        var a = shape.rx;\n        var b = shape.ry;\n        var ox = a * k; // 水平控制点偏移量\n        var oy = b * k; // 垂直控制点偏移量\n        // 从椭圆的左端点开始顺时针绘制四条三次贝塞尔曲线\n        ctx.moveTo(x - a, y);\n        ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b);\n        ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y);\n        ctx.bezierCurveTo(x + a, y + oy, x + ox, y + b, x, y + b);\n        ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y);\n        ctx.closePath();\n    }\n});\n\n// import RadialGradient from '../graphic/RadialGradient';\n// import Pattern from '../graphic/Pattern';\n// import * as vector from '../core/vector';\n// Most of the values can be separated by comma and/or white space.\nvar DILIMITER_REG = /[\\s,]+/;\n\n/**\n * For big svg string, this method might be time consuming.\n *\n * @param {string} svg xml string\n * @return {Object} xml root.\n */\nfunction parseXML(svg) {\n    if (isString(svg)) {\n        var parser = new DOMParser();\n        svg = parser.parseFromString(svg, 'text/xml');\n    }\n\n    // Document node. If using $.get, doc node may be input.\n    if (svg.nodeType === 9) {\n        svg = svg.firstChild;\n    }\n    // nodeName of <!DOCTYPE svg> is also 'svg'.\n    while (svg.nodeName.toLowerCase() !== 'svg' || svg.nodeType !== 1) {\n        svg = svg.nextSibling;\n    }\n\n    return svg;\n}\n\nfunction SVGParser() {\n    this._defs = {};\n    this._root = null;\n\n    this._isDefine = false;\n    this._isText = false;\n}\n\nSVGParser.prototype.parse = function (xml, opt) {\n    opt = opt || {};\n\n    var svg = parseXML(xml);\n\n    if (!svg) {\n        throw new Error('Illegal svg');\n    }\n\n    var root = new Group();\n    this._root = root;\n    // parse view port\n    var viewBox = svg.getAttribute('viewBox') || '';\n\n    // If width/height not specified, means \"100%\" of `opt.width/height`.\n    // TODO: Other percent value not supported yet.\n    var width = parseFloat(svg.getAttribute('width') || opt.width);\n    var height = parseFloat(svg.getAttribute('height') || opt.height);\n    // If width/height not specified, set as null for output.\n    isNaN(width) && (width = null);\n    isNaN(height) && (height = null);\n\n    // Apply inline style on svg element.\n    parseAttributes(svg, root, null, true);\n\n    var child = svg.firstChild;\n    while (child) {\n        this._parseNode(child, root);\n        child = child.nextSibling;\n    }\n\n    var viewBoxRect;\n    var viewBoxTransform;\n\n    if (viewBox) {\n        var viewBoxArr = trim(viewBox).split(DILIMITER_REG);\n        // Some invalid case like viewBox: 'none'.\n        if (viewBoxArr.length >= 4) {\n            viewBoxRect = {\n                x: parseFloat(viewBoxArr[0] || 0),\n                y: parseFloat(viewBoxArr[1] || 0),\n                width: parseFloat(viewBoxArr[2]),\n                height: parseFloat(viewBoxArr[3])\n            };\n        }\n    }\n\n    if (viewBoxRect && width != null && height != null) {\n        viewBoxTransform = makeViewBoxTransform(viewBoxRect, width, height);\n\n        if (!opt.ignoreViewBox) {\n            // If set transform on the output group, it probably bring trouble when\n            // some users only intend to show the clipped content inside the viewBox,\n            // but not intend to transform the output group. So we keep the output\n            // group no transform. If the user intend to use the viewBox as a\n            // camera, just set `opt.ignoreViewBox` as `true` and set transfrom\n            // manually according to the viewBox info in the output of this method.\n            var elRoot = root;\n            root = new Group();\n            root.add(elRoot);\n            elRoot.scale = viewBoxTransform.scale.slice();\n            elRoot.position = viewBoxTransform.position.slice();\n        }\n    }\n\n    // Some shapes might be overflow the viewport, which should be\n    // clipped despite whether the viewBox is used, as the SVG does.\n    if (!opt.ignoreRootClip && width != null && height != null) {\n        root.setClipPath(new Rect({\n            shape: {x: 0, y: 0, width: width, height: height}\n        }));\n    }\n\n    // Set width/height on group just for output the viewport size.\n    return {\n        root: root,\n        width: width,\n        height: height,\n        viewBoxRect: viewBoxRect,\n        viewBoxTransform: viewBoxTransform\n    };\n};\n\nSVGParser.prototype._parseNode = function (xmlNode, parentGroup) {\n\n    var nodeName = xmlNode.nodeName.toLowerCase();\n\n    // TODO\n    // support <style>...</style> in svg, where nodeName is 'style',\n    // CSS classes is defined globally wherever the style tags are declared.\n\n    if (nodeName === 'defs') {\n        // define flag\n        this._isDefine = true;\n    }\n    else if (nodeName === 'text') {\n        this._isText = true;\n    }\n\n    var el;\n    if (this._isDefine) {\n        var parser = defineParsers[nodeName];\n        if (parser) {\n            var def = parser.call(this, xmlNode);\n            var id = xmlNode.getAttribute('id');\n            if (id) {\n                this._defs[id] = def;\n            }\n        }\n    }\n    else {\n        var parser = nodeParsers[nodeName];\n        if (parser) {\n            el = parser.call(this, xmlNode, parentGroup);\n            parentGroup.add(el);\n        }\n    }\n\n    var child = xmlNode.firstChild;\n    while (child) {\n        if (child.nodeType === 1) {\n            this._parseNode(child, el);\n        }\n        // Is text\n        if (child.nodeType === 3 && this._isText) {\n            this._parseText(child, el);\n        }\n        child = child.nextSibling;\n    }\n\n    // Quit define\n    if (nodeName === 'defs') {\n        this._isDefine = false;\n    }\n    else if (nodeName === 'text') {\n        this._isText = false;\n    }\n};\n\nSVGParser.prototype._parseText = function (xmlNode, parentGroup) {\n    if (xmlNode.nodeType === 1) {\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n        this._textX += parseFloat(dx);\n        this._textY += parseFloat(dy);\n    }\n\n    var text = new Text({\n        style: {\n            text: xmlNode.textContent,\n            transformText: true\n        },\n        position: [this._textX || 0, this._textY || 0]\n    });\n\n    inheritStyle(parentGroup, text);\n    parseAttributes(xmlNode, text, this._defs);\n\n    var fontSize = text.style.fontSize;\n    if (fontSize && fontSize < 9) {\n        // PENDING\n        text.style.fontSize = 9;\n        text.scale = text.scale || [1, 1];\n        text.scale[0] *= fontSize / 9;\n        text.scale[1] *= fontSize / 9;\n    }\n\n    var rect = text.getBoundingRect();\n    this._textX += rect.width;\n\n    parentGroup.add(text);\n\n    return text;\n};\n\nvar nodeParsers = {\n    'g': function (xmlNode, parentGroup) {\n        var g = new Group();\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n        return g;\n    },\n    'rect': function (xmlNode, parentGroup) {\n        var rect = new Rect();\n        inheritStyle(parentGroup, rect);\n        parseAttributes(xmlNode, rect, this._defs);\n\n        rect.setShape({\n            x: parseFloat(xmlNode.getAttribute('x') || 0),\n            y: parseFloat(xmlNode.getAttribute('y') || 0),\n            width: parseFloat(xmlNode.getAttribute('width') || 0),\n            height: parseFloat(xmlNode.getAttribute('height') || 0)\n        });\n\n        // console.log(xmlNode.getAttribute('transform'));\n        // console.log(rect.transform);\n\n        return rect;\n    },\n    'circle': function (xmlNode, parentGroup) {\n        var circle = new Circle();\n        inheritStyle(parentGroup, circle);\n        parseAttributes(xmlNode, circle, this._defs);\n\n        circle.setShape({\n            cx: parseFloat(xmlNode.getAttribute('cx') || 0),\n            cy: parseFloat(xmlNode.getAttribute('cy') || 0),\n            r: parseFloat(xmlNode.getAttribute('r') || 0)\n        });\n\n        return circle;\n    },\n    'line': function (xmlNode, parentGroup) {\n        var line = new Line();\n        inheritStyle(parentGroup, line);\n        parseAttributes(xmlNode, line, this._defs);\n\n        line.setShape({\n            x1: parseFloat(xmlNode.getAttribute('x1') || 0),\n            y1: parseFloat(xmlNode.getAttribute('y1') || 0),\n            x2: parseFloat(xmlNode.getAttribute('x2') || 0),\n            y2: parseFloat(xmlNode.getAttribute('y2') || 0)\n        });\n\n        return line;\n    },\n    'ellipse': function (xmlNode, parentGroup) {\n        var ellipse = new Ellipse();\n        inheritStyle(parentGroup, ellipse);\n        parseAttributes(xmlNode, ellipse, this._defs);\n\n        ellipse.setShape({\n            cx: parseFloat(xmlNode.getAttribute('cx') || 0),\n            cy: parseFloat(xmlNode.getAttribute('cy') || 0),\n            rx: parseFloat(xmlNode.getAttribute('rx') || 0),\n            ry: parseFloat(xmlNode.getAttribute('ry') || 0)\n        });\n        return ellipse;\n    },\n    'polygon': function (xmlNode, parentGroup) {\n        var points = xmlNode.getAttribute('points');\n        if (points) {\n            points = parsePoints(points);\n        }\n        var polygon = new Polygon({\n            shape: {\n                points: points || []\n            }\n        });\n\n        inheritStyle(parentGroup, polygon);\n        parseAttributes(xmlNode, polygon, this._defs);\n\n        return polygon;\n    },\n    'polyline': function (xmlNode, parentGroup) {\n        var path = new Path();\n        inheritStyle(parentGroup, path);\n        parseAttributes(xmlNode, path, this._defs);\n\n        var points = xmlNode.getAttribute('points');\n        if (points) {\n            points = parsePoints(points);\n        }\n        var polyline = new Polyline({\n            shape: {\n                points: points || []\n            }\n        });\n\n        return polyline;\n    },\n    'image': function (xmlNode, parentGroup) {\n        var img = new ZImage();\n        inheritStyle(parentGroup, img);\n        parseAttributes(xmlNode, img, this._defs);\n\n        img.setStyle({\n            image: xmlNode.getAttribute('xlink:href'),\n            x: xmlNode.getAttribute('x'),\n            y: xmlNode.getAttribute('y'),\n            width: xmlNode.getAttribute('width'),\n            height: xmlNode.getAttribute('height')\n        });\n\n        return img;\n    },\n    'text': function (xmlNode, parentGroup) {\n        var x = xmlNode.getAttribute('x') || 0;\n        var y = xmlNode.getAttribute('y') || 0;\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n\n        this._textX = parseFloat(x) + parseFloat(dx);\n        this._textY = parseFloat(y) + parseFloat(dy);\n\n        var g = new Group();\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n        return g;\n    },\n    'tspan': function (xmlNode, parentGroup) {\n        var x = xmlNode.getAttribute('x');\n        var y = xmlNode.getAttribute('y');\n        if (x != null) {\n            // new offset x\n            this._textX = parseFloat(x);\n        }\n        if (y != null) {\n            // new offset y\n            this._textY = parseFloat(y);\n        }\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n\n        var g = new Group();\n\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n\n        this._textX += dx;\n        this._textY += dy;\n\n        return g;\n    },\n    'path': function (xmlNode, parentGroup) {\n        // TODO svg fill rule\n        // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule\n        // path.style.globalCompositeOperation = 'xor';\n        var d = xmlNode.getAttribute('d') || '';\n\n        // Performance sensitive.\n\n        var path = createFromString(d);\n\n        inheritStyle(parentGroup, path);\n        parseAttributes(xmlNode, path, this._defs);\n\n        return path;\n    }\n};\n\nvar defineParsers = {\n\n    'lineargradient': function (xmlNode) {\n        var x1 = parseInt(xmlNode.getAttribute('x1') || 0, 10);\n        var y1 = parseInt(xmlNode.getAttribute('y1') || 0, 10);\n        var x2 = parseInt(xmlNode.getAttribute('x2') || 10, 10);\n        var y2 = parseInt(xmlNode.getAttribute('y2') || 0, 10);\n\n        var gradient = new LinearGradient(x1, y1, x2, y2);\n\n        _parseGradientColorStops(xmlNode, gradient);\n\n        return gradient;\n    },\n\n    'radialgradient': function (xmlNode) {\n\n    }\n};\n\nfunction _parseGradientColorStops(xmlNode, gradient) {\n\n    var stop = xmlNode.firstChild;\n\n    while (stop) {\n        if (stop.nodeType === 1) {\n            var offset = stop.getAttribute('offset');\n            if (offset.indexOf('%') > 0) {  // percentage\n                offset = parseInt(offset, 10) / 100;\n            }\n            else if (offset) {    // number from 0 to 1\n                offset = parseFloat(offset);\n            }\n            else {\n                offset = 0;\n            }\n\n            var stopColor = stop.getAttribute('stop-color') || '#000000';\n\n            gradient.addColorStop(offset, stopColor);\n        }\n        stop = stop.nextSibling;\n    }\n}\n\nfunction inheritStyle(parent, child) {\n    if (parent && parent.__inheritedStyle) {\n        if (!child.__inheritedStyle) {\n            child.__inheritedStyle = {};\n        }\n        defaults(child.__inheritedStyle, parent.__inheritedStyle);\n    }\n}\n\nfunction parsePoints(pointsString) {\n    var list = trim(pointsString).split(DILIMITER_REG);\n    var points = [];\n\n    for (var i = 0; i < list.length; i += 2) {\n        var x = parseFloat(list[i]);\n        var y = parseFloat(list[i + 1]);\n        points.push([x, y]);\n    }\n    return points;\n}\n\nvar attributesMap = {\n    'fill': 'fill',\n    'stroke': 'stroke',\n    'stroke-width': 'lineWidth',\n    'opacity': 'opacity',\n    'fill-opacity': 'fillOpacity',\n    'stroke-opacity': 'strokeOpacity',\n    'stroke-dasharray': 'lineDash',\n    'stroke-dashoffset': 'lineDashOffset',\n    'stroke-linecap': 'lineCap',\n    'stroke-linejoin': 'lineJoin',\n    'stroke-miterlimit': 'miterLimit',\n    'font-family': 'fontFamily',\n    'font-size': 'fontSize',\n    'font-style': 'fontStyle',\n    'font-weight': 'fontWeight',\n\n    'text-align': 'textAlign',\n    'alignment-baseline': 'textBaseline'\n};\n\nfunction parseAttributes(xmlNode, el, defs, onlyInlineStyle) {\n    var zrStyle = el.__inheritedStyle || {};\n    var isTextEl = el.type === 'text';\n\n    // TODO Shadow\n    if (xmlNode.nodeType === 1) {\n        parseTransformAttribute(xmlNode, el);\n\n        extend(zrStyle, parseStyleAttribute(xmlNode));\n\n        if (!onlyInlineStyle) {\n            for (var svgAttrName in attributesMap) {\n                if (attributesMap.hasOwnProperty(svgAttrName)) {\n                    var attrValue = xmlNode.getAttribute(svgAttrName);\n                    if (attrValue != null) {\n                        zrStyle[attributesMap[svgAttrName]] = attrValue;\n                    }\n                }\n            }\n        }\n    }\n\n    var elFillProp = isTextEl ? 'textFill' : 'fill';\n    var elStrokeProp = isTextEl ? 'textStroke' : 'stroke';\n\n    el.style = el.style || new Style();\n    var elStyle = el.style;\n\n    zrStyle.fill != null && elStyle.set(elFillProp, getPaint(zrStyle.fill, defs));\n    zrStyle.stroke != null && elStyle.set(elStrokeProp, getPaint(zrStyle.stroke, defs));\n\n    each$1([\n        'lineWidth', 'opacity', 'fillOpacity', 'strokeOpacity', 'miterLimit', 'fontSize'\n    ], function (propName) {\n        var elPropName = (propName === 'lineWidth' && isTextEl) ? 'textStrokeWidth' : propName;\n        zrStyle[propName] != null && elStyle.set(elPropName, parseFloat(zrStyle[propName]));\n    });\n\n    if (!zrStyle.textBaseline || zrStyle.textBaseline === 'auto') {\n        zrStyle.textBaseline = 'alphabetic';\n    }\n    if (zrStyle.textBaseline === 'alphabetic') {\n        zrStyle.textBaseline = 'bottom';\n    }\n    if (zrStyle.textAlign === 'start') {\n        zrStyle.textAlign = 'left';\n    }\n    if (zrStyle.textAlign === 'end') {\n        zrStyle.textAlign = 'right';\n    }\n\n    each$1(['lineDashOffset', 'lineCap', 'lineJoin',\n        'fontWeight', 'fontFamily', 'fontStyle', 'textAlign', 'textBaseline'\n    ], function (propName) {\n        zrStyle[propName] != null && elStyle.set(propName, zrStyle[propName]);\n    });\n\n    if (zrStyle.lineDash) {\n        el.style.lineDash = trim(zrStyle.lineDash).split(DILIMITER_REG);\n    }\n\n    if (elStyle[elStrokeProp] && elStyle[elStrokeProp] !== 'none') {\n        // enable stroke\n        el[elStrokeProp] = true;\n    }\n\n    el.__inheritedStyle = zrStyle;\n}\n\n\nvar urlRegex = /url\\(\\s*#(.*?)\\)/;\nfunction getPaint(str, defs) {\n    // if (str === 'none') {\n    //     return;\n    // }\n    var urlMatch = defs && str && str.match(urlRegex);\n    if (urlMatch) {\n        var url = trim(urlMatch[1]);\n        var def = defs[url];\n        return def;\n    }\n    return str;\n}\n\nvar transformRegex = /(translate|scale|rotate|skewX|skewY|matrix)\\(([\\-\\s0-9\\.e,]*)\\)/g;\n\nfunction parseTransformAttribute(xmlNode, node) {\n    var transform = xmlNode.getAttribute('transform');\n    if (transform) {\n        transform = transform.replace(/,/g, ' ');\n        var m = null;\n        var transformOps = [];\n        transform.replace(transformRegex, function (str, type, value) {\n            transformOps.push(type, value);\n        });\n        for (var i = transformOps.length - 1; i > 0; i -= 2) {\n            var value = transformOps[i];\n            var type = transformOps[i - 1];\n            m = m || create$1();\n            switch (type) {\n                case 'translate':\n                    value = trim(value).split(DILIMITER_REG);\n                    translate(m, m, [parseFloat(value[0]), parseFloat(value[1] || 0)]);\n                    break;\n                case 'scale':\n                    value = trim(value).split(DILIMITER_REG);\n                    scale$1(m, m, [parseFloat(value[0]), parseFloat(value[1] || value[0])]);\n                    break;\n                case 'rotate':\n                    value = trim(value).split(DILIMITER_REG);\n                    rotate(m, m, parseFloat(value[0]));\n                    break;\n                case 'skew':\n                    value = trim(value).split(DILIMITER_REG);\n                    console.warn('Skew transform is not supported yet');\n                    break;\n                case 'matrix':\n                    var value = trim(value).split(DILIMITER_REG);\n                    m[0] = parseFloat(value[0]);\n                    m[1] = parseFloat(value[1]);\n                    m[2] = parseFloat(value[2]);\n                    m[3] = parseFloat(value[3]);\n                    m[4] = parseFloat(value[4]);\n                    m[5] = parseFloat(value[5]);\n                    break;\n            }\n        }\n        node.setLocalTransform(m);\n    }\n}\n\n// Value may contain space.\nvar styleRegex = /([^\\s:;]+)\\s*:\\s*([^:;]+)/g;\nfunction parseStyleAttribute(xmlNode) {\n    var style = xmlNode.getAttribute('style');\n    var result = {};\n\n    if (!style) {\n        return result;\n    }\n\n    var styleList = {};\n    styleRegex.lastIndex = 0;\n    var styleRegResult;\n    while ((styleRegResult = styleRegex.exec(style)) != null) {\n        styleList[styleRegResult[1]] = styleRegResult[2];\n    }\n\n    for (var svgAttrName in attributesMap) {\n        if (attributesMap.hasOwnProperty(svgAttrName) && styleList[svgAttrName] != null) {\n            result[attributesMap[svgAttrName]] = styleList[svgAttrName];\n        }\n    }\n\n    return result;\n}\n\n/**\n * @param {Array.<number>} viewBoxRect\n * @param {number} width\n * @param {number} height\n * @return {Object} {scale, position}\n */\nfunction makeViewBoxTransform(viewBoxRect, width, height) {\n    var scaleX = width / viewBoxRect.width;\n    var scaleY = height / viewBoxRect.height;\n    var scale = Math.min(scaleX, scaleY);\n    // preserveAspectRatio 'xMidYMid'\n    var viewBoxScale = [scale, scale];\n    var viewBoxPosition = [\n        -(viewBoxRect.x + viewBoxRect.width / 2) * scale + width / 2,\n        -(viewBoxRect.y + viewBoxRect.height / 2) * scale + height / 2\n    ];\n\n    return {\n        scale: viewBoxScale,\n        position: viewBoxPosition\n    };\n}\n\n/**\n * @param {string|XMLElement} xml\n * @param {Object} [opt]\n * @param {number} [opt.width] Default width if svg width not specified or is a percent value.\n * @param {number} [opt.height] Default height if svg height not specified or is a percent value.\n * @param {boolean} [opt.ignoreViewBox]\n * @param {boolean} [opt.ignoreRootClip]\n * @return {Object} result:\n * {\n *     root: Group, The root of the the result tree of zrender shapes,\n *     width: number, the viewport width of the SVG,\n *     height: number, the viewport height of the SVG,\n *     viewBoxRect: {x, y, width, height}, the declared viewBox rect of the SVG, if exists,\n *     viewBoxTransform: the {scale, position} calculated by viewBox and viewport, is exists.\n * }\n */\nfunction parseSVG(xml, opt) {\n    var parser = new SVGParser();\n    return parser.parse(xml, opt);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar storage = createHashMap();\n\n// For minimize the code size of common echarts package,\n// do not put too much logic in this module.\n\nvar mapDataStorage = {\n\n    // The format of record: see `echarts.registerMap`.\n    // Compatible with previous `echarts.registerMap`.\n    registerMap: function (mapName, rawGeoJson, rawSpecialAreas) {\n\n        var records;\n\n        if (isArray(rawGeoJson)) {\n            records = rawGeoJson;\n        }\n        else if (rawGeoJson.svg) {\n            records = [{\n                type: 'svg',\n                source: rawGeoJson.svg,\n                specialAreas: rawGeoJson.specialAreas\n            }];\n        }\n        else {\n            // Backward compatibility.\n            if (rawGeoJson.geoJson && !rawGeoJson.features) {\n                rawSpecialAreas = rawGeoJson.specialAreas;\n                rawGeoJson = rawGeoJson.geoJson;\n            }\n            records = [{\n                type: 'geoJSON',\n                source: rawGeoJson,\n                specialAreas: rawSpecialAreas\n            }];\n        }\n\n        each$1(records, function (record) {\n            var type = record.type;\n            type === 'geoJson' && (type = record.type = 'geoJSON');\n\n            var parse = parsers[type];\n\n            if (__DEV__) {\n                assert$1(parse, 'Illegal map type: ' + type);\n            }\n\n            parse(record);\n        });\n\n        return storage.set(mapName, records);\n    },\n\n    retrieveMap: function (mapName) {\n        return storage.get(mapName);\n    }\n\n};\n\nvar parsers = {\n\n    geoJSON: function (record) {\n        var source = record.source;\n        record.geoJSON = !isString(source)\n            ? source\n            : (typeof JSON !== 'undefined' && JSON.parse)\n            ? JSON.parse(source)\n            : (new Function('return (' + source + ');'))();\n    },\n\n    // Only perform parse to XML object here, which might be time\n    // consiming for large SVG.\n    // Although convert XML to zrender element is also time consiming,\n    // if we do it here, the clone of zrender elements has to be\n    // required. So we do it once for each geo instance, util real\n    // performance issues call for optimizing it.\n    svg: function (record) {\n        record.svgXML = parseXML(record.source);\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\nvar assert = assert$1;\nvar each = each$1;\nvar isFunction = isFunction$1;\nvar isObject = isObject$1;\nvar parseClassType = ComponentModel.parseClassType;\n\nvar version = '4.2.1';\n\nvar dependencies = {\n    zrender: '4.0.6'\n};\n\nvar TEST_FRAME_REMAIN_TIME = 1;\n\nvar PRIORITY_PROCESSOR_FILTER = 1000;\nvar PRIORITY_PROCESSOR_STATISTIC = 5000;\n\nvar PRIORITY_VISUAL_LAYOUT = 1000;\nvar PRIORITY_VISUAL_GLOBAL = 2000;\nvar PRIORITY_VISUAL_CHART = 3000;\nvar PRIORITY_VISUAL_COMPONENT = 4000;\n// FIXME\n// necessary?\nvar PRIORITY_VISUAL_BRUSH = 5000;\n\nvar PRIORITY = {\n    PROCESSOR: {\n        FILTER: PRIORITY_PROCESSOR_FILTER,\n        STATISTIC: PRIORITY_PROCESSOR_STATISTIC\n    },\n    VISUAL: {\n        LAYOUT: PRIORITY_VISUAL_LAYOUT,\n        GLOBAL: PRIORITY_VISUAL_GLOBAL,\n        CHART: PRIORITY_VISUAL_CHART,\n        COMPONENT: PRIORITY_VISUAL_COMPONENT,\n        BRUSH: PRIORITY_VISUAL_BRUSH\n    }\n};\n\n// Main process have three entries: `setOption`, `dispatchAction` and `resize`,\n// where they must not be invoked nestedly, except the only case: invoke\n// dispatchAction with updateMethod \"none\" in main process.\n// This flag is used to carry out this rule.\n// All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]).\nvar IN_MAIN_PROCESS = '__flagInMainProcess';\nvar OPTION_UPDATED = '__optionUpdated';\nvar ACTION_REG = /^[a-zA-Z0-9_]+$/;\n\n\nfunction createRegisterEventWithLowercaseName(method) {\n    return function (eventName, handler, context) {\n        // Event name is all lowercase\n        eventName = eventName && eventName.toLowerCase();\n        Eventful.prototype[method].call(this, eventName, handler, context);\n    };\n}\n\n/**\n * @module echarts~MessageCenter\n */\nfunction MessageCenter() {\n    Eventful.call(this);\n}\nMessageCenter.prototype.on = createRegisterEventWithLowercaseName('on');\nMessageCenter.prototype.off = createRegisterEventWithLowercaseName('off');\nMessageCenter.prototype.one = createRegisterEventWithLowercaseName('one');\nmixin(MessageCenter, Eventful);\n\n/**\n * @module echarts~ECharts\n */\nfunction ECharts(dom, theme$$1, opts) {\n    opts = opts || {};\n\n    // Get theme by name\n    if (typeof theme$$1 === 'string') {\n        theme$$1 = themeStorage[theme$$1];\n    }\n\n    /**\n     * @type {string}\n     */\n    this.id;\n\n    /**\n     * Group id\n     * @type {string}\n     */\n    this.group;\n\n    /**\n     * @type {HTMLElement}\n     * @private\n     */\n    this._dom = dom;\n\n    var defaultRenderer = 'canvas';\n    if (__DEV__) {\n        defaultRenderer = (\n            typeof window === 'undefined' ? global : window\n        ).__ECHARTS__DEFAULT__RENDERER__ || defaultRenderer;\n    }\n\n    /**\n     * @type {module:zrender/ZRender}\n     * @private\n     */\n    var zr = this._zr = init$1(dom, {\n        renderer: opts.renderer || defaultRenderer,\n        devicePixelRatio: opts.devicePixelRatio,\n        width: opts.width,\n        height: opts.height\n    });\n\n    /**\n     * Expect 60 pfs.\n     * @type {Function}\n     * @private\n     */\n    this._throttledZrFlush = throttle(bind(zr.flush, zr), 17);\n\n    var theme$$1 = clone(theme$$1);\n    theme$$1 && backwardCompat(theme$$1, true);\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._theme = theme$$1;\n\n    /**\n     * @type {Array.<module:echarts/view/Chart>}\n     * @private\n     */\n    this._chartsViews = [];\n\n    /**\n     * @type {Object.<string, module:echarts/view/Chart>}\n     * @private\n     */\n    this._chartsMap = {};\n\n    /**\n     * @type {Array.<module:echarts/view/Component>}\n     * @private\n     */\n    this._componentsViews = [];\n\n    /**\n     * @type {Object.<string, module:echarts/view/Component>}\n     * @private\n     */\n    this._componentsMap = {};\n\n    /**\n     * @type {module:echarts/CoordinateSystem}\n     * @private\n     */\n    this._coordSysMgr = new CoordinateSystemManager();\n\n    /**\n     * @type {module:echarts/ExtensionAPI}\n     * @private\n     */\n    var api = this._api = createExtensionAPI(this);\n\n    // Sort on demand\n    function prioritySortFunc(a, b) {\n        return a.__prio - b.__prio;\n    }\n    sort(visualFuncs, prioritySortFunc);\n    sort(dataProcessorFuncs, prioritySortFunc);\n\n    /**\n     * @type {module:echarts/stream/Scheduler}\n     */\n    this._scheduler = new Scheduler(this, api, dataProcessorFuncs, visualFuncs);\n\n    Eventful.call(this, this._ecEventProcessor = new EventProcessor());\n\n    /**\n     * @type {module:echarts~MessageCenter}\n     * @private\n     */\n    this._messageCenter = new MessageCenter();\n\n    // Init mouse events\n    this._initEvents();\n\n    // In case some people write `window.onresize = chart.resize`\n    this.resize = bind(this.resize, this);\n\n    // Can't dispatch action during rendering procedure\n    this._pendingActions = [];\n\n    zr.animation.on('frame', this._onframe, this);\n\n    bindRenderedEvent(zr, this);\n\n    // ECharts instance can be used as value.\n    setAsPrimitive(this);\n}\n\nvar echartsProto = ECharts.prototype;\n\nechartsProto._onframe = function () {\n    if (this._disposed) {\n        return;\n    }\n\n    var scheduler = this._scheduler;\n\n    // Lazy update\n    if (this[OPTION_UPDATED]) {\n        var silent = this[OPTION_UPDATED].silent;\n\n        this[IN_MAIN_PROCESS] = true;\n\n        prepare(this);\n        updateMethods.update.call(this);\n\n        this[IN_MAIN_PROCESS] = false;\n\n        this[OPTION_UPDATED] = false;\n\n        flushPendingActions.call(this, silent);\n\n        triggerUpdatedEvent.call(this, silent);\n    }\n    // Avoid do both lazy update and progress in one frame.\n    else if (scheduler.unfinished) {\n        // Stream progress.\n        var remainTime = TEST_FRAME_REMAIN_TIME;\n        var ecModel = this._model;\n        var api = this._api;\n        scheduler.unfinished = false;\n        do {\n            var startTime = +new Date();\n\n            scheduler.performSeriesTasks(ecModel);\n\n            // Currently dataProcessorFuncs do not check threshold.\n            scheduler.performDataProcessorTasks(ecModel);\n\n            updateStreamModes(this, ecModel);\n\n            // Do not update coordinate system here. Because that coord system update in\n            // each frame is not a good user experience. So we follow the rule that\n            // the extent of the coordinate system is determin in the first frame (the\n            // frame is executed immedietely after task reset.\n            // this._coordSysMgr.update(ecModel, api);\n\n            // console.log('--- ec frame visual ---', remainTime);\n            scheduler.performVisualTasks(ecModel);\n\n            renderSeries(this, this._model, api, 'remain');\n\n            remainTime -= (+new Date() - startTime);\n        }\n        while (remainTime > 0 && scheduler.unfinished);\n\n        // Call flush explicitly for trigger finished event.\n        if (!scheduler.unfinished) {\n            this._zr.flush();\n        }\n        // Else, zr flushing be ensue within the same frame,\n        // because zr flushing is after onframe event.\n    }\n};\n\n/**\n * @return {HTMLElement}\n */\nechartsProto.getDom = function () {\n    return this._dom;\n};\n\n/**\n * @return {module:zrender~ZRender}\n */\nechartsProto.getZr = function () {\n    return this._zr;\n};\n\n/**\n * Usage:\n * chart.setOption(option, notMerge, lazyUpdate);\n * chart.setOption(option, {\n *     notMerge: ...,\n *     lazyUpdate: ...,\n *     silent: ...\n * });\n *\n * @param {Object} option\n * @param {Object|boolean} [opts] opts or notMerge.\n * @param {boolean} [opts.notMerge=false]\n * @param {boolean} [opts.lazyUpdate=false] Useful when setOption frequently.\n */\nechartsProto.setOption = function (option, notMerge, lazyUpdate) {\n    if (__DEV__) {\n        assert(!this[IN_MAIN_PROCESS], '`setOption` should not be called during main process.');\n    }\n\n    var silent;\n    if (isObject(notMerge)) {\n        lazyUpdate = notMerge.lazyUpdate;\n        silent = notMerge.silent;\n        notMerge = notMerge.notMerge;\n    }\n\n    this[IN_MAIN_PROCESS] = true;\n\n    if (!this._model || notMerge) {\n        var optionManager = new OptionManager(this._api);\n        var theme$$1 = this._theme;\n        var ecModel = this._model = new GlobalModel(null, null, theme$$1, optionManager);\n        ecModel.scheduler = this._scheduler;\n        ecModel.init(null, null, theme$$1, optionManager);\n    }\n\n    this._model.setOption(option, optionPreprocessorFuncs);\n\n    if (lazyUpdate) {\n        this[OPTION_UPDATED] = {silent: silent};\n        this[IN_MAIN_PROCESS] = false;\n    }\n    else {\n        prepare(this);\n\n        updateMethods.update.call(this);\n\n        // Ensure zr refresh sychronously, and then pixel in canvas can be\n        // fetched after `setOption`.\n        this._zr.flush();\n\n        this[OPTION_UPDATED] = false;\n        this[IN_MAIN_PROCESS] = false;\n\n        flushPendingActions.call(this, silent);\n        triggerUpdatedEvent.call(this, silent);\n    }\n};\n\n/**\n * @DEPRECATED\n */\nechartsProto.setTheme = function () {\n    console.error('ECharts#setTheme() is DEPRECATED in ECharts 3.0');\n};\n\n/**\n * @return {module:echarts/model/Global}\n */\nechartsProto.getModel = function () {\n    return this._model;\n};\n\n/**\n * @return {Object}\n */\nechartsProto.getOption = function () {\n    return this._model && this._model.getOption();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getWidth = function () {\n    return this._zr.getWidth();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getHeight = function () {\n    return this._zr.getHeight();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getDevicePixelRatio = function () {\n    return this._zr.painter.dpr || window.devicePixelRatio || 1;\n};\n\n/**\n * Get canvas which has all thing rendered\n * @param {Object} opts\n * @param {string} [opts.backgroundColor]\n * @return {string}\n */\nechartsProto.getRenderedCanvas = function (opts) {\n    if (!env$1.canvasSupported) {\n        return;\n    }\n    opts = opts || {};\n    opts.pixelRatio = opts.pixelRatio || 1;\n    opts.backgroundColor = opts.backgroundColor\n        || this._model.get('backgroundColor');\n    var zr = this._zr;\n    // var list = zr.storage.getDisplayList();\n    // Stop animations\n    // Never works before in init animation, so remove it.\n    // zrUtil.each(list, function (el) {\n    //     el.stopAnimation(true);\n    // });\n    return zr.painter.getRenderedCanvas(opts);\n};\n\n/**\n * Get svg data url\n * @return {string}\n */\nechartsProto.getSvgDataUrl = function () {\n    if (!env$1.svgSupported) {\n        return;\n    }\n\n    var zr = this._zr;\n    var list = zr.storage.getDisplayList();\n    // Stop animations\n    each$1(list, function (el) {\n        el.stopAnimation(true);\n    });\n\n    return zr.painter.pathToDataUrl();\n};\n\n/**\n * @return {string}\n * @param {Object} opts\n * @param {string} [opts.type='png']\n * @param {string} [opts.pixelRatio=1]\n * @param {string} [opts.backgroundColor]\n * @param {string} [opts.excludeComponents]\n */\nechartsProto.getDataURL = function (opts) {\n    opts = opts || {};\n    var excludeComponents = opts.excludeComponents;\n    var ecModel = this._model;\n    var excludesComponentViews = [];\n    var self = this;\n\n    each(excludeComponents, function (componentType) {\n        ecModel.eachComponent({\n            mainType: componentType\n        }, function (component) {\n            var view = self._componentsMap[component.__viewId];\n            if (!view.group.ignore) {\n                excludesComponentViews.push(view);\n                view.group.ignore = true;\n            }\n        });\n    });\n\n    var url = this._zr.painter.getType() === 'svg'\n        ? this.getSvgDataUrl()\n        : this.getRenderedCanvas(opts).toDataURL(\n            'image/' + (opts && opts.type || 'png')\n        );\n\n    each(excludesComponentViews, function (view) {\n        view.group.ignore = false;\n    });\n\n    return url;\n};\n\n\n/**\n * @return {string}\n * @param {Object} opts\n * @param {string} [opts.type='png']\n * @param {string} [opts.pixelRatio=1]\n * @param {string} [opts.backgroundColor]\n */\nechartsProto.getConnectedDataURL = function (opts) {\n    if (!env$1.canvasSupported) {\n        return;\n    }\n    var groupId = this.group;\n    var mathMin = Math.min;\n    var mathMax = Math.max;\n    var MAX_NUMBER = Infinity;\n    if (connectedGroups[groupId]) {\n        var left = MAX_NUMBER;\n        var top = MAX_NUMBER;\n        var right = -MAX_NUMBER;\n        var bottom = -MAX_NUMBER;\n        var canvasList = [];\n        var dpr = (opts && opts.pixelRatio) || 1;\n\n        each$1(instances, function (chart, id) {\n            if (chart.group === groupId) {\n                var canvas = chart.getRenderedCanvas(\n                    clone(opts)\n                );\n                var boundingRect = chart.getDom().getBoundingClientRect();\n                left = mathMin(boundingRect.left, left);\n                top = mathMin(boundingRect.top, top);\n                right = mathMax(boundingRect.right, right);\n                bottom = mathMax(boundingRect.bottom, bottom);\n                canvasList.push({\n                    dom: canvas,\n                    left: boundingRect.left,\n                    top: boundingRect.top\n                });\n            }\n        });\n\n        left *= dpr;\n        top *= dpr;\n        right *= dpr;\n        bottom *= dpr;\n        var width = right - left;\n        var height = bottom - top;\n        var targetCanvas = createCanvas();\n        targetCanvas.width = width;\n        targetCanvas.height = height;\n        var zr = init$1(targetCanvas);\n\n        each(canvasList, function (item) {\n            var img = new ZImage({\n                style: {\n                    x: item.left * dpr - left,\n                    y: item.top * dpr - top,\n                    image: item.dom\n                }\n            });\n            zr.add(img);\n        });\n        zr.refreshImmediately();\n\n        return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png'));\n    }\n    else {\n        return this.getDataURL(opts);\n    }\n};\n\n/**\n * Convert from logical coordinate system to pixel coordinate system.\n * See CoordinateSystem#convertToPixel.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId, geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName,\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {Array|number} result\n */\nechartsProto.convertToPixel = curry(doConvertPixel, 'convertToPixel');\n\n/**\n * Convert from pixel coordinate system to logical coordinate system.\n * See CoordinateSystem#convertFromPixel.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId / geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {Array|number} result\n */\nechartsProto.convertFromPixel = curry(doConvertPixel, 'convertFromPixel');\n\nfunction doConvertPixel(methodName, finder, value) {\n    var ecModel = this._model;\n    var coordSysList = this._coordSysMgr.getCoordinateSystems();\n    var result;\n\n    finder = parseFinder(ecModel, finder);\n\n    for (var i = 0; i < coordSysList.length; i++) {\n        var coordSys = coordSysList[i];\n        if (coordSys[methodName]\n            && (result = coordSys[methodName](ecModel, finder, value)) != null\n        ) {\n            return result;\n        }\n    }\n\n    if (__DEV__) {\n        console.warn(\n            'No coordinate system that supports ' + methodName + ' found by the given finder.'\n        );\n    }\n}\n\n/**\n * Is the specified coordinate systems or components contain the given pixel point.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId / geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName,\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {boolean} result\n */\nechartsProto.containPixel = function (finder, value) {\n    var ecModel = this._model;\n    var result;\n\n    finder = parseFinder(ecModel, finder);\n\n    each$1(finder, function (models, key) {\n        key.indexOf('Models') >= 0 && each$1(models, function (model) {\n            var coordSys = model.coordinateSystem;\n            if (coordSys && coordSys.containPoint) {\n                result |= !!coordSys.containPoint(value);\n            }\n            else if (key === 'seriesModels') {\n                var view = this._chartsMap[model.__viewId];\n                if (view && view.containPoint) {\n                    result |= view.containPoint(value, model);\n                }\n                else {\n                    if (__DEV__) {\n                        console.warn(key + ': ' + (view\n                            ? 'The found component do not support containPoint.'\n                            : 'No view mapping to the found component.'\n                        ));\n                    }\n                }\n            }\n            else {\n                if (__DEV__) {\n                    console.warn(key + ': containPoint is not supported');\n                }\n            }\n        }, this);\n    }, this);\n\n    return !!result;\n};\n\n/**\n * Get visual from series or data.\n * @param {string|Object} finder\n *        If string, e.g., 'series', means {seriesIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            dataIndex / dataIndexInside\n *        }\n *        If dataIndex is not specified, series visual will be fetched,\n *        but not data item visual.\n *        If all of seriesIndex, seriesId, seriesName are not specified,\n *        visual will be fetched from first series.\n * @param {string} visualType 'color', 'symbol', 'symbolSize'\n */\nechartsProto.getVisual = function (finder, visualType) {\n    var ecModel = this._model;\n\n    finder = parseFinder(ecModel, finder, {defaultMainType: 'series'});\n\n    var seriesModel = finder.seriesModel;\n\n    if (__DEV__) {\n        if (!seriesModel) {\n            console.warn('There is no specified seires model');\n        }\n    }\n\n    var data = seriesModel.getData();\n\n    var dataIndexInside = finder.hasOwnProperty('dataIndexInside')\n        ? finder.dataIndexInside\n        : finder.hasOwnProperty('dataIndex')\n        ? data.indexOfRawIndex(finder.dataIndex)\n        : null;\n\n    return dataIndexInside != null\n        ? data.getItemVisual(dataIndexInside, visualType)\n        : data.getVisual(visualType);\n};\n\n/**\n * Get view of corresponding component model\n * @param  {module:echarts/model/Component} componentModel\n * @return {module:echarts/view/Component}\n */\nechartsProto.getViewOfComponentModel = function (componentModel) {\n    return this._componentsMap[componentModel.__viewId];\n};\n\n/**\n * Get view of corresponding series model\n * @param  {module:echarts/model/Series} seriesModel\n * @return {module:echarts/view/Chart}\n */\nechartsProto.getViewOfSeriesModel = function (seriesModel) {\n    return this._chartsMap[seriesModel.__viewId];\n};\n\nvar updateMethods = {\n\n    prepareAndUpdate: function (payload) {\n        prepare(this);\n        updateMethods.update.call(this, payload);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    update: function (payload) {\n        // console.profile && console.profile('update');\n\n        var ecModel = this._model;\n        var api = this._api;\n        var zr = this._zr;\n        var coordSysMgr = this._coordSysMgr;\n        var scheduler = this._scheduler;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        scheduler.restoreData(ecModel, payload);\n\n        scheduler.performSeriesTasks(ecModel);\n\n        // TODO\n        // Save total ecModel here for undo/redo (after restoring data and before processing data).\n        // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call.\n\n        // Create new coordinate system each update\n        // In LineView may save the old coordinate system and use it to get the orignal point\n        coordSysMgr.create(ecModel, api);\n\n        scheduler.performDataProcessorTasks(ecModel, payload);\n\n        // Current stream render is not supported in data process. So we can update\n        // stream modes after data processing, where the filtered data is used to\n        // deteming whether use progressive rendering.\n        updateStreamModes(this, ecModel);\n\n        // We update stream modes before coordinate system updated, then the modes info\n        // can be fetched when coord sys updating (consider the barGrid extent fix). But\n        // the drawback is the full coord info can not be fetched. Fortunately this full\n        // coord is not requied in stream mode updater currently.\n        coordSysMgr.update(ecModel, api);\n\n        clearColorPalette(ecModel);\n        scheduler.performVisualTasks(ecModel, payload);\n\n        render(this, ecModel, api, payload);\n\n        // Set background\n        var backgroundColor = ecModel.get('backgroundColor') || 'transparent';\n\n        // In IE8\n        if (!env$1.canvasSupported) {\n            var colorArr = parse(backgroundColor);\n            backgroundColor = stringify(colorArr, 'rgb');\n            if (colorArr[3] === 0) {\n                backgroundColor = 'transparent';\n            }\n        }\n        else {\n            zr.setBackgroundColor(backgroundColor);\n        }\n\n        performPostUpdateFuncs(ecModel, api);\n\n        // console.profile && console.profileEnd('update');\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateTransform: function (payload) {\n        var ecModel = this._model;\n        var ecIns = this;\n        var api = this._api;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        // ChartView.markUpdateMethod(payload, 'updateTransform');\n\n        var componentDirtyList = [];\n        ecModel.eachComponent(function (componentType, componentModel) {\n            var componentView = ecIns.getViewOfComponentModel(componentModel);\n            if (componentView && componentView.__alive) {\n                if (componentView.updateTransform) {\n                    var result = componentView.updateTransform(componentModel, ecModel, api, payload);\n                    result && result.update && componentDirtyList.push(componentView);\n                }\n                else {\n                    componentDirtyList.push(componentView);\n                }\n            }\n        });\n\n        var seriesDirtyMap = createHashMap();\n        ecModel.eachSeries(function (seriesModel) {\n            var chartView = ecIns._chartsMap[seriesModel.__viewId];\n            if (chartView.updateTransform) {\n                var result = chartView.updateTransform(seriesModel, ecModel, api, payload);\n                result && result.update && seriesDirtyMap.set(seriesModel.uid, 1);\n            }\n            else {\n                seriesDirtyMap.set(seriesModel.uid, 1);\n            }\n        });\n\n        clearColorPalette(ecModel);\n        // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);\n        this._scheduler.performVisualTasks(\n            ecModel, payload, {setDirty: true, dirtyMap: seriesDirtyMap}\n        );\n\n        // Currently, not call render of components. Geo render cost a lot.\n        // renderComponents(ecIns, ecModel, api, payload, componentDirtyList);\n        renderSeries(ecIns, ecModel, api, payload, seriesDirtyMap);\n\n        performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateView: function (payload) {\n        var ecModel = this._model;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        Chart.markUpdateMethod(payload, 'updateView');\n\n        clearColorPalette(ecModel);\n\n        // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});\n\n        render(this, this._model, this._api, payload);\n\n        performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateVisual: function (payload) {\n        updateMethods.update.call(this, payload);\n\n        // var ecModel = this._model;\n\n        // // update before setOption\n        // if (!ecModel) {\n        //     return;\n        // }\n\n        // ChartView.markUpdateMethod(payload, 'updateVisual');\n\n        // clearColorPalette(ecModel);\n\n        // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // this._scheduler.performVisualTasks(ecModel, payload, {visualType: 'visual', setDirty: true});\n\n        // render(this, this._model, this._api, payload);\n\n        // performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateLayout: function (payload) {\n        updateMethods.update.call(this, payload);\n\n        // var ecModel = this._model;\n\n        // // update before setOption\n        // if (!ecModel) {\n        //     return;\n        // }\n\n        // ChartView.markUpdateMethod(payload, 'updateLayout');\n\n        // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);\n        // this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});\n\n        // render(this, this._model, this._api, payload);\n\n        // performPostUpdateFuncs(ecModel, this._api);\n    }\n};\n\nfunction prepare(ecIns) {\n    var ecModel = ecIns._model;\n    var scheduler = ecIns._scheduler;\n\n    scheduler.restorePipelines(ecModel);\n\n    scheduler.prepareStageTasks();\n\n    prepareView(ecIns, 'component', ecModel, scheduler);\n\n    prepareView(ecIns, 'chart', ecModel, scheduler);\n\n    scheduler.plan();\n}\n\n/**\n * @private\n */\nfunction updateDirectly(ecIns, method, payload, mainType, subType) {\n    var ecModel = ecIns._model;\n\n    // broadcast\n    if (!mainType) {\n        // FIXME\n        // Chart will not be update directly here, except set dirty.\n        // But there is no such scenario now.\n        each(ecIns._componentsViews.concat(ecIns._chartsViews), callView);\n        return;\n    }\n\n    var query = {};\n    query[mainType + 'Id'] = payload[mainType + 'Id'];\n    query[mainType + 'Index'] = payload[mainType + 'Index'];\n    query[mainType + 'Name'] = payload[mainType + 'Name'];\n\n    var condition = {mainType: mainType, query: query};\n    subType && (condition.subType = subType); // subType may be '' by parseClassType;\n\n    var excludeSeriesId = payload.excludeSeriesId;\n    if (excludeSeriesId != null) {\n        excludeSeriesId = createHashMap(normalizeToArray(excludeSeriesId));\n    }\n\n    // If dispatchAction before setOption, do nothing.\n    ecModel && ecModel.eachComponent(condition, function (model) {\n        if (!excludeSeriesId || excludeSeriesId.get(model.id) == null) {\n            callView(ecIns[\n                mainType === 'series' ? '_chartsMap' : '_componentsMap'\n            ][model.__viewId]);\n        }\n    }, ecIns);\n\n    function callView(view) {\n        view && view.__alive && view[method] && view[method](\n            view.__model, ecModel, ecIns._api, payload\n        );\n    }\n}\n\n/**\n * Resize the chart\n * @param {Object} opts\n * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)\n * @param {boolean} [opts.silent=false]\n */\nechartsProto.resize = function (opts) {\n    if (__DEV__) {\n        assert(!this[IN_MAIN_PROCESS], '`resize` should not be called during main process.');\n    }\n\n    this._zr.resize(opts);\n\n    var ecModel = this._model;\n\n    // Resize loading effect\n    this._loadingFX && this._loadingFX.resize();\n\n    if (!ecModel) {\n        return;\n    }\n\n    var optionChanged = ecModel.resetOption('media');\n\n    var silent = opts && opts.silent;\n\n    this[IN_MAIN_PROCESS] = true;\n\n    optionChanged && prepare(this);\n    updateMethods.update.call(this);\n\n    this[IN_MAIN_PROCESS] = false;\n\n    flushPendingActions.call(this, silent);\n\n    triggerUpdatedEvent.call(this, silent);\n};\n\nfunction updateStreamModes(ecIns, ecModel) {\n    var chartsMap = ecIns._chartsMap;\n    var scheduler = ecIns._scheduler;\n    ecModel.eachSeries(function (seriesModel) {\n        scheduler.updateStreamModes(seriesModel, chartsMap[seriesModel.__viewId]);\n    });\n}\n\n/**\n * Show loading effect\n * @param  {string} [name='default']\n * @param  {Object} [cfg]\n */\nechartsProto.showLoading = function (name, cfg) {\n    if (isObject(name)) {\n        cfg = name;\n        name = '';\n    }\n    name = name || 'default';\n\n    this.hideLoading();\n    if (!loadingEffects[name]) {\n        if (__DEV__) {\n            console.warn('Loading effects ' + name + ' not exists.');\n        }\n        return;\n    }\n    var el = loadingEffects[name](this._api, cfg);\n    var zr = this._zr;\n    this._loadingFX = el;\n\n    zr.add(el);\n};\n\n/**\n * Hide loading effect\n */\nechartsProto.hideLoading = function () {\n    this._loadingFX && this._zr.remove(this._loadingFX);\n    this._loadingFX = null;\n};\n\n/**\n * @param {Object} eventObj\n * @return {Object}\n */\nechartsProto.makeActionFromEvent = function (eventObj) {\n    var payload = extend({}, eventObj);\n    payload.type = eventActionMap[eventObj.type];\n    return payload;\n};\n\n/**\n * @pubilc\n * @param {Object} payload\n * @param {string} [payload.type] Action type\n * @param {Object|boolean} [opt] If pass boolean, means opt.silent\n * @param {boolean} [opt.silent=false] Whether trigger events.\n * @param {boolean} [opt.flush=undefined]\n *                  true: Flush immediately, and then pixel in canvas can be fetched\n *                      immediately. Caution: it might affect performance.\n *                  false: Not not flush.\n *                  undefined: Auto decide whether perform flush.\n */\nechartsProto.dispatchAction = function (payload, opt) {\n    if (!isObject(opt)) {\n        opt = {silent: !!opt};\n    }\n\n    if (!actions[payload.type]) {\n        return;\n    }\n\n    // Avoid dispatch action before setOption. Especially in `connect`.\n    if (!this._model) {\n        return;\n    }\n\n    // May dispatchAction in rendering procedure\n    if (this[IN_MAIN_PROCESS]) {\n        this._pendingActions.push(payload);\n        return;\n    }\n\n    doDispatchAction.call(this, payload, opt.silent);\n\n    if (opt.flush) {\n        this._zr.flush(true);\n    }\n    else if (opt.flush !== false && env$1.browser.weChat) {\n        // In WeChat embeded browser, `requestAnimationFrame` and `setInterval`\n        // hang when sliding page (on touch event), which cause that zr does not\n        // refresh util user interaction finished, which is not expected.\n        // But `dispatchAction` may be called too frequently when pan on touch\n        // screen, which impacts performance if do not throttle them.\n        this._throttledZrFlush();\n    }\n\n    flushPendingActions.call(this, opt.silent);\n\n    triggerUpdatedEvent.call(this, opt.silent);\n};\n\nfunction doDispatchAction(payload, silent) {\n    var payloadType = payload.type;\n    var escapeConnect = payload.escapeConnect;\n    var actionWrap = actions[payloadType];\n    var actionInfo = actionWrap.actionInfo;\n\n    var cptType = (actionInfo.update || 'update').split(':');\n    var updateMethod = cptType.pop();\n    cptType = cptType[0] != null && parseClassType(cptType[0]);\n\n    this[IN_MAIN_PROCESS] = true;\n\n    var payloads = [payload];\n    var batched = false;\n    // Batch action\n    if (payload.batch) {\n        batched = true;\n        payloads = map(payload.batch, function (item) {\n            item = defaults(extend({}, item), payload);\n            item.batch = null;\n            return item;\n        });\n    }\n\n    var eventObjBatch = [];\n    var eventObj;\n    var isHighDown = payloadType === 'highlight' || payloadType === 'downplay';\n\n    each(payloads, function (batchItem) {\n        // Action can specify the event by return it.\n        eventObj = actionWrap.action(batchItem, this._model, this._api);\n        // Emit event outside\n        eventObj = eventObj || extend({}, batchItem);\n        // Convert type to eventType\n        eventObj.type = actionInfo.event || eventObj.type;\n        eventObjBatch.push(eventObj);\n\n        // light update does not perform data process, layout and visual.\n        if (isHighDown) {\n            // method, payload, mainType, subType\n            updateDirectly(this, updateMethod, batchItem, 'series');\n        }\n        else if (cptType) {\n            updateDirectly(this, updateMethod, batchItem, cptType.main, cptType.sub);\n        }\n    }, this);\n\n    if (updateMethod !== 'none' && !isHighDown && !cptType) {\n        // Still dirty\n        if (this[OPTION_UPDATED]) {\n            // FIXME Pass payload ?\n            prepare(this);\n            updateMethods.update.call(this, payload);\n            this[OPTION_UPDATED] = false;\n        }\n        else {\n            updateMethods[updateMethod].call(this, payload);\n        }\n    }\n\n    // Follow the rule of action batch\n    if (batched) {\n        eventObj = {\n            type: actionInfo.event || payloadType,\n            escapeConnect: escapeConnect,\n            batch: eventObjBatch\n        };\n    }\n    else {\n        eventObj = eventObjBatch[0];\n    }\n\n    this[IN_MAIN_PROCESS] = false;\n\n    !silent && this._messageCenter.trigger(eventObj.type, eventObj);\n}\n\nfunction flushPendingActions(silent) {\n    var pendingActions = this._pendingActions;\n    while (pendingActions.length) {\n        var payload = pendingActions.shift();\n        doDispatchAction.call(this, payload, silent);\n    }\n}\n\nfunction triggerUpdatedEvent(silent) {\n    !silent && this.trigger('updated');\n}\n\n/**\n * Event `rendered` is triggered when zr\n * rendered. It is useful for realtime\n * snapshot (reflect animation).\n *\n * Event `finished` is triggered when:\n * (1) zrender rendering finished.\n * (2) initial animation finished.\n * (3) progressive rendering finished.\n * (4) no pending action.\n * (5) no delayed setOption needs to be processed.\n */\nfunction bindRenderedEvent(zr, ecIns) {\n    zr.on('rendered', function () {\n\n        ecIns.trigger('rendered');\n\n        // The `finished` event should not be triggered repeatly,\n        // so it should only be triggered when rendering indeed happend\n        // in zrender. (Consider the case that dipatchAction is keep\n        // triggering when mouse move).\n        if (\n            // Although zr is dirty if initial animation is not finished\n            // and this checking is called on frame, we also check\n            // animation finished for robustness.\n            zr.animation.isFinished()\n            && !ecIns[OPTION_UPDATED]\n            && !ecIns._scheduler.unfinished\n            && !ecIns._pendingActions.length\n        ) {\n            ecIns.trigger('finished');\n        }\n    });\n}\n\n/**\n * @param {Object} params\n * @param {number} params.seriesIndex\n * @param {Array|TypedArray} params.data\n */\nechartsProto.appendData = function (params) {\n    var seriesIndex = params.seriesIndex;\n    var ecModel = this.getModel();\n    var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n\n    if (__DEV__) {\n        assert(params.data && seriesModel);\n    }\n\n    seriesModel.appendData(params);\n\n    // Note: `appendData` does not support that update extent of coordinate\n    // system, util some scenario require that. In the expected usage of\n    // `appendData`, the initial extent of coordinate system should better\n    // be fixed by axis `min`/`max` setting or initial data, otherwise if\n    // the extent changed while `appendData`, the location of the painted\n    // graphic elements have to be changed, which make the usage of\n    // `appendData` meaningless.\n\n    this._scheduler.unfinished = true;\n};\n\n/**\n * Register event\n * @method\n */\nechartsProto.on = createRegisterEventWithLowercaseName('on');\nechartsProto.off = createRegisterEventWithLowercaseName('off');\nechartsProto.one = createRegisterEventWithLowercaseName('one');\n\n/**\n * Prepare view instances of charts and components\n * @param  {module:echarts/model/Global} ecModel\n * @private\n */\nfunction prepareView(ecIns, type, ecModel, scheduler) {\n    var isComponent = type === 'component';\n    var viewList = isComponent ? ecIns._componentsViews : ecIns._chartsViews;\n    var viewMap = isComponent ? ecIns._componentsMap : ecIns._chartsMap;\n    var zr = ecIns._zr;\n    var api = ecIns._api;\n\n    for (var i = 0; i < viewList.length; i++) {\n        viewList[i].__alive = false;\n    }\n\n    isComponent\n        ? ecModel.eachComponent(function (componentType, model) {\n            componentType !== 'series' && doPrepare(model);\n        })\n        : ecModel.eachSeries(doPrepare);\n\n    function doPrepare(model) {\n        // Consider: id same and type changed.\n        var viewId = '_ec_' + model.id + '_' + model.type;\n        var view = viewMap[viewId];\n        if (!view) {\n            var classType = parseClassType(model.type);\n            var Clazz = isComponent\n                ? Component.getClass(classType.main, classType.sub)\n                : Chart.getClass(classType.sub);\n\n            if (__DEV__) {\n                assert(Clazz, classType.sub + ' does not exist.');\n            }\n\n            view = new Clazz();\n            view.init(ecModel, api);\n            viewMap[viewId] = view;\n            viewList.push(view);\n            zr.add(view.group);\n        }\n\n        model.__viewId = view.__id = viewId;\n        view.__alive = true;\n        view.__model = model;\n        view.group.__ecComponentInfo = {\n            mainType: model.mainType,\n            index: model.componentIndex\n        };\n        !isComponent && scheduler.prepareView(view, model, ecModel, api);\n    }\n\n    for (var i = 0; i < viewList.length;) {\n        var view = viewList[i];\n        if (!view.__alive) {\n            !isComponent && view.renderTask.dispose();\n            zr.remove(view.group);\n            view.dispose(ecModel, api);\n            viewList.splice(i, 1);\n            delete viewMap[view.__id];\n            view.__id = view.group.__ecComponentInfo = null;\n        }\n        else {\n            i++;\n        }\n    }\n}\n\n// /**\n//  * Encode visual infomation from data after data processing\n//  *\n//  * @param {module:echarts/model/Global} ecModel\n//  * @param {object} layout\n//  * @param {boolean} [layoutFilter] `true`: only layout,\n//  *                                 `false`: only not layout,\n//  *                                 `null`/`undefined`: all.\n//  * @param {string} taskBaseTag\n//  * @private\n//  */\n// function startVisualEncoding(ecIns, ecModel, api, payload, layoutFilter) {\n//     each(visualFuncs, function (visual, index) {\n//         var isLayout = visual.isLayout;\n//         if (layoutFilter == null\n//             || (layoutFilter === false && !isLayout)\n//             || (layoutFilter === true && isLayout)\n//         ) {\n//             visual.func(ecModel, api, payload);\n//         }\n//     });\n// }\n\nfunction clearColorPalette(ecModel) {\n    ecModel.clearColorPalette();\n    ecModel.eachSeries(function (seriesModel) {\n        seriesModel.clearColorPalette();\n    });\n}\n\nfunction render(ecIns, ecModel, api, payload) {\n\n    renderComponents(ecIns, ecModel, api, payload);\n\n    each(ecIns._chartsViews, function (chart) {\n        chart.__alive = false;\n    });\n\n    renderSeries(ecIns, ecModel, api, payload);\n\n    // Remove groups of unrendered charts\n    each(ecIns._chartsViews, function (chart) {\n        if (!chart.__alive) {\n            chart.remove(ecModel, api);\n        }\n    });\n}\n\nfunction renderComponents(ecIns, ecModel, api, payload, dirtyList) {\n    each(dirtyList || ecIns._componentsViews, function (componentView) {\n        var componentModel = componentView.__model;\n        componentView.render(componentModel, ecModel, api, payload);\n\n        updateZ(componentModel, componentView);\n    });\n}\n\n/**\n * Render each chart and component\n * @private\n */\nfunction renderSeries(ecIns, ecModel, api, payload, dirtyMap) {\n    // Render all charts\n    var scheduler = ecIns._scheduler;\n    var unfinished;\n    ecModel.eachSeries(function (seriesModel) {\n        var chartView = ecIns._chartsMap[seriesModel.__viewId];\n        chartView.__alive = true;\n\n        var renderTask = chartView.renderTask;\n        scheduler.updatePayload(renderTask, payload);\n\n        if (dirtyMap && dirtyMap.get(seriesModel.uid)) {\n            renderTask.dirty();\n        }\n\n        unfinished |= renderTask.perform(scheduler.getPerformArgs(renderTask));\n\n        chartView.group.silent = !!seriesModel.get('silent');\n\n        updateZ(seriesModel, chartView);\n\n        updateBlend(seriesModel, chartView);\n    });\n    scheduler.unfinished |= unfinished;\n\n    // If use hover layer\n    updateHoverLayerStatus(ecIns._zr, ecModel);\n\n    // Add aria\n    aria(ecIns._zr.dom, ecModel);\n}\n\nfunction performPostUpdateFuncs(ecModel, api) {\n    each(postUpdateFuncs, function (func) {\n        func(ecModel, api);\n    });\n}\n\n\nvar MOUSE_EVENT_NAMES = [\n    'click', 'dblclick', 'mouseover', 'mouseout', 'mousemove',\n    'mousedown', 'mouseup', 'globalout', 'contextmenu'\n];\n\n/**\n * @private\n */\nechartsProto._initEvents = function () {\n    each(MOUSE_EVENT_NAMES, function (eveName) {\n        var handler = function (e) {\n            var ecModel = this.getModel();\n            var el = e.target;\n            var params;\n            var isGlobalOut = eveName === 'globalout';\n\n            // no e.target when 'globalout'.\n            if (isGlobalOut) {\n                params = {};\n            }\n            else if (el && el.dataIndex != null) {\n                var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex);\n                params = dataModel && dataModel.getDataParams(el.dataIndex, el.dataType, el) || {};\n            }\n            // If element has custom eventData of components\n            else if (el && el.eventData) {\n                params = extend({}, el.eventData);\n            }\n\n            // Contract: if params prepared in mouse event,\n            // these properties must be specified:\n            // {\n            //    componentType: string (component main type)\n            //    componentIndex: number\n            // }\n            // Otherwise event query can not work.\n\n            if (params) {\n                var componentType = params.componentType;\n                var componentIndex = params.componentIndex;\n                // Special handling for historic reason: when trigger by\n                // markLine/markPoint/markArea, the componentType is\n                // 'markLine'/'markPoint'/'markArea', but we should better\n                // enable them to be queried by seriesIndex, since their\n                // option is set in each series.\n                if (componentType === 'markLine'\n                    || componentType === 'markPoint'\n                    || componentType === 'markArea'\n                ) {\n                    componentType = 'series';\n                    componentIndex = params.seriesIndex;\n                }\n                var model = componentType && componentIndex != null\n                    && ecModel.getComponent(componentType, componentIndex);\n                var view = model && this[\n                    model.mainType === 'series' ? '_chartsMap' : '_componentsMap'\n                ][model.__viewId];\n\n                if (__DEV__) {\n                    // `event.componentType` and `event[componentTpype + 'Index']` must not\n                    // be missed, otherwise there is no way to distinguish source component.\n                    // See `dataFormat.getDataParams`.\n                    if (!isGlobalOut && !(model && view)) {\n                        console.warn('model or view can not be found by params');\n                    }\n                }\n\n                params.event = e;\n                params.type = eveName;\n\n                this._ecEventProcessor.eventInfo = {\n                    targetEl: el,\n                    packedEvent: params,\n                    model: model,\n                    view: view\n                };\n\n                this.trigger(eveName, params);\n            }\n        };\n        // Consider that some component (like tooltip, brush, ...)\n        // register zr event handler, but user event handler might\n        // do anything, such as call `setOption` or `dispatchAction`,\n        // which probably update any of the content and probably\n        // cause problem if it is called previous other inner handlers.\n        handler.zrEventfulCallAtLast = true;\n        this._zr.on(eveName, handler, this);\n    }, this);\n\n    each(eventActionMap, function (actionType, eventType) {\n        this._messageCenter.on(eventType, function (event) {\n            this.trigger(eventType, event);\n        }, this);\n    }, this);\n};\n\n/**\n * @return {boolean}\n */\nechartsProto.isDisposed = function () {\n    return this._disposed;\n};\n\n/**\n * Clear\n */\nechartsProto.clear = function () {\n    this.setOption({ series: [] }, true);\n};\n\n/**\n * Dispose instance\n */\nechartsProto.dispose = function () {\n    if (this._disposed) {\n        if (__DEV__) {\n            console.warn('Instance ' + this.id + ' has been disposed');\n        }\n        return;\n    }\n    this._disposed = true;\n\n    setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, '');\n\n    var api = this._api;\n    var ecModel = this._model;\n\n    each(this._componentsViews, function (component) {\n        component.dispose(ecModel, api);\n    });\n    each(this._chartsViews, function (chart) {\n        chart.dispose(ecModel, api);\n    });\n\n    // Dispose after all views disposed\n    this._zr.dispose();\n\n    delete instances[this.id];\n};\n\nmixin(ECharts, Eventful);\n\nfunction updateHoverLayerStatus(zr, ecModel) {\n    var storage = zr.storage;\n    var elCount = 0;\n    storage.traverse(function (el) {\n        if (!el.isGroup) {\n            elCount++;\n        }\n    });\n    if (elCount > ecModel.get('hoverLayerThreshold') && !env$1.node) {\n        storage.traverse(function (el) {\n            if (!el.isGroup) {\n                // Don't switch back.\n                el.useHoverLayer = true;\n            }\n        });\n    }\n}\n\n/**\n * Update chart progressive and blend.\n * @param {module:echarts/model/Series|module:echarts/model/Component} model\n * @param {module:echarts/view/Component|module:echarts/view/Chart} view\n */\nfunction updateBlend(seriesModel, chartView) {\n    var blendMode = seriesModel.get('blendMode') || null;\n    if (__DEV__) {\n        if (!env$1.canvasSupported && blendMode && blendMode !== 'source-over') {\n            console.warn('Only canvas support blendMode');\n        }\n    }\n    chartView.group.traverse(function (el) {\n        // FIXME marker and other components\n        if (!el.isGroup) {\n            // Only set if blendMode is changed. In case element is incremental and don't wan't to rerender.\n            if (el.style.blend !== blendMode) {\n                el.setStyle('blend', blendMode);\n            }\n        }\n        if (el.eachPendingDisplayable) {\n            el.eachPendingDisplayable(function (displayable) {\n                displayable.setStyle('blend', blendMode);\n            });\n        }\n    });\n}\n\n/**\n * @param {module:echarts/model/Series|module:echarts/model/Component} model\n * @param {module:echarts/view/Component|module:echarts/view/Chart} view\n */\nfunction updateZ(model, view) {\n    var z = model.get('z');\n    var zlevel = model.get('zlevel');\n    // Set z and zlevel\n    view.group.traverse(function (el) {\n        if (el.type !== 'group') {\n            z != null && (el.z = z);\n            zlevel != null && (el.zlevel = zlevel);\n        }\n    });\n}\n\nfunction createExtensionAPI(ecInstance) {\n    var coordSysMgr = ecInstance._coordSysMgr;\n    return extend(new ExtensionAPI(ecInstance), {\n        // Inject methods\n        getCoordinateSystems: bind(\n            coordSysMgr.getCoordinateSystems, coordSysMgr\n        ),\n        getComponentByElement: function (el) {\n            while (el) {\n                var modelInfo = el.__ecComponentInfo;\n                if (modelInfo != null) {\n                    return ecInstance._model.getComponent(modelInfo.mainType, modelInfo.index);\n                }\n                el = el.parent;\n            }\n        }\n    });\n}\n\n\n/**\n * @class\n * Usage of query:\n * `chart.on('click', query, handler);`\n * The `query` can be:\n * + The component type query string, only `mainType` or `mainType.subType`,\n *   like: 'xAxis', 'series', 'xAxis.category' or 'series.line'.\n * + The component query object, like:\n *   `{seriesIndex: 2}`, `{seriesName: 'xx'}`, `{seriesId: 'some'}`,\n *   `{xAxisIndex: 2}`, `{xAxisName: 'xx'}`, `{xAxisId: 'some'}`.\n * + The data query object, like:\n *   `{dataIndex: 123}`, `{dataType: 'link'}`, `{name: 'some'}`.\n * + The other query object (cmponent customized query), like:\n *   `{element: 'some'}` (only available in custom series).\n *\n * Caveat: If a prop in the `query` object is `null/undefined`, it is the\n * same as there is no such prop in the `query` object.\n */\nfunction EventProcessor() {\n    // These info required: targetEl, packedEvent, model, view\n    this.eventInfo;\n}\nEventProcessor.prototype = {\n    constructor: EventProcessor,\n\n    normalizeQuery: function (query) {\n        var cptQuery = {};\n        var dataQuery = {};\n        var otherQuery = {};\n\n        // `query` is `mainType` or `mainType.subType` of component.\n        if (isString(query)) {\n            var condCptType = parseClassType(query);\n            // `.main` and `.sub` may be ''.\n            cptQuery.mainType = condCptType.main || null;\n            cptQuery.subType = condCptType.sub || null;\n        }\n        // `query` is an object, convert to {mainType, index, name, id}.\n        else {\n            // `xxxIndex`, `xxxName`, `xxxId`, `name`, `dataIndex`, `dataType` is reserved,\n            // can not be used in `compomentModel.filterForExposedEvent`.\n            var suffixes = ['Index', 'Name', 'Id'];\n            var dataKeys = {name: 1, dataIndex: 1, dataType: 1};\n            each$1(query, function (val, key) {\n                var reserved = false;\n                for (var i = 0; i < suffixes.length; i++) {\n                    var propSuffix = suffixes[i];\n                    var suffixPos = key.lastIndexOf(propSuffix);\n                    if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) {\n                        var mainType = key.slice(0, suffixPos);\n                        // Consider `dataIndex`.\n                        if (mainType !== 'data') {\n                            cptQuery.mainType = mainType;\n                            cptQuery[propSuffix.toLowerCase()] = val;\n                            reserved = true;\n                        }\n                    }\n                }\n                if (dataKeys.hasOwnProperty(key)) {\n                    dataQuery[key] = val;\n                    reserved = true;\n                }\n                if (!reserved) {\n                    otherQuery[key] = val;\n                }\n            });\n        }\n\n        return {\n            cptQuery: cptQuery,\n            dataQuery: dataQuery,\n            otherQuery: otherQuery\n        };\n    },\n\n    filter: function (eventType, query, args) {\n        // They should be assigned before each trigger call.\n        var eventInfo = this.eventInfo;\n\n        if (!eventInfo) {\n            return true;\n        }\n\n        var targetEl = eventInfo.targetEl;\n        var packedEvent = eventInfo.packedEvent;\n        var model = eventInfo.model;\n        var view = eventInfo.view;\n\n        // For event like 'globalout'.\n        if (!model || !view) {\n            return true;\n        }\n\n        var cptQuery = query.cptQuery;\n        var dataQuery = query.dataQuery;\n\n        return check(cptQuery, model, 'mainType')\n            && check(cptQuery, model, 'subType')\n            && check(cptQuery, model, 'index', 'componentIndex')\n            && check(cptQuery, model, 'name')\n            && check(cptQuery, model, 'id')\n            && check(dataQuery, packedEvent, 'name')\n            && check(dataQuery, packedEvent, 'dataIndex')\n            && check(dataQuery, packedEvent, 'dataType')\n            && (!view.filterForExposedEvent || view.filterForExposedEvent(\n                eventType, query.otherQuery, targetEl, packedEvent\n            ));\n\n        function check(query, host, prop, propOnHost) {\n            return query[prop] == null || host[propOnHost || prop] === query[prop];\n        }\n    },\n\n    afterTrigger: function () {\n        // Make sure the eventInfo wont be used in next trigger.\n        this.eventInfo = null;\n    }\n};\n\n\n/**\n * @type {Object} key: actionType.\n * @inner\n */\nvar actions = {};\n\n/**\n * Map eventType to actionType\n * @type {Object}\n */\nvar eventActionMap = {};\n\n/**\n * Data processor functions of each stage\n * @type {Array.<Object.<string, Function>>}\n * @inner\n */\nvar dataProcessorFuncs = [];\n\n/**\n * @type {Array.<Function>}\n * @inner\n */\nvar optionPreprocessorFuncs = [];\n\n/**\n * @type {Array.<Function>}\n * @inner\n */\nvar postUpdateFuncs = [];\n\n/**\n * Visual encoding functions of each stage\n * @type {Array.<Object.<string, Function>>}\n */\nvar visualFuncs = [];\n\n/**\n * Theme storage\n * @type {Object.<key, Object>}\n */\nvar themeStorage = {};\n/**\n * Loading effects\n */\nvar loadingEffects = {};\n\nvar instances = {};\nvar connectedGroups = {};\n\nvar idBase = new Date() - 0;\nvar groupIdBase = new Date() - 0;\nvar DOM_ATTRIBUTE_KEY = '_echarts_instance_';\n\nfunction enableConnect(chart) {\n    var STATUS_PENDING = 0;\n    var STATUS_UPDATING = 1;\n    var STATUS_UPDATED = 2;\n    var STATUS_KEY = '__connectUpdateStatus';\n\n    function updateConnectedChartsStatus(charts, status) {\n        for (var i = 0; i < charts.length; i++) {\n            var otherChart = charts[i];\n            otherChart[STATUS_KEY] = status;\n        }\n    }\n\n    each(eventActionMap, function (actionType, eventType) {\n        chart._messageCenter.on(eventType, function (event) {\n            if (connectedGroups[chart.group] && chart[STATUS_KEY] !== STATUS_PENDING) {\n                if (event && event.escapeConnect) {\n                    return;\n                }\n\n                var action = chart.makeActionFromEvent(event);\n                var otherCharts = [];\n\n                each(instances, function (otherChart) {\n                    if (otherChart !== chart && otherChart.group === chart.group) {\n                        otherCharts.push(otherChart);\n                    }\n                });\n\n                updateConnectedChartsStatus(otherCharts, STATUS_PENDING);\n                each(otherCharts, function (otherChart) {\n                    if (otherChart[STATUS_KEY] !== STATUS_UPDATING) {\n                        otherChart.dispatchAction(action);\n                    }\n                });\n                updateConnectedChartsStatus(otherCharts, STATUS_UPDATED);\n            }\n        });\n    });\n}\n\n/**\n * @param {HTMLElement} dom\n * @param {Object} [theme]\n * @param {Object} opts\n * @param {number} [opts.devicePixelRatio] Use window.devicePixelRatio by default\n * @param {string} [opts.renderer] Currently only 'canvas' is supported.\n * @param {number} [opts.width] Use clientWidth of the input `dom` by default.\n *                              Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Use clientHeight of the input `dom` by default.\n *                               Can be 'auto' (the same as null/undefined)\n */\nfunction init(dom, theme$$1, opts) {\n    if (__DEV__) {\n        // Check version\n        if ((version$1.replace('.', '') - 0) < (dependencies.zrender.replace('.', '') - 0)) {\n            throw new Error(\n                'zrender/src ' + version$1\n                + ' is too old for ECharts ' + version\n                + '. Current version need ZRender '\n                + dependencies.zrender + '+'\n            );\n        }\n\n        if (!dom) {\n            throw new Error('Initialize failed: invalid dom.');\n        }\n    }\n\n    var existInstance = getInstanceByDom(dom);\n    if (existInstance) {\n        if (__DEV__) {\n            console.warn('There is a chart instance already initialized on the dom.');\n        }\n        return existInstance;\n    }\n\n    if (__DEV__) {\n        if (isDom(dom)\n            && dom.nodeName.toUpperCase() !== 'CANVAS'\n            && (\n                (!dom.clientWidth && (!opts || opts.width == null))\n                || (!dom.clientHeight && (!opts || opts.height == null))\n            )\n        ) {\n            console.warn('Can\\'t get dom width or height');\n        }\n    }\n\n    var chart = new ECharts(dom, theme$$1, opts);\n    chart.id = 'ec_' + idBase++;\n    instances[chart.id] = chart;\n\n    setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id);\n\n    enableConnect(chart);\n\n    return chart;\n}\n\n/**\n * @return {string|Array.<module:echarts~ECharts>} groupId\n */\nfunction connect(groupId) {\n    // Is array of charts\n    if (isArray(groupId)) {\n        var charts = groupId;\n        groupId = null;\n        // If any chart has group\n        each(charts, function (chart) {\n            if (chart.group != null) {\n                groupId = chart.group;\n            }\n        });\n        groupId = groupId || ('g_' + groupIdBase++);\n        each(charts, function (chart) {\n            chart.group = groupId;\n        });\n    }\n    connectedGroups[groupId] = true;\n    return groupId;\n}\n\n/**\n * @DEPRECATED\n * @return {string} groupId\n */\nfunction disConnect(groupId) {\n    connectedGroups[groupId] = false;\n}\n\n/**\n * @return {string} groupId\n */\nvar disconnect = disConnect;\n\n/**\n * Dispose a chart instance\n * @param  {module:echarts~ECharts|HTMLDomElement|string} chart\n */\nfunction dispose(chart) {\n    if (typeof chart === 'string') {\n        chart = instances[chart];\n    }\n    else if (!(chart instanceof ECharts)) {\n        // Try to treat as dom\n        chart = getInstanceByDom(chart);\n    }\n    if ((chart instanceof ECharts) && !chart.isDisposed()) {\n        chart.dispose();\n    }\n}\n\n/**\n * @param  {HTMLElement} dom\n * @return {echarts~ECharts}\n */\nfunction getInstanceByDom(dom) {\n    return instances[getAttribute(dom, DOM_ATTRIBUTE_KEY)];\n}\n\n/**\n * @param {string} key\n * @return {echarts~ECharts}\n */\nfunction getInstanceById(key) {\n    return instances[key];\n}\n\n/**\n * Register theme\n */\nfunction registerTheme(name, theme$$1) {\n    themeStorage[name] = theme$$1;\n}\n\n/**\n * Register option preprocessor\n * @param {Function} preprocessorFunc\n */\nfunction registerPreprocessor(preprocessorFunc) {\n    optionPreprocessorFuncs.push(preprocessorFunc);\n}\n\n/**\n * @param {number} [priority=1000]\n * @param {Object|Function} processor\n */\nfunction registerProcessor(priority, processor) {\n    normalizeRegister(dataProcessorFuncs, priority, processor, PRIORITY_PROCESSOR_FILTER);\n}\n\n/**\n * Register postUpdater\n * @param {Function} postUpdateFunc\n */\nfunction registerPostUpdate(postUpdateFunc) {\n    postUpdateFuncs.push(postUpdateFunc);\n}\n\n/**\n * Usage:\n * registerAction('someAction', 'someEvent', function () { ... });\n * registerAction('someAction', function () { ... });\n * registerAction(\n *     {type: 'someAction', event: 'someEvent', update: 'updateView'},\n *     function () { ... }\n * );\n *\n * @param {(string|Object)} actionInfo\n * @param {string} actionInfo.type\n * @param {string} [actionInfo.event]\n * @param {string} [actionInfo.update]\n * @param {string} [eventName]\n * @param {Function} action\n */\nfunction registerAction(actionInfo, eventName, action) {\n    if (typeof eventName === 'function') {\n        action = eventName;\n        eventName = '';\n    }\n    var actionType = isObject(actionInfo)\n        ? actionInfo.type\n        : ([actionInfo, actionInfo = {\n            event: eventName\n        }][0]);\n\n    // Event name is all lowercase\n    actionInfo.event = (actionInfo.event || actionType).toLowerCase();\n    eventName = actionInfo.event;\n\n    // Validate action type and event name.\n    assert(ACTION_REG.test(actionType) && ACTION_REG.test(eventName));\n\n    if (!actions[actionType]) {\n        actions[actionType] = {action: action, actionInfo: actionInfo};\n    }\n    eventActionMap[eventName] = actionType;\n}\n\n/**\n * @param {string} type\n * @param {*} CoordinateSystem\n */\nfunction registerCoordinateSystem(type, CoordinateSystem$$1) {\n    CoordinateSystemManager.register(type, CoordinateSystem$$1);\n}\n\n/**\n * Get dimensions of specified coordinate system.\n * @param {string} type\n * @return {Array.<string|Object>}\n */\nfunction getCoordinateSystemDimensions(type) {\n    var coordSysCreator = CoordinateSystemManager.get(type);\n    if (coordSysCreator) {\n        return coordSysCreator.getDimensionsInfo\n                ? coordSysCreator.getDimensionsInfo()\n                : coordSysCreator.dimensions.slice();\n    }\n}\n\n/**\n * Layout is a special stage of visual encoding\n * Most visual encoding like color are common for different chart\n * But each chart has it's own layout algorithm\n *\n * @param {number} [priority=1000]\n * @param {Function} layoutTask\n */\nfunction registerLayout(priority, layoutTask) {\n    normalizeRegister(visualFuncs, priority, layoutTask, PRIORITY_VISUAL_LAYOUT, 'layout');\n}\n\n/**\n * @param {number} [priority=3000]\n * @param {module:echarts/stream/Task} visualTask\n */\nfunction registerVisual(priority, visualTask) {\n    normalizeRegister(visualFuncs, priority, visualTask, PRIORITY_VISUAL_CHART, 'visual');\n}\n\n/**\n * @param {Object|Function} fn: {seriesType, createOnAllSeries, performRawSeries, reset}\n */\nfunction normalizeRegister(targetList, priority, fn, defaultPriority, visualType) {\n    if (isFunction(priority) || isObject(priority)) {\n        fn = priority;\n        priority = defaultPriority;\n    }\n\n    if (__DEV__) {\n        if (isNaN(priority) || priority == null) {\n            throw new Error('Illegal priority');\n        }\n        // Check duplicate\n        each(targetList, function (wrap) {\n            assert(wrap.__raw !== fn);\n        });\n    }\n\n    var stageHandler = Scheduler.wrapStageHandler(fn, visualType);\n\n    stageHandler.__prio = priority;\n    stageHandler.__raw = fn;\n    targetList.push(stageHandler);\n\n    return stageHandler;\n}\n\n/**\n * @param {string} name\n */\nfunction registerLoading(name, loadingFx) {\n    loadingEffects[name] = loadingFx;\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendComponentModel(opts/*, superClass*/) {\n    // var Clazz = ComponentModel;\n    // if (superClass) {\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentModel.getClass(classType.main, classType.sub, true);\n    // }\n    return ComponentModel.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendComponentView(opts/*, superClass*/) {\n    // var Clazz = ComponentView;\n    // if (superClass) {\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentView.getClass(classType.main, classType.sub, true);\n    // }\n    return Component.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendSeriesModel(opts/*, superClass*/) {\n    // var Clazz = SeriesModel;\n    // if (superClass) {\n    //     superClass = 'series.' + superClass.replace('series.', '');\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentModel.getClass(classType.main, classType.sub, true);\n    // }\n    return SeriesModel.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendChartView(opts/*, superClass*/) {\n    // var Clazz = ChartView;\n    // if (superClass) {\n    //     superClass = superClass.replace('series.', '');\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ChartView.getClass(classType.main, true);\n    // }\n    return Chart.extend(opts);\n}\n\n/**\n * ZRender need a canvas context to do measureText.\n * But in node environment canvas may be created by node-canvas.\n * So we need to specify how to create a canvas instead of using document.createElement('canvas')\n *\n * Be careful of using it in the browser.\n *\n * @param {Function} creator\n * @example\n *     var Canvas = require('canvas');\n *     var echarts = require('echarts');\n *     echarts.setCanvasCreator(function () {\n *         // Small size is enough.\n *         return new Canvas(32, 32);\n *     });\n */\nfunction setCanvasCreator(creator) {\n    $override('createCanvas', creator);\n}\n\n/**\n * @param {string} mapName\n * @param {Array.<Object>|Object|string} geoJson\n * @param {Object} [specialAreas]\n *\n * @example GeoJSON\n *     $.get('USA.json', function (geoJson) {\n *         echarts.registerMap('USA', geoJson);\n *         // Or\n *         echarts.registerMap('USA', {\n *             geoJson: geoJson,\n *             specialAreas: {}\n *         })\n *     });\n *\n *     $.get('airport.svg', function (svg) {\n *         echarts.registerMap('airport', {\n *             svg: svg\n *         }\n *     });\n *\n *     echarts.registerMap('eu', [\n *         {svg: eu-topographic.svg},\n *         {geoJSON: eu.json}\n *     ])\n */\nfunction registerMap(mapName, geoJson, specialAreas) {\n    mapDataStorage.registerMap(mapName, geoJson, specialAreas);\n}\n\n/**\n * @param {string} mapName\n * @return {Object}\n */\nfunction getMap(mapName) {\n    // For backward compatibility, only return the first one.\n    var records = mapDataStorage.retrieveMap(mapName);\n    return records && records[0] && {\n        geoJson: records[0].geoJSON,\n        specialAreas: records[0].specialAreas\n    };\n}\n\nregisterVisual(PRIORITY_VISUAL_GLOBAL, seriesColor);\nregisterPreprocessor(backwardCompat);\nregisterProcessor(PRIORITY_PROCESSOR_STATISTIC, dataStack);\nregisterLoading('default', loadingDefault);\n\n// Default actions\n\nregisterAction({\n    type: 'highlight',\n    event: 'highlight',\n    update: 'highlight'\n}, noop);\n\nregisterAction({\n    type: 'downplay',\n    event: 'downplay',\n    update: 'downplay'\n}, noop);\n\n// Default theme\nregisterTheme('light', lightTheme);\nregisterTheme('dark', theme);\n\n// For backward compatibility, where the namespace `dataTool` will\n// be mounted on `echarts` is the extension `dataTool` is imported.\nvar dataTool = {};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction defaultKeyGetter(item) {\n    return item;\n}\n\n/**\n * @param {Array} oldArr\n * @param {Array} newArr\n * @param {Function} oldKeyGetter\n * @param {Function} newKeyGetter\n * @param {Object} [context] Can be visited by this.context in callback.\n */\nfunction DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter, context) {\n    this._old = oldArr;\n    this._new = newArr;\n\n    this._oldKeyGetter = oldKeyGetter || defaultKeyGetter;\n    this._newKeyGetter = newKeyGetter || defaultKeyGetter;\n\n    this.context = context;\n}\n\nDataDiffer.prototype = {\n\n    constructor: DataDiffer,\n\n    /**\n     * Callback function when add a data\n     */\n    add: function (func) {\n        this._add = func;\n        return this;\n    },\n\n    /**\n     * Callback function when update a data\n     */\n    update: function (func) {\n        this._update = func;\n        return this;\n    },\n\n    /**\n     * Callback function when remove a data\n     */\n    remove: function (func) {\n        this._remove = func;\n        return this;\n    },\n\n    execute: function () {\n        var oldArr = this._old;\n        var newArr = this._new;\n\n        var oldDataIndexMap = {};\n        var newDataIndexMap = {};\n        var oldDataKeyArr = [];\n        var newDataKeyArr = [];\n        var i;\n\n        initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, '_oldKeyGetter', this);\n        initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter', this);\n\n        // Travel by inverted order to make sure order consistency\n        // when duplicate keys exists (consider newDataIndex.pop() below).\n        // For performance consideration, these code below do not look neat.\n        for (i = 0; i < oldArr.length; i++) {\n            var key = oldDataKeyArr[i];\n            var idx = newDataIndexMap[key];\n\n            // idx can never be empty array here. see 'set null' logic below.\n            if (idx != null) {\n                // Consider there is duplicate key (for example, use dataItem.name as key).\n                // We should make sure every item in newArr and oldArr can be visited.\n                var len = idx.length;\n                if (len) {\n                    len === 1 && (newDataIndexMap[key] = null);\n                    idx = idx.unshift();\n                }\n                else {\n                    newDataIndexMap[key] = null;\n                }\n                this._update && this._update(idx, i);\n            }\n            else {\n                this._remove && this._remove(i);\n            }\n        }\n\n        for (var i = 0; i < newDataKeyArr.length; i++) {\n            var key = newDataKeyArr[i];\n            if (newDataIndexMap.hasOwnProperty(key)) {\n                var idx = newDataIndexMap[key];\n                if (idx == null) {\n                    continue;\n                }\n                // idx can never be empty array here. see 'set null' logic above.\n                if (!idx.length) {\n                    this._add && this._add(idx);\n                }\n                else {\n                    for (var j = 0, len = idx.length; j < len; j++) {\n                        this._add && this._add(idx[j]);\n                    }\n                }\n            }\n        }\n    }\n};\n\nfunction initIndexMap(arr, map, keyArr, keyGetterName, dataDiffer) {\n    for (var i = 0; i < arr.length; i++) {\n        // Add prefix to avoid conflict with Object.prototype.\n        var key = '_ec_' + dataDiffer[keyGetterName](arr[i], i);\n        var existence = map[key];\n        if (existence == null) {\n            keyArr.push(key);\n            map[key] = i;\n        }\n        else {\n            if (!existence.length) {\n                map[key] = existence = [existence];\n            }\n            existence.push(i);\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar OTHER_DIMENSIONS = createHashMap([\n    'tooltip', 'label', 'itemName', 'itemId', 'seriesName'\n]);\n\nfunction summarizeDimensions(data) {\n    var summary = {};\n    var encode = summary.encode = {};\n    var notExtraCoordDimMap = createHashMap();\n    var defaultedLabel = [];\n    var defaultedTooltip = [];\n\n    each$1(data.dimensions, function (dimName) {\n        var dimItem = data.getDimensionInfo(dimName);\n\n        var coordDim = dimItem.coordDim;\n        if (coordDim) {\n            if (__DEV__) {\n                assert$1(OTHER_DIMENSIONS.get(coordDim) == null);\n            }\n            var coordDimArr = encode[coordDim];\n            if (!encode.hasOwnProperty(coordDim)) {\n                coordDimArr = encode[coordDim] = [];\n            }\n            coordDimArr[dimItem.coordDimIndex] = dimName;\n\n            if (!dimItem.isExtraCoord) {\n                notExtraCoordDimMap.set(coordDim, 1);\n\n                // Use the last coord dim (and label friendly) as default label,\n                // because when dataset is used, it is hard to guess which dimension\n                // can be value dimension. If both show x, y on label is not look good,\n                // and conventionally y axis is focused more.\n                if (mayLabelDimType(dimItem.type)) {\n                    defaultedLabel[0] = dimName;\n                }\n            }\n            if (dimItem.defaultTooltip) {\n                defaultedTooltip.push(dimName);\n            }\n        }\n\n        OTHER_DIMENSIONS.each(function (v, otherDim) {\n            var otherDimArr = encode[otherDim];\n            if (!encode.hasOwnProperty(otherDim)) {\n                otherDimArr = encode[otherDim] = [];\n            }\n\n            var dimIndex = dimItem.otherDims[otherDim];\n            if (dimIndex != null && dimIndex !== false) {\n                otherDimArr[dimIndex] = dimItem.name;\n            }\n        });\n    });\n\n    var dataDimsOnCoord = [];\n    var encodeFirstDimNotExtra = {};\n\n    notExtraCoordDimMap.each(function (v, coordDim) {\n        var dimArr = encode[coordDim];\n        // ??? FIXME extra coord should not be set in dataDimsOnCoord.\n        // But should fix the case that radar axes: simplify the logic\n        // of `completeDimension`, remove `extraPrefix`.\n        encodeFirstDimNotExtra[coordDim] = dimArr[0];\n        // Not necessary to remove duplicate, because a data\n        // dim canot on more than one coordDim.\n        dataDimsOnCoord = dataDimsOnCoord.concat(dimArr);\n    });\n\n    summary.dataDimsOnCoord = dataDimsOnCoord;\n    summary.encodeFirstDimNotExtra = encodeFirstDimNotExtra;\n\n    var encodeLabel = encode.label;\n    // FIXME `encode.label` is not recommanded, because formatter can not be set\n    // in this way. Use label.formatter instead. May be remove this approach someday.\n    if (encodeLabel && encodeLabel.length) {\n        defaultedLabel = encodeLabel.slice();\n    }\n\n    var encodeTooltip = encode.tooltip;\n    if (encodeTooltip && encodeTooltip.length) {\n        defaultedTooltip = encodeTooltip.slice();\n    }\n    else if (!defaultedTooltip.length) {\n        defaultedTooltip = defaultedLabel.slice();\n    }\n\n    encode.defaultedLabel = defaultedLabel;\n    encode.defaultedTooltip = defaultedTooltip;\n\n    return summary;\n}\n\nfunction getDimensionTypeByAxis(axisType) {\n    return axisType === 'category'\n        ? 'ordinal'\n        : axisType === 'time'\n        ? 'time'\n        : 'float';\n}\n\nfunction mayLabelDimType(dimType) {\n    // In most cases, ordinal and time do not suitable for label.\n    // Ordinal info can be displayed on axis. Time is too long.\n    return !(dimType === 'ordinal' || dimType === 'time');\n}\n\n// function findTheLastDimMayLabel(data) {\n//     // Get last value dim\n//     var dimensions = data.dimensions.slice();\n//     var valueType;\n//     var valueDim;\n//     while (dimensions.length && (\n//         valueDim = dimensions.pop(),\n//         valueType = data.getDimensionInfo(valueDim).type,\n//         valueType === 'ordinal' || valueType === 'time'\n//     )) {} // jshint ignore:line\n//     return valueDim;\n// }\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float64Array, Int32Array, Uint32Array, Uint16Array */\n\n/**\n * List for data storage\n * @module echarts/data/List\n */\n\nvar isObject$4 = isObject$1;\n\nvar UNDEFINED = 'undefined';\nvar INDEX_NOT_FOUND = -1;\n\n// Use prefix to avoid index to be the same as otherIdList[idx],\n// which will cause weird udpate animation.\nvar ID_PREFIX = 'e\\0\\0';\n\nvar dataCtors = {\n    'float': typeof Float64Array === UNDEFINED\n        ? Array : Float64Array,\n    'int': typeof Int32Array === UNDEFINED\n        ? Array : Int32Array,\n    // Ordinal data type can be string or int\n    'ordinal': Array,\n    'number': Array,\n    'time': Array\n};\n\n// Caution: MUST not use `new CtorUint32Array(arr, 0, len)`, because the Ctor of array is\n// different from the Ctor of typed array.\nvar CtorUint32Array = typeof Uint32Array === UNDEFINED ? Array : Uint32Array;\nvar CtorInt32Array = typeof Int32Array === UNDEFINED ? Array : Int32Array;\nvar CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array;\n\nfunction getIndicesCtor(list) {\n    // The possible max value in this._indicies is always this._rawCount despite of filtering.\n    return list._rawCount > 65535 ? CtorUint32Array : CtorUint16Array;\n}\n\nfunction cloneChunk(originalChunk) {\n    var Ctor = originalChunk.constructor;\n    // Only shallow clone is enough when Array.\n    return Ctor === Array ? originalChunk.slice() : new Ctor(originalChunk);\n}\n\nvar TRANSFERABLE_PROPERTIES = [\n    'hasItemOption', '_nameList', '_idList', '_invertedIndicesMap',\n    '_rawData', '_chunkSize', '_chunkCount', '_dimValueGetter',\n    '_count', '_rawCount', '_nameDimIdx', '_idDimIdx'\n];\nvar CLONE_PROPERTIES = [\n    '_extent', '_approximateExtent', '_rawExtent'\n];\n\nfunction transferProperties(target, source) {\n    each$1(TRANSFERABLE_PROPERTIES.concat(source.__wrappedMethods || []), function (propName) {\n        if (source.hasOwnProperty(propName)) {\n            target[propName] = source[propName];\n        }\n    });\n\n    target.__wrappedMethods = source.__wrappedMethods;\n\n    each$1(CLONE_PROPERTIES, function (propName) {\n        target[propName] = clone(source[propName]);\n    });\n\n    target._calculationInfo = extend(source._calculationInfo);\n}\n\n\n\n\n\n/**\n * @constructor\n * @alias module:echarts/data/List\n *\n * @param {Array.<string|Object>} dimensions\n *      For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...].\n *      Dimensions should be concrete names like x, y, z, lng, lat, angle, radius\n *      Spetial fields: {\n *          ordinalMeta: <module:echarts/data/OrdinalMeta>\n *          createInvertedIndices: <boolean>\n *      }\n * @param {module:echarts/model/Model} hostModel\n */\nvar List = function (dimensions, hostModel) {\n\n    dimensions = dimensions || ['x', 'y'];\n\n    var dimensionInfos = {};\n    var dimensionNames = [];\n    var invertedIndicesMap = {};\n\n    for (var i = 0; i < dimensions.length; i++) {\n        // Use the original dimensions[i], where other flag props may exists.\n        var dimensionInfo = dimensions[i];\n\n        if (isString(dimensionInfo)) {\n            dimensionInfo = {name: dimensionInfo};\n        }\n\n        var dimensionName = dimensionInfo.name;\n        dimensionInfo.type = dimensionInfo.type || 'float';\n        if (!dimensionInfo.coordDim) {\n            dimensionInfo.coordDim = dimensionName;\n            dimensionInfo.coordDimIndex = 0;\n        }\n\n        dimensionInfo.otherDims = dimensionInfo.otherDims || {};\n        dimensionNames.push(dimensionName);\n        dimensionInfos[dimensionName] = dimensionInfo;\n\n        dimensionInfo.index = i;\n\n        if (dimensionInfo.createInvertedIndices) {\n            invertedIndicesMap[dimensionName] = [];\n        }\n    }\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    this.dimensions = dimensionNames;\n\n    /**\n     * Infomation of each data dimension, like data type.\n     * @type {Object}\n     */\n    this._dimensionInfos = dimensionInfos;\n\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.hostModel = hostModel;\n\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.dataType;\n\n    /**\n     * Indices stores the indices of data subset after filtered.\n     * This data subset will be used in chart.\n     * @type {Array.<number>}\n     * @readOnly\n     */\n    this._indices = null;\n\n    this._count = 0;\n    this._rawCount = 0;\n\n    /**\n     * Data storage\n     * @type {Object.<key, Array.<TypedArray|Array>>}\n     * @private\n     */\n    this._storage = {};\n\n    /**\n     * @type {Array.<string>}\n     */\n    this._nameList = [];\n    /**\n     * @type {Array.<string>}\n     */\n    this._idList = [];\n\n    /**\n     * Models of data option is stored sparse for optimizing memory cost\n     * @type {Array.<module:echarts/model/Model>}\n     * @private\n     */\n    this._optionModels = [];\n\n    /**\n     * Global visual properties after visual coding\n     * @type {Object}\n     * @private\n     */\n    this._visual = {};\n\n    /**\n     * Globel layout properties.\n     * @type {Object}\n     * @private\n     */\n    this._layout = {};\n\n    /**\n     * Item visual properties after visual coding\n     * @type {Array.<Object>}\n     * @private\n     */\n    this._itemVisuals = [];\n\n    /**\n     * Key: visual type, Value: boolean\n     * @type {Object}\n     * @readOnly\n     */\n    this.hasItemVisual = {};\n\n    /**\n     * Item layout properties after layout\n     * @type {Array.<Object>}\n     * @private\n     */\n    this._itemLayouts = [];\n\n    /**\n     * Graphic elemnents\n     * @type {Array.<module:zrender/Element>}\n     * @private\n     */\n    this._graphicEls = [];\n\n    /**\n     * Max size of each chunk.\n     * @type {number}\n     * @private\n     */\n    this._chunkSize = 1e5;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    this._chunkCount = 0;\n\n    /**\n     * @type {Array.<Array|Object>}\n     * @private\n     */\n    this._rawData;\n\n    /**\n     * Raw extent will not be cloned, but only transfered.\n     * It will not be calculated util needed.\n     * key: dim,\n     * value: {end: number, extent: Array.<number>}\n     * @type {Object}\n     * @private\n     */\n    this._rawExtent = {};\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._extent = {};\n\n    /**\n     * key: dim\n     * value: extent\n     * @type {Object}\n     * @private\n     */\n    this._approximateExtent = {};\n\n    /**\n     * Cache summary info for fast visit. See \"dimensionHelper\".\n     * @type {Object}\n     * @private\n     */\n    this._dimensionsSummary = summarizeDimensions(this);\n\n    /**\n     * @type {Object.<Array|TypedArray>}\n     * @private\n     */\n    this._invertedIndicesMap = invertedIndicesMap;\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._calculationInfo = {};\n};\n\nvar listProto = List.prototype;\n\nlistProto.type = 'list';\n\n/**\n * If each data item has it's own option\n * @type {boolean}\n */\nlistProto.hasItemOption = true;\n\n/**\n * Get dimension name\n * @param {string|number} dim\n *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius\n *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'\n * @return {string} Concrete dim name.\n */\nlistProto.getDimension = function (dim) {\n    if (!isNaN(dim)) {\n        dim = this.dimensions[dim] || dim;\n    }\n    return dim;\n};\n\n/**\n * Get type and calculation info of particular dimension\n * @param {string|number} dim\n *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius\n *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'\n */\nlistProto.getDimensionInfo = function (dim) {\n    // Do not clone, because there may be categories in dimInfo.\n    return this._dimensionInfos[this.getDimension(dim)];\n};\n\n/**\n * @return {Array.<string>} concrete dimension name list on coord.\n */\nlistProto.getDimensionsOnCoord = function () {\n    return this._dimensionsSummary.dataDimsOnCoord.slice();\n};\n\n/**\n * @param {string} coordDim\n * @param {number} [idx] A coordDim may map to more than one data dim.\n *        If idx is `true`, return a array of all mapped dims.\n *        If idx is not specified, return the first dim not extra.\n * @return {string|Array.<string>} concrete data dim.\n *        If idx is number, and not found, return null/undefined.\n *        If idx is `true`, and not found, return empty array (always return array).\n */\nlistProto.mapDimension = function (coordDim, idx) {\n    var dimensionsSummary = this._dimensionsSummary;\n\n    if (idx == null) {\n        return dimensionsSummary.encodeFirstDimNotExtra[coordDim];\n    }\n\n    var dims = dimensionsSummary.encode[coordDim];\n    return idx === true\n        // always return array if idx is `true`\n        ? (dims || []).slice()\n        : (dims && dims[idx]);\n};\n\n/**\n * Initialize from data\n * @param {Array.<Object|number|Array>} data source or data or data provider.\n * @param {Array.<string>} [nameLIst] The name of a datum is used on data diff and\n *        defualt label/tooltip.\n *        A name can be specified in encode.itemName,\n *        or dataItem.name (only for series option data),\n *        or provided in nameList from outside.\n * @param {Function} [dimValueGetter] (dataItem, dimName, dataIndex, dimIndex) => number\n */\nlistProto.initData = function (data, nameList, dimValueGetter) {\n\n    var notProvider = Source.isInstance(data) || isArrayLike(data);\n    if (notProvider) {\n        data = new DefaultDataProvider(data, this.dimensions.length);\n    }\n\n    if (__DEV__) {\n        if (!notProvider && (typeof data.getItem !== 'function' || typeof data.count !== 'function')) {\n            throw new Error('Inavlid data provider.');\n        }\n    }\n\n    this._rawData = data;\n\n    // Clear\n    this._storage = {};\n    this._indices = null;\n\n    this._nameList = nameList || [];\n\n    this._idList = [];\n\n    this._nameRepeatCount = {};\n\n    if (!dimValueGetter) {\n        this.hasItemOption = false;\n    }\n\n    /**\n     * @readOnly\n     */\n    this.defaultDimValueGetter = defaultDimValueGetters[\n        this._rawData.getSource().sourceFormat\n    ];\n    // Default dim value getter\n    this._dimValueGetter = dimValueGetter = dimValueGetter\n        || this.defaultDimValueGetter;\n    this._dimValueGetterArrayRows = defaultDimValueGetters.arrayRows;\n\n    // Reset raw extent.\n    this._rawExtent = {};\n\n    this._initDataFromProvider(0, data.count());\n\n    // If data has no item option.\n    if (data.pure) {\n        this.hasItemOption = false;\n    }\n};\n\nlistProto.getProvider = function () {\n    return this._rawData;\n};\n\n/**\n * Caution: Can be only called on raw data (before `this._indices` created).\n */\nlistProto.appendData = function (data) {\n    if (__DEV__) {\n        assert$1(!this._indices, 'appendData can only be called on raw data.');\n    }\n\n    var rawData = this._rawData;\n    var start = this.count();\n    rawData.appendData(data);\n    var end = rawData.count();\n    if (!rawData.persistent) {\n        end += start;\n    }\n    this._initDataFromProvider(start, end);\n};\n\n/**\n * Caution: Can be only called on raw data (before `this._indices` created).\n * This method does not modify `rawData` (`dataProvider`), but only\n * add values to storage.\n *\n * The final count will be increased by `Math.max(values.length, names.length)`.\n *\n * @param {Array.<Array.<*>>} values That is the SourceType: 'arrayRows', like\n *        [\n *            [12, 33, 44],\n *            [NaN, 43, 1],\n *            ['-', 'asdf', 0]\n *        ]\n *        Each item is exaclty cooresponding to a dimension.\n * @param {Array.<string>} [names]\n */\nlistProto.appendValues = function (values, names) {\n    var chunkSize = this._chunkSize;\n    var storage = this._storage;\n    var dimensions = this.dimensions;\n    var dimLen = dimensions.length;\n    var rawExtent = this._rawExtent;\n\n    var start = this.count();\n    var end = start + Math.max(values.length, names ? names.length : 0);\n    var originalChunkCount = this._chunkCount;\n\n    for (var i = 0; i < dimLen; i++) {\n        var dim = dimensions[i];\n        if (!rawExtent[dim]) {\n            rawExtent[dim] = getInitialExtent();\n        }\n        if (!storage[dim]) {\n            storage[dim] = [];\n        }\n        prepareChunks(storage, this._dimensionInfos[dim], chunkSize, originalChunkCount, end);\n        this._chunkCount = storage[dim].length;\n    }\n\n    var emptyDataItem = new Array(dimLen);\n    for (var idx = start; idx < end; idx++) {\n        var sourceIdx = idx - start;\n        var chunkIndex = Math.floor(idx / chunkSize);\n        var chunkOffset = idx % chunkSize;\n\n        // Store the data by dimensions\n        for (var k = 0; k < dimLen; k++) {\n            var dim = dimensions[k];\n            var val = this._dimValueGetterArrayRows(\n                values[sourceIdx] || emptyDataItem, dim, sourceIdx, k\n            );\n            storage[dim][chunkIndex][chunkOffset] = val;\n\n            var dimRawExtent = rawExtent[dim];\n            val < dimRawExtent[0] && (dimRawExtent[0] = val);\n            val > dimRawExtent[1] && (dimRawExtent[1] = val);\n        }\n\n        if (names) {\n            this._nameList[idx] = names[sourceIdx];\n        }\n    }\n\n    this._rawCount = this._count = end;\n\n    // Reset data extent\n    this._extent = {};\n\n    prepareInvertedIndex(this);\n};\n\nlistProto._initDataFromProvider = function (start, end) {\n    // Optimize.\n    if (start >= end) {\n        return;\n    }\n\n    var chunkSize = this._chunkSize;\n    var rawData = this._rawData;\n    var storage = this._storage;\n    var dimensions = this.dimensions;\n    var dimLen = dimensions.length;\n    var dimensionInfoMap = this._dimensionInfos;\n    var nameList = this._nameList;\n    var idList = this._idList;\n    var rawExtent = this._rawExtent;\n    var nameRepeatCount = this._nameRepeatCount = {};\n    var nameDimIdx;\n\n    var originalChunkCount = this._chunkCount;\n    for (var i = 0; i < dimLen; i++) {\n        var dim = dimensions[i];\n        if (!rawExtent[dim]) {\n            rawExtent[dim] = getInitialExtent();\n        }\n\n        var dimInfo = dimensionInfoMap[dim];\n        if (dimInfo.otherDims.itemName === 0) {\n            nameDimIdx = this._nameDimIdx = i;\n        }\n        if (dimInfo.otherDims.itemId === 0) {\n            this._idDimIdx = i;\n        }\n\n        if (!storage[dim]) {\n            storage[dim] = [];\n        }\n\n        prepareChunks(storage, dimInfo, chunkSize, originalChunkCount, end);\n\n        this._chunkCount = storage[dim].length;\n    }\n\n    var dataItem = new Array(dimLen);\n    for (var idx = start; idx < end; idx++) {\n        // NOTICE: Try not to write things into dataItem\n        dataItem = rawData.getItem(idx, dataItem);\n        // Each data item is value\n        // [1, 2]\n        // 2\n        // Bar chart, line chart which uses category axis\n        // only gives the 'y' value. 'x' value is the indices of category\n        // Use a tempValue to normalize the value to be a (x, y) value\n        var chunkIndex = Math.floor(idx / chunkSize);\n        var chunkOffset = idx % chunkSize;\n\n        // Store the data by dimensions\n        for (var k = 0; k < dimLen; k++) {\n            var dim = dimensions[k];\n            var dimStorage = storage[dim][chunkIndex];\n            // PENDING NULL is empty or zero\n            var val = this._dimValueGetter(dataItem, dim, idx, k);\n            dimStorage[chunkOffset] = val;\n\n            var dimRawExtent = rawExtent[dim];\n            val < dimRawExtent[0] && (dimRawExtent[0] = val);\n            val > dimRawExtent[1] && (dimRawExtent[1] = val);\n        }\n\n        // ??? FIXME not check by pure but sourceFormat?\n        // TODO refactor these logic.\n        if (!rawData.pure) {\n            var name = nameList[idx];\n\n            if (dataItem && name == null) {\n                // If dataItem is {name: ...}, it has highest priority.\n                // That is appropriate for many common cases.\n                if (dataItem.name != null) {\n                    // There is no other place to persistent dataItem.name,\n                    // so save it to nameList.\n                    nameList[idx] = name = dataItem.name;\n                }\n                else if (nameDimIdx != null) {\n                    var nameDim = dimensions[nameDimIdx];\n                    var nameDimChunk = storage[nameDim][chunkIndex];\n                    if (nameDimChunk) {\n                        name = nameDimChunk[chunkOffset];\n                        var ordinalMeta = dimensionInfoMap[nameDim].ordinalMeta;\n                        if (ordinalMeta && ordinalMeta.categories.length) {\n                            name = ordinalMeta.categories[name];\n                        }\n                    }\n                }\n            }\n\n            // Try using the id in option\n            // id or name is used on dynamical data, mapping old and new items.\n            var id = dataItem == null ? null : dataItem.id;\n\n            if (id == null && name != null) {\n                // Use name as id and add counter to avoid same name\n                nameRepeatCount[name] = nameRepeatCount[name] || 0;\n                id = name;\n                if (nameRepeatCount[name] > 0) {\n                    id += '__ec__' + nameRepeatCount[name];\n                }\n                nameRepeatCount[name]++;\n            }\n            id != null && (idList[idx] = id);\n        }\n    }\n\n    if (!rawData.persistent && rawData.clean) {\n        // Clean unused data if data source is typed array.\n        rawData.clean();\n    }\n\n    this._rawCount = this._count = end;\n\n    // Reset data extent\n    this._extent = {};\n\n    prepareInvertedIndex(this);\n};\n\nfunction prepareChunks(storage, dimInfo, chunkSize, chunkCount, end) {\n    var DataCtor = dataCtors[dimInfo.type];\n    var lastChunkIndex = chunkCount - 1;\n    var dim = dimInfo.name;\n    var resizeChunkArray = storage[dim][lastChunkIndex];\n    if (resizeChunkArray && resizeChunkArray.length < chunkSize) {\n        var newStore = new DataCtor(Math.min(end - lastChunkIndex * chunkSize, chunkSize));\n        // The cost of the copy is probably inconsiderable\n        // within the initial chunkSize.\n        for (var j = 0; j < resizeChunkArray.length; j++) {\n            newStore[j] = resizeChunkArray[j];\n        }\n        storage[dim][lastChunkIndex] = newStore;\n    }\n\n    // Create new chunks.\n    for (var k = chunkCount * chunkSize; k < end; k += chunkSize) {\n        storage[dim].push(new DataCtor(Math.min(end - k, chunkSize)));\n    }\n}\n\nfunction prepareInvertedIndex(list) {\n    var invertedIndicesMap = list._invertedIndicesMap;\n    each$1(invertedIndicesMap, function (invertedIndices, dim) {\n        var dimInfo = list._dimensionInfos[dim];\n\n        // Currently, only dimensions that has ordinalMeta can create inverted indices.\n        var ordinalMeta = dimInfo.ordinalMeta;\n        if (ordinalMeta) {\n            invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array(\n                ordinalMeta.categories.length\n            );\n            // The default value of TypedArray is 0. To avoid miss\n            // mapping to 0, we should set it as INDEX_NOT_FOUND.\n            for (var i = 0; i < invertedIndices.length; i++) {\n                invertedIndices[i] = INDEX_NOT_FOUND;\n            }\n            for (var i = 0; i < list._count; i++) {\n                // Only support the case that all values are distinct.\n                invertedIndices[list.get(dim, i)] = i;\n            }\n        }\n    });\n}\n\nfunction getRawValueFromStore(list, dimIndex, rawIndex) {\n    var val;\n    if (dimIndex != null) {\n        var chunkSize = list._chunkSize;\n        var chunkIndex = Math.floor(rawIndex / chunkSize);\n        var chunkOffset = rawIndex % chunkSize;\n        var dim = list.dimensions[dimIndex];\n        var chunk = list._storage[dim][chunkIndex];\n        if (chunk) {\n            val = chunk[chunkOffset];\n            var ordinalMeta = list._dimensionInfos[dim].ordinalMeta;\n            if (ordinalMeta && ordinalMeta.categories.length) {\n                val = ordinalMeta.categories[val];\n            }\n        }\n    }\n    return val;\n}\n\n/**\n * @return {number}\n */\nlistProto.count = function () {\n    return this._count;\n};\n\nlistProto.getIndices = function () {\n    var newIndices;\n\n    var indices = this._indices;\n    if (indices) {\n        var Ctor = indices.constructor;\n        var thisCount = this._count;\n        // `new Array(a, b, c)` is different from `new Uint32Array(a, b, c)`.\n        if (Ctor === Array) {\n            newIndices = new Ctor(thisCount);\n            for (var i = 0; i < thisCount; i++) {\n                newIndices[i] = indices[i];\n            }\n        }\n        else {\n            newIndices = new Ctor(indices.buffer, 0, thisCount);\n        }\n    }\n    else {\n        var Ctor = getIndicesCtor(this);\n        var newIndices = new Ctor(this.count());\n        for (var i = 0; i < newIndices.length; i++) {\n            newIndices[i] = i;\n        }\n    }\n\n    return newIndices;\n};\n\n/**\n * Get value. Return NaN if idx is out of range.\n * @param {string} dim Dim must be concrete name.\n * @param {number} idx\n * @param {boolean} stack\n * @return {number}\n */\nlistProto.get = function (dim, idx /*, stack */) {\n    if (!(idx >= 0 && idx < this._count)) {\n        return NaN;\n    }\n    var storage = this._storage;\n    if (!storage[dim]) {\n        // TODO Warn ?\n        return NaN;\n    }\n\n    idx = this.getRawIndex(idx);\n\n    var chunkIndex = Math.floor(idx / this._chunkSize);\n    var chunkOffset = idx % this._chunkSize;\n\n    var chunkStore = storage[dim][chunkIndex];\n    var value = chunkStore[chunkOffset];\n    // FIXME ordinal data type is not stackable\n    // if (stack) {\n    //     var dimensionInfo = this._dimensionInfos[dim];\n    //     if (dimensionInfo && dimensionInfo.stackable) {\n    //         var stackedOn = this.stackedOn;\n    //         while (stackedOn) {\n    //             // Get no stacked data of stacked on\n    //             var stackedValue = stackedOn.get(dim, idx);\n    //             // Considering positive stack, negative stack and empty data\n    //             if ((value >= 0 && stackedValue > 0)  // Positive stack\n    //                 || (value <= 0 && stackedValue < 0) // Negative stack\n    //             ) {\n    //                 value += stackedValue;\n    //             }\n    //             stackedOn = stackedOn.stackedOn;\n    //         }\n    //     }\n    // }\n\n    return value;\n};\n\n/**\n * @param {string} dim concrete dim\n * @param {number} rawIndex\n * @return {number|string}\n */\nlistProto.getByRawIndex = function (dim, rawIdx) {\n    if (!(rawIdx >= 0 && rawIdx < this._rawCount)) {\n        return NaN;\n    }\n    var dimStore = this._storage[dim];\n    if (!dimStore) {\n        // TODO Warn ?\n        return NaN;\n    }\n\n    var chunkIndex = Math.floor(rawIdx / this._chunkSize);\n    var chunkOffset = rawIdx % this._chunkSize;\n    var chunkStore = dimStore[chunkIndex];\n    return chunkStore[chunkOffset];\n};\n\n/**\n * FIXME Use `get` on chrome maybe slow(in filterSelf and selectRange).\n * Hack a much simpler _getFast\n * @private\n */\nlistProto._getFast = function (dim, rawIdx) {\n    var chunkIndex = Math.floor(rawIdx / this._chunkSize);\n    var chunkOffset = rawIdx % this._chunkSize;\n    var chunkStore = this._storage[dim][chunkIndex];\n    return chunkStore[chunkOffset];\n};\n\n/**\n * Get value for multi dimensions.\n * @param {Array.<string>} [dimensions] If ignored, using all dimensions.\n * @param {number} idx\n * @return {number}\n */\nlistProto.getValues = function (dimensions, idx /*, stack */) {\n    var values = [];\n\n    if (!isArray(dimensions)) {\n        // stack = idx;\n        idx = dimensions;\n        dimensions = this.dimensions;\n    }\n\n    for (var i = 0, len = dimensions.length; i < len; i++) {\n        values.push(this.get(dimensions[i], idx /*, stack */));\n    }\n\n    return values;\n};\n\n/**\n * If value is NaN. Inlcuding '-'\n * Only check the coord dimensions.\n * @param {string} dim\n * @param {number} idx\n * @return {number}\n */\nlistProto.hasValue = function (idx) {\n    var dataDimsOnCoord = this._dimensionsSummary.dataDimsOnCoord;\n    var dimensionInfos = this._dimensionInfos;\n    for (var i = 0, len = dataDimsOnCoord.length; i < len; i++) {\n        if (\n            // Ordinal type can be string or number\n            dimensionInfos[dataDimsOnCoord[i]].type !== 'ordinal'\n            // FIXME check ordinal when using index?\n            && isNaN(this.get(dataDimsOnCoord[i], idx))\n        ) {\n            return false;\n        }\n    }\n    return true;\n};\n\n/**\n * Get extent of data in one dimension\n * @param {string} dim\n * @param {boolean} stack\n */\nlistProto.getDataExtent = function (dim /*, stack */) {\n    // Make sure use concrete dim as cache name.\n    dim = this.getDimension(dim);\n    var dimData = this._storage[dim];\n    var initialExtent = getInitialExtent();\n\n    // stack = !!((stack || false) && this.getCalculationInfo(dim));\n\n    if (!dimData) {\n        return initialExtent;\n    }\n\n    // Make more strict checkings to ensure hitting cache.\n    var currEnd = this.count();\n    // var cacheName = [dim, !!stack].join('_');\n    // var cacheName = dim;\n\n    // Consider the most cases when using data zoom, `getDataExtent`\n    // happened before filtering. We cache raw extent, which is not\n    // necessary to be cleared and recalculated when restore data.\n    var useRaw = !this._indices; // && !stack;\n    var dimExtent;\n\n    if (useRaw) {\n        return this._rawExtent[dim].slice();\n    }\n    dimExtent = this._extent[dim];\n    if (dimExtent) {\n        return dimExtent.slice();\n    }\n    dimExtent = initialExtent;\n\n    var min = dimExtent[0];\n    var max = dimExtent[1];\n\n    for (var i = 0; i < currEnd; i++) {\n        // var value = stack ? this.get(dim, i, true) : this._getFast(dim, this.getRawIndex(i));\n        var value = this._getFast(dim, this.getRawIndex(i));\n        value < min && (min = value);\n        value > max && (max = value);\n    }\n\n    dimExtent = [min, max];\n\n    this._extent[dim] = dimExtent;\n\n    return dimExtent;\n};\n\n/**\n * Optimize for the scenario that data is filtered by a given extent.\n * Consider that if data amount is more than hundreds of thousand,\n * extent calculation will cost more than 10ms and the cache will\n * be erased because of the filtering.\n */\nlistProto.getApproximateExtent = function (dim /*, stack */) {\n    dim = this.getDimension(dim);\n    return this._approximateExtent[dim] || this.getDataExtent(dim /*, stack */);\n};\n\nlistProto.setApproximateExtent = function (extent, dim /*, stack */) {\n    dim = this.getDimension(dim);\n    this._approximateExtent[dim] = extent.slice();\n};\n\n/**\n * @param {string} key\n * @return {*}\n */\nlistProto.getCalculationInfo = function (key) {\n    return this._calculationInfo[key];\n};\n\n/**\n * @param {string|Object} key or k-v object\n * @param {*} [value]\n */\nlistProto.setCalculationInfo = function (key, value) {\n    isObject$4(key)\n        ? extend(this._calculationInfo, key)\n        : (this._calculationInfo[key] = value);\n};\n\n/**\n * Get sum of data in one dimension\n * @param {string} dim\n */\nlistProto.getSum = function (dim /*, stack */) {\n    var dimData = this._storage[dim];\n    var sum = 0;\n    if (dimData) {\n        for (var i = 0, len = this.count(); i < len; i++) {\n            var value = this.get(dim, i /*, stack */);\n            if (!isNaN(value)) {\n                sum += value;\n            }\n        }\n    }\n    return sum;\n};\n\n/**\n * Get median of data in one dimension\n * @param {string} dim\n */\nlistProto.getMedian = function (dim /*, stack */) {\n    var dimDataArray = [];\n    // map all data of one dimension\n    this.each(dim, function (val, idx) {\n        if (!isNaN(val)) {\n            dimDataArray.push(val);\n        }\n    });\n\n    // TODO\n    // Use quick select?\n\n    // immutability & sort\n    var sortedDimDataArray = [].concat(dimDataArray).sort(function (a, b) {\n        return a - b;\n    });\n    var len = this.count();\n    // calculate median\n    return len === 0\n        ? 0\n        : len % 2 === 1\n        ? sortedDimDataArray[(len - 1) / 2]\n        : (sortedDimDataArray[len / 2] + sortedDimDataArray[len / 2 - 1]) / 2;\n};\n\n// /**\n//  * Retreive the index with given value\n//  * @param {string} dim Concrete dimension.\n//  * @param {number} value\n//  * @return {number}\n//  */\n// Currently incorrect: should return dataIndex but not rawIndex.\n// Do not fix it until this method is to be used somewhere.\n// FIXME Precision of float value\n// listProto.indexOf = function (dim, value) {\n//     var storage = this._storage;\n//     var dimData = storage[dim];\n//     var chunkSize = this._chunkSize;\n//     if (dimData) {\n//         for (var i = 0, len = this.count(); i < len; i++) {\n//             var chunkIndex = Math.floor(i / chunkSize);\n//             var chunkOffset = i % chunkSize;\n//             if (dimData[chunkIndex][chunkOffset] === value) {\n//                 return i;\n//             }\n//         }\n//     }\n//     return -1;\n// };\n\n/**\n * Only support the dimension which inverted index created.\n * Do not support other cases until required.\n * @param {string} concrete dim\n * @param {number|string} value\n * @return {number} rawIndex\n */\nlistProto.rawIndexOf = function (dim, value) {\n    var invertedIndices = dim && this._invertedIndicesMap[dim];\n    if (__DEV__) {\n        if (!invertedIndices) {\n            throw new Error('Do not supported yet');\n        }\n    }\n    var rawIndex = invertedIndices[value];\n    if (rawIndex == null || isNaN(rawIndex)) {\n        return INDEX_NOT_FOUND;\n    }\n    return rawIndex;\n};\n\n/**\n * Retreive the index with given name\n * @param {number} idx\n * @param {number} name\n * @return {number}\n */\nlistProto.indexOfName = function (name) {\n    for (var i = 0, len = this.count(); i < len; i++) {\n        if (this.getName(i) === name) {\n            return i;\n        }\n    }\n\n    return -1;\n};\n\n/**\n * Retreive the index with given raw data index\n * @param {number} idx\n * @param {number} name\n * @return {number}\n */\nlistProto.indexOfRawIndex = function (rawIndex) {\n    if (!this._indices) {\n        return rawIndex;\n    }\n\n    if (rawIndex >= this._rawCount || rawIndex < 0) {\n        return -1;\n    }\n\n    // Indices are ascending\n    var indices = this._indices;\n\n    // If rawIndex === dataIndex\n    var rawDataIndex = indices[rawIndex];\n    if (rawDataIndex != null && rawDataIndex < this._count && rawDataIndex === rawIndex) {\n        return rawIndex;\n    }\n\n    var left = 0;\n    var right = this._count - 1;\n    while (left <= right) {\n        var mid = (left + right) / 2 | 0;\n        if (indices[mid] < rawIndex) {\n            left = mid + 1;\n        }\n        else if (indices[mid] > rawIndex) {\n            right = mid - 1;\n        }\n        else {\n            return mid;\n        }\n    }\n    return -1;\n};\n\n/**\n * Retreive the index of nearest value\n * @param {string} dim\n * @param {number} value\n * @param {number} [maxDistance=Infinity]\n * @return {Array.<number>} Considere multiple points has the same value.\n */\nlistProto.indicesOfNearest = function (dim, value, maxDistance) {\n    var storage = this._storage;\n    var dimData = storage[dim];\n    var nearestIndices = [];\n\n    if (!dimData) {\n        return nearestIndices;\n    }\n\n    if (maxDistance == null) {\n        maxDistance = Infinity;\n    }\n\n    var minDist = Number.MAX_VALUE;\n    var minDiff = -1;\n    for (var i = 0, len = this.count(); i < len; i++) {\n        var diff = value - this.get(dim, i /*, stack */);\n        var dist = Math.abs(diff);\n        if (diff <= maxDistance && dist <= minDist) {\n            // For the case of two data are same on xAxis, which has sequence data.\n            // Show the nearest index\n            // https://github.com/ecomfe/echarts/issues/2869\n            if (dist < minDist || (diff >= 0 && minDiff < 0)) {\n                minDist = dist;\n                minDiff = diff;\n                nearestIndices.length = 0;\n            }\n            nearestIndices.push(i);\n        }\n    }\n    return nearestIndices;\n};\n\n/**\n * Get raw data index\n * @param {number} idx\n * @return {number}\n */\nlistProto.getRawIndex = getRawIndexWithoutIndices;\n\nfunction getRawIndexWithoutIndices(idx) {\n    return idx;\n}\n\nfunction getRawIndexWithIndices(idx) {\n    if (idx < this._count && idx >= 0) {\n        return this._indices[idx];\n    }\n    return -1;\n}\n\n/**\n * Get raw data item\n * @param {number} idx\n * @return {number}\n */\nlistProto.getRawDataItem = function (idx) {\n    if (!this._rawData.persistent) {\n        var val = [];\n        for (var i = 0; i < this.dimensions.length; i++) {\n            var dim = this.dimensions[i];\n            val.push(this.get(dim, idx));\n        }\n        return val;\n    }\n    else {\n        return this._rawData.getItem(this.getRawIndex(idx));\n    }\n};\n\n/**\n * @param {number} idx\n * @param {boolean} [notDefaultIdx=false]\n * @return {string}\n */\nlistProto.getName = function (idx) {\n    var rawIndex = this.getRawIndex(idx);\n    return this._nameList[rawIndex]\n        || getRawValueFromStore(this, this._nameDimIdx, rawIndex)\n        || '';\n};\n\n/**\n * @param {number} idx\n * @param {boolean} [notDefaultIdx=false]\n * @return {string}\n */\nlistProto.getId = function (idx) {\n    return getId(this, this.getRawIndex(idx));\n};\n\nfunction getId(list, rawIndex) {\n    var id = list._idList[rawIndex];\n    if (id == null) {\n        id = getRawValueFromStore(list, list._idDimIdx, rawIndex);\n    }\n    if (id == null) {\n        // FIXME Check the usage in graph, should not use prefix.\n        id = ID_PREFIX + rawIndex;\n    }\n    return id;\n}\n\nfunction normalizeDimensions(dimensions) {\n    if (!isArray(dimensions)) {\n        dimensions = [dimensions];\n    }\n    return dimensions;\n}\n\nfunction validateDimensions(list, dims) {\n    for (var i = 0; i < dims.length; i++) {\n        // stroage may be empty when no data, so use\n        // dimensionInfos to check.\n        if (!list._dimensionInfos[dims[i]]) {\n            console.error('Unkown dimension ' + dims[i]);\n        }\n    }\n}\n\n/**\n * Data iteration\n * @param {string|Array.<string>}\n * @param {Function} cb\n * @param {*} [context=this]\n *\n * @example\n *  list.each('x', function (x, idx) {});\n *  list.each(['x', 'y'], function (x, y, idx) {});\n *  list.each(function (idx) {})\n */\nlistProto.each = function (dims, cb, context, contextCompat) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    if (typeof dims === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dims;\n        dims = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dims = map(normalizeDimensions(dims), this.getDimension, this);\n\n    if (__DEV__) {\n        validateDimensions(this, dims);\n    }\n\n    var dimSize = dims.length;\n\n    for (var i = 0; i < this.count(); i++) {\n        // Simple optimization\n        switch (dimSize) {\n            case 0:\n                cb.call(context, i);\n                break;\n            case 1:\n                cb.call(context, this.get(dims[0], i), i);\n                break;\n            case 2:\n                cb.call(context, this.get(dims[0], i), this.get(dims[1], i), i);\n                break;\n            default:\n                var k = 0;\n                var value = [];\n                for (; k < dimSize; k++) {\n                    value[k] = this.get(dims[k], i);\n                }\n                // Index\n                value[k] = i;\n                cb.apply(context, value);\n        }\n    }\n};\n\n/**\n * Data filter\n * @param {string|Array.<string>}\n * @param {Function} cb\n * @param {*} [context=this]\n */\nlistProto.filterSelf = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    if (typeof dimensions === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dimensions;\n        dimensions = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dimensions = map(\n        normalizeDimensions(dimensions), this.getDimension, this\n    );\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n\n    var count = this.count();\n    var Ctor = getIndicesCtor(this);\n    var newIndices = new Ctor(count);\n    var value = [];\n    var dimSize = dimensions.length;\n\n    var offset = 0;\n    var dim0 = dimensions[0];\n\n    for (var i = 0; i < count; i++) {\n        var keep;\n        var rawIdx = this.getRawIndex(i);\n        // Simple optimization\n        if (dimSize === 0) {\n            keep = cb.call(context, i);\n        }\n        else if (dimSize === 1) {\n            var val = this._getFast(dim0, rawIdx);\n            keep = cb.call(context, val, i);\n        }\n        else {\n            for (var k = 0; k < dimSize; k++) {\n                value[k] = this._getFast(dim0, rawIdx);\n            }\n            value[k] = i;\n            keep = cb.apply(context, value);\n        }\n        if (keep) {\n            newIndices[offset++] = rawIdx;\n        }\n    }\n\n    // Set indices after filtered.\n    if (offset < count) {\n        this._indices = newIndices;\n    }\n    this._count = offset;\n    // Reset data extent\n    this._extent = {};\n\n    this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return this;\n};\n\n/**\n * Select data in range. (For optimization of filter)\n * (Manually inline code, support 5 million data filtering in data zoom.)\n */\nlistProto.selectRange = function (range) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    var dimensions = [];\n    for (var dim in range) {\n        if (range.hasOwnProperty(dim)) {\n            dimensions.push(dim);\n        }\n    }\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n    var dimSize = dimensions.length;\n    if (!dimSize) {\n        return;\n    }\n\n    var originalCount = this.count();\n    var Ctor = getIndicesCtor(this);\n    var newIndices = new Ctor(originalCount);\n\n    var offset = 0;\n    var dim0 = dimensions[0];\n\n    var min = range[dim0][0];\n    var max = range[dim0][1];\n\n    var quickFinished = false;\n    if (!this._indices) {\n        // Extreme optimization for common case. About 2x faster in chrome.\n        var idx = 0;\n        if (dimSize === 1) {\n            var dimStorage = this._storage[dimensions[0]];\n            for (var k = 0; k < this._chunkCount; k++) {\n                var chunkStorage = dimStorage[k];\n                var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);\n                for (var i = 0; i < len; i++) {\n                    var val = chunkStorage[i];\n                    // NaN will not be filtered. Consider the case, in line chart, empty\n                    // value indicates the line should be broken. But for the case like\n                    // scatter plot, a data item with empty value will not be rendered,\n                    // but the axis extent may be effected if some other dim of the data\n                    // item has value. Fortunately it is not a significant negative effect.\n                    if (\n                        (val >= min && val <= max) || isNaN(val)\n                    ) {\n                        newIndices[offset++] = idx;\n                    }\n                    idx++;\n                }\n            }\n            quickFinished = true;\n        }\n        else if (dimSize === 2) {\n            var dimStorage = this._storage[dim0];\n            var dimStorage2 = this._storage[dimensions[1]];\n            var min2 = range[dimensions[1]][0];\n            var max2 = range[dimensions[1]][1];\n            for (var k = 0; k < this._chunkCount; k++) {\n                var chunkStorage = dimStorage[k];\n                var chunkStorage2 = dimStorage2[k];\n                var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);\n                for (var i = 0; i < len; i++) {\n                    var val = chunkStorage[i];\n                    var val2 = chunkStorage2[i];\n                    // Do not filter NaN, see comment above.\n                    if ((\n                            (val >= min && val <= max) || isNaN(val)\n                        )\n                        && (\n                            (val2 >= min2 && val2 <= max2) || isNaN(val2)\n                        )\n                    ) {\n                        newIndices[offset++] = idx;\n                    }\n                    idx++;\n                }\n            }\n            quickFinished = true;\n        }\n    }\n    if (!quickFinished) {\n        if (dimSize === 1) {\n            for (var i = 0; i < originalCount; i++) {\n                var rawIndex = this.getRawIndex(i);\n                var val = this._getFast(dim0, rawIndex);\n                // Do not filter NaN, see comment above.\n                if (\n                    (val >= min && val <= max) || isNaN(val)\n                ) {\n                    newIndices[offset++] = rawIndex;\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < originalCount; i++) {\n                var keep = true;\n                var rawIndex = this.getRawIndex(i);\n                for (var k = 0; k < dimSize; k++) {\n                    var dimk = dimensions[k];\n                    var val = this._getFast(dim, rawIndex);\n                    // Do not filter NaN, see comment above.\n                    if (val < range[dimk][0] || val > range[dimk][1]) {\n                        keep = false;\n                    }\n                }\n                if (keep) {\n                    newIndices[offset++] = this.getRawIndex(i);\n                }\n            }\n        }\n    }\n\n    // Set indices after filtered.\n    if (offset < originalCount) {\n        this._indices = newIndices;\n    }\n    this._count = offset;\n    // Reset data extent\n    this._extent = {};\n\n    this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return this;\n};\n\n/**\n * Data mapping to a plain array\n * @param {string|Array.<string>} [dimensions]\n * @param {Function} cb\n * @param {*} [context=this]\n * @return {Array}\n */\nlistProto.mapArray = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    if (typeof dimensions === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dimensions;\n        dimensions = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    var result = [];\n    this.each(dimensions, function () {\n        result.push(cb && cb.apply(this, arguments));\n    }, context);\n    return result;\n};\n\n// Data in excludeDimensions is copied, otherwise transfered.\nfunction cloneListForMapAndSample(original, excludeDimensions) {\n    var allDimensions = original.dimensions;\n    var list = new List(\n        map(allDimensions, original.getDimensionInfo, original),\n        original.hostModel\n    );\n    // FIXME If needs stackedOn, value may already been stacked\n    transferProperties(list, original);\n\n    var storage = list._storage = {};\n    var originalStorage = original._storage;\n\n    // Init storage\n    for (var i = 0; i < allDimensions.length; i++) {\n        var dim = allDimensions[i];\n        if (originalStorage[dim]) {\n            // Notice that we do not reset invertedIndicesMap here, becuase\n            // there is no scenario of mapping or sampling ordinal dimension.\n            if (indexOf(excludeDimensions, dim) >= 0) {\n                storage[dim] = cloneDimStore(originalStorage[dim]);\n                list._rawExtent[dim] = getInitialExtent();\n                list._extent[dim] = null;\n            }\n            else {\n                // Direct reference for other dimensions\n                storage[dim] = originalStorage[dim];\n            }\n        }\n    }\n    return list;\n}\n\nfunction cloneDimStore(originalDimStore) {\n    var newDimStore = new Array(originalDimStore.length);\n    for (var j = 0; j < originalDimStore.length; j++) {\n        newDimStore[j] = cloneChunk(originalDimStore[j]);\n    }\n    return newDimStore;\n}\n\nfunction getInitialExtent() {\n    return [Infinity, -Infinity];\n}\n\n/**\n * Data mapping to a new List with given dimensions\n * @param {string|Array.<string>} dimensions\n * @param {Function} cb\n * @param {*} [context=this]\n * @return {Array}\n */\nlistProto.map = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dimensions = map(\n        normalizeDimensions(dimensions), this.getDimension, this\n    );\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n    var list = cloneListForMapAndSample(this, dimensions);\n\n    // Following properties are all immutable.\n    // So we can reference to the same value\n    list._indices = this._indices;\n    list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    var storage = list._storage;\n\n    var tmpRetValue = [];\n    var chunkSize = this._chunkSize;\n    var dimSize = dimensions.length;\n    var dataCount = this.count();\n    var values = [];\n    var rawExtent = list._rawExtent;\n\n    for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) {\n        for (var dimIndex = 0; dimIndex < dimSize; dimIndex++) {\n            values[dimIndex] = this.get(dimensions[dimIndex], dataIndex /*, stack */);\n        }\n        values[dimSize] = dataIndex;\n\n        var retValue = cb && cb.apply(context, values);\n        if (retValue != null) {\n            // a number or string (in oridinal dimension)?\n            if (typeof retValue !== 'object') {\n                tmpRetValue[0] = retValue;\n                retValue = tmpRetValue;\n            }\n\n            var rawIndex = this.getRawIndex(dataIndex);\n            var chunkIndex = Math.floor(rawIndex / chunkSize);\n            var chunkOffset = rawIndex % chunkSize;\n\n            for (var i = 0; i < retValue.length; i++) {\n                var dim = dimensions[i];\n                var val = retValue[i];\n                var rawExtentOnDim = rawExtent[dim];\n\n                var dimStore = storage[dim];\n                if (dimStore) {\n                    dimStore[chunkIndex][chunkOffset] = val;\n                }\n\n                if (val < rawExtentOnDim[0]) {\n                    rawExtentOnDim[0] = val;\n                }\n                if (val > rawExtentOnDim[1]) {\n                    rawExtentOnDim[1] = val;\n                }\n            }\n        }\n    }\n\n    return list;\n};\n\n/**\n * Large data down sampling on given dimension\n * @param {string} dimension\n * @param {number} rate\n * @param {Function} sampleValue\n * @param {Function} sampleIndex Sample index for name and id\n */\nlistProto.downSample = function (dimension, rate, sampleValue, sampleIndex) {\n    var list = cloneListForMapAndSample(this, [dimension]);\n    var targetStorage = list._storage;\n\n    var frameValues = [];\n    var frameSize = Math.floor(1 / rate);\n\n    var dimStore = targetStorage[dimension];\n    var len = this.count();\n    var chunkSize = this._chunkSize;\n    var rawExtentOnDim = list._rawExtent[dimension];\n\n    var newIndices = new (getIndicesCtor(this))(len);\n\n    var offset = 0;\n    for (var i = 0; i < len; i += frameSize) {\n        // Last frame\n        if (frameSize > len - i) {\n            frameSize = len - i;\n            frameValues.length = frameSize;\n        }\n        for (var k = 0; k < frameSize; k++) {\n            var dataIdx = this.getRawIndex(i + k);\n            var originalChunkIndex = Math.floor(dataIdx / chunkSize);\n            var originalChunkOffset = dataIdx % chunkSize;\n            frameValues[k] = dimStore[originalChunkIndex][originalChunkOffset];\n        }\n        var value = sampleValue(frameValues);\n        var sampleFrameIdx = this.getRawIndex(\n            Math.min(i + sampleIndex(frameValues, value) || 0, len - 1)\n        );\n        var sampleChunkIndex = Math.floor(sampleFrameIdx / chunkSize);\n        var sampleChunkOffset = sampleFrameIdx % chunkSize;\n        // Only write value on the filtered data\n        dimStore[sampleChunkIndex][sampleChunkOffset] = value;\n\n        if (value < rawExtentOnDim[0]) {\n            rawExtentOnDim[0] = value;\n        }\n        if (value > rawExtentOnDim[1]) {\n            rawExtentOnDim[1] = value;\n        }\n\n        newIndices[offset++] = sampleFrameIdx;\n    }\n\n    list._count = offset;\n    list._indices = newIndices;\n\n    list.getRawIndex = getRawIndexWithIndices;\n\n    return list;\n};\n\n/**\n * Get model of one data item.\n *\n * @param {number} idx\n */\n// FIXME Model proxy ?\nlistProto.getItemModel = function (idx) {\n    var hostModel = this.hostModel;\n    return new Model(this.getRawDataItem(idx), hostModel, hostModel && hostModel.ecModel);\n};\n\n/**\n * Create a data differ\n * @param {module:echarts/data/List} otherList\n * @return {module:echarts/data/DataDiffer}\n */\nlistProto.diff = function (otherList) {\n    var thisList = this;\n\n    return new DataDiffer(\n        otherList ? otherList.getIndices() : [],\n        this.getIndices(),\n        function (idx) {\n            return getId(otherList, idx);\n        },\n        function (idx) {\n            return getId(thisList, idx);\n        }\n    );\n};\n/**\n * Get visual property.\n * @param {string} key\n */\nlistProto.getVisual = function (key) {\n    var visual = this._visual;\n    return visual && visual[key];\n};\n\n/**\n * Set visual property\n * @param {string|Object} key\n * @param {*} [value]\n *\n * @example\n *  setVisual('color', color);\n *  setVisual({\n *      'color': color\n *  });\n */\nlistProto.setVisual = function (key, val) {\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                this.setVisual(name, key[name]);\n            }\n        }\n        return;\n    }\n    this._visual = this._visual || {};\n    this._visual[key] = val;\n};\n\n/**\n * Set layout property.\n * @param {string|Object} key\n * @param {*} [val]\n */\nlistProto.setLayout = function (key, val) {\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                this.setLayout(name, key[name]);\n            }\n        }\n        return;\n    }\n    this._layout[key] = val;\n};\n\n/**\n * Get layout property.\n * @param  {string} key.\n * @return {*}\n */\nlistProto.getLayout = function (key) {\n    return this._layout[key];\n};\n\n/**\n * Get layout of single data item\n * @param {number} idx\n */\nlistProto.getItemLayout = function (idx) {\n    return this._itemLayouts[idx];\n};\n\n/**\n * Set layout of single data item\n * @param {number} idx\n * @param {Object} layout\n * @param {boolean=} [merge=false]\n */\nlistProto.setItemLayout = function (idx, layout, merge$$1) {\n    this._itemLayouts[idx] = merge$$1\n        ? extend(this._itemLayouts[idx] || {}, layout)\n        : layout;\n};\n\n/**\n * Clear all layout of single data item\n */\nlistProto.clearItemLayouts = function () {\n    this._itemLayouts.length = 0;\n};\n\n/**\n * Get visual property of single data item\n * @param {number} idx\n * @param {string} key\n * @param {boolean} [ignoreParent=false]\n */\nlistProto.getItemVisual = function (idx, key, ignoreParent) {\n    var itemVisual = this._itemVisuals[idx];\n    var val = itemVisual && itemVisual[key];\n    if (val == null && !ignoreParent) {\n        // Use global visual property\n        return this.getVisual(key);\n    }\n    return val;\n};\n\n/**\n * Set visual property of single data item\n *\n * @param {number} idx\n * @param {string|Object} key\n * @param {*} [value]\n *\n * @example\n *  setItemVisual(0, 'color', color);\n *  setItemVisual(0, {\n *      'color': color\n *  });\n */\nlistProto.setItemVisual = function (idx, key, value) {\n    var itemVisual = this._itemVisuals[idx] || {};\n    var hasItemVisual = this.hasItemVisual;\n    this._itemVisuals[idx] = itemVisual;\n\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                itemVisual[name] = key[name];\n                hasItemVisual[name] = true;\n            }\n        }\n        return;\n    }\n    itemVisual[key] = value;\n    hasItemVisual[key] = true;\n};\n\n/**\n * Clear itemVisuals and list visual.\n */\nlistProto.clearAllVisual = function () {\n    this._visual = {};\n    this._itemVisuals = [];\n    this.hasItemVisual = {};\n};\n\nvar setItemDataAndSeriesIndex = function (child) {\n    child.seriesIndex = this.seriesIndex;\n    child.dataIndex = this.dataIndex;\n    child.dataType = this.dataType;\n};\n/**\n * Set graphic element relative to data. It can be set as null\n * @param {number} idx\n * @param {module:zrender/Element} [el]\n */\nlistProto.setItemGraphicEl = function (idx, el) {\n    var hostModel = this.hostModel;\n\n    if (el) {\n        // Add data index and series index for indexing the data by element\n        // Useful in tooltip\n        el.dataIndex = idx;\n        el.dataType = this.dataType;\n        el.seriesIndex = hostModel && hostModel.seriesIndex;\n        if (el.type === 'group') {\n            el.traverse(setItemDataAndSeriesIndex, el);\n        }\n    }\n\n    this._graphicEls[idx] = el;\n};\n\n/**\n * @param {number} idx\n * @return {module:zrender/Element}\n */\nlistProto.getItemGraphicEl = function (idx) {\n    return this._graphicEls[idx];\n};\n\n/**\n * @param {Function} cb\n * @param {*} context\n */\nlistProto.eachItemGraphicEl = function (cb, context) {\n    each$1(this._graphicEls, function (el, idx) {\n        if (el) {\n            cb && cb.call(context, el, idx);\n        }\n    });\n};\n\n/**\n * Shallow clone a new list except visual and layout properties, and graph elements.\n * New list only change the indices.\n */\nlistProto.cloneShallow = function (list) {\n    if (!list) {\n        var dimensionInfoList = map(this.dimensions, this.getDimensionInfo, this);\n        list = new List(dimensionInfoList, this.hostModel);\n    }\n\n    // FIXME\n    list._storage = this._storage;\n\n    transferProperties(list, this);\n\n    // Clone will not change the data extent and indices\n    if (this._indices) {\n        var Ctor = this._indices.constructor;\n        list._indices = new Ctor(this._indices);\n    }\n    else {\n        list._indices = null;\n    }\n    list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return list;\n};\n\n/**\n * Wrap some method to add more feature\n * @param {string} methodName\n * @param {Function} injectFunction\n */\nlistProto.wrapMethod = function (methodName, injectFunction) {\n    var originalMethod = this[methodName];\n    if (typeof originalMethod !== 'function') {\n        return;\n    }\n    this.__wrappedMethods = this.__wrappedMethods || [];\n    this.__wrappedMethods.push(methodName);\n    this[methodName] = function () {\n        var res = originalMethod.apply(this, arguments);\n        return injectFunction.apply(this, [res].concat(slice(arguments)));\n    };\n};\n\n// Methods that create a new list based on this list should be listed here.\n// Notice that those method should `RETURN` the new list.\nlistProto.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'map'];\n// Methods that change indices of this list should be listed here.\nlistProto.CHANGABLE_METHODS = ['filterSelf', 'selectRange'];\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @deprecated\n * Use `echarts/data/helper/createDimensions` instead.\n */\n\n/**\n * @see {module:echarts/test/ut/spec/data/completeDimensions}\n *\n * Complete the dimensions array, by user defined `dimension` and `encode`,\n * and guessing from the data structure.\n * If no 'value' dimension specified, the first no-named dimension will be\n * named as 'value'.\n *\n * @param {Array.<string>} sysDims Necessary dimensions, like ['x', 'y'], which\n *      provides not only dim template, but also default order.\n *      properties: 'name', 'type', 'displayName'.\n *      `name` of each item provides default coord name.\n *      [{dimsDef: [string|Object, ...]}, ...] dimsDef of sysDim item provides default dim name, and\n *                                    provide dims count that the sysDim required.\n *      [{ordinalMeta}] can be specified.\n * @param {module:echarts/data/Source|Array|Object} source or data (for compatibal with pervious)\n * @param {Object} [opt]\n * @param {Array.<Object|string>} [opt.dimsDef] option.series.dimensions User defined dimensions\n *      For example: ['asdf', {name, type}, ...].\n * @param {Object|HashMap} [opt.encodeDef] option.series.encode {x: 2, y: [3, 1], tooltip: [1, 2], label: 3}\n * @param {string} [opt.generateCoord] Generate coord dim with the given name.\n *                 If not specified, extra dim names will be:\n *                 'value', 'value0', 'value1', ...\n * @param {number} [opt.generateCoordCount] By default, the generated dim name is `generateCoord`.\n *                 If `generateCoordCount` specified, the generated dim names will be:\n *                 `generateCoord` + 0, `generateCoord` + 1, ...\n *                 can be Infinity, indicate that use all of the remain columns.\n * @param {number} [opt.dimCount] If not specified, guess by the first data item.\n * @param {number} [opt.encodeDefaulter] If not specified, auto find the next available data dim.\n * @return {Array.<Object>} [{\n *      name: string mandatory,\n *      displayName: string, the origin name in dimsDef, see source helper.\n *                 If displayName given, the tooltip will displayed vertically.\n *      coordDim: string mandatory,\n *      coordDimIndex: number mandatory,\n *      type: string optional,\n *      otherDims: { never null/undefined\n *          tooltip: number optional,\n *          label: number optional,\n *          itemName: number optional,\n *          seriesName: number optional,\n *      },\n *      isExtraCoord: boolean true if coord is generated\n *          (not specified in encode and not series specified)\n *      other props ...\n * }]\n */\nfunction completeDimensions(sysDims, source, opt) {\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n\n    opt = opt || {};\n    sysDims = (sysDims || []).slice();\n    var dimsDef = (opt.dimsDef || []).slice();\n    var encodeDef = createHashMap(opt.encodeDef);\n    var dataDimNameMap = createHashMap();\n    var coordDimNameMap = createHashMap();\n    // var valueCandidate;\n    var result = [];\n\n    var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimCount);\n\n    // Apply user defined dims (`name` and `type`) and init result.\n    for (var i = 0; i < dimCount; i++) {\n        var dimDefItem = dimsDef[i] = extend(\n            {}, isObject$1(dimsDef[i]) ? dimsDef[i] : {name: dimsDef[i]}\n        );\n        var userDimName = dimDefItem.name;\n        var resultItem = result[i] = {otherDims: {}};\n        // Name will be applied later for avoiding duplication.\n        if (userDimName != null && dataDimNameMap.get(userDimName) == null) {\n            // Only if `series.dimensions` is defined in option\n            // displayName, will be set, and dimension will be diplayed vertically in\n            // tooltip by default.\n            resultItem.name = resultItem.displayName = userDimName;\n            dataDimNameMap.set(userDimName, i);\n        }\n        dimDefItem.type != null && (resultItem.type = dimDefItem.type);\n        dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);\n    }\n\n    // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.\n    encodeDef.each(function (dataDims, coordDim) {\n        dataDims = normalizeToArray(dataDims).slice();\n\n        // Note: It is allowed that `dataDims.length` is `0`, e.g., options is\n        // `{encode: {x: -1, y: 1}}`. Should not filter anything in\n        // this case.\n        if (dataDims.length === 1 && dataDims[0] < 0) {\n            encodeDef.set(coordDim, false);\n            return;\n        }\n\n        var validDataDims = encodeDef.set(coordDim, []);\n        each$1(dataDims, function (resultDimIdx, idx) {\n            // The input resultDimIdx can be dim name or index.\n            isString(resultDimIdx) && (resultDimIdx = dataDimNameMap.get(resultDimIdx));\n            if (resultDimIdx != null && resultDimIdx < dimCount) {\n                validDataDims[idx] = resultDimIdx;\n                applyDim(result[resultDimIdx], coordDim, idx);\n            }\n        });\n    });\n\n    // Apply templetes and default order from `sysDims`.\n    var availDimIdx = 0;\n    each$1(sysDims, function (sysDimItem, sysDimIndex) {\n        var coordDim;\n        var sysDimItem;\n        var sysDimItemDimsDef;\n        var sysDimItemOtherDims;\n        if (isString(sysDimItem)) {\n            coordDim = sysDimItem;\n            sysDimItem = {};\n        }\n        else {\n            coordDim = sysDimItem.name;\n            var ordinalMeta = sysDimItem.ordinalMeta;\n            sysDimItem.ordinalMeta = null;\n            sysDimItem = clone(sysDimItem);\n            sysDimItem.ordinalMeta = ordinalMeta;\n            // `coordDimIndex` should not be set directly.\n            sysDimItemDimsDef = sysDimItem.dimsDef;\n            sysDimItemOtherDims = sysDimItem.otherDims;\n            sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex\n                = sysDimItem.dimsDef = sysDimItem.otherDims = null;\n        }\n\n        var dataDims = encodeDef.get(coordDim);\n\n        // negative resultDimIdx means no need to mapping.\n        if (dataDims === false) {\n            return;\n        }\n\n        var dataDims = normalizeToArray(dataDims);\n\n        // dimensions provides default dim sequences.\n        if (!dataDims.length) {\n            for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {\n                while (availDimIdx < result.length && result[availDimIdx].coordDim != null) {\n                    availDimIdx++;\n                }\n                availDimIdx < result.length && dataDims.push(availDimIdx++);\n            }\n        }\n\n        // Apply templates.\n        each$1(dataDims, function (resultDimIdx, coordDimIndex) {\n            var resultItem = result[resultDimIdx];\n            applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);\n            if (resultItem.name == null && sysDimItemDimsDef) {\n                var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];\n                !isObject$1(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {name: sysDimItemDimsDefItem});\n                resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;\n                resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;\n            }\n            // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}\n            sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);\n        });\n    });\n\n    function applyDim(resultItem, coordDim, coordDimIndex) {\n        if (OTHER_DIMENSIONS.get(coordDim) != null) {\n            resultItem.otherDims[coordDim] = coordDimIndex;\n        }\n        else {\n            resultItem.coordDim = coordDim;\n            resultItem.coordDimIndex = coordDimIndex;\n            coordDimNameMap.set(coordDim, true);\n        }\n    }\n\n    // Make sure the first extra dim is 'value'.\n    var generateCoord = opt.generateCoord;\n    var generateCoordCount = opt.generateCoordCount;\n    var fromZero = generateCoordCount != null;\n    generateCoordCount = generateCoord ? (generateCoordCount || 1) : 0;\n    var extra = generateCoord || 'value';\n\n    // Set dim `name` and other `coordDim` and other props.\n    for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {\n        var resultItem = result[resultDimIdx] = result[resultDimIdx] || {};\n        var coordDim = resultItem.coordDim;\n\n        if (coordDim == null) {\n            resultItem.coordDim = genName(\n                extra, coordDimNameMap, fromZero\n            );\n            resultItem.coordDimIndex = 0;\n            if (!generateCoord || generateCoordCount <= 0) {\n                resultItem.isExtraCoord = true;\n            }\n            generateCoordCount--;\n        }\n\n        resultItem.name == null && (resultItem.name = genName(\n            resultItem.coordDim,\n            dataDimNameMap\n        ));\n\n        if (resultItem.type == null && guessOrdinal(source, resultDimIdx, resultItem.name)) {\n            resultItem.type = 'ordinal';\n        }\n    }\n\n    return result;\n}\n\n// ??? TODO\n// Originally detect dimCount by data[0]. Should we\n// optimize it to only by sysDims and dimensions and encode.\n// So only necessary dims will be initialized.\n// But\n// (1) custom series should be considered. where other dims\n// may be visited.\n// (2) sometimes user need to calcualte bubble size or use visualMap\n// on other dimensions besides coordSys needed.\n// So, dims that is not used by system, should be shared in storage?\nfunction getDimCount(source, sysDims, dimsDef, optDimCount) {\n    // Note that the result dimCount should not small than columns count\n    // of data, otherwise `dataDimNameMap` checking will be incorrect.\n    var dimCount = Math.max(\n        source.dimensionsDetectCount || 1,\n        sysDims.length,\n        dimsDef.length,\n        optDimCount || 0\n    );\n    each$1(sysDims, function (sysDimItem) {\n        var sysDimItemDimsDef = sysDimItem.dimsDef;\n        sysDimItemDimsDef && (dimCount = Math.max(dimCount, sysDimItemDimsDef.length));\n    });\n    return dimCount;\n}\n\nfunction genName(name, map$$1, fromZero) {\n    if (fromZero || map$$1.get(name) != null) {\n        var i = 0;\n        while (map$$1.get(name + i) != null) {\n            i++;\n        }\n        name += i;\n    }\n    map$$1.set(name, true);\n    return name;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Substitute `completeDimensions`.\n * `completeDimensions` is to be deprecated.\n */\n/**\n * @param {module:echarts/data/Source|module:echarts/data/List} source or data.\n * @param {Object|Array} [opt]\n * @param {Array.<string|Object>} [opt.coordDimensions=[]]\n * @param {number} [opt.dimensionsCount]\n * @param {string} [opt.generateCoord]\n * @param {string} [opt.generateCoordCount]\n * @param {Array.<string|Object>} [opt.dimensionsDefine=source.dimensionsDefine] Overwrite source define.\n * @param {Object|HashMap} [opt.encodeDefine=source.encodeDefine] Overwrite source define.\n * @return {Array.<Object>} dimensionsInfo\n */\nvar createDimensions = function (source, opt) {\n    opt = opt || {};\n    return completeDimensions(opt.coordDimensions || [], source, {\n        dimsDef: opt.dimensionsDefine || source.dimensionsDefine,\n        encodeDef: opt.encodeDefine || source.encodeDefine,\n        dimCount: opt.dimensionsCount,\n        generateCoord: opt.generateCoord,\n        generateCoordCount: opt.generateCoordCount\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Note that it is too complicated to support 3d stack by value\n * (have to create two-dimension inverted index), so in 3d case\n * we just support that stacked by index.\n *\n * @param {module:echarts/model/Series} seriesModel\n * @param {Array.<string|Object>} dimensionInfoList The same as the input of <module:echarts/data/List>.\n *        The input dimensionInfoList will be modified.\n * @param {Object} [opt]\n * @param {boolean} [opt.stackedCoordDimension=''] Specify a coord dimension if needed.\n * @param {boolean} [opt.byIndex=false]\n * @return {Object} calculationInfo\n * {\n *     stackedDimension: string\n *     stackedByDimension: string\n *     isStackedByIndex: boolean\n *     stackedOverDimension: string\n *     stackResultDimension: string\n * }\n */\nfunction enableDataStack(seriesModel, dimensionInfoList, opt) {\n    opt = opt || {};\n    var byIndex = opt.byIndex;\n    var stackedCoordDimension = opt.stackedCoordDimension;\n\n    // Compatibal: when `stack` is set as '', do not stack.\n    var mayStack = !!(seriesModel && seriesModel.get('stack'));\n    var stackedByDimInfo;\n    var stackedDimInfo;\n    var stackResultDimension;\n    var stackedOverDimension;\n\n    each$1(dimensionInfoList, function (dimensionInfo, index) {\n        if (isString(dimensionInfo)) {\n            dimensionInfoList[index] = dimensionInfo = {name: dimensionInfo};\n        }\n\n        if (mayStack && !dimensionInfo.isExtraCoord) {\n            // Find the first ordinal dimension as the stackedByDimInfo.\n            if (!byIndex && !stackedByDimInfo && dimensionInfo.ordinalMeta) {\n                stackedByDimInfo = dimensionInfo;\n            }\n            // Find the first stackable dimension as the stackedDimInfo.\n            if (!stackedDimInfo\n                && dimensionInfo.type !== 'ordinal'\n                && dimensionInfo.type !== 'time'\n                && (!stackedCoordDimension || stackedCoordDimension === dimensionInfo.coordDim)\n            ) {\n                stackedDimInfo = dimensionInfo;\n            }\n        }\n    });\n\n    if (stackedDimInfo && !byIndex && !stackedByDimInfo) {\n        // Compatible with previous design, value axis (time axis) only stack by index.\n        // It may make sense if the user provides elaborately constructed data.\n        byIndex = true;\n    }\n\n    // Add stack dimension, they can be both calculated by coordinate system in `unionExtent`.\n    // That put stack logic in List is for using conveniently in echarts extensions, but it\n    // might not be a good way.\n    if (stackedDimInfo) {\n        // Use a weird name that not duplicated with other names.\n        stackResultDimension = '__\\0ecstackresult';\n        stackedOverDimension = '__\\0ecstackedover';\n\n        // Create inverted index to fast query index by value.\n        if (stackedByDimInfo) {\n            stackedByDimInfo.createInvertedIndices = true;\n        }\n\n        var stackedDimCoordDim = stackedDimInfo.coordDim;\n        var stackedDimType = stackedDimInfo.type;\n        var stackedDimCoordIndex = 0;\n\n        each$1(dimensionInfoList, function (dimensionInfo) {\n            if (dimensionInfo.coordDim === stackedDimCoordDim) {\n                stackedDimCoordIndex++;\n            }\n        });\n\n        dimensionInfoList.push({\n            name: stackResultDimension,\n            coordDim: stackedDimCoordDim,\n            coordDimIndex: stackedDimCoordIndex,\n            type: stackedDimType,\n            isExtraCoord: true,\n            isCalculationCoord: true\n        });\n\n        stackedDimCoordIndex++;\n\n        dimensionInfoList.push({\n            name: stackedOverDimension,\n            // This dimension contains stack base (generally, 0), so do not set it as\n            // `stackedDimCoordDim` to avoid extent calculation, consider log scale.\n            coordDim: stackedOverDimension,\n            coordDimIndex: stackedDimCoordIndex,\n            type: stackedDimType,\n            isExtraCoord: true,\n            isCalculationCoord: true\n        });\n    }\n\n    return {\n        stackedDimension: stackedDimInfo && stackedDimInfo.name,\n        stackedByDimension: stackedByDimInfo && stackedByDimInfo.name,\n        isStackedByIndex: byIndex,\n        stackedOverDimension: stackedOverDimension,\n        stackResultDimension: stackResultDimension\n    };\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {string} stackedDim\n */\nfunction isDimensionStacked(data, stackedDim /*, stackedByDim*/) {\n    // Each single series only maps to one pair of axis. So we do not need to\n    // check stackByDim, whatever stacked by a dimension or stacked by index.\n    return !!stackedDim && stackedDim === data.getCalculationInfo('stackedDimension');\n        // && (\n        //     stackedByDim != null\n        //         ? stackedByDim === data.getCalculationInfo('stackedByDimension')\n        //         : data.getCalculationInfo('isStackedByIndex')\n        // );\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {string} targetDim\n * @param {string} [stackedByDim] If not input this parameter, check whether\n *                                stacked by index.\n * @return {string} dimension\n */\nfunction getStackedDimension(data, targetDim) {\n    return isDimensionStacked(data, targetDim)\n        ? data.getCalculationInfo('stackResultDimension')\n        : targetDim;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/data/Source|Array} source Or raw data.\n * @param {module:echarts/model/Series} seriesModel\n * @param {Object} [opt]\n * @param {string} [opt.generateCoord]\n */\nfunction createListFromArray(source, seriesModel, opt) {\n    opt = opt || {};\n\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n\n    var coordSysName = seriesModel.get('coordinateSystem');\n    var registeredCoordSys = CoordinateSystemManager.get(coordSysName);\n\n    var coordSysDefine = getCoordSysDefineBySeries(seriesModel);\n\n    var coordSysDimDefs;\n\n    if (coordSysDefine) {\n        coordSysDimDefs = map(coordSysDefine.coordSysDims, function (dim) {\n            var dimInfo = {name: dim};\n            var axisModel = coordSysDefine.axisMap.get(dim);\n            if (axisModel) {\n                var axisType = axisModel.get('type');\n                dimInfo.type = getDimensionTypeByAxis(axisType);\n                // dimInfo.stackable = isStackable(axisType);\n            }\n            return dimInfo;\n        });\n    }\n\n    if (!coordSysDimDefs) {\n        // Get dimensions from registered coordinate system\n        coordSysDimDefs = (registeredCoordSys && (\n            registeredCoordSys.getDimensionsInfo\n                ? registeredCoordSys.getDimensionsInfo()\n                : registeredCoordSys.dimensions.slice()\n        )) || ['x', 'y'];\n    }\n\n    var dimInfoList = createDimensions(source, {\n        coordDimensions: coordSysDimDefs,\n        generateCoord: opt.generateCoord\n    });\n\n    var firstCategoryDimIndex;\n    var hasNameEncode;\n    coordSysDefine && each$1(dimInfoList, function (dimInfo, dimIndex) {\n        var coordDim = dimInfo.coordDim;\n        var categoryAxisModel = coordSysDefine.categoryAxisMap.get(coordDim);\n        if (categoryAxisModel) {\n            if (firstCategoryDimIndex == null) {\n                firstCategoryDimIndex = dimIndex;\n            }\n            dimInfo.ordinalMeta = categoryAxisModel.getOrdinalMeta();\n        }\n        if (dimInfo.otherDims.itemName != null) {\n            hasNameEncode = true;\n        }\n    });\n    if (!hasNameEncode && firstCategoryDimIndex != null) {\n        dimInfoList[firstCategoryDimIndex].otherDims.itemName = 0;\n    }\n\n    var stackCalculationInfo = enableDataStack(seriesModel, dimInfoList);\n\n    var list = new List(dimInfoList, seriesModel);\n\n    list.setCalculationInfo(stackCalculationInfo);\n\n    var dimValueGetter = (firstCategoryDimIndex != null && isNeedCompleteOrdinalData(source))\n        ? function (itemOpt, dimName, dataIndex, dimIndex) {\n            // Use dataIndex as ordinal value in categoryAxis\n            return dimIndex === firstCategoryDimIndex\n                ? dataIndex\n                : this.defaultDimValueGetter(itemOpt, dimName, dataIndex, dimIndex);\n        }\n        : null;\n\n    list.hasItemOption = false;\n    list.initData(source, null, dimValueGetter);\n\n    return list;\n}\n\nfunction isNeedCompleteOrdinalData(source) {\n    if (source.sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        var sampleItem = firstDataNotNull(source.data || []);\n        return sampleItem != null\n            && !isArray(getDataItemValue(sampleItem));\n    }\n}\n\nfunction firstDataNotNull(data) {\n    var i = 0;\n    while (i < data.length && data[i] == null) {\n        i++;\n    }\n    return data[i];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * // Scale class management\n * @module echarts/scale/Scale\n */\n\n/**\n * @param {Object} [setting]\n */\nfunction Scale(setting) {\n    this._setting = setting || {};\n\n    /**\n     * Extent\n     * @type {Array.<number>}\n     * @protected\n     */\n    this._extent = [Infinity, -Infinity];\n\n    /**\n     * Step is calculated in adjustExtent\n     * @type {Array.<number>}\n     * @protected\n     */\n    this._interval = 0;\n\n    this.init && this.init.apply(this, arguments);\n}\n\n/**\n * Parse input val to valid inner number.\n * @param {*} val\n * @return {number}\n */\nScale.prototype.parse = function (val) {\n    // Notice: This would be a trap here, If the implementation\n    // of this method depends on extent, and this method is used\n    // before extent set (like in dataZoom), it would be wrong.\n    // Nevertheless, parse does not depend on extent generally.\n    return val;\n};\n\nScale.prototype.getSetting = function (name) {\n    return this._setting[name];\n};\n\nScale.prototype.contain = function (val) {\n    var extent = this._extent;\n    return val >= extent[0] && val <= extent[1];\n};\n\n/**\n * Normalize value to linear [0, 1], return 0.5 if extent span is 0\n * @param {number} val\n * @return {number}\n */\nScale.prototype.normalize = function (val) {\n    var extent = this._extent;\n    if (extent[1] === extent[0]) {\n        return 0.5;\n    }\n    return (val - extent[0]) / (extent[1] - extent[0]);\n};\n\n/**\n * Scale normalized value\n * @param {number} val\n * @return {number}\n */\nScale.prototype.scale = function (val) {\n    var extent = this._extent;\n    return val * (extent[1] - extent[0]) + extent[0];\n};\n\n/**\n * Set extent from data\n * @param {Array.<number>} other\n */\nScale.prototype.unionExtent = function (other) {\n    var extent = this._extent;\n    other[0] < extent[0] && (extent[0] = other[0]);\n    other[1] > extent[1] && (extent[1] = other[1]);\n    // not setExtent because in log axis it may transformed to power\n    // this.setExtent(extent[0], extent[1]);\n};\n\n/**\n * Set extent from data\n * @param {module:echarts/data/List} data\n * @param {string} dim\n */\nScale.prototype.unionExtentFromData = function (data, dim) {\n    this.unionExtent(data.getApproximateExtent(dim));\n};\n\n/**\n * Get extent\n * @return {Array.<number>}\n */\nScale.prototype.getExtent = function () {\n    return this._extent.slice();\n};\n\n/**\n * Set extent\n * @param {number} start\n * @param {number} end\n */\nScale.prototype.setExtent = function (start, end) {\n    var thisExtent = this._extent;\n    if (!isNaN(start)) {\n        thisExtent[0] = start;\n    }\n    if (!isNaN(end)) {\n        thisExtent[1] = end;\n    }\n};\n\n/**\n * When axis extent depends on data and no data exists,\n * axis ticks should not be drawn, which is named 'blank'.\n */\nScale.prototype.isBlank = function () {\n    return this._isBlank;\n},\n\n/**\n * When axis extent depends on data and no data exists,\n * axis ticks should not be drawn, which is named 'blank'.\n */\nScale.prototype.setBlank = function (isBlank) {\n    this._isBlank = isBlank;\n};\n\n/**\n * @abstract\n * @param {*} tick\n * @return {string} label of the tick.\n */\nScale.prototype.getLabel = null;\n\n\nenableClassExtend(Scale);\nenableClassManagement(Scale, {\n    registerWhenExtend: true\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @constructor\n * @param {Object} [opt]\n * @param {Object} [opt.categories=[]]\n * @param {Object} [opt.needCollect=false]\n * @param {Object} [opt.deduplication=false]\n */\nfunction OrdinalMeta(opt) {\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    this.categories = opt.categories || [];\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._needCollect = opt.needCollect;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._deduplication = opt.deduplication;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._map;\n}\n\n/**\n * @param {module:echarts/model/Model} axisModel\n * @return {module:echarts/data/OrdinalMeta}\n */\nOrdinalMeta.createByAxisModel = function (axisModel) {\n    var option = axisModel.option;\n    var data = option.data;\n    var categories = data && map(data, getName);\n\n    return new OrdinalMeta({\n        categories: categories,\n        needCollect: !categories,\n        // deduplication is default in axis.\n        deduplication: option.dedplication !== false\n    });\n};\n\nvar proto$1 = OrdinalMeta.prototype;\n\n/**\n * @param {string} category\n * @return {number} ordinal\n */\nproto$1.getOrdinal = function (category) {\n    return getOrCreateMap(this).get(category);\n};\n\n/**\n * @param {*} category\n * @return {number} The ordinal. If not found, return NaN.\n */\nproto$1.parseAndCollect = function (category) {\n    var index;\n    var needCollect = this._needCollect;\n\n    // The value of category dim can be the index of the given category set.\n    // This feature is only supported when !needCollect, because we should\n    // consider a common case: a value is 2017, which is a number but is\n    // expected to be tread as a category. This case usually happen in dataset,\n    // where it happent to be no need of the index feature.\n    if (typeof category !== 'string' && !needCollect) {\n        return category;\n    }\n\n    // Optimize for the scenario:\n    // category is ['2012-01-01', '2012-01-02', ...], where the input\n    // data has been ensured not duplicate and is large data.\n    // Notice, if a dataset dimension provide categroies, usually echarts\n    // should remove duplication except user tell echarts dont do that\n    // (set axis.deduplication = false), because echarts do not know whether\n    // the values in the category dimension has duplication (consider the\n    // parallel-aqi example)\n    if (needCollect && !this._deduplication) {\n        index = this.categories.length;\n        this.categories[index] = category;\n        return index;\n    }\n\n    var map$$1 = getOrCreateMap(this);\n    index = map$$1.get(category);\n\n    if (index == null) {\n        if (needCollect) {\n            index = this.categories.length;\n            this.categories[index] = category;\n            map$$1.set(category, index);\n        }\n        else {\n            index = NaN;\n        }\n    }\n\n    return index;\n};\n\n// Consider big data, do not create map until needed.\nfunction getOrCreateMap(ordinalMeta) {\n    return ordinalMeta._map || (\n        ordinalMeta._map = createHashMap(ordinalMeta.categories)\n    );\n}\n\nfunction getName(obj) {\n    if (isObject$1(obj) && obj.value != null) {\n        return obj.value;\n    }\n    else {\n        return obj + '';\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Linear continuous scale\n * @module echarts/coord/scale/Ordinal\n *\n * http://en.wikipedia.org/wiki/Level_of_measurement\n */\n\n// FIXME only one data\n\nvar scaleProto = Scale.prototype;\n\nvar OrdinalScale = Scale.extend({\n\n    type: 'ordinal',\n\n    /**\n     * @param {module:echarts/data/OrdianlMeta|Array.<string>} ordinalMeta\n     */\n    init: function (ordinalMeta, extent) {\n        // Caution: Should not use instanceof, consider ec-extensions using\n        // import approach to get OrdinalMeta class.\n        if (!ordinalMeta || isArray(ordinalMeta)) {\n            ordinalMeta = new OrdinalMeta({categories: ordinalMeta});\n        }\n        this._ordinalMeta = ordinalMeta;\n        this._extent = extent || [0, ordinalMeta.categories.length - 1];\n    },\n\n    parse: function (val) {\n        return typeof val === 'string'\n            ? this._ordinalMeta.getOrdinal(val)\n            // val might be float.\n            : Math.round(val);\n    },\n\n    contain: function (rank) {\n        rank = this.parse(rank);\n        return scaleProto.contain.call(this, rank)\n            && this._ordinalMeta.categories[rank] != null;\n    },\n\n    /**\n     * Normalize given rank or name to linear [0, 1]\n     * @param {number|string} [val]\n     * @return {number}\n     */\n    normalize: function (val) {\n        return scaleProto.normalize.call(this, this.parse(val));\n    },\n\n    scale: function (val) {\n        return Math.round(scaleProto.scale.call(this, val));\n    },\n\n    /**\n     * @return {Array}\n     */\n    getTicks: function () {\n        var ticks = [];\n        var extent = this._extent;\n        var rank = extent[0];\n\n        while (rank <= extent[1]) {\n            ticks.push(rank);\n            rank++;\n        }\n\n        return ticks;\n    },\n\n    /**\n     * Get item on rank n\n     * @param {number} n\n     * @return {string}\n     */\n    getLabel: function (n) {\n        if (!this.isBlank()) {\n            // Note that if no data, ordinalMeta.categories is an empty array.\n            return this._ordinalMeta.categories[n];\n        }\n    },\n\n    /**\n     * @return {number}\n     */\n    count: function () {\n        return this._extent[1] - this._extent[0] + 1;\n    },\n\n    /**\n     * @override\n     */\n    unionExtentFromData: function (data, dim) {\n        this.unionExtent(data.getApproximateExtent(dim));\n    },\n\n    getOrdinalMeta: function () {\n        return this._ordinalMeta;\n    },\n\n    niceTicks: noop,\n    niceExtent: noop\n});\n\n/**\n * @return {module:echarts/scale/Time}\n */\nOrdinalScale.create = function () {\n    return new OrdinalScale();\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * For testable.\n */\n\nvar roundNumber$1 = round$2;\n\n/**\n * @param {Array.<number>} extent Both extent[0] and extent[1] should be valid number.\n *                                Should be extent[0] < extent[1].\n * @param {number} splitNumber splitNumber should be >= 1.\n * @param {number} [minInterval]\n * @param {number} [maxInterval]\n * @return {Object} {interval, intervalPrecision, niceTickExtent}\n */\nfunction intervalScaleNiceTicks(extent, splitNumber, minInterval, maxInterval) {\n    var result = {};\n    var span = extent[1] - extent[0];\n\n    var interval = result.interval = nice(span / splitNumber, true);\n    if (minInterval != null && interval < minInterval) {\n        interval = result.interval = minInterval;\n    }\n    if (maxInterval != null && interval > maxInterval) {\n        interval = result.interval = maxInterval;\n    }\n    // Tow more digital for tick.\n    var precision = result.intervalPrecision = getIntervalPrecision(interval);\n    // Niced extent inside original extent\n    var niceTickExtent = result.niceTickExtent = [\n        roundNumber$1(Math.ceil(extent[0] / interval) * interval, precision),\n        roundNumber$1(Math.floor(extent[1] / interval) * interval, precision)\n    ];\n\n    fixExtent(niceTickExtent, extent);\n\n    return result;\n}\n\n/**\n * @param {number} interval\n * @return {number} interval precision\n */\nfunction getIntervalPrecision(interval) {\n    // Tow more digital for tick.\n    return getPrecisionSafe(interval) + 2;\n}\n\nfunction clamp(niceTickExtent, idx, extent) {\n    niceTickExtent[idx] = Math.max(Math.min(niceTickExtent[idx], extent[1]), extent[0]);\n}\n\n// In some cases (e.g., splitNumber is 1), niceTickExtent may be out of extent.\nfunction fixExtent(niceTickExtent, extent) {\n    !isFinite(niceTickExtent[0]) && (niceTickExtent[0] = extent[0]);\n    !isFinite(niceTickExtent[1]) && (niceTickExtent[1] = extent[1]);\n    clamp(niceTickExtent, 0, extent);\n    clamp(niceTickExtent, 1, extent);\n    if (niceTickExtent[0] > niceTickExtent[1]) {\n        niceTickExtent[0] = niceTickExtent[1];\n    }\n}\n\nfunction intervalScaleGetTicks(interval, extent, niceTickExtent, intervalPrecision) {\n    var ticks = [];\n\n    // If interval is 0, return [];\n    if (!interval) {\n        return ticks;\n    }\n\n    // Consider this case: using dataZoom toolbox, zoom and zoom.\n    var safeLimit = 10000;\n\n    if (extent[0] < niceTickExtent[0]) {\n        ticks.push(extent[0]);\n    }\n    var tick = niceTickExtent[0];\n\n    while (tick <= niceTickExtent[1]) {\n        ticks.push(tick);\n        // Avoid rounding error\n        tick = roundNumber$1(tick + interval, intervalPrecision);\n        if (tick === ticks[ticks.length - 1]) {\n            // Consider out of safe float point, e.g.,\n            // -3711126.9907707 + 2e-10 === -3711126.9907707\n            break;\n        }\n        if (ticks.length > safeLimit) {\n            return [];\n        }\n    }\n    // Consider this case: the last item of ticks is smaller\n    // than niceTickExtent[1] and niceTickExtent[1] === extent[1].\n    if (extent[1] > (ticks.length ? ticks[ticks.length - 1] : niceTickExtent[1])) {\n        ticks.push(extent[1]);\n    }\n\n    return ticks;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Interval scale\n * @module echarts/scale/Interval\n */\n\n\nvar roundNumber = round$2;\n\n/**\n * @alias module:echarts/coord/scale/Interval\n * @constructor\n */\nvar IntervalScale = Scale.extend({\n\n    type: 'interval',\n\n    _interval: 0,\n\n    _intervalPrecision: 2,\n\n    setExtent: function (start, end) {\n        var thisExtent = this._extent;\n        //start,end may be a Number like '25',so...\n        if (!isNaN(start)) {\n            thisExtent[0] = parseFloat(start);\n        }\n        if (!isNaN(end)) {\n            thisExtent[1] = parseFloat(end);\n        }\n    },\n\n    unionExtent: function (other) {\n        var extent = this._extent;\n        other[0] < extent[0] && (extent[0] = other[0]);\n        other[1] > extent[1] && (extent[1] = other[1]);\n\n        // unionExtent may called by it's sub classes\n        IntervalScale.prototype.setExtent.call(this, extent[0], extent[1]);\n    },\n    /**\n     * Get interval\n     */\n    getInterval: function () {\n        return this._interval;\n    },\n\n    /**\n     * Set interval\n     */\n    setInterval: function (interval) {\n        this._interval = interval;\n        // Dropped auto calculated niceExtent and use user setted extent\n        // We assume user wan't to set both interval, min, max to get a better result\n        this._niceExtent = this._extent.slice();\n\n        this._intervalPrecision = getIntervalPrecision(interval);\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getTicks: function () {\n        return intervalScaleGetTicks(\n            this._interval, this._extent, this._niceExtent, this._intervalPrecision\n        );\n    },\n\n    /**\n     * @param {number} data\n     * @param {Object} [opt]\n     * @param {number|string} [opt.precision] If 'auto', use nice presision.\n     * @param {boolean} [opt.pad] returns 1.50 but not 1.5 if precision is 2.\n     * @return {string}\n     */\n    getLabel: function (data, opt) {\n        if (data == null) {\n            return '';\n        }\n\n        var precision = opt && opt.precision;\n\n        if (precision == null) {\n            precision = getPrecisionSafe(data) || 0;\n        }\n        else if (precision === 'auto') {\n            // Should be more precise then tick.\n            precision = this._intervalPrecision;\n        }\n\n        // (1) If `precision` is set, 12.005 should be display as '12.00500'.\n        // (2) Use roundNumber (toFixed) to avoid scientific notation like '3.5e-7'.\n        data = roundNumber(data, precision, true);\n\n        return addCommas(data);\n    },\n\n    /**\n     * Update interval and extent of intervals for nice ticks\n     *\n     * @param {number} [splitNumber = 5] Desired number of ticks\n     * @param {number} [minInterval]\n     * @param {number} [maxInterval]\n     */\n    niceTicks: function (splitNumber, minInterval, maxInterval) {\n        splitNumber = splitNumber || 5;\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        if (!isFinite(span)) {\n            return;\n        }\n        // User may set axis min 0 and data are all negative\n        // FIXME If it needs to reverse ?\n        if (span < 0) {\n            span = -span;\n            extent.reverse();\n        }\n\n        var result = intervalScaleNiceTicks(\n            extent, splitNumber, minInterval, maxInterval\n        );\n\n        this._intervalPrecision = result.intervalPrecision;\n        this._interval = result.interval;\n        this._niceExtent = result.niceTickExtent;\n    },\n\n    /**\n     * Nice extent.\n     * @param {Object} opt\n     * @param {number} [opt.splitNumber = 5] Given approx tick number\n     * @param {boolean} [opt.fixMin=false]\n     * @param {boolean} [opt.fixMax=false]\n     * @param {boolean} [opt.minInterval]\n     * @param {boolean} [opt.maxInterval]\n     */\n    niceExtent: function (opt) {\n        var extent = this._extent;\n        // If extent start and end are same, expand them\n        if (extent[0] === extent[1]) {\n            if (extent[0] !== 0) {\n                // Expand extent\n                var expandSize = extent[0];\n                // In the fowllowing case\n                //      Axis has been fixed max 100\n                //      Plus data are all 100 and axis extent are [100, 100].\n                // Extend to the both side will cause expanded max is larger than fixed max.\n                // So only expand to the smaller side.\n                if (!opt.fixMax) {\n                    extent[1] += expandSize / 2;\n                    extent[0] -= expandSize / 2;\n                }\n                else {\n                    extent[0] -= expandSize / 2;\n                }\n            }\n            else {\n                extent[1] = 1;\n            }\n        }\n        var span = extent[1] - extent[0];\n        // If there are no data and extent are [Infinity, -Infinity]\n        if (!isFinite(span)) {\n            extent[0] = 0;\n            extent[1] = 1;\n        }\n\n        this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);\n\n        // var extent = this._extent;\n        var interval = this._interval;\n\n        if (!opt.fixMin) {\n            extent[0] = roundNumber(Math.floor(extent[0] / interval) * interval);\n        }\n        if (!opt.fixMax) {\n            extent[1] = roundNumber(Math.ceil(extent[1] / interval) * interval);\n        }\n    }\n});\n\n/**\n * @return {module:echarts/scale/Time}\n */\nIntervalScale.create = function () {\n    return new IntervalScale();\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar STACK_PREFIX = '__ec_stack_';\nvar LARGE_BAR_MIN_WIDTH = 0.5;\n\nvar LargeArr = typeof Float32Array !== 'undefined' ? Float32Array : Array;\n\nfunction getSeriesStackId(seriesModel) {\n    return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex;\n}\n\nfunction getAxisKey(axis) {\n    return axis.dim + axis.index;\n}\n\n/**\n * @param {Object} opt\n * @param {module:echarts/coord/Axis} opt.axis Only support category axis currently.\n * @param {number} opt.count Positive interger.\n * @param {number} [opt.barWidth]\n * @param {number} [opt.barMaxWidth]\n * @param {number} [opt.barGap]\n * @param {number} [opt.barCategoryGap]\n * @return {Object} {width, offset, offsetCenter} If axis.type is not 'category', return undefined.\n */\nfunction getLayoutOnAxis(opt) {\n    var params = [];\n    var baseAxis = opt.axis;\n    var axisKey = 'axis0';\n\n    if (baseAxis.type !== 'category') {\n        return;\n    }\n    var bandWidth = baseAxis.getBandWidth();\n\n    for (var i = 0; i < opt.count || 0; i++) {\n        params.push(defaults({\n            bandWidth: bandWidth,\n            axisKey: axisKey,\n            stackId: STACK_PREFIX + i\n        }, opt));\n    }\n    var widthAndOffsets = doCalBarWidthAndOffset(params);\n\n    var result = [];\n    for (var i = 0; i < opt.count; i++) {\n        var item = widthAndOffsets[axisKey][STACK_PREFIX + i];\n        item.offsetCenter = item.offset + item.width / 2;\n        result.push(item);\n    }\n\n    return result;\n}\n\nfunction prepareLayoutBarSeries(seriesType, ecModel) {\n    var seriesModels = [];\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        // Check series coordinate, do layout for cartesian2d only\n        if (isOnCartesian(seriesModel) && !isInLargeMode(seriesModel)) {\n            seriesModels.push(seriesModel);\n        }\n    });\n    return seriesModels;\n}\n\nfunction makeColumnLayout(barSeries) {\n    var seriesInfoList = [];\n    each$1(barSeries, function (seriesModel) {\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var axisExtent = baseAxis.getExtent();\n        var bandWidth = baseAxis.type === 'category'\n            ? baseAxis.getBandWidth()\n            : (Math.abs(axisExtent[1] - axisExtent[0]) / data.count());\n\n        var barWidth = parsePercent$1(\n            seriesModel.get('barWidth'), bandWidth\n        );\n        var barMaxWidth = parsePercent$1(\n            seriesModel.get('barMaxWidth'), bandWidth\n        );\n        var barGap = seriesModel.get('barGap');\n        var barCategoryGap = seriesModel.get('barCategoryGap');\n\n        seriesInfoList.push({\n            bandWidth: bandWidth,\n            barWidth: barWidth,\n            barMaxWidth: barMaxWidth,\n            barGap: barGap,\n            barCategoryGap: barCategoryGap,\n            axisKey: getAxisKey(baseAxis),\n            stackId: getSeriesStackId(seriesModel)\n        });\n    });\n\n    return doCalBarWidthAndOffset(seriesInfoList);\n}\n\nfunction doCalBarWidthAndOffset(seriesInfoList) {\n    // Columns info on each category axis. Key is cartesian name\n    var columnsMap = {};\n\n    each$1(seriesInfoList, function (seriesInfo, idx) {\n        var axisKey = seriesInfo.axisKey;\n        var bandWidth = seriesInfo.bandWidth;\n        var columnsOnAxis = columnsMap[axisKey] || {\n            bandWidth: bandWidth,\n            remainedWidth: bandWidth,\n            autoWidthCount: 0,\n            categoryGap: '20%',\n            gap: '30%',\n            stacks: {}\n        };\n        var stacks = columnsOnAxis.stacks;\n        columnsMap[axisKey] = columnsOnAxis;\n\n        var stackId = seriesInfo.stackId;\n\n        if (!stacks[stackId]) {\n            columnsOnAxis.autoWidthCount++;\n        }\n        stacks[stackId] = stacks[stackId] || {\n            width: 0,\n            maxWidth: 0\n        };\n\n        // Caution: In a single coordinate system, these barGrid attributes\n        // will be shared by series. Consider that they have default values,\n        // only the attributes set on the last series will work.\n        // Do not change this fact unless there will be a break change.\n\n        // TODO\n        var barWidth = seriesInfo.barWidth;\n        if (barWidth && !stacks[stackId].width) {\n            // See #6312, do not restrict width.\n            stacks[stackId].width = barWidth;\n            barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);\n            columnsOnAxis.remainedWidth -= barWidth;\n        }\n\n        var barMaxWidth = seriesInfo.barMaxWidth;\n        barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);\n        var barGap = seriesInfo.barGap;\n        (barGap != null) && (columnsOnAxis.gap = barGap);\n        var barCategoryGap = seriesInfo.barCategoryGap;\n        (barCategoryGap != null) && (columnsOnAxis.categoryGap = barCategoryGap);\n    });\n\n    var result = {};\n\n    each$1(columnsMap, function (columnsOnAxis, coordSysName) {\n\n        result[coordSysName] = {};\n\n        var stacks = columnsOnAxis.stacks;\n        var bandWidth = columnsOnAxis.bandWidth;\n        var categoryGap = parsePercent$1(columnsOnAxis.categoryGap, bandWidth);\n        var barGapPercent = parsePercent$1(columnsOnAxis.gap, 1);\n\n        var remainedWidth = columnsOnAxis.remainedWidth;\n        var autoWidthCount = columnsOnAxis.autoWidthCount;\n        var autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        // Find if any auto calculated bar exceeded maxBarWidth\n        each$1(stacks, function (column, stack) {\n            var maxWidth = column.maxWidth;\n            if (maxWidth && maxWidth < autoWidth) {\n                maxWidth = Math.min(maxWidth, remainedWidth);\n                if (column.width) {\n                    maxWidth = Math.min(maxWidth, column.width);\n                }\n                remainedWidth -= maxWidth;\n                column.width = maxWidth;\n                autoWidthCount--;\n            }\n        });\n\n        // Recalculate width again\n        autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        var widthSum = 0;\n        var lastColumn;\n        each$1(stacks, function (column, idx) {\n            if (!column.width) {\n                column.width = autoWidth;\n            }\n            lastColumn = column;\n            widthSum += column.width * (1 + barGapPercent);\n        });\n        if (lastColumn) {\n            widthSum -= lastColumn.width * barGapPercent;\n        }\n\n        var offset = -widthSum / 2;\n        each$1(stacks, function (column, stackId) {\n            result[coordSysName][stackId] = result[coordSysName][stackId] || {\n                offset: offset,\n                width: column.width\n            };\n\n            offset += column.width * (1 + barGapPercent);\n        });\n    });\n\n    return result;\n}\n\n/**\n * @param {Object} barWidthAndOffset The result of makeColumnLayout\n * @param {module:echarts/coord/Axis} axis\n * @param {module:echarts/model/Series} [seriesModel] If not provided, return all.\n * @return {Object} {stackId: {offset, width}} or {offset, width} if seriesModel provided.\n */\nfunction retrieveColumnLayout(barWidthAndOffset, axis, seriesModel) {\n    if (barWidthAndOffset && axis) {\n        var result = barWidthAndOffset[getAxisKey(axis)];\n        if (result != null && seriesModel != null) {\n            result = result[getSeriesStackId(seriesModel)];\n        }\n        return result;\n    }\n}\n\n/**\n * @param {string} seriesType\n * @param {module:echarts/model/Global} ecModel\n */\nfunction layout(seriesType, ecModel) {\n\n    var seriesModels = prepareLayoutBarSeries(seriesType, ecModel);\n    var barWidthAndOffset = makeColumnLayout(seriesModels);\n\n    var lastStackCoords = {};\n    each$1(seriesModels, function (seriesModel) {\n\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n\n        var stackId = getSeriesStackId(seriesModel);\n        var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId];\n        var columnOffset = columnLayoutInfo.offset;\n        var columnWidth = columnLayoutInfo.width;\n        var valueAxis = cartesian.getOtherAxis(baseAxis);\n\n        var barMinHeight = seriesModel.get('barMinHeight') || 0;\n\n        lastStackCoords[stackId] = lastStackCoords[stackId] || [];\n        data.setLayout({\n            offset: columnOffset,\n            size: columnWidth\n        });\n\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var stacked = isDimensionStacked(data, valueDim /*, baseDim*/);\n        var isValueAxisH = valueAxis.isHorizontal();\n\n        var valueAxisStart = getValueAxisStart(baseAxis, valueAxis, stacked);\n\n        for (var idx = 0, len = data.count(); idx < len; idx++) {\n            var value = data.get(valueDim, idx);\n            var baseValue = data.get(baseDim, idx);\n\n            if (isNaN(value)) {\n                continue;\n            }\n\n            var sign = value >= 0 ? 'p' : 'n';\n            var baseCoord = valueAxisStart;\n\n            // Because of the barMinHeight, we can not use the value in\n            // stackResultDimension directly.\n            if (stacked) {\n                // Only ordinal axis can be stacked.\n                if (!lastStackCoords[stackId][baseValue]) {\n                    lastStackCoords[stackId][baseValue] = {\n                        p: valueAxisStart, // Positive stack\n                        n: valueAxisStart  // Negative stack\n                    };\n                }\n                // Should also consider #4243\n                baseCoord = lastStackCoords[stackId][baseValue][sign];\n            }\n\n            var x;\n            var y;\n            var width;\n            var height;\n\n            if (isValueAxisH) {\n                var coord = cartesian.dataToPoint([value, baseValue]);\n                x = baseCoord;\n                y = coord[1] + columnOffset;\n                width = coord[0] - valueAxisStart;\n                height = columnWidth;\n\n                if (Math.abs(width) < barMinHeight) {\n                    width = (width < 0 ? -1 : 1) * barMinHeight;\n                }\n                stacked && (lastStackCoords[stackId][baseValue][sign] += width);\n            }\n            else {\n                var coord = cartesian.dataToPoint([baseValue, value]);\n                x = coord[0] + columnOffset;\n                y = baseCoord;\n                width = columnWidth;\n                height = coord[1] - valueAxisStart;\n\n                if (Math.abs(height) < barMinHeight) {\n                    // Include zero to has a positive bar\n                    height = (height <= 0 ? -1 : 1) * barMinHeight;\n                }\n                stacked && (lastStackCoords[stackId][baseValue][sign] += height);\n            }\n\n            data.setItemLayout(idx, {\n                x: x,\n                y: y,\n                width: width,\n                height: height\n            });\n        }\n\n    }, this);\n}\n\n// TODO: Do not support stack in large mode yet.\nvar largeLayout = {\n\n    seriesType: 'bar',\n\n    plan: createRenderPlanner(),\n\n    reset: function (seriesModel) {\n        if (!isOnCartesian(seriesModel) || !isInLargeMode(seriesModel)) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var valueAxis = cartesian.getOtherAxis(baseAxis);\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var valueAxisHorizontal = valueAxis.isHorizontal();\n        var valueDimIdx = valueAxisHorizontal ? 0 : 1;\n\n        var barWidth = retrieveColumnLayout(\n            makeColumnLayout([seriesModel]), baseAxis, seriesModel\n        ).width;\n        if (!(barWidth > LARGE_BAR_MIN_WIDTH)) { // jshint ignore:line\n            barWidth = LARGE_BAR_MIN_WIDTH;\n        }\n\n        return {progress: progress};\n\n        function progress(params, data) {\n            var largePoints = new LargeArr(params.count * 2);\n            var dataIndex;\n            var coord = [];\n            var valuePair = [];\n            var offset = 0;\n\n            while ((dataIndex = params.next()) != null) {\n                valuePair[valueDimIdx] = data.get(valueDim, dataIndex);\n                valuePair[1 - valueDimIdx] = data.get(baseDim, dataIndex);\n\n                coord = cartesian.dataToPoint(valuePair, null, coord);\n                largePoints[offset++] = coord[0];\n                largePoints[offset++] = coord[1];\n            }\n\n            data.setLayout({\n                largePoints: largePoints,\n                barWidth: barWidth,\n                valueAxisStart: getValueAxisStart(baseAxis, valueAxis, false),\n                valueAxisHorizontal: valueAxisHorizontal\n            });\n        }\n    }\n};\n\nfunction isOnCartesian(seriesModel) {\n    return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d';\n}\n\nfunction isInLargeMode(seriesModel) {\n    return seriesModel.pipelineContext && seriesModel.pipelineContext.large;\n}\n\n// See cases in `test/bar-start.html` and `#7412`, `#8747`.\nfunction getValueAxisStart(baseAxis, valueAxis, stacked) {\n    var extent = valueAxis.getGlobalExtent();\n    var min;\n    var max;\n    if (extent[0] > extent[1]) {\n        min = extent[1];\n        max = extent[0];\n    }\n    else {\n        min = extent[0];\n        max = extent[1];\n    }\n\n    var valueStart = valueAxis.toGlobalCoord(valueAxis.dataToCoord(0));\n    valueStart < min && (valueStart = min);\n    valueStart > max && (valueStart = max);\n\n    return valueStart;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The \"scaleLevels\" was originally copied from \"d3.js\" with some\n* modifications made for this project.\n* (See more details in the comment on the definition of \"scaleLevels\" below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\n\n// [About UTC and local time zone]:\n// In most cases, `number.parseDate` will treat input data string as local time\n// (except time zone is specified in time string). And `format.formateTime` returns\n// local time by default. option.useUTC is false by default. This design have\n// concidered these common case:\n// (1) Time that is persistent in server is in UTC, but it is needed to be diplayed\n// in local time by default.\n// (2) By default, the input data string (e.g., '2011-01-02') should be displayed\n// as its original time, without any time difference.\n\nvar intervalScaleProto = IntervalScale.prototype;\n\nvar mathCeil = Math.ceil;\nvar mathFloor = Math.floor;\nvar ONE_SECOND = 1000;\nvar ONE_MINUTE = ONE_SECOND * 60;\nvar ONE_HOUR = ONE_MINUTE * 60;\nvar ONE_DAY = ONE_HOUR * 24;\n\n// FIXME 公用？\nvar bisect = function (a, x, lo, hi) {\n    while (lo < hi) {\n        var mid = lo + hi >>> 1;\n        if (a[mid][1] < x) {\n            lo = mid + 1;\n        }\n        else {\n            hi = mid;\n        }\n    }\n    return lo;\n};\n\n/**\n * @alias module:echarts/coord/scale/Time\n * @constructor\n */\nvar TimeScale = IntervalScale.extend({\n    type: 'time',\n\n    /**\n     * @override\n     */\n    getLabel: function (val) {\n        var stepLvl = this._stepLvl;\n\n        var date = new Date(val);\n\n        return formatTime(stepLvl[0], date, this.getSetting('useUTC'));\n    },\n\n    /**\n     * @override\n     */\n    niceExtent: function (opt) {\n        var extent = this._extent;\n        // If extent start and end are same, expand them\n        if (extent[0] === extent[1]) {\n            // Expand extent\n            extent[0] -= ONE_DAY;\n            extent[1] += ONE_DAY;\n        }\n        // If there are no data and extent are [Infinity, -Infinity]\n        if (extent[1] === -Infinity && extent[0] === Infinity) {\n            var d = new Date();\n            extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate());\n            extent[0] = extent[1] - ONE_DAY;\n        }\n\n        this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);\n\n        // var extent = this._extent;\n        var interval = this._interval;\n\n        if (!opt.fixMin) {\n            extent[0] = round$2(mathFloor(extent[0] / interval) * interval);\n        }\n        if (!opt.fixMax) {\n            extent[1] = round$2(mathCeil(extent[1] / interval) * interval);\n        }\n    },\n\n    /**\n     * @override\n     */\n    niceTicks: function (approxTickNum, minInterval, maxInterval) {\n        approxTickNum = approxTickNum || 10;\n\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        var approxInterval = span / approxTickNum;\n\n        if (minInterval != null && approxInterval < minInterval) {\n            approxInterval = minInterval;\n        }\n        if (maxInterval != null && approxInterval > maxInterval) {\n            approxInterval = maxInterval;\n        }\n\n        var scaleLevelsLen = scaleLevels.length;\n        var idx = bisect(scaleLevels, approxInterval, 0, scaleLevelsLen);\n\n        var level = scaleLevels[Math.min(idx, scaleLevelsLen - 1)];\n        var interval = level[1];\n        // Same with interval scale if span is much larger than 1 year\n        if (level[0] === 'year') {\n            var yearSpan = span / interval;\n\n            // From \"Nice Numbers for Graph Labels\" of Graphic Gems\n            // var niceYearSpan = numberUtil.nice(yearSpan, false);\n            var yearStep = nice(yearSpan / approxTickNum, true);\n\n            interval *= yearStep;\n        }\n\n        var timezoneOffset = this.getSetting('useUTC')\n            ? 0 : (new Date(+extent[0] || +extent[1])).getTimezoneOffset() * 60 * 1000;\n        var niceExtent = [\n            Math.round(mathCeil((extent[0] - timezoneOffset) / interval) * interval + timezoneOffset),\n            Math.round(mathFloor((extent[1] - timezoneOffset) / interval) * interval + timezoneOffset)\n        ];\n\n        fixExtent(niceExtent, extent);\n\n        this._stepLvl = level;\n        // Interval will be used in getTicks\n        this._interval = interval;\n        this._niceExtent = niceExtent;\n    },\n\n    parse: function (val) {\n        // val might be float.\n        return +parseDate(val);\n    }\n});\n\neach$1(['contain', 'normalize'], function (methodName) {\n    TimeScale.prototype[methodName] = function (val) {\n        return intervalScaleProto[methodName].call(this, this.parse(val));\n    };\n});\n\n/**\n * This implementation was originally copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/b516d77fb8566b576088e73410437494717ada26/src/time/scale.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n */\nvar scaleLevels = [\n    // Format              interval\n    ['hh:mm:ss', ONE_SECOND],          // 1s\n    ['hh:mm:ss', ONE_SECOND * 5],      // 5s\n    ['hh:mm:ss', ONE_SECOND * 10],     // 10s\n    ['hh:mm:ss', ONE_SECOND * 15],     // 15s\n    ['hh:mm:ss', ONE_SECOND * 30],     // 30s\n    ['hh:mm\\nMM-dd', ONE_MINUTE],      // 1m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 5],  // 5m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 10], // 10m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 15], // 15m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 30], // 30m\n    ['hh:mm\\nMM-dd', ONE_HOUR],        // 1h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 2],    // 2h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 6],    // 6h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 12],   // 12h\n    ['MM-dd\\nyyyy', ONE_DAY],          // 1d\n    ['MM-dd\\nyyyy', ONE_DAY * 2],      // 2d\n    ['MM-dd\\nyyyy', ONE_DAY * 3],      // 3d\n    ['MM-dd\\nyyyy', ONE_DAY * 4],      // 4d\n    ['MM-dd\\nyyyy', ONE_DAY * 5],      // 5d\n    ['MM-dd\\nyyyy', ONE_DAY * 6],      // 6d\n    ['week', ONE_DAY * 7],             // 7d\n    ['MM-dd\\nyyyy', ONE_DAY * 10],     // 10d\n    ['week', ONE_DAY * 14],            // 2w\n    ['week', ONE_DAY * 21],            // 3w\n    ['month', ONE_DAY * 31],           // 1M\n    ['week', ONE_DAY * 42],            // 6w\n    ['month', ONE_DAY * 62],           // 2M\n    ['week', ONE_DAY * 70],            // 10w\n    ['quarter', ONE_DAY * 95],         // 3M\n    ['month', ONE_DAY * 31 * 4],       // 4M\n    ['month', ONE_DAY * 31 * 5],       // 5M\n    ['half-year', ONE_DAY * 380 / 2],  // 6M\n    ['month', ONE_DAY * 31 * 8],       // 8M\n    ['month', ONE_DAY * 31 * 10],      // 10M\n    ['year', ONE_DAY * 380]            // 1Y\n];\n\n/**\n * @param {module:echarts/model/Model}\n * @return {module:echarts/scale/Time}\n */\nTimeScale.create = function (model) {\n    return new TimeScale({useUTC: model.ecModel.get('useUTC')});\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Log scale\n * @module echarts/scale/Log\n */\n\n// Use some method of IntervalScale\nvar scaleProto$1 = Scale.prototype;\nvar intervalScaleProto$1 = IntervalScale.prototype;\n\nvar getPrecisionSafe$1 = getPrecisionSafe;\nvar roundingErrorFix = round$2;\n\nvar mathFloor$1 = Math.floor;\nvar mathCeil$1 = Math.ceil;\nvar mathPow$1 = Math.pow;\n\nvar mathLog = Math.log;\n\nvar LogScale = Scale.extend({\n\n    type: 'log',\n\n    base: 10,\n\n    $constructor: function () {\n        Scale.apply(this, arguments);\n        this._originalScale = new IntervalScale();\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getTicks: function () {\n        var originalScale = this._originalScale;\n        var extent = this._extent;\n        var originalExtent = originalScale.getExtent();\n\n        return map(intervalScaleProto$1.getTicks.call(this), function (val) {\n            var powVal = round$2(mathPow$1(this.base, val));\n\n            // Fix #4158\n            powVal = (val === extent[0] && originalScale.__fixMin)\n                ? fixRoundingError(powVal, originalExtent[0])\n                : powVal;\n            powVal = (val === extent[1] && originalScale.__fixMax)\n                ? fixRoundingError(powVal, originalExtent[1])\n                : powVal;\n\n            return powVal;\n        }, this);\n    },\n\n    /**\n     * @param {number} val\n     * @return {string}\n     */\n    getLabel: intervalScaleProto$1.getLabel,\n\n    /**\n     * @param  {number} val\n     * @return {number}\n     */\n    scale: function (val) {\n        val = scaleProto$1.scale.call(this, val);\n        return mathPow$1(this.base, val);\n    },\n\n    /**\n     * @param {number} start\n     * @param {number} end\n     */\n    setExtent: function (start, end) {\n        var base = this.base;\n        start = mathLog(start) / mathLog(base);\n        end = mathLog(end) / mathLog(base);\n        intervalScaleProto$1.setExtent.call(this, start, end);\n    },\n\n    /**\n     * @return {number} end\n     */\n    getExtent: function () {\n        var base = this.base;\n        var extent = scaleProto$1.getExtent.call(this);\n        extent[0] = mathPow$1(base, extent[0]);\n        extent[1] = mathPow$1(base, extent[1]);\n\n        // Fix #4158\n        var originalScale = this._originalScale;\n        var originalExtent = originalScale.getExtent();\n        originalScale.__fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0]));\n        originalScale.__fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1]));\n\n        return extent;\n    },\n\n    /**\n     * @param  {Array.<number>} extent\n     */\n    unionExtent: function (extent) {\n        this._originalScale.unionExtent(extent);\n\n        var base = this.base;\n        extent[0] = mathLog(extent[0]) / mathLog(base);\n        extent[1] = mathLog(extent[1]) / mathLog(base);\n        scaleProto$1.unionExtent.call(this, extent);\n    },\n\n    /**\n     * @override\n     */\n    unionExtentFromData: function (data, dim) {\n        // TODO\n        // filter value that <= 0\n        this.unionExtent(data.getApproximateExtent(dim));\n    },\n\n    /**\n     * Update interval and extent of intervals for nice ticks\n     * @param  {number} [approxTickNum = 10] Given approx tick number\n     */\n    niceTicks: function (approxTickNum) {\n        approxTickNum = approxTickNum || 10;\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        if (span === Infinity || span <= 0) {\n            return;\n        }\n\n        var interval = quantity(span);\n        var err = approxTickNum / span * interval;\n\n        // Filter ticks to get closer to the desired count.\n        if (err <= 0.5) {\n            interval *= 10;\n        }\n\n        // Interval should be integer\n        while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) {\n            interval *= 10;\n        }\n\n        var niceExtent = [\n            round$2(mathCeil$1(extent[0] / interval) * interval),\n            round$2(mathFloor$1(extent[1] / interval) * interval)\n        ];\n\n        this._interval = interval;\n        this._niceExtent = niceExtent;\n    },\n\n    /**\n     * Nice extent.\n     * @override\n     */\n    niceExtent: function (opt) {\n        intervalScaleProto$1.niceExtent.call(this, opt);\n\n        var originalScale = this._originalScale;\n        originalScale.__fixMin = opt.fixMin;\n        originalScale.__fixMax = opt.fixMax;\n    }\n\n});\n\neach$1(['contain', 'normalize'], function (methodName) {\n    LogScale.prototype[methodName] = function (val) {\n        val = mathLog(val) / mathLog(this.base);\n        return scaleProto$1[methodName].call(this, val);\n    };\n});\n\nLogScale.create = function () {\n    return new LogScale();\n};\n\nfunction fixRoundingError(val, originalVal) {\n    return roundingErrorFix(val, getPrecisionSafe$1(originalVal));\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Get axis scale extent before niced.\n * Item of returned array can only be number (including Infinity and NaN).\n */\nfunction getScaleExtent(scale, model) {\n    var scaleType = scale.type;\n\n    var min = model.getMin();\n    var max = model.getMax();\n    var fixMin = min != null;\n    var fixMax = max != null;\n    var originalExtent = scale.getExtent();\n\n    var axisDataLen;\n    var boundaryGap;\n    var span;\n    if (scaleType === 'ordinal') {\n        axisDataLen = model.getCategories().length;\n    }\n    else {\n        boundaryGap = model.get('boundaryGap');\n        if (!isArray(boundaryGap)) {\n            boundaryGap = [boundaryGap || 0, boundaryGap || 0];\n        }\n        if (typeof boundaryGap[0] === 'boolean') {\n            if (__DEV__) {\n                console.warn('Boolean type for boundaryGap is only '\n                    + 'allowed for ordinal axis. Please use string in '\n                    + 'percentage instead, e.g., \"20%\". Currently, '\n                    + 'boundaryGap is set to be 0.');\n            }\n            boundaryGap = [0, 0];\n        }\n        boundaryGap[0] = parsePercent$1(boundaryGap[0], 1);\n        boundaryGap[1] = parsePercent$1(boundaryGap[1], 1);\n        span = (originalExtent[1] - originalExtent[0])\n            || Math.abs(originalExtent[0]);\n    }\n\n    // Notice: When min/max is not set (that is, when there are null/undefined,\n    // which is the most common case), these cases should be ensured:\n    // (1) For 'ordinal', show all axis.data.\n    // (2) For others:\n    //      + `boundaryGap` is applied (if min/max set, boundaryGap is\n    //      disabled).\n    //      + If `needCrossZero`, min/max should be zero, otherwise, min/max should\n    //      be the result that originalExtent enlarged by boundaryGap.\n    // (3) If no data, it should be ensured that `scale.setBlank` is set.\n\n    // FIXME\n    // (1) When min/max is 'dataMin' or 'dataMax', should boundaryGap be able to used?\n    // (2) When `needCrossZero` and all data is positive/negative, should it be ensured\n    // that the results processed by boundaryGap are positive/negative?\n\n    if (min == null) {\n        min = scaleType === 'ordinal'\n            ? (axisDataLen ? 0 : NaN)\n            : originalExtent[0] - boundaryGap[0] * span;\n    }\n    if (max == null) {\n        max = scaleType === 'ordinal'\n            ? (axisDataLen ? axisDataLen - 1 : NaN)\n            : originalExtent[1] + boundaryGap[1] * span;\n    }\n\n    if (min === 'dataMin') {\n        min = originalExtent[0];\n    }\n    else if (typeof min === 'function') {\n        min = min({\n            min: originalExtent[0],\n            max: originalExtent[1]\n        });\n    }\n\n    if (max === 'dataMax') {\n        max = originalExtent[1];\n    }\n    else if (typeof max === 'function') {\n        max = max({\n            min: originalExtent[0],\n            max: originalExtent[1]\n        });\n    }\n\n    (min == null || !isFinite(min)) && (min = NaN);\n    (max == null || !isFinite(max)) && (max = NaN);\n\n    scale.setBlank(\n        eqNaN(min)\n        || eqNaN(max)\n        || (scaleType === 'ordinal' && !scale.getOrdinalMeta().categories.length)\n    );\n\n    // Evaluate if axis needs cross zero\n    if (model.getNeedCrossZero()) {\n        // Axis is over zero and min is not set\n        if (min > 0 && max > 0 && !fixMin) {\n            min = 0;\n        }\n        // Axis is under zero and max is not set\n        if (min < 0 && max < 0 && !fixMax) {\n            max = 0;\n        }\n    }\n\n    // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis\n    // is base axis\n    // FIXME\n    // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly.\n    // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent?\n    //     Should not depend on series type `bar`?\n    // (3) Fix that might overlap when using dataZoom.\n    // (4) Consider other chart types using `barGrid`?\n    // See #6728, #4862, `test/bar-overflow-time-plot.html`\n    var ecModel = model.ecModel;\n    if (ecModel && (scaleType === 'time' /*|| scaleType === 'interval' */)) {\n        var barSeriesModels = prepareLayoutBarSeries('bar', ecModel);\n        var isBaseAxisAndHasBarSeries;\n\n        each$1(barSeriesModels, function (seriesModel) {\n            isBaseAxisAndHasBarSeries |= seriesModel.getBaseAxis() === model.axis;\n        });\n\n        if (isBaseAxisAndHasBarSeries) {\n            // Calculate placement of bars on axis\n            var barWidthAndOffset = makeColumnLayout(barSeriesModels);\n\n            // Adjust axis min and max to account for overflow\n            var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset);\n            min = adjustedScale.min;\n            max = adjustedScale.max;\n        }\n    }\n\n    return [min, max];\n}\n\nfunction adjustScaleForOverflow(min, max, model, barWidthAndOffset) {\n\n    // Get Axis Length\n    var axisExtent = model.axis.getExtent();\n    var axisLength = axisExtent[1] - axisExtent[0];\n\n    // Get bars on current base axis and calculate min and max overflow\n    var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis);\n    if (barsOnCurrentAxis === undefined) {\n        return {min: min, max: max};\n    }\n\n    var minOverflow = Infinity;\n    each$1(barsOnCurrentAxis, function (item) {\n        minOverflow = Math.min(item.offset, minOverflow);\n    });\n    var maxOverflow = -Infinity;\n    each$1(barsOnCurrentAxis, function (item) {\n        maxOverflow = Math.max(item.offset + item.width, maxOverflow);\n    });\n    minOverflow = Math.abs(minOverflow);\n    maxOverflow = Math.abs(maxOverflow);\n    var totalOverFlow = minOverflow + maxOverflow;\n\n    // Calulate required buffer based on old range and overflow\n    var oldRange = max - min;\n    var oldRangePercentOfNew = (1 - (minOverflow + maxOverflow) / axisLength);\n    var overflowBuffer = ((oldRange / oldRangePercentOfNew) - oldRange);\n\n    max += overflowBuffer * (maxOverflow / totalOverFlow);\n    min -= overflowBuffer * (minOverflow / totalOverFlow);\n\n    return {min: min, max: max};\n}\n\nfunction niceScaleExtent(scale, model) {\n    var extent = getScaleExtent(scale, model);\n    var fixMin = model.getMin() != null;\n    var fixMax = model.getMax() != null;\n    var splitNumber = model.get('splitNumber');\n\n    if (scale.type === 'log') {\n        scale.base = model.get('logBase');\n    }\n\n    var scaleType = scale.type;\n    scale.setExtent(extent[0], extent[1]);\n    scale.niceExtent({\n        splitNumber: splitNumber,\n        fixMin: fixMin,\n        fixMax: fixMax,\n        minInterval: (scaleType === 'interval' || scaleType === 'time')\n            ? model.get('minInterval') : null,\n        maxInterval: (scaleType === 'interval' || scaleType === 'time')\n            ? model.get('maxInterval') : null\n    });\n\n    // If some one specified the min, max. And the default calculated interval\n    // is not good enough. He can specify the interval. It is often appeared\n    // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard\n    // to be 60.\n    // FIXME\n    var interval = model.get('interval');\n    if (interval != null) {\n        scale.setInterval && scale.setInterval(interval);\n    }\n}\n\n/**\n * @param {module:echarts/model/Model} model\n * @param {string} [axisType] Default retrieve from model.type\n * @return {module:echarts/scale/*}\n */\nfunction createScaleByModel(model, axisType) {\n    axisType = axisType || model.get('type');\n    if (axisType) {\n        switch (axisType) {\n            // Buildin scale\n            case 'category':\n                return new OrdinalScale(\n                    model.getOrdinalMeta\n                        ? model.getOrdinalMeta()\n                        : model.getCategories(),\n                    [Infinity, -Infinity]\n                );\n            case 'value':\n                return new IntervalScale();\n            // Extended scale, like time and log\n            default:\n                return (Scale.getClass(axisType) || IntervalScale).create(model);\n        }\n    }\n}\n\n/**\n * Check if the axis corss 0\n */\nfunction ifAxisCrossZero(axis) {\n    var dataExtent = axis.scale.getExtent();\n    var min = dataExtent[0];\n    var max = dataExtent[1];\n    return !((min > 0 && max > 0) || (min < 0 && max < 0));\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @return {Function} Label formatter function.\n *         param: {number} tickValue,\n *         param: {number} idx, the index in all ticks.\n *                         If category axis, this param is not requied.\n *         return: {string} label string.\n */\nfunction makeLabelFormatter(axis) {\n    var labelFormatter = axis.getLabelModel().get('formatter');\n    var categoryTickStart = axis.type === 'category' ? axis.scale.getExtent()[0] : null;\n\n    if (typeof labelFormatter === 'string') {\n        labelFormatter = (function (tpl) {\n            return function (val) {\n                // For category axis, get raw value; for numeric axis,\n                // get foramtted label like '1,333,444'.\n                val = axis.scale.getLabel(val);\n                return tpl.replace('{value}', val != null ? val : '');\n            };\n        })(labelFormatter);\n        // Consider empty array\n        return labelFormatter;\n    }\n    else if (typeof labelFormatter === 'function') {\n        return function (tickValue, idx) {\n            // The original intention of `idx` is \"the index of the tick in all ticks\".\n            // But the previous implementation of category axis do not consider the\n            // `axisLabel.interval`, which cause that, for example, the `interval` is\n            // `1`, then the ticks \"name5\", \"name7\", \"name9\" are displayed, where the\n            // corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep\n            // the definition here for back compatibility.\n            if (categoryTickStart != null) {\n                idx = tickValue - categoryTickStart;\n            }\n            return labelFormatter(getAxisRawValue(axis, tickValue), idx);\n        };\n    }\n    else {\n        return function (tick) {\n            return axis.scale.getLabel(tick);\n        };\n    }\n}\n\nfunction getAxisRawValue(axis, value) {\n    // In category axis with data zoom, tick is not the original\n    // index of axis.data. So tick should not be exposed to user\n    // in category axis.\n    return axis.type === 'category' ? axis.scale.getLabel(value) : value;\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @return {module:zrender/core/BoundingRect} Be null/undefined if no labels.\n */\nfunction estimateLabelUnionRect(axis) {\n    var axisModel = axis.model;\n    var scale = axis.scale;\n\n    if (!axisModel.get('axisLabel.show') || scale.isBlank()) {\n        return;\n    }\n\n    var isCategory = axis.type === 'category';\n\n    var realNumberScaleTicks;\n    var tickCount;\n    var categoryScaleExtent = scale.getExtent();\n\n    // Optimize for large category data, avoid call `getTicks()`.\n    if (isCategory) {\n        tickCount = scale.count();\n    }\n    else {\n        realNumberScaleTicks = scale.getTicks();\n        tickCount = realNumberScaleTicks.length;\n    }\n\n    var axisLabelModel = axis.getLabelModel();\n    var labelFormatter = makeLabelFormatter(axis);\n\n    var rect;\n    var step = 1;\n    // Simple optimization for large amount of labels\n    if (tickCount > 40) {\n        step = Math.ceil(tickCount / 40);\n    }\n    for (var i = 0; i < tickCount; i += step) {\n        var tickValue = realNumberScaleTicks ? realNumberScaleTicks[i] : categoryScaleExtent[0] + i;\n        var label = labelFormatter(tickValue);\n        var unrotatedSingleRect = axisLabelModel.getTextRect(label);\n        var singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0);\n\n        rect ? rect.union(singleRect) : (rect = singleRect);\n    }\n\n    return rect;\n}\n\nfunction rotateTextRect(textRect, rotate) {\n    var rotateRadians = rotate * Math.PI / 180;\n    var boundingBox = textRect.plain();\n    var beforeWidth = boundingBox.width;\n    var beforeHeight = boundingBox.height;\n    var afterWidth = beforeWidth * Math.cos(rotateRadians) + beforeHeight * Math.sin(rotateRadians);\n    var afterHeight = beforeWidth * Math.sin(rotateRadians) + beforeHeight * Math.cos(rotateRadians);\n    var rotatedRect = new BoundingRect(boundingBox.x, boundingBox.y, afterWidth, afterHeight);\n\n    return rotatedRect;\n}\n\n/**\n * @param {module:echarts/src/model/Model} model axisLabelModel or axisTickModel\n * @return {number|String} Can be null|'auto'|number|function\n */\nfunction getOptionCategoryInterval(model) {\n    var interval = model.get('interval');\n    return interval == null ? 'auto' : interval;\n}\n\n/**\n * Set `categoryInterval` as 0 implicitly indicates that\n * show all labels reguardless of overlap.\n * @param {Object} axis axisModel.axis\n * @return {boolean}\n */\nfunction shouldShowAllLabels(axis) {\n    return axis.type === 'category'\n        && getOptionCategoryInterval(axis.getLabelModel()) === 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import * as axisHelper from './axisHelper';\n\nvar axisModelCommonMixin = {\n\n    /**\n     * @param {boolean} origin\n     * @return {number|string} min value or 'dataMin' or null/undefined (means auto) or NaN\n     */\n    getMin: function (origin) {\n        var option = this.option;\n        var min = (!origin && option.rangeStart != null)\n            ? option.rangeStart : option.min;\n\n        if (this.axis\n            && min != null\n            && min !== 'dataMin'\n            && typeof min !== 'function'\n            && !eqNaN(min)\n        ) {\n            min = this.axis.scale.parse(min);\n        }\n        return min;\n    },\n\n    /**\n     * @param {boolean} origin\n     * @return {number|string} max value or 'dataMax' or null/undefined (means auto) or NaN\n     */\n    getMax: function (origin) {\n        var option = this.option;\n        var max = (!origin && option.rangeEnd != null)\n            ? option.rangeEnd : option.max;\n\n        if (this.axis\n            && max != null\n            && max !== 'dataMax'\n            && typeof max !== 'function'\n            && !eqNaN(max)\n        ) {\n            max = this.axis.scale.parse(max);\n        }\n        return max;\n    },\n\n    /**\n     * @return {boolean}\n     */\n    getNeedCrossZero: function () {\n        var option = this.option;\n        return (option.rangeStart != null || option.rangeEnd != null)\n            ? false : !option.scale;\n    },\n\n    /**\n     * Should be implemented by each axis model if necessary.\n     * @return {module:echarts/model/Component} coordinate system model\n     */\n    getCoordSysModel: noop,\n\n    /**\n     * @param {number} rangeStart Can only be finite number or null/undefined or NaN.\n     * @param {number} rangeEnd Can only be finite number or null/undefined or NaN.\n     */\n    setRange: function (rangeStart, rangeEnd) {\n        this.option.rangeStart = rangeStart;\n        this.option.rangeEnd = rangeEnd;\n    },\n\n    /**\n     * Reset range\n     */\n    resetRange: function () {\n        // rangeStart and rangeEnd is readonly.\n        this.option.rangeStart = this.option.rangeEnd = null;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Symbol factory\n\n/**\n * Triangle shape\n * @inner\n */\nvar Triangle = extendShape({\n    type: 'triangle',\n    shape: {\n        cx: 0,\n        cy: 0,\n        width: 0,\n        height: 0\n    },\n    buildPath: function (path, shape) {\n        var cx = shape.cx;\n        var cy = shape.cy;\n        var width = shape.width / 2;\n        var height = shape.height / 2;\n        path.moveTo(cx, cy - height);\n        path.lineTo(cx + width, cy + height);\n        path.lineTo(cx - width, cy + height);\n        path.closePath();\n    }\n});\n\n/**\n * Diamond shape\n * @inner\n */\nvar Diamond = extendShape({\n    type: 'diamond',\n    shape: {\n        cx: 0,\n        cy: 0,\n        width: 0,\n        height: 0\n    },\n    buildPath: function (path, shape) {\n        var cx = shape.cx;\n        var cy = shape.cy;\n        var width = shape.width / 2;\n        var height = shape.height / 2;\n        path.moveTo(cx, cy - height);\n        path.lineTo(cx + width, cy);\n        path.lineTo(cx, cy + height);\n        path.lineTo(cx - width, cy);\n        path.closePath();\n    }\n});\n\n/**\n * Pin shape\n * @inner\n */\nvar Pin = extendShape({\n    type: 'pin',\n    shape: {\n        // x, y on the cusp\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (path, shape) {\n        var x = shape.x;\n        var y = shape.y;\n        var w = shape.width / 5 * 3;\n        // Height must be larger than width\n        var h = Math.max(w, shape.height);\n        var r = w / 2;\n\n        // Dist on y with tangent point and circle center\n        var dy = r * r / (h - r);\n        var cy = y - h + r + dy;\n        var angle = Math.asin(dy / r);\n        // Dist on x with tangent point and circle center\n        var dx = Math.cos(angle) * r;\n\n        var tanX = Math.sin(angle);\n        var tanY = Math.cos(angle);\n\n        var cpLen = r * 0.6;\n        var cpLen2 = r * 0.7;\n\n        path.moveTo(x - dx, cy + dy);\n\n        path.arc(\n            x, cy, r,\n            Math.PI - angle,\n            Math.PI * 2 + angle\n        );\n        path.bezierCurveTo(\n            x + dx - tanX * cpLen, cy + dy + tanY * cpLen,\n            x, y - cpLen2,\n            x, y\n        );\n        path.bezierCurveTo(\n            x, y - cpLen2,\n            x - dx + tanX * cpLen, cy + dy + tanY * cpLen,\n            x - dx, cy + dy\n        );\n        path.closePath();\n    }\n});\n\n/**\n * Arrow shape\n * @inner\n */\nvar Arrow = extendShape({\n\n    type: 'arrow',\n\n    shape: {\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var height = shape.height;\n        var width = shape.width;\n        var x = shape.x;\n        var y = shape.y;\n        var dx = width / 3 * 2;\n        ctx.moveTo(x, y);\n        ctx.lineTo(x + dx, y + height);\n        ctx.lineTo(x, y + height / 4 * 3);\n        ctx.lineTo(x - dx, y + height);\n        ctx.lineTo(x, y);\n        ctx.closePath();\n    }\n});\n\n/**\n * Map of path contructors\n * @type {Object.<string, module:zrender/graphic/Path>}\n */\nvar symbolCtors = {\n\n    line: Line,\n\n    rect: Rect,\n\n    roundRect: Rect,\n\n    square: Rect,\n\n    circle: Circle,\n\n    diamond: Diamond,\n\n    pin: Pin,\n\n    arrow: Arrow,\n\n    triangle: Triangle\n};\n\nvar symbolShapeMakers = {\n\n    line: function (x, y, w, h, shape) {\n        // FIXME\n        shape.x1 = x;\n        shape.y1 = y + h / 2;\n        shape.x2 = x + w;\n        shape.y2 = y + h / 2;\n    },\n\n    rect: function (x, y, w, h, shape) {\n        shape.x = x;\n        shape.y = y;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    roundRect: function (x, y, w, h, shape) {\n        shape.x = x;\n        shape.y = y;\n        shape.width = w;\n        shape.height = h;\n        shape.r = Math.min(w, h) / 4;\n    },\n\n    square: function (x, y, w, h, shape) {\n        var size = Math.min(w, h);\n        shape.x = x;\n        shape.y = y;\n        shape.width = size;\n        shape.height = size;\n    },\n\n    circle: function (x, y, w, h, shape) {\n        // Put circle in the center of square\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.r = Math.min(w, h) / 2;\n    },\n\n    diamond: function (x, y, w, h, shape) {\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    pin: function (x, y, w, h, shape) {\n        shape.x = x + w / 2;\n        shape.y = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    arrow: function (x, y, w, h, shape) {\n        shape.x = x + w / 2;\n        shape.y = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    triangle: function (x, y, w, h, shape) {\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    }\n};\n\nvar symbolBuildProxies = {};\neach$1(symbolCtors, function (Ctor, name) {\n    symbolBuildProxies[name] = new Ctor();\n});\n\nvar SymbolClz = extendShape({\n\n    type: 'symbol',\n\n    shape: {\n        symbolType: '',\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    beforeBrush: function () {\n        var style = this.style;\n        var shape = this.shape;\n        // FIXME\n        if (shape.symbolType === 'pin' && style.textPosition === 'inside') {\n            style.textPosition = ['50%', '40%'];\n            style.textAlign = 'center';\n            style.textVerticalAlign = 'middle';\n        }\n    },\n\n    buildPath: function (ctx, shape, inBundle) {\n        var symbolType = shape.symbolType;\n        var proxySymbol = symbolBuildProxies[symbolType];\n        if (shape.symbolType !== 'none') {\n            if (!proxySymbol) {\n                // Default rect\n                symbolType = 'rect';\n                proxySymbol = symbolBuildProxies[symbolType];\n            }\n            symbolShapeMakers[symbolType](\n                shape.x, shape.y, shape.width, shape.height, proxySymbol.shape\n            );\n            proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle);\n        }\n    }\n});\n\n// Provide setColor helper method to avoid determine if set the fill or stroke outside\nfunction symbolPathSetColor(color, innerColor) {\n    if (this.type !== 'image') {\n        var symbolStyle = this.style;\n        var symbolShape = this.shape;\n        if (symbolShape && symbolShape.symbolType === 'line') {\n            symbolStyle.stroke = color;\n        }\n        else if (this.__isEmptyBrush) {\n            symbolStyle.stroke = color;\n            symbolStyle.fill = innerColor || '#fff';\n        }\n        else {\n            // FIXME 判断图形默认是填充还是描边，使用 onlyStroke ?\n            symbolStyle.fill && (symbolStyle.fill = color);\n            symbolStyle.stroke && (symbolStyle.stroke = color);\n        }\n        this.dirty(false);\n    }\n}\n\n/**\n * Create a symbol element with given symbol configuration: shape, x, y, width, height, color\n * @param {string} symbolType\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n * @param {string} color\n * @param {boolean} [keepAspect=false] whether to keep the ratio of w/h,\n *                            for path and image only.\n */\nfunction createSymbol(symbolType, x, y, w, h, color, keepAspect) {\n    // TODO Support image object, DynamicImage.\n\n    var isEmpty = symbolType.indexOf('empty') === 0;\n    if (isEmpty) {\n        symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6);\n    }\n    var symbolPath;\n\n    if (symbolType.indexOf('image://') === 0) {\n        symbolPath = makeImage(\n            symbolType.slice(8),\n            new BoundingRect(x, y, w, h),\n            keepAspect ? 'center' : 'cover'\n        );\n    }\n    else if (symbolType.indexOf('path://') === 0) {\n        symbolPath = makePath(\n            symbolType.slice(7),\n            {},\n            new BoundingRect(x, y, w, h),\n            keepAspect ? 'center' : 'cover'\n        );\n    }\n    else {\n        symbolPath = new SymbolClz({\n            shape: {\n                symbolType: symbolType,\n                x: x,\n                y: y,\n                width: w,\n                height: h\n            }\n        });\n    }\n\n    symbolPath.__isEmptyBrush = isEmpty;\n\n    symbolPath.setColor = symbolPathSetColor;\n\n    symbolPath.setColor(color);\n\n    return symbolPath;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import createGraphFromNodeEdge from './chart/helper/createGraphFromNodeEdge';\n/**\n * Create a muti dimension List structure from seriesModel.\n * @param  {module:echarts/model/Model} seriesModel\n * @return {module:echarts/data/List} list\n */\nfunction createList(seriesModel) {\n    return createListFromArray(seriesModel.getSource(), seriesModel);\n}\n\nvar dataStack$1 = {\n    isDimensionStacked: isDimensionStacked,\n    enableDataStack: enableDataStack,\n    getStackedDimension: getStackedDimension\n};\n\n/**\n * Create scale\n * @param {Array.<number>} dataExtent\n * @param {Object|module:echarts/Model} option\n */\nfunction createScale(dataExtent, option) {\n    var axisModel = option;\n    if (!Model.isInstance(option)) {\n        axisModel = new Model(option);\n        mixin(axisModel, axisModelCommonMixin);\n    }\n\n    var scale = createScaleByModel(axisModel);\n    scale.setExtent(dataExtent[0], dataExtent[1]);\n\n    niceScaleExtent(scale, axisModel);\n    return scale;\n}\n\n/**\n * Mixin common methods to axis model,\n *\n * Inlcude methods\n * `getFormattedLabels() => Array.<string>`\n * `getCategories() => Array.<string>`\n * `getMin(origin: boolean) => number`\n * `getMax(origin: boolean) => number`\n * `getNeedCrossZero() => boolean`\n * `setRange(start: number, end: number)`\n * `resetRange()`\n */\nfunction mixinAxisModelCommonMethods(Model$$1) {\n    mixin(Model$$1, axisModelCommonMixin);\n}\n\nvar helper = (Object.freeze || Object)({\n\tcreateList: createList,\n\tgetLayoutRect: getLayoutRect,\n\tdataStack: dataStack$1,\n\tcreateScale: createScale,\n\tmixinAxisModelCommonMethods: mixinAxisModelCommonMethods,\n\tcompleteDimensions: completeDimensions,\n\tcreateDimensions: createDimensions,\n\tcreateSymbol: createSymbol\n});\n\nvar EPSILON$3 = 1e-8;\n\nfunction isAroundEqual$1(a, b) {\n    return Math.abs(a - b) < EPSILON$3;\n}\n\nfunction contain$1(points, x, y) {\n    var w = 0;\n    var p = points[0];\n\n    if (!p) {\n        return false;\n    }\n\n    for (var i = 1; i < points.length; i++) {\n        var p2 = points[i];\n        w += windingLine(p[0], p[1], p2[0], p2[1], x, y);\n        p = p2;\n    }\n\n    // Close polygon\n    var p0 = points[0];\n    if (!isAroundEqual$1(p[0], p0[0]) || !isAroundEqual$1(p[1], p0[1])) {\n        w += windingLine(p[0], p[1], p0[0], p0[1], x, y);\n    }\n\n    return w !== 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/coord/geo/Region\n */\n\n/**\n * @param {string|Region} name\n * @param {Array} geometries\n * @param {Array.<number>} cp\n */\nfunction Region(name, geometries, cp) {\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.name = name;\n\n    /**\n     * @type {Array.<Array>}\n     * @readOnly\n     */\n    this.geometries = geometries;\n\n    if (!cp) {\n        var rect = this.getBoundingRect();\n        cp = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    }\n    else {\n        cp = [cp[0], cp[1]];\n    }\n    /**\n     * @type {Array.<number>}\n     */\n    this.center = cp;\n}\n\nRegion.prototype = {\n\n    constructor: Region,\n\n    properties: null,\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function () {\n        var rect = this._rect;\n        if (rect) {\n            return rect;\n        }\n\n        var MAX_NUMBER = Number.MAX_VALUE;\n        var min$$1 = [MAX_NUMBER, MAX_NUMBER];\n        var max$$1 = [-MAX_NUMBER, -MAX_NUMBER];\n        var min2 = [];\n        var max2 = [];\n        var geometries = this.geometries;\n        for (var i = 0; i < geometries.length; i++) {\n            // Only support polygon\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            // Doesn't consider hole\n            var exterior = geometries[i].exterior;\n            fromPoints(exterior, min2, max2);\n            min(min$$1, min$$1, min2);\n            max(max$$1, max$$1, max2);\n        }\n        // No data\n        if (i === 0) {\n            min$$1[0] = min$$1[1] = max$$1[0] = max$$1[1] = 0;\n        }\n\n        return (this._rect = new BoundingRect(\n            min$$1[0], min$$1[1], max$$1[0] - min$$1[0], max$$1[1] - min$$1[1]\n        ));\n    },\n\n    /**\n     * @param {<Array.<number>} coord\n     * @return {boolean}\n     */\n    contain: function (coord) {\n        var rect = this.getBoundingRect();\n        var geometries = this.geometries;\n        if (!rect.contain(coord[0], coord[1])) {\n            return false;\n        }\n        loopGeo: for (var i = 0, len$$1 = geometries.length; i < len$$1; i++) {\n            // Only support polygon.\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            var exterior = geometries[i].exterior;\n            var interiors = geometries[i].interiors;\n            if (contain$1(exterior, coord[0], coord[1])) {\n                // Not in the region if point is in the hole.\n                for (var k = 0; k < (interiors ? interiors.length : 0); k++) {\n                    if (contain$1(interiors[k])) {\n                        continue loopGeo;\n                    }\n                }\n                return true;\n            }\n        }\n        return false;\n    },\n\n    transformTo: function (x, y, width, height) {\n        var rect = this.getBoundingRect();\n        var aspect = rect.width / rect.height;\n        if (!width) {\n            width = aspect * height;\n        }\n        else if (!height) {\n            height = width / aspect;\n        }\n        var target = new BoundingRect(x, y, width, height);\n        var transform = rect.calculateTransform(target);\n        var geometries = this.geometries;\n        for (var i = 0; i < geometries.length; i++) {\n            // Only support polygon.\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            var exterior = geometries[i].exterior;\n            var interiors = geometries[i].interiors;\n            for (var p = 0; p < exterior.length; p++) {\n                applyTransform(exterior[p], exterior[p], transform);\n            }\n            for (var h = 0; h < (interiors ? interiors.length : 0); h++) {\n                for (var p = 0; p < interiors[h].length; p++) {\n                    applyTransform(interiors[h][p], interiors[h][p], transform);\n                }\n            }\n        }\n        rect = this._rect;\n        rect.copy(target);\n        // Update center\n        this.center = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    },\n\n    cloneShallow: function (name) {\n        name == null && (name = this.name);\n        var newRegion = new Region(name, this.geometries, this.center);\n        newRegion._rect = this._rect;\n        newRegion.transformTo = null; // Simply avoid to be called.\n        return newRegion;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Parse and decode geo json\n * @module echarts/coord/geo/parseGeoJson\n */\n\nfunction decode(json) {\n    if (!json.UTF8Encoding) {\n        return json;\n    }\n    var encodeScale = json.UTF8Scale;\n    if (encodeScale == null) {\n        encodeScale = 1024;\n    }\n\n    var features = json.features;\n\n    for (var f = 0; f < features.length; f++) {\n        var feature = features[f];\n        var geometry = feature.geometry;\n        var coordinates = geometry.coordinates;\n        var encodeOffsets = geometry.encodeOffsets;\n\n        for (var c = 0; c < coordinates.length; c++) {\n            var coordinate = coordinates[c];\n\n            if (geometry.type === 'Polygon') {\n                coordinates[c] = decodePolygon(\n                    coordinate,\n                    encodeOffsets[c],\n                    encodeScale\n                );\n            }\n            else if (geometry.type === 'MultiPolygon') {\n                for (var c2 = 0; c2 < coordinate.length; c2++) {\n                    var polygon = coordinate[c2];\n                    coordinate[c2] = decodePolygon(\n                        polygon,\n                        encodeOffsets[c][c2],\n                        encodeScale\n                    );\n                }\n            }\n        }\n    }\n    // Has been decoded\n    json.UTF8Encoding = false;\n    return json;\n}\n\nfunction decodePolygon(coordinate, encodeOffsets, encodeScale) {\n    var result = [];\n    var prevX = encodeOffsets[0];\n    var prevY = encodeOffsets[1];\n\n    for (var i = 0; i < coordinate.length; i += 2) {\n        var x = coordinate.charCodeAt(i) - 64;\n        var y = coordinate.charCodeAt(i + 1) - 64;\n        // ZigZag decoding\n        x = (x >> 1) ^ (-(x & 1));\n        y = (y >> 1) ^ (-(y & 1));\n        // Delta deocding\n        x += prevX;\n        y += prevY;\n\n        prevX = x;\n        prevY = y;\n        // Dequantize\n        result.push([x / encodeScale, y / encodeScale]);\n    }\n\n    return result;\n}\n\n/**\n * @alias module:echarts/coord/geo/parseGeoJson\n * @param {Object} geoJson\n * @return {module:zrender/container/Group}\n */\nvar parseGeoJson$1 = function (geoJson) {\n\n    decode(geoJson);\n\n    return map(filter(geoJson.features, function (featureObj) {\n        // Output of mapshaper may have geometry null\n        return featureObj.geometry\n            && featureObj.properties\n            && featureObj.geometry.coordinates.length > 0;\n    }), function (featureObj) {\n        var properties = featureObj.properties;\n        var geo = featureObj.geometry;\n\n        var coordinates = geo.coordinates;\n\n        var geometries = [];\n        if (geo.type === 'Polygon') {\n            geometries.push({\n                type: 'polygon',\n                // According to the GeoJSON specification.\n                // First must be exterior, and the rest are all interior(holes).\n                exterior: coordinates[0],\n                interiors: coordinates.slice(1)\n            });\n        }\n        if (geo.type === 'MultiPolygon') {\n            each$1(coordinates, function (item) {\n                if (item[0]) {\n                    geometries.push({\n                        type: 'polygon',\n                        exterior: item[0],\n                        interiors: item.slice(1)\n                    });\n                }\n            });\n        }\n\n        var region = new Region(\n            properties.name,\n            geometries,\n            properties.cp\n        );\n        region.properties = properties;\n        return region;\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$6 = makeInner();\n\n/**\n * @param {module:echats/coord/Axis} axis\n * @return {Object} {\n *     labels: [{\n *         formattedLabel: string,\n *         rawLabel: string,\n *         tickValue: number\n *     }, ...],\n *     labelCategoryInterval: number\n * }\n */\nfunction createAxisLabels(axis) {\n    // Only ordinal scale support tick interval\n    return axis.type === 'category'\n        ? makeCategoryLabels(axis)\n        : makeRealNumberLabels(axis);\n}\n\n/**\n * @param {module:echats/coord/Axis} axis\n * @param {module:echarts/model/Model} tickModel For example, can be axisTick, splitLine, splitArea.\n * @return {Object} {\n *     ticks: Array.<number>\n *     tickCategoryInterval: number\n * }\n */\nfunction createAxisTicks(axis, tickModel) {\n    // Only ordinal scale support tick interval\n    return axis.type === 'category'\n        ? makeCategoryTicks(axis, tickModel)\n        : {ticks: axis.scale.getTicks()};\n}\n\nfunction makeCategoryLabels(axis) {\n    var labelModel = axis.getLabelModel();\n    var result = makeCategoryLabelsActually(axis, labelModel);\n\n    return (!labelModel.get('show') || axis.scale.isBlank())\n        ? {labels: [], labelCategoryInterval: result.labelCategoryInterval}\n        : result;\n}\n\nfunction makeCategoryLabelsActually(axis, labelModel) {\n    var labelsCache = getListCache(axis, 'labels');\n    var optionLabelInterval = getOptionCategoryInterval(labelModel);\n    var result = listCacheGet(labelsCache, optionLabelInterval);\n\n    if (result) {\n        return result;\n    }\n\n    var labels;\n    var numericLabelInterval;\n\n    if (isFunction$1(optionLabelInterval)) {\n        labels = makeLabelsByCustomizedCategoryInterval(axis, optionLabelInterval);\n    }\n    else {\n        numericLabelInterval = optionLabelInterval === 'auto'\n            ? makeAutoCategoryInterval(axis) : optionLabelInterval;\n        labels = makeLabelsByNumericCategoryInterval(axis, numericLabelInterval);\n    }\n\n    // Cache to avoid calling interval function repeatly.\n    return listCacheSet(labelsCache, optionLabelInterval, {\n        labels: labels, labelCategoryInterval: numericLabelInterval\n    });\n}\n\nfunction makeCategoryTicks(axis, tickModel) {\n    var ticksCache = getListCache(axis, 'ticks');\n    var optionTickInterval = getOptionCategoryInterval(tickModel);\n    var result = listCacheGet(ticksCache, optionTickInterval);\n\n    if (result) {\n        return result;\n    }\n\n    var ticks;\n    var tickCategoryInterval;\n\n    // Optimize for the case that large category data and no label displayed,\n    // we should not return all ticks.\n    if (!tickModel.get('show') || axis.scale.isBlank()) {\n        ticks = [];\n    }\n\n    if (isFunction$1(optionTickInterval)) {\n        ticks = makeLabelsByCustomizedCategoryInterval(axis, optionTickInterval, true);\n    }\n    // Always use label interval by default despite label show. Consider this\n    // scenario, Use multiple grid with the xAxis sync, and only one xAxis shows\n    // labels. `splitLine` and `axisTick` should be consistent in this case.\n    else if (optionTickInterval === 'auto') {\n        var labelsResult = makeCategoryLabelsActually(axis, axis.getLabelModel());\n        tickCategoryInterval = labelsResult.labelCategoryInterval;\n        ticks = map(labelsResult.labels, function (labelItem) {\n            return labelItem.tickValue;\n        });\n    }\n    else {\n        tickCategoryInterval = optionTickInterval;\n        ticks = makeLabelsByNumericCategoryInterval(axis, tickCategoryInterval, true);\n    }\n\n    // Cache to avoid calling interval function repeatly.\n    return listCacheSet(ticksCache, optionTickInterval, {\n        ticks: ticks, tickCategoryInterval: tickCategoryInterval\n    });\n}\n\nfunction makeRealNumberLabels(axis) {\n    var ticks = axis.scale.getTicks();\n    var labelFormatter = makeLabelFormatter(axis);\n    return {\n        labels: map(ticks, function (tickValue, idx) {\n            return {\n                formattedLabel: labelFormatter(tickValue, idx),\n                rawLabel: axis.scale.getLabel(tickValue),\n                tickValue: tickValue\n            };\n        })\n    };\n}\n\n// Large category data calculation is performence sensitive, and ticks and label\n// probably be fetched by multiple times. So we cache the result.\n// axis is created each time during a ec process, so we do not need to clear cache.\nfunction getListCache(axis, prop) {\n    // Because key can be funciton, and cache size always be small, we use array cache.\n    return inner$6(axis)[prop] || (inner$6(axis)[prop] = []);\n}\n\nfunction listCacheGet(cache, key) {\n    for (var i = 0; i < cache.length; i++) {\n        if (cache[i].key === key) {\n            return cache[i].value;\n        }\n    }\n}\n\nfunction listCacheSet(cache, key, value) {\n    cache.push({key: key, value: value});\n    return value;\n}\n\nfunction makeAutoCategoryInterval(axis) {\n    var result = inner$6(axis).autoInterval;\n    return result != null\n        ? result\n        : (inner$6(axis).autoInterval = axis.calculateCategoryInterval());\n}\n\n/**\n * Calculate interval for category axis ticks and labels.\n * To get precise result, at least one of `getRotate` and `isHorizontal`\n * should be implemented in axis.\n */\nfunction calculateCategoryInterval(axis) {\n    var params = fetchAutoCategoryIntervalCalculationParams(axis);\n    var labelFormatter = makeLabelFormatter(axis);\n    var rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI;\n\n    var ordinalScale = axis.scale;\n    var ordinalExtent = ordinalScale.getExtent();\n    // Providing this method is for optimization:\n    // avoid generating a long array by `getTicks`\n    // in large category data case.\n    var tickCount = ordinalScale.count();\n\n    if (ordinalExtent[1] - ordinalExtent[0] < 1) {\n        return 0;\n    }\n\n    var step = 1;\n    // Simple optimization. Empirical value: tick count should less than 40.\n    if (tickCount > 40) {\n        step = Math.max(1, Math.floor(tickCount / 40));\n    }\n    var tickValue = ordinalExtent[0];\n    var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue);\n    var unitW = Math.abs(unitSpan * Math.cos(rotation));\n    var unitH = Math.abs(unitSpan * Math.sin(rotation));\n\n    var maxW = 0;\n    var maxH = 0;\n\n    // Caution: Performance sensitive for large category data.\n    // Consider dataZoom, we should make appropriate step to avoid O(n) loop.\n    for (; tickValue <= ordinalExtent[1]; tickValue += step) {\n        var width = 0;\n        var height = 0;\n\n        // Not precise, do not consider align and vertical align\n        // and each distance from axis line yet.\n        var rect = getBoundingRect(\n            labelFormatter(tickValue), params.font, 'center', 'top'\n        );\n        // Magic number\n        width = rect.width * 1.3;\n        height = rect.height * 1.3;\n\n        // Min size, void long loop.\n        maxW = Math.max(maxW, width, 7);\n        maxH = Math.max(maxH, height, 7);\n    }\n\n    var dw = maxW / unitW;\n    var dh = maxH / unitH;\n    // 0/0 is NaN, 1/0 is Infinity.\n    isNaN(dw) && (dw = Infinity);\n    isNaN(dh) && (dh = Infinity);\n    var interval = Math.max(0, Math.floor(Math.min(dw, dh)));\n\n    var cache = inner$6(axis.model);\n    var lastAutoInterval = cache.lastAutoInterval;\n    var lastTickCount = cache.lastTickCount;\n\n    // Use cache to keep interval stable while moving zoom window,\n    // otherwise the calculated interval might jitter when the zoom\n    // window size is close to the interval-changing size.\n    if (lastAutoInterval != null\n        && lastTickCount != null\n        && Math.abs(lastAutoInterval - interval) <= 1\n        && Math.abs(lastTickCount - tickCount) <= 1\n        // Always choose the bigger one, otherwise the critical\n        // point is not the same when zooming in or zooming out.\n        && lastAutoInterval > interval\n    ) {\n        interval = lastAutoInterval;\n    }\n    // Only update cache if cache not used, otherwise the\n    // changing of interval is too insensitive.\n    else {\n        cache.lastTickCount = tickCount;\n        cache.lastAutoInterval = interval;\n    }\n\n    return interval;\n}\n\nfunction fetchAutoCategoryIntervalCalculationParams(axis) {\n    var labelModel = axis.getLabelModel();\n    return {\n        axisRotate: axis.getRotate\n            ? axis.getRotate()\n            : (axis.isHorizontal && !axis.isHorizontal())\n            ? 90\n            : 0,\n        labelRotate: labelModel.get('rotate') || 0,\n        font: labelModel.getFont()\n    };\n}\n\nfunction makeLabelsByNumericCategoryInterval(axis, categoryInterval, onlyTick) {\n    var labelFormatter = makeLabelFormatter(axis);\n    var ordinalScale = axis.scale;\n    var ordinalExtent = ordinalScale.getExtent();\n    var labelModel = axis.getLabelModel();\n    var result = [];\n\n    // TODO: axisType: ordinalTime, pick the tick from each month/day/year/...\n\n    var step = Math.max((categoryInterval || 0) + 1, 1);\n    var startTick = ordinalExtent[0];\n    var tickCount = ordinalScale.count();\n\n    // Calculate start tick based on zero if possible to keep label consistent\n    // while zooming and moving while interval > 0. Otherwise the selection\n    // of displayable ticks and symbols probably keep changing.\n    // 3 is empirical value.\n    if (startTick !== 0 && step > 1 && tickCount / step > 2) {\n        startTick = Math.round(Math.ceil(startTick / step) * step);\n    }\n\n    // (1) Only add min max label here but leave overlap checking\n    // to render stage, which also ensure the returned list\n    // suitable for splitLine and splitArea rendering.\n    // (2) Scales except category always contain min max label so\n    // do not need to perform this process.\n    var showAllLabel = shouldShowAllLabels(axis);\n    var includeMinLabel = labelModel.get('showMinLabel') || showAllLabel;\n    var includeMaxLabel = labelModel.get('showMaxLabel') || showAllLabel;\n\n    if (includeMinLabel && startTick !== ordinalExtent[0]) {\n        addItem(ordinalExtent[0]);\n    }\n\n    // Optimize: avoid generating large array by `ordinalScale.getTicks()`.\n    var tickValue = startTick;\n    for (; tickValue <= ordinalExtent[1]; tickValue += step) {\n        addItem(tickValue);\n    }\n\n    if (includeMaxLabel && tickValue !== ordinalExtent[1]) {\n        addItem(ordinalExtent[1]);\n    }\n\n    function addItem(tVal) {\n        result.push(onlyTick\n            ? tVal\n            : {\n                formattedLabel: labelFormatter(tVal),\n                rawLabel: ordinalScale.getLabel(tVal),\n                tickValue: tVal\n            }\n        );\n    }\n\n    return result;\n}\n\n// When interval is function, the result `false` means ignore the tick.\n// It is time consuming for large category data.\nfunction makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) {\n    var ordinalScale = axis.scale;\n    var labelFormatter = makeLabelFormatter(axis);\n    var result = [];\n\n    each$1(ordinalScale.getTicks(), function (tickValue) {\n        var rawLabel = ordinalScale.getLabel(tickValue);\n        if (categoryInterval(tickValue, rawLabel)) {\n            result.push(onlyTick\n                ? tickValue\n                : {\n                    formattedLabel: labelFormatter(tickValue),\n                    rawLabel: rawLabel,\n                    tickValue: tickValue\n                }\n            );\n        }\n    });\n\n    return result;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar NORMALIZED_EXTENT = [0, 1];\n\n/**\n * Base class of Axis.\n * @constructor\n */\nvar Axis = function (dim, scale, extent) {\n\n    /**\n     * Axis dimension. Such as 'x', 'y', 'z', 'angle', 'radius'.\n     * @type {string}\n     */\n    this.dim = dim;\n\n    /**\n     * Axis scale\n     * @type {module:echarts/coord/scale/*}\n     */\n    this.scale = scale;\n\n    /**\n     * @type {Array.<number>}\n     * @private\n     */\n    this._extent = extent || [0, 0];\n\n    /**\n     * @type {boolean}\n     */\n    this.inverse = false;\n\n    /**\n     * Usually true when axis has a ordinal scale\n     * @type {boolean}\n     */\n    this.onBand = false;\n};\n\nAxis.prototype = {\n\n    constructor: Axis,\n\n    /**\n     * If axis extent contain given coord\n     * @param {number} coord\n     * @return {boolean}\n     */\n    contain: function (coord) {\n        var extent = this._extent;\n        var min = Math.min(extent[0], extent[1]);\n        var max = Math.max(extent[0], extent[1]);\n        return coord >= min && coord <= max;\n    },\n\n    /**\n     * If axis extent contain given data\n     * @param {number} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this.contain(this.dataToCoord(data));\n    },\n\n    /**\n     * Get coord extent.\n     * @return {Array.<number>}\n     */\n    getExtent: function () {\n        return this._extent.slice();\n    },\n\n    /**\n     * Get precision used for formatting\n     * @param {Array.<number>} [dataExtent]\n     * @return {number}\n     */\n    getPixelPrecision: function (dataExtent) {\n        return getPixelPrecision(\n            dataExtent || this.scale.getExtent(),\n            this._extent\n        );\n    },\n\n    /**\n     * Set coord extent\n     * @param {number} start\n     * @param {number} end\n     */\n    setExtent: function (start, end) {\n        var extent = this._extent;\n        extent[0] = start;\n        extent[1] = end;\n    },\n\n    /**\n     * Convert data to coord. Data is the rank if it has an ordinal scale\n     * @param {number} data\n     * @param  {boolean} clamp\n     * @return {number}\n     */\n    dataToCoord: function (data, clamp) {\n        var extent = this._extent;\n        var scale = this.scale;\n        data = scale.normalize(data);\n\n        if (this.onBand && scale.type === 'ordinal') {\n            extent = extent.slice();\n            fixExtentWithBands(extent, scale.count());\n        }\n\n        return linearMap(data, NORMALIZED_EXTENT, extent, clamp);\n    },\n\n    /**\n     * Convert coord to data. Data is the rank if it has an ordinal scale\n     * @param {number} coord\n     * @param  {boolean} clamp\n     * @return {number}\n     */\n    coordToData: function (coord, clamp) {\n        var extent = this._extent;\n        var scale = this.scale;\n\n        if (this.onBand && scale.type === 'ordinal') {\n            extent = extent.slice();\n            fixExtentWithBands(extent, scale.count());\n        }\n\n        var t = linearMap(coord, extent, NORMALIZED_EXTENT, clamp);\n\n        return this.scale.scale(t);\n    },\n\n    /**\n     * Convert pixel point to data in axis\n     * @param {Array.<number>} point\n     * @param  {boolean} clamp\n     * @return {number} data\n     */\n    pointToData: function (point, clamp) {\n        // Should be implemented in derived class if necessary.\n    },\n\n    /**\n     * Different from `zrUtil.map(axis.getTicks(), axis.dataToCoord, axis)`,\n     * `axis.getTicksCoords` considers `onBand`, which is used by\n     * `boundaryGap:true` of category axis and splitLine and splitArea.\n     * @param {Object} [opt]\n     * @param {number} [opt.tickModel=axis.model.getModel('axisTick')]\n     * @param {boolean} [opt.clamp] If `true`, the first and the last\n     *        tick must be at the axis end points. Otherwise, clip ticks\n     *        that outside the axis extent.\n     * @return {Array.<Object>} [{\n     *     coord: ...,\n     *     tickValue: ...\n     * }, ...]\n     */\n    getTicksCoords: function (opt) {\n        opt = opt || {};\n\n        var tickModel = opt.tickModel || this.getTickModel();\n\n        var result = createAxisTicks(this, tickModel);\n        var ticks = result.ticks;\n\n        var ticksCoords = map(ticks, function (tickValue) {\n            return {\n                coord: this.dataToCoord(tickValue),\n                tickValue: tickValue\n            };\n        }, this);\n\n        var alignWithLabel = tickModel.get('alignWithLabel');\n        fixOnBandTicksCoords(\n            this, ticksCoords, result.tickCategoryInterval, alignWithLabel, opt.clamp\n        );\n\n        return ticksCoords;\n    },\n\n    /**\n     * @return {Array.<Object>} [{\n     *     formattedLabel: string,\n     *     rawLabel: axis.scale.getLabel(tickValue)\n     *     tickValue: number\n     * }, ...]\n     */\n    getViewLabels: function () {\n        return createAxisLabels(this).labels;\n    },\n\n    /**\n     * @return {module:echarts/coord/model/Model}\n     */\n    getLabelModel: function () {\n        return this.model.getModel('axisLabel');\n    },\n\n    /**\n     * Notice here we only get the default tick model. For splitLine\n     * or splitArea, we should pass the splitLineModel or splitAreaModel\n     * manually when calling `getTicksCoords`.\n     * In GL, this method may be overrided to:\n     * `axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));`\n     * @return {module:echarts/coord/model/Model}\n     */\n    getTickModel: function () {\n        return this.model.getModel('axisTick');\n    },\n\n    /**\n     * Get width of band\n     * @return {number}\n     */\n    getBandWidth: function () {\n        var axisExtent = this._extent;\n        var dataExtent = this.scale.getExtent();\n\n        var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0);\n        // Fix #2728, avoid NaN when only one data.\n        len === 0 && (len = 1);\n\n        var size = Math.abs(axisExtent[1] - axisExtent[0]);\n\n        return Math.abs(size) / len;\n    },\n\n    /**\n     * @abstract\n     * @return {boolean} Is horizontal\n     */\n    isHorizontal: null,\n\n    /**\n     * @abstract\n     * @return {number} Get axis rotate, by degree.\n     */\n    getRotate: null,\n\n    /**\n     * Only be called in category axis.\n     * Can be overrided, consider other axes like in 3D.\n     * @return {number} Auto interval for cateogry axis tick and label\n     */\n    calculateCategoryInterval: function () {\n        return calculateCategoryInterval(this);\n    }\n\n};\n\nfunction fixExtentWithBands(extent, nTick) {\n    var size = extent[1] - extent[0];\n    var len = nTick;\n    var margin = size / len / 2;\n    extent[0] += margin;\n    extent[1] -= margin;\n}\n\n// If axis has labels [1, 2, 3, 4]. Bands on the axis are\n// |---1---|---2---|---3---|---4---|.\n// So the displayed ticks and splitLine/splitArea should between\n// each data item, otherwise cause misleading (e.g., split tow bars\n// of a single data item when there are two bar series).\n// Also consider if tickCategoryInterval > 0 and onBand, ticks and\n// splitLine/spliteArea should layout appropriately corresponding\n// to displayed labels. (So we should not use `getBandWidth` in this\n// case).\nfunction fixOnBandTicksCoords(axis, ticksCoords, tickCategoryInterval, alignWithLabel, clamp) {\n    var ticksLen = ticksCoords.length;\n\n    if (!axis.onBand || alignWithLabel || !ticksLen) {\n        return;\n    }\n\n    var axisExtent = axis.getExtent();\n    var last;\n    if (ticksLen === 1) {\n        ticksCoords[0].coord = axisExtent[0];\n        last = ticksCoords[1] = {coord: axisExtent[0]};\n    }\n    else {\n        var shift = (ticksCoords[1].coord - ticksCoords[0].coord);\n        each$1(ticksCoords, function (ticksItem) {\n            ticksItem.coord -= shift / 2;\n            var tickCategoryInterval = tickCategoryInterval || 0;\n            // Avoid split a single data item when odd interval.\n            if (tickCategoryInterval % 2 > 0) {\n                ticksItem.coord -= shift / ((tickCategoryInterval + 1) * 2);\n            }\n        });\n        last = {coord: ticksCoords[ticksLen - 1].coord + shift};\n        ticksCoords.push(last);\n    }\n\n    var inverse = axisExtent[0] > axisExtent[1];\n\n    if (littleThan(ticksCoords[0].coord, axisExtent[0])) {\n        clamp ? (ticksCoords[0].coord = axisExtent[0]) : ticksCoords.shift();\n    }\n    if (clamp && littleThan(axisExtent[0], ticksCoords[0].coord)) {\n        ticksCoords.unshift({coord: axisExtent[0]});\n    }\n    if (littleThan(axisExtent[1], last.coord)) {\n        clamp ? (last.coord = axisExtent[1]) : ticksCoords.pop();\n    }\n    if (clamp && littleThan(last.coord, axisExtent[1])) {\n        ticksCoords.push({coord: axisExtent[1]});\n    }\n\n    function littleThan(a, b) {\n        return inverse ? a > b : a < b;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Do not mount those modules on 'src/echarts' for better tree shaking.\n */\n\nvar parseGeoJson = parseGeoJson$1;\n\nvar ecUtil = {};\neach$1(\n    [\n        'map', 'each', 'filter', 'indexOf', 'inherits', 'reduce', 'filter',\n        'bind', 'curry', 'isArray', 'isString', 'isObject', 'isFunction',\n        'extend', 'defaults', 'clone', 'merge'\n    ],\n    function (name) {\n        ecUtil[name] = zrUtil[name];\n    }\n);\nvar graphic$1 = {};\neach$1(\n    [\n        'extendShape', 'extendPath', 'makePath', 'makeImage',\n        'mergePath', 'resizePath', 'createIcon',\n        'setHoverStyle', 'setLabelStyle', 'setTextStyle', 'setText',\n        'getFont', 'updateProps', 'initProps', 'getTransform',\n        'clipPointsByRect', 'clipRectByRect',\n        'Group',\n        'Image',\n        'Text',\n        'Circle',\n        'Sector',\n        'Ring',\n        'Polygon',\n        'Polyline',\n        'Rect',\n        'Line',\n        'BezierCurve',\n        'Arc',\n        'IncrementalDisplayable',\n        'CompoundPath',\n        'LinearGradient',\n        'RadialGradient',\n        'BoundingRect'\n    ],\n    function (name) {\n        graphic$1[name] = graphic[name];\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.line',\n\n    dependencies: ['grid', 'polar'],\n\n    getInitialData: function (option, ecModel) {\n        if (__DEV__) {\n            var coordSys = option.coordinateSystem;\n            if (coordSys !== 'polar' && coordSys !== 'cartesian2d') {\n                throw new Error('Line not support coordinateSystem besides cartesian and polar');\n            }\n        }\n        return createListFromArray(this.getSource(), this);\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // stack: null\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // polarIndex: 0,\n\n        // If clip the overflow value\n        clipOverflow: true,\n        // cursor: null,\n\n        label: {\n            position: 'top'\n        },\n        // itemStyle: {\n        // },\n\n        lineStyle: {\n            width: 2,\n            type: 'solid'\n        },\n        // areaStyle: {\n            // origin of areaStyle. Valid values:\n            // `'auto'/null/undefined`: from axisLine to data\n            // `'start'`: from min to data\n            // `'end'`: from data to max\n            // origin: 'auto'\n        // },\n        // false, 'start', 'end', 'middle'\n        step: false,\n\n        // Disabled if step is true\n        smooth: false,\n        smoothMonotone: null,\n        symbol: 'emptyCircle',\n        symbolSize: 4,\n        symbolRotate: null,\n\n        showSymbol: true,\n        // `false`: follow the label interval strategy.\n        // `true`: show all symbols.\n        // `'auto'`: If possible, show all symbols, otherwise\n        //           follow the label interval strategy.\n        showAllSymbol: 'auto',\n\n        // Whether to connect break point.\n        connectNulls: false,\n\n        // Sampling for large data. Can be: 'average', 'max', 'min', 'sum'.\n        sampling: 'none',\n\n        animationEasing: 'linear',\n\n        // Disable progressive\n        progressive: 0,\n        hoverLayerThreshold: Infinity\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @return {string} label string. Not null/undefined\n */\nfunction getDefaultLabel(data, dataIndex) {\n    var labelDims = data.mapDimension('defaultedLabel', true);\n    var len = labelDims.length;\n\n    // Simple optimization (in lots of cases, label dims length is 1)\n    if (len === 1) {\n        return retrieveRawValue(data, dataIndex, labelDims[0]);\n    }\n    else if (len) {\n        var vals = [];\n        for (var i = 0; i < labelDims.length; i++) {\n            var val = retrieveRawValue(data, dataIndex, labelDims[i]);\n            vals.push(val);\n        }\n        return vals.join(' ');\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Symbol\n */\n\n/**\n * @constructor\n * @alias {module:echarts/chart/helper/Symbol}\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @extends {module:zrender/graphic/Group}\n */\nfunction SymbolClz$1(data, idx, seriesScope) {\n    Group.call(this);\n    this.updateData(data, idx, seriesScope);\n}\n\nvar symbolProto = SymbolClz$1.prototype;\n\n/**\n * @public\n * @static\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @return {Array.<number>} [width, height]\n */\nvar getSymbolSize = SymbolClz$1.getSymbolSize = function (data, idx) {\n    var symbolSize = data.getItemVisual(idx, 'symbolSize');\n    return symbolSize instanceof Array\n        ? symbolSize.slice()\n        : [+symbolSize, +symbolSize];\n};\n\nfunction getScale(symbolSize) {\n    return [symbolSize[0] / 2, symbolSize[1] / 2];\n}\n\nfunction driftSymbol(dx, dy) {\n    this.parent.drift(dx, dy);\n}\n\nsymbolProto._createSymbol = function (\n    symbolType,\n    data,\n    idx,\n    symbolSize,\n    keepAspect\n) {\n    // Remove paths created before\n    this.removeAll();\n\n    var color = data.getItemVisual(idx, 'color');\n\n    // var symbolPath = createSymbol(\n    //     symbolType, -0.5, -0.5, 1, 1, color\n    // );\n    // If width/height are set too small (e.g., set to 1) on ios10\n    // and macOS Sierra, a circle stroke become a rect, no matter what\n    // the scale is set. So we set width/height as 2. See #4150.\n    var symbolPath = createSymbol(\n        symbolType, -1, -1, 2, 2, color, keepAspect\n    );\n\n    symbolPath.attr({\n        z2: 100,\n        culling: true,\n        scale: getScale(symbolSize)\n    });\n    // Rewrite drift method\n    symbolPath.drift = driftSymbol;\n\n    this._symbolType = symbolType;\n\n    this.add(symbolPath);\n};\n\n/**\n * Stop animation\n * @param {boolean} toLastFrame\n */\nsymbolProto.stopSymbolAnimation = function (toLastFrame) {\n    this.childAt(0).stopAnimation(toLastFrame);\n};\n\n/**\n * FIXME:\n * Caution: This method breaks the encapsulation of this module,\n * but it indeed brings convenience. So do not use the method\n * unless you detailedly know all the implements of `Symbol`,\n * especially animation.\n *\n * Get symbol path element.\n */\nsymbolProto.getSymbolPath = function () {\n    return this.childAt(0);\n};\n\n/**\n * Get scale(aka, current symbol size).\n * Including the change caused by animation\n */\nsymbolProto.getScale = function () {\n    return this.childAt(0).scale;\n};\n\n/**\n * Highlight symbol\n */\nsymbolProto.highlight = function () {\n    this.childAt(0).trigger('emphasis');\n};\n\n/**\n * Downplay symbol\n */\nsymbolProto.downplay = function () {\n    this.childAt(0).trigger('normal');\n};\n\n/**\n * @param {number} zlevel\n * @param {number} z\n */\nsymbolProto.setZ = function (zlevel, z) {\n    var symbolPath = this.childAt(0);\n    symbolPath.zlevel = zlevel;\n    symbolPath.z = z;\n};\n\nsymbolProto.setDraggable = function (draggable) {\n    var symbolPath = this.childAt(0);\n    symbolPath.draggable = draggable;\n    symbolPath.cursor = draggable ? 'move' : 'pointer';\n};\n\n/**\n * Update symbol properties\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @param {Object} [seriesScope]\n * @param {Object} [seriesScope.itemStyle]\n * @param {Object} [seriesScope.hoverItemStyle]\n * @param {Object} [seriesScope.symbolRotate]\n * @param {Object} [seriesScope.symbolOffset]\n * @param {module:echarts/model/Model} [seriesScope.labelModel]\n * @param {module:echarts/model/Model} [seriesScope.hoverLabelModel]\n * @param {boolean} [seriesScope.hoverAnimation]\n * @param {Object} [seriesScope.cursorStyle]\n * @param {module:echarts/model/Model} [seriesScope.itemModel]\n * @param {string} [seriesScope.symbolInnerColor]\n * @param {Object} [seriesScope.fadeIn=false]\n */\nsymbolProto.updateData = function (data, idx, seriesScope) {\n    this.silent = false;\n\n    var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';\n    var seriesModel = data.hostModel;\n    var symbolSize = getSymbolSize(data, idx);\n    var isInit = symbolType !== this._symbolType;\n\n    if (isInit) {\n        var keepAspect = data.getItemVisual(idx, 'symbolKeepAspect');\n        this._createSymbol(symbolType, data, idx, symbolSize, keepAspect);\n    }\n    else {\n        var symbolPath = this.childAt(0);\n        symbolPath.silent = false;\n        updateProps(symbolPath, {\n            scale: getScale(symbolSize)\n        }, seriesModel, idx);\n    }\n\n    this._updateCommon(data, idx, symbolSize, seriesScope);\n\n    if (isInit) {\n        var symbolPath = this.childAt(0);\n        var fadeIn = seriesScope && seriesScope.fadeIn;\n\n        var target = {scale: symbolPath.scale.slice()};\n        fadeIn && (target.style = {opacity: symbolPath.style.opacity});\n\n        symbolPath.scale = [0, 0];\n        fadeIn && (symbolPath.style.opacity = 0);\n\n        initProps(symbolPath, target, seriesModel, idx);\n    }\n\n    this._seriesModel = seriesModel;\n};\n\n// Update common properties\nvar normalStyleAccessPath = ['itemStyle'];\nvar emphasisStyleAccessPath = ['emphasis', 'itemStyle'];\nvar normalLabelAccessPath = ['label'];\nvar emphasisLabelAccessPath = ['emphasis', 'label'];\n\n/**\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @param {Array.<number>} symbolSize\n * @param {Object} [seriesScope]\n */\nsymbolProto._updateCommon = function (data, idx, symbolSize, seriesScope) {\n    var symbolPath = this.childAt(0);\n    var seriesModel = data.hostModel;\n    var color = data.getItemVisual(idx, 'color');\n\n    // Reset style\n    if (symbolPath.type !== 'image') {\n        symbolPath.useStyle({\n            strokeNoScale: true\n        });\n    }\n\n    var itemStyle = seriesScope && seriesScope.itemStyle;\n    var hoverItemStyle = seriesScope && seriesScope.hoverItemStyle;\n    var symbolRotate = seriesScope && seriesScope.symbolRotate;\n    var symbolOffset = seriesScope && seriesScope.symbolOffset;\n    var labelModel = seriesScope && seriesScope.labelModel;\n    var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;\n    var hoverAnimation = seriesScope && seriesScope.hoverAnimation;\n    var cursorStyle = seriesScope && seriesScope.cursorStyle;\n\n    if (!seriesScope || data.hasItemOption) {\n        var itemModel = (seriesScope && seriesScope.itemModel)\n            ? seriesScope.itemModel : data.getItemModel(idx);\n\n        // Color must be excluded.\n        // Because symbol provide setColor individually to set fill and stroke\n        itemStyle = itemModel.getModel(normalStyleAccessPath).getItemStyle(['color']);\n        hoverItemStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();\n\n        symbolRotate = itemModel.getShallow('symbolRotate');\n        symbolOffset = itemModel.getShallow('symbolOffset');\n\n        labelModel = itemModel.getModel(normalLabelAccessPath);\n        hoverLabelModel = itemModel.getModel(emphasisLabelAccessPath);\n        hoverAnimation = itemModel.getShallow('hoverAnimation');\n        cursorStyle = itemModel.getShallow('cursor');\n    }\n    else {\n        hoverItemStyle = extend({}, hoverItemStyle);\n    }\n\n    var elStyle = symbolPath.style;\n\n    symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0);\n\n    if (symbolOffset) {\n        symbolPath.attr('position', [\n            parsePercent$1(symbolOffset[0], symbolSize[0]),\n            parsePercent$1(symbolOffset[1], symbolSize[1])\n        ]);\n    }\n\n    cursorStyle && symbolPath.attr('cursor', cursorStyle);\n\n    // PENDING setColor before setStyle!!!\n    symbolPath.setColor(color, seriesScope && seriesScope.symbolInnerColor);\n\n    symbolPath.setStyle(itemStyle);\n\n    var opacity = data.getItemVisual(idx, 'opacity');\n    if (opacity != null) {\n        elStyle.opacity = opacity;\n    }\n\n    var liftZ = data.getItemVisual(idx, 'liftZ');\n    var z2Origin = symbolPath.__z2Origin;\n    if (liftZ != null) {\n        if (z2Origin == null) {\n            symbolPath.__z2Origin = symbolPath.z2;\n            symbolPath.z2 += liftZ;\n        }\n    }\n    else if (z2Origin != null) {\n        symbolPath.z2 = z2Origin;\n        symbolPath.__z2Origin = null;\n    }\n\n    var useNameLabel = seriesScope && seriesScope.useNameLabel;\n\n    setLabelStyle(\n        elStyle, hoverItemStyle, labelModel, hoverLabelModel,\n        {\n            labelFetcher: seriesModel,\n            labelDataIndex: idx,\n            defaultText: getLabelDefaultText,\n            isRectText: true,\n            autoColor: color\n        }\n    );\n\n    // Do not execute util needed.\n    function getLabelDefaultText(idx, opt) {\n        return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx);\n    }\n\n    symbolPath.off('mouseover')\n        .off('mouseout')\n        .off('emphasis')\n        .off('normal');\n\n    symbolPath.hoverStyle = hoverItemStyle;\n\n    // FIXME\n    // Do not use symbol.trigger('emphasis'), but use symbol.highlight() instead.\n    setHoverStyle(symbolPath);\n\n    symbolPath.__symbolOriginalScale = getScale(symbolSize);\n\n    if (hoverAnimation && seriesModel.isAnimationEnabled()) {\n        // Note: consider `off`, should use static function here.\n        symbolPath.on('mouseover', onMouseOver)\n            .on('mouseout', onMouseOut)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal);\n    }\n};\n\nfunction onMouseOver() {\n    // see comment in `graphic.isInEmphasis`\n    !isInEmphasis(this) && onEmphasis.call(this);\n}\n\nfunction onMouseOut() {\n    // see comment in `graphic.isInEmphasis`\n    !isInEmphasis(this) && onNormal.call(this);\n}\n\nfunction onEmphasis() {\n    // Do not support this hover animation util some scenario required.\n    // Animation can only be supported in hover layer when using `el.incremetal`.\n    if (this.incremental || this.useHoverLayer) {\n        return;\n    }\n    var scale = this.__symbolOriginalScale;\n    var ratio = scale[1] / scale[0];\n    this.animateTo({\n        scale: [\n            Math.max(scale[0] * 1.1, scale[0] + 3),\n            Math.max(scale[1] * 1.1, scale[1] + 3 * ratio)\n        ]\n    }, 400, 'elasticOut');\n}\n\nfunction onNormal() {\n    if (this.incremental || this.useHoverLayer) {\n        return;\n    }\n    this.animateTo({\n        scale: this.__symbolOriginalScale\n    }, 400, 'elasticOut');\n}\n\n\n/**\n * @param {Function} cb\n * @param {Object} [opt]\n * @param {Object} [opt.keepLabel=true]\n */\nsymbolProto.fadeOut = function (cb, opt) {\n    var symbolPath = this.childAt(0);\n    // Avoid mistaken hover when fading out\n    this.silent = symbolPath.silent = true;\n    // Not show text when animating\n    !(opt && opt.keepLabel) && (symbolPath.style.text = null);\n\n    updateProps(\n        symbolPath,\n        {\n            style: {opacity: 0},\n            scale: [0, 0]\n        },\n        this._seriesModel,\n        this.dataIndex,\n        cb\n    );\n};\n\ninherits(SymbolClz$1, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/SymbolDraw\n */\n\n/**\n * @constructor\n * @alias module:echarts/chart/helper/SymbolDraw\n * @param {module:zrender/graphic/Group} [symbolCtor]\n */\nfunction SymbolDraw(symbolCtor) {\n    this.group = new Group();\n\n    this._symbolCtor = symbolCtor || SymbolClz$1;\n}\n\nvar symbolDrawProto = SymbolDraw.prototype;\n\nfunction symbolNeedsDraw(data, point, idx, opt) {\n    return point && !isNaN(point[0]) && !isNaN(point[1])\n        && !(opt.isIgnore && opt.isIgnore(idx))\n        // We do not set clipShape on group, because it will cut part of\n        // the symbol element shape. We use the same clip shape here as\n        // the line clip.\n        && !(opt.clipShape && !opt.clipShape.contain(point[0], point[1]))\n        && data.getItemVisual(idx, 'symbol') !== 'none';\n}\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n * @param {Object} [opt] Or isIgnore\n * @param {Function} [opt.isIgnore]\n * @param {Object} [opt.clipShape]\n */\nsymbolDrawProto.updateData = function (data, opt) {\n    opt = normalizeUpdateOpt(opt);\n\n    var group = this.group;\n    var seriesModel = data.hostModel;\n    var oldData = this._data;\n    var SymbolCtor = this._symbolCtor;\n\n    var seriesScope = makeSeriesScope(data);\n\n    // There is no oldLineData only when first rendering or switching from\n    // stream mode to normal mode, where previous elements should be removed.\n    if (!oldData) {\n        group.removeAll();\n    }\n\n    data.diff(oldData)\n        .add(function (newIdx) {\n            var point = data.getItemLayout(newIdx);\n            if (symbolNeedsDraw(data, point, newIdx, opt)) {\n                var symbolEl = new SymbolCtor(data, newIdx, seriesScope);\n                symbolEl.attr('position', point);\n                data.setItemGraphicEl(newIdx, symbolEl);\n                group.add(symbolEl);\n            }\n        })\n        .update(function (newIdx, oldIdx) {\n            var symbolEl = oldData.getItemGraphicEl(oldIdx);\n            var point = data.getItemLayout(newIdx);\n            if (!symbolNeedsDraw(data, point, newIdx, opt)) {\n                group.remove(symbolEl);\n                return;\n            }\n            if (!symbolEl) {\n                symbolEl = new SymbolCtor(data, newIdx);\n                symbolEl.attr('position', point);\n            }\n            else {\n                symbolEl.updateData(data, newIdx, seriesScope);\n                updateProps(symbolEl, {\n                    position: point\n                }, seriesModel);\n            }\n\n            // Add back\n            group.add(symbolEl);\n\n            data.setItemGraphicEl(newIdx, symbolEl);\n        })\n        .remove(function (oldIdx) {\n            var el = oldData.getItemGraphicEl(oldIdx);\n            el && el.fadeOut(function () {\n                group.remove(el);\n            });\n        })\n        .execute();\n\n    this._data = data;\n};\n\nsymbolDrawProto.isPersistent = function () {\n    return true;\n};\n\nsymbolDrawProto.updateLayout = function () {\n    var data = this._data;\n    if (data) {\n        // Not use animation\n        data.eachItemGraphicEl(function (el, idx) {\n            var point = data.getItemLayout(idx);\n            el.attr('position', point);\n        });\n    }\n};\n\nsymbolDrawProto.incrementalPrepareUpdate = function (data) {\n    this._seriesScope = makeSeriesScope(data);\n    this._data = null;\n    this.group.removeAll();\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n * @param {Object} [opt] Or isIgnore\n * @param {Function} [opt.isIgnore]\n * @param {Object} [opt.clipShape]\n */\nsymbolDrawProto.incrementalUpdate = function (taskParams, data, opt) {\n    opt = normalizeUpdateOpt(opt);\n\n    function updateIncrementalAndHover(el) {\n        if (!el.isGroup) {\n            el.incremental = el.useHoverLayer = true;\n        }\n    }\n    for (var idx = taskParams.start; idx < taskParams.end; idx++) {\n        var point = data.getItemLayout(idx);\n        if (symbolNeedsDraw(data, point, idx, opt)) {\n            var el = new this._symbolCtor(data, idx, this._seriesScope);\n            el.traverse(updateIncrementalAndHover);\n            el.attr('position', point);\n            this.group.add(el);\n            data.setItemGraphicEl(idx, el);\n        }\n    }\n};\n\nfunction normalizeUpdateOpt(opt) {\n    if (opt != null && !isObject$1(opt)) {\n        opt = {isIgnore: opt};\n    }\n    return opt || {};\n}\n\nsymbolDrawProto.remove = function (enableAnimation) {\n    var group = this.group;\n    var data = this._data;\n    // Incremental model do not have this._data.\n    if (data && enableAnimation) {\n        data.eachItemGraphicEl(function (el) {\n            el.fadeOut(function () {\n                group.remove(el);\n            });\n        });\n    }\n    else {\n        group.removeAll();\n    }\n};\n\nfunction makeSeriesScope(data) {\n    var seriesModel = data.hostModel;\n    return {\n        itemStyle: seriesModel.getModel('itemStyle').getItemStyle(['color']),\n        hoverItemStyle: seriesModel.getModel('emphasis.itemStyle').getItemStyle(),\n        symbolRotate: seriesModel.get('symbolRotate'),\n        symbolOffset: seriesModel.get('symbolOffset'),\n        hoverAnimation: seriesModel.get('hoverAnimation'),\n        labelModel: seriesModel.getModel('label'),\n        hoverLabelModel: seriesModel.getModel('emphasis.label'),\n        cursorStyle: seriesModel.get('cursor')\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} coordSys\n * @param {module:echarts/data/List} data\n * @param {string} valueOrigin lineSeries.option.areaStyle.origin\n */\nfunction prepareDataCoordInfo(coordSys, data, valueOrigin) {\n    var baseAxis = coordSys.getBaseAxis();\n    var valueAxis = coordSys.getOtherAxis(baseAxis);\n    var valueStart = getValueStart(valueAxis, valueOrigin);\n\n    var baseAxisDim = baseAxis.dim;\n    var valueAxisDim = valueAxis.dim;\n    var valueDim = data.mapDimension(valueAxisDim);\n    var baseDim = data.mapDimension(baseAxisDim);\n    var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0;\n\n    var dims = map(coordSys.dimensions, function (coordDim) {\n        return data.mapDimension(coordDim);\n    });\n\n    var stacked;\n    var stackResultDim = data.getCalculationInfo('stackResultDimension');\n    if (stacked |= isDimensionStacked(data, dims[0] /*, dims[1]*/)) { // jshint ignore:line\n        dims[0] = stackResultDim;\n    }\n    if (stacked |= isDimensionStacked(data, dims[1] /*, dims[0]*/)) { // jshint ignore:line\n        dims[1] = stackResultDim;\n    }\n\n    return {\n        dataDimsForPoint: dims,\n        valueStart: valueStart,\n        valueAxisDim: valueAxisDim,\n        baseAxisDim: baseAxisDim,\n        stacked: !!stacked,\n        valueDim: valueDim,\n        baseDim: baseDim,\n        baseDataOffset: baseDataOffset,\n        stackedOverDimension: data.getCalculationInfo('stackedOverDimension')\n    };\n}\n\nfunction getValueStart(valueAxis, valueOrigin) {\n    var valueStart = 0;\n    var extent = valueAxis.scale.getExtent();\n\n    if (valueOrigin === 'start') {\n        valueStart = extent[0];\n    }\n    else if (valueOrigin === 'end') {\n        valueStart = extent[1];\n    }\n    // auto\n    else {\n        // Both positive\n        if (extent[0] > 0) {\n            valueStart = extent[0];\n        }\n        // Both negative\n        else if (extent[1] < 0) {\n            valueStart = extent[1];\n        }\n        // If is one positive, and one negative, onZero shall be true\n    }\n\n    return valueStart;\n}\n\nfunction getStackedOnPoint(dataCoordInfo, coordSys, data, idx) {\n    var value = NaN;\n    if (dataCoordInfo.stacked) {\n        value = data.get(data.getCalculationInfo('stackedOverDimension'), idx);\n    }\n    if (isNaN(value)) {\n        value = dataCoordInfo.valueStart;\n    }\n\n    var baseDataOffset = dataCoordInfo.baseDataOffset;\n    var stackedData = [];\n    stackedData[baseDataOffset] = data.get(dataCoordInfo.baseDim, idx);\n    stackedData[1 - baseDataOffset] = value;\n\n    return coordSys.dataToPoint(stackedData);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// var arrayDiff = require('zrender/src/core/arrayDiff');\n// 'zrender/src/core/arrayDiff' has been used before, but it did\n// not do well in performance when roam with fixed dataZoom window.\n\n// function convertToIntId(newIdList, oldIdList) {\n//     // Generate int id instead of string id.\n//     // Compare string maybe slow in score function of arrDiff\n\n//     // Assume id in idList are all unique\n//     var idIndicesMap = {};\n//     var idx = 0;\n//     for (var i = 0; i < newIdList.length; i++) {\n//         idIndicesMap[newIdList[i]] = idx;\n//         newIdList[i] = idx++;\n//     }\n//     for (var i = 0; i < oldIdList.length; i++) {\n//         var oldId = oldIdList[i];\n//         // Same with newIdList\n//         if (idIndicesMap[oldId]) {\n//             oldIdList[i] = idIndicesMap[oldId];\n//         }\n//         else {\n//             oldIdList[i] = idx++;\n//         }\n//     }\n// }\n\nfunction diffData(oldData, newData) {\n    var diffResult = [];\n\n    newData.diff(oldData)\n        .add(function (idx) {\n            diffResult.push({cmd: '+', idx: idx});\n        })\n        .update(function (newIdx, oldIdx) {\n            diffResult.push({cmd: '=', idx: oldIdx, idx1: newIdx});\n        })\n        .remove(function (idx) {\n            diffResult.push({cmd: '-', idx: idx});\n        })\n        .execute();\n\n    return diffResult;\n}\n\nvar lineAnimationDiff = function (\n    oldData, newData,\n    oldStackedOnPoints, newStackedOnPoints,\n    oldCoordSys, newCoordSys,\n    oldValueOrigin, newValueOrigin\n) {\n    var diff = diffData(oldData, newData);\n\n    // var newIdList = newData.mapArray(newData.getId);\n    // var oldIdList = oldData.mapArray(oldData.getId);\n\n    // convertToIntId(newIdList, oldIdList);\n\n    // // FIXME One data ?\n    // diff = arrayDiff(oldIdList, newIdList);\n\n    var currPoints = [];\n    var nextPoints = [];\n    // Points for stacking base line\n    var currStackedPoints = [];\n    var nextStackedPoints = [];\n\n    var status = [];\n    var sortedIndices = [];\n    var rawIndices = [];\n\n    var newDataOldCoordInfo = prepareDataCoordInfo(oldCoordSys, newData, oldValueOrigin);\n    var oldDataNewCoordInfo = prepareDataCoordInfo(newCoordSys, oldData, newValueOrigin);\n\n    for (var i = 0; i < diff.length; i++) {\n        var diffItem = diff[i];\n        var pointAdded = true;\n\n        // FIXME, animation is not so perfect when dataZoom window moves fast\n        // Which is in case remvoing or add more than one data in the tail or head\n        switch (diffItem.cmd) {\n            case '=':\n                var currentPt = oldData.getItemLayout(diffItem.idx);\n                var nextPt = newData.getItemLayout(diffItem.idx1);\n                // If previous data is NaN, use next point directly\n                if (isNaN(currentPt[0]) || isNaN(currentPt[1])) {\n                    currentPt = nextPt.slice();\n                }\n                currPoints.push(currentPt);\n                nextPoints.push(nextPt);\n\n                currStackedPoints.push(oldStackedOnPoints[diffItem.idx]);\n                nextStackedPoints.push(newStackedOnPoints[diffItem.idx1]);\n\n                rawIndices.push(newData.getRawIndex(diffItem.idx1));\n                break;\n            case '+':\n                var idx = diffItem.idx;\n                currPoints.push(\n                    oldCoordSys.dataToPoint([\n                        newData.get(newDataOldCoordInfo.dataDimsForPoint[0], idx),\n                        newData.get(newDataOldCoordInfo.dataDimsForPoint[1], idx)\n                    ])\n                );\n\n                nextPoints.push(newData.getItemLayout(idx).slice());\n\n                currStackedPoints.push(\n                    getStackedOnPoint(newDataOldCoordInfo, oldCoordSys, newData, idx)\n                );\n                nextStackedPoints.push(newStackedOnPoints[idx]);\n\n                rawIndices.push(newData.getRawIndex(idx));\n                break;\n            case '-':\n                var idx = diffItem.idx;\n                var rawIndex = oldData.getRawIndex(idx);\n                // Data is replaced. In the case of dynamic data queue\n                // FIXME FIXME FIXME\n                if (rawIndex !== idx) {\n                    currPoints.push(oldData.getItemLayout(idx));\n                    nextPoints.push(newCoordSys.dataToPoint([\n                        oldData.get(oldDataNewCoordInfo.dataDimsForPoint[0], idx),\n                        oldData.get(oldDataNewCoordInfo.dataDimsForPoint[1], idx)\n                    ]));\n\n                    currStackedPoints.push(oldStackedOnPoints[idx]);\n                    nextStackedPoints.push(\n                        getStackedOnPoint(oldDataNewCoordInfo, newCoordSys, oldData, idx)\n                    );\n\n                    rawIndices.push(rawIndex);\n                }\n                else {\n                    pointAdded = false;\n                }\n        }\n\n        // Original indices\n        if (pointAdded) {\n            status.push(diffItem);\n            sortedIndices.push(sortedIndices.length);\n        }\n    }\n\n    // Diff result may be crossed if all items are changed\n    // Sort by data index\n    sortedIndices.sort(function (a, b) {\n        return rawIndices[a] - rawIndices[b];\n    });\n\n    var sortedCurrPoints = [];\n    var sortedNextPoints = [];\n\n    var sortedCurrStackedPoints = [];\n    var sortedNextStackedPoints = [];\n\n    var sortedStatus = [];\n    for (var i = 0; i < sortedIndices.length; i++) {\n        var idx = sortedIndices[i];\n        sortedCurrPoints[i] = currPoints[idx];\n        sortedNextPoints[i] = nextPoints[idx];\n\n        sortedCurrStackedPoints[i] = currStackedPoints[idx];\n        sortedNextStackedPoints[i] = nextStackedPoints[idx];\n\n        sortedStatus[i] = status[idx];\n    }\n\n    return {\n        current: sortedCurrPoints,\n        next: sortedNextPoints,\n\n        stackedOnCurrent: sortedCurrStackedPoints,\n        stackedOnNext: sortedNextStackedPoints,\n\n        status: sortedStatus\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Poly path support NaN point\n\nvar vec2Min = min;\nvar vec2Max = max;\n\nvar scaleAndAdd$1 = scaleAndAdd;\nvar v2Copy = copy;\n\n// Temporary variable\nvar v = [];\nvar cp0 = [];\nvar cp1 = [];\n\nfunction isPointNull(p) {\n    return isNaN(p[0]) || isNaN(p[1]);\n}\n\nfunction drawSegment(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    // if (smoothMonotone == null) {\n    //     if (isMono(points, 'x')) {\n    //         return drawMono(ctx, points, start, segLen, allLen,\n    //             dir, smoothMin, smoothMax, smooth, 'x', connectNulls);\n    //     }\n    //     else if (isMono(points, 'y')) {\n    //         return drawMono(ctx, points, start, segLen, allLen,\n    //             dir, smoothMin, smoothMax, smooth, 'y', connectNulls);\n    //     }\n    //     else {\n    //         return drawNonMono.apply(this, arguments);\n    //     }\n    // }\n    // else if (smoothMonotone !== 'none' && isMono(points, smoothMonotone)) {\n    //     return drawMono.apply(this, arguments);\n    // }\n    // else {\n    //     return drawNonMono.apply(this, arguments);\n    // }\n    if (smoothMonotone === 'none' || !smoothMonotone) {\n        return drawNonMono.apply(this, arguments);\n    }\n    else {\n        return drawMono.apply(this, arguments);\n    }\n}\n\n/**\n * Check if points is in monotone.\n *\n * @param {number[][]} points         Array of points which is in [x, y] form\n * @param {string}     smoothMonotone 'x', 'y', or 'none', stating for which\n *                                    dimension that is checking.\n *                                    If is 'none', `drawNonMono` should be\n *                                    called.\n *                                    If is undefined, either being monotone\n *                                    in 'x' or 'y' will call `drawMono`.\n */\n// function isMono(points, smoothMonotone) {\n//     if (points.length <= 1) {\n//         return true;\n//     }\n\n//     var dim = smoothMonotone === 'x' ? 0 : 1;\n//     var last = points[0][dim];\n//     var lastDiff = 0;\n//     for (var i = 1; i < points.length; ++i) {\n//         var diff = points[i][dim] - last;\n//         if (!isNaN(diff) && !isNaN(lastDiff)\n//             && diff !== 0 && lastDiff !== 0\n//             && ((diff >= 0) !== (lastDiff >= 0))\n//         ) {\n//             return false;\n//         }\n//         if (!isNaN(diff) && diff !== 0) {\n//             lastDiff = diff;\n//             last = points[i][dim];\n//         }\n//     }\n//     return true;\n// }\n\n/**\n * Draw smoothed line in monotone, in which only vertical or horizontal bezier\n * control points will be used. This should be used when points are monotone\n * either in x or y dimension.\n */\nfunction drawMono(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    var prevIdx = 0;\n    var idx = start;\n    for (var k = 0; k < segLen; k++) {\n        var p = points[idx];\n        if (idx >= allLen || idx < 0) {\n            break;\n        }\n        if (isPointNull(p)) {\n            if (connectNulls) {\n                idx += dir;\n                continue;\n            }\n            break;\n        }\n\n        if (idx === start) {\n            ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);\n        }\n        else {\n            if (smooth > 0) {\n                var prevP = points[prevIdx];\n                var dim = smoothMonotone === 'y' ? 1 : 0;\n\n                // Length of control point to p, either in x or y, but not both\n                var ctrlLen = (p[dim] - prevP[dim]) * smooth;\n\n                v2Copy(cp0, prevP);\n                cp0[dim] = prevP[dim] + ctrlLen;\n\n                v2Copy(cp1, p);\n                cp1[dim] = p[dim] - ctrlLen;\n\n                ctx.bezierCurveTo(\n                    cp0[0], cp0[1],\n                    cp1[0], cp1[1],\n                    p[0], p[1]\n                );\n            }\n            else {\n                ctx.lineTo(p[0], p[1]);\n            }\n        }\n\n        prevIdx = idx;\n        idx += dir;\n    }\n\n    return k;\n}\n\n/**\n * Draw smoothed line in non-monotone, in may cause undesired curve in extreme\n * situations. This should be used when points are non-monotone neither in x or\n * y dimension.\n */\nfunction drawNonMono(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    var prevIdx = 0;\n    var idx = start;\n    for (var k = 0; k < segLen; k++) {\n        var p = points[idx];\n        if (idx >= allLen || idx < 0) {\n            break;\n        }\n        if (isPointNull(p)) {\n            if (connectNulls) {\n                idx += dir;\n                continue;\n            }\n            break;\n        }\n\n        if (idx === start) {\n            ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);\n            v2Copy(cp0, p);\n        }\n        else {\n            if (smooth > 0) {\n                var nextIdx = idx + dir;\n                var nextP = points[nextIdx];\n                if (connectNulls) {\n                    // Find next point not null\n                    while (nextP && isPointNull(points[nextIdx])) {\n                        nextIdx += dir;\n                        nextP = points[nextIdx];\n                    }\n                }\n\n                var ratioNextSeg = 0.5;\n                var prevP = points[prevIdx];\n                var nextP = points[nextIdx];\n                // Last point\n                if (!nextP || isPointNull(nextP)) {\n                    v2Copy(cp1, p);\n                }\n                else {\n                    // If next data is null in not connect case\n                    if (isPointNull(nextP) && !connectNulls) {\n                        nextP = p;\n                    }\n\n                    sub(v, nextP, prevP);\n\n                    var lenPrevSeg;\n                    var lenNextSeg;\n                    if (smoothMonotone === 'x' || smoothMonotone === 'y') {\n                        var dim = smoothMonotone === 'x' ? 0 : 1;\n                        lenPrevSeg = Math.abs(p[dim] - prevP[dim]);\n                        lenNextSeg = Math.abs(p[dim] - nextP[dim]);\n                    }\n                    else {\n                        lenPrevSeg = dist(p, prevP);\n                        lenNextSeg = dist(p, nextP);\n                    }\n\n                    // Use ratio of seg length\n                    ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg);\n\n                    scaleAndAdd$1(cp1, p, v, -smooth * (1 - ratioNextSeg));\n                }\n                // Smooth constraint\n                vec2Min(cp0, cp0, smoothMax);\n                vec2Max(cp0, cp0, smoothMin);\n                vec2Min(cp1, cp1, smoothMax);\n                vec2Max(cp1, cp1, smoothMin);\n\n                ctx.bezierCurveTo(\n                    cp0[0], cp0[1],\n                    cp1[0], cp1[1],\n                    p[0], p[1]\n                );\n                // cp0 of next segment\n                scaleAndAdd$1(cp0, p, v, smooth * ratioNextSeg);\n            }\n            else {\n                ctx.lineTo(p[0], p[1]);\n            }\n        }\n\n        prevIdx = idx;\n        idx += dir;\n    }\n\n    return k;\n}\n\nfunction getBoundingBox(points, smoothConstraint) {\n    var ptMin = [Infinity, Infinity];\n    var ptMax = [-Infinity, -Infinity];\n    if (smoothConstraint) {\n        for (var i = 0; i < points.length; i++) {\n            var pt = points[i];\n            if (pt[0] < ptMin[0]) {\n                ptMin[0] = pt[0];\n            }\n            if (pt[1] < ptMin[1]) {\n                ptMin[1] = pt[1];\n            }\n            if (pt[0] > ptMax[0]) {\n                ptMax[0] = pt[0];\n            }\n            if (pt[1] > ptMax[1]) {\n                ptMax[1] = pt[1];\n            }\n        }\n    }\n    return {\n        min: smoothConstraint ? ptMin : ptMax,\n        max: smoothConstraint ? ptMax : ptMin\n    };\n}\n\nvar Polyline$1 = Path.extend({\n\n    type: 'ec-polyline',\n\n    shape: {\n        points: [],\n\n        smooth: 0,\n\n        smoothConstraint: true,\n\n        smoothMonotone: null,\n\n        connectNulls: false\n    },\n\n    style: {\n        fill: null,\n\n        stroke: '#000'\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n        var points = shape.points;\n\n        var i = 0;\n        var len$$1 = points.length;\n\n        var result = getBoundingBox(points, shape.smoothConstraint);\n\n        if (shape.connectNulls) {\n            // Must remove first and last null values avoid draw error in polygon\n            for (; len$$1 > 0; len$$1--) {\n                if (!isPointNull(points[len$$1 - 1])) {\n                    break;\n                }\n            }\n            for (; i < len$$1; i++) {\n                if (!isPointNull(points[i])) {\n                    break;\n                }\n            }\n        }\n        while (i < len$$1) {\n            i += drawSegment(\n                ctx, points, i, len$$1, len$$1,\n                1, result.min, result.max, shape.smooth,\n                shape.smoothMonotone, shape.connectNulls\n            ) + 1;\n        }\n    }\n});\n\nvar Polygon$1 = Path.extend({\n\n    type: 'ec-polygon',\n\n    shape: {\n        points: [],\n\n        // Offset between stacked base points and points\n        stackedOnPoints: [],\n\n        smooth: 0,\n\n        stackedOnSmooth: 0,\n\n        smoothConstraint: true,\n\n        smoothMonotone: null,\n\n        connectNulls: false\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n        var points = shape.points;\n        var stackedOnPoints = shape.stackedOnPoints;\n\n        var i = 0;\n        var len$$1 = points.length;\n        var smoothMonotone = shape.smoothMonotone;\n        var bbox = getBoundingBox(points, shape.smoothConstraint);\n        var stackedOnBBox = getBoundingBox(stackedOnPoints, shape.smoothConstraint);\n\n        if (shape.connectNulls) {\n            // Must remove first and last null values avoid draw error in polygon\n            for (; len$$1 > 0; len$$1--) {\n                if (!isPointNull(points[len$$1 - 1])) {\n                    break;\n                }\n            }\n            for (; i < len$$1; i++) {\n                if (!isPointNull(points[i])) {\n                    break;\n                }\n            }\n        }\n        while (i < len$$1) {\n            var k = drawSegment(\n                ctx, points, i, len$$1, len$$1,\n                1, bbox.min, bbox.max, shape.smooth,\n                smoothMonotone, shape.connectNulls\n            );\n            drawSegment(\n                ctx, stackedOnPoints, i + k - 1, k, len$$1,\n                -1, stackedOnBBox.min, stackedOnBBox.max, shape.stackedOnSmooth,\n                smoothMonotone, shape.connectNulls\n            );\n            i += k + 1;\n\n            ctx.closePath();\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME step not support polar\n\nfunction isPointsSame(points1, points2) {\n    if (points1.length !== points2.length) {\n        return;\n    }\n    for (var i = 0; i < points1.length; i++) {\n        var p1 = points1[i];\n        var p2 = points2[i];\n        if (p1[0] !== p2[0] || p1[1] !== p2[1]) {\n            return;\n        }\n    }\n    return true;\n}\n\nfunction getSmooth(smooth) {\n    return typeof (smooth) === 'number' ? smooth : (smooth ? 0.5 : 0);\n}\n\nfunction getAxisExtentWithGap(axis) {\n    var extent = axis.getGlobalExtent();\n    if (axis.onBand) {\n        // Remove extra 1px to avoid line miter in clipped edge\n        var halfBandWidth = axis.getBandWidth() / 2 - 1;\n        var dir = extent[1] > extent[0] ? 1 : -1;\n        extent[0] += dir * halfBandWidth;\n        extent[1] -= dir * halfBandWidth;\n    }\n    return extent;\n}\n\n/**\n * @param {module:echarts/coord/cartesian/Cartesian2D|module:echarts/coord/polar/Polar} coordSys\n * @param {module:echarts/data/List} data\n * @param {Object} dataCoordInfo\n * @param {Array.<Array.<number>>} points\n */\nfunction getStackedOnPoints(coordSys, data, dataCoordInfo) {\n    if (!dataCoordInfo.valueDim) {\n        return [];\n    }\n\n    var points = [];\n    for (var idx = 0, len = data.count(); idx < len; idx++) {\n        points.push(getStackedOnPoint(dataCoordInfo, coordSys, data, idx));\n    }\n\n    return points;\n}\n\nfunction createGridClipShape(cartesian, hasAnimation, forSymbol, seriesModel) {\n    var xExtent = getAxisExtentWithGap(cartesian.getAxis('x'));\n    var yExtent = getAxisExtentWithGap(cartesian.getAxis('y'));\n    var isHorizontal = cartesian.getBaseAxis().isHorizontal();\n\n    var x = Math.min(xExtent[0], xExtent[1]);\n    var y = Math.min(yExtent[0], yExtent[1]);\n    var width = Math.max(xExtent[0], xExtent[1]) - x;\n    var height = Math.max(yExtent[0], yExtent[1]) - y;\n\n    // Avoid float number rounding error for symbol on the edge of axis extent.\n    // See #7913 and `test/dataZoom-clip.html`.\n    if (forSymbol) {\n        x -= 0.5;\n        width += 0.5;\n        y -= 0.5;\n        height += 0.5;\n    }\n    else {\n        var lineWidth = seriesModel.get('lineStyle.width') || 2;\n        // Expand clip shape to avoid clipping when line value exceeds axis\n        var expandSize = seriesModel.get('clipOverflow') ? lineWidth / 2 : Math.max(width, height);\n        if (isHorizontal) {\n            y -= expandSize;\n            height += expandSize * 2;\n        }\n        else {\n            x -= expandSize;\n            width += expandSize * 2;\n        }\n    }\n\n    var clipPath = new Rect({\n        shape: {\n            x: x,\n            y: y,\n            width: width,\n            height: height\n        }\n    });\n\n    if (hasAnimation) {\n        clipPath.shape[isHorizontal ? 'width' : 'height'] = 0;\n        initProps(clipPath, {\n            shape: {\n                width: width,\n                height: height\n            }\n        }, seriesModel);\n    }\n\n    return clipPath;\n}\n\nfunction createPolarClipShape(polar, hasAnimation, forSymbol, seriesModel) {\n    var angleAxis = polar.getAngleAxis();\n    var radiusAxis = polar.getRadiusAxis();\n\n    var radiusExtent = radiusAxis.getExtent().slice();\n    radiusExtent[0] > radiusExtent[1] && radiusExtent.reverse();\n    var angleExtent = angleAxis.getExtent();\n\n    var RADIAN = Math.PI / 180;\n\n    // Avoid float number rounding error for symbol on the edge of axis extent.\n    if (forSymbol) {\n        radiusExtent[0] -= 0.5;\n        radiusExtent[1] += 0.5;\n    }\n\n    var clipPath = new Sector({\n        shape: {\n            cx: round$2(polar.cx, 1),\n            cy: round$2(polar.cy, 1),\n            r0: round$2(radiusExtent[0], 1),\n            r: round$2(radiusExtent[1], 1),\n            startAngle: -angleExtent[0] * RADIAN,\n            endAngle: -angleExtent[1] * RADIAN,\n            clockwise: angleAxis.inverse\n        }\n    });\n\n    if (hasAnimation) {\n        clipPath.shape.endAngle = -angleExtent[0] * RADIAN;\n        initProps(clipPath, {\n            shape: {\n                endAngle: -angleExtent[1] * RADIAN\n            }\n        }, seriesModel);\n    }\n\n    return clipPath;\n}\n\nfunction createClipShape(coordSys, hasAnimation, forSymbol, seriesModel) {\n    return coordSys.type === 'polar'\n        ? createPolarClipShape(coordSys, hasAnimation, forSymbol, seriesModel)\n        : createGridClipShape(coordSys, hasAnimation, forSymbol, seriesModel);\n}\n\nfunction turnPointsIntoStep(points, coordSys, stepTurnAt) {\n    var baseAxis = coordSys.getBaseAxis();\n    var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1;\n\n    var stepPoints = [];\n    for (var i = 0; i < points.length - 1; i++) {\n        var nextPt = points[i + 1];\n        var pt = points[i];\n        stepPoints.push(pt);\n\n        var stepPt = [];\n        switch (stepTurnAt) {\n            case 'end':\n                stepPt[baseIndex] = nextPt[baseIndex];\n                stepPt[1 - baseIndex] = pt[1 - baseIndex];\n                // default is start\n                stepPoints.push(stepPt);\n                break;\n            case 'middle':\n                // default is start\n                var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2;\n                var stepPt2 = [];\n                stepPt[baseIndex] = stepPt2[baseIndex] = middle;\n                stepPt[1 - baseIndex] = pt[1 - baseIndex];\n                stepPt2[1 - baseIndex] = nextPt[1 - baseIndex];\n                stepPoints.push(stepPt);\n                stepPoints.push(stepPt2);\n                break;\n            default:\n                stepPt[baseIndex] = pt[baseIndex];\n                stepPt[1 - baseIndex] = nextPt[1 - baseIndex];\n                // default is start\n                stepPoints.push(stepPt);\n        }\n    }\n    // Last points\n    points[i] && stepPoints.push(points[i]);\n    return stepPoints;\n}\n\nfunction getVisualGradient(data, coordSys) {\n    var visualMetaList = data.getVisual('visualMeta');\n    if (!visualMetaList || !visualMetaList.length || !data.count()) {\n        // When data.count() is 0, gradient range can not be calculated.\n        return;\n    }\n\n    if (coordSys.type !== 'cartesian2d') {\n        if (__DEV__) {\n            console.warn('Visual map on line style is only supported on cartesian2d.');\n        }\n        return;\n    }\n\n    var coordDim;\n    var visualMeta;\n\n    for (var i = visualMetaList.length - 1; i >= 0; i--) {\n        var dimIndex = visualMetaList[i].dimension;\n        var dimName = data.dimensions[dimIndex];\n        var dimInfo = data.getDimensionInfo(dimName);\n        coordDim = dimInfo && dimInfo.coordDim;\n        // Can only be x or y\n        if (coordDim === 'x' || coordDim === 'y') {\n            visualMeta = visualMetaList[i];\n            break;\n        }\n    }\n\n    if (!visualMeta) {\n        if (__DEV__) {\n            console.warn('Visual map on line style only support x or y dimension.');\n        }\n        return;\n    }\n\n    // If the area to be rendered is bigger than area defined by LinearGradient,\n    // the canvas spec prescribes that the color of the first stop and the last\n    // stop should be used. But if two stops are added at offset 0, in effect\n    // browsers use the color of the second stop to render area outside\n    // LinearGradient. So we can only infinitesimally extend area defined in\n    // LinearGradient to render `outerColors`.\n\n    var axis = coordSys.getAxis(coordDim);\n\n    // dataToCoor mapping may not be linear, but must be monotonic.\n    var colorStops = map(visualMeta.stops, function (stop) {\n        return {\n            coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)),\n            color: stop.color\n        };\n    });\n    var stopLen = colorStops.length;\n    var outerColors = visualMeta.outerColors.slice();\n\n    if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) {\n        colorStops.reverse();\n        outerColors.reverse();\n    }\n\n    var tinyExtent = 10; // Arbitrary value: 10px\n    var minCoord = colorStops[0].coord - tinyExtent;\n    var maxCoord = colorStops[stopLen - 1].coord + tinyExtent;\n    var coordSpan = maxCoord - minCoord;\n\n    if (coordSpan < 1e-3) {\n        return 'transparent';\n    }\n\n    each$1(colorStops, function (stop) {\n        stop.offset = (stop.coord - minCoord) / coordSpan;\n    });\n    colorStops.push({\n        offset: stopLen ? colorStops[stopLen - 1].offset : 0.5,\n        color: outerColors[1] || 'transparent'\n    });\n    colorStops.unshift({ // notice colorStops.length have been changed.\n        offset: stopLen ? colorStops[0].offset : 0.5,\n        color: outerColors[0] || 'transparent'\n    });\n\n    // zrUtil.each(colorStops, function (colorStop) {\n    //     // Make sure each offset has rounded px to avoid not sharp edge\n    //     colorStop.offset = (Math.round(colorStop.offset * (end - start) + start) - start) / (end - start);\n    // });\n\n    var gradient = new LinearGradient(0, 0, 0, 0, colorStops, true);\n    gradient[coordDim] = minCoord;\n    gradient[coordDim + '2'] = maxCoord;\n\n    return gradient;\n}\n\nfunction getIsIgnoreFunc(seriesModel, data, coordSys) {\n    var showAllSymbol = seriesModel.get('showAllSymbol');\n    var isAuto = showAllSymbol === 'auto';\n\n    if (showAllSymbol && !isAuto) {\n        return;\n    }\n\n    var categoryAxis = coordSys.getAxesByScale('ordinal')[0];\n    if (!categoryAxis) {\n        return;\n    }\n\n    // Note that category label interval strategy might bring some weird effect\n    // in some scenario: users may wonder why some of the symbols are not\n    // displayed. So we show all symbols as possible as we can.\n    if (isAuto\n        // Simplify the logic, do not determine label overlap here.\n        && canShowAllSymbolForCategory(categoryAxis, data)\n    ) {\n        return;\n    }\n\n    // Otherwise follow the label interval strategy on category axis.\n    var categoryDataDim = data.mapDimension(categoryAxis.dim);\n    var labelMap = {};\n\n    each$1(categoryAxis.getViewLabels(), function (labelItem) {\n        labelMap[labelItem.tickValue] = 1;\n    });\n\n    return function (dataIndex) {\n        return !labelMap.hasOwnProperty(data.get(categoryDataDim, dataIndex));\n    };\n}\n\nfunction canShowAllSymbolForCategory(categoryAxis, data) {\n    // In mose cases, line is monotonous on category axis, and the label size\n    // is close with each other. So we check the symbol size and some of the\n    // label size alone with the category axis to estimate whether all symbol\n    // can be shown without overlap.\n    var axisExtent = categoryAxis.getExtent();\n    var availSize = Math.abs(axisExtent[1] - axisExtent[0]) / categoryAxis.scale.count();\n    isNaN(availSize) && (availSize = 0); // 0/0 is NaN.\n\n    // Sampling some points, max 5.\n    var dataLen = data.count();\n    var step = Math.max(1, Math.round(dataLen / 5));\n    for (var dataIndex = 0; dataIndex < dataLen; dataIndex += step) {\n        if (SymbolClz$1.getSymbolSize(\n                data, dataIndex\n            // Only for cartesian, where `isHorizontal` exists.\n            )[categoryAxis.isHorizontal() ? 1 : 0]\n            // Empirical number\n            * 1.5 > availSize\n        ) {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nChart.extend({\n\n    type: 'line',\n\n    init: function () {\n        var lineGroup = new Group();\n\n        var symbolDraw = new SymbolDraw();\n        this.group.add(symbolDraw.group);\n\n        this._symbolDraw = symbolDraw;\n        this._lineGroup = lineGroup;\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var group = this.group;\n        var data = seriesModel.getData();\n        var lineStyleModel = seriesModel.getModel('lineStyle');\n        var areaStyleModel = seriesModel.getModel('areaStyle');\n\n        var points = data.mapArray(data.getItemLayout);\n\n        var isCoordSysPolar = coordSys.type === 'polar';\n        var prevCoordSys = this._coordSys;\n\n        var symbolDraw = this._symbolDraw;\n        var polyline = this._polyline;\n        var polygon = this._polygon;\n\n        var lineGroup = this._lineGroup;\n\n        var hasAnimation = seriesModel.get('animation');\n\n        var isAreaChart = !areaStyleModel.isEmpty();\n\n        var valueOrigin = areaStyleModel.get('origin');\n        var dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin);\n\n        var stackedOnPoints = getStackedOnPoints(coordSys, data, dataCoordInfo);\n\n        var showSymbol = seriesModel.get('showSymbol');\n\n        var isIgnoreFunc = showSymbol && !isCoordSysPolar\n            && getIsIgnoreFunc(seriesModel, data, coordSys);\n\n        // Remove temporary symbols\n        var oldData = this._data;\n        oldData && oldData.eachItemGraphicEl(function (el, idx) {\n            if (el.__temp) {\n                group.remove(el);\n                oldData.setItemGraphicEl(idx, null);\n            }\n        });\n\n        // Remove previous created symbols if showSymbol changed to false\n        if (!showSymbol) {\n            symbolDraw.remove();\n        }\n\n        group.add(lineGroup);\n\n        // FIXME step not support polar\n        var step = !isCoordSysPolar && seriesModel.get('step');\n        // Initialization animation or coordinate system changed\n        if (\n            !(polyline && prevCoordSys.type === coordSys.type && step === this._step)\n        ) {\n            showSymbol && symbolDraw.updateData(data, {\n                isIgnore: isIgnoreFunc,\n                clipShape: createClipShape(coordSys, false, true, seriesModel)\n            });\n\n            if (step) {\n                // TODO If stacked series is not step\n                points = turnPointsIntoStep(points, coordSys, step);\n                stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);\n            }\n\n            polyline = this._newPolyline(points, coordSys, hasAnimation);\n            if (isAreaChart) {\n                polygon = this._newPolygon(\n                    points, stackedOnPoints,\n                    coordSys, hasAnimation\n                );\n            }\n            lineGroup.setClipPath(createClipShape(coordSys, true, false, seriesModel));\n        }\n        else {\n            if (isAreaChart && !polygon) {\n                // If areaStyle is added\n                polygon = this._newPolygon(\n                    points, stackedOnPoints,\n                    coordSys, hasAnimation\n                );\n            }\n            else if (polygon && !isAreaChart) {\n                // If areaStyle is removed\n                lineGroup.remove(polygon);\n                polygon = this._polygon = null;\n            }\n\n            // Update clipPath\n            lineGroup.setClipPath(createClipShape(coordSys, false, false, seriesModel));\n\n            // Always update, or it is wrong in the case turning on legend\n            // because points are not changed\n            showSymbol && symbolDraw.updateData(data, {\n                isIgnore: isIgnoreFunc,\n                clipShape: createClipShape(coordSys, false, true, seriesModel)\n            });\n\n            // Stop symbol animation and sync with line points\n            // FIXME performance?\n            data.eachItemGraphicEl(function (el) {\n                el.stopAnimation(true);\n            });\n\n            // In the case data zoom triggerred refreshing frequently\n            // Data may not change if line has a category axis. So it should animate nothing\n            if (!isPointsSame(this._stackedOnPoints, stackedOnPoints)\n                || !isPointsSame(this._points, points)\n            ) {\n                if (hasAnimation) {\n                    this._updateAnimation(\n                        data, stackedOnPoints, coordSys, api, step, valueOrigin\n                    );\n                }\n                else {\n                    // Not do it in update with animation\n                    if (step) {\n                        // TODO If stacked series is not step\n                        points = turnPointsIntoStep(points, coordSys, step);\n                        stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);\n                    }\n\n                    polyline.setShape({\n                        points: points\n                    });\n                    polygon && polygon.setShape({\n                        points: points,\n                        stackedOnPoints: stackedOnPoints\n                    });\n                }\n            }\n        }\n\n        var visualColor = getVisualGradient(data, coordSys) || data.getVisual('color');\n\n        polyline.useStyle(defaults(\n            // Use color in lineStyle first\n            lineStyleModel.getLineStyle(),\n            {\n                fill: 'none',\n                stroke: visualColor,\n                lineJoin: 'bevel'\n            }\n        ));\n\n        var smooth = seriesModel.get('smooth');\n        smooth = getSmooth(seriesModel.get('smooth'));\n        polyline.setShape({\n            smooth: smooth,\n            smoothMonotone: seriesModel.get('smoothMonotone'),\n            connectNulls: seriesModel.get('connectNulls')\n        });\n\n        if (polygon) {\n            var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');\n            var stackedOnSmooth = 0;\n\n            polygon.useStyle(defaults(\n                areaStyleModel.getAreaStyle(),\n                {\n                    fill: visualColor,\n                    opacity: 0.7,\n                    lineJoin: 'bevel'\n                }\n            ));\n\n            if (stackedOnSeries) {\n                stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth'));\n            }\n\n            polygon.setShape({\n                smooth: smooth,\n                stackedOnSmooth: stackedOnSmooth,\n                smoothMonotone: seriesModel.get('smoothMonotone'),\n                connectNulls: seriesModel.get('connectNulls')\n            });\n        }\n\n        this._data = data;\n        // Save the coordinate system for transition animation when data changed\n        this._coordSys = coordSys;\n        this._stackedOnPoints = stackedOnPoints;\n        this._points = points;\n        this._step = step;\n        this._valueOrigin = valueOrigin;\n    },\n\n    dispose: function () {},\n\n    highlight: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n        var dataIndex = queryDataIndex(data, payload);\n\n        if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) {\n            var symbol = data.getItemGraphicEl(dataIndex);\n            if (!symbol) {\n                // Create a temporary symbol if it is not exists\n                var pt = data.getItemLayout(dataIndex);\n                if (!pt) {\n                    // Null data\n                    return;\n                }\n                symbol = new SymbolClz$1(data, dataIndex);\n                symbol.position = pt;\n                symbol.setZ(\n                    seriesModel.get('zlevel'),\n                    seriesModel.get('z')\n                );\n                symbol.ignore = isNaN(pt[0]) || isNaN(pt[1]);\n                symbol.__temp = true;\n                data.setItemGraphicEl(dataIndex, symbol);\n\n                // Stop scale animation\n                symbol.stopSymbolAnimation(true);\n\n                this.group.add(symbol);\n            }\n            symbol.highlight();\n        }\n        else {\n            // Highlight whole series\n            Chart.prototype.highlight.call(\n                this, seriesModel, ecModel, api, payload\n            );\n        }\n    },\n\n    downplay: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n        var dataIndex = queryDataIndex(data, payload);\n        if (dataIndex != null && dataIndex >= 0) {\n            var symbol = data.getItemGraphicEl(dataIndex);\n            if (symbol) {\n                if (symbol.__temp) {\n                    data.setItemGraphicEl(dataIndex, null);\n                    this.group.remove(symbol);\n                }\n                else {\n                    symbol.downplay();\n                }\n            }\n        }\n        else {\n            // FIXME\n            // can not downplay completely.\n            // Downplay whole series\n            Chart.prototype.downplay.call(\n                this, seriesModel, ecModel, api, payload\n            );\n        }\n    },\n\n    /**\n     * @param {module:zrender/container/Group} group\n     * @param {Array.<Array.<number>>} points\n     * @private\n     */\n    _newPolyline: function (points) {\n        var polyline = this._polyline;\n        // Remove previous created polyline\n        if (polyline) {\n            this._lineGroup.remove(polyline);\n        }\n\n        polyline = new Polyline$1({\n            shape: {\n                points: points\n            },\n            silent: true,\n            z2: 10\n        });\n\n        this._lineGroup.add(polyline);\n\n        this._polyline = polyline;\n\n        return polyline;\n    },\n\n    /**\n     * @param {module:zrender/container/Group} group\n     * @param {Array.<Array.<number>>} stackedOnPoints\n     * @param {Array.<Array.<number>>} points\n     * @private\n     */\n    _newPolygon: function (points, stackedOnPoints) {\n        var polygon = this._polygon;\n        // Remove previous created polygon\n        if (polygon) {\n            this._lineGroup.remove(polygon);\n        }\n\n        polygon = new Polygon$1({\n            shape: {\n                points: points,\n                stackedOnPoints: stackedOnPoints\n            },\n            silent: true\n        });\n\n        this._lineGroup.add(polygon);\n\n        this._polygon = polygon;\n        return polygon;\n    },\n\n    /**\n     * @private\n     */\n    // FIXME Two value axis\n    _updateAnimation: function (data, stackedOnPoints, coordSys, api, step, valueOrigin) {\n        var polyline = this._polyline;\n        var polygon = this._polygon;\n        var seriesModel = data.hostModel;\n\n        var diff = lineAnimationDiff(\n            this._data, data,\n            this._stackedOnPoints, stackedOnPoints,\n            this._coordSys, coordSys,\n            this._valueOrigin, valueOrigin\n        );\n\n        var current = diff.current;\n        var stackedOnCurrent = diff.stackedOnCurrent;\n        var next = diff.next;\n        var stackedOnNext = diff.stackedOnNext;\n        if (step) {\n            // TODO If stacked series is not step\n            current = turnPointsIntoStep(diff.current, coordSys, step);\n            stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step);\n            next = turnPointsIntoStep(diff.next, coordSys, step);\n            stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step);\n        }\n        // `diff.current` is subset of `current` (which should be ensured by\n        // turnPointsIntoStep), so points in `__points` can be updated when\n        // points in `current` are update during animation.\n        polyline.shape.__points = diff.current;\n        polyline.shape.points = current;\n\n        updateProps(polyline, {\n            shape: {\n                points: next\n            }\n        }, seriesModel);\n\n        if (polygon) {\n            polygon.setShape({\n                points: current,\n                stackedOnPoints: stackedOnCurrent\n            });\n            updateProps(polygon, {\n                shape: {\n                    points: next,\n                    stackedOnPoints: stackedOnNext\n                }\n            }, seriesModel);\n        }\n\n        var updatedDataInfo = [];\n        var diffStatus = diff.status;\n\n        for (var i = 0; i < diffStatus.length; i++) {\n            var cmd = diffStatus[i].cmd;\n            if (cmd === '=') {\n                var el = data.getItemGraphicEl(diffStatus[i].idx1);\n                if (el) {\n                    updatedDataInfo.push({\n                        el: el,\n                        ptIdx: i    // Index of points\n                    });\n                }\n            }\n        }\n\n        if (polyline.animators && polyline.animators.length) {\n            polyline.animators[0].during(function () {\n                for (var i = 0; i < updatedDataInfo.length; i++) {\n                    var el = updatedDataInfo[i].el;\n                    el.attr('position', polyline.shape.__points[updatedDataInfo[i].ptIdx]);\n                }\n            });\n        }\n    },\n\n    remove: function (ecModel) {\n        var group = this.group;\n        var oldData = this._data;\n        this._lineGroup.removeAll();\n        this._symbolDraw.remove(true);\n        // Remove temporary created elements when highlighting\n        oldData && oldData.eachItemGraphicEl(function (el, idx) {\n            if (el.__temp) {\n                group.remove(el);\n                oldData.setItemGraphicEl(idx, null);\n            }\n        });\n\n        this._polyline\n            = this._polygon\n            = this._coordSys\n            = this._points\n            = this._stackedOnPoints\n            = this._data = null;\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar visualSymbol = function (seriesType, defaultSymbolType, legendSymbol) {\n    // Encoding visual for all series include which is filtered for legend drawing\n    return {\n        seriesType: seriesType,\n\n        // For legend.\n        performRawSeries: true,\n\n        reset: function (seriesModel, ecModel, api) {\n            var data = seriesModel.getData();\n\n            var symbolType = seriesModel.get('symbol') || defaultSymbolType;\n            var symbolSize = seriesModel.get('symbolSize');\n            var keepAspect = seriesModel.get('symbolKeepAspect');\n\n            data.setVisual({\n                legendSymbol: legendSymbol || symbolType,\n                symbol: symbolType,\n                symbolSize: symbolSize,\n                symbolKeepAspect: keepAspect\n            });\n\n            // Only visible series has each data be visual encoded\n            if (ecModel.isSeriesFiltered(seriesModel)) {\n                return;\n            }\n\n            var hasCallback = typeof symbolSize === 'function';\n\n            function dataEach(data, idx) {\n                if (typeof symbolSize === 'function') {\n                    var rawValue = seriesModel.getRawValue(idx);\n                    // FIXME\n                    var params = seriesModel.getDataParams(idx);\n                    data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params));\n                }\n\n                if (data.hasItemOption) {\n                    var itemModel = data.getItemModel(idx);\n                    var itemSymbolType = itemModel.getShallow('symbol', true);\n                    var itemSymbolSize = itemModel.getShallow('symbolSize',\n                        true);\n                    var itemSymbolKeepAspect\n                        = itemModel.getShallow('symbolKeepAspect', true);\n\n                    // If has item symbol\n                    if (itemSymbolType != null) {\n                        data.setItemVisual(idx, 'symbol', itemSymbolType);\n                    }\n                    if (itemSymbolSize != null) {\n                        // PENDING Transform symbolSize ?\n                        data.setItemVisual(idx, 'symbolSize', itemSymbolSize);\n                    }\n                    if (itemSymbolKeepAspect != null) {\n                        data.setItemVisual(idx, 'symbolKeepAspect',\n                            itemSymbolKeepAspect);\n                    }\n                }\n            }\n\n            return { dataEach: (data.hasItemOption || hasCallback) ? dataEach : null };\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar pointsLayout = function (seriesType) {\n    return {\n        seriesType: seriesType,\n\n        plan: createRenderPlanner(),\n\n        reset: function (seriesModel) {\n            var data = seriesModel.getData();\n            var coordSys = seriesModel.coordinateSystem;\n            var pipelineContext = seriesModel.pipelineContext;\n            var isLargeRender = pipelineContext.large;\n\n            if (!coordSys) {\n                return;\n            }\n\n            var dims = map(coordSys.dimensions, function (dim) {\n                return data.mapDimension(dim);\n            }).slice(0, 2);\n            var dimLen = dims.length;\n\n            var stackResultDim = data.getCalculationInfo('stackResultDimension');\n            if (isDimensionStacked(data, dims[0] /*, dims[1]*/)) {\n                dims[0] = stackResultDim;\n            }\n            if (isDimensionStacked(data, dims[1] /*, dims[0]*/)) {\n                dims[1] = stackResultDim;\n            }\n\n            function progress(params, data) {\n                var segCount = params.end - params.start;\n                var points = isLargeRender && new Float32Array(segCount * dimLen);\n\n                for (var i = params.start, offset = 0, tmpIn = [], tmpOut = []; i < params.end; i++) {\n                    var point;\n\n                    if (dimLen === 1) {\n                        var x = data.get(dims[0], i);\n                        point = !isNaN(x) && coordSys.dataToPoint(x, null, tmpOut);\n                    }\n                    else {\n                        var x = tmpIn[0] = data.get(dims[0], i);\n                        var y = tmpIn[1] = data.get(dims[1], i);\n                        // Also {Array.<number>}, not undefined to avoid if...else... statement\n                        point = !isNaN(x) && !isNaN(y) && coordSys.dataToPoint(tmpIn, null, tmpOut);\n                    }\n\n                    if (isLargeRender) {\n                        points[offset++] = point ? point[0] : NaN;\n                        points[offset++] = point ? point[1] : NaN;\n                    }\n                    else {\n                        data.setItemLayout(i, (point && point.slice()) || [NaN, NaN]);\n                    }\n                }\n\n                isLargeRender && data.setLayout('symbolPoints', points);\n            }\n\n            return dimLen && {progress: progress};\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar samplers = {\n    average: function (frame) {\n        var sum = 0;\n        var count = 0;\n        for (var i = 0; i < frame.length; i++) {\n            if (!isNaN(frame[i])) {\n                sum += frame[i];\n                count++;\n            }\n        }\n        // Return NaN if count is 0\n        return count === 0 ? NaN : sum / count;\n    },\n    sum: function (frame) {\n        var sum = 0;\n        for (var i = 0; i < frame.length; i++) {\n            // Ignore NaN\n            sum += frame[i] || 0;\n        }\n        return sum;\n    },\n    max: function (frame) {\n        var max = -Infinity;\n        for (var i = 0; i < frame.length; i++) {\n            frame[i] > max && (max = frame[i]);\n        }\n        // NaN will cause illegal axis extent.\n        return isFinite(max) ? max : NaN;\n    },\n    min: function (frame) {\n        var min = Infinity;\n        for (var i = 0; i < frame.length; i++) {\n            frame[i] < min && (min = frame[i]);\n        }\n        // NaN will cause illegal axis extent.\n        return isFinite(min) ? min : NaN;\n    },\n    // TODO\n    // Median\n    nearest: function (frame) {\n        return frame[0];\n    }\n};\n\nvar indexSampler = function (frame, value) {\n    return Math.round(frame.length / 2);\n};\n\nvar dataSample = function (seriesType) {\n    return {\n\n        seriesType: seriesType,\n\n        modifyOutputEnd: true,\n\n        reset: function (seriesModel, ecModel, api) {\n            var data = seriesModel.getData();\n            var sampling = seriesModel.get('sampling');\n            var coordSys = seriesModel.coordinateSystem;\n            // Only cartesian2d support down sampling\n            if (coordSys.type === 'cartesian2d' && sampling) {\n                var baseAxis = coordSys.getBaseAxis();\n                var valueAxis = coordSys.getOtherAxis(baseAxis);\n                var extent = baseAxis.getExtent();\n                // Coordinste system has been resized\n                var size = extent[1] - extent[0];\n                var rate = Math.round(data.count() / size);\n                if (rate > 1) {\n                    var sampler;\n                    if (typeof sampling === 'string') {\n                        sampler = samplers[sampling];\n                    }\n                    else if (typeof sampling === 'function') {\n                        sampler = sampling;\n                    }\n                    if (sampler) {\n                        // Only support sample the first dim mapped from value axis.\n                        seriesModel.setData(data.downSample(\n                            data.mapDimension(valueAxis.dim), 1 / rate, sampler, indexSampler\n                        ));\n                    }\n                }\n            }\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Cartesian coordinate system\n * @module  echarts/coord/Cartesian\n *\n */\n\nfunction dimAxisMapper(dim) {\n    return this._axes[dim];\n}\n\n/**\n * @alias module:echarts/coord/Cartesian\n * @constructor\n */\nvar Cartesian = function (name) {\n    this._axes = {};\n\n    this._dimList = [];\n\n    /**\n     * @type {string}\n     */\n    this.name = name || '';\n};\n\nCartesian.prototype = {\n\n    constructor: Cartesian,\n\n    type: 'cartesian',\n\n    /**\n     * Get axis\n     * @param  {number|string} dim\n     * @return {module:echarts/coord/Cartesian~Axis}\n     */\n    getAxis: function (dim) {\n        return this._axes[dim];\n    },\n\n    /**\n     * Get axes list\n     * @return {Array.<module:echarts/coord/Cartesian~Axis>}\n     */\n    getAxes: function () {\n        return map(this._dimList, dimAxisMapper, this);\n    },\n\n    /**\n     * Get axes list by given scale type\n     */\n    getAxesByScale: function (scaleType) {\n        scaleType = scaleType.toLowerCase();\n        return filter(\n            this.getAxes(),\n            function (axis) {\n                return axis.scale.type === scaleType;\n            }\n        );\n    },\n\n    /**\n     * Add axis\n     * @param {module:echarts/coord/Cartesian.Axis}\n     */\n    addAxis: function (axis) {\n        var dim = axis.dim;\n\n        this._axes[dim] = axis;\n\n        this._dimList.push(dim);\n    },\n\n    /**\n     * Convert data to coord in nd space\n     * @param {Array.<number>|Object.<string, number>} val\n     * @return {Array.<number>|Object.<string, number>}\n     */\n    dataToCoord: function (val) {\n        return this._dataCoordConvert(val, 'dataToCoord');\n    },\n\n    /**\n     * Convert coord in nd space to data\n     * @param  {Array.<number>|Object.<string, number>} val\n     * @return {Array.<number>|Object.<string, number>}\n     */\n    coordToData: function (val) {\n        return this._dataCoordConvert(val, 'coordToData');\n    },\n\n    _dataCoordConvert: function (input, method) {\n        var dimList = this._dimList;\n\n        var output = input instanceof Array ? [] : {};\n\n        for (var i = 0; i < dimList.length; i++) {\n            var dim = dimList[i];\n            var axis = this._axes[dim];\n\n            output[dim] = axis[method](input[dim]);\n        }\n\n        return output;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction Cartesian2D(name) {\n\n    Cartesian.call(this, name);\n}\n\nCartesian2D.prototype = {\n\n    constructor: Cartesian2D,\n\n    type: 'cartesian2d',\n\n    /**\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['x', 'y'],\n\n    /**\n     * Base axis will be used on stacking.\n     *\n     * @return {module:echarts/coord/cartesian/Axis2D}\n     */\n    getBaseAxis: function () {\n        return this.getAxesByScale('ordinal')[0]\n            || this.getAxesByScale('time')[0]\n            || this.getAxis('x');\n    },\n\n    /**\n     * If contain point\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    containPoint: function (point) {\n        var axisX = this.getAxis('x');\n        var axisY = this.getAxis('y');\n        return axisX.contain(axisX.toLocalCoord(point[0]))\n            && axisY.contain(axisY.toLocalCoord(point[1]));\n    },\n\n    /**\n     * If contain data\n     * @param {Array.<number>} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this.getAxis('x').containData(data[0])\n            && this.getAxis('y').containData(data[1]);\n    },\n\n    /**\n     * @param {Array.<number>} data\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, reserved, out) {\n        var xAxis = this.getAxis('x');\n        var yAxis = this.getAxis('y');\n        out = out || [];\n        out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(data[0]));\n        out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(data[1]));\n        return out;\n    },\n\n    /**\n     * @param {Array.<number>} data\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    clampData: function (data, out) {\n        var xScale = this.getAxis('x').scale;\n        var yScale = this.getAxis('y').scale;\n        var xAxisExtent = xScale.getExtent();\n        var yAxisExtent = yScale.getExtent();\n        var x = xScale.parse(data[0]);\n        var y = yScale.parse(data[1]);\n        out = out || [];\n        out[0] = Math.min(\n            Math.max(Math.min(xAxisExtent[0], xAxisExtent[1]), x),\n            Math.max(xAxisExtent[0], xAxisExtent[1])\n        );\n        out[1] = Math.min(\n            Math.max(Math.min(yAxisExtent[0], yAxisExtent[1]), y),\n            Math.max(yAxisExtent[0], yAxisExtent[1])\n        );\n\n        return out;\n    },\n\n    /**\n     * @param {Array.<number>} point\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    pointToData: function (point, out) {\n        var xAxis = this.getAxis('x');\n        var yAxis = this.getAxis('y');\n        out = out || [];\n        out[0] = xAxis.coordToData(xAxis.toLocalCoord(point[0]));\n        out[1] = yAxis.coordToData(yAxis.toLocalCoord(point[1]));\n        return out;\n    },\n\n    /**\n     * Get other axis\n     * @param {module:echarts/coord/cartesian/Axis2D} axis\n     */\n    getOtherAxis: function (axis) {\n        return this.getAxis(axis.dim === 'x' ? 'y' : 'x');\n    }\n\n};\n\ninherits(Cartesian2D, Cartesian);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Extend axis 2d\n * @constructor module:echarts/coord/cartesian/Axis2D\n * @extends {module:echarts/coord/cartesian/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n * @param {string} position\n */\nvar Axis2D = function (dim, scale, coordExtent, axisType, position) {\n    Axis.call(this, dim, scale, coordExtent);\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * Axis position\n     *  - 'top'\n     *  - 'bottom'\n     *  - 'left'\n     *  - 'right'\n     */\n    this.position = position || 'bottom';\n};\n\nAxis2D.prototype = {\n\n    constructor: Axis2D,\n\n    /**\n     * Index of axis, can be used as key\n     */\n    index: 0,\n\n    /**\n     * Implemented in <module:echarts/coord/cartesian/Grid>.\n     * @return {Array.<module:echarts/coord/cartesian/Axis2D>}\n     *         If not on zero of other axis, return null/undefined.\n     *         If no axes, return an empty array.\n     */\n    getAxesOnZeroOf: null,\n\n    /**\n     * Axis model\n     * @param {module:echarts/coord/cartesian/AxisModel}\n     */\n    model: null,\n\n    isHorizontal: function () {\n        var position = this.position;\n        return position === 'top' || position === 'bottom';\n    },\n\n    /**\n     * Each item cooresponds to this.getExtent(), which\n     * means globalExtent[0] may greater than globalExtent[1],\n     * unless `asc` is input.\n     *\n     * @param {boolean} [asc]\n     * @return {Array.<number>}\n     */\n    getGlobalExtent: function (asc) {\n        var ret = this.getExtent();\n        ret[0] = this.toGlobalCoord(ret[0]);\n        ret[1] = this.toGlobalCoord(ret[1]);\n        asc && ret[0] > ret[1] && ret.reverse();\n        return ret;\n    },\n\n    getOtherAxis: function () {\n        this.grid.getOtherAxis();\n    },\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.coordToData(this.toLocalCoord(point[this.dim === 'x' ? 0 : 1]), clamp);\n    },\n\n    /**\n     * Transform global coord to local coord,\n     * i.e. var localCoord = axis.toLocalCoord(80);\n     * designate by module:echarts/coord/cartesian/Grid.\n     * @type {Function}\n     */\n    toLocalCoord: null,\n\n    /**\n     * Transform global coord to local coord,\n     * i.e. var globalCoord = axis.toLocalCoord(40);\n     * designate by module:echarts/coord/cartesian/Grid.\n     * @type {Function}\n     */\n    toGlobalCoord: null\n\n};\n\ninherits(Axis2D, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar defaultOption = {\n    show: true,\n    zlevel: 0,\n    z: 0,\n    // Inverse the axis.\n    inverse: false,\n\n    // Axis name displayed.\n    name: '',\n    // 'start' | 'middle' | 'end'\n    nameLocation: 'end',\n    // By degree. By defualt auto rotate by nameLocation.\n    nameRotate: null,\n    nameTruncate: {\n        maxWidth: null,\n        ellipsis: '...',\n        placeholder: '.'\n    },\n    // Use global text style by default.\n    nameTextStyle: {},\n    // The gap between axisName and axisLine.\n    nameGap: 15,\n\n    // Default `false` to support tooltip.\n    silent: false,\n    // Default `false` to avoid legacy user event listener fail.\n    triggerEvent: false,\n\n    tooltip: {\n        show: false\n    },\n\n    axisPointer: {},\n\n    axisLine: {\n        show: true,\n        onZero: true,\n        onZeroAxisIndex: null,\n        lineStyle: {\n            color: '#333',\n            width: 1,\n            type: 'solid'\n        },\n        // The arrow at both ends the the axis.\n        symbol: ['none', 'none'],\n        symbolSize: [10, 15]\n    },\n    axisTick: {\n        show: true,\n        // Whether axisTick is inside the grid or outside the grid.\n        inside: false,\n        // The length of axisTick.\n        length: 5,\n        lineStyle: {\n            width: 1\n        }\n    },\n    axisLabel: {\n        show: true,\n        // Whether axisLabel is inside the grid or outside the grid.\n        inside: false,\n        rotate: 0,\n        // true | false | null/undefined (auto)\n        showMinLabel: null,\n        // true | false | null/undefined (auto)\n        showMaxLabel: null,\n        margin: 8,\n        // formatter: null,\n        fontSize: 12\n    },\n    splitLine: {\n        show: true,\n        lineStyle: {\n            color: ['#ccc'],\n            width: 1,\n            type: 'solid'\n        }\n    },\n    splitArea: {\n        show: false,\n        areaStyle: {\n            color: ['rgba(250,250,250,0.3)', 'rgba(200,200,200,0.3)']\n        }\n    }\n};\n\nvar axisDefault = {};\n\naxisDefault.categoryAxis = merge({\n    // The gap at both ends of the axis. For categoryAxis, boolean.\n    boundaryGap: true,\n    // Set false to faster category collection.\n    // Only usefull in the case like: category is\n    // ['2012-01-01', '2012-01-02', ...], where the input\n    // data has been ensured not duplicate and is large data.\n    // null means \"auto\":\n    // if axis.data provided, do not deduplication,\n    // else do deduplication.\n    deduplication: null,\n    // splitArea: {\n        // show: false\n    // },\n    splitLine: {\n        show: false\n    },\n    axisTick: {\n        // If tick is align with label when boundaryGap is true\n        alignWithLabel: false,\n        interval: 'auto'\n    },\n    axisLabel: {\n        interval: 'auto'\n    }\n}, defaultOption);\n\naxisDefault.valueAxis = merge({\n    // The gap at both ends of the axis. For value axis, [GAP, GAP], where\n    // `GAP` can be an absolute pixel number (like `35`), or percent (like `'30%'`)\n    boundaryGap: [0, 0],\n\n    // TODO\n    // min/max: [30, datamin, 60] or [20, datamin] or [datamin, 60]\n\n    // Min value of the axis. can be:\n    // + a number\n    // + 'dataMin': use the min value in data.\n    // + null/undefined: auto decide min value (consider pretty look and boundaryGap).\n    // min: null,\n\n    // Max value of the axis. can be:\n    // + a number\n    // + 'dataMax': use the max value in data.\n    // + null/undefined: auto decide max value (consider pretty look and boundaryGap).\n    // max: null,\n\n    // Readonly prop, specifies start value of the range when using data zoom.\n    // rangeStart: null\n\n    // Readonly prop, specifies end value of the range when using data zoom.\n    // rangeEnd: null\n\n    // Optional value can be:\n    // + `false`: always include value 0.\n    // + `true`: the extent do not consider value 0.\n    // scale: false,\n\n    // AxisTick and axisLabel and splitLine are caculated based on splitNumber.\n    splitNumber: 5\n\n    // Interval specifies the span of the ticks is mandatorily.\n    // interval: null\n\n    // Specify min interval when auto calculate tick interval.\n    // minInterval: null\n\n    // Specify max interval when auto calculate tick interval.\n    // maxInterval: null\n\n}, defaultOption);\n\naxisDefault.timeAxis = defaults({\n    scale: true,\n    min: 'dataMin',\n    max: 'dataMax'\n}, axisDefault.valueAxis);\n\naxisDefault.logAxis = defaults({\n    scale: true,\n    logBase: 10\n}, axisDefault.valueAxis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME axisType is fixed ?\nvar AXIS_TYPES = ['value', 'category', 'time', 'log'];\n\n/**\n * Generate sub axis model class\n * @param {string} axisName 'x' 'y' 'radius' 'angle' 'parallel'\n * @param {module:echarts/model/Component} BaseAxisModelClass\n * @param {Function} axisTypeDefaulter\n * @param {Object} [extraDefaultOption]\n */\nvar axisModelCreator = function (axisName, BaseAxisModelClass, axisTypeDefaulter, extraDefaultOption) {\n\n    each$1(AXIS_TYPES, function (axisType) {\n\n        BaseAxisModelClass.extend({\n\n            /**\n             * @readOnly\n             */\n            type: axisName + 'Axis.' + axisType,\n\n            mergeDefaultAndTheme: function (option, ecModel) {\n                var layoutMode = this.layoutMode;\n                var inputPositionParams = layoutMode\n                    ? getLayoutParams(option) : {};\n\n                var themeModel = ecModel.getTheme();\n                merge(option, themeModel.get(axisType + 'Axis'));\n                merge(option, this.getDefaultOption());\n\n                option.type = axisTypeDefaulter(axisName, option);\n\n                if (layoutMode) {\n                    mergeLayoutParam(option, inputPositionParams, layoutMode);\n                }\n            },\n\n            /**\n             * @override\n             */\n            optionUpdated: function () {\n                var thisOption = this.option;\n                if (thisOption.type === 'category') {\n                    this.__ordinalMeta = OrdinalMeta.createByAxisModel(this);\n                }\n            },\n\n            /**\n             * Should not be called before all of 'getInitailData' finished.\n             * Because categories are collected during initializing data.\n             */\n            getCategories: function (rawData) {\n                var option = this.option;\n                // FIXME\n                // warning if called before all of 'getInitailData' finished.\n                if (option.type === 'category') {\n                    if (rawData) {\n                        return option.data;\n                    }\n                    return this.__ordinalMeta.categories;\n                }\n            },\n\n            getOrdinalMeta: function () {\n                return this.__ordinalMeta;\n            },\n\n            defaultOption: mergeAll(\n                [\n                    {},\n                    axisDefault[axisType + 'Axis'],\n                    extraDefaultOption\n                ],\n                true\n            )\n        });\n    });\n\n    ComponentModel.registerSubTypeDefaulter(\n        axisName + 'Axis',\n        curry(axisTypeDefaulter, axisName)\n    );\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisModel = ComponentModel.extend({\n\n    type: 'cartesian2dAxis',\n\n    /**\n     * @type {module:echarts/coord/cartesian/Axis2D}\n     */\n    axis: null,\n\n    /**\n     * @override\n     */\n    init: function () {\n        AxisModel.superApply(this, 'init', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function () {\n        AxisModel.superApply(this, 'mergeOption', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     */\n    restoreData: function () {\n        AxisModel.superApply(this, 'restoreData', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     * @return {module:echarts/model/Component}\n     */\n    getCoordSysModel: function () {\n        return this.ecModel.queryComponents({\n            mainType: 'grid',\n            index: this.option.gridIndex,\n            id: this.option.gridId\n        })[0];\n    }\n\n});\n\nfunction getAxisType(axisDim, option) {\n    // Default axis with data is category axis\n    return option.type || (option.data ? 'category' : 'value');\n}\n\nmerge(AxisModel.prototype, axisModelCommonMixin);\n\nvar extraOption = {\n    // gridIndex: 0,\n    // gridId: '',\n\n    // Offset is for multiple axis on the same position\n    offset: 0\n};\n\naxisModelCreator('x', AxisModel, getAxisType, extraOption);\naxisModelCreator('y', AxisModel, getAxisType, extraOption);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Grid 是在有直角坐标系的时候必须要存在的\n// 所以这里也要被 Cartesian2D 依赖\n\nComponentModel.extend({\n\n    type: 'grid',\n\n    dependencies: ['xAxis', 'yAxis'],\n\n    layoutMode: 'box',\n\n    /**\n     * @type {module:echarts/coord/cartesian/Grid}\n     */\n    coordinateSystem: null,\n\n    defaultOption: {\n        show: false,\n        zlevel: 0,\n        z: 0,\n        left: '10%',\n        top: 60,\n        right: '10%',\n        bottom: 60,\n        // If grid size contain label\n        containLabel: false,\n        // width: {totalWidth} - left - right,\n        // height: {totalHeight} - top - bottom,\n        backgroundColor: 'rgba(0,0,0,0)',\n        borderWidth: 1,\n        borderColor: '#ccc'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Grid is a region which contains at most 4 cartesian systems\n *\n * TODO Default cartesian\n */\n\n// Depends on GridModel, AxisModel, which performs preprocess.\n/**\n * Check if the axis is used in the specified grid\n * @inner\n */\nfunction isAxisUsedInTheGrid(axisModel, gridModel, ecModel) {\n    return axisModel.getCoordSysModel() === gridModel;\n}\n\nfunction Grid(gridModel, ecModel, api) {\n    /**\n     * @type {Object.<string, module:echarts/coord/cartesian/Cartesian2D>}\n     * @private\n     */\n    this._coordsMap = {};\n\n    /**\n     * @type {Array.<module:echarts/coord/cartesian/Cartesian>}\n     * @private\n     */\n    this._coordsList = [];\n\n    /**\n     * @type {Object.<string, module:echarts/coord/cartesian/Axis2D>}\n     * @private\n     */\n    this._axesMap = {};\n\n    /**\n     * @type {Array.<module:echarts/coord/cartesian/Axis2D>}\n     * @private\n     */\n    this._axesList = [];\n\n    this._initCartesian(gridModel, ecModel, api);\n\n    this.model = gridModel;\n}\n\nvar gridProto = Grid.prototype;\n\ngridProto.type = 'grid';\n\ngridProto.axisPointerEnabled = true;\n\ngridProto.getRect = function () {\n    return this._rect;\n};\n\ngridProto.update = function (ecModel, api) {\n\n    var axesMap = this._axesMap;\n\n    this._updateScale(ecModel, this.model);\n\n    each$1(axesMap.x, function (xAxis) {\n        niceScaleExtent(xAxis.scale, xAxis.model);\n    });\n    each$1(axesMap.y, function (yAxis) {\n        niceScaleExtent(yAxis.scale, yAxis.model);\n    });\n\n    // Key: axisDim_axisIndex, value: boolean, whether onZero target.\n    var onZeroRecords = {};\n\n    each$1(axesMap.x, function (xAxis) {\n        fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords);\n    });\n    each$1(axesMap.y, function (yAxis) {\n        fixAxisOnZero(axesMap, 'x', yAxis, onZeroRecords);\n    });\n\n    // Resize again if containLabel is enabled\n    // FIXME It may cause getting wrong grid size in data processing stage\n    this.resize(this.model, api);\n};\n\nfunction fixAxisOnZero(axesMap, otherAxisDim, axis, onZeroRecords) {\n\n    axis.getAxesOnZeroOf = function () {\n        // TODO: onZero of multiple axes.\n        return otherAxisOnZeroOf ? [otherAxisOnZeroOf] : [];\n    };\n\n    // onZero can not be enabled in these two situations:\n    // 1. When any other axis is a category axis.\n    // 2. When no axis is cross 0 point.\n    var otherAxes = axesMap[otherAxisDim];\n\n    var otherAxisOnZeroOf;\n    var axisModel = axis.model;\n    var onZero = axisModel.get('axisLine.onZero');\n    var onZeroAxisIndex = axisModel.get('axisLine.onZeroAxisIndex');\n\n    if (!onZero) {\n        return;\n    }\n\n    // If target axis is specified.\n    if (onZeroAxisIndex != null) {\n        if (canOnZeroToAxis(otherAxes[onZeroAxisIndex])) {\n            otherAxisOnZeroOf = otherAxes[onZeroAxisIndex];\n        }\n    }\n    else {\n        // Find the first available other axis.\n        for (var idx in otherAxes) {\n            if (otherAxes.hasOwnProperty(idx)\n                && canOnZeroToAxis(otherAxes[idx])\n                // Consider that two Y axes on one value axis,\n                // if both onZero, the two Y axes overlap.\n                && !onZeroRecords[getOnZeroRecordKey(otherAxes[idx])]\n            ) {\n                otherAxisOnZeroOf = otherAxes[idx];\n                break;\n            }\n        }\n    }\n\n    if (otherAxisOnZeroOf) {\n        onZeroRecords[getOnZeroRecordKey(otherAxisOnZeroOf)] = true;\n    }\n\n    function getOnZeroRecordKey(axis) {\n        return axis.dim + '_' + axis.index;\n    }\n}\n\nfunction canOnZeroToAxis(axis) {\n    return axis && axis.type !== 'category' && axis.type !== 'time' && ifAxisCrossZero(axis);\n}\n\n/**\n * Resize the grid\n * @param {module:echarts/coord/cartesian/GridModel} gridModel\n * @param {module:echarts/ExtensionAPI} api\n */\ngridProto.resize = function (gridModel, api, ignoreContainLabel) {\n\n    var gridRect = getLayoutRect(\n        gridModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        });\n\n    this._rect = gridRect;\n\n    var axesList = this._axesList;\n\n    adjustAxes();\n\n    // Minus label size\n    if (!ignoreContainLabel && gridModel.get('containLabel')) {\n        each$1(axesList, function (axis) {\n            if (!axis.model.get('axisLabel.inside')) {\n                var labelUnionRect = estimateLabelUnionRect(axis);\n                if (labelUnionRect) {\n                    var dim = axis.isHorizontal() ? 'height' : 'width';\n                    var margin = axis.model.get('axisLabel.margin');\n                    gridRect[dim] -= labelUnionRect[dim] + margin;\n                    if (axis.position === 'top') {\n                        gridRect.y += labelUnionRect.height + margin;\n                    }\n                    else if (axis.position === 'left') {\n                        gridRect.x += labelUnionRect.width + margin;\n                    }\n                }\n            }\n        });\n\n        adjustAxes();\n    }\n\n    function adjustAxes() {\n        each$1(axesList, function (axis) {\n            var isHorizontal = axis.isHorizontal();\n            var extent = isHorizontal ? [0, gridRect.width] : [0, gridRect.height];\n            var idx = axis.inverse ? 1 : 0;\n            axis.setExtent(extent[idx], extent[1 - idx]);\n            updateAxisTransform(axis, isHorizontal ? gridRect.x : gridRect.y);\n        });\n    }\n};\n\n/**\n * @param {string} axisType\n * @param {number} [axisIndex]\n */\ngridProto.getAxis = function (axisType, axisIndex) {\n    var axesMapOnDim = this._axesMap[axisType];\n    if (axesMapOnDim != null) {\n        if (axisIndex == null) {\n            // Find first axis\n            for (var name in axesMapOnDim) {\n                if (axesMapOnDim.hasOwnProperty(name)) {\n                    return axesMapOnDim[name];\n                }\n            }\n        }\n        return axesMapOnDim[axisIndex];\n    }\n};\n\n/**\n * @return {Array.<module:echarts/coord/Axis>}\n */\ngridProto.getAxes = function () {\n    return this._axesList.slice();\n};\n\n/**\n * Usage:\n *      grid.getCartesian(xAxisIndex, yAxisIndex);\n *      grid.getCartesian(xAxisIndex);\n *      grid.getCartesian(null, yAxisIndex);\n *      grid.getCartesian({xAxisIndex: ..., yAxisIndex: ...});\n *\n * @param {number|Object} [xAxisIndex]\n * @param {number} [yAxisIndex]\n */\ngridProto.getCartesian = function (xAxisIndex, yAxisIndex) {\n    if (xAxisIndex != null && yAxisIndex != null) {\n        var key = 'x' + xAxisIndex + 'y' + yAxisIndex;\n        return this._coordsMap[key];\n    }\n\n    if (isObject$1(xAxisIndex)) {\n        yAxisIndex = xAxisIndex.yAxisIndex;\n        xAxisIndex = xAxisIndex.xAxisIndex;\n    }\n    // When only xAxisIndex or yAxisIndex given, find its first cartesian.\n    for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) {\n        if (coordList[i].getAxis('x').index === xAxisIndex\n            || coordList[i].getAxis('y').index === yAxisIndex\n        ) {\n            return coordList[i];\n        }\n    }\n};\n\ngridProto.getCartesians = function () {\n    return this._coordsList.slice();\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.convertToPixel = function (ecModel, finder, value) {\n    var target = this._findConvertTarget(ecModel, finder);\n\n    return target.cartesian\n        ? target.cartesian.dataToPoint(value)\n        : target.axis\n        ? target.axis.toGlobalCoord(target.axis.dataToCoord(value))\n        : null;\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.convertFromPixel = function (ecModel, finder, value) {\n    var target = this._findConvertTarget(ecModel, finder);\n\n    return target.cartesian\n        ? target.cartesian.pointToData(value)\n        : target.axis\n        ? target.axis.coordToData(target.axis.toLocalCoord(value))\n        : null;\n};\n\n/**\n * @inner\n */\ngridProto._findConvertTarget = function (ecModel, finder) {\n    var seriesModel = finder.seriesModel;\n    var xAxisModel = finder.xAxisModel\n        || (seriesModel && seriesModel.getReferringComponents('xAxis')[0]);\n    var yAxisModel = finder.yAxisModel\n        || (seriesModel && seriesModel.getReferringComponents('yAxis')[0]);\n    var gridModel = finder.gridModel;\n    var coordsList = this._coordsList;\n    var cartesian;\n    var axis;\n\n    if (seriesModel) {\n        cartesian = seriesModel.coordinateSystem;\n        indexOf(coordsList, cartesian) < 0 && (cartesian = null);\n    }\n    else if (xAxisModel && yAxisModel) {\n        cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);\n    }\n    else if (xAxisModel) {\n        axis = this.getAxis('x', xAxisModel.componentIndex);\n    }\n    else if (yAxisModel) {\n        axis = this.getAxis('y', yAxisModel.componentIndex);\n    }\n    // Lowest priority.\n    else if (gridModel) {\n        var grid = gridModel.coordinateSystem;\n        if (grid === this) {\n            cartesian = this._coordsList[0];\n        }\n    }\n\n    return {cartesian: cartesian, axis: axis};\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.containPoint = function (point) {\n    var coord = this._coordsList[0];\n    if (coord) {\n        return coord.containPoint(point);\n    }\n};\n\n/**\n * Initialize cartesian coordinate systems\n * @private\n */\ngridProto._initCartesian = function (gridModel, ecModel, api) {\n    var axisPositionUsed = {\n        left: false,\n        right: false,\n        top: false,\n        bottom: false\n    };\n\n    var axesMap = {\n        x: {},\n        y: {}\n    };\n    var axesCount = {\n        x: 0,\n        y: 0\n    };\n\n    /// Create axis\n    ecModel.eachComponent('xAxis', createAxisCreator('x'), this);\n    ecModel.eachComponent('yAxis', createAxisCreator('y'), this);\n\n    if (!axesCount.x || !axesCount.y) {\n        // Roll back when there no either x or y axis\n        this._axesMap = {};\n        this._axesList = [];\n        return;\n    }\n\n    this._axesMap = axesMap;\n\n    /// Create cartesian2d\n    each$1(axesMap.x, function (xAxis, xAxisIndex) {\n        each$1(axesMap.y, function (yAxis, yAxisIndex) {\n            var key = 'x' + xAxisIndex + 'y' + yAxisIndex;\n            var cartesian = new Cartesian2D(key);\n\n            cartesian.grid = this;\n            cartesian.model = gridModel;\n\n            this._coordsMap[key] = cartesian;\n            this._coordsList.push(cartesian);\n\n            cartesian.addAxis(xAxis);\n            cartesian.addAxis(yAxis);\n        }, this);\n    }, this);\n\n    function createAxisCreator(axisType) {\n        return function (axisModel, idx) {\n            if (!isAxisUsedInTheGrid(axisModel, gridModel, ecModel)) {\n                return;\n            }\n\n            var axisPosition = axisModel.get('position');\n            if (axisType === 'x') {\n                // Fix position\n                if (axisPosition !== 'top' && axisPosition !== 'bottom') {\n                    // Default bottom of X\n                    axisPosition = 'bottom';\n                    if (axisPositionUsed[axisPosition]) {\n                        axisPosition = axisPosition === 'top' ? 'bottom' : 'top';\n                    }\n                }\n            }\n            else {\n                // Fix position\n                if (axisPosition !== 'left' && axisPosition !== 'right') {\n                    // Default left of Y\n                    axisPosition = 'left';\n                    if (axisPositionUsed[axisPosition]) {\n                        axisPosition = axisPosition === 'left' ? 'right' : 'left';\n                    }\n                }\n            }\n            axisPositionUsed[axisPosition] = true;\n\n            var axis = new Axis2D(\n                axisType, createScaleByModel(axisModel),\n                [0, 0],\n                axisModel.get('type'),\n                axisPosition\n            );\n\n            var isCategory = axis.type === 'category';\n            axis.onBand = isCategory && axisModel.get('boundaryGap');\n            axis.inverse = axisModel.get('inverse');\n\n            // Inject axis into axisModel\n            axisModel.axis = axis;\n\n            // Inject axisModel into axis\n            axis.model = axisModel;\n\n            // Inject grid info axis\n            axis.grid = this;\n\n            // Index of axis, can be used as key\n            axis.index = idx;\n\n            this._axesList.push(axis);\n\n            axesMap[axisType][idx] = axis;\n            axesCount[axisType]++;\n        };\n    }\n};\n\n/**\n * Update cartesian properties from series\n * @param  {module:echarts/model/Option} option\n * @private\n */\ngridProto._updateScale = function (ecModel, gridModel) {\n    // Reset scale\n    each$1(this._axesList, function (axis) {\n        axis.scale.setExtent(Infinity, -Infinity);\n    });\n    ecModel.eachSeries(function (seriesModel) {\n        if (isCartesian2D(seriesModel)) {\n            var axesModels = findAxesModels(seriesModel, ecModel);\n            var xAxisModel = axesModels[0];\n            var yAxisModel = axesModels[1];\n\n            if (!isAxisUsedInTheGrid(xAxisModel, gridModel, ecModel)\n                || !isAxisUsedInTheGrid(yAxisModel, gridModel, ecModel)\n            ) {\n                return;\n            }\n\n            var cartesian = this.getCartesian(\n                xAxisModel.componentIndex, yAxisModel.componentIndex\n            );\n            var data = seriesModel.getData();\n            var xAxis = cartesian.getAxis('x');\n            var yAxis = cartesian.getAxis('y');\n\n            if (data.type === 'list') {\n                unionExtent(data, xAxis, seriesModel);\n                unionExtent(data, yAxis, seriesModel);\n            }\n        }\n    }, this);\n\n    function unionExtent(data, axis, seriesModel) {\n        each$1(data.mapDimension(axis.dim, true), function (dim) {\n            axis.scale.unionExtentFromData(\n                // For example, the extent of the orginal dimension\n                // is [0.1, 0.5], the extent of the `stackResultDimension`\n                // is [7, 9], the final extent should not include [0.1, 0.5].\n                data, getStackedDimension(data, dim)\n            );\n        });\n    }\n};\n\n/**\n * @param {string} [dim] 'x' or 'y' or 'auto' or null/undefined\n * @return {Object} {baseAxes: [], otherAxes: []}\n */\ngridProto.getTooltipAxes = function (dim) {\n    var baseAxes = [];\n    var otherAxes = [];\n\n    each$1(this.getCartesians(), function (cartesian) {\n        var baseAxis = (dim != null && dim !== 'auto')\n            ? cartesian.getAxis(dim) : cartesian.getBaseAxis();\n        var otherAxis = cartesian.getOtherAxis(baseAxis);\n        indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis);\n        indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis);\n    });\n\n    return {baseAxes: baseAxes, otherAxes: otherAxes};\n};\n\n/**\n * @inner\n */\nfunction updateAxisTransform(axis, coordBase) {\n    var axisExtent = axis.getExtent();\n    var axisExtentSum = axisExtent[0] + axisExtent[1];\n\n    // Fast transform\n    axis.toGlobalCoord = axis.dim === 'x'\n        ? function (coord) {\n            return coord + coordBase;\n        }\n        : function (coord) {\n            return axisExtentSum - coord + coordBase;\n        };\n    axis.toLocalCoord = axis.dim === 'x'\n        ? function (coord) {\n            return coord - coordBase;\n        }\n        : function (coord) {\n            return axisExtentSum - coord + coordBase;\n        };\n}\n\nvar axesTypes = ['xAxis', 'yAxis'];\n/**\n * @inner\n */\nfunction findAxesModels(seriesModel, ecModel) {\n    return map(axesTypes, function (axisType) {\n        var axisModel = seriesModel.getReferringComponents(axisType)[0];\n\n        if (__DEV__) {\n            if (!axisModel) {\n                throw new Error(axisType + ' \"' + retrieve(\n                    seriesModel.get(axisType + 'Index'),\n                    seriesModel.get(axisType + 'Id'),\n                    0\n                ) + '\" not found');\n            }\n        }\n        return axisModel;\n    });\n}\n\n/**\n * @inner\n */\nfunction isCartesian2D(seriesModel) {\n    return seriesModel.get('coordinateSystem') === 'cartesian2d';\n}\n\nGrid.create = function (ecModel, api) {\n    var grids = [];\n    ecModel.eachComponent('grid', function (gridModel, idx) {\n        var grid = new Grid(gridModel, ecModel, api);\n        grid.name = 'grid_' + idx;\n        // dataSampling requires axis extent, so resize\n        // should be performed in create stage.\n        grid.resize(gridModel, api, true);\n\n        gridModel.coordinateSystem = grid;\n\n        grids.push(grid);\n    });\n\n    // Inject the coordinateSystems into seriesModel\n    ecModel.eachSeries(function (seriesModel) {\n        if (!isCartesian2D(seriesModel)) {\n            return;\n        }\n\n        var axesModels = findAxesModels(seriesModel, ecModel);\n        var xAxisModel = axesModels[0];\n        var yAxisModel = axesModels[1];\n\n        var gridModel = xAxisModel.getCoordSysModel();\n\n        if (__DEV__) {\n            if (!gridModel) {\n                throw new Error(\n                    'Grid \"' + retrieve(\n                        xAxisModel.get('gridIndex'),\n                        xAxisModel.get('gridId'),\n                        0\n                    ) + '\" not found'\n                );\n            }\n            if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) {\n                throw new Error('xAxis and yAxis must use the same grid');\n            }\n        }\n\n        var grid = gridModel.coordinateSystem;\n\n        seriesModel.coordinateSystem = grid.getCartesian(\n            xAxisModel.componentIndex, yAxisModel.componentIndex\n        );\n    });\n\n    return grids;\n};\n\n// For deciding which dimensions to use when creating list data\nGrid.dimensions = Grid.prototype.dimensions = Cartesian2D.prototype.dimensions;\n\nCoordinateSystemManager.register('cartesian2d', Grid);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PI$2 = Math.PI;\n\nfunction makeAxisEventDataBase(axisModel) {\n    var eventData = {\n        componentType: axisModel.mainType,\n        componentIndex: axisModel.componentIndex\n    };\n    eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex;\n    return eventData;\n}\n\n/**\n * A final axis is translated and rotated from a \"standard axis\".\n * So opt.position and opt.rotation is required.\n *\n * A standard axis is and axis from [0, 0] to [0, axisExtent[1]],\n * for example: (0, 0) ------------> (0, 50)\n *\n * nameDirection or tickDirection or labelDirection is 1 means tick\n * or label is below the standard axis, whereas is -1 means above\n * the standard axis. labelOffset means offset between label and axis,\n * which is useful when 'onZero', where axisLabel is in the grid and\n * label in outside grid.\n *\n * Tips: like always,\n * positive rotation represents anticlockwise, and negative rotation\n * represents clockwise.\n * The direction of position coordinate is the same as the direction\n * of screen coordinate.\n *\n * Do not need to consider axis 'inverse', which is auto processed by\n * axis extent.\n *\n * @param {module:zrender/container/Group} group\n * @param {Object} axisModel\n * @param {Object} opt Standard axis parameters.\n * @param {Array.<number>} opt.position [x, y]\n * @param {number} opt.rotation by radian\n * @param {number} [opt.nameDirection=1] 1 or -1 Used when nameLocation is 'middle' or 'center'.\n * @param {number} [opt.tickDirection=1] 1 or -1\n * @param {number} [opt.labelDirection=1] 1 or -1\n * @param {number} [opt.labelOffset=0] Usefull when onZero.\n * @param {string} [opt.axisLabelShow] default get from axisModel.\n * @param {string} [opt.axisName] default get from axisModel.\n * @param {number} [opt.axisNameAvailableWidth]\n * @param {number} [opt.labelRotate] by degree, default get from axisModel.\n * @param {number} [opt.strokeContainThreshold] Default label interval when label\n * @param {number} [opt.nameTruncateMaxWidth]\n */\nvar AxisBuilder = function (axisModel, opt) {\n\n    /**\n     * @readOnly\n     */\n    this.opt = opt;\n\n    /**\n     * @readOnly\n     */\n    this.axisModel = axisModel;\n\n    // Default value\n    defaults(\n        opt,\n        {\n            labelOffset: 0,\n            nameDirection: 1,\n            tickDirection: 1,\n            labelDirection: 1,\n            silent: true\n        }\n    );\n\n    /**\n     * @readOnly\n     */\n    this.group = new Group();\n\n    // FIXME Not use a seperate text group?\n    var dumbGroup = new Group({\n        position: opt.position.slice(),\n        rotation: opt.rotation\n    });\n\n    // this.group.add(dumbGroup);\n    // this._dumbGroup = dumbGroup;\n\n    dumbGroup.updateTransform();\n    this._transform = dumbGroup.transform;\n\n    this._dumbGroup = dumbGroup;\n};\n\nAxisBuilder.prototype = {\n\n    constructor: AxisBuilder,\n\n    hasBuilder: function (name) {\n        return !!builders[name];\n    },\n\n    add: function (name) {\n        builders[name].call(this);\n    },\n\n    getGroup: function () {\n        return this.group;\n    }\n\n};\n\nvar builders = {\n\n    /**\n     * @private\n     */\n    axisLine: function () {\n        var opt = this.opt;\n        var axisModel = this.axisModel;\n\n        if (!axisModel.get('axisLine.show')) {\n            return;\n        }\n\n        var extent = this.axisModel.axis.getExtent();\n\n        var matrix = this._transform;\n        var pt1 = [extent[0], 0];\n        var pt2 = [extent[1], 0];\n        if (matrix) {\n            applyTransform(pt1, pt1, matrix);\n            applyTransform(pt2, pt2, matrix);\n        }\n\n        var lineStyle = extend(\n            {\n                lineCap: 'round'\n            },\n            axisModel.getModel('axisLine.lineStyle').getLineStyle()\n        );\n\n        this.group.add(new Line(subPixelOptimizeLine({\n            // Id for animation\n            anid: 'line',\n\n            shape: {\n                x1: pt1[0],\n                y1: pt1[1],\n                x2: pt2[0],\n                y2: pt2[1]\n            },\n            style: lineStyle,\n            strokeContainThreshold: opt.strokeContainThreshold || 5,\n            silent: true,\n            z2: 1\n        })));\n\n        var arrows = axisModel.get('axisLine.symbol');\n        var arrowSize = axisModel.get('axisLine.symbolSize');\n\n        var arrowOffset = axisModel.get('axisLine.symbolOffset') || 0;\n        if (typeof arrowOffset === 'number') {\n            arrowOffset = [arrowOffset, arrowOffset];\n        }\n\n        if (arrows != null) {\n            if (typeof arrows === 'string') {\n                // Use the same arrow for start and end point\n                arrows = [arrows, arrows];\n            }\n            if (typeof arrowSize === 'string'\n                || typeof arrowSize === 'number'\n            ) {\n                // Use the same size for width and height\n                arrowSize = [arrowSize, arrowSize];\n            }\n\n            var symbolWidth = arrowSize[0];\n            var symbolHeight = arrowSize[1];\n\n            each$1([{\n                rotate: opt.rotation + Math.PI / 2,\n                offset: arrowOffset[0],\n                r: 0\n            }, {\n                rotate: opt.rotation - Math.PI / 2,\n                offset: arrowOffset[1],\n                r: Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0])\n                    + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1]))\n            }], function (point, index) {\n                if (arrows[index] !== 'none' && arrows[index] != null) {\n                    var symbol = createSymbol(\n                        arrows[index],\n                        -symbolWidth / 2,\n                        -symbolHeight / 2,\n                        symbolWidth,\n                        symbolHeight,\n                        lineStyle.stroke,\n                        true\n                    );\n\n                    // Calculate arrow position with offset\n                    var r = point.r + point.offset;\n                    var pos = [\n                        pt1[0] + r * Math.cos(opt.rotation),\n                        pt1[1] - r * Math.sin(opt.rotation)\n                    ];\n\n                    symbol.attr({\n                        rotation: point.rotate,\n                        position: pos,\n                        silent: true,\n                        z2: 11\n                    });\n                    this.group.add(symbol);\n                }\n            }, this);\n        }\n    },\n\n    /**\n     * @private\n     */\n    axisTickLabel: function () {\n        var axisModel = this.axisModel;\n        var opt = this.opt;\n\n        var tickEls = buildAxisTick(this, axisModel, opt);\n        var labelEls = buildAxisLabel(this, axisModel, opt);\n\n        fixMinMaxLabelShow(axisModel, labelEls, tickEls);\n    },\n\n    /**\n     * @private\n     */\n    axisName: function () {\n        var opt = this.opt;\n        var axisModel = this.axisModel;\n        var name = retrieve(opt.axisName, axisModel.get('name'));\n\n        if (!name) {\n            return;\n        }\n\n        var nameLocation = axisModel.get('nameLocation');\n        var nameDirection = opt.nameDirection;\n        var textStyleModel = axisModel.getModel('nameTextStyle');\n        var gap = axisModel.get('nameGap') || 0;\n\n        var extent = this.axisModel.axis.getExtent();\n        var gapSignal = extent[0] > extent[1] ? -1 : 1;\n        var pos = [\n            nameLocation === 'start'\n                ? extent[0] - gapSignal * gap\n                : nameLocation === 'end'\n                ? extent[1] + gapSignal * gap\n                : (extent[0] + extent[1]) / 2, // 'middle'\n            // Reuse labelOffset.\n            isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * gap : 0\n        ];\n\n        var labelLayout;\n\n        var nameRotation = axisModel.get('nameRotate');\n        if (nameRotation != null) {\n            nameRotation = nameRotation * PI$2 / 180; // To radian.\n        }\n\n        var axisNameAvailableWidth;\n\n        if (isNameLocationCenter(nameLocation)) {\n            labelLayout = innerTextLayout(\n                opt.rotation,\n                nameRotation != null ? nameRotation : opt.rotation, // Adapt to axis.\n                nameDirection\n            );\n        }\n        else {\n            labelLayout = endTextLayout(\n                opt, nameLocation, nameRotation || 0, extent\n            );\n\n            axisNameAvailableWidth = opt.axisNameAvailableWidth;\n            if (axisNameAvailableWidth != null) {\n                axisNameAvailableWidth = Math.abs(\n                    axisNameAvailableWidth / Math.sin(labelLayout.rotation)\n                );\n                !isFinite(axisNameAvailableWidth) && (axisNameAvailableWidth = null);\n            }\n        }\n\n        var textFont = textStyleModel.getFont();\n\n        var truncateOpt = axisModel.get('nameTruncate', true) || {};\n        var ellipsis = truncateOpt.ellipsis;\n        var maxWidth = retrieve(\n            opt.nameTruncateMaxWidth, truncateOpt.maxWidth, axisNameAvailableWidth\n        );\n        // FIXME\n        // truncate rich text? (consider performance)\n        var truncatedText = (ellipsis != null && maxWidth != null)\n            ? truncateText$1(\n                name, maxWidth, textFont, ellipsis,\n                {minChar: 2, placeholder: truncateOpt.placeholder}\n            )\n            : name;\n\n        var tooltipOpt = axisModel.get('tooltip', true);\n\n        var mainType = axisModel.mainType;\n        var formatterParams = {\n            componentType: mainType,\n            name: name,\n            $vars: ['name']\n        };\n        formatterParams[mainType + 'Index'] = axisModel.componentIndex;\n\n        var textEl = new Text({\n            // Id for animation\n            anid: 'name',\n\n            __fullText: name,\n            __truncatedText: truncatedText,\n\n            position: pos,\n            rotation: labelLayout.rotation,\n            silent: isSilent(axisModel),\n            z2: 1,\n            tooltip: (tooltipOpt && tooltipOpt.show)\n                ? extend({\n                    content: name,\n                    formatter: function () {\n                        return name;\n                    },\n                    formatterParams: formatterParams\n                }, tooltipOpt)\n                : null\n        });\n\n        setTextStyle(textEl.style, textStyleModel, {\n            text: truncatedText,\n            textFont: textFont,\n            textFill: textStyleModel.getTextColor()\n                || axisModel.get('axisLine.lineStyle.color'),\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.textVerticalAlign\n        });\n\n        if (axisModel.get('triggerEvent')) {\n            textEl.eventData = makeAxisEventDataBase(axisModel);\n            textEl.eventData.targetType = 'axisName';\n            textEl.eventData.name = name;\n        }\n\n        // FIXME\n        this._dumbGroup.add(textEl);\n        textEl.updateTransform();\n\n        this.group.add(textEl);\n\n        textEl.decomposeTransform();\n    }\n\n};\n\n/**\n * @public\n * @static\n * @param {Object} opt\n * @param {number} axisRotation in radian\n * @param {number} textRotation in radian\n * @param {number} direction\n * @return {Object} {\n *  rotation, // according to axis\n *  textAlign,\n *  textVerticalAlign\n * }\n */\nvar innerTextLayout = AxisBuilder.innerTextLayout = function (axisRotation, textRotation, direction) {\n    var rotationDiff = remRadian(textRotation - axisRotation);\n    var textAlign;\n    var textVerticalAlign;\n\n    if (isRadianAroundZero(rotationDiff)) { // Label is parallel with axis line.\n        textVerticalAlign = direction > 0 ? 'top' : 'bottom';\n        textAlign = 'center';\n    }\n    else if (isRadianAroundZero(rotationDiff - PI$2)) { // Label is inverse parallel with axis line.\n        textVerticalAlign = direction > 0 ? 'bottom' : 'top';\n        textAlign = 'center';\n    }\n    else {\n        textVerticalAlign = 'middle';\n\n        if (rotationDiff > 0 && rotationDiff < PI$2) {\n            textAlign = direction > 0 ? 'right' : 'left';\n        }\n        else {\n            textAlign = direction > 0 ? 'left' : 'right';\n        }\n    }\n\n    return {\n        rotation: rotationDiff,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n};\n\nfunction endTextLayout(opt, textPosition, textRotate, extent) {\n    var rotationDiff = remRadian(textRotate - opt.rotation);\n    var textAlign;\n    var textVerticalAlign;\n    var inverse = extent[0] > extent[1];\n    var onLeft = (textPosition === 'start' && !inverse)\n        || (textPosition !== 'start' && inverse);\n\n    if (isRadianAroundZero(rotationDiff - PI$2 / 2)) {\n        textVerticalAlign = onLeft ? 'bottom' : 'top';\n        textAlign = 'center';\n    }\n    else if (isRadianAroundZero(rotationDiff - PI$2 * 1.5)) {\n        textVerticalAlign = onLeft ? 'top' : 'bottom';\n        textAlign = 'center';\n    }\n    else {\n        textVerticalAlign = 'middle';\n        if (rotationDiff < PI$2 * 1.5 && rotationDiff > PI$2 / 2) {\n            textAlign = onLeft ? 'left' : 'right';\n        }\n        else {\n            textAlign = onLeft ? 'right' : 'left';\n        }\n    }\n\n    return {\n        rotation: rotationDiff,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\nfunction isSilent(axisModel) {\n    var tooltipOpt = axisModel.get('tooltip');\n    return axisModel.get('silent')\n        // Consider mouse cursor, add these restrictions.\n        || !(\n            axisModel.get('triggerEvent') || (tooltipOpt && tooltipOpt.show)\n        );\n}\n\nfunction fixMinMaxLabelShow(axisModel, labelEls, tickEls) {\n    if (shouldShowAllLabels(axisModel.axis)) {\n        return;\n    }\n\n    // If min or max are user set, we need to check\n    // If the tick on min(max) are overlap on their neighbour tick\n    // If they are overlapped, we need to hide the min(max) tick label\n    var showMinLabel = axisModel.get('axisLabel.showMinLabel');\n    var showMaxLabel = axisModel.get('axisLabel.showMaxLabel');\n\n    // FIXME\n    // Have not consider onBand yet, where tick els is more than label els.\n\n    labelEls = labelEls || [];\n    tickEls = tickEls || [];\n\n    var firstLabel = labelEls[0];\n    var nextLabel = labelEls[1];\n    var lastLabel = labelEls[labelEls.length - 1];\n    var prevLabel = labelEls[labelEls.length - 2];\n\n    var firstTick = tickEls[0];\n    var nextTick = tickEls[1];\n    var lastTick = tickEls[tickEls.length - 1];\n    var prevTick = tickEls[tickEls.length - 2];\n\n    if (showMinLabel === false) {\n        ignoreEl(firstLabel);\n        ignoreEl(firstTick);\n    }\n    else if (isTwoLabelOverlapped(firstLabel, nextLabel)) {\n        if (showMinLabel) {\n            ignoreEl(nextLabel);\n            ignoreEl(nextTick);\n        }\n        else {\n            ignoreEl(firstLabel);\n            ignoreEl(firstTick);\n        }\n    }\n\n    if (showMaxLabel === false) {\n        ignoreEl(lastLabel);\n        ignoreEl(lastTick);\n    }\n    else if (isTwoLabelOverlapped(prevLabel, lastLabel)) {\n        if (showMaxLabel) {\n            ignoreEl(prevLabel);\n            ignoreEl(prevTick);\n        }\n        else {\n            ignoreEl(lastLabel);\n            ignoreEl(lastTick);\n        }\n    }\n}\n\nfunction ignoreEl(el) {\n    el && (el.ignore = true);\n}\n\nfunction isTwoLabelOverlapped(current, next, labelLayout) {\n    // current and next has the same rotation.\n    var firstRect = current && current.getBoundingRect().clone();\n    var nextRect = next && next.getBoundingRect().clone();\n\n    if (!firstRect || !nextRect) {\n        return;\n    }\n\n    // When checking intersect of two rotated labels, we use mRotationBack\n    // to avoid that boundingRect is enlarge when using `boundingRect.applyTransform`.\n    var mRotationBack = identity([]);\n    rotate(mRotationBack, mRotationBack, -current.rotation);\n\n    firstRect.applyTransform(mul$1([], mRotationBack, current.getLocalTransform()));\n    nextRect.applyTransform(mul$1([], mRotationBack, next.getLocalTransform()));\n\n    return firstRect.intersect(nextRect);\n}\n\nfunction isNameLocationCenter(nameLocation) {\n    return nameLocation === 'middle' || nameLocation === 'center';\n}\n\nfunction buildAxisTick(axisBuilder, axisModel, opt) {\n    var axis = axisModel.axis;\n\n    if (!axisModel.get('axisTick.show') || axis.scale.isBlank()) {\n        return;\n    }\n\n    var tickModel = axisModel.getModel('axisTick');\n\n    var lineStyleModel = tickModel.getModel('lineStyle');\n    var tickLen = tickModel.get('length');\n\n    var ticksCoords = axis.getTicksCoords();\n\n    var pt1 = [];\n    var pt2 = [];\n    var matrix = axisBuilder._transform;\n\n    var tickEls = [];\n\n    for (var i = 0; i < ticksCoords.length; i++) {\n        var tickCoord = ticksCoords[i].coord;\n\n        pt1[0] = tickCoord;\n        pt1[1] = 0;\n        pt2[0] = tickCoord;\n        pt2[1] = opt.tickDirection * tickLen;\n\n        if (matrix) {\n            applyTransform(pt1, pt1, matrix);\n            applyTransform(pt2, pt2, matrix);\n        }\n        // Tick line, Not use group transform to have better line draw\n        var tickEl = new Line(subPixelOptimizeLine({\n            // Id for animation\n            anid: 'tick_' + ticksCoords[i].tickValue,\n\n            shape: {\n                x1: pt1[0],\n                y1: pt1[1],\n                x2: pt2[0],\n                y2: pt2[1]\n            },\n            style: defaults(\n                lineStyleModel.getLineStyle(),\n                {\n                    stroke: axisModel.get('axisLine.lineStyle.color')\n                }\n            ),\n            z2: 2,\n            silent: true\n        }));\n        axisBuilder.group.add(tickEl);\n        tickEls.push(tickEl);\n    }\n\n    return tickEls;\n}\n\nfunction buildAxisLabel(axisBuilder, axisModel, opt) {\n    var axis = axisModel.axis;\n    var show = retrieve(opt.axisLabelShow, axisModel.get('axisLabel.show'));\n\n    if (!show || axis.scale.isBlank()) {\n        return;\n    }\n\n    var labelModel = axisModel.getModel('axisLabel');\n    var labelMargin = labelModel.get('margin');\n    var labels = axis.getViewLabels();\n\n    // Special label rotate.\n    var labelRotation = (\n        retrieve(opt.labelRotate, labelModel.get('rotate')) || 0\n    ) * PI$2 / 180;\n\n    var labelLayout = innerTextLayout(opt.rotation, labelRotation, opt.labelDirection);\n    var rawCategoryData = axisModel.getCategories(true);\n\n    var labelEls = [];\n    var silent = isSilent(axisModel);\n    var triggerEvent = axisModel.get('triggerEvent');\n\n    each$1(labels, function (labelItem, index) {\n        var tickValue = labelItem.tickValue;\n        var formattedLabel = labelItem.formattedLabel;\n        var rawLabel = labelItem.rawLabel;\n\n        var itemLabelModel = labelModel;\n        if (rawCategoryData && rawCategoryData[tickValue] && rawCategoryData[tickValue].textStyle) {\n            itemLabelModel = new Model(\n                rawCategoryData[tickValue].textStyle, labelModel, axisModel.ecModel\n            );\n        }\n\n        var textColor = itemLabelModel.getTextColor()\n            || axisModel.get('axisLine.lineStyle.color');\n\n        var tickCoord = axis.dataToCoord(tickValue);\n        var pos = [\n            tickCoord,\n            opt.labelOffset + opt.labelDirection * labelMargin\n        ];\n\n        var textEl = new Text({\n            // Id for animation\n            anid: 'label_' + tickValue,\n            position: pos,\n            rotation: labelLayout.rotation,\n            silent: silent,\n            z2: 10\n        });\n\n        setTextStyle(textEl.style, itemLabelModel, {\n            text: formattedLabel,\n            textAlign: itemLabelModel.getShallow('align', true)\n                || labelLayout.textAlign,\n            textVerticalAlign: itemLabelModel.getShallow('verticalAlign', true)\n                || itemLabelModel.getShallow('baseline', true)\n                || labelLayout.textVerticalAlign,\n            textFill: typeof textColor === 'function'\n                ? textColor(\n                    // (1) In category axis with data zoom, tick is not the original\n                    // index of axis.data. So tick should not be exposed to user\n                    // in category axis.\n                    // (2) Compatible with previous version, which always use formatted label as\n                    // input. But in interval scale the formatted label is like '223,445', which\n                    // maked user repalce ','. So we modify it to return original val but remain\n                    // it as 'string' to avoid error in replacing.\n                    axis.type === 'category'\n                        ? rawLabel\n                        : axis.type === 'value'\n                        ? tickValue + ''\n                        : tickValue,\n                    index\n                )\n                : textColor\n        });\n\n        // Pack data for mouse event\n        if (triggerEvent) {\n            textEl.eventData = makeAxisEventDataBase(axisModel);\n            textEl.eventData.targetType = 'axisLabel';\n            textEl.eventData.value = rawLabel;\n        }\n\n        // FIXME\n        axisBuilder._dumbGroup.add(textEl);\n        textEl.updateTransform();\n\n        labelEls.push(textEl);\n        axisBuilder.group.add(textEl);\n\n        textEl.decomposeTransform();\n\n    });\n\n    return labelEls;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$6 = each$1;\nvar curry$1 = curry;\n\n// Build axisPointerModel, mergin tooltip.axisPointer model for each axis.\n// allAxesInfo should be updated when setOption performed.\nfunction collect(ecModel, api) {\n    var result = {\n        /**\n         * key: makeKey(axis.model)\n         * value: {\n         *      axis,\n         *      coordSys,\n         *      axisPointerModel,\n         *      triggerTooltip,\n         *      involveSeries,\n         *      snap,\n         *      seriesModels,\n         *      seriesDataCount\n         * }\n         */\n        axesInfo: {},\n        seriesInvolved: false,\n        /**\n         * key: makeKey(coordSys.model)\n         * value: Object: key makeKey(axis.model), value: axisInfo\n         */\n        coordSysAxesInfo: {},\n        coordSysMap: {}\n    };\n\n    collectAxesInfo(result, ecModel, api);\n\n    // Check seriesInvolved for performance, in case too many series in some chart.\n    result.seriesInvolved && collectSeriesInfo(result, ecModel);\n\n    return result;\n}\n\nfunction collectAxesInfo(result, ecModel, api) {\n    var globalTooltipModel = ecModel.getComponent('tooltip');\n    var globalAxisPointerModel = ecModel.getComponent('axisPointer');\n    // links can only be set on global.\n    var linksOption = globalAxisPointerModel.get('link', true) || [];\n    var linkGroups = [];\n\n    // Collect axes info.\n    each$6(api.getCoordinateSystems(), function (coordSys) {\n        // Some coordinate system do not support axes, like geo.\n        if (!coordSys.axisPointerEnabled) {\n            return;\n        }\n\n        var coordSysKey = makeKey(coordSys.model);\n        var axesInfoInCoordSys = result.coordSysAxesInfo[coordSysKey] = {};\n        result.coordSysMap[coordSysKey] = coordSys;\n\n        // Set tooltip (like 'cross') is a convienent way to show axisPointer\n        // for user. So we enable seting tooltip on coordSys model.\n        var coordSysModel = coordSys.model;\n        var baseTooltipModel = coordSysModel.getModel('tooltip', globalTooltipModel);\n\n        each$6(coordSys.getAxes(), curry$1(saveTooltipAxisInfo, false, null));\n\n        // If axis tooltip used, choose tooltip axis for each coordSys.\n        // Notice this case: coordSys is `grid` but not `cartesian2D` here.\n        if (coordSys.getTooltipAxes\n            && globalTooltipModel\n            // If tooltip.showContent is set as false, tooltip will not\n            // show but axisPointer will show as normal.\n            && baseTooltipModel.get('show')\n        ) {\n            // Compatible with previous logic. But series.tooltip.trigger: 'axis'\n            // or series.data[n].tooltip.trigger: 'axis' are not support any more.\n            var triggerAxis = baseTooltipModel.get('trigger') === 'axis';\n            var cross = baseTooltipModel.get('axisPointer.type') === 'cross';\n            var tooltipAxes = coordSys.getTooltipAxes(baseTooltipModel.get('axisPointer.axis'));\n            if (triggerAxis || cross) {\n                each$6(tooltipAxes.baseAxes, curry$1(\n                    saveTooltipAxisInfo, cross ? 'cross' : true, triggerAxis\n                ));\n            }\n            if (cross) {\n                each$6(tooltipAxes.otherAxes, curry$1(saveTooltipAxisInfo, 'cross', false));\n            }\n        }\n\n        // fromTooltip: true | false | 'cross'\n        // triggerTooltip: true | false | null\n        function saveTooltipAxisInfo(fromTooltip, triggerTooltip, axis) {\n            var axisPointerModel = axis.model.getModel('axisPointer', globalAxisPointerModel);\n\n            var axisPointerShow = axisPointerModel.get('show');\n            if (!axisPointerShow || (\n                axisPointerShow === 'auto'\n                && !fromTooltip\n                && !isHandleTrigger(axisPointerModel)\n            )) {\n                return;\n            }\n\n            if (triggerTooltip == null) {\n                triggerTooltip = axisPointerModel.get('triggerTooltip');\n            }\n\n            axisPointerModel = fromTooltip\n                ? makeAxisPointerModel(\n                    axis, baseTooltipModel, globalAxisPointerModel, ecModel,\n                    fromTooltip, triggerTooltip\n                )\n                : axisPointerModel;\n\n            var snap = axisPointerModel.get('snap');\n            var key = makeKey(axis.model);\n            var involveSeries = triggerTooltip || snap || axis.type === 'category';\n\n            // If result.axesInfo[key] exist, override it (tooltip has higher priority).\n            var axisInfo = result.axesInfo[key] = {\n                key: key,\n                axis: axis,\n                coordSys: coordSys,\n                axisPointerModel: axisPointerModel,\n                triggerTooltip: triggerTooltip,\n                involveSeries: involveSeries,\n                snap: snap,\n                useHandle: isHandleTrigger(axisPointerModel),\n                seriesModels: []\n            };\n            axesInfoInCoordSys[key] = axisInfo;\n            result.seriesInvolved |= involveSeries;\n\n            var groupIndex = getLinkGroupIndex(linksOption, axis);\n            if (groupIndex != null) {\n                var linkGroup = linkGroups[groupIndex] || (linkGroups[groupIndex] = {axesInfo: {}});\n                linkGroup.axesInfo[key] = axisInfo;\n                linkGroup.mapper = linksOption[groupIndex].mapper;\n                axisInfo.linkGroup = linkGroup;\n            }\n        }\n    });\n}\n\nfunction makeAxisPointerModel(\n    axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip\n) {\n    var tooltipAxisPointerModel = baseTooltipModel.getModel('axisPointer');\n    var volatileOption = {};\n\n    each$6(\n        [\n            'type', 'snap', 'lineStyle', 'shadowStyle', 'label',\n            'animation', 'animationDurationUpdate', 'animationEasingUpdate', 'z'\n        ],\n        function (field) {\n            volatileOption[field] = clone(tooltipAxisPointerModel.get(field));\n        }\n    );\n\n    // category axis do not auto snap, otherwise some tick that do not\n    // has value can not be hovered. value/time/log axis default snap if\n    // triggered from tooltip and trigger tooltip.\n    volatileOption.snap = axis.type !== 'category' && !!triggerTooltip;\n\n    // Compatibel with previous behavior, tooltip axis do not show label by default.\n    // Only these properties can be overrided from tooltip to axisPointer.\n    if (tooltipAxisPointerModel.get('type') === 'cross') {\n        volatileOption.type = 'line';\n    }\n    var labelOption = volatileOption.label || (volatileOption.label = {});\n    // Follow the convention, do not show label when triggered by tooltip by default.\n    labelOption.show == null && (labelOption.show = false);\n\n    if (fromTooltip === 'cross') {\n        // When 'cross', both axes show labels.\n        var tooltipAxisPointerLabelShow = tooltipAxisPointerModel.get('label.show');\n        labelOption.show = tooltipAxisPointerLabelShow != null ? tooltipAxisPointerLabelShow : true;\n        // If triggerTooltip, this is a base axis, which should better not use cross style\n        // (cross style is dashed by default)\n        if (!triggerTooltip) {\n            var crossStyle = volatileOption.lineStyle = tooltipAxisPointerModel.get('crossStyle');\n            crossStyle && defaults(labelOption, crossStyle.textStyle);\n        }\n    }\n\n    return axis.model.getModel(\n        'axisPointer',\n        new Model(volatileOption, globalAxisPointerModel, ecModel)\n    );\n}\n\nfunction collectSeriesInfo(result, ecModel) {\n    // Prepare data for axis trigger\n    ecModel.eachSeries(function (seriesModel) {\n\n        // Notice this case: this coordSys is `cartesian2D` but not `grid`.\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesTooltipTrigger = seriesModel.get('tooltip.trigger', true);\n        var seriesTooltipShow = seriesModel.get('tooltip.show', true);\n        if (!coordSys\n            || seriesTooltipTrigger === 'none'\n            || seriesTooltipTrigger === false\n            || seriesTooltipTrigger === 'item'\n            || seriesTooltipShow === false\n            || seriesModel.get('axisPointer.show', true) === false\n        ) {\n            return;\n        }\n\n        each$6(result.coordSysAxesInfo[makeKey(coordSys.model)], function (axisInfo) {\n            var axis = axisInfo.axis;\n            if (coordSys.getAxis(axis.dim) === axis) {\n                axisInfo.seriesModels.push(seriesModel);\n                axisInfo.seriesDataCount == null && (axisInfo.seriesDataCount = 0);\n                axisInfo.seriesDataCount += seriesModel.getData().count();\n            }\n        });\n\n    }, this);\n}\n\n/**\n * For example:\n * {\n *     axisPointer: {\n *         links: [{\n *             xAxisIndex: [2, 4],\n *             yAxisIndex: 'all'\n *         }, {\n *             xAxisId: ['a5', 'a7'],\n *             xAxisName: 'xxx'\n *         }]\n *     }\n * }\n */\nfunction getLinkGroupIndex(linksOption, axis) {\n    var axisModel = axis.model;\n    var dim = axis.dim;\n    for (var i = 0; i < linksOption.length; i++) {\n        var linkOption = linksOption[i] || {};\n        if (checkPropInLink(linkOption[dim + 'AxisId'], axisModel.id)\n            || checkPropInLink(linkOption[dim + 'AxisIndex'], axisModel.componentIndex)\n            || checkPropInLink(linkOption[dim + 'AxisName'], axisModel.name)\n        ) {\n            return i;\n        }\n    }\n}\n\nfunction checkPropInLink(linkPropValue, axisPropValue) {\n    return linkPropValue === 'all'\n        || (isArray(linkPropValue) && indexOf(linkPropValue, axisPropValue) >= 0)\n        || linkPropValue === axisPropValue;\n}\n\nfunction fixValue(axisModel) {\n    var axisInfo = getAxisInfo(axisModel);\n    if (!axisInfo) {\n        return;\n    }\n\n    var axisPointerModel = axisInfo.axisPointerModel;\n    var scale = axisInfo.axis.scale;\n    var option = axisPointerModel.option;\n    var status = axisPointerModel.get('status');\n    var value = axisPointerModel.get('value');\n\n    // Parse init value for category and time axis.\n    if (value != null) {\n        value = scale.parse(value);\n    }\n\n    var useHandle = isHandleTrigger(axisPointerModel);\n    // If `handle` used, `axisPointer` will always be displayed, so value\n    // and status should be initialized.\n    if (status == null) {\n        option.status = useHandle ? 'show' : 'hide';\n    }\n\n    var extent = scale.getExtent().slice();\n    extent[0] > extent[1] && extent.reverse();\n\n    if (// Pick a value on axis when initializing.\n        value == null\n        // If both `handle` and `dataZoom` are used, value may be out of axis extent,\n        // where we should re-pick a value to keep `handle` displaying normally.\n        || value > extent[1]\n    ) {\n        // Make handle displayed on the end of the axis when init, which looks better.\n        value = extent[1];\n    }\n    if (value < extent[0]) {\n        value = extent[0];\n    }\n\n    option.value = value;\n\n    if (useHandle) {\n        option.status = axisInfo.axis.scale.isBlank() ? 'hide' : 'show';\n    }\n}\n\nfunction getAxisInfo(axisModel) {\n    var coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') || {}).coordSysAxesInfo;\n    return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)];\n}\n\nfunction getAxisPointerModel(axisModel) {\n    var axisInfo = getAxisInfo(axisModel);\n    return axisInfo && axisInfo.axisPointerModel;\n}\n\nfunction isHandleTrigger(axisPointerModel) {\n    return !!axisPointerModel.get('handle.show');\n}\n\n/**\n * @param {module:echarts/model/Model} model\n * @return {string} unique key\n */\nfunction makeKey(model) {\n    return model.type + '||' + model.id;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Base class of AxisView.\n */\nvar AxisView = extendComponentView({\n\n    type: 'axis',\n\n    /**\n     * @private\n     */\n    _axisPointer: null,\n\n    /**\n     * @protected\n     * @type {string}\n     */\n    axisPointerClass: null,\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n        // FIXME\n        // This process should proformed after coordinate systems updated\n        // (axis scale updated), and should be performed each time update.\n        // So put it here temporarily, although it is not appropriate to\n        // put a model-writing procedure in `view`.\n        this.axisPointerClass && fixValue(axisModel);\n\n        AxisView.superApply(this, 'render', arguments);\n\n        updateAxisPointer(this, axisModel, ecModel, api, payload, true);\n    },\n\n    /**\n     * Action handler.\n     * @public\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/model/Global} ecModel\n     * @param {module:echarts/ExtensionAPI} api\n     * @param {Object} payload\n     */\n    updateAxisPointer: function (axisModel, ecModel, api, payload, force) {\n        updateAxisPointer(this, axisModel, ecModel, api, payload, false);\n    },\n\n    /**\n     * @override\n     */\n    remove: function (ecModel, api) {\n        var axisPointer = this._axisPointer;\n        axisPointer && axisPointer.remove(api);\n        AxisView.superApply(this, 'remove', arguments);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function (ecModel, api) {\n        disposeAxisPointer(this, api);\n        AxisView.superApply(this, 'dispose', arguments);\n    }\n\n});\n\nfunction updateAxisPointer(axisView, axisModel, ecModel, api, payload, forceRender) {\n    var Clazz = AxisView.getAxisPointerClass(axisView.axisPointerClass);\n    if (!Clazz) {\n        return;\n    }\n    var axisPointerModel = getAxisPointerModel(axisModel);\n    axisPointerModel\n        ? (axisView._axisPointer || (axisView._axisPointer = new Clazz()))\n            .render(axisModel, axisPointerModel, api, forceRender)\n        : disposeAxisPointer(axisView, api);\n}\n\nfunction disposeAxisPointer(axisView, ecModel, api) {\n    var axisPointer = axisView._axisPointer;\n    axisPointer && axisPointer.dispose(ecModel, api);\n    axisView._axisPointer = null;\n}\n\nvar axisPointerClazz = [];\n\nAxisView.registerAxisPointerClass = function (type, clazz) {\n    if (__DEV__) {\n        if (axisPointerClazz[type]) {\n            throw new Error('axisPointer ' + type + ' exists');\n        }\n    }\n    axisPointerClazz[type] = clazz;\n};\n\nAxisView.getAxisPointerClass = function (type) {\n    return type && axisPointerClazz[type];\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Can only be called after coordinate system creation stage.\n * (Can be called before coordinate system update stage).\n *\n * @param {Object} opt {labelInside}\n * @return {Object} {\n *  position, rotation, labelDirection, labelOffset,\n *  tickDirection, labelRotate, z2\n * }\n */\nfunction layout$1(gridModel, axisModel, opt) {\n    opt = opt || {};\n    var grid = gridModel.coordinateSystem;\n    var axis = axisModel.axis;\n    var layout = {};\n    var otherAxisOnZeroOf = axis.getAxesOnZeroOf()[0];\n\n    var rawAxisPosition = axis.position;\n    var axisPosition = otherAxisOnZeroOf ? 'onZero' : rawAxisPosition;\n    var axisDim = axis.dim;\n\n    var rect = grid.getRect();\n    var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];\n    var idx = {left: 0, right: 1, top: 0, bottom: 1, onZero: 2};\n    var axisOffset = axisModel.get('offset') || 0;\n\n    var posBound = axisDim === 'x'\n        ? [rectBound[2] - axisOffset, rectBound[3] + axisOffset]\n        : [rectBound[0] - axisOffset, rectBound[1] + axisOffset];\n\n    if (otherAxisOnZeroOf) {\n        var onZeroCoord = otherAxisOnZeroOf.toGlobalCoord(otherAxisOnZeroOf.dataToCoord(0));\n        posBound[idx.onZero] = Math.max(Math.min(onZeroCoord, posBound[1]), posBound[0]);\n    }\n\n    // Axis position\n    layout.position = [\n        axisDim === 'y' ? posBound[idx[axisPosition]] : rectBound[0],\n        axisDim === 'x' ? posBound[idx[axisPosition]] : rectBound[3]\n    ];\n\n    // Axis rotation\n    layout.rotation = Math.PI / 2 * (axisDim === 'x' ? 0 : 1);\n\n    // Tick and label direction, x y is axisDim\n    var dirMap = {top: -1, bottom: 1, left: -1, right: 1};\n\n    layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition];\n    layout.labelOffset = otherAxisOnZeroOf ? posBound[idx[rawAxisPosition]] - posBound[idx.onZero] : 0;\n\n    if (axisModel.get('axisTick.inside')) {\n        layout.tickDirection = -layout.tickDirection;\n    }\n    if (retrieve(opt.labelInside, axisModel.get('axisLabel.inside'))) {\n        layout.labelDirection = -layout.labelDirection;\n    }\n\n    // Special label rotation\n    var labelRotate = axisModel.get('axisLabel.rotate');\n    layout.labelRotate = axisPosition === 'top' ? -labelRotate : labelRotate;\n\n    // Over splitLine and splitArea\n    layout.z2 = 1;\n\n    return layout;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar axisBuilderAttrs = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\nvar selfBuilderAttrs = [\n    'splitArea', 'splitLine'\n];\n\n// function getAlignWithLabel(model, axisModel) {\n//     var alignWithLabel = model.get('alignWithLabel');\n//     if (alignWithLabel === 'auto') {\n//         alignWithLabel = axisModel.get('axisTick.alignWithLabel');\n//     }\n//     return alignWithLabel;\n// }\n\nvar CartesianAxisView = AxisView.extend({\n\n    type: 'cartesianAxis',\n\n    axisPointerClass: 'CartesianAxisPointer',\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n\n        this.group.removeAll();\n\n        var oldAxisGroup = this._axisGroup;\n        this._axisGroup = new Group();\n\n        this.group.add(this._axisGroup);\n\n        if (!axisModel.get('show')) {\n            return;\n        }\n\n        var gridModel = axisModel.getCoordSysModel();\n\n        var layout = layout$1(gridModel, axisModel);\n\n        var axisBuilder = new AxisBuilder(axisModel, layout);\n\n        each$1(axisBuilderAttrs, axisBuilder.add, axisBuilder);\n\n        this._axisGroup.add(axisBuilder.getGroup());\n\n        each$1(selfBuilderAttrs, function (name) {\n            if (axisModel.get(name + '.show')) {\n                this['_' + name](axisModel, gridModel);\n            }\n        }, this);\n\n        groupTransition(oldAxisGroup, this._axisGroup, axisModel);\n\n        CartesianAxisView.superCall(this, 'render', axisModel, ecModel, api, payload);\n    },\n\n    remove: function () {\n        this._splitAreaColors = null;\n    },\n\n    /**\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/coord/cartesian/GridModel} gridModel\n     * @private\n     */\n    _splitLine: function (axisModel, gridModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitLineModel = axisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineColors = lineStyleModel.get('color');\n\n        lineColors = isArray(lineColors) ? lineColors : [lineColors];\n\n        var gridRect = gridModel.coordinateSystem.getRect();\n        var isHorizontal = axis.isHorizontal();\n\n        var lineCount = 0;\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitLineModel\n        });\n\n        var p1 = [];\n        var p2 = [];\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        var lineStyle = lineStyleModel.getLineStyle();\n        for (var i = 0; i < ticksCoords.length; i++) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n\n            if (isHorizontal) {\n                p1[0] = tickCoord;\n                p1[1] = gridRect.y;\n                p2[0] = tickCoord;\n                p2[1] = gridRect.y + gridRect.height;\n            }\n            else {\n                p1[0] = gridRect.x;\n                p1[1] = tickCoord;\n                p2[0] = gridRect.x + gridRect.width;\n                p2[1] = tickCoord;\n            }\n\n            var colorIndex = (lineCount++) % lineColors.length;\n            var tickValue = ticksCoords[i].tickValue;\n            this._axisGroup.add(new Line(subPixelOptimizeLine({\n                anid: tickValue != null ? 'line_' + ticksCoords[i].tickValue : null,\n                shape: {\n                    x1: p1[0],\n                    y1: p1[1],\n                    x2: p2[0],\n                    y2: p2[1]\n                },\n                style: defaults({\n                    stroke: lineColors[colorIndex]\n                }, lineStyle),\n                silent: true\n            })));\n        }\n    },\n\n    /**\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/coord/cartesian/GridModel} gridModel\n     * @private\n     */\n    _splitArea: function (axisModel, gridModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitAreaModel = axisModel.getModel('splitArea');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n        var areaColors = areaStyleModel.get('color');\n\n        var gridRect = gridModel.coordinateSystem.getRect();\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitAreaModel,\n            clamp: true\n        });\n\n        if (!ticksCoords.length) {\n            return;\n        }\n\n        // For Making appropriate splitArea animation, the color and anid\n        // should be corresponding to previous one if possible.\n        var areaColorsLen = areaColors.length;\n        var lastSplitAreaColors = this._splitAreaColors;\n        var newSplitAreaColors = createHashMap();\n        var colorIndex = 0;\n        if (lastSplitAreaColors) {\n            for (var i = 0; i < ticksCoords.length; i++) {\n                var cIndex = lastSplitAreaColors.get(ticksCoords[i].tickValue);\n                if (cIndex != null) {\n                    colorIndex = (cIndex + (areaColorsLen - 1) * i) % areaColorsLen;\n                    break;\n                }\n            }\n        }\n\n        var prev = axis.toGlobalCoord(ticksCoords[0].coord);\n\n        var areaStyle = areaStyleModel.getAreaStyle();\n        areaColors = isArray(areaColors) ? areaColors : [areaColors];\n\n        for (var i = 1; i < ticksCoords.length; i++) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n\n            var x;\n            var y;\n            var width;\n            var height;\n            if (axis.isHorizontal()) {\n                x = prev;\n                y = gridRect.y;\n                width = tickCoord - x;\n                height = gridRect.height;\n                prev = x + width;\n            }\n            else {\n                x = gridRect.x;\n                y = prev;\n                width = gridRect.width;\n                height = tickCoord - y;\n                prev = y + height;\n            }\n\n            var tickValue = ticksCoords[i - 1].tickValue;\n            tickValue != null && newSplitAreaColors.set(tickValue, colorIndex);\n\n            this._axisGroup.add(new Rect({\n                anid: tickValue != null ? 'area_' + tickValue : null,\n                shape: {\n                    x: x,\n                    y: y,\n                    width: width,\n                    height: height\n                },\n                style: defaults({\n                    fill: areaColors[colorIndex]\n                }, areaStyle),\n                silent: true\n            }));\n\n            colorIndex = (colorIndex + 1) % areaColorsLen;\n        }\n\n        this._splitAreaColors = newSplitAreaColors;\n    }\n});\n\nCartesianAxisView.extend({\n    type: 'xAxis'\n});\nCartesianAxisView.extend({\n    type: 'yAxis'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Grid view\nextendComponentView({\n\n    type: 'grid',\n\n    render: function (gridModel, ecModel) {\n        this.group.removeAll();\n        if (gridModel.get('show')) {\n            this.group.add(new Rect({\n                shape: gridModel.coordinateSystem.getRect(),\n                style: defaults({\n                    fill: gridModel.get('backgroundColor')\n                }, gridModel.getItemStyle()),\n                silent: true,\n                z2: -1\n            }));\n        }\n    }\n\n});\n\nregisterPreprocessor(function (option) {\n    // Only create grid when need\n    if (option.xAxis && option.yAxis && !option.grid) {\n        option.grid = {};\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterVisual(visualSymbol('line', 'circle', 'line'));\nregisterLayout(pointsLayout('line'));\n\n// Down sample after filter\nregisterProcessor(\n    PRIORITY.PROCESSOR.STATISTIC,\n    dataSample('line')\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BaseBarSeries = SeriesModel.extend({\n\n    type: 'series.__base_bar__',\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    getMarkerPosition: function (value) {\n        var coordSys = this.coordinateSystem;\n        if (coordSys) {\n            // PENDING if clamp ?\n            var pt = coordSys.dataToPoint(coordSys.clampData(value));\n            var data = this.getData();\n            var offset = data.getLayout('offset');\n            var size = data.getLayout('size');\n            var offsetIndex = coordSys.getBaseAxis().isHorizontal() ? 0 : 1;\n            pt[offsetIndex] += offset + size / 2;\n            return pt;\n        }\n        return [NaN, NaN];\n    },\n\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n        // stack: null\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // 最小高度改为0\n        barMinHeight: 0,\n        // 最小角度为0，仅对极坐标系下的柱状图有效\n        barMinAngle: 0,\n        // cursor: null,\n\n        large: false,\n        largeThreshold: 400,\n        progressive: 3e3,\n        progressiveChunkMode: 'mod',\n\n        // barMaxWidth: null,\n        // 默认自适应\n        // barWidth: null,\n        // 柱间距离，默认为柱形宽度的30%，可设固定值\n        // barGap: '30%',\n        // 类目间柱形距离，默认为类目间距的20%，可设固定值\n        // barCategoryGap: '20%',\n        // label: {\n        //      show: false\n        // },\n        itemStyle: {},\n        emphasis: {}\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nBaseBarSeries.extend({\n\n    type: 'series.bar',\n\n    dependencies: ['grid', 'polar'],\n\n    brushSelector: 'rect',\n\n    /**\n     * @override\n     */\n    getProgressive: function () {\n        // Do not support progressive in normal mode.\n        return this.get('large')\n            ? this.get('progressive')\n            : false;\n    },\n\n    /**\n     * @override\n     */\n    getProgressiveThreshold: function () {\n        // Do not support progressive in normal mode.\n        var progressiveThreshold = this.get('progressiveThreshold');\n        var largeThreshold = this.get('largeThreshold');\n        if (largeThreshold > progressiveThreshold) {\n            progressiveThreshold = largeThreshold;\n        }\n        return progressiveThreshold;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction setLabel(\n    normalStyle, hoverStyle, itemModel, color, seriesModel, dataIndex, labelPositionOutside\n) {\n    var labelModel = itemModel.getModel('label');\n    var hoverLabelModel = itemModel.getModel('emphasis.label');\n\n    setLabelStyle(\n        normalStyle, hoverStyle, labelModel, hoverLabelModel,\n        {\n            labelFetcher: seriesModel,\n            labelDataIndex: dataIndex,\n            defaultText: getDefaultLabel(seriesModel.getData(), dataIndex),\n            isRectText: true,\n            autoColor: color\n        }\n    );\n\n    fixPosition(normalStyle);\n    fixPosition(hoverStyle);\n}\n\nfunction fixPosition(style, labelPositionOutside) {\n    if (style.textPosition === 'outside') {\n        style.textPosition = labelPositionOutside;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getBarItemStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['stroke', 'borderColor'],\n        ['lineWidth', 'borderWidth'],\n        // Compatitable with 2\n        ['stroke', 'barBorderColor'],\n        ['lineWidth', 'barBorderWidth'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor']\n    ]\n);\n\nvar barItemStyle = {\n    getBarItemStyle: function (excludes) {\n        var style = getBarItemStyle(this, excludes);\n        if (this.getBorderLineDash) {\n            var lineDash = this.getBorderLineDash();\n            lineDash && (style.lineDash = lineDash);\n        }\n        return style;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'barBorderWidth'];\n\n// FIXME\n// Just for compatible with ec2.\nextend(Model.prototype, barItemStyle);\n\nextendChartView({\n\n    type: 'bar',\n\n    render: function (seriesModel, ecModel, api) {\n        this._updateDrawMode(seriesModel);\n\n        var coordinateSystemType = seriesModel.get('coordinateSystem');\n\n        if (coordinateSystemType === 'cartesian2d'\n            || coordinateSystemType === 'polar'\n        ) {\n            this._isLargeDraw\n                ? this._renderLarge(seriesModel, ecModel, api)\n                : this._renderNormal(seriesModel, ecModel, api);\n        }\n        else if (__DEV__) {\n            console.warn('Only cartesian2d and polar supported for bar.');\n        }\n\n        return this.group;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this._clear();\n        this._updateDrawMode(seriesModel);\n    },\n\n    incrementalRender: function (params, seriesModel, ecModel, api) {\n        // Do not support progressive in normal mode.\n        this._incrementalRenderLarge(params, seriesModel);\n    },\n\n    _updateDrawMode: function (seriesModel) {\n        var isLargeDraw = seriesModel.pipelineContext.large;\n        if (this._isLargeDraw == null || isLargeDraw ^ this._isLargeDraw) {\n            this._isLargeDraw = isLargeDraw;\n            this._clear();\n        }\n    },\n\n    _renderNormal: function (seriesModel, ecModel, api) {\n        var group = this.group;\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        var coord = seriesModel.coordinateSystem;\n        var baseAxis = coord.getBaseAxis();\n        var isHorizontalOrRadial;\n\n        if (coord.type === 'cartesian2d') {\n            isHorizontalOrRadial = baseAxis.isHorizontal();\n        }\n        else if (coord.type === 'polar') {\n            isHorizontalOrRadial = baseAxis.dim === 'angle';\n        }\n\n        var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null;\n\n        data.diff(oldData)\n            .add(function (dataIndex) {\n                if (!data.hasValue(dataIndex)) {\n                    return;\n                }\n\n                var itemModel = data.getItemModel(dataIndex);\n                var layout = getLayout[coord.type](data, dataIndex, itemModel);\n                var el = elementCreator[coord.type](\n                    data, dataIndex, itemModel, layout, isHorizontalOrRadial, animationModel\n                );\n                data.setItemGraphicEl(dataIndex, el);\n                group.add(el);\n\n                updateStyle(\n                    el, data, dataIndex, itemModel, layout,\n                    seriesModel, isHorizontalOrRadial, coord.type === 'polar'\n                );\n            })\n            .update(function (newIndex, oldIndex) {\n                var el = oldData.getItemGraphicEl(oldIndex);\n\n                if (!data.hasValue(newIndex)) {\n                    group.remove(el);\n                    return;\n                }\n\n                var itemModel = data.getItemModel(newIndex);\n                var layout = getLayout[coord.type](data, newIndex, itemModel);\n\n                if (el) {\n                    updateProps(el, {shape: layout}, animationModel, newIndex);\n                }\n                else {\n                    el = elementCreator[coord.type](\n                        data, newIndex, itemModel, layout, isHorizontalOrRadial, animationModel, true\n                    );\n                }\n\n                data.setItemGraphicEl(newIndex, el);\n                // Add back\n                group.add(el);\n\n                updateStyle(\n                    el, data, newIndex, itemModel, layout,\n                    seriesModel, isHorizontalOrRadial, coord.type === 'polar'\n                );\n            })\n            .remove(function (dataIndex) {\n                var el = oldData.getItemGraphicEl(dataIndex);\n                if (coord.type === 'cartesian2d') {\n                    el && removeRect(dataIndex, animationModel, el);\n                }\n                else {\n                    el && removeSector(dataIndex, animationModel, el);\n                }\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    _renderLarge: function (seriesModel, ecModel, api) {\n        this._clear();\n        createLarge(seriesModel, this.group);\n    },\n\n    _incrementalRenderLarge: function (params, seriesModel) {\n        createLarge(seriesModel, this.group, true);\n    },\n\n    dispose: noop,\n\n    remove: function (ecModel) {\n        this._clear(ecModel);\n    },\n\n    _clear: function (ecModel) {\n        var group = this.group;\n        var data = this._data;\n        if (ecModel && ecModel.get('animation') && data && !this._isLargeDraw) {\n            data.eachItemGraphicEl(function (el) {\n                if (el.type === 'sector') {\n                    removeSector(el.dataIndex, ecModel, el);\n                }\n                else {\n                    removeRect(el.dataIndex, ecModel, el);\n                }\n            });\n        }\n        else {\n            group.removeAll();\n        }\n        this._data = null;\n    }\n\n});\n\nvar elementCreator = {\n\n    cartesian2d: function (\n        data, dataIndex, itemModel, layout, isHorizontal,\n        animationModel, isUpdate\n    ) {\n        var rect = new Rect({shape: extend({}, layout)});\n\n        // Animation\n        if (animationModel) {\n            var rectShape = rect.shape;\n            var animateProperty = isHorizontal ? 'height' : 'width';\n            var animateTarget = {};\n            rectShape[animateProperty] = 0;\n            animateTarget[animateProperty] = layout[animateProperty];\n            graphic[isUpdate ? 'updateProps' : 'initProps'](rect, {\n                shape: animateTarget\n            }, animationModel, dataIndex);\n        }\n\n        return rect;\n    },\n\n    polar: function (\n        data, dataIndex, itemModel, layout, isRadial,\n        animationModel, isUpdate\n    ) {\n        // Keep the same logic with bar in catesion: use end value to control\n        // direction. Notice that if clockwise is true (by default), the sector\n        // will always draw clockwisely, no matter whether endAngle is greater\n        // or less than startAngle.\n        var clockwise = layout.startAngle < layout.endAngle;\n        var sector = new Sector({\n            shape: defaults({clockwise: clockwise}, layout)\n        });\n\n        // Animation\n        if (animationModel) {\n            var sectorShape = sector.shape;\n            var animateProperty = isRadial ? 'r' : 'endAngle';\n            var animateTarget = {};\n            sectorShape[animateProperty] = isRadial ? 0 : layout.startAngle;\n            animateTarget[animateProperty] = layout[animateProperty];\n            graphic[isUpdate ? 'updateProps' : 'initProps'](sector, {\n                shape: animateTarget\n            }, animationModel, dataIndex);\n        }\n\n        return sector;\n    }\n};\n\nfunction removeRect(dataIndex, animationModel, el) {\n    // Not show text when animating\n    el.style.text = null;\n    updateProps(el, {\n        shape: {\n            width: 0\n        }\n    }, animationModel, dataIndex, function () {\n        el.parent && el.parent.remove(el);\n    });\n}\n\nfunction removeSector(dataIndex, animationModel, el) {\n    // Not show text when animating\n    el.style.text = null;\n    updateProps(el, {\n        shape: {\n            r: el.shape.r0\n        }\n    }, animationModel, dataIndex, function () {\n        el.parent && el.parent.remove(el);\n    });\n}\n\nvar getLayout = {\n    cartesian2d: function (data, dataIndex, itemModel) {\n        var layout = data.getItemLayout(dataIndex);\n        var fixedLineWidth = getLineWidth(itemModel, layout);\n\n        // fix layout with lineWidth\n        var signX = layout.width > 0 ? 1 : -1;\n        var signY = layout.height > 0 ? 1 : -1;\n        return {\n            x: layout.x + signX * fixedLineWidth / 2,\n            y: layout.y + signY * fixedLineWidth / 2,\n            width: layout.width - signX * fixedLineWidth,\n            height: layout.height - signY * fixedLineWidth\n        };\n    },\n\n    polar: function (data, dataIndex, itemModel) {\n        var layout = data.getItemLayout(dataIndex);\n        return {\n            cx: layout.cx,\n            cy: layout.cy,\n            r0: layout.r0,\n            r: layout.r,\n            startAngle: layout.startAngle,\n            endAngle: layout.endAngle\n        };\n    }\n};\n\nfunction updateStyle(\n    el, data, dataIndex, itemModel, layout, seriesModel, isHorizontal, isPolar\n) {\n    var color = data.getItemVisual(dataIndex, 'color');\n    var opacity = data.getItemVisual(dataIndex, 'opacity');\n    var itemStyleModel = itemModel.getModel('itemStyle');\n    var hoverStyle = itemModel.getModel('emphasis.itemStyle').getBarItemStyle();\n\n    if (!isPolar) {\n        el.setShape('r', itemStyleModel.get('barBorderRadius') || 0);\n    }\n\n    el.useStyle(defaults(\n        {\n            fill: color,\n            opacity: opacity\n        },\n        itemStyleModel.getBarItemStyle()\n    ));\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && el.attr('cursor', cursorStyle);\n\n    var labelPositionOutside = isHorizontal\n        ? (layout.height > 0 ? 'bottom' : 'top')\n        : (layout.width > 0 ? 'left' : 'right');\n\n    if (!isPolar) {\n        setLabel(\n            el.style, hoverStyle, itemModel, color,\n            seriesModel, dataIndex, labelPositionOutside\n        );\n    }\n\n    setHoverStyle(el, hoverStyle);\n}\n\n// In case width or height are too small.\nfunction getLineWidth(itemModel, rawLayout) {\n    var lineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY) || 0;\n    return Math.min(lineWidth, Math.abs(rawLayout.width), Math.abs(rawLayout.height));\n}\n\n\nvar LargePath = Path.extend({\n\n    type: 'largeBar',\n\n    shape: {points: []},\n\n    buildPath: function (ctx, shape) {\n        // Drawing lines is more efficient than drawing\n        // a whole line or drawing rects.\n        var points = shape.points;\n        var startPoint = this.__startPoint;\n        var valueIdx = this.__valueIdx;\n\n        for (var i = 0; i < points.length; i += 2) {\n            startPoint[this.__valueIdx] = points[i + valueIdx];\n            ctx.moveTo(startPoint[0], startPoint[1]);\n            ctx.lineTo(points[i], points[i + 1]);\n        }\n    }\n});\n\nfunction createLarge(seriesModel, group, incremental) {\n    // TODO support polar\n    var data = seriesModel.getData();\n    var startPoint = [];\n    var valueIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0;\n    startPoint[1 - valueIdx] = data.getLayout('valueAxisStart');\n\n    var el = new LargePath({\n        shape: {points: data.getLayout('largePoints')},\n        incremental: !!incremental,\n        __startPoint: startPoint,\n        __valueIdx: valueIdx\n    });\n    group.add(el);\n    setLargeStyle(el, seriesModel, data);\n}\n\nfunction setLargeStyle(el, seriesModel, data) {\n    var borderColor = data.getVisual('borderColor') || data.getVisual('color');\n    var itemStyle = seriesModel.getModel('itemStyle').getItemStyle(['color', 'borderColor']);\n\n    el.useStyle(itemStyle);\n    el.style.fill = null;\n    el.style.stroke = borderColor;\n    el.style.lineWidth = data.getLayout('barWidth');\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterLayout(curry(layout, 'bar'));\n// Should after normal bar layout, otherwise it is blocked by normal bar layout.\nregisterLayout(largeLayout);\n\nregisterVisual({\n    seriesType: 'bar',\n    reset: function (seriesModel) {\n        // Visual coding for legend\n        seriesModel.getData().setVisual('legendSymbol', 'roundRect');\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * [Usage]:\n * (1)\n * createListSimply(seriesModel, ['value']);\n * (2)\n * createListSimply(seriesModel, {\n *     coordDimensions: ['value'],\n *     dimensionsCount: 5\n * });\n *\n * @param {module:echarts/model/Series} seriesModel\n * @param {Object|Array.<string|Object>} opt opt or coordDimensions\n *        The options in opt, see `echarts/data/helper/createDimensions`\n * @param {Array.<string>} [nameList]\n * @return {module:echarts/data/List}\n */\nvar createListSimply = function (seriesModel, opt, nameList) {\n    opt = isArray(opt) && {coordDimensions: opt} || extend({}, opt);\n\n    var source = seriesModel.getSource();\n\n    var dimensionsInfo = createDimensions(source, opt);\n\n    var list = new List(dimensionsInfo, seriesModel);\n    list.initData(source, nameList);\n\n    return list;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Data selectable mixin for chart series.\n * To eanble data select, option of series must have `selectedMode`.\n * And each data item will use `selected` to toggle itself selected status\n */\n\nvar selectableMixin = {\n\n    /**\n     * @param {Array.<Object>} targetList [{name, value, selected}, ...]\n     *        If targetList is an array, it should like [{name: ..., value: ...}, ...].\n     *        If targetList is a \"List\", it must have coordDim: 'value' dimension and name.\n     */\n    updateSelectedMap: function (targetList) {\n        this._targetList = isArray(targetList) ? targetList.slice() : [];\n\n        this._selectTargetMap = reduce(targetList || [], function (targetMap, target) {\n            targetMap.set(target.name, target);\n            return targetMap;\n        }, createHashMap());\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    // PENGING If selectedMode is null ?\n    select: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        var selectedMode = this.get('selectedMode');\n        if (selectedMode === 'single') {\n            this._selectTargetMap.each(function (target) {\n                target.selected = false;\n            });\n        }\n        target && (target.selected = true);\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    unSelect: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        // var selectedMode = this.get('selectedMode');\n        // selectedMode !== 'single' && target && (target.selected = false);\n        target && (target.selected = false);\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    toggleSelected: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        if (target != null) {\n            this[target.selected ? 'unSelect' : 'select'](name, id);\n            return target.selected;\n        }\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    isSelected: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        return target && target.selected;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PieSeries = extendSeriesModel({\n\n    type: 'series.pie',\n\n    // Overwrite\n    init: function (option) {\n        PieSeries.superApply(this, 'init', arguments);\n\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n\n        this.updateSelectedMap(this._createSelectableList());\n\n        this._defaultLabelLine(option);\n    },\n\n    // Overwrite\n    mergeOption: function (newOption) {\n        PieSeries.superCall(this, 'mergeOption', newOption);\n\n        this.updateSelectedMap(this._createSelectableList());\n    },\n\n    getInitialData: function (option, ecModel) {\n        return createListSimply(this, ['value']);\n    },\n\n    _createSelectableList: function () {\n        var data = this.getRawData();\n        var valueDim = data.mapDimension('value');\n        var targetList = [];\n        for (var i = 0, len = data.count(); i < len; i++) {\n            targetList.push({\n                name: data.getName(i),\n                value: data.get(valueDim, i),\n                selected: retrieveRawAttr(data, i, 'selected')\n            });\n        }\n        return targetList;\n    },\n\n    // Overwrite\n    getDataParams: function (dataIndex) {\n        var data = this.getData();\n        var params = PieSeries.superCall(this, 'getDataParams', dataIndex);\n        // FIXME toFixed?\n\n        var valueList = [];\n        data.each(data.mapDimension('value'), function (value) {\n            valueList.push(value);\n        });\n\n        params.percent = getPercentWithPrecision(\n            valueList,\n            dataIndex,\n            data.hostModel.get('percentPrecision')\n        );\n\n        params.$vars.push('percent');\n        return params;\n    },\n\n    _defaultLabelLine: function (option) {\n        // Extend labelLine emphasis\n        defaultEmphasis(option, 'labelLine', ['show']);\n\n        var labelLineNormalOpt = option.labelLine;\n        var labelLineEmphasisOpt = option.emphasis.labelLine;\n        // Not show label line if `label.normal.show = false`\n        labelLineNormalOpt.show = labelLineNormalOpt.show\n            && option.label.show;\n        labelLineEmphasisOpt.show = labelLineEmphasisOpt.show\n            && option.emphasis.label.show;\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // 默认全局居中\n        center: ['50%', '50%'],\n        radius: [0, '75%'],\n        // 默认顺时针\n        clockwise: true,\n        startAngle: 90,\n        // 最小角度改为0\n        minAngle: 0,\n        // 选中时扇区偏移量\n        selectedOffset: 10,\n        // 高亮扇区偏移量\n        hoverOffset: 10,\n\n        // If use strategy to avoid label overlapping\n        avoidLabelOverlap: true,\n        // 选择模式，默认关闭，可选single，multiple\n        // selectedMode: false,\n        // 南丁格尔玫瑰图模式，'radius'（半径） | 'area'（面积）\n        // roseType: null,\n\n        percentPrecision: 2,\n\n        // If still show when all data zero.\n        stillShowZeroSum: true,\n\n        // cursor: null,\n\n        label: {\n            // If rotate around circle\n            rotate: false,\n            show: true,\n            // 'outer', 'inside', 'center'\n            position: 'outer'\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n            // 默认使用全局文本样式，详见TEXTSTYLE\n            // distance: 当position为inner时有效，为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数\n        },\n        // Enabled when label.normal.position is 'outer'\n        labelLine: {\n            show: true,\n            // 引导线两段中的第一段长度\n            length: 15,\n            // 引导线两段中的第二段长度\n            length2: 15,\n            smooth: false,\n            lineStyle: {\n                // color: 各异,\n                width: 1,\n                type: 'solid'\n            }\n        },\n        itemStyle: {\n            borderWidth: 1\n        },\n\n        // Animation type canbe expansion, scale\n        animationType: 'expansion',\n\n        animationEasing: 'cubicOut'\n    }\n});\n\nmixin(PieSeries, selectableMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/model/Series} seriesModel\n * @param {boolean} hasAnimation\n * @inner\n */\nfunction updateDataSelected(uid, seriesModel, hasAnimation, api) {\n    var data = seriesModel.getData();\n    var dataIndex = this.dataIndex;\n    var name = data.getName(dataIndex);\n    var selectedOffset = seriesModel.get('selectedOffset');\n\n    api.dispatchAction({\n        type: 'pieToggleSelect',\n        from: uid,\n        name: name,\n        seriesId: seriesModel.id\n    });\n\n    data.each(function (idx) {\n        toggleItemSelected(\n            data.getItemGraphicEl(idx),\n            data.getItemLayout(idx),\n            seriesModel.isSelected(data.getName(idx)),\n            selectedOffset,\n            hasAnimation\n        );\n    });\n}\n\n/**\n * @param {module:zrender/graphic/Sector} el\n * @param {Object} layout\n * @param {boolean} isSelected\n * @param {number} selectedOffset\n * @param {boolean} hasAnimation\n * @inner\n */\nfunction toggleItemSelected(el, layout, isSelected, selectedOffset, hasAnimation) {\n    var midAngle = (layout.startAngle + layout.endAngle) / 2;\n\n    var dx = Math.cos(midAngle);\n    var dy = Math.sin(midAngle);\n\n    var offset = isSelected ? selectedOffset : 0;\n    var position = [dx * offset, dy * offset];\n\n    hasAnimation\n        // animateTo will stop revious animation like update transition\n        ? el.animate()\n            .when(200, {\n                position: position\n            })\n            .start('bounceOut')\n        : el.attr('position', position);\n}\n\n/**\n * Piece of pie including Sector, Label, LabelLine\n * @constructor\n * @extends {module:zrender/graphic/Group}\n */\nfunction PiePiece(data, idx) {\n\n    Group.call(this);\n\n    var sector = new Sector({\n        z2: 2\n    });\n    var polyline = new Polyline();\n    var text = new Text();\n    this.add(sector);\n    this.add(polyline);\n    this.add(text);\n\n    this.updateData(data, idx, true);\n\n    // Hover to change label and labelLine\n    function onEmphasis() {\n        polyline.ignore = polyline.hoverIgnore;\n        text.ignore = text.hoverIgnore;\n    }\n    function onNormal() {\n        polyline.ignore = polyline.normalIgnore;\n        text.ignore = text.normalIgnore;\n    }\n    this.on('emphasis', onEmphasis)\n        .on('normal', onNormal)\n        .on('mouseover', onEmphasis)\n        .on('mouseout', onNormal);\n}\n\nvar piePieceProto = PiePiece.prototype;\n\npiePieceProto.updateData = function (data, idx, firstCreate) {\n\n    var sector = this.childAt(0);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var sectorShape = extend({}, layout);\n    sectorShape.label = null;\n\n    if (firstCreate) {\n        sector.setShape(sectorShape);\n\n        var animationType = seriesModel.getShallow('animationType');\n        if (animationType === 'scale') {\n            sector.shape.r = layout.r0;\n            initProps(sector, {\n                shape: {\n                    r: layout.r\n                }\n            }, seriesModel, idx);\n        }\n        // Expansion\n        else {\n            sector.shape.endAngle = layout.startAngle;\n            updateProps(sector, {\n                shape: {\n                    endAngle: layout.endAngle\n                }\n            }, seriesModel, idx);\n        }\n\n    }\n    else {\n        updateProps(sector, {\n            shape: sectorShape\n        }, seriesModel, idx);\n    }\n\n    // Update common style\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    sector.useStyle(\n        defaults(\n            {\n                lineJoin: 'bevel',\n                fill: visualColor\n            },\n            itemModel.getModel('itemStyle').getItemStyle()\n        )\n    );\n    sector.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && sector.attr('cursor', cursorStyle);\n\n    // Toggle selected\n    toggleItemSelected(\n        this,\n        data.getItemLayout(idx),\n        seriesModel.isSelected(null, idx),\n        seriesModel.get('selectedOffset'),\n        seriesModel.get('animation')\n    );\n\n    function onEmphasis() {\n        // Sector may has animation of updating data. Force to move to the last frame\n        // Or it may stopped on the wrong shape\n        sector.stopAnimation(true);\n        sector.animateTo({\n            shape: {\n                r: layout.r + seriesModel.get('hoverOffset')\n            }\n        }, 300, 'elasticOut');\n    }\n    function onNormal() {\n        sector.stopAnimation(true);\n        sector.animateTo({\n            shape: {\n                r: layout.r\n            }\n        }, 300, 'elasticOut');\n    }\n    sector.off('mouseover').off('mouseout').off('emphasis').off('normal');\n    if (itemModel.get('hoverAnimation') && seriesModel.isAnimationEnabled()) {\n        sector\n            .on('mouseover', onEmphasis)\n            .on('mouseout', onNormal)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal);\n    }\n\n    this._updateLabel(data, idx);\n\n    setHoverStyle(this);\n};\n\npiePieceProto._updateLabel = function (data, idx) {\n\n    var labelLine = this.childAt(1);\n    var labelText = this.childAt(2);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var labelLayout = layout.label;\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    updateProps(labelLine, {\n        shape: {\n            points: labelLayout.linePoints || [\n                [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y]\n            ]\n        }\n    }, seriesModel, idx);\n\n    updateProps(labelText, {\n        style: {\n            x: labelLayout.x,\n            y: labelLayout.y\n        }\n    }, seriesModel, idx);\n    labelText.attr({\n        rotation: labelLayout.rotation,\n        origin: [labelLayout.x, labelLayout.y],\n        z2: 10\n    });\n\n    var labelModel = itemModel.getModel('label');\n    var labelHoverModel = itemModel.getModel('emphasis.label');\n    var labelLineModel = itemModel.getModel('labelLine');\n    var labelLineHoverModel = itemModel.getModel('emphasis.labelLine');\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    setLabelStyle(\n        labelText.style, labelText.hoverStyle = {}, labelModel, labelHoverModel,\n        {\n            labelFetcher: data.hostModel,\n            labelDataIndex: idx,\n            defaultText: data.getName(idx),\n            autoColor: visualColor,\n            useInsideStyle: !!labelLayout.inside\n        },\n        {\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.verticalAlign,\n            opacity: data.getItemVisual(idx, 'opacity')\n        }\n    );\n\n    labelText.ignore = labelText.normalIgnore = !labelModel.get('show');\n    labelText.hoverIgnore = !labelHoverModel.get('show');\n\n    labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show');\n    labelLine.hoverIgnore = !labelLineHoverModel.get('show');\n\n    // Default use item visual color\n    labelLine.setStyle({\n        stroke: visualColor,\n        opacity: data.getItemVisual(idx, 'opacity')\n    });\n    labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());\n\n    labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();\n\n    var smooth = labelLineModel.get('smooth');\n    if (smooth && smooth === true) {\n        smooth = 0.4;\n    }\n    labelLine.setShape({\n        smooth: smooth\n    });\n};\n\ninherits(PiePiece, Group);\n\n\n// Pie view\nvar PieView = Chart.extend({\n\n    type: 'pie',\n\n    init: function () {\n        var sectorGroup = new Group();\n        this._sectorGroup = sectorGroup;\n    },\n\n    render: function (seriesModel, ecModel, api, payload) {\n        if (payload && (payload.from === this.uid)) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var oldData = this._data;\n        var group = this.group;\n\n        var hasAnimation = ecModel.get('animation');\n        var isFirstRender = !oldData;\n        var animationType = seriesModel.get('animationType');\n\n        var onSectorClick = curry(\n            updateDataSelected, this.uid, seriesModel, hasAnimation, api\n        );\n\n        var selectedMode = seriesModel.get('selectedMode');\n\n        data.diff(oldData)\n            .add(function (idx) {\n                var piePiece = new PiePiece(data, idx);\n                // Default expansion animation\n                if (isFirstRender && animationType !== 'scale') {\n                    piePiece.eachChild(function (child) {\n                        child.stopAnimation(true);\n                    });\n                }\n\n                selectedMode && piePiece.on('click', onSectorClick);\n\n                data.setItemGraphicEl(idx, piePiece);\n\n                group.add(piePiece);\n            })\n            .update(function (newIdx, oldIdx) {\n                var piePiece = oldData.getItemGraphicEl(oldIdx);\n\n                piePiece.updateData(data, newIdx);\n\n                piePiece.off('click');\n                selectedMode && piePiece.on('click', onSectorClick);\n                group.add(piePiece);\n                data.setItemGraphicEl(newIdx, piePiece);\n            })\n            .remove(function (idx) {\n                var piePiece = oldData.getItemGraphicEl(idx);\n                group.remove(piePiece);\n            })\n            .execute();\n\n        if (\n            hasAnimation && isFirstRender && data.count() > 0\n            // Default expansion animation\n            && animationType !== 'scale'\n        ) {\n            var shape = data.getItemLayout(0);\n            var r = Math.max(api.getWidth(), api.getHeight()) / 2;\n\n            var removeClipPath = bind(group.removeClipPath, group);\n            group.setClipPath(this._createClipPath(\n                shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel\n            ));\n        }\n        else {\n            // clipPath is used in first-time animation, so remove it when otherwise. See: #8994\n            group.removeClipPath();\n        }\n\n        this._data = data;\n    },\n\n    dispose: function () {},\n\n    _createClipPath: function (\n        cx, cy, r, startAngle, clockwise, cb, seriesModel\n    ) {\n        var clipPath = new Sector({\n            shape: {\n                cx: cx,\n                cy: cy,\n                r0: 0,\n                r: r,\n                startAngle: startAngle,\n                endAngle: startAngle,\n                clockwise: clockwise\n            }\n        });\n\n        initProps(clipPath, {\n            shape: {\n                endAngle: startAngle + (clockwise ? 1 : -1) * Math.PI * 2\n            }\n        }, seriesModel, cb);\n\n        return clipPath;\n    },\n\n    /**\n     * @implement\n     */\n    containPoint: function (point, seriesModel) {\n        var data = seriesModel.getData();\n        var itemLayout = data.getItemLayout(0);\n        if (itemLayout) {\n            var dx = point[0] - itemLayout.cx;\n            var dy = point[1] - itemLayout.cy;\n            var radius = Math.sqrt(dx * dx + dy * dy);\n            return radius <= itemLayout.r && radius >= itemLayout.r0;\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar createDataSelectAction = function (seriesType, actionInfos) {\n    each$1(actionInfos, function (actionInfo) {\n        actionInfo.update = 'updateView';\n        /**\n         * @payload\n         * @property {string} seriesName\n         * @property {string} name\n         */\n        registerAction(actionInfo, function (payload, ecModel) {\n            var selected = {};\n            ecModel.eachComponent(\n                {mainType: 'series', subType: seriesType, query: payload},\n                function (seriesModel) {\n                    if (seriesModel[actionInfo.method]) {\n                        seriesModel[actionInfo.method](\n                            payload.name,\n                            payload.dataIndex\n                        );\n                    }\n                    var data = seriesModel.getData();\n                    // Create selected map\n                    data.each(function (idx) {\n                        var name = data.getName(idx);\n                        selected[name] = seriesModel.isSelected(name)\n                            || false;\n                    });\n                }\n            );\n            return {\n                name: payload.name,\n                selected: selected\n            };\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Pick color from palette for each data item.\n// Applicable for charts that require applying color palette\n// in data level (like pie, funnel, chord).\nvar dataColor = function (seriesType) {\n    return {\n        getTargetSeries: function (ecModel) {\n            // Pie and funnel may use diferrent scope\n            var paletteScope = {};\n            var seiresModelMap = createHashMap();\n\n            ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n                seriesModel.__paletteScope = paletteScope;\n                seiresModelMap.set(seriesModel.uid, seriesModel);\n            });\n\n            return seiresModelMap;\n        },\n        reset: function (seriesModel, ecModel) {\n            var dataAll = seriesModel.getRawData();\n            var idxMap = {};\n            var data = seriesModel.getData();\n\n            data.each(function (idx) {\n                var rawIdx = data.getRawIndex(idx);\n                idxMap[rawIdx] = idx;\n            });\n\n            dataAll.each(function (rawIdx) {\n                var filteredIdx = idxMap[rawIdx];\n\n                // If series.itemStyle.normal.color is a function. itemVisual may be encoded\n                var singleDataColor = filteredIdx != null\n                    && data.getItemVisual(filteredIdx, 'color', true);\n\n                if (!singleDataColor) {\n                    // FIXME Performance\n                    var itemModel = dataAll.getItemModel(rawIdx);\n\n                    var color = itemModel.get('itemStyle.color')\n                        || seriesModel.getColorFromPalette(\n                            dataAll.getName(rawIdx) || (rawIdx + ''), seriesModel.__paletteScope,\n                            dataAll.count()\n                        );\n                    // Legend may use the visual info in data before processed\n                    dataAll.setItemVisual(rawIdx, 'color', color);\n\n                    // Data is not filtered\n                    if (filteredIdx != null) {\n                        data.setItemVisual(filteredIdx, 'color', color);\n                    }\n                }\n                else {\n                    // Set data all color for legend\n                    dataAll.setItemVisual(rawIdx, 'color', singleDataColor);\n                }\n            });\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME emphasis label position is not same with normal label position\n\nfunction adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {\n    list.sort(function (a, b) {\n        return a.y - b.y;\n    });\n\n    function shiftDown(start, end, delta, dir) {\n        for (var j = start; j < end; j++) {\n            list[j].y += delta;\n            if (j > start\n                && j + 1 < end\n                && list[j + 1].y > list[j].y + list[j].height\n            ) {\n                shiftUp(j, delta / 2);\n                return;\n            }\n        }\n\n        shiftUp(end - 1, delta / 2);\n    }\n\n    function shiftUp(end, delta) {\n        for (var j = end; j >= 0; j--) {\n            list[j].y -= delta;\n            if (j > 0\n                && list[j].y > list[j - 1].y + list[j - 1].height\n            ) {\n                break;\n            }\n        }\n    }\n\n    function changeX(list, isDownList, cx, cy, r, dir) {\n        var lastDeltaX = dir > 0\n            ? isDownList                // right-side\n                ? Number.MAX_VALUE      // down\n                : 0                     // up\n            : isDownList                // left-side\n                ? Number.MAX_VALUE      // down\n                : 0;                    // up\n\n        for (var i = 0, l = list.length; i < l; i++) {\n            var deltaY = Math.abs(list[i].y - cy);\n            var length = list[i].len;\n            var length2 = list[i].len2;\n            var deltaX = (deltaY < r + length)\n                ? Math.sqrt(\n                        (r + length + length2) * (r + length + length2)\n                        - deltaY * deltaY\n                    )\n                : Math.abs(list[i].x - cx);\n            if (isDownList && deltaX >= lastDeltaX) {\n                // right-down, left-down\n                deltaX = lastDeltaX - 10;\n            }\n            if (!isDownList && deltaX <= lastDeltaX) {\n                // right-up, left-up\n                deltaX = lastDeltaX + 10;\n            }\n\n            list[i].x = cx + deltaX * dir;\n            lastDeltaX = deltaX;\n        }\n    }\n\n    var lastY = 0;\n    var delta;\n    var len = list.length;\n    var upList = [];\n    var downList = [];\n    for (var i = 0; i < len; i++) {\n        delta = list[i].y - lastY;\n        if (delta < 0) {\n            shiftDown(i, len, -delta, dir);\n        }\n        lastY = list[i].y + list[i].height;\n    }\n    if (viewHeight - lastY < 0) {\n        shiftUp(len - 1, lastY - viewHeight);\n    }\n    for (var i = 0; i < len; i++) {\n        if (list[i].y >= cy) {\n            downList.push(list[i]);\n        }\n        else {\n            upList.push(list[i]);\n        }\n    }\n    changeX(upList, false, cx, cy, r, dir);\n    changeX(downList, true, cx, cy, r, dir);\n}\n\nfunction avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) {\n    var leftList = [];\n    var rightList = [];\n    for (var i = 0; i < labelLayoutList.length; i++) {\n        if (isPositionCenter(labelLayoutList[i])) {\n            continue;\n        }\n        if (labelLayoutList[i].x < cx) {\n            leftList.push(labelLayoutList[i]);\n        }\n        else {\n            rightList.push(labelLayoutList[i]);\n        }\n    }\n\n    adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight);\n    adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight);\n\n    for (var i = 0; i < labelLayoutList.length; i++) {\n        if (isPositionCenter(labelLayoutList[i])) {\n            continue;\n        }\n        var linePoints = labelLayoutList[i].linePoints;\n        if (linePoints) {\n            var dist = linePoints[1][0] - linePoints[2][0];\n            if (labelLayoutList[i].x < cx) {\n                linePoints[2][0] = labelLayoutList[i].x + 3;\n            }\n            else {\n                linePoints[2][0] = labelLayoutList[i].x - 3;\n            }\n            linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y;\n            linePoints[1][0] = linePoints[2][0] + dist;\n        }\n    }\n}\n\nfunction isPositionCenter(layout) {\n    // Not change x for center label\n    return layout.position === 'center';\n}\n\nvar labelLayout = function (seriesModel, r, viewWidth, viewHeight) {\n    var data = seriesModel.getData();\n    var labelLayoutList = [];\n    var cx;\n    var cy;\n    var hasLabelRotate = false;\n\n    data.each(function (idx) {\n        var layout = data.getItemLayout(idx);\n\n        var itemModel = data.getItemModel(idx);\n        var labelModel = itemModel.getModel('label');\n        // Use position in normal or emphasis\n        var labelPosition = labelModel.get('position') || itemModel.get('emphasis.label.position');\n\n        var labelLineModel = itemModel.getModel('labelLine');\n        var labelLineLen = labelLineModel.get('length');\n        var labelLineLen2 = labelLineModel.get('length2');\n\n        var midAngle = (layout.startAngle + layout.endAngle) / 2;\n        var dx = Math.cos(midAngle);\n        var dy = Math.sin(midAngle);\n\n        var textX;\n        var textY;\n        var linePoints;\n        var textAlign;\n\n        cx = layout.cx;\n        cy = layout.cy;\n\n        var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';\n        if (labelPosition === 'center') {\n            textX = layout.cx;\n            textY = layout.cy;\n            textAlign = 'center';\n        }\n        else {\n            var x1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dx : layout.r * dx) + cx;\n            var y1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dy : layout.r * dy) + cy;\n\n            textX = x1 + dx * 3;\n            textY = y1 + dy * 3;\n\n            if (!isLabelInside) {\n                // For roseType\n                var x2 = x1 + dx * (labelLineLen + r - layout.r);\n                var y2 = y1 + dy * (labelLineLen + r - layout.r);\n                var x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2);\n                var y3 = y2;\n\n                textX = x3 + (dx < 0 ? -5 : 5);\n                textY = y3;\n                linePoints = [[x1, y1], [x2, y2], [x3, y3]];\n            }\n\n            textAlign = isLabelInside ? 'center' : (dx > 0 ? 'left' : 'right');\n        }\n        var font = labelModel.getFont();\n\n        var labelRotate = labelModel.get('rotate')\n            ? (dx < 0 ? -midAngle + Math.PI : -midAngle) : 0;\n        var text = seriesModel.getFormattedLabel(idx, 'normal')\n                    || data.getName(idx);\n        var textRect = getBoundingRect(\n            text, font, textAlign, 'top'\n        );\n        hasLabelRotate = !!labelRotate;\n        layout.label = {\n            x: textX,\n            y: textY,\n            position: labelPosition,\n            height: textRect.height,\n            len: labelLineLen,\n            len2: labelLineLen2,\n            linePoints: linePoints,\n            textAlign: textAlign,\n            verticalAlign: 'middle',\n            rotation: labelRotate,\n            inside: isLabelInside\n        };\n\n        // Not layout the inside label\n        if (!isLabelInside) {\n            labelLayoutList.push(layout.label);\n        }\n    });\n    if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {\n        avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar PI2$4 = Math.PI * 2;\nvar RADIAN = Math.PI / 180;\n\nvar pieLayout = function (seriesType, ecModel, api, payload) {\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n\n        var center = seriesModel.get('center');\n        var radius = seriesModel.get('radius');\n\n        if (!isArray(radius)) {\n            radius = [0, radius];\n        }\n        if (!isArray(center)) {\n            center = [center, center];\n        }\n\n        var width = api.getWidth();\n        var height = api.getHeight();\n        var size = Math.min(width, height);\n        var cx = parsePercent$1(center[0], width);\n        var cy = parsePercent$1(center[1], height);\n        var r0 = parsePercent$1(radius[0], size / 2);\n        var r = parsePercent$1(radius[1], size / 2);\n\n        var startAngle = -seriesModel.get('startAngle') * RADIAN;\n\n        var minAngle = seriesModel.get('minAngle') * RADIAN;\n\n        var validDataCount = 0;\n        data.each(valueDim, function (value) {\n            !isNaN(value) && validDataCount++;\n        });\n\n        var sum = data.getSum(valueDim);\n        // Sum may be 0\n        var unitRadian = Math.PI / (sum || validDataCount) * 2;\n\n        var clockwise = seriesModel.get('clockwise');\n\n        var roseType = seriesModel.get('roseType');\n        var stillShowZeroSum = seriesModel.get('stillShowZeroSum');\n\n        // [0...max]\n        var extent = data.getDataExtent(valueDim);\n        extent[0] = 0;\n\n        // In the case some sector angle is smaller than minAngle\n        var restAngle = PI2$4;\n        var valueSumLargerThanMinAngle = 0;\n\n        var currentAngle = startAngle;\n        var dir = clockwise ? 1 : -1;\n\n        data.each(valueDim, function (value, idx) {\n            var angle;\n            if (isNaN(value)) {\n                data.setItemLayout(idx, {\n                    angle: NaN,\n                    startAngle: NaN,\n                    endAngle: NaN,\n                    clockwise: clockwise,\n                    cx: cx,\n                    cy: cy,\n                    r0: r0,\n                    r: roseType\n                        ? NaN\n                        : r\n                });\n                return;\n            }\n\n            // FIXME 兼容 2.0 但是 roseType 是 area 的时候才是这样？\n            if (roseType !== 'area') {\n                angle = (sum === 0 && stillShowZeroSum)\n                    ? unitRadian : (value * unitRadian);\n            }\n            else {\n                angle = PI2$4 / validDataCount;\n            }\n\n            if (angle < minAngle) {\n                angle = minAngle;\n                restAngle -= minAngle;\n            }\n            else {\n                valueSumLargerThanMinAngle += value;\n            }\n\n            var endAngle = currentAngle + dir * angle;\n            data.setItemLayout(idx, {\n                angle: angle,\n                startAngle: currentAngle,\n                endAngle: endAngle,\n                clockwise: clockwise,\n                cx: cx,\n                cy: cy,\n                r0: r0,\n                r: roseType\n                    ? linearMap(value, extent, [r0, r])\n                    : r\n            });\n\n            currentAngle = endAngle;\n        });\n\n        // Some sector is constrained by minAngle\n        // Rest sectors needs recalculate angle\n        if (restAngle < PI2$4 && validDataCount) {\n            // Average the angle if rest angle is not enough after all angles is\n            // Constrained by minAngle\n            if (restAngle <= 1e-3) {\n                var angle = PI2$4 / validDataCount;\n                data.each(valueDim, function (value, idx) {\n                    if (!isNaN(value)) {\n                        var layout = data.getItemLayout(idx);\n                        layout.angle = angle;\n                        layout.startAngle = startAngle + dir * idx * angle;\n                        layout.endAngle = startAngle + dir * (idx + 1) * angle;\n                    }\n                });\n            }\n            else {\n                unitRadian = restAngle / valueSumLargerThanMinAngle;\n                currentAngle = startAngle;\n                data.each(valueDim, function (value, idx) {\n                    if (!isNaN(value)) {\n                        var layout = data.getItemLayout(idx);\n                        var angle = layout.angle === minAngle\n                            ? minAngle : value * unitRadian;\n                        layout.startAngle = currentAngle;\n                        layout.endAngle = currentAngle + dir * angle;\n                        currentAngle += dir * angle;\n                    }\n                });\n            }\n        }\n\n        labelLayout(seriesModel, r, width, height);\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar dataFilter = function (seriesType) {\n    return {\n        seriesType: seriesType,\n        reset: function (seriesModel, ecModel) {\n            var legendModels = ecModel.findComponents({\n                mainType: 'legend'\n            });\n            if (!legendModels || !legendModels.length) {\n                return;\n            }\n            var data = seriesModel.getData();\n            data.filterSelf(function (idx) {\n                var name = data.getName(idx);\n                // If in any legend component the status is not selected.\n                for (var i = 0; i < legendModels.length; i++) {\n                    if (!legendModels[i].isSelected(name)) {\n                        return false;\n                    }\n                }\n                return true;\n            });\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\ncreateDataSelectAction('pie', [{\n    type: 'pieToggleSelect',\n    event: 'pieselectchanged',\n    method: 'toggleSelected'\n}, {\n    type: 'pieSelect',\n    event: 'pieselected',\n    method: 'select'\n}, {\n    type: 'pieUnSelect',\n    event: 'pieunselected',\n    method: 'unSelect'\n}]);\n\nregisterVisual(dataColor('pie'));\nregisterLayout(curry(pieLayout, 'pie'));\nregisterProcessor(dataFilter('pie'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.scatter',\n\n    dependencies: ['grid', 'polar', 'geo', 'singleAxis', 'calendar'],\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    brushSelector: 'point',\n\n    getProgressive: function () {\n        var progressive = this.option.progressive;\n        if (progressive == null) {\n            // PENDING\n            return this.option.large ? 5e3 : this.get('progressive');\n        }\n        return progressive;\n    },\n\n    getProgressiveThreshold: function () {\n        var progressiveThreshold = this.option.progressiveThreshold;\n        if (progressiveThreshold == null) {\n            // PENDING\n            return this.option.large ? 1e4 : this.get('progressiveThreshold');\n        }\n        return progressiveThreshold;\n    },\n\n    defaultOption: {\n        coordinateSystem: 'cartesian2d',\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // Polar coordinate system\n        // polarIndex: 0,\n\n        // Geo coordinate system\n        // geoIndex: 0,\n\n        // symbol: null,        // 图形类型\n        symbolSize: 10,          // 图形大小，半宽（半径）参数，当图形为方向或菱形则总宽度为symbolSize * 2\n        // symbolRotate: null,  // 图形旋转控制\n\n        large: false,\n        // Available when large is true\n        largeThreshold: 2000,\n        // cursor: null,\n\n        // label: {\n            // show: false\n            // distance: 5,\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n            // position: 默认自适应，水平布局为'top'，垂直布局为'right'，可选为\n            //           'inside'|'left'|'right'|'top'|'bottom'\n            // 默认使用全局文本样式，详见TEXTSTYLE\n        // },\n        itemStyle: {\n            opacity: 0.8\n            // color: 各异\n        }\n\n        // progressive: null\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\n// TODO Batch by color\n\nvar BOOST_SIZE_THRESHOLD = 4;\n\nvar LargeSymbolPath = extendShape({\n\n    shape: {\n        points: null\n    },\n\n    symbolProxy: null,\n\n    buildPath: function (path, shape) {\n        var points = shape.points;\n        var size = shape.size;\n\n        var symbolProxy = this.symbolProxy;\n        var symbolProxyShape = symbolProxy.shape;\n        var ctx = path.getContext ? path.getContext() : path;\n        var canBoost = ctx && size[0] < BOOST_SIZE_THRESHOLD;\n\n        // Do draw in afterBrush.\n        if (canBoost) {\n            return;\n        }\n\n        for (var i = 0; i < points.length;) {\n            var x = points[i++];\n            var y = points[i++];\n\n            if (isNaN(x) || isNaN(y)) {\n                continue;\n            }\n\n            symbolProxyShape.x = x - size[0] / 2;\n            symbolProxyShape.y = y - size[1] / 2;\n            symbolProxyShape.width = size[0];\n            symbolProxyShape.height = size[1];\n\n            symbolProxy.buildPath(path, symbolProxyShape, true);\n        }\n    },\n\n    afterBrush: function (ctx) {\n        var shape = this.shape;\n        var points = shape.points;\n        var size = shape.size;\n        var canBoost = size[0] < BOOST_SIZE_THRESHOLD;\n\n        if (!canBoost) {\n            return;\n        }\n\n        this.setTransform(ctx);\n        // PENDING If style or other canvas status changed?\n        for (var i = 0; i < points.length;) {\n            var x = points[i++];\n            var y = points[i++];\n            if (isNaN(x) || isNaN(y)) {\n                continue;\n            }\n            // fillRect is faster than building a rect path and draw.\n            // And it support light globalCompositeOperation.\n            ctx.fillRect(\n                x - size[0] / 2, y - size[1] / 2,\n                size[0], size[1]\n            );\n        }\n\n        this.restoreTransform(ctx);\n    },\n\n    findDataIndex: function (x, y) {\n        // TODO ???\n        // Consider transform\n\n        var shape = this.shape;\n        var points = shape.points;\n        var size = shape.size;\n\n        var w = Math.max(size[0], 4);\n        var h = Math.max(size[1], 4);\n\n        // Not consider transform\n        // Treat each element as a rect\n        // top down traverse\n        for (var idx = points.length / 2 - 1; idx >= 0; idx--) {\n            var i = idx * 2;\n            var x0 = points[i] - w / 2;\n            var y0 = points[i + 1] - h / 2;\n            if (x >= x0 && y >= y0 && x <= x0 + w && y <= y0 + h) {\n                return idx;\n            }\n        }\n\n        return -1;\n    }\n});\n\nfunction LargeSymbolDraw() {\n    this.group = new Group();\n}\n\nvar largeSymbolProto = LargeSymbolDraw.prototype;\n\nlargeSymbolProto.isPersistent = function () {\n    return !this._incremental;\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n */\nlargeSymbolProto.updateData = function (data) {\n    this.group.removeAll();\n    var symbolEl = new LargeSymbolPath({\n        rectHover: true,\n        cursor: 'default'\n    });\n\n    symbolEl.setShape({\n        points: data.getLayout('symbolPoints')\n    });\n    this._setCommon(symbolEl, data);\n    this.group.add(symbolEl);\n\n    this._incremental = null;\n};\n\nlargeSymbolProto.updateLayout = function (data) {\n    if (this._incremental) {\n        return;\n    }\n\n    var points = data.getLayout('symbolPoints');\n    this.group.eachChild(function (child) {\n        if (child.startIndex != null) {\n            var len = (child.endIndex - child.startIndex) * 2;\n            var byteOffset = child.startIndex * 4 * 2;\n            points = new Float32Array(points.buffer, byteOffset, len);\n        }\n        child.setShape('points', points);\n    });\n};\n\nlargeSymbolProto.incrementalPrepareUpdate = function (data) {\n    this.group.removeAll();\n\n    this._clearIncremental();\n    // Only use incremental displayables when data amount is larger than 2 million.\n    // PENDING Incremental data?\n    if (data.count() > 2e6) {\n        if (!this._incremental) {\n            this._incremental = new IncrementalDisplayble({\n                silent: true\n            });\n        }\n        this.group.add(this._incremental);\n    }\n    else {\n        this._incremental = null;\n    }\n};\n\nlargeSymbolProto.incrementalUpdate = function (taskParams, data) {\n    var symbolEl;\n    if (this._incremental) {\n        symbolEl = new LargeSymbolPath();\n        this._incremental.addDisplayable(symbolEl, true);\n    }\n    else {\n        symbolEl = new LargeSymbolPath({\n            rectHover: true,\n            cursor: 'default',\n            startIndex: taskParams.start,\n            endIndex: taskParams.end\n        });\n        symbolEl.incremental = true;\n        this.group.add(symbolEl);\n    }\n\n    symbolEl.setShape({\n        points: data.getLayout('symbolPoints')\n    });\n    this._setCommon(symbolEl, data, !!this._incremental);\n};\n\nlargeSymbolProto._setCommon = function (symbolEl, data, isIncremental) {\n    var hostModel = data.hostModel;\n\n    // TODO\n    // if (data.hasItemVisual.symbolSize) {\n    //     // TODO typed array?\n    //     symbolEl.setShape('sizes', data.mapArray(\n    //         function (idx) {\n    //             var size = data.getItemVisual(idx, 'symbolSize');\n    //             return (size instanceof Array) ? size : [size, size];\n    //         }\n    //     ));\n    // }\n    // else {\n    var size = data.getVisual('symbolSize');\n    symbolEl.setShape('size', (size instanceof Array) ? size : [size, size]);\n    // }\n\n    // Create symbolProxy to build path for each data\n    symbolEl.symbolProxy = createSymbol(\n        data.getVisual('symbol'), 0, 0, 0, 0\n    );\n    // Use symbolProxy setColor method\n    symbolEl.setColor = symbolEl.symbolProxy.setColor;\n\n    var extrudeShadow = symbolEl.shape.size[0] < BOOST_SIZE_THRESHOLD;\n    symbolEl.useStyle(\n        // Draw shadow when doing fillRect is extremely slow.\n        hostModel.getModel('itemStyle').getItemStyle(extrudeShadow ? ['color', 'shadowBlur', 'shadowColor'] : ['color'])\n    );\n\n    var visualColor = data.getVisual('color');\n    if (visualColor) {\n        symbolEl.setColor(visualColor);\n    }\n\n    if (!isIncremental) {\n        // Enable tooltip\n        // PENDING May have performance issue when path is extremely large\n        symbolEl.seriesIndex = hostModel.seriesIndex;\n        symbolEl.on('mousemove', function (e) {\n            symbolEl.dataIndex = null;\n            var dataIndex = symbolEl.findDataIndex(e.offsetX, e.offsetY);\n            if (dataIndex >= 0) {\n                // Provide dataIndex for tooltip\n                symbolEl.dataIndex = dataIndex + (symbolEl.startIndex || 0);\n            }\n        });\n    }\n};\n\nlargeSymbolProto.remove = function () {\n    this._clearIncremental();\n    this._incremental = null;\n    this.group.removeAll();\n};\n\nlargeSymbolProto._clearIncremental = function () {\n    var incremental = this._incremental;\n    if (incremental) {\n        incremental.clearDisplaybles();\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendChartView({\n\n    type: 'scatter',\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        var symbolDraw = this._updateSymbolDraw(data, seriesModel);\n        symbolDraw.updateData(data);\n\n        this._finished = true;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var symbolDraw = this._updateSymbolDraw(data, seriesModel);\n\n        symbolDraw.incrementalPrepareUpdate(data);\n\n        this._finished = false;\n    },\n\n    incrementalRender: function (taskParams, seriesModel, ecModel) {\n        this._symbolDraw.incrementalUpdate(taskParams, seriesModel.getData());\n\n        this._finished = taskParams.end === seriesModel.getData().count();\n    },\n\n    updateTransform: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        // Must mark group dirty and make sure the incremental layer will be cleared\n        // PENDING\n        this.group.dirty();\n\n        if (!this._finished || data.count() > 1e4 || !this._symbolDraw.isPersistent()) {\n            return {\n                update: true\n            };\n        }\n        else {\n            var res = pointsLayout().reset(seriesModel);\n            if (res.progress) {\n                res.progress({ start: 0, end: data.count() }, data);\n            }\n\n            this._symbolDraw.updateLayout(data);\n        }\n    },\n\n    _updateSymbolDraw: function (data, seriesModel) {\n        var symbolDraw = this._symbolDraw;\n        var pipelineContext = seriesModel.pipelineContext;\n        var isLargeDraw = pipelineContext.large;\n\n        if (!symbolDraw || isLargeDraw !== this._isLargeDraw) {\n            symbolDraw && symbolDraw.remove();\n            symbolDraw = this._symbolDraw = isLargeDraw\n                ? new LargeSymbolDraw()\n                : new SymbolDraw();\n            this._isLargeDraw = isLargeDraw;\n            this.group.removeAll();\n        }\n\n        this.group.add(symbolDraw.group);\n\n        return symbolDraw;\n    },\n\n    remove: function (ecModel, api) {\n        this._symbolDraw && this._symbolDraw.remove(true);\n        this._symbolDraw = null;\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import * as zrUtil from 'zrender/src/core/util';\n\n// In case developer forget to include grid component\nregisterVisual(visualSymbol('scatter', 'circle'));\nregisterLayout(pointsLayout('scatter'));\n\n// echarts.registerProcessor(function (ecModel, api) {\n//     ecModel.eachSeriesByType('scatter', function (seriesModel) {\n//         var data = seriesModel.getData();\n//         var coordSys = seriesModel.coordinateSystem;\n//         if (coordSys.type !== 'geo') {\n//             return;\n//         }\n//         var startPt = coordSys.pointToData([0, 0]);\n//         var endPt = coordSys.pointToData([api.getWidth(), api.getHeight()]);\n\n//         var dims = zrUtil.map(coordSys.dimensions, function (dim) {\n//             return data.mapDimension(dim);\n//         });\n//         var range = {};\n//         range[dims[0]] = [Math.min(startPt[0], endPt[0]), Math.max(startPt[0], endPt[0])];\n//         range[dims[1]] = [Math.min(startPt[1], endPt[1]), Math.max(startPt[1], endPt[1])];\n\n//         data.selectRange(range);\n//     });\n// });\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction IndicatorAxis(dim, scale, radiusExtent) {\n    Axis.call(this, dim, scale, radiusExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = 'value';\n\n    this.angle = 0;\n\n    /**\n     * Indicator name\n     * @type {string}\n     */\n    this.name = '';\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.model;\n}\n\ninherits(IndicatorAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO clockwise\n\nfunction Radar(radarModel, ecModel, api) {\n\n    this._model = radarModel;\n    /**\n     * Radar dimensions\n     * @type {Array.<string>}\n     */\n    this.dimensions = [];\n\n    this._indicatorAxes = map(radarModel.getIndicatorModels(), function (indicatorModel, idx) {\n        var dim = 'indicator_' + idx;\n        var indicatorAxis = new IndicatorAxis(dim, new IntervalScale());\n        indicatorAxis.name = indicatorModel.get('name');\n        // Inject model and axis\n        indicatorAxis.model = indicatorModel;\n        indicatorModel.axis = indicatorAxis;\n        this.dimensions.push(dim);\n        return indicatorAxis;\n    }, this);\n\n    this.resize(radarModel, api);\n\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.cx;\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.cy;\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.r;\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.r0;\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.startAngle;\n}\n\nRadar.prototype.getIndicatorAxes = function () {\n    return this._indicatorAxes;\n};\n\nRadar.prototype.dataToPoint = function (value, indicatorIndex) {\n    var indicatorAxis = this._indicatorAxes[indicatorIndex];\n\n    return this.coordToPoint(indicatorAxis.dataToCoord(value), indicatorIndex);\n};\n\nRadar.prototype.coordToPoint = function (coord, indicatorIndex) {\n    var indicatorAxis = this._indicatorAxes[indicatorIndex];\n    var angle = indicatorAxis.angle;\n    var x = this.cx + coord * Math.cos(angle);\n    var y = this.cy - coord * Math.sin(angle);\n    return [x, y];\n};\n\nRadar.prototype.pointToData = function (pt) {\n    var dx = pt[0] - this.cx;\n    var dy = pt[1] - this.cy;\n    var radius = Math.sqrt(dx * dx + dy * dy);\n    dx /= radius;\n    dy /= radius;\n\n    var radian = Math.atan2(-dy, dx);\n\n    // Find the closest angle\n    // FIXME index can calculated directly\n    var minRadianDiff = Infinity;\n    var closestAxis;\n    var closestAxisIdx = -1;\n    for (var i = 0; i < this._indicatorAxes.length; i++) {\n        var indicatorAxis = this._indicatorAxes[i];\n        var diff = Math.abs(radian - indicatorAxis.angle);\n        if (diff < minRadianDiff) {\n            closestAxis = indicatorAxis;\n            closestAxisIdx = i;\n            minRadianDiff = diff;\n        }\n    }\n\n    return [closestAxisIdx, +(closestAxis && closestAxis.coodToData(radius))];\n};\n\nRadar.prototype.resize = function (radarModel, api) {\n    var center = radarModel.get('center');\n    var viewWidth = api.getWidth();\n    var viewHeight = api.getHeight();\n    var viewSize = Math.min(viewWidth, viewHeight) / 2;\n    this.cx = parsePercent$1(center[0], viewWidth);\n    this.cy = parsePercent$1(center[1], viewHeight);\n\n    this.startAngle = radarModel.get('startAngle') * Math.PI / 180;\n\n    // radius may be single value like `20`, `'80%'`, or array like `[10, '80%']`\n    var radius = radarModel.get('radius');\n    if (typeof radius === 'string' || typeof radius === 'number') {\n        radius = [0, radius];\n    }\n    this.r0 = parsePercent$1(radius[0], viewSize);\n    this.r = parsePercent$1(radius[1], viewSize);\n\n    each$1(this._indicatorAxes, function (indicatorAxis, idx) {\n        indicatorAxis.setExtent(this.r0, this.r);\n        var angle = (this.startAngle + idx * Math.PI * 2 / this._indicatorAxes.length);\n        // Normalize to [-PI, PI]\n        angle = Math.atan2(Math.sin(angle), Math.cos(angle));\n        indicatorAxis.angle = angle;\n    }, this);\n};\n\nRadar.prototype.update = function (ecModel, api) {\n    var indicatorAxes = this._indicatorAxes;\n    var radarModel = this._model;\n    each$1(indicatorAxes, function (indicatorAxis) {\n        indicatorAxis.scale.setExtent(Infinity, -Infinity);\n    });\n    ecModel.eachSeriesByType('radar', function (radarSeries, idx) {\n        if (radarSeries.get('coordinateSystem') !== 'radar'\n            || ecModel.getComponent('radar', radarSeries.get('radarIndex')) !== radarModel\n        ) {\n            return;\n        }\n        var data = radarSeries.getData();\n        each$1(indicatorAxes, function (indicatorAxis) {\n            indicatorAxis.scale.unionExtentFromData(data, data.mapDimension(indicatorAxis.dim));\n        });\n    }, this);\n\n    var splitNumber = radarModel.get('splitNumber');\n\n    function increaseInterval(interval) {\n        var exp10 = Math.pow(10, Math.floor(Math.log(interval) / Math.LN10));\n        // Increase interval\n        var f = interval / exp10;\n        if (f === 2) {\n            f = 5;\n        }\n        else { // f is 2 or 5\n            f *= 2;\n        }\n        return f * exp10;\n    }\n    // Force all the axis fixing the maxSplitNumber.\n    each$1(indicatorAxes, function (indicatorAxis, idx) {\n        var rawExtent = getScaleExtent(indicatorAxis.scale, indicatorAxis.model);\n        niceScaleExtent(indicatorAxis.scale, indicatorAxis.model);\n\n        var axisModel = indicatorAxis.model;\n        var scale = indicatorAxis.scale;\n        var fixedMin = axisModel.getMin();\n        var fixedMax = axisModel.getMax();\n        var interval = scale.getInterval();\n\n        if (fixedMin != null && fixedMax != null) {\n            // User set min, max, divide to get new interval\n            scale.setExtent(+fixedMin, +fixedMax);\n            scale.setInterval(\n                (fixedMax - fixedMin) / splitNumber\n            );\n        }\n        else if (fixedMin != null) {\n            var max;\n            // User set min, expand extent on the other side\n            do {\n                max = fixedMin + interval * splitNumber;\n                scale.setExtent(+fixedMin, max);\n                // Interval must been set after extent\n                // FIXME\n                scale.setInterval(interval);\n\n                interval = increaseInterval(interval);\n            } while (max < rawExtent[1] && isFinite(max) && isFinite(rawExtent[1]));\n        }\n        else if (fixedMax != null) {\n            var min;\n            // User set min, expand extent on the other side\n            do {\n                min = fixedMax - interval * splitNumber;\n                scale.setExtent(min, +fixedMax);\n                scale.setInterval(interval);\n                interval = increaseInterval(interval);\n            } while (min > rawExtent[0] && isFinite(min) && isFinite(rawExtent[0]));\n        }\n        else {\n            var nicedSplitNumber = scale.getTicks().length - 1;\n            if (nicedSplitNumber > splitNumber) {\n                interval = increaseInterval(interval);\n            }\n            // PENDING\n            var center = Math.round((rawExtent[0] + rawExtent[1]) / 2 / interval) * interval;\n            var halfSplitNumber = Math.round(splitNumber / 2);\n            scale.setExtent(\n                round$2(center - halfSplitNumber * interval),\n                round$2(center + (splitNumber - halfSplitNumber) * interval)\n            );\n            scale.setInterval(interval);\n        }\n    });\n};\n\n/**\n * Radar dimensions is based on the data\n * @type {Array}\n */\nRadar.dimensions = [];\n\nRadar.create = function (ecModel, api) {\n    var radarList = [];\n    ecModel.eachComponent('radar', function (radarModel) {\n        var radar = new Radar(radarModel, ecModel, api);\n        radarList.push(radar);\n        radarModel.coordinateSystem = radar;\n    });\n    ecModel.eachSeriesByType('radar', function (radarSeries) {\n        if (radarSeries.get('coordinateSystem') === 'radar') {\n            // Inject coordinate system\n            radarSeries.coordinateSystem = radarList[radarSeries.get('radarIndex') || 0];\n        }\n    });\n    return radarList;\n};\n\nCoordinateSystemManager.register('radar', Radar);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar valueAxisDefault = axisDefault.valueAxis;\n\nfunction defaultsShow(opt, show) {\n    return defaults({\n        show: show\n    }, opt);\n}\n\nvar RadarModel = extendComponentModel({\n\n    type: 'radar',\n\n    optionUpdated: function () {\n        var boundaryGap = this.get('boundaryGap');\n        var splitNumber = this.get('splitNumber');\n        var scale = this.get('scale');\n        var axisLine = this.get('axisLine');\n        var axisTick = this.get('axisTick');\n        var axisLabel = this.get('axisLabel');\n        var nameTextStyle = this.get('name');\n        var showName = this.get('name.show');\n        var nameFormatter = this.get('name.formatter');\n        var nameGap = this.get('nameGap');\n        var triggerEvent = this.get('triggerEvent');\n\n        var indicatorModels = map(this.get('indicator') || [], function (indicatorOpt) {\n            // PENDING\n            if (indicatorOpt.max != null && indicatorOpt.max > 0 && !indicatorOpt.min) {\n                indicatorOpt.min = 0;\n            }\n            else if (indicatorOpt.min != null && indicatorOpt.min < 0 && !indicatorOpt.max) {\n                indicatorOpt.max = 0;\n            }\n            var iNameTextStyle = nameTextStyle;\n            if (indicatorOpt.color != null) {\n                iNameTextStyle = defaults({color: indicatorOpt.color}, nameTextStyle);\n            }\n            // Use same configuration\n            indicatorOpt = merge(clone(indicatorOpt), {\n                boundaryGap: boundaryGap,\n                splitNumber: splitNumber,\n                scale: scale,\n                axisLine: axisLine,\n                axisTick: axisTick,\n                axisLabel: axisLabel,\n                // Competitable with 2 and use text\n                name: indicatorOpt.text,\n                nameLocation: 'end',\n                nameGap: nameGap,\n                // min: 0,\n                nameTextStyle: iNameTextStyle,\n                triggerEvent: triggerEvent\n            }, false);\n            if (!showName) {\n                indicatorOpt.name = '';\n            }\n            if (typeof nameFormatter === 'string') {\n                var indName = indicatorOpt.name;\n                indicatorOpt.name = nameFormatter.replace('{value}', indName != null ? indName : '');\n            }\n            else if (typeof nameFormatter === 'function') {\n                indicatorOpt.name = nameFormatter(\n                    indicatorOpt.name, indicatorOpt\n                );\n            }\n            var model = extend(\n                new Model(indicatorOpt, null, this.ecModel),\n                axisModelCommonMixin\n            );\n\n            // For triggerEvent.\n            model.mainType = 'radar';\n            model.componentIndex = this.componentIndex;\n\n            return model;\n        }, this);\n\n        this.getIndicatorModels = function () {\n            return indicatorModels;\n        };\n    },\n\n    defaultOption: {\n\n        zlevel: 0,\n\n        z: 0,\n\n        center: ['50%', '50%'],\n\n        radius: '75%',\n\n        startAngle: 90,\n\n        name: {\n            show: true\n            // formatter: null\n            // textStyle: {}\n        },\n\n        boundaryGap: [0, 0],\n\n        splitNumber: 5,\n\n        nameGap: 15,\n\n        scale: false,\n\n        // Polygon or circle\n        shape: 'polygon',\n\n        axisLine: merge(\n            {\n                lineStyle: {\n                    color: '#bbb'\n                }\n            },\n            valueAxisDefault.axisLine\n        ),\n        axisLabel: defaultsShow(valueAxisDefault.axisLabel, false),\n        axisTick: defaultsShow(valueAxisDefault.axisTick, false),\n        splitLine: defaultsShow(valueAxisDefault.splitLine, true),\n        splitArea: defaultsShow(valueAxisDefault.splitArea, true),\n\n        // {text, min, max}\n        indicator: []\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar axisBuilderAttrs$1 = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\n\nextendComponentView({\n\n    type: 'radar',\n\n    render: function (radarModel, ecModel, api) {\n        var group = this.group;\n        group.removeAll();\n\n        this._buildAxes(radarModel);\n        this._buildSplitLineAndArea(radarModel);\n    },\n\n    _buildAxes: function (radarModel) {\n        var radar = radarModel.coordinateSystem;\n        var indicatorAxes = radar.getIndicatorAxes();\n        var axisBuilders = map(indicatorAxes, function (indicatorAxis) {\n            var axisBuilder = new AxisBuilder(indicatorAxis.model, {\n                position: [radar.cx, radar.cy],\n                rotation: indicatorAxis.angle,\n                labelDirection: -1,\n                tickDirection: -1,\n                nameDirection: 1\n            });\n            return axisBuilder;\n        });\n\n        each$1(axisBuilders, function (axisBuilder) {\n            each$1(axisBuilderAttrs$1, axisBuilder.add, axisBuilder);\n            this.group.add(axisBuilder.getGroup());\n        }, this);\n    },\n\n    _buildSplitLineAndArea: function (radarModel) {\n        var radar = radarModel.coordinateSystem;\n        var indicatorAxes = radar.getIndicatorAxes();\n        if (!indicatorAxes.length) {\n            return;\n        }\n        var shape = radarModel.get('shape');\n        var splitLineModel = radarModel.getModel('splitLine');\n        var splitAreaModel = radarModel.getModel('splitArea');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n\n        var showSplitLine = splitLineModel.get('show');\n        var showSplitArea = splitAreaModel.get('show');\n        var splitLineColors = lineStyleModel.get('color');\n        var splitAreaColors = areaStyleModel.get('color');\n\n        splitLineColors = isArray(splitLineColors) ? splitLineColors : [splitLineColors];\n        splitAreaColors = isArray(splitAreaColors) ? splitAreaColors : [splitAreaColors];\n\n        var splitLines = [];\n        var splitAreas = [];\n\n        function getColorIndex(areaOrLine, areaOrLineColorList, idx) {\n            var colorIndex = idx % areaOrLineColorList.length;\n            areaOrLine[colorIndex] = areaOrLine[colorIndex] || [];\n            return colorIndex;\n        }\n\n        if (shape === 'circle') {\n            var ticksRadius = indicatorAxes[0].getTicksCoords();\n            var cx = radar.cx;\n            var cy = radar.cy;\n            for (var i = 0; i < ticksRadius.length; i++) {\n                if (showSplitLine) {\n                    var colorIndex = getColorIndex(splitLines, splitLineColors, i);\n                    splitLines[colorIndex].push(new Circle({\n                        shape: {\n                            cx: cx,\n                            cy: cy,\n                            r: ticksRadius[i].coord\n                        }\n                    }));\n                }\n                if (showSplitArea && i < ticksRadius.length - 1) {\n                    var colorIndex = getColorIndex(splitAreas, splitAreaColors, i);\n                    splitAreas[colorIndex].push(new Ring({\n                        shape: {\n                            cx: cx,\n                            cy: cy,\n                            r0: ticksRadius[i].coord,\n                            r: ticksRadius[i + 1].coord\n                        }\n                    }));\n                }\n            }\n        }\n        // Polyyon\n        else {\n            var realSplitNumber;\n            var axesTicksPoints = map(indicatorAxes, function (indicatorAxis, idx) {\n                var ticksCoords = indicatorAxis.getTicksCoords();\n                realSplitNumber = realSplitNumber == null\n                    ? ticksCoords.length - 1\n                    : Math.min(ticksCoords.length - 1, realSplitNumber);\n                return map(ticksCoords, function (tickCoord) {\n                    return radar.coordToPoint(tickCoord.coord, idx);\n                });\n            });\n\n            var prevPoints = [];\n            for (var i = 0; i <= realSplitNumber; i++) {\n                var points = [];\n                for (var j = 0; j < indicatorAxes.length; j++) {\n                    points.push(axesTicksPoints[j][i]);\n                }\n                // Close\n                if (points[0]) {\n                    points.push(points[0].slice());\n                }\n                else {\n                    if (__DEV__) {\n                        console.error('Can\\'t draw value axis ' + i);\n                    }\n                }\n\n                if (showSplitLine) {\n                    var colorIndex = getColorIndex(splitLines, splitLineColors, i);\n                    splitLines[colorIndex].push(new Polyline({\n                        shape: {\n                            points: points\n                        }\n                    }));\n                }\n                if (showSplitArea && prevPoints) {\n                    var colorIndex = getColorIndex(splitAreas, splitAreaColors, i - 1);\n                    splitAreas[colorIndex].push(new Polygon({\n                        shape: {\n                            points: points.concat(prevPoints)\n                        }\n                    }));\n                }\n                prevPoints = points.slice().reverse();\n            }\n        }\n\n        var lineStyle = lineStyleModel.getLineStyle();\n        var areaStyle = areaStyleModel.getAreaStyle();\n        // Add splitArea before splitLine\n        each$1(splitAreas, function (splitAreas, idx) {\n            this.group.add(mergePath(\n                splitAreas, {\n                    style: defaults({\n                        stroke: 'none',\n                        fill: splitAreaColors[idx % splitAreaColors.length]\n                    }, areaStyle),\n                    silent: true\n                }\n            ));\n        }, this);\n\n        each$1(splitLines, function (splitLines, idx) {\n            this.group.add(mergePath(\n                splitLines, {\n                    style: defaults({\n                        fill: 'none',\n                        stroke: splitLineColors[idx % splitLineColors.length]\n                    }, lineStyle),\n                    silent: true\n                }\n            ));\n        }, this);\n\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar RadarSeries = SeriesModel.extend({\n\n    type: 'series.radar',\n\n    dependencies: ['radar'],\n\n\n    // Overwrite\n    init: function (option) {\n        RadarSeries.superApply(this, 'init', arguments);\n\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n    },\n\n    getInitialData: function (option, ecModel) {\n        return createListSimply(this, {\n            generateCoord: 'indicator_',\n            generateCoordCount: Infinity\n        });\n    },\n\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var coordSys = this.coordinateSystem;\n        var indicatorAxes = coordSys.getIndicatorAxes();\n        var name = this.getData().getName(dataIndex);\n        return encodeHTML(name === '' ? this.name : name) + '<br/>'\n            + map(indicatorAxes, function (axis, idx) {\n                var val = data.get(data.mapDimension(axis.dim), dataIndex);\n                return encodeHTML(axis.name + ' : ' + val);\n            }).join('<br />');\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'radar',\n        legendHoverLink: true,\n        radarIndex: 0,\n        lineStyle: {\n            width: 2,\n            type: 'solid'\n        },\n        label: {\n            position: 'top'\n        },\n        // areaStyle: {\n        // },\n        // itemStyle: {}\n        symbol: 'emptyCircle',\n        symbolSize: 4\n        // symbolRotate: null\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction normalizeSymbolSize(symbolSize) {\n    if (!isArray(symbolSize)) {\n        symbolSize = [+symbolSize, +symbolSize];\n    }\n    return symbolSize;\n}\n\nextendChartView({\n\n    type: 'radar',\n\n    render: function (seriesModel, ecModel, api) {\n        var polar = seriesModel.coordinateSystem;\n        var group = this.group;\n\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        function createSymbol$$1(data, idx) {\n            var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';\n            var color = data.getItemVisual(idx, 'color');\n            if (symbolType === 'none') {\n                return;\n            }\n            var symbolSize = normalizeSymbolSize(\n                data.getItemVisual(idx, 'symbolSize')\n            );\n            var symbolPath = createSymbol(\n                symbolType, -1, -1, 2, 2, color\n            );\n            symbolPath.attr({\n                style: {\n                    strokeNoScale: true\n                },\n                z2: 100,\n                scale: [symbolSize[0] / 2, symbolSize[1] / 2]\n            });\n            return symbolPath;\n        }\n\n        function updateSymbols(oldPoints, newPoints, symbolGroup, data, idx, isInit) {\n            // Simply rerender all\n            symbolGroup.removeAll();\n            for (var i = 0; i < newPoints.length - 1; i++) {\n                var symbolPath = createSymbol$$1(data, idx);\n                if (symbolPath) {\n                    symbolPath.__dimIdx = i;\n                    if (oldPoints[i]) {\n                        symbolPath.attr('position', oldPoints[i]);\n                        graphic[isInit ? 'initProps' : 'updateProps'](\n                            symbolPath, {\n                                position: newPoints[i]\n                            }, seriesModel, idx\n                        );\n                    }\n                    else {\n                        symbolPath.attr('position', newPoints[i]);\n                    }\n                    symbolGroup.add(symbolPath);\n                }\n            }\n        }\n\n        function getInitialPoints(points) {\n            return map(points, function (pt) {\n                return [polar.cx, polar.cy];\n            });\n        }\n        data.diff(oldData)\n            .add(function (idx) {\n                var points = data.getItemLayout(idx);\n                if (!points) {\n                    return;\n                }\n                var polygon = new Polygon();\n                var polyline = new Polyline();\n                var target = {\n                    shape: {\n                        points: points\n                    }\n                };\n                polygon.shape.points = getInitialPoints(points);\n                polyline.shape.points = getInitialPoints(points);\n                initProps(polygon, target, seriesModel, idx);\n                initProps(polyline, target, seriesModel, idx);\n\n                var itemGroup = new Group();\n                var symbolGroup = new Group();\n                itemGroup.add(polyline);\n                itemGroup.add(polygon);\n                itemGroup.add(symbolGroup);\n\n                updateSymbols(\n                    polyline.shape.points, points, symbolGroup, data, idx, true\n                );\n\n                data.setItemGraphicEl(idx, itemGroup);\n            })\n            .update(function (newIdx, oldIdx) {\n                var itemGroup = oldData.getItemGraphicEl(oldIdx);\n                var polyline = itemGroup.childAt(0);\n                var polygon = itemGroup.childAt(1);\n                var symbolGroup = itemGroup.childAt(2);\n                var target = {\n                    shape: {\n                        points: data.getItemLayout(newIdx)\n                    }\n                };\n                if (!target.shape.points) {\n                    return;\n                }\n                updateSymbols(\n                    polyline.shape.points, target.shape.points, symbolGroup, data, newIdx, false\n                );\n\n                updateProps(polyline, target, seriesModel);\n                updateProps(polygon, target, seriesModel);\n\n                data.setItemGraphicEl(newIdx, itemGroup);\n            })\n            .remove(function (idx) {\n                group.remove(oldData.getItemGraphicEl(idx));\n            })\n            .execute();\n\n        data.eachItemGraphicEl(function (itemGroup, idx) {\n            var itemModel = data.getItemModel(idx);\n            var polyline = itemGroup.childAt(0);\n            var polygon = itemGroup.childAt(1);\n            var symbolGroup = itemGroup.childAt(2);\n            var color = data.getItemVisual(idx, 'color');\n\n            group.add(itemGroup);\n\n            polyline.useStyle(\n                defaults(\n                    itemModel.getModel('lineStyle').getLineStyle(),\n                    {\n                        fill: 'none',\n                        stroke: color\n                    }\n                )\n            );\n            polyline.hoverStyle = itemModel.getModel('emphasis.lineStyle').getLineStyle();\n\n            var areaStyleModel = itemModel.getModel('areaStyle');\n            var hoverAreaStyleModel = itemModel.getModel('emphasis.areaStyle');\n            var polygonIgnore = areaStyleModel.isEmpty() && areaStyleModel.parentModel.isEmpty();\n            var hoverPolygonIgnore = hoverAreaStyleModel.isEmpty() && hoverAreaStyleModel.parentModel.isEmpty();\n\n            hoverPolygonIgnore = hoverPolygonIgnore && polygonIgnore;\n            polygon.ignore = polygonIgnore;\n\n            polygon.useStyle(\n                defaults(\n                    areaStyleModel.getAreaStyle(),\n                    {\n                        fill: color,\n                        opacity: 0.7\n                    }\n                )\n            );\n            polygon.hoverStyle = hoverAreaStyleModel.getAreaStyle();\n\n            var itemStyle = itemModel.getModel('itemStyle').getItemStyle(['color']);\n            var itemHoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n            var labelModel = itemModel.getModel('label');\n            var labelHoverModel = itemModel.getModel('emphasis.label');\n            symbolGroup.eachChild(function (symbolPath) {\n                symbolPath.setStyle(itemStyle);\n                symbolPath.hoverStyle = clone(itemHoverStyle);\n\n                setLabelStyle(\n                    symbolPath.style, symbolPath.hoverStyle, labelModel, labelHoverModel,\n                    {\n                        labelFetcher: data.hostModel,\n                        labelDataIndex: idx,\n                        labelDimIndex: symbolPath.__dimIdx,\n                        defaultText: data.get(data.dimensions[symbolPath.__dimIdx], idx),\n                        autoColor: color,\n                        isRectText: true\n                    }\n                );\n            });\n\n            function onEmphasis() {\n                polygon.attr('ignore', hoverPolygonIgnore);\n            }\n\n            function onNormal() {\n                polygon.attr('ignore', polygonIgnore);\n            }\n\n            itemGroup.off('mouseover').off('mouseout').off('normal').off('emphasis');\n            itemGroup.on('emphasis', onEmphasis)\n                .on('mouseover', onEmphasis)\n                .on('normal', onNormal)\n                .on('mouseout', onNormal);\n\n            setHoverStyle(itemGroup);\n        });\n\n        this._data = data;\n    },\n\n    remove: function () {\n        this.group.removeAll();\n        this._data = null;\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar radarLayout = function (ecModel) {\n    ecModel.eachSeriesByType('radar', function (seriesModel) {\n        var data = seriesModel.getData();\n        var points = [];\n        var coordSys = seriesModel.coordinateSystem;\n        if (!coordSys) {\n            return;\n        }\n\n        function pointsConverter(val, idx) {\n            points[idx] = points[idx] || [];\n            points[idx][i] = coordSys.dataToPoint(val, i);\n        }\n        var axes = coordSys.getIndicatorAxes();\n        for (var i = 0; i < axes.length; i++) {\n            data.each(data.mapDimension(axes[i].dim), pointsConverter);\n        }\n\n        data.each(function (idx) {\n            // Close polygon\n            points[idx][0] && points[idx].push(points[idx][0].slice());\n            data.setItemLayout(idx, points[idx]);\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Backward compat for radar chart in 2\nvar backwardCompat$1 = function (option) {\n    var polarOptArr = option.polar;\n    if (polarOptArr) {\n        if (!isArray(polarOptArr)) {\n            polarOptArr = [polarOptArr];\n        }\n        var polarNotRadar = [];\n        each$1(polarOptArr, function (polarOpt, idx) {\n            if (polarOpt.indicator) {\n                if (polarOpt.type && !polarOpt.shape) {\n                    polarOpt.shape = polarOpt.type;\n                }\n                option.radar = option.radar || [];\n                if (!isArray(option.radar)) {\n                    option.radar = [option.radar];\n                }\n                option.radar.push(polarOpt);\n            }\n            else {\n                polarNotRadar.push(polarOpt);\n            }\n        });\n        option.polar = polarNotRadar;\n    }\n    each$1(option.series, function (seriesOpt) {\n        if (seriesOpt && seriesOpt.type === 'radar' && seriesOpt.polarIndex) {\n            seriesOpt.radarIndex = seriesOpt.polarIndex;\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n// Must use radar component\nregisterVisual(dataColor('radar'));\nregisterVisual(visualSymbol('radar', 'circle'));\nregisterLayout(radarLayout);\nregisterProcessor(dataFilter('radar'));\nregisterPreprocessor(backwardCompat$1);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Fix for 南海诸岛\n\nvar geoCoord = [126, 25];\n\nvar points$1 = [\n    [[0, 3.5], [7, 11.2], [15, 11.9], [30, 7], [42, 0.7], [52, 0.7],\n        [56, 7.7], [59, 0.7], [64, 0.7], [64, 0], [5, 0], [0, 3.5]],\n    [[13, 16.1], [19, 14.7], [16, 21.7], [11, 23.1], [13, 16.1]],\n    [[12, 32.2], [14, 38.5], [15, 38.5], [13, 32.2], [12, 32.2]],\n    [[16, 47.6], [12, 53.2], [13, 53.2], [18, 47.6], [16, 47.6]],\n    [[6, 64.4], [8, 70], [9, 70], [8, 64.4], [6, 64.4]],\n    [[23, 82.6], [29, 79.8], [30, 79.8], [25, 82.6], [23, 82.6]],\n    [[37, 70.7], [43, 62.3], [44, 62.3], [39, 70.7], [37, 70.7]],\n    [[48, 51.1], [51, 45.5], [53, 45.5], [50, 51.1], [48, 51.1]],\n    [[51, 35], [51, 28.7], [53, 28.7], [53, 35], [51, 35]],\n    [[52, 22.4], [55, 17.5], [56, 17.5], [53, 22.4], [52, 22.4]],\n    [[58, 12.6], [62, 7], [63, 7], [60, 12.6], [58, 12.6]],\n    [[0, 3.5], [0, 93.1], [64, 93.1], [64, 0], [63, 0], [63, 92.4],\n        [1, 92.4], [1, 3.5], [0, 3.5]]\n];\n\nfor (var i$1 = 0; i$1 < points$1.length; i$1++) {\n    for (var k = 0; k < points$1[i$1].length; k++) {\n        points$1[i$1][k][0] /= 10.5;\n        points$1[i$1][k][1] /= -10.5 / 0.75;\n\n        points$1[i$1][k][0] += geoCoord[0];\n        points$1[i$1][k][1] += geoCoord[1];\n    }\n}\n\nvar fixNanhai = function (mapType, regions) {\n    if (mapType === 'china') {\n        regions.push(new Region(\n            '南海诸岛',\n            map(points$1, function (exterior) {\n                return {\n                    type: 'polygon',\n                    exterior: exterior\n                };\n            }), geoCoord\n        ));\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar coordsOffsetMap = {\n    '南海诸岛': [32, 80],\n    // 全国\n    '广东': [0, -10],\n    '香港': [10, 5],\n    '澳门': [-10, 10],\n    //'北京': [-10, 0],\n    '天津': [5, 5]\n};\n\nvar fixTextCoord = function (mapType, region) {\n    if (mapType === 'china') {\n        var coordFix = coordsOffsetMap[region.name];\n        if (coordFix) {\n            var cp = region.center;\n            cp[0] += coordFix[0] / 10.5;\n            cp[1] += -coordFix[1] / (10.5 / 0.75);\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar geoCoordMap = {\n    'Russia': [100, 60],\n    'United States': [-99, 38],\n    'United States of America': [-99, 38]\n};\n\nvar fixGeoCoord = function (mapType, region) {\n    if (mapType === 'world') {\n        var geoCoord = geoCoordMap[region.name];\n        if (geoCoord) {\n            var cp = region.center;\n            cp[0] = geoCoord[0];\n            cp[1] = geoCoord[1];\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Fix for 钓鱼岛\n\n// var Region = require('../Region');\n// var zrUtil = require('zrender/src/core/util');\n\n// var geoCoord = [126, 25];\n\nvar points$2 = [\n    [\n        [123.45165252685547, 25.73527164402261],\n        [123.49731445312499, 25.73527164402261],\n        [123.49731445312499, 25.750734064600884],\n        [123.45165252685547, 25.750734064600884],\n        [123.45165252685547, 25.73527164402261]\n    ]\n];\n\nvar fixDiaoyuIsland = function (mapType, region) {\n    if (mapType === 'china' && region.name === '台湾') {\n        region.geometries.push({\n            type: 'polygon',\n            exterior: points$2[0]\n        });\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Built-in GEO fixer.\nvar inner$7 = makeInner();\n\nvar geoJSONLoader = {\n\n    /**\n     * @param {string} mapName\n     * @param {Object} mapRecord {specialAreas, geoJSON}\n     * @return {Object} {regions, boundingRect}\n     */\n    load: function (mapName, mapRecord) {\n\n        var parsed = inner$7(mapRecord).parsed;\n\n        if (parsed) {\n            return parsed;\n        }\n\n        var specialAreas = mapRecord.specialAreas || {};\n        var geoJSON = mapRecord.geoJSON;\n        var regions;\n\n        // https://jsperf.com/try-catch-performance-overhead\n        try {\n            regions = geoJSON ? parseGeoJson$1(geoJSON) : [];\n        }\n        catch (e) {\n            throw new Error('Invalid geoJson format\\n' + e.message);\n        }\n\n        each$1(regions, function (region) {\n            var regionName = region.name;\n\n            fixTextCoord(mapName, region);\n            fixGeoCoord(mapName, region);\n            fixDiaoyuIsland(mapName, region);\n\n            // Some area like Alaska in USA map needs to be tansformed\n            // to look better\n            var specialArea = specialAreas[regionName];\n            if (specialArea) {\n                region.transformTo(\n                    specialArea.left, specialArea.top, specialArea.width, specialArea.height\n                );\n            }\n        });\n\n        fixNanhai(mapName, regions);\n\n        return (inner$7(mapRecord).parsed = {\n            regions: regions,\n            boundingRect: getBoundingRect$1(regions)\n        });\n    }\n};\n\nfunction getBoundingRect$1(regions) {\n    var rect;\n    for (var i = 0; i < regions.length; i++) {\n        var regionRect = regions[i].getBoundingRect();\n        rect = rect || regionRect.clone();\n        rect.union(regionRect);\n    }\n    return rect;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$8 = makeInner();\n\nvar geoSVGLoader = {\n\n    /**\n     * @param {string} mapName\n     * @param {Object} mapRecord {specialAreas, geoJSON}\n     * @return {Object} {root, boundingRect}\n     */\n    load: function (mapName, mapRecord) {\n        var originRoot = inner$8(mapRecord).originRoot;\n        if (originRoot) {\n            return {\n                root: originRoot,\n                boundingRect: inner$8(mapRecord).boundingRect\n            };\n        }\n\n        var graphic = buildGraphic(mapRecord);\n\n        inner$8(mapRecord).originRoot = graphic.root;\n        inner$8(mapRecord).boundingRect = graphic.boundingRect;\n\n        return graphic;\n    },\n\n    makeGraphic: function (mapName, mapRecord, hostKey) {\n        // For performance consideration (in large SVG), graphic only maked\n        // when necessary and reuse them according to hostKey.\n        var field = inner$8(mapRecord);\n        var rootMap = field.rootMap || (field.rootMap = createHashMap());\n\n        var root = rootMap.get(hostKey);\n        if (root) {\n            return root;\n        }\n\n        var originRoot = field.originRoot;\n        var boundingRect = field.boundingRect;\n\n        // For performance, if originRoot is not used by a view,\n        // assign it to a view, but not reproduce graphic elements.\n        if (!field.originRootHostKey) {\n            field.originRootHostKey = hostKey;\n            root = originRoot;\n        }\n        else {\n            root = buildGraphic(mapRecord, boundingRect).root;\n        }\n\n        return rootMap.set(hostKey, root);\n    },\n\n    removeGraphic: function (mapName, mapRecord, hostKey) {\n        var field = inner$8(mapRecord);\n        var rootMap = field.rootMap;\n        rootMap && rootMap.removeKey(hostKey);\n        if (hostKey === field.originRootHostKey) {\n            field.originRootHostKey = null;\n        }\n    }\n};\n\nfunction buildGraphic(mapRecord, boundingRect) {\n    var svgXML = mapRecord.svgXML;\n    var result;\n    var root;\n\n    try {\n        result = svgXML && parseSVG(svgXML, {\n            ignoreViewBox: true,\n            ignoreRootClip: true\n        }) || {};\n        root = result.root;\n        assert$1(root != null);\n    }\n    catch (e) {\n        throw new Error('Invalid svg format\\n' + e.message);\n    }\n\n    var svgWidth = result.width;\n    var svgHeight = result.height;\n    var viewBoxRect = result.viewBoxRect;\n\n    if (!boundingRect) {\n        boundingRect = (svgWidth == null || svgHeight == null)\n            // If svg width / height not specified, calculate\n            // bounding rect as the width / height\n            ? root.getBoundingRect()\n            : new BoundingRect(0, 0, 0, 0);\n\n        if (svgWidth != null) {\n            boundingRect.width = svgWidth;\n        }\n        if (svgHeight != null) {\n            boundingRect.height = svgHeight;\n        }\n    }\n\n    if (viewBoxRect) {\n        var viewBoxTransform = makeViewBoxTransform(viewBoxRect, boundingRect.width, boundingRect.height);\n        var elRoot = root;\n        root = new Group();\n        root.add(elRoot);\n        elRoot.scale = viewBoxTransform.scale;\n        elRoot.position = viewBoxTransform.position;\n    }\n\n    root.setClipPath(new Rect({\n        shape: boundingRect.plain()\n    }));\n\n    return {\n        root: root,\n        boundingRect: boundingRect\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar loaders = {\n    geoJSON: geoJSONLoader,\n    svg: geoSVGLoader\n};\n\nvar geoSourceManager = {\n\n    /**\n     * @param {string} mapName\n     * @param {Object} nameMap\n     * @return {Object} source {regions, regionsMap, nameCoordMap, boundingRect}\n     */\n    load: function (mapName, nameMap) {\n        var regions = [];\n        var regionsMap = createHashMap();\n        var nameCoordMap = createHashMap();\n        var boundingRect;\n        var mapRecords = retrieveMap(mapName);\n\n        each$1(mapRecords, function (record) {\n            var singleSource = loaders[record.type].load(mapName, record);\n\n            each$1(singleSource.regions, function (region) {\n                var regionName = region.name;\n\n                // Try use the alias in geoNameMap\n                if (nameMap && nameMap.hasOwnProperty(regionName)) {\n                    region = region.cloneShallow(regionName = nameMap[regionName]);\n                }\n\n                regions.push(region);\n                regionsMap.set(regionName, region);\n                nameCoordMap.set(regionName, region.center);\n            });\n\n            var rect = singleSource.boundingRect;\n            if (rect) {\n                boundingRect\n                    ? boundingRect.union(rect)\n                    : (boundingRect = rect.clone());\n            }\n        });\n\n        return {\n            regions: regions,\n            regionsMap: regionsMap,\n            nameCoordMap: nameCoordMap,\n            // FIXME Always return new ?\n            boundingRect: boundingRect || new BoundingRect(0, 0, 0, 0)\n        };\n    },\n\n    /**\n     * @param {string} mapName\n     * @param {string} hostKey For cache.\n     * @return {Array.<module:zrender/Element>} Roots.\n     */\n    makeGraphic: makeInvoker('makeGraphic'),\n\n    /**\n     * @param {string} mapName\n     * @param {string} hostKey For cache.\n     */\n    removeGraphic: makeInvoker('removeGraphic')\n};\n\nfunction makeInvoker(methodName) {\n    return function (mapName, hostKey) {\n        var mapRecords = retrieveMap(mapName);\n        var results = [];\n\n        each$1(mapRecords, function (record) {\n            var method = loaders[record.type][methodName];\n            method && results.push(method(mapName, record, hostKey));\n        });\n\n        return results;\n    };\n}\n\nfunction mapNotExistsError(mapName) {\n    if (__DEV__) {\n        console.error(\n            'Map ' + mapName + ' not exists. You can download map file on http://echarts.baidu.com/download-map.html'\n        );\n    }\n}\n\nfunction retrieveMap(mapName) {\n    var mapRecords = mapDataStorage.retrieveMap(mapName) || [];\n\n    if (__DEV__) {\n        if (!mapRecords.length) {\n            mapNotExistsError(mapName);\n        }\n    }\n\n    return mapRecords;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar MapSeries = SeriesModel.extend({\n\n    type: 'series.map',\n\n    dependencies: ['geo'],\n\n    layoutMode: 'box',\n\n    /**\n     * Only first map series of same mapType will drawMap\n     * @type {boolean}\n     */\n    needsDrawMap: false,\n\n    /**\n     * Group of all map series with same mapType\n     * @type {boolean}\n     */\n    seriesGroup: [],\n\n    getInitialData: function (option) {\n        var data = createListSimply(this, ['value']);\n        var valueDim = data.mapDimension('value');\n        var dataNameMap = createHashMap();\n        var selectTargetList = [];\n        var toAppendNames = [];\n\n        for (var i = 0, len = data.count(); i < len; i++) {\n            var name = data.getName(i);\n            dataNameMap.set(name, true);\n            selectTargetList.push({\n                name: name,\n                value: data.get(valueDim, i),\n                selected: retrieveRawAttr(data, i, 'selected')\n            });\n        }\n\n        var geoSource = geoSourceManager.load(this.getMapType(), this.option.nameMap);\n        each$1(geoSource.regions, function (region) {\n            var name = region.name;\n            if (!dataNameMap.get(name)) {\n                selectTargetList.push({name: name});\n                toAppendNames.push(name);\n            }\n        });\n\n        this.updateSelectedMap(selectTargetList);\n\n        // Complete data with missing regions. The consequent processes (like visual\n        // map and render) can not be performed without a \"full data\". For example,\n        // find `dataIndex` by name.\n        data.appendValues([], toAppendNames);\n\n        return data;\n    },\n\n    /**\n     * If no host geo model, return null, which means using a\n     * inner exclusive geo model.\n     */\n    getHostGeoModel: function () {\n        var geoIndex = this.option.geoIndex;\n        return geoIndex != null\n            ? this.dependentModels.geo[geoIndex]\n            : null;\n    },\n\n    getMapType: function () {\n        return (this.getHostGeoModel() || this).option.map;\n    },\n\n    // _fillOption: function (option, mapName) {\n        // Shallow clone\n        // option = zrUtil.extend({}, option);\n\n        // option.data = geoCreator.getFilledRegions(option.data, mapName, option.nameMap);\n\n        // return option;\n    // },\n\n    getRawValue: function (dataIndex) {\n        // Use value stored in data instead because it is calculated from multiple series\n        // FIXME Provide all value of multiple series ?\n        var data = this.getData();\n        return data.get(data.mapDimension('value'), dataIndex);\n    },\n\n    /**\n     * Get model of region\n     * @param  {string} name\n     * @return {module:echarts/model/Model}\n     */\n    getRegionModel: function (regionName) {\n        var data = this.getData();\n        return data.getItemModel(data.indexOfName(regionName));\n    },\n\n    /**\n     * Map tooltip formatter\n     *\n     * @param {number} dataIndex\n     */\n    formatTooltip: function (dataIndex) {\n        // FIXME orignalData and data is a bit confusing\n        var data = this.getData();\n        var formattedValue = addCommas(this.getRawValue(dataIndex));\n        var name = data.getName(dataIndex);\n\n        var seriesGroup = this.seriesGroup;\n        var seriesNames = [];\n        for (var i = 0; i < seriesGroup.length; i++) {\n            var otherIndex = seriesGroup[i].originalData.indexOfName(name);\n            var valueDim = data.mapDimension('value');\n            if (!isNaN(seriesGroup[i].originalData.get(valueDim, otherIndex))) {\n                seriesNames.push(\n                    encodeHTML(seriesGroup[i].name)\n                );\n            }\n        }\n\n        return seriesNames.join(', ') + '<br />'\n            + encodeHTML(name + ' : ' + formattedValue);\n    },\n\n    /**\n     * @implement\n     */\n    getTooltipPosition: function (dataIndex) {\n        if (dataIndex != null) {\n            var name = this.getData().getName(dataIndex);\n            var geo = this.coordinateSystem;\n            var region = geo.getRegion(name);\n\n            return region && geo.dataToPoint(region.center);\n        }\n    },\n\n    setZoom: function (zoom) {\n        this.option.zoom = zoom;\n    },\n\n    setCenter: function (center) {\n        this.option.center = center;\n    },\n\n    defaultOption: {\n        // 一级层叠\n        zlevel: 0,\n        // 二级层叠\n        z: 2,\n\n        coordinateSystem: 'geo',\n\n        // map should be explicitly specified since ec3.\n        map: '',\n\n        // If `geoIndex` is not specified, a exclusive geo will be\n        // created. Otherwise use the specified geo component, and\n        // `map` and `mapType` are ignored.\n        // geoIndex: 0,\n\n        // 'center' | 'left' | 'right' | 'x%' | {number}\n        left: 'center',\n        // 'center' | 'top' | 'bottom' | 'x%' | {number}\n        top: 'center',\n        // right\n        // bottom\n        // width:\n        // height\n\n        // Aspect is width / height. Inited to be geoJson bbox aspect\n        // This parameter is used for scale this aspect\n        aspectScale: 0.75,\n\n        ///// Layout with center and size\n        // If you wan't to put map in a fixed size box with right aspect ratio\n        // This two properties may more conveninet\n        // layoutCenter: [50%, 50%]\n        // layoutSize: 100\n\n\n        // 数值合并方式，默认加和，可选为：\n        // 'sum' | 'average' | 'max' | 'min'\n        // mapValueCalculation: 'sum',\n        // 地图数值计算结果小数精度\n        // mapValuePrecision: 0,\n\n\n        // 显示图例颜色标识（系列标识的小圆点），图例开启时有效\n        showLegendSymbol: true,\n        // 选择模式，默认关闭，可选single，multiple\n        // selectedMode: false,\n        dataRangeHoverLink: true,\n        // 是否开启缩放及漫游模式\n        // roam: false,\n\n        // Define left-top, right-bottom coords to control view\n        // For example, [ [180, 90], [-180, -90] ],\n        // higher priority than center and zoom\n        boundingCoords: null,\n\n        // Default on center of map\n        center: null,\n\n        zoom: 1,\n\n        scaleLimit: null,\n\n        label: {\n            show: false,\n            color: '#000'\n        },\n        // scaleLimit: null,\n        itemStyle: {\n            borderWidth: 0.5,\n            borderColor: '#444',\n            areaColor: '#eee'\n        },\n\n        emphasis: {\n            label: {\n                show: true,\n                color: 'rgb(100,0,0)'\n            },\n            itemStyle: {\n                areaColor: 'rgba(255,215,0,0.8)'\n            }\n        }\n    }\n\n});\n\nmixin(MapSeries, selectableMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ATTR = '\\0_ec_interaction_mutex';\n\nfunction take(zr, resourceKey, userKey) {\n    var store = getStore(zr);\n    store[resourceKey] = userKey;\n}\n\nfunction release(zr, resourceKey, userKey) {\n    var store = getStore(zr);\n    var uKey = store[resourceKey];\n\n    if (uKey === userKey) {\n        store[resourceKey] = null;\n    }\n}\n\nfunction isTaken(zr, resourceKey) {\n    return !!getStore(zr)[resourceKey];\n}\n\nfunction getStore(zr) {\n    return zr[ATTR] || (zr[ATTR] = {});\n}\n\n/**\n * payload: {\n *     type: 'takeGlobalCursor',\n *     key: 'dataZoomSelect', or 'brush', or ...,\n *         If no userKey, release global cursor.\n * }\n */\nregisterAction(\n    {type: 'takeGlobalCursor', event: 'globalCursorTaken', update: 'update'},\n    function () {}\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @alias module:echarts/component/helper/RoamController\n * @constructor\n * @mixin {module:zrender/mixin/Eventful}\n *\n * @param {module:zrender/zrender~ZRender} zr\n */\nfunction RoamController(zr) {\n\n    /**\n     * @type {Function}\n     */\n    this.pointerChecker;\n\n    /**\n     * @type {module:zrender}\n     */\n    this._zr = zr;\n\n    /**\n     * @type {Object}\n     */\n    this._opt = {};\n\n    // Avoid two roamController bind the same handler\n    var bind$$1 = bind;\n    var mousedownHandler = bind$$1(mousedown, this);\n    var mousemoveHandler = bind$$1(mousemove, this);\n    var mouseupHandler = bind$$1(mouseup, this);\n    var mousewheelHandler = bind$$1(mousewheel, this);\n    var pinchHandler = bind$$1(pinch, this);\n\n    Eventful.call(this);\n\n    /**\n     * @param {Function} pointerChecker\n     *                   input: x, y\n     *                   output: boolean\n     */\n    this.setPointerChecker = function (pointerChecker) {\n        this.pointerChecker = pointerChecker;\n    };\n\n    /**\n     * Notice: only enable needed types. For example, if 'zoom'\n     * is not needed, 'zoom' should not be enabled, otherwise\n     * default mousewheel behaviour (scroll page) will be disabled.\n     *\n     * @param  {boolean|string} [controlType=true] Specify the control type,\n     *                          which can be null/undefined or true/false\n     *                          or 'pan/move' or 'zoom'/'scale'\n     * @param {Object} [opt]\n     * @param {Object} [opt.zoomOnMouseWheel=true] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.moveOnMouseMove=true] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.moveOnMouseWheel=false] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.preventDefaultMouseMove=true] When pan.\n     */\n    this.enable = function (controlType, opt) {\n\n        // Disable previous first\n        this.disable();\n\n        this._opt = defaults(clone(opt) || {}, {\n            zoomOnMouseWheel: true,\n            moveOnMouseMove: true,\n            // By default, wheel do not trigger move.\n            moveOnMouseWheel: false,\n            preventDefaultMouseMove: true\n        });\n\n        if (controlType == null) {\n            controlType = true;\n        }\n\n        if (controlType === true || (controlType === 'move' || controlType === 'pan')) {\n            zr.on('mousedown', mousedownHandler);\n            zr.on('mousemove', mousemoveHandler);\n            zr.on('mouseup', mouseupHandler);\n        }\n        if (controlType === true || (controlType === 'scale' || controlType === 'zoom')) {\n            zr.on('mousewheel', mousewheelHandler);\n            zr.on('pinch', pinchHandler);\n        }\n    };\n\n    this.disable = function () {\n        zr.off('mousedown', mousedownHandler);\n        zr.off('mousemove', mousemoveHandler);\n        zr.off('mouseup', mouseupHandler);\n        zr.off('mousewheel', mousewheelHandler);\n        zr.off('pinch', pinchHandler);\n    };\n\n    this.dispose = this.disable;\n\n    this.isDragging = function () {\n        return this._dragging;\n    };\n\n    this.isPinching = function () {\n        return this._pinching;\n    };\n}\n\nmixin(RoamController, Eventful);\n\n\nfunction mousedown(e) {\n    if (isMiddleOrRightButtonOnMouseUpDown(e)\n        || (e.target && e.target.draggable)\n    ) {\n        return;\n    }\n\n    var x = e.offsetX;\n    var y = e.offsetY;\n\n    // Only check on mosedown, but not mousemove.\n    // Mouse can be out of target when mouse moving.\n    if (this.pointerChecker && this.pointerChecker(e, x, y)) {\n        this._x = x;\n        this._y = y;\n        this._dragging = true;\n    }\n}\n\nfunction mousemove(e) {\n    if (!this._dragging\n        || !isAvailableBehavior('moveOnMouseMove', e, this._opt)\n        || e.gestureEvent === 'pinch'\n        || isTaken(this._zr, 'globalPan')\n    ) {\n        return;\n    }\n\n    var x = e.offsetX;\n    var y = e.offsetY;\n\n    var oldX = this._x;\n    var oldY = this._y;\n\n    var dx = x - oldX;\n    var dy = y - oldY;\n\n    this._x = x;\n    this._y = y;\n\n    this._opt.preventDefaultMouseMove && stop(e.event);\n\n    trigger(this, 'pan', 'moveOnMouseMove', e, {\n        dx: dx, dy: dy, oldX: oldX, oldY: oldY, newX: x, newY: y\n    });\n}\n\nfunction mouseup(e) {\n    if (!isMiddleOrRightButtonOnMouseUpDown(e)) {\n        this._dragging = false;\n    }\n}\n\nfunction mousewheel(e) {\n    var shouldZoom = isAvailableBehavior('zoomOnMouseWheel', e, this._opt);\n    var shouldMove = isAvailableBehavior('moveOnMouseWheel', e, this._opt);\n    var wheelDelta = e.wheelDelta;\n    var absWheelDeltaDelta = Math.abs(wheelDelta);\n    var originX = e.offsetX;\n    var originY = e.offsetY;\n\n    // wheelDelta maybe -0 in chrome mac.\n    if (wheelDelta === 0 || (!shouldZoom && !shouldMove)) {\n        return;\n    }\n\n    // If both `shouldZoom` and `shouldMove` is true, trigger\n    // their event both, and the final behavior is determined\n    // by event listener themselves.\n\n    if (shouldZoom) {\n        // Convenience:\n        // Mac and VM Windows on Mac: scroll up: zoom out.\n        // Windows: scroll up: zoom in.\n\n        // FIXME: Should do more test in different environment.\n        // wheelDelta is too complicated in difference nvironment\n        // (https://developer.mozilla.org/en-US/docs/Web/Events/mousewheel),\n        // although it has been normallized by zrender.\n        // wheelDelta of mouse wheel is bigger than touch pad.\n        var factor = absWheelDeltaDelta > 3 ? 1.4 : absWheelDeltaDelta > 1 ? 1.2 : 1.1;\n        var scale = wheelDelta > 0 ? factor : 1 / factor;\n        checkPointerAndTrigger(this, 'zoom', 'zoomOnMouseWheel', e, {\n            scale: scale, originX: originX, originY: originY\n        });\n    }\n\n    if (shouldMove) {\n        // FIXME: Should do more test in different environment.\n        var absDelta = Math.abs(wheelDelta);\n        // wheelDelta of mouse wheel is bigger than touch pad.\n        var scrollDelta = (wheelDelta > 0 ? 1 : -1) * (absDelta > 3 ? 0.4 : absDelta > 1 ? 0.15 : 0.05);\n        checkPointerAndTrigger(this, 'scrollMove', 'moveOnMouseWheel', e, {\n            scrollDelta: scrollDelta, originX: originX, originY: originY\n        });\n    }\n}\n\nfunction pinch(e) {\n    if (isTaken(this._zr, 'globalPan')) {\n        return;\n    }\n    var scale = e.pinchScale > 1 ? 1.1 : 1 / 1.1;\n    checkPointerAndTrigger(this, 'zoom', null, e, {\n        scale: scale, originX: e.pinchX, originY: e.pinchY\n    });\n}\n\nfunction checkPointerAndTrigger(controller, eventName, behaviorToCheck, e, contollerEvent) {\n    if (controller.pointerChecker\n        && controller.pointerChecker(e, contollerEvent.originX, contollerEvent.originY)\n    ) {\n        // When mouse is out of roamController rect,\n        // default befavoius should not be be disabled, otherwise\n        // page sliding is disabled, contrary to expectation.\n        stop(e.event);\n\n        trigger(controller, eventName, behaviorToCheck, e, contollerEvent);\n    }\n}\n\nfunction trigger(controller, eventName, behaviorToCheck, e, contollerEvent) {\n    // Also provide behavior checker for event listener, for some case that\n    // multiple components share one listener.\n    contollerEvent.isAvailableBehavior = bind(isAvailableBehavior, null, behaviorToCheck, e);\n    controller.trigger(eventName, contollerEvent);\n}\n\n// settings: {\n//     zoomOnMouseWheel\n//     moveOnMouseMove\n//     moveOnMouseWheel\n// }\n// The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\nfunction isAvailableBehavior(behaviorToCheck, e, settings) {\n    var setting = settings[behaviorToCheck];\n    return !behaviorToCheck || (\n        setting && (!isString(setting) || e.event[setting + 'Key'])\n    );\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * For geo and graph.\n *\n * @param {Object} controllerHost\n * @param {module:zrender/Element} controllerHost.target\n */\nfunction updateViewOnPan(controllerHost, dx, dy) {\n    var target = controllerHost.target;\n    var pos = target.position;\n    pos[0] += dx;\n    pos[1] += dy;\n    target.dirty();\n}\n\n/**\n * For geo and graph.\n *\n * @param {Object} controllerHost\n * @param {module:zrender/Element} controllerHost.target\n * @param {number} controllerHost.zoom\n * @param {number} controllerHost.zoomLimit like: {min: 1, max: 2}\n */\nfunction updateViewOnZoom(controllerHost, zoomDelta, zoomX, zoomY) {\n    var target = controllerHost.target;\n    var zoomLimit = controllerHost.zoomLimit;\n    var pos = target.position;\n    var scale = target.scale;\n\n    var newZoom = controllerHost.zoom = controllerHost.zoom || 1;\n    newZoom *= zoomDelta;\n    if (zoomLimit) {\n        var zoomMin = zoomLimit.min || 0;\n        var zoomMax = zoomLimit.max || Infinity;\n        newZoom = Math.max(\n            Math.min(zoomMax, newZoom),\n            zoomMin\n        );\n    }\n    var zoomScale = newZoom / controllerHost.zoom;\n    controllerHost.zoom = newZoom;\n    // Keep the mouse center when scaling\n    pos[0] -= (zoomX - pos[0]) * (zoomScale - 1);\n    pos[1] -= (zoomY - pos[1]) * (zoomScale - 1);\n    scale[0] *= zoomScale;\n    scale[1] *= zoomScale;\n\n    target.dirty();\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar IRRELEVANT_EXCLUDES = {'axisPointer': 1, 'tooltip': 1, 'brush': 1};\n\n/**\n * Avoid that: mouse click on a elements that is over geo or graph,\n * but roam is triggered.\n */\nfunction onIrrelevantElement(e, api, targetCoordSysModel) {\n    var model = api.getComponentByElement(e.topTarget);\n    // If model is axisModel, it works only if it is injected with coordinateSystem.\n    var coordSys = model && model.coordinateSystem;\n    return model\n        && model !== targetCoordSysModel\n        && !IRRELEVANT_EXCLUDES[model.mainType]\n        && (coordSys && coordSys.model !== targetCoordSysModel);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction getFixedItemStyle(model, scale) {\n    var itemStyle = model.getItemStyle();\n    var areaColor = model.get('areaColor');\n\n    // If user want the color not to be changed when hover,\n    // they should both set areaColor and color to be null.\n    if (areaColor != null) {\n        itemStyle.fill = areaColor;\n    }\n\n    return itemStyle;\n}\n\nfunction updateMapSelectHandler(mapDraw, mapOrGeoModel, regionsGroup, api, fromView) {\n    regionsGroup.off('click');\n    regionsGroup.off('mousedown');\n\n    if (mapOrGeoModel.get('selectedMode')) {\n\n        regionsGroup.on('mousedown', function () {\n            mapDraw._mouseDownFlag = true;\n        });\n\n        regionsGroup.on('click', function (e) {\n            if (!mapDraw._mouseDownFlag) {\n                return;\n            }\n            mapDraw._mouseDownFlag = false;\n\n            var el = e.target;\n            while (!el.__regions) {\n                el = el.parent;\n            }\n            if (!el) {\n                return;\n            }\n\n            var action = {\n                type: (mapOrGeoModel.mainType === 'geo' ? 'geo' : 'map') + 'ToggleSelect',\n                batch: map(el.__regions, function (region) {\n                    return {\n                        name: region.name,\n                        from: fromView.uid\n                    };\n                })\n            };\n            action[mapOrGeoModel.mainType + 'Id'] = mapOrGeoModel.id;\n\n            api.dispatchAction(action);\n\n            updateMapSelected(mapOrGeoModel, regionsGroup);\n        });\n    }\n}\n\nfunction updateMapSelected(mapOrGeoModel, regionsGroup) {\n    // FIXME\n    regionsGroup.eachChild(function (otherRegionEl) {\n        each$1(otherRegionEl.__regions, function (region) {\n            otherRegionEl.trigger(mapOrGeoModel.isSelected(region.name) ? 'emphasis' : 'normal');\n        });\n    });\n}\n\n/**\n * @alias module:echarts/component/helper/MapDraw\n * @param {module:echarts/ExtensionAPI} api\n * @param {boolean} updateGroup\n */\nfunction MapDraw(api, updateGroup) {\n\n    var group = new Group();\n\n    /**\n     * @type {string}\n     * @private\n     */\n    this.uid = getUID('ec_map_draw');\n\n    /**\n     * @type {module:echarts/component/helper/RoamController}\n     * @private\n     */\n    this._controller = new RoamController(api.getZr());\n\n    /**\n     * @type {Object} {target, zoom, zoomLimit}\n     * @private\n     */\n    this._controllerHost = {target: updateGroup ? group : null};\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = group;\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._updateGroup = updateGroup;\n\n    /**\n     * This flag is used to make sure that only one among\n     * `pan`, `zoom`, `click` can occurs, otherwise 'selected'\n     * action may be triggered when `pan`, which is unexpected.\n     * @type {booelan}\n     */\n    this._mouseDownFlag;\n\n    /**\n     * @type {string}\n     */\n    this._mapName;\n\n    /**\n     * @type {boolean}\n     */\n    this._initialized;\n\n    /**\n     * @type {module:zrender/container/Group}\n     */\n    group.add(this._regionsGroup = new Group());\n\n    /**\n     * @type {module:zrender/container/Group}\n     */\n    group.add(this._backgroundGroup = new Group());\n}\n\nMapDraw.prototype = {\n\n    constructor: MapDraw,\n\n    draw: function (mapOrGeoModel, ecModel, api, fromView, payload) {\n\n        var isGeo = mapOrGeoModel.mainType === 'geo';\n\n        // Map series has data. GEO model that controlled by map series\n        // will be assigned with map data. Other GEO model has no data.\n        var data = mapOrGeoModel.getData && mapOrGeoModel.getData();\n        isGeo && ecModel.eachComponent({mainType: 'series', subType: 'map'}, function (mapSeries) {\n            if (!data && mapSeries.getHostGeoModel() === mapOrGeoModel) {\n                data = mapSeries.getData();\n            }\n        });\n\n        var geo = mapOrGeoModel.coordinateSystem;\n\n        this._updateBackground(geo);\n\n        var regionsGroup = this._regionsGroup;\n        var group = this.group;\n\n        var scale = geo.scale;\n        var transform = {\n            position: geo.position,\n            scale: scale\n        };\n\n        // No animation when first draw or in action\n        if (!regionsGroup.childAt(0) || payload) {\n            group.attr(transform);\n        }\n        else {\n            updateProps(group, transform, mapOrGeoModel);\n        }\n\n        regionsGroup.removeAll();\n\n        var itemStyleAccessPath = ['itemStyle'];\n        var hoverItemStyleAccessPath = ['emphasis', 'itemStyle'];\n        var labelAccessPath = ['label'];\n        var hoverLabelAccessPath = ['emphasis', 'label'];\n        var nameMap = createHashMap();\n\n        each$1(geo.regions, function (region) {\n\n            // Consider in GeoJson properties.name may be duplicated, for example,\n            // there is multiple region named \"United Kindom\" or \"France\" (so many\n            // colonies). And it is not appropriate to merge them in geo, which\n            // will make them share the same label and bring trouble in label\n            // location calculation.\n            var regionGroup = nameMap.get(region.name)\n                || nameMap.set(region.name, new Group());\n\n            var compoundPath = new CompoundPath({\n                shape: {\n                    paths: []\n                }\n            });\n            regionGroup.add(compoundPath);\n\n            var regionModel = mapOrGeoModel.getRegionModel(region.name) || mapOrGeoModel;\n\n            var itemStyleModel = regionModel.getModel(itemStyleAccessPath);\n            var hoverItemStyleModel = regionModel.getModel(hoverItemStyleAccessPath);\n            var itemStyle = getFixedItemStyle(itemStyleModel, scale);\n            var hoverItemStyle = getFixedItemStyle(hoverItemStyleModel, scale);\n\n            var labelModel = regionModel.getModel(labelAccessPath);\n            var hoverLabelModel = regionModel.getModel(hoverLabelAccessPath);\n\n            var dataIdx;\n            // Use the itemStyle in data if has data\n            if (data) {\n                dataIdx = data.indexOfName(region.name);\n                // Only visual color of each item will be used. It can be encoded by dataRange\n                // But visual color of series is used in symbol drawing\n                //\n                // Visual color for each series is for the symbol draw\n                var visualColor = data.getItemVisual(dataIdx, 'color', true);\n                if (visualColor) {\n                    itemStyle.fill = visualColor;\n                }\n            }\n\n            each$1(region.geometries, function (geometry) {\n                if (geometry.type !== 'polygon') {\n                    return;\n                }\n                compoundPath.shape.paths.push(new Polygon({\n                    shape: {\n                        points: geometry.exterior\n                    }\n                }));\n\n                for (var i = 0; i < (geometry.interiors ? geometry.interiors.length : 0); i++) {\n                    compoundPath.shape.paths.push(new Polygon({\n                        shape: {\n                            points: geometry.interiors[i]\n                        }\n                    }));\n                }\n            });\n\n            compoundPath.setStyle(itemStyle);\n            compoundPath.style.strokeNoScale = true;\n            compoundPath.culling = true;\n            // Label\n            var showLabel = labelModel.get('show');\n            var hoverShowLabel = hoverLabelModel.get('show');\n\n            var isDataNaN = data && isNaN(data.get(data.mapDimension('value'), dataIdx));\n            var itemLayout = data && data.getItemLayout(dataIdx);\n            // In the following cases label will be drawn\n            // 1. In map series and data value is NaN\n            // 2. In geo component\n            // 4. Region has no series legendSymbol, which will be add a showLabel flag in mapSymbolLayout\n            if (\n                (isGeo || isDataNaN && (showLabel || hoverShowLabel))\n                || (itemLayout && itemLayout.showLabel)\n            ) {\n                var query = !isGeo ? dataIdx : region.name;\n                var labelFetcher;\n\n                // Consider dataIdx not found.\n                if (!data || dataIdx >= 0) {\n                    labelFetcher = mapOrGeoModel;\n                }\n\n                var textEl = new Text({\n                    position: region.center.slice(),\n                    // FIXME\n                    // label rotation is not support yet in geo or regions of series-map\n                    // that has no data. The rotation will be effected by this `scale`.\n                    // So needed to change to RectText?\n                    scale: [1 / scale[0], 1 / scale[1]],\n                    z2: 10,\n                    silent: true\n                });\n\n                setLabelStyle(\n                    textEl.style, textEl.hoverStyle = {}, labelModel, hoverLabelModel,\n                    {\n                        labelFetcher: labelFetcher,\n                        labelDataIndex: query,\n                        defaultText: region.name,\n                        useInsideStyle: false\n                    },\n                    {\n                        textAlign: 'center',\n                        textVerticalAlign: 'middle'\n                    }\n                );\n\n                regionGroup.add(textEl);\n            }\n\n            // setItemGraphicEl, setHoverStyle after all polygons and labels\n            // are added to the rigionGroup\n            if (data) {\n                data.setItemGraphicEl(dataIdx, regionGroup);\n            }\n            else {\n                var regionModel = mapOrGeoModel.getRegionModel(region.name);\n                // Package custom mouse event for geo component\n                compoundPath.eventData = {\n                    componentType: 'geo',\n                    componentIndex: mapOrGeoModel.componentIndex,\n                    geoIndex: mapOrGeoModel.componentIndex,\n                    name: region.name,\n                    region: (regionModel && regionModel.option) || {}\n                };\n            }\n\n            var groupRegions = regionGroup.__regions || (regionGroup.__regions = []);\n            groupRegions.push(region);\n\n            setHoverStyle(\n                regionGroup,\n                hoverItemStyle,\n                {hoverSilentOnTouch: !!mapOrGeoModel.get('selectedMode')}\n            );\n\n            regionsGroup.add(regionGroup);\n        });\n\n        this._updateController(mapOrGeoModel, ecModel, api);\n\n        updateMapSelectHandler(this, mapOrGeoModel, regionsGroup, api, fromView);\n\n        updateMapSelected(mapOrGeoModel, regionsGroup);\n    },\n\n    remove: function () {\n        this._regionsGroup.removeAll();\n        this._backgroundGroup.removeAll();\n        this._controller.dispose();\n        this._mapName && geoSourceManager.removeGraphic(this._mapName, this.uid);\n        this._mapName = null;\n        this._controllerHost = {};\n    },\n\n    _updateBackground: function (geo) {\n        var mapName = geo.map;\n\n        if (this._mapName !== mapName) {\n            each$1(geoSourceManager.makeGraphic(mapName, this.uid), function (root) {\n                this._backgroundGroup.add(root);\n            }, this);\n        }\n\n        this._mapName = mapName;\n    },\n\n    _updateController: function (mapOrGeoModel, ecModel, api) {\n        var geo = mapOrGeoModel.coordinateSystem;\n        var controller = this._controller;\n        var controllerHost = this._controllerHost;\n\n        controllerHost.zoomLimit = mapOrGeoModel.get('scaleLimit');\n        controllerHost.zoom = geo.getZoom();\n\n        // roamType is will be set default true if it is null\n        controller.enable(mapOrGeoModel.get('roam') || false);\n        var mainType = mapOrGeoModel.mainType;\n\n        function makeActionBase() {\n            var action = {\n                type: 'geoRoam',\n                componentType: mainType\n            };\n            action[mainType + 'Id'] = mapOrGeoModel.id;\n            return action;\n        }\n\n        controller.off('pan').on('pan', function (e) {\n            this._mouseDownFlag = false;\n\n            updateViewOnPan(controllerHost, e.dx, e.dy);\n\n            api.dispatchAction(extend(makeActionBase(), {\n                dx: e.dx,\n                dy: e.dy\n            }));\n        }, this);\n\n        controller.off('zoom').on('zoom', function (e) {\n            this._mouseDownFlag = false;\n\n            updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY);\n\n            api.dispatchAction(extend(makeActionBase(), {\n                zoom: e.scale,\n                originX: e.originX,\n                originY: e.originY\n            }));\n\n            if (this._updateGroup) {\n                var scale = this.group.scale;\n                this._regionsGroup.traverse(function (el) {\n                    if (el.type === 'text') {\n                        el.attr('scale', [1 / scale[0], 1 / scale[1]]);\n                    }\n                });\n            }\n        }, this);\n\n        controller.setPointerChecker(function (e, x, y) {\n            return geo.getViewRectAfterRoam().contain(x, y)\n                && !onIrrelevantElement(e, api, mapOrGeoModel);\n        });\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar HIGH_DOWN_PROP = '__seriesMapHighDown';\nvar RECORD_VERSION_PROP = '__seriesMapCallKey';\n\nextendChartView({\n\n    type: 'map',\n\n    render: function (mapModel, ecModel, api, payload) {\n        // Not render if it is an toggleSelect action from self\n        if (payload && payload.type === 'mapToggleSelect'\n            && payload.from === this.uid\n        ) {\n            return;\n        }\n\n        var group = this.group;\n        group.removeAll();\n\n        if (mapModel.getHostGeoModel()) {\n            return;\n        }\n\n        // Not update map if it is an roam action from self\n        if (!(payload && payload.type === 'geoRoam'\n                && payload.componentType === 'series'\n                && payload.seriesId === mapModel.id\n            )\n        ) {\n            if (mapModel.needsDrawMap) {\n                var mapDraw = this._mapDraw || new MapDraw(api, true);\n                group.add(mapDraw.group);\n\n                mapDraw.draw(mapModel, ecModel, api, this, payload);\n\n                this._mapDraw = mapDraw;\n            }\n            else {\n                // Remove drawed map\n                this._mapDraw && this._mapDraw.remove();\n                this._mapDraw = null;\n            }\n        }\n        else {\n            var mapDraw = this._mapDraw;\n            mapDraw && group.add(mapDraw.group);\n        }\n\n        mapModel.get('showLegendSymbol') && ecModel.getComponent('legend')\n            && this._renderSymbols(mapModel, ecModel, api);\n    },\n\n    remove: function () {\n        this._mapDraw && this._mapDraw.remove();\n        this._mapDraw = null;\n        this.group.removeAll();\n    },\n\n    dispose: function () {\n        this._mapDraw && this._mapDraw.remove();\n        this._mapDraw = null;\n    },\n\n    _renderSymbols: function (mapModel, ecModel, api) {\n        var originalData = mapModel.originalData;\n        var group = this.group;\n\n        originalData.each(originalData.mapDimension('value'), function (value, originalDataIndex) {\n            if (isNaN(value)) {\n                return;\n            }\n\n            var layout = originalData.getItemLayout(originalDataIndex);\n\n            if (!layout || !layout.point) {\n                // Not exists in map\n                return;\n            }\n\n            var point = layout.point;\n            var offset = layout.offset;\n\n            var circle = new Circle({\n                style: {\n                    // Because the special of map draw.\n                    // Which needs statistic of multiple series and draw on one map.\n                    // And each series also need a symbol with legend color\n                    //\n                    // Layout and visual are put one the different data\n                    fill: mapModel.getData().getVisual('color')\n                },\n                shape: {\n                    cx: point[0] + offset * 9,\n                    cy: point[1],\n                    r: 3\n                },\n                silent: true,\n                // Do not overlap the first series, on which labels are displayed.\n                z2: 8 + (!offset ? Z2_EMPHASIS_LIFT + 1 : 0)\n            });\n\n            // Only the series that has the first value on the same region is in charge of rendering the label.\n            // But consider the case:\n            // series: [\n            //     {id: 'X', type: 'map', map: 'm', {data: [{name: 'A', value: 11}, {name: 'B', {value: 22}]},\n            //     {id: 'Y', type: 'map', map: 'm', {data: [{name: 'A', value: 21}, {name: 'C', {value: 33}]}\n            // ]\n            // The offset `0` of item `A` is at series `X`, but of item `C` is at series `Y`.\n            // For backward compatibility, we follow the rule that render label `A` by the\n            // settings on series `X` but render label `C` by the settings on series `Y`.\n            if (!offset) {\n\n                var fullData = mapModel.mainSeries.getData();\n                var name = originalData.getName(originalDataIndex);\n\n                var fullIndex = fullData.indexOfName(name);\n\n                var itemModel = originalData.getItemModel(originalDataIndex);\n                var labelModel = itemModel.getModel('label');\n                var hoverLabelModel = itemModel.getModel('emphasis.label');\n\n                var regionGroup = fullData.getItemGraphicEl(fullIndex);\n\n                // `getFormattedLabel` needs to use `getData` inside. Here\n                // `mapModel.getData()` is shallow cloned from `mainSeries.getData()`.\n                // FIXME\n                // If this is not the `mainSeries`, the item model (like label formatter)\n                // set on original data item will never get. But it has been working\n                // like that from the begining, and this scenario is rarely encountered.\n                // So it won't be fixed until have to.\n                var normalText = retrieve2(\n                    mapModel.getFormattedLabel(fullIndex, 'normal'),\n                    name\n                );\n                var emphasisText = retrieve2(\n                    mapModel.getFormattedLabel(fullIndex, 'emphasis'),\n                    normalText\n                );\n\n                var highDownRecord = regionGroup[HIGH_DOWN_PROP];\n                var recordVersion = Math.random();\n\n                // Prevent from register listeners duplicatedly when roaming.\n                if (!highDownRecord) {\n                    highDownRecord = regionGroup[HIGH_DOWN_PROP] = {};\n                    var onEmphasis = curry(onRegionHighDown, true);\n                    var onNormal = curry(onRegionHighDown, false);\n                    regionGroup.on('mouseover', onEmphasis)\n                        .on('mouseout', onNormal)\n                        .on('emphasis', onEmphasis)\n                        .on('normal', onNormal);\n                }\n\n                // Prevent removed regions effect current grapics.\n                regionGroup[RECORD_VERSION_PROP] = recordVersion;\n                extend(highDownRecord, {\n                    recordVersion: recordVersion,\n                    circle: circle,\n                    labelModel: labelModel,\n                    hoverLabelModel: hoverLabelModel,\n                    emphasisText: emphasisText,\n                    normalText: normalText\n                });\n\n                // FIXME\n                // Consider set option when emphasis.\n                enterRegionHighDown(highDownRecord, false);\n            }\n\n            group.add(circle);\n        });\n    }\n});\n\nfunction onRegionHighDown(toHighOrDown) {\n    var highDownRecord = this[HIGH_DOWN_PROP];\n    if (highDownRecord && highDownRecord.recordVersion === this[RECORD_VERSION_PROP]) {\n        enterRegionHighDown(highDownRecord, toHighOrDown);\n    }\n}\n\nfunction enterRegionHighDown(highDownRecord, toHighOrDown) {\n    var circle = highDownRecord.circle;\n    var labelModel = highDownRecord.labelModel;\n    var hoverLabelModel = highDownRecord.hoverLabelModel;\n    var emphasisText = highDownRecord.emphasisText;\n    var normalText = highDownRecord.normalText;\n\n    if (toHighOrDown) {\n        circle.style.extendFrom(\n            setTextStyle({}, hoverLabelModel, {\n                text: hoverLabelModel.get('show') ? emphasisText : null\n            }, {isRectText: true, useInsideStyle: false}, true)\n        );\n        // Make label upper than others if overlaps.\n        circle.__mapOriginalZ2 = circle.z2;\n        circle.z2 += Z2_EMPHASIS_LIFT;\n    }\n    else {\n        setTextStyle(circle.style, labelModel, {\n            text: labelModel.get('show') ? normalText : null,\n            textPosition: labelModel.getShallow('position') || 'bottom'\n        }, {isRectText: true, useInsideStyle: false});\n        // Trigger normalize style like padding.\n        circle.dirty(false);\n\n        if (circle.__mapOriginalZ2 != null) {\n            circle.z2 = circle.__mapOriginalZ2;\n            circle.__mapOriginalZ2 = null;\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/coord/View} view\n * @param {Object} payload\n * @param {Object} [zoomLimit]\n */\nfunction updateCenterAndZoom(\n    view, payload, zoomLimit\n) {\n    var previousZoom = view.getZoom();\n    var center = view.getCenter();\n    var zoom = payload.zoom;\n\n    var point = view.dataToPoint(center);\n\n    if (payload.dx != null && payload.dy != null) {\n        point[0] -= payload.dx;\n        point[1] -= payload.dy;\n\n        var center = view.pointToData(point);\n        view.setCenter(center);\n    }\n    if (zoom != null) {\n        if (zoomLimit) {\n            var zoomMin = zoomLimit.min || 0;\n            var zoomMax = zoomLimit.max || Infinity;\n            zoom = Math.max(\n                Math.min(previousZoom * zoom, zoomMax),\n                zoomMin\n            ) / previousZoom;\n        }\n\n        // Zoom on given point(originX, originY)\n        view.scale[0] *= zoom;\n        view.scale[1] *= zoom;\n        var position = view.position;\n        var fixX = (payload.originX - position[0]) * (zoom - 1);\n        var fixY = (payload.originY - position[1]) * (zoom - 1);\n\n        position[0] -= fixX;\n        position[1] -= fixY;\n\n        view.updateTransform();\n        // Get the new center\n        var center = view.pointToData(point);\n        view.setCenter(center);\n        view.setZoom(zoom * previousZoom);\n    }\n\n    return {\n        center: view.getCenter(),\n        zoom: view.getZoom()\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @payload\n * @property {string} [componentType=series]\n * @property {number} [dx]\n * @property {number} [dy]\n * @property {number} [zoom]\n * @property {number} [originX]\n * @property {number} [originY]\n */\nregisterAction({\n    type: 'geoRoam',\n    event: 'geoRoam',\n    update: 'updateTransform'\n}, function (payload, ecModel) {\n    var componentType = payload.componentType || 'series';\n\n    ecModel.eachComponent(\n        { mainType: componentType, query: payload },\n        function (componentModel) {\n            var geo = componentModel.coordinateSystem;\n            if (geo.type !== 'geo') {\n                return;\n            }\n\n            var res = updateCenterAndZoom(\n                geo, payload, componentModel.get('scaleLimit')\n            );\n\n            componentModel.setCenter\n                && componentModel.setCenter(res.center);\n\n            componentModel.setZoom\n                && componentModel.setZoom(res.zoom);\n\n            // All map series with same `map` use the same geo coordinate system\n            // So the center and zoom must be in sync. Include the series not selected by legend\n            if (componentType === 'series') {\n                each$1(componentModel.seriesGroup, function (seriesModel) {\n                    seriesModel.setCenter(res.center);\n                    seriesModel.setZoom(res.zoom);\n                });\n            }\n        }\n    );\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Simple view coordinate system\n * Mapping given x, y to transformd view x, y\n */\n\nvar v2ApplyTransform$1 = applyTransform;\n\n// Dummy transform node\nfunction TransformDummy() {\n    Transformable.call(this);\n}\nmixin(TransformDummy, Transformable);\n\nfunction View(name) {\n    /**\n     * @type {string}\n     */\n    this.name = name;\n\n    /**\n     * @type {Object}\n     */\n    this.zoomLimit;\n\n    Transformable.call(this);\n\n    this._roamTransformable = new TransformDummy();\n\n    this._rawTransformable = new TransformDummy();\n\n    this._center;\n    this._zoom;\n}\n\nView.prototype = {\n\n    constructor: View,\n\n    type: 'view',\n\n    /**\n     * @param {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['x', 'y'],\n\n    /**\n     * Set bounding rect\n     * @param {number} x\n     * @param {number} y\n     * @param {number} width\n     * @param {number} height\n     */\n\n    // PENDING to getRect\n    setBoundingRect: function (x, y, width, height) {\n        this._rect = new BoundingRect(x, y, width, height);\n        return this._rect;\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    // PENDING to getRect\n    getBoundingRect: function () {\n        return this._rect;\n    },\n\n    /**\n     * @param {number} x\n     * @param {number} y\n     * @param {number} width\n     * @param {number} height\n     */\n    setViewRect: function (x, y, width, height) {\n        this.transformTo(x, y, width, height);\n        this._viewRect = new BoundingRect(x, y, width, height);\n    },\n\n    /**\n     * Transformed to particular position and size\n     * @param {number} x\n     * @param {number} y\n     * @param {number} width\n     * @param {number} height\n     */\n    transformTo: function (x, y, width, height) {\n        var rect = this.getBoundingRect();\n        var rawTransform = this._rawTransformable;\n\n        rawTransform.transform = rect.calculateTransform(\n            new BoundingRect(x, y, width, height)\n        );\n\n        rawTransform.decomposeTransform();\n\n        this._updateTransform();\n    },\n\n    /**\n     * Set center of view\n     * @param {Array.<number>} [centerCoord]\n     */\n    setCenter: function (centerCoord) {\n        if (!centerCoord) {\n            return;\n        }\n        this._center = centerCoord;\n\n        this._updateCenterAndZoom();\n    },\n\n    /**\n     * @param {number} zoom\n     */\n    setZoom: function (zoom) {\n        zoom = zoom || 1;\n\n        var zoomLimit = this.zoomLimit;\n        if (zoomLimit) {\n            if (zoomLimit.max != null) {\n                zoom = Math.min(zoomLimit.max, zoom);\n            }\n            if (zoomLimit.min != null) {\n                zoom = Math.max(zoomLimit.min, zoom);\n            }\n        }\n        this._zoom = zoom;\n\n        this._updateCenterAndZoom();\n    },\n\n    /**\n     * Get default center without roam\n     */\n    getDefaultCenter: function () {\n        // Rect before any transform\n        var rawRect = this.getBoundingRect();\n        var cx = rawRect.x + rawRect.width / 2;\n        var cy = rawRect.y + rawRect.height / 2;\n\n        return [cx, cy];\n    },\n\n    getCenter: function () {\n        return this._center || this.getDefaultCenter();\n    },\n\n    getZoom: function () {\n        return this._zoom || 1;\n    },\n\n    /**\n     * @return {Array.<number}\n     */\n    getRoamTransform: function () {\n        return this._roamTransformable.getLocalTransform();\n    },\n\n    /**\n     * Remove roam\n     */\n\n    _updateCenterAndZoom: function () {\n        // Must update after view transform updated\n        var rawTransformMatrix = this._rawTransformable.getLocalTransform();\n        var roamTransform = this._roamTransformable;\n        var defaultCenter = this.getDefaultCenter();\n        var center = this.getCenter();\n        var zoom = this.getZoom();\n\n        center = applyTransform([], center, rawTransformMatrix);\n        defaultCenter = applyTransform([], defaultCenter, rawTransformMatrix);\n\n        roamTransform.origin = center;\n        roamTransform.position = [\n            defaultCenter[0] - center[0],\n            defaultCenter[1] - center[1]\n        ];\n        roamTransform.scale = [zoom, zoom];\n\n        this._updateTransform();\n    },\n\n    /**\n     * Update transform from roam and mapLocation\n     * @private\n     */\n    _updateTransform: function () {\n        var roamTransformable = this._roamTransformable;\n        var rawTransformable = this._rawTransformable;\n\n        rawTransformable.parent = roamTransformable;\n        roamTransformable.updateTransform();\n        rawTransformable.updateTransform();\n\n        copy$1(this.transform || (this.transform = []), rawTransformable.transform || create$1());\n\n        this._rawTransform = rawTransformable.getLocalTransform();\n\n        this.invTransform = this.invTransform || [];\n        invert(this.invTransform, this.transform);\n\n        this.decomposeTransform();\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getViewRect: function () {\n        return this._viewRect;\n    },\n\n    /**\n     * Get view rect after roam transform\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getViewRectAfterRoam: function () {\n        var rect = this.getBoundingRect().clone();\n        rect.applyTransform(this.transform);\n        return rect;\n    },\n\n    /**\n     * Convert a single (lon, lat) data item to (x, y) point.\n     * @param {Array.<number>} data\n     * @param {boolean} noRoam\n     * @param {Array.<number>} [out]\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, noRoam, out) {\n        var transform = noRoam ? this._rawTransform : this.transform;\n        out = out || [];\n        return transform\n            ? v2ApplyTransform$1(out, data, transform)\n            : copy(out, data);\n    },\n\n    /**\n     * Convert a (x, y) point to (lon, lat) data\n     * @param {Array.<number>} point\n     * @return {Array.<number>}\n     */\n    pointToData: function (point) {\n        var invTransform = this.invTransform;\n        return invTransform\n            ? v2ApplyTransform$1([], point, invTransform)\n            : [point[0], point[1]];\n    },\n\n    /**\n     * @implements\n     * see {module:echarts/CoodinateSystem}\n     */\n    convertToPixel: curry(doConvert$1, 'dataToPoint'),\n\n    /**\n     * @implements\n     * see {module:echarts/CoodinateSystem}\n     */\n    convertFromPixel: curry(doConvert$1, 'pointToData'),\n\n    /**\n     * @implements\n     * see {module:echarts/CoodinateSystem}\n     */\n    containPoint: function (point) {\n        return this.getViewRectAfterRoam().contain(point[0], point[1]);\n    }\n\n    /**\n     * @return {number}\n     */\n    // getScalarScale: function () {\n    //     // Use determinant square root of transform to mutiply scalar\n    //     var m = this.transform;\n    //     var det = Math.sqrt(Math.abs(m[0] * m[3] - m[2] * m[1]));\n    //     return det;\n    // }\n};\n\nmixin(View, Transformable);\n\nfunction doConvert$1(methodName, ecModel, finder, value) {\n    var seriesModel = finder.seriesModel;\n    var coordSys = seriesModel ? seriesModel.coordinateSystem : null; // e.g., graph.\n    return coordSys === this ? coordSys[methodName](value) : null;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * [Geo description]\n * For backward compatibility, the orginal interface:\n * `name, map, geoJson, specialAreas, nameMap` is kept.\n *\n * @param {string|Object} name\n * @param {string} map Map type\n *        Specify the positioned areas by left, top, width, height\n * @param {Object.<string, string>} [nameMap]\n *        Specify name alias\n * @param {boolean} [invertLongitute=true]\n */\nfunction Geo(name, map$$1, nameMap, invertLongitute) {\n\n    View.call(this, name);\n\n    /**\n     * Map type\n     * @type {string}\n     */\n    this.map = map$$1;\n\n    var source = geoSourceManager.load(map$$1, nameMap);\n\n    this._nameCoordMap = source.nameCoordMap;\n    this._regionsMap = source.regionsMap;\n    this._invertLongitute = invertLongitute == null ? true : invertLongitute;\n\n    /**\n     * @readOnly\n     */\n    this.regions = source.regions;\n\n    /**\n     * @type {module:zrender/src/core/BoundingRect}\n     */\n    this._rect = source.boundingRect;\n}\n\nGeo.prototype = {\n\n    constructor: Geo,\n\n    type: 'geo',\n\n    /**\n     * @param {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['lng', 'lat'],\n\n    /**\n     * If contain given lng,lat coord\n     * @param {Array.<number>}\n     * @readOnly\n     */\n    containCoord: function (coord) {\n        var regions = this.regions;\n        for (var i = 0; i < regions.length; i++) {\n            if (regions[i].contain(coord)) {\n                return true;\n            }\n        }\n        return false;\n    },\n\n    /**\n     * @override\n     */\n    transformTo: function (x, y, width, height) {\n        var rect = this.getBoundingRect();\n        var invertLongitute = this._invertLongitute;\n\n        rect = rect.clone();\n\n        if (invertLongitute) {\n            // Longitute is inverted\n            rect.y = -rect.y - rect.height;\n        }\n\n        var rawTransformable = this._rawTransformable;\n\n        rawTransformable.transform = rect.calculateTransform(\n            new BoundingRect(x, y, width, height)\n        );\n\n        rawTransformable.decomposeTransform();\n\n        if (invertLongitute) {\n            var scale = rawTransformable.scale;\n            scale[1] = -scale[1];\n        }\n\n        rawTransformable.updateTransform();\n\n        this._updateTransform();\n    },\n\n    /**\n     * @param {string} name\n     * @return {module:echarts/coord/geo/Region}\n     */\n    getRegion: function (name) {\n        return this._regionsMap.get(name);\n    },\n\n    getRegionByCoord: function (coord) {\n        var regions = this.regions;\n        for (var i = 0; i < regions.length; i++) {\n            if (regions[i].contain(coord)) {\n                return regions[i];\n            }\n        }\n    },\n\n    /**\n     * Add geoCoord for indexing by name\n     * @param {string} name\n     * @param {Array.<number>} geoCoord\n     */\n    addGeoCoord: function (name, geoCoord) {\n        this._nameCoordMap.set(name, geoCoord);\n    },\n\n    /**\n     * Get geoCoord by name\n     * @param {string} name\n     * @return {Array.<number>}\n     */\n    getGeoCoord: function (name) {\n        return this._nameCoordMap.get(name);\n    },\n\n    /**\n     * @override\n     */\n    getBoundingRect: function () {\n        return this._rect;\n    },\n\n    /**\n     * @param {string|Array.<number>} data\n     * @param {boolean} noRoam\n     * @param {Array.<number>} [out]\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, noRoam, out) {\n        if (typeof data === 'string') {\n            // Map area name to geoCoord\n            data = this.getGeoCoord(data);\n        }\n        if (data) {\n            return View.prototype.dataToPoint.call(this, data, noRoam, out);\n        }\n    },\n\n    /**\n     * @override\n     */\n    convertToPixel: curry(doConvert, 'dataToPoint'),\n\n    /**\n     * @override\n     */\n    convertFromPixel: curry(doConvert, 'pointToData')\n\n};\n\nmixin(Geo, View);\n\nfunction doConvert(methodName, ecModel, finder, value) {\n    var geoModel = finder.geoModel;\n    var seriesModel = finder.seriesModel;\n\n    var coordSys = geoModel\n        ? geoModel.coordinateSystem\n        : seriesModel\n        ? (\n            seriesModel.coordinateSystem // For map.\n            || (seriesModel.getReferringComponents('geo')[0] || {}).coordinateSystem\n        )\n        : null;\n\n    return coordSys === this ? coordSys[methodName](value) : null;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Resize method bound to the geo\n * @param {module:echarts/coord/geo/GeoModel|module:echarts/chart/map/MapModel} geoModel\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction resizeGeo(geoModel, api) {\n\n    var boundingCoords = geoModel.get('boundingCoords');\n    if (boundingCoords != null) {\n        var leftTop = boundingCoords[0];\n        var rightBottom = boundingCoords[1];\n        if (isNaN(leftTop[0]) || isNaN(leftTop[1]) || isNaN(rightBottom[0]) || isNaN(rightBottom[1])) {\n            if (__DEV__) {\n                console.error('Invalid boundingCoords');\n            }\n        }\n        else {\n            this.setBoundingRect(leftTop[0], leftTop[1], rightBottom[0] - leftTop[0], rightBottom[1] - leftTop[1]);\n        }\n    }\n\n    var rect = this.getBoundingRect();\n\n    var boxLayoutOption;\n\n    var center = geoModel.get('layoutCenter');\n    var size = geoModel.get('layoutSize');\n\n    var viewWidth = api.getWidth();\n    var viewHeight = api.getHeight();\n\n    var aspect = rect.width / rect.height * this.aspectScale;\n\n    var useCenterAndSize = false;\n\n    if (center && size) {\n        center = [\n            parsePercent$1(center[0], viewWidth),\n            parsePercent$1(center[1], viewHeight)\n        ];\n        size = parsePercent$1(size, Math.min(viewWidth, viewHeight));\n\n        if (!isNaN(center[0]) && !isNaN(center[1]) && !isNaN(size)) {\n            useCenterAndSize = true;\n        }\n        else {\n            if (__DEV__) {\n                console.warn('Given layoutCenter or layoutSize data are invalid. Use left/top/width/height instead.');\n            }\n        }\n    }\n\n    var viewRect;\n    if (useCenterAndSize) {\n        var viewRect = {};\n        if (aspect > 1) {\n            // Width is same with size\n            viewRect.width = size;\n            viewRect.height = size / aspect;\n        }\n        else {\n            viewRect.height = size;\n            viewRect.width = size * aspect;\n        }\n        viewRect.y = center[1] - viewRect.height / 2;\n        viewRect.x = center[0] - viewRect.width / 2;\n    }\n    else {\n        // Use left/top/width/height\n        boxLayoutOption = geoModel.getBoxLayoutParams();\n\n        // 0.75 rate\n        boxLayoutOption.aspect = aspect;\n\n        viewRect = getLayoutRect(boxLayoutOption, {\n            width: viewWidth,\n            height: viewHeight\n        });\n    }\n\n    this.setViewRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height);\n\n    this.setCenter(geoModel.get('center'));\n    this.setZoom(geoModel.get('zoom'));\n}\n\n/**\n * @param {module:echarts/coord/Geo} geo\n * @param {module:echarts/model/Model} model\n * @inner\n */\nfunction setGeoCoords(geo, model) {\n    each$1(model.get('geoCoord'), function (geoCoord, name) {\n        geo.addGeoCoord(name, geoCoord);\n    });\n}\n\nvar geoCreator = {\n\n    // For deciding which dimensions to use when creating list data\n    dimensions: Geo.prototype.dimensions,\n\n    create: function (ecModel, api) {\n        var geoList = [];\n\n        // FIXME Create each time may be slow\n        ecModel.eachComponent('geo', function (geoModel, idx) {\n            var name = geoModel.get('map');\n\n            var aspectScale = geoModel.get('aspectScale');\n            var invertLongitute = true;\n            var mapRecords = mapDataStorage.retrieveMap(name);\n            if (mapRecords && mapRecords[0] && mapRecords[0].type === 'svg') {\n                aspectScale == null && (aspectScale = 1);\n                invertLongitute = false;\n            }\n            else {\n                aspectScale == null && (aspectScale = 0.75);\n            }\n\n            var geo = new Geo(name + idx, name, geoModel.get('nameMap'), invertLongitute);\n\n            geo.aspectScale = aspectScale;\n            geo.zoomLimit = geoModel.get('scaleLimit');\n            geoList.push(geo);\n\n            setGeoCoords(geo, geoModel);\n\n            geoModel.coordinateSystem = geo;\n            geo.model = geoModel;\n\n            // Inject resize method\n            geo.resize = resizeGeo;\n\n            geo.resize(geoModel, api);\n        });\n\n        ecModel.eachSeries(function (seriesModel) {\n            var coordSys = seriesModel.get('coordinateSystem');\n            if (coordSys === 'geo') {\n                var geoIndex = seriesModel.get('geoIndex') || 0;\n                seriesModel.coordinateSystem = geoList[geoIndex];\n            }\n        });\n\n        // If has map series\n        var mapModelGroupBySeries = {};\n\n        ecModel.eachSeriesByType('map', function (seriesModel) {\n            if (!seriesModel.getHostGeoModel()) {\n                var mapType = seriesModel.getMapType();\n                mapModelGroupBySeries[mapType] = mapModelGroupBySeries[mapType] || [];\n                mapModelGroupBySeries[mapType].push(seriesModel);\n            }\n        });\n\n        each$1(mapModelGroupBySeries, function (mapSeries, mapType) {\n            var nameMapList = map(mapSeries, function (singleMapSeries) {\n                return singleMapSeries.get('nameMap');\n            });\n            var geo = new Geo(mapType, mapType, mergeAll(nameMapList));\n\n            geo.zoomLimit = retrieve.apply(null, map(mapSeries, function (singleMapSeries) {\n                return singleMapSeries.get('scaleLimit');\n            }));\n            geoList.push(geo);\n\n            // Inject resize method\n            geo.resize = resizeGeo;\n            geo.aspectScale = mapSeries[0].get('aspectScale');\n\n            geo.resize(mapSeries[0], api);\n\n            each$1(mapSeries, function (singleMapSeries) {\n                singleMapSeries.coordinateSystem = geo;\n\n                setGeoCoords(geo, singleMapSeries);\n            });\n        });\n\n        return geoList;\n    },\n\n    /**\n     * Fill given regions array\n     * @param  {Array.<Object>} originRegionArr\n     * @param  {string} mapName\n     * @param  {Object} [nameMap]\n     * @return {Array}\n     */\n    getFilledRegions: function (originRegionArr, mapName, nameMap) {\n        // Not use the original\n        var regionsArr = (originRegionArr || []).slice();\n\n        var dataNameMap = createHashMap();\n        for (var i = 0; i < regionsArr.length; i++) {\n            dataNameMap.set(regionsArr[i].name, regionsArr[i]);\n        }\n\n        var source = geoSourceManager.load(mapName, nameMap);\n        each$1(source.regions, function (region) {\n            var name = region.name;\n            !dataNameMap.get(name) && regionsArr.push({name: name});\n        });\n\n        return regionsArr;\n    }\n};\n\nregisterCoordinateSystem('geo', geoCreator);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar mapSymbolLayout = function (ecModel) {\n\n    var processedMapType = {};\n\n    ecModel.eachSeriesByType('map', function (mapSeries) {\n        var mapType = mapSeries.getMapType();\n        if (mapSeries.getHostGeoModel() || processedMapType[mapType]) {\n            return;\n        }\n\n        var mapSymbolOffsets = {};\n\n        each$1(mapSeries.seriesGroup, function (subMapSeries) {\n            var geo = subMapSeries.coordinateSystem;\n            var data = subMapSeries.originalData;\n            if (subMapSeries.get('showLegendSymbol') && ecModel.getComponent('legend')) {\n                data.each(data.mapDimension('value'), function (value, idx) {\n                    var name = data.getName(idx);\n                    var region = geo.getRegion(name);\n\n                    // If input series.data is [11, 22, '-'/null/undefined, 44],\n                    // it will be filled with NaN: [11, 22, NaN, 44] and NaN will\n                    // not be drawn. So here must validate if value is NaN.\n                    if (!region || isNaN(value)) {\n                        return;\n                    }\n\n                    var offset = mapSymbolOffsets[name] || 0;\n\n                    var point = geo.dataToPoint(region.center);\n\n                    mapSymbolOffsets[name] = offset + 1;\n\n                    data.setItemLayout(idx, {\n                        point: point,\n                        offset: offset\n                    });\n                });\n            }\n        });\n\n        // Show label of those region not has legendSymbol(which is offset 0)\n        var data = mapSeries.getData();\n        data.each(function (idx) {\n            var name = data.getName(idx);\n            var layout = data.getItemLayout(idx) || {};\n            layout.showLabel = !mapSymbolOffsets[name];\n            data.setItemLayout(idx, layout);\n        });\n\n        processedMapType[mapType] = true;\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar mapVisual = function (ecModel) {\n    ecModel.eachSeriesByType('map', function (seriesModel) {\n        var colorList = seriesModel.get('color');\n        var itemStyleModel = seriesModel.getModel('itemStyle');\n\n        var areaColor = itemStyleModel.get('areaColor');\n        var color = itemStyleModel.get('color')\n            || colorList[seriesModel.seriesIndex % colorList.length];\n\n        seriesModel.getData().setVisual({\n            'areaColor': areaColor,\n            'color': color\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME 公用？\n/**\n * @param {Array.<module:echarts/data/List>} datas\n * @param {string} statisticType 'average' 'sum'\n * @inner\n */\nfunction dataStatistics(datas, statisticType) {\n    var dataNameMap = {};\n\n    each$1(datas, function (data) {\n        data.each(data.mapDimension('value'), function (value, idx) {\n            // Add prefix to avoid conflict with Object.prototype.\n            var mapKey = 'ec-' + data.getName(idx);\n            dataNameMap[mapKey] = dataNameMap[mapKey] || [];\n            if (!isNaN(value)) {\n                dataNameMap[mapKey].push(value);\n            }\n        });\n    });\n\n    return datas[0].map(datas[0].mapDimension('value'), function (value, idx) {\n        var mapKey = 'ec-' + datas[0].getName(idx);\n        var sum = 0;\n        var min = Infinity;\n        var max = -Infinity;\n        var len = dataNameMap[mapKey].length;\n        for (var i = 0; i < len; i++) {\n            min = Math.min(min, dataNameMap[mapKey][i]);\n            max = Math.max(max, dataNameMap[mapKey][i]);\n            sum += dataNameMap[mapKey][i];\n        }\n        var result;\n        if (statisticType === 'min') {\n            result = min;\n        }\n        else if (statisticType === 'max') {\n            result = max;\n        }\n        else if (statisticType === 'average') {\n            result = sum / len;\n        }\n        else {\n            result = sum;\n        }\n        return len === 0 ? NaN : result;\n    });\n}\n\nvar mapDataStatistic = function (ecModel) {\n    var seriesGroups = {};\n    ecModel.eachSeriesByType('map', function (seriesModel) {\n        var hostGeoModel = seriesModel.getHostGeoModel();\n        var key = hostGeoModel ? 'o' + hostGeoModel.id : 'i' + seriesModel.getMapType();\n        (seriesGroups[key] = seriesGroups[key] || []).push(seriesModel);\n    });\n\n    each$1(seriesGroups, function (seriesList, key) {\n        var data = dataStatistics(\n            map(seriesList, function (seriesModel) {\n                return seriesModel.getData();\n            }),\n            seriesList[0].get('mapValueCalculation')\n        );\n\n        for (var i = 0; i < seriesList.length; i++) {\n            seriesList[i].originalData = seriesList[i].getData();\n        }\n\n        // FIXME Put where?\n        for (var i = 0; i < seriesList.length; i++) {\n            seriesList[i].seriesGroup = seriesList;\n            seriesList[i].needsDrawMap = i === 0 && !seriesList[i].getHostGeoModel();\n\n            seriesList[i].setData(data.cloneShallow());\n            seriesList[i].mainSeries = seriesList[0];\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar backwardCompat$2 = function (option) {\n    // Save geoCoord\n    var mapSeries = [];\n    each$1(option.series, function (seriesOpt) {\n        if (seriesOpt && seriesOpt.type === 'map') {\n            mapSeries.push(seriesOpt);\n            seriesOpt.map = seriesOpt.map || seriesOpt.mapType;\n            // Put x, y, width, height, x2, y2 in the top level\n            defaults(seriesOpt, seriesOpt.mapLocation);\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterLayout(mapSymbolLayout);\nregisterVisual(mapVisual);\nregisterProcessor(PRIORITY.PROCESSOR.STATISTIC, mapDataStatistic);\nregisterPreprocessor(backwardCompat$2);\n\ncreateDataSelectAction('map', [{\n    type: 'mapToggleSelect',\n    event: 'mapselectchanged',\n    method: 'toggleSelected'\n}, {\n    type: 'mapSelect',\n    event: 'mapselected',\n    method: 'select'\n}, {\n    type: 'mapUnSelect',\n    event: 'mapunselected',\n    method: 'unSelect'\n}]);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Link lists and struct (graph or tree)\n */\n\nvar each$7 = each$1;\n\nvar DATAS = '\\0__link_datas';\nvar MAIN_DATA = '\\0__link_mainData';\n\n// Caution:\n// In most case, either list or its shallow clones (see list.cloneShallow)\n// is active in echarts process. So considering heap memory consumption,\n// we do not clone tree or graph, but share them among list and its shallow clones.\n// But in some rare case, we have to keep old list (like do animation in chart). So\n// please take care that both the old list and the new list share the same tree/graph.\n\n/**\n * @param {Object} opt\n * @param {module:echarts/data/List} opt.mainData\n * @param {Object} [opt.struct] For example, instance of Graph or Tree.\n * @param {string} [opt.structAttr] designation: list[structAttr] = struct;\n * @param {Object} [opt.datas] {dataType: data},\n *                 like: {node: nodeList, edge: edgeList}.\n *                 Should contain mainData.\n * @param {Object} [opt.datasAttr] {dataType: attr},\n *                 designation: struct[datasAttr[dataType]] = list;\n */\nfunction linkList(opt) {\n    var mainData = opt.mainData;\n    var datas = opt.datas;\n\n    if (!datas) {\n        datas = {main: mainData};\n        opt.datasAttr = {main: 'data'};\n    }\n    opt.datas = opt.mainData = null;\n\n    linkAll(mainData, datas, opt);\n\n    // Porxy data original methods.\n    each$7(datas, function (data) {\n        each$7(mainData.TRANSFERABLE_METHODS, function (methodName) {\n            data.wrapMethod(methodName, curry(transferInjection, opt));\n        });\n\n    });\n\n    // Beyond transfer, additional features should be added to `cloneShallow`.\n    mainData.wrapMethod('cloneShallow', curry(cloneShallowInjection, opt));\n\n    // Only mainData trigger change, because struct.update may trigger\n    // another changable methods, which may bring about dead lock.\n    each$7(mainData.CHANGABLE_METHODS, function (methodName) {\n        mainData.wrapMethod(methodName, curry(changeInjection, opt));\n    });\n\n    // Make sure datas contains mainData.\n    assert$1(datas[mainData.dataType] === mainData);\n}\n\nfunction transferInjection(opt, res) {\n    if (isMainData(this)) {\n        // Transfer datas to new main data.\n        var datas = extend({}, this[DATAS]);\n        datas[this.dataType] = res;\n        linkAll(res, datas, opt);\n    }\n    else {\n        // Modify the reference in main data to point newData.\n        linkSingle(res, this.dataType, this[MAIN_DATA], opt);\n    }\n    return res;\n}\n\nfunction changeInjection(opt, res) {\n    opt.struct && opt.struct.update(this);\n    return res;\n}\n\nfunction cloneShallowInjection(opt, res) {\n    // cloneShallow, which brings about some fragilities, may be inappropriate\n    // to be exposed as an API. So for implementation simplicity we can make\n    // the restriction that cloneShallow of not-mainData should not be invoked\n    // outside, but only be invoked here.\n    each$7(res[DATAS], function (data, dataType) {\n        data !== res && linkSingle(data.cloneShallow(), dataType, res, opt);\n    });\n    return res;\n}\n\n/**\n * Supplement method to List.\n *\n * @public\n * @param {string} [dataType] If not specified, return mainData.\n * @return {module:echarts/data/List}\n */\nfunction getLinkedData(dataType) {\n    var mainData = this[MAIN_DATA];\n    return (dataType == null || mainData == null)\n        ? mainData\n        : mainData[DATAS][dataType];\n}\n\nfunction isMainData(data) {\n    return data[MAIN_DATA] === data;\n}\n\nfunction linkAll(mainData, datas, opt) {\n    mainData[DATAS] = {};\n    each$7(datas, function (data, dataType) {\n        linkSingle(data, dataType, mainData, opt);\n    });\n}\n\nfunction linkSingle(data, dataType, mainData, opt) {\n    mainData[DATAS][dataType] = data;\n    data[MAIN_DATA] = mainData;\n    data.dataType = dataType;\n\n    if (opt.struct) {\n        data[opt.structAttr] = opt.struct;\n        opt.struct[opt.datasAttr[dataType]] = data;\n    }\n\n    // Supplement method.\n    data.getLinkedData = getLinkedData;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Tree data structure\n *\n * @module echarts/data/Tree\n */\n\n/**\n * @constructor module:echarts/data/Tree~TreeNode\n * @param {string} name\n * @param {module:echarts/data/Tree} hostTree\n */\nvar TreeNode = function (name, hostTree) {\n    /**\n     * @type {string}\n     */\n    this.name = name || '';\n\n    /**\n     * Depth of node\n     *\n     * @type {number}\n     * @readOnly\n     */\n    this.depth = 0;\n\n    /**\n     * Height of the subtree rooted at this node.\n     * @type {number}\n     * @readOnly\n     */\n    this.height = 0;\n\n    /**\n     * @type {module:echarts/data/Tree~TreeNode}\n     * @readOnly\n     */\n    this.parentNode = null;\n\n    /**\n     * Reference to list item.\n     * Do not persistent dataIndex outside,\n     * besause it may be changed by list.\n     * If dataIndex -1,\n     * this node is logical deleted (filtered) in list.\n     *\n     * @type {Object}\n     * @readOnly\n     */\n    this.dataIndex = -1;\n\n    /**\n     * @type {Array.<module:echarts/data/Tree~TreeNode>}\n     * @readOnly\n     */\n    this.children = [];\n\n    /**\n     * @type {Array.<module:echarts/data/Tree~TreeNode>}\n     * @pubilc\n     */\n    this.viewChildren = [];\n\n    /**\n     * @type {moduel:echarts/data/Tree}\n     * @readOnly\n     */\n    this.hostTree = hostTree;\n};\n\nTreeNode.prototype = {\n\n    constructor: TreeNode,\n\n    /**\n     * The node is removed.\n     * @return {boolean} is removed.\n     */\n    isRemoved: function () {\n        return this.dataIndex < 0;\n    },\n\n    /**\n     * Travel this subtree (include this node).\n     * Usage:\n     *    node.eachNode(function () { ... }); // preorder\n     *    node.eachNode('preorder', function () { ... }); // preorder\n     *    node.eachNode('postorder', function () { ... }); // postorder\n     *    node.eachNode(\n     *        {order: 'postorder', attr: 'viewChildren'},\n     *        function () { ... }\n     *    ); // postorder\n     *\n     * @param {(Object|string)} options If string, means order.\n     * @param {string=} options.order 'preorder' or 'postorder'\n     * @param {string=} options.attr 'children' or 'viewChildren'\n     * @param {Function} cb If in preorder and return false,\n     *                      its subtree will not be visited.\n     * @param {Object} [context]\n     */\n    eachNode: function (options, cb, context) {\n        if (typeof options === 'function') {\n            context = cb;\n            cb = options;\n            options = null;\n        }\n\n        options = options || {};\n        if (isString(options)) {\n            options = {order: options};\n        }\n\n        var order = options.order || 'preorder';\n        var children = this[options.attr || 'children'];\n\n        var suppressVisitSub;\n        order === 'preorder' && (suppressVisitSub = cb.call(context, this));\n\n        for (var i = 0; !suppressVisitSub && i < children.length; i++) {\n            children[i].eachNode(options, cb, context);\n        }\n\n        order === 'postorder' && cb.call(context, this);\n    },\n\n    /**\n     * Update depth and height of this subtree.\n     *\n     * @param  {number} depth\n     */\n    updateDepthAndHeight: function (depth) {\n        var height = 0;\n        this.depth = depth;\n        for (var i = 0; i < this.children.length; i++) {\n            var child = this.children[i];\n            child.updateDepthAndHeight(depth + 1);\n            if (child.height > height) {\n                height = child.height;\n            }\n        }\n        this.height = height + 1;\n    },\n\n    /**\n     * @param  {string} id\n     * @return {module:echarts/data/Tree~TreeNode}\n     */\n    getNodeById: function (id) {\n        if (this.getId() === id) {\n            return this;\n        }\n        for (var i = 0, children = this.children, len = children.length; i < len; i++) {\n            var res = children[i].getNodeById(id);\n            if (res) {\n                return res;\n            }\n        }\n    },\n\n    /**\n     * @param {module:echarts/data/Tree~TreeNode} node\n     * @return {boolean}\n     */\n    contains: function (node) {\n        if (node === this) {\n            return true;\n        }\n        for (var i = 0, children = this.children, len = children.length; i < len; i++) {\n            var res = children[i].contains(node);\n            if (res) {\n                return res;\n            }\n        }\n    },\n\n    /**\n     * @param {boolean} includeSelf Default false.\n     * @return {Array.<module:echarts/data/Tree~TreeNode>} order: [root, child, grandchild, ...]\n     */\n    getAncestors: function (includeSelf) {\n        var ancestors = [];\n        var node = includeSelf ? this : this.parentNode;\n        while (node) {\n            ancestors.push(node);\n            node = node.parentNode;\n        }\n        ancestors.reverse();\n        return ancestors;\n    },\n\n    /**\n     * @param {string|Array=} [dimension='value'] Default 'value'. can be 0, 1, 2, 3\n     * @return {number} Value.\n     */\n    getValue: function (dimension) {\n        var data = this.hostTree.data;\n        return data.get(data.getDimension(dimension || 'value'), this.dataIndex);\n    },\n\n    /**\n     * @param {Object} layout\n     * @param {boolean=} [merge=false]\n     */\n    setLayout: function (layout, merge$$1) {\n        this.dataIndex >= 0\n            && this.hostTree.data.setItemLayout(this.dataIndex, layout, merge$$1);\n    },\n\n    /**\n     * @return {Object} layout\n     */\n    getLayout: function () {\n        return this.hostTree.data.getItemLayout(this.dataIndex);\n    },\n\n    /**\n     * @param {string} [path]\n     * @return {module:echarts/model/Model}\n     */\n    getModel: function (path) {\n        if (this.dataIndex < 0) {\n            return;\n        }\n        var hostTree = this.hostTree;\n        var itemModel = hostTree.data.getItemModel(this.dataIndex);\n        var levelModel = this.getLevelModel();\n        var leavesModel;\n        if (!levelModel && (this.children.length === 0 || (this.children.length !== 0 && this.isExpand === false))) {\n            leavesModel = this.getLeavesModel();\n        }\n        return itemModel.getModel(path, (levelModel || leavesModel || hostTree.hostModel).getModel(path));\n    },\n\n    /**\n     * @return {module:echarts/model/Model}\n     */\n    getLevelModel: function () {\n        return (this.hostTree.levelModels || [])[this.depth];\n    },\n\n    /**\n     * @return {module:echarts/model/Model}\n     */\n    getLeavesModel: function () {\n        return this.hostTree.leavesModel;\n    },\n\n    /**\n     * @example\n     *  setItemVisual('color', color);\n     *  setItemVisual({\n     *      'color': color\n     *  });\n     */\n    setVisual: function (key, value) {\n        this.dataIndex >= 0\n            && this.hostTree.data.setItemVisual(this.dataIndex, key, value);\n    },\n\n    /**\n     * Get item visual\n     */\n    getVisual: function (key, ignoreParent) {\n        return this.hostTree.data.getItemVisual(this.dataIndex, key, ignoreParent);\n    },\n\n    /**\n     * @public\n     * @return {number}\n     */\n    getRawIndex: function () {\n        return this.hostTree.data.getRawIndex(this.dataIndex);\n    },\n\n    /**\n     * @public\n     * @return {string}\n     */\n    getId: function () {\n        return this.hostTree.data.getId(this.dataIndex);\n    },\n\n    /**\n     * if this is an ancestor of another node\n     *\n     * @public\n     * @param {TreeNode} node another node\n     * @return {boolean} if is ancestor\n     */\n    isAncestorOf: function (node) {\n        var parent = node.parentNode;\n        while (parent) {\n            if (parent === this) {\n                return true;\n            }\n            parent = parent.parentNode;\n        }\n        return false;\n    },\n\n    /**\n     * if this is an descendant of another node\n     *\n     * @public\n     * @param {TreeNode} node another node\n     * @return {boolean} if is descendant\n     */\n    isDescendantOf: function (node) {\n        return node !== this && node.isAncestorOf(this);\n    }\n};\n\n/**\n * @constructor\n * @alias module:echarts/data/Tree\n * @param {module:echarts/model/Model} hostModel\n * @param {Array.<Object>} levelOptions\n * @param {Object} leavesOption\n */\nfunction Tree(hostModel, levelOptions, leavesOption) {\n    /**\n     * @type {module:echarts/data/Tree~TreeNode}\n     * @readOnly\n     */\n    this.root;\n\n    /**\n     * @type {module:echarts/data/List}\n     * @readOnly\n     */\n    this.data;\n\n    /**\n     * Index of each item is the same as the raw index of coresponding list item.\n     * @private\n     * @type {Array.<module:echarts/data/Tree~TreeNode}\n     */\n    this._nodes = [];\n\n    /**\n     * @private\n     * @readOnly\n     * @type {module:echarts/model/Model}\n     */\n    this.hostModel = hostModel;\n\n    /**\n     * @private\n     * @readOnly\n     * @type {Array.<module:echarts/model/Model}\n     */\n    this.levelModels = map(levelOptions || [], function (levelDefine) {\n        return new Model(levelDefine, hostModel, hostModel.ecModel);\n    });\n\n    this.leavesModel = new Model(leavesOption || {}, hostModel, hostModel.ecModel);\n}\n\nTree.prototype = {\n\n    constructor: Tree,\n\n    type: 'tree',\n\n    /**\n     * Travel this subtree (include this node).\n     * Usage:\n     *    node.eachNode(function () { ... }); // preorder\n     *    node.eachNode('preorder', function () { ... }); // preorder\n     *    node.eachNode('postorder', function () { ... }); // postorder\n     *    node.eachNode(\n     *        {order: 'postorder', attr: 'viewChildren'},\n     *        function () { ... }\n     *    ); // postorder\n     *\n     * @param {(Object|string)} options If string, means order.\n     * @param {string=} options.order 'preorder' or 'postorder'\n     * @param {string=} options.attr 'children' or 'viewChildren'\n     * @param {Function} cb\n     * @param {Object}   [context]\n     */\n    eachNode: function (options, cb, context) {\n        this.root.eachNode(options, cb, context);\n    },\n\n    /**\n     * @param {number} dataIndex\n     * @return {module:echarts/data/Tree~TreeNode}\n     */\n    getNodeByDataIndex: function (dataIndex) {\n        var rawIndex = this.data.getRawIndex(dataIndex);\n        return this._nodes[rawIndex];\n    },\n\n    /**\n     * @param {string} name\n     * @return {module:echarts/data/Tree~TreeNode}\n     */\n    getNodeByName: function (name) {\n        return this.root.getNodeByName(name);\n    },\n\n    /**\n     * Update item available by list,\n     * when list has been performed options like 'filterSelf' or 'map'.\n     */\n    update: function () {\n        var data = this.data;\n        var nodes = this._nodes;\n\n        for (var i = 0, len = nodes.length; i < len; i++) {\n            nodes[i].dataIndex = -1;\n        }\n\n        for (var i = 0, len = data.count(); i < len; i++) {\n            nodes[data.getRawIndex(i)].dataIndex = i;\n        }\n    },\n\n    /**\n     * Clear all layouts\n     */\n    clearLayouts: function () {\n        this.data.clearItemLayouts();\n    }\n};\n\n/**\n * data node format:\n * {\n *     name: ...\n *     value: ...\n *     children: [\n *         {\n *             name: ...\n *             value: ...\n *             children: ...\n *         },\n *         ...\n *     ]\n * }\n *\n * @static\n * @param {Object} dataRoot Root node.\n * @param {module:echarts/model/Model} hostModel\n * @param {Object} treeOptions\n * @param {Array.<Object>} treeOptions.levels\n * @param {Array.<Object>} treeOptions.leaves\n * @return module:echarts/data/Tree\n */\nTree.createTree = function (dataRoot, hostModel, treeOptions) {\n\n    var tree = new Tree(hostModel, treeOptions.levels, treeOptions.leaves);\n    var listData = [];\n    var dimMax = 1;\n\n    buildHierarchy(dataRoot);\n\n    function buildHierarchy(dataNode, parentNode) {\n        var value = dataNode.value;\n        dimMax = Math.max(dimMax, isArray(value) ? value.length : 1);\n\n        listData.push(dataNode);\n\n        var node = new TreeNode(dataNode.name, tree);\n        parentNode\n            ? addChild(node, parentNode)\n            : (tree.root = node);\n\n        tree._nodes.push(node);\n\n        var children = dataNode.children;\n        if (children) {\n            for (var i = 0; i < children.length; i++) {\n                buildHierarchy(children[i], node);\n            }\n        }\n    }\n\n    tree.root.updateDepthAndHeight(0);\n\n    var dimensionsInfo = createDimensions(listData, {\n        coordDimensions: ['value'],\n        dimensionsCount: dimMax\n    });\n\n    var list = new List(dimensionsInfo, hostModel);\n    list.initData(listData);\n\n    linkList({\n        mainData: list,\n        struct: tree,\n        structAttr: 'tree'\n    });\n\n    tree.update();\n\n    return tree;\n};\n\n/**\n * It is needed to consider the mess of 'list', 'hostModel' when creating a TreeNote,\n * so this function is not ready and not necessary to be public.\n *\n * @param {(module:echarts/data/Tree~TreeNode|Object)} child\n */\nfunction addChild(child, node) {\n    var children = node.children;\n    if (child.parentNode === node) {\n        return;\n    }\n\n    children.push(child);\n    child.parentNode = node;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Create data struct and define tree view's series model\n * @author Deqing Li(annong035@gmail.com)\n */\n\nSeriesModel.extend({\n\n    type: 'series.tree',\n\n    layoutInfo: null,\n\n    // can support the position parameters 'left', 'top','right','bottom', 'width',\n    // 'height' in the setOption() with 'merge' mode normal.\n    layoutMode: 'box',\n\n    /**\n     * Init a tree data structure from data in option series\n     * @param  {Object} option  the object used to config echarts view\n     * @return {module:echarts/data/List} storage initial data\n     */\n    getInitialData: function (option) {\n\n        //create an virtual root\n        var root = {name: option.name, children: option.data};\n\n        var leaves = option.leaves || {};\n\n        var treeOption = {};\n\n        treeOption.leaves = leaves;\n\n        var tree = Tree.createTree(root, this, treeOption);\n\n        var treeDepth = 0;\n\n        tree.eachNode('preorder', function (node) {\n            if (node.depth > treeDepth) {\n                treeDepth = node.depth;\n            }\n        });\n\n        var expandAndCollapse = option.expandAndCollapse;\n        var expandTreeDepth = (expandAndCollapse && option.initialTreeDepth >= 0)\n            ? option.initialTreeDepth : treeDepth;\n\n        tree.root.eachNode('preorder', function (node) {\n            var item = node.hostTree.data.getRawDataItem(node.dataIndex);\n            // Add item.collapsed != null, because users can collapse node original in the series.data.\n            node.isExpand = (item && item.collapsed != null)\n                ? !item.collapsed\n                : node.depth <= expandTreeDepth;\n        });\n\n        return tree.data;\n    },\n\n    /**\n     * Make the configuration 'orient' backward compatibly, with 'horizontal = LR', 'vertical = TB'.\n     * @returns {string} orient\n     */\n    getOrient: function () {\n        var orient = this.get('orient');\n        if (orient === 'horizontal') {\n            orient = 'LR';\n        }\n        else if (orient === 'vertical') {\n            orient = 'TB';\n        }\n        return orient;\n    },\n\n    setZoom: function (zoom) {\n        this.option.zoom = zoom;\n    },\n\n    setCenter: function (center) {\n        this.option.center = center;\n    },\n\n    /**\n     * @override\n     * @param {number} dataIndex\n     */\n    formatTooltip: function (dataIndex) {\n        var tree = this.getData().tree;\n        var realRoot = tree.root.children[0];\n        var node = tree.getNodeByDataIndex(dataIndex);\n        var value = node.getValue();\n        var name = node.name;\n        while (node && (node !== realRoot)) {\n            name = node.parentNode.name + '.' + name;\n            node = node.parentNode;\n        }\n        return encodeHTML(name + (\n            (isNaN(value) || value == null) ? '' : ' : ' + value\n        ));\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'view',\n\n        // the position of the whole view\n        left: '12%',\n        top: '12%',\n        right: '12%',\n        bottom: '12%',\n\n        // the layout of the tree, two value can be selected, 'orthogonal' or 'radial'\n        layout: 'orthogonal',\n\n        roam: false, // true | false | 'move' | 'scale', see module:component/helper/RoamController.\n        // Symbol size scale ratio in roam\n        nodeScaleRatio: 0.4,\n\n        // Default on center of graph\n        center: null,\n\n        zoom: 1,\n\n        // The orient of orthoginal layout, can be setted to 'LR', 'TB', 'RL', 'BT'.\n        // and the backward compatibility configuration 'horizontal = LR', 'vertical = TB'.\n        orient: 'LR',\n\n        symbol: 'emptyCircle',\n\n        symbolSize: 7,\n\n        expandAndCollapse: true,\n\n        initialTreeDepth: 2,\n\n        lineStyle: {\n            color: '#ccc',\n            width: 1.5,\n            curveness: 0.5\n        },\n\n        itemStyle: {\n            color: 'lightsteelblue',\n            borderColor: '#c23531',\n            borderWidth: 1.5\n        },\n\n        label: {\n            show: true,\n            color: '#555'\n        },\n\n        leaves: {\n            label: {\n                show: true\n            }\n        },\n\n        animationEasing: 'linear',\n\n        animationDuration: 700,\n\n        animationDurationUpdate: 1000\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The tree layoutHelper implementation was originally copied from\n* \"d3.js\"(https://github.com/d3/d3-hierarchy) with\n* some modifications made for this project.\n* (see more details in the comment of the specific method below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the licence of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\n/**\n * @file The layout algorithm of node-link tree diagrams. Here we using Reingold-Tilford algorithm to drawing\n *       the tree.\n */\n\n/**\n * Initialize all computational message for following algorithm.\n *\n * @param  {module:echarts/data/Tree~TreeNode} root   The virtual root of the tree.\n */\nfunction init$2(root) {\n    root.hierNode = {\n        defaultAncestor: null,\n        ancestor: root,\n        prelim: 0,\n        modifier: 0,\n        change: 0,\n        shift: 0,\n        i: 0,\n        thread: null\n    };\n\n    var nodes = [root];\n    var node;\n    var children;\n\n    while (node = nodes.pop()) { // jshint ignore:line\n        children = node.children;\n        if (node.isExpand && children.length) {\n            var n = children.length;\n            for (var i = n - 1; i >= 0; i--) {\n                var child = children[i];\n                child.hierNode = {\n                    defaultAncestor: null,\n                    ancestor: child,\n                    prelim: 0,\n                    modifier: 0,\n                    change: 0,\n                    shift: 0,\n                    i: i,\n                    thread: null\n                };\n                nodes.push(child);\n            }\n        }\n    }\n}\n\n/**\n * The implementation of this function was originally copied from \"d3.js\"\n * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n *\n * Computes a preliminary x coordinate for node. Before that, this function is\n * applied recursively to the children of node, as well as the function\n * apportion(). After spacing out the children by calling executeShifts(), the\n * node is placed to the midpoint of its outermost children.\n *\n * @param  {module:echarts/data/Tree~TreeNode} node\n * @param {Function} separation\n */\nfunction firstWalk(node, separation) {\n    var children = node.isExpand ? node.children : [];\n    var siblings = node.parentNode.children;\n    var subtreeW = node.hierNode.i ? siblings[node.hierNode.i - 1] : null;\n    if (children.length) {\n        executeShifts(node);\n        var midPoint = (children[0].hierNode.prelim + children[children.length - 1].hierNode.prelim) / 2;\n        if (subtreeW) {\n            node.hierNode.prelim = subtreeW.hierNode.prelim + separation(node, subtreeW);\n            node.hierNode.modifier = node.hierNode.prelim - midPoint;\n        }\n        else {\n            node.hierNode.prelim = midPoint;\n        }\n    }\n    else if (subtreeW) {\n        node.hierNode.prelim = subtreeW.hierNode.prelim + separation(node, subtreeW);\n    }\n    node.parentNode.hierNode.defaultAncestor = apportion(\n        node,\n        subtreeW,\n        node.parentNode.hierNode.defaultAncestor || siblings[0],\n        separation\n    );\n}\n\n\n/**\n * The implementation of this function was originally copied from \"d3.js\"\n * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n *\n * Computes all real x-coordinates by summing up the modifiers recursively.\n *\n * @param  {module:echarts/data/Tree~TreeNode} node\n */\nfunction secondWalk(node) {\n    var nodeX = node.hierNode.prelim + node.parentNode.hierNode.modifier;\n    node.setLayout({x: nodeX}, true);\n    node.hierNode.modifier += node.parentNode.hierNode.modifier;\n}\n\n\nfunction separation(cb) {\n    return arguments.length ? cb : defaultSeparation;\n}\n\n/**\n * Transform the common coordinate to radial coordinate.\n *\n * @param  {number} x\n * @param  {number} y\n * @return {Object}\n */\nfunction radialCoordinate(x, y) {\n    var radialCoor = {};\n    x -= Math.PI / 2;\n    radialCoor.x = y * Math.cos(x);\n    radialCoor.y = y * Math.sin(x);\n    return radialCoor;\n}\n\n/**\n * Get the layout position of the whole view.\n *\n * @param {module:echarts/model/Series} seriesModel  the model object of sankey series\n * @param {module:echarts/ExtensionAPI} api  provide the API list that the developer can call\n * @return {module:zrender/core/BoundingRect}  size of rect to draw the sankey view\n */\nfunction getViewRect(seriesModel, api) {\n    return getLayoutRect(\n        seriesModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        }\n    );\n}\n\n/**\n * All other shifts, applied to the smaller subtrees between w- and w+, are\n * performed by this function.\n *\n * The implementation of this function was originally copied from \"d3.js\"\n * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n *\n * @param  {module:echarts/data/Tree~TreeNode} node\n */\nfunction executeShifts(node) {\n    var children = node.children;\n    var n = children.length;\n    var shift = 0;\n    var change = 0;\n    while (--n >= 0) {\n        var child = children[n];\n        child.hierNode.prelim += shift;\n        child.hierNode.modifier += shift;\n        change += child.hierNode.change;\n        shift += child.hierNode.shift + change;\n    }\n}\n\n/**\n * The implementation of this function was originally copied from \"d3.js\"\n * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n *\n * The core of the algorithm. Here, a new subtree is combined with the\n * previous subtrees. Threads are used to traverse the inside and outside\n * contours of the left and right subtree up to the highest common level.\n * Whenever two nodes of the inside contours conflict, we compute the left\n * one of the greatest uncommon ancestors using the function nextAncestor()\n * and call moveSubtree() to shift the subtree and prepare the shifts of\n * smaller subtrees. Finally, we add a new thread (if necessary).\n *\n * @param  {module:echarts/data/Tree~TreeNode} subtreeV\n * @param  {module:echarts/data/Tree~TreeNode} subtreeW\n * @param  {module:echarts/data/Tree~TreeNode} ancestor\n * @param  {Function} separation\n * @return {module:echarts/data/Tree~TreeNode}\n */\nfunction apportion(subtreeV, subtreeW, ancestor, separation) {\n\n    if (subtreeW) {\n        var nodeOutRight = subtreeV;\n        var nodeInRight = subtreeV;\n        var nodeOutLeft = nodeInRight.parentNode.children[0];\n        var nodeInLeft = subtreeW;\n\n        var sumOutRight = nodeOutRight.hierNode.modifier;\n        var sumInRight = nodeInRight.hierNode.modifier;\n        var sumOutLeft = nodeOutLeft.hierNode.modifier;\n        var sumInLeft = nodeInLeft.hierNode.modifier;\n\n        while (nodeInLeft = nextRight(nodeInLeft), nodeInRight = nextLeft(nodeInRight), nodeInLeft && nodeInRight) {\n            nodeOutRight = nextRight(nodeOutRight);\n            nodeOutLeft = nextLeft(nodeOutLeft);\n            nodeOutRight.hierNode.ancestor = subtreeV;\n            var shift = nodeInLeft.hierNode.prelim + sumInLeft - nodeInRight.hierNode.prelim\n                    - sumInRight + separation(nodeInLeft, nodeInRight);\n            if (shift > 0) {\n                moveSubtree(nextAncestor(nodeInLeft, subtreeV, ancestor), subtreeV, shift);\n                sumInRight += shift;\n                sumOutRight += shift;\n            }\n            sumInLeft += nodeInLeft.hierNode.modifier;\n            sumInRight += nodeInRight.hierNode.modifier;\n            sumOutRight += nodeOutRight.hierNode.modifier;\n            sumOutLeft += nodeOutLeft.hierNode.modifier;\n        }\n        if (nodeInLeft && !nextRight(nodeOutRight)) {\n            nodeOutRight.hierNode.thread = nodeInLeft;\n            nodeOutRight.hierNode.modifier += sumInLeft - sumOutRight;\n\n        }\n        if (nodeInRight && !nextLeft(nodeOutLeft)) {\n            nodeOutLeft.hierNode.thread = nodeInRight;\n            nodeOutLeft.hierNode.modifier += sumInRight - sumOutLeft;\n            ancestor = subtreeV;\n        }\n    }\n    return ancestor;\n}\n\n/**\n * This function is used to traverse the right contour of a subtree.\n * It returns the rightmost child of node or the thread of node. The function\n * returns null if and only if node is on the highest depth of its subtree.\n *\n * @param  {module:echarts/data/Tree~TreeNode} node\n * @return {module:echarts/data/Tree~TreeNode}\n */\nfunction nextRight(node) {\n    var children = node.children;\n    return children.length && node.isExpand ? children[children.length - 1] : node.hierNode.thread;\n}\n\n/**\n * This function is used to traverse the left contour of a subtree (or a subforest).\n * It returns the leftmost child of node or the thread of node. The function\n * returns null if and only if node is on the highest depth of its subtree.\n *\n * @param  {module:echarts/data/Tree~TreeNode} node\n * @return {module:echarts/data/Tree~TreeNode}\n */\nfunction nextLeft(node) {\n    var children = node.children;\n    return children.length && node.isExpand ? children[0] : node.hierNode.thread;\n}\n\n/**\n * If nodeInLeft’s ancestor is a sibling of node, returns nodeInLeft’s ancestor.\n * Otherwise, returns the specified ancestor.\n *\n * @param  {module:echarts/data/Tree~TreeNode} nodeInLeft\n * @param  {module:echarts/data/Tree~TreeNode} node\n * @param  {module:echarts/data/Tree~TreeNode} ancestor\n * @return {module:echarts/data/Tree~TreeNode}\n */\nfunction nextAncestor(nodeInLeft, node, ancestor) {\n    return nodeInLeft.hierNode.ancestor.parentNode === node.parentNode\n        ? nodeInLeft.hierNode.ancestor : ancestor;\n}\n\n/**\n * The implementation of this function was originally copied from \"d3.js\"\n * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n *\n * Shifts the current subtree rooted at wr.\n * This is done by increasing prelim(w+) and modifier(w+) by shift.\n *\n * @param  {module:echarts/data/Tree~TreeNode} wl\n * @param  {module:echarts/data/Tree~TreeNode} wr\n * @param  {number} shift [description]\n */\nfunction moveSubtree(wl, wr, shift) {\n    var change = shift / (wr.hierNode.i - wl.hierNode.i);\n    wr.hierNode.change -= change;\n    wr.hierNode.shift += shift;\n    wr.hierNode.modifier += shift;\n    wr.hierNode.prelim += shift;\n    wl.hierNode.change += change;\n}\n\n/**\n * The implementation of this function was originally copied from \"d3.js\"\n * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n */\nfunction defaultSeparation(node1, node2) {\n    return node1.parentNode === node2.parentNode ? 1 : 2;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file This file used to draw tree view.\n * @author Deqing Li(annong035@gmail.com)\n */\n\nextendChartView({\n\n    type: 'tree',\n\n    /**\n     * Init the chart\n     * @override\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    init: function (ecModel, api) {\n\n        /**\n         * @private\n         * @type {module:echarts/data/Tree}\n         */\n        this._oldTree;\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this._mainGroup = new Group();\n\n        /**\n         * @private\n         * @type {module:echarts/componet/helper/RoamController}\n         */\n        this._controller = new RoamController(api.getZr());\n\n        this._controllerHost = {target: this.group};\n\n        this.group.add(this._mainGroup);\n    },\n\n    render: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n\n        var layoutInfo = seriesModel.layoutInfo;\n\n        var group = this._mainGroup;\n\n        var layout = seriesModel.get('layout');\n\n        if (layout === 'radial') {\n            group.attr('position', [layoutInfo.x + layoutInfo.width / 2, layoutInfo.y + layoutInfo.height / 2]);\n        }\n        else {\n            group.attr('position', [layoutInfo.x, layoutInfo.y]);\n        }\n\n        this._updateViewCoordSys(seriesModel);\n        this._updateController(seriesModel, ecModel, api);\n\n        var oldData = this._data;\n\n        var seriesScope = {\n            expandAndCollapse: seriesModel.get('expandAndCollapse'),\n            layout: layout,\n            orient: seriesModel.getOrient(),\n            curvature: seriesModel.get('lineStyle.curveness'),\n            symbolRotate: seriesModel.get('symbolRotate'),\n            symbolOffset: seriesModel.get('symbolOffset'),\n            hoverAnimation: seriesModel.get('hoverAnimation'),\n            useNameLabel: true,\n            fadeIn: true\n        };\n\n        data.diff(oldData)\n            .add(function (newIdx) {\n                if (symbolNeedsDraw$1(data, newIdx)) {\n                    // Create node and edge\n                    updateNode(data, newIdx, null, group, seriesModel, seriesScope);\n                }\n            })\n            .update(function (newIdx, oldIdx) {\n                var symbolEl = oldData.getItemGraphicEl(oldIdx);\n                if (!symbolNeedsDraw$1(data, newIdx)) {\n                    symbolEl && removeNode(oldData, oldIdx, symbolEl, group, seriesModel, seriesScope);\n                    return;\n                }\n                // Update node and edge\n                updateNode(data, newIdx, symbolEl, group, seriesModel, seriesScope);\n            })\n            .remove(function (oldIdx) {\n                var symbolEl = oldData.getItemGraphicEl(oldIdx);\n                // When remove a collapsed node of subtree, since the collapsed\n                // node haven't been initialized with a symbol element,\n                // you can't found it's symbol element through index.\n                // so if we want to remove the symbol element we should insure\n                // that the symbol element is not null.\n                if (symbolEl) {\n                    removeNode(oldData, oldIdx, symbolEl, group, seriesModel, seriesScope);\n                }\n            })\n            .execute();\n\n        this._nodeScaleRatio = seriesModel.get('nodeScaleRatio');\n\n        this._updateNodeAndLinkScale(seriesModel);\n\n        if (seriesScope.expandAndCollapse === true) {\n            data.eachItemGraphicEl(function (el, dataIndex) {\n                el.off('click').on('click', function () {\n                    api.dispatchAction({\n                        type: 'treeExpandAndCollapse',\n                        seriesId: seriesModel.id,\n                        dataIndex: dataIndex\n                    });\n                });\n            });\n        }\n        this._data = data;\n    },\n\n    _updateViewCoordSys: function (seriesModel) {\n        var data = seriesModel.getData();\n        var points = [];\n        data.each(function (idx) {\n            var layout = data.getItemLayout(idx);\n            if (layout && !isNaN(layout.x) && !isNaN(layout.y)) {\n                points.push([+layout.x, +layout.y]);\n            }\n        });\n        var min = [];\n        var max = [];\n        fromPoints(points, min, max);\n        // If width or height is 0\n        if (max[0] - min[0] === 0) {\n            max[0] += 1;\n            min[0] -= 1;\n        }\n        if (max[1] - min[1] === 0) {\n            max[1] += 1;\n            min[1] -= 1;\n        }\n\n        var viewCoordSys = seriesModel.coordinateSystem = new View();\n        viewCoordSys.zoomLimit = seriesModel.get('scaleLimit');\n\n        viewCoordSys.setBoundingRect(min[0], min[1], max[0] - min[0], max[1] - min[1]);\n\n        viewCoordSys.setCenter(seriesModel.get('center'));\n        viewCoordSys.setZoom(seriesModel.get('zoom'));\n\n        // Here we use viewCoordSys just for computing the 'position' and 'scale' of the group\n        this.group.attr({\n            position: viewCoordSys.position,\n            scale: viewCoordSys.scale\n        });\n\n        this._viewCoordSys = viewCoordSys;\n    },\n\n    _updateController: function (seriesModel, ecModel, api) {\n        var controller = this._controller;\n        var controllerHost = this._controllerHost;\n        var group = this.group;\n        controller.setPointerChecker(function (e, x, y) {\n            var rect = group.getBoundingRect();\n            rect.applyTransform(group.transform);\n            return rect.contain(x, y)\n                && !onIrrelevantElement(e, api, seriesModel);\n        });\n\n        controller.enable(seriesModel.get('roam'));\n        controllerHost.zoomLimit = seriesModel.get('scaleLimit');\n        controllerHost.zoom = seriesModel.coordinateSystem.getZoom();\n\n        controller\n            .off('pan')\n            .off('zoom')\n            .on('pan', function (e) {\n                updateViewOnPan(controllerHost, e.dx, e.dy);\n                api.dispatchAction({\n                    seriesId: seriesModel.id,\n                    type: 'treeRoam',\n                    dx: e.dx,\n                    dy: e.dy\n                });\n            }, this)\n            .on('zoom', function (e) {\n                updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY);\n                api.dispatchAction({\n                    seriesId: seriesModel.id,\n                    type: 'treeRoam',\n                    zoom: e.scale,\n                    originX: e.originX,\n                    originY: e.originY\n                });\n                this._updateNodeAndLinkScale(seriesModel);\n            }, this);\n    },\n\n    _updateNodeAndLinkScale: function (seriesModel) {\n        var data = seriesModel.getData();\n\n        var nodeScale = this._getNodeGlobalScale(seriesModel);\n        var invScale = [nodeScale, nodeScale];\n\n        data.eachItemGraphicEl(function (el, idx) {\n            el.attr('scale', invScale);\n        });\n    },\n\n    _getNodeGlobalScale: function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys.type !== 'view') {\n            return 1;\n        }\n\n        var nodeScaleRatio = this._nodeScaleRatio;\n\n        var groupScale = coordSys.scale;\n        var groupZoom = (groupScale && groupScale[0]) || 1;\n        // Scale node when zoom changes\n        var roamZoom = coordSys.getZoom();\n        var nodeScale = (roamZoom - 1) * nodeScaleRatio + 1;\n\n        return nodeScale / groupZoom;\n    },\n\n    dispose: function () {\n        this._controller && this._controller.dispose();\n        this._controllerHost = {};\n    },\n\n    remove: function () {\n        this._mainGroup.removeAll();\n        this._data = null;\n    }\n\n});\n\nfunction symbolNeedsDraw$1(data, dataIndex) {\n    var layout = data.getItemLayout(dataIndex);\n\n    return layout\n        && !isNaN(layout.x) && !isNaN(layout.y)\n        && data.getItemVisual(dataIndex, 'symbol') !== 'none';\n}\n\nfunction getTreeNodeStyle(node, itemModel, seriesScope) {\n    seriesScope.itemModel = itemModel;\n    seriesScope.itemStyle = itemModel.getModel('itemStyle').getItemStyle();\n    seriesScope.hoverItemStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n    seriesScope.lineStyle = itemModel.getModel('lineStyle').getLineStyle();\n    seriesScope.labelModel = itemModel.getModel('label');\n    seriesScope.hoverLabelModel = itemModel.getModel('emphasis.label');\n\n    if (node.isExpand === false && node.children.length !== 0) {\n        seriesScope.symbolInnerColor = seriesScope.itemStyle.fill;\n    }\n    else {\n        seriesScope.symbolInnerColor = '#fff';\n    }\n\n    return seriesScope;\n}\n\nfunction updateNode(data, dataIndex, symbolEl, group, seriesModel, seriesScope) {\n    var isInit = !symbolEl;\n    var node = data.tree.getNodeByDataIndex(dataIndex);\n    var itemModel = node.getModel();\n    var seriesScope = getTreeNodeStyle(node, itemModel, seriesScope);\n    var virtualRoot = data.tree.root;\n\n    var source = node.parentNode === virtualRoot ? node : node.parentNode || node;\n    var sourceSymbolEl = data.getItemGraphicEl(source.dataIndex);\n    var sourceLayout = source.getLayout();\n    var sourceOldLayout = sourceSymbolEl\n        ? {\n            x: sourceSymbolEl.position[0],\n            y: sourceSymbolEl.position[1],\n            rawX: sourceSymbolEl.__radialOldRawX,\n            rawY: sourceSymbolEl.__radialOldRawY\n        }\n        : sourceLayout;\n    var targetLayout = node.getLayout();\n\n    if (isInit) {\n        symbolEl = new SymbolClz$1(data, dataIndex, seriesScope);\n        symbolEl.attr('position', [sourceOldLayout.x, sourceOldLayout.y]);\n    }\n    else {\n        symbolEl.updateData(data, dataIndex, seriesScope);\n    }\n\n    symbolEl.__radialOldRawX = symbolEl.__radialRawX;\n    symbolEl.__radialOldRawY = symbolEl.__radialRawY;\n    symbolEl.__radialRawX = targetLayout.rawX;\n    symbolEl.__radialRawY = targetLayout.rawY;\n\n    group.add(symbolEl);\n    data.setItemGraphicEl(dataIndex, symbolEl);\n    updateProps(symbolEl, {\n        position: [targetLayout.x, targetLayout.y]\n    }, seriesModel);\n\n    var symbolPath = symbolEl.getSymbolPath();\n\n    if (seriesScope.layout === 'radial') {\n        var realRoot = virtualRoot.children[0];\n        var rootLayout = realRoot.getLayout();\n        var length = realRoot.children.length;\n        var rad;\n        var isLeft;\n\n        if (targetLayout.x === rootLayout.x && node.isExpand === true) {\n            var center = {};\n            center.x = (realRoot.children[0].getLayout().x + realRoot.children[length - 1].getLayout().x) / 2;\n            center.y = (realRoot.children[0].getLayout().y + realRoot.children[length - 1].getLayout().y) / 2;\n            rad = Math.atan2(center.y - rootLayout.y, center.x - rootLayout.x);\n            if (rad < 0) {\n                rad = Math.PI * 2 + rad;\n            }\n            isLeft = center.x < rootLayout.x;\n            if (isLeft) {\n                rad = rad - Math.PI;\n            }\n        }\n        else {\n            rad = Math.atan2(targetLayout.y - rootLayout.y, targetLayout.x - rootLayout.x);\n            if (rad < 0) {\n                rad = Math.PI * 2 + rad;\n            }\n            if (node.children.length === 0 || (node.children.length !== 0 && node.isExpand === false)) {\n                isLeft = targetLayout.x < rootLayout.x;\n                if (isLeft) {\n                    rad = rad - Math.PI;\n                }\n            }\n            else {\n                isLeft = targetLayout.x > rootLayout.x;\n                if (!isLeft) {\n                    rad = rad - Math.PI;\n                }\n            }\n        }\n\n        var textPosition = isLeft ? 'left' : 'right';\n        symbolPath.setStyle({\n            textPosition: textPosition,\n            textRotation: -rad,\n            textOrigin: 'center',\n            verticalAlign: 'middle'\n        });\n    }\n\n    if (node.parentNode && node.parentNode !== virtualRoot) {\n        var edge = symbolEl.__edge;\n        if (!edge) {\n            edge = symbolEl.__edge = new BezierCurve({\n                shape: getEdgeShape(seriesScope, sourceOldLayout, sourceOldLayout),\n                style: defaults({opacity: 0, strokeNoScale: true}, seriesScope.lineStyle)\n            });\n        }\n\n        updateProps(edge, {\n            shape: getEdgeShape(seriesScope, sourceLayout, targetLayout),\n            style: {opacity: 1}\n        }, seriesModel);\n\n        group.add(edge);\n    }\n}\n\nfunction removeNode(data, dataIndex, symbolEl, group, seriesModel, seriesScope) {\n    var node = data.tree.getNodeByDataIndex(dataIndex);\n    var virtualRoot = data.tree.root;\n    var itemModel = node.getModel();\n    var seriesScope = getTreeNodeStyle(node, itemModel, seriesScope);\n\n    var source = node.parentNode === virtualRoot ? node : node.parentNode || node;\n    var sourceLayout;\n    while (sourceLayout = source.getLayout(), sourceLayout == null) {\n        source = source.parentNode === virtualRoot ? source : source.parentNode || source;\n    }\n\n    updateProps(symbolEl, {\n        position: [sourceLayout.x + 1, sourceLayout.y + 1]\n    }, seriesModel, function () {\n        group.remove(symbolEl);\n        data.setItemGraphicEl(dataIndex, null);\n    });\n\n    symbolEl.fadeOut(null, {keepLabel: true});\n\n    var edge = symbolEl.__edge;\n    if (edge) {\n        updateProps(edge, {\n            shape: getEdgeShape(seriesScope, sourceLayout, sourceLayout),\n            style: {\n                opacity: 0\n            }\n        }, seriesModel, function () {\n            group.remove(edge);\n        });\n    }\n}\n\nfunction getEdgeShape(seriesScope, sourceLayout, targetLayout) {\n    var cpx1;\n    var cpy1;\n    var cpx2;\n    var cpy2;\n    var orient = seriesScope.orient;\n    var x1;\n    var x2;\n    var y1;\n    var y2;\n\n    if (seriesScope.layout === 'radial') {\n        x1 = sourceLayout.rawX;\n        y1 = sourceLayout.rawY;\n        x2 = targetLayout.rawX;\n        y2 = targetLayout.rawY;\n\n        var radialCoor1 = radialCoordinate(x1, y1);\n        var radialCoor2 = radialCoordinate(x1, y1 + (y2 - y1) * seriesScope.curvature);\n        var radialCoor3 = radialCoordinate(x2, y2 + (y1 - y2) * seriesScope.curvature);\n        var radialCoor4 = radialCoordinate(x2, y2);\n\n        return {\n            x1: radialCoor1.x,\n            y1: radialCoor1.y,\n            x2: radialCoor4.x,\n            y2: radialCoor4.y,\n            cpx1: radialCoor2.x,\n            cpy1: radialCoor2.y,\n            cpx2: radialCoor3.x,\n            cpy2: radialCoor3.y\n        };\n    }\n    else {\n        x1 = sourceLayout.x;\n        y1 = sourceLayout.y;\n        x2 = targetLayout.x;\n        y2 = targetLayout.y;\n\n        if (orient === 'LR' || orient === 'RL') {\n            cpx1 = x1 + (x2 - x1) * seriesScope.curvature;\n            cpy1 = y1;\n            cpx2 = x2 + (x1 - x2) * seriesScope.curvature;\n            cpy2 = y2;\n        }\n        if (orient === 'TB' || orient === 'BT') {\n            cpx1 = x1;\n            cpy1 = y1 + (y2 - y1) * seriesScope.curvature;\n            cpx2 = x2;\n            cpy2 = y2 + (y1 - y2) * seriesScope.curvature;\n        }\n    }\n\n    return {\n        x1: x1,\n        y1: y1,\n        x2: x2,\n        y2: y2,\n        cpx1: cpx1,\n        cpy1: cpy1,\n        cpx2: cpx2,\n        cpy2: cpy2\n    };\n\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Register the actions of the tree\n * @author Deqing Li(annong035@gmail.com)\n */\n\nregisterAction({\n    type: 'treeExpandAndCollapse',\n    event: 'treeExpandAndCollapse',\n    update: 'update'\n}, function (payload, ecModel) {\n    ecModel.eachComponent({mainType: 'series', subType: 'tree', query: payload}, function (seriesModel) {\n        var dataIndex = payload.dataIndex;\n        var tree = seriesModel.getData().tree;\n        var node = tree.getNodeByDataIndex(dataIndex);\n        node.isExpand = !node.isExpand;\n\n    });\n});\n\nregisterAction({\n    type: 'treeRoam',\n    event: 'treeRoam',\n    // Here we set 'none' instead of 'update', because roam action\n    // just need to update the transform matrix without having to recalculate\n    // the layout. So don't need to go through the whole update process, such\n    // as 'dataPrcocess', 'coordSystemUpdate', 'layout' and so on.\n    update: 'none'\n}, function (payload, ecModel) {\n    ecModel.eachComponent({mainType: 'series', subType: 'tree', query: payload}, function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        var res = updateCenterAndZoom(coordSys, payload);\n\n        seriesModel.setCenter\n            && seriesModel.setCenter(res.center);\n\n        seriesModel.setZoom\n            && seriesModel.setZoom(res.zoom);\n    });\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * Traverse the tree from bottom to top and do something\n * @param  {module:echarts/data/Tree~TreeNode} root  The real root of the tree\n * @param  {Function} callback\n */\nfunction eachAfter(root, callback, separation) {\n    var nodes = [root];\n    var next = [];\n    var node;\n\n    while (node = nodes.pop()) { // jshint ignore:line\n        next.push(node);\n        if (node.isExpand) {\n            var children = node.children;\n            if (children.length) {\n                for (var i = 0; i < children.length; i++) {\n                    nodes.push(children[i]);\n                }\n            }\n        }\n    }\n\n    while (node = next.pop()) { // jshint ignore:line\n        callback(node, separation);\n    }\n}\n\n/**\n * Traverse the tree from top to bottom and do something\n * @param  {module:echarts/data/Tree~TreeNode} root  The real root of the tree\n * @param  {Function} callback\n */\nfunction eachBefore(root, callback) {\n    var nodes = [root];\n    var node;\n    while (node = nodes.pop()) { // jshint ignore:line\n        callback(node);\n        if (node.isExpand) {\n            var children = node.children;\n            if (children.length) {\n                for (var i = children.length - 1; i >= 0; i--) {\n                    nodes.push(children[i]);\n                }\n            }\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar treeLayout = function (ecModel, api) {\n    ecModel.eachSeriesByType('tree', function (seriesModel) {\n        commonLayout(seriesModel, api);\n    });\n};\n\nfunction commonLayout(seriesModel, api) {\n    var layoutInfo = getViewRect(seriesModel, api);\n    seriesModel.layoutInfo = layoutInfo;\n    var layout = seriesModel.get('layout');\n    var width = 0;\n    var height = 0;\n    var separation$$1 = null;\n\n    if (layout === 'radial') {\n        width = 2 * Math.PI;\n        height = Math.min(layoutInfo.height, layoutInfo.width) / 2;\n        separation$$1 = separation(function (node1, node2) {\n            return (node1.parentNode === node2.parentNode ? 1 : 2) / node1.depth;\n        });\n    }\n    else {\n        width = layoutInfo.width;\n        height = layoutInfo.height;\n        separation$$1 = separation();\n    }\n\n    var virtualRoot = seriesModel.getData().tree.root;\n    var realRoot = virtualRoot.children[0];\n\n    if (realRoot) {\n        init$2(virtualRoot);\n        eachAfter(realRoot, firstWalk, separation$$1);\n        virtualRoot.hierNode.modifier = -realRoot.hierNode.prelim;\n        eachBefore(realRoot, secondWalk);\n\n        var left = realRoot;\n        var right = realRoot;\n        var bottom = realRoot;\n        eachBefore(realRoot, function (node) {\n            var x = node.getLayout().x;\n            if (x < left.getLayout().x) {\n                left = node;\n            }\n            if (x > right.getLayout().x) {\n                right = node;\n            }\n            if (node.depth > bottom.depth) {\n                bottom = node;\n            }\n        });\n\n        var delta = left === right ? 1 : separation$$1(left, right) / 2;\n        var tx = delta - left.getLayout().x;\n        var kx = 0;\n        var ky = 0;\n        var coorX = 0;\n        var coorY = 0;\n        if (layout === 'radial') {\n            kx = width / (right.getLayout().x + delta + tx);\n            // here we use (node.depth - 1), bucause the real root's depth is 1\n            ky = height / ((bottom.depth - 1) || 1);\n            eachBefore(realRoot, function (node) {\n                coorX = (node.getLayout().x + tx) * kx;\n                coorY = (node.depth - 1) * ky;\n                var finalCoor = radialCoordinate(coorX, coorY);\n                node.setLayout({x: finalCoor.x, y: finalCoor.y, rawX: coorX, rawY: coorY}, true);\n            });\n        }\n        else {\n            var orient = seriesModel.getOrient();\n            if (orient === 'RL' || orient === 'LR') {\n                ky = height / (right.getLayout().x + delta + tx);\n                kx = width / ((bottom.depth - 1) || 1);\n                eachBefore(realRoot, function (node) {\n                    coorY = (node.getLayout().x + tx) * ky;\n                    coorX = orient === 'LR'\n                        ? (node.depth - 1) * kx\n                        : width - (node.depth - 1) * kx;\n                    node.setLayout({x: coorX, y: coorY}, true);\n                });\n            }\n            else if (orient === 'TB' || orient === 'BT') {\n                kx = width / (right.getLayout().x + delta + tx);\n                ky = height / ((bottom.depth - 1) || 1);\n                eachBefore(realRoot, function (node) {\n                    coorX = (node.getLayout().x + tx) * kx;\n                    coorY = orient === 'TB'\n                        ? (node.depth - 1) * ky\n                        : height - (node.depth - 1) * ky;\n                    node.setLayout({x: coorX, y: coorY}, true);\n                });\n            }\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(visualSymbol('tree', 'circle'));\nregisterLayout(treeLayout);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction retrieveTargetInfo(payload, validPayloadTypes, seriesModel) {\n    if (payload && indexOf(validPayloadTypes, payload.type) >= 0) {\n        var root = seriesModel.getData().tree.root;\n        var targetNode = payload.targetNode;\n\n        if (typeof targetNode === 'string') {\n            targetNode = root.getNodeById(targetNode);\n        }\n\n        if (targetNode && root.contains(targetNode)) {\n            return {node: targetNode};\n        }\n\n        var targetNodeId = payload.targetNodeId;\n        if (targetNodeId != null && (targetNode = root.getNodeById(targetNodeId))) {\n            return {node: targetNode};\n        }\n    }\n}\n\n// Not includes the given node at the last item.\nfunction getPathToRoot(node) {\n    var path = [];\n    while (node) {\n        node = node.parentNode;\n        node && path.push(node);\n    }\n    return path.reverse();\n}\n\nfunction aboveViewRoot(viewRoot, node) {\n    var viewPath = getPathToRoot(viewRoot);\n    return indexOf(viewPath, node) >= 0;\n}\n\n// From root to the input node (the input node will be included).\nfunction wrapTreePathInfo(node, seriesModel) {\n    var treePathInfo = [];\n\n    while (node) {\n        var nodeDataIndex = node.dataIndex;\n        treePathInfo.push({\n            name: node.name,\n            dataIndex: nodeDataIndex,\n            value: seriesModel.getRawValue(nodeDataIndex)\n        });\n        node = node.parentNode;\n    }\n\n    treePathInfo.reverse();\n\n    return treePathInfo;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.treemap',\n\n    layoutMode: 'box',\n\n    dependencies: ['grid', 'polar'],\n\n    /**\n     * @type {module:echarts/data/Tree~Node}\n     */\n    _viewRoot: null,\n\n    defaultOption: {\n        // Disable progressive rendering\n        progressive: 0,\n        hoverLayerThreshold: Infinity,\n        // center: ['50%', '50%'],          // not supported in ec3.\n        // size: ['80%', '80%'],            // deprecated, compatible with ec2.\n        left: 'center',\n        top: 'middle',\n        right: null,\n        bottom: null,\n        width: '80%',\n        height: '80%',\n        sort: true,                         // Can be null or false or true\n                                            // (order by desc default, asc not supported yet (strange effect))\n        clipWindow: 'origin',               // Size of clipped window when zooming. 'origin' or 'fullscreen'\n        squareRatio: 0.5 * (1 + Math.sqrt(5)), // golden ratio\n        leafDepth: null,                    // Nodes on depth from root are regarded as leaves.\n                                            // Count from zero (zero represents only view root).\n        drillDownIcon: '▶',                 // Use html character temporarily because it is complicated\n                                            // to align specialized icon. ▷▶❒❐▼✚\n\n        zoomToNodeRatio: 0.32 * 0.32,       // Be effective when using zoomToNode. Specify the proportion of the\n                                            // target node area in the view area.\n        roam: true,                         // true, false, 'scale' or 'zoom', 'move'.\n        nodeClick: 'zoomToNode',            // Leaf node click behaviour: 'zoomToNode', 'link', false.\n                                            // If leafDepth is set and clicking a node which has children but\n                                            // be on left depth, the behaviour would be changing root. Otherwise\n                                            // use behavious defined above.\n        animation: true,\n        animationDurationUpdate: 900,\n        animationEasing: 'quinticInOut',\n        breadcrumb: {\n            show: true,\n            height: 22,\n            left: 'center',\n            top: 'bottom',\n            // right\n            // bottom\n            emptyItemWidth: 25,             // Width of empty node.\n            itemStyle: {\n                color: 'rgba(0,0,0,0.7)', //'#5793f3',\n                borderColor: 'rgba(255,255,255,0.7)',\n                borderWidth: 1,\n                shadowColor: 'rgba(150,150,150,1)',\n                shadowBlur: 3,\n                shadowOffsetX: 0,\n                shadowOffsetY: 0,\n                textStyle: {\n                    color: '#fff'\n                }\n            },\n            emphasis: {\n                textStyle: {}\n            }\n        },\n        label: {\n            show: true,\n            // Do not use textDistance, for ellipsis rect just the same as treemap node rect.\n            distance: 0,\n            padding: 5,\n            position: 'inside', // Can be [5, '5%'] or position stirng like 'insideTopLeft', ...\n            // formatter: null,\n            color: '#fff',\n            ellipsis: true\n            // align\n            // verticalAlign\n        },\n        upperLabel: {                   // Label when node is parent.\n            show: false,\n            position: [0, '50%'],\n            height: 20,\n            // formatter: null,\n            color: '#fff',\n            ellipsis: true,\n            // align: null,\n            verticalAlign: 'middle'\n        },\n        itemStyle: {\n            color: null,            // Can be 'none' if not necessary.\n            colorAlpha: null,       // Can be 'none' if not necessary.\n            colorSaturation: null,  // Can be 'none' if not necessary.\n            borderWidth: 0,\n            gapWidth: 0,\n            borderColor: '#fff',\n            borderColorSaturation: null // If specified, borderColor will be ineffective, and the\n                                        // border color is evaluated by color of current node and\n                                        // borderColorSaturation.\n        },\n        emphasis: {\n            upperLabel: {\n                show: true,\n                position: [0, '50%'],\n                color: '#fff',\n                ellipsis: true,\n                verticalAlign: 'middle'\n            }\n        },\n\n        visualDimension: 0,                 // Can be 0, 1, 2, 3.\n        visualMin: null,\n        visualMax: null,\n\n        color: [],                  // + treemapSeries.color should not be modified. Please only modified\n                                    // level[n].color (if necessary).\n                                    // + Specify color list of each level. level[0].color would be global\n                                    // color list if not specified. (see method `setDefault`).\n                                    // + But set as a empty array to forbid fetch color from global palette\n                                    // when using nodeModel.get('color'), otherwise nodes on deep level\n                                    // will always has color palette set and are not able to inherit color\n                                    // from parent node.\n                                    // + TreemapSeries.color can not be set as 'none', otherwise effect\n                                    // legend color fetching (see seriesColor.js).\n        colorAlpha: null,           // Array. Specify color alpha range of each level, like [0.2, 0.8]\n        colorSaturation: null,      // Array. Specify color saturation of each level, like [0.2, 0.5]\n        colorMappingBy: 'index',    // 'value' or 'index' or 'id'.\n        visibleMin: 10,             // If area less than this threshold (unit: pixel^2), node will not\n                                    // be rendered. Only works when sort is 'asc' or 'desc'.\n        childrenVisibleMin: null,   // If area of a node less than this threshold (unit: pixel^2),\n                                    // grandchildren will not show.\n                                    // Why grandchildren? If not grandchildren but children,\n                                    // some siblings show children and some not,\n                                    // the appearance may be mess and not consistent,\n        levels: []                  // Each item: {\n                                    //     visibleMin, itemStyle, visualDimension, label\n                                    // }\n        // data: {\n        //      value: [],\n        //      children: [],\n        //      link: 'http://xxx.xxx.xxx',\n        //      target: 'blank' or 'self'\n        // }\n    },\n\n    /**\n     * @override\n     */\n    getInitialData: function (option, ecModel) {\n        // Create a virtual root.\n        var root = {name: option.name, children: option.data};\n\n        completeTreeValue(root);\n\n        var levels = option.levels || [];\n\n        levels = option.levels = setDefault(levels, ecModel);\n\n        var treeOption = {};\n\n        treeOption.levels = levels;\n\n        // Make sure always a new tree is created when setOption,\n        // in TreemapView, we check whether oldTree === newTree\n        // to choose mappings approach among old shapes and new shapes.\n        return Tree.createTree(root, this, treeOption).data;\n    },\n\n    optionUpdated: function () {\n        this.resetViewRoot();\n    },\n\n    /**\n     * @override\n     * @param {number} dataIndex\n     * @param {boolean} [mutipleSeries=false]\n     */\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var value = this.getRawValue(dataIndex);\n        var formattedValue = isArray(value)\n            ? addCommas(value[0]) : addCommas(value);\n        var name = data.getName(dataIndex);\n\n        return encodeHTML(name + ': ' + formattedValue);\n    },\n\n    /**\n     * Add tree path to tooltip param\n     *\n     * @override\n     * @param {number} dataIndex\n     * @return {Object}\n     */\n    getDataParams: function (dataIndex) {\n        var params = SeriesModel.prototype.getDataParams.apply(this, arguments);\n\n        var node = this.getData().tree.getNodeByDataIndex(dataIndex);\n        params.treePathInfo = wrapTreePathInfo(node, this);\n\n        return params;\n    },\n\n    /**\n     * @public\n     * @param {Object} layoutInfo {\n     *                                x: containerGroup x\n     *                                y: containerGroup y\n     *                                width: containerGroup width\n     *                                height: containerGroup height\n     *                            }\n     */\n    setLayoutInfo: function (layoutInfo) {\n        /**\n         * @readOnly\n         * @type {Object}\n         */\n        this.layoutInfo = this.layoutInfo || {};\n        extend(this.layoutInfo, layoutInfo);\n    },\n\n    /**\n     * @param  {string} id\n     * @return {number} index\n     */\n    mapIdToIndex: function (id) {\n        // A feature is implemented:\n        // index is monotone increasing with the sequence of\n        // input id at the first time.\n        // This feature can make sure that each data item and its\n        // mapped color have the same index between data list and\n        // color list at the beginning, which is useful for user\n        // to adjust data-color mapping.\n\n        /**\n         * @private\n         * @type {Object}\n         */\n        var idIndexMap = this._idIndexMap;\n\n        if (!idIndexMap) {\n            idIndexMap = this._idIndexMap = createHashMap();\n            /**\n             * @private\n             * @type {number}\n             */\n            this._idIndexMapCount = 0;\n        }\n\n        var index = idIndexMap.get(id);\n        if (index == null) {\n            idIndexMap.set(id, index = this._idIndexMapCount++);\n        }\n\n        return index;\n    },\n\n    getViewRoot: function () {\n        return this._viewRoot;\n    },\n\n    /**\n     * @param {module:echarts/data/Tree~Node} [viewRoot]\n     */\n    resetViewRoot: function (viewRoot) {\n        viewRoot\n            ? (this._viewRoot = viewRoot)\n            : (viewRoot = this._viewRoot);\n\n        var root = this.getRawData().tree.root;\n\n        if (!viewRoot\n            || (viewRoot !== root && !root.contains(viewRoot))\n        ) {\n            this._viewRoot = root;\n        }\n    }\n});\n\n/**\n * @param {Object} dataNode\n */\nfunction completeTreeValue(dataNode) {\n    // Postorder travel tree.\n    // If value of none-leaf node is not set,\n    // calculate it by suming up the value of all children.\n    var sum = 0;\n\n    each$1(dataNode.children, function (child) {\n\n        completeTreeValue(child);\n\n        var childValue = child.value;\n        isArray(childValue) && (childValue = childValue[0]);\n\n        sum += childValue;\n    });\n\n    var thisValue = dataNode.value;\n    if (isArray(thisValue)) {\n        thisValue = thisValue[0];\n    }\n\n    if (thisValue == null || isNaN(thisValue)) {\n        thisValue = sum;\n    }\n    // Value should not less than 0.\n    if (thisValue < 0) {\n        thisValue = 0;\n    }\n\n    isArray(dataNode.value)\n        ? (dataNode.value[0] = thisValue)\n        : (dataNode.value = thisValue);\n}\n\n/**\n * set default to level configuration\n */\nfunction setDefault(levels, ecModel) {\n    var globalColorList = ecModel.get('color');\n\n    if (!globalColorList) {\n        return;\n    }\n\n    levels = levels || [];\n    var hasColorDefine;\n    each$1(levels, function (levelDefine) {\n        var model = new Model(levelDefine);\n        var modelColor = model.get('color');\n\n        if (model.get('itemStyle.color')\n            || (modelColor && modelColor !== 'none')\n        ) {\n            hasColorDefine = true;\n        }\n    });\n\n    if (!hasColorDefine) {\n        var level0 = levels[0] || (levels[0] = {});\n        level0.color = globalColorList.slice();\n    }\n\n    return levels;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TEXT_PADDING = 8;\nvar ITEM_GAP = 8;\nvar ARRAY_LENGTH = 5;\n\nfunction Breadcrumb(containerGroup) {\n    /**\n     * @private\n     * @type {module:zrender/container/Group}\n     */\n    this.group = new Group();\n\n    containerGroup.add(this.group);\n}\n\nBreadcrumb.prototype = {\n\n    constructor: Breadcrumb,\n\n    render: function (seriesModel, api, targetNode, onSelect) {\n        var model = seriesModel.getModel('breadcrumb');\n        var thisGroup = this.group;\n\n        thisGroup.removeAll();\n\n        if (!model.get('show') || !targetNode) {\n            return;\n        }\n\n        var normalStyleModel = model.getModel('itemStyle');\n        // var emphasisStyleModel = model.getModel('emphasis.itemStyle');\n        var textStyleModel = normalStyleModel.getModel('textStyle');\n\n        var layoutParam = {\n            pos: {\n                left: model.get('left'),\n                right: model.get('right'),\n                top: model.get('top'),\n                bottom: model.get('bottom')\n            },\n            box: {\n                width: api.getWidth(),\n                height: api.getHeight()\n            },\n            emptyItemWidth: model.get('emptyItemWidth'),\n            totalWidth: 0,\n            renderList: []\n        };\n\n        this._prepare(targetNode, layoutParam, textStyleModel);\n        this._renderContent(seriesModel, layoutParam, normalStyleModel, textStyleModel, onSelect);\n\n        positionElement(thisGroup, layoutParam.pos, layoutParam.box);\n    },\n\n    /**\n     * Prepare render list and total width\n     * @private\n     */\n    _prepare: function (targetNode, layoutParam, textStyleModel) {\n        for (var node = targetNode; node; node = node.parentNode) {\n            var text = node.getModel().get('name');\n            var textRect = textStyleModel.getTextRect(text);\n            var itemWidth = Math.max(\n                textRect.width + TEXT_PADDING * 2,\n                layoutParam.emptyItemWidth\n            );\n            layoutParam.totalWidth += itemWidth + ITEM_GAP;\n            layoutParam.renderList.push({node: node, text: text, width: itemWidth});\n        }\n    },\n\n    /**\n     * @private\n     */\n    _renderContent: function (\n        seriesModel, layoutParam, normalStyleModel, textStyleModel, onSelect\n    ) {\n        // Start rendering.\n        var lastX = 0;\n        var emptyItemWidth = layoutParam.emptyItemWidth;\n        var height = seriesModel.get('breadcrumb.height');\n        var availableSize = getAvailableSize(layoutParam.pos, layoutParam.box);\n        var totalWidth = layoutParam.totalWidth;\n        var renderList = layoutParam.renderList;\n\n        for (var i = renderList.length - 1; i >= 0; i--) {\n            var item = renderList[i];\n            var itemNode = item.node;\n            var itemWidth = item.width;\n            var text = item.text;\n\n            // Hdie text and shorten width if necessary.\n            if (totalWidth > availableSize.width) {\n                totalWidth -= itemWidth - emptyItemWidth;\n                itemWidth = emptyItemWidth;\n                text = null;\n            }\n\n            var el = new Polygon({\n                shape: {\n                    points: makeItemPoints(\n                        lastX, 0, itemWidth, height,\n                        i === renderList.length - 1, i === 0\n                    )\n                },\n                style: defaults(\n                    normalStyleModel.getItemStyle(),\n                    {\n                        lineJoin: 'bevel',\n                        text: text,\n                        textFill: textStyleModel.getTextColor(),\n                        textFont: textStyleModel.getFont()\n                    }\n                ),\n                z: 10,\n                onclick: curry(onSelect, itemNode)\n            });\n            this.group.add(el);\n\n            packEventData(el, seriesModel, itemNode);\n\n            lastX += itemWidth + ITEM_GAP;\n        }\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this.group.removeAll();\n    }\n};\n\nfunction makeItemPoints(x, y, itemWidth, itemHeight, head, tail) {\n    var points = [\n        [head ? x : x - ARRAY_LENGTH, y],\n        [x + itemWidth, y],\n        [x + itemWidth, y + itemHeight],\n        [head ? x : x - ARRAY_LENGTH, y + itemHeight]\n    ];\n    !tail && points.splice(2, 0, [x + itemWidth + ARRAY_LENGTH, y + itemHeight / 2]);\n    !head && points.push([x, y + itemHeight / 2]);\n    return points;\n}\n\n// Package custom mouse event.\nfunction packEventData(el, seriesModel, itemNode) {\n    el.eventData = {\n        componentType: 'series',\n        componentSubType: 'treemap',\n        componentIndex: seriesModel.componentIndex,\n        seriesIndex: seriesModel.componentIndex,\n        seriesName: seriesModel.name,\n        seriesType: 'treemap',\n        selfType: 'breadcrumb', // Distinguish with click event on treemap node.\n        nodeData: {\n            dataIndex: itemNode && itemNode.dataIndex,\n            name: itemNode && itemNode.name\n        },\n        treePathInfo: itemNode && wrapTreePathInfo(itemNode, seriesModel)\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {number} [time=500] Time in ms\n * @param {string} [easing='linear']\n * @param {number} [delay=0]\n * @param {Function} [callback]\n *\n * @example\n *  // Animate position\n *  animation\n *      .createWrap()\n *      .add(el1, {position: [10, 10]})\n *      .add(el2, {shape: {width: 500}, style: {fill: 'red'}}, 400)\n *      .done(function () { // done })\n *      .start('cubicOut');\n */\nfunction createWrap() {\n\n    var storage = [];\n    var elExistsMap = {};\n    var doneCallback;\n\n    return {\n\n        /**\n         * Caution: a el can only be added once, otherwise 'done'\n         * might not be called. This method checks this (by el.id),\n         * suppresses adding and returns false when existing el found.\n         *\n         * @param {modele:zrender/Element} el\n         * @param {Object} target\n         * @param {number} [time=500]\n         * @param {number} [delay=0]\n         * @param {string} [easing='linear']\n         * @return {boolean} Whether adding succeeded.\n         *\n         * @example\n         *     add(el, target, time, delay, easing);\n         *     add(el, target, time, easing);\n         *     add(el, target, time);\n         *     add(el, target);\n         */\n        add: function (el, target, time, delay, easing) {\n            if (isString(delay)) {\n                easing = delay;\n                delay = 0;\n            }\n\n            if (elExistsMap[el.id]) {\n                return false;\n            }\n            elExistsMap[el.id] = 1;\n\n            storage.push(\n                {el: el, target: target, time: time, delay: delay, easing: easing}\n            );\n\n            return true;\n        },\n\n        /**\n         * Only execute when animation finished. Will not execute when any\n         * of 'stop' or 'stopAnimation' called.\n         *\n         * @param {Function} callback\n         */\n        done: function (callback) {\n            doneCallback = callback;\n            return this;\n        },\n\n        /**\n         * Will stop exist animation firstly.\n         */\n        start: function () {\n            var count = storage.length;\n\n            for (var i = 0, len = storage.length; i < len; i++) {\n                var item = storage[i];\n                item.el.animateTo(item.target, item.time, item.delay, item.easing, done);\n            }\n\n            return this;\n\n            function done() {\n                count--;\n                if (!count) {\n                    storage.length = 0;\n                    elExistsMap = {};\n                    doneCallback && doneCallback();\n                }\n            }\n        }\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$1 = bind;\nvar Group$2 = Group;\nvar Rect$1 = Rect;\nvar each$8 = each$1;\n\nvar DRAG_THRESHOLD = 3;\nvar PATH_LABEL_NOAMAL = ['label'];\nvar PATH_LABEL_EMPHASIS = ['emphasis', 'label'];\nvar PATH_UPPERLABEL_NORMAL = ['upperLabel'];\nvar PATH_UPPERLABEL_EMPHASIS = ['emphasis', 'upperLabel'];\nvar Z_BASE = 10; // Should bigger than every z.\nvar Z_BG = 1;\nvar Z_CONTENT = 2;\n\nvar getItemStyleEmphasis = makeStyleMapper([\n    ['fill', 'color'],\n    // `borderColor` and `borderWidth` has been occupied,\n    // so use `stroke` to indicate the stroke of the rect.\n    ['stroke', 'strokeColor'],\n    ['lineWidth', 'strokeWidth'],\n    ['shadowBlur'],\n    ['shadowOffsetX'],\n    ['shadowOffsetY'],\n    ['shadowColor']\n]);\nvar getItemStyleNormal = function (model) {\n    // Normal style props should include emphasis style props.\n    var itemStyle = getItemStyleEmphasis(model);\n    // Clear styles set by emphasis.\n    itemStyle.stroke = itemStyle.fill = itemStyle.lineWidth = null;\n    return itemStyle;\n};\n\nextendChartView({\n\n    type: 'treemap',\n\n    /**\n     * @override\n     */\n    init: function (o, api) {\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this._containerGroup;\n\n        /**\n         * @private\n         * @type {Object.<string, Array.<module:zrender/container/Group>>}\n         */\n        this._storage = createStorage();\n\n        /**\n         * @private\n         * @type {module:echarts/data/Tree}\n         */\n        this._oldTree;\n\n        /**\n         * @private\n         * @type {module:echarts/chart/treemap/Breadcrumb}\n         */\n        this._breadcrumb;\n\n        /**\n         * @private\n         * @type {module:echarts/component/helper/RoamController}\n         */\n        this._controller;\n\n        /**\n         * 'ready', 'animating'\n         * @private\n         */\n        this._state = 'ready';\n    },\n\n    /**\n     * @override\n     */\n    render: function (seriesModel, ecModel, api, payload) {\n\n        var models = ecModel.findComponents({\n            mainType: 'series', subType: 'treemap', query: payload\n        });\n        if (indexOf(models, seriesModel) < 0) {\n            return;\n        }\n\n        this.seriesModel = seriesModel;\n        this.api = api;\n        this.ecModel = ecModel;\n\n        var types = ['treemapZoomToNode', 'treemapRootToNode'];\n        var targetInfo = retrieveTargetInfo(payload, types, seriesModel);\n        var payloadType = payload && payload.type;\n        var layoutInfo = seriesModel.layoutInfo;\n        var isInit = !this._oldTree;\n        var thisStorage = this._storage;\n\n        // Mark new root when action is treemapRootToNode.\n        var reRoot = (payloadType === 'treemapRootToNode' && targetInfo && thisStorage)\n            ? {\n                rootNodeGroup: thisStorage.nodeGroup[targetInfo.node.getRawIndex()],\n                direction: payload.direction\n            }\n            : null;\n\n        var containerGroup = this._giveContainerGroup(layoutInfo);\n\n        var renderResult = this._doRender(containerGroup, seriesModel, reRoot);\n        (\n            !isInit && (\n                !payloadType\n                || payloadType === 'treemapZoomToNode'\n                || payloadType === 'treemapRootToNode'\n            )\n        )\n            ? this._doAnimation(containerGroup, renderResult, seriesModel, reRoot)\n            : renderResult.renderFinally();\n\n        this._resetController(api);\n\n        this._renderBreadcrumb(seriesModel, api, targetInfo);\n    },\n\n    /**\n     * @private\n     */\n    _giveContainerGroup: function (layoutInfo) {\n        var containerGroup = this._containerGroup;\n        if (!containerGroup) {\n            // FIXME\n            // 加一层containerGroup是为了clip，但是现在clip功能并没有实现。\n            containerGroup = this._containerGroup = new Group$2();\n            this._initEvents(containerGroup);\n            this.group.add(containerGroup);\n        }\n        containerGroup.attr('position', [layoutInfo.x, layoutInfo.y]);\n\n        return containerGroup;\n    },\n\n    /**\n     * @private\n     */\n    _doRender: function (containerGroup, seriesModel, reRoot) {\n        var thisTree = seriesModel.getData().tree;\n        var oldTree = this._oldTree;\n\n        // Clear last shape records.\n        var lastsForAnimation = createStorage();\n        var thisStorage = createStorage();\n        var oldStorage = this._storage;\n        var willInvisibleEls = [];\n        var doRenderNode = curry(\n            renderNode, seriesModel,\n            thisStorage, oldStorage, reRoot,\n            lastsForAnimation, willInvisibleEls\n        );\n\n        // Notice: when thisTree and oldTree are the same tree (see list.cloneShallow),\n        // the oldTree is actually losted, so we can not find all of the old graphic\n        // elements from tree. So we use this stragegy: make element storage, move\n        // from old storage to new storage, clear old storage.\n\n        dualTravel(\n            thisTree.root ? [thisTree.root] : [],\n            (oldTree && oldTree.root) ? [oldTree.root] : [],\n            containerGroup,\n            thisTree === oldTree || !oldTree,\n            0\n        );\n\n        // Process all removing.\n        var willDeleteEls = clearStorage(oldStorage);\n\n        this._oldTree = thisTree;\n        this._storage = thisStorage;\n\n        return {\n            lastsForAnimation: lastsForAnimation,\n            willDeleteEls: willDeleteEls,\n            renderFinally: renderFinally\n        };\n\n        function dualTravel(thisViewChildren, oldViewChildren, parentGroup, sameTree, depth) {\n            // When 'render' is triggered by action,\n            // 'this' and 'old' may be the same tree,\n            // we use rawIndex in that case.\n            if (sameTree) {\n                oldViewChildren = thisViewChildren;\n                each$8(thisViewChildren, function (child, index) {\n                    !child.isRemoved() && processNode(index, index);\n                });\n            }\n            // Diff hierarchically (diff only in each subtree, but not whole).\n            // because, consistency of view is important.\n            else {\n                (new DataDiffer(oldViewChildren, thisViewChildren, getKey, getKey))\n                    .add(processNode)\n                    .update(processNode)\n                    .remove(curry(processNode, null))\n                    .execute();\n            }\n\n            function getKey(node) {\n                // Identify by name or raw index.\n                return node.getId();\n            }\n\n            function processNode(newIndex, oldIndex) {\n                var thisNode = newIndex != null ? thisViewChildren[newIndex] : null;\n                var oldNode = oldIndex != null ? oldViewChildren[oldIndex] : null;\n\n                var group = doRenderNode(thisNode, oldNode, parentGroup, depth);\n\n                group && dualTravel(\n                    thisNode && thisNode.viewChildren || [],\n                    oldNode && oldNode.viewChildren || [],\n                    group,\n                    sameTree,\n                    depth + 1\n                );\n            }\n        }\n\n        function clearStorage(storage) {\n            var willDeleteEls = createStorage();\n            storage && each$8(storage, function (store, storageName) {\n                var delEls = willDeleteEls[storageName];\n                each$8(store, function (el) {\n                    el && (delEls.push(el), el.__tmWillDelete = 1);\n                });\n            });\n            return willDeleteEls;\n        }\n\n        function renderFinally() {\n            each$8(willDeleteEls, function (els) {\n                each$8(els, function (el) {\n                    el.parent && el.parent.remove(el);\n                });\n            });\n            each$8(willInvisibleEls, function (el) {\n                el.invisible = true;\n                // Setting invisible is for optimizing, so no need to set dirty,\n                // just mark as invisible.\n                el.dirty();\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _doAnimation: function (containerGroup, renderResult, seriesModel, reRoot) {\n        if (!seriesModel.get('animation')) {\n            return;\n        }\n\n        var duration = seriesModel.get('animationDurationUpdate');\n        var easing = seriesModel.get('animationEasing');\n        var animationWrap = createWrap();\n\n        // Make delete animations.\n        each$8(renderResult.willDeleteEls, function (store, storageName) {\n            each$8(store, function (el, rawIndex) {\n                if (el.invisible) {\n                    return;\n                }\n\n                var parent = el.parent; // Always has parent, and parent is nodeGroup.\n                var target;\n\n                if (reRoot && reRoot.direction === 'drillDown') {\n                    target = parent === reRoot.rootNodeGroup\n                        // This is the content element of view root.\n                        // Only `content` will enter this branch, because\n                        // `background` and `nodeGroup` will not be deleted.\n                        ? {\n                            shape: {\n                                x: 0,\n                                y: 0,\n                                width: parent.__tmNodeWidth,\n                                height: parent.__tmNodeHeight\n                            },\n                            style: {\n                                opacity: 0\n                            }\n                        }\n                        // Others.\n                        : {style: {opacity: 0}};\n                }\n                else {\n                    var targetX = 0;\n                    var targetY = 0;\n\n                    if (!parent.__tmWillDelete) {\n                        // Let node animate to right-bottom corner, cooperating with fadeout,\n                        // which is appropriate for user understanding.\n                        // Divided by 2 for reRoot rolling up effect.\n                        targetX = parent.__tmNodeWidth / 2;\n                        targetY = parent.__tmNodeHeight / 2;\n                    }\n\n                    target = storageName === 'nodeGroup'\n                        ? {position: [targetX, targetY], style: {opacity: 0}}\n                        : {\n                            shape: {x: targetX, y: targetY, width: 0, height: 0},\n                            style: {opacity: 0}\n                        };\n                }\n\n                target && animationWrap.add(el, target, duration, easing);\n            });\n        });\n\n        // Make other animations\n        each$8(this._storage, function (store, storageName) {\n            each$8(store, function (el, rawIndex) {\n                var last = renderResult.lastsForAnimation[storageName][rawIndex];\n                var target = {};\n\n                if (!last) {\n                    return;\n                }\n\n                if (storageName === 'nodeGroup') {\n                    if (last.old) {\n                        target.position = el.position.slice();\n                        el.attr('position', last.old);\n                    }\n                }\n                else {\n                    if (last.old) {\n                        target.shape = extend({}, el.shape);\n                        el.setShape(last.old);\n                    }\n\n                    if (last.fadein) {\n                        el.setStyle('opacity', 0);\n                        target.style = {opacity: 1};\n                    }\n                    // When animation is stopped for succedent animation starting,\n                    // el.style.opacity might not be 1\n                    else if (el.style.opacity !== 1) {\n                        target.style = {opacity: 1};\n                    }\n                }\n\n                animationWrap.add(el, target, duration, easing);\n            });\n        }, this);\n\n        this._state = 'animating';\n\n        animationWrap\n            .done(bind$1(function () {\n                this._state = 'ready';\n                renderResult.renderFinally();\n            }, this))\n            .start();\n    },\n\n    /**\n     * @private\n     */\n    _resetController: function (api) {\n        var controller = this._controller;\n\n        // Init controller.\n        if (!controller) {\n            controller = this._controller = new RoamController(api.getZr());\n            controller.enable(this.seriesModel.get('roam'));\n            controller.on('pan', bind$1(this._onPan, this));\n            controller.on('zoom', bind$1(this._onZoom, this));\n        }\n\n        var rect = new BoundingRect(0, 0, api.getWidth(), api.getHeight());\n        controller.setPointerChecker(function (e, x, y) {\n            return rect.contain(x, y);\n        });\n    },\n\n    /**\n     * @private\n     */\n    _clearController: function () {\n        var controller = this._controller;\n        if (controller) {\n            controller.dispose();\n            controller = null;\n        }\n    },\n\n    /**\n     * @private\n     */\n    _onPan: function (e) {\n        if (this._state !== 'animating'\n            && (Math.abs(e.dx) > DRAG_THRESHOLD || Math.abs(e.dy) > DRAG_THRESHOLD)\n        ) {\n            // These param must not be cached.\n            var root = this.seriesModel.getData().tree.root;\n\n            if (!root) {\n                return;\n            }\n\n            var rootLayout = root.getLayout();\n\n            if (!rootLayout) {\n                return;\n            }\n\n            this.api.dispatchAction({\n                type: 'treemapMove',\n                from: this.uid,\n                seriesId: this.seriesModel.id,\n                rootRect: {\n                    x: rootLayout.x + e.dx, y: rootLayout.y + e.dy,\n                    width: rootLayout.width, height: rootLayout.height\n                }\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _onZoom: function (e) {\n        var mouseX = e.originX;\n        var mouseY = e.originY;\n\n        if (this._state !== 'animating') {\n            // These param must not be cached.\n            var root = this.seriesModel.getData().tree.root;\n\n            if (!root) {\n                return;\n            }\n\n            var rootLayout = root.getLayout();\n\n            if (!rootLayout) {\n                return;\n            }\n\n            var rect = new BoundingRect(\n                rootLayout.x, rootLayout.y, rootLayout.width, rootLayout.height\n            );\n            var layoutInfo = this.seriesModel.layoutInfo;\n\n            // Transform mouse coord from global to containerGroup.\n            mouseX -= layoutInfo.x;\n            mouseY -= layoutInfo.y;\n\n            // Scale root bounding rect.\n            var m = create$1();\n            translate(m, m, [-mouseX, -mouseY]);\n            scale$1(m, m, [e.scale, e.scale]);\n            translate(m, m, [mouseX, mouseY]);\n\n            rect.applyTransform(m);\n\n            this.api.dispatchAction({\n                type: 'treemapRender',\n                from: this.uid,\n                seriesId: this.seriesModel.id,\n                rootRect: {\n                    x: rect.x, y: rect.y,\n                    width: rect.width, height: rect.height\n                }\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _initEvents: function (containerGroup) {\n        containerGroup.on('click', function (e) {\n            if (this._state !== 'ready') {\n                return;\n            }\n\n            var nodeClick = this.seriesModel.get('nodeClick', true);\n\n            if (!nodeClick) {\n                return;\n            }\n\n            var targetInfo = this.findTarget(e.offsetX, e.offsetY);\n\n            if (!targetInfo) {\n                return;\n            }\n\n            var node = targetInfo.node;\n            if (node.getLayout().isLeafRoot) {\n                this._rootToNode(targetInfo);\n            }\n            else {\n                if (nodeClick === 'zoomToNode') {\n                    this._zoomToNode(targetInfo);\n                }\n                else if (nodeClick === 'link') {\n                    var itemModel = node.hostTree.data.getItemModel(node.dataIndex);\n                    var link = itemModel.get('link', true);\n                    var linkTarget = itemModel.get('target', true) || 'blank';\n                    link && window.open(link, linkTarget);\n                }\n            }\n\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _renderBreadcrumb: function (seriesModel, api, targetInfo) {\n        if (!targetInfo) {\n            targetInfo = seriesModel.get('leafDepth', true) != null\n                ? {node: seriesModel.getViewRoot()}\n                // FIXME\n                // better way?\n                // Find breadcrumb tail on center of containerGroup.\n                : this.findTarget(api.getWidth() / 2, api.getHeight() / 2);\n\n            if (!targetInfo) {\n                targetInfo = {node: seriesModel.getData().tree.root};\n            }\n        }\n\n        (this._breadcrumb || (this._breadcrumb = new Breadcrumb(this.group)))\n            .render(seriesModel, api, targetInfo.node, bind$1(onSelect, this));\n\n        function onSelect(node) {\n            if (this._state !== 'animating') {\n                aboveViewRoot(seriesModel.getViewRoot(), node)\n                    ? this._rootToNode({node: node})\n                    : this._zoomToNode({node: node});\n            }\n        }\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this._clearController();\n        this._containerGroup && this._containerGroup.removeAll();\n        this._storage = createStorage();\n        this._state = 'ready';\n        this._breadcrumb && this._breadcrumb.remove();\n    },\n\n    dispose: function () {\n        this._clearController();\n    },\n\n    /**\n     * @private\n     */\n    _zoomToNode: function (targetInfo) {\n        this.api.dispatchAction({\n            type: 'treemapZoomToNode',\n            from: this.uid,\n            seriesId: this.seriesModel.id,\n            targetNode: targetInfo.node\n        });\n    },\n\n    /**\n     * @private\n     */\n    _rootToNode: function (targetInfo) {\n        this.api.dispatchAction({\n            type: 'treemapRootToNode',\n            from: this.uid,\n            seriesId: this.seriesModel.id,\n            targetNode: targetInfo.node\n        });\n    },\n\n    /**\n     * @public\n     * @param {number} x Global coord x.\n     * @param {number} y Global coord y.\n     * @return {Object} info If not found, return undefined;\n     * @return {number} info.node Target node.\n     * @return {number} info.offsetX x refer to target node.\n     * @return {number} info.offsetY y refer to target node.\n     */\n    findTarget: function (x, y) {\n        var targetInfo;\n        var viewRoot = this.seriesModel.getViewRoot();\n\n        viewRoot.eachNode({attr: 'viewChildren', order: 'preorder'}, function (node) {\n            var bgEl = this._storage.background[node.getRawIndex()];\n            // If invisible, there might be no element.\n            if (bgEl) {\n                var point = bgEl.transformCoordToLocal(x, y);\n                var shape = bgEl.shape;\n\n                // For performance consideration, dont use 'getBoundingRect'.\n                if (shape.x <= point[0]\n                    && point[0] <= shape.x + shape.width\n                    && shape.y <= point[1]\n                    && point[1] <= shape.y + shape.height\n                ) {\n                    targetInfo = {node: node, offsetX: point[0], offsetY: point[1]};\n                }\n                else {\n                    return false; // Suppress visit subtree.\n                }\n            }\n        }, this);\n\n        return targetInfo;\n    }\n\n});\n\n/**\n * @inner\n */\nfunction createStorage() {\n    return {nodeGroup: [], background: [], content: []};\n}\n\n/**\n * @inner\n * @return Return undefined means do not travel further.\n */\nfunction renderNode(\n    seriesModel, thisStorage, oldStorage, reRoot,\n    lastsForAnimation, willInvisibleEls,\n    thisNode, oldNode, parentGroup, depth\n) {\n    // Whether under viewRoot.\n    if (!thisNode) {\n        // Deleting nodes will be performed finally. This method just find\n        // element from old storage, or create new element, set them to new\n        // storage, and set styles.\n        return;\n    }\n\n    // -------------------------------------------------------------------\n    // Start of closure variables available in \"Procedures in renderNode\".\n\n    var thisLayout = thisNode.getLayout();\n\n    if (!thisLayout || !thisLayout.isInView) {\n        return;\n    }\n\n    var thisWidth = thisLayout.width;\n    var thisHeight = thisLayout.height;\n    var borderWidth = thisLayout.borderWidth;\n    var thisInvisible = thisLayout.invisible;\n\n    var thisRawIndex = thisNode.getRawIndex();\n    var oldRawIndex = oldNode && oldNode.getRawIndex();\n\n    var thisViewChildren = thisNode.viewChildren;\n    var upperHeight = thisLayout.upperHeight;\n    var isParent = thisViewChildren && thisViewChildren.length;\n    var itemStyleNormalModel = thisNode.getModel('itemStyle');\n    var itemStyleEmphasisModel = thisNode.getModel('emphasis.itemStyle');\n\n    // End of closure ariables available in \"Procedures in renderNode\".\n    // -----------------------------------------------------------------\n\n    // Node group\n    var group = giveGraphic('nodeGroup', Group$2);\n\n    if (!group) {\n        return;\n    }\n\n    parentGroup.add(group);\n    // x,y are not set when el is above view root.\n    group.attr('position', [thisLayout.x || 0, thisLayout.y || 0]);\n    group.__tmNodeWidth = thisWidth;\n    group.__tmNodeHeight = thisHeight;\n\n    if (thisLayout.isAboveViewRoot) {\n        return group;\n    }\n\n    // Background\n    var bg = giveGraphic('background', Rect$1, depth, Z_BG);\n    bg && renderBackground(group, bg, isParent && thisLayout.upperHeight);\n\n    // No children, render content.\n    if (!isParent) {\n        var content = giveGraphic('content', Rect$1, depth, Z_CONTENT);\n        content && renderContent(group, content);\n    }\n\n    return group;\n\n    // ----------------------------\n    // | Procedures in renderNode |\n    // ----------------------------\n\n    function renderBackground(group, bg, useUpperLabel) {\n        // For tooltip.\n        bg.dataIndex = thisNode.dataIndex;\n        bg.seriesIndex = seriesModel.seriesIndex;\n\n        bg.setShape({x: 0, y: 0, width: thisWidth, height: thisHeight});\n        var visualBorderColor = thisNode.getVisual('borderColor', true);\n        var emphasisBorderColor = itemStyleEmphasisModel.get('borderColor');\n\n        updateStyle(bg, function () {\n            var normalStyle = getItemStyleNormal(itemStyleNormalModel);\n            normalStyle.fill = visualBorderColor;\n            var emphasisStyle = getItemStyleEmphasis(itemStyleEmphasisModel);\n            emphasisStyle.fill = emphasisBorderColor;\n\n            if (useUpperLabel) {\n                var upperLabelWidth = thisWidth - 2 * borderWidth;\n\n                prepareText(\n                    normalStyle, emphasisStyle, visualBorderColor, upperLabelWidth, upperHeight,\n                    {x: borderWidth, y: 0, width: upperLabelWidth, height: upperHeight}\n                );\n            }\n            // For old bg.\n            else {\n                normalStyle.text = emphasisStyle.text = null;\n            }\n\n            bg.setStyle(normalStyle);\n            setHoverStyle(bg, emphasisStyle);\n        });\n\n        group.add(bg);\n    }\n\n    function renderContent(group, content) {\n        // For tooltip.\n        content.dataIndex = thisNode.dataIndex;\n        content.seriesIndex = seriesModel.seriesIndex;\n\n        var contentWidth = Math.max(thisWidth - 2 * borderWidth, 0);\n        var contentHeight = Math.max(thisHeight - 2 * borderWidth, 0);\n\n        content.culling = true;\n        content.setShape({\n            x: borderWidth,\n            y: borderWidth,\n            width: contentWidth,\n            height: contentHeight\n        });\n\n        var visualColor = thisNode.getVisual('color', true);\n        updateStyle(content, function () {\n            var normalStyle = getItemStyleNormal(itemStyleNormalModel);\n            normalStyle.fill = visualColor;\n            var emphasisStyle = getItemStyleEmphasis(itemStyleEmphasisModel);\n\n            prepareText(normalStyle, emphasisStyle, visualColor, contentWidth, contentHeight);\n\n            content.setStyle(normalStyle);\n            setHoverStyle(content, emphasisStyle);\n        });\n\n        group.add(content);\n    }\n\n    function updateStyle(element, cb) {\n        if (!thisInvisible) {\n            // If invisible, do not set visual, otherwise the element will\n            // change immediately before animation. We think it is OK to\n            // remain its origin color when moving out of the view window.\n            cb();\n\n            if (!element.__tmWillVisible) {\n                element.invisible = false;\n            }\n        }\n        else {\n            // Delay invisible setting utill animation finished,\n            // avoid element vanish suddenly before animation.\n            !element.invisible && willInvisibleEls.push(element);\n        }\n    }\n\n    function prepareText(normalStyle, emphasisStyle, visualColor, width, height, upperLabelRect) {\n        var nodeModel = thisNode.getModel();\n        var text = retrieve(\n            seriesModel.getFormattedLabel(\n                thisNode.dataIndex, 'normal', null, null, upperLabelRect ? 'upperLabel' : 'label'\n            ),\n            nodeModel.get('name')\n        );\n        if (!upperLabelRect && thisLayout.isLeafRoot) {\n            var iconChar = seriesModel.get('drillDownIcon', true);\n            text = iconChar ? iconChar + ' ' + text : text;\n        }\n\n        var normalLabelModel = nodeModel.getModel(\n            upperLabelRect ? PATH_UPPERLABEL_NORMAL : PATH_LABEL_NOAMAL\n        );\n        var emphasisLabelModel = nodeModel.getModel(\n            upperLabelRect ? PATH_UPPERLABEL_EMPHASIS : PATH_LABEL_EMPHASIS\n        );\n\n        var isShow = normalLabelModel.getShallow('show');\n\n        setLabelStyle(\n            normalStyle, emphasisStyle, normalLabelModel, emphasisLabelModel,\n            {\n                defaultText: isShow ? text : null,\n                autoColor: visualColor,\n                isRectText: true\n            }\n        );\n\n        upperLabelRect && (normalStyle.textRect = clone(upperLabelRect));\n\n        normalStyle.truncate = (isShow && normalLabelModel.get('ellipsis'))\n            ? {\n                outerWidth: width,\n                outerHeight: height,\n                minChar: 2\n            }\n            : null;\n    }\n\n    function giveGraphic(storageName, Ctor, depth, z) {\n        var element = oldRawIndex != null && oldStorage[storageName][oldRawIndex];\n        var lasts = lastsForAnimation[storageName];\n\n        if (element) {\n            // Remove from oldStorage\n            oldStorage[storageName][oldRawIndex] = null;\n            prepareAnimationWhenHasOld(lasts, element, storageName);\n        }\n        // If invisible and no old element, do not create new element (for optimizing).\n        else if (!thisInvisible) {\n            element = new Ctor({z: calculateZ(depth, z)});\n            element.__tmDepth = depth;\n            element.__tmStorageName = storageName;\n            prepareAnimationWhenNoOld(lasts, element, storageName);\n        }\n\n        // Set to thisStorage\n        return (thisStorage[storageName][thisRawIndex] = element);\n    }\n\n    function prepareAnimationWhenHasOld(lasts, element, storageName) {\n        var lastCfg = lasts[thisRawIndex] = {};\n        lastCfg.old = storageName === 'nodeGroup'\n            ? element.position.slice()\n            : extend({}, element.shape);\n    }\n\n    // If a element is new, we need to find the animation start point carefully,\n    // otherwise it will looks strange when 'zoomToNode'.\n    function prepareAnimationWhenNoOld(lasts, element, storageName) {\n        var lastCfg = lasts[thisRawIndex] = {};\n        var parentNode = thisNode.parentNode;\n\n        if (parentNode && (!reRoot || reRoot.direction === 'drillDown')) {\n            var parentOldX = 0;\n            var parentOldY = 0;\n\n            // New nodes appear from right-bottom corner in 'zoomToNode' animation.\n            // For convenience, get old bounding rect from background.\n            var parentOldBg = lastsForAnimation.background[parentNode.getRawIndex()];\n            if (!reRoot && parentOldBg && parentOldBg.old) {\n                parentOldX = parentOldBg.old.width;\n                parentOldY = parentOldBg.old.height;\n            }\n\n            // When no parent old shape found, its parent is new too,\n            // so we can just use {x:0, y:0}.\n            lastCfg.old = storageName === 'nodeGroup'\n                ? [0, parentOldY]\n                : {x: parentOldX, y: parentOldY, width: 0, height: 0};\n        }\n\n        // Fade in, user can be aware that these nodes are new.\n        lastCfg.fadein = storageName !== 'nodeGroup';\n    }\n}\n\n// We can not set all backgroud with the same z, Because the behaviour of\n// drill down and roll up differ background creation sequence from tree\n// hierarchy sequence, which cause that lowser background element overlap\n// upper ones. So we calculate z based on depth.\n// Moreover, we try to shrink down z interval to [0, 1] to avoid that\n// treemap with large z overlaps other components.\nfunction calculateZ(depth, zInLevel) {\n    var zb = depth * Z_BASE + zInLevel;\n    return (zb - 1) / zb;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Treemap action\n */\n\nvar noop$1 = function () {};\n\nvar actionTypes = [\n    'treemapZoomToNode',\n    'treemapRender',\n    'treemapMove'\n];\n\nfor (var i$2 = 0; i$2 < actionTypes.length; i$2++) {\n    registerAction({type: actionTypes[i$2], update: 'updateView'}, noop$1);\n}\n\nregisterAction(\n    {type: 'treemapRootToNode', update: 'updateView'},\n    function (payload, ecModel) {\n\n        ecModel.eachComponent(\n            {mainType: 'series', subType: 'treemap', query: payload},\n            handleRootToNode\n        );\n\n        function handleRootToNode(model, index) {\n            var types = ['treemapZoomToNode', 'treemapRootToNode'];\n            var targetInfo = retrieveTargetInfo(payload, types, model);\n\n            if (targetInfo) {\n                var originViewRoot = model.getViewRoot();\n                if (originViewRoot) {\n                    payload.direction = aboveViewRoot(originViewRoot, targetInfo.node)\n                        ? 'rollUp' : 'drillDown';\n                }\n                model.resetViewRoot(targetInfo.node);\n            }\n        }\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$9 = each$1;\nvar isObject$5 = isObject$1;\n\nvar CATEGORY_DEFAULT_VISUAL_INDEX = -1;\n\n/**\n * @param {Object} option\n * @param {string} [option.type] See visualHandlers.\n * @param {string} [option.mappingMethod] 'linear' or 'piecewise' or 'category' or 'fixed'\n * @param {Array.<number>=} [option.dataExtent] [minExtent, maxExtent],\n *                                              required when mappingMethod is 'linear'\n * @param {Array.<Object>=} [option.pieceList] [\n *                                             {value: someValue},\n *                                             {interval: [min1, max1], visual: {...}},\n *                                             {interval: [min2, max2]}\n *                                             ],\n *                                            required when mappingMethod is 'piecewise'.\n *                                            Visual for only each piece can be specified.\n * @param {Array.<string|Object>=} [option.categories] ['cate1', 'cate2']\n *                                            required when mappingMethod is 'category'.\n *                                            If no option.categories, categories is set\n *                                            as [0, 1, 2, ...].\n * @param {boolean} [option.loop=false] Whether loop mapping when mappingMethod is 'category'.\n * @param {(Array|Object|*)} [option.visual]  Visual data.\n *                                            when mappingMethod is 'category',\n *                                            visual data can be array or object\n *                                            (like: {cate1: '#222', none: '#fff'})\n *                                            or primary types (which represents\n *                                            defualt category visual), otherwise visual\n *                                            can be array or primary (which will be\n *                                            normalized to array).\n *\n */\nvar VisualMapping = function (option) {\n    var mappingMethod = option.mappingMethod;\n    var visualType = option.type;\n\n    /**\n     * @readOnly\n     * @type {Object}\n     */\n    var thisOption = this.option = clone(option);\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    this.type = visualType;\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    this.mappingMethod = mappingMethod;\n\n    /**\n     * @private\n     * @type {Function}\n     */\n    this._normalizeData = normalizers[mappingMethod];\n\n    var visualHandler = visualHandlers[visualType];\n\n    /**\n     * @public\n     * @type {Function}\n     */\n    this.applyVisual = visualHandler.applyVisual;\n\n    /**\n     * @public\n     * @type {Function}\n     */\n    this.getColorMapper = visualHandler.getColorMapper;\n\n    /**\n     * @private\n     * @type {Function}\n     */\n    this._doMap = visualHandler._doMap[mappingMethod];\n\n    if (mappingMethod === 'piecewise') {\n        normalizeVisualRange(thisOption);\n        preprocessForPiecewise(thisOption);\n    }\n    else if (mappingMethod === 'category') {\n        thisOption.categories\n            ? preprocessForSpecifiedCategory(thisOption)\n            // categories is ordinal when thisOption.categories not specified,\n            // which need no more preprocess except normalize visual.\n            : normalizeVisualRange(thisOption, true);\n    }\n    else { // mappingMethod === 'linear' or 'fixed'\n        assert$1(mappingMethod !== 'linear' || thisOption.dataExtent);\n        normalizeVisualRange(thisOption);\n    }\n};\n\nVisualMapping.prototype = {\n\n    constructor: VisualMapping,\n\n    mapValueToVisual: function (value) {\n        var normalized = this._normalizeData(value);\n        return this._doMap(normalized, value);\n    },\n\n    getNormalizer: function () {\n        return bind(this._normalizeData, this);\n    }\n};\n\nvar visualHandlers = VisualMapping.visualHandlers = {\n\n    color: {\n\n        applyVisual: makeApplyVisual('color'),\n\n        /**\n         * Create a mapper function\n         * @return {Function}\n         */\n        getColorMapper: function () {\n            var thisOption = this.option;\n\n            return bind(\n                thisOption.mappingMethod === 'category'\n                    ? function (value, isNormalized) {\n                        !isNormalized && (value = this._normalizeData(value));\n                        return doMapCategory.call(this, value);\n                    }\n                    : function (value, isNormalized, out) {\n                        // If output rgb array\n                        // which will be much faster and useful in pixel manipulation\n                        var returnRGBArray = !!out;\n                        !isNormalized && (value = this._normalizeData(value));\n                        out = fastLerp(value, thisOption.parsedVisual, out);\n                        return returnRGBArray ? out : stringify(out, 'rgba');\n                    },\n                this\n            );\n        },\n\n        _doMap: {\n            linear: function (normalized) {\n                return stringify(\n                    fastLerp(normalized, this.option.parsedVisual),\n                    'rgba'\n                );\n            },\n            category: doMapCategory,\n            piecewise: function (normalized, value) {\n                var result = getSpecifiedVisual.call(this, value);\n                if (result == null) {\n                    result = stringify(\n                        fastLerp(normalized, this.option.parsedVisual),\n                        'rgba'\n                    );\n                }\n                return result;\n            },\n            fixed: doMapFixed\n        }\n    },\n\n    colorHue: makePartialColorVisualHandler(function (color, value) {\n        return modifyHSL(color, value);\n    }),\n\n    colorSaturation: makePartialColorVisualHandler(function (color, value) {\n        return modifyHSL(color, null, value);\n    }),\n\n    colorLightness: makePartialColorVisualHandler(function (color, value) {\n        return modifyHSL(color, null, null, value);\n    }),\n\n    colorAlpha: makePartialColorVisualHandler(function (color, value) {\n        return modifyAlpha(color, value);\n    }),\n\n    opacity: {\n        applyVisual: makeApplyVisual('opacity'),\n        _doMap: makeDoMap([0, 1])\n    },\n\n    liftZ: {\n        applyVisual: makeApplyVisual('liftZ'),\n        _doMap: {\n            linear: doMapFixed,\n            category: doMapFixed,\n            piecewise: doMapFixed,\n            fixed: doMapFixed\n        }\n    },\n\n    symbol: {\n        applyVisual: function (value, getter, setter) {\n            var symbolCfg = this.mapValueToVisual(value);\n            if (isString(symbolCfg)) {\n                setter('symbol', symbolCfg);\n            }\n            else if (isObject$5(symbolCfg)) {\n                for (var name in symbolCfg) {\n                    if (symbolCfg.hasOwnProperty(name)) {\n                        setter(name, symbolCfg[name]);\n                    }\n                }\n            }\n        },\n        _doMap: {\n            linear: doMapToArray,\n            category: doMapCategory,\n            piecewise: function (normalized, value) {\n                var result = getSpecifiedVisual.call(this, value);\n                if (result == null) {\n                    result = doMapToArray.call(this, normalized);\n                }\n                return result;\n            },\n            fixed: doMapFixed\n        }\n    },\n\n    symbolSize: {\n        applyVisual: makeApplyVisual('symbolSize'),\n        _doMap: makeDoMap([0, 1])\n    }\n};\n\n\nfunction preprocessForPiecewise(thisOption) {\n    var pieceList = thisOption.pieceList;\n    thisOption.hasSpecialVisual = false;\n\n    each$1(pieceList, function (piece, index) {\n        piece.originIndex = index;\n        // piece.visual is \"result visual value\" but not\n        // a visual range, so it does not need to be normalized.\n        if (piece.visual != null) {\n            thisOption.hasSpecialVisual = true;\n        }\n    });\n}\n\nfunction preprocessForSpecifiedCategory(thisOption) {\n    // Hash categories.\n    var categories = thisOption.categories;\n    var visual = thisOption.visual;\n\n    var categoryMap = thisOption.categoryMap = {};\n    each$9(categories, function (cate, index) {\n        categoryMap[cate] = index;\n    });\n\n    // Process visual map input.\n    if (!isArray(visual)) {\n        var visualArr = [];\n\n        if (isObject$1(visual)) {\n            each$9(visual, function (v, cate) {\n                var index = categoryMap[cate];\n                visualArr[index != null ? index : CATEGORY_DEFAULT_VISUAL_INDEX] = v;\n            });\n        }\n        else { // Is primary type, represents default visual.\n            visualArr[CATEGORY_DEFAULT_VISUAL_INDEX] = visual;\n        }\n\n        visual = setVisualToOption(thisOption, visualArr);\n    }\n\n    // Remove categories that has no visual,\n    // then we can mapping them to CATEGORY_DEFAULT_VISUAL_INDEX.\n    for (var i = categories.length - 1; i >= 0; i--) {\n        if (visual[i] == null) {\n            delete categoryMap[categories[i]];\n            categories.pop();\n        }\n    }\n}\n\nfunction normalizeVisualRange(thisOption, isCategory) {\n    var visual = thisOption.visual;\n    var visualArr = [];\n\n    if (isObject$1(visual)) {\n        each$9(visual, function (v) {\n            visualArr.push(v);\n        });\n    }\n    else if (visual != null) {\n        visualArr.push(visual);\n    }\n\n    var doNotNeedPair = {color: 1, symbol: 1};\n\n    if (!isCategory\n        && visualArr.length === 1\n        && !doNotNeedPair.hasOwnProperty(thisOption.type)\n    ) {\n        // Do not care visualArr.length === 0, which is illegal.\n        visualArr[1] = visualArr[0];\n    }\n\n    setVisualToOption(thisOption, visualArr);\n}\n\nfunction makePartialColorVisualHandler(applyValue) {\n    return {\n        applyVisual: function (value, getter, setter) {\n            value = this.mapValueToVisual(value);\n            // Must not be array value\n            setter('color', applyValue(getter('color'), value));\n        },\n        _doMap: makeDoMap([0, 1])\n    };\n}\n\nfunction doMapToArray(normalized) {\n    var visual = this.option.visual;\n    return visual[\n        Math.round(linearMap(normalized, [0, 1], [0, visual.length - 1], true))\n    ] || {};\n}\n\nfunction makeApplyVisual(visualType) {\n    return function (value, getter, setter) {\n        setter(visualType, this.mapValueToVisual(value));\n    };\n}\n\nfunction doMapCategory(normalized) {\n    var visual = this.option.visual;\n    return visual[\n        (this.option.loop && normalized !== CATEGORY_DEFAULT_VISUAL_INDEX)\n            ? normalized % visual.length\n            : normalized\n    ];\n}\n\nfunction doMapFixed() {\n    return this.option.visual[0];\n}\n\nfunction makeDoMap(sourceExtent) {\n    return {\n        linear: function (normalized) {\n            return linearMap(normalized, sourceExtent, this.option.visual, true);\n        },\n        category: doMapCategory,\n        piecewise: function (normalized, value) {\n            var result = getSpecifiedVisual.call(this, value);\n            if (result == null) {\n                result = linearMap(normalized, sourceExtent, this.option.visual, true);\n            }\n            return result;\n        },\n        fixed: doMapFixed\n    };\n}\n\nfunction getSpecifiedVisual(value) {\n    var thisOption = this.option;\n    var pieceList = thisOption.pieceList;\n    if (thisOption.hasSpecialVisual) {\n        var pieceIndex = VisualMapping.findPieceIndex(value, pieceList);\n        var piece = pieceList[pieceIndex];\n        if (piece && piece.visual) {\n            return piece.visual[this.type];\n        }\n    }\n}\n\nfunction setVisualToOption(thisOption, visualArr) {\n    thisOption.visual = visualArr;\n    if (thisOption.type === 'color') {\n        thisOption.parsedVisual = map(visualArr, function (item) {\n            return parse(item);\n        });\n    }\n    return visualArr;\n}\n\n\n/**\n * Normalizers by mapping methods.\n */\nvar normalizers = {\n\n    linear: function (value) {\n        return linearMap(value, this.option.dataExtent, [0, 1], true);\n    },\n\n    piecewise: function (value) {\n        var pieceList = this.option.pieceList;\n        var pieceIndex = VisualMapping.findPieceIndex(value, pieceList, true);\n        if (pieceIndex != null) {\n            return linearMap(pieceIndex, [0, pieceList.length - 1], [0, 1], true);\n        }\n    },\n\n    category: function (value) {\n        var index = this.option.categories\n            ? this.option.categoryMap[value]\n            : value; // ordinal\n        return index == null ? CATEGORY_DEFAULT_VISUAL_INDEX : index;\n    },\n\n    fixed: noop\n};\n\n\n\n/**\n * List available visual types.\n *\n * @public\n * @return {Array.<string>}\n */\nVisualMapping.listVisualTypes = function () {\n    var visualTypes = [];\n    each$1(visualHandlers, function (handler, key) {\n        visualTypes.push(key);\n    });\n    return visualTypes;\n};\n\n/**\n * @public\n */\nVisualMapping.addVisualHandler = function (name, handler) {\n    visualHandlers[name] = handler;\n};\n\n/**\n * @public\n */\nVisualMapping.isValidType = function (visualType) {\n    return visualHandlers.hasOwnProperty(visualType);\n};\n\n/**\n * Convinent method.\n * Visual can be Object or Array or primary type.\n *\n * @public\n */\nVisualMapping.eachVisual = function (visual, callback, context) {\n    if (isObject$1(visual)) {\n        each$1(visual, callback, context);\n    }\n    else {\n        callback.call(context, visual);\n    }\n};\n\nVisualMapping.mapVisual = function (visual, callback, context) {\n    var isPrimary;\n    var newVisual = isArray(visual)\n        ? []\n        : isObject$1(visual)\n        ? {}\n        : (isPrimary = true, null);\n\n    VisualMapping.eachVisual(visual, function (v, key) {\n        var newVal = callback.call(context, v, key);\n        isPrimary ? (newVisual = newVal) : (newVisual[key] = newVal);\n    });\n    return newVisual;\n};\n\n/**\n * @public\n * @param {Object} obj\n * @return {Object} new object containers visual values.\n *                 If no visuals, return null.\n */\nVisualMapping.retrieveVisuals = function (obj) {\n    var ret = {};\n    var hasVisual;\n\n    obj && each$9(visualHandlers, function (h, visualType) {\n        if (obj.hasOwnProperty(visualType)) {\n            ret[visualType] = obj[visualType];\n            hasVisual = true;\n        }\n    });\n\n    return hasVisual ? ret : null;\n};\n\n/**\n * Give order to visual types, considering colorSaturation, colorAlpha depends on color.\n *\n * @public\n * @param {(Object|Array)} visualTypes If Object, like: {color: ..., colorSaturation: ...}\n *                                     IF Array, like: ['color', 'symbol', 'colorSaturation']\n * @return {Array.<string>} Sorted visual types.\n */\nVisualMapping.prepareVisualTypes = function (visualTypes) {\n    if (isObject$5(visualTypes)) {\n        var types = [];\n        each$9(visualTypes, function (item, type) {\n            types.push(type);\n        });\n        visualTypes = types;\n    }\n    else if (isArray(visualTypes)) {\n        visualTypes = visualTypes.slice();\n    }\n    else {\n        return [];\n    }\n\n    visualTypes.sort(function (type1, type2) {\n        // color should be front of colorSaturation, colorAlpha, ...\n        // symbol and symbolSize do not matter.\n        return (type2 === 'color' && type1 !== 'color' && type1.indexOf('color') === 0)\n            ? 1 : -1;\n    });\n\n    return visualTypes;\n};\n\n/**\n * 'color', 'colorSaturation', 'colorAlpha', ... are depends on 'color'.\n * Other visuals are only depends on themself.\n *\n * @public\n * @param {string} visualType1\n * @param {string} visualType2\n * @return {boolean}\n */\nVisualMapping.dependsOn = function (visualType1, visualType2) {\n    return visualType2 === 'color'\n        ? !!(visualType1 && visualType1.indexOf(visualType2) === 0)\n        : visualType1 === visualType2;\n};\n\n/**\n * @param {number} value\n * @param {Array.<Object>} pieceList [{value: ..., interval: [min, max]}, ...]\n *                         Always from small to big.\n * @param {boolean} [findClosestWhenOutside=false]\n * @return {number} index\n */\nVisualMapping.findPieceIndex = function (value, pieceList, findClosestWhenOutside) {\n    var possibleI;\n    var abs = Infinity;\n\n    // value has the higher priority.\n    for (var i = 0, len = pieceList.length; i < len; i++) {\n        var pieceValue = pieceList[i].value;\n        if (pieceValue != null) {\n            if (pieceValue === value\n                // FIXME\n                // It is supposed to compare value according to value type of dimension,\n                // but currently value type can exactly be string or number.\n                // Compromise for numeric-like string (like '12'), especially\n                // in the case that visualMap.categories is ['22', '33'].\n                || (typeof pieceValue === 'string' && pieceValue === value + '')\n            ) {\n                return i;\n            }\n            findClosestWhenOutside && updatePossible(pieceValue, i);\n        }\n    }\n\n    for (var i = 0, len = pieceList.length; i < len; i++) {\n        var piece = pieceList[i];\n        var interval = piece.interval;\n        var close = piece.close;\n\n        if (interval) {\n            if (interval[0] === -Infinity) {\n                if (littleThan(close[1], value, interval[1])) {\n                    return i;\n                }\n            }\n            else if (interval[1] === Infinity) {\n                if (littleThan(close[0], interval[0], value)) {\n                    return i;\n                }\n            }\n            else if (\n                littleThan(close[0], interval[0], value)\n                && littleThan(close[1], value, interval[1])\n            ) {\n                return i;\n            }\n            findClosestWhenOutside && updatePossible(interval[0], i);\n            findClosestWhenOutside && updatePossible(interval[1], i);\n        }\n    }\n\n    if (findClosestWhenOutside) {\n        return value === Infinity\n            ? pieceList.length - 1\n            : value === -Infinity\n            ? 0\n            : possibleI;\n    }\n\n    function updatePossible(val, index) {\n        var newAbs = Math.abs(val - value);\n        if (newAbs < abs) {\n            abs = newAbs;\n            possibleI = index;\n        }\n    }\n\n};\n\nfunction littleThan(close, a, b) {\n    return close ? a <= b : a < b;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar isArray$2 = isArray;\n\nvar ITEM_STYLE_NORMAL = 'itemStyle';\n\nvar treemapVisual = {\n    seriesType: 'treemap',\n    reset: function (seriesModel, ecModel, api, payload) {\n        var tree = seriesModel.getData().tree;\n        var root = tree.root;\n        var seriesItemStyleModel = seriesModel.getModel(ITEM_STYLE_NORMAL);\n\n        if (root.isRemoved()) {\n            return;\n        }\n\n        var levelItemStyles = map(tree.levelModels, function (levelModel) {\n            return levelModel ? levelModel.get(ITEM_STYLE_NORMAL) : null;\n        });\n\n        travelTree(\n            root, // Visual should calculate from tree root but not view root.\n            {},\n            levelItemStyles,\n            seriesItemStyleModel,\n            seriesModel.getViewRoot().getAncestors(),\n            seriesModel\n        );\n    }\n};\n\nfunction travelTree(\n    node, designatedVisual, levelItemStyles, seriesItemStyleModel,\n    viewRootAncestors, seriesModel\n) {\n    var nodeModel = node.getModel();\n    var nodeLayout = node.getLayout();\n\n    // Optimize\n    if (!nodeLayout || nodeLayout.invisible || !nodeLayout.isInView) {\n        return;\n    }\n\n    var nodeItemStyleModel = node.getModel(ITEM_STYLE_NORMAL);\n    var levelItemStyle = levelItemStyles[node.depth];\n    var visuals = buildVisuals(\n        nodeItemStyleModel, designatedVisual, levelItemStyle, seriesItemStyleModel\n    );\n\n    // calculate border color\n    var borderColor = nodeItemStyleModel.get('borderColor');\n    var borderColorSaturation = nodeItemStyleModel.get('borderColorSaturation');\n    var thisNodeColor;\n    if (borderColorSaturation != null) {\n        // For performance, do not always execute 'calculateColor'.\n        thisNodeColor = calculateColor(visuals, node);\n        borderColor = calculateBorderColor(borderColorSaturation, thisNodeColor);\n    }\n    node.setVisual('borderColor', borderColor);\n\n    var viewChildren = node.viewChildren;\n    if (!viewChildren || !viewChildren.length) {\n        thisNodeColor = calculateColor(visuals, node);\n        // Apply visual to this node.\n        node.setVisual('color', thisNodeColor);\n    }\n    else {\n        var mapping = buildVisualMapping(\n            node, nodeModel, nodeLayout, nodeItemStyleModel, visuals, viewChildren\n        );\n\n        // Designate visual to children.\n        each$1(viewChildren, function (child, index) {\n            // If higher than viewRoot, only ancestors of viewRoot is needed to visit.\n            if (child.depth >= viewRootAncestors.length\n                || child === viewRootAncestors[child.depth]\n            ) {\n                var childVisual = mapVisual$1(\n                    nodeModel, visuals, child, index, mapping, seriesModel\n                );\n                travelTree(\n                    child, childVisual, levelItemStyles, seriesItemStyleModel,\n                    viewRootAncestors, seriesModel\n                );\n            }\n        });\n    }\n}\n\nfunction buildVisuals(\n    nodeItemStyleModel, designatedVisual, levelItemStyle, seriesItemStyleModel\n) {\n    var visuals = extend({}, designatedVisual);\n\n    each$1(['color', 'colorAlpha', 'colorSaturation'], function (visualName) {\n        // Priority: thisNode > thisLevel > parentNodeDesignated > seriesModel\n        var val = nodeItemStyleModel.get(visualName, true); // Ignore parent\n        val == null && levelItemStyle && (val = levelItemStyle[visualName]);\n        val == null && (val = designatedVisual[visualName]);\n        val == null && (val = seriesItemStyleModel.get(visualName));\n\n        val != null && (visuals[visualName] = val);\n    });\n\n    return visuals;\n}\n\nfunction calculateColor(visuals) {\n    var color = getValueVisualDefine(visuals, 'color');\n\n    if (color) {\n        var colorAlpha = getValueVisualDefine(visuals, 'colorAlpha');\n        var colorSaturation = getValueVisualDefine(visuals, 'colorSaturation');\n        if (colorSaturation) {\n            color = modifyHSL(color, null, null, colorSaturation);\n        }\n        if (colorAlpha) {\n            color = modifyAlpha(color, colorAlpha);\n        }\n\n        return color;\n    }\n}\n\nfunction calculateBorderColor(borderColorSaturation, thisNodeColor) {\n    return thisNodeColor != null\n            ? modifyHSL(thisNodeColor, null, null, borderColorSaturation)\n            : null;\n}\n\nfunction getValueVisualDefine(visuals, name) {\n    var value = visuals[name];\n    if (value != null && value !== 'none') {\n        return value;\n    }\n}\n\nfunction buildVisualMapping(\n    node, nodeModel, nodeLayout, nodeItemStyleModel, visuals, viewChildren\n) {\n    if (!viewChildren || !viewChildren.length) {\n        return;\n    }\n\n    var rangeVisual = getRangeVisual(nodeModel, 'color')\n        || (\n            visuals.color != null\n            && visuals.color !== 'none'\n            && (\n                getRangeVisual(nodeModel, 'colorAlpha')\n                || getRangeVisual(nodeModel, 'colorSaturation')\n            )\n        );\n\n    if (!rangeVisual) {\n        return;\n    }\n\n    var visualMin = nodeModel.get('visualMin');\n    var visualMax = nodeModel.get('visualMax');\n    var dataExtent = nodeLayout.dataExtent.slice();\n    visualMin != null && visualMin < dataExtent[0] && (dataExtent[0] = visualMin);\n    visualMax != null && visualMax > dataExtent[1] && (dataExtent[1] = visualMax);\n\n    var colorMappingBy = nodeModel.get('colorMappingBy');\n    var opt = {\n        type: rangeVisual.name,\n        dataExtent: dataExtent,\n        visual: rangeVisual.range\n    };\n    if (opt.type === 'color'\n        && (colorMappingBy === 'index' || colorMappingBy === 'id')\n    ) {\n        opt.mappingMethod = 'category';\n        opt.loop = true;\n        // categories is ordinal, so do not set opt.categories.\n    }\n    else {\n        opt.mappingMethod = 'linear';\n    }\n\n    var mapping = new VisualMapping(opt);\n    mapping.__drColorMappingBy = colorMappingBy;\n\n    return mapping;\n}\n\n// Notice: If we dont have the attribute 'colorRange', but only use\n// attribute 'color' to represent both concepts of 'colorRange' and 'color',\n// (It means 'colorRange' when 'color' is Array, means 'color' when not array),\n// this problem will be encountered:\n// If a level-1 node dont have children, and its siblings has children,\n// and colorRange is set on level-1, then the node can not be colored.\n// So we separate 'colorRange' and 'color' to different attributes.\nfunction getRangeVisual(nodeModel, name) {\n    // 'colorRange', 'colorARange', 'colorSRange'.\n    // If not exsits on this node, fetch from levels and series.\n    var range = nodeModel.get(name);\n    return (isArray$2(range) && range.length) ? {name: name, range: range} : null;\n}\n\nfunction mapVisual$1(nodeModel, visuals, child, index, mapping, seriesModel) {\n    var childVisuals = extend({}, visuals);\n\n    if (mapping) {\n        var mappingType = mapping.type;\n        var colorMappingBy = mappingType === 'color' && mapping.__drColorMappingBy;\n        var value = colorMappingBy === 'index'\n            ? index\n            : colorMappingBy === 'id'\n            ? seriesModel.mapIdToIndex(child.getId())\n            : child.getValue(nodeModel.get('visualDimension'));\n\n        childVisuals[mappingType] = mapping.mapValueToVisual(value);\n    }\n\n    return childVisuals;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The treemap layout implementation was originally copied from\n* \"d3.js\" with some modifications made for this project.\n* (See more details in the comment of the method \"squarify\" below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\nvar mathMax$4 = Math.max;\nvar mathMin$4 = Math.min;\nvar retrieveValue = retrieve;\nvar each$10 = each$1;\n\nvar PATH_BORDER_WIDTH = ['itemStyle', 'borderWidth'];\nvar PATH_GAP_WIDTH = ['itemStyle', 'gapWidth'];\nvar PATH_UPPER_LABEL_SHOW = ['upperLabel', 'show'];\nvar PATH_UPPER_LABEL_HEIGHT = ['upperLabel', 'height'];\n\n/**\n * @public\n */\nvar treemapLayout = {\n    seriesType: 'treemap',\n    reset: function (seriesModel, ecModel, api, payload) {\n        // Layout result in each node:\n        // {x, y, width, height, area, borderWidth}\n        var ecWidth = api.getWidth();\n        var ecHeight = api.getHeight();\n        var seriesOption = seriesModel.option;\n\n        var layoutInfo = getLayoutRect(\n            seriesModel.getBoxLayoutParams(),\n            {\n                width: api.getWidth(),\n                height: api.getHeight()\n            }\n        );\n\n        var size = seriesOption.size || []; // Compatible with ec2.\n        var containerWidth = parsePercent$1(\n            retrieveValue(layoutInfo.width, size[0]),\n            ecWidth\n        );\n        var containerHeight = parsePercent$1(\n            retrieveValue(layoutInfo.height, size[1]),\n            ecHeight\n        );\n\n        // Fetch payload info.\n        var payloadType = payload && payload.type;\n        var types = ['treemapZoomToNode', 'treemapRootToNode'];\n        var targetInfo = retrieveTargetInfo(payload, types, seriesModel);\n        var rootRect = (payloadType === 'treemapRender' || payloadType === 'treemapMove')\n            ? payload.rootRect : null;\n        var viewRoot = seriesModel.getViewRoot();\n        var viewAbovePath = getPathToRoot(viewRoot);\n\n        if (payloadType !== 'treemapMove') {\n            var rootSize = payloadType === 'treemapZoomToNode'\n                ? estimateRootSize(\n                    seriesModel, targetInfo, viewRoot, containerWidth, containerHeight\n                )\n                : rootRect\n                ? [rootRect.width, rootRect.height]\n                : [containerWidth, containerHeight];\n\n            var sort = seriesOption.sort;\n            if (sort && sort !== 'asc' && sort !== 'desc') {\n                sort = 'desc';\n            }\n            var options = {\n                squareRatio: seriesOption.squareRatio,\n                sort: sort,\n                leafDepth: seriesOption.leafDepth\n            };\n\n            // layout should be cleared because using updateView but not update.\n            viewRoot.hostTree.clearLayouts();\n\n            // TODO\n            // optimize: if out of view clip, do not layout.\n            // But take care that if do not render node out of view clip,\n            // how to calculate start po\n\n            var viewRootLayout = {\n                x: 0, y: 0,\n                width: rootSize[0], height: rootSize[1],\n                area: rootSize[0] * rootSize[1]\n            };\n            viewRoot.setLayout(viewRootLayout);\n\n            squarify(viewRoot, options, false, 0);\n            // Supplement layout.\n            var viewRootLayout = viewRoot.getLayout();\n            each$10(viewAbovePath, function (node, index) {\n                var childValue = (viewAbovePath[index + 1] || viewRoot).getValue();\n                node.setLayout(extend(\n                    {dataExtent: [childValue, childValue], borderWidth: 0, upperHeight: 0},\n                    viewRootLayout\n                ));\n            });\n        }\n\n        var treeRoot = seriesModel.getData().tree.root;\n\n        treeRoot.setLayout(\n            calculateRootPosition(layoutInfo, rootRect, targetInfo),\n            true\n        );\n\n        seriesModel.setLayoutInfo(layoutInfo);\n\n        // FIXME\n        // 现在没有clip功能，暂时取ec高宽。\n        prunning(\n            treeRoot,\n            // Transform to base element coordinate system.\n            new BoundingRect(-layoutInfo.x, -layoutInfo.y, ecWidth, ecHeight),\n            viewAbovePath,\n            viewRoot,\n            0\n        );\n    }\n};\n\n/**\n * Layout treemap with squarify algorithm.\n * The original presentation of this algorithm\n * was made by Mark Bruls, Kees Huizing, and Jarke J. van Wijk\n * <https://graphics.ethz.ch/teaching/scivis_common/Literature/squarifiedTreeMaps.pdf>.\n * The implementation of this algorithm was originally copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/9cc9a875e636a1dcf36cc1e07bdf77e1ad6e2c74/src/layout/treemap.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n *\n * @protected\n * @param {module:echarts/data/Tree~TreeNode} node\n * @param {Object} options\n * @param {string} options.sort 'asc' or 'desc'\n * @param {number} options.squareRatio\n * @param {boolean} hideChildren\n * @param {number} depth\n */\nfunction squarify(node, options, hideChildren, depth) {\n    var width;\n    var height;\n\n    if (node.isRemoved()) {\n        return;\n    }\n\n    var thisLayout = node.getLayout();\n    width = thisLayout.width;\n    height = thisLayout.height;\n\n    // Considering border and gap\n    var nodeModel = node.getModel();\n    var borderWidth = nodeModel.get(PATH_BORDER_WIDTH);\n    var halfGapWidth = nodeModel.get(PATH_GAP_WIDTH) / 2;\n    var upperLabelHeight = getUpperLabelHeight(nodeModel);\n    var upperHeight = Math.max(borderWidth, upperLabelHeight);\n    var layoutOffset = borderWidth - halfGapWidth;\n    var layoutOffsetUpper = upperHeight - halfGapWidth;\n    var nodeModel = node.getModel();\n\n    node.setLayout({\n        borderWidth: borderWidth,\n        upperHeight: upperHeight,\n        upperLabelHeight: upperLabelHeight\n    }, true);\n\n    width = mathMax$4(width - 2 * layoutOffset, 0);\n    height = mathMax$4(height - layoutOffset - layoutOffsetUpper, 0);\n\n    var totalArea = width * height;\n    var viewChildren = initChildren(\n        node, nodeModel, totalArea, options, hideChildren, depth\n    );\n\n    if (!viewChildren.length) {\n        return;\n    }\n\n    var rect = {x: layoutOffset, y: layoutOffsetUpper, width: width, height: height};\n    var rowFixedLength = mathMin$4(width, height);\n    var best = Infinity; // the best row score so far\n    var row = [];\n    row.area = 0;\n\n    for (var i = 0, len = viewChildren.length; i < len;) {\n        var child = viewChildren[i];\n\n        row.push(child);\n        row.area += child.getLayout().area;\n        var score = worst(row, rowFixedLength, options.squareRatio);\n\n        // continue with this orientation\n        if (score <= best) {\n            i++;\n            best = score;\n        }\n        // abort, and try a different orientation\n        else {\n            row.area -= row.pop().getLayout().area;\n            position(row, rowFixedLength, rect, halfGapWidth, false);\n            rowFixedLength = mathMin$4(rect.width, rect.height);\n            row.length = row.area = 0;\n            best = Infinity;\n        }\n    }\n\n    if (row.length) {\n        position(row, rowFixedLength, rect, halfGapWidth, true);\n    }\n\n    if (!hideChildren) {\n        var childrenVisibleMin = nodeModel.get('childrenVisibleMin');\n        if (childrenVisibleMin != null && totalArea < childrenVisibleMin) {\n            hideChildren = true;\n        }\n    }\n\n    for (var i = 0, len = viewChildren.length; i < len; i++) {\n        squarify(viewChildren[i], options, hideChildren, depth + 1);\n    }\n}\n\n/**\n * Set area to each child, and calculate data extent for visual coding.\n */\nfunction initChildren(node, nodeModel, totalArea, options, hideChildren, depth) {\n    var viewChildren = node.children || [];\n    var orderBy = options.sort;\n    orderBy !== 'asc' && orderBy !== 'desc' && (orderBy = null);\n\n    var overLeafDepth = options.leafDepth != null && options.leafDepth <= depth;\n\n    // leafDepth has higher priority.\n    if (hideChildren && !overLeafDepth) {\n        return (node.viewChildren = []);\n    }\n\n    // Sort children, order by desc.\n    viewChildren = filter(viewChildren, function (child) {\n        return !child.isRemoved();\n    });\n\n    sort$1(viewChildren, orderBy);\n\n    var info = statistic(nodeModel, viewChildren, orderBy);\n\n    if (info.sum === 0) {\n        return (node.viewChildren = []);\n    }\n\n    info.sum = filterByThreshold(nodeModel, totalArea, info.sum, orderBy, viewChildren);\n\n    if (info.sum === 0) {\n        return (node.viewChildren = []);\n    }\n\n    // Set area to each child.\n    for (var i = 0, len = viewChildren.length; i < len; i++) {\n        var area = viewChildren[i].getValue() / info.sum * totalArea;\n        // Do not use setLayout({...}, true), because it is needed to clear last layout.\n        viewChildren[i].setLayout({area: area});\n    }\n\n    if (overLeafDepth) {\n        viewChildren.length && node.setLayout({isLeafRoot: true}, true);\n        viewChildren.length = 0;\n    }\n\n    node.viewChildren = viewChildren;\n    node.setLayout({dataExtent: info.dataExtent}, true);\n\n    return viewChildren;\n}\n\n/**\n * Consider 'visibleMin'. Modify viewChildren and get new sum.\n */\nfunction filterByThreshold(nodeModel, totalArea, sum, orderBy, orderedChildren) {\n\n    // visibleMin is not supported yet when no option.sort.\n    if (!orderBy) {\n        return sum;\n    }\n\n    var visibleMin = nodeModel.get('visibleMin');\n    var len = orderedChildren.length;\n    var deletePoint = len;\n\n    // Always travel from little value to big value.\n    for (var i = len - 1; i >= 0; i--) {\n        var value = orderedChildren[\n            orderBy === 'asc' ? len - i - 1 : i\n        ].getValue();\n\n        if (value / sum * totalArea < visibleMin) {\n            deletePoint = i;\n            sum -= value;\n        }\n    }\n\n    orderBy === 'asc'\n        ? orderedChildren.splice(0, len - deletePoint)\n        : orderedChildren.splice(deletePoint, len - deletePoint);\n\n    return sum;\n}\n\n/**\n * Sort\n */\nfunction sort$1(viewChildren, orderBy) {\n    if (orderBy) {\n        viewChildren.sort(function (a, b) {\n            var diff = orderBy === 'asc'\n                ? a.getValue() - b.getValue() : b.getValue() - a.getValue();\n            return diff === 0\n                ? (orderBy === 'asc'\n                    ? a.dataIndex - b.dataIndex : b.dataIndex - a.dataIndex\n                )\n                : diff;\n        });\n    }\n    return viewChildren;\n}\n\n/**\n * Statistic\n */\nfunction statistic(nodeModel, children, orderBy) {\n    // Calculate sum.\n    var sum = 0;\n    for (var i = 0, len = children.length; i < len; i++) {\n        sum += children[i].getValue();\n    }\n\n    // Statistic data extent for latter visual coding.\n    // Notice: data extent should be calculate based on raw children\n    // but not filtered view children, otherwise visual mapping will not\n    // be stable when zoom (where children is filtered by visibleMin).\n\n    var dimension = nodeModel.get('visualDimension');\n    var dataExtent;\n\n    // The same as area dimension.\n    if (!children || !children.length) {\n        dataExtent = [NaN, NaN];\n    }\n    else if (dimension === 'value' && orderBy) {\n        dataExtent = [\n            children[children.length - 1].getValue(),\n            children[0].getValue()\n        ];\n        orderBy === 'asc' && dataExtent.reverse();\n    }\n    // Other dimension.\n    else {\n        var dataExtent = [Infinity, -Infinity];\n        each$10(children, function (child) {\n            var value = child.getValue(dimension);\n            value < dataExtent[0] && (dataExtent[0] = value);\n            value > dataExtent[1] && (dataExtent[1] = value);\n        });\n    }\n\n    return {sum: sum, dataExtent: dataExtent};\n}\n\n/**\n * Computes the score for the specified row,\n * as the worst aspect ratio.\n */\nfunction worst(row, rowFixedLength, ratio) {\n    var areaMax = 0;\n    var areaMin = Infinity;\n\n    for (var i = 0, area, len = row.length; i < len; i++) {\n        area = row[i].getLayout().area;\n        if (area) {\n            area < areaMin && (areaMin = area);\n            area > areaMax && (areaMax = area);\n        }\n    }\n\n    var squareArea = row.area * row.area;\n    var f = rowFixedLength * rowFixedLength * ratio;\n\n    return squareArea\n        ? mathMax$4(\n            (f * areaMax) / squareArea,\n            squareArea / (f * areaMin)\n        )\n        : Infinity;\n}\n\n/**\n * Positions the specified row of nodes. Modifies `rect`.\n */\nfunction position(row, rowFixedLength, rect, halfGapWidth, flush) {\n    // When rowFixedLength === rect.width,\n    // it is horizontal subdivision,\n    // rowFixedLength is the width of the subdivision,\n    // rowOtherLength is the height of the subdivision,\n    // and nodes will be positioned from left to right.\n\n    // wh[idx0WhenH] means: when horizontal,\n    //      wh[idx0WhenH] => wh[0] => 'width'.\n    //      xy[idx1WhenH] => xy[1] => 'y'.\n    var idx0WhenH = rowFixedLength === rect.width ? 0 : 1;\n    var idx1WhenH = 1 - idx0WhenH;\n    var xy = ['x', 'y'];\n    var wh = ['width', 'height'];\n\n    var last = rect[xy[idx0WhenH]];\n    var rowOtherLength = rowFixedLength\n        ? row.area / rowFixedLength : 0;\n\n    if (flush || rowOtherLength > rect[wh[idx1WhenH]]) {\n        rowOtherLength = rect[wh[idx1WhenH]]; // over+underflow\n    }\n    for (var i = 0, rowLen = row.length; i < rowLen; i++) {\n        var node = row[i];\n        var nodeLayout = {};\n        var step = rowOtherLength\n            ? node.getLayout().area / rowOtherLength : 0;\n\n        var wh1 = nodeLayout[wh[idx1WhenH]] = mathMax$4(rowOtherLength - 2 * halfGapWidth, 0);\n\n        // We use Math.max/min to avoid negative width/height when considering gap width.\n        var remain = rect[xy[idx0WhenH]] + rect[wh[idx0WhenH]] - last;\n        var modWH = (i === rowLen - 1 || remain < step) ? remain : step;\n        var wh0 = nodeLayout[wh[idx0WhenH]] = mathMax$4(modWH - 2 * halfGapWidth, 0);\n\n        nodeLayout[xy[idx1WhenH]] = rect[xy[idx1WhenH]] + mathMin$4(halfGapWidth, wh1 / 2);\n        nodeLayout[xy[idx0WhenH]] = last + mathMin$4(halfGapWidth, wh0 / 2);\n\n        last += modWH;\n        node.setLayout(nodeLayout, true);\n    }\n\n    rect[xy[idx1WhenH]] += rowOtherLength;\n    rect[wh[idx1WhenH]] -= rowOtherLength;\n}\n\n// Return [containerWidth, containerHeight] as defualt.\nfunction estimateRootSize(seriesModel, targetInfo, viewRoot, containerWidth, containerHeight) {\n    // If targetInfo.node exists, we zoom to the node,\n    // so estimate whold width and heigth by target node.\n    var currNode = (targetInfo || {}).node;\n    var defaultSize = [containerWidth, containerHeight];\n\n    if (!currNode || currNode === viewRoot) {\n        return defaultSize;\n    }\n\n    var parent;\n    var viewArea = containerWidth * containerHeight;\n    var area = viewArea * seriesModel.option.zoomToNodeRatio;\n\n    while (parent = currNode.parentNode) { // jshint ignore:line\n        var sum = 0;\n        var siblings = parent.children;\n\n        for (var i = 0, len = siblings.length; i < len; i++) {\n            sum += siblings[i].getValue();\n        }\n        var currNodeValue = currNode.getValue();\n        if (currNodeValue === 0) {\n            return defaultSize;\n        }\n        area *= sum / currNodeValue;\n\n        // Considering border, suppose aspect ratio is 1.\n        var parentModel = parent.getModel();\n        var borderWidth = parentModel.get(PATH_BORDER_WIDTH);\n        var upperHeight = Math.max(borderWidth, getUpperLabelHeight(parentModel, borderWidth));\n        area += 4 * borderWidth * borderWidth\n            + (3 * borderWidth + upperHeight) * Math.pow(area, 0.5);\n\n        area > MAX_SAFE_INTEGER && (area = MAX_SAFE_INTEGER);\n\n        currNode = parent;\n    }\n\n    area < viewArea && (area = viewArea);\n    var scale = Math.pow(area / viewArea, 0.5);\n\n    return [containerWidth * scale, containerHeight * scale];\n}\n\n// Root postion base on coord of containerGroup\nfunction calculateRootPosition(layoutInfo, rootRect, targetInfo) {\n    if (rootRect) {\n        return {x: rootRect.x, y: rootRect.y};\n    }\n\n    var defaultPosition = {x: 0, y: 0};\n    if (!targetInfo) {\n        return defaultPosition;\n    }\n\n    // If targetInfo is fetched by 'retrieveTargetInfo',\n    // old tree and new tree are the same tree,\n    // so the node still exists and we can visit it.\n\n    var targetNode = targetInfo.node;\n    var layout = targetNode.getLayout();\n\n    if (!layout) {\n        return defaultPosition;\n    }\n\n    // Transform coord from local to container.\n    var targetCenter = [layout.width / 2, layout.height / 2];\n    var node = targetNode;\n    while (node) {\n        var nodeLayout = node.getLayout();\n        targetCenter[0] += nodeLayout.x;\n        targetCenter[1] += nodeLayout.y;\n        node = node.parentNode;\n    }\n\n    return {\n        x: layoutInfo.width / 2 - targetCenter[0],\n        y: layoutInfo.height / 2 - targetCenter[1]\n    };\n}\n\n// Mark nodes visible for prunning when visual coding and rendering.\n// Prunning depends on layout and root position, so we have to do it after layout.\nfunction prunning(node, clipRect, viewAbovePath, viewRoot, depth) {\n    var nodeLayout = node.getLayout();\n    var nodeInViewAbovePath = viewAbovePath[depth];\n    var isAboveViewRoot = nodeInViewAbovePath && nodeInViewAbovePath === node;\n\n    if (\n        (nodeInViewAbovePath && !isAboveViewRoot)\n        || (depth === viewAbovePath.length && node !== viewRoot)\n    ) {\n        return;\n    }\n\n    node.setLayout({\n        // isInView means: viewRoot sub tree + viewAbovePath\n        isInView: true,\n        // invisible only means: outside view clip so that the node can not\n        // see but still layout for animation preparation but not render.\n        invisible: !isAboveViewRoot && !clipRect.intersect(nodeLayout),\n        isAboveViewRoot: isAboveViewRoot\n    }, true);\n\n    // Transform to child coordinate.\n    var childClipRect = new BoundingRect(\n        clipRect.x - nodeLayout.x,\n        clipRect.y - nodeLayout.y,\n        clipRect.width,\n        clipRect.height\n    );\n\n    each$10(node.viewChildren || [], function (child) {\n        prunning(child, childClipRect, viewAbovePath, viewRoot, depth + 1);\n    });\n}\n\nfunction getUpperLabelHeight(model) {\n    return model.get(PATH_UPPER_LABEL_SHOW) ? model.get(PATH_UPPER_LABEL_HEIGHT) : 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(treemapVisual);\nregisterLayout(treemapLayout);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Graph data structure\n *\n * @module echarts/data/Graph\n * @author Yi Shen(https://www.github.com/pissang)\n */\n\n// id may be function name of Object, add a prefix to avoid this problem.\nfunction generateNodeKey(id) {\n    return '_EC_' + id;\n}\n/**\n * @alias module:echarts/data/Graph\n * @constructor\n * @param {boolean} directed\n */\nvar Graph = function (directed) {\n    /**\n     * 是否是有向图\n     * @type {boolean}\n     * @private\n     */\n    this._directed = directed || false;\n\n    /**\n     * @type {Array.<module:echarts/data/Graph.Node>}\n     * @readOnly\n     */\n    this.nodes = [];\n\n    /**\n     * @type {Array.<module:echarts/data/Graph.Edge>}\n     * @readOnly\n     */\n    this.edges = [];\n\n    /**\n     * @type {Object.<string, module:echarts/data/Graph.Node>}\n     * @private\n     */\n    this._nodesMap = {};\n    /**\n     * @type {Object.<string, module:echarts/data/Graph.Edge>}\n     * @private\n     */\n    this._edgesMap = {};\n\n    /**\n     * @type {module:echarts/data/List}\n     * @readOnly\n     */\n    this.data;\n\n    /**\n     * @type {module:echarts/data/List}\n     * @readOnly\n     */\n    this.edgeData;\n};\n\nvar graphProto = Graph.prototype;\n/**\n * @type {string}\n */\ngraphProto.type = 'graph';\n\n/**\n * If is directed graph\n * @return {boolean}\n */\ngraphProto.isDirected = function () {\n    return this._directed;\n};\n\n/**\n * Add a new node\n * @param {string} id\n * @param {number} [dataIndex]\n */\ngraphProto.addNode = function (id, dataIndex) {\n    id = id || ('' + dataIndex);\n\n    var nodesMap = this._nodesMap;\n\n    if (nodesMap[generateNodeKey(id)]) {\n        if (__DEV__) {\n            console.error('Graph nodes have duplicate name or id');\n        }\n        return;\n    }\n\n    var node = new Node(id, dataIndex);\n    node.hostGraph = this;\n\n    this.nodes.push(node);\n\n    nodesMap[generateNodeKey(id)] = node;\n    return node;\n};\n\n/**\n * Get node by data index\n * @param  {number} dataIndex\n * @return {module:echarts/data/Graph~Node}\n */\ngraphProto.getNodeByIndex = function (dataIndex) {\n    var rawIdx = this.data.getRawIndex(dataIndex);\n    return this.nodes[rawIdx];\n};\n/**\n * Get node by id\n * @param  {string} id\n * @return {module:echarts/data/Graph.Node}\n */\ngraphProto.getNodeById = function (id) {\n    return this._nodesMap[generateNodeKey(id)];\n};\n\n/**\n * Add a new edge\n * @param {number|string|module:echarts/data/Graph.Node} n1\n * @param {number|string|module:echarts/data/Graph.Node} n2\n * @param {number} [dataIndex=-1]\n * @return {module:echarts/data/Graph.Edge}\n */\ngraphProto.addEdge = function (n1, n2, dataIndex) {\n    var nodesMap = this._nodesMap;\n    var edgesMap = this._edgesMap;\n\n    // PNEDING\n    if (typeof n1 === 'number') {\n        n1 = this.nodes[n1];\n    }\n    if (typeof n2 === 'number') {\n        n2 = this.nodes[n2];\n    }\n\n    if (!Node.isInstance(n1)) {\n        n1 = nodesMap[generateNodeKey(n1)];\n    }\n    if (!Node.isInstance(n2)) {\n        n2 = nodesMap[generateNodeKey(n2)];\n    }\n    if (!n1 || !n2) {\n        return;\n    }\n\n    var key = n1.id + '-' + n2.id;\n    // PENDING\n    if (edgesMap[key]) {\n        return;\n    }\n\n    var edge = new Edge(n1, n2, dataIndex);\n    edge.hostGraph = this;\n\n    if (this._directed) {\n        n1.outEdges.push(edge);\n        n2.inEdges.push(edge);\n    }\n    n1.edges.push(edge);\n    if (n1 !== n2) {\n        n2.edges.push(edge);\n    }\n\n    this.edges.push(edge);\n    edgesMap[key] = edge;\n\n    return edge;\n};\n\n/**\n * Get edge by data index\n * @param  {number} dataIndex\n * @return {module:echarts/data/Graph~Node}\n */\ngraphProto.getEdgeByIndex = function (dataIndex) {\n    var rawIdx = this.edgeData.getRawIndex(dataIndex);\n    return this.edges[rawIdx];\n};\n/**\n * Get edge by two linked nodes\n * @param  {module:echarts/data/Graph.Node|string} n1\n * @param  {module:echarts/data/Graph.Node|string} n2\n * @return {module:echarts/data/Graph.Edge}\n */\ngraphProto.getEdge = function (n1, n2) {\n    if (Node.isInstance(n1)) {\n        n1 = n1.id;\n    }\n    if (Node.isInstance(n2)) {\n        n2 = n2.id;\n    }\n\n    var edgesMap = this._edgesMap;\n\n    if (this._directed) {\n        return edgesMap[n1 + '-' + n2];\n    }\n    else {\n        return edgesMap[n1 + '-' + n2]\n            || edgesMap[n2 + '-' + n1];\n    }\n};\n\n/**\n * Iterate all nodes\n * @param  {Function} cb\n * @param  {*} [context]\n */\ngraphProto.eachNode = function (cb, context) {\n    var nodes = this.nodes;\n    var len = nodes.length;\n    for (var i = 0; i < len; i++) {\n        if (nodes[i].dataIndex >= 0) {\n            cb.call(context, nodes[i], i);\n        }\n    }\n};\n\n/**\n * Iterate all edges\n * @param  {Function} cb\n * @param  {*} [context]\n */\ngraphProto.eachEdge = function (cb, context) {\n    var edges = this.edges;\n    var len = edges.length;\n    for (var i = 0; i < len; i++) {\n        if (edges[i].dataIndex >= 0\n            && edges[i].node1.dataIndex >= 0\n            && edges[i].node2.dataIndex >= 0\n        ) {\n            cb.call(context, edges[i], i);\n        }\n    }\n};\n\n/**\n * Breadth first traverse\n * @param {Function} cb\n * @param {module:echarts/data/Graph.Node} startNode\n * @param {string} [direction='none'] 'none'|'in'|'out'\n * @param {*} [context]\n */\ngraphProto.breadthFirstTraverse = function (\n    cb, startNode, direction, context\n) {\n    if (!Node.isInstance(startNode)) {\n        startNode = this._nodesMap[generateNodeKey(startNode)];\n    }\n    if (!startNode) {\n        return;\n    }\n\n    var edgeType = direction === 'out'\n        ? 'outEdges' : (direction === 'in' ? 'inEdges' : 'edges');\n\n    for (var i = 0; i < this.nodes.length; i++) {\n        this.nodes[i].__visited = false;\n    }\n\n    if (cb.call(context, startNode, null)) {\n        return;\n    }\n\n    var queue = [startNode];\n    while (queue.length) {\n        var currentNode = queue.shift();\n        var edges = currentNode[edgeType];\n\n        for (var i = 0; i < edges.length; i++) {\n            var e = edges[i];\n            var otherNode = e.node1 === currentNode\n                ? e.node2 : e.node1;\n            if (!otherNode.__visited) {\n                if (cb.call(context, otherNode, currentNode)) {\n                    // Stop traversing\n                    return;\n                }\n                queue.push(otherNode);\n                otherNode.__visited = true;\n            }\n        }\n    }\n};\n\n// TODO\n// graphProto.depthFirstTraverse = function (\n//     cb, startNode, direction, context\n// ) {\n\n// };\n\n// Filter update\ngraphProto.update = function () {\n    var data = this.data;\n    var edgeData = this.edgeData;\n    var nodes = this.nodes;\n    var edges = this.edges;\n\n    for (var i = 0, len = nodes.length; i < len; i++) {\n        nodes[i].dataIndex = -1;\n    }\n    for (var i = 0, len = data.count(); i < len; i++) {\n        nodes[data.getRawIndex(i)].dataIndex = i;\n    }\n\n    edgeData.filterSelf(function (idx) {\n        var edge = edges[edgeData.getRawIndex(idx)];\n        return edge.node1.dataIndex >= 0 && edge.node2.dataIndex >= 0;\n    });\n\n    // Update edge\n    for (var i = 0, len = edges.length; i < len; i++) {\n        edges[i].dataIndex = -1;\n    }\n    for (var i = 0, len = edgeData.count(); i < len; i++) {\n        edges[edgeData.getRawIndex(i)].dataIndex = i;\n    }\n};\n\n/**\n * @return {module:echarts/data/Graph}\n */\ngraphProto.clone = function () {\n    var graph = new Graph(this._directed);\n    var nodes = this.nodes;\n    var edges = this.edges;\n    for (var i = 0; i < nodes.length; i++) {\n        graph.addNode(nodes[i].id, nodes[i].dataIndex);\n    }\n    for (var i = 0; i < edges.length; i++) {\n        var e = edges[i];\n        graph.addEdge(e.node1.id, e.node2.id, e.dataIndex);\n    }\n    return graph;\n};\n\n\n/**\n * @alias module:echarts/data/Graph.Node\n */\nfunction Node(id, dataIndex) {\n    /**\n    * @type {string}\n    */\n    this.id = id == null ? '' : id;\n\n    /**\n    * @type {Array.<module:echarts/data/Graph.Edge>}\n    */\n    this.inEdges = [];\n    /**\n    * @type {Array.<module:echarts/data/Graph.Edge>}\n    */\n    this.outEdges = [];\n    /**\n    * @type {Array.<module:echarts/data/Graph.Edge>}\n    */\n    this.edges = [];\n    /**\n     * @type {module:echarts/data/Graph}\n     */\n    this.hostGraph;\n\n    /**\n     * @type {number}\n     */\n    this.dataIndex = dataIndex == null ? -1 : dataIndex;\n}\n\nNode.prototype = {\n\n    constructor: Node,\n\n    /**\n     * @return {number}\n     */\n    degree: function () {\n        return this.edges.length;\n    },\n\n    /**\n     * @return {number}\n     */\n    inDegree: function () {\n        return this.inEdges.length;\n    },\n\n    /**\n    * @return {number}\n    */\n    outDegree: function () {\n        return this.outEdges.length;\n    },\n\n    /**\n     * @param {string} [path]\n     * @return {module:echarts/model/Model}\n     */\n    getModel: function (path) {\n        if (this.dataIndex < 0) {\n            return;\n        }\n        var graph = this.hostGraph;\n        var itemModel = graph.data.getItemModel(this.dataIndex);\n\n        return itemModel.getModel(path);\n    }\n};\n\n/**\n * 图边\n * @alias module:echarts/data/Graph.Edge\n * @param {module:echarts/data/Graph.Node} n1\n * @param {module:echarts/data/Graph.Node} n2\n * @param {number} [dataIndex=-1]\n */\nfunction Edge(n1, n2, dataIndex) {\n\n    /**\n     * 节点1，如果是有向图则为源节点\n     * @type {module:echarts/data/Graph.Node}\n     */\n    this.node1 = n1;\n\n    /**\n     * 节点2，如果是有向图则为目标节点\n     * @type {module:echarts/data/Graph.Node}\n     */\n    this.node2 = n2;\n\n    this.dataIndex = dataIndex == null ? -1 : dataIndex;\n}\n\n/**\n * @param {string} [path]\n * @return {module:echarts/model/Model}\n */\nEdge.prototype.getModel = function (path) {\n    if (this.dataIndex < 0) {\n        return;\n    }\n    var graph = this.hostGraph;\n    var itemModel = graph.edgeData.getItemModel(this.dataIndex);\n\n    return itemModel.getModel(path);\n};\n\nvar createGraphDataProxyMixin = function (hostName, dataName) {\n    return {\n        /**\n         * @param {string=} [dimension='value'] Default 'value'. can be 'a', 'b', 'c', 'd', 'e'.\n         * @return {number}\n         */\n        getValue: function (dimension) {\n            var data = this[hostName][dataName];\n            return data.get(data.getDimension(dimension || 'value'), this.dataIndex);\n        },\n\n        /**\n         * @param {Object|string} key\n         * @param {*} [value]\n         */\n        setVisual: function (key, value) {\n            this.dataIndex >= 0\n                && this[hostName][dataName].setItemVisual(this.dataIndex, key, value);\n        },\n\n        /**\n         * @param {string} key\n         * @return {boolean}\n         */\n        getVisual: function (key, ignoreParent) {\n            return this[hostName][dataName].getItemVisual(this.dataIndex, key, ignoreParent);\n        },\n\n        /**\n         * @param {Object} layout\n         * @return {boolean} [merge=false]\n         */\n        setLayout: function (layout, merge$$1) {\n            this.dataIndex >= 0\n                && this[hostName][dataName].setItemLayout(this.dataIndex, layout, merge$$1);\n        },\n\n        /**\n         * @return {Object}\n         */\n        getLayout: function () {\n            return this[hostName][dataName].getItemLayout(this.dataIndex);\n        },\n\n        /**\n         * @return {module:zrender/Element}\n         */\n        getGraphicEl: function () {\n            return this[hostName][dataName].getItemGraphicEl(this.dataIndex);\n        },\n\n        /**\n         * @return {number}\n         */\n        getRawIndex: function () {\n            return this[hostName][dataName].getRawIndex(this.dataIndex);\n        }\n    };\n};\n\nmixin(Node, createGraphDataProxyMixin('hostGraph', 'data'));\nmixin(Edge, createGraphDataProxyMixin('hostGraph', 'edgeData'));\n\nGraph.Node = Node;\nGraph.Edge = Edge;\n\nenableClassCheck(Node);\nenableClassCheck(Edge);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar createGraphFromNodeEdge = function (nodes, edges, seriesModel, directed, beforeLink) {\n    // ??? TODO\n    // support dataset?\n    var graph = new Graph(directed);\n    for (var i = 0; i < nodes.length; i++) {\n        graph.addNode(retrieve(\n            // Id, name, dataIndex\n            nodes[i].id, nodes[i].name, i\n        ), i);\n    }\n\n    var linkNameList = [];\n    var validEdges = [];\n    var linkCount = 0;\n    for (var i = 0; i < edges.length; i++) {\n        var link = edges[i];\n        var source = link.source;\n        var target = link.target;\n        // addEdge may fail when source or target not exists\n        if (graph.addEdge(source, target, linkCount)) {\n            validEdges.push(link);\n            linkNameList.push(retrieve(link.id, source + ' > ' + target));\n            linkCount++;\n        }\n    }\n\n    var coordSys = seriesModel.get('coordinateSystem');\n    var nodeData;\n    if (coordSys === 'cartesian2d' || coordSys === 'polar') {\n        nodeData = createListFromArray(nodes, seriesModel);\n    }\n    else {\n        var coordSysCtor = CoordinateSystemManager.get(coordSys);\n        var coordDimensions = (coordSysCtor && coordSysCtor.type !== 'view')\n            ? (coordSysCtor.dimensions || []) : [];\n        // FIXME: Some geo do not need `value` dimenson, whereas `calendar` needs\n        // `value` dimension, but graph need `value` dimension. It's better to\n        // uniform this behavior.\n        if (indexOf(coordDimensions, 'value') < 0) {\n            coordDimensions.concat(['value']);\n        }\n\n        var dimensionNames = createDimensions(nodes, {\n            coordDimensions: coordDimensions\n        });\n        nodeData = new List(dimensionNames, seriesModel);\n        nodeData.initData(nodes);\n    }\n\n    var edgeData = new List(['value'], seriesModel);\n    edgeData.initData(validEdges, linkNameList);\n\n    beforeLink && beforeLink(nodeData, edgeData);\n\n    linkList({\n        mainData: nodeData,\n        struct: graph,\n        structAttr: 'graph',\n        datas: {node: nodeData, edge: edgeData},\n        datasAttr: {node: 'data', edge: 'edgeData'}\n    });\n\n    // Update dataIndex of nodes and edges because invalid edge may be removed\n    graph.update();\n\n    return graph;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar GraphSeries = extendSeriesModel({\n\n    type: 'series.graph',\n\n    init: function (option) {\n        GraphSeries.superApply(this, 'init', arguments);\n\n        // Provide data for legend select\n        this.legendDataProvider = function () {\n            return this._categoriesData;\n        };\n\n        this.fillDataTextStyle(option.edges || option.links);\n\n        this._updateCategoriesData();\n    },\n\n    mergeOption: function (option) {\n        GraphSeries.superApply(this, 'mergeOption', arguments);\n\n        this.fillDataTextStyle(option.edges || option.links);\n\n        this._updateCategoriesData();\n    },\n\n    mergeDefaultAndTheme: function (option) {\n        GraphSeries.superApply(this, 'mergeDefaultAndTheme', arguments);\n        defaultEmphasis(option, ['edgeLabel'], ['show']);\n    },\n\n    getInitialData: function (option, ecModel) {\n        var edges = option.edges || option.links || [];\n        var nodes = option.data || option.nodes || [];\n        var self = this;\n\n        if (nodes && edges) {\n            return createGraphFromNodeEdge(nodes, edges, this, true, beforeLink).data;\n        }\n\n        function beforeLink(nodeData, edgeData) {\n            // Overwrite nodeData.getItemModel to\n            nodeData.wrapMethod('getItemModel', function (model) {\n                var categoriesModels = self._categoriesModels;\n                var categoryIdx = model.getShallow('category');\n                var categoryModel = categoriesModels[categoryIdx];\n                if (categoryModel) {\n                    categoryModel.parentModel = model.parentModel;\n                    model.parentModel = categoryModel;\n                }\n                return model;\n            });\n\n            var edgeLabelModel = self.getModel('edgeLabel');\n            // For option `edgeLabel` can be found by label.xxx.xxx on item mode.\n            var fakeSeriesModel = new Model(\n                {label: edgeLabelModel.option},\n                edgeLabelModel.parentModel,\n                ecModel\n            );\n            var emphasisEdgeLabelModel = self.getModel('emphasis.edgeLabel');\n            var emphasisFakeSeriesModel = new Model(\n                {emphasis: {label: emphasisEdgeLabelModel.option}},\n                emphasisEdgeLabelModel.parentModel,\n                ecModel\n            );\n\n            edgeData.wrapMethod('getItemModel', function (model) {\n                model.customizeGetParent(edgeGetParent);\n                return model;\n            });\n\n            function edgeGetParent(path) {\n                path = this.parsePath(path);\n                return (path && path[0] === 'label')\n                    ? fakeSeriesModel\n                    : (path && path[0] === 'emphasis' && path[1] === 'label')\n                    ? emphasisFakeSeriesModel\n                    : this.parentModel;\n            }\n        }\n    },\n\n    /**\n     * @return {module:echarts/data/Graph}\n     */\n    getGraph: function () {\n        return this.getData().graph;\n    },\n\n    /**\n     * @return {module:echarts/data/List}\n     */\n    getEdgeData: function () {\n        return this.getGraph().edgeData;\n    },\n\n    /**\n     * @return {module:echarts/data/List}\n     */\n    getCategoriesData: function () {\n        return this._categoriesData;\n    },\n\n    /**\n     * @override\n     */\n    formatTooltip: function (dataIndex, multipleSeries, dataType) {\n        if (dataType === 'edge') {\n            var nodeData = this.getData();\n            var params = this.getDataParams(dataIndex, dataType);\n            var edge = nodeData.graph.getEdgeByIndex(dataIndex);\n            var sourceName = nodeData.getName(edge.node1.dataIndex);\n            var targetName = nodeData.getName(edge.node2.dataIndex);\n\n            var html = [];\n            sourceName != null && html.push(sourceName);\n            targetName != null && html.push(targetName);\n            html = encodeHTML(html.join(' > '));\n\n            if (params.value) {\n                html += ' : ' + encodeHTML(params.value);\n            }\n            return html;\n        }\n        else { // dataType === 'node' or empty\n            return GraphSeries.superApply(this, 'formatTooltip', arguments);\n        }\n    },\n\n    _updateCategoriesData: function () {\n        var categories = map(this.option.categories || [], function (category) {\n            // Data must has value\n            return category.value != null ? category : extend({\n                value: 0\n            }, category);\n        });\n        var categoriesData = new List(['value'], this);\n        categoriesData.initData(categories);\n\n        this._categoriesData = categoriesData;\n\n        this._categoriesModels = categoriesData.mapArray(function (idx) {\n            return categoriesData.getItemModel(idx, true);\n        });\n    },\n\n    setZoom: function (zoom) {\n        this.option.zoom = zoom;\n    },\n\n    setCenter: function (center) {\n        this.option.center = center;\n    },\n\n    isAnimationEnabled: function () {\n        return GraphSeries.superCall(this, 'isAnimationEnabled')\n            // Not enable animation when do force layout\n            && !(this.get('layout') === 'force' && this.get('force.layoutAnimation'));\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n\n        coordinateSystem: 'view',\n\n        // Default option for all coordinate systems\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n        // polarIndex: 0,\n        // geoIndex: 0,\n\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n\n        layout: null,\n\n        focusNodeAdjacency: false,\n\n        // Configuration of circular layout\n        circular: {\n            rotateLabel: false\n        },\n        // Configuration of force directed layout\n        force: {\n            initLayout: null,\n            // Node repulsion. Can be an array to represent range.\n            repulsion: [0, 50],\n            gravity: 0.1,\n\n            // Edge length. Can be an array to represent range.\n            edgeLength: 30,\n\n            layoutAnimation: true\n        },\n\n        left: 'center',\n        top: 'center',\n        // right: null,\n        // bottom: null,\n        // width: '80%',\n        // height: '80%',\n\n        symbol: 'circle',\n        symbolSize: 10,\n\n        edgeSymbol: ['none', 'none'],\n        edgeSymbolSize: 10,\n        edgeLabel: {\n            position: 'middle'\n        },\n\n        draggable: false,\n\n        roam: false,\n\n        // Default on center of graph\n        center: null,\n\n        zoom: 1,\n        // Symbol size scale ratio in roam\n        nodeScaleRatio: 0.6,\n        // cursor: null,\n\n        // categories: [],\n\n        // data: []\n        // Or\n        // nodes: []\n        //\n        // links: []\n        // Or\n        // edges: []\n\n        label: {\n            show: false,\n            formatter: '{b}'\n        },\n\n        itemStyle: {},\n\n        lineStyle: {\n            color: '#aaa',\n            width: 1,\n            curveness: 0,\n            opacity: 0.5\n        },\n        emphasis: {\n            label: {\n                show: true\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Line path for bezier and straight line draw\n */\n\nvar straightLineProto = Line.prototype;\nvar bezierCurveProto = BezierCurve.prototype;\n\nfunction isLine(shape) {\n    return isNaN(+shape.cpx1) || isNaN(+shape.cpy1);\n}\n\nvar LinePath = extendShape({\n\n    type: 'ec-line',\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    shape: {\n        x1: 0,\n        y1: 0,\n        x2: 0,\n        y2: 0,\n        percent: 1,\n        cpx1: null,\n        cpy1: null\n    },\n\n    buildPath: function (ctx, shape) {\n        (isLine(shape) ? straightLineProto : bezierCurveProto).buildPath(ctx, shape);\n    },\n\n    pointAt: function (t) {\n        return isLine(this.shape)\n            ? straightLineProto.pointAt.call(this, t)\n            : bezierCurveProto.pointAt.call(this, t);\n    },\n\n    tangentAt: function (t) {\n        var shape = this.shape;\n        var p = isLine(shape)\n            ? [shape.x2 - shape.x1, shape.y2 - shape.y1]\n            : bezierCurveProto.tangentAt.call(this, t);\n        return normalize(p, p);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Line\n */\n\nvar SYMBOL_CATEGORIES = ['fromSymbol', 'toSymbol'];\n\nfunction makeSymbolTypeKey(symbolCategory) {\n    return '_' + symbolCategory + 'Type';\n}\n/**\n * @inner\n */\nfunction createSymbol$1(name, lineData, idx) {\n    var color = lineData.getItemVisual(idx, 'color');\n    var symbolType = lineData.getItemVisual(idx, name);\n    var symbolSize = lineData.getItemVisual(idx, name + 'Size');\n\n    if (!symbolType || symbolType === 'none') {\n        return;\n    }\n\n    if (!isArray(symbolSize)) {\n        symbolSize = [symbolSize, symbolSize];\n    }\n    var symbolPath = createSymbol(\n        symbolType, -symbolSize[0] / 2, -symbolSize[1] / 2,\n        symbolSize[0], symbolSize[1], color\n    );\n\n    symbolPath.name = name;\n\n    return symbolPath;\n}\n\nfunction createLine(points) {\n    var line = new LinePath({\n        name: 'line'\n    });\n    setLinePoints(line.shape, points);\n    return line;\n}\n\nfunction setLinePoints(targetShape, points) {\n    var p1 = points[0];\n    var p2 = points[1];\n    var cp1 = points[2];\n    targetShape.x1 = p1[0];\n    targetShape.y1 = p1[1];\n    targetShape.x2 = p2[0];\n    targetShape.y2 = p2[1];\n    targetShape.percent = 1;\n\n    if (cp1) {\n        targetShape.cpx1 = cp1[0];\n        targetShape.cpy1 = cp1[1];\n    }\n    else {\n        targetShape.cpx1 = NaN;\n        targetShape.cpy1 = NaN;\n    }\n}\n\nfunction updateSymbolAndLabelBeforeLineUpdate() {\n    var lineGroup = this;\n    var symbolFrom = lineGroup.childOfName('fromSymbol');\n    var symbolTo = lineGroup.childOfName('toSymbol');\n    var label = lineGroup.childOfName('label');\n    // Quick reject\n    if (!symbolFrom && !symbolTo && label.ignore) {\n        return;\n    }\n\n    var invScale = 1;\n    var parentNode = this.parent;\n    while (parentNode) {\n        if (parentNode.scale) {\n            invScale /= parentNode.scale[0];\n        }\n        parentNode = parentNode.parent;\n    }\n\n    var line = lineGroup.childOfName('line');\n    // If line not changed\n    // FIXME Parent scale changed\n    if (!this.__dirty && !line.__dirty) {\n        return;\n    }\n\n    var percent = line.shape.percent;\n    var fromPos = line.pointAt(0);\n    var toPos = line.pointAt(percent);\n\n    var d = sub([], toPos, fromPos);\n    normalize(d, d);\n\n    if (symbolFrom) {\n        symbolFrom.attr('position', fromPos);\n        var tangent = line.tangentAt(0);\n        symbolFrom.attr('rotation', Math.PI / 2 - Math.atan2(\n            tangent[1], tangent[0]\n        ));\n        symbolFrom.attr('scale', [invScale * percent, invScale * percent]);\n    }\n    if (symbolTo) {\n        symbolTo.attr('position', toPos);\n        var tangent = line.tangentAt(1);\n        symbolTo.attr('rotation', -Math.PI / 2 - Math.atan2(\n            tangent[1], tangent[0]\n        ));\n        symbolTo.attr('scale', [invScale * percent, invScale * percent]);\n    }\n\n    if (!label.ignore) {\n        label.attr('position', toPos);\n\n        var textPosition;\n        var textAlign;\n        var textVerticalAlign;\n\n        var distance$$1 = 5 * invScale;\n        // End\n        if (label.__position === 'end') {\n            textPosition = [d[0] * distance$$1 + toPos[0], d[1] * distance$$1 + toPos[1]];\n            textAlign = d[0] > 0.8 ? 'left' : (d[0] < -0.8 ? 'right' : 'center');\n            textVerticalAlign = d[1] > 0.8 ? 'top' : (d[1] < -0.8 ? 'bottom' : 'middle');\n        }\n        // Middle\n        else if (label.__position === 'middle') {\n            var halfPercent = percent / 2;\n            var tangent = line.tangentAt(halfPercent);\n            var n = [tangent[1], -tangent[0]];\n            var cp = line.pointAt(halfPercent);\n            if (n[1] > 0) {\n                n[0] = -n[0];\n                n[1] = -n[1];\n            }\n            textPosition = [cp[0] + n[0] * distance$$1, cp[1] + n[1] * distance$$1];\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            var rotation = -Math.atan2(tangent[1], tangent[0]);\n            if (toPos[0] < fromPos[0]) {\n                rotation = Math.PI + rotation;\n            }\n            label.attr('rotation', rotation);\n        }\n        // Start\n        else {\n            textPosition = [-d[0] * distance$$1 + fromPos[0], -d[1] * distance$$1 + fromPos[1]];\n            textAlign = d[0] > 0.8 ? 'right' : (d[0] < -0.8 ? 'left' : 'center');\n            textVerticalAlign = d[1] > 0.8 ? 'bottom' : (d[1] < -0.8 ? 'top' : 'middle');\n        }\n        label.attr({\n            style: {\n                // Use the user specified text align and baseline first\n                textVerticalAlign: label.__verticalAlign || textVerticalAlign,\n                textAlign: label.__textAlign || textAlign\n            },\n            position: textPosition,\n            scale: [invScale, invScale]\n        });\n    }\n}\n\n/**\n * @constructor\n * @extends {module:zrender/graphic/Group}\n * @alias {module:echarts/chart/helper/Line}\n */\nfunction Line$1(lineData, idx, seriesScope) {\n    Group.call(this);\n\n    this._createLine(lineData, idx, seriesScope);\n}\n\nvar lineProto = Line$1.prototype;\n\n// Update symbol position and rotation\nlineProto.beforeUpdate = updateSymbolAndLabelBeforeLineUpdate;\n\nlineProto._createLine = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n    var linePoints = lineData.getItemLayout(idx);\n\n    var line = createLine(linePoints);\n    line.shape.percent = 0;\n    initProps(line, {\n        shape: {\n            percent: 1\n        }\n    }, seriesModel, idx);\n\n    this.add(line);\n\n    var label = new Text({\n        name: 'label',\n        // FIXME\n        // Temporary solution for `focusNodeAdjacency`.\n        // line label do not use the opacity of lineStyle.\n        lineLabelOriginalOpacity: 1\n    });\n    this.add(label);\n\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbol = createSymbol$1(symbolCategory, lineData, idx);\n        // symbols must added after line to make sure\n        // it will be updated after line#update.\n        // Or symbol position and rotation update in line#beforeUpdate will be one frame slow\n        this.add(symbol);\n        this[makeSymbolTypeKey(symbolCategory)] = lineData.getItemVisual(idx, symbolCategory);\n    }, this);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\nlineProto.updateData = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n\n    var line = this.childOfName('line');\n    var linePoints = lineData.getItemLayout(idx);\n    var target = {\n        shape: {}\n    };\n    setLinePoints(target.shape, linePoints);\n    updateProps(line, target, seriesModel, idx);\n\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbolType = lineData.getItemVisual(idx, symbolCategory);\n        var key = makeSymbolTypeKey(symbolCategory);\n        // Symbol changed\n        if (this[key] !== symbolType) {\n            this.remove(this.childOfName(symbolCategory));\n            var symbol = createSymbol$1(symbolCategory, lineData, idx);\n            this.add(symbol);\n        }\n        this[key] = symbolType;\n    }, this);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\nlineProto._updateCommonStl = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n\n    var line = this.childOfName('line');\n\n    var lineStyle = seriesScope && seriesScope.lineStyle;\n    var hoverLineStyle = seriesScope && seriesScope.hoverLineStyle;\n    var labelModel = seriesScope && seriesScope.labelModel;\n    var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;\n\n    // Optimization for large dataset\n    if (!seriesScope || lineData.hasItemOption) {\n        var itemModel = lineData.getItemModel(idx);\n\n        lineStyle = itemModel.getModel('lineStyle').getLineStyle();\n        hoverLineStyle = itemModel.getModel('emphasis.lineStyle').getLineStyle();\n\n        labelModel = itemModel.getModel('label');\n        hoverLabelModel = itemModel.getModel('emphasis.label');\n    }\n\n    var visualColor = lineData.getItemVisual(idx, 'color');\n    var visualOpacity = retrieve3(\n        lineData.getItemVisual(idx, 'opacity'),\n        lineStyle.opacity,\n        1\n    );\n\n    line.useStyle(defaults(\n        {\n            strokeNoScale: true,\n            fill: 'none',\n            stroke: visualColor,\n            opacity: visualOpacity\n        },\n        lineStyle\n    ));\n    line.hoverStyle = hoverLineStyle;\n\n    // Update symbol\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbol = this.childOfName(symbolCategory);\n        if (symbol) {\n            symbol.setColor(visualColor);\n            symbol.setStyle({\n                opacity: visualOpacity\n            });\n        }\n    }, this);\n\n    var showLabel = labelModel.getShallow('show');\n    var hoverShowLabel = hoverLabelModel.getShallow('show');\n\n    var label = this.childOfName('label');\n    var defaultLabelColor;\n    var baseText;\n\n    // FIXME: the logic below probably should be merged to `graphic.setLabelStyle`.\n    if (showLabel || hoverShowLabel) {\n        defaultLabelColor = visualColor || '#000';\n\n        baseText = seriesModel.getFormattedLabel(idx, 'normal', lineData.dataType);\n        if (baseText == null) {\n            var rawVal = seriesModel.getRawValue(idx);\n            baseText = rawVal == null\n                ? lineData.getName(idx)\n                : isFinite(rawVal)\n                ? round$2(rawVal)\n                : rawVal;\n        }\n    }\n    var normalText = showLabel ? baseText : null;\n    var emphasisText = hoverShowLabel\n        ? retrieve2(\n            seriesModel.getFormattedLabel(idx, 'emphasis', lineData.dataType),\n            baseText\n        )\n        : null;\n\n    var labelStyle = label.style;\n\n    // Always set `textStyle` even if `normalStyle.text` is null, because default\n    // values have to be set on `normalStyle`.\n    if (normalText != null || emphasisText != null) {\n        setTextStyle(label.style, labelModel, {\n            text: normalText\n        }, {\n            autoColor: defaultLabelColor\n        });\n\n        label.__textAlign = labelStyle.textAlign;\n        label.__verticalAlign = labelStyle.textVerticalAlign;\n        // 'start', 'middle', 'end'\n        label.__position = labelModel.get('position') || 'middle';\n    }\n\n    if (emphasisText != null) {\n        // Only these properties supported in this emphasis style here.\n        label.hoverStyle = {\n            text: emphasisText,\n            textFill: hoverLabelModel.getTextColor(true),\n            // For merging hover style to normal style, do not use\n            // `hoverLabelModel.getFont()` here.\n            fontStyle: hoverLabelModel.getShallow('fontStyle'),\n            fontWeight: hoverLabelModel.getShallow('fontWeight'),\n            fontSize: hoverLabelModel.getShallow('fontSize'),\n            fontFamily: hoverLabelModel.getShallow('fontFamily')\n        };\n    }\n    else {\n        label.hoverStyle = {\n            text: null\n        };\n    }\n\n    label.ignore = !showLabel && !hoverShowLabel;\n\n    setHoverStyle(this);\n};\n\nlineProto.highlight = function () {\n    this.trigger('emphasis');\n};\n\nlineProto.downplay = function () {\n    this.trigger('normal');\n};\n\nlineProto.updateLayout = function (lineData, idx) {\n    this.setLinePoints(lineData.getItemLayout(idx));\n};\n\nlineProto.setLinePoints = function (points) {\n    var linePath = this.childOfName('line');\n    setLinePoints(linePath.shape, points);\n    linePath.dirty();\n};\n\ninherits(Line$1, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/LineDraw\n */\n\n// import IncrementalDisplayable from 'zrender/src/graphic/IncrementalDisplayable';\n\n/**\n * @alias module:echarts/component/marker/LineDraw\n * @constructor\n */\nfunction LineDraw(ctor) {\n    this._ctor = ctor || Line$1;\n\n    this.group = new Group();\n}\n\nvar lineDrawProto = LineDraw.prototype;\n\nlineDrawProto.isPersistent = function () {\n    return true;\n};\n\n/**\n * @param {module:echarts/data/List} lineData\n */\nlineDrawProto.updateData = function (lineData) {\n    var lineDraw = this;\n    var group = lineDraw.group;\n\n    var oldLineData = lineDraw._lineData;\n    lineDraw._lineData = lineData;\n\n    // There is no oldLineData only when first rendering or switching from\n    // stream mode to normal mode, where previous elements should be removed.\n    if (!oldLineData) {\n        group.removeAll();\n    }\n\n    var seriesScope = makeSeriesScope$1(lineData);\n\n    lineData.diff(oldLineData)\n        .add(function (idx) {\n            doAdd(lineDraw, lineData, idx, seriesScope);\n        })\n        .update(function (newIdx, oldIdx) {\n            doUpdate(lineDraw, oldLineData, lineData, oldIdx, newIdx, seriesScope);\n        })\n        .remove(function (idx) {\n            group.remove(oldLineData.getItemGraphicEl(idx));\n        })\n        .execute();\n};\n\nfunction doAdd(lineDraw, lineData, idx, seriesScope) {\n    var itemLayout = lineData.getItemLayout(idx);\n\n    if (!lineNeedsDraw(itemLayout)) {\n        return;\n    }\n\n    var el = new lineDraw._ctor(lineData, idx, seriesScope);\n    lineData.setItemGraphicEl(idx, el);\n    lineDraw.group.add(el);\n}\n\nfunction doUpdate(lineDraw, oldLineData, newLineData, oldIdx, newIdx, seriesScope) {\n    var itemEl = oldLineData.getItemGraphicEl(oldIdx);\n\n    if (!lineNeedsDraw(newLineData.getItemLayout(newIdx))) {\n        lineDraw.group.remove(itemEl);\n        return;\n    }\n\n    if (!itemEl) {\n        itemEl = new lineDraw._ctor(newLineData, newIdx, seriesScope);\n    }\n    else {\n        itemEl.updateData(newLineData, newIdx, seriesScope);\n    }\n\n    newLineData.setItemGraphicEl(newIdx, itemEl);\n\n    lineDraw.group.add(itemEl);\n}\n\nlineDrawProto.updateLayout = function () {\n    var lineData = this._lineData;\n\n    // Do not support update layout in incremental mode.\n    if (!lineData) {\n        return;\n    }\n\n    lineData.eachItemGraphicEl(function (el, idx) {\n        el.updateLayout(lineData, idx);\n    }, this);\n};\n\nlineDrawProto.incrementalPrepareUpdate = function (lineData) {\n    this._seriesScope = makeSeriesScope$1(lineData);\n    this._lineData = null;\n    this.group.removeAll();\n};\n\nlineDrawProto.incrementalUpdate = function (taskParams, lineData) {\n    function updateIncrementalAndHover(el) {\n        if (!el.isGroup) {\n            el.incremental = el.useHoverLayer = true;\n        }\n    }\n\n    for (var idx = taskParams.start; idx < taskParams.end; idx++) {\n        var itemLayout = lineData.getItemLayout(idx);\n\n        if (lineNeedsDraw(itemLayout)) {\n            var el = new this._ctor(lineData, idx, this._seriesScope);\n            el.traverse(updateIncrementalAndHover);\n\n            this.group.add(el);\n            lineData.setItemGraphicEl(idx, el);\n        }\n    }\n};\n\nfunction makeSeriesScope$1(lineData) {\n    var hostModel = lineData.hostModel;\n    return {\n        lineStyle: hostModel.getModel('lineStyle').getLineStyle(),\n        hoverLineStyle: hostModel.getModel('emphasis.lineStyle').getLineStyle(),\n        labelModel: hostModel.getModel('label'),\n        hoverLabelModel: hostModel.getModel('emphasis.label')\n    };\n}\n\nlineDrawProto.remove = function () {\n    this._clearIncremental();\n    this._incremental = null;\n    this.group.removeAll();\n};\n\nlineDrawProto._clearIncremental = function () {\n    var incremental = this._incremental;\n    if (incremental) {\n        incremental.clearDisplaybles();\n    }\n};\n\nfunction isPointNaN(pt) {\n    return isNaN(pt[0]) || isNaN(pt[1]);\n}\n\nfunction lineNeedsDraw(pts) {\n    return !isPointNaN(pts[0]) && !isPointNaN(pts[1]);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar v1 = [];\nvar v2 = [];\nvar v3 = [];\nvar quadraticAt$1 = quadraticAt;\nvar v2DistSquare = distSquare;\nvar mathAbs$1 = Math.abs;\nfunction intersectCurveCircle(curvePoints, center, radius) {\n    var p0 = curvePoints[0];\n    var p1 = curvePoints[1];\n    var p2 = curvePoints[2];\n\n    var d = Infinity;\n    var t;\n    var radiusSquare = radius * radius;\n    var interval = 0.1;\n\n    for (var _t = 0.1; _t <= 0.9; _t += 0.1) {\n        v1[0] = quadraticAt$1(p0[0], p1[0], p2[0], _t);\n        v1[1] = quadraticAt$1(p0[1], p1[1], p2[1], _t);\n        var diff = mathAbs$1(v2DistSquare(v1, center) - radiusSquare);\n        if (diff < d) {\n            d = diff;\n            t = _t;\n        }\n    }\n\n    // Assume the segment is monotone，Find root through Bisection method\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        // var prev = t - interval;\n        var next = t + interval;\n        // v1[0] = quadraticAt(p0[0], p1[0], p2[0], prev);\n        // v1[1] = quadraticAt(p0[1], p1[1], p2[1], prev);\n        v2[0] = quadraticAt$1(p0[0], p1[0], p2[0], t);\n        v2[1] = quadraticAt$1(p0[1], p1[1], p2[1], t);\n        v3[0] = quadraticAt$1(p0[0], p1[0], p2[0], next);\n        v3[1] = quadraticAt$1(p0[1], p1[1], p2[1], next);\n\n        var diff = v2DistSquare(v2, center) - radiusSquare;\n        if (mathAbs$1(diff) < 1e-2) {\n            break;\n        }\n\n        // var prevDiff = v2DistSquare(v1, center) - radiusSquare;\n        var nextDiff = v2DistSquare(v3, center) - radiusSquare;\n\n        interval /= 2;\n        if (diff < 0) {\n            if (nextDiff >= 0) {\n                t = t + interval;\n            }\n            else {\n                t = t - interval;\n            }\n        }\n        else {\n            if (nextDiff >= 0) {\n                t = t - interval;\n            }\n            else {\n                t = t + interval;\n            }\n        }\n    }\n\n    return t;\n}\n\n// Adjust edge to avoid\nvar adjustEdge = function (graph, scale$$1) {\n    var tmp0 = [];\n    var quadraticSubdivide$$1 = quadraticSubdivide;\n    var pts = [[], [], []];\n    var pts2 = [[], []];\n    var v = [];\n    scale$$1 /= 2;\n\n    function getSymbolSize(node) {\n        var symbolSize = node.getVisual('symbolSize');\n        if (symbolSize instanceof Array) {\n            symbolSize = (symbolSize[0] + symbolSize[1]) / 2;\n        }\n        return symbolSize;\n    }\n    graph.eachEdge(function (edge, idx) {\n        var linePoints = edge.getLayout();\n        var fromSymbol = edge.getVisual('fromSymbol');\n        var toSymbol = edge.getVisual('toSymbol');\n\n        if (!linePoints.__original) {\n            linePoints.__original = [\n                clone$1(linePoints[0]),\n                clone$1(linePoints[1])\n            ];\n            if (linePoints[2]) {\n                linePoints.__original.push(clone$1(linePoints[2]));\n            }\n        }\n        var originalPoints = linePoints.__original;\n        // Quadratic curve\n        if (linePoints[2] != null) {\n            copy(pts[0], originalPoints[0]);\n            copy(pts[1], originalPoints[2]);\n            copy(pts[2], originalPoints[1]);\n            if (fromSymbol && fromSymbol !== 'none') {\n                var symbolSize = getSymbolSize(edge.node1);\n\n                var t = intersectCurveCircle(pts, originalPoints[0], symbolSize * scale$$1);\n                // Subdivide and get the second\n                quadraticSubdivide$$1(pts[0][0], pts[1][0], pts[2][0], t, tmp0);\n                pts[0][0] = tmp0[3];\n                pts[1][0] = tmp0[4];\n                quadraticSubdivide$$1(pts[0][1], pts[1][1], pts[2][1], t, tmp0);\n                pts[0][1] = tmp0[3];\n                pts[1][1] = tmp0[4];\n            }\n            if (toSymbol && toSymbol !== 'none') {\n                var symbolSize = getSymbolSize(edge.node2);\n\n                var t = intersectCurveCircle(pts, originalPoints[1], symbolSize * scale$$1);\n                // Subdivide and get the first\n                quadraticSubdivide$$1(pts[0][0], pts[1][0], pts[2][0], t, tmp0);\n                pts[1][0] = tmp0[1];\n                pts[2][0] = tmp0[2];\n                quadraticSubdivide$$1(pts[0][1], pts[1][1], pts[2][1], t, tmp0);\n                pts[1][1] = tmp0[1];\n                pts[2][1] = tmp0[2];\n            }\n            // Copy back to layout\n            copy(linePoints[0], pts[0]);\n            copy(linePoints[1], pts[2]);\n            copy(linePoints[2], pts[1]);\n        }\n        // Line\n        else {\n            copy(pts2[0], originalPoints[0]);\n            copy(pts2[1], originalPoints[1]);\n\n            sub(v, pts2[1], pts2[0]);\n            normalize(v, v);\n            if (fromSymbol && fromSymbol !== 'none') {\n\n                var symbolSize = getSymbolSize(edge.node1);\n\n                scaleAndAdd(pts2[0], pts2[0], v, symbolSize * scale$$1);\n            }\n            if (toSymbol && toSymbol !== 'none') {\n                var symbolSize = getSymbolSize(edge.node2);\n\n                scaleAndAdd(pts2[1], pts2[1], v, -symbolSize * scale$$1);\n            }\n            copy(linePoints[0], pts2[0]);\n            copy(linePoints[1], pts2[1]);\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar FOCUS_ADJACENCY = '__focusNodeAdjacency';\nvar UNFOCUS_ADJACENCY = '__unfocusNodeAdjacency';\n\nvar nodeOpacityPath = ['itemStyle', 'opacity'];\nvar lineOpacityPath = ['lineStyle', 'opacity'];\n\nfunction getItemOpacity(item, opacityPath) {\n    return item.getVisual('opacity') || item.getModel().get(opacityPath);\n}\n\nfunction fadeOutItem(item, opacityPath, opacityRatio) {\n    var el = item.getGraphicEl();\n\n    var opacity = getItemOpacity(item, opacityPath);\n    if (opacityRatio != null) {\n        opacity == null && (opacity = 1);\n        opacity *= opacityRatio;\n    }\n\n    el.downplay && el.downplay();\n    el.traverse(function (child) {\n        if (child.type !== 'group') {\n            var opct = child.lineLabelOriginalOpacity;\n            if (opct == null || opacityRatio != null) {\n                opct = opacity;\n            }\n            child.setStyle('opacity', opct);\n        }\n    });\n}\n\nfunction fadeInItem(item, opacityPath) {\n    var opacity = getItemOpacity(item, opacityPath);\n    var el = item.getGraphicEl();\n\n    el.highlight && el.highlight();\n    el.traverse(function (child) {\n        if (child.type !== 'group') {\n            child.setStyle('opacity', opacity);\n        }\n    });\n}\n\nextendChartView({\n\n    type: 'graph',\n\n    init: function (ecModel, api) {\n        var symbolDraw = new SymbolDraw();\n        var lineDraw = new LineDraw();\n        var group = this.group;\n\n        this._controller = new RoamController(api.getZr());\n        this._controllerHost = {target: group};\n\n        group.add(symbolDraw.group);\n        group.add(lineDraw.group);\n\n        this._symbolDraw = symbolDraw;\n        this._lineDraw = lineDraw;\n\n        this._firstRender = true;\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n\n        this._model = seriesModel;\n        this._nodeScaleRatio = seriesModel.get('nodeScaleRatio');\n\n        var symbolDraw = this._symbolDraw;\n        var lineDraw = this._lineDraw;\n\n        var group = this.group;\n\n        if (coordSys.type === 'view') {\n            var groupNewProp = {\n                position: coordSys.position,\n                scale: coordSys.scale\n            };\n            if (this._firstRender) {\n                group.attr(groupNewProp);\n            }\n            else {\n                updateProps(group, groupNewProp, seriesModel);\n            }\n        }\n        // Fix edge contact point with node\n        adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel));\n\n        var data = seriesModel.getData();\n        symbolDraw.updateData(data);\n\n        var edgeData = seriesModel.getEdgeData();\n        lineDraw.updateData(edgeData);\n\n        this._updateNodeAndLinkScale();\n\n        this._updateController(seriesModel, ecModel, api);\n\n        clearTimeout(this._layoutTimeout);\n        var forceLayout = seriesModel.forceLayout;\n        var layoutAnimation = seriesModel.get('force.layoutAnimation');\n        if (forceLayout) {\n            this._startForceLayoutIteration(forceLayout, layoutAnimation);\n        }\n\n        data.eachItemGraphicEl(function (el, idx) {\n            var itemModel = data.getItemModel(idx);\n            // Update draggable\n            el.off('drag').off('dragend');\n            var draggable = itemModel.get('draggable');\n            if (draggable) {\n                el.on('drag', function () {\n                    if (forceLayout) {\n                        forceLayout.warmUp();\n                        !this._layouting\n                            && this._startForceLayoutIteration(forceLayout, layoutAnimation);\n                        forceLayout.setFixed(idx);\n                        // Write position back to layout\n                        data.setItemLayout(idx, el.position);\n                    }\n                }, this).on('dragend', function () {\n                    if (forceLayout) {\n                        forceLayout.setUnfixed(idx);\n                    }\n                }, this);\n            }\n            el.setDraggable(draggable && forceLayout);\n\n            el[FOCUS_ADJACENCY] && el.off('mouseover', el[FOCUS_ADJACENCY]);\n            el[UNFOCUS_ADJACENCY] && el.off('mouseout', el[UNFOCUS_ADJACENCY]);\n\n            if (itemModel.get('focusNodeAdjacency')) {\n                el.on('mouseover', el[FOCUS_ADJACENCY] = function () {\n                    api.dispatchAction({\n                        type: 'focusNodeAdjacency',\n                        seriesId: seriesModel.id,\n                        dataIndex: el.dataIndex\n                    });\n                });\n                el.on('mouseout', el[UNFOCUS_ADJACENCY] = function () {\n                    api.dispatchAction({\n                        type: 'unfocusNodeAdjacency',\n                        seriesId: seriesModel.id\n                    });\n                });\n            }\n\n        }, this);\n\n        data.graph.eachEdge(function (edge) {\n            var el = edge.getGraphicEl();\n\n            el[FOCUS_ADJACENCY] && el.off('mouseover', el[FOCUS_ADJACENCY]);\n            el[UNFOCUS_ADJACENCY] && el.off('mouseout', el[UNFOCUS_ADJACENCY]);\n\n            if (edge.getModel().get('focusNodeAdjacency')) {\n                el.on('mouseover', el[FOCUS_ADJACENCY] = function () {\n                    api.dispatchAction({\n                        type: 'focusNodeAdjacency',\n                        seriesId: seriesModel.id,\n                        edgeDataIndex: edge.dataIndex\n                    });\n                });\n                el.on('mouseout', el[UNFOCUS_ADJACENCY] = function () {\n                    api.dispatchAction({\n                        type: 'unfocusNodeAdjacency',\n                        seriesId: seriesModel.id\n                    });\n                });\n            }\n        });\n\n        var circularRotateLabel = seriesModel.get('layout') === 'circular'\n            && seriesModel.get('circular.rotateLabel');\n        var cx = data.getLayout('cx');\n        var cy = data.getLayout('cy');\n        data.eachItemGraphicEl(function (el, idx) {\n            var symbolPath = el.getSymbolPath();\n            if (circularRotateLabel) {\n                var pos = data.getItemLayout(idx);\n                var rad = Math.atan2(pos[1] - cy, pos[0] - cx);\n                if (rad < 0) {\n                    rad = Math.PI * 2 + rad;\n                }\n                var isLeft = pos[0] < cx;\n                if (isLeft) {\n                    rad = rad - Math.PI;\n                }\n                var textPosition = isLeft ? 'left' : 'right';\n                symbolPath.setStyle({\n                    textRotation: -rad,\n                    textPosition: textPosition,\n                    textOrigin: 'center'\n                });\n                symbolPath.hoverStyle && (symbolPath.hoverStyle.textPosition = textPosition);\n            }\n            else {\n                symbolPath.setStyle({\n                    textRotation: 0\n                });\n            }\n        });\n\n        this._firstRender = false;\n    },\n\n    dispose: function () {\n        this._controller && this._controller.dispose();\n        this._controllerHost = {};\n    },\n\n    focusNodeAdjacency: function (seriesModel, ecModel, api, payload) {\n        var data = this._model.getData();\n        var graph = data.graph;\n        var dataIndex = payload.dataIndex;\n        var edgeDataIndex = payload.edgeDataIndex;\n\n        var node = graph.getNodeByIndex(dataIndex);\n        var edge = graph.getEdgeByIndex(edgeDataIndex);\n\n        if (!node && !edge) {\n            return;\n        }\n\n        graph.eachNode(function (node) {\n            fadeOutItem(node, nodeOpacityPath, 0.1);\n        });\n        graph.eachEdge(function (edge) {\n            fadeOutItem(edge, lineOpacityPath, 0.1);\n        });\n\n        if (node) {\n            fadeInItem(node, nodeOpacityPath);\n            each$1(node.edges, function (adjacentEdge) {\n                if (adjacentEdge.dataIndex < 0) {\n                    return;\n                }\n                fadeInItem(adjacentEdge, lineOpacityPath);\n                fadeInItem(adjacentEdge.node1, nodeOpacityPath);\n                fadeInItem(adjacentEdge.node2, nodeOpacityPath);\n            });\n        }\n        if (edge) {\n            fadeInItem(edge, lineOpacityPath);\n            fadeInItem(edge.node1, nodeOpacityPath);\n            fadeInItem(edge.node2, nodeOpacityPath);\n        }\n    },\n\n    unfocusNodeAdjacency: function (seriesModel, ecModel, api, payload) {\n        var graph = this._model.getData().graph;\n\n        graph.eachNode(function (node) {\n            fadeOutItem(node, nodeOpacityPath);\n        });\n        graph.eachEdge(function (edge) {\n            fadeOutItem(edge, lineOpacityPath);\n        });\n    },\n\n    _startForceLayoutIteration: function (forceLayout, layoutAnimation) {\n        var self = this;\n        (function step() {\n            forceLayout.step(function (stopped) {\n                self.updateLayout(self._model);\n                (self._layouting = !stopped) && (\n                    layoutAnimation\n                        ? (self._layoutTimeout = setTimeout(step, 16))\n                        : step()\n                );\n            });\n        })();\n    },\n\n    _updateController: function (seriesModel, ecModel, api) {\n        var controller = this._controller;\n        var controllerHost = this._controllerHost;\n        var group = this.group;\n\n        controller.setPointerChecker(function (e, x, y) {\n            var rect = group.getBoundingRect();\n            rect.applyTransform(group.transform);\n            return rect.contain(x, y)\n                && !onIrrelevantElement(e, api, seriesModel);\n        });\n\n        if (seriesModel.coordinateSystem.type !== 'view') {\n            controller.disable();\n            return;\n        }\n        controller.enable(seriesModel.get('roam'));\n        controllerHost.zoomLimit = seriesModel.get('scaleLimit');\n        controllerHost.zoom = seriesModel.coordinateSystem.getZoom();\n\n        controller\n            .off('pan')\n            .off('zoom')\n            .on('pan', function (e) {\n                updateViewOnPan(controllerHost, e.dx, e.dy);\n                api.dispatchAction({\n                    seriesId: seriesModel.id,\n                    type: 'graphRoam',\n                    dx: e.dx,\n                    dy: e.dy\n                });\n            })\n            .on('zoom', function (e) {\n                updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY);\n                api.dispatchAction({\n                    seriesId: seriesModel.id,\n                    type: 'graphRoam',\n                    zoom: e.scale,\n                    originX: e.originX,\n                    originY: e.originY\n                });\n                this._updateNodeAndLinkScale();\n                adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel));\n                this._lineDraw.updateLayout();\n            }, this);\n    },\n\n    _updateNodeAndLinkScale: function () {\n        var seriesModel = this._model;\n        var data = seriesModel.getData();\n\n        var nodeScale = this._getNodeGlobalScale(seriesModel);\n        var invScale = [nodeScale, nodeScale];\n\n        data.eachItemGraphicEl(function (el, idx) {\n            el.attr('scale', invScale);\n        });\n    },\n\n    _getNodeGlobalScale: function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys.type !== 'view') {\n            return 1;\n        }\n\n        var nodeScaleRatio = this._nodeScaleRatio;\n\n        var groupScale = coordSys.scale;\n        var groupZoom = (groupScale && groupScale[0]) || 1;\n        // Scale node when zoom changes\n        var roamZoom = coordSys.getZoom();\n        var nodeScale = (roamZoom - 1) * nodeScaleRatio + 1;\n\n        return nodeScale / groupZoom;\n    },\n\n    updateLayout: function (seriesModel) {\n        adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel));\n\n        this._symbolDraw.updateLayout();\n        this._lineDraw.updateLayout();\n    },\n\n    remove: function (ecModel, api) {\n        this._symbolDraw && this._symbolDraw.remove();\n        this._lineDraw && this._lineDraw.remove();\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @payload\n * @property {number} [seriesIndex]\n * @property {string} [seriesId]\n * @property {string} [seriesName]\n * @property {number} [dataIndex]\n */\nregisterAction({\n    type: 'focusNodeAdjacency',\n    event: 'focusNodeAdjacency',\n    update: 'series:focusNodeAdjacency'\n}, function () {});\n\n/**\n * @payload\n * @property {number} [seriesIndex]\n * @property {string} [seriesId]\n * @property {string} [seriesName]\n */\nregisterAction({\n    type: 'unfocusNodeAdjacency',\n    event: 'unfocusNodeAdjacency',\n    update: 'series:unfocusNodeAdjacency'\n}, function () {});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar actionInfo = {\n    type: 'graphRoam',\n    event: 'graphRoam',\n    update: 'none'\n};\n\n/**\n * @payload\n * @property {string} name Series name\n * @property {number} [dx]\n * @property {number} [dy]\n * @property {number} [zoom]\n * @property {number} [originX]\n * @property {number} [originY]\n */\nregisterAction(actionInfo, function (payload, ecModel) {\n    ecModel.eachComponent({mainType: 'series', query: payload}, function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n\n        var res = updateCenterAndZoom(coordSys, payload);\n\n        seriesModel.setCenter\n            && seriesModel.setCenter(res.center);\n\n        seriesModel.setZoom\n            && seriesModel.setZoom(res.zoom);\n    });\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar categoryFilter = function (ecModel) {\n    var legendModels = ecModel.findComponents({\n        mainType: 'legend'\n    });\n    if (!legendModels || !legendModels.length) {\n        return;\n    }\n    ecModel.eachSeriesByType('graph', function (graphSeries) {\n        var categoriesData = graphSeries.getCategoriesData();\n        var graph = graphSeries.getGraph();\n        var data = graph.data;\n\n        var categoryNames = categoriesData.mapArray(categoriesData.getName);\n\n        data.filterSelf(function (idx) {\n            var model = data.getItemModel(idx);\n            var category = model.getShallow('category');\n            if (category != null) {\n                if (typeof category === 'number') {\n                    category = categoryNames[category];\n                }\n                // If in any legend component the status is not selected.\n                for (var i = 0; i < legendModels.length; i++) {\n                    if (!legendModels[i].isSelected(category)) {\n                        return false;\n                    }\n                }\n            }\n            return true;\n        });\n    }, this);\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar categoryVisual = function (ecModel) {\n\n    var paletteScope = {};\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        var categoriesData = seriesModel.getCategoriesData();\n        var data = seriesModel.getData();\n\n        var categoryNameIdxMap = {};\n\n        categoriesData.each(function (idx) {\n            var name = categoriesData.getName(idx);\n            // Add prefix to avoid conflict with Object.prototype.\n            categoryNameIdxMap['ec-' + name] = idx;\n\n            var itemModel = categoriesData.getItemModel(idx);\n            var color = itemModel.get('itemStyle.color')\n                || seriesModel.getColorFromPalette(name, paletteScope);\n            categoriesData.setItemVisual(idx, 'color', color);\n        });\n\n        // Assign category color to visual\n        if (categoriesData.count()) {\n            data.each(function (idx) {\n                var model = data.getItemModel(idx);\n                var category = model.getShallow('category');\n                if (category != null) {\n                    if (typeof category === 'string') {\n                        category = categoryNameIdxMap['ec-' + category];\n                    }\n                    if (!data.getItemVisual(idx, 'color', true)) {\n                        data.setItemVisual(\n                            idx, 'color',\n                            categoriesData.getItemVisual(category, 'color')\n                        );\n                    }\n                }\n            });\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction normalize$1(a) {\n    if (!(a instanceof Array)) {\n        a = [a, a];\n    }\n    return a;\n}\n\nvar edgeVisual = function (ecModel) {\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        var graph = seriesModel.getGraph();\n        var edgeData = seriesModel.getEdgeData();\n        var symbolType = normalize$1(seriesModel.get('edgeSymbol'));\n        var symbolSize = normalize$1(seriesModel.get('edgeSymbolSize'));\n\n        var colorQuery = 'lineStyle.color'.split('.');\n        var opacityQuery = 'lineStyle.opacity'.split('.');\n\n        edgeData.setVisual('fromSymbol', symbolType && symbolType[0]);\n        edgeData.setVisual('toSymbol', symbolType && symbolType[1]);\n        edgeData.setVisual('fromSymbolSize', symbolSize && symbolSize[0]);\n        edgeData.setVisual('toSymbolSize', symbolSize && symbolSize[1]);\n        edgeData.setVisual('color', seriesModel.get(colorQuery));\n        edgeData.setVisual('opacity', seriesModel.get(opacityQuery));\n\n        edgeData.each(function (idx) {\n            var itemModel = edgeData.getItemModel(idx);\n            var edge = graph.getEdgeByIndex(idx);\n            var symbolType = normalize$1(itemModel.getShallow('symbol', true));\n            var symbolSize = normalize$1(itemModel.getShallow('symbolSize', true));\n            // Edge visual must after node visual\n            var color = itemModel.get(colorQuery);\n            var opacity = itemModel.get(opacityQuery);\n            switch (color) {\n                case 'source':\n                    color = edge.node1.getVisual('color');\n                    break;\n                case 'target':\n                    color = edge.node2.getVisual('color');\n                    break;\n            }\n\n            symbolType[0] && edge.setVisual('fromSymbol', symbolType[0]);\n            symbolType[1] && edge.setVisual('toSymbol', symbolType[1]);\n            symbolSize[0] && edge.setVisual('fromSymbolSize', symbolSize[0]);\n            symbolSize[1] && edge.setVisual('toSymbolSize', symbolSize[1]);\n\n            edge.setVisual('color', color);\n            edge.setVisual('opacity', opacity);\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction simpleLayout$1(seriesModel) {\n    var coordSys = seriesModel.coordinateSystem;\n    if (coordSys && coordSys.type !== 'view') {\n        return;\n    }\n    var graph = seriesModel.getGraph();\n\n    graph.eachNode(function (node) {\n        var model = node.getModel();\n        node.setLayout([+model.get('x'), +model.get('y')]);\n    });\n\n    simpleLayoutEdge(graph);\n}\n\nfunction simpleLayoutEdge(graph) {\n    graph.eachEdge(function (edge) {\n        var curveness = edge.getModel().get('lineStyle.curveness') || 0;\n        var p1 = clone$1(edge.node1.getLayout());\n        var p2 = clone$1(edge.node2.getLayout());\n        var points = [p1, p2];\n        if (+curveness) {\n            points.push([\n                (p1[0] + p2[0]) / 2 - (p1[1] - p2[1]) * curveness,\n                (p1[1] + p2[1]) / 2 - (p2[0] - p1[0]) * curveness\n            ]);\n        }\n        edge.setLayout(points);\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar simpleLayout = function (ecModel, api) {\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        var layout = seriesModel.get('layout');\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys && coordSys.type !== 'view') {\n            var data = seriesModel.getData();\n\n            var dimensions = [];\n            each$1(coordSys.dimensions, function (coordDim) {\n                dimensions = dimensions.concat(data.mapDimension(coordDim, true));\n            });\n\n            for (var dataIndex = 0; dataIndex < data.count(); dataIndex++) {\n                var value = [];\n                var hasValue = false;\n                for (var i = 0; i < dimensions.length; i++) {\n                    var val = data.get(dimensions[i], dataIndex);\n                    if (!isNaN(val)) {\n                        hasValue = true;\n                    }\n                    value.push(val);\n                }\n                if (hasValue) {\n                    data.setItemLayout(dataIndex, coordSys.dataToPoint(value));\n                }\n                else {\n                    // Also {Array.<number>}, not undefined to avoid if...else... statement\n                    data.setItemLayout(dataIndex, [NaN, NaN]);\n                }\n            }\n\n            simpleLayoutEdge(data.graph);\n        }\n        else if (!layout || layout === 'none') {\n            simpleLayout$1(seriesModel);\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction circularLayout$1(seriesModel) {\n    var coordSys = seriesModel.coordinateSystem;\n    if (coordSys && coordSys.type !== 'view') {\n        return;\n    }\n\n    var rect = coordSys.getBoundingRect();\n\n    var nodeData = seriesModel.getData();\n    var graph = nodeData.graph;\n\n    var angle = 0;\n    var sum = nodeData.getSum('value');\n    var unitAngle = Math.PI * 2 / (sum || nodeData.count());\n\n    var cx = rect.width / 2 + rect.x;\n    var cy = rect.height / 2 + rect.y;\n\n    var r = Math.min(rect.width, rect.height) / 2;\n\n    graph.eachNode(function (node) {\n        var value = node.getValue('value');\n\n        angle += unitAngle * (sum ? value : 1) / 2;\n\n        node.setLayout([\n            r * Math.cos(angle) + cx,\n            r * Math.sin(angle) + cy\n        ]);\n\n        angle += unitAngle * (sum ? value : 1) / 2;\n    });\n\n    nodeData.setLayout({\n        cx: cx,\n        cy: cy\n    });\n\n    graph.eachEdge(function (edge) {\n        var curveness = edge.getModel().get('lineStyle.curveness') || 0;\n        var p1 = clone$1(edge.node1.getLayout());\n        var p2 = clone$1(edge.node2.getLayout());\n        var cp1;\n        var x12 = (p1[0] + p2[0]) / 2;\n        var y12 = (p1[1] + p2[1]) / 2;\n        if (+curveness) {\n            curveness *= 3;\n            cp1 = [\n                cx * curveness + x12 * (1 - curveness),\n                cy * curveness + y12 * (1 - curveness)\n            ];\n        }\n        edge.setLayout([p1, p2, cp1]);\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar circularLayout = function (ecModel) {\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        if (seriesModel.get('layout') === 'circular') {\n            circularLayout$1(seriesModel);\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* Some formulas were originally copied from \"d3.js\" with some\n* modifications made for this project.\n* (See more details in the comment of the method \"step\" below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\nvar scaleAndAdd$2 = scaleAndAdd;\n\n// function adjacentNode(n, e) {\n//     return e.n1 === n ? e.n2 : e.n1;\n// }\n\nfunction forceLayout$1(nodes, edges, opts) {\n    var rect = opts.rect;\n    var width = rect.width;\n    var height = rect.height;\n    var center = [rect.x + width / 2, rect.y + height / 2];\n    // var scale = opts.scale || 1;\n    var gravity = opts.gravity == null ? 0.1 : opts.gravity;\n\n    // for (var i = 0; i < edges.length; i++) {\n    //     var e = edges[i];\n    //     var n1 = e.n1;\n    //     var n2 = e.n2;\n    //     n1.edges = n1.edges || [];\n    //     n2.edges = n2.edges || [];\n    //     n1.edges.push(e);\n    //     n2.edges.push(e);\n    // }\n    // Init position\n    for (var i = 0; i < nodes.length; i++) {\n        var n = nodes[i];\n        if (!n.p) {\n            n.p = create(\n                width * (Math.random() - 0.5) + center[0],\n                height * (Math.random() - 0.5) + center[1]\n            );\n        }\n        n.pp = clone$1(n.p);\n        n.edges = null;\n    }\n\n    // Formula in 'Graph Drawing by Force-directed Placement'\n    // var k = scale * Math.sqrt(width * height / nodes.length);\n    // var k2 = k * k;\n\n    var friction = 0.6;\n\n    return {\n        warmUp: function () {\n            friction = 0.5;\n        },\n\n        setFixed: function (idx) {\n            nodes[idx].fixed = true;\n        },\n\n        setUnfixed: function (idx) {\n            nodes[idx].fixed = false;\n        },\n\n        /**\n         * Some formulas were originally copied from \"d3.js\"\n         * https://github.com/d3/d3/blob/b516d77fb8566b576088e73410437494717ada26/src/layout/force.js\n         * with some modifications made for this project.\n         * See the license statement at the head of this file.\n         */\n        step: function (cb) {\n            var v12 = [];\n            var nLen = nodes.length;\n            for (var i = 0; i < edges.length; i++) {\n                var e = edges[i];\n                var n1 = e.n1;\n                var n2 = e.n2;\n\n                sub(v12, n2.p, n1.p);\n                var d = len(v12) - e.d;\n                var w = n2.w / (n1.w + n2.w);\n\n                if (isNaN(w)) {\n                    w = 0;\n                }\n\n                normalize(v12, v12);\n\n                !n1.fixed && scaleAndAdd$2(n1.p, n1.p, v12, w * d * friction);\n                !n2.fixed && scaleAndAdd$2(n2.p, n2.p, v12, -(1 - w) * d * friction);\n            }\n            // Gravity\n            for (var i = 0; i < nLen; i++) {\n                var n = nodes[i];\n                if (!n.fixed) {\n                    sub(v12, center, n.p);\n                    // var d = vec2.len(v12);\n                    // vec2.scale(v12, v12, 1 / d);\n                    // var gravityFactor = gravity;\n                    scaleAndAdd$2(n.p, n.p, v12, gravity * friction);\n                }\n            }\n\n            // Repulsive\n            // PENDING\n            for (var i = 0; i < nLen; i++) {\n                var n1 = nodes[i];\n                for (var j = i + 1; j < nLen; j++) {\n                    var n2 = nodes[j];\n                    sub(v12, n2.p, n1.p);\n                    var d = len(v12);\n                    if (d === 0) {\n                        // Random repulse\n                        set(v12, Math.random() - 0.5, Math.random() - 0.5);\n                        d = 1;\n                    }\n                    var repFact = (n1.rep + n2.rep) / d / d;\n                    !n1.fixed && scaleAndAdd$2(n1.pp, n1.pp, v12, repFact);\n                    !n2.fixed && scaleAndAdd$2(n2.pp, n2.pp, v12, -repFact);\n                }\n            }\n            var v = [];\n            for (var i = 0; i < nLen; i++) {\n                var n = nodes[i];\n                if (!n.fixed) {\n                    sub(v, n.p, n.pp);\n                    scaleAndAdd$2(n.p, n.p, v, friction);\n                    copy(n.pp, n.p);\n                }\n            }\n\n            friction = friction * 0.992;\n\n            cb && cb(nodes, edges, friction < 0.01);\n        }\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar forceLayout = function (ecModel) {\n    ecModel.eachSeriesByType('graph', function (graphSeries) {\n        var coordSys = graphSeries.coordinateSystem;\n        if (coordSys && coordSys.type !== 'view') {\n            return;\n        }\n        if (graphSeries.get('layout') === 'force') {\n            var preservedPoints = graphSeries.preservedPoints || {};\n            var graph = graphSeries.getGraph();\n            var nodeData = graph.data;\n            var edgeData = graph.edgeData;\n            var forceModel = graphSeries.getModel('force');\n            var initLayout = forceModel.get('initLayout');\n            if (graphSeries.preservedPoints) {\n                nodeData.each(function (idx) {\n                    var id = nodeData.getId(idx);\n                    nodeData.setItemLayout(idx, preservedPoints[id] || [NaN, NaN]);\n                });\n            }\n            else if (!initLayout || initLayout === 'none') {\n                simpleLayout$1(graphSeries);\n            }\n            else if (initLayout === 'circular') {\n                circularLayout$1(graphSeries);\n            }\n\n            var nodeDataExtent = nodeData.getDataExtent('value');\n            var edgeDataExtent = edgeData.getDataExtent('value');\n            // var edgeDataExtent = edgeData.getDataExtent('value');\n            var repulsion = forceModel.get('repulsion');\n            var edgeLength = forceModel.get('edgeLength');\n            if (!isArray(repulsion)) {\n                repulsion = [repulsion, repulsion];\n            }\n            if (!isArray(edgeLength)) {\n                edgeLength = [edgeLength, edgeLength];\n            }\n            // Larger value has smaller length\n            edgeLength = [edgeLength[1], edgeLength[0]];\n\n            var nodes = nodeData.mapArray('value', function (value, idx) {\n                var point = nodeData.getItemLayout(idx);\n                var rep = linearMap(value, nodeDataExtent, repulsion);\n                if (isNaN(rep)) {\n                    rep = (repulsion[0] + repulsion[1]) / 2;\n                }\n                return {\n                    w: rep,\n                    rep: rep,\n                    fixed: nodeData.getItemModel(idx).get('fixed'),\n                    p: (!point || isNaN(point[0]) || isNaN(point[1])) ? null : point\n                };\n            });\n            var edges = edgeData.mapArray('value', function (value, idx) {\n                var edge = graph.getEdgeByIndex(idx);\n                var d = linearMap(value, edgeDataExtent, edgeLength);\n                if (isNaN(d)) {\n                    d = (edgeLength[0] + edgeLength[1]) / 2;\n                }\n                return {\n                    n1: nodes[edge.node1.dataIndex],\n                    n2: nodes[edge.node2.dataIndex],\n                    d: d,\n                    curveness: edge.getModel().get('lineStyle.curveness') || 0\n                };\n            });\n\n            var coordSys = graphSeries.coordinateSystem;\n            var rect = coordSys.getBoundingRect();\n            var forceInstance = forceLayout$1(nodes, edges, {\n                rect: rect,\n                gravity: forceModel.get('gravity')\n            });\n            var oldStep = forceInstance.step;\n            forceInstance.step = function (cb) {\n                for (var i = 0, l = nodes.length; i < l; i++) {\n                    if (nodes[i].fixed) {\n                        // Write back to layout instance\n                        copy(nodes[i].p, graph.getNodeByIndex(i).getLayout());\n                    }\n                }\n                oldStep(function (nodes, edges, stopped) {\n                    for (var i = 0, l = nodes.length; i < l; i++) {\n                        if (!nodes[i].fixed) {\n                            graph.getNodeByIndex(i).setLayout(nodes[i].p);\n                        }\n                        preservedPoints[nodeData.getId(i)] = nodes[i].p;\n                    }\n                    for (var i = 0, l = edges.length; i < l; i++) {\n                        var e = edges[i];\n                        var edge = graph.getEdgeByIndex(i);\n                        var p1 = e.n1.p;\n                        var p2 = e.n2.p;\n                        var points = edge.getLayout();\n                        points = points ? points.slice() : [];\n                        points[0] = points[0] || [];\n                        points[1] = points[1] || [];\n                        copy(points[0], p1);\n                        copy(points[1], p2);\n                        if (+e.curveness) {\n                            points[2] = [\n                                (p1[0] + p2[0]) / 2 - (p1[1] - p2[1]) * e.curveness,\n                                (p1[1] + p2[1]) / 2 - (p2[0] - p1[0]) * e.curveness\n                            ];\n                        }\n                        edge.setLayout(points);\n                    }\n                    // Update layout\n\n                    cb && cb(stopped);\n                });\n            };\n            graphSeries.forceLayout = forceInstance;\n            graphSeries.preservedPoints = preservedPoints;\n\n            // Step to get the layout\n            forceInstance.step();\n        }\n        else {\n            // Remove prev injected forceLayout instance\n            graphSeries.forceLayout = null;\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME Where to create the simple view coordinate system\nfunction getViewRect$1(seriesModel, api, aspect) {\n    var option = seriesModel.getBoxLayoutParams();\n    option.aspect = aspect;\n    return getLayoutRect(option, {\n        width: api.getWidth(),\n        height: api.getHeight()\n    });\n}\n\nvar createView = function (ecModel, api) {\n    var viewList = [];\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        var coordSysType = seriesModel.get('coordinateSystem');\n        if (!coordSysType || coordSysType === 'view') {\n\n            var data = seriesModel.getData();\n            var positions = data.mapArray(function (idx) {\n                var itemModel = data.getItemModel(idx);\n                return [+itemModel.get('x'), +itemModel.get('y')];\n            });\n\n            var min = [];\n            var max = [];\n\n            fromPoints(positions, min, max);\n\n            // If width or height is 0\n            if (max[0] - min[0] === 0) {\n                max[0] += 1;\n                min[0] -= 1;\n            }\n            if (max[1] - min[1] === 0) {\n                max[1] += 1;\n                min[1] -= 1;\n            }\n            var aspect = (max[0] - min[0]) / (max[1] - min[1]);\n            // FIXME If get view rect after data processed?\n            var viewRect = getViewRect$1(seriesModel, api, aspect);\n            // Position may be NaN, use view rect instead\n            if (isNaN(aspect)) {\n                min = [viewRect.x, viewRect.y];\n                max = [viewRect.x + viewRect.width, viewRect.y + viewRect.height];\n            }\n\n            var bbWidth = max[0] - min[0];\n            var bbHeight = max[1] - min[1];\n\n            var viewWidth = viewRect.width;\n            var viewHeight = viewRect.height;\n\n            var viewCoordSys = seriesModel.coordinateSystem = new View();\n            viewCoordSys.zoomLimit = seriesModel.get('scaleLimit');\n\n            viewCoordSys.setBoundingRect(\n                min[0], min[1], bbWidth, bbHeight\n            );\n            viewCoordSys.setViewRect(\n                viewRect.x, viewRect.y, viewWidth, viewHeight\n            );\n\n            // Update roam info\n            viewCoordSys.setCenter(seriesModel.get('center'));\n            viewCoordSys.setZoom(seriesModel.get('zoom'));\n\n            viewList.push(viewCoordSys);\n        }\n    });\n\n    return viewList;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterProcessor(categoryFilter);\n\nregisterVisual(visualSymbol('graph', 'circle', null));\nregisterVisual(categoryVisual);\nregisterVisual(edgeVisual);\n\nregisterLayout(simpleLayout);\nregisterLayout(circularLayout);\nregisterLayout(forceLayout);\n\n// Graph view coordinate system\nregisterCoordinateSystem('graphView', {\n    create: createView\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar GaugeSeries = SeriesModel.extend({\n\n    type: 'series.gauge',\n\n    getInitialData: function (option, ecModel) {\n        var dataOpt = option.data || [];\n        if (!isArray(dataOpt)) {\n            dataOpt = [dataOpt];\n        }\n        option.data = dataOpt;\n        return createListSimply(this, ['value']);\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        // 默认全局居中\n        center: ['50%', '50%'],\n        legendHoverLink: true,\n        radius: '75%',\n        startAngle: 225,\n        endAngle: -45,\n        clockwise: true,\n        // 最小值\n        min: 0,\n        // 最大值\n        max: 100,\n        // 分割段数，默认为10\n        splitNumber: 10,\n        // 坐标轴线\n        axisLine: {\n            // 默认显示，属性show控制显示与否\n            show: true,\n            lineStyle: {       // 属性lineStyle控制线条样式\n                color: [[0.2, '#91c7ae'], [0.8, '#63869e'], [1, '#c23531']],\n                width: 30\n            }\n        },\n        // 分隔线\n        splitLine: {\n            // 默认显示，属性show控制显示与否\n            show: true,\n            // 属性length控制线长\n            length: 30,\n            // 属性lineStyle（详见lineStyle）控制线条样式\n            lineStyle: {\n                color: '#eee',\n                width: 2,\n                type: 'solid'\n            }\n        },\n        // 坐标轴小标记\n        axisTick: {\n            // 属性show控制显示与否，默认不显示\n            show: true,\n            // 每份split细分多少段\n            splitNumber: 5,\n            // 属性length控制线长\n            length: 8,\n            // 属性lineStyle控制线条样式\n            lineStyle: {\n                color: '#eee',\n                width: 1,\n                type: 'solid'\n            }\n        },\n        axisLabel: {\n            show: true,\n            distance: 5,\n            // formatter: null,\n            color: 'auto'\n        },\n        pointer: {\n            show: true,\n            length: '80%',\n            width: 8\n        },\n        itemStyle: {\n            color: 'auto'\n        },\n        title: {\n            show: true,\n            // x, y，单位px\n            offsetCenter: [0, '-40%'],\n            // 其余属性默认使用全局文本样式，详见TEXTSTYLE\n            color: '#333',\n            fontSize: 15\n        },\n        detail: {\n            show: true,\n            backgroundColor: 'rgba(0,0,0,0)',\n            borderWidth: 0,\n            borderColor: '#ccc',\n            width: 100,\n            height: null, // self-adaption\n            padding: [5, 10],\n            // x, y，单位px\n            offsetCenter: [0, '40%'],\n            // formatter: null,\n            // 其余属性默认使用全局文本样式，详见TEXTSTYLE\n            color: 'auto',\n            fontSize: 30\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PointerPath = Path.extend({\n\n    type: 'echartsGaugePointer',\n\n    shape: {\n        angle: 0,\n\n        width: 10,\n\n        r: 10,\n\n        x: 0,\n\n        y: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var mathCos = Math.cos;\n        var mathSin = Math.sin;\n\n        var r = shape.r;\n        var width = shape.width;\n        var angle = shape.angle;\n        var x = shape.x - mathCos(angle) * width * (width >= r / 3 ? 1 : 2);\n        var y = shape.y - mathSin(angle) * width * (width >= r / 3 ? 1 : 2);\n\n        angle = shape.angle - Math.PI / 2;\n        ctx.moveTo(x, y);\n        ctx.lineTo(\n            shape.x + mathCos(angle) * width,\n            shape.y + mathSin(angle) * width\n        );\n        ctx.lineTo(\n            shape.x + mathCos(shape.angle) * r,\n            shape.y + mathSin(shape.angle) * r\n        );\n        ctx.lineTo(\n            shape.x - mathCos(angle) * width,\n            shape.y - mathSin(angle) * width\n        );\n        ctx.lineTo(x, y);\n        return;\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction parsePosition(seriesModel, api) {\n    var center = seriesModel.get('center');\n    var width = api.getWidth();\n    var height = api.getHeight();\n    var size = Math.min(width, height);\n    var cx = parsePercent$1(center[0], api.getWidth());\n    var cy = parsePercent$1(center[1], api.getHeight());\n    var r = parsePercent$1(seriesModel.get('radius'), size / 2);\n\n    return {\n        cx: cx,\n        cy: cy,\n        r: r\n    };\n}\n\nfunction formatLabel(label, labelFormatter) {\n    if (labelFormatter) {\n        if (typeof labelFormatter === 'string') {\n            label = labelFormatter.replace('{value}', label != null ? label : '');\n        }\n        else if (typeof labelFormatter === 'function') {\n            label = labelFormatter(label);\n        }\n    }\n\n    return label;\n}\n\nvar PI2$5 = Math.PI * 2;\n\nvar GaugeView = Chart.extend({\n\n    type: 'gauge',\n\n    render: function (seriesModel, ecModel, api) {\n\n        this.group.removeAll();\n\n        var colorList = seriesModel.get('axisLine.lineStyle.color');\n        var posInfo = parsePosition(seriesModel, api);\n\n        this._renderMain(\n            seriesModel, ecModel, api, colorList, posInfo\n        );\n    },\n\n    dispose: function () {},\n\n    _renderMain: function (seriesModel, ecModel, api, colorList, posInfo) {\n        var group = this.group;\n\n        var axisLineModel = seriesModel.getModel('axisLine');\n        var lineStyleModel = axisLineModel.getModel('lineStyle');\n\n        var clockwise = seriesModel.get('clockwise');\n        var startAngle = -seriesModel.get('startAngle') / 180 * Math.PI;\n        var endAngle = -seriesModel.get('endAngle') / 180 * Math.PI;\n\n        var angleRangeSpan = (endAngle - startAngle) % PI2$5;\n\n        var prevEndAngle = startAngle;\n        var axisLineWidth = lineStyleModel.get('width');\n\n        for (var i = 0; i < colorList.length; i++) {\n            // Clamp\n            var percent = Math.min(Math.max(colorList[i][0], 0), 1);\n            var endAngle = startAngle + angleRangeSpan * percent;\n            var sector = new Sector({\n                shape: {\n                    startAngle: prevEndAngle,\n                    endAngle: endAngle,\n                    cx: posInfo.cx,\n                    cy: posInfo.cy,\n                    clockwise: clockwise,\n                    r0: posInfo.r - axisLineWidth,\n                    r: posInfo.r\n                },\n                silent: true\n            });\n\n            sector.setStyle({\n                fill: colorList[i][1]\n            });\n\n            sector.setStyle(lineStyleModel.getLineStyle(\n                // Because we use sector to simulate arc\n                // so the properties for stroking are useless\n                ['color', 'borderWidth', 'borderColor']\n            ));\n\n            group.add(sector);\n\n            prevEndAngle = endAngle;\n        }\n\n        var getColor = function (percent) {\n            // Less than 0\n            if (percent <= 0) {\n                return colorList[0][1];\n            }\n            for (var i = 0; i < colorList.length; i++) {\n                if (colorList[i][0] >= percent\n                    && (i === 0 ? 0 : colorList[i - 1][0]) < percent\n                ) {\n                    return colorList[i][1];\n                }\n            }\n            // More than 1\n            return colorList[i - 1][1];\n        };\n\n        if (!clockwise) {\n            var tmp = startAngle;\n            startAngle = endAngle;\n            endAngle = tmp;\n        }\n\n        this._renderTicks(\n            seriesModel, ecModel, api, getColor, posInfo,\n            startAngle, endAngle, clockwise\n        );\n\n        this._renderPointer(\n            seriesModel, ecModel, api, getColor, posInfo,\n            startAngle, endAngle, clockwise\n        );\n\n        this._renderTitle(\n            seriesModel, ecModel, api, getColor, posInfo\n        );\n        this._renderDetail(\n            seriesModel, ecModel, api, getColor, posInfo\n        );\n    },\n\n    _renderTicks: function (\n        seriesModel, ecModel, api, getColor, posInfo,\n        startAngle, endAngle, clockwise\n    ) {\n        var group = this.group;\n        var cx = posInfo.cx;\n        var cy = posInfo.cy;\n        var r = posInfo.r;\n\n        var minVal = +seriesModel.get('min');\n        var maxVal = +seriesModel.get('max');\n\n        var splitLineModel = seriesModel.getModel('splitLine');\n        var tickModel = seriesModel.getModel('axisTick');\n        var labelModel = seriesModel.getModel('axisLabel');\n\n        var splitNumber = seriesModel.get('splitNumber');\n        var subSplitNumber = tickModel.get('splitNumber');\n\n        var splitLineLen = parsePercent$1(\n            splitLineModel.get('length'), r\n        );\n        var tickLen = parsePercent$1(\n            tickModel.get('length'), r\n        );\n\n        var angle = startAngle;\n        var step = (endAngle - startAngle) / splitNumber;\n        var subStep = step / subSplitNumber;\n\n        var splitLineStyle = splitLineModel.getModel('lineStyle').getLineStyle();\n        var tickLineStyle = tickModel.getModel('lineStyle').getLineStyle();\n\n        for (var i = 0; i <= splitNumber; i++) {\n            var unitX = Math.cos(angle);\n            var unitY = Math.sin(angle);\n            // Split line\n            if (splitLineModel.get('show')) {\n                var splitLine = new Line({\n                    shape: {\n                        x1: unitX * r + cx,\n                        y1: unitY * r + cy,\n                        x2: unitX * (r - splitLineLen) + cx,\n                        y2: unitY * (r - splitLineLen) + cy\n                    },\n                    style: splitLineStyle,\n                    silent: true\n                });\n                if (splitLineStyle.stroke === 'auto') {\n                    splitLine.setStyle({\n                        stroke: getColor(i / splitNumber)\n                    });\n                }\n\n                group.add(splitLine);\n            }\n\n            // Label\n            if (labelModel.get('show')) {\n                var label = formatLabel(\n                    round$2(i / splitNumber * (maxVal - minVal) + minVal),\n                    labelModel.get('formatter')\n                );\n                var distance = labelModel.get('distance');\n                var autoColor = getColor(i / splitNumber);\n\n                group.add(new Text({\n                    style: setTextStyle({}, labelModel, {\n                        text: label,\n                        x: unitX * (r - splitLineLen - distance) + cx,\n                        y: unitY * (r - splitLineLen - distance) + cy,\n                        textVerticalAlign: unitY < -0.4 ? 'top' : (unitY > 0.4 ? 'bottom' : 'middle'),\n                        textAlign: unitX < -0.4 ? 'left' : (unitX > 0.4 ? 'right' : 'center')\n                    }, {autoColor: autoColor}),\n                    silent: true\n                }));\n            }\n\n            // Axis tick\n            if (tickModel.get('show') && i !== splitNumber) {\n                for (var j = 0; j <= subSplitNumber; j++) {\n                    var unitX = Math.cos(angle);\n                    var unitY = Math.sin(angle);\n                    var tickLine = new Line({\n                        shape: {\n                            x1: unitX * r + cx,\n                            y1: unitY * r + cy,\n                            x2: unitX * (r - tickLen) + cx,\n                            y2: unitY * (r - tickLen) + cy\n                        },\n                        silent: true,\n                        style: tickLineStyle\n                    });\n\n                    if (tickLineStyle.stroke === 'auto') {\n                        tickLine.setStyle({\n                            stroke: getColor((i + j / subSplitNumber) / splitNumber)\n                        });\n                    }\n\n                    group.add(tickLine);\n                    angle += subStep;\n                }\n                angle -= subStep;\n            }\n            else {\n                angle += step;\n            }\n        }\n    },\n\n    _renderPointer: function (\n        seriesModel, ecModel, api, getColor, posInfo,\n        startAngle, endAngle, clockwise\n    ) {\n\n        var group = this.group;\n        var oldData = this._data;\n\n        if (!seriesModel.get('pointer.show')) {\n            // Remove old element\n            oldData && oldData.eachItemGraphicEl(function (el) {\n                group.remove(el);\n            });\n            return;\n        }\n\n        var valueExtent = [+seriesModel.get('min'), +seriesModel.get('max')];\n        var angleExtent = [startAngle, endAngle];\n\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n\n        data.diff(oldData)\n            .add(function (idx) {\n                var pointer = new PointerPath({\n                    shape: {\n                        angle: startAngle\n                    }\n                });\n\n                initProps(pointer, {\n                    shape: {\n                        angle: linearMap(data.get(valueDim, idx), valueExtent, angleExtent, true)\n                    }\n                }, seriesModel);\n\n                group.add(pointer);\n                data.setItemGraphicEl(idx, pointer);\n            })\n            .update(function (newIdx, oldIdx) {\n                var pointer = oldData.getItemGraphicEl(oldIdx);\n\n                updateProps(pointer, {\n                    shape: {\n                        angle: linearMap(data.get(valueDim, newIdx), valueExtent, angleExtent, true)\n                    }\n                }, seriesModel);\n\n                group.add(pointer);\n                data.setItemGraphicEl(newIdx, pointer);\n            })\n            .remove(function (idx) {\n                var pointer = oldData.getItemGraphicEl(idx);\n                group.remove(pointer);\n            })\n            .execute();\n\n        data.eachItemGraphicEl(function (pointer, idx) {\n            var itemModel = data.getItemModel(idx);\n            var pointerModel = itemModel.getModel('pointer');\n\n            pointer.setShape({\n                x: posInfo.cx,\n                y: posInfo.cy,\n                width: parsePercent$1(\n                    pointerModel.get('width'), posInfo.r\n                ),\n                r: parsePercent$1(pointerModel.get('length'), posInfo.r)\n            });\n\n            pointer.useStyle(itemModel.getModel('itemStyle').getItemStyle());\n\n            if (pointer.style.fill === 'auto') {\n                pointer.setStyle('fill', getColor(\n                    linearMap(data.get(valueDim, idx), valueExtent, [0, 1], true)\n                ));\n            }\n\n            setHoverStyle(\n                pointer, itemModel.getModel('emphasis.itemStyle').getItemStyle()\n            );\n        });\n\n        this._data = data;\n    },\n\n    _renderTitle: function (\n        seriesModel, ecModel, api, getColor, posInfo\n    ) {\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n        var titleModel = seriesModel.getModel('title');\n        if (titleModel.get('show')) {\n            var offsetCenter = titleModel.get('offsetCenter');\n            var x = posInfo.cx + parsePercent$1(offsetCenter[0], posInfo.r);\n            var y = posInfo.cy + parsePercent$1(offsetCenter[1], posInfo.r);\n\n            var minVal = +seriesModel.get('min');\n            var maxVal = +seriesModel.get('max');\n            var value = seriesModel.getData().get(valueDim, 0);\n            var autoColor = getColor(\n                linearMap(value, [minVal, maxVal], [0, 1], true)\n            );\n\n            this.group.add(new Text({\n                silent: true,\n                style: setTextStyle({}, titleModel, {\n                    x: x,\n                    y: y,\n                    // FIXME First data name ?\n                    text: data.getName(0),\n                    textAlign: 'center',\n                    textVerticalAlign: 'middle'\n                }, {autoColor: autoColor, forceRich: true})\n            }));\n        }\n    },\n\n    _renderDetail: function (\n        seriesModel, ecModel, api, getColor, posInfo\n    ) {\n        var detailModel = seriesModel.getModel('detail');\n        var minVal = +seriesModel.get('min');\n        var maxVal = +seriesModel.get('max');\n        if (detailModel.get('show')) {\n            var offsetCenter = detailModel.get('offsetCenter');\n            var x = posInfo.cx + parsePercent$1(offsetCenter[0], posInfo.r);\n            var y = posInfo.cy + parsePercent$1(offsetCenter[1], posInfo.r);\n            var width = parsePercent$1(detailModel.get('width'), posInfo.r);\n            var height = parsePercent$1(detailModel.get('height'), posInfo.r);\n            var data = seriesModel.getData();\n            var value = data.get(data.mapDimension('value'), 0);\n            var autoColor = getColor(\n                linearMap(value, [minVal, maxVal], [0, 1], true)\n            );\n\n            this.group.add(new Text({\n                silent: true,\n                style: setTextStyle({}, detailModel, {\n                    x: x,\n                    y: y,\n                    text: formatLabel(\n                        // FIXME First data name ?\n                        value, detailModel.get('formatter')\n                    ),\n                    textWidth: isNaN(width) ? null : width,\n                    textHeight: isNaN(height) ? null : height,\n                    textAlign: 'center',\n                    textVerticalAlign: 'middle'\n                }, {autoColor: autoColor, forceRich: true})\n            }));\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar FunnelSeries = extendSeriesModel({\n\n    type: 'series.funnel',\n\n    init: function (option) {\n        FunnelSeries.superApply(this, 'init', arguments);\n\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n        // Extend labelLine emphasis\n        this._defaultLabelLine(option);\n    },\n\n    getInitialData: function (option, ecModel) {\n        return createListSimply(this, ['value']);\n    },\n\n    _defaultLabelLine: function (option) {\n        // Extend labelLine emphasis\n        defaultEmphasis(option, 'labelLine', ['show']);\n\n        var labelLineNormalOpt = option.labelLine;\n        var labelLineEmphasisOpt = option.emphasis.labelLine;\n        // Not show label line if `label.normal.show = false`\n        labelLineNormalOpt.show = labelLineNormalOpt.show\n            && option.label.show;\n        labelLineEmphasisOpt.show = labelLineEmphasisOpt.show\n            && option.emphasis.label.show;\n    },\n\n    // Overwrite\n    getDataParams: function (dataIndex) {\n        var data = this.getData();\n        var params = FunnelSeries.superCall(this, 'getDataParams', dataIndex);\n        var valueDim = data.mapDimension('value');\n        var sum = data.getSum(valueDim);\n        // Percent is 0 if sum is 0\n        params.percent = !sum ? 0 : +(data.get(valueDim, dataIndex) / sum * 100).toFixed(2);\n\n        params.$vars.push('percent');\n        return params;\n    },\n\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n        legendHoverLink: true,\n        left: 80,\n        top: 60,\n        right: 80,\n        bottom: 60,\n        // width: {totalWidth} - left - right,\n        // height: {totalHeight} - top - bottom,\n\n        // 默认取数据最小最大值\n        // min: 0,\n        // max: 100,\n        minSize: '0%',\n        maxSize: '100%',\n        sort: 'descending', // 'ascending', 'descending'\n        gap: 0,\n        funnelAlign: 'center',\n        label: {\n            show: true,\n            position: 'outer'\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n        },\n        labelLine: {\n            show: true,\n            length: 20,\n            lineStyle: {\n                // color: 各异,\n                width: 1,\n                type: 'solid'\n            }\n        },\n        itemStyle: {\n            // color: 各异,\n            borderColor: '#fff',\n            borderWidth: 1\n        },\n        emphasis: {\n            label: {\n                show: true\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Piece of pie including Sector, Label, LabelLine\n * @constructor\n * @extends {module:zrender/graphic/Group}\n */\nfunction FunnelPiece(data, idx) {\n\n    Group.call(this);\n\n    var polygon = new Polygon();\n    var labelLine = new Polyline();\n    var text = new Text();\n    this.add(polygon);\n    this.add(labelLine);\n    this.add(text);\n\n    this.updateData(data, idx, true);\n\n    // Hover to change label and labelLine\n    function onEmphasis() {\n        labelLine.ignore = labelLine.hoverIgnore;\n        text.ignore = text.hoverIgnore;\n    }\n    function onNormal() {\n        labelLine.ignore = labelLine.normalIgnore;\n        text.ignore = text.normalIgnore;\n    }\n    this.on('emphasis', onEmphasis)\n        .on('normal', onNormal)\n        .on('mouseover', onEmphasis)\n        .on('mouseout', onNormal);\n}\n\nvar funnelPieceProto = FunnelPiece.prototype;\n\nvar opacityAccessPath = ['itemStyle', 'opacity'];\nfunnelPieceProto.updateData = function (data, idx, firstCreate) {\n\n    var polygon = this.childAt(0);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var opacity = data.getItemModel(idx).get(opacityAccessPath);\n    opacity = opacity == null ? 1 : opacity;\n\n    // Reset style\n    polygon.useStyle({});\n\n    if (firstCreate) {\n        polygon.setShape({\n            points: layout.points\n        });\n        polygon.setStyle({opacity: 0});\n        initProps(polygon, {\n            style: {\n                opacity: opacity\n            }\n        }, seriesModel, idx);\n    }\n    else {\n        updateProps(polygon, {\n            style: {\n                opacity: opacity\n            },\n            shape: {\n                points: layout.points\n            }\n        }, seriesModel, idx);\n    }\n\n    // Update common style\n    var itemStyleModel = itemModel.getModel('itemStyle');\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    polygon.setStyle(\n        defaults(\n            {\n                lineJoin: 'round',\n                fill: visualColor\n            },\n            itemStyleModel.getItemStyle(['opacity'])\n        )\n    );\n    polygon.hoverStyle = itemStyleModel.getModel('emphasis').getItemStyle();\n\n    this._updateLabel(data, idx);\n\n    setHoverStyle(this);\n};\n\nfunnelPieceProto._updateLabel = function (data, idx) {\n\n    var labelLine = this.childAt(1);\n    var labelText = this.childAt(2);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var labelLayout = layout.label;\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    updateProps(labelLine, {\n        shape: {\n            points: labelLayout.linePoints || labelLayout.linePoints\n        }\n    }, seriesModel, idx);\n\n    updateProps(labelText, {\n        style: {\n            x: labelLayout.x,\n            y: labelLayout.y\n        }\n    }, seriesModel, idx);\n    labelText.attr({\n        rotation: labelLayout.rotation,\n        origin: [labelLayout.x, labelLayout.y],\n        z2: 10\n    });\n\n    var labelModel = itemModel.getModel('label');\n    var labelHoverModel = itemModel.getModel('emphasis.label');\n    var labelLineModel = itemModel.getModel('labelLine');\n    var labelLineHoverModel = itemModel.getModel('emphasis.labelLine');\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    setLabelStyle(\n        labelText.style, labelText.hoverStyle = {}, labelModel, labelHoverModel,\n        {\n            labelFetcher: data.hostModel,\n            labelDataIndex: idx,\n            defaultText: data.getName(idx),\n            autoColor: visualColor,\n            useInsideStyle: !!labelLayout.inside\n        },\n        {\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.verticalAlign\n        }\n    );\n\n    labelText.ignore = labelText.normalIgnore = !labelModel.get('show');\n    labelText.hoverIgnore = !labelHoverModel.get('show');\n\n    labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show');\n    labelLine.hoverIgnore = !labelLineHoverModel.get('show');\n\n    // Default use item visual color\n    labelLine.setStyle({\n        stroke: visualColor\n    });\n    labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());\n\n    labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();\n};\n\ninherits(FunnelPiece, Group);\n\n\nvar FunnelView = Chart.extend({\n\n    type: 'funnel',\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        var group = this.group;\n\n        data.diff(oldData)\n            .add(function (idx) {\n                var funnelPiece = new FunnelPiece(data, idx);\n\n                data.setItemGraphicEl(idx, funnelPiece);\n\n                group.add(funnelPiece);\n            })\n            .update(function (newIdx, oldIdx) {\n                var piePiece = oldData.getItemGraphicEl(oldIdx);\n\n                piePiece.updateData(data, newIdx);\n\n                group.add(piePiece);\n                data.setItemGraphicEl(newIdx, piePiece);\n            })\n            .remove(function (idx) {\n                var piePiece = oldData.getItemGraphicEl(idx);\n                group.remove(piePiece);\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    remove: function () {\n        this.group.removeAll();\n        this._data = null;\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction getViewRect$2(seriesModel, api) {\n    return getLayoutRect(\n        seriesModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        }\n    );\n}\n\nfunction getSortedIndices(data, sort) {\n    var valueDim = data.mapDimension('value');\n    var valueArr = data.mapArray(valueDim, function (val) {\n        return val;\n    });\n    var indices = [];\n    var isAscending = sort === 'ascending';\n    for (var i = 0, len = data.count(); i < len; i++) {\n        indices[i] = i;\n    }\n\n    // Add custom sortable function & none sortable opetion by \"options.sort\"\n    if (typeof sort === 'function') {\n        indices.sort(sort);\n    }\n    else if (sort !== 'none') {\n        indices.sort(function (a, b) {\n            return isAscending ? valueArr[a] - valueArr[b] : valueArr[b] - valueArr[a];\n        });\n    }\n    return indices;\n}\n\nfunction labelLayout$1(data) {\n    data.each(function (idx) {\n        var itemModel = data.getItemModel(idx);\n        var labelModel = itemModel.getModel('label');\n        var labelPosition = labelModel.get('position');\n\n        var labelLineModel = itemModel.getModel('labelLine');\n\n        var layout = data.getItemLayout(idx);\n        var points = layout.points;\n\n        var isLabelInside = labelPosition === 'inner'\n            || labelPosition === 'inside' || labelPosition === 'center';\n\n        var textAlign;\n        var textX;\n        var textY;\n        var linePoints;\n\n        if (isLabelInside) {\n            textX = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4;\n            textY = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4;\n            textAlign = 'center';\n            linePoints = [\n                [textX, textY], [textX, textY]\n            ];\n        }\n        else {\n            var x1;\n            var y1;\n            var x2;\n            var labelLineLen = labelLineModel.get('length');\n            if (labelPosition === 'left') {\n                // Left side\n                x1 = (points[3][0] + points[0][0]) / 2;\n                y1 = (points[3][1] + points[0][1]) / 2;\n                x2 = x1 - labelLineLen;\n                textX = x2 - 5;\n                textAlign = 'right';\n            }\n            else {\n                // Right side\n                x1 = (points[1][0] + points[2][0]) / 2;\n                y1 = (points[1][1] + points[2][1]) / 2;\n                x2 = x1 + labelLineLen;\n                textX = x2 + 5;\n                textAlign = 'left';\n            }\n            var y2 = y1;\n\n            linePoints = [[x1, y1], [x2, y2]];\n            textY = y2;\n        }\n\n        layout.label = {\n            linePoints: linePoints,\n            x: textX,\n            y: textY,\n            verticalAlign: 'middle',\n            textAlign: textAlign,\n            inside: isLabelInside\n        };\n    });\n}\n\nvar funnelLayout = function (ecModel, api, payload) {\n    ecModel.eachSeriesByType('funnel', function (seriesModel) {\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n        var sort = seriesModel.get('sort');\n        var viewRect = getViewRect$2(seriesModel, api);\n        var indices = getSortedIndices(data, sort);\n\n        var sizeExtent = [\n            parsePercent$1(seriesModel.get('minSize'), viewRect.width),\n            parsePercent$1(seriesModel.get('maxSize'), viewRect.width)\n        ];\n        var dataExtent = data.getDataExtent(valueDim);\n        var min = seriesModel.get('min');\n        var max = seriesModel.get('max');\n        if (min == null) {\n            min = Math.min(dataExtent[0], 0);\n        }\n        if (max == null) {\n            max = dataExtent[1];\n        }\n\n        var funnelAlign = seriesModel.get('funnelAlign');\n        var gap = seriesModel.get('gap');\n        var itemHeight = (viewRect.height - gap * (data.count() - 1)) / data.count();\n\n        var y = viewRect.y;\n\n        var getLinePoints = function (idx, offY) {\n            // End point index is data.count() and we assign it 0\n            var val = data.get(valueDim, idx) || 0;\n            var itemWidth = linearMap(val, [min, max], sizeExtent, true);\n            var x0;\n            switch (funnelAlign) {\n                case 'left':\n                    x0 = viewRect.x;\n                    break;\n                case 'center':\n                    x0 = viewRect.x + (viewRect.width - itemWidth) / 2;\n                    break;\n                case 'right':\n                    x0 = viewRect.x + viewRect.width - itemWidth;\n                    break;\n            }\n            return [\n                [x0, offY],\n                [x0 + itemWidth, offY]\n            ];\n        };\n\n        if (sort === 'ascending') {\n            // From bottom to top\n            itemHeight = -itemHeight;\n            gap = -gap;\n            y += viewRect.height;\n            indices = indices.reverse();\n        }\n\n        for (var i = 0; i < indices.length; i++) {\n            var idx = indices[i];\n            var nextIdx = indices[i + 1];\n\n            var itemModel = data.getItemModel(idx);\n            var height = itemModel.get('itemStyle.height');\n            if (height == null) {\n                height = itemHeight;\n            }\n            else {\n                height = parsePercent$1(height, viewRect.height);\n                if (sort === 'ascending') {\n                    height = -height;\n                }\n            }\n\n            var start = getLinePoints(idx, y);\n            var end = getLinePoints(nextIdx, y + height);\n\n            y += height + gap;\n\n            data.setItemLayout(idx, {\n                points: start.concat(end.slice().reverse())\n            });\n        }\n\n        labelLayout$1(data);\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(dataColor('funnel'));\nregisterLayout(funnelLayout);\nregisterProcessor(dataFilter('funnel'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar parallelPreprocessor = function (option) {\n    createParallelIfNeeded(option);\n    mergeAxisOptionFromParallel(option);\n};\n\n/**\n * Create a parallel coordinate if not exists.\n * @inner\n */\nfunction createParallelIfNeeded(option) {\n    if (option.parallel) {\n        return;\n    }\n\n    var hasParallelSeries = false;\n\n    each$1(option.series, function (seriesOpt) {\n        if (seriesOpt && seriesOpt.type === 'parallel') {\n            hasParallelSeries = true;\n        }\n    });\n\n    if (hasParallelSeries) {\n        option.parallel = [{}];\n    }\n}\n\n/**\n * Merge aixs definition from parallel option (if exists) to axis option.\n * @inner\n */\nfunction mergeAxisOptionFromParallel(option) {\n    var axes = normalizeToArray(option.parallelAxis);\n\n    each$1(axes, function (axisOption) {\n        if (!isObject$1(axisOption)) {\n            return;\n        }\n\n        var parallelIndex = axisOption.parallelIndex || 0;\n        var parallelOption = normalizeToArray(option.parallel)[parallelIndex];\n\n        if (parallelOption && parallelOption.parallelAxisDefault) {\n            merge(axisOption, parallelOption.parallelAxisDefault, false);\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @constructor module:echarts/coord/parallel/ParallelAxis\n * @extends {module:echarts/coord/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n */\nvar ParallelAxis = function (dim, scale, coordExtent, axisType, axisIndex) {\n\n    Axis.call(this, dim, scale, coordExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.axisIndex = axisIndex;\n};\n\nParallelAxis.prototype = {\n\n    constructor: ParallelAxis,\n\n    /**\n     * Axis model\n     * @param {module:echarts/coord/parallel/AxisModel}\n     */\n    model: null,\n\n    /**\n     * @override\n     */\n    isHorizontal: function () {\n        return this.coordinateSystem.getModel().get('layout') !== 'horizontal';\n    }\n\n};\n\ninherits(ParallelAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Calculate slider move result.\n * Usage:\n * (1) If both handle0 and handle1 are needed to be moved, set minSpan the same as\n * maxSpan and the same as `Math.abs(handleEnd[1] - handleEnds[0])`.\n * (2) If handle0 is forbidden to cross handle1, set minSpan as `0`.\n *\n * @param {number} delta Move length.\n * @param {Array.<number>} handleEnds handleEnds[0] can be bigger then handleEnds[1].\n *              handleEnds will be modified in this method.\n * @param {Array.<number>} extent handleEnds is restricted by extent.\n *              extent[0] should less or equals than extent[1].\n * @param {number|string} handleIndex Can be 'all', means that both move the two handleEnds,\n *              where the input minSpan and maxSpan will not work.\n * @param {number} [minSpan] The range of dataZoom can not be smaller than that.\n *              If not set, handle0 and cross handle1. If set as a non-negative\n *              number (including `0`), handles will push each other when reaching\n *              the minSpan.\n * @param {number} [maxSpan] The range of dataZoom can not be larger than that.\n * @return {Array.<number>} The input handleEnds.\n */\nvar sliderMove = function (delta, handleEnds, extent, handleIndex, minSpan, maxSpan) {\n    // Normalize firstly.\n    handleEnds[0] = restrict$1(handleEnds[0], extent);\n    handleEnds[1] = restrict$1(handleEnds[1], extent);\n\n    delta = delta || 0;\n\n    var extentSpan = extent[1] - extent[0];\n\n    // Notice maxSpan and minSpan can be null/undefined.\n    if (minSpan != null) {\n        minSpan = restrict$1(minSpan, [0, extentSpan]);\n    }\n    if (maxSpan != null) {\n        maxSpan = Math.max(maxSpan, minSpan != null ? minSpan : 0);\n    }\n    if (handleIndex === 'all') {\n        minSpan = maxSpan = Math.abs(handleEnds[1] - handleEnds[0]);\n        handleIndex = 0;\n    }\n\n    var originalDistSign = getSpanSign(handleEnds, handleIndex);\n\n    handleEnds[handleIndex] += delta;\n\n    // Restrict in extent.\n    var extentMinSpan = minSpan || 0;\n    var realExtent = extent.slice();\n    originalDistSign.sign < 0 ? (realExtent[0] += extentMinSpan) : (realExtent[1] -= extentMinSpan);\n    handleEnds[handleIndex] = restrict$1(handleEnds[handleIndex], realExtent);\n\n    // Expand span.\n    var currDistSign = getSpanSign(handleEnds, handleIndex);\n    if (minSpan != null && (\n        currDistSign.sign !== originalDistSign.sign || currDistSign.span < minSpan\n    )) {\n        // If minSpan exists, 'cross' is forbinden.\n        handleEnds[1 - handleIndex] = handleEnds[handleIndex] + originalDistSign.sign * minSpan;\n    }\n\n    // Shrink span.\n    var currDistSign = getSpanSign(handleEnds, handleIndex);\n    if (maxSpan != null && currDistSign.span > maxSpan) {\n        handleEnds[1 - handleIndex] = handleEnds[handleIndex] + currDistSign.sign * maxSpan;\n    }\n\n    return handleEnds;\n};\n\nfunction getSpanSign(handleEnds, handleIndex) {\n    var dist = handleEnds[handleIndex] - handleEnds[1 - handleIndex];\n    // If `handleEnds[0] === handleEnds[1]`, always believe that handleEnd[0]\n    // is at left of handleEnds[1] for non-cross case.\n    return {span: Math.abs(dist), sign: dist > 0 ? -1 : dist < 0 ? 1 : handleIndex ? -1 : 1};\n}\n\nfunction restrict$1(value, extend) {\n    return Math.min(extend[1], Math.max(extend[0], value));\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Parallel Coordinates\n * <https://en.wikipedia.org/wiki/Parallel_coordinates>\n */\n\nvar each$11 = each$1;\nvar mathMin$5 = Math.min;\nvar mathMax$5 = Math.max;\nvar mathFloor$2 = Math.floor;\nvar mathCeil$2 = Math.ceil;\nvar round$3 = round$2;\n\nvar PI$3 = Math.PI;\n\nfunction Parallel(parallelModel, ecModel, api) {\n\n    /**\n     * key: dimension\n     * @type {Object.<string, module:echarts/coord/parallel/Axis>}\n     * @private\n     */\n    this._axesMap = createHashMap();\n\n    /**\n     * key: dimension\n     * value: {position: [], rotation, }\n     * @type {Object.<string, Object>}\n     * @private\n     */\n    this._axesLayout = {};\n\n    /**\n     * Always follow axis order.\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    this.dimensions = parallelModel.dimensions;\n\n    /**\n     * @type {module:zrender/core/BoundingRect}\n     */\n    this._rect;\n\n    /**\n     * @type {module:echarts/coord/parallel/ParallelModel}\n     */\n    this._model = parallelModel;\n\n    this._init(parallelModel, ecModel, api);\n}\n\nParallel.prototype = {\n\n    type: 'parallel',\n\n    constructor: Parallel,\n\n    /**\n     * Initialize cartesian coordinate systems\n     * @private\n     */\n    _init: function (parallelModel, ecModel, api) {\n\n        var dimensions = parallelModel.dimensions;\n        var parallelAxisIndex = parallelModel.parallelAxisIndex;\n\n        each$11(dimensions, function (dim, idx) {\n\n            var axisIndex = parallelAxisIndex[idx];\n            var axisModel = ecModel.getComponent('parallelAxis', axisIndex);\n\n            var axis = this._axesMap.set(dim, new ParallelAxis(\n                dim,\n                createScaleByModel(axisModel),\n                [0, 0],\n                axisModel.get('type'),\n                axisIndex\n            ));\n\n            var isCategory = axis.type === 'category';\n            axis.onBand = isCategory && axisModel.get('boundaryGap');\n            axis.inverse = axisModel.get('inverse');\n\n            // Injection\n            axisModel.axis = axis;\n            axis.model = axisModel;\n            axis.coordinateSystem = axisModel.coordinateSystem = this;\n\n        }, this);\n    },\n\n    /**\n     * Update axis scale after data processed\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    update: function (ecModel, api) {\n        this._updateAxesFromSeries(this._model, ecModel);\n    },\n\n    /**\n     * @override\n     */\n    containPoint: function (point) {\n        var layoutInfo = this._makeLayoutInfo();\n        var axisBase = layoutInfo.axisBase;\n        var layoutBase = layoutInfo.layoutBase;\n        var pixelDimIndex = layoutInfo.pixelDimIndex;\n        var pAxis = point[1 - pixelDimIndex];\n        var pLayout = point[pixelDimIndex];\n\n        return pAxis >= axisBase\n            && pAxis <= axisBase + layoutInfo.axisLength\n            && pLayout >= layoutBase\n            && pLayout <= layoutBase + layoutInfo.layoutLength;\n    },\n\n    getModel: function () {\n        return this._model;\n    },\n\n    /**\n     * Update properties from series\n     * @private\n     */\n    _updateAxesFromSeries: function (parallelModel, ecModel) {\n        ecModel.eachSeries(function (seriesModel) {\n\n            if (!parallelModel.contains(seriesModel, ecModel)) {\n                return;\n            }\n\n            var data = seriesModel.getData();\n\n            each$11(this.dimensions, function (dim) {\n                var axis = this._axesMap.get(dim);\n                axis.scale.unionExtentFromData(data, data.mapDimension(dim));\n                niceScaleExtent(axis.scale, axis.model);\n            }, this);\n        }, this);\n    },\n\n    /**\n     * Resize the parallel coordinate system.\n     * @param {module:echarts/coord/parallel/ParallelModel} parallelModel\n     * @param {module:echarts/ExtensionAPI} api\n     */\n    resize: function (parallelModel, api) {\n        this._rect = getLayoutRect(\n            parallelModel.getBoxLayoutParams(),\n            {\n                width: api.getWidth(),\n                height: api.getHeight()\n            }\n        );\n\n        this._layoutAxes();\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getRect: function () {\n        return this._rect;\n    },\n\n    /**\n     * @private\n     */\n    _makeLayoutInfo: function () {\n        var parallelModel = this._model;\n        var rect = this._rect;\n        var xy = ['x', 'y'];\n        var wh = ['width', 'height'];\n        var layout = parallelModel.get('layout');\n        var pixelDimIndex = layout === 'horizontal' ? 0 : 1;\n        var layoutLength = rect[wh[pixelDimIndex]];\n        var layoutExtent = [0, layoutLength];\n        var axisCount = this.dimensions.length;\n\n        var axisExpandWidth = restrict(parallelModel.get('axisExpandWidth'), layoutExtent);\n        var axisExpandCount = restrict(parallelModel.get('axisExpandCount') || 0, [0, axisCount]);\n        var axisExpandable = parallelModel.get('axisExpandable')\n            && axisCount > 3\n            && axisCount > axisExpandCount\n            && axisExpandCount > 1\n            && axisExpandWidth > 0\n            && layoutLength > 0;\n\n        // `axisExpandWindow` is According to the coordinates of [0, axisExpandLength],\n        // for sake of consider the case that axisCollapseWidth is 0 (when screen is narrow),\n        // where collapsed axes should be overlapped.\n        var axisExpandWindow = parallelModel.get('axisExpandWindow');\n        var winSize;\n        if (!axisExpandWindow) {\n            winSize = restrict(axisExpandWidth * (axisExpandCount - 1), layoutExtent);\n            var axisExpandCenter = parallelModel.get('axisExpandCenter') || mathFloor$2(axisCount / 2);\n            axisExpandWindow = [axisExpandWidth * axisExpandCenter - winSize / 2];\n            axisExpandWindow[1] = axisExpandWindow[0] + winSize;\n        }\n        else {\n                winSize = restrict(axisExpandWindow[1] - axisExpandWindow[0], layoutExtent);\n                axisExpandWindow[1] = axisExpandWindow[0] + winSize;\n        }\n\n        var axisCollapseWidth = (layoutLength - winSize) / (axisCount - axisExpandCount);\n        // Avoid axisCollapseWidth is too small.\n        axisCollapseWidth < 3 && (axisCollapseWidth = 0);\n\n        // Find the first and last indices > ewin[0] and < ewin[1].\n        var winInnerIndices = [\n            mathFloor$2(round$3(axisExpandWindow[0] / axisExpandWidth, 1)) + 1,\n            mathCeil$2(round$3(axisExpandWindow[1] / axisExpandWidth, 1)) - 1\n        ];\n\n        // Pos in ec coordinates.\n        var axisExpandWindow0Pos = axisCollapseWidth / axisExpandWidth * axisExpandWindow[0];\n\n        return {\n            layout: layout,\n            pixelDimIndex: pixelDimIndex,\n            layoutBase: rect[xy[pixelDimIndex]],\n            layoutLength: layoutLength,\n            axisBase: rect[xy[1 - pixelDimIndex]],\n            axisLength: rect[wh[1 - pixelDimIndex]],\n            axisExpandable: axisExpandable,\n            axisExpandWidth: axisExpandWidth,\n            axisCollapseWidth: axisCollapseWidth,\n            axisExpandWindow: axisExpandWindow,\n            axisCount: axisCount,\n            winInnerIndices: winInnerIndices,\n            axisExpandWindow0Pos: axisExpandWindow0Pos\n        };\n    },\n\n    /**\n     * @private\n     */\n    _layoutAxes: function () {\n        var rect = this._rect;\n        var axes = this._axesMap;\n        var dimensions = this.dimensions;\n        var layoutInfo = this._makeLayoutInfo();\n        var layout = layoutInfo.layout;\n\n        axes.each(function (axis) {\n            var axisExtent = [0, layoutInfo.axisLength];\n            var idx = axis.inverse ? 1 : 0;\n            axis.setExtent(axisExtent[idx], axisExtent[1 - idx]);\n        });\n\n        each$11(dimensions, function (dim, idx) {\n            var posInfo = (layoutInfo.axisExpandable\n                ? layoutAxisWithExpand : layoutAxisWithoutExpand\n            )(idx, layoutInfo);\n\n            var positionTable = {\n                horizontal: {\n                    x: posInfo.position,\n                    y: layoutInfo.axisLength\n                },\n                vertical: {\n                    x: 0,\n                    y: posInfo.position\n                }\n            };\n            var rotationTable = {\n                horizontal: PI$3 / 2,\n                vertical: 0\n            };\n\n            var position = [\n                positionTable[layout].x + rect.x,\n                positionTable[layout].y + rect.y\n            ];\n\n            var rotation = rotationTable[layout];\n            var transform = create$1();\n            rotate(transform, transform, rotation);\n            translate(transform, transform, position);\n\n            // TODO\n            // tick等排布信息。\n\n            // TODO\n            // 根据axis order 更新 dimensions顺序。\n\n            this._axesLayout[dim] = {\n                position: position,\n                rotation: rotation,\n                transform: transform,\n                axisNameAvailableWidth: posInfo.axisNameAvailableWidth,\n                axisLabelShow: posInfo.axisLabelShow,\n                nameTruncateMaxWidth: posInfo.nameTruncateMaxWidth,\n                tickDirection: 1,\n                labelDirection: 1\n            };\n        }, this);\n    },\n\n    /**\n     * Get axis by dim.\n     * @param {string} dim\n     * @return {module:echarts/coord/parallel/ParallelAxis} [description]\n     */\n    getAxis: function (dim) {\n        return this._axesMap.get(dim);\n    },\n\n    /**\n     * Convert a dim value of a single item of series data to Point.\n     * @param {*} value\n     * @param {string} dim\n     * @return {Array}\n     */\n    dataToPoint: function (value, dim) {\n        return this.axisCoordToPoint(\n            this._axesMap.get(dim).dataToCoord(value),\n            dim\n        );\n    },\n\n    /**\n     * Travel data for one time, get activeState of each data item.\n     * @param {module:echarts/data/List} data\n     * @param {Functio} cb param: {string} activeState 'active' or 'inactive' or 'normal'\n     *                            {number} dataIndex\n     * @param {number} [start=0] the start dataIndex that travel from.\n     * @param {number} [end=data.count()] the next dataIndex of the last dataIndex will be travel.\n     */\n    eachActiveState: function (data, callback, start, end) {\n        start == null && (start = 0);\n        end == null && (end = data.count());\n\n        var axesMap = this._axesMap;\n        var dimensions = this.dimensions;\n        var dataDimensions = [];\n        var axisModels = [];\n\n        each$1(dimensions, function (axisDim) {\n            dataDimensions.push(data.mapDimension(axisDim));\n            axisModels.push(axesMap.get(axisDim).model);\n        });\n\n        var hasActiveSet = this.hasAxisBrushed();\n\n        for (var dataIndex = start; dataIndex < end; dataIndex++) {\n            var activeState;\n\n            if (!hasActiveSet) {\n                activeState = 'normal';\n            }\n            else {\n                activeState = 'active';\n                var values = data.getValues(dataDimensions, dataIndex);\n                for (var j = 0, lenj = dimensions.length; j < lenj; j++) {\n                    var state = axisModels[j].getActiveState(values[j]);\n\n                    if (state === 'inactive') {\n                        activeState = 'inactive';\n                        break;\n                    }\n                }\n            }\n\n            callback(activeState, dataIndex);\n        }\n    },\n\n    /**\n     * Whether has any activeSet.\n     * @return {boolean}\n     */\n    hasAxisBrushed: function () {\n        var dimensions = this.dimensions;\n        var axesMap = this._axesMap;\n        var hasActiveSet = false;\n\n        for (var j = 0, lenj = dimensions.length; j < lenj; j++) {\n            if (axesMap.get(dimensions[j]).model.getActiveState() !== 'normal') {\n                hasActiveSet = true;\n            }\n        }\n\n        return hasActiveSet;\n    },\n\n    /**\n     * Convert coords of each axis to Point.\n     *  Return point. For example: [10, 20]\n     * @param {Array.<number>} coords\n     * @param {string} dim\n     * @return {Array.<number>}\n     */\n    axisCoordToPoint: function (coord, dim) {\n        var axisLayout = this._axesLayout[dim];\n        return applyTransform$1([coord, 0], axisLayout.transform);\n    },\n\n    /**\n     * Get axis layout.\n     */\n    getAxisLayout: function (dim) {\n        return clone(this._axesLayout[dim]);\n    },\n\n    /**\n     * @param {Array.<number>} point\n     * @return {Object} {axisExpandWindow, delta, behavior: 'jump' | 'slide' | 'none'}.\n     */\n    getSlidedAxisExpandWindow: function (point) {\n        var layoutInfo = this._makeLayoutInfo();\n        var pixelDimIndex = layoutInfo.pixelDimIndex;\n        var axisExpandWindow = layoutInfo.axisExpandWindow.slice();\n        var winSize = axisExpandWindow[1] - axisExpandWindow[0];\n        var extent = [0, layoutInfo.axisExpandWidth * (layoutInfo.axisCount - 1)];\n\n        // Out of the area of coordinate system.\n        if (!this.containPoint(point)) {\n            return {behavior: 'none', axisExpandWindow: axisExpandWindow};\n        }\n\n        // Conver the point from global to expand coordinates.\n        var pointCoord = point[pixelDimIndex] - layoutInfo.layoutBase - layoutInfo.axisExpandWindow0Pos;\n\n        // For dragging operation convenience, the window should not be\n        // slided when mouse is the center area of the window.\n        var delta;\n        var behavior = 'slide';\n        var axisCollapseWidth = layoutInfo.axisCollapseWidth;\n        var triggerArea = this._model.get('axisExpandSlideTriggerArea');\n        // But consider touch device, jump is necessary.\n        var useJump = triggerArea[0] != null;\n\n        if (axisCollapseWidth) {\n            if (useJump && axisCollapseWidth && pointCoord < winSize * triggerArea[0]) {\n                behavior = 'jump';\n                delta = pointCoord - winSize * triggerArea[2];\n            }\n            else if (useJump && axisCollapseWidth && pointCoord > winSize * (1 - triggerArea[0])) {\n                behavior = 'jump';\n                delta = pointCoord - winSize * (1 - triggerArea[2]);\n            }\n            else {\n                (delta = pointCoord - winSize * triggerArea[1]) >= 0\n                    && (delta = pointCoord - winSize * (1 - triggerArea[1])) <= 0\n                    && (delta = 0);\n            }\n            delta *= layoutInfo.axisExpandWidth / axisCollapseWidth;\n            delta\n                ? sliderMove(delta, axisExpandWindow, extent, 'all')\n                // Avoid nonsense triger on mousemove.\n                : (behavior = 'none');\n        }\n        // When screen is too narrow, make it visible and slidable, although it is hard to interact.\n        else {\n            var winSize = axisExpandWindow[1] - axisExpandWindow[0];\n            var pos = extent[1] * pointCoord / winSize;\n            axisExpandWindow = [mathMax$5(0, pos - winSize / 2)];\n            axisExpandWindow[1] = mathMin$5(extent[1], axisExpandWindow[0] + winSize);\n            axisExpandWindow[0] = axisExpandWindow[1] - winSize;\n        }\n\n        return {\n            axisExpandWindow: axisExpandWindow,\n            behavior: behavior\n        };\n    }\n};\n\nfunction restrict(len, extent) {\n    return mathMin$5(mathMax$5(len, extent[0]), extent[1]);\n}\n\nfunction layoutAxisWithoutExpand(axisIndex, layoutInfo) {\n    var step = layoutInfo.layoutLength / (layoutInfo.axisCount - 1);\n    return {\n        position: step * axisIndex,\n        axisNameAvailableWidth: step,\n        axisLabelShow: true\n    };\n}\n\nfunction layoutAxisWithExpand(axisIndex, layoutInfo) {\n    var layoutLength = layoutInfo.layoutLength;\n    var axisExpandWidth = layoutInfo.axisExpandWidth;\n    var axisCount = layoutInfo.axisCount;\n    var axisCollapseWidth = layoutInfo.axisCollapseWidth;\n    var winInnerIndices = layoutInfo.winInnerIndices;\n\n    var position;\n    var axisNameAvailableWidth = axisCollapseWidth;\n    var axisLabelShow = false;\n    var nameTruncateMaxWidth;\n\n    if (axisIndex < winInnerIndices[0]) {\n        position = axisIndex * axisCollapseWidth;\n        nameTruncateMaxWidth = axisCollapseWidth;\n    }\n    else if (axisIndex <= winInnerIndices[1]) {\n        position = layoutInfo.axisExpandWindow0Pos\n            + axisIndex * axisExpandWidth - layoutInfo.axisExpandWindow[0];\n        axisNameAvailableWidth = axisExpandWidth;\n        axisLabelShow = true;\n    }\n    else {\n        position = layoutLength - (axisCount - 1 - axisIndex) * axisCollapseWidth;\n        nameTruncateMaxWidth = axisCollapseWidth;\n    }\n\n    return {\n        position: position,\n        axisNameAvailableWidth: axisNameAvailableWidth,\n        axisLabelShow: axisLabelShow,\n        nameTruncateMaxWidth: nameTruncateMaxWidth\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Parallel coordinate system creater.\n */\n\nfunction create$2(ecModel, api) {\n    var coordSysList = [];\n\n    ecModel.eachComponent('parallel', function (parallelModel, idx) {\n        var coordSys = new Parallel(parallelModel, ecModel, api);\n\n        coordSys.name = 'parallel_' + idx;\n        coordSys.resize(parallelModel, api);\n\n        parallelModel.coordinateSystem = coordSys;\n        coordSys.model = parallelModel;\n\n        coordSysList.push(coordSys);\n    });\n\n    // Inject the coordinateSystems into seriesModel\n    ecModel.eachSeries(function (seriesModel) {\n        if (seriesModel.get('coordinateSystem') === 'parallel') {\n            var parallelModel = ecModel.queryComponents({\n                mainType: 'parallel',\n                index: seriesModel.get('parallelIndex'),\n                id: seriesModel.get('parallelId')\n            })[0];\n            seriesModel.coordinateSystem = parallelModel.coordinateSystem;\n        }\n    });\n\n    return coordSysList;\n}\n\nCoordinateSystemManager.register('parallel', {create: create$2});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisModel$2 = ComponentModel.extend({\n\n    type: 'baseParallelAxis',\n\n    /**\n     * @type {module:echarts/coord/parallel/Axis}\n     */\n    axis: null,\n\n    /**\n     * @type {Array.<Array.<number>}\n     * @readOnly\n     */\n    activeIntervals: [],\n\n    /**\n     * @return {Object}\n     */\n    getAreaSelectStyle: function () {\n        return makeStyleMapper(\n            [\n                ['fill', 'color'],\n                ['lineWidth', 'borderWidth'],\n                ['stroke', 'borderColor'],\n                ['width', 'width'],\n                ['opacity', 'opacity']\n            ]\n        )(this.getModel('areaSelectStyle'));\n    },\n\n    /**\n     * The code of this feature is put on AxisModel but not ParallelAxis,\n     * because axisModel can be alive after echarts updating but instance of\n     * ParallelAxis having been disposed. this._activeInterval should be kept\n     * when action dispatched (i.e. legend click).\n     *\n     * @param {Array.<Array<number>>} intervals interval.length === 0\n     *                                          means set all active.\n     * @public\n     */\n    setActiveIntervals: function (intervals) {\n        var activeIntervals = this.activeIntervals = clone(intervals);\n\n        // Normalize\n        if (activeIntervals) {\n            for (var i = activeIntervals.length - 1; i >= 0; i--) {\n                asc(activeIntervals[i]);\n            }\n        }\n    },\n\n    /**\n     * @param {number|string} [value] When attempting to detect 'no activeIntervals set',\n     *                         value can not be input.\n     * @return {string} 'normal': no activeIntervals set,\n     *                  'active',\n     *                  'inactive'.\n     * @public\n     */\n    getActiveState: function (value) {\n        var activeIntervals = this.activeIntervals;\n\n        if (!activeIntervals.length) {\n            return 'normal';\n        }\n\n        if (value == null || isNaN(value)) {\n            return 'inactive';\n        }\n\n        // Simple optimization\n        if (activeIntervals.length === 1) {\n            var interval = activeIntervals[0];\n            if (interval[0] <= value && value <= interval[1]) {\n                return 'active';\n            }\n        }\n        else {\n            for (var i = 0, len = activeIntervals.length; i < len; i++) {\n                if (activeIntervals[i][0] <= value && value <= activeIntervals[i][1]) {\n                    return 'active';\n                }\n            }\n        }\n\n        return 'inactive';\n    }\n\n});\n\nvar defaultOption$1 = {\n\n    type: 'value',\n\n    /**\n     * @type {Array.<number>}\n     */\n    dim: null, // 0, 1, 2, ...\n\n    // parallelIndex: null,\n\n    areaSelectStyle: {\n        width: 20,\n        borderWidth: 1,\n        borderColor: 'rgba(160,197,232)',\n        color: 'rgba(160,197,232)',\n        opacity: 0.3\n    },\n\n    realtime: true, // Whether realtime update view when select.\n\n    z: 10\n};\n\nmerge(AxisModel$2.prototype, axisModelCommonMixin);\n\nfunction getAxisType$1(axisName, option) {\n    return option.type || (option.data ? 'category' : 'value');\n}\n\naxisModelCreator('parallel', AxisModel$2, getAxisType$1, defaultOption$1);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nComponentModel.extend({\n\n    type: 'parallel',\n\n    dependencies: ['parallelAxis'],\n\n    /**\n     * @type {module:echarts/coord/parallel/Parallel}\n     */\n    coordinateSystem: null,\n\n    /**\n     * Each item like: 'dim0', 'dim1', 'dim2', ...\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: null,\n\n    /**\n     * Coresponding to dimensions.\n     * @type {Array.<number>}\n     * @readOnly\n     */\n    parallelAxisIndex: null,\n\n    layoutMode: 'box',\n\n    defaultOption: {\n        zlevel: 0,\n        z: 0,\n        left: 80,\n        top: 60,\n        right: 80,\n        bottom: 60,\n        // width: {totalWidth} - left - right,\n        // height: {totalHeight} - top - bottom,\n\n        layout: 'horizontal',      // 'horizontal' or 'vertical'\n\n        // FIXME\n        // naming?\n        axisExpandable: false,\n        axisExpandCenter: null,\n        axisExpandCount: 0,\n        axisExpandWidth: 50,      // FIXME '10%' ?\n        axisExpandRate: 17,\n        axisExpandDebounce: 50,\n        // [out, in, jumpTarget]. In percentage. If use [null, 0.05], null means full.\n        // Do not doc to user until necessary.\n        axisExpandSlideTriggerArea: [-0.15, 0.05, 0.4],\n        axisExpandTriggerOn: 'click', // 'mousemove' or 'click'\n\n        parallelAxisDefault: null\n    },\n\n    /**\n     * @override\n     */\n    init: function () {\n        ComponentModel.prototype.init.apply(this, arguments);\n\n        this.mergeOption({});\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (newOption) {\n        var thisOption = this.option;\n\n        newOption && merge(thisOption, newOption, true);\n\n        this._initDimensions();\n    },\n\n    /**\n     * Whether series or axis is in this coordinate system.\n     * @param {module:echarts/model/Series|module:echarts/coord/parallel/AxisModel} model\n     * @param {module:echarts/model/Global} ecModel\n     */\n    contains: function (model, ecModel) {\n        var parallelIndex = model.get('parallelIndex');\n        return parallelIndex != null\n            && ecModel.getComponent('parallel', parallelIndex) === this;\n    },\n\n    setAxisExpand: function (opt) {\n        each$1(\n            ['axisExpandable', 'axisExpandCenter', 'axisExpandCount', 'axisExpandWidth', 'axisExpandWindow'],\n            function (name) {\n                if (opt.hasOwnProperty(name)) {\n                    this.option[name] = opt[name];\n                }\n            },\n            this\n        );\n    },\n\n    /**\n     * @private\n     */\n    _initDimensions: function () {\n        var dimensions = this.dimensions = [];\n        var parallelAxisIndex = this.parallelAxisIndex = [];\n\n        var axisModels = filter(this.dependentModels.parallelAxis, function (axisModel) {\n            // Can not use this.contains here, because\n            // initialization has not been completed yet.\n            return (axisModel.get('parallelIndex') || 0) === this.componentIndex;\n        }, this);\n\n        each$1(axisModels, function (axisModel) {\n            dimensions.push('dim' + axisModel.get('dim'));\n            parallelAxisIndex.push(axisModel.componentIndex);\n        });\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @payload\n * @property {string} parallelAxisId\n * @property {Array.<Array.<number>>} intervals\n */\nvar actionInfo$1 = {\n    type: 'axisAreaSelect',\n    event: 'axisAreaSelected'\n    // update: 'updateVisual'\n};\n\nregisterAction(actionInfo$1, function (payload, ecModel) {\n    ecModel.eachComponent(\n        {mainType: 'parallelAxis', query: payload},\n        function (parallelAxisModel) {\n            parallelAxisModel.axis.model.setActiveIntervals(payload.intervals);\n        }\n    );\n});\n\n/**\n * @payload\n */\nregisterAction('parallelAxisExpand', function (payload, ecModel) {\n    ecModel.eachComponent(\n        {mainType: 'parallel', query: payload},\n        function (parallelModel) {\n            parallelModel.setAxisExpand(payload);\n        }\n    );\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar curry$2 = curry;\nvar each$12 = each$1;\nvar map$2 = map;\nvar mathMin$6 = Math.min;\nvar mathMax$6 = Math.max;\nvar mathPow$2 = Math.pow;\n\nvar COVER_Z = 10000;\nvar UNSELECT_THRESHOLD = 6;\nvar MIN_RESIZE_LINE_WIDTH = 6;\nvar MUTEX_RESOURCE_KEY = 'globalPan';\n\nvar DIRECTION_MAP = {\n    w: [0, 0],\n    e: [0, 1],\n    n: [1, 0],\n    s: [1, 1]\n};\nvar CURSOR_MAP = {\n    w: 'ew',\n    e: 'ew',\n    n: 'ns',\n    s: 'ns',\n    ne: 'nesw',\n    sw: 'nesw',\n    nw: 'nwse',\n    se: 'nwse'\n};\nvar DEFAULT_BRUSH_OPT = {\n    brushStyle: {\n        lineWidth: 2,\n        stroke: 'rgba(0,0,0,0.3)',\n        fill: 'rgba(0,0,0,0.1)'\n    },\n    transformable: true,\n    brushMode: 'single',\n    removeOnClick: false\n};\n\nvar baseUID = 0;\n\n/**\n * @alias module:echarts/component/helper/BrushController\n * @constructor\n * @mixin {module:zrender/mixin/Eventful}\n * @event module:echarts/component/helper/BrushController#brush\n *        params:\n *            areas: Array.<Array>, coord relates to container group,\n *                                    If no container specified, to global.\n *            opt {\n *                isEnd: boolean,\n *                removeOnClick: boolean\n *            }\n *\n * @param {module:zrender/zrender~ZRender} zr\n */\nfunction BrushController(zr) {\n\n    if (__DEV__) {\n        assert$1(zr);\n    }\n\n    Eventful.call(this);\n\n    /**\n     * @type {module:zrender/zrender~ZRender}\n     * @private\n     */\n    this._zr = zr;\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * Only for drawing (after enabledBrush).\n     *     'line', 'rect', 'polygon' or false\n     *     If passing false/null/undefined, disable brush.\n     *     If passing 'auto', determined by panel.defaultBrushType\n     * @private\n     * @type {string}\n     */\n    this._brushType;\n\n    /**\n     * Only for drawing (after enabledBrush).\n     *\n     * @private\n     * @type {Object}\n     */\n    this._brushOption;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._panels;\n\n    /**\n     * @private\n     * @type {Array.<nubmer>}\n     */\n    this._track = [];\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._dragging;\n\n    /**\n     * @private\n     * @type {Array}\n     */\n    this._covers = [];\n\n    /**\n     * @private\n     * @type {moudule:zrender/container/Group}\n     */\n    this._creatingCover;\n\n    /**\n     * `true` means global panel\n     * @private\n     * @type {module:zrender/container/Group|boolean}\n     */\n    this._creatingPanel;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._enableGlobalPan;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    if (__DEV__) {\n        this._mounted;\n    }\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._uid = 'brushController_' + baseUID++;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._handlers = {};\n    each$12(mouseHandlers, function (handler, eventName) {\n        this._handlers[eventName] = bind(handler, this);\n    }, this);\n}\n\nBrushController.prototype = {\n\n    constructor: BrushController,\n\n    /**\n     * If set to null/undefined/false, select disabled.\n     * @param {Object} brushOption\n     * @param {string|boolean} brushOption.brushType 'line', 'rect', 'polygon' or false\n     *                          If passing false/null/undefined, disable brush.\n     *                          If passing 'auto', determined by panel.defaultBrushType.\n     *                              ('auto' can not be used in global panel)\n     * @param {number} [brushOption.brushMode='single'] 'single' or 'multiple'\n     * @param {boolean} [brushOption.transformable=true]\n     * @param {boolean} [brushOption.removeOnClick=false]\n     * @param {Object} [brushOption.brushStyle]\n     * @param {number} [brushOption.brushStyle.width]\n     * @param {number} [brushOption.brushStyle.lineWidth]\n     * @param {string} [brushOption.brushStyle.stroke]\n     * @param {string} [brushOption.brushStyle.fill]\n     * @param {number} [brushOption.z]\n     */\n    enableBrush: function (brushOption) {\n        if (__DEV__) {\n            assert$1(this._mounted);\n        }\n\n        this._brushType && doDisableBrush(this);\n        brushOption.brushType && doEnableBrush(this, brushOption);\n\n        return this;\n    },\n\n    /**\n     * @param {Array.<Object>} panelOpts If not pass, it is global brush.\n     *        Each items: {\n     *            panelId, // mandatory.\n     *            clipPath, // mandatory. function.\n     *            isTargetByCursor, // mandatory. function.\n     *            defaultBrushType, // optional, only used when brushType is 'auto'.\n     *            getLinearBrushOtherExtent, // optional. function.\n     *        }\n     */\n    setPanels: function (panelOpts) {\n        if (panelOpts && panelOpts.length) {\n            var panels = this._panels = {};\n            each$1(panelOpts, function (panelOpts) {\n                panels[panelOpts.panelId] = clone(panelOpts);\n            });\n        }\n        else {\n            this._panels = null;\n        }\n        return this;\n    },\n\n    /**\n     * @param {Object} [opt]\n     * @return {boolean} [opt.enableGlobalPan=false]\n     */\n    mount: function (opt) {\n        opt = opt || {};\n\n        if (__DEV__) {\n            this._mounted = true; // should be at first.\n        }\n\n        this._enableGlobalPan = opt.enableGlobalPan;\n\n        var thisGroup = this.group;\n        this._zr.add(thisGroup);\n\n        thisGroup.attr({\n            position: opt.position || [0, 0],\n            rotation: opt.rotation || 0,\n            scale: opt.scale || [1, 1]\n        });\n        this._transform = thisGroup.getLocalTransform();\n\n        return this;\n    },\n\n    eachCover: function (cb, context) {\n        each$12(this._covers, cb, context);\n    },\n\n    /**\n     * Update covers.\n     * @param {Array.<Object>} brushOptionList Like:\n     *        [\n     *            {id: 'xx', brushType: 'line', range: [23, 44], brushStyle, transformable},\n     *            {id: 'yy', brushType: 'rect', range: [[23, 44], [23, 54]]},\n     *            ...\n     *        ]\n     *        `brushType` is required in each cover info. (can not be 'auto')\n     *        `id` is not mandatory.\n     *        `brushStyle`, `transformable` is not mandatory, use DEFAULT_BRUSH_OPT by default.\n     *        If brushOptionList is null/undefined, all covers removed.\n     */\n    updateCovers: function (brushOptionList) {\n        if (__DEV__) {\n            assert$1(this._mounted);\n        }\n\n        brushOptionList = map(brushOptionList, function (brushOption) {\n            return merge(clone(DEFAULT_BRUSH_OPT), brushOption, true);\n        });\n\n        var tmpIdPrefix = '\\0-brush-index-';\n        var oldCovers = this._covers;\n        var newCovers = this._covers = [];\n        var controller = this;\n        var creatingCover = this._creatingCover;\n\n        (new DataDiffer(oldCovers, brushOptionList, oldGetKey, getKey))\n            .add(addOrUpdate)\n            .update(addOrUpdate)\n            .remove(remove)\n            .execute();\n\n        return this;\n\n        function getKey(brushOption, index) {\n            return (brushOption.id != null ? brushOption.id : tmpIdPrefix + index)\n                + '-' + brushOption.brushType;\n        }\n\n        function oldGetKey(cover, index) {\n            return getKey(cover.__brushOption, index);\n        }\n\n        function addOrUpdate(newIndex, oldIndex) {\n            var newBrushOption = brushOptionList[newIndex];\n            // Consider setOption in event listener of brushSelect,\n            // where updating cover when creating should be forbiden.\n            if (oldIndex != null && oldCovers[oldIndex] === creatingCover) {\n                newCovers[newIndex] = oldCovers[oldIndex];\n            }\n            else {\n                var cover = newCovers[newIndex] = oldIndex != null\n                    ? (\n                        oldCovers[oldIndex].__brushOption = newBrushOption,\n                        oldCovers[oldIndex]\n                    )\n                    : endCreating(controller, createCover(controller, newBrushOption));\n                updateCoverAfterCreation(controller, cover);\n            }\n        }\n\n        function remove(oldIndex) {\n            if (oldCovers[oldIndex] !== creatingCover) {\n                controller.group.remove(oldCovers[oldIndex]);\n            }\n        }\n    },\n\n    unmount: function () {\n        if (__DEV__) {\n            if (!this._mounted) {\n                return;\n            }\n        }\n\n        this.enableBrush(false);\n\n        // container may 'removeAll' outside.\n        clearCovers(this);\n        this._zr.remove(this.group);\n\n        if (__DEV__) {\n            this._mounted = false; // should be at last.\n        }\n\n        return this;\n    },\n\n    dispose: function () {\n        this.unmount();\n        this.off();\n    }\n};\n\nmixin(BrushController, Eventful);\n\nfunction doEnableBrush(controller, brushOption) {\n    var zr = controller._zr;\n\n    // Consider roam, which takes globalPan too.\n    if (!controller._enableGlobalPan) {\n        take(zr, MUTEX_RESOURCE_KEY, controller._uid);\n    }\n\n    each$12(controller._handlers, function (handler, eventName) {\n        zr.on(eventName, handler);\n    });\n\n    controller._brushType = brushOption.brushType;\n    controller._brushOption = merge(clone(DEFAULT_BRUSH_OPT), brushOption, true);\n}\n\nfunction doDisableBrush(controller) {\n    var zr = controller._zr;\n\n    release(zr, MUTEX_RESOURCE_KEY, controller._uid);\n\n    each$12(controller._handlers, function (handler, eventName) {\n        zr.off(eventName, handler);\n    });\n\n    controller._brushType = controller._brushOption = null;\n}\n\nfunction createCover(controller, brushOption) {\n    var cover = coverRenderers[brushOption.brushType].createCover(controller, brushOption);\n    cover.__brushOption = brushOption;\n    updateZ$1(cover, brushOption);\n    controller.group.add(cover);\n    return cover;\n}\n\nfunction endCreating(controller, creatingCover) {\n    var coverRenderer = getCoverRenderer(creatingCover);\n    if (coverRenderer.endCreating) {\n        coverRenderer.endCreating(controller, creatingCover);\n        updateZ$1(creatingCover, creatingCover.__brushOption);\n    }\n    return creatingCover;\n}\n\nfunction updateCoverShape(controller, cover) {\n    var brushOption = cover.__brushOption;\n    getCoverRenderer(cover).updateCoverShape(\n        controller, cover, brushOption.range, brushOption\n    );\n}\n\nfunction updateZ$1(cover, brushOption) {\n    var z = brushOption.z;\n    z == null && (z = COVER_Z);\n    cover.traverse(function (el) {\n        el.z = z;\n        el.z2 = z; // Consider in given container.\n    });\n}\n\nfunction updateCoverAfterCreation(controller, cover) {\n    getCoverRenderer(cover).updateCommon(controller, cover);\n    updateCoverShape(controller, cover);\n}\n\nfunction getCoverRenderer(cover) {\n    return coverRenderers[cover.__brushOption.brushType];\n}\n\n// return target panel or `true` (means global panel)\nfunction getPanelByPoint(controller, e, localCursorPoint) {\n    var panels = controller._panels;\n    if (!panels) {\n        return true; // Global panel\n    }\n    var panel;\n    var transform = controller._transform;\n    each$12(panels, function (pn) {\n        pn.isTargetByCursor(e, localCursorPoint, transform) && (panel = pn);\n    });\n    return panel;\n}\n\n// Return a panel or true\nfunction getPanelByCover(controller, cover) {\n    var panels = controller._panels;\n    if (!panels) {\n        return true; // Global panel\n    }\n    var panelId = cover.__brushOption.panelId;\n    // User may give cover without coord sys info,\n    // which is then treated as global panel.\n    return panelId != null ? panels[panelId] : true;\n}\n\nfunction clearCovers(controller) {\n    var covers = controller._covers;\n    var originalLength = covers.length;\n    each$12(covers, function (cover) {\n        controller.group.remove(cover);\n    }, controller);\n    covers.length = 0;\n\n    return !!originalLength;\n}\n\nfunction trigger$1(controller, opt) {\n    var areas = map$2(controller._covers, function (cover) {\n        var brushOption = cover.__brushOption;\n        var range = clone(brushOption.range);\n        return {\n            brushType: brushOption.brushType,\n            panelId: brushOption.panelId,\n            range: range\n        };\n    });\n\n    controller.trigger('brush', areas, {\n        isEnd: !!opt.isEnd,\n        removeOnClick: !!opt.removeOnClick\n    });\n}\n\nfunction shouldShowCover(controller) {\n    var track = controller._track;\n\n    if (!track.length) {\n        return false;\n    }\n\n    var p2 = track[track.length - 1];\n    var p1 = track[0];\n    var dx = p2[0] - p1[0];\n    var dy = p2[1] - p1[1];\n    var dist = mathPow$2(dx * dx + dy * dy, 0.5);\n\n    return dist > UNSELECT_THRESHOLD;\n}\n\nfunction getTrackEnds(track) {\n    var tail = track.length - 1;\n    tail < 0 && (tail = 0);\n    return [track[0], track[tail]];\n}\n\nfunction createBaseRectCover(doDrift, controller, brushOption, edgeNames) {\n    var cover = new Group();\n\n    cover.add(new Rect({\n        name: 'main',\n        style: makeStyle(brushOption),\n        silent: true,\n        draggable: true,\n        cursor: 'move',\n        drift: curry$2(doDrift, controller, cover, 'nswe'),\n        ondragend: curry$2(trigger$1, controller, {isEnd: true})\n    }));\n\n    each$12(\n        edgeNames,\n        function (name) {\n            cover.add(new Rect({\n                name: name,\n                style: {opacity: 0},\n                draggable: true,\n                silent: true,\n                invisible: true,\n                drift: curry$2(doDrift, controller, cover, name),\n                ondragend: curry$2(trigger$1, controller, {isEnd: true})\n            }));\n        }\n    );\n\n    return cover;\n}\n\nfunction updateBaseRect(controller, cover, localRange, brushOption) {\n    var lineWidth = brushOption.brushStyle.lineWidth || 0;\n    var handleSize = mathMax$6(lineWidth, MIN_RESIZE_LINE_WIDTH);\n    var x = localRange[0][0];\n    var y = localRange[1][0];\n    var xa = x - lineWidth / 2;\n    var ya = y - lineWidth / 2;\n    var x2 = localRange[0][1];\n    var y2 = localRange[1][1];\n    var x2a = x2 - handleSize + lineWidth / 2;\n    var y2a = y2 - handleSize + lineWidth / 2;\n    var width = x2 - x;\n    var height = y2 - y;\n    var widtha = width + lineWidth;\n    var heighta = height + lineWidth;\n\n    updateRectShape(controller, cover, 'main', x, y, width, height);\n\n    if (brushOption.transformable) {\n        updateRectShape(controller, cover, 'w', xa, ya, handleSize, heighta);\n        updateRectShape(controller, cover, 'e', x2a, ya, handleSize, heighta);\n        updateRectShape(controller, cover, 'n', xa, ya, widtha, handleSize);\n        updateRectShape(controller, cover, 's', xa, y2a, widtha, handleSize);\n\n        updateRectShape(controller, cover, 'nw', xa, ya, handleSize, handleSize);\n        updateRectShape(controller, cover, 'ne', x2a, ya, handleSize, handleSize);\n        updateRectShape(controller, cover, 'sw', xa, y2a, handleSize, handleSize);\n        updateRectShape(controller, cover, 'se', x2a, y2a, handleSize, handleSize);\n    }\n}\n\nfunction updateCommon(controller, cover) {\n    var brushOption = cover.__brushOption;\n    var transformable = brushOption.transformable;\n\n    var mainEl = cover.childAt(0);\n    mainEl.useStyle(makeStyle(brushOption));\n    mainEl.attr({\n        silent: !transformable,\n        cursor: transformable ? 'move' : 'default'\n    });\n\n    each$12(\n        ['w', 'e', 'n', 's', 'se', 'sw', 'ne', 'nw'],\n        function (name) {\n            var el = cover.childOfName(name);\n            var globalDir = getGlobalDirection(controller, name);\n\n            el && el.attr({\n                silent: !transformable,\n                invisible: !transformable,\n                cursor: transformable ? CURSOR_MAP[globalDir] + '-resize' : null\n            });\n        }\n    );\n}\n\nfunction updateRectShape(controller, cover, name, x, y, w, h) {\n    var el = cover.childOfName(name);\n    el && el.setShape(pointsToRect(\n        clipByPanel(controller, cover, [[x, y], [x + w, y + h]])\n    ));\n}\n\nfunction makeStyle(brushOption) {\n    return defaults({strokeNoScale: true}, brushOption.brushStyle);\n}\n\nfunction formatRectRange(x, y, x2, y2) {\n    var min = [mathMin$6(x, x2), mathMin$6(y, y2)];\n    var max = [mathMax$6(x, x2), mathMax$6(y, y2)];\n\n    return [\n        [min[0], max[0]], // x range\n        [min[1], max[1]] // y range\n    ];\n}\n\nfunction getTransform$1(controller) {\n    return getTransform(controller.group);\n}\n\nfunction getGlobalDirection(controller, localDirection) {\n    if (localDirection.length > 1) {\n        localDirection = localDirection.split('');\n        var globalDir = [\n            getGlobalDirection(controller, localDirection[0]),\n            getGlobalDirection(controller, localDirection[1])\n        ];\n        (globalDir[0] === 'e' || globalDir[0] === 'w') && globalDir.reverse();\n        return globalDir.join('');\n    }\n    else {\n        var map$$1 = {w: 'left', e: 'right', n: 'top', s: 'bottom'};\n        var inverseMap = {left: 'w', right: 'e', top: 'n', bottom: 's'};\n        var globalDir = transformDirection(\n            map$$1[localDirection], getTransform$1(controller)\n        );\n        return inverseMap[globalDir];\n    }\n}\n\nfunction driftRect(toRectRange, fromRectRange, controller, cover, name, dx, dy, e) {\n    var brushOption = cover.__brushOption;\n    var rectRange = toRectRange(brushOption.range);\n    var localDelta = toLocalDelta(controller, dx, dy);\n\n    each$12(name.split(''), function (namePart) {\n        var ind = DIRECTION_MAP[namePart];\n        rectRange[ind[0]][ind[1]] += localDelta[ind[0]];\n    });\n\n    brushOption.range = fromRectRange(formatRectRange(\n        rectRange[0][0], rectRange[1][0], rectRange[0][1], rectRange[1][1]\n    ));\n\n    updateCoverAfterCreation(controller, cover);\n    trigger$1(controller, {isEnd: false});\n}\n\nfunction driftPolygon(controller, cover, dx, dy, e) {\n    var range = cover.__brushOption.range;\n    var localDelta = toLocalDelta(controller, dx, dy);\n\n    each$12(range, function (point) {\n        point[0] += localDelta[0];\n        point[1] += localDelta[1];\n    });\n\n    updateCoverAfterCreation(controller, cover);\n    trigger$1(controller, {isEnd: false});\n}\n\nfunction toLocalDelta(controller, dx, dy) {\n    var thisGroup = controller.group;\n    var localD = thisGroup.transformCoordToLocal(dx, dy);\n    var localZero = thisGroup.transformCoordToLocal(0, 0);\n\n    return [localD[0] - localZero[0], localD[1] - localZero[1]];\n}\n\nfunction clipByPanel(controller, cover, data) {\n    var panel = getPanelByCover(controller, cover);\n\n    return (panel && panel !== true)\n        ? panel.clipPath(data, controller._transform)\n        : clone(data);\n}\n\nfunction pointsToRect(points) {\n    var xmin = mathMin$6(points[0][0], points[1][0]);\n    var ymin = mathMin$6(points[0][1], points[1][1]);\n    var xmax = mathMax$6(points[0][0], points[1][0]);\n    var ymax = mathMax$6(points[0][1], points[1][1]);\n\n    return {\n        x: xmin,\n        y: ymin,\n        width: xmax - xmin,\n        height: ymax - ymin\n    };\n}\n\nfunction resetCursor(controller, e, localCursorPoint) {\n    // Check active\n    if (!controller._brushType) {\n        return;\n    }\n\n    var zr = controller._zr;\n    var covers = controller._covers;\n    var currPanel = getPanelByPoint(controller, e, localCursorPoint);\n\n    // Check whether in covers.\n    if (!controller._dragging) {\n        for (var i = 0; i < covers.length; i++) {\n            var brushOption = covers[i].__brushOption;\n            if (currPanel\n                && (currPanel === true || brushOption.panelId === currPanel.panelId)\n                && coverRenderers[brushOption.brushType].contain(\n                    covers[i], localCursorPoint[0], localCursorPoint[1]\n                )\n            ) {\n                // Use cursor style set on cover.\n                return;\n            }\n        }\n    }\n\n    currPanel && zr.setCursorStyle('crosshair');\n}\n\nfunction preventDefault(e) {\n    var rawE = e.event;\n    rawE.preventDefault && rawE.preventDefault();\n}\n\nfunction mainShapeContain(cover, x, y) {\n    return cover.childOfName('main').contain(x, y);\n}\n\nfunction updateCoverByMouse(controller, e, localCursorPoint, isEnd) {\n    var creatingCover = controller._creatingCover;\n    var panel = controller._creatingPanel;\n    var thisBrushOption = controller._brushOption;\n    var eventParams;\n\n    controller._track.push(localCursorPoint.slice());\n\n    if (shouldShowCover(controller) || creatingCover) {\n\n        if (panel && !creatingCover) {\n            thisBrushOption.brushMode === 'single' && clearCovers(controller);\n            var brushOption = clone(thisBrushOption);\n            brushOption.brushType = determineBrushType(brushOption.brushType, panel);\n            brushOption.panelId = panel === true ? null : panel.panelId;\n            creatingCover = controller._creatingCover = createCover(controller, brushOption);\n            controller._covers.push(creatingCover);\n        }\n\n        if (creatingCover) {\n            var coverRenderer = coverRenderers[determineBrushType(controller._brushType, panel)];\n            var coverBrushOption = creatingCover.__brushOption;\n\n            coverBrushOption.range = coverRenderer.getCreatingRange(\n                clipByPanel(controller, creatingCover, controller._track)\n            );\n\n            if (isEnd) {\n                endCreating(controller, creatingCover);\n                coverRenderer.updateCommon(controller, creatingCover);\n            }\n\n            updateCoverShape(controller, creatingCover);\n\n            eventParams = {isEnd: isEnd};\n        }\n    }\n    else if (\n        isEnd\n        && thisBrushOption.brushMode === 'single'\n        && thisBrushOption.removeOnClick\n    ) {\n        // Help user to remove covers easily, only by a tiny drag, in 'single' mode.\n        // But a single click do not clear covers, because user may have casual\n        // clicks (for example, click on other component and do not expect covers\n        // disappear).\n        // Only some cover removed, trigger action, but not every click trigger action.\n        if (getPanelByPoint(controller, e, localCursorPoint) && clearCovers(controller)) {\n            eventParams = {isEnd: isEnd, removeOnClick: true};\n        }\n    }\n\n    return eventParams;\n}\n\nfunction determineBrushType(brushType, panel) {\n    if (brushType === 'auto') {\n        if (__DEV__) {\n            assert$1(\n                panel && panel.defaultBrushType,\n                'MUST have defaultBrushType when brushType is \"atuo\"'\n            );\n        }\n        return panel.defaultBrushType;\n    }\n    return brushType;\n}\n\nvar mouseHandlers = {\n\n    mousedown: function (e) {\n        if (this._dragging) {\n            // In case some browser do not support globalOut,\n            // and release mose out side the browser.\n            handleDragEnd.call(this, e);\n        }\n        else if (!e.target || !e.target.draggable) {\n\n            preventDefault(e);\n\n            var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n\n            this._creatingCover = null;\n            var panel = this._creatingPanel = getPanelByPoint(this, e, localCursorPoint);\n\n            if (panel) {\n                this._dragging = true;\n                this._track = [localCursorPoint.slice()];\n            }\n        }\n    },\n\n    mousemove: function (e) {\n        var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n\n        resetCursor(this, e, localCursorPoint);\n\n        if (this._dragging) {\n\n            preventDefault(e);\n\n            var eventParams = updateCoverByMouse(this, e, localCursorPoint, false);\n\n            eventParams && trigger$1(this, eventParams);\n        }\n    },\n\n    mouseup: handleDragEnd //,\n\n    // FIXME\n    // in tooltip, globalout should not be triggered.\n    // globalout: handleDragEnd\n};\n\nfunction handleDragEnd(e) {\n    if (this._dragging) {\n\n        preventDefault(e);\n\n        var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n        var eventParams = updateCoverByMouse(this, e, localCursorPoint, true);\n\n        this._dragging = false;\n        this._track = [];\n        this._creatingCover = null;\n\n        // trigger event shoule be at final, after procedure will be nested.\n        eventParams && trigger$1(this, eventParams);\n    }\n}\n\n/**\n * key: brushType\n * @type {Object}\n */\nvar coverRenderers = {\n\n    lineX: getLineRenderer(0),\n\n    lineY: getLineRenderer(1),\n\n    rect: {\n        createCover: function (controller, brushOption) {\n            return createBaseRectCover(\n                curry$2(\n                    driftRect,\n                    function (range) {\n                        return range;\n                    },\n                    function (range) {\n                        return range;\n                    }\n                ),\n                controller,\n                brushOption,\n                ['w', 'e', 'n', 's', 'se', 'sw', 'ne', 'nw']\n            );\n        },\n        getCreatingRange: function (localTrack) {\n            var ends = getTrackEnds(localTrack);\n            return formatRectRange(ends[1][0], ends[1][1], ends[0][0], ends[0][1]);\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            updateBaseRect(controller, cover, localRange, brushOption);\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    },\n\n    polygon: {\n        createCover: function (controller, brushOption) {\n            var cover = new Group();\n\n            // Do not use graphic.Polygon because graphic.Polyline do not close the\n            // border of the shape when drawing, which is a better experience for user.\n            cover.add(new Polyline({\n                name: 'main',\n                style: makeStyle(brushOption),\n                silent: true\n            }));\n\n            return cover;\n        },\n        getCreatingRange: function (localTrack) {\n            return localTrack;\n        },\n        endCreating: function (controller, cover) {\n            cover.remove(cover.childAt(0));\n            // Use graphic.Polygon close the shape.\n            cover.add(new Polygon({\n                name: 'main',\n                draggable: true,\n                drift: curry$2(driftPolygon, controller, cover),\n                ondragend: curry$2(trigger$1, controller, {isEnd: true})\n            }));\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            cover.childAt(0).setShape({\n                points: clipByPanel(controller, cover, localRange)\n            });\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    }\n};\n\nfunction getLineRenderer(xyIndex) {\n    return {\n        createCover: function (controller, brushOption) {\n            return createBaseRectCover(\n                curry$2(\n                    driftRect,\n                    function (range) {\n                        var rectRange = [range, [0, 100]];\n                        xyIndex && rectRange.reverse();\n                        return rectRange;\n                    },\n                    function (rectRange) {\n                        return rectRange[xyIndex];\n                    }\n                ),\n                controller,\n                brushOption,\n                [['w', 'e'], ['n', 's']][xyIndex]\n            );\n        },\n        getCreatingRange: function (localTrack) {\n            var ends = getTrackEnds(localTrack);\n            var min = mathMin$6(ends[0][xyIndex], ends[1][xyIndex]);\n            var max = mathMax$6(ends[0][xyIndex], ends[1][xyIndex]);\n\n            return [min, max];\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            var otherExtent;\n            // If brushWidth not specified, fit the panel.\n            var panel = getPanelByCover(controller, cover);\n            if (panel !== true && panel.getLinearBrushOtherExtent) {\n                otherExtent = panel.getLinearBrushOtherExtent(\n                    xyIndex, controller._transform\n                );\n            }\n            else {\n                var zr = controller._zr;\n                otherExtent = [0, [zr.getWidth(), zr.getHeight()][1 - xyIndex]];\n            }\n            var rectRange = [localRange, otherExtent];\n            xyIndex && rectRange.reverse();\n\n            updateBaseRect(controller, cover, rectRange, brushOption);\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction makeRectPanelClipPath(rect) {\n    rect = normalizeRect(rect);\n    return function (localPoints, transform) {\n        return clipPointsByRect(localPoints, rect);\n    };\n}\n\nfunction makeLinearBrushOtherExtent(rect, specifiedXYIndex) {\n    rect = normalizeRect(rect);\n    return function (xyIndex) {\n        var idx = specifiedXYIndex != null ? specifiedXYIndex : xyIndex;\n        var brushWidth = idx ? rect.width : rect.height;\n        var base = idx ? rect.x : rect.y;\n        return [base, base + (brushWidth || 0)];\n    };\n}\n\nfunction makeRectIsTargetByCursor(rect, api, targetModel) {\n    rect = normalizeRect(rect);\n    return function (e, localCursorPoint, transform) {\n        return rect.contain(localCursorPoint[0], localCursorPoint[1])\n            && !onIrrelevantElement(e, api, targetModel);\n    };\n}\n\n// Consider width/height is negative.\nfunction normalizeRect(rect) {\n    return BoundingRect.create(rect);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar elementList = ['axisLine', 'axisTickLabel', 'axisName'];\n\nvar AxisView$2 = extendComponentView({\n\n    type: 'parallelAxis',\n\n    /**\n     * @override\n     */\n    init: function (ecModel, api) {\n        AxisView$2.superApply(this, 'init', arguments);\n\n        /**\n         * @type {module:echarts/component/helper/BrushController}\n         */\n        (this._brushController = new BrushController(api.getZr()))\n            .on('brush', bind(this._onBrush, this));\n    },\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n        if (fromAxisAreaSelect(axisModel, ecModel, payload)) {\n            return;\n        }\n\n        this.axisModel = axisModel;\n        this.api = api;\n\n        this.group.removeAll();\n\n        var oldAxisGroup = this._axisGroup;\n        this._axisGroup = new Group();\n        this.group.add(this._axisGroup);\n\n        if (!axisModel.get('show')) {\n            return;\n        }\n\n        var coordSysModel = getCoordSysModel(axisModel, ecModel);\n        var coordSys = coordSysModel.coordinateSystem;\n\n        var areaSelectStyle = axisModel.getAreaSelectStyle();\n        var areaWidth = areaSelectStyle.width;\n\n        var dim = axisModel.axis.dim;\n        var axisLayout = coordSys.getAxisLayout(dim);\n\n        var builderOpt = extend(\n            {strokeContainThreshold: areaWidth},\n            axisLayout\n        );\n\n        var axisBuilder = new AxisBuilder(axisModel, builderOpt);\n\n        each$1(elementList, axisBuilder.add, axisBuilder);\n\n        this._axisGroup.add(axisBuilder.getGroup());\n\n        this._refreshBrushController(\n            builderOpt, areaSelectStyle, axisModel, coordSysModel, areaWidth, api\n        );\n\n        var animationModel = (payload && payload.animation === false) ? null : axisModel;\n        groupTransition(oldAxisGroup, this._axisGroup, animationModel);\n    },\n\n    // /**\n    //  * @override\n    //  */\n    // updateVisual: function (axisModel, ecModel, api, payload) {\n    //     this._brushController && this._brushController\n    //         .updateCovers(getCoverInfoList(axisModel));\n    // },\n\n    _refreshBrushController: function (\n        builderOpt, areaSelectStyle, axisModel, coordSysModel, areaWidth, api\n    ) {\n        // After filtering, axis may change, select area needs to be update.\n        var extent = axisModel.axis.getExtent();\n        var extentLen = extent[1] - extent[0];\n        var extra = Math.min(30, Math.abs(extentLen) * 0.1); // Arbitrary value.\n\n        // width/height might be negative, which will be\n        // normalized in BoundingRect.\n        var rect = BoundingRect.create({\n            x: extent[0],\n            y: -areaWidth / 2,\n            width: extentLen,\n            height: areaWidth\n        });\n        rect.x -= extra;\n        rect.width += 2 * extra;\n\n        this._brushController\n            .mount({\n                enableGlobalPan: true,\n                rotation: builderOpt.rotation,\n                position: builderOpt.position\n            })\n            .setPanels([{\n                panelId: 'pl',\n                clipPath: makeRectPanelClipPath(rect),\n                isTargetByCursor: makeRectIsTargetByCursor(rect, api, coordSysModel),\n                getLinearBrushOtherExtent: makeLinearBrushOtherExtent(rect, 0)\n            }])\n            .enableBrush({\n                brushType: 'lineX',\n                brushStyle: areaSelectStyle,\n                removeOnClick: true\n            })\n            .updateCovers(getCoverInfoList(axisModel));\n    },\n\n    _onBrush: function (coverInfoList, opt) {\n        // Do not cache these object, because the mey be changed.\n        var axisModel = this.axisModel;\n        var axis = axisModel.axis;\n        var intervals = map(coverInfoList, function (coverInfo) {\n            return [\n                axis.coordToData(coverInfo.range[0], true),\n                axis.coordToData(coverInfo.range[1], true)\n            ];\n        });\n\n        // If realtime is true, action is not dispatched on drag end, because\n        // the drag end emits the same params with the last drag move event,\n        // and may have some delay when using touch pad.\n        if (!axisModel.option.realtime === opt.isEnd || opt.removeOnClick) { // jshint ignore:line\n            this.api.dispatchAction({\n                type: 'axisAreaSelect',\n                parallelAxisId: axisModel.id,\n                intervals: intervals\n            });\n        }\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._brushController.dispose();\n    }\n});\n\nfunction fromAxisAreaSelect(axisModel, ecModel, payload) {\n    return payload\n        && payload.type === 'axisAreaSelect'\n        && ecModel.findComponents(\n            {mainType: 'parallelAxis', query: payload}\n        )[0] === axisModel;\n}\n\nfunction getCoverInfoList(axisModel) {\n    var axis = axisModel.axis;\n    return map(axisModel.activeIntervals, function (interval) {\n        return {\n            brushType: 'lineX',\n            panelId: 'pl',\n            range: [\n                axis.dataToCoord(interval[0], true),\n                axis.dataToCoord(interval[1], true)\n            ]\n        };\n    });\n}\n\nfunction getCoordSysModel(axisModel, ecModel) {\n    return ecModel.getComponent(\n        'parallel', axisModel.get('parallelIndex')\n    );\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar CLICK_THRESHOLD = 5; // > 4\n\n// Parallel view\nextendComponentView({\n    type: 'parallel',\n\n    render: function (parallelModel, ecModel, api) {\n        this._model = parallelModel;\n        this._api = api;\n\n        if (!this._handlers) {\n            this._handlers = {};\n            each$1(handlers, function (handler, eventName) {\n                api.getZr().on(eventName, this._handlers[eventName] = bind(handler, this));\n            }, this);\n        }\n\n        createOrUpdate(\n            this,\n            '_throttledDispatchExpand',\n            parallelModel.get('axisExpandRate'),\n            'fixRate'\n        );\n    },\n\n    dispose: function (ecModel, api) {\n        each$1(this._handlers, function (handler, eventName) {\n            api.getZr().off(eventName, handler);\n        });\n        this._handlers = null;\n    },\n\n    /**\n     * @param {Object} [opt] If null, cancle the last action triggering for debounce.\n     */\n    _throttledDispatchExpand: function (opt) {\n        this._dispatchExpand(opt);\n    },\n\n    _dispatchExpand: function (opt) {\n        opt && this._api.dispatchAction(\n            extend({type: 'parallelAxisExpand'}, opt)\n        );\n    }\n\n});\n\nvar handlers = {\n\n    mousedown: function (e) {\n        if (checkTrigger(this, 'click')) {\n            this._mouseDownPoint = [e.offsetX, e.offsetY];\n        }\n    },\n\n    mouseup: function (e) {\n        var mouseDownPoint = this._mouseDownPoint;\n\n        if (checkTrigger(this, 'click') && mouseDownPoint) {\n            var point = [e.offsetX, e.offsetY];\n            var dist = Math.pow(mouseDownPoint[0] - point[0], 2)\n                + Math.pow(mouseDownPoint[1] - point[1], 2);\n\n            if (dist > CLICK_THRESHOLD) {\n                return;\n            }\n\n            var result = this._model.coordinateSystem.getSlidedAxisExpandWindow(\n                [e.offsetX, e.offsetY]\n            );\n\n            result.behavior !== 'none' && this._dispatchExpand({\n                axisExpandWindow: result.axisExpandWindow\n            });\n        }\n\n        this._mouseDownPoint = null;\n    },\n\n    mousemove: function (e) {\n        // Should do nothing when brushing.\n        if (this._mouseDownPoint || !checkTrigger(this, 'mousemove')) {\n            return;\n        }\n        var model = this._model;\n        var result = model.coordinateSystem.getSlidedAxisExpandWindow(\n            [e.offsetX, e.offsetY]\n        );\n\n        var behavior = result.behavior;\n        behavior === 'jump' && this._throttledDispatchExpand.debounceNextCall(model.get('axisExpandDebounce'));\n        this._throttledDispatchExpand(\n            behavior === 'none'\n                ? null // Cancle the last trigger, in case that mouse slide out of the area quickly.\n                : {\n                    axisExpandWindow: result.axisExpandWindow,\n                    // Jumping uses animation, and sliding suppresses animation.\n                    animation: behavior === 'jump' ? null : false\n                }\n        );\n    }\n};\n\nfunction checkTrigger(view, triggerOn) {\n    var model = view._model;\n    return model.get('axisExpandable') && model.get('axisExpandTriggerOn') === triggerOn;\n}\n\nregisterPreprocessor(parallelPreprocessor);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.parallel',\n\n    dependencies: ['parallel'],\n\n    visualColorAccessPath: 'lineStyle.color',\n\n    getInitialData: function (option, ecModel) {\n        var source = this.getSource();\n\n        setEncodeAndDimensions(source, this);\n\n        return createListFromArray(source, this);\n    },\n\n    /**\n     * User can get data raw indices on 'axisAreaSelected' event received.\n     *\n     * @public\n     * @param {string} activeState 'active' or 'inactive' or 'normal'\n     * @return {Array.<number>} Raw indices\n     */\n    getRawIndicesByActiveState: function (activeState) {\n        var coordSys = this.coordinateSystem;\n        var data = this.getData();\n        var indices = [];\n\n        coordSys.eachActiveState(data, function (theActiveState, dataIndex) {\n            if (activeState === theActiveState) {\n                indices.push(data.getRawIndex(dataIndex));\n            }\n        });\n\n        return indices;\n    },\n\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n\n        coordinateSystem: 'parallel',\n        parallelIndex: 0,\n\n        label: {\n            show: false\n        },\n\n        inactiveOpacity: 0.05,\n        activeOpacity: 1,\n\n        lineStyle: {\n            width: 1,\n            opacity: 0.45,\n            type: 'solid'\n        },\n        emphasis: {\n            label: {\n                show: false\n            }\n        },\n\n        progressive: 500,\n        smooth: false, // true | false | number\n\n        animationEasing: 'linear'\n    }\n});\n\nfunction setEncodeAndDimensions(source, seriesModel) {\n    // The mapping of parallelAxis dimension to data dimension can\n    // be specified in parallelAxis.option.dim. For example, if\n    // parallelAxis.option.dim is 'dim3', it mapping to the third\n    // dimension of data. But `data.encode` has higher priority.\n    // Moreover, parallelModel.dimension should not be regarded as data\n    // dimensions. Consider dimensions = ['dim4', 'dim2', 'dim6'];\n\n    if (source.encodeDefine) {\n        return;\n    }\n\n    var parallelModel = seriesModel.ecModel.getComponent(\n        'parallel', seriesModel.get('parallelIndex')\n    );\n    if (!parallelModel) {\n        return;\n    }\n\n    var encodeDefine = source.encodeDefine = createHashMap();\n    each$1(parallelModel.dimensions, function (axisDim) {\n        var dataDimIndex = convertDimNameToNumber(axisDim);\n        encodeDefine.set(axisDim, dataDimIndex);\n    });\n}\n\nfunction convertDimNameToNumber(dimName) {\n    return +dimName.replace('dim', '');\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DEFAULT_SMOOTH = 0.3;\n\nvar ParallelView = Chart.extend({\n\n    type: 'parallel',\n\n    init: function () {\n\n        /**\n         * @type {module:zrender/container/Group}\n         * @private\n         */\n        this._dataGroup = new Group();\n\n        this.group.add(this._dataGroup);\n\n        /**\n         * @type {module:echarts/data/List}\n         */\n        this._data;\n\n        /**\n         * @type {boolean}\n         */\n        this._initialized;\n    },\n\n    /**\n     * @override\n     */\n    render: function (seriesModel, ecModel, api, payload) {\n        var dataGroup = this._dataGroup;\n        var data = seriesModel.getData();\n        var oldData = this._data;\n        var coordSys = seriesModel.coordinateSystem;\n        var dimensions = coordSys.dimensions;\n        var seriesScope = makeSeriesScope$2(seriesModel);\n\n        data.diff(oldData)\n            .add(add)\n            .update(update)\n            .remove(remove)\n            .execute();\n\n        function add(newDataIndex) {\n            var line = addEl(data, dataGroup, newDataIndex, dimensions, coordSys);\n            updateElCommon(line, data, newDataIndex, seriesScope);\n        }\n\n        function update(newDataIndex, oldDataIndex) {\n            var line = oldData.getItemGraphicEl(oldDataIndex);\n            var points = createLinePoints(data, newDataIndex, dimensions, coordSys);\n            data.setItemGraphicEl(newDataIndex, line);\n            var animationModel = (payload && payload.animation === false) ? null : seriesModel;\n            updateProps(line, {shape: {points: points}}, animationModel, newDataIndex);\n\n            updateElCommon(line, data, newDataIndex, seriesScope);\n        }\n\n        function remove(oldDataIndex) {\n            var line = oldData.getItemGraphicEl(oldDataIndex);\n            dataGroup.remove(line);\n        }\n\n        // First create\n        if (!this._initialized) {\n            this._initialized = true;\n            var clipPath = createGridClipShape$1(\n                coordSys, seriesModel, function () {\n                    // Callback will be invoked immediately if there is no animation\n                    setTimeout(function () {\n                        dataGroup.removeClipPath();\n                    });\n                }\n            );\n            dataGroup.setClipPath(clipPath);\n        }\n\n        this._data = data;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this._initialized = true;\n        this._data = null;\n        this._dataGroup.removeAll();\n    },\n\n    incrementalRender: function (taskParams, seriesModel, ecModel) {\n        var data = seriesModel.getData();\n        var coordSys = seriesModel.coordinateSystem;\n        var dimensions = coordSys.dimensions;\n        var seriesScope = makeSeriesScope$2(seriesModel);\n\n        for (var dataIndex = taskParams.start; dataIndex < taskParams.end; dataIndex++) {\n            var line = addEl(data, this._dataGroup, dataIndex, dimensions, coordSys);\n            line.incremental = true;\n            updateElCommon(line, data, dataIndex, seriesScope);\n        }\n    },\n\n    dispose: function () {},\n\n    // _renderForProgressive: function (seriesModel) {\n    //     var dataGroup = this._dataGroup;\n    //     var data = seriesModel.getData();\n    //     var oldData = this._data;\n    //     var coordSys = seriesModel.coordinateSystem;\n    //     var dimensions = coordSys.dimensions;\n    //     var option = seriesModel.option;\n    //     var progressive = option.progressive;\n    //     var smooth = option.smooth ? SMOOTH : null;\n\n    //     // In progressive animation is disabled, so use simple data diff,\n    //     // which effects performance less.\n    //     // (Typically performance for data with length 7000+ like:\n    //     // simpleDiff: 60ms, addEl: 184ms,\n    //     // in RMBP 2.4GHz intel i7, OSX 10.9 chrome 50.0.2661.102 (64-bit))\n    //     if (simpleDiff(oldData, data, dimensions)) {\n    //         dataGroup.removeAll();\n    //         data.each(function (dataIndex) {\n    //             addEl(data, dataGroup, dataIndex, dimensions, coordSys);\n    //         });\n    //     }\n\n    //     updateElCommon(data, progressive, smooth);\n\n    //     // Consider switch between progressive and not.\n    //     data.__plProgressive = true;\n    //     this._data = data;\n    // },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this._dataGroup && this._dataGroup.removeAll();\n        this._data = null;\n    }\n});\n\nfunction createGridClipShape$1(coordSys, seriesModel, cb) {\n    var parallelModel = coordSys.model;\n    var rect = coordSys.getRect();\n    var rectEl = new Rect({\n        shape: {\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        }\n    });\n\n    var dim = parallelModel.get('layout') === 'horizontal' ? 'width' : 'height';\n    rectEl.setShape(dim, 0);\n    initProps(rectEl, {\n        shape: {\n            width: rect.width,\n            height: rect.height\n        }\n    }, seriesModel, cb);\n    return rectEl;\n}\n\nfunction createLinePoints(data, dataIndex, dimensions, coordSys) {\n    var points = [];\n    for (var i = 0; i < dimensions.length; i++) {\n        var dimName = dimensions[i];\n        var value = data.get(data.mapDimension(dimName), dataIndex);\n        if (!isEmptyValue(value, coordSys.getAxis(dimName).type)) {\n            points.push(coordSys.dataToPoint(value, dimName));\n        }\n    }\n    return points;\n}\n\nfunction addEl(data, dataGroup, dataIndex, dimensions, coordSys) {\n    var points = createLinePoints(data, dataIndex, dimensions, coordSys);\n    var line = new Polyline({\n        shape: {points: points},\n        silent: true,\n        z2: 10\n    });\n    dataGroup.add(line);\n    data.setItemGraphicEl(dataIndex, line);\n    return line;\n}\n\nfunction makeSeriesScope$2(seriesModel) {\n    var smooth = seriesModel.get('smooth', true);\n    smooth === true && (smooth = DEFAULT_SMOOTH);\n    return {\n        lineStyle: seriesModel.getModel('lineStyle').getLineStyle(),\n        smooth: smooth != null ? smooth : DEFAULT_SMOOTH\n    };\n}\n\nfunction updateElCommon(el, data, dataIndex, seriesScope) {\n    var lineStyle = seriesScope.lineStyle;\n\n    if (data.hasItemOption) {\n        var lineStyleModel = data.getItemModel(dataIndex).getModel('lineStyle');\n        lineStyle = lineStyleModel.getLineStyle();\n    }\n\n    el.useStyle(lineStyle);\n\n    var elStyle = el.style;\n    elStyle.fill = null;\n    // lineStyle.color have been set to itemVisual in module:echarts/visual/seriesColor.\n    elStyle.stroke = data.getItemVisual(dataIndex, 'color');\n    // lineStyle.opacity have been set to itemVisual in parallelVisual.\n    elStyle.opacity = data.getItemVisual(dataIndex, 'opacity');\n\n    seriesScope.smooth && (el.shape.smooth = seriesScope.smooth);\n}\n\n// function simpleDiff(oldData, newData, dimensions) {\n//     var oldLen;\n//     if (!oldData\n//         || !oldData.__plProgressive\n//         || (oldLen = oldData.count()) !== newData.count()\n//     ) {\n//         return true;\n//     }\n\n//     var dimLen = dimensions.length;\n//     for (var i = 0; i < oldLen; i++) {\n//         for (var j = 0; j < dimLen; j++) {\n//             if (oldData.get(dimensions[j], i) !== newData.get(dimensions[j], i)) {\n//                 return true;\n//             }\n//         }\n//     }\n\n//     return false;\n// }\n\n// FIXME\n// 公用方法?\nfunction isEmptyValue(val, axisType) {\n    return axisType === 'category'\n        ? val == null\n        : (val == null || isNaN(val)); // axisType === 'value'\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar opacityAccessPath$1 = ['lineStyle', 'normal', 'opacity'];\n\nvar parallelVisual = {\n\n    seriesType: 'parallel',\n\n    reset: function (seriesModel, ecModel, api) {\n\n        var itemStyleModel = seriesModel.getModel('itemStyle');\n        var lineStyleModel = seriesModel.getModel('lineStyle');\n        var globalColors = ecModel.get('color');\n\n        var color = lineStyleModel.get('color')\n            || itemStyleModel.get('color')\n            || globalColors[seriesModel.seriesIndex % globalColors.length];\n        var inactiveOpacity = seriesModel.get('inactiveOpacity');\n        var activeOpacity = seriesModel.get('activeOpacity');\n        var lineStyle = seriesModel.getModel('lineStyle').getLineStyle();\n\n        var coordSys = seriesModel.coordinateSystem;\n        var data = seriesModel.getData();\n\n        var opacityMap = {\n            normal: lineStyle.opacity,\n            active: activeOpacity,\n            inactive: inactiveOpacity\n        };\n\n        data.setVisual('color', color);\n\n        function progress(params, data) {\n            coordSys.eachActiveState(data, function (activeState, dataIndex) {\n                var opacity = opacityMap[activeState];\n                if (activeState === 'normal' && data.hasItemOption) {\n                    var itemOpacity = data.getItemModel(dataIndex).get(opacityAccessPath$1, true);\n                    itemOpacity != null && (opacity = itemOpacity);\n                }\n                data.setItemVisual(dataIndex, 'opacity', opacity);\n            }, params.start, params.end);\n        }\n\n        return {progress: progress};\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(parallelVisual);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Get initial data and define sankey view's series model\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar SankeySeries = SeriesModel.extend({\n\n    type: 'series.sankey',\n\n    layoutInfo: null,\n\n    /**\n     * Init a graph data structure from data in option series\n     *\n     * @param  {Object} option  the object used to config echarts view\n     * @return {module:echarts/data/List} storage initial data\n     */\n    getInitialData: function (option) {\n        var links = option.edges || option.links;\n        var nodes = option.data || option.nodes;\n        if (nodes && links) {\n            var graph = createGraphFromNodeEdge(nodes, links, this, true);\n            return graph.data;\n        }\n    },\n\n    setNodePosition: function (dataIndex, localPosition) {\n        var dataItem = this.option.data[dataIndex];\n        dataItem.localX = localPosition[0];\n        dataItem.localY = localPosition[1];\n    },\n\n    /**\n     * Return the graphic data structure\n     *\n     * @return {module:echarts/data/Graph} graphic data structure\n     */\n    getGraph: function () {\n        return this.getData().graph;\n    },\n\n    /**\n     * Get edge data of graphic data structure\n     *\n     * @return {module:echarts/data/List} data structure of list\n     */\n    getEdgeData: function () {\n        return this.getGraph().edgeData;\n    },\n\n    /**\n     * @override\n     */\n    formatTooltip: function (dataIndex, multipleSeries, dataType) {\n        // dataType === 'node' or empty do not show tooltip by default\n        if (dataType === 'edge') {\n            var params = this.getDataParams(dataIndex, dataType);\n            var rawDataOpt = params.data;\n            var html = rawDataOpt.source + ' -- ' + rawDataOpt.target;\n            if (params.value) {\n                html += ' : ' + params.value;\n            }\n            return encodeHTML(html);\n        }\n\n        return SankeySeries.superCall(this, 'formatTooltip', dataIndex, multipleSeries);\n    },\n\n    optionUpdated: function () {\n        var option = this.option;\n        if (option.focusNodeAdjacency === true) {\n            option.focusNodeAdjacency = 'allEdges';\n        }\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n\n        coordinateSystem: 'view',\n\n        layout: null,\n\n        // The position of the whole view\n        left: '5%',\n        top: '5%',\n        right: '20%',\n        bottom: '5%',\n\n        // Value can be 'vertical'\n        orient: 'horizontal',\n\n        // The dx of the node\n        nodeWidth: 20,\n\n        // The vertical distance between two nodes\n        nodeGap: 8,\n\n        // Control if the node can move or not\n        draggable: true,\n\n        // Value can be 'inEdges', 'outEdges', 'allEdges', true (the same as 'allEdges').\n        focusNodeAdjacency: false,\n\n        // The number of iterations to change the position of the node\n        layoutIterations: 32,\n\n        label: {\n            show: true,\n            position: 'right',\n            color: '#000',\n            fontSize: 12\n        },\n\n        itemStyle: {\n            borderWidth: 1,\n            borderColor: '#333'\n        },\n\n        lineStyle: {\n            color: '#314656',\n            opacity: 0.2,\n            curveness: 0.5\n        },\n\n        emphasis: {\n            label: {\n                show: true\n            },\n            lineStyle: {\n                opacity: 0.6\n            }\n        },\n\n        animationEasing: 'linear',\n\n        animationDuration: 1000\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file  The file used to draw sankey view\n * @author  Deqing Li(annong035@gmail.com)\n */\n\nvar nodeOpacityPath$1 = ['itemStyle', 'opacity'];\nvar lineOpacityPath$1 = ['lineStyle', 'opacity'];\n\nfunction getItemOpacity$1(item, opacityPath) {\n    return item.getVisual('opacity') || item.getModel().get(opacityPath);\n}\n\nfunction fadeOutItem$1(item, opacityPath, opacityRatio) {\n    var el = item.getGraphicEl();\n\n    var opacity = getItemOpacity$1(item, opacityPath);\n    if (opacityRatio != null) {\n        opacity == null && (opacity = 1);\n        opacity *= opacityRatio;\n    }\n\n    el.downplay && el.downplay();\n    el.traverse(function (child) {\n        if (child.type !== 'group') {\n            child.setStyle('opacity', opacity);\n        }\n    });\n}\n\nfunction fadeInItem$1(item, opacityPath) {\n    var opacity = getItemOpacity$1(item, opacityPath);\n    var el = item.getGraphicEl();\n\n    el.highlight && el.highlight();\n    el.traverse(function (child) {\n        if (child.type !== 'group') {\n            child.setStyle('opacity', opacity);\n        }\n    });\n}\n\nvar SankeyShape = extendShape({\n    shape: {\n        x1: 0, y1: 0,\n        x2: 0, y2: 0,\n        cpx1: 0, cpy1: 0,\n        cpx2: 0, cpy2: 0,\n        extent: 0,\n        orient: ''\n    },\n\n    buildPath: function (ctx, shape) {\n        var extent = shape.extent;\n        var orient = shape.orient;\n        if (orient === 'vertical') {\n            ctx.moveTo(shape.x1, shape.y1);\n            ctx.bezierCurveTo(\n                shape.cpx1, shape.cpy1,\n                shape.cpx2, shape.cpy2,\n                shape.x2, shape.y2\n            );\n            ctx.lineTo(shape.x2 + extent, shape.y2);\n            ctx.bezierCurveTo(\n                shape.cpx2 + extent, shape.cpy2,\n                shape.cpx1 + extent, shape.cpy1,\n                shape.x1 + extent, shape.y1\n            );\n        }\n        else {\n            ctx.moveTo(shape.x1, shape.y1);\n            ctx.bezierCurveTo(\n                shape.cpx1, shape.cpy1,\n                shape.cpx2, shape.cpy2,\n                shape.x2, shape.y2\n            );\n            ctx.lineTo(shape.x2, shape.y2 + extent);\n            ctx.bezierCurveTo(\n                shape.cpx2, shape.cpy2 + extent,\n                shape.cpx1, shape.cpy1 + extent,\n                shape.x1, shape.y1 + extent\n            );\n        }\n        ctx.closePath();\n    }\n});\n\nextendChartView({\n\n    type: 'sankey',\n\n    /**\n     * @private\n     * @type {module:echarts/chart/sankey/SankeySeries}\n     */\n    _model: null,\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    _focusAdjacencyDisabled: false,\n\n    render: function (seriesModel, ecModel, api) {\n        var sankeyView = this;\n        var graph = seriesModel.getGraph();\n        var group = this.group;\n        var layoutInfo = seriesModel.layoutInfo;\n        // view width\n        var width = layoutInfo.width;\n        // view height\n        var height = layoutInfo.height;\n        var nodeData = seriesModel.getData();\n        var edgeData = seriesModel.getData('edge');\n        var orient = seriesModel.get('orient');\n\n        this._model = seriesModel;\n\n        group.removeAll();\n\n        group.attr('position', [layoutInfo.x, layoutInfo.y]);\n\n        // generate a bezire Curve for each edge\n        graph.eachEdge(function (edge) {\n            var curve = new SankeyShape();\n            curve.dataIndex = edge.dataIndex;\n            curve.seriesIndex = seriesModel.seriesIndex;\n            curve.dataType = 'edge';\n            var lineStyleModel = edge.getModel('lineStyle');\n            var curvature = lineStyleModel.get('curveness');\n            var n1Layout = edge.node1.getLayout();\n            var node1Model = edge.node1.getModel();\n            var dragX1 = node1Model.get('localX');\n            var dragY1 = node1Model.get('localY');\n            var n2Layout = edge.node2.getLayout();\n            var node2Model = edge.node2.getModel();\n            var dragX2 = node2Model.get('localX');\n            var dragY2 = node2Model.get('localY');\n            var edgeLayout = edge.getLayout();\n            var x1;\n            var y1;\n            var x2;\n            var y2;\n            var cpx1;\n            var cpy1;\n            var cpx2;\n            var cpy2;\n\n            curve.shape.extent = Math.max(1, edgeLayout.dy);\n            curve.shape.orient = orient;\n\n            if (orient === 'vertical') {\n                x1 = (dragX1 != null ? dragX1 * width : n1Layout.x) + edgeLayout.sy;\n                y1 = (dragY1 != null ? dragY1 * height : n1Layout.y) + n1Layout.dy;\n                x2 = (dragX2 != null ? dragX2 * width : n2Layout.x) + edgeLayout.ty;\n                y2 = dragY2 != null ? dragY2 * height : n2Layout.y;\n                cpx1 = x1;\n                cpy1 = y1 * (1 - curvature) + y2 * curvature;\n                cpx2 = x2;\n                cpy2 = y1 * curvature + y2 * (1 - curvature);\n            }\n            else {\n                x1 = (dragX1 != null ? dragX1 * width : n1Layout.x) + n1Layout.dx;\n                y1 = (dragY1 != null ? dragY1 * height : n1Layout.y) + edgeLayout.sy;\n                x2 = dragX2 != null ? dragX2 * width : n2Layout.x;\n                y2 = (dragY2 != null ? dragY2 * height : n2Layout.y) + edgeLayout.ty;\n                cpx1 = x1 * (1 - curvature) + x2 * curvature;\n                cpy1 = y1;\n                cpx2 = x1 * curvature + x2 * (1 - curvature);\n                cpy2 = y2;\n            }\n\n            curve.setShape({\n                x1: x1,\n                y1: y1,\n                x2: x2,\n                y2: y2,\n                cpx1: cpx1,\n                cpy1: cpy1,\n                cpx2: cpx2,\n                cpy2: cpy2\n            });\n\n            curve.setStyle(lineStyleModel.getItemStyle());\n            // Special color, use source node color or target node color\n            switch (curve.style.fill) {\n                case 'source':\n                    curve.style.fill = edge.node1.getVisual('color');\n                    break;\n                case 'target':\n                    curve.style.fill = edge.node2.getVisual('color');\n                    break;\n            }\n\n            setHoverStyle(curve, edge.getModel('emphasis.lineStyle').getItemStyle());\n\n            group.add(curve);\n\n            edgeData.setItemGraphicEl(edge.dataIndex, curve);\n        });\n\n        // Generate a rect for each node\n        graph.eachNode(function (node) {\n            var layout = node.getLayout();\n            var itemModel = node.getModel();\n            var dragX = itemModel.get('localX');\n            var dragY = itemModel.get('localY');\n            var labelModel = itemModel.getModel('label');\n            var labelHoverModel = itemModel.getModel('emphasis.label');\n\n            var rect = new Rect({\n                shape: {\n                    x: dragX != null ? dragX * width : layout.x,\n                    y: dragY != null ? dragY * height : layout.y,\n                    width: layout.dx,\n                    height: layout.dy\n                },\n                style: itemModel.getModel('itemStyle').getItemStyle()\n            });\n\n            var hoverStyle = node.getModel('emphasis.itemStyle').getItemStyle();\n\n            setLabelStyle(\n                rect.style, hoverStyle, labelModel, labelHoverModel,\n                {\n                    labelFetcher: seriesModel,\n                    labelDataIndex: node.dataIndex,\n                    defaultText: node.id,\n                    isRectText: true\n                }\n            );\n\n            rect.setStyle('fill', node.getVisual('color'));\n\n            setHoverStyle(rect, hoverStyle);\n\n            group.add(rect);\n\n            nodeData.setItemGraphicEl(node.dataIndex, rect);\n\n            rect.dataType = 'node';\n        });\n\n        nodeData.eachItemGraphicEl(function (el, dataIndex) {\n            var itemModel = nodeData.getItemModel(dataIndex);\n            if (itemModel.get('draggable')) {\n                el.drift = function (dx, dy) {\n                    sankeyView._focusAdjacencyDisabled = true;\n                    this.shape.x += dx;\n                    this.shape.y += dy;\n                    this.dirty();\n                    api.dispatchAction({\n                        type: 'dragNode',\n                        seriesId: seriesModel.id,\n                        dataIndex: nodeData.getRawIndex(dataIndex),\n                        localX: this.shape.x / width,\n                        localY: this.shape.y / height\n                    });\n                };\n                el.ondragend = function () {\n                    sankeyView._focusAdjacencyDisabled = false;\n                };\n                el.draggable = true;\n                el.cursor = 'move';\n            }\n\n            if (itemModel.get('focusNodeAdjacency')) {\n                el.off('mouseover').on('mouseover', function () {\n                    if (!sankeyView._focusAdjacencyDisabled) {\n                        api.dispatchAction({\n                            type: 'focusNodeAdjacency',\n                            seriesId: seriesModel.id,\n                            dataIndex: el.dataIndex\n                        });\n                    }\n                });\n                el.off('mouseout').on('mouseout', function () {\n                    if (!sankeyView._focusAdjacencyDisabled) {\n                        api.dispatchAction({\n                            type: 'unfocusNodeAdjacency',\n                            seriesId: seriesModel.id\n                        });\n                    }\n                });\n            }\n        });\n\n        edgeData.eachItemGraphicEl(function (el, dataIndex) {\n            var edgeModel = edgeData.getItemModel(dataIndex);\n            if (edgeModel.get('focusNodeAdjacency')) {\n                el.off('mouseover').on('mouseover', function () {\n                    if (!sankeyView._focusAdjacencyDisabled) {\n                        api.dispatchAction({\n                            type: 'focusNodeAdjacency',\n                            seriesId: seriesModel.id,\n                            edgeDataIndex: el.dataIndex\n                        });\n                    }\n                });\n                el.off('mouseout').on('mouseout', function () {\n                    if (!sankeyView._focusAdjacencyDisabled) {\n                        api.dispatchAction({\n                            type: 'unfocusNodeAdjacency',\n                            seriesId: seriesModel.id\n                        });\n                    }\n                });\n            }\n        });\n\n        if (!this._data && seriesModel.get('animation')) {\n            group.setClipPath(createGridClipShape$2(group.getBoundingRect(), seriesModel, function () {\n                group.removeClipPath();\n            }));\n        }\n\n        this._data = seriesModel.getData();\n    },\n\n    dispose: function () {},\n\n    focusNodeAdjacency: function (seriesModel, ecModel, api, payload) {\n        var data = this._model.getData();\n        var graph = data.graph;\n        var dataIndex = payload.dataIndex;\n        var itemModel = data.getItemModel(dataIndex);\n        var edgeDataIndex = payload.edgeDataIndex;\n\n        if (dataIndex == null && edgeDataIndex == null) {\n            return;\n        }\n        var node = graph.getNodeByIndex(dataIndex);\n        var edge = graph.getEdgeByIndex(edgeDataIndex);\n\n        graph.eachNode(function (node) {\n            fadeOutItem$1(node, nodeOpacityPath$1, 0.1);\n        });\n        graph.eachEdge(function (edge) {\n            fadeOutItem$1(edge, lineOpacityPath$1, 0.1);\n        });\n\n        if (node) {\n            fadeInItem$1(node, nodeOpacityPath$1);\n            var focusNodeAdj = itemModel.get('focusNodeAdjacency');\n            if (focusNodeAdj === 'outEdges') {\n                each$1(node.outEdges, function (edge) {\n                    if (edge.dataIndex < 0) {\n                        return;\n                    }\n                    fadeInItem$1(edge, lineOpacityPath$1);\n                    fadeInItem$1(edge.node2, nodeOpacityPath$1);\n                });\n            }\n            else if (focusNodeAdj === 'inEdges') {\n                each$1(node.inEdges, function (edge) {\n                    if (edge.dataIndex < 0) {\n                        return;\n                    }\n                    fadeInItem$1(edge, lineOpacityPath$1);\n                    fadeInItem$1(edge.node1, nodeOpacityPath$1);\n                });\n            }\n            else if (focusNodeAdj === 'allEdges') {\n                each$1(node.edges, function (edge) {\n                    if (edge.dataIndex < 0) {\n                        return;\n                    }\n                    fadeInItem$1(edge, lineOpacityPath$1);\n                    fadeInItem$1(edge.node1, nodeOpacityPath$1);\n                    fadeInItem$1(edge.node2, nodeOpacityPath$1);\n                });\n            }\n        }\n        if (edge) {\n            fadeInItem$1(edge, lineOpacityPath$1);\n            fadeInItem$1(edge.node1, nodeOpacityPath$1);\n            fadeInItem$1(edge.node2, nodeOpacityPath$1);\n        }\n    },\n\n    unfocusNodeAdjacency: function (seriesModel, ecModel, api, payload) {\n        var graph = this._model.getGraph();\n\n        graph.eachNode(function (node) {\n            fadeOutItem$1(node, nodeOpacityPath$1);\n        });\n        graph.eachEdge(function (edge) {\n            fadeOutItem$1(edge, lineOpacityPath$1);\n        });\n    }\n});\n\n// Add animation to the view\nfunction createGridClipShape$2(rect, seriesModel, cb) {\n    var rectEl = new Rect({\n        shape: {\n            x: rect.x - 10,\n            y: rect.y - 10,\n            width: 0,\n            height: rect.height + 20\n        }\n    });\n    initProps(rectEl, {\n        shape: {\n            width: rect.width + 20,\n            height: rect.height + 20\n        }\n    }, seriesModel, cb);\n\n    return rectEl;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file The interactive action of sankey view\n * @author Deqing Li(annong035@gmail.com)\n */\n\nregisterAction({\n    type: 'dragNode',\n    event: 'dragNode',\n    // here can only use 'update' now, other value is not support in echarts.\n    update: 'update'\n}, function (payload, ecModel) {\n    ecModel.eachComponent({mainType: 'series', subType: 'sankey', query: payload}, function (seriesModel) {\n        seriesModel.setNodePosition(payload.dataIndex, [payload.localX, payload.localY]);\n    });\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file The layout algorithm of sankey view\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar sankeyLayout = function (ecModel, api, payload) {\n\n    ecModel.eachSeriesByType('sankey', function (seriesModel) {\n\n        var nodeWidth = seriesModel.get('nodeWidth');\n        var nodeGap = seriesModel.get('nodeGap');\n\n        var layoutInfo = getViewRect$3(seriesModel, api);\n\n        seriesModel.layoutInfo = layoutInfo;\n\n        var width = layoutInfo.width;\n        var height = layoutInfo.height;\n\n        var graph = seriesModel.getGraph();\n\n        var nodes = graph.nodes;\n        var edges = graph.edges;\n\n        computeNodeValues(nodes);\n\n        var filteredNodes = filter(nodes, function (node) {\n            return node.getLayout().value === 0;\n        });\n\n        var iterations = filteredNodes.length !== 0\n            ? 0 : seriesModel.get('layoutIterations');\n\n        var orient = seriesModel.get('orient');\n\n        layoutSankey(nodes, edges, nodeWidth, nodeGap, width, height, iterations, orient);\n    });\n};\n\n/**\n * Get the layout position of the whole view\n *\n * @param {module:echarts/model/Series} seriesModel  the model object of sankey series\n * @param {module:echarts/ExtensionAPI} api  provide the API list that the developer can call\n * @return {module:zrender/core/BoundingRect}  size of rect to draw the sankey view\n */\nfunction getViewRect$3(seriesModel, api) {\n    return getLayoutRect(\n        seriesModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        }\n    );\n}\n\nfunction layoutSankey(nodes, edges, nodeWidth, nodeGap, width, height, iterations, orient) {\n    computeNodeBreadths(nodes, edges, nodeWidth, width, height, orient);\n    computeNodeDepths(nodes, edges, height, width, nodeGap, iterations, orient);\n    computeEdgeDepths(nodes, orient);\n}\n\n/**\n * Compute the value of each node by summing the associated edge's value\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n */\nfunction computeNodeValues(nodes) {\n    each$1(nodes, function (node) {\n        var value1 = sum(node.outEdges, getEdgeValue);\n        var value2 = sum(node.inEdges, getEdgeValue);\n        var value = Math.max(value1, value2);\n        node.setLayout({value: value}, true);\n    });\n}\n\n/**\n * Compute the x-position for each node.\n *\n * Here we use Kahn algorithm to detect cycle when we traverse\n * the node to computer the initial x position.\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param  {number} nodeWidth  the dx of the node\n * @param  {number} width  the whole width of the area to draw the view\n */\nfunction computeNodeBreadths(nodes, edges, nodeWidth, width, height, orient) {\n    // Used to mark whether the edge is deleted. if it is deleted,\n    // the value is 0, otherwise it is 1.\n    var remainEdges = [];\n\n    // Storage each node's indegree.\n    var indegreeArr = [];\n\n    //Used to storage the node with indegree is equal to 0.\n    var zeroIndegrees = [];\n\n    var nextNode = [];\n    var x = 0;\n    var kx = 0;\n\n    for (var i = 0; i < edges.length; i++) {\n        remainEdges[i] = 1;\n    }\n\n    for (i = 0; i < nodes.length; i++) {\n        indegreeArr[i] = nodes[i].inEdges.length;\n        if (indegreeArr[i] === 0) {\n            zeroIndegrees.push(nodes[i]);\n        }\n    }\n\n    while (zeroIndegrees.length) {\n        for (var idx = 0; idx < zeroIndegrees.length; idx++) {\n            var node = zeroIndegrees[idx];\n            if (orient === 'vertical') {\n                node.setLayout({y: x}, true);\n                node.setLayout({dy: nodeWidth}, true);\n            }\n            else {\n                node.setLayout({x: x}, true);\n                node.setLayout({dx: nodeWidth}, true);\n            }\n            for (var oidx = 0; oidx < node.outEdges.length; oidx++) {\n                var edge = node.outEdges[oidx];\n                var indexEdge = edges.indexOf(edge);\n                remainEdges[indexEdge] = 0;\n                var targetNode = edge.node2;\n                var nodeIndex = nodes.indexOf(targetNode);\n                if (--indegreeArr[nodeIndex] === 0) {\n                    nextNode.push(targetNode);\n                }\n            }\n        }\n        ++x;\n        zeroIndegrees = nextNode;\n        nextNode = [];\n    }\n\n    for (i = 0; i < remainEdges.length; i++) {\n        if (__DEV__) {\n            if (remainEdges[i] === 1) {\n                throw new Error('Sankey is a DAG, the original data has cycle!');\n            }\n        }\n    }\n\n    moveSinksRight(nodes, x, orient);\n\n    if (orient === 'vertical') {\n        kx = (height - nodeWidth) / (x - 1);\n    }\n    else {\n        kx = (width - nodeWidth) / (x - 1);\n    }\n    scaleNodeBreadths(nodes, kx, orient);\n}\n\n/**\n * All the node without outEgdes are assigned maximum x-position and\n *     be aligned in the last column.\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param {number} x  value (x-1) use to assign to node without outEdges\n *     as x-position\n */\nfunction moveSinksRight(nodes, x, orient) {\n    each$1(nodes, function (node) {\n        if (!node.outEdges.length) {\n            if (orient === 'vertical') {\n                node.setLayout({y: x - 1}, true);\n            }\n            else {\n                node.setLayout({x: x - 1}, true);\n            }\n        }\n    });\n}\n\n/**\n * Scale node x-position to the width\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param {number} kx   multiple used to scale nodes\n */\nfunction scaleNodeBreadths(nodes, kx, orient) {\n    each$1(nodes, function (node) {\n        if (orient === 'vertical') {\n            var nodeY = node.getLayout().y * kx;\n            node.setLayout({y: nodeY}, true);\n        }\n        else {\n            var nodeX = node.getLayout().x * kx;\n            node.setLayout({x: nodeX}, true);\n        }\n    });\n}\n\n/**\n * Using Gauss-Seidel iterations method to compute the node depth(y-position)\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param {module:echarts/data/Graph~Edge} edges  edge of sankey view\n * @param {number} height  the whole height of the area to draw the view\n * @param {number} nodeGap  the vertical distance between two nodes\n *     in the same column.\n * @param {number} iterations  the number of iterations for the algorithm\n */\nfunction computeNodeDepths(nodes, edges, height, width, nodeGap, iterations, orient) {\n    var nodesByBreadth = prepareNodesByBreadth(nodes, orient);\n\n    initializeNodeDepth(nodes, nodesByBreadth, edges, height, width, nodeGap, orient);\n    resolveCollisions(nodesByBreadth, nodeGap, height, width, orient);\n\n    for (var alpha = 1; iterations > 0; iterations--) {\n        // 0.99 is a experience parameter, ensure that each iterations of\n        // changes as small as possible.\n        alpha *= 0.99;\n        relaxRightToLeft(nodesByBreadth, alpha, orient);\n        resolveCollisions(nodesByBreadth, nodeGap, height, width, orient);\n        relaxLeftToRight(nodesByBreadth, alpha, orient);\n        resolveCollisions(nodesByBreadth, nodeGap, height, width, orient);\n    }\n}\n\nfunction prepareNodesByBreadth(nodes, orient) {\n    var nodesByBreadth = [];\n    var keyAttr = orient === 'vertical' ? 'y' : 'x';\n\n    var groupResult = groupData(nodes, function (node) {\n        return node.getLayout()[keyAttr];\n    });\n    groupResult.keys.sort(function (a, b) {\n        return a - b;\n    });\n    each$1(groupResult.keys, function (key) {\n        nodesByBreadth.push(groupResult.buckets.get(key));\n    });\n\n    return nodesByBreadth;\n}\n\n/**\n * Compute the original y-position for each node\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth\n *     group by the array of all sankey nodes based on the nodes x-position.\n * @param {module:echarts/data/Graph~Edge} edges  edge of sankey view\n * @param {number} height  the whole height of the area to draw the view\n * @param {number} nodeGap  the vertical distance between two nodes\n */\nfunction initializeNodeDepth(nodes, nodesByBreadth, edges, height, width, nodeGap, orient) {\n    var kyArray = [];\n    each$1(nodesByBreadth, function (nodes) {\n        var n = nodes.length;\n        var sum = 0;\n        var ky = 0;\n        each$1(nodes, function (node) {\n            sum += node.getLayout().value;\n        });\n        if (orient === 'vertical') {\n            ky = (width - (n - 1) * nodeGap) / sum;\n        }\n        else {\n            ky = (height - (n - 1) * nodeGap) / sum;\n        }\n        kyArray.push(ky);\n    });\n\n    kyArray.sort(function (a, b) {\n        return a - b;\n    });\n    var ky0 = kyArray[0];\n\n    each$1(nodesByBreadth, function (nodes) {\n        each$1(nodes, function (node, i) {\n            var nodeDy = node.getLayout().value * ky0;\n            if (orient === 'vertical') {\n                node.setLayout({x: i}, true);\n                node.setLayout({dx: nodeDy}, true);\n            }\n            else {\n                node.setLayout({y: i}, true);\n                node.setLayout({dy: nodeDy}, true);\n            }\n\n        });\n    });\n\n    each$1(edges, function (edge) {\n        var edgeDy = +edge.getValue() * ky0;\n        edge.setLayout({dy: edgeDy}, true);\n    });\n}\n\n/**\n * Resolve the collision of initialized depth (y-position)\n *\n * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth\n *     group by the array of all sankey nodes based on the nodes x-position.\n * @param {number} nodeGap  the vertical distance between two nodes\n * @param {number} height  the whole height of the area to draw the view\n */\nfunction resolveCollisions(nodesByBreadth, nodeGap, height, width, orient) {\n    each$1(nodesByBreadth, function (nodes) {\n        var node;\n        var dy;\n        var y0 = 0;\n        var n = nodes.length;\n        var i;\n\n        if (orient === 'vertical') {\n            var nodeX;\n            nodes.sort(function (a, b) {\n                return a.getLayout().x - b.getLayout().x;\n            });\n            for (i = 0; i < n; i++) {\n                node = nodes[i];\n                dy = y0 - node.getLayout().x;\n                if (dy > 0) {\n                    nodeX = node.getLayout().x + dy;\n                    node.setLayout({x: nodeX}, true);\n                }\n                y0 = node.getLayout().x + node.getLayout().dx + nodeGap;\n            }\n            // If the bottommost node goes outside the bounds, push it back up\n            dy = y0 - nodeGap - width;\n            if (dy > 0) {\n                nodeX = node.getLayout().x - dy;\n                node.setLayout({x: nodeX}, true);\n                y0 = nodeX;\n                for (i = n - 2; i >= 0; --i) {\n                    node = nodes[i];\n                    dy = node.getLayout().x + node.getLayout().dx + nodeGap - y0;\n                    if (dy > 0) {\n                        nodeX = node.getLayout().x - dy;\n                        node.setLayout({x: nodeX}, true);\n                    }\n                    y0 = node.getLayout().x;\n                }\n            }\n        }\n        else {\n            var nodeY;\n            nodes.sort(function (a, b) {\n                return a.getLayout().y - b.getLayout().y;\n            });\n            for (i = 0; i < n; i++) {\n                node = nodes[i];\n                dy = y0 - node.getLayout().y;\n                if (dy > 0) {\n                    nodeY = node.getLayout().y + dy;\n                    node.setLayout({y: nodeY}, true);\n                }\n                y0 = node.getLayout().y + node.getLayout().dy + nodeGap;\n            }\n            // If the bottommost node goes outside the bounds, push it back up\n            dy = y0 - nodeGap - height;\n            if (dy > 0) {\n                nodeY = node.getLayout().y - dy;\n                node.setLayout({y: nodeY}, true);\n                y0 = nodeY;\n                for (i = n - 2; i >= 0; --i) {\n                    node = nodes[i];\n                    dy = node.getLayout().y + node.getLayout().dy + nodeGap - y0;\n                    if (dy > 0) {\n                        nodeY = node.getLayout().y - dy;\n                        node.setLayout({y: nodeY}, true);\n                    }\n                    y0 = node.getLayout().y;\n                }\n            }\n        }\n    });\n}\n\n/**\n * Change the y-position of the nodes, except most the right side nodes\n *\n * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth\n *     group by the array of all sankey nodes based on the node x-position.\n * @param {number} alpha  parameter used to adjust the nodes y-position\n */\nfunction relaxRightToLeft(nodesByBreadth, alpha, orient) {\n    each$1(nodesByBreadth.slice().reverse(), function (nodes) {\n        each$1(nodes, function (node) {\n            if (node.outEdges.length) {\n                var y = sum(node.outEdges, weightedTarget, orient) / sum(node.outEdges, getEdgeValue, orient);\n                if (orient === 'vertical') {\n                    var nodeX = node.getLayout().x + (y - center$1(node, orient)) * alpha;\n                    node.setLayout({x: nodeX}, true);\n                }\n                else {\n                    var nodeY = node.getLayout().y + (y - center$1(node, orient)) * alpha;\n                    node.setLayout({y: nodeY}, true);\n                }\n            }\n        });\n    });\n}\n\nfunction weightedTarget(edge, orient) {\n    return center$1(edge.node2, orient) * edge.getValue();\n}\n\nfunction weightedSource(edge, orient) {\n    return center$1(edge.node1, orient) * edge.getValue();\n}\n\nfunction center$1(node, orient) {\n    if (orient === 'vertical') {\n        return node.getLayout().x + node.getLayout().dx / 2;\n    }\n    return node.getLayout().y + node.getLayout().dy / 2;\n}\n\nfunction getEdgeValue(edge) {\n    return edge.getValue();\n}\n\nfunction sum(array, f, orient) {\n    var sum = 0;\n    var len = array.length;\n    var i = -1;\n    while (++i < len) {\n        var value = +f.call(array, array[i], orient);\n        if (!isNaN(value)) {\n            sum += value;\n        }\n    }\n    return sum;\n}\n\n/**\n * Change the y-position of the nodes, except most the left side nodes\n *\n * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth\n *     group by the array of all sankey nodes based on the node x-position.\n * @param {number} alpha  parameter used to adjust the nodes y-position\n */\nfunction relaxLeftToRight(nodesByBreadth, alpha, orient) {\n    each$1(nodesByBreadth, function (nodes) {\n        each$1(nodes, function (node) {\n            if (node.inEdges.length) {\n                var y = sum(node.inEdges, weightedSource, orient) / sum(node.inEdges, getEdgeValue, orient);\n                if (orient === 'vertical') {\n                    var nodeX = node.getLayout().x + (y - center$1(node, orient)) * alpha;\n                    node.setLayout({x: nodeX}, true);\n                }\n                else {\n                    var nodeY = node.getLayout().y + (y - center$1(node, orient)) * alpha;\n                    node.setLayout({y: nodeY}, true);\n                }\n            }\n        });\n    });\n}\n\n/**\n * Compute the depth(y-position) of each edge\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n */\nfunction computeEdgeDepths(nodes, orient) {\n    each$1(nodes, function (node) {\n        if (orient === 'vertical') {\n            node.outEdges.sort(function (a, b) {\n                return a.node2.getLayout().x - b.node2.getLayout().x;\n            });\n            node.inEdges.sort(function (a, b) {\n                return a.node1.getLayout().x - b.node1.getLayout().x;\n            });\n        }\n        else {\n            node.outEdges.sort(function (a, b) {\n                return a.node2.getLayout().y - b.node2.getLayout().y;\n            });\n            node.inEdges.sort(function (a, b) {\n                return a.node1.getLayout().y - b.node1.getLayout().y;\n            });\n        }\n    });\n    each$1(nodes, function (node) {\n        var sy = 0;\n        var ty = 0;\n        each$1(node.outEdges, function (edge) {\n            edge.setLayout({sy: sy}, true);\n            sy += edge.getLayout().dy;\n        });\n        each$1(node.inEdges, function (edge) {\n            edge.setLayout({ty: ty}, true);\n            ty += edge.getLayout().dy;\n        });\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Visual encoding for sankey view\n * @author  Deqing Li(annong035@gmail.com)\n */\n\nvar sankeyVisual = function (ecModel, payload) {\n    ecModel.eachSeriesByType('sankey', function (seriesModel) {\n        var graph = seriesModel.getGraph();\n        var nodes = graph.nodes;\n        if (nodes.length) {\n            var minValue = Infinity;\n            var maxValue = -Infinity;\n            each$1(nodes, function (node) {\n                var nodeValue = node.getLayout().value;\n                if (nodeValue < minValue) {\n                    minValue = nodeValue;\n                }\n                if (nodeValue > maxValue) {\n                    maxValue = nodeValue;\n                }\n            });\n\n            each$1(nodes, function (node) {\n                var mapping = new VisualMapping({\n                    type: 'color',\n                    mappingMethod: 'linear',\n                    dataExtent: [minValue, maxValue],\n                    visual: seriesModel.get('color')\n                });\n\n                var mapValueToColor = mapping.mapValueToVisual(node.getLayout().value);\n                node.setVisual('color', mapValueToColor);\n                // If set itemStyle.normal.color\n                var itemModel = node.getModel();\n                var customColor = itemModel.get('itemStyle.color');\n                if (customColor != null) {\n                    node.setVisual('color', customColor);\n                }\n            });\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterLayout(sankeyLayout);\nregisterVisual(sankeyVisual);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar seriesModelMixin = {\n\n    /**\n     * @private\n     * @type {string}\n     */\n    _baseAxisDim: null,\n\n    /**\n     * @override\n     */\n    getInitialData: function (option, ecModel) {\n        // When both types of xAxis and yAxis are 'value', layout is\n        // needed to be specified by user. Otherwise, layout can be\n        // judged by which axis is category.\n\n        var ordinalMeta;\n\n        var xAxisModel = ecModel.getComponent('xAxis', this.get('xAxisIndex'));\n        var yAxisModel = ecModel.getComponent('yAxis', this.get('yAxisIndex'));\n        var xAxisType = xAxisModel.get('type');\n        var yAxisType = yAxisModel.get('type');\n        var addOrdinal;\n\n        // FIXME\n        // 考虑时间轴\n\n        if (xAxisType === 'category') {\n            option.layout = 'horizontal';\n            ordinalMeta = xAxisModel.getOrdinalMeta();\n            addOrdinal = true;\n        }\n        else if (yAxisType === 'category') {\n            option.layout = 'vertical';\n            ordinalMeta = yAxisModel.getOrdinalMeta();\n            addOrdinal = true;\n        }\n        else {\n            option.layout = option.layout || 'horizontal';\n        }\n\n        var coordDims = ['x', 'y'];\n        var baseAxisDimIndex = option.layout === 'horizontal' ? 0 : 1;\n        var baseAxisDim = this._baseAxisDim = coordDims[baseAxisDimIndex];\n        var otherAxisDim = coordDims[1 - baseAxisDimIndex];\n        var axisModels = [xAxisModel, yAxisModel];\n        var baseAxisType = axisModels[baseAxisDimIndex].get('type');\n        var otherAxisType = axisModels[1 - baseAxisDimIndex].get('type');\n        var data = option.data;\n\n        // ??? FIXME make a stage to perform data transfrom.\n        // MUST create a new data, consider setOption({}) again.\n        if (data && addOrdinal) {\n            var newOptionData = [];\n            each$1(data, function (item, index) {\n                var newItem;\n                if (item.value && isArray(item.value)) {\n                    newItem = item.value.slice();\n                    item.value.unshift(index);\n                }\n                else if (isArray(item)) {\n                    newItem = item.slice();\n                    item.unshift(index);\n                }\n                else {\n                    newItem = item;\n                }\n                newOptionData.push(newItem);\n            });\n            option.data = newOptionData;\n        }\n\n        var defaultValueDimensions = this.defaultValueDimensions;\n\n        return createListSimply(\n            this,\n            {\n                coordDimensions: [{\n                    name: baseAxisDim,\n                    type: getDimensionTypeByAxis(baseAxisType),\n                    ordinalMeta: ordinalMeta,\n                    otherDims: {\n                        tooltip: false,\n                        itemName: 0\n                    },\n                    dimsDef: ['base']\n                }, {\n                    name: otherAxisDim,\n                    type: getDimensionTypeByAxis(otherAxisType),\n                    dimsDef: defaultValueDimensions.slice()\n                }],\n                dimensionsCount: defaultValueDimensions.length + 1\n            }\n        );\n    },\n\n    /**\n     * If horizontal, base axis is x, otherwise y.\n     * @override\n     */\n    getBaseAxis: function () {\n        var dim = this._baseAxisDim;\n        return this.ecModel.getComponent(dim + 'Axis', this.get(dim + 'AxisIndex')).axis;\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BoxplotSeries = SeriesModel.extend({\n\n    type: 'series.boxplot',\n\n    dependencies: ['xAxis', 'yAxis', 'grid'],\n\n    // TODO\n    // box width represents group size, so dimension should have 'size'.\n\n    /**\n     * @see <https://en.wikipedia.org/wiki/Box_plot>\n     * The meanings of 'min' and 'max' depend on user,\n     * and echarts do not need to know it.\n     * @readOnly\n     */\n    defaultValueDimensions: [\n        {name: 'min', defaultTooltip: true},\n        {name: 'Q1', defaultTooltip: true},\n        {name: 'median', defaultTooltip: true},\n        {name: 'Q3', defaultTooltip: true},\n        {name: 'max', defaultTooltip: true}\n    ],\n\n    /**\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: null,\n\n    /**\n     * @override\n     */\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        layout: null,               // 'horizontal' or 'vertical'\n        boxWidth: [7, 50],       // [min, max] can be percent of band width.\n\n        itemStyle: {\n            color: '#fff',\n            borderWidth: 1\n        },\n\n        emphasis: {\n            itemStyle: {\n                borderWidth: 2,\n                shadowBlur: 5,\n                shadowOffsetX: 2,\n                shadowOffsetY: 2,\n                shadowColor: 'rgba(0,0,0,0.4)'\n            }\n        },\n\n        animationEasing: 'elasticOut',\n        animationDuration: 800\n    }\n});\n\nmixin(BoxplotSeries, seriesModelMixin, true);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Update common properties\nvar NORMAL_ITEM_STYLE_PATH = ['itemStyle'];\nvar EMPHASIS_ITEM_STYLE_PATH = ['emphasis', 'itemStyle'];\n\nvar BoxplotView = Chart.extend({\n\n    type: 'boxplot',\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var group = this.group;\n        var oldData = this._data;\n\n        // There is no old data only when first rendering or switching from\n        // stream mode to normal mode, where previous elements should be removed.\n        if (!this._data) {\n            group.removeAll();\n        }\n\n        var constDim = seriesModel.get('layout') === 'horizontal' ? 1 : 0;\n\n        data.diff(oldData)\n            .add(function (newIdx) {\n                if (data.hasValue(newIdx)) {\n                    var itemLayout = data.getItemLayout(newIdx);\n                    var symbolEl = createNormalBox(itemLayout, data, newIdx, constDim, true);\n                    data.setItemGraphicEl(newIdx, symbolEl);\n                    group.add(symbolEl);\n                }\n            })\n            .update(function (newIdx, oldIdx) {\n                var symbolEl = oldData.getItemGraphicEl(oldIdx);\n\n                // Empty data\n                if (!data.hasValue(newIdx)) {\n                    group.remove(symbolEl);\n                    return;\n                }\n\n                var itemLayout = data.getItemLayout(newIdx);\n                if (!symbolEl) {\n                    symbolEl = createNormalBox(itemLayout, data, newIdx, constDim);\n                }\n                else {\n                    updateNormalBoxData(itemLayout, symbolEl, data, newIdx);\n                }\n\n                group.add(symbolEl);\n\n                data.setItemGraphicEl(newIdx, symbolEl);\n            })\n            .remove(function (oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n                el && group.remove(el);\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    remove: function (ecModel) {\n        var group = this.group;\n        var data = this._data;\n        this._data = null;\n        data && data.eachItemGraphicEl(function (el) {\n            el && group.remove(el);\n        });\n    },\n\n    dispose: noop\n\n});\n\n\nvar BoxPath = Path.extend({\n\n    type: 'boxplotBoxPath',\n\n    shape: {},\n\n    buildPath: function (ctx, shape) {\n        var ends = shape.points;\n\n        var i = 0;\n        ctx.moveTo(ends[i][0], ends[i][1]);\n        i++;\n        for (; i < 4; i++) {\n            ctx.lineTo(ends[i][0], ends[i][1]);\n        }\n        ctx.closePath();\n\n        for (; i < ends.length; i++) {\n            ctx.moveTo(ends[i][0], ends[i][1]);\n            i++;\n            ctx.lineTo(ends[i][0], ends[i][1]);\n        }\n    }\n});\n\n\nfunction createNormalBox(itemLayout, data, dataIndex, constDim, isInit) {\n    var ends = itemLayout.ends;\n\n    var el = new BoxPath({\n        shape: {\n            points: isInit\n                ? transInit(ends, constDim, itemLayout)\n                : ends\n        }\n    });\n\n    updateNormalBoxData(itemLayout, el, data, dataIndex, isInit);\n\n    return el;\n}\n\nfunction updateNormalBoxData(itemLayout, el, data, dataIndex, isInit) {\n    var seriesModel = data.hostModel;\n    var updateMethod = graphic[isInit ? 'initProps' : 'updateProps'];\n\n    updateMethod(\n        el,\n        {shape: {points: itemLayout.ends}},\n        seriesModel,\n        dataIndex\n    );\n\n    var itemModel = data.getItemModel(dataIndex);\n    var normalItemStyleModel = itemModel.getModel(NORMAL_ITEM_STYLE_PATH);\n    var borderColor = data.getItemVisual(dataIndex, 'color');\n\n    // Exclude borderColor.\n    var itemStyle = normalItemStyleModel.getItemStyle(['borderColor']);\n    itemStyle.stroke = borderColor;\n    itemStyle.strokeNoScale = true;\n    el.useStyle(itemStyle);\n\n    el.z2 = 100;\n\n    var hoverStyle = itemModel.getModel(EMPHASIS_ITEM_STYLE_PATH).getItemStyle();\n    setHoverStyle(el, hoverStyle);\n}\n\nfunction transInit(points, dim, itemLayout) {\n    return map(points, function (point) {\n        point = point.slice();\n        point[dim] = itemLayout.initBaseline;\n        return point;\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar borderColorQuery = ['itemStyle', 'borderColor'];\n\nvar boxplotVisual = function (ecModel, api) {\n\n    var globalColors = ecModel.get('color');\n\n    ecModel.eachRawSeriesByType('boxplot', function (seriesModel) {\n\n        var defaulColor = globalColors[seriesModel.seriesIndex % globalColors.length];\n        var data = seriesModel.getData();\n\n        data.setVisual({\n            legendSymbol: 'roundRect',\n            // Use name 'color' but not 'borderColor' for legend usage and\n            // visual coding from other component like dataRange.\n            color: seriesModel.get(borderColorQuery) || defaulColor\n        });\n\n        // Only visible series has each data be visual encoded\n        if (!ecModel.isSeriesFiltered(seriesModel)) {\n            data.each(function (idx) {\n                var itemModel = data.getItemModel(idx);\n                data.setItemVisual(\n                    idx,\n                    {color: itemModel.get(borderColorQuery, true)}\n                );\n            });\n        }\n    });\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$13 = each$1;\n\nvar boxplotLayout = function (ecModel) {\n\n    var groupResult = groupSeriesByAxis(ecModel);\n\n    each$13(groupResult, function (groupItem) {\n        var seriesModels = groupItem.seriesModels;\n\n        if (!seriesModels.length) {\n            return;\n        }\n\n        calculateBase(groupItem);\n\n        each$13(seriesModels, function (seriesModel, idx) {\n            layoutSingleSeries(\n                seriesModel,\n                groupItem.boxOffsetList[idx],\n                groupItem.boxWidthList[idx]\n            );\n        });\n    });\n};\n\n/**\n * Group series by axis.\n */\nfunction groupSeriesByAxis(ecModel) {\n    var result = [];\n    var axisList = [];\n\n    ecModel.eachSeriesByType('boxplot', function (seriesModel) {\n        var baseAxis = seriesModel.getBaseAxis();\n        var idx = indexOf(axisList, baseAxis);\n\n        if (idx < 0) {\n            idx = axisList.length;\n            axisList[idx] = baseAxis;\n            result[idx] = {axis: baseAxis, seriesModels: []};\n        }\n\n        result[idx].seriesModels.push(seriesModel);\n    });\n\n    return result;\n}\n\n/**\n * Calculate offset and box width for each series.\n */\nfunction calculateBase(groupItem) {\n    var extent;\n    var baseAxis = groupItem.axis;\n    var seriesModels = groupItem.seriesModels;\n    var seriesCount = seriesModels.length;\n\n    var boxWidthList = groupItem.boxWidthList = [];\n    var boxOffsetList = groupItem.boxOffsetList = [];\n    var boundList = [];\n\n    var bandWidth;\n    if (baseAxis.type === 'category') {\n        bandWidth = baseAxis.getBandWidth();\n    }\n    else {\n        var maxDataCount = 0;\n        each$13(seriesModels, function (seriesModel) {\n            maxDataCount = Math.max(maxDataCount, seriesModel.getData().count());\n        });\n        extent = baseAxis.getExtent(),\n        Math.abs(extent[1] - extent[0]) / maxDataCount;\n    }\n\n    each$13(seriesModels, function (seriesModel) {\n        var boxWidthBound = seriesModel.get('boxWidth');\n        if (!isArray(boxWidthBound)) {\n            boxWidthBound = [boxWidthBound, boxWidthBound];\n        }\n        boundList.push([\n            parsePercent$1(boxWidthBound[0], bandWidth) || 0,\n            parsePercent$1(boxWidthBound[1], bandWidth) || 0\n        ]);\n    });\n\n    var availableWidth = bandWidth * 0.8 - 2;\n    var boxGap = availableWidth / seriesCount * 0.3;\n    var boxWidth = (availableWidth - boxGap * (seriesCount - 1)) / seriesCount;\n    var base = boxWidth / 2 - availableWidth / 2;\n\n    each$13(seriesModels, function (seriesModel, idx) {\n        boxOffsetList.push(base);\n        base += boxGap + boxWidth;\n\n        boxWidthList.push(\n            Math.min(Math.max(boxWidth, boundList[idx][0]), boundList[idx][1])\n        );\n    });\n}\n\n/**\n * Calculate points location for each series.\n */\nfunction layoutSingleSeries(seriesModel, offset, boxWidth) {\n    var coordSys = seriesModel.coordinateSystem;\n    var data = seriesModel.getData();\n    var halfWidth = boxWidth / 2;\n    var cDimIdx = seriesModel.get('layout') === 'horizontal' ? 0 : 1;\n    var vDimIdx = 1 - cDimIdx;\n    var coordDims = ['x', 'y'];\n    var cDim = data.mapDimension(coordDims[cDimIdx]);\n    var vDims = data.mapDimension(coordDims[vDimIdx], true);\n\n    if (cDim == null || vDims.length < 5) {\n        return;\n    }\n\n    for (var dataIndex = 0; dataIndex < data.count(); dataIndex++) {\n        var axisDimVal = data.get(cDim, dataIndex);\n\n        var median = getPoint(axisDimVal, vDims[2], dataIndex);\n        var end1 = getPoint(axisDimVal, vDims[0], dataIndex);\n        var end2 = getPoint(axisDimVal, vDims[1], dataIndex);\n        var end4 = getPoint(axisDimVal, vDims[3], dataIndex);\n        var end5 = getPoint(axisDimVal, vDims[4], dataIndex);\n\n        var ends = [];\n        addBodyEnd(ends, end2, 0);\n        addBodyEnd(ends, end4, 1);\n\n        ends.push(end1, end2, end5, end4);\n        layEndLine(ends, end1);\n        layEndLine(ends, end5);\n        layEndLine(ends, median);\n\n        data.setItemLayout(dataIndex, {\n            initBaseline: median[vDimIdx],\n            ends: ends\n        });\n    }\n\n    function getPoint(axisDimVal, dimIdx, dataIndex) {\n        var val = data.get(dimIdx, dataIndex);\n        var p = [];\n        p[cDimIdx] = axisDimVal;\n        p[vDimIdx] = val;\n        var point;\n        if (isNaN(axisDimVal) || isNaN(val)) {\n            point = [NaN, NaN];\n        }\n        else {\n            point = coordSys.dataToPoint(p);\n            point[cDimIdx] += offset;\n        }\n        return point;\n    }\n\n    function addBodyEnd(ends, point, start) {\n        var point1 = point.slice();\n        var point2 = point.slice();\n        point1[cDimIdx] += halfWidth;\n        point2[cDimIdx] -= halfWidth;\n        start\n            ? ends.push(point1, point2)\n            : ends.push(point2, point1);\n    }\n\n    function layEndLine(ends, endCenter) {\n        var from = endCenter.slice();\n        var to = endCenter.slice();\n        from[cDimIdx] -= halfWidth;\n        to[cDimIdx] += halfWidth;\n        ends.push(from, to);\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(boxplotVisual);\nregisterLayout(boxplotLayout);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar CandlestickSeries = SeriesModel.extend({\n\n    type: 'series.candlestick',\n\n    dependencies: ['xAxis', 'yAxis', 'grid'],\n\n    /**\n     * @readOnly\n     */\n    defaultValueDimensions: [\n        {name: 'open', defaultTooltip: true},\n        {name: 'close', defaultTooltip: true},\n        {name: 'lowest', defaultTooltip: true},\n        {name: 'highest', defaultTooltip: true}\n    ],\n\n    /**\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: null,\n\n    /**\n     * @override\n     */\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        layout: null, // 'horizontal' or 'vertical'\n\n        itemStyle: {\n            color: '#c23531', // 阳线 positive\n            color0: '#314656', // 阴线 negative     '#c23531', '#314656'\n            borderWidth: 1,\n            // FIXME\n            // ec2中使用的是lineStyle.color 和 lineStyle.color0\n            borderColor: '#c23531',\n            borderColor0: '#314656'\n        },\n\n        emphasis: {\n            itemStyle: {\n                borderWidth: 2\n            }\n        },\n\n        barMaxWidth: null,\n        barMinWidth: null,\n        barWidth: null,\n\n        large: true,\n        largeThreshold: 600,\n\n        progressive: 3e3,\n        progressiveThreshold: 1e4,\n        progressiveChunkMode: 'mod',\n\n        animationUpdate: false,\n        animationEasing: 'linear',\n        animationDuration: 300\n    },\n\n    /**\n     * Get dimension for shadow in dataZoom\n     * @return {string} dimension name\n     */\n    getShadowDim: function () {\n        return 'open';\n    },\n\n    brushSelector: function (dataIndex, data, selectors) {\n        var itemLayout = data.getItemLayout(dataIndex);\n        return itemLayout && selectors.rect(itemLayout.brushRect);\n    }\n\n});\n\nmixin(CandlestickSeries, seriesModelMixin, true);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar NORMAL_ITEM_STYLE_PATH$1 = ['itemStyle'];\nvar EMPHASIS_ITEM_STYLE_PATH$1 = ['emphasis', 'itemStyle'];\nvar SKIP_PROPS = ['color', 'color0', 'borderColor', 'borderColor0'];\n\n\nvar CandlestickView = Chart.extend({\n\n    type: 'candlestick',\n\n    render: function (seriesModel, ecModel, api) {\n        this._updateDrawMode(seriesModel);\n\n        this._isLargeDraw\n            ? this._renderLarge(seriesModel)\n            : this._renderNormal(seriesModel);\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this._clear();\n        this._updateDrawMode(seriesModel);\n    },\n\n    incrementalRender: function (params, seriesModel, ecModel, api) {\n        this._isLargeDraw\n             ? this._incrementalRenderLarge(params, seriesModel)\n             : this._incrementalRenderNormal(params, seriesModel);\n    },\n\n    _updateDrawMode: function (seriesModel) {\n        var isLargeDraw = seriesModel.pipelineContext.large;\n        if (this._isLargeDraw == null || isLargeDraw ^ this._isLargeDraw) {\n            this._isLargeDraw = isLargeDraw;\n            this._clear();\n        }\n    },\n\n    _renderNormal: function (seriesModel) {\n        var data = seriesModel.getData();\n        var oldData = this._data;\n        var group = this.group;\n        var isSimpleBox = data.getLayout('isSimpleBox');\n\n        // There is no old data only when first rendering or switching from\n        // stream mode to normal mode, where previous elements should be removed.\n        if (!this._data) {\n            group.removeAll();\n        }\n\n        data.diff(oldData)\n            .add(function (newIdx) {\n                if (data.hasValue(newIdx)) {\n                    var el;\n\n                    var itemLayout = data.getItemLayout(newIdx);\n                    el = createNormalBox$1(itemLayout, newIdx, true);\n                    initProps(el, {shape: {points: itemLayout.ends}}, seriesModel, newIdx);\n\n                    setBoxCommon(el, data, newIdx, isSimpleBox);\n\n                    group.add(el);\n                    data.setItemGraphicEl(newIdx, el);\n                }\n            })\n            .update(function (newIdx, oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n\n                // Empty data\n                if (!data.hasValue(newIdx)) {\n                    group.remove(el);\n                    return;\n                }\n\n                var itemLayout = data.getItemLayout(newIdx);\n                if (!el) {\n                    el = createNormalBox$1(itemLayout, newIdx);\n                }\n                else {\n                    updateProps(el, {shape: {points: itemLayout.ends}}, seriesModel, newIdx);\n                }\n\n                setBoxCommon(el, data, newIdx, isSimpleBox);\n\n                group.add(el);\n                data.setItemGraphicEl(newIdx, el);\n            })\n            .remove(function (oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n                el && group.remove(el);\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    _renderLarge: function (seriesModel) {\n        this._clear();\n        createLarge$1(seriesModel, this.group);\n    },\n\n    _incrementalRenderNormal: function (params, seriesModel) {\n        var data = seriesModel.getData();\n        var isSimpleBox = data.getLayout('isSimpleBox');\n\n        var dataIndex;\n        while ((dataIndex = params.next()) != null) {\n            var el;\n\n            var itemLayout = data.getItemLayout(dataIndex);\n            el = createNormalBox$1(itemLayout, dataIndex);\n            setBoxCommon(el, data, dataIndex, isSimpleBox);\n\n            el.incremental = true;\n            this.group.add(el);\n        }\n    },\n\n    _incrementalRenderLarge: function (params, seriesModel) {\n        createLarge$1(seriesModel, this.group, true);\n    },\n\n    remove: function (ecModel) {\n        this._clear();\n    },\n\n    _clear: function () {\n        this.group.removeAll();\n        this._data = null;\n    },\n\n    dispose: noop\n\n});\n\n\nvar NormalBoxPath = Path.extend({\n\n    type: 'normalCandlestickBox',\n\n    shape: {},\n\n    buildPath: function (ctx, shape) {\n        var ends = shape.points;\n\n        if (this.__simpleBox) {\n            ctx.moveTo(ends[4][0], ends[4][1]);\n            ctx.lineTo(ends[6][0], ends[6][1]);\n        }\n        else {\n            ctx.moveTo(ends[0][0], ends[0][1]);\n            ctx.lineTo(ends[1][0], ends[1][1]);\n            ctx.lineTo(ends[2][0], ends[2][1]);\n            ctx.lineTo(ends[3][0], ends[3][1]);\n            ctx.closePath();\n\n            ctx.moveTo(ends[4][0], ends[4][1]);\n            ctx.lineTo(ends[5][0], ends[5][1]);\n            ctx.moveTo(ends[6][0], ends[6][1]);\n            ctx.lineTo(ends[7][0], ends[7][1]);\n        }\n    }\n});\n\nfunction createNormalBox$1(itemLayout, dataIndex, isInit) {\n    var ends = itemLayout.ends;\n    return new NormalBoxPath({\n        shape: {\n            points: isInit\n                ? transInit$1(ends, itemLayout)\n                : ends\n        },\n        z2: 100\n    });\n}\n\nfunction setBoxCommon(el, data, dataIndex, isSimpleBox) {\n    var itemModel = data.getItemModel(dataIndex);\n    var normalItemStyleModel = itemModel.getModel(NORMAL_ITEM_STYLE_PATH$1);\n    var color = data.getItemVisual(dataIndex, 'color');\n    var borderColor = data.getItemVisual(dataIndex, 'borderColor') || color;\n\n    // Color must be excluded.\n    // Because symbol provide setColor individually to set fill and stroke\n    var itemStyle = normalItemStyleModel.getItemStyle(SKIP_PROPS);\n\n    el.useStyle(itemStyle);\n    el.style.strokeNoScale = true;\n    el.style.fill = color;\n    el.style.stroke = borderColor;\n\n    el.__simpleBox = isSimpleBox;\n\n    var hoverStyle = itemModel.getModel(EMPHASIS_ITEM_STYLE_PATH$1).getItemStyle();\n    setHoverStyle(el, hoverStyle);\n}\n\nfunction transInit$1(points, itemLayout) {\n    return map(points, function (point) {\n        point = point.slice();\n        point[1] = itemLayout.initBaseline;\n        return point;\n    });\n}\n\n\n\nvar LargeBoxPath = Path.extend({\n\n    type: 'largeCandlestickBox',\n\n    shape: {},\n\n    buildPath: function (ctx, shape) {\n        // Drawing lines is more efficient than drawing\n        // a whole line or drawing rects.\n        var points = shape.points;\n        for (var i = 0; i < points.length;) {\n            if (this.__sign === points[i++]) {\n                var x = points[i++];\n                ctx.moveTo(x, points[i++]);\n                ctx.lineTo(x, points[i++]);\n            }\n            else {\n                i += 3;\n            }\n        }\n    }\n});\n\nfunction createLarge$1(seriesModel, group, incremental) {\n    var data = seriesModel.getData();\n    var largePoints = data.getLayout('largePoints');\n\n    var elP = new LargeBoxPath({\n        shape: {points: largePoints},\n        __sign: 1\n    });\n    group.add(elP);\n    var elN = new LargeBoxPath({\n        shape: {points: largePoints},\n        __sign: -1\n    });\n    group.add(elN);\n\n    setLargeStyle$1(1, elP, seriesModel, data);\n    setLargeStyle$1(-1, elN, seriesModel, data);\n\n    if (incremental) {\n        elP.incremental = true;\n        elN.incremental = true;\n    }\n}\n\nfunction setLargeStyle$1(sign, el, seriesModel, data) {\n    var suffix = sign > 0 ? 'P' : 'N';\n    var borderColor = data.getVisual('borderColor' + suffix)\n        || data.getVisual('color' + suffix);\n\n    // Color must be excluded.\n    // Because symbol provide setColor individually to set fill and stroke\n    var itemStyle = seriesModel.getModel(NORMAL_ITEM_STYLE_PATH$1).getItemStyle(SKIP_PROPS);\n\n    el.useStyle(itemStyle);\n    el.style.fill = null;\n    el.style.stroke = borderColor;\n    // No different\n    // el.style.lineWidth = .5;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar preprocessor = function (option) {\n    if (!option || !isArray(option.series)) {\n        return;\n    }\n\n    // Translate 'k' to 'candlestick'.\n    each$1(option.series, function (seriesItem) {\n        if (isObject$1(seriesItem) && seriesItem.type === 'k') {\n            seriesItem.type = 'candlestick';\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar positiveBorderColorQuery = ['itemStyle', 'borderColor'];\nvar negativeBorderColorQuery = ['itemStyle', 'borderColor0'];\nvar positiveColorQuery = ['itemStyle', 'color'];\nvar negativeColorQuery = ['itemStyle', 'color0'];\n\nvar candlestickVisual = {\n\n    seriesType: 'candlestick',\n\n    plan: createRenderPlanner(),\n\n    // For legend.\n    performRawSeries: true,\n\n    reset: function (seriesModel, ecModel) {\n\n        var data = seriesModel.getData();\n        var isLargeRender = seriesModel.pipelineContext.large;\n\n        data.setVisual({\n            legendSymbol: 'roundRect',\n            colorP: getColor(1, seriesModel),\n            colorN: getColor(-1, seriesModel),\n            borderColorP: getBorderColor(1, seriesModel),\n            borderColorN: getBorderColor(-1, seriesModel)\n        });\n\n        // Only visible series has each data be visual encoded\n        if (ecModel.isSeriesFiltered(seriesModel)) {\n            return;\n        }\n\n        return !isLargeRender && {progress: progress};\n\n\n        function progress(params, data) {\n            var dataIndex;\n            while ((dataIndex = params.next()) != null) {\n                var itemModel = data.getItemModel(dataIndex);\n                var sign = data.getItemLayout(dataIndex).sign;\n\n                data.setItemVisual(\n                    dataIndex,\n                    {\n                        color: getColor(sign, itemModel),\n                        borderColor: getBorderColor(sign, itemModel)\n                    }\n                );\n            }\n        }\n\n        function getColor(sign, model) {\n            return model.get(\n                sign > 0 ? positiveColorQuery : negativeColorQuery\n            );\n        }\n\n        function getBorderColor(sign, model) {\n            return model.get(\n                sign > 0 ? positiveBorderColorQuery : negativeBorderColorQuery\n            );\n        }\n\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar LargeArr$1 = typeof Float32Array !== 'undefined' ? Float32Array : Array;\n\nvar candlestickLayout = {\n\n    seriesType: 'candlestick',\n\n    plan: createRenderPlanner(),\n\n    reset: function (seriesModel) {\n\n        var coordSys = seriesModel.coordinateSystem;\n        var data = seriesModel.getData();\n        var candleWidth = calculateCandleWidth(seriesModel, data);\n        var cDimIdx = 0;\n        var vDimIdx = 1;\n        var coordDims = ['x', 'y'];\n        var cDim = data.mapDimension(coordDims[cDimIdx]);\n        var vDims = data.mapDimension(coordDims[vDimIdx], true);\n        var openDim = vDims[0];\n        var closeDim = vDims[1];\n        var lowestDim = vDims[2];\n        var highestDim = vDims[3];\n\n        data.setLayout({\n            candleWidth: candleWidth,\n            // The value is experimented visually.\n            isSimpleBox: candleWidth <= 1.3\n        });\n\n        if (cDim == null || vDims.length < 4) {\n            return;\n        }\n\n        return {\n            progress: seriesModel.pipelineContext.large\n                ? largeProgress : normalProgress\n        };\n\n        function normalProgress(params, data) {\n            var dataIndex;\n            while ((dataIndex = params.next()) != null) {\n\n                var axisDimVal = data.get(cDim, dataIndex);\n                var openVal = data.get(openDim, dataIndex);\n                var closeVal = data.get(closeDim, dataIndex);\n                var lowestVal = data.get(lowestDim, dataIndex);\n                var highestVal = data.get(highestDim, dataIndex);\n\n                var ocLow = Math.min(openVal, closeVal);\n                var ocHigh = Math.max(openVal, closeVal);\n\n                var ocLowPoint = getPoint(ocLow, axisDimVal);\n                var ocHighPoint = getPoint(ocHigh, axisDimVal);\n                var lowestPoint = getPoint(lowestVal, axisDimVal);\n                var highestPoint = getPoint(highestVal, axisDimVal);\n\n                var ends = [];\n                addBodyEnd(ends, ocHighPoint, 0);\n                addBodyEnd(ends, ocLowPoint, 1);\n\n                ends.push(\n                    subPixelOptimizePoint(highestPoint),\n                    subPixelOptimizePoint(ocHighPoint),\n                    subPixelOptimizePoint(lowestPoint),\n                    subPixelOptimizePoint(ocLowPoint)\n                );\n\n                data.setItemLayout(dataIndex, {\n                    sign: getSign(data, dataIndex, openVal, closeVal, closeDim),\n                    initBaseline: openVal > closeVal\n                        ? ocHighPoint[vDimIdx] : ocLowPoint[vDimIdx], // open point.\n                    ends: ends,\n                    brushRect: makeBrushRect(lowestVal, highestVal, axisDimVal)\n                });\n            }\n\n            function getPoint(val, axisDimVal) {\n                var p = [];\n                p[cDimIdx] = axisDimVal;\n                p[vDimIdx] = val;\n                return (isNaN(axisDimVal) || isNaN(val))\n                    ? [NaN, NaN]\n                    : coordSys.dataToPoint(p);\n            }\n\n            function addBodyEnd(ends, point, start) {\n                var point1 = point.slice();\n                var point2 = point.slice();\n\n                point1[cDimIdx] = subPixelOptimize(\n                    point1[cDimIdx] + candleWidth / 2, 1, false\n                );\n                point2[cDimIdx] = subPixelOptimize(\n                    point2[cDimIdx] - candleWidth / 2, 1, true\n                );\n\n                start\n                    ? ends.push(point1, point2)\n                    : ends.push(point2, point1);\n            }\n\n            function makeBrushRect(lowestVal, highestVal, axisDimVal) {\n                var pmin = getPoint(lowestVal, axisDimVal);\n                var pmax = getPoint(highestVal, axisDimVal);\n\n                pmin[cDimIdx] -= candleWidth / 2;\n                pmax[cDimIdx] -= candleWidth / 2;\n\n                return {\n                    x: pmin[0],\n                    y: pmin[1],\n                    width: vDimIdx ? candleWidth : pmax[0] - pmin[0],\n                    height: vDimIdx ? pmax[1] - pmin[1] : candleWidth\n                };\n            }\n\n            function subPixelOptimizePoint(point) {\n                point[cDimIdx] = subPixelOptimize(point[cDimIdx], 1);\n                return point;\n            }\n        }\n\n        function largeProgress(params, data) {\n            // Structure: [sign, x, yhigh, ylow, sign, x, yhigh, ylow, ...]\n            var points = new LargeArr$1(params.count * 5);\n            var offset = 0;\n            var point;\n            var tmpIn = [];\n            var tmpOut = [];\n            var dataIndex;\n\n            while ((dataIndex = params.next()) != null) {\n                var axisDimVal = data.get(cDim, dataIndex);\n                var openVal = data.get(openDim, dataIndex);\n                var closeVal = data.get(closeDim, dataIndex);\n                var lowestVal = data.get(lowestDim, dataIndex);\n                var highestVal = data.get(highestDim, dataIndex);\n\n                if (isNaN(axisDimVal) || isNaN(lowestVal) || isNaN(highestVal)) {\n                    points[offset++] = NaN;\n                    offset += 4;\n                    continue;\n                }\n\n                points[offset++] = getSign(data, dataIndex, openVal, closeVal, closeDim);\n\n                tmpIn[cDimIdx] = axisDimVal;\n\n                tmpIn[vDimIdx] = lowestVal;\n                point = coordSys.dataToPoint(tmpIn, null, tmpOut);\n                points[offset++] = point ? point[0] : NaN;\n                points[offset++] = point ? point[1] : NaN;\n                tmpIn[vDimIdx] = highestVal;\n                point = coordSys.dataToPoint(tmpIn, null, tmpOut);\n                points[offset++] = point ? point[1] : NaN;\n            }\n\n            data.setLayout('largePoints', points);\n        }\n    }\n};\n\nfunction getSign(data, dataIndex, openVal, closeVal, closeDim) {\n    var sign;\n    if (openVal > closeVal) {\n        sign = -1;\n    }\n    else if (openVal < closeVal) {\n        sign = 1;\n    }\n    else {\n        sign = dataIndex > 0\n            // If close === open, compare with close of last record\n            ? (data.get(closeDim, dataIndex - 1) <= closeVal ? 1 : -1)\n            // No record of previous, set to be positive\n            : 1;\n    }\n\n    return sign;\n}\n\nfunction calculateCandleWidth(seriesModel, data) {\n    var baseAxis = seriesModel.getBaseAxis();\n    var extent;\n\n    var bandWidth = baseAxis.type === 'category'\n        ? baseAxis.getBandWidth()\n        : (\n            extent = baseAxis.getExtent(),\n            Math.abs(extent[1] - extent[0]) / data.count()\n        );\n\n    var barMaxWidth = parsePercent$1(\n        retrieve2(seriesModel.get('barMaxWidth'), bandWidth),\n        bandWidth\n    );\n    var barMinWidth = parsePercent$1(\n        retrieve2(seriesModel.get('barMinWidth'), 1),\n        bandWidth\n    );\n    var barWidth = seriesModel.get('barWidth');\n\n    return barWidth != null\n        ? parsePercent$1(barWidth, bandWidth)\n        // Put max outer to ensure bar visible in spite of overlap.\n        : Math.max(Math.min(bandWidth / 2, barMaxWidth), barMinWidth);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterPreprocessor(preprocessor);\nregisterVisual(candlestickVisual);\nregisterLayout(candlestickLayout);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.effectScatter',\n\n    dependencies: ['grid', 'polar'],\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    brushSelector: 'point',\n\n    defaultOption: {\n        coordinateSystem: 'cartesian2d',\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        effectType: 'ripple',\n\n        progressive: 0,\n\n        // When to show the effect, option: 'render'|'emphasis'\n        showEffectOn: 'render',\n\n        // Ripple effect config\n        rippleEffect: {\n            period: 4,\n            // Scale of ripple\n            scale: 2.5,\n            // Brush type can be fill or stroke\n            brushType: 'fill'\n        },\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // Polar coordinate system\n        // polarIndex: 0,\n\n        // Geo coordinate system\n        // geoIndex: 0,\n\n        // symbol: null,        // 图形类型\n        symbolSize: 10          // 图形大小，半宽（半径）参数，当图形为方向或菱形则总宽度为symbolSize * 2\n        // symbolRotate: null,  // 图形旋转控制\n\n        // large: false,\n        // Available when large is true\n        // largeThreshold: 2000,\n\n        // itemStyle: {\n        //     opacity: 1\n        // }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Symbol with ripple effect\n * @module echarts/chart/helper/EffectSymbol\n */\n\nvar EFFECT_RIPPLE_NUMBER = 3;\n\nfunction normalizeSymbolSize$1(symbolSize) {\n    if (!isArray(symbolSize)) {\n        symbolSize = [+symbolSize, +symbolSize];\n    }\n    return symbolSize;\n}\n\nfunction updateRipplePath(rippleGroup, effectCfg) {\n    rippleGroup.eachChild(function (ripplePath) {\n        ripplePath.attr({\n            z: effectCfg.z,\n            zlevel: effectCfg.zlevel,\n            style: {\n                stroke: effectCfg.brushType === 'stroke' ? effectCfg.color : null,\n                fill: effectCfg.brushType === 'fill' ? effectCfg.color : null\n            }\n        });\n    });\n}\n/**\n * @constructor\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @extends {module:zrender/graphic/Group}\n */\nfunction EffectSymbol(data, idx) {\n    Group.call(this);\n\n    var symbol = new SymbolClz$1(data, idx);\n    var rippleGroup = new Group();\n    this.add(symbol);\n    this.add(rippleGroup);\n\n    rippleGroup.beforeUpdate = function () {\n        this.attr(symbol.getScale());\n    };\n    this.updateData(data, idx);\n}\n\nvar effectSymbolProto = EffectSymbol.prototype;\n\neffectSymbolProto.stopEffectAnimation = function () {\n    this.childAt(1).removeAll();\n};\n\neffectSymbolProto.startEffectAnimation = function (effectCfg) {\n    var symbolType = effectCfg.symbolType;\n    var color = effectCfg.color;\n    var rippleGroup = this.childAt(1);\n\n    for (var i = 0; i < EFFECT_RIPPLE_NUMBER; i++) {\n        // var ripplePath = createSymbol(\n        //     symbolType, -0.5, -0.5, 1, 1, color\n        // );\n        // If width/height are set too small (e.g., set to 1) on ios10\n        // and macOS Sierra, a circle stroke become a rect, no matter what\n        // the scale is set. So we set width/height as 2. See #4136.\n        var ripplePath = createSymbol(\n            symbolType, -1, -1, 2, 2, color\n        );\n        ripplePath.attr({\n            style: {\n                strokeNoScale: true\n            },\n            z2: 99,\n            silent: true,\n            scale: [0.5, 0.5]\n        });\n\n        var delay = -i / EFFECT_RIPPLE_NUMBER * effectCfg.period + effectCfg.effectOffset;\n        // TODO Configurable effectCfg.period\n        ripplePath.animate('', true)\n            .when(effectCfg.period, {\n                scale: [effectCfg.rippleScale / 2, effectCfg.rippleScale / 2]\n            })\n            .delay(delay)\n            .start();\n        ripplePath.animateStyle(true)\n            .when(effectCfg.period, {\n                opacity: 0\n            })\n            .delay(delay)\n            .start();\n\n        rippleGroup.add(ripplePath);\n    }\n\n    updateRipplePath(rippleGroup, effectCfg);\n};\n\n/**\n * Update effect symbol\n */\neffectSymbolProto.updateEffectAnimation = function (effectCfg) {\n    var oldEffectCfg = this._effectCfg;\n    var rippleGroup = this.childAt(1);\n\n    // Must reinitialize effect if following configuration changed\n    var DIFFICULT_PROPS = ['symbolType', 'period', 'rippleScale'];\n    for (var i = 0; i < DIFFICULT_PROPS.length; i++) {\n        var propName = DIFFICULT_PROPS[i];\n        if (oldEffectCfg[propName] !== effectCfg[propName]) {\n            this.stopEffectAnimation();\n            this.startEffectAnimation(effectCfg);\n            return;\n        }\n    }\n\n    updateRipplePath(rippleGroup, effectCfg);\n};\n\n/**\n * Highlight symbol\n */\neffectSymbolProto.highlight = function () {\n    this.trigger('emphasis');\n};\n\n/**\n * Downplay symbol\n */\neffectSymbolProto.downplay = function () {\n    this.trigger('normal');\n};\n\n/**\n * Update symbol properties\n * @param  {module:echarts/data/List} data\n * @param  {number} idx\n */\neffectSymbolProto.updateData = function (data, idx) {\n    var seriesModel = data.hostModel;\n\n    this.childAt(0).updateData(data, idx);\n\n    var rippleGroup = this.childAt(1);\n    var itemModel = data.getItemModel(idx);\n    var symbolType = data.getItemVisual(idx, 'symbol');\n    var symbolSize = normalizeSymbolSize$1(data.getItemVisual(idx, 'symbolSize'));\n    var color = data.getItemVisual(idx, 'color');\n\n    rippleGroup.attr('scale', symbolSize);\n\n    rippleGroup.traverse(function (ripplePath) {\n        ripplePath.attr({\n            fill: color\n        });\n    });\n\n    var symbolOffset = itemModel.getShallow('symbolOffset');\n    if (symbolOffset) {\n        var pos = rippleGroup.position;\n        pos[0] = parsePercent$1(symbolOffset[0], symbolSize[0]);\n        pos[1] = parsePercent$1(symbolOffset[1], symbolSize[1]);\n    }\n    rippleGroup.rotation = (itemModel.getShallow('symbolRotate') || 0) * Math.PI / 180 || 0;\n\n    var effectCfg = {};\n\n    effectCfg.showEffectOn = seriesModel.get('showEffectOn');\n    effectCfg.rippleScale = itemModel.get('rippleEffect.scale');\n    effectCfg.brushType = itemModel.get('rippleEffect.brushType');\n    effectCfg.period = itemModel.get('rippleEffect.period') * 1000;\n    effectCfg.effectOffset = idx / data.count();\n    effectCfg.z = itemModel.getShallow('z') || 0;\n    effectCfg.zlevel = itemModel.getShallow('zlevel') || 0;\n    effectCfg.symbolType = symbolType;\n    effectCfg.color = color;\n\n    this.off('mouseover').off('mouseout').off('emphasis').off('normal');\n\n    if (effectCfg.showEffectOn === 'render') {\n        this._effectCfg\n            ? this.updateEffectAnimation(effectCfg)\n            : this.startEffectAnimation(effectCfg);\n\n        this._effectCfg = effectCfg;\n    }\n    else {\n        // Not keep old effect config\n        this._effectCfg = null;\n\n        this.stopEffectAnimation();\n        var symbol = this.childAt(0);\n        var onEmphasis = function () {\n            symbol.highlight();\n            if (effectCfg.showEffectOn !== 'render') {\n                this.startEffectAnimation(effectCfg);\n            }\n        };\n        var onNormal = function () {\n            symbol.downplay();\n            if (effectCfg.showEffectOn !== 'render') {\n                this.stopEffectAnimation();\n            }\n        };\n        this.on('mouseover', onEmphasis, this)\n            .on('mouseout', onNormal, this)\n            .on('emphasis', onEmphasis, this)\n            .on('normal', onNormal, this);\n    }\n\n    this._effectCfg = effectCfg;\n};\n\neffectSymbolProto.fadeOut = function (cb) {\n    this.off('mouseover').off('mouseout').off('emphasis').off('normal');\n    cb && cb();\n};\n\ninherits(EffectSymbol, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendChartView({\n\n    type: 'effectScatter',\n\n    init: function () {\n        this._symbolDraw = new SymbolDraw(EffectSymbol);\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var effectSymbolDraw = this._symbolDraw;\n        effectSymbolDraw.updateData(data);\n        this.group.add(effectSymbolDraw.group);\n    },\n\n    updateTransform: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        this.group.dirty();\n\n        var res = pointsLayout().reset(seriesModel);\n        if (res.progress) {\n            res.progress({ start: 0, end: data.count() }, data);\n        }\n\n        this._symbolDraw.updateLayout(data);\n    },\n\n    _updateGroupTransform: function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys && coordSys.getRoamTransform) {\n            this.group.transform = clone$2(coordSys.getRoamTransform());\n            this.group.decomposeTransform();\n        }\n    },\n\n    remove: function (ecModel, api) {\n        this._symbolDraw && this._symbolDraw.remove(api);\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(visualSymbol('effectScatter', 'circle'));\nregisterLayout(pointsLayout('effectScatter'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Uint32Array, Float64Array, Float32Array */\n\nvar Uint32Arr = typeof Uint32Array === 'undefined' ? Array : Uint32Array;\nvar Float64Arr = typeof Float64Array === 'undefined' ? Array : Float64Array;\n\nfunction compatEc2(seriesOpt) {\n    var data = seriesOpt.data;\n    if (data && data[0] && data[0][0] && data[0][0].coord) {\n        if (__DEV__) {\n            console.warn('Lines data configuration has been changed to'\n                + ' { coords:[[1,2],[2,3]] }');\n        }\n        seriesOpt.data = map(data, function (itemOpt) {\n            var coords = [\n                itemOpt[0].coord, itemOpt[1].coord\n            ];\n            var target = {\n                coords: coords\n            };\n            if (itemOpt[0].name) {\n                target.fromName = itemOpt[0].name;\n            }\n            if (itemOpt[1].name) {\n                target.toName = itemOpt[1].name;\n            }\n            return mergeAll([target, itemOpt[0], itemOpt[1]]);\n        });\n    }\n}\n\nvar LinesSeries = SeriesModel.extend({\n\n    type: 'series.lines',\n\n    dependencies: ['grid', 'polar'],\n\n    visualColorAccessPath: 'lineStyle.color',\n\n    init: function (option) {\n        // The input data may be null/undefined.\n        option.data = option.data || [];\n\n        // Not using preprocessor because mergeOption may not have series.type\n        compatEc2(option);\n\n        var result = this._processFlatCoordsArray(option.data);\n        this._flatCoords = result.flatCoords;\n        this._flatCoordsOffset = result.flatCoordsOffset;\n        if (result.flatCoords) {\n            option.data = new Float32Array(result.count);\n        }\n\n        LinesSeries.superApply(this, 'init', arguments);\n    },\n\n    mergeOption: function (option) {\n        // The input data may be null/undefined.\n        option.data = option.data || [];\n\n        compatEc2(option);\n\n        if (option.data) {\n            // Only update when have option data to merge.\n            var result = this._processFlatCoordsArray(option.data);\n            this._flatCoords = result.flatCoords;\n            this._flatCoordsOffset = result.flatCoordsOffset;\n            if (result.flatCoords) {\n                option.data = new Float32Array(result.count);\n            }\n        }\n\n        LinesSeries.superApply(this, 'mergeOption', arguments);\n    },\n\n    appendData: function (params) {\n        var result = this._processFlatCoordsArray(params.data);\n        if (result.flatCoords) {\n            if (!this._flatCoords) {\n                this._flatCoords = result.flatCoords;\n                this._flatCoordsOffset = result.flatCoordsOffset;\n            }\n            else {\n                this._flatCoords = concatArray(this._flatCoords, result.flatCoords);\n                this._flatCoordsOffset = concatArray(this._flatCoordsOffset, result.flatCoordsOffset);\n            }\n            params.data = new Float32Array(result.count);\n        }\n\n        this.getRawData().appendData(params.data);\n    },\n\n    _getCoordsFromItemModel: function (idx) {\n        var itemModel = this.getData().getItemModel(idx);\n        var coords = (itemModel.option instanceof Array)\n            ? itemModel.option : itemModel.getShallow('coords');\n\n        if (__DEV__) {\n            if (!(coords instanceof Array && coords.length > 0 && coords[0] instanceof Array)) {\n                throw new Error(\n                    'Invalid coords ' + JSON.stringify(coords) + '. Lines must have 2d coords array in data item.'\n                );\n            }\n        }\n        return coords;\n    },\n\n    getLineCoordsCount: function (idx) {\n        if (this._flatCoordsOffset) {\n            return this._flatCoordsOffset[idx * 2 + 1];\n        }\n        else {\n            return this._getCoordsFromItemModel(idx).length;\n        }\n    },\n\n    getLineCoords: function (idx, out) {\n        if (this._flatCoordsOffset) {\n            var offset = this._flatCoordsOffset[idx * 2];\n            var len = this._flatCoordsOffset[idx * 2 + 1];\n            for (var i = 0; i < len; i++) {\n                out[i] = out[i] || [];\n                out[i][0] = this._flatCoords[offset + i * 2];\n                out[i][1] = this._flatCoords[offset + i * 2 + 1];\n            }\n            return len;\n        }\n        else {\n            var coords = this._getCoordsFromItemModel(idx);\n            for (var i = 0; i < coords.length; i++) {\n                out[i] = out[i] || [];\n                out[i][0] = coords[i][0];\n                out[i][1] = coords[i][1];\n            }\n            return coords.length;\n        }\n    },\n\n    _processFlatCoordsArray: function (data) {\n        var startOffset = 0;\n        if (this._flatCoords) {\n            startOffset = this._flatCoords.length;\n        }\n        // Stored as a typed array. In format\n        // Points Count(2) | x | y | x | y | Points Count(3) | x |  y | x | y | x | y |\n        if (typeof data[0] === 'number') {\n            var len = data.length;\n            // Store offset and len of each segment\n            var coordsOffsetAndLenStorage = new Uint32Arr(len);\n            var coordsStorage = new Float64Arr(len);\n            var coordsCursor = 0;\n            var offsetCursor = 0;\n            var dataCount = 0;\n            for (var i = 0; i < len;) {\n                dataCount++;\n                var count = data[i++];\n                // Offset\n                coordsOffsetAndLenStorage[offsetCursor++] = coordsCursor + startOffset;\n                // Len\n                coordsOffsetAndLenStorage[offsetCursor++] = count;\n                for (var k = 0; k < count; k++) {\n                    var x = data[i++];\n                    var y = data[i++];\n                    coordsStorage[coordsCursor++] = x;\n                    coordsStorage[coordsCursor++] = y;\n\n                    if (i > len) {\n                        if (__DEV__) {\n                            throw new Error('Invalid data format.');\n                        }\n                    }\n                }\n            }\n\n            return {\n                flatCoordsOffset: new Uint32Array(coordsOffsetAndLenStorage.buffer, 0, offsetCursor),\n                flatCoords: coordsStorage,\n                count: dataCount\n            };\n        }\n\n        return {\n            flatCoordsOffset: null,\n            flatCoords: null,\n            count: data.length\n        };\n    },\n\n    getInitialData: function (option, ecModel) {\n        if (__DEV__) {\n            var CoordSys = CoordinateSystemManager.get(option.coordinateSystem);\n            if (!CoordSys) {\n                throw new Error('Unkown coordinate system ' + option.coordinateSystem);\n            }\n        }\n\n        var lineData = new List(['value'], this);\n        lineData.hasItemOption = false;\n\n        lineData.initData(option.data, [], function (dataItem, dimName, dataIndex, dimIndex) {\n            // dataItem is simply coords\n            if (dataItem instanceof Array) {\n                return NaN;\n            }\n            else {\n                lineData.hasItemOption = true;\n                var value = dataItem.value;\n                if (value != null) {\n                    return value instanceof Array ? value[dimIndex] : value;\n                }\n            }\n        });\n\n        return lineData;\n    },\n\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var itemModel = data.getItemModel(dataIndex);\n        var name = itemModel.get('name');\n        if (name) {\n            return name;\n        }\n        var fromName = itemModel.get('fromName');\n        var toName = itemModel.get('toName');\n        var html = [];\n        fromName != null && html.push(fromName);\n        toName != null && html.push(toName);\n\n        return encodeHTML(html.join(' > '));\n    },\n\n    preventIncremental: function () {\n        return !!this.get('effect.show');\n    },\n\n    getProgressive: function () {\n        var progressive = this.option.progressive;\n        if (progressive == null) {\n            return this.option.large ? 1e4 : this.get('progressive');\n        }\n        return progressive;\n    },\n\n    getProgressiveThreshold: function () {\n        var progressiveThreshold = this.option.progressiveThreshold;\n        if (progressiveThreshold == null) {\n            return this.option.large ? 2e4 : this.get('progressiveThreshold');\n        }\n        return progressiveThreshold;\n    },\n\n    defaultOption: {\n        coordinateSystem: 'geo',\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // Cartesian coordinate system\n        xAxisIndex: 0,\n        yAxisIndex: 0,\n\n        symbol: ['none', 'none'],\n        symbolSize: [10, 10],\n        // Geo coordinate system\n        geoIndex: 0,\n\n        effect: {\n            show: false,\n            period: 4,\n            // Animation delay. support callback\n            // delay: 0,\n            // If move with constant speed px/sec\n            // period will be ignored if this property is > 0,\n            constantSpeed: 0,\n            symbol: 'circle',\n            symbolSize: 3,\n            loop: true,\n            // Length of trail, 0 - 1\n            trailLength: 0.2\n            // Same with lineStyle.color\n            // color\n        },\n\n        large: false,\n        // Available when large is true\n        largeThreshold: 2000,\n\n        // If lines are polyline\n        // polyline not support curveness, label, animation\n        polyline: false,\n\n        label: {\n            show: false,\n            position: 'end'\n            // distance: 5,\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n        },\n\n        lineStyle: {\n            opacity: 0.5\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Provide effect for line\n * @module echarts/chart/helper/EffectLine\n */\n\n/**\n * @constructor\n * @extends {module:zrender/graphic/Group}\n * @alias {module:echarts/chart/helper/Line}\n */\nfunction EffectLine(lineData, idx, seriesScope) {\n    Group.call(this);\n\n    this.add(this.createLine(lineData, idx, seriesScope));\n\n    this._updateEffectSymbol(lineData, idx);\n}\n\nvar effectLineProto = EffectLine.prototype;\n\neffectLineProto.createLine = function (lineData, idx, seriesScope) {\n    return new Line$1(lineData, idx, seriesScope);\n};\n\neffectLineProto._updateEffectSymbol = function (lineData, idx) {\n    var itemModel = lineData.getItemModel(idx);\n    var effectModel = itemModel.getModel('effect');\n    var size = effectModel.get('symbolSize');\n    var symbolType = effectModel.get('symbol');\n    if (!isArray(size)) {\n        size = [size, size];\n    }\n    var color = effectModel.get('color') || lineData.getItemVisual(idx, 'color');\n    var symbol = this.childAt(1);\n\n    if (this._symbolType !== symbolType) {\n        // Remove previous\n        this.remove(symbol);\n\n        symbol = createSymbol(\n            symbolType, -0.5, -0.5, 1, 1, color\n        );\n        symbol.z2 = 100;\n        symbol.culling = true;\n\n        this.add(symbol);\n    }\n\n    // Symbol may be removed if loop is false\n    if (!symbol) {\n        return;\n    }\n\n    // Shadow color is same with color in default\n    symbol.setStyle('shadowColor', color);\n    symbol.setStyle(effectModel.getItemStyle(['color']));\n\n    symbol.attr('scale', size);\n\n    symbol.setColor(color);\n    symbol.attr('scale', size);\n\n    this._symbolType = symbolType;\n\n    this._updateEffectAnimation(lineData, effectModel, idx);\n};\n\neffectLineProto._updateEffectAnimation = function (lineData, effectModel, idx) {\n\n    var symbol = this.childAt(1);\n    if (!symbol) {\n        return;\n    }\n\n    var self = this;\n\n    var points = lineData.getItemLayout(idx);\n\n    var period = effectModel.get('period') * 1000;\n    var loop = effectModel.get('loop');\n    var constantSpeed = effectModel.get('constantSpeed');\n    var delayExpr = retrieve(effectModel.get('delay'), function (idx) {\n        return idx / lineData.count() * period / 3;\n    });\n    var isDelayFunc = typeof delayExpr === 'function';\n\n    // Ignore when updating\n    symbol.ignore = true;\n\n    this.updateAnimationPoints(symbol, points);\n\n    if (constantSpeed > 0) {\n        period = this.getLineLength(symbol) / constantSpeed * 1000;\n    }\n\n    if (period !== this._period || loop !== this._loop) {\n\n        symbol.stopAnimation();\n\n        var delay = delayExpr;\n        if (isDelayFunc) {\n            delay = delayExpr(idx);\n        }\n        if (symbol.__t > 0) {\n            delay = -period * symbol.__t;\n        }\n        symbol.__t = 0;\n        var animator = symbol.animate('', loop)\n            .when(period, {\n                __t: 1\n            })\n            .delay(delay)\n            .during(function () {\n                self.updateSymbolPosition(symbol);\n            });\n        if (!loop) {\n            animator.done(function () {\n                self.remove(symbol);\n            });\n        }\n        animator.start();\n    }\n\n    this._period = period;\n    this._loop = loop;\n};\n\neffectLineProto.getLineLength = function (symbol) {\n    // Not so accurate\n    return (dist(symbol.__p1, symbol.__cp1)\n        + dist(symbol.__cp1, symbol.__p2));\n};\n\neffectLineProto.updateAnimationPoints = function (symbol, points) {\n    symbol.__p1 = points[0];\n    symbol.__p2 = points[1];\n    symbol.__cp1 = points[2] || [\n        (points[0][0] + points[1][0]) / 2,\n        (points[0][1] + points[1][1]) / 2\n    ];\n};\n\neffectLineProto.updateData = function (lineData, idx, seriesScope) {\n    this.childAt(0).updateData(lineData, idx, seriesScope);\n    this._updateEffectSymbol(lineData, idx);\n};\n\neffectLineProto.updateSymbolPosition = function (symbol) {\n    var p1 = symbol.__p1;\n    var p2 = symbol.__p2;\n    var cp1 = symbol.__cp1;\n    var t = symbol.__t;\n    var pos = symbol.position;\n    var quadraticAt$$1 = quadraticAt;\n    var quadraticDerivativeAt$$1 = quadraticDerivativeAt;\n    pos[0] = quadraticAt$$1(p1[0], cp1[0], p2[0], t);\n    pos[1] = quadraticAt$$1(p1[1], cp1[1], p2[1], t);\n\n    // Tangent\n    var tx = quadraticDerivativeAt$$1(p1[0], cp1[0], p2[0], t);\n    var ty = quadraticDerivativeAt$$1(p1[1], cp1[1], p2[1], t);\n\n    symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2;\n\n    symbol.ignore = false;\n};\n\n\neffectLineProto.updateLayout = function (lineData, idx) {\n    this.childAt(0).updateLayout(lineData, idx);\n\n    var effectModel = lineData.getItemModel(idx).getModel('effect');\n    this._updateEffectAnimation(lineData, effectModel, idx);\n};\n\ninherits(EffectLine, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Line\n */\n\n/**\n * @constructor\n * @extends {module:zrender/graphic/Group}\n * @alias {module:echarts/chart/helper/Polyline}\n */\nfunction Polyline$2(lineData, idx, seriesScope) {\n    Group.call(this);\n\n    this._createPolyline(lineData, idx, seriesScope);\n}\n\nvar polylineProto = Polyline$2.prototype;\n\npolylineProto._createPolyline = function (lineData, idx, seriesScope) {\n    // var seriesModel = lineData.hostModel;\n    var points = lineData.getItemLayout(idx);\n\n    var line = new Polyline({\n        shape: {\n            points: points\n        }\n    });\n\n    this.add(line);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\npolylineProto.updateData = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n\n    var line = this.childAt(0);\n    var target = {\n        shape: {\n            points: lineData.getItemLayout(idx)\n        }\n    };\n    updateProps(line, target, seriesModel, idx);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\npolylineProto._updateCommonStl = function (lineData, idx, seriesScope) {\n    var line = this.childAt(0);\n    var itemModel = lineData.getItemModel(idx);\n\n    var visualColor = lineData.getItemVisual(idx, 'color');\n\n    var lineStyle = seriesScope && seriesScope.lineStyle;\n    var hoverLineStyle = seriesScope && seriesScope.hoverLineStyle;\n\n    if (!seriesScope || lineData.hasItemOption) {\n        lineStyle = itemModel.getModel('lineStyle').getLineStyle();\n        hoverLineStyle = itemModel.getModel('emphasis.lineStyle').getLineStyle();\n    }\n    line.useStyle(defaults(\n        {\n            strokeNoScale: true,\n            fill: 'none',\n            stroke: visualColor\n        },\n        lineStyle\n    ));\n    line.hoverStyle = hoverLineStyle;\n\n    setHoverStyle(this);\n};\n\npolylineProto.updateLayout = function (lineData, idx) {\n    var polyline = this.childAt(0);\n    polyline.setShape('points', lineData.getItemLayout(idx));\n};\n\ninherits(Polyline$2, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Provide effect for line\n * @module echarts/chart/helper/EffectLine\n */\n\n/**\n * @constructor\n * @extends {module:echarts/chart/helper/EffectLine}\n * @alias {module:echarts/chart/helper/Polyline}\n */\nfunction EffectPolyline(lineData, idx, seriesScope) {\n    EffectLine.call(this, lineData, idx, seriesScope);\n    this._lastFrame = 0;\n    this._lastFramePercent = 0;\n}\n\nvar effectPolylineProto = EffectPolyline.prototype;\n\n// Overwrite\neffectPolylineProto.createLine = function (lineData, idx, seriesScope) {\n    return new Polyline$2(lineData, idx, seriesScope);\n};\n\n// Overwrite\neffectPolylineProto.updateAnimationPoints = function (symbol, points) {\n    this._points = points;\n    var accLenArr = [0];\n    var len$$1 = 0;\n    for (var i = 1; i < points.length; i++) {\n        var p1 = points[i - 1];\n        var p2 = points[i];\n        len$$1 += dist(p1, p2);\n        accLenArr.push(len$$1);\n    }\n    if (len$$1 === 0) {\n        return;\n    }\n\n    for (var i = 0; i < accLenArr.length; i++) {\n        accLenArr[i] /= len$$1;\n    }\n    this._offsets = accLenArr;\n    this._length = len$$1;\n};\n\n// Overwrite\neffectPolylineProto.getLineLength = function (symbol) {\n    return this._length;\n};\n\n// Overwrite\neffectPolylineProto.updateSymbolPosition = function (symbol) {\n    var t = symbol.__t;\n    var points = this._points;\n    var offsets = this._offsets;\n    var len$$1 = points.length;\n\n    if (!offsets) {\n        // Has length 0\n        return;\n    }\n\n    var lastFrame = this._lastFrame;\n    var frame;\n\n    if (t < this._lastFramePercent) {\n        // Start from the next frame\n        // PENDING start from lastFrame ?\n        var start = Math.min(lastFrame + 1, len$$1 - 1);\n        for (frame = start; frame >= 0; frame--) {\n            if (offsets[frame] <= t) {\n                break;\n            }\n        }\n        // PENDING really need to do this ?\n        frame = Math.min(frame, len$$1 - 2);\n    }\n    else {\n        for (var frame = lastFrame; frame < len$$1; frame++) {\n            if (offsets[frame] > t) {\n                break;\n            }\n        }\n        frame = Math.min(frame - 1, len$$1 - 2);\n    }\n\n    lerp(\n        symbol.position, points[frame], points[frame + 1],\n        (t - offsets[frame]) / (offsets[frame + 1] - offsets[frame])\n    );\n\n    var tx = points[frame + 1][0] - points[frame][0];\n    var ty = points[frame + 1][1] - points[frame][1];\n    symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2;\n\n    this._lastFrame = frame;\n    this._lastFramePercent = t;\n\n    symbol.ignore = false;\n};\n\ninherits(EffectPolyline, EffectLine);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Batch by color\n\nvar LargeLineShape = extendShape({\n\n    shape: {\n        polyline: false,\n        curveness: 0,\n        segs: []\n    },\n\n    buildPath: function (path, shape) {\n        var segs = shape.segs;\n        var curveness = shape.curveness;\n\n        if (shape.polyline) {\n            for (var i = 0; i < segs.length;) {\n                var count = segs[i++];\n                if (count > 0) {\n                    path.moveTo(segs[i++], segs[i++]);\n                    for (var k = 1; k < count; k++) {\n                        path.lineTo(segs[i++], segs[i++]);\n                    }\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < segs.length;) {\n                var x0 = segs[i++];\n                var y0 = segs[i++];\n                var x1 = segs[i++];\n                var y1 = segs[i++];\n                path.moveTo(x0, y0);\n                if (curveness > 0) {\n                    var x2 = (x0 + x1) / 2 - (y0 - y1) * curveness;\n                    var y2 = (y0 + y1) / 2 - (x1 - x0) * curveness;\n                    path.quadraticCurveTo(x2, y2, x1, y1);\n                }\n                else {\n                    path.lineTo(x1, y1);\n                }\n            }\n        }\n    },\n\n    findDataIndex: function (x, y) {\n\n        var shape = this.shape;\n        var segs = shape.segs;\n        var curveness = shape.curveness;\n\n        if (shape.polyline) {\n            var dataIndex = 0;\n            for (var i = 0; i < segs.length;) {\n                var count = segs[i++];\n                if (count > 0) {\n                    var x0 = segs[i++];\n                    var y0 = segs[i++];\n                    for (var k = 1; k < count; k++) {\n                        var x1 = segs[i++];\n                        var y1 = segs[i++];\n                        if (containStroke$1(x0, y0, x1, y1)) {\n                            return dataIndex;\n                        }\n                    }\n                }\n\n                dataIndex++;\n            }\n        }\n        else {\n            var dataIndex = 0;\n            for (var i = 0; i < segs.length;) {\n                var x0 = segs[i++];\n                var y0 = segs[i++];\n                var x1 = segs[i++];\n                var y1 = segs[i++];\n                if (curveness > 0) {\n                    var x2 = (x0 + x1) / 2 - (y0 - y1) * curveness;\n                    var y2 = (y0 + y1) / 2 - (x1 - x0) * curveness;\n\n                    if (containStroke$3(x0, y0, x2, y2, x1, y1)) {\n                        return dataIndex;\n                    }\n                }\n                else {\n                    if (containStroke$1(x0, y0, x1, y1)) {\n                        return dataIndex;\n                    }\n                }\n\n                dataIndex++;\n            }\n        }\n\n        return -1;\n    }\n});\n\nfunction LargeLineDraw() {\n    this.group = new Group();\n}\n\nvar largeLineProto = LargeLineDraw.prototype;\n\nlargeLineProto.isPersistent = function () {\n    return !this._incremental;\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n */\nlargeLineProto.updateData = function (data) {\n    this.group.removeAll();\n\n    var lineEl = new LargeLineShape({\n        rectHover: true,\n        cursor: 'default'\n    });\n    lineEl.setShape({\n        segs: data.getLayout('linesPoints')\n    });\n\n    this._setCommon(lineEl, data);\n\n    // Add back\n    this.group.add(lineEl);\n\n    this._incremental = null;\n};\n\n/**\n * @override\n */\nlargeLineProto.incrementalPrepareUpdate = function (data) {\n    this.group.removeAll();\n\n    this._clearIncremental();\n\n    if (data.count() > 5e5) {\n        if (!this._incremental) {\n            this._incremental = new IncrementalDisplayble({\n                silent: true\n            });\n        }\n        this.group.add(this._incremental);\n    }\n    else {\n        this._incremental = null;\n    }\n};\n\n/**\n * @override\n */\nlargeLineProto.incrementalUpdate = function (taskParams, data) {\n    var lineEl = new LargeLineShape();\n    lineEl.setShape({\n        segs: data.getLayout('linesPoints')\n    });\n\n    this._setCommon(lineEl, data, !!this._incremental);\n\n    if (!this._incremental) {\n        lineEl.rectHover = true;\n        lineEl.cursor = 'default';\n        lineEl.__startIndex = taskParams.start;\n        this.group.add(lineEl);\n    }\n    else {\n        this._incremental.addDisplayable(lineEl, true);\n    }\n};\n\n/**\n * @override\n */\nlargeLineProto.remove = function () {\n    this._clearIncremental();\n    this._incremental = null;\n    this.group.removeAll();\n};\n\nlargeLineProto._setCommon = function (lineEl, data, isIncremental) {\n    var hostModel = data.hostModel;\n\n    lineEl.setShape({\n        polyline: hostModel.get('polyline'),\n        curveness: hostModel.get('lineStyle.curveness')\n    });\n\n    lineEl.useStyle(\n        hostModel.getModel('lineStyle').getLineStyle()\n    );\n    lineEl.style.strokeNoScale = true;\n\n    var visualColor = data.getVisual('color');\n    if (visualColor) {\n        lineEl.setStyle('stroke', visualColor);\n    }\n    lineEl.setStyle('fill');\n\n    if (!isIncremental) {\n        // Enable tooltip\n        // PENDING May have performance issue when path is extremely large\n        lineEl.seriesIndex = hostModel.seriesIndex;\n        lineEl.on('mousemove', function (e) {\n            lineEl.dataIndex = null;\n            var dataIndex = lineEl.findDataIndex(e.offsetX, e.offsetY);\n            if (dataIndex > 0) {\n                // Provide dataIndex for tooltip\n                lineEl.dataIndex = dataIndex + lineEl.__startIndex;\n            }\n        });\n    }\n};\n\nlargeLineProto._clearIncremental = function () {\n    var incremental = this._incremental;\n    if (incremental) {\n        incremental.clearDisplaybles();\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar linesLayout = {\n    seriesType: 'lines',\n\n    plan: createRenderPlanner(),\n\n    reset: function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        var isPolyline = seriesModel.get('polyline');\n        var isLarge = seriesModel.pipelineContext.large;\n\n        function progress(params, lineData) {\n            var lineCoords = [];\n            if (isLarge) {\n                var points;\n                var segCount = params.end - params.start;\n                if (isPolyline) {\n                    var totalCoordsCount = 0;\n                    for (var i = params.start; i < params.end; i++) {\n                        totalCoordsCount += seriesModel.getLineCoordsCount(i);\n                    }\n                    points = new Float32Array(segCount + totalCoordsCount * 2);\n                }\n                else {\n                    points = new Float32Array(segCount * 4);\n                }\n\n                var offset = 0;\n                var pt = [];\n                for (var i = params.start; i < params.end; i++) {\n                    var len = seriesModel.getLineCoords(i, lineCoords);\n                    if (isPolyline) {\n                        points[offset++] = len;\n                    }\n                    for (var k = 0; k < len; k++) {\n                        pt = coordSys.dataToPoint(lineCoords[k], false, pt);\n                        points[offset++] = pt[0];\n                        points[offset++] = pt[1];\n                    }\n                }\n\n                lineData.setLayout('linesPoints', points);\n            }\n            else {\n                for (var i = params.start; i < params.end; i++) {\n                    var itemModel = lineData.getItemModel(i);\n                    var len = seriesModel.getLineCoords(i, lineCoords);\n\n                    var pts = [];\n                    if (isPolyline) {\n                        for (var j = 0; j < len; j++) {\n                            pts.push(coordSys.dataToPoint(lineCoords[j]));\n                        }\n                    }\n                    else {\n                        pts[0] = coordSys.dataToPoint(lineCoords[0]);\n                        pts[1] = coordSys.dataToPoint(lineCoords[1]);\n\n                        var curveness = itemModel.get('lineStyle.curveness');\n                        if (+curveness) {\n                            pts[2] = [\n                                (pts[0][0] + pts[1][0]) / 2 - (pts[0][1] - pts[1][1]) * curveness,\n                                (pts[0][1] + pts[1][1]) / 2 - (pts[1][0] - pts[0][0]) * curveness\n                            ];\n                        }\n                    }\n                    lineData.setItemLayout(i, pts);\n                }\n            }\n        }\n\n        return { progress: progress };\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendChartView({\n\n    type: 'lines',\n\n    init: function () {},\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        var lineDraw = this._updateLineDraw(data, seriesModel);\n\n        var zlevel = seriesModel.get('zlevel');\n        var trailLength = seriesModel.get('effect.trailLength');\n\n        var zr = api.getZr();\n        // Avoid the drag cause ghost shadow\n        // FIXME Better way ?\n        // SVG doesn't support\n        var isSvg = zr.painter.getType() === 'svg';\n        if (!isSvg) {\n            zr.painter.getLayer(zlevel).clear(true);\n        }\n        // Config layer with motion blur\n        if (this._lastZlevel != null && !isSvg) {\n            zr.configLayer(this._lastZlevel, {\n                motionBlur: false\n            });\n        }\n        if (this._showEffect(seriesModel) && trailLength) {\n            if (__DEV__) {\n                var notInIndividual = false;\n                ecModel.eachSeries(function (otherSeriesModel) {\n                    if (otherSeriesModel !== seriesModel && otherSeriesModel.get('zlevel') === zlevel) {\n                        notInIndividual = true;\n                    }\n                });\n                notInIndividual && console.warn('Lines with trail effect should have an individual zlevel');\n            }\n\n            if (!isSvg) {\n                zr.configLayer(zlevel, {\n                    motionBlur: true,\n                    lastFrameAlpha: Math.max(Math.min(trailLength / 10 + 0.9, 1), 0)\n                });\n            }\n        }\n\n        lineDraw.updateData(data);\n\n        this._lastZlevel = zlevel;\n\n        this._finished = true;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        var lineDraw = this._updateLineDraw(data, seriesModel);\n\n        lineDraw.incrementalPrepareUpdate(data);\n\n        this._clearLayer(api);\n\n        this._finished = false;\n    },\n\n    incrementalRender: function (taskParams, seriesModel, ecModel) {\n        this._lineDraw.incrementalUpdate(taskParams, seriesModel.getData());\n\n        this._finished = taskParams.end === seriesModel.getData().count();\n    },\n\n    updateTransform: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var pipelineContext = seriesModel.pipelineContext;\n\n        if (!this._finished || pipelineContext.large || pipelineContext.progressiveRender) {\n            // TODO Don't have to do update in large mode. Only do it when there are millions of data.\n            return {\n                update: true\n            };\n        }\n        else {\n            // TODO Use same logic with ScatterView.\n            // Manually update layout\n            var res = linesLayout.reset(seriesModel);\n            if (res.progress) {\n                res.progress({ start: 0, end: data.count() }, data);\n            }\n            this._lineDraw.updateLayout();\n            this._clearLayer(api);\n        }\n    },\n\n    _updateLineDraw: function (data, seriesModel) {\n        var lineDraw = this._lineDraw;\n        var hasEffect = this._showEffect(seriesModel);\n        var isPolyline = !!seriesModel.get('polyline');\n        var pipelineContext = seriesModel.pipelineContext;\n        var isLargeDraw = pipelineContext.large;\n\n        if (__DEV__) {\n            if (hasEffect && isLargeDraw) {\n                console.warn('Large lines not support effect');\n            }\n        }\n        if (!lineDraw\n            || hasEffect !== this._hasEffet\n            || isPolyline !== this._isPolyline\n            || isLargeDraw !== this._isLargeDraw\n        ) {\n            if (lineDraw) {\n                lineDraw.remove();\n            }\n            lineDraw = this._lineDraw = isLargeDraw\n                ? new LargeLineDraw()\n                : new LineDraw(\n                    isPolyline\n                        ? (hasEffect ? EffectPolyline : Polyline$2)\n                        : (hasEffect ? EffectLine : Line$1)\n                );\n            this._hasEffet = hasEffect;\n            this._isPolyline = isPolyline;\n            this._isLargeDraw = isLargeDraw;\n            this.group.removeAll();\n        }\n\n        this.group.add(lineDraw.group);\n\n        return lineDraw;\n    },\n\n    _showEffect: function (seriesModel) {\n        return !!seriesModel.get('effect.show');\n    },\n\n    _clearLayer: function (api) {\n        // Not use motion when dragging or zooming\n        var zr = api.getZr();\n        var isSvg = zr.painter.getType() === 'svg';\n        if (!isSvg && this._lastZlevel != null) {\n            zr.painter.getLayer(this._lastZlevel).clear(true);\n        }\n    },\n\n    remove: function (ecModel, api) {\n        this._lineDraw && this._lineDraw.remove();\n        this._lineDraw = null;\n        // Clear motion when lineDraw is removed\n        this._clearLayer(api);\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction normalize$2(a) {\n    if (!(a instanceof Array)) {\n        a = [a, a];\n    }\n    return a;\n}\n\nvar opacityQuery = 'lineStyle.opacity'.split('.');\n\nvar linesVisual = {\n    seriesType: 'lines',\n    reset: function (seriesModel, ecModel, api) {\n        var symbolType = normalize$2(seriesModel.get('symbol'));\n        var symbolSize = normalize$2(seriesModel.get('symbolSize'));\n        var data = seriesModel.getData();\n\n        data.setVisual('fromSymbol', symbolType && symbolType[0]);\n        data.setVisual('toSymbol', symbolType && symbolType[1]);\n        data.setVisual('fromSymbolSize', symbolSize && symbolSize[0]);\n        data.setVisual('toSymbolSize', symbolSize && symbolSize[1]);\n        data.setVisual('opacity', seriesModel.get(opacityQuery));\n\n        function dataEach(data, idx) {\n            var itemModel = data.getItemModel(idx);\n            var symbolType = normalize$2(itemModel.getShallow('symbol', true));\n            var symbolSize = normalize$2(itemModel.getShallow('symbolSize', true));\n            var opacity = itemModel.get(opacityQuery);\n\n            symbolType[0] && data.setItemVisual(idx, 'fromSymbol', symbolType[0]);\n            symbolType[1] && data.setItemVisual(idx, 'toSymbol', symbolType[1]);\n            symbolSize[0] && data.setItemVisual(idx, 'fromSymbolSize', symbolSize[0]);\n            symbolSize[1] && data.setItemVisual(idx, 'toSymbolSize', symbolSize[1]);\n\n            data.setItemVisual(idx, 'opacity', opacity);\n        }\n\n        return {dataEach: data.hasItemOption ? dataEach : null};\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterLayout(linesLayout);\nregisterVisual(linesVisual);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n    type: 'series.heatmap',\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this, {\n            generateCoord: 'value'\n        });\n    },\n\n    preventIncremental: function () {\n        var coordSysCreator = CoordinateSystemManager.get(this.get('coordinateSystem'));\n        if (coordSysCreator && coordSysCreator.dimensions) {\n            return coordSysCreator.dimensions[0] === 'lng' && coordSysCreator.dimensions[1] === 'lat';\n        }\n    },\n\n    defaultOption: {\n\n        // Cartesian2D or geo\n        coordinateSystem: 'cartesian2d',\n\n        zlevel: 0,\n\n        z: 2,\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // Geo coordinate system\n        geoIndex: 0,\n\n        blurSize: 30,\n\n        pointSize: 20,\n\n        maxOpacity: 1,\n\n        minOpacity: 0\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Uint8ClampedArray */\n\n/**\n * @file defines echarts Heatmap Chart\n * @author Ovilia (me@zhangwenli.com)\n * Inspired by https://github.com/mourner/simpleheat\n *\n * @module\n */\n\nvar GRADIENT_LEVELS = 256;\n\n/**\n * Heatmap Chart\n *\n * @class\n */\nfunction Heatmap() {\n    var canvas = createCanvas();\n    this.canvas = canvas;\n\n    this.blurSize = 30;\n    this.pointSize = 20;\n\n    this.maxOpacity = 1;\n    this.minOpacity = 0;\n\n    this._gradientPixels = {};\n}\n\nHeatmap.prototype = {\n    /**\n     * Renders Heatmap and returns the rendered canvas\n     * @param {Array} data array of data, each has x, y, value\n     * @param {number} width canvas width\n     * @param {number} height canvas height\n     */\n    update: function (data, width, height, normalize, colorFunc, isInRange) {\n        var brush = this._getBrush();\n        var gradientInRange = this._getGradient(data, colorFunc, 'inRange');\n        var gradientOutOfRange = this._getGradient(data, colorFunc, 'outOfRange');\n        var r = this.pointSize + this.blurSize;\n\n        var canvas = this.canvas;\n        var ctx = canvas.getContext('2d');\n        var len = data.length;\n        canvas.width = width;\n        canvas.height = height;\n        for (var i = 0; i < len; ++i) {\n            var p = data[i];\n            var x = p[0];\n            var y = p[1];\n            var value = p[2];\n\n            // calculate alpha using value\n            var alpha = normalize(value);\n\n            // draw with the circle brush with alpha\n            ctx.globalAlpha = alpha;\n            ctx.drawImage(brush, x - r, y - r);\n        }\n\n        if (!canvas.width || !canvas.height) {\n            // Avoid \"Uncaught DOMException: Failed to execute 'getImageData' on\n            // 'CanvasRenderingContext2D': The source height is 0.\"\n            return canvas;\n        }\n\n        // colorize the canvas using alpha value and set with gradient\n        var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n\n        var pixels = imageData.data;\n        var offset = 0;\n        var pixelLen = pixels.length;\n        var minOpacity = this.minOpacity;\n        var maxOpacity = this.maxOpacity;\n        var diffOpacity = maxOpacity - minOpacity;\n\n        while (offset < pixelLen) {\n            var alpha = pixels[offset + 3] / 256;\n            var gradientOffset = Math.floor(alpha * (GRADIENT_LEVELS - 1)) * 4;\n            // Simple optimize to ignore the empty data\n            if (alpha > 0) {\n                var gradient = isInRange(alpha) ? gradientInRange : gradientOutOfRange;\n                // Any alpha > 0 will be mapped to [minOpacity, maxOpacity]\n                alpha > 0 && (alpha = alpha * diffOpacity + minOpacity);\n                pixels[offset++] = gradient[gradientOffset];\n                pixels[offset++] = gradient[gradientOffset + 1];\n                pixels[offset++] = gradient[gradientOffset + 2];\n                pixels[offset++] = gradient[gradientOffset + 3] * alpha * 256;\n            }\n            else {\n                offset += 4;\n            }\n        }\n        ctx.putImageData(imageData, 0, 0);\n\n        return canvas;\n    },\n\n    /**\n     * get canvas of a black circle brush used for canvas to draw later\n     * @private\n     * @returns {Object} circle brush canvas\n     */\n    _getBrush: function () {\n        var brushCanvas = this._brushCanvas || (this._brushCanvas = createCanvas());\n        // set brush size\n        var r = this.pointSize + this.blurSize;\n        var d = r * 2;\n        brushCanvas.width = d;\n        brushCanvas.height = d;\n\n        var ctx = brushCanvas.getContext('2d');\n        ctx.clearRect(0, 0, d, d);\n\n        // in order to render shadow without the distinct circle,\n        // draw the distinct circle in an invisible place,\n        // and use shadowOffset to draw shadow in the center of the canvas\n        ctx.shadowOffsetX = d;\n        ctx.shadowBlur = this.blurSize;\n        // draw the shadow in black, and use alpha and shadow blur to generate\n        // color in color map\n        ctx.shadowColor = '#000';\n\n        // draw circle in the left to the canvas\n        ctx.beginPath();\n        ctx.arc(-r, r, this.pointSize, 0, Math.PI * 2, true);\n        ctx.closePath();\n        ctx.fill();\n        return brushCanvas;\n    },\n\n    /**\n     * get gradient color map\n     * @private\n     */\n    _getGradient: function (data, colorFunc, state) {\n        var gradientPixels = this._gradientPixels;\n        var pixelsSingleState = gradientPixels[state] || (gradientPixels[state] = new Uint8ClampedArray(256 * 4));\n        var color = [0, 0, 0, 0];\n        var off = 0;\n        for (var i = 0; i < 256; i++) {\n            colorFunc[state](i / 255, true, color);\n            pixelsSingleState[off++] = color[0];\n            pixelsSingleState[off++] = color[1];\n            pixelsSingleState[off++] = color[2];\n            pixelsSingleState[off++] = color[3];\n        }\n        return pixelsSingleState;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction getIsInPiecewiseRange(dataExtent, pieceList, selected) {\n    var dataSpan = dataExtent[1] - dataExtent[0];\n    pieceList = map(pieceList, function (piece) {\n        return {\n            interval: [\n                (piece.interval[0] - dataExtent[0]) / dataSpan,\n                (piece.interval[1] - dataExtent[0]) / dataSpan\n            ]\n        };\n    });\n    var len = pieceList.length;\n    var lastIndex = 0;\n\n    return function (val) {\n        // Try to find in the location of the last found\n        for (var i = lastIndex; i < len; i++) {\n            var interval = pieceList[i].interval;\n            if (interval[0] <= val && val <= interval[1]) {\n                lastIndex = i;\n                break;\n            }\n        }\n        if (i === len) { // Not found, back interation\n            for (var i = lastIndex - 1; i >= 0; i--) {\n                var interval = pieceList[i].interval;\n                if (interval[0] <= val && val <= interval[1]) {\n                    lastIndex = i;\n                    break;\n                }\n            }\n        }\n        return i >= 0 && i < len && selected[i];\n    };\n}\n\nfunction getIsInContinuousRange(dataExtent, range) {\n    var dataSpan = dataExtent[1] - dataExtent[0];\n    range = [\n        (range[0] - dataExtent[0]) / dataSpan,\n        (range[1] - dataExtent[0]) / dataSpan\n    ];\n    return function (val) {\n        return val >= range[0] && val <= range[1];\n    };\n}\n\nfunction isGeoCoordSys(coordSys) {\n    var dimensions = coordSys.dimensions;\n    // Not use coorSys.type === 'geo' because coordSys maybe extended\n    return dimensions[0] === 'lng' && dimensions[1] === 'lat';\n}\n\nextendChartView({\n\n    type: 'heatmap',\n\n    render: function (seriesModel, ecModel, api) {\n        var visualMapOfThisSeries;\n        ecModel.eachComponent('visualMap', function (visualMap) {\n            visualMap.eachTargetSeries(function (targetSeries) {\n                if (targetSeries === seriesModel) {\n                    visualMapOfThisSeries = visualMap;\n                }\n            });\n        });\n\n        if (__DEV__) {\n            if (!visualMapOfThisSeries) {\n                throw new Error('Heatmap must use with visualMap');\n            }\n        }\n\n        this.group.removeAll();\n\n        this._incrementalDisplayable = null;\n\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys.type === 'cartesian2d' || coordSys.type === 'calendar') {\n            this._renderOnCartesianAndCalendar(seriesModel, api, 0, seriesModel.getData().count());\n        }\n        else if (isGeoCoordSys(coordSys)) {\n            this._renderOnGeo(\n                coordSys, seriesModel, visualMapOfThisSeries, api\n            );\n        }\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this.group.removeAll();\n    },\n\n    incrementalRender: function (params, seriesModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys) {\n            this._renderOnCartesianAndCalendar(seriesModel, api, params.start, params.end, true);\n        }\n    },\n\n    _renderOnCartesianAndCalendar: function (seriesModel, api, start, end, incremental) {\n\n        var coordSys = seriesModel.coordinateSystem;\n        var width;\n        var height;\n\n        if (coordSys.type === 'cartesian2d') {\n            var xAxis = coordSys.getAxis('x');\n            var yAxis = coordSys.getAxis('y');\n\n            if (__DEV__) {\n                if (!(xAxis.type === 'category' && yAxis.type === 'category')) {\n                    throw new Error('Heatmap on cartesian must have two category axes');\n                }\n                if (!(xAxis.onBand && yAxis.onBand)) {\n                    throw new Error('Heatmap on cartesian must have two axes with boundaryGap true');\n                }\n            }\n\n            width = xAxis.getBandWidth();\n            height = yAxis.getBandWidth();\n        }\n\n        var group = this.group;\n        var data = seriesModel.getData();\n\n        var itemStyleQuery = 'itemStyle';\n        var hoverItemStyleQuery = 'emphasis.itemStyle';\n        var labelQuery = 'label';\n        var hoverLabelQuery = 'emphasis.label';\n        var style = seriesModel.getModel(itemStyleQuery).getItemStyle(['color']);\n        var hoverStl = seriesModel.getModel(hoverItemStyleQuery).getItemStyle();\n        var labelModel = seriesModel.getModel(labelQuery);\n        var hoverLabelModel = seriesModel.getModel(hoverLabelQuery);\n        var coordSysType = coordSys.type;\n\n\n        var dataDims = coordSysType === 'cartesian2d'\n            ? [\n                data.mapDimension('x'),\n                data.mapDimension('y'),\n                data.mapDimension('value')\n            ]\n            : [\n                data.mapDimension('time'),\n                data.mapDimension('value')\n            ];\n\n        for (var idx = start; idx < end; idx++) {\n            var rect;\n\n            if (coordSysType === 'cartesian2d') {\n                // Ignore empty data\n                if (isNaN(data.get(dataDims[2], idx))) {\n                    continue;\n                }\n\n                var point = coordSys.dataToPoint([\n                    data.get(dataDims[0], idx),\n                    data.get(dataDims[1], idx)\n                ]);\n\n                rect = new Rect({\n                    shape: {\n                        x: point[0] - width / 2,\n                        y: point[1] - height / 2,\n                        width: width,\n                        height: height\n                    },\n                    style: {\n                        fill: data.getItemVisual(idx, 'color'),\n                        opacity: data.getItemVisual(idx, 'opacity')\n                    }\n                });\n            }\n            else {\n                // Ignore empty data\n                if (isNaN(data.get(dataDims[1], idx))) {\n                    continue;\n                }\n\n                rect = new Rect({\n                    z2: 1,\n                    shape: coordSys.dataToRect([data.get(dataDims[0], idx)]).contentShape,\n                    style: {\n                        fill: data.getItemVisual(idx, 'color'),\n                        opacity: data.getItemVisual(idx, 'opacity')\n                    }\n                });\n            }\n\n            var itemModel = data.getItemModel(idx);\n\n            // Optimization for large datset\n            if (data.hasItemOption) {\n                style = itemModel.getModel(itemStyleQuery).getItemStyle(['color']);\n                hoverStl = itemModel.getModel(hoverItemStyleQuery).getItemStyle();\n                labelModel = itemModel.getModel(labelQuery);\n                hoverLabelModel = itemModel.getModel(hoverLabelQuery);\n            }\n\n            var rawValue = seriesModel.getRawValue(idx);\n            var defaultText = '-';\n            if (rawValue && rawValue[2] != null) {\n                defaultText = rawValue[2];\n            }\n\n            setLabelStyle(\n                style, hoverStl, labelModel, hoverLabelModel,\n                {\n                    labelFetcher: seriesModel,\n                    labelDataIndex: idx,\n                    defaultText: defaultText,\n                    isRectText: true\n                }\n            );\n\n            rect.setStyle(style);\n            setHoverStyle(rect, data.hasItemOption ? hoverStl : extend({}, hoverStl));\n\n            rect.incremental = incremental;\n            // PENDING\n            if (incremental) {\n                // Rect must use hover layer if it's incremental.\n                rect.useHoverLayer = true;\n            }\n\n            group.add(rect);\n            data.setItemGraphicEl(idx, rect);\n        }\n    },\n\n    _renderOnGeo: function (geo, seriesModel, visualMapModel, api) {\n        var inRangeVisuals = visualMapModel.targetVisuals.inRange;\n        var outOfRangeVisuals = visualMapModel.targetVisuals.outOfRange;\n        // if (!visualMapping) {\n        //     throw new Error('Data range must have color visuals');\n        // }\n\n        var data = seriesModel.getData();\n        var hmLayer = this._hmLayer || (this._hmLayer || new Heatmap());\n        hmLayer.blurSize = seriesModel.get('blurSize');\n        hmLayer.pointSize = seriesModel.get('pointSize');\n        hmLayer.minOpacity = seriesModel.get('minOpacity');\n        hmLayer.maxOpacity = seriesModel.get('maxOpacity');\n\n        var rect = geo.getViewRect().clone();\n        var roamTransform = geo.getRoamTransform();\n        rect.applyTransform(roamTransform);\n\n        // Clamp on viewport\n        var x = Math.max(rect.x, 0);\n        var y = Math.max(rect.y, 0);\n        var x2 = Math.min(rect.width + rect.x, api.getWidth());\n        var y2 = Math.min(rect.height + rect.y, api.getHeight());\n        var width = x2 - x;\n        var height = y2 - y;\n\n        var dims = [\n            data.mapDimension('lng'),\n            data.mapDimension('lat'),\n            data.mapDimension('value')\n        ];\n\n        var points = data.mapArray(dims, function (lng, lat, value) {\n            var pt = geo.dataToPoint([lng, lat]);\n            pt[0] -= x;\n            pt[1] -= y;\n            pt.push(value);\n            return pt;\n        });\n\n        var dataExtent = visualMapModel.getExtent();\n        var isInRange = visualMapModel.type === 'visualMap.continuous'\n            ? getIsInContinuousRange(dataExtent, visualMapModel.option.range)\n            : getIsInPiecewiseRange(\n                dataExtent, visualMapModel.getPieceList(), visualMapModel.option.selected\n            );\n\n        hmLayer.update(\n            points, width, height,\n            inRangeVisuals.color.getNormalizer(),\n            {\n                inRange: inRangeVisuals.color.getColorMapper(),\n                outOfRange: outOfRangeVisuals.color.getColorMapper()\n            },\n            isInRange\n        );\n        var img = new ZImage({\n            style: {\n                width: width,\n                height: height,\n                x: x,\n                y: y,\n                image: hmLayer.canvas\n            },\n            silent: true\n        });\n        this.group.add(img);\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PictorialBarSeries = BaseBarSeries.extend({\n\n    type: 'series.pictorialBar',\n\n    dependencies: ['grid'],\n\n    defaultOption: {\n        symbol: 'circle',     // Customized bar shape\n        symbolSize: null,     // Can be ['100%', '100%'], null means auto.\n        symbolRotate: null,\n\n        symbolPosition: null, // 'start' or 'end' or 'center', null means auto.\n        symbolOffset: null,\n        symbolMargin: null,   // start margin and end margin. Can be a number or a percent string.\n                                // Auto margin by defualt.\n        symbolRepeat: false,  // false/null/undefined, means no repeat.\n                                // Can be true, means auto calculate repeat times and cut by data.\n                                // Can be a number, specifies repeat times, and do not cut by data.\n                                // Can be 'fixed', means auto calculate repeat times but do not cut by data.\n        symbolRepeatDirection: 'end', // 'end' means from 'start' to 'end'.\n\n        symbolClip: false,\n        symbolBoundingData: null, // Can be 60 or -40 or [-40, 60]\n        symbolPatternSize: 400, // 400 * 400 px\n\n        barGap: '-100%',      // In most case, overlap is needed.\n\n        // z can be set in data item, which is z2 actually.\n\n        // Disable progressive\n        progressive: 0,\n        hoverAnimation: false // Open only when needed.\n    },\n\n    getInitialData: function (option) {\n        // Disable stack.\n        option.stack = null;\n        return PictorialBarSeries.superApply(this, 'getInitialData', arguments);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BAR_BORDER_WIDTH_QUERY$1 = ['itemStyle', 'borderWidth'];\n\n// index: +isHorizontal\nvar LAYOUT_ATTRS = [\n    {xy: 'x', wh: 'width', index: 0, posDesc: ['left', 'right']},\n    {xy: 'y', wh: 'height', index: 1, posDesc: ['top', 'bottom']}\n];\n\nvar pathForLineWidth = new Circle();\n\nvar BarView$1 = extendChartView({\n\n    type: 'pictorialBar',\n\n    render: function (seriesModel, ecModel, api) {\n        var group = this.group;\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var isHorizontal = !!baseAxis.isHorizontal();\n        var coordSysRect = cartesian.grid.getRect();\n\n        var opt = {\n            ecSize: {width: api.getWidth(), height: api.getHeight()},\n            seriesModel: seriesModel,\n            coordSys: cartesian,\n            coordSysExtent: [\n                [coordSysRect.x, coordSysRect.x + coordSysRect.width],\n                [coordSysRect.y, coordSysRect.y + coordSysRect.height]\n            ],\n            isHorizontal: isHorizontal,\n            valueDim: LAYOUT_ATTRS[+isHorizontal],\n            categoryDim: LAYOUT_ATTRS[1 - isHorizontal]\n        };\n\n        data.diff(oldData)\n            .add(function (dataIndex) {\n                if (!data.hasValue(dataIndex)) {\n                    return;\n                }\n\n                var itemModel = getItemModel(data, dataIndex);\n                var symbolMeta = getSymbolMeta(data, dataIndex, itemModel, opt);\n\n                var bar = createBar(data, opt, symbolMeta);\n\n                data.setItemGraphicEl(dataIndex, bar);\n                group.add(bar);\n\n                updateCommon$1(bar, opt, symbolMeta);\n            })\n            .update(function (newIndex, oldIndex) {\n                var bar = oldData.getItemGraphicEl(oldIndex);\n\n                if (!data.hasValue(newIndex)) {\n                    group.remove(bar);\n                    return;\n                }\n\n                var itemModel = getItemModel(data, newIndex);\n                var symbolMeta = getSymbolMeta(data, newIndex, itemModel, opt);\n\n                var pictorialShapeStr = getShapeStr(data, symbolMeta);\n                if (bar && pictorialShapeStr !== bar.__pictorialShapeStr) {\n                    group.remove(bar);\n                    data.setItemGraphicEl(newIndex, null);\n                    bar = null;\n                }\n\n                if (bar) {\n                    updateBar(bar, opt, symbolMeta);\n                }\n                else {\n                    bar = createBar(data, opt, symbolMeta, true);\n                }\n\n                data.setItemGraphicEl(newIndex, bar);\n                bar.__pictorialSymbolMeta = symbolMeta;\n                // Add back\n                group.add(bar);\n\n                updateCommon$1(bar, opt, symbolMeta);\n            })\n            .remove(function (dataIndex) {\n                var bar = oldData.getItemGraphicEl(dataIndex);\n                bar && removeBar(oldData, dataIndex, bar.__pictorialSymbolMeta.animationModel, bar);\n            })\n            .execute();\n\n        this._data = data;\n\n        return this.group;\n    },\n\n    dispose: noop,\n\n    remove: function (ecModel, api) {\n        var group = this.group;\n        var data = this._data;\n        if (ecModel.get('animation')) {\n            if (data) {\n                data.eachItemGraphicEl(function (bar) {\n                    removeBar(data, bar.dataIndex, ecModel, bar);\n                });\n            }\n        }\n        else {\n            group.removeAll();\n        }\n    }\n});\n\n\n// Set or calculate default value about symbol, and calculate layout info.\nfunction getSymbolMeta(data, dataIndex, itemModel, opt) {\n    var layout = data.getItemLayout(dataIndex);\n    var symbolRepeat = itemModel.get('symbolRepeat');\n    var symbolClip = itemModel.get('symbolClip');\n    var symbolPosition = itemModel.get('symbolPosition') || 'start';\n    var symbolRotate = itemModel.get('symbolRotate');\n    var rotation = (symbolRotate || 0) * Math.PI / 180 || 0;\n    var symbolPatternSize = itemModel.get('symbolPatternSize') || 2;\n    var isAnimationEnabled = itemModel.isAnimationEnabled();\n\n    var symbolMeta = {\n        dataIndex: dataIndex,\n        layout: layout,\n        itemModel: itemModel,\n        symbolType: data.getItemVisual(dataIndex, 'symbol') || 'circle',\n        color: data.getItemVisual(dataIndex, 'color'),\n        symbolClip: symbolClip,\n        symbolRepeat: symbolRepeat,\n        symbolRepeatDirection: itemModel.get('symbolRepeatDirection'),\n        symbolPatternSize: symbolPatternSize,\n        rotation: rotation,\n        animationModel: isAnimationEnabled ? itemModel : null,\n        hoverAnimation: isAnimationEnabled && itemModel.get('hoverAnimation'),\n        z2: itemModel.getShallow('z', true) || 0\n    };\n\n    prepareBarLength(itemModel, symbolRepeat, layout, opt, symbolMeta);\n\n    prepareSymbolSize(\n        data, dataIndex, layout, symbolRepeat, symbolClip, symbolMeta.boundingLength,\n        symbolMeta.pxSign, symbolPatternSize, opt, symbolMeta\n    );\n\n    prepareLineWidth(itemModel, symbolMeta.symbolScale, rotation, opt, symbolMeta);\n\n    var symbolSize = symbolMeta.symbolSize;\n    var symbolOffset = itemModel.get('symbolOffset');\n    if (isArray(symbolOffset)) {\n        symbolOffset = [\n            parsePercent$1(symbolOffset[0], symbolSize[0]),\n            parsePercent$1(symbolOffset[1], symbolSize[1])\n        ];\n    }\n\n    prepareLayoutInfo(\n        itemModel, symbolSize, layout, symbolRepeat, symbolClip, symbolOffset,\n        symbolPosition, symbolMeta.valueLineWidth, symbolMeta.boundingLength, symbolMeta.repeatCutLength,\n        opt, symbolMeta\n    );\n\n    return symbolMeta;\n}\n\n// bar length can be negative.\nfunction prepareBarLength(itemModel, symbolRepeat, layout, opt, output) {\n    var valueDim = opt.valueDim;\n    var symbolBoundingData = itemModel.get('symbolBoundingData');\n    var valueAxis = opt.coordSys.getOtherAxis(opt.coordSys.getBaseAxis());\n    var zeroPx = valueAxis.toGlobalCoord(valueAxis.dataToCoord(0));\n    var pxSignIdx = 1 - +(layout[valueDim.wh] <= 0);\n    var boundingLength;\n\n    if (isArray(symbolBoundingData)) {\n        var symbolBoundingExtent = [\n            convertToCoordOnAxis(valueAxis, symbolBoundingData[0]) - zeroPx,\n            convertToCoordOnAxis(valueAxis, symbolBoundingData[1]) - zeroPx\n        ];\n        symbolBoundingExtent[1] < symbolBoundingExtent[0] && (symbolBoundingExtent.reverse());\n        boundingLength = symbolBoundingExtent[pxSignIdx];\n    }\n    else if (symbolBoundingData != null) {\n        boundingLength = convertToCoordOnAxis(valueAxis, symbolBoundingData) - zeroPx;\n    }\n    else if (symbolRepeat) {\n        boundingLength = opt.coordSysExtent[valueDim.index][pxSignIdx] - zeroPx;\n    }\n    else {\n        boundingLength = layout[valueDim.wh];\n    }\n\n    output.boundingLength = boundingLength;\n\n    if (symbolRepeat) {\n        output.repeatCutLength = layout[valueDim.wh];\n    }\n\n    output.pxSign = boundingLength > 0 ? 1 : boundingLength < 0 ? -1 : 0;\n}\n\nfunction convertToCoordOnAxis(axis, value) {\n    return axis.toGlobalCoord(axis.dataToCoord(axis.scale.parse(value)));\n}\n\n// Support ['100%', '100%']\nfunction prepareSymbolSize(\n    data, dataIndex, layout, symbolRepeat, symbolClip, boundingLength,\n    pxSign, symbolPatternSize, opt, output\n) {\n    var valueDim = opt.valueDim;\n    var categoryDim = opt.categoryDim;\n    var categorySize = Math.abs(layout[categoryDim.wh]);\n\n    var symbolSize = data.getItemVisual(dataIndex, 'symbolSize');\n    if (isArray(symbolSize)) {\n        symbolSize = symbolSize.slice();\n    }\n    else {\n        if (symbolSize == null) {\n            symbolSize = '100%';\n        }\n        symbolSize = [symbolSize, symbolSize];\n    }\n\n    // Note: percentage symbolSize (like '100%') do not consider lineWidth, because it is\n    // to complicated to calculate real percent value if considering scaled lineWidth.\n    // So the actual size will bigger than layout size if lineWidth is bigger than zero,\n    // which can be tolerated in pictorial chart.\n\n    symbolSize[categoryDim.index] = parsePercent$1(\n        symbolSize[categoryDim.index],\n        categorySize\n    );\n    symbolSize[valueDim.index] = parsePercent$1(\n        symbolSize[valueDim.index],\n        symbolRepeat ? categorySize : Math.abs(boundingLength)\n    );\n\n    output.symbolSize = symbolSize;\n\n    // If x or y is less than zero, show reversed shape.\n    var symbolScale = output.symbolScale = [\n        symbolSize[0] / symbolPatternSize,\n        symbolSize[1] / symbolPatternSize\n    ];\n    // Follow convention, 'right' and 'top' is the normal scale.\n    symbolScale[valueDim.index] *= (opt.isHorizontal ? -1 : 1) * pxSign;\n}\n\nfunction prepareLineWidth(itemModel, symbolScale, rotation, opt, output) {\n    // In symbols are drawn with scale, so do not need to care about the case that width\n    // or height are too small. But symbol use strokeNoScale, where acture lineWidth should\n    // be calculated.\n    var valueLineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY$1) || 0;\n\n    if (valueLineWidth) {\n        pathForLineWidth.attr({\n            scale: symbolScale.slice(),\n            rotation: rotation\n        });\n        pathForLineWidth.updateTransform();\n        valueLineWidth /= pathForLineWidth.getLineScale();\n        valueLineWidth *= symbolScale[opt.valueDim.index];\n    }\n\n    output.valueLineWidth = valueLineWidth;\n}\n\nfunction prepareLayoutInfo(\n    itemModel, symbolSize, layout, symbolRepeat, symbolClip, symbolOffset,\n    symbolPosition, valueLineWidth, boundingLength, repeatCutLength, opt, output\n) {\n    var categoryDim = opt.categoryDim;\n    var valueDim = opt.valueDim;\n    var pxSign = output.pxSign;\n\n    var unitLength = Math.max(symbolSize[valueDim.index] + valueLineWidth, 0);\n    var pathLen = unitLength;\n\n    // Note: rotation will not effect the layout of symbols, because user may\n    // want symbols to rotate on its center, which should not be translated\n    // when rotating.\n\n    if (symbolRepeat) {\n        var absBoundingLength = Math.abs(boundingLength);\n\n        var symbolMargin = retrieve(itemModel.get('symbolMargin'), '15%') + '';\n        var hasEndGap = false;\n        if (symbolMargin.lastIndexOf('!') === symbolMargin.length - 1) {\n            hasEndGap = true;\n            symbolMargin = symbolMargin.slice(0, symbolMargin.length - 1);\n        }\n        symbolMargin = parsePercent$1(symbolMargin, symbolSize[valueDim.index]);\n\n        var uLenWithMargin = Math.max(unitLength + symbolMargin * 2, 0);\n\n        // When symbol margin is less than 0, margin at both ends will be subtracted\n        // to ensure that all of the symbols will not be overflow the given area.\n        var endFix = hasEndGap ? 0 : symbolMargin * 2;\n\n        // Both final repeatTimes and final symbolMargin area calculated based on\n        // boundingLength.\n        var repeatSpecified = isNumeric(symbolRepeat);\n        var repeatTimes = repeatSpecified\n            ? symbolRepeat\n            : toIntTimes((absBoundingLength + endFix) / uLenWithMargin);\n\n        // Adjust calculate margin, to ensure each symbol is displayed\n        // entirely in the given layout area.\n        var mDiff = absBoundingLength - repeatTimes * unitLength;\n        symbolMargin = mDiff / 2 / (hasEndGap ? repeatTimes : repeatTimes - 1);\n        uLenWithMargin = unitLength + symbolMargin * 2;\n        endFix = hasEndGap ? 0 : symbolMargin * 2;\n\n        // Update repeatTimes when not all symbol will be shown.\n        if (!repeatSpecified && symbolRepeat !== 'fixed') {\n            repeatTimes = repeatCutLength\n                ? toIntTimes((Math.abs(repeatCutLength) + endFix) / uLenWithMargin)\n                : 0;\n        }\n\n        pathLen = repeatTimes * uLenWithMargin - endFix;\n        output.repeatTimes = repeatTimes;\n        output.symbolMargin = symbolMargin;\n    }\n\n    var sizeFix = pxSign * (pathLen / 2);\n    var pathPosition = output.pathPosition = [];\n    pathPosition[categoryDim.index] = layout[categoryDim.wh] / 2;\n    pathPosition[valueDim.index] = symbolPosition === 'start'\n        ? sizeFix\n        : symbolPosition === 'end'\n        ? boundingLength - sizeFix\n        : boundingLength / 2; // 'center'\n    if (symbolOffset) {\n        pathPosition[0] += symbolOffset[0];\n        pathPosition[1] += symbolOffset[1];\n    }\n\n    var bundlePosition = output.bundlePosition = [];\n    bundlePosition[categoryDim.index] = layout[categoryDim.xy];\n    bundlePosition[valueDim.index] = layout[valueDim.xy];\n\n    var barRectShape = output.barRectShape = extend({}, layout);\n    barRectShape[valueDim.wh] = pxSign * Math.max(\n        Math.abs(layout[valueDim.wh]), Math.abs(pathPosition[valueDim.index] + sizeFix)\n    );\n    barRectShape[categoryDim.wh] = layout[categoryDim.wh];\n\n    var clipShape = output.clipShape = {};\n    // Consider that symbol may be overflow layout rect.\n    clipShape[categoryDim.xy] = -layout[categoryDim.xy];\n    clipShape[categoryDim.wh] = opt.ecSize[categoryDim.wh];\n    clipShape[valueDim.xy] = 0;\n    clipShape[valueDim.wh] = layout[valueDim.wh];\n}\n\nfunction createPath(symbolMeta) {\n    var symbolPatternSize = symbolMeta.symbolPatternSize;\n    var path = createSymbol(\n        // Consider texture img, make a big size.\n        symbolMeta.symbolType,\n        -symbolPatternSize / 2,\n        -symbolPatternSize / 2,\n        symbolPatternSize,\n        symbolPatternSize,\n        symbolMeta.color\n    );\n    path.attr({\n        culling: true\n    });\n    path.type !== 'image' && path.setStyle({\n        strokeNoScale: true\n    });\n\n    return path;\n}\n\nfunction createOrUpdateRepeatSymbols(bar, opt, symbolMeta, isUpdate) {\n    var bundle = bar.__pictorialBundle;\n    var symbolSize = symbolMeta.symbolSize;\n    var valueLineWidth = symbolMeta.valueLineWidth;\n    var pathPosition = symbolMeta.pathPosition;\n    var valueDim = opt.valueDim;\n    var repeatTimes = symbolMeta.repeatTimes || 0;\n\n    var index = 0;\n    var unit = symbolSize[opt.valueDim.index] + valueLineWidth + symbolMeta.symbolMargin * 2;\n\n    eachPath(bar, function (path) {\n        path.__pictorialAnimationIndex = index;\n        path.__pictorialRepeatTimes = repeatTimes;\n        if (index < repeatTimes) {\n            updateAttr(path, null, makeTarget(index), symbolMeta, isUpdate);\n        }\n        else {\n            updateAttr(path, null, {scale: [0, 0]}, symbolMeta, isUpdate, function () {\n                bundle.remove(path);\n            });\n        }\n\n        updateHoverAnimation(path, symbolMeta);\n\n        index++;\n    });\n\n    for (; index < repeatTimes; index++) {\n        var path = createPath(symbolMeta);\n        path.__pictorialAnimationIndex = index;\n        path.__pictorialRepeatTimes = repeatTimes;\n        bundle.add(path);\n\n        var target = makeTarget(index);\n\n        updateAttr(\n            path,\n            {\n                position: target.position,\n                scale: [0, 0]\n            },\n            {\n                scale: target.scale,\n                rotation: target.rotation\n            },\n            symbolMeta,\n            isUpdate\n        );\n\n        // FIXME\n        // If all emphasis/normal through action.\n        path\n            .on('mouseover', onMouseOver)\n            .on('mouseout', onMouseOut);\n\n        updateHoverAnimation(path, symbolMeta);\n    }\n\n    function makeTarget(index) {\n        var position = pathPosition.slice();\n        // (start && pxSign > 0) || (end && pxSign < 0): i = repeatTimes - index\n        // Otherwise: i = index;\n        var pxSign = symbolMeta.pxSign;\n        var i = index;\n        if (symbolMeta.symbolRepeatDirection === 'start' ? pxSign > 0 : pxSign < 0) {\n            i = repeatTimes - 1 - index;\n        }\n        position[valueDim.index] = unit * (i - repeatTimes / 2 + 0.5) + pathPosition[valueDim.index];\n\n        return {\n            position: position,\n            scale: symbolMeta.symbolScale.slice(),\n            rotation: symbolMeta.rotation\n        };\n    }\n\n    function onMouseOver() {\n        eachPath(bar, function (path) {\n            path.trigger('emphasis');\n        });\n    }\n\n    function onMouseOut() {\n        eachPath(bar, function (path) {\n            path.trigger('normal');\n        });\n    }\n}\n\nfunction createOrUpdateSingleSymbol(bar, opt, symbolMeta, isUpdate) {\n    var bundle = bar.__pictorialBundle;\n    var mainPath = bar.__pictorialMainPath;\n\n    if (!mainPath) {\n        mainPath = bar.__pictorialMainPath = createPath(symbolMeta);\n        bundle.add(mainPath);\n\n        updateAttr(\n            mainPath,\n            {\n                position: symbolMeta.pathPosition.slice(),\n                scale: [0, 0],\n                rotation: symbolMeta.rotation\n            },\n            {\n                scale: symbolMeta.symbolScale.slice()\n            },\n            symbolMeta,\n            isUpdate\n        );\n\n        mainPath\n            .on('mouseover', onMouseOver)\n            .on('mouseout', onMouseOut);\n    }\n    else {\n        updateAttr(\n            mainPath,\n            null,\n            {\n                position: symbolMeta.pathPosition.slice(),\n                scale: symbolMeta.symbolScale.slice(),\n                rotation: symbolMeta.rotation\n            },\n            symbolMeta,\n            isUpdate\n        );\n    }\n\n    updateHoverAnimation(mainPath, symbolMeta);\n\n    function onMouseOver() {\n        this.trigger('emphasis');\n    }\n\n    function onMouseOut() {\n        this.trigger('normal');\n    }\n}\n\n// bar rect is used for label.\nfunction createOrUpdateBarRect(bar, symbolMeta, isUpdate) {\n    var rectShape = extend({}, symbolMeta.barRectShape);\n\n    var barRect = bar.__pictorialBarRect;\n    if (!barRect) {\n        barRect = bar.__pictorialBarRect = new Rect({\n            z2: 2,\n            shape: rectShape,\n            silent: true,\n            style: {\n                stroke: 'transparent',\n                fill: 'transparent',\n                lineWidth: 0\n            }\n        });\n\n        bar.add(barRect);\n    }\n    else {\n        updateAttr(barRect, null, {shape: rectShape}, symbolMeta, isUpdate);\n    }\n}\n\nfunction createOrUpdateClip(bar, opt, symbolMeta, isUpdate) {\n    // If not clip, symbol will be remove and rebuilt.\n    if (symbolMeta.symbolClip) {\n        var clipPath = bar.__pictorialClipPath;\n        var clipShape = extend({}, symbolMeta.clipShape);\n        var valueDim = opt.valueDim;\n        var animationModel = symbolMeta.animationModel;\n        var dataIndex = symbolMeta.dataIndex;\n\n        if (clipPath) {\n            updateProps(\n                clipPath, {shape: clipShape}, animationModel, dataIndex\n            );\n        }\n        else {\n            clipShape[valueDim.wh] = 0;\n            clipPath = new Rect({shape: clipShape});\n            bar.__pictorialBundle.setClipPath(clipPath);\n            bar.__pictorialClipPath = clipPath;\n\n            var target = {};\n            target[valueDim.wh] = symbolMeta.clipShape[valueDim.wh];\n\n            graphic[isUpdate ? 'updateProps' : 'initProps'](\n                clipPath, {shape: target}, animationModel, dataIndex\n            );\n        }\n    }\n}\n\nfunction getItemModel(data, dataIndex) {\n    var itemModel = data.getItemModel(dataIndex);\n    itemModel.getAnimationDelayParams = getAnimationDelayParams;\n    itemModel.isAnimationEnabled = isAnimationEnabled;\n    return itemModel;\n}\n\nfunction getAnimationDelayParams(path) {\n    // The order is the same as the z-order, see `symbolRepeatDiretion`.\n    return {\n        index: path.__pictorialAnimationIndex,\n        count: path.__pictorialRepeatTimes\n    };\n}\n\nfunction isAnimationEnabled() {\n    // `animation` prop can be set on itemModel in pictorial bar chart.\n    return this.parentModel.isAnimationEnabled() && !!this.getShallow('animation');\n}\n\nfunction updateHoverAnimation(path, symbolMeta) {\n    path.off('emphasis').off('normal');\n\n    var scale = symbolMeta.symbolScale.slice();\n\n    symbolMeta.hoverAnimation && path\n        .on('emphasis', function () {\n            this.animateTo({\n                scale: [scale[0] * 1.1, scale[1] * 1.1]\n            }, 400, 'elasticOut');\n        })\n        .on('normal', function () {\n            this.animateTo({\n                scale: scale.slice()\n            }, 400, 'elasticOut');\n        });\n}\n\nfunction createBar(data, opt, symbolMeta, isUpdate) {\n    // bar is the main element for each data.\n    var bar = new Group();\n    // bundle is used for location and clip.\n    var bundle = new Group();\n    bar.add(bundle);\n    bar.__pictorialBundle = bundle;\n    bundle.attr('position', symbolMeta.bundlePosition.slice());\n\n    if (symbolMeta.symbolRepeat) {\n        createOrUpdateRepeatSymbols(bar, opt, symbolMeta);\n    }\n    else {\n        createOrUpdateSingleSymbol(bar, opt, symbolMeta);\n    }\n\n    createOrUpdateBarRect(bar, symbolMeta, isUpdate);\n\n    createOrUpdateClip(bar, opt, symbolMeta, isUpdate);\n\n    bar.__pictorialShapeStr = getShapeStr(data, symbolMeta);\n    bar.__pictorialSymbolMeta = symbolMeta;\n\n    return bar;\n}\n\nfunction updateBar(bar, opt, symbolMeta) {\n    var animationModel = symbolMeta.animationModel;\n    var dataIndex = symbolMeta.dataIndex;\n    var bundle = bar.__pictorialBundle;\n\n    updateProps(\n        bundle, {position: symbolMeta.bundlePosition.slice()}, animationModel, dataIndex\n    );\n\n    if (symbolMeta.symbolRepeat) {\n        createOrUpdateRepeatSymbols(bar, opt, symbolMeta, true);\n    }\n    else {\n        createOrUpdateSingleSymbol(bar, opt, symbolMeta, true);\n    }\n\n    createOrUpdateBarRect(bar, symbolMeta, true);\n\n    createOrUpdateClip(bar, opt, symbolMeta, true);\n}\n\nfunction removeBar(data, dataIndex, animationModel, bar) {\n    // Not show text when animating\n    var labelRect = bar.__pictorialBarRect;\n    labelRect && (labelRect.style.text = null);\n\n    var pathes = [];\n    eachPath(bar, function (path) {\n        pathes.push(path);\n    });\n    bar.__pictorialMainPath && pathes.push(bar.__pictorialMainPath);\n\n    // I do not find proper remove animation for clip yet.\n    bar.__pictorialClipPath && (animationModel = null);\n\n    each$1(pathes, function (path) {\n        updateProps(\n            path, {scale: [0, 0]}, animationModel, dataIndex,\n            function () {\n                bar.parent && bar.parent.remove(bar);\n            }\n        );\n    });\n\n    data.setItemGraphicEl(dataIndex, null);\n}\n\nfunction getShapeStr(data, symbolMeta) {\n    return [\n        data.getItemVisual(symbolMeta.dataIndex, 'symbol') || 'none',\n        !!symbolMeta.symbolRepeat,\n        !!symbolMeta.symbolClip\n    ].join(':');\n}\n\nfunction eachPath(bar, cb, context) {\n    // Do not use Group#eachChild, because it do not support remove.\n    each$1(bar.__pictorialBundle.children(), function (el) {\n        el !== bar.__pictorialBarRect && cb.call(context, el);\n    });\n}\n\nfunction updateAttr(el, immediateAttrs, animationAttrs, symbolMeta, isUpdate, cb) {\n    immediateAttrs && el.attr(immediateAttrs);\n    // when symbolCip used, only clip path has init animation, otherwise it would be weird effect.\n    if (symbolMeta.symbolClip && !isUpdate) {\n        animationAttrs && el.attr(animationAttrs);\n    }\n    else {\n        animationAttrs && graphic[isUpdate ? 'updateProps' : 'initProps'](\n            el, animationAttrs, symbolMeta.animationModel, symbolMeta.dataIndex, cb\n        );\n    }\n}\n\nfunction updateCommon$1(bar, opt, symbolMeta) {\n    var color = symbolMeta.color;\n    var dataIndex = symbolMeta.dataIndex;\n    var itemModel = symbolMeta.itemModel;\n    // Color must be excluded.\n    // Because symbol provide setColor individually to set fill and stroke\n    var normalStyle = itemModel.getModel('itemStyle').getItemStyle(['color']);\n    var hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n    var cursorStyle = itemModel.getShallow('cursor');\n\n    eachPath(bar, function (path) {\n        // PENDING setColor should be before setStyle!!!\n        path.setColor(color);\n        path.setStyle(defaults(\n            {\n                fill: color,\n                opacity: symbolMeta.opacity\n            },\n            normalStyle\n        ));\n        setHoverStyle(path, hoverStyle);\n\n        cursorStyle && (path.cursor = cursorStyle);\n        path.z2 = symbolMeta.z2;\n    });\n\n    var barRectHoverStyle = {};\n    var barPositionOutside = opt.valueDim.posDesc[+(symbolMeta.boundingLength > 0)];\n    var barRect = bar.__pictorialBarRect;\n\n    setLabel(\n        barRect.style, barRectHoverStyle, itemModel,\n        color, opt.seriesModel, dataIndex, barPositionOutside\n    );\n\n    setHoverStyle(barRect, barRectHoverStyle);\n}\n\nfunction toIntTimes(times) {\n    var roundedTimes = Math.round(times);\n    // Escapse accurate error\n    return Math.abs(times - roundedTimes) < 1e-4\n        ? roundedTimes\n        : Math.ceil(times);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterLayout(curry(\n    layout, 'pictorialBar'\n));\nregisterVisual(visualSymbol('pictorialBar', 'roundRect'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @constructor  module:echarts/coord/single/SingleAxis\n * @extends {module:echarts/coord/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n * @param {string} position\n */\nvar SingleAxis = function (dim, scale, coordExtent, axisType, position) {\n\n    Axis.call(this, dim, scale, coordExtent);\n\n    /**\n     * Axis type\n     * - 'category'\n     * - 'value'\n     * - 'time'\n     * - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * Axis position\n     *  - 'top'\n     *  - 'bottom'\n     *  - 'left'\n     *  - 'right'\n     *  @type {string}\n     */\n    this.position = position || 'bottom';\n\n    /**\n     * Axis orient\n     *  - 'horizontal'\n     *  - 'vertical'\n     * @type {[type]}\n     */\n    this.orient = null;\n\n};\n\nSingleAxis.prototype = {\n\n    constructor: SingleAxis,\n\n    /**\n     * Axis model\n     * @type {module:echarts/coord/single/AxisModel}\n     */\n    model: null,\n\n    /**\n     * Judge the orient of the axis.\n     * @return {boolean}\n     */\n    isHorizontal: function () {\n        var position = this.position;\n        return position === 'top' || position === 'bottom';\n\n    },\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.coordinateSystem.pointToData(point, clamp)[0];\n    },\n\n    /**\n     * Convert the local coord(processed by dataToCoord())\n     * to global coord(concrete pixel coord).\n     * designated by module:echarts/coord/single/Single.\n     * @type {Function}\n     */\n    toGlobalCoord: null,\n\n    /**\n     * Convert the global coord to local coord.\n     * designated by module:echarts/coord/single/Single.\n     * @type {Function}\n     */\n    toLocalCoord: null\n\n};\n\ninherits(SingleAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Single coordinates system.\n */\n\n/**\n * Create a single coordinates system.\n *\n * @param {module:echarts/coord/single/AxisModel} axisModel\n * @param {module:echarts/model/Global} ecModel\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction Single(axisModel, ecModel, api) {\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.dimension = 'single';\n\n    /**\n     * Add it just for draw tooltip.\n     *\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    this.dimensions = ['single'];\n\n    /**\n     * @private\n     * @type {module:echarts/coord/single/SingleAxis}.\n     */\n    this._axis = null;\n\n    /**\n     * @private\n     * @type {module:zrender/core/BoundingRect}\n     */\n    this._rect;\n\n    this._init(axisModel, ecModel, api);\n\n    /**\n     * @type {module:echarts/coord/single/AxisModel}\n     */\n    this.model = axisModel;\n}\n\nSingle.prototype = {\n\n    type: 'singleAxis',\n\n    axisPointerEnabled: true,\n\n    constructor: Single,\n\n    /**\n     * Initialize single coordinate system.\n     *\n     * @param  {module:echarts/coord/single/AxisModel} axisModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @private\n     */\n    _init: function (axisModel, ecModel, api) {\n\n        var dim = this.dimension;\n\n        var axis = new SingleAxis(\n            dim,\n            createScaleByModel(axisModel),\n            [0, 0],\n            axisModel.get('type'),\n            axisModel.get('position')\n        );\n\n        var isCategory = axis.type === 'category';\n        axis.onBand = isCategory && axisModel.get('boundaryGap');\n        axis.inverse = axisModel.get('inverse');\n        axis.orient = axisModel.get('orient');\n\n        axisModel.axis = axis;\n        axis.model = axisModel;\n        axis.coordinateSystem = this;\n        this._axis = axis;\n    },\n\n    /**\n     * Update axis scale after data processed\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    update: function (ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            if (seriesModel.coordinateSystem === this) {\n                var data = seriesModel.getData();\n                each$1(data.mapDimension(this.dimension, true), function (dim) {\n                    this._axis.scale.unionExtentFromData(data, dim);\n                }, this);\n                niceScaleExtent(this._axis.scale, this._axis.model);\n            }\n        }, this);\n    },\n\n    /**\n     * Resize the single coordinate system.\n     *\n     * @param  {module:echarts/coord/single/AxisModel} axisModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    resize: function (axisModel, api) {\n        this._rect = getLayoutRect(\n            {\n                left: axisModel.get('left'),\n                top: axisModel.get('top'),\n                right: axisModel.get('right'),\n                bottom: axisModel.get('bottom'),\n                width: axisModel.get('width'),\n                height: axisModel.get('height')\n            },\n            {\n                width: api.getWidth(),\n                height: api.getHeight()\n            }\n        );\n\n        this._adjustAxis();\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getRect: function () {\n        return this._rect;\n    },\n\n    /**\n     * @private\n     */\n    _adjustAxis: function () {\n\n        var rect = this._rect;\n        var axis = this._axis;\n\n        var isHorizontal = axis.isHorizontal();\n        var extent = isHorizontal ? [0, rect.width] : [0, rect.height];\n        var idx = axis.reverse ? 1 : 0;\n\n        axis.setExtent(extent[idx], extent[1 - idx]);\n\n        this._updateAxisTransform(axis, isHorizontal ? rect.x : rect.y);\n\n    },\n\n    /**\n     * @param  {module:echarts/coord/single/SingleAxis} axis\n     * @param  {number} coordBase\n     */\n    _updateAxisTransform: function (axis, coordBase) {\n\n        var axisExtent = axis.getExtent();\n        var extentSum = axisExtent[0] + axisExtent[1];\n        var isHorizontal = axis.isHorizontal();\n\n        axis.toGlobalCoord = isHorizontal\n            ? function (coord) {\n                return coord + coordBase;\n            }\n            : function (coord) {\n                return extentSum - coord + coordBase;\n            };\n\n        axis.toLocalCoord = isHorizontal\n            ? function (coord) {\n                return coord - coordBase;\n            }\n            : function (coord) {\n                return extentSum - coord + coordBase;\n            };\n    },\n\n    /**\n     * Get axis.\n     *\n     * @return {module:echarts/coord/single/SingleAxis}\n     */\n    getAxis: function () {\n        return this._axis;\n    },\n\n    /**\n     * Get axis, add it just for draw tooltip.\n     *\n     * @return {[type]} [description]\n     */\n    getBaseAxis: function () {\n        return this._axis;\n    },\n\n    /**\n     * @return {Array.<module:echarts/coord/Axis>}\n     */\n    getAxes: function () {\n        return [this._axis];\n    },\n\n    /**\n     * @return {Object} {baseAxes: [], otherAxes: []}\n     */\n    getTooltipAxes: function () {\n        return {baseAxes: [this.getAxis()]};\n    },\n\n    /**\n     * If contain point.\n     *\n     * @param  {Array.<number>} point\n     * @return {boolean}\n     */\n    containPoint: function (point) {\n        var rect = this.getRect();\n        var axis = this.getAxis();\n        var orient = axis.orient;\n        if (orient === 'horizontal') {\n            return axis.contain(axis.toLocalCoord(point[0]))\n            && (point[1] >= rect.y && point[1] <= (rect.y + rect.height));\n        }\n        else {\n            return axis.contain(axis.toLocalCoord(point[1]))\n            && (point[0] >= rect.y && point[0] <= (rect.y + rect.height));\n        }\n    },\n\n    /**\n     * @param {Array.<number>} point\n     * @return {Array.<number>}\n     */\n    pointToData: function (point) {\n        var axis = this.getAxis();\n        return [axis.coordToData(axis.toLocalCoord(\n            point[axis.orient === 'horizontal' ? 0 : 1]\n        ))];\n    },\n\n    /**\n     * Convert the series data to concrete point.\n     *\n     * @param  {number|Array.<number>} val\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (val) {\n        var axis = this.getAxis();\n        var rect = this.getRect();\n        var pt = [];\n        var idx = axis.orient === 'horizontal' ? 0 : 1;\n\n        if (val instanceof Array) {\n            val = val[0];\n        }\n\n        pt[idx] = axis.toGlobalCoord(axis.dataToCoord(+val));\n        pt[1 - idx] = idx === 0 ? (rect.y + rect.height / 2) : (rect.x + rect.width / 2);\n        return pt;\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Single coordinate system creator.\n */\n\n/**\n * Create single coordinate system and inject it into seriesModel.\n *\n * @param {module:echarts/model/Global} ecModel\n * @param {module:echarts/ExtensionAPI} api\n * @return {Array.<module:echarts/coord/single/Single>}\n */\nfunction create$3(ecModel, api) {\n    var singles = [];\n\n    ecModel.eachComponent('singleAxis', function (axisModel, idx) {\n\n        var single = new Single(axisModel, ecModel, api);\n        single.name = 'single_' + idx;\n        single.resize(axisModel, api);\n        axisModel.coordinateSystem = single;\n        singles.push(single);\n\n    });\n\n    ecModel.eachSeries(function (seriesModel) {\n        if (seriesModel.get('coordinateSystem') === 'singleAxis') {\n            var singleAxisModel = ecModel.queryComponents({\n                mainType: 'singleAxis',\n                index: seriesModel.get('singleAxisIndex'),\n                id: seriesModel.get('singleAxisId')\n            })[0];\n            seriesModel.coordinateSystem = singleAxisModel && singleAxisModel.coordinateSystem;\n        }\n    });\n\n    return singles;\n}\n\nCoordinateSystemManager.register('single', {\n    create: create$3,\n    dimensions: Single.prototype.dimensions\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} opt {labelInside}\n * @return {Object} {\n *  position, rotation, labelDirection, labelOffset,\n *  tickDirection, labelRotate, z2\n * }\n */\nfunction layout$2(axisModel, opt) {\n    opt = opt || {};\n    var single = axisModel.coordinateSystem;\n    var axis = axisModel.axis;\n    var layout = {};\n\n    var axisPosition = axis.position;\n    var orient = axis.orient;\n\n    var rect = single.getRect();\n    var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];\n\n    var positionMap = {\n        horizontal: {top: rectBound[2], bottom: rectBound[3]},\n        vertical: {left: rectBound[0], right: rectBound[1]}\n    };\n\n    layout.position = [\n        orient === 'vertical'\n            ? positionMap.vertical[axisPosition]\n            : rectBound[0],\n        orient === 'horizontal'\n            ? positionMap.horizontal[axisPosition]\n            : rectBound[3]\n    ];\n\n    var r = {horizontal: 0, vertical: 1};\n    layout.rotation = Math.PI / 2 * r[orient];\n\n    var directionMap = {top: -1, bottom: 1, right: 1, left: -1};\n\n    layout.labelDirection = layout.tickDirection\n        = layout.nameDirection\n        = directionMap[axisPosition];\n\n    if (axisModel.get('axisTick.inside')) {\n        layout.tickDirection = -layout.tickDirection;\n    }\n\n    if (retrieve(opt.labelInside, axisModel.get('axisLabel.inside'))) {\n        layout.labelDirection = -layout.labelDirection;\n    }\n\n    var labelRotation = opt.rotate;\n    labelRotation == null && (labelRotation = axisModel.get('axisLabel.rotate'));\n    layout.labelRotation = axisPosition === 'top' ? -labelRotation : labelRotation;\n\n    layout.z2 = 1;\n\n    return layout;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar axisBuilderAttrs$2 = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\n\nvar selfBuilderAttr = 'splitLine';\n\nvar SingleAxisView = AxisView.extend({\n\n    type: 'singleAxis',\n\n    axisPointerClass: 'SingleAxisPointer',\n\n    render: function (axisModel, ecModel, api, payload) {\n\n        var group = this.group;\n\n        group.removeAll();\n\n        var layout = layout$2(axisModel);\n\n        var axisBuilder = new AxisBuilder(axisModel, layout);\n\n        each$1(axisBuilderAttrs$2, axisBuilder.add, axisBuilder);\n\n        group.add(axisBuilder.getGroup());\n\n        if (axisModel.get(selfBuilderAttr + '.show')) {\n            this['_' + selfBuilderAttr](axisModel);\n        }\n\n        SingleAxisView.superCall(this, 'render', axisModel, ecModel, api, payload);\n    },\n\n    _splitLine: function (axisModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitLineModel = axisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineWidth = lineStyleModel.get('width');\n        var lineColors = lineStyleModel.get('color');\n\n        lineColors = lineColors instanceof Array ? lineColors : [lineColors];\n\n        var gridRect = axisModel.coordinateSystem.getRect();\n        var isHorizontal = axis.isHorizontal();\n\n        var splitLines = [];\n        var lineCount = 0;\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitLineModel\n        });\n\n        var p1 = [];\n        var p2 = [];\n\n        for (var i = 0; i < ticksCoords.length; ++i) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n            if (isHorizontal) {\n                p1[0] = tickCoord;\n                p1[1] = gridRect.y;\n                p2[0] = tickCoord;\n                p2[1] = gridRect.y + gridRect.height;\n            }\n            else {\n                p1[0] = gridRect.x;\n                p1[1] = tickCoord;\n                p2[0] = gridRect.x + gridRect.width;\n                p2[1] = tickCoord;\n            }\n            var colorIndex = (lineCount++) % lineColors.length;\n            splitLines[colorIndex] = splitLines[colorIndex] || [];\n            splitLines[colorIndex].push(new Line(\n                subPixelOptimizeLine({\n                    shape: {\n                        x1: p1[0],\n                        y1: p1[1],\n                        x2: p2[0],\n                        y2: p2[1]\n                    },\n                    style: {\n                        lineWidth: lineWidth\n                    },\n                    silent: true\n                })));\n        }\n\n        for (var i = 0; i < splitLines.length; ++i) {\n            this.group.add(mergePath(splitLines[i], {\n                style: {\n                    stroke: lineColors[i % lineColors.length],\n                    lineDash: lineStyleModel.getLineDash(lineWidth),\n                    lineWidth: lineWidth\n                },\n                silent: true\n            }));\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisModel$4 = ComponentModel.extend({\n\n    type: 'singleAxis',\n\n    layoutMode: 'box',\n\n    /**\n     * @type {module:echarts/coord/single/SingleAxis}\n     */\n    axis: null,\n\n    /**\n     * @type {module:echarts/coord/single/Single}\n     */\n    coordinateSystem: null,\n\n    /**\n     * @override\n     */\n    getCoordSysModel: function () {\n        return this;\n    }\n\n});\n\nvar defaultOption$2 = {\n\n    left: '5%',\n    top: '5%',\n    right: '5%',\n    bottom: '5%',\n\n    type: 'value',\n\n    position: 'bottom',\n\n    orient: 'horizontal',\n\n    axisLine: {\n        show: true,\n        lineStyle: {\n            width: 2,\n            type: 'solid'\n        }\n    },\n\n    // Single coordinate system and single axis is the,\n    // which is used as the parent tooltip model.\n    // same model, so we set default tooltip show as true.\n    tooltip: {\n        show: true\n    },\n\n    axisTick: {\n        show: true,\n        length: 6,\n        lineStyle: {\n            width: 2\n        }\n    },\n\n    axisLabel: {\n        show: true,\n        interval: 'auto'\n    },\n\n    splitLine: {\n        show: true,\n        lineStyle: {\n            type: 'dashed',\n            opacity: 0.2\n        }\n    }\n};\n\nfunction getAxisType$2(axisName, option) {\n    return option.type || (option.data ? 'category' : 'value');\n}\n\nmerge(AxisModel$4.prototype, axisModelCommonMixin);\n\naxisModelCreator('single', AxisModel$4, getAxisType$2, defaultOption$2);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} finder contains {seriesIndex, dataIndex, dataIndexInside}\n * @param {module:echarts/model/Global} ecModel\n * @return {Object} {point: [x, y], el: ...} point Will not be null.\n */\nvar findPointFromSeries = function (finder, ecModel) {\n    var point = [];\n    var seriesIndex = finder.seriesIndex;\n    var seriesModel;\n    if (seriesIndex == null || !(\n        seriesModel = ecModel.getSeriesByIndex(seriesIndex)\n    )) {\n        return {point: []};\n    }\n\n    var data = seriesModel.getData();\n    var dataIndex = queryDataIndex(data, finder);\n    if (dataIndex == null || dataIndex < 0 || isArray(dataIndex)) {\n        return {point: []};\n    }\n\n    var el = data.getItemGraphicEl(dataIndex);\n    var coordSys = seriesModel.coordinateSystem;\n\n    if (seriesModel.getTooltipPosition) {\n        point = seriesModel.getTooltipPosition(dataIndex) || [];\n    }\n    else if (coordSys && coordSys.dataToPoint) {\n        point = coordSys.dataToPoint(\n            data.getValues(\n                map(coordSys.dimensions, function (dim) {\n                    return data.mapDimension(dim);\n                }), dataIndex, true\n            )\n        ) || [];\n    }\n    else if (el) {\n        // Use graphic bounding rect\n        var rect = el.getBoundingRect().clone();\n        rect.applyTransform(el.transform);\n        point = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    }\n\n    return {point: point, el: el};\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$14 = each$1;\nvar curry$3 = curry;\nvar inner$9 = makeInner();\n\n/**\n * Basic logic: check all axis, if they do not demand show/highlight,\n * then hide/downplay them.\n *\n * @param {Object} coordSysAxesInfo\n * @param {Object} payload\n * @param {string} [payload.currTrigger] 'click' | 'mousemove' | 'leave'\n * @param {Array.<number>} [payload.x] x and y, which are mandatory, specify a point to\n *              trigger axisPointer and tooltip.\n * @param {Array.<number>} [payload.y] x and y, which are mandatory, specify a point to\n *              trigger axisPointer and tooltip.\n * @param {Object} [payload.seriesIndex] finder, optional, restrict target axes.\n * @param {Object} [payload.dataIndex] finder, restrict target axes.\n * @param {Object} [payload.axesInfo] finder, restrict target axes.\n *        [{\n *          axisDim: 'x'|'y'|'angle'|...,\n *          axisIndex: ...,\n *          value: ...\n *        }, ...]\n * @param {Function} [payload.dispatchAction]\n * @param {Object} [payload.tooltipOption]\n * @param {Object|Array.<number>|Function} [payload.position] Tooltip position,\n *        which can be specified in dispatchAction\n * @param {module:echarts/model/Global} ecModel\n * @param {module:echarts/ExtensionAPI} api\n * @return {Object} content of event obj for echarts.connect.\n */\nvar axisTrigger = function (payload, ecModel, api) {\n    var currTrigger = payload.currTrigger;\n    var point = [payload.x, payload.y];\n    var finder = payload;\n    var dispatchAction = payload.dispatchAction || bind(api.dispatchAction, api);\n    var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo;\n\n    // Pending\n    // See #6121. But we are not able to reproduce it yet.\n    if (!coordSysAxesInfo) {\n        return;\n    }\n\n    if (illegalPoint(point)) {\n        // Used in the default behavior of `connection`: use the sample seriesIndex\n        // and dataIndex. And also used in the tooltipView trigger.\n        point = findPointFromSeries({\n            seriesIndex: finder.seriesIndex,\n            // Do not use dataIndexInside from other ec instance.\n            // FIXME: auto detect it?\n            dataIndex: finder.dataIndex\n        }, ecModel).point;\n    }\n    var isIllegalPoint = illegalPoint(point);\n\n    // Axis and value can be specified when calling dispatchAction({type: 'updateAxisPointer'}).\n    // Notice: In this case, it is difficult to get the `point` (which is necessary to show\n    // tooltip, so if point is not given, we just use the point found by sample seriesIndex\n    // and dataIndex.\n    var inputAxesInfo = finder.axesInfo;\n\n    var axesInfo = coordSysAxesInfo.axesInfo;\n    var shouldHide = currTrigger === 'leave' || illegalPoint(point);\n    var outputFinder = {};\n\n    var showValueMap = {};\n    var dataByCoordSys = {list: [], map: {}};\n    var updaters = {\n        showPointer: curry$3(showPointer, showValueMap),\n        showTooltip: curry$3(showTooltip, dataByCoordSys)\n    };\n\n    // Process for triggered axes.\n    each$14(coordSysAxesInfo.coordSysMap, function (coordSys, coordSysKey) {\n        // If a point given, it must be contained by the coordinate system.\n        var coordSysContainsPoint = isIllegalPoint || coordSys.containPoint(point);\n\n        each$14(coordSysAxesInfo.coordSysAxesInfo[coordSysKey], function (axisInfo, key) {\n            var axis = axisInfo.axis;\n            var inputAxisInfo = findInputAxisInfo(inputAxesInfo, axisInfo);\n            // If no inputAxesInfo, no axis is restricted.\n            if (!shouldHide && coordSysContainsPoint && (!inputAxesInfo || inputAxisInfo)) {\n                var val = inputAxisInfo && inputAxisInfo.value;\n                if (val == null && !isIllegalPoint) {\n                    val = axis.pointToData(point);\n                }\n                val != null && processOnAxis(axisInfo, val, updaters, false, outputFinder);\n            }\n        });\n    });\n\n    // Process for linked axes.\n    var linkTriggers = {};\n    each$14(axesInfo, function (tarAxisInfo, tarKey) {\n        var linkGroup = tarAxisInfo.linkGroup;\n\n        // If axis has been triggered in the previous stage, it should not be triggered by link.\n        if (linkGroup && !showValueMap[tarKey]) {\n            each$14(linkGroup.axesInfo, function (srcAxisInfo, srcKey) {\n                var srcValItem = showValueMap[srcKey];\n                // If srcValItem exist, source axis is triggered, so link to target axis.\n                if (srcAxisInfo !== tarAxisInfo && srcValItem) {\n                    var val = srcValItem.value;\n                    linkGroup.mapper && (val = tarAxisInfo.axis.scale.parse(linkGroup.mapper(\n                        val, makeMapperParam(srcAxisInfo), makeMapperParam(tarAxisInfo)\n                    )));\n                    linkTriggers[tarAxisInfo.key] = val;\n                }\n            });\n        }\n    });\n    each$14(linkTriggers, function (val, tarKey) {\n        processOnAxis(axesInfo[tarKey], val, updaters, true, outputFinder);\n    });\n\n    updateModelActually(showValueMap, axesInfo, outputFinder);\n    dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction);\n    dispatchHighDownActually(axesInfo, dispatchAction, api);\n\n    return outputFinder;\n};\n\nfunction processOnAxis(axisInfo, newValue, updaters, dontSnap, outputFinder) {\n    var axis = axisInfo.axis;\n\n    if (axis.scale.isBlank() || !axis.containData(newValue)) {\n        return;\n    }\n\n    if (!axisInfo.involveSeries) {\n        updaters.showPointer(axisInfo, newValue);\n        return;\n    }\n\n    // Heavy calculation. So put it after axis.containData checking.\n    var payloadInfo = buildPayloadsBySeries(newValue, axisInfo);\n    var payloadBatch = payloadInfo.payloadBatch;\n    var snapToValue = payloadInfo.snapToValue;\n\n    // Fill content of event obj for echarts.connect.\n    // By defualt use the first involved series data as a sample to connect.\n    if (payloadBatch[0] && outputFinder.seriesIndex == null) {\n        extend(outputFinder, payloadBatch[0]);\n    }\n\n    // If no linkSource input, this process is for collecting link\n    // target, where snap should not be accepted.\n    if (!dontSnap && axisInfo.snap) {\n        if (axis.containData(snapToValue) && snapToValue != null) {\n            newValue = snapToValue;\n        }\n    }\n\n    updaters.showPointer(axisInfo, newValue, payloadBatch, outputFinder);\n    // Tooltip should always be snapToValue, otherwise there will be\n    // incorrect \"axis value ~ series value\" mapping displayed in tooltip.\n    updaters.showTooltip(axisInfo, payloadInfo, snapToValue);\n}\n\nfunction buildPayloadsBySeries(value, axisInfo) {\n    var axis = axisInfo.axis;\n    var dim = axis.dim;\n    var snapToValue = value;\n    var payloadBatch = [];\n    var minDist = Number.MAX_VALUE;\n    var minDiff = -1;\n\n    each$14(axisInfo.seriesModels, function (series, idx) {\n        var dataDim = series.getData().mapDimension(dim, true);\n        var seriesNestestValue;\n        var dataIndices;\n\n        if (series.getAxisTooltipData) {\n            var result = series.getAxisTooltipData(dataDim, value, axis);\n            dataIndices = result.dataIndices;\n            seriesNestestValue = result.nestestValue;\n        }\n        else {\n            dataIndices = series.getData().indicesOfNearest(\n                dataDim[0],\n                value,\n                // Add a threshold to avoid find the wrong dataIndex\n                // when data length is not same.\n                // false,\n                axis.type === 'category' ? 0.5 : null\n            );\n            if (!dataIndices.length) {\n                return;\n            }\n            seriesNestestValue = series.getData().get(dataDim[0], dataIndices[0]);\n        }\n\n        if (seriesNestestValue == null || !isFinite(seriesNestestValue)) {\n            return;\n        }\n\n        var diff = value - seriesNestestValue;\n        var dist = Math.abs(diff);\n        // Consider category case\n        if (dist <= minDist) {\n            if (dist < minDist || (diff >= 0 && minDiff < 0)) {\n                minDist = dist;\n                minDiff = diff;\n                snapToValue = seriesNestestValue;\n                payloadBatch.length = 0;\n            }\n            each$14(dataIndices, function (dataIndex) {\n                payloadBatch.push({\n                    seriesIndex: series.seriesIndex,\n                    dataIndexInside: dataIndex,\n                    dataIndex: series.getData().getRawIndex(dataIndex)\n                });\n            });\n        }\n    });\n\n    return {\n        payloadBatch: payloadBatch,\n        snapToValue: snapToValue\n    };\n}\n\nfunction showPointer(showValueMap, axisInfo, value, payloadBatch) {\n    showValueMap[axisInfo.key] = {value: value, payloadBatch: payloadBatch};\n}\n\nfunction showTooltip(dataByCoordSys, axisInfo, payloadInfo, value) {\n    var payloadBatch = payloadInfo.payloadBatch;\n    var axis = axisInfo.axis;\n    var axisModel = axis.model;\n    var axisPointerModel = axisInfo.axisPointerModel;\n\n    // If no data, do not create anything in dataByCoordSys,\n    // whose length will be used to judge whether dispatch action.\n    if (!axisInfo.triggerTooltip || !payloadBatch.length) {\n        return;\n    }\n\n    var coordSysModel = axisInfo.coordSys.model;\n    var coordSysKey = makeKey(coordSysModel);\n    var coordSysItem = dataByCoordSys.map[coordSysKey];\n    if (!coordSysItem) {\n        coordSysItem = dataByCoordSys.map[coordSysKey] = {\n            coordSysId: coordSysModel.id,\n            coordSysIndex: coordSysModel.componentIndex,\n            coordSysType: coordSysModel.type,\n            coordSysMainType: coordSysModel.mainType,\n            dataByAxis: []\n        };\n        dataByCoordSys.list.push(coordSysItem);\n    }\n\n    coordSysItem.dataByAxis.push({\n        axisDim: axis.dim,\n        axisIndex: axisModel.componentIndex,\n        axisType: axisModel.type,\n        axisId: axisModel.id,\n        value: value,\n        // Caustion: viewHelper.getValueLabel is actually on \"view stage\", which\n        // depends that all models have been updated. So it should not be performed\n        // here. Considering axisPointerModel used here is volatile, which is hard\n        // to be retrieve in TooltipView, we prepare parameters here.\n        valueLabelOpt: {\n            precision: axisPointerModel.get('label.precision'),\n            formatter: axisPointerModel.get('label.formatter')\n        },\n        seriesDataIndices: payloadBatch.slice()\n    });\n}\n\nfunction updateModelActually(showValueMap, axesInfo, outputFinder) {\n    var outputAxesInfo = outputFinder.axesInfo = [];\n    // Basic logic: If no 'show' required, 'hide' this axisPointer.\n    each$14(axesInfo, function (axisInfo, key) {\n        var option = axisInfo.axisPointerModel.option;\n        var valItem = showValueMap[key];\n\n        if (valItem) {\n            !axisInfo.useHandle && (option.status = 'show');\n            option.value = valItem.value;\n            // For label formatter param and highlight.\n            option.seriesDataIndices = (valItem.payloadBatch || []).slice();\n        }\n        // When always show (e.g., handle used), remain\n        // original value and status.\n        else {\n            // If hide, value still need to be set, consider\n            // click legend to toggle axis blank.\n            !axisInfo.useHandle && (option.status = 'hide');\n        }\n\n        // If status is 'hide', should be no info in payload.\n        option.status === 'show' && outputAxesInfo.push({\n            axisDim: axisInfo.axis.dim,\n            axisIndex: axisInfo.axis.model.componentIndex,\n            value: option.value\n        });\n    });\n}\n\nfunction dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction) {\n    // Basic logic: If no showTip required, hideTip will be dispatched.\n    if (illegalPoint(point) || !dataByCoordSys.list.length) {\n        dispatchAction({type: 'hideTip'});\n        return;\n    }\n\n    // In most case only one axis (or event one series is used). It is\n    // convinient to fetch payload.seriesIndex and payload.dataIndex\n    // dirtectly. So put the first seriesIndex and dataIndex of the first\n    // axis on the payload.\n    var sampleItem = ((dataByCoordSys.list[0].dataByAxis[0] || {}).seriesDataIndices || [])[0] || {};\n\n    dispatchAction({\n        type: 'showTip',\n        escapeConnect: true,\n        x: point[0],\n        y: point[1],\n        tooltipOption: payload.tooltipOption,\n        position: payload.position,\n        dataIndexInside: sampleItem.dataIndexInside,\n        dataIndex: sampleItem.dataIndex,\n        seriesIndex: sampleItem.seriesIndex,\n        dataByCoordSys: dataByCoordSys.list\n    });\n}\n\nfunction dispatchHighDownActually(axesInfo, dispatchAction, api) {\n    // FIXME\n    // highlight status modification shoule be a stage of main process?\n    // (Consider confilct (e.g., legend and axisPointer) and setOption)\n\n    var zr = api.getZr();\n    var highDownKey = 'axisPointerLastHighlights';\n    var lastHighlights = inner$9(zr)[highDownKey] || {};\n    var newHighlights = inner$9(zr)[highDownKey] = {};\n\n    // Update highlight/downplay status according to axisPointer model.\n    // Build hash map and remove duplicate incidentally.\n    each$14(axesInfo, function (axisInfo, key) {\n        var option = axisInfo.axisPointerModel.option;\n        option.status === 'show' && each$14(option.seriesDataIndices, function (batchItem) {\n            var key = batchItem.seriesIndex + ' | ' + batchItem.dataIndex;\n            newHighlights[key] = batchItem;\n        });\n    });\n\n    // Diff.\n    var toHighlight = [];\n    var toDownplay = [];\n    each$1(lastHighlights, function (batchItem, key) {\n        !newHighlights[key] && toDownplay.push(batchItem);\n    });\n    each$1(newHighlights, function (batchItem, key) {\n        !lastHighlights[key] && toHighlight.push(batchItem);\n    });\n\n    toDownplay.length && api.dispatchAction({\n        type: 'downplay', escapeConnect: true, batch: toDownplay\n    });\n    toHighlight.length && api.dispatchAction({\n        type: 'highlight', escapeConnect: true, batch: toHighlight\n    });\n}\n\nfunction findInputAxisInfo(inputAxesInfo, axisInfo) {\n    for (var i = 0; i < (inputAxesInfo || []).length; i++) {\n        var inputAxisInfo = inputAxesInfo[i];\n        if (axisInfo.axis.dim === inputAxisInfo.axisDim\n            && axisInfo.axis.model.componentIndex === inputAxisInfo.axisIndex\n        ) {\n            return inputAxisInfo;\n        }\n    }\n}\n\nfunction makeMapperParam(axisInfo) {\n    var axisModel = axisInfo.axis.model;\n    var item = {};\n    var dim = item.axisDim = axisInfo.axis.dim;\n    item.axisIndex = item[dim + 'AxisIndex'] = axisModel.componentIndex;\n    item.axisName = item[dim + 'AxisName'] = axisModel.name;\n    item.axisId = item[dim + 'AxisId'] = axisModel.id;\n    return item;\n}\n\nfunction illegalPoint(point) {\n    return !point || point[0] == null || isNaN(point[0]) || point[1] == null || isNaN(point[1]);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisPointerModel = extendComponentModel({\n\n    type: 'axisPointer',\n\n    coordSysAxesInfo: null,\n\n    defaultOption: {\n        // 'auto' means that show when triggered by tooltip or handle.\n        show: 'auto',\n        // 'click' | 'mousemove' | 'none'\n        triggerOn: null, // set default in AxisPonterView.js\n\n        zlevel: 0,\n        z: 50,\n\n        type: 'line', // 'line' 'shadow' 'cross' 'none'.\n        // axispointer triggered by tootip determine snap automatically,\n        // see `modelHelper`.\n        snap: false,\n        triggerTooltip: true,\n\n        value: null,\n        status: null, // Init value depends on whether handle is used.\n\n        // [group0, group1, ...]\n        // Each group can be: {\n        //      mapper: function () {},\n        //      singleTooltip: 'multiple',  // 'multiple' or 'single'\n        //      xAxisId: ...,\n        //      yAxisName: ...,\n        //      angleAxisIndex: ...\n        // }\n        // mapper: can be ignored.\n        //      input: {axisInfo, value}\n        //      output: {axisInfo, value}\n        link: [],\n\n        // Do not set 'auto' here, otherwise global animation: false\n        // will not effect at this axispointer.\n        animation: null,\n        animationDurationUpdate: 200,\n\n        lineStyle: {\n            color: '#aaa',\n            width: 1,\n            type: 'solid'\n        },\n\n        shadowStyle: {\n            color: 'rgba(150,150,150,0.3)'\n        },\n\n        label: {\n            show: true,\n            formatter: null, // string | Function\n            precision: 'auto', // Or a number like 0, 1, 2 ...\n            margin: 3,\n            color: '#fff',\n            padding: [5, 7, 5, 7],\n            backgroundColor: 'auto', // default: axis line color\n            borderColor: null,\n            borderWidth: 0,\n            shadowBlur: 3,\n            shadowColor: '#aaa'\n            // Considering applicability, common style should\n            // better not have shadowOffset.\n            // shadowOffsetX: 0,\n            // shadowOffsetY: 2\n        },\n\n        handle: {\n            show: false,\n            /* eslint-disable */\n            icon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z', // jshint ignore:line\n            /* eslint-enable */\n            size: 45,\n            // handle margin is from symbol center to axis, which is stable when circular move.\n            margin: 50,\n            // color: '#1b8bbd'\n            // color: '#2f4554'\n            color: '#333',\n            shadowBlur: 3,\n            shadowColor: '#aaa',\n            shadowOffsetX: 0,\n            shadowOffsetY: 2,\n\n            // For mobile performance\n            throttle: 40\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$10 = makeInner();\nvar each$15 = each$1;\n\n/**\n * @param {string} key\n * @param {module:echarts/ExtensionAPI} api\n * @param {Function} handler\n *      param: {string} currTrigger\n *      param: {Array.<number>} point\n */\nfunction register(key, api, handler) {\n    if (env$1.node) {\n        return;\n    }\n\n    var zr = api.getZr();\n    inner$10(zr).records || (inner$10(zr).records = {});\n\n    initGlobalListeners(zr, api);\n\n    var record = inner$10(zr).records[key] || (inner$10(zr).records[key] = {});\n    record.handler = handler;\n}\n\nfunction initGlobalListeners(zr, api) {\n    if (inner$10(zr).initialized) {\n        return;\n    }\n\n    inner$10(zr).initialized = true;\n\n    useHandler('click', curry(doEnter, 'click'));\n    useHandler('mousemove', curry(doEnter, 'mousemove'));\n    // useHandler('mouseout', onLeave);\n    useHandler('globalout', onLeave);\n\n    function useHandler(eventType, cb) {\n        zr.on(eventType, function (e) {\n            var dis = makeDispatchAction(api);\n\n            each$15(inner$10(zr).records, function (record) {\n                record && cb(record, e, dis.dispatchAction);\n            });\n\n            dispatchTooltipFinally(dis.pendings, api);\n        });\n    }\n}\n\nfunction dispatchTooltipFinally(pendings, api) {\n    var showLen = pendings.showTip.length;\n    var hideLen = pendings.hideTip.length;\n\n    var actuallyPayload;\n    if (showLen) {\n        actuallyPayload = pendings.showTip[showLen - 1];\n    }\n    else if (hideLen) {\n        actuallyPayload = pendings.hideTip[hideLen - 1];\n    }\n    if (actuallyPayload) {\n        actuallyPayload.dispatchAction = null;\n        api.dispatchAction(actuallyPayload);\n    }\n}\n\nfunction onLeave(record, e, dispatchAction) {\n    record.handler('leave', null, dispatchAction);\n}\n\nfunction doEnter(currTrigger, record, e, dispatchAction) {\n    record.handler(currTrigger, e, dispatchAction);\n}\n\nfunction makeDispatchAction(api) {\n    var pendings = {\n        showTip: [],\n        hideTip: []\n    };\n    // FIXME\n    // better approach?\n    // 'showTip' and 'hideTip' can be triggered by axisPointer and tooltip,\n    // which may be conflict, (axisPointer call showTip but tooltip call hideTip);\n    // So we have to add \"final stage\" to merge those dispatched actions.\n    var dispatchAction = function (payload) {\n        var pendingList = pendings[payload.type];\n        if (pendingList) {\n            pendingList.push(payload);\n        }\n        else {\n            payload.dispatchAction = dispatchAction;\n            api.dispatchAction(payload);\n        }\n    };\n\n    return {\n        dispatchAction: dispatchAction,\n        pendings: pendings\n    };\n}\n\n/**\n * @param {string} key\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction unregister(key, api) {\n    if (env$1.node) {\n        return;\n    }\n    var zr = api.getZr();\n    var record = (inner$10(zr).records || {})[key];\n    if (record) {\n        inner$10(zr).records[key] = null;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisPointerView = extendComponentView({\n\n    type: 'axisPointer',\n\n    render: function (globalAxisPointerModel, ecModel, api) {\n        var globalTooltipModel = ecModel.getComponent('tooltip');\n        var triggerOn = globalAxisPointerModel.get('triggerOn')\n            || (globalTooltipModel && globalTooltipModel.get('triggerOn') || 'mousemove|click');\n\n        // Register global listener in AxisPointerView to enable\n        // AxisPointerView to be independent to Tooltip.\n        register(\n            'axisPointer',\n            api,\n            function (currTrigger, e, dispatchAction) {\n                // If 'none', it is not controlled by mouse totally.\n                if (triggerOn !== 'none'\n                    && (currTrigger === 'leave' || triggerOn.indexOf(currTrigger) >= 0)\n                ) {\n                    dispatchAction({\n                        type: 'updateAxisPointer',\n                        currTrigger: currTrigger,\n                        x: e && e.offsetX,\n                        y: e && e.offsetY\n                    });\n                }\n            }\n        );\n    },\n\n    /**\n     * @override\n     */\n    remove: function (ecModel, api) {\n        unregister(api.getZr(), 'axisPointer');\n        AxisPointerView.superApply(this._model, 'remove', arguments);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function (ecModel, api) {\n        unregister('axisPointer', api);\n        AxisPointerView.superApply(this._model, 'dispose', arguments);\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$11 = makeInner();\nvar clone$4 = clone;\nvar bind$2 = bind;\n\n/**\n * Base axis pointer class in 2D.\n * Implemenents {module:echarts/component/axis/IAxisPointer}.\n */\nfunction BaseAxisPointer() {\n}\n\nBaseAxisPointer.prototype = {\n\n    /**\n     * @private\n     */\n    _group: null,\n\n    /**\n     * @private\n     */\n    _lastGraphicKey: null,\n\n    /**\n     * @private\n     */\n    _handle: null,\n\n    /**\n     * @private\n     */\n    _dragging: false,\n\n    /**\n     * @private\n     */\n    _lastValue: null,\n\n    /**\n     * @private\n     */\n    _lastStatus: null,\n\n    /**\n     * @private\n     */\n    _payloadInfo: null,\n\n    /**\n     * In px, arbitrary value. Do not set too small,\n     * no animation is ok for most cases.\n     * @protected\n     */\n    animationThreshold: 15,\n\n    /**\n     * @implement\n     */\n    render: function (axisModel, axisPointerModel, api, forceRender) {\n        var value = axisPointerModel.get('value');\n        var status = axisPointerModel.get('status');\n\n        // Bind them to `this`, not in closure, otherwise they will not\n        // be replaced when user calling setOption in not merge mode.\n        this._axisModel = axisModel;\n        this._axisPointerModel = axisPointerModel;\n        this._api = api;\n\n        // Optimize: `render` will be called repeatly during mouse move.\n        // So it is power consuming if performing `render` each time,\n        // especially on mobile device.\n        if (!forceRender\n            && this._lastValue === value\n            && this._lastStatus === status\n        ) {\n            return;\n        }\n        this._lastValue = value;\n        this._lastStatus = status;\n\n        var group = this._group;\n        var handle = this._handle;\n\n        if (!status || status === 'hide') {\n            // Do not clear here, for animation better.\n            group && group.hide();\n            handle && handle.hide();\n            return;\n        }\n        group && group.show();\n        handle && handle.show();\n\n        // Otherwise status is 'show'\n        var elOption = {};\n        this.makeElOption(elOption, value, axisModel, axisPointerModel, api);\n\n        // Enable change axis pointer type.\n        var graphicKey = elOption.graphicKey;\n        if (graphicKey !== this._lastGraphicKey) {\n            this.clear(api);\n        }\n        this._lastGraphicKey = graphicKey;\n\n        var moveAnimation = this._moveAnimation\n            = this.determineAnimation(axisModel, axisPointerModel);\n\n        if (!group) {\n            group = this._group = new Group();\n            this.createPointerEl(group, elOption, axisModel, axisPointerModel);\n            this.createLabelEl(group, elOption, axisModel, axisPointerModel);\n            api.getZr().add(group);\n        }\n        else {\n            var doUpdateProps = curry(updateProps$1, axisPointerModel, moveAnimation);\n            this.updatePointerEl(group, elOption, doUpdateProps, axisPointerModel);\n            this.updateLabelEl(group, elOption, doUpdateProps, axisPointerModel);\n        }\n\n        updateMandatoryProps(group, axisPointerModel, true);\n\n        this._renderHandle(value);\n    },\n\n    /**\n     * @implement\n     */\n    remove: function (api) {\n        this.clear(api);\n    },\n\n    /**\n     * @implement\n     */\n    dispose: function (api) {\n        this.clear(api);\n    },\n\n    /**\n     * @protected\n     */\n    determineAnimation: function (axisModel, axisPointerModel) {\n        var animation = axisPointerModel.get('animation');\n        var axis = axisModel.axis;\n        var isCategoryAxis = axis.type === 'category';\n        var useSnap = axisPointerModel.get('snap');\n\n        // Value axis without snap always do not snap.\n        if (!useSnap && !isCategoryAxis) {\n            return false;\n        }\n\n        if (animation === 'auto' || animation == null) {\n            var animationThreshold = this.animationThreshold;\n            if (isCategoryAxis && axis.getBandWidth() > animationThreshold) {\n                return true;\n            }\n\n            // It is important to auto animation when snap used. Consider if there is\n            // a dataZoom, animation will be disabled when too many points exist, while\n            // it will be enabled for better visual effect when little points exist.\n            if (useSnap) {\n                var seriesDataCount = getAxisInfo(axisModel).seriesDataCount;\n                var axisExtent = axis.getExtent();\n                // Approximate band width\n                return Math.abs(axisExtent[0] - axisExtent[1]) / seriesDataCount > animationThreshold;\n            }\n\n            return false;\n        }\n\n        return animation === true;\n    },\n\n    /**\n     * add {pointer, label, graphicKey} to elOption\n     * @protected\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        // Shoule be implemenented by sub-class.\n    },\n\n    /**\n     * @protected\n     */\n    createPointerEl: function (group, elOption, axisModel, axisPointerModel) {\n        var pointerOption = elOption.pointer;\n        if (pointerOption) {\n            var pointerEl = inner$11(group).pointerEl = new graphic[pointerOption.type](\n                clone$4(elOption.pointer)\n            );\n            group.add(pointerEl);\n        }\n    },\n\n    /**\n     * @protected\n     */\n    createLabelEl: function (group, elOption, axisModel, axisPointerModel) {\n        if (elOption.label) {\n            var labelEl = inner$11(group).labelEl = new Rect(\n                clone$4(elOption.label)\n            );\n\n            group.add(labelEl);\n            updateLabelShowHide(labelEl, axisPointerModel);\n        }\n    },\n\n    /**\n     * @protected\n     */\n    updatePointerEl: function (group, elOption, updateProps$$1) {\n        var pointerEl = inner$11(group).pointerEl;\n        if (pointerEl) {\n            pointerEl.setStyle(elOption.pointer.style);\n            updateProps$$1(pointerEl, {shape: elOption.pointer.shape});\n        }\n    },\n\n    /**\n     * @protected\n     */\n    updateLabelEl: function (group, elOption, updateProps$$1, axisPointerModel) {\n        var labelEl = inner$11(group).labelEl;\n        if (labelEl) {\n            labelEl.setStyle(elOption.label.style);\n            updateProps$$1(labelEl, {\n                // Consider text length change in vertical axis, animation should\n                // be used on shape, otherwise the effect will be weird.\n                shape: elOption.label.shape,\n                position: elOption.label.position\n            });\n\n            updateLabelShowHide(labelEl, axisPointerModel);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _renderHandle: function (value) {\n        if (this._dragging || !this.updateHandleTransform) {\n            return;\n        }\n\n        var axisPointerModel = this._axisPointerModel;\n        var zr = this._api.getZr();\n        var handle = this._handle;\n        var handleModel = axisPointerModel.getModel('handle');\n\n        var status = axisPointerModel.get('status');\n        if (!handleModel.get('show') || !status || status === 'hide') {\n            handle && zr.remove(handle);\n            this._handle = null;\n            return;\n        }\n\n        var isInit;\n        if (!this._handle) {\n            isInit = true;\n            handle = this._handle = createIcon(\n                handleModel.get('icon'),\n                {\n                    cursor: 'move',\n                    draggable: true,\n                    onmousemove: function (e) {\n                        // Fot mobile devicem, prevent screen slider on the button.\n                        stop(e.event);\n                    },\n                    onmousedown: bind$2(this._onHandleDragMove, this, 0, 0),\n                    drift: bind$2(this._onHandleDragMove, this),\n                    ondragend: bind$2(this._onHandleDragEnd, this)\n                }\n            );\n            zr.add(handle);\n        }\n\n        updateMandatoryProps(handle, axisPointerModel, false);\n\n        // update style\n        var includeStyles = [\n            'color', 'borderColor', 'borderWidth', 'opacity',\n            'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'\n        ];\n        handle.setStyle(handleModel.getItemStyle(null, includeStyles));\n\n        // update position\n        var handleSize = handleModel.get('size');\n        if (!isArray(handleSize)) {\n            handleSize = [handleSize, handleSize];\n        }\n        handle.attr('scale', [handleSize[0] / 2, handleSize[1] / 2]);\n\n        createOrUpdate(\n            this,\n            '_doDispatchAxisPointer',\n            handleModel.get('throttle') || 0,\n            'fixRate'\n        );\n\n        this._moveHandleToValue(value, isInit);\n    },\n\n    /**\n     * @private\n     */\n    _moveHandleToValue: function (value, isInit) {\n        updateProps$1(\n            this._axisPointerModel,\n            !isInit && this._moveAnimation,\n            this._handle,\n            getHandleTransProps(this.getHandleTransform(\n                value, this._axisModel, this._axisPointerModel\n            ))\n        );\n    },\n\n    /**\n     * @private\n     */\n    _onHandleDragMove: function (dx, dy) {\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        this._dragging = true;\n\n        // Persistent for throttle.\n        var trans = this.updateHandleTransform(\n            getHandleTransProps(handle),\n            [dx, dy],\n            this._axisModel,\n            this._axisPointerModel\n        );\n        this._payloadInfo = trans;\n\n        handle.stopAnimation();\n        handle.attr(getHandleTransProps(trans));\n        inner$11(handle).lastProp = null;\n\n        this._doDispatchAxisPointer();\n    },\n\n    /**\n     * Throttled method.\n     * @private\n     */\n    _doDispatchAxisPointer: function () {\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        var payloadInfo = this._payloadInfo;\n        var axisModel = this._axisModel;\n        this._api.dispatchAction({\n            type: 'updateAxisPointer',\n            x: payloadInfo.cursorPoint[0],\n            y: payloadInfo.cursorPoint[1],\n            tooltipOption: payloadInfo.tooltipOption,\n            axesInfo: [{\n                axisDim: axisModel.axis.dim,\n                axisIndex: axisModel.componentIndex\n            }]\n        });\n    },\n\n    /**\n     * @private\n     */\n    _onHandleDragEnd: function (moveAnimation) {\n        this._dragging = false;\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        var value = this._axisPointerModel.get('value');\n        // Consider snap or categroy axis, handle may be not consistent with\n        // axisPointer. So move handle to align the exact value position when\n        // drag ended.\n        this._moveHandleToValue(value);\n\n        // For the effect: tooltip will be shown when finger holding on handle\n        // button, and will be hidden after finger left handle button.\n        this._api.dispatchAction({\n            type: 'hideTip'\n        });\n    },\n\n    /**\n     * Should be implemenented by sub-class if support `handle`.\n     * @protected\n     * @param {number} value\n     * @param {module:echarts/model/Model} axisModel\n     * @param {module:echarts/model/Model} axisPointerModel\n     * @return {Object} {position: [x, y], rotation: 0}\n     */\n    getHandleTransform: null,\n\n    /**\n     * * Should be implemenented by sub-class if support `handle`.\n     * @protected\n     * @param {Object} transform {position, rotation}\n     * @param {Array.<number>} delta [dx, dy]\n     * @param {module:echarts/model/Model} axisModel\n     * @param {module:echarts/model/Model} axisPointerModel\n     * @return {Object} {position: [x, y], rotation: 0, cursorPoint: [x, y]}\n     */\n    updateHandleTransform: null,\n\n    /**\n     * @private\n     */\n    clear: function (api) {\n        this._lastValue = null;\n        this._lastStatus = null;\n\n        var zr = api.getZr();\n        var group = this._group;\n        var handle = this._handle;\n        if (zr && group) {\n            this._lastGraphicKey = null;\n            group && zr.remove(group);\n            handle && zr.remove(handle);\n            this._group = null;\n            this._handle = null;\n            this._payloadInfo = null;\n        }\n    },\n\n    /**\n     * @protected\n     */\n    doClear: function () {\n        // Implemented by sub-class if necessary.\n    },\n\n    /**\n     * @protected\n     * @param {Array.<number>} xy\n     * @param {Array.<number>} wh\n     * @param {number} [xDimIndex=0] or 1\n     */\n    buildLabel: function (xy, wh, xDimIndex) {\n        xDimIndex = xDimIndex || 0;\n        return {\n            x: xy[xDimIndex],\n            y: xy[1 - xDimIndex],\n            width: wh[xDimIndex],\n            height: wh[1 - xDimIndex]\n        };\n    }\n};\n\nBaseAxisPointer.prototype.constructor = BaseAxisPointer;\n\n\nfunction updateProps$1(animationModel, moveAnimation, el, props) {\n    // Animation optimize.\n    if (!propsEqual(inner$11(el).lastProp, props)) {\n        inner$11(el).lastProp = props;\n        moveAnimation\n            ? updateProps(el, props, animationModel)\n            : (el.stopAnimation(), el.attr(props));\n    }\n}\n\nfunction propsEqual(lastProps, newProps) {\n    if (isObject$1(lastProps) && isObject$1(newProps)) {\n        var equals = true;\n        each$1(newProps, function (item, key) {\n            equals = equals && propsEqual(lastProps[key], item);\n        });\n        return !!equals;\n    }\n    else {\n        return lastProps === newProps;\n    }\n}\n\nfunction updateLabelShowHide(labelEl, axisPointerModel) {\n    labelEl[axisPointerModel.get('label.show') ? 'show' : 'hide']();\n}\n\nfunction getHandleTransProps(trans) {\n    return {\n        position: trans.position.slice(),\n        rotation: trans.rotation || 0\n    };\n}\n\nfunction updateMandatoryProps(group, axisPointerModel, silent) {\n    var z = axisPointerModel.get('z');\n    var zlevel = axisPointerModel.get('zlevel');\n\n    group && group.traverse(function (el) {\n        if (el.type !== 'group') {\n            z != null && (el.z = z);\n            zlevel != null && (el.zlevel = zlevel);\n            el.silent = silent;\n        }\n    });\n}\n\nenableClassExtend(BaseAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/model/Model} axisPointerModel\n */\nfunction buildElStyle(axisPointerModel) {\n    var axisPointerType = axisPointerModel.get('type');\n    var styleModel = axisPointerModel.getModel(axisPointerType + 'Style');\n    var style;\n    if (axisPointerType === 'line') {\n        style = styleModel.getLineStyle();\n        style.fill = null;\n    }\n    else if (axisPointerType === 'shadow') {\n        style = styleModel.getAreaStyle();\n        style.stroke = null;\n    }\n    return style;\n}\n\n/**\n * @param {Function} labelPos {align, verticalAlign, position}\n */\nfunction buildLabelElOption(\n    elOption, axisModel, axisPointerModel, api, labelPos\n) {\n    var value = axisPointerModel.get('value');\n    var text = getValueLabel(\n        value, axisModel.axis, axisModel.ecModel,\n        axisPointerModel.get('seriesDataIndices'),\n        {\n            precision: axisPointerModel.get('label.precision'),\n            formatter: axisPointerModel.get('label.formatter')\n        }\n    );\n    var labelModel = axisPointerModel.getModel('label');\n    var paddings = normalizeCssArray$1(labelModel.get('padding') || 0);\n\n    var font = labelModel.getFont();\n    var textRect = getBoundingRect(text, font);\n\n    var position = labelPos.position;\n    var width = textRect.width + paddings[1] + paddings[3];\n    var height = textRect.height + paddings[0] + paddings[2];\n\n    // Adjust by align.\n    var align = labelPos.align;\n    align === 'right' && (position[0] -= width);\n    align === 'center' && (position[0] -= width / 2);\n    var verticalAlign = labelPos.verticalAlign;\n    verticalAlign === 'bottom' && (position[1] -= height);\n    verticalAlign === 'middle' && (position[1] -= height / 2);\n\n    // Not overflow ec container\n    confineInContainer(position, width, height, api);\n\n    var bgColor = labelModel.get('backgroundColor');\n    if (!bgColor || bgColor === 'auto') {\n        bgColor = axisModel.get('axisLine.lineStyle.color');\n    }\n\n    elOption.label = {\n        shape: {x: 0, y: 0, width: width, height: height, r: labelModel.get('borderRadius')},\n        position: position.slice(),\n        // TODO: rich\n        style: {\n            text: text,\n            textFont: font,\n            textFill: labelModel.getTextColor(),\n            textPosition: 'inside',\n            fill: bgColor,\n            stroke: labelModel.get('borderColor') || 'transparent',\n            lineWidth: labelModel.get('borderWidth') || 0,\n            shadowBlur: labelModel.get('shadowBlur'),\n            shadowColor: labelModel.get('shadowColor'),\n            shadowOffsetX: labelModel.get('shadowOffsetX'),\n            shadowOffsetY: labelModel.get('shadowOffsetY')\n        },\n        // Lable should be over axisPointer.\n        z2: 10\n    };\n}\n\n// Do not overflow ec container\nfunction confineInContainer(position, width, height, api) {\n    var viewWidth = api.getWidth();\n    var viewHeight = api.getHeight();\n    position[0] = Math.min(position[0] + width, viewWidth) - width;\n    position[1] = Math.min(position[1] + height, viewHeight) - height;\n    position[0] = Math.max(position[0], 0);\n    position[1] = Math.max(position[1], 0);\n}\n\n/**\n * @param {number} value\n * @param {module:echarts/coord/Axis} axis\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} opt\n * @param {Array.<Object>} seriesDataIndices\n * @param {number|string} opt.precision 'auto' or a number\n * @param {string|Function} opt.formatter label formatter\n */\nfunction getValueLabel(value, axis, ecModel, seriesDataIndices, opt) {\n    value = axis.scale.parse(value);\n    var text = axis.scale.getLabel(\n        // If `precision` is set, width can be fixed (like '12.00500'), which\n        // helps to debounce when when moving label.\n        value, {precision: opt.precision}\n    );\n    var formatter = opt.formatter;\n\n    if (formatter) {\n        var params = {\n            value: getAxisRawValue(axis, value),\n            seriesData: []\n        };\n        each$1(seriesDataIndices, function (idxItem) {\n            var series = ecModel.getSeriesByIndex(idxItem.seriesIndex);\n            var dataIndex = idxItem.dataIndexInside;\n            var dataParams = series && series.getDataParams(dataIndex);\n            dataParams && params.seriesData.push(dataParams);\n        });\n\n        if (isString(formatter)) {\n            text = formatter.replace('{value}', text);\n        }\n        else if (isFunction$1(formatter)) {\n            text = formatter(params);\n        }\n    }\n\n    return text;\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @param {number} value\n * @param {Object} layoutInfo {\n *  rotation, position, labelOffset, labelDirection, labelMargin\n * }\n */\nfunction getTransformedPosition(axis, value, layoutInfo) {\n    var transform = create$1();\n    rotate(transform, transform, layoutInfo.rotation);\n    translate(transform, transform, layoutInfo.position);\n\n    return applyTransform$1([\n        axis.dataToCoord(value),\n        (layoutInfo.labelOffset || 0)\n            + (layoutInfo.labelDirection || 1) * (layoutInfo.labelMargin || 0)\n    ], transform);\n}\n\nfunction buildCartesianSingleLabelElOption(\n    value, elOption, layoutInfo, axisModel, axisPointerModel, api\n) {\n    var textLayout = AxisBuilder.innerTextLayout(\n        layoutInfo.rotation, 0, layoutInfo.labelDirection\n    );\n    layoutInfo.labelMargin = axisPointerModel.get('label.margin');\n    buildLabelElOption(elOption, axisModel, axisPointerModel, api, {\n        position: getTransformedPosition(axisModel.axis, value, layoutInfo),\n        align: textLayout.textAlign,\n        verticalAlign: textLayout.textVerticalAlign\n    });\n}\n\n/**\n * @param {Array.<number>} p1\n * @param {Array.<number>} p2\n * @param {number} [xDimIndex=0] or 1\n */\nfunction makeLineShape(p1, p2, xDimIndex) {\n    xDimIndex = xDimIndex || 0;\n    return {\n        x1: p1[xDimIndex],\n        y1: p1[1 - xDimIndex],\n        x2: p2[xDimIndex],\n        y2: p2[1 - xDimIndex]\n    };\n}\n\n/**\n * @param {Array.<number>} xy\n * @param {Array.<number>} wh\n * @param {number} [xDimIndex=0] or 1\n */\nfunction makeRectShape(xy, wh, xDimIndex) {\n    xDimIndex = xDimIndex || 0;\n    return {\n        x: xy[xDimIndex],\n        y: xy[1 - xDimIndex],\n        width: wh[xDimIndex],\n        height: wh[1 - xDimIndex]\n    };\n}\n\nfunction makeSectorShape(cx, cy, r0, r, startAngle, endAngle) {\n    return {\n        cx: cx,\n        cy: cy,\n        r0: r0,\n        r: r,\n        startAngle: startAngle,\n        endAngle: endAngle,\n        clockwise: true\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar CartesianAxisPointer = BaseAxisPointer.extend({\n\n    /**\n     * @override\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        var axis = axisModel.axis;\n        var grid = axis.grid;\n        var axisPointerType = axisPointerModel.get('type');\n        var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent();\n        var pixelValue = axis.toGlobalCoord(axis.dataToCoord(value, true));\n\n        if (axisPointerType && axisPointerType !== 'none') {\n            var elStyle = buildElStyle(axisPointerModel);\n            var pointerOption = pointerShapeBuilder[axisPointerType](\n                axis, pixelValue, otherExtent, elStyle\n            );\n            pointerOption.style = elStyle;\n            elOption.graphicKey = pointerOption.type;\n            elOption.pointer = pointerOption;\n        }\n\n        var layoutInfo = layout$1(grid.model, axisModel);\n        buildCartesianSingleLabelElOption(\n            value, elOption, layoutInfo, axisModel, axisPointerModel, api\n        );\n    },\n\n    /**\n     * @override\n     */\n    getHandleTransform: function (value, axisModel, axisPointerModel) {\n        var layoutInfo = layout$1(axisModel.axis.grid.model, axisModel, {\n            labelInside: false\n        });\n        layoutInfo.labelMargin = axisPointerModel.get('handle.margin');\n        return {\n            position: getTransformedPosition(axisModel.axis, value, layoutInfo),\n            rotation: layoutInfo.rotation + (layoutInfo.labelDirection < 0 ? Math.PI : 0)\n        };\n    },\n\n    /**\n     * @override\n     */\n    updateHandleTransform: function (transform, delta, axisModel, axisPointerModel) {\n        var axis = axisModel.axis;\n        var grid = axis.grid;\n        var axisExtent = axis.getGlobalExtent(true);\n        var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent();\n        var dimIndex = axis.dim === 'x' ? 0 : 1;\n\n        var currPosition = transform.position;\n        currPosition[dimIndex] += delta[dimIndex];\n        currPosition[dimIndex] = Math.min(axisExtent[1], currPosition[dimIndex]);\n        currPosition[dimIndex] = Math.max(axisExtent[0], currPosition[dimIndex]);\n\n        var cursorOtherValue = (otherExtent[1] + otherExtent[0]) / 2;\n        var cursorPoint = [cursorOtherValue, cursorOtherValue];\n        cursorPoint[dimIndex] = currPosition[dimIndex];\n\n        // Make tooltip do not overlap axisPointer and in the middle of the grid.\n        var tooltipOptions = [{verticalAlign: 'middle'}, {align: 'center'}];\n\n        return {\n            position: currPosition,\n            rotation: transform.rotation,\n            cursorPoint: cursorPoint,\n            tooltipOption: tooltipOptions[dimIndex]\n        };\n    }\n\n});\n\nfunction getCartesian(grid, axis) {\n    var opt = {};\n    opt[axis.dim + 'AxisIndex'] = axis.index;\n    return grid.getCartesian(opt);\n}\n\nvar pointerShapeBuilder = {\n\n    line: function (axis, pixelValue, otherExtent, elStyle) {\n        var targetShape = makeLineShape(\n            [pixelValue, otherExtent[0]],\n            [pixelValue, otherExtent[1]],\n            getAxisDimIndex(axis)\n        );\n        subPixelOptimizeLine({\n            shape: targetShape,\n            style: elStyle\n        });\n        return {\n            type: 'Line',\n            shape: targetShape\n        };\n    },\n\n    shadow: function (axis, pixelValue, otherExtent, elStyle) {\n        var bandWidth = Math.max(1, axis.getBandWidth());\n        var span = otherExtent[1] - otherExtent[0];\n        return {\n            type: 'Rect',\n            shape: makeRectShape(\n                [pixelValue - bandWidth / 2, otherExtent[0]],\n                [bandWidth, span],\n                getAxisDimIndex(axis)\n            )\n        };\n    }\n};\n\nfunction getAxisDimIndex(axis) {\n    return axis.dim === 'x' ? 0 : 1;\n}\n\nAxisView.registerAxisPointerClass('CartesianAxisPointer', CartesianAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// CartesianAxisPointer is not supposed to be required here. But consider\n// echarts.simple.js and online build tooltip, which only require gridSimple,\n// CartesianAxisPointer should be able to required somewhere.\nregisterPreprocessor(function (option) {\n    // Always has a global axisPointerModel for default setting.\n    if (option) {\n        (!option.axisPointer || option.axisPointer.length === 0)\n            && (option.axisPointer = {});\n\n        var link = option.axisPointer.link;\n        // Normalize to array to avoid object mergin. But if link\n        // is not set, remain null/undefined, otherwise it will\n        // override existent link setting.\n        if (link && !isArray(link)) {\n            option.axisPointer.link = [link];\n        }\n    }\n});\n\n// This process should proformed after coordinate systems created\n// and series data processed. So put it on statistic processing stage.\nregisterProcessor(PRIORITY.PROCESSOR.STATISTIC, function (ecModel, api) {\n    // Build axisPointerModel, mergin tooltip.axisPointer model for each axis.\n    // allAxesInfo should be updated when setOption performed.\n    ecModel.getComponent('axisPointer').coordSysAxesInfo\n        = collect(ecModel, api);\n});\n\n// Broadcast to all views.\nregisterAction({\n    type: 'updateAxisPointer',\n    event: 'updateAxisPointer',\n    update: ':updateAxisPointer'\n}, axisTrigger);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar XY = ['x', 'y'];\nvar WH = ['width', 'height'];\n\nvar SingleAxisPointer = BaseAxisPointer.extend({\n\n    /**\n     * @override\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        var axis = axisModel.axis;\n        var coordSys = axis.coordinateSystem;\n        var otherExtent = getGlobalExtent(coordSys, 1 - getPointDimIndex(axis));\n        var pixelValue = coordSys.dataToPoint(value)[0];\n\n        var axisPointerType = axisPointerModel.get('type');\n        if (axisPointerType && axisPointerType !== 'none') {\n            var elStyle = buildElStyle(axisPointerModel);\n            var pointerOption = pointerShapeBuilder$1[axisPointerType](\n                axis, pixelValue, otherExtent, elStyle\n            );\n            pointerOption.style = elStyle;\n\n            elOption.graphicKey = pointerOption.type;\n            elOption.pointer = pointerOption;\n        }\n\n        var layoutInfo = layout$2(axisModel);\n        buildCartesianSingleLabelElOption(\n            value, elOption, layoutInfo, axisModel, axisPointerModel, api\n        );\n    },\n\n    /**\n     * @override\n     */\n    getHandleTransform: function (value, axisModel, axisPointerModel) {\n        var layoutInfo = layout$2(axisModel, {labelInside: false});\n        layoutInfo.labelMargin = axisPointerModel.get('handle.margin');\n        return {\n            position: getTransformedPosition(axisModel.axis, value, layoutInfo),\n            rotation: layoutInfo.rotation + (layoutInfo.labelDirection < 0 ? Math.PI : 0)\n        };\n    },\n\n    /**\n     * @override\n     */\n    updateHandleTransform: function (transform, delta, axisModel, axisPointerModel) {\n        var axis = axisModel.axis;\n        var coordSys = axis.coordinateSystem;\n        var dimIndex = getPointDimIndex(axis);\n        var axisExtent = getGlobalExtent(coordSys, dimIndex);\n        var currPosition = transform.position;\n        currPosition[dimIndex] += delta[dimIndex];\n        currPosition[dimIndex] = Math.min(axisExtent[1], currPosition[dimIndex]);\n        currPosition[dimIndex] = Math.max(axisExtent[0], currPosition[dimIndex]);\n        var otherExtent = getGlobalExtent(coordSys, 1 - dimIndex);\n        var cursorOtherValue = (otherExtent[1] + otherExtent[0]) / 2;\n        var cursorPoint = [cursorOtherValue, cursorOtherValue];\n        cursorPoint[dimIndex] = currPosition[dimIndex];\n\n        return {\n            position: currPosition,\n            rotation: transform.rotation,\n            cursorPoint: cursorPoint,\n            tooltipOption: {\n                verticalAlign: 'middle'\n            }\n        };\n    }\n});\n\nvar pointerShapeBuilder$1 = {\n\n    line: function (axis, pixelValue, otherExtent, elStyle) {\n        var targetShape = makeLineShape(\n            [pixelValue, otherExtent[0]],\n            [pixelValue, otherExtent[1]],\n            getPointDimIndex(axis)\n        );\n        subPixelOptimizeLine({\n            shape: targetShape,\n            style: elStyle\n        });\n        return {\n            type: 'Line',\n            shape: targetShape\n        };\n    },\n\n    shadow: function (axis, pixelValue, otherExtent, elStyle) {\n        var bandWidth = axis.getBandWidth();\n        var span = otherExtent[1] - otherExtent[0];\n        return {\n            type: 'Rect',\n            shape: makeRectShape(\n                [pixelValue - bandWidth / 2, otherExtent[0]],\n                [bandWidth, span],\n                getPointDimIndex(axis)\n            )\n        };\n    }\n};\n\nfunction getPointDimIndex(axis) {\n    return axis.isHorizontal() ? 0 : 1;\n}\n\nfunction getGlobalExtent(coordSys, dimIndex) {\n    var rect = coordSys.getRect();\n    return [rect[XY[dimIndex]], rect[XY[dimIndex]] + rect[WH[dimIndex]]];\n}\n\nAxisView.registerAxisPointerClass('SingleAxisPointer', SingleAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentView({\n    type: 'single'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file  Define the themeRiver view's series model\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar DATA_NAME_INDEX = 2;\n\nvar ThemeRiverSeries = SeriesModel.extend({\n\n    type: 'series.themeRiver',\n\n    dependencies: ['singleAxis'],\n\n    /**\n     * @readOnly\n     * @type {module:zrender/core/util#HashMap}\n     */\n    nameMap: null,\n\n    /**\n     * @override\n     */\n    init: function (option) {\n        // eslint-disable-next-line\n        ThemeRiverSeries.superApply(this, 'init', arguments);\n\n        // Put this function here is for the sake of consistency of code style.\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n    },\n\n    /**\n     * If there is no value of a certain point in the time for some event,set it value to 0.\n     *\n     * @param {Array} data  initial data in the option\n     * @return {Array}\n     */\n    fixData: function (data) {\n        var rawDataLength = data.length;\n\n        // grouped data by name\n        var groupResult = groupData(data, function (item) {\n            return item[2];\n        });\n        var layData = [];\n        groupResult.buckets.each(function (items, key) {\n            layData.push({name: key, dataList: items});\n        });\n\n        var layerNum = layData.length;\n        var largestLayer = -1;\n        var index = -1;\n        for (var i = 0; i < layerNum; ++i) {\n            var len = layData[i].dataList.length;\n            if (len > largestLayer) {\n                largestLayer = len;\n                index = i;\n            }\n        }\n\n        for (var k = 0; k < layerNum; ++k) {\n            if (k === index) {\n                continue;\n            }\n            var name = layData[k].name;\n            for (var j = 0; j < largestLayer; ++j) {\n                var timeValue = layData[index].dataList[j][0];\n                var length = layData[k].dataList.length;\n                var keyIndex = -1;\n                for (var l = 0; l < length; ++l) {\n                    var value = layData[k].dataList[l][0];\n                    if (value === timeValue) {\n                        keyIndex = l;\n                        break;\n                    }\n                }\n                if (keyIndex === -1) {\n                    data[rawDataLength] = [];\n                    data[rawDataLength][0] = timeValue;\n                    data[rawDataLength][1] = 0;\n                    data[rawDataLength][2] = name;\n                    rawDataLength++;\n\n                }\n            }\n        }\n        return data;\n    },\n\n    /**\n     * @override\n     * @param  {Object} option  the initial option that user gived\n     * @param  {module:echarts/model/Model} ecModel  the model object for themeRiver option\n     * @return {module:echarts/data/List}\n     */\n    getInitialData: function (option, ecModel) {\n\n        var singleAxisModel = ecModel.queryComponents({\n            mainType: 'singleAxis',\n            index: this.get('singleAxisIndex'),\n            id: this.get('singleAxisId')\n        })[0];\n\n        var axisType = singleAxisModel.get('type');\n\n        // filter the data item with the value of label is undefined\n        var filterData = filter(option.data, function (dataItem) {\n            return dataItem[2] !== undefined;\n        });\n\n        // ??? TODO design a stage to transfer data for themeRiver and lines?\n        var data = this.fixData(filterData || []);\n        var nameList = [];\n        var nameMap = this.nameMap = createHashMap();\n        var count = 0;\n\n        for (var i = 0; i < data.length; ++i) {\n            nameList.push(data[i][DATA_NAME_INDEX]);\n            if (!nameMap.get(data[i][DATA_NAME_INDEX])) {\n                nameMap.set(data[i][DATA_NAME_INDEX], count);\n                count++;\n            }\n        }\n\n        var dimensionsInfo = createDimensions(data, {\n            coordDimensions: ['single'],\n            dimensionsDefine: [\n                {\n                    name: 'time',\n                    type: getDimensionTypeByAxis(axisType)\n                },\n                {\n                    name: 'value',\n                    type: 'float'\n                },\n                {\n                    name: 'name',\n                    type: 'ordinal'\n                }\n            ],\n            encodeDefine: {\n                single: 0,\n                value: 1,\n                itemName: 2\n            }\n        });\n\n        var list = new List(dimensionsInfo, this);\n        list.initData(data);\n\n        return list;\n    },\n\n    /**\n     * The raw data is divided into multiple layers and each layer\n     *     has same name.\n     *\n     * @return {Array.<Array.<number>>}\n     */\n    getLayerSeries: function () {\n        var data = this.getData();\n        var lenCount = data.count();\n        var indexArr = [];\n\n        for (var i = 0; i < lenCount; ++i) {\n            indexArr[i] = i;\n        }\n\n        var timeDim = data.mapDimension('single');\n\n        // data group by name\n        var groupResult = groupData(indexArr, function (index) {\n            return data.get('name', index);\n        });\n        var layerSeries = [];\n        groupResult.buckets.each(function (items, key) {\n            items.sort(function (index1, index2) {\n                return data.get(timeDim, index1) - data.get(timeDim, index2);\n            });\n            layerSeries.push({name: key, indices: items});\n        });\n\n        return layerSeries;\n    },\n\n    /**\n     * Get data indices for show tooltip content\n     *\n     * @param {Array.<string>|string} dim  single coordinate dimension\n     * @param {number} value axis value\n     * @param {module:echarts/coord/single/SingleAxis} baseAxis  single Axis used\n     *     the themeRiver.\n     * @return {Object} {dataIndices, nestestValue}\n     */\n    getAxisTooltipData: function (dim, value, baseAxis) {\n        if (!isArray(dim)) {\n            dim = dim ? [dim] : [];\n        }\n\n        var data = this.getData();\n        var layerSeries = this.getLayerSeries();\n        var indices = [];\n        var layerNum = layerSeries.length;\n        var nestestValue;\n\n        for (var i = 0; i < layerNum; ++i) {\n            var minDist = Number.MAX_VALUE;\n            var nearestIdx = -1;\n            var pointNum = layerSeries[i].indices.length;\n            for (var j = 0; j < pointNum; ++j) {\n                var theValue = data.get(dim[0], layerSeries[i].indices[j]);\n                var dist = Math.abs(theValue - value);\n                if (dist <= minDist) {\n                    nestestValue = theValue;\n                    minDist = dist;\n                    nearestIdx = layerSeries[i].indices[j];\n                }\n            }\n            indices.push(nearestIdx);\n        }\n\n        return {dataIndices: indices, nestestValue: nestestValue};\n    },\n\n    /**\n     * @override\n     * @param {number} dataIndex  index of data\n     */\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var htmlName = data.getName(dataIndex);\n        var htmlValue = data.get(data.mapDimension('value'), dataIndex);\n        if (isNaN(htmlValue) || htmlValue == null) {\n            htmlValue = '-';\n        }\n        return encodeHTML(htmlName + ' : ' + htmlValue);\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n\n        coordinateSystem: 'singleAxis',\n\n        // gap in axis's orthogonal orientation\n        boundaryGap: ['10%', '10%'],\n\n        // legendHoverLink: true,\n\n        singleAxisIndex: 0,\n\n        animationEasing: 'linear',\n\n        label: {\n            margin: 4,\n            show: true,\n            position: 'left',\n            color: '#000',\n            fontSize: 11\n        },\n\n        emphasis: {\n            label: {\n                show: true\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file  The file used to draw themeRiver view\n * @author  Deqing Li(annong035@gmail.com)\n */\n\nextendChartView({\n\n    type: 'themeRiver',\n\n    init: function () {\n        this._layers = [];\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        var group = this.group;\n\n        var layerSeries = seriesModel.getLayerSeries();\n\n        var layoutInfo = data.getLayout('layoutInfo');\n        var rect = layoutInfo.rect;\n        var boundaryGap = layoutInfo.boundaryGap;\n\n        group.attr('position', [0, rect.y + boundaryGap[0]]);\n\n        function keyGetter(item) {\n            return item.name;\n        }\n        var dataDiffer = new DataDiffer(\n            this._layersSeries || [], layerSeries,\n            keyGetter, keyGetter\n        );\n\n        var newLayersGroups = {};\n\n        dataDiffer\n            .add(bind(process, this, 'add'))\n            .update(bind(process, this, 'update'))\n            .remove(bind(process, this, 'remove'))\n            .execute();\n\n        function process(status, idx, oldIdx) {\n            var oldLayersGroups = this._layers;\n            if (status === 'remove') {\n                group.remove(oldLayersGroups[idx]);\n                return;\n            }\n            var points0 = [];\n            var points1 = [];\n            var color;\n            var indices = layerSeries[idx].indices;\n            for (var j = 0; j < indices.length; j++) {\n                var layout = data.getItemLayout(indices[j]);\n                var x = layout.x;\n                var y0 = layout.y0;\n                var y = layout.y;\n\n                points0.push([x, y0]);\n                points1.push([x, y0 + y]);\n\n                color = data.getItemVisual(indices[j], 'color');\n            }\n\n            var polygon;\n            var text;\n            var textLayout = data.getItemLayout(indices[0]);\n            var itemModel = data.getItemModel(indices[j - 1]);\n            var labelModel = itemModel.getModel('label');\n            var margin = labelModel.get('margin');\n            if (status === 'add') {\n                var layerGroup = newLayersGroups[idx] = new Group();\n                polygon = new Polygon$1({\n                    shape: {\n                        points: points0,\n                        stackedOnPoints: points1,\n                        smooth: 0.4,\n                        stackedOnSmooth: 0.4,\n                        smoothConstraint: false\n                    },\n                    z2: 0\n                });\n                text = new Text({\n                    style: {\n                        x: textLayout.x - margin,\n                        y: textLayout.y0 + textLayout.y / 2\n                    }\n                });\n                layerGroup.add(polygon);\n                layerGroup.add(text);\n                group.add(layerGroup);\n\n                polygon.setClipPath(createGridClipShape$3(polygon.getBoundingRect(), seriesModel, function () {\n                    polygon.removeClipPath();\n                }));\n            }\n            else {\n                var layerGroup = oldLayersGroups[oldIdx];\n                polygon = layerGroup.childAt(0);\n                text = layerGroup.childAt(1);\n                group.add(layerGroup);\n\n                newLayersGroups[idx] = layerGroup;\n\n                updateProps(polygon, {\n                    shape: {\n                        points: points0,\n                        stackedOnPoints: points1\n                    }\n                }, seriesModel);\n\n                updateProps(text, {\n                    style: {\n                        x: textLayout.x - margin,\n                        y: textLayout.y0 + textLayout.y / 2\n                    }\n                }, seriesModel);\n            }\n\n            var hoverItemStyleModel = itemModel.getModel('emphasis.itemStyle');\n            var itemStyleModel = itemModel.getModel('itemStyle');\n\n            setTextStyle(text.style, labelModel, {\n                text: labelModel.get('show')\n                    ? seriesModel.getFormattedLabel(indices[j - 1], 'normal')\n                        || data.getName(indices[j - 1])\n                    : null,\n                textVerticalAlign: 'middle'\n            });\n\n            polygon.setStyle(extend({\n                fill: color\n            }, itemStyleModel.getItemStyle(['color'])));\n\n            setHoverStyle(polygon, hoverItemStyleModel.getItemStyle());\n        }\n\n        this._layersSeries = layerSeries;\n        this._layers = newLayersGroups;\n    },\n\n    dispose: function () {}\n});\n\n// add animation to the view\nfunction createGridClipShape$3(rect, seriesModel, cb) {\n    var rectEl = new Rect({\n        shape: {\n            x: rect.x - 10,\n            y: rect.y - 10,\n            width: 0,\n            height: rect.height + 20\n        }\n    });\n    initProps(rectEl, {\n        shape: {\n            width: rect.width + 20,\n            height: rect.height + 20\n        }\n    }, seriesModel, cb);\n\n    return rectEl;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file  Using layout algorithm transform the raw data to layout information.\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar themeRiverLayout = function (ecModel, api) {\n\n    ecModel.eachSeriesByType('themeRiver', function (seriesModel) {\n\n        var data = seriesModel.getData();\n\n        var single = seriesModel.coordinateSystem;\n\n        var layoutInfo = {};\n\n        // use the axis boundingRect for view\n        var rect = single.getRect();\n\n        layoutInfo.rect = rect;\n\n        var boundaryGap = seriesModel.get('boundaryGap');\n\n        var axis = single.getAxis();\n\n        layoutInfo.boundaryGap = boundaryGap;\n\n        if (axis.orient === 'horizontal') {\n            boundaryGap[0] = parsePercent$1(boundaryGap[0], rect.height);\n            boundaryGap[1] = parsePercent$1(boundaryGap[1], rect.height);\n            var height = rect.height - boundaryGap[0] - boundaryGap[1];\n            themeRiverLayout$1(data, seriesModel, height);\n        }\n        else {\n            boundaryGap[0] = parsePercent$1(boundaryGap[0], rect.width);\n            boundaryGap[1] = parsePercent$1(boundaryGap[1], rect.width);\n            var width = rect.width - boundaryGap[0] - boundaryGap[1];\n            themeRiverLayout$1(data, seriesModel, width);\n        }\n\n        data.setLayout('layoutInfo', layoutInfo);\n    });\n};\n\n/**\n * The layout information about themeriver\n *\n * @param {module:echarts/data/List} data  data in the series\n * @param {module:echarts/model/Series} seriesModel  the model object of themeRiver series\n * @param {number} height  value used to compute every series height\n */\nfunction themeRiverLayout$1(data, seriesModel, height) {\n    if (!data.count()) {\n        return;\n    }\n    var coordSys = seriesModel.coordinateSystem;\n    // the data in each layer are organized into a series.\n    var layerSeries = seriesModel.getLayerSeries();\n\n    // the points in each layer.\n    var timeDim = data.mapDimension('single');\n    var valueDim = data.mapDimension('value');\n    var layerPoints = map(layerSeries, function (singleLayer) {\n        return map(singleLayer.indices, function (idx) {\n            var pt = coordSys.dataToPoint(data.get(timeDim, idx));\n            pt[1] = data.get(valueDim, idx);\n            return pt;\n        });\n    });\n\n    var base = computeBaseline(layerPoints);\n    var baseLine = base.y0;\n    var ky = height / base.max;\n\n    // set layout information for each item.\n    var n = layerSeries.length;\n    var m = layerSeries[0].indices.length;\n    var baseY0;\n    for (var j = 0; j < m; ++j) {\n        baseY0 = baseLine[j] * ky;\n        data.setItemLayout(layerSeries[0].indices[j], {\n            layerIndex: 0,\n            x: layerPoints[0][j][0],\n            y0: baseY0,\n            y: layerPoints[0][j][1] * ky\n        });\n        for (var i = 1; i < n; ++i) {\n            baseY0 += layerPoints[i - 1][j][1] * ky;\n            data.setItemLayout(layerSeries[i].indices[j], {\n                layerIndex: i,\n                x: layerPoints[i][j][0],\n                y0: baseY0,\n                y: layerPoints[i][j][1] * ky\n            });\n        }\n    }\n}\n\n/**\n * Compute the baseLine of the rawdata\n * Inspired by Lee Byron's paper Stacked Graphs - Geometry & Aesthetics\n *\n * @param  {Array.<Array>} data  the points in each layer\n * @return {Object}\n */\nfunction computeBaseline(data) {\n    var layerNum = data.length;\n    var pointNum = data[0].length;\n    var sums = [];\n    var y0 = [];\n    var max = 0;\n    var temp;\n    var base = {};\n\n    for (var i = 0; i < pointNum; ++i) {\n        for (var j = 0, temp = 0; j < layerNum; ++j) {\n            temp += data[j][i][1];\n        }\n        if (temp > max) {\n            max = temp;\n        }\n        sums.push(temp);\n    }\n\n    for (var k = 0; k < pointNum; ++k) {\n        y0[k] = (max - sums[k]) / 2;\n    }\n    max = 0;\n\n    for (var l = 0; l < pointNum; ++l) {\n        var sum = sums[l] + y0[l];\n        if (sum > max) {\n            max = sum;\n        }\n    }\n    base.y0 = y0;\n    base.max = max;\n\n    return base;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Visual encoding for themeRiver view\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar themeRiverVisual = function (ecModel) {\n    ecModel.eachSeriesByType('themeRiver', function (seriesModel) {\n        var data = seriesModel.getData();\n        var rawData = seriesModel.getRawData();\n        var colorList = seriesModel.get('color');\n        var idxMap = createHashMap();\n\n        data.each(function (idx) {\n            idxMap.set(data.getRawIndex(idx), idx);\n        });\n\n        rawData.each(function (rawIndex) {\n            var name = rawData.getName(rawIndex);\n            var color = colorList[(seriesModel.nameMap.get(name) - 1) % colorList.length];\n\n            rawData.setItemVisual(rawIndex, 'color', color);\n\n            var idx = idxMap.get(rawIndex);\n\n            if (idx != null) {\n                data.setItemVisual(idx, 'color', color);\n            }\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterLayout(themeRiverLayout);\nregisterVisual(themeRiverVisual);\nregisterProcessor(dataFilter('themeRiver'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.sunburst',\n\n    /**\n     * @type {module:echarts/data/Tree~Node}\n     */\n    _viewRoot: null,\n\n    getInitialData: function (option, ecModel) {\n        // Create a virtual root.\n        var root = { name: option.name, children: option.data };\n\n        completeTreeValue$1(root);\n\n        var levels = option.levels || [];\n\n        // levels = option.levels = setDefault(levels, ecModel);\n\n        var treeOption = {};\n\n        treeOption.levels = levels;\n\n        // Make sure always a new tree is created when setOption,\n        // in TreemapView, we check whether oldTree === newTree\n        // to choose mappings approach among old shapes and new shapes.\n        return Tree.createTree(root, this, treeOption).data;\n    },\n\n    optionUpdated: function () {\n        this.resetViewRoot();\n    },\n\n    /*\n     * @override\n     */\n    getDataParams: function (dataIndex) {\n        var params = SeriesModel.prototype.getDataParams.apply(this, arguments);\n\n        var node = this.getData().tree.getNodeByDataIndex(dataIndex);\n        params.treePathInfo = wrapTreePathInfo(node, this);\n\n        return params;\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n\n        // 默认全局居中\n        center: ['50%', '50%'],\n        radius: [0, '75%'],\n        // 默认顺时针\n        clockwise: true,\n        startAngle: 90,\n        // 最小角度改为0\n        minAngle: 0,\n\n        percentPrecision: 2,\n\n        // If still show when all data zero.\n        stillShowZeroSum: true,\n\n        // Policy of highlighting pieces when hover on one\n        // Valid values: 'none' (for not downplay others), 'descendant',\n        // 'ancestor', 'self'\n        highlightPolicy: 'descendant',\n\n        // 'rootToNode', 'link', or false\n        nodeClick: 'rootToNode',\n\n        renderLabelForZeroData: false,\n\n        label: {\n            // could be: 'radial', 'tangential', or 'none'\n            rotate: 'radial',\n            show: true,\n            opacity: 1,\n            // 'left' is for inner side of inside, and 'right' is for outter\n            // side for inside\n            align: 'center',\n            position: 'inside',\n            distance: 5,\n            silent: true,\n            emphasis: {}\n        },\n        itemStyle: {\n            borderWidth: 1,\n            borderColor: 'white',\n            borderType: 'solid',\n            shadowBlur: 0,\n            shadowColor: 'rgba(0, 0, 0, 0.2)',\n            shadowOffsetX: 0,\n            shadowOffsetY: 0,\n            opacity: 1,\n            emphasis: {},\n            highlight: {\n                opacity: 1\n            },\n            downplay: {\n                opacity: 0.9\n            }\n        },\n\n        // Animation type canbe expansion, scale\n        animationType: 'expansion',\n        animationDuration: 1000,\n        animationDurationUpdate: 500,\n        animationEasing: 'cubicOut',\n\n        data: [],\n\n        levels: [],\n\n        /**\n         * Sort order.\n         *\n         * Valid values: 'desc', 'asc', null, or callback function.\n         * 'desc' and 'asc' for descend and ascendant order;\n         * null for not sorting;\n         * example of callback function:\n         * function(nodeA, nodeB) {\n         *     return nodeA.getValue() - nodeB.getValue();\n         * }\n         */\n        sort: 'desc'\n    },\n\n    getViewRoot: function () {\n        return this._viewRoot;\n    },\n\n    /**\n     * @param {module:echarts/data/Tree~Node} [viewRoot]\n     */\n    resetViewRoot: function (viewRoot) {\n        viewRoot\n            ? (this._viewRoot = viewRoot)\n            : (viewRoot = this._viewRoot);\n\n        var root = this.getRawData().tree.root;\n\n        if (!viewRoot\n            || (viewRoot !== root && !root.contains(viewRoot))\n        ) {\n            this._viewRoot = root;\n        }\n    }\n});\n\n\n\n/**\n * @param {Object} dataNode\n */\nfunction completeTreeValue$1(dataNode) {\n    // Postorder travel tree.\n    // If value of none-leaf node is not set,\n    // calculate it by suming up the value of all children.\n    var sum = 0;\n\n    each$1(dataNode.children, function (child) {\n\n        completeTreeValue$1(child);\n\n        var childValue = child.value;\n        isArray(childValue) && (childValue = childValue[0]);\n\n        sum += childValue;\n    });\n\n    var thisValue = dataNode.value;\n    if (isArray(thisValue)) {\n        thisValue = thisValue[0];\n    }\n\n    if (thisValue == null || isNaN(thisValue)) {\n        thisValue = sum;\n    }\n    // Value should not less than 0.\n    if (thisValue < 0) {\n        thisValue = 0;\n    }\n\n    isArray(dataNode.value)\n        ? (dataNode.value[0] = thisValue)\n        : (dataNode.value = thisValue);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar NodeHighlightPolicy = {\n    NONE: 'none', // not downplay others\n    DESCENDANT: 'descendant',\n    ANCESTOR: 'ancestor',\n    SELF: 'self'\n};\n\nvar DEFAULT_SECTOR_Z = 2;\nvar DEFAULT_TEXT_Z = 4;\n\n/**\n * Sunburstce of Sunburst including Sector, Label, LabelLine\n * @constructor\n * @extends {module:zrender/graphic/Group}\n */\nfunction SunburstPiece(node, seriesModel, ecModel) {\n\n    Group.call(this);\n\n    var sector = new Sector({\n        z2: DEFAULT_SECTOR_Z\n    });\n    sector.seriesIndex = seriesModel.seriesIndex;\n\n    var text = new Text({\n        z2: DEFAULT_TEXT_Z,\n        silent: node.getModel('label').get('silent')\n    });\n    this.add(sector);\n    this.add(text);\n\n    this.updateData(true, node, 'normal', seriesModel, ecModel);\n\n    // Hover to change label and labelLine\n    function onEmphasis() {\n        text.ignore = text.hoverIgnore;\n    }\n    function onNormal() {\n        text.ignore = text.normalIgnore;\n    }\n    this.on('emphasis', onEmphasis)\n        .on('normal', onNormal)\n        .on('mouseover', onEmphasis)\n        .on('mouseout', onNormal);\n}\n\nvar SunburstPieceProto = SunburstPiece.prototype;\n\nSunburstPieceProto.updateData = function (\n    firstCreate,\n    node,\n    state,\n    seriesModel,\n    ecModel\n) {\n    this.node = node;\n    node.piece = this;\n\n    seriesModel = seriesModel || this._seriesModel;\n    ecModel = ecModel || this._ecModel;\n\n    var sector = this.childAt(0);\n    sector.dataIndex = node.dataIndex;\n\n    var itemModel = node.getModel();\n    var layout = node.getLayout();\n    // if (!layout) {\n    //     console.log(node.getLayout());\n    // }\n    var sectorShape = extend({}, layout);\n    sectorShape.label = null;\n\n    var visualColor = getNodeColor(node, seriesModel, ecModel);\n\n    fillDefaultColor(node, seriesModel, visualColor);\n\n    var normalStyle = itemModel.getModel('itemStyle').getItemStyle();\n    var style;\n    if (state === 'normal') {\n        style = normalStyle;\n    }\n    else {\n        var stateStyle = itemModel.getModel(state + '.itemStyle')\n            .getItemStyle();\n        style = merge(stateStyle, normalStyle);\n    }\n    style = defaults(\n        {\n            lineJoin: 'bevel',\n            fill: style.fill || visualColor\n        },\n        style\n    );\n\n    if (firstCreate) {\n        sector.setShape(sectorShape);\n        sector.shape.r = layout.r0;\n        updateProps(\n            sector,\n            {\n                shape: {\n                    r: layout.r\n                }\n            },\n            seriesModel,\n            node.dataIndex\n        );\n        sector.useStyle(style);\n    }\n    else if (typeof style.fill === 'object' && style.fill.type\n        || typeof sector.style.fill === 'object' && sector.style.fill.type\n    ) {\n        // Disable animation for gradient since no interpolation method\n        // is supported for gradient\n        updateProps(sector, {\n            shape: sectorShape\n        }, seriesModel);\n        sector.useStyle(style);\n    }\n    else {\n        updateProps(sector, {\n            shape: sectorShape,\n            style: style\n        }, seriesModel);\n    }\n\n    this._updateLabel(seriesModel, visualColor, state);\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && sector.attr('cursor', cursorStyle);\n\n    if (firstCreate) {\n        var highlightPolicy = seriesModel.getShallow('highlightPolicy');\n        this._initEvents(sector, node, seriesModel, highlightPolicy);\n    }\n\n    this._seriesModel = seriesModel || this._seriesModel;\n    this._ecModel = ecModel || this._ecModel;\n};\n\nSunburstPieceProto.onEmphasis = function (highlightPolicy) {\n    var that = this;\n    this.node.hostTree.root.eachNode(function (n) {\n        if (n.piece) {\n            if (that.node === n) {\n                n.piece.updateData(false, n, 'emphasis');\n            }\n            else if (isNodeHighlighted(n, that.node, highlightPolicy)) {\n                n.piece.childAt(0).trigger('highlight');\n            }\n            else if (highlightPolicy !== NodeHighlightPolicy.NONE) {\n                n.piece.childAt(0).trigger('downplay');\n            }\n        }\n    });\n};\n\nSunburstPieceProto.onNormal = function () {\n    this.node.hostTree.root.eachNode(function (n) {\n        if (n.piece) {\n            n.piece.updateData(false, n, 'normal');\n        }\n    });\n};\n\nSunburstPieceProto.onHighlight = function () {\n    this.updateData(false, this.node, 'highlight');\n};\n\nSunburstPieceProto.onDownplay = function () {\n    this.updateData(false, this.node, 'downplay');\n};\n\nSunburstPieceProto._updateLabel = function (seriesModel, visualColor, state) {\n    var itemModel = this.node.getModel();\n    var normalModel = itemModel.getModel('label');\n    var labelModel = state === 'normal' || state === 'emphasis'\n        ? normalModel\n        : itemModel.getModel(state + '.label');\n    var labelHoverModel = itemModel.getModel('emphasis.label');\n\n    var text = retrieve(\n        seriesModel.getFormattedLabel(\n            this.node.dataIndex, 'normal', null, null, 'label'\n        ),\n        this.node.name\n    );\n    if (getLabelAttr('show') === false) {\n        text = '';\n    }\n\n    var layout = this.node.getLayout();\n    var labelMinAngle = labelModel.get('minAngle');\n    if (labelMinAngle == null) {\n        labelMinAngle = normalModel.get('minAngle');\n    }\n    labelMinAngle = labelMinAngle / 180 * Math.PI;\n    var angle = layout.endAngle - layout.startAngle;\n    if (labelMinAngle != null && Math.abs(angle) < labelMinAngle) {\n        // Not displaying text when angle is too small\n        text = '';\n    }\n\n    var label = this.childAt(1);\n\n    setLabelStyle(\n        label.style, label.hoverStyle || {}, normalModel, labelHoverModel,\n        {\n            defaultText: labelModel.getShallow('show') ? text : null,\n            autoColor: visualColor,\n            useInsideStyle: true\n        }\n    );\n\n    var midAngle = (layout.startAngle + layout.endAngle) / 2;\n    var dx = Math.cos(midAngle);\n    var dy = Math.sin(midAngle);\n\n    var r;\n    var labelPosition = getLabelAttr('position');\n    var labelPadding = getLabelAttr('distance') || 0;\n    var textAlign = getLabelAttr('align');\n    if (labelPosition === 'outside') {\n        r = layout.r + labelPadding;\n        textAlign = midAngle > Math.PI / 2 ? 'right' : 'left';\n    }\n    else {\n        if (!textAlign || textAlign === 'center') {\n            r = (layout.r + layout.r0) / 2;\n            textAlign = 'center';\n        }\n        else if (textAlign === 'left') {\n            r = layout.r0 + labelPadding;\n            if (midAngle > Math.PI / 2) {\n                textAlign = 'right';\n            }\n        }\n        else if (textAlign === 'right') {\n            r = layout.r - labelPadding;\n            if (midAngle > Math.PI / 2) {\n                textAlign = 'left';\n            }\n        }\n    }\n\n    label.attr('style', {\n        text: text,\n        textAlign: textAlign,\n        textVerticalAlign: getLabelAttr('verticalAlign') || 'middle',\n        opacity: getLabelAttr('opacity')\n    });\n\n    var textX = r * dx + layout.cx;\n    var textY = r * dy + layout.cy;\n    label.attr('position', [textX, textY]);\n\n    var rotateType = getLabelAttr('rotate');\n    var rotate = 0;\n    if (rotateType === 'radial') {\n        rotate = -midAngle;\n        if (rotate < -Math.PI / 2) {\n            rotate += Math.PI;\n        }\n    }\n    else if (rotateType === 'tangential') {\n        rotate = Math.PI / 2 - midAngle;\n        if (rotate > Math.PI / 2) {\n            rotate -= Math.PI;\n        }\n        else if (rotate < -Math.PI / 2) {\n            rotate += Math.PI;\n        }\n    } else if (typeof rotateType === 'number') {\n        rotate = rotateType * Math.PI / 180;\n    }\n    label.attr('rotation', rotate);\n\n    function getLabelAttr(name) {\n        var stateAttr = labelModel.get(name);\n        if (stateAttr == null) {\n            return normalModel.get(name);\n        }\n        else {\n            return stateAttr;\n        }\n    }\n};\n\nSunburstPieceProto._initEvents = function (\n    sector,\n    node,\n    seriesModel,\n    highlightPolicy\n) {\n    sector.off('mouseover').off('mouseout').off('emphasis').off('normal');\n\n    var that = this;\n    var onEmphasis = function () {\n        that.onEmphasis(highlightPolicy);\n    };\n    var onNormal = function () {\n        that.onNormal();\n    };\n    var onDownplay = function () {\n        that.onDownplay();\n    };\n    var onHighlight = function () {\n        that.onHighlight();\n    };\n\n    if (seriesModel.isAnimationEnabled()) {\n        sector\n            .on('mouseover', onEmphasis)\n            .on('mouseout', onNormal)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal)\n            .on('downplay', onDownplay)\n            .on('highlight', onHighlight);\n    }\n};\n\ninherits(SunburstPiece, Group);\n\n/**\n * Get node color\n *\n * @param {TreeNode} node the node to get color\n * @param {module:echarts/model/Series} seriesModel series\n * @param {module:echarts/model/Global} ecModel echarts defaults\n */\nfunction getNodeColor(node, seriesModel, ecModel) {\n    // Color from visualMap\n    var visualColor = node.getVisual('color');\n    var visualMetaList = node.getVisual('visualMeta');\n    if (!visualMetaList || visualMetaList.length === 0) {\n        // Use first-generation color if has no visualMap\n        visualColor = null;\n    }\n\n    // Self color or level color\n    var color = node.getModel('itemStyle').get('color');\n    if (color) {\n        return color;\n    }\n    else if (visualColor) {\n        // Color mapping\n        return visualColor;\n    }\n    else if (node.depth === 0) {\n        // Virtual root node\n        return ecModel.option.color[0];\n    }\n    else {\n        // First-generation color\n        var length = ecModel.option.color.length;\n        color = ecModel.option.color[getRootId(node) % length];\n    }\n    return color;\n}\n\n/**\n * Get index of root in sorted order\n *\n * @param {TreeNode} node current node\n * @return {number} index in root\n */\nfunction getRootId(node) {\n    var ancestor = node;\n    while (ancestor.depth > 1) {\n        ancestor = ancestor.parentNode;\n    }\n\n    var virtualRoot = node.getAncestors()[0];\n    return indexOf(virtualRoot.children, ancestor);\n}\n\nfunction isNodeHighlighted(node, activeNode, policy) {\n    if (policy === NodeHighlightPolicy.NONE) {\n        return false;\n    }\n    else if (policy === NodeHighlightPolicy.SELF) {\n        return node === activeNode;\n    }\n    else if (policy === NodeHighlightPolicy.ANCESTOR) {\n        return node === activeNode || node.isAncestorOf(activeNode);\n    }\n    else {\n        return node === activeNode || node.isDescendantOf(activeNode);\n    }\n}\n\n// Fix tooltip callback function params.color incorrect when pick a default color\nfunction fillDefaultColor(node, seriesModel, color) {\n    var data = seriesModel.getData();\n    data.setItemVisual(node.dataIndex, 'color', color);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ROOT_TO_NODE_ACTION = 'sunburstRootToNode';\n\nvar SunburstView = Chart.extend({\n\n    type: 'sunburst',\n\n    init: function () {\n    },\n\n    render: function (seriesModel, ecModel, api, payload) {\n        var that = this;\n\n        this.seriesModel = seriesModel;\n        this.api = api;\n        this.ecModel = ecModel;\n\n        var data = seriesModel.getData();\n        var virtualRoot = data.tree.root;\n\n        var newRoot = seriesModel.getViewRoot();\n\n        var group = this.group;\n\n        var renderLabelForZeroData = seriesModel.get('renderLabelForZeroData');\n\n        var newChildren = [];\n        newRoot.eachNode(function (node) {\n            newChildren.push(node);\n        });\n        var oldChildren = this._oldChildren || [];\n\n        dualTravel(newChildren, oldChildren);\n\n        renderRollUp(virtualRoot, newRoot);\n\n        if (payload && payload.highlight && payload.highlight.piece) {\n            var highlightPolicy = seriesModel.getShallow('highlightPolicy');\n            payload.highlight.piece.onEmphasis(highlightPolicy);\n        }\n        else if (payload && payload.unhighlight) {\n            var piece = this.virtualPiece;\n            if (!piece && virtualRoot.children.length) {\n                piece = virtualRoot.children[0].piece;\n            }\n            if (piece) {\n                piece.onNormal();\n            }\n        }\n\n        this._initEvents();\n\n        this._oldChildren = newChildren;\n\n        function dualTravel(newChildren, oldChildren) {\n            if (newChildren.length === 0 && oldChildren.length === 0) {\n                return;\n            }\n\n            new DataDiffer(oldChildren, newChildren, getKey, getKey)\n                .add(processNode)\n                .update(processNode)\n                .remove(curry(processNode, null))\n                .execute();\n\n            function getKey(node) {\n                return node.getId();\n            }\n\n            function processNode(newId, oldId) {\n                var newNode = newId == null ? null : newChildren[newId];\n                var oldNode = oldId == null ? null : oldChildren[oldId];\n\n                doRenderNode(newNode, oldNode);\n            }\n        }\n\n        function doRenderNode(newNode, oldNode) {\n            if (!renderLabelForZeroData && newNode && !newNode.getValue()) {\n                // Not render data with value 0\n                newNode = null;\n            }\n\n            if (newNode !== virtualRoot && oldNode !== virtualRoot) {\n                if (oldNode && oldNode.piece) {\n                    if (newNode) {\n                        // Update\n                        oldNode.piece.updateData(\n                            false, newNode, 'normal', seriesModel, ecModel);\n\n                        // For tooltip\n                        data.setItemGraphicEl(newNode.dataIndex, oldNode.piece);\n                    }\n                    else {\n                        // Remove\n                        removeNode(oldNode);\n                    }\n                }\n                else if (newNode) {\n                    // Add\n                    var piece = new SunburstPiece(\n                        newNode,\n                        seriesModel,\n                        ecModel\n                    );\n                    group.add(piece);\n\n                    // For tooltip\n                    data.setItemGraphicEl(newNode.dataIndex, piece);\n                }\n            }\n        }\n\n        function removeNode(node) {\n            if (!node) {\n                return;\n            }\n\n            if (node.piece) {\n                group.remove(node.piece);\n                node.piece = null;\n            }\n        }\n\n        function renderRollUp(virtualRoot, viewRoot) {\n            if (viewRoot.depth > 0) {\n                // Render\n                if (that.virtualPiece) {\n                    // Update\n                    that.virtualPiece.updateData(\n                        false, virtualRoot, 'normal', seriesModel, ecModel);\n                }\n                else {\n                    // Add\n                    that.virtualPiece = new SunburstPiece(\n                        virtualRoot,\n                        seriesModel,\n                        ecModel\n                    );\n                    group.add(that.virtualPiece);\n                }\n\n                if (viewRoot.piece._onclickEvent) {\n                    viewRoot.piece.off('click', viewRoot.piece._onclickEvent);\n                }\n                var event = function (e) {\n                    that._rootToNode(viewRoot.parentNode);\n                };\n                viewRoot.piece._onclickEvent = event;\n                that.virtualPiece.on('click', event);\n            }\n            else if (that.virtualPiece) {\n                // Remove\n                group.remove(that.virtualPiece);\n                that.virtualPiece = null;\n            }\n        }\n    },\n\n    dispose: function () {\n    },\n\n    /**\n     * @private\n     */\n    _initEvents: function () {\n        var that = this;\n\n        var event = function (e) {\n            var targetFound = false;\n            var viewRoot = that.seriesModel.getViewRoot();\n            viewRoot.eachNode(function (node) {\n                if (!targetFound\n                    && node.piece && node.piece.childAt(0) === e.target\n                ) {\n                    var nodeClick = node.getModel().get('nodeClick');\n                    if (nodeClick === 'rootToNode') {\n                        that._rootToNode(node);\n                    }\n                    else if (nodeClick === 'link') {\n                        var itemModel = node.getModel();\n                        var link = itemModel.get('link');\n                        if (link) {\n                            var linkTarget = itemModel.get('target', true)\n                                || '_blank';\n                            window.open(link, linkTarget);\n                        }\n                    }\n                    targetFound = true;\n                }\n            });\n        };\n\n        if (this.group._onclickEvent) {\n            this.group.off('click', this.group._onclickEvent);\n        }\n        this.group.on('click', event);\n        this.group._onclickEvent = event;\n    },\n\n    /**\n     * @private\n     */\n    _rootToNode: function (node) {\n        if (node !== this.seriesModel.getViewRoot()) {\n            this.api.dispatchAction({\n                type: ROOT_TO_NODE_ACTION,\n                from: this.uid,\n                seriesId: this.seriesModel.id,\n                targetNode: node\n            });\n        }\n    },\n\n    /**\n     * @implement\n     */\n    containPoint: function (point, seriesModel) {\n        var treeRoot = seriesModel.getData();\n        var itemLayout = treeRoot.getItemLayout(0);\n        if (itemLayout) {\n            var dx = point[0] - itemLayout.cx;\n            var dy = point[1] - itemLayout.cy;\n            var radius = Math.sqrt(dx * dx + dy * dy);\n            return radius <= itemLayout.r && radius >= itemLayout.r0;\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Sunburst action\n */\n\nvar ROOT_TO_NODE_ACTION$1 = 'sunburstRootToNode';\n\nregisterAction(\n    {type: ROOT_TO_NODE_ACTION$1, update: 'updateView'},\n    function (payload, ecModel) {\n\n        ecModel.eachComponent(\n            {mainType: 'series', subType: 'sunburst', query: payload},\n            handleRootToNode\n        );\n\n        function handleRootToNode(model, index) {\n            var targetInfo = retrieveTargetInfo(payload, [ROOT_TO_NODE_ACTION$1], model);\n\n            if (targetInfo) {\n                var originViewRoot = model.getViewRoot();\n                if (originViewRoot) {\n                    payload.direction = aboveViewRoot(originViewRoot, targetInfo.node)\n                        ? 'rollUp' : 'drillDown';\n                }\n                model.resetViewRoot(targetInfo.node);\n            }\n        }\n    }\n);\n\n\nvar HIGHLIGHT_ACTION = 'sunburstHighlight';\n\nregisterAction(\n    {type: HIGHLIGHT_ACTION, update: 'updateView'},\n    function (payload, ecModel) {\n\n        ecModel.eachComponent(\n            {mainType: 'series', subType: 'sunburst', query: payload},\n            handleHighlight\n        );\n\n        function handleHighlight(model, index) {\n            var targetInfo = retrieveTargetInfo(payload, [HIGHLIGHT_ACTION], model);\n\n            if (targetInfo) {\n                payload.highlight = targetInfo.node;\n            }\n        }\n    }\n);\n\n\nvar UNHIGHLIGHT_ACTION = 'sunburstUnhighlight';\n\nregisterAction(\n    {type: UNHIGHLIGHT_ACTION, update: 'updateView'},\n    function (payload, ecModel) {\n\n        ecModel.eachComponent(\n            {mainType: 'series', subType: 'sunburst', query: payload},\n            handleUnhighlight\n        );\n\n        function handleUnhighlight(model, index) {\n            payload.unhighlight = true;\n        }\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar RADIAN$1 = Math.PI / 180;\n\nvar sunburstLayout = function (seriesType, ecModel, api, payload) {\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        var center = seriesModel.get('center');\n        var radius = seriesModel.get('radius');\n\n        if (!isArray(radius)) {\n            radius = [0, radius];\n        }\n        if (!isArray(center)) {\n            center = [center, center];\n        }\n\n        var width = api.getWidth();\n        var height = api.getHeight();\n        var size = Math.min(width, height);\n        var cx = parsePercent$1(center[0], width);\n        var cy = parsePercent$1(center[1], height);\n        var r0 = parsePercent$1(radius[0], size / 2);\n        var r = parsePercent$1(radius[1], size / 2);\n\n        var startAngle = -seriesModel.get('startAngle') * RADIAN$1;\n        var minAngle = seriesModel.get('minAngle') * RADIAN$1;\n\n        var virtualRoot = seriesModel.getData().tree.root;\n        var treeRoot = seriesModel.getViewRoot();\n        var rootDepth = treeRoot.depth;\n\n        var sort = seriesModel.get('sort');\n        if (sort != null) {\n            initChildren$1(treeRoot, sort);\n        }\n\n        var validDataCount = 0;\n        each$1(treeRoot.children, function (child) {\n            !isNaN(child.getValue()) && validDataCount++;\n        });\n\n        var sum = treeRoot.getValue();\n        // Sum may be 0\n        var unitRadian = Math.PI / (sum || validDataCount) * 2;\n\n        var renderRollupNode = treeRoot.depth > 0;\n        var levels = treeRoot.height - (renderRollupNode ? -1 : 1);\n        var rPerLevel = (r - r0) / (levels || 1);\n\n        var clockwise = seriesModel.get('clockwise');\n\n        var stillShowZeroSum = seriesModel.get('stillShowZeroSum');\n\n        // In the case some sector angle is smaller than minAngle\n        var dir = clockwise ? 1 : -1;\n\n        /**\n         * Render a tree\n         * @return increased angle\n         */\n        var renderNode = function (node, startAngle) {\n            if (!node) {\n                return;\n            }\n\n            var endAngle = startAngle;\n\n            // Render self\n            if (node !== virtualRoot) {\n                // Tree node is virtual, so it doesn't need to be drawn\n                var value = node.getValue();\n\n                var angle = (sum === 0 && stillShowZeroSum)\n                    ? unitRadian : (value * unitRadian);\n                if (angle < minAngle) {\n                    angle = minAngle;\n                    \n                }\n                else {\n                    \n                }\n\n                endAngle = startAngle + dir * angle;\n\n                var depth = node.depth - rootDepth\n                    - (renderRollupNode ? -1 : 1);\n                var rStart = r0 + rPerLevel * depth;\n                var rEnd = r0 + rPerLevel * (depth + 1);\n\n                var itemModel = node.getModel();\n                if (itemModel.get('r0') != null) {\n                    rStart = parsePercent$1(itemModel.get('r0'), size / 2);\n                }\n                if (itemModel.get('r') != null) {\n                    rEnd = parsePercent$1(itemModel.get('r'), size / 2);\n                }\n\n                node.setLayout({\n                    angle: angle,\n                    startAngle: startAngle,\n                    endAngle: endAngle,\n                    clockwise: clockwise,\n                    cx: cx,\n                    cy: cy,\n                    r0: rStart,\n                    r: rEnd\n                });\n            }\n\n            // Render children\n            if (node.children && node.children.length) {\n                // currentAngle = startAngle;\n                var siblingAngle = 0;\n                each$1(node.children, function (node) {\n                    siblingAngle += renderNode(node, startAngle + siblingAngle);\n                });\n            }\n\n            return endAngle - startAngle;\n        };\n\n        // Virtual root node for roll up\n        if (renderRollupNode) {\n            var rStart = r0;\n            var rEnd = r0 + rPerLevel;\n\n            var angle = Math.PI * 2;\n            virtualRoot.setLayout({\n                angle: angle,\n                startAngle: startAngle,\n                endAngle: startAngle + angle,\n                clockwise: clockwise,\n                cx: cx,\n                cy: cy,\n                r0: rStart,\n                r: rEnd\n            });\n        }\n\n        renderNode(treeRoot, startAngle);\n    });\n};\n\n/**\n * Init node children by order and update visual\n *\n * @param {TreeNode} node  root node\n * @param {boolean}  isAsc if is in ascendant order\n */\nfunction initChildren$1(node, isAsc) {\n    var children = node.children || [];\n\n    node.children = sort$2(children, isAsc);\n\n    // Init children recursively\n    if (children.length) {\n        each$1(node.children, function (child) {\n            initChildren$1(child, isAsc);\n        });\n    }\n}\n\n/**\n * Sort children nodes\n *\n * @param {TreeNode[]}               children children of node to be sorted\n * @param {string | function | null} sort sort method\n *                                   See SunburstSeries.js for details.\n */\nfunction sort$2(children, sortOrder) {\n    if (typeof sortOrder === 'function') {\n        return children.sort(sortOrder);\n    }\n    else {\n        var isAsc = sortOrder === 'asc';\n        return children.sort(function (a, b) {\n            var diff = (a.getValue() - b.getValue()) * (isAsc ? 1 : -1);\n            return diff === 0\n                ? (a.dataIndex - b.dataIndex) * (isAsc ? -1 : 1)\n                : diff;\n        });\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(curry(dataColor, 'sunburst'));\nregisterLayout(curry(sunburstLayout, 'sunburst'));\nregisterProcessor(curry(dataFilter, 'sunburst'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction dataToCoordSize(dataSize, dataItem) {\n    // dataItem is necessary in log axis.\n    dataItem = dataItem || [0, 0];\n    return map(['x', 'y'], function (dim, dimIdx) {\n        var axis = this.getAxis(dim);\n        var val = dataItem[dimIdx];\n        var halfSize = dataSize[dimIdx] / 2;\n        return axis.type === 'category'\n            ? axis.getBandWidth()\n            : Math.abs(axis.dataToCoord(val - halfSize) - axis.dataToCoord(val + halfSize));\n    }, this);\n}\n\nvar prepareCartesian2d = function (coordSys) {\n    var rect = coordSys.grid.getRect();\n    return {\n        coordSys: {\n            // The name exposed to user is always 'cartesian2d' but not 'grid'.\n            type: 'cartesian2d',\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        },\n        api: {\n            coord: function (data) {\n                // do not provide \"out\" param\n                return coordSys.dataToPoint(data);\n            },\n            size: bind(dataToCoordSize, coordSys)\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction dataToCoordSize$1(dataSize, dataItem) {\n    dataItem = dataItem || [0, 0];\n    return map([0, 1], function (dimIdx) {\n        var val = dataItem[dimIdx];\n        var halfSize = dataSize[dimIdx] / 2;\n        var p1 = [];\n        var p2 = [];\n        p1[dimIdx] = val - halfSize;\n        p2[dimIdx] = val + halfSize;\n        p1[1 - dimIdx] = p2[1 - dimIdx] = dataItem[1 - dimIdx];\n        return Math.abs(this.dataToPoint(p1)[dimIdx] - this.dataToPoint(p2)[dimIdx]);\n    }, this);\n}\n\nvar prepareGeo = function (coordSys) {\n    var rect = coordSys.getBoundingRect();\n    return {\n        coordSys: {\n            type: 'geo',\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height,\n            zoom: coordSys.getZoom()\n        },\n        api: {\n            coord: function (data) {\n                // do not provide \"out\" and noRoam param,\n                // Compatible with this usage:\n                // echarts.util.map(item.points, api.coord)\n                return coordSys.dataToPoint(data);\n            },\n            size: bind(dataToCoordSize$1, coordSys)\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction dataToCoordSize$2(dataSize, dataItem) {\n    // dataItem is necessary in log axis.\n    var axis = this.getAxis();\n    var val = dataItem instanceof Array ? dataItem[0] : dataItem;\n    var halfSize = (dataSize instanceof Array ? dataSize[0] : dataSize) / 2;\n    return axis.type === 'category'\n        ? axis.getBandWidth()\n        : Math.abs(axis.dataToCoord(val - halfSize) - axis.dataToCoord(val + halfSize));\n}\n\nvar prepareSingleAxis = function (coordSys) {\n    var rect = coordSys.getRect();\n\n    return {\n        coordSys: {\n            type: 'singleAxis',\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        },\n        api: {\n            coord: function (val) {\n                // do not provide \"out\" param\n                return coordSys.dataToPoint(val);\n            },\n            size: bind(dataToCoordSize$2, coordSys)\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction dataToCoordSize$3(dataSize, dataItem) {\n    // dataItem is necessary in log axis.\n    return map(['Radius', 'Angle'], function (dim, dimIdx) {\n        var axis = this['get' + dim + 'Axis']();\n        var val = dataItem[dimIdx];\n        var halfSize = dataSize[dimIdx] / 2;\n        var method = 'dataTo' + dim;\n\n        var result = axis.type === 'category'\n            ? axis.getBandWidth()\n            : Math.abs(axis[method](val - halfSize) - axis[method](val + halfSize));\n\n        if (dim === 'Angle') {\n            result = result * Math.PI / 180;\n        }\n\n        return result;\n\n    }, this);\n}\n\nvar preparePolar = function (coordSys) {\n    var radiusAxis = coordSys.getRadiusAxis();\n    var angleAxis = coordSys.getAngleAxis();\n    var radius = radiusAxis.getExtent();\n    radius[0] > radius[1] && radius.reverse();\n\n    return {\n        coordSys: {\n            type: 'polar',\n            cx: coordSys.cx,\n            cy: coordSys.cy,\n            r: radius[1],\n            r0: radius[0]\n        },\n        api: {\n            coord: bind(function (data) {\n                var radius = radiusAxis.dataToRadius(data[0]);\n                var angle = angleAxis.dataToAngle(data[1]);\n                var coord = coordSys.coordToPoint([radius, angle]);\n                coord.push(radius, angle * Math.PI / 180);\n                return coord;\n            }),\n            size: bind(dataToCoordSize$3, coordSys)\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar prepareCalendar = function (coordSys) {\n    var rect = coordSys.getRect();\n    var rangeInfo = coordSys.getRangeInfo();\n\n    return {\n        coordSys: {\n            type: 'calendar',\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height,\n            cellWidth: coordSys.getCellWidth(),\n            cellHeight: coordSys.getCellHeight(),\n            rangeInfo: {\n                start: rangeInfo.start,\n                end: rangeInfo.end,\n                weeks: rangeInfo.weeks,\n                dayCount: rangeInfo.allDay\n            }\n        },\n        api: {\n            coord: function (data, clamp) {\n                return coordSys.dataToPoint(data, clamp);\n            }\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ITEM_STYLE_NORMAL_PATH = ['itemStyle'];\nvar ITEM_STYLE_EMPHASIS_PATH = ['emphasis', 'itemStyle'];\nvar LABEL_NORMAL = ['label'];\nvar LABEL_EMPHASIS = ['emphasis', 'label'];\n// Use prefix to avoid index to be the same as el.name,\n// which will cause weird udpate animation.\nvar GROUP_DIFF_PREFIX = 'e\\0\\0';\n\n/**\n * To reduce total package size of each coordinate systems, the modules `prepareCustom`\n * of each coordinate systems are not required by each coordinate systems directly, but\n * required by the module `custom`.\n *\n * prepareInfoForCustomSeries {Function}: optional\n *     @return {Object} {coordSys: {...}, api: {\n *         coord: function (data, clamp) {}, // return point in global.\n *         size: function (dataSize, dataItem) {} // return size of each axis in coordSys.\n *     }}\n */\nvar prepareCustoms = {\n    cartesian2d: prepareCartesian2d,\n    geo: prepareGeo,\n    singleAxis: prepareSingleAxis,\n    polar: preparePolar,\n    calendar: prepareCalendar\n};\n\n\n// ------\n// Model\n// ------\n\nSeriesModel.extend({\n\n    type: 'series.custom',\n\n    dependencies: ['grid', 'polar', 'geo', 'singleAxis', 'calendar'],\n\n    defaultOption: {\n        coordinateSystem: 'cartesian2d', // Can be set as 'none'\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        useTransform: true\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // Polar coordinate system\n        // polarIndex: 0,\n\n        // Geo coordinate system\n        // geoIndex: 0,\n\n        // label: {}\n        // itemStyle: {}\n    },\n\n    /**\n     * @override\n     */\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    /**\n     * @override\n     */\n    getDataParams: function (dataIndex, dataType, el) {\n        var params = SeriesModel.prototype.getDataParams.apply(this, arguments);\n        el && (params.info = el.info);\n        return params;\n    }\n});\n\n// -----\n// View\n// -----\n\nChart.extend({\n\n    type: 'custom',\n\n    /**\n     * @private\n     * @type {module:echarts/data/List}\n     */\n    _data: null,\n\n    /**\n     * @override\n     */\n    render: function (customSeries, ecModel, api, payload) {\n        var oldData = this._data;\n        var data = customSeries.getData();\n        var group = this.group;\n        var renderItem = makeRenderItem(customSeries, data, ecModel, api);\n\n        // By default, merge mode is applied. In most cases, custom series is\n        // used in the scenario that data amount is not large but graphic elements\n        // is complicated, where merge mode is probably necessary for optimization.\n        // For example, reuse graphic elements and only update the transform when\n        // roam or data zoom according to `actionType`.\n        data.diff(oldData)\n            .add(function (newIdx) {\n                createOrUpdate$1(\n                    null, newIdx, renderItem(newIdx, payload), customSeries, group, data\n                );\n            })\n            .update(function (newIdx, oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n                createOrUpdate$1(\n                    el, newIdx, renderItem(newIdx, payload), customSeries, group, data\n                );\n            })\n            .remove(function (oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n                el && group.remove(el);\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    incrementalPrepareRender: function (customSeries, ecModel, api) {\n        this.group.removeAll();\n        this._data = null;\n    },\n\n    incrementalRender: function (params, customSeries, ecModel, api, payload) {\n        var data = customSeries.getData();\n        var renderItem = makeRenderItem(customSeries, data, ecModel, api);\n        function setIncrementalAndHoverLayer(el) {\n            if (!el.isGroup) {\n                el.incremental = true;\n                el.useHoverLayer = true;\n            }\n        }\n        for (var idx = params.start; idx < params.end; idx++) {\n            var el = createOrUpdate$1(null, idx, renderItem(idx, payload), customSeries, this.group, data);\n            el.traverse(setIncrementalAndHoverLayer);\n        }\n    },\n\n    /**\n     * @override\n     */\n    dispose: noop,\n\n    /**\n     * @override\n     */\n    filterForExposedEvent: function (eventType, query, targetEl, packedEvent) {\n        var elementName = query.element;\n        if (elementName == null || targetEl.name === elementName) {\n            return true;\n        }\n\n        // Enable to give a name on a group made by `renderItem`, and listen\n        // events that triggerd by its descendents.\n        while ((targetEl = targetEl.parent) && targetEl !== this.group) {\n            if (targetEl.name === elementName) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n});\n\n\nfunction createEl(elOption) {\n    var graphicType = elOption.type;\n    var el;\n\n    if (graphicType === 'path') {\n        var shape = elOption.shape;\n        // Using pathRect brings convenience to users sacle svg path.\n        var pathRect = (shape.width != null && shape.height != null)\n            ? {\n                x: shape.x || 0,\n                y: shape.y || 0,\n                width: shape.width,\n                height: shape.height\n            }\n            : null;\n        var pathData = getPathData(shape);\n        // Path is also used for icon, so layout 'center' by default.\n        el = makePath(pathData, null, pathRect, shape.layout || 'center');\n        el.__customPathData = pathData;\n    }\n    else if (graphicType === 'image') {\n        el = new ZImage({});\n        el.__customImagePath = elOption.style.image;\n    }\n    else if (graphicType === 'text') {\n        el = new Text({});\n        el.__customText = elOption.style.text;\n    }\n    else {\n        var Clz = graphic[graphicType.charAt(0).toUpperCase() + graphicType.slice(1)];\n\n        if (__DEV__) {\n            assert$1(Clz, 'graphic type \"' + graphicType + '\" can not be found.');\n        }\n\n        el = new Clz();\n    }\n\n    el.__customGraphicType = graphicType;\n    el.name = elOption.name;\n\n    return el;\n}\n\nfunction updateEl(el, dataIndex, elOption, animatableModel, data, isInit, isRoot) {\n    var transitionProps = {};\n    var elOptionStyle = elOption.style || {};\n\n    elOption.shape && (transitionProps.shape = clone(elOption.shape));\n    elOption.position && (transitionProps.position = elOption.position.slice());\n    elOption.scale && (transitionProps.scale = elOption.scale.slice());\n    elOption.origin && (transitionProps.origin = elOption.origin.slice());\n    elOption.rotation && (transitionProps.rotation = elOption.rotation);\n\n    if (el.type === 'image' && elOption.style) {\n        var targetStyle = transitionProps.style = {};\n        each$1(['x', 'y', 'width', 'height'], function (prop) {\n            prepareStyleTransition(prop, targetStyle, elOptionStyle, el.style, isInit);\n        });\n    }\n\n    if (el.type === 'text' && elOption.style) {\n        var targetStyle = transitionProps.style = {};\n        each$1(['x', 'y'], function (prop) {\n            prepareStyleTransition(prop, targetStyle, elOptionStyle, el.style, isInit);\n        });\n        // Compatible with previous: both support\n        // textFill and fill, textStroke and stroke in 'text' element.\n        !elOptionStyle.hasOwnProperty('textFill') && elOptionStyle.fill && (\n            elOptionStyle.textFill = elOptionStyle.fill\n        );\n        !elOptionStyle.hasOwnProperty('textStroke') && elOptionStyle.stroke && (\n            elOptionStyle.textStroke = elOptionStyle.stroke\n        );\n    }\n\n    if (el.type !== 'group') {\n        el.useStyle(elOptionStyle);\n\n        // Init animation.\n        if (isInit) {\n            el.style.opacity = 0;\n            var targetOpacity = elOptionStyle.opacity;\n            targetOpacity == null && (targetOpacity = 1);\n            initProps(el, {style: {opacity: targetOpacity}}, animatableModel, dataIndex);\n        }\n    }\n\n    if (isInit) {\n        el.attr(transitionProps);\n    }\n    else {\n        updateProps(el, transitionProps, animatableModel, dataIndex);\n    }\n\n    // Merge by default.\n    // z2 must not be null/undefined, otherwise sort error may occur.\n    elOption.hasOwnProperty('z2') && el.attr('z2', elOption.z2 || 0);\n    elOption.hasOwnProperty('silent') && el.attr('silent', elOption.silent);\n    elOption.hasOwnProperty('invisible') && el.attr('invisible', elOption.invisible);\n    elOption.hasOwnProperty('ignore') && el.attr('ignore', elOption.ignore);\n    // `elOption.info` enables user to mount some info on\n    // elements and use them in event handlers.\n    // Update them only when user specified, otherwise, remain.\n    elOption.hasOwnProperty('info') && el.attr('info', elOption.info);\n\n    // If `elOption.styleEmphasis` is `false`, remove hover style. The\n    // logic is ensured by `graphicUtil.setElementHoverStyle`.\n    var styleEmphasis = elOption.styleEmphasis;\n    var disableStyleEmphasis = styleEmphasis === false;\n    if (!(\n        // Try to escapse setting hover style for performance.\n        (el.__cusHasEmphStl && styleEmphasis == null)\n        || (!el.__cusHasEmphStl && disableStyleEmphasis)\n    )) {\n        // Should not use graphicUtil.setHoverStyle, since the styleEmphasis\n        // should not be share by group and its descendants.\n        setElementHoverStyle(el, styleEmphasis);\n        el.__cusHasEmphStl = !disableStyleEmphasis;\n    }\n    isRoot && setAsHoverStyleTrigger(el, !disableStyleEmphasis);\n}\n\nfunction prepareStyleTransition(prop, targetStyle, elOptionStyle, oldElStyle, isInit) {\n    if (elOptionStyle[prop] != null && !isInit) {\n        targetStyle[prop] = elOptionStyle[prop];\n        elOptionStyle[prop] = oldElStyle[prop];\n    }\n}\n\nfunction makeRenderItem(customSeries, data, ecModel, api) {\n    var renderItem = customSeries.get('renderItem');\n    var coordSys = customSeries.coordinateSystem;\n    var prepareResult = {};\n\n    if (coordSys) {\n        if (__DEV__) {\n            assert$1(renderItem, 'series.render is required.');\n            assert$1(\n                coordSys.prepareCustoms || prepareCustoms[coordSys.type],\n                'This coordSys does not support custom series.'\n            );\n        }\n\n        prepareResult = coordSys.prepareCustoms\n            ? coordSys.prepareCustoms()\n            : prepareCustoms[coordSys.type](coordSys);\n    }\n\n    var userAPI = defaults({\n        getWidth: api.getWidth,\n        getHeight: api.getHeight,\n        getZr: api.getZr,\n        getDevicePixelRatio: api.getDevicePixelRatio,\n        value: value,\n        style: style,\n        styleEmphasis: styleEmphasis,\n        visual: visual,\n        barLayout: barLayout,\n        currentSeriesIndices: currentSeriesIndices,\n        font: font\n    }, prepareResult.api || {});\n\n    var userParams = {\n        // The life cycle of context: current round of rendering.\n        // The global life cycle is probably not necessary, because\n        // user can store global status by themselves.\n        context: {},\n        seriesId: customSeries.id,\n        seriesName: customSeries.name,\n        seriesIndex: customSeries.seriesIndex,\n        coordSys: prepareResult.coordSys,\n        dataInsideLength: data.count(),\n        encode: wrapEncodeDef(customSeries.getData())\n    };\n\n    // Do not support call `api` asynchronously without dataIndexInside input.\n    var currDataIndexInside;\n    var currDirty = true;\n    var currItemModel;\n    var currLabelNormalModel;\n    var currLabelEmphasisModel;\n    var currVisualColor;\n\n    return function (dataIndexInside, payload) {\n        currDataIndexInside = dataIndexInside;\n        currDirty = true;\n\n        return renderItem && renderItem(\n            defaults({\n                dataIndexInside: dataIndexInside,\n                dataIndex: data.getRawIndex(dataIndexInside),\n                // Can be used for optimization when zoom or roam.\n                actionType: payload ? payload.type : null\n            }, userParams),\n            userAPI\n        );\n    };\n\n    // Do not update cache until api called.\n    function updateCache(dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        if (currDirty) {\n            currItemModel = data.getItemModel(dataIndexInside);\n            currLabelNormalModel = currItemModel.getModel(LABEL_NORMAL);\n            currLabelEmphasisModel = currItemModel.getModel(LABEL_EMPHASIS);\n            currVisualColor = data.getItemVisual(dataIndexInside, 'color');\n\n            currDirty = false;\n        }\n    }\n\n    /**\n     * @public\n     * @param {number|string} dim\n     * @param {number} [dataIndexInside=currDataIndexInside]\n     * @return {number|string} value\n     */\n    function value(dim, dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        return data.get(data.getDimension(dim || 0), dataIndexInside);\n    }\n\n    /**\n     * By default, `visual` is applied to style (to support visualMap).\n     * `visual.color` is applied at `fill`. If user want apply visual.color on `stroke`,\n     * it can be implemented as:\n     * `api.style({stroke: api.visual('color'), fill: null})`;\n     * @public\n     * @param {Object} [extra]\n     * @param {number} [dataIndexInside=currDataIndexInside]\n     */\n    function style(extra, dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        updateCache(dataIndexInside);\n\n        var itemStyle = currItemModel.getModel(ITEM_STYLE_NORMAL_PATH).getItemStyle();\n\n        currVisualColor != null && (itemStyle.fill = currVisualColor);\n        var opacity = data.getItemVisual(dataIndexInside, 'opacity');\n        opacity != null && (itemStyle.opacity = opacity);\n\n        setTextStyle(itemStyle, currLabelNormalModel, null, {\n            autoColor: currVisualColor,\n            isRectText: true\n        });\n\n        itemStyle.text = currLabelNormalModel.getShallow('show')\n            ? retrieve2(\n                customSeries.getFormattedLabel(dataIndexInside, 'normal'),\n                getDefaultLabel(data, dataIndexInside)\n            )\n            : null;\n\n        extra && extend(itemStyle, extra);\n        return itemStyle;\n    }\n\n    /**\n     * @public\n     * @param {Object} [extra]\n     * @param {number} [dataIndexInside=currDataIndexInside]\n     */\n    function styleEmphasis(extra, dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        updateCache(dataIndexInside);\n\n        var itemStyle = currItemModel.getModel(ITEM_STYLE_EMPHASIS_PATH).getItemStyle();\n\n        setTextStyle(itemStyle, currLabelEmphasisModel, null, {\n            isRectText: true\n        }, true);\n\n        itemStyle.text = currLabelEmphasisModel.getShallow('show')\n            ? retrieve3(\n                customSeries.getFormattedLabel(dataIndexInside, 'emphasis'),\n                customSeries.getFormattedLabel(dataIndexInside, 'normal'),\n                getDefaultLabel(data, dataIndexInside)\n            )\n            : null;\n\n        extra && extend(itemStyle, extra);\n        return itemStyle;\n    }\n\n    /**\n     * @public\n     * @param {string} visualType\n     * @param {number} [dataIndexInside=currDataIndexInside]\n     */\n    function visual(visualType, dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        return data.getItemVisual(dataIndexInside, visualType);\n    }\n\n    /**\n     * @public\n     * @param {number} opt.count Positive interger.\n     * @param {number} [opt.barWidth]\n     * @param {number} [opt.barMaxWidth]\n     * @param {number} [opt.barGap]\n     * @param {number} [opt.barCategoryGap]\n     * @return {Object} {width, offset, offsetCenter} is not support, return undefined.\n     */\n    function barLayout(opt) {\n        if (coordSys.getBaseAxis) {\n            var baseAxis = coordSys.getBaseAxis();\n            return getLayoutOnAxis(defaults({axis: baseAxis}, opt), api);\n        }\n    }\n\n    /**\n     * @public\n     * @return {Array.<number>}\n     */\n    function currentSeriesIndices() {\n        return ecModel.getCurrentSeriesIndices();\n    }\n\n    /**\n     * @public\n     * @param {Object} opt\n     * @param {string} [opt.fontStyle]\n     * @param {number} [opt.fontWeight]\n     * @param {number} [opt.fontSize]\n     * @param {string} [opt.fontFamily]\n     * @return {string} font string\n     */\n    function font(opt) {\n        return getFont(opt, ecModel);\n    }\n}\n\nfunction wrapEncodeDef(data) {\n    var encodeDef = {};\n    each$1(data.dimensions, function (dimName, dataDimIndex) {\n        var dimInfo = data.getDimensionInfo(dimName);\n        if (!dimInfo.isExtraCoord) {\n            var coordDim = dimInfo.coordDim;\n            var dataDims = encodeDef[coordDim] = encodeDef[coordDim] || [];\n            dataDims[dimInfo.coordDimIndex] = dataDimIndex;\n        }\n    });\n    return encodeDef;\n}\n\nfunction createOrUpdate$1(el, dataIndex, elOption, animatableModel, group, data) {\n    el = doCreateOrUpdate(el, dataIndex, elOption, animatableModel, group, data, true);\n    el && data.setItemGraphicEl(dataIndex, el);\n\n    return el;\n}\n\nfunction doCreateOrUpdate(el, dataIndex, elOption, animatableModel, group, data, isRoot) {\n\n    // [Rule]\n    // By default, follow merge mode.\n    //     (It probably brings benifit for performance in some cases of large data, where\n    //     user program can be optimized to that only updated props needed to be re-calculated,\n    //     or according to `actionType` some calculation can be skipped.)\n    // If `renderItem` returns `null`/`undefined`/`false`, remove the previous el if existing.\n    //     (It seems that violate the \"merge\" principle, but most of users probably intuitively\n    //     regard \"return;\" as \"show nothing element whatever\", so make a exception to meet the\n    //     most cases.)\n\n    var simplyRemove = !elOption; // `null`/`undefined`/`false`\n    elOption = elOption || {};\n    var elOptionType = elOption.type;\n    var elOptionShape = elOption.shape;\n    var elOptionStyle = elOption.style;\n\n    if (el && (\n        simplyRemove\n        // || elOption.$merge === false\n        // If `elOptionType` is `null`, follow the merge principle.\n        || (elOptionType != null\n            && elOptionType !== el.__customGraphicType\n        )\n        || (elOptionType === 'path'\n            && hasOwnPathData(elOptionShape) && getPathData(elOptionShape) !== el.__customPathData\n        )\n        || (elOptionType === 'image'\n            && hasOwn(elOptionStyle, 'image') && elOptionStyle.image !== el.__customImagePath\n        )\n        // FIXME test and remove this restriction?\n        || (elOptionType === 'text'\n            && hasOwn(elOptionShape, 'text') && elOptionStyle.text !== el.__customText\n        )\n    )) {\n        group.remove(el);\n        el = null;\n    }\n\n    // `elOption.type` is undefined when `renderItem` returns nothing.\n    if (simplyRemove) {\n        return;\n    }\n\n    var isInit = !el;\n    !el && (el = createEl(elOption));\n    updateEl(el, dataIndex, elOption, animatableModel, data, isInit, isRoot);\n\n    if (elOptionType === 'group') {\n        mergeChildren(el, dataIndex, elOption, animatableModel, data);\n    }\n\n    // Always add whatever already added to ensure sequence.\n    group.add(el);\n\n    return el;\n}\n\n// Usage:\n// (1) By default, `elOption.$mergeChildren` is `'byIndex'`, which indicates that\n//     the existing children will not be removed, and enables the feature that\n//     update some of the props of some of the children simply by construct\n//     the returned children of `renderItem` like:\n//     `var children = group.children = []; children[3] = {opacity: 0.5};`\n// (2) If `elOption.$mergeChildren` is `'byName'`, add/update/remove children\n//     by child.name. But that might be lower performance.\n// (3) If `elOption.$mergeChildren` is `false`, the existing children will be\n//     replaced totally.\n// (4) If `!elOption.children`, following the \"merge\" principle, nothing will happen.\n//\n// For implementation simpleness, do not provide a direct way to remove sinlge\n// child (otherwise the total indicies of the children array have to be modified).\n// User can remove a single child by set its `ignore` as `true` or replace\n// it by another element, where its `$merge` can be set as `true` if necessary.\nfunction mergeChildren(el, dataIndex, elOption, animatableModel, data) {\n    var newChildren = elOption.children;\n    var newLen = newChildren ? newChildren.length : 0;\n    var mergeChildren = elOption.$mergeChildren;\n    // `diffChildrenByName` has been deprecated.\n    var byName = mergeChildren === 'byName' || elOption.diffChildrenByName;\n    var notMerge = mergeChildren === false;\n\n    // For better performance on roam update, only enter if necessary.\n    if (!newLen && !byName && !notMerge) {\n        return;\n    }\n\n    if (byName) {\n        diffGroupChildren({\n            oldChildren: el.children() || [],\n            newChildren: newChildren || [],\n            dataIndex: dataIndex,\n            animatableModel: animatableModel,\n            group: el,\n            data: data\n        });\n        return;\n    }\n\n    notMerge && el.removeAll();\n\n    // Mapping children of a group simply by index, which\n    // might be better performance.\n    var index = 0;\n    for (; index < newLen; index++) {\n        newChildren[index] && doCreateOrUpdate(\n            el.childAt(index),\n            dataIndex,\n            newChildren[index],\n            animatableModel,\n            el,\n            data\n        );\n    }\n    if (__DEV__) {\n        assert$1(\n            !notMerge || el.childCount() === index,\n            'MUST NOT contain empty item in children array when `group.$mergeChildren` is `false`.'\n        );\n    }\n}\n\nfunction diffGroupChildren(context) {\n    (new DataDiffer(\n        context.oldChildren,\n        context.newChildren,\n        getKey,\n        getKey,\n        context\n    ))\n        .add(processAddUpdate)\n        .update(processAddUpdate)\n        .remove(processRemove)\n        .execute();\n}\n\nfunction getKey(item, idx) {\n    var name = item && item.name;\n    return name != null ? name : GROUP_DIFF_PREFIX + idx;\n}\n\nfunction processAddUpdate(newIndex, oldIndex) {\n    var context = this.context;\n    var childOption = newIndex != null ? context.newChildren[newIndex] : null;\n    var child = oldIndex != null ? context.oldChildren[oldIndex] : null;\n\n    doCreateOrUpdate(\n        child,\n        context.dataIndex,\n        childOption,\n        context.animatableModel,\n        context.group,\n        context.data\n    );\n}\n\nfunction processRemove(oldIndex) {\n    var context = this.context;\n    var child = context.oldChildren[oldIndex];\n    child && context.group.remove(child);\n}\n\nfunction getPathData(shape) {\n    // \"d\" follows the SVG convention.\n    return shape && (shape.pathData || shape.d);\n}\n\nfunction hasOwnPathData(shape) {\n    return shape && (shape.hasOwnProperty('pathData') || shape.hasOwnProperty('d'));\n}\n\nfunction hasOwn(host, prop) {\n    return host && host.hasOwnProperty(prop);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// -------------\n// Preprocessor\n// -------------\n\nregisterPreprocessor(function (option) {\n    var graphicOption = option.graphic;\n\n    // Convert\n    // {graphic: [{left: 10, type: 'circle'}, ...]}\n    // or\n    // {graphic: {left: 10, type: 'circle'}}\n    // to\n    // {graphic: [{elements: [{left: 10, type: 'circle'}, ...]}]}\n    if (isArray(graphicOption)) {\n        if (!graphicOption[0] || !graphicOption[0].elements) {\n            option.graphic = [{elements: graphicOption}];\n        }\n        else {\n            // Only one graphic instance can be instantiated. (We dont\n            // want that too many views are created in echarts._viewMap)\n            option.graphic = [option.graphic[0]];\n        }\n    }\n    else if (graphicOption && !graphicOption.elements) {\n        option.graphic = [{elements: [graphicOption]}];\n    }\n});\n\n// ------\n// Model\n// ------\n\nvar GraphicModel = extendComponentModel({\n\n    type: 'graphic',\n\n    defaultOption: {\n\n        // Extra properties for each elements:\n        //\n        // left/right/top/bottom: (like 12, '22%', 'center', default undefined)\n        //      If left/rigth is set, shape.x/shape.cx/position will not be used.\n        //      If top/bottom is set, shape.y/shape.cy/position will not be used.\n        //      This mechanism is useful when you want to position a group/element\n        //      against the right side or the center of this container.\n        //\n        // width/height: (can only be pixel value, default 0)\n        //      Only be used to specify contianer(group) size, if needed. And\n        //      can not be percentage value (like '33%'). See the reason in the\n        //      layout algorithm below.\n        //\n        // bounding: (enum: 'all' (default) | 'raw')\n        //      Specify how to calculate boundingRect when locating.\n        //      'all': Get uioned and transformed boundingRect\n        //          from both itself and its descendants.\n        //          This mode simplies confining a group of elements in the bounding\n        //          of their ancester container (e.g., using 'right: 0').\n        //      'raw': Only use the boundingRect of itself and before transformed.\n        //          This mode is similar to css behavior, which is useful when you\n        //          want an element to be able to overflow its container. (Consider\n        //          a rotated circle needs to be located in a corner.)\n        // info: custom info. enables user to mount some info on elements and use them\n        //      in event handlers. Update them only when user specified, otherwise, remain.\n\n        // Note: elements is always behind its ancestors in this elements array.\n        elements: [],\n        parentId: null\n    },\n\n    /**\n     * Save el options for the sake of the performance (only update modified graphics).\n     * The order is the same as those in option. (ancesters -> descendants)\n     *\n     * @private\n     * @type {Array.<Object>}\n     */\n    _elOptionsToUpdate: null,\n\n    /**\n     * @override\n     */\n    mergeOption: function (option) {\n        // Prevent default merge to elements\n        var elements = this.option.elements;\n        this.option.elements = null;\n\n        GraphicModel.superApply(this, 'mergeOption', arguments);\n\n        this.option.elements = elements;\n    },\n\n    /**\n     * @override\n     */\n    optionUpdated: function (newOption, isInit) {\n        var thisOption = this.option;\n        var newList = (isInit ? thisOption : newOption).elements;\n        var existList = thisOption.elements = isInit ? [] : thisOption.elements;\n\n        var flattenedList = [];\n        this._flatten(newList, flattenedList);\n\n        var mappingResult = mappingToExists(existList, flattenedList);\n        makeIdAndName(mappingResult);\n\n        // Clear elOptionsToUpdate\n        var elOptionsToUpdate = this._elOptionsToUpdate = [];\n\n        each$1(mappingResult, function (resultItem, index) {\n            var newElOption = resultItem.option;\n\n            if (__DEV__) {\n                assert$1(\n                    isObject$1(newElOption) || resultItem.exist,\n                    'Empty graphic option definition'\n                );\n            }\n\n            if (!newElOption) {\n                return;\n            }\n\n            elOptionsToUpdate.push(newElOption);\n\n            setKeyInfoToNewElOption(resultItem, newElOption);\n\n            mergeNewElOptionToExist(existList, index, newElOption);\n\n            setLayoutInfoToExist(existList[index], newElOption);\n\n        }, this);\n\n        // Clean\n        for (var i = existList.length - 1; i >= 0; i--) {\n            if (existList[i] == null) {\n                existList.splice(i, 1);\n            }\n            else {\n                // $action should be volatile, otherwise option gotten from\n                // `getOption` will contain unexpected $action.\n                delete existList[i].$action;\n            }\n        }\n    },\n\n    /**\n     * Convert\n     * [{\n     *  type: 'group',\n     *  id: 'xx',\n     *  children: [{type: 'circle'}, {type: 'polygon'}]\n     * }]\n     * to\n     * [\n     *  {type: 'group', id: 'xx'},\n     *  {type: 'circle', parentId: 'xx'},\n     *  {type: 'polygon', parentId: 'xx'}\n     * ]\n     *\n     * @private\n     * @param {Array.<Object>} optionList option list\n     * @param {Array.<Object>} result result of flatten\n     * @param {Object} parentOption parent option\n     */\n    _flatten: function (optionList, result, parentOption) {\n        each$1(optionList, function (option) {\n            if (!option) {\n                return;\n            }\n\n            if (parentOption) {\n                option.parentOption = parentOption;\n            }\n\n            result.push(option);\n\n            var children = option.children;\n            if (option.type === 'group' && children) {\n                this._flatten(children, result, option);\n            }\n            // Deleting for JSON output, and for not affecting group creation.\n            delete option.children;\n        }, this);\n    },\n\n    // FIXME\n    // Pass to view using payload? setOption has a payload?\n    useElOptionsToUpdate: function () {\n        var els = this._elOptionsToUpdate;\n        // Clear to avoid render duplicately when zooming.\n        this._elOptionsToUpdate = null;\n        return els;\n    }\n});\n\n// -----\n// View\n// -----\n\nextendComponentView({\n\n    type: 'graphic',\n\n    /**\n     * @override\n     */\n    init: function (ecModel, api) {\n\n        /**\n         * @private\n         * @type {module:zrender/core/util.HashMap}\n         */\n        this._elMap = createHashMap();\n\n        /**\n         * @private\n         * @type {module:echarts/graphic/GraphicModel}\n         */\n        this._lastGraphicModel;\n    },\n\n    /**\n     * @override\n     */\n    render: function (graphicModel, ecModel, api) {\n\n        // Having leveraged between use cases and algorithm complexity, a very\n        // simple layout mechanism is used:\n        // The size(width/height) can be determined by itself or its parent (not\n        // implemented yet), but can not by its children. (Top-down travel)\n        // The location(x/y) can be determined by the bounding rect of itself\n        // (can including its descendants or not) and the size of its parent.\n        // (Bottom-up travel)\n\n        // When `chart.clear()` or `chart.setOption({...}, true)` with the same id,\n        // view will be reused.\n        if (graphicModel !== this._lastGraphicModel) {\n            this._clear();\n        }\n        this._lastGraphicModel = graphicModel;\n\n        this._updateElements(graphicModel);\n        this._relocate(graphicModel, api);\n    },\n\n    /**\n     * Update graphic elements.\n     *\n     * @private\n     * @param {Object} graphicModel graphic model\n     */\n    _updateElements: function (graphicModel) {\n        var elOptionsToUpdate = graphicModel.useElOptionsToUpdate();\n\n        if (!elOptionsToUpdate) {\n            return;\n        }\n\n        var elMap = this._elMap;\n        var rootGroup = this.group;\n\n        // Top-down tranverse to assign graphic settings to each elements.\n        each$1(elOptionsToUpdate, function (elOption) {\n            var $action = elOption.$action;\n            var id = elOption.id;\n            var existEl = elMap.get(id);\n            var parentId = elOption.parentId;\n            var targetElParent = parentId != null ? elMap.get(parentId) : rootGroup;\n\n            var elOptionStyle = elOption.style;\n            if (elOption.type === 'text' && elOptionStyle) {\n                // In top/bottom mode, textVerticalAlign should not be used, which cause\n                // inaccurately locating.\n                if (elOption.hv && elOption.hv[1]) {\n                    elOptionStyle.textVerticalAlign = elOptionStyle.textBaseline = null;\n                }\n\n                // Compatible with previous setting: both support fill and textFill,\n                // stroke and textStroke.\n                !elOptionStyle.hasOwnProperty('textFill') && elOptionStyle.fill && (\n                    elOptionStyle.textFill = elOptionStyle.fill\n                );\n                !elOptionStyle.hasOwnProperty('textStroke') && elOptionStyle.stroke && (\n                    elOptionStyle.textStroke = elOptionStyle.stroke\n                );\n            }\n\n            // Remove unnecessary props to avoid potential problems.\n            var elOptionCleaned = getCleanedElOption(elOption);\n\n            // For simple, do not support parent change, otherwise reorder is needed.\n            if (__DEV__) {\n                existEl && assert$1(\n                    targetElParent === existEl.parent,\n                    'Changing parent is not supported.'\n                );\n            }\n\n            if (!$action || $action === 'merge') {\n                existEl\n                    ? existEl.attr(elOptionCleaned)\n                    : createEl$1(id, targetElParent, elOptionCleaned, elMap);\n            }\n            else if ($action === 'replace') {\n                removeEl(existEl, elMap);\n                createEl$1(id, targetElParent, elOptionCleaned, elMap);\n            }\n            else if ($action === 'remove') {\n                removeEl(existEl, elMap);\n            }\n\n            var el = elMap.get(id);\n            if (el) {\n                el.__ecGraphicWidth = elOption.width;\n                el.__ecGraphicHeight = elOption.height;\n                setEventData(el, graphicModel, elOption);\n            }\n        });\n    },\n\n    /**\n     * Locate graphic elements.\n     *\n     * @private\n     * @param {Object} graphicModel graphic model\n     * @param {module:echarts/ExtensionAPI} api extension API\n     */\n    _relocate: function (graphicModel, api) {\n        var elOptions = graphicModel.option.elements;\n        var rootGroup = this.group;\n        var elMap = this._elMap;\n\n        // Bottom-up tranvese all elements (consider ec resize) to locate elements.\n        for (var i = elOptions.length - 1; i >= 0; i--) {\n            var elOption = elOptions[i];\n            var el = elMap.get(elOption.id);\n\n            if (!el) {\n                continue;\n            }\n\n            var parentEl = el.parent;\n            var containerInfo = parentEl === rootGroup\n                ? {\n                    width: api.getWidth(),\n                    height: api.getHeight()\n                }\n                : { // Like 'position:absolut' in css, default 0.\n                    width: parentEl.__ecGraphicWidth || 0,\n                    height: parentEl.__ecGraphicHeight || 0\n                };\n\n            positionElement(\n                el, elOption, containerInfo, null,\n                {hv: elOption.hv, boundingMode: elOption.bounding}\n            );\n        }\n    },\n\n    /**\n     * Clear all elements.\n     *\n     * @private\n     */\n    _clear: function () {\n        var elMap = this._elMap;\n        elMap.each(function (el) {\n            removeEl(el, elMap);\n        });\n        this._elMap = createHashMap();\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._clear();\n    }\n});\n\nfunction createEl$1(id, targetElParent, elOption, elMap) {\n    var graphicType = elOption.type;\n\n    if (__DEV__) {\n        assert$1(graphicType, 'graphic type MUST be set');\n    }\n\n    var Clz = graphic[graphicType.charAt(0).toUpperCase() + graphicType.slice(1)];\n\n    if (__DEV__) {\n        assert$1(Clz, 'graphic type can not be found');\n    }\n\n    var el = new Clz(elOption);\n    targetElParent.add(el);\n    elMap.set(id, el);\n    el.__ecGraphicId = id;\n}\n\nfunction removeEl(existEl, elMap) {\n    var existElParent = existEl && existEl.parent;\n    if (existElParent) {\n        existEl.type === 'group' && existEl.traverse(function (el) {\n            removeEl(el, elMap);\n        });\n        elMap.removeKey(existEl.__ecGraphicId);\n        existElParent.remove(existEl);\n    }\n}\n\n// Remove unnecessary props to avoid potential problems.\nfunction getCleanedElOption(elOption) {\n    elOption = extend({}, elOption);\n    each$1(\n        ['id', 'parentId', '$action', 'hv', 'bounding'].concat(LOCATION_PARAMS),\n        function (name) {\n            delete elOption[name];\n        }\n    );\n    return elOption;\n}\n\nfunction isSetLoc(obj, props) {\n    var isSet;\n    each$1(props, function (prop) {\n        obj[prop] != null && obj[prop] !== 'auto' && (isSet = true);\n    });\n    return isSet;\n}\n\nfunction setKeyInfoToNewElOption(resultItem, newElOption) {\n    var existElOption = resultItem.exist;\n\n    // Set id and type after id assigned.\n    newElOption.id = resultItem.keyInfo.id;\n    !newElOption.type && existElOption && (newElOption.type = existElOption.type);\n\n    // Set parent id if not specified\n    if (newElOption.parentId == null) {\n        var newElParentOption = newElOption.parentOption;\n        if (newElParentOption) {\n            newElOption.parentId = newElParentOption.id;\n        }\n        else if (existElOption) {\n            newElOption.parentId = existElOption.parentId;\n        }\n    }\n\n    // Clear\n    newElOption.parentOption = null;\n}\n\nfunction mergeNewElOptionToExist(existList, index, newElOption) {\n    // Update existing options, for `getOption` feature.\n    var newElOptCopy = extend({}, newElOption);\n    var existElOption = existList[index];\n\n    var $action = newElOption.$action || 'merge';\n    if ($action === 'merge') {\n        if (existElOption) {\n\n            if (__DEV__) {\n                var newType = newElOption.type;\n                assert$1(\n                    !newType || existElOption.type === newType,\n                    'Please set $action: \"replace\" to change `type`'\n                );\n            }\n\n            // We can ensure that newElOptCopy and existElOption are not\n            // the same object, so `merge` will not change newElOptCopy.\n            merge(existElOption, newElOptCopy, true);\n            // Rigid body, use ignoreSize.\n            mergeLayoutParam(existElOption, newElOptCopy, {ignoreSize: true});\n            // Will be used in render.\n            copyLayoutParams(newElOption, existElOption);\n        }\n        else {\n            existList[index] = newElOptCopy;\n        }\n    }\n    else if ($action === 'replace') {\n        existList[index] = newElOptCopy;\n    }\n    else if ($action === 'remove') {\n        // null will be cleaned later.\n        existElOption && (existList[index] = null);\n    }\n}\n\nfunction setLayoutInfoToExist(existItem, newElOption) {\n    if (!existItem) {\n        return;\n    }\n    existItem.hv = newElOption.hv = [\n        // Rigid body, dont care `width`.\n        isSetLoc(newElOption, ['left', 'right']),\n        // Rigid body, dont care `height`.\n        isSetLoc(newElOption, ['top', 'bottom'])\n    ];\n    // Give default group size. Otherwise layout error may occur.\n    if (existItem.type === 'group') {\n        existItem.width == null && (existItem.width = newElOption.width = 0);\n        existItem.height == null && (existItem.height = newElOption.height = 0);\n    }\n}\n\nfunction setEventData(el, graphicModel, elOption) {\n    var eventData = el.eventData;\n    // Simple optimize for large amount of elements that no need event.\n    if (!el.silent && !el.ignore && !eventData) {\n        eventData = el.eventData = {\n            componentType: 'graphic',\n            componentIndex: graphicModel.componentIndex,\n            name: el.name\n        };\n    }\n\n    // `elOption.info` enables user to mount some info on\n    // elements and use them in event handlers.\n    if (eventData) {\n        eventData.info = el.info;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar LegendModel = extendComponentModel({\n\n    type: 'legend.plain',\n\n    dependencies: ['series'],\n\n    layoutMode: {\n        type: 'box',\n        // legend.width/height are maxWidth/maxHeight actually,\n        // whereas realy width/height is calculated by its content.\n        // (Setting {left: 10, right: 10} does not make sense).\n        // So consider the case:\n        // `setOption({legend: {left: 10});`\n        // then `setOption({legend: {right: 10});`\n        // The previous `left` should be cleared by setting `ignoreSize`.\n        ignoreSize: true\n    },\n\n    init: function (option, parentModel, ecModel) {\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        option.selected = option.selected || {};\n    },\n\n    mergeOption: function (option) {\n        LegendModel.superCall(this, 'mergeOption', option);\n    },\n\n    optionUpdated: function () {\n        this._updateData(this.ecModel);\n\n        var legendData = this._data;\n\n        // If selectedMode is single, try to select one\n        if (legendData[0] && this.get('selectedMode') === 'single') {\n            var hasSelected = false;\n            // If has any selected in option.selected\n            for (var i = 0; i < legendData.length; i++) {\n                var name = legendData[i].get('name');\n                if (this.isSelected(name)) {\n                    // Force to unselect others\n                    this.select(name);\n                    hasSelected = true;\n                    break;\n                }\n            }\n            // Try select the first if selectedMode is single\n            !hasSelected && this.select(legendData[0].get('name'));\n        }\n    },\n\n    _updateData: function (ecModel) {\n        var potentialData = [];\n        var availableNames = [];\n\n        ecModel.eachRawSeries(function (seriesModel) {\n            var seriesName = seriesModel.name;\n            availableNames.push(seriesName);\n            var isPotential;\n\n            if (seriesModel.legendDataProvider) {\n                var data = seriesModel.legendDataProvider();\n                var names = data.mapArray(data.getName);\n\n                if (!ecModel.isSeriesFiltered(seriesModel)) {\n                    availableNames = availableNames.concat(names);\n                }\n\n                if (names.length) {\n                    potentialData = potentialData.concat(names);\n                }\n                else {\n                    isPotential = true;\n                }\n            }\n            else {\n                isPotential = true;\n            }\n\n            if (isPotential && isNameSpecified(seriesModel)) {\n                potentialData.push(seriesModel.name);\n            }\n        });\n\n        /**\n         * @type {Array.<string>}\n         * @private\n         */\n        this._availableNames = availableNames;\n\n        // If legend.data not specified in option, use availableNames as data,\n        // which is convinient for user preparing option.\n        var rawData = this.get('data') || potentialData;\n\n        var legendData = map(rawData, function (dataItem) {\n            // Can be string or number\n            if (typeof dataItem === 'string' || typeof dataItem === 'number') {\n                dataItem = {\n                    name: dataItem\n                };\n            }\n            return new Model(dataItem, this, this.ecModel);\n        }, this);\n\n        /**\n         * @type {Array.<module:echarts/model/Model>}\n         * @private\n         */\n        this._data = legendData;\n    },\n\n    /**\n     * @return {Array.<module:echarts/model/Model>}\n     */\n    getData: function () {\n        return this._data;\n    },\n\n    /**\n     * @param {string} name\n     */\n    select: function (name) {\n        var selected = this.option.selected;\n        var selectedMode = this.get('selectedMode');\n        if (selectedMode === 'single') {\n            var data = this._data;\n            each$1(data, function (dataItem) {\n                selected[dataItem.get('name')] = false;\n            });\n        }\n        selected[name] = true;\n    },\n\n    /**\n     * @param {string} name\n     */\n    unSelect: function (name) {\n        if (this.get('selectedMode') !== 'single') {\n            this.option.selected[name] = false;\n        }\n    },\n\n    /**\n     * @param {string} name\n     */\n    toggleSelected: function (name) {\n        var selected = this.option.selected;\n        // Default is true\n        if (!selected.hasOwnProperty(name)) {\n            selected[name] = true;\n        }\n        this[selected[name] ? 'unSelect' : 'select'](name);\n    },\n\n    /**\n     * @param {string} name\n     */\n    isSelected: function (name) {\n        var selected = this.option.selected;\n        return !(selected.hasOwnProperty(name) && !selected[name])\n            && indexOf(this._availableNames, name) >= 0;\n    },\n\n    defaultOption: {\n        // 一级层叠\n        zlevel: 0,\n        // 二级层叠\n        z: 4,\n        show: true,\n\n        // 布局方式，默认为水平布局，可选为：\n        // 'horizontal' | 'vertical'\n        orient: 'horizontal',\n\n        left: 'center',\n        // right: 'center',\n\n        top: 0,\n        // bottom: null,\n\n        // 水平对齐\n        // 'auto' | 'left' | 'right'\n        // 默认为 'auto', 根据 x 的位置判断是左对齐还是右对齐\n        align: 'auto',\n\n        backgroundColor: 'rgba(0,0,0,0)',\n        // 图例边框颜色\n        borderColor: '#ccc',\n        borderRadius: 0,\n        // 图例边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n        // 图例内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n        // 各个item之间的间隔，单位px，默认为10，\n        // 横向布局时为水平间隔，纵向布局时为纵向间隔\n        itemGap: 10,\n        // 图例图形宽度\n        itemWidth: 25,\n        // 图例图形高度\n        itemHeight: 14,\n\n        // 图例关闭时候的颜色\n        inactiveColor: '#ccc',\n\n        textStyle: {\n            // 图例文字颜色\n            color: '#333'\n        },\n        // formatter: '',\n        // 选择模式，默认开启图例开关\n        selectedMode: true,\n        // 配置默认选中状态，可配合LEGEND.SELECTED事件做动态数据载入\n        // selected: null,\n        // 图例内容（详见legend.data，数组中每一项代表一个item\n        // data: [],\n\n        // Tooltip 相关配置\n        tooltip: {\n            show: false\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction legendSelectActionHandler(methodName, payload, ecModel) {\n    var selectedMap = {};\n    var isToggleSelect = methodName === 'toggleSelected';\n    var isSelected;\n    // Update all legend components\n    ecModel.eachComponent('legend', function (legendModel) {\n        if (isToggleSelect && isSelected != null) {\n            // Force other legend has same selected status\n            // Or the first is toggled to true and other are toggled to false\n            // In the case one legend has some item unSelected in option. And if other legend\n            // doesn't has the item, they will assume it is selected.\n            legendModel[isSelected ? 'select' : 'unSelect'](payload.name);\n        }\n        else {\n            legendModel[methodName](payload.name);\n            isSelected = legendModel.isSelected(payload.name);\n        }\n        var legendData = legendModel.getData();\n        each$1(legendData, function (model) {\n            var name = model.get('name');\n            // Wrap element\n            if (name === '\\n' || name === '') {\n                return;\n            }\n            var isItemSelected = legendModel.isSelected(name);\n            if (selectedMap.hasOwnProperty(name)) {\n                // Unselected if any legend is unselected\n                selectedMap[name] = selectedMap[name] && isItemSelected;\n            }\n            else {\n                selectedMap[name] = isItemSelected;\n            }\n        });\n    });\n    // Return the event explicitly\n    return {\n        name: payload.name,\n        selected: selectedMap\n    };\n}\n/**\n * @event legendToggleSelect\n * @type {Object}\n * @property {string} type 'legendToggleSelect'\n * @property {string} [from]\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendToggleSelect', 'legendselectchanged',\n    curry(legendSelectActionHandler, 'toggleSelected')\n);\n\n/**\n * @event legendSelect\n * @type {Object}\n * @property {string} type 'legendSelect'\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendSelect', 'legendselected',\n    curry(legendSelectActionHandler, 'select')\n);\n\n/**\n * @event legendUnSelect\n * @type {Object}\n * @property {string} type 'legendUnSelect'\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendUnSelect', 'legendunselected',\n    curry(legendSelectActionHandler, 'unSelect')\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Layout list like component.\n * It will box layout each items in group of component and then position the whole group in the viewport\n * @param {module:zrender/group/Group} group\n * @param {module:echarts/model/Component} componentModel\n * @param {module:echarts/ExtensionAPI}\n */\nfunction layout$3(group, componentModel, api) {\n    var boxLayoutParams = componentModel.getBoxLayoutParams();\n    var padding = componentModel.get('padding');\n    var viewportSize = {width: api.getWidth(), height: api.getHeight()};\n\n    var rect = getLayoutRect(\n        boxLayoutParams,\n        viewportSize,\n        padding\n    );\n\n    box(\n        componentModel.get('orient'),\n        group,\n        componentModel.get('itemGap'),\n        rect.width,\n        rect.height\n    );\n\n    positionElement(\n        group,\n        boxLayoutParams,\n        viewportSize,\n        padding\n    );\n}\n\nfunction makeBackground(rect, componentModel) {\n    var padding = normalizeCssArray$1(\n        componentModel.get('padding')\n    );\n    var style = componentModel.getItemStyle(['color', 'opacity']);\n    style.fill = componentModel.get('backgroundColor');\n    var rect = new Rect({\n        shape: {\n            x: rect.x - padding[3],\n            y: rect.y - padding[0],\n            width: rect.width + padding[1] + padding[3],\n            height: rect.height + padding[0] + padding[2],\n            r: componentModel.get('borderRadius')\n        },\n        style: style,\n        silent: true,\n        z2: -1\n    });\n    // FIXME\n    // `subPixelOptimizeRect` may bring some gap between edge of viewpart\n    // and background rect when setting like `left: 0`, `top: 0`.\n    // graphic.subPixelOptimizeRect(rect);\n\n    return rect;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar curry$4 = curry;\nvar each$16 = each$1;\nvar Group$3 = Group;\n\nvar LegendView = extendComponentView({\n\n    type: 'legend.plain',\n\n    newlineDisabled: false,\n\n    /**\n     * @override\n     */\n    init: function () {\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._contentGroup = new Group$3());\n\n        /**\n         * @private\n         * @type {module:zrender/Element}\n         */\n        this._backgroundEl;\n\n        /**\n         * If first rendering, `contentGroup.position` is [0, 0], which\n         * does not make sense and may cause unexepcted animation if adopted.\n         * @private\n         * @type {boolean}\n         */\n        this._isFirstRender = true;\n    },\n\n    /**\n     * @protected\n     */\n    getContentGroup: function () {\n        return this._contentGroup;\n    },\n\n    /**\n     * @override\n     */\n    render: function (legendModel, ecModel, api) {\n        var isFirstRender = this._isFirstRender;\n        this._isFirstRender = false;\n\n        this.resetInner();\n\n        if (!legendModel.get('show', true)) {\n            return;\n        }\n\n        var itemAlign = legendModel.get('align');\n        if (!itemAlign || itemAlign === 'auto') {\n            itemAlign = (\n                legendModel.get('left') === 'right'\n                && legendModel.get('orient') === 'vertical'\n            ) ? 'right' : 'left';\n        }\n\n        this.renderInner(itemAlign, legendModel, ecModel, api);\n\n        // Perform layout.\n        var positionInfo = legendModel.getBoxLayoutParams();\n        var viewportSize = {width: api.getWidth(), height: api.getHeight()};\n        var padding = legendModel.get('padding');\n\n        var maxSize = getLayoutRect(positionInfo, viewportSize, padding);\n\n        var mainRect = this.layoutInner(legendModel, itemAlign, maxSize, isFirstRender);\n\n        // Place mainGroup, based on the calculated `mainRect`.\n        var layoutRect = getLayoutRect(\n            defaults({width: mainRect.width, height: mainRect.height}, positionInfo),\n            viewportSize,\n            padding\n        );\n        this.group.attr('position', [layoutRect.x - mainRect.x, layoutRect.y - mainRect.y]);\n\n        // Render background after group is layout.\n        this.group.add(\n            this._backgroundEl = makeBackground(mainRect, legendModel)\n        );\n    },\n\n    /**\n     * @protected\n     */\n    resetInner: function () {\n        this.getContentGroup().removeAll();\n        this._backgroundEl && this.group.remove(this._backgroundEl);\n    },\n\n    /**\n     * @protected\n     */\n    renderInner: function (itemAlign, legendModel, ecModel, api) {\n        var contentGroup = this.getContentGroup();\n        var legendDrawnMap = createHashMap();\n        var selectMode = legendModel.get('selectedMode');\n\n        var excludeSeriesId = [];\n        ecModel.eachRawSeries(function (seriesModel) {\n            !seriesModel.get('legendHoverLink') && excludeSeriesId.push(seriesModel.id);\n        });\n\n        each$16(legendModel.getData(), function (itemModel, dataIndex) {\n            var name = itemModel.get('name');\n\n            // Use empty string or \\n as a newline string\n            if (!this.newlineDisabled && (name === '' || name === '\\n')) {\n                contentGroup.add(new Group$3({\n                    newline: true\n                }));\n                return;\n            }\n\n            // Representitive series.\n            var seriesModel = ecModel.getSeriesByName(name)[0];\n\n            if (legendDrawnMap.get(name)) {\n                // Have been drawed\n                return;\n            }\n\n            // Series legend\n            if (seriesModel) {\n                var data = seriesModel.getData();\n                var color = data.getVisual('color');\n\n                // If color is a callback function\n                if (typeof color === 'function') {\n                    // Use the first data\n                    color = color(seriesModel.getDataParams(0));\n                }\n\n                // Using rect symbol defaultly\n                var legendSymbolType = data.getVisual('legendSymbol') || 'roundRect';\n                var symbolType = data.getVisual('symbol');\n\n                var itemGroup = this._createItem(\n                    name, dataIndex, itemModel, legendModel,\n                    legendSymbolType, symbolType,\n                    itemAlign, color,\n                    selectMode\n                );\n\n                itemGroup.on('click', curry$4(dispatchSelectAction, name, api))\n                    .on('mouseover', curry$4(dispatchHighlightAction, seriesModel.name, null, api, excludeSeriesId))\n                    .on('mouseout', curry$4(dispatchDownplayAction, seriesModel.name, null, api, excludeSeriesId));\n\n                legendDrawnMap.set(name, true);\n            }\n            else {\n                // Data legend of pie, funnel\n                ecModel.eachRawSeries(function (seriesModel) {\n                    // In case multiple series has same data name\n                    if (legendDrawnMap.get(name)) {\n                        return;\n                    }\n\n                    if (seriesModel.legendDataProvider) {\n                        var data = seriesModel.legendDataProvider();\n                        var idx = data.indexOfName(name);\n                        if (idx < 0) {\n                            return;\n                        }\n\n                        var color = data.getItemVisual(idx, 'color');\n\n                        var legendSymbolType = 'roundRect';\n\n                        var itemGroup = this._createItem(\n                            name, dataIndex, itemModel, legendModel,\n                            legendSymbolType, null,\n                            itemAlign, color,\n                            selectMode\n                        );\n\n                        // FIXME: consider different series has items with the same name.\n                        itemGroup.on('click', curry$4(dispatchSelectAction, name, api))\n                            // Should not specify the series name, consider legend controls\n                            // more than one pie series.\n                            .on('mouseover', curry$4(dispatchHighlightAction, null, name, api, excludeSeriesId))\n                            .on('mouseout', curry$4(dispatchDownplayAction, null, name, api, excludeSeriesId));\n\n                        legendDrawnMap.set(name, true);\n                    }\n\n                }, this);\n            }\n\n            if (__DEV__) {\n                if (!legendDrawnMap.get(name)) {\n                    console.warn(\n                        name + ' series not exists. Legend data should be same with series name or data name.'\n                    );\n                }\n            }\n        }, this);\n    },\n\n    _createItem: function (\n        name, dataIndex, itemModel, legendModel,\n        legendSymbolType, symbolType,\n        itemAlign, color, selectMode\n    ) {\n        var itemWidth = legendModel.get('itemWidth');\n        var itemHeight = legendModel.get('itemHeight');\n        var inactiveColor = legendModel.get('inactiveColor');\n        var symbolKeepAspect = legendModel.get('symbolKeepAspect');\n\n        var isSelected = legendModel.isSelected(name);\n        var itemGroup = new Group$3();\n\n        var textStyleModel = itemModel.getModel('textStyle');\n\n        var itemIcon = itemModel.get('icon');\n\n        var tooltipModel = itemModel.getModel('tooltip');\n        var legendGlobalTooltipModel = tooltipModel.parentModel;\n\n        // Use user given icon first\n        legendSymbolType = itemIcon || legendSymbolType;\n        itemGroup.add(createSymbol(\n            legendSymbolType,\n            0,\n            0,\n            itemWidth,\n            itemHeight,\n            isSelected ? color : inactiveColor,\n            // symbolKeepAspect default true for legend\n            symbolKeepAspect == null ? true : symbolKeepAspect\n        ));\n\n        // Compose symbols\n        // PENDING\n        if (!itemIcon && symbolType\n            // At least show one symbol, can't be all none\n            && ((symbolType !== legendSymbolType) || symbolType === 'none')\n        ) {\n            var size = itemHeight * 0.8;\n            if (symbolType === 'none') {\n                symbolType = 'circle';\n            }\n            // Put symbol in the center\n            itemGroup.add(createSymbol(\n                symbolType,\n                (itemWidth - size) / 2,\n                (itemHeight - size) / 2,\n                size,\n                size,\n                isSelected ? color : inactiveColor,\n                // symbolKeepAspect default true for legend\n                symbolKeepAspect == null ? true : symbolKeepAspect\n            ));\n        }\n\n        var textX = itemAlign === 'left' ? itemWidth + 5 : -5;\n        var textAlign = itemAlign;\n\n        var formatter = legendModel.get('formatter');\n        var content = name;\n        if (typeof formatter === 'string' && formatter) {\n            content = formatter.replace('{name}', name != null ? name : '');\n        }\n        else if (typeof formatter === 'function') {\n            content = formatter(name);\n        }\n\n        itemGroup.add(new Text({\n            style: setTextStyle({}, textStyleModel, {\n                text: content,\n                x: textX,\n                y: itemHeight / 2,\n                textFill: isSelected ? textStyleModel.getTextColor() : inactiveColor,\n                textAlign: textAlign,\n                textVerticalAlign: 'middle'\n            })\n        }));\n\n        // Add a invisible rect to increase the area of mouse hover\n        var hitRect = new Rect({\n            shape: itemGroup.getBoundingRect(),\n            invisible: true,\n            tooltip: tooltipModel.get('show') ? extend({\n                content: name,\n                // Defaul formatter\n                formatter: legendGlobalTooltipModel.get('formatter', true) || function () {\n                    return name;\n                },\n                formatterParams: {\n                    componentType: 'legend',\n                    legendIndex: legendModel.componentIndex,\n                    name: name,\n                    $vars: ['name']\n                }\n            }, tooltipModel.option) : null\n        });\n        itemGroup.add(hitRect);\n\n        itemGroup.eachChild(function (child) {\n            child.silent = true;\n        });\n\n        hitRect.silent = !selectMode;\n\n        this.getContentGroup().add(itemGroup);\n\n        setHoverStyle(itemGroup);\n\n        itemGroup.__legendDataIndex = dataIndex;\n\n        return itemGroup;\n    },\n\n    /**\n     * @protected\n     */\n    layoutInner: function (legendModel, itemAlign, maxSize) {\n        var contentGroup = this.getContentGroup();\n\n        // Place items in contentGroup.\n        box(\n            legendModel.get('orient'),\n            contentGroup,\n            legendModel.get('itemGap'),\n            maxSize.width,\n            maxSize.height\n        );\n\n        var contentRect = contentGroup.getBoundingRect();\n        contentGroup.attr('position', [-contentRect.x, -contentRect.y]);\n\n        return this.group.getBoundingRect();\n    },\n\n    /**\n     * @protected\n     */\n    remove: function () {\n        this.getContentGroup().removeAll();\n        this._isFirstRender = true;\n    }\n\n});\n\nfunction dispatchSelectAction(name, api) {\n    api.dispatchAction({\n        type: 'legendToggleSelect',\n        name: name\n    });\n}\n\nfunction dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId) {\n    // If element hover will move to a hoverLayer.\n    var el = api.getZr().storage.getDisplayList()[0];\n    if (!(el && el.useHoverLayer)) {\n        api.dispatchAction({\n            type: 'highlight',\n            seriesName: seriesName,\n            name: dataName,\n            excludeSeriesId: excludeSeriesId\n        });\n    }\n}\n\nfunction dispatchDownplayAction(seriesName, dataName, api, excludeSeriesId) {\n    // If element hover will move to a hoverLayer.\n    var el = api.getZr().storage.getDisplayList()[0];\n    if (!(el && el.useHoverLayer)) {\n        api.dispatchAction({\n            type: 'downplay',\n            seriesName: seriesName,\n            name: dataName,\n            excludeSeriesId: excludeSeriesId\n        });\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar legendFilter = function (ecModel) {\n\n    var legendModels = ecModel.findComponents({\n        mainType: 'legend'\n    });\n    if (legendModels && legendModels.length) {\n        ecModel.filterSeries(function (series) {\n            // If in any legend component the status is not selected.\n            // Because in legend series is assumed selected when it is not in the legend data.\n            for (var i = 0; i < legendModels.length; i++) {\n                if (!legendModels[i].isSelected(series.name)) {\n                    return false;\n                }\n            }\n            return true;\n        });\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n// Do not contain scrollable legend, for sake of file size.\n\n// Series Filter\nregisterProcessor(legendFilter);\n\nComponentModel.registerSubTypeDefaulter('legend', function () {\n    // Default 'plain' when no type specified.\n    return 'plain';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ScrollableLegendModel = LegendModel.extend({\n\n    type: 'legend.scroll',\n\n    /**\n     * @param {number} scrollDataIndex\n     */\n    setScrollDataIndex: function (scrollDataIndex) {\n        this.option.scrollDataIndex = scrollDataIndex;\n    },\n\n    defaultOption: {\n        scrollDataIndex: 0,\n        pageButtonItemGap: 5,\n        pageButtonGap: null,\n        pageButtonPosition: 'end', // 'start' or 'end'\n        pageFormatter: '{current}/{total}', // If null/undefined, do not show page.\n        pageIcons: {\n            horizontal: ['M0,0L12,-10L12,10z', 'M0,0L-12,-10L-12,10z'],\n            vertical: ['M0,0L20,0L10,-20z', 'M0,0L20,0L10,20z']\n        },\n        pageIconColor: '#2f4554',\n        pageIconInactiveColor: '#aaa',\n        pageIconSize: 15, // Can be [10, 3], which represents [width, height]\n        pageTextStyle: {\n            color: '#333'\n        },\n\n        animationDurationUpdate: 800\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel, extraOpt) {\n        var inputPositionParams = getLayoutParams(option);\n\n        ScrollableLegendModel.superCall(this, 'init', option, parentModel, ecModel, extraOpt);\n\n        mergeAndNormalizeLayoutParams(this, option, inputPositionParams);\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (option, extraOpt) {\n        ScrollableLegendModel.superCall(this, 'mergeOption', option, extraOpt);\n\n        mergeAndNormalizeLayoutParams(this, this.option, option);\n    },\n\n    getOrient: function () {\n        return this.get('orient') === 'vertical'\n            ? {index: 1, name: 'vertical'}\n            : {index: 0, name: 'horizontal'};\n    }\n\n});\n\n// Do not `ignoreSize` to enable setting {left: 10, right: 10}.\nfunction mergeAndNormalizeLayoutParams(legendModel, target, raw) {\n    var orient = legendModel.getOrient();\n    var ignoreSize = [1, 1];\n    ignoreSize[orient.index] = 0;\n    mergeLayoutParam(target, raw, {\n        type: 'box', ignoreSize: ignoreSize\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Separate legend and scrollable legend to reduce package size.\n */\n\nvar Group$4 = Group;\n\nvar WH$1 = ['width', 'height'];\nvar XY$1 = ['x', 'y'];\n\nvar ScrollableLegendView = LegendView.extend({\n\n    type: 'legend.scroll',\n\n    newlineDisabled: true,\n\n    init: function () {\n\n        ScrollableLegendView.superCall(this, 'init');\n\n        /**\n         * @private\n         * @type {number} For `scroll`.\n         */\n        this._currentIndex = 0;\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._containerGroup = new Group$4());\n        this._containerGroup.add(this.getContentGroup());\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._controllerGroup = new Group$4());\n\n        /**\n         *\n         * @private\n         */\n        this._showController;\n    },\n\n    /**\n     * @override\n     */\n    resetInner: function () {\n        ScrollableLegendView.superCall(this, 'resetInner');\n\n        this._controllerGroup.removeAll();\n        this._containerGroup.removeClipPath();\n        this._containerGroup.__rectSize = null;\n    },\n\n    /**\n     * @override\n     */\n    renderInner: function (itemAlign, legendModel, ecModel, api) {\n        var me = this;\n\n        // Render content items.\n        ScrollableLegendView.superCall(this, 'renderInner', itemAlign, legendModel, ecModel, api);\n\n        var controllerGroup = this._controllerGroup;\n\n        // FIXME: support be 'auto' adapt to size number text length,\n        // e.g., '3/12345' should not overlap with the control arrow button.\n        var pageIconSize = legendModel.get('pageIconSize', true);\n        if (!isArray(pageIconSize)) {\n            pageIconSize = [pageIconSize, pageIconSize];\n        }\n\n        createPageButton('pagePrev', 0);\n\n        var pageTextStyleModel = legendModel.getModel('pageTextStyle');\n        controllerGroup.add(new Text({\n            name: 'pageText',\n            style: {\n                textFill: pageTextStyleModel.getTextColor(),\n                font: pageTextStyleModel.getFont(),\n                textVerticalAlign: 'middle',\n                textAlign: 'center'\n            },\n            silent: true\n        }));\n\n        createPageButton('pageNext', 1);\n\n        function createPageButton(name, iconIdx) {\n            var pageDataIndexName = name + 'DataIndex';\n            var icon = createIcon(\n                legendModel.get('pageIcons', true)[legendModel.getOrient().name][iconIdx],\n                {\n                    // Buttons will be created in each render, so we do not need\n                    // to worry about avoiding using legendModel kept in scope.\n                    onclick: bind(\n                        me._pageGo, me, pageDataIndexName, legendModel, api\n                    )\n                },\n                {\n                    x: -pageIconSize[0] / 2,\n                    y: -pageIconSize[1] / 2,\n                    width: pageIconSize[0],\n                    height: pageIconSize[1]\n                }\n            );\n            icon.name = name;\n            controllerGroup.add(icon);\n        }\n    },\n\n    /**\n     * @override\n     */\n    layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender) {\n        var contentGroup = this.getContentGroup();\n        var containerGroup = this._containerGroup;\n        var controllerGroup = this._controllerGroup;\n\n        var orientIdx = legendModel.getOrient().index;\n        var wh = WH$1[orientIdx];\n        var hw = WH$1[1 - orientIdx];\n        var yx = XY$1[1 - orientIdx];\n\n        // Place items in contentGroup.\n        box(\n            legendModel.get('orient'),\n            contentGroup,\n            legendModel.get('itemGap'),\n            !orientIdx ? null : maxSize.width,\n            orientIdx ? null : maxSize.height\n        );\n\n        box(\n            // Buttons in controller are layout always horizontally.\n            'horizontal',\n            controllerGroup,\n            legendModel.get('pageButtonItemGap', true)\n        );\n\n        var contentRect = contentGroup.getBoundingRect();\n        var controllerRect = controllerGroup.getBoundingRect();\n        var showController = this._showController = contentRect[wh] > maxSize[wh];\n\n        var contentPos = [-contentRect.x, -contentRect.y];\n        // Remain contentPos when scroll animation perfroming.\n        // If first rendering, `contentGroup.position` is [0, 0], which\n        // does not make sense and may cause unexepcted animation if adopted.\n        if (!isFirstRender) {\n            contentPos[orientIdx] = contentGroup.position[orientIdx];\n        }\n\n        // Layout container group based on 0.\n        var containerPos = [0, 0];\n        var controllerPos = [-controllerRect.x, -controllerRect.y];\n        var pageButtonGap = retrieve2(\n            legendModel.get('pageButtonGap', true), legendModel.get('itemGap', true)\n        );\n\n        // Place containerGroup and controllerGroup and contentGroup.\n        if (showController) {\n            var pageButtonPosition = legendModel.get('pageButtonPosition', true);\n            // controller is on the right / bottom.\n            if (pageButtonPosition === 'end') {\n                controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh];\n            }\n            // controller is on the left / top.\n            else {\n                containerPos[orientIdx] += controllerRect[wh] + pageButtonGap;\n            }\n        }\n\n        // Always align controller to content as 'middle'.\n        controllerPos[1 - orientIdx] += contentRect[hw] / 2 - controllerRect[hw] / 2;\n\n        contentGroup.attr('position', contentPos);\n        containerGroup.attr('position', containerPos);\n        controllerGroup.attr('position', controllerPos);\n\n        // Calculate `mainRect` and set `clipPath`.\n        // mainRect should not be calculated by `this.group.getBoundingRect()`\n        // for sake of the overflow.\n        var mainRect = this.group.getBoundingRect();\n        var mainRect = {x: 0, y: 0};\n        // Consider content may be overflow (should be clipped).\n        mainRect[wh] = showController ? maxSize[wh] : contentRect[wh];\n        mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw]);\n        // `containerRect[yx] + containerPos[1 - orientIdx]` is 0.\n        mainRect[yx] = Math.min(0, controllerRect[yx] + controllerPos[1 - orientIdx]);\n\n        containerGroup.__rectSize = maxSize[wh];\n        if (showController) {\n            var clipShape = {x: 0, y: 0};\n            clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap, 0);\n            clipShape[hw] = mainRect[hw];\n            containerGroup.setClipPath(new Rect({shape: clipShape}));\n            // Consider content may be larger than container, container rect\n            // can not be obtained from `containerGroup.getBoundingRect()`.\n            containerGroup.__rectSize = clipShape[wh];\n        }\n        else {\n            // Do not remove or ignore controller. Keep them set as place holders.\n            controllerGroup.eachChild(function (child) {\n                child.attr({invisible: true, silent: true});\n            });\n        }\n\n        // Content translate animation.\n        var pageInfo = this._getPageInfo(legendModel);\n        pageInfo.pageIndex != null && updateProps(\n            contentGroup,\n            {position: pageInfo.contentPosition},\n            // When switch from \"show controller\" to \"not show controller\", view should be\n            // updated immediately without animation, otherwise causes weird efffect.\n            showController ? legendModel : false\n        );\n\n        this._updatePageInfoView(legendModel, pageInfo);\n\n        return mainRect;\n    },\n\n    _pageGo: function (to, legendModel, api) {\n        var scrollDataIndex = this._getPageInfo(legendModel)[to];\n\n        scrollDataIndex != null && api.dispatchAction({\n            type: 'legendScroll',\n            scrollDataIndex: scrollDataIndex,\n            legendId: legendModel.id\n        });\n    },\n\n    _updatePageInfoView: function (legendModel, pageInfo) {\n        var controllerGroup = this._controllerGroup;\n\n        each$1(['pagePrev', 'pageNext'], function (name) {\n            var canJump = pageInfo[name + 'DataIndex'] != null;\n            var icon = controllerGroup.childOfName(name);\n            if (icon) {\n                icon.setStyle(\n                    'fill',\n                    canJump\n                        ? legendModel.get('pageIconColor', true)\n                        : legendModel.get('pageIconInactiveColor', true)\n                );\n                icon.cursor = canJump ? 'pointer' : 'default';\n            }\n        });\n\n        var pageText = controllerGroup.childOfName('pageText');\n        var pageFormatter = legendModel.get('pageFormatter');\n        var pageIndex = pageInfo.pageIndex;\n        var current = pageIndex != null ? pageIndex + 1 : 0;\n        var total = pageInfo.pageCount;\n\n        pageText && pageFormatter && pageText.setStyle(\n            'text',\n            isString(pageFormatter)\n                ? pageFormatter.replace('{current}', current).replace('{total}', total)\n                : pageFormatter({current: current, total: total})\n        );\n    },\n\n    /**\n     * @param {module:echarts/model/Model} legendModel\n     * @return {Object} {\n     *  contentPosition: Array.<number>, null when data item not found.\n     *  pageIndex: number, null when data item not found.\n     *  pageCount: number, always be a number, can be 0.\n     *  pagePrevDataIndex: number, null when no next page.\n     *  pageNextDataIndex: number, null when no previous page.\n     * }\n     */\n    _getPageInfo: function (legendModel) {\n        var scrollDataIndex = legendModel.get('scrollDataIndex', true);\n        var contentGroup = this.getContentGroup();\n        var containerRectSize = this._containerGroup.__rectSize;\n        var orientIdx = legendModel.getOrient().index;\n        var wh = WH$1[orientIdx];\n        var xy = XY$1[orientIdx];\n        var targetItemIndex = this._findTargetItemIndex(scrollDataIndex);\n        var children = contentGroup.children();\n        var targetItem = children[targetItemIndex];\n        var itemCount = children.length;\n        var pCount = !itemCount ? 0 : 1;\n\n        var result = {\n            contentPosition: contentGroup.position.slice(),\n            pageCount: pCount,\n            pageIndex: pCount - 1,\n            pagePrevDataIndex: null,\n            pageNextDataIndex: null\n        };\n\n        if (!targetItem) {\n            return result;\n        }\n\n        var targetItemInfo = getItemInfo(targetItem);\n        result.contentPosition[orientIdx] = -targetItemInfo.s;\n\n        // Strategy:\n        // (1) Always align based on the left/top most item.\n        // (2) It is user-friendly that the last item shown in the\n        // current window is shown at the begining of next window.\n        // Otherwise if half of the last item is cut by the window,\n        // it will have no chance to display entirely.\n        // (3) Consider that item size probably be different, we\n        // have calculate pageIndex by size rather than item index,\n        // and we can not get page index directly by division.\n        // (4) The window is to narrow to contain more than\n        // one item, we should make sure that the page can be fliped.\n\n        for (var i = targetItemIndex + 1,\n            winStartItemInfo = targetItemInfo,\n            winEndItemInfo = targetItemInfo,\n            currItemInfo = null;\n            i <= itemCount;\n            ++i\n        ) {\n            currItemInfo = getItemInfo(children[i]);\n            if (\n                // Half of the last item is out of the window.\n                (!currItemInfo && winEndItemInfo.e > winStartItemInfo.s + containerRectSize)\n                // If the current item does not intersect with the window, the new page\n                // can be started at the current item or the last item.\n                || (currItemInfo && !intersect(currItemInfo, winStartItemInfo.s))\n            ) {\n                if (winEndItemInfo.i > winStartItemInfo.i) {\n                    winStartItemInfo = winEndItemInfo;\n                }\n                else { // e.g., when page size is smaller than item size.\n                    winStartItemInfo = currItemInfo;\n                }\n                if (winStartItemInfo) {\n                    if (result.pageNextDataIndex == null) {\n                        result.pageNextDataIndex = winStartItemInfo.i;\n                    }\n                    ++result.pageCount;\n                }\n            }\n            winEndItemInfo = currItemInfo;\n        }\n\n        for (var i = targetItemIndex - 1,\n            winStartItemInfo = targetItemInfo,\n            winEndItemInfo = targetItemInfo,\n            currItemInfo = null;\n            i >= -1;\n            --i\n        ) {\n            currItemInfo = getItemInfo(children[i]);\n            if (\n                // If the the end item does not intersect with the window started\n                // from the current item, a page can be settled.\n                (!currItemInfo || !intersect(winEndItemInfo, currItemInfo.s))\n                // e.g., when page size is smaller than item size.\n                && winStartItemInfo.i < winEndItemInfo.i\n            ) {\n                winEndItemInfo = winStartItemInfo;\n                if (result.pagePrevDataIndex == null) {\n                    result.pagePrevDataIndex = winStartItemInfo.i;\n                }\n                ++result.pageCount;\n                ++result.pageIndex;\n            }\n            winStartItemInfo = currItemInfo;\n        }\n\n        return result;\n\n        function getItemInfo(el) {\n            if (el) {\n                var itemRect = el.getBoundingRect();\n                var start = itemRect[xy] + el.position[orientIdx];\n                return {\n                    s: start,\n                    e: start + itemRect[wh],\n                    i: el.__legendDataIndex\n                };\n            }\n        }\n\n        function intersect(itemInfo, winStart) {\n            return itemInfo.e >= winStart && itemInfo.s <= winStart + containerRectSize;\n        }\n    },\n\n    _findTargetItemIndex: function (targetDataIndex) {\n        var index;\n        var contentGroup = this.getContentGroup();\n        if (this._showController) {\n            contentGroup.eachChild(function (child, idx) {\n                if (child.__legendDataIndex === targetDataIndex) {\n                    index = idx;\n                }\n            });\n        }\n        else {\n            index = 0;\n        }\n        return index;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @event legendScroll\n * @type {Object}\n * @property {string} type 'legendScroll'\n * @property {string} scrollDataIndex\n */\nregisterAction(\n    'legendScroll', 'legendscroll',\n    function (payload, ecModel) {\n        var scrollDataIndex = payload.scrollDataIndex;\n\n        scrollDataIndex != null && ecModel.eachComponent(\n            {mainType: 'legend', subType: 'scroll', query: payload},\n            function (legendModel) {\n                legendModel.setScrollDataIndex(scrollDataIndex);\n            }\n        );\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Legend component entry file8\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentModel({\n\n    type: 'tooltip',\n\n    dependencies: ['axisPointer'],\n\n    defaultOption: {\n        zlevel: 0,\n\n        z: 60,\n\n        show: true,\n\n        // tooltip主体内容\n        showContent: true,\n\n        // 'trigger' only works on coordinate system.\n        // 'item' | 'axis' | 'none'\n        trigger: 'item',\n\n        // 'click' | 'mousemove' | 'none'\n        triggerOn: 'mousemove|click',\n\n        alwaysShowContent: false,\n\n        displayMode: 'single', // 'single' | 'multipleByCoordSys'\n\n        renderMode: 'auto', // 'auto' | 'html' | 'richText'\n        // 'auto': use html by default, and use non-html if `document` is not defined\n        // 'html': use html for tooltip\n        // 'richText': use canvas, svg, and etc. for tooltip\n\n        // 位置 {Array} | {Function}\n        // position: null\n        // Consider triggered from axisPointer handle, verticalAlign should be 'middle'\n        // align: null,\n        // verticalAlign: null,\n\n        // 是否约束 content 在 viewRect 中。默认 false 是为了兼容以前版本。\n        confine: false,\n\n        // 内容格式器：{string}（Template） ¦ {Function}\n        // formatter: null\n\n        showDelay: 0,\n\n        // 隐藏延迟，单位ms\n        hideDelay: 100,\n\n        // 动画变换时间，单位s\n        transitionDuration: 0.4,\n\n        enterable: false,\n\n        // 提示背景颜色，默认为透明度为0.7的黑色\n        backgroundColor: 'rgba(50,50,50,0.7)',\n\n        // 提示边框颜色\n        borderColor: '#333',\n\n        // 提示边框圆角，单位px，默认为4\n        borderRadius: 4,\n\n        // 提示边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n\n        // 提示内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n\n        // Extra css text\n        extraCssText: '',\n\n        // 坐标轴指示器，坐标轴触发有效\n        axisPointer: {\n            // 默认为直线\n            // 可选为：'line' | 'shadow' | 'cross'\n            type: 'line',\n\n            // type 为 line 的时候有效，指定 tooltip line 所在的轴，可选\n            // 可选 'x' | 'y' | 'angle' | 'radius' | 'auto'\n            // 默认 'auto'，会选择类型为 category 的轴，对于双数值轴，笛卡尔坐标系会默认选择 x 轴\n            // 极坐标系会默认选择 angle 轴\n            axis: 'auto',\n\n            animation: 'auto',\n            animationDurationUpdate: 200,\n            animationEasingUpdate: 'exponentialOut',\n\n            crossStyle: {\n                color: '#999',\n                width: 1,\n                type: 'dashed',\n\n                // TODO formatter\n                textStyle: {}\n            }\n\n            // lineStyle and shadowStyle should not be specified here,\n            // otherwise it will always override those styles on option.axisPointer.\n        },\n        textStyle: {\n            color: '#fff',\n            fontSize: 14\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$18 = each$1;\nvar toCamelCase$1 = toCamelCase;\n\nvar vendors = ['', '-webkit-', '-moz-', '-o-'];\n\nvar gCssText = 'position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;';\n\n/**\n * @param {number} duration\n * @return {string}\n * @inner\n */\nfunction assembleTransition(duration) {\n    var transitionCurve = 'cubic-bezier(0.23, 1, 0.32, 1)';\n    var transitionText = 'left ' + duration + 's ' + transitionCurve + ','\n                        + 'top ' + duration + 's ' + transitionCurve;\n    return map(vendors, function (vendorPrefix) {\n        return vendorPrefix + 'transition:' + transitionText;\n    }).join(';');\n}\n\n/**\n * @param {Object} textStyle\n * @return {string}\n * @inner\n */\nfunction assembleFont(textStyleModel) {\n    var cssText = [];\n\n    var fontSize = textStyleModel.get('fontSize');\n    var color = textStyleModel.getTextColor();\n\n    color && cssText.push('color:' + color);\n\n    cssText.push('font:' + textStyleModel.getFont());\n\n    fontSize\n        && cssText.push('line-height:' + Math.round(fontSize * 3 / 2) + 'px');\n\n    each$18(['decoration', 'align'], function (name) {\n        var val = textStyleModel.get(name);\n        val && cssText.push('text-' + name + ':' + val);\n    });\n\n    return cssText.join(';');\n}\n\n/**\n * @param {Object} tooltipModel\n * @return {string}\n * @inner\n */\nfunction assembleCssText(tooltipModel) {\n\n    var cssText = [];\n\n    var transitionDuration = tooltipModel.get('transitionDuration');\n    var backgroundColor = tooltipModel.get('backgroundColor');\n    var textStyleModel = tooltipModel.getModel('textStyle');\n    var padding = tooltipModel.get('padding');\n\n    // Animation transition. Do not animate when transitionDuration is 0.\n    transitionDuration\n        && cssText.push(assembleTransition(transitionDuration));\n\n    if (backgroundColor) {\n        if (env$1.canvasSupported) {\n            cssText.push('background-Color:' + backgroundColor);\n        }\n        else {\n            // for ie\n            cssText.push(\n                'background-Color:#' + toHex(backgroundColor)\n            );\n            cssText.push('filter:alpha(opacity=70)');\n        }\n    }\n\n    // Border style\n    each$18(['width', 'color', 'radius'], function (name) {\n        var borderName = 'border-' + name;\n        var camelCase = toCamelCase$1(borderName);\n        var val = tooltipModel.get(camelCase);\n        val != null\n            && cssText.push(borderName + ':' + val + (name === 'color' ? '' : 'px'));\n    });\n\n    // Text style\n    cssText.push(assembleFont(textStyleModel));\n\n    // Padding\n    if (padding != null) {\n        cssText.push('padding:' + normalizeCssArray$1(padding).join('px ') + 'px');\n    }\n\n    return cssText.join(';') + ';';\n}\n\n/**\n * @alias module:echarts/component/tooltip/TooltipContent\n * @constructor\n */\nfunction TooltipContent(container, api) {\n    if (env$1.wxa) {\n        return null;\n    }\n\n    var el = document.createElement('div');\n    var zr = this._zr = api.getZr();\n\n    this.el = el;\n\n    this._x = api.getWidth() / 2;\n    this._y = api.getHeight() / 2;\n\n    container.appendChild(el);\n\n    this._container = container;\n\n    this._show = false;\n\n    /**\n     * @private\n     */\n    this._hideTimeout;\n\n    var self = this;\n    el.onmouseenter = function () {\n        // clear the timeout in hideLater and keep showing tooltip\n        if (self._enterable) {\n            clearTimeout(self._hideTimeout);\n            self._show = true;\n        }\n        self._inContent = true;\n    };\n    el.onmousemove = function (e) {\n        e = e || window.event;\n        if (!self._enterable) {\n            // Try trigger zrender event to avoid mouse\n            // in and out shape too frequently\n            var handler = zr.handler;\n            normalizeEvent(container, e, true);\n            handler.dispatch('mousemove', e);\n        }\n    };\n    el.onmouseleave = function () {\n        if (self._enterable) {\n            if (self._show) {\n                self.hideLater(self._hideDelay);\n            }\n        }\n        self._inContent = false;\n    };\n}\n\nTooltipContent.prototype = {\n\n    constructor: TooltipContent,\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    _enterable: true,\n\n    /**\n     * Update when tooltip is rendered\n     */\n    update: function () {\n        // FIXME\n        // Move this logic to ec main?\n        var container = this._container;\n        var stl = container.currentStyle\n            || document.defaultView.getComputedStyle(container);\n        var domStyle = container.style;\n        if (domStyle.position !== 'absolute' && stl.position !== 'absolute') {\n            domStyle.position = 'relative';\n        }\n        // Hide the tooltip\n        // PENDING\n        // this.hide();\n    },\n\n    show: function (tooltipModel) {\n        clearTimeout(this._hideTimeout);\n        var el = this.el;\n\n        el.style.cssText = gCssText + assembleCssText(tooltipModel)\n            // http://stackoverflow.com/questions/21125587/css3-transition-not-working-in-chrome-anymore\n            + ';left:' + this._x + 'px;top:' + this._y + 'px;'\n            + (tooltipModel.get('extraCssText') || '');\n\n        el.style.display = el.innerHTML ? 'block' : 'none';\n\n        // If mouse occsionally move over the tooltip, a mouseout event will be\n        // triggered by canvas, and cuase some unexpectable result like dragging\n        // stop, \"unfocusAdjacency\". Here `pointer-events: none` is used to solve\n        // it. Although it is not suppored by IE8~IE10, fortunately it is a rare\n        // scenario.\n        el.style.pointerEvents = this._enterable ? 'auto' : 'none';\n\n        this._show = true;\n    },\n\n    setContent: function (content) {\n        this.el.innerHTML = content == null ? '' : content;\n    },\n\n    setEnterable: function (enterable) {\n        this._enterable = enterable;\n    },\n\n    getSize: function () {\n        var el = this.el;\n        return [el.clientWidth, el.clientHeight];\n    },\n\n    moveTo: function (x, y) {\n        // xy should be based on canvas root. But tooltipContent is\n        // the sibling of canvas root. So padding of ec container\n        // should be considered here.\n        var zr = this._zr;\n        var viewportRootOffset;\n        if (zr && zr.painter && (viewportRootOffset = zr.painter.getViewportRootOffset())) {\n            x += viewportRootOffset.offsetLeft;\n            y += viewportRootOffset.offsetTop;\n        }\n\n        var style = this.el.style;\n        style.left = x + 'px';\n        style.top = y + 'px';\n\n        this._x = x;\n        this._y = y;\n    },\n\n    hide: function () {\n        this.el.style.display = 'none';\n        this._show = false;\n    },\n\n    hideLater: function (time) {\n        if (this._show && !(this._inContent && this._enterable)) {\n            if (time) {\n                this._hideDelay = time;\n                // Set show false to avoid invoke hideLater mutiple times\n                this._show = false;\n                this._hideTimeout = setTimeout(bind(this.hide, this), time);\n            }\n            else {\n                this.hide();\n            }\n        }\n    },\n\n    isShow: function () {\n        return this._show;\n    },\n\n    getOuterSize: function () {\n        var width = this.el.clientWidth;\n        var height = this.el.clientHeight;\n\n        // Consider browser compatibility.\n        // IE8 does not support getComputedStyle.\n        if (document.defaultView && document.defaultView.getComputedStyle) {\n            var stl = document.defaultView.getComputedStyle(this.el);\n            if (stl) {\n                width += parseInt(stl.paddingLeft, 10) + parseInt(stl.paddingRight, 10)\n                    + parseInt(stl.borderLeftWidth, 10) + parseInt(stl.borderRightWidth, 10);\n                height += parseInt(stl.paddingTop, 10) + parseInt(stl.paddingBottom, 10)\n                    + parseInt(stl.borderTopWidth, 10) + parseInt(stl.borderBottomWidth, 10);\n            }\n        }\n\n        return {width: width, height: height};\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import Group from 'zrender/src/container/Group';\n/**\n * @alias module:echarts/component/tooltip/TooltipRichContent\n * @constructor\n */\nfunction TooltipRichContent(api) {\n\n    this._zr = api.getZr();\n\n    this._show = false;\n\n    /**\n     * @private\n     */\n    this._hideTimeout;\n}\n\nTooltipRichContent.prototype = {\n\n    constructor: TooltipRichContent,\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    _enterable: true,\n\n    /**\n     * Update when tooltip is rendered\n     */\n    update: function () {\n        // noop\n    },\n\n    show: function (tooltipModel) {\n        if (this._hideTimeout) {\n            clearTimeout(this._hideTimeout);\n        }\n\n        this.el.attr('show', true);\n        this._show = true;\n    },\n\n    /**\n     * Set tooltip content\n     *\n     * @param {string} content rich text string of content\n     * @param {Object} markerRich rich text style\n     * @param {Object} tooltipModel tooltip model\n     */\n    setContent: function (content, markerRich, tooltipModel) {\n        if (this.el) {\n            this._zr.remove(this.el);\n        }\n\n        var markers = {};\n        var text = content;\n        var prefix = '{marker';\n        var suffix = '|}';\n        var startId = text.indexOf(prefix);\n        while (startId >= 0) {\n            var endId = text.indexOf(suffix);\n            var name = text.substr(startId + prefix.length, endId - startId - prefix.length);\n            if (name.indexOf('sub') > -1) {\n                markers['marker' + name] = {\n                    textWidth: 4,\n                    textHeight: 4,\n                    textBorderRadius: 2,\n                    textBackgroundColor: markerRich[name],\n                    // TODO: textOffset is not implemented for rich text\n                    textOffset: [3, 0]\n                };\n            }\n            else {\n                markers['marker' + name] = {\n                    textWidth: 10,\n                    textHeight: 10,\n                    textBorderRadius: 5,\n                    textBackgroundColor: markerRich[name]\n                };\n            }\n\n            text = text.substr(endId + 1);\n            startId = text.indexOf('{marker');\n        }\n\n        this.el = new Text({\n            style: {\n                rich: markers,\n                text: content,\n                textLineHeight: 20,\n                textBackgroundColor: tooltipModel.get('backgroundColor'),\n                textBorderRadius: tooltipModel.get('borderRadius'),\n                textFill: tooltipModel.get('textStyle.color'),\n                textPadding: tooltipModel.get('padding')\n            },\n            z: tooltipModel.get('z')\n        });\n        this._zr.add(this.el);\n\n        var self = this;\n        this.el.on('mouseover', function () {\n            // clear the timeout in hideLater and keep showing tooltip\n            if (self._enterable) {\n                clearTimeout(self._hideTimeout);\n                self._show = true;\n            }\n            self._inContent = true;\n        });\n        this.el.on('mouseout', function () {\n            if (self._enterable) {\n                if (self._show) {\n                    self.hideLater(self._hideDelay);\n                }\n            }\n            self._inContent = false;\n        });\n    },\n\n    setEnterable: function (enterable) {\n        this._enterable = enterable;\n    },\n\n    getSize: function () {\n        var bounding = this.el.getBoundingRect();\n        return [bounding.width, bounding.height];\n    },\n\n    moveTo: function (x, y) {\n        if (this.el) {\n            this.el.attr('position', [x, y]);\n        }\n    },\n\n    hide: function () {\n        this.el.hide();\n        this._show = false;\n    },\n\n    hideLater: function (time) {\n        if (this._show && !(this._inContent && this._enterable)) {\n            if (time) {\n                this._hideDelay = time;\n                // Set show false to avoid invoke hideLater mutiple times\n                this._show = false;\n                this._hideTimeout = setTimeout(bind(this.hide, this), time);\n            }\n            else {\n                this.hide();\n            }\n        }\n    },\n\n    isShow: function () {\n        return this._show;\n    },\n\n    getOuterSize: function () {\n        return this.getSize();\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$3 = bind;\nvar each$17 = each$1;\nvar parsePercent$2 = parsePercent$1;\n\nvar proxyRect = new Rect({\n    shape: {x: -1, y: -1, width: 2, height: 2}\n});\n\nextendComponentView({\n\n    type: 'tooltip',\n\n    init: function (ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n\n        var tooltipModel = ecModel.getComponent('tooltip');\n        var renderMode = tooltipModel.get('renderMode');\n        this._renderMode = getTooltipRenderMode(renderMode);\n\n        var tooltipContent;\n        if (this._renderMode === 'html') {\n            tooltipContent = new TooltipContent(api.getDom(), api);\n            this._newLine = '<br/>';\n        }\n        else {\n            tooltipContent = new TooltipRichContent(api);\n            this._newLine = '\\n';\n        }\n\n        this._tooltipContent = tooltipContent;\n    },\n\n    render: function (tooltipModel, ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n\n        // Reset\n        this.group.removeAll();\n\n        /**\n         * @private\n         * @type {module:echarts/component/tooltip/TooltipModel}\n         */\n        this._tooltipModel = tooltipModel;\n\n        /**\n         * @private\n         * @type {module:echarts/model/Global}\n         */\n        this._ecModel = ecModel;\n\n        /**\n         * @private\n         * @type {module:echarts/ExtensionAPI}\n         */\n        this._api = api;\n\n        /**\n         * Should be cleaned when render.\n         * @private\n         * @type {Array.<Array.<Object>>}\n         */\n        this._lastDataByCoordSys = null;\n\n        /**\n         * @private\n         * @type {boolean}\n         */\n        this._alwaysShowContent = tooltipModel.get('alwaysShowContent');\n\n        var tooltipContent = this._tooltipContent;\n        tooltipContent.update();\n        tooltipContent.setEnterable(tooltipModel.get('enterable'));\n\n        this._initGlobalListener();\n\n        this._keepShow();\n    },\n\n    _initGlobalListener: function () {\n        var tooltipModel = this._tooltipModel;\n        var triggerOn = tooltipModel.get('triggerOn');\n\n        register(\n            'itemTooltip',\n            this._api,\n            bind$3(function (currTrigger, e, dispatchAction) {\n                // If 'none', it is not controlled by mouse totally.\n                if (triggerOn !== 'none') {\n                    if (triggerOn.indexOf(currTrigger) >= 0) {\n                        this._tryShow(e, dispatchAction);\n                    }\n                    else if (currTrigger === 'leave') {\n                        this._hide(dispatchAction);\n                    }\n                }\n            }, this)\n        );\n    },\n\n    _keepShow: function () {\n        var tooltipModel = this._tooltipModel;\n        var ecModel = this._ecModel;\n        var api = this._api;\n\n        // Try to keep the tooltip show when refreshing\n        if (this._lastX != null\n            && this._lastY != null\n            // When user is willing to control tooltip totally using API,\n            // self.manuallyShowTip({x, y}) might cause tooltip hide,\n            // which is not expected.\n            && tooltipModel.get('triggerOn') !== 'none'\n        ) {\n            var self = this;\n            clearTimeout(this._refreshUpdateTimeout);\n            this._refreshUpdateTimeout = setTimeout(function () {\n                // Show tip next tick after other charts are rendered\n                // In case highlight action has wrong result\n                // FIXME\n                self.manuallyShowTip(tooltipModel, ecModel, api, {\n                    x: self._lastX,\n                    y: self._lastY\n                });\n            });\n        }\n    },\n\n    /**\n     * Show tip manually by\n     * dispatchAction({\n     *     type: 'showTip',\n     *     x: 10,\n     *     y: 10\n     * });\n     * Or\n     * dispatchAction({\n     *      type: 'showTip',\n     *      seriesIndex: 0,\n     *      dataIndex or dataIndexInside or name\n     * });\n     *\n     *  TODO Batch\n     */\n    manuallyShowTip: function (tooltipModel, ecModel, api, payload) {\n        if (payload.from === this.uid || env$1.node) {\n            return;\n        }\n\n        var dispatchAction = makeDispatchAction$1(payload, api);\n\n        // Reset ticket\n        this._ticket = '';\n\n        // When triggered from axisPointer.\n        var dataByCoordSys = payload.dataByCoordSys;\n\n        if (payload.tooltip && payload.x != null && payload.y != null) {\n            var el = proxyRect;\n            el.position = [payload.x, payload.y];\n            el.update();\n            el.tooltip = payload.tooltip;\n            // Manually show tooltip while view is not using zrender elements.\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                target: el\n            }, dispatchAction);\n        }\n        else if (dataByCoordSys) {\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                position: payload.position,\n                event: {},\n                dataByCoordSys: payload.dataByCoordSys,\n                tooltipOption: payload.tooltipOption\n            }, dispatchAction);\n        }\n        else if (payload.seriesIndex != null) {\n\n            if (this._manuallyAxisShowTip(tooltipModel, ecModel, api, payload)) {\n                return;\n            }\n\n            var pointInfo = findPointFromSeries(payload, ecModel);\n            var cx = pointInfo.point[0];\n            var cy = pointInfo.point[1];\n            if (cx != null && cy != null) {\n                this._tryShow({\n                    offsetX: cx,\n                    offsetY: cy,\n                    position: payload.position,\n                    target: pointInfo.el,\n                    event: {}\n                }, dispatchAction);\n            }\n        }\n        else if (payload.x != null && payload.y != null) {\n            // FIXME\n            // should wrap dispatchAction like `axisPointer/globalListener` ?\n            api.dispatchAction({\n                type: 'updateAxisPointer',\n                x: payload.x,\n                y: payload.y\n            });\n\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                position: payload.position,\n                target: api.getZr().findHover(payload.x, payload.y).target,\n                event: {}\n            }, dispatchAction);\n        }\n    },\n\n    manuallyHideTip: function (tooltipModel, ecModel, api, payload) {\n        var tooltipContent = this._tooltipContent;\n\n        if (!this._alwaysShowContent && this._tooltipModel) {\n            tooltipContent.hideLater(this._tooltipModel.get('hideDelay'));\n        }\n\n        this._lastX = this._lastY = null;\n\n        if (payload.from !== this.uid) {\n            this._hide(makeDispatchAction$1(payload, api));\n        }\n    },\n\n    // Be compatible with previous design, that is, when tooltip.type is 'axis' and\n    // dispatchAction 'showTip' with seriesIndex and dataIndex will trigger axis pointer\n    // and tooltip.\n    _manuallyAxisShowTip: function (tooltipModel, ecModel, api, payload) {\n        var seriesIndex = payload.seriesIndex;\n        var dataIndex = payload.dataIndex;\n        var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo;\n\n        if (seriesIndex == null || dataIndex == null || coordSysAxesInfo == null) {\n            return;\n        }\n\n        var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n        if (!seriesModel) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var tooltipModel = buildTooltipModel([\n            data.getItemModel(dataIndex),\n            seriesModel,\n            (seriesModel.coordinateSystem || {}).model,\n            tooltipModel\n        ]);\n\n        if (tooltipModel.get('trigger') !== 'axis') {\n            return;\n        }\n\n        api.dispatchAction({\n            type: 'updateAxisPointer',\n            seriesIndex: seriesIndex,\n            dataIndex: dataIndex,\n            position: payload.position\n        });\n\n        return true;\n    },\n\n    _tryShow: function (e, dispatchAction) {\n        var el = e.target;\n        var tooltipModel = this._tooltipModel;\n\n        if (!tooltipModel) {\n            return;\n        }\n\n        // Save mouse x, mouse y. So we can try to keep showing the tip if chart is refreshed\n        this._lastX = e.offsetX;\n        this._lastY = e.offsetY;\n\n        var dataByCoordSys = e.dataByCoordSys;\n        if (dataByCoordSys && dataByCoordSys.length) {\n            this._showAxisTooltip(dataByCoordSys, e);\n        }\n        // Always show item tooltip if mouse is on the element with dataIndex\n        else if (el && el.dataIndex != null) {\n            this._lastDataByCoordSys = null;\n            this._showSeriesItemTooltip(e, el, dispatchAction);\n        }\n        // Tooltip provided directly. Like legend.\n        else if (el && el.tooltip) {\n            this._lastDataByCoordSys = null;\n            this._showComponentItemTooltip(e, el, dispatchAction);\n        }\n        else {\n            this._lastDataByCoordSys = null;\n            this._hide(dispatchAction);\n        }\n    },\n\n    _showOrMove: function (tooltipModel, cb) {\n        // showDelay is used in this case: tooltip.enterable is set\n        // as true. User intent to move mouse into tooltip and click\n        // something. `showDelay` makes it easyer to enter the content\n        // but tooltip do not move immediately.\n        var delay = tooltipModel.get('showDelay');\n        cb = bind(cb, this);\n        clearTimeout(this._showTimout);\n        delay > 0\n            ? (this._showTimout = setTimeout(cb, delay))\n            : cb();\n    },\n\n    _showAxisTooltip: function (dataByCoordSys, e) {\n        var ecModel = this._ecModel;\n        var globalTooltipModel = this._tooltipModel;\n        var point = [e.offsetX, e.offsetY];\n        var singleDefaultHTML = [];\n        var singleParamsList = [];\n        var singleTooltipModel = buildTooltipModel([\n            e.tooltipOption,\n            globalTooltipModel\n        ]);\n\n        var renderMode = this._renderMode;\n        var newLine = this._newLine;\n\n        var markers = {};\n\n        each$17(dataByCoordSys, function (itemCoordSys) {\n            // var coordParamList = [];\n            // var coordDefaultHTML = [];\n            // var coordTooltipModel = buildTooltipModel([\n            //     e.tooltipOption,\n            //     itemCoordSys.tooltipOption,\n            //     ecModel.getComponent(itemCoordSys.coordSysMainType, itemCoordSys.coordSysIndex),\n            //     globalTooltipModel\n            // ]);\n            // var displayMode = coordTooltipModel.get('displayMode');\n            // var paramsList = displayMode === 'single' ? singleParamsList : [];\n\n            each$17(itemCoordSys.dataByAxis, function (item) {\n                var axisModel = ecModel.getComponent(item.axisDim + 'Axis', item.axisIndex);\n                var axisValue = item.value;\n                var seriesDefaultHTML = [];\n\n                if (!axisModel || axisValue == null) {\n                    return;\n                }\n\n                var valueLabel = getValueLabel(\n                    axisValue, axisModel.axis, ecModel,\n                    item.seriesDataIndices,\n                    item.valueLabelOpt\n                );\n\n                each$1(item.seriesDataIndices, function (idxItem) {\n                    var series = ecModel.getSeriesByIndex(idxItem.seriesIndex);\n                    var dataIndex = idxItem.dataIndexInside;\n                    var dataParams = series && series.getDataParams(dataIndex);\n                    dataParams.axisDim = item.axisDim;\n                    dataParams.axisIndex = item.axisIndex;\n                    dataParams.axisType = item.axisType;\n                    dataParams.axisId = item.axisId;\n                    dataParams.axisValue = getAxisRawValue(axisModel.axis, axisValue);\n                    dataParams.axisValueLabel = valueLabel;\n\n                    if (dataParams) {\n                        singleParamsList.push(dataParams);\n                        var seriesTooltip = series.formatTooltip(dataIndex, true, null, renderMode);\n\n                        var html;\n                        if (isObject$1(seriesTooltip)) {\n                            html = seriesTooltip.html;\n                            var newMarkers = seriesTooltip.markers;\n                            merge(markers, newMarkers);\n                        }\n                        else {\n                            html = seriesTooltip;\n                        }\n                        seriesDefaultHTML.push(html);\n                    }\n                });\n\n                // Default tooltip content\n                // FIXME\n                // (1) shold be the first data which has name?\n                // (2) themeRiver, firstDataIndex is array, and first line is unnecessary.\n                var firstLine = valueLabel;\n                if (renderMode !== 'html') {\n                    singleDefaultHTML.push(seriesDefaultHTML.join(newLine));\n                }\n                else {\n                    singleDefaultHTML.push(\n                        (firstLine ? encodeHTML(firstLine) + newLine : '')\n                        + seriesDefaultHTML.join(newLine)\n                    );\n                }\n            });\n        }, this);\n\n        // In most case, the second axis is shown upper than the first one.\n        singleDefaultHTML.reverse();\n        singleDefaultHTML = singleDefaultHTML.join(this._newLine + this._newLine);\n\n        var positionExpr = e.position;\n        this._showOrMove(singleTooltipModel, function () {\n            if (this._updateContentNotChangedOnAxis(dataByCoordSys)) {\n                this._updatePosition(\n                    singleTooltipModel,\n                    positionExpr,\n                    point[0], point[1],\n                    this._tooltipContent,\n                    singleParamsList\n                );\n            }\n            else {\n                this._showTooltipContent(\n                    singleTooltipModel, singleDefaultHTML, singleParamsList, Math.random(),\n                    point[0], point[1], positionExpr, undefined, markers\n                );\n            }\n        });\n\n        // Do not trigger events here, because this branch only be entered\n        // from dispatchAction.\n    },\n\n    _showSeriesItemTooltip: function (e, el, dispatchAction) {\n        var ecModel = this._ecModel;\n        // Use dataModel in element if possible\n        // Used when mouseover on a element like markPoint or edge\n        // In which case, the data is not main data in series.\n        var seriesIndex = el.seriesIndex;\n        var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n\n        // For example, graph link.\n        var dataModel = el.dataModel || seriesModel;\n        var dataIndex = el.dataIndex;\n        var dataType = el.dataType;\n        var data = dataModel.getData();\n\n        var tooltipModel = buildTooltipModel([\n            data.getItemModel(dataIndex),\n            dataModel,\n            seriesModel && (seriesModel.coordinateSystem || {}).model,\n            this._tooltipModel\n        ]);\n\n        var tooltipTrigger = tooltipModel.get('trigger');\n        if (tooltipTrigger != null && tooltipTrigger !== 'item') {\n            return;\n        }\n\n        var params = dataModel.getDataParams(dataIndex, dataType);\n        var seriesTooltip = dataModel.formatTooltip(dataIndex, false, dataType, this._renderMode);\n        var defaultHtml;\n        var markers;\n        if (isObject$1(seriesTooltip)) {\n            defaultHtml = seriesTooltip.html;\n            markers = seriesTooltip.markers;\n        }\n        else {\n            defaultHtml = seriesTooltip;\n            markers = null;\n        }\n\n        var asyncTicket = 'item_' + dataModel.name + '_' + dataIndex;\n\n        this._showOrMove(tooltipModel, function () {\n            this._showTooltipContent(\n                tooltipModel, defaultHtml, params, asyncTicket,\n                e.offsetX, e.offsetY, e.position, e.target, markers\n            );\n        });\n\n        // FIXME\n        // duplicated showtip if manuallyShowTip is called from dispatchAction.\n        dispatchAction({\n            type: 'showTip',\n            dataIndexInside: dataIndex,\n            dataIndex: data.getRawIndex(dataIndex),\n            seriesIndex: seriesIndex,\n            from: this.uid\n        });\n    },\n\n    _showComponentItemTooltip: function (e, el, dispatchAction) {\n        var tooltipOpt = el.tooltip;\n        if (typeof tooltipOpt === 'string') {\n            var content = tooltipOpt;\n            tooltipOpt = {\n                content: content,\n                // Fixed formatter\n                formatter: content\n            };\n        }\n        var subTooltipModel = new Model(tooltipOpt, this._tooltipModel, this._ecModel);\n        var defaultHtml = subTooltipModel.get('content');\n        var asyncTicket = Math.random();\n\n        // Do not check whether `trigger` is 'none' here, because `trigger`\n        // only works on cooridinate system. In fact, we have not found case\n        // that requires setting `trigger` nothing on component yet.\n\n        this._showOrMove(subTooltipModel, function () {\n            this._showTooltipContent(\n                subTooltipModel, defaultHtml, subTooltipModel.get('formatterParams') || {},\n                asyncTicket, e.offsetX, e.offsetY, e.position, el\n            );\n        });\n\n        // If not dispatch showTip, tip may be hide triggered by axis.\n        dispatchAction({\n            type: 'showTip',\n            from: this.uid\n        });\n    },\n\n    _showTooltipContent: function (\n        tooltipModel, defaultHtml, params, asyncTicket, x, y, positionExpr, el, markers\n    ) {\n        // Reset ticket\n        this._ticket = '';\n\n        if (!tooltipModel.get('showContent') || !tooltipModel.get('show')) {\n            return;\n        }\n\n        var tooltipContent = this._tooltipContent;\n\n        var formatter = tooltipModel.get('formatter');\n        positionExpr = positionExpr || tooltipModel.get('position');\n        var html = defaultHtml;\n\n        if (formatter && typeof formatter === 'string') {\n            html = formatTpl(formatter, params, true);\n        }\n        else if (typeof formatter === 'function') {\n            var callback = bind$3(function (cbTicket, html) {\n                if (cbTicket === this._ticket) {\n                    tooltipContent.setContent(html, markers, tooltipModel);\n                    this._updatePosition(\n                        tooltipModel, positionExpr, x, y, tooltipContent, params, el\n                    );\n                }\n            }, this);\n            this._ticket = asyncTicket;\n            html = formatter(params, asyncTicket, callback);\n        }\n\n        tooltipContent.setContent(html, markers, tooltipModel);\n        tooltipContent.show(tooltipModel);\n\n        this._updatePosition(\n            tooltipModel, positionExpr, x, y, tooltipContent, params, el\n        );\n    },\n\n    /**\n     * @param  {string|Function|Array.<number>|Object} positionExpr\n     * @param  {number} x Mouse x\n     * @param  {number} y Mouse y\n     * @param  {boolean} confine Whether confine tooltip content in view rect.\n     * @param  {Object|<Array.<Object>} params\n     * @param  {module:zrender/Element} el target element\n     * @param  {module:echarts/ExtensionAPI} api\n     * @return {Array.<number>}\n     */\n    _updatePosition: function (tooltipModel, positionExpr, x, y, content, params, el) {\n        var viewWidth = this._api.getWidth();\n        var viewHeight = this._api.getHeight();\n        positionExpr = positionExpr || tooltipModel.get('position');\n\n        var contentSize = content.getSize();\n        var align = tooltipModel.get('align');\n        var vAlign = tooltipModel.get('verticalAlign');\n        var rect = el && el.getBoundingRect().clone();\n        el && rect.applyTransform(el.transform);\n\n        if (typeof positionExpr === 'function') {\n            // Callback of position can be an array or a string specify the position\n            positionExpr = positionExpr([x, y], params, content.el, rect, {\n                viewSize: [viewWidth, viewHeight],\n                contentSize: contentSize.slice()\n            });\n        }\n\n        if (isArray(positionExpr)) {\n            x = parsePercent$2(positionExpr[0], viewWidth);\n            y = parsePercent$2(positionExpr[1], viewHeight);\n        }\n        else if (isObject$1(positionExpr)) {\n            positionExpr.width = contentSize[0];\n            positionExpr.height = contentSize[1];\n            var layoutRect = getLayoutRect(\n                positionExpr, {width: viewWidth, height: viewHeight}\n            );\n            x = layoutRect.x;\n            y = layoutRect.y;\n            align = null;\n            // When positionExpr is left/top/right/bottom,\n            // align and verticalAlign will not work.\n            vAlign = null;\n        }\n        // Specify tooltip position by string 'top' 'bottom' 'left' 'right' around graphic element\n        else if (typeof positionExpr === 'string' && el) {\n            var pos = calcTooltipPosition(\n                positionExpr, rect, contentSize\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n        else {\n            var pos = refixTooltipPosition(\n                x, y, content, viewWidth, viewHeight, align ? null : 20, vAlign ? null : 20\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n\n        align && (x -= isCenterAlign(align) ? contentSize[0] / 2 : align === 'right' ? contentSize[0] : 0);\n        vAlign && (y -= isCenterAlign(vAlign) ? contentSize[1] / 2 : vAlign === 'bottom' ? contentSize[1] : 0);\n\n        if (tooltipModel.get('confine')) {\n            var pos = confineTooltipPosition(\n                x, y, content, viewWidth, viewHeight\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n\n        content.moveTo(x, y);\n    },\n\n    // FIXME\n    // Should we remove this but leave this to user?\n    _updateContentNotChangedOnAxis: function (dataByCoordSys) {\n        var lastCoordSys = this._lastDataByCoordSys;\n        var contentNotChanged = !!lastCoordSys\n            && lastCoordSys.length === dataByCoordSys.length;\n\n        contentNotChanged && each$17(lastCoordSys, function (lastItemCoordSys, indexCoordSys) {\n            var lastDataByAxis = lastItemCoordSys.dataByAxis || {};\n            var thisItemCoordSys = dataByCoordSys[indexCoordSys] || {};\n            var thisDataByAxis = thisItemCoordSys.dataByAxis || [];\n            contentNotChanged &= lastDataByAxis.length === thisDataByAxis.length;\n\n            contentNotChanged && each$17(lastDataByAxis, function (lastItem, indexAxis) {\n                var thisItem = thisDataByAxis[indexAxis] || {};\n                var lastIndices = lastItem.seriesDataIndices || [];\n                var newIndices = thisItem.seriesDataIndices || [];\n\n                contentNotChanged\n                    &= lastItem.value === thisItem.value\n                    && lastItem.axisType === thisItem.axisType\n                    && lastItem.axisId === thisItem.axisId\n                    && lastIndices.length === newIndices.length;\n\n                contentNotChanged && each$17(lastIndices, function (lastIdxItem, j) {\n                    var newIdxItem = newIndices[j];\n                    contentNotChanged\n                        &= lastIdxItem.seriesIndex === newIdxItem.seriesIndex\n                        && lastIdxItem.dataIndex === newIdxItem.dataIndex;\n                });\n            });\n        });\n\n        this._lastDataByCoordSys = dataByCoordSys;\n\n        return !!contentNotChanged;\n    },\n\n    _hide: function (dispatchAction) {\n        // Do not directly hideLater here, because this behavior may be prevented\n        // in dispatchAction when showTip is dispatched.\n\n        // FIXME\n        // duplicated hideTip if manuallyHideTip is called from dispatchAction.\n        this._lastDataByCoordSys = null;\n        dispatchAction({\n            type: 'hideTip',\n            from: this.uid\n        });\n    },\n\n    dispose: function (ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n        this._tooltipContent.hide();\n        unregister('itemTooltip', api);\n    }\n});\n\n\n/**\n * @param {Array.<Object|module:echarts/model/Model>} modelCascade\n * From top to bottom. (the last one should be globalTooltipModel);\n */\nfunction buildTooltipModel(modelCascade) {\n    var resultModel = modelCascade.pop();\n    while (modelCascade.length) {\n        var tooltipOpt = modelCascade.pop();\n        if (tooltipOpt) {\n            if (Model.isInstance(tooltipOpt)) {\n                tooltipOpt = tooltipOpt.get('tooltip', true);\n            }\n            // In each data item tooltip can be simply write:\n            // {\n            //  value: 10,\n            //  tooltip: 'Something you need to know'\n            // }\n            if (typeof tooltipOpt === 'string') {\n                tooltipOpt = {formatter: tooltipOpt};\n            }\n            resultModel = new Model(tooltipOpt, resultModel, resultModel.ecModel);\n        }\n    }\n    return resultModel;\n}\n\nfunction makeDispatchAction$1(payload, api) {\n    return payload.dispatchAction || bind(api.dispatchAction, api);\n}\n\nfunction refixTooltipPosition(x, y, content, viewWidth, viewHeight, gapH, gapV) {\n    var size = content.getOuterSize();\n    var width = size.width;\n    var height = size.height;\n\n    if (gapH != null) {\n        if (x + width + gapH > viewWidth) {\n            x -= width + gapH;\n        }\n        else {\n            x += gapH;\n        }\n    }\n    if (gapV != null) {\n        if (y + height + gapV > viewHeight) {\n            y -= height + gapV;\n        }\n        else {\n            y += gapV;\n        }\n    }\n    return [x, y];\n}\n\nfunction confineTooltipPosition(x, y, content, viewWidth, viewHeight) {\n    var size = content.getOuterSize();\n    var width = size.width;\n    var height = size.height;\n\n    x = Math.min(x + width, viewWidth) - width;\n    y = Math.min(y + height, viewHeight) - height;\n    x = Math.max(x, 0);\n    y = Math.max(y, 0);\n\n    return [x, y];\n}\n\nfunction calcTooltipPosition(position, rect, contentSize) {\n    var domWidth = contentSize[0];\n    var domHeight = contentSize[1];\n    var gap = 5;\n    var x = 0;\n    var y = 0;\n    var rectWidth = rect.width;\n    var rectHeight = rect.height;\n    switch (position) {\n        case 'inside':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n            break;\n        case 'top':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y - domHeight - gap;\n            break;\n        case 'bottom':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y + rectHeight + gap;\n            break;\n        case 'left':\n            x = rect.x - domWidth - gap;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n            break;\n        case 'right':\n            x = rect.x + rectWidth + gap;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n    }\n    return [x, y];\n}\n\nfunction isCenterAlign(align) {\n    return align === 'center' || align === 'middle';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME Better way to pack data in graphic element\n\n/**\n * @action\n * @property {string} type\n * @property {number} seriesIndex\n * @property {number} dataIndex\n * @property {number} [x]\n * @property {number} [y]\n */\nregisterAction(\n    {\n        type: 'showTip',\n        event: 'showTip',\n        update: 'tooltip:manuallyShowTip'\n    },\n    // noop\n    function () {}\n);\n\nregisterAction(\n    {\n        type: 'hideTip',\n        event: 'hideTip',\n        update: 'tooltip:manuallyHideTip'\n    },\n    // noop\n    function () {}\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction getSeriesStackId$1(seriesModel) {\n    return seriesModel.get('stack')\n        || '__ec_stack_' + seriesModel.seriesIndex;\n}\n\nfunction getAxisKey$1(axis) {\n    return axis.dim;\n}\n\n/**\n * @param {string} seriesType\n * @param {module:echarts/model/Global} ecModel\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction barLayoutPolar(seriesType, ecModel, api) {\n\n    // FIXME\n    // Revert becuase it brings bar progressive bug.\n    // The complete fix will be added in the next version.\n    var width = api.getWidth();\n    var height = api.getHeight();\n\n    var lastStackCoords = {};\n\n    var barWidthAndOffset = calRadialBar(\n        filter(\n            ecModel.getSeriesByType(seriesType),\n            function (seriesModel) {\n                return !ecModel.isSeriesFiltered(seriesModel)\n                    && seriesModel.coordinateSystem\n                    && seriesModel.coordinateSystem.type === 'polar';\n            }\n        )\n    );\n\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        // Check series coordinate, do layout for polar only\n        if (seriesModel.coordinateSystem.type !== 'polar') {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var polar = seriesModel.coordinateSystem;\n        var baseAxis = polar.getBaseAxis();\n\n        var stackId = getSeriesStackId$1(seriesModel);\n        var columnLayoutInfo\n            = barWidthAndOffset[getAxisKey$1(baseAxis)][stackId];\n        var columnOffset = columnLayoutInfo.offset;\n        var columnWidth = columnLayoutInfo.width;\n        var valueAxis = polar.getOtherAxis(baseAxis);\n\n        var cx = seriesModel.coordinateSystem.cx;\n        var cy = seriesModel.coordinateSystem.cy;\n\n        var barMinHeight = seriesModel.get('barMinHeight') || 0;\n        var barMinAngle = seriesModel.get('barMinAngle') || 0;\n\n        lastStackCoords[stackId] = lastStackCoords[stackId] || [];\n\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var stacked = isDimensionStacked(data, valueDim /*, baseDim*/);\n\n        var valueAxisStart = valueAxis.getExtent()[0];\n\n        for (var idx = 0, len = data.count(); idx < len; idx++) {\n            var value = data.get(valueDim, idx);\n            var baseValue = data.get(baseDim, idx);\n\n            if (isNaN(value)) {\n                continue;\n            }\n\n            var sign = value >= 0 ? 'p' : 'n';\n            var baseCoord = valueAxisStart;\n\n            // Because of the barMinHeight, we can not use the value in\n            // stackResultDimension directly.\n            // Only ordinal axis can be stacked.\n            if (stacked) {\n                if (!lastStackCoords[stackId][baseValue]) {\n                    lastStackCoords[stackId][baseValue] = {\n                        p: valueAxisStart, // Positive stack\n                        n: valueAxisStart  // Negative stack\n                    };\n                }\n                // Should also consider #4243\n                baseCoord = lastStackCoords[stackId][baseValue][sign];\n            }\n\n            var r0;\n            var r;\n            var startAngle;\n            var endAngle;\n\n            // radial sector\n            if (valueAxis.dim === 'radius') {\n                var radiusSpan = valueAxis.dataToRadius(value) - valueAxisStart;\n                var angle = baseAxis.dataToAngle(baseValue);\n\n                if (Math.abs(radiusSpan) < barMinHeight) {\n                    radiusSpan = (radiusSpan < 0 ? -1 : 1) * barMinHeight;\n                }\n\n                r0 = baseCoord;\n                r = baseCoord + radiusSpan;\n                startAngle = angle - columnOffset;\n                endAngle = startAngle - columnWidth;\n\n                stacked && (lastStackCoords[stackId][baseValue][sign] = r);\n            }\n            // tangential sector\n            else {\n                // angleAxis must be clamped.\n                var angleSpan = valueAxis.dataToAngle(value, true) - valueAxisStart;\n                var radius = baseAxis.dataToRadius(baseValue);\n\n                if (Math.abs(angleSpan) < barMinAngle) {\n                    angleSpan = (angleSpan < 0 ? -1 : 1) * barMinAngle;\n                }\n\n                r0 = radius + columnOffset;\n                r = r0 + columnWidth;\n                startAngle = baseCoord;\n                endAngle = baseCoord + angleSpan;\n\n                // if the previous stack is at the end of the ring,\n                // add a round to differentiate it from origin\n                // var extent = angleAxis.getExtent();\n                // var stackCoord = angle;\n                // if (stackCoord === extent[0] && value > 0) {\n                //     stackCoord = extent[1];\n                // }\n                // else if (stackCoord === extent[1] && value < 0) {\n                //     stackCoord = extent[0];\n                // }\n                stacked && (lastStackCoords[stackId][baseValue][sign] = endAngle);\n            }\n\n            data.setItemLayout(idx, {\n                cx: cx,\n                cy: cy,\n                r0: r0,\n                r: r,\n                // Consider that positive angle is anti-clockwise,\n                // while positive radian of sector is clockwise\n                startAngle: -startAngle * Math.PI / 180,\n                endAngle: -endAngle * Math.PI / 180\n            });\n\n        }\n\n    }, this);\n\n}\n\n/**\n * Calculate bar width and offset for radial bar charts\n */\nfunction calRadialBar(barSeries, api) {\n    // Columns info on each category axis. Key is polar name\n    var columnsMap = {};\n\n    each$1(barSeries, function (seriesModel, idx) {\n        var data = seriesModel.getData();\n        var polar = seriesModel.coordinateSystem;\n\n        var baseAxis = polar.getBaseAxis();\n\n        var axisExtent = baseAxis.getExtent();\n        var bandWidth = baseAxis.type === 'category'\n            ? baseAxis.getBandWidth()\n            : (Math.abs(axisExtent[1] - axisExtent[0]) / data.count());\n\n        var columnsOnAxis = columnsMap[getAxisKey$1(baseAxis)] || {\n            bandWidth: bandWidth,\n            remainedWidth: bandWidth,\n            autoWidthCount: 0,\n            categoryGap: '20%',\n            gap: '30%',\n            stacks: {}\n        };\n        var stacks = columnsOnAxis.stacks;\n        columnsMap[getAxisKey$1(baseAxis)] = columnsOnAxis;\n\n        var stackId = getSeriesStackId$1(seriesModel);\n\n        if (!stacks[stackId]) {\n            columnsOnAxis.autoWidthCount++;\n        }\n        stacks[stackId] = stacks[stackId] || {\n            width: 0,\n            maxWidth: 0\n        };\n\n        var barWidth = parsePercent$1(\n            seriesModel.get('barWidth'),\n            bandWidth\n        );\n        var barMaxWidth = parsePercent$1(\n            seriesModel.get('barMaxWidth'),\n            bandWidth\n        );\n        var barGap = seriesModel.get('barGap');\n        var barCategoryGap = seriesModel.get('barCategoryGap');\n\n        if (barWidth && !stacks[stackId].width) {\n            barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);\n            stacks[stackId].width = barWidth;\n            columnsOnAxis.remainedWidth -= barWidth;\n        }\n\n        barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);\n        (barGap != null) && (columnsOnAxis.gap = barGap);\n        (barCategoryGap != null) && (columnsOnAxis.categoryGap = barCategoryGap);\n    });\n\n\n    var result = {};\n\n    each$1(columnsMap, function (columnsOnAxis, coordSysName) {\n\n        result[coordSysName] = {};\n\n        var stacks = columnsOnAxis.stacks;\n        var bandWidth = columnsOnAxis.bandWidth;\n        var categoryGap = parsePercent$1(columnsOnAxis.categoryGap, bandWidth);\n        var barGapPercent = parsePercent$1(columnsOnAxis.gap, 1);\n\n        var remainedWidth = columnsOnAxis.remainedWidth;\n        var autoWidthCount = columnsOnAxis.autoWidthCount;\n        var autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        // Find if any auto calculated bar exceeded maxBarWidth\n        each$1(stacks, function (column, stack) {\n            var maxWidth = column.maxWidth;\n            if (maxWidth && maxWidth < autoWidth) {\n                maxWidth = Math.min(maxWidth, remainedWidth);\n                if (column.width) {\n                    maxWidth = Math.min(maxWidth, column.width);\n                }\n                remainedWidth -= maxWidth;\n                column.width = maxWidth;\n                autoWidthCount--;\n            }\n        });\n\n        // Recalculate width again\n        autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        var widthSum = 0;\n        var lastColumn;\n        each$1(stacks, function (column, idx) {\n            if (!column.width) {\n                column.width = autoWidth;\n            }\n            lastColumn = column;\n            widthSum += column.width * (1 + barGapPercent);\n        });\n        if (lastColumn) {\n            widthSum -= lastColumn.width * barGapPercent;\n        }\n\n        var offset = -widthSum / 2;\n        each$1(stacks, function (column, stackId) {\n            result[coordSysName][stackId] = result[coordSysName][stackId] || {\n                offset: offset,\n                width: column.width\n            };\n\n            offset += column.width * (1 + barGapPercent);\n        });\n    });\n\n    return result;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction RadiusAxis(scale, radiusExtent) {\n\n    Axis.call(this, 'radius', scale, radiusExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = 'category';\n}\n\nRadiusAxis.prototype = {\n\n    constructor: RadiusAxis,\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.polar.pointToData(point, clamp)[this.dim === 'radius' ? 0 : 1];\n    },\n\n    dataToRadius: Axis.prototype.dataToCoord,\n\n    radiusToData: Axis.prototype.coordToData\n};\n\ninherits(RadiusAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$12 = makeInner();\n\nfunction AngleAxis(scale, angleExtent) {\n\n    angleExtent = angleExtent || [0, 360];\n\n    Axis.call(this, 'angle', scale, angleExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = 'category';\n}\n\nAngleAxis.prototype = {\n\n    constructor: AngleAxis,\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.polar.pointToData(point, clamp)[this.dim === 'radius' ? 0 : 1];\n    },\n\n    dataToAngle: Axis.prototype.dataToCoord,\n\n    angleToData: Axis.prototype.coordToData,\n\n    /**\n     * Only be called in category axis.\n     * Angle axis uses text height to decide interval\n     *\n     * @override\n     * @return {number} Auto interval for cateogry axis tick and label\n     */\n    calculateCategoryInterval: function () {\n        var axis = this;\n        var labelModel = axis.getLabelModel();\n\n        var ordinalScale = axis.scale;\n        var ordinalExtent = ordinalScale.getExtent();\n        // Providing this method is for optimization:\n        // avoid generating a long array by `getTicks`\n        // in large category data case.\n        var tickCount = ordinalScale.count();\n\n        if (ordinalExtent[1] - ordinalExtent[0] < 1) {\n            return 0;\n        }\n\n        var tickValue = ordinalExtent[0];\n        var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue);\n        var unitH = Math.abs(unitSpan);\n\n        // Not precise, just use height as text width\n        // and each distance from axis line yet.\n        var rect = getBoundingRect(\n            tickValue, labelModel.getFont(), 'center', 'top'\n        );\n        var maxH = Math.max(rect.height, 7);\n\n        var dh = maxH / unitH;\n        // 0/0 is NaN, 1/0 is Infinity.\n        isNaN(dh) && (dh = Infinity);\n        var interval = Math.max(0, Math.floor(dh));\n\n        var cache = inner$12(axis.model);\n        var lastAutoInterval = cache.lastAutoInterval;\n        var lastTickCount = cache.lastTickCount;\n\n        // Use cache to keep interval stable while moving zoom window,\n        // otherwise the calculated interval might jitter when the zoom\n        // window size is close to the interval-changing size.\n        if (lastAutoInterval != null\n            && lastTickCount != null\n            && Math.abs(lastAutoInterval - interval) <= 1\n            && Math.abs(lastTickCount - tickCount) <= 1\n            // Always choose the bigger one, otherwise the critical\n            // point is not the same when zooming in or zooming out.\n            && lastAutoInterval > interval\n        ) {\n            interval = lastAutoInterval;\n        }\n        // Only update cache if cache not used, otherwise the\n        // changing of interval is too insensitive.\n        else {\n            cache.lastTickCount = tickCount;\n            cache.lastAutoInterval = interval;\n        }\n\n        return interval;\n    }\n};\n\ninherits(AngleAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/coord/polar/Polar\n */\n\n/**\n * @alias {module:echarts/coord/polar/Polar}\n * @constructor\n * @param {string} name\n */\nvar Polar = function (name) {\n\n    /**\n     * @type {string}\n     */\n    this.name = name || '';\n\n    /**\n     * x of polar center\n     * @type {number}\n     */\n    this.cx = 0;\n\n    /**\n     * y of polar center\n     * @type {number}\n     */\n    this.cy = 0;\n\n    /**\n     * @type {module:echarts/coord/polar/RadiusAxis}\n     * @private\n     */\n    this._radiusAxis = new RadiusAxis();\n\n    /**\n     * @type {module:echarts/coord/polar/AngleAxis}\n     * @private\n     */\n    this._angleAxis = new AngleAxis();\n\n    this._radiusAxis.polar = this._angleAxis.polar = this;\n};\n\nPolar.prototype = {\n\n    type: 'polar',\n\n    axisPointerEnabled: true,\n\n    constructor: Polar,\n\n    /**\n     * @param {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['radius', 'angle'],\n\n    /**\n     * @type {module:echarts/coord/PolarModel}\n     */\n    model: null,\n\n    /**\n     * If contain coord\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    containPoint: function (point) {\n        var coord = this.pointToCoord(point);\n        return this._radiusAxis.contain(coord[0])\n            && this._angleAxis.contain(coord[1]);\n    },\n\n    /**\n     * If contain data\n     * @param {Array.<number>} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this._radiusAxis.containData(data[0])\n            && this._angleAxis.containData(data[1]);\n    },\n\n    /**\n     * @param {string} dim\n     * @return {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}\n     */\n    getAxis: function (dim) {\n        return this['_' + dim + 'Axis'];\n    },\n\n    /**\n     * @return {Array.<module:echarts/coord/Axis>}\n     */\n    getAxes: function () {\n        return [this._radiusAxis, this._angleAxis];\n    },\n\n    /**\n     * Get axes by type of scale\n     * @param {string} scaleType\n     * @return {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}\n     */\n    getAxesByScale: function (scaleType) {\n        var axes = [];\n        var angleAxis = this._angleAxis;\n        var radiusAxis = this._radiusAxis;\n        angleAxis.scale.type === scaleType && axes.push(angleAxis);\n        radiusAxis.scale.type === scaleType && axes.push(radiusAxis);\n\n        return axes;\n    },\n\n    /**\n     * @return {module:echarts/coord/polar/AngleAxis}\n     */\n    getAngleAxis: function () {\n        return this._angleAxis;\n    },\n\n    /**\n     * @return {module:echarts/coord/polar/RadiusAxis}\n     */\n    getRadiusAxis: function () {\n        return this._radiusAxis;\n    },\n\n    /**\n     * @param {module:echarts/coord/polar/Axis}\n     * @return {module:echarts/coord/polar/Axis}\n     */\n    getOtherAxis: function (axis) {\n        var angleAxis = this._angleAxis;\n        return axis === angleAxis ? this._radiusAxis : angleAxis;\n    },\n\n    /**\n     * Base axis will be used on stacking.\n     *\n     * @return {module:echarts/coord/polar/Axis}\n     */\n    getBaseAxis: function () {\n        return this.getAxesByScale('ordinal')[0]\n            || this.getAxesByScale('time')[0]\n            || this.getAngleAxis();\n    },\n\n    /**\n     * @param {string} [dim] 'radius' or 'angle' or 'auto' or null/undefined\n     * @return {Object} {baseAxes: [], otherAxes: []}\n     */\n    getTooltipAxes: function (dim) {\n        var baseAxis = (dim != null && dim !== 'auto')\n            ? this.getAxis(dim) : this.getBaseAxis();\n        return {\n            baseAxes: [baseAxis],\n            otherAxes: [this.getOtherAxis(baseAxis)]\n        };\n    },\n\n    /**\n     * Convert a single data item to (x, y) point.\n     * Parameter data is an array which the first element is radius and the second is angle\n     * @param {Array.<number>} data\n     * @param {boolean} [clamp=false]\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, clamp) {\n        return this.coordToPoint([\n            this._radiusAxis.dataToRadius(data[0], clamp),\n            this._angleAxis.dataToAngle(data[1], clamp)\n        ]);\n    },\n\n    /**\n     * Convert a (x, y) point to data\n     * @param {Array.<number>} point\n     * @param {boolean} [clamp=false]\n     * @return {Array.<number>}\n     */\n    pointToData: function (point, clamp) {\n        var coord = this.pointToCoord(point);\n        return [\n            this._radiusAxis.radiusToData(coord[0], clamp),\n            this._angleAxis.angleToData(coord[1], clamp)\n        ];\n    },\n\n    /**\n     * Convert a (x, y) point to (radius, angle) coord\n     * @param {Array.<number>} point\n     * @return {Array.<number>}\n     */\n    pointToCoord: function (point) {\n        var dx = point[0] - this.cx;\n        var dy = point[1] - this.cy;\n        var angleAxis = this.getAngleAxis();\n        var extent = angleAxis.getExtent();\n        var minAngle = Math.min(extent[0], extent[1]);\n        var maxAngle = Math.max(extent[0], extent[1]);\n        // Fix fixed extent in polarCreator\n        // FIXME\n        angleAxis.inverse\n            ? (minAngle = maxAngle - 360)\n            : (maxAngle = minAngle + 360);\n\n        var radius = Math.sqrt(dx * dx + dy * dy);\n        dx /= radius;\n        dy /= radius;\n\n        var radian = Math.atan2(-dy, dx) / Math.PI * 180;\n\n        // move to angleExtent\n        var dir = radian < minAngle ? 1 : -1;\n        while (radian < minAngle || radian > maxAngle) {\n            radian += dir * 360;\n        }\n\n        return [radius, radian];\n    },\n\n    /**\n     * Convert a (radius, angle) coord to (x, y) point\n     * @param {Array.<number>} coord\n     * @return {Array.<number>}\n     */\n    coordToPoint: function (coord) {\n        var radius = coord[0];\n        var radian = coord[1] / 180 * Math.PI;\n        var x = Math.cos(radian) * radius + this.cx;\n        // Inverse the y\n        var y = -Math.sin(radian) * radius + this.cy;\n\n        return [x, y];\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PolarAxisModel = ComponentModel.extend({\n\n    type: 'polarAxis',\n\n    /**\n     * @type {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}\n     */\n    axis: null,\n\n    /**\n     * @override\n     */\n    getCoordSysModel: function () {\n        return this.ecModel.queryComponents({\n            mainType: 'polar',\n            index: this.option.polarIndex,\n            id: this.option.polarId\n        })[0];\n    }\n\n});\n\nmerge(PolarAxisModel.prototype, axisModelCommonMixin);\n\nvar polarAxisDefaultExtendedOption = {\n    angle: {\n        // polarIndex: 0,\n        // polarId: '',\n\n        startAngle: 90,\n\n        clockwise: true,\n\n        splitNumber: 12,\n\n        axisLabel: {\n            rotate: false\n        }\n    },\n    radius: {\n        // polarIndex: 0,\n        // polarId: '',\n\n        splitNumber: 5\n    }\n};\n\nfunction getAxisType$3(axisDim, option) {\n    // Default axis with data is category axis\n    return option.type || (option.data ? 'category' : 'value');\n}\n\naxisModelCreator('angle', PolarAxisModel, getAxisType$3, polarAxisDefaultExtendedOption.angle);\naxisModelCreator('radius', PolarAxisModel, getAxisType$3, polarAxisDefaultExtendedOption.radius);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentModel({\n\n    type: 'polar',\n\n    dependencies: ['polarAxis', 'angleAxis'],\n\n    /**\n     * @type {module:echarts/coord/polar/Polar}\n     */\n    coordinateSystem: null,\n\n    /**\n     * @param {string} axisType\n     * @return {module:echarts/coord/polar/AxisModel}\n     */\n    findAxisModel: function (axisType) {\n        var foundAxisModel;\n        var ecModel = this.ecModel;\n\n        ecModel.eachComponent(axisType, function (axisModel) {\n            if (axisModel.getCoordSysModel() === this) {\n                foundAxisModel = axisModel;\n            }\n        }, this);\n        return foundAxisModel;\n    },\n\n    defaultOption: {\n\n        zlevel: 0,\n\n        z: 0,\n\n        center: ['50%', '50%'],\n\n        radius: '80%'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Axis scale\n\n/**\n * Resize method bound to the polar\n * @param {module:echarts/coord/polar/PolarModel} polarModel\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction resizePolar(polar, polarModel, api) {\n    var center = polarModel.get('center');\n    var width = api.getWidth();\n    var height = api.getHeight();\n\n    polar.cx = parsePercent$1(center[0], width);\n    polar.cy = parsePercent$1(center[1], height);\n\n    var radiusAxis = polar.getRadiusAxis();\n    var size = Math.min(width, height) / 2;\n    var radius = parsePercent$1(polarModel.get('radius'), size);\n    radiusAxis.inverse\n        ? radiusAxis.setExtent(radius, 0)\n        : radiusAxis.setExtent(0, radius);\n}\n\n/**\n * Update polar\n */\nfunction updatePolarScale(ecModel, api) {\n    var polar = this;\n    var angleAxis = polar.getAngleAxis();\n    var radiusAxis = polar.getRadiusAxis();\n    // Reset scale\n    angleAxis.scale.setExtent(Infinity, -Infinity);\n    radiusAxis.scale.setExtent(Infinity, -Infinity);\n\n    ecModel.eachSeries(function (seriesModel) {\n        if (seriesModel.coordinateSystem === polar) {\n            var data = seriesModel.getData();\n            each$1(data.mapDimension('radius', true), function (dim) {\n                radiusAxis.scale.unionExtentFromData(\n                    data, getStackedDimension(data, dim)\n                );\n            });\n            each$1(data.mapDimension('angle', true), function (dim) {\n                angleAxis.scale.unionExtentFromData(\n                    data, getStackedDimension(data, dim)\n                );\n            });\n        }\n    });\n\n    niceScaleExtent(angleAxis.scale, angleAxis.model);\n    niceScaleExtent(radiusAxis.scale, radiusAxis.model);\n\n    // Fix extent of category angle axis\n    if (angleAxis.type === 'category' && !angleAxis.onBand) {\n        var extent = angleAxis.getExtent();\n        var diff = 360 / angleAxis.scale.count();\n        angleAxis.inverse ? (extent[1] += diff) : (extent[1] -= diff);\n        angleAxis.setExtent(extent[0], extent[1]);\n    }\n}\n\n/**\n * Set common axis properties\n * @param {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}\n * @param {module:echarts/coord/polar/AxisModel}\n * @inner\n */\nfunction setAxis(axis, axisModel) {\n    axis.type = axisModel.get('type');\n    axis.scale = createScaleByModel(axisModel);\n    axis.onBand = axisModel.get('boundaryGap') && axis.type === 'category';\n    axis.inverse = axisModel.get('inverse');\n\n    if (axisModel.mainType === 'angleAxis') {\n        axis.inverse ^= axisModel.get('clockwise');\n        var startAngle = axisModel.get('startAngle');\n        axis.setExtent(startAngle, startAngle + (axis.inverse ? -360 : 360));\n    }\n\n    // Inject axis instance\n    axisModel.axis = axis;\n    axis.model = axisModel;\n}\n\n\nvar polarCreator = {\n\n    dimensions: Polar.prototype.dimensions,\n\n    create: function (ecModel, api) {\n        var polarList = [];\n        ecModel.eachComponent('polar', function (polarModel, idx) {\n            var polar = new Polar(idx);\n            // Inject resize and update method\n            polar.update = updatePolarScale;\n\n            var radiusAxis = polar.getRadiusAxis();\n            var angleAxis = polar.getAngleAxis();\n\n            var radiusAxisModel = polarModel.findAxisModel('radiusAxis');\n            var angleAxisModel = polarModel.findAxisModel('angleAxis');\n\n            setAxis(radiusAxis, radiusAxisModel);\n            setAxis(angleAxis, angleAxisModel);\n\n            resizePolar(polar, polarModel, api);\n\n            polarList.push(polar);\n\n            polarModel.coordinateSystem = polar;\n            polar.model = polarModel;\n        });\n        // Inject coordinateSystem to series\n        ecModel.eachSeries(function (seriesModel) {\n            if (seriesModel.get('coordinateSystem') === 'polar') {\n                var polarModel = ecModel.queryComponents({\n                    mainType: 'polar',\n                    index: seriesModel.get('polarIndex'),\n                    id: seriesModel.get('polarId')\n                })[0];\n\n                if (__DEV__) {\n                    if (!polarModel) {\n                        throw new Error(\n                            'Polar \"' + retrieve(\n                                seriesModel.get('polarIndex'),\n                                seriesModel.get('polarId'),\n                                0\n                            ) + '\" not found'\n                        );\n                    }\n                }\n                seriesModel.coordinateSystem = polarModel.coordinateSystem;\n            }\n        });\n\n        return polarList;\n    }\n};\n\nCoordinateSystemManager.register('polar', polarCreator);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar elementList$1 = ['axisLine', 'axisLabel', 'axisTick', 'splitLine', 'splitArea'];\n\nfunction getAxisLineShape(polar, rExtent, angle) {\n    rExtent[1] > rExtent[0] && (rExtent = rExtent.slice().reverse());\n    var start = polar.coordToPoint([rExtent[0], angle]);\n    var end = polar.coordToPoint([rExtent[1], angle]);\n\n    return {\n        x1: start[0],\n        y1: start[1],\n        x2: end[0],\n        y2: end[1]\n    };\n}\n\nfunction getRadiusIdx(polar) {\n    var radiusAxis = polar.getRadiusAxis();\n    return radiusAxis.inverse ? 0 : 1;\n}\n\n// Remove the last tick which will overlap the first tick\nfunction fixAngleOverlap(list) {\n    var firstItem = list[0];\n    var lastItem = list[list.length - 1];\n    if (firstItem\n        && lastItem\n        && Math.abs(Math.abs(firstItem.coord - lastItem.coord) - 360) < 1e-4\n    ) {\n        list.pop();\n    }\n}\n\nAxisView.extend({\n\n    type: 'angleAxis',\n\n    axisPointerClass: 'PolarAxisPointer',\n\n    render: function (angleAxisModel, ecModel) {\n        this.group.removeAll();\n        if (!angleAxisModel.get('show')) {\n            return;\n        }\n\n        var angleAxis = angleAxisModel.axis;\n        var polar = angleAxis.polar;\n        var radiusExtent = polar.getRadiusAxis().getExtent();\n\n        var ticksAngles = angleAxis.getTicksCoords();\n        var labels = map(angleAxis.getViewLabels(), function (labelItem) {\n            var labelItem = clone(labelItem);\n            labelItem.coord = angleAxis.dataToCoord(labelItem.tickValue);\n            return labelItem;\n        });\n\n        fixAngleOverlap(labels);\n        fixAngleOverlap(ticksAngles);\n\n        each$1(elementList$1, function (name) {\n            if (angleAxisModel.get(name + '.show')\n                && (!angleAxis.scale.isBlank() || name === 'axisLine')\n            ) {\n                this['_' + name](angleAxisModel, polar, ticksAngles, radiusExtent, labels);\n            }\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _axisLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) {\n        var lineStyleModel = angleAxisModel.getModel('axisLine.lineStyle');\n\n        var circle = new Circle({\n            shape: {\n                cx: polar.cx,\n                cy: polar.cy,\n                r: radiusExtent[getRadiusIdx(polar)]\n            },\n            style: lineStyleModel.getLineStyle(),\n            z2: 1,\n            silent: true\n        });\n        circle.style.fill = null;\n\n        this.group.add(circle);\n    },\n\n    /**\n     * @private\n     */\n    _axisTick: function (angleAxisModel, polar, ticksAngles, radiusExtent) {\n        var tickModel = angleAxisModel.getModel('axisTick');\n\n        var tickLen = (tickModel.get('inside') ? -1 : 1) * tickModel.get('length');\n        var radius = radiusExtent[getRadiusIdx(polar)];\n\n        var lines = map(ticksAngles, function (tickAngleItem) {\n            return new Line({\n                shape: getAxisLineShape(polar, [radius, radius + tickLen], tickAngleItem.coord)\n            });\n        });\n        this.group.add(mergePath(\n            lines, {\n                style: defaults(\n                    tickModel.getModel('lineStyle').getLineStyle(),\n                    {\n                        stroke: angleAxisModel.get('axisLine.lineStyle.color')\n                    }\n                )\n            }\n        ));\n    },\n\n    /**\n     * @private\n     */\n    _axisLabel: function (angleAxisModel, polar, ticksAngles, radiusExtent, labels) {\n        var rawCategoryData = angleAxisModel.getCategories(true);\n\n        var commonLabelModel = angleAxisModel.getModel('axisLabel');\n\n        var labelMargin = commonLabelModel.get('margin');\n\n        // Use length of ticksAngles because it may remove the last tick to avoid overlapping\n        each$1(labels, function (labelItem, idx) {\n            var labelModel = commonLabelModel;\n            var tickValue = labelItem.tickValue;\n\n            var r = radiusExtent[getRadiusIdx(polar)];\n            var p = polar.coordToPoint([r + labelMargin, labelItem.coord]);\n            var cx = polar.cx;\n            var cy = polar.cy;\n\n            var labelTextAlign = Math.abs(p[0] - cx) / r < 0.3\n                ? 'center' : (p[0] > cx ? 'left' : 'right');\n            var labelTextVerticalAlign = Math.abs(p[1] - cy) / r < 0.3\n                ? 'middle' : (p[1] > cy ? 'top' : 'bottom');\n\n            if (rawCategoryData && rawCategoryData[tickValue] && rawCategoryData[tickValue].textStyle) {\n                labelModel = new Model(\n                    rawCategoryData[tickValue].textStyle, commonLabelModel, commonLabelModel.ecModel\n                );\n            }\n\n            var textEl = new Text({silent: true});\n            this.group.add(textEl);\n            setTextStyle(textEl.style, labelModel, {\n                x: p[0],\n                y: p[1],\n                textFill: labelModel.getTextColor() || angleAxisModel.get('axisLine.lineStyle.color'),\n                text: labelItem.formattedLabel,\n                textAlign: labelTextAlign,\n                textVerticalAlign: labelTextVerticalAlign\n            });\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _splitLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) {\n        var splitLineModel = angleAxisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineColors = lineStyleModel.get('color');\n        var lineCount = 0;\n\n        lineColors = lineColors instanceof Array ? lineColors : [lineColors];\n\n        var splitLines = [];\n\n        for (var i = 0; i < ticksAngles.length; i++) {\n            var colorIndex = (lineCount++) % lineColors.length;\n            splitLines[colorIndex] = splitLines[colorIndex] || [];\n            splitLines[colorIndex].push(new Line({\n                shape: getAxisLineShape(polar, radiusExtent, ticksAngles[i].coord)\n            }));\n        }\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        for (var i = 0; i < splitLines.length; i++) {\n            this.group.add(mergePath(splitLines[i], {\n                style: defaults({\n                    stroke: lineColors[i % lineColors.length]\n                }, lineStyleModel.getLineStyle()),\n                silent: true,\n                z: angleAxisModel.get('z')\n            }));\n        }\n    },\n\n    /**\n     * @private\n     */\n    _splitArea: function (angleAxisModel, polar, ticksAngles, radiusExtent) {\n        if (!ticksAngles.length) {\n            return;\n        }\n\n        var splitAreaModel = angleAxisModel.getModel('splitArea');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n        var areaColors = areaStyleModel.get('color');\n        var lineCount = 0;\n\n        areaColors = areaColors instanceof Array ? areaColors : [areaColors];\n\n        var splitAreas = [];\n\n        var RADIAN = Math.PI / 180;\n        var prevAngle = -ticksAngles[0].coord * RADIAN;\n        var r0 = Math.min(radiusExtent[0], radiusExtent[1]);\n        var r1 = Math.max(radiusExtent[0], radiusExtent[1]);\n\n        var clockwise = angleAxisModel.get('clockwise');\n\n        for (var i = 1; i < ticksAngles.length; i++) {\n            var colorIndex = (lineCount++) % areaColors.length;\n            splitAreas[colorIndex] = splitAreas[colorIndex] || [];\n            splitAreas[colorIndex].push(new Sector({\n                shape: {\n                    cx: polar.cx,\n                    cy: polar.cy,\n                    r0: r0,\n                    r: r1,\n                    startAngle: prevAngle,\n                    endAngle: -ticksAngles[i].coord * RADIAN,\n                    clockwise: clockwise\n                },\n                silent: true\n            }));\n            prevAngle = -ticksAngles[i].coord * RADIAN;\n        }\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        for (var i = 0; i < splitAreas.length; i++) {\n            this.group.add(mergePath(splitAreas[i], {\n                style: defaults({\n                    fill: areaColors[i % areaColors.length]\n                }, areaStyleModel.getAreaStyle()),\n                silent: true\n            }));\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar axisBuilderAttrs$3 = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\nvar selfBuilderAttrs$1 = [\n    'splitLine', 'splitArea'\n];\n\nAxisView.extend({\n\n    type: 'radiusAxis',\n\n    axisPointerClass: 'PolarAxisPointer',\n\n    render: function (radiusAxisModel, ecModel) {\n        this.group.removeAll();\n        if (!radiusAxisModel.get('show')) {\n            return;\n        }\n        var radiusAxis = radiusAxisModel.axis;\n        var polar = radiusAxis.polar;\n        var angleAxis = polar.getAngleAxis();\n        var ticksCoords = radiusAxis.getTicksCoords();\n        var axisAngle = angleAxis.getExtent()[0];\n        var radiusExtent = radiusAxis.getExtent();\n\n        var layout = layoutAxis(polar, radiusAxisModel, axisAngle);\n        var axisBuilder = new AxisBuilder(radiusAxisModel, layout);\n        each$1(axisBuilderAttrs$3, axisBuilder.add, axisBuilder);\n        this.group.add(axisBuilder.getGroup());\n\n        each$1(selfBuilderAttrs$1, function (name) {\n            if (radiusAxisModel.get(name + '.show') && !radiusAxis.scale.isBlank()) {\n                this['_' + name](radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords);\n            }\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _splitLine: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) {\n        var splitLineModel = radiusAxisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineColors = lineStyleModel.get('color');\n        var lineCount = 0;\n\n        lineColors = lineColors instanceof Array ? lineColors : [lineColors];\n\n        var splitLines = [];\n\n        for (var i = 0; i < ticksCoords.length; i++) {\n            var colorIndex = (lineCount++) % lineColors.length;\n            splitLines[colorIndex] = splitLines[colorIndex] || [];\n            splitLines[colorIndex].push(new Circle({\n                shape: {\n                    cx: polar.cx,\n                    cy: polar.cy,\n                    r: ticksCoords[i].coord\n                },\n                silent: true\n            }));\n        }\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        for (var i = 0; i < splitLines.length; i++) {\n            this.group.add(mergePath(splitLines[i], {\n                style: defaults({\n                    stroke: lineColors[i % lineColors.length],\n                    fill: null\n                }, lineStyleModel.getLineStyle()),\n                silent: true\n            }));\n        }\n    },\n\n    /**\n     * @private\n     */\n    _splitArea: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) {\n        if (!ticksCoords.length) {\n            return;\n        }\n\n        var splitAreaModel = radiusAxisModel.getModel('splitArea');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n        var areaColors = areaStyleModel.get('color');\n        var lineCount = 0;\n\n        areaColors = areaColors instanceof Array ? areaColors : [areaColors];\n\n        var splitAreas = [];\n\n        var prevRadius = ticksCoords[0].coord;\n        for (var i = 1; i < ticksCoords.length; i++) {\n            var colorIndex = (lineCount++) % areaColors.length;\n            splitAreas[colorIndex] = splitAreas[colorIndex] || [];\n            splitAreas[colorIndex].push(new Sector({\n                shape: {\n                    cx: polar.cx,\n                    cy: polar.cy,\n                    r0: prevRadius,\n                    r: ticksCoords[i].coord,\n                    startAngle: 0,\n                    endAngle: Math.PI * 2\n                },\n                silent: true\n            }));\n            prevRadius = ticksCoords[i].coord;\n        }\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        for (var i = 0; i < splitAreas.length; i++) {\n            this.group.add(mergePath(splitAreas[i], {\n                style: defaults({\n                    fill: areaColors[i % areaColors.length]\n                }, areaStyleModel.getAreaStyle()),\n                silent: true\n            }));\n        }\n    }\n});\n\n/**\n * @inner\n */\nfunction layoutAxis(polar, radiusAxisModel, axisAngle) {\n    return {\n        position: [polar.cx, polar.cy],\n        rotation: axisAngle / 180 * Math.PI,\n        labelDirection: -1,\n        tickDirection: -1,\n        nameDirection: 1,\n        labelRotate: radiusAxisModel.getModel('axisLabel').get('rotate'),\n        // Over splitLine and splitArea\n        z2: 1\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PolarAxisPointer = BaseAxisPointer.extend({\n\n    /**\n     * @override\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        var axis = axisModel.axis;\n\n        if (axis.dim === 'angle') {\n            this.animationThreshold = Math.PI / 18;\n        }\n\n        var polar = axis.polar;\n        var otherAxis = polar.getOtherAxis(axis);\n        var otherExtent = otherAxis.getExtent();\n\n        var coordValue;\n        coordValue = axis['dataTo' + capitalFirst(axis.dim)](value);\n\n        var axisPointerType = axisPointerModel.get('type');\n        if (axisPointerType && axisPointerType !== 'none') {\n            var elStyle = buildElStyle(axisPointerModel);\n            var pointerOption = pointerShapeBuilder$2[axisPointerType](\n                axis, polar, coordValue, otherExtent, elStyle\n            );\n            pointerOption.style = elStyle;\n            elOption.graphicKey = pointerOption.type;\n            elOption.pointer = pointerOption;\n        }\n\n        var labelMargin = axisPointerModel.get('label.margin');\n        var labelPos = getLabelPosition(value, axisModel, axisPointerModel, polar, labelMargin);\n        buildLabelElOption(elOption, axisModel, axisPointerModel, api, labelPos);\n    }\n\n    // Do not support handle, utill any user requires it.\n\n});\n\nfunction getLabelPosition(value, axisModel, axisPointerModel, polar, labelMargin) {\n    var axis = axisModel.axis;\n    var coord = axis.dataToCoord(value);\n    var axisAngle = polar.getAngleAxis().getExtent()[0];\n    axisAngle = axisAngle / 180 * Math.PI;\n    var radiusExtent = polar.getRadiusAxis().getExtent();\n    var position;\n    var align;\n    var verticalAlign;\n\n    if (axis.dim === 'radius') {\n        var transform = create$1();\n        rotate(transform, transform, axisAngle);\n        translate(transform, transform, [polar.cx, polar.cy]);\n        position = applyTransform$1([coord, -labelMargin], transform);\n\n        var labelRotation = axisModel.getModel('axisLabel').get('rotate') || 0;\n        var labelLayout = AxisBuilder.innerTextLayout(\n            axisAngle, labelRotation * Math.PI / 180, -1\n        );\n        align = labelLayout.textAlign;\n        verticalAlign = labelLayout.textVerticalAlign;\n    }\n    else { // angle axis\n        var r = radiusExtent[1];\n        position = polar.coordToPoint([r + labelMargin, coord]);\n        var cx = polar.cx;\n        var cy = polar.cy;\n        align = Math.abs(position[0] - cx) / r < 0.3\n            ? 'center' : (position[0] > cx ? 'left' : 'right');\n        verticalAlign = Math.abs(position[1] - cy) / r < 0.3\n            ? 'middle' : (position[1] > cy ? 'top' : 'bottom');\n    }\n\n    return {\n        position: position,\n        align: align,\n        verticalAlign: verticalAlign\n    };\n}\n\n\nvar pointerShapeBuilder$2 = {\n\n    line: function (axis, polar, coordValue, otherExtent, elStyle) {\n        return axis.dim === 'angle'\n            ? {\n                type: 'Line',\n                shape: makeLineShape(\n                    polar.coordToPoint([otherExtent[0], coordValue]),\n                    polar.coordToPoint([otherExtent[1], coordValue])\n                )\n            }\n            : {\n                type: 'Circle',\n                shape: {\n                    cx: polar.cx,\n                    cy: polar.cy,\n                    r: coordValue\n                }\n            };\n    },\n\n    shadow: function (axis, polar, coordValue, otherExtent, elStyle) {\n        var bandWidth = Math.max(1, axis.getBandWidth());\n        var radian = Math.PI / 180;\n\n        return axis.dim === 'angle'\n            ? {\n                type: 'Sector',\n                shape: makeSectorShape(\n                    polar.cx, polar.cy,\n                    otherExtent[0], otherExtent[1],\n                    // In ECharts y is negative if angle is positive\n                    (-coordValue - bandWidth / 2) * radian,\n                    (-coordValue + bandWidth / 2) * radian\n                )\n            }\n            : {\n                type: 'Sector',\n                shape: makeSectorShape(\n                    polar.cx, polar.cy,\n                    coordValue - bandWidth / 2,\n                    coordValue + bandWidth / 2,\n                    0, Math.PI * 2\n                )\n            };\n    }\n};\n\nAxisView.registerAxisPointerClass('PolarAxisPointer', PolarAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// For reducing size of echarts.min, barLayoutPolar is required by polar.\nregisterLayout(curry(barLayoutPolar, 'bar'));\n\n// Polar view\nextendComponentView({\n    type: 'polar'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar GeoModel = ComponentModel.extend({\n\n    type: 'geo',\n\n    /**\n     * @type {module:echarts/coord/geo/Geo}\n     */\n    coordinateSystem: null,\n\n    layoutMode: 'box',\n\n    init: function (option) {\n        ComponentModel.prototype.init.apply(this, arguments);\n\n        // Default label emphasis `show`\n        defaultEmphasis(option, 'label', ['show']);\n    },\n\n    optionUpdated: function () {\n        var option = this.option;\n        var self = this;\n\n        option.regions = geoCreator.getFilledRegions(option.regions, option.map, option.nameMap);\n\n        this._optionModelMap = reduce(option.regions || [], function (optionModelMap, regionOpt) {\n            if (regionOpt.name) {\n                optionModelMap.set(regionOpt.name, new Model(regionOpt, self));\n            }\n            return optionModelMap;\n        }, createHashMap());\n\n        this.updateSelectedMap(option.regions);\n    },\n\n    defaultOption: {\n\n        zlevel: 0,\n\n        z: 0,\n\n        show: true,\n\n        left: 'center',\n\n        top: 'center',\n\n\n        // width:,\n        // height:,\n        // right\n        // bottom\n\n        // Aspect is width / height. Inited to be geoJson bbox aspect\n        // This parameter is used for scale this aspect\n        // If svg used, aspectScale is 1 by default.\n        // aspectScale: 0.75,\n        aspectScale: null,\n\n        ///// Layout with center and size\n        // If you wan't to put map in a fixed size box with right aspect ratio\n        // This two properties may more conveninet\n        // layoutCenter: [50%, 50%]\n        // layoutSize: 100\n\n        silent: false,\n\n        // Map type\n        map: '',\n\n        // Define left-top, right-bottom coords to control view\n        // For example, [ [180, 90], [-180, -90] ]\n        boundingCoords: null,\n\n        // Default on center of map\n        center: null,\n\n        zoom: 1,\n\n        scaleLimit: null,\n\n        // selectedMode: false\n\n        label: {\n            show: false,\n            color: '#000'\n        },\n\n        itemStyle: {\n            // color: 各异,\n            borderWidth: 0.5,\n            borderColor: '#444',\n            color: '#eee'\n        },\n\n        emphasis: {\n            label: {\n                show: true,\n                color: 'rgb(100,0,0)'\n            },\n            itemStyle: {\n                color: 'rgba(255,215,0,0.8)'\n            }\n        },\n\n        regions: []\n    },\n\n    /**\n     * Get model of region\n     * @param  {string} name\n     * @return {module:echarts/model/Model}\n     */\n    getRegionModel: function (name) {\n        return this._optionModelMap.get(name) || new Model(null, this, this.ecModel);\n    },\n\n    /**\n     * Format label\n     * @param {string} name Region name\n     * @param {string} [status='normal'] 'normal' or 'emphasis'\n     * @return {string}\n     */\n    getFormattedLabel: function (name, status) {\n        var regionModel = this.getRegionModel(name);\n        var formatter = regionModel.get('label.' + status + '.formatter');\n        var params = {\n            name: name\n        };\n        if (typeof formatter === 'function') {\n            params.status = status;\n            return formatter(params);\n        }\n        else if (typeof formatter === 'string') {\n            return formatter.replace('{a}', name != null ? name : '');\n        }\n    },\n\n    setZoom: function (zoom) {\n        this.option.zoom = zoom;\n    },\n\n    setCenter: function (center) {\n        this.option.center = center;\n    }\n});\n\nmixin(GeoModel, selectableMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentView({\n\n    type: 'geo',\n\n    init: function (ecModel, api) {\n        var mapDraw = new MapDraw(api, true);\n        this._mapDraw = mapDraw;\n\n        this.group.add(mapDraw.group);\n    },\n\n    render: function (geoModel, ecModel, api, payload) {\n        // Not render if it is an toggleSelect action from self\n        if (payload && payload.type === 'geoToggleSelect'\n            && payload.from === this.uid\n        ) {\n            return;\n        }\n\n        var mapDraw = this._mapDraw;\n        if (geoModel.get('show')) {\n            mapDraw.draw(geoModel, ecModel, api, this, payload);\n        }\n        else {\n            this._mapDraw.group.removeAll();\n        }\n\n        this.group.silent = geoModel.get('silent');\n    },\n\n    dispose: function () {\n        this._mapDraw && this._mapDraw.remove();\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction makeAction(method, actionInfo) {\n    actionInfo.update = 'updateView';\n    registerAction(actionInfo, function (payload, ecModel) {\n        var selected = {};\n\n        ecModel.eachComponent(\n            { mainType: 'geo', query: payload},\n            function (geoModel) {\n                geoModel[method](payload.name);\n                var geo = geoModel.coordinateSystem;\n                each$1(geo.regions, function (region) {\n                    selected[region.name] = geoModel.isSelected(region.name) || false;\n                });\n            }\n        );\n\n        return {\n            selected: selected,\n            name: payload.name\n        };\n    });\n}\n\nmakeAction('toggleSelected', {\n    type: 'geoToggleSelect',\n    event: 'geoselectchanged'\n});\nmakeAction('select', {\n    type: 'geoSelect',\n    event: 'geoselected'\n});\nmakeAction('unSelect', {\n    type: 'geoUnSelect',\n    event: 'geounselected'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DEFAULT_TOOLBOX_BTNS = ['rect', 'polygon', 'keep', 'clear'];\n\nvar preprocessor$1 = function (option, isNew) {\n    var brushComponents = option && option.brush;\n    if (!isArray(brushComponents)) {\n        brushComponents = brushComponents ? [brushComponents] : [];\n    }\n\n    if (!brushComponents.length) {\n        return;\n    }\n\n    var brushComponentSpecifiedBtns = [];\n\n    each$1(brushComponents, function (brushOpt) {\n        var tbs = brushOpt.hasOwnProperty('toolbox')\n            ? brushOpt.toolbox : [];\n\n        if (tbs instanceof Array) {\n            brushComponentSpecifiedBtns = brushComponentSpecifiedBtns.concat(tbs);\n        }\n    });\n\n    var toolbox = option && option.toolbox;\n\n    if (isArray(toolbox)) {\n        toolbox = toolbox[0];\n    }\n    if (!toolbox) {\n        toolbox = {feature: {}};\n        option.toolbox = [toolbox];\n    }\n\n    var toolboxFeature = (toolbox.feature || (toolbox.feature = {}));\n    var toolboxBrush = toolboxFeature.brush || (toolboxFeature.brush = {});\n    var brushTypes = toolboxBrush.type || (toolboxBrush.type = []);\n\n    brushTypes.push.apply(brushTypes, brushComponentSpecifiedBtns);\n\n    removeDuplicate(brushTypes);\n\n    if (isNew && !brushTypes.length) {\n        brushTypes.push.apply(brushTypes, DEFAULT_TOOLBOX_BTNS);\n    }\n};\n\nfunction removeDuplicate(arr) {\n    var map$$1 = {};\n    each$1(arr, function (val) {\n        map$$1[val] = 1;\n    });\n    arr.length = 0;\n    each$1(map$$1, function (flag, val) {\n        arr.push(val);\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Visual solution, for consistent option specification.\n */\n\nvar each$19 = each$1;\n\nfunction hasKeys(obj) {\n    if (obj) {\n        for (var name in obj) {\n            if (obj.hasOwnProperty(name)) {\n                return true;\n            }\n        }\n    }\n}\n\n/**\n * @param {Object} option\n * @param {Array.<string>} stateList\n * @param {Function} [supplementVisualOption]\n * @return {Object} visualMappings <state, <visualType, module:echarts/visual/VisualMapping>>\n */\nfunction createVisualMappings(option, stateList, supplementVisualOption) {\n    var visualMappings = {};\n\n    each$19(stateList, function (state) {\n        var mappings = visualMappings[state] = createMappings();\n\n        each$19(option[state], function (visualData, visualType) {\n            if (!VisualMapping.isValidType(visualType)) {\n                return;\n            }\n            var mappingOption = {\n                type: visualType,\n                visual: visualData\n            };\n            supplementVisualOption && supplementVisualOption(mappingOption, state);\n            mappings[visualType] = new VisualMapping(mappingOption);\n\n            // Prepare a alpha for opacity, for some case that opacity\n            // is not supported, such as rendering using gradient color.\n            if (visualType === 'opacity') {\n                mappingOption = clone(mappingOption);\n                mappingOption.type = 'colorAlpha';\n                mappings.__hidden.__alphaForOpacity = new VisualMapping(mappingOption);\n            }\n        });\n    });\n\n    return visualMappings;\n\n    function createMappings() {\n        var Creater = function () {};\n        // Make sure hidden fields will not be visited by\n        // object iteration (with hasOwnProperty checking).\n        Creater.prototype.__hidden = Creater.prototype;\n        var obj = new Creater();\n        return obj;\n    }\n}\n\n/**\n * @param {Object} thisOption\n * @param {Object} newOption\n * @param {Array.<string>} keys\n */\nfunction replaceVisualOption(thisOption, newOption, keys) {\n    // Visual attributes merge is not supported, otherwise it\n    // brings overcomplicated merge logic. See #2853. So if\n    // newOption has anyone of these keys, all of these keys\n    // will be reset. Otherwise, all keys remain.\n    var has;\n    each$1(keys, function (key) {\n        if (newOption.hasOwnProperty(key) && hasKeys(newOption[key])) {\n            has = true;\n        }\n    });\n    has && each$1(keys, function (key) {\n        if (newOption.hasOwnProperty(key) && hasKeys(newOption[key])) {\n            thisOption[key] = clone(newOption[key]);\n        }\n        else {\n            delete thisOption[key];\n        }\n    });\n}\n\n/**\n * @param {Array.<string>} stateList\n * @param {Object} visualMappings <state, Object.<visualType, module:echarts/visual/VisualMapping>>\n * @param {module:echarts/data/List} list\n * @param {Function} getValueState param: valueOrIndex, return: state.\n * @param {object} [scope] Scope for getValueState\n * @param {string} [dimension] Concrete dimension, if used.\n */\n// ???! handle brush?\nfunction applyVisual(stateList, visualMappings, data, getValueState, scope, dimension) {\n    var visualTypesMap = {};\n    each$1(stateList, function (state) {\n        var visualTypes = VisualMapping.prepareVisualTypes(visualMappings[state]);\n        visualTypesMap[state] = visualTypes;\n    });\n\n    var dataIndex;\n\n    function getVisual(key) {\n        return data.getItemVisual(dataIndex, key);\n    }\n\n    function setVisual(key, value) {\n        data.setItemVisual(dataIndex, key, value);\n    }\n\n    if (dimension == null) {\n        data.each(eachItem);\n    }\n    else {\n        data.each([dimension], eachItem);\n    }\n\n    function eachItem(valueOrIndex, index) {\n        dataIndex = dimension == null ? valueOrIndex : index;\n\n        var rawDataItem = data.getRawDataItem(dataIndex);\n        // Consider performance\n        if (rawDataItem && rawDataItem.visualMap === false) {\n            return;\n        }\n\n        var valueState = getValueState.call(scope, valueOrIndex);\n        var mappings = visualMappings[valueState];\n        var visualTypes = visualTypesMap[valueState];\n\n        for (var i = 0, len = visualTypes.length; i < len; i++) {\n            var type = visualTypes[i];\n            mappings[type] && mappings[type].applyVisual(\n                valueOrIndex, getVisual, setVisual\n            );\n        }\n    }\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {Array.<string>} stateList\n * @param {Object} visualMappings <state, Object.<visualType, module:echarts/visual/VisualMapping>>\n * @param {Function} getValueState param: valueOrIndex, return: state.\n * @param {number} [dim] dimension or dimension index.\n */\nfunction incrementalApplyVisual(stateList, visualMappings, getValueState, dim) {\n    var visualTypesMap = {};\n    each$1(stateList, function (state) {\n        var visualTypes = VisualMapping.prepareVisualTypes(visualMappings[state]);\n        visualTypesMap[state] = visualTypes;\n    });\n\n    function progress(params, data) {\n        if (dim != null) {\n            dim = data.getDimension(dim);\n        }\n\n        function getVisual(key) {\n            return data.getItemVisual(dataIndex, key);\n        }\n\n        function setVisual(key, value) {\n            data.setItemVisual(dataIndex, key, value);\n        }\n\n        var dataIndex;\n        while ((dataIndex = params.next()) != null) {\n            var rawDataItem = data.getRawDataItem(dataIndex);\n\n            // Consider performance\n            if (rawDataItem && rawDataItem.visualMap === false) {\n                continue;\n            }\n\n            var value = dim != null\n                ? data.get(dim, dataIndex, true)\n                : dataIndex;\n\n            var valueState = getValueState(value);\n            var mappings = visualMappings[valueState];\n            var visualTypes = visualTypesMap[valueState];\n\n            for (var i = 0, len = visualTypes.length; i < len; i++) {\n                var type = visualTypes[i];\n                mappings[type] && mappings[type].applyVisual(value, getVisual, setVisual);\n            }\n        }\n    }\n\n    return {progress: progress};\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Key of the first level is brushType: `line`, `rect`, `polygon`.\n// Key of the second level is chart element type: `point`, `rect`.\n// See moudule:echarts/component/helper/BrushController\n// function param:\n//      {Object} itemLayout fetch from data.getItemLayout(dataIndex)\n//      {Object} selectors {point: selector, rect: selector, ...}\n//      {Object} area {range: [[], [], ..], boudingRect}\n// function return:\n//      {boolean} Whether in the given brush.\nvar selector = {\n    lineX: getLineSelectors(0),\n    lineY: getLineSelectors(1),\n    rect: {\n        point: function (itemLayout, selectors, area) {\n            return itemLayout && area.boundingRect.contain(itemLayout[0], itemLayout[1]);\n        },\n        rect: function (itemLayout, selectors, area) {\n            return itemLayout && area.boundingRect.intersect(itemLayout);\n        }\n    },\n    polygon: {\n        point: function (itemLayout, selectors, area) {\n            return itemLayout\n                && area.boundingRect.contain(itemLayout[0], itemLayout[1])\n                && contain$1(area.range, itemLayout[0], itemLayout[1]);\n        },\n        rect: function (itemLayout, selectors, area) {\n            var points = area.range;\n\n            if (!itemLayout || points.length <= 1) {\n                return false;\n            }\n\n            var x = itemLayout.x;\n            var y = itemLayout.y;\n            var width = itemLayout.width;\n            var height = itemLayout.height;\n            var p = points[0];\n\n            if (contain$1(points, x, y)\n                || contain$1(points, x + width, y)\n                || contain$1(points, x, y + height)\n                || contain$1(points, x + width, y + height)\n                || BoundingRect.create(itemLayout).contain(p[0], p[1])\n                || lineIntersectPolygon(x, y, x + width, y, points)\n                || lineIntersectPolygon(x, y, x, y + height, points)\n                || lineIntersectPolygon(x + width, y, x + width, y + height, points)\n                || lineIntersectPolygon(x, y + height, x + width, y + height, points)\n            ) {\n                return true;\n            }\n        }\n    }\n};\n\nfunction getLineSelectors(xyIndex) {\n    var xy = ['x', 'y'];\n    var wh = ['width', 'height'];\n\n    return {\n        point: function (itemLayout, selectors, area) {\n            if (itemLayout) {\n                var range = area.range;\n                var p = itemLayout[xyIndex];\n                return inLineRange(p, range);\n            }\n        },\n        rect: function (itemLayout, selectors, area) {\n            if (itemLayout) {\n                var range = area.range;\n                var layoutRange = [\n                    itemLayout[xy[xyIndex]],\n                    itemLayout[xy[xyIndex]] + itemLayout[wh[xyIndex]]\n                ];\n                layoutRange[1] < layoutRange[0] && layoutRange.reverse();\n                return inLineRange(layoutRange[0], range)\n                    || inLineRange(layoutRange[1], range)\n                    || inLineRange(range[0], layoutRange)\n                    || inLineRange(range[1], layoutRange);\n            }\n        }\n    };\n}\n\nfunction inLineRange(p, range) {\n    return range[0] <= p && p <= range[1];\n}\n\nfunction lineIntersectPolygon(lx, ly, l2x, l2y, points) {\n    for (var i = 0, p2 = points[points.length - 1]; i < points.length; i++) {\n        var p = points[i];\n        if (lineIntersect(lx, ly, l2x, l2y, p[0], p[1], p2[0], p2[1])) {\n            return true;\n        }\n        p2 = p;\n    }\n}\n\n// Code from <http://blog.csdn.net/rickliuxiao/article/details/6259322> with some fix.\n// See <https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection>\nfunction lineIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y) {\n    var delta = determinant(a2x - a1x, b1x - b2x, a2y - a1y, b1y - b2y);\n    if (nearZero(delta)) { // parallel\n        return false;\n    }\n    var namenda = determinant(b1x - a1x, b1x - b2x, b1y - a1y, b1y - b2y) / delta;\n    if (namenda < 0 || namenda > 1) {\n        return false;\n    }\n    var miu = determinant(a2x - a1x, b1x - a1x, a2y - a1y, b1y - a1y) / delta;\n    if (miu < 0 || miu > 1) {\n        return false;\n    }\n    return true;\n}\n\nfunction nearZero(val) {\n    return val <= (1e-6) && val >= -(1e-6);\n}\n\nfunction determinant(v1, v2, v3, v4) {\n    return v1 * v4 - v2 * v3;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$20 = each$1;\nvar indexOf$1 = indexOf;\nvar curry$5 = curry;\n\nvar COORD_CONVERTS = ['dataToPoint', 'pointToData'];\n\n// FIXME\n// how to genarialize to more coordinate systems.\nvar INCLUDE_FINDER_MAIN_TYPES = [\n    'grid', 'xAxis', 'yAxis', 'geo', 'graph',\n    'polar', 'radiusAxis', 'angleAxis', 'bmap'\n];\n\n/**\n * [option in constructor]:\n * {\n *     Index/Id/Name of geo, xAxis, yAxis, grid: See util/model#parseFinder.\n * }\n *\n *\n * [targetInfo]:\n *\n * There can be multiple axes in a single targetInfo. Consider the case\n * of `grid` component, a targetInfo represents a grid which contains one or more\n * cartesian and one or more axes. And consider the case of parallel system,\n * which has multiple axes in a coordinate system.\n * Can be {\n *     panelId: ...,\n *     coordSys: <a representitive cartesian in grid (first cartesian by default)>,\n *     coordSyses: all cartesians.\n *     gridModel: <grid component>\n *     xAxes: correspond to coordSyses on index\n *     yAxes: correspond to coordSyses on index\n * }\n * or {\n *     panelId: ...,\n *     coordSys: <geo coord sys>\n *     coordSyses: [<geo coord sys>]\n *     geoModel: <geo component>\n * }\n *\n *\n * [panelOpt]:\n *\n * Make from targetInfo. Input to BrushController.\n * {\n *     panelId: ...,\n *     rect: ...\n * }\n *\n *\n * [area]:\n *\n * Generated by BrushController or user input.\n * {\n *     panelId: Used to locate coordInfo directly. If user inpput, no panelId.\n *     brushType: determine how to convert to/from coord('rect' or 'polygon' or 'lineX/Y').\n *     Index/Id/Name of geo, xAxis, yAxis, grid: See util/model#parseFinder.\n *     range: pixel range.\n *     coordRange: representitive coord range (the first one of coordRanges).\n *     coordRanges: <Array> coord ranges, used in multiple cartesian in one grid.\n * }\n */\n\n/**\n * @param {Object} option contains Index/Id/Name of xAxis/yAxis/geo/grid\n *        Each can be {number|Array.<number>}. like: {xAxisIndex: [3, 4]}\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} [opt]\n * @param {Array.<string>} [opt.include] include coordinate system types.\n */\nfunction BrushTargetManager(option, ecModel, opt) {\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    var targetInfoList = this._targetInfoList = [];\n    var info = {};\n    var foundCpts = parseFinder$1(ecModel, option);\n\n    each$20(targetInfoBuilders, function (builder, type) {\n        if (!opt || !opt.include || indexOf$1(opt.include, type) >= 0) {\n            builder(foundCpts, targetInfoList, info);\n        }\n    });\n}\n\nvar proto$2 = BrushTargetManager.prototype;\n\nproto$2.setOutputRanges = function (areas, ecModel) {\n    this.matchOutputRanges(areas, ecModel, function (area, coordRange, coordSys) {\n        (area.coordRanges || (area.coordRanges = [])).push(coordRange);\n        // area.coordRange is the first of area.coordRanges\n        if (!area.coordRange) {\n            area.coordRange = coordRange;\n            // In 'category' axis, coord to pixel is not reversible, so we can not\n            // rebuild range by coordRange accrately, which may bring trouble when\n            // brushing only one item. So we use __rangeOffset to rebuilding range\n            // by coordRange. And this it only used in brush component so it is no\n            // need to be adapted to coordRanges.\n            var result = coordConvert[area.brushType](0, coordSys, coordRange);\n            area.__rangeOffset = {\n                offset: diffProcessor[area.brushType](result.values, area.range, [1, 1]),\n                xyMinMax: result.xyMinMax\n            };\n        }\n    });\n};\n\nproto$2.matchOutputRanges = function (areas, ecModel, cb) {\n    each$20(areas, function (area) {\n        var targetInfo = this.findTargetInfo(area, ecModel);\n\n        if (targetInfo && targetInfo !== true) {\n            each$1(\n                targetInfo.coordSyses,\n                function (coordSys) {\n                    var result = coordConvert[area.brushType](1, coordSys, area.range);\n                    cb(area, result.values, coordSys, ecModel);\n                }\n            );\n        }\n    }, this);\n};\n\nproto$2.setInputRanges = function (areas, ecModel) {\n    each$20(areas, function (area) {\n        var targetInfo = this.findTargetInfo(area, ecModel);\n\n        if (__DEV__) {\n            assert$1(\n                !targetInfo || targetInfo === true || area.coordRange,\n                'coordRange must be specified when coord index specified.'\n            );\n            assert$1(\n                !targetInfo || targetInfo !== true || area.range,\n                'range must be specified in global brush.'\n            );\n        }\n\n        area.range = area.range || [];\n\n        // convert coordRange to global range and set panelId.\n        if (targetInfo && targetInfo !== true) {\n            area.panelId = targetInfo.panelId;\n            // (1) area.range shoule always be calculate from coordRange but does\n            // not keep its original value, for the sake of the dataZoom scenario,\n            // where area.coordRange remains unchanged but area.range may be changed.\n            // (2) Only support converting one coordRange to pixel range in brush\n            // component. So do not consider `coordRanges`.\n            // (3) About __rangeOffset, see comment above.\n            var result = coordConvert[area.brushType](0, targetInfo.coordSys, area.coordRange);\n            var rangeOffset = area.__rangeOffset;\n            area.range = rangeOffset\n                ? diffProcessor[area.brushType](\n                    result.values,\n                    rangeOffset.offset,\n                    getScales(result.xyMinMax, rangeOffset.xyMinMax)\n                )\n                : result.values;\n        }\n    }, this);\n};\n\nproto$2.makePanelOpts = function (api, getDefaultBrushType) {\n    return map(this._targetInfoList, function (targetInfo) {\n        var rect = targetInfo.getPanelRect();\n        return {\n            panelId: targetInfo.panelId,\n            defaultBrushType: getDefaultBrushType && getDefaultBrushType(targetInfo),\n            clipPath: makeRectPanelClipPath(rect),\n            isTargetByCursor: makeRectIsTargetByCursor(\n                rect, api, targetInfo.coordSysModel\n            ),\n            getLinearBrushOtherExtent: makeLinearBrushOtherExtent(rect)\n        };\n    });\n};\n\nproto$2.controlSeries = function (area, seriesModel, ecModel) {\n    // Check whether area is bound in coord, and series do not belong to that coord.\n    // If do not do this check, some brush (like lineX) will controll all axes.\n    var targetInfo = this.findTargetInfo(area, ecModel);\n    return targetInfo === true || (\n        targetInfo && indexOf$1(targetInfo.coordSyses, seriesModel.coordinateSystem) >= 0\n    );\n};\n\n/**\n * If return Object, a coord found.\n * If reutrn true, global found.\n * Otherwise nothing found.\n *\n * @param {Object} area\n * @param {Array} targetInfoList\n * @return {Object|boolean}\n */\nproto$2.findTargetInfo = function (area, ecModel) {\n    var targetInfoList = this._targetInfoList;\n    var foundCpts = parseFinder$1(ecModel, area);\n\n    for (var i = 0; i < targetInfoList.length; i++) {\n        var targetInfo = targetInfoList[i];\n        var areaPanelId = area.panelId;\n        if (areaPanelId) {\n            if (targetInfo.panelId === areaPanelId) {\n                return targetInfo;\n            }\n        }\n        else {\n            for (var i = 0; i < targetInfoMatchers.length; i++) {\n                if (targetInfoMatchers[i](foundCpts, targetInfo)) {\n                    return targetInfo;\n                }\n            }\n        }\n    }\n\n    return true;\n};\n\nfunction formatMinMax(minMax) {\n    minMax[0] > minMax[1] && minMax.reverse();\n    return minMax;\n}\n\nfunction parseFinder$1(ecModel, option) {\n    return parseFinder(\n        ecModel, option, {includeMainTypes: INCLUDE_FINDER_MAIN_TYPES}\n    );\n}\n\nvar targetInfoBuilders = {\n\n    grid: function (foundCpts, targetInfoList) {\n        var xAxisModels = foundCpts.xAxisModels;\n        var yAxisModels = foundCpts.yAxisModels;\n        var gridModels = foundCpts.gridModels;\n        // Remove duplicated.\n        var gridModelMap = createHashMap();\n        var xAxesHas = {};\n        var yAxesHas = {};\n\n        if (!xAxisModels && !yAxisModels && !gridModels) {\n            return;\n        }\n\n        each$20(xAxisModels, function (axisModel) {\n            var gridModel = axisModel.axis.grid.model;\n            gridModelMap.set(gridModel.id, gridModel);\n            xAxesHas[gridModel.id] = true;\n        });\n        each$20(yAxisModels, function (axisModel) {\n            var gridModel = axisModel.axis.grid.model;\n            gridModelMap.set(gridModel.id, gridModel);\n            yAxesHas[gridModel.id] = true;\n        });\n        each$20(gridModels, function (gridModel) {\n            gridModelMap.set(gridModel.id, gridModel);\n            xAxesHas[gridModel.id] = true;\n            yAxesHas[gridModel.id] = true;\n        });\n\n        gridModelMap.each(function (gridModel) {\n            var grid = gridModel.coordinateSystem;\n            var cartesians = [];\n\n            each$20(grid.getCartesians(), function (cartesian, index) {\n                if (indexOf$1(xAxisModels, cartesian.getAxis('x').model) >= 0\n                    || indexOf$1(yAxisModels, cartesian.getAxis('y').model) >= 0\n                ) {\n                    cartesians.push(cartesian);\n                }\n            });\n            targetInfoList.push({\n                panelId: 'grid--' + gridModel.id,\n                gridModel: gridModel,\n                coordSysModel: gridModel,\n                // Use the first one as the representitive coordSys.\n                coordSys: cartesians[0],\n                coordSyses: cartesians,\n                getPanelRect: panelRectBuilder.grid,\n                xAxisDeclared: xAxesHas[gridModel.id],\n                yAxisDeclared: yAxesHas[gridModel.id]\n            });\n        });\n    },\n\n    geo: function (foundCpts, targetInfoList) {\n        each$20(foundCpts.geoModels, function (geoModel) {\n            var coordSys = geoModel.coordinateSystem;\n            targetInfoList.push({\n                panelId: 'geo--' + geoModel.id,\n                geoModel: geoModel,\n                coordSysModel: geoModel,\n                coordSys: coordSys,\n                coordSyses: [coordSys],\n                getPanelRect: panelRectBuilder.geo\n            });\n        });\n    }\n};\n\nvar targetInfoMatchers = [\n\n    // grid\n    function (foundCpts, targetInfo) {\n        var xAxisModel = foundCpts.xAxisModel;\n        var yAxisModel = foundCpts.yAxisModel;\n        var gridModel = foundCpts.gridModel;\n\n        !gridModel && xAxisModel && (gridModel = xAxisModel.axis.grid.model);\n        !gridModel && yAxisModel && (gridModel = yAxisModel.axis.grid.model);\n\n        return gridModel && gridModel === targetInfo.gridModel;\n    },\n\n    // geo\n    function (foundCpts, targetInfo) {\n        var geoModel = foundCpts.geoModel;\n        return geoModel && geoModel === targetInfo.geoModel;\n    }\n];\n\nvar panelRectBuilder = {\n\n    grid: function () {\n        // grid is not Transformable.\n        return this.coordSys.grid.getRect().clone();\n    },\n\n    geo: function () {\n        var coordSys = this.coordSys;\n        var rect = coordSys.getBoundingRect().clone();\n        // geo roam and zoom transform\n        rect.applyTransform(getTransform(coordSys));\n        return rect;\n    }\n};\n\nvar coordConvert = {\n\n    lineX: curry$5(axisConvert, 0),\n\n    lineY: curry$5(axisConvert, 1),\n\n    rect: function (to, coordSys, rangeOrCoordRange) {\n        var xminymin = coordSys[COORD_CONVERTS[to]]([rangeOrCoordRange[0][0], rangeOrCoordRange[1][0]]);\n        var xmaxymax = coordSys[COORD_CONVERTS[to]]([rangeOrCoordRange[0][1], rangeOrCoordRange[1][1]]);\n        var values = [\n            formatMinMax([xminymin[0], xmaxymax[0]]),\n            formatMinMax([xminymin[1], xmaxymax[1]])\n        ];\n        return {values: values, xyMinMax: values};\n    },\n\n    polygon: function (to, coordSys, rangeOrCoordRange) {\n        var xyMinMax = [[Infinity, -Infinity], [Infinity, -Infinity]];\n        var values = map(rangeOrCoordRange, function (item) {\n            var p = coordSys[COORD_CONVERTS[to]](item);\n            xyMinMax[0][0] = Math.min(xyMinMax[0][0], p[0]);\n            xyMinMax[1][0] = Math.min(xyMinMax[1][0], p[1]);\n            xyMinMax[0][1] = Math.max(xyMinMax[0][1], p[0]);\n            xyMinMax[1][1] = Math.max(xyMinMax[1][1], p[1]);\n            return p;\n        });\n        return {values: values, xyMinMax: xyMinMax};\n    }\n};\n\nfunction axisConvert(axisNameIndex, to, coordSys, rangeOrCoordRange) {\n    if (__DEV__) {\n        assert$1(\n            coordSys.type === 'cartesian2d',\n            'lineX/lineY brush is available only in cartesian2d.'\n        );\n    }\n\n    var axis = coordSys.getAxis(['x', 'y'][axisNameIndex]);\n    var values = formatMinMax(map([0, 1], function (i) {\n        return to\n            ? axis.coordToData(axis.toLocalCoord(rangeOrCoordRange[i]))\n            : axis.toGlobalCoord(axis.dataToCoord(rangeOrCoordRange[i]));\n    }));\n    var xyMinMax = [];\n    xyMinMax[axisNameIndex] = values;\n    xyMinMax[1 - axisNameIndex] = [NaN, NaN];\n\n    return {values: values, xyMinMax: xyMinMax};\n}\n\nvar diffProcessor = {\n    lineX: curry$5(axisDiffProcessor, 0),\n\n    lineY: curry$5(axisDiffProcessor, 1),\n\n    rect: function (values, refer, scales) {\n        return [\n            [values[0][0] - scales[0] * refer[0][0], values[0][1] - scales[0] * refer[0][1]],\n            [values[1][0] - scales[1] * refer[1][0], values[1][1] - scales[1] * refer[1][1]]\n        ];\n    },\n\n    polygon: function (values, refer, scales) {\n        return map(values, function (item, idx) {\n            return [item[0] - scales[0] * refer[idx][0], item[1] - scales[1] * refer[idx][1]];\n        });\n    }\n};\n\nfunction axisDiffProcessor(axisNameIndex, values, refer, scales) {\n    return [\n        values[0] - scales[axisNameIndex] * refer[0],\n        values[1] - scales[axisNameIndex] * refer[1]\n    ];\n}\n\n// We have to process scale caused by dataZoom manually,\n// although it might be not accurate.\nfunction getScales(xyMinMaxCurr, xyMinMaxOrigin) {\n    var sizeCurr = getSize(xyMinMaxCurr);\n    var sizeOrigin = getSize(xyMinMaxOrigin);\n    var scales = [sizeCurr[0] / sizeOrigin[0], sizeCurr[1] / sizeOrigin[1]];\n    isNaN(scales[0]) && (scales[0] = 1);\n    isNaN(scales[1]) && (scales[1] = 1);\n    return scales;\n}\n\nfunction getSize(xyMinMax) {\n    return xyMinMax\n        ? [xyMinMax[0][1] - xyMinMax[0][0], xyMinMax[1][1] - xyMinMax[1][0]]\n        : [NaN, NaN];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar STATE_LIST = ['inBrush', 'outOfBrush'];\nvar DISPATCH_METHOD = '__ecBrushSelect';\nvar DISPATCH_FLAG = '__ecInBrushSelectEvent';\nvar PRIORITY_BRUSH = PRIORITY.VISUAL.BRUSH;\n\n/**\n * Layout for visual, the priority higher than other layout, and before brush visual.\n */\nregisterLayout(PRIORITY_BRUSH, function (ecModel, api, payload) {\n    ecModel.eachComponent({mainType: 'brush'}, function (brushModel) {\n\n        payload && payload.type === 'takeGlobalCursor' && brushModel.setBrushOption(\n            payload.key === 'brush' ? payload.brushOption : {brushType: false}\n        );\n\n        var brushTargetManager = brushModel.brushTargetManager = new BrushTargetManager(brushModel.option, ecModel);\n\n        brushTargetManager.setInputRanges(brushModel.areas, ecModel);\n    });\n});\n\n/**\n * Register the visual encoding if this modules required.\n */\nregisterVisual(PRIORITY_BRUSH, function (ecModel, api, payload) {\n\n    var brushSelected = [];\n    var throttleType;\n    var throttleDelay;\n\n    ecModel.eachComponent({mainType: 'brush'}, function (brushModel, brushIndex) {\n\n        var thisBrushSelected = {\n            brushId: brushModel.id,\n            brushIndex: brushIndex,\n            brushName: brushModel.name,\n            areas: clone(brushModel.areas),\n            selected: []\n        };\n        // Every brush component exists in event params, convenient\n        // for user to find by index.\n        brushSelected.push(thisBrushSelected);\n\n        var brushOption = brushModel.option;\n        var brushLink = brushOption.brushLink;\n        var linkedSeriesMap = [];\n        var selectedDataIndexForLink = [];\n        var rangeInfoBySeries = [];\n        var hasBrushExists = 0;\n\n        if (!brushIndex) { // Only the first throttle setting works.\n            throttleType = brushOption.throttleType;\n            throttleDelay = brushOption.throttleDelay;\n        }\n\n        // Add boundingRect and selectors to range.\n        var areas = map(brushModel.areas, function (area) {\n            return bindSelector(\n                defaults(\n                    {boundingRect: boundingRectBuilders[area.brushType](area)},\n                    area\n                )\n            );\n        });\n\n        var visualMappings = createVisualMappings(\n            brushModel.option, STATE_LIST, function (mappingOption) {\n                mappingOption.mappingMethod = 'fixed';\n            }\n        );\n\n        isArray(brushLink) && each$1(brushLink, function (seriesIndex) {\n            linkedSeriesMap[seriesIndex] = 1;\n        });\n\n        function linkOthers(seriesIndex) {\n            return brushLink === 'all' || linkedSeriesMap[seriesIndex];\n        }\n\n        // If no supported brush or no brush on the series,\n        // all visuals should be in original state.\n        function brushed(rangeInfoList) {\n            return !!rangeInfoList.length;\n        }\n\n        /**\n         * Logic for each series: (If the logic has to be modified one day, do it carefully!)\n         *\n         * ( brushed ┬ && ┬hasBrushExist ┬ && linkOthers  ) => StepA: ┬record, ┬ StepB: ┬visualByRecord.\n         *   !brushed┘    ├hasBrushExist ┤                            └nothing,┘        ├visualByRecord.\n         *                └!hasBrushExist┘                                              └nothing.\n         * ( !brushed  && ┬hasBrushExist ┬ && linkOthers  ) => StepA:  nothing,  StepB: ┬visualByRecord.\n         *                └!hasBrushExist┘                                              └nothing.\n         * ( brushed ┬ &&                     !linkOthers ) => StepA:  nothing,  StepB: ┬visualByCheck.\n         *   !brushed┘                                                                  └nothing.\n         * ( !brushed  &&                     !linkOthers ) => StepA:  nothing,  StepB:  nothing.\n         */\n\n        // Step A\n        ecModel.eachSeries(function (seriesModel, seriesIndex) {\n            var rangeInfoList = rangeInfoBySeries[seriesIndex] = [];\n\n            seriesModel.subType === 'parallel'\n                ? stepAParallel(seriesModel, seriesIndex, rangeInfoList)\n                : stepAOthers(seriesModel, seriesIndex, rangeInfoList);\n        });\n\n        function stepAParallel(seriesModel, seriesIndex) {\n            var coordSys = seriesModel.coordinateSystem;\n            hasBrushExists |= coordSys.hasAxisBrushed();\n\n            linkOthers(seriesIndex) && coordSys.eachActiveState(\n                seriesModel.getData(),\n                function (activeState, dataIndex) {\n                    activeState === 'active' && (selectedDataIndexForLink[dataIndex] = 1);\n                }\n            );\n        }\n\n        function stepAOthers(seriesModel, seriesIndex, rangeInfoList) {\n            var selectorsByBrushType = getSelectorsByBrushType(seriesModel);\n            if (!selectorsByBrushType || brushModelNotControll(brushModel, seriesIndex)) {\n                return;\n            }\n\n            each$1(areas, function (area) {\n                selectorsByBrushType[area.brushType]\n                    && brushModel.brushTargetManager.controlSeries(area, seriesModel, ecModel)\n                    && rangeInfoList.push(area);\n                hasBrushExists |= brushed(rangeInfoList);\n            });\n\n            if (linkOthers(seriesIndex) && brushed(rangeInfoList)) {\n                var data = seriesModel.getData();\n                data.each(function (dataIndex) {\n                    if (checkInRange(selectorsByBrushType, rangeInfoList, data, dataIndex)) {\n                        selectedDataIndexForLink[dataIndex] = 1;\n                    }\n                });\n            }\n        }\n\n        // Step B\n        ecModel.eachSeries(function (seriesModel, seriesIndex) {\n            var seriesBrushSelected = {\n                seriesId: seriesModel.id,\n                seriesIndex: seriesIndex,\n                seriesName: seriesModel.name,\n                dataIndex: []\n            };\n            // Every series exists in event params, convenient\n            // for user to find series by seriesIndex.\n            thisBrushSelected.selected.push(seriesBrushSelected);\n\n            var selectorsByBrushType = getSelectorsByBrushType(seriesModel);\n            var rangeInfoList = rangeInfoBySeries[seriesIndex];\n\n            var data = seriesModel.getData();\n            var getValueState = linkOthers(seriesIndex)\n                ? function (dataIndex) {\n                    return selectedDataIndexForLink[dataIndex]\n                        ? (seriesBrushSelected.dataIndex.push(data.getRawIndex(dataIndex)), 'inBrush')\n                        : 'outOfBrush';\n                }\n                : function (dataIndex) {\n                    return checkInRange(selectorsByBrushType, rangeInfoList, data, dataIndex)\n                        ? (seriesBrushSelected.dataIndex.push(data.getRawIndex(dataIndex)), 'inBrush')\n                        : 'outOfBrush';\n                };\n\n            // If no supported brush or no brush, all visuals are in original state.\n            (linkOthers(seriesIndex) ? hasBrushExists : brushed(rangeInfoList))\n                && applyVisual(\n                    STATE_LIST, visualMappings, data, getValueState\n                );\n        });\n\n    });\n\n    dispatchAction(api, throttleType, throttleDelay, brushSelected, payload);\n});\n\nfunction dispatchAction(api, throttleType, throttleDelay, brushSelected, payload) {\n    // This event will not be triggered when `setOpion`, otherwise dead lock may\n    // triggered when do `setOption` in event listener, which we do not find\n    // satisfactory way to solve yet. Some considered resolutions:\n    // (a) Diff with prevoius selected data ant only trigger event when changed.\n    // But store previous data and diff precisely (i.e., not only by dataIndex, but\n    // also detect value changes in selected data) might bring complexity or fragility.\n    // (b) Use spectial param like `silent` to suppress event triggering.\n    // But such kind of volatile param may be weird in `setOption`.\n    if (!payload) {\n        return;\n    }\n\n    var zr = api.getZr();\n    if (zr[DISPATCH_FLAG]) {\n        return;\n    }\n\n    if (!zr[DISPATCH_METHOD]) {\n        zr[DISPATCH_METHOD] = doDispatch;\n    }\n\n    var fn = createOrUpdate(zr, DISPATCH_METHOD, throttleDelay, throttleType);\n\n    fn(api, brushSelected);\n}\n\nfunction doDispatch(api, brushSelected) {\n    if (!api.isDisposed()) {\n        var zr = api.getZr();\n        zr[DISPATCH_FLAG] = true;\n        api.dispatchAction({\n            type: 'brushSelect',\n            batch: brushSelected\n        });\n        zr[DISPATCH_FLAG] = false;\n    }\n}\n\nfunction checkInRange(selectorsByBrushType, rangeInfoList, data, dataIndex) {\n    for (var i = 0, len = rangeInfoList.length; i < len; i++) {\n        var area = rangeInfoList[i];\n        if (selectorsByBrushType[area.brushType](\n            dataIndex, data, area.selectors, area\n        )) {\n            return true;\n        }\n    }\n}\n\nfunction getSelectorsByBrushType(seriesModel) {\n    var brushSelector = seriesModel.brushSelector;\n    if (isString(brushSelector)) {\n        var sels = [];\n        each$1(selector, function (selectorsByElementType, brushType) {\n            sels[brushType] = function (dataIndex, data, selectors, area) {\n                var itemLayout = data.getItemLayout(dataIndex);\n                return selectorsByElementType[brushSelector](itemLayout, selectors, area);\n            };\n        });\n        return sels;\n    }\n    else if (isFunction$1(brushSelector)) {\n        var bSelector = {};\n        each$1(selector, function (sel, brushType) {\n            bSelector[brushType] = brushSelector;\n        });\n        return bSelector;\n    }\n    return brushSelector;\n}\n\nfunction brushModelNotControll(brushModel, seriesIndex) {\n    var seriesIndices = brushModel.option.seriesIndex;\n    return seriesIndices != null\n        && seriesIndices !== 'all'\n        && (\n            isArray(seriesIndices)\n            ? indexOf(seriesIndices, seriesIndex) < 0\n            : seriesIndex !== seriesIndices\n        );\n}\n\nfunction bindSelector(area) {\n    var selectors = area.selectors = {};\n    each$1(selector[area.brushType], function (selFn, elType) {\n        // Do not use function binding or curry for performance.\n        selectors[elType] = function (itemLayout) {\n            return selFn(itemLayout, selectors, area);\n        };\n    });\n    return area;\n}\n\nvar boundingRectBuilders = {\n\n    lineX: noop,\n\n    lineY: noop,\n\n    rect: function (area) {\n        return getBoundingRectFromMinMax(area.range);\n    },\n\n    polygon: function (area) {\n        var minMax;\n        var range = area.range;\n\n        for (var i = 0, len = range.length; i < len; i++) {\n            minMax = minMax || [[Infinity, -Infinity], [Infinity, -Infinity]];\n            var rg = range[i];\n            rg[0] < minMax[0][0] && (minMax[0][0] = rg[0]);\n            rg[0] > minMax[0][1] && (minMax[0][1] = rg[0]);\n            rg[1] < minMax[1][0] && (minMax[1][0] = rg[1]);\n            rg[1] > minMax[1][1] && (minMax[1][1] = rg[1]);\n        }\n\n        return minMax && getBoundingRectFromMinMax(minMax);\n    }\n};\n\nfunction getBoundingRectFromMinMax(minMax) {\n    return new BoundingRect(\n        minMax[0][0],\n        minMax[1][0],\n        minMax[0][1] - minMax[0][0],\n        minMax[1][1] - minMax[1][0]\n    );\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DEFAULT_OUT_OF_BRUSH_COLOR = ['#ddd'];\n\nvar BrushModel = extendComponentModel({\n\n    type: 'brush',\n\n    dependencies: ['geo', 'grid', 'xAxis', 'yAxis', 'parallel', 'series'],\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        // inBrush: null,\n        // outOfBrush: null,\n        toolbox: null,          // Default value see preprocessor.\n        brushLink: null,        // Series indices array, broadcast using dataIndex.\n                                // or 'all', which means all series. 'none' or null means no series.\n        seriesIndex: 'all',     // seriesIndex array, specify series controlled by this brush component.\n        geoIndex: null,         //\n        xAxisIndex: null,\n        yAxisIndex: null,\n\n        brushType: 'rect',      // Default brushType, see BrushController.\n        brushMode: 'single',    // Default brushMode, 'single' or 'multiple'\n        transformable: true,    // Default transformable.\n        brushStyle: {           // Default brushStyle\n            borderWidth: 1,\n            color: 'rgba(120,140,180,0.3)',\n            borderColor: 'rgba(120,140,180,0.8)'\n        },\n\n        throttleType: 'fixRate', // Throttle in brushSelected event. 'fixRate' or 'debounce'.\n                                 // If null, no throttle. Valid only in the first brush component\n        throttleDelay: 0,        // Unit: ms, 0 means every event will be triggered.\n\n        // FIXME\n        // 试验效果\n        removeOnClick: true,\n\n        z: 10000\n    },\n\n    /**\n     * @readOnly\n     * @type {Array.<Object>}\n     */\n    areas: [],\n\n    /**\n     * Current activated brush type.\n     * If null, brush is inactived.\n     * see module:echarts/component/helper/BrushController\n     * @readOnly\n     * @type {string}\n     */\n    brushType: null,\n\n    /**\n     * Current brush opt.\n     * see module:echarts/component/helper/BrushController\n     * @readOnly\n     * @type {Object}\n     */\n    brushOption: {},\n\n    /**\n     * @readOnly\n     * @type {Array.<Object>}\n     */\n    coordInfoList: [],\n\n    optionUpdated: function (newOption, isInit) {\n        var thisOption = this.option;\n\n        !isInit && replaceVisualOption(\n            thisOption, newOption, ['inBrush', 'outOfBrush']\n        );\n\n        var inBrush = thisOption.inBrush = thisOption.inBrush || {};\n        // Always give default visual, consider setOption at the second time.\n        thisOption.outOfBrush = thisOption.outOfBrush || {color: DEFAULT_OUT_OF_BRUSH_COLOR};\n\n        if (!inBrush.hasOwnProperty('liftZ')) {\n            // Bigger than the highlight z lift, otherwise it will\n            // be effected by the highlight z when brush.\n            inBrush.liftZ = 5;\n        }\n    },\n\n    /**\n     * If ranges is null/undefined, range state remain.\n     *\n     * @param {Array.<Object>} [ranges]\n     */\n    setAreas: function (areas) {\n        if (__DEV__) {\n            assert$1(isArray(areas));\n            each$1(areas, function (area) {\n                assert$1(area.brushType, 'Illegal areas');\n            });\n        }\n\n        // If ranges is null/undefined, range state remain.\n        // This helps user to dispatchAction({type: 'brush'}) with no areas\n        // set but just want to get the current brush select info from a `brush` event.\n        if (!areas) {\n            return;\n        }\n\n        this.areas = map(areas, function (area) {\n            return generateBrushOption(this.option, area);\n        }, this);\n    },\n\n    /**\n     * see module:echarts/component/helper/BrushController\n     * @param {Object} brushOption\n     */\n    setBrushOption: function (brushOption) {\n        this.brushOption = generateBrushOption(this.option, brushOption);\n        this.brushType = this.brushOption.brushType;\n    }\n\n});\n\nfunction generateBrushOption(option, brushOption) {\n    return merge(\n        {\n            brushType: option.brushType,\n            brushMode: option.brushMode,\n            transformable: option.transformable,\n            brushStyle: new Model(option.brushStyle).getItemStyle(),\n            removeOnClick: option.removeOnClick,\n            z: option.z\n        },\n        brushOption,\n        true\n    );\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentView({\n\n    type: 'brush',\n\n    init: function (ecModel, api) {\n\n        /**\n         * @readOnly\n         * @type {module:echarts/model/Global}\n         */\n        this.ecModel = ecModel;\n\n        /**\n         * @readOnly\n         * @type {module:echarts/ExtensionAPI}\n         */\n        this.api = api;\n\n        /**\n         * @readOnly\n         * @type {module:echarts/component/brush/BrushModel}\n         */\n        this.model;\n\n        /**\n         * @private\n         * @type {module:echarts/component/helper/BrushController}\n         */\n        (this._brushController = new BrushController(api.getZr()))\n            .on('brush', bind(this._onBrush, this))\n            .mount();\n    },\n\n    /**\n     * @override\n     */\n    render: function (brushModel) {\n        this.model = brushModel;\n        return updateController.apply(this, arguments);\n    },\n\n    /**\n     * @override\n     */\n    updateTransform: updateController,\n\n    /**\n     * @override\n     */\n    updateView: updateController,\n\n    // /**\n    //  * @override\n    //  */\n    // updateLayout: updateController,\n\n    // /**\n    //  * @override\n    //  */\n    // updateVisual: updateController,\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._brushController.dispose();\n    },\n\n    /**\n     * @private\n     */\n    _onBrush: function (areas, opt) {\n        var modelId = this.model.id;\n\n        this.model.brushTargetManager.setOutputRanges(areas, this.ecModel);\n\n        // Action is not dispatched on drag end, because the drag end\n        // emits the same params with the last drag move event, and\n        // may have some delay when using touch pad, which makes\n        // animation not smooth (when using debounce).\n        (!opt.isEnd || opt.removeOnClick) && this.api.dispatchAction({\n            type: 'brush',\n            brushId: modelId,\n            areas: clone(areas),\n            $from: modelId\n        });\n    }\n\n});\n\nfunction updateController(brushModel, ecModel, api, payload) {\n    // Do not update controller when drawing.\n    (!payload || payload.$from !== brushModel.id) && this._brushController\n        .setPanels(brushModel.brushTargetManager.makePanelOpts(api))\n        .enableBrush(brushModel.brushOption)\n        .updateCovers(brushModel.areas.slice());\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * payload: {\n *      brushIndex: number, or,\n *      brushId: string, or,\n *      brushName: string,\n *      globalRanges: Array\n * }\n */\nregisterAction(\n        {type: 'brush', event: 'brush' /*, update: 'updateView' */},\n    function (payload, ecModel) {\n        ecModel.eachComponent({mainType: 'brush', query: payload}, function (brushModel) {\n            brushModel.setAreas(payload.areas);\n        });\n    }\n);\n\n/**\n * payload: {\n *      brushComponents: [\n *          {\n *              brushId,\n *              brushIndex,\n *              brushName,\n *              series: [\n *                  {\n *                      seriesId,\n *                      seriesIndex,\n *                      seriesName,\n *                      rawIndices: [21, 34, ...]\n *                  },\n *                  ...\n *              ]\n *          },\n *          ...\n *      ]\n * }\n */\nregisterAction(\n    {type: 'brushSelect', event: 'brushSelected', update: 'none'},\n    function () {}\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar features = {};\n\nfunction register$1(name, ctor) {\n    features[name] = ctor;\n}\n\nfunction get$1(name) {\n    return features[name];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar brushLang = lang.toolbox.brush;\n\nfunction Brush(model, ecModel, api) {\n    this.model = model;\n    this.ecModel = ecModel;\n    this.api = api;\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._brushType;\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._brushMode;\n}\n\nBrush.defaultOption = {\n    show: true,\n    type: ['rect', 'polygon', 'lineX', 'lineY', 'keep', 'clear'],\n    icon: {\n        /* eslint-disable */\n        rect: 'M7.3,34.7 M0.4,10V-0.2h9.8 M89.6,10V-0.2h-9.8 M0.4,60v10.2h9.8 M89.6,60v10.2h-9.8 M12.3,22.4V10.5h13.1 M33.6,10.5h7.8 M49.1,10.5h7.8 M77.5,22.4V10.5h-13 M12.3,31.1v8.2 M77.7,31.1v8.2 M12.3,47.6v11.9h13.1 M33.6,59.5h7.6 M49.1,59.5 h7.7 M77.5,47.6v11.9h-13', // jshint ignore:line\n        polygon: 'M55.2,34.9c1.7,0,3.1,1.4,3.1,3.1s-1.4,3.1-3.1,3.1 s-3.1-1.4-3.1-3.1S53.5,34.9,55.2,34.9z M50.4,51c1.7,0,3.1,1.4,3.1,3.1c0,1.7-1.4,3.1-3.1,3.1c-1.7,0-3.1-1.4-3.1-3.1 C47.3,52.4,48.7,51,50.4,51z M55.6,37.1l1.5-7.8 M60.1,13.5l1.6-8.7l-7.8,4 M59,19l-1,5.3 M24,16.1l6.4,4.9l6.4-3.3 M48.5,11.6 l-5.9,3.1 M19.1,12.8L9.7,5.1l1.1,7.7 M13.4,29.8l1,7.3l6.6,1.6 M11.6,18.4l1,6.1 M32.8,41.9 M26.6,40.4 M27.3,40.2l6.1,1.6 M49.9,52.1l-5.6-7.6l-4.9-1.2', // jshint ignore:line\n        lineX: 'M15.2,30 M19.7,15.6V1.9H29 M34.8,1.9H40.4 M55.3,15.6V1.9H45.9 M19.7,44.4V58.1H29 M34.8,58.1H40.4 M55.3,44.4 V58.1H45.9 M12.5,20.3l-9.4,9.6l9.6,9.8 M3.1,29.9h16.5 M62.5,20.3l9.4,9.6L62.3,39.7 M71.9,29.9H55.4', // jshint ignore:line\n        lineY: 'M38.8,7.7 M52.7,12h13.2v9 M65.9,26.6V32 M52.7,46.3h13.2v-9 M24.9,12H11.8v9 M11.8,26.6V32 M24.9,46.3H11.8v-9 M48.2,5.1l-9.3-9l-9.4,9.2 M38.9-3.9V12 M48.2,53.3l-9.3,9l-9.4-9.2 M38.9,62.3V46.4', // jshint ignore:line\n        keep: 'M4,10.5V1h10.3 M20.7,1h6.1 M33,1h6.1 M55.4,10.5V1H45.2 M4,17.3v6.6 M55.6,17.3v6.6 M4,30.5V40h10.3 M20.7,40 h6.1 M33,40h6.1 M55.4,30.5V40H45.2 M21,18.9h62.9v48.6H21V18.9z', // jshint ignore:line\n        clear: 'M22,14.7l30.9,31 M52.9,14.7L22,45.7 M4.7,16.8V4.2h13.1 M26,4.2h7.8 M41.6,4.2h7.8 M70.3,16.8V4.2H57.2 M4.7,25.9v8.6 M70.3,25.9v8.6 M4.7,43.2v12.6h13.1 M26,55.8h7.8 M41.6,55.8h7.8 M70.3,43.2v12.6H57.2' // jshint ignore:line\n        /* eslint-enable */\n    },\n    // `rect`, `polygon`, `lineX`, `lineY`, `keep`, `clear`\n    title: clone(brushLang.title)\n};\n\nvar proto$3 = Brush.prototype;\n\n// proto.updateLayout = function (featureModel, ecModel, api) {\n/* eslint-disable */\nproto$3.render =\n/* eslint-enable */\nproto$3.updateView = function (featureModel, ecModel, api) {\n    var brushType;\n    var brushMode;\n    var isBrushed;\n\n    ecModel.eachComponent({mainType: 'brush'}, function (brushModel) {\n        brushType = brushModel.brushType;\n        brushMode = brushModel.brushOption.brushMode || 'single';\n        isBrushed |= brushModel.areas.length;\n    });\n    this._brushType = brushType;\n    this._brushMode = brushMode;\n\n    each$1(featureModel.get('type', true), function (type) {\n        featureModel.setIconStatus(\n            type,\n            (\n                type === 'keep'\n                ? brushMode === 'multiple'\n                : type === 'clear'\n                ? isBrushed\n                : type === brushType\n            ) ? 'emphasis' : 'normal'\n        );\n    });\n};\n\nproto$3.getIcons = function () {\n    var model = this.model;\n    var availableIcons = model.get('icon', true);\n    var icons = {};\n    each$1(model.get('type', true), function (type) {\n        if (availableIcons[type]) {\n            icons[type] = availableIcons[type];\n        }\n    });\n    return icons;\n};\n\nproto$3.onclick = function (ecModel, api, type) {\n    var brushType = this._brushType;\n    var brushMode = this._brushMode;\n\n    if (type === 'clear') {\n        // Trigger parallel action firstly\n        api.dispatchAction({\n            type: 'axisAreaSelect',\n            intervals: []\n        });\n\n        api.dispatchAction({\n            type: 'brush',\n            command: 'clear',\n            // Clear all areas of all brush components.\n            areas: []\n        });\n    }\n    else {\n        api.dispatchAction({\n            type: 'takeGlobalCursor',\n            key: 'brush',\n            brushOption: {\n                brushType: type === 'keep'\n                    ? brushType\n                    : (brushType === type ? false : type),\n                brushMode: type === 'keep'\n                    ? (brushMode === 'multiple' ? 'single' : 'multiple')\n                    : brushMode\n            }\n        });\n    }\n};\n\nregister$1('brush', Brush);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Brush component entry\n */\n\nregisterPreprocessor(preprocessor$1);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (24*60*60*1000)\nvar PROXIMATE_ONE_DAY = 86400000;\n\n/**\n * Calendar\n *\n * @constructor\n *\n * @param {Object} calendarModel calendarModel\n * @param {Object} ecModel       ecModel\n * @param {Object} api           api\n */\nfunction Calendar(calendarModel, ecModel, api) {\n    this._model = calendarModel;\n}\n\nCalendar.prototype = {\n\n    constructor: Calendar,\n\n    type: 'calendar',\n\n    dimensions: ['time', 'value'],\n\n    // Required in createListFromData\n    getDimensionsInfo: function () {\n        return [{name: 'time', type: 'time'}, 'value'];\n    },\n\n    getRangeInfo: function () {\n        return this._rangeInfo;\n    },\n\n    getModel: function () {\n        return this._model;\n    },\n\n    getRect: function () {\n        return this._rect;\n    },\n\n    getCellWidth: function () {\n        return this._sw;\n    },\n\n    getCellHeight: function () {\n        return this._sh;\n    },\n\n    getOrient: function () {\n        return this._orient;\n    },\n\n    /**\n     * getFirstDayOfWeek\n     *\n     * @example\n     *     0 : start at Sunday\n     *     1 : start at Monday\n     *\n     * @return {number}\n     */\n    getFirstDayOfWeek: function () {\n        return this._firstDayOfWeek;\n    },\n\n    /**\n     * get date info\n     *\n     * @param  {string|number} date date\n     * @return {Object}\n     * {\n     *      y: string, local full year, eg., '1940',\n     *      m: string, local month, from '01' ot '12',\n     *      d: string, local date, from '01' to '31' (if exists),\n     *      day: It is not date.getDay(). It is the location of the cell in a week, from 0 to 6,\n     *      time: timestamp,\n     *      formatedDate: string, yyyy-MM-dd,\n     *      date: original date object.\n     * }\n     */\n    getDateInfo: function (date) {\n\n        date = parseDate(date);\n\n        var y = date.getFullYear();\n\n        var m = date.getMonth() + 1;\n        m = m < 10 ? '0' + m : m;\n\n        var d = date.getDate();\n        d = d < 10 ? '0' + d : d;\n\n        var day = date.getDay();\n\n        day = Math.abs((day + 7 - this.getFirstDayOfWeek()) % 7);\n\n        return {\n            y: y,\n            m: m,\n            d: d,\n            day: day,\n            time: date.getTime(),\n            formatedDate: y + '-' + m + '-' + d,\n            date: date\n        };\n    },\n\n    getNextNDay: function (date, n) {\n        n = n || 0;\n        if (n === 0) {\n            return this.getDateInfo(date);\n        }\n\n        date = new Date(this.getDateInfo(date).time);\n        date.setDate(date.getDate() + n);\n\n        return this.getDateInfo(date);\n    },\n\n    update: function (ecModel, api) {\n\n        this._firstDayOfWeek = +this._model.getModel('dayLabel').get('firstDay');\n        this._orient = this._model.get('orient');\n        this._lineWidth = this._model.getModel('itemStyle').getItemStyle().lineWidth || 0;\n\n\n        this._rangeInfo = this._getRangeInfo(this._initRangeOption());\n        var weeks = this._rangeInfo.weeks || 1;\n        var whNames = ['width', 'height'];\n        var cellSize = this._model.get('cellSize').slice();\n        var layoutParams = this._model.getBoxLayoutParams();\n        var cellNumbers = this._orient === 'horizontal' ? [weeks, 7] : [7, weeks];\n\n        each$1([0, 1], function (idx) {\n            if (cellSizeSpecified(cellSize, idx)) {\n                layoutParams[whNames[idx]] = cellSize[idx] * cellNumbers[idx];\n            }\n        });\n\n        var whGlobal = {\n            width: api.getWidth(),\n            height: api.getHeight()\n        };\n        var calendarRect = this._rect = getLayoutRect(layoutParams, whGlobal);\n\n        each$1([0, 1], function (idx) {\n            if (!cellSizeSpecified(cellSize, idx)) {\n                cellSize[idx] = calendarRect[whNames[idx]] / cellNumbers[idx];\n            }\n        });\n\n        function cellSizeSpecified(cellSize, idx) {\n            return cellSize[idx] != null && cellSize[idx] !== 'auto';\n        }\n\n        this._sw = cellSize[0];\n        this._sh = cellSize[1];\n    },\n\n\n    /**\n     * Convert a time data(time, value) item to (x, y) point.\n     *\n     * @override\n     * @param  {Array|number} data data\n     * @param  {boolean} [clamp=true] out of range\n     * @return {Array} point\n     */\n    dataToPoint: function (data, clamp) {\n        isArray(data) && (data = data[0]);\n        clamp == null && (clamp = true);\n\n        var dayInfo = this.getDateInfo(data);\n        var range = this._rangeInfo;\n        var date = dayInfo.formatedDate;\n\n        // if not in range return [NaN, NaN]\n        if (clamp && !(\n            dayInfo.time >= range.start.time\n            && dayInfo.time < range.end.time + PROXIMATE_ONE_DAY\n        )) {\n            return [NaN, NaN];\n        }\n\n        var week = dayInfo.day;\n        var nthWeek = this._getRangeInfo([range.start.time, date]).nthWeek;\n\n        if (this._orient === 'vertical') {\n            return [\n                this._rect.x + week * this._sw + this._sw / 2,\n                this._rect.y + nthWeek * this._sh + this._sh / 2\n            ];\n\n        }\n\n        return [\n            this._rect.x + nthWeek * this._sw + this._sw / 2,\n            this._rect.y + week * this._sh + this._sh / 2\n        ];\n\n    },\n\n    /**\n     * Convert a (x, y) point to time data\n     *\n     * @override\n     * @param  {string} point point\n     * @return {string}       data\n     */\n    pointToData: function (point) {\n\n        var date = this.pointToDate(point);\n\n        return date && date.time;\n    },\n\n    /**\n     * Convert a time date item to (x, y) four point.\n     *\n     * @param  {Array} data  date[0] is date\n     * @param  {boolean} [clamp=true]  out of range\n     * @return {Object}       point\n     */\n    dataToRect: function (data, clamp) {\n        var point = this.dataToPoint(data, clamp);\n\n        return {\n            contentShape: {\n                x: point[0] - (this._sw - this._lineWidth) / 2,\n                y: point[1] - (this._sh - this._lineWidth) / 2,\n                width: this._sw - this._lineWidth,\n                height: this._sh - this._lineWidth\n            },\n\n            center: point,\n\n            tl: [\n                point[0] - this._sw / 2,\n                point[1] - this._sh / 2\n            ],\n\n            tr: [\n                point[0] + this._sw / 2,\n                point[1] - this._sh / 2\n            ],\n\n            br: [\n                point[0] + this._sw / 2,\n                point[1] + this._sh / 2\n            ],\n\n            bl: [\n                point[0] - this._sw / 2,\n                point[1] + this._sh / 2\n            ]\n\n        };\n    },\n\n    /**\n     * Convert a (x, y) point to time date\n     *\n     * @param  {Array} point point\n     * @return {Object}       date\n     */\n    pointToDate: function (point) {\n        var nthX = Math.floor((point[0] - this._rect.x) / this._sw) + 1;\n        var nthY = Math.floor((point[1] - this._rect.y) / this._sh) + 1;\n        var range = this._rangeInfo.range;\n\n        if (this._orient === 'vertical') {\n            return this._getDateByWeeksAndDay(nthY, nthX - 1, range);\n        }\n\n        return this._getDateByWeeksAndDay(nthX, nthY - 1, range);\n    },\n\n    /**\n     * @inheritDoc\n     */\n    convertToPixel: curry(doConvert$2, 'dataToPoint'),\n\n    /**\n     * @inheritDoc\n     */\n    convertFromPixel: curry(doConvert$2, 'pointToData'),\n\n    /**\n     * initRange\n     *\n     * @private\n     * @return {Array} [start, end]\n     */\n    _initRangeOption: function () {\n        var range = this._model.get('range');\n\n        var rg = range;\n\n        if (isArray(rg) && rg.length === 1) {\n            rg = rg[0];\n        }\n\n        if (/^\\d{4}$/.test(rg)) {\n            range = [rg + '-01-01', rg + '-12-31'];\n        }\n\n        if (/^\\d{4}[\\/|-]\\d{1,2}$/.test(rg)) {\n\n            var start = this.getDateInfo(rg);\n            var firstDay = start.date;\n            firstDay.setMonth(firstDay.getMonth() + 1);\n\n            var end = this.getNextNDay(firstDay, -1);\n            range = [start.formatedDate, end.formatedDate];\n        }\n\n        if (/^\\d{4}[\\/|-]\\d{1,2}[\\/|-]\\d{1,2}$/.test(rg)) {\n            range = [rg, rg];\n        }\n\n        var tmp = this._getRangeInfo(range);\n\n        if (tmp.start.time > tmp.end.time) {\n            range.reverse();\n        }\n\n        return range;\n    },\n\n    /**\n     * range info\n     *\n     * @private\n     * @param  {Array} range range ['2017-01-01', '2017-07-08']\n     *  If range[0] > range[1], they will not be reversed.\n     * @return {Object}       obj\n     */\n    _getRangeInfo: function (range) {\n        range = [\n            this.getDateInfo(range[0]),\n            this.getDateInfo(range[1])\n        ];\n\n        var reversed;\n        if (range[0].time > range[1].time) {\n            reversed = true;\n            range.reverse();\n        }\n\n        var allDay = Math.floor(range[1].time / PROXIMATE_ONE_DAY)\n            - Math.floor(range[0].time / PROXIMATE_ONE_DAY) + 1;\n\n        // Consider case:\n        // Firstly set system timezone as \"Time Zone: America/Toronto\",\n        // ```\n        // var first = new Date(1478412000000 - 3600 * 1000 * 2.5);\n        // var second = new Date(1478412000000);\n        // var allDays = Math.floor(second / ONE_DAY) - Math.floor(first / ONE_DAY) + 1;\n        // ```\n        // will get wrong result because of DST. So we should fix it.\n        var date = new Date(range[0].time);\n        var startDateNum = date.getDate();\n        var endDateNum = range[1].date.getDate();\n        date.setDate(startDateNum + allDay - 1);\n        // The bias can not over a month, so just compare date.\n        if (date.getDate() !== endDateNum) {\n            var sign = date.getTime() - range[1].time > 0 ? 1 : -1;\n            while (date.getDate() !== endDateNum && (date.getTime() - range[1].time) * sign > 0) {\n                allDay -= sign;\n                date.setDate(startDateNum + allDay - 1);\n            }\n        }\n\n        var weeks = Math.floor((allDay + range[0].day + 6) / 7);\n        var nthWeek = reversed ? -weeks + 1 : weeks - 1;\n\n        reversed && range.reverse();\n\n        return {\n            range: [range[0].formatedDate, range[1].formatedDate],\n            start: range[0],\n            end: range[1],\n            allDay: allDay,\n            weeks: weeks,\n            // From 0.\n            nthWeek: nthWeek,\n            fweek: range[0].day,\n            lweek: range[1].day\n        };\n    },\n\n    /**\n     * get date by nthWeeks and week day in range\n     *\n     * @private\n     * @param  {number} nthWeek the week\n     * @param  {number} day   the week day\n     * @param  {Array} range [d1, d2]\n     * @return {Object}\n     */\n    _getDateByWeeksAndDay: function (nthWeek, day, range) {\n        var rangeInfo = this._getRangeInfo(range);\n\n        if (nthWeek > rangeInfo.weeks\n            || (nthWeek === 0 && day < rangeInfo.fweek)\n            || (nthWeek === rangeInfo.weeks && day > rangeInfo.lweek)\n        ) {\n            return false;\n        }\n\n        var nthDay = (nthWeek - 1) * 7 - rangeInfo.fweek + day;\n        var date = new Date(rangeInfo.start.time);\n        date.setDate(rangeInfo.start.d + nthDay);\n\n        return this.getDateInfo(date);\n    }\n};\n\nCalendar.dimensions = Calendar.prototype.dimensions;\n\nCalendar.getDimensionsInfo = Calendar.prototype.getDimensionsInfo;\n\nCalendar.create = function (ecModel, api) {\n    var calendarList = [];\n\n    ecModel.eachComponent('calendar', function (calendarModel) {\n        var calendar = new Calendar(calendarModel, ecModel, api);\n        calendarList.push(calendar);\n        calendarModel.coordinateSystem = calendar;\n    });\n\n    ecModel.eachSeries(function (calendarSeries) {\n        if (calendarSeries.get('coordinateSystem') === 'calendar') {\n            // Inject coordinate system\n            calendarSeries.coordinateSystem = calendarList[calendarSeries.get('calendarIndex') || 0];\n        }\n    });\n    return calendarList;\n};\n\nfunction doConvert$2(methodName, ecModel, finder, value) {\n    var calendarModel = finder.calendarModel;\n    var seriesModel = finder.seriesModel;\n\n    var coordSys = calendarModel\n        ? calendarModel.coordinateSystem\n        : seriesModel\n        ? seriesModel.coordinateSystem\n        : null;\n\n    return coordSys === this ? coordSys[methodName](value) : null;\n}\n\nCoordinateSystemManager.register('calendar', Calendar);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar CalendarModel = ComponentModel.extend({\n\n    type: 'calendar',\n\n    /**\n     * @type {module:echarts/coord/calendar/Calendar}\n     */\n    coordinateSystem: null,\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        left: 80,\n        top: 60,\n\n        cellSize: 20,\n\n        // horizontal vertical\n        orient: 'horizontal',\n\n        // month separate line style\n        splitLine: {\n            show: true,\n            lineStyle: {\n                color: '#000',\n                width: 1,\n                type: 'solid'\n            }\n        },\n\n        // rect style  temporarily unused emphasis\n        itemStyle: {\n            color: '#fff',\n            borderWidth: 1,\n            borderColor: '#ccc'\n        },\n\n        // week text style\n        dayLabel: {\n            show: true,\n\n            // a week first day\n            firstDay: 0,\n\n            // start end\n            position: 'start',\n            margin: '50%', // 50% of cellSize\n            nameMap: 'en',\n            color: '#000'\n        },\n\n        // month text style\n        monthLabel: {\n            show: true,\n\n            // start end\n            position: 'start',\n            margin: 5,\n\n            // center or left\n            align: 'center',\n\n            // cn en []\n            nameMap: 'en',\n            formatter: null,\n            color: '#000'\n        },\n\n        // year text style\n        yearLabel: {\n            show: true,\n\n            // top bottom left right\n            position: null,\n            margin: 30,\n            formatter: null,\n            color: '#ccc',\n            fontFamily: 'sans-serif',\n            fontWeight: 'bolder',\n            fontSize: 20\n        }\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel, extraOpt) {\n        var inputPositionParams = getLayoutParams(option);\n\n        CalendarModel.superApply(this, 'init', arguments);\n\n        mergeAndNormalizeLayoutParams$1(option, inputPositionParams);\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (option, extraOpt) {\n        CalendarModel.superApply(this, 'mergeOption', arguments);\n\n        mergeAndNormalizeLayoutParams$1(this.option, option);\n    }\n});\n\nfunction mergeAndNormalizeLayoutParams$1(target, raw) {\n    // Normalize cellSize\n    var cellSize = target.cellSize;\n\n    if (!isArray(cellSize)) {\n        cellSize = target.cellSize = [cellSize, cellSize];\n    }\n    else if (cellSize.length === 1) {\n        cellSize[1] = cellSize[0];\n    }\n\n    var ignoreSize = map([0, 1], function (hvIdx) {\n        // If user have set `width` or both `left` and `right`, cellSize\n        // will be automatically set to 'auto', otherwise the default\n        // setting of cellSize will make `width` setting not work.\n        if (sizeCalculable(raw, hvIdx)) {\n            cellSize[hvIdx] = 'auto';\n        }\n        return cellSize[hvIdx] != null && cellSize[hvIdx] !== 'auto';\n    });\n\n    mergeLayoutParam(target, raw, {\n        type: 'box', ignoreSize: ignoreSize\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar MONTH_TEXT = {\n    EN: [\n        'Jan', 'Feb', 'Mar',\n        'Apr', 'May', 'Jun',\n        'Jul', 'Aug', 'Sep',\n        'Oct', 'Nov', 'Dec'\n    ],\n    CN: [\n        '一月', '二月', '三月',\n        '四月', '五月', '六月',\n        '七月', '八月', '九月',\n        '十月', '十一月', '十二月'\n    ]\n};\n\nvar WEEK_TEXT = {\n    EN: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],\n    CN: ['日', '一', '二', '三', '四', '五', '六']\n};\n\nextendComponentView({\n\n    type: 'calendar',\n\n    /**\n     * top/left line points\n     *  @private\n     */\n    _tlpoints: null,\n\n    /**\n     * bottom/right line points\n     *  @private\n     */\n    _blpoints: null,\n\n    /**\n     * first day of month\n     *  @private\n     */\n    _firstDayOfMonth: null,\n\n    /**\n     * first day point of month\n     *  @private\n     */\n    _firstDayPoints: null,\n\n    render: function (calendarModel, ecModel, api) {\n\n        var group = this.group;\n\n        group.removeAll();\n\n        var coordSys = calendarModel.coordinateSystem;\n\n        // range info\n        var rangeData = coordSys.getRangeInfo();\n        var orient = coordSys.getOrient();\n\n        this._renderDayRect(calendarModel, rangeData, group);\n\n        // _renderLines must be called prior to following function\n        this._renderLines(calendarModel, rangeData, orient, group);\n\n        this._renderYearText(calendarModel, rangeData, orient, group);\n\n        this._renderMonthText(calendarModel, orient, group);\n\n        this._renderWeekText(calendarModel, rangeData, orient, group);\n    },\n\n    // render day rect\n    _renderDayRect: function (calendarModel, rangeData, group) {\n        var coordSys = calendarModel.coordinateSystem;\n        var itemRectStyleModel = calendarModel.getModel('itemStyle').getItemStyle();\n        var sw = coordSys.getCellWidth();\n        var sh = coordSys.getCellHeight();\n\n        for (var i = rangeData.start.time;\n            i <= rangeData.end.time;\n            i = coordSys.getNextNDay(i, 1).time\n        ) {\n\n            var point = coordSys.dataToRect([i], false).tl;\n\n            // every rect\n            var rect = new Rect({\n                shape: {\n                    x: point[0],\n                    y: point[1],\n                    width: sw,\n                    height: sh\n                },\n                cursor: 'default',\n                style: itemRectStyleModel\n            });\n\n            group.add(rect);\n        }\n\n    },\n\n    // render separate line\n    _renderLines: function (calendarModel, rangeData, orient, group) {\n\n        var self = this;\n\n        var coordSys = calendarModel.coordinateSystem;\n\n        var lineStyleModel = calendarModel.getModel('splitLine.lineStyle').getLineStyle();\n        var show = calendarModel.get('splitLine.show');\n\n        var lineWidth = lineStyleModel.lineWidth;\n\n        this._tlpoints = [];\n        this._blpoints = [];\n        this._firstDayOfMonth = [];\n        this._firstDayPoints = [];\n\n\n        var firstDay = rangeData.start;\n\n        for (var i = 0; firstDay.time <= rangeData.end.time; i++) {\n            addPoints(firstDay.formatedDate);\n\n            if (i === 0) {\n                firstDay = coordSys.getDateInfo(rangeData.start.y + '-' + rangeData.start.m);\n            }\n\n            var date = firstDay.date;\n            date.setMonth(date.getMonth() + 1);\n            firstDay = coordSys.getDateInfo(date);\n        }\n\n        addPoints(coordSys.getNextNDay(rangeData.end.time, 1).formatedDate);\n\n        function addPoints(date) {\n\n            self._firstDayOfMonth.push(coordSys.getDateInfo(date));\n            self._firstDayPoints.push(coordSys.dataToRect([date], false).tl);\n\n            var points = self._getLinePointsOfOneWeek(calendarModel, date, orient);\n\n            self._tlpoints.push(points[0]);\n            self._blpoints.push(points[points.length - 1]);\n\n            show && self._drawSplitline(points, lineStyleModel, group);\n        }\n\n\n        // render top/left line\n        show && this._drawSplitline(self._getEdgesPoints(self._tlpoints, lineWidth, orient), lineStyleModel, group);\n\n        // render bottom/right line\n        show && this._drawSplitline(self._getEdgesPoints(self._blpoints, lineWidth, orient), lineStyleModel, group);\n\n    },\n\n    // get points at both ends\n    _getEdgesPoints: function (points, lineWidth, orient) {\n        var rs = [points[0].slice(), points[points.length - 1].slice()];\n        var idx = orient === 'horizontal' ? 0 : 1;\n\n        // both ends of the line are extend half lineWidth\n        rs[0][idx] = rs[0][idx] - lineWidth / 2;\n        rs[1][idx] = rs[1][idx] + lineWidth / 2;\n\n        return rs;\n    },\n\n    // render split line\n    _drawSplitline: function (points, lineStyleModel, group) {\n\n        var poyline = new Polyline({\n            z2: 20,\n            shape: {\n                points: points\n            },\n            style: lineStyleModel\n        });\n\n        group.add(poyline);\n    },\n\n    // render month line of one week points\n    _getLinePointsOfOneWeek: function (calendarModel, date, orient) {\n\n        var coordSys = calendarModel.coordinateSystem;\n        date = coordSys.getDateInfo(date);\n\n        var points = [];\n\n        for (var i = 0; i < 7; i++) {\n\n            var tmpD = coordSys.getNextNDay(date.time, i);\n            var point = coordSys.dataToRect([tmpD.time], false);\n\n            points[2 * tmpD.day] = point.tl;\n            points[2 * tmpD.day + 1] = point[orient === 'horizontal' ? 'bl' : 'tr'];\n        }\n\n        return points;\n\n    },\n\n    _formatterLabel: function (formatter, params) {\n\n        if (typeof formatter === 'string' && formatter) {\n            return formatTplSimple(formatter, params);\n        }\n\n        if (typeof formatter === 'function') {\n            return formatter(params);\n        }\n\n        return params.nameMap;\n\n    },\n\n    _yearTextPositionControl: function (textEl, point, orient, position, margin) {\n\n        point = point.slice();\n        var aligns = ['center', 'bottom'];\n\n        if (position === 'bottom') {\n            point[1] += margin;\n            aligns = ['center', 'top'];\n        }\n        else if (position === 'left') {\n            point[0] -= margin;\n        }\n        else if (position === 'right') {\n            point[0] += margin;\n            aligns = ['center', 'top'];\n        }\n        else { // top\n            point[1] -= margin;\n        }\n\n        var rotate = 0;\n        if (position === 'left' || position === 'right') {\n            rotate = Math.PI / 2;\n        }\n\n        return {\n            rotation: rotate,\n            position: point,\n            style: {\n                textAlign: aligns[0],\n                textVerticalAlign: aligns[1]\n            }\n        };\n    },\n\n    // render year\n    _renderYearText: function (calendarModel, rangeData, orient, group) {\n        var yearLabel = calendarModel.getModel('yearLabel');\n\n        if (!yearLabel.get('show')) {\n            return;\n        }\n\n        var margin = yearLabel.get('margin');\n        var pos = yearLabel.get('position');\n\n        if (!pos) {\n            pos = orient !== 'horizontal' ? 'top' : 'left';\n        }\n\n        var points = [this._tlpoints[this._tlpoints.length - 1], this._blpoints[0]];\n        var xc = (points[0][0] + points[1][0]) / 2;\n        var yc = (points[0][1] + points[1][1]) / 2;\n\n        var idx = orient === 'horizontal' ? 0 : 1;\n\n        var posPoints = {\n            top: [xc, points[idx][1]],\n            bottom: [xc, points[1 - idx][1]],\n            left: [points[1 - idx][0], yc],\n            right: [points[idx][0], yc]\n        };\n\n        var name = rangeData.start.y;\n\n        if (+rangeData.end.y > +rangeData.start.y) {\n            name = name + '-' + rangeData.end.y;\n        }\n\n        var formatter = yearLabel.get('formatter');\n\n        var params = {\n            start: rangeData.start.y,\n            end: rangeData.end.y,\n            nameMap: name\n        };\n\n        var content = this._formatterLabel(formatter, params);\n\n        var yearText = new Text({z2: 30});\n        setTextStyle(yearText.style, yearLabel, {text: content}),\n        yearText.attr(this._yearTextPositionControl(yearText, posPoints[pos], orient, pos, margin));\n\n        group.add(yearText);\n    },\n\n    _monthTextPositionControl: function (point, isCenter, orient, position, margin) {\n        var align = 'left';\n        var vAlign = 'top';\n        var x = point[0];\n        var y = point[1];\n\n        if (orient === 'horizontal') {\n            y = y + margin;\n\n            if (isCenter) {\n                align = 'center';\n            }\n\n            if (position === 'start') {\n                vAlign = 'bottom';\n            }\n        }\n        else {\n            x = x + margin;\n\n            if (isCenter) {\n                vAlign = 'middle';\n            }\n\n            if (position === 'start') {\n                align = 'right';\n            }\n        }\n\n        return {\n            x: x,\n            y: y,\n            textAlign: align,\n            textVerticalAlign: vAlign\n        };\n    },\n\n    // render month and year text\n    _renderMonthText: function (calendarModel, orient, group) {\n        var monthLabel = calendarModel.getModel('monthLabel');\n\n        if (!monthLabel.get('show')) {\n            return;\n        }\n\n        var nameMap = monthLabel.get('nameMap');\n        var margin = monthLabel.get('margin');\n        var pos = monthLabel.get('position');\n        var align = monthLabel.get('align');\n\n        var termPoints = [this._tlpoints, this._blpoints];\n\n        if (isString(nameMap)) {\n            nameMap = MONTH_TEXT[nameMap.toUpperCase()] || [];\n        }\n\n        var idx = pos === 'start' ? 0 : 1;\n        var axis = orient === 'horizontal' ? 0 : 1;\n        margin = pos === 'start' ? -margin : margin;\n        var isCenter = (align === 'center');\n\n        for (var i = 0; i < termPoints[idx].length - 1; i++) {\n\n            var tmp = termPoints[idx][i].slice();\n            var firstDay = this._firstDayOfMonth[i];\n\n            if (isCenter) {\n                var firstDayPoints = this._firstDayPoints[i];\n                tmp[axis] = (firstDayPoints[axis] + termPoints[0][i + 1][axis]) / 2;\n            }\n\n            var formatter = monthLabel.get('formatter');\n            var name = nameMap[+firstDay.m - 1];\n            var params = {\n                yyyy: firstDay.y,\n                yy: (firstDay.y + '').slice(2),\n                MM: firstDay.m,\n                M: +firstDay.m,\n                nameMap: name\n            };\n\n            var content = this._formatterLabel(formatter, params);\n\n            var monthText = new Text({z2: 30});\n            extend(\n                setTextStyle(monthText.style, monthLabel, {text: content}),\n                this._monthTextPositionControl(tmp, isCenter, orient, pos, margin)\n            );\n\n            group.add(monthText);\n        }\n    },\n\n    _weekTextPositionControl: function (point, orient, position, margin, cellSize) {\n        var align = 'center';\n        var vAlign = 'middle';\n        var x = point[0];\n        var y = point[1];\n        var isStart = position === 'start';\n\n        if (orient === 'horizontal') {\n            x = x + margin + (isStart ? 1 : -1) * cellSize[0] / 2;\n            align = isStart ? 'right' : 'left';\n        }\n        else {\n            y = y + margin + (isStart ? 1 : -1) * cellSize[1] / 2;\n            vAlign = isStart ? 'bottom' : 'top';\n        }\n\n        return {\n            x: x,\n            y: y,\n            textAlign: align,\n            textVerticalAlign: vAlign\n        };\n    },\n\n    // render weeks\n    _renderWeekText: function (calendarModel, rangeData, orient, group) {\n        var dayLabel = calendarModel.getModel('dayLabel');\n\n        if (!dayLabel.get('show')) {\n            return;\n        }\n\n        var coordSys = calendarModel.coordinateSystem;\n        var pos = dayLabel.get('position');\n        var nameMap = dayLabel.get('nameMap');\n        var margin = dayLabel.get('margin');\n        var firstDayOfWeek = coordSys.getFirstDayOfWeek();\n\n        if (isString(nameMap)) {\n            nameMap = WEEK_TEXT[nameMap.toUpperCase()] || [];\n        }\n\n        var start = coordSys.getNextNDay(\n            rangeData.end.time, (7 - rangeData.lweek)\n        ).time;\n\n        var cellSize = [coordSys.getCellWidth(), coordSys.getCellHeight()];\n        margin = parsePercent$1(margin, cellSize[orient === 'horizontal' ? 0 : 1]);\n\n        if (pos === 'start') {\n            start = coordSys.getNextNDay(\n                rangeData.start.time, -(7 + rangeData.fweek)\n            ).time;\n            margin = -margin;\n        }\n\n        for (var i = 0; i < 7; i++) {\n\n            var tmpD = coordSys.getNextNDay(start, i);\n            var point = coordSys.dataToRect([tmpD.time], false).center;\n            var day = i;\n            day = Math.abs((i + firstDayOfWeek) % 7);\n            var weekText = new Text({z2: 30});\n\n            extend(\n                setTextStyle(weekText.style, dayLabel, {text: nameMap[day]}),\n                this._weekTextPositionControl(point, orient, pos, margin, cellSize)\n            );\n            group.add(weekText);\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file calendar.js\n * @author dxh\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Model\nextendComponentModel({\n\n    type: 'title',\n\n    layoutMode: {type: 'box', ignoreSize: true},\n\n    defaultOption: {\n        // 一级层叠\n        zlevel: 0,\n        // 二级层叠\n        z: 6,\n        show: true,\n\n        text: '',\n        // 超链接跳转\n        // link: null,\n        // 仅支持self | blank\n        target: 'blank',\n        subtext: '',\n\n        // 超链接跳转\n        // sublink: null,\n        // 仅支持self | blank\n        subtarget: 'blank',\n\n        // 'center' ¦ 'left' ¦ 'right'\n        // ¦ {number}（x坐标，单位px）\n        left: 0,\n        // 'top' ¦ 'bottom' ¦ 'center'\n        // ¦ {number}（y坐标，单位px）\n        top: 0,\n\n        // 水平对齐\n        // 'auto' | 'left' | 'right' | 'center'\n        // 默认根据 left 的位置判断是左对齐还是右对齐\n        // textAlign: null\n        //\n        // 垂直对齐\n        // 'auto' | 'top' | 'bottom' | 'middle'\n        // 默认根据 top 位置判断是上对齐还是下对齐\n        // textBaseline: null\n\n        backgroundColor: 'rgba(0,0,0,0)',\n\n        // 标题边框颜色\n        borderColor: '#ccc',\n\n        // 标题边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n\n        // 标题内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n\n        // 主副标题纵向间隔，单位px，默认为10，\n        itemGap: 10,\n        textStyle: {\n            fontSize: 18,\n            fontWeight: 'bolder',\n            color: '#333'\n        },\n        subtextStyle: {\n            color: '#aaa'\n        }\n    }\n});\n\n// View\nextendComponentView({\n\n    type: 'title',\n\n    render: function (titleModel, ecModel, api) {\n        this.group.removeAll();\n\n        if (!titleModel.get('show')) {\n            return;\n        }\n\n        var group = this.group;\n\n        var textStyleModel = titleModel.getModel('textStyle');\n        var subtextStyleModel = titleModel.getModel('subtextStyle');\n\n        var textAlign = titleModel.get('textAlign');\n        var textBaseline = titleModel.get('textBaseline');\n\n        var textEl = new Text({\n            style: setTextStyle({}, textStyleModel, {\n                text: titleModel.get('text'),\n                textFill: textStyleModel.getTextColor()\n            }, {disableBox: true}),\n            z2: 10\n        });\n\n        var textRect = textEl.getBoundingRect();\n\n        var subText = titleModel.get('subtext');\n        var subTextEl = new Text({\n            style: setTextStyle({}, subtextStyleModel, {\n                text: subText,\n                textFill: subtextStyleModel.getTextColor(),\n                y: textRect.height + titleModel.get('itemGap'),\n                textVerticalAlign: 'top'\n            }, {disableBox: true}),\n            z2: 10\n        });\n\n        var link = titleModel.get('link');\n        var sublink = titleModel.get('sublink');\n        var triggerEvent = titleModel.get('triggerEvent', true);\n\n        textEl.silent = !link && !triggerEvent;\n        subTextEl.silent = !sublink && !triggerEvent;\n\n        if (link) {\n            textEl.on('click', function () {\n                window.open(link, '_' + titleModel.get('target'));\n            });\n        }\n        if (sublink) {\n            subTextEl.on('click', function () {\n                window.open(sublink, '_' + titleModel.get('subtarget'));\n            });\n        }\n\n        textEl.eventData = subTextEl.eventData = triggerEvent\n            ? {\n                componentType: 'title',\n                componentIndex: titleModel.componentIndex\n            }\n            : null;\n\n        group.add(textEl);\n        subText && group.add(subTextEl);\n        // If no subText, but add subTextEl, there will be an empty line.\n\n        var groupRect = group.getBoundingRect();\n        var layoutOption = titleModel.getBoxLayoutParams();\n        layoutOption.width = groupRect.width;\n        layoutOption.height = groupRect.height;\n        var layoutRect = getLayoutRect(\n            layoutOption, {\n                width: api.getWidth(),\n                height: api.getHeight()\n            }, titleModel.get('padding')\n        );\n        // Adjust text align based on position\n        if (!textAlign) {\n            // Align left if title is on the left. center and right is same\n            textAlign = titleModel.get('left') || titleModel.get('right');\n            if (textAlign === 'middle') {\n                textAlign = 'center';\n            }\n            // Adjust layout by text align\n            if (textAlign === 'right') {\n                layoutRect.x += layoutRect.width;\n            }\n            else if (textAlign === 'center') {\n                layoutRect.x += layoutRect.width / 2;\n            }\n        }\n        if (!textBaseline) {\n            textBaseline = titleModel.get('top') || titleModel.get('bottom');\n            if (textBaseline === 'center') {\n                textBaseline = 'middle';\n            }\n            if (textBaseline === 'bottom') {\n                layoutRect.y += layoutRect.height;\n            }\n            else if (textBaseline === 'middle') {\n                layoutRect.y += layoutRect.height / 2;\n            }\n\n            textBaseline = textBaseline || 'top';\n        }\n\n        group.attr('position', [layoutRect.x, layoutRect.y]);\n        var alignStyle = {\n            textAlign: textAlign,\n            textVerticalAlign: textBaseline\n        };\n        textEl.setStyle(alignStyle);\n        subTextEl.setStyle(alignStyle);\n\n        // Render background\n        // Get groupRect again because textAlign has been changed\n        groupRect = group.getBoundingRect();\n        var padding = layoutRect.margin;\n        var style = titleModel.getItemStyle(['color', 'opacity']);\n        style.fill = titleModel.get('backgroundColor');\n        var rect = new Rect({\n            shape: {\n                x: groupRect.x - padding[3],\n                y: groupRect.y - padding[0],\n                width: groupRect.width + padding[1] + padding[3],\n                height: groupRect.height + padding[0] + padding[2],\n                r: titleModel.get('borderRadius')\n            },\n            style: style,\n            silent: true\n        });\n        subPixelOptimizeRect(rect);\n\n        group.add(rect);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nComponentModel.registerSubTypeDefaulter('dataZoom', function () {\n    // Default 'slider' when no type specified.\n    return 'slider';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AXIS_DIMS = ['x', 'y', 'z', 'radius', 'angle', 'single'];\n// Supported coords.\nvar COORDS = ['cartesian2d', 'polar', 'singleAxis'];\n\n/**\n * @param {string} coordType\n * @return {boolean}\n */\nfunction isCoordSupported(coordType) {\n    return indexOf(COORDS, coordType) >= 0;\n}\n\n/**\n * Create \"each\" method to iterate names.\n *\n * @pubilc\n * @param  {Array.<string>} names\n * @param  {Array.<string>=} attrs\n * @return {Function}\n */\nfunction createNameEach(names, attrs) {\n    names = names.slice();\n    var capitalNames = map(names, capitalFirst);\n    attrs = (attrs || []).slice();\n    var capitalAttrs = map(attrs, capitalFirst);\n\n    return function (callback, context) {\n        each$1(names, function (name, index) {\n            var nameObj = {name: name, capital: capitalNames[index]};\n\n            for (var j = 0; j < attrs.length; j++) {\n                nameObj[attrs[j]] = name + capitalAttrs[j];\n            }\n\n            callback.call(context, nameObj);\n        });\n    };\n}\n\n/**\n * Iterate each dimension name.\n *\n * @public\n * @param {Function} callback The parameter is like:\n *                            {\n *                                name: 'angle',\n *                                capital: 'Angle',\n *                                axis: 'angleAxis',\n *                                axisIndex: 'angleAixs',\n *                                index: 'angleIndex'\n *                            }\n * @param {Object} context\n */\nvar eachAxisDim$1 = createNameEach(AXIS_DIMS, ['axisIndex', 'axis', 'index', 'id']);\n\n/**\n * If tow dataZoomModels has the same axis controlled, we say that they are 'linked'.\n * dataZoomModels and 'links' make up one or more graphics.\n * This function finds the graphic where the source dataZoomModel is in.\n *\n * @public\n * @param {Function} forEachNode Node iterator.\n * @param {Function} forEachEdgeType edgeType iterator\n * @param {Function} edgeIdGetter Giving node and edgeType, return an array of edge id.\n * @return {Function} Input: sourceNode, Output: Like {nodes: [], dims: {}}\n */\nfunction createLinkedNodesFinder(forEachNode, forEachEdgeType, edgeIdGetter) {\n\n    return function (sourceNode) {\n        var result = {\n            nodes: [],\n            records: {} // key: edgeType.name, value: Object (key: edge id, value: boolean).\n        };\n\n        forEachEdgeType(function (edgeType) {\n            result.records[edgeType.name] = {};\n        });\n\n        if (!sourceNode) {\n            return result;\n        }\n\n        absorb(sourceNode, result);\n\n        var existsLink;\n        do {\n            existsLink = false;\n            forEachNode(processSingleNode);\n        }\n        while (existsLink);\n\n        function processSingleNode(node) {\n            if (!isNodeAbsorded(node, result) && isLinked(node, result)) {\n                absorb(node, result);\n                existsLink = true;\n            }\n        }\n\n        return result;\n    };\n\n    function isNodeAbsorded(node, result) {\n        return indexOf(result.nodes, node) >= 0;\n    }\n\n    function isLinked(node, result) {\n        var hasLink = false;\n        forEachEdgeType(function (edgeType) {\n            each$1(edgeIdGetter(node, edgeType) || [], function (edgeId) {\n                result.records[edgeType.name][edgeId] && (hasLink = true);\n            });\n        });\n        return hasLink;\n    }\n\n    function absorb(node, result) {\n        result.nodes.push(node);\n        forEachEdgeType(function (edgeType) {\n            each$1(edgeIdGetter(node, edgeType) || [], function (edgeId) {\n                result.records[edgeType.name][edgeId] = true;\n            });\n        });\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$22 = each$1;\nvar asc$1 = asc;\n\n/**\n * Operate single axis.\n * One axis can only operated by one axis operator.\n * Different dataZoomModels may be defined to operate the same axis.\n * (i.e. 'inside' data zoom and 'slider' data zoom components)\n * So dataZoomModels share one axisProxy in that case.\n *\n * @class\n */\nvar AxisProxy = function (dimName, axisIndex, dataZoomModel, ecModel) {\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._dimName = dimName;\n\n    /**\n     * @private\n     */\n    this._axisIndex = axisIndex;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._valueWindow;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._percentWindow;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._dataExtent;\n\n    /**\n     * {minSpan, maxSpan, minValueSpan, maxValueSpan}\n     * @private\n     * @type {Object}\n     */\n    this._minMaxSpan;\n\n    /**\n     * @readOnly\n     * @type {module: echarts/model/Global}\n     */\n    this.ecModel = ecModel;\n\n    /**\n     * @private\n     * @type {module: echarts/component/dataZoom/DataZoomModel}\n     */\n    this._dataZoomModel = dataZoomModel;\n\n    // /**\n    //  * @readOnly\n    //  * @private\n    //  */\n    // this.hasSeriesStacked;\n};\n\nAxisProxy.prototype = {\n\n    constructor: AxisProxy,\n\n    /**\n     * Whether the axisProxy is hosted by dataZoomModel.\n     *\n     * @public\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     * @return {boolean}\n     */\n    hostedBy: function (dataZoomModel) {\n        return this._dataZoomModel === dataZoomModel;\n    },\n\n    /**\n     * @return {Array.<number>} Value can only be NaN or finite value.\n     */\n    getDataValueWindow: function () {\n        return this._valueWindow.slice();\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getDataPercentWindow: function () {\n        return this._percentWindow.slice();\n    },\n\n    /**\n     * @public\n     * @param {number} axisIndex\n     * @return {Array} seriesModels\n     */\n    getTargetSeriesModels: function () {\n        var seriesModels = [];\n        var ecModel = this.ecModel;\n\n        ecModel.eachSeries(function (seriesModel) {\n            if (isCoordSupported(seriesModel.get('coordinateSystem'))) {\n                var dimName = this._dimName;\n                var axisModel = ecModel.queryComponents({\n                    mainType: dimName + 'Axis',\n                    index: seriesModel.get(dimName + 'AxisIndex'),\n                    id: seriesModel.get(dimName + 'AxisId')\n                })[0];\n                if (this._axisIndex === (axisModel && axisModel.componentIndex)) {\n                    seriesModels.push(seriesModel);\n                }\n            }\n        }, this);\n\n        return seriesModels;\n    },\n\n    getAxisModel: function () {\n        return this.ecModel.getComponent(this._dimName + 'Axis', this._axisIndex);\n    },\n\n    getOtherAxisModel: function () {\n        var axisDim = this._dimName;\n        var ecModel = this.ecModel;\n        var axisModel = this.getAxisModel();\n        var isCartesian = axisDim === 'x' || axisDim === 'y';\n        var otherAxisDim;\n        var coordSysIndexName;\n        if (isCartesian) {\n            coordSysIndexName = 'gridIndex';\n            otherAxisDim = axisDim === 'x' ? 'y' : 'x';\n        }\n        else {\n            coordSysIndexName = 'polarIndex';\n            otherAxisDim = axisDim === 'angle' ? 'radius' : 'angle';\n        }\n        var foundOtherAxisModel;\n        ecModel.eachComponent(otherAxisDim + 'Axis', function (otherAxisModel) {\n            if ((otherAxisModel.get(coordSysIndexName) || 0)\n                === (axisModel.get(coordSysIndexName) || 0)\n            ) {\n                foundOtherAxisModel = otherAxisModel;\n            }\n        });\n        return foundOtherAxisModel;\n    },\n\n    getMinMaxSpan: function () {\n        return clone(this._minMaxSpan);\n    },\n\n    /**\n     * Only calculate by given range and this._dataExtent, do not change anything.\n     *\n     * @param {Object} opt\n     * @param {number} [opt.start]\n     * @param {number} [opt.end]\n     * @param {number} [opt.startValue]\n     * @param {number} [opt.endValue]\n     */\n    calculateDataWindow: function (opt) {\n        var dataExtent = this._dataExtent;\n        var axisModel = this.getAxisModel();\n        var scale = axisModel.axis.scale;\n        var rangePropMode = this._dataZoomModel.getRangePropMode();\n        var percentExtent = [0, 100];\n        var percentWindow = [\n            opt.start,\n            opt.end\n        ];\n        var valueWindow = [];\n\n        each$22(['startValue', 'endValue'], function (prop) {\n            valueWindow.push(opt[prop] != null ? scale.parse(opt[prop]) : null);\n        });\n\n        // Normalize bound.\n        each$22([0, 1], function (idx) {\n            var boundValue = valueWindow[idx];\n            var boundPercent = percentWindow[idx];\n\n            // Notice: dataZoom is based either on `percentProp` ('start', 'end') or\n            // on `valueProp` ('startValue', 'endValue'). The former one is suitable\n            // for cases that a dataZoom component controls multiple axes with different\n            // unit or extent, and the latter one is suitable for accurate zoom by pixel\n            // (e.g., in dataZoomSelect). `valueProp` can be calculated from `percentProp`,\n            // but it is awkward that `percentProp` can not be obtained from `valueProp`\n            // accurately (because all of values that are overflow the `dataExtent` will\n            // be calculated to percent '100%'). So we have to use\n            // `dataZoom.getRangePropMode()` to mark which prop is used.\n            // `rangePropMode` is updated only when setOption or dispatchAction, otherwise\n            // it remains its original value.\n\n            if (rangePropMode[idx] === 'percent') {\n                if (boundPercent == null) {\n                    boundPercent = percentExtent[idx];\n                }\n                // Use scale.parse to math round for category or time axis.\n                boundValue = scale.parse(linearMap(\n                    boundPercent, percentExtent, dataExtent, true\n                ));\n            }\n            else {\n                // Calculating `percent` from `value` may be not accurate, because\n                // This calculation can not be inversed, because all of values that\n                // are overflow the `dataExtent` will be calculated to percent '100%'\n                boundPercent = linearMap(\n                    boundValue, dataExtent, percentExtent, true\n                );\n            }\n\n            // valueWindow[idx] = round(boundValue);\n            // percentWindow[idx] = round(boundPercent);\n            valueWindow[idx] = boundValue;\n            percentWindow[idx] = boundPercent;\n        });\n\n        return {\n            valueWindow: asc$1(valueWindow),\n            percentWindow: asc$1(percentWindow)\n        };\n    },\n\n    /**\n     * Notice: reset should not be called before series.restoreData() called,\n     * so it is recommanded to be called in \"process stage\" but not \"model init\n     * stage\".\n     *\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    reset: function (dataZoomModel) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        var targetSeries = this.getTargetSeriesModels();\n        // Culculate data window and data extent, and record them.\n        this._dataExtent = calculateDataExtent(this, this._dimName, targetSeries);\n\n        // this.hasSeriesStacked = false;\n        // each(targetSeries, function (series) {\n            // var data = series.getData();\n            // var dataDim = data.mapDimension(this._dimName);\n            // var stackedDimension = data.getCalculationInfo('stackedDimension');\n            // if (stackedDimension && stackedDimension === dataDim) {\n                // this.hasSeriesStacked = true;\n            // }\n        // }, this);\n\n        var dataWindow = this.calculateDataWindow(dataZoomModel.option);\n\n        this._valueWindow = dataWindow.valueWindow;\n        this._percentWindow = dataWindow.percentWindow;\n\n        setMinMaxSpan(this);\n\n        // Update axis setting then.\n        setAxisModel(this);\n    },\n\n    /**\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    restore: function (dataZoomModel) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        this._valueWindow = this._percentWindow = null;\n        setAxisModel(this, true);\n    },\n\n    /**\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    filterData: function (dataZoomModel, api) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        var axisDim = this._dimName;\n        var seriesModels = this.getTargetSeriesModels();\n        var filterMode = dataZoomModel.get('filterMode');\n        var valueWindow = this._valueWindow;\n\n        if (filterMode === 'none') {\n            return;\n        }\n\n        // FIXME\n        // Toolbox may has dataZoom injected. And if there are stacked bar chart\n        // with NaN data, NaN will be filtered and stack will be wrong.\n        // So we need to force the mode to be set empty.\n        // In fect, it is not a big deal that do not support filterMode-'filter'\n        // when using toolbox#dataZoom, utill tooltip#dataZoom support \"single axis\n        // selection\" some day, which might need \"adapt to data extent on the\n        // otherAxis\", which is disabled by filterMode-'empty'.\n        // But currently, stack has been fixed to based on value but not index,\n        // so this is not an issue any more.\n        // var otherAxisModel = this.getOtherAxisModel();\n        // if (dataZoomModel.get('$fromToolbox')\n        //     && otherAxisModel\n        //     && otherAxisModel.hasSeriesStacked\n        // ) {\n        //     filterMode = 'empty';\n        // }\n\n        // TODO\n        // filterMode 'weakFilter' and 'empty' is not optimized for huge data yet.\n\n        each$22(seriesModels, function (seriesModel) {\n            var seriesData = seriesModel.getData();\n            var dataDims = seriesData.mapDimension(axisDim, true);\n\n            if (!dataDims.length) {\n                return;\n            }\n\n            if (filterMode === 'weakFilter') {\n                seriesData.filterSelf(function (dataIndex) {\n                    var leftOut;\n                    var rightOut;\n                    var hasValue;\n                    for (var i = 0; i < dataDims.length; i++) {\n                        var value = seriesData.get(dataDims[i], dataIndex);\n                        var thisHasValue = !isNaN(value);\n                        var thisLeftOut = value < valueWindow[0];\n                        var thisRightOut = value > valueWindow[1];\n                        if (thisHasValue && !thisLeftOut && !thisRightOut) {\n                            return true;\n                        }\n                        thisHasValue && (hasValue = true);\n                        thisLeftOut && (leftOut = true);\n                        thisRightOut && (rightOut = true);\n                    }\n                    // If both left out and right out, do not filter.\n                    return hasValue && leftOut && rightOut;\n                });\n            }\n            else {\n                each$22(dataDims, function (dim) {\n                    if (filterMode === 'empty') {\n                        seriesModel.setData(\n                            seriesData.map(dim, function (value) {\n                                return !isInWindow(value) ? NaN : value;\n                            })\n                        );\n                    }\n                    else {\n                        var range = {};\n                        range[dim] = valueWindow;\n\n                        // console.time('select');\n                        seriesData.selectRange(range);\n                        // console.timeEnd('select');\n                    }\n                });\n            }\n\n            each$22(dataDims, function (dim) {\n                seriesData.setApproximateExtent(valueWindow, dim);\n            });\n        });\n\n        function isInWindow(value) {\n            return value >= valueWindow[0] && value <= valueWindow[1];\n        }\n    }\n};\n\nfunction calculateDataExtent(axisProxy, axisDim, seriesModels) {\n    var dataExtent = [Infinity, -Infinity];\n\n    each$22(seriesModels, function (seriesModel) {\n        var seriesData = seriesModel.getData();\n        if (seriesData) {\n            each$22(seriesData.mapDimension(axisDim, true), function (dim) {\n                var seriesExtent = seriesData.getApproximateExtent(dim);\n                seriesExtent[0] < dataExtent[0] && (dataExtent[0] = seriesExtent[0]);\n                seriesExtent[1] > dataExtent[1] && (dataExtent[1] = seriesExtent[1]);\n            });\n        }\n    });\n\n    if (dataExtent[1] < dataExtent[0]) {\n        dataExtent = [NaN, NaN];\n    }\n\n    // It is important to get \"consistent\" extent when more then one axes is\n    // controlled by a `dataZoom`, otherwise those axes will not be synchronized\n    // when zooming. But it is difficult to know what is \"consistent\", considering\n    // axes have different type or even different meanings (For example, two\n    // time axes are used to compare data of the same date in different years).\n    // So basically dataZoom just obtains extent by series.data (in category axis\n    // extent can be obtained from axis.data).\n    // Nevertheless, user can set min/max/scale on axes to make extent of axes\n    // consistent.\n    fixExtentByAxis(axisProxy, dataExtent);\n\n    return dataExtent;\n}\n\nfunction fixExtentByAxis(axisProxy, dataExtent) {\n    var axisModel = axisProxy.getAxisModel();\n    var min = axisModel.getMin(true);\n\n    // For category axis, if min/max/scale are not set, extent is determined\n    // by axis.data by default.\n    var isCategoryAxis = axisModel.get('type') === 'category';\n    var axisDataLen = isCategoryAxis && axisModel.getCategories().length;\n\n    if (min != null && min !== 'dataMin' && typeof min !== 'function') {\n        dataExtent[0] = min;\n    }\n    else if (isCategoryAxis) {\n        dataExtent[0] = axisDataLen > 0 ? 0 : NaN;\n    }\n\n    var max = axisModel.getMax(true);\n    if (max != null && max !== 'dataMax' && typeof max !== 'function') {\n        dataExtent[1] = max;\n    }\n    else if (isCategoryAxis) {\n        dataExtent[1] = axisDataLen > 0 ? axisDataLen - 1 : NaN;\n    }\n\n    if (!axisModel.get('scale', true)) {\n        dataExtent[0] > 0 && (dataExtent[0] = 0);\n        dataExtent[1] < 0 && (dataExtent[1] = 0);\n    }\n\n    // For value axis, if min/max/scale are not set, we just use the extent obtained\n    // by series data, which may be a little different from the extent calculated by\n    // `axisHelper.getScaleExtent`. But the different just affects the experience a\n    // little when zooming. So it will not be fixed until some users require it strongly.\n\n    return dataExtent;\n}\n\nfunction setAxisModel(axisProxy, isRestore) {\n    var axisModel = axisProxy.getAxisModel();\n\n    var percentWindow = axisProxy._percentWindow;\n    var valueWindow = axisProxy._valueWindow;\n\n    if (!percentWindow) {\n        return;\n    }\n\n    // [0, 500]: arbitrary value, guess axis extent.\n    var precision = getPixelPrecision(valueWindow, [0, 500]);\n    precision = Math.min(precision, 20);\n    // isRestore or isFull\n    var useOrigin = isRestore || (percentWindow[0] === 0 && percentWindow[1] === 100);\n\n    axisModel.setRange(\n        useOrigin ? null : +valueWindow[0].toFixed(precision),\n        useOrigin ? null : +valueWindow[1].toFixed(precision)\n    );\n}\n\nfunction setMinMaxSpan(axisProxy) {\n    var minMaxSpan = axisProxy._minMaxSpan = {};\n    var dataZoomModel = axisProxy._dataZoomModel;\n\n    each$22(['min', 'max'], function (minMax) {\n        minMaxSpan[minMax + 'Span'] = dataZoomModel.get(minMax + 'Span');\n\n        // minValueSpan and maxValueSpan has higher priority than minSpan and maxSpan\n        var valueSpan = dataZoomModel.get(minMax + 'ValueSpan');\n\n        if (valueSpan != null) {\n            minMaxSpan[minMax + 'ValueSpan'] = valueSpan;\n            valueSpan = axisProxy.getAxisModel().axis.scale.parse(valueSpan);\n\n            if (valueSpan != null) {\n                var dataExtent = axisProxy._dataExtent;\n                minMaxSpan[minMax + 'Span'] = linearMap(\n                    dataExtent[0] + valueSpan, dataExtent, [0, 100], true\n                );\n            }\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$21 = each$1;\nvar eachAxisDim = eachAxisDim$1;\n\nvar DataZoomModel = extendComponentModel({\n\n    type: 'dataZoom',\n\n    dependencies: [\n        'xAxis', 'yAxis', 'zAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'series'\n    ],\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        zlevel: 0,\n        z: 4,                   // Higher than normal component (z: 2).\n        orient: null,           // Default auto by axisIndex. Possible value: 'horizontal', 'vertical'.\n        xAxisIndex: null,       // Default the first horizontal category axis.\n        yAxisIndex: null,       // Default the first vertical category axis.\n\n        filterMode: 'filter',   // Possible values: 'filter' or 'empty' or 'weakFilter'.\n                                // 'filter': data items which are out of window will be removed. This option is\n                                //          applicable when filtering outliers. For each data item, it will be\n                                //          filtered if one of the relevant dimensions is out of the window.\n                                // 'weakFilter': data items which are out of window will be removed. This option\n                                //          is applicable when filtering outliers. For each data item, it will be\n                                //          filtered only if all  of the relevant dimensions are out of the same\n                                //          side of the window.\n                                // 'empty': data items which are out of window will be set to empty.\n                                //          This option is applicable when user should not neglect\n                                //          that there are some data items out of window.\n                                // 'none': Do not filter.\n                                // Taking line chart as an example, line will be broken in\n                                // the filtered points when filterModel is set to 'empty', but\n                                // be connected when set to 'filter'.\n\n        throttle: null,         // Dispatch action by the fixed rate, avoid frequency.\n                                // default 100. Do not throttle when use null/undefined.\n                                // If animation === true and animationDurationUpdate > 0,\n                                // default value is 100, otherwise 20.\n        start: 0,               // Start percent. 0 ~ 100\n        end: 100,               // End percent. 0 ~ 100\n        startValue: null,       // Start value. If startValue specified, start is ignored.\n        endValue: null,         // End value. If endValue specified, end is ignored.\n        minSpan: null,          // 0 ~ 100\n        maxSpan: null,          // 0 ~ 100\n        minValueSpan: null,     // The range of dataZoom can not be smaller than that.\n        maxValueSpan: null,     // The range of dataZoom can not be larger than that.\n        rangeMode: null         // Array, can be 'value' or 'percent'.\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel) {\n\n        /**\n         * key like x_0, y_1\n         * @private\n         * @type {Object}\n         */\n        this._dataIntervalByAxis = {};\n\n        /**\n         * @private\n         */\n        this._dataInfo = {};\n\n        /**\n         * key like x_0, y_1\n         * @private\n         */\n        this._axisProxies = {};\n\n        /**\n         * @readOnly\n         */\n        this.textStyleModel;\n\n        /**\n         * @private\n         */\n        this._autoThrottle = true;\n\n        /**\n         * 'percent' or 'value'\n         * @private\n         */\n        this._rangePropMode = ['percent', 'percent'];\n\n        var rawOption = retrieveRaw(option);\n\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        this.doInit(rawOption);\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (newOption) {\n        var rawOption = retrieveRaw(newOption);\n\n        //FIX #2591\n        merge(this.option, newOption, true);\n\n        this.doInit(rawOption);\n    },\n\n    /**\n     * @protected\n     */\n    doInit: function (rawOption) {\n        var thisOption = this.option;\n\n        // Disable realtime view update if canvas is not supported.\n        if (!env$1.canvasSupported) {\n            thisOption.realtime = false;\n        }\n\n        this._setDefaultThrottle(rawOption);\n\n        updateRangeUse(this, rawOption);\n\n        each$21([['start', 'startValue'], ['end', 'endValue']], function (names, index) {\n            // start/end has higher priority over startValue/endValue if they\n            // both set, but we should make chart.setOption({endValue: 1000})\n            // effective, rather than chart.setOption({endValue: 1000, end: null}).\n            if (this._rangePropMode[index] === 'value') {\n                thisOption[names[0]] = null;\n            }\n            // Otherwise do nothing and use the merge result.\n        }, this);\n\n        this.textStyleModel = this.getModel('textStyle');\n\n        this._resetTarget();\n\n        this._giveAxisProxies();\n    },\n\n    /**\n     * @private\n     */\n    _giveAxisProxies: function () {\n        var axisProxies = this._axisProxies;\n\n        this.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel, ecModel) {\n            var axisModel = this.dependentModels[dimNames.axis][axisIndex];\n\n            // If exists, share axisProxy with other dataZoomModels.\n            var axisProxy = axisModel.__dzAxisProxy || (\n                // Use the first dataZoomModel as the main model of axisProxy.\n                axisModel.__dzAxisProxy = new AxisProxy(\n                    dimNames.name, axisIndex, this, ecModel\n                )\n            );\n            // FIXME\n            // dispose __dzAxisProxy\n\n            axisProxies[dimNames.name + '_' + axisIndex] = axisProxy;\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _resetTarget: function () {\n        var thisOption = this.option;\n\n        var autoMode = this._judgeAutoMode();\n\n        eachAxisDim(function (dimNames) {\n            var axisIndexName = dimNames.axisIndex;\n            thisOption[axisIndexName] = normalizeToArray(\n                thisOption[axisIndexName]\n            );\n        }, this);\n\n        if (autoMode === 'axisIndex') {\n            this._autoSetAxisIndex();\n        }\n        else if (autoMode === 'orient') {\n            this._autoSetOrient();\n        }\n    },\n\n    /**\n     * @private\n     */\n    _judgeAutoMode: function () {\n        // Auto set only works for setOption at the first time.\n        // The following is user's reponsibility. So using merged\n        // option is OK.\n        var thisOption = this.option;\n\n        var hasIndexSpecified = false;\n        eachAxisDim(function (dimNames) {\n            // When user set axisIndex as a empty array, we think that user specify axisIndex\n            // but do not want use auto mode. Because empty array may be encountered when\n            // some error occured.\n            if (thisOption[dimNames.axisIndex] != null) {\n                hasIndexSpecified = true;\n            }\n        }, this);\n\n        var orient = thisOption.orient;\n\n        if (orient == null && hasIndexSpecified) {\n            return 'orient';\n        }\n        else if (!hasIndexSpecified) {\n            if (orient == null) {\n                thisOption.orient = 'horizontal';\n            }\n            return 'axisIndex';\n        }\n    },\n\n    /**\n     * @private\n     */\n    _autoSetAxisIndex: function () {\n        var autoAxisIndex = true;\n        var orient = this.get('orient', true);\n        var thisOption = this.option;\n        var dependentModels = this.dependentModels;\n\n        if (autoAxisIndex) {\n            // Find axis that parallel to dataZoom as default.\n            var dimName = orient === 'vertical' ? 'y' : 'x';\n\n            if (dependentModels[dimName + 'Axis'].length) {\n                thisOption[dimName + 'AxisIndex'] = [0];\n                autoAxisIndex = false;\n            }\n            else {\n                each$21(dependentModels.singleAxis, function (singleAxisModel) {\n                    if (autoAxisIndex && singleAxisModel.get('orient', true) === orient) {\n                        thisOption.singleAxisIndex = [singleAxisModel.componentIndex];\n                        autoAxisIndex = false;\n                    }\n                });\n            }\n        }\n\n        if (autoAxisIndex) {\n            // Find the first category axis as default. (consider polar)\n            eachAxisDim(function (dimNames) {\n                if (!autoAxisIndex) {\n                    return;\n                }\n                var axisIndices = [];\n                var axisModels = this.dependentModels[dimNames.axis];\n                if (axisModels.length && !axisIndices.length) {\n                    for (var i = 0, len = axisModels.length; i < len; i++) {\n                        if (axisModels[i].get('type') === 'category') {\n                            axisIndices.push(i);\n                        }\n                    }\n                }\n                thisOption[dimNames.axisIndex] = axisIndices;\n                if (axisIndices.length) {\n                    autoAxisIndex = false;\n                }\n            }, this);\n        }\n\n        if (autoAxisIndex) {\n            // FIXME\n            // 这里是兼容ec2的写法（没指定xAxisIndex和yAxisIndex时把scatter和双数值轴折柱纳入dataZoom控制），\n            // 但是实际是否需要Grid.js#getScaleByOption来判断（考虑time，log等axis type）？\n\n            // If both dataZoom.xAxisIndex and dataZoom.yAxisIndex is not specified,\n            // dataZoom component auto adopts series that reference to\n            // both xAxis and yAxis which type is 'value'.\n            this.ecModel.eachSeries(function (seriesModel) {\n                if (this._isSeriesHasAllAxesTypeOf(seriesModel, 'value')) {\n                    eachAxisDim(function (dimNames) {\n                        var axisIndices = thisOption[dimNames.axisIndex];\n\n                        var axisIndex = seriesModel.get(dimNames.axisIndex);\n                        var axisId = seriesModel.get(dimNames.axisId);\n\n                        var axisModel = seriesModel.ecModel.queryComponents({\n                            mainType: dimNames.axis,\n                            index: axisIndex,\n                            id: axisId\n                        })[0];\n\n                        if (__DEV__) {\n                            if (!axisModel) {\n                                throw new Error(\n                                    dimNames.axis + ' \"' + retrieve(\n                                        axisIndex,\n                                        axisId,\n                                        0\n                                    ) + '\" not found'\n                                );\n                            }\n                        }\n                        axisIndex = axisModel.componentIndex;\n\n                        if (indexOf(axisIndices, axisIndex) < 0) {\n                            axisIndices.push(axisIndex);\n                        }\n                    });\n                }\n            }, this);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _autoSetOrient: function () {\n        var dim;\n\n        // Find the first axis\n        this.eachTargetAxis(function (dimNames) {\n            !dim && (dim = dimNames.name);\n        }, this);\n\n        this.option.orient = dim === 'y' ? 'vertical' : 'horizontal';\n    },\n\n    /**\n     * @private\n     */\n    _isSeriesHasAllAxesTypeOf: function (seriesModel, axisType) {\n        // FIXME\n        // 需要series的xAxisIndex和yAxisIndex都首先自动设置上。\n        // 例如series.type === scatter时。\n\n        var is = true;\n        eachAxisDim(function (dimNames) {\n            var seriesAxisIndex = seriesModel.get(dimNames.axisIndex);\n            var axisModel = this.dependentModels[dimNames.axis][seriesAxisIndex];\n\n            if (!axisModel || axisModel.get('type') !== axisType) {\n                is = false;\n            }\n        }, this);\n        return is;\n    },\n\n    /**\n     * @private\n     */\n    _setDefaultThrottle: function (rawOption) {\n        // When first time user set throttle, auto throttle ends.\n        if (rawOption.hasOwnProperty('throttle')) {\n            this._autoThrottle = false;\n        }\n        if (this._autoThrottle) {\n            var globalOption = this.ecModel.option;\n            this.option.throttle\n                = (globalOption.animation && globalOption.animationDurationUpdate > 0)\n                ? 100 : 20;\n        }\n    },\n\n    /**\n     * @public\n     */\n    getFirstTargetAxisModel: function () {\n        var firstAxisModel;\n        eachAxisDim(function (dimNames) {\n            if (firstAxisModel == null) {\n                var indices = this.get(dimNames.axisIndex);\n                if (indices.length) {\n                    firstAxisModel = this.dependentModels[dimNames.axis][indices[0]];\n                }\n            }\n        }, this);\n\n        return firstAxisModel;\n    },\n\n    /**\n     * @public\n     * @param {Function} callback param: axisModel, dimNames, axisIndex, dataZoomModel, ecModel\n     */\n    eachTargetAxis: function (callback, context) {\n        var ecModel = this.ecModel;\n        eachAxisDim(function (dimNames) {\n            each$21(\n                this.get(dimNames.axisIndex),\n                function (axisIndex) {\n                    callback.call(context, dimNames, axisIndex, this, ecModel);\n                },\n                this\n            );\n        }, this);\n    },\n\n    /**\n     * @param {string} dimName\n     * @param {number} axisIndex\n     * @return {module:echarts/component/dataZoom/AxisProxy} If not found, return null/undefined.\n     */\n    getAxisProxy: function (dimName, axisIndex) {\n        return this._axisProxies[dimName + '_' + axisIndex];\n    },\n\n    /**\n     * @param {string} dimName\n     * @param {number} axisIndex\n     * @return {module:echarts/model/Model} If not found, return null/undefined.\n     */\n    getAxisModel: function (dimName, axisIndex) {\n        var axisProxy = this.getAxisProxy(dimName, axisIndex);\n        return axisProxy && axisProxy.getAxisModel();\n    },\n\n    /**\n     * If not specified, set to undefined.\n     *\n     * @public\n     * @param {Object} opt\n     * @param {number} [opt.start]\n     * @param {number} [opt.end]\n     * @param {number} [opt.startValue]\n     * @param {number} [opt.endValue]\n     * @param {boolean} [ignoreUpdateRangeUsg=false]\n     */\n    setRawRange: function (opt, ignoreUpdateRangeUsg) {\n        var option = this.option;\n        each$21([['start', 'startValue'], ['end', 'endValue']], function (names) {\n            // If only one of 'start' and 'startValue' is not null/undefined, the other\n            // should be cleared, which enable clear the option.\n            // If both of them are not set, keep option with the original value, which\n            // enable use only set start but not set end when calling `dispatchAction`.\n            // The same as 'end' and 'endValue'.\n            if (opt[names[0]] != null || opt[names[1]] != null) {\n                option[names[0]] = opt[names[0]];\n                option[names[1]] = opt[names[1]];\n            }\n        }, this);\n\n        !ignoreUpdateRangeUsg && updateRangeUse(this, opt);\n    },\n\n    /**\n     * @public\n     * @return {Array.<number>} [startPercent, endPercent]\n     */\n    getPercentRange: function () {\n        var axisProxy = this.findRepresentativeAxisProxy();\n        if (axisProxy) {\n            return axisProxy.getDataPercentWindow();\n        }\n    },\n\n    /**\n     * @public\n     * For example, chart.getModel().getComponent('dataZoom').getValueRange('y', 0);\n     *\n     * @param {string} [axisDimName]\n     * @param {number} [axisIndex]\n     * @return {Array.<number>} [startValue, endValue] value can only be '-' or finite number.\n     */\n    getValueRange: function (axisDimName, axisIndex) {\n        if (axisDimName == null && axisIndex == null) {\n            var axisProxy = this.findRepresentativeAxisProxy();\n            if (axisProxy) {\n                return axisProxy.getDataValueWindow();\n            }\n        }\n        else {\n            return this.getAxisProxy(axisDimName, axisIndex).getDataValueWindow();\n        }\n    },\n\n    /**\n     * @public\n     * @param {module:echarts/model/Model} [axisModel] If axisModel given, find axisProxy\n     *      corresponding to the axisModel\n     * @return {module:echarts/component/dataZoom/AxisProxy}\n     */\n    findRepresentativeAxisProxy: function (axisModel) {\n        if (axisModel) {\n            return axisModel.__dzAxisProxy;\n        }\n\n        // Find the first hosted axisProxy\n        var axisProxies = this._axisProxies;\n        for (var key in axisProxies) {\n            if (axisProxies.hasOwnProperty(key) && axisProxies[key].hostedBy(this)) {\n                return axisProxies[key];\n            }\n        }\n\n        // If no hosted axis find not hosted axisProxy.\n        // Consider this case: dataZoomModel1 and dataZoomModel2 control the same axis,\n        // and the option.start or option.end settings are different. The percentRange\n        // should follow axisProxy.\n        // (We encounter this problem in toolbox data zoom.)\n        for (var key in axisProxies) {\n            if (axisProxies.hasOwnProperty(key) && !axisProxies[key].hostedBy(this)) {\n                return axisProxies[key];\n            }\n        }\n    },\n\n    /**\n     * @return {Array.<string>}\n     */\n    getRangePropMode: function () {\n        return this._rangePropMode.slice();\n    }\n\n});\n\nfunction retrieveRaw(option) {\n    var ret = {};\n    each$21(\n        ['start', 'end', 'startValue', 'endValue', 'throttle'],\n        function (name) {\n            option.hasOwnProperty(name) && (ret[name] = option[name]);\n        }\n    );\n    return ret;\n}\n\nfunction updateRangeUse(dataZoomModel, rawOption) {\n    var rangePropMode = dataZoomModel._rangePropMode;\n    var rangeModeInOption = dataZoomModel.get('rangeMode');\n\n    each$21([['start', 'startValue'], ['end', 'endValue']], function (names, index) {\n        var percentSpecified = rawOption[names[0]] != null;\n        var valueSpecified = rawOption[names[1]] != null;\n        if (percentSpecified && !valueSpecified) {\n            rangePropMode[index] = 'percent';\n        }\n        else if (!percentSpecified && valueSpecified) {\n            rangePropMode[index] = 'value';\n        }\n        else if (rangeModeInOption) {\n            rangePropMode[index] = rangeModeInOption[index];\n        }\n        else if (percentSpecified) { // percentSpecified && valueSpecified\n            rangePropMode[index] = 'percent';\n        }\n        // else remain its original setting.\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DataZoomView = Component.extend({\n\n    type: 'dataZoom',\n\n    render: function (dataZoomModel, ecModel, api, payload) {\n        this.dataZoomModel = dataZoomModel;\n        this.ecModel = ecModel;\n        this.api = api;\n    },\n\n    /**\n     * Find the first target coordinate system.\n     *\n     * @protected\n     * @return {Object} {\n     *                   grid: [\n     *                       {model: coord0, axisModels: [axis1, axis3], coordIndex: 1},\n     *                       {model: coord1, axisModels: [axis0, axis2], coordIndex: 0},\n     *                       ...\n     *                   ],  // cartesians must not be null/undefined.\n     *                   polar: [\n     *                       {model: coord0, axisModels: [axis4], coordIndex: 0},\n     *                       ...\n     *                   ],  // polars must not be null/undefined.\n     *                   singleAxis: [\n     *                       {model: coord0, axisModels: [], coordIndex: 0}\n     *                   ]\n     */\n    getTargetCoordInfo: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var ecModel = this.ecModel;\n        var coordSysLists = {};\n\n        dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {\n            var axisModel = ecModel.getComponent(dimNames.axis, axisIndex);\n            if (axisModel) {\n                var coordModel = axisModel.getCoordSysModel();\n                coordModel && save(\n                    coordModel,\n                    axisModel,\n                    coordSysLists[coordModel.mainType] || (coordSysLists[coordModel.mainType] = []),\n                    coordModel.componentIndex\n                );\n            }\n        }, this);\n\n        function save(coordModel, axisModel, store, coordIndex) {\n            var item;\n            for (var i = 0; i < store.length; i++) {\n                if (store[i].model === coordModel) {\n                    item = store[i];\n                    break;\n                }\n            }\n            if (!item) {\n                store.push(item = {\n                    model: coordModel, axisModels: [], coordIndex: coordIndex\n                });\n            }\n            item.axisModels.push(axisModel);\n        }\n\n        return coordSysLists;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar SliderZoomModel = DataZoomModel.extend({\n\n    type: 'dataZoom.slider',\n\n    layoutMode: 'box',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        show: true,\n\n        // ph => placeholder. Using placehoder here because\n        // deault value can only be drived in view stage.\n        right: 'ph',  // Default align to grid rect.\n        top: 'ph',    // Default align to grid rect.\n        width: 'ph',  // Default align to grid rect.\n        height: 'ph', // Default align to grid rect.\n        left: null,   // Default align to grid rect.\n        bottom: null, // Default align to grid rect.\n\n        backgroundColor: 'rgba(47,69,84,0)',    // Background of slider zoom component.\n        // dataBackgroundColor: '#ddd',         // Background coor of data shadow and border of box,\n                                                // highest priority, remain for compatibility of\n                                                // previous version, but not recommended any more.\n        dataBackground: {\n            lineStyle: {\n                color: '#2f4554',\n                width: 0.5,\n                opacity: 0.3\n            },\n            areaStyle: {\n                color: 'rgba(47,69,84,0.3)',\n                opacity: 0.3\n            }\n        },\n        borderColor: '#ddd',                    // border color of the box. For compatibility,\n                                                // if dataBackgroundColor is set, borderColor\n                                                // is ignored.\n\n        fillerColor: 'rgba(167,183,204,0.4)',     // Color of selected area.\n        // handleColor: 'rgba(89,170,216,0.95)',     // Color of handle.\n        // handleIcon: 'path://M4.9,17.8c0-1.4,4.5-10.5,5.5-12.4c0-0.1,0.6-1.1,0.9-1.1c0.4,0,0.9,1,0.9,1.1c1.1,2.2,5.4,11,5.4,12.4v17.8c0,1.5-0.6,2.1-1.3,2.1H6.1c-0.7,0-1.3-0.6-1.3-2.1V17.8z',\n        /* eslint-disable */\n        handleIcon: 'M8.2,13.6V3.9H6.3v9.7H3.1v14.9h3.3v9.7h1.8v-9.7h3.3V13.6H8.2z M9.7,24.4H4.8v-1.4h4.9V24.4z M9.7,19.1H4.8v-1.4h4.9V19.1z',\n        /* eslint-enable */\n        // Percent of the slider height\n        handleSize: '100%',\n\n        handleStyle: {\n            color: '#a7b7cc'\n        },\n\n        labelPrecision: null,\n        labelFormatter: null,\n        showDetail: true,\n        showDataShadow: 'auto',                 // Default auto decision.\n        realtime: true,\n        zoomLock: false,                        // Whether disable zoom.\n        textStyle: {\n            color: '#333'\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar Rect$2 = Rect;\nvar linearMap$1 = linearMap;\nvar asc$2 = asc;\nvar bind$4 = bind;\nvar each$23 = each$1;\n\n// Constants\nvar DEFAULT_LOCATION_EDGE_GAP = 7;\nvar DEFAULT_FRAME_BORDER_WIDTH = 1;\nvar DEFAULT_FILLER_SIZE = 30;\nvar HORIZONTAL = 'horizontal';\nvar VERTICAL = 'vertical';\nvar LABEL_GAP = 5;\nvar SHOW_DATA_SHADOW_SERIES_TYPE = ['line', 'bar', 'candlestick', 'scatter'];\n\nvar SliderZoomView = DataZoomView.extend({\n\n    type: 'dataZoom.slider',\n\n    init: function (ecModel, api) {\n\n        /**\n         * @private\n         * @type {Object}\n         */\n        this._displayables = {};\n\n        /**\n         * @private\n         * @type {string}\n         */\n        this._orient;\n\n        /**\n         * [0, 100]\n         * @private\n         */\n        this._range;\n\n        /**\n         * [coord of the first handle, coord of the second handle]\n         * @private\n         */\n        this._handleEnds;\n\n        /**\n         * [length, thick]\n         * @private\n         * @type {Array.<number>}\n         */\n        this._size;\n\n        /**\n         * @private\n         * @type {number}\n         */\n        this._handleWidth;\n\n        /**\n         * @private\n         * @type {number}\n         */\n        this._handleHeight;\n\n        /**\n         * @private\n         */\n        this._location;\n\n        /**\n         * @private\n         */\n        this._dragging;\n\n        /**\n         * @private\n         */\n        this._dataShadowInfo;\n\n        this.api = api;\n    },\n\n    /**\n     * @override\n     */\n    render: function (dataZoomModel, ecModel, api, payload) {\n        SliderZoomView.superApply(this, 'render', arguments);\n\n        createOrUpdate(\n            this,\n            '_dispatchZoomAction',\n            this.dataZoomModel.get('throttle'),\n            'fixRate'\n        );\n\n        this._orient = dataZoomModel.get('orient');\n\n        if (this.dataZoomModel.get('show') === false) {\n            this.group.removeAll();\n            return;\n        }\n\n        // Notice: this._resetInterval() should not be executed when payload.type\n        // is 'dataZoom', origin this._range should be maintained, otherwise 'pan'\n        // or 'zoom' info will be missed because of 'throttle' of this.dispatchAction,\n        if (!payload || payload.type !== 'dataZoom' || payload.from !== this.uid) {\n            this._buildView();\n        }\n\n        this._updateView();\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        SliderZoomView.superApply(this, 'remove', arguments);\n        clear(this, '_dispatchZoomAction');\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        SliderZoomView.superApply(this, 'dispose', arguments);\n        clear(this, '_dispatchZoomAction');\n    },\n\n    _buildView: function () {\n        var thisGroup = this.group;\n\n        thisGroup.removeAll();\n\n        this._resetLocation();\n        this._resetInterval();\n\n        var barGroup = this._displayables.barGroup = new Group();\n\n        this._renderBackground();\n\n        this._renderHandle();\n\n        this._renderDataShadow();\n\n        thisGroup.add(barGroup);\n\n        this._positionGroup();\n    },\n\n    /**\n     * @private\n     */\n    _resetLocation: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var api = this.api;\n\n        // If some of x/y/width/height are not specified,\n        // auto-adapt according to target grid.\n        var coordRect = this._findCoordRect();\n        var ecSize = {width: api.getWidth(), height: api.getHeight()};\n        // Default align by coordinate system rect.\n        var positionInfo = this._orient === HORIZONTAL\n            ? {\n                // Why using 'right', because right should be used in vertical,\n                // and it is better to be consistent for dealing with position param merge.\n                right: ecSize.width - coordRect.x - coordRect.width,\n                top: (ecSize.height - DEFAULT_FILLER_SIZE - DEFAULT_LOCATION_EDGE_GAP),\n                width: coordRect.width,\n                height: DEFAULT_FILLER_SIZE\n            }\n            : { // vertical\n                right: DEFAULT_LOCATION_EDGE_GAP,\n                top: coordRect.y,\n                width: DEFAULT_FILLER_SIZE,\n                height: coordRect.height\n            };\n\n        // Do not write back to option and replace value 'ph', because\n        // the 'ph' value should be recalculated when resize.\n        var layoutParams = getLayoutParams(dataZoomModel.option);\n\n        // Replace the placeholder value.\n        each$1(['right', 'top', 'width', 'height'], function (name) {\n            if (layoutParams[name] === 'ph') {\n                layoutParams[name] = positionInfo[name];\n            }\n        });\n\n        var layoutRect = getLayoutRect(\n            layoutParams,\n            ecSize,\n            dataZoomModel.padding\n        );\n\n        this._location = {x: layoutRect.x, y: layoutRect.y};\n        this._size = [layoutRect.width, layoutRect.height];\n        this._orient === VERTICAL && this._size.reverse();\n    },\n\n    /**\n     * @private\n     */\n    _positionGroup: function () {\n        var thisGroup = this.group;\n        var location = this._location;\n        var orient = this._orient;\n\n        // Just use the first axis to determine mapping.\n        var targetAxisModel = this.dataZoomModel.getFirstTargetAxisModel();\n        var inverse = targetAxisModel && targetAxisModel.get('inverse');\n\n        var barGroup = this._displayables.barGroup;\n        var otherAxisInverse = (this._dataShadowInfo || {}).otherAxisInverse;\n\n        // Transform barGroup.\n        barGroup.attr(\n            (orient === HORIZONTAL && !inverse)\n            ? {scale: otherAxisInverse ? [1, 1] : [1, -1]}\n            : (orient === HORIZONTAL && inverse)\n            ? {scale: otherAxisInverse ? [-1, 1] : [-1, -1]}\n            : (orient === VERTICAL && !inverse)\n            ? {scale: otherAxisInverse ? [1, -1] : [1, 1], rotation: Math.PI / 2}\n            // Dont use Math.PI, considering shadow direction.\n            : {scale: otherAxisInverse ? [-1, -1] : [-1, 1], rotation: Math.PI / 2}\n        );\n\n        // Position barGroup\n        var rect = thisGroup.getBoundingRect([barGroup]);\n        thisGroup.attr('position', [location.x - rect.x, location.y - rect.y]);\n    },\n\n    /**\n     * @private\n     */\n    _getViewExtent: function () {\n        return [0, this._size[0]];\n    },\n\n    _renderBackground: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var size = this._size;\n        var barGroup = this._displayables.barGroup;\n\n        barGroup.add(new Rect$2({\n            silent: true,\n            shape: {\n                x: 0, y: 0, width: size[0], height: size[1]\n            },\n            style: {\n                fill: dataZoomModel.get('backgroundColor')\n            },\n            z2: -40\n        }));\n\n        // Click panel, over shadow, below handles.\n        barGroup.add(new Rect$2({\n            shape: {\n                x: 0, y: 0, width: size[0], height: size[1]\n            },\n            style: {\n                fill: 'transparent'\n            },\n            z2: 0,\n            onclick: bind(this._onClickPanelClick, this)\n        }));\n    },\n\n    _renderDataShadow: function () {\n        var info = this._dataShadowInfo = this._prepareDataShadowInfo();\n\n        if (!info) {\n            return;\n        }\n\n        var size = this._size;\n        var seriesModel = info.series;\n        var data = seriesModel.getRawData();\n\n        var otherDim = seriesModel.getShadowDim\n            ? seriesModel.getShadowDim() // @see candlestick\n            : info.otherDim;\n\n        if (otherDim == null) {\n            return;\n        }\n\n        var otherDataExtent = data.getDataExtent(otherDim);\n        // Nice extent.\n        var otherOffset = (otherDataExtent[1] - otherDataExtent[0]) * 0.3;\n        otherDataExtent = [\n            otherDataExtent[0] - otherOffset,\n            otherDataExtent[1] + otherOffset\n        ];\n        var otherShadowExtent = [0, size[1]];\n\n        var thisShadowExtent = [0, size[0]];\n\n        var areaPoints = [[size[0], 0], [0, 0]];\n        var linePoints = [];\n        var step = thisShadowExtent[1] / (data.count() - 1);\n        var thisCoord = 0;\n\n        // Optimize for large data shadow\n        var stride = Math.round(data.count() / size[0]);\n        var lastIsEmpty;\n        data.each([otherDim], function (value, index) {\n            if (stride > 0 && (index % stride)) {\n                thisCoord += step;\n                return;\n            }\n\n            // FIXME\n            // Should consider axis.min/axis.max when drawing dataShadow.\n\n            // FIXME\n            // 应该使用统一的空判断？还是在list里进行空判断？\n            var isEmpty = value == null || isNaN(value) || value === '';\n            // See #4235.\n            var otherCoord = isEmpty\n                ? 0 : linearMap$1(value, otherDataExtent, otherShadowExtent, true);\n\n            // Attempt to draw data shadow precisely when there are empty value.\n            if (isEmpty && !lastIsEmpty && index) {\n                areaPoints.push([areaPoints[areaPoints.length - 1][0], 0]);\n                linePoints.push([linePoints[linePoints.length - 1][0], 0]);\n            }\n            else if (!isEmpty && lastIsEmpty) {\n                areaPoints.push([thisCoord, 0]);\n                linePoints.push([thisCoord, 0]);\n            }\n\n            areaPoints.push([thisCoord, otherCoord]);\n            linePoints.push([thisCoord, otherCoord]);\n\n            thisCoord += step;\n            lastIsEmpty = isEmpty;\n        });\n\n        var dataZoomModel = this.dataZoomModel;\n        // var dataBackgroundModel = dataZoomModel.getModel('dataBackground');\n        this._displayables.barGroup.add(new Polygon({\n            shape: {points: areaPoints},\n            style: defaults(\n                {fill: dataZoomModel.get('dataBackgroundColor')},\n                dataZoomModel.getModel('dataBackground.areaStyle').getAreaStyle()\n            ),\n            silent: true,\n            z2: -20\n        }));\n        this._displayables.barGroup.add(new Polyline({\n            shape: {points: linePoints},\n            style: dataZoomModel.getModel('dataBackground.lineStyle').getLineStyle(),\n            silent: true,\n            z2: -19\n        }));\n    },\n\n    _prepareDataShadowInfo: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var showDataShadow = dataZoomModel.get('showDataShadow');\n\n        if (showDataShadow === false) {\n            return;\n        }\n\n        // Find a representative series.\n        var result;\n        var ecModel = this.ecModel;\n\n        dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {\n            var seriesModels = dataZoomModel\n                .getAxisProxy(dimNames.name, axisIndex)\n                .getTargetSeriesModels();\n\n            each$1(seriesModels, function (seriesModel) {\n                if (result) {\n                    return;\n                }\n\n                if (showDataShadow !== true && indexOf(\n                        SHOW_DATA_SHADOW_SERIES_TYPE, seriesModel.get('type')\n                    ) < 0\n                ) {\n                    return;\n                }\n\n                var thisAxis = ecModel.getComponent(dimNames.axis, axisIndex).axis;\n                var otherDim = getOtherDim(dimNames.name);\n                var otherAxisInverse;\n                var coordSys = seriesModel.coordinateSystem;\n\n                if (otherDim != null && coordSys.getOtherAxis) {\n                    otherAxisInverse = coordSys.getOtherAxis(thisAxis).inverse;\n                }\n\n                otherDim = seriesModel.getData().mapDimension(otherDim);\n\n                result = {\n                    thisAxis: thisAxis,\n                    series: seriesModel,\n                    thisDim: dimNames.name,\n                    otherDim: otherDim,\n                    otherAxisInverse: otherAxisInverse\n                };\n\n            }, this);\n\n        }, this);\n\n        return result;\n    },\n\n    _renderHandle: function () {\n        var displaybles = this._displayables;\n        var handles = displaybles.handles = [];\n        var handleLabels = displaybles.handleLabels = [];\n        var barGroup = this._displayables.barGroup;\n        var size = this._size;\n        var dataZoomModel = this.dataZoomModel;\n\n        barGroup.add(displaybles.filler = new Rect$2({\n            draggable: true,\n            cursor: getCursor(this._orient),\n            drift: bind$4(this._onDragMove, this, 'all'),\n            onmousemove: function (e) {\n                // Fot mobile devicem, prevent screen slider on the button.\n                stop(e.event);\n            },\n            ondragstart: bind$4(this._showDataInfo, this, true),\n            ondragend: bind$4(this._onDragEnd, this),\n            onmouseover: bind$4(this._showDataInfo, this, true),\n            onmouseout: bind$4(this._showDataInfo, this, false),\n            style: {\n                fill: dataZoomModel.get('fillerColor'),\n                textPosition: 'inside'\n            }\n        }));\n\n        // Frame border.\n        barGroup.add(new Rect$2(subPixelOptimizeRect({\n            silent: true,\n            shape: {\n                x: 0,\n                y: 0,\n                width: size[0],\n                height: size[1]\n            },\n            style: {\n                stroke: dataZoomModel.get('dataBackgroundColor')\n                    || dataZoomModel.get('borderColor'),\n                lineWidth: DEFAULT_FRAME_BORDER_WIDTH,\n                fill: 'rgba(0,0,0,0)'\n            }\n        })));\n\n        each$23([0, 1], function (handleIndex) {\n            var path = createIcon(\n                dataZoomModel.get('handleIcon'),\n                {\n                    cursor: getCursor(this._orient),\n                    draggable: true,\n                    drift: bind$4(this._onDragMove, this, handleIndex),\n                    onmousemove: function (e) {\n                        // Fot mobile devicem, prevent screen slider on the button.\n                        stop(e.event);\n                    },\n                    ondragend: bind$4(this._onDragEnd, this),\n                    onmouseover: bind$4(this._showDataInfo, this, true),\n                    onmouseout: bind$4(this._showDataInfo, this, false)\n                },\n                {x: -1, y: 0, width: 2, height: 2}\n            );\n\n            var bRect = path.getBoundingRect();\n            this._handleHeight = parsePercent$1(dataZoomModel.get('handleSize'), this._size[1]);\n            this._handleWidth = bRect.width / bRect.height * this._handleHeight;\n\n            path.setStyle(dataZoomModel.getModel('handleStyle').getItemStyle());\n            var handleColor = dataZoomModel.get('handleColor');\n            // Compatitable with previous version\n            if (handleColor != null) {\n                path.style.fill = handleColor;\n            }\n\n            barGroup.add(handles[handleIndex] = path);\n\n            var textStyleModel = dataZoomModel.textStyleModel;\n\n            this.group.add(\n                handleLabels[handleIndex] = new Text({\n                silent: true,\n                invisible: true,\n                style: {\n                    x: 0, y: 0, text: '',\n                    textVerticalAlign: 'middle',\n                    textAlign: 'center',\n                    textFill: textStyleModel.getTextColor(),\n                    textFont: textStyleModel.getFont()\n                },\n                z2: 10\n            }));\n\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _resetInterval: function () {\n        var range = this._range = this.dataZoomModel.getPercentRange();\n        var viewExtent = this._getViewExtent();\n\n        this._handleEnds = [\n            linearMap$1(range[0], [0, 100], viewExtent, true),\n            linearMap$1(range[1], [0, 100], viewExtent, true)\n        ];\n    },\n\n    /**\n     * @private\n     * @param {(number|string)} handleIndex 0 or 1 or 'all'\n     * @param {number} delta\n     * @return {boolean} changed\n     */\n    _updateInterval: function (handleIndex, delta) {\n        var dataZoomModel = this.dataZoomModel;\n        var handleEnds = this._handleEnds;\n        var viewExtend = this._getViewExtent();\n        var minMaxSpan = dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan();\n        var percentExtent = [0, 100];\n\n        sliderMove(\n            delta,\n            handleEnds,\n            viewExtend,\n            dataZoomModel.get('zoomLock') ? 'all' : handleIndex,\n            minMaxSpan.minSpan != null\n                ? linearMap$1(minMaxSpan.minSpan, percentExtent, viewExtend, true) : null,\n            minMaxSpan.maxSpan != null\n                ? linearMap$1(minMaxSpan.maxSpan, percentExtent, viewExtend, true) : null\n        );\n\n        var lastRange = this._range;\n        var range = this._range = asc$2([\n            linearMap$1(handleEnds[0], viewExtend, percentExtent, true),\n            linearMap$1(handleEnds[1], viewExtend, percentExtent, true)\n        ]);\n\n        return !lastRange || lastRange[0] !== range[0] || lastRange[1] !== range[1];\n    },\n\n    /**\n     * @private\n     */\n    _updateView: function (nonRealtime) {\n        var displaybles = this._displayables;\n        var handleEnds = this._handleEnds;\n        var handleInterval = asc$2(handleEnds.slice());\n        var size = this._size;\n\n        each$23([0, 1], function (handleIndex) {\n            // Handles\n            var handle = displaybles.handles[handleIndex];\n            var handleHeight = this._handleHeight;\n            handle.attr({\n                scale: [handleHeight / 2, handleHeight / 2],\n                position: [handleEnds[handleIndex], size[1] / 2 - handleHeight / 2]\n            });\n        }, this);\n\n        // Filler\n        displaybles.filler.setShape({\n            x: handleInterval[0],\n            y: 0,\n            width: handleInterval[1] - handleInterval[0],\n            height: size[1]\n        });\n\n        this._updateDataInfo(nonRealtime);\n    },\n\n    /**\n     * @private\n     */\n    _updateDataInfo: function (nonRealtime) {\n        var dataZoomModel = this.dataZoomModel;\n        var displaybles = this._displayables;\n        var handleLabels = displaybles.handleLabels;\n        var orient = this._orient;\n        var labelTexts = ['', ''];\n\n        // FIXME\n        // date型，支持formatter，autoformatter（ec2 date.getAutoFormatter）\n        if (dataZoomModel.get('showDetail')) {\n            var axisProxy = dataZoomModel.findRepresentativeAxisProxy();\n\n            if (axisProxy) {\n                var axis = axisProxy.getAxisModel().axis;\n                var range = this._range;\n\n                var dataInterval = nonRealtime\n                    // See #4434, data and axis are not processed and reset yet in non-realtime mode.\n                    ? axisProxy.calculateDataWindow({\n                        start: range[0], end: range[1]\n                    }).valueWindow\n                    : axisProxy.getDataValueWindow();\n\n                labelTexts = [\n                    this._formatLabel(dataInterval[0], axis),\n                    this._formatLabel(dataInterval[1], axis)\n                ];\n            }\n        }\n\n        var orderedHandleEnds = asc$2(this._handleEnds.slice());\n\n        setLabel.call(this, 0);\n        setLabel.call(this, 1);\n\n        function setLabel(handleIndex) {\n            // Label\n            // Text should not transform by barGroup.\n            // Ignore handlers transform\n            var barTransform = getTransform(\n                displaybles.handles[handleIndex].parent, this.group\n            );\n            var direction = transformDirection(\n                handleIndex === 0 ? 'right' : 'left', barTransform\n            );\n            var offset = this._handleWidth / 2 + LABEL_GAP;\n            var textPoint = applyTransform$1(\n                [\n                    orderedHandleEnds[handleIndex] + (handleIndex === 0 ? -offset : offset),\n                    this._size[1] / 2\n                ],\n                barTransform\n            );\n            handleLabels[handleIndex].setStyle({\n                x: textPoint[0],\n                y: textPoint[1],\n                textVerticalAlign: orient === HORIZONTAL ? 'middle' : direction,\n                textAlign: orient === HORIZONTAL ? direction : 'center',\n                text: labelTexts[handleIndex]\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _formatLabel: function (value, axis) {\n        var dataZoomModel = this.dataZoomModel;\n        var labelFormatter = dataZoomModel.get('labelFormatter');\n\n        var labelPrecision = dataZoomModel.get('labelPrecision');\n        if (labelPrecision == null || labelPrecision === 'auto') {\n            labelPrecision = axis.getPixelPrecision();\n        }\n\n        var valueStr = (value == null || isNaN(value))\n            ? ''\n            // FIXME Glue code\n            : (axis.type === 'category' || axis.type === 'time')\n                ? axis.scale.getLabel(Math.round(value))\n                // param of toFixed should less then 20.\n                : value.toFixed(Math.min(labelPrecision, 20));\n\n        return isFunction$1(labelFormatter)\n            ? labelFormatter(value, valueStr)\n            : isString(labelFormatter)\n            ? labelFormatter.replace('{value}', valueStr)\n            : valueStr;\n    },\n\n    /**\n     * @private\n     * @param {boolean} showOrHide true: show, false: hide\n     */\n    _showDataInfo: function (showOrHide) {\n        // Always show when drgging.\n        showOrHide = this._dragging || showOrHide;\n\n        var handleLabels = this._displayables.handleLabels;\n        handleLabels[0].attr('invisible', !showOrHide);\n        handleLabels[1].attr('invisible', !showOrHide);\n    },\n\n    _onDragMove: function (handleIndex, dx, dy) {\n        this._dragging = true;\n\n        // Transform dx, dy to bar coordination.\n        var barTransform = this._displayables.barGroup.getLocalTransform();\n        var vertex = applyTransform$1([dx, dy], barTransform, true);\n\n        var changed = this._updateInterval(handleIndex, vertex[0]);\n\n        var realtime = this.dataZoomModel.get('realtime');\n\n        this._updateView(!realtime);\n\n        // Avoid dispatch dataZoom repeatly but range not changed,\n        // which cause bad visual effect when progressive enabled.\n        changed && realtime && this._dispatchZoomAction();\n    },\n\n    _onDragEnd: function () {\n        this._dragging = false;\n        this._showDataInfo(false);\n\n        // While in realtime mode and stream mode, dispatch action when\n        // drag end will cause the whole view rerender, which is unnecessary.\n        var realtime = this.dataZoomModel.get('realtime');\n        !realtime && this._dispatchZoomAction();\n    },\n\n    _onClickPanelClick: function (e) {\n        var size = this._size;\n        var localPoint = this._displayables.barGroup.transformCoordToLocal(e.offsetX, e.offsetY);\n\n        if (localPoint[0] < 0 || localPoint[0] > size[0]\n            || localPoint[1] < 0 || localPoint[1] > size[1]\n        ) {\n            return;\n        }\n\n        var handleEnds = this._handleEnds;\n        var center = (handleEnds[0] + handleEnds[1]) / 2;\n\n        var changed = this._updateInterval('all', localPoint[0] - center);\n        this._updateView();\n        changed && this._dispatchZoomAction();\n    },\n\n    /**\n     * This action will be throttled.\n     * @private\n     */\n    _dispatchZoomAction: function () {\n        var range = this._range;\n\n        this.api.dispatchAction({\n            type: 'dataZoom',\n            from: this.uid,\n            dataZoomId: this.dataZoomModel.id,\n            start: range[0],\n            end: range[1]\n        });\n    },\n\n    /**\n     * @private\n     */\n    _findCoordRect: function () {\n        // Find the grid coresponding to the first axis referred by dataZoom.\n        var rect;\n        each$23(this.getTargetCoordInfo(), function (coordInfoList) {\n            if (!rect && coordInfoList.length) {\n                var coordSys = coordInfoList[0].model.coordinateSystem;\n                rect = coordSys.getRect && coordSys.getRect();\n            }\n        });\n        if (!rect) {\n            var width = this.api.getWidth();\n            var height = this.api.getHeight();\n            rect = {\n                x: width * 0.2,\n                y: height * 0.2,\n                width: width * 0.6,\n                height: height * 0.6\n            };\n        }\n\n        return rect;\n    }\n\n});\n\nfunction getOtherDim(thisDim) {\n    // FIXME\n    // 这个逻辑和getOtherAxis里一致，但是写在这里是否不好\n    var map$$1 = {x: 'y', y: 'x', radius: 'angle', angle: 'radius'};\n    return map$$1[thisDim];\n}\n\nfunction getCursor(orient) {\n    return orient === 'vertical' ? 'ns-resize' : 'ew-resize';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomModel.extend({\n\n    type: 'dataZoom.inside',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        disabled: false,   // Whether disable this inside zoom.\n        zoomLock: false,   // Whether disable zoom but only pan.\n        zoomOnMouseWheel: true, // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        moveOnMouseMove: true,   // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        moveOnMouseWheel: false, // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        preventDefaultMouseMove: true\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Only create one roam controller for each coordinate system.\n// one roam controller might be refered by two inside data zoom\n// components (for example, one for x and one for y). When user\n// pan or zoom, only dispatch one action for those data zoom\n// components.\n\nvar ATTR$1 = '\\0_ec_dataZoom_roams';\n\n\n/**\n * @public\n * @param {module:echarts/ExtensionAPI} api\n * @param {Object} dataZoomInfo\n * @param {string} dataZoomInfo.coordId\n * @param {Function} dataZoomInfo.containsPoint\n * @param {Array.<string>} dataZoomInfo.allCoordIds\n * @param {string} dataZoomInfo.dataZoomId\n * @param {Object} dataZoomInfo.getRange\n * @param {Function} dataZoomInfo.getRange.pan\n * @param {Function} dataZoomInfo.getRange.zoom\n * @param {Function} dataZoomInfo.getRange.scrollMove\n * @param {boolean} dataZoomInfo.dataZoomModel\n */\nfunction register$2(api, dataZoomInfo) {\n    var store = giveStore(api);\n    var theDataZoomId = dataZoomInfo.dataZoomId;\n    var theCoordId = dataZoomInfo.coordId;\n\n    // Do clean when a dataZoom changes its target coordnate system.\n    // Avoid memory leak, dispose all not-used-registered.\n    each$1(store, function (record, coordId) {\n        var dataZoomInfos = record.dataZoomInfos;\n        if (dataZoomInfos[theDataZoomId]\n            && indexOf(dataZoomInfo.allCoordIds, theCoordId) < 0\n        ) {\n            delete dataZoomInfos[theDataZoomId];\n            record.count--;\n        }\n    });\n\n    cleanStore(store);\n\n    var record = store[theCoordId];\n    // Create if needed.\n    if (!record) {\n        record = store[theCoordId] = {\n            coordId: theCoordId,\n            dataZoomInfos: {},\n            count: 0\n        };\n        record.controller = createController(api, record);\n        record.dispatchAction = curry(dispatchAction$1, api);\n    }\n\n    // Update reference of dataZoom.\n    !(record.dataZoomInfos[theDataZoomId]) && record.count++;\n    record.dataZoomInfos[theDataZoomId] = dataZoomInfo;\n\n    var controllerParams = mergeControllerParams(record.dataZoomInfos);\n    record.controller.enable(controllerParams.controlType, controllerParams.opt);\n\n    // Consider resize, area should be always updated.\n    record.controller.setPointerChecker(dataZoomInfo.containsPoint);\n\n    // Update throttle.\n    createOrUpdate(\n        record,\n        'dispatchAction',\n        dataZoomInfo.dataZoomModel.get('throttle', true),\n        'fixRate'\n    );\n}\n\n/**\n * @public\n * @param {module:echarts/ExtensionAPI} api\n * @param {string} dataZoomId\n */\nfunction unregister$1(api, dataZoomId) {\n    var store = giveStore(api);\n\n    each$1(store, function (record) {\n        record.controller.dispose();\n        var dataZoomInfos = record.dataZoomInfos;\n        if (dataZoomInfos[dataZoomId]) {\n            delete dataZoomInfos[dataZoomId];\n            record.count--;\n        }\n    });\n\n    cleanStore(store);\n}\n\n/**\n * @public\n */\nfunction generateCoordId(coordModel) {\n    return coordModel.type + '\\0_' + coordModel.id;\n}\n\n/**\n * Key: coordId, value: {dataZoomInfos: [], count, controller}\n * @type {Array.<Object>}\n */\nfunction giveStore(api) {\n    // Mount store on zrender instance, so that we do not\n    // need to worry about dispose.\n    var zr = api.getZr();\n    return zr[ATTR$1] || (zr[ATTR$1] = {});\n}\n\nfunction createController(api, newRecord) {\n    var controller = new RoamController(api.getZr());\n\n    each$1(['pan', 'zoom', 'scrollMove'], function (eventName) {\n        controller.on(eventName, function (event) {\n            var batch = [];\n\n            each$1(newRecord.dataZoomInfos, function (info) {\n                // Check whether the behaviors (zoomOnMouseWheel, moveOnMouseMove,\n                // moveOnMouseWheel, ...) enabled.\n                if (!event.isAvailableBehavior(info.dataZoomModel.option)) {\n                    return;\n                }\n\n                var method = (info.getRange || {})[eventName];\n                var range = method && method(newRecord.controller, event);\n\n                !info.dataZoomModel.get('disabled', true) && range && batch.push({\n                    dataZoomId: info.dataZoomId,\n                    start: range[0],\n                    end: range[1]\n                });\n            });\n\n            batch.length && newRecord.dispatchAction(batch);\n        });\n    });\n\n    return controller;\n}\n\nfunction cleanStore(store) {\n    each$1(store, function (record, coordId) {\n        if (!record.count) {\n            record.controller.dispose();\n            delete store[coordId];\n        }\n    });\n}\n\n/**\n * This action will be throttled.\n */\nfunction dispatchAction$1(api, batch) {\n    api.dispatchAction({\n        type: 'dataZoom',\n        batch: batch\n    });\n}\n\n/**\n * Merge roamController settings when multiple dataZooms share one roamController.\n */\nfunction mergeControllerParams(dataZoomInfos) {\n    var controlType;\n    // DO NOT use reserved word (true, false, undefined) as key literally. Even if encapsulated\n    // as string, it is probably revert to reserved word by compress tool. See #7411.\n    var prefix = 'type_';\n    var typePriority = {\n        'type_true': 2,\n        'type_move': 1,\n        'type_false': 0,\n        'type_undefined': -1\n    };\n    var preventDefaultMouseMove = true;\n\n    each$1(dataZoomInfos, function (dataZoomInfo) {\n        var dataZoomModel = dataZoomInfo.dataZoomModel;\n        var oneType = dataZoomModel.get('disabled', true)\n            ? false\n            : dataZoomModel.get('zoomLock', true)\n            ? 'move'\n            : true;\n        if (typePriority[prefix + oneType] > typePriority[prefix + controlType]) {\n            controlType = oneType;\n        }\n\n        // Prevent default move event by default. If one false, do not prevent. Otherwise\n        // users may be confused why it does not work when multiple insideZooms exist.\n        preventDefaultMouseMove &= dataZoomModel.get('preventDefaultMouseMove', true);\n    });\n\n    return {\n        controlType: controlType,\n        opt: {\n            // RoamController will enable all of these functionalities,\n            // and the final behavior is determined by its event listener\n            // provided by each inside zoom.\n            zoomOnMouseWheel: true,\n            moveOnMouseMove: true,\n            moveOnMouseWheel: true,\n            preventDefaultMouseMove: !!preventDefaultMouseMove\n        }\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$5 = bind;\n\nvar InsideZoomView = DataZoomView.extend({\n\n    type: 'dataZoom.inside',\n\n    /**\n     * @override\n     */\n    init: function (ecModel, api) {\n        /**\n         * 'throttle' is used in this.dispatchAction, so we save range\n         * to avoid missing some 'pan' info.\n         * @private\n         * @type {Array.<number>}\n         */\n        this._range;\n    },\n\n    /**\n     * @override\n     */\n    render: function (dataZoomModel, ecModel, api, payload) {\n        InsideZoomView.superApply(this, 'render', arguments);\n\n        // Hance the `throttle` util ensures to preserve command order,\n        // here simply updating range all the time will not cause missing\n        // any of the the roam change.\n        this._range = dataZoomModel.getPercentRange();\n\n        // Reset controllers.\n        each$1(this.getTargetCoordInfo(), function (coordInfoList, coordSysName) {\n\n            var allCoordIds = map(coordInfoList, function (coordInfo) {\n                return generateCoordId(coordInfo.model);\n            });\n\n            each$1(coordInfoList, function (coordInfo) {\n                var coordModel = coordInfo.model;\n\n                var getRange = {};\n                each$1(['pan', 'zoom', 'scrollMove'], function (eventName) {\n                    getRange[eventName] = bind$5(roamHandlers[eventName], this, coordInfo, coordSysName);\n                }, this);\n\n                register$2(\n                    api,\n                    {\n                        coordId: generateCoordId(coordModel),\n                        allCoordIds: allCoordIds,\n                        containsPoint: function (e, x, y) {\n                            return coordModel.coordinateSystem.containPoint([x, y]);\n                        },\n                        dataZoomId: dataZoomModel.id,\n                        dataZoomModel: dataZoomModel,\n                        getRange: getRange\n                    }\n                );\n            }, this);\n\n        }, this);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        unregister$1(this.api, this.dataZoomModel.id);\n        InsideZoomView.superApply(this, 'dispose', arguments);\n        this._range = null;\n    }\n\n});\n\nvar roamHandlers = {\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    zoom: function (coordInfo, coordSysName, controller, e) {\n        var lastRange = this._range;\n        var range = lastRange.slice();\n\n        // Calculate transform by the first axis.\n        var axisModel = coordInfo.axisModels[0];\n        if (!axisModel) {\n            return;\n        }\n\n        var directionInfo = getDirectionInfo[coordSysName](\n            null, [e.originX, e.originY], axisModel, controller, coordInfo\n        );\n        var percentPoint = (\n            directionInfo.signal > 0\n                ? (directionInfo.pixelStart + directionInfo.pixelLength - directionInfo.pixel)\n                : (directionInfo.pixel - directionInfo.pixelStart)\n            ) / directionInfo.pixelLength * (range[1] - range[0]) + range[0];\n\n        var scale = Math.max(1 / e.scale, 0);\n        range[0] = (range[0] - percentPoint) * scale + percentPoint;\n        range[1] = (range[1] - percentPoint) * scale + percentPoint;\n\n        // Restrict range.\n        var minMaxSpan = this.dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan();\n\n        sliderMove(0, range, [0, 100], 0, minMaxSpan.minSpan, minMaxSpan.maxSpan);\n\n        this._range = range;\n\n        if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) {\n            return range;\n        }\n    },\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    pan: makeMover(function (range, axisModel, coordInfo, coordSysName, controller, e) {\n        var directionInfo = getDirectionInfo[coordSysName](\n            [e.oldX, e.oldY], [e.newX, e.newY], axisModel, controller, coordInfo\n        );\n\n        return directionInfo.signal\n            * (range[1] - range[0])\n            * directionInfo.pixel / directionInfo.pixelLength;\n    }),\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    scrollMove: makeMover(function (range, axisModel, coordInfo, coordSysName, controller, e) {\n        var directionInfo = getDirectionInfo[coordSysName](\n            [0, 0], [e.scrollDelta, e.scrollDelta], axisModel, controller, coordInfo\n        );\n        return directionInfo.signal * (range[1] - range[0]) * e.scrollDelta;\n    })\n};\n\nfunction makeMover(getPercentDelta) {\n    return function (coordInfo, coordSysName, controller, e) {\n        var lastRange = this._range;\n        var range = lastRange.slice();\n\n        // Calculate transform by the first axis.\n        var axisModel = coordInfo.axisModels[0];\n        if (!axisModel) {\n            return;\n        }\n\n        var percentDelta = getPercentDelta(\n            range, axisModel, coordInfo, coordSysName, controller, e\n        );\n\n        sliderMove(percentDelta, range, [0, 100], 'all');\n\n        this._range = range;\n\n        if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) {\n            return range;\n        }\n    };\n}\n\nvar getDirectionInfo = {\n\n    grid: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var ret = {};\n        var rect = coordInfo.model.coordinateSystem.getRect();\n        oldPoint = oldPoint || [0, 0];\n\n        if (axis.dim === 'x') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            ret.pixelLength = rect.width;\n            ret.pixelStart = rect.x;\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // axis.dim === 'y'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            ret.pixelLength = rect.height;\n            ret.pixelStart = rect.y;\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    },\n\n    polar: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var ret = {};\n        var polar = coordInfo.model.coordinateSystem;\n        var radiusExtent = polar.getRadiusAxis().getExtent();\n        var angleExtent = polar.getAngleAxis().getExtent();\n\n        oldPoint = oldPoint ? polar.pointToCoord(oldPoint) : [0, 0];\n        newPoint = polar.pointToCoord(newPoint);\n\n        if (axisModel.mainType === 'radiusAxis') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            // ret.pixelLength = Math.abs(radiusExtent[1] - radiusExtent[0]);\n            // ret.pixelStart = Math.min(radiusExtent[0], radiusExtent[1]);\n            ret.pixelLength = radiusExtent[1] - radiusExtent[0];\n            ret.pixelStart = radiusExtent[0];\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // 'angleAxis'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            // ret.pixelLength = Math.abs(angleExtent[1] - angleExtent[0]);\n            // ret.pixelStart = Math.min(angleExtent[0], angleExtent[1]);\n            ret.pixelLength = angleExtent[1] - angleExtent[0];\n            ret.pixelStart = angleExtent[0];\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    },\n\n    singleAxis: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var rect = coordInfo.model.coordinateSystem.getRect();\n        var ret = {};\n\n        oldPoint = oldPoint || [0, 0];\n\n        if (axis.orient === 'horizontal') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            ret.pixelLength = rect.width;\n            ret.pixelStart = rect.x;\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // 'vertical'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            ret.pixelLength = rect.height;\n            ret.pixelStart = rect.y;\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterProcessor({\n\n    // `dataZoomProcessor` will only be performed in needed series. Consider if\n    // there is a line series and a pie series, it is better not to update the\n    // line series if only pie series is needed to be updated.\n    getTargetSeries: function (ecModel) {\n        var seriesModelMap = createHashMap();\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                var axisProxy = dataZoomModel.getAxisProxy(dimNames.name, axisIndex);\n                each$1(axisProxy.getTargetSeriesModels(), function (seriesModel) {\n                    seriesModelMap.set(seriesModel.uid, seriesModel);\n                });\n            });\n        });\n\n        return seriesModelMap;\n    },\n\n    modifyOutputEnd: true,\n\n    // Consider appendData, where filter should be performed. Because data process is\n    // in block mode currently, it is not need to worry about that the overallProgress\n    // execute every frame.\n    overallReset: function (ecModel, api) {\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            // We calculate window and reset axis here but not in model\n            // init stage and not after action dispatch handler, because\n            // reset should be called after seriesData.restoreData.\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                dataZoomModel.getAxisProxy(dimNames.name, axisIndex).reset(dataZoomModel, api);\n            });\n\n            // Caution: data zoom filtering is order sensitive when using\n            // percent range and no min/max/scale set on axis.\n            // For example, we have dataZoom definition:\n            // [\n            //      {xAxisIndex: 0, start: 30, end: 70},\n            //      {yAxisIndex: 0, start: 20, end: 80}\n            // ]\n            // In this case, [20, 80] of y-dataZoom should be based on data\n            // that have filtered by x-dataZoom using range of [30, 70],\n            // but should not be based on full raw data. Thus sliding\n            // x-dataZoom will change both ranges of xAxis and yAxis,\n            // while sliding y-dataZoom will only change the range of yAxis.\n            // So we should filter x-axis after reset x-axis immediately,\n            // and then reset y-axis and filter y-axis.\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                dataZoomModel.getAxisProxy(dimNames.name, axisIndex).filterData(dataZoomModel, api);\n            });\n        });\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            // Fullfill all of the range props so that user\n            // is able to get them from chart.getOption().\n            var axisProxy = dataZoomModel.findRepresentativeAxisProxy();\n            var percentRange = axisProxy.getDataPercentWindow();\n            var valueRange = axisProxy.getDataValueWindow();\n\n            dataZoomModel.setRawRange({\n                start: percentRange[0],\n                end: percentRange[1],\n                startValue: valueRange[0],\n                endValue: valueRange[1]\n            }, true);\n        });\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterAction('dataZoom', function (payload, ecModel) {\n\n    var linkedNodesFinder = createLinkedNodesFinder(\n        bind(ecModel.eachComponent, ecModel, 'dataZoom'),\n        eachAxisDim$1,\n        function (model, dimNames) {\n            return model.get(dimNames.axisIndex);\n        }\n    );\n\n    var effectedModels = [];\n\n    ecModel.eachComponent(\n        {mainType: 'dataZoom', query: payload},\n        function (model, index) {\n            effectedModels.push.apply(\n                effectedModels, linkedNodesFinder(model).nodes\n            );\n        }\n    );\n\n    each$1(effectedModels, function (dataZoomModel, index) {\n        dataZoomModel.setRawRange({\n            start: payload.start,\n            end: payload.end,\n            startValue: payload.startValue,\n            endValue: payload.endValue\n        });\n    });\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$24 = each$1;\n\nvar preprocessor$2 = function (option) {\n    var visualMap = option && option.visualMap;\n\n    if (!isArray(visualMap)) {\n        visualMap = visualMap ? [visualMap] : [];\n    }\n\n    each$24(visualMap, function (opt) {\n        if (!opt) {\n            return;\n        }\n\n        // rename splitList to pieces\n        if (has$1(opt, 'splitList') && !has$1(opt, 'pieces')) {\n            opt.pieces = opt.splitList;\n            delete opt.splitList;\n        }\n\n        var pieces = opt.pieces;\n        if (pieces && isArray(pieces)) {\n            each$24(pieces, function (piece) {\n                if (isObject$1(piece)) {\n                    if (has$1(piece, 'start') && !has$1(piece, 'min')) {\n                        piece.min = piece.start;\n                    }\n                    if (has$1(piece, 'end') && !has$1(piece, 'max')) {\n                        piece.max = piece.end;\n                    }\n                }\n            });\n        }\n    });\n};\n\nfunction has$1(obj, name) {\n    return obj && obj.hasOwnProperty && obj.hasOwnProperty(name);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nComponentModel.registerSubTypeDefaulter('visualMap', function (option) {\n    // Compatible with ec2, when splitNumber === 0, continuous visualMap will be used.\n    return (\n            !option.categories\n            && (\n                !(\n                    option.pieces\n                        ? option.pieces.length > 0\n                        : option.splitNumber > 0\n                )\n                || option.calculable\n            )\n        )\n        ? 'continuous' : 'piecewise';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar VISUAL_PRIORITY = PRIORITY.VISUAL.COMPONENT;\n\nregisterVisual(VISUAL_PRIORITY, {\n    createOnAllSeries: true,\n    reset: function (seriesModel, ecModel) {\n        var resetDefines = [];\n        ecModel.eachComponent('visualMap', function (visualMapModel) {\n            var pipelineContext = seriesModel.pipelineContext;\n            if (!visualMapModel.isTargetSeries(seriesModel)\n                || (pipelineContext && pipelineContext.large)\n            ) {\n                return;\n            }\n\n            resetDefines.push(incrementalApplyVisual(\n                visualMapModel.stateList,\n                visualMapModel.targetVisuals,\n                bind(visualMapModel.getValueState, visualMapModel),\n                visualMapModel.getDataDimension(seriesModel.getData())\n            ));\n        });\n\n        return resetDefines;\n    }\n});\n\n// Only support color.\nregisterVisual(VISUAL_PRIORITY, {\n    createOnAllSeries: true,\n    reset: function (seriesModel, ecModel) {\n        var data = seriesModel.getData();\n        var visualMetaList = [];\n\n        ecModel.eachComponent('visualMap', function (visualMapModel) {\n            if (visualMapModel.isTargetSeries(seriesModel)) {\n                var visualMeta = visualMapModel.getVisualMeta(\n                    bind(getColorVisual, null, seriesModel, visualMapModel)\n                ) || {stops: [], outerColors: []};\n\n                var concreteDim = visualMapModel.getDataDimension(data);\n                var dimInfo = data.getDimensionInfo(concreteDim);\n                if (dimInfo != null) {\n                    // visualMeta.dimension should be dimension index, but not concrete dimension.\n                    visualMeta.dimension = dimInfo.index;\n                    visualMetaList.push(visualMeta);\n                }\n            }\n        });\n\n        // console.log(JSON.stringify(visualMetaList.map(a => a.stops)));\n        seriesModel.getData().setVisual('visualMeta', visualMetaList);\n    }\n});\n\n// FIXME\n// performance and export for heatmap?\n// value can be Infinity or -Infinity\nfunction getColorVisual(seriesModel, visualMapModel, value, valueState) {\n    var mappings = visualMapModel.targetVisuals[valueState];\n    var visualTypes = VisualMapping.prepareVisualTypes(mappings);\n    var resultVisual = {\n        color: seriesModel.getData().getVisual('color') // default color.\n    };\n\n    for (var i = 0, len = visualTypes.length; i < len; i++) {\n        var type = visualTypes[i];\n        var mapping = mappings[\n            type === 'opacity' ? '__alphaForOpacity' : type\n        ];\n        mapping && mapping.applyVisual(value, getVisual, setVisual);\n    }\n\n    return resultVisual.color;\n\n    function getVisual(key) {\n        return resultVisual[key];\n    }\n\n    function setVisual(key, value) {\n        resultVisual[key] = value;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Visual mapping.\n */\n\nvar visualDefault = {\n\n    /**\n     * @public\n     */\n    get: function (visualType, key, isCategory) {\n        var value = clone(\n            (defaultOption$3[visualType] || {})[key]\n        );\n\n        return isCategory\n            ? (isArray(value) ? value[value.length - 1] : value)\n            : value;\n    }\n\n};\n\nvar defaultOption$3 = {\n\n    color: {\n        active: ['#006edd', '#e0ffff'],\n        inactive: ['rgba(0,0,0,0)']\n    },\n\n    colorHue: {\n        active: [0, 360],\n        inactive: [0, 0]\n    },\n\n    colorSaturation: {\n        active: [0.3, 1],\n        inactive: [0, 0]\n    },\n\n    colorLightness: {\n        active: [0.9, 0.5],\n        inactive: [0, 0]\n    },\n\n    colorAlpha: {\n        active: [0.3, 1],\n        inactive: [0, 0]\n    },\n\n    opacity: {\n        active: [0.3, 1],\n        inactive: [0, 0]\n    },\n\n    symbol: {\n        active: ['circle', 'roundRect', 'diamond'],\n        inactive: ['none']\n    },\n\n    symbolSize: {\n        active: [10, 50],\n        inactive: [0, 0]\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar mapVisual$2 = VisualMapping.mapVisual;\nvar eachVisual = VisualMapping.eachVisual;\nvar isArray$3 = isArray;\nvar each$25 = each$1;\nvar asc$3 = asc;\nvar linearMap$2 = linearMap;\nvar noop$2 = noop;\n\nvar VisualMapModel = extendComponentModel({\n\n    type: 'visualMap',\n\n    dependencies: ['series'],\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    stateList: ['inRange', 'outOfRange'],\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    replacableOptionKeys: [\n        'inRange', 'outOfRange', 'target', 'controller', 'color'\n    ],\n\n    /**\n     * [lowerBound, upperBound]\n     *\n     * @readOnly\n     * @type {Array.<number>}\n     */\n    dataBound: [-Infinity, Infinity],\n\n    /**\n     * @readOnly\n     * @type {string|Object}\n     */\n    layoutMode: {type: 'box', ignoreSize: true},\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        show: true,\n\n        zlevel: 0,\n        z: 4,\n\n        seriesIndex: 'all',     // 'all' or null/undefined: all series.\n                                // A number or an array of number: the specified series.\n\n                                // set min: 0, max: 200, only for campatible with ec2.\n                                // In fact min max should not have default value.\n        min: 0,                 // min value, must specified if pieces is not specified.\n        max: 200,               // max value, must specified if pieces is not specified.\n\n        dimension: null,\n        inRange: null,          // 'color', 'colorHue', 'colorSaturation', 'colorLightness', 'colorAlpha',\n                                // 'symbol', 'symbolSize'\n        outOfRange: null,       // 'color', 'colorHue', 'colorSaturation',\n                                // 'colorLightness', 'colorAlpha',\n                                // 'symbol', 'symbolSize'\n\n        left: 0,                // 'center' ¦ 'left' ¦ 'right' ¦ {number} (px)\n        right: null,            // The same as left.\n        top: null,              // 'top' ¦ 'bottom' ¦ 'center' ¦ {number} (px)\n        bottom: 0,              // The same as top.\n\n        itemWidth: null,\n        itemHeight: null,\n        inverse: false,\n        orient: 'vertical',        // 'horizontal' ¦ 'vertical'\n\n        backgroundColor: 'rgba(0,0,0,0)',\n        borderColor: '#ccc',       // 值域边框颜色\n        contentColor: '#5793f3',\n        inactiveColor: '#aaa',\n        borderWidth: 0,            // 值域边框线宽，单位px，默认为0（无边框）\n        padding: 5,                // 值域内边距，单位px，默认各方向内边距为5，\n                                    // 接受数组分别设定上右下左边距，同css\n        textGap: 10,               //\n        precision: 0,              // 小数精度，默认为0，无小数点\n        color: null,               //颜色（deprecated，兼容ec2，顺序同pieces，不同于inRange/outOfRange）\n\n        formatter: null,\n        text: null,                // 文本，如['高', '低']，兼容ec2，text[0]对应高值，text[1]对应低值\n        textStyle: {\n            color: '#333'          // 值域文字颜色\n        }\n    },\n\n    /**\n     * @protected\n     */\n    init: function (option, parentModel, ecModel) {\n\n        /**\n         * @private\n         * @type {Array.<number>}\n         */\n        this._dataExtent;\n\n        /**\n         * @readOnly\n         */\n        this.targetVisuals = {};\n\n        /**\n         * @readOnly\n         */\n        this.controllerVisuals = {};\n\n        /**\n         * @readOnly\n         */\n        this.textStyleModel;\n\n        /**\n         * [width, height]\n         * @readOnly\n         * @type {Array.<number>}\n         */\n        this.itemSize;\n\n        this.mergeDefaultAndTheme(option, ecModel);\n    },\n\n    /**\n     * @protected\n     */\n    optionUpdated: function (newOption, isInit) {\n        var thisOption = this.option;\n\n        // FIXME\n        // necessary?\n        // Disable realtime view update if canvas is not supported.\n        if (!env$1.canvasSupported) {\n            thisOption.realtime = false;\n        }\n\n        !isInit && replaceVisualOption(\n            thisOption, newOption, this.replacableOptionKeys\n        );\n\n        this.textStyleModel = this.getModel('textStyle');\n\n        this.resetItemSize();\n\n        this.completeVisualOption();\n    },\n\n    /**\n     * @protected\n     */\n    resetVisual: function (supplementVisualOption) {\n        var stateList = this.stateList;\n        supplementVisualOption = bind(supplementVisualOption, this);\n\n        this.controllerVisuals = createVisualMappings(\n            this.option.controller, stateList, supplementVisualOption\n        );\n        this.targetVisuals = createVisualMappings(\n            this.option.target, stateList, supplementVisualOption\n        );\n    },\n\n    /**\n     * @protected\n     * @return {Array.<number>} An array of series indices.\n     */\n    getTargetSeriesIndices: function () {\n        var optionSeriesIndex = this.option.seriesIndex;\n        var seriesIndices = [];\n\n        if (optionSeriesIndex == null || optionSeriesIndex === 'all') {\n            this.ecModel.eachSeries(function (seriesModel, index) {\n                seriesIndices.push(index);\n            });\n        }\n        else {\n            seriesIndices = normalizeToArray(optionSeriesIndex);\n        }\n\n        return seriesIndices;\n    },\n\n    /**\n     * @public\n     */\n    eachTargetSeries: function (callback, context) {\n        each$1(this.getTargetSeriesIndices(), function (seriesIndex) {\n            callback.call(context, this.ecModel.getSeriesByIndex(seriesIndex));\n        }, this);\n    },\n\n    /**\n     * @pubilc\n     */\n    isTargetSeries: function (seriesModel) {\n        var is = false;\n        this.eachTargetSeries(function (model) {\n            model === seriesModel && (is = true);\n        });\n        return is;\n    },\n\n    /**\n     * @example\n     * this.formatValueText(someVal); // format single numeric value to text.\n     * this.formatValueText(someVal, true); // format single category value to text.\n     * this.formatValueText([min, max]); // format numeric min-max to text.\n     * this.formatValueText([this.dataBound[0], max]); // using data lower bound.\n     * this.formatValueText([min, this.dataBound[1]]); // using data upper bound.\n     *\n     * @param {number|Array.<number>} value Real value, or this.dataBound[0 or 1].\n     * @param {boolean} [isCategory=false] Only available when value is number.\n     * @param {Array.<string>} edgeSymbols Open-close symbol when value is interval.\n     * @return {string}\n     * @protected\n     */\n    formatValueText: function (value, isCategory, edgeSymbols) {\n        var option = this.option;\n        var precision = option.precision;\n        var dataBound = this.dataBound;\n        var formatter = option.formatter;\n        var isMinMax;\n        var textValue;\n        edgeSymbols = edgeSymbols || ['<', '>'];\n\n        if (isArray(value)) {\n            value = value.slice();\n            isMinMax = true;\n        }\n\n        textValue = isCategory\n            ? value\n            : (isMinMax\n                ? [toFixed(value[0]), toFixed(value[1])]\n                : toFixed(value)\n            );\n\n        if (isString(formatter)) {\n            return formatter\n                .replace('{value}', isMinMax ? textValue[0] : textValue)\n                .replace('{value2}', isMinMax ? textValue[1] : textValue);\n        }\n        else if (isFunction$1(formatter)) {\n            return isMinMax\n                ? formatter(value[0], value[1])\n                : formatter(value);\n        }\n\n        if (isMinMax) {\n            if (value[0] === dataBound[0]) {\n                return edgeSymbols[0] + ' ' + textValue[1];\n            }\n            else if (value[1] === dataBound[1]) {\n                return edgeSymbols[1] + ' ' + textValue[0];\n            }\n            else {\n                return textValue[0] + ' - ' + textValue[1];\n            }\n        }\n        else { // Format single value (includes category case).\n            return textValue;\n        }\n\n        function toFixed(val) {\n            return val === dataBound[0]\n                ? 'min'\n                : val === dataBound[1]\n                ? 'max'\n                : (+val).toFixed(Math.min(precision, 20));\n        }\n    },\n\n    /**\n     * @protected\n     */\n    resetExtent: function () {\n        var thisOption = this.option;\n\n        // Can not calculate data extent by data here.\n        // Because series and data may be modified in processing stage.\n        // So we do not support the feature \"auto min/max\".\n\n        var extent = asc$3([thisOption.min, thisOption.max]);\n\n        this._dataExtent = extent;\n    },\n\n    /**\n     * @public\n     * @param {module:echarts/data/List} list\n     * @return {string} Concrete dimention. If return null/undefined,\n     *                  no dimension used.\n     */\n    getDataDimension: function (list) {\n        var optDim = this.option.dimension;\n        var listDimensions = list.dimensions;\n        if (optDim == null && !listDimensions.length) {\n            return;\n        }\n\n        if (optDim != null) {\n            return list.getDimension(optDim);\n        }\n\n        var dimNames = list.dimensions;\n        for (var i = dimNames.length - 1; i >= 0; i--) {\n            var dimName = dimNames[i];\n            var dimInfo = list.getDimensionInfo(dimName);\n            if (!dimInfo.isCalculationCoord) {\n                return dimName;\n            }\n        }\n    },\n\n    /**\n     * @public\n     * @override\n     */\n    getExtent: function () {\n        return this._dataExtent.slice();\n    },\n\n    /**\n     * @protected\n     */\n    completeVisualOption: function () {\n        var ecModel = this.ecModel;\n        var thisOption = this.option;\n        var base = {inRange: thisOption.inRange, outOfRange: thisOption.outOfRange};\n\n        var target = thisOption.target || (thisOption.target = {});\n        var controller = thisOption.controller || (thisOption.controller = {});\n\n        merge(target, base); // Do not override\n        merge(controller, base); // Do not override\n\n        var isCategory = this.isCategory();\n\n        completeSingle.call(this, target);\n        completeSingle.call(this, controller);\n        completeInactive.call(this, target, 'inRange', 'outOfRange');\n        // completeInactive.call(this, target, 'outOfRange', 'inRange');\n        completeController.call(this, controller);\n\n        function completeSingle(base) {\n            // Compatible with ec2 dataRange.color.\n            // The mapping order of dataRange.color is: [high value, ..., low value]\n            // whereas inRange.color and outOfRange.color is [low value, ..., high value]\n            // Notice: ec2 has no inverse.\n            if (isArray$3(thisOption.color)\n                // If there has been inRange: {symbol: ...}, adding color is a mistake.\n                // So adding color only when no inRange defined.\n                && !base.inRange\n            ) {\n                base.inRange = {color: thisOption.color.slice().reverse()};\n            }\n\n            // Compatible with previous logic, always give a defautl color, otherwise\n            // simple config with no inRange and outOfRange will not work.\n            // Originally we use visualMap.color as the default color, but setOption at\n            // the second time the default color will be erased. So we change to use\n            // constant DEFAULT_COLOR.\n            // If user do not want the defualt color, set inRange: {color: null}.\n            base.inRange = base.inRange || {color: ecModel.get('gradientColor')};\n\n            // If using shortcut like: {inRange: 'symbol'}, complete default value.\n            each$25(this.stateList, function (state) {\n                var visualType = base[state];\n\n                if (isString(visualType)) {\n                    var defa = visualDefault.get(visualType, 'active', isCategory);\n                    if (defa) {\n                        base[state] = {};\n                        base[state][visualType] = defa;\n                    }\n                    else {\n                        // Mark as not specified.\n                        delete base[state];\n                    }\n                }\n            }, this);\n        }\n\n        function completeInactive(base, stateExist, stateAbsent) {\n            var optExist = base[stateExist];\n            var optAbsent = base[stateAbsent];\n\n            if (optExist && !optAbsent) {\n                optAbsent = base[stateAbsent] = {};\n                each$25(optExist, function (visualData, visualType) {\n                    if (!VisualMapping.isValidType(visualType)) {\n                        return;\n                    }\n\n                    var defa = visualDefault.get(visualType, 'inactive', isCategory);\n\n                    if (defa != null) {\n                        optAbsent[visualType] = defa;\n\n                        // Compatibable with ec2:\n                        // Only inactive color to rgba(0,0,0,0) can not\n                        // make label transparent, so use opacity also.\n                        if (visualType === 'color'\n                            && !optAbsent.hasOwnProperty('opacity')\n                            && !optAbsent.hasOwnProperty('colorAlpha')\n                        ) {\n                            optAbsent.opacity = [0, 0];\n                        }\n                    }\n                });\n            }\n        }\n\n        function completeController(controller) {\n            var symbolExists = (controller.inRange || {}).symbol\n                || (controller.outOfRange || {}).symbol;\n            var symbolSizeExists = (controller.inRange || {}).symbolSize\n                || (controller.outOfRange || {}).symbolSize;\n            var inactiveColor = this.get('inactiveColor');\n\n            each$25(this.stateList, function (state) {\n\n                var itemSize = this.itemSize;\n                var visuals = controller[state];\n\n                // Set inactive color for controller if no other color\n                // attr (like colorAlpha) specified.\n                if (!visuals) {\n                    visuals = controller[state] = {\n                        color: isCategory ? inactiveColor : [inactiveColor]\n                    };\n                }\n\n                // Consistent symbol and symbolSize if not specified.\n                if (visuals.symbol == null) {\n                    visuals.symbol = symbolExists\n                        && clone(symbolExists)\n                        || (isCategory ? 'roundRect' : ['roundRect']);\n                }\n                if (visuals.symbolSize == null) {\n                    visuals.symbolSize = symbolSizeExists\n                        && clone(symbolSizeExists)\n                        || (isCategory ? itemSize[0] : [itemSize[0], itemSize[0]]);\n                }\n\n                // Filter square and none.\n                visuals.symbol = mapVisual$2(visuals.symbol, function (symbol) {\n                    return (symbol === 'none' || symbol === 'square') ? 'roundRect' : symbol;\n                });\n\n                // Normalize symbolSize\n                var symbolSize = visuals.symbolSize;\n\n                if (symbolSize != null) {\n                    var max = -Infinity;\n                    // symbolSize can be object when categories defined.\n                    eachVisual(symbolSize, function (value) {\n                        value > max && (max = value);\n                    });\n                    visuals.symbolSize = mapVisual$2(symbolSize, function (value) {\n                        return linearMap$2(value, [0, max], [0, itemSize[0]], true);\n                    });\n                }\n\n            }, this);\n        }\n    },\n\n    /**\n     * @protected\n     */\n    resetItemSize: function () {\n        this.itemSize = [\n            parseFloat(this.get('itemWidth')),\n            parseFloat(this.get('itemHeight'))\n        ];\n    },\n\n    /**\n     * @public\n     */\n    isCategory: function () {\n        return !!this.option.categories;\n    },\n\n    /**\n     * @public\n     * @abstract\n     */\n    setSelected: noop$2,\n\n    /**\n     * @public\n     * @abstract\n     * @param {*|module:echarts/data/List} valueOrData\n     * @param {number} dataIndex\n     * @return {string} state See this.stateList\n     */\n    getValueState: noop$2,\n\n    /**\n     * FIXME\n     * Do not publish to thirt-part-dev temporarily\n     * util the interface is stable. (Should it return\n     * a function but not visual meta?)\n     *\n     * @pubilc\n     * @abstract\n     * @param {Function} getColorVisual\n     *        params: value, valueState\n     *        return: color\n     * @return {Object} visualMeta\n     *        should includes {stops, outerColors}\n     *        outerColor means [colorBeyondMinValue, colorBeyondMaxValue]\n     */\n    getVisualMeta: noop$2\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Constant\nvar DEFAULT_BAR_BOUND = [20, 140];\n\nvar ContinuousModel = VisualMapModel.extend({\n\n    type: 'visualMap.continuous',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        align: 'auto',           // 'auto', 'left', 'right', 'top', 'bottom'\n        calculable: false,       // This prop effect default component type determine,\n                                 // See echarts/component/visualMap/typeDefaulter.\n        range: null,             // selected range. In default case `range` is [min, max]\n                                 // and can auto change along with modification of min max,\n                                 // util use specifid a range.\n        realtime: true,          // Whether realtime update.\n        itemHeight: null,        // The length of the range control edge.\n        itemWidth: null,         // The length of the other side.\n        hoverLink: true,         // Enable hover highlight.\n        hoverLinkDataSize: null, // The size of hovered data.\n        hoverLinkOnHandle: null  // Whether trigger hoverLink when hover handle.\n                                 // If not specified, follow the value of `realtime`.\n    },\n\n    /**\n     * @override\n     */\n    optionUpdated: function (newOption, isInit) {\n        ContinuousModel.superApply(this, 'optionUpdated', arguments);\n\n        this.resetExtent();\n\n        this.resetVisual(function (mappingOption) {\n            mappingOption.mappingMethod = 'linear';\n            mappingOption.dataExtent = this.getExtent();\n        });\n\n        this._resetRange();\n    },\n\n    /**\n     * @protected\n     * @override\n     */\n    resetItemSize: function () {\n        ContinuousModel.superApply(this, 'resetItemSize', arguments);\n\n        var itemSize = this.itemSize;\n\n        this._orient === 'horizontal' && itemSize.reverse();\n\n        (itemSize[0] == null || isNaN(itemSize[0])) && (itemSize[0] = DEFAULT_BAR_BOUND[0]);\n        (itemSize[1] == null || isNaN(itemSize[1])) && (itemSize[1] = DEFAULT_BAR_BOUND[1]);\n    },\n\n    /**\n     * @private\n     */\n    _resetRange: function () {\n        var dataExtent = this.getExtent();\n        var range = this.option.range;\n\n        if (!range || range.auto) {\n            // `range` should always be array (so we dont use other\n            // value like 'auto') for user-friend. (consider getOption).\n            dataExtent.auto = 1;\n            this.option.range = dataExtent;\n        }\n        else if (isArray(range)) {\n            if (range[0] > range[1]) {\n                range.reverse();\n            }\n            range[0] = Math.max(range[0], dataExtent[0]);\n            range[1] = Math.min(range[1], dataExtent[1]);\n        }\n    },\n\n    /**\n     * @protected\n     * @override\n     */\n    completeVisualOption: function () {\n        VisualMapModel.prototype.completeVisualOption.apply(this, arguments);\n\n        each$1(this.stateList, function (state) {\n            var symbolSize = this.option.controller[state].symbolSize;\n            if (symbolSize && symbolSize[0] !== symbolSize[1]) {\n                symbolSize[0] = 0; // For good looking.\n            }\n        }, this);\n    },\n\n    /**\n     * @override\n     */\n    setSelected: function (selected) {\n        this.option.range = selected.slice();\n        this._resetRange();\n    },\n\n    /**\n     * @public\n     */\n    getSelected: function () {\n        var dataExtent = this.getExtent();\n\n        var dataInterval = asc(\n            (this.get('range') || []).slice()\n        );\n\n        // Clamp\n        dataInterval[0] > dataExtent[1] && (dataInterval[0] = dataExtent[1]);\n        dataInterval[1] > dataExtent[1] && (dataInterval[1] = dataExtent[1]);\n        dataInterval[0] < dataExtent[0] && (dataInterval[0] = dataExtent[0]);\n        dataInterval[1] < dataExtent[0] && (dataInterval[1] = dataExtent[0]);\n\n        return dataInterval;\n    },\n\n    /**\n     * @override\n     */\n    getValueState: function (value) {\n        var range = this.option.range;\n        var dataExtent = this.getExtent();\n\n        // When range[0] === dataExtent[0], any value larger than dataExtent[0] maps to 'inRange'.\n        // range[1] is processed likewise.\n        return (\n            (range[0] <= dataExtent[0] || range[0] <= value)\n            && (range[1] >= dataExtent[1] || value <= range[1])\n        ) ? 'inRange' : 'outOfRange';\n    },\n\n    /**\n     * @params {Array.<number>} range target value: range[0] <= value && value <= range[1]\n     * @return {Array.<Object>} [{seriesId, dataIndices: <Array.<number>>}, ...]\n     */\n    findTargetDataIndices: function (range) {\n        var result = [];\n\n        this.eachTargetSeries(function (seriesModel) {\n            var dataIndices = [];\n            var data = seriesModel.getData();\n\n            data.each(this.getDataDimension(data), function (value, dataIndex) {\n                range[0] <= value && value <= range[1] && dataIndices.push(dataIndex);\n            }, this);\n\n            result.push({seriesId: seriesModel.id, dataIndex: dataIndices});\n        }, this);\n\n        return result;\n    },\n\n    /**\n     * @implement\n     */\n    getVisualMeta: function (getColorVisual) {\n        var oVals = getColorStopValues(this, 'outOfRange', this.getExtent());\n        var iVals = getColorStopValues(this, 'inRange', this.option.range.slice());\n        var stops = [];\n\n        function setStop(value, valueState) {\n            stops.push({\n                value: value,\n                color: getColorVisual(value, valueState)\n            });\n        }\n\n        // Format to: outOfRange -- inRange -- outOfRange.\n        var iIdx = 0;\n        var oIdx = 0;\n        var iLen = iVals.length;\n        var oLen = oVals.length;\n\n        for (; oIdx < oLen && (!iVals.length || oVals[oIdx] <= iVals[0]); oIdx++) {\n            // If oVal[oIdx] === iVals[iIdx], oVal[oIdx] should be ignored.\n            if (oVals[oIdx] < iVals[iIdx]) {\n                setStop(oVals[oIdx], 'outOfRange');\n            }\n        }\n        for (var first = 1; iIdx < iLen; iIdx++, first = 0) {\n            // If range is full, value beyond min, max will be clamped.\n            // make a singularity\n            first && stops.length && setStop(iVals[iIdx], 'outOfRange');\n            setStop(iVals[iIdx], 'inRange');\n        }\n        for (var first = 1; oIdx < oLen; oIdx++) {\n            if (!iVals.length || iVals[iVals.length - 1] < oVals[oIdx]) {\n                // make a singularity\n                if (first) {\n                    stops.length && setStop(stops[stops.length - 1].value, 'outOfRange');\n                    first = 0;\n                }\n                setStop(oVals[oIdx], 'outOfRange');\n            }\n        }\n\n        var stopsLen = stops.length;\n\n        return {\n            stops: stops,\n            outerColors: [\n                stopsLen ? stops[0].color : 'transparent',\n                stopsLen ? stops[stopsLen - 1].color : 'transparent'\n            ]\n        };\n    }\n\n});\n\nfunction getColorStopValues(visualMapModel, valueState, dataExtent) {\n    if (dataExtent[0] === dataExtent[1]) {\n        return dataExtent.slice();\n    }\n\n    // When using colorHue mapping, it is not linear color any more.\n    // Moreover, canvas gradient seems not to be accurate linear.\n    // FIXME\n    // Should be arbitrary value 100? or based on pixel size?\n    var count = 200;\n    var step = (dataExtent[1] - dataExtent[0]) / count;\n\n    var value = dataExtent[0];\n    var stopValues = [];\n    for (var i = 0; i <= count && value < dataExtent[1]; i++) {\n        stopValues.push(value);\n        value += step;\n    }\n    stopValues.push(dataExtent[1]);\n\n    return stopValues;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar VisualMapView = extendComponentView({\n\n    type: 'visualMap',\n\n    /**\n     * @readOnly\n     * @type {Object}\n     */\n    autoPositionValues: {left: 1, right: 1, top: 1, bottom: 1},\n\n    init: function (ecModel, api) {\n        /**\n         * @readOnly\n         * @type {module:echarts/model/Global}\n         */\n        this.ecModel = ecModel;\n\n        /**\n         * @readOnly\n         * @type {module:echarts/ExtensionAPI}\n         */\n        this.api = api;\n\n        /**\n         * @readOnly\n         * @type {module:echarts/component/visualMap/visualMapModel}\n         */\n        this.visualMapModel;\n    },\n\n    /**\n     * @protected\n     */\n    render: function (visualMapModel, ecModel, api, payload) {\n        this.visualMapModel = visualMapModel;\n\n        if (visualMapModel.get('show') === false) {\n            this.group.removeAll();\n            return;\n        }\n\n        this.doRender.apply(this, arguments);\n    },\n\n    /**\n     * @protected\n     */\n    renderBackground: function (group) {\n        var visualMapModel = this.visualMapModel;\n        var padding = normalizeCssArray$1(visualMapModel.get('padding') || 0);\n        var rect = group.getBoundingRect();\n\n        group.add(new Rect({\n            z2: -1, // Lay background rect on the lowest layer.\n            silent: true,\n            shape: {\n                x: rect.x - padding[3],\n                y: rect.y - padding[0],\n                width: rect.width + padding[3] + padding[1],\n                height: rect.height + padding[0] + padding[2]\n            },\n            style: {\n                fill: visualMapModel.get('backgroundColor'),\n                stroke: visualMapModel.get('borderColor'),\n                lineWidth: visualMapModel.get('borderWidth')\n            }\n        }));\n    },\n\n    /**\n     * @protected\n     * @param {number} targetValue can be Infinity or -Infinity\n     * @param {string=} visualCluster Only can be 'color' 'opacity' 'symbol' 'symbolSize'\n     * @param {Object} [opts]\n     * @param {string=} [opts.forceState] Specify state, instead of using getValueState method.\n     * @param {string=} [opts.convertOpacityToAlpha=false] For color gradient in controller widget.\n     * @return {*} Visual value.\n     */\n    getControllerVisual: function (targetValue, visualCluster, opts) {\n        opts = opts || {};\n\n        var forceState = opts.forceState;\n        var visualMapModel = this.visualMapModel;\n        var visualObj = {};\n\n        // Default values.\n        if (visualCluster === 'symbol') {\n            visualObj.symbol = visualMapModel.get('itemSymbol');\n        }\n        if (visualCluster === 'color') {\n            var defaultColor = visualMapModel.get('contentColor');\n            visualObj.color = defaultColor;\n        }\n\n        function getter(key) {\n            return visualObj[key];\n        }\n\n        function setter(key, value) {\n            visualObj[key] = value;\n        }\n\n        var mappings = visualMapModel.controllerVisuals[\n            forceState || visualMapModel.getValueState(targetValue)\n        ];\n        var visualTypes = VisualMapping.prepareVisualTypes(mappings);\n\n        each$1(visualTypes, function (type) {\n            var visualMapping = mappings[type];\n            if (opts.convertOpacityToAlpha && type === 'opacity') {\n                type = 'colorAlpha';\n                visualMapping = mappings.__alphaForOpacity;\n            }\n            if (VisualMapping.dependsOn(type, visualCluster)) {\n                visualMapping && visualMapping.applyVisual(\n                    targetValue, getter, setter\n                );\n            }\n        });\n\n        return visualObj[visualCluster];\n    },\n\n    /**\n     * @protected\n     */\n    positionGroup: function (group) {\n        var model = this.visualMapModel;\n        var api = this.api;\n\n        positionElement(\n            group,\n            model.getBoxLayoutParams(),\n            {width: api.getWidth(), height: api.getHeight()}\n        );\n    },\n\n    /**\n     * @protected\n     * @abstract\n     */\n    doRender: noop\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/component/visualMap/VisualMapModel} visualMapModel\\\n * @param {module:echarts/ExtensionAPI} api\n * @param {Array.<number>} itemSize always [short, long]\n * @return {string} 'left' or 'right' or 'top' or 'bottom'\n */\nfunction getItemAlign(visualMapModel, api, itemSize) {\n    var modelOption = visualMapModel.option;\n    var itemAlign = modelOption.align;\n\n    if (itemAlign != null && itemAlign !== 'auto') {\n        return itemAlign;\n    }\n\n    // Auto decision align.\n    var ecSize = {width: api.getWidth(), height: api.getHeight()};\n    var realIndex = modelOption.orient === 'horizontal' ? 1 : 0;\n\n    var paramsSet = [\n        ['left', 'right', 'width'],\n        ['top', 'bottom', 'height']\n    ];\n    var reals = paramsSet[realIndex];\n    var fakeValue = [0, null, 10];\n\n    var layoutInput = {};\n    for (var i = 0; i < 3; i++) {\n        layoutInput[paramsSet[1 - realIndex][i]] = fakeValue[i];\n        layoutInput[reals[i]] = i === 2 ? itemSize[0] : modelOption[reals[i]];\n    }\n\n    var rParam = [['x', 'width', 3], ['y', 'height', 0]][realIndex];\n    var rect = getLayoutRect(layoutInput, ecSize, modelOption.padding);\n\n    return reals[\n        (rect.margin[rParam[2]] || 0) + rect[rParam[0]] + rect[rParam[1]] * 0.5\n            < ecSize[rParam[1]] * 0.5 ? 0 : 1\n    ];\n}\n\n/**\n * Prepare dataIndex for outside usage, where dataIndex means rawIndex, and\n * dataIndexInside means filtered index.\n */\nfunction convertDataIndex(batch) {\n    each$1(batch || [], function (batchItem) {\n        if (batch.dataIndex != null) {\n            batch.dataIndexInside = batch.dataIndex;\n            batch.dataIndex = null;\n        }\n    });\n    return batch;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar linearMap$3 = linearMap;\nvar each$26 = each$1;\nvar mathMin$7 = Math.min;\nvar mathMax$7 = Math.max;\n\n// Arbitrary value\nvar HOVER_LINK_SIZE = 12;\nvar HOVER_LINK_OUT = 6;\n\n// Notice:\n// Any \"interval\" should be by the order of [low, high].\n// \"handle0\" (handleIndex === 0) maps to\n// low data value: this._dataInterval[0] and has low coord.\n// \"handle1\" (handleIndex === 1) maps to\n// high data value: this._dataInterval[1] and has high coord.\n// The logic of transform is implemented in this._createBarGroup.\n\nvar ContinuousView = VisualMapView.extend({\n\n    type: 'visualMap.continuous',\n\n    /**\n     * @override\n     */\n    init: function () {\n\n        ContinuousView.superApply(this, 'init', arguments);\n\n        /**\n         * @private\n         */\n        this._shapes = {};\n\n        /**\n         * @private\n         */\n        this._dataInterval = [];\n\n        /**\n         * @private\n         */\n        this._handleEnds = [];\n\n        /**\n         * @private\n         */\n        this._orient;\n\n        /**\n         * @private\n         */\n        this._useHandle;\n\n        /**\n         * @private\n         */\n        this._hoverLinkDataIndices = [];\n\n        /**\n         * @private\n         */\n        this._dragging;\n\n        /**\n         * @private\n         */\n        this._hovering;\n    },\n\n    /**\n     * @protected\n     * @override\n     */\n    doRender: function (visualMapModel, ecModel, api, payload) {\n        if (!payload || payload.type !== 'selectDataRange' || payload.from !== this.uid) {\n            this._buildView();\n        }\n    },\n\n    /**\n     * @private\n     */\n    _buildView: function () {\n        this.group.removeAll();\n\n        var visualMapModel = this.visualMapModel;\n        var thisGroup = this.group;\n\n        this._orient = visualMapModel.get('orient');\n        this._useHandle = visualMapModel.get('calculable');\n\n        this._resetInterval();\n\n        this._renderBar(thisGroup);\n\n        var dataRangeText = visualMapModel.get('text');\n        this._renderEndsText(thisGroup, dataRangeText, 0);\n        this._renderEndsText(thisGroup, dataRangeText, 1);\n\n        // Do this for background size calculation.\n        this._updateView(true);\n\n        // After updating view, inner shapes is built completely,\n        // and then background can be rendered.\n        this.renderBackground(thisGroup);\n\n        // Real update view\n        this._updateView();\n\n        this._enableHoverLinkToSeries();\n        this._enableHoverLinkFromSeries();\n\n        this.positionGroup(thisGroup);\n    },\n\n    /**\n     * @private\n     */\n    _renderEndsText: function (group, dataRangeText, endsIndex) {\n        if (!dataRangeText) {\n            return;\n        }\n\n        // Compatible with ec2, text[0] map to high value, text[1] map low value.\n        var text = dataRangeText[1 - endsIndex];\n        text = text != null ? text + '' : '';\n\n        var visualMapModel = this.visualMapModel;\n        var textGap = visualMapModel.get('textGap');\n        var itemSize = visualMapModel.itemSize;\n\n        var barGroup = this._shapes.barGroup;\n        var position = this._applyTransform(\n            [\n                itemSize[0] / 2,\n                endsIndex === 0 ? -textGap : itemSize[1] + textGap\n            ],\n            barGroup\n        );\n        var align = this._applyTransform(\n            endsIndex === 0 ? 'bottom' : 'top',\n            barGroup\n        );\n        var orient = this._orient;\n        var textStyleModel = this.visualMapModel.textStyleModel;\n\n        this.group.add(new Text({\n            style: {\n                x: position[0],\n                y: position[1],\n                textVerticalAlign: orient === 'horizontal' ? 'middle' : align,\n                textAlign: orient === 'horizontal' ? align : 'center',\n                text: text,\n                textFont: textStyleModel.getFont(),\n                textFill: textStyleModel.getTextColor()\n            }\n        }));\n    },\n\n    /**\n     * @private\n     */\n    _renderBar: function (targetGroup) {\n        var visualMapModel = this.visualMapModel;\n        var shapes = this._shapes;\n        var itemSize = visualMapModel.itemSize;\n        var orient = this._orient;\n        var useHandle = this._useHandle;\n        var itemAlign = getItemAlign(visualMapModel, this.api, itemSize);\n        var barGroup = shapes.barGroup = this._createBarGroup(itemAlign);\n\n        // Bar\n        barGroup.add(shapes.outOfRange = createPolygon());\n        barGroup.add(shapes.inRange = createPolygon(\n            null,\n            useHandle ? getCursor$1(this._orient) : null,\n            bind(this._dragHandle, this, 'all', false),\n            bind(this._dragHandle, this, 'all', true)\n        ));\n\n        var textRect = visualMapModel.textStyleModel.getTextRect('国');\n        var textSize = mathMax$7(textRect.width, textRect.height);\n\n        // Handle\n        if (useHandle) {\n            shapes.handleThumbs = [];\n            shapes.handleLabels = [];\n            shapes.handleLabelPoints = [];\n\n            this._createHandle(barGroup, 0, itemSize, textSize, orient, itemAlign);\n            this._createHandle(barGroup, 1, itemSize, textSize, orient, itemAlign);\n        }\n\n        this._createIndicator(barGroup, itemSize, textSize, orient);\n\n        targetGroup.add(barGroup);\n    },\n\n    /**\n     * @private\n     */\n    _createHandle: function (barGroup, handleIndex, itemSize, textSize, orient) {\n        var onDrift = bind(this._dragHandle, this, handleIndex, false);\n        var onDragEnd = bind(this._dragHandle, this, handleIndex, true);\n        var handleThumb = createPolygon(\n            createHandlePoints(handleIndex, textSize),\n            getCursor$1(this._orient),\n            onDrift,\n            onDragEnd\n        );\n        handleThumb.position[0] = itemSize[0];\n        barGroup.add(handleThumb);\n\n        // Text is always horizontal layout but should not be effected by\n        // transform (orient/inverse). So label is built separately but not\n        // use zrender/graphic/helper/RectText, and is located based on view\n        // group (according to handleLabelPoint) but not barGroup.\n        var textStyleModel = this.visualMapModel.textStyleModel;\n        var handleLabel = new Text({\n            draggable: true,\n            drift: onDrift,\n            onmousemove: function (e) {\n                // Fot mobile devicem, prevent screen slider on the button.\n                stop(e.event);\n            },\n            ondragend: onDragEnd,\n            style: {\n                x: 0, y: 0, text: '',\n                textFont: textStyleModel.getFont(),\n                textFill: textStyleModel.getTextColor()\n            }\n        });\n        this.group.add(handleLabel);\n\n        var handleLabelPoint = [\n            orient === 'horizontal'\n                ? textSize / 2\n                : textSize * 1.5,\n            orient === 'horizontal'\n                ? (handleIndex === 0 ? -(textSize * 1.5) : (textSize * 1.5))\n                : (handleIndex === 0 ? -textSize / 2 : textSize / 2)\n        ];\n\n        var shapes = this._shapes;\n        shapes.handleThumbs[handleIndex] = handleThumb;\n        shapes.handleLabelPoints[handleIndex] = handleLabelPoint;\n        shapes.handleLabels[handleIndex] = handleLabel;\n    },\n\n    /**\n     * @private\n     */\n    _createIndicator: function (barGroup, itemSize, textSize, orient) {\n        var indicator = createPolygon([[0, 0]], 'move');\n        indicator.position[0] = itemSize[0];\n        indicator.attr({invisible: true, silent: true});\n        barGroup.add(indicator);\n\n        var textStyleModel = this.visualMapModel.textStyleModel;\n        var indicatorLabel = new Text({\n            silent: true,\n            invisible: true,\n            style: {\n                x: 0, y: 0, text: '',\n                textFont: textStyleModel.getFont(),\n                textFill: textStyleModel.getTextColor()\n            }\n        });\n        this.group.add(indicatorLabel);\n\n        var indicatorLabelPoint = [\n            orient === 'horizontal' ? textSize / 2 : HOVER_LINK_OUT + 3,\n            0\n        ];\n\n        var shapes = this._shapes;\n        shapes.indicator = indicator;\n        shapes.indicatorLabel = indicatorLabel;\n        shapes.indicatorLabelPoint = indicatorLabelPoint;\n    },\n\n    /**\n     * @private\n     */\n    _dragHandle: function (handleIndex, isEnd, dx, dy) {\n        if (!this._useHandle) {\n            return;\n        }\n\n        this._dragging = !isEnd;\n\n        if (!isEnd) {\n            // Transform dx, dy to bar coordination.\n            var vertex = this._applyTransform([dx, dy], this._shapes.barGroup, true);\n            this._updateInterval(handleIndex, vertex[1]);\n\n            // Considering realtime, update view should be executed\n            // before dispatch action.\n            this._updateView();\n        }\n\n        // dragEnd do not dispatch action when realtime.\n        if (isEnd === !this.visualMapModel.get('realtime')) { // jshint ignore:line\n            this.api.dispatchAction({\n                type: 'selectDataRange',\n                from: this.uid,\n                visualMapId: this.visualMapModel.id,\n                selected: this._dataInterval.slice()\n            });\n        }\n\n        if (isEnd) {\n            !this._hovering && this._clearHoverLinkToSeries();\n        }\n        else if (useHoverLinkOnHandle(this.visualMapModel)) {\n            this._doHoverLinkToSeries(this._handleEnds[handleIndex], false);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _resetInterval: function () {\n        var visualMapModel = this.visualMapModel;\n\n        var dataInterval = this._dataInterval = visualMapModel.getSelected();\n        var dataExtent = visualMapModel.getExtent();\n        var sizeExtent = [0, visualMapModel.itemSize[1]];\n\n        this._handleEnds = [\n            linearMap$3(dataInterval[0], dataExtent, sizeExtent, true),\n            linearMap$3(dataInterval[1], dataExtent, sizeExtent, true)\n        ];\n    },\n\n    /**\n     * @private\n     * @param {(number|string)} handleIndex 0 or 1 or 'all'\n     * @param {number} dx\n     * @param {number} dy\n     */\n    _updateInterval: function (handleIndex, delta) {\n        delta = delta || 0;\n        var visualMapModel = this.visualMapModel;\n        var handleEnds = this._handleEnds;\n        var sizeExtent = [0, visualMapModel.itemSize[1]];\n\n        sliderMove(\n            delta,\n            handleEnds,\n            sizeExtent,\n            handleIndex,\n            // cross is forbiden\n            0\n        );\n\n        var dataExtent = visualMapModel.getExtent();\n        // Update data interval.\n        this._dataInterval = [\n            linearMap$3(handleEnds[0], sizeExtent, dataExtent, true),\n            linearMap$3(handleEnds[1], sizeExtent, dataExtent, true)\n        ];\n    },\n\n    /**\n     * @private\n     */\n    _updateView: function (forSketch) {\n        var visualMapModel = this.visualMapModel;\n        var dataExtent = visualMapModel.getExtent();\n        var shapes = this._shapes;\n\n        var outOfRangeHandleEnds = [0, visualMapModel.itemSize[1]];\n        var inRangeHandleEnds = forSketch ? outOfRangeHandleEnds : this._handleEnds;\n\n        var visualInRange = this._createBarVisual(\n            this._dataInterval, dataExtent, inRangeHandleEnds, 'inRange'\n        );\n        var visualOutOfRange = this._createBarVisual(\n            dataExtent, dataExtent, outOfRangeHandleEnds, 'outOfRange'\n        );\n\n        shapes.inRange\n            .setStyle({\n                fill: visualInRange.barColor,\n                opacity: visualInRange.opacity\n            })\n            .setShape('points', visualInRange.barPoints);\n        shapes.outOfRange\n            .setStyle({\n                fill: visualOutOfRange.barColor,\n                opacity: visualOutOfRange.opacity\n            })\n            .setShape('points', visualOutOfRange.barPoints);\n\n        this._updateHandle(inRangeHandleEnds, visualInRange);\n    },\n\n    /**\n     * @private\n     */\n    _createBarVisual: function (dataInterval, dataExtent, handleEnds, forceState) {\n        var opts = {\n            forceState: forceState,\n            convertOpacityToAlpha: true\n        };\n        var colorStops = this._makeColorGradient(dataInterval, opts);\n\n        var symbolSizes = [\n            this.getControllerVisual(dataInterval[0], 'symbolSize', opts),\n            this.getControllerVisual(dataInterval[1], 'symbolSize', opts)\n        ];\n        var barPoints = this._createBarPoints(handleEnds, symbolSizes);\n\n        return {\n            barColor: new LinearGradient(0, 0, 0, 1, colorStops),\n            barPoints: barPoints,\n            handlesColor: [\n                colorStops[0].color,\n                colorStops[colorStops.length - 1].color\n            ]\n        };\n    },\n\n    /**\n     * @private\n     */\n    _makeColorGradient: function (dataInterval, opts) {\n        // Considering colorHue, which is not linear, so we have to sample\n        // to calculate gradient color stops, but not only caculate head\n        // and tail.\n        var sampleNumber = 100; // Arbitrary value.\n        var colorStops = [];\n        var step = (dataInterval[1] - dataInterval[0]) / sampleNumber;\n\n        colorStops.push({\n            color: this.getControllerVisual(dataInterval[0], 'color', opts),\n            offset: 0\n        });\n\n        for (var i = 1; i < sampleNumber; i++) {\n            var currValue = dataInterval[0] + step * i;\n            if (currValue > dataInterval[1]) {\n                break;\n            }\n            colorStops.push({\n                color: this.getControllerVisual(currValue, 'color', opts),\n                offset: i / sampleNumber\n            });\n        }\n\n        colorStops.push({\n            color: this.getControllerVisual(dataInterval[1], 'color', opts),\n            offset: 1\n        });\n\n        return colorStops;\n    },\n\n    /**\n     * @private\n     */\n    _createBarPoints: function (handleEnds, symbolSizes) {\n        var itemSize = this.visualMapModel.itemSize;\n\n        return [\n            [itemSize[0] - symbolSizes[0], handleEnds[0]],\n            [itemSize[0], handleEnds[0]],\n            [itemSize[0], handleEnds[1]],\n            [itemSize[0] - symbolSizes[1], handleEnds[1]]\n        ];\n    },\n\n    /**\n     * @private\n     */\n    _createBarGroup: function (itemAlign) {\n        var orient = this._orient;\n        var inverse = this.visualMapModel.get('inverse');\n\n        return new Group(\n            (orient === 'horizontal' && !inverse)\n            ? {scale: itemAlign === 'bottom' ? [1, 1] : [-1, 1], rotation: Math.PI / 2}\n            : (orient === 'horizontal' && inverse)\n            ? {scale: itemAlign === 'bottom' ? [-1, 1] : [1, 1], rotation: -Math.PI / 2}\n            : (orient === 'vertical' && !inverse)\n            ? {scale: itemAlign === 'left' ? [1, -1] : [-1, -1]}\n            : {scale: itemAlign === 'left' ? [1, 1] : [-1, 1]}\n        );\n    },\n\n    /**\n     * @private\n     */\n    _updateHandle: function (handleEnds, visualInRange) {\n        if (!this._useHandle) {\n            return;\n        }\n\n        var shapes = this._shapes;\n        var visualMapModel = this.visualMapModel;\n        var handleThumbs = shapes.handleThumbs;\n        var handleLabels = shapes.handleLabels;\n\n        each$26([0, 1], function (handleIndex) {\n            var handleThumb = handleThumbs[handleIndex];\n            handleThumb.setStyle('fill', visualInRange.handlesColor[handleIndex]);\n            handleThumb.position[1] = handleEnds[handleIndex];\n\n            // Update handle label position.\n            var textPoint = applyTransform$1(\n                shapes.handleLabelPoints[handleIndex],\n                getTransform(handleThumb, this.group)\n            );\n            handleLabels[handleIndex].setStyle({\n                x: textPoint[0],\n                y: textPoint[1],\n                text: visualMapModel.formatValueText(this._dataInterval[handleIndex]),\n                textVerticalAlign: 'middle',\n                textAlign: this._applyTransform(\n                    this._orient === 'horizontal'\n                        ? (handleIndex === 0 ? 'bottom' : 'top')\n                        : 'left',\n                    shapes.barGroup\n                )\n            });\n        }, this);\n    },\n\n    /**\n     * @private\n     * @param {number} cursorValue\n     * @param {number} textValue\n     * @param {string} [rangeSymbol]\n     * @param {number} [halfHoverLinkSize]\n     */\n    _showIndicator: function (cursorValue, textValue, rangeSymbol, halfHoverLinkSize) {\n        var visualMapModel = this.visualMapModel;\n        var dataExtent = visualMapModel.getExtent();\n        var itemSize = visualMapModel.itemSize;\n        var sizeExtent = [0, itemSize[1]];\n        var pos = linearMap$3(cursorValue, dataExtent, sizeExtent, true);\n\n        var shapes = this._shapes;\n        var indicator = shapes.indicator;\n        if (!indicator) {\n            return;\n        }\n\n        indicator.position[1] = pos;\n        indicator.attr('invisible', false);\n        indicator.setShape('points', createIndicatorPoints(\n            !!rangeSymbol, halfHoverLinkSize, pos, itemSize[1]\n        ));\n\n        var opts = {convertOpacityToAlpha: true};\n        var color = this.getControllerVisual(cursorValue, 'color', opts);\n        indicator.setStyle('fill', color);\n\n        // Update handle label position.\n        var textPoint = applyTransform$1(\n            shapes.indicatorLabelPoint,\n            getTransform(indicator, this.group)\n        );\n\n        var indicatorLabel = shapes.indicatorLabel;\n        indicatorLabel.attr('invisible', false);\n        var align = this._applyTransform('left', shapes.barGroup);\n        var orient = this._orient;\n        indicatorLabel.setStyle({\n            text: (rangeSymbol ? rangeSymbol : '') + visualMapModel.formatValueText(textValue),\n            textVerticalAlign: orient === 'horizontal' ? align : 'middle',\n            textAlign: orient === 'horizontal' ? 'center' : align,\n            x: textPoint[0],\n            y: textPoint[1]\n        });\n    },\n\n    /**\n     * @private\n     */\n    _enableHoverLinkToSeries: function () {\n        var self = this;\n        this._shapes.barGroup\n\n            .on('mousemove', function (e) {\n                self._hovering = true;\n\n                if (!self._dragging) {\n                    var itemSize = self.visualMapModel.itemSize;\n                    var pos = self._applyTransform(\n                        [e.offsetX, e.offsetY], self._shapes.barGroup, true, true\n                    );\n                    // For hover link show when hover handle, which might be\n                    // below or upper than sizeExtent.\n                    pos[1] = mathMin$7(mathMax$7(0, pos[1]), itemSize[1]);\n                    self._doHoverLinkToSeries(\n                        pos[1],\n                        0 <= pos[0] && pos[0] <= itemSize[0]\n                    );\n                }\n            })\n\n            .on('mouseout', function () {\n                // When mouse is out of handle, hoverLink still need\n                // to be displayed when realtime is set as false.\n                self._hovering = false;\n                !self._dragging && self._clearHoverLinkToSeries();\n            });\n    },\n\n    /**\n     * @private\n     */\n    _enableHoverLinkFromSeries: function () {\n        var zr = this.api.getZr();\n\n        if (this.visualMapModel.option.hoverLink) {\n            zr.on('mouseover', this._hoverLinkFromSeriesMouseOver, this);\n            zr.on('mouseout', this._hideIndicator, this);\n        }\n        else {\n            this._clearHoverLinkFromSeries();\n        }\n    },\n\n    /**\n     * @private\n     */\n    _doHoverLinkToSeries: function (cursorPos, hoverOnBar) {\n        var visualMapModel = this.visualMapModel;\n        var itemSize = visualMapModel.itemSize;\n\n        if (!visualMapModel.option.hoverLink) {\n            return;\n        }\n\n        var sizeExtent = [0, itemSize[1]];\n        var dataExtent = visualMapModel.getExtent();\n\n        // For hover link show when hover handle, which might be below or upper than sizeExtent.\n        cursorPos = mathMin$7(mathMax$7(sizeExtent[0], cursorPos), sizeExtent[1]);\n\n        var halfHoverLinkSize = getHalfHoverLinkSize(visualMapModel, dataExtent, sizeExtent);\n        var hoverRange = [cursorPos - halfHoverLinkSize, cursorPos + halfHoverLinkSize];\n        var cursorValue = linearMap$3(cursorPos, sizeExtent, dataExtent, true);\n        var valueRange = [\n            linearMap$3(hoverRange[0], sizeExtent, dataExtent, true),\n            linearMap$3(hoverRange[1], sizeExtent, dataExtent, true)\n        ];\n        // Consider data range is out of visualMap range, see test/visualMap-continuous.html,\n        // where china and india has very large population.\n        hoverRange[0] < sizeExtent[0] && (valueRange[0] = -Infinity);\n        hoverRange[1] > sizeExtent[1] && (valueRange[1] = Infinity);\n\n        // Do not show indicator when mouse is over handle,\n        // otherwise labels overlap, especially when dragging.\n        if (hoverOnBar) {\n            if (valueRange[0] === -Infinity) {\n                this._showIndicator(cursorValue, valueRange[1], '< ', halfHoverLinkSize);\n            }\n            else if (valueRange[1] === Infinity) {\n                this._showIndicator(cursorValue, valueRange[0], '> ', halfHoverLinkSize);\n            }\n            else {\n                this._showIndicator(cursorValue, cursorValue, '≈ ', halfHoverLinkSize);\n            }\n        }\n\n        // When realtime is set as false, handles, which are in barGroup,\n        // also trigger hoverLink, which help user to realize where they\n        // focus on when dragging. (see test/heatmap-large.html)\n        // When realtime is set as true, highlight will not show when hover\n        // handle, because the label on handle, which displays a exact value\n        // but not range, might mislead users.\n        var oldBatch = this._hoverLinkDataIndices;\n        var newBatch = [];\n        if (hoverOnBar || useHoverLinkOnHandle(visualMapModel)) {\n            newBatch = this._hoverLinkDataIndices = visualMapModel.findTargetDataIndices(valueRange);\n        }\n\n        var resultBatches = compressBatches(oldBatch, newBatch);\n\n        this._dispatchHighDown('downplay', convertDataIndex(resultBatches[0]));\n        this._dispatchHighDown('highlight', convertDataIndex(resultBatches[1]));\n    },\n\n    /**\n     * @private\n     */\n    _hoverLinkFromSeriesMouseOver: function (e) {\n        var el = e.target;\n        var visualMapModel = this.visualMapModel;\n\n        if (!el || el.dataIndex == null) {\n            return;\n        }\n\n        var dataModel = this.ecModel.getSeriesByIndex(el.seriesIndex);\n\n        if (!visualMapModel.isTargetSeries(dataModel)) {\n            return;\n        }\n\n        var data = dataModel.getData(el.dataType);\n        var value = data.get(visualMapModel.getDataDimension(data), el.dataIndex, true);\n\n        if (!isNaN(value)) {\n            this._showIndicator(value, value);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _hideIndicator: function () {\n        var shapes = this._shapes;\n        shapes.indicator && shapes.indicator.attr('invisible', true);\n        shapes.indicatorLabel && shapes.indicatorLabel.attr('invisible', true);\n    },\n\n    /**\n     * @private\n     */\n    _clearHoverLinkToSeries: function () {\n        this._hideIndicator();\n\n        var indices = this._hoverLinkDataIndices;\n        this._dispatchHighDown('downplay', convertDataIndex(indices));\n\n        indices.length = 0;\n    },\n\n    /**\n     * @private\n     */\n    _clearHoverLinkFromSeries: function () {\n        this._hideIndicator();\n\n        var zr = this.api.getZr();\n        zr.off('mouseover', this._hoverLinkFromSeriesMouseOver);\n        zr.off('mouseout', this._hideIndicator);\n    },\n\n    /**\n     * @private\n     */\n    _applyTransform: function (vertex, element, inverse, global) {\n        var transform = getTransform(element, global ? null : this.group);\n\n        return graphic[\n            isArray(vertex) ? 'applyTransform' : 'transformDirection'\n        ](vertex, transform, inverse);\n    },\n\n    /**\n     * @private\n     */\n    _dispatchHighDown: function (type, batch) {\n        batch && batch.length && this.api.dispatchAction({\n            type: type,\n            batch: batch\n        });\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._clearHoverLinkFromSeries();\n        this._clearHoverLinkToSeries();\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this._clearHoverLinkFromSeries();\n        this._clearHoverLinkToSeries();\n    }\n\n});\n\nfunction createPolygon(points, cursor, onDrift, onDragEnd) {\n    return new Polygon({\n        shape: {points: points},\n        draggable: !!onDrift,\n        cursor: cursor,\n        drift: onDrift,\n        onmousemove: function (e) {\n            // Fot mobile devicem, prevent screen slider on the button.\n            stop(e.event);\n        },\n        ondragend: onDragEnd\n    });\n}\n\nfunction createHandlePoints(handleIndex, textSize) {\n    return handleIndex === 0\n        ? [[0, 0], [textSize, 0], [textSize, -textSize]]\n        : [[0, 0], [textSize, 0], [textSize, textSize]];\n}\n\nfunction createIndicatorPoints(isRange, halfHoverLinkSize, pos, extentMax) {\n    return isRange\n        ? [ // indicate range\n            [0, -mathMin$7(halfHoverLinkSize, mathMax$7(pos, 0))],\n            [HOVER_LINK_OUT, 0],\n            [0, mathMin$7(halfHoverLinkSize, mathMax$7(extentMax - pos, 0))]\n        ]\n        : [ // indicate single value\n            [0, 0], [5, -5], [5, 5]\n        ];\n}\n\nfunction getHalfHoverLinkSize(visualMapModel, dataExtent, sizeExtent) {\n    var halfHoverLinkSize = HOVER_LINK_SIZE / 2;\n    var hoverLinkDataSize = visualMapModel.get('hoverLinkDataSize');\n    if (hoverLinkDataSize) {\n        halfHoverLinkSize = linearMap$3(hoverLinkDataSize, dataExtent, sizeExtent, true) / 2;\n    }\n    return halfHoverLinkSize;\n}\n\nfunction useHoverLinkOnHandle(visualMapModel) {\n    var hoverLinkOnHandle = visualMapModel.get('hoverLinkOnHandle');\n    return !!(hoverLinkOnHandle == null ? visualMapModel.get('realtime') : hoverLinkOnHandle);\n}\n\nfunction getCursor$1(orient) {\n    return orient === 'vertical' ? 'ns-resize' : 'ew-resize';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar actionInfo$2 = {\n    type: 'selectDataRange',\n    event: 'dataRangeSelected',\n    // FIXME use updateView appears wrong\n    update: 'update'\n};\n\nregisterAction(actionInfo$2, function (payload, ecModel) {\n\n    ecModel.eachComponent({mainType: 'visualMap', query: payload}, function (model) {\n        model.setSelected(payload.selected);\n    });\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\nregisterPreprocessor(preprocessor$2);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PiecewiseModel = VisualMapModel.extend({\n\n    type: 'visualMap.piecewise',\n\n    /**\n     * Order Rule:\n     *\n     * option.categories / option.pieces / option.text / option.selected:\n     *     If !option.inverse,\n     *     Order when vertical: ['top', ..., 'bottom'].\n     *     Order when horizontal: ['left', ..., 'right'].\n     *     If option.inverse, the meaning of\n     *     the order should be reversed.\n     *\n     * this._pieceList:\n     *     The order is always [low, ..., high].\n     *\n     * Mapping from location to low-high:\n     *     If !option.inverse\n     *     When vertical, top is high.\n     *     When horizontal, right is high.\n     *     If option.inverse, reverse.\n     */\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        selected: null,             // Object. If not specified, means selected.\n                                    // When pieces and splitNumber: {'0': true, '5': true}\n                                    // When categories: {'cate1': false, 'cate3': true}\n                                    // When selected === false, means all unselected.\n\n        minOpen: false,             // Whether include values that smaller than `min`.\n        maxOpen: false,             // Whether include values that bigger than `max`.\n\n        align: 'auto',              // 'auto', 'left', 'right'\n        itemWidth: 20,              // When put the controller vertically, it is the length of\n                                    // horizontal side of each item. Otherwise, vertical side.\n        itemHeight: 14,             // When put the controller vertically, it is the length of\n                                    // vertical side of each item. Otherwise, horizontal side.\n        itemSymbol: 'roundRect',\n        pieceList: null,            // Each item is Object, with some of those attrs:\n                                    // {min, max, lt, gt, lte, gte, value,\n                                    // color, colorSaturation, colorAlpha, opacity,\n                                    // symbol, symbolSize}, which customize the range or visual\n                                    // coding of the certain piece. Besides, see \"Order Rule\".\n        categories: null,           // category names, like: ['some1', 'some2', 'some3'].\n                                    // Attr min/max are ignored when categories set. See \"Order Rule\"\n        splitNumber: 5,             // If set to 5, auto split five pieces equally.\n                                    // If set to 0 and component type not set, component type will be\n                                    // determined as \"continuous\". (It is less reasonable but for ec2\n                                    // compatibility, see echarts/component/visualMap/typeDefaulter)\n        selectedMode: 'multiple',   // Can be 'multiple' or 'single'.\n        itemGap: 10,                // The gap between two items, in px.\n        hoverLink: true,            // Enable hover highlight.\n\n        showLabel: null             // By default, when text is used, label will hide (the logic\n                                    // is remained for compatibility reason)\n    },\n\n    /**\n     * @override\n     */\n    optionUpdated: function (newOption, isInit) {\n        PiecewiseModel.superApply(this, 'optionUpdated', arguments);\n\n        /**\n         * The order is always [low, ..., high].\n         * [{text: string, interval: Array.<number>}, ...]\n         * @private\n         * @type {Array.<Object>}\n         */\n        this._pieceList = [];\n\n        this.resetExtent();\n\n        /**\n         * 'pieces', 'categories', 'splitNumber'\n         * @type {string}\n         */\n        var mode = this._mode = this._determineMode();\n\n        resetMethods[this._mode].call(this);\n\n        this._resetSelected(newOption, isInit);\n\n        var categories = this.option.categories;\n\n        this.resetVisual(function (mappingOption, state) {\n            if (mode === 'categories') {\n                mappingOption.mappingMethod = 'category';\n                mappingOption.categories = clone(categories);\n            }\n            else {\n                mappingOption.dataExtent = this.getExtent();\n                mappingOption.mappingMethod = 'piecewise';\n                mappingOption.pieceList = map(this._pieceList, function (piece) {\n                    var piece = clone(piece);\n                    if (state !== 'inRange') {\n                        // FIXME\n                        // outOfRange do not support special visual in pieces.\n                        piece.visual = null;\n                    }\n                    return piece;\n                });\n            }\n        });\n    },\n\n    /**\n     * @protected\n     * @override\n     */\n    completeVisualOption: function () {\n        // Consider this case:\n        // visualMap: {\n        //      pieces: [{symbol: 'circle', lt: 0}, {symbol: 'rect', gte: 0}]\n        // }\n        // where no inRange/outOfRange set but only pieces. So we should make\n        // default inRange/outOfRange for this case, otherwise visuals that only\n        // appear in `pieces` will not be taken into account in visual encoding.\n\n        var option = this.option;\n        var visualTypesInPieces = {};\n        var visualTypes = VisualMapping.listVisualTypes();\n        var isCategory = this.isCategory();\n\n        each$1(option.pieces, function (piece) {\n            each$1(visualTypes, function (visualType) {\n                if (piece.hasOwnProperty(visualType)) {\n                    visualTypesInPieces[visualType] = 1;\n                }\n            });\n        });\n\n        each$1(visualTypesInPieces, function (v, visualType) {\n            var exists = 0;\n            each$1(this.stateList, function (state) {\n                exists |= has(option, state, visualType)\n                    || has(option.target, state, visualType);\n            }, this);\n\n            !exists && each$1(this.stateList, function (state) {\n                (option[state] || (option[state] = {}))[visualType] = visualDefault.get(\n                    visualType, state === 'inRange' ? 'active' : 'inactive', isCategory\n                );\n            });\n        }, this);\n\n        function has(obj, state, visualType) {\n            return obj && obj[state] && (\n                isObject$1(obj[state])\n                    ? obj[state].hasOwnProperty(visualType)\n                    : obj[state] === visualType // e.g., inRange: 'symbol'\n            );\n        }\n\n        VisualMapModel.prototype.completeVisualOption.apply(this, arguments);\n    },\n\n    _resetSelected: function (newOption, isInit) {\n        var thisOption = this.option;\n        var pieceList = this._pieceList;\n\n        // Selected do not merge but all override.\n        var selected = (isInit ? thisOption : newOption).selected || {};\n        thisOption.selected = selected;\n\n        // Consider 'not specified' means true.\n        each$1(pieceList, function (piece, index) {\n            var key = this.getSelectedMapKey(piece);\n            if (!selected.hasOwnProperty(key)) {\n                selected[key] = true;\n            }\n        }, this);\n\n        if (thisOption.selectedMode === 'single') {\n            // Ensure there is only one selected.\n            var hasSel = false;\n\n            each$1(pieceList, function (piece, index) {\n                var key = this.getSelectedMapKey(piece);\n                if (selected[key]) {\n                    hasSel\n                        ? (selected[key] = false)\n                        : (hasSel = true);\n                }\n            }, this);\n        }\n        // thisOption.selectedMode === 'multiple', default: all selected.\n    },\n\n    /**\n     * @public\n     */\n    getSelectedMapKey: function (piece) {\n        return this._mode === 'categories'\n            ? piece.value + '' : piece.index + '';\n    },\n\n    /**\n     * @public\n     */\n    getPieceList: function () {\n        return this._pieceList;\n    },\n\n    /**\n     * @private\n     * @return {string}\n     */\n    _determineMode: function () {\n        var option = this.option;\n\n        return option.pieces && option.pieces.length > 0\n            ? 'pieces'\n            : this.option.categories\n            ? 'categories'\n            : 'splitNumber';\n    },\n\n    /**\n     * @public\n     * @override\n     */\n    setSelected: function (selected) {\n        this.option.selected = clone(selected);\n    },\n\n    /**\n     * @public\n     * @override\n     */\n    getValueState: function (value) {\n        var index = VisualMapping.findPieceIndex(value, this._pieceList);\n\n        return index != null\n            ? (this.option.selected[this.getSelectedMapKey(this._pieceList[index])]\n                ? 'inRange' : 'outOfRange'\n            )\n            : 'outOfRange';\n    },\n\n    /**\n     * @public\n     * @params {number} pieceIndex piece index in visualMapModel.getPieceList()\n     * @return {Array.<Object>} [{seriesId, dataIndices: <Array.<number>>}, ...]\n     */\n    findTargetDataIndices: function (pieceIndex) {\n        var result = [];\n\n        this.eachTargetSeries(function (seriesModel) {\n            var dataIndices = [];\n            var data = seriesModel.getData();\n\n            data.each(this.getDataDimension(data), function (value, dataIndex) {\n                // Should always base on model pieceList, because it is order sensitive.\n                var pIdx = VisualMapping.findPieceIndex(value, this._pieceList);\n                pIdx === pieceIndex && dataIndices.push(dataIndex);\n            }, this);\n\n            result.push({seriesId: seriesModel.id, dataIndex: dataIndices});\n        }, this);\n\n        return result;\n    },\n\n    /**\n     * @private\n     * @param {Object} piece piece.value or piece.interval is required.\n     * @return {number} Can be Infinity or -Infinity\n     */\n    getRepresentValue: function (piece) {\n        var representValue;\n        if (this.isCategory()) {\n            representValue = piece.value;\n        }\n        else {\n            if (piece.value != null) {\n                representValue = piece.value;\n            }\n            else {\n                var pieceInterval = piece.interval || [];\n                representValue = (pieceInterval[0] === -Infinity && pieceInterval[1] === Infinity)\n                    ? 0\n                    : (pieceInterval[0] + pieceInterval[1]) / 2;\n            }\n        }\n        return representValue;\n    },\n\n    getVisualMeta: function (getColorVisual) {\n        // Do not support category. (category axis is ordinal, numerical)\n        if (this.isCategory()) {\n            return;\n        }\n\n        var stops = [];\n        var outerColors = [];\n        var visualMapModel = this;\n\n        function setStop(interval, valueState) {\n            var representValue = visualMapModel.getRepresentValue({interval: interval});\n            if (!valueState) {\n                valueState = visualMapModel.getValueState(representValue);\n            }\n            var color = getColorVisual(representValue, valueState);\n            if (interval[0] === -Infinity) {\n                outerColors[0] = color;\n            }\n            else if (interval[1] === Infinity) {\n                outerColors[1] = color;\n            }\n            else {\n                stops.push(\n                    {value: interval[0], color: color},\n                    {value: interval[1], color: color}\n                );\n            }\n        }\n\n        // Suplement\n        var pieceList = this._pieceList.slice();\n        if (!pieceList.length) {\n            pieceList.push({interval: [-Infinity, Infinity]});\n        }\n        else {\n            var edge = pieceList[0].interval[0];\n            edge !== -Infinity && pieceList.unshift({interval: [-Infinity, edge]});\n            edge = pieceList[pieceList.length - 1].interval[1];\n            edge !== Infinity && pieceList.push({interval: [edge, Infinity]});\n        }\n\n        var curr = -Infinity;\n        each$1(pieceList, function (piece) {\n            var interval = piece.interval;\n            if (interval) {\n                // Fulfill gap.\n                interval[0] > curr && setStop([curr, interval[0]], 'outOfRange');\n                setStop(interval.slice());\n                curr = interval[1];\n            }\n        }, this);\n\n        return {stops: stops, outerColors: outerColors};\n    }\n\n});\n\n/**\n * Key is this._mode\n * @type {Object}\n * @this {module:echarts/component/viusalMap/PiecewiseMode}\n */\nvar resetMethods = {\n\n    splitNumber: function () {\n        var thisOption = this.option;\n        var pieceList = this._pieceList;\n        var precision = Math.min(thisOption.precision, 20);\n        var dataExtent = this.getExtent();\n        var splitNumber = thisOption.splitNumber;\n        splitNumber = Math.max(parseInt(splitNumber, 10), 1);\n        thisOption.splitNumber = splitNumber;\n\n        var splitStep = (dataExtent[1] - dataExtent[0]) / splitNumber;\n        // Precision auto-adaption\n        while (+splitStep.toFixed(precision) !== splitStep && precision < 5) {\n            precision++;\n        }\n        thisOption.precision = precision;\n        splitStep = +splitStep.toFixed(precision);\n\n        var index = 0;\n\n        if (thisOption.minOpen) {\n            pieceList.push({\n                index: index++,\n                interval: [-Infinity, dataExtent[0]],\n                close: [0, 0]\n            });\n        }\n\n        for (\n            var curr = dataExtent[0], len = index + splitNumber;\n            index < len;\n            curr += splitStep\n        ) {\n            var max = index === splitNumber - 1 ? dataExtent[1] : (curr + splitStep);\n\n            pieceList.push({\n                index: index++,\n                interval: [curr, max],\n                close: [1, 1]\n            });\n        }\n\n        if (thisOption.maxOpen) {\n            pieceList.push({\n                index: index++,\n                interval: [dataExtent[1], Infinity],\n                close: [0, 0]\n            });\n        }\n\n        reformIntervals(pieceList);\n\n        each$1(pieceList, function (piece) {\n            piece.text = this.formatValueText(piece.interval);\n        }, this);\n    },\n\n    categories: function () {\n        var thisOption = this.option;\n        each$1(thisOption.categories, function (cate) {\n            // FIXME category模式也使用pieceList，但在visualMapping中不是使用pieceList。\n            // 是否改一致。\n            this._pieceList.push({\n                text: this.formatValueText(cate, true),\n                value: cate\n            });\n        }, this);\n\n        // See \"Order Rule\".\n        normalizeReverse(thisOption, this._pieceList);\n    },\n\n    pieces: function () {\n        var thisOption = this.option;\n        var pieceList = this._pieceList;\n\n        each$1(thisOption.pieces, function (pieceListItem, index) {\n\n            if (!isObject$1(pieceListItem)) {\n                pieceListItem = {value: pieceListItem};\n            }\n\n            var item = {text: '', index: index};\n\n            if (pieceListItem.label != null) {\n                item.text = pieceListItem.label;\n            }\n\n            if (pieceListItem.hasOwnProperty('value')) {\n                var value = item.value = pieceListItem.value;\n                item.interval = [value, value];\n                item.close = [1, 1];\n            }\n            else {\n                // `min` `max` is legacy option.\n                // `lt` `gt` `lte` `gte` is recommanded.\n                var interval = item.interval = [];\n                var close = item.close = [0, 0];\n\n                var closeList = [1, 0, 1];\n                var infinityList = [-Infinity, Infinity];\n\n                var useMinMax = [];\n                for (var lg = 0; lg < 2; lg++) {\n                    var names = [['gte', 'gt', 'min'], ['lte', 'lt', 'max']][lg];\n                    for (var i = 0; i < 3 && interval[lg] == null; i++) {\n                        interval[lg] = pieceListItem[names[i]];\n                        close[lg] = closeList[i];\n                        useMinMax[lg] = i === 2;\n                    }\n                    interval[lg] == null && (interval[lg] = infinityList[lg]);\n                }\n                useMinMax[0] && interval[1] === Infinity && (close[0] = 0);\n                useMinMax[1] && interval[0] === -Infinity && (close[1] = 0);\n\n                if (__DEV__) {\n                    if (interval[0] > interval[1]) {\n                        console.warn(\n                            'Piece ' + index + 'is illegal: ' + interval\n                            + ' lower bound should not greater then uppper bound.'\n                        );\n                    }\n                }\n\n                if (interval[0] === interval[1] && close[0] && close[1]) {\n                    // Consider: [{min: 5, max: 5, visual: {...}}, {min: 0, max: 5}],\n                    // we use value to lift the priority when min === max\n                    item.value = interval[0];\n                }\n            }\n\n            item.visual = VisualMapping.retrieveVisuals(pieceListItem);\n\n            pieceList.push(item);\n\n        }, this);\n\n        // See \"Order Rule\".\n        normalizeReverse(thisOption, pieceList);\n        // Only pieces\n        reformIntervals(pieceList);\n\n        each$1(pieceList, function (piece) {\n            var close = piece.close;\n            var edgeSymbols = [['<', '≤'][close[1]], ['>', '≥'][close[0]]];\n            piece.text = piece.text || this.formatValueText(\n                piece.value != null ? piece.value : piece.interval,\n                false,\n                edgeSymbols\n            );\n        }, this);\n    }\n};\n\nfunction normalizeReverse(thisOption, pieceList) {\n    var inverse = thisOption.inverse;\n    if (thisOption.orient === 'vertical' ? !inverse : inverse) {\n            pieceList.reverse();\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PiecewiseVisualMapView = VisualMapView.extend({\n\n    type: 'visualMap.piecewise',\n\n    /**\n     * @protected\n     * @override\n     */\n    doRender: function () {\n        var thisGroup = this.group;\n\n        thisGroup.removeAll();\n\n        var visualMapModel = this.visualMapModel;\n        var textGap = visualMapModel.get('textGap');\n        var textStyleModel = visualMapModel.textStyleModel;\n        var textFont = textStyleModel.getFont();\n        var textFill = textStyleModel.getTextColor();\n        var itemAlign = this._getItemAlign();\n        var itemSize = visualMapModel.itemSize;\n        var viewData = this._getViewData();\n        var endsText = viewData.endsText;\n        var showLabel = retrieve(visualMapModel.get('showLabel', true), !endsText);\n\n        endsText && this._renderEndsText(\n            thisGroup, endsText[0], itemSize, showLabel, itemAlign\n        );\n\n        each$1(viewData.viewPieceList, renderItem, this);\n\n        endsText && this._renderEndsText(\n            thisGroup, endsText[1], itemSize, showLabel, itemAlign\n        );\n\n        box(\n            visualMapModel.get('orient'), thisGroup, visualMapModel.get('itemGap')\n        );\n\n        this.renderBackground(thisGroup);\n\n        this.positionGroup(thisGroup);\n\n        function renderItem(item) {\n            var piece = item.piece;\n\n            var itemGroup = new Group();\n            itemGroup.onclick = bind(this._onItemClick, this, piece);\n\n            this._enableHoverLink(itemGroup, item.indexInModelPieceList);\n\n            var representValue = visualMapModel.getRepresentValue(piece);\n\n            this._createItemSymbol(\n                itemGroup, representValue, [0, 0, itemSize[0], itemSize[1]]\n            );\n\n            if (showLabel) {\n                var visualState = this.visualMapModel.getValueState(representValue);\n\n                itemGroup.add(new Text({\n                    style: {\n                        x: itemAlign === 'right' ? -textGap : itemSize[0] + textGap,\n                        y: itemSize[1] / 2,\n                        text: piece.text,\n                        textVerticalAlign: 'middle',\n                        textAlign: itemAlign,\n                        textFont: textFont,\n                        textFill: textFill,\n                        opacity: visualState === 'outOfRange' ? 0.5 : 1\n                    }\n                }));\n            }\n\n            thisGroup.add(itemGroup);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _enableHoverLink: function (itemGroup, pieceIndex) {\n        itemGroup\n            .on('mouseover', bind(onHoverLink, this, 'highlight'))\n            .on('mouseout', bind(onHoverLink, this, 'downplay'));\n\n        function onHoverLink(method) {\n            var visualMapModel = this.visualMapModel;\n\n            visualMapModel.option.hoverLink && this.api.dispatchAction({\n                type: method,\n                batch: convertDataIndex(\n                    visualMapModel.findTargetDataIndices(pieceIndex)\n                )\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _getItemAlign: function () {\n        var visualMapModel = this.visualMapModel;\n        var modelOption = visualMapModel.option;\n\n        if (modelOption.orient === 'vertical') {\n            return getItemAlign(\n                visualMapModel, this.api, visualMapModel.itemSize\n            );\n        }\n        else { // horizontal, most case left unless specifying right.\n            var align = modelOption.align;\n            if (!align || align === 'auto') {\n                align = 'left';\n            }\n            return align;\n        }\n    },\n\n    /**\n     * @private\n     */\n    _renderEndsText: function (group, text, itemSize, showLabel, itemAlign) {\n        if (!text) {\n            return;\n        }\n\n        var itemGroup = new Group();\n        var textStyleModel = this.visualMapModel.textStyleModel;\n\n        itemGroup.add(new Text({\n            style: {\n                x: showLabel ? (itemAlign === 'right' ? itemSize[0] : 0) : itemSize[0] / 2,\n                y: itemSize[1] / 2,\n                textVerticalAlign: 'middle',\n                textAlign: showLabel ? itemAlign : 'center',\n                text: text,\n                textFont: textStyleModel.getFont(),\n                textFill: textStyleModel.getTextColor()\n            }\n        }));\n\n        group.add(itemGroup);\n    },\n\n    /**\n     * @private\n     * @return {Object} {peiceList, endsText} The order is the same as screen pixel order.\n     */\n    _getViewData: function () {\n        var visualMapModel = this.visualMapModel;\n\n        var viewPieceList = map(visualMapModel.getPieceList(), function (piece, index) {\n            return {piece: piece, indexInModelPieceList: index};\n        });\n        var endsText = visualMapModel.get('text');\n\n        // Consider orient and inverse.\n        var orient = visualMapModel.get('orient');\n        var inverse = visualMapModel.get('inverse');\n\n        // Order of model pieceList is always [low, ..., high]\n        if (orient === 'horizontal' ? inverse : !inverse) {\n            viewPieceList.reverse();\n        }\n        // Origin order of endsText is [high, low]\n        else if (endsText) {\n            endsText = endsText.slice().reverse();\n        }\n\n        return {viewPieceList: viewPieceList, endsText: endsText};\n    },\n\n    /**\n     * @private\n     */\n    _createItemSymbol: function (group, representValue, shapeParam) {\n        group.add(createSymbol(\n            this.getControllerVisual(representValue, 'symbol'),\n            shapeParam[0], shapeParam[1], shapeParam[2], shapeParam[3],\n            this.getControllerVisual(representValue, 'color')\n        ));\n    },\n\n    /**\n     * @private\n     */\n    _onItemClick: function (piece) {\n        var visualMapModel = this.visualMapModel;\n        var option = visualMapModel.option;\n        var selected = clone(option.selected);\n        var newKey = visualMapModel.getSelectedMapKey(piece);\n\n        if (option.selectedMode === 'single') {\n            selected[newKey] = true;\n            each$1(selected, function (o, key) {\n                selected[key] = key === newKey;\n            });\n        }\n        else {\n            selected[newKey] = !selected[newKey];\n        }\n\n        this.api.dispatchAction({\n            type: 'selectDataRange',\n            from: this.uid,\n            visualMapId: this.visualMapModel.id,\n            selected: selected\n        });\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\nregisterPreprocessor(preprocessor$2);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * visualMap component entry\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar addCommas$1 = addCommas;\nvar encodeHTML$1 = encodeHTML;\n\nfunction fillLabel(opt) {\n    defaultEmphasis(opt, 'label', ['show']);\n}\nvar MarkerModel = extendComponentModel({\n\n    type: 'marker',\n\n    dependencies: ['series', 'grid', 'polar', 'geo'],\n\n    /**\n     * @overrite\n     */\n    init: function (option, parentModel, ecModel, extraOpt) {\n\n        if (__DEV__) {\n            if (this.type === 'marker') {\n                throw new Error('Marker component is abstract component. Use markLine, markPoint, markArea instead.');\n            }\n        }\n        this.mergeDefaultAndTheme(option, ecModel);\n        this.mergeOption(option, ecModel, extraOpt.createdBySelf, true);\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isAnimationEnabled: function () {\n        if (env$1.node) {\n            return false;\n        }\n\n        var hostSeries = this.__hostSeries;\n        return this.getShallow('animation') && hostSeries && hostSeries.isAnimationEnabled();\n    },\n\n    mergeOption: function (newOpt, ecModel, createdBySelf, isInit) {\n        var MarkerModel = this.constructor;\n        var modelPropName = this.mainType + 'Model';\n        if (!createdBySelf) {\n            ecModel.eachSeries(function (seriesModel) {\n\n                var markerOpt = seriesModel.get(this.mainType, true);\n\n                var markerModel = seriesModel[modelPropName];\n                if (!markerOpt || !markerOpt.data) {\n                    seriesModel[modelPropName] = null;\n                    return;\n                }\n                if (!markerModel) {\n                    if (isInit) {\n                        // Default label emphasis `position` and `show`\n                        fillLabel(markerOpt);\n                    }\n                    each$1(markerOpt.data, function (item) {\n                        // FIXME Overwrite fillLabel method ?\n                        if (item instanceof Array) {\n                            fillLabel(item[0]);\n                            fillLabel(item[1]);\n                        }\n                        else {\n                            fillLabel(item);\n                        }\n                    });\n\n                    markerModel = new MarkerModel(\n                        markerOpt, this, ecModel\n                    );\n\n                    extend(markerModel, {\n                        mainType: this.mainType,\n                        // Use the same series index and name\n                        seriesIndex: seriesModel.seriesIndex,\n                        name: seriesModel.name,\n                        createdBySelf: true\n                    });\n\n                    markerModel.__hostSeries = seriesModel;\n                }\n                else {\n                    markerModel.mergeOption(markerOpt, ecModel, true);\n                }\n                seriesModel[modelPropName] = markerModel;\n            }, this);\n        }\n    },\n\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var value = this.getRawValue(dataIndex);\n        var formattedValue = isArray(value)\n            ? map(value, addCommas$1).join(', ') : addCommas$1(value);\n        var name = data.getName(dataIndex);\n        var html = encodeHTML$1(this.name);\n        if (value != null || name) {\n            html += '<br />';\n        }\n        if (name) {\n            html += encodeHTML$1(name);\n            if (value != null) {\n                html += ' : ';\n            }\n        }\n        if (value != null) {\n            html += encodeHTML$1(formattedValue);\n        }\n        return html;\n    },\n\n    getData: function () {\n        return this._data;\n    },\n\n    setData: function (data) {\n        this._data = data;\n    }\n});\n\nmixin(MarkerModel, dataFormatMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markPoint',\n\n    defaultOption: {\n        zlevel: 0,\n        z: 5,\n        symbol: 'pin',\n        symbolSize: 50,\n        //symbolRotate: 0,\n        //symbolOffset: [0, 0]\n        tooltip: {\n            trigger: 'item'\n        },\n        label: {\n            show: true,\n            position: 'inside'\n        },\n        itemStyle: {\n            borderWidth: 2\n        },\n        emphasis: {\n            label: {\n                show: true\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar indexOf$2 = indexOf;\n\nfunction hasXOrY(item) {\n    return !(isNaN(parseFloat(item.x)) && isNaN(parseFloat(item.y)));\n}\n\nfunction hasXAndY(item) {\n    return !isNaN(parseFloat(item.x)) && !isNaN(parseFloat(item.y));\n}\n\n// Make it simple, do not visit all stacked value to count precision.\n// function getPrecision(data, valueAxisDim, dataIndex) {\n//     var precision = -1;\n//     var stackedDim = data.mapDimension(valueAxisDim);\n//     do {\n//         precision = Math.max(\n//             numberUtil.getPrecision(data.get(stackedDim, dataIndex)),\n//             precision\n//         );\n//         var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');\n//         if (stackedOnSeries) {\n//             var byValue = data.get(data.getCalculationInfo('stackedByDimension'), dataIndex);\n//             data = stackedOnSeries.getData();\n//             dataIndex = data.indexOf(data.getCalculationInfo('stackedByDimension'), byValue);\n//             stackedDim = data.getCalculationInfo('stackedDimension');\n//         }\n//         else {\n//             data = null;\n//         }\n//     } while (data);\n\n//     return precision;\n// }\n\nfunction markerTypeCalculatorWithExtent(\n    mlType, data, otherDataDim, targetDataDim, otherCoordIndex, targetCoordIndex\n) {\n    var coordArr = [];\n\n    var stacked = isDimensionStacked(data, targetDataDim /*, otherDataDim*/);\n    var calcDataDim = stacked\n        ? data.getCalculationInfo('stackResultDimension')\n        : targetDataDim;\n\n    var value = numCalculate(data, calcDataDim, mlType);\n\n    var dataIndex = data.indicesOfNearest(calcDataDim, value)[0];\n    coordArr[otherCoordIndex] = data.get(otherDataDim, dataIndex);\n    coordArr[targetCoordIndex] = data.get(targetDataDim, dataIndex);\n\n    // Make it simple, do not visit all stacked value to count precision.\n    var precision = getPrecision(data.get(targetDataDim, dataIndex));\n    precision = Math.min(precision, 20);\n    if (precision >= 0) {\n        coordArr[targetCoordIndex] = +coordArr[targetCoordIndex].toFixed(precision);\n    }\n\n    return coordArr;\n}\n\nvar curry$6 = curry;\n// TODO Specified percent\nvar markerTypeCalculator = {\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    min: curry$6(markerTypeCalculatorWithExtent, 'min'),\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    max: curry$6(markerTypeCalculatorWithExtent, 'max'),\n\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    average: curry$6(markerTypeCalculatorWithExtent, 'average')\n};\n\n/**\n * Transform markPoint data item to format used in List by do the following\n * 1. Calculate statistic like `max`, `min`, `average`\n * 2. Convert `item.xAxis`, `item.yAxis` to `item.coord` array\n * @param  {module:echarts/model/Series} seriesModel\n * @param  {module:echarts/coord/*} [coordSys]\n * @param  {Object} item\n * @return {Object}\n */\nfunction dataTransform(seriesModel, item) {\n    var data = seriesModel.getData();\n    var coordSys = seriesModel.coordinateSystem;\n\n    // 1. If not specify the position with pixel directly\n    // 2. If `coord` is not a data array. Which uses `xAxis`,\n    // `yAxis` to specify the coord on each dimension\n\n    // parseFloat first because item.x and item.y can be percent string like '20%'\n    if (item && !hasXAndY(item) && !isArray(item.coord) && coordSys) {\n        var dims = coordSys.dimensions;\n        var axisInfo = getAxisInfo$1(item, data, coordSys, seriesModel);\n\n        // Clone the option\n        // Transform the properties xAxis, yAxis, radiusAxis, angleAxis, geoCoord to value\n        item = clone(item);\n\n        if (item.type\n            && markerTypeCalculator[item.type]\n            && axisInfo.baseAxis && axisInfo.valueAxis\n        ) {\n            var otherCoordIndex = indexOf$2(dims, axisInfo.baseAxis.dim);\n            var targetCoordIndex = indexOf$2(dims, axisInfo.valueAxis.dim);\n\n            item.coord = markerTypeCalculator[item.type](\n                data, axisInfo.baseDataDim, axisInfo.valueDataDim,\n                otherCoordIndex, targetCoordIndex\n            );\n            // Force to use the value of calculated value.\n            item.value = item.coord[targetCoordIndex];\n        }\n        else {\n            // FIXME Only has one of xAxis and yAxis.\n            var coord = [\n                item.xAxis != null ? item.xAxis : item.radiusAxis,\n                item.yAxis != null ? item.yAxis : item.angleAxis\n            ];\n            // Each coord support max, min, average\n            for (var i = 0; i < 2; i++) {\n                if (markerTypeCalculator[coord[i]]) {\n                    coord[i] = numCalculate(data, data.mapDimension(dims[i]), coord[i]);\n                }\n            }\n            item.coord = coord;\n        }\n    }\n    return item;\n}\n\nfunction getAxisInfo$1(item, data, coordSys, seriesModel) {\n    var ret = {};\n\n    if (item.valueIndex != null || item.valueDim != null) {\n        ret.valueDataDim = item.valueIndex != null\n            ? data.getDimension(item.valueIndex) : item.valueDim;\n        ret.valueAxis = coordSys.getAxis(dataDimToCoordDim(seriesModel, ret.valueDataDim));\n        ret.baseAxis = coordSys.getOtherAxis(ret.valueAxis);\n        ret.baseDataDim = data.mapDimension(ret.baseAxis.dim);\n    }\n    else {\n        ret.baseAxis = seriesModel.getBaseAxis();\n        ret.valueAxis = coordSys.getOtherAxis(ret.baseAxis);\n        ret.baseDataDim = data.mapDimension(ret.baseAxis.dim);\n        ret.valueDataDim = data.mapDimension(ret.valueAxis.dim);\n    }\n\n    return ret;\n}\n\nfunction dataDimToCoordDim(seriesModel, dataDim) {\n    var data = seriesModel.getData();\n    var dimensions = data.dimensions;\n    dataDim = data.getDimension(dataDim);\n    for (var i = 0; i < dimensions.length; i++) {\n        var dimItem = data.getDimensionInfo(dimensions[i]);\n        if (dimItem.name === dataDim) {\n            return dimItem.coordDim;\n        }\n    }\n}\n\n/**\n * Filter data which is out of coordinateSystem range\n * [dataFilter description]\n * @param  {module:echarts/coord/*} [coordSys]\n * @param  {Object} item\n * @return {boolean}\n */\nfunction dataFilter$1(coordSys, item) {\n    // Alwalys return true if there is no coordSys\n    return (coordSys && coordSys.containData && item.coord && !hasXOrY(item))\n        ? coordSys.containData(item.coord) : true;\n}\n\nfunction dimValueGetter(item, dimName, dataIndex, dimIndex) {\n    // x, y, radius, angle\n    if (dimIndex < 2) {\n        return item.coord && item.coord[dimIndex];\n    }\n    return item.value;\n}\n\nfunction numCalculate(data, valueDataDim, type) {\n    if (type === 'average') {\n        var sum = 0;\n        var count = 0;\n        data.each(valueDataDim, function (val, idx) {\n            if (!isNaN(val)) {\n                sum += val;\n                count++;\n            }\n        });\n        return sum / count;\n    }\n    else if (type === 'median') {\n        return data.getMedian(valueDataDim);\n    }\n    else {\n        // max & min\n        return data.getDataExtent(valueDataDim, true)[type === 'max' ? 1 : 0];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar MarkerView = extendComponentView({\n\n    type: 'marker',\n\n    init: function () {\n        /**\n         * Markline grouped by series\n         * @private\n         * @type {module:zrender/core/util.HashMap}\n         */\n        this.markerGroupMap = createHashMap();\n    },\n\n    render: function (markerModel, ecModel, api) {\n        var markerGroupMap = this.markerGroupMap;\n        markerGroupMap.each(function (item) {\n            item.__keep = false;\n        });\n\n        var markerModelKey = this.type + 'Model';\n        ecModel.eachSeries(function (seriesModel) {\n            var markerModel = seriesModel[markerModelKey];\n            markerModel && this.renderSeries(seriesModel, markerModel, ecModel, api);\n        }, this);\n\n        markerGroupMap.each(function (item) {\n            !item.__keep && this.group.remove(item.group);\n        }, this);\n    },\n\n    renderSeries: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction updateMarkerLayout(mpData, seriesModel, api) {\n    var coordSys = seriesModel.coordinateSystem;\n    mpData.each(function (idx) {\n        var itemModel = mpData.getItemModel(idx);\n        var point;\n        var xPx = parsePercent$1(itemModel.get('x'), api.getWidth());\n        var yPx = parsePercent$1(itemModel.get('y'), api.getHeight());\n        if (!isNaN(xPx) && !isNaN(yPx)) {\n            point = [xPx, yPx];\n        }\n        // Chart like bar may have there own marker positioning logic\n        else if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                mpData.getValues(mpData.dimensions, idx)\n            );\n        }\n        else if (coordSys) {\n            var x = mpData.get(coordSys.dimensions[0], idx);\n            var y = mpData.get(coordSys.dimensions[1], idx);\n            point = coordSys.dataToPoint([x, y]);\n\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n\n        mpData.setItemLayout(idx, point);\n    });\n}\n\nMarkerView.extend({\n\n    type: 'markPoint',\n\n    // updateLayout: function (markPointModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var mpModel = seriesModel.markPointModel;\n    //         if (mpModel) {\n    //             updateMarkerLayout(mpModel.getData(), seriesModel, api);\n    //             this.markerGroupMap.get(seriesModel.id).updateLayout(mpModel);\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markPointModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var mpModel = seriesModel.markPointModel;\n            if (mpModel) {\n                updateMarkerLayout(mpModel.getData(), seriesModel, api);\n                this.markerGroupMap.get(seriesModel.id).updateLayout(mpModel);\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, mpModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var symbolDrawMap = this.markerGroupMap;\n        var symbolDraw = symbolDrawMap.get(seriesId)\n            || symbolDrawMap.set(seriesId, new SymbolDraw());\n\n        var mpData = createList$1(coordSys, seriesModel, mpModel);\n\n        // FIXME\n        mpModel.setData(mpData);\n\n        updateMarkerLayout(mpModel.getData(), seriesModel, api);\n\n        mpData.each(function (idx) {\n            var itemModel = mpData.getItemModel(idx);\n            var symbolSize = itemModel.getShallow('symbolSize');\n            if (typeof symbolSize === 'function') {\n                // FIXME 这里不兼容 ECharts 2.x，2.x 貌似参数是整个数据？\n                symbolSize = symbolSize(\n                    mpModel.getRawValue(idx), mpModel.getDataParams(idx)\n                );\n            }\n            mpData.setItemVisual(idx, {\n                symbolSize: symbolSize,\n                color: itemModel.get('itemStyle.color')\n                    || seriesData.getVisual('color'),\n                symbol: itemModel.getShallow('symbol')\n            });\n        });\n\n        // TODO Text are wrong\n        symbolDraw.updateData(mpData);\n        this.group.add(symbolDraw.group);\n\n        // Set host model for tooltip\n        // FIXME\n        mpData.eachItemGraphicEl(function (el) {\n            el.traverse(function (child) {\n                child.dataModel = mpModel;\n            });\n        });\n\n        symbolDraw.__keep = true;\n\n        symbolDraw.group.silent = mpModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} [coordSys]\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$1(coordSys, seriesModel, mpModel) {\n    var coordDimsInfos;\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var info = seriesModel.getData().getDimensionInfo(\n                seriesModel.getData().mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n    }\n\n    var mpData = new List(coordDimsInfos, mpModel);\n    var dataOpt = map(mpModel.get('data'), curry(\n            dataTransform, seriesModel\n        ));\n    if (coordSys) {\n        dataOpt = filter(\n            dataOpt, curry(dataFilter$1, coordSys)\n        );\n    }\n\n    mpData.initData(dataOpt, null,\n        coordSys ? dimValueGetter : function (item) {\n            return item.value;\n        }\n    );\n\n    return mpData;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// HINT Markpoint can't be used too much\nregisterPreprocessor(function (opt) {\n    // Make sure markPoint component is enabled\n    opt.markPoint = opt.markPoint || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markLine',\n\n    defaultOption: {\n        zlevel: 0,\n        z: 5,\n\n        symbol: ['circle', 'arrow'],\n        symbolSize: [8, 16],\n\n        //symbolRotate: 0,\n\n        precision: 2,\n        tooltip: {\n            trigger: 'item'\n        },\n        label: {\n            show: true,\n            position: 'end'\n        },\n        lineStyle: {\n            type: 'dashed'\n        },\n        emphasis: {\n            label: {\n                show: true\n            },\n            lineStyle: {\n                width: 3\n            }\n        },\n        animationEasing: 'linear'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar markLineTransform = function (seriesModel, coordSys, mlModel, item) {\n    var data = seriesModel.getData();\n    // Special type markLine like 'min', 'max', 'average', 'median'\n    var mlType = item.type;\n\n    if (!isArray(item)\n        && (\n            mlType === 'min' || mlType === 'max' || mlType === 'average' || mlType === 'median'\n            // In case\n            // data: [{\n            //   yAxis: 10\n            // }]\n            || (item.xAxis != null || item.yAxis != null)\n        )\n    ) {\n        var valueAxis;\n        var valueDataDim;\n        var value;\n\n        if (item.yAxis != null || item.xAxis != null) {\n            valueDataDim = item.yAxis != null ? 'y' : 'x';\n            valueAxis = coordSys.getAxis(valueDataDim);\n\n            value = retrieve(item.yAxis, item.xAxis);\n        }\n        else {\n            var axisInfo = getAxisInfo$1(item, data, coordSys, seriesModel);\n            valueDataDim = axisInfo.valueDataDim;\n            valueAxis = axisInfo.valueAxis;\n            value = numCalculate(data, valueDataDim, mlType);\n        }\n        var valueIndex = valueDataDim === 'x' ? 0 : 1;\n        var baseIndex = 1 - valueIndex;\n\n        var mlFrom = clone(item);\n        var mlTo = {};\n\n        mlFrom.type = null;\n\n        mlFrom.coord = [];\n        mlTo.coord = [];\n        mlFrom.coord[baseIndex] = -Infinity;\n        mlTo.coord[baseIndex] = Infinity;\n\n        var precision = mlModel.get('precision');\n        if (precision >= 0 && typeof value === 'number') {\n            value = +value.toFixed(Math.min(precision, 20));\n        }\n\n        mlFrom.coord[valueIndex] = mlTo.coord[valueIndex] = value;\n\n        item = [mlFrom, mlTo, { // Extra option for tooltip and label\n            type: mlType,\n            valueIndex: item.valueIndex,\n            // Force to use the value of calculated value.\n            value: value\n        }];\n    }\n\n    item = [\n        dataTransform(seriesModel, item[0]),\n        dataTransform(seriesModel, item[1]),\n        extend({}, item[2])\n    ];\n\n    // Avoid line data type is extended by from(to) data type\n    item[2].type = item[2].type || '';\n\n    // Merge from option and to option into line option\n    merge(item[2], item[0]);\n    merge(item[2], item[1]);\n\n    return item;\n};\n\nfunction isInifinity(val) {\n    return !isNaN(val) && !isFinite(val);\n}\n\n// If a markLine has one dim\nfunction ifMarkLineHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) {\n    var otherDimIndex = 1 - dimIndex;\n    var dimName = coordSys.dimensions[dimIndex];\n    return isInifinity(fromCoord[otherDimIndex]) && isInifinity(toCoord[otherDimIndex])\n        && fromCoord[dimIndex] === toCoord[dimIndex] && coordSys.getAxis(dimName).containData(fromCoord[dimIndex]);\n}\n\nfunction markLineFilter(coordSys, item) {\n    if (coordSys.type === 'cartesian2d') {\n        var fromCoord = item[0].coord;\n        var toCoord = item[1].coord;\n        // In case\n        // {\n        //  markLine: {\n        //    data: [{ yAxis: 2 }]\n        //  }\n        // }\n        if (\n            fromCoord && toCoord\n            && (ifMarkLineHasOnlyDim(1, fromCoord, toCoord, coordSys)\n            || ifMarkLineHasOnlyDim(0, fromCoord, toCoord, coordSys))\n        ) {\n            return true;\n        }\n    }\n    return dataFilter$1(coordSys, item[0])\n        && dataFilter$1(coordSys, item[1]);\n}\n\nfunction updateSingleMarkerEndLayout(\n    data, idx, isFrom, seriesModel, api\n) {\n    var coordSys = seriesModel.coordinateSystem;\n    var itemModel = data.getItemModel(idx);\n\n    var point;\n    var xPx = parsePercent$1(itemModel.get('x'), api.getWidth());\n    var yPx = parsePercent$1(itemModel.get('y'), api.getHeight());\n    if (!isNaN(xPx) && !isNaN(yPx)) {\n        point = [xPx, yPx];\n    }\n    else {\n        // Chart like bar may have there own marker positioning logic\n        if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                data.getValues(data.dimensions, idx)\n            );\n        }\n        else {\n            var dims = coordSys.dimensions;\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            point = coordSys.dataToPoint([x, y]);\n        }\n        // Expand line to the edge of grid if value on one axis is Inifnity\n        // In case\n        //  markLine: {\n        //    data: [{\n        //      yAxis: 2\n        //      // or\n        //      type: 'average'\n        //    }]\n        //  }\n        if (coordSys.type === 'cartesian2d') {\n            var xAxis = coordSys.getAxis('x');\n            var yAxis = coordSys.getAxis('y');\n            var dims = coordSys.dimensions;\n            if (isInifinity(data.get(dims[0], idx))) {\n                point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[isFrom ? 0 : 1]);\n            }\n            else if (isInifinity(data.get(dims[1], idx))) {\n                point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[isFrom ? 0 : 1]);\n            }\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n    }\n\n    data.setItemLayout(idx, point);\n}\n\nMarkerView.extend({\n\n    type: 'markLine',\n\n    // updateLayout: function (markLineModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var mlModel = seriesModel.markLineModel;\n    //         if (mlModel) {\n    //             var mlData = mlModel.getData();\n    //             var fromData = mlModel.__from;\n    //             var toData = mlModel.__to;\n    //             // Update visual and layout of from symbol and to symbol\n    //             fromData.each(function (idx) {\n    //                 updateSingleMarkerEndLayout(fromData, idx, true, seriesModel, api);\n    //                 updateSingleMarkerEndLayout(toData, idx, false, seriesModel, api);\n    //             });\n    //             // Update layout of line\n    //             mlData.each(function (idx) {\n    //                 mlData.setItemLayout(idx, [\n    //                     fromData.getItemLayout(idx),\n    //                     toData.getItemLayout(idx)\n    //                 ]);\n    //             });\n\n    //             this.markerGroupMap.get(seriesModel.id).updateLayout();\n\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markLineModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var mlModel = seriesModel.markLineModel;\n            if (mlModel) {\n                var mlData = mlModel.getData();\n                var fromData = mlModel.__from;\n                var toData = mlModel.__to;\n                // Update visual and layout of from symbol and to symbol\n                fromData.each(function (idx) {\n                    updateSingleMarkerEndLayout(fromData, idx, true, seriesModel, api);\n                    updateSingleMarkerEndLayout(toData, idx, false, seriesModel, api);\n                });\n                // Update layout of line\n                mlData.each(function (idx) {\n                    mlData.setItemLayout(idx, [\n                        fromData.getItemLayout(idx),\n                        toData.getItemLayout(idx)\n                    ]);\n                });\n\n                this.markerGroupMap.get(seriesModel.id).updateLayout();\n\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, mlModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var lineDrawMap = this.markerGroupMap;\n        var lineDraw = lineDrawMap.get(seriesId)\n            || lineDrawMap.set(seriesId, new LineDraw());\n        this.group.add(lineDraw.group);\n\n        var mlData = createList$2(coordSys, seriesModel, mlModel);\n\n        var fromData = mlData.from;\n        var toData = mlData.to;\n        var lineData = mlData.line;\n\n        mlModel.__from = fromData;\n        mlModel.__to = toData;\n        // Line data for tooltip and formatter\n        mlModel.setData(lineData);\n\n        var symbolType = mlModel.get('symbol');\n        var symbolSize = mlModel.get('symbolSize');\n        if (!isArray(symbolType)) {\n            symbolType = [symbolType, symbolType];\n        }\n        if (typeof symbolSize === 'number') {\n            symbolSize = [symbolSize, symbolSize];\n        }\n\n        // Update visual and layout of from symbol and to symbol\n        mlData.from.each(function (idx) {\n            updateDataVisualAndLayout(fromData, idx, true);\n            updateDataVisualAndLayout(toData, idx, false);\n        });\n\n        // Update visual and layout of line\n        lineData.each(function (idx) {\n            var lineColor = lineData.getItemModel(idx).get('lineStyle.color');\n            lineData.setItemVisual(idx, {\n                color: lineColor || fromData.getItemVisual(idx, 'color')\n            });\n            lineData.setItemLayout(idx, [\n                fromData.getItemLayout(idx),\n                toData.getItemLayout(idx)\n            ]);\n\n            lineData.setItemVisual(idx, {\n                'fromSymbolSize': fromData.getItemVisual(idx, 'symbolSize'),\n                'fromSymbol': fromData.getItemVisual(idx, 'symbol'),\n                'toSymbolSize': toData.getItemVisual(idx, 'symbolSize'),\n                'toSymbol': toData.getItemVisual(idx, 'symbol')\n            });\n        });\n\n        lineDraw.updateData(lineData);\n\n        // Set host model for tooltip\n        // FIXME\n        mlData.line.eachItemGraphicEl(function (el, idx) {\n            el.traverse(function (child) {\n                child.dataModel = mlModel;\n            });\n        });\n\n        function updateDataVisualAndLayout(data, idx, isFrom) {\n            var itemModel = data.getItemModel(idx);\n\n            updateSingleMarkerEndLayout(\n                data, idx, isFrom, seriesModel, api\n            );\n\n            data.setItemVisual(idx, {\n                symbolSize: itemModel.get('symbolSize') || symbolSize[isFrom ? 0 : 1],\n                symbol: itemModel.get('symbol', true) || symbolType[isFrom ? 0 : 1],\n                color: itemModel.get('itemStyle.color') || seriesData.getVisual('color')\n            });\n        }\n\n        lineDraw.__keep = true;\n\n        lineDraw.group.silent = mlModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} coordSys\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$2(coordSys, seriesModel, mlModel) {\n\n    var coordDimsInfos;\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var info = seriesModel.getData().getDimensionInfo(\n                seriesModel.getData().mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n    }\n\n    var fromData = new List(coordDimsInfos, mlModel);\n    var toData = new List(coordDimsInfos, mlModel);\n    // No dimensions\n    var lineData = new List([], mlModel);\n\n    var optData = map(mlModel.get('data'), curry(\n        markLineTransform, seriesModel, coordSys, mlModel\n    ));\n    if (coordSys) {\n        optData = filter(\n            optData, curry(markLineFilter, coordSys)\n        );\n    }\n    var dimValueGetter$$1 = coordSys ? dimValueGetter : function (item) {\n        return item.value;\n    };\n    fromData.initData(\n        map(optData, function (item) {\n            return item[0];\n        }),\n        null,\n        dimValueGetter$$1\n    );\n    toData.initData(\n        map(optData, function (item) {\n            return item[1];\n        }),\n        null,\n        dimValueGetter$$1\n    );\n    lineData.initData(\n        map(optData, function (item) {\n            return item[2];\n        })\n    );\n    lineData.hasItemOption = true;\n\n    return {\n        from: fromData,\n        to: toData,\n        line: lineData\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterPreprocessor(function (opt) {\n    // Make sure markLine component is enabled\n    opt.markLine = opt.markLine || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markArea',\n\n    defaultOption: {\n        zlevel: 0,\n        // PENDING\n        z: 1,\n        tooltip: {\n            trigger: 'item'\n        },\n        // markArea should fixed on the coordinate system\n        animation: false,\n        label: {\n            show: true,\n            position: 'top'\n        },\n        itemStyle: {\n            // color and borderColor default to use color from series\n            // color: 'auto'\n            // borderColor: 'auto'\n            borderWidth: 0\n        },\n\n        emphasis: {\n            label: {\n                show: true,\n                position: 'top'\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Better on polar\n\nvar markAreaTransform = function (seriesModel, coordSys, maModel, item) {\n    var lt = dataTransform(seriesModel, item[0]);\n    var rb = dataTransform(seriesModel, item[1]);\n    var retrieve$$1 = retrieve;\n\n    // FIXME make sure lt is less than rb\n    var ltCoord = lt.coord;\n    var rbCoord = rb.coord;\n    ltCoord[0] = retrieve$$1(ltCoord[0], -Infinity);\n    ltCoord[1] = retrieve$$1(ltCoord[1], -Infinity);\n\n    rbCoord[0] = retrieve$$1(rbCoord[0], Infinity);\n    rbCoord[1] = retrieve$$1(rbCoord[1], Infinity);\n\n    // Merge option into one\n    var result = mergeAll([{}, lt, rb]);\n\n    result.coord = [\n        lt.coord, rb.coord\n    ];\n    result.x0 = lt.x;\n    result.y0 = lt.y;\n    result.x1 = rb.x;\n    result.y1 = rb.y;\n    return result;\n};\n\nfunction isInifinity$1(val) {\n    return !isNaN(val) && !isFinite(val);\n}\n\n// If a markArea has one dim\nfunction ifMarkLineHasOnlyDim$1(dimIndex, fromCoord, toCoord, coordSys) {\n    var otherDimIndex = 1 - dimIndex;\n    return isInifinity$1(fromCoord[otherDimIndex]) && isInifinity$1(toCoord[otherDimIndex]);\n}\n\nfunction markAreaFilter(coordSys, item) {\n    var fromCoord = item.coord[0];\n    var toCoord = item.coord[1];\n    if (coordSys.type === 'cartesian2d') {\n        // In case\n        // {\n        //  markArea: {\n        //    data: [{ yAxis: 2 }]\n        //  }\n        // }\n        if (\n            fromCoord && toCoord\n            && (ifMarkLineHasOnlyDim$1(1, fromCoord, toCoord, coordSys)\n            || ifMarkLineHasOnlyDim$1(0, fromCoord, toCoord, coordSys))\n        ) {\n            return true;\n        }\n    }\n    return dataFilter$1(coordSys, {\n            coord: fromCoord,\n            x: item.x0,\n            y: item.y0\n        })\n        || dataFilter$1(coordSys, {\n            coord: toCoord,\n            x: item.x1,\n            y: item.y1\n        });\n}\n\n// dims can be ['x0', 'y0'], ['x1', 'y1'], ['x0', 'y1'], ['x1', 'y0']\nfunction getSingleMarkerEndPoint(data, idx, dims, seriesModel, api) {\n    var coordSys = seriesModel.coordinateSystem;\n    var itemModel = data.getItemModel(idx);\n\n    var point;\n    var xPx = parsePercent$1(itemModel.get(dims[0]), api.getWidth());\n    var yPx = parsePercent$1(itemModel.get(dims[1]), api.getHeight());\n    if (!isNaN(xPx) && !isNaN(yPx)) {\n        point = [xPx, yPx];\n    }\n    else {\n        // Chart like bar may have there own marker positioning logic\n        if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                data.getValues(dims, idx)\n            );\n        }\n        else {\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            var pt = [x, y];\n            coordSys.clampData && coordSys.clampData(pt, pt);\n            point = coordSys.dataToPoint(pt, true);\n        }\n        if (coordSys.type === 'cartesian2d') {\n            var xAxis = coordSys.getAxis('x');\n            var yAxis = coordSys.getAxis('y');\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            if (isInifinity$1(x)) {\n                point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[dims[0] === 'x0' ? 0 : 1]);\n            }\n            else if (isInifinity$1(y)) {\n                point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[dims[1] === 'y0' ? 0 : 1]);\n            }\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n    }\n\n    return point;\n}\n\nvar dimPermutations = [['x0', 'y0'], ['x1', 'y0'], ['x1', 'y1'], ['x0', 'y1']];\n\nMarkerView.extend({\n\n    type: 'markArea',\n\n    // updateLayout: function (markAreaModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var maModel = seriesModel.markAreaModel;\n    //         if (maModel) {\n    //             var areaData = maModel.getData();\n    //             areaData.each(function (idx) {\n    //                 var points = zrUtil.map(dimPermutations, function (dim) {\n    //                     return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n    //                 });\n    //                 // Layout\n    //                 areaData.setItemLayout(idx, points);\n    //                 var el = areaData.getItemGraphicEl(idx);\n    //                 el.setShape('points', points);\n    //             });\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markAreaModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var maModel = seriesModel.markAreaModel;\n            if (maModel) {\n                var areaData = maModel.getData();\n                areaData.each(function (idx) {\n                    var points = map(dimPermutations, function (dim) {\n                        return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n                    });\n                    // Layout\n                    areaData.setItemLayout(idx, points);\n                    var el = areaData.getItemGraphicEl(idx);\n                    el.setShape('points', points);\n                });\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, maModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var areaGroupMap = this.markerGroupMap;\n        var polygonGroup = areaGroupMap.get(seriesId)\n            || areaGroupMap.set(seriesId, {group: new Group()});\n\n        this.group.add(polygonGroup.group);\n        polygonGroup.__keep = true;\n\n        var areaData = createList$3(coordSys, seriesModel, maModel);\n\n        // Line data for tooltip and formatter\n        maModel.setData(areaData);\n\n        // Update visual and layout of line\n        areaData.each(function (idx) {\n            // Layout\n            areaData.setItemLayout(idx, map(dimPermutations, function (dim) {\n                return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n            }));\n\n            // Visual\n            areaData.setItemVisual(idx, {\n                color: seriesData.getVisual('color')\n            });\n        });\n\n\n        areaData.diff(polygonGroup.__data)\n            .add(function (idx) {\n                var polygon = new Polygon({\n                    shape: {\n                        points: areaData.getItemLayout(idx)\n                    }\n                });\n                areaData.setItemGraphicEl(idx, polygon);\n                polygonGroup.group.add(polygon);\n            })\n            .update(function (newIdx, oldIdx) {\n                var polygon = polygonGroup.__data.getItemGraphicEl(oldIdx);\n                updateProps(polygon, {\n                    shape: {\n                        points: areaData.getItemLayout(newIdx)\n                    }\n                }, maModel, newIdx);\n                polygonGroup.group.add(polygon);\n                areaData.setItemGraphicEl(newIdx, polygon);\n            })\n            .remove(function (idx) {\n                var polygon = polygonGroup.__data.getItemGraphicEl(idx);\n                polygonGroup.group.remove(polygon);\n            })\n            .execute();\n\n        areaData.eachItemGraphicEl(function (polygon, idx) {\n            var itemModel = areaData.getItemModel(idx);\n            var labelModel = itemModel.getModel('label');\n            var labelHoverModel = itemModel.getModel('emphasis.label');\n            var color = areaData.getItemVisual(idx, 'color');\n            polygon.useStyle(\n                defaults(\n                    itemModel.getModel('itemStyle').getItemStyle(),\n                    {\n                        fill: modifyAlpha(color, 0.4),\n                        stroke: color\n                    }\n                )\n            );\n\n            polygon.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n\n            setLabelStyle(\n                polygon.style, polygon.hoverStyle, labelModel, labelHoverModel,\n                {\n                    labelFetcher: maModel,\n                    labelDataIndex: idx,\n                    defaultText: areaData.getName(idx) || '',\n                    isRectText: true,\n                    autoColor: color\n                }\n            );\n\n            setHoverStyle(polygon, {});\n\n            polygon.dataModel = maModel;\n        });\n\n        polygonGroup.__data = areaData;\n\n        polygonGroup.group.silent = maModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} coordSys\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$3(coordSys, seriesModel, maModel) {\n\n    var coordDimsInfos;\n    var areaData;\n    var dims = ['x0', 'y0', 'x1', 'y1'];\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var data = seriesModel.getData();\n            var info = data.getDimensionInfo(\n                data.mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n        areaData = new List(map(dims, function (dim, idx) {\n            return {\n                name: dim,\n                type: coordDimsInfos[idx % 2].type\n            };\n        }), maModel);\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n        areaData = new List(coordDimsInfos, maModel);\n    }\n\n    var optData = map(maModel.get('data'), curry(\n        markAreaTransform, seriesModel, coordSys, maModel\n    ));\n    if (coordSys) {\n        optData = filter(\n            optData, curry(markAreaFilter, coordSys)\n        );\n    }\n\n    var dimValueGetter$$1 = coordSys ? function (item, dimName, dataIndex, dimIndex) {\n        return item.coord[Math.floor(dimIndex / 2)][dimIndex % 2];\n    } : function (item) {\n        return item.value;\n    };\n    areaData.initData(optData, null, dimValueGetter$$1);\n    areaData.hasItemOption = true;\n    return areaData;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterPreprocessor(function (opt) {\n    // Make sure markArea component is enabled\n    opt.markArea = opt.markArea || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar preprocessor$3 = function (option) {\n    var timelineOpt = option && option.timeline;\n\n    if (!isArray(timelineOpt)) {\n        timelineOpt = timelineOpt ? [timelineOpt] : [];\n    }\n\n    each$1(timelineOpt, function (opt) {\n        if (!opt) {\n            return;\n        }\n\n        compatibleEC2(opt);\n    });\n};\n\nfunction compatibleEC2(opt) {\n    var type = opt.type;\n\n    var ec2Types = {'number': 'value', 'time': 'time'};\n\n    // Compatible with ec2\n    if (ec2Types[type]) {\n        opt.axisType = ec2Types[type];\n        delete opt.type;\n    }\n\n    transferItem(opt);\n\n    if (has$2(opt, 'controlPosition')) {\n        var controlStyle = opt.controlStyle || (opt.controlStyle = {});\n        if (!has$2(controlStyle, 'position')) {\n            controlStyle.position = opt.controlPosition;\n        }\n        if (controlStyle.position === 'none' && !has$2(controlStyle, 'show')) {\n            controlStyle.show = false;\n            delete controlStyle.position;\n        }\n        delete opt.controlPosition;\n    }\n\n    each$1(opt.data || [], function (dataItem) {\n        if (isObject$1(dataItem) && !isArray(dataItem)) {\n            if (!has$2(dataItem, 'value') && has$2(dataItem, 'name')) {\n                // In ec2, using name as value.\n                dataItem.value = dataItem.name;\n            }\n            transferItem(dataItem);\n        }\n    });\n}\n\nfunction transferItem(opt) {\n    var itemStyle = opt.itemStyle || (opt.itemStyle = {});\n\n    var itemStyleEmphasis = itemStyle.emphasis || (itemStyle.emphasis = {});\n\n    // Transfer label out\n    var label = opt.label || (opt.label || {});\n    var labelNormal = label.normal || (label.normal = {});\n    var excludeLabelAttr = {normal: 1, emphasis: 1};\n\n    each$1(label, function (value, name) {\n        if (!excludeLabelAttr[name] && !has$2(labelNormal, name)) {\n            labelNormal[name] = value;\n        }\n    });\n\n    if (itemStyleEmphasis.label && !has$2(label, 'emphasis')) {\n        label.emphasis = itemStyleEmphasis.label;\n        delete itemStyleEmphasis.label;\n    }\n}\n\nfunction has$2(obj, attr) {\n    return obj.hasOwnProperty(attr);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nComponentModel.registerSubTypeDefaulter('timeline', function () {\n    // Only slider now.\n    return 'slider';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterAction(\n\n    {type: 'timelineChange', event: 'timelineChanged', update: 'prepareAndUpdate'},\n\n    function (payload, ecModel) {\n\n        var timelineModel = ecModel.getComponent('timeline');\n        if (timelineModel && payload.currentIndex != null) {\n            timelineModel.setCurrentIndex(payload.currentIndex);\n\n            if (!timelineModel.get('loop', true) && timelineModel.isIndexMax()) {\n                timelineModel.setPlayState(false);\n            }\n        }\n\n        // Set normalized currentIndex to payload.\n        ecModel.resetOption('timeline');\n\n        return defaults({\n            currentIndex: timelineModel.option.currentIndex\n        }, payload);\n    }\n);\n\nregisterAction(\n\n    {type: 'timelinePlayChange', event: 'timelinePlayChanged', update: 'update'},\n\n    function (payload, ecModel) {\n        var timelineModel = ecModel.getComponent('timeline');\n        if (timelineModel && payload.playState != null) {\n            timelineModel.setPlayState(payload.playState);\n        }\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TimelineModel = ComponentModel.extend({\n\n    type: 'timeline',\n\n    layoutMode: 'box',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n\n        zlevel: 0,                  // 一级层叠\n        z: 4,                       // 二级层叠\n        show: true,\n\n        axisType: 'time',  // 模式是时间类型，支持 value, category\n\n        realtime: true,\n\n        left: '20%',\n        top: null,\n        right: '20%',\n        bottom: 0,\n        width: null,\n        height: 40,\n        padding: 5,\n\n        controlPosition: 'left',           // 'left' 'right' 'top' 'bottom' 'none'\n        autoPlay: false,\n        rewind: false,                     // 反向播放\n        loop: true,\n        playInterval: 2000,                // 播放时间间隔，单位ms\n\n        currentIndex: 0,\n\n        itemStyle: {},\n        label: {\n            color: '#000'\n        },\n\n        data: []\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel) {\n\n        /**\n         * @private\n         * @type {module:echarts/data/List}\n         */\n        this._data;\n\n        /**\n         * @private\n         * @type {Array.<string>}\n         */\n        this._names;\n\n        this.mergeDefaultAndTheme(option, ecModel);\n        this._initData();\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (option) {\n        TimelineModel.superApply(this, 'mergeOption', arguments);\n        this._initData();\n    },\n\n    /**\n     * @param {number} [currentIndex]\n     */\n    setCurrentIndex: function (currentIndex) {\n        if (currentIndex == null) {\n            currentIndex = this.option.currentIndex;\n        }\n        var count = this._data.count();\n\n        if (this.option.loop) {\n            currentIndex = (currentIndex % count + count) % count;\n        }\n        else {\n            currentIndex >= count && (currentIndex = count - 1);\n            currentIndex < 0 && (currentIndex = 0);\n        }\n\n        this.option.currentIndex = currentIndex;\n    },\n\n    /**\n     * @return {number} currentIndex\n     */\n    getCurrentIndex: function () {\n        return this.option.currentIndex;\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isIndexMax: function () {\n        return this.getCurrentIndex() >= this._data.count() - 1;\n    },\n\n    /**\n     * @param {boolean} state true: play, false: stop\n     */\n    setPlayState: function (state) {\n        this.option.autoPlay = !!state;\n    },\n\n    /**\n     * @return {boolean} true: play, false: stop\n     */\n    getPlayState: function () {\n        return !!this.option.autoPlay;\n    },\n\n    /**\n     * @private\n     */\n    _initData: function () {\n        var thisOption = this.option;\n        var dataArr = thisOption.data || [];\n        var axisType = thisOption.axisType;\n        var names = this._names = [];\n\n        if (axisType === 'category') {\n            var idxArr = [];\n            each$1(dataArr, function (item, index) {\n                var value = getDataItemValue(item);\n                var newItem;\n\n                if (isObject$1(item)) {\n                    newItem = clone(item);\n                    newItem.value = index;\n                }\n                else {\n                    newItem = index;\n                }\n\n                idxArr.push(newItem);\n\n                if (!isString(value) && (value == null || isNaN(value))) {\n                    value = '';\n                }\n\n                names.push(value + '');\n            });\n            dataArr = idxArr;\n        }\n\n        var dimType = ({category: 'ordinal', time: 'time'})[axisType] || 'number';\n\n        var data = this._data = new List([{name: 'value', type: dimType}], this);\n\n        data.initData(dataArr, names);\n    },\n\n    getData: function () {\n        return this._data;\n    },\n\n    /**\n     * @public\n     * @return {Array.<string>} categoreis\n     */\n    getCategories: function () {\n        if (this.get('axisType') === 'category') {\n            return this._names.slice();\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar SliderTimelineModel = TimelineModel.extend({\n\n    type: 'timeline.slider',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n\n        backgroundColor: 'rgba(0,0,0,0)',   // 时间轴背景颜色\n        borderColor: '#ccc',               // 时间轴边框颜色\n        borderWidth: 0,                    // 时间轴边框线宽，单位px，默认为0（无边框）\n\n        orient: 'horizontal',              // 'vertical'\n        inverse: false,\n\n        tooltip: {                          // boolean or Object\n            trigger: 'item'                 // data item may also have tootip attr.\n        },\n\n        symbol: 'emptyCircle',\n        symbolSize: 10,\n\n        lineStyle: {\n            show: true,\n            width: 2,\n            color: '#304654'\n        },\n        label: {                            // 文本标签\n            position: 'auto',           // auto left right top bottom\n                                        // When using number, label position is not\n                                        // restricted by viewRect.\n                                        // positive: right/bottom, negative: left/top\n            show: true,\n            interval: 'auto',\n            rotate: 0,\n            // formatter: null,\n            // 其余属性默认使用全局文本样式，详见TEXTSTYLE\n            color: '#304654'\n        },\n        itemStyle: {\n            color: '#304654',\n            borderWidth: 1\n        },\n\n        checkpointStyle: {\n            symbol: 'circle',\n            symbolSize: 13,\n            color: '#c23531',\n            borderWidth: 5,\n            borderColor: 'rgba(194,53,49, 0.5)',\n            animation: true,\n            animationDuration: 300,\n            animationEasing: 'quinticInOut'\n        },\n\n        controlStyle: {\n            show: true,\n            showPlayBtn: true,\n            showPrevBtn: true,\n            showNextBtn: true,\n            itemSize: 22,\n            itemGap: 12,\n            position: 'left',  // 'left' 'right' 'top' 'bottom'\n            playIcon: 'path://M31.6,53C17.5,53,6,41.5,6,27.4S17.5,1.8,31.6,1.8C45.7,1.8,57.2,13.3,57.2,27.4S45.7,53,31.6,53z M31.6,3.3 C18.4,3.3,7.5,14.1,7.5,27.4c0,13.3,10.8,24.1,24.1,24.1C44.9,51.5,55.7,40.7,55.7,27.4C55.7,14.1,44.9,3.3,31.6,3.3z M24.9,21.3 c0-2.2,1.6-3.1,3.5-2l10.5,6.1c1.899,1.1,1.899,2.9,0,4l-10.5,6.1c-1.9,1.1-3.5,0.2-3.5-2V21.3z', // jshint ignore:line\n            stopIcon: 'path://M30.9,53.2C16.8,53.2,5.3,41.7,5.3,27.6S16.8,2,30.9,2C45,2,56.4,13.5,56.4,27.6S45,53.2,30.9,53.2z M30.9,3.5C17.6,3.5,6.8,14.4,6.8,27.6c0,13.3,10.8,24.1,24.101,24.1C44.2,51.7,55,40.9,55,27.6C54.9,14.4,44.1,3.5,30.9,3.5z M36.9,35.8c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H36c0.5,0,0.9,0.4,0.9,1V35.8z M27.8,35.8 c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H27c0.5,0,0.9,0.4,0.9,1L27.8,35.8L27.8,35.8z', // jshint ignore:line\n            nextIcon: 'path://M18.6,50.8l22.5-22.5c0.2-0.2,0.3-0.4,0.3-0.7c0-0.3-0.1-0.5-0.3-0.7L18.7,4.4c-0.1-0.1-0.2-0.3-0.2-0.5 c0-0.4,0.3-0.8,0.8-0.8c0.2,0,0.5,0.1,0.6,0.3l23.5,23.5l0,0c0.2,0.2,0.3,0.4,0.3,0.7c0,0.3-0.1,0.5-0.3,0.7l-0.1,0.1L19.7,52 c-0.1,0.1-0.3,0.2-0.5,0.2c-0.4,0-0.8-0.3-0.8-0.8C18.4,51.2,18.5,51,18.6,50.8z', // jshint ignore:line\n            prevIcon: 'path://M43,52.8L20.4,30.3c-0.2-0.2-0.3-0.4-0.3-0.7c0-0.3,0.1-0.5,0.3-0.7L42.9,6.4c0.1-0.1,0.2-0.3,0.2-0.5 c0-0.4-0.3-0.8-0.8-0.8c-0.2,0-0.5,0.1-0.6,0.3L18.3,28.8l0,0c-0.2,0.2-0.3,0.4-0.3,0.7c0,0.3,0.1,0.5,0.3,0.7l0.1,0.1L41.9,54 c0.1,0.1,0.3,0.2,0.5,0.2c0.4,0,0.8-0.3,0.8-0.8C43.2,53.2,43.1,53,43,52.8z', // jshint ignore:line\n\n            color: '#304654',\n            borderColor: '#304654',\n            borderWidth: 1\n        },\n\n        emphasis: {\n            label: {\n                show: true,\n                // 其余属性默认使用全局文本样式，详见TEXTSTYLE\n                color: '#c23531'\n            },\n\n            itemStyle: {\n                color: '#c23531'\n            },\n\n            controlStyle: {\n                color: '#c23531',\n                borderColor: '#c23531',\n                borderWidth: 2\n            }\n        },\n        data: []\n    }\n\n});\n\nmixin(SliderTimelineModel, dataFormatMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TimelineView = Component.extend({\n    type: 'timeline'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Extend axis 2d\n * @constructor module:echarts/coord/cartesian/Axis2D\n * @extends {module:echarts/coord/cartesian/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n * @param {string} position\n */\nvar TimelineAxis = function (dim, scale, coordExtent, axisType) {\n\n    Axis.call(this, dim, scale, coordExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * Axis model\n     * @param {module:echarts/component/TimelineModel}\n     */\n    this.model = null;\n};\n\nTimelineAxis.prototype = {\n\n    constructor: TimelineAxis,\n\n    /**\n     * @override\n     */\n    getLabelModel: function () {\n        return this.model.getModel('label');\n    },\n\n    /**\n     * @override\n     */\n    isHorizontal: function () {\n        return this.model.get('orient') === 'horizontal';\n    }\n\n};\n\ninherits(TimelineAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$6 = bind;\nvar each$27 = each$1;\n\nvar PI$4 = Math.PI;\n\nTimelineView.extend({\n\n    type: 'timeline.slider',\n\n    init: function (ecModel, api) {\n\n        this.api = api;\n\n        /**\n         * @private\n         * @type {module:echarts/component/timeline/TimelineAxis}\n         */\n        this._axis;\n\n        /**\n         * @private\n         * @type {module:zrender/core/BoundingRect}\n         */\n        this._viewRect;\n\n        /**\n         * @type {number}\n         */\n        this._timer;\n\n        /**\n         * @type {module:zrender/Element}\n         */\n        this._currentPointer;\n\n        /**\n         * @type {module:zrender/container/Group}\n         */\n        this._mainGroup;\n\n        /**\n         * @type {module:zrender/container/Group}\n         */\n        this._labelGroup;\n    },\n\n    /**\n     * @override\n     */\n    render: function (timelineModel, ecModel, api, payload) {\n        this.model = timelineModel;\n        this.api = api;\n        this.ecModel = ecModel;\n\n        this.group.removeAll();\n\n        if (timelineModel.get('show', true)) {\n\n            var layoutInfo = this._layout(timelineModel, api);\n            var mainGroup = this._createGroup('mainGroup');\n            var labelGroup = this._createGroup('labelGroup');\n\n            /**\n             * @private\n             * @type {module:echarts/component/timeline/TimelineAxis}\n             */\n            var axis = this._axis = this._createAxis(layoutInfo, timelineModel);\n\n            timelineModel.formatTooltip = function (dataIndex) {\n                return encodeHTML(axis.scale.getLabel(dataIndex));\n            };\n\n            each$27(\n                ['AxisLine', 'AxisTick', 'Control', 'CurrentPointer'],\n                function (name) {\n                    this['_render' + name](layoutInfo, mainGroup, axis, timelineModel);\n                },\n                this\n            );\n\n            this._renderAxisLabel(layoutInfo, labelGroup, axis, timelineModel);\n            this._position(layoutInfo, timelineModel);\n        }\n\n        this._doPlayStop();\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this._clearTimer();\n        this.group.removeAll();\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._clearTimer();\n    },\n\n    _layout: function (timelineModel, api) {\n        var labelPosOpt = timelineModel.get('label.position');\n        var orient = timelineModel.get('orient');\n        var viewRect = getViewRect$4(timelineModel, api);\n        // Auto label offset.\n        if (labelPosOpt == null || labelPosOpt === 'auto') {\n            labelPosOpt = orient === 'horizontal'\n                ? ((viewRect.y + viewRect.height / 2) < api.getHeight() / 2 ? '-' : '+')\n                : ((viewRect.x + viewRect.width / 2) < api.getWidth() / 2 ? '+' : '-');\n        }\n        else if (isNaN(labelPosOpt)) {\n            labelPosOpt = ({\n                horizontal: {top: '-', bottom: '+'},\n                vertical: {left: '-', right: '+'}\n            })[orient][labelPosOpt];\n        }\n\n        var labelAlignMap = {\n            horizontal: 'center',\n            vertical: (labelPosOpt >= 0 || labelPosOpt === '+') ? 'left' : 'right'\n        };\n\n        var labelBaselineMap = {\n            horizontal: (labelPosOpt >= 0 || labelPosOpt === '+') ? 'top' : 'bottom',\n            vertical: 'middle'\n        };\n        var rotationMap = {\n            horizontal: 0,\n            vertical: PI$4 / 2\n        };\n\n        // Position\n        var mainLength = orient === 'vertical' ? viewRect.height : viewRect.width;\n\n        var controlModel = timelineModel.getModel('controlStyle');\n        var showControl = controlModel.get('show', true);\n        var controlSize = showControl ? controlModel.get('itemSize') : 0;\n        var controlGap = showControl ? controlModel.get('itemGap') : 0;\n        var sizePlusGap = controlSize + controlGap;\n\n        // Special label rotate.\n        var labelRotation = timelineModel.get('label.rotate') || 0;\n        labelRotation = labelRotation * PI$4 / 180; // To radian.\n\n        var playPosition;\n        var prevBtnPosition;\n        var nextBtnPosition;\n        var axisExtent;\n        var controlPosition = controlModel.get('position', true);\n        var showPlayBtn = showControl && controlModel.get('showPlayBtn', true);\n        var showPrevBtn = showControl && controlModel.get('showPrevBtn', true);\n        var showNextBtn = showControl && controlModel.get('showNextBtn', true);\n        var xLeft = 0;\n        var xRight = mainLength;\n\n        // position[0] means left, position[1] means middle.\n        if (controlPosition === 'left' || controlPosition === 'bottom') {\n            showPlayBtn && (playPosition = [0, 0], xLeft += sizePlusGap);\n            showPrevBtn && (prevBtnPosition = [xLeft, 0], xLeft += sizePlusGap);\n            showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);\n        }\n        else { // 'top' 'right'\n            showPlayBtn && (playPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);\n            showPrevBtn && (prevBtnPosition = [0, 0], xLeft += sizePlusGap);\n            showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);\n        }\n        axisExtent = [xLeft, xRight];\n\n        if (timelineModel.get('inverse')) {\n            axisExtent.reverse();\n        }\n\n        return {\n            viewRect: viewRect,\n            mainLength: mainLength,\n            orient: orient,\n\n            rotation: rotationMap[orient],\n            labelRotation: labelRotation,\n            labelPosOpt: labelPosOpt,\n            labelAlign: timelineModel.get('label.align') || labelAlignMap[orient],\n            labelBaseline: timelineModel.get('label.verticalAlign')\n                || timelineModel.get('label.baseline')\n                || labelBaselineMap[orient],\n\n            // Based on mainGroup.\n            playPosition: playPosition,\n            prevBtnPosition: prevBtnPosition,\n            nextBtnPosition: nextBtnPosition,\n            axisExtent: axisExtent,\n\n            controlSize: controlSize,\n            controlGap: controlGap\n        };\n    },\n\n    _position: function (layoutInfo, timelineModel) {\n        // Position is be called finally, because bounding rect is needed for\n        // adapt content to fill viewRect (auto adapt offset).\n\n        // Timeline may be not all in the viewRect when 'offset' is specified\n        // as a number, because it is more appropriate that label aligns at\n        // 'offset' but not the other edge defined by viewRect.\n\n        var mainGroup = this._mainGroup;\n        var labelGroup = this._labelGroup;\n\n        var viewRect = layoutInfo.viewRect;\n        if (layoutInfo.orient === 'vertical') {\n            // transform to horizontal, inverse rotate by left-top point.\n            var m = create$1();\n            var rotateOriginX = viewRect.x;\n            var rotateOriginY = viewRect.y + viewRect.height;\n            translate(m, m, [-rotateOriginX, -rotateOriginY]);\n            rotate(m, m, -PI$4 / 2);\n            translate(m, m, [rotateOriginX, rotateOriginY]);\n            viewRect = viewRect.clone();\n            viewRect.applyTransform(m);\n        }\n\n        var viewBound = getBound(viewRect);\n        var mainBound = getBound(mainGroup.getBoundingRect());\n        var labelBound = getBound(labelGroup.getBoundingRect());\n\n        var mainPosition = mainGroup.position;\n        var labelsPosition = labelGroup.position;\n\n        labelsPosition[0] = mainPosition[0] = viewBound[0][0];\n\n        var labelPosOpt = layoutInfo.labelPosOpt;\n\n        if (isNaN(labelPosOpt)) { // '+' or '-'\n            var mainBoundIdx = labelPosOpt === '+' ? 0 : 1;\n            toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx);\n            toBound(labelsPosition, labelBound, viewBound, 1, 1 - mainBoundIdx);\n        }\n        else {\n            var mainBoundIdx = labelPosOpt >= 0 ? 0 : 1;\n            toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx);\n            labelsPosition[1] = mainPosition[1] + labelPosOpt;\n        }\n\n        mainGroup.attr('position', mainPosition);\n        labelGroup.attr('position', labelsPosition);\n        mainGroup.rotation = labelGroup.rotation = layoutInfo.rotation;\n\n        setOrigin(mainGroup);\n        setOrigin(labelGroup);\n\n        function setOrigin(targetGroup) {\n            var pos = targetGroup.position;\n            targetGroup.origin = [\n                viewBound[0][0] - pos[0],\n                viewBound[1][0] - pos[1]\n            ];\n        }\n\n        function getBound(rect) {\n            // [[xmin, xmax], [ymin, ymax]]\n            return [\n                [rect.x, rect.x + rect.width],\n                [rect.y, rect.y + rect.height]\n            ];\n        }\n\n        function toBound(fromPos, from, to, dimIdx, boundIdx) {\n            fromPos[dimIdx] += to[dimIdx][boundIdx] - from[dimIdx][boundIdx];\n        }\n    },\n\n    _createAxis: function (layoutInfo, timelineModel) {\n        var data = timelineModel.getData();\n        var axisType = timelineModel.get('axisType');\n\n        var scale = createScaleByModel(timelineModel, axisType);\n\n        // Customize scale. The `tickValue` is `dataIndex`.\n        scale.getTicks = function () {\n            return data.mapArray(['value'], function (value) {\n                return value;\n            });\n        };\n\n        var dataExtent = data.getDataExtent('value');\n        scale.setExtent(dataExtent[0], dataExtent[1]);\n        scale.niceTicks();\n\n        var axis = new TimelineAxis('value', scale, layoutInfo.axisExtent, axisType);\n        axis.model = timelineModel;\n\n        return axis;\n    },\n\n    _createGroup: function (name) {\n        var newGroup = this['_' + name] = new Group();\n        this.group.add(newGroup);\n        return newGroup;\n    },\n\n    _renderAxisLine: function (layoutInfo, group, axis, timelineModel) {\n        var axisExtent = axis.getExtent();\n\n        if (!timelineModel.get('lineStyle.show')) {\n            return;\n        }\n\n        group.add(new Line({\n            shape: {\n                x1: axisExtent[0], y1: 0,\n                x2: axisExtent[1], y2: 0\n            },\n            style: extend(\n                {lineCap: 'round'},\n                timelineModel.getModel('lineStyle').getLineStyle()\n            ),\n            silent: true,\n            z2: 1\n        }));\n    },\n\n    /**\n     * @private\n     */\n    _renderAxisTick: function (layoutInfo, group, axis, timelineModel) {\n        var data = timelineModel.getData();\n        // Show all ticks, despite ignoring strategy.\n        var ticks = axis.scale.getTicks();\n\n        // The value is dataIndex, see the costomized scale.\n        each$27(ticks, function (value) {\n            var tickCoord = axis.dataToCoord(value);\n            var itemModel = data.getItemModel(value);\n            var itemStyleModel = itemModel.getModel('itemStyle');\n            var hoverStyleModel = itemModel.getModel('emphasis.itemStyle');\n            var symbolOpt = {\n                position: [tickCoord, 0],\n                onclick: bind$6(this._changeTimeline, this, value)\n            };\n            var el = giveSymbol(itemModel, itemStyleModel, group, symbolOpt);\n            setHoverStyle(el, hoverStyleModel.getItemStyle());\n\n            if (itemModel.get('tooltip')) {\n                el.dataIndex = value;\n                el.dataModel = timelineModel;\n            }\n            else {\n                el.dataIndex = el.dataModel = null;\n            }\n\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _renderAxisLabel: function (layoutInfo, group, axis, timelineModel) {\n        var labelModel = axis.getLabelModel();\n\n        if (!labelModel.get('show')) {\n            return;\n        }\n\n        var data = timelineModel.getData();\n        var labels = axis.getViewLabels();\n\n        each$27(labels, function (labelItem) {\n            // The tickValue is dataIndex, see the costomized scale.\n            var dataIndex = labelItem.tickValue;\n\n            var itemModel = data.getItemModel(dataIndex);\n            var normalLabelModel = itemModel.getModel('label');\n            var hoverLabelModel = itemModel.getModel('emphasis.label');\n            var tickCoord = axis.dataToCoord(labelItem.tickValue);\n            var textEl = new Text({\n                position: [tickCoord, 0],\n                rotation: layoutInfo.labelRotation - layoutInfo.rotation,\n                onclick: bind$6(this._changeTimeline, this, dataIndex),\n                silent: false\n            });\n            setTextStyle(textEl.style, normalLabelModel, {\n                text: labelItem.formattedLabel,\n                textAlign: layoutInfo.labelAlign,\n                textVerticalAlign: layoutInfo.labelBaseline\n            });\n\n            group.add(textEl);\n            setHoverStyle(\n                textEl, setTextStyle({}, hoverLabelModel)\n            );\n\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _renderControl: function (layoutInfo, group, axis, timelineModel) {\n        var controlSize = layoutInfo.controlSize;\n        var rotation = layoutInfo.rotation;\n\n        var itemStyle = timelineModel.getModel('controlStyle').getItemStyle();\n        var hoverStyle = timelineModel.getModel('emphasis.controlStyle').getItemStyle();\n        var rect = [0, -controlSize / 2, controlSize, controlSize];\n        var playState = timelineModel.getPlayState();\n        var inverse = timelineModel.get('inverse', true);\n\n        makeBtn(\n            layoutInfo.nextBtnPosition,\n            'controlStyle.nextIcon',\n            bind$6(this._changeTimeline, this, inverse ? '-' : '+')\n        );\n        makeBtn(\n            layoutInfo.prevBtnPosition,\n            'controlStyle.prevIcon',\n            bind$6(this._changeTimeline, this, inverse ? '+' : '-')\n        );\n        makeBtn(\n            layoutInfo.playPosition,\n            'controlStyle.' + (playState ? 'stopIcon' : 'playIcon'),\n            bind$6(this._handlePlayClick, this, !playState),\n            true\n        );\n\n        function makeBtn(position, iconPath, onclick, willRotate) {\n            if (!position) {\n                return;\n            }\n            var opt = {\n                position: position,\n                origin: [controlSize / 2, 0],\n                rotation: willRotate ? -rotation : 0,\n                rectHover: true,\n                style: itemStyle,\n                onclick: onclick\n            };\n            var btn = makeIcon(timelineModel, iconPath, rect, opt);\n            group.add(btn);\n            setHoverStyle(btn, hoverStyle);\n        }\n    },\n\n    _renderCurrentPointer: function (layoutInfo, group, axis, timelineModel) {\n        var data = timelineModel.getData();\n        var currentIndex = timelineModel.getCurrentIndex();\n        var pointerModel = data.getItemModel(currentIndex).getModel('checkpointStyle');\n        var me = this;\n\n        var callback = {\n            onCreate: function (pointer) {\n                pointer.draggable = true;\n                pointer.drift = bind$6(me._handlePointerDrag, me);\n                pointer.ondragend = bind$6(me._handlePointerDragend, me);\n                pointerMoveTo(pointer, currentIndex, axis, timelineModel, true);\n            },\n            onUpdate: function (pointer) {\n                pointerMoveTo(pointer, currentIndex, axis, timelineModel);\n            }\n        };\n\n        // Reuse when exists, for animation and drag.\n        this._currentPointer = giveSymbol(\n            pointerModel, pointerModel, this._mainGroup, {}, this._currentPointer, callback\n        );\n    },\n\n    _handlePlayClick: function (nextState) {\n        this._clearTimer();\n        this.api.dispatchAction({\n            type: 'timelinePlayChange',\n            playState: nextState,\n            from: this.uid\n        });\n    },\n\n    _handlePointerDrag: function (dx, dy, e) {\n        this._clearTimer();\n        this._pointerChangeTimeline([e.offsetX, e.offsetY]);\n    },\n\n    _handlePointerDragend: function (e) {\n        this._pointerChangeTimeline([e.offsetX, e.offsetY], true);\n    },\n\n    _pointerChangeTimeline: function (mousePos, trigger) {\n        var toCoord = this._toAxisCoord(mousePos)[0];\n\n        var axis = this._axis;\n        var axisExtent = asc(axis.getExtent().slice());\n\n        toCoord > axisExtent[1] && (toCoord = axisExtent[1]);\n        toCoord < axisExtent[0] && (toCoord = axisExtent[0]);\n\n        this._currentPointer.position[0] = toCoord;\n        this._currentPointer.dirty();\n\n        var targetDataIndex = this._findNearestTick(toCoord);\n        var timelineModel = this.model;\n\n        if (trigger || (\n            targetDataIndex !== timelineModel.getCurrentIndex()\n            && timelineModel.get('realtime')\n        )) {\n            this._changeTimeline(targetDataIndex);\n        }\n    },\n\n    _doPlayStop: function () {\n        this._clearTimer();\n\n        if (this.model.getPlayState()) {\n            this._timer = setTimeout(\n                bind$6(handleFrame, this),\n                this.model.get('playInterval')\n            );\n        }\n\n        function handleFrame() {\n            // Do not cache\n            var timelineModel = this.model;\n            this._changeTimeline(\n                timelineModel.getCurrentIndex()\n                + (timelineModel.get('rewind', true) ? -1 : 1)\n            );\n        }\n    },\n\n    _toAxisCoord: function (vertex) {\n        var trans = this._mainGroup.getLocalTransform();\n        return applyTransform$1(vertex, trans, true);\n    },\n\n    _findNearestTick: function (axisCoord) {\n        var data = this.model.getData();\n        var dist = Infinity;\n        var targetDataIndex;\n        var axis = this._axis;\n\n        data.each(['value'], function (value, dataIndex) {\n            var coord = axis.dataToCoord(value);\n            var d = Math.abs(coord - axisCoord);\n            if (d < dist) {\n                dist = d;\n                targetDataIndex = dataIndex;\n            }\n        });\n\n        return targetDataIndex;\n    },\n\n    _clearTimer: function () {\n        if (this._timer) {\n            clearTimeout(this._timer);\n            this._timer = null;\n        }\n    },\n\n    _changeTimeline: function (nextIndex) {\n        var currentIndex = this.model.getCurrentIndex();\n\n        if (nextIndex === '+') {\n            nextIndex = currentIndex + 1;\n        }\n        else if (nextIndex === '-') {\n            nextIndex = currentIndex - 1;\n        }\n\n        this.api.dispatchAction({\n            type: 'timelineChange',\n            currentIndex: nextIndex,\n            from: this.uid\n        });\n    }\n\n});\n\nfunction getViewRect$4(model, api) {\n    return getLayoutRect(\n        model.getBoxLayoutParams(),\n        {\n            width: api.getWidth(),\n            height: api.getHeight()\n        },\n        model.get('padding')\n    );\n}\n\nfunction makeIcon(timelineModel, objPath, rect, opts) {\n    var icon = makePath(\n        timelineModel.get(objPath).replace(/^path:\\/\\//, ''),\n        clone(opts || {}),\n        new BoundingRect(rect[0], rect[1], rect[2], rect[3]),\n        'center'\n    );\n\n    return icon;\n}\n\n/**\n * Create symbol or update symbol\n * opt: basic position and event handlers\n */\nfunction giveSymbol(hostModel, itemStyleModel, group, opt, symbol, callback) {\n    var color = itemStyleModel.get('color');\n\n    if (!symbol) {\n        var symbolType = hostModel.get('symbol');\n        symbol = createSymbol(symbolType, -1, -1, 2, 2, color);\n        symbol.setStyle('strokeNoScale', true);\n        group.add(symbol);\n        callback && callback.onCreate(symbol);\n    }\n    else {\n        symbol.setColor(color);\n        group.add(symbol); // Group may be new, also need to add.\n        callback && callback.onUpdate(symbol);\n    }\n\n    // Style\n    var itemStyle = itemStyleModel.getItemStyle(['color', 'symbol', 'symbolSize']);\n    symbol.setStyle(itemStyle);\n\n    // Transform and events.\n    opt = merge({\n        rectHover: true,\n        z2: 100\n    }, opt, true);\n\n    var symbolSize = hostModel.get('symbolSize');\n    symbolSize = symbolSize instanceof Array\n        ? symbolSize.slice()\n        : [+symbolSize, +symbolSize];\n    symbolSize[0] /= 2;\n    symbolSize[1] /= 2;\n    opt.scale = symbolSize;\n\n    var symbolOffset = hostModel.get('symbolOffset');\n    if (symbolOffset) {\n        var pos = opt.position = opt.position || [0, 0];\n        pos[0] += parsePercent$1(symbolOffset[0], symbolSize[0]);\n        pos[1] += parsePercent$1(symbolOffset[1], symbolSize[1]);\n    }\n\n    var symbolRotate = hostModel.get('symbolRotate');\n    opt.rotation = (symbolRotate || 0) * Math.PI / 180 || 0;\n\n    symbol.attr(opt);\n\n    // FIXME\n    // (1) When symbol.style.strokeNoScale is true and updateTransform is not performed,\n    // getBoundingRect will return wrong result.\n    // (This is supposed to be resolved in zrender, but it is a little difficult to\n    // leverage performance and auto updateTransform)\n    // (2) All of ancesters of symbol do not scale, so we can just updateTransform symbol.\n    symbol.updateTransform();\n\n    return symbol;\n}\n\nfunction pointerMoveTo(pointer, dataIndex, axis, timelineModel, noAnimation) {\n    if (pointer.dragging) {\n        return;\n    }\n\n    var pointerModel = timelineModel.getModel('checkpointStyle');\n    var toCoord = axis.dataToCoord(timelineModel.getData().get(['value'], dataIndex));\n\n    if (noAnimation || !pointerModel.get('animation', true)) {\n        pointer.attr({position: [toCoord, 0]});\n    }\n    else {\n        pointer.stopAnimation(true);\n        pointer.animateTo(\n            {position: [toCoord, 0]},\n            pointerModel.get('animationDuration', true),\n            pointerModel.get('animationEasing', true)\n        );\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\nregisterPreprocessor(preprocessor$3);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ToolboxModel = extendComponentModel({\n\n    type: 'toolbox',\n\n    layoutMode: {\n        type: 'box',\n        ignoreSize: true\n    },\n\n    optionUpdated: function () {\n        ToolboxModel.superApply(this, 'optionUpdated', arguments);\n\n        each$1(this.option.feature, function (featureOpt, featureName) {\n            var Feature = get$1(featureName);\n            Feature && merge(featureOpt, Feature.defaultOption);\n        });\n    },\n\n    defaultOption: {\n\n        show: true,\n\n        z: 6,\n\n        zlevel: 0,\n\n        orient: 'horizontal',\n\n        left: 'right',\n\n        top: 'top',\n\n        // right\n        // bottom\n\n        backgroundColor: 'transparent',\n\n        borderColor: '#ccc',\n\n        borderRadius: 0,\n\n        borderWidth: 0,\n\n        padding: 5,\n\n        itemSize: 15,\n\n        itemGap: 8,\n\n        showTitle: true,\n\n        iconStyle: {\n            borderColor: '#666',\n            color: 'none'\n        },\n        emphasis: {\n            iconStyle: {\n                borderColor: '#3E98C5'\n            }\n        }\n        // textStyle: {},\n\n        // feature\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentView({\n\n    type: 'toolbox',\n\n    render: function (toolboxModel, ecModel, api, payload) {\n        var group = this.group;\n        group.removeAll();\n\n        if (!toolboxModel.get('show')) {\n            return;\n        }\n\n        var itemSize = +toolboxModel.get('itemSize');\n        var featureOpts = toolboxModel.get('feature') || {};\n        var features = this._features || (this._features = {});\n\n        var featureNames = [];\n        each$1(featureOpts, function (opt, name) {\n            featureNames.push(name);\n        });\n\n        (new DataDiffer(this._featureNames || [], featureNames))\n            .add(processFeature)\n            .update(processFeature)\n            .remove(curry(processFeature, null))\n            .execute();\n\n        // Keep for diff.\n        this._featureNames = featureNames;\n\n        function processFeature(newIndex, oldIndex) {\n            var featureName = featureNames[newIndex];\n            var oldName = featureNames[oldIndex];\n            var featureOpt = featureOpts[featureName];\n            var featureModel = new Model(featureOpt, toolboxModel, toolboxModel.ecModel);\n            var feature;\n\n            if (featureName && !oldName) { // Create\n                if (isUserFeatureName(featureName)) {\n                    feature = {\n                        model: featureModel,\n                        onclick: featureModel.option.onclick,\n                        featureName: featureName\n                    };\n                }\n                else {\n                    var Feature = get$1(featureName);\n                    if (!Feature) {\n                        return;\n                    }\n                    feature = new Feature(featureModel, ecModel, api);\n                }\n                features[featureName] = feature;\n            }\n            else {\n                feature = features[oldName];\n                // If feature does not exsit.\n                if (!feature) {\n                    return;\n                }\n                feature.model = featureModel;\n                feature.ecModel = ecModel;\n                feature.api = api;\n            }\n\n            if (!featureName && oldName) {\n                feature.dispose && feature.dispose(ecModel, api);\n                return;\n            }\n\n            if (!featureModel.get('show') || feature.unusable) {\n                feature.remove && feature.remove(ecModel, api);\n                return;\n            }\n\n            createIconPaths(featureModel, feature, featureName);\n\n            featureModel.setIconStatus = function (iconName, status) {\n                var option = this.option;\n                var iconPaths = this.iconPaths;\n                option.iconStatus = option.iconStatus || {};\n                option.iconStatus[iconName] = status;\n                // FIXME\n                iconPaths[iconName] && iconPaths[iconName].trigger(status);\n            };\n\n            if (feature.render) {\n                feature.render(featureModel, ecModel, api, payload);\n            }\n        }\n\n        function createIconPaths(featureModel, feature, featureName) {\n            var iconStyleModel = featureModel.getModel('iconStyle');\n            var iconStyleEmphasisModel = featureModel.getModel('emphasis.iconStyle');\n\n            // If one feature has mutiple icon. they are orginaized as\n            // {\n            //     icon: {\n            //         foo: '',\n            //         bar: ''\n            //     },\n            //     title: {\n            //         foo: '',\n            //         bar: ''\n            //     }\n            // }\n            var icons = feature.getIcons ? feature.getIcons() : featureModel.get('icon');\n            var titles = featureModel.get('title') || {};\n            if (typeof icons === 'string') {\n                var icon = icons;\n                var title = titles;\n                icons = {};\n                titles = {};\n                icons[featureName] = icon;\n                titles[featureName] = title;\n            }\n            var iconPaths = featureModel.iconPaths = {};\n            each$1(icons, function (iconStr, iconName) {\n                var path = createIcon(\n                    iconStr,\n                    {},\n                    {\n                        x: -itemSize / 2,\n                        y: -itemSize / 2,\n                        width: itemSize,\n                        height: itemSize\n                    }\n                );\n                path.setStyle(iconStyleModel.getItemStyle());\n                path.hoverStyle = iconStyleEmphasisModel.getItemStyle();\n\n                setHoverStyle(path);\n\n                if (toolboxModel.get('showTitle')) {\n                    path.__title = titles[iconName];\n                    path.on('mouseover', function () {\n                            // Should not reuse above hoverStyle, which might be modified.\n                            var hoverStyle = iconStyleEmphasisModel.getItemStyle();\n                            path.setStyle({\n                                text: titles[iconName],\n                                textPosition: hoverStyle.textPosition || 'bottom',\n                                textFill: hoverStyle.fill || hoverStyle.stroke || '#000',\n                                textAlign: hoverStyle.textAlign || 'center'\n                            });\n                        })\n                        .on('mouseout', function () {\n                            path.setStyle({\n                                textFill: null\n                            });\n                        });\n                }\n                path.trigger(featureModel.get('iconStatus.' + iconName) || 'normal');\n\n                group.add(path);\n                path.on('click', bind(\n                    feature.onclick, feature, ecModel, api, iconName\n                ));\n\n                iconPaths[iconName] = path;\n            });\n        }\n\n        layout$3(group, toolboxModel, api);\n        // Render background after group is layout\n        // FIXME\n        group.add(makeBackground(group.getBoundingRect(), toolboxModel));\n\n        // Adjust icon title positions to avoid them out of screen\n        group.eachChild(function (icon) {\n            var titleText = icon.__title;\n            var hoverStyle = icon.hoverStyle;\n            // May be background element\n            if (hoverStyle && titleText) {\n                var rect = getBoundingRect(\n                    titleText, makeFont(hoverStyle)\n                );\n                var offsetX = icon.position[0] + group.position[0];\n                var offsetY = icon.position[1] + group.position[1] + itemSize;\n\n                var needPutOnTop = false;\n                if (offsetY + rect.height > api.getHeight()) {\n                    hoverStyle.textPosition = 'top';\n                    needPutOnTop = true;\n                }\n                var topOffset = needPutOnTop ? (-5 - rect.height) : (itemSize + 8);\n                if (offsetX + rect.width / 2 > api.getWidth()) {\n                    hoverStyle.textPosition = ['100%', topOffset];\n                    hoverStyle.textAlign = 'right';\n                }\n                else if (offsetX - rect.width / 2 < 0) {\n                    hoverStyle.textPosition = [0, topOffset];\n                    hoverStyle.textAlign = 'left';\n                }\n            }\n        });\n    },\n\n    updateView: function (toolboxModel, ecModel, api, payload) {\n        each$1(this._features, function (feature) {\n            feature.updateView && feature.updateView(feature.model, ecModel, api, payload);\n        });\n    },\n\n    // updateLayout: function (toolboxModel, ecModel, api, payload) {\n    //     zrUtil.each(this._features, function (feature) {\n    //         feature.updateLayout && feature.updateLayout(feature.model, ecModel, api, payload);\n    //     });\n    // },\n\n    remove: function (ecModel, api) {\n        each$1(this._features, function (feature) {\n            feature.remove && feature.remove(ecModel, api);\n        });\n        this.group.removeAll();\n    },\n\n    dispose: function (ecModel, api) {\n        each$1(this._features, function (feature) {\n            feature.dispose && feature.dispose(ecModel, api);\n        });\n    }\n});\n\nfunction isUserFeatureName(featureName) {\n    return featureName.indexOf('my') === 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Uint8Array */\n\nvar saveAsImageLang = lang.toolbox.saveAsImage;\n\nfunction SaveAsImage(model) {\n    this.model = model;\n}\n\nSaveAsImage.defaultOption = {\n    show: true,\n    icon: 'M4.7,22.9L29.3,45.5L54.7,23.4M4.6,43.6L4.6,58L53.8,58L53.8,43.6M29.2,45.1L29.2,0',\n    title: saveAsImageLang.title,\n    type: 'png',\n    // Default use option.backgroundColor\n    // backgroundColor: '#fff',\n    name: '',\n    excludeComponents: ['toolbox'],\n    pixelRatio: 1,\n    lang: saveAsImageLang.lang.slice()\n};\n\nSaveAsImage.prototype.unusable = !env$1.canvasSupported;\n\nvar proto$4 = SaveAsImage.prototype;\n\nproto$4.onclick = function (ecModel, api) {\n    var model = this.model;\n    var title = model.get('name') || ecModel.get('title.0.text') || 'echarts';\n    var $a = document.createElement('a');\n    var type = model.get('type', true) || 'png';\n    $a.download = title + '.' + type;\n    $a.target = '_blank';\n    var url = api.getConnectedDataURL({\n        type: type,\n        backgroundColor: model.get('backgroundColor', true)\n            || ecModel.get('backgroundColor') || '#fff',\n        excludeComponents: model.get('excludeComponents'),\n        pixelRatio: model.get('pixelRatio')\n    });\n    $a.href = url;\n    // Chrome and Firefox\n    if (typeof MouseEvent === 'function' && !env$1.browser.ie && !env$1.browser.edge) {\n        var evt = new MouseEvent('click', {\n            view: window,\n            bubbles: true,\n            cancelable: false\n        });\n        $a.dispatchEvent(evt);\n    }\n    // IE\n    else {\n        if (window.navigator.msSaveOrOpenBlob) {\n            var bstr = atob(url.split(',')[1]);\n            var n = bstr.length;\n            var u8arr = new Uint8Array(n);\n            while (n--) {\n                u8arr[n] = bstr.charCodeAt(n);\n            }\n            var blob = new Blob([u8arr]);\n            window.navigator.msSaveOrOpenBlob(blob, title + '.' + type);\n        }\n        else {\n            var lang$$1 = model.get('lang');\n            var html = ''\n                + '<body style=\"margin:0;\">'\n                + '<img src=\"' + url + '\" style=\"max-width:100%;\" title=\"' + ((lang$$1 && lang$$1[0]) || '') + '\" />'\n                + '</body>';\n            var tab = window.open();\n            tab.document.write(html);\n        }\n    }\n};\n\nregister$1(\n    'saveAsImage', SaveAsImage\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar magicTypeLang = lang.toolbox.magicType;\n\nfunction MagicType(model) {\n    this.model = model;\n}\n\nMagicType.defaultOption = {\n    show: true,\n    type: [],\n    // Icon group\n    icon: {\n        /* eslint-disable */\n        line: 'M4.1,28.9h7.1l9.3-22l7.4,38l9.7-19.7l3,12.8h14.9M4.1,58h51.4',\n        bar: 'M6.7,22.9h10V48h-10V22.9zM24.9,13h10v35h-10V13zM43.2,2h10v46h-10V2zM3.1,58h53.7',\n        stack: 'M8.2,38.4l-8.4,4.1l30.6,15.3L60,42.5l-8.1-4.1l-21.5,11L8.2,38.4z M51.9,30l-8.1,4.2l-13.4,6.9l-13.9-6.9L8.2,30l-8.4,4.2l8.4,4.2l22.2,11l21.5-11l8.1-4.2L51.9,30z M51.9,21.7l-8.1,4.2L35.7,30l-5.3,2.8L24.9,30l-8.4-4.1l-8.3-4.2l-8.4,4.2L8.2,30l8.3,4.2l13.9,6.9l13.4-6.9l8.1-4.2l8.1-4.1L51.9,21.7zM30.4,2.2L-0.2,17.5l8.4,4.1l8.3,4.2l8.4,4.2l5.5,2.7l5.3-2.7l8.1-4.2l8.1-4.2l8.1-4.1L30.4,2.2z', // jshint ignore:line\n        tiled: 'M2.3,2.2h22.8V25H2.3V2.2z M35,2.2h22.8V25H35V2.2zM2.3,35h22.8v22.8H2.3V35z M35,35h22.8v22.8H35V35z'\n        /* eslint-enable */\n    },\n    // `line`, `bar`, `stack`, `tiled`\n    title: clone(magicTypeLang.title),\n    option: {},\n    seriesIndex: {}\n};\n\nvar proto$5 = MagicType.prototype;\n\nproto$5.getIcons = function () {\n    var model = this.model;\n    var availableIcons = model.get('icon');\n    var icons = {};\n    each$1(model.get('type'), function (type) {\n        if (availableIcons[type]) {\n            icons[type] = availableIcons[type];\n        }\n    });\n    return icons;\n};\n\nvar seriesOptGenreator = {\n    'line': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                type: 'line',\n                // Preserve data related option\n                data: seriesModel.get('data'),\n                stack: seriesModel.get('stack'),\n                markPoint: seriesModel.get('markPoint'),\n                markLine: seriesModel.get('markLine')\n            }, model.get('option.line') || {}, true);\n        }\n    },\n    'bar': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line') {\n            return merge({\n                id: seriesId,\n                type: 'bar',\n                // Preserve data related option\n                data: seriesModel.get('data'),\n                stack: seriesModel.get('stack'),\n                markPoint: seriesModel.get('markPoint'),\n                markLine: seriesModel.get('markLine')\n            }, model.get('option.bar') || {}, true);\n        }\n    },\n    'stack': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line' || seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                stack: '__ec_magicType_stack__'\n            }, model.get('option.stack') || {}, true);\n        }\n    },\n    'tiled': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line' || seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                stack: ''\n            }, model.get('option.tiled') || {}, true);\n        }\n    }\n};\n\nvar radioTypes = [\n    ['line', 'bar'],\n    ['stack', 'tiled']\n];\n\nproto$5.onclick = function (ecModel, api, type) {\n    var model = this.model;\n    var seriesIndex = model.get('seriesIndex.' + type);\n    // Not supported magicType\n    if (!seriesOptGenreator[type]) {\n        return;\n    }\n    var newOption = {\n        series: []\n    };\n    var generateNewSeriesTypes = function (seriesModel) {\n        var seriesType = seriesModel.subType;\n        var seriesId = seriesModel.id;\n        var newSeriesOpt = seriesOptGenreator[type](\n            seriesType, seriesId, seriesModel, model\n        );\n        if (newSeriesOpt) {\n            // PENDING If merge original option?\n            defaults(newSeriesOpt, seriesModel.option);\n            newOption.series.push(newSeriesOpt);\n        }\n        // Modify boundaryGap\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys && coordSys.type === 'cartesian2d' && (type === 'line' || type === 'bar')) {\n            var categoryAxis = coordSys.getAxesByScale('ordinal')[0];\n            if (categoryAxis) {\n                var axisDim = categoryAxis.dim;\n                var axisType = axisDim + 'Axis';\n                var axisModel = ecModel.queryComponents({\n                    mainType: axisType,\n                    index: seriesModel.get(name + 'Index'),\n                    id: seriesModel.get(name + 'Id')\n                })[0];\n                var axisIndex = axisModel.componentIndex;\n\n                newOption[axisType] = newOption[axisType] || [];\n                for (var i = 0; i <= axisIndex; i++) {\n                    newOption[axisType][axisIndex] = newOption[axisType][axisIndex] || {};\n                }\n                newOption[axisType][axisIndex].boundaryGap = type === 'bar';\n            }\n        }\n    };\n\n    each$1(radioTypes, function (radio) {\n        if (indexOf(radio, type) >= 0) {\n            each$1(radio, function (item) {\n                model.setIconStatus(item, 'normal');\n            });\n        }\n    });\n\n    model.setIconStatus(type, 'emphasis');\n\n    ecModel.eachComponent(\n        {\n            mainType: 'series',\n            query: seriesIndex == null ? null : {\n                seriesIndex: seriesIndex\n            }\n        }, generateNewSeriesTypes\n    );\n    api.dispatchAction({\n        type: 'changeMagicType',\n        currentType: type,\n        newOption: newOption\n    });\n};\n\nregisterAction({\n    type: 'changeMagicType',\n    event: 'magicTypeChanged',\n    update: 'prepareAndUpdate'\n}, function (payload, ecModel) {\n    ecModel.mergeOption(payload.newOption);\n});\n\nregister$1('magicType', MagicType);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar dataViewLang = lang.toolbox.dataView;\n\nvar BLOCK_SPLITER = new Array(60).join('-');\nvar ITEM_SPLITER = '\\t';\n/**\n * Group series into two types\n *  1. on category axis, like line, bar\n *  2. others, like scatter, pie\n * @param {module:echarts/model/Global} ecModel\n * @return {Object}\n * @inner\n */\nfunction groupSeries(ecModel) {\n    var seriesGroupByCategoryAxis = {};\n    var otherSeries = [];\n    var meta = [];\n    ecModel.eachRawSeries(function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n\n        if (coordSys && (coordSys.type === 'cartesian2d' || coordSys.type === 'polar')) {\n            var baseAxis = coordSys.getBaseAxis();\n            if (baseAxis.type === 'category') {\n                var key = baseAxis.dim + '_' + baseAxis.index;\n                if (!seriesGroupByCategoryAxis[key]) {\n                    seriesGroupByCategoryAxis[key] = {\n                        categoryAxis: baseAxis,\n                        valueAxis: coordSys.getOtherAxis(baseAxis),\n                        series: []\n                    };\n                    meta.push({\n                        axisDim: baseAxis.dim,\n                        axisIndex: baseAxis.index\n                    });\n                }\n                seriesGroupByCategoryAxis[key].series.push(seriesModel);\n            }\n            else {\n                otherSeries.push(seriesModel);\n            }\n        }\n        else {\n            otherSeries.push(seriesModel);\n        }\n    });\n\n    return {\n        seriesGroupByCategoryAxis: seriesGroupByCategoryAxis,\n        other: otherSeries,\n        meta: meta\n    };\n}\n\n/**\n * Assemble content of series on cateogory axis\n * @param {Array.<module:echarts/model/Series>} series\n * @return {string}\n * @inner\n */\nfunction assembleSeriesWithCategoryAxis(series) {\n    var tables = [];\n    each$1(series, function (group, key) {\n        var categoryAxis = group.categoryAxis;\n        var valueAxis = group.valueAxis;\n        var valueAxisDim = valueAxis.dim;\n\n        var headers = [' '].concat(map(group.series, function (series) {\n            return series.name;\n        }));\n        var columns = [categoryAxis.model.getCategories()];\n        each$1(group.series, function (series) {\n            columns.push(series.getRawData().mapArray(valueAxisDim, function (val) {\n                return val;\n            }));\n        });\n        // Assemble table content\n        var lines = [headers.join(ITEM_SPLITER)];\n        for (var i = 0; i < columns[0].length; i++) {\n            var items = [];\n            for (var j = 0; j < columns.length; j++) {\n                items.push(columns[j][i]);\n            }\n            lines.push(items.join(ITEM_SPLITER));\n        }\n        tables.push(lines.join('\\n'));\n    });\n    return tables.join('\\n\\n' + BLOCK_SPLITER + '\\n\\n');\n}\n\n/**\n * Assemble content of other series\n * @param {Array.<module:echarts/model/Series>} series\n * @return {string}\n * @inner\n */\nfunction assembleOtherSeries(series) {\n    return map(series, function (series) {\n        var data = series.getRawData();\n        var lines = [series.name];\n        var vals = [];\n        data.each(data.dimensions, function () {\n            var argLen = arguments.length;\n            var dataIndex = arguments[argLen - 1];\n            var name = data.getName(dataIndex);\n            for (var i = 0; i < argLen - 1; i++) {\n                vals[i] = arguments[i];\n            }\n            lines.push((name ? (name + ITEM_SPLITER) : '') + vals.join(ITEM_SPLITER));\n        });\n        return lines.join('\\n');\n    }).join('\\n\\n' + BLOCK_SPLITER + '\\n\\n');\n}\n\n/**\n * @param {module:echarts/model/Global}\n * @return {Object}\n * @inner\n */\nfunction getContentFromModel(ecModel) {\n\n    var result = groupSeries(ecModel);\n\n    return {\n        value: filter([\n                assembleSeriesWithCategoryAxis(result.seriesGroupByCategoryAxis),\n                assembleOtherSeries(result.other)\n            ], function (str) {\n                return str.replace(/[\\n\\t\\s]/g, '');\n            }).join('\\n\\n' + BLOCK_SPLITER + '\\n\\n'),\n\n        meta: result.meta\n    };\n}\n\n\nfunction trim$1(str) {\n    return str.replace(/^\\s\\s*/, '').replace(/\\s\\s*$/, '');\n}\n/**\n * If a block is tsv format\n */\nfunction isTSVFormat(block) {\n    // Simple method to find out if a block is tsv format\n    var firstLine = block.slice(0, block.indexOf('\\n'));\n    if (firstLine.indexOf(ITEM_SPLITER) >= 0) {\n        return true;\n    }\n}\n\nvar itemSplitRegex = new RegExp('[' + ITEM_SPLITER + ']+', 'g');\n/**\n * @param {string} tsv\n * @return {Object}\n */\nfunction parseTSVContents(tsv) {\n    var tsvLines = tsv.split(/\\n+/g);\n    var headers = trim$1(tsvLines.shift()).split(itemSplitRegex);\n\n    var categories = [];\n    var series = map(headers, function (header) {\n        return {\n            name: header,\n            data: []\n        };\n    });\n    for (var i = 0; i < tsvLines.length; i++) {\n        var items = trim$1(tsvLines[i]).split(itemSplitRegex);\n        categories.push(items.shift());\n        for (var j = 0; j < items.length; j++) {\n            series[j] && (series[j].data[i] = items[j]);\n        }\n    }\n    return {\n        series: series,\n        categories: categories\n    };\n}\n\n/**\n * @param {string} str\n * @return {Array.<Object>}\n * @inner\n */\nfunction parseListContents(str) {\n    var lines = str.split(/\\n+/g);\n    var seriesName = trim$1(lines.shift());\n\n    var data = [];\n    for (var i = 0; i < lines.length; i++) {\n        var items = trim$1(lines[i]).split(itemSplitRegex);\n        var name = '';\n        var value;\n        var hasName = false;\n        if (isNaN(items[0])) { // First item is name\n            hasName = true;\n            name = items[0];\n            items = items.slice(1);\n            data[i] = {\n                name: name,\n                value: []\n            };\n            value = data[i].value;\n        }\n        else {\n            value = data[i] = [];\n        }\n        for (var j = 0; j < items.length; j++) {\n            value.push(+items[j]);\n        }\n        if (value.length === 1) {\n            hasName ? (data[i].value = value[0]) : (data[i] = value[0]);\n        }\n    }\n\n    return {\n        name: seriesName,\n        data: data\n    };\n}\n\n/**\n * @param {string} str\n * @param {Array.<Object>} blockMetaList\n * @return {Object}\n * @inner\n */\nfunction parseContents(str, blockMetaList) {\n    var blocks = str.split(new RegExp('\\n*' + BLOCK_SPLITER + '\\n*', 'g'));\n    var newOption = {\n        series: []\n    };\n    each$1(blocks, function (block, idx) {\n        if (isTSVFormat(block)) {\n            var result = parseTSVContents(block);\n            var blockMeta = blockMetaList[idx];\n            var axisKey = blockMeta.axisDim + 'Axis';\n\n            if (blockMeta) {\n                newOption[axisKey] = newOption[axisKey] || [];\n                newOption[axisKey][blockMeta.axisIndex] = {\n                    data: result.categories\n                };\n                newOption.series = newOption.series.concat(result.series);\n            }\n        }\n        else {\n            var result = parseListContents(block);\n            newOption.series.push(result);\n        }\n    });\n    return newOption;\n}\n\n/**\n * @alias {module:echarts/component/toolbox/feature/DataView}\n * @constructor\n * @param {module:echarts/model/Model} model\n */\nfunction DataView(model) {\n\n    this._dom = null;\n\n    this.model = model;\n}\n\nDataView.defaultOption = {\n    show: true,\n    readOnly: false,\n    optionToContent: null,\n    contentToOption: null,\n\n    icon: 'M17.5,17.3H33 M17.5,17.3H33 M45.4,29.5h-28 M11.5,2v56H51V14.8L38.4,2H11.5z M38.4,2.2v12.7H51 M45.4,41.7h-28',\n    title: clone(dataViewLang.title),\n    lang: clone(dataViewLang.lang),\n    backgroundColor: '#fff',\n    textColor: '#000',\n    textareaColor: '#fff',\n    textareaBorderColor: '#333',\n    buttonColor: '#c23531',\n    buttonTextColor: '#fff'\n};\n\nDataView.prototype.onclick = function (ecModel, api) {\n    var container = api.getDom();\n    var model = this.model;\n    if (this._dom) {\n        container.removeChild(this._dom);\n    }\n    var root = document.createElement('div');\n    root.style.cssText = 'position:absolute;left:5px;top:5px;bottom:5px;right:5px;';\n    root.style.backgroundColor = model.get('backgroundColor') || '#fff';\n\n    // Create elements\n    var header = document.createElement('h4');\n    var lang$$1 = model.get('lang') || [];\n    header.innerHTML = lang$$1[0] || model.get('title');\n    header.style.cssText = 'margin: 10px 20px;';\n    header.style.color = model.get('textColor');\n\n    var viewMain = document.createElement('div');\n    var textarea = document.createElement('textarea');\n    viewMain.style.cssText = 'display:block;width:100%;overflow:auto;';\n\n    var optionToContent = model.get('optionToContent');\n    var contentToOption = model.get('contentToOption');\n    var result = getContentFromModel(ecModel);\n    if (typeof optionToContent === 'function') {\n        var htmlOrDom = optionToContent(api.getOption());\n        if (typeof htmlOrDom === 'string') {\n            viewMain.innerHTML = htmlOrDom;\n        }\n        else if (isDom(htmlOrDom)) {\n            viewMain.appendChild(htmlOrDom);\n        }\n    }\n    else {\n        // Use default textarea\n        viewMain.appendChild(textarea);\n        textarea.readOnly = model.get('readOnly');\n        textarea.style.cssText = 'width:100%;height:100%;font-family:monospace;font-size:14px;line-height:1.6rem;';\n        textarea.style.color = model.get('textColor');\n        textarea.style.borderColor = model.get('textareaBorderColor');\n        textarea.style.backgroundColor = model.get('textareaColor');\n        textarea.value = result.value;\n    }\n\n    var blockMetaList = result.meta;\n\n    var buttonContainer = document.createElement('div');\n    buttonContainer.style.cssText = 'position:absolute;bottom:0;left:0;right:0;';\n\n    var buttonStyle = 'float:right;margin-right:20px;border:none;'\n        + 'cursor:pointer;padding:2px 5px;font-size:12px;border-radius:3px';\n    var closeButton = document.createElement('div');\n    var refreshButton = document.createElement('div');\n\n    buttonStyle += ';background-color:' + model.get('buttonColor');\n    buttonStyle += ';color:' + model.get('buttonTextColor');\n\n    var self = this;\n\n    function close() {\n        container.removeChild(root);\n        self._dom = null;\n    }\n    addEventListener(closeButton, 'click', close);\n\n    addEventListener(refreshButton, 'click', function () {\n        var newOption;\n        try {\n            if (typeof contentToOption === 'function') {\n                newOption = contentToOption(viewMain, api.getOption());\n            }\n            else {\n                newOption = parseContents(textarea.value, blockMetaList);\n            }\n        }\n        catch (e) {\n            close();\n            throw new Error('Data view format error ' + e);\n        }\n        if (newOption) {\n            api.dispatchAction({\n                type: 'changeDataView',\n                newOption: newOption\n            });\n        }\n\n        close();\n    });\n\n    closeButton.innerHTML = lang$$1[1];\n    refreshButton.innerHTML = lang$$1[2];\n    refreshButton.style.cssText = buttonStyle;\n    closeButton.style.cssText = buttonStyle;\n\n    !model.get('readOnly') && buttonContainer.appendChild(refreshButton);\n    buttonContainer.appendChild(closeButton);\n\n    // http://stackoverflow.com/questions/6637341/use-tab-to-indent-in-textarea\n    addEventListener(textarea, 'keydown', function (e) {\n        if ((e.keyCode || e.which) === 9) {\n            // get caret position/selection\n            var val = this.value;\n            var start = this.selectionStart;\n            var end = this.selectionEnd;\n\n            // set textarea value to: text before caret + tab + text after caret\n            this.value = val.substring(0, start) + ITEM_SPLITER + val.substring(end);\n\n            // put caret at right position again\n            this.selectionStart = this.selectionEnd = start + 1;\n\n            // prevent the focus lose\n            stop(e);\n        }\n    });\n\n    root.appendChild(header);\n    root.appendChild(viewMain);\n    root.appendChild(buttonContainer);\n\n    viewMain.style.height = (container.clientHeight - 80) + 'px';\n\n    container.appendChild(root);\n    this._dom = root;\n};\n\nDataView.prototype.remove = function (ecModel, api) {\n    this._dom && api.getDom().removeChild(this._dom);\n};\n\nDataView.prototype.dispose = function (ecModel, api) {\n    this.remove(ecModel, api);\n};\n\n/**\n * @inner\n */\nfunction tryMergeDataOption(newData, originalData) {\n    return map(newData, function (newVal, idx) {\n        var original = originalData && originalData[idx];\n        if (isObject$1(original) && !isArray(original)) {\n            if (isObject$1(newVal) && !isArray(newVal)) {\n                newVal = newVal.value;\n            }\n            // Original data has option\n            return defaults({\n                value: newVal\n            }, original);\n        }\n        else {\n            return newVal;\n        }\n    });\n}\n\nregister$1('dataView', DataView);\n\nregisterAction({\n    type: 'changeDataView',\n    event: 'dataViewChanged',\n    update: 'prepareAndUpdate'\n}, function (payload, ecModel) {\n    var newSeriesOptList = [];\n    each$1(payload.newOption.series, function (seriesOpt) {\n        var seriesModel = ecModel.getSeriesByName(seriesOpt.name)[0];\n        if (!seriesModel) {\n            // New created series\n            // Geuss the series type\n            newSeriesOptList.push(extend({\n                // Default is scatter\n                type: 'scatter'\n            }, seriesOpt));\n        }\n        else {\n            var originalData = seriesModel.get('data');\n            newSeriesOptList.push({\n                name: seriesOpt.name,\n                data: tryMergeDataOption(seriesOpt.data, originalData)\n            });\n        }\n    });\n\n    ecModel.mergeOption(defaults({\n        series: newSeriesOptList\n    }, payload.newOption));\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$29 = each$1;\n\nvar ATTR$2 = '\\0_ec_hist_store';\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} newSnapshot {dataZoomId, batch: [payloadInfo, ...]}\n */\nfunction push(ecModel, newSnapshot) {\n    var store = giveStore$1(ecModel);\n\n    // If previous dataZoom can not be found,\n    // complete an range with current range.\n    each$29(newSnapshot, function (batchItem, dataZoomId) {\n        var i = store.length - 1;\n        for (; i >= 0; i--) {\n            var snapshot = store[i];\n            if (snapshot[dataZoomId]) {\n                break;\n            }\n        }\n        if (i < 0) {\n            // No origin range set, create one by current range.\n            var dataZoomModel = ecModel.queryComponents(\n                {mainType: 'dataZoom', subType: 'select', id: dataZoomId}\n            )[0];\n            if (dataZoomModel) {\n                var percentRange = dataZoomModel.getPercentRange();\n                store[0][dataZoomId] = {\n                    dataZoomId: dataZoomId,\n                    start: percentRange[0],\n                    end: percentRange[1]\n                };\n            }\n        }\n    });\n\n    store.push(newSnapshot);\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @return {Object} snapshot\n */\nfunction pop(ecModel) {\n    var store = giveStore$1(ecModel);\n    var head = store[store.length - 1];\n    store.length > 1 && store.pop();\n\n    // Find top for all dataZoom.\n    var snapshot = {};\n    each$29(head, function (batchItem, dataZoomId) {\n        for (var i = store.length - 1; i >= 0; i--) {\n            var batchItem = store[i][dataZoomId];\n            if (batchItem) {\n                snapshot[dataZoomId] = batchItem;\n                break;\n            }\n        }\n    });\n\n    return snapshot;\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n */\nfunction clear$1(ecModel) {\n    ecModel[ATTR$2] = null;\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @return {number} records. always >= 1.\n */\nfunction count(ecModel) {\n    return giveStore$1(ecModel).length;\n}\n\n/**\n * [{key: dataZoomId, value: {dataZoomId, range}}, ...]\n * History length of each dataZoom may be different.\n * this._history[0] is used to store origin range.\n * @type {Array.<Object>}\n */\nfunction giveStore$1(ecModel) {\n    var store = ecModel[ATTR$2];\n    if (!store) {\n        store = ecModel[ATTR$2] = [{}];\n    }\n    return store;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomModel.extend({\n    type: 'dataZoom.select'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomView.extend({\n    type: 'dataZoom.select'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Use dataZoomSelect\nvar dataZoomLang = lang.toolbox.dataZoom;\nvar each$28 = each$1;\n\n// Spectial component id start with \\0ec\\0, see echarts/model/Global.js~hasInnerId\nvar DATA_ZOOM_ID_BASE = '\\0_ec_\\0toolbox-dataZoom_';\n\nfunction DataZoom(model, ecModel, api) {\n\n    /**\n     * @private\n     * @type {module:echarts/component/helper/BrushController}\n     */\n    (this._brushController = new BrushController(api.getZr()))\n        .on('brush', bind(this._onBrush, this))\n        .mount();\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._isZoomActive;\n}\n\nDataZoom.defaultOption = {\n    show: true,\n    // Icon group\n    icon: {\n        zoom: 'M0,13.5h26.9 M13.5,26.9V0 M32.1,13.5H58V58H13.5 V32.1',\n        back: 'M22,1.4L9.9,13.5l12.3,12.3 M10.3,13.5H54.9v44.6 H10.3v-26'\n    },\n    // `zoom`, `back`\n    title: clone(dataZoomLang.title)\n};\n\nvar proto$6 = DataZoom.prototype;\n\nproto$6.render = function (featureModel, ecModel, api, payload) {\n    this.model = featureModel;\n    this.ecModel = ecModel;\n    this.api = api;\n\n    updateZoomBtnStatus(featureModel, ecModel, this, payload, api);\n    updateBackBtnStatus(featureModel, ecModel);\n};\n\nproto$6.onclick = function (ecModel, api, type) {\n    handlers$1[type].call(this);\n};\n\nproto$6.remove = function (ecModel, api) {\n    this._brushController.unmount();\n};\n\nproto$6.dispose = function (ecModel, api) {\n    this._brushController.dispose();\n};\n\n/**\n * @private\n */\nvar handlers$1 = {\n\n    zoom: function () {\n        var nextActive = !this._isZoomActive;\n\n        this.api.dispatchAction({\n            type: 'takeGlobalCursor',\n            key: 'dataZoomSelect',\n            dataZoomSelectActive: nextActive\n        });\n    },\n\n    back: function () {\n        this._dispatchZoomAction(pop(this.ecModel));\n    }\n};\n\n/**\n * @private\n */\nproto$6._onBrush = function (areas, opt) {\n    if (!opt.isEnd || !areas.length) {\n        return;\n    }\n    var snapshot = {};\n    var ecModel = this.ecModel;\n\n    this._brushController.updateCovers([]); // remove cover\n\n    var brushTargetManager = new BrushTargetManager(\n        retrieveAxisSetting(this.model.option), ecModel, {include: ['grid']}\n    );\n    brushTargetManager.matchOutputRanges(areas, ecModel, function (area, coordRange, coordSys) {\n        if (coordSys.type !== 'cartesian2d') {\n            return;\n        }\n\n        var brushType = area.brushType;\n        if (brushType === 'rect') {\n            setBatch('x', coordSys, coordRange[0]);\n            setBatch('y', coordSys, coordRange[1]);\n        }\n        else {\n            setBatch(({lineX: 'x', lineY: 'y'})[brushType], coordSys, coordRange);\n        }\n    });\n\n    push(ecModel, snapshot);\n\n    this._dispatchZoomAction(snapshot);\n\n    function setBatch(dimName, coordSys, minMax) {\n        var axis = coordSys.getAxis(dimName);\n        var axisModel = axis.model;\n        var dataZoomModel = findDataZoom(dimName, axisModel, ecModel);\n\n        // Restrict range.\n        var minMaxSpan = dataZoomModel.findRepresentativeAxisProxy(axisModel).getMinMaxSpan();\n        if (minMaxSpan.minValueSpan != null || minMaxSpan.maxValueSpan != null) {\n            minMax = sliderMove(\n                0, minMax.slice(), axis.scale.getExtent(), 0,\n                minMaxSpan.minValueSpan, minMaxSpan.maxValueSpan\n            );\n        }\n\n        dataZoomModel && (snapshot[dataZoomModel.id] = {\n            dataZoomId: dataZoomModel.id,\n            startValue: minMax[0],\n            endValue: minMax[1]\n        });\n    }\n\n    function findDataZoom(dimName, axisModel, ecModel) {\n        var found;\n        ecModel.eachComponent({mainType: 'dataZoom', subType: 'select'}, function (dzModel) {\n            var has = dzModel.getAxisModel(dimName, axisModel.componentIndex);\n            has && (found = dzModel);\n        });\n        return found;\n    }\n};\n\n/**\n * @private\n */\nproto$6._dispatchZoomAction = function (snapshot) {\n    var batch = [];\n\n    // Convert from hash map to array.\n    each$28(snapshot, function (batchItem, dataZoomId) {\n        batch.push(clone(batchItem));\n    });\n\n    batch.length && this.api.dispatchAction({\n        type: 'dataZoom',\n        from: this.uid,\n        batch: batch\n    });\n};\n\nfunction retrieveAxisSetting(option) {\n    var setting = {};\n    // Compatible with previous setting: null => all axis, false => no axis.\n    each$1(['xAxisIndex', 'yAxisIndex'], function (name) {\n        setting[name] = option[name];\n        setting[name] == null && (setting[name] = 'all');\n        (setting[name] === false || setting[name] === 'none') && (setting[name] = []);\n    });\n    return setting;\n}\n\nfunction updateBackBtnStatus(featureModel, ecModel) {\n    featureModel.setIconStatus(\n        'back',\n        count(ecModel) > 1 ? 'emphasis' : 'normal'\n    );\n}\n\nfunction updateZoomBtnStatus(featureModel, ecModel, view, payload, api) {\n    var zoomActive = view._isZoomActive;\n\n    if (payload && payload.type === 'takeGlobalCursor') {\n        zoomActive = payload.key === 'dataZoomSelect'\n            ? payload.dataZoomSelectActive : false;\n    }\n\n    view._isZoomActive = zoomActive;\n\n    featureModel.setIconStatus('zoom', zoomActive ? 'emphasis' : 'normal');\n\n    var brushTargetManager = new BrushTargetManager(\n        retrieveAxisSetting(featureModel.option), ecModel, {include: ['grid']}\n    );\n\n    view._brushController\n        .setPanels(brushTargetManager.makePanelOpts(api, function (targetInfo) {\n            return (targetInfo.xAxisDeclared && !targetInfo.yAxisDeclared)\n                ? 'lineX'\n                : (!targetInfo.xAxisDeclared && targetInfo.yAxisDeclared)\n                ? 'lineY'\n                : 'rect';\n        }))\n        .enableBrush(\n            zoomActive\n            ? {\n                brushType: 'auto',\n                brushStyle: {\n                    // FIXME user customized?\n                    lineWidth: 0,\n                    fill: 'rgba(0,0,0,0.2)'\n                }\n            }\n            : false\n        );\n}\n\n\nregister$1('dataZoom', DataZoom);\n\n\n// Create special dataZoom option for select\n// FIXME consider the case of merge option, where axes options are not exists.\nregisterPreprocessor(function (option) {\n    if (!option) {\n        return;\n    }\n\n    var dataZoomOpts = option.dataZoom || (option.dataZoom = []);\n    if (!isArray(dataZoomOpts)) {\n        option.dataZoom = dataZoomOpts = [dataZoomOpts];\n    }\n\n    var toolboxOpt = option.toolbox;\n    if (toolboxOpt) {\n        // Assume there is only one toolbox\n        if (isArray(toolboxOpt)) {\n            toolboxOpt = toolboxOpt[0];\n        }\n\n        if (toolboxOpt && toolboxOpt.feature) {\n            var dataZoomOpt = toolboxOpt.feature.dataZoom;\n            // FIXME: If add dataZoom when setOption in merge mode,\n            // no axis info to be added. See `test/dataZoom-extreme.html`\n            addForAxis('xAxis', dataZoomOpt);\n            addForAxis('yAxis', dataZoomOpt);\n        }\n    }\n\n    function addForAxis(axisName, dataZoomOpt) {\n        if (!dataZoomOpt) {\n            return;\n        }\n\n        // Try not to modify model, because it is not merged yet.\n        var axisIndicesName = axisName + 'Index';\n        var givenAxisIndices = dataZoomOpt[axisIndicesName];\n        if (givenAxisIndices != null\n            && givenAxisIndices !== 'all'\n            && !isArray(givenAxisIndices)\n        ) {\n            givenAxisIndices = (givenAxisIndices === false || givenAxisIndices === 'none') ? [] : [givenAxisIndices];\n        }\n\n        forEachComponent(axisName, function (axisOpt, axisIndex) {\n            if (givenAxisIndices != null\n                && givenAxisIndices !== 'all'\n                && indexOf(givenAxisIndices, axisIndex) === -1\n            ) {\n                return;\n            }\n            var newOpt = {\n                type: 'select',\n                $fromToolbox: true,\n                // Id for merge mapping.\n                id: DATA_ZOOM_ID_BASE + axisName + axisIndex\n            };\n            // FIXME\n            // Only support one axis now.\n            newOpt[axisIndicesName] = axisIndex;\n            dataZoomOpts.push(newOpt);\n        });\n    }\n\n    function forEachComponent(mainType, cb) {\n        var opts = option[mainType];\n        if (!isArray(opts)) {\n            opts = opts ? [opts] : [];\n        }\n        each$28(opts, cb);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar restoreLang = lang.toolbox.restore;\n\nfunction Restore(model) {\n    this.model = model;\n}\n\nRestore.defaultOption = {\n    show: true,\n    /* eslint-disable */\n    icon: 'M3.8,33.4 M47,18.9h9.8V8.7 M56.3,20.1 C52.1,9,40.5,0.6,26.8,2.1C12.6,3.7,1.6,16.2,2.1,30.6 M13,41.1H3.1v10.2 M3.7,39.9c4.2,11.1,15.8,19.5,29.5,18 c14.2-1.6,25.2-14.1,24.7-28.5',\n    /* eslint-enable */\n    title: restoreLang.title\n};\n\nvar proto$7 = Restore.prototype;\n\nproto$7.onclick = function (ecModel, api, type) {\n    clear$1(ecModel);\n\n    api.dispatchAction({\n        type: 'restore',\n        from: this.uid\n    });\n};\n\nregister$1('restore', Restore);\n\nregisterAction(\n    {type: 'restore', event: 'restore', update: 'prepareAndUpdate'},\n    function (payload, ecModel) {\n        ecModel.resetOption('recreate');\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar urn = 'urn:schemas-microsoft-com:vml';\nvar win = typeof window === 'undefined' ? null : window;\n\nvar vmlInited = false;\n\nvar doc = win && win.document;\n\nfunction createNode(tagName) {\n    return doCreateNode(tagName);\n}\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar doCreateNode;\n\nif (doc && !env$1.canvasSupported) {\n    try {\n        !doc.namespaces.zrvml && doc.namespaces.add('zrvml', urn);\n        doCreateNode = function (tagName) {\n            return doc.createElement('<zrvml:' + tagName + ' class=\"zrvml\">');\n        };\n    }\n    catch (e) {\n        doCreateNode = function (tagName) {\n            return doc.createElement('<' + tagName + ' xmlns=\"' + urn + '\" class=\"zrvml\">');\n        };\n    }\n}\n\n// From raphael\nfunction initVML() {\n    if (vmlInited || !doc) {\n        return;\n    }\n    vmlInited = true;\n\n    var styleSheets = doc.styleSheets;\n    if (styleSheets.length < 31) {\n        doc.createStyleSheet().addRule('.zrvml', 'behavior:url(#default#VML)');\n    }\n    else {\n        // http://msdn.microsoft.com/en-us/library/ms531194%28VS.85%29.aspx\n        styleSheets[0].addRule('.zrvml', 'behavior:url(#default#VML)');\n    }\n}\n\n// http://www.w3.org/TR/NOTE-VML\n// TODO Use proxy like svg instead of overwrite brush methods\n\nvar CMD$3 = PathProxy.CMD;\nvar round$4 = Math.round;\nvar sqrt = Math.sqrt;\nvar abs$1 = Math.abs;\nvar cos = Math.cos;\nvar sin = Math.sin;\nvar mathMax$8 = Math.max;\n\nif (!env$1.canvasSupported) {\n\n    var comma = ',';\n    var imageTransformPrefix = 'progid:DXImageTransform.Microsoft';\n\n    var Z = 21600;\n    var Z2 = Z / 2;\n\n    var ZLEVEL_BASE = 100000;\n    var Z_BASE$1 = 1000;\n\n    var initRootElStyle = function (el) {\n        el.style.cssText = 'position:absolute;left:0;top:0;width:1px;height:1px;';\n        el.coordsize = Z + ',' + Z;\n        el.coordorigin = '0,0';\n    };\n\n    var encodeHtmlAttribute = function (s) {\n        return String(s).replace(/&/g, '&amp;').replace(/\"/g, '&quot;');\n    };\n\n    var rgb2Str = function (r, g, b) {\n        return 'rgb(' + [r, g, b].join(',') + ')';\n    };\n\n    var append = function (parent, child) {\n        if (child && parent && child.parentNode !== parent) {\n            parent.appendChild(child);\n        }\n    };\n\n    var remove = function (parent, child) {\n        if (child && parent && child.parentNode === parent) {\n            parent.removeChild(child);\n        }\n    };\n\n    var getZIndex = function (zlevel, z, z2) {\n        // z 的取值范围为 [0, 1000]\n        return (parseFloat(zlevel) || 0) * ZLEVEL_BASE + (parseFloat(z) || 0) * Z_BASE$1 + z2;\n    };\n\n    var parsePercent$3 = function (value, maxValue) {\n        if (typeof value === 'string') {\n            if (value.lastIndexOf('%') >= 0) {\n                return parseFloat(value) / 100 * maxValue;\n            }\n            return parseFloat(value);\n        }\n        return value;\n    };\n\n    /***************************************************\n     * PATH\n     **************************************************/\n\n    var setColorAndOpacity = function (el, color, opacity) {\n        var colorArr = parse(color);\n        opacity = +opacity;\n        if (isNaN(opacity)) {\n            opacity = 1;\n        }\n        if (colorArr) {\n            el.color = rgb2Str(colorArr[0], colorArr[1], colorArr[2]);\n            el.opacity = opacity * colorArr[3];\n        }\n    };\n\n    var getColorAndAlpha = function (color) {\n        var colorArr = parse(color);\n        return [\n            rgb2Str(colorArr[0], colorArr[1], colorArr[2]),\n            colorArr[3]\n        ];\n    };\n\n    var updateFillNode = function (el, style, zrEl) {\n        // TODO pattern\n        var fill = style.fill;\n        if (fill != null) {\n            // Modified from excanvas\n            if (fill instanceof Gradient) {\n                var gradientType;\n                var angle = 0;\n                var focus = [0, 0];\n                // additional offset\n                var shift = 0;\n                // scale factor for offset\n                var expansion = 1;\n                var rect = zrEl.getBoundingRect();\n                var rectWidth = rect.width;\n                var rectHeight = rect.height;\n                if (fill.type === 'linear') {\n                    gradientType = 'gradient';\n                    var transform = zrEl.transform;\n                    var p0 = [fill.x * rectWidth, fill.y * rectHeight];\n                    var p1 = [fill.x2 * rectWidth, fill.y2 * rectHeight];\n                    if (transform) {\n                        applyTransform(p0, p0, transform);\n                        applyTransform(p1, p1, transform);\n                    }\n                    var dx = p1[0] - p0[0];\n                    var dy = p1[1] - p0[1];\n                    angle = Math.atan2(dx, dy) * 180 / Math.PI;\n                    // The angle should be a non-negative number.\n                    if (angle < 0) {\n                        angle += 360;\n                    }\n\n                    // Very small angles produce an unexpected result because they are\n                    // converted to a scientific notation string.\n                    if (angle < 1e-6) {\n                        angle = 0;\n                    }\n                }\n                else {\n                    gradientType = 'gradientradial';\n                    var p0 = [fill.x * rectWidth, fill.y * rectHeight];\n                    var transform = zrEl.transform;\n                    var scale$$1 = zrEl.scale;\n                    var width = rectWidth;\n                    var height = rectHeight;\n                    focus = [\n                        // Percent in bounding rect\n                        (p0[0] - rect.x) / width,\n                        (p0[1] - rect.y) / height\n                    ];\n                    if (transform) {\n                        applyTransform(p0, p0, transform);\n                    }\n\n                    width /= scale$$1[0] * Z;\n                    height /= scale$$1[1] * Z;\n                    var dimension = mathMax$8(width, height);\n                    shift = 2 * 0 / dimension;\n                    expansion = 2 * fill.r / dimension - shift;\n                }\n\n                // We need to sort the color stops in ascending order by offset,\n                // otherwise IE won't interpret it correctly.\n                var stops = fill.colorStops.slice();\n                stops.sort(function (cs1, cs2) {\n                    return cs1.offset - cs2.offset;\n                });\n\n                var length$$1 = stops.length;\n                // Color and alpha list of first and last stop\n                var colorAndAlphaList = [];\n                var colors = [];\n                for (var i = 0; i < length$$1; i++) {\n                    var stop = stops[i];\n                    var colorAndAlpha = getColorAndAlpha(stop.color);\n                    colors.push(stop.offset * expansion + shift + ' ' + colorAndAlpha[0]);\n                    if (i === 0 || i === length$$1 - 1) {\n                        colorAndAlphaList.push(colorAndAlpha);\n                    }\n                }\n\n                if (length$$1 >= 2) {\n                    var color1 = colorAndAlphaList[0][0];\n                    var color2 = colorAndAlphaList[1][0];\n                    var opacity1 = colorAndAlphaList[0][1] * style.opacity;\n                    var opacity2 = colorAndAlphaList[1][1] * style.opacity;\n\n                    el.type = gradientType;\n                    el.method = 'none';\n                    el.focus = '100%';\n                    el.angle = angle;\n                    el.color = color1;\n                    el.color2 = color2;\n                    el.colors = colors.join(',');\n                    // When colors attribute is used, the meanings of opacity and o:opacity2\n                    // are reversed.\n                    el.opacity = opacity2;\n                    // FIXME g_o_:opacity ?\n                    el.opacity2 = opacity1;\n                }\n                if (gradientType === 'radial') {\n                    el.focusposition = focus.join(',');\n                }\n            }\n            else {\n                // FIXME Change from Gradient fill to color fill\n                setColorAndOpacity(el, fill, style.opacity);\n            }\n        }\n    };\n\n    var updateStrokeNode = function (el, style) {\n        // if (style.lineJoin != null) {\n        //     el.joinstyle = style.lineJoin;\n        // }\n        // if (style.miterLimit != null) {\n        //     el.miterlimit = style.miterLimit * Z;\n        // }\n        // if (style.lineCap != null) {\n        //     el.endcap = style.lineCap;\n        // }\n        if (style.lineDash != null) {\n            el.dashstyle = style.lineDash.join(' ');\n        }\n        if (style.stroke != null && !(style.stroke instanceof Gradient)) {\n            setColorAndOpacity(el, style.stroke, style.opacity);\n        }\n    };\n\n    var updateFillAndStroke = function (vmlEl, type, style, zrEl) {\n        var isFill = type === 'fill';\n        var el = vmlEl.getElementsByTagName(type)[0];\n        // Stroke must have lineWidth\n        if (style[type] != null && style[type] !== 'none' && (isFill || (!isFill && style.lineWidth))) {\n            vmlEl[isFill ? 'filled' : 'stroked'] = 'true';\n            // FIXME Remove before updating, or set `colors` will throw error\n            if (style[type] instanceof Gradient) {\n                remove(vmlEl, el);\n            }\n            if (!el) {\n                el = createNode(type);\n            }\n\n            isFill ? updateFillNode(el, style, zrEl) : updateStrokeNode(el, style);\n            append(vmlEl, el);\n        }\n        else {\n            vmlEl[isFill ? 'filled' : 'stroked'] = 'false';\n            remove(vmlEl, el);\n        }\n    };\n\n    var points$3 = [[], [], []];\n    var pathDataToString = function (path, m) {\n        var M = CMD$3.M;\n        var C = CMD$3.C;\n        var L = CMD$3.L;\n        var A = CMD$3.A;\n        var Q = CMD$3.Q;\n\n        var str = [];\n        var nPoint;\n        var cmdStr;\n        var cmd;\n        var i;\n        var xi;\n        var yi;\n        var data = path.data;\n        var dataLength = path.len();\n        for (i = 0; i < dataLength;) {\n            cmd = data[i++];\n            cmdStr = '';\n            nPoint = 0;\n            switch (cmd) {\n                case M:\n                    cmdStr = ' m ';\n                    nPoint = 1;\n                    xi = data[i++];\n                    yi = data[i++];\n                    points$3[0][0] = xi;\n                    points$3[0][1] = yi;\n                    break;\n                case L:\n                    cmdStr = ' l ';\n                    nPoint = 1;\n                    xi = data[i++];\n                    yi = data[i++];\n                    points$3[0][0] = xi;\n                    points$3[0][1] = yi;\n                    break;\n                case Q:\n                case C:\n                    cmdStr = ' c ';\n                    nPoint = 3;\n                    var x1 = data[i++];\n                    var y1 = data[i++];\n                    var x2 = data[i++];\n                    var y2 = data[i++];\n                    var x3;\n                    var y3;\n                    if (cmd === Q) {\n                        // Convert quadratic to cubic using degree elevation\n                        x3 = x2;\n                        y3 = y2;\n                        x2 = (x2 + 2 * x1) / 3;\n                        y2 = (y2 + 2 * y1) / 3;\n                        x1 = (xi + 2 * x1) / 3;\n                        y1 = (yi + 2 * y1) / 3;\n                    }\n                    else {\n                        x3 = data[i++];\n                        y3 = data[i++];\n                    }\n                    points$3[0][0] = x1;\n                    points$3[0][1] = y1;\n                    points$3[1][0] = x2;\n                    points$3[1][1] = y2;\n                    points$3[2][0] = x3;\n                    points$3[2][1] = y3;\n\n                    xi = x3;\n                    yi = y3;\n                    break;\n                case A:\n                    var x = 0;\n                    var y = 0;\n                    var sx = 1;\n                    var sy = 1;\n                    var angle = 0;\n                    if (m) {\n                        // Extract SRT from matrix\n                        x = m[4];\n                        y = m[5];\n                        sx = sqrt(m[0] * m[0] + m[1] * m[1]);\n                        sy = sqrt(m[2] * m[2] + m[3] * m[3]);\n                        angle = Math.atan2(-m[1] / sy, m[0] / sx);\n                    }\n\n                    var cx = data[i++];\n                    var cy = data[i++];\n                    var rx = data[i++];\n                    var ry = data[i++];\n                    var startAngle = data[i++] + angle;\n                    var endAngle = data[i++] + startAngle + angle;\n                    // FIXME\n                    // var psi = data[i++];\n                    i++;\n                    var clockwise = data[i++];\n\n                    var x0 = cx + cos(startAngle) * rx;\n                    var y0 = cy + sin(startAngle) * ry;\n\n                    var x1 = cx + cos(endAngle) * rx;\n                    var y1 = cy + sin(endAngle) * ry;\n\n                    var type = clockwise ? ' wa ' : ' at ';\n                    if (Math.abs(x0 - x1) < 1e-4) {\n                        // IE won't render arches drawn counter clockwise if x0 == x1.\n                        if (Math.abs(endAngle - startAngle) > 1e-2) {\n                            // Offset x0 by 1/80 of a pixel. Use something\n                            // that can be represented in binary\n                            if (clockwise) {\n                                x0 += 270 / Z;\n                            }\n                        }\n                        else {\n                            // Avoid case draw full circle\n                            if (Math.abs(y0 - cy) < 1e-4) {\n                                if ((clockwise && x0 < cx) || (!clockwise && x0 > cx)) {\n                                    y1 -= 270 / Z;\n                                }\n                                else {\n                                    y1 += 270 / Z;\n                                }\n                            }\n                            else if ((clockwise && y0 < cy) || (!clockwise && y0 > cy)) {\n                                x1 += 270 / Z;\n                            }\n                            else {\n                                x1 -= 270 / Z;\n                            }\n                        }\n                    }\n                    str.push(\n                        type,\n                        round$4(((cx - rx) * sx + x) * Z - Z2), comma,\n                        round$4(((cy - ry) * sy + y) * Z - Z2), comma,\n                        round$4(((cx + rx) * sx + x) * Z - Z2), comma,\n                        round$4(((cy + ry) * sy + y) * Z - Z2), comma,\n                        round$4((x0 * sx + x) * Z - Z2), comma,\n                        round$4((y0 * sy + y) * Z - Z2), comma,\n                        round$4((x1 * sx + x) * Z - Z2), comma,\n                        round$4((y1 * sy + y) * Z - Z2)\n                    );\n\n                    xi = x1;\n                    yi = y1;\n                    break;\n                case CMD$3.R:\n                    var p0 = points$3[0];\n                    var p1 = points$3[1];\n                    // x0, y0\n                    p0[0] = data[i++];\n                    p0[1] = data[i++];\n                    // x1, y1\n                    p1[0] = p0[0] + data[i++];\n                    p1[1] = p0[1] + data[i++];\n\n                    if (m) {\n                        applyTransform(p0, p0, m);\n                        applyTransform(p1, p1, m);\n                    }\n\n                    p0[0] = round$4(p0[0] * Z - Z2);\n                    p1[0] = round$4(p1[0] * Z - Z2);\n                    p0[1] = round$4(p0[1] * Z - Z2);\n                    p1[1] = round$4(p1[1] * Z - Z2);\n                    str.push(\n                        // x0, y0\n                        ' m ', p0[0], comma, p0[1],\n                        // x1, y0\n                        ' l ', p1[0], comma, p0[1],\n                        // x1, y1\n                        ' l ', p1[0], comma, p1[1],\n                        // x0, y1\n                        ' l ', p0[0], comma, p1[1]\n                    );\n                    break;\n                case CMD$3.Z:\n                    // FIXME Update xi, yi\n                    str.push(' x ');\n            }\n\n            if (nPoint > 0) {\n                str.push(cmdStr);\n                for (var k = 0; k < nPoint; k++) {\n                    var p = points$3[k];\n\n                    m && applyTransform(p, p, m);\n                    // 不 round 会非常慢\n                    str.push(\n                        round$4(p[0] * Z - Z2), comma, round$4(p[1] * Z - Z2),\n                        k < nPoint - 1 ? comma : ''\n                    );\n                }\n            }\n        }\n\n        return str.join('');\n    };\n\n    // Rewrite the original path method\n    Path.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n\n        var vmlEl = this._vmlEl;\n        if (!vmlEl) {\n            vmlEl = createNode('shape');\n            initRootElStyle(vmlEl);\n\n            this._vmlEl = vmlEl;\n        }\n\n        updateFillAndStroke(vmlEl, 'fill', style, this);\n        updateFillAndStroke(vmlEl, 'stroke', style, this);\n\n        var m = this.transform;\n        var needTransform = m != null;\n        var strokeEl = vmlEl.getElementsByTagName('stroke')[0];\n        if (strokeEl) {\n            var lineWidth = style.lineWidth;\n            // Get the line scale.\n            // Determinant of this.m_ means how much the area is enlarged by the\n            // transformation. So its square root can be used as a scale factor\n            // for width.\n            if (needTransform && !style.strokeNoScale) {\n                var det = m[0] * m[3] - m[1] * m[2];\n                lineWidth *= sqrt(abs$1(det));\n            }\n            strokeEl.weight = lineWidth + 'px';\n        }\n\n        var path = this.path || (this.path = new PathProxy());\n        if (this.__dirtyPath) {\n            path.beginPath();\n            path.subPixelOptimize = false;\n            this.buildPath(path, this.shape);\n            path.toStatic();\n            this.__dirtyPath = false;\n        }\n\n        vmlEl.path = pathDataToString(path, this.transform);\n\n        vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Append to root\n        append(vmlRoot, vmlEl);\n\n        // Text\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, this.getBoundingRect());\n        }\n        else {\n            this.removeRectText(vmlRoot);\n        }\n    };\n\n    Path.prototype.onRemove = function (vmlRoot) {\n        remove(vmlRoot, this._vmlEl);\n        this.removeRectText(vmlRoot);\n    };\n\n    Path.prototype.onAdd = function (vmlRoot) {\n        append(vmlRoot, this._vmlEl);\n        this.appendRectText(vmlRoot);\n    };\n\n    /***************************************************\n     * IMAGE\n     **************************************************/\n    var isImage = function (img) {\n        // FIXME img instanceof Image 如果 img 是一个字符串的时候，IE8 下会报错\n        return (typeof img === 'object') && img.tagName && img.tagName.toUpperCase() === 'IMG';\n        // return img instanceof Image;\n    };\n\n    // Rewrite the original path method\n    ZImage.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n        var image = style.image;\n\n        // Image original width, height\n        var ow;\n        var oh;\n\n        if (isImage(image)) {\n            var src = image.src;\n            if (src === this._imageSrc) {\n                ow = this._imageWidth;\n                oh = this._imageHeight;\n            }\n            else {\n                var imageRuntimeStyle = image.runtimeStyle;\n                var oldRuntimeWidth = imageRuntimeStyle.width;\n                var oldRuntimeHeight = imageRuntimeStyle.height;\n                imageRuntimeStyle.width = 'auto';\n                imageRuntimeStyle.height = 'auto';\n\n                // get the original size\n                ow = image.width;\n                oh = image.height;\n\n                // and remove overides\n                imageRuntimeStyle.width = oldRuntimeWidth;\n                imageRuntimeStyle.height = oldRuntimeHeight;\n\n                // Caching image original width, height and src\n                this._imageSrc = src;\n                this._imageWidth = ow;\n                this._imageHeight = oh;\n            }\n            image = src;\n        }\n        else {\n            if (image === this._imageSrc) {\n                ow = this._imageWidth;\n                oh = this._imageHeight;\n            }\n        }\n        if (!image) {\n            return;\n        }\n\n        var x = style.x || 0;\n        var y = style.y || 0;\n\n        var dw = style.width;\n        var dh = style.height;\n\n        var sw = style.sWidth;\n        var sh = style.sHeight;\n        var sx = style.sx || 0;\n        var sy = style.sy || 0;\n\n        var hasCrop = sw && sh;\n\n        var vmlEl = this._vmlEl;\n        if (!vmlEl) {\n            // FIXME 使用 group 在 left, top 都不是 0 的时候就无法显示了。\n            // vmlEl = vmlCore.createNode('group');\n            vmlEl = doc.createElement('div');\n            initRootElStyle(vmlEl);\n\n            this._vmlEl = vmlEl;\n        }\n\n        var vmlElStyle = vmlEl.style;\n        var hasRotation = false;\n        var m;\n        var scaleX = 1;\n        var scaleY = 1;\n        if (this.transform) {\n            m = this.transform;\n            scaleX = sqrt(m[0] * m[0] + m[1] * m[1]);\n            scaleY = sqrt(m[2] * m[2] + m[3] * m[3]);\n\n            hasRotation = m[1] || m[2];\n        }\n        if (hasRotation) {\n            // If filters are necessary (rotation exists), create them\n            // filters are bog-slow, so only create them if abbsolutely necessary\n            // The following check doesn't account for skews (which don't exist\n            // in the canvas spec (yet) anyway.\n            // From excanvas\n            var p0 = [x, y];\n            var p1 = [x + dw, y];\n            var p2 = [x, y + dh];\n            var p3 = [x + dw, y + dh];\n            applyTransform(p0, p0, m);\n            applyTransform(p1, p1, m);\n            applyTransform(p2, p2, m);\n            applyTransform(p3, p3, m);\n\n            var maxX = mathMax$8(p0[0], p1[0], p2[0], p3[0]);\n            var maxY = mathMax$8(p0[1], p1[1], p2[1], p3[1]);\n\n            var transformFilter = [];\n            transformFilter.push('M11=', m[0] / scaleX, comma,\n                        'M12=', m[2] / scaleY, comma,\n                        'M21=', m[1] / scaleX, comma,\n                        'M22=', m[3] / scaleY, comma,\n                        'Dx=', round$4(x * scaleX + m[4]), comma,\n                        'Dy=', round$4(y * scaleY + m[5]));\n\n            vmlElStyle.padding = '0 ' + round$4(maxX) + 'px ' + round$4(maxY) + 'px 0';\n            // FIXME DXImageTransform 在 IE11 的兼容模式下不起作用\n            vmlElStyle.filter = imageTransformPrefix + '.Matrix('\n                + transformFilter.join('') + ', SizingMethod=clip)';\n\n        }\n        else {\n            if (m) {\n                x = x * scaleX + m[4];\n                y = y * scaleY + m[5];\n            }\n            vmlElStyle.filter = '';\n            vmlElStyle.left = round$4(x) + 'px';\n            vmlElStyle.top = round$4(y) + 'px';\n        }\n\n        var imageEl = this._imageEl;\n        var cropEl = this._cropEl;\n\n        if (!imageEl) {\n            imageEl = doc.createElement('div');\n            this._imageEl = imageEl;\n        }\n        var imageELStyle = imageEl.style;\n        if (hasCrop) {\n            // Needs know image original width and height\n            if (!(ow && oh)) {\n                var tmpImage = new Image();\n                var self = this;\n                tmpImage.onload = function () {\n                    tmpImage.onload = null;\n                    ow = tmpImage.width;\n                    oh = tmpImage.height;\n                    // Adjust image width and height to fit the ratio destinationSize / sourceSize\n                    imageELStyle.width = round$4(scaleX * ow * dw / sw) + 'px';\n                    imageELStyle.height = round$4(scaleY * oh * dh / sh) + 'px';\n\n                    // Caching image original width, height and src\n                    self._imageWidth = ow;\n                    self._imageHeight = oh;\n                    self._imageSrc = image;\n                };\n                tmpImage.src = image;\n            }\n            else {\n                imageELStyle.width = round$4(scaleX * ow * dw / sw) + 'px';\n                imageELStyle.height = round$4(scaleY * oh * dh / sh) + 'px';\n            }\n\n            if (!cropEl) {\n                cropEl = doc.createElement('div');\n                cropEl.style.overflow = 'hidden';\n                this._cropEl = cropEl;\n            }\n            var cropElStyle = cropEl.style;\n            cropElStyle.width = round$4((dw + sx * dw / sw) * scaleX);\n            cropElStyle.height = round$4((dh + sy * dh / sh) * scaleY);\n            cropElStyle.filter = imageTransformPrefix + '.Matrix(Dx='\n                    + (-sx * dw / sw * scaleX) + ',Dy=' + (-sy * dh / sh * scaleY) + ')';\n\n            if (!cropEl.parentNode) {\n                vmlEl.appendChild(cropEl);\n            }\n            if (imageEl.parentNode !== cropEl) {\n                cropEl.appendChild(imageEl);\n            }\n        }\n        else {\n            imageELStyle.width = round$4(scaleX * dw) + 'px';\n            imageELStyle.height = round$4(scaleY * dh) + 'px';\n\n            vmlEl.appendChild(imageEl);\n\n            if (cropEl && cropEl.parentNode) {\n                vmlEl.removeChild(cropEl);\n                this._cropEl = null;\n            }\n        }\n\n        var filterStr = '';\n        var alpha = style.opacity;\n        if (alpha < 1) {\n            filterStr += '.Alpha(opacity=' + round$4(alpha * 100) + ') ';\n        }\n        filterStr += imageTransformPrefix + '.AlphaImageLoader(src=' + image + ', SizingMethod=scale)';\n\n        imageELStyle.filter = filterStr;\n\n        vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Append to root\n        append(vmlRoot, vmlEl);\n\n        // Text\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, this.getBoundingRect());\n        }\n    };\n\n    ZImage.prototype.onRemove = function (vmlRoot) {\n        remove(vmlRoot, this._vmlEl);\n\n        this._vmlEl = null;\n        this._cropEl = null;\n        this._imageEl = null;\n\n        this.removeRectText(vmlRoot);\n    };\n\n    ZImage.prototype.onAdd = function (vmlRoot) {\n        append(vmlRoot, this._vmlEl);\n        this.appendRectText(vmlRoot);\n    };\n\n\n    /***************************************************\n     * TEXT\n     **************************************************/\n\n    var DEFAULT_STYLE_NORMAL = 'normal';\n\n    var fontStyleCache = {};\n    var fontStyleCacheCount = 0;\n    var MAX_FONT_CACHE_SIZE = 100;\n    var fontEl = document.createElement('div');\n\n    var getFontStyle = function (fontString) {\n        var fontStyle = fontStyleCache[fontString];\n        if (!fontStyle) {\n            // Clear cache\n            if (fontStyleCacheCount > MAX_FONT_CACHE_SIZE) {\n                fontStyleCacheCount = 0;\n                fontStyleCache = {};\n            }\n\n            var style = fontEl.style;\n            var fontFamily;\n            try {\n                style.font = fontString;\n                fontFamily = style.fontFamily.split(',')[0];\n            }\n            catch (e) {\n            }\n\n            fontStyle = {\n                style: style.fontStyle || DEFAULT_STYLE_NORMAL,\n                variant: style.fontVariant || DEFAULT_STYLE_NORMAL,\n                weight: style.fontWeight || DEFAULT_STYLE_NORMAL,\n                size: parseFloat(style.fontSize || 12) | 0,\n                family: fontFamily || 'Microsoft YaHei'\n            };\n\n            fontStyleCache[fontString] = fontStyle;\n            fontStyleCacheCount++;\n        }\n        return fontStyle;\n    };\n\n    var textMeasureEl;\n    // Overwrite measure text method\n    $override$1('measureText', function (text, textFont) {\n        var doc$$1 = doc;\n        if (!textMeasureEl) {\n            textMeasureEl = doc$$1.createElement('div');\n            textMeasureEl.style.cssText = 'position:absolute;top:-20000px;left:0;'\n                + 'padding:0;margin:0;border:none;white-space:pre;';\n            doc.body.appendChild(textMeasureEl);\n        }\n\n        try {\n            textMeasureEl.style.font = textFont;\n        }\n        catch (ex) {\n            // Ignore failures to set to invalid font.\n        }\n        textMeasureEl.innerHTML = '';\n        // Don't use innerHTML or innerText because they allow markup/whitespace.\n        textMeasureEl.appendChild(doc$$1.createTextNode(text));\n        return {\n            width: textMeasureEl.offsetWidth\n        };\n    });\n\n    var tmpRect$2 = new BoundingRect();\n\n    var drawRectText = function (vmlRoot, rect, textRect, fromTextEl) {\n\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        var text = style.text;\n        // Convert to string\n        text != null && (text += '');\n        if (!text) {\n            return;\n        }\n\n        // Convert rich text to plain text. Rich text is not supported in\n        // IE8-, but tags in rich text template will be removed.\n        if (style.rich) {\n            var contentBlock = parseRichText(text, style);\n            text = [];\n            for (var i = 0; i < contentBlock.lines.length; i++) {\n                var tokens = contentBlock.lines[i].tokens;\n                var textLine = [];\n                for (var j = 0; j < tokens.length; j++) {\n                    textLine.push(tokens[j].text);\n                }\n                text.push(textLine.join(''));\n            }\n            text = text.join('\\n');\n        }\n\n        var x;\n        var y;\n        var align = style.textAlign;\n        var verticalAlign = style.textVerticalAlign;\n\n        var fontStyle = getFontStyle(style.font);\n        // FIXME encodeHtmlAttribute ?\n        var font = fontStyle.style + ' ' + fontStyle.variant + ' ' + fontStyle.weight + ' '\n            + fontStyle.size + 'px \"' + fontStyle.family + '\"';\n\n        textRect = textRect || getBoundingRect(\n            text, font, align, verticalAlign, style.textPadding, style.textLineHeight\n        );\n\n        // Transform rect to view space\n        var m = this.transform;\n        // Ignore transform for text in other element\n        if (m && !fromTextEl) {\n            tmpRect$2.copy(rect);\n            tmpRect$2.applyTransform(m);\n            rect = tmpRect$2;\n        }\n\n        if (!fromTextEl) {\n            var textPosition = style.textPosition;\n            var distance$$1 = style.textDistance;\n            // Text position represented by coord\n            if (textPosition instanceof Array) {\n                x = rect.x + parsePercent$3(textPosition[0], rect.width);\n                y = rect.y + parsePercent$3(textPosition[1], rect.height);\n\n                align = align || 'left';\n            }\n            else {\n                var res = adjustTextPositionOnRect(\n                    textPosition, rect, distance$$1\n                );\n                x = res.x;\n                y = res.y;\n\n                // Default align and baseline when has textPosition\n                align = align || res.textAlign;\n                verticalAlign = verticalAlign || res.textVerticalAlign;\n            }\n        }\n        else {\n            x = rect.x;\n            y = rect.y;\n        }\n\n        x = adjustTextX(x, textRect.width, align);\n        y = adjustTextY(y, textRect.height, verticalAlign);\n\n        // Force baseline 'middle'\n        y += textRect.height / 2;\n\n        // var fontSize = fontStyle.size;\n        // 1.75 is an arbitrary number, as there is no info about the text baseline\n        // switch (baseline) {\n            // case 'hanging':\n            // case 'top':\n            //     y += fontSize / 1.75;\n            //     break;\n        //     case 'middle':\n        //         break;\n        //     default:\n        //     // case null:\n        //     // case 'alphabetic':\n        //     // case 'ideographic':\n        //     // case 'bottom':\n        //         y -= fontSize / 2.25;\n        //         break;\n        // }\n\n        // switch (align) {\n        //     case 'left':\n        //         break;\n        //     case 'center':\n        //         x -= textRect.width / 2;\n        //         break;\n        //     case 'right':\n        //         x -= textRect.width;\n        //         break;\n            // case 'end':\n                // align = elementStyle.direction == 'ltr' ? 'right' : 'left';\n                // break;\n            // case 'start':\n                // align = elementStyle.direction == 'rtl' ? 'right' : 'left';\n                // break;\n            // default:\n            //     align = 'left';\n        // }\n\n        var createNode$$1 = createNode;\n\n        var textVmlEl = this._textVmlEl;\n        var pathEl;\n        var textPathEl;\n        var skewEl;\n        if (!textVmlEl) {\n            textVmlEl = createNode$$1('line');\n            pathEl = createNode$$1('path');\n            textPathEl = createNode$$1('textpath');\n            skewEl = createNode$$1('skew');\n\n            // FIXME Why here is not cammel case\n            // Align 'center' seems wrong\n            textPathEl.style['v-text-align'] = 'left';\n\n            initRootElStyle(textVmlEl);\n\n            pathEl.textpathok = true;\n            textPathEl.on = true;\n\n            textVmlEl.from = '0 0';\n            textVmlEl.to = '1000 0.05';\n\n            append(textVmlEl, skewEl);\n            append(textVmlEl, pathEl);\n            append(textVmlEl, textPathEl);\n\n            this._textVmlEl = textVmlEl;\n        }\n        else {\n            // 这里是在前面 appendChild 保证顺序的前提下\n            skewEl = textVmlEl.firstChild;\n            pathEl = skewEl.nextSibling;\n            textPathEl = pathEl.nextSibling;\n        }\n\n        var coords = [x, y];\n        var textVmlElStyle = textVmlEl.style;\n        // Ignore transform for text in other element\n        if (m && fromTextEl) {\n            applyTransform(coords, coords, m);\n\n            skewEl.on = true;\n\n            skewEl.matrix = m[0].toFixed(3) + comma + m[2].toFixed(3) + comma\n                            + m[1].toFixed(3) + comma + m[3].toFixed(3) + ',0,0';\n\n            // Text position\n            skewEl.offset = (round$4(coords[0]) || 0) + ',' + (round$4(coords[1]) || 0);\n            // Left top point as origin\n            skewEl.origin = '0 0';\n\n            textVmlElStyle.left = '0px';\n            textVmlElStyle.top = '0px';\n        }\n        else {\n            skewEl.on = false;\n            textVmlElStyle.left = round$4(x) + 'px';\n            textVmlElStyle.top = round$4(y) + 'px';\n        }\n\n        textPathEl.string = encodeHtmlAttribute(text);\n        // TODO\n        try {\n            textPathEl.style.font = font;\n        }\n        // Error font format\n        catch (e) {}\n\n        updateFillAndStroke(textVmlEl, 'fill', {\n            fill: style.textFill,\n            opacity: style.opacity\n        }, this);\n        updateFillAndStroke(textVmlEl, 'stroke', {\n            stroke: style.textStroke,\n            opacity: style.opacity,\n            lineDash: style.lineDash\n        }, this);\n\n        textVmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Attached to root\n        append(vmlRoot, textVmlEl);\n    };\n\n    var removeRectText = function (vmlRoot) {\n        remove(vmlRoot, this._textVmlEl);\n        this._textVmlEl = null;\n    };\n\n    var appendRectText = function (vmlRoot) {\n        append(vmlRoot, this._textVmlEl);\n    };\n\n    var list = [RectText, Displayable, ZImage, Path, Text];\n\n    // In case Displayable has been mixed in RectText\n    for (var i$3 = 0; i$3 < list.length; i$3++) {\n        var proto$8 = list[i$3].prototype;\n        proto$8.drawRectText = drawRectText;\n        proto$8.removeRectText = removeRectText;\n        proto$8.appendRectText = appendRectText;\n    }\n\n    Text.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, {\n                x: style.x || 0, y: style.y || 0,\n                width: 0, height: 0\n            }, this.getBoundingRect(), true);\n        }\n        else {\n            this.removeRectText(vmlRoot);\n        }\n    };\n\n    Text.prototype.onRemove = function (vmlRoot) {\n        this.removeRectText(vmlRoot);\n    };\n\n    Text.prototype.onAdd = function (vmlRoot) {\n        this.appendRectText(vmlRoot);\n    };\n}\n\n/**\n * VML Painter.\n *\n * @module zrender/vml/Painter\n */\n\nfunction parseInt10$1(val) {\n    return parseInt(val, 10);\n}\n\n/**\n * @alias module:zrender/vml/Painter\n */\nfunction VMLPainter(root, storage) {\n\n    initVML();\n\n    this.root = root;\n\n    this.storage = storage;\n\n    var vmlViewport = document.createElement('div');\n\n    var vmlRoot = document.createElement('div');\n\n    vmlViewport.style.cssText = 'display:inline-block;overflow:hidden;position:relative;width:300px;height:150px;';\n\n    vmlRoot.style.cssText = 'position:absolute;left:0;top:0;';\n\n    root.appendChild(vmlViewport);\n\n    this._vmlRoot = vmlRoot;\n    this._vmlViewport = vmlViewport;\n\n    this.resize();\n\n    // Modify storage\n    var oldDelFromStorage = storage.delFromStorage;\n    var oldAddToStorage = storage.addToStorage;\n    storage.delFromStorage = function (el) {\n        oldDelFromStorage.call(storage, el);\n\n        if (el) {\n            el.onRemove && el.onRemove(vmlRoot);\n        }\n    };\n\n    storage.addToStorage = function (el) {\n        // Displayable already has a vml node\n        el.onAdd && el.onAdd(vmlRoot);\n\n        oldAddToStorage.call(storage, el);\n    };\n\n    this._firstPaint = true;\n}\n\nVMLPainter.prototype = {\n\n    constructor: VMLPainter,\n\n    getType: function () {\n        return 'vml';\n    },\n\n    /**\n     * @return {HTMLDivElement}\n     */\n    getViewportRoot: function () {\n        return this._vmlViewport;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    /**\n     * 刷新\n     */\n    refresh: function () {\n\n        var list = this.storage.getDisplayList(true, true);\n\n        this._paintList(list);\n    },\n\n    _paintList: function (list) {\n        var vmlRoot = this._vmlRoot;\n        for (var i = 0; i < list.length; i++) {\n            var el = list[i];\n            if (el.invisible || el.ignore) {\n                if (!el.__alreadyNotVisible) {\n                    el.onRemove(vmlRoot);\n                }\n                // Set as already invisible\n                el.__alreadyNotVisible = true;\n            }\n            else {\n                if (el.__alreadyNotVisible) {\n                    el.onAdd(vmlRoot);\n                }\n                el.__alreadyNotVisible = false;\n                if (el.__dirty) {\n                    el.beforeBrush && el.beforeBrush();\n                    (el.brushVML || el.brush).call(el, vmlRoot);\n                    el.afterBrush && el.afterBrush();\n                }\n            }\n            el.__dirty = false;\n        }\n\n        if (this._firstPaint) {\n            // Detached from document at first time\n            // to avoid page refreshing too many times\n\n            // FIXME 如果每次都先 removeChild 可能会导致一些填充和描边的效果改变\n            this._vmlViewport.appendChild(vmlRoot);\n            this._firstPaint = false;\n        }\n    },\n\n    resize: function (width, height) {\n        var width = width == null ? this._getWidth() : width;\n        var height = height == null ? this._getHeight() : height;\n\n        if (this._width !== width || this._height !== height) {\n            this._width = width;\n            this._height = height;\n\n            var vmlViewportStyle = this._vmlViewport.style;\n            vmlViewportStyle.width = width + 'px';\n            vmlViewportStyle.height = height + 'px';\n        }\n    },\n\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this._vmlRoot =\n        this._vmlViewport =\n        this.storage = null;\n    },\n\n    getWidth: function () {\n        return this._width;\n    },\n\n    getHeight: function () {\n        return this._height;\n    },\n\n    clear: function () {\n        if (this._vmlViewport) {\n            this.root.removeChild(this._vmlViewport);\n        }\n    },\n\n    _getWidth: function () {\n        var root = this.root;\n        var stl = root.currentStyle;\n\n        return ((root.clientWidth || parseInt10$1(stl.width))\n                - parseInt10$1(stl.paddingLeft)\n                - parseInt10$1(stl.paddingRight)) | 0;\n    },\n\n    _getHeight: function () {\n        var root = this.root;\n        var stl = root.currentStyle;\n\n        return ((root.clientHeight || parseInt10$1(stl.height))\n                - parseInt10$1(stl.paddingTop)\n                - parseInt10$1(stl.paddingBottom)) | 0;\n    }\n};\n\n// Not supported methods\nfunction createMethodNotSupport(method) {\n    return function () {\n        zrLog('In IE8.0 VML mode painter not support method \"' + method + '\"');\n    };\n}\n\n// Unsupported methods\neach$1([\n    'getLayer', 'insertLayer', 'eachLayer', 'eachBuiltinLayer', 'eachOtherLayer', 'getLayers',\n    'modLayer', 'delLayer', 'clearLayer', 'toDataURL', 'pathToImage'\n], function (name) {\n    VMLPainter.prototype[name] = createMethodNotSupport(name);\n});\n\nregisterPainter('vml', VMLPainter);\n\nvar svgURI = 'http://www.w3.org/2000/svg';\n\nfunction createElement(name) {\n    return document.createElementNS(svgURI, name);\n}\n\n// TODO\n// 1. shadow\n// 2. Image: sx, sy, sw, sh\n\nvar CMD$4 = PathProxy.CMD;\nvar arrayJoin = Array.prototype.join;\n\nvar NONE = 'none';\nvar mathRound = Math.round;\nvar mathSin$3 = Math.sin;\nvar mathCos$3 = Math.cos;\nvar PI$5 = Math.PI;\nvar PI2$7 = Math.PI * 2;\nvar degree = 180 / PI$5;\n\nvar EPSILON$4 = 1e-4;\n\nfunction round4(val) {\n    return mathRound(val * 1e4) / 1e4;\n}\n\nfunction isAroundZero$1(val) {\n    return val < EPSILON$4 && val > -EPSILON$4;\n}\n\nfunction pathHasFill(style, isText) {\n    var fill = isText ? style.textFill : style.fill;\n    return fill != null && fill !== NONE;\n}\n\nfunction pathHasStroke(style, isText) {\n    var stroke = isText ? style.textStroke : style.stroke;\n    return stroke != null && stroke !== NONE;\n}\n\nfunction setTransform(svgEl, m) {\n    if (m) {\n        attr(svgEl, 'transform', 'matrix(' + arrayJoin.call(m, ',') + ')');\n    }\n}\n\nfunction attr(el, key, val) {\n    if (!val || val.type !== 'linear' && val.type !== 'radial') {\n        // Don't set attribute for gradient, since it need new dom nodes\n        el.setAttribute(key, val);\n    }\n}\n\nfunction attrXLink(el, key, val) {\n    el.setAttributeNS('http://www.w3.org/1999/xlink', key, val);\n}\n\nfunction bindStyle(svgEl, style, isText, el) {\n    if (pathHasFill(style, isText)) {\n        var fill = isText ? style.textFill : style.fill;\n        fill = fill === 'transparent' ? NONE : fill;\n\n        /**\n         * FIXME:\n         * This is a temporary fix for Chrome's clipping bug\n         * that happens when a clip-path is referring another one.\n         * This fix should be used before Chrome's bug is fixed.\n         * For an element that has clip-path, and fill is none,\n         * set it to be \"rgba(0, 0, 0, 0.002)\" will hide the element.\n         * Otherwise, it will show black fill color.\n         * 0.002 is used because this won't work for alpha values smaller\n         * than 0.002.\n         *\n         * See\n         * https://bugs.chromium.org/p/chromium/issues/detail?id=659790\n         * for more information.\n         */\n        if (svgEl.getAttribute('clip-path') !== 'none' && fill === NONE) {\n            fill = 'rgba(0, 0, 0, 0.002)';\n        }\n\n        attr(svgEl, 'fill', fill);\n        attr(svgEl, 'fill-opacity', style.fillOpacity != null ? style.fillOpacity * style.opacity : style.opacity);\n    }\n    else {\n        attr(svgEl, 'fill', NONE);\n    }\n\n    if (pathHasStroke(style, isText)) {\n        var stroke = isText ? style.textStroke : style.stroke;\n        stroke = stroke === 'transparent' ? NONE : stroke;\n        attr(svgEl, 'stroke', stroke);\n        var strokeWidth = isText\n            ? style.textStrokeWidth\n            : style.lineWidth;\n        var strokeScale = !isText && style.strokeNoScale\n            ? el.getLineScale()\n            : 1;\n        attr(svgEl, 'stroke-width', strokeWidth / strokeScale);\n        // stroke then fill for text; fill then stroke for others\n        attr(svgEl, 'paint-order', isText ? 'stroke' : 'fill');\n        attr(svgEl, 'stroke-opacity', style.strokeOpacity != null ? style.strokeOpacity : style.opacity);\n        var lineDash = style.lineDash;\n        if (lineDash) {\n            attr(svgEl, 'stroke-dasharray', style.lineDash.join(','));\n            attr(svgEl, 'stroke-dashoffset', mathRound(style.lineDashOffset || 0));\n        }\n        else {\n            attr(svgEl, 'stroke-dasharray', '');\n        }\n\n        // PENDING\n        style.lineCap && attr(svgEl, 'stroke-linecap', style.lineCap);\n        style.lineJoin && attr(svgEl, 'stroke-linejoin', style.lineJoin);\n        style.miterLimit && attr(svgEl, 'stroke-miterlimit', style.miterLimit);\n    }\n    else {\n        attr(svgEl, 'stroke', NONE);\n    }\n}\n\n/***************************************************\n * PATH\n **************************************************/\nfunction pathDataToString$1(path) {\n    var str = [];\n    var data = path.data;\n    var dataLength = path.len();\n    for (var i = 0; i < dataLength;) {\n        var cmd = data[i++];\n        var cmdStr = '';\n        var nData = 0;\n        switch (cmd) {\n            case CMD$4.M:\n                cmdStr = 'M';\n                nData = 2;\n                break;\n            case CMD$4.L:\n                cmdStr = 'L';\n                nData = 2;\n                break;\n            case CMD$4.Q:\n                cmdStr = 'Q';\n                nData = 4;\n                break;\n            case CMD$4.C:\n                cmdStr = 'C';\n                nData = 6;\n                break;\n            case CMD$4.A:\n                var cx = data[i++];\n                var cy = data[i++];\n                var rx = data[i++];\n                var ry = data[i++];\n                var theta = data[i++];\n                var dTheta = data[i++];\n                var psi = data[i++];\n                var clockwise = data[i++];\n\n                var dThetaPositive = Math.abs(dTheta);\n                var isCircle = isAroundZero$1(dThetaPositive - PI2$7)\n                    && !isAroundZero$1(dThetaPositive);\n\n                var large = false;\n                if (dThetaPositive >= PI2$7) {\n                    large = true;\n                }\n                else if (isAroundZero$1(dThetaPositive)) {\n                    large = false;\n                }\n                else {\n                    large = (dTheta > -PI$5 && dTheta < 0 || dTheta > PI$5)\n                        === !!clockwise;\n                }\n\n                var x0 = round4(cx + rx * mathCos$3(theta));\n                var y0 = round4(cy + ry * mathSin$3(theta));\n\n                // It will not draw if start point and end point are exactly the same\n                // We need to shift the end point with a small value\n                // FIXME A better way to draw circle ?\n                if (isCircle) {\n                    if (clockwise) {\n                        dTheta = PI2$7 - 1e-4;\n                    }\n                    else {\n                        dTheta = -PI2$7 + 1e-4;\n                    }\n\n                    large = true;\n\n                    if (i === 9) {\n                        // Move to (x0, y0) only when CMD.A comes at the\n                        // first position of a shape.\n                        // For instance, when drawing a ring, CMD.A comes\n                        // after CMD.M, so it's unnecessary to move to\n                        // (x0, y0).\n                        str.push('M', x0, y0);\n                    }\n                }\n\n                var x = round4(cx + rx * mathCos$3(theta + dTheta));\n                var y = round4(cy + ry * mathSin$3(theta + dTheta));\n\n                // FIXME Ellipse\n                str.push('A', round4(rx), round4(ry),\n                    mathRound(psi * degree), +large, +clockwise, x, y);\n                break;\n            case CMD$4.Z:\n                cmdStr = 'Z';\n                break;\n            case CMD$4.R:\n                var x = round4(data[i++]);\n                var y = round4(data[i++]);\n                var w = round4(data[i++]);\n                var h = round4(data[i++]);\n                str.push(\n                    'M', x, y,\n                    'L', x + w, y,\n                    'L', x + w, y + h,\n                    'L', x, y + h,\n                    'L', x, y\n                );\n                break;\n        }\n        cmdStr && str.push(cmdStr);\n        for (var j = 0; j < nData; j++) {\n            // PENDING With scale\n            str.push(round4(data[i++]));\n        }\n    }\n    return str.join(' ');\n}\n\nvar svgPath = {};\nsvgPath.brush = function (el) {\n    var style = el.style;\n\n    var svgEl = el.__svgEl;\n    if (!svgEl) {\n        svgEl = createElement('path');\n        el.__svgEl = svgEl;\n    }\n\n    if (!el.path) {\n        el.createPathProxy();\n    }\n    var path = el.path;\n\n    if (el.__dirtyPath) {\n        path.beginPath();\n        path.subPixelOptimize = false;\n        el.buildPath(path, el.shape);\n        el.__dirtyPath = false;\n\n        var pathStr = pathDataToString$1(path);\n        if (pathStr.indexOf('NaN') < 0) {\n            // Ignore illegal path, which may happen such in out-of-range\n            // data in Calendar series.\n            attr(svgEl, 'd', pathStr);\n        }\n    }\n\n    bindStyle(svgEl, style, false, el);\n    setTransform(svgEl, el.transform);\n\n    if (style.text != null) {\n        svgTextDrawRectText(el, el.getBoundingRect());\n    }\n};\n\n/***************************************************\n * IMAGE\n **************************************************/\nvar svgImage = {};\nsvgImage.brush = function (el) {\n    var style = el.style;\n    var image = style.image;\n\n    if (image instanceof HTMLImageElement) {\n        var src = image.src;\n        image = src;\n    }\n    if (!image) {\n        return;\n    }\n\n    var x = style.x || 0;\n    var y = style.y || 0;\n\n    var dw = style.width;\n    var dh = style.height;\n\n    var svgEl = el.__svgEl;\n    if (!svgEl) {\n        svgEl = createElement('image');\n        el.__svgEl = svgEl;\n    }\n\n    if (image !== el.__imageSrc) {\n        attrXLink(svgEl, 'href', image);\n        // Caching image src\n        el.__imageSrc = image;\n    }\n\n    attr(svgEl, 'width', dw);\n    attr(svgEl, 'height', dh);\n\n    attr(svgEl, 'x', x);\n    attr(svgEl, 'y', y);\n\n    setTransform(svgEl, el.transform);\n\n    if (style.text != null) {\n        svgTextDrawRectText(el, el.getBoundingRect());\n    }\n};\n\n/***************************************************\n * TEXT\n **************************************************/\nvar svgText = {};\nvar tmpRect$3 = new BoundingRect();\n\nvar svgTextDrawRectText = function (el, rect, textRect) {\n    var style = el.style;\n\n    el.__dirty && normalizeTextStyle(style, true);\n\n    var text = style.text;\n    // Convert to string\n    if (text == null) {\n        // Draw no text only when text is set to null, but not ''\n        return;\n    }\n    else {\n        text += '';\n    }\n\n    var textSvgEl = el.__textSvgEl;\n    if (!textSvgEl) {\n        textSvgEl = createElement('text');\n        el.__textSvgEl = textSvgEl;\n    }\n\n    var x;\n    var y;\n    var textPosition = style.textPosition;\n    var distance = style.textDistance;\n    var align = style.textAlign || 'left';\n\n    if (typeof style.fontSize === 'number') {\n        style.fontSize += 'px';\n    }\n    var font = style.font\n        || [\n            style.fontStyle || '',\n            style.fontWeight || '',\n            style.fontSize || '',\n            style.fontFamily || ''\n        ].join(' ')\n        || DEFAULT_FONT$1;\n\n    var verticalAlign = getVerticalAlignForSvg(style.textVerticalAlign);\n\n    textRect = getBoundingRect(\n        text, font, align,\n        verticalAlign, style.textPadding, style.textLineHeight\n    );\n\n    var lineHeight = textRect.lineHeight;\n    // Text position represented by coord\n    if (textPosition instanceof Array) {\n        x = rect.x + textPosition[0];\n        y = rect.y + textPosition[1];\n    }\n    else {\n        var newPos = adjustTextPositionOnRect(\n            textPosition, rect, distance\n        );\n        x = newPos.x;\n        y = newPos.y;\n        verticalAlign = getVerticalAlignForSvg(newPos.textVerticalAlign);\n        align = newPos.textAlign;\n    }\n\n    attr(textSvgEl, 'alignment-baseline', verticalAlign);\n\n    if (font) {\n        textSvgEl.style.font = font;\n    }\n\n    var textPadding = style.textPadding;\n\n    // Make baseline top\n    attr(textSvgEl, 'x', x);\n    attr(textSvgEl, 'y', y);\n\n    bindStyle(textSvgEl, style, true, el);\n    if (el instanceof Text || el.style.transformText) {\n        // Transform text with element\n        setTransform(textSvgEl, el.transform);\n    }\n    else {\n        if (el.transform) {\n            tmpRect$3.copy(rect);\n            tmpRect$3.applyTransform(el.transform);\n            rect = tmpRect$3;\n        }\n        else {\n            var pos = el.transformCoordToGlobal(rect.x, rect.y);\n            rect.x = pos[0];\n            rect.y = pos[1];\n            el.transform = identity(create$1());\n        }\n\n        // Text rotation, but no element transform\n        var origin = style.textOrigin;\n        if (origin === 'center') {\n            x = textRect.width / 2 + x;\n            y = textRect.height / 2 + y;\n        }\n        else if (origin) {\n            x = origin[0] + x;\n            y = origin[1] + y;\n        }\n        var rotate$$1 = -style.textRotation || 0;\n        var transform = create$1();\n        // Apply textRotate to element matrix\n        rotate(transform, transform, rotate$$1);\n\n        var pos = [el.transform[4], el.transform[5]];\n        translate(transform, transform, pos);\n        setTransform(textSvgEl, transform);\n    }\n\n    var textLines = text.split('\\n');\n    var nTextLines = textLines.length;\n    var textAnchor = align;\n    // PENDING\n    if (textAnchor === 'left') {\n        textAnchor = 'start';\n        textPadding && (x += textPadding[3]);\n    }\n    else if (textAnchor === 'right') {\n        textAnchor = 'end';\n        textPadding && (x -= textPadding[1]);\n    }\n    else if (textAnchor === 'center') {\n        textAnchor = 'middle';\n        textPadding && (x += (textPadding[3] - textPadding[1]) / 2);\n    }\n\n    var dy = 0;\n    if (verticalAlign === 'after-edge') {\n        dy = -textRect.height + lineHeight;\n        textPadding && (dy -= textPadding[2]);\n    }\n    else if (verticalAlign === 'middle') {\n        dy = (-textRect.height + lineHeight) / 2;\n        textPadding && (y += (textPadding[0] - textPadding[2]) / 2);\n    }\n    else {\n        textPadding && (dy += textPadding[0]);\n    }\n\n    // Font may affect position of each tspan elements\n    if (el.__text !== text || el.__textFont !== font) {\n        var tspanList = el.__tspanList || [];\n        el.__tspanList = tspanList;\n        for (var i = 0; i < nTextLines; i++) {\n            // Using cached tspan elements\n            var tspan = tspanList[i];\n            if (!tspan) {\n                tspan = tspanList[i] = createElement('tspan');\n                textSvgEl.appendChild(tspan);\n                attr(tspan, 'alignment-baseline', verticalAlign);\n                attr(tspan, 'text-anchor', textAnchor);\n            }\n            else {\n                tspan.innerHTML = '';\n            }\n            attr(tspan, 'x', x);\n            attr(tspan, 'y', y + i * lineHeight + dy);\n            tspan.appendChild(document.createTextNode(textLines[i]));\n        }\n        // Remove unsed tspan elements\n        for (; i < tspanList.length; i++) {\n            textSvgEl.removeChild(tspanList[i]);\n        }\n        tspanList.length = nTextLines;\n\n        el.__text = text;\n        el.__textFont = font;\n    }\n    else if (el.__tspanList.length) {\n        // Update span x and y\n        var len = el.__tspanList.length;\n        for (var i = 0; i < len; ++i) {\n            var tspan = el.__tspanList[i];\n            if (tspan) {\n                attr(tspan, 'x', x);\n                attr(tspan, 'y', y + i * lineHeight + dy);\n            }\n        }\n    }\n};\n\nfunction getVerticalAlignForSvg(verticalAlign) {\n    if (verticalAlign === 'middle') {\n        return 'middle';\n    }\n    else if (verticalAlign === 'bottom') {\n        return 'after-edge';\n    }\n    else {\n        return 'hanging';\n    }\n}\n\nsvgText.drawRectText = svgTextDrawRectText;\n\nsvgText.brush = function (el) {\n    var style = el.style;\n    if (style.text != null) {\n        // 强制设置 textPosition\n        style.textPosition = [0, 0];\n        svgTextDrawRectText(el, {\n            x: style.x || 0, y: style.y || 0,\n            width: 0, height: 0\n        }, el.getBoundingRect());\n    }\n};\n\n// Myers' Diff Algorithm\n// Modified from https://github.com/kpdecker/jsdiff/blob/master/src/diff/base.js\n\nfunction Diff() {}\n\nDiff.prototype = {\n    diff: function (oldArr, newArr, equals) {\n        if (!equals) {\n            equals = function (a, b) {\n                return a === b;\n            };\n        }\n        this.equals = equals;\n\n        var self = this;\n\n        oldArr = oldArr.slice();\n        newArr = newArr.slice();\n        // Allow subclasses to massage the input prior to running\n        var newLen = newArr.length;\n        var oldLen = oldArr.length;\n        var editLength = 1;\n        var maxEditLength = newLen + oldLen;\n        var bestPath = [{ newPos: -1, components: [] }];\n\n        // Seed editLength = 0, i.e. the content starts with the same values\n        var oldPos = this.extractCommon(bestPath[0], newArr, oldArr, 0);\n        if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) {\n            var indices = [];\n            for (var i = 0; i < newArr.length; i++) {\n                indices.push(i);\n            }\n            // Identity per the equality and tokenizer\n            return [{\n                indices: indices, count: newArr.length\n            }];\n        }\n\n        // Main worker method. checks all permutations of a given edit length for acceptance.\n        function execEditLength() {\n            for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) {\n                var basePath;\n                var addPath = bestPath[diagonalPath - 1];\n                var removePath = bestPath[diagonalPath + 1];\n                var oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;\n                if (addPath) {\n                    // No one else is going to attempt to use this value, clear it\n                    bestPath[diagonalPath - 1] = undefined;\n                }\n\n                var canAdd = addPath && addPath.newPos + 1 < newLen;\n                var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;\n                if (!canAdd && !canRemove) {\n                    // If this path is a terminal then prune\n                    bestPath[diagonalPath] = undefined;\n                    continue;\n                }\n\n                // Select the diagonal that we want to branch from. We select the prior\n                // path whose position in the new string is the farthest from the origin\n                // and does not pass the bounds of the diff graph\n                if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {\n                    basePath = clonePath(removePath);\n                    self.pushComponent(basePath.components, undefined, true);\n                }\n                else {\n                    basePath = addPath;   // No need to clone, we've pulled it from the list\n                    basePath.newPos++;\n                    self.pushComponent(basePath.components, true, undefined);\n                }\n\n                oldPos = self.extractCommon(basePath, newArr, oldArr, diagonalPath);\n\n                // If we have hit the end of both strings, then we are done\n                if (basePath.newPos + 1 >= newLen && oldPos + 1 >= oldLen) {\n                    return buildValues(self, basePath.components, newArr, oldArr);\n                }\n                else {\n                    // Otherwise track this path as a potential candidate and continue.\n                    bestPath[diagonalPath] = basePath;\n                }\n            }\n\n            editLength++;\n        }\n\n        while (editLength <= maxEditLength) {\n            var ret = execEditLength();\n            if (ret) {\n                return ret;\n            }\n        }\n    },\n\n    pushComponent: function (components, added, removed) {\n        var last = components[components.length - 1];\n        if (last && last.added === added && last.removed === removed) {\n            // We need to clone here as the component clone operation is just\n            // as shallow array clone\n            components[components.length - 1] = {count: last.count + 1, added: added, removed: removed };\n        }\n        else {\n            components.push({count: 1, added: added, removed: removed });\n        }\n    },\n    extractCommon: function (basePath, newArr, oldArr, diagonalPath) {\n        var newLen = newArr.length;\n        var oldLen = oldArr.length;\n        var newPos = basePath.newPos;\n        var oldPos = newPos - diagonalPath;\n        var commonCount = 0;\n\n        while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newArr[newPos + 1], oldArr[oldPos + 1])) {\n            newPos++;\n            oldPos++;\n            commonCount++;\n        }\n\n        if (commonCount) {\n            basePath.components.push({count: commonCount});\n        }\n\n        basePath.newPos = newPos;\n        return oldPos;\n    },\n    tokenize: function (value) {\n        return value.slice();\n    },\n    join: function (value) {\n        return value.slice();\n    }\n};\n\nfunction buildValues(diff, components, newArr, oldArr) {\n    var componentPos = 0;\n    var componentLen = components.length;\n    var newPos = 0;\n    var oldPos = 0;\n\n    for (; componentPos < componentLen; componentPos++) {\n        var component = components[componentPos];\n        if (!component.removed) {\n            var indices = [];\n            for (var i = newPos; i < newPos + component.count; i++) {\n                indices.push(i);\n            }\n            component.indices = indices;\n            newPos += component.count;\n            // Common case\n            if (!component.added) {\n                oldPos += component.count;\n            }\n        }\n        else {\n            var indices = [];\n            for (var i = oldPos; i < oldPos + component.count; i++) {\n                indices.push(i);\n            }\n            component.indices = indices;\n            oldPos += component.count;\n        }\n    }\n\n    return components;\n}\n\nfunction clonePath(path) {\n    return { newPos: path.newPos, components: path.components.slice(0) };\n}\n\nvar arrayDiff = new Diff();\n\nvar arrayDiff$1 = function (oldArr, newArr, callback) {\n    return arrayDiff.diff(oldArr, newArr, callback);\n};\n\n/**\n * @file Manages elements that can be defined in <defs> in SVG,\n *       e.g., gradients, clip path, etc.\n * @author Zhang Wenli\n */\n\nvar MARK_UNUSED = '0';\nvar MARK_USED = '1';\n\n/**\n * Manages elements that can be defined in <defs> in SVG,\n * e.g., gradients, clip path, etc.\n *\n * @class\n * @param {number}          zrId      zrender instance id\n * @param {SVGElement}      svgRoot   root of SVG document\n * @param {string|string[]} tagNames  possible tag names\n * @param {string}          markLabel label name to make if the element\n *                                    is used\n */\nfunction Definable(\n    zrId,\n    svgRoot,\n    tagNames,\n    markLabel,\n    domName\n) {\n    this._zrId = zrId;\n    this._svgRoot = svgRoot;\n    this._tagNames = typeof tagNames === 'string' ? [tagNames] : tagNames;\n    this._markLabel = markLabel;\n    this._domName = domName || '_dom';\n\n    this.nextId = 0;\n}\n\n\nDefinable.prototype.createElement = createElement;\n\n\n/**\n * Get the <defs> tag for svgRoot; optionally creates one if not exists.\n *\n * @param {boolean} isForceCreating if need to create when not exists\n * @return {SVGDefsElement} SVG <defs> element, null if it doesn't\n * exist and isForceCreating is false\n */\nDefinable.prototype.getDefs = function (isForceCreating) {\n    var svgRoot = this._svgRoot;\n    var defs = this._svgRoot.getElementsByTagName('defs');\n    if (defs.length === 0) {\n        // Not exist\n        if (isForceCreating) {\n            defs = svgRoot.insertBefore(\n                this.createElement('defs'), // Create new tag\n                svgRoot.firstChild // Insert in the front of svg\n            );\n            if (!defs.contains) {\n                // IE doesn't support contains method\n                defs.contains = function (el) {\n                    var children = defs.children;\n                    if (!children) {\n                        return false;\n                    }\n                    for (var i = children.length - 1; i >= 0; --i) {\n                        if (children[i] === el) {\n                            return true;\n                        }\n                    }\n                    return false;\n                };\n            }\n            return defs;\n        }\n        else {\n            return null;\n        }\n    }\n    else {\n        return defs[0];\n    }\n};\n\n\n/**\n * Update DOM element if necessary.\n *\n * @param {Object|string} element style element. e.g., for gradient,\n *                                it may be '#ccc' or {type: 'linear', ...}\n * @param {Function|undefined} onUpdate update callback\n */\nDefinable.prototype.update = function (element, onUpdate) {\n    if (!element) {\n        return;\n    }\n\n    var defs = this.getDefs(false);\n    if (element[this._domName] && defs.contains(element[this._domName])) {\n        // Update DOM\n        if (typeof onUpdate === 'function') {\n            onUpdate(element);\n        }\n    }\n    else {\n        // No previous dom, create new\n        var dom = this.add(element);\n        if (dom) {\n            element[this._domName] = dom;\n        }\n    }\n};\n\n\n/**\n * Add gradient dom to defs\n *\n * @param {SVGElement} dom DOM to be added to <defs>\n */\nDefinable.prototype.addDom = function (dom) {\n    var defs = this.getDefs(true);\n    defs.appendChild(dom);\n};\n\n\n/**\n * Remove DOM of a given element.\n *\n * @param {SVGElement} element element to remove dom\n */\nDefinable.prototype.removeDom = function (element) {\n    var defs = this.getDefs(false);\n    if (defs && element[this._domName]) {\n        defs.removeChild(element[this._domName]);\n        element[this._domName] = null;\n    }\n};\n\n\n/**\n * Get DOMs of this element.\n *\n * @return {HTMLDomElement} doms of this defineable elements in <defs>\n */\nDefinable.prototype.getDoms = function () {\n    var defs = this.getDefs(false);\n    if (!defs) {\n        // No dom when defs is not defined\n        return [];\n    }\n\n    var doms = [];\n    each$1(this._tagNames, function (tagName) {\n        var tags = defs.getElementsByTagName(tagName);\n        // Note that tags is HTMLCollection, which is array-like\n        // rather than real array.\n        // So `doms.concat(tags)` add tags as one object.\n        doms = doms.concat([].slice.call(tags));\n    });\n\n    return doms;\n};\n\n\n/**\n * Mark DOMs to be unused before painting, and clear unused ones at the end\n * of the painting.\n */\nDefinable.prototype.markAllUnused = function () {\n    var doms = this.getDoms();\n    var that = this;\n    each$1(doms, function (dom) {\n        dom[that._markLabel] = MARK_UNUSED;\n    });\n};\n\n\n/**\n * Mark a single DOM to be used.\n *\n * @param {SVGElement} dom DOM to mark\n */\nDefinable.prototype.markUsed = function (dom) {\n    if (dom) {\n        dom[this._markLabel] = MARK_USED;\n    }\n};\n\n\n/**\n * Remove unused DOMs defined in <defs>\n */\nDefinable.prototype.removeUnused = function () {\n    var defs = this.getDefs(false);\n    if (!defs) {\n        // Nothing to remove\n        return;\n    }\n\n    var doms = this.getDoms();\n    var that = this;\n    each$1(doms, function (dom) {\n        if (dom[that._markLabel] !== MARK_USED) {\n            // Remove gradient\n            defs.removeChild(dom);\n        }\n    });\n};\n\n\n/**\n * Get SVG proxy.\n *\n * @param {Displayable} displayable displayable element\n * @return {Path|Image|Text} svg proxy of given element\n */\nDefinable.prototype.getSvgProxy = function (displayable) {\n    if (displayable instanceof Path) {\n        return svgPath;\n    }\n    else if (displayable instanceof ZImage) {\n        return svgImage;\n    }\n    else if (displayable instanceof Text) {\n        return svgText;\n    }\n    else {\n        return svgPath;\n    }\n};\n\n\n/**\n * Get text SVG element.\n *\n * @param {Displayable} displayable displayable element\n * @return {SVGElement} SVG element of text\n */\nDefinable.prototype.getTextSvgElement = function (displayable) {\n    return displayable.__textSvgEl;\n};\n\n\n/**\n * Get SVG element.\n *\n * @param {Displayable} displayable displayable element\n * @return {SVGElement} SVG element\n */\nDefinable.prototype.getSvgElement = function (displayable) {\n    return displayable.__svgEl;\n};\n\n/**\n * @file Manages SVG gradient elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG gradient elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction GradientManager(zrId, svgRoot) {\n    Definable.call(\n        this,\n        zrId,\n        svgRoot,\n        ['linearGradient', 'radialGradient'],\n        '__gradient_in_use__'\n    );\n}\n\n\ninherits(GradientManager, Definable);\n\n\n/**\n * Create new gradient DOM for fill or stroke if not exist,\n * but will not update gradient if exists.\n *\n * @param {SvgElement}  svgElement   SVG element to paint\n * @param {Displayable} displayable  zrender displayable element\n */\nGradientManager.prototype.addWithoutUpdate = function (\n    svgElement,\n    displayable\n) {\n    if (displayable && displayable.style) {\n        var that = this;\n        each$1(['fill', 'stroke'], function (fillOrStroke) {\n            if (displayable.style[fillOrStroke]\n                && (displayable.style[fillOrStroke].type === 'linear'\n                || displayable.style[fillOrStroke].type === 'radial')\n            ) {\n                var gradient = displayable.style[fillOrStroke];\n                var defs = that.getDefs(true);\n\n                // Create dom in <defs> if not exists\n                var dom;\n                if (gradient._dom) {\n                    // Gradient exists\n                    dom = gradient._dom;\n                    if (!defs.contains(gradient._dom)) {\n                        // _dom is no longer in defs, recreate\n                        that.addDom(dom);\n                    }\n                }\n                else {\n                    // New dom\n                    dom = that.add(gradient);\n                }\n\n                that.markUsed(displayable);\n\n                var id = dom.getAttribute('id');\n                svgElement.setAttribute(fillOrStroke, 'url(#' + id + ')');\n            }\n        });\n    }\n};\n\n\n/**\n * Add a new gradient tag in <defs>\n *\n * @param   {Gradient} gradient zr gradient instance\n * @return {SVGLinearGradientElement | SVGRadialGradientElement}\n *                            created DOM\n */\nGradientManager.prototype.add = function (gradient) {\n    var dom;\n    if (gradient.type === 'linear') {\n        dom = this.createElement('linearGradient');\n    }\n    else if (gradient.type === 'radial') {\n        dom = this.createElement('radialGradient');\n    }\n    else {\n        zrLog('Illegal gradient type.');\n        return null;\n    }\n\n    // Set dom id with gradient id, since each gradient instance\n    // will have no more than one dom element.\n    // id may exists before for those dirty elements, in which case\n    // id should remain the same, and other attributes should be\n    // updated.\n    gradient.id = gradient.id || this.nextId++;\n    dom.setAttribute('id', 'zr' + this._zrId\n        + '-gradient-' + gradient.id);\n\n    this.updateDom(gradient, dom);\n    this.addDom(dom);\n\n    return dom;\n};\n\n\n/**\n * Update gradient.\n *\n * @param {Gradient} gradient zr gradient instance\n */\nGradientManager.prototype.update = function (gradient) {\n    var that = this;\n    Definable.prototype.update.call(this, gradient, function () {\n        var type = gradient.type;\n        var tagName = gradient._dom.tagName;\n        if (type === 'linear' && tagName === 'linearGradient'\n            || type === 'radial' && tagName === 'radialGradient'\n        ) {\n            // Gradient type is not changed, update gradient\n            that.updateDom(gradient, gradient._dom);\n        }\n        else {\n            // Remove and re-create if type is changed\n            that.removeDom(gradient);\n            that.add(gradient);\n        }\n    });\n};\n\n\n/**\n * Update gradient dom\n *\n * @param {Gradient} gradient zr gradient instance\n * @param {SVGLinearGradientElement | SVGRadialGradientElement} dom\n *                            DOM to update\n */\nGradientManager.prototype.updateDom = function (gradient, dom) {\n    if (gradient.type === 'linear') {\n        dom.setAttribute('x1', gradient.x);\n        dom.setAttribute('y1', gradient.y);\n        dom.setAttribute('x2', gradient.x2);\n        dom.setAttribute('y2', gradient.y2);\n    }\n    else if (gradient.type === 'radial') {\n        dom.setAttribute('cx', gradient.x);\n        dom.setAttribute('cy', gradient.y);\n        dom.setAttribute('r', gradient.r);\n    }\n    else {\n        zrLog('Illegal gradient type.');\n        return;\n    }\n\n    if (gradient.global) {\n        // x1, x2, y1, y2 in range of 0 to canvas width or height\n        dom.setAttribute('gradientUnits', 'userSpaceOnUse');\n    }\n    else {\n        // x1, x2, y1, y2 in range of 0 to 1\n        dom.setAttribute('gradientUnits', 'objectBoundingBox');\n    }\n\n    // Remove color stops if exists\n    dom.innerHTML = '';\n\n    // Add color stops\n    var colors = gradient.colorStops;\n    for (var i = 0, len = colors.length; i < len; ++i) {\n        var stop = this.createElement('stop');\n        stop.setAttribute('offset', colors[i].offset * 100 + '%');\n\n        var color = colors[i].color;\n        if (color.indexOf('rgba' > -1)) {\n            // Fix Safari bug that stop-color not recognizing alpha #9014\n            var opacity = parse(color)[3];\n            var hex = toHex(color);\n\n            // stop-color cannot be color, since:\n            // The opacity value used for the gradient calculation is the\n            // *product* of the value of stop-opacity and the opacity of the\n            // value of stop-color.\n            // See https://www.w3.org/TR/SVG2/pservers.html#StopOpacityProperty\n            stop.setAttribute('stop-color', '#' + hex);\n            stop.setAttribute('stop-opacity', opacity);\n        }\n        else {\n            stop.setAttribute('stop-color', colors[i].color);\n        }\n\n        dom.appendChild(stop);\n    }\n\n    // Store dom element in gradient, to avoid creating multiple\n    // dom instances for the same gradient element\n    gradient._dom = dom;\n};\n\n/**\n * Mark a single gradient to be used\n *\n * @param {Displayable} displayable displayable element\n */\nGradientManager.prototype.markUsed = function (displayable) {\n    if (displayable.style) {\n        var gradient = displayable.style.fill;\n        if (gradient && gradient._dom) {\n            Definable.prototype.markUsed.call(this, gradient._dom);\n        }\n\n        gradient = displayable.style.stroke;\n        if (gradient && gradient._dom) {\n            Definable.prototype.markUsed.call(this, gradient._dom);\n        }\n    }\n};\n\n/**\n * @file Manages SVG clipPath elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG clipPath elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction ClippathManager(zrId, svgRoot) {\n    Definable.call(this, zrId, svgRoot, 'clipPath', '__clippath_in_use__');\n}\n\n\ninherits(ClippathManager, Definable);\n\n\n/**\n * Update clipPath.\n *\n * @param {Displayable} displayable displayable element\n */\nClippathManager.prototype.update = function (displayable) {\n    var svgEl = this.getSvgElement(displayable);\n    if (svgEl) {\n        this.updateDom(svgEl, displayable.__clipPaths, false);\n    }\n\n    var textEl = this.getTextSvgElement(displayable);\n    if (textEl) {\n        // Make another clipPath for text, since it's transform\n        // matrix is not the same with svgElement\n        this.updateDom(textEl, displayable.__clipPaths, true);\n    }\n\n    this.markUsed(displayable);\n};\n\n\n/**\n * Create an SVGElement of displayable and create a <clipPath> of its\n * clipPath\n *\n * @param {Displayable} parentEl  parent element\n * @param {ClipPath[]}  clipPaths clipPaths of parent element\n * @param {boolean}     isText    if parent element is Text\n */\nClippathManager.prototype.updateDom = function (\n    parentEl,\n    clipPaths,\n    isText\n) {\n    if (clipPaths && clipPaths.length > 0) {\n        // Has clipPath, create <clipPath> with the first clipPath\n        var defs = this.getDefs(true);\n        var clipPath = clipPaths[0];\n        var clipPathEl;\n        var id;\n\n        var dom = isText ? '_textDom' : '_dom';\n\n        if (clipPath[dom]) {\n            // Use a dom that is already in <defs>\n            id = clipPath[dom].getAttribute('id');\n            clipPathEl = clipPath[dom];\n\n            // Use a dom that is already in <defs>\n            if (!defs.contains(clipPathEl)) {\n                // This happens when set old clipPath that has\n                // been previously removed\n                defs.appendChild(clipPathEl);\n            }\n        }\n        else {\n            // New <clipPath>\n            id = 'zr' + this._zrId + '-clip-' + this.nextId;\n            ++this.nextId;\n            clipPathEl = this.createElement('clipPath');\n            clipPathEl.setAttribute('id', id);\n            defs.appendChild(clipPathEl);\n\n            clipPath[dom] = clipPathEl;\n        }\n\n        // Build path and add to <clipPath>\n        var svgProxy = this.getSvgProxy(clipPath);\n        if (clipPath.transform\n            && clipPath.parent.invTransform\n            && !isText\n        ) {\n            /**\n             * If a clipPath has a parent with transform, the transform\n             * of parent should not be considered when setting transform\n             * of clipPath. So we need to transform back from parent's\n             * transform, which is done by multiplying parent's inverse\n             * transform.\n             */\n            // Store old transform\n            var transform = Array.prototype.slice.call(\n                clipPath.transform\n            );\n\n            // Transform back from parent, and brush path\n            mul$1(\n                clipPath.transform,\n                clipPath.parent.invTransform,\n                clipPath.transform\n            );\n            svgProxy.brush(clipPath);\n\n            // Set back transform of clipPath\n            clipPath.transform = transform;\n        }\n        else {\n            svgProxy.brush(clipPath);\n        }\n\n        var pathEl = this.getSvgElement(clipPath);\n\n        clipPathEl.innerHTML = '';\n        /**\n         * Use `cloneNode()` here to appendChild to multiple parents,\n         * which may happend when Text and other shapes are using the same\n         * clipPath. Since Text will create an extra clipPath DOM due to\n         * different transform rules.\n         */\n        clipPathEl.appendChild(pathEl.cloneNode());\n\n        parentEl.setAttribute('clip-path', 'url(#' + id + ')');\n\n        if (clipPaths.length > 1) {\n            // Make the other clipPaths recursively\n            this.updateDom(clipPathEl, clipPaths.slice(1), isText);\n        }\n    }\n    else {\n        // No clipPath\n        if (parentEl) {\n            parentEl.setAttribute('clip-path', 'none');\n        }\n    }\n};\n\n/**\n * Mark a single clipPath to be used\n *\n * @param {Displayable} displayable displayable element\n */\nClippathManager.prototype.markUsed = function (displayable) {\n    var that = this;\n    if (displayable.__clipPaths && displayable.__clipPaths.length > 0) {\n        each$1(displayable.__clipPaths, function (clipPath) {\n            if (clipPath._dom) {\n                Definable.prototype.markUsed.call(that, clipPath._dom);\n            }\n            if (clipPath._textDom) {\n                Definable.prototype.markUsed.call(that, clipPath._textDom);\n            }\n        });\n    }\n};\n\n/**\n * @file Manages SVG shadow elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG shadow elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction ShadowManager(zrId, svgRoot) {\n    Definable.call(\n        this,\n        zrId,\n        svgRoot,\n        ['filter'],\n        '__filter_in_use__',\n        '_shadowDom'\n    );\n}\n\n\ninherits(ShadowManager, Definable);\n\n\n/**\n * Create new shadow DOM for fill or stroke if not exist,\n * but will not update shadow if exists.\n *\n * @param {SvgElement}  svgElement   SVG element to paint\n * @param {Displayable} displayable  zrender displayable element\n */\nShadowManager.prototype.addWithoutUpdate = function (\n    svgElement,\n    displayable\n) {\n    if (displayable && hasShadow(displayable.style)) {\n        var style = displayable.style;\n\n        // Create dom in <defs> if not exists\n        var dom;\n        if (style._shadowDom) {\n            // Gradient exists\n            dom = style._shadowDom;\n\n            var defs = this.getDefs(true);\n            if (!defs.contains(style._shadowDom)) {\n                // _shadowDom is no longer in defs, recreate\n                this.addDom(dom);\n            }\n        }\n        else {\n            // New dom\n            dom = this.add(displayable);\n        }\n\n        this.markUsed(displayable);\n\n        var id = dom.getAttribute('id');\n        svgElement.style.filter = 'url(#' + id + ')';\n    }\n};\n\n\n/**\n * Add a new shadow tag in <defs>\n *\n * @param {Displayable} displayable  zrender displayable element\n * @return {SVGFilterElement} created DOM\n */\nShadowManager.prototype.add = function (displayable) {\n    var dom = this.createElement('filter');\n    var style = displayable.style;\n\n    // Set dom id with shadow id, since each shadow instance\n    // will have no more than one dom element.\n    // id may exists before for those dirty elements, in which case\n    // id should remain the same, and other attributes should be\n    // updated.\n    style._shadowDomId = style._shadowDomId || this.nextId++;\n    dom.setAttribute('id', 'zr' + this._zrId\n        + '-shadow-' + style._shadowDomId);\n\n    this.updateDom(displayable, dom);\n    this.addDom(dom);\n\n    return dom;\n};\n\n\n/**\n * Update shadow.\n *\n * @param {Displayable} displayable  zrender displayable element\n */\nShadowManager.prototype.update = function (svgElement, displayable) {\n    var style = displayable.style;\n    if (hasShadow(style)) {\n        var that = this;\n        Definable.prototype.update.call(this, displayable, function (style) {\n            that.updateDom(displayable, style._shadowDom);\n        });\n    }\n    else {\n        // Remove shadow\n        this.remove(svgElement, style);\n    }\n};\n\n\n/**\n * Remove DOM and clear parent filter\n */\nShadowManager.prototype.remove = function (svgElement, style) {\n    if (style._shadowDomId != null) {\n        this.removeDom(style);\n        svgElement.style.filter = '';\n    }\n};\n\n\n/**\n * Update shadow dom\n *\n * @param {Displayable} displayable  zrender displayable element\n * @param {SVGFilterElement} dom DOM to update\n */\nShadowManager.prototype.updateDom = function (displayable, dom) {\n    var domChild = dom.getElementsByTagName('feDropShadow');\n    if (domChild.length === 0) {\n        domChild = this.createElement('feDropShadow');\n    }\n    else {\n        domChild = domChild[0];\n    }\n\n    var style = displayable.style;\n    var scaleX = displayable.scale ? (displayable.scale[0] || 1) : 1;\n    var scaleY = displayable.scale ? (displayable.scale[1] || 1) : 1;\n\n    // TODO: textBoxShadowBlur is not supported yet\n    var offsetX, offsetY, blur, color;\n    if (style.shadowBlur || style.shadowOffsetX || style.shadowOffsetY) {\n        offsetX = style.shadowOffsetX || 0;\n        offsetY = style.shadowOffsetY || 0;\n        blur = style.shadowBlur;\n        color = style.shadowColor;\n    }\n    else if (style.textShadowBlur) {\n        offsetX = style.textShadowOffsetX || 0;\n        offsetY = style.textShadowOffsetY || 0;\n        blur = style.textShadowBlur;\n        color = style.textShadowColor;\n    }\n    else {\n        // Remove shadow\n        this.removeDom(dom, style);\n        return;\n    }\n\n    domChild.setAttribute('dx', offsetX / scaleX);\n    domChild.setAttribute('dy', offsetY / scaleY);\n    domChild.setAttribute('flood-color', color);\n\n    // Divide by two here so that it looks the same as in canvas\n    // See: https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-shadowblur\n    var stdDx = blur / 2 / scaleX;\n    var stdDy = blur / 2 / scaleY;\n    var stdDeviation = stdDx + ' ' + stdDy;\n    domChild.setAttribute('stdDeviation', stdDeviation);\n\n    // Fix filter clipping problem\n    dom.setAttribute('x', '-100%');\n    dom.setAttribute('y', '-100%');\n    dom.setAttribute('width', Math.ceil(blur / 2 * 200) + '%');\n    dom.setAttribute('height', Math.ceil(blur / 2 * 200) + '%');\n\n    dom.appendChild(domChild);\n\n    // Store dom element in shadow, to avoid creating multiple\n    // dom instances for the same shadow element\n    style._shadowDom = dom;\n};\n\n/**\n * Mark a single shadow to be used\n *\n * @param {Displayable} displayable displayable element\n */\nShadowManager.prototype.markUsed = function (displayable) {\n    var style = displayable.style;\n    if (style && style._shadowDom) {\n        Definable.prototype.markUsed.call(this, style._shadowDom);\n    }\n};\n\nfunction hasShadow(style) {\n    // TODO: textBoxShadowBlur is not supported yet\n    return style\n        && (style.shadowBlur || style.shadowOffsetX || style.shadowOffsetY\n            || style.textShadowBlur || style.textShadowOffsetX\n            || style.textShadowOffsetY);\n}\n\n/**\n * SVG Painter\n * @module zrender/svg/Painter\n */\n\nfunction parseInt10$2(val) {\n    return parseInt(val, 10);\n}\n\nfunction getSvgProxy(el) {\n    if (el instanceof Path) {\n        return svgPath;\n    }\n    else if (el instanceof ZImage) {\n        return svgImage;\n    }\n    else if (el instanceof Text) {\n        return svgText;\n    }\n    else {\n        return svgPath;\n    }\n}\n\nfunction checkParentAvailable(parent, child) {\n    return child && parent && child.parentNode !== parent;\n}\n\nfunction insertAfter(parent, child, prevSibling) {\n    if (checkParentAvailable(parent, child) && prevSibling) {\n        var nextSibling = prevSibling.nextSibling;\n        nextSibling ? parent.insertBefore(child, nextSibling)\n            : parent.appendChild(child);\n    }\n}\n\nfunction prepend(parent, child) {\n    if (checkParentAvailable(parent, child)) {\n        var firstChild = parent.firstChild;\n        firstChild ? parent.insertBefore(child, firstChild)\n            : parent.appendChild(child);\n    }\n}\n\nfunction remove$1(parent, child) {\n    if (child && parent && child.parentNode === parent) {\n        parent.removeChild(child);\n    }\n}\n\nfunction getTextSvgElement(displayable) {\n    return displayable.__textSvgEl;\n}\n\nfunction getSvgElement(displayable) {\n    return displayable.__svgEl;\n}\n\n/**\n * @alias module:zrender/svg/Painter\n * @constructor\n * @param {HTMLElement} root 绘图容器\n * @param {module:zrender/Storage} storage\n * @param {Object} opts\n */\nvar SVGPainter = function (root, storage, opts, zrId) {\n\n    this.root = root;\n    this.storage = storage;\n    this._opts = opts = extend({}, opts || {});\n\n    var svgRoot = createElement('svg');\n    svgRoot.setAttribute('xmlns', 'http://www.w3.org/2000/svg');\n    svgRoot.setAttribute('version', '1.1');\n    svgRoot.setAttribute('baseProfile', 'full');\n    svgRoot.style.cssText = 'user-select:none;position:absolute;left:0;top:0;';\n\n    this.gradientManager = new GradientManager(zrId, svgRoot);\n    this.clipPathManager = new ClippathManager(zrId, svgRoot);\n    this.shadowManager = new ShadowManager(zrId, svgRoot);\n\n    var viewport = document.createElement('div');\n    viewport.style.cssText = 'overflow:hidden;position:relative';\n\n    this._svgRoot = svgRoot;\n    this._viewport = viewport;\n\n    root.appendChild(viewport);\n    viewport.appendChild(svgRoot);\n\n    this.resize(opts.width, opts.height);\n\n    this._visibleList = [];\n};\n\nSVGPainter.prototype = {\n\n    constructor: SVGPainter,\n\n    getType: function () {\n        return 'svg';\n    },\n\n    getViewportRoot: function () {\n        return this._viewport;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    refresh: function () {\n\n        var list = this.storage.getDisplayList(true);\n\n        this._paintList(list);\n    },\n\n    setBackgroundColor: function (backgroundColor) {\n        // TODO gradient\n        this._viewport.style.background = backgroundColor;\n    },\n\n    _paintList: function (list) {\n        this.gradientManager.markAllUnused();\n        this.clipPathManager.markAllUnused();\n        this.shadowManager.markAllUnused();\n\n        var svgRoot = this._svgRoot;\n        var visibleList = this._visibleList;\n        var listLen = list.length;\n\n        var newVisibleList = [];\n        var i;\n        for (i = 0; i < listLen; i++) {\n            var displayable = list[i];\n            var svgProxy = getSvgProxy(displayable);\n            var svgElement = getSvgElement(displayable)\n                || getTextSvgElement(displayable);\n            if (!displayable.invisible) {\n                if (displayable.__dirty) {\n                    svgProxy && svgProxy.brush(displayable);\n\n                    // Update clipPath\n                    this.clipPathManager.update(displayable);\n\n                    // Update gradient and shadow\n                    if (displayable.style) {\n                        this.gradientManager\n                            .update(displayable.style.fill);\n                        this.gradientManager\n                            .update(displayable.style.stroke);\n\n                        this.shadowManager\n                            .update(svgElement, displayable);\n                    }\n\n                    displayable.__dirty = false;\n                }\n                newVisibleList.push(displayable);\n            }\n        }\n\n        var diff = arrayDiff$1(visibleList, newVisibleList);\n        var prevSvgElement;\n\n        // First do remove, in case element moved to the head and do remove\n        // after add\n        for (i = 0; i < diff.length; i++) {\n            var item = diff[i];\n            if (item.removed) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = visibleList[item.indices[k]];\n                    var svgElement = getSvgElement(displayable);\n                    var textSvgElement = getTextSvgElement(displayable);\n                    remove$1(svgRoot, svgElement);\n                    remove$1(svgRoot, textSvgElement);\n                }\n            }\n        }\n        for (i = 0; i < diff.length; i++) {\n            var item = diff[i];\n            if (item.added) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = newVisibleList[item.indices[k]];\n                    var svgElement = getSvgElement(displayable);\n                    var textSvgElement = getTextSvgElement(displayable);\n                    prevSvgElement\n                        ? insertAfter(svgRoot, svgElement, prevSvgElement)\n                        : prepend(svgRoot, svgElement);\n                    if (svgElement) {\n                        insertAfter(svgRoot, textSvgElement, svgElement);\n                    }\n                    else if (prevSvgElement) {\n                        insertAfter(\n                            svgRoot, textSvgElement, prevSvgElement\n                        );\n                    }\n                    else {\n                        prepend(svgRoot, textSvgElement);\n                    }\n                    // Insert text\n                    insertAfter(svgRoot, textSvgElement, svgElement);\n                    prevSvgElement = textSvgElement || svgElement\n                        || prevSvgElement;\n\n                    this.gradientManager\n                        .addWithoutUpdate(svgElement, displayable);\n                    this.shadowManager\n                        .addWithoutUpdate(prevSvgElement, displayable);\n                    this.clipPathManager.markUsed(displayable);\n                }\n            }\n            else if (!item.removed) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = newVisibleList[item.indices[k]];\n                    prevSvgElement =\n                        svgElement =\n                        getTextSvgElement(displayable)\n                        || getSvgElement(displayable)\n                        || prevSvgElement;\n\n                    this.gradientManager.markUsed(displayable);\n                    this.gradientManager\n                        .addWithoutUpdate(svgElement, displayable);\n\n                    this.shadowManager.markUsed(displayable);\n                    this.shadowManager\n                        .addWithoutUpdate(svgElement, displayable);\n\n                    this.clipPathManager.markUsed(displayable);\n                }\n            }\n        }\n\n        this.gradientManager.removeUnused();\n        this.clipPathManager.removeUnused();\n        this.shadowManager.removeUnused();\n\n        this._visibleList = newVisibleList;\n    },\n\n    _getDefs: function (isForceCreating) {\n        var svgRoot = this._svgRoot;\n        var defs = this._svgRoot.getElementsByTagName('defs');\n        if (defs.length === 0) {\n            // Not exist\n            if (isForceCreating) {\n                var defs = svgRoot.insertBefore(\n                    createElement('defs'), // Create new tag\n                    svgRoot.firstChild // Insert in the front of svg\n                );\n                if (!defs.contains) {\n                    // IE doesn't support contains method\n                    defs.contains = function (el) {\n                        var children = defs.children;\n                        if (!children) {\n                            return false;\n                        }\n                        for (var i = children.length - 1; i >= 0; --i) {\n                            if (children[i] === el) {\n                                return true;\n                            }\n                        }\n                        return false;\n                    };\n                }\n                return defs;\n            }\n            else {\n                return null;\n            }\n        }\n        else {\n            return defs[0];\n        }\n    },\n\n    resize: function (width, height) {\n        var viewport = this._viewport;\n        // FIXME Why ?\n        viewport.style.display = 'none';\n\n        // Save input w/h\n        var opts = this._opts;\n        width != null && (opts.width = width);\n        height != null && (opts.height = height);\n\n        width = this._getSize(0);\n        height = this._getSize(1);\n\n        viewport.style.display = '';\n\n        if (this._width !== width || this._height !== height) {\n            this._width = width;\n            this._height = height;\n\n            var viewportStyle = viewport.style;\n            viewportStyle.width = width + 'px';\n            viewportStyle.height = height + 'px';\n\n            var svgRoot = this._svgRoot;\n            // Set width by 'svgRoot.width = width' is invalid\n            svgRoot.setAttribute('width', width);\n            svgRoot.setAttribute('height', height);\n        }\n    },\n\n    /**\n     * 获取绘图区域宽度\n     */\n    getWidth: function () {\n        return this._width;\n    },\n\n    /**\n     * 获取绘图区域高度\n     */\n    getHeight: function () {\n        return this._height;\n    },\n\n    _getSize: function (whIdx) {\n        var opts = this._opts;\n        var wh = ['width', 'height'][whIdx];\n        var cwh = ['clientWidth', 'clientHeight'][whIdx];\n        var plt = ['paddingLeft', 'paddingTop'][whIdx];\n        var prb = ['paddingRight', 'paddingBottom'][whIdx];\n\n        if (opts[wh] != null && opts[wh] !== 'auto') {\n            return parseFloat(opts[wh]);\n        }\n\n        var root = this.root;\n        // IE8 does not support getComputedStyle, but it use VML.\n        var stl = document.defaultView.getComputedStyle(root);\n\n        return (\n            (root[cwh] || parseInt10$2(stl[wh]) || parseInt10$2(root.style[wh]))\n            - (parseInt10$2(stl[plt]) || 0)\n            - (parseInt10$2(stl[prb]) || 0)\n        ) | 0;\n    },\n\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this._svgRoot =\n            this._viewport =\n            this.storage =\n            null;\n    },\n\n    clear: function () {\n        if (this._viewport) {\n            this.root.removeChild(this._viewport);\n        }\n    },\n\n    pathToDataUrl: function () {\n        this.refresh();\n        var html = this._svgRoot.outerHTML;\n        return 'data:image/svg+xml;charset=UTF-8,' + html;\n    }\n};\n\n// Not supported methods\nfunction createMethodNotSupport$1(method) {\n    return function () {\n        zrLog('In SVG mode painter not support method \"' + method + '\"');\n    };\n}\n\n// Unsuppoted methods\neach$1([\n    'getLayer', 'insertLayer', 'eachLayer', 'eachBuiltinLayer',\n    'eachOtherLayer', 'getLayers', 'modLayer', 'delLayer', 'clearLayer',\n    'toDataURL', 'pathToImage'\n], function (name) {\n    SVGPainter.prototype[name] = createMethodNotSupport$1(name);\n});\n\nregisterPainter('svg', SVGPainter);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Import all charts and components\n\nexports.version = version;\nexports.dependencies = dependencies;\nexports.PRIORITY = PRIORITY;\nexports.init = init;\nexports.connect = connect;\nexports.disConnect = disConnect;\nexports.disconnect = disconnect;\nexports.dispose = dispose;\nexports.getInstanceByDom = getInstanceByDom;\nexports.getInstanceById = getInstanceById;\nexports.registerTheme = registerTheme;\nexports.registerPreprocessor = registerPreprocessor;\nexports.registerProcessor = registerProcessor;\nexports.registerPostUpdate = registerPostUpdate;\nexports.registerAction = registerAction;\nexports.registerCoordinateSystem = registerCoordinateSystem;\nexports.getCoordinateSystemDimensions = getCoordinateSystemDimensions;\nexports.registerLayout = registerLayout;\nexports.registerVisual = registerVisual;\nexports.registerLoading = registerLoading;\nexports.extendComponentModel = extendComponentModel;\nexports.extendComponentView = extendComponentView;\nexports.extendSeriesModel = extendSeriesModel;\nexports.extendChartView = extendChartView;\nexports.setCanvasCreator = setCanvasCreator;\nexports.registerMap = registerMap;\nexports.getMap = getMap;\nexports.dataTool = dataTool;\nexports.zrender = zrender;\nexports.number = number;\nexports.format = format;\nexports.throttle = throttle;\nexports.helper = helper;\nexports.matrix = matrix;\nexports.vector = vector;\nexports.color = color;\nexports.parseGeoJSON = parseGeoJson$1;\nexports.parseGeoJson = parseGeoJson;\nexports.util = ecUtil;\nexports.graphic = graphic$1;\nexports.List = List;\nexports.Model = Model;\nexports.Axis = Axis;\nexports.env = env$1;\n\n})));\n//# sourceMappingURL=echarts-en.js.map\n"
  },
  {
    "path": "static/js/Echarts/echarts-en.simple.js",
    "content": "(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n\ttypeof define === 'function' && define.amd ? define(['exports'], factory) :\n\t(factory((global.echarts = {})));\n}(this, (function (exports) { 'use strict';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (1) The code `if (__DEV__) ...` can be removed by build tool.\n// (2) If intend to use `__DEV__`, this module should be imported. Use a global\n// variable `__DEV__` may cause that miss the declaration (see #6535), or the\n// declaration is behind of the using position (for example in `Model.extent`,\n// And tools like rollup can not analysis the dependency if not import).\n\nvar dev;\n\n// In browser\nif (typeof window !== 'undefined') {\n    dev = window.__DEV__;\n}\n// In node\nelse if (typeof global !== 'undefined') {\n    dev = global.__DEV__;\n}\n\nif (typeof dev === 'undefined') {\n    dev = true;\n}\n\nvar __DEV__ = dev;\n\n/**\n * zrender: 生成唯一id\n *\n * @author errorrik (errorrik@gmail.com)\n */\n\nvar idStart = 0x0907;\n\nvar guid = function () {\n    return idStart++;\n};\n\n/**\n * echarts设备环境识别\n *\n * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。\n * @author firede[firede@firede.us]\n * @desc thanks zepto.\n */\n\nvar env = {};\n\nif (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') {\n    // In Weixin Application\n    env = {\n        browser: {},\n        os: {},\n        node: false,\n        wxa: true, // Weixin Application\n        canvasSupported: true,\n        svgSupported: false,\n        touchEventsSupported: true,\n        domSupported: false\n    };\n}\nelse if (typeof document === 'undefined' && typeof self !== 'undefined') {\n    // In worker\n    env = {\n        browser: {},\n        os: {},\n        node: false,\n        worker: true,\n        canvasSupported: true,\n        domSupported: false\n    };\n}\nelse if (typeof navigator === 'undefined') {\n    // In node\n    env = {\n        browser: {},\n        os: {},\n        node: true,\n        worker: false,\n        // Assume canvas is supported\n        canvasSupported: true,\n        svgSupported: true,\n        domSupported: false\n    };\n}\nelse {\n    env = detect(navigator.userAgent);\n}\n\nvar env$1 = env;\n\n// Zepto.js\n// (c) 2010-2013 Thomas Fuchs\n// Zepto.js may be freely distributed under the MIT license.\n\nfunction detect(ua) {\n    var os = {};\n    var browser = {};\n    // var webkit = ua.match(/Web[kK]it[\\/]{0,1}([\\d.]+)/);\n    // var android = ua.match(/(Android);?[\\s\\/]+([\\d.]+)?/);\n    // var ipad = ua.match(/(iPad).*OS\\s([\\d_]+)/);\n    // var ipod = ua.match(/(iPod)(.*OS\\s([\\d_]+))?/);\n    // var iphone = !ipad && ua.match(/(iPhone\\sOS)\\s([\\d_]+)/);\n    // var webos = ua.match(/(webOS|hpwOS)[\\s\\/]([\\d.]+)/);\n    // var touchpad = webos && ua.match(/TouchPad/);\n    // var kindle = ua.match(/Kindle\\/([\\d.]+)/);\n    // var silk = ua.match(/Silk\\/([\\d._]+)/);\n    // var blackberry = ua.match(/(BlackBerry).*Version\\/([\\d.]+)/);\n    // var bb10 = ua.match(/(BB10).*Version\\/([\\d.]+)/);\n    // var rimtabletos = ua.match(/(RIM\\sTablet\\sOS)\\s([\\d.]+)/);\n    // var playbook = ua.match(/PlayBook/);\n    // var chrome = ua.match(/Chrome\\/([\\d.]+)/) || ua.match(/CriOS\\/([\\d.]+)/);\n    var firefox = ua.match(/Firefox\\/([\\d.]+)/);\n    // var safari = webkit && ua.match(/Mobile\\//) && !chrome;\n    // var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome;\n    var ie = ua.match(/MSIE\\s([\\d.]+)/)\n        // IE 11 Trident/7.0; rv:11.0\n        || ua.match(/Trident\\/.+?rv:(([\\d.]+))/);\n    var edge = ua.match(/Edge\\/([\\d.]+)/); // IE 12 and 12+\n\n    var weChat = (/micromessenger/i).test(ua);\n\n    // Todo: clean this up with a better OS/browser seperation:\n    // - discern (more) between multiple browsers on android\n    // - decide if kindle fire in silk mode is android or not\n    // - Firefox on Android doesn't specify the Android version\n    // - possibly devide in os, device and browser hashes\n\n    // if (browser.webkit = !!webkit) browser.version = webkit[1];\n\n    // if (android) os.android = true, os.version = android[2];\n    // if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.');\n    // if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.');\n    // if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null;\n    // if (webos) os.webos = true, os.version = webos[2];\n    // if (touchpad) os.touchpad = true;\n    // if (blackberry) os.blackberry = true, os.version = blackberry[2];\n    // if (bb10) os.bb10 = true, os.version = bb10[2];\n    // if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2];\n    // if (playbook) browser.playbook = true;\n    // if (kindle) os.kindle = true, os.version = kindle[1];\n    // if (silk) browser.silk = true, browser.version = silk[1];\n    // if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true;\n    // if (chrome) browser.chrome = true, browser.version = chrome[1];\n    if (firefox) {\n        browser.firefox = true;\n        browser.version = firefox[1];\n    }\n    // if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true;\n    // if (webview) browser.webview = true;\n\n    if (ie) {\n        browser.ie = true;\n        browser.version = ie[1];\n    }\n\n    if (edge) {\n        browser.edge = true;\n        browser.version = edge[1];\n    }\n\n    // It is difficult to detect WeChat in Win Phone precisely, because ua can\n    // not be set on win phone. So we do not consider Win Phone.\n    if (weChat) {\n        browser.weChat = true;\n    }\n\n    // os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) ||\n    //     (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/)));\n    // os.phone  = !!(!os.tablet && !os.ipod && (android || iphone || webos ||\n    //     (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\\/([\\d.]+)/)) ||\n    //     (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/))));\n\n    return {\n        browser: browser,\n        os: os,\n        node: false,\n        // 原生canvas支持，改极端点了\n        // canvasSupported : !(browser.ie && parseFloat(browser.version) < 9)\n        canvasSupported: !!document.createElement('canvas').getContext,\n        svgSupported: typeof SVGRect !== 'undefined',\n        // works on most browsers\n        // IE10/11 does not support touch event, and MS Edge supports them but not by\n        // default, so we dont check navigator.maxTouchPoints for them here.\n        touchEventsSupported: 'ontouchstart' in window && !browser.ie && !browser.edge,\n        // <http://caniuse.com/#search=pointer%20event>.\n        pointerEventsSupported: 'onpointerdown' in window\n            // Firefox supports pointer but not by default, only MS browsers are reliable on pointer\n            // events currently. So we dont use that on other browsers unless tested sufficiently.\n            // Although IE 10 supports pointer event, it use old style and is different from the\n            // standard. So we exclude that. (IE 10 is hardly used on touch device)\n            && (browser.edge || (browser.ie && browser.version >= 11)),\n        // passiveSupported: detectPassiveSupport()\n        domSupported: typeof document !== 'undefined'\n    };\n}\n\n// See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection\n// function detectPassiveSupport() {\n//     // Test via a getter in the options object to see if the passive property is accessed\n//     var supportsPassive = false;\n//     try {\n//         var opts = Object.defineProperty({}, 'passive', {\n//             get: function() {\n//                 supportsPassive = true;\n//             }\n//         });\n//         window.addEventListener('testPassive', function() {}, opts);\n//     } catch (e) {\n//     }\n//     return supportsPassive;\n// }\n\n/**\n * @module zrender/core/util\n */\n\n// 用于处理merge时无法遍历Date等对象的问题\nvar BUILTIN_OBJECT = {\n    '[object Function]': 1,\n    '[object RegExp]': 1,\n    '[object Date]': 1,\n    '[object Error]': 1,\n    '[object CanvasGradient]': 1,\n    '[object CanvasPattern]': 1,\n    // For node-canvas\n    '[object Image]': 1,\n    '[object Canvas]': 1\n};\n\nvar TYPED_ARRAY = {\n    '[object Int8Array]': 1,\n    '[object Uint8Array]': 1,\n    '[object Uint8ClampedArray]': 1,\n    '[object Int16Array]': 1,\n    '[object Uint16Array]': 1,\n    '[object Int32Array]': 1,\n    '[object Uint32Array]': 1,\n    '[object Float32Array]': 1,\n    '[object Float64Array]': 1\n};\n\nvar objToString = Object.prototype.toString;\n\nvar arrayProto = Array.prototype;\nvar nativeForEach = arrayProto.forEach;\nvar nativeFilter = arrayProto.filter;\nvar nativeSlice = arrayProto.slice;\nvar nativeMap = arrayProto.map;\nvar nativeReduce = arrayProto.reduce;\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar methods = {};\n\nfunction $override(name, fn) {\n    // Clear ctx instance for different environment\n    if (name === 'createCanvas') {\n        _ctx = null;\n    }\n\n    methods[name] = fn;\n}\n\n/**\n * Those data types can be cloned:\n *     Plain object, Array, TypedArray, number, string, null, undefined.\n * Those data types will be assgined using the orginal data:\n *     BUILTIN_OBJECT\n * Instance of user defined class will be cloned to a plain object, without\n * properties in prototype.\n * Other data types is not supported (not sure what will happen).\n *\n * Caution: do not support clone Date, for performance consideration.\n * (There might be a large number of date in `series.data`).\n * So date should not be modified in and out of echarts.\n *\n * @param {*} source\n * @return {*} new\n */\nfunction clone(source) {\n    if (source == null || typeof source !== 'object') {\n        return source;\n    }\n\n    var result = source;\n    var typeStr = objToString.call(source);\n\n    if (typeStr === '[object Array]') {\n        if (!isPrimitive(source)) {\n            result = [];\n            for (var i = 0, len = source.length; i < len; i++) {\n                result[i] = clone(source[i]);\n            }\n        }\n    }\n    else if (TYPED_ARRAY[typeStr]) {\n        if (!isPrimitive(source)) {\n            var Ctor = source.constructor;\n            if (source.constructor.from) {\n                result = Ctor.from(source);\n            }\n            else {\n                result = new Ctor(source.length);\n                for (var i = 0, len = source.length; i < len; i++) {\n                    result[i] = clone(source[i]);\n                }\n            }\n        }\n    }\n    else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) {\n        result = {};\n        for (var key in source) {\n            if (source.hasOwnProperty(key)) {\n                result[key] = clone(source[key]);\n            }\n        }\n    }\n\n    return result;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overwrite=false]\n */\nfunction merge(target, source, overwrite) {\n    // We should escapse that source is string\n    // and enter for ... in ...\n    if (!isObject$1(source) || !isObject$1(target)) {\n        return overwrite ? clone(source) : target;\n    }\n\n    for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n            var targetProp = target[key];\n            var sourceProp = source[key];\n\n            if (isObject$1(sourceProp)\n                && isObject$1(targetProp)\n                && !isArray(sourceProp)\n                && !isArray(targetProp)\n                && !isDom(sourceProp)\n                && !isDom(targetProp)\n                && !isBuiltInObject(sourceProp)\n                && !isBuiltInObject(targetProp)\n                && !isPrimitive(sourceProp)\n                && !isPrimitive(targetProp)\n            ) {\n                // 如果需要递归覆盖，就递归调用merge\n                merge(targetProp, sourceProp, overwrite);\n            }\n            else if (overwrite || !(key in target)) {\n                // 否则只处理overwrite为true，或者在目标对象中没有此属性的情况\n                // NOTE，在 target[key] 不存在的时候也是直接覆盖\n                target[key] = clone(source[key], true);\n            }\n        }\n    }\n\n    return target;\n}\n\n/**\n * @param {Array} targetAndSources The first item is target, and the rests are source.\n * @param {boolean} [overwrite=false]\n * @return {*} target\n */\nfunction mergeAll(targetAndSources, overwrite) {\n    var result = targetAndSources[0];\n    for (var i = 1, len = targetAndSources.length; i < len; i++) {\n        result = merge(result, targetAndSources[i], overwrite);\n    }\n    return result;\n}\n\n/**\n * @param {*} target\n * @param {*} source\n * @memberOf module:zrender/core/util\n */\nfunction extend(target, source) {\n    for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n            target[key] = source[key];\n        }\n    }\n    return target;\n}\n\n/**\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overlay=false]\n * @memberOf module:zrender/core/util\n */\nfunction defaults(target, source, overlay) {\n    for (var key in source) {\n        if (source.hasOwnProperty(key)\n            && (overlay ? source[key] != null : target[key] == null)\n        ) {\n            target[key] = source[key];\n        }\n    }\n    return target;\n}\n\nvar createCanvas = function () {\n    return methods.createCanvas();\n};\n\nmethods.createCanvas = function () {\n    return document.createElement('canvas');\n};\n\n// FIXME\nvar _ctx;\n\nfunction getContext() {\n    if (!_ctx) {\n        // Use util.createCanvas instead of createCanvas\n        // because createCanvas may be overwritten in different environment\n        _ctx = createCanvas().getContext('2d');\n    }\n    return _ctx;\n}\n\n/**\n * 查询数组中元素的index\n * @memberOf module:zrender/core/util\n */\nfunction indexOf(array, value) {\n    if (array) {\n        if (array.indexOf) {\n            return array.indexOf(value);\n        }\n        for (var i = 0, len = array.length; i < len; i++) {\n            if (array[i] === value) {\n                return i;\n            }\n        }\n    }\n    return -1;\n}\n\n/**\n * 构造类继承关系\n *\n * @memberOf module:zrender/core/util\n * @param {Function} clazz 源类\n * @param {Function} baseClazz 基类\n */\nfunction inherits(clazz, baseClazz) {\n    var clazzPrototype = clazz.prototype;\n    function F() {}\n    F.prototype = baseClazz.prototype;\n    clazz.prototype = new F();\n\n    for (var prop in clazzPrototype) {\n        clazz.prototype[prop] = clazzPrototype[prop];\n    }\n    clazz.prototype.constructor = clazz;\n    clazz.superClass = baseClazz;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Object|Function} target\n * @param {Object|Function} sorce\n * @param {boolean} overlay\n */\nfunction mixin(target, source, overlay) {\n    target = 'prototype' in target ? target.prototype : target;\n    source = 'prototype' in source ? source.prototype : source;\n\n    defaults(target, source, overlay);\n}\n\n/**\n * Consider typed array.\n * @param {Array|TypedArray} data\n */\nfunction isArrayLike(data) {\n    if (!data) {\n        return;\n    }\n    if (typeof data === 'string') {\n        return false;\n    }\n    return typeof data.length === 'number';\n}\n\n/**\n * 数组或对象遍历\n * @memberOf module:zrender/core/util\n * @param {Object|Array} obj\n * @param {Function} cb\n * @param {*} [context]\n */\nfunction each$1(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.forEach && obj.forEach === nativeForEach) {\n        obj.forEach(cb, context);\n    }\n    else if (obj.length === +obj.length) {\n        for (var i = 0, len = obj.length; i < len; i++) {\n            cb.call(context, obj[i], i, obj);\n        }\n    }\n    else {\n        for (var key in obj) {\n            if (obj.hasOwnProperty(key)) {\n                cb.call(context, obj[key], key, obj);\n            }\n        }\n    }\n}\n\n/**\n * 数组映射\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction map(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.map && obj.map === nativeMap) {\n        return obj.map(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            result.push(cb.call(context, obj[i], i, obj));\n        }\n        return result;\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {Object} [memo]\n * @param {*} [context]\n * @return {Array}\n */\nfunction reduce(obj, cb, memo, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.reduce && obj.reduce === nativeReduce) {\n        return obj.reduce(cb, memo, context);\n    }\n    else {\n        for (var i = 0, len = obj.length; i < len; i++) {\n            memo = cb.call(context, memo, obj[i], i, obj);\n        }\n        return memo;\n    }\n}\n\n/**\n * 数组过滤\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction filter(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.filter && obj.filter === nativeFilter) {\n        return obj.filter(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            if (cb.call(context, obj[i], i, obj)) {\n                result.push(obj[i]);\n            }\n        }\n        return result;\n    }\n}\n\n/**\n * 数组项查找\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {*}\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @param {*} context\n * @return {Function}\n */\nfunction bind(func, context) {\n    var args = nativeSlice.call(arguments, 2);\n    return function () {\n        return func.apply(context, args.concat(nativeSlice.call(arguments)));\n    };\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @return {Function}\n */\nfunction curry(func) {\n    var args = nativeSlice.call(arguments, 1);\n    return function () {\n        return func.apply(this, args.concat(nativeSlice.call(arguments)));\n    };\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isArray(value) {\n    return objToString.call(value) === '[object Array]';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isFunction$1(value) {\n    return typeof value === 'function';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isString(value) {\n    return objToString.call(value) === '[object String]';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isObject$1(value) {\n    // Avoid a V8 JIT bug in Chrome 19-20.\n    // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.\n    var type = typeof value;\n    return type === 'function' || (!!value && type === 'object');\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isBuiltInObject(value) {\n    return !!BUILTIN_OBJECT[objToString.call(value)];\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isTypedArray(value) {\n    return !!TYPED_ARRAY[objToString.call(value)];\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isDom(value) {\n    return typeof value === 'object'\n        && typeof value.nodeType === 'number'\n        && typeof value.ownerDocument === 'object';\n}\n\n/**\n * Whether is exactly NaN. Notice isNaN('a') returns true.\n * @param {*} value\n * @return {boolean}\n */\nfunction eqNaN(value) {\n    return value !== value;\n}\n\n/**\n * If value1 is not null, then return value1, otherwise judget rest of values.\n * Low performance.\n * @memberOf module:zrender/core/util\n * @return {*} Final value\n */\nfunction retrieve(values) {\n    for (var i = 0, len = arguments.length; i < len; i++) {\n        if (arguments[i] != null) {\n            return arguments[i];\n        }\n    }\n}\n\nfunction retrieve2(value0, value1) {\n    return value0 != null\n        ? value0\n        : value1;\n}\n\nfunction retrieve3(value0, value1, value2) {\n    return value0 != null\n        ? value0\n        : value1 != null\n        ? value1\n        : value2;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} arr\n * @param {number} startIndex\n * @param {number} endIndex\n * @return {Array}\n */\nfunction slice() {\n    return Function.call.apply(nativeSlice, arguments);\n}\n\n/**\n * Normalize css liked array configuration\n * e.g.\n *  3 => [3, 3, 3, 3]\n *  [4, 2] => [4, 2, 4, 2]\n *  [4, 3, 2] => [4, 3, 2, 3]\n * @param {number|Array.<number>} val\n * @return {Array.<number>}\n */\nfunction normalizeCssArray(val) {\n    if (typeof (val) === 'number') {\n        return [val, val, val, val];\n    }\n    var len = val.length;\n    if (len === 2) {\n        // vertical | horizontal\n        return [val[0], val[1], val[0], val[1]];\n    }\n    else if (len === 3) {\n        // top | horizontal | bottom\n        return [val[0], val[1], val[2], val[1]];\n    }\n    return val;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {boolean} condition\n * @param {string} message\n */\nfunction assert$1(condition, message) {\n    if (!condition) {\n        throw new Error(message);\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {string} str string to be trimed\n * @return {string} trimed string\n */\nfunction trim(str) {\n    if (str == null) {\n        return null;\n    }\n    else if (typeof str.trim === 'function') {\n        return str.trim();\n    }\n    else {\n        return str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n    }\n}\n\nvar primitiveKey = '__ec_primitive__';\n/**\n * Set an object as primitive to be ignored traversing children in clone or merge\n */\nfunction setAsPrimitive(obj) {\n    obj[primitiveKey] = true;\n}\n\nfunction isPrimitive(obj) {\n    return obj[primitiveKey];\n}\n\n/**\n * @constructor\n * @param {Object} obj Only apply `ownProperty`.\n */\nfunction HashMap(obj) {\n    var isArr = isArray(obj);\n    // Key should not be set on this, otherwise\n    // methods get/set/... may be overrided.\n    this.data = {};\n    var thisMap = this;\n\n    (obj instanceof HashMap)\n        ? obj.each(visit)\n        : (obj && each$1(obj, visit));\n\n    function visit(value, key) {\n        isArr ? thisMap.set(value, key) : thisMap.set(key, value);\n    }\n}\n\nHashMap.prototype = {\n    constructor: HashMap,\n    // Do not provide `has` method to avoid defining what is `has`.\n    // (We usually treat `null` and `undefined` as the same, different\n    // from ES6 Map).\n    get: function (key) {\n        return this.data.hasOwnProperty(key) ? this.data[key] : null;\n    },\n    set: function (key, value) {\n        // Comparing with invocation chaining, `return value` is more commonly\n        // used in this case: `var someVal = map.set('a', genVal());`\n        return (this.data[key] = value);\n    },\n    // Although util.each can be performed on this hashMap directly, user\n    // should not use the exposed keys, who are prefixed.\n    each: function (cb, context) {\n        context !== void 0 && (cb = bind(cb, context));\n        for (var key in this.data) {\n            this.data.hasOwnProperty(key) && cb(this.data[key], key);\n        }\n    },\n    // Do not use this method if performance sensitive.\n    removeKey: function (key) {\n        delete this.data[key];\n    }\n};\n\nfunction createHashMap(obj) {\n    return new HashMap(obj);\n}\n\n\n\n\nfunction noop() {}\n\nvar ArrayCtor = typeof Float32Array === 'undefined'\n    ? Array\n    : Float32Array;\n\n/**\n * 创建一个向量\n * @param {number} [x=0]\n * @param {number} [y=0]\n * @return {Vector2}\n */\nfunction create(x, y) {\n    var out = new ArrayCtor(2);\n    if (x == null) {\n        x = 0;\n    }\n    if (y == null) {\n        y = 0;\n    }\n    out[0] = x;\n    out[1] = y;\n    return out;\n}\n\n/**\n * 复制向量数据\n * @param {Vector2} out\n * @param {Vector2} v\n * @return {Vector2}\n */\nfunction copy(out, v) {\n    out[0] = v[0];\n    out[1] = v[1];\n    return out;\n}\n\n/**\n * 克隆一个向量\n * @param {Vector2} v\n * @return {Vector2}\n */\nfunction clone$1(v) {\n    var out = new ArrayCtor(2);\n    out[0] = v[0];\n    out[1] = v[1];\n    return out;\n}\n\n/**\n * 设置向量的两个项\n * @param {Vector2} out\n * @param {number} a\n * @param {number} b\n * @return {Vector2} 结果\n */\n\n\n/**\n * 向量相加\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction add(out, v1, v2) {\n    out[0] = v1[0] + v2[0];\n    out[1] = v1[1] + v2[1];\n    return out;\n}\n\n/**\n * 向量缩放后相加\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @param {number} a\n */\nfunction scaleAndAdd(out, v1, v2, a) {\n    out[0] = v1[0] + v2[0] * a;\n    out[1] = v1[1] + v2[1] * a;\n    return out;\n}\n\n/**\n * 向量相减\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction sub(out, v1, v2) {\n    out[0] = v1[0] - v2[0];\n    out[1] = v1[1] - v2[1];\n    return out;\n}\n\n/**\n * 向量长度\n * @param {Vector2} v\n * @return {number}\n */\nfunction len(v) {\n    return Math.sqrt(lenSquare(v));\n}\n // jshint ignore:line\n\n/**\n * 向量长度平方\n * @param {Vector2} v\n * @return {number}\n */\nfunction lenSquare(v) {\n    return v[0] * v[0] + v[1] * v[1];\n}\n\n\n/**\n * 向量乘法\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\n\n\n/**\n * 向量除法\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\n\n\n/**\n * 向量点乘\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\n\n\n/**\n * 向量缩放\n * @param {Vector2} out\n * @param {Vector2} v\n * @param {number} s\n */\nfunction scale(out, v, s) {\n    out[0] = v[0] * s;\n    out[1] = v[1] * s;\n    return out;\n}\n\n/**\n * 向量归一化\n * @param {Vector2} out\n * @param {Vector2} v\n */\nfunction normalize(out, v) {\n    var d = len(v);\n    if (d === 0) {\n        out[0] = 0;\n        out[1] = 0;\n    }\n    else {\n        out[0] = v[0] / d;\n        out[1] = v[1] / d;\n    }\n    return out;\n}\n\n/**\n * 计算向量间距离\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction distance(v1, v2) {\n    return Math.sqrt(\n        (v1[0] - v2[0]) * (v1[0] - v2[0])\n        + (v1[1] - v2[1]) * (v1[1] - v2[1])\n    );\n}\nvar dist = distance;\n\n/**\n * 向量距离平方\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction distanceSquare(v1, v2) {\n    return (v1[0] - v2[0]) * (v1[0] - v2[0])\n        + (v1[1] - v2[1]) * (v1[1] - v2[1]);\n}\nvar distSquare = distanceSquare;\n\n/**\n * 求负向量\n * @param {Vector2} out\n * @param {Vector2} v\n */\n\n\n/**\n * 插值两个点\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @param {number} t\n */\n\n\n/**\n * 矩阵左乘向量\n * @param {Vector2} out\n * @param {Vector2} v\n * @param {Vector2} m\n */\nfunction applyTransform(out, v, m) {\n    var x = v[0];\n    var y = v[1];\n    out[0] = m[0] * x + m[2] * y + m[4];\n    out[1] = m[1] * x + m[3] * y + m[5];\n    return out;\n}\n\n/**\n * 求两个向量最小值\n * @param  {Vector2} out\n * @param  {Vector2} v1\n * @param  {Vector2} v2\n */\nfunction min(out, v1, v2) {\n    out[0] = Math.min(v1[0], v2[0]);\n    out[1] = Math.min(v1[1], v2[1]);\n    return out;\n}\n\n/**\n * 求两个向量最大值\n * @param  {Vector2} out\n * @param  {Vector2} v1\n * @param  {Vector2} v2\n */\nfunction max(out, v1, v2) {\n    out[0] = Math.max(v1[0], v2[0]);\n    out[1] = Math.max(v1[1], v2[1]);\n    return out;\n}\n\n// TODO Draggable for group\n// FIXME Draggable on element which has parent rotation or scale\nfunction Draggable() {\n\n    this.on('mousedown', this._dragStart, this);\n    this.on('mousemove', this._drag, this);\n    this.on('mouseup', this._dragEnd, this);\n    this.on('globalout', this._dragEnd, this);\n    // this._dropTarget = null;\n    // this._draggingTarget = null;\n\n    // this._x = 0;\n    // this._y = 0;\n}\n\nDraggable.prototype = {\n\n    constructor: Draggable,\n\n    _dragStart: function (e) {\n        var draggingTarget = e.target;\n        if (draggingTarget && draggingTarget.draggable) {\n            this._draggingTarget = draggingTarget;\n            draggingTarget.dragging = true;\n            this._x = e.offsetX;\n            this._y = e.offsetY;\n\n            this.dispatchToElement(param(draggingTarget, e), 'dragstart', e.event);\n        }\n    },\n\n    _drag: function (e) {\n        var draggingTarget = this._draggingTarget;\n        if (draggingTarget) {\n\n            var x = e.offsetX;\n            var y = e.offsetY;\n\n            var dx = x - this._x;\n            var dy = y - this._y;\n            this._x = x;\n            this._y = y;\n\n            draggingTarget.drift(dx, dy, e);\n            this.dispatchToElement(param(draggingTarget, e), 'drag', e.event);\n\n            var dropTarget = this.findHover(x, y, draggingTarget).target;\n            var lastDropTarget = this._dropTarget;\n            this._dropTarget = dropTarget;\n\n            if (draggingTarget !== dropTarget) {\n                if (lastDropTarget && dropTarget !== lastDropTarget) {\n                    this.dispatchToElement(param(lastDropTarget, e), 'dragleave', e.event);\n                }\n                if (dropTarget && dropTarget !== lastDropTarget) {\n                    this.dispatchToElement(param(dropTarget, e), 'dragenter', e.event);\n                }\n            }\n        }\n    },\n\n    _dragEnd: function (e) {\n        var draggingTarget = this._draggingTarget;\n\n        if (draggingTarget) {\n            draggingTarget.dragging = false;\n        }\n\n        this.dispatchToElement(param(draggingTarget, e), 'dragend', e.event);\n\n        if (this._dropTarget) {\n            this.dispatchToElement(param(this._dropTarget, e), 'drop', e.event);\n        }\n\n        this._draggingTarget = null;\n        this._dropTarget = null;\n    }\n\n};\n\nfunction param(target, e) {\n    return {target: target, topTarget: e && e.topTarget};\n}\n\n/**\n * Event Mixin\n * @module zrender/mixin/Eventful\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         pissang (https://www.github.com/pissang)\n */\n\nvar arrySlice = Array.prototype.slice;\n\n/**\n * Event dispatcher.\n *\n * @alias module:zrender/mixin/Eventful\n * @constructor\n * @param {Object} [eventProcessor] The object eventProcessor is the scope when\n *        `eventProcessor.xxx` called.\n * @param {Function} [eventProcessor.normalizeQuery]\n *        param: {string|Object} Raw query.\n *        return: {string|Object} Normalized query.\n * @param {Function} [eventProcessor.filter] Event will be dispatched only\n *        if it returns `true`.\n *        param: {string} eventType\n *        param: {string|Object} query\n *        return: {boolean}\n * @param {Function} [eventProcessor.afterTrigger] Call after all handlers called.\n *        param: {string} eventType\n */\nvar Eventful = function (eventProcessor) {\n    this._$handlers = {};\n    this._$eventProcessor = eventProcessor;\n};\n\nEventful.prototype = {\n\n    constructor: Eventful,\n\n    /**\n     * The handler can only be triggered once, then removed.\n     *\n     * @param {string} event The event name.\n     * @param {string|Object} [query] Condition used on event filter.\n     * @param {Function} handler The event handler.\n     * @param {Object} context\n     */\n    one: function (event, query, handler, context) {\n        return on(this, event, query, handler, context, true);\n    },\n\n    /**\n     * Bind a handler.\n     *\n     * @param {string} event The event name.\n     * @param {string|Object} [query] Condition used on event filter.\n     * @param {Function} handler The event handler.\n     * @param {Object} [context]\n     */\n    on: function (event, query, handler, context) {\n        return on(this, event, query, handler, context, false);\n    },\n\n    /**\n     * Whether any handler has bound.\n     *\n     * @param  {string}  event\n     * @return {boolean}\n     */\n    isSilent: function (event) {\n        var _h = this._$handlers;\n        return !_h[event] || !_h[event].length;\n    },\n\n    /**\n     * Unbind a event.\n     *\n     * @param {string} event The event name.\n     * @param {Function} [handler] The event handler.\n     */\n    off: function (event, handler) {\n        var _h = this._$handlers;\n\n        if (!event) {\n            this._$handlers = {};\n            return this;\n        }\n\n        if (handler) {\n            if (_h[event]) {\n                var newList = [];\n                for (var i = 0, l = _h[event].length; i < l; i++) {\n                    if (_h[event][i].h !== handler) {\n                        newList.push(_h[event][i]);\n                    }\n                }\n                _h[event] = newList;\n            }\n\n            if (_h[event] && _h[event].length === 0) {\n                delete _h[event];\n            }\n        }\n        else {\n            delete _h[event];\n        }\n\n        return this;\n    },\n\n    /**\n     * Dispatch a event.\n     *\n     * @param {string} type The event name.\n     */\n    trigger: function (type) {\n        var _h = this._$handlers[type];\n        var eventProcessor = this._$eventProcessor;\n\n        if (_h) {\n            var args = arguments;\n            var argLen = args.length;\n\n            if (argLen > 3) {\n                args = arrySlice.call(args, 1);\n            }\n\n            var len = _h.length;\n            for (var i = 0; i < len;) {\n                var hItem = _h[i];\n                if (eventProcessor\n                    && eventProcessor.filter\n                    && hItem.query != null\n                    && !eventProcessor.filter(type, hItem.query)\n                ) {\n                    i++;\n                    continue;\n                }\n\n                // Optimize advise from backbone\n                switch (argLen) {\n                    case 1:\n                        hItem.h.call(hItem.ctx);\n                        break;\n                    case 2:\n                        hItem.h.call(hItem.ctx, args[1]);\n                        break;\n                    case 3:\n                        hItem.h.call(hItem.ctx, args[1], args[2]);\n                        break;\n                    default:\n                        // have more than 2 given arguments\n                        hItem.h.apply(hItem.ctx, args);\n                        break;\n                }\n\n                if (hItem.one) {\n                    _h.splice(i, 1);\n                    len--;\n                }\n                else {\n                    i++;\n                }\n            }\n        }\n\n        eventProcessor && eventProcessor.afterTrigger\n            && eventProcessor.afterTrigger(type);\n\n        return this;\n    },\n\n    /**\n     * Dispatch a event with context, which is specified at the last parameter.\n     *\n     * @param {string} type The event name.\n     */\n    triggerWithContext: function (type) {\n        var _h = this._$handlers[type];\n        var eventProcessor = this._$eventProcessor;\n\n        if (_h) {\n            var args = arguments;\n            var argLen = args.length;\n\n            if (argLen > 4) {\n                args = arrySlice.call(args, 1, args.length - 1);\n            }\n            var ctx = args[args.length - 1];\n\n            var len = _h.length;\n            for (var i = 0; i < len;) {\n                var hItem = _h[i];\n                if (eventProcessor\n                    && eventProcessor.filter\n                    && hItem.query != null\n                    && !eventProcessor.filter(type, hItem.query)\n                ) {\n                    i++;\n                    continue;\n                }\n\n                // Optimize advise from backbone\n                switch (argLen) {\n                    case 1:\n                        hItem.h.call(ctx);\n                        break;\n                    case 2:\n                        hItem.h.call(ctx, args[1]);\n                        break;\n                    case 3:\n                        hItem.h.call(ctx, args[1], args[2]);\n                        break;\n                    default:\n                        // have more than 2 given arguments\n                        hItem.h.apply(ctx, args);\n                        break;\n                }\n\n                if (hItem.one) {\n                    _h.splice(i, 1);\n                    len--;\n                }\n                else {\n                    i++;\n                }\n            }\n        }\n\n        eventProcessor && eventProcessor.afterTrigger\n            && eventProcessor.afterTrigger(type);\n\n        return this;\n    }\n};\n\nfunction normalizeQuery(host, query) {\n    var eventProcessor = host._$eventProcessor;\n    if (query != null && eventProcessor && eventProcessor.normalizeQuery) {\n        query = eventProcessor.normalizeQuery(query);\n    }\n    return query;\n}\n\nfunction on(eventful, event, query, handler, context, isOnce) {\n    var _h = eventful._$handlers;\n\n    if (typeof query === 'function') {\n        context = handler;\n        handler = query;\n        query = null;\n    }\n\n    if (!handler || !event) {\n        return eventful;\n    }\n\n    query = normalizeQuery(eventful, query);\n\n    if (!_h[event]) {\n        _h[event] = [];\n    }\n\n    for (var i = 0; i < _h[event].length; i++) {\n        if (_h[event][i].h === handler) {\n            return eventful;\n        }\n    }\n\n    var wrap = {\n        h: handler,\n        one: isOnce,\n        query: query,\n        ctx: context || eventful,\n        // FIXME\n        // Do not publish this feature util it is proved that it makes sense.\n        callAtLast: handler.zrEventfulCallAtLast\n    };\n\n    var lastIndex = _h[event].length - 1;\n    var lastWrap = _h[event][lastIndex];\n    (lastWrap && lastWrap.callAtLast)\n        ? _h[event].splice(lastIndex, 0, wrap)\n        : _h[event].push(wrap);\n\n    return eventful;\n}\n\n/**\n * 事件辅助类\n * @module zrender/core/event\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n */\n\nvar isDomLevel2 = (typeof window !== 'undefined') && !!window.addEventListener;\n\nvar MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;\n\nfunction getBoundingClientRect(el) {\n    // BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect\n    return el.getBoundingClientRect ? el.getBoundingClientRect() : {left: 0, top: 0};\n}\n\n// `calculate` is optional, default false\nfunction clientToLocal(el, e, out, calculate) {\n    out = out || {};\n\n    // According to the W3C Working Draft, offsetX and offsetY should be relative\n    // to the padding edge of the target element. The only browser using this convention\n    // is IE. Webkit uses the border edge, Opera uses the content edge, and FireFox does\n    // not support the properties.\n    // (see http://www.jacklmoore.com/notes/mouse-position/)\n    // In zr painter.dom, padding edge equals to border edge.\n\n    // FIXME\n    // When mousemove event triggered on ec tooltip, target is not zr painter.dom, and\n    // offsetX/Y is relative to e.target, where the calculation of zrX/Y via offsetX/Y\n    // is too complex. So css-transfrom dont support in this case temporarily.\n    if (calculate || !env$1.canvasSupported) {\n        defaultGetZrXY(el, e, out);\n    }\n    // Caution: In FireFox, layerX/layerY Mouse position relative to the closest positioned\n    // ancestor element, so we should make sure el is positioned (e.g., not position:static).\n    // BTW1, Webkit don't return the same results as FF in non-simple cases (like add\n    // zoom-factor, overflow / opacity layers, transforms ...)\n    // BTW2, (ev.offsetY || ev.pageY - $(ev.target).offset().top) is not correct in preserve-3d.\n    // <https://bugs.jquery.com/ticket/8523#comment:14>\n    // BTW3, In ff, offsetX/offsetY is always 0.\n    else if (env$1.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) {\n        out.zrX = e.layerX;\n        out.zrY = e.layerY;\n    }\n    // For IE6+, chrome, safari, opera. (When will ff support offsetX?)\n    else if (e.offsetX != null) {\n        out.zrX = e.offsetX;\n        out.zrY = e.offsetY;\n    }\n    // For some other device, e.g., IOS safari.\n    else {\n        defaultGetZrXY(el, e, out);\n    }\n\n    return out;\n}\n\nfunction defaultGetZrXY(el, e, out) {\n    // This well-known method below does not support css transform.\n    var box = getBoundingClientRect(el);\n    out.zrX = e.clientX - box.left;\n    out.zrY = e.clientY - box.top;\n}\n\n/**\n * 如果存在第三方嵌入的一些dom触发的事件，或touch事件，需要转换一下事件坐标.\n * `calculate` is optional, default false.\n */\nfunction normalizeEvent(el, e, calculate) {\n\n    e = e || window.event;\n\n    if (e.zrX != null) {\n        return e;\n    }\n\n    var eventType = e.type;\n    var isTouch = eventType && eventType.indexOf('touch') >= 0;\n\n    if (!isTouch) {\n        clientToLocal(el, e, e, calculate);\n        e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3;\n    }\n    else {\n        var touch = eventType !== 'touchend'\n            ? e.targetTouches[0]\n            : e.changedTouches[0];\n        touch && clientToLocal(el, touch, e, calculate);\n    }\n\n    // Add which for click: 1 === left; 2 === middle; 3 === right; otherwise: 0;\n    // See jQuery: https://github.com/jquery/jquery/blob/master/src/event.js\n    // If e.which has been defined, if may be readonly,\n    // see: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which\n    var button = e.button;\n    if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) {\n        e.which = (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));\n    }\n    // [Caution]: `e.which` from browser is not always reliable. For example,\n    // when press left button and `mousemove (pointermove)` in Edge, the `e.which`\n    // is 65536 and the `e.button` is -1. But the `mouseup (pointerup)` and\n    // `mousedown (pointerdown)` is the same as Chrome does.\n\n    return e;\n}\n\n/**\n * @param {HTMLElement} el\n * @param {string} name\n * @param {Function} handler\n */\nfunction addEventListener(el, name, handler) {\n    if (isDomLevel2) {\n        // Reproduct the console warning:\n        // [Violation] Added non-passive event listener to a scroll-blocking <some> event.\n        // Consider marking event handler as 'passive' to make the page more responsive.\n        // Just set console log level: verbose in chrome dev tool.\n        // then the warning log will be printed when addEventListener called.\n        // See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md\n        // We have not yet found a neat way to using passive. Because in zrender the dom event\n        // listener delegate all of the upper events of element. Some of those events need\n        // to prevent default. For example, the feature `preventDefaultMouseMove` of echarts.\n        // Before passive can be adopted, these issues should be considered:\n        // (1) Whether and how a zrender user specifies an event listener passive. And by default,\n        // passive or not.\n        // (2) How to tread that some zrender event listener is passive, and some is not. If\n        // we use other way but not preventDefault of mousewheel and touchmove, browser\n        // compatibility should be handled.\n\n        // var opts = (env.passiveSupported && name === 'mousewheel')\n        //     ? {passive: true}\n        //     // By default, the third param of el.addEventListener is `capture: false`.\n        //     : void 0;\n        // el.addEventListener(name, handler /* , opts */);\n        el.addEventListener(name, handler);\n    }\n    else {\n        el.attachEvent('on' + name, handler);\n    }\n}\n\nfunction removeEventListener(el, name, handler) {\n    if (isDomLevel2) {\n        el.removeEventListener(name, handler);\n    }\n    else {\n        el.detachEvent('on' + name, handler);\n    }\n}\n\n/**\n * preventDefault and stopPropagation.\n * Notice: do not do that in zrender. Upper application\n * do that if necessary.\n *\n * @memberOf module:zrender/core/event\n * @method\n * @param {Event} e : event对象\n */\nvar stop = isDomLevel2\n    ? function (e) {\n        e.preventDefault();\n        e.stopPropagation();\n        e.cancelBubble = true;\n    }\n    : function (e) {\n        e.returnValue = false;\n        e.cancelBubble = true;\n    };\n\n/**\n * This method only works for mouseup and mousedown. The functionality is restricted\n * for fault tolerance, See the `e.which` compatibility above.\n *\n * @param {MouseEvent} e\n * @return {boolean}\n */\n\n\n/**\n * To be removed.\n * @deprecated\n */\n\n/**\n * Only implements needed gestures for mobile.\n */\n\nvar GestureMgr = function () {\n\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    this._track = [];\n};\n\nGestureMgr.prototype = {\n\n    constructor: GestureMgr,\n\n    recognize: function (event, target, root) {\n        this._doTrack(event, target, root);\n        return this._recognize(event);\n    },\n\n    clear: function () {\n        this._track.length = 0;\n        return this;\n    },\n\n    _doTrack: function (event, target, root) {\n        var touches = event.touches;\n\n        if (!touches) {\n            return;\n        }\n\n        var trackItem = {\n            points: [],\n            touches: [],\n            target: target,\n            event: event\n        };\n\n        for (var i = 0, len = touches.length; i < len; i++) {\n            var touch = touches[i];\n            var pos = clientToLocal(root, touch, {});\n            trackItem.points.push([pos.zrX, pos.zrY]);\n            trackItem.touches.push(touch);\n        }\n\n        this._track.push(trackItem);\n    },\n\n    _recognize: function (event) {\n        for (var eventName in recognizers) {\n            if (recognizers.hasOwnProperty(eventName)) {\n                var gestureInfo = recognizers[eventName](this._track, event);\n                if (gestureInfo) {\n                    return gestureInfo;\n                }\n            }\n        }\n    }\n};\n\nfunction dist$1(pointPair) {\n    var dx = pointPair[1][0] - pointPair[0][0];\n    var dy = pointPair[1][1] - pointPair[0][1];\n\n    return Math.sqrt(dx * dx + dy * dy);\n}\n\nfunction center(pointPair) {\n    return [\n        (pointPair[0][0] + pointPair[1][0]) / 2,\n        (pointPair[0][1] + pointPair[1][1]) / 2\n    ];\n}\n\nvar recognizers = {\n\n    pinch: function (track, event) {\n        var trackLen = track.length;\n\n        if (!trackLen) {\n            return;\n        }\n\n        var pinchEnd = (track[trackLen - 1] || {}).points;\n        var pinchPre = (track[trackLen - 2] || {}).points || pinchEnd;\n\n        if (pinchPre\n            && pinchPre.length > 1\n            && pinchEnd\n            && pinchEnd.length > 1\n        ) {\n            var pinchScale = dist$1(pinchEnd) / dist$1(pinchPre);\n            !isFinite(pinchScale) && (pinchScale = 1);\n\n            event.pinchScale = pinchScale;\n\n            var pinchCenter = center(pinchEnd);\n            event.pinchX = pinchCenter[0];\n            event.pinchY = pinchCenter[1];\n\n            return {\n                type: 'pinch',\n                target: track[0].target,\n                event: event\n            };\n        }\n    }\n\n    // Only pinch currently.\n};\n\nvar SILENT = 'silent';\n\nfunction makeEventPacket(eveType, targetInfo, event) {\n    return {\n        type: eveType,\n        event: event,\n        // target can only be an element that is not silent.\n        target: targetInfo.target,\n        // topTarget can be a silent element.\n        topTarget: targetInfo.topTarget,\n        cancelBubble: false,\n        offsetX: event.zrX,\n        offsetY: event.zrY,\n        gestureEvent: event.gestureEvent,\n        pinchX: event.pinchX,\n        pinchY: event.pinchY,\n        pinchScale: event.pinchScale,\n        wheelDelta: event.zrDelta,\n        zrByTouch: event.zrByTouch,\n        which: event.which,\n        stop: stopEvent\n    };\n}\n\nfunction stopEvent(event) {\n    stop(this.event);\n}\n\nfunction EmptyProxy() {}\nEmptyProxy.prototype.dispose = function () {};\n\nvar handlerNames = [\n    'click', 'dblclick', 'mousewheel', 'mouseout',\n    'mouseup', 'mousedown', 'mousemove', 'contextmenu'\n];\n/**\n * @alias module:zrender/Handler\n * @constructor\n * @extends module:zrender/mixin/Eventful\n * @param {module:zrender/Storage} storage Storage instance.\n * @param {module:zrender/Painter} painter Painter instance.\n * @param {module:zrender/dom/HandlerProxy} proxy HandlerProxy instance.\n * @param {HTMLElement} painterRoot painter.root (not painter.getViewportRoot()).\n */\nvar Handler = function (storage, painter, proxy, painterRoot) {\n    Eventful.call(this);\n\n    this.storage = storage;\n\n    this.painter = painter;\n\n    this.painterRoot = painterRoot;\n\n    proxy = proxy || new EmptyProxy();\n\n    /**\n     * Proxy of event. can be Dom, WebGLSurface, etc.\n     */\n    this.proxy = null;\n\n    /**\n     * {target, topTarget, x, y}\n     * @private\n     * @type {Object}\n     */\n    this._hovered = {};\n\n    /**\n     * @private\n     * @type {Date}\n     */\n    this._lastTouchMoment;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._lastX;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._lastY;\n\n    /**\n     * @private\n     * @type {module:zrender/core/GestureMgr}\n     */\n    this._gestureMgr;\n\n\n    Draggable.call(this);\n\n    this.setHandlerProxy(proxy);\n};\n\nHandler.prototype = {\n\n    constructor: Handler,\n\n    setHandlerProxy: function (proxy) {\n        if (this.proxy) {\n            this.proxy.dispose();\n        }\n\n        if (proxy) {\n            each$1(handlerNames, function (name) {\n                proxy.on && proxy.on(name, this[name], this);\n            }, this);\n            // Attach handler\n            proxy.handler = this;\n        }\n        this.proxy = proxy;\n    },\n\n    mousemove: function (event) {\n        var x = event.zrX;\n        var y = event.zrY;\n\n        var lastHovered = this._hovered;\n        var lastHoveredTarget = lastHovered.target;\n\n        // If lastHoveredTarget is removed from zr (detected by '__zr') by some API call\n        // (like 'setOption' or 'dispatchAction') in event handlers, we should find\n        // lastHovered again here. Otherwise 'mouseout' can not be triggered normally.\n        // See #6198.\n        if (lastHoveredTarget && !lastHoveredTarget.__zr) {\n            lastHovered = this.findHover(lastHovered.x, lastHovered.y);\n            lastHoveredTarget = lastHovered.target;\n        }\n\n        var hovered = this._hovered = this.findHover(x, y);\n        var hoveredTarget = hovered.target;\n\n        var proxy = this.proxy;\n        proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default');\n\n        // Mouse out on previous hovered element\n        if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget) {\n            this.dispatchToElement(lastHovered, 'mouseout', event);\n        }\n\n        // Mouse moving on one element\n        this.dispatchToElement(hovered, 'mousemove', event);\n\n        // Mouse over on a new element\n        if (hoveredTarget && hoveredTarget !== lastHoveredTarget) {\n            this.dispatchToElement(hovered, 'mouseover', event);\n        }\n    },\n\n    mouseout: function (event) {\n        this.dispatchToElement(this._hovered, 'mouseout', event);\n\n        // There might be some doms created by upper layer application\n        // at the same level of painter.getViewportRoot() (e.g., tooltip\n        // dom created by echarts), where 'globalout' event should not\n        // be triggered when mouse enters these doms. (But 'mouseout'\n        // should be triggered at the original hovered element as usual).\n        var element = event.toElement || event.relatedTarget;\n        var innerDom;\n        do {\n            element = element && element.parentNode;\n        }\n        while (element && element.nodeType !== 9 && !(\n            innerDom = element === this.painterRoot\n        ));\n\n        !innerDom && this.trigger('globalout', {event: event});\n    },\n\n    /**\n     * Resize\n     */\n    resize: function (event) {\n        this._hovered = {};\n    },\n\n    /**\n     * Dispatch event\n     * @param {string} eventName\n     * @param {event=} eventArgs\n     */\n    dispatch: function (eventName, eventArgs) {\n        var handler = this[eventName];\n        handler && handler.call(this, eventArgs);\n    },\n\n    /**\n     * Dispose\n     */\n    dispose: function () {\n\n        this.proxy.dispose();\n\n        this.storage =\n        this.proxy =\n        this.painter = null;\n    },\n\n    /**\n     * 设置默认的cursor style\n     * @param {string} [cursorStyle='default'] 例如 crosshair\n     */\n    setCursorStyle: function (cursorStyle) {\n        var proxy = this.proxy;\n        proxy.setCursor && proxy.setCursor(cursorStyle);\n    },\n\n    /**\n     * 事件分发代理\n     *\n     * @private\n     * @param {Object} targetInfo {target, topTarget} 目标图形元素\n     * @param {string} eventName 事件名称\n     * @param {Object} event 事件对象\n     */\n    dispatchToElement: function (targetInfo, eventName, event) {\n        targetInfo = targetInfo || {};\n        var el = targetInfo.target;\n        if (el && el.silent) {\n            return;\n        }\n        var eventHandler = 'on' + eventName;\n        var eventPacket = makeEventPacket(eventName, targetInfo, event);\n\n        while (el) {\n            el[eventHandler]\n                && (eventPacket.cancelBubble = el[eventHandler].call(el, eventPacket));\n\n            el.trigger(eventName, eventPacket);\n\n            el = el.parent;\n\n            if (eventPacket.cancelBubble) {\n                break;\n            }\n        }\n\n        if (!eventPacket.cancelBubble) {\n            // 冒泡到顶级 zrender 对象\n            this.trigger(eventName, eventPacket);\n            // 分发事件到用户自定义层\n            // 用户有可能在全局 click 事件中 dispose，所以需要判断下 painter 是否存在\n            this.painter && this.painter.eachOtherLayer(function (layer) {\n                if (typeof (layer[eventHandler]) === 'function') {\n                    layer[eventHandler].call(layer, eventPacket);\n                }\n                if (layer.trigger) {\n                    layer.trigger(eventName, eventPacket);\n                }\n            });\n        }\n    },\n\n    /**\n     * @private\n     * @param {number} x\n     * @param {number} y\n     * @param {module:zrender/graphic/Displayable} exclude\n     * @return {model:zrender/Element}\n     * @method\n     */\n    findHover: function (x, y, exclude) {\n        var list = this.storage.getDisplayList();\n        var out = {x: x, y: y};\n\n        for (var i = list.length - 1; i >= 0; i--) {\n            var hoverCheckResult;\n            if (list[i] !== exclude\n                // getDisplayList may include ignored item in VML mode\n                && !list[i].ignore\n                && (hoverCheckResult = isHover(list[i], x, y))\n            ) {\n                !out.topTarget && (out.topTarget = list[i]);\n                if (hoverCheckResult !== SILENT) {\n                    out.target = list[i];\n                    break;\n                }\n            }\n        }\n\n        return out;\n    },\n\n    processGesture: function (event, stage) {\n        if (!this._gestureMgr) {\n            this._gestureMgr = new GestureMgr();\n        }\n        var gestureMgr = this._gestureMgr;\n\n        stage === 'start' && gestureMgr.clear();\n\n        var gestureInfo = gestureMgr.recognize(\n            event,\n            this.findHover(event.zrX, event.zrY, null).target,\n            this.proxy.dom\n        );\n\n        stage === 'end' && gestureMgr.clear();\n\n        // Do not do any preventDefault here. Upper application do that if necessary.\n        if (gestureInfo) {\n            var type = gestureInfo.type;\n            event.gestureEvent = type;\n\n            this.dispatchToElement({target: gestureInfo.target}, type, gestureInfo.event);\n        }\n    }\n};\n\n// Common handlers\neach$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {\n    Handler.prototype[name] = function (event) {\n        // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover\n        var hovered = this.findHover(event.zrX, event.zrY);\n        var hoveredTarget = hovered.target;\n\n        if (name === 'mousedown') {\n            this._downEl = hoveredTarget;\n            this._downPoint = [event.zrX, event.zrY];\n            // In case click triggered before mouseup\n            this._upEl = hoveredTarget;\n        }\n        else if (name === 'mouseup') {\n            this._upEl = hoveredTarget;\n        }\n        else if (name === 'click') {\n            if (this._downEl !== this._upEl\n                // Original click event is triggered on the whole canvas element,\n                // including the case that `mousedown` - `mousemove` - `mouseup`,\n                // which should be filtered, otherwise it will bring trouble to\n                // pan and zoom.\n                || !this._downPoint\n                // Arbitrary value\n                || dist(this._downPoint, [event.zrX, event.zrY]) > 4\n            ) {\n                return;\n            }\n            this._downPoint = null;\n        }\n\n        this.dispatchToElement(hovered, name, event);\n    };\n});\n\nfunction isHover(displayable, x, y) {\n    if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) {\n        var el = displayable;\n        var isSilent;\n        while (el) {\n            // If clipped by ancestor.\n            // FIXME: If clipPath has neither stroke nor fill,\n            // el.clipPath.contain(x, y) will always return false.\n            if (el.clipPath && !el.clipPath.contain(x, y)) {\n                return false;\n            }\n            if (el.silent) {\n                isSilent = true;\n            }\n            el = el.parent;\n        }\n        return isSilent ? SILENT : true;\n    }\n\n    return false;\n}\n\nmixin(Handler, Eventful);\nmixin(Handler, Draggable);\n\n/**\n * 3x2矩阵操作类\n * @exports zrender/tool/matrix\n */\n\nvar ArrayCtor$1 = typeof Float32Array === 'undefined'\n    ? Array\n    : Float32Array;\n\n/**\n * Create a identity matrix.\n * @return {Float32Array|Array.<number>}\n */\nfunction create$1() {\n    var out = new ArrayCtor$1(6);\n    identity(out);\n\n    return out;\n}\n\n/**\n * 设置矩阵为单位矩阵\n * @param {Float32Array|Array.<number>} out\n */\nfunction identity(out) {\n    out[0] = 1;\n    out[1] = 0;\n    out[2] = 0;\n    out[3] = 1;\n    out[4] = 0;\n    out[5] = 0;\n    return out;\n}\n\n/**\n * 复制矩阵\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} m\n */\nfunction copy$1(out, m) {\n    out[0] = m[0];\n    out[1] = m[1];\n    out[2] = m[2];\n    out[3] = m[3];\n    out[4] = m[4];\n    out[5] = m[5];\n    return out;\n}\n\n/**\n * 矩阵相乘\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} m1\n * @param {Float32Array|Array.<number>} m2\n */\nfunction mul$1(out, m1, m2) {\n    // Consider matrix.mul(m, m2, m);\n    // where out is the same as m2.\n    // So use temp variable to escape error.\n    var out0 = m1[0] * m2[0] + m1[2] * m2[1];\n    var out1 = m1[1] * m2[0] + m1[3] * m2[1];\n    var out2 = m1[0] * m2[2] + m1[2] * m2[3];\n    var out3 = m1[1] * m2[2] + m1[3] * m2[3];\n    var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];\n    var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];\n    out[0] = out0;\n    out[1] = out1;\n    out[2] = out2;\n    out[3] = out3;\n    out[4] = out4;\n    out[5] = out5;\n    return out;\n}\n\n/**\n * 平移变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {Float32Array|Array.<number>} v\n */\nfunction translate(out, a, v) {\n    out[0] = a[0];\n    out[1] = a[1];\n    out[2] = a[2];\n    out[3] = a[3];\n    out[4] = a[4] + v[0];\n    out[5] = a[5] + v[1];\n    return out;\n}\n\n/**\n * 旋转变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {number} rad\n */\nfunction rotate(out, a, rad) {\n    var aa = a[0];\n    var ac = a[2];\n    var atx = a[4];\n    var ab = a[1];\n    var ad = a[3];\n    var aty = a[5];\n    var st = Math.sin(rad);\n    var ct = Math.cos(rad);\n\n    out[0] = aa * ct + ab * st;\n    out[1] = -aa * st + ab * ct;\n    out[2] = ac * ct + ad * st;\n    out[3] = -ac * st + ct * ad;\n    out[4] = ct * atx + st * aty;\n    out[5] = ct * aty - st * atx;\n    return out;\n}\n\n/**\n * 缩放变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {Float32Array|Array.<number>} v\n */\nfunction scale$1(out, a, v) {\n    var vx = v[0];\n    var vy = v[1];\n    out[0] = a[0] * vx;\n    out[1] = a[1] * vy;\n    out[2] = a[2] * vx;\n    out[3] = a[3] * vy;\n    out[4] = a[4] * vx;\n    out[5] = a[5] * vy;\n    return out;\n}\n\n/**\n * 求逆矩阵\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n */\nfunction invert(out, a) {\n\n    var aa = a[0];\n    var ac = a[2];\n    var atx = a[4];\n    var ab = a[1];\n    var ad = a[3];\n    var aty = a[5];\n\n    var det = aa * ad - ab * ac;\n    if (!det) {\n        return null;\n    }\n    det = 1.0 / det;\n\n    out[0] = ad * det;\n    out[1] = -ab * det;\n    out[2] = -ac * det;\n    out[3] = aa * det;\n    out[4] = (ac * aty - ad * atx) * det;\n    out[5] = (ab * atx - aa * aty) * det;\n    return out;\n}\n\n/**\n * Clone a new matrix.\n * @param {Float32Array|Array.<number>} a\n */\n\n/**\n * 提供变换扩展\n * @module zrender/mixin/Transformable\n * @author pissang (https://www.github.com/pissang)\n */\n\nvar mIdentity = identity;\n\nvar EPSILON = 5e-5;\n\nfunction isNotAroundZero(val) {\n    return val > EPSILON || val < -EPSILON;\n}\n\n/**\n * @alias module:zrender/mixin/Transformable\n * @constructor\n */\nvar Transformable = function (opts) {\n    opts = opts || {};\n    // If there are no given position, rotation, scale\n    if (!opts.position) {\n        /**\n         * 平移\n         * @type {Array.<number>}\n         * @default [0, 0]\n         */\n        this.position = [0, 0];\n    }\n    if (opts.rotation == null) {\n        /**\n         * 旋转\n         * @type {Array.<number>}\n         * @default 0\n         */\n        this.rotation = 0;\n    }\n    if (!opts.scale) {\n        /**\n         * 缩放\n         * @type {Array.<number>}\n         * @default [1, 1]\n         */\n        this.scale = [1, 1];\n    }\n    /**\n     * 旋转和缩放的原点\n     * @type {Array.<number>}\n     * @default null\n     */\n    this.origin = this.origin || null;\n};\n\nvar transformableProto = Transformable.prototype;\ntransformableProto.transform = null;\n\n/**\n * 判断是否需要有坐标变换\n * 如果有坐标变换, 则从position, rotation, scale以及父节点的transform计算出自身的transform矩阵\n */\ntransformableProto.needLocalTransform = function () {\n    return isNotAroundZero(this.rotation)\n        || isNotAroundZero(this.position[0])\n        || isNotAroundZero(this.position[1])\n        || isNotAroundZero(this.scale[0] - 1)\n        || isNotAroundZero(this.scale[1] - 1);\n};\n\nvar scaleTmp = [];\ntransformableProto.updateTransform = function () {\n    var parent = this.parent;\n    var parentHasTransform = parent && parent.transform;\n    var needLocalTransform = this.needLocalTransform();\n\n    var m = this.transform;\n    if (!(needLocalTransform || parentHasTransform)) {\n        m && mIdentity(m);\n        return;\n    }\n\n    m = m || create$1();\n\n    if (needLocalTransform) {\n        this.getLocalTransform(m);\n    }\n    else {\n        mIdentity(m);\n    }\n\n    // 应用父节点变换\n    if (parentHasTransform) {\n        if (needLocalTransform) {\n            mul$1(m, parent.transform, m);\n        }\n        else {\n            copy$1(m, parent.transform);\n        }\n    }\n    // 保存这个变换矩阵\n    this.transform = m;\n\n    var globalScaleRatio = this.globalScaleRatio;\n    if (globalScaleRatio != null && globalScaleRatio !== 1) {\n        this.getGlobalScale(scaleTmp);\n        var relX = scaleTmp[0] < 0 ? -1 : 1;\n        var relY = scaleTmp[1] < 0 ? -1 : 1;\n        var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0;\n        var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0;\n\n        m[0] *= sx;\n        m[1] *= sx;\n        m[2] *= sy;\n        m[3] *= sy;\n    }\n\n    this.invTransform = this.invTransform || create$1();\n    invert(this.invTransform, m);\n};\n\ntransformableProto.getLocalTransform = function (m) {\n    return Transformable.getLocalTransform(this, m);\n};\n\n/**\n * 将自己的transform应用到context上\n * @param {CanvasRenderingContext2D} ctx\n */\ntransformableProto.setTransform = function (ctx) {\n    var m = this.transform;\n    var dpr = ctx.dpr || 1;\n    if (m) {\n        ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]);\n    }\n    else {\n        ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    }\n};\n\ntransformableProto.restoreTransform = function (ctx) {\n    var dpr = ctx.dpr || 1;\n    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n};\n\nvar tmpTransform = [];\nvar originTransform = create$1();\n\ntransformableProto.setLocalTransform = function (m) {\n    if (!m) {\n        // TODO return or set identity?\n        return;\n    }\n    var sx = m[0] * m[0] + m[1] * m[1];\n    var sy = m[2] * m[2] + m[3] * m[3];\n    var position = this.position;\n    var scale$$1 = this.scale;\n    if (isNotAroundZero(sx - 1)) {\n        sx = Math.sqrt(sx);\n    }\n    if (isNotAroundZero(sy - 1)) {\n        sy = Math.sqrt(sy);\n    }\n    if (m[0] < 0) {\n        sx = -sx;\n    }\n    if (m[3] < 0) {\n        sy = -sy;\n    }\n\n    position[0] = m[4];\n    position[1] = m[5];\n    scale$$1[0] = sx;\n    scale$$1[1] = sy;\n    this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);\n};\n/**\n * 分解`transform`矩阵到`position`, `rotation`, `scale`\n */\ntransformableProto.decomposeTransform = function () {\n    if (!this.transform) {\n        return;\n    }\n    var parent = this.parent;\n    var m = this.transform;\n    if (parent && parent.transform) {\n        // Get local transform and decompose them to position, scale, rotation\n        mul$1(tmpTransform, parent.invTransform, m);\n        m = tmpTransform;\n    }\n    var origin = this.origin;\n    if (origin && (origin[0] || origin[1])) {\n        originTransform[4] = origin[0];\n        originTransform[5] = origin[1];\n        mul$1(tmpTransform, m, originTransform);\n        tmpTransform[4] -= origin[0];\n        tmpTransform[5] -= origin[1];\n        m = tmpTransform;\n    }\n\n    this.setLocalTransform(m);\n};\n\n/**\n * Get global scale\n * @return {Array.<number>}\n */\ntransformableProto.getGlobalScale = function (out) {\n    var m = this.transform;\n    out = out || [];\n    if (!m) {\n        out[0] = 1;\n        out[1] = 1;\n        return out;\n    }\n    out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]);\n    out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]);\n    if (m[0] < 0) {\n        out[0] = -out[0];\n    }\n    if (m[3] < 0) {\n        out[1] = -out[1];\n    }\n    return out;\n};\n/**\n * 变换坐标位置到 shape 的局部坐标空间\n * @method\n * @param {number} x\n * @param {number} y\n * @return {Array.<number>}\n */\ntransformableProto.transformCoordToLocal = function (x, y) {\n    var v2 = [x, y];\n    var invTransform = this.invTransform;\n    if (invTransform) {\n        applyTransform(v2, v2, invTransform);\n    }\n    return v2;\n};\n\n/**\n * 变换局部坐标位置到全局坐标空间\n * @method\n * @param {number} x\n * @param {number} y\n * @return {Array.<number>}\n */\ntransformableProto.transformCoordToGlobal = function (x, y) {\n    var v2 = [x, y];\n    var transform = this.transform;\n    if (transform) {\n        applyTransform(v2, v2, transform);\n    }\n    return v2;\n};\n\n/**\n * @static\n * @param {Object} target\n * @param {Array.<number>} target.origin\n * @param {number} target.rotation\n * @param {Array.<number>} target.position\n * @param {Array.<number>} [m]\n */\nTransformable.getLocalTransform = function (target, m) {\n    m = m || [];\n    mIdentity(m);\n\n    var origin = target.origin;\n    var scale$$1 = target.scale || [1, 1];\n    var rotation = target.rotation || 0;\n    var position = target.position || [0, 0];\n\n    if (origin) {\n        // Translate to origin\n        m[4] -= origin[0];\n        m[5] -= origin[1];\n    }\n    scale$1(m, m, scale$$1);\n    if (rotation) {\n        rotate(m, m, rotation);\n    }\n    if (origin) {\n        // Translate back from origin\n        m[4] += origin[0];\n        m[5] += origin[1];\n    }\n\n    m[4] += position[0];\n    m[5] += position[1];\n\n    return m;\n};\n\n/**\n * 缓动代码来自 https://github.com/sole/tween.js/blob/master/src/Tween.js\n * @see http://sole.github.io/tween.js/examples/03_graphs.html\n * @exports zrender/animation/easing\n */\nvar easing = {\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    linear: function (k) {\n        return k;\n    },\n\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticIn: function (k) {\n        return k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticOut: function (k) {\n        return k * (2 - k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k;\n        }\n        return -0.5 * (--k * (k - 2) - 1);\n    },\n\n    // 三次方的缓动（t^3）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicIn: function (k) {\n        return k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicOut: function (k) {\n        return --k * k * k + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k;\n        }\n        return 0.5 * ((k -= 2) * k * k + 2);\n    },\n\n    // 四次方的缓动（t^4）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticIn: function (k) {\n        return k * k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticOut: function (k) {\n        return 1 - (--k * k * k * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k * k;\n        }\n        return -0.5 * ((k -= 2) * k * k * k - 2);\n    },\n\n    // 五次方的缓动（t^5）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticIn: function (k) {\n        return k * k * k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticOut: function (k) {\n        return --k * k * k * k * k + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k * k * k;\n        }\n        return 0.5 * ((k -= 2) * k * k * k * k + 2);\n    },\n\n    // 正弦曲线的缓动（sin(t)）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalIn: function (k) {\n        return 1 - Math.cos(k * Math.PI / 2);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalOut: function (k) {\n        return Math.sin(k * Math.PI / 2);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalInOut: function (k) {\n        return 0.5 * (1 - Math.cos(Math.PI * k));\n    },\n\n    // 指数曲线的缓动（2^t）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialIn: function (k) {\n        return k === 0 ? 0 : Math.pow(1024, k - 1);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialOut: function (k) {\n        return k === 1 ? 1 : 1 - Math.pow(2, -10 * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialInOut: function (k) {\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if ((k *= 2) < 1) {\n            return 0.5 * Math.pow(1024, k - 1);\n        }\n        return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);\n    },\n\n    // 圆形曲线的缓动（sqrt(1-t^2)）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularIn: function (k) {\n        return 1 - Math.sqrt(1 - k * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularOut: function (k) {\n        return Math.sqrt(1 - (--k * k));\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return -0.5 * (Math.sqrt(1 - k * k) - 1);\n        }\n        return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);\n    },\n\n    // 创建类似于弹簧在停止前来回振荡的动画\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticIn: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        return -(a * Math.pow(2, 10 * (k -= 1))\n                    * Math.sin((k - s) * (2 * Math.PI) / p));\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticOut: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        return (a * Math.pow(2, -10 * k)\n                    * Math.sin((k - s) * (2 * Math.PI) / p) + 1);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticInOut: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        if ((k *= 2) < 1) {\n            return -0.5 * (a * Math.pow(2, 10 * (k -= 1))\n                * Math.sin((k - s) * (2 * Math.PI) / p));\n        }\n        return a * Math.pow(2, -10 * (k -= 1))\n                * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;\n\n    },\n\n    // 在某一动画开始沿指示的路径进行动画处理前稍稍收回该动画的移动\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backIn: function (k) {\n        var s = 1.70158;\n        return k * k * ((s + 1) * k - s);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backOut: function (k) {\n        var s = 1.70158;\n        return --k * k * ((s + 1) * k + s) + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backInOut: function (k) {\n        var s = 1.70158 * 1.525;\n        if ((k *= 2) < 1) {\n            return 0.5 * (k * k * ((s + 1) * k - s));\n        }\n        return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);\n    },\n\n    // 创建弹跳效果\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceIn: function (k) {\n        return 1 - easing.bounceOut(1 - k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceOut: function (k) {\n        if (k < (1 / 2.75)) {\n            return 7.5625 * k * k;\n        }\n        else if (k < (2 / 2.75)) {\n            return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;\n        }\n        else if (k < (2.5 / 2.75)) {\n            return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;\n        }\n        else {\n            return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;\n        }\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceInOut: function (k) {\n        if (k < 0.5) {\n            return easing.bounceIn(k * 2) * 0.5;\n        }\n        return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;\n    }\n};\n\n/**\n * 动画主控制器\n * @config target 动画对象，可以是数组，如果是数组的话会批量分发onframe等事件\n * @config life(1000) 动画时长\n * @config delay(0) 动画延迟时间\n * @config loop(true)\n * @config gap(0) 循环的间隔时间\n * @config onframe\n * @config easing(optional)\n * @config ondestroy(optional)\n * @config onrestart(optional)\n *\n * TODO pause\n */\n\nfunction Clip(options) {\n\n    this._target = options.target;\n\n    // 生命周期\n    this._life = options.life || 1000;\n    // 延时\n    this._delay = options.delay || 0;\n    // 开始时间\n    // this._startTime = new Date().getTime() + this._delay;// 单位毫秒\n    this._initialized = false;\n\n    // 是否循环\n    this.loop = options.loop == null ? false : options.loop;\n\n    this.gap = options.gap || 0;\n\n    this.easing = options.easing || 'Linear';\n\n    this.onframe = options.onframe;\n    this.ondestroy = options.ondestroy;\n    this.onrestart = options.onrestart;\n\n    this._pausedTime = 0;\n    this._paused = false;\n}\n\nClip.prototype = {\n\n    constructor: Clip,\n\n    step: function (globalTime, deltaTime) {\n        // Set startTime on first step, or _startTime may has milleseconds different between clips\n        // PENDING\n        if (!this._initialized) {\n            this._startTime = globalTime + this._delay;\n            this._initialized = true;\n        }\n\n        if (this._paused) {\n            this._pausedTime += deltaTime;\n            return;\n        }\n\n        var percent = (globalTime - this._startTime - this._pausedTime) / this._life;\n\n        // 还没开始\n        if (percent < 0) {\n            return;\n        }\n\n        percent = Math.min(percent, 1);\n\n        var easing$$1 = this.easing;\n        var easingFunc = typeof easing$$1 === 'string' ? easing[easing$$1] : easing$$1;\n        var schedule = typeof easingFunc === 'function'\n            ? easingFunc(percent)\n            : percent;\n\n        this.fire('frame', schedule);\n\n        // 结束\n        if (percent === 1) {\n            if (this.loop) {\n                this.restart(globalTime);\n                // 重新开始周期\n                // 抛出而不是直接调用事件直到 stage.update 后再统一调用这些事件\n                return 'restart';\n            }\n\n            // 动画完成将这个控制器标识为待删除\n            // 在Animation.update中进行批量删除\n            this._needsRemove = true;\n            return 'destroy';\n        }\n\n        return null;\n    },\n\n    restart: function (globalTime) {\n        var remainder = (globalTime - this._startTime - this._pausedTime) % this._life;\n        this._startTime = globalTime - remainder + this.gap;\n        this._pausedTime = 0;\n\n        this._needsRemove = false;\n    },\n\n    fire: function (eventType, arg) {\n        eventType = 'on' + eventType;\n        if (this[eventType]) {\n            this[eventType](this._target, arg);\n        }\n    },\n\n    pause: function () {\n        this._paused = true;\n    },\n\n    resume: function () {\n        this._paused = false;\n    }\n};\n\n// Simple LRU cache use doubly linked list\n// @module zrender/core/LRU\n\n/**\n * Simple double linked list. Compared with array, it has O(1) remove operation.\n * @constructor\n */\nvar LinkedList = function () {\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.head = null;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.tail = null;\n\n    this._len = 0;\n};\n\nvar linkedListProto = LinkedList.prototype;\n/**\n * Insert a new value at the tail\n * @param  {} val\n * @return {module:zrender/core/LRU~Entry}\n */\nlinkedListProto.insert = function (val) {\n    var entry = new Entry(val);\n    this.insertEntry(entry);\n    return entry;\n};\n\n/**\n * Insert an entry at the tail\n * @param  {module:zrender/core/LRU~Entry} entry\n */\nlinkedListProto.insertEntry = function (entry) {\n    if (!this.head) {\n        this.head = this.tail = entry;\n    }\n    else {\n        this.tail.next = entry;\n        entry.prev = this.tail;\n        entry.next = null;\n        this.tail = entry;\n    }\n    this._len++;\n};\n\n/**\n * Remove entry.\n * @param  {module:zrender/core/LRU~Entry} entry\n */\nlinkedListProto.remove = function (entry) {\n    var prev = entry.prev;\n    var next = entry.next;\n    if (prev) {\n        prev.next = next;\n    }\n    else {\n        // Is head\n        this.head = next;\n    }\n    if (next) {\n        next.prev = prev;\n    }\n    else {\n        // Is tail\n        this.tail = prev;\n    }\n    entry.next = entry.prev = null;\n    this._len--;\n};\n\n/**\n * @return {number}\n */\nlinkedListProto.len = function () {\n    return this._len;\n};\n\n/**\n * Clear list\n */\nlinkedListProto.clear = function () {\n    this.head = this.tail = null;\n    this._len = 0;\n};\n\n/**\n * @constructor\n * @param {} val\n */\nvar Entry = function (val) {\n    /**\n     * @type {}\n     */\n    this.value = val;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.next;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.prev;\n};\n\n/**\n * LRU Cache\n * @constructor\n * @alias module:zrender/core/LRU\n */\nvar LRU = function (maxSize) {\n\n    this._list = new LinkedList();\n\n    this._map = {};\n\n    this._maxSize = maxSize || 10;\n\n    this._lastRemovedEntry = null;\n};\n\nvar LRUProto = LRU.prototype;\n\n/**\n * @param  {string} key\n * @param  {} value\n * @return {} Removed value\n */\nLRUProto.put = function (key, value) {\n    var list = this._list;\n    var map = this._map;\n    var removed = null;\n    if (map[key] == null) {\n        var len = list.len();\n        // Reuse last removed entry\n        var entry = this._lastRemovedEntry;\n\n        if (len >= this._maxSize && len > 0) {\n            // Remove the least recently used\n            var leastUsedEntry = list.head;\n            list.remove(leastUsedEntry);\n            delete map[leastUsedEntry.key];\n\n            removed = leastUsedEntry.value;\n            this._lastRemovedEntry = leastUsedEntry;\n        }\n\n        if (entry) {\n            entry.value = value;\n        }\n        else {\n            entry = new Entry(value);\n        }\n        entry.key = key;\n        list.insertEntry(entry);\n        map[key] = entry;\n    }\n\n    return removed;\n};\n\n/**\n * @param  {string} key\n * @return {}\n */\nLRUProto.get = function (key) {\n    var entry = this._map[key];\n    var list = this._list;\n    if (entry != null) {\n        // Put the latest used entry in the tail\n        if (entry !== list.tail) {\n            list.remove(entry);\n            list.insertEntry(entry);\n        }\n\n        return entry.value;\n    }\n};\n\n/**\n * Clear the cache\n */\nLRUProto.clear = function () {\n    this._list.clear();\n    this._map = {};\n};\n\nvar kCSSColorTable = {\n    'transparent': [0, 0, 0, 0], 'aliceblue': [240, 248, 255, 1],\n    'antiquewhite': [250, 235, 215, 1], 'aqua': [0, 255, 255, 1],\n    'aquamarine': [127, 255, 212, 1], 'azure': [240, 255, 255, 1],\n    'beige': [245, 245, 220, 1], 'bisque': [255, 228, 196, 1],\n    'black': [0, 0, 0, 1], 'blanchedalmond': [255, 235, 205, 1],\n    'blue': [0, 0, 255, 1], 'blueviolet': [138, 43, 226, 1],\n    'brown': [165, 42, 42, 1], 'burlywood': [222, 184, 135, 1],\n    'cadetblue': [95, 158, 160, 1], 'chartreuse': [127, 255, 0, 1],\n    'chocolate': [210, 105, 30, 1], 'coral': [255, 127, 80, 1],\n    'cornflowerblue': [100, 149, 237, 1], 'cornsilk': [255, 248, 220, 1],\n    'crimson': [220, 20, 60, 1], 'cyan': [0, 255, 255, 1],\n    'darkblue': [0, 0, 139, 1], 'darkcyan': [0, 139, 139, 1],\n    'darkgoldenrod': [184, 134, 11, 1], 'darkgray': [169, 169, 169, 1],\n    'darkgreen': [0, 100, 0, 1], 'darkgrey': [169, 169, 169, 1],\n    'darkkhaki': [189, 183, 107, 1], 'darkmagenta': [139, 0, 139, 1],\n    'darkolivegreen': [85, 107, 47, 1], 'darkorange': [255, 140, 0, 1],\n    'darkorchid': [153, 50, 204, 1], 'darkred': [139, 0, 0, 1],\n    'darksalmon': [233, 150, 122, 1], 'darkseagreen': [143, 188, 143, 1],\n    'darkslateblue': [72, 61, 139, 1], 'darkslategray': [47, 79, 79, 1],\n    'darkslategrey': [47, 79, 79, 1], 'darkturquoise': [0, 206, 209, 1],\n    'darkviolet': [148, 0, 211, 1], 'deeppink': [255, 20, 147, 1],\n    'deepskyblue': [0, 191, 255, 1], 'dimgray': [105, 105, 105, 1],\n    'dimgrey': [105, 105, 105, 1], 'dodgerblue': [30, 144, 255, 1],\n    'firebrick': [178, 34, 34, 1], 'floralwhite': [255, 250, 240, 1],\n    'forestgreen': [34, 139, 34, 1], 'fuchsia': [255, 0, 255, 1],\n    'gainsboro': [220, 220, 220, 1], 'ghostwhite': [248, 248, 255, 1],\n    'gold': [255, 215, 0, 1], 'goldenrod': [218, 165, 32, 1],\n    'gray': [128, 128, 128, 1], 'green': [0, 128, 0, 1],\n    'greenyellow': [173, 255, 47, 1], 'grey': [128, 128, 128, 1],\n    'honeydew': [240, 255, 240, 1], 'hotpink': [255, 105, 180, 1],\n    'indianred': [205, 92, 92, 1], 'indigo': [75, 0, 130, 1],\n    'ivory': [255, 255, 240, 1], 'khaki': [240, 230, 140, 1],\n    'lavender': [230, 230, 250, 1], 'lavenderblush': [255, 240, 245, 1],\n    'lawngreen': [124, 252, 0, 1], 'lemonchiffon': [255, 250, 205, 1],\n    'lightblue': [173, 216, 230, 1], 'lightcoral': [240, 128, 128, 1],\n    'lightcyan': [224, 255, 255, 1], 'lightgoldenrodyellow': [250, 250, 210, 1],\n    'lightgray': [211, 211, 211, 1], 'lightgreen': [144, 238, 144, 1],\n    'lightgrey': [211, 211, 211, 1], 'lightpink': [255, 182, 193, 1],\n    'lightsalmon': [255, 160, 122, 1], 'lightseagreen': [32, 178, 170, 1],\n    'lightskyblue': [135, 206, 250, 1], 'lightslategray': [119, 136, 153, 1],\n    'lightslategrey': [119, 136, 153, 1], 'lightsteelblue': [176, 196, 222, 1],\n    'lightyellow': [255, 255, 224, 1], 'lime': [0, 255, 0, 1],\n    'limegreen': [50, 205, 50, 1], 'linen': [250, 240, 230, 1],\n    'magenta': [255, 0, 255, 1], 'maroon': [128, 0, 0, 1],\n    'mediumaquamarine': [102, 205, 170, 1], 'mediumblue': [0, 0, 205, 1],\n    'mediumorchid': [186, 85, 211, 1], 'mediumpurple': [147, 112, 219, 1],\n    'mediumseagreen': [60, 179, 113, 1], 'mediumslateblue': [123, 104, 238, 1],\n    'mediumspringgreen': [0, 250, 154, 1], 'mediumturquoise': [72, 209, 204, 1],\n    'mediumvioletred': [199, 21, 133, 1], 'midnightblue': [25, 25, 112, 1],\n    'mintcream': [245, 255, 250, 1], 'mistyrose': [255, 228, 225, 1],\n    'moccasin': [255, 228, 181, 1], 'navajowhite': [255, 222, 173, 1],\n    'navy': [0, 0, 128, 1], 'oldlace': [253, 245, 230, 1],\n    'olive': [128, 128, 0, 1], 'olivedrab': [107, 142, 35, 1],\n    'orange': [255, 165, 0, 1], 'orangered': [255, 69, 0, 1],\n    'orchid': [218, 112, 214, 1], 'palegoldenrod': [238, 232, 170, 1],\n    'palegreen': [152, 251, 152, 1], 'paleturquoise': [175, 238, 238, 1],\n    'palevioletred': [219, 112, 147, 1], 'papayawhip': [255, 239, 213, 1],\n    'peachpuff': [255, 218, 185, 1], 'peru': [205, 133, 63, 1],\n    'pink': [255, 192, 203, 1], 'plum': [221, 160, 221, 1],\n    'powderblue': [176, 224, 230, 1], 'purple': [128, 0, 128, 1],\n    'red': [255, 0, 0, 1], 'rosybrown': [188, 143, 143, 1],\n    'royalblue': [65, 105, 225, 1], 'saddlebrown': [139, 69, 19, 1],\n    'salmon': [250, 128, 114, 1], 'sandybrown': [244, 164, 96, 1],\n    'seagreen': [46, 139, 87, 1], 'seashell': [255, 245, 238, 1],\n    'sienna': [160, 82, 45, 1], 'silver': [192, 192, 192, 1],\n    'skyblue': [135, 206, 235, 1], 'slateblue': [106, 90, 205, 1],\n    'slategray': [112, 128, 144, 1], 'slategrey': [112, 128, 144, 1],\n    'snow': [255, 250, 250, 1], 'springgreen': [0, 255, 127, 1],\n    'steelblue': [70, 130, 180, 1], 'tan': [210, 180, 140, 1],\n    'teal': [0, 128, 128, 1], 'thistle': [216, 191, 216, 1],\n    'tomato': [255, 99, 71, 1], 'turquoise': [64, 224, 208, 1],\n    'violet': [238, 130, 238, 1], 'wheat': [245, 222, 179, 1],\n    'white': [255, 255, 255, 1], 'whitesmoke': [245, 245, 245, 1],\n    'yellow': [255, 255, 0, 1], 'yellowgreen': [154, 205, 50, 1]\n};\n\nfunction clampCssByte(i) {  // Clamp to integer 0 .. 255.\n    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).\n    return i < 0 ? 0 : i > 255 ? 255 : i;\n}\n\nfunction clampCssFloat(f) {  // Clamp to float 0.0 .. 1.0.\n    return f < 0 ? 0 : f > 1 ? 1 : f;\n}\n\nfunction parseCssInt(str) {  // int or percentage.\n    if (str.length && str.charAt(str.length - 1) === '%') {\n        return clampCssByte(parseFloat(str) / 100 * 255);\n    }\n    return clampCssByte(parseInt(str, 10));\n}\n\nfunction parseCssFloat(str) {  // float or percentage.\n    if (str.length && str.charAt(str.length - 1) === '%') {\n        return clampCssFloat(parseFloat(str) / 100);\n    }\n    return clampCssFloat(parseFloat(str));\n}\n\nfunction cssHueToRgb(m1, m2, h) {\n    if (h < 0) {\n        h += 1;\n    }\n    else if (h > 1) {\n        h -= 1;\n    }\n\n    if (h * 6 < 1) {\n        return m1 + (m2 - m1) * h * 6;\n    }\n    if (h * 2 < 1) {\n        return m2;\n    }\n    if (h * 3 < 2) {\n        return m1 + (m2 - m1) * (2 / 3 - h) * 6;\n    }\n    return m1;\n}\n\nfunction setRgba(out, r, g, b, a) {\n    out[0] = r; out[1] = g; out[2] = b; out[3] = a;\n    return out;\n}\nfunction copyRgba(out, a) {\n    out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3];\n    return out;\n}\n\nvar colorCache = new LRU(20);\nvar lastRemovedArr = null;\n\nfunction putToCache(colorStr, rgbaArr) {\n    // Reuse removed array\n    if (lastRemovedArr) {\n        copyRgba(lastRemovedArr, rgbaArr);\n    }\n    lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice()));\n}\n\n/**\n * @param {string} colorStr\n * @param {Array.<number>} out\n * @return {Array.<number>}\n * @memberOf module:zrender/util/color\n */\nfunction parse(colorStr, rgbaArr) {\n    if (!colorStr) {\n        return;\n    }\n    rgbaArr = rgbaArr || [];\n\n    var cached = colorCache.get(colorStr);\n    if (cached) {\n        return copyRgba(rgbaArr, cached);\n    }\n\n    // colorStr may be not string\n    colorStr = colorStr + '';\n    // Remove all whitespace, not compliant, but should just be more accepting.\n    var str = colorStr.replace(/ /g, '').toLowerCase();\n\n    // Color keywords (and transparent) lookup.\n    if (str in kCSSColorTable) {\n        copyRgba(rgbaArr, kCSSColorTable[str]);\n        putToCache(colorStr, rgbaArr);\n        return rgbaArr;\n    }\n\n    // #abc and #abc123 syntax.\n    if (str.charAt(0) === '#') {\n        if (str.length === 4) {\n            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n            if (!(iv >= 0 && iv <= 0xfff)) {\n                setRgba(rgbaArr, 0, 0, 0, 1);\n                return;  // Covers NaN.\n            }\n            setRgba(rgbaArr,\n                ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8),\n                (iv & 0xf0) | ((iv & 0xf0) >> 4),\n                (iv & 0xf) | ((iv & 0xf) << 4),\n                1\n            );\n            putToCache(colorStr, rgbaArr);\n            return rgbaArr;\n        }\n        else if (str.length === 7) {\n            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n            if (!(iv >= 0 && iv <= 0xffffff)) {\n                setRgba(rgbaArr, 0, 0, 0, 1);\n                return;  // Covers NaN.\n            }\n            setRgba(rgbaArr,\n                (iv & 0xff0000) >> 16,\n                (iv & 0xff00) >> 8,\n                iv & 0xff,\n                1\n            );\n            putToCache(colorStr, rgbaArr);\n            return rgbaArr;\n        }\n\n        return;\n    }\n    var op = str.indexOf('(');\n    var ep = str.indexOf(')');\n    if (op !== -1 && ep + 1 === str.length) {\n        var fname = str.substr(0, op);\n        var params = str.substr(op + 1, ep - (op + 1)).split(',');\n        var alpha = 1;  // To allow case fallthrough.\n        switch (fname) {\n            case 'rgba':\n                if (params.length !== 4) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                alpha = parseCssFloat(params.pop()); // jshint ignore:line\n            // Fall through.\n            case 'rgb':\n                if (params.length !== 3) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                setRgba(rgbaArr,\n                    parseCssInt(params[0]),\n                    parseCssInt(params[1]),\n                    parseCssInt(params[2]),\n                    alpha\n                );\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            case 'hsla':\n                if (params.length !== 4) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                params[3] = parseCssFloat(params[3]);\n                hsla2rgba(params, rgbaArr);\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            case 'hsl':\n                if (params.length !== 3) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                hsla2rgba(params, rgbaArr);\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            default:\n                return;\n        }\n    }\n\n    setRgba(rgbaArr, 0, 0, 0, 1);\n    return;\n}\n\n/**\n * @param {Array.<number>} hsla\n * @param {Array.<number>} rgba\n * @return {Array.<number>} rgba\n */\nfunction hsla2rgba(hsla, rgba) {\n    var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360;  // 0 .. 1\n    // NOTE(deanm): According to the CSS spec s/l should only be\n    // percentages, but we don't bother and let float or percentage.\n    var s = parseCssFloat(hsla[1]);\n    var l = parseCssFloat(hsla[2]);\n    var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;\n    var m1 = l * 2 - m2;\n\n    rgba = rgba || [];\n    setRgba(rgba,\n        clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255),\n        clampCssByte(cssHueToRgb(m1, m2, h) * 255),\n        clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255),\n        1\n    );\n\n    if (hsla.length === 4) {\n        rgba[3] = hsla[3];\n    }\n\n    return rgba;\n}\n\n/**\n * @param {string} color\n * @param {number} level\n * @return {string}\n * @memberOf module:zrender/util/color\n */\nfunction lift(color, level) {\n    var colorArr = parse(color);\n    if (colorArr) {\n        for (var i = 0; i < 3; i++) {\n            if (level < 0) {\n                colorArr[i] = colorArr[i] * (1 - level) | 0;\n            }\n            else {\n                colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0;\n            }\n            if (colorArr[i] > 255) {\n                colorArr[i] = 255;\n            }\n            else if (color[i] < 0) {\n                colorArr[i] = 0;\n            }\n        }\n        return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');\n    }\n}\n\n/**\n * @param {string} color\n * @return {string}\n * @memberOf module:zrender/util/color\n */\n\n\n/**\n * Map value to color. Faster than lerp methods because color is represented by rgba array.\n * @param {number} normalizedValue A float between 0 and 1.\n * @param {Array.<Array.<number>>} colors List of rgba color array\n * @param {Array.<number>} [out] Mapped gba color array\n * @return {Array.<number>} will be null/undefined if input illegal.\n */\n\n\n/**\n * @deprecated\n */\n\n\n/**\n * @param {number} normalizedValue A float between 0 and 1.\n * @param {Array.<string>} colors Color list.\n * @param {boolean=} fullOutput Default false.\n * @return {(string|Object)} Result color. If fullOutput,\n *                           return {color: ..., leftIndex: ..., rightIndex: ..., value: ...},\n * @memberOf module:zrender/util/color\n */\n\n\n/**\n * @deprecated\n */\n\n\n/**\n * @param {string} color\n * @param {number=} h 0 ~ 360, ignore when null.\n * @param {number=} s 0 ~ 1, ignore when null.\n * @param {number=} l 0 ~ 1, ignore when null.\n * @return {string} Color string in rgba format.\n * @memberOf module:zrender/util/color\n */\n\n\n/**\n * @param {string} color\n * @param {number=} alpha 0 ~ 1\n * @return {string} Color string in rgba format.\n * @memberOf module:zrender/util/color\n */\n\n\n/**\n * @param {Array.<number>} arrColor like [12,33,44,0.4]\n * @param {string} type 'rgba', 'hsva', ...\n * @return {string} Result color. (If input illegal, return undefined).\n */\nfunction stringify(arrColor, type) {\n    if (!arrColor || !arrColor.length) {\n        return;\n    }\n    var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];\n    if (type === 'rgba' || type === 'hsva' || type === 'hsla') {\n        colorStr += ',' + arrColor[3];\n    }\n    return type + '(' + colorStr + ')';\n}\n\n/**\n * @module echarts/animation/Animator\n */\n\nvar arraySlice = Array.prototype.slice;\n\nfunction defaultGetter(target, key) {\n    return target[key];\n}\n\nfunction defaultSetter(target, key, value) {\n    target[key] = value;\n}\n\n/**\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} percent\n * @return {number}\n */\nfunction interpolateNumber(p0, p1, percent) {\n    return (p1 - p0) * percent + p0;\n}\n\n/**\n * @param  {string} p0\n * @param  {string} p1\n * @param  {number} percent\n * @return {string}\n */\nfunction interpolateString(p0, p1, percent) {\n    return percent > 0.5 ? p1 : p0;\n}\n\n/**\n * @param  {Array} p0\n * @param  {Array} p1\n * @param  {number} percent\n * @param  {Array} out\n * @param  {number} arrDim\n */\nfunction interpolateArray(p0, p1, percent, out, arrDim) {\n    var len = p0.length;\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            out[i] = interpolateNumber(p0[i], p1[i], percent);\n        }\n    }\n    else {\n        var len2 = len && p0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                out[i][j] = interpolateNumber(\n                    p0[i][j], p1[i][j], percent\n                );\n            }\n        }\n    }\n}\n\n// arr0 is source array, arr1 is target array.\n// Do some preprocess to avoid error happened when interpolating from arr0 to arr1\nfunction fillArr(arr0, arr1, arrDim) {\n    var arr0Len = arr0.length;\n    var arr1Len = arr1.length;\n    if (arr0Len !== arr1Len) {\n        // FIXME Not work for TypedArray\n        var isPreviousLarger = arr0Len > arr1Len;\n        if (isPreviousLarger) {\n            // Cut the previous\n            arr0.length = arr1Len;\n        }\n        else {\n            // Fill the previous\n            for (var i = arr0Len; i < arr1Len; i++) {\n                arr0.push(\n                    arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i])\n                );\n            }\n        }\n    }\n    // Handling NaN value\n    var len2 = arr0[0] && arr0[0].length;\n    for (var i = 0; i < arr0.length; i++) {\n        if (arrDim === 1) {\n            if (isNaN(arr0[i])) {\n                arr0[i] = arr1[i];\n            }\n        }\n        else {\n            for (var j = 0; j < len2; j++) {\n                if (isNaN(arr0[i][j])) {\n                    arr0[i][j] = arr1[i][j];\n                }\n            }\n        }\n    }\n}\n\n/**\n * @param  {Array} arr0\n * @param  {Array} arr1\n * @param  {number} arrDim\n * @return {boolean}\n */\nfunction isArraySame(arr0, arr1, arrDim) {\n    if (arr0 === arr1) {\n        return true;\n    }\n    var len = arr0.length;\n    if (len !== arr1.length) {\n        return false;\n    }\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            if (arr0[i] !== arr1[i]) {\n                return false;\n            }\n        }\n    }\n    else {\n        var len2 = arr0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                if (arr0[i][j] !== arr1[i][j]) {\n                    return false;\n                }\n            }\n        }\n    }\n    return true;\n}\n\n/**\n * Catmull Rom interpolate array\n * @param  {Array} p0\n * @param  {Array} p1\n * @param  {Array} p2\n * @param  {Array} p3\n * @param  {number} t\n * @param  {number} t2\n * @param  {number} t3\n * @param  {Array} out\n * @param  {number} arrDim\n */\nfunction catmullRomInterpolateArray(\n    p0, p1, p2, p3, t, t2, t3, out, arrDim\n) {\n    var len = p0.length;\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            out[i] = catmullRomInterpolate(\n                p0[i], p1[i], p2[i], p3[i], t, t2, t3\n            );\n        }\n    }\n    else {\n        var len2 = p0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                out[i][j] = catmullRomInterpolate(\n                    p0[i][j], p1[i][j], p2[i][j], p3[i][j],\n                    t, t2, t3\n                );\n            }\n        }\n    }\n}\n\n/**\n * Catmull Rom interpolate number\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @param  {number} t2\n * @param  {number} t3\n * @return {number}\n */\nfunction catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {\n    var v0 = (p2 - p0) * 0.5;\n    var v1 = (p3 - p1) * 0.5;\n    return (2 * (p1 - p2) + v0 + v1) * t3\n            + (-3 * (p1 - p2) - 2 * v0 - v1) * t2\n            + v0 * t + p1;\n}\n\nfunction cloneValue(value) {\n    if (isArrayLike(value)) {\n        var len = value.length;\n        if (isArrayLike(value[0])) {\n            var ret = [];\n            for (var i = 0; i < len; i++) {\n                ret.push(arraySlice.call(value[i]));\n            }\n            return ret;\n        }\n\n        return arraySlice.call(value);\n    }\n\n    return value;\n}\n\nfunction rgba2String(rgba) {\n    rgba[0] = Math.floor(rgba[0]);\n    rgba[1] = Math.floor(rgba[1]);\n    rgba[2] = Math.floor(rgba[2]);\n\n    return 'rgba(' + rgba.join(',') + ')';\n}\n\nfunction getArrayDim(keyframes) {\n    var lastValue = keyframes[keyframes.length - 1].value;\n    return isArrayLike(lastValue && lastValue[0]) ? 2 : 1;\n}\n\nfunction createTrackClip(animator, easing, oneTrackDone, keyframes, propName, forceAnimate) {\n    var getter = animator._getter;\n    var setter = animator._setter;\n    var useSpline = easing === 'spline';\n\n    var trackLen = keyframes.length;\n    if (!trackLen) {\n        return;\n    }\n    // Guess data type\n    var firstVal = keyframes[0].value;\n    var isValueArray = isArrayLike(firstVal);\n    var isValueColor = false;\n    var isValueString = false;\n\n    // For vertices morphing\n    var arrDim = isValueArray ? getArrayDim(keyframes) : 0;\n\n    var trackMaxTime;\n    // Sort keyframe as ascending\n    keyframes.sort(function (a, b) {\n        return a.time - b.time;\n    });\n\n    trackMaxTime = keyframes[trackLen - 1].time;\n    // Percents of each keyframe\n    var kfPercents = [];\n    // Value of each keyframe\n    var kfValues = [];\n    var prevValue = keyframes[0].value;\n    var isAllValueEqual = true;\n    for (var i = 0; i < trackLen; i++) {\n        kfPercents.push(keyframes[i].time / trackMaxTime);\n        // Assume value is a color when it is a string\n        var value = keyframes[i].value;\n\n        // Check if value is equal, deep check if value is array\n        if (!((isValueArray && isArraySame(value, prevValue, arrDim))\n            || (!isValueArray && value === prevValue))) {\n            isAllValueEqual = false;\n        }\n        prevValue = value;\n\n        // Try converting a string to a color array\n        if (typeof value === 'string') {\n            var colorArray = parse(value);\n            if (colorArray) {\n                value = colorArray;\n                isValueColor = true;\n            }\n            else {\n                isValueString = true;\n            }\n        }\n        kfValues.push(value);\n    }\n    if (!forceAnimate && isAllValueEqual) {\n        return;\n    }\n\n    var lastValue = kfValues[trackLen - 1];\n    // Polyfill array and NaN value\n    for (var i = 0; i < trackLen - 1; i++) {\n        if (isValueArray) {\n            fillArr(kfValues[i], lastValue, arrDim);\n        }\n        else {\n            if (isNaN(kfValues[i]) && !isNaN(lastValue) && !isValueString && !isValueColor) {\n                kfValues[i] = lastValue;\n            }\n        }\n    }\n    isValueArray && fillArr(getter(animator._target, propName), lastValue, arrDim);\n\n    // Cache the key of last frame to speed up when\n    // animation playback is sequency\n    var lastFrame = 0;\n    var lastFramePercent = 0;\n    var start;\n    var w;\n    var p0;\n    var p1;\n    var p2;\n    var p3;\n\n    if (isValueColor) {\n        var rgba = [0, 0, 0, 0];\n    }\n\n    var onframe = function (target, percent) {\n        // Find the range keyframes\n        // kf1-----kf2---------current--------kf3\n        // find kf2 and kf3 and do interpolation\n        var frame;\n        // In the easing function like elasticOut, percent may less than 0\n        if (percent < 0) {\n            frame = 0;\n        }\n        else if (percent < lastFramePercent) {\n            // Start from next key\n            // PENDING start from lastFrame ?\n            start = Math.min(lastFrame + 1, trackLen - 1);\n            for (frame = start; frame >= 0; frame--) {\n                if (kfPercents[frame] <= percent) {\n                    break;\n                }\n            }\n            // PENDING really need to do this ?\n            frame = Math.min(frame, trackLen - 2);\n        }\n        else {\n            for (frame = lastFrame; frame < trackLen; frame++) {\n                if (kfPercents[frame] > percent) {\n                    break;\n                }\n            }\n            frame = Math.min(frame - 1, trackLen - 2);\n        }\n        lastFrame = frame;\n        lastFramePercent = percent;\n\n        var range = (kfPercents[frame + 1] - kfPercents[frame]);\n        if (range === 0) {\n            return;\n        }\n        else {\n            w = (percent - kfPercents[frame]) / range;\n        }\n        if (useSpline) {\n            p1 = kfValues[frame];\n            p0 = kfValues[frame === 0 ? frame : frame - 1];\n            p2 = kfValues[frame > trackLen - 2 ? trackLen - 1 : frame + 1];\n            p3 = kfValues[frame > trackLen - 3 ? trackLen - 1 : frame + 2];\n            if (isValueArray) {\n                catmullRomInterpolateArray(\n                    p0, p1, p2, p3, w, w * w, w * w * w,\n                    getter(target, propName),\n                    arrDim\n                );\n            }\n            else {\n                var value;\n                if (isValueColor) {\n                    value = catmullRomInterpolateArray(\n                        p0, p1, p2, p3, w, w * w, w * w * w,\n                        rgba, 1\n                    );\n                    value = rgba2String(rgba);\n                }\n                else if (isValueString) {\n                    // String is step(0.5)\n                    return interpolateString(p1, p2, w);\n                }\n                else {\n                    value = catmullRomInterpolate(\n                        p0, p1, p2, p3, w, w * w, w * w * w\n                    );\n                }\n                setter(\n                    target,\n                    propName,\n                    value\n                );\n            }\n        }\n        else {\n            if (isValueArray) {\n                interpolateArray(\n                    kfValues[frame], kfValues[frame + 1], w,\n                    getter(target, propName),\n                    arrDim\n                );\n            }\n            else {\n                var value;\n                if (isValueColor) {\n                    interpolateArray(\n                        kfValues[frame], kfValues[frame + 1], w,\n                        rgba, 1\n                    );\n                    value = rgba2String(rgba);\n                }\n                else if (isValueString) {\n                    // String is step(0.5)\n                    return interpolateString(kfValues[frame], kfValues[frame + 1], w);\n                }\n                else {\n                    value = interpolateNumber(kfValues[frame], kfValues[frame + 1], w);\n                }\n                setter(\n                    target,\n                    propName,\n                    value\n                );\n            }\n        }\n    };\n\n    var clip = new Clip({\n        target: animator._target,\n        life: trackMaxTime,\n        loop: animator._loop,\n        delay: animator._delay,\n        onframe: onframe,\n        ondestroy: oneTrackDone\n    });\n\n    if (easing && easing !== 'spline') {\n        clip.easing = easing;\n    }\n\n    return clip;\n}\n\n/**\n * @alias module:zrender/animation/Animator\n * @constructor\n * @param {Object} target\n * @param {boolean} loop\n * @param {Function} getter\n * @param {Function} setter\n */\nvar Animator = function (target, loop, getter, setter) {\n    this._tracks = {};\n    this._target = target;\n\n    this._loop = loop || false;\n\n    this._getter = getter || defaultGetter;\n    this._setter = setter || defaultSetter;\n\n    this._clipCount = 0;\n\n    this._delay = 0;\n\n    this._doneList = [];\n\n    this._onframeList = [];\n\n    this._clipList = [];\n};\n\nAnimator.prototype = {\n    /**\n     * 设置动画关键帧\n     * @param  {number} time 关键帧时间，单位是ms\n     * @param  {Object} props 关键帧的属性值，key-value表示\n     * @return {module:zrender/animation/Animator}\n     */\n    when: function (time /* ms */, props) {\n        var tracks = this._tracks;\n        for (var propName in props) {\n            if (!props.hasOwnProperty(propName)) {\n                continue;\n            }\n\n            if (!tracks[propName]) {\n                tracks[propName] = [];\n                // Invalid value\n                var value = this._getter(this._target, propName);\n                if (value == null) {\n                    // zrLog('Invalid property ' + propName);\n                    continue;\n                }\n                // If time is 0\n                //  Then props is given initialize value\n                // Else\n                //  Initialize value from current prop value\n                if (time !== 0) {\n                    tracks[propName].push({\n                        time: 0,\n                        value: cloneValue(value)\n                    });\n                }\n            }\n            tracks[propName].push({\n                time: time,\n                value: props[propName]\n            });\n        }\n        return this;\n    },\n    /**\n     * 添加动画每一帧的回调函数\n     * @param  {Function} callback\n     * @return {module:zrender/animation/Animator}\n     */\n    during: function (callback) {\n        this._onframeList.push(callback);\n        return this;\n    },\n\n    pause: function () {\n        for (var i = 0; i < this._clipList.length; i++) {\n            this._clipList[i].pause();\n        }\n        this._paused = true;\n    },\n\n    resume: function () {\n        for (var i = 0; i < this._clipList.length; i++) {\n            this._clipList[i].resume();\n        }\n        this._paused = false;\n    },\n\n    isPaused: function () {\n        return !!this._paused;\n    },\n\n    _doneCallback: function () {\n        // Clear all tracks\n        this._tracks = {};\n        // Clear all clips\n        this._clipList.length = 0;\n\n        var doneList = this._doneList;\n        var len = doneList.length;\n        for (var i = 0; i < len; i++) {\n            doneList[i].call(this);\n        }\n    },\n    /**\n     * 开始执行动画\n     * @param  {string|Function} [easing]\n     *         动画缓动函数，详见{@link module:zrender/animation/easing}\n     * @param  {boolean} forceAnimate\n     * @return {module:zrender/animation/Animator}\n     */\n    start: function (easing, forceAnimate) {\n\n        var self = this;\n        var clipCount = 0;\n\n        var oneTrackDone = function () {\n            clipCount--;\n            if (!clipCount) {\n                self._doneCallback();\n            }\n        };\n\n        var lastClip;\n        for (var propName in this._tracks) {\n            if (!this._tracks.hasOwnProperty(propName)) {\n                continue;\n            }\n            var clip = createTrackClip(\n                this, easing, oneTrackDone,\n                this._tracks[propName], propName, forceAnimate\n            );\n            if (clip) {\n                this._clipList.push(clip);\n                clipCount++;\n\n                // If start after added to animation\n                if (this.animation) {\n                    this.animation.addClip(clip);\n                }\n\n                lastClip = clip;\n            }\n        }\n\n        // Add during callback on the last clip\n        if (lastClip) {\n            var oldOnFrame = lastClip.onframe;\n            lastClip.onframe = function (target, percent) {\n                oldOnFrame(target, percent);\n\n                for (var i = 0; i < self._onframeList.length; i++) {\n                    self._onframeList[i](target, percent);\n                }\n            };\n        }\n\n        // This optimization will help the case that in the upper application\n        // the view may be refreshed frequently, where animation will be\n        // called repeatly but nothing changed.\n        if (!clipCount) {\n            this._doneCallback();\n        }\n        return this;\n    },\n    /**\n     * 停止动画\n     * @param {boolean} forwardToLast If move to last frame before stop\n     */\n    stop: function (forwardToLast) {\n        var clipList = this._clipList;\n        var animation = this.animation;\n        for (var i = 0; i < clipList.length; i++) {\n            var clip = clipList[i];\n            if (forwardToLast) {\n                // Move to last frame before stop\n                clip.onframe(this._target, 1);\n            }\n            animation && animation.removeClip(clip);\n        }\n        clipList.length = 0;\n    },\n    /**\n     * 设置动画延迟开始的时间\n     * @param  {number} time 单位ms\n     * @return {module:zrender/animation/Animator}\n     */\n    delay: function (time) {\n        this._delay = time;\n        return this;\n    },\n    /**\n     * 添加动画结束的回调\n     * @param  {Function} cb\n     * @return {module:zrender/animation/Animator}\n     */\n    done: function (cb) {\n        if (cb) {\n            this._doneList.push(cb);\n        }\n        return this;\n    },\n\n    /**\n     * @return {Array.<module:zrender/animation/Clip>}\n     */\n    getClips: function () {\n        return this._clipList;\n    }\n};\n\nvar dpr = 1;\n\n// If in browser environment\nif (typeof window !== 'undefined') {\n    dpr = Math.max(window.devicePixelRatio || 1, 1);\n}\n\n/**\n * config默认配置项\n * @exports zrender/config\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n */\n\n/**\n * debug日志选项：catchBrushException为true下有效\n * 0 : 不生成debug数据，发布用\n * 1 : 异常抛出，调试用\n * 2 : 控制台输出，调试用\n */\nvar debugMode = 0;\n\n// retina 屏幕优化\nvar devicePixelRatio = dpr;\n\nvar log = function () {\n};\n\nif (debugMode === 1) {\n    log = function () {\n        for (var k in arguments) {\n            throw new Error(arguments[k]);\n        }\n    };\n}\nelse if (debugMode > 1) {\n    log = function () {\n        for (var k in arguments) {\n            console.log(arguments[k]);\n        }\n    };\n}\n\nvar log$1 = log;\n\n/**\n * @alias modue:zrender/mixin/Animatable\n * @constructor\n */\nvar Animatable = function () {\n\n    /**\n     * @type {Array.<module:zrender/animation/Animator>}\n     * @readOnly\n     */\n    this.animators = [];\n};\n\nAnimatable.prototype = {\n\n    constructor: Animatable,\n\n    /**\n     * 动画\n     *\n     * @param {string} path The path to fetch value from object, like 'a.b.c'.\n     * @param {boolean} [loop] Whether to loop animation.\n     * @return {module:zrender/animation/Animator}\n     * @example:\n     *     el.animate('style', false)\n     *         .when(1000, {x: 10} )\n     *         .done(function(){ // Animation done })\n     *         .start()\n     */\n    animate: function (path, loop) {\n        var target;\n        var animatingShape = false;\n        var el = this;\n        var zr = this.__zr;\n        if (path) {\n            var pathSplitted = path.split('.');\n            var prop = el;\n            // If animating shape\n            animatingShape = pathSplitted[0] === 'shape';\n            for (var i = 0, l = pathSplitted.length; i < l; i++) {\n                if (!prop) {\n                    continue;\n                }\n                prop = prop[pathSplitted[i]];\n            }\n            if (prop) {\n                target = prop;\n            }\n        }\n        else {\n            target = el;\n        }\n\n        if (!target) {\n            log$1(\n                'Property \"'\n                + path\n                + '\" is not existed in element '\n                + el.id\n            );\n            return;\n        }\n\n        var animators = el.animators;\n\n        var animator = new Animator(target, loop);\n\n        animator.during(function (target) {\n            el.dirty(animatingShape);\n        })\n        .done(function () {\n            // FIXME Animator will not be removed if use `Animator#stop` to stop animation\n            animators.splice(indexOf(animators, animator), 1);\n        });\n\n        animators.push(animator);\n\n        // If animate after added to the zrender\n        if (zr) {\n            zr.animation.addAnimator(animator);\n        }\n\n        return animator;\n    },\n\n    /**\n     * 停止动画\n     * @param {boolean} forwardToLast If move to last frame before stop\n     */\n    stopAnimation: function (forwardToLast) {\n        var animators = this.animators;\n        var len = animators.length;\n        for (var i = 0; i < len; i++) {\n            animators[i].stop(forwardToLast);\n        }\n        animators.length = 0;\n\n        return this;\n    },\n\n    /**\n     * Caution: this method will stop previous animation.\n     * So do not use this method to one element twice before\n     * animation starts, unless you know what you are doing.\n     * @param {Object} target\n     * @param {number} [time=500] Time in ms\n     * @param {string} [easing='linear']\n     * @param {number} [delay=0]\n     * @param {Function} [callback]\n     * @param {Function} [forceAnimate] Prevent stop animation and callback\n     *        immediently when target values are the same as current values.\n     *\n     * @example\n     *  // Animate position\n     *  el.animateTo({\n     *      position: [10, 10]\n     *  }, function () { // done })\n     *\n     *  // Animate shape, style and position in 100ms, delayed 100ms, with cubicOut easing\n     *  el.animateTo({\n     *      shape: {\n     *          width: 500\n     *      },\n     *      style: {\n     *          fill: 'red'\n     *      }\n     *      position: [10, 10]\n     *  }, 100, 100, 'cubicOut', function () { // done })\n     */\n    // TODO Return animation key\n    animateTo: function (target, time, delay, easing, callback, forceAnimate) {\n        animateTo(this, target, time, delay, easing, callback, forceAnimate);\n    },\n\n    /**\n     * Animate from the target state to current state.\n     * The params and the return value are the same as `this.animateTo`.\n     */\n    animateFrom: function (target, time, delay, easing, callback, forceAnimate) {\n        animateTo(this, target, time, delay, easing, callback, forceAnimate, true);\n    }\n};\n\nfunction animateTo(animatable, target, time, delay, easing, callback, forceAnimate, reverse) {\n    // animateTo(target, time, easing, callback);\n    if (isString(delay)) {\n        callback = easing;\n        easing = delay;\n        delay = 0;\n    }\n    // animateTo(target, time, delay, callback);\n    else if (isFunction$1(easing)) {\n        callback = easing;\n        easing = 'linear';\n        delay = 0;\n    }\n    // animateTo(target, time, callback);\n    else if (isFunction$1(delay)) {\n        callback = delay;\n        delay = 0;\n    }\n    // animateTo(target, callback)\n    else if (isFunction$1(time)) {\n        callback = time;\n        time = 500;\n    }\n    // animateTo(target)\n    else if (!time) {\n        time = 500;\n    }\n    // Stop all previous animations\n    animatable.stopAnimation();\n    animateToShallow(animatable, '', animatable, target, time, delay, reverse);\n\n    // Animators may be removed immediately after start\n    // if there is nothing to animate\n    var animators = animatable.animators.slice();\n    var count = animators.length;\n    function done() {\n        count--;\n        if (!count) {\n            callback && callback();\n        }\n    }\n\n    // No animators. This should be checked before animators[i].start(),\n    // because 'done' may be executed immediately if no need to animate.\n    if (!count) {\n        callback && callback();\n    }\n    // Start after all animators created\n    // Incase any animator is done immediately when all animation properties are not changed\n    for (var i = 0; i < animators.length; i++) {\n        animators[i]\n            .done(done)\n            .start(easing, forceAnimate);\n    }\n}\n\n/**\n * @param {string} path=''\n * @param {Object} source=animatable\n * @param {Object} target\n * @param {number} [time=500]\n * @param {number} [delay=0]\n * @param {boolean} [reverse] If `true`, animate\n *        from the `target` to current state.\n *\n * @example\n *  // Animate position\n *  el._animateToShallow({\n *      position: [10, 10]\n *  })\n *\n *  // Animate shape, style and position in 100ms, delayed 100ms\n *  el._animateToShallow({\n *      shape: {\n *          width: 500\n *      },\n *      style: {\n *          fill: 'red'\n *      }\n *      position: [10, 10]\n *  }, 100, 100)\n */\nfunction animateToShallow(animatable, path, source, target, time, delay, reverse) {\n    var objShallow = {};\n    var propertyCount = 0;\n    for (var name in target) {\n        if (!target.hasOwnProperty(name)) {\n            continue;\n        }\n\n        if (source[name] != null) {\n            if (isObject$1(target[name]) && !isArrayLike(target[name])) {\n                animateToShallow(\n                    animatable,\n                    path ? path + '.' + name : name,\n                    source[name],\n                    target[name],\n                    time,\n                    delay,\n                    reverse\n                );\n            }\n            else {\n                if (reverse) {\n                    objShallow[name] = source[name];\n                    setAttrByPath(animatable, path, name, target[name]);\n                }\n                else {\n                    objShallow[name] = target[name];\n                }\n                propertyCount++;\n            }\n        }\n        else if (target[name] != null && !reverse) {\n            setAttrByPath(animatable, path, name, target[name]);\n        }\n    }\n\n    if (propertyCount > 0) {\n        animatable.animate(path, false)\n            .when(time == null ? 500 : time, objShallow)\n            .delay(delay || 0);\n    }\n}\n\nfunction setAttrByPath(el, path, name, value) {\n    // Attr directly if not has property\n    // FIXME, if some property not needed for element ?\n    if (!path) {\n        el.attr(name, value);\n    }\n    else {\n        // Only support set shape or style\n        var props = {};\n        props[path] = {};\n        props[path][name] = value;\n        el.attr(props);\n    }\n}\n\n/**\n * @alias module:zrender/Element\n * @constructor\n * @extends {module:zrender/mixin/Animatable}\n * @extends {module:zrender/mixin/Transformable}\n * @extends {module:zrender/mixin/Eventful}\n */\nvar Element = function (opts) { // jshint ignore:line\n\n    Transformable.call(this, opts);\n    Eventful.call(this, opts);\n    Animatable.call(this, opts);\n\n    /**\n     * 画布元素ID\n     * @type {string}\n     */\n    this.id = opts.id || guid();\n};\n\nElement.prototype = {\n\n    /**\n     * 元素类型\n     * Element type\n     * @type {string}\n     */\n    type: 'element',\n\n    /**\n     * 元素名字\n     * Element name\n     * @type {string}\n     */\n    name: '',\n\n    /**\n     * ZRender 实例对象，会在 element 添加到 zrender 实例中后自动赋值\n     * ZRender instance will be assigned when element is associated with zrender\n     * @name module:/zrender/Element#__zr\n     * @type {module:zrender/ZRender}\n     */\n    __zr: null,\n\n    /**\n     * 图形是否忽略，为true时忽略图形的绘制以及事件触发\n     * If ignore drawing and events of the element object\n     * @name module:/zrender/Element#ignore\n     * @type {boolean}\n     * @default false\n     */\n    ignore: false,\n\n    /**\n     * 用于裁剪的路径(shape)，所有 Group 内的路径在绘制时都会被这个路径裁剪\n     * 该路径会继承被裁减对象的变换\n     * @type {module:zrender/graphic/Path}\n     * @see http://www.w3.org/TR/2dcontext/#clipping-region\n     * @readOnly\n     */\n    clipPath: null,\n\n    /**\n     * 是否是 Group\n     * @type {boolean}\n     */\n    isGroup: false,\n\n    /**\n     * Drift element\n     * @param  {number} dx dx on the global space\n     * @param  {number} dy dy on the global space\n     */\n    drift: function (dx, dy) {\n        switch (this.draggable) {\n            case 'horizontal':\n                dy = 0;\n                break;\n            case 'vertical':\n                dx = 0;\n                break;\n        }\n\n        var m = this.transform;\n        if (!m) {\n            m = this.transform = [1, 0, 0, 1, 0, 0];\n        }\n        m[4] += dx;\n        m[5] += dy;\n\n        this.decomposeTransform();\n        this.dirty(false);\n    },\n\n    /**\n     * Hook before update\n     */\n    beforeUpdate: function () {},\n    /**\n     * Hook after update\n     */\n    afterUpdate: function () {},\n    /**\n     * Update each frame\n     */\n    update: function () {\n        this.updateTransform();\n    },\n\n    /**\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {},\n\n    /**\n     * @protected\n     */\n    attrKV: function (key, value) {\n        if (key === 'position' || key === 'scale' || key === 'origin') {\n            // Copy the array\n            if (value) {\n                var target = this[key];\n                if (!target) {\n                    target = this[key] = [];\n                }\n                target[0] = value[0];\n                target[1] = value[1];\n            }\n        }\n        else {\n            this[key] = value;\n        }\n    },\n\n    /**\n     * Hide the element\n     */\n    hide: function () {\n        this.ignore = true;\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * Show the element\n     */\n    show: function () {\n        this.ignore = false;\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * @param {string|Object} key\n     * @param {*} value\n     */\n    attr: function (key, value) {\n        if (typeof key === 'string') {\n            this.attrKV(key, value);\n        }\n        else if (isObject$1(key)) {\n            for (var name in key) {\n                if (key.hasOwnProperty(name)) {\n                    this.attrKV(name, key[name]);\n                }\n            }\n        }\n\n        this.dirty(false);\n\n        return this;\n    },\n\n    /**\n     * @param {module:zrender/graphic/Path} clipPath\n     */\n    setClipPath: function (clipPath) {\n        var zr = this.__zr;\n        if (zr) {\n            clipPath.addSelfToZr(zr);\n        }\n\n        // Remove previous clip path\n        if (this.clipPath && this.clipPath !== clipPath) {\n            this.removeClipPath();\n        }\n\n        this.clipPath = clipPath;\n        clipPath.__zr = zr;\n        clipPath.__clipTarget = this;\n\n        this.dirty(false);\n    },\n\n    /**\n     */\n    removeClipPath: function () {\n        var clipPath = this.clipPath;\n        if (clipPath) {\n            if (clipPath.__zr) {\n                clipPath.removeSelfFromZr(clipPath.__zr);\n            }\n\n            clipPath.__zr = null;\n            clipPath.__clipTarget = null;\n            this.clipPath = null;\n\n            this.dirty(false);\n        }\n    },\n\n    /**\n     * Add self from zrender instance.\n     * Not recursively because it will be invoked when element added to storage.\n     * @param {module:zrender/ZRender} zr\n     */\n    addSelfToZr: function (zr) {\n        this.__zr = zr;\n        // 添加动画\n        var animators = this.animators;\n        if (animators) {\n            for (var i = 0; i < animators.length; i++) {\n                zr.animation.addAnimator(animators[i]);\n            }\n        }\n\n        if (this.clipPath) {\n            this.clipPath.addSelfToZr(zr);\n        }\n    },\n\n    /**\n     * Remove self from zrender instance.\n     * Not recursively because it will be invoked when element added to storage.\n     * @param {module:zrender/ZRender} zr\n     */\n    removeSelfFromZr: function (zr) {\n        this.__zr = null;\n        // 移除动画\n        var animators = this.animators;\n        if (animators) {\n            for (var i = 0; i < animators.length; i++) {\n                zr.animation.removeAnimator(animators[i]);\n            }\n        }\n\n        if (this.clipPath) {\n            this.clipPath.removeSelfFromZr(zr);\n        }\n    }\n};\n\nmixin(Element, Animatable);\nmixin(Element, Transformable);\nmixin(Element, Eventful);\n\n/**\n * @module echarts/core/BoundingRect\n */\n\nvar v2ApplyTransform = applyTransform;\nvar mathMin = Math.min;\nvar mathMax = Math.max;\n\n/**\n * @alias module:echarts/core/BoundingRect\n */\nfunction BoundingRect(x, y, width, height) {\n\n    if (width < 0) {\n        x = x + width;\n        width = -width;\n    }\n    if (height < 0) {\n        y = y + height;\n        height = -height;\n    }\n\n    /**\n     * @type {number}\n     */\n    this.x = x;\n    /**\n     * @type {number}\n     */\n    this.y = y;\n    /**\n     * @type {number}\n     */\n    this.width = width;\n    /**\n     * @type {number}\n     */\n    this.height = height;\n}\n\nBoundingRect.prototype = {\n\n    constructor: BoundingRect,\n\n    /**\n     * @param {module:echarts/core/BoundingRect} other\n     */\n    union: function (other) {\n        var x = mathMin(other.x, this.x);\n        var y = mathMin(other.y, this.y);\n\n        this.width = mathMax(\n                other.x + other.width,\n                this.x + this.width\n            ) - x;\n        this.height = mathMax(\n                other.y + other.height,\n                this.y + this.height\n            ) - y;\n        this.x = x;\n        this.y = y;\n    },\n\n    /**\n     * @param {Array.<number>} m\n     * @methods\n     */\n    applyTransform: (function () {\n        var lt = [];\n        var rb = [];\n        var lb = [];\n        var rt = [];\n        return function (m) {\n            // In case usage like this\n            // el.getBoundingRect().applyTransform(el.transform)\n            // And element has no transform\n            if (!m) {\n                return;\n            }\n            lt[0] = lb[0] = this.x;\n            lt[1] = rt[1] = this.y;\n            rb[0] = rt[0] = this.x + this.width;\n            rb[1] = lb[1] = this.y + this.height;\n\n            v2ApplyTransform(lt, lt, m);\n            v2ApplyTransform(rb, rb, m);\n            v2ApplyTransform(lb, lb, m);\n            v2ApplyTransform(rt, rt, m);\n\n            this.x = mathMin(lt[0], rb[0], lb[0], rt[0]);\n            this.y = mathMin(lt[1], rb[1], lb[1], rt[1]);\n            var maxX = mathMax(lt[0], rb[0], lb[0], rt[0]);\n            var maxY = mathMax(lt[1], rb[1], lb[1], rt[1]);\n            this.width = maxX - this.x;\n            this.height = maxY - this.y;\n        };\n    })(),\n\n    /**\n     * Calculate matrix of transforming from self to target rect\n     * @param  {module:zrender/core/BoundingRect} b\n     * @return {Array.<number>}\n     */\n    calculateTransform: function (b) {\n        var a = this;\n        var sx = b.width / a.width;\n        var sy = b.height / a.height;\n\n        var m = create$1();\n\n        // 矩阵右乘\n        translate(m, m, [-a.x, -a.y]);\n        scale$1(m, m, [sx, sy]);\n        translate(m, m, [b.x, b.y]);\n\n        return m;\n    },\n\n    /**\n     * @param {(module:echarts/core/BoundingRect|Object)} b\n     * @return {boolean}\n     */\n    intersect: function (b) {\n        if (!b) {\n            return false;\n        }\n\n        if (!(b instanceof BoundingRect)) {\n            // Normalize negative width/height.\n            b = BoundingRect.create(b);\n        }\n\n        var a = this;\n        var ax0 = a.x;\n        var ax1 = a.x + a.width;\n        var ay0 = a.y;\n        var ay1 = a.y + a.height;\n\n        var bx0 = b.x;\n        var bx1 = b.x + b.width;\n        var by0 = b.y;\n        var by1 = b.y + b.height;\n\n        return !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);\n    },\n\n    contain: function (x, y) {\n        var rect = this;\n        return x >= rect.x\n            && x <= (rect.x + rect.width)\n            && y >= rect.y\n            && y <= (rect.y + rect.height);\n    },\n\n    /**\n     * @return {module:echarts/core/BoundingRect}\n     */\n    clone: function () {\n        return new BoundingRect(this.x, this.y, this.width, this.height);\n    },\n\n    /**\n     * Copy from another rect\n     */\n    copy: function (other) {\n        this.x = other.x;\n        this.y = other.y;\n        this.width = other.width;\n        this.height = other.height;\n    },\n\n    plain: function () {\n        return {\n            x: this.x,\n            y: this.y,\n            width: this.width,\n            height: this.height\n        };\n    }\n};\n\n/**\n * @param {Object|module:zrender/core/BoundingRect} rect\n * @param {number} rect.x\n * @param {number} rect.y\n * @param {number} rect.width\n * @param {number} rect.height\n * @return {module:zrender/core/BoundingRect}\n */\nBoundingRect.create = function (rect) {\n    return new BoundingRect(rect.x, rect.y, rect.width, rect.height);\n};\n\n/**\n * Group是一个容器，可以插入子节点，Group的变换也会被应用到子节点上\n * @module zrender/graphic/Group\n * @example\n *     var Group = require('zrender/container/Group');\n *     var Circle = require('zrender/graphic/shape/Circle');\n *     var g = new Group();\n *     g.position[0] = 100;\n *     g.position[1] = 100;\n *     g.add(new Circle({\n *         style: {\n *             x: 100,\n *             y: 100,\n *             r: 20,\n *         }\n *     }));\n *     zr.add(g);\n */\n\n/**\n * @alias module:zrender/graphic/Group\n * @constructor\n * @extends module:zrender/mixin/Transformable\n * @extends module:zrender/mixin/Eventful\n */\nvar Group = function (opts) {\n\n    opts = opts || {};\n\n    Element.call(this, opts);\n\n    for (var key in opts) {\n        if (opts.hasOwnProperty(key)) {\n            this[key] = opts[key];\n        }\n    }\n\n    this._children = [];\n\n    this.__storage = null;\n\n    this.__dirty = true;\n};\n\nGroup.prototype = {\n\n    constructor: Group,\n\n    isGroup: true,\n\n    /**\n     * @type {string}\n     */\n    type: 'group',\n\n    /**\n     * 所有子孙元素是否响应鼠标事件\n     * @name module:/zrender/container/Group#silent\n     * @type {boolean}\n     * @default false\n     */\n    silent: false,\n\n    /**\n     * @return {Array.<module:zrender/Element>}\n     */\n    children: function () {\n        return this._children.slice();\n    },\n\n    /**\n     * 获取指定 index 的儿子节点\n     * @param  {number} idx\n     * @return {module:zrender/Element}\n     */\n    childAt: function (idx) {\n        return this._children[idx];\n    },\n\n    /**\n     * 获取指定名字的儿子节点\n     * @param  {string} name\n     * @return {module:zrender/Element}\n     */\n    childOfName: function (name) {\n        var children = this._children;\n        for (var i = 0; i < children.length; i++) {\n            if (children[i].name === name) {\n                return children[i];\n            }\n            }\n    },\n\n    /**\n     * @return {number}\n     */\n    childCount: function () {\n        return this._children.length;\n    },\n\n    /**\n     * 添加子节点到最后\n     * @param {module:zrender/Element} child\n     */\n    add: function (child) {\n        if (child && child !== this && child.parent !== this) {\n\n            this._children.push(child);\n\n            this._doAdd(child);\n        }\n\n        return this;\n    },\n\n    /**\n     * 添加子节点在 nextSibling 之前\n     * @param {module:zrender/Element} child\n     * @param {module:zrender/Element} nextSibling\n     */\n    addBefore: function (child, nextSibling) {\n        if (child && child !== this && child.parent !== this\n            && nextSibling && nextSibling.parent === this) {\n\n            var children = this._children;\n            var idx = children.indexOf(nextSibling);\n\n            if (idx >= 0) {\n                children.splice(idx, 0, child);\n                this._doAdd(child);\n            }\n        }\n\n        return this;\n    },\n\n    _doAdd: function (child) {\n        if (child.parent) {\n            child.parent.remove(child);\n        }\n\n        child.parent = this;\n\n        var storage = this.__storage;\n        var zr = this.__zr;\n        if (storage && storage !== child.__storage) {\n\n            storage.addToStorage(child);\n\n            if (child instanceof Group) {\n                child.addChildrenToStorage(storage);\n            }\n        }\n\n        zr && zr.refresh();\n    },\n\n    /**\n     * 移除子节点\n     * @param {module:zrender/Element} child\n     */\n    remove: function (child) {\n        var zr = this.__zr;\n        var storage = this.__storage;\n        var children = this._children;\n\n        var idx = indexOf(children, child);\n        if (idx < 0) {\n            return this;\n        }\n        children.splice(idx, 1);\n\n        child.parent = null;\n\n        if (storage) {\n\n            storage.delFromStorage(child);\n\n            if (child instanceof Group) {\n                child.delChildrenFromStorage(storage);\n            }\n        }\n\n        zr && zr.refresh();\n\n        return this;\n    },\n\n    /**\n     * 移除所有子节点\n     */\n    removeAll: function () {\n        var children = this._children;\n        var storage = this.__storage;\n        var child;\n        var i;\n        for (i = 0; i < children.length; i++) {\n            child = children[i];\n            if (storage) {\n                storage.delFromStorage(child);\n                if (child instanceof Group) {\n                    child.delChildrenFromStorage(storage);\n                }\n            }\n            child.parent = null;\n        }\n        children.length = 0;\n\n        return this;\n    },\n\n    /**\n     * 遍历所有子节点\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    eachChild: function (cb, context) {\n        var children = this._children;\n        for (var i = 0; i < children.length; i++) {\n            var child = children[i];\n            cb.call(context, child, i);\n        }\n        return this;\n    },\n\n    /**\n     * 深度优先遍历所有子孙节点\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            cb.call(context, child);\n\n            if (child.type === 'group') {\n                child.traverse(cb, context);\n            }\n        }\n        return this;\n    },\n\n    addChildrenToStorage: function (storage) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            storage.addToStorage(child);\n            if (child instanceof Group) {\n                child.addChildrenToStorage(storage);\n            }\n        }\n    },\n\n    delChildrenFromStorage: function (storage) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            storage.delFromStorage(child);\n            if (child instanceof Group) {\n                child.delChildrenFromStorage(storage);\n            }\n        }\n    },\n\n    dirty: function () {\n        this.__dirty = true;\n        this.__zr && this.__zr.refresh();\n        return this;\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function (includeChildren) {\n        // TODO Caching\n        var rect = null;\n        var tmpRect = new BoundingRect(0, 0, 0, 0);\n        var children = includeChildren || this._children;\n        var tmpMat = [];\n\n        for (var i = 0; i < children.length; i++) {\n            var child = children[i];\n            if (child.ignore || child.invisible) {\n                continue;\n            }\n\n            var childRect = child.getBoundingRect();\n            var transform = child.getLocalTransform(tmpMat);\n            // TODO\n            // The boundingRect cacluated by transforming original\n            // rect may be bigger than the actual bundingRect when rotation\n            // is used. (Consider a circle rotated aginst its center, where\n            // the actual boundingRect should be the same as that not be\n            // rotated.) But we can not find better approach to calculate\n            // actual boundingRect yet, considering performance.\n            if (transform) {\n                tmpRect.copy(childRect);\n                tmpRect.applyTransform(transform);\n                rect = rect || tmpRect.clone();\n                rect.union(tmpRect);\n            }\n            else {\n                rect = rect || childRect.clone();\n                rect.union(childRect);\n            }\n        }\n        return rect || tmpRect;\n    }\n};\n\ninherits(Group, Element);\n\n// https://github.com/mziccard/node-timsort\nvar DEFAULT_MIN_MERGE = 32;\n\nvar DEFAULT_MIN_GALLOPING = 7;\n\nfunction minRunLength(n) {\n    var r = 0;\n\n    while (n >= DEFAULT_MIN_MERGE) {\n        r |= n & 1;\n        n >>= 1;\n    }\n\n    return n + r;\n}\n\nfunction makeAscendingRun(array, lo, hi, compare) {\n    var runHi = lo + 1;\n\n    if (runHi === hi) {\n        return 1;\n    }\n\n    if (compare(array[runHi++], array[lo]) < 0) {\n        while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {\n            runHi++;\n        }\n\n        reverseRun(array, lo, runHi);\n    }\n    else {\n        while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {\n            runHi++;\n        }\n    }\n\n    return runHi - lo;\n}\n\nfunction reverseRun(array, lo, hi) {\n    hi--;\n\n    while (lo < hi) {\n        var t = array[lo];\n        array[lo++] = array[hi];\n        array[hi--] = t;\n    }\n}\n\nfunction binaryInsertionSort(array, lo, hi, start, compare) {\n    if (start === lo) {\n        start++;\n    }\n\n    for (; start < hi; start++) {\n        var pivot = array[start];\n\n        var left = lo;\n        var right = start;\n        var mid;\n\n        while (left < right) {\n            mid = left + right >>> 1;\n\n            if (compare(pivot, array[mid]) < 0) {\n                right = mid;\n            }\n            else {\n                left = mid + 1;\n            }\n        }\n\n        var n = start - left;\n\n        switch (n) {\n            case 3:\n                array[left + 3] = array[left + 2];\n\n            case 2:\n                array[left + 2] = array[left + 1];\n\n            case 1:\n                array[left + 1] = array[left];\n                break;\n            default:\n                while (n > 0) {\n                    array[left + n] = array[left + n - 1];\n                    n--;\n                }\n        }\n\n        array[left] = pivot;\n    }\n}\n\nfunction gallopLeft(value, array, start, length, hint, compare) {\n    var lastOffset = 0;\n    var maxOffset = 0;\n    var offset = 1;\n\n    if (compare(value, array[start + hint]) > 0) {\n        maxOffset = length - hint;\n\n        while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        lastOffset += hint;\n        offset += hint;\n    }\n    else {\n        maxOffset = hint + 1;\n        while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        var tmp = lastOffset;\n        lastOffset = hint - offset;\n        offset = hint - tmp;\n    }\n\n    lastOffset++;\n    while (lastOffset < offset) {\n        var m = lastOffset + (offset - lastOffset >>> 1);\n\n        if (compare(value, array[start + m]) > 0) {\n            lastOffset = m + 1;\n        }\n        else {\n            offset = m;\n        }\n    }\n    return offset;\n}\n\nfunction gallopRight(value, array, start, length, hint, compare) {\n    var lastOffset = 0;\n    var maxOffset = 0;\n    var offset = 1;\n\n    if (compare(value, array[start + hint]) < 0) {\n        maxOffset = hint + 1;\n\n        while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        var tmp = lastOffset;\n        lastOffset = hint - offset;\n        offset = hint - tmp;\n    }\n    else {\n        maxOffset = length - hint;\n\n        while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        lastOffset += hint;\n        offset += hint;\n    }\n\n    lastOffset++;\n\n    while (lastOffset < offset) {\n        var m = lastOffset + (offset - lastOffset >>> 1);\n\n        if (compare(value, array[start + m]) < 0) {\n            offset = m;\n        }\n        else {\n            lastOffset = m + 1;\n        }\n    }\n\n    return offset;\n}\n\nfunction TimSort(array, compare) {\n    var minGallop = DEFAULT_MIN_GALLOPING;\n    var runStart;\n    var runLength;\n    var stackSize = 0;\n\n    var tmp = [];\n\n    runStart = [];\n    runLength = [];\n\n    function pushRun(_runStart, _runLength) {\n        runStart[stackSize] = _runStart;\n        runLength[stackSize] = _runLength;\n        stackSize += 1;\n    }\n\n    function mergeRuns() {\n        while (stackSize > 1) {\n            var n = stackSize - 2;\n\n            if (n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1] || n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1]) {\n                if (runLength[n - 1] < runLength[n + 1]) {\n                    n--;\n                }\n            }\n            else if (runLength[n] > runLength[n + 1]) {\n                break;\n            }\n            mergeAt(n);\n        }\n    }\n\n    function forceMergeRuns() {\n        while (stackSize > 1) {\n            var n = stackSize - 2;\n\n            if (n > 0 && runLength[n - 1] < runLength[n + 1]) {\n                n--;\n            }\n\n            mergeAt(n);\n        }\n    }\n\n    function mergeAt(i) {\n        var start1 = runStart[i];\n        var length1 = runLength[i];\n        var start2 = runStart[i + 1];\n        var length2 = runLength[i + 1];\n\n        runLength[i] = length1 + length2;\n\n        if (i === stackSize - 3) {\n            runStart[i + 1] = runStart[i + 2];\n            runLength[i + 1] = runLength[i + 2];\n        }\n\n        stackSize--;\n\n        var k = gallopRight(array[start2], array, start1, length1, 0, compare);\n        start1 += k;\n        length1 -= k;\n\n        if (length1 === 0) {\n            return;\n        }\n\n        length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);\n\n        if (length2 === 0) {\n            return;\n        }\n\n        if (length1 <= length2) {\n            mergeLow(start1, length1, start2, length2);\n        }\n        else {\n            mergeHigh(start1, length1, start2, length2);\n        }\n    }\n\n    function mergeLow(start1, length1, start2, length2) {\n        var i = 0;\n\n        for (i = 0; i < length1; i++) {\n            tmp[i] = array[start1 + i];\n        }\n\n        var cursor1 = 0;\n        var cursor2 = start2;\n        var dest = start1;\n\n        array[dest++] = array[cursor2++];\n\n        if (--length2 === 0) {\n            for (i = 0; i < length1; i++) {\n                array[dest + i] = tmp[cursor1 + i];\n            }\n            return;\n        }\n\n        if (length1 === 1) {\n            for (i = 0; i < length2; i++) {\n                array[dest + i] = array[cursor2 + i];\n            }\n            array[dest + length2] = tmp[cursor1];\n            return;\n        }\n\n        var _minGallop = minGallop;\n        var count1, count2, exit;\n\n        while (1) {\n            count1 = 0;\n            count2 = 0;\n            exit = false;\n\n            do {\n                if (compare(array[cursor2], tmp[cursor1]) < 0) {\n                    array[dest++] = array[cursor2++];\n                    count2++;\n                    count1 = 0;\n\n                    if (--length2 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                else {\n                    array[dest++] = tmp[cursor1++];\n                    count1++;\n                    count2 = 0;\n                    if (--length1 === 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n            } while ((count1 | count2) < _minGallop);\n\n            if (exit) {\n                break;\n            }\n\n            do {\n                count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);\n\n                if (count1 !== 0) {\n                    for (i = 0; i < count1; i++) {\n                        array[dest + i] = tmp[cursor1 + i];\n                    }\n\n                    dest += count1;\n                    cursor1 += count1;\n                    length1 -= count1;\n                    if (length1 <= 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest++] = array[cursor2++];\n\n                if (--length2 === 0) {\n                    exit = true;\n                    break;\n                }\n\n                count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);\n\n                if (count2 !== 0) {\n                    for (i = 0; i < count2; i++) {\n                        array[dest + i] = array[cursor2 + i];\n                    }\n\n                    dest += count2;\n                    cursor2 += count2;\n                    length2 -= count2;\n\n                    if (length2 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                array[dest++] = tmp[cursor1++];\n\n                if (--length1 === 1) {\n                    exit = true;\n                    break;\n                }\n\n                _minGallop--;\n            } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);\n\n            if (exit) {\n                break;\n            }\n\n            if (_minGallop < 0) {\n                _minGallop = 0;\n            }\n\n            _minGallop += 2;\n        }\n\n        minGallop = _minGallop;\n\n        minGallop < 1 && (minGallop = 1);\n\n        if (length1 === 1) {\n            for (i = 0; i < length2; i++) {\n                array[dest + i] = array[cursor2 + i];\n            }\n            array[dest + length2] = tmp[cursor1];\n        }\n        else if (length1 === 0) {\n            throw new Error();\n            // throw new Error('mergeLow preconditions were not respected');\n        }\n        else {\n            for (i = 0; i < length1; i++) {\n                array[dest + i] = tmp[cursor1 + i];\n            }\n        }\n    }\n\n    function mergeHigh(start1, length1, start2, length2) {\n        var i = 0;\n\n        for (i = 0; i < length2; i++) {\n            tmp[i] = array[start2 + i];\n        }\n\n        var cursor1 = start1 + length1 - 1;\n        var cursor2 = length2 - 1;\n        var dest = start2 + length2 - 1;\n        var customCursor = 0;\n        var customDest = 0;\n\n        array[dest--] = array[cursor1--];\n\n        if (--length1 === 0) {\n            customCursor = dest - (length2 - 1);\n\n            for (i = 0; i < length2; i++) {\n                array[customCursor + i] = tmp[i];\n            }\n\n            return;\n        }\n\n        if (length2 === 1) {\n            dest -= length1;\n            cursor1 -= length1;\n            customDest = dest + 1;\n            customCursor = cursor1 + 1;\n\n            for (i = length1 - 1; i >= 0; i--) {\n                array[customDest + i] = array[customCursor + i];\n            }\n\n            array[dest] = tmp[cursor2];\n            return;\n        }\n\n        var _minGallop = minGallop;\n\n        while (true) {\n            var count1 = 0;\n            var count2 = 0;\n            var exit = false;\n\n            do {\n                if (compare(tmp[cursor2], array[cursor1]) < 0) {\n                    array[dest--] = array[cursor1--];\n                    count1++;\n                    count2 = 0;\n                    if (--length1 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                else {\n                    array[dest--] = tmp[cursor2--];\n                    count2++;\n                    count1 = 0;\n                    if (--length2 === 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n            } while ((count1 | count2) < _minGallop);\n\n            if (exit) {\n                break;\n            }\n\n            do {\n                count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);\n\n                if (count1 !== 0) {\n                    dest -= count1;\n                    cursor1 -= count1;\n                    length1 -= count1;\n                    customDest = dest + 1;\n                    customCursor = cursor1 + 1;\n\n                    for (i = count1 - 1; i >= 0; i--) {\n                        array[customDest + i] = array[customCursor + i];\n                    }\n\n                    if (length1 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest--] = tmp[cursor2--];\n\n                if (--length2 === 1) {\n                    exit = true;\n                    break;\n                }\n\n                count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);\n\n                if (count2 !== 0) {\n                    dest -= count2;\n                    cursor2 -= count2;\n                    length2 -= count2;\n                    customDest = dest + 1;\n                    customCursor = cursor2 + 1;\n\n                    for (i = 0; i < count2; i++) {\n                        array[customDest + i] = tmp[customCursor + i];\n                    }\n\n                    if (length2 <= 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest--] = array[cursor1--];\n\n                if (--length1 === 0) {\n                    exit = true;\n                    break;\n                }\n\n                _minGallop--;\n            } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);\n\n            if (exit) {\n                break;\n            }\n\n            if (_minGallop < 0) {\n                _minGallop = 0;\n            }\n\n            _minGallop += 2;\n        }\n\n        minGallop = _minGallop;\n\n        if (minGallop < 1) {\n            minGallop = 1;\n        }\n\n        if (length2 === 1) {\n            dest -= length1;\n            cursor1 -= length1;\n            customDest = dest + 1;\n            customCursor = cursor1 + 1;\n\n            for (i = length1 - 1; i >= 0; i--) {\n                array[customDest + i] = array[customCursor + i];\n            }\n\n            array[dest] = tmp[cursor2];\n        }\n        else if (length2 === 0) {\n            throw new Error();\n            // throw new Error('mergeHigh preconditions were not respected');\n        }\n        else {\n            customCursor = dest - (length2 - 1);\n            for (i = 0; i < length2; i++) {\n                array[customCursor + i] = tmp[i];\n            }\n        }\n    }\n\n    this.mergeRuns = mergeRuns;\n    this.forceMergeRuns = forceMergeRuns;\n    this.pushRun = pushRun;\n}\n\nfunction sort(array, compare, lo, hi) {\n    if (!lo) {\n        lo = 0;\n    }\n    if (!hi) {\n        hi = array.length;\n    }\n\n    var remaining = hi - lo;\n\n    if (remaining < 2) {\n        return;\n    }\n\n    var runLength = 0;\n\n    if (remaining < DEFAULT_MIN_MERGE) {\n        runLength = makeAscendingRun(array, lo, hi, compare);\n        binaryInsertionSort(array, lo, hi, lo + runLength, compare);\n        return;\n    }\n\n    var ts = new TimSort(array, compare);\n\n    var minRun = minRunLength(remaining);\n\n    do {\n        runLength = makeAscendingRun(array, lo, hi, compare);\n        if (runLength < minRun) {\n            var force = remaining;\n            if (force > minRun) {\n                force = minRun;\n            }\n\n            binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);\n            runLength = force;\n        }\n\n        ts.pushRun(lo, runLength);\n        ts.mergeRuns();\n\n        remaining -= runLength;\n        lo += runLength;\n    } while (remaining !== 0);\n\n    ts.forceMergeRuns();\n}\n\n// Use timsort because in most case elements are partially sorted\n// https://jsfiddle.net/pissang/jr4x7mdm/8/\nfunction shapeCompareFunc(a, b) {\n    if (a.zlevel === b.zlevel) {\n        if (a.z === b.z) {\n            // if (a.z2 === b.z2) {\n            //     // FIXME Slow has renderidx compare\n            //     // http://stackoverflow.com/questions/20883421/sorting-in-javascript-should-every-compare-function-have-a-return-0-statement\n            //     // https://github.com/v8/v8/blob/47cce544a31ed5577ffe2963f67acb4144ee0232/src/js/array.js#L1012\n            //     return a.__renderidx - b.__renderidx;\n            // }\n            return a.z2 - b.z2;\n        }\n        return a.z - b.z;\n    }\n    return a.zlevel - b.zlevel;\n}\n/**\n * 内容仓库 (M)\n * @alias module:zrender/Storage\n * @constructor\n */\nvar Storage = function () { // jshint ignore:line\n    this._roots = [];\n\n    this._displayList = [];\n\n    this._displayListLen = 0;\n};\n\nStorage.prototype = {\n\n    constructor: Storage,\n\n    /**\n     * @param  {Function} cb\n     *\n     */\n    traverse: function (cb, context) {\n        for (var i = 0; i < this._roots.length; i++) {\n            this._roots[i].traverse(cb, context);\n        }\n    },\n\n    /**\n     * 返回所有图形的绘制队列\n     * @param {boolean} [update=false] 是否在返回前更新该数组\n     * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组, 在 update 为 true 的时候有效\n     *\n     * 详见{@link module:zrender/graphic/Displayable.prototype.updateDisplayList}\n     * @return {Array.<module:zrender/graphic/Displayable>}\n     */\n    getDisplayList: function (update, includeIgnore) {\n        includeIgnore = includeIgnore || false;\n        if (update) {\n            this.updateDisplayList(includeIgnore);\n        }\n        return this._displayList;\n    },\n\n    /**\n     * 更新图形的绘制队列。\n     * 每次绘制前都会调用，该方法会先深度优先遍历整个树，更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中，\n     * 最后根据绘制的优先级（zlevel > z > 插入顺序）排序得到绘制队列\n     * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组\n     */\n    updateDisplayList: function (includeIgnore) {\n        this._displayListLen = 0;\n\n        var roots = this._roots;\n        var displayList = this._displayList;\n        for (var i = 0, len = roots.length; i < len; i++) {\n            this._updateAndAddDisplayable(roots[i], null, includeIgnore);\n        }\n\n        displayList.length = this._displayListLen;\n\n        env$1.canvasSupported && sort(displayList, shapeCompareFunc);\n    },\n\n    _updateAndAddDisplayable: function (el, clipPaths, includeIgnore) {\n\n        if (el.ignore && !includeIgnore) {\n            return;\n        }\n\n        el.beforeUpdate();\n\n        if (el.__dirty) {\n\n            el.update();\n\n        }\n\n        el.afterUpdate();\n\n        var userSetClipPath = el.clipPath;\n        if (userSetClipPath) {\n\n            // FIXME 效率影响\n            if (clipPaths) {\n                clipPaths = clipPaths.slice();\n            }\n            else {\n                clipPaths = [];\n            }\n\n            var currentClipPath = userSetClipPath;\n            var parentClipPath = el;\n            // Recursively add clip path\n            while (currentClipPath) {\n                // clipPath 的变换是基于使用这个 clipPath 的元素\n                currentClipPath.parent = parentClipPath;\n                currentClipPath.updateTransform();\n\n                clipPaths.push(currentClipPath);\n\n                parentClipPath = currentClipPath;\n                currentClipPath = currentClipPath.clipPath;\n            }\n        }\n\n        if (el.isGroup) {\n            var children = el._children;\n\n            for (var i = 0; i < children.length; i++) {\n                var child = children[i];\n\n                // Force to mark as dirty if group is dirty\n                // FIXME __dirtyPath ?\n                if (el.__dirty) {\n                    child.__dirty = true;\n                }\n\n                this._updateAndAddDisplayable(child, clipPaths, includeIgnore);\n            }\n\n            // Mark group clean here\n            el.__dirty = false;\n\n        }\n        else {\n            el.__clipPaths = clipPaths;\n\n            this._displayList[this._displayListLen++] = el;\n        }\n    },\n\n    /**\n     * 添加图形(Shape)或者组(Group)到根节点\n     * @param {module:zrender/Element} el\n     */\n    addRoot: function (el) {\n        if (el.__storage === this) {\n            return;\n        }\n\n        if (el instanceof Group) {\n            el.addChildrenToStorage(this);\n        }\n\n        this.addToStorage(el);\n        this._roots.push(el);\n    },\n\n    /**\n     * 删除指定的图形(Shape)或者组(Group)\n     * @param {string|Array.<string>} [el] 如果为空清空整个Storage\n     */\n    delRoot: function (el) {\n        if (el == null) {\n            // 不指定el清空\n            for (var i = 0; i < this._roots.length; i++) {\n                var root = this._roots[i];\n                if (root instanceof Group) {\n                    root.delChildrenFromStorage(this);\n                }\n            }\n\n            this._roots = [];\n            this._displayList = [];\n            this._displayListLen = 0;\n\n            return;\n        }\n\n        if (el instanceof Array) {\n            for (var i = 0, l = el.length; i < l; i++) {\n                this.delRoot(el[i]);\n            }\n            return;\n        }\n\n\n        var idx = indexOf(this._roots, el);\n        if (idx >= 0) {\n            this.delFromStorage(el);\n            this._roots.splice(idx, 1);\n            if (el instanceof Group) {\n                el.delChildrenFromStorage(this);\n            }\n        }\n    },\n\n    addToStorage: function (el) {\n        if (el) {\n            el.__storage = this;\n            el.dirty(false);\n        }\n        return this;\n    },\n\n    delFromStorage: function (el) {\n        if (el) {\n            el.__storage = null;\n        }\n\n        return this;\n    },\n\n    /**\n     * 清空并且释放Storage\n     */\n    dispose: function () {\n        this._renderList =\n        this._roots = null;\n    },\n\n    displayableSortFunc: shapeCompareFunc\n};\n\nvar SHADOW_PROPS = {\n    'shadowBlur': 1,\n    'shadowOffsetX': 1,\n    'shadowOffsetY': 1,\n    'textShadowBlur': 1,\n    'textShadowOffsetX': 1,\n    'textShadowOffsetY': 1,\n    'textBoxShadowBlur': 1,\n    'textBoxShadowOffsetX': 1,\n    'textBoxShadowOffsetY': 1\n};\n\nvar fixShadow = function (ctx, propName, value) {\n    if (SHADOW_PROPS.hasOwnProperty(propName)) {\n        return value *= ctx.dpr;\n    }\n    return value;\n};\n\nvar ContextCachedBy = {\n    NONE: 0,\n    STYLE_BIND: 1,\n    PLAIN_TEXT: 2\n};\n\n// Avoid confused with 0/false.\nvar WILL_BE_RESTORED = 9;\n\nvar STYLE_COMMON_PROPS = [\n    ['shadowBlur', 0], ['shadowOffsetX', 0], ['shadowOffsetY', 0], ['shadowColor', '#000'],\n    ['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]\n];\n\n// var SHADOW_PROPS = STYLE_COMMON_PROPS.slice(0, 4);\n// var LINE_PROPS = STYLE_COMMON_PROPS.slice(4);\n\nvar Style = function (opts) {\n    this.extendFrom(opts, false);\n};\n\nfunction createLinearGradient(ctx, obj, rect) {\n    var x = obj.x == null ? 0 : obj.x;\n    var x2 = obj.x2 == null ? 1 : obj.x2;\n    var y = obj.y == null ? 0 : obj.y;\n    var y2 = obj.y2 == null ? 0 : obj.y2;\n\n    if (!obj.global) {\n        x = x * rect.width + rect.x;\n        x2 = x2 * rect.width + rect.x;\n        y = y * rect.height + rect.y;\n        y2 = y2 * rect.height + rect.y;\n    }\n\n    // Fix NaN when rect is Infinity\n    x = isNaN(x) ? 0 : x;\n    x2 = isNaN(x2) ? 1 : x2;\n    y = isNaN(y) ? 0 : y;\n    y2 = isNaN(y2) ? 0 : y2;\n\n    var canvasGradient = ctx.createLinearGradient(x, y, x2, y2);\n\n    return canvasGradient;\n}\n\nfunction createRadialGradient(ctx, obj, rect) {\n    var width = rect.width;\n    var height = rect.height;\n    var min = Math.min(width, height);\n\n    var x = obj.x == null ? 0.5 : obj.x;\n    var y = obj.y == null ? 0.5 : obj.y;\n    var r = obj.r == null ? 0.5 : obj.r;\n    if (!obj.global) {\n        x = x * width + rect.x;\n        y = y * height + rect.y;\n        r = r * min;\n    }\n\n    var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r);\n\n    return canvasGradient;\n}\n\n\nStyle.prototype = {\n\n    constructor: Style,\n\n    /**\n     * @type {string}\n     */\n    fill: '#000',\n\n    /**\n     * @type {string}\n     */\n    stroke: null,\n\n    /**\n     * @type {number}\n     */\n    opacity: 1,\n\n    /**\n     * @type {number}\n     */\n    fillOpacity: null,\n\n    /**\n     * @type {number}\n     */\n    strokeOpacity: null,\n\n    /**\n     * @type {Array.<number>}\n     */\n    lineDash: null,\n\n    /**\n     * @type {number}\n     */\n    lineDashOffset: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowOffsetY: 0,\n\n    /**\n     * @type {number}\n     */\n    lineWidth: 1,\n\n    /**\n     * If stroke ignore scale\n     * @type {Boolean}\n     */\n    strokeNoScale: false,\n\n    // Bounding rect text configuration\n    // Not affected by element transform\n    /**\n     * @type {string}\n     */\n    text: null,\n\n    /**\n     * If `fontSize` or `fontFamily` exists, `font` will be reset by\n     * `fontSize`, `fontStyle`, `fontWeight`, `fontFamily`.\n     * So do not visit it directly in upper application (like echarts),\n     * but use `contain/text#makeFont` instead.\n     * @type {string}\n     */\n    font: null,\n\n    /**\n     * The same as font. Use font please.\n     * @deprecated\n     * @type {string}\n     */\n    textFont: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontStyle: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontWeight: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * Should be 12 but not '12px'.\n     * @type {number}\n     */\n    fontSize: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontFamily: null,\n\n    /**\n     * Reserved for special functinality, like 'hr'.\n     * @type {string}\n     */\n    textTag: null,\n\n    /**\n     * @type {string}\n     */\n    textFill: '#000',\n\n    /**\n     * @type {string}\n     */\n    textStroke: null,\n\n    /**\n     * @type {number}\n     */\n    textWidth: null,\n\n    /**\n     * Only for textBackground.\n     * @type {number}\n     */\n    textHeight: null,\n\n    /**\n     * textStroke may be set as some color as a default\n     * value in upper applicaion, where the default value\n     * of textStrokeWidth should be 0 to make sure that\n     * user can choose to do not use text stroke.\n     * @type {number}\n     */\n    textStrokeWidth: 0,\n\n    /**\n     * @type {number}\n     */\n    textLineHeight: null,\n\n    /**\n     * 'inside', 'left', 'right', 'top', 'bottom'\n     * [x, y]\n     * Based on x, y of rect.\n     * @type {string|Array.<number>}\n     * @default 'inside'\n     */\n    textPosition: 'inside',\n\n    /**\n     * If not specified, use the boundingRect of a `displayable`.\n     * @type {Object}\n     */\n    textRect: null,\n\n    /**\n     * [x, y]\n     * @type {Array.<number>}\n     */\n    textOffset: null,\n\n    /**\n     * @type {string}\n     */\n    textAlign: null,\n\n    /**\n     * @type {string}\n     */\n    textVerticalAlign: null,\n\n    /**\n     * @type {number}\n     */\n    textDistance: 5,\n\n    /**\n     * @type {string}\n     */\n    textShadowColor: 'transparent',\n\n    /**\n     * @type {number}\n     */\n    textShadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    textShadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    textShadowOffsetY: 0,\n\n    /**\n     * @type {string}\n     */\n    textBoxShadowColor: 'transparent',\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowOffsetY: 0,\n\n    /**\n     * Whether transform text.\n     * Only useful in Path and Image element\n     * @type {boolean}\n     */\n    transformText: false,\n\n    /**\n     * Text rotate around position of Path or Image\n     * Only useful in Path and Image element and transformText is false.\n     */\n    textRotation: 0,\n\n    /**\n     * Text origin of text rotation, like [10, 40].\n     * Based on x, y of rect.\n     * Useful in label rotation of circular symbol.\n     * By default, this origin is textPosition.\n     * Can be 'center'.\n     * @type {string|Array.<number>}\n     */\n    textOrigin: null,\n\n    /**\n     * @type {string}\n     */\n    textBackgroundColor: null,\n\n    /**\n     * @type {string}\n     */\n    textBorderColor: null,\n\n    /**\n     * @type {number}\n     */\n    textBorderWidth: 0,\n\n    /**\n     * @type {number}\n     */\n    textBorderRadius: 0,\n\n    /**\n     * Can be `2` or `[2, 4]` or `[2, 3, 4, 5]`\n     * @type {number|Array.<number>}\n     */\n    textPadding: null,\n\n    /**\n     * Text styles for rich text.\n     * @type {Object}\n     */\n    rich: null,\n\n    /**\n     * {outerWidth, outerHeight, ellipsis, placeholder}\n     * @type {Object}\n     */\n    truncate: null,\n\n    /**\n     * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation\n     * @type {string}\n     */\n    blend: null,\n\n    /**\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    bind: function (ctx, el, prevEl) {\n        var style = this;\n        var prevStyle = prevEl && prevEl.style;\n        // If no prevStyle, it means first draw.\n        // Only apply cache if the last time cachced by this function.\n        var notCheckCache = !prevStyle || ctx.__attrCachedBy !== ContextCachedBy.STYLE_BIND;\n\n        ctx.__attrCachedBy = ContextCachedBy.STYLE_BIND;\n\n        for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {\n            var prop = STYLE_COMMON_PROPS[i];\n            var styleName = prop[0];\n\n            if (notCheckCache || style[styleName] !== prevStyle[styleName]) {\n                // FIXME Invalid property value will cause style leak from previous element.\n                ctx[styleName] =\n                    fixShadow(ctx, styleName, style[styleName] || prop[1]);\n            }\n        }\n\n        if ((notCheckCache || style.fill !== prevStyle.fill)) {\n            ctx.fillStyle = style.fill;\n        }\n        if ((notCheckCache || style.stroke !== prevStyle.stroke)) {\n            ctx.strokeStyle = style.stroke;\n        }\n        if ((notCheckCache || style.opacity !== prevStyle.opacity)) {\n            ctx.globalAlpha = style.opacity == null ? 1 : style.opacity;\n        }\n\n        if ((notCheckCache || style.blend !== prevStyle.blend)) {\n            ctx.globalCompositeOperation = style.blend || 'source-over';\n        }\n        if (this.hasStroke()) {\n            var lineWidth = style.lineWidth;\n            ctx.lineWidth = lineWidth / (\n                (this.strokeNoScale && el && el.getLineScale) ? el.getLineScale() : 1\n            );\n        }\n    },\n\n    hasFill: function () {\n        var fill = this.fill;\n        return fill != null && fill !== 'none';\n    },\n\n    hasStroke: function () {\n        var stroke = this.stroke;\n        return stroke != null && stroke !== 'none' && this.lineWidth > 0;\n    },\n\n    /**\n     * Extend from other style\n     * @param {zrender/graphic/Style} otherStyle\n     * @param {boolean} overwrite true: overwrirte any way.\n     *                            false: overwrite only when !target.hasOwnProperty\n     *                            others: overwrite when property is not null/undefined.\n     */\n    extendFrom: function (otherStyle, overwrite) {\n        if (otherStyle) {\n            for (var name in otherStyle) {\n                if (otherStyle.hasOwnProperty(name)\n                    && (overwrite === true\n                        || (\n                            overwrite === false\n                                ? !this.hasOwnProperty(name)\n                                : otherStyle[name] != null\n                        )\n                    )\n                ) {\n                    this[name] = otherStyle[name];\n                }\n            }\n        }\n    },\n\n    /**\n     * Batch setting style with a given object\n     * @param {Object|string} obj\n     * @param {*} [obj]\n     */\n    set: function (obj, value) {\n        if (typeof obj === 'string') {\n            this[obj] = value;\n        }\n        else {\n            this.extendFrom(obj, true);\n        }\n    },\n\n    /**\n     * Clone\n     * @return {zrender/graphic/Style} [description]\n     */\n    clone: function () {\n        var newStyle = new this.constructor();\n        newStyle.extendFrom(this, true);\n        return newStyle;\n    },\n\n    getGradient: function (ctx, obj, rect) {\n        var method = obj.type === 'radial' ? createRadialGradient : createLinearGradient;\n        var canvasGradient = method(ctx, obj, rect);\n        var colorStops = obj.colorStops;\n        for (var i = 0; i < colorStops.length; i++) {\n            canvasGradient.addColorStop(\n                colorStops[i].offset, colorStops[i].color\n            );\n        }\n        return canvasGradient;\n    }\n\n};\n\nvar styleProto = Style.prototype;\nfor (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {\n    var prop = STYLE_COMMON_PROPS[i];\n    if (!(prop[0] in styleProto)) {\n        styleProto[prop[0]] = prop[1];\n    }\n}\n\n// Provide for others\nStyle.getGradient = styleProto.getGradient;\n\nvar Pattern = function (image, repeat) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {image: ...}`, where this constructor will not be called.\n\n    this.image = image;\n    this.repeat = repeat;\n\n    // Can be cloned\n    this.type = 'pattern';\n};\n\nPattern.prototype.getCanvasPattern = function (ctx) {\n    return ctx.createPattern(this.image, this.repeat || 'repeat');\n};\n\n/**\n * @module zrender/Layer\n * @author pissang(https://www.github.com/pissang)\n */\n\nfunction returnFalse() {\n    return false;\n}\n\n/**\n * 创建dom\n *\n * @inner\n * @param {string} id dom id 待用\n * @param {Painter} painter painter instance\n * @param {number} number\n */\nfunction createDom(id, painter, dpr) {\n    var newDom = createCanvas();\n    var width = painter.getWidth();\n    var height = painter.getHeight();\n\n    var newDomStyle = newDom.style;\n    if (newDomStyle) {  // In node or some other non-browser environment\n        newDomStyle.position = 'absolute';\n        newDomStyle.left = 0;\n        newDomStyle.top = 0;\n        newDomStyle.width = width + 'px';\n        newDomStyle.height = height + 'px';\n\n        newDom.setAttribute('data-zr-dom-id', id);\n    }\n\n    newDom.width = width * dpr;\n    newDom.height = height * dpr;\n\n    return newDom;\n}\n\n/**\n * @alias module:zrender/Layer\n * @constructor\n * @extends module:zrender/mixin/Transformable\n * @param {string} id\n * @param {module:zrender/Painter} painter\n * @param {number} [dpr]\n */\nvar Layer = function (id, painter, dpr) {\n    var dom;\n    dpr = dpr || devicePixelRatio;\n    if (typeof id === 'string') {\n        dom = createDom(id, painter, dpr);\n    }\n    // Not using isDom because in node it will return false\n    else if (isObject$1(id)) {\n        dom = id;\n        id = dom.id;\n    }\n    this.id = id;\n    this.dom = dom;\n\n    var domStyle = dom.style;\n    if (domStyle) { // Not in node\n        dom.onselectstart = returnFalse; // 避免页面选中的尴尬\n        domStyle['-webkit-user-select'] = 'none';\n        domStyle['user-select'] = 'none';\n        domStyle['-webkit-touch-callout'] = 'none';\n        domStyle['-webkit-tap-highlight-color'] = 'rgba(0,0,0,0)';\n        domStyle['padding'] = 0;\n        domStyle['margin'] = 0;\n        domStyle['border-width'] = 0;\n    }\n\n    this.domBack = null;\n    this.ctxBack = null;\n\n    this.painter = painter;\n\n    this.config = null;\n\n    // Configs\n    /**\n     * 每次清空画布的颜色\n     * @type {string}\n     * @default 0\n     */\n    this.clearColor = 0;\n    /**\n     * 是否开启动态模糊\n     * @type {boolean}\n     * @default false\n     */\n    this.motionBlur = false;\n    /**\n     * 在开启动态模糊的时候使用，与上一帧混合的alpha值，值越大尾迹越明显\n     * @type {number}\n     * @default 0.7\n     */\n    this.lastFrameAlpha = 0.7;\n\n    /**\n     * Layer dpr\n     * @type {number}\n     */\n    this.dpr = dpr;\n};\n\nLayer.prototype = {\n\n    constructor: Layer,\n\n    __dirty: true,\n\n    __used: false,\n\n    __drawIndex: 0,\n    __startIndex: 0,\n    __endIndex: 0,\n\n    incremental: false,\n\n    getElementCount: function () {\n        return this.__endIndex - this.__startIndex;\n    },\n\n    initContext: function () {\n        this.ctx = this.dom.getContext('2d');\n        this.ctx.dpr = this.dpr;\n    },\n\n    createBackBuffer: function () {\n        var dpr = this.dpr;\n\n        this.domBack = createDom('back-' + this.id, this.painter, dpr);\n        this.ctxBack = this.domBack.getContext('2d');\n\n        if (dpr !== 1) {\n            this.ctxBack.scale(dpr, dpr);\n        }\n    },\n\n    /**\n     * @param  {number} width\n     * @param  {number} height\n     */\n    resize: function (width, height) {\n        var dpr = this.dpr;\n\n        var dom = this.dom;\n        var domStyle = dom.style;\n        var domBack = this.domBack;\n\n        if (domStyle) {\n            domStyle.width = width + 'px';\n            domStyle.height = height + 'px';\n        }\n\n        dom.width = width * dpr;\n        dom.height = height * dpr;\n\n        if (domBack) {\n            domBack.width = width * dpr;\n            domBack.height = height * dpr;\n\n            if (dpr !== 1) {\n                this.ctxBack.scale(dpr, dpr);\n            }\n        }\n    },\n\n    /**\n     * 清空该层画布\n     * @param {boolean} [clearAll]=false Clear all with out motion blur\n     * @param {Color} [clearColor]\n     */\n    clear: function (clearAll, clearColor) {\n        var dom = this.dom;\n        var ctx = this.ctx;\n        var width = dom.width;\n        var height = dom.height;\n\n        var clearColor = clearColor || this.clearColor;\n        var haveMotionBLur = this.motionBlur && !clearAll;\n        var lastFrameAlpha = this.lastFrameAlpha;\n\n        var dpr = this.dpr;\n\n        if (haveMotionBLur) {\n            if (!this.domBack) {\n                this.createBackBuffer();\n            }\n\n            this.ctxBack.globalCompositeOperation = 'copy';\n            this.ctxBack.drawImage(\n                dom, 0, 0,\n                width / dpr,\n                height / dpr\n            );\n        }\n\n        ctx.clearRect(0, 0, width, height);\n        if (clearColor && clearColor !== 'transparent') {\n            var clearColorGradientOrPattern;\n            // Gradient\n            if (clearColor.colorStops) {\n                // Cache canvas gradient\n                clearColorGradientOrPattern = clearColor.__canvasGradient || Style.getGradient(ctx, clearColor, {\n                    x: 0,\n                    y: 0,\n                    width: width,\n                    height: height\n                });\n\n                clearColor.__canvasGradient = clearColorGradientOrPattern;\n            }\n            // Pattern\n            else if (clearColor.image) {\n                clearColorGradientOrPattern = Pattern.prototype.getCanvasPattern.call(clearColor, ctx);\n            }\n            ctx.save();\n            ctx.fillStyle = clearColorGradientOrPattern || clearColor;\n            ctx.fillRect(0, 0, width, height);\n            ctx.restore();\n        }\n\n        if (haveMotionBLur) {\n            var domBack = this.domBack;\n            ctx.save();\n            ctx.globalAlpha = lastFrameAlpha;\n            ctx.drawImage(domBack, 0, 0, width, height);\n            ctx.restore();\n        }\n    }\n};\n\nvar requestAnimationFrame = (\n    typeof window !== 'undefined'\n    && (\n        (window.requestAnimationFrame && window.requestAnimationFrame.bind(window))\n        // https://github.com/ecomfe/zrender/issues/189#issuecomment-224919809\n        || (window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window))\n        || window.mozRequestAnimationFrame\n        || window.webkitRequestAnimationFrame\n    )\n) || function (func) {\n    setTimeout(func, 16);\n};\n\nvar globalImageCache = new LRU(50);\n\n/**\n * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc\n * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image\n */\nfunction findExistImage(newImageOrSrc) {\n    if (typeof newImageOrSrc === 'string') {\n        var cachedImgObj = globalImageCache.get(newImageOrSrc);\n        return cachedImgObj && cachedImgObj.image;\n    }\n    else {\n        return newImageOrSrc;\n    }\n}\n\n/**\n * Caution: User should cache loaded images, but not just count on LRU.\n * Consider if required images more than LRU size, will dead loop occur?\n *\n * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc\n * @param {HTMLImageElement|HTMLCanvasElement|Canvas} image Existent image.\n * @param {module:zrender/Element} [hostEl] For calling `dirty`.\n * @param {Function} [cb] params: (image, cbPayload)\n * @param {Object} [cbPayload] Payload on cb calling.\n * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image\n */\nfunction createOrUpdateImage(newImageOrSrc, image, hostEl, cb, cbPayload) {\n    if (!newImageOrSrc) {\n        return image;\n    }\n    else if (typeof newImageOrSrc === 'string') {\n\n        // Image should not be loaded repeatly.\n        if ((image && image.__zrImageSrc === newImageOrSrc) || !hostEl) {\n            return image;\n        }\n\n        // Only when there is no existent image or existent image src\n        // is different, this method is responsible for load.\n        var cachedImgObj = globalImageCache.get(newImageOrSrc);\n\n        var pendingWrap = {hostEl: hostEl, cb: cb, cbPayload: cbPayload};\n\n        if (cachedImgObj) {\n            image = cachedImgObj.image;\n            !isImageReady(image) && cachedImgObj.pending.push(pendingWrap);\n        }\n        else {\n            image = new Image();\n            image.onload = image.onerror = imageOnLoad;\n\n            globalImageCache.put(\n                newImageOrSrc,\n                image.__cachedImgObj = {\n                    image: image,\n                    pending: [pendingWrap]\n                }\n            );\n\n            image.src = image.__zrImageSrc = newImageOrSrc;\n        }\n\n        return image;\n    }\n    // newImageOrSrc is an HTMLImageElement or HTMLCanvasElement or Canvas\n    else {\n        return newImageOrSrc;\n    }\n}\n\nfunction imageOnLoad() {\n    var cachedImgObj = this.__cachedImgObj;\n    this.onload = this.onerror = this.__cachedImgObj = null;\n\n    for (var i = 0; i < cachedImgObj.pending.length; i++) {\n        var pendingWrap = cachedImgObj.pending[i];\n        var cb = pendingWrap.cb;\n        cb && cb(this, pendingWrap.cbPayload);\n        pendingWrap.hostEl.dirty();\n    }\n    cachedImgObj.pending.length = 0;\n}\n\nfunction isImageReady(image) {\n    return image && image.width && image.height;\n}\n\nvar textWidthCache = {};\nvar textWidthCacheCounter = 0;\n\nvar TEXT_CACHE_MAX = 5000;\nvar STYLE_REG = /\\{([a-zA-Z0-9_]+)\\|([^}]*)\\}/g;\n\nvar DEFAULT_FONT$1 = '12px sans-serif';\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar methods$1 = {};\n\n\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @return {number} width\n */\nfunction getWidth(text, font) {\n    font = font || DEFAULT_FONT$1;\n    var key = text + ':' + font;\n    if (textWidthCache[key]) {\n        return textWidthCache[key];\n    }\n\n    var textLines = (text + '').split('\\n');\n    var width = 0;\n\n    for (var i = 0, l = textLines.length; i < l; i++) {\n        // textContain.measureText may be overrided in SVG or VML\n        width = Math.max(measureText(textLines[i], font).width, width);\n    }\n\n    if (textWidthCacheCounter > TEXT_CACHE_MAX) {\n        textWidthCacheCounter = 0;\n        textWidthCache = {};\n    }\n    textWidthCacheCounter++;\n    textWidthCache[key] = width;\n\n    return width;\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @param {string} [textAlign='left']\n * @param {string} [textVerticalAlign='top']\n * @param {Array.<number>} [textPadding]\n * @param {Object} [rich]\n * @param {Object} [truncate]\n * @return {Object} {x, y, width, height, lineHeight}\n */\nfunction getBoundingRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) {\n    return rich\n        ? getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate)\n        : getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate);\n}\n\nfunction getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate) {\n    var contentBlock = parsePlainText(text, font, textPadding, textLineHeight, truncate);\n    var outerWidth = getWidth(text, font);\n    if (textPadding) {\n        outerWidth += textPadding[1] + textPadding[3];\n    }\n    var outerHeight = contentBlock.outerHeight;\n\n    var x = adjustTextX(0, outerWidth, textAlign);\n    var y = adjustTextY(0, outerHeight, textVerticalAlign);\n\n    var rect = new BoundingRect(x, y, outerWidth, outerHeight);\n    rect.lineHeight = contentBlock.lineHeight;\n\n    return rect;\n}\n\nfunction getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) {\n    var contentBlock = parseRichText(text, {\n        rich: rich,\n        truncate: truncate,\n        font: font,\n        textAlign: textAlign,\n        textPadding: textPadding,\n        textLineHeight: textLineHeight\n    });\n    var outerWidth = contentBlock.outerWidth;\n    var outerHeight = contentBlock.outerHeight;\n\n    var x = adjustTextX(0, outerWidth, textAlign);\n    var y = adjustTextY(0, outerHeight, textVerticalAlign);\n\n    return new BoundingRect(x, y, outerWidth, outerHeight);\n}\n\n/**\n * @public\n * @param {number} x\n * @param {number} width\n * @param {string} [textAlign='left']\n * @return {number} Adjusted x.\n */\nfunction adjustTextX(x, width, textAlign) {\n    // FIXME Right to left language\n    if (textAlign === 'right') {\n        x -= width;\n    }\n    else if (textAlign === 'center') {\n        x -= width / 2;\n    }\n    return x;\n}\n\n/**\n * @public\n * @param {number} y\n * @param {number} height\n * @param {string} [textVerticalAlign='top']\n * @return {number} Adjusted y.\n */\nfunction adjustTextY(y, height, textVerticalAlign) {\n    if (textVerticalAlign === 'middle') {\n        y -= height / 2;\n    }\n    else if (textVerticalAlign === 'bottom') {\n        y -= height;\n    }\n    return y;\n}\n\n/**\n * @public\n * @param {stirng} textPosition\n * @param {Object} rect {x, y, width, height}\n * @param {number} distance\n * @return {Object} {x, y, textAlign, textVerticalAlign}\n */\nfunction adjustTextPositionOnRect(textPosition, rect, distance) {\n\n    var x = rect.x;\n    var y = rect.y;\n\n    var height = rect.height;\n    var width = rect.width;\n    var halfHeight = height / 2;\n\n    var textAlign = 'left';\n    var textVerticalAlign = 'top';\n\n    switch (textPosition) {\n        case 'left':\n            x -= distance;\n            y += halfHeight;\n            textAlign = 'right';\n            textVerticalAlign = 'middle';\n            break;\n        case 'right':\n            x += distance + width;\n            y += halfHeight;\n            textVerticalAlign = 'middle';\n            break;\n        case 'top':\n            x += width / 2;\n            y -= distance;\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            break;\n        case 'bottom':\n            x += width / 2;\n            y += height + distance;\n            textAlign = 'center';\n            break;\n        case 'inside':\n            x += width / 2;\n            y += halfHeight;\n            textAlign = 'center';\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideLeft':\n            x += distance;\n            y += halfHeight;\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideRight':\n            x += width - distance;\n            y += halfHeight;\n            textAlign = 'right';\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideTop':\n            x += width / 2;\n            y += distance;\n            textAlign = 'center';\n            break;\n        case 'insideBottom':\n            x += width / 2;\n            y += height - distance;\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            break;\n        case 'insideTopLeft':\n            x += distance;\n            y += distance;\n            break;\n        case 'insideTopRight':\n            x += width - distance;\n            y += distance;\n            textAlign = 'right';\n            break;\n        case 'insideBottomLeft':\n            x += distance;\n            y += height - distance;\n            textVerticalAlign = 'bottom';\n            break;\n        case 'insideBottomRight':\n            x += width - distance;\n            y += height - distance;\n            textAlign = 'right';\n            textVerticalAlign = 'bottom';\n            break;\n    }\n\n    return {\n        x: x,\n        y: y,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\n/**\n * Show ellipsis if overflow.\n *\n * @public\n * @param  {string} text\n * @param  {string} containerWidth\n * @param  {string} font\n * @param  {number} [ellipsis='...']\n * @param  {Object} [options]\n * @param  {number} [options.maxIterations=3]\n * @param  {number} [options.minChar=0] If truncate result are less\n *                  then minChar, ellipsis will not show, which is\n *                  better for user hint in some cases.\n * @param  {number} [options.placeholder=''] When all truncated, use the placeholder.\n * @return {string}\n */\nfunction truncateText(text, containerWidth, font, ellipsis, options) {\n    if (!containerWidth) {\n        return '';\n    }\n\n    var textLines = (text + '').split('\\n');\n    options = prepareTruncateOptions(containerWidth, font, ellipsis, options);\n\n    // FIXME\n    // It is not appropriate that every line has '...' when truncate multiple lines.\n    for (var i = 0, len = textLines.length; i < len; i++) {\n        textLines[i] = truncateSingleLine(textLines[i], options);\n    }\n\n    return textLines.join('\\n');\n}\n\nfunction prepareTruncateOptions(containerWidth, font, ellipsis, options) {\n    options = extend({}, options);\n\n    options.font = font;\n    var ellipsis = retrieve2(ellipsis, '...');\n    options.maxIterations = retrieve2(options.maxIterations, 2);\n    var minChar = options.minChar = retrieve2(options.minChar, 0);\n    // FIXME\n    // Other languages?\n    options.cnCharWidth = getWidth('国', font);\n    // FIXME\n    // Consider proportional font?\n    var ascCharWidth = options.ascCharWidth = getWidth('a', font);\n    options.placeholder = retrieve2(options.placeholder, '');\n\n    // Example 1: minChar: 3, text: 'asdfzxcv', truncate result: 'asdf', but not: 'a...'.\n    // Example 2: minChar: 3, text: '维度', truncate result: '维', but not: '...'.\n    var contentWidth = containerWidth = Math.max(0, containerWidth - 1); // Reserve some gap.\n    for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) {\n        contentWidth -= ascCharWidth;\n    }\n\n    var ellipsisWidth = getWidth(ellipsis, font);\n    if (ellipsisWidth > contentWidth) {\n        ellipsis = '';\n        ellipsisWidth = 0;\n    }\n\n    contentWidth = containerWidth - ellipsisWidth;\n\n    options.ellipsis = ellipsis;\n    options.ellipsisWidth = ellipsisWidth;\n    options.contentWidth = contentWidth;\n    options.containerWidth = containerWidth;\n\n    return options;\n}\n\nfunction truncateSingleLine(textLine, options) {\n    var containerWidth = options.containerWidth;\n    var font = options.font;\n    var contentWidth = options.contentWidth;\n\n    if (!containerWidth) {\n        return '';\n    }\n\n    var lineWidth = getWidth(textLine, font);\n\n    if (lineWidth <= containerWidth) {\n        return textLine;\n    }\n\n    for (var j = 0; ; j++) {\n        if (lineWidth <= contentWidth || j >= options.maxIterations) {\n            textLine += options.ellipsis;\n            break;\n        }\n\n        var subLength = j === 0\n            ? estimateLength(textLine, contentWidth, options.ascCharWidth, options.cnCharWidth)\n            : lineWidth > 0\n            ? Math.floor(textLine.length * contentWidth / lineWidth)\n            : 0;\n\n        textLine = textLine.substr(0, subLength);\n        lineWidth = getWidth(textLine, font);\n    }\n\n    if (textLine === '') {\n        textLine = options.placeholder;\n    }\n\n    return textLine;\n}\n\nfunction estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) {\n    var width = 0;\n    var i = 0;\n    for (var len = text.length; i < len && width < contentWidth; i++) {\n        var charCode = text.charCodeAt(i);\n        width += (0 <= charCode && charCode <= 127) ? ascCharWidth : cnCharWidth;\n    }\n    return i;\n}\n\n/**\n * @public\n * @param {string} font\n * @return {number} line height\n */\nfunction getLineHeight(font) {\n    // FIXME A rough approach.\n    return getWidth('国', font);\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @return {Object} width\n */\nfunction measureText(text, font) {\n    return methods$1.measureText(text, font);\n}\n\n// Avoid assign to an exported variable, for transforming to cjs.\nmethods$1.measureText = function (text, font) {\n    var ctx = getContext();\n    ctx.font = font || DEFAULT_FONT$1;\n    return ctx.measureText(text);\n};\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @param {Object} [truncate]\n * @return {Object} block: {lineHeight, lines, height, outerHeight}\n *  Notice: for performance, do not calculate outerWidth util needed.\n */\nfunction parsePlainText(text, font, padding, textLineHeight, truncate) {\n    text != null && (text += '');\n\n    var lineHeight = retrieve2(textLineHeight, getLineHeight(font));\n    var lines = text ? text.split('\\n') : [];\n    var height = lines.length * lineHeight;\n    var outerHeight = height;\n\n    if (padding) {\n        outerHeight += padding[0] + padding[2];\n    }\n\n    if (text && truncate) {\n        var truncOuterHeight = truncate.outerHeight;\n        var truncOuterWidth = truncate.outerWidth;\n        if (truncOuterHeight != null && outerHeight > truncOuterHeight) {\n            text = '';\n            lines = [];\n        }\n        else if (truncOuterWidth != null) {\n            var options = prepareTruncateOptions(\n                truncOuterWidth - (padding ? padding[1] + padding[3] : 0),\n                font,\n                truncate.ellipsis,\n                {minChar: truncate.minChar, placeholder: truncate.placeholder}\n            );\n\n            // FIXME\n            // It is not appropriate that every line has '...' when truncate multiple lines.\n            for (var i = 0, len = lines.length; i < len; i++) {\n                lines[i] = truncateSingleLine(lines[i], options);\n            }\n        }\n    }\n\n    return {\n        lines: lines,\n        height: height,\n        outerHeight: outerHeight,\n        lineHeight: lineHeight\n    };\n}\n\n/**\n * For example: 'some text {a|some text}other text{b|some text}xxx{c|}xxx'\n * Also consider 'bbbb{a|xxx\\nzzz}xxxx\\naaaa'.\n *\n * @public\n * @param {string} text\n * @param {Object} style\n * @return {Object} block\n * {\n *      width,\n *      height,\n *      lines: [{\n *          lineHeight,\n *          width,\n *          tokens: [[{\n *              styleName,\n *              text,\n *              width,      // include textPadding\n *              height,     // include textPadding\n *              textWidth, // pure text width\n *              textHeight, // pure text height\n *              lineHeihgt,\n *              font,\n *              textAlign,\n *              textVerticalAlign\n *          }], [...], ...]\n *      }, ...]\n * }\n * If styleName is undefined, it is plain text.\n */\nfunction parseRichText(text, style) {\n    var contentBlock = {lines: [], width: 0, height: 0};\n\n    text != null && (text += '');\n    if (!text) {\n        return contentBlock;\n    }\n\n    var lastIndex = STYLE_REG.lastIndex = 0;\n    var result;\n    while ((result = STYLE_REG.exec(text)) != null) {\n        var matchedIndex = result.index;\n        if (matchedIndex > lastIndex) {\n            pushTokens(contentBlock, text.substring(lastIndex, matchedIndex));\n        }\n        pushTokens(contentBlock, result[2], result[1]);\n        lastIndex = STYLE_REG.lastIndex;\n    }\n\n    if (lastIndex < text.length) {\n        pushTokens(contentBlock, text.substring(lastIndex, text.length));\n    }\n\n    var lines = contentBlock.lines;\n    var contentHeight = 0;\n    var contentWidth = 0;\n    // For `textWidth: 100%`\n    var pendingList = [];\n\n    var stlPadding = style.textPadding;\n\n    var truncate = style.truncate;\n    var truncateWidth = truncate && truncate.outerWidth;\n    var truncateHeight = truncate && truncate.outerHeight;\n    if (stlPadding) {\n        truncateWidth != null && (truncateWidth -= stlPadding[1] + stlPadding[3]);\n        truncateHeight != null && (truncateHeight -= stlPadding[0] + stlPadding[2]);\n    }\n\n    // Calculate layout info of tokens.\n    for (var i = 0; i < lines.length; i++) {\n        var line = lines[i];\n        var lineHeight = 0;\n        var lineWidth = 0;\n\n        for (var j = 0; j < line.tokens.length; j++) {\n            var token = line.tokens[j];\n            var tokenStyle = token.styleName && style.rich[token.styleName] || {};\n            // textPadding should not inherit from style.\n            var textPadding = token.textPadding = tokenStyle.textPadding;\n\n            // textFont has been asigned to font by `normalizeStyle`.\n            var font = token.font = tokenStyle.font || style.font;\n\n            // textHeight can be used when textVerticalAlign is specified in token.\n            var tokenHeight = token.textHeight = retrieve2(\n                // textHeight should not be inherited, consider it can be specified\n                // as box height of the block.\n                tokenStyle.textHeight, getLineHeight(font)\n            );\n            textPadding && (tokenHeight += textPadding[0] + textPadding[2]);\n            token.height = tokenHeight;\n            token.lineHeight = retrieve3(\n                tokenStyle.textLineHeight, style.textLineHeight, tokenHeight\n            );\n\n            token.textAlign = tokenStyle && tokenStyle.textAlign || style.textAlign;\n            token.textVerticalAlign = tokenStyle && tokenStyle.textVerticalAlign || 'middle';\n\n            if (truncateHeight != null && contentHeight + token.lineHeight > truncateHeight) {\n                return {lines: [], width: 0, height: 0};\n            }\n\n            token.textWidth = getWidth(token.text, font);\n            var tokenWidth = tokenStyle.textWidth;\n            var tokenWidthNotSpecified = tokenWidth == null || tokenWidth === 'auto';\n\n            // Percent width, can be `100%`, can be used in drawing separate\n            // line when box width is needed to be auto.\n            if (typeof tokenWidth === 'string' && tokenWidth.charAt(tokenWidth.length - 1) === '%') {\n                token.percentWidth = tokenWidth;\n                pendingList.push(token);\n                tokenWidth = 0;\n                // Do not truncate in this case, because there is no user case\n                // and it is too complicated.\n            }\n            else {\n                if (tokenWidthNotSpecified) {\n                    tokenWidth = token.textWidth;\n\n                    // FIXME: If image is not loaded and textWidth is not specified, calling\n                    // `getBoundingRect()` will not get correct result.\n                    var textBackgroundColor = tokenStyle.textBackgroundColor;\n                    var bgImg = textBackgroundColor && textBackgroundColor.image;\n\n                    // Use cases:\n                    // (1) If image is not loaded, it will be loaded at render phase and call\n                    // `dirty()` and `textBackgroundColor.image` will be replaced with the loaded\n                    // image, and then the right size will be calculated here at the next tick.\n                    // See `graphic/helper/text.js`.\n                    // (2) If image loaded, and `textBackgroundColor.image` is image src string,\n                    // use `imageHelper.findExistImage` to find cached image.\n                    // `imageHelper.findExistImage` will always be called here before\n                    // `imageHelper.createOrUpdateImage` in `graphic/helper/text.js#renderRichText`\n                    // which ensures that image will not be rendered before correct size calcualted.\n                    if (bgImg) {\n                        bgImg = findExistImage(bgImg);\n                        if (isImageReady(bgImg)) {\n                            tokenWidth = Math.max(tokenWidth, bgImg.width * tokenHeight / bgImg.height);\n                        }\n                    }\n                }\n\n                var paddingW = textPadding ? textPadding[1] + textPadding[3] : 0;\n                tokenWidth += paddingW;\n\n                var remianTruncWidth = truncateWidth != null ? truncateWidth - lineWidth : null;\n\n                if (remianTruncWidth != null && remianTruncWidth < tokenWidth) {\n                    if (!tokenWidthNotSpecified || remianTruncWidth < paddingW) {\n                        token.text = '';\n                        token.textWidth = tokenWidth = 0;\n                    }\n                    else {\n                        token.text = truncateText(\n                            token.text, remianTruncWidth - paddingW, font, truncate.ellipsis,\n                            {minChar: truncate.minChar}\n                        );\n                        token.textWidth = getWidth(token.text, font);\n                        tokenWidth = token.textWidth + paddingW;\n                    }\n                }\n            }\n\n            lineWidth += (token.width = tokenWidth);\n            tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight));\n        }\n\n        line.width = lineWidth;\n        line.lineHeight = lineHeight;\n        contentHeight += lineHeight;\n        contentWidth = Math.max(contentWidth, lineWidth);\n    }\n\n    contentBlock.outerWidth = contentBlock.width = retrieve2(style.textWidth, contentWidth);\n    contentBlock.outerHeight = contentBlock.height = retrieve2(style.textHeight, contentHeight);\n\n    if (stlPadding) {\n        contentBlock.outerWidth += stlPadding[1] + stlPadding[3];\n        contentBlock.outerHeight += stlPadding[0] + stlPadding[2];\n    }\n\n    for (var i = 0; i < pendingList.length; i++) {\n        var token = pendingList[i];\n        var percentWidth = token.percentWidth;\n        // Should not base on outerWidth, because token can not be placed out of padding.\n        token.width = parseInt(percentWidth, 10) / 100 * contentWidth;\n    }\n\n    return contentBlock;\n}\n\nfunction pushTokens(block, str, styleName) {\n    var isEmptyStr = str === '';\n    var strs = str.split('\\n');\n    var lines = block.lines;\n\n    for (var i = 0; i < strs.length; i++) {\n        var text = strs[i];\n        var token = {\n            styleName: styleName,\n            text: text,\n            isLineHolder: !text && !isEmptyStr\n        };\n\n        // The first token should be appended to the last line.\n        if (!i) {\n            var tokens = (lines[lines.length - 1] || (lines[0] = {tokens: []})).tokens;\n\n            // Consider cases:\n            // (1) ''.split('\\n') => ['', '\\n', ''], the '' at the first item\n            // (which is a placeholder) should be replaced by new token.\n            // (2) A image backage, where token likes {a|}.\n            // (3) A redundant '' will affect textAlign in line.\n            // (4) tokens with the same tplName should not be merged, because\n            // they should be displayed in different box (with border and padding).\n            var tokensLen = tokens.length;\n            (tokensLen === 1 && tokens[0].isLineHolder)\n                ? (tokens[0] = token)\n                // Consider text is '', only insert when it is the \"lineHolder\" or\n                // \"emptyStr\". Otherwise a redundant '' will affect textAlign in line.\n                : ((text || !tokensLen || isEmptyStr) && tokens.push(token));\n        }\n        // Other tokens always start a new line.\n        else {\n            // If there is '', insert it as a placeholder.\n            lines.push({tokens: [token]});\n        }\n    }\n}\n\nfunction makeFont(style) {\n    // FIXME in node-canvas fontWeight is before fontStyle\n    // Use `fontSize` `fontFamily` to check whether font properties are defined.\n    var font = (style.fontSize || style.fontFamily) && [\n        style.fontStyle,\n        style.fontWeight,\n        (style.fontSize || 12) + 'px',\n        // If font properties are defined, `fontFamily` should not be ignored.\n        style.fontFamily || 'sans-serif'\n    ].join(' ');\n    return font && trim(font) || style.textFont || style.font;\n}\n\n/**\n * @param {Object} ctx\n * @param {Object} shape\n * @param {number} shape.x\n * @param {number} shape.y\n * @param {number} shape.width\n * @param {number} shape.height\n * @param {number} shape.r\n */\nfunction buildPath(ctx, shape) {\n    var x = shape.x;\n    var y = shape.y;\n    var width = shape.width;\n    var height = shape.height;\n    var r = shape.r;\n    var r1;\n    var r2;\n    var r3;\n    var r4;\n\n    // Convert width and height to positive for better borderRadius\n    if (width < 0) {\n        x = x + width;\n        width = -width;\n    }\n    if (height < 0) {\n        y = y + height;\n        height = -height;\n    }\n\n    if (typeof r === 'number') {\n        r1 = r2 = r3 = r4 = r;\n    }\n    else if (r instanceof Array) {\n        if (r.length === 1) {\n            r1 = r2 = r3 = r4 = r[0];\n        }\n        else if (r.length === 2) {\n            r1 = r3 = r[0];\n            r2 = r4 = r[1];\n        }\n        else if (r.length === 3) {\n            r1 = r[0];\n            r2 = r4 = r[1];\n            r3 = r[2];\n        }\n        else {\n            r1 = r[0];\n            r2 = r[1];\n            r3 = r[2];\n            r4 = r[3];\n        }\n    }\n    else {\n        r1 = r2 = r3 = r4 = 0;\n    }\n\n    var total;\n    if (r1 + r2 > width) {\n        total = r1 + r2;\n        r1 *= width / total;\n        r2 *= width / total;\n    }\n    if (r3 + r4 > width) {\n        total = r3 + r4;\n        r3 *= width / total;\n        r4 *= width / total;\n    }\n    if (r2 + r3 > height) {\n        total = r2 + r3;\n        r2 *= height / total;\n        r3 *= height / total;\n    }\n    if (r1 + r4 > height) {\n        total = r1 + r4;\n        r1 *= height / total;\n        r4 *= height / total;\n    }\n    ctx.moveTo(x + r1, y);\n    ctx.lineTo(x + width - r2, y);\n    r2 !== 0 && ctx.arc(x + width - r2, y + r2, r2, -Math.PI / 2, 0);\n    ctx.lineTo(x + width, y + height - r3);\n    r3 !== 0 && ctx.arc(x + width - r3, y + height - r3, r3, 0, Math.PI / 2);\n    ctx.lineTo(x + r4, y + height);\n    r4 !== 0 && ctx.arc(x + r4, y + height - r4, r4, Math.PI / 2, Math.PI);\n    ctx.lineTo(x, y + r1);\n    r1 !== 0 && ctx.arc(x + r1, y + r1, r1, Math.PI, Math.PI * 1.5);\n}\n\nvar DEFAULT_FONT = DEFAULT_FONT$1;\n\n// TODO: Have not support 'start', 'end' yet.\nvar VALID_TEXT_ALIGN = {left: 1, right: 1, center: 1};\nvar VALID_TEXT_VERTICAL_ALIGN = {top: 1, bottom: 1, middle: 1};\n// Different from `STYLE_COMMON_PROPS` of `graphic/Style`,\n// the default value of shadowColor is `'transparent'`.\nvar SHADOW_STYLE_COMMON_PROPS = [\n    ['textShadowBlur', 'shadowBlur', 0],\n    ['textShadowOffsetX', 'shadowOffsetX', 0],\n    ['textShadowOffsetY', 'shadowOffsetY', 0],\n    ['textShadowColor', 'shadowColor', 'transparent']\n];\n\n/**\n * @param {module:zrender/graphic/Style} style\n * @return {module:zrender/graphic/Style} The input style.\n */\nfunction normalizeTextStyle(style) {\n    normalizeStyle(style);\n    each$1(style.rich, normalizeStyle);\n    return style;\n}\n\nfunction normalizeStyle(style) {\n    if (style) {\n\n        style.font = makeFont(style);\n\n        var textAlign = style.textAlign;\n        textAlign === 'middle' && (textAlign = 'center');\n        style.textAlign = (\n            textAlign == null || VALID_TEXT_ALIGN[textAlign]\n        ) ? textAlign : 'left';\n\n        // Compatible with textBaseline.\n        var textVerticalAlign = style.textVerticalAlign || style.textBaseline;\n        textVerticalAlign === 'center' && (textVerticalAlign = 'middle');\n        style.textVerticalAlign = (\n            textVerticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[textVerticalAlign]\n        ) ? textVerticalAlign : 'top';\n\n        var textPadding = style.textPadding;\n        if (textPadding) {\n            style.textPadding = normalizeCssArray(style.textPadding);\n        }\n    }\n}\n\n/**\n * @param {CanvasRenderingContext2D} ctx\n * @param {string} text\n * @param {module:zrender/graphic/Style} style\n * @param {Object|boolean} [rect] {x, y, width, height}\n *                  If set false, rect text is not used.\n * @param {Element|module:zrender/graphic/helper/constant.WILL_BE_RESTORED} [prevEl] For ctx prop cache.\n */\nfunction renderText(hostEl, ctx, text, style, rect, prevEl) {\n    style.rich\n        ? renderRichText(hostEl, ctx, text, style, rect, prevEl)\n        : renderPlainText(hostEl, ctx, text, style, rect, prevEl);\n}\n\n// Avoid setting to ctx according to prevEl if possible for\n// performance in scenarios of large amount text.\nfunction renderPlainText(hostEl, ctx, text, style, rect, prevEl) {\n    'use strict';\n\n    var needDrawBg = needDrawBackground(style);\n\n    var prevStyle;\n    var checkCache = false;\n    var cachedByMe = ctx.__attrCachedBy === ContextCachedBy.PLAIN_TEXT;\n\n    // Only take and check cache for `Text` el, but not RectText.\n    if (prevEl !== WILL_BE_RESTORED) {\n        if (prevEl) {\n            prevStyle = prevEl.style;\n            checkCache = !needDrawBg && cachedByMe && prevStyle;\n        }\n\n        // Prevent from using cache in `Style::bind`, because of the case:\n        // ctx property is modified by other properties than `Style::bind`\n        // used, and Style::bind is called next.\n        ctx.__attrCachedBy = needDrawBg ? ContextCachedBy.NONE : ContextCachedBy.PLAIN_TEXT;\n    }\n    // Since this will be restored, prevent from using these props to check cache in the next\n    // entering of this method. But do not need to clear other cache like `Style::bind`.\n    else if (cachedByMe) {\n        ctx.__attrCachedBy = ContextCachedBy.NONE;\n    }\n\n    var styleFont = style.font || DEFAULT_FONT;\n    // PENDING\n    // Only `Text` el set `font` and keep it (`RectText` will restore). So theoretically\n    // we can make font cache on ctx, which can cache for text el that are discontinuous.\n    // But layer save/restore needed to be considered.\n    // if (styleFont !== ctx.__fontCache) {\n    //     ctx.font = styleFont;\n    //     if (prevEl !== WILL_BE_RESTORED) {\n    //         ctx.__fontCache = styleFont;\n    //     }\n    // }\n    if (!checkCache || styleFont !== (prevStyle.font || DEFAULT_FONT)) {\n        ctx.font = styleFont;\n    }\n\n    // Use the final font from context-2d, because the final\n    // font might not be the style.font when it is illegal.\n    // But get `ctx.font` might be time consuming.\n    var computedFont = hostEl.__computedFont;\n    if (hostEl.__styleFont !== styleFont) {\n        hostEl.__styleFont = styleFont;\n        computedFont = hostEl.__computedFont = ctx.font;\n    }\n\n    var textPadding = style.textPadding;\n    var textLineHeight = style.textLineHeight;\n\n    var contentBlock = hostEl.__textCotentBlock;\n    if (!contentBlock || hostEl.__dirtyText) {\n        contentBlock = hostEl.__textCotentBlock = parsePlainText(\n            text, computedFont, textPadding, textLineHeight, style.truncate\n        );\n    }\n\n    var outerHeight = contentBlock.outerHeight;\n\n    var textLines = contentBlock.lines;\n    var lineHeight = contentBlock.lineHeight;\n\n    var boxPos = getBoxPosition(outerHeight, style, rect);\n    var baseX = boxPos.baseX;\n    var baseY = boxPos.baseY;\n    var textAlign = boxPos.textAlign || 'left';\n    var textVerticalAlign = boxPos.textVerticalAlign;\n\n    // Origin of textRotation should be the base point of text drawing.\n    applyTextRotation(ctx, style, rect, baseX, baseY);\n\n    var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);\n    var textX = baseX;\n    var textY = boxY;\n\n    if (needDrawBg || textPadding) {\n        // Consider performance, do not call getTextWidth util necessary.\n        var textWidth = getWidth(text, computedFont);\n        var outerWidth = textWidth;\n        textPadding && (outerWidth += textPadding[1] + textPadding[3]);\n        var boxX = adjustTextX(baseX, outerWidth, textAlign);\n\n        needDrawBg && drawBackground(hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight);\n\n        if (textPadding) {\n            textX = getTextXForPadding(baseX, textAlign, textPadding);\n            textY += textPadding[0];\n        }\n    }\n\n    // Always set textAlign and textBase line, because it is difficute to calculate\n    // textAlign from prevEl, and we dont sure whether textAlign will be reset if\n    // font set happened.\n    ctx.textAlign = textAlign;\n    // Force baseline to be \"middle\". Otherwise, if using \"top\", the\n    // text will offset downward a little bit in font \"Microsoft YaHei\".\n    ctx.textBaseline = 'middle';\n    // Set text opacity\n    ctx.globalAlpha = style.opacity || 1;\n\n    // Always set shadowBlur and shadowOffset to avoid leak from displayable.\n    for (var i = 0; i < SHADOW_STYLE_COMMON_PROPS.length; i++) {\n        var propItem = SHADOW_STYLE_COMMON_PROPS[i];\n        var styleProp = propItem[0];\n        var ctxProp = propItem[1];\n        var val = style[styleProp];\n        if (!checkCache || val !== prevStyle[styleProp]) {\n            ctx[ctxProp] = fixShadow(ctx, ctxProp, val || propItem[2]);\n        }\n    }\n\n    // `textBaseline` is set as 'middle'.\n    textY += lineHeight / 2;\n\n    var textStrokeWidth = style.textStrokeWidth;\n    var textStrokeWidthPrev = checkCache ? prevStyle.textStrokeWidth : null;\n    var strokeWidthChanged = !checkCache || textStrokeWidth !== textStrokeWidthPrev;\n    var strokeChanged = !checkCache || strokeWidthChanged || style.textStroke !== prevStyle.textStroke;\n    var textStroke = getStroke(style.textStroke, textStrokeWidth);\n    var textFill = getFill(style.textFill);\n\n    if (textStroke) {\n        if (strokeWidthChanged) {\n            ctx.lineWidth = textStrokeWidth;\n        }\n        if (strokeChanged) {\n            ctx.strokeStyle = textStroke;\n        }\n    }\n    if (textFill) {\n        if (!checkCache || style.textFill !== prevStyle.textFill) {\n            ctx.fillStyle = textFill;\n        }\n    }\n\n    // Optimize simply, in most cases only one line exists.\n    if (textLines.length === 1) {\n        // Fill after stroke so the outline will not cover the main part.\n        textStroke && ctx.strokeText(textLines[0], textX, textY);\n        textFill && ctx.fillText(textLines[0], textX, textY);\n    }\n    else {\n        for (var i = 0; i < textLines.length; i++) {\n            // Fill after stroke so the outline will not cover the main part.\n            textStroke && ctx.strokeText(textLines[i], textX, textY);\n            textFill && ctx.fillText(textLines[i], textX, textY);\n            textY += lineHeight;\n        }\n    }\n}\n\nfunction renderRichText(hostEl, ctx, text, style, rect, prevEl) {\n    // Do not do cache for rich text because of the complexity.\n    // But `RectText` this will be restored, do not need to clear other cache like `Style::bind`.\n    if (prevEl !== WILL_BE_RESTORED) {\n        ctx.__attrCachedBy = ContextCachedBy.NONE;\n    }\n\n    var contentBlock = hostEl.__textCotentBlock;\n\n    if (!contentBlock || hostEl.__dirtyText) {\n        contentBlock = hostEl.__textCotentBlock = parseRichText(text, style);\n    }\n\n    drawRichText(hostEl, ctx, contentBlock, style, rect);\n}\n\nfunction drawRichText(hostEl, ctx, contentBlock, style, rect) {\n    var contentWidth = contentBlock.width;\n    var outerWidth = contentBlock.outerWidth;\n    var outerHeight = contentBlock.outerHeight;\n    var textPadding = style.textPadding;\n\n    var boxPos = getBoxPosition(outerHeight, style, rect);\n    var baseX = boxPos.baseX;\n    var baseY = boxPos.baseY;\n    var textAlign = boxPos.textAlign;\n    var textVerticalAlign = boxPos.textVerticalAlign;\n\n    // Origin of textRotation should be the base point of text drawing.\n    applyTextRotation(ctx, style, rect, baseX, baseY);\n\n    var boxX = adjustTextX(baseX, outerWidth, textAlign);\n    var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);\n    var xLeft = boxX;\n    var lineTop = boxY;\n    if (textPadding) {\n        xLeft += textPadding[3];\n        lineTop += textPadding[0];\n    }\n    var xRight = xLeft + contentWidth;\n\n    needDrawBackground(style) && drawBackground(\n        hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight\n    );\n\n    for (var i = 0; i < contentBlock.lines.length; i++) {\n        var line = contentBlock.lines[i];\n        var tokens = line.tokens;\n        var tokenCount = tokens.length;\n        var lineHeight = line.lineHeight;\n        var usedWidth = line.width;\n\n        var leftIndex = 0;\n        var lineXLeft = xLeft;\n        var lineXRight = xRight;\n        var rightIndex = tokenCount - 1;\n        var token;\n\n        while (\n            leftIndex < tokenCount\n            && (token = tokens[leftIndex], !token.textAlign || token.textAlign === 'left')\n        ) {\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft, 'left');\n            usedWidth -= token.width;\n            lineXLeft += token.width;\n            leftIndex++;\n        }\n\n        while (\n            rightIndex >= 0\n            && (token = tokens[rightIndex], token.textAlign === 'right')\n        ) {\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXRight, 'right');\n            usedWidth -= token.width;\n            lineXRight -= token.width;\n            rightIndex--;\n        }\n\n        // The other tokens are placed as textAlign 'center' if there is enough space.\n        lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - usedWidth) / 2;\n        while (leftIndex <= rightIndex) {\n            token = tokens[leftIndex];\n            // Consider width specified by user, use 'center' rather than 'left'.\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center');\n            lineXLeft += token.width;\n            leftIndex++;\n        }\n\n        lineTop += lineHeight;\n    }\n}\n\nfunction applyTextRotation(ctx, style, rect, x, y) {\n    // textRotation only apply in RectText.\n    if (rect && style.textRotation) {\n        var origin = style.textOrigin;\n        if (origin === 'center') {\n            x = rect.width / 2 + rect.x;\n            y = rect.height / 2 + rect.y;\n        }\n        else if (origin) {\n            x = origin[0] + rect.x;\n            y = origin[1] + rect.y;\n        }\n\n        ctx.translate(x, y);\n        // Positive: anticlockwise\n        ctx.rotate(-style.textRotation);\n        ctx.translate(-x, -y);\n    }\n}\n\nfunction placeToken(hostEl, ctx, token, style, lineHeight, lineTop, x, textAlign) {\n    var tokenStyle = style.rich[token.styleName] || {};\n    tokenStyle.text = token.text;\n\n    // 'ctx.textBaseline' is always set as 'middle', for sake of\n    // the bias of \"Microsoft YaHei\".\n    var textVerticalAlign = token.textVerticalAlign;\n    var y = lineTop + lineHeight / 2;\n    if (textVerticalAlign === 'top') {\n        y = lineTop + token.height / 2;\n    }\n    else if (textVerticalAlign === 'bottom') {\n        y = lineTop + lineHeight - token.height / 2;\n    }\n\n    !token.isLineHolder && needDrawBackground(tokenStyle) && drawBackground(\n        hostEl,\n        ctx,\n        tokenStyle,\n        textAlign === 'right'\n            ? x - token.width\n            : textAlign === 'center'\n            ? x - token.width / 2\n            : x,\n        y - token.height / 2,\n        token.width,\n        token.height\n    );\n\n    var textPadding = token.textPadding;\n    if (textPadding) {\n        x = getTextXForPadding(x, textAlign, textPadding);\n        y -= token.height / 2 - textPadding[2] - token.textHeight / 2;\n    }\n\n    setCtx(ctx, 'shadowBlur', retrieve3(tokenStyle.textShadowBlur, style.textShadowBlur, 0));\n    setCtx(ctx, 'shadowColor', tokenStyle.textShadowColor || style.textShadowColor || 'transparent');\n    setCtx(ctx, 'shadowOffsetX', retrieve3(tokenStyle.textShadowOffsetX, style.textShadowOffsetX, 0));\n    setCtx(ctx, 'shadowOffsetY', retrieve3(tokenStyle.textShadowOffsetY, style.textShadowOffsetY, 0));\n\n    setCtx(ctx, 'textAlign', textAlign);\n    // Force baseline to be \"middle\". Otherwise, if using \"top\", the\n    // text will offset downward a little bit in font \"Microsoft YaHei\".\n    setCtx(ctx, 'textBaseline', 'middle');\n\n    setCtx(ctx, 'font', token.font || DEFAULT_FONT);\n\n    var textStroke = getStroke(tokenStyle.textStroke || style.textStroke, textStrokeWidth);\n    var textFill = getFill(tokenStyle.textFill || style.textFill);\n    var textStrokeWidth = retrieve2(tokenStyle.textStrokeWidth, style.textStrokeWidth);\n\n    // Fill after stroke so the outline will not cover the main part.\n    if (textStroke) {\n        setCtx(ctx, 'lineWidth', textStrokeWidth);\n        setCtx(ctx, 'strokeStyle', textStroke);\n        ctx.strokeText(token.text, x, y);\n    }\n    if (textFill) {\n        setCtx(ctx, 'fillStyle', textFill);\n        ctx.fillText(token.text, x, y);\n    }\n}\n\nfunction needDrawBackground(style) {\n    return !!(\n        style.textBackgroundColor\n        || (style.textBorderWidth && style.textBorderColor)\n    );\n}\n\n// style: {textBackgroundColor, textBorderWidth, textBorderColor, textBorderRadius, text}\n// shape: {x, y, width, height}\nfunction drawBackground(hostEl, ctx, style, x, y, width, height) {\n    var textBackgroundColor = style.textBackgroundColor;\n    var textBorderWidth = style.textBorderWidth;\n    var textBorderColor = style.textBorderColor;\n    var isPlainBg = isString(textBackgroundColor);\n\n    setCtx(ctx, 'shadowBlur', style.textBoxShadowBlur || 0);\n    setCtx(ctx, 'shadowColor', style.textBoxShadowColor || 'transparent');\n    setCtx(ctx, 'shadowOffsetX', style.textBoxShadowOffsetX || 0);\n    setCtx(ctx, 'shadowOffsetY', style.textBoxShadowOffsetY || 0);\n\n    if (isPlainBg || (textBorderWidth && textBorderColor)) {\n        ctx.beginPath();\n        var textBorderRadius = style.textBorderRadius;\n        if (!textBorderRadius) {\n            ctx.rect(x, y, width, height);\n        }\n        else {\n            buildPath(ctx, {\n                x: x, y: y, width: width, height: height, r: textBorderRadius\n            });\n        }\n        ctx.closePath();\n    }\n\n    if (isPlainBg) {\n        setCtx(ctx, 'fillStyle', textBackgroundColor);\n\n        if (style.fillOpacity != null) {\n            var originalGlobalAlpha = ctx.globalAlpha;\n            ctx.globalAlpha = style.fillOpacity * style.opacity;\n            ctx.fill();\n            ctx.globalAlpha = originalGlobalAlpha;\n        }\n        else {\n            ctx.fill();\n        }\n    }\n    else if (isObject$1(textBackgroundColor)) {\n        var image = textBackgroundColor.image;\n\n        image = createOrUpdateImage(\n            image, null, hostEl, onBgImageLoaded, textBackgroundColor\n        );\n        if (image && isImageReady(image)) {\n            ctx.drawImage(image, x, y, width, height);\n        }\n    }\n\n    if (textBorderWidth && textBorderColor) {\n        setCtx(ctx, 'lineWidth', textBorderWidth);\n        setCtx(ctx, 'strokeStyle', textBorderColor);\n\n        if (style.strokeOpacity != null) {\n            var originalGlobalAlpha = ctx.globalAlpha;\n            ctx.globalAlpha = style.strokeOpacity * style.opacity;\n            ctx.stroke();\n            ctx.globalAlpha = originalGlobalAlpha;\n        }\n        else {\n            ctx.stroke();\n        }\n    }\n}\n\nfunction onBgImageLoaded(image, textBackgroundColor) {\n    // Replace image, so that `contain/text.js#parseRichText`\n    // will get correct result in next tick.\n    textBackgroundColor.image = image;\n}\n\nfunction getBoxPosition(blockHeiht, style, rect) {\n    var baseX = style.x || 0;\n    var baseY = style.y || 0;\n    var textAlign = style.textAlign;\n    var textVerticalAlign = style.textVerticalAlign;\n\n    // Text position represented by coord\n    if (rect) {\n        var textPosition = style.textPosition;\n        if (textPosition instanceof Array) {\n            // Percent\n            baseX = rect.x + parsePercent(textPosition[0], rect.width);\n            baseY = rect.y + parsePercent(textPosition[1], rect.height);\n        }\n        else {\n            var res = adjustTextPositionOnRect(\n                textPosition, rect, style.textDistance\n            );\n            baseX = res.x;\n            baseY = res.y;\n            // Default align and baseline when has textPosition\n            textAlign = textAlign || res.textAlign;\n            textVerticalAlign = textVerticalAlign || res.textVerticalAlign;\n        }\n\n        // textOffset is only support in RectText, otherwise\n        // we have to adjust boundingRect for textOffset.\n        var textOffset = style.textOffset;\n        if (textOffset) {\n            baseX += textOffset[0];\n            baseY += textOffset[1];\n        }\n    }\n\n    return {\n        baseX: baseX,\n        baseY: baseY,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\nfunction setCtx(ctx, prop, value) {\n    ctx[prop] = fixShadow(ctx, prop, value);\n    return ctx[prop];\n}\n\n/**\n * @param {string} [stroke] If specified, do not check style.textStroke.\n * @param {string} [lineWidth] If specified, do not check style.textStroke.\n * @param {number} style\n */\nfunction getStroke(stroke, lineWidth) {\n    return (stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none')\n        ? null\n        // TODO pattern and gradient?\n        : (stroke.image || stroke.colorStops)\n        ? '#000'\n        : stroke;\n}\n\nfunction getFill(fill) {\n    return (fill == null || fill === 'none')\n        ? null\n        // TODO pattern and gradient?\n        : (fill.image || fill.colorStops)\n        ? '#000'\n        : fill;\n}\n\nfunction parsePercent(value, maxValue) {\n    if (typeof value === 'string') {\n        if (value.lastIndexOf('%') >= 0) {\n            return parseFloat(value) / 100 * maxValue;\n        }\n        return parseFloat(value);\n    }\n    return value;\n}\n\nfunction getTextXForPadding(x, textAlign, textPadding) {\n    return textAlign === 'right'\n        ? (x - textPadding[1])\n        : textAlign === 'center'\n        ? (x + textPadding[3] / 2 - textPadding[1] / 2)\n        : (x + textPadding[3]);\n}\n\n/**\n * @param {string} text\n * @param {module:zrender/Style} style\n * @return {boolean}\n */\nfunction needDrawText(text, style) {\n    return text != null\n        && (text\n            || style.textBackgroundColor\n            || (style.textBorderWidth && style.textBorderColor)\n            || style.textPadding\n        );\n}\n\n/**\n * Mixin for drawing text in a element bounding rect\n * @module zrender/mixin/RectText\n */\n\nvar tmpRect$1 = new BoundingRect();\n\nvar RectText = function () {};\n\nRectText.prototype = {\n\n    constructor: RectText,\n\n    /**\n     * Draw text in a rect with specified position.\n     * @param  {CanvasRenderingContext2D} ctx\n     * @param  {Object} rect Displayable rect\n     */\n    drawRectText: function (ctx, rect) {\n        var style = this.style;\n\n        rect = style.textRect || rect;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        var text = style.text;\n\n        // Convert to string\n        text != null && (text += '');\n\n        if (!needDrawText(text, style)) {\n            return;\n        }\n\n        // FIXME\n        // Do not provide prevEl to `textHelper.renderText` for ctx prop cache,\n        // but use `ctx.save()` and `ctx.restore()`. Because the cache for rect\n        // text propably break the cache for its host elements.\n        ctx.save();\n\n        // Transform rect to view space\n        var transform = this.transform;\n        if (!style.transformText) {\n            if (transform) {\n                tmpRect$1.copy(rect);\n                tmpRect$1.applyTransform(transform);\n                rect = tmpRect$1;\n            }\n        }\n        else {\n            this.setTransform(ctx);\n        }\n\n        // transformText and textRotation can not be used at the same time.\n        renderText(this, ctx, text, style, rect, WILL_BE_RESTORED);\n\n        ctx.restore();\n    }\n};\n\n/**\n * 可绘制的图形基类\n * Base class of all displayable graphic objects\n * @module zrender/graphic/Displayable\n */\n\n\n/**\n * @alias module:zrender/graphic/Displayable\n * @extends module:zrender/Element\n * @extends module:zrender/graphic/mixin/RectText\n */\nfunction Displayable(opts) {\n\n    opts = opts || {};\n\n    Element.call(this, opts);\n\n    // Extend properties\n    for (var name in opts) {\n        if (\n            opts.hasOwnProperty(name)\n                && name !== 'style'\n        ) {\n            this[name] = opts[name];\n        }\n    }\n\n    /**\n     * @type {module:zrender/graphic/Style}\n     */\n    this.style = new Style(opts.style, this);\n\n    this._rect = null;\n    // Shapes for cascade clipping.\n    this.__clipPaths = [];\n\n    // FIXME Stateful must be mixined after style is setted\n    // Stateful.call(this, opts);\n}\n\nDisplayable.prototype = {\n\n    constructor: Displayable,\n\n    type: 'displayable',\n\n    /**\n     * Displayable 是否为脏，Painter 中会根据该标记判断是否需要是否需要重新绘制\n     * Dirty flag. From which painter will determine if this displayable object needs brush\n     * @name module:zrender/graphic/Displayable#__dirty\n     * @type {boolean}\n     */\n    __dirty: true,\n\n    /**\n     * 图形是否可见，为true时不绘制图形，但是仍能触发鼠标事件\n     * If ignore drawing of the displayable object. Mouse event will still be triggered\n     * @name module:/zrender/graphic/Displayable#invisible\n     * @type {boolean}\n     * @default false\n     */\n    invisible: false,\n\n    /**\n     * @name module:/zrender/graphic/Displayable#z\n     * @type {number}\n     * @default 0\n     */\n    z: 0,\n\n    /**\n     * @name module:/zrender/graphic/Displayable#z\n     * @type {number}\n     * @default 0\n     */\n    z2: 0,\n\n    /**\n     * z层level，决定绘画在哪层canvas中\n     * @name module:/zrender/graphic/Displayable#zlevel\n     * @type {number}\n     * @default 0\n     */\n    zlevel: 0,\n\n    /**\n     * 是否可拖拽\n     * @name module:/zrender/graphic/Displayable#draggable\n     * @type {boolean}\n     * @default false\n     */\n    draggable: false,\n\n    /**\n     * 是否正在拖拽\n     * @name module:/zrender/graphic/Displayable#draggable\n     * @type {boolean}\n     * @default false\n     */\n    dragging: false,\n\n    /**\n     * 是否相应鼠标事件\n     * @name module:/zrender/graphic/Displayable#silent\n     * @type {boolean}\n     * @default false\n     */\n    silent: false,\n\n    /**\n     * If enable culling\n     * @type {boolean}\n     * @default false\n     */\n    culling: false,\n\n    /**\n     * Mouse cursor when hovered\n     * @name module:/zrender/graphic/Displayable#cursor\n     * @type {string}\n     */\n    cursor: 'pointer',\n\n    /**\n     * If hover area is bounding rect\n     * @name module:/zrender/graphic/Displayable#rectHover\n     * @type {string}\n     */\n    rectHover: false,\n\n    /**\n     * Render the element progressively when the value >= 0,\n     * usefull for large data.\n     * @type {boolean}\n     */\n    progressive: false,\n\n    /**\n     * @type {boolean}\n     */\n    incremental: false,\n    /**\n     * Scale ratio for global scale.\n     * @type {boolean}\n     */\n    globalScaleRatio: 1,\n\n    beforeBrush: function (ctx) {},\n\n    afterBrush: function (ctx) {},\n\n    /**\n     * 图形绘制方法\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    // Interface\n    brush: function (ctx, prevEl) {},\n\n    /**\n     * 获取最小包围盒\n     * @return {module:zrender/core/BoundingRect}\n     */\n    // Interface\n    getBoundingRect: function () {},\n\n    /**\n     * 判断坐标 x, y 是否在图形上\n     * If displayable element contain coord x, y\n     * @param  {number} x\n     * @param  {number} y\n     * @return {boolean}\n     */\n    contain: function (x, y) {\n        return this.rectContain(x, y);\n    },\n\n    /**\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {\n        cb.call(context, this);\n    },\n\n    /**\n     * 判断坐标 x, y 是否在图形的包围盒上\n     * If bounding rect of element contain coord x, y\n     * @param  {number} x\n     * @param  {number} y\n     * @return {boolean}\n     */\n    rectContain: function (x, y) {\n        var coord = this.transformCoordToLocal(x, y);\n        var rect = this.getBoundingRect();\n        return rect.contain(coord[0], coord[1]);\n    },\n\n    /**\n     * 标记图形元素为脏，并且在下一帧重绘\n     * Mark displayable element dirty and refresh next frame\n     */\n    dirty: function () {\n        this.__dirty = this.__dirtyText = true;\n\n        this._rect = null;\n\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * 图形是否会触发事件\n     * If displayable object binded any event\n     * @return {boolean}\n     */\n    // TODO, 通过 bind 绑定的事件\n    // isSilent: function () {\n    //     return !(\n    //         this.hoverable || this.draggable\n    //         || this.onmousemove || this.onmouseover || this.onmouseout\n    //         || this.onmousedown || this.onmouseup || this.onclick\n    //         || this.ondragenter || this.ondragover || this.ondragleave\n    //         || this.ondrop\n    //     );\n    // },\n    /**\n     * Alias for animate('style')\n     * @param {boolean} loop\n     */\n    animateStyle: function (loop) {\n        return this.animate('style', loop);\n    },\n\n    attrKV: function (key, value) {\n        if (key !== 'style') {\n            Element.prototype.attrKV.call(this, key, value);\n        }\n        else {\n            this.style.set(value);\n        }\n    },\n\n    /**\n     * @param {Object|string} key\n     * @param {*} value\n     */\n    setStyle: function (key, value) {\n        this.style.set(key, value);\n        this.dirty(false);\n        return this;\n    },\n\n    /**\n     * Use given style object\n     * @param  {Object} obj\n     */\n    useStyle: function (obj) {\n        this.style = new Style(obj, this);\n        this.dirty(false);\n        return this;\n    }\n};\n\ninherits(Displayable, Element);\n\nmixin(Displayable, RectText);\n\n/**\n * @alias zrender/graphic/Image\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nfunction ZImage(opts) {\n    Displayable.call(this, opts);\n}\n\nZImage.prototype = {\n\n    constructor: ZImage,\n\n    type: 'image',\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n        var src = style.image;\n\n        // Must bind each time\n        style.bind(ctx, this, prevEl);\n\n        var image = this._image = createOrUpdateImage(\n            src,\n            this._image,\n            this,\n            this.onload\n        );\n\n        if (!image || !isImageReady(image)) {\n            return;\n        }\n\n        // 图片已经加载完成\n        // if (image.nodeName.toUpperCase() == 'IMG') {\n        //     if (!image.complete) {\n        //         return;\n        //     }\n        // }\n        // Else is canvas\n\n        var x = style.x || 0;\n        var y = style.y || 0;\n        var width = style.width;\n        var height = style.height;\n        var aspect = image.width / image.height;\n        if (width == null && height != null) {\n            // Keep image/height ratio\n            width = height * aspect;\n        }\n        else if (height == null && width != null) {\n            height = width / aspect;\n        }\n        else if (width == null && height == null) {\n            width = image.width;\n            height = image.height;\n        }\n\n        // 设置transform\n        this.setTransform(ctx);\n\n        if (style.sWidth && style.sHeight) {\n            var sx = style.sx || 0;\n            var sy = style.sy || 0;\n            ctx.drawImage(\n                image,\n                sx, sy, style.sWidth, style.sHeight,\n                x, y, width, height\n            );\n        }\n        else if (style.sx && style.sy) {\n            var sx = style.sx;\n            var sy = style.sy;\n            var sWidth = width - sx;\n            var sHeight = height - sy;\n            ctx.drawImage(\n                image,\n                sx, sy, sWidth, sHeight,\n                x, y, width, height\n            );\n        }\n        else {\n            ctx.drawImage(image, x, y, width, height);\n        }\n\n        // Draw rect text\n        if (style.text != null) {\n            // Only restore transform when needs draw text.\n            this.restoreTransform(ctx);\n            this.drawRectText(ctx, this.getBoundingRect());\n        }\n    },\n\n    getBoundingRect: function () {\n        var style = this.style;\n        if (!this._rect) {\n            this._rect = new BoundingRect(\n                style.x || 0, style.y || 0, style.width || 0, style.height || 0\n            );\n        }\n        return this._rect;\n    }\n};\n\ninherits(ZImage, Displayable);\n\nvar HOVER_LAYER_ZLEVEL = 1e5;\nvar CANVAS_ZLEVEL = 314159;\n\nvar EL_AFTER_INCREMENTAL_INC = 0.01;\nvar INCREMENTAL_INC = 0.001;\n\nfunction parseInt10(val) {\n    return parseInt(val, 10);\n}\n\nfunction isLayerValid(layer) {\n    if (!layer) {\n        return false;\n    }\n\n    if (layer.__builtin__) {\n        return true;\n    }\n\n    if (typeof (layer.resize) !== 'function'\n        || typeof (layer.refresh) !== 'function'\n    ) {\n        return false;\n    }\n\n    return true;\n}\n\nvar tmpRect = new BoundingRect(0, 0, 0, 0);\nvar viewRect = new BoundingRect(0, 0, 0, 0);\nfunction isDisplayableCulled(el, width, height) {\n    tmpRect.copy(el.getBoundingRect());\n    if (el.transform) {\n        tmpRect.applyTransform(el.transform);\n    }\n    viewRect.width = width;\n    viewRect.height = height;\n    return !tmpRect.intersect(viewRect);\n}\n\nfunction isClipPathChanged(clipPaths, prevClipPaths) {\n    if (clipPaths === prevClipPaths) { // Can both be null or undefined\n        return false;\n    }\n\n    if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) {\n        return true;\n    }\n    for (var i = 0; i < clipPaths.length; i++) {\n        if (clipPaths[i] !== prevClipPaths[i]) {\n            return true;\n        }\n    }\n}\n\nfunction doClip(clipPaths, ctx) {\n    for (var i = 0; i < clipPaths.length; i++) {\n        var clipPath = clipPaths[i];\n\n        clipPath.setTransform(ctx);\n        ctx.beginPath();\n        clipPath.buildPath(ctx, clipPath.shape);\n        ctx.clip();\n        // Transform back\n        clipPath.restoreTransform(ctx);\n    }\n}\n\nfunction createRoot(width, height) {\n    var domRoot = document.createElement('div');\n\n    // domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬\n    domRoot.style.cssText = [\n        'position:relative',\n        'overflow:hidden',\n        'width:' + width + 'px',\n        'height:' + height + 'px',\n        'padding:0',\n        'margin:0',\n        'border-width:0'\n    ].join(';') + ';';\n\n    return domRoot;\n}\n\n\n/**\n * @alias module:zrender/Painter\n * @constructor\n * @param {HTMLElement} root 绘图容器\n * @param {module:zrender/Storage} storage\n * @param {Object} opts\n */\nvar Painter = function (root, storage, opts) {\n\n    this.type = 'canvas';\n\n    // In node environment using node-canvas\n    var singleCanvas = !root.nodeName // In node ?\n        || root.nodeName.toUpperCase() === 'CANVAS';\n\n    this._opts = opts = extend({}, opts || {});\n\n    /**\n     * @type {number}\n     */\n    this.dpr = opts.devicePixelRatio || devicePixelRatio;\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._singleCanvas = singleCanvas;\n    /**\n     * 绘图容器\n     * @type {HTMLElement}\n     */\n    this.root = root;\n\n    var rootStyle = root.style;\n\n    if (rootStyle) {\n        rootStyle['-webkit-tap-highlight-color'] = 'transparent';\n        rootStyle['-webkit-user-select'] =\n        rootStyle['user-select'] =\n        rootStyle['-webkit-touch-callout'] = 'none';\n\n        root.innerHTML = '';\n    }\n\n    /**\n     * @type {module:zrender/Storage}\n     */\n    this.storage = storage;\n\n    /**\n     * @type {Array.<number>}\n     * @private\n     */\n    var zlevelList = this._zlevelList = [];\n\n    /**\n     * @type {Object.<string, module:zrender/Layer>}\n     * @private\n     */\n    var layers = this._layers = {};\n\n    /**\n     * @type {Object.<string, Object>}\n     * @private\n     */\n    this._layerConfig = {};\n\n    /**\n     * zrender will do compositing when root is a canvas and have multiple zlevels.\n     */\n    this._needsManuallyCompositing = false;\n\n    if (!singleCanvas) {\n        this._width = this._getSize(0);\n        this._height = this._getSize(1);\n\n        var domRoot = this._domRoot = createRoot(\n            this._width, this._height\n        );\n        root.appendChild(domRoot);\n    }\n    else {\n        var width = root.width;\n        var height = root.height;\n\n        if (opts.width != null) {\n            width = opts.width;\n        }\n        if (opts.height != null) {\n            height = opts.height;\n        }\n        this.dpr = opts.devicePixelRatio || 1;\n\n        // Use canvas width and height directly\n        root.width = width * this.dpr;\n        root.height = height * this.dpr;\n\n        this._width = width;\n        this._height = height;\n\n        // Create layer if only one given canvas\n        // Device can be specified to create a high dpi image.\n        var mainLayer = new Layer(root, this, this.dpr);\n        mainLayer.__builtin__ = true;\n        mainLayer.initContext();\n        // FIXME Use canvas width and height\n        // mainLayer.resize(width, height);\n        layers[CANVAS_ZLEVEL] = mainLayer;\n        mainLayer.zlevel = CANVAS_ZLEVEL;\n        // Not use common zlevel.\n        zlevelList.push(CANVAS_ZLEVEL);\n\n        this._domRoot = root;\n    }\n\n    /**\n     * @type {module:zrender/Layer}\n     * @private\n     */\n    this._hoverlayer = null;\n\n    this._hoverElements = [];\n};\n\nPainter.prototype = {\n\n    constructor: Painter,\n\n    getType: function () {\n        return 'canvas';\n    },\n\n    /**\n     * If painter use a single canvas\n     * @return {boolean}\n     */\n    isSingleCanvas: function () {\n        return this._singleCanvas;\n    },\n    /**\n     * @return {HTMLDivElement}\n     */\n    getViewportRoot: function () {\n        return this._domRoot;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    /**\n     * 刷新\n     * @param {boolean} [paintAll=false] 强制绘制所有displayable\n     */\n    refresh: function (paintAll) {\n\n        var list = this.storage.getDisplayList(true);\n\n        var zlevelList = this._zlevelList;\n\n        this._redrawId = Math.random();\n\n        this._paintList(list, paintAll, this._redrawId);\n\n        // Paint custum layers\n        for (var i = 0; i < zlevelList.length; i++) {\n            var z = zlevelList[i];\n            var layer = this._layers[z];\n            if (!layer.__builtin__ && layer.refresh) {\n                var clearColor = i === 0 ? this._backgroundColor : null;\n                layer.refresh(clearColor);\n            }\n        }\n\n        this.refreshHover();\n\n        return this;\n    },\n\n    addHover: function (el, hoverStyle) {\n        if (el.__hoverMir) {\n            return;\n        }\n        var elMirror = new el.constructor({\n            style: el.style,\n            shape: el.shape,\n            z: el.z,\n            z2: el.z2,\n            silent: el.silent\n        });\n        elMirror.__from = el;\n        el.__hoverMir = elMirror;\n        hoverStyle && elMirror.setStyle(hoverStyle);\n        this._hoverElements.push(elMirror);\n\n        return elMirror;\n    },\n\n    removeHover: function (el) {\n        var elMirror = el.__hoverMir;\n        var hoverElements = this._hoverElements;\n        var idx = indexOf(hoverElements, elMirror);\n        if (idx >= 0) {\n            hoverElements.splice(idx, 1);\n        }\n        el.__hoverMir = null;\n    },\n\n    clearHover: function (el) {\n        var hoverElements = this._hoverElements;\n        for (var i = 0; i < hoverElements.length; i++) {\n            var from = hoverElements[i].__from;\n            if (from) {\n                from.__hoverMir = null;\n            }\n        }\n        hoverElements.length = 0;\n    },\n\n    refreshHover: function () {\n        var hoverElements = this._hoverElements;\n        var len = hoverElements.length;\n        var hoverLayer = this._hoverlayer;\n        hoverLayer && hoverLayer.clear();\n\n        if (!len) {\n            return;\n        }\n        sort(hoverElements, this.storage.displayableSortFunc);\n\n        // Use a extream large zlevel\n        // FIXME?\n        if (!hoverLayer) {\n            hoverLayer = this._hoverlayer = this.getLayer(HOVER_LAYER_ZLEVEL);\n        }\n\n        var scope = {};\n        hoverLayer.ctx.save();\n        for (var i = 0; i < len;) {\n            var el = hoverElements[i];\n            var originalEl = el.__from;\n            // Original el is removed\n            // PENDING\n            if (!(originalEl && originalEl.__zr)) {\n                hoverElements.splice(i, 1);\n                originalEl.__hoverMir = null;\n                len--;\n                continue;\n            }\n            i++;\n\n            // Use transform\n            // FIXME style and shape ?\n            if (!originalEl.invisible) {\n                el.transform = originalEl.transform;\n                el.invTransform = originalEl.invTransform;\n                el.__clipPaths = originalEl.__clipPaths;\n                // el.\n                this._doPaintEl(el, hoverLayer, true, scope);\n            }\n        }\n\n        hoverLayer.ctx.restore();\n    },\n\n    getHoverLayer: function () {\n        return this.getLayer(HOVER_LAYER_ZLEVEL);\n    },\n\n    _paintList: function (list, paintAll, redrawId) {\n        if (this._redrawId !== redrawId) {\n            return;\n        }\n\n        paintAll = paintAll || false;\n\n        this._updateLayerStatus(list);\n\n        var finished = this._doPaintList(list, paintAll);\n\n        if (this._needsManuallyCompositing) {\n            this._compositeManually();\n        }\n\n        if (!finished) {\n            var self = this;\n            requestAnimationFrame(function () {\n                self._paintList(list, paintAll, redrawId);\n            });\n        }\n    },\n\n    _compositeManually: function () {\n        var ctx = this.getLayer(CANVAS_ZLEVEL).ctx;\n        var width = this._domRoot.width;\n        var height = this._domRoot.height;\n        ctx.clearRect(0, 0, width, height);\n        // PENDING, If only builtin layer?\n        this.eachBuiltinLayer(function (layer) {\n            if (layer.virtual) {\n                ctx.drawImage(layer.dom, 0, 0, width, height);\n            }\n        });\n    },\n\n    _doPaintList: function (list, paintAll) {\n        var layerList = [];\n        for (var zi = 0; zi < this._zlevelList.length; zi++) {\n            var zlevel = this._zlevelList[zi];\n            var layer = this._layers[zlevel];\n            if (layer.__builtin__\n                && layer !== this._hoverlayer\n                && (layer.__dirty || paintAll)\n            ) {\n                layerList.push(layer);\n            }\n        }\n\n        var finished = true;\n\n        for (var k = 0; k < layerList.length; k++) {\n            var layer = layerList[k];\n            var ctx = layer.ctx;\n            var scope = {};\n            ctx.save();\n\n            var start = paintAll ? layer.__startIndex : layer.__drawIndex;\n\n            var useTimer = !paintAll && layer.incremental && Date.now;\n            var startTime = useTimer && Date.now();\n\n            var clearColor = layer.zlevel === this._zlevelList[0]\n                ? this._backgroundColor : null;\n            // All elements in this layer are cleared.\n            if (layer.__startIndex === layer.__endIndex) {\n                layer.clear(false, clearColor);\n            }\n            else if (start === layer.__startIndex) {\n                var firstEl = list[start];\n                if (!firstEl.incremental || !firstEl.notClear || paintAll) {\n                    layer.clear(false, clearColor);\n                }\n            }\n            if (start === -1) {\n                console.error('For some unknown reason. drawIndex is -1');\n                start = layer.__startIndex;\n            }\n            for (var i = start; i < layer.__endIndex; i++) {\n                var el = list[i];\n                this._doPaintEl(el, layer, paintAll, scope);\n                el.__dirty = el.__dirtyText = false;\n\n                if (useTimer) {\n                    // Date.now can be executed in 13,025,305 ops/second.\n                    var dTime = Date.now() - startTime;\n                    // Give 15 millisecond to draw.\n                    // The rest elements will be drawn in the next frame.\n                    if (dTime > 15) {\n                        break;\n                    }\n                }\n            }\n\n            layer.__drawIndex = i;\n\n            if (layer.__drawIndex < layer.__endIndex) {\n                finished = false;\n            }\n\n            if (scope.prevElClipPaths) {\n                // Needs restore the state. If last drawn element is in the clipping area.\n                ctx.restore();\n            }\n\n            ctx.restore();\n        }\n\n        if (env$1.wxa) {\n            // Flush for weixin application\n            each$1(this._layers, function (layer) {\n                if (layer && layer.ctx && layer.ctx.draw) {\n                    layer.ctx.draw();\n                }\n            });\n        }\n\n        return finished;\n    },\n\n    _doPaintEl: function (el, currentLayer, forcePaint, scope) {\n        var ctx = currentLayer.ctx;\n        var m = el.transform;\n        if (\n            (currentLayer.__dirty || forcePaint)\n            // Ignore invisible element\n            && !el.invisible\n            // Ignore transparent element\n            && el.style.opacity !== 0\n            // Ignore scale 0 element, in some environment like node-canvas\n            // Draw a scale 0 element can cause all following draw wrong\n            // And setTransform with scale 0 will cause set back transform failed.\n            && !(m && !m[0] && !m[3])\n            // Ignore culled element\n            && !(el.culling && isDisplayableCulled(el, this._width, this._height))\n        ) {\n\n            var clipPaths = el.__clipPaths;\n\n            // Optimize when clipping on group with several elements\n            if (!scope.prevElClipPaths\n                || isClipPathChanged(clipPaths, scope.prevElClipPaths)\n            ) {\n                // If has previous clipping state, restore from it\n                if (scope.prevElClipPaths) {\n                    currentLayer.ctx.restore();\n                    scope.prevElClipPaths = null;\n\n                    // Reset prevEl since context has been restored\n                    scope.prevEl = null;\n                }\n                // New clipping state\n                if (clipPaths) {\n                    ctx.save();\n                    doClip(clipPaths, ctx);\n                    scope.prevElClipPaths = clipPaths;\n                }\n            }\n            el.beforeBrush && el.beforeBrush(ctx);\n\n            el.brush(ctx, scope.prevEl || null);\n            scope.prevEl = el;\n\n            el.afterBrush && el.afterBrush(ctx);\n        }\n    },\n\n    /**\n     * 获取 zlevel 所在层，如果不存在则会创建一个新的层\n     * @param {number} zlevel\n     * @param {boolean} virtual Virtual layer will not be inserted into dom.\n     * @return {module:zrender/Layer}\n     */\n    getLayer: function (zlevel, virtual) {\n        if (this._singleCanvas && !this._needsManuallyCompositing) {\n            zlevel = CANVAS_ZLEVEL;\n        }\n        var layer = this._layers[zlevel];\n        if (!layer) {\n            // Create a new layer\n            layer = new Layer('zr_' + zlevel, this, this.dpr);\n            layer.zlevel = zlevel;\n            layer.__builtin__ = true;\n\n            if (this._layerConfig[zlevel]) {\n                merge(layer, this._layerConfig[zlevel], true);\n            }\n\n            if (virtual) {\n                layer.virtual = virtual;\n            }\n\n            this.insertLayer(zlevel, layer);\n\n            // Context is created after dom inserted to document\n            // Or excanvas will get 0px clientWidth and clientHeight\n            layer.initContext();\n        }\n\n        return layer;\n    },\n\n    insertLayer: function (zlevel, layer) {\n\n        var layersMap = this._layers;\n        var zlevelList = this._zlevelList;\n        var len = zlevelList.length;\n        var prevLayer = null;\n        var i = -1;\n        var domRoot = this._domRoot;\n\n        if (layersMap[zlevel]) {\n            log$1('ZLevel ' + zlevel + ' has been used already');\n            return;\n        }\n        // Check if is a valid layer\n        if (!isLayerValid(layer)) {\n            log$1('Layer of zlevel ' + zlevel + ' is not valid');\n            return;\n        }\n\n        if (len > 0 && zlevel > zlevelList[0]) {\n            for (i = 0; i < len - 1; i++) {\n                if (\n                    zlevelList[i] < zlevel\n                    && zlevelList[i + 1] > zlevel\n                ) {\n                    break;\n                }\n            }\n            prevLayer = layersMap[zlevelList[i]];\n        }\n        zlevelList.splice(i + 1, 0, zlevel);\n\n        layersMap[zlevel] = layer;\n\n        // Vitual layer will not directly show on the screen.\n        // (It can be a WebGL layer and assigned to a ZImage element)\n        // But it still under management of zrender.\n        if (!layer.virtual) {\n            if (prevLayer) {\n                var prevDom = prevLayer.dom;\n                if (prevDom.nextSibling) {\n                    domRoot.insertBefore(\n                        layer.dom,\n                        prevDom.nextSibling\n                    );\n                }\n                else {\n                    domRoot.appendChild(layer.dom);\n                }\n            }\n            else {\n                if (domRoot.firstChild) {\n                    domRoot.insertBefore(layer.dom, domRoot.firstChild);\n                }\n                else {\n                    domRoot.appendChild(layer.dom);\n                }\n            }\n        }\n    },\n\n    // Iterate each layer\n    eachLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            cb.call(context, this._layers[z], z);\n        }\n    },\n\n    // Iterate each buildin layer\n    eachBuiltinLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var layer;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            layer = this._layers[z];\n            if (layer.__builtin__) {\n                cb.call(context, layer, z);\n            }\n        }\n    },\n\n    // Iterate each other layer except buildin layer\n    eachOtherLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var layer;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            layer = this._layers[z];\n            if (!layer.__builtin__) {\n                cb.call(context, layer, z);\n            }\n        }\n    },\n\n    /**\n     * 获取所有已创建的层\n     * @param {Array.<module:zrender/Layer>} [prevLayer]\n     */\n    getLayers: function () {\n        return this._layers;\n    },\n\n    _updateLayerStatus: function (list) {\n\n        this.eachBuiltinLayer(function (layer, z) {\n            layer.__dirty = layer.__used = false;\n        });\n\n        function updatePrevLayer(idx) {\n            if (prevLayer) {\n                if (prevLayer.__endIndex !== idx) {\n                    prevLayer.__dirty = true;\n                }\n                prevLayer.__endIndex = idx;\n            }\n        }\n\n        if (this._singleCanvas) {\n            for (var i = 1; i < list.length; i++) {\n                var el = list[i];\n                if (el.zlevel !== list[i - 1].zlevel || el.incremental) {\n                    this._needsManuallyCompositing = true;\n                    break;\n                }\n            }\n        }\n\n        var prevLayer = null;\n        var incrementalLayerCount = 0;\n        for (var i = 0; i < list.length; i++) {\n            var el = list[i];\n            var zlevel = el.zlevel;\n            var layer;\n            // PENDING If change one incremental element style ?\n            // TODO Where there are non-incremental elements between incremental elements.\n            if (el.incremental) {\n                layer = this.getLayer(zlevel + INCREMENTAL_INC, this._needsManuallyCompositing);\n                layer.incremental = true;\n                incrementalLayerCount = 1;\n            }\n            else {\n                layer = this.getLayer(zlevel + (incrementalLayerCount > 0 ? EL_AFTER_INCREMENTAL_INC : 0), this._needsManuallyCompositing);\n            }\n\n            if (!layer.__builtin__) {\n                log$1('ZLevel ' + zlevel + ' has been used by unkown layer ' + layer.id);\n            }\n\n            if (layer !== prevLayer) {\n                layer.__used = true;\n                if (layer.__startIndex !== i) {\n                    layer.__dirty = true;\n                }\n                layer.__startIndex = i;\n                if (!layer.incremental) {\n                    layer.__drawIndex = i;\n                }\n                else {\n                    // Mark layer draw index needs to update.\n                    layer.__drawIndex = -1;\n                }\n                updatePrevLayer(i);\n                prevLayer = layer;\n            }\n            if (el.__dirty) {\n                layer.__dirty = true;\n                if (layer.incremental && layer.__drawIndex < 0) {\n                    // Start draw from the first dirty element.\n                    layer.__drawIndex = i;\n                }\n            }\n        }\n\n        updatePrevLayer(i);\n\n        this.eachBuiltinLayer(function (layer, z) {\n            // Used in last frame but not in this frame. Needs clear\n            if (!layer.__used && layer.getElementCount() > 0) {\n                layer.__dirty = true;\n                layer.__startIndex = layer.__endIndex = layer.__drawIndex = 0;\n            }\n            // For incremental layer. In case start index changed and no elements are dirty.\n            if (layer.__dirty && layer.__drawIndex < 0) {\n                layer.__drawIndex = layer.__startIndex;\n            }\n        });\n    },\n\n    /**\n     * 清除hover层外所有内容\n     */\n    clear: function () {\n        this.eachBuiltinLayer(this._clearLayer);\n        return this;\n    },\n\n    _clearLayer: function (layer) {\n        layer.clear();\n    },\n\n    setBackgroundColor: function (backgroundColor) {\n        this._backgroundColor = backgroundColor;\n    },\n\n    /**\n     * 修改指定zlevel的绘制参数\n     *\n     * @param {string} zlevel\n     * @param {Object} config 配置对象\n     * @param {string} [config.clearColor=0] 每次清空画布的颜色\n     * @param {string} [config.motionBlur=false] 是否开启动态模糊\n     * @param {number} [config.lastFrameAlpha=0.7]\n     *                 在开启动态模糊的时候使用，与上一帧混合的alpha值，值越大尾迹越明显\n     */\n    configLayer: function (zlevel, config) {\n        if (config) {\n            var layerConfig = this._layerConfig;\n            if (!layerConfig[zlevel]) {\n                layerConfig[zlevel] = config;\n            }\n            else {\n                merge(layerConfig[zlevel], config, true);\n            }\n\n            for (var i = 0; i < this._zlevelList.length; i++) {\n                var _zlevel = this._zlevelList[i];\n                if (_zlevel === zlevel || _zlevel === zlevel + EL_AFTER_INCREMENTAL_INC) {\n                    var layer = this._layers[_zlevel];\n                    merge(layer, layerConfig[zlevel], true);\n                }\n            }\n        }\n    },\n\n    /**\n     * 删除指定层\n     * @param {number} zlevel 层所在的zlevel\n     */\n    delLayer: function (zlevel) {\n        var layers = this._layers;\n        var zlevelList = this._zlevelList;\n        var layer = layers[zlevel];\n        if (!layer) {\n            return;\n        }\n        layer.dom.parentNode.removeChild(layer.dom);\n        delete layers[zlevel];\n\n        zlevelList.splice(indexOf(zlevelList, zlevel), 1);\n    },\n\n    /**\n     * 区域大小变化后重绘\n     */\n    resize: function (width, height) {\n        if (!this._domRoot.style) { // Maybe in node or worker\n            if (width == null || height == null) {\n                return;\n            }\n            this._width = width;\n            this._height = height;\n\n            this.getLayer(CANVAS_ZLEVEL).resize(width, height);\n        }\n        else {\n            var domRoot = this._domRoot;\n            // FIXME Why ?\n            domRoot.style.display = 'none';\n\n            // Save input w/h\n            var opts = this._opts;\n            width != null && (opts.width = width);\n            height != null && (opts.height = height);\n\n            width = this._getSize(0);\n            height = this._getSize(1);\n\n            domRoot.style.display = '';\n\n            // 优化没有实际改变的resize\n            if (this._width !== width || height !== this._height) {\n                domRoot.style.width = width + 'px';\n                domRoot.style.height = height + 'px';\n\n                for (var id in this._layers) {\n                    if (this._layers.hasOwnProperty(id)) {\n                        this._layers[id].resize(width, height);\n                    }\n                }\n                each$1(this._progressiveLayers, function (layer) {\n                    layer.resize(width, height);\n                });\n\n                this.refresh(true);\n            }\n\n            this._width = width;\n            this._height = height;\n\n        }\n        return this;\n    },\n\n    /**\n     * 清除单独的一个层\n     * @param {number} zlevel\n     */\n    clearLayer: function (zlevel) {\n        var layer = this._layers[zlevel];\n        if (layer) {\n            layer.clear();\n        }\n    },\n\n    /**\n     * 释放\n     */\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this.root =\n        this.storage =\n\n        this._domRoot =\n        this._layers = null;\n    },\n\n    /**\n     * Get canvas which has all thing rendered\n     * @param {Object} opts\n     * @param {string} [opts.backgroundColor]\n     * @param {number} [opts.pixelRatio]\n     */\n    getRenderedCanvas: function (opts) {\n        opts = opts || {};\n        if (this._singleCanvas && !this._compositeManually) {\n            return this._layers[CANVAS_ZLEVEL].dom;\n        }\n\n        var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr);\n        imageLayer.initContext();\n        imageLayer.clear(false, opts.backgroundColor || this._backgroundColor);\n\n        if (opts.pixelRatio <= this.dpr) {\n            this.refresh();\n\n            var width = imageLayer.dom.width;\n            var height = imageLayer.dom.height;\n            var ctx = imageLayer.ctx;\n            this.eachLayer(function (layer) {\n                if (layer.__builtin__) {\n                    ctx.drawImage(layer.dom, 0, 0, width, height);\n                }\n                else if (layer.renderToCanvas) {\n                    imageLayer.ctx.save();\n                    layer.renderToCanvas(imageLayer.ctx);\n                    imageLayer.ctx.restore();\n                }\n            });\n        }\n        else {\n            // PENDING, echarts-gl and incremental rendering.\n            var scope = {};\n            var displayList = this.storage.getDisplayList(true);\n            for (var i = 0; i < displayList.length; i++) {\n                var el = displayList[i];\n                this._doPaintEl(el, imageLayer, true, scope);\n            }\n        }\n\n        return imageLayer.dom;\n    },\n    /**\n     * 获取绘图区域宽度\n     */\n    getWidth: function () {\n        return this._width;\n    },\n\n    /**\n     * 获取绘图区域高度\n     */\n    getHeight: function () {\n        return this._height;\n    },\n\n    _getSize: function (whIdx) {\n        var opts = this._opts;\n        var wh = ['width', 'height'][whIdx];\n        var cwh = ['clientWidth', 'clientHeight'][whIdx];\n        var plt = ['paddingLeft', 'paddingTop'][whIdx];\n        var prb = ['paddingRight', 'paddingBottom'][whIdx];\n\n        if (opts[wh] != null && opts[wh] !== 'auto') {\n            return parseFloat(opts[wh]);\n        }\n\n        var root = this.root;\n        // IE8 does not support getComputedStyle, but it use VML.\n        var stl = document.defaultView.getComputedStyle(root);\n\n        return (\n            (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh]))\n            - (parseInt10(stl[plt]) || 0)\n            - (parseInt10(stl[prb]) || 0)\n        ) | 0;\n    },\n\n    pathToImage: function (path, dpr) {\n        dpr = dpr || this.dpr;\n\n        var canvas = document.createElement('canvas');\n        var ctx = canvas.getContext('2d');\n        var rect = path.getBoundingRect();\n        var style = path.style;\n        var shadowBlurSize = style.shadowBlur * dpr;\n        var shadowOffsetX = style.shadowOffsetX * dpr;\n        var shadowOffsetY = style.shadowOffsetY * dpr;\n        var lineWidth = style.hasStroke() ? style.lineWidth : 0;\n\n        var leftMargin = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize);\n        var rightMargin = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize);\n        var topMargin = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize);\n        var bottomMargin = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize);\n        var width = rect.width + leftMargin + rightMargin;\n        var height = rect.height + topMargin + bottomMargin;\n\n        canvas.width = width * dpr;\n        canvas.height = height * dpr;\n\n        ctx.scale(dpr, dpr);\n        ctx.clearRect(0, 0, width, height);\n        ctx.dpr = dpr;\n\n        var pathTransform = {\n            position: path.position,\n            rotation: path.rotation,\n            scale: path.scale\n        };\n        path.position = [leftMargin - rect.x, topMargin - rect.y];\n        path.rotation = 0;\n        path.scale = [1, 1];\n        path.updateTransform();\n        if (path) {\n            path.brush(ctx);\n        }\n\n        var ImageShape = ZImage;\n        var imgShape = new ImageShape({\n            style: {\n                x: 0,\n                y: 0,\n                image: canvas\n            }\n        });\n\n        if (pathTransform.position != null) {\n            imgShape.position = path.position = pathTransform.position;\n        }\n\n        if (pathTransform.rotation != null) {\n            imgShape.rotation = path.rotation = pathTransform.rotation;\n        }\n\n        if (pathTransform.scale != null) {\n            imgShape.scale = path.scale = pathTransform.scale;\n        }\n\n        return imgShape;\n    }\n};\n\n/**\n * 动画主类, 调度和管理所有动画控制器\n *\n * @module zrender/animation/Animation\n * @author pissang(https://github.com/pissang)\n */\n// TODO Additive animation\n// http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/\n// https://developer.apple.com/videos/wwdc2014/#236\n\n/**\n * @typedef {Object} IZRenderStage\n * @property {Function} update\n */\n\n/**\n * @alias module:zrender/animation/Animation\n * @constructor\n * @param {Object} [options]\n * @param {Function} [options.onframe]\n * @param {IZRenderStage} [options.stage]\n * @example\n *     var animation = new Animation();\n *     var obj = {\n *         x: 100,\n *         y: 100\n *     };\n *     animation.animate(node.position)\n *         .when(1000, {\n *             x: 500,\n *             y: 500\n *         })\n *         .when(2000, {\n *             x: 100,\n *             y: 100\n *         })\n *         .start('spline');\n */\nvar Animation = function (options) {\n\n    options = options || {};\n\n    this.stage = options.stage || {};\n\n    this.onframe = options.onframe || function () {};\n\n    // private properties\n    this._clips = [];\n\n    this._running = false;\n\n    this._time;\n\n    this._pausedTime;\n\n    this._pauseStart;\n\n    this._paused = false;\n\n    Eventful.call(this);\n};\n\nAnimation.prototype = {\n\n    constructor: Animation,\n    /**\n     * 添加 clip\n     * @param {module:zrender/animation/Clip} clip\n     */\n    addClip: function (clip) {\n        this._clips.push(clip);\n    },\n    /**\n     * 添加 animator\n     * @param {module:zrender/animation/Animator} animator\n     */\n    addAnimator: function (animator) {\n        animator.animation = this;\n        var clips = animator.getClips();\n        for (var i = 0; i < clips.length; i++) {\n            this.addClip(clips[i]);\n        }\n    },\n    /**\n     * 删除动画片段\n     * @param {module:zrender/animation/Clip} clip\n     */\n    removeClip: function (clip) {\n        var idx = indexOf(this._clips, clip);\n        if (idx >= 0) {\n            this._clips.splice(idx, 1);\n        }\n    },\n\n    /**\n     * 删除动画片段\n     * @param {module:zrender/animation/Animator} animator\n     */\n    removeAnimator: function (animator) {\n        var clips = animator.getClips();\n        for (var i = 0; i < clips.length; i++) {\n            this.removeClip(clips[i]);\n        }\n        animator.animation = null;\n    },\n\n    _update: function () {\n        var time = new Date().getTime() - this._pausedTime;\n        var delta = time - this._time;\n        var clips = this._clips;\n        var len = clips.length;\n\n        var deferredEvents = [];\n        var deferredClips = [];\n        for (var i = 0; i < len; i++) {\n            var clip = clips[i];\n            var e = clip.step(time, delta);\n            // Throw out the events need to be called after\n            // stage.update, like destroy\n            if (e) {\n                deferredEvents.push(e);\n                deferredClips.push(clip);\n            }\n        }\n\n        // Remove the finished clip\n        for (var i = 0; i < len;) {\n            if (clips[i]._needsRemove) {\n                clips[i] = clips[len - 1];\n                clips.pop();\n                len--;\n            }\n            else {\n                i++;\n            }\n        }\n\n        len = deferredEvents.length;\n        for (var i = 0; i < len; i++) {\n            deferredClips[i].fire(deferredEvents[i]);\n        }\n\n        this._time = time;\n\n        this.onframe(delta);\n\n        // 'frame' should be triggered before stage, because upper application\n        // depends on the sequence (e.g., echarts-stream and finish\n        // event judge)\n        this.trigger('frame', delta);\n\n        if (this.stage.update) {\n            this.stage.update();\n        }\n    },\n\n    _startLoop: function () {\n        var self = this;\n\n        this._running = true;\n\n        function step() {\n            if (self._running) {\n\n                requestAnimationFrame(step);\n\n                !self._paused && self._update();\n            }\n        }\n\n        requestAnimationFrame(step);\n    },\n\n    /**\n     * Start animation.\n     */\n    start: function () {\n\n        this._time = new Date().getTime();\n        this._pausedTime = 0;\n\n        this._startLoop();\n    },\n\n    /**\n     * Stop animation.\n     */\n    stop: function () {\n        this._running = false;\n    },\n\n    /**\n     * Pause animation.\n     */\n    pause: function () {\n        if (!this._paused) {\n            this._pauseStart = new Date().getTime();\n            this._paused = true;\n        }\n    },\n\n    /**\n     * Resume animation.\n     */\n    resume: function () {\n        if (this._paused) {\n            this._pausedTime += (new Date().getTime()) - this._pauseStart;\n            this._paused = false;\n        }\n    },\n\n    /**\n     * Clear animation.\n     */\n    clear: function () {\n        this._clips = [];\n    },\n\n    /**\n     * Whether animation finished.\n     */\n    isFinished: function () {\n        return !this._clips.length;\n    },\n\n    /**\n     * Creat animator for a target, whose props can be animated.\n     *\n     * @param  {Object} target\n     * @param  {Object} options\n     * @param  {boolean} [options.loop=false] Whether loop animation.\n     * @param  {Function} [options.getter=null] Get value from target.\n     * @param  {Function} [options.setter=null] Set value to target.\n     * @return {module:zrender/animation/Animation~Animator}\n     */\n    // TODO Gap\n    animate: function (target, options) {\n        options = options || {};\n\n        var animator = new Animator(\n            target,\n            options.loop,\n            options.getter,\n            options.setter\n        );\n\n        this.addAnimator(animator);\n\n        return animator;\n    }\n};\n\nmixin(Animation, Eventful);\n\nvar TOUCH_CLICK_DELAY = 300;\n\nvar mouseHandlerNames = [\n    'click', 'dblclick', 'mousewheel', 'mouseout',\n    'mouseup', 'mousedown', 'mousemove', 'contextmenu'\n];\n\nvar touchHandlerNames = [\n    'touchstart', 'touchend', 'touchmove'\n];\n\nvar pointerEventNames = {\n    pointerdown: 1, pointerup: 1, pointermove: 1, pointerout: 1\n};\n\nvar pointerHandlerNames = map(mouseHandlerNames, function (name) {\n    var nm = name.replace('mouse', 'pointer');\n    return pointerEventNames[nm] ? nm : name;\n});\n\nfunction eventNameFix(name) {\n    return (name === 'mousewheel' && env$1.browser.firefox) ? 'DOMMouseScroll' : name;\n}\n\n// function onMSGestureChange(proxy, event) {\n//     if (event.translationX || event.translationY) {\n//         // mousemove is carried by MSGesture to reduce the sensitivity.\n//         proxy.handler.dispatchToElement(event.target, 'mousemove', event);\n//     }\n//     if (event.scale !== 1) {\n//         event.pinchX = event.offsetX;\n//         event.pinchY = event.offsetY;\n//         event.pinchScale = event.scale;\n//         proxy.handler.dispatchToElement(event.target, 'pinch', event);\n//     }\n// }\n\n/**\n * Prevent mouse event from being dispatched after Touch Events action\n * @see <https://github.com/deltakosh/handjs/blob/master/src/hand.base.js>\n * 1. Mobile browsers dispatch mouse events 300ms after touchend.\n * 2. Chrome for Android dispatch mousedown for long-touch about 650ms\n * Result: Blocking Mouse Events for 700ms.\n */\nfunction setTouchTimer(instance) {\n    instance._touching = true;\n    clearTimeout(instance._touchTimer);\n    instance._touchTimer = setTimeout(function () {\n        instance._touching = false;\n    }, 700);\n}\n\n\nvar domHandlers = {\n    /**\n     * Mouse move handler\n     * @inner\n     * @param {Event} event\n     */\n    mousemove: function (event) {\n        event = normalizeEvent(this.dom, event);\n\n        this.trigger('mousemove', event);\n    },\n\n    /**\n     * Mouse out handler\n     * @inner\n     * @param {Event} event\n     */\n    mouseout: function (event) {\n        event = normalizeEvent(this.dom, event);\n\n        var element = event.toElement || event.relatedTarget;\n        if (element !== this.dom) {\n            while (element && element.nodeType !== 9) {\n                // 忽略包含在root中的dom引起的mouseOut\n                if (element === this.dom) {\n                    return;\n                }\n\n                element = element.parentNode;\n            }\n        }\n\n        this.trigger('mouseout', event);\n    },\n\n    /**\n     * Touch开始响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchstart: function (event) {\n        // Default mouse behaviour should not be disabled here.\n        // For example, page may needs to be slided.\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this._lastTouchMoment = new Date();\n\n        this.handler.processGesture(this, event, 'start');\n\n        // In touch device, trigger `mousemove`(`mouseover`) should\n        // be triggered, and must before `mousedown` triggered.\n        domHandlers.mousemove.call(this, event);\n\n        domHandlers.mousedown.call(this, event);\n\n        setTouchTimer(this);\n    },\n\n    /**\n     * Touch移动响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchmove: function (event) {\n\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this.handler.processGesture(this, event, 'change');\n\n        // Mouse move should always be triggered no matter whether\n        // there is gestrue event, because mouse move and pinch may\n        // be used at the same time.\n        domHandlers.mousemove.call(this, event);\n\n        setTouchTimer(this);\n    },\n\n    /**\n     * Touch结束响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchend: function (event) {\n\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this.handler.processGesture(this, event, 'end');\n\n        domHandlers.mouseup.call(this, event);\n\n        // Do not trigger `mouseout` here, in spite of `mousemove`(`mouseover`) is\n        // triggered in `touchstart`. This seems to be illogical, but by this mechanism,\n        // we can conveniently implement \"hover style\" in both PC and touch device just\n        // by listening to `mouseover` to add \"hover style\" and listening to `mouseout`\n        // to remove \"hover style\" on an element, without any additional code for\n        // compatibility. (`mouseout` will not be triggered in `touchend`, so \"hover\n        // style\" will remain for user view)\n\n        // click event should always be triggered no matter whether\n        // there is gestrue event. System click can not be prevented.\n        if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) {\n            domHandlers.click.call(this, event);\n        }\n\n        setTouchTimer(this);\n    },\n\n    pointerdown: function (event) {\n        domHandlers.mousedown.call(this, event);\n\n        // if (useMSGuesture(this, event)) {\n        //     this._msGesture.addPointer(event.pointerId);\n        // }\n    },\n\n    pointermove: function (event) {\n        // FIXME\n        // pointermove is so sensitive that it always triggered when\n        // tap(click) on touch screen, which affect some judgement in\n        // upper application. So, we dont support mousemove on MS touch\n        // device yet.\n        if (!isPointerFromTouch(event)) {\n            domHandlers.mousemove.call(this, event);\n        }\n    },\n\n    pointerup: function (event) {\n        domHandlers.mouseup.call(this, event);\n    },\n\n    pointerout: function (event) {\n        // pointerout will be triggered when tap on touch screen\n        // (IE11+/Edge on MS Surface) after click event triggered,\n        // which is inconsistent with the mousout behavior we defined\n        // in touchend. So we unify them.\n        // (check domHandlers.touchend for detailed explanation)\n        if (!isPointerFromTouch(event)) {\n            domHandlers.mouseout.call(this, event);\n        }\n    }\n};\n\nfunction isPointerFromTouch(event) {\n    var pointerType = event.pointerType;\n    return pointerType === 'pen' || pointerType === 'touch';\n}\n\n// function useMSGuesture(handlerProxy, event) {\n//     return isPointerFromTouch(event) && !!handlerProxy._msGesture;\n// }\n\n// Common handlers\neach$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {\n    domHandlers[name] = function (event) {\n        event = normalizeEvent(this.dom, event);\n        this.trigger(name, event);\n    };\n});\n\n/**\n * 为控制类实例初始化dom 事件处理函数\n *\n * @inner\n * @param {module:zrender/Handler} instance 控制类实例\n */\nfunction initDomHandler(instance) {\n    each$1(touchHandlerNames, function (name) {\n        instance._handlers[name] = bind(domHandlers[name], instance);\n    });\n\n    each$1(pointerHandlerNames, function (name) {\n        instance._handlers[name] = bind(domHandlers[name], instance);\n    });\n\n    each$1(mouseHandlerNames, function (name) {\n        instance._handlers[name] = makeMouseHandler(domHandlers[name], instance);\n    });\n\n    function makeMouseHandler(fn, instance) {\n        return function () {\n            if (instance._touching) {\n                return;\n            }\n            return fn.apply(instance, arguments);\n        };\n    }\n}\n\n\nfunction HandlerDomProxy(dom) {\n    Eventful.call(this);\n\n    this.dom = dom;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._touching = false;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._touchTimer;\n\n    this._handlers = {};\n\n    initDomHandler(this);\n\n    if (env$1.pointerEventsSupported) { // Only IE11+/Edge\n        // 1. On devices that both enable touch and mouse (e.g., MS Surface and lenovo X240),\n        // IE11+/Edge do not trigger touch event, but trigger pointer event and mouse event\n        // at the same time.\n        // 2. On MS Surface, it probablely only trigger mousedown but no mouseup when tap on\n        // screen, which do not occurs in pointer event.\n        // So we use pointer event to both detect touch gesture and mouse behavior.\n        mountHandlers(pointerHandlerNames, this);\n\n        // FIXME\n        // Note: MS Gesture require CSS touch-action set. But touch-action is not reliable,\n        // which does not prevent defuault behavior occasionally (which may cause view port\n        // zoomed in but use can not zoom it back). And event.preventDefault() does not work.\n        // So we have to not to use MSGesture and not to support touchmove and pinch on MS\n        // touch screen. And we only support click behavior on MS touch screen now.\n\n        // MS Gesture Event is only supported on IE11+/Edge and on Windows 8+.\n        // We dont support touch on IE on win7.\n        // See <https://msdn.microsoft.com/en-us/library/dn433243(v=vs.85).aspx>\n        // if (typeof MSGesture === 'function') {\n        //     (this._msGesture = new MSGesture()).target = dom; // jshint ignore:line\n        //     dom.addEventListener('MSGestureChange', onMSGestureChange);\n        // }\n    }\n    else {\n        if (env$1.touchEventsSupported) {\n            mountHandlers(touchHandlerNames, this);\n            // Handler of 'mouseout' event is needed in touch mode, which will be mounted below.\n            // addEventListener(root, 'mouseout', this._mouseoutHandler);\n        }\n\n        // 1. Considering some devices that both enable touch and mouse event (like on MS Surface\n        // and lenovo X240, @see #2350), we make mouse event be always listened, otherwise\n        // mouse event can not be handle in those devices.\n        // 2. On MS Surface, Chrome will trigger both touch event and mouse event. How to prevent\n        // mouseevent after touch event triggered, see `setTouchTimer`.\n        mountHandlers(mouseHandlerNames, this);\n    }\n\n    function mountHandlers(handlerNames, instance) {\n        each$1(handlerNames, function (name) {\n            addEventListener(dom, eventNameFix(name), instance._handlers[name]);\n        }, instance);\n    }\n}\n\nvar handlerDomProxyProto = HandlerDomProxy.prototype;\nhandlerDomProxyProto.dispose = function () {\n    var handlerNames = mouseHandlerNames.concat(touchHandlerNames);\n\n    for (var i = 0; i < handlerNames.length; i++) {\n        var name = handlerNames[i];\n        removeEventListener(this.dom, eventNameFix(name), this._handlers[name]);\n    }\n};\n\nhandlerDomProxyProto.setCursor = function (cursorStyle) {\n    this.dom.style && (this.dom.style.cursor = cursorStyle || 'default');\n};\n\nmixin(HandlerDomProxy, Eventful);\n\n/*!\n* ZRender, a high performance 2d drawing library.\n*\n* Copyright (c) 2013, Baidu Inc.\n* All rights reserved.\n*\n* LICENSE\n* https://github.com/ecomfe/zrender/blob/master/LICENSE.txt\n*/\n\nvar useVML = !env$1.canvasSupported;\n\nvar painterCtors = {\n    canvas: Painter\n};\n\n/**\n * @type {string}\n */\nvar version$1 = '4.0.7';\n\n/**\n * Initializing a zrender instance\n * @param {HTMLElement} dom\n * @param {Object} [opts]\n * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'\n * @param {number} [opts.devicePixelRatio]\n * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)\n * @return {module:zrender/ZRender}\n */\nfunction init$1(dom, opts) {\n    var zr = new ZRender(guid(), dom, opts);\n    return zr;\n}\n\n/**\n * Dispose zrender instance\n * @param {module:zrender/ZRender} zr\n */\n\n\n/**\n * Get zrender instance by id\n * @param {string} id zrender instance id\n * @return {module:zrender/ZRender}\n */\n\n\n\n\n/**\n * @module zrender/ZRender\n */\n/**\n * @constructor\n * @alias module:zrender/ZRender\n * @param {string} id\n * @param {HTMLElement} dom\n * @param {Object} opts\n * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'\n * @param {number} [opts.devicePixelRatio]\n * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)\n */\nvar ZRender = function (id, dom, opts) {\n\n    opts = opts || {};\n\n    /**\n     * @type {HTMLDomElement}\n     */\n    this.dom = dom;\n\n    /**\n     * @type {string}\n     */\n    this.id = id;\n\n    var self = this;\n    var storage = new Storage();\n\n    var rendererType = opts.renderer;\n    // TODO WebGL\n    if (useVML) {\n        if (!painterCtors.vml) {\n            throw new Error('You need to require \\'zrender/vml/vml\\' to support IE8');\n        }\n        rendererType = 'vml';\n    }\n    else if (!rendererType || !painterCtors[rendererType]) {\n        rendererType = 'canvas';\n    }\n    var painter = new painterCtors[rendererType](dom, storage, opts, id);\n\n    this.storage = storage;\n    this.painter = painter;\n\n    var handerProxy = (!env$1.node && !env$1.worker) ? new HandlerDomProxy(painter.getViewportRoot()) : null;\n    this.handler = new Handler(storage, painter, handerProxy, painter.root);\n\n    /**\n     * @type {module:zrender/animation/Animation}\n     */\n    this.animation = new Animation({\n        stage: {\n            update: bind(this.flush, this)\n        }\n    });\n    this.animation.start();\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._needsRefresh;\n\n    // 修改 storage.delFromStorage, 每次删除元素之前删除动画\n    // FIXME 有点ugly\n    var oldDelFromStorage = storage.delFromStorage;\n    var oldAddToStorage = storage.addToStorage;\n\n    storage.delFromStorage = function (el) {\n        oldDelFromStorage.call(storage, el);\n\n        el && el.removeSelfFromZr(self);\n    };\n\n    storage.addToStorage = function (el) {\n        oldAddToStorage.call(storage, el);\n\n        el.addSelfToZr(self);\n    };\n};\n\nZRender.prototype = {\n\n    constructor: ZRender,\n    /**\n     * 获取实例唯一标识\n     * @return {string}\n     */\n    getId: function () {\n        return this.id;\n    },\n\n    /**\n     * 添加元素\n     * @param  {module:zrender/Element} el\n     */\n    add: function (el) {\n        this.storage.addRoot(el);\n        this._needsRefresh = true;\n    },\n\n    /**\n     * 删除元素\n     * @param  {module:zrender/Element} el\n     */\n    remove: function (el) {\n        this.storage.delRoot(el);\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Change configuration of layer\n     * @param {string} zLevel\n     * @param {Object} config\n     * @param {string} [config.clearColor=0] Clear color\n     * @param {string} [config.motionBlur=false] If enable motion blur\n     * @param {number} [config.lastFrameAlpha=0.7] Motion blur factor. Larger value cause longer trailer\n    */\n    configLayer: function (zLevel, config) {\n        if (this.painter.configLayer) {\n            this.painter.configLayer(zLevel, config);\n        }\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Set background color\n     * @param {string} backgroundColor\n     */\n    setBackgroundColor: function (backgroundColor) {\n        if (this.painter.setBackgroundColor) {\n            this.painter.setBackgroundColor(backgroundColor);\n        }\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Repaint the canvas immediately\n     */\n    refreshImmediately: function () {\n        // var start = new Date();\n        // Clear needsRefresh ahead to avoid something wrong happens in refresh\n        // Or it will cause zrender refreshes again and again.\n        this._needsRefresh = false;\n        this.painter.refresh();\n        /**\n         * Avoid trigger zr.refresh in Element#beforeUpdate hook\n         */\n        this._needsRefresh = false;\n        // var end = new Date();\n        // var log = document.getElementById('log');\n        // if (log) {\n        //     log.innerHTML = log.innerHTML + '<br>' + (end - start);\n        // }\n    },\n\n    /**\n     * Mark and repaint the canvas in the next frame of browser\n     */\n    refresh: function () {\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Perform all refresh\n     */\n    flush: function () {\n        var triggerRendered;\n\n        if (this._needsRefresh) {\n            triggerRendered = true;\n            this.refreshImmediately();\n        }\n        if (this._needsRefreshHover) {\n            triggerRendered = true;\n            this.refreshHoverImmediately();\n        }\n\n        triggerRendered && this.trigger('rendered');\n    },\n\n    /**\n     * Add element to hover layer\n     * @param  {module:zrender/Element} el\n     * @param {Object} style\n     */\n    addHover: function (el, style) {\n        if (this.painter.addHover) {\n            var elMirror = this.painter.addHover(el, style);\n            this.refreshHover();\n            return elMirror;\n        }\n    },\n\n    /**\n     * Add element from hover layer\n     * @param  {module:zrender/Element} el\n     */\n    removeHover: function (el) {\n        if (this.painter.removeHover) {\n            this.painter.removeHover(el);\n            this.refreshHover();\n        }\n    },\n\n    /**\n     * Clear all hover elements in hover layer\n     * @param  {module:zrender/Element} el\n     */\n    clearHover: function () {\n        if (this.painter.clearHover) {\n            this.painter.clearHover();\n            this.refreshHover();\n        }\n    },\n\n    /**\n     * Refresh hover in next frame\n     */\n    refreshHover: function () {\n        this._needsRefreshHover = true;\n    },\n\n    /**\n     * Refresh hover immediately\n     */\n    refreshHoverImmediately: function () {\n        this._needsRefreshHover = false;\n        this.painter.refreshHover && this.painter.refreshHover();\n    },\n\n    /**\n     * Resize the canvas.\n     * Should be invoked when container size is changed\n     * @param {Object} [opts]\n     * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)\n     * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)\n     */\n    resize: function (opts) {\n        opts = opts || {};\n        this.painter.resize(opts.width, opts.height);\n        this.handler.resize();\n    },\n\n    /**\n     * Stop and clear all animation immediately\n     */\n    clearAnimation: function () {\n        this.animation.clear();\n    },\n\n    /**\n     * Get container width\n     */\n    getWidth: function () {\n        return this.painter.getWidth();\n    },\n\n    /**\n     * Get container height\n     */\n    getHeight: function () {\n        return this.painter.getHeight();\n    },\n\n    /**\n     * Export the canvas as Base64 URL\n     * @param {string} type\n     * @param {string} [backgroundColor='#fff']\n     * @return {string} Base64 URL\n     */\n    // toDataURL: function(type, backgroundColor) {\n    //     return this.painter.getRenderedCanvas({\n    //         backgroundColor: backgroundColor\n    //     }).toDataURL(type);\n    // },\n\n    /**\n     * Converting a path to image.\n     * It has much better performance of drawing image rather than drawing a vector path.\n     * @param {module:zrender/graphic/Path} e\n     * @param {number} width\n     * @param {number} height\n     */\n    pathToImage: function (e, dpr) {\n        return this.painter.pathToImage(e, dpr);\n    },\n\n    /**\n     * Set default cursor\n     * @param {string} [cursorStyle='default'] 例如 crosshair\n     */\n    setCursorStyle: function (cursorStyle) {\n        this.handler.setCursorStyle(cursorStyle);\n    },\n\n    /**\n     * Find hovered element\n     * @param {number} x\n     * @param {number} y\n     * @return {Object} {target, topTarget}\n     */\n    findHover: function (x, y) {\n        return this.handler.findHover(x, y);\n    },\n\n    /**\n     * Bind event\n     *\n     * @param {string} eventName Event name\n     * @param {Function} eventHandler Handler function\n     * @param {Object} [context] Context object\n     */\n    on: function (eventName, eventHandler, context) {\n        this.handler.on(eventName, eventHandler, context);\n    },\n\n    /**\n     * Unbind event\n     * @param {string} eventName Event name\n     * @param {Function} [eventHandler] Handler function\n     */\n    off: function (eventName, eventHandler) {\n        this.handler.off(eventName, eventHandler);\n    },\n\n    /**\n     * Trigger event manually\n     *\n     * @param {string} eventName Event name\n     * @param {event=} event Event object\n     */\n    trigger: function (eventName, event) {\n        this.handler.trigger(eventName, event);\n    },\n\n\n    /**\n     * Clear all objects and the canvas.\n     */\n    clear: function () {\n        this.storage.delRoot();\n        this.painter.clear();\n    },\n\n    /**\n     * Dispose self.\n     */\n    dispose: function () {\n        this.animation.stop();\n\n        this.clear();\n        this.storage.dispose();\n        this.painter.dispose();\n        this.handler.dispose();\n\n        this.animation =\n        this.storage =\n        this.painter =\n        this.handler = null;\n\n        \n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$2 = each$1;\nvar isObject$2 = isObject$1;\nvar isArray$1 = isArray;\n\n/**\n * Make the name displayable. But we should\n * make sure it is not duplicated with user\n * specified name, so use '\\0';\n */\nvar DUMMY_COMPONENT_NAME_PREFIX = 'series\\0';\n\n/**\n * If value is not array, then translate it to array.\n * @param  {*} value\n * @return {Array} [value] or value\n */\nfunction normalizeToArray(value) {\n    return value instanceof Array\n        ? value\n        : value == null\n        ? []\n        : [value];\n}\n\n/**\n * Sync default option between normal and emphasis like `position` and `show`\n * In case some one will write code like\n *     label: {\n *          show: false,\n *          position: 'outside',\n *          fontSize: 18\n *     },\n *     emphasis: {\n *          label: { show: true }\n *     }\n * @param {Object} opt\n * @param {string} key\n * @param {Array.<string>} subOpts\n */\nfunction defaultEmphasis(opt, key, subOpts) {\n    // Caution: performance sensitive.\n    if (opt) {\n        opt[key] = opt[key] || {};\n        opt.emphasis = opt.emphasis || {};\n        opt.emphasis[key] = opt.emphasis[key] || {};\n\n        // Default emphasis option from normal\n        for (var i = 0, len = subOpts.length; i < len; i++) {\n            var subOptName = subOpts[i];\n            if (!opt.emphasis[key].hasOwnProperty(subOptName)\n                && opt[key].hasOwnProperty(subOptName)\n            ) {\n                opt.emphasis[key][subOptName] = opt[key][subOptName];\n            }\n        }\n    }\n}\n\nvar TEXT_STYLE_OPTIONS = [\n    'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',\n    'rich', 'tag', 'color', 'textBorderColor', 'textBorderWidth',\n    'width', 'height', 'lineHeight', 'align', 'verticalAlign', 'baseline',\n    'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY',\n    'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY',\n    'backgroundColor', 'borderColor', 'borderWidth', 'borderRadius', 'padding'\n];\n\n// modelUtil.LABEL_OPTIONS = modelUtil.TEXT_STYLE_OPTIONS.concat([\n//     'position', 'offset', 'rotate', 'origin', 'show', 'distance', 'formatter',\n//     'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',\n//     // FIXME: deprecated, check and remove it.\n//     'textStyle'\n// ]);\n\n/**\n * The method do not ensure performance.\n * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]\n * This helper method retieves value from data.\n * @param {string|number|Date|Array|Object} dataItem\n * @return {number|string|Date|Array.<number|string|Date>}\n */\nfunction getDataItemValue(dataItem) {\n    return (isObject$2(dataItem) && !isArray$1(dataItem) && !(dataItem instanceof Date))\n        ? dataItem.value : dataItem;\n}\n\n/**\n * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]\n * This helper method determine if dataItem has extra option besides value\n * @param {string|number|Date|Array|Object} dataItem\n */\nfunction isDataItemOption(dataItem) {\n    return isObject$2(dataItem)\n        && !(dataItem instanceof Array);\n        // // markLine data can be array\n        // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array));\n}\n\n/**\n * Mapping to exists for merge.\n *\n * @public\n * @param {Array.<Object>|Array.<module:echarts/model/Component>} exists\n * @param {Object|Array.<Object>} newCptOptions\n * @return {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],\n *                          index of which is the same as exists.\n */\nfunction mappingToExists(exists, newCptOptions) {\n    // Mapping by the order by original option (but not order of\n    // new option) in merge mode. Because we should ensure\n    // some specified index (like xAxisIndex) is consistent with\n    // original option, which is easy to understand, espatially in\n    // media query. And in most case, merge option is used to\n    // update partial option but not be expected to change order.\n    newCptOptions = (newCptOptions || []).slice();\n\n    var result = map(exists || [], function (obj, index) {\n        return {exist: obj};\n    });\n\n    // Mapping by id or name if specified.\n    each$2(newCptOptions, function (cptOption, index) {\n        if (!isObject$2(cptOption)) {\n            return;\n        }\n\n        // id has highest priority.\n        for (var i = 0; i < result.length; i++) {\n            if (!result[i].option // Consider name: two map to one.\n                && cptOption.id != null\n                && result[i].exist.id === cptOption.id + ''\n            ) {\n                result[i].option = cptOption;\n                newCptOptions[index] = null;\n                return;\n            }\n        }\n\n        for (var i = 0; i < result.length; i++) {\n            var exist = result[i].exist;\n            if (!result[i].option // Consider name: two map to one.\n                // Can not match when both ids exist but different.\n                && (exist.id == null || cptOption.id == null)\n                && cptOption.name != null\n                && !isIdInner(cptOption)\n                && !isIdInner(exist)\n                && exist.name === cptOption.name + ''\n            ) {\n                result[i].option = cptOption;\n                newCptOptions[index] = null;\n                return;\n            }\n        }\n    });\n\n    // Otherwise mapping by index.\n    each$2(newCptOptions, function (cptOption, index) {\n        if (!isObject$2(cptOption)) {\n            return;\n        }\n\n        var i = 0;\n        for (; i < result.length; i++) {\n            var exist = result[i].exist;\n            if (!result[i].option\n                // Existing model that already has id should be able to\n                // mapped to (because after mapping performed model may\n                // be assigned with a id, whish should not affect next\n                // mapping), except those has inner id.\n                && !isIdInner(exist)\n                // Caution:\n                // Do not overwrite id. But name can be overwritten,\n                // because axis use name as 'show label text'.\n                // 'exist' always has id and name and we dont\n                // need to check it.\n                && cptOption.id == null\n            ) {\n                result[i].option = cptOption;\n                break;\n            }\n        }\n\n        if (i >= result.length) {\n            result.push({option: cptOption});\n        }\n    });\n\n    return result;\n}\n\n/**\n * Make id and name for mapping result (result of mappingToExists)\n * into `keyInfo` field.\n *\n * @public\n * @param {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],\n *                          which order is the same as exists.\n * @return {Array.<Object>} The input.\n */\nfunction makeIdAndName(mapResult) {\n    // We use this id to hash component models and view instances\n    // in echarts. id can be specified by user, or auto generated.\n\n    // The id generation rule ensures new view instance are able\n    // to mapped to old instance when setOption are called in\n    // no-merge mode. So we generate model id by name and plus\n    // type in view id.\n\n    // name can be duplicated among components, which is convenient\n    // to specify multi components (like series) by one name.\n\n    // Ensure that each id is distinct.\n    var idMap = createHashMap();\n\n    each$2(mapResult, function (item, index) {\n        var existCpt = item.exist;\n        existCpt && idMap.set(existCpt.id, item);\n    });\n\n    each$2(mapResult, function (item, index) {\n        var opt = item.option;\n\n        assert$1(\n            !opt || opt.id == null || !idMap.get(opt.id) || idMap.get(opt.id) === item,\n            'id duplicates: ' + (opt && opt.id)\n        );\n\n        opt && opt.id != null && idMap.set(opt.id, item);\n        !item.keyInfo && (item.keyInfo = {});\n    });\n\n    // Make name and id.\n    each$2(mapResult, function (item, index) {\n        var existCpt = item.exist;\n        var opt = item.option;\n        var keyInfo = item.keyInfo;\n\n        if (!isObject$2(opt)) {\n            return;\n        }\n\n        // name can be overwitten. Consider case: axis.name = '20km'.\n        // But id generated by name will not be changed, which affect\n        // only in that case: setOption with 'not merge mode' and view\n        // instance will be recreated, which can be accepted.\n        keyInfo.name = opt.name != null\n            ? opt.name + ''\n            : existCpt\n            ? existCpt.name\n            // Avoid diffferent series has the same name,\n            // because name may be used like in color pallet.\n            : DUMMY_COMPONENT_NAME_PREFIX + index;\n\n        if (existCpt) {\n            keyInfo.id = existCpt.id;\n        }\n        else if (opt.id != null) {\n            keyInfo.id = opt.id + '';\n        }\n        else {\n            // Consider this situatoin:\n            //  optionA: [{name: 'a'}, {name: 'a'}, {..}]\n            //  optionB [{..}, {name: 'a'}, {name: 'a'}]\n            // Series with the same name between optionA and optionB\n            // should be mapped.\n            var idNum = 0;\n            do {\n                keyInfo.id = '\\0' + keyInfo.name + '\\0' + idNum++;\n            }\n            while (idMap.get(keyInfo.id));\n        }\n\n        idMap.set(keyInfo.id, item);\n    });\n}\n\nfunction isNameSpecified(componentModel) {\n    var name = componentModel.name;\n    // Is specified when `indexOf` get -1 or > 0.\n    return !!(name && name.indexOf(DUMMY_COMPONENT_NAME_PREFIX));\n}\n\n/**\n * @public\n * @param {Object} cptOption\n * @return {boolean}\n */\nfunction isIdInner(cptOption) {\n    return isObject$2(cptOption)\n        && cptOption.id\n        && (cptOption.id + '').indexOf('\\0_ec_\\0') === 0;\n}\n\n/**\n * A helper for removing duplicate items between batchA and batchB,\n * and in themselves, and categorize by series.\n *\n * @param {Array.<Object>} batchA Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]\n * @param {Array.<Object>} batchB Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]\n * @return {Array.<Array.<Object>, Array.<Object>>} result: [resultBatchA, resultBatchB]\n */\n\n\n/**\n * @param {module:echarts/data/List} data\n * @param {Object} payload Contains dataIndex (means rawIndex) / dataIndexInside / name\n *                         each of which can be Array or primary type.\n * @return {number|Array.<number>} dataIndex If not found, return undefined/null.\n */\nfunction queryDataIndex(data, payload) {\n    if (payload.dataIndexInside != null) {\n        return payload.dataIndexInside;\n    }\n    else if (payload.dataIndex != null) {\n        return isArray(payload.dataIndex)\n            ? map(payload.dataIndex, function (value) {\n                return data.indexOfRawIndex(value);\n            })\n            : data.indexOfRawIndex(payload.dataIndex);\n    }\n    else if (payload.name != null) {\n        return isArray(payload.name)\n            ? map(payload.name, function (value) {\n                return data.indexOfName(value);\n            })\n            : data.indexOfName(payload.name);\n    }\n}\n\n/**\n * Enable property storage to any host object.\n * Notice: Serialization is not supported.\n *\n * For example:\n * var inner = zrUitl.makeInner();\n *\n * function some1(hostObj) {\n *      inner(hostObj).someProperty = 1212;\n *      ...\n * }\n * function some2() {\n *      var fields = inner(this);\n *      fields.someProperty1 = 1212;\n *      fields.someProperty2 = 'xx';\n *      ...\n * }\n *\n * @return {Function}\n */\nfunction makeInner() {\n    // Consider different scope by es module import.\n    var key = '__\\0ec_inner_' + innerUniqueIndex++ + '_' + Math.random().toFixed(5);\n    return function (hostObj) {\n        return hostObj[key] || (hostObj[key] = {});\n    };\n}\nvar innerUniqueIndex = 0;\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex, seriesId, seriesName,\n *            geoIndex, geoId, geoName,\n *            bmapIndex, bmapId, bmapName,\n *            xAxisIndex, xAxisId, xAxisName,\n *            yAxisIndex, yAxisId, yAxisName,\n *            gridIndex, gridId, gridName,\n *            ... (can be extended)\n *        }\n *        Each properties can be number|string|Array.<number>|Array.<string>\n *        For example, a finder could be\n *        {\n *            seriesIndex: 3,\n *            geoId: ['aa', 'cc'],\n *            gridName: ['xx', 'rr']\n *        }\n *        xxxIndex can be set as 'all' (means all xxx) or 'none' (means not specify)\n *        If nothing or null/undefined specified, return nothing.\n * @param {Object} [opt]\n * @param {string} [opt.defaultMainType]\n * @param {Array.<string>} [opt.includeMainTypes]\n * @return {Object} result like:\n *        {\n *            seriesModels: [seriesModel1, seriesModel2],\n *            seriesModel: seriesModel1, // The first model\n *            geoModels: [geoModel1, geoModel2],\n *            geoModel: geoModel1, // The first model\n *            ...\n *        }\n */\nfunction parseFinder(ecModel, finder, opt) {\n    if (isString(finder)) {\n        var obj = {};\n        obj[finder + 'Index'] = 0;\n        finder = obj;\n    }\n\n    var defaultMainType = opt && opt.defaultMainType;\n    if (defaultMainType\n        && !has(finder, defaultMainType + 'Index')\n        && !has(finder, defaultMainType + 'Id')\n        && !has(finder, defaultMainType + 'Name')\n    ) {\n        finder[defaultMainType + 'Index'] = 0;\n    }\n\n    var result = {};\n\n    each$2(finder, function (value, key) {\n        var value = finder[key];\n\n        // Exclude 'dataIndex' and other illgal keys.\n        if (key === 'dataIndex' || key === 'dataIndexInside') {\n            result[key] = value;\n            return;\n        }\n\n        var parsedKey = key.match(/^(\\w+)(Index|Id|Name)$/) || [];\n        var mainType = parsedKey[1];\n        var queryType = (parsedKey[2] || '').toLowerCase();\n\n        if (!mainType\n            || !queryType\n            || value == null\n            || (queryType === 'index' && value === 'none')\n            || (opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0)\n        ) {\n            return;\n        }\n\n        var queryParam = {mainType: mainType};\n        if (queryType !== 'index' || value !== 'all') {\n            queryParam[queryType] = value;\n        }\n\n        var models = ecModel.queryComponents(queryParam);\n        result[mainType + 'Models'] = models;\n        result[mainType + 'Model'] = models[0];\n    });\n\n    return result;\n}\n\nfunction has(obj, prop) {\n    return obj && obj.hasOwnProperty(prop);\n}\n\nfunction setAttribute(dom, key, value) {\n    dom.setAttribute\n        ? dom.setAttribute(key, value)\n        : (dom[key] = value);\n}\n\nfunction getAttribute(dom, key) {\n    return dom.getAttribute\n        ? dom.getAttribute(key)\n        : dom[key];\n}\n\nfunction getTooltipRenderMode(renderModeOption) {\n    if (renderModeOption === 'auto') {\n        // Using html when `document` exists, use richText otherwise\n        return env$1.domSupported ? 'html' : 'richText';\n    }\n    else {\n        return renderModeOption || 'html';\n    }\n}\n\n/**\n * Group a list by key.\n *\n * @param {Array} array\n * @param {Function} getKey\n *        param {*} Array item\n *        return {string} key\n * @return {Object} Result\n *        {Array}: keys,\n *        {module:zrender/core/util/HashMap} buckets: {key -> Array}\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TYPE_DELIMITER = '.';\nvar IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';\n\n/**\n * Notice, parseClassType('') should returns {main: '', sub: ''}\n * @public\n */\nfunction parseClassType$1(componentType) {\n    var ret = {main: '', sub: ''};\n    if (componentType) {\n        componentType = componentType.split(TYPE_DELIMITER);\n        ret.main = componentType[0] || '';\n        ret.sub = componentType[1] || '';\n    }\n    return ret;\n}\n\n/**\n * @public\n */\nfunction checkClassType(componentType) {\n    assert$1(\n        /^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType),\n        'componentType \"' + componentType + '\" illegal'\n    );\n}\n\n/**\n * @public\n */\nfunction enableClassExtend(RootClass, mandatoryMethods) {\n\n    RootClass.$constructor = RootClass;\n    RootClass.extend = function (proto) {\n\n        if (__DEV__) {\n            each$1(mandatoryMethods, function (method) {\n                if (!proto[method]) {\n                    console.warn(\n                        'Method `' + method + '` should be implemented'\n                        + (proto.type ? ' in ' + proto.type : '') + '.'\n                    );\n                }\n            });\n        }\n\n        var superClass = this;\n        var ExtendedClass = function () {\n            if (!proto.$constructor) {\n                superClass.apply(this, arguments);\n            }\n            else {\n                proto.$constructor.apply(this, arguments);\n            }\n        };\n\n        extend(ExtendedClass.prototype, proto);\n\n        ExtendedClass.extend = this.extend;\n        ExtendedClass.superCall = superCall;\n        ExtendedClass.superApply = superApply;\n        inherits(ExtendedClass, this);\n        ExtendedClass.superClass = superClass;\n\n        return ExtendedClass;\n    };\n}\n\nvar classBase = 0;\n\n/**\n * Can not use instanceof, consider different scope by\n * cross domain or es module import in ec extensions.\n * Mount a method \"isInstance()\" to Clz.\n */\nfunction enableClassCheck(Clz) {\n    var classAttr = ['__\\0is_clz', classBase++, Math.random().toFixed(3)].join('_');\n    Clz.prototype[classAttr] = true;\n\n    if (__DEV__) {\n        assert$1(!Clz.isInstance, 'The method \"is\" can not be defined.');\n    }\n\n    Clz.isInstance = function (obj) {\n        return !!(obj && obj[classAttr]);\n    };\n}\n\n// superCall should have class info, which can not be fetch from 'this'.\n// Consider this case:\n// class A has method f,\n// class B inherits class A, overrides method f, f call superApply('f'),\n// class C inherits class B, do not overrides method f,\n// then when method of class C is called, dead loop occured.\nfunction superCall(context, methodName) {\n    var args = slice(arguments, 2);\n    return this.superClass.prototype[methodName].apply(context, args);\n}\n\nfunction superApply(context, methodName, args) {\n    return this.superClass.prototype[methodName].apply(context, args);\n}\n\n/**\n * @param {Object} entity\n * @param {Object} options\n * @param {boolean} [options.registerWhenExtend]\n * @public\n */\nfunction enableClassManagement(entity, options) {\n    options = options || {};\n\n    /**\n     * Component model classes\n     * key: componentType,\n     * value:\n     *     componentClass, when componentType is 'xxx'\n     *     or Object.<subKey, componentClass>, when componentType is 'xxx.yy'\n     * @type {Object}\n     */\n    var storage = {};\n\n    entity.registerClass = function (Clazz, componentType) {\n        if (componentType) {\n            checkClassType(componentType);\n            componentType = parseClassType$1(componentType);\n\n            if (!componentType.sub) {\n                if (__DEV__) {\n                    if (storage[componentType.main]) {\n                        console.warn(componentType.main + ' exists.');\n                    }\n                }\n                storage[componentType.main] = Clazz;\n            }\n            else if (componentType.sub !== IS_CONTAINER) {\n                var container = makeContainer(componentType);\n                container[componentType.sub] = Clazz;\n            }\n        }\n        return Clazz;\n    };\n\n    entity.getClass = function (componentMainType, subType, throwWhenNotFound) {\n        var Clazz = storage[componentMainType];\n\n        if (Clazz && Clazz[IS_CONTAINER]) {\n            Clazz = subType ? Clazz[subType] : null;\n        }\n\n        if (throwWhenNotFound && !Clazz) {\n            throw new Error(\n                !subType\n                    ? componentMainType + '.' + 'type should be specified.'\n                    : 'Component ' + componentMainType + '.' + (subType || '') + ' not exists. Load it first.'\n            );\n        }\n\n        return Clazz;\n    };\n\n    entity.getClassesByMainType = function (componentType) {\n        componentType = parseClassType$1(componentType);\n\n        var result = [];\n        var obj = storage[componentType.main];\n\n        if (obj && obj[IS_CONTAINER]) {\n            each$1(obj, function (o, type) {\n                type !== IS_CONTAINER && result.push(o);\n            });\n        }\n        else {\n            result.push(obj);\n        }\n\n        return result;\n    };\n\n    entity.hasClass = function (componentType) {\n        // Just consider componentType.main.\n        componentType = parseClassType$1(componentType);\n        return !!storage[componentType.main];\n    };\n\n    /**\n     * @return {Array.<string>} Like ['aa', 'bb'], but can not be ['aa.xx']\n     */\n    entity.getAllClassMainTypes = function () {\n        var types = [];\n        each$1(storage, function (obj, type) {\n            types.push(type);\n        });\n        return types;\n    };\n\n    /**\n     * If a main type is container and has sub types\n     * @param  {string}  mainType\n     * @return {boolean}\n     */\n    entity.hasSubTypes = function (componentType) {\n        componentType = parseClassType$1(componentType);\n        var obj = storage[componentType.main];\n        return obj && obj[IS_CONTAINER];\n    };\n\n    entity.parseClassType = parseClassType$1;\n\n    function makeContainer(componentType) {\n        var container = storage[componentType.main];\n        if (!container || !container[IS_CONTAINER]) {\n            container = storage[componentType.main] = {};\n            container[IS_CONTAINER] = true;\n        }\n        return container;\n    }\n\n    if (options.registerWhenExtend) {\n        var originalExtend = entity.extend;\n        if (originalExtend) {\n            entity.extend = function (proto) {\n                var ExtendedClass = originalExtend.call(this, proto);\n                return entity.registerClass(ExtendedClass, proto.type);\n            };\n        }\n    }\n\n    return entity;\n}\n\n/**\n * @param {string|Array.<string>} properties\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Parse shadow style\n// TODO Only shallow path support\nvar makeStyleMapper = function (properties) {\n    // Normalize\n    for (var i = 0; i < properties.length; i++) {\n        if (!properties[i][1]) {\n            properties[i][1] = properties[i][0];\n        }\n    }\n    return function (model, excludes, includes) {\n        var style = {};\n        for (var i = 0; i < properties.length; i++) {\n            var propName = properties[i][1];\n            if ((excludes && indexOf(excludes, propName) >= 0)\n                || (includes && indexOf(includes, propName) < 0)\n            ) {\n                continue;\n            }\n            var val = model.getShallow(propName);\n            if (val != null) {\n                style[properties[i][0]] = val;\n            }\n        }\n        return style;\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getLineStyle = makeStyleMapper(\n    [\n        ['lineWidth', 'width'],\n        ['stroke', 'color'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor']\n    ]\n);\n\nvar lineStyleMixin = {\n    getLineStyle: function (excludes) {\n        var style = getLineStyle(this, excludes);\n        var lineDash = this.getLineDash(style.lineWidth);\n        lineDash && (style.lineDash = lineDash);\n        return style;\n    },\n\n    getLineDash: function (lineWidth) {\n        if (lineWidth == null) {\n            lineWidth = 1;\n        }\n        var lineType = this.get('type');\n        var dotSize = Math.max(lineWidth, 2);\n        var dashSize = lineWidth * 4;\n        return (lineType === 'solid' || lineType == null) ? null\n            : (lineType === 'dashed' ? [dashSize, dashSize] : [dotSize, dotSize]);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getAreaStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['opacity'],\n        ['shadowColor']\n    ]\n);\n\nvar areaStyleMixin = {\n    getAreaStyle: function (excludes, includes) {\n        return getAreaStyle(this, excludes, includes);\n    }\n};\n\n/**\n * 曲线辅助模块\n * @module zrender/core/curve\n * @author pissang(https://www.github.com/pissang)\n */\n\nvar mathPow = Math.pow;\nvar mathSqrt$2 = Math.sqrt;\n\nvar EPSILON$1 = 1e-8;\nvar EPSILON_NUMERIC = 1e-4;\n\nvar THREE_SQRT = mathSqrt$2(3);\nvar ONE_THIRD = 1 / 3;\n\n// 临时变量\nvar _v0 = create();\nvar _v1 = create();\nvar _v2 = create();\n\nfunction isAroundZero(val) {\n    return val > -EPSILON$1 && val < EPSILON$1;\n}\nfunction isNotAroundZero$1(val) {\n    return val > EPSILON$1 || val < -EPSILON$1;\n}\n/**\n * 计算三次贝塞尔值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @return {number}\n */\nfunction cubicAt(p0, p1, p2, p3, t) {\n    var onet = 1 - t;\n    return onet * onet * (onet * p0 + 3 * t * p1)\n            + t * t * (t * p3 + 3 * onet * p2);\n}\n\n/**\n * 计算三次贝塞尔导数值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @return {number}\n */\nfunction cubicDerivativeAt(p0, p1, p2, p3, t) {\n    var onet = 1 - t;\n    return 3 * (\n        ((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet\n        + (p3 - p2) * t * t\n    );\n}\n\n/**\n * 计算三次贝塞尔方程根，使用盛金公式\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} val\n * @param  {Array.<number>} roots\n * @return {number} 有效根数目\n */\nfunction cubicRootAt(p0, p1, p2, p3, val, roots) {\n    // Evaluate roots of cubic functions\n    var a = p3 + 3 * (p1 - p2) - p0;\n    var b = 3 * (p2 - p1 * 2 + p0);\n    var c = 3 * (p1 - p0);\n    var d = p0 - val;\n\n    var A = b * b - 3 * a * c;\n    var B = b * c - 9 * a * d;\n    var C = c * c - 3 * b * d;\n\n    var n = 0;\n\n    if (isAroundZero(A) && isAroundZero(B)) {\n        if (isAroundZero(b)) {\n            roots[0] = 0;\n        }\n        else {\n            var t1 = -c / b;  //t1, t2, t3, b is not zero\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = B * B - 4 * A * C;\n\n        if (isAroundZero(disc)) {\n            var K = B / A;\n            var t1 = -b / a + K;  // t1, a is not zero\n            var t2 = -K / 2;  // t2, t3\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var Y1 = A * b + 1.5 * a * (-B + discSqrt);\n            var Y2 = A * b + 1.5 * a * (-B - discSqrt);\n            if (Y1 < 0) {\n                Y1 = -mathPow(-Y1, ONE_THIRD);\n            }\n            else {\n                Y1 = mathPow(Y1, ONE_THIRD);\n            }\n            if (Y2 < 0) {\n                Y2 = -mathPow(-Y2, ONE_THIRD);\n            }\n            else {\n                Y2 = mathPow(Y2, ONE_THIRD);\n            }\n            var t1 = (-b - (Y1 + Y2)) / (3 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n        else {\n            var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt$2(A * A * A));\n            var theta = Math.acos(T) / 3;\n            var ASqrt = mathSqrt$2(A);\n            var tmp = Math.cos(theta);\n\n            var t1 = (-b - 2 * ASqrt * tmp) / (3 * a);\n            var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a);\n            var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n            if (t3 >= 0 && t3 <= 1) {\n                roots[n++] = t3;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 计算三次贝塞尔方程极限值的位置\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {Array.<number>} extrema\n * @return {number} 有效数目\n */\nfunction cubicExtrema(p0, p1, p2, p3, extrema) {\n    var b = 6 * p2 - 12 * p1 + 6 * p0;\n    var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2;\n    var c = 3 * p1 - 3 * p0;\n\n    var n = 0;\n    if (isAroundZero(a)) {\n        if (isNotAroundZero$1(b)) {\n            var t1 = -c / b;\n            if (t1 >= 0 && t1 <= 1) {\n                extrema[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = b * b - 4 * a * c;\n        if (isAroundZero(disc)) {\n            extrema[0] = -b / (2 * a);\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var t1 = (-b + discSqrt) / (2 * a);\n            var t2 = (-b - discSqrt) / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                extrema[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                extrema[n++] = t2;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 细分三次贝塞尔曲线\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @param  {Array.<number>} out\n */\nfunction cubicSubdivide(p0, p1, p2, p3, t, out) {\n    var p01 = (p1 - p0) * t + p0;\n    var p12 = (p2 - p1) * t + p1;\n    var p23 = (p3 - p2) * t + p2;\n\n    var p012 = (p12 - p01) * t + p01;\n    var p123 = (p23 - p12) * t + p12;\n\n    var p0123 = (p123 - p012) * t + p012;\n    // Seg0\n    out[0] = p0;\n    out[1] = p01;\n    out[2] = p012;\n    out[3] = p0123;\n    // Seg1\n    out[4] = p0123;\n    out[5] = p123;\n    out[6] = p23;\n    out[7] = p3;\n}\n\n/**\n * 投射点到三次贝塞尔曲线上，返回投射距离。\n * 投射点有可能会有一个或者多个，这里只返回其中距离最短的一个。\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x3\n * @param {number} y3\n * @param {number} x\n * @param {number} y\n * @param {Array.<number>} [out] 投射点\n * @return {number}\n */\nfunction cubicProjectPoint(\n    x0, y0, x1, y1, x2, y2, x3, y3,\n    x, y, out\n) {\n    // http://pomax.github.io/bezierinfo/#projections\n    var t;\n    var interval = 0.005;\n    var d = Infinity;\n    var prev;\n    var next;\n    var d1;\n    var d2;\n\n    _v0[0] = x;\n    _v0[1] = y;\n\n    // 先粗略估计一下可能的最小距离的 t 值\n    // PENDING\n    for (var _t = 0; _t < 1; _t += 0.05) {\n        _v1[0] = cubicAt(x0, x1, x2, x3, _t);\n        _v1[1] = cubicAt(y0, y1, y2, y3, _t);\n        d1 = distSquare(_v0, _v1);\n        if (d1 < d) {\n            t = _t;\n            d = d1;\n        }\n    }\n    d = Infinity;\n\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        if (interval < EPSILON_NUMERIC) {\n            break;\n        }\n        prev = t - interval;\n        next = t + interval;\n        // t - interval\n        _v1[0] = cubicAt(x0, x1, x2, x3, prev);\n        _v1[1] = cubicAt(y0, y1, y2, y3, prev);\n\n        d1 = distSquare(_v1, _v0);\n\n        if (prev >= 0 && d1 < d) {\n            t = prev;\n            d = d1;\n        }\n        else {\n            // t + interval\n            _v2[0] = cubicAt(x0, x1, x2, x3, next);\n            _v2[1] = cubicAt(y0, y1, y2, y3, next);\n            d2 = distSquare(_v2, _v0);\n\n            if (next <= 1 && d2 < d) {\n                t = next;\n                d = d2;\n            }\n            else {\n                interval *= 0.5;\n            }\n        }\n    }\n    // t\n    if (out) {\n        out[0] = cubicAt(x0, x1, x2, x3, t);\n        out[1] = cubicAt(y0, y1, y2, y3, t);\n    }\n    // console.log(interval, i);\n    return mathSqrt$2(d);\n}\n\n/**\n * 计算二次方贝塞尔值\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @return {number}\n */\nfunction quadraticAt(p0, p1, p2, t) {\n    var onet = 1 - t;\n    return onet * (onet * p0 + 2 * t * p1) + t * t * p2;\n}\n\n/**\n * 计算二次方贝塞尔导数值\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @return {number}\n */\nfunction quadraticDerivativeAt(p0, p1, p2, t) {\n    return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1));\n}\n\n/**\n * 计算二次方贝塞尔方程根\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @param  {Array.<number>} roots\n * @return {number} 有效根数目\n */\nfunction quadraticRootAt(p0, p1, p2, val, roots) {\n    var a = p0 - 2 * p1 + p2;\n    var b = 2 * (p1 - p0);\n    var c = p0 - val;\n\n    var n = 0;\n    if (isAroundZero(a)) {\n        if (isNotAroundZero$1(b)) {\n            var t1 = -c / b;\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = b * b - 4 * a * c;\n        if (isAroundZero(disc)) {\n            var t1 = -b / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var t1 = (-b + discSqrt) / (2 * a);\n            var t2 = (-b - discSqrt) / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 计算二次贝塞尔方程极限值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @return {number}\n */\nfunction quadraticExtremum(p0, p1, p2) {\n    var divider = p0 + p2 - 2 * p1;\n    if (divider === 0) {\n        // p1 is center of p0 and p2\n        return 0.5;\n    }\n    else {\n        return (p0 - p1) / divider;\n    }\n}\n\n/**\n * 细分二次贝塞尔曲线\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @param  {Array.<number>} out\n */\nfunction quadraticSubdivide(p0, p1, p2, t, out) {\n    var p01 = (p1 - p0) * t + p0;\n    var p12 = (p2 - p1) * t + p1;\n    var p012 = (p12 - p01) * t + p01;\n\n    // Seg0\n    out[0] = p0;\n    out[1] = p01;\n    out[2] = p012;\n\n    // Seg1\n    out[3] = p012;\n    out[4] = p12;\n    out[5] = p2;\n}\n\n/**\n * 投射点到二次贝塞尔曲线上，返回投射距离。\n * 投射点有可能会有一个或者多个，这里只返回其中距离最短的一个。\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x\n * @param {number} y\n * @param {Array.<number>} out 投射点\n * @return {number}\n */\nfunction quadraticProjectPoint(\n    x0, y0, x1, y1, x2, y2,\n    x, y, out\n) {\n    // http://pomax.github.io/bezierinfo/#projections\n    var t;\n    var interval = 0.005;\n    var d = Infinity;\n\n    _v0[0] = x;\n    _v0[1] = y;\n\n    // 先粗略估计一下可能的最小距离的 t 值\n    // PENDING\n    for (var _t = 0; _t < 1; _t += 0.05) {\n        _v1[0] = quadraticAt(x0, x1, x2, _t);\n        _v1[1] = quadraticAt(y0, y1, y2, _t);\n        var d1 = distSquare(_v0, _v1);\n        if (d1 < d) {\n            t = _t;\n            d = d1;\n        }\n    }\n    d = Infinity;\n\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        if (interval < EPSILON_NUMERIC) {\n            break;\n        }\n        var prev = t - interval;\n        var next = t + interval;\n        // t - interval\n        _v1[0] = quadraticAt(x0, x1, x2, prev);\n        _v1[1] = quadraticAt(y0, y1, y2, prev);\n\n        var d1 = distSquare(_v1, _v0);\n\n        if (prev >= 0 && d1 < d) {\n            t = prev;\n            d = d1;\n        }\n        else {\n            // t + interval\n            _v2[0] = quadraticAt(x0, x1, x2, next);\n            _v2[1] = quadraticAt(y0, y1, y2, next);\n            var d2 = distSquare(_v2, _v0);\n            if (next <= 1 && d2 < d) {\n                t = next;\n                d = d2;\n            }\n            else {\n                interval *= 0.5;\n            }\n        }\n    }\n    // t\n    if (out) {\n        out[0] = quadraticAt(x0, x1, x2, t);\n        out[1] = quadraticAt(y0, y1, y2, t);\n    }\n    // console.log(interval, i);\n    return mathSqrt$2(d);\n}\n\n/**\n * @author Yi Shen(https://github.com/pissang)\n */\n\nvar mathMin$3 = Math.min;\nvar mathMax$3 = Math.max;\nvar mathSin$2 = Math.sin;\nvar mathCos$2 = Math.cos;\nvar PI2 = Math.PI * 2;\n\nvar start = create();\nvar end = create();\nvar extremity = create();\n\n/**\n * 从顶点数组中计算出最小包围盒，写入`min`和`max`中\n * @module zrender/core/bbox\n * @param {Array<Object>} points 顶点数组\n * @param {number} min\n * @param {number} max\n */\n\n\n/**\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromLine(x0, y0, x1, y1, min$$1, max$$1) {\n    min$$1[0] = mathMin$3(x0, x1);\n    min$$1[1] = mathMin$3(y0, y1);\n    max$$1[0] = mathMax$3(x0, x1);\n    max$$1[1] = mathMax$3(y0, y1);\n}\n\nvar xDim = [];\nvar yDim = [];\n/**\n * 从三阶贝塞尔曲线(p0, p1, p2, p3)中计算出最小包围盒，写入`min`和`max`中\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x3\n * @param {number} y3\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromCubic(\n    x0, y0, x1, y1, x2, y2, x3, y3, min$$1, max$$1\n) {\n    var cubicExtrema$$1 = cubicExtrema;\n    var cubicAt$$1 = cubicAt;\n    var i;\n    var n = cubicExtrema$$1(x0, x1, x2, x3, xDim);\n    min$$1[0] = Infinity;\n    min$$1[1] = Infinity;\n    max$$1[0] = -Infinity;\n    max$$1[1] = -Infinity;\n\n    for (i = 0; i < n; i++) {\n        var x = cubicAt$$1(x0, x1, x2, x3, xDim[i]);\n        min$$1[0] = mathMin$3(x, min$$1[0]);\n        max$$1[0] = mathMax$3(x, max$$1[0]);\n    }\n    n = cubicExtrema$$1(y0, y1, y2, y3, yDim);\n    for (i = 0; i < n; i++) {\n        var y = cubicAt$$1(y0, y1, y2, y3, yDim[i]);\n        min$$1[1] = mathMin$3(y, min$$1[1]);\n        max$$1[1] = mathMax$3(y, max$$1[1]);\n    }\n\n    min$$1[0] = mathMin$3(x0, min$$1[0]);\n    max$$1[0] = mathMax$3(x0, max$$1[0]);\n    min$$1[0] = mathMin$3(x3, min$$1[0]);\n    max$$1[0] = mathMax$3(x3, max$$1[0]);\n\n    min$$1[1] = mathMin$3(y0, min$$1[1]);\n    max$$1[1] = mathMax$3(y0, max$$1[1]);\n    min$$1[1] = mathMin$3(y3, min$$1[1]);\n    max$$1[1] = mathMax$3(y3, max$$1[1]);\n}\n\n/**\n * 从二阶贝塞尔曲线(p0, p1, p2)中计算出最小包围盒，写入`min`和`max`中\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromQuadratic(x0, y0, x1, y1, x2, y2, min$$1, max$$1) {\n    var quadraticExtremum$$1 = quadraticExtremum;\n    var quadraticAt$$1 = quadraticAt;\n    // Find extremities, where derivative in x dim or y dim is zero\n    var tx =\n        mathMax$3(\n            mathMin$3(quadraticExtremum$$1(x0, x1, x2), 1), 0\n        );\n    var ty =\n        mathMax$3(\n            mathMin$3(quadraticExtremum$$1(y0, y1, y2), 1), 0\n        );\n\n    var x = quadraticAt$$1(x0, x1, x2, tx);\n    var y = quadraticAt$$1(y0, y1, y2, ty);\n\n    min$$1[0] = mathMin$3(x0, x2, x);\n    min$$1[1] = mathMin$3(y0, y2, y);\n    max$$1[0] = mathMax$3(x0, x2, x);\n    max$$1[1] = mathMax$3(y0, y2, y);\n}\n\n/**\n * 从圆弧中计算出最小包围盒，写入`min`和`max`中\n * @method\n * @memberOf module:zrender/core/bbox\n * @param {number} x\n * @param {number} y\n * @param {number} rx\n * @param {number} ry\n * @param {number} startAngle\n * @param {number} endAngle\n * @param {number} anticlockwise\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromArc(\n    x, y, rx, ry, startAngle, endAngle, anticlockwise, min$$1, max$$1\n) {\n    var vec2Min = min;\n    var vec2Max = max;\n\n    var diff = Math.abs(startAngle - endAngle);\n\n\n    if (diff % PI2 < 1e-4 && diff > 1e-4) {\n        // Is a circle\n        min$$1[0] = x - rx;\n        min$$1[1] = y - ry;\n        max$$1[0] = x + rx;\n        max$$1[1] = y + ry;\n        return;\n    }\n\n    start[0] = mathCos$2(startAngle) * rx + x;\n    start[1] = mathSin$2(startAngle) * ry + y;\n\n    end[0] = mathCos$2(endAngle) * rx + x;\n    end[1] = mathSin$2(endAngle) * ry + y;\n\n    vec2Min(min$$1, start, end);\n    vec2Max(max$$1, start, end);\n\n    // Thresh to [0, Math.PI * 2]\n    startAngle = startAngle % (PI2);\n    if (startAngle < 0) {\n        startAngle = startAngle + PI2;\n    }\n    endAngle = endAngle % (PI2);\n    if (endAngle < 0) {\n        endAngle = endAngle + PI2;\n    }\n\n    if (startAngle > endAngle && !anticlockwise) {\n        endAngle += PI2;\n    }\n    else if (startAngle < endAngle && anticlockwise) {\n        startAngle += PI2;\n    }\n    if (anticlockwise) {\n        var tmp = endAngle;\n        endAngle = startAngle;\n        startAngle = tmp;\n    }\n\n    // var number = 0;\n    // var step = (anticlockwise ? -Math.PI : Math.PI) / 2;\n    for (var angle = 0; angle < endAngle; angle += Math.PI / 2) {\n        if (angle > startAngle) {\n            extremity[0] = mathCos$2(angle) * rx + x;\n            extremity[1] = mathSin$2(angle) * ry + y;\n\n            vec2Min(min$$1, extremity, min$$1);\n            vec2Max(max$$1, extremity, max$$1);\n        }\n    }\n}\n\n/**\n * Path 代理，可以在`buildPath`中用于替代`ctx`, 会保存每个path操作的命令到pathCommands属性中\n * 可以用于 isInsidePath 判断以及获取boundingRect\n *\n * @module zrender/core/PathProxy\n * @author Yi Shen (http://www.github.com/pissang)\n */\n\n// TODO getTotalLength, getPointAtLength\n\nvar CMD = {\n    M: 1,\n    L: 2,\n    C: 3,\n    Q: 4,\n    A: 5,\n    Z: 6,\n    // Rect\n    R: 7\n};\n\n// var CMD_MEM_SIZE = {\n//     M: 3,\n//     L: 3,\n//     C: 7,\n//     Q: 5,\n//     A: 9,\n//     R: 5,\n//     Z: 1\n// };\n\nvar min$1 = [];\nvar max$1 = [];\nvar min2 = [];\nvar max2 = [];\nvar mathMin$2 = Math.min;\nvar mathMax$2 = Math.max;\nvar mathCos$1 = Math.cos;\nvar mathSin$1 = Math.sin;\nvar mathSqrt$1 = Math.sqrt;\nvar mathAbs = Math.abs;\n\nvar hasTypedArray = typeof Float32Array !== 'undefined';\n\n/**\n * @alias module:zrender/core/PathProxy\n * @constructor\n */\nvar PathProxy = function (notSaveData) {\n\n    this._saveData = !(notSaveData || false);\n\n    if (this._saveData) {\n        /**\n         * Path data. Stored as flat array\n         * @type {Array.<Object>}\n         */\n        this.data = [];\n    }\n\n    this._ctx = null;\n};\n\n/**\n * 快速计算Path包围盒（并不是最小包围盒）\n * @return {Object}\n */\nPathProxy.prototype = {\n\n    constructor: PathProxy,\n\n    _xi: 0,\n    _yi: 0,\n\n    _x0: 0,\n    _y0: 0,\n    // Unit x, Unit y. Provide for avoiding drawing that too short line segment\n    _ux: 0,\n    _uy: 0,\n\n    _len: 0,\n\n    _lineDash: null,\n\n    _dashOffset: 0,\n\n    _dashIdx: 0,\n\n    _dashSum: 0,\n\n    /**\n     * @readOnly\n     */\n    setScale: function (sx, sy) {\n        this._ux = mathAbs(1 / devicePixelRatio / sx) || 0;\n        this._uy = mathAbs(1 / devicePixelRatio / sy) || 0;\n    },\n\n    getContext: function () {\n        return this._ctx;\n    },\n\n    /**\n     * @param  {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    beginPath: function (ctx) {\n\n        this._ctx = ctx;\n\n        ctx && ctx.beginPath();\n\n        ctx && (this.dpr = ctx.dpr);\n\n        // Reset\n        if (this._saveData) {\n            this._len = 0;\n        }\n\n        if (this._lineDash) {\n            this._lineDash = null;\n\n            this._dashOffset = 0;\n        }\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x\n     * @param  {number} y\n     * @return {module:zrender/core/PathProxy}\n     */\n    moveTo: function (x, y) {\n        this.addData(CMD.M, x, y);\n        this._ctx && this._ctx.moveTo(x, y);\n\n        // x0, y0, xi, yi 是记录在 _dashedXXXXTo 方法中使用\n        // xi, yi 记录当前点, x0, y0 在 closePath 的时候回到起始点。\n        // 有可能在 beginPath 之后直接调用 lineTo，这时候 x0, y0 需要\n        // 在 lineTo 方法中记录，这里先不考虑这种情况，dashed line 也只在 IE10- 中不支持\n        this._x0 = x;\n        this._y0 = y;\n\n        this._xi = x;\n        this._yi = y;\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x\n     * @param  {number} y\n     * @return {module:zrender/core/PathProxy}\n     */\n    lineTo: function (x, y) {\n        var exceedUnit = mathAbs(x - this._xi) > this._ux\n            || mathAbs(y - this._yi) > this._uy\n            // Force draw the first segment\n            || this._len < 5;\n\n        this.addData(CMD.L, x, y);\n\n        if (this._ctx && exceedUnit) {\n            this._needsDash() ? this._dashedLineTo(x, y)\n                : this._ctx.lineTo(x, y);\n        }\n        if (exceedUnit) {\n            this._xi = x;\n            this._yi = y;\n        }\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x1\n     * @param  {number} y1\n     * @param  {number} x2\n     * @param  {number} y2\n     * @param  {number} x3\n     * @param  {number} y3\n     * @return {module:zrender/core/PathProxy}\n     */\n    bezierCurveTo: function (x1, y1, x2, y2, x3, y3) {\n        this.addData(CMD.C, x1, y1, x2, y2, x3, y3);\n        if (this._ctx) {\n            this._needsDash() ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3)\n                : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);\n        }\n        this._xi = x3;\n        this._yi = y3;\n        return this;\n    },\n\n    /**\n     * @param  {number} x1\n     * @param  {number} y1\n     * @param  {number} x2\n     * @param  {number} y2\n     * @return {module:zrender/core/PathProxy}\n     */\n    quadraticCurveTo: function (x1, y1, x2, y2) {\n        this.addData(CMD.Q, x1, y1, x2, y2);\n        if (this._ctx) {\n            this._needsDash() ? this._dashedQuadraticTo(x1, y1, x2, y2)\n                : this._ctx.quadraticCurveTo(x1, y1, x2, y2);\n        }\n        this._xi = x2;\n        this._yi = y2;\n        return this;\n    },\n\n    /**\n     * @param  {number} cx\n     * @param  {number} cy\n     * @param  {number} r\n     * @param  {number} startAngle\n     * @param  {number} endAngle\n     * @param  {boolean} anticlockwise\n     * @return {module:zrender/core/PathProxy}\n     */\n    arc: function (cx, cy, r, startAngle, endAngle, anticlockwise) {\n        this.addData(\n            CMD.A, cx, cy, r, r, startAngle, endAngle - startAngle, 0, anticlockwise ? 0 : 1\n        );\n        this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);\n\n        this._xi = mathCos$1(endAngle) * r + cx;\n        this._yi = mathSin$1(endAngle) * r + cy;\n        return this;\n    },\n\n    // TODO\n    arcTo: function (x1, y1, x2, y2, radius) {\n        if (this._ctx) {\n            this._ctx.arcTo(x1, y1, x2, y2, radius);\n        }\n        return this;\n    },\n\n    // TODO\n    rect: function (x, y, w, h) {\n        this._ctx && this._ctx.rect(x, y, w, h);\n        this.addData(CMD.R, x, y, w, h);\n        return this;\n    },\n\n    /**\n     * @return {module:zrender/core/PathProxy}\n     */\n    closePath: function () {\n        this.addData(CMD.Z);\n\n        var ctx = this._ctx;\n        var x0 = this._x0;\n        var y0 = this._y0;\n        if (ctx) {\n            this._needsDash() && this._dashedLineTo(x0, y0);\n            ctx.closePath();\n        }\n\n        this._xi = x0;\n        this._yi = y0;\n        return this;\n    },\n\n    /**\n     * Context 从外部传入，因为有可能是 rebuildPath 完之后再 fill。\n     * stroke 同样\n     * @param {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    fill: function (ctx) {\n        ctx && ctx.fill();\n        this.toStatic();\n    },\n\n    /**\n     * @param {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    stroke: function (ctx) {\n        ctx && ctx.stroke();\n        this.toStatic();\n    },\n\n    /**\n     * 必须在其它绘制命令前调用\n     * Must be invoked before all other path drawing methods\n     * @return {module:zrender/core/PathProxy}\n     */\n    setLineDash: function (lineDash) {\n        if (lineDash instanceof Array) {\n            this._lineDash = lineDash;\n\n            this._dashIdx = 0;\n\n            var lineDashSum = 0;\n            for (var i = 0; i < lineDash.length; i++) {\n                lineDashSum += lineDash[i];\n            }\n            this._dashSum = lineDashSum;\n        }\n        return this;\n    },\n\n    /**\n     * 必须在其它绘制命令前调用\n     * Must be invoked before all other path drawing methods\n     * @return {module:zrender/core/PathProxy}\n     */\n    setLineDashOffset: function (offset) {\n        this._dashOffset = offset;\n        return this;\n    },\n\n    /**\n     *\n     * @return {boolean}\n     */\n    len: function () {\n        return this._len;\n    },\n\n    /**\n     * 直接设置 Path 数据\n     */\n    setData: function (data) {\n\n        var len$$1 = data.length;\n\n        if (!(this.data && this.data.length === len$$1) && hasTypedArray) {\n            this.data = new Float32Array(len$$1);\n        }\n\n        for (var i = 0; i < len$$1; i++) {\n            this.data[i] = data[i];\n        }\n\n        this._len = len$$1;\n    },\n\n    /**\n     * 添加子路径\n     * @param {module:zrender/core/PathProxy|Array.<module:zrender/core/PathProxy>} path\n     */\n    appendPath: function (path) {\n        if (!(path instanceof Array)) {\n            path = [path];\n        }\n        var len$$1 = path.length;\n        var appendSize = 0;\n        var offset = this._len;\n        for (var i = 0; i < len$$1; i++) {\n            appendSize += path[i].len();\n        }\n        if (hasTypedArray && (this.data instanceof Float32Array)) {\n            this.data = new Float32Array(offset + appendSize);\n        }\n        for (var i = 0; i < len$$1; i++) {\n            var appendPathData = path[i].data;\n            for (var k = 0; k < appendPathData.length; k++) {\n                this.data[offset++] = appendPathData[k];\n            }\n        }\n        this._len = offset;\n    },\n\n    /**\n     * 填充 Path 数据。\n     * 尽量复用而不申明新的数组。大部分图形重绘的指令数据长度都是不变的。\n     */\n    addData: function (cmd) {\n        if (!this._saveData) {\n            return;\n        }\n\n        var data = this.data;\n        if (this._len + arguments.length > data.length) {\n            // 因为之前的数组已经转换成静态的 Float32Array\n            // 所以不够用时需要扩展一个新的动态数组\n            this._expandData();\n            data = this.data;\n        }\n        for (var i = 0; i < arguments.length; i++) {\n            data[this._len++] = arguments[i];\n        }\n\n        this._prevCmd = cmd;\n    },\n\n    _expandData: function () {\n        // Only if data is Float32Array\n        if (!(this.data instanceof Array)) {\n            var newData = [];\n            for (var i = 0; i < this._len; i++) {\n                newData[i] = this.data[i];\n            }\n            this.data = newData;\n        }\n    },\n\n    /**\n     * If needs js implemented dashed line\n     * @return {boolean}\n     * @private\n     */\n    _needsDash: function () {\n        return this._lineDash;\n    },\n\n    _dashedLineTo: function (x1, y1) {\n        var dashSum = this._dashSum;\n        var offset = this._dashOffset;\n        var lineDash = this._lineDash;\n        var ctx = this._ctx;\n\n        var x0 = this._xi;\n        var y0 = this._yi;\n        var dx = x1 - x0;\n        var dy = y1 - y0;\n        var dist$$1 = mathSqrt$1(dx * dx + dy * dy);\n        var x = x0;\n        var y = y0;\n        var dash;\n        var nDash = lineDash.length;\n        var idx;\n        dx /= dist$$1;\n        dy /= dist$$1;\n\n        if (offset < 0) {\n            // Convert to positive offset\n            offset = dashSum + offset;\n        }\n        offset %= dashSum;\n        x -= offset * dx;\n        y -= offset * dy;\n\n        while ((dx > 0 && x <= x1) || (dx < 0 && x >= x1)\n        || (dx === 0 && ((dy > 0 && y <= y1) || (dy < 0 && y >= y1)))) {\n            idx = this._dashIdx;\n            dash = lineDash[idx];\n            x += dx * dash;\n            y += dy * dash;\n            this._dashIdx = (idx + 1) % nDash;\n            // Skip positive offset\n            if ((dx > 0 && x < x0) || (dx < 0 && x > x0) || (dy > 0 && y < y0) || (dy < 0 && y > y0)) {\n                continue;\n            }\n            ctx[idx % 2 ? 'moveTo' : 'lineTo'](\n                dx >= 0 ? mathMin$2(x, x1) : mathMax$2(x, x1),\n                dy >= 0 ? mathMin$2(y, y1) : mathMax$2(y, y1)\n            );\n        }\n        // Offset for next lineTo\n        dx = x - x1;\n        dy = y - y1;\n        this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);\n    },\n\n    // Not accurate dashed line to\n    _dashedBezierTo: function (x1, y1, x2, y2, x3, y3) {\n        var dashSum = this._dashSum;\n        var offset = this._dashOffset;\n        var lineDash = this._lineDash;\n        var ctx = this._ctx;\n\n        var x0 = this._xi;\n        var y0 = this._yi;\n        var t;\n        var dx;\n        var dy;\n        var cubicAt$$1 = cubicAt;\n        var bezierLen = 0;\n        var idx = this._dashIdx;\n        var nDash = lineDash.length;\n\n        var x;\n        var y;\n\n        var tmpLen = 0;\n\n        if (offset < 0) {\n            // Convert to positive offset\n            offset = dashSum + offset;\n        }\n        offset %= dashSum;\n        // Bezier approx length\n        for (t = 0; t < 1; t += 0.1) {\n            dx = cubicAt$$1(x0, x1, x2, x3, t + 0.1)\n                - cubicAt$$1(x0, x1, x2, x3, t);\n            dy = cubicAt$$1(y0, y1, y2, y3, t + 0.1)\n                - cubicAt$$1(y0, y1, y2, y3, t);\n            bezierLen += mathSqrt$1(dx * dx + dy * dy);\n        }\n\n        // Find idx after add offset\n        for (; idx < nDash; idx++) {\n            tmpLen += lineDash[idx];\n            if (tmpLen > offset) {\n                break;\n            }\n        }\n        t = (tmpLen - offset) / bezierLen;\n\n        while (t <= 1) {\n\n            x = cubicAt$$1(x0, x1, x2, x3, t);\n            y = cubicAt$$1(y0, y1, y2, y3, t);\n\n            // Use line to approximate dashed bezier\n            // Bad result if dash is long\n            idx % 2 ? ctx.moveTo(x, y)\n                : ctx.lineTo(x, y);\n\n            t += lineDash[idx] / bezierLen;\n\n            idx = (idx + 1) % nDash;\n        }\n\n        // Finish the last segment and calculate the new offset\n        (idx % 2 !== 0) && ctx.lineTo(x3, y3);\n        dx = x3 - x;\n        dy = y3 - y;\n        this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);\n    },\n\n    _dashedQuadraticTo: function (x1, y1, x2, y2) {\n        // Convert quadratic to cubic using degree elevation\n        var x3 = x2;\n        var y3 = y2;\n        x2 = (x2 + 2 * x1) / 3;\n        y2 = (y2 + 2 * y1) / 3;\n        x1 = (this._xi + 2 * x1) / 3;\n        y1 = (this._yi + 2 * y1) / 3;\n\n        this._dashedBezierTo(x1, y1, x2, y2, x3, y3);\n    },\n\n    /**\n     * 转成静态的 Float32Array 减少堆内存占用\n     * Convert dynamic array to static Float32Array\n     */\n    toStatic: function () {\n        var data = this.data;\n        if (data instanceof Array) {\n            data.length = this._len;\n            if (hasTypedArray) {\n                this.data = new Float32Array(data);\n            }\n        }\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function () {\n        min$1[0] = min$1[1] = min2[0] = min2[1] = Number.MAX_VALUE;\n        max$1[0] = max$1[1] = max2[0] = max2[1] = -Number.MAX_VALUE;\n\n        var data = this.data;\n        var xi = 0;\n        var yi = 0;\n        var x0 = 0;\n        var y0 = 0;\n\n        for (var i = 0; i < data.length;) {\n            var cmd = data[i++];\n\n            if (i === 1) {\n                // 如果第一个命令是 L, C, Q\n                // 则 previous point 同绘制命令的第一个 point\n                //\n                // 第一个命令为 Arc 的情况下会在后面特殊处理\n                xi = data[i];\n                yi = data[i + 1];\n\n                x0 = xi;\n                y0 = yi;\n            }\n\n            switch (cmd) {\n                case CMD.M:\n                    // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点\n                    // 在 closePath 的时候使用\n                    x0 = data[i++];\n                    y0 = data[i++];\n                    xi = x0;\n                    yi = y0;\n                    min2[0] = x0;\n                    min2[1] = y0;\n                    max2[0] = x0;\n                    max2[1] = y0;\n                    break;\n                case CMD.L:\n                    fromLine(xi, yi, data[i], data[i + 1], min2, max2);\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.C:\n                    fromCubic(\n                        xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        min2, max2\n                    );\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.Q:\n                    fromQuadratic(\n                        xi, yi, data[i++], data[i++], data[i], data[i + 1],\n                        min2, max2\n                    );\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.A:\n                    // TODO Arc 判断的开销比较大\n                    var cx = data[i++];\n                    var cy = data[i++];\n                    var rx = data[i++];\n                    var ry = data[i++];\n                    var startAngle = data[i++];\n                    var endAngle = data[i++] + startAngle;\n                    // TODO Arc 旋转\n                    i += 1;\n                    var anticlockwise = 1 - data[i++];\n\n                    if (i === 1) {\n                        // 直接使用 arc 命令\n                        // 第一个命令起点还未定义\n                        x0 = mathCos$1(startAngle) * rx + cx;\n                        y0 = mathSin$1(startAngle) * ry + cy;\n                    }\n\n                    fromArc(\n                        cx, cy, rx, ry, startAngle, endAngle,\n                        anticlockwise, min2, max2\n                    );\n\n                    xi = mathCos$1(endAngle) * rx + cx;\n                    yi = mathSin$1(endAngle) * ry + cy;\n                    break;\n                case CMD.R:\n                    x0 = xi = data[i++];\n                    y0 = yi = data[i++];\n                    var width = data[i++];\n                    var height = data[i++];\n                    // Use fromLine\n                    fromLine(x0, y0, x0 + width, y0 + height, min2, max2);\n                    break;\n                case CMD.Z:\n                    xi = x0;\n                    yi = y0;\n                    break;\n            }\n\n            // Union\n            min(min$1, min$1, min2);\n            max(max$1, max$1, max2);\n        }\n\n        // No data\n        if (i === 0) {\n            min$1[0] = min$1[1] = max$1[0] = max$1[1] = 0;\n        }\n\n        return new BoundingRect(\n            min$1[0], min$1[1], max$1[0] - min$1[0], max$1[1] - min$1[1]\n        );\n    },\n\n    /**\n     * Rebuild path from current data\n     * Rebuild path will not consider javascript implemented line dash.\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    rebuildPath: function (ctx) {\n        var d = this.data;\n        var x0, y0;\n        var xi, yi;\n        var x, y;\n        var ux = this._ux;\n        var uy = this._uy;\n        var len$$1 = this._len;\n        for (var i = 0; i < len$$1;) {\n            var cmd = d[i++];\n\n            if (i === 1) {\n                // 如果第一个命令是 L, C, Q\n                // 则 previous point 同绘制命令的第一个 point\n                //\n                // 第一个命令为 Arc 的情况下会在后面特殊处理\n                xi = d[i];\n                yi = d[i + 1];\n\n                x0 = xi;\n                y0 = yi;\n            }\n            switch (cmd) {\n                case CMD.M:\n                    x0 = xi = d[i++];\n                    y0 = yi = d[i++];\n                    ctx.moveTo(xi, yi);\n                    break;\n                case CMD.L:\n                    x = d[i++];\n                    y = d[i++];\n                    // Not draw too small seg between\n                    if (mathAbs(x - xi) > ux || mathAbs(y - yi) > uy || i === len$$1 - 1) {\n                        ctx.lineTo(x, y);\n                        xi = x;\n                        yi = y;\n                    }\n                    break;\n                case CMD.C:\n                    ctx.bezierCurveTo(\n                        d[i++], d[i++], d[i++], d[i++], d[i++], d[i++]\n                    );\n                    xi = d[i - 2];\n                    yi = d[i - 1];\n                    break;\n                case CMD.Q:\n                    ctx.quadraticCurveTo(d[i++], d[i++], d[i++], d[i++]);\n                    xi = d[i - 2];\n                    yi = d[i - 1];\n                    break;\n                case CMD.A:\n                    var cx = d[i++];\n                    var cy = d[i++];\n                    var rx = d[i++];\n                    var ry = d[i++];\n                    var theta = d[i++];\n                    var dTheta = d[i++];\n                    var psi = d[i++];\n                    var fs = d[i++];\n                    var r = (rx > ry) ? rx : ry;\n                    var scaleX = (rx > ry) ? 1 : rx / ry;\n                    var scaleY = (rx > ry) ? ry / rx : 1;\n                    var isEllipse = Math.abs(rx - ry) > 1e-3;\n                    var endAngle = theta + dTheta;\n                    if (isEllipse) {\n                        ctx.translate(cx, cy);\n                        ctx.rotate(psi);\n                        ctx.scale(scaleX, scaleY);\n                        ctx.arc(0, 0, r, theta, endAngle, 1 - fs);\n                        ctx.scale(1 / scaleX, 1 / scaleY);\n                        ctx.rotate(-psi);\n                        ctx.translate(-cx, -cy);\n                    }\n                    else {\n                        ctx.arc(cx, cy, r, theta, endAngle, 1 - fs);\n                    }\n\n                    if (i === 1) {\n                        // 直接使用 arc 命令\n                        // 第一个命令起点还未定义\n                        x0 = mathCos$1(theta) * rx + cx;\n                        y0 = mathSin$1(theta) * ry + cy;\n                    }\n                    xi = mathCos$1(endAngle) * rx + cx;\n                    yi = mathSin$1(endAngle) * ry + cy;\n                    break;\n                case CMD.R:\n                    x0 = xi = d[i];\n                    y0 = yi = d[i + 1];\n                    ctx.rect(d[i++], d[i++], d[i++], d[i++]);\n                    break;\n                case CMD.Z:\n                    ctx.closePath();\n                    xi = x0;\n                    yi = y0;\n            }\n        }\n    }\n};\n\nPathProxy.CMD = CMD;\n\n/**\n * 线段包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$1(x0, y0, x1, y1, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    var _a = 0;\n    var _b = x0;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l)\n        || (y < y0 - _l && y < y1 - _l)\n        || (x > x0 + _l && x > x1 + _l)\n        || (x < x0 - _l && x < x1 - _l)\n    ) {\n        return false;\n    }\n\n    if (x0 !== x1) {\n        _a = (y0 - y1) / (x0 - x1);\n        _b = (x0 * y1 - x1 * y0) / (x0 - x1);\n    }\n    else {\n        return Math.abs(x - x0) <= _l / 2;\n    }\n    var tmp = _a * x - y + _b;\n    var _s = tmp * tmp / (_a * _a + 1);\n    return _s <= _l / 2 * _l / 2;\n}\n\n/**\n * 三次贝塞尔曲线描边包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  x2\n * @param  {number}  y2\n * @param  {number}  x3\n * @param  {number}  y3\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$2(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l)\n        || (y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l)\n        || (x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l)\n        || (x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l)\n    ) {\n        return false;\n    }\n    var d = cubicProjectPoint(\n        x0, y0, x1, y1, x2, y2, x3, y3,\n        x, y, null\n    );\n    return d <= _l / 2;\n}\n\n/**\n * 二次贝塞尔曲线描边包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  x2\n * @param  {number}  y2\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$3(x0, y0, x1, y1, x2, y2, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l && y > y2 + _l)\n        || (y < y0 - _l && y < y1 - _l && y < y2 - _l)\n        || (x > x0 + _l && x > x1 + _l && x > x2 + _l)\n        || (x < x0 - _l && x < x1 - _l && x < x2 - _l)\n    ) {\n        return false;\n    }\n    var d = quadraticProjectPoint(\n        x0, y0, x1, y1, x2, y2,\n        x, y, null\n    );\n    return d <= _l / 2;\n}\n\nvar PI2$3 = Math.PI * 2;\n\nfunction normalizeRadian(angle) {\n    angle %= PI2$3;\n    if (angle < 0) {\n        angle += PI2$3;\n    }\n    return angle;\n}\n\nvar PI2$2 = Math.PI * 2;\n\n/**\n * 圆弧描边包含判断\n * @param  {number}  cx\n * @param  {number}  cy\n * @param  {number}  r\n * @param  {number}  startAngle\n * @param  {number}  endAngle\n * @param  {boolean}  anticlockwise\n * @param  {number} lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {Boolean}\n */\nfunction containStroke$4(\n    cx, cy, r, startAngle, endAngle, anticlockwise,\n    lineWidth, x, y\n) {\n\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n\n    x -= cx;\n    y -= cy;\n    var d = Math.sqrt(x * x + y * y);\n\n    if ((d - _l > r) || (d + _l < r)) {\n        return false;\n    }\n    if (Math.abs(startAngle - endAngle) % PI2$2 < 1e-4) {\n        // Is a circle\n        return true;\n    }\n    if (anticlockwise) {\n        var tmp = startAngle;\n        startAngle = normalizeRadian(endAngle);\n        endAngle = normalizeRadian(tmp);\n    }\n    else {\n        startAngle = normalizeRadian(startAngle);\n        endAngle = normalizeRadian(endAngle);\n    }\n    if (startAngle > endAngle) {\n        endAngle += PI2$2;\n    }\n\n    var angle = Math.atan2(y, x);\n    if (angle < 0) {\n        angle += PI2$2;\n    }\n    return (angle >= startAngle && angle <= endAngle)\n        || (angle + PI2$2 >= startAngle && angle + PI2$2 <= endAngle);\n}\n\nfunction windingLine(x0, y0, x1, y1, x, y) {\n    if ((y > y0 && y > y1) || (y < y0 && y < y1)) {\n        return 0;\n    }\n    // Ignore horizontal line\n    if (y1 === y0) {\n        return 0;\n    }\n    var dir = y1 < y0 ? 1 : -1;\n    var t = (y - y0) / (y1 - y0);\n\n    // Avoid winding error when intersection point is the connect point of two line of polygon\n    if (t === 1 || t === 0) {\n        dir = y1 < y0 ? 0.5 : -0.5;\n    }\n\n    var x_ = t * (x1 - x0) + x0;\n\n    // If (x, y) on the line, considered as \"contain\".\n    return x_ === x ? Infinity : x_ > x ? dir : 0;\n}\n\nvar CMD$1 = PathProxy.CMD;\nvar PI2$1 = Math.PI * 2;\n\nvar EPSILON$2 = 1e-4;\n\nfunction isAroundEqual(a, b) {\n    return Math.abs(a - b) < EPSILON$2;\n}\n\n// 临时数组\nvar roots = [-1, -1, -1];\nvar extrema = [-1, -1];\n\nfunction swapExtrema() {\n    var tmp = extrema[0];\n    extrema[0] = extrema[1];\n    extrema[1] = tmp;\n}\n\nfunction windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {\n    // Quick reject\n    if (\n        (y > y0 && y > y1 && y > y2 && y > y3)\n        || (y < y0 && y < y1 && y < y2 && y < y3)\n    ) {\n        return 0;\n    }\n    var nRoots = cubicRootAt(y0, y1, y2, y3, y, roots);\n    if (nRoots === 0) {\n        return 0;\n    }\n    else {\n        var w = 0;\n        var nExtrema = -1;\n        var y0_;\n        var y1_;\n        for (var i = 0; i < nRoots; i++) {\n            var t = roots[i];\n\n            // Avoid winding error when intersection point is the connect point of two line of polygon\n            var unit = (t === 0 || t === 1) ? 0.5 : 1;\n\n            var x_ = cubicAt(x0, x1, x2, x3, t);\n            if (x_ < x) { // Quick reject\n                continue;\n            }\n            if (nExtrema < 0) {\n                nExtrema = cubicExtrema(y0, y1, y2, y3, extrema);\n                if (extrema[1] < extrema[0] && nExtrema > 1) {\n                    swapExtrema();\n                }\n                y0_ = cubicAt(y0, y1, y2, y3, extrema[0]);\n                if (nExtrema > 1) {\n                    y1_ = cubicAt(y0, y1, y2, y3, extrema[1]);\n                }\n            }\n            if (nExtrema === 2) {\n                // 分成三段单调函数\n                if (t < extrema[0]) {\n                    w += y0_ < y0 ? unit : -unit;\n                }\n                else if (t < extrema[1]) {\n                    w += y1_ < y0_ ? unit : -unit;\n                }\n                else {\n                    w += y3 < y1_ ? unit : -unit;\n                }\n            }\n            else {\n                // 分成两段单调函数\n                if (t < extrema[0]) {\n                    w += y0_ < y0 ? unit : -unit;\n                }\n                else {\n                    w += y3 < y0_ ? unit : -unit;\n                }\n            }\n        }\n        return w;\n    }\n}\n\nfunction windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {\n    // Quick reject\n    if (\n        (y > y0 && y > y1 && y > y2)\n        || (y < y0 && y < y1 && y < y2)\n    ) {\n        return 0;\n    }\n    var nRoots = quadraticRootAt(y0, y1, y2, y, roots);\n    if (nRoots === 0) {\n        return 0;\n    }\n    else {\n        var t = quadraticExtremum(y0, y1, y2);\n        if (t >= 0 && t <= 1) {\n            var w = 0;\n            var y_ = quadraticAt(y0, y1, y2, t);\n            for (var i = 0; i < nRoots; i++) {\n                // Remove one endpoint.\n                var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1;\n\n                var x_ = quadraticAt(x0, x1, x2, roots[i]);\n                if (x_ < x) {   // Quick reject\n                    continue;\n                }\n                if (roots[i] < t) {\n                    w += y_ < y0 ? unit : -unit;\n                }\n                else {\n                    w += y2 < y_ ? unit : -unit;\n                }\n            }\n            return w;\n        }\n        else {\n            // Remove one endpoint.\n            var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1;\n\n            var x_ = quadraticAt(x0, x1, x2, roots[0]);\n            if (x_ < x) {   // Quick reject\n                return 0;\n            }\n            return y2 < y0 ? unit : -unit;\n        }\n    }\n}\n\n// TODO\n// Arc 旋转\nfunction windingArc(\n    cx, cy, r, startAngle, endAngle, anticlockwise, x, y\n) {\n    y -= cy;\n    if (y > r || y < -r) {\n        return 0;\n    }\n    var tmp = Math.sqrt(r * r - y * y);\n    roots[0] = -tmp;\n    roots[1] = tmp;\n\n    var diff = Math.abs(startAngle - endAngle);\n    if (diff < 1e-4) {\n        return 0;\n    }\n    if (diff % PI2$1 < 1e-4) {\n        // Is a circle\n        startAngle = 0;\n        endAngle = PI2$1;\n        var dir = anticlockwise ? 1 : -1;\n        if (x >= roots[0] + cx && x <= roots[1] + cx) {\n            return dir;\n        }\n        else {\n            return 0;\n        }\n    }\n\n    if (anticlockwise) {\n        var tmp = startAngle;\n        startAngle = normalizeRadian(endAngle);\n        endAngle = normalizeRadian(tmp);\n    }\n    else {\n        startAngle = normalizeRadian(startAngle);\n        endAngle = normalizeRadian(endAngle);\n    }\n    if (startAngle > endAngle) {\n        endAngle += PI2$1;\n    }\n\n    var w = 0;\n    for (var i = 0; i < 2; i++) {\n        var x_ = roots[i];\n        if (x_ + cx > x) {\n            var angle = Math.atan2(y, x_);\n            var dir = anticlockwise ? 1 : -1;\n            if (angle < 0) {\n                angle = PI2$1 + angle;\n            }\n            if (\n                (angle >= startAngle && angle <= endAngle)\n                || (angle + PI2$1 >= startAngle && angle + PI2$1 <= endAngle)\n            ) {\n                if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {\n                    dir = -dir;\n                }\n                w += dir;\n            }\n        }\n    }\n    return w;\n}\n\nfunction containPath(data, lineWidth, isStroke, x, y) {\n    var w = 0;\n    var xi = 0;\n    var yi = 0;\n    var x0 = 0;\n    var y0 = 0;\n\n    for (var i = 0; i < data.length;) {\n        var cmd = data[i++];\n        // Begin a new subpath\n        if (cmd === CMD$1.M && i > 1) {\n            // Close previous subpath\n            if (!isStroke) {\n                w += windingLine(xi, yi, x0, y0, x, y);\n            }\n            // 如果被任何一个 subpath 包含\n            // if (w !== 0) {\n            //     return true;\n            // }\n        }\n\n        if (i === 1) {\n            // 如果第一个命令是 L, C, Q\n            // 则 previous point 同绘制命令的第一个 point\n            //\n            // 第一个命令为 Arc 的情况下会在后面特殊处理\n            xi = data[i];\n            yi = data[i + 1];\n\n            x0 = xi;\n            y0 = yi;\n        }\n\n        switch (cmd) {\n            case CMD$1.M:\n                // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点\n                // 在 closePath 的时候使用\n                x0 = data[i++];\n                y0 = data[i++];\n                xi = x0;\n                yi = y0;\n                break;\n            case CMD$1.L:\n                if (isStroke) {\n                    if (containStroke$1(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {\n                        return true;\n                    }\n                }\n                else {\n                    // NOTE 在第一个命令为 L, C, Q 的时候会计算出 NaN\n                    w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.C:\n                if (isStroke) {\n                    if (containStroke$2(xi, yi,\n                        data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingCubic(\n                        xi, yi,\n                        data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        x, y\n                    ) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.Q:\n                if (isStroke) {\n                    if (containStroke$3(xi, yi,\n                        data[i++], data[i++], data[i], data[i + 1],\n                        lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingQuadratic(\n                        xi, yi,\n                        data[i++], data[i++], data[i], data[i + 1],\n                        x, y\n                    ) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.A:\n                // TODO Arc 判断的开销比较大\n                var cx = data[i++];\n                var cy = data[i++];\n                var rx = data[i++];\n                var ry = data[i++];\n                var theta = data[i++];\n                var dTheta = data[i++];\n                // TODO Arc 旋转\n                i += 1;\n                var anticlockwise = 1 - data[i++];\n                var x1 = Math.cos(theta) * rx + cx;\n                var y1 = Math.sin(theta) * ry + cy;\n                // 不是直接使用 arc 命令\n                if (i > 1) {\n                    w += windingLine(xi, yi, x1, y1, x, y);\n                }\n                else {\n                    // 第一个命令起点还未定义\n                    x0 = x1;\n                    y0 = y1;\n                }\n                // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放\n                var _x = (x - cx) * ry / rx + cx;\n                if (isStroke) {\n                    if (containStroke$4(\n                        cx, cy, ry, theta, theta + dTheta, anticlockwise,\n                        lineWidth, _x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingArc(\n                        cx, cy, ry, theta, theta + dTheta, anticlockwise,\n                        _x, y\n                    );\n                }\n                xi = Math.cos(theta + dTheta) * rx + cx;\n                yi = Math.sin(theta + dTheta) * ry + cy;\n                break;\n            case CMD$1.R:\n                x0 = xi = data[i++];\n                y0 = yi = data[i++];\n                var width = data[i++];\n                var height = data[i++];\n                var x1 = x0 + width;\n                var y1 = y0 + height;\n                if (isStroke) {\n                    if (containStroke$1(x0, y0, x1, y0, lineWidth, x, y)\n                        || containStroke$1(x1, y0, x1, y1, lineWidth, x, y)\n                        || containStroke$1(x1, y1, x0, y1, lineWidth, x, y)\n                        || containStroke$1(x0, y1, x0, y0, lineWidth, x, y)\n                    ) {\n                        return true;\n                    }\n                }\n                else {\n                    // FIXME Clockwise ?\n                    w += windingLine(x1, y0, x1, y1, x, y);\n                    w += windingLine(x0, y1, x0, y0, x, y);\n                }\n                break;\n            case CMD$1.Z:\n                if (isStroke) {\n                    if (containStroke$1(\n                        xi, yi, x0, y0, lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    // Close a subpath\n                    w += windingLine(xi, yi, x0, y0, x, y);\n                    // 如果被任何一个 subpath 包含\n                    // FIXME subpaths may overlap\n                    // if (w !== 0) {\n                    //     return true;\n                    // }\n                }\n                xi = x0;\n                yi = y0;\n                break;\n        }\n    }\n    if (!isStroke && !isAroundEqual(yi, y0)) {\n        w += windingLine(xi, yi, x0, y0, x, y) || 0;\n    }\n    return w !== 0;\n}\n\nfunction contain(pathData, x, y) {\n    return containPath(pathData, 0, false, x, y);\n}\n\nfunction containStroke(pathData, lineWidth, x, y) {\n    return containPath(pathData, lineWidth, true, x, y);\n}\n\nvar getCanvasPattern = Pattern.prototype.getCanvasPattern;\n\nvar abs = Math.abs;\n\nvar pathProxyForDraw = new PathProxy(true);\n/**\n * @alias module:zrender/graphic/Path\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nfunction Path(opts) {\n    Displayable.call(this, opts);\n\n    /**\n     * @type {module:zrender/core/PathProxy}\n     * @readOnly\n     */\n    this.path = null;\n}\n\nPath.prototype = {\n\n    constructor: Path,\n\n    type: 'path',\n\n    __dirtyPath: true,\n\n    strokeContainThreshold: 5,\n\n    /**\n     * See `module:zrender/src/graphic/helper/subPixelOptimize`.\n     * @type {boolean}\n     */\n    subPixelOptimize: false,\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n        var path = this.path || pathProxyForDraw;\n        var hasStroke = style.hasStroke();\n        var hasFill = style.hasFill();\n        var fill = style.fill;\n        var stroke = style.stroke;\n        var hasFillGradient = hasFill && !!(fill.colorStops);\n        var hasStrokeGradient = hasStroke && !!(stroke.colorStops);\n        var hasFillPattern = hasFill && !!(fill.image);\n        var hasStrokePattern = hasStroke && !!(stroke.image);\n\n        style.bind(ctx, this, prevEl);\n        this.setTransform(ctx);\n\n        if (this.__dirty) {\n            var rect;\n            // Update gradient because bounding rect may changed\n            if (hasFillGradient) {\n                rect = rect || this.getBoundingRect();\n                this._fillGradient = style.getGradient(ctx, fill, rect);\n            }\n            if (hasStrokeGradient) {\n                rect = rect || this.getBoundingRect();\n                this._strokeGradient = style.getGradient(ctx, stroke, rect);\n            }\n        }\n        // Use the gradient or pattern\n        if (hasFillGradient) {\n            // PENDING If may have affect the state\n            ctx.fillStyle = this._fillGradient;\n        }\n        else if (hasFillPattern) {\n            ctx.fillStyle = getCanvasPattern.call(fill, ctx);\n        }\n        if (hasStrokeGradient) {\n            ctx.strokeStyle = this._strokeGradient;\n        }\n        else if (hasStrokePattern) {\n            ctx.strokeStyle = getCanvasPattern.call(stroke, ctx);\n        }\n\n        var lineDash = style.lineDash;\n        var lineDashOffset = style.lineDashOffset;\n\n        var ctxLineDash = !!ctx.setLineDash;\n\n        // Update path sx, sy\n        var scale = this.getGlobalScale();\n        path.setScale(scale[0], scale[1]);\n\n        // Proxy context\n        // Rebuild path in following 2 cases\n        // 1. Path is dirty\n        // 2. Path needs javascript implemented lineDash stroking.\n        //    In this case, lineDash information will not be saved in PathProxy\n        if (this.__dirtyPath\n            || (lineDash && !ctxLineDash && hasStroke)\n        ) {\n            path.beginPath(ctx);\n\n            // Setting line dash before build path\n            if (lineDash && !ctxLineDash) {\n                path.setLineDash(lineDash);\n                path.setLineDashOffset(lineDashOffset);\n            }\n\n            this.buildPath(path, this.shape, false);\n\n            // Clear path dirty flag\n            if (this.path) {\n                this.__dirtyPath = false;\n            }\n        }\n        else {\n            // Replay path building\n            ctx.beginPath();\n            this.path.rebuildPath(ctx);\n        }\n\n        if (hasFill) {\n            if (style.fillOpacity != null) {\n                var originalGlobalAlpha = ctx.globalAlpha;\n                ctx.globalAlpha = style.fillOpacity * style.opacity;\n                path.fill(ctx);\n                ctx.globalAlpha = originalGlobalAlpha;\n            }\n            else {\n                path.fill(ctx);\n            }\n        }\n\n        if (lineDash && ctxLineDash) {\n            ctx.setLineDash(lineDash);\n            ctx.lineDashOffset = lineDashOffset;\n        }\n\n        if (hasStroke) {\n            if (style.strokeOpacity != null) {\n                var originalGlobalAlpha = ctx.globalAlpha;\n                ctx.globalAlpha = style.strokeOpacity * style.opacity;\n                path.stroke(ctx);\n                ctx.globalAlpha = originalGlobalAlpha;\n            }\n            else {\n                path.stroke(ctx);\n            }\n        }\n\n        if (lineDash && ctxLineDash) {\n            // PENDING\n            // Remove lineDash\n            ctx.setLineDash([]);\n        }\n\n        // Draw rect text\n        if (style.text != null) {\n            // Only restore transform when needs draw text.\n            this.restoreTransform(ctx);\n            this.drawRectText(ctx, this.getBoundingRect());\n        }\n    },\n\n    // When bundling path, some shape may decide if use moveTo to begin a new subpath or closePath\n    // Like in circle\n    buildPath: function (ctx, shapeCfg, inBundle) {},\n\n    createPathProxy: function () {\n        this.path = new PathProxy();\n    },\n\n    getBoundingRect: function () {\n        var rect = this._rect;\n        var style = this.style;\n        var needsUpdateRect = !rect;\n        if (needsUpdateRect) {\n            var path = this.path;\n            if (!path) {\n                // Create path on demand.\n                path = this.path = new PathProxy();\n            }\n            if (this.__dirtyPath) {\n                path.beginPath();\n                this.buildPath(path, this.shape, false);\n            }\n            rect = path.getBoundingRect();\n        }\n        this._rect = rect;\n\n        if (style.hasStroke()) {\n            // Needs update rect with stroke lineWidth when\n            // 1. Element changes scale or lineWidth\n            // 2. Shape is changed\n            var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone());\n            if (this.__dirty || needsUpdateRect) {\n                rectWithStroke.copy(rect);\n                // FIXME Must after updateTransform\n                var w = style.lineWidth;\n                // PENDING, Min line width is needed when line is horizontal or vertical\n                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;\n\n                // Only add extra hover lineWidth when there are no fill\n                if (!style.hasFill()) {\n                    w = Math.max(w, this.strokeContainThreshold || 4);\n                }\n                // Consider line width\n                // Line scale can't be 0;\n                if (lineScale > 1e-10) {\n                    rectWithStroke.width += w / lineScale;\n                    rectWithStroke.height += w / lineScale;\n                    rectWithStroke.x -= w / lineScale / 2;\n                    rectWithStroke.y -= w / lineScale / 2;\n                }\n            }\n\n            // Return rect with stroke\n            return rectWithStroke;\n        }\n\n        return rect;\n    },\n\n    contain: function (x, y) {\n        var localPos = this.transformCoordToLocal(x, y);\n        var rect = this.getBoundingRect();\n        var style = this.style;\n        x = localPos[0];\n        y = localPos[1];\n\n        if (rect.contain(x, y)) {\n            var pathData = this.path.data;\n            if (style.hasStroke()) {\n                var lineWidth = style.lineWidth;\n                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;\n                // Line scale can't be 0;\n                if (lineScale > 1e-10) {\n                    // Only add extra hover lineWidth when there are no fill\n                    if (!style.hasFill()) {\n                        lineWidth = Math.max(lineWidth, this.strokeContainThreshold);\n                    }\n                    if (containStroke(\n                        pathData, lineWidth / lineScale, x, y\n                    )) {\n                        return true;\n                    }\n                }\n            }\n            if (style.hasFill()) {\n                return contain(pathData, x, y);\n            }\n        }\n        return false;\n    },\n\n    /**\n     * @param  {boolean} dirtyPath\n     */\n    dirty: function (dirtyPath) {\n        if (dirtyPath == null) {\n            dirtyPath = true;\n        }\n        // Only mark dirty, not mark clean\n        if (dirtyPath) {\n            this.__dirtyPath = dirtyPath;\n            this._rect = null;\n        }\n\n        this.__dirty = this.__dirtyText = true;\n\n        this.__zr && this.__zr.refresh();\n\n        // Used as a clipping path\n        if (this.__clipTarget) {\n            this.__clipTarget.dirty();\n        }\n    },\n\n    /**\n     * Alias for animate('shape')\n     * @param {boolean} loop\n     */\n    animateShape: function (loop) {\n        return this.animate('shape', loop);\n    },\n\n    // Overwrite attrKV\n    attrKV: function (key, value) {\n        // FIXME\n        if (key === 'shape') {\n            this.setShape(value);\n            this.__dirtyPath = true;\n            this._rect = null;\n        }\n        else {\n            Displayable.prototype.attrKV.call(this, key, value);\n        }\n    },\n\n    /**\n     * @param {Object|string} key\n     * @param {*} value\n     */\n    setShape: function (key, value) {\n        var shape = this.shape;\n        // Path from string may not have shape\n        if (shape) {\n            if (isObject$1(key)) {\n                for (var name in key) {\n                    if (key.hasOwnProperty(name)) {\n                        shape[name] = key[name];\n                    }\n                }\n            }\n            else {\n                shape[key] = value;\n            }\n            this.dirty(true);\n        }\n        return this;\n    },\n\n    getLineScale: function () {\n        var m = this.transform;\n        // Get the line scale.\n        // Determinant of `m` means how much the area is enlarged by the\n        // transformation. So its square root can be used as a scale factor\n        // for width.\n        return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10\n            ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1]))\n            : 1;\n    }\n};\n\n/**\n * 扩展一个 Path element, 比如星形，圆等。\n * Extend a path element\n * @param {Object} props\n * @param {string} props.type Path type\n * @param {Function} props.init Initialize\n * @param {Function} props.buildPath Overwrite buildPath method\n * @param {Object} [props.style] Extended default style config\n * @param {Object} [props.shape] Extended default shape config\n */\nPath.extend = function (defaults$$1) {\n    var Sub = function (opts) {\n        Path.call(this, opts);\n\n        if (defaults$$1.style) {\n            // Extend default style\n            this.style.extendFrom(defaults$$1.style, false);\n        }\n\n        // Extend default shape\n        var defaultShape = defaults$$1.shape;\n        if (defaultShape) {\n            this.shape = this.shape || {};\n            var thisShape = this.shape;\n            for (var name in defaultShape) {\n                if (\n                    !thisShape.hasOwnProperty(name)\n                    && defaultShape.hasOwnProperty(name)\n                ) {\n                    thisShape[name] = defaultShape[name];\n                }\n            }\n        }\n\n        defaults$$1.init && defaults$$1.init.call(this, opts);\n    };\n\n    inherits(Sub, Path);\n\n    // FIXME 不能 extend position, rotation 等引用对象\n    for (var name in defaults$$1) {\n        // Extending prototype values and methods\n        if (name !== 'style' && name !== 'shape') {\n            Sub.prototype[name] = defaults$$1[name];\n        }\n    }\n\n    return Sub;\n};\n\ninherits(Path, Displayable);\n\nvar CMD$2 = PathProxy.CMD;\n\nvar points = [[], [], []];\nvar mathSqrt$3 = Math.sqrt;\nvar mathAtan2 = Math.atan2;\n\nvar transformPath = function (path, m) {\n    var data = path.data;\n    var cmd;\n    var nPoint;\n    var i;\n    var j;\n    var k;\n    var p;\n\n    var M = CMD$2.M;\n    var C = CMD$2.C;\n    var L = CMD$2.L;\n    var R = CMD$2.R;\n    var A = CMD$2.A;\n    var Q = CMD$2.Q;\n\n    for (i = 0, j = 0; i < data.length;) {\n        cmd = data[i++];\n        j = i;\n        nPoint = 0;\n\n        switch (cmd) {\n            case M:\n                nPoint = 1;\n                break;\n            case L:\n                nPoint = 1;\n                break;\n            case C:\n                nPoint = 3;\n                break;\n            case Q:\n                nPoint = 2;\n                break;\n            case A:\n                var x = m[4];\n                var y = m[5];\n                var sx = mathSqrt$3(m[0] * m[0] + m[1] * m[1]);\n                var sy = mathSqrt$3(m[2] * m[2] + m[3] * m[3]);\n                var angle = mathAtan2(-m[1] / sy, m[0] / sx);\n                // cx\n                data[i] *= sx;\n                data[i++] += x;\n                // cy\n                data[i] *= sy;\n                data[i++] += y;\n                // Scale rx and ry\n                // FIXME Assume psi is 0 here\n                data[i++] *= sx;\n                data[i++] *= sy;\n\n                // Start angle\n                data[i++] += angle;\n                // end angle\n                data[i++] += angle;\n                // FIXME psi\n                i += 2;\n                j = i;\n                break;\n            case R:\n                // x0, y0\n                p[0] = data[i++];\n                p[1] = data[i++];\n                applyTransform(p, p, m);\n                data[j++] = p[0];\n                data[j++] = p[1];\n                // x1, y1\n                p[0] += data[i++];\n                p[1] += data[i++];\n                applyTransform(p, p, m);\n                data[j++] = p[0];\n                data[j++] = p[1];\n        }\n\n        for (k = 0; k < nPoint; k++) {\n            var p = points[k];\n            p[0] = data[i++];\n            p[1] = data[i++];\n\n            applyTransform(p, p, m);\n            // Write back\n            data[j++] = p[0];\n            data[j++] = p[1];\n        }\n    }\n};\n\n// command chars\n// var cc = [\n//     'm', 'M', 'l', 'L', 'v', 'V', 'h', 'H', 'z', 'Z',\n//     'c', 'C', 'q', 'Q', 't', 'T', 's', 'S', 'a', 'A'\n// ];\n\nvar mathSqrt = Math.sqrt;\nvar mathSin = Math.sin;\nvar mathCos = Math.cos;\nvar PI = Math.PI;\n\nvar vMag = function (v) {\n    return Math.sqrt(v[0] * v[0] + v[1] * v[1]);\n};\nvar vRatio = function (u, v) {\n    return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));\n};\nvar vAngle = function (u, v) {\n    return (u[0] * v[1] < u[1] * v[0] ? -1 : 1)\n            * Math.acos(vRatio(u, v));\n};\n\nfunction processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) {\n    var psi = psiDeg * (PI / 180.0);\n    var xp = mathCos(psi) * (x1 - x2) / 2.0\n                + mathSin(psi) * (y1 - y2) / 2.0;\n    var yp = -1 * mathSin(psi) * (x1 - x2) / 2.0\n                + mathCos(psi) * (y1 - y2) / 2.0;\n\n    var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);\n\n    if (lambda > 1) {\n        rx *= mathSqrt(lambda);\n        ry *= mathSqrt(lambda);\n    }\n\n    var f = (fa === fs ? -1 : 1)\n        * mathSqrt((((rx * rx) * (ry * ry))\n                - ((rx * rx) * (yp * yp))\n                - ((ry * ry) * (xp * xp))) / ((rx * rx) * (yp * yp)\n                + (ry * ry) * (xp * xp))\n            ) || 0;\n\n    var cxp = f * rx * yp / ry;\n    var cyp = f * -ry * xp / rx;\n\n    var cx = (x1 + x2) / 2.0\n                + mathCos(psi) * cxp\n                - mathSin(psi) * cyp;\n    var cy = (y1 + y2) / 2.0\n            + mathSin(psi) * cxp\n            + mathCos(psi) * cyp;\n\n    var theta = vAngle([ 1, 0 ], [ (xp - cxp) / rx, (yp - cyp) / ry ]);\n    var u = [ (xp - cxp) / rx, (yp - cyp) / ry ];\n    var v = [ (-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry ];\n    var dTheta = vAngle(u, v);\n\n    if (vRatio(u, v) <= -1) {\n        dTheta = PI;\n    }\n    if (vRatio(u, v) >= 1) {\n        dTheta = 0;\n    }\n    if (fs === 0 && dTheta > 0) {\n        dTheta = dTheta - 2 * PI;\n    }\n    if (fs === 1 && dTheta < 0) {\n        dTheta = dTheta + 2 * PI;\n    }\n\n    path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs);\n}\n\n\nvar commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig;\n// Consider case:\n// (1) delimiter can be comma or space, where continuous commas\n// or spaces should be seen as one comma.\n// (2) value can be like:\n// '2e-4', 'l.5.9' (ignore 0), 'M-10-10', 'l-2.43e-1,34.9983',\n// 'l-.5E1,54', '121-23-44-11' (no delimiter)\nvar numberReg = /-?([0-9]*\\.)?[0-9]+([eE]-?[0-9]+)?/g;\n// var valueSplitReg = /[\\s,]+/;\n\nfunction createPathProxyFromString(data) {\n    if (!data) {\n        return new PathProxy();\n    }\n\n    // var data = data.replace(/-/g, ' -')\n    //     .replace(/  /g, ' ')\n    //     .replace(/ /g, ',')\n    //     .replace(/,,/g, ',');\n\n    // var n;\n    // create pipes so that we can split the data\n    // for (n = 0; n < cc.length; n++) {\n    //     cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]);\n    // }\n\n    // data = data.replace(/-/g, ',-');\n\n    // create array\n    // var arr = cs.split('|');\n    // init context point\n    var cpx = 0;\n    var cpy = 0;\n    var subpathX = cpx;\n    var subpathY = cpy;\n    var prevCmd;\n\n    var path = new PathProxy();\n    var CMD = PathProxy.CMD;\n\n    // commandReg.lastIndex = 0;\n    // var cmdResult;\n    // while ((cmdResult = commandReg.exec(data)) != null) {\n    //     var cmdStr = cmdResult[1];\n    //     var cmdContent = cmdResult[2];\n\n    var cmdList = data.match(commandReg);\n    for (var l = 0; l < cmdList.length; l++) {\n        var cmdText = cmdList[l];\n        var cmdStr = cmdText.charAt(0);\n\n        var cmd;\n\n        // String#split is faster a little bit than String#replace or RegExp#exec.\n        // var p = cmdContent.split(valueSplitReg);\n        // var pLen = 0;\n        // for (var i = 0; i < p.length; i++) {\n        //     // '' and other invalid str => NaN\n        //     var val = parseFloat(p[i]);\n        //     !isNaN(val) && (p[pLen++] = val);\n        // }\n\n        var p = cmdText.match(numberReg) || [];\n        var pLen = p.length;\n        for (var i = 0; i < pLen; i++) {\n            p[i] = parseFloat(p[i]);\n        }\n\n        var off = 0;\n        while (off < pLen) {\n            var ctlPtx;\n            var ctlPty;\n\n            var rx;\n            var ry;\n            var psi;\n            var fa;\n            var fs;\n\n            var x1 = cpx;\n            var y1 = cpy;\n\n            // convert l, H, h, V, and v to L\n            switch (cmdStr) {\n                case 'l':\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'L':\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'm':\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.M;\n                    path.addData(cmd, cpx, cpy);\n                    subpathX = cpx;\n                    subpathY = cpy;\n                    cmdStr = 'l';\n                    break;\n                case 'M':\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.M;\n                    path.addData(cmd, cpx, cpy);\n                    subpathX = cpx;\n                    subpathY = cpy;\n                    cmdStr = 'L';\n                    break;\n                case 'h':\n                    cpx += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'H':\n                    cpx = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'v':\n                    cpy += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'V':\n                    cpy = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'C':\n                    cmd = CMD.C;\n                    path.addData(\n                        cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]\n                    );\n                    cpx = p[off - 2];\n                    cpy = p[off - 1];\n                    break;\n                case 'c':\n                    cmd = CMD.C;\n                    path.addData(\n                        cmd,\n                        p[off++] + cpx, p[off++] + cpy,\n                        p[off++] + cpx, p[off++] + cpy,\n                        p[off++] + cpx, p[off++] + cpy\n                    );\n                    cpx += p[off - 2];\n                    cpy += p[off - 1];\n                    break;\n                case 'S':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.C) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cmd = CMD.C;\n                    x1 = p[off++];\n                    y1 = p[off++];\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);\n                    break;\n                case 's':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.C) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cmd = CMD.C;\n                    x1 = cpx + p[off++];\n                    y1 = cpy + p[off++];\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);\n                    break;\n                case 'Q':\n                    x1 = p[off++];\n                    y1 = p[off++];\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, x1, y1, cpx, cpy);\n                    break;\n                case 'q':\n                    x1 = p[off++] + cpx;\n                    y1 = p[off++] + cpy;\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, x1, y1, cpx, cpy);\n                    break;\n                case 'T':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.Q) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);\n                    break;\n                case 't':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.Q) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);\n                    break;\n                case 'A':\n                    rx = p[off++];\n                    ry = p[off++];\n                    psi = p[off++];\n                    fa = p[off++];\n                    fs = p[off++];\n\n                    x1 = cpx, y1 = cpy;\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.A;\n                    processArc(\n                        x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path\n                    );\n                    break;\n                case 'a':\n                    rx = p[off++];\n                    ry = p[off++];\n                    psi = p[off++];\n                    fa = p[off++];\n                    fs = p[off++];\n\n                    x1 = cpx, y1 = cpy;\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.A;\n                    processArc(\n                        x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path\n                    );\n                    break;\n            }\n        }\n\n        if (cmdStr === 'z' || cmdStr === 'Z') {\n            cmd = CMD.Z;\n            path.addData(cmd);\n            // z may be in the middle of the path.\n            cpx = subpathX;\n            cpy = subpathY;\n        }\n\n        prevCmd = cmd;\n    }\n\n    path.toStatic();\n\n    return path;\n}\n\n// TODO Optimize double memory cost problem\nfunction createPathOptions(str, opts) {\n    var pathProxy = createPathProxyFromString(str);\n    opts = opts || {};\n    opts.buildPath = function (path) {\n        if (path.setData) {\n            path.setData(pathProxy.data);\n            // Svg and vml renderer don't have context\n            var ctx = path.getContext();\n            if (ctx) {\n                path.rebuildPath(ctx);\n            }\n        }\n        else {\n            var ctx = path;\n            pathProxy.rebuildPath(ctx);\n        }\n    };\n\n    opts.applyTransform = function (m) {\n        transformPath(pathProxy, m);\n        this.dirty(true);\n    };\n\n    return opts;\n}\n\n/**\n * Create a Path object from path string data\n * http://www.w3.org/TR/SVG/paths.html#PathData\n * @param  {Object} opts Other options\n */\nfunction createFromString(str, opts) {\n    return new Path(createPathOptions(str, opts));\n}\n\n/**\n * Create a Path class from path string data\n * @param  {string} str\n * @param  {Object} opts Other options\n */\nfunction extendFromString(str, opts) {\n    return Path.extend(createPathOptions(str, opts));\n}\n\n/**\n * Merge multiple paths\n */\n// TODO Apply transform\n// TODO stroke dash\n// TODO Optimize double memory cost problem\nfunction mergePath$1(pathEls, opts) {\n    var pathList = [];\n    var len = pathEls.length;\n    for (var i = 0; i < len; i++) {\n        var pathEl = pathEls[i];\n        if (!pathEl.path) {\n            pathEl.createPathProxy();\n        }\n        if (pathEl.__dirtyPath) {\n            pathEl.buildPath(pathEl.path, pathEl.shape, true);\n        }\n        pathList.push(pathEl.path);\n    }\n\n    var pathBundle = new Path(opts);\n    // Need path proxy.\n    pathBundle.createPathProxy();\n    pathBundle.buildPath = function (path) {\n        path.appendPath(pathList);\n        // Svg and vml renderer don't have context\n        var ctx = path.getContext();\n        if (ctx) {\n            path.rebuildPath(ctx);\n        }\n    };\n\n    return pathBundle;\n}\n\n/**\n * @alias zrender/graphic/Text\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nvar Text = function (opts) { // jshint ignore:line\n    Displayable.call(this, opts);\n};\n\nText.prototype = {\n\n    constructor: Text,\n\n    type: 'text',\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        // Use props with prefix 'text'.\n        style.fill = style.stroke = style.shadowBlur = style.shadowColor =\n            style.shadowOffsetX = style.shadowOffsetY = null;\n\n        var text = style.text;\n        // Convert to string\n        text != null && (text += '');\n\n        // Do not apply style.bind in Text node. Because the real bind job\n        // is in textHelper.renderText, and performance of text render should\n        // be considered.\n        // style.bind(ctx, this, prevEl);\n\n        if (!needDrawText(text, style)) {\n            // The current el.style is not applied\n            // and should not be used as cache.\n            ctx.__attrCachedBy = ContextCachedBy.NONE;\n            return;\n        }\n\n        this.setTransform(ctx);\n\n        renderText(this, ctx, text, style, null, prevEl);\n\n        this.restoreTransform(ctx);\n    },\n\n    getBoundingRect: function () {\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        if (!this._rect) {\n            var text = style.text;\n            text != null ? (text += '') : (text = '');\n\n            var rect = getBoundingRect(\n                style.text + '',\n                style.font,\n                style.textAlign,\n                style.textVerticalAlign,\n                style.textPadding,\n                style.textLineHeight,\n                style.rich\n            );\n\n            rect.x += style.x || 0;\n            rect.y += style.y || 0;\n\n            if (getStroke(style.textStroke, style.textStrokeWidth)) {\n                var w = style.textStrokeWidth;\n                rect.x -= w / 2;\n                rect.y -= w / 2;\n                rect.width += w;\n                rect.height += w;\n            }\n\n            this._rect = rect;\n        }\n\n        return this._rect;\n    }\n};\n\ninherits(Text, Displayable);\n\n/**\n * 圆形\n * @module zrender/shape/Circle\n */\n\nvar Circle = Path.extend({\n\n    type: 'circle',\n\n    shape: {\n        cx: 0,\n        cy: 0,\n        r: 0\n    },\n\n\n    buildPath: function (ctx, shape, inBundle) {\n        // Better stroking in ShapeBundle\n        // Always do it may have performence issue ( fill may be 2x more cost)\n        if (inBundle) {\n            ctx.moveTo(shape.cx + shape.r, shape.cy);\n        }\n        // else {\n        //     if (ctx.allocate && !ctx.data.length) {\n        //         ctx.allocate(ctx.CMD_MEM_SIZE.A);\n        //     }\n        // }\n        // Better stroking in ShapeBundle\n        // ctx.moveTo(shape.cx + shape.r, shape.cy);\n        ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true);\n    }\n});\n\n// Fix weird bug in some version of IE11 (like 11.0.9600.178**),\n// where exception \"unexpected call to method or property access\"\n// might be thrown when calling ctx.fill or ctx.stroke after a path\n// whose area size is zero is drawn and ctx.clip() is called and\n// shadowBlur is set. See #4572, #3112, #5777.\n// (e.g.,\n//  ctx.moveTo(10, 10);\n//  ctx.lineTo(20, 10);\n//  ctx.closePath();\n//  ctx.clip();\n//  ctx.shadowBlur = 10;\n//  ...\n//  ctx.fill();\n// )\n\nvar shadowTemp = [\n    ['shadowBlur', 0],\n    ['shadowColor', '#000'],\n    ['shadowOffsetX', 0],\n    ['shadowOffsetY', 0]\n];\n\nvar fixClipWithShadow = function (orignalBrush) {\n\n    // version string can be: '11.0'\n    return (env$1.browser.ie && env$1.browser.version >= 11)\n\n        ? function () {\n            var clipPaths = this.__clipPaths;\n            var style = this.style;\n            var modified;\n\n            if (clipPaths) {\n                for (var i = 0; i < clipPaths.length; i++) {\n                    var clipPath = clipPaths[i];\n                    var shape = clipPath && clipPath.shape;\n                    var type = clipPath && clipPath.type;\n\n                    if (shape && (\n                        (type === 'sector' && shape.startAngle === shape.endAngle)\n                        || (type === 'rect' && (!shape.width || !shape.height))\n                    )) {\n                        for (var j = 0; j < shadowTemp.length; j++) {\n                            // It is save to put shadowTemp static, because shadowTemp\n                            // will be all modified each item brush called.\n                            shadowTemp[j][2] = style[shadowTemp[j][0]];\n                            style[shadowTemp[j][0]] = shadowTemp[j][1];\n                        }\n                        modified = true;\n                        break;\n                    }\n                }\n            }\n\n            orignalBrush.apply(this, arguments);\n\n            if (modified) {\n                for (var j = 0; j < shadowTemp.length; j++) {\n                    style[shadowTemp[j][0]] = shadowTemp[j][2];\n                }\n            }\n        }\n\n        : orignalBrush;\n};\n\n/**\n * 扇形\n * @module zrender/graphic/shape/Sector\n */\n\nvar Sector = Path.extend({\n\n    type: 'sector',\n\n    shape: {\n\n        cx: 0,\n\n        cy: 0,\n\n        r0: 0,\n\n        r: 0,\n\n        startAngle: 0,\n\n        endAngle: Math.PI * 2,\n\n        clockwise: true\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n\n        var x = shape.cx;\n        var y = shape.cy;\n        var r0 = Math.max(shape.r0 || 0, 0);\n        var r = Math.max(shape.r, 0);\n        var startAngle = shape.startAngle;\n        var endAngle = shape.endAngle;\n        var clockwise = shape.clockwise;\n\n        var unitX = Math.cos(startAngle);\n        var unitY = Math.sin(startAngle);\n\n        ctx.moveTo(unitX * r0 + x, unitY * r0 + y);\n\n        ctx.lineTo(unitX * r + x, unitY * r + y);\n\n        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);\n\n        ctx.lineTo(\n            Math.cos(endAngle) * r0 + x,\n            Math.sin(endAngle) * r0 + y\n        );\n\n        if (r0 !== 0) {\n            ctx.arc(x, y, r0, endAngle, startAngle, clockwise);\n        }\n\n        ctx.closePath();\n    }\n});\n\n/**\n * 圆环\n * @module zrender/graphic/shape/Ring\n */\n\nvar Ring = Path.extend({\n\n    type: 'ring',\n\n    shape: {\n        cx: 0,\n        cy: 0,\n        r: 0,\n        r0: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var x = shape.cx;\n        var y = shape.cy;\n        var PI2 = Math.PI * 2;\n        ctx.moveTo(x + shape.r, y);\n        ctx.arc(x, y, shape.r, 0, PI2, false);\n        ctx.moveTo(x + shape.r0, y);\n        ctx.arc(x, y, shape.r0, 0, PI2, true);\n    }\n});\n\n/**\n * Catmull-Rom spline 插值折线\n * @module zrender/shape/util/smoothSpline\n * @author pissang (https://www.github.com/pissang)\n *         Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         errorrik (errorrik@gmail.com)\n */\n\n/**\n * @inner\n */\nfunction interpolate(p0, p1, p2, p3, t, t2, t3) {\n    var v0 = (p2 - p0) * 0.5;\n    var v1 = (p3 - p1) * 0.5;\n    return (2 * (p1 - p2) + v0 + v1) * t3\n            + (-3 * (p1 - p2) - 2 * v0 - v1) * t2\n            + v0 * t + p1;\n}\n\n/**\n * @alias module:zrender/shape/util/smoothSpline\n * @param {Array} points 线段顶点数组\n * @param {boolean} isLoop\n * @return {Array}\n */\nvar smoothSpline = function (points, isLoop) {\n    var len$$1 = points.length;\n    var ret = [];\n\n    var distance$$1 = 0;\n    for (var i = 1; i < len$$1; i++) {\n        distance$$1 += distance(points[i - 1], points[i]);\n    }\n\n    var segs = distance$$1 / 2;\n    segs = segs < len$$1 ? len$$1 : segs;\n    for (var i = 0; i < segs; i++) {\n        var pos = i / (segs - 1) * (isLoop ? len$$1 : len$$1 - 1);\n        var idx = Math.floor(pos);\n\n        var w = pos - idx;\n\n        var p0;\n        var p1 = points[idx % len$$1];\n        var p2;\n        var p3;\n        if (!isLoop) {\n            p0 = points[idx === 0 ? idx : idx - 1];\n            p2 = points[idx > len$$1 - 2 ? len$$1 - 1 : idx + 1];\n            p3 = points[idx > len$$1 - 3 ? len$$1 - 1 : idx + 2];\n        }\n        else {\n            p0 = points[(idx - 1 + len$$1) % len$$1];\n            p2 = points[(idx + 1) % len$$1];\n            p3 = points[(idx + 2) % len$$1];\n        }\n\n        var w2 = w * w;\n        var w3 = w * w2;\n\n        ret.push([\n            interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3),\n            interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3)\n        ]);\n    }\n    return ret;\n};\n\n/**\n * 贝塞尔平滑曲线\n * @module zrender/shape/util/smoothBezier\n * @author pissang (https://www.github.com/pissang)\n *         Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         errorrik (errorrik@gmail.com)\n */\n\n/**\n * 贝塞尔平滑曲线\n * @alias module:zrender/shape/util/smoothBezier\n * @param {Array} points 线段顶点数组\n * @param {number} smooth 平滑等级, 0-1\n * @param {boolean} isLoop\n * @param {Array} constraint 将计算出来的控制点约束在一个包围盒内\n *                           比如 [[0, 0], [100, 100]], 这个包围盒会与\n *                           整个折线的包围盒做一个并集用来约束控制点。\n * @param {Array} 计算出来的控制点数组\n */\nvar smoothBezier = function (points, smooth, isLoop, constraint) {\n    var cps = [];\n\n    var v = [];\n    var v1 = [];\n    var v2 = [];\n    var prevPoint;\n    var nextPoint;\n\n    var min$$1;\n    var max$$1;\n    if (constraint) {\n        min$$1 = [Infinity, Infinity];\n        max$$1 = [-Infinity, -Infinity];\n        for (var i = 0, len$$1 = points.length; i < len$$1; i++) {\n            min(min$$1, min$$1, points[i]);\n            max(max$$1, max$$1, points[i]);\n        }\n        // 与指定的包围盒做并集\n        min(min$$1, min$$1, constraint[0]);\n        max(max$$1, max$$1, constraint[1]);\n    }\n\n    for (var i = 0, len$$1 = points.length; i < len$$1; i++) {\n        var point = points[i];\n\n        if (isLoop) {\n            prevPoint = points[i ? i - 1 : len$$1 - 1];\n            nextPoint = points[(i + 1) % len$$1];\n        }\n        else {\n            if (i === 0 || i === len$$1 - 1) {\n                cps.push(clone$1(points[i]));\n                continue;\n            }\n            else {\n                prevPoint = points[i - 1];\n                nextPoint = points[i + 1];\n            }\n        }\n\n        sub(v, nextPoint, prevPoint);\n\n        // use degree to scale the handle length\n        scale(v, v, smooth);\n\n        var d0 = distance(point, prevPoint);\n        var d1 = distance(point, nextPoint);\n        var sum = d0 + d1;\n        if (sum !== 0) {\n            d0 /= sum;\n            d1 /= sum;\n        }\n\n        scale(v1, v, -d0);\n        scale(v2, v, d1);\n        var cp0 = add([], point, v1);\n        var cp1 = add([], point, v2);\n        if (constraint) {\n            max(cp0, cp0, min$$1);\n            min(cp0, cp0, max$$1);\n            max(cp1, cp1, min$$1);\n            min(cp1, cp1, max$$1);\n        }\n        cps.push(cp0);\n        cps.push(cp1);\n    }\n\n    if (isLoop) {\n        cps.push(cps.shift());\n    }\n\n    return cps;\n};\n\nfunction buildPath$1(ctx, shape, closePath) {\n    var points = shape.points;\n    var smooth = shape.smooth;\n    if (points && points.length >= 2) {\n        if (smooth && smooth !== 'spline') {\n            var controlPoints = smoothBezier(\n                points, smooth, closePath, shape.smoothConstraint\n            );\n\n            ctx.moveTo(points[0][0], points[0][1]);\n            var len = points.length;\n            for (var i = 0; i < (closePath ? len : len - 1); i++) {\n                var cp1 = controlPoints[i * 2];\n                var cp2 = controlPoints[i * 2 + 1];\n                var p = points[(i + 1) % len];\n                ctx.bezierCurveTo(\n                    cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]\n                );\n            }\n        }\n        else {\n            if (smooth === 'spline') {\n                points = smoothSpline(points, closePath);\n            }\n\n            ctx.moveTo(points[0][0], points[0][1]);\n            for (var i = 1, l = points.length; i < l; i++) {\n                ctx.lineTo(points[i][0], points[i][1]);\n            }\n        }\n\n        closePath && ctx.closePath();\n    }\n}\n\n/**\n * 多边形\n * @module zrender/shape/Polygon\n */\n\nvar Polygon = Path.extend({\n\n    type: 'polygon',\n\n    shape: {\n        points: null,\n\n        smooth: false,\n\n        smoothConstraint: null\n    },\n\n    buildPath: function (ctx, shape) {\n        buildPath$1(ctx, shape, true);\n    }\n});\n\n/**\n * @module zrender/graphic/shape/Polyline\n */\n\nvar Polyline = Path.extend({\n\n    type: 'polyline',\n\n    shape: {\n        points: null,\n\n        smooth: false,\n\n        smoothConstraint: null\n    },\n\n    style: {\n        stroke: '#000',\n\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        buildPath$1(ctx, shape, false);\n    }\n});\n\n/**\n * Sub-pixel optimize for canvas rendering, prevent from blur\n * when rendering a thin vertical/horizontal line.\n */\n\nvar round$1 = Math.round;\n\n/**\n * Sub pixel optimize line for canvas\n *\n * @param {Object} outputShape The modification will be performed on `outputShape`.\n *                 `outputShape` and `inputShape` can be the same object.\n *                 `outputShape` object can be used repeatly, because all of\n *                 the `x1`, `x2`, `y1`, `y2` will be assigned in this method.\n * @param {Object} [inputShape]\n * @param {number} [inputShape.x1]\n * @param {number} [inputShape.y1]\n * @param {number} [inputShape.x2]\n * @param {number} [inputShape.y2]\n * @param {Object} [style]\n * @param {number} [style.lineWidth]\n */\nfunction subPixelOptimizeLine$1(outputShape, inputShape, style) {\n    var lineWidth = style && style.lineWidth;\n\n    if (!inputShape || !lineWidth) {\n        return;\n    }\n\n    var x1 = inputShape.x1;\n    var x2 = inputShape.x2;\n    var y1 = inputShape.y1;\n    var y2 = inputShape.y2;\n\n    if (round$1(x1 * 2) === round$1(x2 * 2)) {\n        outputShape.x1 = outputShape.x2 = subPixelOptimize$1(x1, lineWidth, true);\n    }\n    else {\n        outputShape.x1 = x1;\n        outputShape.x2 = x2;\n    }\n    if (round$1(y1 * 2) === round$1(y2 * 2)) {\n        outputShape.y1 = outputShape.y2 = subPixelOptimize$1(y1, lineWidth, true);\n    }\n    else {\n        outputShape.y1 = y1;\n        outputShape.y2 = y2;\n    }\n}\n\n/**\n * Sub pixel optimize rect for canvas\n *\n * @param {Object} outputShape The modification will be performed on `outputShape`.\n *                 `outputShape` and `inputShape` can be the same object.\n *                 `outputShape` object can be used repeatly, because all of\n *                 the `x`, `y`, `width`, `height` will be assigned in this method.\n * @param {Object} [inputShape]\n * @param {number} [inputShape.x]\n * @param {number} [inputShape.y]\n * @param {number} [inputShape.width]\n * @param {number} [inputShape.height]\n * @param {Object} [style]\n * @param {number} [style.lineWidth]\n */\nfunction subPixelOptimizeRect$1(outputShape, inputShape, style) {\n    var lineWidth = style && style.lineWidth;\n\n    if (!inputShape || !lineWidth) {\n        return;\n    }\n\n    var originX = inputShape.x;\n    var originY = inputShape.y;\n    var originWidth = inputShape.width;\n    var originHeight = inputShape.height;\n\n    outputShape.x = subPixelOptimize$1(originX, lineWidth, true);\n    outputShape.y = subPixelOptimize$1(originY, lineWidth, true);\n    outputShape.width = Math.max(\n        subPixelOptimize$1(originX + originWidth, lineWidth, false) - outputShape.x,\n        originWidth === 0 ? 0 : 1\n    );\n    outputShape.height = Math.max(\n        subPixelOptimize$1(originY + originHeight, lineWidth, false) - outputShape.y,\n        originHeight === 0 ? 0 : 1\n    );\n}\n\n/**\n * Sub pixel optimize for canvas\n *\n * @param {number} position Coordinate, such as x, y\n * @param {number} lineWidth Should be nonnegative integer.\n * @param {boolean=} positiveOrNegative Default false (negative).\n * @return {number} Optimized position.\n */\nfunction subPixelOptimize$1(position, lineWidth, positiveOrNegative) {\n    // Assure that (position + lineWidth / 2) is near integer edge,\n    // otherwise line will be fuzzy in canvas.\n    var doubledPosition = round$1(position * 2);\n    return (doubledPosition + round$1(lineWidth)) % 2 === 0\n        ? doubledPosition / 2\n        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;\n}\n\n/**\n * 矩形\n * @module zrender/graphic/shape/Rect\n */\n\n// Avoid create repeatly.\nvar subPixelOptimizeOutputShape = {};\n\nvar Rect = Path.extend({\n\n    type: 'rect',\n\n    shape: {\n        // 左上、右上、右下、左下角的半径依次为r1、r2、r3、r4\n        // r缩写为1         相当于 [1, 1, 1, 1]\n        // r缩写为[1]       相当于 [1, 1, 1, 1]\n        // r缩写为[1, 2]    相当于 [1, 2, 1, 2]\n        // r缩写为[1, 2, 3] 相当于 [1, 2, 3, 2]\n        r: 0,\n\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var x;\n        var y;\n        var width;\n        var height;\n\n        if (this.subPixelOptimize) {\n            subPixelOptimizeRect$1(subPixelOptimizeOutputShape, shape, this.style);\n            x = subPixelOptimizeOutputShape.x;\n            y = subPixelOptimizeOutputShape.y;\n            width = subPixelOptimizeOutputShape.width;\n            height = subPixelOptimizeOutputShape.height;\n            subPixelOptimizeOutputShape.r = shape.r;\n            shape = subPixelOptimizeOutputShape;\n        }\n        else {\n            x = shape.x;\n            y = shape.y;\n            width = shape.width;\n            height = shape.height;\n        }\n\n        if (!shape.r) {\n            ctx.rect(x, y, width, height);\n        }\n        else {\n            buildPath(ctx, shape);\n        }\n        ctx.closePath();\n        return;\n    }\n});\n\n/**\n * 直线\n * @module zrender/graphic/shape/Line\n */\n\n// Avoid create repeatly.\nvar subPixelOptimizeOutputShape$1 = {};\n\nvar Line = Path.extend({\n\n    type: 'line',\n\n    shape: {\n        // Start point\n        x1: 0,\n        y1: 0,\n        // End point\n        x2: 0,\n        y2: 0,\n\n        percent: 1\n    },\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        var x1;\n        var y1;\n        var x2;\n        var y2;\n\n        if (this.subPixelOptimize) {\n            subPixelOptimizeLine$1(subPixelOptimizeOutputShape$1, shape, this.style);\n            x1 = subPixelOptimizeOutputShape$1.x1;\n            y1 = subPixelOptimizeOutputShape$1.y1;\n            x2 = subPixelOptimizeOutputShape$1.x2;\n            y2 = subPixelOptimizeOutputShape$1.y2;\n        }\n        else {\n            x1 = shape.x1;\n            y1 = shape.y1;\n            x2 = shape.x2;\n            y2 = shape.y2;\n        }\n\n        var percent = shape.percent;\n\n        if (percent === 0) {\n            return;\n        }\n\n        ctx.moveTo(x1, y1);\n\n        if (percent < 1) {\n            x2 = x1 * (1 - percent) + x2 * percent;\n            y2 = y1 * (1 - percent) + y2 * percent;\n        }\n        ctx.lineTo(x2, y2);\n    },\n\n    /**\n     * Get point at percent\n     * @param  {number} percent\n     * @return {Array.<number>}\n     */\n    pointAt: function (p) {\n        var shape = this.shape;\n        return [\n            shape.x1 * (1 - p) + shape.x2 * p,\n            shape.y1 * (1 - p) + shape.y2 * p\n        ];\n    }\n});\n\n/**\n * 贝塞尔曲线\n * @module zrender/shape/BezierCurve\n */\n\nvar out = [];\n\nfunction someVectorAt(shape, t, isTangent) {\n    var cpx2 = shape.cpx2;\n    var cpy2 = shape.cpy2;\n    if (cpx2 === null || cpy2 === null) {\n        return [\n            (isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t),\n            (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t)\n        ];\n    }\n    else {\n        return [\n            (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t),\n            (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t)\n        ];\n    }\n}\n\nvar BezierCurve = Path.extend({\n\n    type: 'bezier-curve',\n\n    shape: {\n        x1: 0,\n        y1: 0,\n        x2: 0,\n        y2: 0,\n        cpx1: 0,\n        cpy1: 0,\n        // cpx2: 0,\n        // cpy2: 0\n\n        // Curve show percent, for animating\n        percent: 1\n    },\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        var x1 = shape.x1;\n        var y1 = shape.y1;\n        var x2 = shape.x2;\n        var y2 = shape.y2;\n        var cpx1 = shape.cpx1;\n        var cpy1 = shape.cpy1;\n        var cpx2 = shape.cpx2;\n        var cpy2 = shape.cpy2;\n        var percent = shape.percent;\n        if (percent === 0) {\n            return;\n        }\n\n        ctx.moveTo(x1, y1);\n\n        if (cpx2 == null || cpy2 == null) {\n            if (percent < 1) {\n                quadraticSubdivide(\n                    x1, cpx1, x2, percent, out\n                );\n                cpx1 = out[1];\n                x2 = out[2];\n                quadraticSubdivide(\n                    y1, cpy1, y2, percent, out\n                );\n                cpy1 = out[1];\n                y2 = out[2];\n            }\n\n            ctx.quadraticCurveTo(\n                cpx1, cpy1,\n                x2, y2\n            );\n        }\n        else {\n            if (percent < 1) {\n                cubicSubdivide(\n                    x1, cpx1, cpx2, x2, percent, out\n                );\n                cpx1 = out[1];\n                cpx2 = out[2];\n                x2 = out[3];\n                cubicSubdivide(\n                    y1, cpy1, cpy2, y2, percent, out\n                );\n                cpy1 = out[1];\n                cpy2 = out[2];\n                y2 = out[3];\n            }\n            ctx.bezierCurveTo(\n                cpx1, cpy1,\n                cpx2, cpy2,\n                x2, y2\n            );\n        }\n    },\n\n    /**\n     * Get point at percent\n     * @param  {number} t\n     * @return {Array.<number>}\n     */\n    pointAt: function (t) {\n        return someVectorAt(this.shape, t, false);\n    },\n\n    /**\n     * Get tangent at percent\n     * @param  {number} t\n     * @return {Array.<number>}\n     */\n    tangentAt: function (t) {\n        var p = someVectorAt(this.shape, t, true);\n        return normalize(p, p);\n    }\n});\n\n/**\n * 圆弧\n * @module zrender/graphic/shape/Arc\n */\n\nvar Arc = Path.extend({\n\n    type: 'arc',\n\n    shape: {\n\n        cx: 0,\n\n        cy: 0,\n\n        r: 0,\n\n        startAngle: 0,\n\n        endAngle: Math.PI * 2,\n\n        clockwise: true\n    },\n\n    style: {\n\n        stroke: '#000',\n\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n\n        var x = shape.cx;\n        var y = shape.cy;\n        var r = Math.max(shape.r, 0);\n        var startAngle = shape.startAngle;\n        var endAngle = shape.endAngle;\n        var clockwise = shape.clockwise;\n\n        var unitX = Math.cos(startAngle);\n        var unitY = Math.sin(startAngle);\n\n        ctx.moveTo(unitX * r + x, unitY * r + y);\n        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);\n    }\n});\n\n// CompoundPath to improve performance\n\nvar CompoundPath = Path.extend({\n\n    type: 'compound',\n\n    shape: {\n\n        paths: null\n    },\n\n    _updatePathDirty: function () {\n        var dirtyPath = this.__dirtyPath;\n        var paths = this.shape.paths;\n        for (var i = 0; i < paths.length; i++) {\n            // Mark as dirty if any subpath is dirty\n            dirtyPath = dirtyPath || paths[i].__dirtyPath;\n        }\n        this.__dirtyPath = dirtyPath;\n        this.__dirty = this.__dirty || dirtyPath;\n    },\n\n    beforeBrush: function () {\n        this._updatePathDirty();\n        var paths = this.shape.paths || [];\n        var scale = this.getGlobalScale();\n        // Update path scale\n        for (var i = 0; i < paths.length; i++) {\n            if (!paths[i].path) {\n                paths[i].createPathProxy();\n            }\n            paths[i].path.setScale(scale[0], scale[1]);\n        }\n    },\n\n    buildPath: function (ctx, shape) {\n        var paths = shape.paths || [];\n        for (var i = 0; i < paths.length; i++) {\n            paths[i].buildPath(ctx, paths[i].shape, true);\n        }\n    },\n\n    afterBrush: function () {\n        var paths = this.shape.paths || [];\n        for (var i = 0; i < paths.length; i++) {\n            paths[i].__dirtyPath = false;\n        }\n    },\n\n    getBoundingRect: function () {\n        this._updatePathDirty();\n        return Path.prototype.getBoundingRect.call(this);\n    }\n});\n\n/**\n * @param {Array.<Object>} colorStops\n */\nvar Gradient = function (colorStops) {\n\n    this.colorStops = colorStops || [];\n\n};\n\nGradient.prototype = {\n\n    constructor: Gradient,\n\n    addColorStop: function (offset, color) {\n        this.colorStops.push({\n\n            offset: offset,\n\n            color: color\n        });\n    }\n\n};\n\n/**\n * x, y, x2, y2 are all percent from 0 to 1\n * @param {number} [x=0]\n * @param {number} [y=0]\n * @param {number} [x2=1]\n * @param {number} [y2=0]\n * @param {Array.<Object>} colorStops\n * @param {boolean} [globalCoord=false]\n */\nvar LinearGradient = function (x, y, x2, y2, colorStops, globalCoord) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {type: 'linear', colorStops: ...}`, where\n    // this constructor will not be called.\n\n    this.x = x == null ? 0 : x;\n\n    this.y = y == null ? 0 : y;\n\n    this.x2 = x2 == null ? 1 : x2;\n\n    this.y2 = y2 == null ? 0 : y2;\n\n    // Can be cloned\n    this.type = 'linear';\n\n    // If use global coord\n    this.global = globalCoord || false;\n\n    Gradient.call(this, colorStops);\n};\n\nLinearGradient.prototype = {\n\n    constructor: LinearGradient\n};\n\ninherits(LinearGradient, Gradient);\n\n/**\n * x, y, r are all percent from 0 to 1\n * @param {number} [x=0.5]\n * @param {number} [y=0.5]\n * @param {number} [r=0.5]\n * @param {Array.<Object>} [colorStops]\n * @param {boolean} [globalCoord=false]\n */\nvar RadialGradient = function (x, y, r, colorStops, globalCoord) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {type: 'radial', colorStops: ...}`, where\n    // this constructor will not be called.\n\n    this.x = x == null ? 0.5 : x;\n\n    this.y = y == null ? 0.5 : y;\n\n    this.r = r == null ? 0.5 : r;\n\n    // Can be cloned\n    this.type = 'radial';\n\n    // If use global coord\n    this.global = globalCoord || false;\n\n    Gradient.call(this, colorStops);\n};\n\nRadialGradient.prototype = {\n\n    constructor: RadialGradient\n};\n\ninherits(RadialGradient, Gradient);\n\n/**\n * Displayable for incremental rendering. It will be rendered in a separate layer\n * IncrementalDisplay have two main methods. `clearDisplayables` and `addDisplayables`\n * addDisplayables will render the added displayables incremetally.\n *\n * It use a not clearFlag to tell the painter don't clear the layer if it's the first element.\n */\n// TODO Style override ?\nfunction IncrementalDisplayble(opts) {\n\n    Displayable.call(this, opts);\n\n    this._displayables = [];\n\n    this._temporaryDisplayables = [];\n\n    this._cursor = 0;\n\n    this.notClear = true;\n}\n\nIncrementalDisplayble.prototype.incremental = true;\n\nIncrementalDisplayble.prototype.clearDisplaybles = function () {\n    this._displayables = [];\n    this._temporaryDisplayables = [];\n    this._cursor = 0;\n    this.dirty();\n\n    this.notClear = false;\n};\n\nIncrementalDisplayble.prototype.addDisplayable = function (displayable, notPersistent) {\n    if (notPersistent) {\n        this._temporaryDisplayables.push(displayable);\n    }\n    else {\n        this._displayables.push(displayable);\n    }\n    this.dirty();\n};\n\nIncrementalDisplayble.prototype.addDisplayables = function (displayables, notPersistent) {\n    notPersistent = notPersistent || false;\n    for (var i = 0; i < displayables.length; i++) {\n        this.addDisplayable(displayables[i], notPersistent);\n    }\n};\n\nIncrementalDisplayble.prototype.eachPendingDisplayable = function (cb) {\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        cb && cb(this._displayables[i]);\n    }\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        cb && cb(this._temporaryDisplayables[i]);\n    }\n};\n\nIncrementalDisplayble.prototype.update = function () {\n    this.updateTransform();\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        var displayable = this._displayables[i];\n        // PENDING\n        displayable.parent = this;\n        displayable.update();\n        displayable.parent = null;\n    }\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        var displayable = this._temporaryDisplayables[i];\n        // PENDING\n        displayable.parent = this;\n        displayable.update();\n        displayable.parent = null;\n    }\n};\n\nIncrementalDisplayble.prototype.brush = function (ctx, prevEl) {\n    // Render persistant displayables.\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        var displayable = this._displayables[i];\n        displayable.beforeBrush && displayable.beforeBrush(ctx);\n        displayable.brush(ctx, i === this._cursor ? null : this._displayables[i - 1]);\n        displayable.afterBrush && displayable.afterBrush(ctx);\n    }\n    this._cursor = i;\n    // Render temporary displayables.\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        var displayable = this._temporaryDisplayables[i];\n        displayable.beforeBrush && displayable.beforeBrush(ctx);\n        displayable.brush(ctx, i === 0 ? null : this._temporaryDisplayables[i - 1]);\n        displayable.afterBrush && displayable.afterBrush(ctx);\n    }\n\n    this._temporaryDisplayables = [];\n\n    this.notClear = true;\n};\n\nvar m = [];\nIncrementalDisplayble.prototype.getBoundingRect = function () {\n    if (!this._rect) {\n        var rect = new BoundingRect(Infinity, Infinity, -Infinity, -Infinity);\n        for (var i = 0; i < this._displayables.length; i++) {\n            var displayable = this._displayables[i];\n            var childRect = displayable.getBoundingRect().clone();\n            if (displayable.needLocalTransform()) {\n                childRect.applyTransform(displayable.getLocalTransform(m));\n            }\n            rect.union(childRect);\n        }\n        this._rect = rect;\n    }\n    return this._rect;\n};\n\nIncrementalDisplayble.prototype.contain = function (x, y) {\n    var localPos = this.transformCoordToLocal(x, y);\n    var rect = this.getBoundingRect();\n\n    if (rect.contain(localPos[0], localPos[1])) {\n        for (var i = 0; i < this._displayables.length; i++) {\n            var displayable = this._displayables[i];\n            if (displayable.contain(x, y)) {\n                return true;\n            }\n        }\n    }\n    return false;\n};\n\ninherits(IncrementalDisplayble, Displayable);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar round = Math.round;\nvar mathMax$1 = Math.max;\nvar mathMin$1 = Math.min;\n\nvar EMPTY_OBJ = {};\n\nvar Z2_EMPHASIS_LIFT = 1;\n\n/**\n * Extend shape with parameters\n */\nfunction extendShape(opts) {\n    return Path.extend(opts);\n}\n\n/**\n * Extend path\n */\nfunction extendPath(pathData, opts) {\n    return extendFromString(pathData, opts);\n}\n\n/**\n * Create a path element from path data string\n * @param {string} pathData\n * @param {Object} opts\n * @param {module:zrender/core/BoundingRect} rect\n * @param {string} [layout=cover] 'center' or 'cover'\n */\nfunction makePath(pathData, opts, rect, layout) {\n    var path = createFromString(pathData, opts);\n    if (rect) {\n        if (layout === 'center') {\n            rect = centerGraphic(rect, path.getBoundingRect());\n        }\n        resizePath(path, rect);\n    }\n    return path;\n}\n\n/**\n * Create a image element from image url\n * @param {string} imageUrl image url\n * @param {Object} opts options\n * @param {module:zrender/core/BoundingRect} rect constrain rect\n * @param {string} [layout=cover] 'center' or 'cover'\n */\nfunction makeImage(imageUrl, rect, layout) {\n    var path = new ZImage({\n        style: {\n            image: imageUrl,\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        },\n        onload: function (img) {\n            if (layout === 'center') {\n                var boundingRect = {\n                    width: img.width,\n                    height: img.height\n                };\n                path.setStyle(centerGraphic(rect, boundingRect));\n            }\n        }\n    });\n    return path;\n}\n\n/**\n * Get position of centered element in bounding box.\n *\n * @param  {Object} rect         element local bounding box\n * @param  {Object} boundingRect constraint bounding box\n * @return {Object} element position containing x, y, width, and height\n */\nfunction centerGraphic(rect, boundingRect) {\n    // Set rect to center, keep width / height ratio.\n    var aspect = boundingRect.width / boundingRect.height;\n    var width = rect.height * aspect;\n    var height;\n    if (width <= rect.width) {\n        height = rect.height;\n    }\n    else {\n        width = rect.width;\n        height = width / aspect;\n    }\n    var cx = rect.x + rect.width / 2;\n    var cy = rect.y + rect.height / 2;\n\n    return {\n        x: cx - width / 2,\n        y: cy - height / 2,\n        width: width,\n        height: height\n    };\n}\n\nvar mergePath = mergePath$1;\n\n/**\n * Resize a path to fit the rect\n * @param {module:zrender/graphic/Path} path\n * @param {Object} rect\n */\nfunction resizePath(path, rect) {\n    if (!path.applyTransform) {\n        return;\n    }\n\n    var pathRect = path.getBoundingRect();\n\n    var m = pathRect.calculateTransform(rect);\n\n    path.applyTransform(m);\n}\n\n/**\n * Sub pixel optimize line for canvas\n *\n * @param {Object} param\n * @param {Object} [param.shape]\n * @param {number} [param.shape.x1]\n * @param {number} [param.shape.y1]\n * @param {number} [param.shape.x2]\n * @param {number} [param.shape.y2]\n * @param {Object} [param.style]\n * @param {number} [param.style.lineWidth]\n * @return {Object} Modified param\n */\nfunction subPixelOptimizeLine(param) {\n    var shape = param.shape;\n    var lineWidth = param.style.lineWidth;\n\n    if (round(shape.x1 * 2) === round(shape.x2 * 2)) {\n        shape.x1 = shape.x2 = subPixelOptimize(shape.x1, lineWidth, true);\n    }\n    if (round(shape.y1 * 2) === round(shape.y2 * 2)) {\n        shape.y1 = shape.y2 = subPixelOptimize(shape.y1, lineWidth, true);\n    }\n    return param;\n}\n\n/**\n * Sub pixel optimize rect for canvas\n *\n * @param {Object} param\n * @param {Object} [param.shape]\n * @param {number} [param.shape.x]\n * @param {number} [param.shape.y]\n * @param {number} [param.shape.width]\n * @param {number} [param.shape.height]\n * @param {Object} [param.style]\n * @param {number} [param.style.lineWidth]\n * @return {Object} Modified param\n */\nfunction subPixelOptimizeRect(param) {\n    var shape = param.shape;\n    var lineWidth = param.style.lineWidth;\n    var originX = shape.x;\n    var originY = shape.y;\n    var originWidth = shape.width;\n    var originHeight = shape.height;\n    shape.x = subPixelOptimize(shape.x, lineWidth, true);\n    shape.y = subPixelOptimize(shape.y, lineWidth, true);\n    shape.width = Math.max(\n        subPixelOptimize(originX + originWidth, lineWidth, false) - shape.x,\n        originWidth === 0 ? 0 : 1\n    );\n    shape.height = Math.max(\n        subPixelOptimize(originY + originHeight, lineWidth, false) - shape.y,\n        originHeight === 0 ? 0 : 1\n    );\n    return param;\n}\n\n/**\n * Sub pixel optimize for canvas\n *\n * @param {number} position Coordinate, such as x, y\n * @param {number} lineWidth Should be nonnegative integer.\n * @param {boolean=} positiveOrNegative Default false (negative).\n * @return {number} Optimized position.\n */\nfunction subPixelOptimize(position, lineWidth, positiveOrNegative) {\n    // Assure that (position + lineWidth / 2) is near integer edge,\n    // otherwise line will be fuzzy in canvas.\n    var doubledPosition = round(position * 2);\n    return (doubledPosition + round(lineWidth)) % 2 === 0\n        ? doubledPosition / 2\n        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;\n}\n\nfunction hasFillOrStroke(fillOrStroke) {\n    return fillOrStroke != null && fillOrStroke !== 'none';\n}\n\n// Most lifted color are duplicated.\nvar liftedColorMap = createHashMap();\nvar liftedColorCount = 0;\n\nfunction liftColor(color) {\n    if (typeof color !== 'string') {\n        return color;\n    }\n    var liftedColor = liftedColorMap.get(color);\n    if (!liftedColor) {\n        liftedColor = lift(color, -0.1);\n        if (liftedColorCount < 10000) {\n            liftedColorMap.set(color, liftedColor);\n            liftedColorCount++;\n        }\n    }\n    return liftedColor;\n}\n\nfunction cacheElementStl(el) {\n    if (!el.__hoverStlDirty) {\n        return;\n    }\n    el.__hoverStlDirty = false;\n\n    var hoverStyle = el.__hoverStl;\n    if (!hoverStyle) {\n        el.__cachedNormalStl = el.__cachedNormalZ2 = null;\n        return;\n    }\n\n    var normalStyle = el.__cachedNormalStl = {};\n    el.__cachedNormalZ2 = el.z2;\n    var elStyle = el.style;\n\n    for (var name in hoverStyle) {\n        // See comment in `doSingleEnterHover`.\n        if (hoverStyle[name] != null) {\n            normalStyle[name] = elStyle[name];\n        }\n    }\n\n    // Always cache fill and stroke to normalStyle for lifting color.\n    normalStyle.fill = elStyle.fill;\n    normalStyle.stroke = elStyle.stroke;\n}\n\nfunction doSingleEnterHover(el) {\n    var hoverStl = el.__hoverStl;\n\n    if (!hoverStl || el.__highlighted) {\n        return;\n    }\n\n    var useHoverLayer = el.useHoverLayer;\n    el.__highlighted = useHoverLayer ? 'layer' : 'plain';\n\n    var zr = el.__zr;\n    if (!zr && useHoverLayer) {\n        return;\n    }\n\n    var elTarget = el;\n    var targetStyle = el.style;\n\n    if (useHoverLayer) {\n        elTarget = zr.addHover(el);\n        targetStyle = elTarget.style;\n    }\n\n    rollbackDefaultTextStyle(targetStyle);\n\n    if (!useHoverLayer) {\n        cacheElementStl(elTarget);\n    }\n\n    // styles can be:\n    // {\n    //    label: {\n    //        show: false,\n    //        position: 'outside',\n    //        fontSize: 18\n    //    },\n    //    emphasis: {\n    //        label: {\n    //            show: true\n    //        }\n    //    }\n    // },\n    // where properties of `emphasis` may not appear in `normal`. We previously use\n    // module:echarts/util/model#defaultEmphasis to merge `normal` to `emphasis`.\n    // But consider rich text and setOption in merge mode, it is impossible to cover\n    // all properties in merge. So we use merge mode when setting style here, where\n    // only properties that is not `null/undefined` can be set. The disadventage:\n    // null/undefined can not be used to remove style any more in `emphasis`.\n    targetStyle.extendFrom(hoverStl);\n\n    setDefaultHoverFillStroke(targetStyle, hoverStl, 'fill');\n    setDefaultHoverFillStroke(targetStyle, hoverStl, 'stroke');\n\n    applyDefaultTextStyle(targetStyle);\n\n    if (!useHoverLayer) {\n        el.dirty(false);\n        el.z2 += Z2_EMPHASIS_LIFT;\n    }\n}\n\nfunction setDefaultHoverFillStroke(targetStyle, hoverStyle, prop) {\n    if (!hasFillOrStroke(hoverStyle[prop]) && hasFillOrStroke(targetStyle[prop])) {\n        targetStyle[prop] = liftColor(targetStyle[prop]);\n    }\n}\n\nfunction doSingleLeaveHover(el) {\n    var highlighted = el.__highlighted;\n\n    if (!highlighted) {\n        return;\n    }\n\n    el.__highlighted = false;\n\n    if (highlighted === 'layer') {\n        el.__zr && el.__zr.removeHover(el);\n    }\n    else if (highlighted) {\n        var style = el.style;\n\n        var normalStl = el.__cachedNormalStl;\n        if (normalStl) {\n            rollbackDefaultTextStyle(style);\n            // Consider null/undefined value, should use\n            // `setStyle` but not `extendFrom(stl, true)`.\n            el.setStyle(normalStl);\n            applyDefaultTextStyle(style);\n        }\n        // `__cachedNormalZ2` will not be reset if calling `setElementHoverStyle`\n        // when `el` is on emphasis state. So here by comparing with 1, we try\n        // hard to make the bug case rare.\n        var normalZ2 = el.__cachedNormalZ2;\n        if (normalZ2 != null && el.z2 - normalZ2 === Z2_EMPHASIS_LIFT) {\n            el.z2 = normalZ2;\n        }\n    }\n}\n\nfunction traverseCall(el, method) {\n    el.isGroup\n        ? el.traverse(function (child) {\n            !child.isGroup && method(child);\n        })\n        : method(el);\n}\n\n/**\n * Set hover style (namely \"emphasis style\") of element, based on the current\n * style of the given `el`.\n * This method should be called after all of the normal styles have been adopted\n * to the `el`. See the reason on `setHoverStyle`.\n *\n * @param {module:zrender/Element} el Should not be `zrender/container/Group`.\n * @param {Object|boolean} [hoverStl] The specified hover style.\n *        If set as `false`, disable the hover style.\n *        Similarly, The `el.hoverStyle` can alse be set\n *        as `false` to disable the hover style.\n *        Otherwise, use the default hover style if not provided.\n * @param {Object} [opt]\n * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`\n */\nfunction setElementHoverStyle(el, hoverStl) {\n    // For performance consideration, it might be better to make the \"hover style\" only the\n    // difference properties from the \"normal style\", but not a entire copy of all styles.\n    hoverStl = el.__hoverStl = hoverStl !== false && (hoverStl || {});\n    el.__hoverStlDirty = true;\n\n    // FIXME\n    // It is not completely right to save \"normal\"/\"emphasis\" flag on elements.\n    // It probably should be saved on `data` of series. Consider the cases:\n    // (1) A highlighted elements are moved out of the view port and re-enter\n    // again by dataZoom.\n    // (2) call `setOption` and replace elements totally when they are highlighted.\n    if (el.__highlighted) {\n        // Consider the case:\n        // The styles of a highlighted `el` is being updated. The new \"emphasis style\"\n        // should be adapted to the `el`. Notice here new \"normal styles\" should have\n        // been set outside and the cached \"normal style\" is out of date.\n        el.__cachedNormalStl = null;\n        // Do not clear `__cachedNormalZ2` here, because setting `z2` is not a constraint\n        // of this method. In most cases, `z2` is not set and hover style should be able\n        // to rollback. Of course, that would bring bug, but only in a rare case, see\n        // `doSingleLeaveHover` for details.\n        doSingleLeaveHover(el);\n\n        doSingleEnterHover(el);\n    }\n}\n\n/**\n * Emphasis (called by API) has higher priority than `mouseover`.\n * When element has been called to be entered emphasis, mouse over\n * should not trigger the highlight effect (for example, animation\n * scale) again, and `mouseout` should not downplay the highlight\n * effect. So the listener of `mouseover` and `mouseout` should\n * check `isInEmphasis`.\n *\n * @param {module:zrender/Element} el\n * @return {boolean}\n */\nfunction isInEmphasis(el) {\n    return el && el.__isEmphasisEntered;\n}\n\nfunction onElementMouseOver(e) {\n    if (this.__hoverSilentOnTouch && e.zrByTouch) {\n        return;\n    }\n\n    // Only if element is not in emphasis status\n    !this.__isEmphasisEntered && traverseCall(this, doSingleEnterHover);\n}\n\nfunction onElementMouseOut(e) {\n    if (this.__hoverSilentOnTouch && e.zrByTouch) {\n        return;\n    }\n\n    // Only if element is not in emphasis status\n    !this.__isEmphasisEntered && traverseCall(this, doSingleLeaveHover);\n}\n\nfunction enterEmphasis() {\n    this.__isEmphasisEntered = true;\n    traverseCall(this, doSingleEnterHover);\n}\n\nfunction leaveEmphasis() {\n    this.__isEmphasisEntered = false;\n    traverseCall(this, doSingleLeaveHover);\n}\n\n/**\n * Set hover style (namely \"emphasis style\") of element,\n * based on the current style of the given `el`.\n *\n * (1)\n * **CONSTRAINTS** for this method:\n * <A> This method MUST be called after all of the normal styles having been adopted\n * to the `el`.\n * <B> The input `hoverStyle` (that is, \"emphasis style\") MUST be the subset of the\n * \"normal style\" having been set to the el.\n * <C> `color` MUST be one of the \"normal styles\" (because color might be lifted as\n * a default hover style).\n *\n * The reason: this method treat the current style of the `el` as the \"normal style\"\n * and cache them when enter/update the \"emphasis style\". Consider the case: the `el`\n * is in \"emphasis\" state and `setOption`/`dispatchAction` trigger the style updating\n * logic, where the el should shift from the original emphasis style to the new\n * \"emphasis style\" and should be able to \"downplay\" back to the new \"normal style\".\n *\n * Indeed, it is error-prone to make a interface has so many constraints, but I have\n * not found a better solution yet to fit the backward compatibility, performance and\n * the current programming style.\n *\n * (2)\n * Call the method for a \"root\" element once. Do not call it for each descendants.\n * If the descendants elemenets of a group has itself hover style different from the\n * root group, we can simply mount the style on `el.hoverStyle` for them, but should\n * not call this method for them.\n *\n * @param {module:zrender/Element} el\n * @param {Object|boolean} [hoverStyle] See `graphic.setElementHoverStyle`.\n * @param {Object} [opt]\n * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`.\n */\nfunction setHoverStyle(el, hoverStyle, opt) {\n    el.isGroup\n        ? el.traverse(function (child) {\n            // If element has sepcified hoverStyle, then use it instead of given hoverStyle\n            // Often used when item group has a label element and it's hoverStyle is different\n            !child.isGroup && setElementHoverStyle(child, child.hoverStyle || hoverStyle);\n        })\n        : setElementHoverStyle(el, el.hoverStyle || hoverStyle);\n\n    setAsHoverStyleTrigger(el, opt);\n}\n\n/**\n * @param {Object|boolean} [opt] If `false`, means disable trigger.\n * @param {boolean} [opt.hoverSilentOnTouch=false]\n *        In touch device, mouseover event will be trigger on touchstart event\n *        (see module:zrender/dom/HandlerProxy). By this mechanism, we can\n *        conveniently use hoverStyle when tap on touch screen without additional\n *        code for compatibility.\n *        But if the chart/component has select feature, which usually also use\n *        hoverStyle, there might be conflict between 'select-highlight' and\n *        'hover-highlight' especially when roam is enabled (see geo for example).\n *        In this case, hoverSilentOnTouch should be used to disable hover-highlight\n *        on touch device.\n */\nfunction setAsHoverStyleTrigger(el, opt) {\n    var disable = opt === false;\n    el.__hoverSilentOnTouch = opt != null && opt.hoverSilentOnTouch;\n\n    // Simple optimize, since this method might be\n    // called for each elements of a group in some cases.\n    if (!disable || el.__hoverStyleTrigger) {\n        var method = disable ? 'off' : 'on';\n\n        // Duplicated function will be auto-ignored, see Eventful.js.\n        el[method]('mouseover', onElementMouseOver)[method]('mouseout', onElementMouseOut);\n        // Emphasis, normal can be triggered manually\n        el[method]('emphasis', enterEmphasis)[method]('normal', leaveEmphasis);\n\n        el.__hoverStyleTrigger = !disable;\n    }\n}\n\n/**\n * See more info in `setTextStyleCommon`.\n * @param {Object|module:zrender/graphic/Style} normalStyle\n * @param {Object} emphasisStyle\n * @param {module:echarts/model/Model} normalModel\n * @param {module:echarts/model/Model} emphasisModel\n * @param {Object} opt Check `opt` of `setTextStyleCommon` to find other props.\n * @param {string|Function} [opt.defaultText]\n * @param {module:echarts/model/Model} [opt.labelFetcher] Fetch text by\n *      `opt.labelFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {module:echarts/model/Model} [opt.labelDataIndex] Fetch text by\n *      `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {module:echarts/model/Model} [opt.labelDimIndex] Fetch text by\n *      `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {Object} [normalSpecified]\n * @param {Object} [emphasisSpecified]\n */\nfunction setLabelStyle(\n    normalStyle, emphasisStyle,\n    normalModel, emphasisModel,\n    opt,\n    normalSpecified, emphasisSpecified\n) {\n    opt = opt || EMPTY_OBJ;\n    var labelFetcher = opt.labelFetcher;\n    var labelDataIndex = opt.labelDataIndex;\n    var labelDimIndex = opt.labelDimIndex;\n\n    // This scenario, `label.normal.show = true; label.emphasis.show = false`,\n    // is not supported util someone requests.\n\n    var showNormal = normalModel.getShallow('show');\n    var showEmphasis = emphasisModel.getShallow('show');\n\n    // Consider performance, only fetch label when necessary.\n    // If `normal.show` is `false` and `emphasis.show` is `true` and `emphasis.formatter` is not set,\n    // label should be displayed, where text is fetched by `normal.formatter` or `opt.defaultText`.\n    var baseText;\n    if (showNormal || showEmphasis) {\n        if (labelFetcher) {\n            baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex);\n        }\n        if (baseText == null) {\n            baseText = isFunction$1(opt.defaultText) ? opt.defaultText(labelDataIndex, opt) : opt.defaultText;\n        }\n    }\n    var normalStyleText = showNormal ? baseText : null;\n    var emphasisStyleText = showEmphasis\n        ? retrieve2(\n            labelFetcher\n                ? labelFetcher.getFormattedLabel(labelDataIndex, 'emphasis', null, labelDimIndex)\n                : null,\n            baseText\n        )\n        : null;\n\n    // Optimize: If style.text is null, text will not be drawn.\n    if (normalStyleText != null || emphasisStyleText != null) {\n        // Always set `textStyle` even if `normalStyle.text` is null, because default\n        // values have to be set on `normalStyle`.\n        // If we set default values on `emphasisStyle`, consider case:\n        // Firstly, `setOption(... label: {normal: {text: null}, emphasis: {show: true}} ...);`\n        // Secondly, `setOption(... label: {noraml: {show: true, text: 'abc', color: 'red'} ...);`\n        // Then the 'red' will not work on emphasis.\n        setTextStyle(normalStyle, normalModel, normalSpecified, opt);\n        setTextStyle(emphasisStyle, emphasisModel, emphasisSpecified, opt, true);\n    }\n\n    normalStyle.text = normalStyleText;\n    emphasisStyle.text = emphasisStyleText;\n}\n\n/**\n * Set basic textStyle properties.\n * See more info in `setTextStyleCommon`.\n * @param {Object|module:zrender/graphic/Style} textStyle\n * @param {module:echarts/model/Model} model\n * @param {Object} [specifiedTextStyle] Can be overrided by settings in model.\n * @param {Object} [opt] See `opt` of `setTextStyleCommon`.\n * @param {boolean} [isEmphasis]\n */\nfunction setTextStyle(\n    textStyle, textStyleModel, specifiedTextStyle, opt, isEmphasis\n) {\n    setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis);\n    specifiedTextStyle && extend(textStyle, specifiedTextStyle);\n    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);\n\n    return textStyle;\n}\n\n/**\n * Set text option in the style.\n * See more info in `setTextStyleCommon`.\n * @deprecated\n * @param {Object} textStyle\n * @param {module:echarts/model/Model} labelModel\n * @param {string|boolean} defaultColor Default text color.\n *        If set as false, it will be processed as a emphasis style.\n */\nfunction setText(textStyle, labelModel, defaultColor) {\n    var opt = {isRectText: true};\n    var isEmphasis;\n\n    if (defaultColor === false) {\n        isEmphasis = true;\n    }\n    else {\n        // Support setting color as 'auto' to get visual color.\n        opt.autoColor = defaultColor;\n    }\n    setTextStyleCommon(textStyle, labelModel, opt, isEmphasis);\n    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);\n}\n\n/**\n * The uniform entry of set text style, that is, retrieve style definitions\n * from `model` and set to `textStyle` object.\n *\n * Never in merge mode, but in overwrite mode, that is, all of the text style\n * properties will be set. (Consider the states of normal and emphasis and\n * default value can be adopted, merge would make the logic too complicated\n * to manage.)\n *\n * The `textStyle` object can either be a plain object or an instance of\n * `zrender/src/graphic/Style`, and either be the style of normal or emphasis.\n * After this mothod called, the `textStyle` object can then be used in\n * `el.setStyle(textStyle)` or `el.hoverStyle = textStyle`.\n *\n * Default value will be adopted and `insideRollbackOpt` will be created.\n * See `applyDefaultTextStyle` `rollbackDefaultTextStyle` for more details.\n *\n * opt: {\n *      disableBox: boolean, Whether diable drawing box of block (outer most).\n *      isRectText: boolean,\n *      autoColor: string, specify a color when color is 'auto',\n *              for textFill, textStroke, textBackgroundColor, and textBorderColor.\n *              If autoColor specified, it is used as default textFill.\n *      useInsideStyle:\n *              `true`: Use inside style (textFill, textStroke, textStrokeWidth)\n *                  if `textFill` is not specified.\n *              `false`: Do not use inside style.\n *              `null/undefined`: use inside style if `isRectText` is true and\n *                  `textFill` is not specified and textPosition contains `'inside'`.\n *      forceRich: boolean\n * }\n */\nfunction setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis) {\n    // Consider there will be abnormal when merge hover style to normal style if given default value.\n    opt = opt || EMPTY_OBJ;\n\n    if (opt.isRectText) {\n        var textPosition = textStyleModel.getShallow('position')\n            || (isEmphasis ? null : 'inside');\n        // 'outside' is not a valid zr textPostion value, but used\n        // in bar series, and magric type should be considered.\n        textPosition === 'outside' && (textPosition = 'top');\n        textStyle.textPosition = textPosition;\n        textStyle.textOffset = textStyleModel.getShallow('offset');\n        var labelRotate = textStyleModel.getShallow('rotate');\n        labelRotate != null && (labelRotate *= Math.PI / 180);\n        textStyle.textRotation = labelRotate;\n        textStyle.textDistance = retrieve2(\n            textStyleModel.getShallow('distance'), isEmphasis ? null : 5\n        );\n    }\n\n    var ecModel = textStyleModel.ecModel;\n    var globalTextStyle = ecModel && ecModel.option.textStyle;\n\n    // Consider case:\n    // {\n    //     data: [{\n    //         value: 12,\n    //         label: {\n    //             rich: {\n    //                 // no 'a' here but using parent 'a'.\n    //             }\n    //         }\n    //     }],\n    //     rich: {\n    //         a: { ... }\n    //     }\n    // }\n    var richItemNames = getRichItemNames(textStyleModel);\n    var richResult;\n    if (richItemNames) {\n        richResult = {};\n        for (var name in richItemNames) {\n            if (richItemNames.hasOwnProperty(name)) {\n                // Cascade is supported in rich.\n                var richTextStyle = textStyleModel.getModel(['rich', name]);\n                // In rich, never `disableBox`.\n                setTokenTextStyle(richResult[name] = {}, richTextStyle, globalTextStyle, opt, isEmphasis);\n            }\n        }\n    }\n    textStyle.rich = richResult;\n\n    setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, true);\n\n    if (opt.forceRich && !opt.textStyle) {\n        opt.textStyle = {};\n    }\n\n    return textStyle;\n}\n\n// Consider case:\n// {\n//     data: [{\n//         value: 12,\n//         label: {\n//             rich: {\n//                 // no 'a' here but using parent 'a'.\n//             }\n//         }\n//     }],\n//     rich: {\n//         a: { ... }\n//     }\n// }\nfunction getRichItemNames(textStyleModel) {\n    // Use object to remove duplicated names.\n    var richItemNameMap;\n    while (textStyleModel && textStyleModel !== textStyleModel.ecModel) {\n        var rich = (textStyleModel.option || EMPTY_OBJ).rich;\n        if (rich) {\n            richItemNameMap = richItemNameMap || {};\n            for (var name in rich) {\n                if (rich.hasOwnProperty(name)) {\n                    richItemNameMap[name] = 1;\n                }\n            }\n        }\n        textStyleModel = textStyleModel.parentModel;\n    }\n    return richItemNameMap;\n}\n\nfunction setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, isBlock) {\n    // In merge mode, default value should not be given.\n    globalTextStyle = !isEmphasis && globalTextStyle || EMPTY_OBJ;\n\n    textStyle.textFill = getAutoColor(textStyleModel.getShallow('color'), opt)\n        || globalTextStyle.color;\n    textStyle.textStroke = getAutoColor(textStyleModel.getShallow('textBorderColor'), opt)\n        || globalTextStyle.textBorderColor;\n    textStyle.textStrokeWidth = retrieve2(\n        textStyleModel.getShallow('textBorderWidth'),\n        globalTextStyle.textBorderWidth\n    );\n\n    // Save original textPosition, because style.textPosition will be repalced by\n    // real location (like [10, 30]) in zrender.\n    textStyle.insideRawTextPosition = textStyle.textPosition;\n\n    if (!isEmphasis) {\n        if (isBlock) {\n            textStyle.insideRollbackOpt = opt;\n            applyDefaultTextStyle(textStyle);\n        }\n\n        // Set default finally.\n        if (textStyle.textFill == null) {\n            textStyle.textFill = opt.autoColor;\n        }\n    }\n\n    // Do not use `getFont` here, because merge should be supported, where\n    // part of these properties may be changed in emphasis style, and the\n    // others should remain their original value got from normal style.\n    textStyle.fontStyle = textStyleModel.getShallow('fontStyle') || globalTextStyle.fontStyle;\n    textStyle.fontWeight = textStyleModel.getShallow('fontWeight') || globalTextStyle.fontWeight;\n    textStyle.fontSize = textStyleModel.getShallow('fontSize') || globalTextStyle.fontSize;\n    textStyle.fontFamily = textStyleModel.getShallow('fontFamily') || globalTextStyle.fontFamily;\n\n    textStyle.textAlign = textStyleModel.getShallow('align');\n    textStyle.textVerticalAlign = textStyleModel.getShallow('verticalAlign')\n        || textStyleModel.getShallow('baseline');\n\n    textStyle.textLineHeight = textStyleModel.getShallow('lineHeight');\n    textStyle.textWidth = textStyleModel.getShallow('width');\n    textStyle.textHeight = textStyleModel.getShallow('height');\n    textStyle.textTag = textStyleModel.getShallow('tag');\n\n    if (!isBlock || !opt.disableBox) {\n        textStyle.textBackgroundColor = getAutoColor(textStyleModel.getShallow('backgroundColor'), opt);\n        textStyle.textPadding = textStyleModel.getShallow('padding');\n        textStyle.textBorderColor = getAutoColor(textStyleModel.getShallow('borderColor'), opt);\n        textStyle.textBorderWidth = textStyleModel.getShallow('borderWidth');\n        textStyle.textBorderRadius = textStyleModel.getShallow('borderRadius');\n\n        textStyle.textBoxShadowColor = textStyleModel.getShallow('shadowColor');\n        textStyle.textBoxShadowBlur = textStyleModel.getShallow('shadowBlur');\n        textStyle.textBoxShadowOffsetX = textStyleModel.getShallow('shadowOffsetX');\n        textStyle.textBoxShadowOffsetY = textStyleModel.getShallow('shadowOffsetY');\n    }\n\n    textStyle.textShadowColor = textStyleModel.getShallow('textShadowColor')\n        || globalTextStyle.textShadowColor;\n    textStyle.textShadowBlur = textStyleModel.getShallow('textShadowBlur')\n        || globalTextStyle.textShadowBlur;\n    textStyle.textShadowOffsetX = textStyleModel.getShallow('textShadowOffsetX')\n        || globalTextStyle.textShadowOffsetX;\n    textStyle.textShadowOffsetY = textStyleModel.getShallow('textShadowOffsetY')\n        || globalTextStyle.textShadowOffsetY;\n}\n\nfunction getAutoColor(color, opt) {\n    return color !== 'auto' ? color : (opt && opt.autoColor) ? opt.autoColor : null;\n}\n\n/**\n * Give some default value to the input `textStyle` object, based on the current settings\n * in this `textStyle` object.\n *\n * The Scenario:\n * when text position is `inside` and `textFill` is not specified, we show\n * text border by default for better view. But it should be considered that text position\n * might be changed when hovering or being emphasis, where the `insideRollback` is used to\n * restore the style.\n *\n * Usage (& NOTICE):\n * When a style object (eithor plain object or instance of `zrender/src/graphic/Style`) is\n * about to be modified on its text related properties, `rollbackDefaultTextStyle` should\n * be called before the modification and `applyDefaultTextStyle` should be called after that.\n * (For the case that all of the text related properties is reset, like `setTextStyleCommon`\n * does, `rollbackDefaultTextStyle` is not needed to be called).\n */\nfunction applyDefaultTextStyle(textStyle) {\n    var opt = textStyle.insideRollbackOpt;\n\n    // Only `insideRollbackOpt` created (in `setTextStyleCommon`),\n    // applyDefaultTextStyle works.\n    if (!opt || textStyle.textFill != null) {\n        return;\n    }\n\n    var useInsideStyle = opt.useInsideStyle;\n    var textPosition = textStyle.insideRawTextPosition;\n    var insideRollback;\n    var autoColor = opt.autoColor;\n\n    if (useInsideStyle !== false\n        && (useInsideStyle === true\n            || (opt.isRectText\n                && textPosition\n                // textPosition can be [10, 30]\n                && typeof textPosition === 'string'\n                && textPosition.indexOf('inside') >= 0\n            )\n        )\n    ) {\n        insideRollback = {\n            textFill: null,\n            textStroke: textStyle.textStroke,\n            textStrokeWidth: textStyle.textStrokeWidth\n        };\n        textStyle.textFill = '#fff';\n        // Consider text with #fff overflow its container.\n        if (textStyle.textStroke == null) {\n            textStyle.textStroke = autoColor;\n            textStyle.textStrokeWidth == null && (textStyle.textStrokeWidth = 2);\n        }\n    }\n    else if (autoColor != null) {\n        insideRollback = {textFill: null};\n        textStyle.textFill = autoColor;\n    }\n\n    // Always set `insideRollback`, for clearing previous.\n    if (insideRollback) {\n        textStyle.insideRollback = insideRollback;\n    }\n}\n\n/**\n * Consider the case: in a scatter,\n * label: {\n *     normal: {position: 'inside'},\n *     emphasis: {position: 'top'}\n * }\n * In the normal state, the `textFill` will be set as '#fff' for pretty view (see\n * `applyDefaultTextStyle`), but when switching to emphasis state, the `textFill`\n * should be retured to 'autoColor', but not keep '#fff'.\n */\nfunction rollbackDefaultTextStyle(style) {\n    var insideRollback = style.insideRollback;\n    if (insideRollback) {\n        style.textFill = insideRollback.textFill;\n        style.textStroke = insideRollback.textStroke;\n        style.textStrokeWidth = insideRollback.textStrokeWidth;\n        style.insideRollback = null;\n    }\n}\n\nfunction getFont(opt, ecModel) {\n    // ecModel or default text style model.\n    var gTextStyleModel = ecModel || ecModel.getModel('textStyle');\n    return trim([\n        // FIXME in node-canvas fontWeight is before fontStyle\n        opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '',\n        opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '',\n        (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px',\n        opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'\n    ].join(' '));\n}\n\nfunction animateOrSetProps(isUpdate, el, props, animatableModel, dataIndex, cb) {\n    if (typeof dataIndex === 'function') {\n        cb = dataIndex;\n        dataIndex = null;\n    }\n    // Do not check 'animation' property directly here. Consider this case:\n    // animation model is an `itemModel`, whose does not have `isAnimationEnabled`\n    // but its parent model (`seriesModel`) does.\n    var animationEnabled = animatableModel && animatableModel.isAnimationEnabled();\n\n    if (animationEnabled) {\n        var postfix = isUpdate ? 'Update' : '';\n        var duration = animatableModel.getShallow('animationDuration' + postfix);\n        var animationEasing = animatableModel.getShallow('animationEasing' + postfix);\n        var animationDelay = animatableModel.getShallow('animationDelay' + postfix);\n        if (typeof animationDelay === 'function') {\n            animationDelay = animationDelay(\n                dataIndex,\n                animatableModel.getAnimationDelayParams\n                    ? animatableModel.getAnimationDelayParams(el, dataIndex)\n                    : null\n            );\n        }\n        if (typeof duration === 'function') {\n            duration = duration(dataIndex);\n        }\n\n        duration > 0\n            ? el.animateTo(props, duration, animationDelay || 0, animationEasing, cb, !!cb)\n            : (el.stopAnimation(), el.attr(props), cb && cb());\n    }\n    else {\n        el.stopAnimation();\n        el.attr(props);\n        cb && cb();\n    }\n}\n\n/**\n * Update graphic element properties with or without animation according to the\n * configuration in series.\n *\n * Caution: this method will stop previous animation.\n * So if do not use this method to one element twice before\n * animation starts, unless you know what you are doing.\n *\n * @param {module:zrender/Element} el\n * @param {Object} props\n * @param {module:echarts/model/Model} [animatableModel]\n * @param {number} [dataIndex]\n * @param {Function} [cb]\n * @example\n *     graphic.updateProps(el, {\n *         position: [100, 100]\n *     }, seriesModel, dataIndex, function () { console.log('Animation done!'); });\n *     // Or\n *     graphic.updateProps(el, {\n *         position: [100, 100]\n *     }, seriesModel, function () { console.log('Animation done!'); });\n */\nfunction updateProps(el, props, animatableModel, dataIndex, cb) {\n    animateOrSetProps(true, el, props, animatableModel, dataIndex, cb);\n}\n\n/**\n * Init graphic element properties with or without animation according to the\n * configuration in series.\n *\n * Caution: this method will stop previous animation.\n * So if do not use this method to one element twice before\n * animation starts, unless you know what you are doing.\n *\n * @param {module:zrender/Element} el\n * @param {Object} props\n * @param {module:echarts/model/Model} [animatableModel]\n * @param {number} [dataIndex]\n * @param {Function} cb\n */\nfunction initProps(el, props, animatableModel, dataIndex, cb) {\n    animateOrSetProps(false, el, props, animatableModel, dataIndex, cb);\n}\n\n/**\n * Get transform matrix of target (param target),\n * in coordinate of its ancestor (param ancestor)\n *\n * @param {module:zrender/mixin/Transformable} target\n * @param {module:zrender/mixin/Transformable} [ancestor]\n */\nfunction getTransform(target, ancestor) {\n    var mat = identity([]);\n\n    while (target && target !== ancestor) {\n        mul$1(mat, target.getLocalTransform(), mat);\n        target = target.parent;\n    }\n\n    return mat;\n}\n\n/**\n * Apply transform to an vertex.\n * @param {Array.<number>} target [x, y]\n * @param {Array.<number>|TypedArray.<number>|Object} transform Can be:\n *      + Transform matrix: like [1, 0, 0, 1, 0, 0]\n *      + {position, rotation, scale}, the same as `zrender/Transformable`.\n * @param {boolean=} invert Whether use invert matrix.\n * @return {Array.<number>} [x, y]\n */\nfunction applyTransform$1(target, transform, invert$$1) {\n    if (transform && !isArrayLike(transform)) {\n        transform = Transformable.getLocalTransform(transform);\n    }\n\n    if (invert$$1) {\n        transform = invert([], transform);\n    }\n    return applyTransform([], target, transform);\n}\n\n/**\n * @param {string} direction 'left' 'right' 'top' 'bottom'\n * @param {Array.<number>} transform Transform matrix: like [1, 0, 0, 1, 0, 0]\n * @param {boolean=} invert Whether use invert matrix.\n * @return {string} Transformed direction. 'left' 'right' 'top' 'bottom'\n */\nfunction transformDirection(direction, transform, invert$$1) {\n\n    // Pick a base, ensure that transform result will not be (0, 0).\n    var hBase = (transform[4] === 0 || transform[5] === 0 || transform[0] === 0)\n        ? 1 : Math.abs(2 * transform[4] / transform[0]);\n    var vBase = (transform[4] === 0 || transform[5] === 0 || transform[2] === 0)\n        ? 1 : Math.abs(2 * transform[4] / transform[2]);\n\n    var vertex = [\n        direction === 'left' ? -hBase : direction === 'right' ? hBase : 0,\n        direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0\n    ];\n\n    vertex = applyTransform$1(vertex, transform, invert$$1);\n\n    return Math.abs(vertex[0]) > Math.abs(vertex[1])\n        ? (vertex[0] > 0 ? 'right' : 'left')\n        : (vertex[1] > 0 ? 'bottom' : 'top');\n}\n\n/**\n * Apply group transition animation from g1 to g2.\n * If no animatableModel, no animation.\n */\nfunction groupTransition(g1, g2, animatableModel, cb) {\n    if (!g1 || !g2) {\n        return;\n    }\n\n    function getElMap(g) {\n        var elMap = {};\n        g.traverse(function (el) {\n            if (!el.isGroup && el.anid) {\n                elMap[el.anid] = el;\n            }\n        });\n        return elMap;\n    }\n    function getAnimatableProps(el) {\n        var obj = {\n            position: clone$1(el.position),\n            rotation: el.rotation\n        };\n        if (el.shape) {\n            obj.shape = extend({}, el.shape);\n        }\n        return obj;\n    }\n    var elMap1 = getElMap(g1);\n\n    g2.traverse(function (el) {\n        if (!el.isGroup && el.anid) {\n            var oldEl = elMap1[el.anid];\n            if (oldEl) {\n                var newProp = getAnimatableProps(el);\n                el.attr(getAnimatableProps(oldEl));\n                updateProps(el, newProp, animatableModel, el.dataIndex);\n            }\n            // else {\n            //     if (el.previousProps) {\n            //         graphic.updateProps\n            //     }\n            // }\n        }\n    });\n}\n\n/**\n * @param {Array.<Array.<number>>} points Like: [[23, 44], [53, 66], ...]\n * @param {Object} rect {x, y, width, height}\n * @return {Array.<Array.<number>>} A new clipped points.\n */\nfunction clipPointsByRect(points, rect) {\n    // FIXME: this way migth be incorrect when grpahic clipped by a corner.\n    // and when element have border.\n    return map(points, function (point) {\n        var x = point[0];\n        x = mathMax$1(x, rect.x);\n        x = mathMin$1(x, rect.x + rect.width);\n        var y = point[1];\n        y = mathMax$1(y, rect.y);\n        y = mathMin$1(y, rect.y + rect.height);\n        return [x, y];\n    });\n}\n\n/**\n * @param {Object} targetRect {x, y, width, height}\n * @param {Object} rect {x, y, width, height}\n * @return {Object} A new clipped rect. If rect size are negative, return undefined.\n */\nfunction clipRectByRect(targetRect, rect) {\n    var x = mathMax$1(targetRect.x, rect.x);\n    var x2 = mathMin$1(targetRect.x + targetRect.width, rect.x + rect.width);\n    var y = mathMax$1(targetRect.y, rect.y);\n    var y2 = mathMin$1(targetRect.y + targetRect.height, rect.y + rect.height);\n\n    // If the total rect is cliped, nothing, including the border,\n    // should be painted. So return undefined.\n    if (x2 >= x && y2 >= y) {\n        return {\n            x: x,\n            y: y,\n            width: x2 - x,\n            height: y2 - y\n        };\n    }\n}\n\n/**\n * @param {string} iconStr Support 'image://' or 'path://' or direct svg path.\n * @param {Object} [opt] Properties of `module:zrender/Element`, except `style`.\n * @param {Object} [rect] {x, y, width, height}\n * @return {module:zrender/Element} Icon path or image element.\n */\nfunction createIcon(iconStr, opt, rect) {\n    opt = extend({rectHover: true}, opt);\n    var style = opt.style = {strokeNoScale: true};\n    rect = rect || {x: -1, y: -1, width: 2, height: 2};\n\n    if (iconStr) {\n        return iconStr.indexOf('image://') === 0\n            ? (\n                style.image = iconStr.slice(8),\n                defaults(style, rect),\n                new ZImage(opt)\n            )\n            : (\n                makePath(\n                    iconStr.replace('path://', ''),\n                    opt,\n                    rect,\n                    'center'\n                )\n            );\n    }\n}\n\n\n\n\nvar graphic = (Object.freeze || Object)({\n\tZ2_EMPHASIS_LIFT: Z2_EMPHASIS_LIFT,\n\textendShape: extendShape,\n\textendPath: extendPath,\n\tmakePath: makePath,\n\tmakeImage: makeImage,\n\tmergePath: mergePath,\n\tresizePath: resizePath,\n\tsubPixelOptimizeLine: subPixelOptimizeLine,\n\tsubPixelOptimizeRect: subPixelOptimizeRect,\n\tsubPixelOptimize: subPixelOptimize,\n\tsetElementHoverStyle: setElementHoverStyle,\n\tisInEmphasis: isInEmphasis,\n\tsetHoverStyle: setHoverStyle,\n\tsetAsHoverStyleTrigger: setAsHoverStyleTrigger,\n\tsetLabelStyle: setLabelStyle,\n\tsetTextStyle: setTextStyle,\n\tsetText: setText,\n\tgetFont: getFont,\n\tupdateProps: updateProps,\n\tinitProps: initProps,\n\tgetTransform: getTransform,\n\tapplyTransform: applyTransform$1,\n\ttransformDirection: transformDirection,\n\tgroupTransition: groupTransition,\n\tclipPointsByRect: clipPointsByRect,\n\tclipRectByRect: clipRectByRect,\n\tcreateIcon: createIcon,\n\tGroup: Group,\n\tImage: ZImage,\n\tText: Text,\n\tCircle: Circle,\n\tSector: Sector,\n\tRing: Ring,\n\tPolygon: Polygon,\n\tPolyline: Polyline,\n\tRect: Rect,\n\tLine: Line,\n\tBezierCurve: BezierCurve,\n\tArc: Arc,\n\tIncrementalDisplayable: IncrementalDisplayble,\n\tCompoundPath: CompoundPath,\n\tLinearGradient: LinearGradient,\n\tRadialGradient: RadialGradient,\n\tBoundingRect: BoundingRect\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PATH_COLOR = ['textStyle', 'color'];\n\nvar textStyleMixin = {\n    /**\n     * Get color property or get color from option.textStyle.color\n     * @param {boolean} [isEmphasis]\n     * @return {string}\n     */\n    getTextColor: function (isEmphasis) {\n        var ecModel = this.ecModel;\n        return this.getShallow('color')\n            || (\n                (!isEmphasis && ecModel) ? ecModel.get(PATH_COLOR) : null\n            );\n    },\n\n    /**\n     * Create font string from fontStyle, fontWeight, fontSize, fontFamily\n     * @return {string}\n     */\n    getFont: function () {\n        return getFont({\n            fontStyle: this.getShallow('fontStyle'),\n            fontWeight: this.getShallow('fontWeight'),\n            fontSize: this.getShallow('fontSize'),\n            fontFamily: this.getShallow('fontFamily')\n        }, this.ecModel);\n    },\n\n    getTextRect: function (text) {\n        return getBoundingRect(\n            text,\n            this.getFont(),\n            this.getShallow('align'),\n            this.getShallow('verticalAlign') || this.getShallow('baseline'),\n            this.getShallow('padding'),\n            this.getShallow('lineHeight'),\n            this.getShallow('rich'),\n            this.getShallow('truncateText')\n        );\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getItemStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['stroke', 'borderColor'],\n        ['lineWidth', 'borderWidth'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor'],\n        ['textPosition'],\n        ['textAlign']\n    ]\n);\n\nvar itemStyleMixin = {\n    getItemStyle: function (excludes, includes) {\n        var style = getItemStyle(this, excludes, includes);\n        var lineDash = this.getBorderLineDash();\n        lineDash && (style.lineDash = lineDash);\n        return style;\n    },\n\n    getBorderLineDash: function () {\n        var lineType = this.get('borderType');\n        return (lineType === 'solid' || lineType == null) ? null\n            : (lineType === 'dashed' ? [5, 5] : [1, 1]);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/model/Model\n */\n\nvar mixin$1 = mixin;\nvar inner = makeInner();\n\n/**\n * @alias module:echarts/model/Model\n * @constructor\n * @param {Object} [option]\n * @param {module:echarts/model/Model} [parentModel]\n * @param {module:echarts/model/Global} [ecModel]\n */\nfunction Model(option, parentModel, ecModel) {\n    /**\n     * @type {module:echarts/model/Model}\n     * @readOnly\n     */\n    this.parentModel = parentModel;\n\n    /**\n     * @type {module:echarts/model/Global}\n     * @readOnly\n     */\n    this.ecModel = ecModel;\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    this.option = option;\n\n    // Simple optimization\n    // if (this.init) {\n    //     if (arguments.length <= 4) {\n    //         this.init(option, parentModel, ecModel, extraOpt);\n    //     }\n    //     else {\n    //         this.init.apply(this, arguments);\n    //     }\n    // }\n}\n\nModel.prototype = {\n\n    constructor: Model,\n\n    /**\n     * Model 的初始化函数\n     * @param {Object} option\n     */\n    init: null,\n\n    /**\n     * 从新的 Option merge\n     */\n    mergeOption: function (option) {\n        merge(this.option, option, true);\n    },\n\n    /**\n     * @param {string|Array.<string>} path\n     * @param {boolean} [ignoreParent=false]\n     * @return {*}\n     */\n    get: function (path, ignoreParent) {\n        if (path == null) {\n            return this.option;\n        }\n\n        return doGet(\n            this.option,\n            this.parsePath(path),\n            !ignoreParent && getParent(this, path)\n        );\n    },\n\n    /**\n     * @param {string} key\n     * @param {boolean} [ignoreParent=false]\n     * @return {*}\n     */\n    getShallow: function (key, ignoreParent) {\n        var option = this.option;\n\n        var val = option == null ? option : option[key];\n        var parentModel = !ignoreParent && getParent(this, key);\n        if (val == null && parentModel) {\n            val = parentModel.getShallow(key);\n        }\n        return val;\n    },\n\n    /**\n     * @param {string|Array.<string>} [path]\n     * @param {module:echarts/model/Model} [parentModel]\n     * @return {module:echarts/model/Model}\n     */\n    getModel: function (path, parentModel) {\n        var obj = path == null\n            ? this.option\n            : doGet(this.option, path = this.parsePath(path));\n\n        var thisParentModel;\n        parentModel = parentModel || (\n            (thisParentModel = getParent(this, path))\n                && thisParentModel.getModel(path)\n        );\n\n        return new Model(obj, parentModel, this.ecModel);\n    },\n\n    /**\n     * If model has option\n     */\n    isEmpty: function () {\n        return this.option == null;\n    },\n\n    restoreData: function () {},\n\n    // Pending\n    clone: function () {\n        var Ctor = this.constructor;\n        return new Ctor(clone(this.option));\n    },\n\n    setReadOnly: function (properties) {\n        // clazzUtil.setReadOnly(this, properties);\n    },\n\n    // If path is null/undefined, return null/undefined.\n    parsePath: function (path) {\n        if (typeof path === 'string') {\n            path = path.split('.');\n        }\n        return path;\n    },\n\n    /**\n     * @param {Function} getParentMethod\n     *        param {Array.<string>|string} path\n     *        return {module:echarts/model/Model}\n     */\n    customizeGetParent: function (getParentMethod) {\n        inner(this).getParent = getParentMethod;\n    },\n\n    isAnimationEnabled: function () {\n        if (!env$1.node) {\n            if (this.option.animation != null) {\n                return !!this.option.animation;\n            }\n            else if (this.parentModel) {\n                return this.parentModel.isAnimationEnabled();\n            }\n        }\n    }\n\n};\n\nfunction doGet(obj, pathArr, parentModel) {\n    for (var i = 0; i < pathArr.length; i++) {\n        // Ignore empty\n        if (!pathArr[i]) {\n            continue;\n        }\n        // obj could be number/string/... (like 0)\n        obj = (obj && typeof obj === 'object') ? obj[pathArr[i]] : null;\n        if (obj == null) {\n            break;\n        }\n    }\n    if (obj == null && parentModel) {\n        obj = parentModel.get(pathArr);\n    }\n    return obj;\n}\n\n// `path` can be null/undefined\nfunction getParent(model, path) {\n    var getParentMethod = inner(model).getParent;\n    return getParentMethod ? getParentMethod.call(model, path) : model.parentModel;\n}\n\n// Enable Model.extend.\nenableClassExtend(Model);\nenableClassCheck(Model);\n\nmixin$1(Model, lineStyleMixin);\nmixin$1(Model, areaStyleMixin);\nmixin$1(Model, textStyleMixin);\nmixin$1(Model, itemStyleMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar base = 0;\n\n/**\n * @public\n * @param {string} type\n * @return {string}\n */\nfunction getUID(type) {\n    // Considering the case of crossing js context,\n    // use Math.random to make id as unique as possible.\n    return [(type || ''), base++, Math.random().toFixed(5)].join('_');\n}\n\n/**\n * @inner\n */\nfunction enableSubTypeDefaulter(entity) {\n\n    var subTypeDefaulters = {};\n\n    entity.registerSubTypeDefaulter = function (componentType, defaulter) {\n        componentType = parseClassType$1(componentType);\n        subTypeDefaulters[componentType.main] = defaulter;\n    };\n\n    entity.determineSubType = function (componentType, option) {\n        var type = option.type;\n        if (!type) {\n            var componentTypeMain = parseClassType$1(componentType).main;\n            if (entity.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) {\n                type = subTypeDefaulters[componentTypeMain](option);\n            }\n        }\n        return type;\n    };\n\n    return entity;\n}\n\n/**\n * Topological travel on Activity Network (Activity On Vertices).\n * Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis'].\n *\n * If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology.\n *\n * If there is circle dependencey, Error will be thrown.\n *\n */\nfunction enableTopologicalTravel(entity, dependencyGetter) {\n\n    /**\n     * @public\n     * @param {Array.<string>} targetNameList Target Component type list.\n     *                                           Can be ['aa', 'bb', 'aa.xx']\n     * @param {Array.<string>} fullNameList By which we can build dependency graph.\n     * @param {Function} callback Params: componentType, dependencies.\n     * @param {Object} context Scope of callback.\n     */\n    entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) {\n        if (!targetNameList.length) {\n            return;\n        }\n\n        var result = makeDepndencyGraph(fullNameList);\n        var graph = result.graph;\n        var stack = result.noEntryList;\n\n        var targetNameSet = {};\n        each$1(targetNameList, function (name) {\n            targetNameSet[name] = true;\n        });\n\n        while (stack.length) {\n            var currComponentType = stack.pop();\n            var currVertex = graph[currComponentType];\n            var isInTargetNameSet = !!targetNameSet[currComponentType];\n            if (isInTargetNameSet) {\n                callback.call(context, currComponentType, currVertex.originalDeps.slice());\n                delete targetNameSet[currComponentType];\n            }\n            each$1(\n                currVertex.successor,\n                isInTargetNameSet ? removeEdgeAndAdd : removeEdge\n            );\n        }\n\n        each$1(targetNameSet, function () {\n            throw new Error('Circle dependency may exists');\n        });\n\n        function removeEdge(succComponentType) {\n            graph[succComponentType].entryCount--;\n            if (graph[succComponentType].entryCount === 0) {\n                stack.push(succComponentType);\n            }\n        }\n\n        // Consider this case: legend depends on series, and we call\n        // chart.setOption({series: [...]}), where only series is in option.\n        // If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will\n        // not be called, but only sereis.mergeOption is called. Thus legend\n        // have no chance to update its local record about series (like which\n        // name of series is available in legend).\n        function removeEdgeAndAdd(succComponentType) {\n            targetNameSet[succComponentType] = true;\n            removeEdge(succComponentType);\n        }\n    };\n\n    /**\n     * DepndencyGraph: {Object}\n     * key: conponentType,\n     * value: {\n     *     successor: [conponentTypes...],\n     *     originalDeps: [conponentTypes...],\n     *     entryCount: {number}\n     * }\n     */\n    function makeDepndencyGraph(fullNameList) {\n        var graph = {};\n        var noEntryList = [];\n\n        each$1(fullNameList, function (name) {\n\n            var thisItem = createDependencyGraphItem(graph, name);\n            var originalDeps = thisItem.originalDeps = dependencyGetter(name);\n\n            var availableDeps = getAvailableDependencies(originalDeps, fullNameList);\n            thisItem.entryCount = availableDeps.length;\n            if (thisItem.entryCount === 0) {\n                noEntryList.push(name);\n            }\n\n            each$1(availableDeps, function (dependentName) {\n                if (indexOf(thisItem.predecessor, dependentName) < 0) {\n                    thisItem.predecessor.push(dependentName);\n                }\n                var thatItem = createDependencyGraphItem(graph, dependentName);\n                if (indexOf(thatItem.successor, dependentName) < 0) {\n                    thatItem.successor.push(name);\n                }\n            });\n        });\n\n        return {graph: graph, noEntryList: noEntryList};\n    }\n\n    function createDependencyGraphItem(graph, name) {\n        if (!graph[name]) {\n            graph[name] = {predecessor: [], successor: []};\n        }\n        return graph[name];\n    }\n\n    function getAvailableDependencies(originalDeps, fullNameList) {\n        var availableDeps = [];\n        each$1(originalDeps, function (dep) {\n            indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep);\n        });\n        return availableDeps;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The method \"quantile\" was copied from \"d3.js\".\n* (See more details in the comment of the method below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\nvar RADIAN_EPSILON = 1e-4;\n\nfunction _trim(str) {\n    return str.replace(/^\\s+/, '').replace(/\\s+$/, '');\n}\n\n/**\n * Linear mapping a value from domain to range\n * @memberOf module:echarts/util/number\n * @param  {(number|Array.<number>)} val\n * @param  {Array.<number>} domain Domain extent domain[0] can be bigger than domain[1]\n * @param  {Array.<number>} range  Range extent range[0] can be bigger than range[1]\n * @param  {boolean} clamp\n * @return {(number|Array.<number>}\n */\nfunction linearMap(val, domain, range, clamp) {\n    var subDomain = domain[1] - domain[0];\n    var subRange = range[1] - range[0];\n\n    if (subDomain === 0) {\n        return subRange === 0\n            ? range[0]\n            : (range[0] + range[1]) / 2;\n    }\n\n    // Avoid accuracy problem in edge, such as\n    // 146.39 - 62.83 === 83.55999999999999.\n    // See echarts/test/ut/spec/util/number.js#linearMap#accuracyError\n    // It is a little verbose for efficiency considering this method\n    // is a hotspot.\n    if (clamp) {\n        if (subDomain > 0) {\n            if (val <= domain[0]) {\n                return range[0];\n            }\n            else if (val >= domain[1]) {\n                return range[1];\n            }\n        }\n        else {\n            if (val >= domain[0]) {\n                return range[0];\n            }\n            else if (val <= domain[1]) {\n                return range[1];\n            }\n        }\n    }\n    else {\n        if (val === domain[0]) {\n            return range[0];\n        }\n        if (val === domain[1]) {\n            return range[1];\n        }\n    }\n\n    return (val - domain[0]) / subDomain * subRange + range[0];\n}\n\n/**\n * Convert a percent string to absolute number.\n * Returns NaN if percent is not a valid string or number\n * @memberOf module:echarts/util/number\n * @param {string|number} percent\n * @param {number} all\n * @return {number}\n */\nfunction parsePercent$1(percent, all) {\n    switch (percent) {\n        case 'center':\n        case 'middle':\n            percent = '50%';\n            break;\n        case 'left':\n        case 'top':\n            percent = '0%';\n            break;\n        case 'right':\n        case 'bottom':\n            percent = '100%';\n            break;\n    }\n    if (typeof percent === 'string') {\n        if (_trim(percent).match(/%$/)) {\n            return parseFloat(percent) / 100 * all;\n        }\n\n        return parseFloat(percent);\n    }\n\n    return percent == null ? NaN : +percent;\n}\n\n/**\n * (1) Fix rounding error of float numbers.\n * (2) Support return string to avoid scientific notation like '3.5e-7'.\n *\n * @param {number} x\n * @param {number} [precision]\n * @param {boolean} [returnStr]\n * @return {number|string}\n */\nfunction round$2(x, precision, returnStr) {\n    if (precision == null) {\n        precision = 10;\n    }\n    // Avoid range error\n    precision = Math.min(Math.max(0, precision), 20);\n    x = (+x).toFixed(precision);\n    return returnStr ? x : +x;\n}\n\n\n\n/**\n * Get precision\n * @param {number} val\n */\n\n\n/**\n * @param {string|number} val\n * @return {number}\n */\nfunction getPrecisionSafe(val) {\n    var str = val.toString();\n\n    // Consider scientific notation: '3.4e-12' '3.4e+12'\n    var eIndex = str.indexOf('e');\n    if (eIndex > 0) {\n        var precision = +str.slice(eIndex + 1);\n        return precision < 0 ? -precision : 0;\n    }\n    else {\n        var dotIndex = str.indexOf('.');\n        return dotIndex < 0 ? 0 : str.length - 1 - dotIndex;\n    }\n}\n\n/**\n * Minimal dicernible data precisioin according to a single pixel.\n *\n * @param {Array.<number>} dataExtent\n * @param {Array.<number>} pixelExtent\n * @return {number} precision\n */\nfunction getPixelPrecision(dataExtent, pixelExtent) {\n    var log = Math.log;\n    var LN10 = Math.LN10;\n    var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10);\n    var sizeQuantity = Math.round(log(Math.abs(pixelExtent[1] - pixelExtent[0])) / LN10);\n    // toFixed() digits argument must be between 0 and 20.\n    var precision = Math.min(Math.max(-dataQuantity + sizeQuantity, 0), 20);\n    return !isFinite(precision) ? 20 : precision;\n}\n\n/**\n * Get a data of given precision, assuring the sum of percentages\n * in valueList is 1.\n * The largest remainer method is used.\n * https://en.wikipedia.org/wiki/Largest_remainder_method\n *\n * @param {Array.<number>} valueList a list of all data\n * @param {number} idx index of the data to be processed in valueList\n * @param {number} precision integer number showing digits of precision\n * @return {number} percent ranging from 0 to 100\n */\nfunction getPercentWithPrecision(valueList, idx, precision) {\n    if (!valueList[idx]) {\n        return 0;\n    }\n\n    var sum = reduce(valueList, function (acc, val) {\n        return acc + (isNaN(val) ? 0 : val);\n    }, 0);\n    if (sum === 0) {\n        return 0;\n    }\n\n    var digits = Math.pow(10, precision);\n    var votesPerQuota = map(valueList, function (val) {\n        return (isNaN(val) ? 0 : val) / sum * digits * 100;\n    });\n    var targetSeats = digits * 100;\n\n    var seats = map(votesPerQuota, function (votes) {\n        // Assign automatic seats.\n        return Math.floor(votes);\n    });\n    var currentSum = reduce(seats, function (acc, val) {\n        return acc + val;\n    }, 0);\n\n    var remainder = map(votesPerQuota, function (votes, idx) {\n        return votes - seats[idx];\n    });\n\n    // Has remainding votes.\n    while (currentSum < targetSeats) {\n        // Find next largest remainder.\n        var max = Number.NEGATIVE_INFINITY;\n        var maxId = null;\n        for (var i = 0, len = remainder.length; i < len; ++i) {\n            if (remainder[i] > max) {\n                max = remainder[i];\n                maxId = i;\n            }\n        }\n\n        // Add a vote to max remainder.\n        ++seats[maxId];\n        remainder[maxId] = 0;\n        ++currentSum;\n    }\n\n    return seats[idx] / digits;\n}\n\n// Number.MAX_SAFE_INTEGER, ie do not support.\n\n\n/**\n * To 0 - 2 * PI, considering negative radian.\n * @param {number} radian\n * @return {number}\n */\nfunction remRadian(radian) {\n    var pi2 = Math.PI * 2;\n    return (radian % pi2 + pi2) % pi2;\n}\n\n/**\n * @param {type} radian\n * @return {boolean}\n */\nfunction isRadianAroundZero(val) {\n    return val > -RADIAN_EPSILON && val < RADIAN_EPSILON;\n}\n\n/* eslint-disable */\nvar TIME_REG = /^(?:(\\d{4})(?:[-\\/](\\d{1,2})(?:[-\\/](\\d{1,2})(?:[T ](\\d{1,2})(?::(\\d\\d)(?::(\\d\\d)(?:[.,](\\d+))?)?)?(Z|[\\+\\-]\\d\\d:?\\d\\d)?)?)?)?)?$/; // jshint ignore:line\n/* eslint-enable */\n\n/**\n * @param {string|Date|number} value These values can be accepted:\n *   + An instance of Date, represent a time in its own time zone.\n *   + Or string in a subset of ISO 8601, only including:\n *     + only year, month, date: '2012-03', '2012-03-01', '2012-03-01 05', '2012-03-01 05:06',\n *     + separated with T or space: '2012-03-01T12:22:33.123', '2012-03-01 12:22:33.123',\n *     + time zone: '2012-03-01T12:22:33Z', '2012-03-01T12:22:33+8000', '2012-03-01T12:22:33-05:00',\n *     all of which will be treated as local time if time zone is not specified\n *     (see <https://momentjs.com/>).\n *   + Or other string format, including (all of which will be treated as loacal time):\n *     '2012', '2012-3-1', '2012/3/1', '2012/03/01',\n *     '2009/6/12 2:00', '2009/6/12 2:05:08', '2009/6/12 2:05:08.123'\n *   + a timestamp, which represent a time in UTC.\n * @return {Date} date\n */\nfunction parseDate(value) {\n    if (value instanceof Date) {\n        return value;\n    }\n    else if (typeof value === 'string') {\n        // Different browsers parse date in different way, so we parse it manually.\n        // Some other issues:\n        // new Date('1970-01-01') is UTC,\n        // new Date('1970/01/01') and new Date('1970-1-01') is local.\n        // See issue #3623\n        var match = TIME_REG.exec(value);\n\n        if (!match) {\n            // return Invalid Date.\n            return new Date(NaN);\n        }\n\n        // Use local time when no timezone offset specifed.\n        if (!match[8]) {\n            // match[n] can only be string or undefined.\n            // But take care of '12' + 1 => '121'.\n            return new Date(\n                +match[1],\n                +(match[2] || 1) - 1,\n                +match[3] || 1,\n                +match[4] || 0,\n                +(match[5] || 0),\n                +match[6] || 0,\n                +match[7] || 0\n            );\n        }\n        // Timezoneoffset of Javascript Date has considered DST (Daylight Saving Time,\n        // https://tc39.github.io/ecma262/#sec-daylight-saving-time-adjustment).\n        // For example, system timezone is set as \"Time Zone: America/Toronto\",\n        // then these code will get different result:\n        // `new Date(1478411999999).getTimezoneOffset();  // get 240`\n        // `new Date(1478412000000).getTimezoneOffset();  // get 300`\n        // So we should not use `new Date`, but use `Date.UTC`.\n        else {\n            var hour = +match[4] || 0;\n            if (match[8].toUpperCase() !== 'Z') {\n                hour -= match[8].slice(0, 3);\n            }\n            return new Date(Date.UTC(\n                +match[1],\n                +(match[2] || 1) - 1,\n                +match[3] || 1,\n                hour,\n                +(match[5] || 0),\n                +match[6] || 0,\n                +match[7] || 0\n            ));\n        }\n    }\n    else if (value == null) {\n        return new Date(NaN);\n    }\n\n    return new Date(Math.round(value));\n}\n\n/**\n * Quantity of a number. e.g. 0.1, 1, 10, 100\n *\n * @param  {number} val\n * @return {number}\n */\nfunction quantity(val) {\n    return Math.pow(10, quantityExponent(val));\n}\n\nfunction quantityExponent(val) {\n    return Math.floor(Math.log(val) / Math.LN10);\n}\n\n/**\n * find a “nice” number approximately equal to x. Round the number if round = true,\n * take ceiling if round = false. The primary observation is that the “nicest”\n * numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers.\n *\n * See \"Nice Numbers for Graph Labels\" of Graphic Gems.\n *\n * @param  {number} val Non-negative value.\n * @param  {boolean} round\n * @return {number}\n */\nfunction nice(val, round) {\n    var exponent = quantityExponent(val);\n    var exp10 = Math.pow(10, exponent);\n    var f = val / exp10; // 1 <= f < 10\n    var nf;\n    if (round) {\n        if (f < 1.5) {\n            nf = 1;\n        }\n        else if (f < 2.5) {\n            nf = 2;\n        }\n        else if (f < 4) {\n            nf = 3;\n        }\n        else if (f < 7) {\n            nf = 5;\n        }\n        else {\n            nf = 10;\n        }\n    }\n    else {\n        if (f < 1) {\n            nf = 1;\n        }\n        else if (f < 2) {\n            nf = 2;\n        }\n        else if (f < 3) {\n            nf = 3;\n        }\n        else if (f < 5) {\n            nf = 5;\n        }\n        else {\n            nf = 10;\n        }\n    }\n    val = nf * exp10;\n\n    // Fix 3 * 0.1 === 0.30000000000000004 issue (see IEEE 754).\n    // 20 is the uppper bound of toFixed.\n    return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val;\n}\n\n/**\n * This code was copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/9cc9a875e636a1dcf36cc1e07bdf77e1ad6e2c74/src/arrays/quantile.js>.\n * See the license statement at the head of this file.\n * @param {Array.<number>} ascArr\n */\n\n\n/**\n * Order intervals asc, and split them when overlap.\n * expect(numberUtil.reformIntervals([\n *     {interval: [18, 62], close: [1, 1]},\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [1, 1]},\n *     {interval: [62, 150], close: [1, 1]},\n *     {interval: [106, 150], close: [1, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ])).toEqual([\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [0, 1]},\n *     {interval: [18, 62], close: [0, 1]},\n *     {interval: [62, 150], close: [0, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ]);\n * @param {Array.<Object>} list, where `close` mean open or close\n *        of the interval, and Infinity can be used.\n * @return {Array.<Object>} The origin list, which has been reformed.\n */\n\n\n/**\n * parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n * ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n * subtraction forces infinities to NaN\n *\n * @param {*} v\n * @return {boolean}\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import Text from 'zrender/src/graphic/Text';\n\n/**\n * 每三位默认加,格式化\n * @param {string|number} x\n * @return {string}\n */\nfunction addCommas(x) {\n    if (isNaN(x)) {\n        return '-';\n    }\n    x = (x + '').split('.');\n    return x[0].replace(/(\\d{1,3})(?=(?:\\d{3})+(?!\\d))/g, '$1,')\n            + (x.length > 1 ? ('.' + x[1]) : '');\n}\n\n/**\n * @param {string} str\n * @param {boolean} [upperCaseFirst=false]\n * @return {string} str\n */\n\n\nvar normalizeCssArray$1 = normalizeCssArray;\n\n\nvar replaceReg = /([&<>\"'])/g;\nvar replaceMap = {\n    '&': '&amp;',\n    '<': '&lt;',\n    '>': '&gt;',\n    '\"': '&quot;',\n    '\\'': '&#39;'\n};\n\nfunction encodeHTML(source) {\n    return source == null\n        ? ''\n        : (source + '').replace(replaceReg, function (str, c) {\n            return replaceMap[c];\n        });\n}\n\nvar TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];\n\nvar wrapVar = function (varName, seriesIdx) {\n    return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}';\n};\n\n/**\n * Template formatter\n * @param {string} tpl\n * @param {Array.<Object>|Object} paramsList\n * @param {boolean} [encode=false]\n * @return {string}\n */\nfunction formatTpl(tpl, paramsList, encode) {\n    if (!isArray(paramsList)) {\n        paramsList = [paramsList];\n    }\n    var seriesLen = paramsList.length;\n    if (!seriesLen) {\n        return '';\n    }\n\n    var $vars = paramsList[0].$vars || [];\n    for (var i = 0; i < $vars.length; i++) {\n        var alias = TPL_VAR_ALIAS[i];\n        tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0));\n    }\n    for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) {\n        for (var k = 0; k < $vars.length; k++) {\n            var val = paramsList[seriesIdx][$vars[k]];\n            tpl = tpl.replace(\n                wrapVar(TPL_VAR_ALIAS[k], seriesIdx),\n                encode ? encodeHTML(val) : val\n            );\n        }\n    }\n\n    return tpl;\n}\n\n/**\n * simple Template formatter\n *\n * @param {string} tpl\n * @param {Object} param\n * @param {boolean} [encode=false]\n * @return {string}\n */\n\n\n/**\n * @param {Object|string} [opt] If string, means color.\n * @param {string} [opt.color]\n * @param {string} [opt.extraCssText]\n * @param {string} [opt.type='item'] 'item' or 'subItem'\n * @param {string} [opt.renderMode='html'] render mode of tooltip, 'html' or 'richText'\n * @param {string} [opt.markerId='X'] id name for marker. If only one marker is in a rich text, this can be omitted.\n * @return {string}\n */\nfunction getTooltipMarker(opt, extraCssText) {\n    opt = isString(opt) ? {color: opt, extraCssText: extraCssText} : (opt || {});\n    var color = opt.color;\n    var type = opt.type;\n    var extraCssText = opt.extraCssText;\n    var renderMode = opt.renderMode || 'html';\n    var markerId = opt.markerId || 'X';\n\n    if (!color) {\n        return '';\n    }\n\n    if (renderMode === 'html') {\n        return type === 'subItem'\n        ? '<span style=\"display:inline-block;vertical-align:middle;margin-right:8px;margin-left:3px;'\n            + 'border-radius:4px;width:4px;height:4px;background-color:'\n            + encodeHTML(color) + ';' + (extraCssText || '') + '\"></span>'\n        : '<span style=\"display:inline-block;margin-right:5px;'\n            + 'border-radius:10px;width:10px;height:10px;background-color:'\n            + encodeHTML(color) + ';' + (extraCssText || '') + '\"></span>';\n    }\n    else {\n        // Space for rich element marker\n        return {\n            renderMode: renderMode,\n            content: '{marker' + markerId + '|}  ',\n            style: {\n                color: color\n            }\n        };\n    }\n}\n\nfunction pad(str, len) {\n    str += '';\n    return '0000'.substr(0, len - str.length) + str;\n}\n\n\n/**\n * ISO Date format\n * @param {string} tpl\n * @param {number} value\n * @param {boolean} [isUTC=false] Default in local time.\n *           see `module:echarts/scale/Time`\n *           and `module:echarts/util/number#parseDate`.\n * @inner\n */\nfunction formatTime(tpl, value, isUTC) {\n    if (tpl === 'week'\n        || tpl === 'month'\n        || tpl === 'quarter'\n        || tpl === 'half-year'\n        || tpl === 'year'\n    ) {\n        tpl = 'MM-dd\\nyyyy';\n    }\n\n    var date = parseDate(value);\n    var utc = isUTC ? 'UTC' : '';\n    var y = date['get' + utc + 'FullYear']();\n    var M = date['get' + utc + 'Month']() + 1;\n    var d = date['get' + utc + 'Date']();\n    var h = date['get' + utc + 'Hours']();\n    var m = date['get' + utc + 'Minutes']();\n    var s = date['get' + utc + 'Seconds']();\n    var S = date['get' + utc + 'Milliseconds']();\n\n    tpl = tpl.replace('MM', pad(M, 2))\n        .replace('M', M)\n        .replace('yyyy', y)\n        .replace('yy', y % 100)\n        .replace('dd', pad(d, 2))\n        .replace('d', d)\n        .replace('hh', pad(h, 2))\n        .replace('h', h)\n        .replace('mm', pad(m, 2))\n        .replace('m', m)\n        .replace('ss', pad(s, 2))\n        .replace('s', s)\n        .replace('SSS', pad(S, 3));\n\n    return tpl;\n}\n\n/**\n * Capital first\n * @param {string} str\n * @return {string}\n */\n\n\nvar truncateText$1 = truncateText;\n\n/**\n * @public\n * @param {Object} opt\n * @param {string} opt.text\n * @param {string} opt.font\n * @param {string} [opt.textAlign='left']\n * @param {string} [opt.textVerticalAlign='top']\n * @param {Array.<number>} [opt.textPadding]\n * @param {number} [opt.textLineHeight]\n * @param {Object} [opt.rich]\n * @param {Object} [opt.truncate]\n * @return {Object} {x, y, width, height, lineHeight}\n */\n\n\n/**\n * @deprecated\n * the `textLineHeight` was added later.\n * For backward compatiblility, put it as the last parameter.\n * But deprecated this interface. Please use `getTextBoundingRect` instead.\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Layout helpers for each component positioning\n\nvar each$3 = each$1;\n\n/**\n * @public\n */\nvar LOCATION_PARAMS = [\n    'left', 'right', 'top', 'bottom', 'width', 'height'\n];\n\n/**\n * @public\n */\nvar HV_NAMES = [\n    ['width', 'left', 'right'],\n    ['height', 'top', 'bottom']\n];\n\nfunction boxLayout(orient, group, gap, maxWidth, maxHeight) {\n    var x = 0;\n    var y = 0;\n\n    if (maxWidth == null) {\n        maxWidth = Infinity;\n    }\n    if (maxHeight == null) {\n        maxHeight = Infinity;\n    }\n    var currentLineMaxSize = 0;\n\n    group.eachChild(function (child, idx) {\n        var position = child.position;\n        var rect = child.getBoundingRect();\n        var nextChild = group.childAt(idx + 1);\n        var nextChildRect = nextChild && nextChild.getBoundingRect();\n        var nextX;\n        var nextY;\n\n        if (orient === 'horizontal') {\n            var moveX = rect.width + (nextChildRect ? (-nextChildRect.x + rect.x) : 0);\n            nextX = x + moveX;\n            // Wrap when width exceeds maxWidth or meet a `newline` group\n            // FIXME compare before adding gap?\n            if (nextX > maxWidth || child.newline) {\n                x = 0;\n                nextX = moveX;\n                y += currentLineMaxSize + gap;\n                currentLineMaxSize = rect.height;\n            }\n            else {\n                // FIXME: consider rect.y is not `0`?\n                currentLineMaxSize = Math.max(currentLineMaxSize, rect.height);\n            }\n        }\n        else {\n            var moveY = rect.height + (nextChildRect ? (-nextChildRect.y + rect.y) : 0);\n            nextY = y + moveY;\n            // Wrap when width exceeds maxHeight or meet a `newline` group\n            if (nextY > maxHeight || child.newline) {\n                x += currentLineMaxSize + gap;\n                y = 0;\n                nextY = moveY;\n                currentLineMaxSize = rect.width;\n            }\n            else {\n                currentLineMaxSize = Math.max(currentLineMaxSize, rect.width);\n            }\n        }\n\n        if (child.newline) {\n            return;\n        }\n\n        position[0] = x;\n        position[1] = y;\n\n        orient === 'horizontal'\n            ? (x = nextX + gap)\n            : (y = nextY + gap);\n    });\n}\n\n/**\n * VBox or HBox layouting\n * @param {string} orient\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\n\n\n/**\n * VBox layouting\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar vbox = curry(boxLayout, 'vertical');\n\n/**\n * HBox layouting\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar hbox = curry(boxLayout, 'horizontal');\n\n/**\n * If x or x2 is not specified or 'center' 'left' 'right',\n * the width would be as long as possible.\n * If y or y2 is not specified or 'middle' 'top' 'bottom',\n * the height would be as long as possible.\n *\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.x]\n * @param {number|string} [positionInfo.y]\n * @param {number|string} [positionInfo.x2]\n * @param {number|string} [positionInfo.y2]\n * @param {Object} containerRect {width, height}\n * @param {string|number} margin\n * @return {Object} {width, height}\n */\n\n\n/**\n * Parse position info.\n *\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.left]\n * @param {number|string} [positionInfo.top]\n * @param {number|string} [positionInfo.right]\n * @param {number|string} [positionInfo.bottom]\n * @param {number|string} [positionInfo.width]\n * @param {number|string} [positionInfo.height]\n * @param {number|string} [positionInfo.aspect] Aspect is width / height\n * @param {Object} containerRect\n * @param {string|number} [margin]\n *\n * @return {module:zrender/core/BoundingRect}\n */\nfunction getLayoutRect(\n    positionInfo, containerRect, margin\n) {\n    margin = normalizeCssArray$1(margin || 0);\n\n    var containerWidth = containerRect.width;\n    var containerHeight = containerRect.height;\n\n    var left = parsePercent$1(positionInfo.left, containerWidth);\n    var top = parsePercent$1(positionInfo.top, containerHeight);\n    var right = parsePercent$1(positionInfo.right, containerWidth);\n    var bottom = parsePercent$1(positionInfo.bottom, containerHeight);\n    var width = parsePercent$1(positionInfo.width, containerWidth);\n    var height = parsePercent$1(positionInfo.height, containerHeight);\n\n    var verticalMargin = margin[2] + margin[0];\n    var horizontalMargin = margin[1] + margin[3];\n    var aspect = positionInfo.aspect;\n\n    // If width is not specified, calculate width from left and right\n    if (isNaN(width)) {\n        width = containerWidth - right - horizontalMargin - left;\n    }\n    if (isNaN(height)) {\n        height = containerHeight - bottom - verticalMargin - top;\n    }\n\n    if (aspect != null) {\n        // If width and height are not given\n        // 1. Graph should not exceeds the container\n        // 2. Aspect must be keeped\n        // 3. Graph should take the space as more as possible\n        // FIXME\n        // Margin is not considered, because there is no case that both\n        // using margin and aspect so far.\n        if (isNaN(width) && isNaN(height)) {\n            if (aspect > containerWidth / containerHeight) {\n                width = containerWidth * 0.8;\n            }\n            else {\n                height = containerHeight * 0.8;\n            }\n        }\n\n        // Calculate width or height with given aspect\n        if (isNaN(width)) {\n            width = aspect * height;\n        }\n        if (isNaN(height)) {\n            height = width / aspect;\n        }\n    }\n\n    // If left is not specified, calculate left from right and width\n    if (isNaN(left)) {\n        left = containerWidth - right - width - horizontalMargin;\n    }\n    if (isNaN(top)) {\n        top = containerHeight - bottom - height - verticalMargin;\n    }\n\n    // Align left and top\n    switch (positionInfo.left || positionInfo.right) {\n        case 'center':\n            left = containerWidth / 2 - width / 2 - margin[3];\n            break;\n        case 'right':\n            left = containerWidth - width - horizontalMargin;\n            break;\n    }\n    switch (positionInfo.top || positionInfo.bottom) {\n        case 'middle':\n        case 'center':\n            top = containerHeight / 2 - height / 2 - margin[0];\n            break;\n        case 'bottom':\n            top = containerHeight - height - verticalMargin;\n            break;\n    }\n    // If something is wrong and left, top, width, height are calculated as NaN\n    left = left || 0;\n    top = top || 0;\n    if (isNaN(width)) {\n        // Width may be NaN if only one value is given except width\n        width = containerWidth - horizontalMargin - left - (right || 0);\n    }\n    if (isNaN(height)) {\n        // Height may be NaN if only one value is given except height\n        height = containerHeight - verticalMargin - top - (bottom || 0);\n    }\n\n    var rect = new BoundingRect(left + margin[3], top + margin[0], width, height);\n    rect.margin = margin;\n    return rect;\n}\n\n\n/**\n * Position a zr element in viewport\n *  Group position is specified by either\n *  {left, top}, {right, bottom}\n *  If all properties exists, right and bottom will be igonred.\n *\n * Logic:\n *     1. Scale (against origin point in parent coord)\n *     2. Rotate (against origin point in parent coord)\n *     3. Traslate (with el.position by this method)\n * So this method only fixes the last step 'Traslate', which does not affect\n * scaling and rotating.\n *\n * If be called repeatly with the same input el, the same result will be gotten.\n *\n * @param {module:zrender/Element} el Should have `getBoundingRect` method.\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.left]\n * @param {number|string} [positionInfo.top]\n * @param {number|string} [positionInfo.right]\n * @param {number|string} [positionInfo.bottom]\n * @param {number|string} [positionInfo.width] Only for opt.boundingModel: 'raw'\n * @param {number|string} [positionInfo.height] Only for opt.boundingModel: 'raw'\n * @param {Object} containerRect\n * @param {string|number} margin\n * @param {Object} [opt]\n * @param {Array.<number>} [opt.hv=[1,1]] Only horizontal or only vertical.\n * @param {Array.<number>} [opt.boundingMode='all']\n *        Specify how to calculate boundingRect when locating.\n *        'all': Position the boundingRect that is transformed and uioned\n *               both itself and its descendants.\n *               This mode simplies confine the elements in the bounding\n *               of their container (e.g., using 'right: 0').\n *        'raw': Position the boundingRect that is not transformed and only itself.\n *               This mode is useful when you want a element can overflow its\n *               container. (Consider a rotated circle needs to be located in a corner.)\n *               In this mode positionInfo.width/height can only be number.\n */\n\n\n/**\n * @param {Object} option Contains some of the properties in HV_NAMES.\n * @param {number} hvIdx 0: horizontal; 1: vertical.\n */\n\n\n/**\n * Consider Case:\n * When defulat option has {left: 0, width: 100}, and we set {right: 0}\n * through setOption or media query, using normal zrUtil.merge will cause\n * {right: 0} does not take effect.\n *\n * @example\n * ComponentModel.extend({\n *     init: function () {\n *         ...\n *         var inputPositionParams = layout.getLayoutParams(option);\n *         this.mergeOption(inputPositionParams);\n *     },\n *     mergeOption: function (newOption) {\n *         newOption && zrUtil.merge(thisOption, newOption, true);\n *         layout.mergeLayoutParam(thisOption, newOption);\n *     }\n * });\n *\n * @param {Object} targetOption\n * @param {Object} newOption\n * @param {Object|string} [opt]\n * @param {boolean|Array.<boolean>} [opt.ignoreSize=false] Used for the components\n *  that width (or height) should not be calculated by left and right (or top and bottom).\n */\nfunction mergeLayoutParam(targetOption, newOption, opt) {\n    !isObject$1(opt) && (opt = {});\n\n    var ignoreSize = opt.ignoreSize;\n    !isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]);\n\n    var hResult = merge$$1(HV_NAMES[0], 0);\n    var vResult = merge$$1(HV_NAMES[1], 1);\n\n    copy(HV_NAMES[0], targetOption, hResult);\n    copy(HV_NAMES[1], targetOption, vResult);\n\n    function merge$$1(names, hvIdx) {\n        var newParams = {};\n        var newValueCount = 0;\n        var merged = {};\n        var mergedValueCount = 0;\n        var enoughParamNumber = 2;\n\n        each$3(names, function (name) {\n            merged[name] = targetOption[name];\n        });\n        each$3(names, function (name) {\n            // Consider case: newOption.width is null, which is\n            // set by user for removing width setting.\n            hasProp(newOption, name) && (newParams[name] = merged[name] = newOption[name]);\n            hasValue(newParams, name) && newValueCount++;\n            hasValue(merged, name) && mergedValueCount++;\n        });\n\n        if (ignoreSize[hvIdx]) {\n            // Only one of left/right is premitted to exist.\n            if (hasValue(newOption, names[1])) {\n                merged[names[2]] = null;\n            }\n            else if (hasValue(newOption, names[2])) {\n                merged[names[1]] = null;\n            }\n            return merged;\n        }\n\n        // Case: newOption: {width: ..., right: ...},\n        // or targetOption: {right: ...} and newOption: {width: ...},\n        // There is no conflict when merged only has params count\n        // little than enoughParamNumber.\n        if (mergedValueCount === enoughParamNumber || !newValueCount) {\n            return merged;\n        }\n        // Case: newOption: {width: ..., right: ...},\n        // Than we can make sure user only want those two, and ignore\n        // all origin params in targetOption.\n        else if (newValueCount >= enoughParamNumber) {\n            return newParams;\n        }\n        else {\n            // Chose another param from targetOption by priority.\n            for (var i = 0; i < names.length; i++) {\n                var name = names[i];\n                if (!hasProp(newParams, name) && hasProp(targetOption, name)) {\n                    newParams[name] = targetOption[name];\n                    break;\n                }\n            }\n            return newParams;\n        }\n    }\n\n    function hasProp(obj, name) {\n        return obj.hasOwnProperty(name);\n    }\n\n    function hasValue(obj, name) {\n        return obj[name] != null && obj[name] !== 'auto';\n    }\n\n    function copy(names, target, source) {\n        each$3(names, function (name) {\n            target[name] = source[name];\n        });\n    }\n}\n\n/**\n * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.\n * @param {Object} source\n * @return {Object} Result contains those props.\n */\nfunction getLayoutParams(source) {\n    return copyLayoutParams({}, source);\n}\n\n/**\n * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.\n * @param {Object} source\n * @return {Object} Result contains those props.\n */\nfunction copyLayoutParams(target, source) {\n    source && target && each$3(LOCATION_PARAMS, function (name) {\n        source.hasOwnProperty(name) && (target[name] = source[name]);\n    });\n    return target;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar boxLayoutMixin = {\n    getBoxLayoutParams: function () {\n        return {\n            left: this.get('left'),\n            top: this.get('top'),\n            right: this.get('right'),\n            bottom: this.get('bottom'),\n            width: this.get('width'),\n            height: this.get('height')\n        };\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Component model\n *\n * @module echarts/model/Component\n */\n\nvar inner$1 = makeInner();\n\n/**\n * @alias module:echarts/model/Component\n * @constructor\n * @param {Object} option\n * @param {module:echarts/model/Model} parentModel\n * @param {module:echarts/model/Model} ecModel\n */\nvar ComponentModel = Model.extend({\n\n    type: 'component',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    id: '',\n\n    /**\n     * Because simplified concept is probably better, series.name (or component.name)\n     * has been having too many resposibilities:\n     * (1) Generating id (which requires name in option should not be modified).\n     * (2) As an index to mapping series when merging option or calling API (a name\n     * can refer to more then one components, which is convinient is some case).\n     * (3) Display.\n     * @readOnly\n     */\n    name: '',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    mainType: '',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    subType: '',\n\n    /**\n     * @readOnly\n     * @type {number}\n     */\n    componentIndex: 0,\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    defaultOption: null,\n\n    /**\n     * @type {module:echarts/model/Global}\n     * @readOnly\n     */\n    ecModel: null,\n\n    /**\n     * key: componentType\n     * value:  Component model list, can not be null.\n     * @type {Object.<string, Array.<module:echarts/model/Model>>}\n     * @readOnly\n     */\n    dependentModels: [],\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    uid: null,\n\n    /**\n     * Support merge layout params.\n     * Only support 'box' now (left/right/top/bottom/width/height).\n     * @type {string|Object} Object can be {ignoreSize: true}\n     * @readOnly\n     */\n    layoutMode: null,\n\n    $constructor: function (option, parentModel, ecModel, extraOpt) {\n        Model.call(this, option, parentModel, ecModel, extraOpt);\n\n        this.uid = getUID('ec_cpt_model');\n    },\n\n    init: function (option, parentModel, ecModel, extraOpt) {\n        this.mergeDefaultAndTheme(option, ecModel);\n    },\n\n    mergeDefaultAndTheme: function (option, ecModel) {\n        var layoutMode = this.layoutMode;\n        var inputPositionParams = layoutMode\n            ? getLayoutParams(option) : {};\n\n        var themeModel = ecModel.getTheme();\n        merge(option, themeModel.get(this.mainType));\n        merge(option, this.getDefaultOption());\n\n        if (layoutMode) {\n            mergeLayoutParam(option, inputPositionParams, layoutMode);\n        }\n    },\n\n    mergeOption: function (option, extraOpt) {\n        merge(this.option, option, true);\n\n        var layoutMode = this.layoutMode;\n        if (layoutMode) {\n            mergeLayoutParam(this.option, option, layoutMode);\n        }\n    },\n\n    // Hooker after init or mergeOption\n    optionUpdated: function (newCptOption, isInit) {},\n\n    getDefaultOption: function () {\n        var fields = inner$1(this);\n        if (!fields.defaultOption) {\n            var optList = [];\n            var Class = this.constructor;\n            while (Class) {\n                var opt = Class.prototype.defaultOption;\n                opt && optList.push(opt);\n                Class = Class.superClass;\n            }\n\n            var defaultOption = {};\n            for (var i = optList.length - 1; i >= 0; i--) {\n                defaultOption = merge(defaultOption, optList[i], true);\n            }\n            fields.defaultOption = defaultOption;\n        }\n        return fields.defaultOption;\n    },\n\n    getReferringComponents: function (mainType) {\n        return this.ecModel.queryComponents({\n            mainType: mainType,\n            index: this.get(mainType + 'Index', true),\n            id: this.get(mainType + 'Id', true)\n        });\n    }\n\n});\n\n// Reset ComponentModel.extend, add preConstruct.\n// clazzUtil.enableClassExtend(\n//     ComponentModel,\n//     function (option, parentModel, ecModel, extraOpt) {\n//         // Set dependentModels, componentIndex, name, id, mainType, subType.\n//         zrUtil.extend(this, extraOpt);\n\n//         this.uid = componentUtil.getUID('componentModel');\n\n//         // this.setReadOnly([\n//         //     'type', 'id', 'uid', 'name', 'mainType', 'subType',\n//         //     'dependentModels', 'componentIndex'\n//         // ]);\n//     }\n// );\n\n// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(\n    ComponentModel, {registerWhenExtend: true}\n);\nenableSubTypeDefaulter(ComponentModel);\n\n// Add capability of ComponentModel.topologicalTravel.\nenableTopologicalTravel(ComponentModel, getDependencies);\n\nfunction getDependencies(componentType) {\n    var deps = [];\n    each$1(ComponentModel.getClassesByMainType(componentType), function (Clazz) {\n        deps = deps.concat(Clazz.prototype.dependencies || []);\n    });\n\n    // Ensure main type.\n    deps = map(deps, function (type) {\n        return parseClassType$1(type).main;\n    });\n\n    // Hack dataset for convenience.\n    if (componentType !== 'dataset' && indexOf(deps, 'dataset') <= 0) {\n        deps.unshift('dataset');\n    }\n\n    return deps;\n}\n\nmixin(ComponentModel, boxLayoutMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar platform = '';\n// Navigator not exists in node\nif (typeof navigator !== 'undefined') {\n    platform = navigator.platform || '';\n}\n\nvar globalDefault = {\n    // backgroundColor: 'rgba(0,0,0,0)',\n\n    // https://dribbble.com/shots/1065960-Infographic-Pie-chart-visualization\n    // color: ['#5793f3', '#d14a61', '#fd9c35', '#675bba', '#fec42c', '#dd4444', '#d4df5a', '#cd4870'],\n    // Light colors:\n    // color: ['#bcd3bb', '#e88f70', '#edc1a5', '#9dc5c8', '#e1e8c8', '#7b7c68', '#e5b5b5', '#f0b489', '#928ea8', '#bda29a'],\n    // color: ['#cc5664', '#9bd6ec', '#ea946e', '#8acaaa', '#f1ec64', '#ee8686', '#a48dc1', '#5da6bc', '#b9dcae'],\n    // Dark colors:\n    color: [\n        '#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83',\n        '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'\n    ],\n\n    gradientColor: ['#f6efa6', '#d88273', '#bf444c'],\n\n    // If xAxis and yAxis declared, grid is created by default.\n    // grid: {},\n\n    textStyle: {\n        // color: '#000',\n        // decoration: 'none',\n        // PENDING\n        fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif',\n        // fontFamily: 'Arial, Verdana, sans-serif',\n        fontSize: 12,\n        fontStyle: 'normal',\n        fontWeight: 'normal'\n    },\n\n    // http://blogs.adobe.com/webplatform/2014/02/24/using-blend-modes-in-html-canvas/\n    // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation\n    // Default is source-over\n    blendMode: null,\n\n    animation: 'auto',\n    animationDuration: 1000,\n    animationDurationUpdate: 300,\n    animationEasing: 'exponentialOut',\n    animationEasingUpdate: 'cubicOut',\n\n    animationThreshold: 2000,\n    // Configuration for progressive/incremental rendering\n    progressiveThreshold: 3000,\n    progressive: 400,\n\n    // Threshold of if use single hover layer to optimize.\n    // It is recommended that `hoverLayerThreshold` is equivalent to or less than\n    // `progressiveThreshold`, otherwise hover will cause restart of progressive,\n    // which is unexpected.\n    // see example <echarts/test/heatmap-large.html>.\n    hoverLayerThreshold: 3000,\n\n    // See: module:echarts/scale/Time\n    useUTC: false\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$2 = makeInner();\n\nfunction getNearestColorPalette(colors, requestColorNum) {\n    var paletteNum = colors.length;\n    // TODO colors must be in order\n    for (var i = 0; i < paletteNum; i++) {\n        if (colors[i].length > requestColorNum) {\n            return colors[i];\n        }\n    }\n    return colors[paletteNum - 1];\n}\n\nvar colorPaletteMixin = {\n    clearColorPalette: function () {\n        inner$2(this).colorIdx = 0;\n        inner$2(this).colorNameMap = {};\n    },\n\n    /**\n     * @param {string} name MUST NOT be null/undefined. Otherwise call this function\n     *                 twise with the same parameters will get different result.\n     * @param {Object} [scope=this]\n     * @param {Object} [requestColorNum]\n     * @return {string} color string.\n     */\n    getColorFromPalette: function (name, scope, requestColorNum) {\n        scope = scope || this;\n        var scopeFields = inner$2(scope);\n        var colorIdx = scopeFields.colorIdx || 0;\n        var colorNameMap = scopeFields.colorNameMap = scopeFields.colorNameMap || {};\n        // Use `hasOwnProperty` to avoid conflict with Object.prototype.\n        if (colorNameMap.hasOwnProperty(name)) {\n            return colorNameMap[name];\n        }\n        var defaultColorPalette = normalizeToArray(this.get('color', true));\n        var layeredColorPalette = this.get('colorLayer', true);\n        var colorPalette = ((requestColorNum == null || !layeredColorPalette)\n            ? defaultColorPalette : getNearestColorPalette(layeredColorPalette, requestColorNum));\n\n        // In case can't find in layered color palette.\n        colorPalette = colorPalette || defaultColorPalette;\n\n        if (!colorPalette || !colorPalette.length) {\n            return;\n        }\n\n        var color = colorPalette[colorIdx];\n        if (name) {\n            colorNameMap[name] = color;\n        }\n        scopeFields.colorIdx = (colorIdx + 1) % colorPalette.length;\n\n        return color;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Helper for model references.\n * There are many manners to refer axis/coordSys.\n */\n\n// TODO\n// merge relevant logic to this file?\n// check: \"modelHelper\" of tooltip and \"BrushTargetManager\".\n\n/**\n * @return {Object} For example:\n * {\n *     coordSysName: 'cartesian2d',\n *     coordSysDims: ['x', 'y', ...],\n *     axisMap: HashMap({\n *         x: xAxisModel,\n *         y: yAxisModel\n *     }),\n *     categoryAxisMap: HashMap({\n *         x: xAxisModel,\n *         y: undefined\n *     }),\n *     // It also indicate that whether there is category axis.\n *     firstCategoryDimIndex: 1,\n *     // To replace user specified encode.\n * }\n */\nfunction getCoordSysDefineBySeries(seriesModel) {\n    var coordSysName = seriesModel.get('coordinateSystem');\n    var result = {\n        coordSysName: coordSysName,\n        coordSysDims: [],\n        axisMap: createHashMap(),\n        categoryAxisMap: createHashMap()\n    };\n    var fetch = fetchers[coordSysName];\n    if (fetch) {\n        fetch(seriesModel, result, result.axisMap, result.categoryAxisMap);\n        return result;\n    }\n}\n\nvar fetchers = {\n\n    cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var xAxisModel = seriesModel.getReferringComponents('xAxis')[0];\n        var yAxisModel = seriesModel.getReferringComponents('yAxis')[0];\n\n        if (__DEV__) {\n            if (!xAxisModel) {\n                throw new Error('xAxis \"' + retrieve(\n                    seriesModel.get('xAxisIndex'),\n                    seriesModel.get('xAxisId'),\n                    0\n                ) + '\" not found');\n            }\n            if (!yAxisModel) {\n                throw new Error('yAxis \"' + retrieve(\n                    seriesModel.get('xAxisIndex'),\n                    seriesModel.get('yAxisId'),\n                    0\n                ) + '\" not found');\n            }\n        }\n\n        result.coordSysDims = ['x', 'y'];\n        axisMap.set('x', xAxisModel);\n        axisMap.set('y', yAxisModel);\n\n        if (isCategory(xAxisModel)) {\n            categoryAxisMap.set('x', xAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n        if (isCategory(yAxisModel)) {\n            categoryAxisMap.set('y', yAxisModel);\n            result.firstCategoryDimIndex = 1;\n        }\n    },\n\n    singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var singleAxisModel = seriesModel.getReferringComponents('singleAxis')[0];\n\n        if (__DEV__) {\n            if (!singleAxisModel) {\n                throw new Error('singleAxis should be specified.');\n            }\n        }\n\n        result.coordSysDims = ['single'];\n        axisMap.set('single', singleAxisModel);\n\n        if (isCategory(singleAxisModel)) {\n            categoryAxisMap.set('single', singleAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n    },\n\n    polar: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var polarModel = seriesModel.getReferringComponents('polar')[0];\n        var radiusAxisModel = polarModel.findAxisModel('radiusAxis');\n        var angleAxisModel = polarModel.findAxisModel('angleAxis');\n\n        if (__DEV__) {\n            if (!angleAxisModel) {\n                throw new Error('angleAxis option not found');\n            }\n            if (!radiusAxisModel) {\n                throw new Error('radiusAxis option not found');\n            }\n        }\n\n        result.coordSysDims = ['radius', 'angle'];\n        axisMap.set('radius', radiusAxisModel);\n        axisMap.set('angle', angleAxisModel);\n\n        if (isCategory(radiusAxisModel)) {\n            categoryAxisMap.set('radius', radiusAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n        if (isCategory(angleAxisModel)) {\n            categoryAxisMap.set('angle', angleAxisModel);\n            result.firstCategoryDimIndex = 1;\n        }\n    },\n\n    geo: function (seriesModel, result, axisMap, categoryAxisMap) {\n        result.coordSysDims = ['lng', 'lat'];\n    },\n\n    parallel: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var ecModel = seriesModel.ecModel;\n        var parallelModel = ecModel.getComponent(\n            'parallel', seriesModel.get('parallelIndex')\n        );\n        var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice();\n\n        each$1(parallelModel.parallelAxisIndex, function (axisIndex, index) {\n            var axisModel = ecModel.getComponent('parallelAxis', axisIndex);\n            var axisDim = coordSysDims[index];\n            axisMap.set(axisDim, axisModel);\n\n            if (isCategory(axisModel) && result.firstCategoryDimIndex == null) {\n                categoryAxisMap.set(axisDim, axisModel);\n                result.firstCategoryDimIndex = index;\n            }\n        });\n    }\n};\n\nfunction isCategory(axisModel) {\n    return axisModel.get('type') === 'category';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Avoid typo.\nvar SOURCE_FORMAT_ORIGINAL = 'original';\nvar SOURCE_FORMAT_ARRAY_ROWS = 'arrayRows';\nvar SOURCE_FORMAT_OBJECT_ROWS = 'objectRows';\nvar SOURCE_FORMAT_KEYED_COLUMNS = 'keyedColumns';\nvar SOURCE_FORMAT_UNKNOWN = 'unknown';\n// ??? CHANGE A NAME\nvar SOURCE_FORMAT_TYPED_ARRAY = 'typedArray';\n\nvar SERIES_LAYOUT_BY_COLUMN = 'column';\nvar SERIES_LAYOUT_BY_ROW = 'row';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * [sourceFormat]\n *\n * + \"original\":\n * This format is only used in series.data, where\n * itemStyle can be specified in data item.\n *\n * + \"arrayRows\":\n * [\n *     ['product', 'score', 'amount'],\n *     ['Matcha Latte', 89.3, 95.8],\n *     ['Milk Tea', 92.1, 89.4],\n *     ['Cheese Cocoa', 94.4, 91.2],\n *     ['Walnut Brownie', 85.4, 76.9]\n * ]\n *\n * + \"objectRows\":\n * [\n *     {product: 'Matcha Latte', score: 89.3, amount: 95.8},\n *     {product: 'Milk Tea', score: 92.1, amount: 89.4},\n *     {product: 'Cheese Cocoa', score: 94.4, amount: 91.2},\n *     {product: 'Walnut Brownie', score: 85.4, amount: 76.9}\n * ]\n *\n * + \"keyedColumns\":\n * {\n *     'product': ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie'],\n *     'count': [823, 235, 1042, 988],\n *     'score': [95.8, 81.4, 91.2, 76.9]\n * }\n *\n * + \"typedArray\"\n *\n * + \"unknown\"\n */\n\n/**\n * @constructor\n * @param {Object} fields\n * @param {string} fields.sourceFormat\n * @param {Array|Object} fields.fromDataset\n * @param {Array|Object} [fields.data]\n * @param {string} [seriesLayoutBy='column']\n * @param {Array.<Object|string>} [dimensionsDefine]\n * @param {Objet|HashMap} [encodeDefine]\n * @param {number} [startIndex=0]\n * @param {number} [dimensionsDetectCount]\n */\nfunction Source(fields) {\n\n    /**\n     * @type {boolean}\n     */\n    this.fromDataset = fields.fromDataset;\n\n    /**\n     * Not null/undefined.\n     * @type {Array|Object}\n     */\n    this.data = fields.data || (\n        fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []\n    );\n\n    /**\n     * See also \"detectSourceFormat\".\n     * Not null/undefined.\n     * @type {string}\n     */\n    this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN;\n\n    /**\n     * 'row' or 'column'\n     * Not null/undefined.\n     * @type {string} seriesLayoutBy\n     */\n    this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN;\n\n    /**\n     * dimensions definition in option.\n     * can be null/undefined.\n     * @type {Array.<Object|string>}\n     */\n    this.dimensionsDefine = fields.dimensionsDefine;\n\n    /**\n     * encode definition in option.\n     * can be null/undefined.\n     * @type {Objet|HashMap}\n     */\n    this.encodeDefine = fields.encodeDefine && createHashMap(fields.encodeDefine);\n\n    /**\n     * Not null/undefined, uint.\n     * @type {number}\n     */\n    this.startIndex = fields.startIndex || 0;\n\n    /**\n     * Can be null/undefined (when unknown), uint.\n     * @type {number}\n     */\n    this.dimensionsDetectCount = fields.dimensionsDetectCount;\n}\n\n/**\n * Wrap original series data for some compatibility cases.\n */\nSource.seriesDataToSource = function (data) {\n    return new Source({\n        data: data,\n        sourceFormat: isTypedArray(data)\n            ? SOURCE_FORMAT_TYPED_ARRAY\n            : SOURCE_FORMAT_ORIGINAL,\n        fromDataset: false\n    });\n};\n\nenableClassCheck(Source);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$3 = makeInner();\n\n/**\n * @see {module:echarts/data/Source}\n * @param {module:echarts/component/dataset/DatasetModel} datasetModel\n * @return {string} sourceFormat\n */\nfunction detectSourceFormat(datasetModel) {\n    var data = datasetModel.option.source;\n    var sourceFormat = SOURCE_FORMAT_UNKNOWN;\n\n    if (isTypedArray(data)) {\n        sourceFormat = SOURCE_FORMAT_TYPED_ARRAY;\n    }\n    else if (isArray(data)) {\n        // FIXME Whether tolerate null in top level array?\n        if (data.length === 0) {\n            sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;\n        }\n\n        for (var i = 0, len = data.length; i < len; i++) {\n            var item = data[i];\n\n            if (item == null) {\n                continue;\n            }\n            else if (isArray(item)) {\n                sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;\n                break;\n            }\n            else if (isObject$1(item)) {\n                sourceFormat = SOURCE_FORMAT_OBJECT_ROWS;\n                break;\n            }\n        }\n    }\n    else if (isObject$1(data)) {\n        for (var key in data) {\n            if (data.hasOwnProperty(key) && isArrayLike(data[key])) {\n                sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS;\n                break;\n            }\n        }\n    }\n    else if (data != null) {\n        throw new Error('Invalid data');\n    }\n\n    inner$3(datasetModel).sourceFormat = sourceFormat;\n}\n\n/**\n * [Scenarios]:\n * (1) Provide source data directly:\n *     series: {\n *         encode: {...},\n *         dimensions: [...]\n *         seriesLayoutBy: 'row',\n *         data: [[...]]\n *     }\n * (2) Refer to datasetModel.\n *     series: [{\n *         encode: {...}\n *         // Ignore datasetIndex means `datasetIndex: 0`\n *         // and the dimensions defination in dataset is used\n *     }, {\n *         encode: {...},\n *         seriesLayoutBy: 'column',\n *         datasetIndex: 1\n *     }]\n *\n * Get data from series itself or datset.\n * @return {module:echarts/data/Source} source\n */\nfunction getSource(seriesModel) {\n    return inner$3(seriesModel).source;\n}\n\n/**\n * MUST be called before mergeOption of all series.\n * @param {module:echarts/model/Global} ecModel\n */\nfunction resetSourceDefaulter(ecModel) {\n    // `datasetMap` is used to make default encode.\n    inner$3(ecModel).datasetMap = createHashMap();\n}\n\n/**\n * [Caution]:\n * MUST be called after series option merged and\n * before \"series.getInitailData()\" called.\n *\n * [The rule of making default encode]:\n * Category axis (if exists) alway map to the first dimension.\n * Each other axis occupies a subsequent dimension.\n *\n * [Why make default encode]:\n * Simplify the typing of encode in option, avoiding the case like that:\n * series: [{encode: {x: 0, y: 1}}, {encode: {x: 0, y: 2}}, {encode: {x: 0, y: 3}}],\n * where the \"y\" have to be manually typed as \"1, 2, 3, ...\".\n *\n * @param {module:echarts/model/Series} seriesModel\n */\nfunction prepareSource(seriesModel) {\n    var seriesOption = seriesModel.option;\n\n    var data = seriesOption.data;\n    var sourceFormat = isTypedArray(data)\n        ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL;\n    var fromDataset = false;\n\n    var seriesLayoutBy = seriesOption.seriesLayoutBy;\n    var sourceHeader = seriesOption.sourceHeader;\n    var dimensionsDefine = seriesOption.dimensions;\n\n    var datasetModel = getDatasetModel(seriesModel);\n    if (datasetModel) {\n        var datasetOption = datasetModel.option;\n\n        data = datasetOption.source;\n        sourceFormat = inner$3(datasetModel).sourceFormat;\n        fromDataset = true;\n\n        // These settings from series has higher priority.\n        seriesLayoutBy = seriesLayoutBy || datasetOption.seriesLayoutBy;\n        sourceHeader == null && (sourceHeader = datasetOption.sourceHeader);\n        dimensionsDefine = dimensionsDefine || datasetOption.dimensions;\n    }\n\n    var completeResult = completeBySourceData(\n        data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine\n    );\n\n    // Note: dataset option does not have `encode`.\n    var encodeDefine = seriesOption.encode;\n    if (!encodeDefine && datasetModel) {\n        encodeDefine = makeDefaultEncode(\n            seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult\n        );\n    }\n\n    inner$3(seriesModel).source = new Source({\n        data: data,\n        fromDataset: fromDataset,\n        seriesLayoutBy: seriesLayoutBy,\n        sourceFormat: sourceFormat,\n        dimensionsDefine: completeResult.dimensionsDefine,\n        startIndex: completeResult.startIndex,\n        dimensionsDetectCount: completeResult.dimensionsDetectCount,\n        encodeDefine: encodeDefine\n    });\n}\n\n// return {startIndex, dimensionsDefine, dimensionsCount}\nfunction completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine) {\n    if (!data) {\n        return {dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine)};\n    }\n\n    var dimensionsDetectCount;\n    var startIndex;\n    var findPotentialName;\n\n    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {\n        // Rule: Most of the first line are string: it is header.\n        // Caution: consider a line with 5 string and 1 number,\n        // it still can not be sure it is a head, because the\n        // 5 string may be 5 values of category columns.\n        if (sourceHeader === 'auto' || sourceHeader == null) {\n            arrayRowsTravelFirst(function (val) {\n                // '-' is regarded as null/undefined.\n                if (val != null && val !== '-') {\n                    if (isString(val)) {\n                        startIndex == null && (startIndex = 1);\n                    }\n                    else {\n                        startIndex = 0;\n                    }\n                }\n            // 10 is an experience number, avoid long loop.\n            }, seriesLayoutBy, data, 10);\n        }\n        else {\n            startIndex = sourceHeader ? 1 : 0;\n        }\n\n        if (!dimensionsDefine && startIndex === 1) {\n            dimensionsDefine = [];\n            arrayRowsTravelFirst(function (val, index) {\n                dimensionsDefine[index] = val != null ? val : '';\n            }, seriesLayoutBy, data);\n        }\n\n        dimensionsDetectCount = dimensionsDefine\n            ? dimensionsDefine.length\n            : seriesLayoutBy === SERIES_LAYOUT_BY_ROW\n            ? data.length\n            : data[0]\n            ? data[0].length\n            : null;\n    }\n    else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {\n        if (!dimensionsDefine) {\n            dimensionsDefine = objectRowsCollectDimensions(data);\n            findPotentialName = true;\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {\n        if (!dimensionsDefine) {\n            dimensionsDefine = [];\n            findPotentialName = true;\n            each$1(data, function (colArr, key) {\n                dimensionsDefine.push(key);\n            });\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        var value0 = getDataItemValue(data[0]);\n        dimensionsDetectCount = isArray(value0) && value0.length || 1;\n    }\n    else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {\n        if (__DEV__) {\n            assert$1(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.');\n        }\n    }\n\n    var potentialNameDimIndex;\n    if (findPotentialName) {\n        each$1(dimensionsDefine, function (dim, idx) {\n            if ((isObject$1(dim) ? dim.name : dim) === 'name') {\n                potentialNameDimIndex = idx;\n            }\n        });\n    }\n\n    return {\n        startIndex: startIndex,\n        dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine),\n        dimensionsDetectCount: dimensionsDetectCount,\n        potentialNameDimIndex: potentialNameDimIndex\n        // TODO: potentialIdDimIdx\n    };\n}\n\n// Consider dimensions defined like ['A', 'price', 'B', 'price', 'C', 'price'],\n// which is reasonable. But dimension name is duplicated.\n// Returns undefined or an array contains only object without null/undefiend or string.\nfunction normalizeDimensionsDefine(dimensionsDefine) {\n    if (!dimensionsDefine) {\n        // The meaning of null/undefined is different from empty array.\n        return;\n    }\n    var nameMap = createHashMap();\n    return map(dimensionsDefine, function (item, index) {\n        item = extend({}, isObject$1(item) ? item : {name: item});\n\n        // User can set null in dimensions.\n        // We dont auto specify name, othewise a given name may\n        // cause it be refered unexpectedly.\n        if (item.name == null) {\n            return item;\n        }\n\n        // Also consider number form like 2012.\n        item.name += '';\n        // User may also specify displayName.\n        // displayName will always exists except user not\n        // specified or dim name is not specified or detected.\n        // (A auto generated dim name will not be used as\n        // displayName).\n        if (item.displayName == null) {\n            item.displayName = item.name;\n        }\n\n        var exist = nameMap.get(item.name);\n        if (!exist) {\n            nameMap.set(item.name, {count: 1});\n        }\n        else {\n            item.name += '-' + exist.count++;\n        }\n\n        return item;\n    });\n}\n\nfunction arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) {\n    maxLoop == null && (maxLoop = Infinity);\n    if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            cb(data[i] ? data[i][0] : null, i);\n        }\n    }\n    else {\n        var value0 = data[0] || [];\n        for (var i = 0; i < value0.length && i < maxLoop; i++) {\n            cb(value0[i], i);\n        }\n    }\n}\n\nfunction objectRowsCollectDimensions(data) {\n    var firstIndex = 0;\n    var obj;\n    while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line\n    if (obj) {\n        var dimensions = [];\n        each$1(obj, function (value, key) {\n            dimensions.push(key);\n        });\n        return dimensions;\n    }\n}\n\n// ??? TODO merge to completedimensions, where also has\n// default encode making logic. And the default rule\n// should depends on series? consider 'map'.\nfunction makeDefaultEncode(\n    seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult\n) {\n    var coordSysDefine = getCoordSysDefineBySeries(seriesModel);\n    var encode = {};\n    // var encodeTooltip = [];\n    // var encodeLabel = [];\n    var encodeItemName = [];\n    var encodeSeriesName = [];\n    var seriesType = seriesModel.subType;\n\n    // ??? TODO refactor: provide by series itself.\n    // Consider the case: 'map' series is based on geo coordSys,\n    // 'graph', 'heatmap' can be based on cartesian. But can not\n    // give default rule simply here.\n    var nSeriesMap = createHashMap(['pie', 'map', 'funnel']);\n    var cSeriesMap = createHashMap([\n        'line', 'bar', 'pictorialBar', 'scatter', 'effectScatter', 'candlestick', 'boxplot'\n    ]);\n\n    // Usually in this case series will use the first data\n    // dimension as the \"value\" dimension, or other default\n    // processes respectively.\n    if (coordSysDefine && cSeriesMap.get(seriesType) != null) {\n        var ecModel = seriesModel.ecModel;\n        var datasetMap = inner$3(ecModel).datasetMap;\n        var key = datasetModel.uid + '_' + seriesLayoutBy;\n        var datasetRecord = datasetMap.get(key)\n            || datasetMap.set(key, {categoryWayDim: 1, valueWayDim: 0});\n\n        // TODO\n        // Auto detect first time axis and do arrangement.\n        each$1(coordSysDefine.coordSysDims, function (coordDim) {\n            // In value way.\n            if (coordSysDefine.firstCategoryDimIndex == null) {\n                var dataDim = datasetRecord.valueWayDim++;\n                encode[coordDim] = dataDim;\n\n                // ??? TODO give a better default series name rule?\n                // especially when encode x y specified.\n                // consider: when mutiple series share one dimension\n                // category axis, series name should better use\n                // the other dimsion name. On the other hand, use\n                // both dimensions name.\n\n                encodeSeriesName.push(dataDim);\n                // encodeTooltip.push(dataDim);\n                // encodeLabel.push(dataDim);\n            }\n            // In category way, category axis.\n            else if (coordSysDefine.categoryAxisMap.get(coordDim)) {\n                encode[coordDim] = 0;\n                encodeItemName.push(0);\n            }\n            // In category way, non-category axis.\n            else {\n                var dataDim = datasetRecord.categoryWayDim++;\n                encode[coordDim] = dataDim;\n                // encodeTooltip.push(dataDim);\n                // encodeLabel.push(dataDim);\n                encodeSeriesName.push(dataDim);\n            }\n        });\n    }\n    // Do not make a complex rule! Hard to code maintain and not necessary.\n    // ??? TODO refactor: provide by series itself.\n    // [{name: ..., value: ...}, ...] like:\n    else if (nSeriesMap.get(seriesType) != null) {\n        // Find the first not ordinal. (5 is an experience value)\n        var firstNotOrdinal;\n        for (var i = 0; i < 5 && firstNotOrdinal == null; i++) {\n            if (!doGuessOrdinal(\n                data, sourceFormat, seriesLayoutBy,\n                completeResult.dimensionsDefine, completeResult.startIndex, i\n            )) {\n                firstNotOrdinal = i;\n            }\n        }\n        if (firstNotOrdinal != null) {\n            encode.value = firstNotOrdinal;\n            var nameDimIndex = completeResult.potentialNameDimIndex\n                || Math.max(firstNotOrdinal - 1, 0);\n            // By default, label use itemName in charts.\n            // So we dont set encodeLabel here.\n            encodeSeriesName.push(nameDimIndex);\n            encodeItemName.push(nameDimIndex);\n            // encodeTooltip.push(firstNotOrdinal);\n        }\n    }\n\n    // encodeTooltip.length && (encode.tooltip = encodeTooltip);\n    // encodeLabel.length && (encode.label = encodeLabel);\n    encodeItemName.length && (encode.itemName = encodeItemName);\n    encodeSeriesName.length && (encode.seriesName = encodeSeriesName);\n\n    return encode;\n}\n\n/**\n * If return null/undefined, indicate that should not use datasetModel.\n */\nfunction getDatasetModel(seriesModel) {\n    var option = seriesModel.option;\n    // Caution: consider the scenario:\n    // A dataset is declared and a series is not expected to use the dataset,\n    // and at the beginning `setOption({series: { noData })` (just prepare other\n    // option but no data), then `setOption({series: {data: [...]}); In this case,\n    // the user should set an empty array to avoid that dataset is used by default.\n    var thisData = option.data;\n    if (!thisData) {\n        return seriesModel.ecModel.getComponent('dataset', option.datasetIndex || 0);\n    }\n}\n\n/**\n * The rule should not be complex, otherwise user might not\n * be able to known where the data is wrong.\n * The code is ugly, but how to make it neat?\n *\n * @param {module:echars/data/Source} source\n * @param {number} dimIndex\n * @return {boolean} Whether ordinal.\n */\nfunction guessOrdinal(source, dimIndex) {\n    return doGuessOrdinal(\n        source.data,\n        source.sourceFormat,\n        source.seriesLayoutBy,\n        source.dimensionsDefine,\n        source.startIndex,\n        dimIndex\n    );\n}\n\n// dimIndex may be overflow source data.\nfunction doGuessOrdinal(\n    data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex\n) {\n    var result;\n    // Experience value.\n    var maxLoop = 5;\n\n    if (isTypedArray(data)) {\n        return false;\n    }\n\n    // When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine\n    // always exists in source.\n    var dimName;\n    if (dimensionsDefine) {\n        dimName = dimensionsDefine[dimIndex];\n        dimName = isObject$1(dimName) ? dimName.name : dimName;\n    }\n\n    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {\n        if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {\n            var sample = data[dimIndex];\n            for (var i = 0; i < (sample || []).length && i < maxLoop; i++) {\n                if ((result = detectValue(sample[startIndex + i])) != null) {\n                    return result;\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < data.length && i < maxLoop; i++) {\n                var row = data[startIndex + i];\n                if (row && (result = detectValue(row[dimIndex])) != null) {\n                    return result;\n                }\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {\n        if (!dimName) {\n            return;\n        }\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            var item = data[i];\n            if (item && (result = detectValue(item[dimName])) != null) {\n                return result;\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {\n        if (!dimName) {\n            return;\n        }\n        var sample = data[dimName];\n        if (!sample || isTypedArray(sample)) {\n            return false;\n        }\n        for (var i = 0; i < sample.length && i < maxLoop; i++) {\n            if ((result = detectValue(sample[i])) != null) {\n                return result;\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            var item = data[i];\n            var val = getDataItemValue(item);\n            if (!isArray(val)) {\n                return false;\n            }\n            if ((result = detectValue(val[dimIndex])) != null) {\n                return result;\n            }\n        }\n    }\n\n    function detectValue(val) {\n        // Consider usage convenience, '1', '2' will be treated as \"number\".\n        // `isFinit('')` get `true`.\n        if (val != null && isFinite(val) && val !== '') {\n            return false;\n        }\n        else if (isString(val) && val !== '-') {\n            return true;\n        }\n    }\n\n    return false;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * ECharts global model\n *\n * @module {echarts/model/Global}\n */\n\n\n/**\n * Caution: If the mechanism should be changed some day, these cases\n * should be considered:\n *\n * (1) In `merge option` mode, if using the same option to call `setOption`\n * many times, the result should be the same (try our best to ensure that).\n * (2) In `merge option` mode, if a component has no id/name specified, it\n * will be merged by index, and the result sequence of the components is\n * consistent to the original sequence.\n * (3) `reset` feature (in toolbox). Find detailed info in comments about\n * `mergeOption` in module:echarts/model/OptionManager.\n */\n\nvar OPTION_INNER_KEY = '\\0_ec_inner';\n\n/**\n * @alias module:echarts/model/Global\n *\n * @param {Object} option\n * @param {module:echarts/model/Model} parentModel\n * @param {Object} theme\n */\nvar GlobalModel = Model.extend({\n\n    init: function (option, parentModel, theme, optionManager) {\n        theme = theme || {};\n\n        this.option = null; // Mark as not initialized.\n\n        /**\n         * @type {module:echarts/model/Model}\n         * @private\n         */\n        this._theme = new Model(theme);\n\n        /**\n         * @type {module:echarts/model/OptionManager}\n         */\n        this._optionManager = optionManager;\n    },\n\n    setOption: function (option, optionPreprocessorFuncs) {\n        assert$1(\n            !(OPTION_INNER_KEY in option),\n            'please use chart.getOption()'\n        );\n\n        this._optionManager.setOption(option, optionPreprocessorFuncs);\n\n        this.resetOption(null);\n    },\n\n    /**\n     * @param {string} type null/undefined: reset all.\n     *                      'recreate': force recreate all.\n     *                      'timeline': only reset timeline option\n     *                      'media': only reset media query option\n     * @return {boolean} Whether option changed.\n     */\n    resetOption: function (type) {\n        var optionChanged = false;\n        var optionManager = this._optionManager;\n\n        if (!type || type === 'recreate') {\n            var baseOption = optionManager.mountOption(type === 'recreate');\n\n            if (!this.option || type === 'recreate') {\n                initBase.call(this, baseOption);\n            }\n            else {\n                this.restoreData();\n                this.mergeOption(baseOption);\n            }\n            optionChanged = true;\n        }\n\n        if (type === 'timeline' || type === 'media') {\n            this.restoreData();\n        }\n\n        if (!type || type === 'recreate' || type === 'timeline') {\n            var timelineOption = optionManager.getTimelineOption(this);\n            timelineOption && (this.mergeOption(timelineOption), optionChanged = true);\n        }\n\n        if (!type || type === 'recreate' || type === 'media') {\n            var mediaOptions = optionManager.getMediaOption(this, this._api);\n            if (mediaOptions.length) {\n                each$1(mediaOptions, function (mediaOption) {\n                    this.mergeOption(mediaOption, optionChanged = true);\n                }, this);\n            }\n        }\n\n        return optionChanged;\n    },\n\n    /**\n     * @protected\n     */\n    mergeOption: function (newOption) {\n        var option = this.option;\n        var componentsMap = this._componentsMap;\n        var newCptTypes = [];\n\n        resetSourceDefaulter(this);\n\n        // If no component class, merge directly.\n        // For example: color, animaiton options, etc.\n        each$1(newOption, function (componentOption, mainType) {\n            if (componentOption == null) {\n                return;\n            }\n\n            if (!ComponentModel.hasClass(mainType)) {\n                // globalSettingTask.dirty();\n                option[mainType] = option[mainType] == null\n                    ? clone(componentOption)\n                    : merge(option[mainType], componentOption, true);\n            }\n            else if (mainType) {\n                newCptTypes.push(mainType);\n            }\n        });\n\n        ComponentModel.topologicalTravel(\n            newCptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this\n        );\n\n        function visitComponent(mainType, dependencies) {\n\n            var newCptOptionList = normalizeToArray(newOption[mainType]);\n\n            var mapResult = mappingToExists(\n                componentsMap.get(mainType), newCptOptionList\n            );\n\n            makeIdAndName(mapResult);\n\n            // Set mainType and complete subType.\n            each$1(mapResult, function (item, index) {\n                var opt = item.option;\n                if (isObject$1(opt)) {\n                    item.keyInfo.mainType = mainType;\n                    item.keyInfo.subType = determineSubType(mainType, opt, item.exist);\n                }\n            });\n\n            var dependentModels = getComponentsByTypes(\n                componentsMap, dependencies\n            );\n\n            option[mainType] = [];\n            componentsMap.set(mainType, []);\n\n            each$1(mapResult, function (resultItem, index) {\n                var componentModel = resultItem.exist;\n                var newCptOption = resultItem.option;\n\n                assert$1(\n                    isObject$1(newCptOption) || componentModel,\n                    'Empty component definition'\n                );\n\n                // Consider where is no new option and should be merged using {},\n                // see removeEdgeAndAdd in topologicalTravel and\n                // ComponentModel.getAllClassMainTypes.\n                if (!newCptOption) {\n                    componentModel.mergeOption({}, this);\n                    componentModel.optionUpdated({}, false);\n                }\n                else {\n                    var ComponentModelClass = ComponentModel.getClass(\n                        mainType, resultItem.keyInfo.subType, true\n                    );\n\n                    if (componentModel && componentModel instanceof ComponentModelClass) {\n                        componentModel.name = resultItem.keyInfo.name;\n                        // componentModel.settingTask && componentModel.settingTask.dirty();\n                        componentModel.mergeOption(newCptOption, this);\n                        componentModel.optionUpdated(newCptOption, false);\n                    }\n                    else {\n                        // PENDING Global as parent ?\n                        var extraOpt = extend(\n                            {\n                                dependentModels: dependentModels,\n                                componentIndex: index\n                            },\n                            resultItem.keyInfo\n                        );\n                        componentModel = new ComponentModelClass(\n                            newCptOption, this, this, extraOpt\n                        );\n                        extend(componentModel, extraOpt);\n                        componentModel.init(newCptOption, this, this, extraOpt);\n\n                        // Call optionUpdated after init.\n                        // newCptOption has been used as componentModel.option\n                        // and may be merged with theme and default, so pass null\n                        // to avoid confusion.\n                        componentModel.optionUpdated(null, true);\n                    }\n                }\n\n                componentsMap.get(mainType)[index] = componentModel;\n                option[mainType][index] = componentModel.option;\n            }, this);\n\n            // Backup series for filtering.\n            if (mainType === 'series') {\n                createSeriesIndices(this, componentsMap.get('series'));\n            }\n        }\n\n        this._seriesIndicesMap = createHashMap(\n            this._seriesIndices = this._seriesIndices || []\n        );\n    },\n\n    /**\n     * Get option for output (cloned option and inner info removed)\n     * @public\n     * @return {Object}\n     */\n    getOption: function () {\n        var option = clone(this.option);\n\n        each$1(option, function (opts, mainType) {\n            if (ComponentModel.hasClass(mainType)) {\n                var opts = normalizeToArray(opts);\n                for (var i = opts.length - 1; i >= 0; i--) {\n                    // Remove options with inner id.\n                    if (isIdInner(opts[i])) {\n                        opts.splice(i, 1);\n                    }\n                }\n                option[mainType] = opts;\n            }\n        });\n\n        delete option[OPTION_INNER_KEY];\n\n        return option;\n    },\n\n    /**\n     * @return {module:echarts/model/Model}\n     */\n    getTheme: function () {\n        return this._theme;\n    },\n\n    /**\n     * @param {string} mainType\n     * @param {number} [idx=0]\n     * @return {module:echarts/model/Component}\n     */\n    getComponent: function (mainType, idx) {\n        var list = this._componentsMap.get(mainType);\n        if (list) {\n            return list[idx || 0];\n        }\n    },\n\n    /**\n     * If none of index and id and name used, return all components with mainType.\n     * @param {Object} condition\n     * @param {string} condition.mainType\n     * @param {string} [condition.subType] If ignore, only query by mainType\n     * @param {number|Array.<number>} [condition.index] Either input index or id or name.\n     * @param {string|Array.<string>} [condition.id] Either input index or id or name.\n     * @param {string|Array.<string>} [condition.name] Either input index or id or name.\n     * @return {Array.<module:echarts/model/Component>}\n     */\n    queryComponents: function (condition) {\n        var mainType = condition.mainType;\n        if (!mainType) {\n            return [];\n        }\n\n        var index = condition.index;\n        var id = condition.id;\n        var name = condition.name;\n\n        var cpts = this._componentsMap.get(mainType);\n\n        if (!cpts || !cpts.length) {\n            return [];\n        }\n\n        var result;\n\n        if (index != null) {\n            if (!isArray(index)) {\n                index = [index];\n            }\n            result = filter(map(index, function (idx) {\n                return cpts[idx];\n            }), function (val) {\n                return !!val;\n            });\n        }\n        else if (id != null) {\n            var isIdArray = isArray(id);\n            result = filter(cpts, function (cpt) {\n                return (isIdArray && indexOf(id, cpt.id) >= 0)\n                    || (!isIdArray && cpt.id === id);\n            });\n        }\n        else if (name != null) {\n            var isNameArray = isArray(name);\n            result = filter(cpts, function (cpt) {\n                return (isNameArray && indexOf(name, cpt.name) >= 0)\n                    || (!isNameArray && cpt.name === name);\n            });\n        }\n        else {\n            // Return all components with mainType\n            result = cpts.slice();\n        }\n\n        return filterBySubType(result, condition);\n    },\n\n    /**\n     * The interface is different from queryComponents,\n     * which is convenient for inner usage.\n     *\n     * @usage\n     * var result = findComponents(\n     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}}\n     * );\n     * var result = findComponents(\n     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}}\n     * );\n     * var result = findComponents(\n     *     {mainType: 'series'},\n     *     function (model, index) {...}\n     * );\n     * // result like [component0, componnet1, ...]\n     *\n     * @param {Object} condition\n     * @param {string} condition.mainType Mandatory.\n     * @param {string} [condition.subType] Optional.\n     * @param {Object} [condition.query] like {xxxIndex, xxxId, xxxName},\n     *        where xxx is mainType.\n     *        If query attribute is null/undefined or has no index/id/name,\n     *        do not filtering by query conditions, which is convenient for\n     *        no-payload situations or when target of action is global.\n     * @param {Function} [condition.filter] parameter: component, return boolean.\n     * @return {Array.<module:echarts/model/Component>}\n     */\n    findComponents: function (condition) {\n        var query = condition.query;\n        var mainType = condition.mainType;\n\n        var queryCond = getQueryCond(query);\n        var result = queryCond\n            ? this.queryComponents(queryCond)\n            : this._componentsMap.get(mainType);\n\n        return doFilter(filterBySubType(result, condition));\n\n        function getQueryCond(q) {\n            var indexAttr = mainType + 'Index';\n            var idAttr = mainType + 'Id';\n            var nameAttr = mainType + 'Name';\n            return q && (\n                    q[indexAttr] != null\n                    || q[idAttr] != null\n                    || q[nameAttr] != null\n                )\n                ? {\n                    mainType: mainType,\n                    // subType will be filtered finally.\n                    index: q[indexAttr],\n                    id: q[idAttr],\n                    name: q[nameAttr]\n                }\n                : null;\n        }\n\n        function doFilter(res) {\n            return condition.filter\n                    ? filter(res, condition.filter)\n                    : res;\n        }\n    },\n\n    /**\n     * @usage\n     * eachComponent('legend', function (legendModel, index) {\n     *     ...\n     * });\n     * eachComponent(function (componentType, model, index) {\n     *     // componentType does not include subType\n     *     // (componentType is 'xxx' but not 'xxx.aa')\n     * });\n     * eachComponent(\n     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}},\n     *     function (model, index) {...}\n     * );\n     * eachComponent(\n     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}},\n     *     function (model, index) {...}\n     * );\n     *\n     * @param {string|Object=} mainType When mainType is object, the definition\n     *                                  is the same as the method 'findComponents'.\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachComponent: function (mainType, cb, context) {\n        var componentsMap = this._componentsMap;\n\n        if (typeof mainType === 'function') {\n            context = cb;\n            cb = mainType;\n            componentsMap.each(function (components, componentType) {\n                each$1(components, function (component, index) {\n                    cb.call(context, componentType, component, index);\n                });\n            });\n        }\n        else if (isString(mainType)) {\n            each$1(componentsMap.get(mainType), cb, context);\n        }\n        else if (isObject$1(mainType)) {\n            var queryResult = this.findComponents(mainType);\n            each$1(queryResult, cb, context);\n        }\n    },\n\n    /**\n     * @param {string} name\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeriesByName: function (name) {\n        var series = this._componentsMap.get('series');\n        return filter(series, function (oneSeries) {\n            return oneSeries.name === name;\n        });\n    },\n\n    /**\n     * @param {number} seriesIndex\n     * @return {module:echarts/model/Series}\n     */\n    getSeriesByIndex: function (seriesIndex) {\n        return this._componentsMap.get('series')[seriesIndex];\n    },\n\n    /**\n     * Get series list before filtered by type.\n     * FIXME: rename to getRawSeriesByType?\n     *\n     * @param {string} subType\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeriesByType: function (subType) {\n        var series = this._componentsMap.get('series');\n        return filter(series, function (oneSeries) {\n            return oneSeries.subType === subType;\n        });\n    },\n\n    /**\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeries: function () {\n        return this._componentsMap.get('series').slice();\n    },\n\n    /**\n     * @return {number}\n     */\n    getSeriesCount: function () {\n        return this._componentsMap.get('series').length;\n    },\n\n    /**\n     * After filtering, series may be different\n     * frome raw series.\n     *\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachSeries: function (cb, context) {\n        assertSeriesInitialized(this);\n        each$1(this._seriesIndices, function (rawSeriesIndex) {\n            var series = this._componentsMap.get('series')[rawSeriesIndex];\n            cb.call(context, series, rawSeriesIndex);\n        }, this);\n    },\n\n    /**\n     * Iterate raw series before filtered.\n     *\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachRawSeries: function (cb, context) {\n        each$1(this._componentsMap.get('series'), cb, context);\n    },\n\n    /**\n     * After filtering, series may be different.\n     * frome raw series.\n     *\n     * @parma {string} subType\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachSeriesByType: function (subType, cb, context) {\n        assertSeriesInitialized(this);\n        each$1(this._seriesIndices, function (rawSeriesIndex) {\n            var series = this._componentsMap.get('series')[rawSeriesIndex];\n            if (series.subType === subType) {\n                cb.call(context, series, rawSeriesIndex);\n            }\n        }, this);\n    },\n\n    /**\n     * Iterate raw series before filtered of given type.\n     *\n     * @parma {string} subType\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachRawSeriesByType: function (subType, cb, context) {\n        return each$1(this.getSeriesByType(subType), cb, context);\n    },\n\n    /**\n     * @param {module:echarts/model/Series} seriesModel\n     */\n    isSeriesFiltered: function (seriesModel) {\n        assertSeriesInitialized(this);\n        return this._seriesIndicesMap.get(seriesModel.componentIndex) == null;\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getCurrentSeriesIndices: function () {\n        return (this._seriesIndices || []).slice();\n    },\n\n    /**\n     * @param {Function} cb\n     * @param {*} context\n     */\n    filterSeries: function (cb, context) {\n        assertSeriesInitialized(this);\n        var filteredSeries = filter(\n            this._componentsMap.get('series'), cb, context\n        );\n        createSeriesIndices(this, filteredSeries);\n    },\n\n    restoreData: function (payload) {\n        var componentsMap = this._componentsMap;\n\n        createSeriesIndices(this, componentsMap.get('series'));\n\n        var componentTypes = [];\n        componentsMap.each(function (components, componentType) {\n            componentTypes.push(componentType);\n        });\n\n        ComponentModel.topologicalTravel(\n            componentTypes,\n            ComponentModel.getAllClassMainTypes(),\n            function (componentType, dependencies) {\n                each$1(componentsMap.get(componentType), function (component) {\n                    (componentType !== 'series' || !isNotTargetSeries(component, payload))\n                        && component.restoreData();\n                });\n            }\n        );\n    }\n\n});\n\nfunction isNotTargetSeries(seriesModel, payload) {\n    if (payload) {\n        var index = payload.seiresIndex;\n        var id = payload.seriesId;\n        var name = payload.seriesName;\n        return (index != null && seriesModel.componentIndex !== index)\n            || (id != null && seriesModel.id !== id)\n            || (name != null && seriesModel.name !== name);\n    }\n}\n\n/**\n * @inner\n */\nfunction mergeTheme(option, theme) {\n    // PENDING\n    // NOT use `colorLayer` in theme if option has `color`\n    var notMergeColorLayer = option.color && !option.colorLayer;\n\n    each$1(theme, function (themeItem, name) {\n        if (name === 'colorLayer' && notMergeColorLayer) {\n            return;\n        }\n        // 如果有 component model 则把具体的 merge 逻辑交给该 model 处理\n        if (!ComponentModel.hasClass(name)) {\n            if (typeof themeItem === 'object') {\n                option[name] = !option[name]\n                    ? clone(themeItem)\n                    : merge(option[name], themeItem, false);\n            }\n            else {\n                if (option[name] == null) {\n                    option[name] = themeItem;\n                }\n            }\n        }\n    });\n}\n\nfunction initBase(baseOption) {\n    baseOption = baseOption;\n\n    // Using OPTION_INNER_KEY to mark that this option can not be used outside,\n    // i.e. `chart.setOption(chart.getModel().option);` is forbiden.\n    this.option = {};\n    this.option[OPTION_INNER_KEY] = 1;\n\n    /**\n     * Init with series: [], in case of calling findSeries method\n     * before series initialized.\n     * @type {Object.<string, Array.<module:echarts/model/Model>>}\n     * @private\n     */\n    this._componentsMap = createHashMap({series: []});\n\n    /**\n     * Mapping between filtered series list and raw series list.\n     * key: filtered series indices, value: raw series indices.\n     * @type {Array.<nubmer>}\n     * @private\n     */\n    this._seriesIndices;\n\n    this._seriesIndicesMap;\n\n    mergeTheme(baseOption, this._theme.option);\n\n    // TODO Needs clone when merging to the unexisted property\n    merge(baseOption, globalDefault, false);\n\n    this.mergeOption(baseOption);\n}\n\n/**\n * @inner\n * @param {Array.<string>|string} types model types\n * @return {Object} key: {string} type, value: {Array.<Object>} models\n */\nfunction getComponentsByTypes(componentsMap, types) {\n    if (!isArray(types)) {\n        types = types ? [types] : [];\n    }\n\n    var ret = {};\n    each$1(types, function (type) {\n        ret[type] = (componentsMap.get(type) || []).slice();\n    });\n\n    return ret;\n}\n\n/**\n * @inner\n */\nfunction determineSubType(mainType, newCptOption, existComponent) {\n    var subType = newCptOption.type\n        ? newCptOption.type\n        : existComponent\n        ? existComponent.subType\n        // Use determineSubType only when there is no existComponent.\n        : ComponentModel.determineSubType(mainType, newCptOption);\n\n    // tooltip, markline, markpoint may always has no subType\n    return subType;\n}\n\n/**\n * @inner\n */\nfunction createSeriesIndices(ecModel, seriesModels) {\n    ecModel._seriesIndicesMap = createHashMap(\n        ecModel._seriesIndices = map(seriesModels, function (series) {\n            return series.componentIndex;\n        }) || []\n    );\n}\n\n/**\n * @inner\n */\nfunction filterBySubType(components, condition) {\n    // Using hasOwnProperty for restrict. Consider\n    // subType is undefined in user payload.\n    return condition.hasOwnProperty('subType')\n        ? filter(components, function (cpt) {\n            return cpt.subType === condition.subType;\n        })\n        : components;\n}\n\n/**\n * @inner\n */\nfunction assertSeriesInitialized(ecModel) {\n    // Components that use _seriesIndices should depends on series component,\n    // which make sure that their initialization is after series.\n    if (__DEV__) {\n        if (!ecModel._seriesIndices) {\n            throw new Error('Option should contains series.');\n        }\n    }\n}\n\nmixin(GlobalModel, colorPaletteMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar echartsAPIList = [\n    'getDom', 'getZr', 'getWidth', 'getHeight', 'getDevicePixelRatio', 'dispatchAction', 'isDisposed',\n    'on', 'off', 'getDataURL', 'getConnectedDataURL', 'getModel', 'getOption',\n    'getViewOfComponentModel', 'getViewOfSeriesModel'\n];\n// And `getCoordinateSystems` and `getComponentByElement` will be injected in echarts.js\n\nfunction ExtensionAPI(chartInstance) {\n    each$1(echartsAPIList, function (name) {\n        this[name] = bind(chartInstance[name], chartInstance);\n    }, this);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar coordinateSystemCreators = {};\n\nfunction CoordinateSystemManager() {\n\n    this._coordinateSystems = [];\n}\n\nCoordinateSystemManager.prototype = {\n\n    constructor: CoordinateSystemManager,\n\n    create: function (ecModel, api) {\n        var coordinateSystems = [];\n        each$1(coordinateSystemCreators, function (creater, type) {\n            var list = creater.create(ecModel, api);\n            coordinateSystems = coordinateSystems.concat(list || []);\n        });\n\n        this._coordinateSystems = coordinateSystems;\n    },\n\n    update: function (ecModel, api) {\n        each$1(this._coordinateSystems, function (coordSys) {\n            coordSys.update && coordSys.update(ecModel, api);\n        });\n    },\n\n    getCoordinateSystems: function () {\n        return this._coordinateSystems.slice();\n    }\n};\n\nCoordinateSystemManager.register = function (type, coordinateSystemCreator) {\n    coordinateSystemCreators[type] = coordinateSystemCreator;\n};\n\nCoordinateSystemManager.get = function (type) {\n    return coordinateSystemCreators[type];\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * ECharts option manager\n *\n * @module {echarts/model/OptionManager}\n */\n\n\nvar each$4 = each$1;\nvar clone$3 = clone;\nvar map$1 = map;\nvar merge$1 = merge;\n\nvar QUERY_REG = /^(min|max)?(.+)$/;\n\n/**\n * TERM EXPLANATIONS:\n *\n * [option]:\n *\n *     An object that contains definitions of components. For example:\n *     var option = {\n *         title: {...},\n *         legend: {...},\n *         visualMap: {...},\n *         series: [\n *             {data: [...]},\n *             {data: [...]},\n *             ...\n *         ]\n *     };\n *\n * [rawOption]:\n *\n *     An object input to echarts.setOption. 'rawOption' may be an\n *     'option', or may be an object contains multi-options. For example:\n *     var option = {\n *         baseOption: {\n *             title: {...},\n *             legend: {...},\n *             series: [\n *                 {data: [...]},\n *                 {data: [...]},\n *                 ...\n *             ]\n *         },\n *         timeline: {...},\n *         options: [\n *             {title: {...}, series: {data: [...]}},\n *             {title: {...}, series: {data: [...]}},\n *             ...\n *         ],\n *         media: [\n *             {\n *                 query: {maxWidth: 320},\n *                 option: {series: {x: 20}, visualMap: {show: false}}\n *             },\n *             {\n *                 query: {minWidth: 320, maxWidth: 720},\n *                 option: {series: {x: 500}, visualMap: {show: true}}\n *             },\n *             {\n *                 option: {series: {x: 1200}, visualMap: {show: true}}\n *             }\n *         ]\n *     };\n *\n * @alias module:echarts/model/OptionManager\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction OptionManager(api) {\n\n    /**\n     * @private\n     * @type {module:echarts/ExtensionAPI}\n     */\n    this._api = api;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._timelineOptions = [];\n\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    this._mediaList = [];\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._mediaDefault;\n\n    /**\n     * -1, means default.\n     * empty means no media.\n     * @private\n     * @type {Array.<number>}\n     */\n    this._currentMediaIndices = [];\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._optionBackup;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._newBaseOption;\n}\n\n// timeline.notMerge is not supported in ec3. Firstly there is rearly\n// case that notMerge is needed. Secondly supporting 'notMerge' requires\n// rawOption cloned and backuped when timeline changed, which does no\n// good to performance. What's more, that both timeline and setOption\n// method supply 'notMerge' brings complex and some problems.\n// Consider this case:\n// (step1) chart.setOption({timeline: {notMerge: false}, ...}, false);\n// (step2) chart.setOption({timeline: {notMerge: true}, ...}, false);\n\nOptionManager.prototype = {\n\n    constructor: OptionManager,\n\n    /**\n     * @public\n     * @param {Object} rawOption Raw option.\n     * @param {module:echarts/model/Global} ecModel\n     * @param {Array.<Function>} optionPreprocessorFuncs\n     * @return {Object} Init option\n     */\n    setOption: function (rawOption, optionPreprocessorFuncs) {\n        if (rawOption) {\n            // That set dat primitive is dangerous if user reuse the data when setOption again.\n            each$1(normalizeToArray(rawOption.series), function (series) {\n                series && series.data && isTypedArray(series.data) && setAsPrimitive(series.data);\n            });\n        }\n\n        // Caution: some series modify option data, if do not clone,\n        // it should ensure that the repeat modify correctly\n        // (create a new object when modify itself).\n        rawOption = clone$3(rawOption, true);\n\n        // FIXME\n        // 如果 timeline options 或者 media 中设置了某个属性，而baseOption中没有设置，则进行警告。\n\n        var oldOptionBackup = this._optionBackup;\n        var newParsedOption = parseRawOption.call(\n            this, rawOption, optionPreprocessorFuncs, !oldOptionBackup\n        );\n        this._newBaseOption = newParsedOption.baseOption;\n\n        // For setOption at second time (using merge mode);\n        if (oldOptionBackup) {\n            // Only baseOption can be merged.\n            mergeOption(oldOptionBackup.baseOption, newParsedOption.baseOption);\n\n            // For simplicity, timeline options and media options do not support merge,\n            // that is, if you `setOption` twice and both has timeline options, the latter\n            // timeline opitons will not be merged to the formers, but just substitude them.\n            if (newParsedOption.timelineOptions.length) {\n                oldOptionBackup.timelineOptions = newParsedOption.timelineOptions;\n            }\n            if (newParsedOption.mediaList.length) {\n                oldOptionBackup.mediaList = newParsedOption.mediaList;\n            }\n            if (newParsedOption.mediaDefault) {\n                oldOptionBackup.mediaDefault = newParsedOption.mediaDefault;\n            }\n        }\n        else {\n            this._optionBackup = newParsedOption;\n        }\n    },\n\n    /**\n     * @param {boolean} isRecreate\n     * @return {Object}\n     */\n    mountOption: function (isRecreate) {\n        var optionBackup = this._optionBackup;\n\n        // TODO\n        // 如果没有reset功能则不clone。\n\n        this._timelineOptions = map$1(optionBackup.timelineOptions, clone$3);\n        this._mediaList = map$1(optionBackup.mediaList, clone$3);\n        this._mediaDefault = clone$3(optionBackup.mediaDefault);\n        this._currentMediaIndices = [];\n\n        return clone$3(isRecreate\n            // this._optionBackup.baseOption, which is created at the first `setOption`\n            // called, and is merged into every new option by inner method `mergeOption`\n            // each time `setOption` called, can be only used in `isRecreate`, because\n            // its reliability is under suspicion. In other cases option merge is\n            // performed by `model.mergeOption`.\n            ? optionBackup.baseOption : this._newBaseOption\n        );\n    },\n\n    /**\n     * @param {module:echarts/model/Global} ecModel\n     * @return {Object}\n     */\n    getTimelineOption: function (ecModel) {\n        var option;\n        var timelineOptions = this._timelineOptions;\n\n        if (timelineOptions.length) {\n            // getTimelineOption can only be called after ecModel inited,\n            // so we can get currentIndex from timelineModel.\n            var timelineModel = ecModel.getComponent('timeline');\n            if (timelineModel) {\n                option = clone$3(\n                    timelineOptions[timelineModel.getCurrentIndex()],\n                    true\n                );\n            }\n        }\n\n        return option;\n    },\n\n    /**\n     * @param {module:echarts/model/Global} ecModel\n     * @return {Array.<Object>}\n     */\n    getMediaOption: function (ecModel) {\n        var ecWidth = this._api.getWidth();\n        var ecHeight = this._api.getHeight();\n        var mediaList = this._mediaList;\n        var mediaDefault = this._mediaDefault;\n        var indices = [];\n        var result = [];\n\n        // No media defined.\n        if (!mediaList.length && !mediaDefault) {\n            return result;\n        }\n\n        // Multi media may be applied, the latter defined media has higher priority.\n        for (var i = 0, len = mediaList.length; i < len; i++) {\n            if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) {\n                indices.push(i);\n            }\n        }\n\n        // FIXME\n        // 是否mediaDefault应该强制用户设置，否则可能修改不能回归。\n        if (!indices.length && mediaDefault) {\n            indices = [-1];\n        }\n\n        if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) {\n            result = map$1(indices, function (index) {\n                return clone$3(\n                    index === -1 ? mediaDefault.option : mediaList[index].option\n                );\n            });\n        }\n        // Otherwise return nothing.\n\n        this._currentMediaIndices = indices;\n\n        return result;\n    }\n};\n\nfunction parseRawOption(rawOption, optionPreprocessorFuncs, isNew) {\n    var timelineOptions = [];\n    var mediaList = [];\n    var mediaDefault;\n    var baseOption;\n\n    // Compatible with ec2.\n    var timelineOpt = rawOption.timeline;\n\n    if (rawOption.baseOption) {\n        baseOption = rawOption.baseOption;\n    }\n\n    // For timeline\n    if (timelineOpt || rawOption.options) {\n        baseOption = baseOption || {};\n        timelineOptions = (rawOption.options || []).slice();\n    }\n\n    // For media query\n    if (rawOption.media) {\n        baseOption = baseOption || {};\n        var media = rawOption.media;\n        each$4(media, function (singleMedia) {\n            if (singleMedia && singleMedia.option) {\n                if (singleMedia.query) {\n                    mediaList.push(singleMedia);\n                }\n                else if (!mediaDefault) {\n                    // Use the first media default.\n                    mediaDefault = singleMedia;\n                }\n            }\n        });\n    }\n\n    // For normal option\n    if (!baseOption) {\n        baseOption = rawOption;\n    }\n\n    // Set timelineOpt to baseOption in ec3,\n    // which is convenient for merge option.\n    if (!baseOption.timeline) {\n        baseOption.timeline = timelineOpt;\n    }\n\n    // Preprocess.\n    each$4([baseOption].concat(timelineOptions)\n        .concat(map(mediaList, function (media) {\n            return media.option;\n        })),\n        function (option) {\n            each$4(optionPreprocessorFuncs, function (preProcess) {\n                preProcess(option, isNew);\n            });\n        }\n    );\n\n    return {\n        baseOption: baseOption,\n        timelineOptions: timelineOptions,\n        mediaDefault: mediaDefault,\n        mediaList: mediaList\n    };\n}\n\n/**\n * @see <http://www.w3.org/TR/css3-mediaqueries/#media1>\n * Support: width, height, aspectRatio\n * Can use max or min as prefix.\n */\nfunction applyMediaQuery(query, ecWidth, ecHeight) {\n    var realMap = {\n        width: ecWidth,\n        height: ecHeight,\n        aspectratio: ecWidth / ecHeight // lowser case for convenientce.\n    };\n\n    var applicatable = true;\n\n    each$1(query, function (value, attr) {\n        var matched = attr.match(QUERY_REG);\n\n        if (!matched || !matched[1] || !matched[2]) {\n            return;\n        }\n\n        var operator = matched[1];\n        var realAttr = matched[2].toLowerCase();\n\n        if (!compare(realMap[realAttr], value, operator)) {\n            applicatable = false;\n        }\n    });\n\n    return applicatable;\n}\n\nfunction compare(real, expect, operator) {\n    if (operator === 'min') {\n        return real >= expect;\n    }\n    else if (operator === 'max') {\n        return real <= expect;\n    }\n    else { // Equals\n        return real === expect;\n    }\n}\n\nfunction indicesEquals(indices1, indices2) {\n    // indices is always order by asc and has only finite number.\n    return indices1.join(',') === indices2.join(',');\n}\n\n/**\n * Consider case:\n * `chart.setOption(opt1);`\n * Then user do some interaction like dataZoom, dataView changing.\n * `chart.setOption(opt2);`\n * Then user press 'reset button' in toolbox.\n *\n * After doing that all of the interaction effects should be reset, the\n * chart should be the same as the result of invoke\n * `chart.setOption(opt1); chart.setOption(opt2);`.\n *\n * Although it is not able ensure that\n * `chart.setOption(opt1); chart.setOption(opt2);` is equivalents to\n * `chart.setOption(merge(opt1, opt2));` exactly,\n * this might be the only simple way to implement that feature.\n *\n * MEMO: We've considered some other approaches:\n * 1. Each model handle its self restoration but not uniform treatment.\n *     (Too complex in logic and error-prone)\n * 2. Use a shadow ecModel. (Performace expensive)\n */\nfunction mergeOption(oldOption, newOption) {\n    newOption = newOption || {};\n\n    each$4(newOption, function (newCptOpt, mainType) {\n        if (newCptOpt == null) {\n            return;\n        }\n\n        var oldCptOpt = oldOption[mainType];\n\n        if (!ComponentModel.hasClass(mainType)) {\n            oldOption[mainType] = merge$1(oldCptOpt, newCptOpt, true);\n        }\n        else {\n            newCptOpt = normalizeToArray(newCptOpt);\n            oldCptOpt = normalizeToArray(oldCptOpt);\n\n            var mapResult = mappingToExists(oldCptOpt, newCptOpt);\n\n            oldOption[mainType] = map$1(mapResult, function (item) {\n                return (item.option && item.exist)\n                    ? merge$1(item.exist, item.option, true)\n                    : (item.exist || item.option);\n            });\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$5 = each$1;\nvar isObject$3 = isObject$1;\n\nvar POSSIBLE_STYLES = [\n    'areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle',\n    'chordStyle', 'label', 'labelLine'\n];\n\nfunction compatEC2ItemStyle(opt) {\n    var itemStyleOpt = opt && opt.itemStyle;\n    if (!itemStyleOpt) {\n        return;\n    }\n    for (var i = 0, len = POSSIBLE_STYLES.length; i < len; i++) {\n        var styleName = POSSIBLE_STYLES[i];\n        var normalItemStyleOpt = itemStyleOpt.normal;\n        var emphasisItemStyleOpt = itemStyleOpt.emphasis;\n        if (normalItemStyleOpt && normalItemStyleOpt[styleName]) {\n            opt[styleName] = opt[styleName] || {};\n            if (!opt[styleName].normal) {\n                opt[styleName].normal = normalItemStyleOpt[styleName];\n            }\n            else {\n                merge(opt[styleName].normal, normalItemStyleOpt[styleName]);\n            }\n            normalItemStyleOpt[styleName] = null;\n        }\n        if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) {\n            opt[styleName] = opt[styleName] || {};\n            if (!opt[styleName].emphasis) {\n                opt[styleName].emphasis = emphasisItemStyleOpt[styleName];\n            }\n            else {\n                merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]);\n            }\n            emphasisItemStyleOpt[styleName] = null;\n        }\n    }\n}\n\nfunction convertNormalEmphasis(opt, optType, useExtend) {\n    if (opt && opt[optType] && (opt[optType].normal || opt[optType].emphasis)) {\n        var normalOpt = opt[optType].normal;\n        var emphasisOpt = opt[optType].emphasis;\n\n        if (normalOpt) {\n            // Timeline controlStyle has other properties besides normal and emphasis\n            if (useExtend) {\n                opt[optType].normal = opt[optType].emphasis = null;\n                defaults(opt[optType], normalOpt);\n            }\n            else {\n                opt[optType] = normalOpt;\n            }\n        }\n        if (emphasisOpt) {\n            opt.emphasis = opt.emphasis || {};\n            opt.emphasis[optType] = emphasisOpt;\n        }\n    }\n}\nfunction removeEC3NormalStatus(opt) {\n    convertNormalEmphasis(opt, 'itemStyle');\n    convertNormalEmphasis(opt, 'lineStyle');\n    convertNormalEmphasis(opt, 'areaStyle');\n    convertNormalEmphasis(opt, 'label');\n    convertNormalEmphasis(opt, 'labelLine');\n    // treemap\n    convertNormalEmphasis(opt, 'upperLabel');\n    // graph\n    convertNormalEmphasis(opt, 'edgeLabel');\n}\n\nfunction compatTextStyle(opt, propName) {\n    // Check whether is not object (string\\null\\undefined ...)\n    var labelOptSingle = isObject$3(opt) && opt[propName];\n    var textStyle = isObject$3(labelOptSingle) && labelOptSingle.textStyle;\n    if (textStyle) {\n        for (var i = 0, len = TEXT_STYLE_OPTIONS.length; i < len; i++) {\n            var propName = TEXT_STYLE_OPTIONS[i];\n            if (textStyle.hasOwnProperty(propName)) {\n                labelOptSingle[propName] = textStyle[propName];\n            }\n        }\n    }\n}\n\nfunction compatEC3CommonStyles(opt) {\n    if (opt) {\n        removeEC3NormalStatus(opt);\n        compatTextStyle(opt, 'label');\n        opt.emphasis && compatTextStyle(opt.emphasis, 'label');\n    }\n}\n\nfunction processSeries(seriesOpt) {\n    if (!isObject$3(seriesOpt)) {\n        return;\n    }\n\n    compatEC2ItemStyle(seriesOpt);\n    removeEC3NormalStatus(seriesOpt);\n\n    compatTextStyle(seriesOpt, 'label');\n    // treemap\n    compatTextStyle(seriesOpt, 'upperLabel');\n    // graph\n    compatTextStyle(seriesOpt, 'edgeLabel');\n    if (seriesOpt.emphasis) {\n        compatTextStyle(seriesOpt.emphasis, 'label');\n        // treemap\n        compatTextStyle(seriesOpt.emphasis, 'upperLabel');\n        // graph\n        compatTextStyle(seriesOpt.emphasis, 'edgeLabel');\n    }\n\n    var markPoint = seriesOpt.markPoint;\n    if (markPoint) {\n        compatEC2ItemStyle(markPoint);\n        compatEC3CommonStyles(markPoint);\n    }\n\n    var markLine = seriesOpt.markLine;\n    if (markLine) {\n        compatEC2ItemStyle(markLine);\n        compatEC3CommonStyles(markLine);\n    }\n\n    var markArea = seriesOpt.markArea;\n    if (markArea) {\n        compatEC3CommonStyles(markArea);\n    }\n\n    var data = seriesOpt.data;\n\n    // Break with ec3: if `setOption` again, there may be no `type` in option,\n    // then the backward compat based on option type will not be performed.\n\n    if (seriesOpt.type === 'graph') {\n        data = data || seriesOpt.nodes;\n        var edgeData = seriesOpt.links || seriesOpt.edges;\n        if (edgeData && !isTypedArray(edgeData)) {\n            for (var i = 0; i < edgeData.length; i++) {\n                compatEC3CommonStyles(edgeData[i]);\n            }\n        }\n        each$1(seriesOpt.categories, function (opt) {\n            removeEC3NormalStatus(opt);\n        });\n    }\n\n    if (data && !isTypedArray(data)) {\n        for (var i = 0; i < data.length; i++) {\n            compatEC3CommonStyles(data[i]);\n        }\n    }\n\n    // mark point data\n    var markPoint = seriesOpt.markPoint;\n    if (markPoint && markPoint.data) {\n        var mpData = markPoint.data;\n        for (var i = 0; i < mpData.length; i++) {\n            compatEC3CommonStyles(mpData[i]);\n        }\n    }\n    // mark line data\n    var markLine = seriesOpt.markLine;\n    if (markLine && markLine.data) {\n        var mlData = markLine.data;\n        for (var i = 0; i < mlData.length; i++) {\n            if (isArray(mlData[i])) {\n                compatEC3CommonStyles(mlData[i][0]);\n                compatEC3CommonStyles(mlData[i][1]);\n            }\n            else {\n                compatEC3CommonStyles(mlData[i]);\n            }\n        }\n    }\n\n    // Series\n    if (seriesOpt.type === 'gauge') {\n        compatTextStyle(seriesOpt, 'axisLabel');\n        compatTextStyle(seriesOpt, 'title');\n        compatTextStyle(seriesOpt, 'detail');\n    }\n    else if (seriesOpt.type === 'treemap') {\n        convertNormalEmphasis(seriesOpt.breadcrumb, 'itemStyle');\n        each$1(seriesOpt.levels, function (opt) {\n            removeEC3NormalStatus(opt);\n        });\n    }\n    else if (seriesOpt.type === 'tree') {\n        removeEC3NormalStatus(seriesOpt.leaves);\n    }\n    // sunburst starts from ec4, so it does not need to compat levels.\n}\n\nfunction toArr(o) {\n    return isArray(o) ? o : o ? [o] : [];\n}\n\nfunction toObj(o) {\n    return (isArray(o) ? o[0] : o) || {};\n}\n\nvar compatStyle = function (option, isTheme) {\n    each$5(toArr(option.series), function (seriesOpt) {\n        isObject$3(seriesOpt) && processSeries(seriesOpt);\n    });\n\n    var axes = ['xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'parallelAxis', 'radar'];\n    isTheme && axes.push('valueAxis', 'categoryAxis', 'logAxis', 'timeAxis');\n\n    each$5(\n        axes,\n        function (axisName) {\n            each$5(toArr(option[axisName]), function (axisOpt) {\n                if (axisOpt) {\n                    compatTextStyle(axisOpt, 'axisLabel');\n                    compatTextStyle(axisOpt.axisPointer, 'label');\n                }\n            });\n        }\n    );\n\n    each$5(toArr(option.parallel), function (parallelOpt) {\n        var parallelAxisDefault = parallelOpt && parallelOpt.parallelAxisDefault;\n        compatTextStyle(parallelAxisDefault, 'axisLabel');\n        compatTextStyle(parallelAxisDefault && parallelAxisDefault.axisPointer, 'label');\n    });\n\n    each$5(toArr(option.calendar), function (calendarOpt) {\n        convertNormalEmphasis(calendarOpt, 'itemStyle');\n        compatTextStyle(calendarOpt, 'dayLabel');\n        compatTextStyle(calendarOpt, 'monthLabel');\n        compatTextStyle(calendarOpt, 'yearLabel');\n    });\n\n    // radar.name.textStyle\n    each$5(toArr(option.radar), function (radarOpt) {\n        compatTextStyle(radarOpt, 'name');\n    });\n\n    each$5(toArr(option.geo), function (geoOpt) {\n        if (isObject$3(geoOpt)) {\n            compatEC3CommonStyles(geoOpt);\n            each$5(toArr(geoOpt.regions), function (regionObj) {\n                compatEC3CommonStyles(regionObj);\n            });\n        }\n    });\n\n    each$5(toArr(option.timeline), function (timelineOpt) {\n        compatEC3CommonStyles(timelineOpt);\n        convertNormalEmphasis(timelineOpt, 'label');\n        convertNormalEmphasis(timelineOpt, 'itemStyle');\n        convertNormalEmphasis(timelineOpt, 'controlStyle', true);\n\n        var data = timelineOpt.data;\n        isArray(data) && each$1(data, function (item) {\n            if (isObject$1(item)) {\n                convertNormalEmphasis(item, 'label');\n                convertNormalEmphasis(item, 'itemStyle');\n            }\n        });\n    });\n\n    each$5(toArr(option.toolbox), function (toolboxOpt) {\n        convertNormalEmphasis(toolboxOpt, 'iconStyle');\n        each$5(toolboxOpt.feature, function (featureOpt) {\n            convertNormalEmphasis(featureOpt, 'iconStyle');\n        });\n    });\n\n    compatTextStyle(toObj(option.axisPointer), 'label');\n    compatTextStyle(toObj(option.tooltip).axisPointer, 'label');\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Compatitable with 2.0\n\nfunction get(opt, path) {\n    path = path.split(',');\n    var obj = opt;\n    for (var i = 0; i < path.length; i++) {\n        obj = obj && obj[path[i]];\n        if (obj == null) {\n            break;\n        }\n    }\n    return obj;\n}\n\nfunction set$1(opt, path, val, overwrite) {\n    path = path.split(',');\n    var obj = opt;\n    var key;\n    for (var i = 0; i < path.length - 1; i++) {\n        key = path[i];\n        if (obj[key] == null) {\n            obj[key] = {};\n        }\n        obj = obj[key];\n    }\n    if (overwrite || obj[path[i]] == null) {\n        obj[path[i]] = val;\n    }\n}\n\nfunction compatLayoutProperties(option) {\n    each$1(LAYOUT_PROPERTIES, function (prop) {\n        if (prop[0] in option && !(prop[1] in option)) {\n            option[prop[1]] = option[prop[0]];\n        }\n    });\n}\n\nvar LAYOUT_PROPERTIES = [\n    ['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom']\n];\n\nvar COMPATITABLE_COMPONENTS = [\n    'grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline'\n];\n\nvar backwardCompat = function (option, isTheme) {\n    compatStyle(option, isTheme);\n\n    // Make sure series array for model initialization.\n    option.series = normalizeToArray(option.series);\n\n    each$1(option.series, function (seriesOpt) {\n        if (!isObject$1(seriesOpt)) {\n            return;\n        }\n\n        var seriesType = seriesOpt.type;\n\n        if (seriesType === 'pie' || seriesType === 'gauge') {\n            if (seriesOpt.clockWise != null) {\n                seriesOpt.clockwise = seriesOpt.clockWise;\n            }\n        }\n        if (seriesType === 'gauge') {\n            var pointerColor = get(seriesOpt, 'pointer.color');\n            pointerColor != null\n                && set$1(seriesOpt, 'itemStyle.normal.color', pointerColor);\n        }\n\n        compatLayoutProperties(seriesOpt);\n    });\n\n    // dataRange has changed to visualMap\n    if (option.dataRange) {\n        option.visualMap = option.dataRange;\n    }\n\n    each$1(COMPATITABLE_COMPONENTS, function (componentName) {\n        var options = option[componentName];\n        if (options) {\n            if (!isArray(options)) {\n                options = [options];\n            }\n            each$1(options, function (option) {\n                compatLayoutProperties(option);\n            });\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (1) [Caution]: the logic is correct based on the premises:\n//     data processing stage is blocked in stream.\n//     See <module:echarts/stream/Scheduler#performDataProcessorTasks>\n// (2) Only register once when import repeatly.\n//     Should be executed before after series filtered and before stack calculation.\nvar dataStack = function (ecModel) {\n    var stackInfoMap = createHashMap();\n    ecModel.eachSeries(function (seriesModel) {\n        var stack = seriesModel.get('stack');\n        // Compatibal: when `stack` is set as '', do not stack.\n        if (stack) {\n            var stackInfoList = stackInfoMap.get(stack) || stackInfoMap.set(stack, []);\n            var data = seriesModel.getData();\n\n            var stackInfo = {\n                // Used for calculate axis extent automatically.\n                stackResultDimension: data.getCalculationInfo('stackResultDimension'),\n                stackedOverDimension: data.getCalculationInfo('stackedOverDimension'),\n                stackedDimension: data.getCalculationInfo('stackedDimension'),\n                stackedByDimension: data.getCalculationInfo('stackedByDimension'),\n                isStackedByIndex: data.getCalculationInfo('isStackedByIndex'),\n                data: data,\n                seriesModel: seriesModel\n            };\n\n            // If stacked on axis that do not support data stack.\n            if (!stackInfo.stackedDimension\n                || !(stackInfo.isStackedByIndex || stackInfo.stackedByDimension)\n            ) {\n                return;\n            }\n\n            stackInfoList.length && data.setCalculationInfo(\n                'stackedOnSeries', stackInfoList[stackInfoList.length - 1].seriesModel\n            );\n\n            stackInfoList.push(stackInfo);\n        }\n    });\n\n    stackInfoMap.each(calculateStack);\n};\n\nfunction calculateStack(stackInfoList) {\n    each$1(stackInfoList, function (targetStackInfo, idxInStack) {\n        var resultVal = [];\n        var resultNaN = [NaN, NaN];\n        var dims = [targetStackInfo.stackResultDimension, targetStackInfo.stackedOverDimension];\n        var targetData = targetStackInfo.data;\n        var isStackedByIndex = targetStackInfo.isStackedByIndex;\n\n        // Should not write on raw data, because stack series model list changes\n        // depending on legend selection.\n        var newData = targetData.map(dims, function (v0, v1, dataIndex) {\n            var sum = targetData.get(targetStackInfo.stackedDimension, dataIndex);\n\n            // Consider `connectNulls` of line area, if value is NaN, stackedOver\n            // should also be NaN, to draw a appropriate belt area.\n            if (isNaN(sum)) {\n                return resultNaN;\n            }\n\n            var byValue;\n            var stackedDataRawIndex;\n\n            if (isStackedByIndex) {\n                stackedDataRawIndex = targetData.getRawIndex(dataIndex);\n            }\n            else {\n                byValue = targetData.get(targetStackInfo.stackedByDimension, dataIndex);\n            }\n\n            // If stackOver is NaN, chart view will render point on value start.\n            var stackedOver = NaN;\n\n            for (var j = idxInStack - 1; j >= 0; j--) {\n                var stackInfo = stackInfoList[j];\n\n                // Has been optimized by inverted indices on `stackedByDimension`.\n                if (!isStackedByIndex) {\n                    stackedDataRawIndex = stackInfo.data.rawIndexOf(stackInfo.stackedByDimension, byValue);\n                }\n\n                if (stackedDataRawIndex >= 0) {\n                    var val = stackInfo.data.getByRawIndex(stackInfo.stackResultDimension, stackedDataRawIndex);\n\n                    // Considering positive stack, negative stack and empty data\n                    if ((sum >= 0 && val > 0) // Positive stack\n                        || (sum <= 0 && val < 0) // Negative stack\n                    ) {\n                        sum += val;\n                        stackedOver = val;\n                        break;\n                    }\n                }\n            }\n\n            resultVal[0] = sum;\n            resultVal[1] = stackedOver;\n\n            return resultVal;\n        });\n\n        targetData.hostModel.setData(newData);\n        // Update for consequent calculation\n        targetStackInfo.data = newData;\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO\n// ??? refactor? check the outer usage of data provider.\n// merge with defaultDimValueGetter?\n\n/**\n * If normal array used, mutable chunk size is supported.\n * If typed array used, chunk size must be fixed.\n */\nfunction DefaultDataProvider(source, dimSize) {\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n    this._source = source;\n\n    var data = this._data = source.data;\n    var sourceFormat = source.sourceFormat;\n\n    // Typed array. TODO IE10+?\n    if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {\n        if (__DEV__) {\n            if (dimSize == null) {\n                throw new Error('Typed array data must specify dimension size');\n            }\n        }\n        this._offset = 0;\n        this._dimSize = dimSize;\n        this._data = data;\n    }\n\n    var methods = providerMethods[\n        sourceFormat === SOURCE_FORMAT_ARRAY_ROWS\n        ? sourceFormat + '_' + source.seriesLayoutBy\n        : sourceFormat\n    ];\n\n    if (__DEV__) {\n        assert$1(methods, 'Invalide sourceFormat: ' + sourceFormat);\n    }\n\n    extend(this, methods);\n}\n\nvar providerProto = DefaultDataProvider.prototype;\n// If data is pure without style configuration\nproviderProto.pure = false;\n// If data is persistent and will not be released after use.\nproviderProto.persistent = true;\n\n// ???! FIXME legacy data provider do not has method getSource\nproviderProto.getSource = function () {\n    return this._source;\n};\n\nvar providerMethods = {\n\n    'arrayRows_column': {\n        pure: true,\n        count: function () {\n            return Math.max(0, this._data.length - this._source.startIndex);\n        },\n        getItem: function (idx) {\n            return this._data[idx + this._source.startIndex];\n        },\n        appendData: appendDataSimply\n    },\n\n    'arrayRows_row': {\n        pure: true,\n        count: function () {\n            var row = this._data[0];\n            return row ? Math.max(0, row.length - this._source.startIndex) : 0;\n        },\n        getItem: function (idx) {\n            idx += this._source.startIndex;\n            var item = [];\n            var data = this._data;\n            for (var i = 0; i < data.length; i++) {\n                var row = data[i];\n                item.push(row ? row[idx] : null);\n            }\n            return item;\n        },\n        appendData: function () {\n            throw new Error('Do not support appendData when set seriesLayoutBy: \"row\".');\n        }\n    },\n\n    'objectRows': {\n        pure: true,\n        count: countSimply,\n        getItem: getItemSimply,\n        appendData: appendDataSimply\n    },\n\n    'keyedColumns': {\n        pure: true,\n        count: function () {\n            var dimName = this._source.dimensionsDefine[0].name;\n            var col = this._data[dimName];\n            return col ? col.length : 0;\n        },\n        getItem: function (idx) {\n            var item = [];\n            var dims = this._source.dimensionsDefine;\n            for (var i = 0; i < dims.length; i++) {\n                var col = this._data[dims[i].name];\n                item.push(col ? col[idx] : null);\n            }\n            return item;\n        },\n        appendData: function (newData) {\n            var data = this._data;\n            each$1(newData, function (newCol, key) {\n                var oldCol = data[key] || (data[key] = []);\n                for (var i = 0; i < (newCol || []).length; i++) {\n                    oldCol.push(newCol[i]);\n                }\n            });\n        }\n    },\n\n    'original': {\n        count: countSimply,\n        getItem: getItemSimply,\n        appendData: appendDataSimply\n    },\n\n    'typedArray': {\n        persistent: false,\n        pure: true,\n        count: function () {\n            return this._data ? (this._data.length / this._dimSize) : 0;\n        },\n        getItem: function (idx, out) {\n            idx = idx - this._offset;\n            out = out || [];\n            var offset = this._dimSize * idx;\n            for (var i = 0; i < this._dimSize; i++) {\n                out[i] = this._data[offset + i];\n            }\n            return out;\n        },\n        appendData: function (newData) {\n            if (__DEV__) {\n                assert$1(\n                    isTypedArray(newData),\n                    'Added data must be TypedArray if data in initialization is TypedArray'\n                );\n            }\n\n            this._data = newData;\n        },\n\n        // Clean self if data is already used.\n        clean: function () {\n            // PENDING\n            this._offset += this.count();\n            this._data = null;\n        }\n    }\n};\n\nfunction countSimply() {\n    return this._data.length;\n}\nfunction getItemSimply(idx) {\n    return this._data[idx];\n}\nfunction appendDataSimply(newData) {\n    for (var i = 0; i < newData.length; i++) {\n        this._data.push(newData[i]);\n    }\n}\n\n\n\nvar rawValueGetters = {\n\n    arrayRows: getRawValueSimply,\n\n    objectRows: function (dataItem, dataIndex, dimIndex, dimName) {\n        return dimIndex != null ? dataItem[dimName] : dataItem;\n    },\n\n    keyedColumns: getRawValueSimply,\n\n    original: function (dataItem, dataIndex, dimIndex, dimName) {\n        // FIXME\n        // In some case (markpoint in geo (geo-map.html)), dataItem\n        // is {coord: [...]}\n        var value = getDataItemValue(dataItem);\n        return (dimIndex == null || !(value instanceof Array))\n            ? value\n            : value[dimIndex];\n    },\n\n    typedArray: getRawValueSimply\n};\n\nfunction getRawValueSimply(dataItem, dataIndex, dimIndex, dimName) {\n    return dimIndex != null ? dataItem[dimIndex] : dataItem;\n}\n\n\nvar defaultDimValueGetters = {\n\n    arrayRows: getDimValueSimply,\n\n    objectRows: function (dataItem, dimName, dataIndex, dimIndex) {\n        return converDataValue(dataItem[dimName], this._dimensionInfos[dimName]);\n    },\n\n    keyedColumns: getDimValueSimply,\n\n    original: function (dataItem, dimName, dataIndex, dimIndex) {\n        // Performance sensitive, do not use modelUtil.getDataItemValue.\n        // If dataItem is an plain object with no value field, the var `value`\n        // will be assigned with the object, but it will be tread correctly\n        // in the `convertDataValue`.\n        var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value);\n\n        // If any dataItem is like { value: 10 }\n        if (!this._rawData.pure && isDataItemOption(dataItem)) {\n            this.hasItemOption = true;\n        }\n        return converDataValue(\n            (value instanceof Array)\n                ? value[dimIndex]\n                // If value is a single number or something else not array.\n                : value,\n            this._dimensionInfos[dimName]\n        );\n    },\n\n    typedArray: function (dataItem, dimName, dataIndex, dimIndex) {\n        return dataItem[dimIndex];\n    }\n\n};\n\nfunction getDimValueSimply(dataItem, dimName, dataIndex, dimIndex) {\n    return converDataValue(dataItem[dimIndex], this._dimensionInfos[dimName]);\n}\n\n/**\n * This helper method convert value in data.\n * @param {string|number|Date} value\n * @param {Object|string} [dimInfo] If string (like 'x'), dimType defaults 'number'.\n *        If \"dimInfo.ordinalParseAndSave\", ordinal value can be parsed.\n */\nfunction converDataValue(value, dimInfo) {\n    // Performance sensitive.\n    var dimType = dimInfo && dimInfo.type;\n    if (dimType === 'ordinal') {\n        // If given value is a category string\n        var ordinalMeta = dimInfo && dimInfo.ordinalMeta;\n        return ordinalMeta\n            ? ordinalMeta.parseAndCollect(value)\n            : value;\n    }\n\n    if (dimType === 'time'\n        // spead up when using timestamp\n        && typeof value !== 'number'\n        && value != null\n        && value !== '-'\n    ) {\n        value = +parseDate(value);\n    }\n\n    // dimType defaults 'number'.\n    // If dimType is not ordinal and value is null or undefined or NaN or '-',\n    // parse to NaN.\n    return (value == null || value === '')\n        ? NaN\n        // If string (like '-'), using '+' parse to NaN\n        // If object, also parse to NaN\n        : +value;\n}\n\n// ??? FIXME can these logic be more neat: getRawValue, getRawDataItem,\n// Consider persistent.\n// Caution: why use raw value to display on label or tooltip?\n// A reason is to avoid format. For example time value we do not know\n// how to format is expected. More over, if stack is used, calculated\n// value may be 0.91000000001, which have brings trouble to display.\n// TODO: consider how to treat null/undefined/NaN when display?\n/**\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @param {string|number} [dim] dimName or dimIndex\n * @return {Array.<number>|string|number} can be null/undefined.\n */\nfunction retrieveRawValue(data, dataIndex, dim) {\n    if (!data) {\n        return;\n    }\n\n    // Consider data may be not persistent.\n    var dataItem = data.getRawDataItem(dataIndex);\n\n    if (dataItem == null) {\n        return;\n    }\n\n    var sourceFormat = data.getProvider().getSource().sourceFormat;\n    var dimName;\n    var dimIndex;\n\n    var dimInfo = data.getDimensionInfo(dim);\n    if (dimInfo) {\n        dimName = dimInfo.name;\n        dimIndex = dimInfo.index;\n    }\n\n    return rawValueGetters[sourceFormat](dataItem, dataIndex, dimIndex, dimName);\n}\n\n/**\n * Compatible with some cases (in pie, map) like:\n * data: [{name: 'xx', value: 5, selected: true}, ...]\n * where only sourceFormat is 'original' and 'objectRows' supported.\n *\n * ??? TODO\n * Supported detail options in data item when using 'arrayRows'.\n *\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @param {string} attr like 'selected'\n */\nfunction retrieveRawAttr(data, dataIndex, attr) {\n    if (!data) {\n        return;\n    }\n\n    var sourceFormat = data.getProvider().getSource().sourceFormat;\n\n    if (sourceFormat !== SOURCE_FORMAT_ORIGINAL\n        && sourceFormat !== SOURCE_FORMAT_OBJECT_ROWS\n    ) {\n        return;\n    }\n\n    var dataItem = data.getRawDataItem(dataIndex);\n    if (sourceFormat === SOURCE_FORMAT_ORIGINAL && !isObject$1(dataItem)) {\n        dataItem = null;\n    }\n    if (dataItem) {\n        return dataItem[attr];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DIMENSION_LABEL_REG = /\\{@(.+?)\\}/g;\n\n// PENDING A little ugly\nvar dataFormatMixin = {\n    /**\n     * Get params for formatter\n     * @param {number} dataIndex\n     * @param {string} [dataType]\n     * @return {Object}\n     */\n    getDataParams: function (dataIndex, dataType) {\n        var data = this.getData(dataType);\n        var rawValue = this.getRawValue(dataIndex, dataType);\n        var rawDataIndex = data.getRawIndex(dataIndex);\n        var name = data.getName(dataIndex);\n        var itemOpt = data.getRawDataItem(dataIndex);\n        var color = data.getItemVisual(dataIndex, 'color');\n        var tooltipModel = this.ecModel.getComponent('tooltip');\n        var renderModeOption = tooltipModel && tooltipModel.get('renderMode');\n        var renderMode = getTooltipRenderMode(renderModeOption);\n        var mainType = this.mainType;\n        var isSeries = mainType === 'series';\n\n        return {\n            componentType: mainType,\n            componentSubType: this.subType,\n            componentIndex: this.componentIndex,\n            seriesType: isSeries ? this.subType : null,\n            seriesIndex: this.seriesIndex,\n            seriesId: isSeries ? this.id : null,\n            seriesName: isSeries ? this.name : null,\n            name: name,\n            dataIndex: rawDataIndex,\n            data: itemOpt,\n            dataType: dataType,\n            value: rawValue,\n            color: color,\n            marker: getTooltipMarker({\n                color: color,\n                renderMode: renderMode\n            }),\n\n            // Param name list for mapping `a`, `b`, `c`, `d`, `e`\n            $vars: ['seriesName', 'name', 'value']\n        };\n    },\n\n    /**\n     * Format label\n     * @param {number} dataIndex\n     * @param {string} [status='normal'] 'normal' or 'emphasis'\n     * @param {string} [dataType]\n     * @param {number} [dimIndex]\n     * @param {string} [labelProp='label']\n     * @return {string} If not formatter, return null/undefined\n     */\n    getFormattedLabel: function (dataIndex, status, dataType, dimIndex, labelProp) {\n        status = status || 'normal';\n        var data = this.getData(dataType);\n        var itemModel = data.getItemModel(dataIndex);\n\n        var params = this.getDataParams(dataIndex, dataType);\n        if (dimIndex != null && (params.value instanceof Array)) {\n            params.value = params.value[dimIndex];\n        }\n\n        var formatter = itemModel.get(\n            status === 'normal'\n            ? [labelProp || 'label', 'formatter']\n            : [status, labelProp || 'label', 'formatter']\n        );\n\n        if (typeof formatter === 'function') {\n            params.status = status;\n            return formatter(params);\n        }\n        else if (typeof formatter === 'string') {\n            var str = formatTpl(formatter, params);\n\n            // Support 'aaa{@[3]}bbb{@product}ccc'.\n            // Do not support '}' in dim name util have to.\n            return str.replace(DIMENSION_LABEL_REG, function (origin, dim) {\n                var len = dim.length;\n                if (dim.charAt(0) === '[' && dim.charAt(len - 1) === ']') {\n                    dim = +dim.slice(1, len - 1); // Also: '[]' => 0\n                }\n                return retrieveRawValue(data, dataIndex, dim);\n            });\n        }\n    },\n\n    /**\n     * Get raw value in option\n     * @param {number} idx\n     * @param {string} [dataType]\n     * @return {Array|number|string}\n     */\n    getRawValue: function (idx, dataType) {\n        return retrieveRawValue(this.getData(dataType), idx);\n    },\n\n    /**\n     * Should be implemented.\n     * @param {number} dataIndex\n     * @param {boolean} [multipleSeries=false]\n     * @param {number} [dataType]\n     * @return {string} tooltip string\n     */\n    formatTooltip: function () {\n        // Empty function\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} define\n * @return See the return of `createTask`.\n */\nfunction createTask(define) {\n    return new Task(define);\n}\n\n/**\n * @constructor\n * @param {Object} define\n * @param {Function} define.reset Custom reset\n * @param {Function} [define.plan] Returns 'reset' indicate reset immediately.\n * @param {Function} [define.count] count is used to determin data task.\n * @param {Function} [define.onDirty] count is used to determin data task.\n */\nfunction Task(define) {\n    define = define || {};\n\n    this._reset = define.reset;\n    this._plan = define.plan;\n    this._count = define.count;\n    this._onDirty = define.onDirty;\n\n    this._dirty = true;\n\n    // Context must be specified implicitly, to\n    // avoid miss update context when model changed.\n    this.context;\n}\n\nvar taskProto = Task.prototype;\n\n/**\n * @param {Object} performArgs\n * @param {number} [performArgs.step] Specified step.\n * @param {number} [performArgs.skip] Skip customer perform call.\n * @param {number} [performArgs.modBy] Sampling window size.\n * @param {number} [performArgs.modDataCount] Sampling count.\n */\ntaskProto.perform = function (performArgs) {\n    var upTask = this._upstream;\n    var skip = performArgs && performArgs.skip;\n\n    // TODO some refactor.\n    // Pull data. Must pull data each time, because context.data\n    // may be updated by Series.setData.\n    if (this._dirty && upTask) {\n        var context = this.context;\n        context.data = context.outputData = upTask.context.outputData;\n    }\n\n    if (this.__pipeline) {\n        this.__pipeline.currentTask = this;\n    }\n\n    var planResult;\n    if (this._plan && !skip) {\n        planResult = this._plan(this.context);\n    }\n\n    // Support sharding by mod, which changes the render sequence and makes the rendered graphic\n    // elements uniformed distributed when progress, especially when moving or zooming.\n    var lastModBy = normalizeModBy(this._modBy);\n    var lastModDataCount = this._modDataCount || 0;\n    var modBy = normalizeModBy(performArgs && performArgs.modBy);\n    var modDataCount = performArgs && performArgs.modDataCount || 0;\n    if (lastModBy !== modBy || lastModDataCount !== modDataCount) {\n        planResult = 'reset';\n    }\n\n    function normalizeModBy(val) {\n        !(val >= 1) && (val = 1); // jshint ignore:line\n        return val;\n    }\n\n    var forceFirstProgress;\n    if (this._dirty || planResult === 'reset') {\n        this._dirty = false;\n        forceFirstProgress = reset(this, skip);\n    }\n\n    this._modBy = modBy;\n    this._modDataCount = modDataCount;\n\n    var step = performArgs && performArgs.step;\n\n    if (upTask) {\n\n        if (__DEV__) {\n            assert$1(upTask._outputDueEnd != null);\n        }\n        this._dueEnd = upTask._outputDueEnd;\n    }\n    // DataTask or overallTask\n    else {\n        if (__DEV__) {\n            assert$1(!this._progress || this._count);\n        }\n        this._dueEnd = this._count ? this._count(this.context) : Infinity;\n    }\n\n    // Note: Stubs, that its host overall task let it has progress, has progress.\n    // If no progress, pass index from upstream to downstream each time plan called.\n    if (this._progress) {\n        var start = this._dueIndex;\n        var end = Math.min(\n            step != null ? this._dueIndex + step : Infinity,\n            this._dueEnd\n        );\n\n        if (!skip && (forceFirstProgress || start < end)) {\n            var progress = this._progress;\n            if (isArray(progress)) {\n                for (var i = 0; i < progress.length; i++) {\n                    doProgress(this, progress[i], start, end, modBy, modDataCount);\n                }\n            }\n            else {\n                doProgress(this, progress, start, end, modBy, modDataCount);\n            }\n        }\n\n        this._dueIndex = end;\n        // If no `outputDueEnd`, assume that output data and\n        // input data is the same, so use `dueIndex` as `outputDueEnd`.\n        var outputDueEnd = this._settedOutputEnd != null\n            ? this._settedOutputEnd : end;\n\n        if (__DEV__) {\n            // ??? Can not rollback.\n            assert$1(outputDueEnd >= this._outputDueEnd);\n        }\n\n        this._outputDueEnd = outputDueEnd;\n    }\n    else {\n        // (1) Some overall task has no progress.\n        // (2) Stubs, that its host overall task do not let it has progress, has no progress.\n        // This should always be performed so it can be passed to downstream.\n        this._dueIndex = this._outputDueEnd = this._settedOutputEnd != null\n            ? this._settedOutputEnd : this._dueEnd;\n    }\n\n    return this.unfinished();\n};\n\nvar iterator = (function () {\n\n    var end;\n    var current;\n    var modBy;\n    var modDataCount;\n    var winCount;\n\n    var it = {\n        reset: function (s, e, sStep, sCount) {\n            current = s;\n            end = e;\n\n            modBy = sStep;\n            modDataCount = sCount;\n            winCount = Math.ceil(modDataCount / modBy);\n\n            it.next = (modBy > 1 && modDataCount > 0) ? modNext : sequentialNext;\n        }\n    };\n\n    return it;\n\n    function sequentialNext() {\n        return current < end ? current++ : null;\n    }\n\n    function modNext() {\n        var dataIndex = (current % winCount) * modBy + Math.ceil(current / winCount);\n        var result = current >= end\n            ? null\n            : dataIndex < modDataCount\n            ? dataIndex\n            // If modDataCount is smaller than data.count() (consider `appendData` case),\n            // Use normal linear rendering mode.\n            : current;\n        current++;\n        return result;\n    }\n})();\n\ntaskProto.dirty = function () {\n    this._dirty = true;\n    this._onDirty && this._onDirty(this.context);\n};\n\nfunction doProgress(taskIns, progress, start, end, modBy, modDataCount) {\n    iterator.reset(start, end, modBy, modDataCount);\n    taskIns._callingProgress = progress;\n    taskIns._callingProgress({\n        start: start, end: end, count: end - start, next: iterator.next\n    }, taskIns.context);\n}\n\nfunction reset(taskIns, skip) {\n    taskIns._dueIndex = taskIns._outputDueEnd = taskIns._dueEnd = 0;\n    taskIns._settedOutputEnd = null;\n\n    var progress;\n    var forceFirstProgress;\n\n    if (!skip && taskIns._reset) {\n        progress = taskIns._reset(taskIns.context);\n        if (progress && progress.progress) {\n            forceFirstProgress = progress.forceFirstProgress;\n            progress = progress.progress;\n        }\n        // To simplify no progress checking, array must has item.\n        if (isArray(progress) && !progress.length) {\n            progress = null;\n        }\n    }\n\n    taskIns._progress = progress;\n    taskIns._modBy = taskIns._modDataCount = null;\n\n    var downstream = taskIns._downstream;\n    downstream && downstream.dirty();\n\n    return forceFirstProgress;\n}\n\n/**\n * @return {boolean}\n */\ntaskProto.unfinished = function () {\n    return this._progress && this._dueIndex < this._dueEnd;\n};\n\n/**\n * @param {Object} downTask The downstream task.\n * @return {Object} The downstream task.\n */\ntaskProto.pipe = function (downTask) {\n    if (__DEV__) {\n        assert$1(downTask && !downTask._disposed && downTask !== this);\n    }\n\n    // If already downstream, do not dirty downTask.\n    if (this._downstream !== downTask || this._dirty) {\n        this._downstream = downTask;\n        downTask._upstream = this;\n        downTask.dirty();\n    }\n};\n\ntaskProto.dispose = function () {\n    if (this._disposed) {\n        return;\n    }\n\n    this._upstream && (this._upstream._downstream = null);\n    this._downstream && (this._downstream._upstream = null);\n\n    this._dirty = false;\n    this._disposed = true;\n};\n\ntaskProto.getUpstream = function () {\n    return this._upstream;\n};\n\ntaskProto.getDownstream = function () {\n    return this._downstream;\n};\n\ntaskProto.setOutputEnd = function (end) {\n    // This only happend in dataTask, dataZoom, map, currently.\n    // where dataZoom do not set end each time, but only set\n    // when reset. So we should record the setted end, in case\n    // that the stub of dataZoom perform again and earse the\n    // setted end by upstream.\n    this._outputDueEnd = this._settedOutputEnd = end;\n};\n\n\n///////////////////////////////////////////////////////////\n// For stream debug (Should be commented out after used!)\n// Usage: printTask(this, 'begin');\n// Usage: printTask(this, null, {someExtraProp});\n// function printTask(task, prefix, extra) {\n//     window.ecTaskUID == null && (window.ecTaskUID = 0);\n//     task.uidDebug == null && (task.uidDebug = `task_${window.ecTaskUID++}`);\n//     task.agent && task.agent.uidDebug == null && (task.agent.uidDebug = `task_${window.ecTaskUID++}`);\n//     var props = [];\n//     if (task.__pipeline) {\n//         var val = `${task.__idxInPipeline}/${task.__pipeline.tail.__idxInPipeline} ${task.agent ? '(stub)' : ''}`;\n//         props.push({text: 'idx', value: val});\n//     } else {\n//         var stubCount = 0;\n//         task.agentStubMap.each(() => stubCount++);\n//         props.push({text: 'idx', value: `overall (stubs: ${stubCount})`});\n//     }\n//     props.push({text: 'uid', value: task.uidDebug});\n//     if (task.__pipeline) {\n//         props.push({text: 'pid', value: task.__pipeline.id});\n//         task.agent && props.push(\n//             {text: 'stubFor', value: task.agent.uidDebug}\n//         );\n//     }\n//     props.push(\n//         {text: 'dirty', value: task._dirty},\n//         {text: 'dueIndex', value: task._dueIndex},\n//         {text: 'dueEnd', value: task._dueEnd},\n//         {text: 'outputDueEnd', value: task._outputDueEnd}\n//     );\n//     if (extra) {\n//         Object.keys(extra).forEach(key => {\n//             props.push({text: key, value: extra[key]});\n//         });\n//     }\n//     var args = ['color: blue'];\n//     var msg = `%c[${prefix || 'T'}] %c` + props.map(item => (\n//         args.push('color: black', 'color: red'),\n//         `${item.text}: %c${item.value}`\n//     )).join('%c, ');\n//     console.log.apply(console, [msg].concat(args));\n//     // console.log(this);\n// }\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$4 = makeInner();\n\nvar SeriesModel = ComponentModel.extend({\n\n    type: 'series.__base__',\n\n    /**\n     * @readOnly\n     */\n    seriesIndex: 0,\n\n    // coodinateSystem will be injected in the echarts/CoordinateSystem\n    coordinateSystem: null,\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    defaultOption: null,\n\n    /**\n     * Data provided for legend\n     * @type {Function}\n     */\n    // PENDING\n    legendDataProvider: null,\n\n    /**\n     * Access path of color for visual\n     */\n    visualColorAccessPath: 'itemStyle.color',\n\n    /**\n     * Support merge layout params.\n     * Only support 'box' now (left/right/top/bottom/width/height).\n     * @type {string|Object} Object can be {ignoreSize: true}\n     * @readOnly\n     */\n    layoutMode: null,\n\n    init: function (option, parentModel, ecModel, extraOpt) {\n\n        /**\n         * @type {number}\n         * @readOnly\n         */\n        this.seriesIndex = this.componentIndex;\n\n        this.dataTask = createTask({\n            count: dataTaskCount,\n            reset: dataTaskReset\n        });\n        this.dataTask.context = {model: this};\n\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        prepareSource(this);\n\n\n        var data = this.getInitialData(option, ecModel);\n        wrapData(data, this);\n        this.dataTask.context.data = data;\n\n        if (__DEV__) {\n            assert$1(data, 'getInitialData returned invalid data.');\n        }\n\n        /**\n         * @type {module:echarts/data/List|module:echarts/data/Tree|module:echarts/data/Graph}\n         * @private\n         */\n        inner$4(this).dataBeforeProcessed = data;\n\n        // If we reverse the order (make data firstly, and then make\n        // dataBeforeProcessed by cloneShallow), cloneShallow will\n        // cause data.graph.data !== data when using\n        // module:echarts/data/Graph or module:echarts/data/Tree.\n        // See module:echarts/data/helper/linkList\n\n        // Theoretically, it is unreasonable to call `seriesModel.getData()` in the model\n        // init or merge stage, because the data can be restored. So we do not `restoreData`\n        // and `setData` here, which forbids calling `seriesModel.getData()` in this stage.\n        // Call `seriesModel.getRawData()` instead.\n        // this.restoreData();\n\n        autoSeriesName(this);\n    },\n\n    /**\n     * Util for merge default and theme to option\n     * @param  {Object} option\n     * @param  {module:echarts/model/Global} ecModel\n     */\n    mergeDefaultAndTheme: function (option, ecModel) {\n        var layoutMode = this.layoutMode;\n        var inputPositionParams = layoutMode\n            ? getLayoutParams(option) : {};\n\n        // Backward compat: using subType on theme.\n        // But if name duplicate between series subType\n        // (for example: parallel) add component mainType,\n        // add suffix 'Series'.\n        var themeSubType = this.subType;\n        if (ComponentModel.hasClass(themeSubType)) {\n            themeSubType += 'Series';\n        }\n        merge(\n            option,\n            ecModel.getTheme().get(this.subType)\n        );\n        merge(option, this.getDefaultOption());\n\n        // Default label emphasis `show`\n        defaultEmphasis(option, 'label', ['show']);\n\n        this.fillDataTextStyle(option.data);\n\n        if (layoutMode) {\n            mergeLayoutParam(option, inputPositionParams, layoutMode);\n        }\n    },\n\n    mergeOption: function (newSeriesOption, ecModel) {\n        // this.settingTask.dirty();\n\n        newSeriesOption = merge(this.option, newSeriesOption, true);\n        this.fillDataTextStyle(newSeriesOption.data);\n\n        var layoutMode = this.layoutMode;\n        if (layoutMode) {\n            mergeLayoutParam(this.option, newSeriesOption, layoutMode);\n        }\n\n        prepareSource(this);\n\n        var data = this.getInitialData(newSeriesOption, ecModel);\n        wrapData(data, this);\n        this.dataTask.dirty();\n        this.dataTask.context.data = data;\n\n        inner$4(this).dataBeforeProcessed = data;\n\n        autoSeriesName(this);\n    },\n\n    fillDataTextStyle: function (data) {\n        // Default data label emphasis `show`\n        // FIXME Tree structure data ?\n        // FIXME Performance ?\n        if (data && !isTypedArray(data)) {\n            var props = ['show'];\n            for (var i = 0; i < data.length; i++) {\n                if (data[i] && data[i].label) {\n                    defaultEmphasis(data[i], 'label', props);\n                }\n            }\n        }\n    },\n\n    /**\n     * Init a data structure from data related option in series\n     * Must be overwritten\n     */\n    getInitialData: function () {},\n\n    /**\n     * Append data to list\n     * @param {Object} params\n     * @param {Array|TypedArray} params.data\n     */\n    appendData: function (params) {\n        // FIXME ???\n        // (1) If data from dataset, forbidden append.\n        // (2) support append data of dataset.\n        var data = this.getRawData();\n        data.appendData(params.data);\n    },\n\n    /**\n     * Consider some method like `filter`, `map` need make new data,\n     * We should make sure that `seriesModel.getData()` get correct\n     * data in the stream procedure. So we fetch data from upstream\n     * each time `task.perform` called.\n     * @param {string} [dataType]\n     * @return {module:echarts/data/List}\n     */\n    getData: function (dataType) {\n        var task = getCurrentTask(this);\n        if (task) {\n            var data = task.context.data;\n            return dataType == null ? data : data.getLinkedData(dataType);\n        }\n        else {\n            // When series is not alive (that may happen when click toolbox\n            // restore or setOption with not merge mode), series data may\n            // be still need to judge animation or something when graphic\n            // elements want to know whether fade out.\n            return inner$4(this).data;\n        }\n    },\n\n    /**\n     * @param {module:echarts/data/List} data\n     */\n    setData: function (data) {\n        var task = getCurrentTask(this);\n        if (task) {\n            var context = task.context;\n            // Consider case: filter, data sample.\n            if (context.data !== data && task.modifyOutputEnd) {\n                task.setOutputEnd(data.count());\n            }\n            context.outputData = data;\n            // Caution: setData should update context.data,\n            // Because getData may be called multiply in a\n            // single stage and expect to get the data just\n            // set. (For example, AxisProxy, x y both call\n            // getData and setDate sequentially).\n            // So the context.data should be fetched from\n            // upstream each time when a stage starts to be\n            // performed.\n            if (task !== this.dataTask) {\n                context.data = data;\n            }\n        }\n        inner$4(this).data = data;\n    },\n\n    /**\n     * @see {module:echarts/data/helper/sourceHelper#getSource}\n     * @return {module:echarts/data/Source} source\n     */\n    getSource: function () {\n        return getSource(this);\n    },\n\n    /**\n     * Get data before processed\n     * @return {module:echarts/data/List}\n     */\n    getRawData: function () {\n        return inner$4(this).dataBeforeProcessed;\n    },\n\n    /**\n     * Get base axis if has coordinate system and has axis.\n     * By default use coordSys.getBaseAxis();\n     * Can be overrided for some chart.\n     * @return {type} description\n     */\n    getBaseAxis: function () {\n        var coordSys = this.coordinateSystem;\n        return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis();\n    },\n\n    // FIXME\n    /**\n     * Default tooltip formatter\n     *\n     * @param {number} dataIndex\n     * @param {boolean} [multipleSeries=false]\n     * @param {number} [dataType]\n     * @param {string} [renderMode='html'] valid values: 'html' and 'richText'.\n     *                                     'html' is used for rendering tooltip in extra DOM form, and the result\n     *                                     string is used as DOM HTML content.\n     *                                     'richText' is used for rendering tooltip in rich text form, for those where\n     *                                     DOM operation is not supported.\n     * @return {Object} formatted tooltip with `html` and `markers`\n     */\n    formatTooltip: function (dataIndex, multipleSeries, dataType, renderMode) {\n\n        var series = this;\n        renderMode = renderMode || 'html';\n        var newLine = renderMode === 'html' ? '<br/>' : '\\n';\n        var isRichText = renderMode === 'richText';\n        var markers = {};\n        var markerId = 0;\n\n        function formatArrayValue(value) {\n            // ??? TODO refactor these logic.\n            // check: category-no-encode-has-axis-data in dataset.html\n            var vertially = reduce(value, function (vertially, val, idx) {\n                var dimItem = data.getDimensionInfo(idx);\n                return vertially |= dimItem && dimItem.tooltip !== false && dimItem.displayName != null;\n            }, 0);\n\n            var result = [];\n\n            tooltipDims.length\n                ? each$1(tooltipDims, function (dim) {\n                    setEachItem(retrieveRawValue(data, dataIndex, dim), dim);\n                })\n                // By default, all dims is used on tooltip.\n                : each$1(value, setEachItem);\n\n            function setEachItem(val, dim) {\n                var dimInfo = data.getDimensionInfo(dim);\n                // If `dimInfo.tooltip` is not set, show tooltip.\n                if (!dimInfo || dimInfo.otherDims.tooltip === false) {\n                    return;\n                }\n                var dimType = dimInfo.type;\n                var markName = 'sub' + series.seriesIndex + 'at' + markerId;\n                var dimHead = getTooltipMarker({\n                    color: color,\n                    type: 'subItem',\n                    renderMode: renderMode,\n                    markerId: markName\n                });\n\n                var dimHeadStr = typeof dimHead === 'string' ? dimHead : dimHead.content;\n                var valStr = (vertially\n                        ? dimHeadStr + encodeHTML(dimInfo.displayName || '-') + ': '\n                        : ''\n                    )\n                    // FIXME should not format time for raw data?\n                    + encodeHTML(dimType === 'ordinal'\n                        ? val + ''\n                        : dimType === 'time'\n                        ? (multipleSeries ? '' : formatTime('yyyy/MM/dd hh:mm:ss', val))\n                        : addCommas(val)\n                    );\n                valStr && result.push(valStr);\n\n                if (isRichText) {\n                    markers[markName] = color;\n                    ++markerId;\n                }\n            }\n\n            var newLine = vertially ? (isRichText ? '\\n' : '<br/>') : '';\n            var content = newLine + result.join(newLine || ', ');\n            return {\n                renderMode: renderMode,\n                content: content,\n                style: markers\n            };\n        }\n\n        function formatSingleValue(val) {\n            // return encodeHTML(addCommas(val));\n            return {\n                renderMode: renderMode,\n                content: encodeHTML(addCommas(val)),\n                style: markers\n            };\n        }\n\n        var data = this.getData();\n        var tooltipDims = data.mapDimension('defaultedTooltip', true);\n        var tooltipDimLen = tooltipDims.length;\n        var value = this.getRawValue(dataIndex);\n        var isValueArr = isArray(value);\n\n        var color = data.getItemVisual(dataIndex, 'color');\n        if (isObject$1(color) && color.colorStops) {\n            color = (color.colorStops[0] || {}).color;\n        }\n        color = color || 'transparent';\n\n        // Complicated rule for pretty tooltip.\n        var formattedValue = (tooltipDimLen > 1 || (isValueArr && !tooltipDimLen))\n            ? formatArrayValue(value)\n            : tooltipDimLen\n            ? formatSingleValue(retrieveRawValue(data, dataIndex, tooltipDims[0]))\n            : formatSingleValue(isValueArr ? value[0] : value);\n        var content = formattedValue.content;\n\n        var markName = series.seriesIndex + 'at' + markerId;\n        var colorEl = getTooltipMarker({\n            color: color,\n            type: 'item',\n            renderMode: renderMode,\n            markerId: markName\n        });\n        markers[markName] = color;\n        ++markerId;\n\n        var name = data.getName(dataIndex);\n\n        var seriesName = this.name;\n        if (!isNameSpecified(this)) {\n            seriesName = '';\n        }\n        seriesName = seriesName\n            ? encodeHTML(seriesName) + (!multipleSeries ? newLine : ': ')\n            : '';\n\n        var colorStr = typeof colorEl === 'string' ? colorEl : colorEl.content;\n        var html = !multipleSeries\n            ? seriesName + colorStr\n                + (name\n                    ? encodeHTML(name) + ': ' + content\n                    : content\n                )\n            : colorStr + seriesName + content;\n\n        return {\n            html: html,\n            markers: markers\n        };\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isAnimationEnabled: function () {\n        if (env$1.node) {\n            return false;\n        }\n\n        var animationEnabled = this.getShallow('animation');\n        if (animationEnabled) {\n            if (this.getData().count() > this.getShallow('animationThreshold')) {\n                animationEnabled = false;\n            }\n        }\n        return animationEnabled;\n    },\n\n    restoreData: function () {\n        this.dataTask.dirty();\n    },\n\n    getColorFromPalette: function (name, scope, requestColorNum) {\n        var ecModel = this.ecModel;\n        // PENDING\n        var color = colorPaletteMixin.getColorFromPalette.call(this, name, scope, requestColorNum);\n        if (!color) {\n            color = ecModel.getColorFromPalette(name, scope, requestColorNum);\n        }\n        return color;\n    },\n\n    /**\n     * Use `data.mapDimension(coordDim, true)` instead.\n     * @deprecated\n     */\n    coordDimToDataDim: function (coordDim) {\n        return this.getRawData().mapDimension(coordDim, true);\n    },\n\n    /**\n     * Get progressive rendering count each step\n     * @return {number}\n     */\n    getProgressive: function () {\n        return this.get('progressive');\n    },\n\n    /**\n     * Get progressive rendering count each step\n     * @return {number}\n     */\n    getProgressiveThreshold: function () {\n        return this.get('progressiveThreshold');\n    },\n\n    /**\n     * Get data indices for show tooltip content. See tooltip.\n     * @abstract\n     * @param {Array.<string>|string} dim\n     * @param {Array.<number>} value\n     * @param {module:echarts/coord/single/SingleAxis} baseAxis\n     * @return {Object} {dataIndices, nestestValue}.\n     */\n    getAxisTooltipData: null,\n\n    /**\n     * See tooltip.\n     * @abstract\n     * @param {number} dataIndex\n     * @return {Array.<number>} Point of tooltip. null/undefined can be returned.\n     */\n    getTooltipPosition: null,\n\n    /**\n     * @see {module:echarts/stream/Scheduler}\n     */\n    pipeTask: null,\n\n    /**\n     * Convinient for override in extended class.\n     * @protected\n     * @type {Function}\n     */\n    preventIncremental: null,\n\n    /**\n     * @public\n     * @readOnly\n     * @type {Object}\n     */\n    pipelineContext: null\n\n});\n\n\nmixin(SeriesModel, dataFormatMixin);\nmixin(SeriesModel, colorPaletteMixin);\n\n/**\n * MUST be called after `prepareSource` called\n * Here we need to make auto series, especially for auto legend. But we\n * do not modify series.name in option to avoid side effects.\n */\nfunction autoSeriesName(seriesModel) {\n    // User specified name has higher priority, otherwise it may cause\n    // series can not be queried unexpectedly.\n    var name = seriesModel.name;\n    if (!isNameSpecified(seriesModel)) {\n        seriesModel.name = getSeriesAutoName(seriesModel) || name;\n    }\n}\n\nfunction getSeriesAutoName(seriesModel) {\n    var data = seriesModel.getRawData();\n    var dataDims = data.mapDimension('seriesName', true);\n    var nameArr = [];\n    each$1(dataDims, function (dataDim) {\n        var dimInfo = data.getDimensionInfo(dataDim);\n        dimInfo.displayName && nameArr.push(dimInfo.displayName);\n    });\n    return nameArr.join(' ');\n}\n\nfunction dataTaskCount(context) {\n    return context.model.getRawData().count();\n}\n\nfunction dataTaskReset(context) {\n    var seriesModel = context.model;\n    seriesModel.setData(seriesModel.getRawData().cloneShallow());\n    return dataTaskProgress;\n}\n\nfunction dataTaskProgress(param, context) {\n    // Avoid repead cloneShallow when data just created in reset.\n    if (param.end > context.outputData.count()) {\n        context.model.getRawData().cloneShallow(context.outputData);\n    }\n}\n\n// TODO refactor\nfunction wrapData(data, seriesModel) {\n    each$1(data.CHANGABLE_METHODS, function (methodName) {\n        data.wrapMethod(methodName, curry(onDataSelfChange, seriesModel));\n    });\n}\n\nfunction onDataSelfChange(seriesModel) {\n    var task = getCurrentTask(seriesModel);\n    if (task) {\n        // Consider case: filter, selectRange\n        task.setOutputEnd(this.count());\n    }\n}\n\nfunction getCurrentTask(seriesModel) {\n    var scheduler = (seriesModel.ecModel || {}).scheduler;\n    var pipeline = scheduler && scheduler.getPipeline(seriesModel.uid);\n\n    if (pipeline) {\n        // When pipline finished, the currrentTask keep the last\n        // task (renderTask).\n        var task = pipeline.currentTask;\n        if (task) {\n            var agentStubMap = task.agentStubMap;\n            if (agentStubMap) {\n                task = agentStubMap.get(seriesModel.uid);\n            }\n        }\n        return task;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar Component = function () {\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.uid = getUID('viewComponent');\n};\n\nComponent.prototype = {\n\n    constructor: Component,\n\n    init: function (ecModel, api) {},\n\n    render: function (componentModel, ecModel, api, payload) {},\n\n    dispose: function () {},\n\n    /**\n     * @param {string} eventType\n     * @param {Object} query\n     * @param {module:zrender/Element} targetEl\n     * @param {Object} packedEvent\n     * @return {boolen} Pass only when return `true`.\n     */\n    filterForExposedEvent: null\n\n};\n\nvar componentProto = Component.prototype;\ncomponentProto.updateView\n    = componentProto.updateLayout\n    = componentProto.updateVisual\n    = function (seriesModel, ecModel, api, payload) {\n        // Do nothing;\n    };\n// Enable Component.extend.\nenableClassExtend(Component);\n\n// Enable capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(Component, {registerWhenExtend: true});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @return {string} If large mode changed, return string 'reset';\n */\nvar createRenderPlanner = function () {\n    var inner = makeInner();\n\n    return function (seriesModel) {\n        var fields = inner(seriesModel);\n        var pipelineContext = seriesModel.pipelineContext;\n\n        var originalLarge = fields.large;\n        var originalProgressive = fields.progressiveRender;\n\n        var large = fields.large = pipelineContext.large;\n        var progressive = fields.progressiveRender = pipelineContext.progressiveRender;\n\n        return !!((originalLarge ^ large) || (originalProgressive ^ progressive)) && 'reset';\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$5 = makeInner();\nvar renderPlanner = createRenderPlanner();\n\nfunction Chart() {\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.uid = getUID('viewChart');\n\n    this.renderTask = createTask({\n        plan: renderTaskPlan,\n        reset: renderTaskReset\n    });\n    this.renderTask.context = {view: this};\n}\n\nChart.prototype = {\n\n    type: 'chart',\n\n    /**\n     * Init the chart.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    init: function (ecModel, api) {},\n\n    /**\n     * Render the chart.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    render: function (seriesModel, ecModel, api, payload) {},\n\n    /**\n     * Highlight series or specified data item.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    highlight: function (seriesModel, ecModel, api, payload) {\n        toggleHighlight(seriesModel.getData(), payload, 'emphasis');\n    },\n\n    /**\n     * Downplay series or specified data item.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    downplay: function (seriesModel, ecModel, api, payload) {\n        toggleHighlight(seriesModel.getData(), payload, 'normal');\n    },\n\n    /**\n     * Remove self.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    remove: function (ecModel, api) {\n        this.group.removeAll();\n    },\n\n    /**\n     * Dispose self.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    dispose: function () {},\n\n    /**\n     * Rendering preparation in progressive mode.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    incrementalPrepareRender: null,\n\n    /**\n     * Render in progressive mode.\n     * @param  {Object} params See taskParams in `stream/task.js`\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    incrementalRender: null,\n\n    /**\n     * Update transform directly.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     * @return {Object} {update: true}\n     */\n    updateTransform: null,\n\n    /**\n     * The view contains the given point.\n     * @interface\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    // containPoint: function () {}\n\n    /**\n     * @param {string} eventType\n     * @param {Object} query\n     * @param {module:zrender/Element} targetEl\n     * @param {Object} packedEvent\n     * @return {boolen} Pass only when return `true`.\n     */\n    filterForExposedEvent: null\n\n};\n\nvar chartProto = Chart.prototype;\nchartProto.updateView\n    = chartProto.updateLayout\n    = chartProto.updateVisual\n    = function (seriesModel, ecModel, api, payload) {\n        this.render(seriesModel, ecModel, api, payload);\n    };\n\n/**\n * Set state of single element\n * @param  {module:zrender/Element} el\n * @param  {string} state\n */\nfunction elSetState(el, state) {\n    if (el) {\n        el.trigger(state);\n        if (el.type === 'group') {\n            for (var i = 0; i < el.childCount(); i++) {\n                elSetState(el.childAt(i), state);\n            }\n        }\n    }\n}\n/**\n * @param  {module:echarts/data/List} data\n * @param  {Object} payload\n * @param  {string} state 'normal'|'emphasis'\n */\nfunction toggleHighlight(data, payload, state) {\n    var dataIndex = queryDataIndex(data, payload);\n\n    if (dataIndex != null) {\n        each$1(normalizeToArray(dataIndex), function (dataIdx) {\n            elSetState(data.getItemGraphicEl(dataIdx), state);\n        });\n    }\n    else {\n        data.eachItemGraphicEl(function (el) {\n            elSetState(el, state);\n        });\n    }\n}\n\n// Enable Chart.extend.\nenableClassExtend(Chart, ['dispose']);\n\n// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(Chart, {registerWhenExtend: true});\n\nChart.markUpdateMethod = function (payload, methodName) {\n    inner$5(payload).updateMethod = methodName;\n};\n\nfunction renderTaskPlan(context) {\n    return renderPlanner(context.model);\n}\n\nfunction renderTaskReset(context) {\n    var seriesModel = context.model;\n    var ecModel = context.ecModel;\n    var api = context.api;\n    var payload = context.payload;\n    // ???! remove updateView updateVisual\n    var progressiveRender = seriesModel.pipelineContext.progressiveRender;\n    var view = context.view;\n\n    var updateMethod = payload && inner$5(payload).updateMethod;\n    var methodName = progressiveRender\n        ? 'incrementalPrepareRender'\n        : (updateMethod && view[updateMethod])\n        ? updateMethod\n        // `appendData` is also supported when data amount\n        // is less than progressive threshold.\n        : 'render';\n\n    if (methodName !== 'render') {\n        view[methodName](seriesModel, ecModel, api, payload);\n    }\n\n    return progressMethodMap[methodName];\n}\n\nvar progressMethodMap = {\n    incrementalPrepareRender: {\n        progress: function (params, context) {\n            context.view.incrementalRender(\n                params, context.model, context.ecModel, context.api, context.payload\n            );\n        }\n    },\n    render: {\n        // Put view.render in `progress` to support appendData. But in this case\n        // view.render should not be called in reset, otherwise it will be called\n        // twise. Use `forceFirstProgress` to make sure that view.render is called\n        // in any cases.\n        forceFirstProgress: true,\n        progress: function (params, context) {\n            context.view.render(\n                context.model, context.ecModel, context.api, context.payload\n            );\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * @public\n * @param {(Function)} fn\n * @param {number} [delay=0] Unit: ms.\n * @param {boolean} [debounce=false]\n *        true: If call interval less than `delay`, only the last call works.\n *        false: If call interval less than `delay, call works on fixed rate.\n * @return {(Function)} throttled fn.\n */\nfunction throttle(fn, delay, debounce) {\n\n    var currCall;\n    var lastCall = 0;\n    var lastExec = 0;\n    var timer = null;\n    var diff;\n    var scope;\n    var args;\n    var debounceNextCall;\n\n    delay = delay || 0;\n\n    function exec() {\n        lastExec = (new Date()).getTime();\n        timer = null;\n        fn.apply(scope, args || []);\n    }\n\n    var cb = function () {\n        currCall = (new Date()).getTime();\n        scope = this;\n        args = arguments;\n        var thisDelay = debounceNextCall || delay;\n        var thisDebounce = debounceNextCall || debounce;\n        debounceNextCall = null;\n        diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay;\n\n        clearTimeout(timer);\n\n        // Here we should make sure that: the `exec` SHOULD NOT be called later\n        // than a new call of `cb`, that is, preserving the command order. Consider\n        // calculating \"scale rate\" when roaming as an example. When a call of `cb`\n        // happens, either the `exec` is called dierectly, or the call is delayed.\n        // But the delayed call should never be later than next call of `cb`. Under\n        // this assurance, we can simply update view state each time `dispatchAction`\n        // triggered by user roaming, but not need to add extra code to avoid the\n        // state being \"rolled-back\".\n        if (thisDebounce) {\n            timer = setTimeout(exec, thisDelay);\n        }\n        else {\n            if (diff >= 0) {\n                exec();\n            }\n            else {\n                timer = setTimeout(exec, -diff);\n            }\n        }\n\n        lastCall = currCall;\n    };\n\n    /**\n     * Clear throttle.\n     * @public\n     */\n    cb.clear = function () {\n        if (timer) {\n            clearTimeout(timer);\n            timer = null;\n        }\n    };\n\n    /**\n     * Enable debounce once.\n     */\n    cb.debounceNextCall = function (debounceDelay) {\n        debounceNextCall = debounceDelay;\n    };\n\n    return cb;\n}\n\n/**\n * Create throttle method or update throttle rate.\n *\n * @example\n * ComponentView.prototype.render = function () {\n *     ...\n *     throttle.createOrUpdate(\n *         this,\n *         '_dispatchAction',\n *         this.model.get('throttle'),\n *         'fixRate'\n *     );\n * };\n * ComponentView.prototype.remove = function () {\n *     throttle.clear(this, '_dispatchAction');\n * };\n * ComponentView.prototype.dispose = function () {\n *     throttle.clear(this, '_dispatchAction');\n * };\n *\n * @public\n * @param {Object} obj\n * @param {string} fnAttr\n * @param {number} [rate]\n * @param {string} [throttleType='fixRate'] 'fixRate' or 'debounce'\n * @return {Function} throttled function.\n */\n\n\n/**\n * Clear throttle. Example see throttle.createOrUpdate.\n *\n * @public\n * @param {Object} obj\n * @param {string} fnAttr\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar seriesColor = {\n    createOnAllSeries: true,\n    performRawSeries: true,\n    reset: function (seriesModel, ecModel) {\n        var data = seriesModel.getData();\n        var colorAccessPath = (seriesModel.visualColorAccessPath || 'itemStyle.color').split('.');\n        var color = seriesModel.get(colorAccessPath) // Set in itemStyle\n            || seriesModel.getColorFromPalette(\n                // TODO series count changed.\n                seriesModel.name, null, ecModel.getSeriesCount()\n            );  // Default color\n\n        // FIXME Set color function or use the platte color\n        data.setVisual('color', color);\n\n        // Only visible series has each data be visual encoded\n        if (!ecModel.isSeriesFiltered(seriesModel)) {\n            if (typeof color === 'function' && !(color instanceof Gradient)) {\n                data.each(function (idx) {\n                    data.setItemVisual(\n                        idx, 'color', color(seriesModel.getDataParams(idx))\n                    );\n                });\n            }\n\n            // itemStyle in each data item\n            var dataEach = function (data, idx) {\n                var itemModel = data.getItemModel(idx);\n                var color = itemModel.get(colorAccessPath, true);\n                if (color != null) {\n                    data.setItemVisual(idx, 'color', color);\n                }\n            };\n\n            return { dataEach: data.hasItemOption ? dataEach : null };\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar lang = {\n    toolbox: {\n        brush: {\n            title: {\n                rect: 'Box Select',\n                polygon: 'Lasso Select',\n                lineX: 'Horizontally Select',\n                lineY: 'Vertically Select',\n                keep: 'Keep Selections',\n                clear: 'Clear Selections'\n            }\n        },\n        dataView: {\n            title: 'Data View',\n            lang: ['Data View', 'Close', 'Refresh']\n        },\n        dataZoom: {\n            title: {\n                zoom: 'Zoom',\n                back: 'Zoom Reset'\n            }\n        },\n        magicType: {\n            title: {\n                line: 'Switch to Line Chart',\n                bar: 'Switch to Bar Chart',\n                stack: 'Stack',\n                tiled: 'Tile'\n            }\n        },\n        restore: {\n            title: 'Restore'\n        },\n        saveAsImage: {\n            title: 'Save as Image',\n            lang: ['Right Click to Save Image']\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar aria = function (dom, ecModel) {\n    var ariaModel = ecModel.getModel('aria');\n    if (!ariaModel.get('show')) {\n        return;\n    }\n    else if (ariaModel.get('description')) {\n        dom.setAttribute('aria-label', ariaModel.get('description'));\n        return;\n    }\n\n    var seriesCnt = 0;\n    ecModel.eachSeries(function (seriesModel, idx) {\n        ++seriesCnt;\n    }, this);\n\n    var maxDataCnt = ariaModel.get('data.maxCount') || 10;\n    var maxSeriesCnt = ariaModel.get('series.maxCount') || 10;\n    var displaySeriesCnt = Math.min(seriesCnt, maxSeriesCnt);\n\n    var ariaLabel;\n    if (seriesCnt < 1) {\n        // No series, no aria label\n        return;\n    }\n    else {\n        var title = getTitle();\n        if (title) {\n            ariaLabel = replace(getConfig('general.withTitle'), {\n                title: title\n            });\n        }\n        else {\n            ariaLabel = getConfig('general.withoutTitle');\n        }\n\n        var seriesLabels = [];\n        var prefix = seriesCnt > 1\n            ? 'series.multiple.prefix'\n            : 'series.single.prefix';\n        ariaLabel += replace(getConfig(prefix), { seriesCount: seriesCnt });\n\n        ecModel.eachSeries(function (seriesModel, idx) {\n            if (idx < displaySeriesCnt) {\n                var seriesLabel;\n\n                var seriesName = seriesModel.get('name');\n                var seriesTpl = 'series.'\n                    + (seriesCnt > 1 ? 'multiple' : 'single') + '.';\n                seriesLabel = getConfig(seriesName\n                    ? seriesTpl + 'withName'\n                    : seriesTpl + 'withoutName');\n\n                seriesLabel = replace(seriesLabel, {\n                    seriesId: seriesModel.seriesIndex,\n                    seriesName: seriesModel.get('name'),\n                    seriesType: getSeriesTypeName(seriesModel.subType)\n                });\n\n                var data = seriesModel.getData();\n                window.data = data;\n                if (data.count() > maxDataCnt) {\n                    // Show part of data\n                    seriesLabel += replace(getConfig('data.partialData'), {\n                        displayCnt: maxDataCnt\n                    });\n                }\n                else {\n                    seriesLabel += getConfig('data.allData');\n                }\n\n                var dataLabels = [];\n                for (var i = 0; i < data.count(); i++) {\n                    if (i < maxDataCnt) {\n                        var name = data.getName(i);\n                        var value = retrieveRawValue(data, i);\n                        dataLabels.push(\n                            replace(\n                                name\n                                    ? getConfig('data.withName')\n                                    : getConfig('data.withoutName'),\n                                {\n                                    name: name,\n                                    value: value\n                                }\n                            )\n                        );\n                    }\n                }\n                seriesLabel += dataLabels\n                    .join(getConfig('data.separator.middle'))\n                    + getConfig('data.separator.end');\n\n                seriesLabels.push(seriesLabel);\n            }\n        });\n\n        ariaLabel += seriesLabels\n            .join(getConfig('series.multiple.separator.middle'))\n            + getConfig('series.multiple.separator.end');\n\n        dom.setAttribute('aria-label', ariaLabel);\n    }\n\n    function replace(str, keyValues) {\n        if (typeof str !== 'string') {\n            return str;\n        }\n\n        var result = str;\n        each$1(keyValues, function (value, key) {\n            result = result.replace(\n                new RegExp('\\\\{\\\\s*' + key + '\\\\s*\\\\}', 'g'),\n                value\n            );\n        });\n        return result;\n    }\n\n    function getConfig(path) {\n        var userConfig = ariaModel.get(path);\n        if (userConfig == null) {\n            var pathArr = path.split('.');\n            var result = lang.aria;\n            for (var i = 0; i < pathArr.length; ++i) {\n                result = result[pathArr[i]];\n            }\n            return result;\n        }\n        else {\n            return userConfig;\n        }\n    }\n\n    function getTitle() {\n        var title = ecModel.getModel('title').option;\n        if (title && title.length) {\n            title = title[0];\n        }\n        return title && title.text;\n    }\n\n    function getSeriesTypeName(type) {\n        return lang.series.typeNames[type] || '自定义图';\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PI$1 = Math.PI;\n\n/**\n * @param {module:echarts/ExtensionAPI} api\n * @param {Object} [opts]\n * @param {string} [opts.text]\n * @param {string} [opts.color]\n * @param {string} [opts.textColor]\n * @return {module:zrender/Element}\n */\nvar loadingDefault = function (api, opts) {\n    opts = opts || {};\n    defaults(opts, {\n        text: 'loading',\n        color: '#c23531',\n        textColor: '#000',\n        maskColor: 'rgba(255, 255, 255, 0.8)',\n        zlevel: 0\n    });\n    var mask = new Rect({\n        style: {\n            fill: opts.maskColor\n        },\n        zlevel: opts.zlevel,\n        z: 10000\n    });\n    var arc = new Arc({\n        shape: {\n            startAngle: -PI$1 / 2,\n            endAngle: -PI$1 / 2 + 0.1,\n            r: 10\n        },\n        style: {\n            stroke: opts.color,\n            lineCap: 'round',\n            lineWidth: 5\n        },\n        zlevel: opts.zlevel,\n        z: 10001\n    });\n    var labelRect = new Rect({\n        style: {\n            fill: 'none',\n            text: opts.text,\n            textPosition: 'right',\n            textDistance: 10,\n            textFill: opts.textColor\n        },\n        zlevel: opts.zlevel,\n        z: 10001\n    });\n\n    arc.animateShape(true)\n        .when(1000, {\n            endAngle: PI$1 * 3 / 2\n        })\n        .start('circularInOut');\n    arc.animateShape(true)\n        .when(1000, {\n            startAngle: PI$1 * 3 / 2\n        })\n        .delay(300)\n        .start('circularInOut');\n\n    var group = new Group();\n    group.add(arc);\n    group.add(labelRect);\n    group.add(mask);\n    // Inject resize\n    group.resize = function () {\n        var cx = api.getWidth() / 2;\n        var cy = api.getHeight() / 2;\n        arc.setShape({\n            cx: cx,\n            cy: cy\n        });\n        var r = arc.shape.r;\n        labelRect.setShape({\n            x: cx - r,\n            y: cy - r,\n            width: r * 2,\n            height: r * 2\n        });\n\n        mask.setShape({\n            x: 0,\n            y: 0,\n            width: api.getWidth(),\n            height: api.getHeight()\n        });\n    };\n    group.resize();\n    return group;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/stream/Scheduler\n */\n\n/**\n * @constructor\n */\nfunction Scheduler(ecInstance, api, dataProcessorHandlers, visualHandlers) {\n    this.ecInstance = ecInstance;\n    this.api = api;\n    this.unfinished;\n\n    // Fix current processors in case that in some rear cases that\n    // processors might be registered after echarts instance created.\n    // Register processors incrementally for a echarts instance is\n    // not supported by this stream architecture.\n    var dataProcessorHandlers = this._dataProcessorHandlers = dataProcessorHandlers.slice();\n    var visualHandlers = this._visualHandlers = visualHandlers.slice();\n    this._allHandlers = dataProcessorHandlers.concat(visualHandlers);\n\n    /**\n     * @private\n     * @type {\n     *     [handlerUID: string]: {\n     *         seriesTaskMap?: {\n     *             [seriesUID: string]: Task\n     *         },\n     *         overallTask?: Task\n     *     }\n     * }\n     */\n    this._stageTaskMap = createHashMap();\n}\n\nvar proto = Scheduler.prototype;\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} payload\n */\nproto.restoreData = function (ecModel, payload) {\n    // TODO: Only restroe needed series and components, but not all components.\n    // Currently `restoreData` of all of the series and component will be called.\n    // But some independent components like `title`, `legend`, `graphic`, `toolbox`,\n    // `tooltip`, `axisPointer`, etc, do not need series refresh when `setOption`,\n    // and some components like coordinate system, axes, dataZoom, visualMap only\n    // need their target series refresh.\n    // (1) If we are implementing this feature some day, we should consider these cases:\n    // if a data processor depends on a component (e.g., dataZoomProcessor depends\n    // on the settings of `dataZoom`), it should be re-performed if the component\n    // is modified by `setOption`.\n    // (2) If a processor depends on sevral series, speicified by its `getTargetSeries`,\n    // it should be re-performed when the result array of `getTargetSeries` changed.\n    // We use `dependencies` to cover these issues.\n    // (3) How to update target series when coordinate system related components modified.\n\n    // TODO: simply the dirty mechanism? Check whether only the case here can set tasks dirty,\n    // and this case all of the tasks will be set as dirty.\n\n    ecModel.restoreData(payload);\n\n    // Theoretically an overall task not only depends on each of its target series, but also\n    // depends on all of the series.\n    // The overall task is not in pipeline, and `ecModel.restoreData` only set pipeline tasks\n    // dirty. If `getTargetSeries` of an overall task returns nothing, we should also ensure\n    // that the overall task is set as dirty and to be performed, otherwise it probably cause\n    // state chaos. So we have to set dirty of all of the overall tasks manually, otherwise it\n    // probably cause state chaos (consider `dataZoomProcessor`).\n    this._stageTaskMap.each(function (taskRecord) {\n        var overallTask = taskRecord.overallTask;\n        overallTask && overallTask.dirty();\n    });\n};\n\n// If seriesModel provided, incremental threshold is check by series data.\nproto.getPerformArgs = function (task, isBlock) {\n    // For overall task\n    if (!task.__pipeline) {\n        return;\n    }\n\n    var pipeline = this._pipelineMap.get(task.__pipeline.id);\n    var pCtx = pipeline.context;\n    var incremental = !isBlock\n        && pipeline.progressiveEnabled\n        && (!pCtx || pCtx.progressiveRender)\n        && task.__idxInPipeline > pipeline.blockIndex;\n\n    var step = incremental ? pipeline.step : null;\n    var modDataCount = pCtx && pCtx.modDataCount;\n    var modBy = modDataCount != null ? Math.ceil(modDataCount / step) : null;\n\n    return {step: step, modBy: modBy, modDataCount: modDataCount};\n};\n\nproto.getPipeline = function (pipelineId) {\n    return this._pipelineMap.get(pipelineId);\n};\n\n/**\n * Current, progressive rendering starts from visual and layout.\n * Always detect render mode in the same stage, avoiding that incorrect\n * detection caused by data filtering.\n * Caution:\n * `updateStreamModes` use `seriesModel.getData()`.\n */\nproto.updateStreamModes = function (seriesModel, view) {\n    var pipeline = this._pipelineMap.get(seriesModel.uid);\n    var data = seriesModel.getData();\n    var dataLen = data.count();\n\n    // `progressiveRender` means that can render progressively in each\n    // animation frame. Note that some types of series do not provide\n    // `view.incrementalPrepareRender` but support `chart.appendData`. We\n    // use the term `incremental` but not `progressive` to describe the\n    // case that `chart.appendData`.\n    var progressiveRender = pipeline.progressiveEnabled\n        && view.incrementalPrepareRender\n        && dataLen >= pipeline.threshold;\n\n    var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold');\n\n    // TODO: modDataCount should not updated if `appendData`, otherwise cause whole repaint.\n    // see `test/candlestick-large3.html`\n    var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null;\n\n    seriesModel.pipelineContext = pipeline.context = {\n        progressiveRender: progressiveRender,\n        modDataCount: modDataCount,\n        large: large\n    };\n};\n\nproto.restorePipelines = function (ecModel) {\n    var scheduler = this;\n    var pipelineMap = scheduler._pipelineMap = createHashMap();\n\n    ecModel.eachSeries(function (seriesModel) {\n        var progressive = seriesModel.getProgressive();\n        var pipelineId = seriesModel.uid;\n\n        pipelineMap.set(pipelineId, {\n            id: pipelineId,\n            head: null,\n            tail: null,\n            threshold: seriesModel.getProgressiveThreshold(),\n            progressiveEnabled: progressive\n                && !(seriesModel.preventIncremental && seriesModel.preventIncremental()),\n            blockIndex: -1,\n            step: Math.round(progressive || 700),\n            count: 0\n        });\n\n        pipe(scheduler, seriesModel, seriesModel.dataTask);\n    });\n};\n\nproto.prepareStageTasks = function () {\n    var stageTaskMap = this._stageTaskMap;\n    var ecModel = this.ecInstance.getModel();\n    var api = this.api;\n\n    each$1(this._allHandlers, function (handler) {\n        var record = stageTaskMap.get(handler.uid) || stageTaskMap.set(handler.uid, []);\n\n        handler.reset && createSeriesStageTask(this, handler, record, ecModel, api);\n        handler.overallReset && createOverallStageTask(this, handler, record, ecModel, api);\n    }, this);\n};\n\nproto.prepareView = function (view, model, ecModel, api) {\n    var renderTask = view.renderTask;\n    var context = renderTask.context;\n\n    context.model = model;\n    context.ecModel = ecModel;\n    context.api = api;\n\n    renderTask.__block = !view.incrementalPrepareRender;\n\n    pipe(this, model, renderTask);\n};\n\n\nproto.performDataProcessorTasks = function (ecModel, payload) {\n    // If we do not use `block` here, it should be considered when to update modes.\n    performStageTasks(this, this._dataProcessorHandlers, ecModel, payload, {block: true});\n};\n\n// opt\n// opt.visualType: 'visual' or 'layout'\n// opt.setDirty\nproto.performVisualTasks = function (ecModel, payload, opt) {\n    performStageTasks(this, this._visualHandlers, ecModel, payload, opt);\n};\n\nfunction performStageTasks(scheduler, stageHandlers, ecModel, payload, opt) {\n    opt = opt || {};\n    var unfinished;\n\n    each$1(stageHandlers, function (stageHandler, idx) {\n        if (opt.visualType && opt.visualType !== stageHandler.visualType) {\n            return;\n        }\n\n        var stageHandlerRecord = scheduler._stageTaskMap.get(stageHandler.uid);\n        var seriesTaskMap = stageHandlerRecord.seriesTaskMap;\n        var overallTask = stageHandlerRecord.overallTask;\n\n        if (overallTask) {\n            var overallNeedDirty;\n            var agentStubMap = overallTask.agentStubMap;\n            agentStubMap.each(function (stub) {\n                if (needSetDirty(opt, stub)) {\n                    stub.dirty();\n                    overallNeedDirty = true;\n                }\n            });\n            overallNeedDirty && overallTask.dirty();\n            updatePayload(overallTask, payload);\n            var performArgs = scheduler.getPerformArgs(overallTask, opt.block);\n            // Execute stubs firstly, which may set the overall task dirty,\n            // then execute the overall task. And stub will call seriesModel.setData,\n            // which ensures that in the overallTask seriesModel.getData() will not\n            // return incorrect data.\n            agentStubMap.each(function (stub) {\n                stub.perform(performArgs);\n            });\n            unfinished |= overallTask.perform(performArgs);\n        }\n        else if (seriesTaskMap) {\n            seriesTaskMap.each(function (task, pipelineId) {\n                if (needSetDirty(opt, task)) {\n                    task.dirty();\n                }\n                var performArgs = scheduler.getPerformArgs(task, opt.block);\n                performArgs.skip = !stageHandler.performRawSeries\n                    && ecModel.isSeriesFiltered(task.context.model);\n                updatePayload(task, payload);\n                unfinished |= task.perform(performArgs);\n            });\n        }\n    });\n\n    function needSetDirty(opt, task) {\n        return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id));\n    }\n\n    scheduler.unfinished |= unfinished;\n}\n\nproto.performSeriesTasks = function (ecModel) {\n    var unfinished;\n\n    ecModel.eachSeries(function (seriesModel) {\n        // Progress to the end for dataInit and dataRestore.\n        unfinished |= seriesModel.dataTask.perform();\n    });\n\n    this.unfinished |= unfinished;\n};\n\nproto.plan = function () {\n    // Travel pipelines, check block.\n    this._pipelineMap.each(function (pipeline) {\n        var task = pipeline.tail;\n        do {\n            if (task.__block) {\n                pipeline.blockIndex = task.__idxInPipeline;\n                break;\n            }\n            task = task.getUpstream();\n        }\n        while (task);\n    });\n};\n\nvar updatePayload = proto.updatePayload = function (task, payload) {\n    payload !== 'remain' && (task.context.payload = payload);\n};\n\nfunction createSeriesStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) {\n    var seriesTaskMap = stageHandlerRecord.seriesTaskMap\n        || (stageHandlerRecord.seriesTaskMap = createHashMap());\n    var seriesType = stageHandler.seriesType;\n    var getTargetSeries = stageHandler.getTargetSeries;\n\n    // If a stageHandler should cover all series, `createOnAllSeries` should be declared mandatorily,\n    // to avoid some typo or abuse. Otherwise if an extension do not specify a `seriesType`,\n    // it works but it may cause other irrelevant charts blocked.\n    if (stageHandler.createOnAllSeries) {\n        ecModel.eachRawSeries(create);\n    }\n    else if (seriesType) {\n        ecModel.eachRawSeriesByType(seriesType, create);\n    }\n    else if (getTargetSeries) {\n        getTargetSeries(ecModel, api).each(create);\n    }\n\n    function create(seriesModel) {\n        var pipelineId = seriesModel.uid;\n\n        // Init tasks for each seriesModel only once.\n        // Reuse original task instance.\n        var task = seriesTaskMap.get(pipelineId)\n            || seriesTaskMap.set(pipelineId, createTask({\n                plan: seriesTaskPlan,\n                reset: seriesTaskReset,\n                count: seriesTaskCount\n            }));\n        task.context = {\n            model: seriesModel,\n            ecModel: ecModel,\n            api: api,\n            useClearVisual: stageHandler.isVisual && !stageHandler.isLayout,\n            plan: stageHandler.plan,\n            reset: stageHandler.reset,\n            scheduler: scheduler\n        };\n        pipe(scheduler, seriesModel, task);\n    }\n\n    // Clear unused series tasks.\n    var pipelineMap = scheduler._pipelineMap;\n    seriesTaskMap.each(function (task, pipelineId) {\n        if (!pipelineMap.get(pipelineId)) {\n            task.dispose();\n            seriesTaskMap.removeKey(pipelineId);\n        }\n    });\n}\n\nfunction createOverallStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) {\n    var overallTask = stageHandlerRecord.overallTask = stageHandlerRecord.overallTask\n        // For overall task, the function only be called on reset stage.\n        || createTask({reset: overallTaskReset});\n\n    overallTask.context = {\n        ecModel: ecModel,\n        api: api,\n        overallReset: stageHandler.overallReset,\n        scheduler: scheduler\n    };\n\n    // Reuse orignal stubs.\n    var agentStubMap = overallTask.agentStubMap = overallTask.agentStubMap || createHashMap();\n\n    var seriesType = stageHandler.seriesType;\n    var getTargetSeries = stageHandler.getTargetSeries;\n    var overallProgress = true;\n    var modifyOutputEnd = stageHandler.modifyOutputEnd;\n\n    // An overall task with seriesType detected or has `getTargetSeries`, we add\n    // stub in each pipelines, it will set the overall task dirty when the pipeline\n    // progress. Moreover, to avoid call the overall task each frame (too frequent),\n    // we set the pipeline block.\n    if (seriesType) {\n        ecModel.eachRawSeriesByType(seriesType, createStub);\n    }\n    else if (getTargetSeries) {\n        getTargetSeries(ecModel, api).each(createStub);\n    }\n    // Otherwise, (usually it is legancy case), the overall task will only be\n    // executed when upstream dirty. Otherwise the progressive rendering of all\n    // pipelines will be disabled unexpectedly. But it still needs stubs to receive\n    // dirty info from upsteam.\n    else {\n        overallProgress = false;\n        each$1(ecModel.getSeries(), createStub);\n    }\n\n    function createStub(seriesModel) {\n        var pipelineId = seriesModel.uid;\n        var stub = agentStubMap.get(pipelineId);\n        if (!stub) {\n            stub = agentStubMap.set(pipelineId, createTask(\n                {reset: stubReset, onDirty: stubOnDirty}\n            ));\n            // When the result of `getTargetSeries` changed, the overallTask\n            // should be set as dirty and re-performed.\n            overallTask.dirty();\n        }\n        stub.context = {\n            model: seriesModel,\n            overallProgress: overallProgress,\n            modifyOutputEnd: modifyOutputEnd\n        };\n        stub.agent = overallTask;\n        stub.__block = overallProgress;\n\n        pipe(scheduler, seriesModel, stub);\n    }\n\n    // Clear unused stubs.\n    var pipelineMap = scheduler._pipelineMap;\n    agentStubMap.each(function (stub, pipelineId) {\n        if (!pipelineMap.get(pipelineId)) {\n            stub.dispose();\n            // When the result of `getTargetSeries` changed, the overallTask\n            // should be set as dirty and re-performed.\n            overallTask.dirty();\n            agentStubMap.removeKey(pipelineId);\n        }\n    });\n}\n\nfunction overallTaskReset(context) {\n    context.overallReset(\n        context.ecModel, context.api, context.payload\n    );\n}\n\nfunction stubReset(context, upstreamContext) {\n    return context.overallProgress && stubProgress;\n}\n\nfunction stubProgress() {\n    this.agent.dirty();\n    this.getDownstream().dirty();\n}\n\nfunction stubOnDirty() {\n    this.agent && this.agent.dirty();\n}\n\nfunction seriesTaskPlan(context) {\n    return context.plan && context.plan(\n        context.model, context.ecModel, context.api, context.payload\n    );\n}\n\nfunction seriesTaskReset(context) {\n    if (context.useClearVisual) {\n        context.data.clearAllVisual();\n    }\n    var resetDefines = context.resetDefines = normalizeToArray(context.reset(\n        context.model, context.ecModel, context.api, context.payload\n    ));\n    return resetDefines.length > 1\n        ? map(resetDefines, function (v, idx) {\n            return makeSeriesTaskProgress(idx);\n        })\n        : singleSeriesTaskProgress;\n}\n\nvar singleSeriesTaskProgress = makeSeriesTaskProgress(0);\n\nfunction makeSeriesTaskProgress(resetDefineIdx) {\n    return function (params, context) {\n        var data = context.data;\n        var resetDefine = context.resetDefines[resetDefineIdx];\n\n        if (resetDefine && resetDefine.dataEach) {\n            for (var i = params.start; i < params.end; i++) {\n                resetDefine.dataEach(data, i);\n            }\n        }\n        else if (resetDefine && resetDefine.progress) {\n            resetDefine.progress(params, data);\n        }\n    };\n}\n\nfunction seriesTaskCount(context) {\n    return context.data.count();\n}\n\nfunction pipe(scheduler, seriesModel, task) {\n    var pipelineId = seriesModel.uid;\n    var pipeline = scheduler._pipelineMap.get(pipelineId);\n    !pipeline.head && (pipeline.head = task);\n    pipeline.tail && pipeline.tail.pipe(task);\n    pipeline.tail = task;\n    task.__idxInPipeline = pipeline.count++;\n    task.__pipeline = pipeline;\n}\n\nScheduler.wrapStageHandler = function (stageHandler, visualType) {\n    if (isFunction$1(stageHandler)) {\n        stageHandler = {\n            overallReset: stageHandler,\n            seriesType: detectSeriseType(stageHandler)\n        };\n    }\n\n    stageHandler.uid = getUID('stageHandler');\n    visualType && (stageHandler.visualType = visualType);\n\n    return stageHandler;\n};\n\n\n\n/**\n * Only some legacy stage handlers (usually in echarts extensions) are pure function.\n * To ensure that they can work normally, they should work in block mode, that is,\n * they should not be started util the previous tasks finished. So they cause the\n * progressive rendering disabled. We try to detect the series type, to narrow down\n * the block range to only the series type they concern, but not all series.\n */\nfunction detectSeriseType(legacyFunc) {\n    seriesType = null;\n    try {\n        // Assume there is no async when calling `eachSeriesByType`.\n        legacyFunc(ecModelMock, apiMock);\n    }\n    catch (e) {\n    }\n    return seriesType;\n}\n\nvar ecModelMock = {};\nvar apiMock = {};\nvar seriesType;\n\nmockMethods(ecModelMock, GlobalModel);\nmockMethods(apiMock, ExtensionAPI);\necModelMock.eachSeriesByType = ecModelMock.eachRawSeriesByType = function (type) {\n    seriesType = type;\n};\necModelMock.eachComponent = function (cond) {\n    if (cond.mainType === 'series' && cond.subType) {\n        seriesType = cond.subType;\n    }\n};\n\nfunction mockMethods(target, Clz) {\n    /* eslint-disable */\n    for (var name in Clz.prototype) {\n        // Do not use hasOwnProperty\n        target[name] = noop;\n    }\n    /* eslint-enable */\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar colorAll = [\n    '#37A2DA', '#32C5E9', '#67E0E3', '#9FE6B8', '#FFDB5C', '#ff9f7f',\n    '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF'\n];\n\nvar lightTheme = {\n\n    color: colorAll,\n\n    colorLayer: [\n        ['#37A2DA', '#ffd85c', '#fd7b5f'],\n        ['#37A2DA', '#67E0E3', '#FFDB5C', '#ff9f7f', '#E062AE', '#9d96f5'],\n        ['#37A2DA', '#32C5E9', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#e7bcf3', '#8378EA', '#96BFFF'],\n        colorAll\n    ]\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar contrastColor = '#eee';\nvar axisCommon = function () {\n    return {\n        axisLine: {\n            lineStyle: {\n                color: contrastColor\n            }\n        },\n        axisTick: {\n            lineStyle: {\n                color: contrastColor\n            }\n        },\n        axisLabel: {\n            textStyle: {\n                color: contrastColor\n            }\n        },\n        splitLine: {\n            lineStyle: {\n                type: 'dashed',\n                color: '#aaa'\n            }\n        },\n        splitArea: {\n            areaStyle: {\n                color: contrastColor\n            }\n        }\n    };\n};\n\nvar colorPalette = [\n    '#dd6b66', '#759aa0', '#e69d87', '#8dc1a9', '#ea7e53',\n    '#eedd78', '#73a373', '#73b9bc', '#7289ab', '#91ca8c', '#f49f42'\n];\nvar theme = {\n    color: colorPalette,\n    backgroundColor: '#333',\n    tooltip: {\n        axisPointer: {\n            lineStyle: {\n                color: contrastColor\n            },\n            crossStyle: {\n                color: contrastColor\n            }\n        }\n    },\n    legend: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    textStyle: {\n        color: contrastColor\n    },\n    title: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    toolbox: {\n        iconStyle: {\n            normal: {\n                borderColor: contrastColor\n            }\n        }\n    },\n    dataZoom: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    visualMap: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    timeline: {\n        lineStyle: {\n            color: contrastColor\n        },\n        itemStyle: {\n            normal: {\n                color: colorPalette[1]\n            }\n        },\n        label: {\n            normal: {\n                textStyle: {\n                    color: contrastColor\n                }\n            }\n        },\n        controlStyle: {\n            normal: {\n                color: contrastColor,\n                borderColor: contrastColor\n            }\n        }\n    },\n    timeAxis: axisCommon(),\n    logAxis: axisCommon(),\n    valueAxis: axisCommon(),\n    categoryAxis: axisCommon(),\n\n    line: {\n        symbol: 'circle'\n    },\n    graph: {\n        color: colorPalette\n    },\n    gauge: {\n        title: {\n            textStyle: {\n                color: contrastColor\n            }\n        }\n    },\n    candlestick: {\n        itemStyle: {\n            normal: {\n                color: '#FD1050',\n                color0: '#0CF49B',\n                borderColor: '#FD1050',\n                borderColor0: '#0CF49B'\n            }\n        }\n    }\n};\ntheme.categoryAxis.splitLine.show = false;\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * This module is imported by echarts directly.\n *\n * Notice:\n * Always keep this file exists for backward compatibility.\n * Because before 4.1.0, dataset is an optional component,\n * some users may import this module manually.\n */\n\nComponentModel.extend({\n\n    type: 'dataset',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n\n        // 'row', 'column'\n        seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN,\n\n        // null/'auto': auto detect header, see \"module:echarts/data/helper/sourceHelper\"\n        sourceHeader: null,\n\n        dimensions: null,\n\n        source: null\n    },\n\n    optionUpdated: function () {\n        detectSourceFormat(this);\n    }\n\n});\n\nComponent.extend({\n\n    type: 'dataset'\n\n});\n\n/**\n * 椭圆形状\n * @module zrender/graphic/shape/Ellipse\n */\n\nvar Ellipse = Path.extend({\n\n    type: 'ellipse',\n\n    shape: {\n        cx: 0, cy: 0,\n        rx: 0, ry: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var k = 0.5522848;\n        var x = shape.cx;\n        var y = shape.cy;\n        var a = shape.rx;\n        var b = shape.ry;\n        var ox = a * k; // 水平控制点偏移量\n        var oy = b * k; // 垂直控制点偏移量\n        // 从椭圆的左端点开始顺时针绘制四条三次贝塞尔曲线\n        ctx.moveTo(x - a, y);\n        ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b);\n        ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y);\n        ctx.bezierCurveTo(x + a, y + oy, x + ox, y + b, x, y + b);\n        ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y);\n        ctx.closePath();\n    }\n});\n\n// import RadialGradient from '../graphic/RadialGradient';\n// import Pattern from '../graphic/Pattern';\n// import * as vector from '../core/vector';\n// Most of the values can be separated by comma and/or white space.\nvar DILIMITER_REG = /[\\s,]+/;\n\n/**\n * For big svg string, this method might be time consuming.\n *\n * @param {string} svg xml string\n * @return {Object} xml root.\n */\nfunction parseXML(svg) {\n    if (isString(svg)) {\n        var parser = new DOMParser();\n        svg = parser.parseFromString(svg, 'text/xml');\n    }\n\n    // Document node. If using $.get, doc node may be input.\n    if (svg.nodeType === 9) {\n        svg = svg.firstChild;\n    }\n    // nodeName of <!DOCTYPE svg> is also 'svg'.\n    while (svg.nodeName.toLowerCase() !== 'svg' || svg.nodeType !== 1) {\n        svg = svg.nextSibling;\n    }\n\n    return svg;\n}\n\nfunction SVGParser() {\n    this._defs = {};\n    this._root = null;\n\n    this._isDefine = false;\n    this._isText = false;\n}\n\nSVGParser.prototype.parse = function (xml, opt) {\n    opt = opt || {};\n\n    var svg = parseXML(xml);\n\n    if (!svg) {\n        throw new Error('Illegal svg');\n    }\n\n    var root = new Group();\n    this._root = root;\n    // parse view port\n    var viewBox = svg.getAttribute('viewBox') || '';\n\n    // If width/height not specified, means \"100%\" of `opt.width/height`.\n    // TODO: Other percent value not supported yet.\n    var width = parseFloat(svg.getAttribute('width') || opt.width);\n    var height = parseFloat(svg.getAttribute('height') || opt.height);\n    // If width/height not specified, set as null for output.\n    isNaN(width) && (width = null);\n    isNaN(height) && (height = null);\n\n    // Apply inline style on svg element.\n    parseAttributes(svg, root, null, true);\n\n    var child = svg.firstChild;\n    while (child) {\n        this._parseNode(child, root);\n        child = child.nextSibling;\n    }\n\n    var viewBoxRect;\n    var viewBoxTransform;\n\n    if (viewBox) {\n        var viewBoxArr = trim(viewBox).split(DILIMITER_REG);\n        // Some invalid case like viewBox: 'none'.\n        if (viewBoxArr.length >= 4) {\n            viewBoxRect = {\n                x: parseFloat(viewBoxArr[0] || 0),\n                y: parseFloat(viewBoxArr[1] || 0),\n                width: parseFloat(viewBoxArr[2]),\n                height: parseFloat(viewBoxArr[3])\n            };\n        }\n    }\n\n    if (viewBoxRect && width != null && height != null) {\n        viewBoxTransform = makeViewBoxTransform(viewBoxRect, width, height);\n\n        if (!opt.ignoreViewBox) {\n            // If set transform on the output group, it probably bring trouble when\n            // some users only intend to show the clipped content inside the viewBox,\n            // but not intend to transform the output group. So we keep the output\n            // group no transform. If the user intend to use the viewBox as a\n            // camera, just set `opt.ignoreViewBox` as `true` and set transfrom\n            // manually according to the viewBox info in the output of this method.\n            var elRoot = root;\n            root = new Group();\n            root.add(elRoot);\n            elRoot.scale = viewBoxTransform.scale.slice();\n            elRoot.position = viewBoxTransform.position.slice();\n        }\n    }\n\n    // Some shapes might be overflow the viewport, which should be\n    // clipped despite whether the viewBox is used, as the SVG does.\n    if (!opt.ignoreRootClip && width != null && height != null) {\n        root.setClipPath(new Rect({\n            shape: {x: 0, y: 0, width: width, height: height}\n        }));\n    }\n\n    // Set width/height on group just for output the viewport size.\n    return {\n        root: root,\n        width: width,\n        height: height,\n        viewBoxRect: viewBoxRect,\n        viewBoxTransform: viewBoxTransform\n    };\n};\n\nSVGParser.prototype._parseNode = function (xmlNode, parentGroup) {\n\n    var nodeName = xmlNode.nodeName.toLowerCase();\n\n    // TODO\n    // support <style>...</style> in svg, where nodeName is 'style',\n    // CSS classes is defined globally wherever the style tags are declared.\n\n    if (nodeName === 'defs') {\n        // define flag\n        this._isDefine = true;\n    }\n    else if (nodeName === 'text') {\n        this._isText = true;\n    }\n\n    var el;\n    if (this._isDefine) {\n        var parser = defineParsers[nodeName];\n        if (parser) {\n            var def = parser.call(this, xmlNode);\n            var id = xmlNode.getAttribute('id');\n            if (id) {\n                this._defs[id] = def;\n            }\n        }\n    }\n    else {\n        var parser = nodeParsers[nodeName];\n        if (parser) {\n            el = parser.call(this, xmlNode, parentGroup);\n            parentGroup.add(el);\n        }\n    }\n\n    var child = xmlNode.firstChild;\n    while (child) {\n        if (child.nodeType === 1) {\n            this._parseNode(child, el);\n        }\n        // Is text\n        if (child.nodeType === 3 && this._isText) {\n            this._parseText(child, el);\n        }\n        child = child.nextSibling;\n    }\n\n    // Quit define\n    if (nodeName === 'defs') {\n        this._isDefine = false;\n    }\n    else if (nodeName === 'text') {\n        this._isText = false;\n    }\n};\n\nSVGParser.prototype._parseText = function (xmlNode, parentGroup) {\n    if (xmlNode.nodeType === 1) {\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n        this._textX += parseFloat(dx);\n        this._textY += parseFloat(dy);\n    }\n\n    var text = new Text({\n        style: {\n            text: xmlNode.textContent,\n            transformText: true\n        },\n        position: [this._textX || 0, this._textY || 0]\n    });\n\n    inheritStyle(parentGroup, text);\n    parseAttributes(xmlNode, text, this._defs);\n\n    var fontSize = text.style.fontSize;\n    if (fontSize && fontSize < 9) {\n        // PENDING\n        text.style.fontSize = 9;\n        text.scale = text.scale || [1, 1];\n        text.scale[0] *= fontSize / 9;\n        text.scale[1] *= fontSize / 9;\n    }\n\n    var rect = text.getBoundingRect();\n    this._textX += rect.width;\n\n    parentGroup.add(text);\n\n    return text;\n};\n\nvar nodeParsers = {\n    'g': function (xmlNode, parentGroup) {\n        var g = new Group();\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n        return g;\n    },\n    'rect': function (xmlNode, parentGroup) {\n        var rect = new Rect();\n        inheritStyle(parentGroup, rect);\n        parseAttributes(xmlNode, rect, this._defs);\n\n        rect.setShape({\n            x: parseFloat(xmlNode.getAttribute('x') || 0),\n            y: parseFloat(xmlNode.getAttribute('y') || 0),\n            width: parseFloat(xmlNode.getAttribute('width') || 0),\n            height: parseFloat(xmlNode.getAttribute('height') || 0)\n        });\n\n        // console.log(xmlNode.getAttribute('transform'));\n        // console.log(rect.transform);\n\n        return rect;\n    },\n    'circle': function (xmlNode, parentGroup) {\n        var circle = new Circle();\n        inheritStyle(parentGroup, circle);\n        parseAttributes(xmlNode, circle, this._defs);\n\n        circle.setShape({\n            cx: parseFloat(xmlNode.getAttribute('cx') || 0),\n            cy: parseFloat(xmlNode.getAttribute('cy') || 0),\n            r: parseFloat(xmlNode.getAttribute('r') || 0)\n        });\n\n        return circle;\n    },\n    'line': function (xmlNode, parentGroup) {\n        var line = new Line();\n        inheritStyle(parentGroup, line);\n        parseAttributes(xmlNode, line, this._defs);\n\n        line.setShape({\n            x1: parseFloat(xmlNode.getAttribute('x1') || 0),\n            y1: parseFloat(xmlNode.getAttribute('y1') || 0),\n            x2: parseFloat(xmlNode.getAttribute('x2') || 0),\n            y2: parseFloat(xmlNode.getAttribute('y2') || 0)\n        });\n\n        return line;\n    },\n    'ellipse': function (xmlNode, parentGroup) {\n        var ellipse = new Ellipse();\n        inheritStyle(parentGroup, ellipse);\n        parseAttributes(xmlNode, ellipse, this._defs);\n\n        ellipse.setShape({\n            cx: parseFloat(xmlNode.getAttribute('cx') || 0),\n            cy: parseFloat(xmlNode.getAttribute('cy') || 0),\n            rx: parseFloat(xmlNode.getAttribute('rx') || 0),\n            ry: parseFloat(xmlNode.getAttribute('ry') || 0)\n        });\n        return ellipse;\n    },\n    'polygon': function (xmlNode, parentGroup) {\n        var points = xmlNode.getAttribute('points');\n        if (points) {\n            points = parsePoints(points);\n        }\n        var polygon = new Polygon({\n            shape: {\n                points: points || []\n            }\n        });\n\n        inheritStyle(parentGroup, polygon);\n        parseAttributes(xmlNode, polygon, this._defs);\n\n        return polygon;\n    },\n    'polyline': function (xmlNode, parentGroup) {\n        var path = new Path();\n        inheritStyle(parentGroup, path);\n        parseAttributes(xmlNode, path, this._defs);\n\n        var points = xmlNode.getAttribute('points');\n        if (points) {\n            points = parsePoints(points);\n        }\n        var polyline = new Polyline({\n            shape: {\n                points: points || []\n            }\n        });\n\n        return polyline;\n    },\n    'image': function (xmlNode, parentGroup) {\n        var img = new ZImage();\n        inheritStyle(parentGroup, img);\n        parseAttributes(xmlNode, img, this._defs);\n\n        img.setStyle({\n            image: xmlNode.getAttribute('xlink:href'),\n            x: xmlNode.getAttribute('x'),\n            y: xmlNode.getAttribute('y'),\n            width: xmlNode.getAttribute('width'),\n            height: xmlNode.getAttribute('height')\n        });\n\n        return img;\n    },\n    'text': function (xmlNode, parentGroup) {\n        var x = xmlNode.getAttribute('x') || 0;\n        var y = xmlNode.getAttribute('y') || 0;\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n\n        this._textX = parseFloat(x) + parseFloat(dx);\n        this._textY = parseFloat(y) + parseFloat(dy);\n\n        var g = new Group();\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n        return g;\n    },\n    'tspan': function (xmlNode, parentGroup) {\n        var x = xmlNode.getAttribute('x');\n        var y = xmlNode.getAttribute('y');\n        if (x != null) {\n            // new offset x\n            this._textX = parseFloat(x);\n        }\n        if (y != null) {\n            // new offset y\n            this._textY = parseFloat(y);\n        }\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n\n        var g = new Group();\n\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n\n        this._textX += dx;\n        this._textY += dy;\n\n        return g;\n    },\n    'path': function (xmlNode, parentGroup) {\n        // TODO svg fill rule\n        // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule\n        // path.style.globalCompositeOperation = 'xor';\n        var d = xmlNode.getAttribute('d') || '';\n\n        // Performance sensitive.\n\n        var path = createFromString(d);\n\n        inheritStyle(parentGroup, path);\n        parseAttributes(xmlNode, path, this._defs);\n\n        return path;\n    }\n};\n\nvar defineParsers = {\n\n    'lineargradient': function (xmlNode) {\n        var x1 = parseInt(xmlNode.getAttribute('x1') || 0, 10);\n        var y1 = parseInt(xmlNode.getAttribute('y1') || 0, 10);\n        var x2 = parseInt(xmlNode.getAttribute('x2') || 10, 10);\n        var y2 = parseInt(xmlNode.getAttribute('y2') || 0, 10);\n\n        var gradient = new LinearGradient(x1, y1, x2, y2);\n\n        _parseGradientColorStops(xmlNode, gradient);\n\n        return gradient;\n    },\n\n    'radialgradient': function (xmlNode) {\n\n    }\n};\n\nfunction _parseGradientColorStops(xmlNode, gradient) {\n\n    var stop = xmlNode.firstChild;\n\n    while (stop) {\n        if (stop.nodeType === 1) {\n            var offset = stop.getAttribute('offset');\n            if (offset.indexOf('%') > 0) {  // percentage\n                offset = parseInt(offset, 10) / 100;\n            }\n            else if (offset) {    // number from 0 to 1\n                offset = parseFloat(offset);\n            }\n            else {\n                offset = 0;\n            }\n\n            var stopColor = stop.getAttribute('stop-color') || '#000000';\n\n            gradient.addColorStop(offset, stopColor);\n        }\n        stop = stop.nextSibling;\n    }\n}\n\nfunction inheritStyle(parent, child) {\n    if (parent && parent.__inheritedStyle) {\n        if (!child.__inheritedStyle) {\n            child.__inheritedStyle = {};\n        }\n        defaults(child.__inheritedStyle, parent.__inheritedStyle);\n    }\n}\n\nfunction parsePoints(pointsString) {\n    var list = trim(pointsString).split(DILIMITER_REG);\n    var points = [];\n\n    for (var i = 0; i < list.length; i += 2) {\n        var x = parseFloat(list[i]);\n        var y = parseFloat(list[i + 1]);\n        points.push([x, y]);\n    }\n    return points;\n}\n\nvar attributesMap = {\n    'fill': 'fill',\n    'stroke': 'stroke',\n    'stroke-width': 'lineWidth',\n    'opacity': 'opacity',\n    'fill-opacity': 'fillOpacity',\n    'stroke-opacity': 'strokeOpacity',\n    'stroke-dasharray': 'lineDash',\n    'stroke-dashoffset': 'lineDashOffset',\n    'stroke-linecap': 'lineCap',\n    'stroke-linejoin': 'lineJoin',\n    'stroke-miterlimit': 'miterLimit',\n    'font-family': 'fontFamily',\n    'font-size': 'fontSize',\n    'font-style': 'fontStyle',\n    'font-weight': 'fontWeight',\n\n    'text-align': 'textAlign',\n    'alignment-baseline': 'textBaseline'\n};\n\nfunction parseAttributes(xmlNode, el, defs, onlyInlineStyle) {\n    var zrStyle = el.__inheritedStyle || {};\n    var isTextEl = el.type === 'text';\n\n    // TODO Shadow\n    if (xmlNode.nodeType === 1) {\n        parseTransformAttribute(xmlNode, el);\n\n        extend(zrStyle, parseStyleAttribute(xmlNode));\n\n        if (!onlyInlineStyle) {\n            for (var svgAttrName in attributesMap) {\n                if (attributesMap.hasOwnProperty(svgAttrName)) {\n                    var attrValue = xmlNode.getAttribute(svgAttrName);\n                    if (attrValue != null) {\n                        zrStyle[attributesMap[svgAttrName]] = attrValue;\n                    }\n                }\n            }\n        }\n    }\n\n    var elFillProp = isTextEl ? 'textFill' : 'fill';\n    var elStrokeProp = isTextEl ? 'textStroke' : 'stroke';\n\n    el.style = el.style || new Style();\n    var elStyle = el.style;\n\n    zrStyle.fill != null && elStyle.set(elFillProp, getPaint(zrStyle.fill, defs));\n    zrStyle.stroke != null && elStyle.set(elStrokeProp, getPaint(zrStyle.stroke, defs));\n\n    each$1([\n        'lineWidth', 'opacity', 'fillOpacity', 'strokeOpacity', 'miterLimit', 'fontSize'\n    ], function (propName) {\n        var elPropName = (propName === 'lineWidth' && isTextEl) ? 'textStrokeWidth' : propName;\n        zrStyle[propName] != null && elStyle.set(elPropName, parseFloat(zrStyle[propName]));\n    });\n\n    if (!zrStyle.textBaseline || zrStyle.textBaseline === 'auto') {\n        zrStyle.textBaseline = 'alphabetic';\n    }\n    if (zrStyle.textBaseline === 'alphabetic') {\n        zrStyle.textBaseline = 'bottom';\n    }\n    if (zrStyle.textAlign === 'start') {\n        zrStyle.textAlign = 'left';\n    }\n    if (zrStyle.textAlign === 'end') {\n        zrStyle.textAlign = 'right';\n    }\n\n    each$1(['lineDashOffset', 'lineCap', 'lineJoin',\n        'fontWeight', 'fontFamily', 'fontStyle', 'textAlign', 'textBaseline'\n    ], function (propName) {\n        zrStyle[propName] != null && elStyle.set(propName, zrStyle[propName]);\n    });\n\n    if (zrStyle.lineDash) {\n        el.style.lineDash = trim(zrStyle.lineDash).split(DILIMITER_REG);\n    }\n\n    if (elStyle[elStrokeProp] && elStyle[elStrokeProp] !== 'none') {\n        // enable stroke\n        el[elStrokeProp] = true;\n    }\n\n    el.__inheritedStyle = zrStyle;\n}\n\n\nvar urlRegex = /url\\(\\s*#(.*?)\\)/;\nfunction getPaint(str, defs) {\n    // if (str === 'none') {\n    //     return;\n    // }\n    var urlMatch = defs && str && str.match(urlRegex);\n    if (urlMatch) {\n        var url = trim(urlMatch[1]);\n        var def = defs[url];\n        return def;\n    }\n    return str;\n}\n\nvar transformRegex = /(translate|scale|rotate|skewX|skewY|matrix)\\(([\\-\\s0-9\\.e,]*)\\)/g;\n\nfunction parseTransformAttribute(xmlNode, node) {\n    var transform = xmlNode.getAttribute('transform');\n    if (transform) {\n        transform = transform.replace(/,/g, ' ');\n        var m = null;\n        var transformOps = [];\n        transform.replace(transformRegex, function (str, type, value) {\n            transformOps.push(type, value);\n        });\n        for (var i = transformOps.length - 1; i > 0; i -= 2) {\n            var value = transformOps[i];\n            var type = transformOps[i - 1];\n            m = m || create$1();\n            switch (type) {\n                case 'translate':\n                    value = trim(value).split(DILIMITER_REG);\n                    translate(m, m, [parseFloat(value[0]), parseFloat(value[1] || 0)]);\n                    break;\n                case 'scale':\n                    value = trim(value).split(DILIMITER_REG);\n                    scale$1(m, m, [parseFloat(value[0]), parseFloat(value[1] || value[0])]);\n                    break;\n                case 'rotate':\n                    value = trim(value).split(DILIMITER_REG);\n                    rotate(m, m, parseFloat(value[0]));\n                    break;\n                case 'skew':\n                    value = trim(value).split(DILIMITER_REG);\n                    console.warn('Skew transform is not supported yet');\n                    break;\n                case 'matrix':\n                    var value = trim(value).split(DILIMITER_REG);\n                    m[0] = parseFloat(value[0]);\n                    m[1] = parseFloat(value[1]);\n                    m[2] = parseFloat(value[2]);\n                    m[3] = parseFloat(value[3]);\n                    m[4] = parseFloat(value[4]);\n                    m[5] = parseFloat(value[5]);\n                    break;\n            }\n        }\n        node.setLocalTransform(m);\n    }\n}\n\n// Value may contain space.\nvar styleRegex = /([^\\s:;]+)\\s*:\\s*([^:;]+)/g;\nfunction parseStyleAttribute(xmlNode) {\n    var style = xmlNode.getAttribute('style');\n    var result = {};\n\n    if (!style) {\n        return result;\n    }\n\n    var styleList = {};\n    styleRegex.lastIndex = 0;\n    var styleRegResult;\n    while ((styleRegResult = styleRegex.exec(style)) != null) {\n        styleList[styleRegResult[1]] = styleRegResult[2];\n    }\n\n    for (var svgAttrName in attributesMap) {\n        if (attributesMap.hasOwnProperty(svgAttrName) && styleList[svgAttrName] != null) {\n            result[attributesMap[svgAttrName]] = styleList[svgAttrName];\n        }\n    }\n\n    return result;\n}\n\n/**\n * @param {Array.<number>} viewBoxRect\n * @param {number} width\n * @param {number} height\n * @return {Object} {scale, position}\n */\nfunction makeViewBoxTransform(viewBoxRect, width, height) {\n    var scaleX = width / viewBoxRect.width;\n    var scaleY = height / viewBoxRect.height;\n    var scale = Math.min(scaleX, scaleY);\n    // preserveAspectRatio 'xMidYMid'\n    var viewBoxScale = [scale, scale];\n    var viewBoxPosition = [\n        -(viewBoxRect.x + viewBoxRect.width / 2) * scale + width / 2,\n        -(viewBoxRect.y + viewBoxRect.height / 2) * scale + height / 2\n    ];\n\n    return {\n        scale: viewBoxScale,\n        position: viewBoxPosition\n    };\n}\n\n/**\n * @param {string|XMLElement} xml\n * @param {Object} [opt]\n * @param {number} [opt.width] Default width if svg width not specified or is a percent value.\n * @param {number} [opt.height] Default height if svg height not specified or is a percent value.\n * @param {boolean} [opt.ignoreViewBox]\n * @param {boolean} [opt.ignoreRootClip]\n * @return {Object} result:\n * {\n *     root: Group, The root of the the result tree of zrender shapes,\n *     width: number, the viewport width of the SVG,\n *     height: number, the viewport height of the SVG,\n *     viewBoxRect: {x, y, width, height}, the declared viewBox rect of the SVG, if exists,\n *     viewBoxTransform: the {scale, position} calculated by viewBox and viewport, is exists.\n * }\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar storage = createHashMap();\n\n// For minimize the code size of common echarts package,\n// do not put too much logic in this module.\n\nvar mapDataStorage = {\n\n    // The format of record: see `echarts.registerMap`.\n    // Compatible with previous `echarts.registerMap`.\n    registerMap: function (mapName, rawGeoJson, rawSpecialAreas) {\n\n        var records;\n\n        if (isArray(rawGeoJson)) {\n            records = rawGeoJson;\n        }\n        else if (rawGeoJson.svg) {\n            records = [{\n                type: 'svg',\n                source: rawGeoJson.svg,\n                specialAreas: rawGeoJson.specialAreas\n            }];\n        }\n        else {\n            // Backward compatibility.\n            if (rawGeoJson.geoJson && !rawGeoJson.features) {\n                rawSpecialAreas = rawGeoJson.specialAreas;\n                rawGeoJson = rawGeoJson.geoJson;\n            }\n            records = [{\n                type: 'geoJSON',\n                source: rawGeoJson,\n                specialAreas: rawSpecialAreas\n            }];\n        }\n\n        each$1(records, function (record) {\n            var type = record.type;\n            type === 'geoJson' && (type = record.type = 'geoJSON');\n\n            var parse = parsers[type];\n\n            if (__DEV__) {\n                assert$1(parse, 'Illegal map type: ' + type);\n            }\n\n            parse(record);\n        });\n\n        return storage.set(mapName, records);\n    },\n\n    retrieveMap: function (mapName) {\n        return storage.get(mapName);\n    }\n\n};\n\nvar parsers = {\n\n    geoJSON: function (record) {\n        var source = record.source;\n        record.geoJSON = !isString(source)\n            ? source\n            : (typeof JSON !== 'undefined' && JSON.parse)\n            ? JSON.parse(source)\n            : (new Function('return (' + source + ');'))();\n    },\n\n    // Only perform parse to XML object here, which might be time\n    // consiming for large SVG.\n    // Although convert XML to zrender element is also time consiming,\n    // if we do it here, the clone of zrender elements has to be\n    // required. So we do it once for each geo instance, util real\n    // performance issues call for optimizing it.\n    svg: function (record) {\n        record.svgXML = parseXML(record.source);\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\nvar assert = assert$1;\nvar each = each$1;\nvar isFunction = isFunction$1;\nvar isObject = isObject$1;\nvar parseClassType = ComponentModel.parseClassType;\n\nvar version = '4.2.1';\n\nvar dependencies = {\n    zrender: '4.0.6'\n};\n\nvar TEST_FRAME_REMAIN_TIME = 1;\n\nvar PRIORITY_PROCESSOR_FILTER = 1000;\nvar PRIORITY_PROCESSOR_STATISTIC = 5000;\n\nvar PRIORITY_VISUAL_LAYOUT = 1000;\nvar PRIORITY_VISUAL_GLOBAL = 2000;\nvar PRIORITY_VISUAL_CHART = 3000;\nvar PRIORITY_VISUAL_COMPONENT = 4000;\n// FIXME\n// necessary?\nvar PRIORITY_VISUAL_BRUSH = 5000;\n\nvar PRIORITY = {\n    PROCESSOR: {\n        FILTER: PRIORITY_PROCESSOR_FILTER,\n        STATISTIC: PRIORITY_PROCESSOR_STATISTIC\n    },\n    VISUAL: {\n        LAYOUT: PRIORITY_VISUAL_LAYOUT,\n        GLOBAL: PRIORITY_VISUAL_GLOBAL,\n        CHART: PRIORITY_VISUAL_CHART,\n        COMPONENT: PRIORITY_VISUAL_COMPONENT,\n        BRUSH: PRIORITY_VISUAL_BRUSH\n    }\n};\n\n// Main process have three entries: `setOption`, `dispatchAction` and `resize`,\n// where they must not be invoked nestedly, except the only case: invoke\n// dispatchAction with updateMethod \"none\" in main process.\n// This flag is used to carry out this rule.\n// All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]).\nvar IN_MAIN_PROCESS = '__flagInMainProcess';\nvar OPTION_UPDATED = '__optionUpdated';\nvar ACTION_REG = /^[a-zA-Z0-9_]+$/;\n\n\nfunction createRegisterEventWithLowercaseName(method) {\n    return function (eventName, handler, context) {\n        // Event name is all lowercase\n        eventName = eventName && eventName.toLowerCase();\n        Eventful.prototype[method].call(this, eventName, handler, context);\n    };\n}\n\n/**\n * @module echarts~MessageCenter\n */\nfunction MessageCenter() {\n    Eventful.call(this);\n}\nMessageCenter.prototype.on = createRegisterEventWithLowercaseName('on');\nMessageCenter.prototype.off = createRegisterEventWithLowercaseName('off');\nMessageCenter.prototype.one = createRegisterEventWithLowercaseName('one');\nmixin(MessageCenter, Eventful);\n\n/**\n * @module echarts~ECharts\n */\nfunction ECharts(dom, theme$$1, opts) {\n    opts = opts || {};\n\n    // Get theme by name\n    if (typeof theme$$1 === 'string') {\n        theme$$1 = themeStorage[theme$$1];\n    }\n\n    /**\n     * @type {string}\n     */\n    this.id;\n\n    /**\n     * Group id\n     * @type {string}\n     */\n    this.group;\n\n    /**\n     * @type {HTMLElement}\n     * @private\n     */\n    this._dom = dom;\n\n    var defaultRenderer = 'canvas';\n    if (__DEV__) {\n        defaultRenderer = (\n            typeof window === 'undefined' ? global : window\n        ).__ECHARTS__DEFAULT__RENDERER__ || defaultRenderer;\n    }\n\n    /**\n     * @type {module:zrender/ZRender}\n     * @private\n     */\n    var zr = this._zr = init$1(dom, {\n        renderer: opts.renderer || defaultRenderer,\n        devicePixelRatio: opts.devicePixelRatio,\n        width: opts.width,\n        height: opts.height\n    });\n\n    /**\n     * Expect 60 pfs.\n     * @type {Function}\n     * @private\n     */\n    this._throttledZrFlush = throttle(bind(zr.flush, zr), 17);\n\n    var theme$$1 = clone(theme$$1);\n    theme$$1 && backwardCompat(theme$$1, true);\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._theme = theme$$1;\n\n    /**\n     * @type {Array.<module:echarts/view/Chart>}\n     * @private\n     */\n    this._chartsViews = [];\n\n    /**\n     * @type {Object.<string, module:echarts/view/Chart>}\n     * @private\n     */\n    this._chartsMap = {};\n\n    /**\n     * @type {Array.<module:echarts/view/Component>}\n     * @private\n     */\n    this._componentsViews = [];\n\n    /**\n     * @type {Object.<string, module:echarts/view/Component>}\n     * @private\n     */\n    this._componentsMap = {};\n\n    /**\n     * @type {module:echarts/CoordinateSystem}\n     * @private\n     */\n    this._coordSysMgr = new CoordinateSystemManager();\n\n    /**\n     * @type {module:echarts/ExtensionAPI}\n     * @private\n     */\n    var api = this._api = createExtensionAPI(this);\n\n    // Sort on demand\n    function prioritySortFunc(a, b) {\n        return a.__prio - b.__prio;\n    }\n    sort(visualFuncs, prioritySortFunc);\n    sort(dataProcessorFuncs, prioritySortFunc);\n\n    /**\n     * @type {module:echarts/stream/Scheduler}\n     */\n    this._scheduler = new Scheduler(this, api, dataProcessorFuncs, visualFuncs);\n\n    Eventful.call(this, this._ecEventProcessor = new EventProcessor());\n\n    /**\n     * @type {module:echarts~MessageCenter}\n     * @private\n     */\n    this._messageCenter = new MessageCenter();\n\n    // Init mouse events\n    this._initEvents();\n\n    // In case some people write `window.onresize = chart.resize`\n    this.resize = bind(this.resize, this);\n\n    // Can't dispatch action during rendering procedure\n    this._pendingActions = [];\n\n    zr.animation.on('frame', this._onframe, this);\n\n    bindRenderedEvent(zr, this);\n\n    // ECharts instance can be used as value.\n    setAsPrimitive(this);\n}\n\nvar echartsProto = ECharts.prototype;\n\nechartsProto._onframe = function () {\n    if (this._disposed) {\n        return;\n    }\n\n    var scheduler = this._scheduler;\n\n    // Lazy update\n    if (this[OPTION_UPDATED]) {\n        var silent = this[OPTION_UPDATED].silent;\n\n        this[IN_MAIN_PROCESS] = true;\n\n        prepare(this);\n        updateMethods.update.call(this);\n\n        this[IN_MAIN_PROCESS] = false;\n\n        this[OPTION_UPDATED] = false;\n\n        flushPendingActions.call(this, silent);\n\n        triggerUpdatedEvent.call(this, silent);\n    }\n    // Avoid do both lazy update and progress in one frame.\n    else if (scheduler.unfinished) {\n        // Stream progress.\n        var remainTime = TEST_FRAME_REMAIN_TIME;\n        var ecModel = this._model;\n        var api = this._api;\n        scheduler.unfinished = false;\n        do {\n            var startTime = +new Date();\n\n            scheduler.performSeriesTasks(ecModel);\n\n            // Currently dataProcessorFuncs do not check threshold.\n            scheduler.performDataProcessorTasks(ecModel);\n\n            updateStreamModes(this, ecModel);\n\n            // Do not update coordinate system here. Because that coord system update in\n            // each frame is not a good user experience. So we follow the rule that\n            // the extent of the coordinate system is determin in the first frame (the\n            // frame is executed immedietely after task reset.\n            // this._coordSysMgr.update(ecModel, api);\n\n            // console.log('--- ec frame visual ---', remainTime);\n            scheduler.performVisualTasks(ecModel);\n\n            renderSeries(this, this._model, api, 'remain');\n\n            remainTime -= (+new Date() - startTime);\n        }\n        while (remainTime > 0 && scheduler.unfinished);\n\n        // Call flush explicitly for trigger finished event.\n        if (!scheduler.unfinished) {\n            this._zr.flush();\n        }\n        // Else, zr flushing be ensue within the same frame,\n        // because zr flushing is after onframe event.\n    }\n};\n\n/**\n * @return {HTMLElement}\n */\nechartsProto.getDom = function () {\n    return this._dom;\n};\n\n/**\n * @return {module:zrender~ZRender}\n */\nechartsProto.getZr = function () {\n    return this._zr;\n};\n\n/**\n * Usage:\n * chart.setOption(option, notMerge, lazyUpdate);\n * chart.setOption(option, {\n *     notMerge: ...,\n *     lazyUpdate: ...,\n *     silent: ...\n * });\n *\n * @param {Object} option\n * @param {Object|boolean} [opts] opts or notMerge.\n * @param {boolean} [opts.notMerge=false]\n * @param {boolean} [opts.lazyUpdate=false] Useful when setOption frequently.\n */\nechartsProto.setOption = function (option, notMerge, lazyUpdate) {\n    if (__DEV__) {\n        assert(!this[IN_MAIN_PROCESS], '`setOption` should not be called during main process.');\n    }\n\n    var silent;\n    if (isObject(notMerge)) {\n        lazyUpdate = notMerge.lazyUpdate;\n        silent = notMerge.silent;\n        notMerge = notMerge.notMerge;\n    }\n\n    this[IN_MAIN_PROCESS] = true;\n\n    if (!this._model || notMerge) {\n        var optionManager = new OptionManager(this._api);\n        var theme$$1 = this._theme;\n        var ecModel = this._model = new GlobalModel(null, null, theme$$1, optionManager);\n        ecModel.scheduler = this._scheduler;\n        ecModel.init(null, null, theme$$1, optionManager);\n    }\n\n    this._model.setOption(option, optionPreprocessorFuncs);\n\n    if (lazyUpdate) {\n        this[OPTION_UPDATED] = {silent: silent};\n        this[IN_MAIN_PROCESS] = false;\n    }\n    else {\n        prepare(this);\n\n        updateMethods.update.call(this);\n\n        // Ensure zr refresh sychronously, and then pixel in canvas can be\n        // fetched after `setOption`.\n        this._zr.flush();\n\n        this[OPTION_UPDATED] = false;\n        this[IN_MAIN_PROCESS] = false;\n\n        flushPendingActions.call(this, silent);\n        triggerUpdatedEvent.call(this, silent);\n    }\n};\n\n/**\n * @DEPRECATED\n */\nechartsProto.setTheme = function () {\n    console.error('ECharts#setTheme() is DEPRECATED in ECharts 3.0');\n};\n\n/**\n * @return {module:echarts/model/Global}\n */\nechartsProto.getModel = function () {\n    return this._model;\n};\n\n/**\n * @return {Object}\n */\nechartsProto.getOption = function () {\n    return this._model && this._model.getOption();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getWidth = function () {\n    return this._zr.getWidth();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getHeight = function () {\n    return this._zr.getHeight();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getDevicePixelRatio = function () {\n    return this._zr.painter.dpr || window.devicePixelRatio || 1;\n};\n\n/**\n * Get canvas which has all thing rendered\n * @param {Object} opts\n * @param {string} [opts.backgroundColor]\n * @return {string}\n */\nechartsProto.getRenderedCanvas = function (opts) {\n    if (!env$1.canvasSupported) {\n        return;\n    }\n    opts = opts || {};\n    opts.pixelRatio = opts.pixelRatio || 1;\n    opts.backgroundColor = opts.backgroundColor\n        || this._model.get('backgroundColor');\n    var zr = this._zr;\n    // var list = zr.storage.getDisplayList();\n    // Stop animations\n    // Never works before in init animation, so remove it.\n    // zrUtil.each(list, function (el) {\n    //     el.stopAnimation(true);\n    // });\n    return zr.painter.getRenderedCanvas(opts);\n};\n\n/**\n * Get svg data url\n * @return {string}\n */\nechartsProto.getSvgDataUrl = function () {\n    if (!env$1.svgSupported) {\n        return;\n    }\n\n    var zr = this._zr;\n    var list = zr.storage.getDisplayList();\n    // Stop animations\n    each$1(list, function (el) {\n        el.stopAnimation(true);\n    });\n\n    return zr.painter.pathToDataUrl();\n};\n\n/**\n * @return {string}\n * @param {Object} opts\n * @param {string} [opts.type='png']\n * @param {string} [opts.pixelRatio=1]\n * @param {string} [opts.backgroundColor]\n * @param {string} [opts.excludeComponents]\n */\nechartsProto.getDataURL = function (opts) {\n    opts = opts || {};\n    var excludeComponents = opts.excludeComponents;\n    var ecModel = this._model;\n    var excludesComponentViews = [];\n    var self = this;\n\n    each(excludeComponents, function (componentType) {\n        ecModel.eachComponent({\n            mainType: componentType\n        }, function (component) {\n            var view = self._componentsMap[component.__viewId];\n            if (!view.group.ignore) {\n                excludesComponentViews.push(view);\n                view.group.ignore = true;\n            }\n        });\n    });\n\n    var url = this._zr.painter.getType() === 'svg'\n        ? this.getSvgDataUrl()\n        : this.getRenderedCanvas(opts).toDataURL(\n            'image/' + (opts && opts.type || 'png')\n        );\n\n    each(excludesComponentViews, function (view) {\n        view.group.ignore = false;\n    });\n\n    return url;\n};\n\n\n/**\n * @return {string}\n * @param {Object} opts\n * @param {string} [opts.type='png']\n * @param {string} [opts.pixelRatio=1]\n * @param {string} [opts.backgroundColor]\n */\nechartsProto.getConnectedDataURL = function (opts) {\n    if (!env$1.canvasSupported) {\n        return;\n    }\n    var groupId = this.group;\n    var mathMin = Math.min;\n    var mathMax = Math.max;\n    var MAX_NUMBER = Infinity;\n    if (connectedGroups[groupId]) {\n        var left = MAX_NUMBER;\n        var top = MAX_NUMBER;\n        var right = -MAX_NUMBER;\n        var bottom = -MAX_NUMBER;\n        var canvasList = [];\n        var dpr = (opts && opts.pixelRatio) || 1;\n\n        each$1(instances, function (chart, id) {\n            if (chart.group === groupId) {\n                var canvas = chart.getRenderedCanvas(\n                    clone(opts)\n                );\n                var boundingRect = chart.getDom().getBoundingClientRect();\n                left = mathMin(boundingRect.left, left);\n                top = mathMin(boundingRect.top, top);\n                right = mathMax(boundingRect.right, right);\n                bottom = mathMax(boundingRect.bottom, bottom);\n                canvasList.push({\n                    dom: canvas,\n                    left: boundingRect.left,\n                    top: boundingRect.top\n                });\n            }\n        });\n\n        left *= dpr;\n        top *= dpr;\n        right *= dpr;\n        bottom *= dpr;\n        var width = right - left;\n        var height = bottom - top;\n        var targetCanvas = createCanvas();\n        targetCanvas.width = width;\n        targetCanvas.height = height;\n        var zr = init$1(targetCanvas);\n\n        each(canvasList, function (item) {\n            var img = new ZImage({\n                style: {\n                    x: item.left * dpr - left,\n                    y: item.top * dpr - top,\n                    image: item.dom\n                }\n            });\n            zr.add(img);\n        });\n        zr.refreshImmediately();\n\n        return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png'));\n    }\n    else {\n        return this.getDataURL(opts);\n    }\n};\n\n/**\n * Convert from logical coordinate system to pixel coordinate system.\n * See CoordinateSystem#convertToPixel.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId, geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName,\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {Array|number} result\n */\nechartsProto.convertToPixel = curry(doConvertPixel, 'convertToPixel');\n\n/**\n * Convert from pixel coordinate system to logical coordinate system.\n * See CoordinateSystem#convertFromPixel.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId / geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {Array|number} result\n */\nechartsProto.convertFromPixel = curry(doConvertPixel, 'convertFromPixel');\n\nfunction doConvertPixel(methodName, finder, value) {\n    var ecModel = this._model;\n    var coordSysList = this._coordSysMgr.getCoordinateSystems();\n    var result;\n\n    finder = parseFinder(ecModel, finder);\n\n    for (var i = 0; i < coordSysList.length; i++) {\n        var coordSys = coordSysList[i];\n        if (coordSys[methodName]\n            && (result = coordSys[methodName](ecModel, finder, value)) != null\n        ) {\n            return result;\n        }\n    }\n\n    if (__DEV__) {\n        console.warn(\n            'No coordinate system that supports ' + methodName + ' found by the given finder.'\n        );\n    }\n}\n\n/**\n * Is the specified coordinate systems or components contain the given pixel point.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId / geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName,\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {boolean} result\n */\nechartsProto.containPixel = function (finder, value) {\n    var ecModel = this._model;\n    var result;\n\n    finder = parseFinder(ecModel, finder);\n\n    each$1(finder, function (models, key) {\n        key.indexOf('Models') >= 0 && each$1(models, function (model) {\n            var coordSys = model.coordinateSystem;\n            if (coordSys && coordSys.containPoint) {\n                result |= !!coordSys.containPoint(value);\n            }\n            else if (key === 'seriesModels') {\n                var view = this._chartsMap[model.__viewId];\n                if (view && view.containPoint) {\n                    result |= view.containPoint(value, model);\n                }\n                else {\n                    if (__DEV__) {\n                        console.warn(key + ': ' + (view\n                            ? 'The found component do not support containPoint.'\n                            : 'No view mapping to the found component.'\n                        ));\n                    }\n                }\n            }\n            else {\n                if (__DEV__) {\n                    console.warn(key + ': containPoint is not supported');\n                }\n            }\n        }, this);\n    }, this);\n\n    return !!result;\n};\n\n/**\n * Get visual from series or data.\n * @param {string|Object} finder\n *        If string, e.g., 'series', means {seriesIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            dataIndex / dataIndexInside\n *        }\n *        If dataIndex is not specified, series visual will be fetched,\n *        but not data item visual.\n *        If all of seriesIndex, seriesId, seriesName are not specified,\n *        visual will be fetched from first series.\n * @param {string} visualType 'color', 'symbol', 'symbolSize'\n */\nechartsProto.getVisual = function (finder, visualType) {\n    var ecModel = this._model;\n\n    finder = parseFinder(ecModel, finder, {defaultMainType: 'series'});\n\n    var seriesModel = finder.seriesModel;\n\n    if (__DEV__) {\n        if (!seriesModel) {\n            console.warn('There is no specified seires model');\n        }\n    }\n\n    var data = seriesModel.getData();\n\n    var dataIndexInside = finder.hasOwnProperty('dataIndexInside')\n        ? finder.dataIndexInside\n        : finder.hasOwnProperty('dataIndex')\n        ? data.indexOfRawIndex(finder.dataIndex)\n        : null;\n\n    return dataIndexInside != null\n        ? data.getItemVisual(dataIndexInside, visualType)\n        : data.getVisual(visualType);\n};\n\n/**\n * Get view of corresponding component model\n * @param  {module:echarts/model/Component} componentModel\n * @return {module:echarts/view/Component}\n */\nechartsProto.getViewOfComponentModel = function (componentModel) {\n    return this._componentsMap[componentModel.__viewId];\n};\n\n/**\n * Get view of corresponding series model\n * @param  {module:echarts/model/Series} seriesModel\n * @return {module:echarts/view/Chart}\n */\nechartsProto.getViewOfSeriesModel = function (seriesModel) {\n    return this._chartsMap[seriesModel.__viewId];\n};\n\nvar updateMethods = {\n\n    prepareAndUpdate: function (payload) {\n        prepare(this);\n        updateMethods.update.call(this, payload);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    update: function (payload) {\n        // console.profile && console.profile('update');\n\n        var ecModel = this._model;\n        var api = this._api;\n        var zr = this._zr;\n        var coordSysMgr = this._coordSysMgr;\n        var scheduler = this._scheduler;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        scheduler.restoreData(ecModel, payload);\n\n        scheduler.performSeriesTasks(ecModel);\n\n        // TODO\n        // Save total ecModel here for undo/redo (after restoring data and before processing data).\n        // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call.\n\n        // Create new coordinate system each update\n        // In LineView may save the old coordinate system and use it to get the orignal point\n        coordSysMgr.create(ecModel, api);\n\n        scheduler.performDataProcessorTasks(ecModel, payload);\n\n        // Current stream render is not supported in data process. So we can update\n        // stream modes after data processing, where the filtered data is used to\n        // deteming whether use progressive rendering.\n        updateStreamModes(this, ecModel);\n\n        // We update stream modes before coordinate system updated, then the modes info\n        // can be fetched when coord sys updating (consider the barGrid extent fix). But\n        // the drawback is the full coord info can not be fetched. Fortunately this full\n        // coord is not requied in stream mode updater currently.\n        coordSysMgr.update(ecModel, api);\n\n        clearColorPalette(ecModel);\n        scheduler.performVisualTasks(ecModel, payload);\n\n        render(this, ecModel, api, payload);\n\n        // Set background\n        var backgroundColor = ecModel.get('backgroundColor') || 'transparent';\n\n        // In IE8\n        if (!env$1.canvasSupported) {\n            var colorArr = parse(backgroundColor);\n            backgroundColor = stringify(colorArr, 'rgb');\n            if (colorArr[3] === 0) {\n                backgroundColor = 'transparent';\n            }\n        }\n        else {\n            zr.setBackgroundColor(backgroundColor);\n        }\n\n        performPostUpdateFuncs(ecModel, api);\n\n        // console.profile && console.profileEnd('update');\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateTransform: function (payload) {\n        var ecModel = this._model;\n        var ecIns = this;\n        var api = this._api;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        // ChartView.markUpdateMethod(payload, 'updateTransform');\n\n        var componentDirtyList = [];\n        ecModel.eachComponent(function (componentType, componentModel) {\n            var componentView = ecIns.getViewOfComponentModel(componentModel);\n            if (componentView && componentView.__alive) {\n                if (componentView.updateTransform) {\n                    var result = componentView.updateTransform(componentModel, ecModel, api, payload);\n                    result && result.update && componentDirtyList.push(componentView);\n                }\n                else {\n                    componentDirtyList.push(componentView);\n                }\n            }\n        });\n\n        var seriesDirtyMap = createHashMap();\n        ecModel.eachSeries(function (seriesModel) {\n            var chartView = ecIns._chartsMap[seriesModel.__viewId];\n            if (chartView.updateTransform) {\n                var result = chartView.updateTransform(seriesModel, ecModel, api, payload);\n                result && result.update && seriesDirtyMap.set(seriesModel.uid, 1);\n            }\n            else {\n                seriesDirtyMap.set(seriesModel.uid, 1);\n            }\n        });\n\n        clearColorPalette(ecModel);\n        // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);\n        this._scheduler.performVisualTasks(\n            ecModel, payload, {setDirty: true, dirtyMap: seriesDirtyMap}\n        );\n\n        // Currently, not call render of components. Geo render cost a lot.\n        // renderComponents(ecIns, ecModel, api, payload, componentDirtyList);\n        renderSeries(ecIns, ecModel, api, payload, seriesDirtyMap);\n\n        performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateView: function (payload) {\n        var ecModel = this._model;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        Chart.markUpdateMethod(payload, 'updateView');\n\n        clearColorPalette(ecModel);\n\n        // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});\n\n        render(this, this._model, this._api, payload);\n\n        performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateVisual: function (payload) {\n        updateMethods.update.call(this, payload);\n\n        // var ecModel = this._model;\n\n        // // update before setOption\n        // if (!ecModel) {\n        //     return;\n        // }\n\n        // ChartView.markUpdateMethod(payload, 'updateVisual');\n\n        // clearColorPalette(ecModel);\n\n        // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // this._scheduler.performVisualTasks(ecModel, payload, {visualType: 'visual', setDirty: true});\n\n        // render(this, this._model, this._api, payload);\n\n        // performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateLayout: function (payload) {\n        updateMethods.update.call(this, payload);\n\n        // var ecModel = this._model;\n\n        // // update before setOption\n        // if (!ecModel) {\n        //     return;\n        // }\n\n        // ChartView.markUpdateMethod(payload, 'updateLayout');\n\n        // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);\n        // this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});\n\n        // render(this, this._model, this._api, payload);\n\n        // performPostUpdateFuncs(ecModel, this._api);\n    }\n};\n\nfunction prepare(ecIns) {\n    var ecModel = ecIns._model;\n    var scheduler = ecIns._scheduler;\n\n    scheduler.restorePipelines(ecModel);\n\n    scheduler.prepareStageTasks();\n\n    prepareView(ecIns, 'component', ecModel, scheduler);\n\n    prepareView(ecIns, 'chart', ecModel, scheduler);\n\n    scheduler.plan();\n}\n\n/**\n * @private\n */\nfunction updateDirectly(ecIns, method, payload, mainType, subType) {\n    var ecModel = ecIns._model;\n\n    // broadcast\n    if (!mainType) {\n        // FIXME\n        // Chart will not be update directly here, except set dirty.\n        // But there is no such scenario now.\n        each(ecIns._componentsViews.concat(ecIns._chartsViews), callView);\n        return;\n    }\n\n    var query = {};\n    query[mainType + 'Id'] = payload[mainType + 'Id'];\n    query[mainType + 'Index'] = payload[mainType + 'Index'];\n    query[mainType + 'Name'] = payload[mainType + 'Name'];\n\n    var condition = {mainType: mainType, query: query};\n    subType && (condition.subType = subType); // subType may be '' by parseClassType;\n\n    var excludeSeriesId = payload.excludeSeriesId;\n    if (excludeSeriesId != null) {\n        excludeSeriesId = createHashMap(normalizeToArray(excludeSeriesId));\n    }\n\n    // If dispatchAction before setOption, do nothing.\n    ecModel && ecModel.eachComponent(condition, function (model) {\n        if (!excludeSeriesId || excludeSeriesId.get(model.id) == null) {\n            callView(ecIns[\n                mainType === 'series' ? '_chartsMap' : '_componentsMap'\n            ][model.__viewId]);\n        }\n    }, ecIns);\n\n    function callView(view) {\n        view && view.__alive && view[method] && view[method](\n            view.__model, ecModel, ecIns._api, payload\n        );\n    }\n}\n\n/**\n * Resize the chart\n * @param {Object} opts\n * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)\n * @param {boolean} [opts.silent=false]\n */\nechartsProto.resize = function (opts) {\n    if (__DEV__) {\n        assert(!this[IN_MAIN_PROCESS], '`resize` should not be called during main process.');\n    }\n\n    this._zr.resize(opts);\n\n    var ecModel = this._model;\n\n    // Resize loading effect\n    this._loadingFX && this._loadingFX.resize();\n\n    if (!ecModel) {\n        return;\n    }\n\n    var optionChanged = ecModel.resetOption('media');\n\n    var silent = opts && opts.silent;\n\n    this[IN_MAIN_PROCESS] = true;\n\n    optionChanged && prepare(this);\n    updateMethods.update.call(this);\n\n    this[IN_MAIN_PROCESS] = false;\n\n    flushPendingActions.call(this, silent);\n\n    triggerUpdatedEvent.call(this, silent);\n};\n\nfunction updateStreamModes(ecIns, ecModel) {\n    var chartsMap = ecIns._chartsMap;\n    var scheduler = ecIns._scheduler;\n    ecModel.eachSeries(function (seriesModel) {\n        scheduler.updateStreamModes(seriesModel, chartsMap[seriesModel.__viewId]);\n    });\n}\n\n/**\n * Show loading effect\n * @param  {string} [name='default']\n * @param  {Object} [cfg]\n */\nechartsProto.showLoading = function (name, cfg) {\n    if (isObject(name)) {\n        cfg = name;\n        name = '';\n    }\n    name = name || 'default';\n\n    this.hideLoading();\n    if (!loadingEffects[name]) {\n        if (__DEV__) {\n            console.warn('Loading effects ' + name + ' not exists.');\n        }\n        return;\n    }\n    var el = loadingEffects[name](this._api, cfg);\n    var zr = this._zr;\n    this._loadingFX = el;\n\n    zr.add(el);\n};\n\n/**\n * Hide loading effect\n */\nechartsProto.hideLoading = function () {\n    this._loadingFX && this._zr.remove(this._loadingFX);\n    this._loadingFX = null;\n};\n\n/**\n * @param {Object} eventObj\n * @return {Object}\n */\nechartsProto.makeActionFromEvent = function (eventObj) {\n    var payload = extend({}, eventObj);\n    payload.type = eventActionMap[eventObj.type];\n    return payload;\n};\n\n/**\n * @pubilc\n * @param {Object} payload\n * @param {string} [payload.type] Action type\n * @param {Object|boolean} [opt] If pass boolean, means opt.silent\n * @param {boolean} [opt.silent=false] Whether trigger events.\n * @param {boolean} [opt.flush=undefined]\n *                  true: Flush immediately, and then pixel in canvas can be fetched\n *                      immediately. Caution: it might affect performance.\n *                  false: Not not flush.\n *                  undefined: Auto decide whether perform flush.\n */\nechartsProto.dispatchAction = function (payload, opt) {\n    if (!isObject(opt)) {\n        opt = {silent: !!opt};\n    }\n\n    if (!actions[payload.type]) {\n        return;\n    }\n\n    // Avoid dispatch action before setOption. Especially in `connect`.\n    if (!this._model) {\n        return;\n    }\n\n    // May dispatchAction in rendering procedure\n    if (this[IN_MAIN_PROCESS]) {\n        this._pendingActions.push(payload);\n        return;\n    }\n\n    doDispatchAction.call(this, payload, opt.silent);\n\n    if (opt.flush) {\n        this._zr.flush(true);\n    }\n    else if (opt.flush !== false && env$1.browser.weChat) {\n        // In WeChat embeded browser, `requestAnimationFrame` and `setInterval`\n        // hang when sliding page (on touch event), which cause that zr does not\n        // refresh util user interaction finished, which is not expected.\n        // But `dispatchAction` may be called too frequently when pan on touch\n        // screen, which impacts performance if do not throttle them.\n        this._throttledZrFlush();\n    }\n\n    flushPendingActions.call(this, opt.silent);\n\n    triggerUpdatedEvent.call(this, opt.silent);\n};\n\nfunction doDispatchAction(payload, silent) {\n    var payloadType = payload.type;\n    var escapeConnect = payload.escapeConnect;\n    var actionWrap = actions[payloadType];\n    var actionInfo = actionWrap.actionInfo;\n\n    var cptType = (actionInfo.update || 'update').split(':');\n    var updateMethod = cptType.pop();\n    cptType = cptType[0] != null && parseClassType(cptType[0]);\n\n    this[IN_MAIN_PROCESS] = true;\n\n    var payloads = [payload];\n    var batched = false;\n    // Batch action\n    if (payload.batch) {\n        batched = true;\n        payloads = map(payload.batch, function (item) {\n            item = defaults(extend({}, item), payload);\n            item.batch = null;\n            return item;\n        });\n    }\n\n    var eventObjBatch = [];\n    var eventObj;\n    var isHighDown = payloadType === 'highlight' || payloadType === 'downplay';\n\n    each(payloads, function (batchItem) {\n        // Action can specify the event by return it.\n        eventObj = actionWrap.action(batchItem, this._model, this._api);\n        // Emit event outside\n        eventObj = eventObj || extend({}, batchItem);\n        // Convert type to eventType\n        eventObj.type = actionInfo.event || eventObj.type;\n        eventObjBatch.push(eventObj);\n\n        // light update does not perform data process, layout and visual.\n        if (isHighDown) {\n            // method, payload, mainType, subType\n            updateDirectly(this, updateMethod, batchItem, 'series');\n        }\n        else if (cptType) {\n            updateDirectly(this, updateMethod, batchItem, cptType.main, cptType.sub);\n        }\n    }, this);\n\n    if (updateMethod !== 'none' && !isHighDown && !cptType) {\n        // Still dirty\n        if (this[OPTION_UPDATED]) {\n            // FIXME Pass payload ?\n            prepare(this);\n            updateMethods.update.call(this, payload);\n            this[OPTION_UPDATED] = false;\n        }\n        else {\n            updateMethods[updateMethod].call(this, payload);\n        }\n    }\n\n    // Follow the rule of action batch\n    if (batched) {\n        eventObj = {\n            type: actionInfo.event || payloadType,\n            escapeConnect: escapeConnect,\n            batch: eventObjBatch\n        };\n    }\n    else {\n        eventObj = eventObjBatch[0];\n    }\n\n    this[IN_MAIN_PROCESS] = false;\n\n    !silent && this._messageCenter.trigger(eventObj.type, eventObj);\n}\n\nfunction flushPendingActions(silent) {\n    var pendingActions = this._pendingActions;\n    while (pendingActions.length) {\n        var payload = pendingActions.shift();\n        doDispatchAction.call(this, payload, silent);\n    }\n}\n\nfunction triggerUpdatedEvent(silent) {\n    !silent && this.trigger('updated');\n}\n\n/**\n * Event `rendered` is triggered when zr\n * rendered. It is useful for realtime\n * snapshot (reflect animation).\n *\n * Event `finished` is triggered when:\n * (1) zrender rendering finished.\n * (2) initial animation finished.\n * (3) progressive rendering finished.\n * (4) no pending action.\n * (5) no delayed setOption needs to be processed.\n */\nfunction bindRenderedEvent(zr, ecIns) {\n    zr.on('rendered', function () {\n\n        ecIns.trigger('rendered');\n\n        // The `finished` event should not be triggered repeatly,\n        // so it should only be triggered when rendering indeed happend\n        // in zrender. (Consider the case that dipatchAction is keep\n        // triggering when mouse move).\n        if (\n            // Although zr is dirty if initial animation is not finished\n            // and this checking is called on frame, we also check\n            // animation finished for robustness.\n            zr.animation.isFinished()\n            && !ecIns[OPTION_UPDATED]\n            && !ecIns._scheduler.unfinished\n            && !ecIns._pendingActions.length\n        ) {\n            ecIns.trigger('finished');\n        }\n    });\n}\n\n/**\n * @param {Object} params\n * @param {number} params.seriesIndex\n * @param {Array|TypedArray} params.data\n */\nechartsProto.appendData = function (params) {\n    var seriesIndex = params.seriesIndex;\n    var ecModel = this.getModel();\n    var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n\n    if (__DEV__) {\n        assert(params.data && seriesModel);\n    }\n\n    seriesModel.appendData(params);\n\n    // Note: `appendData` does not support that update extent of coordinate\n    // system, util some scenario require that. In the expected usage of\n    // `appendData`, the initial extent of coordinate system should better\n    // be fixed by axis `min`/`max` setting or initial data, otherwise if\n    // the extent changed while `appendData`, the location of the painted\n    // graphic elements have to be changed, which make the usage of\n    // `appendData` meaningless.\n\n    this._scheduler.unfinished = true;\n};\n\n/**\n * Register event\n * @method\n */\nechartsProto.on = createRegisterEventWithLowercaseName('on');\nechartsProto.off = createRegisterEventWithLowercaseName('off');\nechartsProto.one = createRegisterEventWithLowercaseName('one');\n\n/**\n * Prepare view instances of charts and components\n * @param  {module:echarts/model/Global} ecModel\n * @private\n */\nfunction prepareView(ecIns, type, ecModel, scheduler) {\n    var isComponent = type === 'component';\n    var viewList = isComponent ? ecIns._componentsViews : ecIns._chartsViews;\n    var viewMap = isComponent ? ecIns._componentsMap : ecIns._chartsMap;\n    var zr = ecIns._zr;\n    var api = ecIns._api;\n\n    for (var i = 0; i < viewList.length; i++) {\n        viewList[i].__alive = false;\n    }\n\n    isComponent\n        ? ecModel.eachComponent(function (componentType, model) {\n            componentType !== 'series' && doPrepare(model);\n        })\n        : ecModel.eachSeries(doPrepare);\n\n    function doPrepare(model) {\n        // Consider: id same and type changed.\n        var viewId = '_ec_' + model.id + '_' + model.type;\n        var view = viewMap[viewId];\n        if (!view) {\n            var classType = parseClassType(model.type);\n            var Clazz = isComponent\n                ? Component.getClass(classType.main, classType.sub)\n                : Chart.getClass(classType.sub);\n\n            if (__DEV__) {\n                assert(Clazz, classType.sub + ' does not exist.');\n            }\n\n            view = new Clazz();\n            view.init(ecModel, api);\n            viewMap[viewId] = view;\n            viewList.push(view);\n            zr.add(view.group);\n        }\n\n        model.__viewId = view.__id = viewId;\n        view.__alive = true;\n        view.__model = model;\n        view.group.__ecComponentInfo = {\n            mainType: model.mainType,\n            index: model.componentIndex\n        };\n        !isComponent && scheduler.prepareView(view, model, ecModel, api);\n    }\n\n    for (var i = 0; i < viewList.length;) {\n        var view = viewList[i];\n        if (!view.__alive) {\n            !isComponent && view.renderTask.dispose();\n            zr.remove(view.group);\n            view.dispose(ecModel, api);\n            viewList.splice(i, 1);\n            delete viewMap[view.__id];\n            view.__id = view.group.__ecComponentInfo = null;\n        }\n        else {\n            i++;\n        }\n    }\n}\n\n// /**\n//  * Encode visual infomation from data after data processing\n//  *\n//  * @param {module:echarts/model/Global} ecModel\n//  * @param {object} layout\n//  * @param {boolean} [layoutFilter] `true`: only layout,\n//  *                                 `false`: only not layout,\n//  *                                 `null`/`undefined`: all.\n//  * @param {string} taskBaseTag\n//  * @private\n//  */\n// function startVisualEncoding(ecIns, ecModel, api, payload, layoutFilter) {\n//     each(visualFuncs, function (visual, index) {\n//         var isLayout = visual.isLayout;\n//         if (layoutFilter == null\n//             || (layoutFilter === false && !isLayout)\n//             || (layoutFilter === true && isLayout)\n//         ) {\n//             visual.func(ecModel, api, payload);\n//         }\n//     });\n// }\n\nfunction clearColorPalette(ecModel) {\n    ecModel.clearColorPalette();\n    ecModel.eachSeries(function (seriesModel) {\n        seriesModel.clearColorPalette();\n    });\n}\n\nfunction render(ecIns, ecModel, api, payload) {\n\n    renderComponents(ecIns, ecModel, api, payload);\n\n    each(ecIns._chartsViews, function (chart) {\n        chart.__alive = false;\n    });\n\n    renderSeries(ecIns, ecModel, api, payload);\n\n    // Remove groups of unrendered charts\n    each(ecIns._chartsViews, function (chart) {\n        if (!chart.__alive) {\n            chart.remove(ecModel, api);\n        }\n    });\n}\n\nfunction renderComponents(ecIns, ecModel, api, payload, dirtyList) {\n    each(dirtyList || ecIns._componentsViews, function (componentView) {\n        var componentModel = componentView.__model;\n        componentView.render(componentModel, ecModel, api, payload);\n\n        updateZ(componentModel, componentView);\n    });\n}\n\n/**\n * Render each chart and component\n * @private\n */\nfunction renderSeries(ecIns, ecModel, api, payload, dirtyMap) {\n    // Render all charts\n    var scheduler = ecIns._scheduler;\n    var unfinished;\n    ecModel.eachSeries(function (seriesModel) {\n        var chartView = ecIns._chartsMap[seriesModel.__viewId];\n        chartView.__alive = true;\n\n        var renderTask = chartView.renderTask;\n        scheduler.updatePayload(renderTask, payload);\n\n        if (dirtyMap && dirtyMap.get(seriesModel.uid)) {\n            renderTask.dirty();\n        }\n\n        unfinished |= renderTask.perform(scheduler.getPerformArgs(renderTask));\n\n        chartView.group.silent = !!seriesModel.get('silent');\n\n        updateZ(seriesModel, chartView);\n\n        updateBlend(seriesModel, chartView);\n    });\n    scheduler.unfinished |= unfinished;\n\n    // If use hover layer\n    updateHoverLayerStatus(ecIns._zr, ecModel);\n\n    // Add aria\n    aria(ecIns._zr.dom, ecModel);\n}\n\nfunction performPostUpdateFuncs(ecModel, api) {\n    each(postUpdateFuncs, function (func) {\n        func(ecModel, api);\n    });\n}\n\n\nvar MOUSE_EVENT_NAMES = [\n    'click', 'dblclick', 'mouseover', 'mouseout', 'mousemove',\n    'mousedown', 'mouseup', 'globalout', 'contextmenu'\n];\n\n/**\n * @private\n */\nechartsProto._initEvents = function () {\n    each(MOUSE_EVENT_NAMES, function (eveName) {\n        var handler = function (e) {\n            var ecModel = this.getModel();\n            var el = e.target;\n            var params;\n            var isGlobalOut = eveName === 'globalout';\n\n            // no e.target when 'globalout'.\n            if (isGlobalOut) {\n                params = {};\n            }\n            else if (el && el.dataIndex != null) {\n                var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex);\n                params = dataModel && dataModel.getDataParams(el.dataIndex, el.dataType, el) || {};\n            }\n            // If element has custom eventData of components\n            else if (el && el.eventData) {\n                params = extend({}, el.eventData);\n            }\n\n            // Contract: if params prepared in mouse event,\n            // these properties must be specified:\n            // {\n            //    componentType: string (component main type)\n            //    componentIndex: number\n            // }\n            // Otherwise event query can not work.\n\n            if (params) {\n                var componentType = params.componentType;\n                var componentIndex = params.componentIndex;\n                // Special handling for historic reason: when trigger by\n                // markLine/markPoint/markArea, the componentType is\n                // 'markLine'/'markPoint'/'markArea', but we should better\n                // enable them to be queried by seriesIndex, since their\n                // option is set in each series.\n                if (componentType === 'markLine'\n                    || componentType === 'markPoint'\n                    || componentType === 'markArea'\n                ) {\n                    componentType = 'series';\n                    componentIndex = params.seriesIndex;\n                }\n                var model = componentType && componentIndex != null\n                    && ecModel.getComponent(componentType, componentIndex);\n                var view = model && this[\n                    model.mainType === 'series' ? '_chartsMap' : '_componentsMap'\n                ][model.__viewId];\n\n                if (__DEV__) {\n                    // `event.componentType` and `event[componentTpype + 'Index']` must not\n                    // be missed, otherwise there is no way to distinguish source component.\n                    // See `dataFormat.getDataParams`.\n                    if (!isGlobalOut && !(model && view)) {\n                        console.warn('model or view can not be found by params');\n                    }\n                }\n\n                params.event = e;\n                params.type = eveName;\n\n                this._ecEventProcessor.eventInfo = {\n                    targetEl: el,\n                    packedEvent: params,\n                    model: model,\n                    view: view\n                };\n\n                this.trigger(eveName, params);\n            }\n        };\n        // Consider that some component (like tooltip, brush, ...)\n        // register zr event handler, but user event handler might\n        // do anything, such as call `setOption` or `dispatchAction`,\n        // which probably update any of the content and probably\n        // cause problem if it is called previous other inner handlers.\n        handler.zrEventfulCallAtLast = true;\n        this._zr.on(eveName, handler, this);\n    }, this);\n\n    each(eventActionMap, function (actionType, eventType) {\n        this._messageCenter.on(eventType, function (event) {\n            this.trigger(eventType, event);\n        }, this);\n    }, this);\n};\n\n/**\n * @return {boolean}\n */\nechartsProto.isDisposed = function () {\n    return this._disposed;\n};\n\n/**\n * Clear\n */\nechartsProto.clear = function () {\n    this.setOption({ series: [] }, true);\n};\n\n/**\n * Dispose instance\n */\nechartsProto.dispose = function () {\n    if (this._disposed) {\n        if (__DEV__) {\n            console.warn('Instance ' + this.id + ' has been disposed');\n        }\n        return;\n    }\n    this._disposed = true;\n\n    setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, '');\n\n    var api = this._api;\n    var ecModel = this._model;\n\n    each(this._componentsViews, function (component) {\n        component.dispose(ecModel, api);\n    });\n    each(this._chartsViews, function (chart) {\n        chart.dispose(ecModel, api);\n    });\n\n    // Dispose after all views disposed\n    this._zr.dispose();\n\n    delete instances[this.id];\n};\n\nmixin(ECharts, Eventful);\n\nfunction updateHoverLayerStatus(zr, ecModel) {\n    var storage = zr.storage;\n    var elCount = 0;\n    storage.traverse(function (el) {\n        if (!el.isGroup) {\n            elCount++;\n        }\n    });\n    if (elCount > ecModel.get('hoverLayerThreshold') && !env$1.node) {\n        storage.traverse(function (el) {\n            if (!el.isGroup) {\n                // Don't switch back.\n                el.useHoverLayer = true;\n            }\n        });\n    }\n}\n\n/**\n * Update chart progressive and blend.\n * @param {module:echarts/model/Series|module:echarts/model/Component} model\n * @param {module:echarts/view/Component|module:echarts/view/Chart} view\n */\nfunction updateBlend(seriesModel, chartView) {\n    var blendMode = seriesModel.get('blendMode') || null;\n    if (__DEV__) {\n        if (!env$1.canvasSupported && blendMode && blendMode !== 'source-over') {\n            console.warn('Only canvas support blendMode');\n        }\n    }\n    chartView.group.traverse(function (el) {\n        // FIXME marker and other components\n        if (!el.isGroup) {\n            // Only set if blendMode is changed. In case element is incremental and don't wan't to rerender.\n            if (el.style.blend !== blendMode) {\n                el.setStyle('blend', blendMode);\n            }\n        }\n        if (el.eachPendingDisplayable) {\n            el.eachPendingDisplayable(function (displayable) {\n                displayable.setStyle('blend', blendMode);\n            });\n        }\n    });\n}\n\n/**\n * @param {module:echarts/model/Series|module:echarts/model/Component} model\n * @param {module:echarts/view/Component|module:echarts/view/Chart} view\n */\nfunction updateZ(model, view) {\n    var z = model.get('z');\n    var zlevel = model.get('zlevel');\n    // Set z and zlevel\n    view.group.traverse(function (el) {\n        if (el.type !== 'group') {\n            z != null && (el.z = z);\n            zlevel != null && (el.zlevel = zlevel);\n        }\n    });\n}\n\nfunction createExtensionAPI(ecInstance) {\n    var coordSysMgr = ecInstance._coordSysMgr;\n    return extend(new ExtensionAPI(ecInstance), {\n        // Inject methods\n        getCoordinateSystems: bind(\n            coordSysMgr.getCoordinateSystems, coordSysMgr\n        ),\n        getComponentByElement: function (el) {\n            while (el) {\n                var modelInfo = el.__ecComponentInfo;\n                if (modelInfo != null) {\n                    return ecInstance._model.getComponent(modelInfo.mainType, modelInfo.index);\n                }\n                el = el.parent;\n            }\n        }\n    });\n}\n\n\n/**\n * @class\n * Usage of query:\n * `chart.on('click', query, handler);`\n * The `query` can be:\n * + The component type query string, only `mainType` or `mainType.subType`,\n *   like: 'xAxis', 'series', 'xAxis.category' or 'series.line'.\n * + The component query object, like:\n *   `{seriesIndex: 2}`, `{seriesName: 'xx'}`, `{seriesId: 'some'}`,\n *   `{xAxisIndex: 2}`, `{xAxisName: 'xx'}`, `{xAxisId: 'some'}`.\n * + The data query object, like:\n *   `{dataIndex: 123}`, `{dataType: 'link'}`, `{name: 'some'}`.\n * + The other query object (cmponent customized query), like:\n *   `{element: 'some'}` (only available in custom series).\n *\n * Caveat: If a prop in the `query` object is `null/undefined`, it is the\n * same as there is no such prop in the `query` object.\n */\nfunction EventProcessor() {\n    // These info required: targetEl, packedEvent, model, view\n    this.eventInfo;\n}\nEventProcessor.prototype = {\n    constructor: EventProcessor,\n\n    normalizeQuery: function (query) {\n        var cptQuery = {};\n        var dataQuery = {};\n        var otherQuery = {};\n\n        // `query` is `mainType` or `mainType.subType` of component.\n        if (isString(query)) {\n            var condCptType = parseClassType(query);\n            // `.main` and `.sub` may be ''.\n            cptQuery.mainType = condCptType.main || null;\n            cptQuery.subType = condCptType.sub || null;\n        }\n        // `query` is an object, convert to {mainType, index, name, id}.\n        else {\n            // `xxxIndex`, `xxxName`, `xxxId`, `name`, `dataIndex`, `dataType` is reserved,\n            // can not be used in `compomentModel.filterForExposedEvent`.\n            var suffixes = ['Index', 'Name', 'Id'];\n            var dataKeys = {name: 1, dataIndex: 1, dataType: 1};\n            each$1(query, function (val, key) {\n                var reserved = false;\n                for (var i = 0; i < suffixes.length; i++) {\n                    var propSuffix = suffixes[i];\n                    var suffixPos = key.lastIndexOf(propSuffix);\n                    if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) {\n                        var mainType = key.slice(0, suffixPos);\n                        // Consider `dataIndex`.\n                        if (mainType !== 'data') {\n                            cptQuery.mainType = mainType;\n                            cptQuery[propSuffix.toLowerCase()] = val;\n                            reserved = true;\n                        }\n                    }\n                }\n                if (dataKeys.hasOwnProperty(key)) {\n                    dataQuery[key] = val;\n                    reserved = true;\n                }\n                if (!reserved) {\n                    otherQuery[key] = val;\n                }\n            });\n        }\n\n        return {\n            cptQuery: cptQuery,\n            dataQuery: dataQuery,\n            otherQuery: otherQuery\n        };\n    },\n\n    filter: function (eventType, query, args) {\n        // They should be assigned before each trigger call.\n        var eventInfo = this.eventInfo;\n\n        if (!eventInfo) {\n            return true;\n        }\n\n        var targetEl = eventInfo.targetEl;\n        var packedEvent = eventInfo.packedEvent;\n        var model = eventInfo.model;\n        var view = eventInfo.view;\n\n        // For event like 'globalout'.\n        if (!model || !view) {\n            return true;\n        }\n\n        var cptQuery = query.cptQuery;\n        var dataQuery = query.dataQuery;\n\n        return check(cptQuery, model, 'mainType')\n            && check(cptQuery, model, 'subType')\n            && check(cptQuery, model, 'index', 'componentIndex')\n            && check(cptQuery, model, 'name')\n            && check(cptQuery, model, 'id')\n            && check(dataQuery, packedEvent, 'name')\n            && check(dataQuery, packedEvent, 'dataIndex')\n            && check(dataQuery, packedEvent, 'dataType')\n            && (!view.filterForExposedEvent || view.filterForExposedEvent(\n                eventType, query.otherQuery, targetEl, packedEvent\n            ));\n\n        function check(query, host, prop, propOnHost) {\n            return query[prop] == null || host[propOnHost || prop] === query[prop];\n        }\n    },\n\n    afterTrigger: function () {\n        // Make sure the eventInfo wont be used in next trigger.\n        this.eventInfo = null;\n    }\n};\n\n\n/**\n * @type {Object} key: actionType.\n * @inner\n */\nvar actions = {};\n\n/**\n * Map eventType to actionType\n * @type {Object}\n */\nvar eventActionMap = {};\n\n/**\n * Data processor functions of each stage\n * @type {Array.<Object.<string, Function>>}\n * @inner\n */\nvar dataProcessorFuncs = [];\n\n/**\n * @type {Array.<Function>}\n * @inner\n */\nvar optionPreprocessorFuncs = [];\n\n/**\n * @type {Array.<Function>}\n * @inner\n */\nvar postUpdateFuncs = [];\n\n/**\n * Visual encoding functions of each stage\n * @type {Array.<Object.<string, Function>>}\n */\nvar visualFuncs = [];\n\n/**\n * Theme storage\n * @type {Object.<key, Object>}\n */\nvar themeStorage = {};\n/**\n * Loading effects\n */\nvar loadingEffects = {};\n\nvar instances = {};\nvar connectedGroups = {};\n\nvar idBase = new Date() - 0;\nvar groupIdBase = new Date() - 0;\nvar DOM_ATTRIBUTE_KEY = '_echarts_instance_';\n\nfunction enableConnect(chart) {\n    var STATUS_PENDING = 0;\n    var STATUS_UPDATING = 1;\n    var STATUS_UPDATED = 2;\n    var STATUS_KEY = '__connectUpdateStatus';\n\n    function updateConnectedChartsStatus(charts, status) {\n        for (var i = 0; i < charts.length; i++) {\n            var otherChart = charts[i];\n            otherChart[STATUS_KEY] = status;\n        }\n    }\n\n    each(eventActionMap, function (actionType, eventType) {\n        chart._messageCenter.on(eventType, function (event) {\n            if (connectedGroups[chart.group] && chart[STATUS_KEY] !== STATUS_PENDING) {\n                if (event && event.escapeConnect) {\n                    return;\n                }\n\n                var action = chart.makeActionFromEvent(event);\n                var otherCharts = [];\n\n                each(instances, function (otherChart) {\n                    if (otherChart !== chart && otherChart.group === chart.group) {\n                        otherCharts.push(otherChart);\n                    }\n                });\n\n                updateConnectedChartsStatus(otherCharts, STATUS_PENDING);\n                each(otherCharts, function (otherChart) {\n                    if (otherChart[STATUS_KEY] !== STATUS_UPDATING) {\n                        otherChart.dispatchAction(action);\n                    }\n                });\n                updateConnectedChartsStatus(otherCharts, STATUS_UPDATED);\n            }\n        });\n    });\n}\n\n/**\n * @param {HTMLElement} dom\n * @param {Object} [theme]\n * @param {Object} opts\n * @param {number} [opts.devicePixelRatio] Use window.devicePixelRatio by default\n * @param {string} [opts.renderer] Currently only 'canvas' is supported.\n * @param {number} [opts.width] Use clientWidth of the input `dom` by default.\n *                              Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Use clientHeight of the input `dom` by default.\n *                               Can be 'auto' (the same as null/undefined)\n */\nfunction init(dom, theme$$1, opts) {\n    if (__DEV__) {\n        // Check version\n        if ((version$1.replace('.', '') - 0) < (dependencies.zrender.replace('.', '') - 0)) {\n            throw new Error(\n                'zrender/src ' + version$1\n                + ' is too old for ECharts ' + version\n                + '. Current version need ZRender '\n                + dependencies.zrender + '+'\n            );\n        }\n\n        if (!dom) {\n            throw new Error('Initialize failed: invalid dom.');\n        }\n    }\n\n    var existInstance = getInstanceByDom(dom);\n    if (existInstance) {\n        if (__DEV__) {\n            console.warn('There is a chart instance already initialized on the dom.');\n        }\n        return existInstance;\n    }\n\n    if (__DEV__) {\n        if (isDom(dom)\n            && dom.nodeName.toUpperCase() !== 'CANVAS'\n            && (\n                (!dom.clientWidth && (!opts || opts.width == null))\n                || (!dom.clientHeight && (!opts || opts.height == null))\n            )\n        ) {\n            console.warn('Can\\'t get dom width or height');\n        }\n    }\n\n    var chart = new ECharts(dom, theme$$1, opts);\n    chart.id = 'ec_' + idBase++;\n    instances[chart.id] = chart;\n\n    setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id);\n\n    enableConnect(chart);\n\n    return chart;\n}\n\n/**\n * @return {string|Array.<module:echarts~ECharts>} groupId\n */\nfunction connect(groupId) {\n    // Is array of charts\n    if (isArray(groupId)) {\n        var charts = groupId;\n        groupId = null;\n        // If any chart has group\n        each(charts, function (chart) {\n            if (chart.group != null) {\n                groupId = chart.group;\n            }\n        });\n        groupId = groupId || ('g_' + groupIdBase++);\n        each(charts, function (chart) {\n            chart.group = groupId;\n        });\n    }\n    connectedGroups[groupId] = true;\n    return groupId;\n}\n\n/**\n * @DEPRECATED\n * @return {string} groupId\n */\nfunction disConnect(groupId) {\n    connectedGroups[groupId] = false;\n}\n\n/**\n * @return {string} groupId\n */\nvar disconnect = disConnect;\n\n/**\n * Dispose a chart instance\n * @param  {module:echarts~ECharts|HTMLDomElement|string} chart\n */\nfunction dispose(chart) {\n    if (typeof chart === 'string') {\n        chart = instances[chart];\n    }\n    else if (!(chart instanceof ECharts)) {\n        // Try to treat as dom\n        chart = getInstanceByDom(chart);\n    }\n    if ((chart instanceof ECharts) && !chart.isDisposed()) {\n        chart.dispose();\n    }\n}\n\n/**\n * @param  {HTMLElement} dom\n * @return {echarts~ECharts}\n */\nfunction getInstanceByDom(dom) {\n    return instances[getAttribute(dom, DOM_ATTRIBUTE_KEY)];\n}\n\n/**\n * @param {string} key\n * @return {echarts~ECharts}\n */\nfunction getInstanceById(key) {\n    return instances[key];\n}\n\n/**\n * Register theme\n */\nfunction registerTheme(name, theme$$1) {\n    themeStorage[name] = theme$$1;\n}\n\n/**\n * Register option preprocessor\n * @param {Function} preprocessorFunc\n */\nfunction registerPreprocessor(preprocessorFunc) {\n    optionPreprocessorFuncs.push(preprocessorFunc);\n}\n\n/**\n * @param {number} [priority=1000]\n * @param {Object|Function} processor\n */\nfunction registerProcessor(priority, processor) {\n    normalizeRegister(dataProcessorFuncs, priority, processor, PRIORITY_PROCESSOR_FILTER);\n}\n\n/**\n * Register postUpdater\n * @param {Function} postUpdateFunc\n */\nfunction registerPostUpdate(postUpdateFunc) {\n    postUpdateFuncs.push(postUpdateFunc);\n}\n\n/**\n * Usage:\n * registerAction('someAction', 'someEvent', function () { ... });\n * registerAction('someAction', function () { ... });\n * registerAction(\n *     {type: 'someAction', event: 'someEvent', update: 'updateView'},\n *     function () { ... }\n * );\n *\n * @param {(string|Object)} actionInfo\n * @param {string} actionInfo.type\n * @param {string} [actionInfo.event]\n * @param {string} [actionInfo.update]\n * @param {string} [eventName]\n * @param {Function} action\n */\nfunction registerAction(actionInfo, eventName, action) {\n    if (typeof eventName === 'function') {\n        action = eventName;\n        eventName = '';\n    }\n    var actionType = isObject(actionInfo)\n        ? actionInfo.type\n        : ([actionInfo, actionInfo = {\n            event: eventName\n        }][0]);\n\n    // Event name is all lowercase\n    actionInfo.event = (actionInfo.event || actionType).toLowerCase();\n    eventName = actionInfo.event;\n\n    // Validate action type and event name.\n    assert(ACTION_REG.test(actionType) && ACTION_REG.test(eventName));\n\n    if (!actions[actionType]) {\n        actions[actionType] = {action: action, actionInfo: actionInfo};\n    }\n    eventActionMap[eventName] = actionType;\n}\n\n/**\n * @param {string} type\n * @param {*} CoordinateSystem\n */\nfunction registerCoordinateSystem(type, CoordinateSystem$$1) {\n    CoordinateSystemManager.register(type, CoordinateSystem$$1);\n}\n\n/**\n * Get dimensions of specified coordinate system.\n * @param {string} type\n * @return {Array.<string|Object>}\n */\nfunction getCoordinateSystemDimensions(type) {\n    var coordSysCreator = CoordinateSystemManager.get(type);\n    if (coordSysCreator) {\n        return coordSysCreator.getDimensionsInfo\n                ? coordSysCreator.getDimensionsInfo()\n                : coordSysCreator.dimensions.slice();\n    }\n}\n\n/**\n * Layout is a special stage of visual encoding\n * Most visual encoding like color are common for different chart\n * But each chart has it's own layout algorithm\n *\n * @param {number} [priority=1000]\n * @param {Function} layoutTask\n */\nfunction registerLayout(priority, layoutTask) {\n    normalizeRegister(visualFuncs, priority, layoutTask, PRIORITY_VISUAL_LAYOUT, 'layout');\n}\n\n/**\n * @param {number} [priority=3000]\n * @param {module:echarts/stream/Task} visualTask\n */\nfunction registerVisual(priority, visualTask) {\n    normalizeRegister(visualFuncs, priority, visualTask, PRIORITY_VISUAL_CHART, 'visual');\n}\n\n/**\n * @param {Object|Function} fn: {seriesType, createOnAllSeries, performRawSeries, reset}\n */\nfunction normalizeRegister(targetList, priority, fn, defaultPriority, visualType) {\n    if (isFunction(priority) || isObject(priority)) {\n        fn = priority;\n        priority = defaultPriority;\n    }\n\n    if (__DEV__) {\n        if (isNaN(priority) || priority == null) {\n            throw new Error('Illegal priority');\n        }\n        // Check duplicate\n        each(targetList, function (wrap) {\n            assert(wrap.__raw !== fn);\n        });\n    }\n\n    var stageHandler = Scheduler.wrapStageHandler(fn, visualType);\n\n    stageHandler.__prio = priority;\n    stageHandler.__raw = fn;\n    targetList.push(stageHandler);\n\n    return stageHandler;\n}\n\n/**\n * @param {string} name\n */\nfunction registerLoading(name, loadingFx) {\n    loadingEffects[name] = loadingFx;\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendComponentModel(opts/*, superClass*/) {\n    // var Clazz = ComponentModel;\n    // if (superClass) {\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentModel.getClass(classType.main, classType.sub, true);\n    // }\n    return ComponentModel.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendComponentView(opts/*, superClass*/) {\n    // var Clazz = ComponentView;\n    // if (superClass) {\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentView.getClass(classType.main, classType.sub, true);\n    // }\n    return Component.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendSeriesModel(opts/*, superClass*/) {\n    // var Clazz = SeriesModel;\n    // if (superClass) {\n    //     superClass = 'series.' + superClass.replace('series.', '');\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentModel.getClass(classType.main, classType.sub, true);\n    // }\n    return SeriesModel.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendChartView(opts/*, superClass*/) {\n    // var Clazz = ChartView;\n    // if (superClass) {\n    //     superClass = superClass.replace('series.', '');\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ChartView.getClass(classType.main, true);\n    // }\n    return Chart.extend(opts);\n}\n\n/**\n * ZRender need a canvas context to do measureText.\n * But in node environment canvas may be created by node-canvas.\n * So we need to specify how to create a canvas instead of using document.createElement('canvas')\n *\n * Be careful of using it in the browser.\n *\n * @param {Function} creator\n * @example\n *     var Canvas = require('canvas');\n *     var echarts = require('echarts');\n *     echarts.setCanvasCreator(function () {\n *         // Small size is enough.\n *         return new Canvas(32, 32);\n *     });\n */\nfunction setCanvasCreator(creator) {\n    $override('createCanvas', creator);\n}\n\n/**\n * @param {string} mapName\n * @param {Array.<Object>|Object|string} geoJson\n * @param {Object} [specialAreas]\n *\n * @example GeoJSON\n *     $.get('USA.json', function (geoJson) {\n *         echarts.registerMap('USA', geoJson);\n *         // Or\n *         echarts.registerMap('USA', {\n *             geoJson: geoJson,\n *             specialAreas: {}\n *         })\n *     });\n *\n *     $.get('airport.svg', function (svg) {\n *         echarts.registerMap('airport', {\n *             svg: svg\n *         }\n *     });\n *\n *     echarts.registerMap('eu', [\n *         {svg: eu-topographic.svg},\n *         {geoJSON: eu.json}\n *     ])\n */\nfunction registerMap(mapName, geoJson, specialAreas) {\n    mapDataStorage.registerMap(mapName, geoJson, specialAreas);\n}\n\n/**\n * @param {string} mapName\n * @return {Object}\n */\nfunction getMap(mapName) {\n    // For backward compatibility, only return the first one.\n    var records = mapDataStorage.retrieveMap(mapName);\n    return records && records[0] && {\n        geoJson: records[0].geoJSON,\n        specialAreas: records[0].specialAreas\n    };\n}\n\nregisterVisual(PRIORITY_VISUAL_GLOBAL, seriesColor);\nregisterPreprocessor(backwardCompat);\nregisterProcessor(PRIORITY_PROCESSOR_STATISTIC, dataStack);\nregisterLoading('default', loadingDefault);\n\n// Default actions\n\nregisterAction({\n    type: 'highlight',\n    event: 'highlight',\n    update: 'highlight'\n}, noop);\n\nregisterAction({\n    type: 'downplay',\n    event: 'downplay',\n    update: 'downplay'\n}, noop);\n\n// Default theme\nregisterTheme('light', lightTheme);\nregisterTheme('dark', theme);\n\n// For backward compatibility, where the namespace `dataTool` will\n// be mounted on `echarts` is the extension `dataTool` is imported.\nvar dataTool = {};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction defaultKeyGetter(item) {\n    return item;\n}\n\n/**\n * @param {Array} oldArr\n * @param {Array} newArr\n * @param {Function} oldKeyGetter\n * @param {Function} newKeyGetter\n * @param {Object} [context] Can be visited by this.context in callback.\n */\nfunction DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter, context) {\n    this._old = oldArr;\n    this._new = newArr;\n\n    this._oldKeyGetter = oldKeyGetter || defaultKeyGetter;\n    this._newKeyGetter = newKeyGetter || defaultKeyGetter;\n\n    this.context = context;\n}\n\nDataDiffer.prototype = {\n\n    constructor: DataDiffer,\n\n    /**\n     * Callback function when add a data\n     */\n    add: function (func) {\n        this._add = func;\n        return this;\n    },\n\n    /**\n     * Callback function when update a data\n     */\n    update: function (func) {\n        this._update = func;\n        return this;\n    },\n\n    /**\n     * Callback function when remove a data\n     */\n    remove: function (func) {\n        this._remove = func;\n        return this;\n    },\n\n    execute: function () {\n        var oldArr = this._old;\n        var newArr = this._new;\n\n        var oldDataIndexMap = {};\n        var newDataIndexMap = {};\n        var oldDataKeyArr = [];\n        var newDataKeyArr = [];\n        var i;\n\n        initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, '_oldKeyGetter', this);\n        initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter', this);\n\n        // Travel by inverted order to make sure order consistency\n        // when duplicate keys exists (consider newDataIndex.pop() below).\n        // For performance consideration, these code below do not look neat.\n        for (i = 0; i < oldArr.length; i++) {\n            var key = oldDataKeyArr[i];\n            var idx = newDataIndexMap[key];\n\n            // idx can never be empty array here. see 'set null' logic below.\n            if (idx != null) {\n                // Consider there is duplicate key (for example, use dataItem.name as key).\n                // We should make sure every item in newArr and oldArr can be visited.\n                var len = idx.length;\n                if (len) {\n                    len === 1 && (newDataIndexMap[key] = null);\n                    idx = idx.unshift();\n                }\n                else {\n                    newDataIndexMap[key] = null;\n                }\n                this._update && this._update(idx, i);\n            }\n            else {\n                this._remove && this._remove(i);\n            }\n        }\n\n        for (var i = 0; i < newDataKeyArr.length; i++) {\n            var key = newDataKeyArr[i];\n            if (newDataIndexMap.hasOwnProperty(key)) {\n                var idx = newDataIndexMap[key];\n                if (idx == null) {\n                    continue;\n                }\n                // idx can never be empty array here. see 'set null' logic above.\n                if (!idx.length) {\n                    this._add && this._add(idx);\n                }\n                else {\n                    for (var j = 0, len = idx.length; j < len; j++) {\n                        this._add && this._add(idx[j]);\n                    }\n                }\n            }\n        }\n    }\n};\n\nfunction initIndexMap(arr, map, keyArr, keyGetterName, dataDiffer) {\n    for (var i = 0; i < arr.length; i++) {\n        // Add prefix to avoid conflict with Object.prototype.\n        var key = '_ec_' + dataDiffer[keyGetterName](arr[i], i);\n        var existence = map[key];\n        if (existence == null) {\n            keyArr.push(key);\n            map[key] = i;\n        }\n        else {\n            if (!existence.length) {\n                map[key] = existence = [existence];\n            }\n            existence.push(i);\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar OTHER_DIMENSIONS = createHashMap([\n    'tooltip', 'label', 'itemName', 'itemId', 'seriesName'\n]);\n\nfunction summarizeDimensions(data) {\n    var summary = {};\n    var encode = summary.encode = {};\n    var notExtraCoordDimMap = createHashMap();\n    var defaultedLabel = [];\n    var defaultedTooltip = [];\n\n    each$1(data.dimensions, function (dimName) {\n        var dimItem = data.getDimensionInfo(dimName);\n\n        var coordDim = dimItem.coordDim;\n        if (coordDim) {\n            if (__DEV__) {\n                assert$1(OTHER_DIMENSIONS.get(coordDim) == null);\n            }\n            var coordDimArr = encode[coordDim];\n            if (!encode.hasOwnProperty(coordDim)) {\n                coordDimArr = encode[coordDim] = [];\n            }\n            coordDimArr[dimItem.coordDimIndex] = dimName;\n\n            if (!dimItem.isExtraCoord) {\n                notExtraCoordDimMap.set(coordDim, 1);\n\n                // Use the last coord dim (and label friendly) as default label,\n                // because when dataset is used, it is hard to guess which dimension\n                // can be value dimension. If both show x, y on label is not look good,\n                // and conventionally y axis is focused more.\n                if (mayLabelDimType(dimItem.type)) {\n                    defaultedLabel[0] = dimName;\n                }\n            }\n            if (dimItem.defaultTooltip) {\n                defaultedTooltip.push(dimName);\n            }\n        }\n\n        OTHER_DIMENSIONS.each(function (v, otherDim) {\n            var otherDimArr = encode[otherDim];\n            if (!encode.hasOwnProperty(otherDim)) {\n                otherDimArr = encode[otherDim] = [];\n            }\n\n            var dimIndex = dimItem.otherDims[otherDim];\n            if (dimIndex != null && dimIndex !== false) {\n                otherDimArr[dimIndex] = dimItem.name;\n            }\n        });\n    });\n\n    var dataDimsOnCoord = [];\n    var encodeFirstDimNotExtra = {};\n\n    notExtraCoordDimMap.each(function (v, coordDim) {\n        var dimArr = encode[coordDim];\n        // ??? FIXME extra coord should not be set in dataDimsOnCoord.\n        // But should fix the case that radar axes: simplify the logic\n        // of `completeDimension`, remove `extraPrefix`.\n        encodeFirstDimNotExtra[coordDim] = dimArr[0];\n        // Not necessary to remove duplicate, because a data\n        // dim canot on more than one coordDim.\n        dataDimsOnCoord = dataDimsOnCoord.concat(dimArr);\n    });\n\n    summary.dataDimsOnCoord = dataDimsOnCoord;\n    summary.encodeFirstDimNotExtra = encodeFirstDimNotExtra;\n\n    var encodeLabel = encode.label;\n    // FIXME `encode.label` is not recommanded, because formatter can not be set\n    // in this way. Use label.formatter instead. May be remove this approach someday.\n    if (encodeLabel && encodeLabel.length) {\n        defaultedLabel = encodeLabel.slice();\n    }\n\n    var encodeTooltip = encode.tooltip;\n    if (encodeTooltip && encodeTooltip.length) {\n        defaultedTooltip = encodeTooltip.slice();\n    }\n    else if (!defaultedTooltip.length) {\n        defaultedTooltip = defaultedLabel.slice();\n    }\n\n    encode.defaultedLabel = defaultedLabel;\n    encode.defaultedTooltip = defaultedTooltip;\n\n    return summary;\n}\n\nfunction getDimensionTypeByAxis(axisType) {\n    return axisType === 'category'\n        ? 'ordinal'\n        : axisType === 'time'\n        ? 'time'\n        : 'float';\n}\n\nfunction mayLabelDimType(dimType) {\n    // In most cases, ordinal and time do not suitable for label.\n    // Ordinal info can be displayed on axis. Time is too long.\n    return !(dimType === 'ordinal' || dimType === 'time');\n}\n\n// function findTheLastDimMayLabel(data) {\n//     // Get last value dim\n//     var dimensions = data.dimensions.slice();\n//     var valueType;\n//     var valueDim;\n//     while (dimensions.length && (\n//         valueDim = dimensions.pop(),\n//         valueType = data.getDimensionInfo(valueDim).type,\n//         valueType === 'ordinal' || valueType === 'time'\n//     )) {} // jshint ignore:line\n//     return valueDim;\n// }\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float64Array, Int32Array, Uint32Array, Uint16Array */\n\n/**\n * List for data storage\n * @module echarts/data/List\n */\n\nvar isObject$4 = isObject$1;\n\nvar UNDEFINED = 'undefined';\nvar INDEX_NOT_FOUND = -1;\n\n// Use prefix to avoid index to be the same as otherIdList[idx],\n// which will cause weird udpate animation.\nvar ID_PREFIX = 'e\\0\\0';\n\nvar dataCtors = {\n    'float': typeof Float64Array === UNDEFINED\n        ? Array : Float64Array,\n    'int': typeof Int32Array === UNDEFINED\n        ? Array : Int32Array,\n    // Ordinal data type can be string or int\n    'ordinal': Array,\n    'number': Array,\n    'time': Array\n};\n\n// Caution: MUST not use `new CtorUint32Array(arr, 0, len)`, because the Ctor of array is\n// different from the Ctor of typed array.\nvar CtorUint32Array = typeof Uint32Array === UNDEFINED ? Array : Uint32Array;\nvar CtorInt32Array = typeof Int32Array === UNDEFINED ? Array : Int32Array;\nvar CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array;\n\nfunction getIndicesCtor(list) {\n    // The possible max value in this._indicies is always this._rawCount despite of filtering.\n    return list._rawCount > 65535 ? CtorUint32Array : CtorUint16Array;\n}\n\nfunction cloneChunk(originalChunk) {\n    var Ctor = originalChunk.constructor;\n    // Only shallow clone is enough when Array.\n    return Ctor === Array ? originalChunk.slice() : new Ctor(originalChunk);\n}\n\nvar TRANSFERABLE_PROPERTIES = [\n    'hasItemOption', '_nameList', '_idList', '_invertedIndicesMap',\n    '_rawData', '_chunkSize', '_chunkCount', '_dimValueGetter',\n    '_count', '_rawCount', '_nameDimIdx', '_idDimIdx'\n];\nvar CLONE_PROPERTIES = [\n    '_extent', '_approximateExtent', '_rawExtent'\n];\n\nfunction transferProperties(target, source) {\n    each$1(TRANSFERABLE_PROPERTIES.concat(source.__wrappedMethods || []), function (propName) {\n        if (source.hasOwnProperty(propName)) {\n            target[propName] = source[propName];\n        }\n    });\n\n    target.__wrappedMethods = source.__wrappedMethods;\n\n    each$1(CLONE_PROPERTIES, function (propName) {\n        target[propName] = clone(source[propName]);\n    });\n\n    target._calculationInfo = extend(source._calculationInfo);\n}\n\n\n\n\n\n/**\n * @constructor\n * @alias module:echarts/data/List\n *\n * @param {Array.<string|Object>} dimensions\n *      For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...].\n *      Dimensions should be concrete names like x, y, z, lng, lat, angle, radius\n *      Spetial fields: {\n *          ordinalMeta: <module:echarts/data/OrdinalMeta>\n *          createInvertedIndices: <boolean>\n *      }\n * @param {module:echarts/model/Model} hostModel\n */\nvar List = function (dimensions, hostModel) {\n\n    dimensions = dimensions || ['x', 'y'];\n\n    var dimensionInfos = {};\n    var dimensionNames = [];\n    var invertedIndicesMap = {};\n\n    for (var i = 0; i < dimensions.length; i++) {\n        // Use the original dimensions[i], where other flag props may exists.\n        var dimensionInfo = dimensions[i];\n\n        if (isString(dimensionInfo)) {\n            dimensionInfo = {name: dimensionInfo};\n        }\n\n        var dimensionName = dimensionInfo.name;\n        dimensionInfo.type = dimensionInfo.type || 'float';\n        if (!dimensionInfo.coordDim) {\n            dimensionInfo.coordDim = dimensionName;\n            dimensionInfo.coordDimIndex = 0;\n        }\n\n        dimensionInfo.otherDims = dimensionInfo.otherDims || {};\n        dimensionNames.push(dimensionName);\n        dimensionInfos[dimensionName] = dimensionInfo;\n\n        dimensionInfo.index = i;\n\n        if (dimensionInfo.createInvertedIndices) {\n            invertedIndicesMap[dimensionName] = [];\n        }\n    }\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    this.dimensions = dimensionNames;\n\n    /**\n     * Infomation of each data dimension, like data type.\n     * @type {Object}\n     */\n    this._dimensionInfos = dimensionInfos;\n\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.hostModel = hostModel;\n\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.dataType;\n\n    /**\n     * Indices stores the indices of data subset after filtered.\n     * This data subset will be used in chart.\n     * @type {Array.<number>}\n     * @readOnly\n     */\n    this._indices = null;\n\n    this._count = 0;\n    this._rawCount = 0;\n\n    /**\n     * Data storage\n     * @type {Object.<key, Array.<TypedArray|Array>>}\n     * @private\n     */\n    this._storage = {};\n\n    /**\n     * @type {Array.<string>}\n     */\n    this._nameList = [];\n    /**\n     * @type {Array.<string>}\n     */\n    this._idList = [];\n\n    /**\n     * Models of data option is stored sparse for optimizing memory cost\n     * @type {Array.<module:echarts/model/Model>}\n     * @private\n     */\n    this._optionModels = [];\n\n    /**\n     * Global visual properties after visual coding\n     * @type {Object}\n     * @private\n     */\n    this._visual = {};\n\n    /**\n     * Globel layout properties.\n     * @type {Object}\n     * @private\n     */\n    this._layout = {};\n\n    /**\n     * Item visual properties after visual coding\n     * @type {Array.<Object>}\n     * @private\n     */\n    this._itemVisuals = [];\n\n    /**\n     * Key: visual type, Value: boolean\n     * @type {Object}\n     * @readOnly\n     */\n    this.hasItemVisual = {};\n\n    /**\n     * Item layout properties after layout\n     * @type {Array.<Object>}\n     * @private\n     */\n    this._itemLayouts = [];\n\n    /**\n     * Graphic elemnents\n     * @type {Array.<module:zrender/Element>}\n     * @private\n     */\n    this._graphicEls = [];\n\n    /**\n     * Max size of each chunk.\n     * @type {number}\n     * @private\n     */\n    this._chunkSize = 1e5;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    this._chunkCount = 0;\n\n    /**\n     * @type {Array.<Array|Object>}\n     * @private\n     */\n    this._rawData;\n\n    /**\n     * Raw extent will not be cloned, but only transfered.\n     * It will not be calculated util needed.\n     * key: dim,\n     * value: {end: number, extent: Array.<number>}\n     * @type {Object}\n     * @private\n     */\n    this._rawExtent = {};\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._extent = {};\n\n    /**\n     * key: dim\n     * value: extent\n     * @type {Object}\n     * @private\n     */\n    this._approximateExtent = {};\n\n    /**\n     * Cache summary info for fast visit. See \"dimensionHelper\".\n     * @type {Object}\n     * @private\n     */\n    this._dimensionsSummary = summarizeDimensions(this);\n\n    /**\n     * @type {Object.<Array|TypedArray>}\n     * @private\n     */\n    this._invertedIndicesMap = invertedIndicesMap;\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._calculationInfo = {};\n};\n\nvar listProto = List.prototype;\n\nlistProto.type = 'list';\n\n/**\n * If each data item has it's own option\n * @type {boolean}\n */\nlistProto.hasItemOption = true;\n\n/**\n * Get dimension name\n * @param {string|number} dim\n *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius\n *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'\n * @return {string} Concrete dim name.\n */\nlistProto.getDimension = function (dim) {\n    if (!isNaN(dim)) {\n        dim = this.dimensions[dim] || dim;\n    }\n    return dim;\n};\n\n/**\n * Get type and calculation info of particular dimension\n * @param {string|number} dim\n *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius\n *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'\n */\nlistProto.getDimensionInfo = function (dim) {\n    // Do not clone, because there may be categories in dimInfo.\n    return this._dimensionInfos[this.getDimension(dim)];\n};\n\n/**\n * @return {Array.<string>} concrete dimension name list on coord.\n */\nlistProto.getDimensionsOnCoord = function () {\n    return this._dimensionsSummary.dataDimsOnCoord.slice();\n};\n\n/**\n * @param {string} coordDim\n * @param {number} [idx] A coordDim may map to more than one data dim.\n *        If idx is `true`, return a array of all mapped dims.\n *        If idx is not specified, return the first dim not extra.\n * @return {string|Array.<string>} concrete data dim.\n *        If idx is number, and not found, return null/undefined.\n *        If idx is `true`, and not found, return empty array (always return array).\n */\nlistProto.mapDimension = function (coordDim, idx) {\n    var dimensionsSummary = this._dimensionsSummary;\n\n    if (idx == null) {\n        return dimensionsSummary.encodeFirstDimNotExtra[coordDim];\n    }\n\n    var dims = dimensionsSummary.encode[coordDim];\n    return idx === true\n        // always return array if idx is `true`\n        ? (dims || []).slice()\n        : (dims && dims[idx]);\n};\n\n/**\n * Initialize from data\n * @param {Array.<Object|number|Array>} data source or data or data provider.\n * @param {Array.<string>} [nameLIst] The name of a datum is used on data diff and\n *        defualt label/tooltip.\n *        A name can be specified in encode.itemName,\n *        or dataItem.name (only for series option data),\n *        or provided in nameList from outside.\n * @param {Function} [dimValueGetter] (dataItem, dimName, dataIndex, dimIndex) => number\n */\nlistProto.initData = function (data, nameList, dimValueGetter) {\n\n    var notProvider = Source.isInstance(data) || isArrayLike(data);\n    if (notProvider) {\n        data = new DefaultDataProvider(data, this.dimensions.length);\n    }\n\n    if (__DEV__) {\n        if (!notProvider && (typeof data.getItem !== 'function' || typeof data.count !== 'function')) {\n            throw new Error('Inavlid data provider.');\n        }\n    }\n\n    this._rawData = data;\n\n    // Clear\n    this._storage = {};\n    this._indices = null;\n\n    this._nameList = nameList || [];\n\n    this._idList = [];\n\n    this._nameRepeatCount = {};\n\n    if (!dimValueGetter) {\n        this.hasItemOption = false;\n    }\n\n    /**\n     * @readOnly\n     */\n    this.defaultDimValueGetter = defaultDimValueGetters[\n        this._rawData.getSource().sourceFormat\n    ];\n    // Default dim value getter\n    this._dimValueGetter = dimValueGetter = dimValueGetter\n        || this.defaultDimValueGetter;\n    this._dimValueGetterArrayRows = defaultDimValueGetters.arrayRows;\n\n    // Reset raw extent.\n    this._rawExtent = {};\n\n    this._initDataFromProvider(0, data.count());\n\n    // If data has no item option.\n    if (data.pure) {\n        this.hasItemOption = false;\n    }\n};\n\nlistProto.getProvider = function () {\n    return this._rawData;\n};\n\n/**\n * Caution: Can be only called on raw data (before `this._indices` created).\n */\nlistProto.appendData = function (data) {\n    if (__DEV__) {\n        assert$1(!this._indices, 'appendData can only be called on raw data.');\n    }\n\n    var rawData = this._rawData;\n    var start = this.count();\n    rawData.appendData(data);\n    var end = rawData.count();\n    if (!rawData.persistent) {\n        end += start;\n    }\n    this._initDataFromProvider(start, end);\n};\n\n/**\n * Caution: Can be only called on raw data (before `this._indices` created).\n * This method does not modify `rawData` (`dataProvider`), but only\n * add values to storage.\n *\n * The final count will be increased by `Math.max(values.length, names.length)`.\n *\n * @param {Array.<Array.<*>>} values That is the SourceType: 'arrayRows', like\n *        [\n *            [12, 33, 44],\n *            [NaN, 43, 1],\n *            ['-', 'asdf', 0]\n *        ]\n *        Each item is exaclty cooresponding to a dimension.\n * @param {Array.<string>} [names]\n */\nlistProto.appendValues = function (values, names) {\n    var chunkSize = this._chunkSize;\n    var storage = this._storage;\n    var dimensions = this.dimensions;\n    var dimLen = dimensions.length;\n    var rawExtent = this._rawExtent;\n\n    var start = this.count();\n    var end = start + Math.max(values.length, names ? names.length : 0);\n    var originalChunkCount = this._chunkCount;\n\n    for (var i = 0; i < dimLen; i++) {\n        var dim = dimensions[i];\n        if (!rawExtent[dim]) {\n            rawExtent[dim] = getInitialExtent();\n        }\n        if (!storage[dim]) {\n            storage[dim] = [];\n        }\n        prepareChunks(storage, this._dimensionInfos[dim], chunkSize, originalChunkCount, end);\n        this._chunkCount = storage[dim].length;\n    }\n\n    var emptyDataItem = new Array(dimLen);\n    for (var idx = start; idx < end; idx++) {\n        var sourceIdx = idx - start;\n        var chunkIndex = Math.floor(idx / chunkSize);\n        var chunkOffset = idx % chunkSize;\n\n        // Store the data by dimensions\n        for (var k = 0; k < dimLen; k++) {\n            var dim = dimensions[k];\n            var val = this._dimValueGetterArrayRows(\n                values[sourceIdx] || emptyDataItem, dim, sourceIdx, k\n            );\n            storage[dim][chunkIndex][chunkOffset] = val;\n\n            var dimRawExtent = rawExtent[dim];\n            val < dimRawExtent[0] && (dimRawExtent[0] = val);\n            val > dimRawExtent[1] && (dimRawExtent[1] = val);\n        }\n\n        if (names) {\n            this._nameList[idx] = names[sourceIdx];\n        }\n    }\n\n    this._rawCount = this._count = end;\n\n    // Reset data extent\n    this._extent = {};\n\n    prepareInvertedIndex(this);\n};\n\nlistProto._initDataFromProvider = function (start, end) {\n    // Optimize.\n    if (start >= end) {\n        return;\n    }\n\n    var chunkSize = this._chunkSize;\n    var rawData = this._rawData;\n    var storage = this._storage;\n    var dimensions = this.dimensions;\n    var dimLen = dimensions.length;\n    var dimensionInfoMap = this._dimensionInfos;\n    var nameList = this._nameList;\n    var idList = this._idList;\n    var rawExtent = this._rawExtent;\n    var nameRepeatCount = this._nameRepeatCount = {};\n    var nameDimIdx;\n\n    var originalChunkCount = this._chunkCount;\n    for (var i = 0; i < dimLen; i++) {\n        var dim = dimensions[i];\n        if (!rawExtent[dim]) {\n            rawExtent[dim] = getInitialExtent();\n        }\n\n        var dimInfo = dimensionInfoMap[dim];\n        if (dimInfo.otherDims.itemName === 0) {\n            nameDimIdx = this._nameDimIdx = i;\n        }\n        if (dimInfo.otherDims.itemId === 0) {\n            this._idDimIdx = i;\n        }\n\n        if (!storage[dim]) {\n            storage[dim] = [];\n        }\n\n        prepareChunks(storage, dimInfo, chunkSize, originalChunkCount, end);\n\n        this._chunkCount = storage[dim].length;\n    }\n\n    var dataItem = new Array(dimLen);\n    for (var idx = start; idx < end; idx++) {\n        // NOTICE: Try not to write things into dataItem\n        dataItem = rawData.getItem(idx, dataItem);\n        // Each data item is value\n        // [1, 2]\n        // 2\n        // Bar chart, line chart which uses category axis\n        // only gives the 'y' value. 'x' value is the indices of category\n        // Use a tempValue to normalize the value to be a (x, y) value\n        var chunkIndex = Math.floor(idx / chunkSize);\n        var chunkOffset = idx % chunkSize;\n\n        // Store the data by dimensions\n        for (var k = 0; k < dimLen; k++) {\n            var dim = dimensions[k];\n            var dimStorage = storage[dim][chunkIndex];\n            // PENDING NULL is empty or zero\n            var val = this._dimValueGetter(dataItem, dim, idx, k);\n            dimStorage[chunkOffset] = val;\n\n            var dimRawExtent = rawExtent[dim];\n            val < dimRawExtent[0] && (dimRawExtent[0] = val);\n            val > dimRawExtent[1] && (dimRawExtent[1] = val);\n        }\n\n        // ??? FIXME not check by pure but sourceFormat?\n        // TODO refactor these logic.\n        if (!rawData.pure) {\n            var name = nameList[idx];\n\n            if (dataItem && name == null) {\n                // If dataItem is {name: ...}, it has highest priority.\n                // That is appropriate for many common cases.\n                if (dataItem.name != null) {\n                    // There is no other place to persistent dataItem.name,\n                    // so save it to nameList.\n                    nameList[idx] = name = dataItem.name;\n                }\n                else if (nameDimIdx != null) {\n                    var nameDim = dimensions[nameDimIdx];\n                    var nameDimChunk = storage[nameDim][chunkIndex];\n                    if (nameDimChunk) {\n                        name = nameDimChunk[chunkOffset];\n                        var ordinalMeta = dimensionInfoMap[nameDim].ordinalMeta;\n                        if (ordinalMeta && ordinalMeta.categories.length) {\n                            name = ordinalMeta.categories[name];\n                        }\n                    }\n                }\n            }\n\n            // Try using the id in option\n            // id or name is used on dynamical data, mapping old and new items.\n            var id = dataItem == null ? null : dataItem.id;\n\n            if (id == null && name != null) {\n                // Use name as id and add counter to avoid same name\n                nameRepeatCount[name] = nameRepeatCount[name] || 0;\n                id = name;\n                if (nameRepeatCount[name] > 0) {\n                    id += '__ec__' + nameRepeatCount[name];\n                }\n                nameRepeatCount[name]++;\n            }\n            id != null && (idList[idx] = id);\n        }\n    }\n\n    if (!rawData.persistent && rawData.clean) {\n        // Clean unused data if data source is typed array.\n        rawData.clean();\n    }\n\n    this._rawCount = this._count = end;\n\n    // Reset data extent\n    this._extent = {};\n\n    prepareInvertedIndex(this);\n};\n\nfunction prepareChunks(storage, dimInfo, chunkSize, chunkCount, end) {\n    var DataCtor = dataCtors[dimInfo.type];\n    var lastChunkIndex = chunkCount - 1;\n    var dim = dimInfo.name;\n    var resizeChunkArray = storage[dim][lastChunkIndex];\n    if (resizeChunkArray && resizeChunkArray.length < chunkSize) {\n        var newStore = new DataCtor(Math.min(end - lastChunkIndex * chunkSize, chunkSize));\n        // The cost of the copy is probably inconsiderable\n        // within the initial chunkSize.\n        for (var j = 0; j < resizeChunkArray.length; j++) {\n            newStore[j] = resizeChunkArray[j];\n        }\n        storage[dim][lastChunkIndex] = newStore;\n    }\n\n    // Create new chunks.\n    for (var k = chunkCount * chunkSize; k < end; k += chunkSize) {\n        storage[dim].push(new DataCtor(Math.min(end - k, chunkSize)));\n    }\n}\n\nfunction prepareInvertedIndex(list) {\n    var invertedIndicesMap = list._invertedIndicesMap;\n    each$1(invertedIndicesMap, function (invertedIndices, dim) {\n        var dimInfo = list._dimensionInfos[dim];\n\n        // Currently, only dimensions that has ordinalMeta can create inverted indices.\n        var ordinalMeta = dimInfo.ordinalMeta;\n        if (ordinalMeta) {\n            invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array(\n                ordinalMeta.categories.length\n            );\n            // The default value of TypedArray is 0. To avoid miss\n            // mapping to 0, we should set it as INDEX_NOT_FOUND.\n            for (var i = 0; i < invertedIndices.length; i++) {\n                invertedIndices[i] = INDEX_NOT_FOUND;\n            }\n            for (var i = 0; i < list._count; i++) {\n                // Only support the case that all values are distinct.\n                invertedIndices[list.get(dim, i)] = i;\n            }\n        }\n    });\n}\n\nfunction getRawValueFromStore(list, dimIndex, rawIndex) {\n    var val;\n    if (dimIndex != null) {\n        var chunkSize = list._chunkSize;\n        var chunkIndex = Math.floor(rawIndex / chunkSize);\n        var chunkOffset = rawIndex % chunkSize;\n        var dim = list.dimensions[dimIndex];\n        var chunk = list._storage[dim][chunkIndex];\n        if (chunk) {\n            val = chunk[chunkOffset];\n            var ordinalMeta = list._dimensionInfos[dim].ordinalMeta;\n            if (ordinalMeta && ordinalMeta.categories.length) {\n                val = ordinalMeta.categories[val];\n            }\n        }\n    }\n    return val;\n}\n\n/**\n * @return {number}\n */\nlistProto.count = function () {\n    return this._count;\n};\n\nlistProto.getIndices = function () {\n    var newIndices;\n\n    var indices = this._indices;\n    if (indices) {\n        var Ctor = indices.constructor;\n        var thisCount = this._count;\n        // `new Array(a, b, c)` is different from `new Uint32Array(a, b, c)`.\n        if (Ctor === Array) {\n            newIndices = new Ctor(thisCount);\n            for (var i = 0; i < thisCount; i++) {\n                newIndices[i] = indices[i];\n            }\n        }\n        else {\n            newIndices = new Ctor(indices.buffer, 0, thisCount);\n        }\n    }\n    else {\n        var Ctor = getIndicesCtor(this);\n        var newIndices = new Ctor(this.count());\n        for (var i = 0; i < newIndices.length; i++) {\n            newIndices[i] = i;\n        }\n    }\n\n    return newIndices;\n};\n\n/**\n * Get value. Return NaN if idx is out of range.\n * @param {string} dim Dim must be concrete name.\n * @param {number} idx\n * @param {boolean} stack\n * @return {number}\n */\nlistProto.get = function (dim, idx /*, stack */) {\n    if (!(idx >= 0 && idx < this._count)) {\n        return NaN;\n    }\n    var storage = this._storage;\n    if (!storage[dim]) {\n        // TODO Warn ?\n        return NaN;\n    }\n\n    idx = this.getRawIndex(idx);\n\n    var chunkIndex = Math.floor(idx / this._chunkSize);\n    var chunkOffset = idx % this._chunkSize;\n\n    var chunkStore = storage[dim][chunkIndex];\n    var value = chunkStore[chunkOffset];\n    // FIXME ordinal data type is not stackable\n    // if (stack) {\n    //     var dimensionInfo = this._dimensionInfos[dim];\n    //     if (dimensionInfo && dimensionInfo.stackable) {\n    //         var stackedOn = this.stackedOn;\n    //         while (stackedOn) {\n    //             // Get no stacked data of stacked on\n    //             var stackedValue = stackedOn.get(dim, idx);\n    //             // Considering positive stack, negative stack and empty data\n    //             if ((value >= 0 && stackedValue > 0)  // Positive stack\n    //                 || (value <= 0 && stackedValue < 0) // Negative stack\n    //             ) {\n    //                 value += stackedValue;\n    //             }\n    //             stackedOn = stackedOn.stackedOn;\n    //         }\n    //     }\n    // }\n\n    return value;\n};\n\n/**\n * @param {string} dim concrete dim\n * @param {number} rawIndex\n * @return {number|string}\n */\nlistProto.getByRawIndex = function (dim, rawIdx) {\n    if (!(rawIdx >= 0 && rawIdx < this._rawCount)) {\n        return NaN;\n    }\n    var dimStore = this._storage[dim];\n    if (!dimStore) {\n        // TODO Warn ?\n        return NaN;\n    }\n\n    var chunkIndex = Math.floor(rawIdx / this._chunkSize);\n    var chunkOffset = rawIdx % this._chunkSize;\n    var chunkStore = dimStore[chunkIndex];\n    return chunkStore[chunkOffset];\n};\n\n/**\n * FIXME Use `get` on chrome maybe slow(in filterSelf and selectRange).\n * Hack a much simpler _getFast\n * @private\n */\nlistProto._getFast = function (dim, rawIdx) {\n    var chunkIndex = Math.floor(rawIdx / this._chunkSize);\n    var chunkOffset = rawIdx % this._chunkSize;\n    var chunkStore = this._storage[dim][chunkIndex];\n    return chunkStore[chunkOffset];\n};\n\n/**\n * Get value for multi dimensions.\n * @param {Array.<string>} [dimensions] If ignored, using all dimensions.\n * @param {number} idx\n * @return {number}\n */\nlistProto.getValues = function (dimensions, idx /*, stack */) {\n    var values = [];\n\n    if (!isArray(dimensions)) {\n        // stack = idx;\n        idx = dimensions;\n        dimensions = this.dimensions;\n    }\n\n    for (var i = 0, len = dimensions.length; i < len; i++) {\n        values.push(this.get(dimensions[i], idx /*, stack */));\n    }\n\n    return values;\n};\n\n/**\n * If value is NaN. Inlcuding '-'\n * Only check the coord dimensions.\n * @param {string} dim\n * @param {number} idx\n * @return {number}\n */\nlistProto.hasValue = function (idx) {\n    var dataDimsOnCoord = this._dimensionsSummary.dataDimsOnCoord;\n    var dimensionInfos = this._dimensionInfos;\n    for (var i = 0, len = dataDimsOnCoord.length; i < len; i++) {\n        if (\n            // Ordinal type can be string or number\n            dimensionInfos[dataDimsOnCoord[i]].type !== 'ordinal'\n            // FIXME check ordinal when using index?\n            && isNaN(this.get(dataDimsOnCoord[i], idx))\n        ) {\n            return false;\n        }\n    }\n    return true;\n};\n\n/**\n * Get extent of data in one dimension\n * @param {string} dim\n * @param {boolean} stack\n */\nlistProto.getDataExtent = function (dim /*, stack */) {\n    // Make sure use concrete dim as cache name.\n    dim = this.getDimension(dim);\n    var dimData = this._storage[dim];\n    var initialExtent = getInitialExtent();\n\n    // stack = !!((stack || false) && this.getCalculationInfo(dim));\n\n    if (!dimData) {\n        return initialExtent;\n    }\n\n    // Make more strict checkings to ensure hitting cache.\n    var currEnd = this.count();\n    // var cacheName = [dim, !!stack].join('_');\n    // var cacheName = dim;\n\n    // Consider the most cases when using data zoom, `getDataExtent`\n    // happened before filtering. We cache raw extent, which is not\n    // necessary to be cleared and recalculated when restore data.\n    var useRaw = !this._indices; // && !stack;\n    var dimExtent;\n\n    if (useRaw) {\n        return this._rawExtent[dim].slice();\n    }\n    dimExtent = this._extent[dim];\n    if (dimExtent) {\n        return dimExtent.slice();\n    }\n    dimExtent = initialExtent;\n\n    var min = dimExtent[0];\n    var max = dimExtent[1];\n\n    for (var i = 0; i < currEnd; i++) {\n        // var value = stack ? this.get(dim, i, true) : this._getFast(dim, this.getRawIndex(i));\n        var value = this._getFast(dim, this.getRawIndex(i));\n        value < min && (min = value);\n        value > max && (max = value);\n    }\n\n    dimExtent = [min, max];\n\n    this._extent[dim] = dimExtent;\n\n    return dimExtent;\n};\n\n/**\n * Optimize for the scenario that data is filtered by a given extent.\n * Consider that if data amount is more than hundreds of thousand,\n * extent calculation will cost more than 10ms and the cache will\n * be erased because of the filtering.\n */\nlistProto.getApproximateExtent = function (dim /*, stack */) {\n    dim = this.getDimension(dim);\n    return this._approximateExtent[dim] || this.getDataExtent(dim /*, stack */);\n};\n\nlistProto.setApproximateExtent = function (extent, dim /*, stack */) {\n    dim = this.getDimension(dim);\n    this._approximateExtent[dim] = extent.slice();\n};\n\n/**\n * @param {string} key\n * @return {*}\n */\nlistProto.getCalculationInfo = function (key) {\n    return this._calculationInfo[key];\n};\n\n/**\n * @param {string|Object} key or k-v object\n * @param {*} [value]\n */\nlistProto.setCalculationInfo = function (key, value) {\n    isObject$4(key)\n        ? extend(this._calculationInfo, key)\n        : (this._calculationInfo[key] = value);\n};\n\n/**\n * Get sum of data in one dimension\n * @param {string} dim\n */\nlistProto.getSum = function (dim /*, stack */) {\n    var dimData = this._storage[dim];\n    var sum = 0;\n    if (dimData) {\n        for (var i = 0, len = this.count(); i < len; i++) {\n            var value = this.get(dim, i /*, stack */);\n            if (!isNaN(value)) {\n                sum += value;\n            }\n        }\n    }\n    return sum;\n};\n\n/**\n * Get median of data in one dimension\n * @param {string} dim\n */\nlistProto.getMedian = function (dim /*, stack */) {\n    var dimDataArray = [];\n    // map all data of one dimension\n    this.each(dim, function (val, idx) {\n        if (!isNaN(val)) {\n            dimDataArray.push(val);\n        }\n    });\n\n    // TODO\n    // Use quick select?\n\n    // immutability & sort\n    var sortedDimDataArray = [].concat(dimDataArray).sort(function (a, b) {\n        return a - b;\n    });\n    var len = this.count();\n    // calculate median\n    return len === 0\n        ? 0\n        : len % 2 === 1\n        ? sortedDimDataArray[(len - 1) / 2]\n        : (sortedDimDataArray[len / 2] + sortedDimDataArray[len / 2 - 1]) / 2;\n};\n\n// /**\n//  * Retreive the index with given value\n//  * @param {string} dim Concrete dimension.\n//  * @param {number} value\n//  * @return {number}\n//  */\n// Currently incorrect: should return dataIndex but not rawIndex.\n// Do not fix it until this method is to be used somewhere.\n// FIXME Precision of float value\n// listProto.indexOf = function (dim, value) {\n//     var storage = this._storage;\n//     var dimData = storage[dim];\n//     var chunkSize = this._chunkSize;\n//     if (dimData) {\n//         for (var i = 0, len = this.count(); i < len; i++) {\n//             var chunkIndex = Math.floor(i / chunkSize);\n//             var chunkOffset = i % chunkSize;\n//             if (dimData[chunkIndex][chunkOffset] === value) {\n//                 return i;\n//             }\n//         }\n//     }\n//     return -1;\n// };\n\n/**\n * Only support the dimension which inverted index created.\n * Do not support other cases until required.\n * @param {string} concrete dim\n * @param {number|string} value\n * @return {number} rawIndex\n */\nlistProto.rawIndexOf = function (dim, value) {\n    var invertedIndices = dim && this._invertedIndicesMap[dim];\n    if (__DEV__) {\n        if (!invertedIndices) {\n            throw new Error('Do not supported yet');\n        }\n    }\n    var rawIndex = invertedIndices[value];\n    if (rawIndex == null || isNaN(rawIndex)) {\n        return INDEX_NOT_FOUND;\n    }\n    return rawIndex;\n};\n\n/**\n * Retreive the index with given name\n * @param {number} idx\n * @param {number} name\n * @return {number}\n */\nlistProto.indexOfName = function (name) {\n    for (var i = 0, len = this.count(); i < len; i++) {\n        if (this.getName(i) === name) {\n            return i;\n        }\n    }\n\n    return -1;\n};\n\n/**\n * Retreive the index with given raw data index\n * @param {number} idx\n * @param {number} name\n * @return {number}\n */\nlistProto.indexOfRawIndex = function (rawIndex) {\n    if (!this._indices) {\n        return rawIndex;\n    }\n\n    if (rawIndex >= this._rawCount || rawIndex < 0) {\n        return -1;\n    }\n\n    // Indices are ascending\n    var indices = this._indices;\n\n    // If rawIndex === dataIndex\n    var rawDataIndex = indices[rawIndex];\n    if (rawDataIndex != null && rawDataIndex < this._count && rawDataIndex === rawIndex) {\n        return rawIndex;\n    }\n\n    var left = 0;\n    var right = this._count - 1;\n    while (left <= right) {\n        var mid = (left + right) / 2 | 0;\n        if (indices[mid] < rawIndex) {\n            left = mid + 1;\n        }\n        else if (indices[mid] > rawIndex) {\n            right = mid - 1;\n        }\n        else {\n            return mid;\n        }\n    }\n    return -1;\n};\n\n/**\n * Retreive the index of nearest value\n * @param {string} dim\n * @param {number} value\n * @param {number} [maxDistance=Infinity]\n * @return {Array.<number>} Considere multiple points has the same value.\n */\nlistProto.indicesOfNearest = function (dim, value, maxDistance) {\n    var storage = this._storage;\n    var dimData = storage[dim];\n    var nearestIndices = [];\n\n    if (!dimData) {\n        return nearestIndices;\n    }\n\n    if (maxDistance == null) {\n        maxDistance = Infinity;\n    }\n\n    var minDist = Number.MAX_VALUE;\n    var minDiff = -1;\n    for (var i = 0, len = this.count(); i < len; i++) {\n        var diff = value - this.get(dim, i /*, stack */);\n        var dist = Math.abs(diff);\n        if (diff <= maxDistance && dist <= minDist) {\n            // For the case of two data are same on xAxis, which has sequence data.\n            // Show the nearest index\n            // https://github.com/ecomfe/echarts/issues/2869\n            if (dist < minDist || (diff >= 0 && minDiff < 0)) {\n                minDist = dist;\n                minDiff = diff;\n                nearestIndices.length = 0;\n            }\n            nearestIndices.push(i);\n        }\n    }\n    return nearestIndices;\n};\n\n/**\n * Get raw data index\n * @param {number} idx\n * @return {number}\n */\nlistProto.getRawIndex = getRawIndexWithoutIndices;\n\nfunction getRawIndexWithoutIndices(idx) {\n    return idx;\n}\n\nfunction getRawIndexWithIndices(idx) {\n    if (idx < this._count && idx >= 0) {\n        return this._indices[idx];\n    }\n    return -1;\n}\n\n/**\n * Get raw data item\n * @param {number} idx\n * @return {number}\n */\nlistProto.getRawDataItem = function (idx) {\n    if (!this._rawData.persistent) {\n        var val = [];\n        for (var i = 0; i < this.dimensions.length; i++) {\n            var dim = this.dimensions[i];\n            val.push(this.get(dim, idx));\n        }\n        return val;\n    }\n    else {\n        return this._rawData.getItem(this.getRawIndex(idx));\n    }\n};\n\n/**\n * @param {number} idx\n * @param {boolean} [notDefaultIdx=false]\n * @return {string}\n */\nlistProto.getName = function (idx) {\n    var rawIndex = this.getRawIndex(idx);\n    return this._nameList[rawIndex]\n        || getRawValueFromStore(this, this._nameDimIdx, rawIndex)\n        || '';\n};\n\n/**\n * @param {number} idx\n * @param {boolean} [notDefaultIdx=false]\n * @return {string}\n */\nlistProto.getId = function (idx) {\n    return getId(this, this.getRawIndex(idx));\n};\n\nfunction getId(list, rawIndex) {\n    var id = list._idList[rawIndex];\n    if (id == null) {\n        id = getRawValueFromStore(list, list._idDimIdx, rawIndex);\n    }\n    if (id == null) {\n        // FIXME Check the usage in graph, should not use prefix.\n        id = ID_PREFIX + rawIndex;\n    }\n    return id;\n}\n\nfunction normalizeDimensions(dimensions) {\n    if (!isArray(dimensions)) {\n        dimensions = [dimensions];\n    }\n    return dimensions;\n}\n\nfunction validateDimensions(list, dims) {\n    for (var i = 0; i < dims.length; i++) {\n        // stroage may be empty when no data, so use\n        // dimensionInfos to check.\n        if (!list._dimensionInfos[dims[i]]) {\n            console.error('Unkown dimension ' + dims[i]);\n        }\n    }\n}\n\n/**\n * Data iteration\n * @param {string|Array.<string>}\n * @param {Function} cb\n * @param {*} [context=this]\n *\n * @example\n *  list.each('x', function (x, idx) {});\n *  list.each(['x', 'y'], function (x, y, idx) {});\n *  list.each(function (idx) {})\n */\nlistProto.each = function (dims, cb, context, contextCompat) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    if (typeof dims === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dims;\n        dims = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dims = map(normalizeDimensions(dims), this.getDimension, this);\n\n    if (__DEV__) {\n        validateDimensions(this, dims);\n    }\n\n    var dimSize = dims.length;\n\n    for (var i = 0; i < this.count(); i++) {\n        // Simple optimization\n        switch (dimSize) {\n            case 0:\n                cb.call(context, i);\n                break;\n            case 1:\n                cb.call(context, this.get(dims[0], i), i);\n                break;\n            case 2:\n                cb.call(context, this.get(dims[0], i), this.get(dims[1], i), i);\n                break;\n            default:\n                var k = 0;\n                var value = [];\n                for (; k < dimSize; k++) {\n                    value[k] = this.get(dims[k], i);\n                }\n                // Index\n                value[k] = i;\n                cb.apply(context, value);\n        }\n    }\n};\n\n/**\n * Data filter\n * @param {string|Array.<string>}\n * @param {Function} cb\n * @param {*} [context=this]\n */\nlistProto.filterSelf = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    if (typeof dimensions === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dimensions;\n        dimensions = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dimensions = map(\n        normalizeDimensions(dimensions), this.getDimension, this\n    );\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n\n    var count = this.count();\n    var Ctor = getIndicesCtor(this);\n    var newIndices = new Ctor(count);\n    var value = [];\n    var dimSize = dimensions.length;\n\n    var offset = 0;\n    var dim0 = dimensions[0];\n\n    for (var i = 0; i < count; i++) {\n        var keep;\n        var rawIdx = this.getRawIndex(i);\n        // Simple optimization\n        if (dimSize === 0) {\n            keep = cb.call(context, i);\n        }\n        else if (dimSize === 1) {\n            var val = this._getFast(dim0, rawIdx);\n            keep = cb.call(context, val, i);\n        }\n        else {\n            for (var k = 0; k < dimSize; k++) {\n                value[k] = this._getFast(dim0, rawIdx);\n            }\n            value[k] = i;\n            keep = cb.apply(context, value);\n        }\n        if (keep) {\n            newIndices[offset++] = rawIdx;\n        }\n    }\n\n    // Set indices after filtered.\n    if (offset < count) {\n        this._indices = newIndices;\n    }\n    this._count = offset;\n    // Reset data extent\n    this._extent = {};\n\n    this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return this;\n};\n\n/**\n * Select data in range. (For optimization of filter)\n * (Manually inline code, support 5 million data filtering in data zoom.)\n */\nlistProto.selectRange = function (range) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    var dimensions = [];\n    for (var dim in range) {\n        if (range.hasOwnProperty(dim)) {\n            dimensions.push(dim);\n        }\n    }\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n    var dimSize = dimensions.length;\n    if (!dimSize) {\n        return;\n    }\n\n    var originalCount = this.count();\n    var Ctor = getIndicesCtor(this);\n    var newIndices = new Ctor(originalCount);\n\n    var offset = 0;\n    var dim0 = dimensions[0];\n\n    var min = range[dim0][0];\n    var max = range[dim0][1];\n\n    var quickFinished = false;\n    if (!this._indices) {\n        // Extreme optimization for common case. About 2x faster in chrome.\n        var idx = 0;\n        if (dimSize === 1) {\n            var dimStorage = this._storage[dimensions[0]];\n            for (var k = 0; k < this._chunkCount; k++) {\n                var chunkStorage = dimStorage[k];\n                var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);\n                for (var i = 0; i < len; i++) {\n                    var val = chunkStorage[i];\n                    // NaN will not be filtered. Consider the case, in line chart, empty\n                    // value indicates the line should be broken. But for the case like\n                    // scatter plot, a data item with empty value will not be rendered,\n                    // but the axis extent may be effected if some other dim of the data\n                    // item has value. Fortunately it is not a significant negative effect.\n                    if (\n                        (val >= min && val <= max) || isNaN(val)\n                    ) {\n                        newIndices[offset++] = idx;\n                    }\n                    idx++;\n                }\n            }\n            quickFinished = true;\n        }\n        else if (dimSize === 2) {\n            var dimStorage = this._storage[dim0];\n            var dimStorage2 = this._storage[dimensions[1]];\n            var min2 = range[dimensions[1]][0];\n            var max2 = range[dimensions[1]][1];\n            for (var k = 0; k < this._chunkCount; k++) {\n                var chunkStorage = dimStorage[k];\n                var chunkStorage2 = dimStorage2[k];\n                var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);\n                for (var i = 0; i < len; i++) {\n                    var val = chunkStorage[i];\n                    var val2 = chunkStorage2[i];\n                    // Do not filter NaN, see comment above.\n                    if ((\n                            (val >= min && val <= max) || isNaN(val)\n                        )\n                        && (\n                            (val2 >= min2 && val2 <= max2) || isNaN(val2)\n                        )\n                    ) {\n                        newIndices[offset++] = idx;\n                    }\n                    idx++;\n                }\n            }\n            quickFinished = true;\n        }\n    }\n    if (!quickFinished) {\n        if (dimSize === 1) {\n            for (var i = 0; i < originalCount; i++) {\n                var rawIndex = this.getRawIndex(i);\n                var val = this._getFast(dim0, rawIndex);\n                // Do not filter NaN, see comment above.\n                if (\n                    (val >= min && val <= max) || isNaN(val)\n                ) {\n                    newIndices[offset++] = rawIndex;\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < originalCount; i++) {\n                var keep = true;\n                var rawIndex = this.getRawIndex(i);\n                for (var k = 0; k < dimSize; k++) {\n                    var dimk = dimensions[k];\n                    var val = this._getFast(dim, rawIndex);\n                    // Do not filter NaN, see comment above.\n                    if (val < range[dimk][0] || val > range[dimk][1]) {\n                        keep = false;\n                    }\n                }\n                if (keep) {\n                    newIndices[offset++] = this.getRawIndex(i);\n                }\n            }\n        }\n    }\n\n    // Set indices after filtered.\n    if (offset < originalCount) {\n        this._indices = newIndices;\n    }\n    this._count = offset;\n    // Reset data extent\n    this._extent = {};\n\n    this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return this;\n};\n\n/**\n * Data mapping to a plain array\n * @param {string|Array.<string>} [dimensions]\n * @param {Function} cb\n * @param {*} [context=this]\n * @return {Array}\n */\nlistProto.mapArray = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    if (typeof dimensions === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dimensions;\n        dimensions = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    var result = [];\n    this.each(dimensions, function () {\n        result.push(cb && cb.apply(this, arguments));\n    }, context);\n    return result;\n};\n\n// Data in excludeDimensions is copied, otherwise transfered.\nfunction cloneListForMapAndSample(original, excludeDimensions) {\n    var allDimensions = original.dimensions;\n    var list = new List(\n        map(allDimensions, original.getDimensionInfo, original),\n        original.hostModel\n    );\n    // FIXME If needs stackedOn, value may already been stacked\n    transferProperties(list, original);\n\n    var storage = list._storage = {};\n    var originalStorage = original._storage;\n\n    // Init storage\n    for (var i = 0; i < allDimensions.length; i++) {\n        var dim = allDimensions[i];\n        if (originalStorage[dim]) {\n            // Notice that we do not reset invertedIndicesMap here, becuase\n            // there is no scenario of mapping or sampling ordinal dimension.\n            if (indexOf(excludeDimensions, dim) >= 0) {\n                storage[dim] = cloneDimStore(originalStorage[dim]);\n                list._rawExtent[dim] = getInitialExtent();\n                list._extent[dim] = null;\n            }\n            else {\n                // Direct reference for other dimensions\n                storage[dim] = originalStorage[dim];\n            }\n        }\n    }\n    return list;\n}\n\nfunction cloneDimStore(originalDimStore) {\n    var newDimStore = new Array(originalDimStore.length);\n    for (var j = 0; j < originalDimStore.length; j++) {\n        newDimStore[j] = cloneChunk(originalDimStore[j]);\n    }\n    return newDimStore;\n}\n\nfunction getInitialExtent() {\n    return [Infinity, -Infinity];\n}\n\n/**\n * Data mapping to a new List with given dimensions\n * @param {string|Array.<string>} dimensions\n * @param {Function} cb\n * @param {*} [context=this]\n * @return {Array}\n */\nlistProto.map = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dimensions = map(\n        normalizeDimensions(dimensions), this.getDimension, this\n    );\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n    var list = cloneListForMapAndSample(this, dimensions);\n\n    // Following properties are all immutable.\n    // So we can reference to the same value\n    list._indices = this._indices;\n    list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    var storage = list._storage;\n\n    var tmpRetValue = [];\n    var chunkSize = this._chunkSize;\n    var dimSize = dimensions.length;\n    var dataCount = this.count();\n    var values = [];\n    var rawExtent = list._rawExtent;\n\n    for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) {\n        for (var dimIndex = 0; dimIndex < dimSize; dimIndex++) {\n            values[dimIndex] = this.get(dimensions[dimIndex], dataIndex /*, stack */);\n        }\n        values[dimSize] = dataIndex;\n\n        var retValue = cb && cb.apply(context, values);\n        if (retValue != null) {\n            // a number or string (in oridinal dimension)?\n            if (typeof retValue !== 'object') {\n                tmpRetValue[0] = retValue;\n                retValue = tmpRetValue;\n            }\n\n            var rawIndex = this.getRawIndex(dataIndex);\n            var chunkIndex = Math.floor(rawIndex / chunkSize);\n            var chunkOffset = rawIndex % chunkSize;\n\n            for (var i = 0; i < retValue.length; i++) {\n                var dim = dimensions[i];\n                var val = retValue[i];\n                var rawExtentOnDim = rawExtent[dim];\n\n                var dimStore = storage[dim];\n                if (dimStore) {\n                    dimStore[chunkIndex][chunkOffset] = val;\n                }\n\n                if (val < rawExtentOnDim[0]) {\n                    rawExtentOnDim[0] = val;\n                }\n                if (val > rawExtentOnDim[1]) {\n                    rawExtentOnDim[1] = val;\n                }\n            }\n        }\n    }\n\n    return list;\n};\n\n/**\n * Large data down sampling on given dimension\n * @param {string} dimension\n * @param {number} rate\n * @param {Function} sampleValue\n * @param {Function} sampleIndex Sample index for name and id\n */\nlistProto.downSample = function (dimension, rate, sampleValue, sampleIndex) {\n    var list = cloneListForMapAndSample(this, [dimension]);\n    var targetStorage = list._storage;\n\n    var frameValues = [];\n    var frameSize = Math.floor(1 / rate);\n\n    var dimStore = targetStorage[dimension];\n    var len = this.count();\n    var chunkSize = this._chunkSize;\n    var rawExtentOnDim = list._rawExtent[dimension];\n\n    var newIndices = new (getIndicesCtor(this))(len);\n\n    var offset = 0;\n    for (var i = 0; i < len; i += frameSize) {\n        // Last frame\n        if (frameSize > len - i) {\n            frameSize = len - i;\n            frameValues.length = frameSize;\n        }\n        for (var k = 0; k < frameSize; k++) {\n            var dataIdx = this.getRawIndex(i + k);\n            var originalChunkIndex = Math.floor(dataIdx / chunkSize);\n            var originalChunkOffset = dataIdx % chunkSize;\n            frameValues[k] = dimStore[originalChunkIndex][originalChunkOffset];\n        }\n        var value = sampleValue(frameValues);\n        var sampleFrameIdx = this.getRawIndex(\n            Math.min(i + sampleIndex(frameValues, value) || 0, len - 1)\n        );\n        var sampleChunkIndex = Math.floor(sampleFrameIdx / chunkSize);\n        var sampleChunkOffset = sampleFrameIdx % chunkSize;\n        // Only write value on the filtered data\n        dimStore[sampleChunkIndex][sampleChunkOffset] = value;\n\n        if (value < rawExtentOnDim[0]) {\n            rawExtentOnDim[0] = value;\n        }\n        if (value > rawExtentOnDim[1]) {\n            rawExtentOnDim[1] = value;\n        }\n\n        newIndices[offset++] = sampleFrameIdx;\n    }\n\n    list._count = offset;\n    list._indices = newIndices;\n\n    list.getRawIndex = getRawIndexWithIndices;\n\n    return list;\n};\n\n/**\n * Get model of one data item.\n *\n * @param {number} idx\n */\n// FIXME Model proxy ?\nlistProto.getItemModel = function (idx) {\n    var hostModel = this.hostModel;\n    return new Model(this.getRawDataItem(idx), hostModel, hostModel && hostModel.ecModel);\n};\n\n/**\n * Create a data differ\n * @param {module:echarts/data/List} otherList\n * @return {module:echarts/data/DataDiffer}\n */\nlistProto.diff = function (otherList) {\n    var thisList = this;\n\n    return new DataDiffer(\n        otherList ? otherList.getIndices() : [],\n        this.getIndices(),\n        function (idx) {\n            return getId(otherList, idx);\n        },\n        function (idx) {\n            return getId(thisList, idx);\n        }\n    );\n};\n/**\n * Get visual property.\n * @param {string} key\n */\nlistProto.getVisual = function (key) {\n    var visual = this._visual;\n    return visual && visual[key];\n};\n\n/**\n * Set visual property\n * @param {string|Object} key\n * @param {*} [value]\n *\n * @example\n *  setVisual('color', color);\n *  setVisual({\n *      'color': color\n *  });\n */\nlistProto.setVisual = function (key, val) {\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                this.setVisual(name, key[name]);\n            }\n        }\n        return;\n    }\n    this._visual = this._visual || {};\n    this._visual[key] = val;\n};\n\n/**\n * Set layout property.\n * @param {string|Object} key\n * @param {*} [val]\n */\nlistProto.setLayout = function (key, val) {\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                this.setLayout(name, key[name]);\n            }\n        }\n        return;\n    }\n    this._layout[key] = val;\n};\n\n/**\n * Get layout property.\n * @param  {string} key.\n * @return {*}\n */\nlistProto.getLayout = function (key) {\n    return this._layout[key];\n};\n\n/**\n * Get layout of single data item\n * @param {number} idx\n */\nlistProto.getItemLayout = function (idx) {\n    return this._itemLayouts[idx];\n};\n\n/**\n * Set layout of single data item\n * @param {number} idx\n * @param {Object} layout\n * @param {boolean=} [merge=false]\n */\nlistProto.setItemLayout = function (idx, layout, merge$$1) {\n    this._itemLayouts[idx] = merge$$1\n        ? extend(this._itemLayouts[idx] || {}, layout)\n        : layout;\n};\n\n/**\n * Clear all layout of single data item\n */\nlistProto.clearItemLayouts = function () {\n    this._itemLayouts.length = 0;\n};\n\n/**\n * Get visual property of single data item\n * @param {number} idx\n * @param {string} key\n * @param {boolean} [ignoreParent=false]\n */\nlistProto.getItemVisual = function (idx, key, ignoreParent) {\n    var itemVisual = this._itemVisuals[idx];\n    var val = itemVisual && itemVisual[key];\n    if (val == null && !ignoreParent) {\n        // Use global visual property\n        return this.getVisual(key);\n    }\n    return val;\n};\n\n/**\n * Set visual property of single data item\n *\n * @param {number} idx\n * @param {string|Object} key\n * @param {*} [value]\n *\n * @example\n *  setItemVisual(0, 'color', color);\n *  setItemVisual(0, {\n *      'color': color\n *  });\n */\nlistProto.setItemVisual = function (idx, key, value) {\n    var itemVisual = this._itemVisuals[idx] || {};\n    var hasItemVisual = this.hasItemVisual;\n    this._itemVisuals[idx] = itemVisual;\n\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                itemVisual[name] = key[name];\n                hasItemVisual[name] = true;\n            }\n        }\n        return;\n    }\n    itemVisual[key] = value;\n    hasItemVisual[key] = true;\n};\n\n/**\n * Clear itemVisuals and list visual.\n */\nlistProto.clearAllVisual = function () {\n    this._visual = {};\n    this._itemVisuals = [];\n    this.hasItemVisual = {};\n};\n\nvar setItemDataAndSeriesIndex = function (child) {\n    child.seriesIndex = this.seriesIndex;\n    child.dataIndex = this.dataIndex;\n    child.dataType = this.dataType;\n};\n/**\n * Set graphic element relative to data. It can be set as null\n * @param {number} idx\n * @param {module:zrender/Element} [el]\n */\nlistProto.setItemGraphicEl = function (idx, el) {\n    var hostModel = this.hostModel;\n\n    if (el) {\n        // Add data index and series index for indexing the data by element\n        // Useful in tooltip\n        el.dataIndex = idx;\n        el.dataType = this.dataType;\n        el.seriesIndex = hostModel && hostModel.seriesIndex;\n        if (el.type === 'group') {\n            el.traverse(setItemDataAndSeriesIndex, el);\n        }\n    }\n\n    this._graphicEls[idx] = el;\n};\n\n/**\n * @param {number} idx\n * @return {module:zrender/Element}\n */\nlistProto.getItemGraphicEl = function (idx) {\n    return this._graphicEls[idx];\n};\n\n/**\n * @param {Function} cb\n * @param {*} context\n */\nlistProto.eachItemGraphicEl = function (cb, context) {\n    each$1(this._graphicEls, function (el, idx) {\n        if (el) {\n            cb && cb.call(context, el, idx);\n        }\n    });\n};\n\n/**\n * Shallow clone a new list except visual and layout properties, and graph elements.\n * New list only change the indices.\n */\nlistProto.cloneShallow = function (list) {\n    if (!list) {\n        var dimensionInfoList = map(this.dimensions, this.getDimensionInfo, this);\n        list = new List(dimensionInfoList, this.hostModel);\n    }\n\n    // FIXME\n    list._storage = this._storage;\n\n    transferProperties(list, this);\n\n    // Clone will not change the data extent and indices\n    if (this._indices) {\n        var Ctor = this._indices.constructor;\n        list._indices = new Ctor(this._indices);\n    }\n    else {\n        list._indices = null;\n    }\n    list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return list;\n};\n\n/**\n * Wrap some method to add more feature\n * @param {string} methodName\n * @param {Function} injectFunction\n */\nlistProto.wrapMethod = function (methodName, injectFunction) {\n    var originalMethod = this[methodName];\n    if (typeof originalMethod !== 'function') {\n        return;\n    }\n    this.__wrappedMethods = this.__wrappedMethods || [];\n    this.__wrappedMethods.push(methodName);\n    this[methodName] = function () {\n        var res = originalMethod.apply(this, arguments);\n        return injectFunction.apply(this, [res].concat(slice(arguments)));\n    };\n};\n\n// Methods that create a new list based on this list should be listed here.\n// Notice that those method should `RETURN` the new list.\nlistProto.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'map'];\n// Methods that change indices of this list should be listed here.\nlistProto.CHANGABLE_METHODS = ['filterSelf', 'selectRange'];\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @deprecated\n * Use `echarts/data/helper/createDimensions` instead.\n */\n\n/**\n * @see {module:echarts/test/ut/spec/data/completeDimensions}\n *\n * Complete the dimensions array, by user defined `dimension` and `encode`,\n * and guessing from the data structure.\n * If no 'value' dimension specified, the first no-named dimension will be\n * named as 'value'.\n *\n * @param {Array.<string>} sysDims Necessary dimensions, like ['x', 'y'], which\n *      provides not only dim template, but also default order.\n *      properties: 'name', 'type', 'displayName'.\n *      `name` of each item provides default coord name.\n *      [{dimsDef: [string|Object, ...]}, ...] dimsDef of sysDim item provides default dim name, and\n *                                    provide dims count that the sysDim required.\n *      [{ordinalMeta}] can be specified.\n * @param {module:echarts/data/Source|Array|Object} source or data (for compatibal with pervious)\n * @param {Object} [opt]\n * @param {Array.<Object|string>} [opt.dimsDef] option.series.dimensions User defined dimensions\n *      For example: ['asdf', {name, type}, ...].\n * @param {Object|HashMap} [opt.encodeDef] option.series.encode {x: 2, y: [3, 1], tooltip: [1, 2], label: 3}\n * @param {string} [opt.generateCoord] Generate coord dim with the given name.\n *                 If not specified, extra dim names will be:\n *                 'value', 'value0', 'value1', ...\n * @param {number} [opt.generateCoordCount] By default, the generated dim name is `generateCoord`.\n *                 If `generateCoordCount` specified, the generated dim names will be:\n *                 `generateCoord` + 0, `generateCoord` + 1, ...\n *                 can be Infinity, indicate that use all of the remain columns.\n * @param {number} [opt.dimCount] If not specified, guess by the first data item.\n * @param {number} [opt.encodeDefaulter] If not specified, auto find the next available data dim.\n * @return {Array.<Object>} [{\n *      name: string mandatory,\n *      displayName: string, the origin name in dimsDef, see source helper.\n *                 If displayName given, the tooltip will displayed vertically.\n *      coordDim: string mandatory,\n *      coordDimIndex: number mandatory,\n *      type: string optional,\n *      otherDims: { never null/undefined\n *          tooltip: number optional,\n *          label: number optional,\n *          itemName: number optional,\n *          seriesName: number optional,\n *      },\n *      isExtraCoord: boolean true if coord is generated\n *          (not specified in encode and not series specified)\n *      other props ...\n * }]\n */\nfunction completeDimensions(sysDims, source, opt) {\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n\n    opt = opt || {};\n    sysDims = (sysDims || []).slice();\n    var dimsDef = (opt.dimsDef || []).slice();\n    var encodeDef = createHashMap(opt.encodeDef);\n    var dataDimNameMap = createHashMap();\n    var coordDimNameMap = createHashMap();\n    // var valueCandidate;\n    var result = [];\n\n    var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimCount);\n\n    // Apply user defined dims (`name` and `type`) and init result.\n    for (var i = 0; i < dimCount; i++) {\n        var dimDefItem = dimsDef[i] = extend(\n            {}, isObject$1(dimsDef[i]) ? dimsDef[i] : {name: dimsDef[i]}\n        );\n        var userDimName = dimDefItem.name;\n        var resultItem = result[i] = {otherDims: {}};\n        // Name will be applied later for avoiding duplication.\n        if (userDimName != null && dataDimNameMap.get(userDimName) == null) {\n            // Only if `series.dimensions` is defined in option\n            // displayName, will be set, and dimension will be diplayed vertically in\n            // tooltip by default.\n            resultItem.name = resultItem.displayName = userDimName;\n            dataDimNameMap.set(userDimName, i);\n        }\n        dimDefItem.type != null && (resultItem.type = dimDefItem.type);\n        dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);\n    }\n\n    // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.\n    encodeDef.each(function (dataDims, coordDim) {\n        dataDims = normalizeToArray(dataDims).slice();\n\n        // Note: It is allowed that `dataDims.length` is `0`, e.g., options is\n        // `{encode: {x: -1, y: 1}}`. Should not filter anything in\n        // this case.\n        if (dataDims.length === 1 && dataDims[0] < 0) {\n            encodeDef.set(coordDim, false);\n            return;\n        }\n\n        var validDataDims = encodeDef.set(coordDim, []);\n        each$1(dataDims, function (resultDimIdx, idx) {\n            // The input resultDimIdx can be dim name or index.\n            isString(resultDimIdx) && (resultDimIdx = dataDimNameMap.get(resultDimIdx));\n            if (resultDimIdx != null && resultDimIdx < dimCount) {\n                validDataDims[idx] = resultDimIdx;\n                applyDim(result[resultDimIdx], coordDim, idx);\n            }\n        });\n    });\n\n    // Apply templetes and default order from `sysDims`.\n    var availDimIdx = 0;\n    each$1(sysDims, function (sysDimItem, sysDimIndex) {\n        var coordDim;\n        var sysDimItem;\n        var sysDimItemDimsDef;\n        var sysDimItemOtherDims;\n        if (isString(sysDimItem)) {\n            coordDim = sysDimItem;\n            sysDimItem = {};\n        }\n        else {\n            coordDim = sysDimItem.name;\n            var ordinalMeta = sysDimItem.ordinalMeta;\n            sysDimItem.ordinalMeta = null;\n            sysDimItem = clone(sysDimItem);\n            sysDimItem.ordinalMeta = ordinalMeta;\n            // `coordDimIndex` should not be set directly.\n            sysDimItemDimsDef = sysDimItem.dimsDef;\n            sysDimItemOtherDims = sysDimItem.otherDims;\n            sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex\n                = sysDimItem.dimsDef = sysDimItem.otherDims = null;\n        }\n\n        var dataDims = encodeDef.get(coordDim);\n\n        // negative resultDimIdx means no need to mapping.\n        if (dataDims === false) {\n            return;\n        }\n\n        var dataDims = normalizeToArray(dataDims);\n\n        // dimensions provides default dim sequences.\n        if (!dataDims.length) {\n            for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {\n                while (availDimIdx < result.length && result[availDimIdx].coordDim != null) {\n                    availDimIdx++;\n                }\n                availDimIdx < result.length && dataDims.push(availDimIdx++);\n            }\n        }\n\n        // Apply templates.\n        each$1(dataDims, function (resultDimIdx, coordDimIndex) {\n            var resultItem = result[resultDimIdx];\n            applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);\n            if (resultItem.name == null && sysDimItemDimsDef) {\n                var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];\n                !isObject$1(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {name: sysDimItemDimsDefItem});\n                resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;\n                resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;\n            }\n            // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}\n            sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);\n        });\n    });\n\n    function applyDim(resultItem, coordDim, coordDimIndex) {\n        if (OTHER_DIMENSIONS.get(coordDim) != null) {\n            resultItem.otherDims[coordDim] = coordDimIndex;\n        }\n        else {\n            resultItem.coordDim = coordDim;\n            resultItem.coordDimIndex = coordDimIndex;\n            coordDimNameMap.set(coordDim, true);\n        }\n    }\n\n    // Make sure the first extra dim is 'value'.\n    var generateCoord = opt.generateCoord;\n    var generateCoordCount = opt.generateCoordCount;\n    var fromZero = generateCoordCount != null;\n    generateCoordCount = generateCoord ? (generateCoordCount || 1) : 0;\n    var extra = generateCoord || 'value';\n\n    // Set dim `name` and other `coordDim` and other props.\n    for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {\n        var resultItem = result[resultDimIdx] = result[resultDimIdx] || {};\n        var coordDim = resultItem.coordDim;\n\n        if (coordDim == null) {\n            resultItem.coordDim = genName(\n                extra, coordDimNameMap, fromZero\n            );\n            resultItem.coordDimIndex = 0;\n            if (!generateCoord || generateCoordCount <= 0) {\n                resultItem.isExtraCoord = true;\n            }\n            generateCoordCount--;\n        }\n\n        resultItem.name == null && (resultItem.name = genName(\n            resultItem.coordDim,\n            dataDimNameMap\n        ));\n\n        if (resultItem.type == null && guessOrdinal(source, resultDimIdx, resultItem.name)) {\n            resultItem.type = 'ordinal';\n        }\n    }\n\n    return result;\n}\n\n// ??? TODO\n// Originally detect dimCount by data[0]. Should we\n// optimize it to only by sysDims and dimensions and encode.\n// So only necessary dims will be initialized.\n// But\n// (1) custom series should be considered. where other dims\n// may be visited.\n// (2) sometimes user need to calcualte bubble size or use visualMap\n// on other dimensions besides coordSys needed.\n// So, dims that is not used by system, should be shared in storage?\nfunction getDimCount(source, sysDims, dimsDef, optDimCount) {\n    // Note that the result dimCount should not small than columns count\n    // of data, otherwise `dataDimNameMap` checking will be incorrect.\n    var dimCount = Math.max(\n        source.dimensionsDetectCount || 1,\n        sysDims.length,\n        dimsDef.length,\n        optDimCount || 0\n    );\n    each$1(sysDims, function (sysDimItem) {\n        var sysDimItemDimsDef = sysDimItem.dimsDef;\n        sysDimItemDimsDef && (dimCount = Math.max(dimCount, sysDimItemDimsDef.length));\n    });\n    return dimCount;\n}\n\nfunction genName(name, map$$1, fromZero) {\n    if (fromZero || map$$1.get(name) != null) {\n        var i = 0;\n        while (map$$1.get(name + i) != null) {\n            i++;\n        }\n        name += i;\n    }\n    map$$1.set(name, true);\n    return name;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Substitute `completeDimensions`.\n * `completeDimensions` is to be deprecated.\n */\n/**\n * @param {module:echarts/data/Source|module:echarts/data/List} source or data.\n * @param {Object|Array} [opt]\n * @param {Array.<string|Object>} [opt.coordDimensions=[]]\n * @param {number} [opt.dimensionsCount]\n * @param {string} [opt.generateCoord]\n * @param {string} [opt.generateCoordCount]\n * @param {Array.<string|Object>} [opt.dimensionsDefine=source.dimensionsDefine] Overwrite source define.\n * @param {Object|HashMap} [opt.encodeDefine=source.encodeDefine] Overwrite source define.\n * @return {Array.<Object>} dimensionsInfo\n */\nvar createDimensions = function (source, opt) {\n    opt = opt || {};\n    return completeDimensions(opt.coordDimensions || [], source, {\n        dimsDef: opt.dimensionsDefine || source.dimensionsDefine,\n        encodeDef: opt.encodeDefine || source.encodeDefine,\n        dimCount: opt.dimensionsCount,\n        generateCoord: opt.generateCoord,\n        generateCoordCount: opt.generateCoordCount\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Note that it is too complicated to support 3d stack by value\n * (have to create two-dimension inverted index), so in 3d case\n * we just support that stacked by index.\n *\n * @param {module:echarts/model/Series} seriesModel\n * @param {Array.<string|Object>} dimensionInfoList The same as the input of <module:echarts/data/List>.\n *        The input dimensionInfoList will be modified.\n * @param {Object} [opt]\n * @param {boolean} [opt.stackedCoordDimension=''] Specify a coord dimension if needed.\n * @param {boolean} [opt.byIndex=false]\n * @return {Object} calculationInfo\n * {\n *     stackedDimension: string\n *     stackedByDimension: string\n *     isStackedByIndex: boolean\n *     stackedOverDimension: string\n *     stackResultDimension: string\n * }\n */\nfunction enableDataStack(seriesModel, dimensionInfoList, opt) {\n    opt = opt || {};\n    var byIndex = opt.byIndex;\n    var stackedCoordDimension = opt.stackedCoordDimension;\n\n    // Compatibal: when `stack` is set as '', do not stack.\n    var mayStack = !!(seriesModel && seriesModel.get('stack'));\n    var stackedByDimInfo;\n    var stackedDimInfo;\n    var stackResultDimension;\n    var stackedOverDimension;\n\n    each$1(dimensionInfoList, function (dimensionInfo, index) {\n        if (isString(dimensionInfo)) {\n            dimensionInfoList[index] = dimensionInfo = {name: dimensionInfo};\n        }\n\n        if (mayStack && !dimensionInfo.isExtraCoord) {\n            // Find the first ordinal dimension as the stackedByDimInfo.\n            if (!byIndex && !stackedByDimInfo && dimensionInfo.ordinalMeta) {\n                stackedByDimInfo = dimensionInfo;\n            }\n            // Find the first stackable dimension as the stackedDimInfo.\n            if (!stackedDimInfo\n                && dimensionInfo.type !== 'ordinal'\n                && dimensionInfo.type !== 'time'\n                && (!stackedCoordDimension || stackedCoordDimension === dimensionInfo.coordDim)\n            ) {\n                stackedDimInfo = dimensionInfo;\n            }\n        }\n    });\n\n    if (stackedDimInfo && !byIndex && !stackedByDimInfo) {\n        // Compatible with previous design, value axis (time axis) only stack by index.\n        // It may make sense if the user provides elaborately constructed data.\n        byIndex = true;\n    }\n\n    // Add stack dimension, they can be both calculated by coordinate system in `unionExtent`.\n    // That put stack logic in List is for using conveniently in echarts extensions, but it\n    // might not be a good way.\n    if (stackedDimInfo) {\n        // Use a weird name that not duplicated with other names.\n        stackResultDimension = '__\\0ecstackresult';\n        stackedOverDimension = '__\\0ecstackedover';\n\n        // Create inverted index to fast query index by value.\n        if (stackedByDimInfo) {\n            stackedByDimInfo.createInvertedIndices = true;\n        }\n\n        var stackedDimCoordDim = stackedDimInfo.coordDim;\n        var stackedDimType = stackedDimInfo.type;\n        var stackedDimCoordIndex = 0;\n\n        each$1(dimensionInfoList, function (dimensionInfo) {\n            if (dimensionInfo.coordDim === stackedDimCoordDim) {\n                stackedDimCoordIndex++;\n            }\n        });\n\n        dimensionInfoList.push({\n            name: stackResultDimension,\n            coordDim: stackedDimCoordDim,\n            coordDimIndex: stackedDimCoordIndex,\n            type: stackedDimType,\n            isExtraCoord: true,\n            isCalculationCoord: true\n        });\n\n        stackedDimCoordIndex++;\n\n        dimensionInfoList.push({\n            name: stackedOverDimension,\n            // This dimension contains stack base (generally, 0), so do not set it as\n            // `stackedDimCoordDim` to avoid extent calculation, consider log scale.\n            coordDim: stackedOverDimension,\n            coordDimIndex: stackedDimCoordIndex,\n            type: stackedDimType,\n            isExtraCoord: true,\n            isCalculationCoord: true\n        });\n    }\n\n    return {\n        stackedDimension: stackedDimInfo && stackedDimInfo.name,\n        stackedByDimension: stackedByDimInfo && stackedByDimInfo.name,\n        isStackedByIndex: byIndex,\n        stackedOverDimension: stackedOverDimension,\n        stackResultDimension: stackResultDimension\n    };\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {string} stackedDim\n */\nfunction isDimensionStacked(data, stackedDim /*, stackedByDim*/) {\n    // Each single series only maps to one pair of axis. So we do not need to\n    // check stackByDim, whatever stacked by a dimension or stacked by index.\n    return !!stackedDim && stackedDim === data.getCalculationInfo('stackedDimension');\n        // && (\n        //     stackedByDim != null\n        //         ? stackedByDim === data.getCalculationInfo('stackedByDimension')\n        //         : data.getCalculationInfo('isStackedByIndex')\n        // );\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {string} targetDim\n * @param {string} [stackedByDim] If not input this parameter, check whether\n *                                stacked by index.\n * @return {string} dimension\n */\nfunction getStackedDimension(data, targetDim) {\n    return isDimensionStacked(data, targetDim)\n        ? data.getCalculationInfo('stackResultDimension')\n        : targetDim;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/data/Source|Array} source Or raw data.\n * @param {module:echarts/model/Series} seriesModel\n * @param {Object} [opt]\n * @param {string} [opt.generateCoord]\n */\nfunction createListFromArray(source, seriesModel, opt) {\n    opt = opt || {};\n\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n\n    var coordSysName = seriesModel.get('coordinateSystem');\n    var registeredCoordSys = CoordinateSystemManager.get(coordSysName);\n\n    var coordSysDefine = getCoordSysDefineBySeries(seriesModel);\n\n    var coordSysDimDefs;\n\n    if (coordSysDefine) {\n        coordSysDimDefs = map(coordSysDefine.coordSysDims, function (dim) {\n            var dimInfo = {name: dim};\n            var axisModel = coordSysDefine.axisMap.get(dim);\n            if (axisModel) {\n                var axisType = axisModel.get('type');\n                dimInfo.type = getDimensionTypeByAxis(axisType);\n                // dimInfo.stackable = isStackable(axisType);\n            }\n            return dimInfo;\n        });\n    }\n\n    if (!coordSysDimDefs) {\n        // Get dimensions from registered coordinate system\n        coordSysDimDefs = (registeredCoordSys && (\n            registeredCoordSys.getDimensionsInfo\n                ? registeredCoordSys.getDimensionsInfo()\n                : registeredCoordSys.dimensions.slice()\n        )) || ['x', 'y'];\n    }\n\n    var dimInfoList = createDimensions(source, {\n        coordDimensions: coordSysDimDefs,\n        generateCoord: opt.generateCoord\n    });\n\n    var firstCategoryDimIndex;\n    var hasNameEncode;\n    coordSysDefine && each$1(dimInfoList, function (dimInfo, dimIndex) {\n        var coordDim = dimInfo.coordDim;\n        var categoryAxisModel = coordSysDefine.categoryAxisMap.get(coordDim);\n        if (categoryAxisModel) {\n            if (firstCategoryDimIndex == null) {\n                firstCategoryDimIndex = dimIndex;\n            }\n            dimInfo.ordinalMeta = categoryAxisModel.getOrdinalMeta();\n        }\n        if (dimInfo.otherDims.itemName != null) {\n            hasNameEncode = true;\n        }\n    });\n    if (!hasNameEncode && firstCategoryDimIndex != null) {\n        dimInfoList[firstCategoryDimIndex].otherDims.itemName = 0;\n    }\n\n    var stackCalculationInfo = enableDataStack(seriesModel, dimInfoList);\n\n    var list = new List(dimInfoList, seriesModel);\n\n    list.setCalculationInfo(stackCalculationInfo);\n\n    var dimValueGetter = (firstCategoryDimIndex != null && isNeedCompleteOrdinalData(source))\n        ? function (itemOpt, dimName, dataIndex, dimIndex) {\n            // Use dataIndex as ordinal value in categoryAxis\n            return dimIndex === firstCategoryDimIndex\n                ? dataIndex\n                : this.defaultDimValueGetter(itemOpt, dimName, dataIndex, dimIndex);\n        }\n        : null;\n\n    list.hasItemOption = false;\n    list.initData(source, null, dimValueGetter);\n\n    return list;\n}\n\nfunction isNeedCompleteOrdinalData(source) {\n    if (source.sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        var sampleItem = firstDataNotNull(source.data || []);\n        return sampleItem != null\n            && !isArray(getDataItemValue(sampleItem));\n    }\n}\n\nfunction firstDataNotNull(data) {\n    var i = 0;\n    while (i < data.length && data[i] == null) {\n        i++;\n    }\n    return data[i];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.line',\n\n    dependencies: ['grid', 'polar'],\n\n    getInitialData: function (option, ecModel) {\n        if (__DEV__) {\n            var coordSys = option.coordinateSystem;\n            if (coordSys !== 'polar' && coordSys !== 'cartesian2d') {\n                throw new Error('Line not support coordinateSystem besides cartesian and polar');\n            }\n        }\n        return createListFromArray(this.getSource(), this);\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // stack: null\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // polarIndex: 0,\n\n        // If clip the overflow value\n        clipOverflow: true,\n        // cursor: null,\n\n        label: {\n            position: 'top'\n        },\n        // itemStyle: {\n        // },\n\n        lineStyle: {\n            width: 2,\n            type: 'solid'\n        },\n        // areaStyle: {\n            // origin of areaStyle. Valid values:\n            // `'auto'/null/undefined`: from axisLine to data\n            // `'start'`: from min to data\n            // `'end'`: from data to max\n            // origin: 'auto'\n        // },\n        // false, 'start', 'end', 'middle'\n        step: false,\n\n        // Disabled if step is true\n        smooth: false,\n        smoothMonotone: null,\n        symbol: 'emptyCircle',\n        symbolSize: 4,\n        symbolRotate: null,\n\n        showSymbol: true,\n        // `false`: follow the label interval strategy.\n        // `true`: show all symbols.\n        // `'auto'`: If possible, show all symbols, otherwise\n        //           follow the label interval strategy.\n        showAllSymbol: 'auto',\n\n        // Whether to connect break point.\n        connectNulls: false,\n\n        // Sampling for large data. Can be: 'average', 'max', 'min', 'sum'.\n        sampling: 'none',\n\n        animationEasing: 'linear',\n\n        // Disable progressive\n        progressive: 0,\n        hoverLayerThreshold: Infinity\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Symbol factory\n\n/**\n * Triangle shape\n * @inner\n */\nvar Triangle = extendShape({\n    type: 'triangle',\n    shape: {\n        cx: 0,\n        cy: 0,\n        width: 0,\n        height: 0\n    },\n    buildPath: function (path, shape) {\n        var cx = shape.cx;\n        var cy = shape.cy;\n        var width = shape.width / 2;\n        var height = shape.height / 2;\n        path.moveTo(cx, cy - height);\n        path.lineTo(cx + width, cy + height);\n        path.lineTo(cx - width, cy + height);\n        path.closePath();\n    }\n});\n\n/**\n * Diamond shape\n * @inner\n */\nvar Diamond = extendShape({\n    type: 'diamond',\n    shape: {\n        cx: 0,\n        cy: 0,\n        width: 0,\n        height: 0\n    },\n    buildPath: function (path, shape) {\n        var cx = shape.cx;\n        var cy = shape.cy;\n        var width = shape.width / 2;\n        var height = shape.height / 2;\n        path.moveTo(cx, cy - height);\n        path.lineTo(cx + width, cy);\n        path.lineTo(cx, cy + height);\n        path.lineTo(cx - width, cy);\n        path.closePath();\n    }\n});\n\n/**\n * Pin shape\n * @inner\n */\nvar Pin = extendShape({\n    type: 'pin',\n    shape: {\n        // x, y on the cusp\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (path, shape) {\n        var x = shape.x;\n        var y = shape.y;\n        var w = shape.width / 5 * 3;\n        // Height must be larger than width\n        var h = Math.max(w, shape.height);\n        var r = w / 2;\n\n        // Dist on y with tangent point and circle center\n        var dy = r * r / (h - r);\n        var cy = y - h + r + dy;\n        var angle = Math.asin(dy / r);\n        // Dist on x with tangent point and circle center\n        var dx = Math.cos(angle) * r;\n\n        var tanX = Math.sin(angle);\n        var tanY = Math.cos(angle);\n\n        var cpLen = r * 0.6;\n        var cpLen2 = r * 0.7;\n\n        path.moveTo(x - dx, cy + dy);\n\n        path.arc(\n            x, cy, r,\n            Math.PI - angle,\n            Math.PI * 2 + angle\n        );\n        path.bezierCurveTo(\n            x + dx - tanX * cpLen, cy + dy + tanY * cpLen,\n            x, y - cpLen2,\n            x, y\n        );\n        path.bezierCurveTo(\n            x, y - cpLen2,\n            x - dx + tanX * cpLen, cy + dy + tanY * cpLen,\n            x - dx, cy + dy\n        );\n        path.closePath();\n    }\n});\n\n/**\n * Arrow shape\n * @inner\n */\nvar Arrow = extendShape({\n\n    type: 'arrow',\n\n    shape: {\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var height = shape.height;\n        var width = shape.width;\n        var x = shape.x;\n        var y = shape.y;\n        var dx = width / 3 * 2;\n        ctx.moveTo(x, y);\n        ctx.lineTo(x + dx, y + height);\n        ctx.lineTo(x, y + height / 4 * 3);\n        ctx.lineTo(x - dx, y + height);\n        ctx.lineTo(x, y);\n        ctx.closePath();\n    }\n});\n\n/**\n * Map of path contructors\n * @type {Object.<string, module:zrender/graphic/Path>}\n */\nvar symbolCtors = {\n\n    line: Line,\n\n    rect: Rect,\n\n    roundRect: Rect,\n\n    square: Rect,\n\n    circle: Circle,\n\n    diamond: Diamond,\n\n    pin: Pin,\n\n    arrow: Arrow,\n\n    triangle: Triangle\n};\n\nvar symbolShapeMakers = {\n\n    line: function (x, y, w, h, shape) {\n        // FIXME\n        shape.x1 = x;\n        shape.y1 = y + h / 2;\n        shape.x2 = x + w;\n        shape.y2 = y + h / 2;\n    },\n\n    rect: function (x, y, w, h, shape) {\n        shape.x = x;\n        shape.y = y;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    roundRect: function (x, y, w, h, shape) {\n        shape.x = x;\n        shape.y = y;\n        shape.width = w;\n        shape.height = h;\n        shape.r = Math.min(w, h) / 4;\n    },\n\n    square: function (x, y, w, h, shape) {\n        var size = Math.min(w, h);\n        shape.x = x;\n        shape.y = y;\n        shape.width = size;\n        shape.height = size;\n    },\n\n    circle: function (x, y, w, h, shape) {\n        // Put circle in the center of square\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.r = Math.min(w, h) / 2;\n    },\n\n    diamond: function (x, y, w, h, shape) {\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    pin: function (x, y, w, h, shape) {\n        shape.x = x + w / 2;\n        shape.y = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    arrow: function (x, y, w, h, shape) {\n        shape.x = x + w / 2;\n        shape.y = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    triangle: function (x, y, w, h, shape) {\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    }\n};\n\nvar symbolBuildProxies = {};\neach$1(symbolCtors, function (Ctor, name) {\n    symbolBuildProxies[name] = new Ctor();\n});\n\nvar SymbolClz$2 = extendShape({\n\n    type: 'symbol',\n\n    shape: {\n        symbolType: '',\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    beforeBrush: function () {\n        var style = this.style;\n        var shape = this.shape;\n        // FIXME\n        if (shape.symbolType === 'pin' && style.textPosition === 'inside') {\n            style.textPosition = ['50%', '40%'];\n            style.textAlign = 'center';\n            style.textVerticalAlign = 'middle';\n        }\n    },\n\n    buildPath: function (ctx, shape, inBundle) {\n        var symbolType = shape.symbolType;\n        var proxySymbol = symbolBuildProxies[symbolType];\n        if (shape.symbolType !== 'none') {\n            if (!proxySymbol) {\n                // Default rect\n                symbolType = 'rect';\n                proxySymbol = symbolBuildProxies[symbolType];\n            }\n            symbolShapeMakers[symbolType](\n                shape.x, shape.y, shape.width, shape.height, proxySymbol.shape\n            );\n            proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle);\n        }\n    }\n});\n\n// Provide setColor helper method to avoid determine if set the fill or stroke outside\nfunction symbolPathSetColor(color, innerColor) {\n    if (this.type !== 'image') {\n        var symbolStyle = this.style;\n        var symbolShape = this.shape;\n        if (symbolShape && symbolShape.symbolType === 'line') {\n            symbolStyle.stroke = color;\n        }\n        else if (this.__isEmptyBrush) {\n            symbolStyle.stroke = color;\n            symbolStyle.fill = innerColor || '#fff';\n        }\n        else {\n            // FIXME 判断图形默认是填充还是描边，使用 onlyStroke ?\n            symbolStyle.fill && (symbolStyle.fill = color);\n            symbolStyle.stroke && (symbolStyle.stroke = color);\n        }\n        this.dirty(false);\n    }\n}\n\n/**\n * Create a symbol element with given symbol configuration: shape, x, y, width, height, color\n * @param {string} symbolType\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n * @param {string} color\n * @param {boolean} [keepAspect=false] whether to keep the ratio of w/h,\n *                            for path and image only.\n */\nfunction createSymbol(symbolType, x, y, w, h, color, keepAspect) {\n    // TODO Support image object, DynamicImage.\n\n    var isEmpty = symbolType.indexOf('empty') === 0;\n    if (isEmpty) {\n        symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6);\n    }\n    var symbolPath;\n\n    if (symbolType.indexOf('image://') === 0) {\n        symbolPath = makeImage(\n            symbolType.slice(8),\n            new BoundingRect(x, y, w, h),\n            keepAspect ? 'center' : 'cover'\n        );\n    }\n    else if (symbolType.indexOf('path://') === 0) {\n        symbolPath = makePath(\n            symbolType.slice(7),\n            {},\n            new BoundingRect(x, y, w, h),\n            keepAspect ? 'center' : 'cover'\n        );\n    }\n    else {\n        symbolPath = new SymbolClz$2({\n            shape: {\n                symbolType: symbolType,\n                x: x,\n                y: y,\n                width: w,\n                height: h\n            }\n        });\n    }\n\n    symbolPath.__isEmptyBrush = isEmpty;\n\n    symbolPath.setColor = symbolPathSetColor;\n\n    symbolPath.setColor(color);\n\n    return symbolPath;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @return {string} label string. Not null/undefined\n */\nfunction getDefaultLabel(data, dataIndex) {\n    var labelDims = data.mapDimension('defaultedLabel', true);\n    var len = labelDims.length;\n\n    // Simple optimization (in lots of cases, label dims length is 1)\n    if (len === 1) {\n        return retrieveRawValue(data, dataIndex, labelDims[0]);\n    }\n    else if (len) {\n        var vals = [];\n        for (var i = 0; i < labelDims.length; i++) {\n            var val = retrieveRawValue(data, dataIndex, labelDims[i]);\n            vals.push(val);\n        }\n        return vals.join(' ');\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Symbol\n */\n\n/**\n * @constructor\n * @alias {module:echarts/chart/helper/Symbol}\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @extends {module:zrender/graphic/Group}\n */\nfunction SymbolClz(data, idx, seriesScope) {\n    Group.call(this);\n    this.updateData(data, idx, seriesScope);\n}\n\nvar symbolProto = SymbolClz.prototype;\n\n/**\n * @public\n * @static\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @return {Array.<number>} [width, height]\n */\nvar getSymbolSize = SymbolClz.getSymbolSize = function (data, idx) {\n    var symbolSize = data.getItemVisual(idx, 'symbolSize');\n    return symbolSize instanceof Array\n        ? symbolSize.slice()\n        : [+symbolSize, +symbolSize];\n};\n\nfunction getScale(symbolSize) {\n    return [symbolSize[0] / 2, symbolSize[1] / 2];\n}\n\nfunction driftSymbol(dx, dy) {\n    this.parent.drift(dx, dy);\n}\n\nsymbolProto._createSymbol = function (\n    symbolType,\n    data,\n    idx,\n    symbolSize,\n    keepAspect\n) {\n    // Remove paths created before\n    this.removeAll();\n\n    var color = data.getItemVisual(idx, 'color');\n\n    // var symbolPath = createSymbol(\n    //     symbolType, -0.5, -0.5, 1, 1, color\n    // );\n    // If width/height are set too small (e.g., set to 1) on ios10\n    // and macOS Sierra, a circle stroke become a rect, no matter what\n    // the scale is set. So we set width/height as 2. See #4150.\n    var symbolPath = createSymbol(\n        symbolType, -1, -1, 2, 2, color, keepAspect\n    );\n\n    symbolPath.attr({\n        z2: 100,\n        culling: true,\n        scale: getScale(symbolSize)\n    });\n    // Rewrite drift method\n    symbolPath.drift = driftSymbol;\n\n    this._symbolType = symbolType;\n\n    this.add(symbolPath);\n};\n\n/**\n * Stop animation\n * @param {boolean} toLastFrame\n */\nsymbolProto.stopSymbolAnimation = function (toLastFrame) {\n    this.childAt(0).stopAnimation(toLastFrame);\n};\n\n/**\n * FIXME:\n * Caution: This method breaks the encapsulation of this module,\n * but it indeed brings convenience. So do not use the method\n * unless you detailedly know all the implements of `Symbol`,\n * especially animation.\n *\n * Get symbol path element.\n */\nsymbolProto.getSymbolPath = function () {\n    return this.childAt(0);\n};\n\n/**\n * Get scale(aka, current symbol size).\n * Including the change caused by animation\n */\nsymbolProto.getScale = function () {\n    return this.childAt(0).scale;\n};\n\n/**\n * Highlight symbol\n */\nsymbolProto.highlight = function () {\n    this.childAt(0).trigger('emphasis');\n};\n\n/**\n * Downplay symbol\n */\nsymbolProto.downplay = function () {\n    this.childAt(0).trigger('normal');\n};\n\n/**\n * @param {number} zlevel\n * @param {number} z\n */\nsymbolProto.setZ = function (zlevel, z) {\n    var symbolPath = this.childAt(0);\n    symbolPath.zlevel = zlevel;\n    symbolPath.z = z;\n};\n\nsymbolProto.setDraggable = function (draggable) {\n    var symbolPath = this.childAt(0);\n    symbolPath.draggable = draggable;\n    symbolPath.cursor = draggable ? 'move' : 'pointer';\n};\n\n/**\n * Update symbol properties\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @param {Object} [seriesScope]\n * @param {Object} [seriesScope.itemStyle]\n * @param {Object} [seriesScope.hoverItemStyle]\n * @param {Object} [seriesScope.symbolRotate]\n * @param {Object} [seriesScope.symbolOffset]\n * @param {module:echarts/model/Model} [seriesScope.labelModel]\n * @param {module:echarts/model/Model} [seriesScope.hoverLabelModel]\n * @param {boolean} [seriesScope.hoverAnimation]\n * @param {Object} [seriesScope.cursorStyle]\n * @param {module:echarts/model/Model} [seriesScope.itemModel]\n * @param {string} [seriesScope.symbolInnerColor]\n * @param {Object} [seriesScope.fadeIn=false]\n */\nsymbolProto.updateData = function (data, idx, seriesScope) {\n    this.silent = false;\n\n    var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';\n    var seriesModel = data.hostModel;\n    var symbolSize = getSymbolSize(data, idx);\n    var isInit = symbolType !== this._symbolType;\n\n    if (isInit) {\n        var keepAspect = data.getItemVisual(idx, 'symbolKeepAspect');\n        this._createSymbol(symbolType, data, idx, symbolSize, keepAspect);\n    }\n    else {\n        var symbolPath = this.childAt(0);\n        symbolPath.silent = false;\n        updateProps(symbolPath, {\n            scale: getScale(symbolSize)\n        }, seriesModel, idx);\n    }\n\n    this._updateCommon(data, idx, symbolSize, seriesScope);\n\n    if (isInit) {\n        var symbolPath = this.childAt(0);\n        var fadeIn = seriesScope && seriesScope.fadeIn;\n\n        var target = {scale: symbolPath.scale.slice()};\n        fadeIn && (target.style = {opacity: symbolPath.style.opacity});\n\n        symbolPath.scale = [0, 0];\n        fadeIn && (symbolPath.style.opacity = 0);\n\n        initProps(symbolPath, target, seriesModel, idx);\n    }\n\n    this._seriesModel = seriesModel;\n};\n\n// Update common properties\nvar normalStyleAccessPath = ['itemStyle'];\nvar emphasisStyleAccessPath = ['emphasis', 'itemStyle'];\nvar normalLabelAccessPath = ['label'];\nvar emphasisLabelAccessPath = ['emphasis', 'label'];\n\n/**\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @param {Array.<number>} symbolSize\n * @param {Object} [seriesScope]\n */\nsymbolProto._updateCommon = function (data, idx, symbolSize, seriesScope) {\n    var symbolPath = this.childAt(0);\n    var seriesModel = data.hostModel;\n    var color = data.getItemVisual(idx, 'color');\n\n    // Reset style\n    if (symbolPath.type !== 'image') {\n        symbolPath.useStyle({\n            strokeNoScale: true\n        });\n    }\n\n    var itemStyle = seriesScope && seriesScope.itemStyle;\n    var hoverItemStyle = seriesScope && seriesScope.hoverItemStyle;\n    var symbolRotate = seriesScope && seriesScope.symbolRotate;\n    var symbolOffset = seriesScope && seriesScope.symbolOffset;\n    var labelModel = seriesScope && seriesScope.labelModel;\n    var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;\n    var hoverAnimation = seriesScope && seriesScope.hoverAnimation;\n    var cursorStyle = seriesScope && seriesScope.cursorStyle;\n\n    if (!seriesScope || data.hasItemOption) {\n        var itemModel = (seriesScope && seriesScope.itemModel)\n            ? seriesScope.itemModel : data.getItemModel(idx);\n\n        // Color must be excluded.\n        // Because symbol provide setColor individually to set fill and stroke\n        itemStyle = itemModel.getModel(normalStyleAccessPath).getItemStyle(['color']);\n        hoverItemStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();\n\n        symbolRotate = itemModel.getShallow('symbolRotate');\n        symbolOffset = itemModel.getShallow('symbolOffset');\n\n        labelModel = itemModel.getModel(normalLabelAccessPath);\n        hoverLabelModel = itemModel.getModel(emphasisLabelAccessPath);\n        hoverAnimation = itemModel.getShallow('hoverAnimation');\n        cursorStyle = itemModel.getShallow('cursor');\n    }\n    else {\n        hoverItemStyle = extend({}, hoverItemStyle);\n    }\n\n    var elStyle = symbolPath.style;\n\n    symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0);\n\n    if (symbolOffset) {\n        symbolPath.attr('position', [\n            parsePercent$1(symbolOffset[0], symbolSize[0]),\n            parsePercent$1(symbolOffset[1], symbolSize[1])\n        ]);\n    }\n\n    cursorStyle && symbolPath.attr('cursor', cursorStyle);\n\n    // PENDING setColor before setStyle!!!\n    symbolPath.setColor(color, seriesScope && seriesScope.symbolInnerColor);\n\n    symbolPath.setStyle(itemStyle);\n\n    var opacity = data.getItemVisual(idx, 'opacity');\n    if (opacity != null) {\n        elStyle.opacity = opacity;\n    }\n\n    var liftZ = data.getItemVisual(idx, 'liftZ');\n    var z2Origin = symbolPath.__z2Origin;\n    if (liftZ != null) {\n        if (z2Origin == null) {\n            symbolPath.__z2Origin = symbolPath.z2;\n            symbolPath.z2 += liftZ;\n        }\n    }\n    else if (z2Origin != null) {\n        symbolPath.z2 = z2Origin;\n        symbolPath.__z2Origin = null;\n    }\n\n    var useNameLabel = seriesScope && seriesScope.useNameLabel;\n\n    setLabelStyle(\n        elStyle, hoverItemStyle, labelModel, hoverLabelModel,\n        {\n            labelFetcher: seriesModel,\n            labelDataIndex: idx,\n            defaultText: getLabelDefaultText,\n            isRectText: true,\n            autoColor: color\n        }\n    );\n\n    // Do not execute util needed.\n    function getLabelDefaultText(idx, opt) {\n        return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx);\n    }\n\n    symbolPath.off('mouseover')\n        .off('mouseout')\n        .off('emphasis')\n        .off('normal');\n\n    symbolPath.hoverStyle = hoverItemStyle;\n\n    // FIXME\n    // Do not use symbol.trigger('emphasis'), but use symbol.highlight() instead.\n    setHoverStyle(symbolPath);\n\n    symbolPath.__symbolOriginalScale = getScale(symbolSize);\n\n    if (hoverAnimation && seriesModel.isAnimationEnabled()) {\n        // Note: consider `off`, should use static function here.\n        symbolPath.on('mouseover', onMouseOver)\n            .on('mouseout', onMouseOut)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal);\n    }\n};\n\nfunction onMouseOver() {\n    // see comment in `graphic.isInEmphasis`\n    !isInEmphasis(this) && onEmphasis.call(this);\n}\n\nfunction onMouseOut() {\n    // see comment in `graphic.isInEmphasis`\n    !isInEmphasis(this) && onNormal.call(this);\n}\n\nfunction onEmphasis() {\n    // Do not support this hover animation util some scenario required.\n    // Animation can only be supported in hover layer when using `el.incremetal`.\n    if (this.incremental || this.useHoverLayer) {\n        return;\n    }\n    var scale = this.__symbolOriginalScale;\n    var ratio = scale[1] / scale[0];\n    this.animateTo({\n        scale: [\n            Math.max(scale[0] * 1.1, scale[0] + 3),\n            Math.max(scale[1] * 1.1, scale[1] + 3 * ratio)\n        ]\n    }, 400, 'elasticOut');\n}\n\nfunction onNormal() {\n    if (this.incremental || this.useHoverLayer) {\n        return;\n    }\n    this.animateTo({\n        scale: this.__symbolOriginalScale\n    }, 400, 'elasticOut');\n}\n\n\n/**\n * @param {Function} cb\n * @param {Object} [opt]\n * @param {Object} [opt.keepLabel=true]\n */\nsymbolProto.fadeOut = function (cb, opt) {\n    var symbolPath = this.childAt(0);\n    // Avoid mistaken hover when fading out\n    this.silent = symbolPath.silent = true;\n    // Not show text when animating\n    !(opt && opt.keepLabel) && (symbolPath.style.text = null);\n\n    updateProps(\n        symbolPath,\n        {\n            style: {opacity: 0},\n            scale: [0, 0]\n        },\n        this._seriesModel,\n        this.dataIndex,\n        cb\n    );\n};\n\ninherits(SymbolClz, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/SymbolDraw\n */\n\n/**\n * @constructor\n * @alias module:echarts/chart/helper/SymbolDraw\n * @param {module:zrender/graphic/Group} [symbolCtor]\n */\nfunction SymbolDraw(symbolCtor) {\n    this.group = new Group();\n\n    this._symbolCtor = symbolCtor || SymbolClz;\n}\n\nvar symbolDrawProto = SymbolDraw.prototype;\n\nfunction symbolNeedsDraw(data, point, idx, opt) {\n    return point && !isNaN(point[0]) && !isNaN(point[1])\n        && !(opt.isIgnore && opt.isIgnore(idx))\n        // We do not set clipShape on group, because it will cut part of\n        // the symbol element shape. We use the same clip shape here as\n        // the line clip.\n        && !(opt.clipShape && !opt.clipShape.contain(point[0], point[1]))\n        && data.getItemVisual(idx, 'symbol') !== 'none';\n}\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n * @param {Object} [opt] Or isIgnore\n * @param {Function} [opt.isIgnore]\n * @param {Object} [opt.clipShape]\n */\nsymbolDrawProto.updateData = function (data, opt) {\n    opt = normalizeUpdateOpt(opt);\n\n    var group = this.group;\n    var seriesModel = data.hostModel;\n    var oldData = this._data;\n    var SymbolCtor = this._symbolCtor;\n\n    var seriesScope = makeSeriesScope(data);\n\n    // There is no oldLineData only when first rendering or switching from\n    // stream mode to normal mode, where previous elements should be removed.\n    if (!oldData) {\n        group.removeAll();\n    }\n\n    data.diff(oldData)\n        .add(function (newIdx) {\n            var point = data.getItemLayout(newIdx);\n            if (symbolNeedsDraw(data, point, newIdx, opt)) {\n                var symbolEl = new SymbolCtor(data, newIdx, seriesScope);\n                symbolEl.attr('position', point);\n                data.setItemGraphicEl(newIdx, symbolEl);\n                group.add(symbolEl);\n            }\n        })\n        .update(function (newIdx, oldIdx) {\n            var symbolEl = oldData.getItemGraphicEl(oldIdx);\n            var point = data.getItemLayout(newIdx);\n            if (!symbolNeedsDraw(data, point, newIdx, opt)) {\n                group.remove(symbolEl);\n                return;\n            }\n            if (!symbolEl) {\n                symbolEl = new SymbolCtor(data, newIdx);\n                symbolEl.attr('position', point);\n            }\n            else {\n                symbolEl.updateData(data, newIdx, seriesScope);\n                updateProps(symbolEl, {\n                    position: point\n                }, seriesModel);\n            }\n\n            // Add back\n            group.add(symbolEl);\n\n            data.setItemGraphicEl(newIdx, symbolEl);\n        })\n        .remove(function (oldIdx) {\n            var el = oldData.getItemGraphicEl(oldIdx);\n            el && el.fadeOut(function () {\n                group.remove(el);\n            });\n        })\n        .execute();\n\n    this._data = data;\n};\n\nsymbolDrawProto.isPersistent = function () {\n    return true;\n};\n\nsymbolDrawProto.updateLayout = function () {\n    var data = this._data;\n    if (data) {\n        // Not use animation\n        data.eachItemGraphicEl(function (el, idx) {\n            var point = data.getItemLayout(idx);\n            el.attr('position', point);\n        });\n    }\n};\n\nsymbolDrawProto.incrementalPrepareUpdate = function (data) {\n    this._seriesScope = makeSeriesScope(data);\n    this._data = null;\n    this.group.removeAll();\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n * @param {Object} [opt] Or isIgnore\n * @param {Function} [opt.isIgnore]\n * @param {Object} [opt.clipShape]\n */\nsymbolDrawProto.incrementalUpdate = function (taskParams, data, opt) {\n    opt = normalizeUpdateOpt(opt);\n\n    function updateIncrementalAndHover(el) {\n        if (!el.isGroup) {\n            el.incremental = el.useHoverLayer = true;\n        }\n    }\n    for (var idx = taskParams.start; idx < taskParams.end; idx++) {\n        var point = data.getItemLayout(idx);\n        if (symbolNeedsDraw(data, point, idx, opt)) {\n            var el = new this._symbolCtor(data, idx, this._seriesScope);\n            el.traverse(updateIncrementalAndHover);\n            el.attr('position', point);\n            this.group.add(el);\n            data.setItemGraphicEl(idx, el);\n        }\n    }\n};\n\nfunction normalizeUpdateOpt(opt) {\n    if (opt != null && !isObject$1(opt)) {\n        opt = {isIgnore: opt};\n    }\n    return opt || {};\n}\n\nsymbolDrawProto.remove = function (enableAnimation) {\n    var group = this.group;\n    var data = this._data;\n    // Incremental model do not have this._data.\n    if (data && enableAnimation) {\n        data.eachItemGraphicEl(function (el) {\n            el.fadeOut(function () {\n                group.remove(el);\n            });\n        });\n    }\n    else {\n        group.removeAll();\n    }\n};\n\nfunction makeSeriesScope(data) {\n    var seriesModel = data.hostModel;\n    return {\n        itemStyle: seriesModel.getModel('itemStyle').getItemStyle(['color']),\n        hoverItemStyle: seriesModel.getModel('emphasis.itemStyle').getItemStyle(),\n        symbolRotate: seriesModel.get('symbolRotate'),\n        symbolOffset: seriesModel.get('symbolOffset'),\n        hoverAnimation: seriesModel.get('hoverAnimation'),\n        labelModel: seriesModel.getModel('label'),\n        hoverLabelModel: seriesModel.getModel('emphasis.label'),\n        cursorStyle: seriesModel.get('cursor')\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} coordSys\n * @param {module:echarts/data/List} data\n * @param {string} valueOrigin lineSeries.option.areaStyle.origin\n */\nfunction prepareDataCoordInfo(coordSys, data, valueOrigin) {\n    var baseAxis = coordSys.getBaseAxis();\n    var valueAxis = coordSys.getOtherAxis(baseAxis);\n    var valueStart = getValueStart(valueAxis, valueOrigin);\n\n    var baseAxisDim = baseAxis.dim;\n    var valueAxisDim = valueAxis.dim;\n    var valueDim = data.mapDimension(valueAxisDim);\n    var baseDim = data.mapDimension(baseAxisDim);\n    var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0;\n\n    var dims = map(coordSys.dimensions, function (coordDim) {\n        return data.mapDimension(coordDim);\n    });\n\n    var stacked;\n    var stackResultDim = data.getCalculationInfo('stackResultDimension');\n    if (stacked |= isDimensionStacked(data, dims[0] /*, dims[1]*/)) { // jshint ignore:line\n        dims[0] = stackResultDim;\n    }\n    if (stacked |= isDimensionStacked(data, dims[1] /*, dims[0]*/)) { // jshint ignore:line\n        dims[1] = stackResultDim;\n    }\n\n    return {\n        dataDimsForPoint: dims,\n        valueStart: valueStart,\n        valueAxisDim: valueAxisDim,\n        baseAxisDim: baseAxisDim,\n        stacked: !!stacked,\n        valueDim: valueDim,\n        baseDim: baseDim,\n        baseDataOffset: baseDataOffset,\n        stackedOverDimension: data.getCalculationInfo('stackedOverDimension')\n    };\n}\n\nfunction getValueStart(valueAxis, valueOrigin) {\n    var valueStart = 0;\n    var extent = valueAxis.scale.getExtent();\n\n    if (valueOrigin === 'start') {\n        valueStart = extent[0];\n    }\n    else if (valueOrigin === 'end') {\n        valueStart = extent[1];\n    }\n    // auto\n    else {\n        // Both positive\n        if (extent[0] > 0) {\n            valueStart = extent[0];\n        }\n        // Both negative\n        else if (extent[1] < 0) {\n            valueStart = extent[1];\n        }\n        // If is one positive, and one negative, onZero shall be true\n    }\n\n    return valueStart;\n}\n\nfunction getStackedOnPoint(dataCoordInfo, coordSys, data, idx) {\n    var value = NaN;\n    if (dataCoordInfo.stacked) {\n        value = data.get(data.getCalculationInfo('stackedOverDimension'), idx);\n    }\n    if (isNaN(value)) {\n        value = dataCoordInfo.valueStart;\n    }\n\n    var baseDataOffset = dataCoordInfo.baseDataOffset;\n    var stackedData = [];\n    stackedData[baseDataOffset] = data.get(dataCoordInfo.baseDim, idx);\n    stackedData[1 - baseDataOffset] = value;\n\n    return coordSys.dataToPoint(stackedData);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// var arrayDiff = require('zrender/src/core/arrayDiff');\n// 'zrender/src/core/arrayDiff' has been used before, but it did\n// not do well in performance when roam with fixed dataZoom window.\n\n// function convertToIntId(newIdList, oldIdList) {\n//     // Generate int id instead of string id.\n//     // Compare string maybe slow in score function of arrDiff\n\n//     // Assume id in idList are all unique\n//     var idIndicesMap = {};\n//     var idx = 0;\n//     for (var i = 0; i < newIdList.length; i++) {\n//         idIndicesMap[newIdList[i]] = idx;\n//         newIdList[i] = idx++;\n//     }\n//     for (var i = 0; i < oldIdList.length; i++) {\n//         var oldId = oldIdList[i];\n//         // Same with newIdList\n//         if (idIndicesMap[oldId]) {\n//             oldIdList[i] = idIndicesMap[oldId];\n//         }\n//         else {\n//             oldIdList[i] = idx++;\n//         }\n//     }\n// }\n\nfunction diffData(oldData, newData) {\n    var diffResult = [];\n\n    newData.diff(oldData)\n        .add(function (idx) {\n            diffResult.push({cmd: '+', idx: idx});\n        })\n        .update(function (newIdx, oldIdx) {\n            diffResult.push({cmd: '=', idx: oldIdx, idx1: newIdx});\n        })\n        .remove(function (idx) {\n            diffResult.push({cmd: '-', idx: idx});\n        })\n        .execute();\n\n    return diffResult;\n}\n\nvar lineAnimationDiff = function (\n    oldData, newData,\n    oldStackedOnPoints, newStackedOnPoints,\n    oldCoordSys, newCoordSys,\n    oldValueOrigin, newValueOrigin\n) {\n    var diff = diffData(oldData, newData);\n\n    // var newIdList = newData.mapArray(newData.getId);\n    // var oldIdList = oldData.mapArray(oldData.getId);\n\n    // convertToIntId(newIdList, oldIdList);\n\n    // // FIXME One data ?\n    // diff = arrayDiff(oldIdList, newIdList);\n\n    var currPoints = [];\n    var nextPoints = [];\n    // Points for stacking base line\n    var currStackedPoints = [];\n    var nextStackedPoints = [];\n\n    var status = [];\n    var sortedIndices = [];\n    var rawIndices = [];\n\n    var newDataOldCoordInfo = prepareDataCoordInfo(oldCoordSys, newData, oldValueOrigin);\n    var oldDataNewCoordInfo = prepareDataCoordInfo(newCoordSys, oldData, newValueOrigin);\n\n    for (var i = 0; i < diff.length; i++) {\n        var diffItem = diff[i];\n        var pointAdded = true;\n\n        // FIXME, animation is not so perfect when dataZoom window moves fast\n        // Which is in case remvoing or add more than one data in the tail or head\n        switch (diffItem.cmd) {\n            case '=':\n                var currentPt = oldData.getItemLayout(diffItem.idx);\n                var nextPt = newData.getItemLayout(diffItem.idx1);\n                // If previous data is NaN, use next point directly\n                if (isNaN(currentPt[0]) || isNaN(currentPt[1])) {\n                    currentPt = nextPt.slice();\n                }\n                currPoints.push(currentPt);\n                nextPoints.push(nextPt);\n\n                currStackedPoints.push(oldStackedOnPoints[diffItem.idx]);\n                nextStackedPoints.push(newStackedOnPoints[diffItem.idx1]);\n\n                rawIndices.push(newData.getRawIndex(diffItem.idx1));\n                break;\n            case '+':\n                var idx = diffItem.idx;\n                currPoints.push(\n                    oldCoordSys.dataToPoint([\n                        newData.get(newDataOldCoordInfo.dataDimsForPoint[0], idx),\n                        newData.get(newDataOldCoordInfo.dataDimsForPoint[1], idx)\n                    ])\n                );\n\n                nextPoints.push(newData.getItemLayout(idx).slice());\n\n                currStackedPoints.push(\n                    getStackedOnPoint(newDataOldCoordInfo, oldCoordSys, newData, idx)\n                );\n                nextStackedPoints.push(newStackedOnPoints[idx]);\n\n                rawIndices.push(newData.getRawIndex(idx));\n                break;\n            case '-':\n                var idx = diffItem.idx;\n                var rawIndex = oldData.getRawIndex(idx);\n                // Data is replaced. In the case of dynamic data queue\n                // FIXME FIXME FIXME\n                if (rawIndex !== idx) {\n                    currPoints.push(oldData.getItemLayout(idx));\n                    nextPoints.push(newCoordSys.dataToPoint([\n                        oldData.get(oldDataNewCoordInfo.dataDimsForPoint[0], idx),\n                        oldData.get(oldDataNewCoordInfo.dataDimsForPoint[1], idx)\n                    ]));\n\n                    currStackedPoints.push(oldStackedOnPoints[idx]);\n                    nextStackedPoints.push(\n                        getStackedOnPoint(oldDataNewCoordInfo, newCoordSys, oldData, idx)\n                    );\n\n                    rawIndices.push(rawIndex);\n                }\n                else {\n                    pointAdded = false;\n                }\n        }\n\n        // Original indices\n        if (pointAdded) {\n            status.push(diffItem);\n            sortedIndices.push(sortedIndices.length);\n        }\n    }\n\n    // Diff result may be crossed if all items are changed\n    // Sort by data index\n    sortedIndices.sort(function (a, b) {\n        return rawIndices[a] - rawIndices[b];\n    });\n\n    var sortedCurrPoints = [];\n    var sortedNextPoints = [];\n\n    var sortedCurrStackedPoints = [];\n    var sortedNextStackedPoints = [];\n\n    var sortedStatus = [];\n    for (var i = 0; i < sortedIndices.length; i++) {\n        var idx = sortedIndices[i];\n        sortedCurrPoints[i] = currPoints[idx];\n        sortedNextPoints[i] = nextPoints[idx];\n\n        sortedCurrStackedPoints[i] = currStackedPoints[idx];\n        sortedNextStackedPoints[i] = nextStackedPoints[idx];\n\n        sortedStatus[i] = status[idx];\n    }\n\n    return {\n        current: sortedCurrPoints,\n        next: sortedNextPoints,\n\n        stackedOnCurrent: sortedCurrStackedPoints,\n        stackedOnNext: sortedNextStackedPoints,\n\n        status: sortedStatus\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Poly path support NaN point\n\nvar vec2Min = min;\nvar vec2Max = max;\n\nvar scaleAndAdd$1 = scaleAndAdd;\nvar v2Copy = copy;\n\n// Temporary variable\nvar v = [];\nvar cp0 = [];\nvar cp1 = [];\n\nfunction isPointNull(p) {\n    return isNaN(p[0]) || isNaN(p[1]);\n}\n\nfunction drawSegment(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    // if (smoothMonotone == null) {\n    //     if (isMono(points, 'x')) {\n    //         return drawMono(ctx, points, start, segLen, allLen,\n    //             dir, smoothMin, smoothMax, smooth, 'x', connectNulls);\n    //     }\n    //     else if (isMono(points, 'y')) {\n    //         return drawMono(ctx, points, start, segLen, allLen,\n    //             dir, smoothMin, smoothMax, smooth, 'y', connectNulls);\n    //     }\n    //     else {\n    //         return drawNonMono.apply(this, arguments);\n    //     }\n    // }\n    // else if (smoothMonotone !== 'none' && isMono(points, smoothMonotone)) {\n    //     return drawMono.apply(this, arguments);\n    // }\n    // else {\n    //     return drawNonMono.apply(this, arguments);\n    // }\n    if (smoothMonotone === 'none' || !smoothMonotone) {\n        return drawNonMono.apply(this, arguments);\n    }\n    else {\n        return drawMono.apply(this, arguments);\n    }\n}\n\n/**\n * Check if points is in monotone.\n *\n * @param {number[][]} points         Array of points which is in [x, y] form\n * @param {string}     smoothMonotone 'x', 'y', or 'none', stating for which\n *                                    dimension that is checking.\n *                                    If is 'none', `drawNonMono` should be\n *                                    called.\n *                                    If is undefined, either being monotone\n *                                    in 'x' or 'y' will call `drawMono`.\n */\n// function isMono(points, smoothMonotone) {\n//     if (points.length <= 1) {\n//         return true;\n//     }\n\n//     var dim = smoothMonotone === 'x' ? 0 : 1;\n//     var last = points[0][dim];\n//     var lastDiff = 0;\n//     for (var i = 1; i < points.length; ++i) {\n//         var diff = points[i][dim] - last;\n//         if (!isNaN(diff) && !isNaN(lastDiff)\n//             && diff !== 0 && lastDiff !== 0\n//             && ((diff >= 0) !== (lastDiff >= 0))\n//         ) {\n//             return false;\n//         }\n//         if (!isNaN(diff) && diff !== 0) {\n//             lastDiff = diff;\n//             last = points[i][dim];\n//         }\n//     }\n//     return true;\n// }\n\n/**\n * Draw smoothed line in monotone, in which only vertical or horizontal bezier\n * control points will be used. This should be used when points are monotone\n * either in x or y dimension.\n */\nfunction drawMono(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    var prevIdx = 0;\n    var idx = start;\n    for (var k = 0; k < segLen; k++) {\n        var p = points[idx];\n        if (idx >= allLen || idx < 0) {\n            break;\n        }\n        if (isPointNull(p)) {\n            if (connectNulls) {\n                idx += dir;\n                continue;\n            }\n            break;\n        }\n\n        if (idx === start) {\n            ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);\n        }\n        else {\n            if (smooth > 0) {\n                var prevP = points[prevIdx];\n                var dim = smoothMonotone === 'y' ? 1 : 0;\n\n                // Length of control point to p, either in x or y, but not both\n                var ctrlLen = (p[dim] - prevP[dim]) * smooth;\n\n                v2Copy(cp0, prevP);\n                cp0[dim] = prevP[dim] + ctrlLen;\n\n                v2Copy(cp1, p);\n                cp1[dim] = p[dim] - ctrlLen;\n\n                ctx.bezierCurveTo(\n                    cp0[0], cp0[1],\n                    cp1[0], cp1[1],\n                    p[0], p[1]\n                );\n            }\n            else {\n                ctx.lineTo(p[0], p[1]);\n            }\n        }\n\n        prevIdx = idx;\n        idx += dir;\n    }\n\n    return k;\n}\n\n/**\n * Draw smoothed line in non-monotone, in may cause undesired curve in extreme\n * situations. This should be used when points are non-monotone neither in x or\n * y dimension.\n */\nfunction drawNonMono(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    var prevIdx = 0;\n    var idx = start;\n    for (var k = 0; k < segLen; k++) {\n        var p = points[idx];\n        if (idx >= allLen || idx < 0) {\n            break;\n        }\n        if (isPointNull(p)) {\n            if (connectNulls) {\n                idx += dir;\n                continue;\n            }\n            break;\n        }\n\n        if (idx === start) {\n            ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);\n            v2Copy(cp0, p);\n        }\n        else {\n            if (smooth > 0) {\n                var nextIdx = idx + dir;\n                var nextP = points[nextIdx];\n                if (connectNulls) {\n                    // Find next point not null\n                    while (nextP && isPointNull(points[nextIdx])) {\n                        nextIdx += dir;\n                        nextP = points[nextIdx];\n                    }\n                }\n\n                var ratioNextSeg = 0.5;\n                var prevP = points[prevIdx];\n                var nextP = points[nextIdx];\n                // Last point\n                if (!nextP || isPointNull(nextP)) {\n                    v2Copy(cp1, p);\n                }\n                else {\n                    // If next data is null in not connect case\n                    if (isPointNull(nextP) && !connectNulls) {\n                        nextP = p;\n                    }\n\n                    sub(v, nextP, prevP);\n\n                    var lenPrevSeg;\n                    var lenNextSeg;\n                    if (smoothMonotone === 'x' || smoothMonotone === 'y') {\n                        var dim = smoothMonotone === 'x' ? 0 : 1;\n                        lenPrevSeg = Math.abs(p[dim] - prevP[dim]);\n                        lenNextSeg = Math.abs(p[dim] - nextP[dim]);\n                    }\n                    else {\n                        lenPrevSeg = dist(p, prevP);\n                        lenNextSeg = dist(p, nextP);\n                    }\n\n                    // Use ratio of seg length\n                    ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg);\n\n                    scaleAndAdd$1(cp1, p, v, -smooth * (1 - ratioNextSeg));\n                }\n                // Smooth constraint\n                vec2Min(cp0, cp0, smoothMax);\n                vec2Max(cp0, cp0, smoothMin);\n                vec2Min(cp1, cp1, smoothMax);\n                vec2Max(cp1, cp1, smoothMin);\n\n                ctx.bezierCurveTo(\n                    cp0[0], cp0[1],\n                    cp1[0], cp1[1],\n                    p[0], p[1]\n                );\n                // cp0 of next segment\n                scaleAndAdd$1(cp0, p, v, smooth * ratioNextSeg);\n            }\n            else {\n                ctx.lineTo(p[0], p[1]);\n            }\n        }\n\n        prevIdx = idx;\n        idx += dir;\n    }\n\n    return k;\n}\n\nfunction getBoundingBox(points, smoothConstraint) {\n    var ptMin = [Infinity, Infinity];\n    var ptMax = [-Infinity, -Infinity];\n    if (smoothConstraint) {\n        for (var i = 0; i < points.length; i++) {\n            var pt = points[i];\n            if (pt[0] < ptMin[0]) {\n                ptMin[0] = pt[0];\n            }\n            if (pt[1] < ptMin[1]) {\n                ptMin[1] = pt[1];\n            }\n            if (pt[0] > ptMax[0]) {\n                ptMax[0] = pt[0];\n            }\n            if (pt[1] > ptMax[1]) {\n                ptMax[1] = pt[1];\n            }\n        }\n    }\n    return {\n        min: smoothConstraint ? ptMin : ptMax,\n        max: smoothConstraint ? ptMax : ptMin\n    };\n}\n\nvar Polyline$1 = Path.extend({\n\n    type: 'ec-polyline',\n\n    shape: {\n        points: [],\n\n        smooth: 0,\n\n        smoothConstraint: true,\n\n        smoothMonotone: null,\n\n        connectNulls: false\n    },\n\n    style: {\n        fill: null,\n\n        stroke: '#000'\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n        var points = shape.points;\n\n        var i = 0;\n        var len$$1 = points.length;\n\n        var result = getBoundingBox(points, shape.smoothConstraint);\n\n        if (shape.connectNulls) {\n            // Must remove first and last null values avoid draw error in polygon\n            for (; len$$1 > 0; len$$1--) {\n                if (!isPointNull(points[len$$1 - 1])) {\n                    break;\n                }\n            }\n            for (; i < len$$1; i++) {\n                if (!isPointNull(points[i])) {\n                    break;\n                }\n            }\n        }\n        while (i < len$$1) {\n            i += drawSegment(\n                ctx, points, i, len$$1, len$$1,\n                1, result.min, result.max, shape.smooth,\n                shape.smoothMonotone, shape.connectNulls\n            ) + 1;\n        }\n    }\n});\n\nvar Polygon$1 = Path.extend({\n\n    type: 'ec-polygon',\n\n    shape: {\n        points: [],\n\n        // Offset between stacked base points and points\n        stackedOnPoints: [],\n\n        smooth: 0,\n\n        stackedOnSmooth: 0,\n\n        smoothConstraint: true,\n\n        smoothMonotone: null,\n\n        connectNulls: false\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n        var points = shape.points;\n        var stackedOnPoints = shape.stackedOnPoints;\n\n        var i = 0;\n        var len$$1 = points.length;\n        var smoothMonotone = shape.smoothMonotone;\n        var bbox = getBoundingBox(points, shape.smoothConstraint);\n        var stackedOnBBox = getBoundingBox(stackedOnPoints, shape.smoothConstraint);\n\n        if (shape.connectNulls) {\n            // Must remove first and last null values avoid draw error in polygon\n            for (; len$$1 > 0; len$$1--) {\n                if (!isPointNull(points[len$$1 - 1])) {\n                    break;\n                }\n            }\n            for (; i < len$$1; i++) {\n                if (!isPointNull(points[i])) {\n                    break;\n                }\n            }\n        }\n        while (i < len$$1) {\n            var k = drawSegment(\n                ctx, points, i, len$$1, len$$1,\n                1, bbox.min, bbox.max, shape.smooth,\n                smoothMonotone, shape.connectNulls\n            );\n            drawSegment(\n                ctx, stackedOnPoints, i + k - 1, k, len$$1,\n                -1, stackedOnBBox.min, stackedOnBBox.max, shape.stackedOnSmooth,\n                smoothMonotone, shape.connectNulls\n            );\n            i += k + 1;\n\n            ctx.closePath();\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME step not support polar\n\nfunction isPointsSame(points1, points2) {\n    if (points1.length !== points2.length) {\n        return;\n    }\n    for (var i = 0; i < points1.length; i++) {\n        var p1 = points1[i];\n        var p2 = points2[i];\n        if (p1[0] !== p2[0] || p1[1] !== p2[1]) {\n            return;\n        }\n    }\n    return true;\n}\n\nfunction getSmooth(smooth) {\n    return typeof (smooth) === 'number' ? smooth : (smooth ? 0.5 : 0);\n}\n\nfunction getAxisExtentWithGap(axis) {\n    var extent = axis.getGlobalExtent();\n    if (axis.onBand) {\n        // Remove extra 1px to avoid line miter in clipped edge\n        var halfBandWidth = axis.getBandWidth() / 2 - 1;\n        var dir = extent[1] > extent[0] ? 1 : -1;\n        extent[0] += dir * halfBandWidth;\n        extent[1] -= dir * halfBandWidth;\n    }\n    return extent;\n}\n\n/**\n * @param {module:echarts/coord/cartesian/Cartesian2D|module:echarts/coord/polar/Polar} coordSys\n * @param {module:echarts/data/List} data\n * @param {Object} dataCoordInfo\n * @param {Array.<Array.<number>>} points\n */\nfunction getStackedOnPoints(coordSys, data, dataCoordInfo) {\n    if (!dataCoordInfo.valueDim) {\n        return [];\n    }\n\n    var points = [];\n    for (var idx = 0, len = data.count(); idx < len; idx++) {\n        points.push(getStackedOnPoint(dataCoordInfo, coordSys, data, idx));\n    }\n\n    return points;\n}\n\nfunction createGridClipShape(cartesian, hasAnimation, forSymbol, seriesModel) {\n    var xExtent = getAxisExtentWithGap(cartesian.getAxis('x'));\n    var yExtent = getAxisExtentWithGap(cartesian.getAxis('y'));\n    var isHorizontal = cartesian.getBaseAxis().isHorizontal();\n\n    var x = Math.min(xExtent[0], xExtent[1]);\n    var y = Math.min(yExtent[0], yExtent[1]);\n    var width = Math.max(xExtent[0], xExtent[1]) - x;\n    var height = Math.max(yExtent[0], yExtent[1]) - y;\n\n    // Avoid float number rounding error for symbol on the edge of axis extent.\n    // See #7913 and `test/dataZoom-clip.html`.\n    if (forSymbol) {\n        x -= 0.5;\n        width += 0.5;\n        y -= 0.5;\n        height += 0.5;\n    }\n    else {\n        var lineWidth = seriesModel.get('lineStyle.width') || 2;\n        // Expand clip shape to avoid clipping when line value exceeds axis\n        var expandSize = seriesModel.get('clipOverflow') ? lineWidth / 2 : Math.max(width, height);\n        if (isHorizontal) {\n            y -= expandSize;\n            height += expandSize * 2;\n        }\n        else {\n            x -= expandSize;\n            width += expandSize * 2;\n        }\n    }\n\n    var clipPath = new Rect({\n        shape: {\n            x: x,\n            y: y,\n            width: width,\n            height: height\n        }\n    });\n\n    if (hasAnimation) {\n        clipPath.shape[isHorizontal ? 'width' : 'height'] = 0;\n        initProps(clipPath, {\n            shape: {\n                width: width,\n                height: height\n            }\n        }, seriesModel);\n    }\n\n    return clipPath;\n}\n\nfunction createPolarClipShape(polar, hasAnimation, forSymbol, seriesModel) {\n    var angleAxis = polar.getAngleAxis();\n    var radiusAxis = polar.getRadiusAxis();\n\n    var radiusExtent = radiusAxis.getExtent().slice();\n    radiusExtent[0] > radiusExtent[1] && radiusExtent.reverse();\n    var angleExtent = angleAxis.getExtent();\n\n    var RADIAN = Math.PI / 180;\n\n    // Avoid float number rounding error for symbol on the edge of axis extent.\n    if (forSymbol) {\n        radiusExtent[0] -= 0.5;\n        radiusExtent[1] += 0.5;\n    }\n\n    var clipPath = new Sector({\n        shape: {\n            cx: round$2(polar.cx, 1),\n            cy: round$2(polar.cy, 1),\n            r0: round$2(radiusExtent[0], 1),\n            r: round$2(radiusExtent[1], 1),\n            startAngle: -angleExtent[0] * RADIAN,\n            endAngle: -angleExtent[1] * RADIAN,\n            clockwise: angleAxis.inverse\n        }\n    });\n\n    if (hasAnimation) {\n        clipPath.shape.endAngle = -angleExtent[0] * RADIAN;\n        initProps(clipPath, {\n            shape: {\n                endAngle: -angleExtent[1] * RADIAN\n            }\n        }, seriesModel);\n    }\n\n    return clipPath;\n}\n\nfunction createClipShape(coordSys, hasAnimation, forSymbol, seriesModel) {\n    return coordSys.type === 'polar'\n        ? createPolarClipShape(coordSys, hasAnimation, forSymbol, seriesModel)\n        : createGridClipShape(coordSys, hasAnimation, forSymbol, seriesModel);\n}\n\nfunction turnPointsIntoStep(points, coordSys, stepTurnAt) {\n    var baseAxis = coordSys.getBaseAxis();\n    var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1;\n\n    var stepPoints = [];\n    for (var i = 0; i < points.length - 1; i++) {\n        var nextPt = points[i + 1];\n        var pt = points[i];\n        stepPoints.push(pt);\n\n        var stepPt = [];\n        switch (stepTurnAt) {\n            case 'end':\n                stepPt[baseIndex] = nextPt[baseIndex];\n                stepPt[1 - baseIndex] = pt[1 - baseIndex];\n                // default is start\n                stepPoints.push(stepPt);\n                break;\n            case 'middle':\n                // default is start\n                var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2;\n                var stepPt2 = [];\n                stepPt[baseIndex] = stepPt2[baseIndex] = middle;\n                stepPt[1 - baseIndex] = pt[1 - baseIndex];\n                stepPt2[1 - baseIndex] = nextPt[1 - baseIndex];\n                stepPoints.push(stepPt);\n                stepPoints.push(stepPt2);\n                break;\n            default:\n                stepPt[baseIndex] = pt[baseIndex];\n                stepPt[1 - baseIndex] = nextPt[1 - baseIndex];\n                // default is start\n                stepPoints.push(stepPt);\n        }\n    }\n    // Last points\n    points[i] && stepPoints.push(points[i]);\n    return stepPoints;\n}\n\nfunction getVisualGradient(data, coordSys) {\n    var visualMetaList = data.getVisual('visualMeta');\n    if (!visualMetaList || !visualMetaList.length || !data.count()) {\n        // When data.count() is 0, gradient range can not be calculated.\n        return;\n    }\n\n    if (coordSys.type !== 'cartesian2d') {\n        if (__DEV__) {\n            console.warn('Visual map on line style is only supported on cartesian2d.');\n        }\n        return;\n    }\n\n    var coordDim;\n    var visualMeta;\n\n    for (var i = visualMetaList.length - 1; i >= 0; i--) {\n        var dimIndex = visualMetaList[i].dimension;\n        var dimName = data.dimensions[dimIndex];\n        var dimInfo = data.getDimensionInfo(dimName);\n        coordDim = dimInfo && dimInfo.coordDim;\n        // Can only be x or y\n        if (coordDim === 'x' || coordDim === 'y') {\n            visualMeta = visualMetaList[i];\n            break;\n        }\n    }\n\n    if (!visualMeta) {\n        if (__DEV__) {\n            console.warn('Visual map on line style only support x or y dimension.');\n        }\n        return;\n    }\n\n    // If the area to be rendered is bigger than area defined by LinearGradient,\n    // the canvas spec prescribes that the color of the first stop and the last\n    // stop should be used. But if two stops are added at offset 0, in effect\n    // browsers use the color of the second stop to render area outside\n    // LinearGradient. So we can only infinitesimally extend area defined in\n    // LinearGradient to render `outerColors`.\n\n    var axis = coordSys.getAxis(coordDim);\n\n    // dataToCoor mapping may not be linear, but must be monotonic.\n    var colorStops = map(visualMeta.stops, function (stop) {\n        return {\n            coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)),\n            color: stop.color\n        };\n    });\n    var stopLen = colorStops.length;\n    var outerColors = visualMeta.outerColors.slice();\n\n    if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) {\n        colorStops.reverse();\n        outerColors.reverse();\n    }\n\n    var tinyExtent = 10; // Arbitrary value: 10px\n    var minCoord = colorStops[0].coord - tinyExtent;\n    var maxCoord = colorStops[stopLen - 1].coord + tinyExtent;\n    var coordSpan = maxCoord - minCoord;\n\n    if (coordSpan < 1e-3) {\n        return 'transparent';\n    }\n\n    each$1(colorStops, function (stop) {\n        stop.offset = (stop.coord - minCoord) / coordSpan;\n    });\n    colorStops.push({\n        offset: stopLen ? colorStops[stopLen - 1].offset : 0.5,\n        color: outerColors[1] || 'transparent'\n    });\n    colorStops.unshift({ // notice colorStops.length have been changed.\n        offset: stopLen ? colorStops[0].offset : 0.5,\n        color: outerColors[0] || 'transparent'\n    });\n\n    // zrUtil.each(colorStops, function (colorStop) {\n    //     // Make sure each offset has rounded px to avoid not sharp edge\n    //     colorStop.offset = (Math.round(colorStop.offset * (end - start) + start) - start) / (end - start);\n    // });\n\n    var gradient = new LinearGradient(0, 0, 0, 0, colorStops, true);\n    gradient[coordDim] = minCoord;\n    gradient[coordDim + '2'] = maxCoord;\n\n    return gradient;\n}\n\nfunction getIsIgnoreFunc(seriesModel, data, coordSys) {\n    var showAllSymbol = seriesModel.get('showAllSymbol');\n    var isAuto = showAllSymbol === 'auto';\n\n    if (showAllSymbol && !isAuto) {\n        return;\n    }\n\n    var categoryAxis = coordSys.getAxesByScale('ordinal')[0];\n    if (!categoryAxis) {\n        return;\n    }\n\n    // Note that category label interval strategy might bring some weird effect\n    // in some scenario: users may wonder why some of the symbols are not\n    // displayed. So we show all symbols as possible as we can.\n    if (isAuto\n        // Simplify the logic, do not determine label overlap here.\n        && canShowAllSymbolForCategory(categoryAxis, data)\n    ) {\n        return;\n    }\n\n    // Otherwise follow the label interval strategy on category axis.\n    var categoryDataDim = data.mapDimension(categoryAxis.dim);\n    var labelMap = {};\n\n    each$1(categoryAxis.getViewLabels(), function (labelItem) {\n        labelMap[labelItem.tickValue] = 1;\n    });\n\n    return function (dataIndex) {\n        return !labelMap.hasOwnProperty(data.get(categoryDataDim, dataIndex));\n    };\n}\n\nfunction canShowAllSymbolForCategory(categoryAxis, data) {\n    // In mose cases, line is monotonous on category axis, and the label size\n    // is close with each other. So we check the symbol size and some of the\n    // label size alone with the category axis to estimate whether all symbol\n    // can be shown without overlap.\n    var axisExtent = categoryAxis.getExtent();\n    var availSize = Math.abs(axisExtent[1] - axisExtent[0]) / categoryAxis.scale.count();\n    isNaN(availSize) && (availSize = 0); // 0/0 is NaN.\n\n    // Sampling some points, max 5.\n    var dataLen = data.count();\n    var step = Math.max(1, Math.round(dataLen / 5));\n    for (var dataIndex = 0; dataIndex < dataLen; dataIndex += step) {\n        if (SymbolClz.getSymbolSize(\n                data, dataIndex\n            // Only for cartesian, where `isHorizontal` exists.\n            )[categoryAxis.isHorizontal() ? 1 : 0]\n            // Empirical number\n            * 1.5 > availSize\n        ) {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nChart.extend({\n\n    type: 'line',\n\n    init: function () {\n        var lineGroup = new Group();\n\n        var symbolDraw = new SymbolDraw();\n        this.group.add(symbolDraw.group);\n\n        this._symbolDraw = symbolDraw;\n        this._lineGroup = lineGroup;\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var group = this.group;\n        var data = seriesModel.getData();\n        var lineStyleModel = seriesModel.getModel('lineStyle');\n        var areaStyleModel = seriesModel.getModel('areaStyle');\n\n        var points = data.mapArray(data.getItemLayout);\n\n        var isCoordSysPolar = coordSys.type === 'polar';\n        var prevCoordSys = this._coordSys;\n\n        var symbolDraw = this._symbolDraw;\n        var polyline = this._polyline;\n        var polygon = this._polygon;\n\n        var lineGroup = this._lineGroup;\n\n        var hasAnimation = seriesModel.get('animation');\n\n        var isAreaChart = !areaStyleModel.isEmpty();\n\n        var valueOrigin = areaStyleModel.get('origin');\n        var dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin);\n\n        var stackedOnPoints = getStackedOnPoints(coordSys, data, dataCoordInfo);\n\n        var showSymbol = seriesModel.get('showSymbol');\n\n        var isIgnoreFunc = showSymbol && !isCoordSysPolar\n            && getIsIgnoreFunc(seriesModel, data, coordSys);\n\n        // Remove temporary symbols\n        var oldData = this._data;\n        oldData && oldData.eachItemGraphicEl(function (el, idx) {\n            if (el.__temp) {\n                group.remove(el);\n                oldData.setItemGraphicEl(idx, null);\n            }\n        });\n\n        // Remove previous created symbols if showSymbol changed to false\n        if (!showSymbol) {\n            symbolDraw.remove();\n        }\n\n        group.add(lineGroup);\n\n        // FIXME step not support polar\n        var step = !isCoordSysPolar && seriesModel.get('step');\n        // Initialization animation or coordinate system changed\n        if (\n            !(polyline && prevCoordSys.type === coordSys.type && step === this._step)\n        ) {\n            showSymbol && symbolDraw.updateData(data, {\n                isIgnore: isIgnoreFunc,\n                clipShape: createClipShape(coordSys, false, true, seriesModel)\n            });\n\n            if (step) {\n                // TODO If stacked series is not step\n                points = turnPointsIntoStep(points, coordSys, step);\n                stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);\n            }\n\n            polyline = this._newPolyline(points, coordSys, hasAnimation);\n            if (isAreaChart) {\n                polygon = this._newPolygon(\n                    points, stackedOnPoints,\n                    coordSys, hasAnimation\n                );\n            }\n            lineGroup.setClipPath(createClipShape(coordSys, true, false, seriesModel));\n        }\n        else {\n            if (isAreaChart && !polygon) {\n                // If areaStyle is added\n                polygon = this._newPolygon(\n                    points, stackedOnPoints,\n                    coordSys, hasAnimation\n                );\n            }\n            else if (polygon && !isAreaChart) {\n                // If areaStyle is removed\n                lineGroup.remove(polygon);\n                polygon = this._polygon = null;\n            }\n\n            // Update clipPath\n            lineGroup.setClipPath(createClipShape(coordSys, false, false, seriesModel));\n\n            // Always update, or it is wrong in the case turning on legend\n            // because points are not changed\n            showSymbol && symbolDraw.updateData(data, {\n                isIgnore: isIgnoreFunc,\n                clipShape: createClipShape(coordSys, false, true, seriesModel)\n            });\n\n            // Stop symbol animation and sync with line points\n            // FIXME performance?\n            data.eachItemGraphicEl(function (el) {\n                el.stopAnimation(true);\n            });\n\n            // In the case data zoom triggerred refreshing frequently\n            // Data may not change if line has a category axis. So it should animate nothing\n            if (!isPointsSame(this._stackedOnPoints, stackedOnPoints)\n                || !isPointsSame(this._points, points)\n            ) {\n                if (hasAnimation) {\n                    this._updateAnimation(\n                        data, stackedOnPoints, coordSys, api, step, valueOrigin\n                    );\n                }\n                else {\n                    // Not do it in update with animation\n                    if (step) {\n                        // TODO If stacked series is not step\n                        points = turnPointsIntoStep(points, coordSys, step);\n                        stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);\n                    }\n\n                    polyline.setShape({\n                        points: points\n                    });\n                    polygon && polygon.setShape({\n                        points: points,\n                        stackedOnPoints: stackedOnPoints\n                    });\n                }\n            }\n        }\n\n        var visualColor = getVisualGradient(data, coordSys) || data.getVisual('color');\n\n        polyline.useStyle(defaults(\n            // Use color in lineStyle first\n            lineStyleModel.getLineStyle(),\n            {\n                fill: 'none',\n                stroke: visualColor,\n                lineJoin: 'bevel'\n            }\n        ));\n\n        var smooth = seriesModel.get('smooth');\n        smooth = getSmooth(seriesModel.get('smooth'));\n        polyline.setShape({\n            smooth: smooth,\n            smoothMonotone: seriesModel.get('smoothMonotone'),\n            connectNulls: seriesModel.get('connectNulls')\n        });\n\n        if (polygon) {\n            var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');\n            var stackedOnSmooth = 0;\n\n            polygon.useStyle(defaults(\n                areaStyleModel.getAreaStyle(),\n                {\n                    fill: visualColor,\n                    opacity: 0.7,\n                    lineJoin: 'bevel'\n                }\n            ));\n\n            if (stackedOnSeries) {\n                stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth'));\n            }\n\n            polygon.setShape({\n                smooth: smooth,\n                stackedOnSmooth: stackedOnSmooth,\n                smoothMonotone: seriesModel.get('smoothMonotone'),\n                connectNulls: seriesModel.get('connectNulls')\n            });\n        }\n\n        this._data = data;\n        // Save the coordinate system for transition animation when data changed\n        this._coordSys = coordSys;\n        this._stackedOnPoints = stackedOnPoints;\n        this._points = points;\n        this._step = step;\n        this._valueOrigin = valueOrigin;\n    },\n\n    dispose: function () {},\n\n    highlight: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n        var dataIndex = queryDataIndex(data, payload);\n\n        if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) {\n            var symbol = data.getItemGraphicEl(dataIndex);\n            if (!symbol) {\n                // Create a temporary symbol if it is not exists\n                var pt = data.getItemLayout(dataIndex);\n                if (!pt) {\n                    // Null data\n                    return;\n                }\n                symbol = new SymbolClz(data, dataIndex);\n                symbol.position = pt;\n                symbol.setZ(\n                    seriesModel.get('zlevel'),\n                    seriesModel.get('z')\n                );\n                symbol.ignore = isNaN(pt[0]) || isNaN(pt[1]);\n                symbol.__temp = true;\n                data.setItemGraphicEl(dataIndex, symbol);\n\n                // Stop scale animation\n                symbol.stopSymbolAnimation(true);\n\n                this.group.add(symbol);\n            }\n            symbol.highlight();\n        }\n        else {\n            // Highlight whole series\n            Chart.prototype.highlight.call(\n                this, seriesModel, ecModel, api, payload\n            );\n        }\n    },\n\n    downplay: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n        var dataIndex = queryDataIndex(data, payload);\n        if (dataIndex != null && dataIndex >= 0) {\n            var symbol = data.getItemGraphicEl(dataIndex);\n            if (symbol) {\n                if (symbol.__temp) {\n                    data.setItemGraphicEl(dataIndex, null);\n                    this.group.remove(symbol);\n                }\n                else {\n                    symbol.downplay();\n                }\n            }\n        }\n        else {\n            // FIXME\n            // can not downplay completely.\n            // Downplay whole series\n            Chart.prototype.downplay.call(\n                this, seriesModel, ecModel, api, payload\n            );\n        }\n    },\n\n    /**\n     * @param {module:zrender/container/Group} group\n     * @param {Array.<Array.<number>>} points\n     * @private\n     */\n    _newPolyline: function (points) {\n        var polyline = this._polyline;\n        // Remove previous created polyline\n        if (polyline) {\n            this._lineGroup.remove(polyline);\n        }\n\n        polyline = new Polyline$1({\n            shape: {\n                points: points\n            },\n            silent: true,\n            z2: 10\n        });\n\n        this._lineGroup.add(polyline);\n\n        this._polyline = polyline;\n\n        return polyline;\n    },\n\n    /**\n     * @param {module:zrender/container/Group} group\n     * @param {Array.<Array.<number>>} stackedOnPoints\n     * @param {Array.<Array.<number>>} points\n     * @private\n     */\n    _newPolygon: function (points, stackedOnPoints) {\n        var polygon = this._polygon;\n        // Remove previous created polygon\n        if (polygon) {\n            this._lineGroup.remove(polygon);\n        }\n\n        polygon = new Polygon$1({\n            shape: {\n                points: points,\n                stackedOnPoints: stackedOnPoints\n            },\n            silent: true\n        });\n\n        this._lineGroup.add(polygon);\n\n        this._polygon = polygon;\n        return polygon;\n    },\n\n    /**\n     * @private\n     */\n    // FIXME Two value axis\n    _updateAnimation: function (data, stackedOnPoints, coordSys, api, step, valueOrigin) {\n        var polyline = this._polyline;\n        var polygon = this._polygon;\n        var seriesModel = data.hostModel;\n\n        var diff = lineAnimationDiff(\n            this._data, data,\n            this._stackedOnPoints, stackedOnPoints,\n            this._coordSys, coordSys,\n            this._valueOrigin, valueOrigin\n        );\n\n        var current = diff.current;\n        var stackedOnCurrent = diff.stackedOnCurrent;\n        var next = diff.next;\n        var stackedOnNext = diff.stackedOnNext;\n        if (step) {\n            // TODO If stacked series is not step\n            current = turnPointsIntoStep(diff.current, coordSys, step);\n            stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step);\n            next = turnPointsIntoStep(diff.next, coordSys, step);\n            stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step);\n        }\n        // `diff.current` is subset of `current` (which should be ensured by\n        // turnPointsIntoStep), so points in `__points` can be updated when\n        // points in `current` are update during animation.\n        polyline.shape.__points = diff.current;\n        polyline.shape.points = current;\n\n        updateProps(polyline, {\n            shape: {\n                points: next\n            }\n        }, seriesModel);\n\n        if (polygon) {\n            polygon.setShape({\n                points: current,\n                stackedOnPoints: stackedOnCurrent\n            });\n            updateProps(polygon, {\n                shape: {\n                    points: next,\n                    stackedOnPoints: stackedOnNext\n                }\n            }, seriesModel);\n        }\n\n        var updatedDataInfo = [];\n        var diffStatus = diff.status;\n\n        for (var i = 0; i < diffStatus.length; i++) {\n            var cmd = diffStatus[i].cmd;\n            if (cmd === '=') {\n                var el = data.getItemGraphicEl(diffStatus[i].idx1);\n                if (el) {\n                    updatedDataInfo.push({\n                        el: el,\n                        ptIdx: i    // Index of points\n                    });\n                }\n            }\n        }\n\n        if (polyline.animators && polyline.animators.length) {\n            polyline.animators[0].during(function () {\n                for (var i = 0; i < updatedDataInfo.length; i++) {\n                    var el = updatedDataInfo[i].el;\n                    el.attr('position', polyline.shape.__points[updatedDataInfo[i].ptIdx]);\n                }\n            });\n        }\n    },\n\n    remove: function (ecModel) {\n        var group = this.group;\n        var oldData = this._data;\n        this._lineGroup.removeAll();\n        this._symbolDraw.remove(true);\n        // Remove temporary created elements when highlighting\n        oldData && oldData.eachItemGraphicEl(function (el, idx) {\n            if (el.__temp) {\n                group.remove(el);\n                oldData.setItemGraphicEl(idx, null);\n            }\n        });\n\n        this._polyline\n            = this._polygon\n            = this._coordSys\n            = this._points\n            = this._stackedOnPoints\n            = this._data = null;\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar visualSymbol = function (seriesType, defaultSymbolType, legendSymbol) {\n    // Encoding visual for all series include which is filtered for legend drawing\n    return {\n        seriesType: seriesType,\n\n        // For legend.\n        performRawSeries: true,\n\n        reset: function (seriesModel, ecModel, api) {\n            var data = seriesModel.getData();\n\n            var symbolType = seriesModel.get('symbol') || defaultSymbolType;\n            var symbolSize = seriesModel.get('symbolSize');\n            var keepAspect = seriesModel.get('symbolKeepAspect');\n\n            data.setVisual({\n                legendSymbol: legendSymbol || symbolType,\n                symbol: symbolType,\n                symbolSize: symbolSize,\n                symbolKeepAspect: keepAspect\n            });\n\n            // Only visible series has each data be visual encoded\n            if (ecModel.isSeriesFiltered(seriesModel)) {\n                return;\n            }\n\n            var hasCallback = typeof symbolSize === 'function';\n\n            function dataEach(data, idx) {\n                if (typeof symbolSize === 'function') {\n                    var rawValue = seriesModel.getRawValue(idx);\n                    // FIXME\n                    var params = seriesModel.getDataParams(idx);\n                    data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params));\n                }\n\n                if (data.hasItemOption) {\n                    var itemModel = data.getItemModel(idx);\n                    var itemSymbolType = itemModel.getShallow('symbol', true);\n                    var itemSymbolSize = itemModel.getShallow('symbolSize',\n                        true);\n                    var itemSymbolKeepAspect\n                        = itemModel.getShallow('symbolKeepAspect', true);\n\n                    // If has item symbol\n                    if (itemSymbolType != null) {\n                        data.setItemVisual(idx, 'symbol', itemSymbolType);\n                    }\n                    if (itemSymbolSize != null) {\n                        // PENDING Transform symbolSize ?\n                        data.setItemVisual(idx, 'symbolSize', itemSymbolSize);\n                    }\n                    if (itemSymbolKeepAspect != null) {\n                        data.setItemVisual(idx, 'symbolKeepAspect',\n                            itemSymbolKeepAspect);\n                    }\n                }\n            }\n\n            return { dataEach: (data.hasItemOption || hasCallback) ? dataEach : null };\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar layoutPoints = function (seriesType) {\n    return {\n        seriesType: seriesType,\n\n        plan: createRenderPlanner(),\n\n        reset: function (seriesModel) {\n            var data = seriesModel.getData();\n            var coordSys = seriesModel.coordinateSystem;\n            var pipelineContext = seriesModel.pipelineContext;\n            var isLargeRender = pipelineContext.large;\n\n            if (!coordSys) {\n                return;\n            }\n\n            var dims = map(coordSys.dimensions, function (dim) {\n                return data.mapDimension(dim);\n            }).slice(0, 2);\n            var dimLen = dims.length;\n\n            var stackResultDim = data.getCalculationInfo('stackResultDimension');\n            if (isDimensionStacked(data, dims[0] /*, dims[1]*/)) {\n                dims[0] = stackResultDim;\n            }\n            if (isDimensionStacked(data, dims[1] /*, dims[0]*/)) {\n                dims[1] = stackResultDim;\n            }\n\n            function progress(params, data) {\n                var segCount = params.end - params.start;\n                var points = isLargeRender && new Float32Array(segCount * dimLen);\n\n                for (var i = params.start, offset = 0, tmpIn = [], tmpOut = []; i < params.end; i++) {\n                    var point;\n\n                    if (dimLen === 1) {\n                        var x = data.get(dims[0], i);\n                        point = !isNaN(x) && coordSys.dataToPoint(x, null, tmpOut);\n                    }\n                    else {\n                        var x = tmpIn[0] = data.get(dims[0], i);\n                        var y = tmpIn[1] = data.get(dims[1], i);\n                        // Also {Array.<number>}, not undefined to avoid if...else... statement\n                        point = !isNaN(x) && !isNaN(y) && coordSys.dataToPoint(tmpIn, null, tmpOut);\n                    }\n\n                    if (isLargeRender) {\n                        points[offset++] = point ? point[0] : NaN;\n                        points[offset++] = point ? point[1] : NaN;\n                    }\n                    else {\n                        data.setItemLayout(i, (point && point.slice()) || [NaN, NaN]);\n                    }\n                }\n\n                isLargeRender && data.setLayout('symbolPoints', points);\n            }\n\n            return dimLen && {progress: progress};\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar samplers = {\n    average: function (frame) {\n        var sum = 0;\n        var count = 0;\n        for (var i = 0; i < frame.length; i++) {\n            if (!isNaN(frame[i])) {\n                sum += frame[i];\n                count++;\n            }\n        }\n        // Return NaN if count is 0\n        return count === 0 ? NaN : sum / count;\n    },\n    sum: function (frame) {\n        var sum = 0;\n        for (var i = 0; i < frame.length; i++) {\n            // Ignore NaN\n            sum += frame[i] || 0;\n        }\n        return sum;\n    },\n    max: function (frame) {\n        var max = -Infinity;\n        for (var i = 0; i < frame.length; i++) {\n            frame[i] > max && (max = frame[i]);\n        }\n        // NaN will cause illegal axis extent.\n        return isFinite(max) ? max : NaN;\n    },\n    min: function (frame) {\n        var min = Infinity;\n        for (var i = 0; i < frame.length; i++) {\n            frame[i] < min && (min = frame[i]);\n        }\n        // NaN will cause illegal axis extent.\n        return isFinite(min) ? min : NaN;\n    },\n    // TODO\n    // Median\n    nearest: function (frame) {\n        return frame[0];\n    }\n};\n\nvar indexSampler = function (frame, value) {\n    return Math.round(frame.length / 2);\n};\n\nvar dataSample = function (seriesType) {\n    return {\n\n        seriesType: seriesType,\n\n        modifyOutputEnd: true,\n\n        reset: function (seriesModel, ecModel, api) {\n            var data = seriesModel.getData();\n            var sampling = seriesModel.get('sampling');\n            var coordSys = seriesModel.coordinateSystem;\n            // Only cartesian2d support down sampling\n            if (coordSys.type === 'cartesian2d' && sampling) {\n                var baseAxis = coordSys.getBaseAxis();\n                var valueAxis = coordSys.getOtherAxis(baseAxis);\n                var extent = baseAxis.getExtent();\n                // Coordinste system has been resized\n                var size = extent[1] - extent[0];\n                var rate = Math.round(data.count() / size);\n                if (rate > 1) {\n                    var sampler;\n                    if (typeof sampling === 'string') {\n                        sampler = samplers[sampling];\n                    }\n                    else if (typeof sampling === 'function') {\n                        sampler = sampling;\n                    }\n                    if (sampler) {\n                        // Only support sample the first dim mapped from value axis.\n                        seriesModel.setData(data.downSample(\n                            data.mapDimension(valueAxis.dim), 1 / rate, sampler, indexSampler\n                        ));\n                    }\n                }\n            }\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * // Scale class management\n * @module echarts/scale/Scale\n */\n\n/**\n * @param {Object} [setting]\n */\nfunction Scale(setting) {\n    this._setting = setting || {};\n\n    /**\n     * Extent\n     * @type {Array.<number>}\n     * @protected\n     */\n    this._extent = [Infinity, -Infinity];\n\n    /**\n     * Step is calculated in adjustExtent\n     * @type {Array.<number>}\n     * @protected\n     */\n    this._interval = 0;\n\n    this.init && this.init.apply(this, arguments);\n}\n\n/**\n * Parse input val to valid inner number.\n * @param {*} val\n * @return {number}\n */\nScale.prototype.parse = function (val) {\n    // Notice: This would be a trap here, If the implementation\n    // of this method depends on extent, and this method is used\n    // before extent set (like in dataZoom), it would be wrong.\n    // Nevertheless, parse does not depend on extent generally.\n    return val;\n};\n\nScale.prototype.getSetting = function (name) {\n    return this._setting[name];\n};\n\nScale.prototype.contain = function (val) {\n    var extent = this._extent;\n    return val >= extent[0] && val <= extent[1];\n};\n\n/**\n * Normalize value to linear [0, 1], return 0.5 if extent span is 0\n * @param {number} val\n * @return {number}\n */\nScale.prototype.normalize = function (val) {\n    var extent = this._extent;\n    if (extent[1] === extent[0]) {\n        return 0.5;\n    }\n    return (val - extent[0]) / (extent[1] - extent[0]);\n};\n\n/**\n * Scale normalized value\n * @param {number} val\n * @return {number}\n */\nScale.prototype.scale = function (val) {\n    var extent = this._extent;\n    return val * (extent[1] - extent[0]) + extent[0];\n};\n\n/**\n * Set extent from data\n * @param {Array.<number>} other\n */\nScale.prototype.unionExtent = function (other) {\n    var extent = this._extent;\n    other[0] < extent[0] && (extent[0] = other[0]);\n    other[1] > extent[1] && (extent[1] = other[1]);\n    // not setExtent because in log axis it may transformed to power\n    // this.setExtent(extent[0], extent[1]);\n};\n\n/**\n * Set extent from data\n * @param {module:echarts/data/List} data\n * @param {string} dim\n */\nScale.prototype.unionExtentFromData = function (data, dim) {\n    this.unionExtent(data.getApproximateExtent(dim));\n};\n\n/**\n * Get extent\n * @return {Array.<number>}\n */\nScale.prototype.getExtent = function () {\n    return this._extent.slice();\n};\n\n/**\n * Set extent\n * @param {number} start\n * @param {number} end\n */\nScale.prototype.setExtent = function (start, end) {\n    var thisExtent = this._extent;\n    if (!isNaN(start)) {\n        thisExtent[0] = start;\n    }\n    if (!isNaN(end)) {\n        thisExtent[1] = end;\n    }\n};\n\n/**\n * When axis extent depends on data and no data exists,\n * axis ticks should not be drawn, which is named 'blank'.\n */\nScale.prototype.isBlank = function () {\n    return this._isBlank;\n},\n\n/**\n * When axis extent depends on data and no data exists,\n * axis ticks should not be drawn, which is named 'blank'.\n */\nScale.prototype.setBlank = function (isBlank) {\n    this._isBlank = isBlank;\n};\n\n/**\n * @abstract\n * @param {*} tick\n * @return {string} label of the tick.\n */\nScale.prototype.getLabel = null;\n\n\nenableClassExtend(Scale);\nenableClassManagement(Scale, {\n    registerWhenExtend: true\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @constructor\n * @param {Object} [opt]\n * @param {Object} [opt.categories=[]]\n * @param {Object} [opt.needCollect=false]\n * @param {Object} [opt.deduplication=false]\n */\nfunction OrdinalMeta(opt) {\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    this.categories = opt.categories || [];\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._needCollect = opt.needCollect;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._deduplication = opt.deduplication;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._map;\n}\n\n/**\n * @param {module:echarts/model/Model} axisModel\n * @return {module:echarts/data/OrdinalMeta}\n */\nOrdinalMeta.createByAxisModel = function (axisModel) {\n    var option = axisModel.option;\n    var data = option.data;\n    var categories = data && map(data, getName);\n\n    return new OrdinalMeta({\n        categories: categories,\n        needCollect: !categories,\n        // deduplication is default in axis.\n        deduplication: option.dedplication !== false\n    });\n};\n\nvar proto$1 = OrdinalMeta.prototype;\n\n/**\n * @param {string} category\n * @return {number} ordinal\n */\nproto$1.getOrdinal = function (category) {\n    return getOrCreateMap(this).get(category);\n};\n\n/**\n * @param {*} category\n * @return {number} The ordinal. If not found, return NaN.\n */\nproto$1.parseAndCollect = function (category) {\n    var index;\n    var needCollect = this._needCollect;\n\n    // The value of category dim can be the index of the given category set.\n    // This feature is only supported when !needCollect, because we should\n    // consider a common case: a value is 2017, which is a number but is\n    // expected to be tread as a category. This case usually happen in dataset,\n    // where it happent to be no need of the index feature.\n    if (typeof category !== 'string' && !needCollect) {\n        return category;\n    }\n\n    // Optimize for the scenario:\n    // category is ['2012-01-01', '2012-01-02', ...], where the input\n    // data has been ensured not duplicate and is large data.\n    // Notice, if a dataset dimension provide categroies, usually echarts\n    // should remove duplication except user tell echarts dont do that\n    // (set axis.deduplication = false), because echarts do not know whether\n    // the values in the category dimension has duplication (consider the\n    // parallel-aqi example)\n    if (needCollect && !this._deduplication) {\n        index = this.categories.length;\n        this.categories[index] = category;\n        return index;\n    }\n\n    var map$$1 = getOrCreateMap(this);\n    index = map$$1.get(category);\n\n    if (index == null) {\n        if (needCollect) {\n            index = this.categories.length;\n            this.categories[index] = category;\n            map$$1.set(category, index);\n        }\n        else {\n            index = NaN;\n        }\n    }\n\n    return index;\n};\n\n// Consider big data, do not create map until needed.\nfunction getOrCreateMap(ordinalMeta) {\n    return ordinalMeta._map || (\n        ordinalMeta._map = createHashMap(ordinalMeta.categories)\n    );\n}\n\nfunction getName(obj) {\n    if (isObject$1(obj) && obj.value != null) {\n        return obj.value;\n    }\n    else {\n        return obj + '';\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Linear continuous scale\n * @module echarts/coord/scale/Ordinal\n *\n * http://en.wikipedia.org/wiki/Level_of_measurement\n */\n\n// FIXME only one data\n\nvar scaleProto = Scale.prototype;\n\nvar OrdinalScale = Scale.extend({\n\n    type: 'ordinal',\n\n    /**\n     * @param {module:echarts/data/OrdianlMeta|Array.<string>} ordinalMeta\n     */\n    init: function (ordinalMeta, extent) {\n        // Caution: Should not use instanceof, consider ec-extensions using\n        // import approach to get OrdinalMeta class.\n        if (!ordinalMeta || isArray(ordinalMeta)) {\n            ordinalMeta = new OrdinalMeta({categories: ordinalMeta});\n        }\n        this._ordinalMeta = ordinalMeta;\n        this._extent = extent || [0, ordinalMeta.categories.length - 1];\n    },\n\n    parse: function (val) {\n        return typeof val === 'string'\n            ? this._ordinalMeta.getOrdinal(val)\n            // val might be float.\n            : Math.round(val);\n    },\n\n    contain: function (rank) {\n        rank = this.parse(rank);\n        return scaleProto.contain.call(this, rank)\n            && this._ordinalMeta.categories[rank] != null;\n    },\n\n    /**\n     * Normalize given rank or name to linear [0, 1]\n     * @param {number|string} [val]\n     * @return {number}\n     */\n    normalize: function (val) {\n        return scaleProto.normalize.call(this, this.parse(val));\n    },\n\n    scale: function (val) {\n        return Math.round(scaleProto.scale.call(this, val));\n    },\n\n    /**\n     * @return {Array}\n     */\n    getTicks: function () {\n        var ticks = [];\n        var extent = this._extent;\n        var rank = extent[0];\n\n        while (rank <= extent[1]) {\n            ticks.push(rank);\n            rank++;\n        }\n\n        return ticks;\n    },\n\n    /**\n     * Get item on rank n\n     * @param {number} n\n     * @return {string}\n     */\n    getLabel: function (n) {\n        if (!this.isBlank()) {\n            // Note that if no data, ordinalMeta.categories is an empty array.\n            return this._ordinalMeta.categories[n];\n        }\n    },\n\n    /**\n     * @return {number}\n     */\n    count: function () {\n        return this._extent[1] - this._extent[0] + 1;\n    },\n\n    /**\n     * @override\n     */\n    unionExtentFromData: function (data, dim) {\n        this.unionExtent(data.getApproximateExtent(dim));\n    },\n\n    getOrdinalMeta: function () {\n        return this._ordinalMeta;\n    },\n\n    niceTicks: noop,\n    niceExtent: noop\n});\n\n/**\n * @return {module:echarts/scale/Time}\n */\nOrdinalScale.create = function () {\n    return new OrdinalScale();\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * For testable.\n */\n\nvar roundNumber$1 = round$2;\n\n/**\n * @param {Array.<number>} extent Both extent[0] and extent[1] should be valid number.\n *                                Should be extent[0] < extent[1].\n * @param {number} splitNumber splitNumber should be >= 1.\n * @param {number} [minInterval]\n * @param {number} [maxInterval]\n * @return {Object} {interval, intervalPrecision, niceTickExtent}\n */\nfunction intervalScaleNiceTicks(extent, splitNumber, minInterval, maxInterval) {\n    var result = {};\n    var span = extent[1] - extent[0];\n\n    var interval = result.interval = nice(span / splitNumber, true);\n    if (minInterval != null && interval < minInterval) {\n        interval = result.interval = minInterval;\n    }\n    if (maxInterval != null && interval > maxInterval) {\n        interval = result.interval = maxInterval;\n    }\n    // Tow more digital for tick.\n    var precision = result.intervalPrecision = getIntervalPrecision(interval);\n    // Niced extent inside original extent\n    var niceTickExtent = result.niceTickExtent = [\n        roundNumber$1(Math.ceil(extent[0] / interval) * interval, precision),\n        roundNumber$1(Math.floor(extent[1] / interval) * interval, precision)\n    ];\n\n    fixExtent(niceTickExtent, extent);\n\n    return result;\n}\n\n/**\n * @param {number} interval\n * @return {number} interval precision\n */\nfunction getIntervalPrecision(interval) {\n    // Tow more digital for tick.\n    return getPrecisionSafe(interval) + 2;\n}\n\nfunction clamp(niceTickExtent, idx, extent) {\n    niceTickExtent[idx] = Math.max(Math.min(niceTickExtent[idx], extent[1]), extent[0]);\n}\n\n// In some cases (e.g., splitNumber is 1), niceTickExtent may be out of extent.\nfunction fixExtent(niceTickExtent, extent) {\n    !isFinite(niceTickExtent[0]) && (niceTickExtent[0] = extent[0]);\n    !isFinite(niceTickExtent[1]) && (niceTickExtent[1] = extent[1]);\n    clamp(niceTickExtent, 0, extent);\n    clamp(niceTickExtent, 1, extent);\n    if (niceTickExtent[0] > niceTickExtent[1]) {\n        niceTickExtent[0] = niceTickExtent[1];\n    }\n}\n\nfunction intervalScaleGetTicks(interval, extent, niceTickExtent, intervalPrecision) {\n    var ticks = [];\n\n    // If interval is 0, return [];\n    if (!interval) {\n        return ticks;\n    }\n\n    // Consider this case: using dataZoom toolbox, zoom and zoom.\n    var safeLimit = 10000;\n\n    if (extent[0] < niceTickExtent[0]) {\n        ticks.push(extent[0]);\n    }\n    var tick = niceTickExtent[0];\n\n    while (tick <= niceTickExtent[1]) {\n        ticks.push(tick);\n        // Avoid rounding error\n        tick = roundNumber$1(tick + interval, intervalPrecision);\n        if (tick === ticks[ticks.length - 1]) {\n            // Consider out of safe float point, e.g.,\n            // -3711126.9907707 + 2e-10 === -3711126.9907707\n            break;\n        }\n        if (ticks.length > safeLimit) {\n            return [];\n        }\n    }\n    // Consider this case: the last item of ticks is smaller\n    // than niceTickExtent[1] and niceTickExtent[1] === extent[1].\n    if (extent[1] > (ticks.length ? ticks[ticks.length - 1] : niceTickExtent[1])) {\n        ticks.push(extent[1]);\n    }\n\n    return ticks;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Interval scale\n * @module echarts/scale/Interval\n */\n\n\nvar roundNumber = round$2;\n\n/**\n * @alias module:echarts/coord/scale/Interval\n * @constructor\n */\nvar IntervalScale = Scale.extend({\n\n    type: 'interval',\n\n    _interval: 0,\n\n    _intervalPrecision: 2,\n\n    setExtent: function (start, end) {\n        var thisExtent = this._extent;\n        //start,end may be a Number like '25',so...\n        if (!isNaN(start)) {\n            thisExtent[0] = parseFloat(start);\n        }\n        if (!isNaN(end)) {\n            thisExtent[1] = parseFloat(end);\n        }\n    },\n\n    unionExtent: function (other) {\n        var extent = this._extent;\n        other[0] < extent[0] && (extent[0] = other[0]);\n        other[1] > extent[1] && (extent[1] = other[1]);\n\n        // unionExtent may called by it's sub classes\n        IntervalScale.prototype.setExtent.call(this, extent[0], extent[1]);\n    },\n    /**\n     * Get interval\n     */\n    getInterval: function () {\n        return this._interval;\n    },\n\n    /**\n     * Set interval\n     */\n    setInterval: function (interval) {\n        this._interval = interval;\n        // Dropped auto calculated niceExtent and use user setted extent\n        // We assume user wan't to set both interval, min, max to get a better result\n        this._niceExtent = this._extent.slice();\n\n        this._intervalPrecision = getIntervalPrecision(interval);\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getTicks: function () {\n        return intervalScaleGetTicks(\n            this._interval, this._extent, this._niceExtent, this._intervalPrecision\n        );\n    },\n\n    /**\n     * @param {number} data\n     * @param {Object} [opt]\n     * @param {number|string} [opt.precision] If 'auto', use nice presision.\n     * @param {boolean} [opt.pad] returns 1.50 but not 1.5 if precision is 2.\n     * @return {string}\n     */\n    getLabel: function (data, opt) {\n        if (data == null) {\n            return '';\n        }\n\n        var precision = opt && opt.precision;\n\n        if (precision == null) {\n            precision = getPrecisionSafe(data) || 0;\n        }\n        else if (precision === 'auto') {\n            // Should be more precise then tick.\n            precision = this._intervalPrecision;\n        }\n\n        // (1) If `precision` is set, 12.005 should be display as '12.00500'.\n        // (2) Use roundNumber (toFixed) to avoid scientific notation like '3.5e-7'.\n        data = roundNumber(data, precision, true);\n\n        return addCommas(data);\n    },\n\n    /**\n     * Update interval and extent of intervals for nice ticks\n     *\n     * @param {number} [splitNumber = 5] Desired number of ticks\n     * @param {number} [minInterval]\n     * @param {number} [maxInterval]\n     */\n    niceTicks: function (splitNumber, minInterval, maxInterval) {\n        splitNumber = splitNumber || 5;\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        if (!isFinite(span)) {\n            return;\n        }\n        // User may set axis min 0 and data are all negative\n        // FIXME If it needs to reverse ?\n        if (span < 0) {\n            span = -span;\n            extent.reverse();\n        }\n\n        var result = intervalScaleNiceTicks(\n            extent, splitNumber, minInterval, maxInterval\n        );\n\n        this._intervalPrecision = result.intervalPrecision;\n        this._interval = result.interval;\n        this._niceExtent = result.niceTickExtent;\n    },\n\n    /**\n     * Nice extent.\n     * @param {Object} opt\n     * @param {number} [opt.splitNumber = 5] Given approx tick number\n     * @param {boolean} [opt.fixMin=false]\n     * @param {boolean} [opt.fixMax=false]\n     * @param {boolean} [opt.minInterval]\n     * @param {boolean} [opt.maxInterval]\n     */\n    niceExtent: function (opt) {\n        var extent = this._extent;\n        // If extent start and end are same, expand them\n        if (extent[0] === extent[1]) {\n            if (extent[0] !== 0) {\n                // Expand extent\n                var expandSize = extent[0];\n                // In the fowllowing case\n                //      Axis has been fixed max 100\n                //      Plus data are all 100 and axis extent are [100, 100].\n                // Extend to the both side will cause expanded max is larger than fixed max.\n                // So only expand to the smaller side.\n                if (!opt.fixMax) {\n                    extent[1] += expandSize / 2;\n                    extent[0] -= expandSize / 2;\n                }\n                else {\n                    extent[0] -= expandSize / 2;\n                }\n            }\n            else {\n                extent[1] = 1;\n            }\n        }\n        var span = extent[1] - extent[0];\n        // If there are no data and extent are [Infinity, -Infinity]\n        if (!isFinite(span)) {\n            extent[0] = 0;\n            extent[1] = 1;\n        }\n\n        this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);\n\n        // var extent = this._extent;\n        var interval = this._interval;\n\n        if (!opt.fixMin) {\n            extent[0] = roundNumber(Math.floor(extent[0] / interval) * interval);\n        }\n        if (!opt.fixMax) {\n            extent[1] = roundNumber(Math.ceil(extent[1] / interval) * interval);\n        }\n    }\n});\n\n/**\n * @return {module:echarts/scale/Time}\n */\nIntervalScale.create = function () {\n    return new IntervalScale();\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar STACK_PREFIX = '__ec_stack_';\nvar LARGE_BAR_MIN_WIDTH = 0.5;\n\nvar LargeArr = typeof Float32Array !== 'undefined' ? Float32Array : Array;\n\nfunction getSeriesStackId(seriesModel) {\n    return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex;\n}\n\nfunction getAxisKey(axis) {\n    return axis.dim + axis.index;\n}\n\n/**\n * @param {Object} opt\n * @param {module:echarts/coord/Axis} opt.axis Only support category axis currently.\n * @param {number} opt.count Positive interger.\n * @param {number} [opt.barWidth]\n * @param {number} [opt.barMaxWidth]\n * @param {number} [opt.barGap]\n * @param {number} [opt.barCategoryGap]\n * @return {Object} {width, offset, offsetCenter} If axis.type is not 'category', return undefined.\n */\n\n\nfunction prepareLayoutBarSeries(seriesType, ecModel) {\n    var seriesModels = [];\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        // Check series coordinate, do layout for cartesian2d only\n        if (isOnCartesian(seriesModel) && !isInLargeMode(seriesModel)) {\n            seriesModels.push(seriesModel);\n        }\n    });\n    return seriesModels;\n}\n\nfunction makeColumnLayout(barSeries) {\n    var seriesInfoList = [];\n    each$1(barSeries, function (seriesModel) {\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var axisExtent = baseAxis.getExtent();\n        var bandWidth = baseAxis.type === 'category'\n            ? baseAxis.getBandWidth()\n            : (Math.abs(axisExtent[1] - axisExtent[0]) / data.count());\n\n        var barWidth = parsePercent$1(\n            seriesModel.get('barWidth'), bandWidth\n        );\n        var barMaxWidth = parsePercent$1(\n            seriesModel.get('barMaxWidth'), bandWidth\n        );\n        var barGap = seriesModel.get('barGap');\n        var barCategoryGap = seriesModel.get('barCategoryGap');\n\n        seriesInfoList.push({\n            bandWidth: bandWidth,\n            barWidth: barWidth,\n            barMaxWidth: barMaxWidth,\n            barGap: barGap,\n            barCategoryGap: barCategoryGap,\n            axisKey: getAxisKey(baseAxis),\n            stackId: getSeriesStackId(seriesModel)\n        });\n    });\n\n    return doCalBarWidthAndOffset(seriesInfoList);\n}\n\nfunction doCalBarWidthAndOffset(seriesInfoList) {\n    // Columns info on each category axis. Key is cartesian name\n    var columnsMap = {};\n\n    each$1(seriesInfoList, function (seriesInfo, idx) {\n        var axisKey = seriesInfo.axisKey;\n        var bandWidth = seriesInfo.bandWidth;\n        var columnsOnAxis = columnsMap[axisKey] || {\n            bandWidth: bandWidth,\n            remainedWidth: bandWidth,\n            autoWidthCount: 0,\n            categoryGap: '20%',\n            gap: '30%',\n            stacks: {}\n        };\n        var stacks = columnsOnAxis.stacks;\n        columnsMap[axisKey] = columnsOnAxis;\n\n        var stackId = seriesInfo.stackId;\n\n        if (!stacks[stackId]) {\n            columnsOnAxis.autoWidthCount++;\n        }\n        stacks[stackId] = stacks[stackId] || {\n            width: 0,\n            maxWidth: 0\n        };\n\n        // Caution: In a single coordinate system, these barGrid attributes\n        // will be shared by series. Consider that they have default values,\n        // only the attributes set on the last series will work.\n        // Do not change this fact unless there will be a break change.\n\n        // TODO\n        var barWidth = seriesInfo.barWidth;\n        if (barWidth && !stacks[stackId].width) {\n            // See #6312, do not restrict width.\n            stacks[stackId].width = barWidth;\n            barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);\n            columnsOnAxis.remainedWidth -= barWidth;\n        }\n\n        var barMaxWidth = seriesInfo.barMaxWidth;\n        barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);\n        var barGap = seriesInfo.barGap;\n        (barGap != null) && (columnsOnAxis.gap = barGap);\n        var barCategoryGap = seriesInfo.barCategoryGap;\n        (barCategoryGap != null) && (columnsOnAxis.categoryGap = barCategoryGap);\n    });\n\n    var result = {};\n\n    each$1(columnsMap, function (columnsOnAxis, coordSysName) {\n\n        result[coordSysName] = {};\n\n        var stacks = columnsOnAxis.stacks;\n        var bandWidth = columnsOnAxis.bandWidth;\n        var categoryGap = parsePercent$1(columnsOnAxis.categoryGap, bandWidth);\n        var barGapPercent = parsePercent$1(columnsOnAxis.gap, 1);\n\n        var remainedWidth = columnsOnAxis.remainedWidth;\n        var autoWidthCount = columnsOnAxis.autoWidthCount;\n        var autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        // Find if any auto calculated bar exceeded maxBarWidth\n        each$1(stacks, function (column, stack) {\n            var maxWidth = column.maxWidth;\n            if (maxWidth && maxWidth < autoWidth) {\n                maxWidth = Math.min(maxWidth, remainedWidth);\n                if (column.width) {\n                    maxWidth = Math.min(maxWidth, column.width);\n                }\n                remainedWidth -= maxWidth;\n                column.width = maxWidth;\n                autoWidthCount--;\n            }\n        });\n\n        // Recalculate width again\n        autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        var widthSum = 0;\n        var lastColumn;\n        each$1(stacks, function (column, idx) {\n            if (!column.width) {\n                column.width = autoWidth;\n            }\n            lastColumn = column;\n            widthSum += column.width * (1 + barGapPercent);\n        });\n        if (lastColumn) {\n            widthSum -= lastColumn.width * barGapPercent;\n        }\n\n        var offset = -widthSum / 2;\n        each$1(stacks, function (column, stackId) {\n            result[coordSysName][stackId] = result[coordSysName][stackId] || {\n                offset: offset,\n                width: column.width\n            };\n\n            offset += column.width * (1 + barGapPercent);\n        });\n    });\n\n    return result;\n}\n\n/**\n * @param {Object} barWidthAndOffset The result of makeColumnLayout\n * @param {module:echarts/coord/Axis} axis\n * @param {module:echarts/model/Series} [seriesModel] If not provided, return all.\n * @return {Object} {stackId: {offset, width}} or {offset, width} if seriesModel provided.\n */\nfunction retrieveColumnLayout(barWidthAndOffset, axis, seriesModel) {\n    if (barWidthAndOffset && axis) {\n        var result = barWidthAndOffset[getAxisKey(axis)];\n        if (result != null && seriesModel != null) {\n            result = result[getSeriesStackId(seriesModel)];\n        }\n        return result;\n    }\n}\n\n/**\n * @param {string} seriesType\n * @param {module:echarts/model/Global} ecModel\n */\nfunction layout(seriesType, ecModel) {\n\n    var seriesModels = prepareLayoutBarSeries(seriesType, ecModel);\n    var barWidthAndOffset = makeColumnLayout(seriesModels);\n\n    var lastStackCoords = {};\n    each$1(seriesModels, function (seriesModel) {\n\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n\n        var stackId = getSeriesStackId(seriesModel);\n        var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId];\n        var columnOffset = columnLayoutInfo.offset;\n        var columnWidth = columnLayoutInfo.width;\n        var valueAxis = cartesian.getOtherAxis(baseAxis);\n\n        var barMinHeight = seriesModel.get('barMinHeight') || 0;\n\n        lastStackCoords[stackId] = lastStackCoords[stackId] || [];\n        data.setLayout({\n            offset: columnOffset,\n            size: columnWidth\n        });\n\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var stacked = isDimensionStacked(data, valueDim /*, baseDim*/);\n        var isValueAxisH = valueAxis.isHorizontal();\n\n        var valueAxisStart = getValueAxisStart(baseAxis, valueAxis, stacked);\n\n        for (var idx = 0, len = data.count(); idx < len; idx++) {\n            var value = data.get(valueDim, idx);\n            var baseValue = data.get(baseDim, idx);\n\n            if (isNaN(value)) {\n                continue;\n            }\n\n            var sign = value >= 0 ? 'p' : 'n';\n            var baseCoord = valueAxisStart;\n\n            // Because of the barMinHeight, we can not use the value in\n            // stackResultDimension directly.\n            if (stacked) {\n                // Only ordinal axis can be stacked.\n                if (!lastStackCoords[stackId][baseValue]) {\n                    lastStackCoords[stackId][baseValue] = {\n                        p: valueAxisStart, // Positive stack\n                        n: valueAxisStart  // Negative stack\n                    };\n                }\n                // Should also consider #4243\n                baseCoord = lastStackCoords[stackId][baseValue][sign];\n            }\n\n            var x;\n            var y;\n            var width;\n            var height;\n\n            if (isValueAxisH) {\n                var coord = cartesian.dataToPoint([value, baseValue]);\n                x = baseCoord;\n                y = coord[1] + columnOffset;\n                width = coord[0] - valueAxisStart;\n                height = columnWidth;\n\n                if (Math.abs(width) < barMinHeight) {\n                    width = (width < 0 ? -1 : 1) * barMinHeight;\n                }\n                stacked && (lastStackCoords[stackId][baseValue][sign] += width);\n            }\n            else {\n                var coord = cartesian.dataToPoint([baseValue, value]);\n                x = coord[0] + columnOffset;\n                y = baseCoord;\n                width = columnWidth;\n                height = coord[1] - valueAxisStart;\n\n                if (Math.abs(height) < barMinHeight) {\n                    // Include zero to has a positive bar\n                    height = (height <= 0 ? -1 : 1) * barMinHeight;\n                }\n                stacked && (lastStackCoords[stackId][baseValue][sign] += height);\n            }\n\n            data.setItemLayout(idx, {\n                x: x,\n                y: y,\n                width: width,\n                height: height\n            });\n        }\n\n    }, this);\n}\n\n// TODO: Do not support stack in large mode yet.\nvar largeLayout = {\n\n    seriesType: 'bar',\n\n    plan: createRenderPlanner(),\n\n    reset: function (seriesModel) {\n        if (!isOnCartesian(seriesModel) || !isInLargeMode(seriesModel)) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var valueAxis = cartesian.getOtherAxis(baseAxis);\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var valueAxisHorizontal = valueAxis.isHorizontal();\n        var valueDimIdx = valueAxisHorizontal ? 0 : 1;\n\n        var barWidth = retrieveColumnLayout(\n            makeColumnLayout([seriesModel]), baseAxis, seriesModel\n        ).width;\n        if (!(barWidth > LARGE_BAR_MIN_WIDTH)) { // jshint ignore:line\n            barWidth = LARGE_BAR_MIN_WIDTH;\n        }\n\n        return {progress: progress};\n\n        function progress(params, data) {\n            var largePoints = new LargeArr(params.count * 2);\n            var dataIndex;\n            var coord = [];\n            var valuePair = [];\n            var offset = 0;\n\n            while ((dataIndex = params.next()) != null) {\n                valuePair[valueDimIdx] = data.get(valueDim, dataIndex);\n                valuePair[1 - valueDimIdx] = data.get(baseDim, dataIndex);\n\n                coord = cartesian.dataToPoint(valuePair, null, coord);\n                largePoints[offset++] = coord[0];\n                largePoints[offset++] = coord[1];\n            }\n\n            data.setLayout({\n                largePoints: largePoints,\n                barWidth: barWidth,\n                valueAxisStart: getValueAxisStart(baseAxis, valueAxis, false),\n                valueAxisHorizontal: valueAxisHorizontal\n            });\n        }\n    }\n};\n\nfunction isOnCartesian(seriesModel) {\n    return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d';\n}\n\nfunction isInLargeMode(seriesModel) {\n    return seriesModel.pipelineContext && seriesModel.pipelineContext.large;\n}\n\n// See cases in `test/bar-start.html` and `#7412`, `#8747`.\nfunction getValueAxisStart(baseAxis, valueAxis, stacked) {\n    var extent = valueAxis.getGlobalExtent();\n    var min;\n    var max;\n    if (extent[0] > extent[1]) {\n        min = extent[1];\n        max = extent[0];\n    }\n    else {\n        min = extent[0];\n        max = extent[1];\n    }\n\n    var valueStart = valueAxis.toGlobalCoord(valueAxis.dataToCoord(0));\n    valueStart < min && (valueStart = min);\n    valueStart > max && (valueStart = max);\n\n    return valueStart;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The \"scaleLevels\" was originally copied from \"d3.js\" with some\n* modifications made for this project.\n* (See more details in the comment on the definition of \"scaleLevels\" below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\n\n// [About UTC and local time zone]:\n// In most cases, `number.parseDate` will treat input data string as local time\n// (except time zone is specified in time string). And `format.formateTime` returns\n// local time by default. option.useUTC is false by default. This design have\n// concidered these common case:\n// (1) Time that is persistent in server is in UTC, but it is needed to be diplayed\n// in local time by default.\n// (2) By default, the input data string (e.g., '2011-01-02') should be displayed\n// as its original time, without any time difference.\n\nvar intervalScaleProto = IntervalScale.prototype;\n\nvar mathCeil = Math.ceil;\nvar mathFloor = Math.floor;\nvar ONE_SECOND = 1000;\nvar ONE_MINUTE = ONE_SECOND * 60;\nvar ONE_HOUR = ONE_MINUTE * 60;\nvar ONE_DAY = ONE_HOUR * 24;\n\n// FIXME 公用？\nvar bisect = function (a, x, lo, hi) {\n    while (lo < hi) {\n        var mid = lo + hi >>> 1;\n        if (a[mid][1] < x) {\n            lo = mid + 1;\n        }\n        else {\n            hi = mid;\n        }\n    }\n    return lo;\n};\n\n/**\n * @alias module:echarts/coord/scale/Time\n * @constructor\n */\nvar TimeScale = IntervalScale.extend({\n    type: 'time',\n\n    /**\n     * @override\n     */\n    getLabel: function (val) {\n        var stepLvl = this._stepLvl;\n\n        var date = new Date(val);\n\n        return formatTime(stepLvl[0], date, this.getSetting('useUTC'));\n    },\n\n    /**\n     * @override\n     */\n    niceExtent: function (opt) {\n        var extent = this._extent;\n        // If extent start and end are same, expand them\n        if (extent[0] === extent[1]) {\n            // Expand extent\n            extent[0] -= ONE_DAY;\n            extent[1] += ONE_DAY;\n        }\n        // If there are no data and extent are [Infinity, -Infinity]\n        if (extent[1] === -Infinity && extent[0] === Infinity) {\n            var d = new Date();\n            extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate());\n            extent[0] = extent[1] - ONE_DAY;\n        }\n\n        this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);\n\n        // var extent = this._extent;\n        var interval = this._interval;\n\n        if (!opt.fixMin) {\n            extent[0] = round$2(mathFloor(extent[0] / interval) * interval);\n        }\n        if (!opt.fixMax) {\n            extent[1] = round$2(mathCeil(extent[1] / interval) * interval);\n        }\n    },\n\n    /**\n     * @override\n     */\n    niceTicks: function (approxTickNum, minInterval, maxInterval) {\n        approxTickNum = approxTickNum || 10;\n\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        var approxInterval = span / approxTickNum;\n\n        if (minInterval != null && approxInterval < minInterval) {\n            approxInterval = minInterval;\n        }\n        if (maxInterval != null && approxInterval > maxInterval) {\n            approxInterval = maxInterval;\n        }\n\n        var scaleLevelsLen = scaleLevels.length;\n        var idx = bisect(scaleLevels, approxInterval, 0, scaleLevelsLen);\n\n        var level = scaleLevels[Math.min(idx, scaleLevelsLen - 1)];\n        var interval = level[1];\n        // Same with interval scale if span is much larger than 1 year\n        if (level[0] === 'year') {\n            var yearSpan = span / interval;\n\n            // From \"Nice Numbers for Graph Labels\" of Graphic Gems\n            // var niceYearSpan = numberUtil.nice(yearSpan, false);\n            var yearStep = nice(yearSpan / approxTickNum, true);\n\n            interval *= yearStep;\n        }\n\n        var timezoneOffset = this.getSetting('useUTC')\n            ? 0 : (new Date(+extent[0] || +extent[1])).getTimezoneOffset() * 60 * 1000;\n        var niceExtent = [\n            Math.round(mathCeil((extent[0] - timezoneOffset) / interval) * interval + timezoneOffset),\n            Math.round(mathFloor((extent[1] - timezoneOffset) / interval) * interval + timezoneOffset)\n        ];\n\n        fixExtent(niceExtent, extent);\n\n        this._stepLvl = level;\n        // Interval will be used in getTicks\n        this._interval = interval;\n        this._niceExtent = niceExtent;\n    },\n\n    parse: function (val) {\n        // val might be float.\n        return +parseDate(val);\n    }\n});\n\neach$1(['contain', 'normalize'], function (methodName) {\n    TimeScale.prototype[methodName] = function (val) {\n        return intervalScaleProto[methodName].call(this, this.parse(val));\n    };\n});\n\n/**\n * This implementation was originally copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/b516d77fb8566b576088e73410437494717ada26/src/time/scale.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n */\nvar scaleLevels = [\n    // Format              interval\n    ['hh:mm:ss', ONE_SECOND],          // 1s\n    ['hh:mm:ss', ONE_SECOND * 5],      // 5s\n    ['hh:mm:ss', ONE_SECOND * 10],     // 10s\n    ['hh:mm:ss', ONE_SECOND * 15],     // 15s\n    ['hh:mm:ss', ONE_SECOND * 30],     // 30s\n    ['hh:mm\\nMM-dd', ONE_MINUTE],      // 1m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 5],  // 5m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 10], // 10m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 15], // 15m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 30], // 30m\n    ['hh:mm\\nMM-dd', ONE_HOUR],        // 1h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 2],    // 2h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 6],    // 6h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 12],   // 12h\n    ['MM-dd\\nyyyy', ONE_DAY],          // 1d\n    ['MM-dd\\nyyyy', ONE_DAY * 2],      // 2d\n    ['MM-dd\\nyyyy', ONE_DAY * 3],      // 3d\n    ['MM-dd\\nyyyy', ONE_DAY * 4],      // 4d\n    ['MM-dd\\nyyyy', ONE_DAY * 5],      // 5d\n    ['MM-dd\\nyyyy', ONE_DAY * 6],      // 6d\n    ['week', ONE_DAY * 7],             // 7d\n    ['MM-dd\\nyyyy', ONE_DAY * 10],     // 10d\n    ['week', ONE_DAY * 14],            // 2w\n    ['week', ONE_DAY * 21],            // 3w\n    ['month', ONE_DAY * 31],           // 1M\n    ['week', ONE_DAY * 42],            // 6w\n    ['month', ONE_DAY * 62],           // 2M\n    ['week', ONE_DAY * 70],            // 10w\n    ['quarter', ONE_DAY * 95],         // 3M\n    ['month', ONE_DAY * 31 * 4],       // 4M\n    ['month', ONE_DAY * 31 * 5],       // 5M\n    ['half-year', ONE_DAY * 380 / 2],  // 6M\n    ['month', ONE_DAY * 31 * 8],       // 8M\n    ['month', ONE_DAY * 31 * 10],      // 10M\n    ['year', ONE_DAY * 380]            // 1Y\n];\n\n/**\n * @param {module:echarts/model/Model}\n * @return {module:echarts/scale/Time}\n */\nTimeScale.create = function (model) {\n    return new TimeScale({useUTC: model.ecModel.get('useUTC')});\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Log scale\n * @module echarts/scale/Log\n */\n\n// Use some method of IntervalScale\nvar scaleProto$1 = Scale.prototype;\nvar intervalScaleProto$1 = IntervalScale.prototype;\n\nvar getPrecisionSafe$1 = getPrecisionSafe;\nvar roundingErrorFix = round$2;\n\nvar mathFloor$1 = Math.floor;\nvar mathCeil$1 = Math.ceil;\nvar mathPow$1 = Math.pow;\n\nvar mathLog = Math.log;\n\nvar LogScale = Scale.extend({\n\n    type: 'log',\n\n    base: 10,\n\n    $constructor: function () {\n        Scale.apply(this, arguments);\n        this._originalScale = new IntervalScale();\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getTicks: function () {\n        var originalScale = this._originalScale;\n        var extent = this._extent;\n        var originalExtent = originalScale.getExtent();\n\n        return map(intervalScaleProto$1.getTicks.call(this), function (val) {\n            var powVal = round$2(mathPow$1(this.base, val));\n\n            // Fix #4158\n            powVal = (val === extent[0] && originalScale.__fixMin)\n                ? fixRoundingError(powVal, originalExtent[0])\n                : powVal;\n            powVal = (val === extent[1] && originalScale.__fixMax)\n                ? fixRoundingError(powVal, originalExtent[1])\n                : powVal;\n\n            return powVal;\n        }, this);\n    },\n\n    /**\n     * @param {number} val\n     * @return {string}\n     */\n    getLabel: intervalScaleProto$1.getLabel,\n\n    /**\n     * @param  {number} val\n     * @return {number}\n     */\n    scale: function (val) {\n        val = scaleProto$1.scale.call(this, val);\n        return mathPow$1(this.base, val);\n    },\n\n    /**\n     * @param {number} start\n     * @param {number} end\n     */\n    setExtent: function (start, end) {\n        var base = this.base;\n        start = mathLog(start) / mathLog(base);\n        end = mathLog(end) / mathLog(base);\n        intervalScaleProto$1.setExtent.call(this, start, end);\n    },\n\n    /**\n     * @return {number} end\n     */\n    getExtent: function () {\n        var base = this.base;\n        var extent = scaleProto$1.getExtent.call(this);\n        extent[0] = mathPow$1(base, extent[0]);\n        extent[1] = mathPow$1(base, extent[1]);\n\n        // Fix #4158\n        var originalScale = this._originalScale;\n        var originalExtent = originalScale.getExtent();\n        originalScale.__fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0]));\n        originalScale.__fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1]));\n\n        return extent;\n    },\n\n    /**\n     * @param  {Array.<number>} extent\n     */\n    unionExtent: function (extent) {\n        this._originalScale.unionExtent(extent);\n\n        var base = this.base;\n        extent[0] = mathLog(extent[0]) / mathLog(base);\n        extent[1] = mathLog(extent[1]) / mathLog(base);\n        scaleProto$1.unionExtent.call(this, extent);\n    },\n\n    /**\n     * @override\n     */\n    unionExtentFromData: function (data, dim) {\n        // TODO\n        // filter value that <= 0\n        this.unionExtent(data.getApproximateExtent(dim));\n    },\n\n    /**\n     * Update interval and extent of intervals for nice ticks\n     * @param  {number} [approxTickNum = 10] Given approx tick number\n     */\n    niceTicks: function (approxTickNum) {\n        approxTickNum = approxTickNum || 10;\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        if (span === Infinity || span <= 0) {\n            return;\n        }\n\n        var interval = quantity(span);\n        var err = approxTickNum / span * interval;\n\n        // Filter ticks to get closer to the desired count.\n        if (err <= 0.5) {\n            interval *= 10;\n        }\n\n        // Interval should be integer\n        while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) {\n            interval *= 10;\n        }\n\n        var niceExtent = [\n            round$2(mathCeil$1(extent[0] / interval) * interval),\n            round$2(mathFloor$1(extent[1] / interval) * interval)\n        ];\n\n        this._interval = interval;\n        this._niceExtent = niceExtent;\n    },\n\n    /**\n     * Nice extent.\n     * @override\n     */\n    niceExtent: function (opt) {\n        intervalScaleProto$1.niceExtent.call(this, opt);\n\n        var originalScale = this._originalScale;\n        originalScale.__fixMin = opt.fixMin;\n        originalScale.__fixMax = opt.fixMax;\n    }\n\n});\n\neach$1(['contain', 'normalize'], function (methodName) {\n    LogScale.prototype[methodName] = function (val) {\n        val = mathLog(val) / mathLog(this.base);\n        return scaleProto$1[methodName].call(this, val);\n    };\n});\n\nLogScale.create = function () {\n    return new LogScale();\n};\n\nfunction fixRoundingError(val, originalVal) {\n    return roundingErrorFix(val, getPrecisionSafe$1(originalVal));\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Get axis scale extent before niced.\n * Item of returned array can only be number (including Infinity and NaN).\n */\nfunction getScaleExtent(scale, model) {\n    var scaleType = scale.type;\n\n    var min = model.getMin();\n    var max = model.getMax();\n    var fixMin = min != null;\n    var fixMax = max != null;\n    var originalExtent = scale.getExtent();\n\n    var axisDataLen;\n    var boundaryGap;\n    var span;\n    if (scaleType === 'ordinal') {\n        axisDataLen = model.getCategories().length;\n    }\n    else {\n        boundaryGap = model.get('boundaryGap');\n        if (!isArray(boundaryGap)) {\n            boundaryGap = [boundaryGap || 0, boundaryGap || 0];\n        }\n        if (typeof boundaryGap[0] === 'boolean') {\n            if (__DEV__) {\n                console.warn('Boolean type for boundaryGap is only '\n                    + 'allowed for ordinal axis. Please use string in '\n                    + 'percentage instead, e.g., \"20%\". Currently, '\n                    + 'boundaryGap is set to be 0.');\n            }\n            boundaryGap = [0, 0];\n        }\n        boundaryGap[0] = parsePercent$1(boundaryGap[0], 1);\n        boundaryGap[1] = parsePercent$1(boundaryGap[1], 1);\n        span = (originalExtent[1] - originalExtent[0])\n            || Math.abs(originalExtent[0]);\n    }\n\n    // Notice: When min/max is not set (that is, when there are null/undefined,\n    // which is the most common case), these cases should be ensured:\n    // (1) For 'ordinal', show all axis.data.\n    // (2) For others:\n    //      + `boundaryGap` is applied (if min/max set, boundaryGap is\n    //      disabled).\n    //      + If `needCrossZero`, min/max should be zero, otherwise, min/max should\n    //      be the result that originalExtent enlarged by boundaryGap.\n    // (3) If no data, it should be ensured that `scale.setBlank` is set.\n\n    // FIXME\n    // (1) When min/max is 'dataMin' or 'dataMax', should boundaryGap be able to used?\n    // (2) When `needCrossZero` and all data is positive/negative, should it be ensured\n    // that the results processed by boundaryGap are positive/negative?\n\n    if (min == null) {\n        min = scaleType === 'ordinal'\n            ? (axisDataLen ? 0 : NaN)\n            : originalExtent[0] - boundaryGap[0] * span;\n    }\n    if (max == null) {\n        max = scaleType === 'ordinal'\n            ? (axisDataLen ? axisDataLen - 1 : NaN)\n            : originalExtent[1] + boundaryGap[1] * span;\n    }\n\n    if (min === 'dataMin') {\n        min = originalExtent[0];\n    }\n    else if (typeof min === 'function') {\n        min = min({\n            min: originalExtent[0],\n            max: originalExtent[1]\n        });\n    }\n\n    if (max === 'dataMax') {\n        max = originalExtent[1];\n    }\n    else if (typeof max === 'function') {\n        max = max({\n            min: originalExtent[0],\n            max: originalExtent[1]\n        });\n    }\n\n    (min == null || !isFinite(min)) && (min = NaN);\n    (max == null || !isFinite(max)) && (max = NaN);\n\n    scale.setBlank(\n        eqNaN(min)\n        || eqNaN(max)\n        || (scaleType === 'ordinal' && !scale.getOrdinalMeta().categories.length)\n    );\n\n    // Evaluate if axis needs cross zero\n    if (model.getNeedCrossZero()) {\n        // Axis is over zero and min is not set\n        if (min > 0 && max > 0 && !fixMin) {\n            min = 0;\n        }\n        // Axis is under zero and max is not set\n        if (min < 0 && max < 0 && !fixMax) {\n            max = 0;\n        }\n    }\n\n    // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis\n    // is base axis\n    // FIXME\n    // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly.\n    // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent?\n    //     Should not depend on series type `bar`?\n    // (3) Fix that might overlap when using dataZoom.\n    // (4) Consider other chart types using `barGrid`?\n    // See #6728, #4862, `test/bar-overflow-time-plot.html`\n    var ecModel = model.ecModel;\n    if (ecModel && (scaleType === 'time' /*|| scaleType === 'interval' */)) {\n        var barSeriesModels = prepareLayoutBarSeries('bar', ecModel);\n        var isBaseAxisAndHasBarSeries;\n\n        each$1(barSeriesModels, function (seriesModel) {\n            isBaseAxisAndHasBarSeries |= seriesModel.getBaseAxis() === model.axis;\n        });\n\n        if (isBaseAxisAndHasBarSeries) {\n            // Calculate placement of bars on axis\n            var barWidthAndOffset = makeColumnLayout(barSeriesModels);\n\n            // Adjust axis min and max to account for overflow\n            var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset);\n            min = adjustedScale.min;\n            max = adjustedScale.max;\n        }\n    }\n\n    return [min, max];\n}\n\nfunction adjustScaleForOverflow(min, max, model, barWidthAndOffset) {\n\n    // Get Axis Length\n    var axisExtent = model.axis.getExtent();\n    var axisLength = axisExtent[1] - axisExtent[0];\n\n    // Get bars on current base axis and calculate min and max overflow\n    var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis);\n    if (barsOnCurrentAxis === undefined) {\n        return {min: min, max: max};\n    }\n\n    var minOverflow = Infinity;\n    each$1(barsOnCurrentAxis, function (item) {\n        minOverflow = Math.min(item.offset, minOverflow);\n    });\n    var maxOverflow = -Infinity;\n    each$1(barsOnCurrentAxis, function (item) {\n        maxOverflow = Math.max(item.offset + item.width, maxOverflow);\n    });\n    minOverflow = Math.abs(minOverflow);\n    maxOverflow = Math.abs(maxOverflow);\n    var totalOverFlow = minOverflow + maxOverflow;\n\n    // Calulate required buffer based on old range and overflow\n    var oldRange = max - min;\n    var oldRangePercentOfNew = (1 - (minOverflow + maxOverflow) / axisLength);\n    var overflowBuffer = ((oldRange / oldRangePercentOfNew) - oldRange);\n\n    max += overflowBuffer * (maxOverflow / totalOverFlow);\n    min -= overflowBuffer * (minOverflow / totalOverFlow);\n\n    return {min: min, max: max};\n}\n\nfunction niceScaleExtent(scale, model) {\n    var extent = getScaleExtent(scale, model);\n    var fixMin = model.getMin() != null;\n    var fixMax = model.getMax() != null;\n    var splitNumber = model.get('splitNumber');\n\n    if (scale.type === 'log') {\n        scale.base = model.get('logBase');\n    }\n\n    var scaleType = scale.type;\n    scale.setExtent(extent[0], extent[1]);\n    scale.niceExtent({\n        splitNumber: splitNumber,\n        fixMin: fixMin,\n        fixMax: fixMax,\n        minInterval: (scaleType === 'interval' || scaleType === 'time')\n            ? model.get('minInterval') : null,\n        maxInterval: (scaleType === 'interval' || scaleType === 'time')\n            ? model.get('maxInterval') : null\n    });\n\n    // If some one specified the min, max. And the default calculated interval\n    // is not good enough. He can specify the interval. It is often appeared\n    // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard\n    // to be 60.\n    // FIXME\n    var interval = model.get('interval');\n    if (interval != null) {\n        scale.setInterval && scale.setInterval(interval);\n    }\n}\n\n/**\n * @param {module:echarts/model/Model} model\n * @param {string} [axisType] Default retrieve from model.type\n * @return {module:echarts/scale/*}\n */\nfunction createScaleByModel(model, axisType) {\n    axisType = axisType || model.get('type');\n    if (axisType) {\n        switch (axisType) {\n            // Buildin scale\n            case 'category':\n                return new OrdinalScale(\n                    model.getOrdinalMeta\n                        ? model.getOrdinalMeta()\n                        : model.getCategories(),\n                    [Infinity, -Infinity]\n                );\n            case 'value':\n                return new IntervalScale();\n            // Extended scale, like time and log\n            default:\n                return (Scale.getClass(axisType) || IntervalScale).create(model);\n        }\n    }\n}\n\n/**\n * Check if the axis corss 0\n */\nfunction ifAxisCrossZero(axis) {\n    var dataExtent = axis.scale.getExtent();\n    var min = dataExtent[0];\n    var max = dataExtent[1];\n    return !((min > 0 && max > 0) || (min < 0 && max < 0));\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @return {Function} Label formatter function.\n *         param: {number} tickValue,\n *         param: {number} idx, the index in all ticks.\n *                         If category axis, this param is not requied.\n *         return: {string} label string.\n */\nfunction makeLabelFormatter(axis) {\n    var labelFormatter = axis.getLabelModel().get('formatter');\n    var categoryTickStart = axis.type === 'category' ? axis.scale.getExtent()[0] : null;\n\n    if (typeof labelFormatter === 'string') {\n        labelFormatter = (function (tpl) {\n            return function (val) {\n                // For category axis, get raw value; for numeric axis,\n                // get foramtted label like '1,333,444'.\n                val = axis.scale.getLabel(val);\n                return tpl.replace('{value}', val != null ? val : '');\n            };\n        })(labelFormatter);\n        // Consider empty array\n        return labelFormatter;\n    }\n    else if (typeof labelFormatter === 'function') {\n        return function (tickValue, idx) {\n            // The original intention of `idx` is \"the index of the tick in all ticks\".\n            // But the previous implementation of category axis do not consider the\n            // `axisLabel.interval`, which cause that, for example, the `interval` is\n            // `1`, then the ticks \"name5\", \"name7\", \"name9\" are displayed, where the\n            // corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep\n            // the definition here for back compatibility.\n            if (categoryTickStart != null) {\n                idx = tickValue - categoryTickStart;\n            }\n            return labelFormatter(getAxisRawValue(axis, tickValue), idx);\n        };\n    }\n    else {\n        return function (tick) {\n            return axis.scale.getLabel(tick);\n        };\n    }\n}\n\nfunction getAxisRawValue(axis, value) {\n    // In category axis with data zoom, tick is not the original\n    // index of axis.data. So tick should not be exposed to user\n    // in category axis.\n    return axis.type === 'category' ? axis.scale.getLabel(value) : value;\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @return {module:zrender/core/BoundingRect} Be null/undefined if no labels.\n */\nfunction estimateLabelUnionRect(axis) {\n    var axisModel = axis.model;\n    var scale = axis.scale;\n\n    if (!axisModel.get('axisLabel.show') || scale.isBlank()) {\n        return;\n    }\n\n    var isCategory = axis.type === 'category';\n\n    var realNumberScaleTicks;\n    var tickCount;\n    var categoryScaleExtent = scale.getExtent();\n\n    // Optimize for large category data, avoid call `getTicks()`.\n    if (isCategory) {\n        tickCount = scale.count();\n    }\n    else {\n        realNumberScaleTicks = scale.getTicks();\n        tickCount = realNumberScaleTicks.length;\n    }\n\n    var axisLabelModel = axis.getLabelModel();\n    var labelFormatter = makeLabelFormatter(axis);\n\n    var rect;\n    var step = 1;\n    // Simple optimization for large amount of labels\n    if (tickCount > 40) {\n        step = Math.ceil(tickCount / 40);\n    }\n    for (var i = 0; i < tickCount; i += step) {\n        var tickValue = realNumberScaleTicks ? realNumberScaleTicks[i] : categoryScaleExtent[0] + i;\n        var label = labelFormatter(tickValue);\n        var unrotatedSingleRect = axisLabelModel.getTextRect(label);\n        var singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0);\n\n        rect ? rect.union(singleRect) : (rect = singleRect);\n    }\n\n    return rect;\n}\n\nfunction rotateTextRect(textRect, rotate) {\n    var rotateRadians = rotate * Math.PI / 180;\n    var boundingBox = textRect.plain();\n    var beforeWidth = boundingBox.width;\n    var beforeHeight = boundingBox.height;\n    var afterWidth = beforeWidth * Math.cos(rotateRadians) + beforeHeight * Math.sin(rotateRadians);\n    var afterHeight = beforeWidth * Math.sin(rotateRadians) + beforeHeight * Math.cos(rotateRadians);\n    var rotatedRect = new BoundingRect(boundingBox.x, boundingBox.y, afterWidth, afterHeight);\n\n    return rotatedRect;\n}\n\n/**\n * @param {module:echarts/src/model/Model} model axisLabelModel or axisTickModel\n * @return {number|String} Can be null|'auto'|number|function\n */\nfunction getOptionCategoryInterval(model) {\n    var interval = model.get('interval');\n    return interval == null ? 'auto' : interval;\n}\n\n/**\n * Set `categoryInterval` as 0 implicitly indicates that\n * show all labels reguardless of overlap.\n * @param {Object} axis axisModel.axis\n * @return {boolean}\n */\nfunction shouldShowAllLabels(axis) {\n    return axis.type === 'category'\n        && getOptionCategoryInterval(axis.getLabelModel()) === 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Cartesian coordinate system\n * @module  echarts/coord/Cartesian\n *\n */\n\nfunction dimAxisMapper(dim) {\n    return this._axes[dim];\n}\n\n/**\n * @alias module:echarts/coord/Cartesian\n * @constructor\n */\nvar Cartesian = function (name) {\n    this._axes = {};\n\n    this._dimList = [];\n\n    /**\n     * @type {string}\n     */\n    this.name = name || '';\n};\n\nCartesian.prototype = {\n\n    constructor: Cartesian,\n\n    type: 'cartesian',\n\n    /**\n     * Get axis\n     * @param  {number|string} dim\n     * @return {module:echarts/coord/Cartesian~Axis}\n     */\n    getAxis: function (dim) {\n        return this._axes[dim];\n    },\n\n    /**\n     * Get axes list\n     * @return {Array.<module:echarts/coord/Cartesian~Axis>}\n     */\n    getAxes: function () {\n        return map(this._dimList, dimAxisMapper, this);\n    },\n\n    /**\n     * Get axes list by given scale type\n     */\n    getAxesByScale: function (scaleType) {\n        scaleType = scaleType.toLowerCase();\n        return filter(\n            this.getAxes(),\n            function (axis) {\n                return axis.scale.type === scaleType;\n            }\n        );\n    },\n\n    /**\n     * Add axis\n     * @param {module:echarts/coord/Cartesian.Axis}\n     */\n    addAxis: function (axis) {\n        var dim = axis.dim;\n\n        this._axes[dim] = axis;\n\n        this._dimList.push(dim);\n    },\n\n    /**\n     * Convert data to coord in nd space\n     * @param {Array.<number>|Object.<string, number>} val\n     * @return {Array.<number>|Object.<string, number>}\n     */\n    dataToCoord: function (val) {\n        return this._dataCoordConvert(val, 'dataToCoord');\n    },\n\n    /**\n     * Convert coord in nd space to data\n     * @param  {Array.<number>|Object.<string, number>} val\n     * @return {Array.<number>|Object.<string, number>}\n     */\n    coordToData: function (val) {\n        return this._dataCoordConvert(val, 'coordToData');\n    },\n\n    _dataCoordConvert: function (input, method) {\n        var dimList = this._dimList;\n\n        var output = input instanceof Array ? [] : {};\n\n        for (var i = 0; i < dimList.length; i++) {\n            var dim = dimList[i];\n            var axis = this._axes[dim];\n\n            output[dim] = axis[method](input[dim]);\n        }\n\n        return output;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction Cartesian2D(name) {\n\n    Cartesian.call(this, name);\n}\n\nCartesian2D.prototype = {\n\n    constructor: Cartesian2D,\n\n    type: 'cartesian2d',\n\n    /**\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['x', 'y'],\n\n    /**\n     * Base axis will be used on stacking.\n     *\n     * @return {module:echarts/coord/cartesian/Axis2D}\n     */\n    getBaseAxis: function () {\n        return this.getAxesByScale('ordinal')[0]\n            || this.getAxesByScale('time')[0]\n            || this.getAxis('x');\n    },\n\n    /**\n     * If contain point\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    containPoint: function (point) {\n        var axisX = this.getAxis('x');\n        var axisY = this.getAxis('y');\n        return axisX.contain(axisX.toLocalCoord(point[0]))\n            && axisY.contain(axisY.toLocalCoord(point[1]));\n    },\n\n    /**\n     * If contain data\n     * @param {Array.<number>} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this.getAxis('x').containData(data[0])\n            && this.getAxis('y').containData(data[1]);\n    },\n\n    /**\n     * @param {Array.<number>} data\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, reserved, out) {\n        var xAxis = this.getAxis('x');\n        var yAxis = this.getAxis('y');\n        out = out || [];\n        out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(data[0]));\n        out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(data[1]));\n        return out;\n    },\n\n    /**\n     * @param {Array.<number>} data\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    clampData: function (data, out) {\n        var xScale = this.getAxis('x').scale;\n        var yScale = this.getAxis('y').scale;\n        var xAxisExtent = xScale.getExtent();\n        var yAxisExtent = yScale.getExtent();\n        var x = xScale.parse(data[0]);\n        var y = yScale.parse(data[1]);\n        out = out || [];\n        out[0] = Math.min(\n            Math.max(Math.min(xAxisExtent[0], xAxisExtent[1]), x),\n            Math.max(xAxisExtent[0], xAxisExtent[1])\n        );\n        out[1] = Math.min(\n            Math.max(Math.min(yAxisExtent[0], yAxisExtent[1]), y),\n            Math.max(yAxisExtent[0], yAxisExtent[1])\n        );\n\n        return out;\n    },\n\n    /**\n     * @param {Array.<number>} point\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    pointToData: function (point, out) {\n        var xAxis = this.getAxis('x');\n        var yAxis = this.getAxis('y');\n        out = out || [];\n        out[0] = xAxis.coordToData(xAxis.toLocalCoord(point[0]));\n        out[1] = yAxis.coordToData(yAxis.toLocalCoord(point[1]));\n        return out;\n    },\n\n    /**\n     * Get other axis\n     * @param {module:echarts/coord/cartesian/Axis2D} axis\n     */\n    getOtherAxis: function (axis) {\n        return this.getAxis(axis.dim === 'x' ? 'y' : 'x');\n    }\n\n};\n\ninherits(Cartesian2D, Cartesian);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$6 = makeInner();\n\n/**\n * @param {module:echats/coord/Axis} axis\n * @return {Object} {\n *     labels: [{\n *         formattedLabel: string,\n *         rawLabel: string,\n *         tickValue: number\n *     }, ...],\n *     labelCategoryInterval: number\n * }\n */\nfunction createAxisLabels(axis) {\n    // Only ordinal scale support tick interval\n    return axis.type === 'category'\n        ? makeCategoryLabels(axis)\n        : makeRealNumberLabels(axis);\n}\n\n/**\n * @param {module:echats/coord/Axis} axis\n * @param {module:echarts/model/Model} tickModel For example, can be axisTick, splitLine, splitArea.\n * @return {Object} {\n *     ticks: Array.<number>\n *     tickCategoryInterval: number\n * }\n */\nfunction createAxisTicks(axis, tickModel) {\n    // Only ordinal scale support tick interval\n    return axis.type === 'category'\n        ? makeCategoryTicks(axis, tickModel)\n        : {ticks: axis.scale.getTicks()};\n}\n\nfunction makeCategoryLabels(axis) {\n    var labelModel = axis.getLabelModel();\n    var result = makeCategoryLabelsActually(axis, labelModel);\n\n    return (!labelModel.get('show') || axis.scale.isBlank())\n        ? {labels: [], labelCategoryInterval: result.labelCategoryInterval}\n        : result;\n}\n\nfunction makeCategoryLabelsActually(axis, labelModel) {\n    var labelsCache = getListCache(axis, 'labels');\n    var optionLabelInterval = getOptionCategoryInterval(labelModel);\n    var result = listCacheGet(labelsCache, optionLabelInterval);\n\n    if (result) {\n        return result;\n    }\n\n    var labels;\n    var numericLabelInterval;\n\n    if (isFunction$1(optionLabelInterval)) {\n        labels = makeLabelsByCustomizedCategoryInterval(axis, optionLabelInterval);\n    }\n    else {\n        numericLabelInterval = optionLabelInterval === 'auto'\n            ? makeAutoCategoryInterval(axis) : optionLabelInterval;\n        labels = makeLabelsByNumericCategoryInterval(axis, numericLabelInterval);\n    }\n\n    // Cache to avoid calling interval function repeatly.\n    return listCacheSet(labelsCache, optionLabelInterval, {\n        labels: labels, labelCategoryInterval: numericLabelInterval\n    });\n}\n\nfunction makeCategoryTicks(axis, tickModel) {\n    var ticksCache = getListCache(axis, 'ticks');\n    var optionTickInterval = getOptionCategoryInterval(tickModel);\n    var result = listCacheGet(ticksCache, optionTickInterval);\n\n    if (result) {\n        return result;\n    }\n\n    var ticks;\n    var tickCategoryInterval;\n\n    // Optimize for the case that large category data and no label displayed,\n    // we should not return all ticks.\n    if (!tickModel.get('show') || axis.scale.isBlank()) {\n        ticks = [];\n    }\n\n    if (isFunction$1(optionTickInterval)) {\n        ticks = makeLabelsByCustomizedCategoryInterval(axis, optionTickInterval, true);\n    }\n    // Always use label interval by default despite label show. Consider this\n    // scenario, Use multiple grid with the xAxis sync, and only one xAxis shows\n    // labels. `splitLine` and `axisTick` should be consistent in this case.\n    else if (optionTickInterval === 'auto') {\n        var labelsResult = makeCategoryLabelsActually(axis, axis.getLabelModel());\n        tickCategoryInterval = labelsResult.labelCategoryInterval;\n        ticks = map(labelsResult.labels, function (labelItem) {\n            return labelItem.tickValue;\n        });\n    }\n    else {\n        tickCategoryInterval = optionTickInterval;\n        ticks = makeLabelsByNumericCategoryInterval(axis, tickCategoryInterval, true);\n    }\n\n    // Cache to avoid calling interval function repeatly.\n    return listCacheSet(ticksCache, optionTickInterval, {\n        ticks: ticks, tickCategoryInterval: tickCategoryInterval\n    });\n}\n\nfunction makeRealNumberLabels(axis) {\n    var ticks = axis.scale.getTicks();\n    var labelFormatter = makeLabelFormatter(axis);\n    return {\n        labels: map(ticks, function (tickValue, idx) {\n            return {\n                formattedLabel: labelFormatter(tickValue, idx),\n                rawLabel: axis.scale.getLabel(tickValue),\n                tickValue: tickValue\n            };\n        })\n    };\n}\n\n// Large category data calculation is performence sensitive, and ticks and label\n// probably be fetched by multiple times. So we cache the result.\n// axis is created each time during a ec process, so we do not need to clear cache.\nfunction getListCache(axis, prop) {\n    // Because key can be funciton, and cache size always be small, we use array cache.\n    return inner$6(axis)[prop] || (inner$6(axis)[prop] = []);\n}\n\nfunction listCacheGet(cache, key) {\n    for (var i = 0; i < cache.length; i++) {\n        if (cache[i].key === key) {\n            return cache[i].value;\n        }\n    }\n}\n\nfunction listCacheSet(cache, key, value) {\n    cache.push({key: key, value: value});\n    return value;\n}\n\nfunction makeAutoCategoryInterval(axis) {\n    var result = inner$6(axis).autoInterval;\n    return result != null\n        ? result\n        : (inner$6(axis).autoInterval = axis.calculateCategoryInterval());\n}\n\n/**\n * Calculate interval for category axis ticks and labels.\n * To get precise result, at least one of `getRotate` and `isHorizontal`\n * should be implemented in axis.\n */\nfunction calculateCategoryInterval(axis) {\n    var params = fetchAutoCategoryIntervalCalculationParams(axis);\n    var labelFormatter = makeLabelFormatter(axis);\n    var rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI;\n\n    var ordinalScale = axis.scale;\n    var ordinalExtent = ordinalScale.getExtent();\n    // Providing this method is for optimization:\n    // avoid generating a long array by `getTicks`\n    // in large category data case.\n    var tickCount = ordinalScale.count();\n\n    if (ordinalExtent[1] - ordinalExtent[0] < 1) {\n        return 0;\n    }\n\n    var step = 1;\n    // Simple optimization. Empirical value: tick count should less than 40.\n    if (tickCount > 40) {\n        step = Math.max(1, Math.floor(tickCount / 40));\n    }\n    var tickValue = ordinalExtent[0];\n    var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue);\n    var unitW = Math.abs(unitSpan * Math.cos(rotation));\n    var unitH = Math.abs(unitSpan * Math.sin(rotation));\n\n    var maxW = 0;\n    var maxH = 0;\n\n    // Caution: Performance sensitive for large category data.\n    // Consider dataZoom, we should make appropriate step to avoid O(n) loop.\n    for (; tickValue <= ordinalExtent[1]; tickValue += step) {\n        var width = 0;\n        var height = 0;\n\n        // Not precise, do not consider align and vertical align\n        // and each distance from axis line yet.\n        var rect = getBoundingRect(\n            labelFormatter(tickValue), params.font, 'center', 'top'\n        );\n        // Magic number\n        width = rect.width * 1.3;\n        height = rect.height * 1.3;\n\n        // Min size, void long loop.\n        maxW = Math.max(maxW, width, 7);\n        maxH = Math.max(maxH, height, 7);\n    }\n\n    var dw = maxW / unitW;\n    var dh = maxH / unitH;\n    // 0/0 is NaN, 1/0 is Infinity.\n    isNaN(dw) && (dw = Infinity);\n    isNaN(dh) && (dh = Infinity);\n    var interval = Math.max(0, Math.floor(Math.min(dw, dh)));\n\n    var cache = inner$6(axis.model);\n    var lastAutoInterval = cache.lastAutoInterval;\n    var lastTickCount = cache.lastTickCount;\n\n    // Use cache to keep interval stable while moving zoom window,\n    // otherwise the calculated interval might jitter when the zoom\n    // window size is close to the interval-changing size.\n    if (lastAutoInterval != null\n        && lastTickCount != null\n        && Math.abs(lastAutoInterval - interval) <= 1\n        && Math.abs(lastTickCount - tickCount) <= 1\n        // Always choose the bigger one, otherwise the critical\n        // point is not the same when zooming in or zooming out.\n        && lastAutoInterval > interval\n    ) {\n        interval = lastAutoInterval;\n    }\n    // Only update cache if cache not used, otherwise the\n    // changing of interval is too insensitive.\n    else {\n        cache.lastTickCount = tickCount;\n        cache.lastAutoInterval = interval;\n    }\n\n    return interval;\n}\n\nfunction fetchAutoCategoryIntervalCalculationParams(axis) {\n    var labelModel = axis.getLabelModel();\n    return {\n        axisRotate: axis.getRotate\n            ? axis.getRotate()\n            : (axis.isHorizontal && !axis.isHorizontal())\n            ? 90\n            : 0,\n        labelRotate: labelModel.get('rotate') || 0,\n        font: labelModel.getFont()\n    };\n}\n\nfunction makeLabelsByNumericCategoryInterval(axis, categoryInterval, onlyTick) {\n    var labelFormatter = makeLabelFormatter(axis);\n    var ordinalScale = axis.scale;\n    var ordinalExtent = ordinalScale.getExtent();\n    var labelModel = axis.getLabelModel();\n    var result = [];\n\n    // TODO: axisType: ordinalTime, pick the tick from each month/day/year/...\n\n    var step = Math.max((categoryInterval || 0) + 1, 1);\n    var startTick = ordinalExtent[0];\n    var tickCount = ordinalScale.count();\n\n    // Calculate start tick based on zero if possible to keep label consistent\n    // while zooming and moving while interval > 0. Otherwise the selection\n    // of displayable ticks and symbols probably keep changing.\n    // 3 is empirical value.\n    if (startTick !== 0 && step > 1 && tickCount / step > 2) {\n        startTick = Math.round(Math.ceil(startTick / step) * step);\n    }\n\n    // (1) Only add min max label here but leave overlap checking\n    // to render stage, which also ensure the returned list\n    // suitable for splitLine and splitArea rendering.\n    // (2) Scales except category always contain min max label so\n    // do not need to perform this process.\n    var showAllLabel = shouldShowAllLabels(axis);\n    var includeMinLabel = labelModel.get('showMinLabel') || showAllLabel;\n    var includeMaxLabel = labelModel.get('showMaxLabel') || showAllLabel;\n\n    if (includeMinLabel && startTick !== ordinalExtent[0]) {\n        addItem(ordinalExtent[0]);\n    }\n\n    // Optimize: avoid generating large array by `ordinalScale.getTicks()`.\n    var tickValue = startTick;\n    for (; tickValue <= ordinalExtent[1]; tickValue += step) {\n        addItem(tickValue);\n    }\n\n    if (includeMaxLabel && tickValue !== ordinalExtent[1]) {\n        addItem(ordinalExtent[1]);\n    }\n\n    function addItem(tVal) {\n        result.push(onlyTick\n            ? tVal\n            : {\n                formattedLabel: labelFormatter(tVal),\n                rawLabel: ordinalScale.getLabel(tVal),\n                tickValue: tVal\n            }\n        );\n    }\n\n    return result;\n}\n\n// When interval is function, the result `false` means ignore the tick.\n// It is time consuming for large category data.\nfunction makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) {\n    var ordinalScale = axis.scale;\n    var labelFormatter = makeLabelFormatter(axis);\n    var result = [];\n\n    each$1(ordinalScale.getTicks(), function (tickValue) {\n        var rawLabel = ordinalScale.getLabel(tickValue);\n        if (categoryInterval(tickValue, rawLabel)) {\n            result.push(onlyTick\n                ? tickValue\n                : {\n                    formattedLabel: labelFormatter(tickValue),\n                    rawLabel: rawLabel,\n                    tickValue: tickValue\n                }\n            );\n        }\n    });\n\n    return result;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar NORMALIZED_EXTENT = [0, 1];\n\n/**\n * Base class of Axis.\n * @constructor\n */\nvar Axis = function (dim, scale, extent) {\n\n    /**\n     * Axis dimension. Such as 'x', 'y', 'z', 'angle', 'radius'.\n     * @type {string}\n     */\n    this.dim = dim;\n\n    /**\n     * Axis scale\n     * @type {module:echarts/coord/scale/*}\n     */\n    this.scale = scale;\n\n    /**\n     * @type {Array.<number>}\n     * @private\n     */\n    this._extent = extent || [0, 0];\n\n    /**\n     * @type {boolean}\n     */\n    this.inverse = false;\n\n    /**\n     * Usually true when axis has a ordinal scale\n     * @type {boolean}\n     */\n    this.onBand = false;\n};\n\nAxis.prototype = {\n\n    constructor: Axis,\n\n    /**\n     * If axis extent contain given coord\n     * @param {number} coord\n     * @return {boolean}\n     */\n    contain: function (coord) {\n        var extent = this._extent;\n        var min = Math.min(extent[0], extent[1]);\n        var max = Math.max(extent[0], extent[1]);\n        return coord >= min && coord <= max;\n    },\n\n    /**\n     * If axis extent contain given data\n     * @param {number} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this.contain(this.dataToCoord(data));\n    },\n\n    /**\n     * Get coord extent.\n     * @return {Array.<number>}\n     */\n    getExtent: function () {\n        return this._extent.slice();\n    },\n\n    /**\n     * Get precision used for formatting\n     * @param {Array.<number>} [dataExtent]\n     * @return {number}\n     */\n    getPixelPrecision: function (dataExtent) {\n        return getPixelPrecision(\n            dataExtent || this.scale.getExtent(),\n            this._extent\n        );\n    },\n\n    /**\n     * Set coord extent\n     * @param {number} start\n     * @param {number} end\n     */\n    setExtent: function (start, end) {\n        var extent = this._extent;\n        extent[0] = start;\n        extent[1] = end;\n    },\n\n    /**\n     * Convert data to coord. Data is the rank if it has an ordinal scale\n     * @param {number} data\n     * @param  {boolean} clamp\n     * @return {number}\n     */\n    dataToCoord: function (data, clamp) {\n        var extent = this._extent;\n        var scale = this.scale;\n        data = scale.normalize(data);\n\n        if (this.onBand && scale.type === 'ordinal') {\n            extent = extent.slice();\n            fixExtentWithBands(extent, scale.count());\n        }\n\n        return linearMap(data, NORMALIZED_EXTENT, extent, clamp);\n    },\n\n    /**\n     * Convert coord to data. Data is the rank if it has an ordinal scale\n     * @param {number} coord\n     * @param  {boolean} clamp\n     * @return {number}\n     */\n    coordToData: function (coord, clamp) {\n        var extent = this._extent;\n        var scale = this.scale;\n\n        if (this.onBand && scale.type === 'ordinal') {\n            extent = extent.slice();\n            fixExtentWithBands(extent, scale.count());\n        }\n\n        var t = linearMap(coord, extent, NORMALIZED_EXTENT, clamp);\n\n        return this.scale.scale(t);\n    },\n\n    /**\n     * Convert pixel point to data in axis\n     * @param {Array.<number>} point\n     * @param  {boolean} clamp\n     * @return {number} data\n     */\n    pointToData: function (point, clamp) {\n        // Should be implemented in derived class if necessary.\n    },\n\n    /**\n     * Different from `zrUtil.map(axis.getTicks(), axis.dataToCoord, axis)`,\n     * `axis.getTicksCoords` considers `onBand`, which is used by\n     * `boundaryGap:true` of category axis and splitLine and splitArea.\n     * @param {Object} [opt]\n     * @param {number} [opt.tickModel=axis.model.getModel('axisTick')]\n     * @param {boolean} [opt.clamp] If `true`, the first and the last\n     *        tick must be at the axis end points. Otherwise, clip ticks\n     *        that outside the axis extent.\n     * @return {Array.<Object>} [{\n     *     coord: ...,\n     *     tickValue: ...\n     * }, ...]\n     */\n    getTicksCoords: function (opt) {\n        opt = opt || {};\n\n        var tickModel = opt.tickModel || this.getTickModel();\n\n        var result = createAxisTicks(this, tickModel);\n        var ticks = result.ticks;\n\n        var ticksCoords = map(ticks, function (tickValue) {\n            return {\n                coord: this.dataToCoord(tickValue),\n                tickValue: tickValue\n            };\n        }, this);\n\n        var alignWithLabel = tickModel.get('alignWithLabel');\n        fixOnBandTicksCoords(\n            this, ticksCoords, result.tickCategoryInterval, alignWithLabel, opt.clamp\n        );\n\n        return ticksCoords;\n    },\n\n    /**\n     * @return {Array.<Object>} [{\n     *     formattedLabel: string,\n     *     rawLabel: axis.scale.getLabel(tickValue)\n     *     tickValue: number\n     * }, ...]\n     */\n    getViewLabels: function () {\n        return createAxisLabels(this).labels;\n    },\n\n    /**\n     * @return {module:echarts/coord/model/Model}\n     */\n    getLabelModel: function () {\n        return this.model.getModel('axisLabel');\n    },\n\n    /**\n     * Notice here we only get the default tick model. For splitLine\n     * or splitArea, we should pass the splitLineModel or splitAreaModel\n     * manually when calling `getTicksCoords`.\n     * In GL, this method may be overrided to:\n     * `axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));`\n     * @return {module:echarts/coord/model/Model}\n     */\n    getTickModel: function () {\n        return this.model.getModel('axisTick');\n    },\n\n    /**\n     * Get width of band\n     * @return {number}\n     */\n    getBandWidth: function () {\n        var axisExtent = this._extent;\n        var dataExtent = this.scale.getExtent();\n\n        var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0);\n        // Fix #2728, avoid NaN when only one data.\n        len === 0 && (len = 1);\n\n        var size = Math.abs(axisExtent[1] - axisExtent[0]);\n\n        return Math.abs(size) / len;\n    },\n\n    /**\n     * @abstract\n     * @return {boolean} Is horizontal\n     */\n    isHorizontal: null,\n\n    /**\n     * @abstract\n     * @return {number} Get axis rotate, by degree.\n     */\n    getRotate: null,\n\n    /**\n     * Only be called in category axis.\n     * Can be overrided, consider other axes like in 3D.\n     * @return {number} Auto interval for cateogry axis tick and label\n     */\n    calculateCategoryInterval: function () {\n        return calculateCategoryInterval(this);\n    }\n\n};\n\nfunction fixExtentWithBands(extent, nTick) {\n    var size = extent[1] - extent[0];\n    var len = nTick;\n    var margin = size / len / 2;\n    extent[0] += margin;\n    extent[1] -= margin;\n}\n\n// If axis has labels [1, 2, 3, 4]. Bands on the axis are\n// |---1---|---2---|---3---|---4---|.\n// So the displayed ticks and splitLine/splitArea should between\n// each data item, otherwise cause misleading (e.g., split tow bars\n// of a single data item when there are two bar series).\n// Also consider if tickCategoryInterval > 0 and onBand, ticks and\n// splitLine/spliteArea should layout appropriately corresponding\n// to displayed labels. (So we should not use `getBandWidth` in this\n// case).\nfunction fixOnBandTicksCoords(axis, ticksCoords, tickCategoryInterval, alignWithLabel, clamp) {\n    var ticksLen = ticksCoords.length;\n\n    if (!axis.onBand || alignWithLabel || !ticksLen) {\n        return;\n    }\n\n    var axisExtent = axis.getExtent();\n    var last;\n    if (ticksLen === 1) {\n        ticksCoords[0].coord = axisExtent[0];\n        last = ticksCoords[1] = {coord: axisExtent[0]};\n    }\n    else {\n        var shift = (ticksCoords[1].coord - ticksCoords[0].coord);\n        each$1(ticksCoords, function (ticksItem) {\n            ticksItem.coord -= shift / 2;\n            var tickCategoryInterval = tickCategoryInterval || 0;\n            // Avoid split a single data item when odd interval.\n            if (tickCategoryInterval % 2 > 0) {\n                ticksItem.coord -= shift / ((tickCategoryInterval + 1) * 2);\n            }\n        });\n        last = {coord: ticksCoords[ticksLen - 1].coord + shift};\n        ticksCoords.push(last);\n    }\n\n    var inverse = axisExtent[0] > axisExtent[1];\n\n    if (littleThan(ticksCoords[0].coord, axisExtent[0])) {\n        clamp ? (ticksCoords[0].coord = axisExtent[0]) : ticksCoords.shift();\n    }\n    if (clamp && littleThan(axisExtent[0], ticksCoords[0].coord)) {\n        ticksCoords.unshift({coord: axisExtent[0]});\n    }\n    if (littleThan(axisExtent[1], last.coord)) {\n        clamp ? (last.coord = axisExtent[1]) : ticksCoords.pop();\n    }\n    if (clamp && littleThan(last.coord, axisExtent[1])) {\n        ticksCoords.push({coord: axisExtent[1]});\n    }\n\n    function littleThan(a, b) {\n        return inverse ? a > b : a < b;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Extend axis 2d\n * @constructor module:echarts/coord/cartesian/Axis2D\n * @extends {module:echarts/coord/cartesian/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n * @param {string} position\n */\nvar Axis2D = function (dim, scale, coordExtent, axisType, position) {\n    Axis.call(this, dim, scale, coordExtent);\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * Axis position\n     *  - 'top'\n     *  - 'bottom'\n     *  - 'left'\n     *  - 'right'\n     */\n    this.position = position || 'bottom';\n};\n\nAxis2D.prototype = {\n\n    constructor: Axis2D,\n\n    /**\n     * Index of axis, can be used as key\n     */\n    index: 0,\n\n    /**\n     * Implemented in <module:echarts/coord/cartesian/Grid>.\n     * @return {Array.<module:echarts/coord/cartesian/Axis2D>}\n     *         If not on zero of other axis, return null/undefined.\n     *         If no axes, return an empty array.\n     */\n    getAxesOnZeroOf: null,\n\n    /**\n     * Axis model\n     * @param {module:echarts/coord/cartesian/AxisModel}\n     */\n    model: null,\n\n    isHorizontal: function () {\n        var position = this.position;\n        return position === 'top' || position === 'bottom';\n    },\n\n    /**\n     * Each item cooresponds to this.getExtent(), which\n     * means globalExtent[0] may greater than globalExtent[1],\n     * unless `asc` is input.\n     *\n     * @param {boolean} [asc]\n     * @return {Array.<number>}\n     */\n    getGlobalExtent: function (asc) {\n        var ret = this.getExtent();\n        ret[0] = this.toGlobalCoord(ret[0]);\n        ret[1] = this.toGlobalCoord(ret[1]);\n        asc && ret[0] > ret[1] && ret.reverse();\n        return ret;\n    },\n\n    getOtherAxis: function () {\n        this.grid.getOtherAxis();\n    },\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.coordToData(this.toLocalCoord(point[this.dim === 'x' ? 0 : 1]), clamp);\n    },\n\n    /**\n     * Transform global coord to local coord,\n     * i.e. var localCoord = axis.toLocalCoord(80);\n     * designate by module:echarts/coord/cartesian/Grid.\n     * @type {Function}\n     */\n    toLocalCoord: null,\n\n    /**\n     * Transform global coord to local coord,\n     * i.e. var globalCoord = axis.toLocalCoord(40);\n     * designate by module:echarts/coord/cartesian/Grid.\n     * @type {Function}\n     */\n    toGlobalCoord: null\n\n};\n\ninherits(Axis2D, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar defaultOption = {\n    show: true,\n    zlevel: 0,\n    z: 0,\n    // Inverse the axis.\n    inverse: false,\n\n    // Axis name displayed.\n    name: '',\n    // 'start' | 'middle' | 'end'\n    nameLocation: 'end',\n    // By degree. By defualt auto rotate by nameLocation.\n    nameRotate: null,\n    nameTruncate: {\n        maxWidth: null,\n        ellipsis: '...',\n        placeholder: '.'\n    },\n    // Use global text style by default.\n    nameTextStyle: {},\n    // The gap between axisName and axisLine.\n    nameGap: 15,\n\n    // Default `false` to support tooltip.\n    silent: false,\n    // Default `false` to avoid legacy user event listener fail.\n    triggerEvent: false,\n\n    tooltip: {\n        show: false\n    },\n\n    axisPointer: {},\n\n    axisLine: {\n        show: true,\n        onZero: true,\n        onZeroAxisIndex: null,\n        lineStyle: {\n            color: '#333',\n            width: 1,\n            type: 'solid'\n        },\n        // The arrow at both ends the the axis.\n        symbol: ['none', 'none'],\n        symbolSize: [10, 15]\n    },\n    axisTick: {\n        show: true,\n        // Whether axisTick is inside the grid or outside the grid.\n        inside: false,\n        // The length of axisTick.\n        length: 5,\n        lineStyle: {\n            width: 1\n        }\n    },\n    axisLabel: {\n        show: true,\n        // Whether axisLabel is inside the grid or outside the grid.\n        inside: false,\n        rotate: 0,\n        // true | false | null/undefined (auto)\n        showMinLabel: null,\n        // true | false | null/undefined (auto)\n        showMaxLabel: null,\n        margin: 8,\n        // formatter: null,\n        fontSize: 12\n    },\n    splitLine: {\n        show: true,\n        lineStyle: {\n            color: ['#ccc'],\n            width: 1,\n            type: 'solid'\n        }\n    },\n    splitArea: {\n        show: false,\n        areaStyle: {\n            color: ['rgba(250,250,250,0.3)', 'rgba(200,200,200,0.3)']\n        }\n    }\n};\n\nvar axisDefault = {};\n\naxisDefault.categoryAxis = merge({\n    // The gap at both ends of the axis. For categoryAxis, boolean.\n    boundaryGap: true,\n    // Set false to faster category collection.\n    // Only usefull in the case like: category is\n    // ['2012-01-01', '2012-01-02', ...], where the input\n    // data has been ensured not duplicate and is large data.\n    // null means \"auto\":\n    // if axis.data provided, do not deduplication,\n    // else do deduplication.\n    deduplication: null,\n    // splitArea: {\n        // show: false\n    // },\n    splitLine: {\n        show: false\n    },\n    axisTick: {\n        // If tick is align with label when boundaryGap is true\n        alignWithLabel: false,\n        interval: 'auto'\n    },\n    axisLabel: {\n        interval: 'auto'\n    }\n}, defaultOption);\n\naxisDefault.valueAxis = merge({\n    // The gap at both ends of the axis. For value axis, [GAP, GAP], where\n    // `GAP` can be an absolute pixel number (like `35`), or percent (like `'30%'`)\n    boundaryGap: [0, 0],\n\n    // TODO\n    // min/max: [30, datamin, 60] or [20, datamin] or [datamin, 60]\n\n    // Min value of the axis. can be:\n    // + a number\n    // + 'dataMin': use the min value in data.\n    // + null/undefined: auto decide min value (consider pretty look and boundaryGap).\n    // min: null,\n\n    // Max value of the axis. can be:\n    // + a number\n    // + 'dataMax': use the max value in data.\n    // + null/undefined: auto decide max value (consider pretty look and boundaryGap).\n    // max: null,\n\n    // Readonly prop, specifies start value of the range when using data zoom.\n    // rangeStart: null\n\n    // Readonly prop, specifies end value of the range when using data zoom.\n    // rangeEnd: null\n\n    // Optional value can be:\n    // + `false`: always include value 0.\n    // + `true`: the extent do not consider value 0.\n    // scale: false,\n\n    // AxisTick and axisLabel and splitLine are caculated based on splitNumber.\n    splitNumber: 5\n\n    // Interval specifies the span of the ticks is mandatorily.\n    // interval: null\n\n    // Specify min interval when auto calculate tick interval.\n    // minInterval: null\n\n    // Specify max interval when auto calculate tick interval.\n    // maxInterval: null\n\n}, defaultOption);\n\naxisDefault.timeAxis = defaults({\n    scale: true,\n    min: 'dataMin',\n    max: 'dataMax'\n}, axisDefault.valueAxis);\n\naxisDefault.logAxis = defaults({\n    scale: true,\n    logBase: 10\n}, axisDefault.valueAxis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME axisType is fixed ?\nvar AXIS_TYPES = ['value', 'category', 'time', 'log'];\n\n/**\n * Generate sub axis model class\n * @param {string} axisName 'x' 'y' 'radius' 'angle' 'parallel'\n * @param {module:echarts/model/Component} BaseAxisModelClass\n * @param {Function} axisTypeDefaulter\n * @param {Object} [extraDefaultOption]\n */\nvar axisModelCreator = function (axisName, BaseAxisModelClass, axisTypeDefaulter, extraDefaultOption) {\n\n    each$1(AXIS_TYPES, function (axisType) {\n\n        BaseAxisModelClass.extend({\n\n            /**\n             * @readOnly\n             */\n            type: axisName + 'Axis.' + axisType,\n\n            mergeDefaultAndTheme: function (option, ecModel) {\n                var layoutMode = this.layoutMode;\n                var inputPositionParams = layoutMode\n                    ? getLayoutParams(option) : {};\n\n                var themeModel = ecModel.getTheme();\n                merge(option, themeModel.get(axisType + 'Axis'));\n                merge(option, this.getDefaultOption());\n\n                option.type = axisTypeDefaulter(axisName, option);\n\n                if (layoutMode) {\n                    mergeLayoutParam(option, inputPositionParams, layoutMode);\n                }\n            },\n\n            /**\n             * @override\n             */\n            optionUpdated: function () {\n                var thisOption = this.option;\n                if (thisOption.type === 'category') {\n                    this.__ordinalMeta = OrdinalMeta.createByAxisModel(this);\n                }\n            },\n\n            /**\n             * Should not be called before all of 'getInitailData' finished.\n             * Because categories are collected during initializing data.\n             */\n            getCategories: function (rawData) {\n                var option = this.option;\n                // FIXME\n                // warning if called before all of 'getInitailData' finished.\n                if (option.type === 'category') {\n                    if (rawData) {\n                        return option.data;\n                    }\n                    return this.__ordinalMeta.categories;\n                }\n            },\n\n            getOrdinalMeta: function () {\n                return this.__ordinalMeta;\n            },\n\n            defaultOption: mergeAll(\n                [\n                    {},\n                    axisDefault[axisType + 'Axis'],\n                    extraDefaultOption\n                ],\n                true\n            )\n        });\n    });\n\n    ComponentModel.registerSubTypeDefaulter(\n        axisName + 'Axis',\n        curry(axisTypeDefaulter, axisName)\n    );\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import * as axisHelper from './axisHelper';\n\nvar axisModelCommonMixin = {\n\n    /**\n     * @param {boolean} origin\n     * @return {number|string} min value or 'dataMin' or null/undefined (means auto) or NaN\n     */\n    getMin: function (origin) {\n        var option = this.option;\n        var min = (!origin && option.rangeStart != null)\n            ? option.rangeStart : option.min;\n\n        if (this.axis\n            && min != null\n            && min !== 'dataMin'\n            && typeof min !== 'function'\n            && !eqNaN(min)\n        ) {\n            min = this.axis.scale.parse(min);\n        }\n        return min;\n    },\n\n    /**\n     * @param {boolean} origin\n     * @return {number|string} max value or 'dataMax' or null/undefined (means auto) or NaN\n     */\n    getMax: function (origin) {\n        var option = this.option;\n        var max = (!origin && option.rangeEnd != null)\n            ? option.rangeEnd : option.max;\n\n        if (this.axis\n            && max != null\n            && max !== 'dataMax'\n            && typeof max !== 'function'\n            && !eqNaN(max)\n        ) {\n            max = this.axis.scale.parse(max);\n        }\n        return max;\n    },\n\n    /**\n     * @return {boolean}\n     */\n    getNeedCrossZero: function () {\n        var option = this.option;\n        return (option.rangeStart != null || option.rangeEnd != null)\n            ? false : !option.scale;\n    },\n\n    /**\n     * Should be implemented by each axis model if necessary.\n     * @return {module:echarts/model/Component} coordinate system model\n     */\n    getCoordSysModel: noop,\n\n    /**\n     * @param {number} rangeStart Can only be finite number or null/undefined or NaN.\n     * @param {number} rangeEnd Can only be finite number or null/undefined or NaN.\n     */\n    setRange: function (rangeStart, rangeEnd) {\n        this.option.rangeStart = rangeStart;\n        this.option.rangeEnd = rangeEnd;\n    },\n\n    /**\n     * Reset range\n     */\n    resetRange: function () {\n        // rangeStart and rangeEnd is readonly.\n        this.option.rangeStart = this.option.rangeEnd = null;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisModel = ComponentModel.extend({\n\n    type: 'cartesian2dAxis',\n\n    /**\n     * @type {module:echarts/coord/cartesian/Axis2D}\n     */\n    axis: null,\n\n    /**\n     * @override\n     */\n    init: function () {\n        AxisModel.superApply(this, 'init', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function () {\n        AxisModel.superApply(this, 'mergeOption', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     */\n    restoreData: function () {\n        AxisModel.superApply(this, 'restoreData', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     * @return {module:echarts/model/Component}\n     */\n    getCoordSysModel: function () {\n        return this.ecModel.queryComponents({\n            mainType: 'grid',\n            index: this.option.gridIndex,\n            id: this.option.gridId\n        })[0];\n    }\n\n});\n\nfunction getAxisType(axisDim, option) {\n    // Default axis with data is category axis\n    return option.type || (option.data ? 'category' : 'value');\n}\n\nmerge(AxisModel.prototype, axisModelCommonMixin);\n\nvar extraOption = {\n    // gridIndex: 0,\n    // gridId: '',\n\n    // Offset is for multiple axis on the same position\n    offset: 0\n};\n\naxisModelCreator('x', AxisModel, getAxisType, extraOption);\naxisModelCreator('y', AxisModel, getAxisType, extraOption);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Grid 是在有直角坐标系的时候必须要存在的\n// 所以这里也要被 Cartesian2D 依赖\n\nComponentModel.extend({\n\n    type: 'grid',\n\n    dependencies: ['xAxis', 'yAxis'],\n\n    layoutMode: 'box',\n\n    /**\n     * @type {module:echarts/coord/cartesian/Grid}\n     */\n    coordinateSystem: null,\n\n    defaultOption: {\n        show: false,\n        zlevel: 0,\n        z: 0,\n        left: '10%',\n        top: 60,\n        right: '10%',\n        bottom: 60,\n        // If grid size contain label\n        containLabel: false,\n        // width: {totalWidth} - left - right,\n        // height: {totalHeight} - top - bottom,\n        backgroundColor: 'rgba(0,0,0,0)',\n        borderWidth: 1,\n        borderColor: '#ccc'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Grid is a region which contains at most 4 cartesian systems\n *\n * TODO Default cartesian\n */\n\n// Depends on GridModel, AxisModel, which performs preprocess.\n/**\n * Check if the axis is used in the specified grid\n * @inner\n */\nfunction isAxisUsedInTheGrid(axisModel, gridModel, ecModel) {\n    return axisModel.getCoordSysModel() === gridModel;\n}\n\nfunction Grid(gridModel, ecModel, api) {\n    /**\n     * @type {Object.<string, module:echarts/coord/cartesian/Cartesian2D>}\n     * @private\n     */\n    this._coordsMap = {};\n\n    /**\n     * @type {Array.<module:echarts/coord/cartesian/Cartesian>}\n     * @private\n     */\n    this._coordsList = [];\n\n    /**\n     * @type {Object.<string, module:echarts/coord/cartesian/Axis2D>}\n     * @private\n     */\n    this._axesMap = {};\n\n    /**\n     * @type {Array.<module:echarts/coord/cartesian/Axis2D>}\n     * @private\n     */\n    this._axesList = [];\n\n    this._initCartesian(gridModel, ecModel, api);\n\n    this.model = gridModel;\n}\n\nvar gridProto = Grid.prototype;\n\ngridProto.type = 'grid';\n\ngridProto.axisPointerEnabled = true;\n\ngridProto.getRect = function () {\n    return this._rect;\n};\n\ngridProto.update = function (ecModel, api) {\n\n    var axesMap = this._axesMap;\n\n    this._updateScale(ecModel, this.model);\n\n    each$1(axesMap.x, function (xAxis) {\n        niceScaleExtent(xAxis.scale, xAxis.model);\n    });\n    each$1(axesMap.y, function (yAxis) {\n        niceScaleExtent(yAxis.scale, yAxis.model);\n    });\n\n    // Key: axisDim_axisIndex, value: boolean, whether onZero target.\n    var onZeroRecords = {};\n\n    each$1(axesMap.x, function (xAxis) {\n        fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords);\n    });\n    each$1(axesMap.y, function (yAxis) {\n        fixAxisOnZero(axesMap, 'x', yAxis, onZeroRecords);\n    });\n\n    // Resize again if containLabel is enabled\n    // FIXME It may cause getting wrong grid size in data processing stage\n    this.resize(this.model, api);\n};\n\nfunction fixAxisOnZero(axesMap, otherAxisDim, axis, onZeroRecords) {\n\n    axis.getAxesOnZeroOf = function () {\n        // TODO: onZero of multiple axes.\n        return otherAxisOnZeroOf ? [otherAxisOnZeroOf] : [];\n    };\n\n    // onZero can not be enabled in these two situations:\n    // 1. When any other axis is a category axis.\n    // 2. When no axis is cross 0 point.\n    var otherAxes = axesMap[otherAxisDim];\n\n    var otherAxisOnZeroOf;\n    var axisModel = axis.model;\n    var onZero = axisModel.get('axisLine.onZero');\n    var onZeroAxisIndex = axisModel.get('axisLine.onZeroAxisIndex');\n\n    if (!onZero) {\n        return;\n    }\n\n    // If target axis is specified.\n    if (onZeroAxisIndex != null) {\n        if (canOnZeroToAxis(otherAxes[onZeroAxisIndex])) {\n            otherAxisOnZeroOf = otherAxes[onZeroAxisIndex];\n        }\n    }\n    else {\n        // Find the first available other axis.\n        for (var idx in otherAxes) {\n            if (otherAxes.hasOwnProperty(idx)\n                && canOnZeroToAxis(otherAxes[idx])\n                // Consider that two Y axes on one value axis,\n                // if both onZero, the two Y axes overlap.\n                && !onZeroRecords[getOnZeroRecordKey(otherAxes[idx])]\n            ) {\n                otherAxisOnZeroOf = otherAxes[idx];\n                break;\n            }\n        }\n    }\n\n    if (otherAxisOnZeroOf) {\n        onZeroRecords[getOnZeroRecordKey(otherAxisOnZeroOf)] = true;\n    }\n\n    function getOnZeroRecordKey(axis) {\n        return axis.dim + '_' + axis.index;\n    }\n}\n\nfunction canOnZeroToAxis(axis) {\n    return axis && axis.type !== 'category' && axis.type !== 'time' && ifAxisCrossZero(axis);\n}\n\n/**\n * Resize the grid\n * @param {module:echarts/coord/cartesian/GridModel} gridModel\n * @param {module:echarts/ExtensionAPI} api\n */\ngridProto.resize = function (gridModel, api, ignoreContainLabel) {\n\n    var gridRect = getLayoutRect(\n        gridModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        });\n\n    this._rect = gridRect;\n\n    var axesList = this._axesList;\n\n    adjustAxes();\n\n    // Minus label size\n    if (!ignoreContainLabel && gridModel.get('containLabel')) {\n        each$1(axesList, function (axis) {\n            if (!axis.model.get('axisLabel.inside')) {\n                var labelUnionRect = estimateLabelUnionRect(axis);\n                if (labelUnionRect) {\n                    var dim = axis.isHorizontal() ? 'height' : 'width';\n                    var margin = axis.model.get('axisLabel.margin');\n                    gridRect[dim] -= labelUnionRect[dim] + margin;\n                    if (axis.position === 'top') {\n                        gridRect.y += labelUnionRect.height + margin;\n                    }\n                    else if (axis.position === 'left') {\n                        gridRect.x += labelUnionRect.width + margin;\n                    }\n                }\n            }\n        });\n\n        adjustAxes();\n    }\n\n    function adjustAxes() {\n        each$1(axesList, function (axis) {\n            var isHorizontal = axis.isHorizontal();\n            var extent = isHorizontal ? [0, gridRect.width] : [0, gridRect.height];\n            var idx = axis.inverse ? 1 : 0;\n            axis.setExtent(extent[idx], extent[1 - idx]);\n            updateAxisTransform(axis, isHorizontal ? gridRect.x : gridRect.y);\n        });\n    }\n};\n\n/**\n * @param {string} axisType\n * @param {number} [axisIndex]\n */\ngridProto.getAxis = function (axisType, axisIndex) {\n    var axesMapOnDim = this._axesMap[axisType];\n    if (axesMapOnDim != null) {\n        if (axisIndex == null) {\n            // Find first axis\n            for (var name in axesMapOnDim) {\n                if (axesMapOnDim.hasOwnProperty(name)) {\n                    return axesMapOnDim[name];\n                }\n            }\n        }\n        return axesMapOnDim[axisIndex];\n    }\n};\n\n/**\n * @return {Array.<module:echarts/coord/Axis>}\n */\ngridProto.getAxes = function () {\n    return this._axesList.slice();\n};\n\n/**\n * Usage:\n *      grid.getCartesian(xAxisIndex, yAxisIndex);\n *      grid.getCartesian(xAxisIndex);\n *      grid.getCartesian(null, yAxisIndex);\n *      grid.getCartesian({xAxisIndex: ..., yAxisIndex: ...});\n *\n * @param {number|Object} [xAxisIndex]\n * @param {number} [yAxisIndex]\n */\ngridProto.getCartesian = function (xAxisIndex, yAxisIndex) {\n    if (xAxisIndex != null && yAxisIndex != null) {\n        var key = 'x' + xAxisIndex + 'y' + yAxisIndex;\n        return this._coordsMap[key];\n    }\n\n    if (isObject$1(xAxisIndex)) {\n        yAxisIndex = xAxisIndex.yAxisIndex;\n        xAxisIndex = xAxisIndex.xAxisIndex;\n    }\n    // When only xAxisIndex or yAxisIndex given, find its first cartesian.\n    for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) {\n        if (coordList[i].getAxis('x').index === xAxisIndex\n            || coordList[i].getAxis('y').index === yAxisIndex\n        ) {\n            return coordList[i];\n        }\n    }\n};\n\ngridProto.getCartesians = function () {\n    return this._coordsList.slice();\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.convertToPixel = function (ecModel, finder, value) {\n    var target = this._findConvertTarget(ecModel, finder);\n\n    return target.cartesian\n        ? target.cartesian.dataToPoint(value)\n        : target.axis\n        ? target.axis.toGlobalCoord(target.axis.dataToCoord(value))\n        : null;\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.convertFromPixel = function (ecModel, finder, value) {\n    var target = this._findConvertTarget(ecModel, finder);\n\n    return target.cartesian\n        ? target.cartesian.pointToData(value)\n        : target.axis\n        ? target.axis.coordToData(target.axis.toLocalCoord(value))\n        : null;\n};\n\n/**\n * @inner\n */\ngridProto._findConvertTarget = function (ecModel, finder) {\n    var seriesModel = finder.seriesModel;\n    var xAxisModel = finder.xAxisModel\n        || (seriesModel && seriesModel.getReferringComponents('xAxis')[0]);\n    var yAxisModel = finder.yAxisModel\n        || (seriesModel && seriesModel.getReferringComponents('yAxis')[0]);\n    var gridModel = finder.gridModel;\n    var coordsList = this._coordsList;\n    var cartesian;\n    var axis;\n\n    if (seriesModel) {\n        cartesian = seriesModel.coordinateSystem;\n        indexOf(coordsList, cartesian) < 0 && (cartesian = null);\n    }\n    else if (xAxisModel && yAxisModel) {\n        cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);\n    }\n    else if (xAxisModel) {\n        axis = this.getAxis('x', xAxisModel.componentIndex);\n    }\n    else if (yAxisModel) {\n        axis = this.getAxis('y', yAxisModel.componentIndex);\n    }\n    // Lowest priority.\n    else if (gridModel) {\n        var grid = gridModel.coordinateSystem;\n        if (grid === this) {\n            cartesian = this._coordsList[0];\n        }\n    }\n\n    return {cartesian: cartesian, axis: axis};\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.containPoint = function (point) {\n    var coord = this._coordsList[0];\n    if (coord) {\n        return coord.containPoint(point);\n    }\n};\n\n/**\n * Initialize cartesian coordinate systems\n * @private\n */\ngridProto._initCartesian = function (gridModel, ecModel, api) {\n    var axisPositionUsed = {\n        left: false,\n        right: false,\n        top: false,\n        bottom: false\n    };\n\n    var axesMap = {\n        x: {},\n        y: {}\n    };\n    var axesCount = {\n        x: 0,\n        y: 0\n    };\n\n    /// Create axis\n    ecModel.eachComponent('xAxis', createAxisCreator('x'), this);\n    ecModel.eachComponent('yAxis', createAxisCreator('y'), this);\n\n    if (!axesCount.x || !axesCount.y) {\n        // Roll back when there no either x or y axis\n        this._axesMap = {};\n        this._axesList = [];\n        return;\n    }\n\n    this._axesMap = axesMap;\n\n    /// Create cartesian2d\n    each$1(axesMap.x, function (xAxis, xAxisIndex) {\n        each$1(axesMap.y, function (yAxis, yAxisIndex) {\n            var key = 'x' + xAxisIndex + 'y' + yAxisIndex;\n            var cartesian = new Cartesian2D(key);\n\n            cartesian.grid = this;\n            cartesian.model = gridModel;\n\n            this._coordsMap[key] = cartesian;\n            this._coordsList.push(cartesian);\n\n            cartesian.addAxis(xAxis);\n            cartesian.addAxis(yAxis);\n        }, this);\n    }, this);\n\n    function createAxisCreator(axisType) {\n        return function (axisModel, idx) {\n            if (!isAxisUsedInTheGrid(axisModel, gridModel, ecModel)) {\n                return;\n            }\n\n            var axisPosition = axisModel.get('position');\n            if (axisType === 'x') {\n                // Fix position\n                if (axisPosition !== 'top' && axisPosition !== 'bottom') {\n                    // Default bottom of X\n                    axisPosition = 'bottom';\n                    if (axisPositionUsed[axisPosition]) {\n                        axisPosition = axisPosition === 'top' ? 'bottom' : 'top';\n                    }\n                }\n            }\n            else {\n                // Fix position\n                if (axisPosition !== 'left' && axisPosition !== 'right') {\n                    // Default left of Y\n                    axisPosition = 'left';\n                    if (axisPositionUsed[axisPosition]) {\n                        axisPosition = axisPosition === 'left' ? 'right' : 'left';\n                    }\n                }\n            }\n            axisPositionUsed[axisPosition] = true;\n\n            var axis = new Axis2D(\n                axisType, createScaleByModel(axisModel),\n                [0, 0],\n                axisModel.get('type'),\n                axisPosition\n            );\n\n            var isCategory = axis.type === 'category';\n            axis.onBand = isCategory && axisModel.get('boundaryGap');\n            axis.inverse = axisModel.get('inverse');\n\n            // Inject axis into axisModel\n            axisModel.axis = axis;\n\n            // Inject axisModel into axis\n            axis.model = axisModel;\n\n            // Inject grid info axis\n            axis.grid = this;\n\n            // Index of axis, can be used as key\n            axis.index = idx;\n\n            this._axesList.push(axis);\n\n            axesMap[axisType][idx] = axis;\n            axesCount[axisType]++;\n        };\n    }\n};\n\n/**\n * Update cartesian properties from series\n * @param  {module:echarts/model/Option} option\n * @private\n */\ngridProto._updateScale = function (ecModel, gridModel) {\n    // Reset scale\n    each$1(this._axesList, function (axis) {\n        axis.scale.setExtent(Infinity, -Infinity);\n    });\n    ecModel.eachSeries(function (seriesModel) {\n        if (isCartesian2D(seriesModel)) {\n            var axesModels = findAxesModels(seriesModel, ecModel);\n            var xAxisModel = axesModels[0];\n            var yAxisModel = axesModels[1];\n\n            if (!isAxisUsedInTheGrid(xAxisModel, gridModel, ecModel)\n                || !isAxisUsedInTheGrid(yAxisModel, gridModel, ecModel)\n            ) {\n                return;\n            }\n\n            var cartesian = this.getCartesian(\n                xAxisModel.componentIndex, yAxisModel.componentIndex\n            );\n            var data = seriesModel.getData();\n            var xAxis = cartesian.getAxis('x');\n            var yAxis = cartesian.getAxis('y');\n\n            if (data.type === 'list') {\n                unionExtent(data, xAxis, seriesModel);\n                unionExtent(data, yAxis, seriesModel);\n            }\n        }\n    }, this);\n\n    function unionExtent(data, axis, seriesModel) {\n        each$1(data.mapDimension(axis.dim, true), function (dim) {\n            axis.scale.unionExtentFromData(\n                // For example, the extent of the orginal dimension\n                // is [0.1, 0.5], the extent of the `stackResultDimension`\n                // is [7, 9], the final extent should not include [0.1, 0.5].\n                data, getStackedDimension(data, dim)\n            );\n        });\n    }\n};\n\n/**\n * @param {string} [dim] 'x' or 'y' or 'auto' or null/undefined\n * @return {Object} {baseAxes: [], otherAxes: []}\n */\ngridProto.getTooltipAxes = function (dim) {\n    var baseAxes = [];\n    var otherAxes = [];\n\n    each$1(this.getCartesians(), function (cartesian) {\n        var baseAxis = (dim != null && dim !== 'auto')\n            ? cartesian.getAxis(dim) : cartesian.getBaseAxis();\n        var otherAxis = cartesian.getOtherAxis(baseAxis);\n        indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis);\n        indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis);\n    });\n\n    return {baseAxes: baseAxes, otherAxes: otherAxes};\n};\n\n/**\n * @inner\n */\nfunction updateAxisTransform(axis, coordBase) {\n    var axisExtent = axis.getExtent();\n    var axisExtentSum = axisExtent[0] + axisExtent[1];\n\n    // Fast transform\n    axis.toGlobalCoord = axis.dim === 'x'\n        ? function (coord) {\n            return coord + coordBase;\n        }\n        : function (coord) {\n            return axisExtentSum - coord + coordBase;\n        };\n    axis.toLocalCoord = axis.dim === 'x'\n        ? function (coord) {\n            return coord - coordBase;\n        }\n        : function (coord) {\n            return axisExtentSum - coord + coordBase;\n        };\n}\n\nvar axesTypes = ['xAxis', 'yAxis'];\n/**\n * @inner\n */\nfunction findAxesModels(seriesModel, ecModel) {\n    return map(axesTypes, function (axisType) {\n        var axisModel = seriesModel.getReferringComponents(axisType)[0];\n\n        if (__DEV__) {\n            if (!axisModel) {\n                throw new Error(axisType + ' \"' + retrieve(\n                    seriesModel.get(axisType + 'Index'),\n                    seriesModel.get(axisType + 'Id'),\n                    0\n                ) + '\" not found');\n            }\n        }\n        return axisModel;\n    });\n}\n\n/**\n * @inner\n */\nfunction isCartesian2D(seriesModel) {\n    return seriesModel.get('coordinateSystem') === 'cartesian2d';\n}\n\nGrid.create = function (ecModel, api) {\n    var grids = [];\n    ecModel.eachComponent('grid', function (gridModel, idx) {\n        var grid = new Grid(gridModel, ecModel, api);\n        grid.name = 'grid_' + idx;\n        // dataSampling requires axis extent, so resize\n        // should be performed in create stage.\n        grid.resize(gridModel, api, true);\n\n        gridModel.coordinateSystem = grid;\n\n        grids.push(grid);\n    });\n\n    // Inject the coordinateSystems into seriesModel\n    ecModel.eachSeries(function (seriesModel) {\n        if (!isCartesian2D(seriesModel)) {\n            return;\n        }\n\n        var axesModels = findAxesModels(seriesModel, ecModel);\n        var xAxisModel = axesModels[0];\n        var yAxisModel = axesModels[1];\n\n        var gridModel = xAxisModel.getCoordSysModel();\n\n        if (__DEV__) {\n            if (!gridModel) {\n                throw new Error(\n                    'Grid \"' + retrieve(\n                        xAxisModel.get('gridIndex'),\n                        xAxisModel.get('gridId'),\n                        0\n                    ) + '\" not found'\n                );\n            }\n            if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) {\n                throw new Error('xAxis and yAxis must use the same grid');\n            }\n        }\n\n        var grid = gridModel.coordinateSystem;\n\n        seriesModel.coordinateSystem = grid.getCartesian(\n            xAxisModel.componentIndex, yAxisModel.componentIndex\n        );\n    });\n\n    return grids;\n};\n\n// For deciding which dimensions to use when creating list data\nGrid.dimensions = Grid.prototype.dimensions = Cartesian2D.prototype.dimensions;\n\nCoordinateSystemManager.register('cartesian2d', Grid);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PI$2 = Math.PI;\n\nfunction makeAxisEventDataBase(axisModel) {\n    var eventData = {\n        componentType: axisModel.mainType,\n        componentIndex: axisModel.componentIndex\n    };\n    eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex;\n    return eventData;\n}\n\n/**\n * A final axis is translated and rotated from a \"standard axis\".\n * So opt.position and opt.rotation is required.\n *\n * A standard axis is and axis from [0, 0] to [0, axisExtent[1]],\n * for example: (0, 0) ------------> (0, 50)\n *\n * nameDirection or tickDirection or labelDirection is 1 means tick\n * or label is below the standard axis, whereas is -1 means above\n * the standard axis. labelOffset means offset between label and axis,\n * which is useful when 'onZero', where axisLabel is in the grid and\n * label in outside grid.\n *\n * Tips: like always,\n * positive rotation represents anticlockwise, and negative rotation\n * represents clockwise.\n * The direction of position coordinate is the same as the direction\n * of screen coordinate.\n *\n * Do not need to consider axis 'inverse', which is auto processed by\n * axis extent.\n *\n * @param {module:zrender/container/Group} group\n * @param {Object} axisModel\n * @param {Object} opt Standard axis parameters.\n * @param {Array.<number>} opt.position [x, y]\n * @param {number} opt.rotation by radian\n * @param {number} [opt.nameDirection=1] 1 or -1 Used when nameLocation is 'middle' or 'center'.\n * @param {number} [opt.tickDirection=1] 1 or -1\n * @param {number} [opt.labelDirection=1] 1 or -1\n * @param {number} [opt.labelOffset=0] Usefull when onZero.\n * @param {string} [opt.axisLabelShow] default get from axisModel.\n * @param {string} [opt.axisName] default get from axisModel.\n * @param {number} [opt.axisNameAvailableWidth]\n * @param {number} [opt.labelRotate] by degree, default get from axisModel.\n * @param {number} [opt.strokeContainThreshold] Default label interval when label\n * @param {number} [opt.nameTruncateMaxWidth]\n */\nvar AxisBuilder = function (axisModel, opt) {\n\n    /**\n     * @readOnly\n     */\n    this.opt = opt;\n\n    /**\n     * @readOnly\n     */\n    this.axisModel = axisModel;\n\n    // Default value\n    defaults(\n        opt,\n        {\n            labelOffset: 0,\n            nameDirection: 1,\n            tickDirection: 1,\n            labelDirection: 1,\n            silent: true\n        }\n    );\n\n    /**\n     * @readOnly\n     */\n    this.group = new Group();\n\n    // FIXME Not use a seperate text group?\n    var dumbGroup = new Group({\n        position: opt.position.slice(),\n        rotation: opt.rotation\n    });\n\n    // this.group.add(dumbGroup);\n    // this._dumbGroup = dumbGroup;\n\n    dumbGroup.updateTransform();\n    this._transform = dumbGroup.transform;\n\n    this._dumbGroup = dumbGroup;\n};\n\nAxisBuilder.prototype = {\n\n    constructor: AxisBuilder,\n\n    hasBuilder: function (name) {\n        return !!builders[name];\n    },\n\n    add: function (name) {\n        builders[name].call(this);\n    },\n\n    getGroup: function () {\n        return this.group;\n    }\n\n};\n\nvar builders = {\n\n    /**\n     * @private\n     */\n    axisLine: function () {\n        var opt = this.opt;\n        var axisModel = this.axisModel;\n\n        if (!axisModel.get('axisLine.show')) {\n            return;\n        }\n\n        var extent = this.axisModel.axis.getExtent();\n\n        var matrix = this._transform;\n        var pt1 = [extent[0], 0];\n        var pt2 = [extent[1], 0];\n        if (matrix) {\n            applyTransform(pt1, pt1, matrix);\n            applyTransform(pt2, pt2, matrix);\n        }\n\n        var lineStyle = extend(\n            {\n                lineCap: 'round'\n            },\n            axisModel.getModel('axisLine.lineStyle').getLineStyle()\n        );\n\n        this.group.add(new Line(subPixelOptimizeLine({\n            // Id for animation\n            anid: 'line',\n\n            shape: {\n                x1: pt1[0],\n                y1: pt1[1],\n                x2: pt2[0],\n                y2: pt2[1]\n            },\n            style: lineStyle,\n            strokeContainThreshold: opt.strokeContainThreshold || 5,\n            silent: true,\n            z2: 1\n        })));\n\n        var arrows = axisModel.get('axisLine.symbol');\n        var arrowSize = axisModel.get('axisLine.symbolSize');\n\n        var arrowOffset = axisModel.get('axisLine.symbolOffset') || 0;\n        if (typeof arrowOffset === 'number') {\n            arrowOffset = [arrowOffset, arrowOffset];\n        }\n\n        if (arrows != null) {\n            if (typeof arrows === 'string') {\n                // Use the same arrow for start and end point\n                arrows = [arrows, arrows];\n            }\n            if (typeof arrowSize === 'string'\n                || typeof arrowSize === 'number'\n            ) {\n                // Use the same size for width and height\n                arrowSize = [arrowSize, arrowSize];\n            }\n\n            var symbolWidth = arrowSize[0];\n            var symbolHeight = arrowSize[1];\n\n            each$1([{\n                rotate: opt.rotation + Math.PI / 2,\n                offset: arrowOffset[0],\n                r: 0\n            }, {\n                rotate: opt.rotation - Math.PI / 2,\n                offset: arrowOffset[1],\n                r: Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0])\n                    + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1]))\n            }], function (point, index) {\n                if (arrows[index] !== 'none' && arrows[index] != null) {\n                    var symbol = createSymbol(\n                        arrows[index],\n                        -symbolWidth / 2,\n                        -symbolHeight / 2,\n                        symbolWidth,\n                        symbolHeight,\n                        lineStyle.stroke,\n                        true\n                    );\n\n                    // Calculate arrow position with offset\n                    var r = point.r + point.offset;\n                    var pos = [\n                        pt1[0] + r * Math.cos(opt.rotation),\n                        pt1[1] - r * Math.sin(opt.rotation)\n                    ];\n\n                    symbol.attr({\n                        rotation: point.rotate,\n                        position: pos,\n                        silent: true,\n                        z2: 11\n                    });\n                    this.group.add(symbol);\n                }\n            }, this);\n        }\n    },\n\n    /**\n     * @private\n     */\n    axisTickLabel: function () {\n        var axisModel = this.axisModel;\n        var opt = this.opt;\n\n        var tickEls = buildAxisTick(this, axisModel, opt);\n        var labelEls = buildAxisLabel(this, axisModel, opt);\n\n        fixMinMaxLabelShow(axisModel, labelEls, tickEls);\n    },\n\n    /**\n     * @private\n     */\n    axisName: function () {\n        var opt = this.opt;\n        var axisModel = this.axisModel;\n        var name = retrieve(opt.axisName, axisModel.get('name'));\n\n        if (!name) {\n            return;\n        }\n\n        var nameLocation = axisModel.get('nameLocation');\n        var nameDirection = opt.nameDirection;\n        var textStyleModel = axisModel.getModel('nameTextStyle');\n        var gap = axisModel.get('nameGap') || 0;\n\n        var extent = this.axisModel.axis.getExtent();\n        var gapSignal = extent[0] > extent[1] ? -1 : 1;\n        var pos = [\n            nameLocation === 'start'\n                ? extent[0] - gapSignal * gap\n                : nameLocation === 'end'\n                ? extent[1] + gapSignal * gap\n                : (extent[0] + extent[1]) / 2, // 'middle'\n            // Reuse labelOffset.\n            isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * gap : 0\n        ];\n\n        var labelLayout;\n\n        var nameRotation = axisModel.get('nameRotate');\n        if (nameRotation != null) {\n            nameRotation = nameRotation * PI$2 / 180; // To radian.\n        }\n\n        var axisNameAvailableWidth;\n\n        if (isNameLocationCenter(nameLocation)) {\n            labelLayout = innerTextLayout(\n                opt.rotation,\n                nameRotation != null ? nameRotation : opt.rotation, // Adapt to axis.\n                nameDirection\n            );\n        }\n        else {\n            labelLayout = endTextLayout(\n                opt, nameLocation, nameRotation || 0, extent\n            );\n\n            axisNameAvailableWidth = opt.axisNameAvailableWidth;\n            if (axisNameAvailableWidth != null) {\n                axisNameAvailableWidth = Math.abs(\n                    axisNameAvailableWidth / Math.sin(labelLayout.rotation)\n                );\n                !isFinite(axisNameAvailableWidth) && (axisNameAvailableWidth = null);\n            }\n        }\n\n        var textFont = textStyleModel.getFont();\n\n        var truncateOpt = axisModel.get('nameTruncate', true) || {};\n        var ellipsis = truncateOpt.ellipsis;\n        var maxWidth = retrieve(\n            opt.nameTruncateMaxWidth, truncateOpt.maxWidth, axisNameAvailableWidth\n        );\n        // FIXME\n        // truncate rich text? (consider performance)\n        var truncatedText = (ellipsis != null && maxWidth != null)\n            ? truncateText$1(\n                name, maxWidth, textFont, ellipsis,\n                {minChar: 2, placeholder: truncateOpt.placeholder}\n            )\n            : name;\n\n        var tooltipOpt = axisModel.get('tooltip', true);\n\n        var mainType = axisModel.mainType;\n        var formatterParams = {\n            componentType: mainType,\n            name: name,\n            $vars: ['name']\n        };\n        formatterParams[mainType + 'Index'] = axisModel.componentIndex;\n\n        var textEl = new Text({\n            // Id for animation\n            anid: 'name',\n\n            __fullText: name,\n            __truncatedText: truncatedText,\n\n            position: pos,\n            rotation: labelLayout.rotation,\n            silent: isSilent(axisModel),\n            z2: 1,\n            tooltip: (tooltipOpt && tooltipOpt.show)\n                ? extend({\n                    content: name,\n                    formatter: function () {\n                        return name;\n                    },\n                    formatterParams: formatterParams\n                }, tooltipOpt)\n                : null\n        });\n\n        setTextStyle(textEl.style, textStyleModel, {\n            text: truncatedText,\n            textFont: textFont,\n            textFill: textStyleModel.getTextColor()\n                || axisModel.get('axisLine.lineStyle.color'),\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.textVerticalAlign\n        });\n\n        if (axisModel.get('triggerEvent')) {\n            textEl.eventData = makeAxisEventDataBase(axisModel);\n            textEl.eventData.targetType = 'axisName';\n            textEl.eventData.name = name;\n        }\n\n        // FIXME\n        this._dumbGroup.add(textEl);\n        textEl.updateTransform();\n\n        this.group.add(textEl);\n\n        textEl.decomposeTransform();\n    }\n\n};\n\n/**\n * @public\n * @static\n * @param {Object} opt\n * @param {number} axisRotation in radian\n * @param {number} textRotation in radian\n * @param {number} direction\n * @return {Object} {\n *  rotation, // according to axis\n *  textAlign,\n *  textVerticalAlign\n * }\n */\nvar innerTextLayout = AxisBuilder.innerTextLayout = function (axisRotation, textRotation, direction) {\n    var rotationDiff = remRadian(textRotation - axisRotation);\n    var textAlign;\n    var textVerticalAlign;\n\n    if (isRadianAroundZero(rotationDiff)) { // Label is parallel with axis line.\n        textVerticalAlign = direction > 0 ? 'top' : 'bottom';\n        textAlign = 'center';\n    }\n    else if (isRadianAroundZero(rotationDiff - PI$2)) { // Label is inverse parallel with axis line.\n        textVerticalAlign = direction > 0 ? 'bottom' : 'top';\n        textAlign = 'center';\n    }\n    else {\n        textVerticalAlign = 'middle';\n\n        if (rotationDiff > 0 && rotationDiff < PI$2) {\n            textAlign = direction > 0 ? 'right' : 'left';\n        }\n        else {\n            textAlign = direction > 0 ? 'left' : 'right';\n        }\n    }\n\n    return {\n        rotation: rotationDiff,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n};\n\nfunction endTextLayout(opt, textPosition, textRotate, extent) {\n    var rotationDiff = remRadian(textRotate - opt.rotation);\n    var textAlign;\n    var textVerticalAlign;\n    var inverse = extent[0] > extent[1];\n    var onLeft = (textPosition === 'start' && !inverse)\n        || (textPosition !== 'start' && inverse);\n\n    if (isRadianAroundZero(rotationDiff - PI$2 / 2)) {\n        textVerticalAlign = onLeft ? 'bottom' : 'top';\n        textAlign = 'center';\n    }\n    else if (isRadianAroundZero(rotationDiff - PI$2 * 1.5)) {\n        textVerticalAlign = onLeft ? 'top' : 'bottom';\n        textAlign = 'center';\n    }\n    else {\n        textVerticalAlign = 'middle';\n        if (rotationDiff < PI$2 * 1.5 && rotationDiff > PI$2 / 2) {\n            textAlign = onLeft ? 'left' : 'right';\n        }\n        else {\n            textAlign = onLeft ? 'right' : 'left';\n        }\n    }\n\n    return {\n        rotation: rotationDiff,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\nfunction isSilent(axisModel) {\n    var tooltipOpt = axisModel.get('tooltip');\n    return axisModel.get('silent')\n        // Consider mouse cursor, add these restrictions.\n        || !(\n            axisModel.get('triggerEvent') || (tooltipOpt && tooltipOpt.show)\n        );\n}\n\nfunction fixMinMaxLabelShow(axisModel, labelEls, tickEls) {\n    if (shouldShowAllLabels(axisModel.axis)) {\n        return;\n    }\n\n    // If min or max are user set, we need to check\n    // If the tick on min(max) are overlap on their neighbour tick\n    // If they are overlapped, we need to hide the min(max) tick label\n    var showMinLabel = axisModel.get('axisLabel.showMinLabel');\n    var showMaxLabel = axisModel.get('axisLabel.showMaxLabel');\n\n    // FIXME\n    // Have not consider onBand yet, where tick els is more than label els.\n\n    labelEls = labelEls || [];\n    tickEls = tickEls || [];\n\n    var firstLabel = labelEls[0];\n    var nextLabel = labelEls[1];\n    var lastLabel = labelEls[labelEls.length - 1];\n    var prevLabel = labelEls[labelEls.length - 2];\n\n    var firstTick = tickEls[0];\n    var nextTick = tickEls[1];\n    var lastTick = tickEls[tickEls.length - 1];\n    var prevTick = tickEls[tickEls.length - 2];\n\n    if (showMinLabel === false) {\n        ignoreEl(firstLabel);\n        ignoreEl(firstTick);\n    }\n    else if (isTwoLabelOverlapped(firstLabel, nextLabel)) {\n        if (showMinLabel) {\n            ignoreEl(nextLabel);\n            ignoreEl(nextTick);\n        }\n        else {\n            ignoreEl(firstLabel);\n            ignoreEl(firstTick);\n        }\n    }\n\n    if (showMaxLabel === false) {\n        ignoreEl(lastLabel);\n        ignoreEl(lastTick);\n    }\n    else if (isTwoLabelOverlapped(prevLabel, lastLabel)) {\n        if (showMaxLabel) {\n            ignoreEl(prevLabel);\n            ignoreEl(prevTick);\n        }\n        else {\n            ignoreEl(lastLabel);\n            ignoreEl(lastTick);\n        }\n    }\n}\n\nfunction ignoreEl(el) {\n    el && (el.ignore = true);\n}\n\nfunction isTwoLabelOverlapped(current, next, labelLayout) {\n    // current and next has the same rotation.\n    var firstRect = current && current.getBoundingRect().clone();\n    var nextRect = next && next.getBoundingRect().clone();\n\n    if (!firstRect || !nextRect) {\n        return;\n    }\n\n    // When checking intersect of two rotated labels, we use mRotationBack\n    // to avoid that boundingRect is enlarge when using `boundingRect.applyTransform`.\n    var mRotationBack = identity([]);\n    rotate(mRotationBack, mRotationBack, -current.rotation);\n\n    firstRect.applyTransform(mul$1([], mRotationBack, current.getLocalTransform()));\n    nextRect.applyTransform(mul$1([], mRotationBack, next.getLocalTransform()));\n\n    return firstRect.intersect(nextRect);\n}\n\nfunction isNameLocationCenter(nameLocation) {\n    return nameLocation === 'middle' || nameLocation === 'center';\n}\n\nfunction buildAxisTick(axisBuilder, axisModel, opt) {\n    var axis = axisModel.axis;\n\n    if (!axisModel.get('axisTick.show') || axis.scale.isBlank()) {\n        return;\n    }\n\n    var tickModel = axisModel.getModel('axisTick');\n\n    var lineStyleModel = tickModel.getModel('lineStyle');\n    var tickLen = tickModel.get('length');\n\n    var ticksCoords = axis.getTicksCoords();\n\n    var pt1 = [];\n    var pt2 = [];\n    var matrix = axisBuilder._transform;\n\n    var tickEls = [];\n\n    for (var i = 0; i < ticksCoords.length; i++) {\n        var tickCoord = ticksCoords[i].coord;\n\n        pt1[0] = tickCoord;\n        pt1[1] = 0;\n        pt2[0] = tickCoord;\n        pt2[1] = opt.tickDirection * tickLen;\n\n        if (matrix) {\n            applyTransform(pt1, pt1, matrix);\n            applyTransform(pt2, pt2, matrix);\n        }\n        // Tick line, Not use group transform to have better line draw\n        var tickEl = new Line(subPixelOptimizeLine({\n            // Id for animation\n            anid: 'tick_' + ticksCoords[i].tickValue,\n\n            shape: {\n                x1: pt1[0],\n                y1: pt1[1],\n                x2: pt2[0],\n                y2: pt2[1]\n            },\n            style: defaults(\n                lineStyleModel.getLineStyle(),\n                {\n                    stroke: axisModel.get('axisLine.lineStyle.color')\n                }\n            ),\n            z2: 2,\n            silent: true\n        }));\n        axisBuilder.group.add(tickEl);\n        tickEls.push(tickEl);\n    }\n\n    return tickEls;\n}\n\nfunction buildAxisLabel(axisBuilder, axisModel, opt) {\n    var axis = axisModel.axis;\n    var show = retrieve(opt.axisLabelShow, axisModel.get('axisLabel.show'));\n\n    if (!show || axis.scale.isBlank()) {\n        return;\n    }\n\n    var labelModel = axisModel.getModel('axisLabel');\n    var labelMargin = labelModel.get('margin');\n    var labels = axis.getViewLabels();\n\n    // Special label rotate.\n    var labelRotation = (\n        retrieve(opt.labelRotate, labelModel.get('rotate')) || 0\n    ) * PI$2 / 180;\n\n    var labelLayout = innerTextLayout(opt.rotation, labelRotation, opt.labelDirection);\n    var rawCategoryData = axisModel.getCategories(true);\n\n    var labelEls = [];\n    var silent = isSilent(axisModel);\n    var triggerEvent = axisModel.get('triggerEvent');\n\n    each$1(labels, function (labelItem, index) {\n        var tickValue = labelItem.tickValue;\n        var formattedLabel = labelItem.formattedLabel;\n        var rawLabel = labelItem.rawLabel;\n\n        var itemLabelModel = labelModel;\n        if (rawCategoryData && rawCategoryData[tickValue] && rawCategoryData[tickValue].textStyle) {\n            itemLabelModel = new Model(\n                rawCategoryData[tickValue].textStyle, labelModel, axisModel.ecModel\n            );\n        }\n\n        var textColor = itemLabelModel.getTextColor()\n            || axisModel.get('axisLine.lineStyle.color');\n\n        var tickCoord = axis.dataToCoord(tickValue);\n        var pos = [\n            tickCoord,\n            opt.labelOffset + opt.labelDirection * labelMargin\n        ];\n\n        var textEl = new Text({\n            // Id for animation\n            anid: 'label_' + tickValue,\n            position: pos,\n            rotation: labelLayout.rotation,\n            silent: silent,\n            z2: 10\n        });\n\n        setTextStyle(textEl.style, itemLabelModel, {\n            text: formattedLabel,\n            textAlign: itemLabelModel.getShallow('align', true)\n                || labelLayout.textAlign,\n            textVerticalAlign: itemLabelModel.getShallow('verticalAlign', true)\n                || itemLabelModel.getShallow('baseline', true)\n                || labelLayout.textVerticalAlign,\n            textFill: typeof textColor === 'function'\n                ? textColor(\n                    // (1) In category axis with data zoom, tick is not the original\n                    // index of axis.data. So tick should not be exposed to user\n                    // in category axis.\n                    // (2) Compatible with previous version, which always use formatted label as\n                    // input. But in interval scale the formatted label is like '223,445', which\n                    // maked user repalce ','. So we modify it to return original val but remain\n                    // it as 'string' to avoid error in replacing.\n                    axis.type === 'category'\n                        ? rawLabel\n                        : axis.type === 'value'\n                        ? tickValue + ''\n                        : tickValue,\n                    index\n                )\n                : textColor\n        });\n\n        // Pack data for mouse event\n        if (triggerEvent) {\n            textEl.eventData = makeAxisEventDataBase(axisModel);\n            textEl.eventData.targetType = 'axisLabel';\n            textEl.eventData.value = rawLabel;\n        }\n\n        // FIXME\n        axisBuilder._dumbGroup.add(textEl);\n        textEl.updateTransform();\n\n        labelEls.push(textEl);\n        axisBuilder.group.add(textEl);\n\n        textEl.decomposeTransform();\n\n    });\n\n    return labelEls;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Build axisPointerModel, mergin tooltip.axisPointer model for each axis.\n// allAxesInfo should be updated when setOption performed.\n\n\nfunction fixValue(axisModel) {\n    var axisInfo = getAxisInfo(axisModel);\n    if (!axisInfo) {\n        return;\n    }\n\n    var axisPointerModel = axisInfo.axisPointerModel;\n    var scale = axisInfo.axis.scale;\n    var option = axisPointerModel.option;\n    var status = axisPointerModel.get('status');\n    var value = axisPointerModel.get('value');\n\n    // Parse init value for category and time axis.\n    if (value != null) {\n        value = scale.parse(value);\n    }\n\n    var useHandle = isHandleTrigger(axisPointerModel);\n    // If `handle` used, `axisPointer` will always be displayed, so value\n    // and status should be initialized.\n    if (status == null) {\n        option.status = useHandle ? 'show' : 'hide';\n    }\n\n    var extent = scale.getExtent().slice();\n    extent[0] > extent[1] && extent.reverse();\n\n    if (// Pick a value on axis when initializing.\n        value == null\n        // If both `handle` and `dataZoom` are used, value may be out of axis extent,\n        // where we should re-pick a value to keep `handle` displaying normally.\n        || value > extent[1]\n    ) {\n        // Make handle displayed on the end of the axis when init, which looks better.\n        value = extent[1];\n    }\n    if (value < extent[0]) {\n        value = extent[0];\n    }\n\n    option.value = value;\n\n    if (useHandle) {\n        option.status = axisInfo.axis.scale.isBlank() ? 'hide' : 'show';\n    }\n}\n\nfunction getAxisInfo(axisModel) {\n    var coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') || {}).coordSysAxesInfo;\n    return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)];\n}\n\nfunction getAxisPointerModel(axisModel) {\n    var axisInfo = getAxisInfo(axisModel);\n    return axisInfo && axisInfo.axisPointerModel;\n}\n\nfunction isHandleTrigger(axisPointerModel) {\n    return !!axisPointerModel.get('handle.show');\n}\n\n/**\n * @param {module:echarts/model/Model} model\n * @return {string} unique key\n */\nfunction makeKey(model) {\n    return model.type + '||' + model.id;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Base class of AxisView.\n */\nvar AxisView = extendComponentView({\n\n    type: 'axis',\n\n    /**\n     * @private\n     */\n    _axisPointer: null,\n\n    /**\n     * @protected\n     * @type {string}\n     */\n    axisPointerClass: null,\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n        // FIXME\n        // This process should proformed after coordinate systems updated\n        // (axis scale updated), and should be performed each time update.\n        // So put it here temporarily, although it is not appropriate to\n        // put a model-writing procedure in `view`.\n        this.axisPointerClass && fixValue(axisModel);\n\n        AxisView.superApply(this, 'render', arguments);\n\n        updateAxisPointer(this, axisModel, ecModel, api, payload, true);\n    },\n\n    /**\n     * Action handler.\n     * @public\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/model/Global} ecModel\n     * @param {module:echarts/ExtensionAPI} api\n     * @param {Object} payload\n     */\n    updateAxisPointer: function (axisModel, ecModel, api, payload, force) {\n        updateAxisPointer(this, axisModel, ecModel, api, payload, false);\n    },\n\n    /**\n     * @override\n     */\n    remove: function (ecModel, api) {\n        var axisPointer = this._axisPointer;\n        axisPointer && axisPointer.remove(api);\n        AxisView.superApply(this, 'remove', arguments);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function (ecModel, api) {\n        disposeAxisPointer(this, api);\n        AxisView.superApply(this, 'dispose', arguments);\n    }\n\n});\n\nfunction updateAxisPointer(axisView, axisModel, ecModel, api, payload, forceRender) {\n    var Clazz = AxisView.getAxisPointerClass(axisView.axisPointerClass);\n    if (!Clazz) {\n        return;\n    }\n    var axisPointerModel = getAxisPointerModel(axisModel);\n    axisPointerModel\n        ? (axisView._axisPointer || (axisView._axisPointer = new Clazz()))\n            .render(axisModel, axisPointerModel, api, forceRender)\n        : disposeAxisPointer(axisView, api);\n}\n\nfunction disposeAxisPointer(axisView, ecModel, api) {\n    var axisPointer = axisView._axisPointer;\n    axisPointer && axisPointer.dispose(ecModel, api);\n    axisView._axisPointer = null;\n}\n\nvar axisPointerClazz = [];\n\nAxisView.registerAxisPointerClass = function (type, clazz) {\n    if (__DEV__) {\n        if (axisPointerClazz[type]) {\n            throw new Error('axisPointer ' + type + ' exists');\n        }\n    }\n    axisPointerClazz[type] = clazz;\n};\n\nAxisView.getAxisPointerClass = function (type) {\n    return type && axisPointerClazz[type];\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Can only be called after coordinate system creation stage.\n * (Can be called before coordinate system update stage).\n *\n * @param {Object} opt {labelInside}\n * @return {Object} {\n *  position, rotation, labelDirection, labelOffset,\n *  tickDirection, labelRotate, z2\n * }\n */\nfunction layout$1(gridModel, axisModel, opt) {\n    opt = opt || {};\n    var grid = gridModel.coordinateSystem;\n    var axis = axisModel.axis;\n    var layout = {};\n    var otherAxisOnZeroOf = axis.getAxesOnZeroOf()[0];\n\n    var rawAxisPosition = axis.position;\n    var axisPosition = otherAxisOnZeroOf ? 'onZero' : rawAxisPosition;\n    var axisDim = axis.dim;\n\n    var rect = grid.getRect();\n    var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];\n    var idx = {left: 0, right: 1, top: 0, bottom: 1, onZero: 2};\n    var axisOffset = axisModel.get('offset') || 0;\n\n    var posBound = axisDim === 'x'\n        ? [rectBound[2] - axisOffset, rectBound[3] + axisOffset]\n        : [rectBound[0] - axisOffset, rectBound[1] + axisOffset];\n\n    if (otherAxisOnZeroOf) {\n        var onZeroCoord = otherAxisOnZeroOf.toGlobalCoord(otherAxisOnZeroOf.dataToCoord(0));\n        posBound[idx.onZero] = Math.max(Math.min(onZeroCoord, posBound[1]), posBound[0]);\n    }\n\n    // Axis position\n    layout.position = [\n        axisDim === 'y' ? posBound[idx[axisPosition]] : rectBound[0],\n        axisDim === 'x' ? posBound[idx[axisPosition]] : rectBound[3]\n    ];\n\n    // Axis rotation\n    layout.rotation = Math.PI / 2 * (axisDim === 'x' ? 0 : 1);\n\n    // Tick and label direction, x y is axisDim\n    var dirMap = {top: -1, bottom: 1, left: -1, right: 1};\n\n    layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition];\n    layout.labelOffset = otherAxisOnZeroOf ? posBound[idx[rawAxisPosition]] - posBound[idx.onZero] : 0;\n\n    if (axisModel.get('axisTick.inside')) {\n        layout.tickDirection = -layout.tickDirection;\n    }\n    if (retrieve(opt.labelInside, axisModel.get('axisLabel.inside'))) {\n        layout.labelDirection = -layout.labelDirection;\n    }\n\n    // Special label rotation\n    var labelRotate = axisModel.get('axisLabel.rotate');\n    layout.labelRotate = axisPosition === 'top' ? -labelRotate : labelRotate;\n\n    // Over splitLine and splitArea\n    layout.z2 = 1;\n\n    return layout;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar axisBuilderAttrs = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\nvar selfBuilderAttrs = [\n    'splitArea', 'splitLine'\n];\n\n// function getAlignWithLabel(model, axisModel) {\n//     var alignWithLabel = model.get('alignWithLabel');\n//     if (alignWithLabel === 'auto') {\n//         alignWithLabel = axisModel.get('axisTick.alignWithLabel');\n//     }\n//     return alignWithLabel;\n// }\n\nvar CartesianAxisView = AxisView.extend({\n\n    type: 'cartesianAxis',\n\n    axisPointerClass: 'CartesianAxisPointer',\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n\n        this.group.removeAll();\n\n        var oldAxisGroup = this._axisGroup;\n        this._axisGroup = new Group();\n\n        this.group.add(this._axisGroup);\n\n        if (!axisModel.get('show')) {\n            return;\n        }\n\n        var gridModel = axisModel.getCoordSysModel();\n\n        var layout = layout$1(gridModel, axisModel);\n\n        var axisBuilder = new AxisBuilder(axisModel, layout);\n\n        each$1(axisBuilderAttrs, axisBuilder.add, axisBuilder);\n\n        this._axisGroup.add(axisBuilder.getGroup());\n\n        each$1(selfBuilderAttrs, function (name) {\n            if (axisModel.get(name + '.show')) {\n                this['_' + name](axisModel, gridModel);\n            }\n        }, this);\n\n        groupTransition(oldAxisGroup, this._axisGroup, axisModel);\n\n        CartesianAxisView.superCall(this, 'render', axisModel, ecModel, api, payload);\n    },\n\n    remove: function () {\n        this._splitAreaColors = null;\n    },\n\n    /**\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/coord/cartesian/GridModel} gridModel\n     * @private\n     */\n    _splitLine: function (axisModel, gridModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitLineModel = axisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineColors = lineStyleModel.get('color');\n\n        lineColors = isArray(lineColors) ? lineColors : [lineColors];\n\n        var gridRect = gridModel.coordinateSystem.getRect();\n        var isHorizontal = axis.isHorizontal();\n\n        var lineCount = 0;\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitLineModel\n        });\n\n        var p1 = [];\n        var p2 = [];\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        var lineStyle = lineStyleModel.getLineStyle();\n        for (var i = 0; i < ticksCoords.length; i++) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n\n            if (isHorizontal) {\n                p1[0] = tickCoord;\n                p1[1] = gridRect.y;\n                p2[0] = tickCoord;\n                p2[1] = gridRect.y + gridRect.height;\n            }\n            else {\n                p1[0] = gridRect.x;\n                p1[1] = tickCoord;\n                p2[0] = gridRect.x + gridRect.width;\n                p2[1] = tickCoord;\n            }\n\n            var colorIndex = (lineCount++) % lineColors.length;\n            var tickValue = ticksCoords[i].tickValue;\n            this._axisGroup.add(new Line(subPixelOptimizeLine({\n                anid: tickValue != null ? 'line_' + ticksCoords[i].tickValue : null,\n                shape: {\n                    x1: p1[0],\n                    y1: p1[1],\n                    x2: p2[0],\n                    y2: p2[1]\n                },\n                style: defaults({\n                    stroke: lineColors[colorIndex]\n                }, lineStyle),\n                silent: true\n            })));\n        }\n    },\n\n    /**\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/coord/cartesian/GridModel} gridModel\n     * @private\n     */\n    _splitArea: function (axisModel, gridModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitAreaModel = axisModel.getModel('splitArea');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n        var areaColors = areaStyleModel.get('color');\n\n        var gridRect = gridModel.coordinateSystem.getRect();\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitAreaModel,\n            clamp: true\n        });\n\n        if (!ticksCoords.length) {\n            return;\n        }\n\n        // For Making appropriate splitArea animation, the color and anid\n        // should be corresponding to previous one if possible.\n        var areaColorsLen = areaColors.length;\n        var lastSplitAreaColors = this._splitAreaColors;\n        var newSplitAreaColors = createHashMap();\n        var colorIndex = 0;\n        if (lastSplitAreaColors) {\n            for (var i = 0; i < ticksCoords.length; i++) {\n                var cIndex = lastSplitAreaColors.get(ticksCoords[i].tickValue);\n                if (cIndex != null) {\n                    colorIndex = (cIndex + (areaColorsLen - 1) * i) % areaColorsLen;\n                    break;\n                }\n            }\n        }\n\n        var prev = axis.toGlobalCoord(ticksCoords[0].coord);\n\n        var areaStyle = areaStyleModel.getAreaStyle();\n        areaColors = isArray(areaColors) ? areaColors : [areaColors];\n\n        for (var i = 1; i < ticksCoords.length; i++) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n\n            var x;\n            var y;\n            var width;\n            var height;\n            if (axis.isHorizontal()) {\n                x = prev;\n                y = gridRect.y;\n                width = tickCoord - x;\n                height = gridRect.height;\n                prev = x + width;\n            }\n            else {\n                x = gridRect.x;\n                y = prev;\n                width = gridRect.width;\n                height = tickCoord - y;\n                prev = y + height;\n            }\n\n            var tickValue = ticksCoords[i - 1].tickValue;\n            tickValue != null && newSplitAreaColors.set(tickValue, colorIndex);\n\n            this._axisGroup.add(new Rect({\n                anid: tickValue != null ? 'area_' + tickValue : null,\n                shape: {\n                    x: x,\n                    y: y,\n                    width: width,\n                    height: height\n                },\n                style: defaults({\n                    fill: areaColors[colorIndex]\n                }, areaStyle),\n                silent: true\n            }));\n\n            colorIndex = (colorIndex + 1) % areaColorsLen;\n        }\n\n        this._splitAreaColors = newSplitAreaColors;\n    }\n});\n\nCartesianAxisView.extend({\n    type: 'xAxis'\n});\nCartesianAxisView.extend({\n    type: 'yAxis'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Grid view\nextendComponentView({\n\n    type: 'grid',\n\n    render: function (gridModel, ecModel) {\n        this.group.removeAll();\n        if (gridModel.get('show')) {\n            this.group.add(new Rect({\n                shape: gridModel.coordinateSystem.getRect(),\n                style: defaults({\n                    fill: gridModel.get('backgroundColor')\n                }, gridModel.getItemStyle()),\n                silent: true,\n                z2: -1\n            }));\n        }\n    }\n\n});\n\nregisterPreprocessor(function (option) {\n    // Only create grid when need\n    if (option.xAxis && option.yAxis && !option.grid) {\n        option.grid = {};\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterVisual(visualSymbol('line', 'circle', 'line'));\nregisterLayout(layoutPoints('line'));\n\n// Down sample after filter\nregisterProcessor(\n    PRIORITY.PROCESSOR.STATISTIC,\n    dataSample('line')\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BaseBarSeries = SeriesModel.extend({\n\n    type: 'series.__base_bar__',\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    getMarkerPosition: function (value) {\n        var coordSys = this.coordinateSystem;\n        if (coordSys) {\n            // PENDING if clamp ?\n            var pt = coordSys.dataToPoint(coordSys.clampData(value));\n            var data = this.getData();\n            var offset = data.getLayout('offset');\n            var size = data.getLayout('size');\n            var offsetIndex = coordSys.getBaseAxis().isHorizontal() ? 0 : 1;\n            pt[offsetIndex] += offset + size / 2;\n            return pt;\n        }\n        return [NaN, NaN];\n    },\n\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n        // stack: null\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // 最小高度改为0\n        barMinHeight: 0,\n        // 最小角度为0，仅对极坐标系下的柱状图有效\n        barMinAngle: 0,\n        // cursor: null,\n\n        large: false,\n        largeThreshold: 400,\n        progressive: 3e3,\n        progressiveChunkMode: 'mod',\n\n        // barMaxWidth: null,\n        // 默认自适应\n        // barWidth: null,\n        // 柱间距离，默认为柱形宽度的30%，可设固定值\n        // barGap: '30%',\n        // 类目间柱形距离，默认为类目间距的20%，可设固定值\n        // barCategoryGap: '20%',\n        // label: {\n        //      show: false\n        // },\n        itemStyle: {},\n        emphasis: {}\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nBaseBarSeries.extend({\n\n    type: 'series.bar',\n\n    dependencies: ['grid', 'polar'],\n\n    brushSelector: 'rect',\n\n    /**\n     * @override\n     */\n    getProgressive: function () {\n        // Do not support progressive in normal mode.\n        return this.get('large')\n            ? this.get('progressive')\n            : false;\n    },\n\n    /**\n     * @override\n     */\n    getProgressiveThreshold: function () {\n        // Do not support progressive in normal mode.\n        var progressiveThreshold = this.get('progressiveThreshold');\n        var largeThreshold = this.get('largeThreshold');\n        if (largeThreshold > progressiveThreshold) {\n            progressiveThreshold = largeThreshold;\n        }\n        return progressiveThreshold;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction setLabel(\n    normalStyle, hoverStyle, itemModel, color, seriesModel, dataIndex, labelPositionOutside\n) {\n    var labelModel = itemModel.getModel('label');\n    var hoverLabelModel = itemModel.getModel('emphasis.label');\n\n    setLabelStyle(\n        normalStyle, hoverStyle, labelModel, hoverLabelModel,\n        {\n            labelFetcher: seriesModel,\n            labelDataIndex: dataIndex,\n            defaultText: getDefaultLabel(seriesModel.getData(), dataIndex),\n            isRectText: true,\n            autoColor: color\n        }\n    );\n\n    fixPosition(normalStyle);\n    fixPosition(hoverStyle);\n}\n\nfunction fixPosition(style, labelPositionOutside) {\n    if (style.textPosition === 'outside') {\n        style.textPosition = labelPositionOutside;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getBarItemStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['stroke', 'borderColor'],\n        ['lineWidth', 'borderWidth'],\n        // Compatitable with 2\n        ['stroke', 'barBorderColor'],\n        ['lineWidth', 'barBorderWidth'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor']\n    ]\n);\n\nvar barItemStyle = {\n    getBarItemStyle: function (excludes) {\n        var style = getBarItemStyle(this, excludes);\n        if (this.getBorderLineDash) {\n            var lineDash = this.getBorderLineDash();\n            lineDash && (style.lineDash = lineDash);\n        }\n        return style;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'barBorderWidth'];\n\n// FIXME\n// Just for compatible with ec2.\nextend(Model.prototype, barItemStyle);\n\nextendChartView({\n\n    type: 'bar',\n\n    render: function (seriesModel, ecModel, api) {\n        this._updateDrawMode(seriesModel);\n\n        var coordinateSystemType = seriesModel.get('coordinateSystem');\n\n        if (coordinateSystemType === 'cartesian2d'\n            || coordinateSystemType === 'polar'\n        ) {\n            this._isLargeDraw\n                ? this._renderLarge(seriesModel, ecModel, api)\n                : this._renderNormal(seriesModel, ecModel, api);\n        }\n        else if (__DEV__) {\n            console.warn('Only cartesian2d and polar supported for bar.');\n        }\n\n        return this.group;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this._clear();\n        this._updateDrawMode(seriesModel);\n    },\n\n    incrementalRender: function (params, seriesModel, ecModel, api) {\n        // Do not support progressive in normal mode.\n        this._incrementalRenderLarge(params, seriesModel);\n    },\n\n    _updateDrawMode: function (seriesModel) {\n        var isLargeDraw = seriesModel.pipelineContext.large;\n        if (this._isLargeDraw == null || isLargeDraw ^ this._isLargeDraw) {\n            this._isLargeDraw = isLargeDraw;\n            this._clear();\n        }\n    },\n\n    _renderNormal: function (seriesModel, ecModel, api) {\n        var group = this.group;\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        var coord = seriesModel.coordinateSystem;\n        var baseAxis = coord.getBaseAxis();\n        var isHorizontalOrRadial;\n\n        if (coord.type === 'cartesian2d') {\n            isHorizontalOrRadial = baseAxis.isHorizontal();\n        }\n        else if (coord.type === 'polar') {\n            isHorizontalOrRadial = baseAxis.dim === 'angle';\n        }\n\n        var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null;\n\n        data.diff(oldData)\n            .add(function (dataIndex) {\n                if (!data.hasValue(dataIndex)) {\n                    return;\n                }\n\n                var itemModel = data.getItemModel(dataIndex);\n                var layout = getLayout[coord.type](data, dataIndex, itemModel);\n                var el = elementCreator[coord.type](\n                    data, dataIndex, itemModel, layout, isHorizontalOrRadial, animationModel\n                );\n                data.setItemGraphicEl(dataIndex, el);\n                group.add(el);\n\n                updateStyle(\n                    el, data, dataIndex, itemModel, layout,\n                    seriesModel, isHorizontalOrRadial, coord.type === 'polar'\n                );\n            })\n            .update(function (newIndex, oldIndex) {\n                var el = oldData.getItemGraphicEl(oldIndex);\n\n                if (!data.hasValue(newIndex)) {\n                    group.remove(el);\n                    return;\n                }\n\n                var itemModel = data.getItemModel(newIndex);\n                var layout = getLayout[coord.type](data, newIndex, itemModel);\n\n                if (el) {\n                    updateProps(el, {shape: layout}, animationModel, newIndex);\n                }\n                else {\n                    el = elementCreator[coord.type](\n                        data, newIndex, itemModel, layout, isHorizontalOrRadial, animationModel, true\n                    );\n                }\n\n                data.setItemGraphicEl(newIndex, el);\n                // Add back\n                group.add(el);\n\n                updateStyle(\n                    el, data, newIndex, itemModel, layout,\n                    seriesModel, isHorizontalOrRadial, coord.type === 'polar'\n                );\n            })\n            .remove(function (dataIndex) {\n                var el = oldData.getItemGraphicEl(dataIndex);\n                if (coord.type === 'cartesian2d') {\n                    el && removeRect(dataIndex, animationModel, el);\n                }\n                else {\n                    el && removeSector(dataIndex, animationModel, el);\n                }\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    _renderLarge: function (seriesModel, ecModel, api) {\n        this._clear();\n        createLarge(seriesModel, this.group);\n    },\n\n    _incrementalRenderLarge: function (params, seriesModel) {\n        createLarge(seriesModel, this.group, true);\n    },\n\n    dispose: noop,\n\n    remove: function (ecModel) {\n        this._clear(ecModel);\n    },\n\n    _clear: function (ecModel) {\n        var group = this.group;\n        var data = this._data;\n        if (ecModel && ecModel.get('animation') && data && !this._isLargeDraw) {\n            data.eachItemGraphicEl(function (el) {\n                if (el.type === 'sector') {\n                    removeSector(el.dataIndex, ecModel, el);\n                }\n                else {\n                    removeRect(el.dataIndex, ecModel, el);\n                }\n            });\n        }\n        else {\n            group.removeAll();\n        }\n        this._data = null;\n    }\n\n});\n\nvar elementCreator = {\n\n    cartesian2d: function (\n        data, dataIndex, itemModel, layout, isHorizontal,\n        animationModel, isUpdate\n    ) {\n        var rect = new Rect({shape: extend({}, layout)});\n\n        // Animation\n        if (animationModel) {\n            var rectShape = rect.shape;\n            var animateProperty = isHorizontal ? 'height' : 'width';\n            var animateTarget = {};\n            rectShape[animateProperty] = 0;\n            animateTarget[animateProperty] = layout[animateProperty];\n            graphic[isUpdate ? 'updateProps' : 'initProps'](rect, {\n                shape: animateTarget\n            }, animationModel, dataIndex);\n        }\n\n        return rect;\n    },\n\n    polar: function (\n        data, dataIndex, itemModel, layout, isRadial,\n        animationModel, isUpdate\n    ) {\n        // Keep the same logic with bar in catesion: use end value to control\n        // direction. Notice that if clockwise is true (by default), the sector\n        // will always draw clockwisely, no matter whether endAngle is greater\n        // or less than startAngle.\n        var clockwise = layout.startAngle < layout.endAngle;\n        var sector = new Sector({\n            shape: defaults({clockwise: clockwise}, layout)\n        });\n\n        // Animation\n        if (animationModel) {\n            var sectorShape = sector.shape;\n            var animateProperty = isRadial ? 'r' : 'endAngle';\n            var animateTarget = {};\n            sectorShape[animateProperty] = isRadial ? 0 : layout.startAngle;\n            animateTarget[animateProperty] = layout[animateProperty];\n            graphic[isUpdate ? 'updateProps' : 'initProps'](sector, {\n                shape: animateTarget\n            }, animationModel, dataIndex);\n        }\n\n        return sector;\n    }\n};\n\nfunction removeRect(dataIndex, animationModel, el) {\n    // Not show text when animating\n    el.style.text = null;\n    updateProps(el, {\n        shape: {\n            width: 0\n        }\n    }, animationModel, dataIndex, function () {\n        el.parent && el.parent.remove(el);\n    });\n}\n\nfunction removeSector(dataIndex, animationModel, el) {\n    // Not show text when animating\n    el.style.text = null;\n    updateProps(el, {\n        shape: {\n            r: el.shape.r0\n        }\n    }, animationModel, dataIndex, function () {\n        el.parent && el.parent.remove(el);\n    });\n}\n\nvar getLayout = {\n    cartesian2d: function (data, dataIndex, itemModel) {\n        var layout = data.getItemLayout(dataIndex);\n        var fixedLineWidth = getLineWidth(itemModel, layout);\n\n        // fix layout with lineWidth\n        var signX = layout.width > 0 ? 1 : -1;\n        var signY = layout.height > 0 ? 1 : -1;\n        return {\n            x: layout.x + signX * fixedLineWidth / 2,\n            y: layout.y + signY * fixedLineWidth / 2,\n            width: layout.width - signX * fixedLineWidth,\n            height: layout.height - signY * fixedLineWidth\n        };\n    },\n\n    polar: function (data, dataIndex, itemModel) {\n        var layout = data.getItemLayout(dataIndex);\n        return {\n            cx: layout.cx,\n            cy: layout.cy,\n            r0: layout.r0,\n            r: layout.r,\n            startAngle: layout.startAngle,\n            endAngle: layout.endAngle\n        };\n    }\n};\n\nfunction updateStyle(\n    el, data, dataIndex, itemModel, layout, seriesModel, isHorizontal, isPolar\n) {\n    var color = data.getItemVisual(dataIndex, 'color');\n    var opacity = data.getItemVisual(dataIndex, 'opacity');\n    var itemStyleModel = itemModel.getModel('itemStyle');\n    var hoverStyle = itemModel.getModel('emphasis.itemStyle').getBarItemStyle();\n\n    if (!isPolar) {\n        el.setShape('r', itemStyleModel.get('barBorderRadius') || 0);\n    }\n\n    el.useStyle(defaults(\n        {\n            fill: color,\n            opacity: opacity\n        },\n        itemStyleModel.getBarItemStyle()\n    ));\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && el.attr('cursor', cursorStyle);\n\n    var labelPositionOutside = isHorizontal\n        ? (layout.height > 0 ? 'bottom' : 'top')\n        : (layout.width > 0 ? 'left' : 'right');\n\n    if (!isPolar) {\n        setLabel(\n            el.style, hoverStyle, itemModel, color,\n            seriesModel, dataIndex, labelPositionOutside\n        );\n    }\n\n    setHoverStyle(el, hoverStyle);\n}\n\n// In case width or height are too small.\nfunction getLineWidth(itemModel, rawLayout) {\n    var lineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY) || 0;\n    return Math.min(lineWidth, Math.abs(rawLayout.width), Math.abs(rawLayout.height));\n}\n\n\nvar LargePath = Path.extend({\n\n    type: 'largeBar',\n\n    shape: {points: []},\n\n    buildPath: function (ctx, shape) {\n        // Drawing lines is more efficient than drawing\n        // a whole line or drawing rects.\n        var points = shape.points;\n        var startPoint = this.__startPoint;\n        var valueIdx = this.__valueIdx;\n\n        for (var i = 0; i < points.length; i += 2) {\n            startPoint[this.__valueIdx] = points[i + valueIdx];\n            ctx.moveTo(startPoint[0], startPoint[1]);\n            ctx.lineTo(points[i], points[i + 1]);\n        }\n    }\n});\n\nfunction createLarge(seriesModel, group, incremental) {\n    // TODO support polar\n    var data = seriesModel.getData();\n    var startPoint = [];\n    var valueIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0;\n    startPoint[1 - valueIdx] = data.getLayout('valueAxisStart');\n\n    var el = new LargePath({\n        shape: {points: data.getLayout('largePoints')},\n        incremental: !!incremental,\n        __startPoint: startPoint,\n        __valueIdx: valueIdx\n    });\n    group.add(el);\n    setLargeStyle(el, seriesModel, data);\n}\n\nfunction setLargeStyle(el, seriesModel, data) {\n    var borderColor = data.getVisual('borderColor') || data.getVisual('color');\n    var itemStyle = seriesModel.getModel('itemStyle').getItemStyle(['color', 'borderColor']);\n\n    el.useStyle(itemStyle);\n    el.style.fill = null;\n    el.style.stroke = borderColor;\n    el.style.lineWidth = data.getLayout('barWidth');\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterLayout(curry(layout, 'bar'));\n// Should after normal bar layout, otherwise it is blocked by normal bar layout.\nregisterLayout(largeLayout);\n\nregisterVisual({\n    seriesType: 'bar',\n    reset: function (seriesModel) {\n        // Visual coding for legend\n        seriesModel.getData().setVisual('legendSymbol', 'roundRect');\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * [Usage]:\n * (1)\n * createListSimply(seriesModel, ['value']);\n * (2)\n * createListSimply(seriesModel, {\n *     coordDimensions: ['value'],\n *     dimensionsCount: 5\n * });\n *\n * @param {module:echarts/model/Series} seriesModel\n * @param {Object|Array.<string|Object>} opt opt or coordDimensions\n *        The options in opt, see `echarts/data/helper/createDimensions`\n * @param {Array.<string>} [nameList]\n * @return {module:echarts/data/List}\n */\nvar createListSimply = function (seriesModel, opt, nameList) {\n    opt = isArray(opt) && {coordDimensions: opt} || extend({}, opt);\n\n    var source = seriesModel.getSource();\n\n    var dimensionsInfo = createDimensions(source, opt);\n\n    var list = new List(dimensionsInfo, seriesModel);\n    list.initData(source, nameList);\n\n    return list;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Data selectable mixin for chart series.\n * To eanble data select, option of series must have `selectedMode`.\n * And each data item will use `selected` to toggle itself selected status\n */\n\nvar dataSelectableMixin = {\n\n    /**\n     * @param {Array.<Object>} targetList [{name, value, selected}, ...]\n     *        If targetList is an array, it should like [{name: ..., value: ...}, ...].\n     *        If targetList is a \"List\", it must have coordDim: 'value' dimension and name.\n     */\n    updateSelectedMap: function (targetList) {\n        this._targetList = isArray(targetList) ? targetList.slice() : [];\n\n        this._selectTargetMap = reduce(targetList || [], function (targetMap, target) {\n            targetMap.set(target.name, target);\n            return targetMap;\n        }, createHashMap());\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    // PENGING If selectedMode is null ?\n    select: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        var selectedMode = this.get('selectedMode');\n        if (selectedMode === 'single') {\n            this._selectTargetMap.each(function (target) {\n                target.selected = false;\n            });\n        }\n        target && (target.selected = true);\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    unSelect: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        // var selectedMode = this.get('selectedMode');\n        // selectedMode !== 'single' && target && (target.selected = false);\n        target && (target.selected = false);\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    toggleSelected: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        if (target != null) {\n            this[target.selected ? 'unSelect' : 'select'](name, id);\n            return target.selected;\n        }\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    isSelected: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        return target && target.selected;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PieSeries = extendSeriesModel({\n\n    type: 'series.pie',\n\n    // Overwrite\n    init: function (option) {\n        PieSeries.superApply(this, 'init', arguments);\n\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n\n        this.updateSelectedMap(this._createSelectableList());\n\n        this._defaultLabelLine(option);\n    },\n\n    // Overwrite\n    mergeOption: function (newOption) {\n        PieSeries.superCall(this, 'mergeOption', newOption);\n\n        this.updateSelectedMap(this._createSelectableList());\n    },\n\n    getInitialData: function (option, ecModel) {\n        return createListSimply(this, ['value']);\n    },\n\n    _createSelectableList: function () {\n        var data = this.getRawData();\n        var valueDim = data.mapDimension('value');\n        var targetList = [];\n        for (var i = 0, len = data.count(); i < len; i++) {\n            targetList.push({\n                name: data.getName(i),\n                value: data.get(valueDim, i),\n                selected: retrieveRawAttr(data, i, 'selected')\n            });\n        }\n        return targetList;\n    },\n\n    // Overwrite\n    getDataParams: function (dataIndex) {\n        var data = this.getData();\n        var params = PieSeries.superCall(this, 'getDataParams', dataIndex);\n        // FIXME toFixed?\n\n        var valueList = [];\n        data.each(data.mapDimension('value'), function (value) {\n            valueList.push(value);\n        });\n\n        params.percent = getPercentWithPrecision(\n            valueList,\n            dataIndex,\n            data.hostModel.get('percentPrecision')\n        );\n\n        params.$vars.push('percent');\n        return params;\n    },\n\n    _defaultLabelLine: function (option) {\n        // Extend labelLine emphasis\n        defaultEmphasis(option, 'labelLine', ['show']);\n\n        var labelLineNormalOpt = option.labelLine;\n        var labelLineEmphasisOpt = option.emphasis.labelLine;\n        // Not show label line if `label.normal.show = false`\n        labelLineNormalOpt.show = labelLineNormalOpt.show\n            && option.label.show;\n        labelLineEmphasisOpt.show = labelLineEmphasisOpt.show\n            && option.emphasis.label.show;\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // 默认全局居中\n        center: ['50%', '50%'],\n        radius: [0, '75%'],\n        // 默认顺时针\n        clockwise: true,\n        startAngle: 90,\n        // 最小角度改为0\n        minAngle: 0,\n        // 选中时扇区偏移量\n        selectedOffset: 10,\n        // 高亮扇区偏移量\n        hoverOffset: 10,\n\n        // If use strategy to avoid label overlapping\n        avoidLabelOverlap: true,\n        // 选择模式，默认关闭，可选single，multiple\n        // selectedMode: false,\n        // 南丁格尔玫瑰图模式，'radius'（半径） | 'area'（面积）\n        // roseType: null,\n\n        percentPrecision: 2,\n\n        // If still show when all data zero.\n        stillShowZeroSum: true,\n\n        // cursor: null,\n\n        label: {\n            // If rotate around circle\n            rotate: false,\n            show: true,\n            // 'outer', 'inside', 'center'\n            position: 'outer'\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n            // 默认使用全局文本样式，详见TEXTSTYLE\n            // distance: 当position为inner时有效，为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数\n        },\n        // Enabled when label.normal.position is 'outer'\n        labelLine: {\n            show: true,\n            // 引导线两段中的第一段长度\n            length: 15,\n            // 引导线两段中的第二段长度\n            length2: 15,\n            smooth: false,\n            lineStyle: {\n                // color: 各异,\n                width: 1,\n                type: 'solid'\n            }\n        },\n        itemStyle: {\n            borderWidth: 1\n        },\n\n        // Animation type canbe expansion, scale\n        animationType: 'expansion',\n\n        animationEasing: 'cubicOut'\n    }\n});\n\nmixin(PieSeries, dataSelectableMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/model/Series} seriesModel\n * @param {boolean} hasAnimation\n * @inner\n */\nfunction updateDataSelected(uid, seriesModel, hasAnimation, api) {\n    var data = seriesModel.getData();\n    var dataIndex = this.dataIndex;\n    var name = data.getName(dataIndex);\n    var selectedOffset = seriesModel.get('selectedOffset');\n\n    api.dispatchAction({\n        type: 'pieToggleSelect',\n        from: uid,\n        name: name,\n        seriesId: seriesModel.id\n    });\n\n    data.each(function (idx) {\n        toggleItemSelected(\n            data.getItemGraphicEl(idx),\n            data.getItemLayout(idx),\n            seriesModel.isSelected(data.getName(idx)),\n            selectedOffset,\n            hasAnimation\n        );\n    });\n}\n\n/**\n * @param {module:zrender/graphic/Sector} el\n * @param {Object} layout\n * @param {boolean} isSelected\n * @param {number} selectedOffset\n * @param {boolean} hasAnimation\n * @inner\n */\nfunction toggleItemSelected(el, layout, isSelected, selectedOffset, hasAnimation) {\n    var midAngle = (layout.startAngle + layout.endAngle) / 2;\n\n    var dx = Math.cos(midAngle);\n    var dy = Math.sin(midAngle);\n\n    var offset = isSelected ? selectedOffset : 0;\n    var position = [dx * offset, dy * offset];\n\n    hasAnimation\n        // animateTo will stop revious animation like update transition\n        ? el.animate()\n            .when(200, {\n                position: position\n            })\n            .start('bounceOut')\n        : el.attr('position', position);\n}\n\n/**\n * Piece of pie including Sector, Label, LabelLine\n * @constructor\n * @extends {module:zrender/graphic/Group}\n */\nfunction PiePiece(data, idx) {\n\n    Group.call(this);\n\n    var sector = new Sector({\n        z2: 2\n    });\n    var polyline = new Polyline();\n    var text = new Text();\n    this.add(sector);\n    this.add(polyline);\n    this.add(text);\n\n    this.updateData(data, idx, true);\n\n    // Hover to change label and labelLine\n    function onEmphasis() {\n        polyline.ignore = polyline.hoverIgnore;\n        text.ignore = text.hoverIgnore;\n    }\n    function onNormal() {\n        polyline.ignore = polyline.normalIgnore;\n        text.ignore = text.normalIgnore;\n    }\n    this.on('emphasis', onEmphasis)\n        .on('normal', onNormal)\n        .on('mouseover', onEmphasis)\n        .on('mouseout', onNormal);\n}\n\nvar piePieceProto = PiePiece.prototype;\n\npiePieceProto.updateData = function (data, idx, firstCreate) {\n\n    var sector = this.childAt(0);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var sectorShape = extend({}, layout);\n    sectorShape.label = null;\n\n    if (firstCreate) {\n        sector.setShape(sectorShape);\n\n        var animationType = seriesModel.getShallow('animationType');\n        if (animationType === 'scale') {\n            sector.shape.r = layout.r0;\n            initProps(sector, {\n                shape: {\n                    r: layout.r\n                }\n            }, seriesModel, idx);\n        }\n        // Expansion\n        else {\n            sector.shape.endAngle = layout.startAngle;\n            updateProps(sector, {\n                shape: {\n                    endAngle: layout.endAngle\n                }\n            }, seriesModel, idx);\n        }\n\n    }\n    else {\n        updateProps(sector, {\n            shape: sectorShape\n        }, seriesModel, idx);\n    }\n\n    // Update common style\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    sector.useStyle(\n        defaults(\n            {\n                lineJoin: 'bevel',\n                fill: visualColor\n            },\n            itemModel.getModel('itemStyle').getItemStyle()\n        )\n    );\n    sector.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && sector.attr('cursor', cursorStyle);\n\n    // Toggle selected\n    toggleItemSelected(\n        this,\n        data.getItemLayout(idx),\n        seriesModel.isSelected(null, idx),\n        seriesModel.get('selectedOffset'),\n        seriesModel.get('animation')\n    );\n\n    function onEmphasis() {\n        // Sector may has animation of updating data. Force to move to the last frame\n        // Or it may stopped on the wrong shape\n        sector.stopAnimation(true);\n        sector.animateTo({\n            shape: {\n                r: layout.r + seriesModel.get('hoverOffset')\n            }\n        }, 300, 'elasticOut');\n    }\n    function onNormal() {\n        sector.stopAnimation(true);\n        sector.animateTo({\n            shape: {\n                r: layout.r\n            }\n        }, 300, 'elasticOut');\n    }\n    sector.off('mouseover').off('mouseout').off('emphasis').off('normal');\n    if (itemModel.get('hoverAnimation') && seriesModel.isAnimationEnabled()) {\n        sector\n            .on('mouseover', onEmphasis)\n            .on('mouseout', onNormal)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal);\n    }\n\n    this._updateLabel(data, idx);\n\n    setHoverStyle(this);\n};\n\npiePieceProto._updateLabel = function (data, idx) {\n\n    var labelLine = this.childAt(1);\n    var labelText = this.childAt(2);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var labelLayout = layout.label;\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    updateProps(labelLine, {\n        shape: {\n            points: labelLayout.linePoints || [\n                [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y]\n            ]\n        }\n    }, seriesModel, idx);\n\n    updateProps(labelText, {\n        style: {\n            x: labelLayout.x,\n            y: labelLayout.y\n        }\n    }, seriesModel, idx);\n    labelText.attr({\n        rotation: labelLayout.rotation,\n        origin: [labelLayout.x, labelLayout.y],\n        z2: 10\n    });\n\n    var labelModel = itemModel.getModel('label');\n    var labelHoverModel = itemModel.getModel('emphasis.label');\n    var labelLineModel = itemModel.getModel('labelLine');\n    var labelLineHoverModel = itemModel.getModel('emphasis.labelLine');\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    setLabelStyle(\n        labelText.style, labelText.hoverStyle = {}, labelModel, labelHoverModel,\n        {\n            labelFetcher: data.hostModel,\n            labelDataIndex: idx,\n            defaultText: data.getName(idx),\n            autoColor: visualColor,\n            useInsideStyle: !!labelLayout.inside\n        },\n        {\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.verticalAlign,\n            opacity: data.getItemVisual(idx, 'opacity')\n        }\n    );\n\n    labelText.ignore = labelText.normalIgnore = !labelModel.get('show');\n    labelText.hoverIgnore = !labelHoverModel.get('show');\n\n    labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show');\n    labelLine.hoverIgnore = !labelLineHoverModel.get('show');\n\n    // Default use item visual color\n    labelLine.setStyle({\n        stroke: visualColor,\n        opacity: data.getItemVisual(idx, 'opacity')\n    });\n    labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());\n\n    labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();\n\n    var smooth = labelLineModel.get('smooth');\n    if (smooth && smooth === true) {\n        smooth = 0.4;\n    }\n    labelLine.setShape({\n        smooth: smooth\n    });\n};\n\ninherits(PiePiece, Group);\n\n\n// Pie view\nvar PieView = Chart.extend({\n\n    type: 'pie',\n\n    init: function () {\n        var sectorGroup = new Group();\n        this._sectorGroup = sectorGroup;\n    },\n\n    render: function (seriesModel, ecModel, api, payload) {\n        if (payload && (payload.from === this.uid)) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var oldData = this._data;\n        var group = this.group;\n\n        var hasAnimation = ecModel.get('animation');\n        var isFirstRender = !oldData;\n        var animationType = seriesModel.get('animationType');\n\n        var onSectorClick = curry(\n            updateDataSelected, this.uid, seriesModel, hasAnimation, api\n        );\n\n        var selectedMode = seriesModel.get('selectedMode');\n\n        data.diff(oldData)\n            .add(function (idx) {\n                var piePiece = new PiePiece(data, idx);\n                // Default expansion animation\n                if (isFirstRender && animationType !== 'scale') {\n                    piePiece.eachChild(function (child) {\n                        child.stopAnimation(true);\n                    });\n                }\n\n                selectedMode && piePiece.on('click', onSectorClick);\n\n                data.setItemGraphicEl(idx, piePiece);\n\n                group.add(piePiece);\n            })\n            .update(function (newIdx, oldIdx) {\n                var piePiece = oldData.getItemGraphicEl(oldIdx);\n\n                piePiece.updateData(data, newIdx);\n\n                piePiece.off('click');\n                selectedMode && piePiece.on('click', onSectorClick);\n                group.add(piePiece);\n                data.setItemGraphicEl(newIdx, piePiece);\n            })\n            .remove(function (idx) {\n                var piePiece = oldData.getItemGraphicEl(idx);\n                group.remove(piePiece);\n            })\n            .execute();\n\n        if (\n            hasAnimation && isFirstRender && data.count() > 0\n            // Default expansion animation\n            && animationType !== 'scale'\n        ) {\n            var shape = data.getItemLayout(0);\n            var r = Math.max(api.getWidth(), api.getHeight()) / 2;\n\n            var removeClipPath = bind(group.removeClipPath, group);\n            group.setClipPath(this._createClipPath(\n                shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel\n            ));\n        }\n        else {\n            // clipPath is used in first-time animation, so remove it when otherwise. See: #8994\n            group.removeClipPath();\n        }\n\n        this._data = data;\n    },\n\n    dispose: function () {},\n\n    _createClipPath: function (\n        cx, cy, r, startAngle, clockwise, cb, seriesModel\n    ) {\n        var clipPath = new Sector({\n            shape: {\n                cx: cx,\n                cy: cy,\n                r0: 0,\n                r: r,\n                startAngle: startAngle,\n                endAngle: startAngle,\n                clockwise: clockwise\n            }\n        });\n\n        initProps(clipPath, {\n            shape: {\n                endAngle: startAngle + (clockwise ? 1 : -1) * Math.PI * 2\n            }\n        }, seriesModel, cb);\n\n        return clipPath;\n    },\n\n    /**\n     * @implement\n     */\n    containPoint: function (point, seriesModel) {\n        var data = seriesModel.getData();\n        var itemLayout = data.getItemLayout(0);\n        if (itemLayout) {\n            var dx = point[0] - itemLayout.cx;\n            var dy = point[1] - itemLayout.cy;\n            var radius = Math.sqrt(dx * dx + dy * dy);\n            return radius <= itemLayout.r && radius >= itemLayout.r0;\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar createDataSelectAction = function (seriesType, actionInfos) {\n    each$1(actionInfos, function (actionInfo) {\n        actionInfo.update = 'updateView';\n        /**\n         * @payload\n         * @property {string} seriesName\n         * @property {string} name\n         */\n        registerAction(actionInfo, function (payload, ecModel) {\n            var selected = {};\n            ecModel.eachComponent(\n                {mainType: 'series', subType: seriesType, query: payload},\n                function (seriesModel) {\n                    if (seriesModel[actionInfo.method]) {\n                        seriesModel[actionInfo.method](\n                            payload.name,\n                            payload.dataIndex\n                        );\n                    }\n                    var data = seriesModel.getData();\n                    // Create selected map\n                    data.each(function (idx) {\n                        var name = data.getName(idx);\n                        selected[name] = seriesModel.isSelected(name)\n                            || false;\n                    });\n                }\n            );\n            return {\n                name: payload.name,\n                selected: selected\n            };\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Pick color from palette for each data item.\n// Applicable for charts that require applying color palette\n// in data level (like pie, funnel, chord).\nvar dataColor = function (seriesType) {\n    return {\n        getTargetSeries: function (ecModel) {\n            // Pie and funnel may use diferrent scope\n            var paletteScope = {};\n            var seiresModelMap = createHashMap();\n\n            ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n                seriesModel.__paletteScope = paletteScope;\n                seiresModelMap.set(seriesModel.uid, seriesModel);\n            });\n\n            return seiresModelMap;\n        },\n        reset: function (seriesModel, ecModel) {\n            var dataAll = seriesModel.getRawData();\n            var idxMap = {};\n            var data = seriesModel.getData();\n\n            data.each(function (idx) {\n                var rawIdx = data.getRawIndex(idx);\n                idxMap[rawIdx] = idx;\n            });\n\n            dataAll.each(function (rawIdx) {\n                var filteredIdx = idxMap[rawIdx];\n\n                // If series.itemStyle.normal.color is a function. itemVisual may be encoded\n                var singleDataColor = filteredIdx != null\n                    && data.getItemVisual(filteredIdx, 'color', true);\n\n                if (!singleDataColor) {\n                    // FIXME Performance\n                    var itemModel = dataAll.getItemModel(rawIdx);\n\n                    var color = itemModel.get('itemStyle.color')\n                        || seriesModel.getColorFromPalette(\n                            dataAll.getName(rawIdx) || (rawIdx + ''), seriesModel.__paletteScope,\n                            dataAll.count()\n                        );\n                    // Legend may use the visual info in data before processed\n                    dataAll.setItemVisual(rawIdx, 'color', color);\n\n                    // Data is not filtered\n                    if (filteredIdx != null) {\n                        data.setItemVisual(filteredIdx, 'color', color);\n                    }\n                }\n                else {\n                    // Set data all color for legend\n                    dataAll.setItemVisual(rawIdx, 'color', singleDataColor);\n                }\n            });\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME emphasis label position is not same with normal label position\n\nfunction adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {\n    list.sort(function (a, b) {\n        return a.y - b.y;\n    });\n\n    function shiftDown(start, end, delta, dir) {\n        for (var j = start; j < end; j++) {\n            list[j].y += delta;\n            if (j > start\n                && j + 1 < end\n                && list[j + 1].y > list[j].y + list[j].height\n            ) {\n                shiftUp(j, delta / 2);\n                return;\n            }\n        }\n\n        shiftUp(end - 1, delta / 2);\n    }\n\n    function shiftUp(end, delta) {\n        for (var j = end; j >= 0; j--) {\n            list[j].y -= delta;\n            if (j > 0\n                && list[j].y > list[j - 1].y + list[j - 1].height\n            ) {\n                break;\n            }\n        }\n    }\n\n    function changeX(list, isDownList, cx, cy, r, dir) {\n        var lastDeltaX = dir > 0\n            ? isDownList                // right-side\n                ? Number.MAX_VALUE      // down\n                : 0                     // up\n            : isDownList                // left-side\n                ? Number.MAX_VALUE      // down\n                : 0;                    // up\n\n        for (var i = 0, l = list.length; i < l; i++) {\n            var deltaY = Math.abs(list[i].y - cy);\n            var length = list[i].len;\n            var length2 = list[i].len2;\n            var deltaX = (deltaY < r + length)\n                ? Math.sqrt(\n                        (r + length + length2) * (r + length + length2)\n                        - deltaY * deltaY\n                    )\n                : Math.abs(list[i].x - cx);\n            if (isDownList && deltaX >= lastDeltaX) {\n                // right-down, left-down\n                deltaX = lastDeltaX - 10;\n            }\n            if (!isDownList && deltaX <= lastDeltaX) {\n                // right-up, left-up\n                deltaX = lastDeltaX + 10;\n            }\n\n            list[i].x = cx + deltaX * dir;\n            lastDeltaX = deltaX;\n        }\n    }\n\n    var lastY = 0;\n    var delta;\n    var len = list.length;\n    var upList = [];\n    var downList = [];\n    for (var i = 0; i < len; i++) {\n        delta = list[i].y - lastY;\n        if (delta < 0) {\n            shiftDown(i, len, -delta, dir);\n        }\n        lastY = list[i].y + list[i].height;\n    }\n    if (viewHeight - lastY < 0) {\n        shiftUp(len - 1, lastY - viewHeight);\n    }\n    for (var i = 0; i < len; i++) {\n        if (list[i].y >= cy) {\n            downList.push(list[i]);\n        }\n        else {\n            upList.push(list[i]);\n        }\n    }\n    changeX(upList, false, cx, cy, r, dir);\n    changeX(downList, true, cx, cy, r, dir);\n}\n\nfunction avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) {\n    var leftList = [];\n    var rightList = [];\n    for (var i = 0; i < labelLayoutList.length; i++) {\n        if (isPositionCenter(labelLayoutList[i])) {\n            continue;\n        }\n        if (labelLayoutList[i].x < cx) {\n            leftList.push(labelLayoutList[i]);\n        }\n        else {\n            rightList.push(labelLayoutList[i]);\n        }\n    }\n\n    adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight);\n    adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight);\n\n    for (var i = 0; i < labelLayoutList.length; i++) {\n        if (isPositionCenter(labelLayoutList[i])) {\n            continue;\n        }\n        var linePoints = labelLayoutList[i].linePoints;\n        if (linePoints) {\n            var dist = linePoints[1][0] - linePoints[2][0];\n            if (labelLayoutList[i].x < cx) {\n                linePoints[2][0] = labelLayoutList[i].x + 3;\n            }\n            else {\n                linePoints[2][0] = labelLayoutList[i].x - 3;\n            }\n            linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y;\n            linePoints[1][0] = linePoints[2][0] + dist;\n        }\n    }\n}\n\nfunction isPositionCenter(layout) {\n    // Not change x for center label\n    return layout.position === 'center';\n}\n\nvar labelLayout = function (seriesModel, r, viewWidth, viewHeight) {\n    var data = seriesModel.getData();\n    var labelLayoutList = [];\n    var cx;\n    var cy;\n    var hasLabelRotate = false;\n\n    data.each(function (idx) {\n        var layout = data.getItemLayout(idx);\n\n        var itemModel = data.getItemModel(idx);\n        var labelModel = itemModel.getModel('label');\n        // Use position in normal or emphasis\n        var labelPosition = labelModel.get('position') || itemModel.get('emphasis.label.position');\n\n        var labelLineModel = itemModel.getModel('labelLine');\n        var labelLineLen = labelLineModel.get('length');\n        var labelLineLen2 = labelLineModel.get('length2');\n\n        var midAngle = (layout.startAngle + layout.endAngle) / 2;\n        var dx = Math.cos(midAngle);\n        var dy = Math.sin(midAngle);\n\n        var textX;\n        var textY;\n        var linePoints;\n        var textAlign;\n\n        cx = layout.cx;\n        cy = layout.cy;\n\n        var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';\n        if (labelPosition === 'center') {\n            textX = layout.cx;\n            textY = layout.cy;\n            textAlign = 'center';\n        }\n        else {\n            var x1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dx : layout.r * dx) + cx;\n            var y1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dy : layout.r * dy) + cy;\n\n            textX = x1 + dx * 3;\n            textY = y1 + dy * 3;\n\n            if (!isLabelInside) {\n                // For roseType\n                var x2 = x1 + dx * (labelLineLen + r - layout.r);\n                var y2 = y1 + dy * (labelLineLen + r - layout.r);\n                var x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2);\n                var y3 = y2;\n\n                textX = x3 + (dx < 0 ? -5 : 5);\n                textY = y3;\n                linePoints = [[x1, y1], [x2, y2], [x3, y3]];\n            }\n\n            textAlign = isLabelInside ? 'center' : (dx > 0 ? 'left' : 'right');\n        }\n        var font = labelModel.getFont();\n\n        var labelRotate = labelModel.get('rotate')\n            ? (dx < 0 ? -midAngle + Math.PI : -midAngle) : 0;\n        var text = seriesModel.getFormattedLabel(idx, 'normal')\n                    || data.getName(idx);\n        var textRect = getBoundingRect(\n            text, font, textAlign, 'top'\n        );\n        hasLabelRotate = !!labelRotate;\n        layout.label = {\n            x: textX,\n            y: textY,\n            position: labelPosition,\n            height: textRect.height,\n            len: labelLineLen,\n            len2: labelLineLen2,\n            linePoints: linePoints,\n            textAlign: textAlign,\n            verticalAlign: 'middle',\n            rotation: labelRotate,\n            inside: isLabelInside\n        };\n\n        // Not layout the inside label\n        if (!isLabelInside) {\n            labelLayoutList.push(layout.label);\n        }\n    });\n    if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {\n        avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar PI2$4 = Math.PI * 2;\nvar RADIAN = Math.PI / 180;\n\nvar pieLayout = function (seriesType, ecModel, api, payload) {\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n\n        var center = seriesModel.get('center');\n        var radius = seriesModel.get('radius');\n\n        if (!isArray(radius)) {\n            radius = [0, radius];\n        }\n        if (!isArray(center)) {\n            center = [center, center];\n        }\n\n        var width = api.getWidth();\n        var height = api.getHeight();\n        var size = Math.min(width, height);\n        var cx = parsePercent$1(center[0], width);\n        var cy = parsePercent$1(center[1], height);\n        var r0 = parsePercent$1(radius[0], size / 2);\n        var r = parsePercent$1(radius[1], size / 2);\n\n        var startAngle = -seriesModel.get('startAngle') * RADIAN;\n\n        var minAngle = seriesModel.get('minAngle') * RADIAN;\n\n        var validDataCount = 0;\n        data.each(valueDim, function (value) {\n            !isNaN(value) && validDataCount++;\n        });\n\n        var sum = data.getSum(valueDim);\n        // Sum may be 0\n        var unitRadian = Math.PI / (sum || validDataCount) * 2;\n\n        var clockwise = seriesModel.get('clockwise');\n\n        var roseType = seriesModel.get('roseType');\n        var stillShowZeroSum = seriesModel.get('stillShowZeroSum');\n\n        // [0...max]\n        var extent = data.getDataExtent(valueDim);\n        extent[0] = 0;\n\n        // In the case some sector angle is smaller than minAngle\n        var restAngle = PI2$4;\n        var valueSumLargerThanMinAngle = 0;\n\n        var currentAngle = startAngle;\n        var dir = clockwise ? 1 : -1;\n\n        data.each(valueDim, function (value, idx) {\n            var angle;\n            if (isNaN(value)) {\n                data.setItemLayout(idx, {\n                    angle: NaN,\n                    startAngle: NaN,\n                    endAngle: NaN,\n                    clockwise: clockwise,\n                    cx: cx,\n                    cy: cy,\n                    r0: r0,\n                    r: roseType\n                        ? NaN\n                        : r\n                });\n                return;\n            }\n\n            // FIXME 兼容 2.0 但是 roseType 是 area 的时候才是这样？\n            if (roseType !== 'area') {\n                angle = (sum === 0 && stillShowZeroSum)\n                    ? unitRadian : (value * unitRadian);\n            }\n            else {\n                angle = PI2$4 / validDataCount;\n            }\n\n            if (angle < minAngle) {\n                angle = minAngle;\n                restAngle -= minAngle;\n            }\n            else {\n                valueSumLargerThanMinAngle += value;\n            }\n\n            var endAngle = currentAngle + dir * angle;\n            data.setItemLayout(idx, {\n                angle: angle,\n                startAngle: currentAngle,\n                endAngle: endAngle,\n                clockwise: clockwise,\n                cx: cx,\n                cy: cy,\n                r0: r0,\n                r: roseType\n                    ? linearMap(value, extent, [r0, r])\n                    : r\n            });\n\n            currentAngle = endAngle;\n        });\n\n        // Some sector is constrained by minAngle\n        // Rest sectors needs recalculate angle\n        if (restAngle < PI2$4 && validDataCount) {\n            // Average the angle if rest angle is not enough after all angles is\n            // Constrained by minAngle\n            if (restAngle <= 1e-3) {\n                var angle = PI2$4 / validDataCount;\n                data.each(valueDim, function (value, idx) {\n                    if (!isNaN(value)) {\n                        var layout = data.getItemLayout(idx);\n                        layout.angle = angle;\n                        layout.startAngle = startAngle + dir * idx * angle;\n                        layout.endAngle = startAngle + dir * (idx + 1) * angle;\n                    }\n                });\n            }\n            else {\n                unitRadian = restAngle / valueSumLargerThanMinAngle;\n                currentAngle = startAngle;\n                data.each(valueDim, function (value, idx) {\n                    if (!isNaN(value)) {\n                        var layout = data.getItemLayout(idx);\n                        var angle = layout.angle === minAngle\n                            ? minAngle : value * unitRadian;\n                        layout.startAngle = currentAngle;\n                        layout.endAngle = currentAngle + dir * angle;\n                        currentAngle += dir * angle;\n                    }\n                });\n            }\n        }\n\n        labelLayout(seriesModel, r, width, height);\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar dataFilter = function (seriesType) {\n    return {\n        seriesType: seriesType,\n        reset: function (seriesModel, ecModel) {\n            var legendModels = ecModel.findComponents({\n                mainType: 'legend'\n            });\n            if (!legendModels || !legendModels.length) {\n                return;\n            }\n            var data = seriesModel.getData();\n            data.filterSelf(function (idx) {\n                var name = data.getName(idx);\n                // If in any legend component the status is not selected.\n                for (var i = 0; i < legendModels.length; i++) {\n                    if (!legendModels[i].isSelected(name)) {\n                        return false;\n                    }\n                }\n                return true;\n            });\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\ncreateDataSelectAction('pie', [{\n    type: 'pieToggleSelect',\n    event: 'pieselectchanged',\n    method: 'toggleSelected'\n}, {\n    type: 'pieSelect',\n    event: 'pieselected',\n    method: 'select'\n}, {\n    type: 'pieUnSelect',\n    event: 'pieunselected',\n    method: 'unSelect'\n}]);\n\nregisterVisual(dataColor('pie'));\nregisterLayout(curry(pieLayout, 'pie'));\nregisterProcessor(dataFilter('pie'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nexports.version = version;\nexports.dependencies = dependencies;\nexports.PRIORITY = PRIORITY;\nexports.init = init;\nexports.connect = connect;\nexports.disConnect = disConnect;\nexports.disconnect = disconnect;\nexports.dispose = dispose;\nexports.getInstanceByDom = getInstanceByDom;\nexports.getInstanceById = getInstanceById;\nexports.registerTheme = registerTheme;\nexports.registerPreprocessor = registerPreprocessor;\nexports.registerProcessor = registerProcessor;\nexports.registerPostUpdate = registerPostUpdate;\nexports.registerAction = registerAction;\nexports.registerCoordinateSystem = registerCoordinateSystem;\nexports.getCoordinateSystemDimensions = getCoordinateSystemDimensions;\nexports.registerLayout = registerLayout;\nexports.registerVisual = registerVisual;\nexports.registerLoading = registerLoading;\nexports.extendComponentModel = extendComponentModel;\nexports.extendComponentView = extendComponentView;\nexports.extendSeriesModel = extendSeriesModel;\nexports.extendChartView = extendChartView;\nexports.setCanvasCreator = setCanvasCreator;\nexports.registerMap = registerMap;\nexports.getMap = getMap;\nexports.dataTool = dataTool;\n\n})));\n"
  },
  {
    "path": "static/js/Echarts/echarts.common.js",
    "content": "(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n\ttypeof define === 'function' && define.amd ? define(['exports'], factory) :\n\t(factory((global.echarts = {})));\n}(this, (function (exports) { 'use strict';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (1) The code `if (__DEV__) ...` can be removed by build tool.\n// (2) If intend to use `__DEV__`, this module should be imported. Use a global\n// variable `__DEV__` may cause that miss the declaration (see #6535), or the\n// declaration is behind of the using position (for example in `Model.extent`,\n// And tools like rollup can not analysis the dependency if not import).\n\nvar dev;\n\n// In browser\nif (typeof window !== 'undefined') {\n    dev = window.__DEV__;\n}\n// In node\nelse if (typeof global !== 'undefined') {\n    dev = global.__DEV__;\n}\n\nif (typeof dev === 'undefined') {\n    dev = true;\n}\n\nvar __DEV__ = dev;\n\n/**\n * zrender: 生成唯一id\n *\n * @author errorrik (errorrik@gmail.com)\n */\n\nvar idStart = 0x0907;\n\nvar guid = function () {\n    return idStart++;\n};\n\n/**\n * echarts设备环境识别\n *\n * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。\n * @author firede[firede@firede.us]\n * @desc thanks zepto.\n */\n\nvar env = {};\n\nif (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') {\n    // In Weixin Application\n    env = {\n        browser: {},\n        os: {},\n        node: false,\n        wxa: true, // Weixin Application\n        canvasSupported: true,\n        svgSupported: false,\n        touchEventsSupported: true,\n        domSupported: false\n    };\n}\nelse if (typeof document === 'undefined' && typeof self !== 'undefined') {\n    // In worker\n    env = {\n        browser: {},\n        os: {},\n        node: false,\n        worker: true,\n        canvasSupported: true,\n        domSupported: false\n    };\n}\nelse if (typeof navigator === 'undefined') {\n    // In node\n    env = {\n        browser: {},\n        os: {},\n        node: true,\n        worker: false,\n        // Assume canvas is supported\n        canvasSupported: true,\n        svgSupported: true,\n        domSupported: false\n    };\n}\nelse {\n    env = detect(navigator.userAgent);\n}\n\nvar env$1 = env;\n\n// Zepto.js\n// (c) 2010-2013 Thomas Fuchs\n// Zepto.js may be freely distributed under the MIT license.\n\nfunction detect(ua) {\n    var os = {};\n    var browser = {};\n    // var webkit = ua.match(/Web[kK]it[\\/]{0,1}([\\d.]+)/);\n    // var android = ua.match(/(Android);?[\\s\\/]+([\\d.]+)?/);\n    // var ipad = ua.match(/(iPad).*OS\\s([\\d_]+)/);\n    // var ipod = ua.match(/(iPod)(.*OS\\s([\\d_]+))?/);\n    // var iphone = !ipad && ua.match(/(iPhone\\sOS)\\s([\\d_]+)/);\n    // var webos = ua.match(/(webOS|hpwOS)[\\s\\/]([\\d.]+)/);\n    // var touchpad = webos && ua.match(/TouchPad/);\n    // var kindle = ua.match(/Kindle\\/([\\d.]+)/);\n    // var silk = ua.match(/Silk\\/([\\d._]+)/);\n    // var blackberry = ua.match(/(BlackBerry).*Version\\/([\\d.]+)/);\n    // var bb10 = ua.match(/(BB10).*Version\\/([\\d.]+)/);\n    // var rimtabletos = ua.match(/(RIM\\sTablet\\sOS)\\s([\\d.]+)/);\n    // var playbook = ua.match(/PlayBook/);\n    // var chrome = ua.match(/Chrome\\/([\\d.]+)/) || ua.match(/CriOS\\/([\\d.]+)/);\n    var firefox = ua.match(/Firefox\\/([\\d.]+)/);\n    // var safari = webkit && ua.match(/Mobile\\//) && !chrome;\n    // var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome;\n    var ie = ua.match(/MSIE\\s([\\d.]+)/)\n        // IE 11 Trident/7.0; rv:11.0\n        || ua.match(/Trident\\/.+?rv:(([\\d.]+))/);\n    var edge = ua.match(/Edge\\/([\\d.]+)/); // IE 12 and 12+\n\n    var weChat = (/micromessenger/i).test(ua);\n\n    // Todo: clean this up with a better OS/browser seperation:\n    // - discern (more) between multiple browsers on android\n    // - decide if kindle fire in silk mode is android or not\n    // - Firefox on Android doesn't specify the Android version\n    // - possibly devide in os, device and browser hashes\n\n    // if (browser.webkit = !!webkit) browser.version = webkit[1];\n\n    // if (android) os.android = true, os.version = android[2];\n    // if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.');\n    // if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.');\n    // if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null;\n    // if (webos) os.webos = true, os.version = webos[2];\n    // if (touchpad) os.touchpad = true;\n    // if (blackberry) os.blackberry = true, os.version = blackberry[2];\n    // if (bb10) os.bb10 = true, os.version = bb10[2];\n    // if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2];\n    // if (playbook) browser.playbook = true;\n    // if (kindle) os.kindle = true, os.version = kindle[1];\n    // if (silk) browser.silk = true, browser.version = silk[1];\n    // if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true;\n    // if (chrome) browser.chrome = true, browser.version = chrome[1];\n    if (firefox) {\n        browser.firefox = true;\n        browser.version = firefox[1];\n    }\n    // if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true;\n    // if (webview) browser.webview = true;\n\n    if (ie) {\n        browser.ie = true;\n        browser.version = ie[1];\n    }\n\n    if (edge) {\n        browser.edge = true;\n        browser.version = edge[1];\n    }\n\n    // It is difficult to detect WeChat in Win Phone precisely, because ua can\n    // not be set on win phone. So we do not consider Win Phone.\n    if (weChat) {\n        browser.weChat = true;\n    }\n\n    // os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) ||\n    //     (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/)));\n    // os.phone  = !!(!os.tablet && !os.ipod && (android || iphone || webos ||\n    //     (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\\/([\\d.]+)/)) ||\n    //     (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/))));\n\n    return {\n        browser: browser,\n        os: os,\n        node: false,\n        // 原生canvas支持，改极端点了\n        // canvasSupported : !(browser.ie && parseFloat(browser.version) < 9)\n        canvasSupported: !!document.createElement('canvas').getContext,\n        svgSupported: typeof SVGRect !== 'undefined',\n        // works on most browsers\n        // IE10/11 does not support touch event, and MS Edge supports them but not by\n        // default, so we dont check navigator.maxTouchPoints for them here.\n        touchEventsSupported: 'ontouchstart' in window && !browser.ie && !browser.edge,\n        // <http://caniuse.com/#search=pointer%20event>.\n        pointerEventsSupported: 'onpointerdown' in window\n            // Firefox supports pointer but not by default, only MS browsers are reliable on pointer\n            // events currently. So we dont use that on other browsers unless tested sufficiently.\n            // Although IE 10 supports pointer event, it use old style and is different from the\n            // standard. So we exclude that. (IE 10 is hardly used on touch device)\n            && (browser.edge || (browser.ie && browser.version >= 11)),\n        // passiveSupported: detectPassiveSupport()\n        domSupported: typeof document !== 'undefined'\n    };\n}\n\n// See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection\n// function detectPassiveSupport() {\n//     // Test via a getter in the options object to see if the passive property is accessed\n//     var supportsPassive = false;\n//     try {\n//         var opts = Object.defineProperty({}, 'passive', {\n//             get: function() {\n//                 supportsPassive = true;\n//             }\n//         });\n//         window.addEventListener('testPassive', function() {}, opts);\n//     } catch (e) {\n//     }\n//     return supportsPassive;\n// }\n\n/**\n * @module zrender/core/util\n */\n\n// 用于处理merge时无法遍历Date等对象的问题\nvar BUILTIN_OBJECT = {\n    '[object Function]': 1,\n    '[object RegExp]': 1,\n    '[object Date]': 1,\n    '[object Error]': 1,\n    '[object CanvasGradient]': 1,\n    '[object CanvasPattern]': 1,\n    // For node-canvas\n    '[object Image]': 1,\n    '[object Canvas]': 1\n};\n\nvar TYPED_ARRAY = {\n    '[object Int8Array]': 1,\n    '[object Uint8Array]': 1,\n    '[object Uint8ClampedArray]': 1,\n    '[object Int16Array]': 1,\n    '[object Uint16Array]': 1,\n    '[object Int32Array]': 1,\n    '[object Uint32Array]': 1,\n    '[object Float32Array]': 1,\n    '[object Float64Array]': 1\n};\n\nvar objToString = Object.prototype.toString;\n\nvar arrayProto = Array.prototype;\nvar nativeForEach = arrayProto.forEach;\nvar nativeFilter = arrayProto.filter;\nvar nativeSlice = arrayProto.slice;\nvar nativeMap = arrayProto.map;\nvar nativeReduce = arrayProto.reduce;\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar methods = {};\n\nfunction $override(name, fn) {\n    // Clear ctx instance for different environment\n    if (name === 'createCanvas') {\n        _ctx = null;\n    }\n\n    methods[name] = fn;\n}\n\n/**\n * Those data types can be cloned:\n *     Plain object, Array, TypedArray, number, string, null, undefined.\n * Those data types will be assgined using the orginal data:\n *     BUILTIN_OBJECT\n * Instance of user defined class will be cloned to a plain object, without\n * properties in prototype.\n * Other data types is not supported (not sure what will happen).\n *\n * Caution: do not support clone Date, for performance consideration.\n * (There might be a large number of date in `series.data`).\n * So date should not be modified in and out of echarts.\n *\n * @param {*} source\n * @return {*} new\n */\nfunction clone(source) {\n    if (source == null || typeof source !== 'object') {\n        return source;\n    }\n\n    var result = source;\n    var typeStr = objToString.call(source);\n\n    if (typeStr === '[object Array]') {\n        if (!isPrimitive(source)) {\n            result = [];\n            for (var i = 0, len = source.length; i < len; i++) {\n                result[i] = clone(source[i]);\n            }\n        }\n    }\n    else if (TYPED_ARRAY[typeStr]) {\n        if (!isPrimitive(source)) {\n            var Ctor = source.constructor;\n            if (source.constructor.from) {\n                result = Ctor.from(source);\n            }\n            else {\n                result = new Ctor(source.length);\n                for (var i = 0, len = source.length; i < len; i++) {\n                    result[i] = clone(source[i]);\n                }\n            }\n        }\n    }\n    else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) {\n        result = {};\n        for (var key in source) {\n            if (source.hasOwnProperty(key)) {\n                result[key] = clone(source[key]);\n            }\n        }\n    }\n\n    return result;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overwrite=false]\n */\nfunction merge(target, source, overwrite) {\n    // We should escapse that source is string\n    // and enter for ... in ...\n    if (!isObject$1(source) || !isObject$1(target)) {\n        return overwrite ? clone(source) : target;\n    }\n\n    for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n            var targetProp = target[key];\n            var sourceProp = source[key];\n\n            if (isObject$1(sourceProp)\n                && isObject$1(targetProp)\n                && !isArray(sourceProp)\n                && !isArray(targetProp)\n                && !isDom(sourceProp)\n                && !isDom(targetProp)\n                && !isBuiltInObject(sourceProp)\n                && !isBuiltInObject(targetProp)\n                && !isPrimitive(sourceProp)\n                && !isPrimitive(targetProp)\n            ) {\n                // 如果需要递归覆盖，就递归调用merge\n                merge(targetProp, sourceProp, overwrite);\n            }\n            else if (overwrite || !(key in target)) {\n                // 否则只处理overwrite为true，或者在目标对象中没有此属性的情况\n                // NOTE，在 target[key] 不存在的时候也是直接覆盖\n                target[key] = clone(source[key], true);\n            }\n        }\n    }\n\n    return target;\n}\n\n/**\n * @param {Array} targetAndSources The first item is target, and the rests are source.\n * @param {boolean} [overwrite=false]\n * @return {*} target\n */\nfunction mergeAll(targetAndSources, overwrite) {\n    var result = targetAndSources[0];\n    for (var i = 1, len = targetAndSources.length; i < len; i++) {\n        result = merge(result, targetAndSources[i], overwrite);\n    }\n    return result;\n}\n\n/**\n * @param {*} target\n * @param {*} source\n * @memberOf module:zrender/core/util\n */\nfunction extend(target, source) {\n    for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n            target[key] = source[key];\n        }\n    }\n    return target;\n}\n\n/**\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overlay=false]\n * @memberOf module:zrender/core/util\n */\nfunction defaults(target, source, overlay) {\n    for (var key in source) {\n        if (source.hasOwnProperty(key)\n            && (overlay ? source[key] != null : target[key] == null)\n        ) {\n            target[key] = source[key];\n        }\n    }\n    return target;\n}\n\nvar createCanvas = function () {\n    return methods.createCanvas();\n};\n\nmethods.createCanvas = function () {\n    return document.createElement('canvas');\n};\n\n// FIXME\nvar _ctx;\n\nfunction getContext() {\n    if (!_ctx) {\n        // Use util.createCanvas instead of createCanvas\n        // because createCanvas may be overwritten in different environment\n        _ctx = createCanvas().getContext('2d');\n    }\n    return _ctx;\n}\n\n/**\n * 查询数组中元素的index\n * @memberOf module:zrender/core/util\n */\nfunction indexOf(array, value) {\n    if (array) {\n        if (array.indexOf) {\n            return array.indexOf(value);\n        }\n        for (var i = 0, len = array.length; i < len; i++) {\n            if (array[i] === value) {\n                return i;\n            }\n        }\n    }\n    return -1;\n}\n\n/**\n * 构造类继承关系\n *\n * @memberOf module:zrender/core/util\n * @param {Function} clazz 源类\n * @param {Function} baseClazz 基类\n */\nfunction inherits(clazz, baseClazz) {\n    var clazzPrototype = clazz.prototype;\n    function F() {}\n    F.prototype = baseClazz.prototype;\n    clazz.prototype = new F();\n\n    for (var prop in clazzPrototype) {\n        clazz.prototype[prop] = clazzPrototype[prop];\n    }\n    clazz.prototype.constructor = clazz;\n    clazz.superClass = baseClazz;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Object|Function} target\n * @param {Object|Function} sorce\n * @param {boolean} overlay\n */\nfunction mixin(target, source, overlay) {\n    target = 'prototype' in target ? target.prototype : target;\n    source = 'prototype' in source ? source.prototype : source;\n\n    defaults(target, source, overlay);\n}\n\n/**\n * Consider typed array.\n * @param {Array|TypedArray} data\n */\nfunction isArrayLike(data) {\n    if (!data) {\n        return;\n    }\n    if (typeof data === 'string') {\n        return false;\n    }\n    return typeof data.length === 'number';\n}\n\n/**\n * 数组或对象遍历\n * @memberOf module:zrender/core/util\n * @param {Object|Array} obj\n * @param {Function} cb\n * @param {*} [context]\n */\nfunction each$1(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.forEach && obj.forEach === nativeForEach) {\n        obj.forEach(cb, context);\n    }\n    else if (obj.length === +obj.length) {\n        for (var i = 0, len = obj.length; i < len; i++) {\n            cb.call(context, obj[i], i, obj);\n        }\n    }\n    else {\n        for (var key in obj) {\n            if (obj.hasOwnProperty(key)) {\n                cb.call(context, obj[key], key, obj);\n            }\n        }\n    }\n}\n\n/**\n * 数组映射\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction map(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.map && obj.map === nativeMap) {\n        return obj.map(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            result.push(cb.call(context, obj[i], i, obj));\n        }\n        return result;\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {Object} [memo]\n * @param {*} [context]\n * @return {Array}\n */\nfunction reduce(obj, cb, memo, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.reduce && obj.reduce === nativeReduce) {\n        return obj.reduce(cb, memo, context);\n    }\n    else {\n        for (var i = 0, len = obj.length; i < len; i++) {\n            memo = cb.call(context, memo, obj[i], i, obj);\n        }\n        return memo;\n    }\n}\n\n/**\n * 数组过滤\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction filter(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.filter && obj.filter === nativeFilter) {\n        return obj.filter(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            if (cb.call(context, obj[i], i, obj)) {\n                result.push(obj[i]);\n            }\n        }\n        return result;\n    }\n}\n\n/**\n * 数组项查找\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {*}\n */\nfunction find(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    for (var i = 0, len = obj.length; i < len; i++) {\n        if (cb.call(context, obj[i], i, obj)) {\n            return obj[i];\n        }\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @param {*} context\n * @return {Function}\n */\nfunction bind(func, context) {\n    var args = nativeSlice.call(arguments, 2);\n    return function () {\n        return func.apply(context, args.concat(nativeSlice.call(arguments)));\n    };\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @return {Function}\n */\nfunction curry(func) {\n    var args = nativeSlice.call(arguments, 1);\n    return function () {\n        return func.apply(this, args.concat(nativeSlice.call(arguments)));\n    };\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isArray(value) {\n    return objToString.call(value) === '[object Array]';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isFunction$1(value) {\n    return typeof value === 'function';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isString(value) {\n    return objToString.call(value) === '[object String]';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isObject$1(value) {\n    // Avoid a V8 JIT bug in Chrome 19-20.\n    // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.\n    var type = typeof value;\n    return type === 'function' || (!!value && type === 'object');\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isBuiltInObject(value) {\n    return !!BUILTIN_OBJECT[objToString.call(value)];\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isTypedArray(value) {\n    return !!TYPED_ARRAY[objToString.call(value)];\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isDom(value) {\n    return typeof value === 'object'\n        && typeof value.nodeType === 'number'\n        && typeof value.ownerDocument === 'object';\n}\n\n/**\n * Whether is exactly NaN. Notice isNaN('a') returns true.\n * @param {*} value\n * @return {boolean}\n */\nfunction eqNaN(value) {\n    return value !== value;\n}\n\n/**\n * If value1 is not null, then return value1, otherwise judget rest of values.\n * Low performance.\n * @memberOf module:zrender/core/util\n * @return {*} Final value\n */\nfunction retrieve(values) {\n    for (var i = 0, len = arguments.length; i < len; i++) {\n        if (arguments[i] != null) {\n            return arguments[i];\n        }\n    }\n}\n\nfunction retrieve2(value0, value1) {\n    return value0 != null\n        ? value0\n        : value1;\n}\n\nfunction retrieve3(value0, value1, value2) {\n    return value0 != null\n        ? value0\n        : value1 != null\n        ? value1\n        : value2;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} arr\n * @param {number} startIndex\n * @param {number} endIndex\n * @return {Array}\n */\nfunction slice() {\n    return Function.call.apply(nativeSlice, arguments);\n}\n\n/**\n * Normalize css liked array configuration\n * e.g.\n *  3 => [3, 3, 3, 3]\n *  [4, 2] => [4, 2, 4, 2]\n *  [4, 3, 2] => [4, 3, 2, 3]\n * @param {number|Array.<number>} val\n * @return {Array.<number>}\n */\nfunction normalizeCssArray(val) {\n    if (typeof (val) === 'number') {\n        return [val, val, val, val];\n    }\n    var len = val.length;\n    if (len === 2) {\n        // vertical | horizontal\n        return [val[0], val[1], val[0], val[1]];\n    }\n    else if (len === 3) {\n        // top | horizontal | bottom\n        return [val[0], val[1], val[2], val[1]];\n    }\n    return val;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {boolean} condition\n * @param {string} message\n */\nfunction assert$1(condition, message) {\n    if (!condition) {\n        throw new Error(message);\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {string} str string to be trimed\n * @return {string} trimed string\n */\nfunction trim(str) {\n    if (str == null) {\n        return null;\n    }\n    else if (typeof str.trim === 'function') {\n        return str.trim();\n    }\n    else {\n        return str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n    }\n}\n\nvar primitiveKey = '__ec_primitive__';\n/**\n * Set an object as primitive to be ignored traversing children in clone or merge\n */\nfunction setAsPrimitive(obj) {\n    obj[primitiveKey] = true;\n}\n\nfunction isPrimitive(obj) {\n    return obj[primitiveKey];\n}\n\n/**\n * @constructor\n * @param {Object} obj Only apply `ownProperty`.\n */\nfunction HashMap(obj) {\n    var isArr = isArray(obj);\n    // Key should not be set on this, otherwise\n    // methods get/set/... may be overrided.\n    this.data = {};\n    var thisMap = this;\n\n    (obj instanceof HashMap)\n        ? obj.each(visit)\n        : (obj && each$1(obj, visit));\n\n    function visit(value, key) {\n        isArr ? thisMap.set(value, key) : thisMap.set(key, value);\n    }\n}\n\nHashMap.prototype = {\n    constructor: HashMap,\n    // Do not provide `has` method to avoid defining what is `has`.\n    // (We usually treat `null` and `undefined` as the same, different\n    // from ES6 Map).\n    get: function (key) {\n        return this.data.hasOwnProperty(key) ? this.data[key] : null;\n    },\n    set: function (key, value) {\n        // Comparing with invocation chaining, `return value` is more commonly\n        // used in this case: `var someVal = map.set('a', genVal());`\n        return (this.data[key] = value);\n    },\n    // Although util.each can be performed on this hashMap directly, user\n    // should not use the exposed keys, who are prefixed.\n    each: function (cb, context) {\n        context !== void 0 && (cb = bind(cb, context));\n        for (var key in this.data) {\n            this.data.hasOwnProperty(key) && cb(this.data[key], key);\n        }\n    },\n    // Do not use this method if performance sensitive.\n    removeKey: function (key) {\n        delete this.data[key];\n    }\n};\n\nfunction createHashMap(obj) {\n    return new HashMap(obj);\n}\n\nfunction concatArray(a, b) {\n    var newArray = new a.constructor(a.length + b.length);\n    for (var i = 0; i < a.length; i++) {\n        newArray[i] = a[i];\n    }\n    var offset = a.length;\n    for (i = 0; i < b.length; i++) {\n        newArray[i + offset] = b[i];\n    }\n    return newArray;\n}\n\n\nfunction noop() {}\n\n\nvar zrUtil = (Object.freeze || Object)({\n\t$override: $override,\n\tclone: clone,\n\tmerge: merge,\n\tmergeAll: mergeAll,\n\textend: extend,\n\tdefaults: defaults,\n\tcreateCanvas: createCanvas,\n\tgetContext: getContext,\n\tindexOf: indexOf,\n\tinherits: inherits,\n\tmixin: mixin,\n\tisArrayLike: isArrayLike,\n\teach: each$1,\n\tmap: map,\n\treduce: reduce,\n\tfilter: filter,\n\tfind: find,\n\tbind: bind,\n\tcurry: curry,\n\tisArray: isArray,\n\tisFunction: isFunction$1,\n\tisString: isString,\n\tisObject: isObject$1,\n\tisBuiltInObject: isBuiltInObject,\n\tisTypedArray: isTypedArray,\n\tisDom: isDom,\n\teqNaN: eqNaN,\n\tretrieve: retrieve,\n\tretrieve2: retrieve2,\n\tretrieve3: retrieve3,\n\tslice: slice,\n\tnormalizeCssArray: normalizeCssArray,\n\tassert: assert$1,\n\ttrim: trim,\n\tsetAsPrimitive: setAsPrimitive,\n\tisPrimitive: isPrimitive,\n\tcreateHashMap: createHashMap,\n\tconcatArray: concatArray,\n\tnoop: noop\n});\n\nvar ArrayCtor = typeof Float32Array === 'undefined'\n    ? Array\n    : Float32Array;\n\n/**\n * 创建一个向量\n * @param {number} [x=0]\n * @param {number} [y=0]\n * @return {Vector2}\n */\nfunction create(x, y) {\n    var out = new ArrayCtor(2);\n    if (x == null) {\n        x = 0;\n    }\n    if (y == null) {\n        y = 0;\n    }\n    out[0] = x;\n    out[1] = y;\n    return out;\n}\n\n/**\n * 复制向量数据\n * @param {Vector2} out\n * @param {Vector2} v\n * @return {Vector2}\n */\nfunction copy(out, v) {\n    out[0] = v[0];\n    out[1] = v[1];\n    return out;\n}\n\n/**\n * 克隆一个向量\n * @param {Vector2} v\n * @return {Vector2}\n */\nfunction clone$1(v) {\n    var out = new ArrayCtor(2);\n    out[0] = v[0];\n    out[1] = v[1];\n    return out;\n}\n\n/**\n * 设置向量的两个项\n * @param {Vector2} out\n * @param {number} a\n * @param {number} b\n * @return {Vector2} 结果\n */\nfunction set(out, a, b) {\n    out[0] = a;\n    out[1] = b;\n    return out;\n}\n\n/**\n * 向量相加\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction add(out, v1, v2) {\n    out[0] = v1[0] + v2[0];\n    out[1] = v1[1] + v2[1];\n    return out;\n}\n\n/**\n * 向量缩放后相加\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @param {number} a\n */\nfunction scaleAndAdd(out, v1, v2, a) {\n    out[0] = v1[0] + v2[0] * a;\n    out[1] = v1[1] + v2[1] * a;\n    return out;\n}\n\n/**\n * 向量相减\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction sub(out, v1, v2) {\n    out[0] = v1[0] - v2[0];\n    out[1] = v1[1] - v2[1];\n    return out;\n}\n\n/**\n * 向量长度\n * @param {Vector2} v\n * @return {number}\n */\nfunction len(v) {\n    return Math.sqrt(lenSquare(v));\n}\nvar length = len; // jshint ignore:line\n\n/**\n * 向量长度平方\n * @param {Vector2} v\n * @return {number}\n */\nfunction lenSquare(v) {\n    return v[0] * v[0] + v[1] * v[1];\n}\nvar lengthSquare = lenSquare;\n\n/**\n * 向量乘法\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction mul(out, v1, v2) {\n    out[0] = v1[0] * v2[0];\n    out[1] = v1[1] * v2[1];\n    return out;\n}\n\n/**\n * 向量除法\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction div(out, v1, v2) {\n    out[0] = v1[0] / v2[0];\n    out[1] = v1[1] / v2[1];\n    return out;\n}\n\n/**\n * 向量点乘\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction dot(v1, v2) {\n    return v1[0] * v2[0] + v1[1] * v2[1];\n}\n\n/**\n * 向量缩放\n * @param {Vector2} out\n * @param {Vector2} v\n * @param {number} s\n */\nfunction scale(out, v, s) {\n    out[0] = v[0] * s;\n    out[1] = v[1] * s;\n    return out;\n}\n\n/**\n * 向量归一化\n * @param {Vector2} out\n * @param {Vector2} v\n */\nfunction normalize(out, v) {\n    var d = len(v);\n    if (d === 0) {\n        out[0] = 0;\n        out[1] = 0;\n    }\n    else {\n        out[0] = v[0] / d;\n        out[1] = v[1] / d;\n    }\n    return out;\n}\n\n/**\n * 计算向量间距离\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction distance(v1, v2) {\n    return Math.sqrt(\n        (v1[0] - v2[0]) * (v1[0] - v2[0])\n        + (v1[1] - v2[1]) * (v1[1] - v2[1])\n    );\n}\nvar dist = distance;\n\n/**\n * 向量距离平方\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction distanceSquare(v1, v2) {\n    return (v1[0] - v2[0]) * (v1[0] - v2[0])\n        + (v1[1] - v2[1]) * (v1[1] - v2[1]);\n}\nvar distSquare = distanceSquare;\n\n/**\n * 求负向量\n * @param {Vector2} out\n * @param {Vector2} v\n */\nfunction negate(out, v) {\n    out[0] = -v[0];\n    out[1] = -v[1];\n    return out;\n}\n\n/**\n * 插值两个点\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @param {number} t\n */\nfunction lerp(out, v1, v2, t) {\n    out[0] = v1[0] + t * (v2[0] - v1[0]);\n    out[1] = v1[1] + t * (v2[1] - v1[1]);\n    return out;\n}\n\n/**\n * 矩阵左乘向量\n * @param {Vector2} out\n * @param {Vector2} v\n * @param {Vector2} m\n */\nfunction applyTransform(out, v, m) {\n    var x = v[0];\n    var y = v[1];\n    out[0] = m[0] * x + m[2] * y + m[4];\n    out[1] = m[1] * x + m[3] * y + m[5];\n    return out;\n}\n\n/**\n * 求两个向量最小值\n * @param  {Vector2} out\n * @param  {Vector2} v1\n * @param  {Vector2} v2\n */\nfunction min(out, v1, v2) {\n    out[0] = Math.min(v1[0], v2[0]);\n    out[1] = Math.min(v1[1], v2[1]);\n    return out;\n}\n\n/**\n * 求两个向量最大值\n * @param  {Vector2} out\n * @param  {Vector2} v1\n * @param  {Vector2} v2\n */\nfunction max(out, v1, v2) {\n    out[0] = Math.max(v1[0], v2[0]);\n    out[1] = Math.max(v1[1], v2[1]);\n    return out;\n}\n\n\nvar vector = (Object.freeze || Object)({\n\tcreate: create,\n\tcopy: copy,\n\tclone: clone$1,\n\tset: set,\n\tadd: add,\n\tscaleAndAdd: scaleAndAdd,\n\tsub: sub,\n\tlen: len,\n\tlength: length,\n\tlenSquare: lenSquare,\n\tlengthSquare: lengthSquare,\n\tmul: mul,\n\tdiv: div,\n\tdot: dot,\n\tscale: scale,\n\tnormalize: normalize,\n\tdistance: distance,\n\tdist: dist,\n\tdistanceSquare: distanceSquare,\n\tdistSquare: distSquare,\n\tnegate: negate,\n\tlerp: lerp,\n\tapplyTransform: applyTransform,\n\tmin: min,\n\tmax: max\n});\n\n// TODO Draggable for group\n// FIXME Draggable on element which has parent rotation or scale\nfunction Draggable() {\n\n    this.on('mousedown', this._dragStart, this);\n    this.on('mousemove', this._drag, this);\n    this.on('mouseup', this._dragEnd, this);\n    this.on('globalout', this._dragEnd, this);\n    // this._dropTarget = null;\n    // this._draggingTarget = null;\n\n    // this._x = 0;\n    // this._y = 0;\n}\n\nDraggable.prototype = {\n\n    constructor: Draggable,\n\n    _dragStart: function (e) {\n        var draggingTarget = e.target;\n        if (draggingTarget && draggingTarget.draggable) {\n            this._draggingTarget = draggingTarget;\n            draggingTarget.dragging = true;\n            this._x = e.offsetX;\n            this._y = e.offsetY;\n\n            this.dispatchToElement(param(draggingTarget, e), 'dragstart', e.event);\n        }\n    },\n\n    _drag: function (e) {\n        var draggingTarget = this._draggingTarget;\n        if (draggingTarget) {\n\n            var x = e.offsetX;\n            var y = e.offsetY;\n\n            var dx = x - this._x;\n            var dy = y - this._y;\n            this._x = x;\n            this._y = y;\n\n            draggingTarget.drift(dx, dy, e);\n            this.dispatchToElement(param(draggingTarget, e), 'drag', e.event);\n\n            var dropTarget = this.findHover(x, y, draggingTarget).target;\n            var lastDropTarget = this._dropTarget;\n            this._dropTarget = dropTarget;\n\n            if (draggingTarget !== dropTarget) {\n                if (lastDropTarget && dropTarget !== lastDropTarget) {\n                    this.dispatchToElement(param(lastDropTarget, e), 'dragleave', e.event);\n                }\n                if (dropTarget && dropTarget !== lastDropTarget) {\n                    this.dispatchToElement(param(dropTarget, e), 'dragenter', e.event);\n                }\n            }\n        }\n    },\n\n    _dragEnd: function (e) {\n        var draggingTarget = this._draggingTarget;\n\n        if (draggingTarget) {\n            draggingTarget.dragging = false;\n        }\n\n        this.dispatchToElement(param(draggingTarget, e), 'dragend', e.event);\n\n        if (this._dropTarget) {\n            this.dispatchToElement(param(this._dropTarget, e), 'drop', e.event);\n        }\n\n        this._draggingTarget = null;\n        this._dropTarget = null;\n    }\n\n};\n\nfunction param(target, e) {\n    return {target: target, topTarget: e && e.topTarget};\n}\n\n/**\n * Event Mixin\n * @module zrender/mixin/Eventful\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         pissang (https://www.github.com/pissang)\n */\n\nvar arrySlice = Array.prototype.slice;\n\n/**\n * Event dispatcher.\n *\n * @alias module:zrender/mixin/Eventful\n * @constructor\n * @param {Object} [eventProcessor] The object eventProcessor is the scope when\n *        `eventProcessor.xxx` called.\n * @param {Function} [eventProcessor.normalizeQuery]\n *        param: {string|Object} Raw query.\n *        return: {string|Object} Normalized query.\n * @param {Function} [eventProcessor.filter] Event will be dispatched only\n *        if it returns `true`.\n *        param: {string} eventType\n *        param: {string|Object} query\n *        return: {boolean}\n * @param {Function} [eventProcessor.afterTrigger] Call after all handlers called.\n *        param: {string} eventType\n */\nvar Eventful = function (eventProcessor) {\n    this._$handlers = {};\n    this._$eventProcessor = eventProcessor;\n};\n\nEventful.prototype = {\n\n    constructor: Eventful,\n\n    /**\n     * The handler can only be triggered once, then removed.\n     *\n     * @param {string} event The event name.\n     * @param {string|Object} [query] Condition used on event filter.\n     * @param {Function} handler The event handler.\n     * @param {Object} context\n     */\n    one: function (event, query, handler, context) {\n        return on(this, event, query, handler, context, true);\n    },\n\n    /**\n     * Bind a handler.\n     *\n     * @param {string} event The event name.\n     * @param {string|Object} [query] Condition used on event filter.\n     * @param {Function} handler The event handler.\n     * @param {Object} [context]\n     */\n    on: function (event, query, handler, context) {\n        return on(this, event, query, handler, context, false);\n    },\n\n    /**\n     * Whether any handler has bound.\n     *\n     * @param  {string}  event\n     * @return {boolean}\n     */\n    isSilent: function (event) {\n        var _h = this._$handlers;\n        return !_h[event] || !_h[event].length;\n    },\n\n    /**\n     * Unbind a event.\n     *\n     * @param {string} event The event name.\n     * @param {Function} [handler] The event handler.\n     */\n    off: function (event, handler) {\n        var _h = this._$handlers;\n\n        if (!event) {\n            this._$handlers = {};\n            return this;\n        }\n\n        if (handler) {\n            if (_h[event]) {\n                var newList = [];\n                for (var i = 0, l = _h[event].length; i < l; i++) {\n                    if (_h[event][i].h !== handler) {\n                        newList.push(_h[event][i]);\n                    }\n                }\n                _h[event] = newList;\n            }\n\n            if (_h[event] && _h[event].length === 0) {\n                delete _h[event];\n            }\n        }\n        else {\n            delete _h[event];\n        }\n\n        return this;\n    },\n\n    /**\n     * Dispatch a event.\n     *\n     * @param {string} type The event name.\n     */\n    trigger: function (type) {\n        var _h = this._$handlers[type];\n        var eventProcessor = this._$eventProcessor;\n\n        if (_h) {\n            var args = arguments;\n            var argLen = args.length;\n\n            if (argLen > 3) {\n                args = arrySlice.call(args, 1);\n            }\n\n            var len = _h.length;\n            for (var i = 0; i < len;) {\n                var hItem = _h[i];\n                if (eventProcessor\n                    && eventProcessor.filter\n                    && hItem.query != null\n                    && !eventProcessor.filter(type, hItem.query)\n                ) {\n                    i++;\n                    continue;\n                }\n\n                // Optimize advise from backbone\n                switch (argLen) {\n                    case 1:\n                        hItem.h.call(hItem.ctx);\n                        break;\n                    case 2:\n                        hItem.h.call(hItem.ctx, args[1]);\n                        break;\n                    case 3:\n                        hItem.h.call(hItem.ctx, args[1], args[2]);\n                        break;\n                    default:\n                        // have more than 2 given arguments\n                        hItem.h.apply(hItem.ctx, args);\n                        break;\n                }\n\n                if (hItem.one) {\n                    _h.splice(i, 1);\n                    len--;\n                }\n                else {\n                    i++;\n                }\n            }\n        }\n\n        eventProcessor && eventProcessor.afterTrigger\n            && eventProcessor.afterTrigger(type);\n\n        return this;\n    },\n\n    /**\n     * Dispatch a event with context, which is specified at the last parameter.\n     *\n     * @param {string} type The event name.\n     */\n    triggerWithContext: function (type) {\n        var _h = this._$handlers[type];\n        var eventProcessor = this._$eventProcessor;\n\n        if (_h) {\n            var args = arguments;\n            var argLen = args.length;\n\n            if (argLen > 4) {\n                args = arrySlice.call(args, 1, args.length - 1);\n            }\n            var ctx = args[args.length - 1];\n\n            var len = _h.length;\n            for (var i = 0; i < len;) {\n                var hItem = _h[i];\n                if (eventProcessor\n                    && eventProcessor.filter\n                    && hItem.query != null\n                    && !eventProcessor.filter(type, hItem.query)\n                ) {\n                    i++;\n                    continue;\n                }\n\n                // Optimize advise from backbone\n                switch (argLen) {\n                    case 1:\n                        hItem.h.call(ctx);\n                        break;\n                    case 2:\n                        hItem.h.call(ctx, args[1]);\n                        break;\n                    case 3:\n                        hItem.h.call(ctx, args[1], args[2]);\n                        break;\n                    default:\n                        // have more than 2 given arguments\n                        hItem.h.apply(ctx, args);\n                        break;\n                }\n\n                if (hItem.one) {\n                    _h.splice(i, 1);\n                    len--;\n                }\n                else {\n                    i++;\n                }\n            }\n        }\n\n        eventProcessor && eventProcessor.afterTrigger\n            && eventProcessor.afterTrigger(type);\n\n        return this;\n    }\n};\n\nfunction normalizeQuery(host, query) {\n    var eventProcessor = host._$eventProcessor;\n    if (query != null && eventProcessor && eventProcessor.normalizeQuery) {\n        query = eventProcessor.normalizeQuery(query);\n    }\n    return query;\n}\n\nfunction on(eventful, event, query, handler, context, isOnce) {\n    var _h = eventful._$handlers;\n\n    if (typeof query === 'function') {\n        context = handler;\n        handler = query;\n        query = null;\n    }\n\n    if (!handler || !event) {\n        return eventful;\n    }\n\n    query = normalizeQuery(eventful, query);\n\n    if (!_h[event]) {\n        _h[event] = [];\n    }\n\n    for (var i = 0; i < _h[event].length; i++) {\n        if (_h[event][i].h === handler) {\n            return eventful;\n        }\n    }\n\n    var wrap = {\n        h: handler,\n        one: isOnce,\n        query: query,\n        ctx: context || eventful,\n        // FIXME\n        // Do not publish this feature util it is proved that it makes sense.\n        callAtLast: handler.zrEventfulCallAtLast\n    };\n\n    var lastIndex = _h[event].length - 1;\n    var lastWrap = _h[event][lastIndex];\n    (lastWrap && lastWrap.callAtLast)\n        ? _h[event].splice(lastIndex, 0, wrap)\n        : _h[event].push(wrap);\n\n    return eventful;\n}\n\n/**\n * 事件辅助类\n * @module zrender/core/event\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n */\n\nvar isDomLevel2 = (typeof window !== 'undefined') && !!window.addEventListener;\n\nvar MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;\n\nfunction getBoundingClientRect(el) {\n    // BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect\n    return el.getBoundingClientRect ? el.getBoundingClientRect() : {left: 0, top: 0};\n}\n\n// `calculate` is optional, default false\nfunction clientToLocal(el, e, out, calculate) {\n    out = out || {};\n\n    // According to the W3C Working Draft, offsetX and offsetY should be relative\n    // to the padding edge of the target element. The only browser using this convention\n    // is IE. Webkit uses the border edge, Opera uses the content edge, and FireFox does\n    // not support the properties.\n    // (see http://www.jacklmoore.com/notes/mouse-position/)\n    // In zr painter.dom, padding edge equals to border edge.\n\n    // FIXME\n    // When mousemove event triggered on ec tooltip, target is not zr painter.dom, and\n    // offsetX/Y is relative to e.target, where the calculation of zrX/Y via offsetX/Y\n    // is too complex. So css-transfrom dont support in this case temporarily.\n    if (calculate || !env$1.canvasSupported) {\n        defaultGetZrXY(el, e, out);\n    }\n    // Caution: In FireFox, layerX/layerY Mouse position relative to the closest positioned\n    // ancestor element, so we should make sure el is positioned (e.g., not position:static).\n    // BTW1, Webkit don't return the same results as FF in non-simple cases (like add\n    // zoom-factor, overflow / opacity layers, transforms ...)\n    // BTW2, (ev.offsetY || ev.pageY - $(ev.target).offset().top) is not correct in preserve-3d.\n    // <https://bugs.jquery.com/ticket/8523#comment:14>\n    // BTW3, In ff, offsetX/offsetY is always 0.\n    else if (env$1.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) {\n        out.zrX = e.layerX;\n        out.zrY = e.layerY;\n    }\n    // For IE6+, chrome, safari, opera. (When will ff support offsetX?)\n    else if (e.offsetX != null) {\n        out.zrX = e.offsetX;\n        out.zrY = e.offsetY;\n    }\n    // For some other device, e.g., IOS safari.\n    else {\n        defaultGetZrXY(el, e, out);\n    }\n\n    return out;\n}\n\nfunction defaultGetZrXY(el, e, out) {\n    // This well-known method below does not support css transform.\n    var box = getBoundingClientRect(el);\n    out.zrX = e.clientX - box.left;\n    out.zrY = e.clientY - box.top;\n}\n\n/**\n * 如果存在第三方嵌入的一些dom触发的事件，或touch事件，需要转换一下事件坐标.\n * `calculate` is optional, default false.\n */\nfunction normalizeEvent(el, e, calculate) {\n\n    e = e || window.event;\n\n    if (e.zrX != null) {\n        return e;\n    }\n\n    var eventType = e.type;\n    var isTouch = eventType && eventType.indexOf('touch') >= 0;\n\n    if (!isTouch) {\n        clientToLocal(el, e, e, calculate);\n        e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3;\n    }\n    else {\n        var touch = eventType !== 'touchend'\n            ? e.targetTouches[0]\n            : e.changedTouches[0];\n        touch && clientToLocal(el, touch, e, calculate);\n    }\n\n    // Add which for click: 1 === left; 2 === middle; 3 === right; otherwise: 0;\n    // See jQuery: https://github.com/jquery/jquery/blob/master/src/event.js\n    // If e.which has been defined, if may be readonly,\n    // see: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which\n    var button = e.button;\n    if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) {\n        e.which = (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));\n    }\n    // [Caution]: `e.which` from browser is not always reliable. For example,\n    // when press left button and `mousemove (pointermove)` in Edge, the `e.which`\n    // is 65536 and the `e.button` is -1. But the `mouseup (pointerup)` and\n    // `mousedown (pointerdown)` is the same as Chrome does.\n\n    return e;\n}\n\n/**\n * @param {HTMLElement} el\n * @param {string} name\n * @param {Function} handler\n */\nfunction addEventListener(el, name, handler) {\n    if (isDomLevel2) {\n        // Reproduct the console warning:\n        // [Violation] Added non-passive event listener to a scroll-blocking <some> event.\n        // Consider marking event handler as 'passive' to make the page more responsive.\n        // Just set console log level: verbose in chrome dev tool.\n        // then the warning log will be printed when addEventListener called.\n        // See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md\n        // We have not yet found a neat way to using passive. Because in zrender the dom event\n        // listener delegate all of the upper events of element. Some of those events need\n        // to prevent default. For example, the feature `preventDefaultMouseMove` of echarts.\n        // Before passive can be adopted, these issues should be considered:\n        // (1) Whether and how a zrender user specifies an event listener passive. And by default,\n        // passive or not.\n        // (2) How to tread that some zrender event listener is passive, and some is not. If\n        // we use other way but not preventDefault of mousewheel and touchmove, browser\n        // compatibility should be handled.\n\n        // var opts = (env.passiveSupported && name === 'mousewheel')\n        //     ? {passive: true}\n        //     // By default, the third param of el.addEventListener is `capture: false`.\n        //     : void 0;\n        // el.addEventListener(name, handler /* , opts */);\n        el.addEventListener(name, handler);\n    }\n    else {\n        el.attachEvent('on' + name, handler);\n    }\n}\n\nfunction removeEventListener(el, name, handler) {\n    if (isDomLevel2) {\n        el.removeEventListener(name, handler);\n    }\n    else {\n        el.detachEvent('on' + name, handler);\n    }\n}\n\n/**\n * preventDefault and stopPropagation.\n * Notice: do not do that in zrender. Upper application\n * do that if necessary.\n *\n * @memberOf module:zrender/core/event\n * @method\n * @param {Event} e : event对象\n */\nvar stop = isDomLevel2\n    ? function (e) {\n        e.preventDefault();\n        e.stopPropagation();\n        e.cancelBubble = true;\n    }\n    : function (e) {\n        e.returnValue = false;\n        e.cancelBubble = true;\n    };\n\n/**\n * This method only works for mouseup and mousedown. The functionality is restricted\n * for fault tolerance, See the `e.which` compatibility above.\n *\n * @param {MouseEvent} e\n * @return {boolean}\n */\nfunction isMiddleOrRightButtonOnMouseUpDown(e) {\n    return e.which === 2 || e.which === 3;\n}\n\n/**\n * To be removed.\n * @deprecated\n */\n\n/**\n * Only implements needed gestures for mobile.\n */\n\nvar GestureMgr = function () {\n\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    this._track = [];\n};\n\nGestureMgr.prototype = {\n\n    constructor: GestureMgr,\n\n    recognize: function (event, target, root) {\n        this._doTrack(event, target, root);\n        return this._recognize(event);\n    },\n\n    clear: function () {\n        this._track.length = 0;\n        return this;\n    },\n\n    _doTrack: function (event, target, root) {\n        var touches = event.touches;\n\n        if (!touches) {\n            return;\n        }\n\n        var trackItem = {\n            points: [],\n            touches: [],\n            target: target,\n            event: event\n        };\n\n        for (var i = 0, len = touches.length; i < len; i++) {\n            var touch = touches[i];\n            var pos = clientToLocal(root, touch, {});\n            trackItem.points.push([pos.zrX, pos.zrY]);\n            trackItem.touches.push(touch);\n        }\n\n        this._track.push(trackItem);\n    },\n\n    _recognize: function (event) {\n        for (var eventName in recognizers) {\n            if (recognizers.hasOwnProperty(eventName)) {\n                var gestureInfo = recognizers[eventName](this._track, event);\n                if (gestureInfo) {\n                    return gestureInfo;\n                }\n            }\n        }\n    }\n};\n\nfunction dist$1(pointPair) {\n    var dx = pointPair[1][0] - pointPair[0][0];\n    var dy = pointPair[1][1] - pointPair[0][1];\n\n    return Math.sqrt(dx * dx + dy * dy);\n}\n\nfunction center(pointPair) {\n    return [\n        (pointPair[0][0] + pointPair[1][0]) / 2,\n        (pointPair[0][1] + pointPair[1][1]) / 2\n    ];\n}\n\nvar recognizers = {\n\n    pinch: function (track, event) {\n        var trackLen = track.length;\n\n        if (!trackLen) {\n            return;\n        }\n\n        var pinchEnd = (track[trackLen - 1] || {}).points;\n        var pinchPre = (track[trackLen - 2] || {}).points || pinchEnd;\n\n        if (pinchPre\n            && pinchPre.length > 1\n            && pinchEnd\n            && pinchEnd.length > 1\n        ) {\n            var pinchScale = dist$1(pinchEnd) / dist$1(pinchPre);\n            !isFinite(pinchScale) && (pinchScale = 1);\n\n            event.pinchScale = pinchScale;\n\n            var pinchCenter = center(pinchEnd);\n            event.pinchX = pinchCenter[0];\n            event.pinchY = pinchCenter[1];\n\n            return {\n                type: 'pinch',\n                target: track[0].target,\n                event: event\n            };\n        }\n    }\n\n    // Only pinch currently.\n};\n\nvar SILENT = 'silent';\n\nfunction makeEventPacket(eveType, targetInfo, event) {\n    return {\n        type: eveType,\n        event: event,\n        // target can only be an element that is not silent.\n        target: targetInfo.target,\n        // topTarget can be a silent element.\n        topTarget: targetInfo.topTarget,\n        cancelBubble: false,\n        offsetX: event.zrX,\n        offsetY: event.zrY,\n        gestureEvent: event.gestureEvent,\n        pinchX: event.pinchX,\n        pinchY: event.pinchY,\n        pinchScale: event.pinchScale,\n        wheelDelta: event.zrDelta,\n        zrByTouch: event.zrByTouch,\n        which: event.which,\n        stop: stopEvent\n    };\n}\n\nfunction stopEvent(event) {\n    stop(this.event);\n}\n\nfunction EmptyProxy() {}\nEmptyProxy.prototype.dispose = function () {};\n\nvar handlerNames = [\n    'click', 'dblclick', 'mousewheel', 'mouseout',\n    'mouseup', 'mousedown', 'mousemove', 'contextmenu'\n];\n/**\n * @alias module:zrender/Handler\n * @constructor\n * @extends module:zrender/mixin/Eventful\n * @param {module:zrender/Storage} storage Storage instance.\n * @param {module:zrender/Painter} painter Painter instance.\n * @param {module:zrender/dom/HandlerProxy} proxy HandlerProxy instance.\n * @param {HTMLElement} painterRoot painter.root (not painter.getViewportRoot()).\n */\nvar Handler = function (storage, painter, proxy, painterRoot) {\n    Eventful.call(this);\n\n    this.storage = storage;\n\n    this.painter = painter;\n\n    this.painterRoot = painterRoot;\n\n    proxy = proxy || new EmptyProxy();\n\n    /**\n     * Proxy of event. can be Dom, WebGLSurface, etc.\n     */\n    this.proxy = null;\n\n    /**\n     * {target, topTarget, x, y}\n     * @private\n     * @type {Object}\n     */\n    this._hovered = {};\n\n    /**\n     * @private\n     * @type {Date}\n     */\n    this._lastTouchMoment;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._lastX;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._lastY;\n\n    /**\n     * @private\n     * @type {module:zrender/core/GestureMgr}\n     */\n    this._gestureMgr;\n\n\n    Draggable.call(this);\n\n    this.setHandlerProxy(proxy);\n};\n\nHandler.prototype = {\n\n    constructor: Handler,\n\n    setHandlerProxy: function (proxy) {\n        if (this.proxy) {\n            this.proxy.dispose();\n        }\n\n        if (proxy) {\n            each$1(handlerNames, function (name) {\n                proxy.on && proxy.on(name, this[name], this);\n            }, this);\n            // Attach handler\n            proxy.handler = this;\n        }\n        this.proxy = proxy;\n    },\n\n    mousemove: function (event) {\n        var x = event.zrX;\n        var y = event.zrY;\n\n        var lastHovered = this._hovered;\n        var lastHoveredTarget = lastHovered.target;\n\n        // If lastHoveredTarget is removed from zr (detected by '__zr') by some API call\n        // (like 'setOption' or 'dispatchAction') in event handlers, we should find\n        // lastHovered again here. Otherwise 'mouseout' can not be triggered normally.\n        // See #6198.\n        if (lastHoveredTarget && !lastHoveredTarget.__zr) {\n            lastHovered = this.findHover(lastHovered.x, lastHovered.y);\n            lastHoveredTarget = lastHovered.target;\n        }\n\n        var hovered = this._hovered = this.findHover(x, y);\n        var hoveredTarget = hovered.target;\n\n        var proxy = this.proxy;\n        proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default');\n\n        // Mouse out on previous hovered element\n        if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget) {\n            this.dispatchToElement(lastHovered, 'mouseout', event);\n        }\n\n        // Mouse moving on one element\n        this.dispatchToElement(hovered, 'mousemove', event);\n\n        // Mouse over on a new element\n        if (hoveredTarget && hoveredTarget !== lastHoveredTarget) {\n            this.dispatchToElement(hovered, 'mouseover', event);\n        }\n    },\n\n    mouseout: function (event) {\n        this.dispatchToElement(this._hovered, 'mouseout', event);\n\n        // There might be some doms created by upper layer application\n        // at the same level of painter.getViewportRoot() (e.g., tooltip\n        // dom created by echarts), where 'globalout' event should not\n        // be triggered when mouse enters these doms. (But 'mouseout'\n        // should be triggered at the original hovered element as usual).\n        var element = event.toElement || event.relatedTarget;\n        var innerDom;\n        do {\n            element = element && element.parentNode;\n        }\n        while (element && element.nodeType !== 9 && !(\n            innerDom = element === this.painterRoot\n        ));\n\n        !innerDom && this.trigger('globalout', {event: event});\n    },\n\n    /**\n     * Resize\n     */\n    resize: function (event) {\n        this._hovered = {};\n    },\n\n    /**\n     * Dispatch event\n     * @param {string} eventName\n     * @param {event=} eventArgs\n     */\n    dispatch: function (eventName, eventArgs) {\n        var handler = this[eventName];\n        handler && handler.call(this, eventArgs);\n    },\n\n    /**\n     * Dispose\n     */\n    dispose: function () {\n\n        this.proxy.dispose();\n\n        this.storage =\n        this.proxy =\n        this.painter = null;\n    },\n\n    /**\n     * 设置默认的cursor style\n     * @param {string} [cursorStyle='default'] 例如 crosshair\n     */\n    setCursorStyle: function (cursorStyle) {\n        var proxy = this.proxy;\n        proxy.setCursor && proxy.setCursor(cursorStyle);\n    },\n\n    /**\n     * 事件分发代理\n     *\n     * @private\n     * @param {Object} targetInfo {target, topTarget} 目标图形元素\n     * @param {string} eventName 事件名称\n     * @param {Object} event 事件对象\n     */\n    dispatchToElement: function (targetInfo, eventName, event) {\n        targetInfo = targetInfo || {};\n        var el = targetInfo.target;\n        if (el && el.silent) {\n            return;\n        }\n        var eventHandler = 'on' + eventName;\n        var eventPacket = makeEventPacket(eventName, targetInfo, event);\n\n        while (el) {\n            el[eventHandler]\n                && (eventPacket.cancelBubble = el[eventHandler].call(el, eventPacket));\n\n            el.trigger(eventName, eventPacket);\n\n            el = el.parent;\n\n            if (eventPacket.cancelBubble) {\n                break;\n            }\n        }\n\n        if (!eventPacket.cancelBubble) {\n            // 冒泡到顶级 zrender 对象\n            this.trigger(eventName, eventPacket);\n            // 分发事件到用户自定义层\n            // 用户有可能在全局 click 事件中 dispose，所以需要判断下 painter 是否存在\n            this.painter && this.painter.eachOtherLayer(function (layer) {\n                if (typeof (layer[eventHandler]) === 'function') {\n                    layer[eventHandler].call(layer, eventPacket);\n                }\n                if (layer.trigger) {\n                    layer.trigger(eventName, eventPacket);\n                }\n            });\n        }\n    },\n\n    /**\n     * @private\n     * @param {number} x\n     * @param {number} y\n     * @param {module:zrender/graphic/Displayable} exclude\n     * @return {model:zrender/Element}\n     * @method\n     */\n    findHover: function (x, y, exclude) {\n        var list = this.storage.getDisplayList();\n        var out = {x: x, y: y};\n\n        for (var i = list.length - 1; i >= 0; i--) {\n            var hoverCheckResult;\n            if (list[i] !== exclude\n                // getDisplayList may include ignored item in VML mode\n                && !list[i].ignore\n                && (hoverCheckResult = isHover(list[i], x, y))\n            ) {\n                !out.topTarget && (out.topTarget = list[i]);\n                if (hoverCheckResult !== SILENT) {\n                    out.target = list[i];\n                    break;\n                }\n            }\n        }\n\n        return out;\n    },\n\n    processGesture: function (event, stage) {\n        if (!this._gestureMgr) {\n            this._gestureMgr = new GestureMgr();\n        }\n        var gestureMgr = this._gestureMgr;\n\n        stage === 'start' && gestureMgr.clear();\n\n        var gestureInfo = gestureMgr.recognize(\n            event,\n            this.findHover(event.zrX, event.zrY, null).target,\n            this.proxy.dom\n        );\n\n        stage === 'end' && gestureMgr.clear();\n\n        // Do not do any preventDefault here. Upper application do that if necessary.\n        if (gestureInfo) {\n            var type = gestureInfo.type;\n            event.gestureEvent = type;\n\n            this.dispatchToElement({target: gestureInfo.target}, type, gestureInfo.event);\n        }\n    }\n};\n\n// Common handlers\neach$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {\n    Handler.prototype[name] = function (event) {\n        // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover\n        var hovered = this.findHover(event.zrX, event.zrY);\n        var hoveredTarget = hovered.target;\n\n        if (name === 'mousedown') {\n            this._downEl = hoveredTarget;\n            this._downPoint = [event.zrX, event.zrY];\n            // In case click triggered before mouseup\n            this._upEl = hoveredTarget;\n        }\n        else if (name === 'mouseup') {\n            this._upEl = hoveredTarget;\n        }\n        else if (name === 'click') {\n            if (this._downEl !== this._upEl\n                // Original click event is triggered on the whole canvas element,\n                // including the case that `mousedown` - `mousemove` - `mouseup`,\n                // which should be filtered, otherwise it will bring trouble to\n                // pan and zoom.\n                || !this._downPoint\n                // Arbitrary value\n                || dist(this._downPoint, [event.zrX, event.zrY]) > 4\n            ) {\n                return;\n            }\n            this._downPoint = null;\n        }\n\n        this.dispatchToElement(hovered, name, event);\n    };\n});\n\nfunction isHover(displayable, x, y) {\n    if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) {\n        var el = displayable;\n        var isSilent;\n        while (el) {\n            // If clipped by ancestor.\n            // FIXME: If clipPath has neither stroke nor fill,\n            // el.clipPath.contain(x, y) will always return false.\n            if (el.clipPath && !el.clipPath.contain(x, y)) {\n                return false;\n            }\n            if (el.silent) {\n                isSilent = true;\n            }\n            el = el.parent;\n        }\n        return isSilent ? SILENT : true;\n    }\n\n    return false;\n}\n\nmixin(Handler, Eventful);\nmixin(Handler, Draggable);\n\n/**\n * 3x2矩阵操作类\n * @exports zrender/tool/matrix\n */\n\nvar ArrayCtor$1 = typeof Float32Array === 'undefined'\n    ? Array\n    : Float32Array;\n\n/**\n * Create a identity matrix.\n * @return {Float32Array|Array.<number>}\n */\nfunction create$1() {\n    var out = new ArrayCtor$1(6);\n    identity(out);\n\n    return out;\n}\n\n/**\n * 设置矩阵为单位矩阵\n * @param {Float32Array|Array.<number>} out\n */\nfunction identity(out) {\n    out[0] = 1;\n    out[1] = 0;\n    out[2] = 0;\n    out[3] = 1;\n    out[4] = 0;\n    out[5] = 0;\n    return out;\n}\n\n/**\n * 复制矩阵\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} m\n */\nfunction copy$1(out, m) {\n    out[0] = m[0];\n    out[1] = m[1];\n    out[2] = m[2];\n    out[3] = m[3];\n    out[4] = m[4];\n    out[5] = m[5];\n    return out;\n}\n\n/**\n * 矩阵相乘\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} m1\n * @param {Float32Array|Array.<number>} m2\n */\nfunction mul$1(out, m1, m2) {\n    // Consider matrix.mul(m, m2, m);\n    // where out is the same as m2.\n    // So use temp variable to escape error.\n    var out0 = m1[0] * m2[0] + m1[2] * m2[1];\n    var out1 = m1[1] * m2[0] + m1[3] * m2[1];\n    var out2 = m1[0] * m2[2] + m1[2] * m2[3];\n    var out3 = m1[1] * m2[2] + m1[3] * m2[3];\n    var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];\n    var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];\n    out[0] = out0;\n    out[1] = out1;\n    out[2] = out2;\n    out[3] = out3;\n    out[4] = out4;\n    out[5] = out5;\n    return out;\n}\n\n/**\n * 平移变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {Float32Array|Array.<number>} v\n */\nfunction translate(out, a, v) {\n    out[0] = a[0];\n    out[1] = a[1];\n    out[2] = a[2];\n    out[3] = a[3];\n    out[4] = a[4] + v[0];\n    out[5] = a[5] + v[1];\n    return out;\n}\n\n/**\n * 旋转变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {number} rad\n */\nfunction rotate(out, a, rad) {\n    var aa = a[0];\n    var ac = a[2];\n    var atx = a[4];\n    var ab = a[1];\n    var ad = a[3];\n    var aty = a[5];\n    var st = Math.sin(rad);\n    var ct = Math.cos(rad);\n\n    out[0] = aa * ct + ab * st;\n    out[1] = -aa * st + ab * ct;\n    out[2] = ac * ct + ad * st;\n    out[3] = -ac * st + ct * ad;\n    out[4] = ct * atx + st * aty;\n    out[5] = ct * aty - st * atx;\n    return out;\n}\n\n/**\n * 缩放变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {Float32Array|Array.<number>} v\n */\nfunction scale$1(out, a, v) {\n    var vx = v[0];\n    var vy = v[1];\n    out[0] = a[0] * vx;\n    out[1] = a[1] * vy;\n    out[2] = a[2] * vx;\n    out[3] = a[3] * vy;\n    out[4] = a[4] * vx;\n    out[5] = a[5] * vy;\n    return out;\n}\n\n/**\n * 求逆矩阵\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n */\nfunction invert(out, a) {\n\n    var aa = a[0];\n    var ac = a[2];\n    var atx = a[4];\n    var ab = a[1];\n    var ad = a[3];\n    var aty = a[5];\n\n    var det = aa * ad - ab * ac;\n    if (!det) {\n        return null;\n    }\n    det = 1.0 / det;\n\n    out[0] = ad * det;\n    out[1] = -ab * det;\n    out[2] = -ac * det;\n    out[3] = aa * det;\n    out[4] = (ac * aty - ad * atx) * det;\n    out[5] = (ab * atx - aa * aty) * det;\n    return out;\n}\n\n/**\n * Clone a new matrix.\n * @param {Float32Array|Array.<number>} a\n */\nfunction clone$2(a) {\n    var b = create$1();\n    copy$1(b, a);\n    return b;\n}\n\nvar matrix = (Object.freeze || Object)({\n\tcreate: create$1,\n\tidentity: identity,\n\tcopy: copy$1,\n\tmul: mul$1,\n\ttranslate: translate,\n\trotate: rotate,\n\tscale: scale$1,\n\tinvert: invert,\n\tclone: clone$2\n});\n\n/**\n * 提供变换扩展\n * @module zrender/mixin/Transformable\n * @author pissang (https://www.github.com/pissang)\n */\n\nvar mIdentity = identity;\n\nvar EPSILON = 5e-5;\n\nfunction isNotAroundZero(val) {\n    return val > EPSILON || val < -EPSILON;\n}\n\n/**\n * @alias module:zrender/mixin/Transformable\n * @constructor\n */\nvar Transformable = function (opts) {\n    opts = opts || {};\n    // If there are no given position, rotation, scale\n    if (!opts.position) {\n        /**\n         * 平移\n         * @type {Array.<number>}\n         * @default [0, 0]\n         */\n        this.position = [0, 0];\n    }\n    if (opts.rotation == null) {\n        /**\n         * 旋转\n         * @type {Array.<number>}\n         * @default 0\n         */\n        this.rotation = 0;\n    }\n    if (!opts.scale) {\n        /**\n         * 缩放\n         * @type {Array.<number>}\n         * @default [1, 1]\n         */\n        this.scale = [1, 1];\n    }\n    /**\n     * 旋转和缩放的原点\n     * @type {Array.<number>}\n     * @default null\n     */\n    this.origin = this.origin || null;\n};\n\nvar transformableProto = Transformable.prototype;\ntransformableProto.transform = null;\n\n/**\n * 判断是否需要有坐标变换\n * 如果有坐标变换, 则从position, rotation, scale以及父节点的transform计算出自身的transform矩阵\n */\ntransformableProto.needLocalTransform = function () {\n    return isNotAroundZero(this.rotation)\n        || isNotAroundZero(this.position[0])\n        || isNotAroundZero(this.position[1])\n        || isNotAroundZero(this.scale[0] - 1)\n        || isNotAroundZero(this.scale[1] - 1);\n};\n\nvar scaleTmp = [];\ntransformableProto.updateTransform = function () {\n    var parent = this.parent;\n    var parentHasTransform = parent && parent.transform;\n    var needLocalTransform = this.needLocalTransform();\n\n    var m = this.transform;\n    if (!(needLocalTransform || parentHasTransform)) {\n        m && mIdentity(m);\n        return;\n    }\n\n    m = m || create$1();\n\n    if (needLocalTransform) {\n        this.getLocalTransform(m);\n    }\n    else {\n        mIdentity(m);\n    }\n\n    // 应用父节点变换\n    if (parentHasTransform) {\n        if (needLocalTransform) {\n            mul$1(m, parent.transform, m);\n        }\n        else {\n            copy$1(m, parent.transform);\n        }\n    }\n    // 保存这个变换矩阵\n    this.transform = m;\n\n    var globalScaleRatio = this.globalScaleRatio;\n    if (globalScaleRatio != null && globalScaleRatio !== 1) {\n        this.getGlobalScale(scaleTmp);\n        var relX = scaleTmp[0] < 0 ? -1 : 1;\n        var relY = scaleTmp[1] < 0 ? -1 : 1;\n        var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0;\n        var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0;\n\n        m[0] *= sx;\n        m[1] *= sx;\n        m[2] *= sy;\n        m[3] *= sy;\n    }\n\n    this.invTransform = this.invTransform || create$1();\n    invert(this.invTransform, m);\n};\n\ntransformableProto.getLocalTransform = function (m) {\n    return Transformable.getLocalTransform(this, m);\n};\n\n/**\n * 将自己的transform应用到context上\n * @param {CanvasRenderingContext2D} ctx\n */\ntransformableProto.setTransform = function (ctx) {\n    var m = this.transform;\n    var dpr = ctx.dpr || 1;\n    if (m) {\n        ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]);\n    }\n    else {\n        ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    }\n};\n\ntransformableProto.restoreTransform = function (ctx) {\n    var dpr = ctx.dpr || 1;\n    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n};\n\nvar tmpTransform = [];\nvar originTransform = create$1();\n\ntransformableProto.setLocalTransform = function (m) {\n    if (!m) {\n        // TODO return or set identity?\n        return;\n    }\n    var sx = m[0] * m[0] + m[1] * m[1];\n    var sy = m[2] * m[2] + m[3] * m[3];\n    var position = this.position;\n    var scale$$1 = this.scale;\n    if (isNotAroundZero(sx - 1)) {\n        sx = Math.sqrt(sx);\n    }\n    if (isNotAroundZero(sy - 1)) {\n        sy = Math.sqrt(sy);\n    }\n    if (m[0] < 0) {\n        sx = -sx;\n    }\n    if (m[3] < 0) {\n        sy = -sy;\n    }\n\n    position[0] = m[4];\n    position[1] = m[5];\n    scale$$1[0] = sx;\n    scale$$1[1] = sy;\n    this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);\n};\n/**\n * 分解`transform`矩阵到`position`, `rotation`, `scale`\n */\ntransformableProto.decomposeTransform = function () {\n    if (!this.transform) {\n        return;\n    }\n    var parent = this.parent;\n    var m = this.transform;\n    if (parent && parent.transform) {\n        // Get local transform and decompose them to position, scale, rotation\n        mul$1(tmpTransform, parent.invTransform, m);\n        m = tmpTransform;\n    }\n    var origin = this.origin;\n    if (origin && (origin[0] || origin[1])) {\n        originTransform[4] = origin[0];\n        originTransform[5] = origin[1];\n        mul$1(tmpTransform, m, originTransform);\n        tmpTransform[4] -= origin[0];\n        tmpTransform[5] -= origin[1];\n        m = tmpTransform;\n    }\n\n    this.setLocalTransform(m);\n};\n\n/**\n * Get global scale\n * @return {Array.<number>}\n */\ntransformableProto.getGlobalScale = function (out) {\n    var m = this.transform;\n    out = out || [];\n    if (!m) {\n        out[0] = 1;\n        out[1] = 1;\n        return out;\n    }\n    out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]);\n    out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]);\n    if (m[0] < 0) {\n        out[0] = -out[0];\n    }\n    if (m[3] < 0) {\n        out[1] = -out[1];\n    }\n    return out;\n};\n/**\n * 变换坐标位置到 shape 的局部坐标空间\n * @method\n * @param {number} x\n * @param {number} y\n * @return {Array.<number>}\n */\ntransformableProto.transformCoordToLocal = function (x, y) {\n    var v2 = [x, y];\n    var invTransform = this.invTransform;\n    if (invTransform) {\n        applyTransform(v2, v2, invTransform);\n    }\n    return v2;\n};\n\n/**\n * 变换局部坐标位置到全局坐标空间\n * @method\n * @param {number} x\n * @param {number} y\n * @return {Array.<number>}\n */\ntransformableProto.transformCoordToGlobal = function (x, y) {\n    var v2 = [x, y];\n    var transform = this.transform;\n    if (transform) {\n        applyTransform(v2, v2, transform);\n    }\n    return v2;\n};\n\n/**\n * @static\n * @param {Object} target\n * @param {Array.<number>} target.origin\n * @param {number} target.rotation\n * @param {Array.<number>} target.position\n * @param {Array.<number>} [m]\n */\nTransformable.getLocalTransform = function (target, m) {\n    m = m || [];\n    mIdentity(m);\n\n    var origin = target.origin;\n    var scale$$1 = target.scale || [1, 1];\n    var rotation = target.rotation || 0;\n    var position = target.position || [0, 0];\n\n    if (origin) {\n        // Translate to origin\n        m[4] -= origin[0];\n        m[5] -= origin[1];\n    }\n    scale$1(m, m, scale$$1);\n    if (rotation) {\n        rotate(m, m, rotation);\n    }\n    if (origin) {\n        // Translate back from origin\n        m[4] += origin[0];\n        m[5] += origin[1];\n    }\n\n    m[4] += position[0];\n    m[5] += position[1];\n\n    return m;\n};\n\n/**\n * 缓动代码来自 https://github.com/sole/tween.js/blob/master/src/Tween.js\n * @see http://sole.github.io/tween.js/examples/03_graphs.html\n * @exports zrender/animation/easing\n */\nvar easing = {\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    linear: function (k) {\n        return k;\n    },\n\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticIn: function (k) {\n        return k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticOut: function (k) {\n        return k * (2 - k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k;\n        }\n        return -0.5 * (--k * (k - 2) - 1);\n    },\n\n    // 三次方的缓动（t^3）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicIn: function (k) {\n        return k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicOut: function (k) {\n        return --k * k * k + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k;\n        }\n        return 0.5 * ((k -= 2) * k * k + 2);\n    },\n\n    // 四次方的缓动（t^4）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticIn: function (k) {\n        return k * k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticOut: function (k) {\n        return 1 - (--k * k * k * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k * k;\n        }\n        return -0.5 * ((k -= 2) * k * k * k - 2);\n    },\n\n    // 五次方的缓动（t^5）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticIn: function (k) {\n        return k * k * k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticOut: function (k) {\n        return --k * k * k * k * k + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k * k * k;\n        }\n        return 0.5 * ((k -= 2) * k * k * k * k + 2);\n    },\n\n    // 正弦曲线的缓动（sin(t)）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalIn: function (k) {\n        return 1 - Math.cos(k * Math.PI / 2);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalOut: function (k) {\n        return Math.sin(k * Math.PI / 2);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalInOut: function (k) {\n        return 0.5 * (1 - Math.cos(Math.PI * k));\n    },\n\n    // 指数曲线的缓动（2^t）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialIn: function (k) {\n        return k === 0 ? 0 : Math.pow(1024, k - 1);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialOut: function (k) {\n        return k === 1 ? 1 : 1 - Math.pow(2, -10 * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialInOut: function (k) {\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if ((k *= 2) < 1) {\n            return 0.5 * Math.pow(1024, k - 1);\n        }\n        return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);\n    },\n\n    // 圆形曲线的缓动（sqrt(1-t^2)）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularIn: function (k) {\n        return 1 - Math.sqrt(1 - k * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularOut: function (k) {\n        return Math.sqrt(1 - (--k * k));\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return -0.5 * (Math.sqrt(1 - k * k) - 1);\n        }\n        return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);\n    },\n\n    // 创建类似于弹簧在停止前来回振荡的动画\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticIn: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        return -(a * Math.pow(2, 10 * (k -= 1))\n                    * Math.sin((k - s) * (2 * Math.PI) / p));\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticOut: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        return (a * Math.pow(2, -10 * k)\n                    * Math.sin((k - s) * (2 * Math.PI) / p) + 1);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticInOut: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        if ((k *= 2) < 1) {\n            return -0.5 * (a * Math.pow(2, 10 * (k -= 1))\n                * Math.sin((k - s) * (2 * Math.PI) / p));\n        }\n        return a * Math.pow(2, -10 * (k -= 1))\n                * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;\n\n    },\n\n    // 在某一动画开始沿指示的路径进行动画处理前稍稍收回该动画的移动\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backIn: function (k) {\n        var s = 1.70158;\n        return k * k * ((s + 1) * k - s);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backOut: function (k) {\n        var s = 1.70158;\n        return --k * k * ((s + 1) * k + s) + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backInOut: function (k) {\n        var s = 1.70158 * 1.525;\n        if ((k *= 2) < 1) {\n            return 0.5 * (k * k * ((s + 1) * k - s));\n        }\n        return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);\n    },\n\n    // 创建弹跳效果\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceIn: function (k) {\n        return 1 - easing.bounceOut(1 - k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceOut: function (k) {\n        if (k < (1 / 2.75)) {\n            return 7.5625 * k * k;\n        }\n        else if (k < (2 / 2.75)) {\n            return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;\n        }\n        else if (k < (2.5 / 2.75)) {\n            return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;\n        }\n        else {\n            return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;\n        }\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceInOut: function (k) {\n        if (k < 0.5) {\n            return easing.bounceIn(k * 2) * 0.5;\n        }\n        return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;\n    }\n};\n\n/**\n * 动画主控制器\n * @config target 动画对象，可以是数组，如果是数组的话会批量分发onframe等事件\n * @config life(1000) 动画时长\n * @config delay(0) 动画延迟时间\n * @config loop(true)\n * @config gap(0) 循环的间隔时间\n * @config onframe\n * @config easing(optional)\n * @config ondestroy(optional)\n * @config onrestart(optional)\n *\n * TODO pause\n */\n\nfunction Clip(options) {\n\n    this._target = options.target;\n\n    // 生命周期\n    this._life = options.life || 1000;\n    // 延时\n    this._delay = options.delay || 0;\n    // 开始时间\n    // this._startTime = new Date().getTime() + this._delay;// 单位毫秒\n    this._initialized = false;\n\n    // 是否循环\n    this.loop = options.loop == null ? false : options.loop;\n\n    this.gap = options.gap || 0;\n\n    this.easing = options.easing || 'Linear';\n\n    this.onframe = options.onframe;\n    this.ondestroy = options.ondestroy;\n    this.onrestart = options.onrestart;\n\n    this._pausedTime = 0;\n    this._paused = false;\n}\n\nClip.prototype = {\n\n    constructor: Clip,\n\n    step: function (globalTime, deltaTime) {\n        // Set startTime on first step, or _startTime may has milleseconds different between clips\n        // PENDING\n        if (!this._initialized) {\n            this._startTime = globalTime + this._delay;\n            this._initialized = true;\n        }\n\n        if (this._paused) {\n            this._pausedTime += deltaTime;\n            return;\n        }\n\n        var percent = (globalTime - this._startTime - this._pausedTime) / this._life;\n\n        // 还没开始\n        if (percent < 0) {\n            return;\n        }\n\n        percent = Math.min(percent, 1);\n\n        var easing$$1 = this.easing;\n        var easingFunc = typeof easing$$1 === 'string' ? easing[easing$$1] : easing$$1;\n        var schedule = typeof easingFunc === 'function'\n            ? easingFunc(percent)\n            : percent;\n\n        this.fire('frame', schedule);\n\n        // 结束\n        if (percent === 1) {\n            if (this.loop) {\n                this.restart(globalTime);\n                // 重新开始周期\n                // 抛出而不是直接调用事件直到 stage.update 后再统一调用这些事件\n                return 'restart';\n            }\n\n            // 动画完成将这个控制器标识为待删除\n            // 在Animation.update中进行批量删除\n            this._needsRemove = true;\n            return 'destroy';\n        }\n\n        return null;\n    },\n\n    restart: function (globalTime) {\n        var remainder = (globalTime - this._startTime - this._pausedTime) % this._life;\n        this._startTime = globalTime - remainder + this.gap;\n        this._pausedTime = 0;\n\n        this._needsRemove = false;\n    },\n\n    fire: function (eventType, arg) {\n        eventType = 'on' + eventType;\n        if (this[eventType]) {\n            this[eventType](this._target, arg);\n        }\n    },\n\n    pause: function () {\n        this._paused = true;\n    },\n\n    resume: function () {\n        this._paused = false;\n    }\n};\n\n// Simple LRU cache use doubly linked list\n// @module zrender/core/LRU\n\n/**\n * Simple double linked list. Compared with array, it has O(1) remove operation.\n * @constructor\n */\nvar LinkedList = function () {\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.head = null;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.tail = null;\n\n    this._len = 0;\n};\n\nvar linkedListProto = LinkedList.prototype;\n/**\n * Insert a new value at the tail\n * @param  {} val\n * @return {module:zrender/core/LRU~Entry}\n */\nlinkedListProto.insert = function (val) {\n    var entry = new Entry(val);\n    this.insertEntry(entry);\n    return entry;\n};\n\n/**\n * Insert an entry at the tail\n * @param  {module:zrender/core/LRU~Entry} entry\n */\nlinkedListProto.insertEntry = function (entry) {\n    if (!this.head) {\n        this.head = this.tail = entry;\n    }\n    else {\n        this.tail.next = entry;\n        entry.prev = this.tail;\n        entry.next = null;\n        this.tail = entry;\n    }\n    this._len++;\n};\n\n/**\n * Remove entry.\n * @param  {module:zrender/core/LRU~Entry} entry\n */\nlinkedListProto.remove = function (entry) {\n    var prev = entry.prev;\n    var next = entry.next;\n    if (prev) {\n        prev.next = next;\n    }\n    else {\n        // Is head\n        this.head = next;\n    }\n    if (next) {\n        next.prev = prev;\n    }\n    else {\n        // Is tail\n        this.tail = prev;\n    }\n    entry.next = entry.prev = null;\n    this._len--;\n};\n\n/**\n * @return {number}\n */\nlinkedListProto.len = function () {\n    return this._len;\n};\n\n/**\n * Clear list\n */\nlinkedListProto.clear = function () {\n    this.head = this.tail = null;\n    this._len = 0;\n};\n\n/**\n * @constructor\n * @param {} val\n */\nvar Entry = function (val) {\n    /**\n     * @type {}\n     */\n    this.value = val;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.next;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.prev;\n};\n\n/**\n * LRU Cache\n * @constructor\n * @alias module:zrender/core/LRU\n */\nvar LRU = function (maxSize) {\n\n    this._list = new LinkedList();\n\n    this._map = {};\n\n    this._maxSize = maxSize || 10;\n\n    this._lastRemovedEntry = null;\n};\n\nvar LRUProto = LRU.prototype;\n\n/**\n * @param  {string} key\n * @param  {} value\n * @return {} Removed value\n */\nLRUProto.put = function (key, value) {\n    var list = this._list;\n    var map = this._map;\n    var removed = null;\n    if (map[key] == null) {\n        var len = list.len();\n        // Reuse last removed entry\n        var entry = this._lastRemovedEntry;\n\n        if (len >= this._maxSize && len > 0) {\n            // Remove the least recently used\n            var leastUsedEntry = list.head;\n            list.remove(leastUsedEntry);\n            delete map[leastUsedEntry.key];\n\n            removed = leastUsedEntry.value;\n            this._lastRemovedEntry = leastUsedEntry;\n        }\n\n        if (entry) {\n            entry.value = value;\n        }\n        else {\n            entry = new Entry(value);\n        }\n        entry.key = key;\n        list.insertEntry(entry);\n        map[key] = entry;\n    }\n\n    return removed;\n};\n\n/**\n * @param  {string} key\n * @return {}\n */\nLRUProto.get = function (key) {\n    var entry = this._map[key];\n    var list = this._list;\n    if (entry != null) {\n        // Put the latest used entry in the tail\n        if (entry !== list.tail) {\n            list.remove(entry);\n            list.insertEntry(entry);\n        }\n\n        return entry.value;\n    }\n};\n\n/**\n * Clear the cache\n */\nLRUProto.clear = function () {\n    this._list.clear();\n    this._map = {};\n};\n\nvar kCSSColorTable = {\n    'transparent': [0, 0, 0, 0], 'aliceblue': [240, 248, 255, 1],\n    'antiquewhite': [250, 235, 215, 1], 'aqua': [0, 255, 255, 1],\n    'aquamarine': [127, 255, 212, 1], 'azure': [240, 255, 255, 1],\n    'beige': [245, 245, 220, 1], 'bisque': [255, 228, 196, 1],\n    'black': [0, 0, 0, 1], 'blanchedalmond': [255, 235, 205, 1],\n    'blue': [0, 0, 255, 1], 'blueviolet': [138, 43, 226, 1],\n    'brown': [165, 42, 42, 1], 'burlywood': [222, 184, 135, 1],\n    'cadetblue': [95, 158, 160, 1], 'chartreuse': [127, 255, 0, 1],\n    'chocolate': [210, 105, 30, 1], 'coral': [255, 127, 80, 1],\n    'cornflowerblue': [100, 149, 237, 1], 'cornsilk': [255, 248, 220, 1],\n    'crimson': [220, 20, 60, 1], 'cyan': [0, 255, 255, 1],\n    'darkblue': [0, 0, 139, 1], 'darkcyan': [0, 139, 139, 1],\n    'darkgoldenrod': [184, 134, 11, 1], 'darkgray': [169, 169, 169, 1],\n    'darkgreen': [0, 100, 0, 1], 'darkgrey': [169, 169, 169, 1],\n    'darkkhaki': [189, 183, 107, 1], 'darkmagenta': [139, 0, 139, 1],\n    'darkolivegreen': [85, 107, 47, 1], 'darkorange': [255, 140, 0, 1],\n    'darkorchid': [153, 50, 204, 1], 'darkred': [139, 0, 0, 1],\n    'darksalmon': [233, 150, 122, 1], 'darkseagreen': [143, 188, 143, 1],\n    'darkslateblue': [72, 61, 139, 1], 'darkslategray': [47, 79, 79, 1],\n    'darkslategrey': [47, 79, 79, 1], 'darkturquoise': [0, 206, 209, 1],\n    'darkviolet': [148, 0, 211, 1], 'deeppink': [255, 20, 147, 1],\n    'deepskyblue': [0, 191, 255, 1], 'dimgray': [105, 105, 105, 1],\n    'dimgrey': [105, 105, 105, 1], 'dodgerblue': [30, 144, 255, 1],\n    'firebrick': [178, 34, 34, 1], 'floralwhite': [255, 250, 240, 1],\n    'forestgreen': [34, 139, 34, 1], 'fuchsia': [255, 0, 255, 1],\n    'gainsboro': [220, 220, 220, 1], 'ghostwhite': [248, 248, 255, 1],\n    'gold': [255, 215, 0, 1], 'goldenrod': [218, 165, 32, 1],\n    'gray': [128, 128, 128, 1], 'green': [0, 128, 0, 1],\n    'greenyellow': [173, 255, 47, 1], 'grey': [128, 128, 128, 1],\n    'honeydew': [240, 255, 240, 1], 'hotpink': [255, 105, 180, 1],\n    'indianred': [205, 92, 92, 1], 'indigo': [75, 0, 130, 1],\n    'ivory': [255, 255, 240, 1], 'khaki': [240, 230, 140, 1],\n    'lavender': [230, 230, 250, 1], 'lavenderblush': [255, 240, 245, 1],\n    'lawngreen': [124, 252, 0, 1], 'lemonchiffon': [255, 250, 205, 1],\n    'lightblue': [173, 216, 230, 1], 'lightcoral': [240, 128, 128, 1],\n    'lightcyan': [224, 255, 255, 1], 'lightgoldenrodyellow': [250, 250, 210, 1],\n    'lightgray': [211, 211, 211, 1], 'lightgreen': [144, 238, 144, 1],\n    'lightgrey': [211, 211, 211, 1], 'lightpink': [255, 182, 193, 1],\n    'lightsalmon': [255, 160, 122, 1], 'lightseagreen': [32, 178, 170, 1],\n    'lightskyblue': [135, 206, 250, 1], 'lightslategray': [119, 136, 153, 1],\n    'lightslategrey': [119, 136, 153, 1], 'lightsteelblue': [176, 196, 222, 1],\n    'lightyellow': [255, 255, 224, 1], 'lime': [0, 255, 0, 1],\n    'limegreen': [50, 205, 50, 1], 'linen': [250, 240, 230, 1],\n    'magenta': [255, 0, 255, 1], 'maroon': [128, 0, 0, 1],\n    'mediumaquamarine': [102, 205, 170, 1], 'mediumblue': [0, 0, 205, 1],\n    'mediumorchid': [186, 85, 211, 1], 'mediumpurple': [147, 112, 219, 1],\n    'mediumseagreen': [60, 179, 113, 1], 'mediumslateblue': [123, 104, 238, 1],\n    'mediumspringgreen': [0, 250, 154, 1], 'mediumturquoise': [72, 209, 204, 1],\n    'mediumvioletred': [199, 21, 133, 1], 'midnightblue': [25, 25, 112, 1],\n    'mintcream': [245, 255, 250, 1], 'mistyrose': [255, 228, 225, 1],\n    'moccasin': [255, 228, 181, 1], 'navajowhite': [255, 222, 173, 1],\n    'navy': [0, 0, 128, 1], 'oldlace': [253, 245, 230, 1],\n    'olive': [128, 128, 0, 1], 'olivedrab': [107, 142, 35, 1],\n    'orange': [255, 165, 0, 1], 'orangered': [255, 69, 0, 1],\n    'orchid': [218, 112, 214, 1], 'palegoldenrod': [238, 232, 170, 1],\n    'palegreen': [152, 251, 152, 1], 'paleturquoise': [175, 238, 238, 1],\n    'palevioletred': [219, 112, 147, 1], 'papayawhip': [255, 239, 213, 1],\n    'peachpuff': [255, 218, 185, 1], 'peru': [205, 133, 63, 1],\n    'pink': [255, 192, 203, 1], 'plum': [221, 160, 221, 1],\n    'powderblue': [176, 224, 230, 1], 'purple': [128, 0, 128, 1],\n    'red': [255, 0, 0, 1], 'rosybrown': [188, 143, 143, 1],\n    'royalblue': [65, 105, 225, 1], 'saddlebrown': [139, 69, 19, 1],\n    'salmon': [250, 128, 114, 1], 'sandybrown': [244, 164, 96, 1],\n    'seagreen': [46, 139, 87, 1], 'seashell': [255, 245, 238, 1],\n    'sienna': [160, 82, 45, 1], 'silver': [192, 192, 192, 1],\n    'skyblue': [135, 206, 235, 1], 'slateblue': [106, 90, 205, 1],\n    'slategray': [112, 128, 144, 1], 'slategrey': [112, 128, 144, 1],\n    'snow': [255, 250, 250, 1], 'springgreen': [0, 255, 127, 1],\n    'steelblue': [70, 130, 180, 1], 'tan': [210, 180, 140, 1],\n    'teal': [0, 128, 128, 1], 'thistle': [216, 191, 216, 1],\n    'tomato': [255, 99, 71, 1], 'turquoise': [64, 224, 208, 1],\n    'violet': [238, 130, 238, 1], 'wheat': [245, 222, 179, 1],\n    'white': [255, 255, 255, 1], 'whitesmoke': [245, 245, 245, 1],\n    'yellow': [255, 255, 0, 1], 'yellowgreen': [154, 205, 50, 1]\n};\n\nfunction clampCssByte(i) {  // Clamp to integer 0 .. 255.\n    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).\n    return i < 0 ? 0 : i > 255 ? 255 : i;\n}\n\nfunction clampCssAngle(i) {  // Clamp to integer 0 .. 360.\n    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).\n    return i < 0 ? 0 : i > 360 ? 360 : i;\n}\n\nfunction clampCssFloat(f) {  // Clamp to float 0.0 .. 1.0.\n    return f < 0 ? 0 : f > 1 ? 1 : f;\n}\n\nfunction parseCssInt(str) {  // int or percentage.\n    if (str.length && str.charAt(str.length - 1) === '%') {\n        return clampCssByte(parseFloat(str) / 100 * 255);\n    }\n    return clampCssByte(parseInt(str, 10));\n}\n\nfunction parseCssFloat(str) {  // float or percentage.\n    if (str.length && str.charAt(str.length - 1) === '%') {\n        return clampCssFloat(parseFloat(str) / 100);\n    }\n    return clampCssFloat(parseFloat(str));\n}\n\nfunction cssHueToRgb(m1, m2, h) {\n    if (h < 0) {\n        h += 1;\n    }\n    else if (h > 1) {\n        h -= 1;\n    }\n\n    if (h * 6 < 1) {\n        return m1 + (m2 - m1) * h * 6;\n    }\n    if (h * 2 < 1) {\n        return m2;\n    }\n    if (h * 3 < 2) {\n        return m1 + (m2 - m1) * (2 / 3 - h) * 6;\n    }\n    return m1;\n}\n\nfunction lerpNumber(a, b, p) {\n    return a + (b - a) * p;\n}\n\nfunction setRgba(out, r, g, b, a) {\n    out[0] = r; out[1] = g; out[2] = b; out[3] = a;\n    return out;\n}\nfunction copyRgba(out, a) {\n    out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3];\n    return out;\n}\n\nvar colorCache = new LRU(20);\nvar lastRemovedArr = null;\n\nfunction putToCache(colorStr, rgbaArr) {\n    // Reuse removed array\n    if (lastRemovedArr) {\n        copyRgba(lastRemovedArr, rgbaArr);\n    }\n    lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice()));\n}\n\n/**\n * @param {string} colorStr\n * @param {Array.<number>} out\n * @return {Array.<number>}\n * @memberOf module:zrender/util/color\n */\nfunction parse(colorStr, rgbaArr) {\n    if (!colorStr) {\n        return;\n    }\n    rgbaArr = rgbaArr || [];\n\n    var cached = colorCache.get(colorStr);\n    if (cached) {\n        return copyRgba(rgbaArr, cached);\n    }\n\n    // colorStr may be not string\n    colorStr = colorStr + '';\n    // Remove all whitespace, not compliant, but should just be more accepting.\n    var str = colorStr.replace(/ /g, '').toLowerCase();\n\n    // Color keywords (and transparent) lookup.\n    if (str in kCSSColorTable) {\n        copyRgba(rgbaArr, kCSSColorTable[str]);\n        putToCache(colorStr, rgbaArr);\n        return rgbaArr;\n    }\n\n    // #abc and #abc123 syntax.\n    if (str.charAt(0) === '#') {\n        if (str.length === 4) {\n            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n            if (!(iv >= 0 && iv <= 0xfff)) {\n                setRgba(rgbaArr, 0, 0, 0, 1);\n                return;  // Covers NaN.\n            }\n            setRgba(rgbaArr,\n                ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8),\n                (iv & 0xf0) | ((iv & 0xf0) >> 4),\n                (iv & 0xf) | ((iv & 0xf) << 4),\n                1\n            );\n            putToCache(colorStr, rgbaArr);\n            return rgbaArr;\n        }\n        else if (str.length === 7) {\n            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n            if (!(iv >= 0 && iv <= 0xffffff)) {\n                setRgba(rgbaArr, 0, 0, 0, 1);\n                return;  // Covers NaN.\n            }\n            setRgba(rgbaArr,\n                (iv & 0xff0000) >> 16,\n                (iv & 0xff00) >> 8,\n                iv & 0xff,\n                1\n            );\n            putToCache(colorStr, rgbaArr);\n            return rgbaArr;\n        }\n\n        return;\n    }\n    var op = str.indexOf('(');\n    var ep = str.indexOf(')');\n    if (op !== -1 && ep + 1 === str.length) {\n        var fname = str.substr(0, op);\n        var params = str.substr(op + 1, ep - (op + 1)).split(',');\n        var alpha = 1;  // To allow case fallthrough.\n        switch (fname) {\n            case 'rgba':\n                if (params.length !== 4) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                alpha = parseCssFloat(params.pop()); // jshint ignore:line\n            // Fall through.\n            case 'rgb':\n                if (params.length !== 3) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                setRgba(rgbaArr,\n                    parseCssInt(params[0]),\n                    parseCssInt(params[1]),\n                    parseCssInt(params[2]),\n                    alpha\n                );\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            case 'hsla':\n                if (params.length !== 4) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                params[3] = parseCssFloat(params[3]);\n                hsla2rgba(params, rgbaArr);\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            case 'hsl':\n                if (params.length !== 3) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                hsla2rgba(params, rgbaArr);\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            default:\n                return;\n        }\n    }\n\n    setRgba(rgbaArr, 0, 0, 0, 1);\n    return;\n}\n\n/**\n * @param {Array.<number>} hsla\n * @param {Array.<number>} rgba\n * @return {Array.<number>} rgba\n */\nfunction hsla2rgba(hsla, rgba) {\n    var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360;  // 0 .. 1\n    // NOTE(deanm): According to the CSS spec s/l should only be\n    // percentages, but we don't bother and let float or percentage.\n    var s = parseCssFloat(hsla[1]);\n    var l = parseCssFloat(hsla[2]);\n    var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;\n    var m1 = l * 2 - m2;\n\n    rgba = rgba || [];\n    setRgba(rgba,\n        clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255),\n        clampCssByte(cssHueToRgb(m1, m2, h) * 255),\n        clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255),\n        1\n    );\n\n    if (hsla.length === 4) {\n        rgba[3] = hsla[3];\n    }\n\n    return rgba;\n}\n\n/**\n * @param {Array.<number>} rgba\n * @return {Array.<number>} hsla\n */\nfunction rgba2hsla(rgba) {\n    if (!rgba) {\n        return;\n    }\n\n    // RGB from 0 to 255\n    var R = rgba[0] / 255;\n    var G = rgba[1] / 255;\n    var B = rgba[2] / 255;\n\n    var vMin = Math.min(R, G, B); // Min. value of RGB\n    var vMax = Math.max(R, G, B); // Max. value of RGB\n    var delta = vMax - vMin; // Delta RGB value\n\n    var L = (vMax + vMin) / 2;\n    var H;\n    var S;\n    // HSL results from 0 to 1\n    if (delta === 0) {\n        H = 0;\n        S = 0;\n    }\n    else {\n        if (L < 0.5) {\n            S = delta / (vMax + vMin);\n        }\n        else {\n            S = delta / (2 - vMax - vMin);\n        }\n\n        var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta;\n        var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta;\n        var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta;\n\n        if (R === vMax) {\n            H = deltaB - deltaG;\n        }\n        else if (G === vMax) {\n            H = (1 / 3) + deltaR - deltaB;\n        }\n        else if (B === vMax) {\n            H = (2 / 3) + deltaG - deltaR;\n        }\n\n        if (H < 0) {\n            H += 1;\n        }\n\n        if (H > 1) {\n            H -= 1;\n        }\n    }\n\n    var hsla = [H * 360, S, L];\n\n    if (rgba[3] != null) {\n        hsla.push(rgba[3]);\n    }\n\n    return hsla;\n}\n\n/**\n * @param {string} color\n * @param {number} level\n * @return {string}\n * @memberOf module:zrender/util/color\n */\nfunction lift(color, level) {\n    var colorArr = parse(color);\n    if (colorArr) {\n        for (var i = 0; i < 3; i++) {\n            if (level < 0) {\n                colorArr[i] = colorArr[i] * (1 - level) | 0;\n            }\n            else {\n                colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0;\n            }\n            if (colorArr[i] > 255) {\n                colorArr[i] = 255;\n            }\n            else if (color[i] < 0) {\n                colorArr[i] = 0;\n            }\n        }\n        return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');\n    }\n}\n\n/**\n * @param {string} color\n * @return {string}\n * @memberOf module:zrender/util/color\n */\nfunction toHex(color) {\n    var colorArr = parse(color);\n    if (colorArr) {\n        return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1);\n    }\n}\n\n/**\n * Map value to color. Faster than lerp methods because color is represented by rgba array.\n * @param {number} normalizedValue A float between 0 and 1.\n * @param {Array.<Array.<number>>} colors List of rgba color array\n * @param {Array.<number>} [out] Mapped gba color array\n * @return {Array.<number>} will be null/undefined if input illegal.\n */\nfunction fastLerp(normalizedValue, colors, out) {\n    if (!(colors && colors.length)\n        || !(normalizedValue >= 0 && normalizedValue <= 1)\n    ) {\n        return;\n    }\n\n    out = out || [];\n\n    var value = normalizedValue * (colors.length - 1);\n    var leftIndex = Math.floor(value);\n    var rightIndex = Math.ceil(value);\n    var leftColor = colors[leftIndex];\n    var rightColor = colors[rightIndex];\n    var dv = value - leftIndex;\n    out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv));\n    out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv));\n    out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv));\n    out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv));\n\n    return out;\n}\n\n/**\n * @deprecated\n */\nvar fastMapToColor = fastLerp;\n\n/**\n * @param {number} normalizedValue A float between 0 and 1.\n * @param {Array.<string>} colors Color list.\n * @param {boolean=} fullOutput Default false.\n * @return {(string|Object)} Result color. If fullOutput,\n *                           return {color: ..., leftIndex: ..., rightIndex: ..., value: ...},\n * @memberOf module:zrender/util/color\n */\nfunction lerp$1(normalizedValue, colors, fullOutput) {\n    if (!(colors && colors.length)\n        || !(normalizedValue >= 0 && normalizedValue <= 1)\n    ) {\n        return;\n    }\n\n    var value = normalizedValue * (colors.length - 1);\n    var leftIndex = Math.floor(value);\n    var rightIndex = Math.ceil(value);\n    var leftColor = parse(colors[leftIndex]);\n    var rightColor = parse(colors[rightIndex]);\n    var dv = value - leftIndex;\n\n    var color = stringify(\n        [\n            clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)),\n            clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)),\n            clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)),\n            clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv))\n        ],\n        'rgba'\n    );\n\n    return fullOutput\n        ? {\n            color: color,\n            leftIndex: leftIndex,\n            rightIndex: rightIndex,\n            value: value\n        }\n        : color;\n}\n\n/**\n * @deprecated\n */\nvar mapToColor = lerp$1;\n\n/**\n * @param {string} color\n * @param {number=} h 0 ~ 360, ignore when null.\n * @param {number=} s 0 ~ 1, ignore when null.\n * @param {number=} l 0 ~ 1, ignore when null.\n * @return {string} Color string in rgba format.\n * @memberOf module:zrender/util/color\n */\nfunction modifyHSL(color, h, s, l) {\n    color = parse(color);\n\n    if (color) {\n        color = rgba2hsla(color);\n        h != null && (color[0] = clampCssAngle(h));\n        s != null && (color[1] = parseCssFloat(s));\n        l != null && (color[2] = parseCssFloat(l));\n\n        return stringify(hsla2rgba(color), 'rgba');\n    }\n}\n\n/**\n * @param {string} color\n * @param {number=} alpha 0 ~ 1\n * @return {string} Color string in rgba format.\n * @memberOf module:zrender/util/color\n */\nfunction modifyAlpha(color, alpha) {\n    color = parse(color);\n\n    if (color && alpha != null) {\n        color[3] = clampCssFloat(alpha);\n        return stringify(color, 'rgba');\n    }\n}\n\n/**\n * @param {Array.<number>} arrColor like [12,33,44,0.4]\n * @param {string} type 'rgba', 'hsva', ...\n * @return {string} Result color. (If input illegal, return undefined).\n */\nfunction stringify(arrColor, type) {\n    if (!arrColor || !arrColor.length) {\n        return;\n    }\n    var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];\n    if (type === 'rgba' || type === 'hsva' || type === 'hsla') {\n        colorStr += ',' + arrColor[3];\n    }\n    return type + '(' + colorStr + ')';\n}\n\n\nvar color = (Object.freeze || Object)({\n\tparse: parse,\n\tlift: lift,\n\ttoHex: toHex,\n\tfastLerp: fastLerp,\n\tfastMapToColor: fastMapToColor,\n\tlerp: lerp$1,\n\tmapToColor: mapToColor,\n\tmodifyHSL: modifyHSL,\n\tmodifyAlpha: modifyAlpha,\n\tstringify: stringify\n});\n\n/**\n * @module echarts/animation/Animator\n */\n\nvar arraySlice = Array.prototype.slice;\n\nfunction defaultGetter(target, key) {\n    return target[key];\n}\n\nfunction defaultSetter(target, key, value) {\n    target[key] = value;\n}\n\n/**\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} percent\n * @return {number}\n */\nfunction interpolateNumber(p0, p1, percent) {\n    return (p1 - p0) * percent + p0;\n}\n\n/**\n * @param  {string} p0\n * @param  {string} p1\n * @param  {number} percent\n * @return {string}\n */\nfunction interpolateString(p0, p1, percent) {\n    return percent > 0.5 ? p1 : p0;\n}\n\n/**\n * @param  {Array} p0\n * @param  {Array} p1\n * @param  {number} percent\n * @param  {Array} out\n * @param  {number} arrDim\n */\nfunction interpolateArray(p0, p1, percent, out, arrDim) {\n    var len = p0.length;\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            out[i] = interpolateNumber(p0[i], p1[i], percent);\n        }\n    }\n    else {\n        var len2 = len && p0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                out[i][j] = interpolateNumber(\n                    p0[i][j], p1[i][j], percent\n                );\n            }\n        }\n    }\n}\n\n// arr0 is source array, arr1 is target array.\n// Do some preprocess to avoid error happened when interpolating from arr0 to arr1\nfunction fillArr(arr0, arr1, arrDim) {\n    var arr0Len = arr0.length;\n    var arr1Len = arr1.length;\n    if (arr0Len !== arr1Len) {\n        // FIXME Not work for TypedArray\n        var isPreviousLarger = arr0Len > arr1Len;\n        if (isPreviousLarger) {\n            // Cut the previous\n            arr0.length = arr1Len;\n        }\n        else {\n            // Fill the previous\n            for (var i = arr0Len; i < arr1Len; i++) {\n                arr0.push(\n                    arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i])\n                );\n            }\n        }\n    }\n    // Handling NaN value\n    var len2 = arr0[0] && arr0[0].length;\n    for (var i = 0; i < arr0.length; i++) {\n        if (arrDim === 1) {\n            if (isNaN(arr0[i])) {\n                arr0[i] = arr1[i];\n            }\n        }\n        else {\n            for (var j = 0; j < len2; j++) {\n                if (isNaN(arr0[i][j])) {\n                    arr0[i][j] = arr1[i][j];\n                }\n            }\n        }\n    }\n}\n\n/**\n * @param  {Array} arr0\n * @param  {Array} arr1\n * @param  {number} arrDim\n * @return {boolean}\n */\nfunction isArraySame(arr0, arr1, arrDim) {\n    if (arr0 === arr1) {\n        return true;\n    }\n    var len = arr0.length;\n    if (len !== arr1.length) {\n        return false;\n    }\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            if (arr0[i] !== arr1[i]) {\n                return false;\n            }\n        }\n    }\n    else {\n        var len2 = arr0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                if (arr0[i][j] !== arr1[i][j]) {\n                    return false;\n                }\n            }\n        }\n    }\n    return true;\n}\n\n/**\n * Catmull Rom interpolate array\n * @param  {Array} p0\n * @param  {Array} p1\n * @param  {Array} p2\n * @param  {Array} p3\n * @param  {number} t\n * @param  {number} t2\n * @param  {number} t3\n * @param  {Array} out\n * @param  {number} arrDim\n */\nfunction catmullRomInterpolateArray(\n    p0, p1, p2, p3, t, t2, t3, out, arrDim\n) {\n    var len = p0.length;\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            out[i] = catmullRomInterpolate(\n                p0[i], p1[i], p2[i], p3[i], t, t2, t3\n            );\n        }\n    }\n    else {\n        var len2 = p0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                out[i][j] = catmullRomInterpolate(\n                    p0[i][j], p1[i][j], p2[i][j], p3[i][j],\n                    t, t2, t3\n                );\n            }\n        }\n    }\n}\n\n/**\n * Catmull Rom interpolate number\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @param  {number} t2\n * @param  {number} t3\n * @return {number}\n */\nfunction catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {\n    var v0 = (p2 - p0) * 0.5;\n    var v1 = (p3 - p1) * 0.5;\n    return (2 * (p1 - p2) + v0 + v1) * t3\n            + (-3 * (p1 - p2) - 2 * v0 - v1) * t2\n            + v0 * t + p1;\n}\n\nfunction cloneValue(value) {\n    if (isArrayLike(value)) {\n        var len = value.length;\n        if (isArrayLike(value[0])) {\n            var ret = [];\n            for (var i = 0; i < len; i++) {\n                ret.push(arraySlice.call(value[i]));\n            }\n            return ret;\n        }\n\n        return arraySlice.call(value);\n    }\n\n    return value;\n}\n\nfunction rgba2String(rgba) {\n    rgba[0] = Math.floor(rgba[0]);\n    rgba[1] = Math.floor(rgba[1]);\n    rgba[2] = Math.floor(rgba[2]);\n\n    return 'rgba(' + rgba.join(',') + ')';\n}\n\nfunction getArrayDim(keyframes) {\n    var lastValue = keyframes[keyframes.length - 1].value;\n    return isArrayLike(lastValue && lastValue[0]) ? 2 : 1;\n}\n\nfunction createTrackClip(animator, easing, oneTrackDone, keyframes, propName, forceAnimate) {\n    var getter = animator._getter;\n    var setter = animator._setter;\n    var useSpline = easing === 'spline';\n\n    var trackLen = keyframes.length;\n    if (!trackLen) {\n        return;\n    }\n    // Guess data type\n    var firstVal = keyframes[0].value;\n    var isValueArray = isArrayLike(firstVal);\n    var isValueColor = false;\n    var isValueString = false;\n\n    // For vertices morphing\n    var arrDim = isValueArray ? getArrayDim(keyframes) : 0;\n\n    var trackMaxTime;\n    // Sort keyframe as ascending\n    keyframes.sort(function (a, b) {\n        return a.time - b.time;\n    });\n\n    trackMaxTime = keyframes[trackLen - 1].time;\n    // Percents of each keyframe\n    var kfPercents = [];\n    // Value of each keyframe\n    var kfValues = [];\n    var prevValue = keyframes[0].value;\n    var isAllValueEqual = true;\n    for (var i = 0; i < trackLen; i++) {\n        kfPercents.push(keyframes[i].time / trackMaxTime);\n        // Assume value is a color when it is a string\n        var value = keyframes[i].value;\n\n        // Check if value is equal, deep check if value is array\n        if (!((isValueArray && isArraySame(value, prevValue, arrDim))\n            || (!isValueArray && value === prevValue))) {\n            isAllValueEqual = false;\n        }\n        prevValue = value;\n\n        // Try converting a string to a color array\n        if (typeof value === 'string') {\n            var colorArray = parse(value);\n            if (colorArray) {\n                value = colorArray;\n                isValueColor = true;\n            }\n            else {\n                isValueString = true;\n            }\n        }\n        kfValues.push(value);\n    }\n    if (!forceAnimate && isAllValueEqual) {\n        return;\n    }\n\n    var lastValue = kfValues[trackLen - 1];\n    // Polyfill array and NaN value\n    for (var i = 0; i < trackLen - 1; i++) {\n        if (isValueArray) {\n            fillArr(kfValues[i], lastValue, arrDim);\n        }\n        else {\n            if (isNaN(kfValues[i]) && !isNaN(lastValue) && !isValueString && !isValueColor) {\n                kfValues[i] = lastValue;\n            }\n        }\n    }\n    isValueArray && fillArr(getter(animator._target, propName), lastValue, arrDim);\n\n    // Cache the key of last frame to speed up when\n    // animation playback is sequency\n    var lastFrame = 0;\n    var lastFramePercent = 0;\n    var start;\n    var w;\n    var p0;\n    var p1;\n    var p2;\n    var p3;\n\n    if (isValueColor) {\n        var rgba = [0, 0, 0, 0];\n    }\n\n    var onframe = function (target, percent) {\n        // Find the range keyframes\n        // kf1-----kf2---------current--------kf3\n        // find kf2 and kf3 and do interpolation\n        var frame;\n        // In the easing function like elasticOut, percent may less than 0\n        if (percent < 0) {\n            frame = 0;\n        }\n        else if (percent < lastFramePercent) {\n            // Start from next key\n            // PENDING start from lastFrame ?\n            start = Math.min(lastFrame + 1, trackLen - 1);\n            for (frame = start; frame >= 0; frame--) {\n                if (kfPercents[frame] <= percent) {\n                    break;\n                }\n            }\n            // PENDING really need to do this ?\n            frame = Math.min(frame, trackLen - 2);\n        }\n        else {\n            for (frame = lastFrame; frame < trackLen; frame++) {\n                if (kfPercents[frame] > percent) {\n                    break;\n                }\n            }\n            frame = Math.min(frame - 1, trackLen - 2);\n        }\n        lastFrame = frame;\n        lastFramePercent = percent;\n\n        var range = (kfPercents[frame + 1] - kfPercents[frame]);\n        if (range === 0) {\n            return;\n        }\n        else {\n            w = (percent - kfPercents[frame]) / range;\n        }\n        if (useSpline) {\n            p1 = kfValues[frame];\n            p0 = kfValues[frame === 0 ? frame : frame - 1];\n            p2 = kfValues[frame > trackLen - 2 ? trackLen - 1 : frame + 1];\n            p3 = kfValues[frame > trackLen - 3 ? trackLen - 1 : frame + 2];\n            if (isValueArray) {\n                catmullRomInterpolateArray(\n                    p0, p1, p2, p3, w, w * w, w * w * w,\n                    getter(target, propName),\n                    arrDim\n                );\n            }\n            else {\n                var value;\n                if (isValueColor) {\n                    value = catmullRomInterpolateArray(\n                        p0, p1, p2, p3, w, w * w, w * w * w,\n                        rgba, 1\n                    );\n                    value = rgba2String(rgba);\n                }\n                else if (isValueString) {\n                    // String is step(0.5)\n                    return interpolateString(p1, p2, w);\n                }\n                else {\n                    value = catmullRomInterpolate(\n                        p0, p1, p2, p3, w, w * w, w * w * w\n                    );\n                }\n                setter(\n                    target,\n                    propName,\n                    value\n                );\n            }\n        }\n        else {\n            if (isValueArray) {\n                interpolateArray(\n                    kfValues[frame], kfValues[frame + 1], w,\n                    getter(target, propName),\n                    arrDim\n                );\n            }\n            else {\n                var value;\n                if (isValueColor) {\n                    interpolateArray(\n                        kfValues[frame], kfValues[frame + 1], w,\n                        rgba, 1\n                    );\n                    value = rgba2String(rgba);\n                }\n                else if (isValueString) {\n                    // String is step(0.5)\n                    return interpolateString(kfValues[frame], kfValues[frame + 1], w);\n                }\n                else {\n                    value = interpolateNumber(kfValues[frame], kfValues[frame + 1], w);\n                }\n                setter(\n                    target,\n                    propName,\n                    value\n                );\n            }\n        }\n    };\n\n    var clip = new Clip({\n        target: animator._target,\n        life: trackMaxTime,\n        loop: animator._loop,\n        delay: animator._delay,\n        onframe: onframe,\n        ondestroy: oneTrackDone\n    });\n\n    if (easing && easing !== 'spline') {\n        clip.easing = easing;\n    }\n\n    return clip;\n}\n\n/**\n * @alias module:zrender/animation/Animator\n * @constructor\n * @param {Object} target\n * @param {boolean} loop\n * @param {Function} getter\n * @param {Function} setter\n */\nvar Animator = function (target, loop, getter, setter) {\n    this._tracks = {};\n    this._target = target;\n\n    this._loop = loop || false;\n\n    this._getter = getter || defaultGetter;\n    this._setter = setter || defaultSetter;\n\n    this._clipCount = 0;\n\n    this._delay = 0;\n\n    this._doneList = [];\n\n    this._onframeList = [];\n\n    this._clipList = [];\n};\n\nAnimator.prototype = {\n    /**\n     * 设置动画关键帧\n     * @param  {number} time 关键帧时间，单位是ms\n     * @param  {Object} props 关键帧的属性值，key-value表示\n     * @return {module:zrender/animation/Animator}\n     */\n    when: function (time /* ms */, props) {\n        var tracks = this._tracks;\n        for (var propName in props) {\n            if (!props.hasOwnProperty(propName)) {\n                continue;\n            }\n\n            if (!tracks[propName]) {\n                tracks[propName] = [];\n                // Invalid value\n                var value = this._getter(this._target, propName);\n                if (value == null) {\n                    // zrLog('Invalid property ' + propName);\n                    continue;\n                }\n                // If time is 0\n                //  Then props is given initialize value\n                // Else\n                //  Initialize value from current prop value\n                if (time !== 0) {\n                    tracks[propName].push({\n                        time: 0,\n                        value: cloneValue(value)\n                    });\n                }\n            }\n            tracks[propName].push({\n                time: time,\n                value: props[propName]\n            });\n        }\n        return this;\n    },\n    /**\n     * 添加动画每一帧的回调函数\n     * @param  {Function} callback\n     * @return {module:zrender/animation/Animator}\n     */\n    during: function (callback) {\n        this._onframeList.push(callback);\n        return this;\n    },\n\n    pause: function () {\n        for (var i = 0; i < this._clipList.length; i++) {\n            this._clipList[i].pause();\n        }\n        this._paused = true;\n    },\n\n    resume: function () {\n        for (var i = 0; i < this._clipList.length; i++) {\n            this._clipList[i].resume();\n        }\n        this._paused = false;\n    },\n\n    isPaused: function () {\n        return !!this._paused;\n    },\n\n    _doneCallback: function () {\n        // Clear all tracks\n        this._tracks = {};\n        // Clear all clips\n        this._clipList.length = 0;\n\n        var doneList = this._doneList;\n        var len = doneList.length;\n        for (var i = 0; i < len; i++) {\n            doneList[i].call(this);\n        }\n    },\n    /**\n     * 开始执行动画\n     * @param  {string|Function} [easing]\n     *         动画缓动函数，详见{@link module:zrender/animation/easing}\n     * @param  {boolean} forceAnimate\n     * @return {module:zrender/animation/Animator}\n     */\n    start: function (easing, forceAnimate) {\n\n        var self = this;\n        var clipCount = 0;\n\n        var oneTrackDone = function () {\n            clipCount--;\n            if (!clipCount) {\n                self._doneCallback();\n            }\n        };\n\n        var lastClip;\n        for (var propName in this._tracks) {\n            if (!this._tracks.hasOwnProperty(propName)) {\n                continue;\n            }\n            var clip = createTrackClip(\n                this, easing, oneTrackDone,\n                this._tracks[propName], propName, forceAnimate\n            );\n            if (clip) {\n                this._clipList.push(clip);\n                clipCount++;\n\n                // If start after added to animation\n                if (this.animation) {\n                    this.animation.addClip(clip);\n                }\n\n                lastClip = clip;\n            }\n        }\n\n        // Add during callback on the last clip\n        if (lastClip) {\n            var oldOnFrame = lastClip.onframe;\n            lastClip.onframe = function (target, percent) {\n                oldOnFrame(target, percent);\n\n                for (var i = 0; i < self._onframeList.length; i++) {\n                    self._onframeList[i](target, percent);\n                }\n            };\n        }\n\n        // This optimization will help the case that in the upper application\n        // the view may be refreshed frequently, where animation will be\n        // called repeatly but nothing changed.\n        if (!clipCount) {\n            this._doneCallback();\n        }\n        return this;\n    },\n    /**\n     * 停止动画\n     * @param {boolean} forwardToLast If move to last frame before stop\n     */\n    stop: function (forwardToLast) {\n        var clipList = this._clipList;\n        var animation = this.animation;\n        for (var i = 0; i < clipList.length; i++) {\n            var clip = clipList[i];\n            if (forwardToLast) {\n                // Move to last frame before stop\n                clip.onframe(this._target, 1);\n            }\n            animation && animation.removeClip(clip);\n        }\n        clipList.length = 0;\n    },\n    /**\n     * 设置动画延迟开始的时间\n     * @param  {number} time 单位ms\n     * @return {module:zrender/animation/Animator}\n     */\n    delay: function (time) {\n        this._delay = time;\n        return this;\n    },\n    /**\n     * 添加动画结束的回调\n     * @param  {Function} cb\n     * @return {module:zrender/animation/Animator}\n     */\n    done: function (cb) {\n        if (cb) {\n            this._doneList.push(cb);\n        }\n        return this;\n    },\n\n    /**\n     * @return {Array.<module:zrender/animation/Clip>}\n     */\n    getClips: function () {\n        return this._clipList;\n    }\n};\n\nvar dpr = 1;\n\n// If in browser environment\nif (typeof window !== 'undefined') {\n    dpr = Math.max(window.devicePixelRatio || 1, 1);\n}\n\n/**\n * config默认配置项\n * @exports zrender/config\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n */\n\n/**\n * debug日志选项：catchBrushException为true下有效\n * 0 : 不生成debug数据，发布用\n * 1 : 异常抛出，调试用\n * 2 : 控制台输出，调试用\n */\nvar debugMode = 0;\n\n// retina 屏幕优化\nvar devicePixelRatio = dpr;\n\nvar log = function () {\n};\n\nif (debugMode === 1) {\n    log = function () {\n        for (var k in arguments) {\n            throw new Error(arguments[k]);\n        }\n    };\n}\nelse if (debugMode > 1) {\n    log = function () {\n        for (var k in arguments) {\n            console.log(arguments[k]);\n        }\n    };\n}\n\nvar zrLog = log;\n\n/**\n * @alias modue:zrender/mixin/Animatable\n * @constructor\n */\nvar Animatable = function () {\n\n    /**\n     * @type {Array.<module:zrender/animation/Animator>}\n     * @readOnly\n     */\n    this.animators = [];\n};\n\nAnimatable.prototype = {\n\n    constructor: Animatable,\n\n    /**\n     * 动画\n     *\n     * @param {string} path The path to fetch value from object, like 'a.b.c'.\n     * @param {boolean} [loop] Whether to loop animation.\n     * @return {module:zrender/animation/Animator}\n     * @example:\n     *     el.animate('style', false)\n     *         .when(1000, {x: 10} )\n     *         .done(function(){ // Animation done })\n     *         .start()\n     */\n    animate: function (path, loop) {\n        var target;\n        var animatingShape = false;\n        var el = this;\n        var zr = this.__zr;\n        if (path) {\n            var pathSplitted = path.split('.');\n            var prop = el;\n            // If animating shape\n            animatingShape = pathSplitted[0] === 'shape';\n            for (var i = 0, l = pathSplitted.length; i < l; i++) {\n                if (!prop) {\n                    continue;\n                }\n                prop = prop[pathSplitted[i]];\n            }\n            if (prop) {\n                target = prop;\n            }\n        }\n        else {\n            target = el;\n        }\n\n        if (!target) {\n            zrLog(\n                'Property \"'\n                + path\n                + '\" is not existed in element '\n                + el.id\n            );\n            return;\n        }\n\n        var animators = el.animators;\n\n        var animator = new Animator(target, loop);\n\n        animator.during(function (target) {\n            el.dirty(animatingShape);\n        })\n        .done(function () {\n            // FIXME Animator will not be removed if use `Animator#stop` to stop animation\n            animators.splice(indexOf(animators, animator), 1);\n        });\n\n        animators.push(animator);\n\n        // If animate after added to the zrender\n        if (zr) {\n            zr.animation.addAnimator(animator);\n        }\n\n        return animator;\n    },\n\n    /**\n     * 停止动画\n     * @param {boolean} forwardToLast If move to last frame before stop\n     */\n    stopAnimation: function (forwardToLast) {\n        var animators = this.animators;\n        var len = animators.length;\n        for (var i = 0; i < len; i++) {\n            animators[i].stop(forwardToLast);\n        }\n        animators.length = 0;\n\n        return this;\n    },\n\n    /**\n     * Caution: this method will stop previous animation.\n     * So do not use this method to one element twice before\n     * animation starts, unless you know what you are doing.\n     * @param {Object} target\n     * @param {number} [time=500] Time in ms\n     * @param {string} [easing='linear']\n     * @param {number} [delay=0]\n     * @param {Function} [callback]\n     * @param {Function} [forceAnimate] Prevent stop animation and callback\n     *        immediently when target values are the same as current values.\n     *\n     * @example\n     *  // Animate position\n     *  el.animateTo({\n     *      position: [10, 10]\n     *  }, function () { // done })\n     *\n     *  // Animate shape, style and position in 100ms, delayed 100ms, with cubicOut easing\n     *  el.animateTo({\n     *      shape: {\n     *          width: 500\n     *      },\n     *      style: {\n     *          fill: 'red'\n     *      }\n     *      position: [10, 10]\n     *  }, 100, 100, 'cubicOut', function () { // done })\n     */\n    // TODO Return animation key\n    animateTo: function (target, time, delay, easing, callback, forceAnimate) {\n        animateTo(this, target, time, delay, easing, callback, forceAnimate);\n    },\n\n    /**\n     * Animate from the target state to current state.\n     * The params and the return value are the same as `this.animateTo`.\n     */\n    animateFrom: function (target, time, delay, easing, callback, forceAnimate) {\n        animateTo(this, target, time, delay, easing, callback, forceAnimate, true);\n    }\n};\n\nfunction animateTo(animatable, target, time, delay, easing, callback, forceAnimate, reverse) {\n    // animateTo(target, time, easing, callback);\n    if (isString(delay)) {\n        callback = easing;\n        easing = delay;\n        delay = 0;\n    }\n    // animateTo(target, time, delay, callback);\n    else if (isFunction$1(easing)) {\n        callback = easing;\n        easing = 'linear';\n        delay = 0;\n    }\n    // animateTo(target, time, callback);\n    else if (isFunction$1(delay)) {\n        callback = delay;\n        delay = 0;\n    }\n    // animateTo(target, callback)\n    else if (isFunction$1(time)) {\n        callback = time;\n        time = 500;\n    }\n    // animateTo(target)\n    else if (!time) {\n        time = 500;\n    }\n    // Stop all previous animations\n    animatable.stopAnimation();\n    animateToShallow(animatable, '', animatable, target, time, delay, reverse);\n\n    // Animators may be removed immediately after start\n    // if there is nothing to animate\n    var animators = animatable.animators.slice();\n    var count = animators.length;\n    function done() {\n        count--;\n        if (!count) {\n            callback && callback();\n        }\n    }\n\n    // No animators. This should be checked before animators[i].start(),\n    // because 'done' may be executed immediately if no need to animate.\n    if (!count) {\n        callback && callback();\n    }\n    // Start after all animators created\n    // Incase any animator is done immediately when all animation properties are not changed\n    for (var i = 0; i < animators.length; i++) {\n        animators[i]\n            .done(done)\n            .start(easing, forceAnimate);\n    }\n}\n\n/**\n * @param {string} path=''\n * @param {Object} source=animatable\n * @param {Object} target\n * @param {number} [time=500]\n * @param {number} [delay=0]\n * @param {boolean} [reverse] If `true`, animate\n *        from the `target` to current state.\n *\n * @example\n *  // Animate position\n *  el._animateToShallow({\n *      position: [10, 10]\n *  })\n *\n *  // Animate shape, style and position in 100ms, delayed 100ms\n *  el._animateToShallow({\n *      shape: {\n *          width: 500\n *      },\n *      style: {\n *          fill: 'red'\n *      }\n *      position: [10, 10]\n *  }, 100, 100)\n */\nfunction animateToShallow(animatable, path, source, target, time, delay, reverse) {\n    var objShallow = {};\n    var propertyCount = 0;\n    for (var name in target) {\n        if (!target.hasOwnProperty(name)) {\n            continue;\n        }\n\n        if (source[name] != null) {\n            if (isObject$1(target[name]) && !isArrayLike(target[name])) {\n                animateToShallow(\n                    animatable,\n                    path ? path + '.' + name : name,\n                    source[name],\n                    target[name],\n                    time,\n                    delay,\n                    reverse\n                );\n            }\n            else {\n                if (reverse) {\n                    objShallow[name] = source[name];\n                    setAttrByPath(animatable, path, name, target[name]);\n                }\n                else {\n                    objShallow[name] = target[name];\n                }\n                propertyCount++;\n            }\n        }\n        else if (target[name] != null && !reverse) {\n            setAttrByPath(animatable, path, name, target[name]);\n        }\n    }\n\n    if (propertyCount > 0) {\n        animatable.animate(path, false)\n            .when(time == null ? 500 : time, objShallow)\n            .delay(delay || 0);\n    }\n}\n\nfunction setAttrByPath(el, path, name, value) {\n    // Attr directly if not has property\n    // FIXME, if some property not needed for element ?\n    if (!path) {\n        el.attr(name, value);\n    }\n    else {\n        // Only support set shape or style\n        var props = {};\n        props[path] = {};\n        props[path][name] = value;\n        el.attr(props);\n    }\n}\n\n/**\n * @alias module:zrender/Element\n * @constructor\n * @extends {module:zrender/mixin/Animatable}\n * @extends {module:zrender/mixin/Transformable}\n * @extends {module:zrender/mixin/Eventful}\n */\nvar Element = function (opts) { // jshint ignore:line\n\n    Transformable.call(this, opts);\n    Eventful.call(this, opts);\n    Animatable.call(this, opts);\n\n    /**\n     * 画布元素ID\n     * @type {string}\n     */\n    this.id = opts.id || guid();\n};\n\nElement.prototype = {\n\n    /**\n     * 元素类型\n     * Element type\n     * @type {string}\n     */\n    type: 'element',\n\n    /**\n     * 元素名字\n     * Element name\n     * @type {string}\n     */\n    name: '',\n\n    /**\n     * ZRender 实例对象，会在 element 添加到 zrender 实例中后自动赋值\n     * ZRender instance will be assigned when element is associated with zrender\n     * @name module:/zrender/Element#__zr\n     * @type {module:zrender/ZRender}\n     */\n    __zr: null,\n\n    /**\n     * 图形是否忽略，为true时忽略图形的绘制以及事件触发\n     * If ignore drawing and events of the element object\n     * @name module:/zrender/Element#ignore\n     * @type {boolean}\n     * @default false\n     */\n    ignore: false,\n\n    /**\n     * 用于裁剪的路径(shape)，所有 Group 内的路径在绘制时都会被这个路径裁剪\n     * 该路径会继承被裁减对象的变换\n     * @type {module:zrender/graphic/Path}\n     * @see http://www.w3.org/TR/2dcontext/#clipping-region\n     * @readOnly\n     */\n    clipPath: null,\n\n    /**\n     * 是否是 Group\n     * @type {boolean}\n     */\n    isGroup: false,\n\n    /**\n     * Drift element\n     * @param  {number} dx dx on the global space\n     * @param  {number} dy dy on the global space\n     */\n    drift: function (dx, dy) {\n        switch (this.draggable) {\n            case 'horizontal':\n                dy = 0;\n                break;\n            case 'vertical':\n                dx = 0;\n                break;\n        }\n\n        var m = this.transform;\n        if (!m) {\n            m = this.transform = [1, 0, 0, 1, 0, 0];\n        }\n        m[4] += dx;\n        m[5] += dy;\n\n        this.decomposeTransform();\n        this.dirty(false);\n    },\n\n    /**\n     * Hook before update\n     */\n    beforeUpdate: function () {},\n    /**\n     * Hook after update\n     */\n    afterUpdate: function () {},\n    /**\n     * Update each frame\n     */\n    update: function () {\n        this.updateTransform();\n    },\n\n    /**\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {},\n\n    /**\n     * @protected\n     */\n    attrKV: function (key, value) {\n        if (key === 'position' || key === 'scale' || key === 'origin') {\n            // Copy the array\n            if (value) {\n                var target = this[key];\n                if (!target) {\n                    target = this[key] = [];\n                }\n                target[0] = value[0];\n                target[1] = value[1];\n            }\n        }\n        else {\n            this[key] = value;\n        }\n    },\n\n    /**\n     * Hide the element\n     */\n    hide: function () {\n        this.ignore = true;\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * Show the element\n     */\n    show: function () {\n        this.ignore = false;\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * @param {string|Object} key\n     * @param {*} value\n     */\n    attr: function (key, value) {\n        if (typeof key === 'string') {\n            this.attrKV(key, value);\n        }\n        else if (isObject$1(key)) {\n            for (var name in key) {\n                if (key.hasOwnProperty(name)) {\n                    this.attrKV(name, key[name]);\n                }\n            }\n        }\n\n        this.dirty(false);\n\n        return this;\n    },\n\n    /**\n     * @param {module:zrender/graphic/Path} clipPath\n     */\n    setClipPath: function (clipPath) {\n        var zr = this.__zr;\n        if (zr) {\n            clipPath.addSelfToZr(zr);\n        }\n\n        // Remove previous clip path\n        if (this.clipPath && this.clipPath !== clipPath) {\n            this.removeClipPath();\n        }\n\n        this.clipPath = clipPath;\n        clipPath.__zr = zr;\n        clipPath.__clipTarget = this;\n\n        this.dirty(false);\n    },\n\n    /**\n     */\n    removeClipPath: function () {\n        var clipPath = this.clipPath;\n        if (clipPath) {\n            if (clipPath.__zr) {\n                clipPath.removeSelfFromZr(clipPath.__zr);\n            }\n\n            clipPath.__zr = null;\n            clipPath.__clipTarget = null;\n            this.clipPath = null;\n\n            this.dirty(false);\n        }\n    },\n\n    /**\n     * Add self from zrender instance.\n     * Not recursively because it will be invoked when element added to storage.\n     * @param {module:zrender/ZRender} zr\n     */\n    addSelfToZr: function (zr) {\n        this.__zr = zr;\n        // 添加动画\n        var animators = this.animators;\n        if (animators) {\n            for (var i = 0; i < animators.length; i++) {\n                zr.animation.addAnimator(animators[i]);\n            }\n        }\n\n        if (this.clipPath) {\n            this.clipPath.addSelfToZr(zr);\n        }\n    },\n\n    /**\n     * Remove self from zrender instance.\n     * Not recursively because it will be invoked when element added to storage.\n     * @param {module:zrender/ZRender} zr\n     */\n    removeSelfFromZr: function (zr) {\n        this.__zr = null;\n        // 移除动画\n        var animators = this.animators;\n        if (animators) {\n            for (var i = 0; i < animators.length; i++) {\n                zr.animation.removeAnimator(animators[i]);\n            }\n        }\n\n        if (this.clipPath) {\n            this.clipPath.removeSelfFromZr(zr);\n        }\n    }\n};\n\nmixin(Element, Animatable);\nmixin(Element, Transformable);\nmixin(Element, Eventful);\n\n/**\n * @module echarts/core/BoundingRect\n */\n\nvar v2ApplyTransform = applyTransform;\nvar mathMin = Math.min;\nvar mathMax = Math.max;\n\n/**\n * @alias module:echarts/core/BoundingRect\n */\nfunction BoundingRect(x, y, width, height) {\n\n    if (width < 0) {\n        x = x + width;\n        width = -width;\n    }\n    if (height < 0) {\n        y = y + height;\n        height = -height;\n    }\n\n    /**\n     * @type {number}\n     */\n    this.x = x;\n    /**\n     * @type {number}\n     */\n    this.y = y;\n    /**\n     * @type {number}\n     */\n    this.width = width;\n    /**\n     * @type {number}\n     */\n    this.height = height;\n}\n\nBoundingRect.prototype = {\n\n    constructor: BoundingRect,\n\n    /**\n     * @param {module:echarts/core/BoundingRect} other\n     */\n    union: function (other) {\n        var x = mathMin(other.x, this.x);\n        var y = mathMin(other.y, this.y);\n\n        this.width = mathMax(\n                other.x + other.width,\n                this.x + this.width\n            ) - x;\n        this.height = mathMax(\n                other.y + other.height,\n                this.y + this.height\n            ) - y;\n        this.x = x;\n        this.y = y;\n    },\n\n    /**\n     * @param {Array.<number>} m\n     * @methods\n     */\n    applyTransform: (function () {\n        var lt = [];\n        var rb = [];\n        var lb = [];\n        var rt = [];\n        return function (m) {\n            // In case usage like this\n            // el.getBoundingRect().applyTransform(el.transform)\n            // And element has no transform\n            if (!m) {\n                return;\n            }\n            lt[0] = lb[0] = this.x;\n            lt[1] = rt[1] = this.y;\n            rb[0] = rt[0] = this.x + this.width;\n            rb[1] = lb[1] = this.y + this.height;\n\n            v2ApplyTransform(lt, lt, m);\n            v2ApplyTransform(rb, rb, m);\n            v2ApplyTransform(lb, lb, m);\n            v2ApplyTransform(rt, rt, m);\n\n            this.x = mathMin(lt[0], rb[0], lb[0], rt[0]);\n            this.y = mathMin(lt[1], rb[1], lb[1], rt[1]);\n            var maxX = mathMax(lt[0], rb[0], lb[0], rt[0]);\n            var maxY = mathMax(lt[1], rb[1], lb[1], rt[1]);\n            this.width = maxX - this.x;\n            this.height = maxY - this.y;\n        };\n    })(),\n\n    /**\n     * Calculate matrix of transforming from self to target rect\n     * @param  {module:zrender/core/BoundingRect} b\n     * @return {Array.<number>}\n     */\n    calculateTransform: function (b) {\n        var a = this;\n        var sx = b.width / a.width;\n        var sy = b.height / a.height;\n\n        var m = create$1();\n\n        // 矩阵右乘\n        translate(m, m, [-a.x, -a.y]);\n        scale$1(m, m, [sx, sy]);\n        translate(m, m, [b.x, b.y]);\n\n        return m;\n    },\n\n    /**\n     * @param {(module:echarts/core/BoundingRect|Object)} b\n     * @return {boolean}\n     */\n    intersect: function (b) {\n        if (!b) {\n            return false;\n        }\n\n        if (!(b instanceof BoundingRect)) {\n            // Normalize negative width/height.\n            b = BoundingRect.create(b);\n        }\n\n        var a = this;\n        var ax0 = a.x;\n        var ax1 = a.x + a.width;\n        var ay0 = a.y;\n        var ay1 = a.y + a.height;\n\n        var bx0 = b.x;\n        var bx1 = b.x + b.width;\n        var by0 = b.y;\n        var by1 = b.y + b.height;\n\n        return !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);\n    },\n\n    contain: function (x, y) {\n        var rect = this;\n        return x >= rect.x\n            && x <= (rect.x + rect.width)\n            && y >= rect.y\n            && y <= (rect.y + rect.height);\n    },\n\n    /**\n     * @return {module:echarts/core/BoundingRect}\n     */\n    clone: function () {\n        return new BoundingRect(this.x, this.y, this.width, this.height);\n    },\n\n    /**\n     * Copy from another rect\n     */\n    copy: function (other) {\n        this.x = other.x;\n        this.y = other.y;\n        this.width = other.width;\n        this.height = other.height;\n    },\n\n    plain: function () {\n        return {\n            x: this.x,\n            y: this.y,\n            width: this.width,\n            height: this.height\n        };\n    }\n};\n\n/**\n * @param {Object|module:zrender/core/BoundingRect} rect\n * @param {number} rect.x\n * @param {number} rect.y\n * @param {number} rect.width\n * @param {number} rect.height\n * @return {module:zrender/core/BoundingRect}\n */\nBoundingRect.create = function (rect) {\n    return new BoundingRect(rect.x, rect.y, rect.width, rect.height);\n};\n\n/**\n * Group是一个容器，可以插入子节点，Group的变换也会被应用到子节点上\n * @module zrender/graphic/Group\n * @example\n *     var Group = require('zrender/container/Group');\n *     var Circle = require('zrender/graphic/shape/Circle');\n *     var g = new Group();\n *     g.position[0] = 100;\n *     g.position[1] = 100;\n *     g.add(new Circle({\n *         style: {\n *             x: 100,\n *             y: 100,\n *             r: 20,\n *         }\n *     }));\n *     zr.add(g);\n */\n\n/**\n * @alias module:zrender/graphic/Group\n * @constructor\n * @extends module:zrender/mixin/Transformable\n * @extends module:zrender/mixin/Eventful\n */\nvar Group = function (opts) {\n\n    opts = opts || {};\n\n    Element.call(this, opts);\n\n    for (var key in opts) {\n        if (opts.hasOwnProperty(key)) {\n            this[key] = opts[key];\n        }\n    }\n\n    this._children = [];\n\n    this.__storage = null;\n\n    this.__dirty = true;\n};\n\nGroup.prototype = {\n\n    constructor: Group,\n\n    isGroup: true,\n\n    /**\n     * @type {string}\n     */\n    type: 'group',\n\n    /**\n     * 所有子孙元素是否响应鼠标事件\n     * @name module:/zrender/container/Group#silent\n     * @type {boolean}\n     * @default false\n     */\n    silent: false,\n\n    /**\n     * @return {Array.<module:zrender/Element>}\n     */\n    children: function () {\n        return this._children.slice();\n    },\n\n    /**\n     * 获取指定 index 的儿子节点\n     * @param  {number} idx\n     * @return {module:zrender/Element}\n     */\n    childAt: function (idx) {\n        return this._children[idx];\n    },\n\n    /**\n     * 获取指定名字的儿子节点\n     * @param  {string} name\n     * @return {module:zrender/Element}\n     */\n    childOfName: function (name) {\n        var children = this._children;\n        for (var i = 0; i < children.length; i++) {\n            if (children[i].name === name) {\n                return children[i];\n            }\n            }\n    },\n\n    /**\n     * @return {number}\n     */\n    childCount: function () {\n        return this._children.length;\n    },\n\n    /**\n     * 添加子节点到最后\n     * @param {module:zrender/Element} child\n     */\n    add: function (child) {\n        if (child && child !== this && child.parent !== this) {\n\n            this._children.push(child);\n\n            this._doAdd(child);\n        }\n\n        return this;\n    },\n\n    /**\n     * 添加子节点在 nextSibling 之前\n     * @param {module:zrender/Element} child\n     * @param {module:zrender/Element} nextSibling\n     */\n    addBefore: function (child, nextSibling) {\n        if (child && child !== this && child.parent !== this\n            && nextSibling && nextSibling.parent === this) {\n\n            var children = this._children;\n            var idx = children.indexOf(nextSibling);\n\n            if (idx >= 0) {\n                children.splice(idx, 0, child);\n                this._doAdd(child);\n            }\n        }\n\n        return this;\n    },\n\n    _doAdd: function (child) {\n        if (child.parent) {\n            child.parent.remove(child);\n        }\n\n        child.parent = this;\n\n        var storage = this.__storage;\n        var zr = this.__zr;\n        if (storage && storage !== child.__storage) {\n\n            storage.addToStorage(child);\n\n            if (child instanceof Group) {\n                child.addChildrenToStorage(storage);\n            }\n        }\n\n        zr && zr.refresh();\n    },\n\n    /**\n     * 移除子节点\n     * @param {module:zrender/Element} child\n     */\n    remove: function (child) {\n        var zr = this.__zr;\n        var storage = this.__storage;\n        var children = this._children;\n\n        var idx = indexOf(children, child);\n        if (idx < 0) {\n            return this;\n        }\n        children.splice(idx, 1);\n\n        child.parent = null;\n\n        if (storage) {\n\n            storage.delFromStorage(child);\n\n            if (child instanceof Group) {\n                child.delChildrenFromStorage(storage);\n            }\n        }\n\n        zr && zr.refresh();\n\n        return this;\n    },\n\n    /**\n     * 移除所有子节点\n     */\n    removeAll: function () {\n        var children = this._children;\n        var storage = this.__storage;\n        var child;\n        var i;\n        for (i = 0; i < children.length; i++) {\n            child = children[i];\n            if (storage) {\n                storage.delFromStorage(child);\n                if (child instanceof Group) {\n                    child.delChildrenFromStorage(storage);\n                }\n            }\n            child.parent = null;\n        }\n        children.length = 0;\n\n        return this;\n    },\n\n    /**\n     * 遍历所有子节点\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    eachChild: function (cb, context) {\n        var children = this._children;\n        for (var i = 0; i < children.length; i++) {\n            var child = children[i];\n            cb.call(context, child, i);\n        }\n        return this;\n    },\n\n    /**\n     * 深度优先遍历所有子孙节点\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            cb.call(context, child);\n\n            if (child.type === 'group') {\n                child.traverse(cb, context);\n            }\n        }\n        return this;\n    },\n\n    addChildrenToStorage: function (storage) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            storage.addToStorage(child);\n            if (child instanceof Group) {\n                child.addChildrenToStorage(storage);\n            }\n        }\n    },\n\n    delChildrenFromStorage: function (storage) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            storage.delFromStorage(child);\n            if (child instanceof Group) {\n                child.delChildrenFromStorage(storage);\n            }\n        }\n    },\n\n    dirty: function () {\n        this.__dirty = true;\n        this.__zr && this.__zr.refresh();\n        return this;\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function (includeChildren) {\n        // TODO Caching\n        var rect = null;\n        var tmpRect = new BoundingRect(0, 0, 0, 0);\n        var children = includeChildren || this._children;\n        var tmpMat = [];\n\n        for (var i = 0; i < children.length; i++) {\n            var child = children[i];\n            if (child.ignore || child.invisible) {\n                continue;\n            }\n\n            var childRect = child.getBoundingRect();\n            var transform = child.getLocalTransform(tmpMat);\n            // TODO\n            // The boundingRect cacluated by transforming original\n            // rect may be bigger than the actual bundingRect when rotation\n            // is used. (Consider a circle rotated aginst its center, where\n            // the actual boundingRect should be the same as that not be\n            // rotated.) But we can not find better approach to calculate\n            // actual boundingRect yet, considering performance.\n            if (transform) {\n                tmpRect.copy(childRect);\n                tmpRect.applyTransform(transform);\n                rect = rect || tmpRect.clone();\n                rect.union(tmpRect);\n            }\n            else {\n                rect = rect || childRect.clone();\n                rect.union(childRect);\n            }\n        }\n        return rect || tmpRect;\n    }\n};\n\ninherits(Group, Element);\n\n// https://github.com/mziccard/node-timsort\nvar DEFAULT_MIN_MERGE = 32;\n\nvar DEFAULT_MIN_GALLOPING = 7;\n\nfunction minRunLength(n) {\n    var r = 0;\n\n    while (n >= DEFAULT_MIN_MERGE) {\n        r |= n & 1;\n        n >>= 1;\n    }\n\n    return n + r;\n}\n\nfunction makeAscendingRun(array, lo, hi, compare) {\n    var runHi = lo + 1;\n\n    if (runHi === hi) {\n        return 1;\n    }\n\n    if (compare(array[runHi++], array[lo]) < 0) {\n        while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {\n            runHi++;\n        }\n\n        reverseRun(array, lo, runHi);\n    }\n    else {\n        while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {\n            runHi++;\n        }\n    }\n\n    return runHi - lo;\n}\n\nfunction reverseRun(array, lo, hi) {\n    hi--;\n\n    while (lo < hi) {\n        var t = array[lo];\n        array[lo++] = array[hi];\n        array[hi--] = t;\n    }\n}\n\nfunction binaryInsertionSort(array, lo, hi, start, compare) {\n    if (start === lo) {\n        start++;\n    }\n\n    for (; start < hi; start++) {\n        var pivot = array[start];\n\n        var left = lo;\n        var right = start;\n        var mid;\n\n        while (left < right) {\n            mid = left + right >>> 1;\n\n            if (compare(pivot, array[mid]) < 0) {\n                right = mid;\n            }\n            else {\n                left = mid + 1;\n            }\n        }\n\n        var n = start - left;\n\n        switch (n) {\n            case 3:\n                array[left + 3] = array[left + 2];\n\n            case 2:\n                array[left + 2] = array[left + 1];\n\n            case 1:\n                array[left + 1] = array[left];\n                break;\n            default:\n                while (n > 0) {\n                    array[left + n] = array[left + n - 1];\n                    n--;\n                }\n        }\n\n        array[left] = pivot;\n    }\n}\n\nfunction gallopLeft(value, array, start, length, hint, compare) {\n    var lastOffset = 0;\n    var maxOffset = 0;\n    var offset = 1;\n\n    if (compare(value, array[start + hint]) > 0) {\n        maxOffset = length - hint;\n\n        while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        lastOffset += hint;\n        offset += hint;\n    }\n    else {\n        maxOffset = hint + 1;\n        while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        var tmp = lastOffset;\n        lastOffset = hint - offset;\n        offset = hint - tmp;\n    }\n\n    lastOffset++;\n    while (lastOffset < offset) {\n        var m = lastOffset + (offset - lastOffset >>> 1);\n\n        if (compare(value, array[start + m]) > 0) {\n            lastOffset = m + 1;\n        }\n        else {\n            offset = m;\n        }\n    }\n    return offset;\n}\n\nfunction gallopRight(value, array, start, length, hint, compare) {\n    var lastOffset = 0;\n    var maxOffset = 0;\n    var offset = 1;\n\n    if (compare(value, array[start + hint]) < 0) {\n        maxOffset = hint + 1;\n\n        while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        var tmp = lastOffset;\n        lastOffset = hint - offset;\n        offset = hint - tmp;\n    }\n    else {\n        maxOffset = length - hint;\n\n        while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        lastOffset += hint;\n        offset += hint;\n    }\n\n    lastOffset++;\n\n    while (lastOffset < offset) {\n        var m = lastOffset + (offset - lastOffset >>> 1);\n\n        if (compare(value, array[start + m]) < 0) {\n            offset = m;\n        }\n        else {\n            lastOffset = m + 1;\n        }\n    }\n\n    return offset;\n}\n\nfunction TimSort(array, compare) {\n    var minGallop = DEFAULT_MIN_GALLOPING;\n    var runStart;\n    var runLength;\n    var stackSize = 0;\n\n    var tmp = [];\n\n    runStart = [];\n    runLength = [];\n\n    function pushRun(_runStart, _runLength) {\n        runStart[stackSize] = _runStart;\n        runLength[stackSize] = _runLength;\n        stackSize += 1;\n    }\n\n    function mergeRuns() {\n        while (stackSize > 1) {\n            var n = stackSize - 2;\n\n            if (n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1] || n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1]) {\n                if (runLength[n - 1] < runLength[n + 1]) {\n                    n--;\n                }\n            }\n            else if (runLength[n] > runLength[n + 1]) {\n                break;\n            }\n            mergeAt(n);\n        }\n    }\n\n    function forceMergeRuns() {\n        while (stackSize > 1) {\n            var n = stackSize - 2;\n\n            if (n > 0 && runLength[n - 1] < runLength[n + 1]) {\n                n--;\n            }\n\n            mergeAt(n);\n        }\n    }\n\n    function mergeAt(i) {\n        var start1 = runStart[i];\n        var length1 = runLength[i];\n        var start2 = runStart[i + 1];\n        var length2 = runLength[i + 1];\n\n        runLength[i] = length1 + length2;\n\n        if (i === stackSize - 3) {\n            runStart[i + 1] = runStart[i + 2];\n            runLength[i + 1] = runLength[i + 2];\n        }\n\n        stackSize--;\n\n        var k = gallopRight(array[start2], array, start1, length1, 0, compare);\n        start1 += k;\n        length1 -= k;\n\n        if (length1 === 0) {\n            return;\n        }\n\n        length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);\n\n        if (length2 === 0) {\n            return;\n        }\n\n        if (length1 <= length2) {\n            mergeLow(start1, length1, start2, length2);\n        }\n        else {\n            mergeHigh(start1, length1, start2, length2);\n        }\n    }\n\n    function mergeLow(start1, length1, start2, length2) {\n        var i = 0;\n\n        for (i = 0; i < length1; i++) {\n            tmp[i] = array[start1 + i];\n        }\n\n        var cursor1 = 0;\n        var cursor2 = start2;\n        var dest = start1;\n\n        array[dest++] = array[cursor2++];\n\n        if (--length2 === 0) {\n            for (i = 0; i < length1; i++) {\n                array[dest + i] = tmp[cursor1 + i];\n            }\n            return;\n        }\n\n        if (length1 === 1) {\n            for (i = 0; i < length2; i++) {\n                array[dest + i] = array[cursor2 + i];\n            }\n            array[dest + length2] = tmp[cursor1];\n            return;\n        }\n\n        var _minGallop = minGallop;\n        var count1, count2, exit;\n\n        while (1) {\n            count1 = 0;\n            count2 = 0;\n            exit = false;\n\n            do {\n                if (compare(array[cursor2], tmp[cursor1]) < 0) {\n                    array[dest++] = array[cursor2++];\n                    count2++;\n                    count1 = 0;\n\n                    if (--length2 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                else {\n                    array[dest++] = tmp[cursor1++];\n                    count1++;\n                    count2 = 0;\n                    if (--length1 === 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n            } while ((count1 | count2) < _minGallop);\n\n            if (exit) {\n                break;\n            }\n\n            do {\n                count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);\n\n                if (count1 !== 0) {\n                    for (i = 0; i < count1; i++) {\n                        array[dest + i] = tmp[cursor1 + i];\n                    }\n\n                    dest += count1;\n                    cursor1 += count1;\n                    length1 -= count1;\n                    if (length1 <= 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest++] = array[cursor2++];\n\n                if (--length2 === 0) {\n                    exit = true;\n                    break;\n                }\n\n                count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);\n\n                if (count2 !== 0) {\n                    for (i = 0; i < count2; i++) {\n                        array[dest + i] = array[cursor2 + i];\n                    }\n\n                    dest += count2;\n                    cursor2 += count2;\n                    length2 -= count2;\n\n                    if (length2 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                array[dest++] = tmp[cursor1++];\n\n                if (--length1 === 1) {\n                    exit = true;\n                    break;\n                }\n\n                _minGallop--;\n            } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);\n\n            if (exit) {\n                break;\n            }\n\n            if (_minGallop < 0) {\n                _minGallop = 0;\n            }\n\n            _minGallop += 2;\n        }\n\n        minGallop = _minGallop;\n\n        minGallop < 1 && (minGallop = 1);\n\n        if (length1 === 1) {\n            for (i = 0; i < length2; i++) {\n                array[dest + i] = array[cursor2 + i];\n            }\n            array[dest + length2] = tmp[cursor1];\n        }\n        else if (length1 === 0) {\n            throw new Error();\n            // throw new Error('mergeLow preconditions were not respected');\n        }\n        else {\n            for (i = 0; i < length1; i++) {\n                array[dest + i] = tmp[cursor1 + i];\n            }\n        }\n    }\n\n    function mergeHigh(start1, length1, start2, length2) {\n        var i = 0;\n\n        for (i = 0; i < length2; i++) {\n            tmp[i] = array[start2 + i];\n        }\n\n        var cursor1 = start1 + length1 - 1;\n        var cursor2 = length2 - 1;\n        var dest = start2 + length2 - 1;\n        var customCursor = 0;\n        var customDest = 0;\n\n        array[dest--] = array[cursor1--];\n\n        if (--length1 === 0) {\n            customCursor = dest - (length2 - 1);\n\n            for (i = 0; i < length2; i++) {\n                array[customCursor + i] = tmp[i];\n            }\n\n            return;\n        }\n\n        if (length2 === 1) {\n            dest -= length1;\n            cursor1 -= length1;\n            customDest = dest + 1;\n            customCursor = cursor1 + 1;\n\n            for (i = length1 - 1; i >= 0; i--) {\n                array[customDest + i] = array[customCursor + i];\n            }\n\n            array[dest] = tmp[cursor2];\n            return;\n        }\n\n        var _minGallop = minGallop;\n\n        while (true) {\n            var count1 = 0;\n            var count2 = 0;\n            var exit = false;\n\n            do {\n                if (compare(tmp[cursor2], array[cursor1]) < 0) {\n                    array[dest--] = array[cursor1--];\n                    count1++;\n                    count2 = 0;\n                    if (--length1 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                else {\n                    array[dest--] = tmp[cursor2--];\n                    count2++;\n                    count1 = 0;\n                    if (--length2 === 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n            } while ((count1 | count2) < _minGallop);\n\n            if (exit) {\n                break;\n            }\n\n            do {\n                count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);\n\n                if (count1 !== 0) {\n                    dest -= count1;\n                    cursor1 -= count1;\n                    length1 -= count1;\n                    customDest = dest + 1;\n                    customCursor = cursor1 + 1;\n\n                    for (i = count1 - 1; i >= 0; i--) {\n                        array[customDest + i] = array[customCursor + i];\n                    }\n\n                    if (length1 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest--] = tmp[cursor2--];\n\n                if (--length2 === 1) {\n                    exit = true;\n                    break;\n                }\n\n                count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);\n\n                if (count2 !== 0) {\n                    dest -= count2;\n                    cursor2 -= count2;\n                    length2 -= count2;\n                    customDest = dest + 1;\n                    customCursor = cursor2 + 1;\n\n                    for (i = 0; i < count2; i++) {\n                        array[customDest + i] = tmp[customCursor + i];\n                    }\n\n                    if (length2 <= 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest--] = array[cursor1--];\n\n                if (--length1 === 0) {\n                    exit = true;\n                    break;\n                }\n\n                _minGallop--;\n            } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);\n\n            if (exit) {\n                break;\n            }\n\n            if (_minGallop < 0) {\n                _minGallop = 0;\n            }\n\n            _minGallop += 2;\n        }\n\n        minGallop = _minGallop;\n\n        if (minGallop < 1) {\n            minGallop = 1;\n        }\n\n        if (length2 === 1) {\n            dest -= length1;\n            cursor1 -= length1;\n            customDest = dest + 1;\n            customCursor = cursor1 + 1;\n\n            for (i = length1 - 1; i >= 0; i--) {\n                array[customDest + i] = array[customCursor + i];\n            }\n\n            array[dest] = tmp[cursor2];\n        }\n        else if (length2 === 0) {\n            throw new Error();\n            // throw new Error('mergeHigh preconditions were not respected');\n        }\n        else {\n            customCursor = dest - (length2 - 1);\n            for (i = 0; i < length2; i++) {\n                array[customCursor + i] = tmp[i];\n            }\n        }\n    }\n\n    this.mergeRuns = mergeRuns;\n    this.forceMergeRuns = forceMergeRuns;\n    this.pushRun = pushRun;\n}\n\nfunction sort(array, compare, lo, hi) {\n    if (!lo) {\n        lo = 0;\n    }\n    if (!hi) {\n        hi = array.length;\n    }\n\n    var remaining = hi - lo;\n\n    if (remaining < 2) {\n        return;\n    }\n\n    var runLength = 0;\n\n    if (remaining < DEFAULT_MIN_MERGE) {\n        runLength = makeAscendingRun(array, lo, hi, compare);\n        binaryInsertionSort(array, lo, hi, lo + runLength, compare);\n        return;\n    }\n\n    var ts = new TimSort(array, compare);\n\n    var minRun = minRunLength(remaining);\n\n    do {\n        runLength = makeAscendingRun(array, lo, hi, compare);\n        if (runLength < minRun) {\n            var force = remaining;\n            if (force > minRun) {\n                force = minRun;\n            }\n\n            binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);\n            runLength = force;\n        }\n\n        ts.pushRun(lo, runLength);\n        ts.mergeRuns();\n\n        remaining -= runLength;\n        lo += runLength;\n    } while (remaining !== 0);\n\n    ts.forceMergeRuns();\n}\n\n// Use timsort because in most case elements are partially sorted\n// https://jsfiddle.net/pissang/jr4x7mdm/8/\nfunction shapeCompareFunc(a, b) {\n    if (a.zlevel === b.zlevel) {\n        if (a.z === b.z) {\n            // if (a.z2 === b.z2) {\n            //     // FIXME Slow has renderidx compare\n            //     // http://stackoverflow.com/questions/20883421/sorting-in-javascript-should-every-compare-function-have-a-return-0-statement\n            //     // https://github.com/v8/v8/blob/47cce544a31ed5577ffe2963f67acb4144ee0232/src/js/array.js#L1012\n            //     return a.__renderidx - b.__renderidx;\n            // }\n            return a.z2 - b.z2;\n        }\n        return a.z - b.z;\n    }\n    return a.zlevel - b.zlevel;\n}\n/**\n * 内容仓库 (M)\n * @alias module:zrender/Storage\n * @constructor\n */\nvar Storage = function () { // jshint ignore:line\n    this._roots = [];\n\n    this._displayList = [];\n\n    this._displayListLen = 0;\n};\n\nStorage.prototype = {\n\n    constructor: Storage,\n\n    /**\n     * @param  {Function} cb\n     *\n     */\n    traverse: function (cb, context) {\n        for (var i = 0; i < this._roots.length; i++) {\n            this._roots[i].traverse(cb, context);\n        }\n    },\n\n    /**\n     * 返回所有图形的绘制队列\n     * @param {boolean} [update=false] 是否在返回前更新该数组\n     * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组, 在 update 为 true 的时候有效\n     *\n     * 详见{@link module:zrender/graphic/Displayable.prototype.updateDisplayList}\n     * @return {Array.<module:zrender/graphic/Displayable>}\n     */\n    getDisplayList: function (update, includeIgnore) {\n        includeIgnore = includeIgnore || false;\n        if (update) {\n            this.updateDisplayList(includeIgnore);\n        }\n        return this._displayList;\n    },\n\n    /**\n     * 更新图形的绘制队列。\n     * 每次绘制前都会调用，该方法会先深度优先遍历整个树，更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中，\n     * 最后根据绘制的优先级（zlevel > z > 插入顺序）排序得到绘制队列\n     * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组\n     */\n    updateDisplayList: function (includeIgnore) {\n        this._displayListLen = 0;\n\n        var roots = this._roots;\n        var displayList = this._displayList;\n        for (var i = 0, len = roots.length; i < len; i++) {\n            this._updateAndAddDisplayable(roots[i], null, includeIgnore);\n        }\n\n        displayList.length = this._displayListLen;\n\n        env$1.canvasSupported && sort(displayList, shapeCompareFunc);\n    },\n\n    _updateAndAddDisplayable: function (el, clipPaths, includeIgnore) {\n\n        if (el.ignore && !includeIgnore) {\n            return;\n        }\n\n        el.beforeUpdate();\n\n        if (el.__dirty) {\n\n            el.update();\n\n        }\n\n        el.afterUpdate();\n\n        var userSetClipPath = el.clipPath;\n        if (userSetClipPath) {\n\n            // FIXME 效率影响\n            if (clipPaths) {\n                clipPaths = clipPaths.slice();\n            }\n            else {\n                clipPaths = [];\n            }\n\n            var currentClipPath = userSetClipPath;\n            var parentClipPath = el;\n            // Recursively add clip path\n            while (currentClipPath) {\n                // clipPath 的变换是基于使用这个 clipPath 的元素\n                currentClipPath.parent = parentClipPath;\n                currentClipPath.updateTransform();\n\n                clipPaths.push(currentClipPath);\n\n                parentClipPath = currentClipPath;\n                currentClipPath = currentClipPath.clipPath;\n            }\n        }\n\n        if (el.isGroup) {\n            var children = el._children;\n\n            for (var i = 0; i < children.length; i++) {\n                var child = children[i];\n\n                // Force to mark as dirty if group is dirty\n                // FIXME __dirtyPath ?\n                if (el.__dirty) {\n                    child.__dirty = true;\n                }\n\n                this._updateAndAddDisplayable(child, clipPaths, includeIgnore);\n            }\n\n            // Mark group clean here\n            el.__dirty = false;\n\n        }\n        else {\n            el.__clipPaths = clipPaths;\n\n            this._displayList[this._displayListLen++] = el;\n        }\n    },\n\n    /**\n     * 添加图形(Shape)或者组(Group)到根节点\n     * @param {module:zrender/Element} el\n     */\n    addRoot: function (el) {\n        if (el.__storage === this) {\n            return;\n        }\n\n        if (el instanceof Group) {\n            el.addChildrenToStorage(this);\n        }\n\n        this.addToStorage(el);\n        this._roots.push(el);\n    },\n\n    /**\n     * 删除指定的图形(Shape)或者组(Group)\n     * @param {string|Array.<string>} [el] 如果为空清空整个Storage\n     */\n    delRoot: function (el) {\n        if (el == null) {\n            // 不指定el清空\n            for (var i = 0; i < this._roots.length; i++) {\n                var root = this._roots[i];\n                if (root instanceof Group) {\n                    root.delChildrenFromStorage(this);\n                }\n            }\n\n            this._roots = [];\n            this._displayList = [];\n            this._displayListLen = 0;\n\n            return;\n        }\n\n        if (el instanceof Array) {\n            for (var i = 0, l = el.length; i < l; i++) {\n                this.delRoot(el[i]);\n            }\n            return;\n        }\n\n\n        var idx = indexOf(this._roots, el);\n        if (idx >= 0) {\n            this.delFromStorage(el);\n            this._roots.splice(idx, 1);\n            if (el instanceof Group) {\n                el.delChildrenFromStorage(this);\n            }\n        }\n    },\n\n    addToStorage: function (el) {\n        if (el) {\n            el.__storage = this;\n            el.dirty(false);\n        }\n        return this;\n    },\n\n    delFromStorage: function (el) {\n        if (el) {\n            el.__storage = null;\n        }\n\n        return this;\n    },\n\n    /**\n     * 清空并且释放Storage\n     */\n    dispose: function () {\n        this._renderList =\n        this._roots = null;\n    },\n\n    displayableSortFunc: shapeCompareFunc\n};\n\nvar SHADOW_PROPS = {\n    'shadowBlur': 1,\n    'shadowOffsetX': 1,\n    'shadowOffsetY': 1,\n    'textShadowBlur': 1,\n    'textShadowOffsetX': 1,\n    'textShadowOffsetY': 1,\n    'textBoxShadowBlur': 1,\n    'textBoxShadowOffsetX': 1,\n    'textBoxShadowOffsetY': 1\n};\n\nvar fixShadow = function (ctx, propName, value) {\n    if (SHADOW_PROPS.hasOwnProperty(propName)) {\n        return value *= ctx.dpr;\n    }\n    return value;\n};\n\nvar ContextCachedBy = {\n    NONE: 0,\n    STYLE_BIND: 1,\n    PLAIN_TEXT: 2\n};\n\n// Avoid confused with 0/false.\nvar WILL_BE_RESTORED = 9;\n\nvar STYLE_COMMON_PROPS = [\n    ['shadowBlur', 0], ['shadowOffsetX', 0], ['shadowOffsetY', 0], ['shadowColor', '#000'],\n    ['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]\n];\n\n// var SHADOW_PROPS = STYLE_COMMON_PROPS.slice(0, 4);\n// var LINE_PROPS = STYLE_COMMON_PROPS.slice(4);\n\nvar Style = function (opts) {\n    this.extendFrom(opts, false);\n};\n\nfunction createLinearGradient(ctx, obj, rect) {\n    var x = obj.x == null ? 0 : obj.x;\n    var x2 = obj.x2 == null ? 1 : obj.x2;\n    var y = obj.y == null ? 0 : obj.y;\n    var y2 = obj.y2 == null ? 0 : obj.y2;\n\n    if (!obj.global) {\n        x = x * rect.width + rect.x;\n        x2 = x2 * rect.width + rect.x;\n        y = y * rect.height + rect.y;\n        y2 = y2 * rect.height + rect.y;\n    }\n\n    // Fix NaN when rect is Infinity\n    x = isNaN(x) ? 0 : x;\n    x2 = isNaN(x2) ? 1 : x2;\n    y = isNaN(y) ? 0 : y;\n    y2 = isNaN(y2) ? 0 : y2;\n\n    var canvasGradient = ctx.createLinearGradient(x, y, x2, y2);\n\n    return canvasGradient;\n}\n\nfunction createRadialGradient(ctx, obj, rect) {\n    var width = rect.width;\n    var height = rect.height;\n    var min = Math.min(width, height);\n\n    var x = obj.x == null ? 0.5 : obj.x;\n    var y = obj.y == null ? 0.5 : obj.y;\n    var r = obj.r == null ? 0.5 : obj.r;\n    if (!obj.global) {\n        x = x * width + rect.x;\n        y = y * height + rect.y;\n        r = r * min;\n    }\n\n    var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r);\n\n    return canvasGradient;\n}\n\n\nStyle.prototype = {\n\n    constructor: Style,\n\n    /**\n     * @type {string}\n     */\n    fill: '#000',\n\n    /**\n     * @type {string}\n     */\n    stroke: null,\n\n    /**\n     * @type {number}\n     */\n    opacity: 1,\n\n    /**\n     * @type {number}\n     */\n    fillOpacity: null,\n\n    /**\n     * @type {number}\n     */\n    strokeOpacity: null,\n\n    /**\n     * @type {Array.<number>}\n     */\n    lineDash: null,\n\n    /**\n     * @type {number}\n     */\n    lineDashOffset: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowOffsetY: 0,\n\n    /**\n     * @type {number}\n     */\n    lineWidth: 1,\n\n    /**\n     * If stroke ignore scale\n     * @type {Boolean}\n     */\n    strokeNoScale: false,\n\n    // Bounding rect text configuration\n    // Not affected by element transform\n    /**\n     * @type {string}\n     */\n    text: null,\n\n    /**\n     * If `fontSize` or `fontFamily` exists, `font` will be reset by\n     * `fontSize`, `fontStyle`, `fontWeight`, `fontFamily`.\n     * So do not visit it directly in upper application (like echarts),\n     * but use `contain/text#makeFont` instead.\n     * @type {string}\n     */\n    font: null,\n\n    /**\n     * The same as font. Use font please.\n     * @deprecated\n     * @type {string}\n     */\n    textFont: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontStyle: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontWeight: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * Should be 12 but not '12px'.\n     * @type {number}\n     */\n    fontSize: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontFamily: null,\n\n    /**\n     * Reserved for special functinality, like 'hr'.\n     * @type {string}\n     */\n    textTag: null,\n\n    /**\n     * @type {string}\n     */\n    textFill: '#000',\n\n    /**\n     * @type {string}\n     */\n    textStroke: null,\n\n    /**\n     * @type {number}\n     */\n    textWidth: null,\n\n    /**\n     * Only for textBackground.\n     * @type {number}\n     */\n    textHeight: null,\n\n    /**\n     * textStroke may be set as some color as a default\n     * value in upper applicaion, where the default value\n     * of textStrokeWidth should be 0 to make sure that\n     * user can choose to do not use text stroke.\n     * @type {number}\n     */\n    textStrokeWidth: 0,\n\n    /**\n     * @type {number}\n     */\n    textLineHeight: null,\n\n    /**\n     * 'inside', 'left', 'right', 'top', 'bottom'\n     * [x, y]\n     * Based on x, y of rect.\n     * @type {string|Array.<number>}\n     * @default 'inside'\n     */\n    textPosition: 'inside',\n\n    /**\n     * If not specified, use the boundingRect of a `displayable`.\n     * @type {Object}\n     */\n    textRect: null,\n\n    /**\n     * [x, y]\n     * @type {Array.<number>}\n     */\n    textOffset: null,\n\n    /**\n     * @type {string}\n     */\n    textAlign: null,\n\n    /**\n     * @type {string}\n     */\n    textVerticalAlign: null,\n\n    /**\n     * @type {number}\n     */\n    textDistance: 5,\n\n    /**\n     * @type {string}\n     */\n    textShadowColor: 'transparent',\n\n    /**\n     * @type {number}\n     */\n    textShadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    textShadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    textShadowOffsetY: 0,\n\n    /**\n     * @type {string}\n     */\n    textBoxShadowColor: 'transparent',\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowOffsetY: 0,\n\n    /**\n     * Whether transform text.\n     * Only useful in Path and Image element\n     * @type {boolean}\n     */\n    transformText: false,\n\n    /**\n     * Text rotate around position of Path or Image\n     * Only useful in Path and Image element and transformText is false.\n     */\n    textRotation: 0,\n\n    /**\n     * Text origin of text rotation, like [10, 40].\n     * Based on x, y of rect.\n     * Useful in label rotation of circular symbol.\n     * By default, this origin is textPosition.\n     * Can be 'center'.\n     * @type {string|Array.<number>}\n     */\n    textOrigin: null,\n\n    /**\n     * @type {string}\n     */\n    textBackgroundColor: null,\n\n    /**\n     * @type {string}\n     */\n    textBorderColor: null,\n\n    /**\n     * @type {number}\n     */\n    textBorderWidth: 0,\n\n    /**\n     * @type {number}\n     */\n    textBorderRadius: 0,\n\n    /**\n     * Can be `2` or `[2, 4]` or `[2, 3, 4, 5]`\n     * @type {number|Array.<number>}\n     */\n    textPadding: null,\n\n    /**\n     * Text styles for rich text.\n     * @type {Object}\n     */\n    rich: null,\n\n    /**\n     * {outerWidth, outerHeight, ellipsis, placeholder}\n     * @type {Object}\n     */\n    truncate: null,\n\n    /**\n     * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation\n     * @type {string}\n     */\n    blend: null,\n\n    /**\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    bind: function (ctx, el, prevEl) {\n        var style = this;\n        var prevStyle = prevEl && prevEl.style;\n        // If no prevStyle, it means first draw.\n        // Only apply cache if the last time cachced by this function.\n        var notCheckCache = !prevStyle || ctx.__attrCachedBy !== ContextCachedBy.STYLE_BIND;\n\n        ctx.__attrCachedBy = ContextCachedBy.STYLE_BIND;\n\n        for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {\n            var prop = STYLE_COMMON_PROPS[i];\n            var styleName = prop[0];\n\n            if (notCheckCache || style[styleName] !== prevStyle[styleName]) {\n                // FIXME Invalid property value will cause style leak from previous element.\n                ctx[styleName] =\n                    fixShadow(ctx, styleName, style[styleName] || prop[1]);\n            }\n        }\n\n        if ((notCheckCache || style.fill !== prevStyle.fill)) {\n            ctx.fillStyle = style.fill;\n        }\n        if ((notCheckCache || style.stroke !== prevStyle.stroke)) {\n            ctx.strokeStyle = style.stroke;\n        }\n        if ((notCheckCache || style.opacity !== prevStyle.opacity)) {\n            ctx.globalAlpha = style.opacity == null ? 1 : style.opacity;\n        }\n\n        if ((notCheckCache || style.blend !== prevStyle.blend)) {\n            ctx.globalCompositeOperation = style.blend || 'source-over';\n        }\n        if (this.hasStroke()) {\n            var lineWidth = style.lineWidth;\n            ctx.lineWidth = lineWidth / (\n                (this.strokeNoScale && el && el.getLineScale) ? el.getLineScale() : 1\n            );\n        }\n    },\n\n    hasFill: function () {\n        var fill = this.fill;\n        return fill != null && fill !== 'none';\n    },\n\n    hasStroke: function () {\n        var stroke = this.stroke;\n        return stroke != null && stroke !== 'none' && this.lineWidth > 0;\n    },\n\n    /**\n     * Extend from other style\n     * @param {zrender/graphic/Style} otherStyle\n     * @param {boolean} overwrite true: overwrirte any way.\n     *                            false: overwrite only when !target.hasOwnProperty\n     *                            others: overwrite when property is not null/undefined.\n     */\n    extendFrom: function (otherStyle, overwrite) {\n        if (otherStyle) {\n            for (var name in otherStyle) {\n                if (otherStyle.hasOwnProperty(name)\n                    && (overwrite === true\n                        || (\n                            overwrite === false\n                                ? !this.hasOwnProperty(name)\n                                : otherStyle[name] != null\n                        )\n                    )\n                ) {\n                    this[name] = otherStyle[name];\n                }\n            }\n        }\n    },\n\n    /**\n     * Batch setting style with a given object\n     * @param {Object|string} obj\n     * @param {*} [obj]\n     */\n    set: function (obj, value) {\n        if (typeof obj === 'string') {\n            this[obj] = value;\n        }\n        else {\n            this.extendFrom(obj, true);\n        }\n    },\n\n    /**\n     * Clone\n     * @return {zrender/graphic/Style} [description]\n     */\n    clone: function () {\n        var newStyle = new this.constructor();\n        newStyle.extendFrom(this, true);\n        return newStyle;\n    },\n\n    getGradient: function (ctx, obj, rect) {\n        var method = obj.type === 'radial' ? createRadialGradient : createLinearGradient;\n        var canvasGradient = method(ctx, obj, rect);\n        var colorStops = obj.colorStops;\n        for (var i = 0; i < colorStops.length; i++) {\n            canvasGradient.addColorStop(\n                colorStops[i].offset, colorStops[i].color\n            );\n        }\n        return canvasGradient;\n    }\n\n};\n\nvar styleProto = Style.prototype;\nfor (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {\n    var prop = STYLE_COMMON_PROPS[i];\n    if (!(prop[0] in styleProto)) {\n        styleProto[prop[0]] = prop[1];\n    }\n}\n\n// Provide for others\nStyle.getGradient = styleProto.getGradient;\n\nvar Pattern = function (image, repeat) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {image: ...}`, where this constructor will not be called.\n\n    this.image = image;\n    this.repeat = repeat;\n\n    // Can be cloned\n    this.type = 'pattern';\n};\n\nPattern.prototype.getCanvasPattern = function (ctx) {\n    return ctx.createPattern(this.image, this.repeat || 'repeat');\n};\n\n/**\n * @module zrender/Layer\n * @author pissang(https://www.github.com/pissang)\n */\n\nfunction returnFalse() {\n    return false;\n}\n\n/**\n * 创建dom\n *\n * @inner\n * @param {string} id dom id 待用\n * @param {Painter} painter painter instance\n * @param {number} number\n */\nfunction createDom(id, painter, dpr) {\n    var newDom = createCanvas();\n    var width = painter.getWidth();\n    var height = painter.getHeight();\n\n    var newDomStyle = newDom.style;\n    if (newDomStyle) {  // In node or some other non-browser environment\n        newDomStyle.position = 'absolute';\n        newDomStyle.left = 0;\n        newDomStyle.top = 0;\n        newDomStyle.width = width + 'px';\n        newDomStyle.height = height + 'px';\n\n        newDom.setAttribute('data-zr-dom-id', id);\n    }\n\n    newDom.width = width * dpr;\n    newDom.height = height * dpr;\n\n    return newDom;\n}\n\n/**\n * @alias module:zrender/Layer\n * @constructor\n * @extends module:zrender/mixin/Transformable\n * @param {string} id\n * @param {module:zrender/Painter} painter\n * @param {number} [dpr]\n */\nvar Layer = function (id, painter, dpr) {\n    var dom;\n    dpr = dpr || devicePixelRatio;\n    if (typeof id === 'string') {\n        dom = createDom(id, painter, dpr);\n    }\n    // Not using isDom because in node it will return false\n    else if (isObject$1(id)) {\n        dom = id;\n        id = dom.id;\n    }\n    this.id = id;\n    this.dom = dom;\n\n    var domStyle = dom.style;\n    if (domStyle) { // Not in node\n        dom.onselectstart = returnFalse; // 避免页面选中的尴尬\n        domStyle['-webkit-user-select'] = 'none';\n        domStyle['user-select'] = 'none';\n        domStyle['-webkit-touch-callout'] = 'none';\n        domStyle['-webkit-tap-highlight-color'] = 'rgba(0,0,0,0)';\n        domStyle['padding'] = 0;\n        domStyle['margin'] = 0;\n        domStyle['border-width'] = 0;\n    }\n\n    this.domBack = null;\n    this.ctxBack = null;\n\n    this.painter = painter;\n\n    this.config = null;\n\n    // Configs\n    /**\n     * 每次清空画布的颜色\n     * @type {string}\n     * @default 0\n     */\n    this.clearColor = 0;\n    /**\n     * 是否开启动态模糊\n     * @type {boolean}\n     * @default false\n     */\n    this.motionBlur = false;\n    /**\n     * 在开启动态模糊的时候使用，与上一帧混合的alpha值，值越大尾迹越明显\n     * @type {number}\n     * @default 0.7\n     */\n    this.lastFrameAlpha = 0.7;\n\n    /**\n     * Layer dpr\n     * @type {number}\n     */\n    this.dpr = dpr;\n};\n\nLayer.prototype = {\n\n    constructor: Layer,\n\n    __dirty: true,\n\n    __used: false,\n\n    __drawIndex: 0,\n    __startIndex: 0,\n    __endIndex: 0,\n\n    incremental: false,\n\n    getElementCount: function () {\n        return this.__endIndex - this.__startIndex;\n    },\n\n    initContext: function () {\n        this.ctx = this.dom.getContext('2d');\n        this.ctx.dpr = this.dpr;\n    },\n\n    createBackBuffer: function () {\n        var dpr = this.dpr;\n\n        this.domBack = createDom('back-' + this.id, this.painter, dpr);\n        this.ctxBack = this.domBack.getContext('2d');\n\n        if (dpr !== 1) {\n            this.ctxBack.scale(dpr, dpr);\n        }\n    },\n\n    /**\n     * @param  {number} width\n     * @param  {number} height\n     */\n    resize: function (width, height) {\n        var dpr = this.dpr;\n\n        var dom = this.dom;\n        var domStyle = dom.style;\n        var domBack = this.domBack;\n\n        if (domStyle) {\n            domStyle.width = width + 'px';\n            domStyle.height = height + 'px';\n        }\n\n        dom.width = width * dpr;\n        dom.height = height * dpr;\n\n        if (domBack) {\n            domBack.width = width * dpr;\n            domBack.height = height * dpr;\n\n            if (dpr !== 1) {\n                this.ctxBack.scale(dpr, dpr);\n            }\n        }\n    },\n\n    /**\n     * 清空该层画布\n     * @param {boolean} [clearAll]=false Clear all with out motion blur\n     * @param {Color} [clearColor]\n     */\n    clear: function (clearAll, clearColor) {\n        var dom = this.dom;\n        var ctx = this.ctx;\n        var width = dom.width;\n        var height = dom.height;\n\n        var clearColor = clearColor || this.clearColor;\n        var haveMotionBLur = this.motionBlur && !clearAll;\n        var lastFrameAlpha = this.lastFrameAlpha;\n\n        var dpr = this.dpr;\n\n        if (haveMotionBLur) {\n            if (!this.domBack) {\n                this.createBackBuffer();\n            }\n\n            this.ctxBack.globalCompositeOperation = 'copy';\n            this.ctxBack.drawImage(\n                dom, 0, 0,\n                width / dpr,\n                height / dpr\n            );\n        }\n\n        ctx.clearRect(0, 0, width, height);\n        if (clearColor && clearColor !== 'transparent') {\n            var clearColorGradientOrPattern;\n            // Gradient\n            if (clearColor.colorStops) {\n                // Cache canvas gradient\n                clearColorGradientOrPattern = clearColor.__canvasGradient || Style.getGradient(ctx, clearColor, {\n                    x: 0,\n                    y: 0,\n                    width: width,\n                    height: height\n                });\n\n                clearColor.__canvasGradient = clearColorGradientOrPattern;\n            }\n            // Pattern\n            else if (clearColor.image) {\n                clearColorGradientOrPattern = Pattern.prototype.getCanvasPattern.call(clearColor, ctx);\n            }\n            ctx.save();\n            ctx.fillStyle = clearColorGradientOrPattern || clearColor;\n            ctx.fillRect(0, 0, width, height);\n            ctx.restore();\n        }\n\n        if (haveMotionBLur) {\n            var domBack = this.domBack;\n            ctx.save();\n            ctx.globalAlpha = lastFrameAlpha;\n            ctx.drawImage(domBack, 0, 0, width, height);\n            ctx.restore();\n        }\n    }\n};\n\nvar requestAnimationFrame = (\n    typeof window !== 'undefined'\n    && (\n        (window.requestAnimationFrame && window.requestAnimationFrame.bind(window))\n        // https://github.com/ecomfe/zrender/issues/189#issuecomment-224919809\n        || (window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window))\n        || window.mozRequestAnimationFrame\n        || window.webkitRequestAnimationFrame\n    )\n) || function (func) {\n    setTimeout(func, 16);\n};\n\nvar globalImageCache = new LRU(50);\n\n/**\n * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc\n * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image\n */\nfunction findExistImage(newImageOrSrc) {\n    if (typeof newImageOrSrc === 'string') {\n        var cachedImgObj = globalImageCache.get(newImageOrSrc);\n        return cachedImgObj && cachedImgObj.image;\n    }\n    else {\n        return newImageOrSrc;\n    }\n}\n\n/**\n * Caution: User should cache loaded images, but not just count on LRU.\n * Consider if required images more than LRU size, will dead loop occur?\n *\n * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc\n * @param {HTMLImageElement|HTMLCanvasElement|Canvas} image Existent image.\n * @param {module:zrender/Element} [hostEl] For calling `dirty`.\n * @param {Function} [cb] params: (image, cbPayload)\n * @param {Object} [cbPayload] Payload on cb calling.\n * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image\n */\nfunction createOrUpdateImage(newImageOrSrc, image, hostEl, cb, cbPayload) {\n    if (!newImageOrSrc) {\n        return image;\n    }\n    else if (typeof newImageOrSrc === 'string') {\n\n        // Image should not be loaded repeatly.\n        if ((image && image.__zrImageSrc === newImageOrSrc) || !hostEl) {\n            return image;\n        }\n\n        // Only when there is no existent image or existent image src\n        // is different, this method is responsible for load.\n        var cachedImgObj = globalImageCache.get(newImageOrSrc);\n\n        var pendingWrap = {hostEl: hostEl, cb: cb, cbPayload: cbPayload};\n\n        if (cachedImgObj) {\n            image = cachedImgObj.image;\n            !isImageReady(image) && cachedImgObj.pending.push(pendingWrap);\n        }\n        else {\n            image = new Image();\n            image.onload = image.onerror = imageOnLoad;\n\n            globalImageCache.put(\n                newImageOrSrc,\n                image.__cachedImgObj = {\n                    image: image,\n                    pending: [pendingWrap]\n                }\n            );\n\n            image.src = image.__zrImageSrc = newImageOrSrc;\n        }\n\n        return image;\n    }\n    // newImageOrSrc is an HTMLImageElement or HTMLCanvasElement or Canvas\n    else {\n        return newImageOrSrc;\n    }\n}\n\nfunction imageOnLoad() {\n    var cachedImgObj = this.__cachedImgObj;\n    this.onload = this.onerror = this.__cachedImgObj = null;\n\n    for (var i = 0; i < cachedImgObj.pending.length; i++) {\n        var pendingWrap = cachedImgObj.pending[i];\n        var cb = pendingWrap.cb;\n        cb && cb(this, pendingWrap.cbPayload);\n        pendingWrap.hostEl.dirty();\n    }\n    cachedImgObj.pending.length = 0;\n}\n\nfunction isImageReady(image) {\n    return image && image.width && image.height;\n}\n\nvar textWidthCache = {};\nvar textWidthCacheCounter = 0;\n\nvar TEXT_CACHE_MAX = 5000;\nvar STYLE_REG = /\\{([a-zA-Z0-9_]+)\\|([^}]*)\\}/g;\n\nvar DEFAULT_FONT$1 = '12px sans-serif';\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar methods$1 = {};\n\nfunction $override$1(name, fn) {\n    methods$1[name] = fn;\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @return {number} width\n */\nfunction getWidth(text, font) {\n    font = font || DEFAULT_FONT$1;\n    var key = text + ':' + font;\n    if (textWidthCache[key]) {\n        return textWidthCache[key];\n    }\n\n    var textLines = (text + '').split('\\n');\n    var width = 0;\n\n    for (var i = 0, l = textLines.length; i < l; i++) {\n        // textContain.measureText may be overrided in SVG or VML\n        width = Math.max(measureText(textLines[i], font).width, width);\n    }\n\n    if (textWidthCacheCounter > TEXT_CACHE_MAX) {\n        textWidthCacheCounter = 0;\n        textWidthCache = {};\n    }\n    textWidthCacheCounter++;\n    textWidthCache[key] = width;\n\n    return width;\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @param {string} [textAlign='left']\n * @param {string} [textVerticalAlign='top']\n * @param {Array.<number>} [textPadding]\n * @param {Object} [rich]\n * @param {Object} [truncate]\n * @return {Object} {x, y, width, height, lineHeight}\n */\nfunction getBoundingRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) {\n    return rich\n        ? getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate)\n        : getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate);\n}\n\nfunction getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate) {\n    var contentBlock = parsePlainText(text, font, textPadding, textLineHeight, truncate);\n    var outerWidth = getWidth(text, font);\n    if (textPadding) {\n        outerWidth += textPadding[1] + textPadding[3];\n    }\n    var outerHeight = contentBlock.outerHeight;\n\n    var x = adjustTextX(0, outerWidth, textAlign);\n    var y = adjustTextY(0, outerHeight, textVerticalAlign);\n\n    var rect = new BoundingRect(x, y, outerWidth, outerHeight);\n    rect.lineHeight = contentBlock.lineHeight;\n\n    return rect;\n}\n\nfunction getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) {\n    var contentBlock = parseRichText(text, {\n        rich: rich,\n        truncate: truncate,\n        font: font,\n        textAlign: textAlign,\n        textPadding: textPadding,\n        textLineHeight: textLineHeight\n    });\n    var outerWidth = contentBlock.outerWidth;\n    var outerHeight = contentBlock.outerHeight;\n\n    var x = adjustTextX(0, outerWidth, textAlign);\n    var y = adjustTextY(0, outerHeight, textVerticalAlign);\n\n    return new BoundingRect(x, y, outerWidth, outerHeight);\n}\n\n/**\n * @public\n * @param {number} x\n * @param {number} width\n * @param {string} [textAlign='left']\n * @return {number} Adjusted x.\n */\nfunction adjustTextX(x, width, textAlign) {\n    // FIXME Right to left language\n    if (textAlign === 'right') {\n        x -= width;\n    }\n    else if (textAlign === 'center') {\n        x -= width / 2;\n    }\n    return x;\n}\n\n/**\n * @public\n * @param {number} y\n * @param {number} height\n * @param {string} [textVerticalAlign='top']\n * @return {number} Adjusted y.\n */\nfunction adjustTextY(y, height, textVerticalAlign) {\n    if (textVerticalAlign === 'middle') {\n        y -= height / 2;\n    }\n    else if (textVerticalAlign === 'bottom') {\n        y -= height;\n    }\n    return y;\n}\n\n/**\n * @public\n * @param {stirng} textPosition\n * @param {Object} rect {x, y, width, height}\n * @param {number} distance\n * @return {Object} {x, y, textAlign, textVerticalAlign}\n */\nfunction adjustTextPositionOnRect(textPosition, rect, distance) {\n\n    var x = rect.x;\n    var y = rect.y;\n\n    var height = rect.height;\n    var width = rect.width;\n    var halfHeight = height / 2;\n\n    var textAlign = 'left';\n    var textVerticalAlign = 'top';\n\n    switch (textPosition) {\n        case 'left':\n            x -= distance;\n            y += halfHeight;\n            textAlign = 'right';\n            textVerticalAlign = 'middle';\n            break;\n        case 'right':\n            x += distance + width;\n            y += halfHeight;\n            textVerticalAlign = 'middle';\n            break;\n        case 'top':\n            x += width / 2;\n            y -= distance;\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            break;\n        case 'bottom':\n            x += width / 2;\n            y += height + distance;\n            textAlign = 'center';\n            break;\n        case 'inside':\n            x += width / 2;\n            y += halfHeight;\n            textAlign = 'center';\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideLeft':\n            x += distance;\n            y += halfHeight;\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideRight':\n            x += width - distance;\n            y += halfHeight;\n            textAlign = 'right';\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideTop':\n            x += width / 2;\n            y += distance;\n            textAlign = 'center';\n            break;\n        case 'insideBottom':\n            x += width / 2;\n            y += height - distance;\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            break;\n        case 'insideTopLeft':\n            x += distance;\n            y += distance;\n            break;\n        case 'insideTopRight':\n            x += width - distance;\n            y += distance;\n            textAlign = 'right';\n            break;\n        case 'insideBottomLeft':\n            x += distance;\n            y += height - distance;\n            textVerticalAlign = 'bottom';\n            break;\n        case 'insideBottomRight':\n            x += width - distance;\n            y += height - distance;\n            textAlign = 'right';\n            textVerticalAlign = 'bottom';\n            break;\n    }\n\n    return {\n        x: x,\n        y: y,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\n/**\n * Show ellipsis if overflow.\n *\n * @public\n * @param  {string} text\n * @param  {string} containerWidth\n * @param  {string} font\n * @param  {number} [ellipsis='...']\n * @param  {Object} [options]\n * @param  {number} [options.maxIterations=3]\n * @param  {number} [options.minChar=0] If truncate result are less\n *                  then minChar, ellipsis will not show, which is\n *                  better for user hint in some cases.\n * @param  {number} [options.placeholder=''] When all truncated, use the placeholder.\n * @return {string}\n */\nfunction truncateText(text, containerWidth, font, ellipsis, options) {\n    if (!containerWidth) {\n        return '';\n    }\n\n    var textLines = (text + '').split('\\n');\n    options = prepareTruncateOptions(containerWidth, font, ellipsis, options);\n\n    // FIXME\n    // It is not appropriate that every line has '...' when truncate multiple lines.\n    for (var i = 0, len = textLines.length; i < len; i++) {\n        textLines[i] = truncateSingleLine(textLines[i], options);\n    }\n\n    return textLines.join('\\n');\n}\n\nfunction prepareTruncateOptions(containerWidth, font, ellipsis, options) {\n    options = extend({}, options);\n\n    options.font = font;\n    var ellipsis = retrieve2(ellipsis, '...');\n    options.maxIterations = retrieve2(options.maxIterations, 2);\n    var minChar = options.minChar = retrieve2(options.minChar, 0);\n    // FIXME\n    // Other languages?\n    options.cnCharWidth = getWidth('国', font);\n    // FIXME\n    // Consider proportional font?\n    var ascCharWidth = options.ascCharWidth = getWidth('a', font);\n    options.placeholder = retrieve2(options.placeholder, '');\n\n    // Example 1: minChar: 3, text: 'asdfzxcv', truncate result: 'asdf', but not: 'a...'.\n    // Example 2: minChar: 3, text: '维度', truncate result: '维', but not: '...'.\n    var contentWidth = containerWidth = Math.max(0, containerWidth - 1); // Reserve some gap.\n    for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) {\n        contentWidth -= ascCharWidth;\n    }\n\n    var ellipsisWidth = getWidth(ellipsis, font);\n    if (ellipsisWidth > contentWidth) {\n        ellipsis = '';\n        ellipsisWidth = 0;\n    }\n\n    contentWidth = containerWidth - ellipsisWidth;\n\n    options.ellipsis = ellipsis;\n    options.ellipsisWidth = ellipsisWidth;\n    options.contentWidth = contentWidth;\n    options.containerWidth = containerWidth;\n\n    return options;\n}\n\nfunction truncateSingleLine(textLine, options) {\n    var containerWidth = options.containerWidth;\n    var font = options.font;\n    var contentWidth = options.contentWidth;\n\n    if (!containerWidth) {\n        return '';\n    }\n\n    var lineWidth = getWidth(textLine, font);\n\n    if (lineWidth <= containerWidth) {\n        return textLine;\n    }\n\n    for (var j = 0; ; j++) {\n        if (lineWidth <= contentWidth || j >= options.maxIterations) {\n            textLine += options.ellipsis;\n            break;\n        }\n\n        var subLength = j === 0\n            ? estimateLength(textLine, contentWidth, options.ascCharWidth, options.cnCharWidth)\n            : lineWidth > 0\n            ? Math.floor(textLine.length * contentWidth / lineWidth)\n            : 0;\n\n        textLine = textLine.substr(0, subLength);\n        lineWidth = getWidth(textLine, font);\n    }\n\n    if (textLine === '') {\n        textLine = options.placeholder;\n    }\n\n    return textLine;\n}\n\nfunction estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) {\n    var width = 0;\n    var i = 0;\n    for (var len = text.length; i < len && width < contentWidth; i++) {\n        var charCode = text.charCodeAt(i);\n        width += (0 <= charCode && charCode <= 127) ? ascCharWidth : cnCharWidth;\n    }\n    return i;\n}\n\n/**\n * @public\n * @param {string} font\n * @return {number} line height\n */\nfunction getLineHeight(font) {\n    // FIXME A rough approach.\n    return getWidth('国', font);\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @return {Object} width\n */\nfunction measureText(text, font) {\n    return methods$1.measureText(text, font);\n}\n\n// Avoid assign to an exported variable, for transforming to cjs.\nmethods$1.measureText = function (text, font) {\n    var ctx = getContext();\n    ctx.font = font || DEFAULT_FONT$1;\n    return ctx.measureText(text);\n};\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @param {Object} [truncate]\n * @return {Object} block: {lineHeight, lines, height, outerHeight}\n *  Notice: for performance, do not calculate outerWidth util needed.\n */\nfunction parsePlainText(text, font, padding, textLineHeight, truncate) {\n    text != null && (text += '');\n\n    var lineHeight = retrieve2(textLineHeight, getLineHeight(font));\n    var lines = text ? text.split('\\n') : [];\n    var height = lines.length * lineHeight;\n    var outerHeight = height;\n\n    if (padding) {\n        outerHeight += padding[0] + padding[2];\n    }\n\n    if (text && truncate) {\n        var truncOuterHeight = truncate.outerHeight;\n        var truncOuterWidth = truncate.outerWidth;\n        if (truncOuterHeight != null && outerHeight > truncOuterHeight) {\n            text = '';\n            lines = [];\n        }\n        else if (truncOuterWidth != null) {\n            var options = prepareTruncateOptions(\n                truncOuterWidth - (padding ? padding[1] + padding[3] : 0),\n                font,\n                truncate.ellipsis,\n                {minChar: truncate.minChar, placeholder: truncate.placeholder}\n            );\n\n            // FIXME\n            // It is not appropriate that every line has '...' when truncate multiple lines.\n            for (var i = 0, len = lines.length; i < len; i++) {\n                lines[i] = truncateSingleLine(lines[i], options);\n            }\n        }\n    }\n\n    return {\n        lines: lines,\n        height: height,\n        outerHeight: outerHeight,\n        lineHeight: lineHeight\n    };\n}\n\n/**\n * For example: 'some text {a|some text}other text{b|some text}xxx{c|}xxx'\n * Also consider 'bbbb{a|xxx\\nzzz}xxxx\\naaaa'.\n *\n * @public\n * @param {string} text\n * @param {Object} style\n * @return {Object} block\n * {\n *      width,\n *      height,\n *      lines: [{\n *          lineHeight,\n *          width,\n *          tokens: [[{\n *              styleName,\n *              text,\n *              width,      // include textPadding\n *              height,     // include textPadding\n *              textWidth, // pure text width\n *              textHeight, // pure text height\n *              lineHeihgt,\n *              font,\n *              textAlign,\n *              textVerticalAlign\n *          }], [...], ...]\n *      }, ...]\n * }\n * If styleName is undefined, it is plain text.\n */\nfunction parseRichText(text, style) {\n    var contentBlock = {lines: [], width: 0, height: 0};\n\n    text != null && (text += '');\n    if (!text) {\n        return contentBlock;\n    }\n\n    var lastIndex = STYLE_REG.lastIndex = 0;\n    var result;\n    while ((result = STYLE_REG.exec(text)) != null) {\n        var matchedIndex = result.index;\n        if (matchedIndex > lastIndex) {\n            pushTokens(contentBlock, text.substring(lastIndex, matchedIndex));\n        }\n        pushTokens(contentBlock, result[2], result[1]);\n        lastIndex = STYLE_REG.lastIndex;\n    }\n\n    if (lastIndex < text.length) {\n        pushTokens(contentBlock, text.substring(lastIndex, text.length));\n    }\n\n    var lines = contentBlock.lines;\n    var contentHeight = 0;\n    var contentWidth = 0;\n    // For `textWidth: 100%`\n    var pendingList = [];\n\n    var stlPadding = style.textPadding;\n\n    var truncate = style.truncate;\n    var truncateWidth = truncate && truncate.outerWidth;\n    var truncateHeight = truncate && truncate.outerHeight;\n    if (stlPadding) {\n        truncateWidth != null && (truncateWidth -= stlPadding[1] + stlPadding[3]);\n        truncateHeight != null && (truncateHeight -= stlPadding[0] + stlPadding[2]);\n    }\n\n    // Calculate layout info of tokens.\n    for (var i = 0; i < lines.length; i++) {\n        var line = lines[i];\n        var lineHeight = 0;\n        var lineWidth = 0;\n\n        for (var j = 0; j < line.tokens.length; j++) {\n            var token = line.tokens[j];\n            var tokenStyle = token.styleName && style.rich[token.styleName] || {};\n            // textPadding should not inherit from style.\n            var textPadding = token.textPadding = tokenStyle.textPadding;\n\n            // textFont has been asigned to font by `normalizeStyle`.\n            var font = token.font = tokenStyle.font || style.font;\n\n            // textHeight can be used when textVerticalAlign is specified in token.\n            var tokenHeight = token.textHeight = retrieve2(\n                // textHeight should not be inherited, consider it can be specified\n                // as box height of the block.\n                tokenStyle.textHeight, getLineHeight(font)\n            );\n            textPadding && (tokenHeight += textPadding[0] + textPadding[2]);\n            token.height = tokenHeight;\n            token.lineHeight = retrieve3(\n                tokenStyle.textLineHeight, style.textLineHeight, tokenHeight\n            );\n\n            token.textAlign = tokenStyle && tokenStyle.textAlign || style.textAlign;\n            token.textVerticalAlign = tokenStyle && tokenStyle.textVerticalAlign || 'middle';\n\n            if (truncateHeight != null && contentHeight + token.lineHeight > truncateHeight) {\n                return {lines: [], width: 0, height: 0};\n            }\n\n            token.textWidth = getWidth(token.text, font);\n            var tokenWidth = tokenStyle.textWidth;\n            var tokenWidthNotSpecified = tokenWidth == null || tokenWidth === 'auto';\n\n            // Percent width, can be `100%`, can be used in drawing separate\n            // line when box width is needed to be auto.\n            if (typeof tokenWidth === 'string' && tokenWidth.charAt(tokenWidth.length - 1) === '%') {\n                token.percentWidth = tokenWidth;\n                pendingList.push(token);\n                tokenWidth = 0;\n                // Do not truncate in this case, because there is no user case\n                // and it is too complicated.\n            }\n            else {\n                if (tokenWidthNotSpecified) {\n                    tokenWidth = token.textWidth;\n\n                    // FIXME: If image is not loaded and textWidth is not specified, calling\n                    // `getBoundingRect()` will not get correct result.\n                    var textBackgroundColor = tokenStyle.textBackgroundColor;\n                    var bgImg = textBackgroundColor && textBackgroundColor.image;\n\n                    // Use cases:\n                    // (1) If image is not loaded, it will be loaded at render phase and call\n                    // `dirty()` and `textBackgroundColor.image` will be replaced with the loaded\n                    // image, and then the right size will be calculated here at the next tick.\n                    // See `graphic/helper/text.js`.\n                    // (2) If image loaded, and `textBackgroundColor.image` is image src string,\n                    // use `imageHelper.findExistImage` to find cached image.\n                    // `imageHelper.findExistImage` will always be called here before\n                    // `imageHelper.createOrUpdateImage` in `graphic/helper/text.js#renderRichText`\n                    // which ensures that image will not be rendered before correct size calcualted.\n                    if (bgImg) {\n                        bgImg = findExistImage(bgImg);\n                        if (isImageReady(bgImg)) {\n                            tokenWidth = Math.max(tokenWidth, bgImg.width * tokenHeight / bgImg.height);\n                        }\n                    }\n                }\n\n                var paddingW = textPadding ? textPadding[1] + textPadding[3] : 0;\n                tokenWidth += paddingW;\n\n                var remianTruncWidth = truncateWidth != null ? truncateWidth - lineWidth : null;\n\n                if (remianTruncWidth != null && remianTruncWidth < tokenWidth) {\n                    if (!tokenWidthNotSpecified || remianTruncWidth < paddingW) {\n                        token.text = '';\n                        token.textWidth = tokenWidth = 0;\n                    }\n                    else {\n                        token.text = truncateText(\n                            token.text, remianTruncWidth - paddingW, font, truncate.ellipsis,\n                            {minChar: truncate.minChar}\n                        );\n                        token.textWidth = getWidth(token.text, font);\n                        tokenWidth = token.textWidth + paddingW;\n                    }\n                }\n            }\n\n            lineWidth += (token.width = tokenWidth);\n            tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight));\n        }\n\n        line.width = lineWidth;\n        line.lineHeight = lineHeight;\n        contentHeight += lineHeight;\n        contentWidth = Math.max(contentWidth, lineWidth);\n    }\n\n    contentBlock.outerWidth = contentBlock.width = retrieve2(style.textWidth, contentWidth);\n    contentBlock.outerHeight = contentBlock.height = retrieve2(style.textHeight, contentHeight);\n\n    if (stlPadding) {\n        contentBlock.outerWidth += stlPadding[1] + stlPadding[3];\n        contentBlock.outerHeight += stlPadding[0] + stlPadding[2];\n    }\n\n    for (var i = 0; i < pendingList.length; i++) {\n        var token = pendingList[i];\n        var percentWidth = token.percentWidth;\n        // Should not base on outerWidth, because token can not be placed out of padding.\n        token.width = parseInt(percentWidth, 10) / 100 * contentWidth;\n    }\n\n    return contentBlock;\n}\n\nfunction pushTokens(block, str, styleName) {\n    var isEmptyStr = str === '';\n    var strs = str.split('\\n');\n    var lines = block.lines;\n\n    for (var i = 0; i < strs.length; i++) {\n        var text = strs[i];\n        var token = {\n            styleName: styleName,\n            text: text,\n            isLineHolder: !text && !isEmptyStr\n        };\n\n        // The first token should be appended to the last line.\n        if (!i) {\n            var tokens = (lines[lines.length - 1] || (lines[0] = {tokens: []})).tokens;\n\n            // Consider cases:\n            // (1) ''.split('\\n') => ['', '\\n', ''], the '' at the first item\n            // (which is a placeholder) should be replaced by new token.\n            // (2) A image backage, where token likes {a|}.\n            // (3) A redundant '' will affect textAlign in line.\n            // (4) tokens with the same tplName should not be merged, because\n            // they should be displayed in different box (with border and padding).\n            var tokensLen = tokens.length;\n            (tokensLen === 1 && tokens[0].isLineHolder)\n                ? (tokens[0] = token)\n                // Consider text is '', only insert when it is the \"lineHolder\" or\n                // \"emptyStr\". Otherwise a redundant '' will affect textAlign in line.\n                : ((text || !tokensLen || isEmptyStr) && tokens.push(token));\n        }\n        // Other tokens always start a new line.\n        else {\n            // If there is '', insert it as a placeholder.\n            lines.push({tokens: [token]});\n        }\n    }\n}\n\nfunction makeFont(style) {\n    // FIXME in node-canvas fontWeight is before fontStyle\n    // Use `fontSize` `fontFamily` to check whether font properties are defined.\n    var font = (style.fontSize || style.fontFamily) && [\n        style.fontStyle,\n        style.fontWeight,\n        (style.fontSize || 12) + 'px',\n        // If font properties are defined, `fontFamily` should not be ignored.\n        style.fontFamily || 'sans-serif'\n    ].join(' ');\n    return font && trim(font) || style.textFont || style.font;\n}\n\n/**\n * @param {Object} ctx\n * @param {Object} shape\n * @param {number} shape.x\n * @param {number} shape.y\n * @param {number} shape.width\n * @param {number} shape.height\n * @param {number} shape.r\n */\nfunction buildPath(ctx, shape) {\n    var x = shape.x;\n    var y = shape.y;\n    var width = shape.width;\n    var height = shape.height;\n    var r = shape.r;\n    var r1;\n    var r2;\n    var r3;\n    var r4;\n\n    // Convert width and height to positive for better borderRadius\n    if (width < 0) {\n        x = x + width;\n        width = -width;\n    }\n    if (height < 0) {\n        y = y + height;\n        height = -height;\n    }\n\n    if (typeof r === 'number') {\n        r1 = r2 = r3 = r4 = r;\n    }\n    else if (r instanceof Array) {\n        if (r.length === 1) {\n            r1 = r2 = r3 = r4 = r[0];\n        }\n        else if (r.length === 2) {\n            r1 = r3 = r[0];\n            r2 = r4 = r[1];\n        }\n        else if (r.length === 3) {\n            r1 = r[0];\n            r2 = r4 = r[1];\n            r3 = r[2];\n        }\n        else {\n            r1 = r[0];\n            r2 = r[1];\n            r3 = r[2];\n            r4 = r[3];\n        }\n    }\n    else {\n        r1 = r2 = r3 = r4 = 0;\n    }\n\n    var total;\n    if (r1 + r2 > width) {\n        total = r1 + r2;\n        r1 *= width / total;\n        r2 *= width / total;\n    }\n    if (r3 + r4 > width) {\n        total = r3 + r4;\n        r3 *= width / total;\n        r4 *= width / total;\n    }\n    if (r2 + r3 > height) {\n        total = r2 + r3;\n        r2 *= height / total;\n        r3 *= height / total;\n    }\n    if (r1 + r4 > height) {\n        total = r1 + r4;\n        r1 *= height / total;\n        r4 *= height / total;\n    }\n    ctx.moveTo(x + r1, y);\n    ctx.lineTo(x + width - r2, y);\n    r2 !== 0 && ctx.arc(x + width - r2, y + r2, r2, -Math.PI / 2, 0);\n    ctx.lineTo(x + width, y + height - r3);\n    r3 !== 0 && ctx.arc(x + width - r3, y + height - r3, r3, 0, Math.PI / 2);\n    ctx.lineTo(x + r4, y + height);\n    r4 !== 0 && ctx.arc(x + r4, y + height - r4, r4, Math.PI / 2, Math.PI);\n    ctx.lineTo(x, y + r1);\n    r1 !== 0 && ctx.arc(x + r1, y + r1, r1, Math.PI, Math.PI * 1.5);\n}\n\nvar DEFAULT_FONT = DEFAULT_FONT$1;\n\n// TODO: Have not support 'start', 'end' yet.\nvar VALID_TEXT_ALIGN = {left: 1, right: 1, center: 1};\nvar VALID_TEXT_VERTICAL_ALIGN = {top: 1, bottom: 1, middle: 1};\n// Different from `STYLE_COMMON_PROPS` of `graphic/Style`,\n// the default value of shadowColor is `'transparent'`.\nvar SHADOW_STYLE_COMMON_PROPS = [\n    ['textShadowBlur', 'shadowBlur', 0],\n    ['textShadowOffsetX', 'shadowOffsetX', 0],\n    ['textShadowOffsetY', 'shadowOffsetY', 0],\n    ['textShadowColor', 'shadowColor', 'transparent']\n];\n\n/**\n * @param {module:zrender/graphic/Style} style\n * @return {module:zrender/graphic/Style} The input style.\n */\nfunction normalizeTextStyle(style) {\n    normalizeStyle(style);\n    each$1(style.rich, normalizeStyle);\n    return style;\n}\n\nfunction normalizeStyle(style) {\n    if (style) {\n\n        style.font = makeFont(style);\n\n        var textAlign = style.textAlign;\n        textAlign === 'middle' && (textAlign = 'center');\n        style.textAlign = (\n            textAlign == null || VALID_TEXT_ALIGN[textAlign]\n        ) ? textAlign : 'left';\n\n        // Compatible with textBaseline.\n        var textVerticalAlign = style.textVerticalAlign || style.textBaseline;\n        textVerticalAlign === 'center' && (textVerticalAlign = 'middle');\n        style.textVerticalAlign = (\n            textVerticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[textVerticalAlign]\n        ) ? textVerticalAlign : 'top';\n\n        var textPadding = style.textPadding;\n        if (textPadding) {\n            style.textPadding = normalizeCssArray(style.textPadding);\n        }\n    }\n}\n\n/**\n * @param {CanvasRenderingContext2D} ctx\n * @param {string} text\n * @param {module:zrender/graphic/Style} style\n * @param {Object|boolean} [rect] {x, y, width, height}\n *                  If set false, rect text is not used.\n * @param {Element|module:zrender/graphic/helper/constant.WILL_BE_RESTORED} [prevEl] For ctx prop cache.\n */\nfunction renderText(hostEl, ctx, text, style, rect, prevEl) {\n    style.rich\n        ? renderRichText(hostEl, ctx, text, style, rect, prevEl)\n        : renderPlainText(hostEl, ctx, text, style, rect, prevEl);\n}\n\n// Avoid setting to ctx according to prevEl if possible for\n// performance in scenarios of large amount text.\nfunction renderPlainText(hostEl, ctx, text, style, rect, prevEl) {\n    'use strict';\n\n    var needDrawBg = needDrawBackground(style);\n\n    var prevStyle;\n    var checkCache = false;\n    var cachedByMe = ctx.__attrCachedBy === ContextCachedBy.PLAIN_TEXT;\n\n    // Only take and check cache for `Text` el, but not RectText.\n    if (prevEl !== WILL_BE_RESTORED) {\n        if (prevEl) {\n            prevStyle = prevEl.style;\n            checkCache = !needDrawBg && cachedByMe && prevStyle;\n        }\n\n        // Prevent from using cache in `Style::bind`, because of the case:\n        // ctx property is modified by other properties than `Style::bind`\n        // used, and Style::bind is called next.\n        ctx.__attrCachedBy = needDrawBg ? ContextCachedBy.NONE : ContextCachedBy.PLAIN_TEXT;\n    }\n    // Since this will be restored, prevent from using these props to check cache in the next\n    // entering of this method. But do not need to clear other cache like `Style::bind`.\n    else if (cachedByMe) {\n        ctx.__attrCachedBy = ContextCachedBy.NONE;\n    }\n\n    var styleFont = style.font || DEFAULT_FONT;\n    // PENDING\n    // Only `Text` el set `font` and keep it (`RectText` will restore). So theoretically\n    // we can make font cache on ctx, which can cache for text el that are discontinuous.\n    // But layer save/restore needed to be considered.\n    // if (styleFont !== ctx.__fontCache) {\n    //     ctx.font = styleFont;\n    //     if (prevEl !== WILL_BE_RESTORED) {\n    //         ctx.__fontCache = styleFont;\n    //     }\n    // }\n    if (!checkCache || styleFont !== (prevStyle.font || DEFAULT_FONT)) {\n        ctx.font = styleFont;\n    }\n\n    // Use the final font from context-2d, because the final\n    // font might not be the style.font when it is illegal.\n    // But get `ctx.font` might be time consuming.\n    var computedFont = hostEl.__computedFont;\n    if (hostEl.__styleFont !== styleFont) {\n        hostEl.__styleFont = styleFont;\n        computedFont = hostEl.__computedFont = ctx.font;\n    }\n\n    var textPadding = style.textPadding;\n    var textLineHeight = style.textLineHeight;\n\n    var contentBlock = hostEl.__textCotentBlock;\n    if (!contentBlock || hostEl.__dirtyText) {\n        contentBlock = hostEl.__textCotentBlock = parsePlainText(\n            text, computedFont, textPadding, textLineHeight, style.truncate\n        );\n    }\n\n    var outerHeight = contentBlock.outerHeight;\n\n    var textLines = contentBlock.lines;\n    var lineHeight = contentBlock.lineHeight;\n\n    var boxPos = getBoxPosition(outerHeight, style, rect);\n    var baseX = boxPos.baseX;\n    var baseY = boxPos.baseY;\n    var textAlign = boxPos.textAlign || 'left';\n    var textVerticalAlign = boxPos.textVerticalAlign;\n\n    // Origin of textRotation should be the base point of text drawing.\n    applyTextRotation(ctx, style, rect, baseX, baseY);\n\n    var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);\n    var textX = baseX;\n    var textY = boxY;\n\n    if (needDrawBg || textPadding) {\n        // Consider performance, do not call getTextWidth util necessary.\n        var textWidth = getWidth(text, computedFont);\n        var outerWidth = textWidth;\n        textPadding && (outerWidth += textPadding[1] + textPadding[3]);\n        var boxX = adjustTextX(baseX, outerWidth, textAlign);\n\n        needDrawBg && drawBackground(hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight);\n\n        if (textPadding) {\n            textX = getTextXForPadding(baseX, textAlign, textPadding);\n            textY += textPadding[0];\n        }\n    }\n\n    // Always set textAlign and textBase line, because it is difficute to calculate\n    // textAlign from prevEl, and we dont sure whether textAlign will be reset if\n    // font set happened.\n    ctx.textAlign = textAlign;\n    // Force baseline to be \"middle\". Otherwise, if using \"top\", the\n    // text will offset downward a little bit in font \"Microsoft YaHei\".\n    ctx.textBaseline = 'middle';\n    // Set text opacity\n    ctx.globalAlpha = style.opacity || 1;\n\n    // Always set shadowBlur and shadowOffset to avoid leak from displayable.\n    for (var i = 0; i < SHADOW_STYLE_COMMON_PROPS.length; i++) {\n        var propItem = SHADOW_STYLE_COMMON_PROPS[i];\n        var styleProp = propItem[0];\n        var ctxProp = propItem[1];\n        var val = style[styleProp];\n        if (!checkCache || val !== prevStyle[styleProp]) {\n            ctx[ctxProp] = fixShadow(ctx, ctxProp, val || propItem[2]);\n        }\n    }\n\n    // `textBaseline` is set as 'middle'.\n    textY += lineHeight / 2;\n\n    var textStrokeWidth = style.textStrokeWidth;\n    var textStrokeWidthPrev = checkCache ? prevStyle.textStrokeWidth : null;\n    var strokeWidthChanged = !checkCache || textStrokeWidth !== textStrokeWidthPrev;\n    var strokeChanged = !checkCache || strokeWidthChanged || style.textStroke !== prevStyle.textStroke;\n    var textStroke = getStroke(style.textStroke, textStrokeWidth);\n    var textFill = getFill(style.textFill);\n\n    if (textStroke) {\n        if (strokeWidthChanged) {\n            ctx.lineWidth = textStrokeWidth;\n        }\n        if (strokeChanged) {\n            ctx.strokeStyle = textStroke;\n        }\n    }\n    if (textFill) {\n        if (!checkCache || style.textFill !== prevStyle.textFill) {\n            ctx.fillStyle = textFill;\n        }\n    }\n\n    // Optimize simply, in most cases only one line exists.\n    if (textLines.length === 1) {\n        // Fill after stroke so the outline will not cover the main part.\n        textStroke && ctx.strokeText(textLines[0], textX, textY);\n        textFill && ctx.fillText(textLines[0], textX, textY);\n    }\n    else {\n        for (var i = 0; i < textLines.length; i++) {\n            // Fill after stroke so the outline will not cover the main part.\n            textStroke && ctx.strokeText(textLines[i], textX, textY);\n            textFill && ctx.fillText(textLines[i], textX, textY);\n            textY += lineHeight;\n        }\n    }\n}\n\nfunction renderRichText(hostEl, ctx, text, style, rect, prevEl) {\n    // Do not do cache for rich text because of the complexity.\n    // But `RectText` this will be restored, do not need to clear other cache like `Style::bind`.\n    if (prevEl !== WILL_BE_RESTORED) {\n        ctx.__attrCachedBy = ContextCachedBy.NONE;\n    }\n\n    var contentBlock = hostEl.__textCotentBlock;\n\n    if (!contentBlock || hostEl.__dirtyText) {\n        contentBlock = hostEl.__textCotentBlock = parseRichText(text, style);\n    }\n\n    drawRichText(hostEl, ctx, contentBlock, style, rect);\n}\n\nfunction drawRichText(hostEl, ctx, contentBlock, style, rect) {\n    var contentWidth = contentBlock.width;\n    var outerWidth = contentBlock.outerWidth;\n    var outerHeight = contentBlock.outerHeight;\n    var textPadding = style.textPadding;\n\n    var boxPos = getBoxPosition(outerHeight, style, rect);\n    var baseX = boxPos.baseX;\n    var baseY = boxPos.baseY;\n    var textAlign = boxPos.textAlign;\n    var textVerticalAlign = boxPos.textVerticalAlign;\n\n    // Origin of textRotation should be the base point of text drawing.\n    applyTextRotation(ctx, style, rect, baseX, baseY);\n\n    var boxX = adjustTextX(baseX, outerWidth, textAlign);\n    var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);\n    var xLeft = boxX;\n    var lineTop = boxY;\n    if (textPadding) {\n        xLeft += textPadding[3];\n        lineTop += textPadding[0];\n    }\n    var xRight = xLeft + contentWidth;\n\n    needDrawBackground(style) && drawBackground(\n        hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight\n    );\n\n    for (var i = 0; i < contentBlock.lines.length; i++) {\n        var line = contentBlock.lines[i];\n        var tokens = line.tokens;\n        var tokenCount = tokens.length;\n        var lineHeight = line.lineHeight;\n        var usedWidth = line.width;\n\n        var leftIndex = 0;\n        var lineXLeft = xLeft;\n        var lineXRight = xRight;\n        var rightIndex = tokenCount - 1;\n        var token;\n\n        while (\n            leftIndex < tokenCount\n            && (token = tokens[leftIndex], !token.textAlign || token.textAlign === 'left')\n        ) {\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft, 'left');\n            usedWidth -= token.width;\n            lineXLeft += token.width;\n            leftIndex++;\n        }\n\n        while (\n            rightIndex >= 0\n            && (token = tokens[rightIndex], token.textAlign === 'right')\n        ) {\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXRight, 'right');\n            usedWidth -= token.width;\n            lineXRight -= token.width;\n            rightIndex--;\n        }\n\n        // The other tokens are placed as textAlign 'center' if there is enough space.\n        lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - usedWidth) / 2;\n        while (leftIndex <= rightIndex) {\n            token = tokens[leftIndex];\n            // Consider width specified by user, use 'center' rather than 'left'.\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center');\n            lineXLeft += token.width;\n            leftIndex++;\n        }\n\n        lineTop += lineHeight;\n    }\n}\n\nfunction applyTextRotation(ctx, style, rect, x, y) {\n    // textRotation only apply in RectText.\n    if (rect && style.textRotation) {\n        var origin = style.textOrigin;\n        if (origin === 'center') {\n            x = rect.width / 2 + rect.x;\n            y = rect.height / 2 + rect.y;\n        }\n        else if (origin) {\n            x = origin[0] + rect.x;\n            y = origin[1] + rect.y;\n        }\n\n        ctx.translate(x, y);\n        // Positive: anticlockwise\n        ctx.rotate(-style.textRotation);\n        ctx.translate(-x, -y);\n    }\n}\n\nfunction placeToken(hostEl, ctx, token, style, lineHeight, lineTop, x, textAlign) {\n    var tokenStyle = style.rich[token.styleName] || {};\n    tokenStyle.text = token.text;\n\n    // 'ctx.textBaseline' is always set as 'middle', for sake of\n    // the bias of \"Microsoft YaHei\".\n    var textVerticalAlign = token.textVerticalAlign;\n    var y = lineTop + lineHeight / 2;\n    if (textVerticalAlign === 'top') {\n        y = lineTop + token.height / 2;\n    }\n    else if (textVerticalAlign === 'bottom') {\n        y = lineTop + lineHeight - token.height / 2;\n    }\n\n    !token.isLineHolder && needDrawBackground(tokenStyle) && drawBackground(\n        hostEl,\n        ctx,\n        tokenStyle,\n        textAlign === 'right'\n            ? x - token.width\n            : textAlign === 'center'\n            ? x - token.width / 2\n            : x,\n        y - token.height / 2,\n        token.width,\n        token.height\n    );\n\n    var textPadding = token.textPadding;\n    if (textPadding) {\n        x = getTextXForPadding(x, textAlign, textPadding);\n        y -= token.height / 2 - textPadding[2] - token.textHeight / 2;\n    }\n\n    setCtx(ctx, 'shadowBlur', retrieve3(tokenStyle.textShadowBlur, style.textShadowBlur, 0));\n    setCtx(ctx, 'shadowColor', tokenStyle.textShadowColor || style.textShadowColor || 'transparent');\n    setCtx(ctx, 'shadowOffsetX', retrieve3(tokenStyle.textShadowOffsetX, style.textShadowOffsetX, 0));\n    setCtx(ctx, 'shadowOffsetY', retrieve3(tokenStyle.textShadowOffsetY, style.textShadowOffsetY, 0));\n\n    setCtx(ctx, 'textAlign', textAlign);\n    // Force baseline to be \"middle\". Otherwise, if using \"top\", the\n    // text will offset downward a little bit in font \"Microsoft YaHei\".\n    setCtx(ctx, 'textBaseline', 'middle');\n\n    setCtx(ctx, 'font', token.font || DEFAULT_FONT);\n\n    var textStroke = getStroke(tokenStyle.textStroke || style.textStroke, textStrokeWidth);\n    var textFill = getFill(tokenStyle.textFill || style.textFill);\n    var textStrokeWidth = retrieve2(tokenStyle.textStrokeWidth, style.textStrokeWidth);\n\n    // Fill after stroke so the outline will not cover the main part.\n    if (textStroke) {\n        setCtx(ctx, 'lineWidth', textStrokeWidth);\n        setCtx(ctx, 'strokeStyle', textStroke);\n        ctx.strokeText(token.text, x, y);\n    }\n    if (textFill) {\n        setCtx(ctx, 'fillStyle', textFill);\n        ctx.fillText(token.text, x, y);\n    }\n}\n\nfunction needDrawBackground(style) {\n    return !!(\n        style.textBackgroundColor\n        || (style.textBorderWidth && style.textBorderColor)\n    );\n}\n\n// style: {textBackgroundColor, textBorderWidth, textBorderColor, textBorderRadius, text}\n// shape: {x, y, width, height}\nfunction drawBackground(hostEl, ctx, style, x, y, width, height) {\n    var textBackgroundColor = style.textBackgroundColor;\n    var textBorderWidth = style.textBorderWidth;\n    var textBorderColor = style.textBorderColor;\n    var isPlainBg = isString(textBackgroundColor);\n\n    setCtx(ctx, 'shadowBlur', style.textBoxShadowBlur || 0);\n    setCtx(ctx, 'shadowColor', style.textBoxShadowColor || 'transparent');\n    setCtx(ctx, 'shadowOffsetX', style.textBoxShadowOffsetX || 0);\n    setCtx(ctx, 'shadowOffsetY', style.textBoxShadowOffsetY || 0);\n\n    if (isPlainBg || (textBorderWidth && textBorderColor)) {\n        ctx.beginPath();\n        var textBorderRadius = style.textBorderRadius;\n        if (!textBorderRadius) {\n            ctx.rect(x, y, width, height);\n        }\n        else {\n            buildPath(ctx, {\n                x: x, y: y, width: width, height: height, r: textBorderRadius\n            });\n        }\n        ctx.closePath();\n    }\n\n    if (isPlainBg) {\n        setCtx(ctx, 'fillStyle', textBackgroundColor);\n\n        if (style.fillOpacity != null) {\n            var originalGlobalAlpha = ctx.globalAlpha;\n            ctx.globalAlpha = style.fillOpacity * style.opacity;\n            ctx.fill();\n            ctx.globalAlpha = originalGlobalAlpha;\n        }\n        else {\n            ctx.fill();\n        }\n    }\n    else if (isObject$1(textBackgroundColor)) {\n        var image = textBackgroundColor.image;\n\n        image = createOrUpdateImage(\n            image, null, hostEl, onBgImageLoaded, textBackgroundColor\n        );\n        if (image && isImageReady(image)) {\n            ctx.drawImage(image, x, y, width, height);\n        }\n    }\n\n    if (textBorderWidth && textBorderColor) {\n        setCtx(ctx, 'lineWidth', textBorderWidth);\n        setCtx(ctx, 'strokeStyle', textBorderColor);\n\n        if (style.strokeOpacity != null) {\n            var originalGlobalAlpha = ctx.globalAlpha;\n            ctx.globalAlpha = style.strokeOpacity * style.opacity;\n            ctx.stroke();\n            ctx.globalAlpha = originalGlobalAlpha;\n        }\n        else {\n            ctx.stroke();\n        }\n    }\n}\n\nfunction onBgImageLoaded(image, textBackgroundColor) {\n    // Replace image, so that `contain/text.js#parseRichText`\n    // will get correct result in next tick.\n    textBackgroundColor.image = image;\n}\n\nfunction getBoxPosition(blockHeiht, style, rect) {\n    var baseX = style.x || 0;\n    var baseY = style.y || 0;\n    var textAlign = style.textAlign;\n    var textVerticalAlign = style.textVerticalAlign;\n\n    // Text position represented by coord\n    if (rect) {\n        var textPosition = style.textPosition;\n        if (textPosition instanceof Array) {\n            // Percent\n            baseX = rect.x + parsePercent(textPosition[0], rect.width);\n            baseY = rect.y + parsePercent(textPosition[1], rect.height);\n        }\n        else {\n            var res = adjustTextPositionOnRect(\n                textPosition, rect, style.textDistance\n            );\n            baseX = res.x;\n            baseY = res.y;\n            // Default align and baseline when has textPosition\n            textAlign = textAlign || res.textAlign;\n            textVerticalAlign = textVerticalAlign || res.textVerticalAlign;\n        }\n\n        // textOffset is only support in RectText, otherwise\n        // we have to adjust boundingRect for textOffset.\n        var textOffset = style.textOffset;\n        if (textOffset) {\n            baseX += textOffset[0];\n            baseY += textOffset[1];\n        }\n    }\n\n    return {\n        baseX: baseX,\n        baseY: baseY,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\nfunction setCtx(ctx, prop, value) {\n    ctx[prop] = fixShadow(ctx, prop, value);\n    return ctx[prop];\n}\n\n/**\n * @param {string} [stroke] If specified, do not check style.textStroke.\n * @param {string} [lineWidth] If specified, do not check style.textStroke.\n * @param {number} style\n */\nfunction getStroke(stroke, lineWidth) {\n    return (stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none')\n        ? null\n        // TODO pattern and gradient?\n        : (stroke.image || stroke.colorStops)\n        ? '#000'\n        : stroke;\n}\n\nfunction getFill(fill) {\n    return (fill == null || fill === 'none')\n        ? null\n        // TODO pattern and gradient?\n        : (fill.image || fill.colorStops)\n        ? '#000'\n        : fill;\n}\n\nfunction parsePercent(value, maxValue) {\n    if (typeof value === 'string') {\n        if (value.lastIndexOf('%') >= 0) {\n            return parseFloat(value) / 100 * maxValue;\n        }\n        return parseFloat(value);\n    }\n    return value;\n}\n\nfunction getTextXForPadding(x, textAlign, textPadding) {\n    return textAlign === 'right'\n        ? (x - textPadding[1])\n        : textAlign === 'center'\n        ? (x + textPadding[3] / 2 - textPadding[1] / 2)\n        : (x + textPadding[3]);\n}\n\n/**\n * @param {string} text\n * @param {module:zrender/Style} style\n * @return {boolean}\n */\nfunction needDrawText(text, style) {\n    return text != null\n        && (text\n            || style.textBackgroundColor\n            || (style.textBorderWidth && style.textBorderColor)\n            || style.textPadding\n        );\n}\n\n/**\n * Mixin for drawing text in a element bounding rect\n * @module zrender/mixin/RectText\n */\n\nvar tmpRect$1 = new BoundingRect();\n\nvar RectText = function () {};\n\nRectText.prototype = {\n\n    constructor: RectText,\n\n    /**\n     * Draw text in a rect with specified position.\n     * @param  {CanvasRenderingContext2D} ctx\n     * @param  {Object} rect Displayable rect\n     */\n    drawRectText: function (ctx, rect) {\n        var style = this.style;\n\n        rect = style.textRect || rect;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        var text = style.text;\n\n        // Convert to string\n        text != null && (text += '');\n\n        if (!needDrawText(text, style)) {\n            return;\n        }\n\n        // FIXME\n        // Do not provide prevEl to `textHelper.renderText` for ctx prop cache,\n        // but use `ctx.save()` and `ctx.restore()`. Because the cache for rect\n        // text propably break the cache for its host elements.\n        ctx.save();\n\n        // Transform rect to view space\n        var transform = this.transform;\n        if (!style.transformText) {\n            if (transform) {\n                tmpRect$1.copy(rect);\n                tmpRect$1.applyTransform(transform);\n                rect = tmpRect$1;\n            }\n        }\n        else {\n            this.setTransform(ctx);\n        }\n\n        // transformText and textRotation can not be used at the same time.\n        renderText(this, ctx, text, style, rect, WILL_BE_RESTORED);\n\n        ctx.restore();\n    }\n};\n\n/**\n * 可绘制的图形基类\n * Base class of all displayable graphic objects\n * @module zrender/graphic/Displayable\n */\n\n\n/**\n * @alias module:zrender/graphic/Displayable\n * @extends module:zrender/Element\n * @extends module:zrender/graphic/mixin/RectText\n */\nfunction Displayable(opts) {\n\n    opts = opts || {};\n\n    Element.call(this, opts);\n\n    // Extend properties\n    for (var name in opts) {\n        if (\n            opts.hasOwnProperty(name)\n                && name !== 'style'\n        ) {\n            this[name] = opts[name];\n        }\n    }\n\n    /**\n     * @type {module:zrender/graphic/Style}\n     */\n    this.style = new Style(opts.style, this);\n\n    this._rect = null;\n    // Shapes for cascade clipping.\n    this.__clipPaths = [];\n\n    // FIXME Stateful must be mixined after style is setted\n    // Stateful.call(this, opts);\n}\n\nDisplayable.prototype = {\n\n    constructor: Displayable,\n\n    type: 'displayable',\n\n    /**\n     * Displayable 是否为脏，Painter 中会根据该标记判断是否需要是否需要重新绘制\n     * Dirty flag. From which painter will determine if this displayable object needs brush\n     * @name module:zrender/graphic/Displayable#__dirty\n     * @type {boolean}\n     */\n    __dirty: true,\n\n    /**\n     * 图形是否可见，为true时不绘制图形，但是仍能触发鼠标事件\n     * If ignore drawing of the displayable object. Mouse event will still be triggered\n     * @name module:/zrender/graphic/Displayable#invisible\n     * @type {boolean}\n     * @default false\n     */\n    invisible: false,\n\n    /**\n     * @name module:/zrender/graphic/Displayable#z\n     * @type {number}\n     * @default 0\n     */\n    z: 0,\n\n    /**\n     * @name module:/zrender/graphic/Displayable#z\n     * @type {number}\n     * @default 0\n     */\n    z2: 0,\n\n    /**\n     * z层level，决定绘画在哪层canvas中\n     * @name module:/zrender/graphic/Displayable#zlevel\n     * @type {number}\n     * @default 0\n     */\n    zlevel: 0,\n\n    /**\n     * 是否可拖拽\n     * @name module:/zrender/graphic/Displayable#draggable\n     * @type {boolean}\n     * @default false\n     */\n    draggable: false,\n\n    /**\n     * 是否正在拖拽\n     * @name module:/zrender/graphic/Displayable#draggable\n     * @type {boolean}\n     * @default false\n     */\n    dragging: false,\n\n    /**\n     * 是否相应鼠标事件\n     * @name module:/zrender/graphic/Displayable#silent\n     * @type {boolean}\n     * @default false\n     */\n    silent: false,\n\n    /**\n     * If enable culling\n     * @type {boolean}\n     * @default false\n     */\n    culling: false,\n\n    /**\n     * Mouse cursor when hovered\n     * @name module:/zrender/graphic/Displayable#cursor\n     * @type {string}\n     */\n    cursor: 'pointer',\n\n    /**\n     * If hover area is bounding rect\n     * @name module:/zrender/graphic/Displayable#rectHover\n     * @type {string}\n     */\n    rectHover: false,\n\n    /**\n     * Render the element progressively when the value >= 0,\n     * usefull for large data.\n     * @type {boolean}\n     */\n    progressive: false,\n\n    /**\n     * @type {boolean}\n     */\n    incremental: false,\n    /**\n     * Scale ratio for global scale.\n     * @type {boolean}\n     */\n    globalScaleRatio: 1,\n\n    beforeBrush: function (ctx) {},\n\n    afterBrush: function (ctx) {},\n\n    /**\n     * 图形绘制方法\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    // Interface\n    brush: function (ctx, prevEl) {},\n\n    /**\n     * 获取最小包围盒\n     * @return {module:zrender/core/BoundingRect}\n     */\n    // Interface\n    getBoundingRect: function () {},\n\n    /**\n     * 判断坐标 x, y 是否在图形上\n     * If displayable element contain coord x, y\n     * @param  {number} x\n     * @param  {number} y\n     * @return {boolean}\n     */\n    contain: function (x, y) {\n        return this.rectContain(x, y);\n    },\n\n    /**\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {\n        cb.call(context, this);\n    },\n\n    /**\n     * 判断坐标 x, y 是否在图形的包围盒上\n     * If bounding rect of element contain coord x, y\n     * @param  {number} x\n     * @param  {number} y\n     * @return {boolean}\n     */\n    rectContain: function (x, y) {\n        var coord = this.transformCoordToLocal(x, y);\n        var rect = this.getBoundingRect();\n        return rect.contain(coord[0], coord[1]);\n    },\n\n    /**\n     * 标记图形元素为脏，并且在下一帧重绘\n     * Mark displayable element dirty and refresh next frame\n     */\n    dirty: function () {\n        this.__dirty = this.__dirtyText = true;\n\n        this._rect = null;\n\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * 图形是否会触发事件\n     * If displayable object binded any event\n     * @return {boolean}\n     */\n    // TODO, 通过 bind 绑定的事件\n    // isSilent: function () {\n    //     return !(\n    //         this.hoverable || this.draggable\n    //         || this.onmousemove || this.onmouseover || this.onmouseout\n    //         || this.onmousedown || this.onmouseup || this.onclick\n    //         || this.ondragenter || this.ondragover || this.ondragleave\n    //         || this.ondrop\n    //     );\n    // },\n    /**\n     * Alias for animate('style')\n     * @param {boolean} loop\n     */\n    animateStyle: function (loop) {\n        return this.animate('style', loop);\n    },\n\n    attrKV: function (key, value) {\n        if (key !== 'style') {\n            Element.prototype.attrKV.call(this, key, value);\n        }\n        else {\n            this.style.set(value);\n        }\n    },\n\n    /**\n     * @param {Object|string} key\n     * @param {*} value\n     */\n    setStyle: function (key, value) {\n        this.style.set(key, value);\n        this.dirty(false);\n        return this;\n    },\n\n    /**\n     * Use given style object\n     * @param  {Object} obj\n     */\n    useStyle: function (obj) {\n        this.style = new Style(obj, this);\n        this.dirty(false);\n        return this;\n    }\n};\n\ninherits(Displayable, Element);\n\nmixin(Displayable, RectText);\n\n/**\n * @alias zrender/graphic/Image\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nfunction ZImage(opts) {\n    Displayable.call(this, opts);\n}\n\nZImage.prototype = {\n\n    constructor: ZImage,\n\n    type: 'image',\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n        var src = style.image;\n\n        // Must bind each time\n        style.bind(ctx, this, prevEl);\n\n        var image = this._image = createOrUpdateImage(\n            src,\n            this._image,\n            this,\n            this.onload\n        );\n\n        if (!image || !isImageReady(image)) {\n            return;\n        }\n\n        // 图片已经加载完成\n        // if (image.nodeName.toUpperCase() == 'IMG') {\n        //     if (!image.complete) {\n        //         return;\n        //     }\n        // }\n        // Else is canvas\n\n        var x = style.x || 0;\n        var y = style.y || 0;\n        var width = style.width;\n        var height = style.height;\n        var aspect = image.width / image.height;\n        if (width == null && height != null) {\n            // Keep image/height ratio\n            width = height * aspect;\n        }\n        else if (height == null && width != null) {\n            height = width / aspect;\n        }\n        else if (width == null && height == null) {\n            width = image.width;\n            height = image.height;\n        }\n\n        // 设置transform\n        this.setTransform(ctx);\n\n        if (style.sWidth && style.sHeight) {\n            var sx = style.sx || 0;\n            var sy = style.sy || 0;\n            ctx.drawImage(\n                image,\n                sx, sy, style.sWidth, style.sHeight,\n                x, y, width, height\n            );\n        }\n        else if (style.sx && style.sy) {\n            var sx = style.sx;\n            var sy = style.sy;\n            var sWidth = width - sx;\n            var sHeight = height - sy;\n            ctx.drawImage(\n                image,\n                sx, sy, sWidth, sHeight,\n                x, y, width, height\n            );\n        }\n        else {\n            ctx.drawImage(image, x, y, width, height);\n        }\n\n        // Draw rect text\n        if (style.text != null) {\n            // Only restore transform when needs draw text.\n            this.restoreTransform(ctx);\n            this.drawRectText(ctx, this.getBoundingRect());\n        }\n    },\n\n    getBoundingRect: function () {\n        var style = this.style;\n        if (!this._rect) {\n            this._rect = new BoundingRect(\n                style.x || 0, style.y || 0, style.width || 0, style.height || 0\n            );\n        }\n        return this._rect;\n    }\n};\n\ninherits(ZImage, Displayable);\n\nvar HOVER_LAYER_ZLEVEL = 1e5;\nvar CANVAS_ZLEVEL = 314159;\n\nvar EL_AFTER_INCREMENTAL_INC = 0.01;\nvar INCREMENTAL_INC = 0.001;\n\nfunction parseInt10(val) {\n    return parseInt(val, 10);\n}\n\nfunction isLayerValid(layer) {\n    if (!layer) {\n        return false;\n    }\n\n    if (layer.__builtin__) {\n        return true;\n    }\n\n    if (typeof (layer.resize) !== 'function'\n        || typeof (layer.refresh) !== 'function'\n    ) {\n        return false;\n    }\n\n    return true;\n}\n\nvar tmpRect = new BoundingRect(0, 0, 0, 0);\nvar viewRect = new BoundingRect(0, 0, 0, 0);\nfunction isDisplayableCulled(el, width, height) {\n    tmpRect.copy(el.getBoundingRect());\n    if (el.transform) {\n        tmpRect.applyTransform(el.transform);\n    }\n    viewRect.width = width;\n    viewRect.height = height;\n    return !tmpRect.intersect(viewRect);\n}\n\nfunction isClipPathChanged(clipPaths, prevClipPaths) {\n    if (clipPaths === prevClipPaths) { // Can both be null or undefined\n        return false;\n    }\n\n    if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) {\n        return true;\n    }\n    for (var i = 0; i < clipPaths.length; i++) {\n        if (clipPaths[i] !== prevClipPaths[i]) {\n            return true;\n        }\n    }\n}\n\nfunction doClip(clipPaths, ctx) {\n    for (var i = 0; i < clipPaths.length; i++) {\n        var clipPath = clipPaths[i];\n\n        clipPath.setTransform(ctx);\n        ctx.beginPath();\n        clipPath.buildPath(ctx, clipPath.shape);\n        ctx.clip();\n        // Transform back\n        clipPath.restoreTransform(ctx);\n    }\n}\n\nfunction createRoot(width, height) {\n    var domRoot = document.createElement('div');\n\n    // domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬\n    domRoot.style.cssText = [\n        'position:relative',\n        'overflow:hidden',\n        'width:' + width + 'px',\n        'height:' + height + 'px',\n        'padding:0',\n        'margin:0',\n        'border-width:0'\n    ].join(';') + ';';\n\n    return domRoot;\n}\n\n\n/**\n * @alias module:zrender/Painter\n * @constructor\n * @param {HTMLElement} root 绘图容器\n * @param {module:zrender/Storage} storage\n * @param {Object} opts\n */\nvar Painter = function (root, storage, opts) {\n\n    this.type = 'canvas';\n\n    // In node environment using node-canvas\n    var singleCanvas = !root.nodeName // In node ?\n        || root.nodeName.toUpperCase() === 'CANVAS';\n\n    this._opts = opts = extend({}, opts || {});\n\n    /**\n     * @type {number}\n     */\n    this.dpr = opts.devicePixelRatio || devicePixelRatio;\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._singleCanvas = singleCanvas;\n    /**\n     * 绘图容器\n     * @type {HTMLElement}\n     */\n    this.root = root;\n\n    var rootStyle = root.style;\n\n    if (rootStyle) {\n        rootStyle['-webkit-tap-highlight-color'] = 'transparent';\n        rootStyle['-webkit-user-select'] =\n        rootStyle['user-select'] =\n        rootStyle['-webkit-touch-callout'] = 'none';\n\n        root.innerHTML = '';\n    }\n\n    /**\n     * @type {module:zrender/Storage}\n     */\n    this.storage = storage;\n\n    /**\n     * @type {Array.<number>}\n     * @private\n     */\n    var zlevelList = this._zlevelList = [];\n\n    /**\n     * @type {Object.<string, module:zrender/Layer>}\n     * @private\n     */\n    var layers = this._layers = {};\n\n    /**\n     * @type {Object.<string, Object>}\n     * @private\n     */\n    this._layerConfig = {};\n\n    /**\n     * zrender will do compositing when root is a canvas and have multiple zlevels.\n     */\n    this._needsManuallyCompositing = false;\n\n    if (!singleCanvas) {\n        this._width = this._getSize(0);\n        this._height = this._getSize(1);\n\n        var domRoot = this._domRoot = createRoot(\n            this._width, this._height\n        );\n        root.appendChild(domRoot);\n    }\n    else {\n        var width = root.width;\n        var height = root.height;\n\n        if (opts.width != null) {\n            width = opts.width;\n        }\n        if (opts.height != null) {\n            height = opts.height;\n        }\n        this.dpr = opts.devicePixelRatio || 1;\n\n        // Use canvas width and height directly\n        root.width = width * this.dpr;\n        root.height = height * this.dpr;\n\n        this._width = width;\n        this._height = height;\n\n        // Create layer if only one given canvas\n        // Device can be specified to create a high dpi image.\n        var mainLayer = new Layer(root, this, this.dpr);\n        mainLayer.__builtin__ = true;\n        mainLayer.initContext();\n        // FIXME Use canvas width and height\n        // mainLayer.resize(width, height);\n        layers[CANVAS_ZLEVEL] = mainLayer;\n        mainLayer.zlevel = CANVAS_ZLEVEL;\n        // Not use common zlevel.\n        zlevelList.push(CANVAS_ZLEVEL);\n\n        this._domRoot = root;\n    }\n\n    /**\n     * @type {module:zrender/Layer}\n     * @private\n     */\n    this._hoverlayer = null;\n\n    this._hoverElements = [];\n};\n\nPainter.prototype = {\n\n    constructor: Painter,\n\n    getType: function () {\n        return 'canvas';\n    },\n\n    /**\n     * If painter use a single canvas\n     * @return {boolean}\n     */\n    isSingleCanvas: function () {\n        return this._singleCanvas;\n    },\n    /**\n     * @return {HTMLDivElement}\n     */\n    getViewportRoot: function () {\n        return this._domRoot;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    /**\n     * 刷新\n     * @param {boolean} [paintAll=false] 强制绘制所有displayable\n     */\n    refresh: function (paintAll) {\n\n        var list = this.storage.getDisplayList(true);\n\n        var zlevelList = this._zlevelList;\n\n        this._redrawId = Math.random();\n\n        this._paintList(list, paintAll, this._redrawId);\n\n        // Paint custum layers\n        for (var i = 0; i < zlevelList.length; i++) {\n            var z = zlevelList[i];\n            var layer = this._layers[z];\n            if (!layer.__builtin__ && layer.refresh) {\n                var clearColor = i === 0 ? this._backgroundColor : null;\n                layer.refresh(clearColor);\n            }\n        }\n\n        this.refreshHover();\n\n        return this;\n    },\n\n    addHover: function (el, hoverStyle) {\n        if (el.__hoverMir) {\n            return;\n        }\n        var elMirror = new el.constructor({\n            style: el.style,\n            shape: el.shape,\n            z: el.z,\n            z2: el.z2,\n            silent: el.silent\n        });\n        elMirror.__from = el;\n        el.__hoverMir = elMirror;\n        hoverStyle && elMirror.setStyle(hoverStyle);\n        this._hoverElements.push(elMirror);\n\n        return elMirror;\n    },\n\n    removeHover: function (el) {\n        var elMirror = el.__hoverMir;\n        var hoverElements = this._hoverElements;\n        var idx = indexOf(hoverElements, elMirror);\n        if (idx >= 0) {\n            hoverElements.splice(idx, 1);\n        }\n        el.__hoverMir = null;\n    },\n\n    clearHover: function (el) {\n        var hoverElements = this._hoverElements;\n        for (var i = 0; i < hoverElements.length; i++) {\n            var from = hoverElements[i].__from;\n            if (from) {\n                from.__hoverMir = null;\n            }\n        }\n        hoverElements.length = 0;\n    },\n\n    refreshHover: function () {\n        var hoverElements = this._hoverElements;\n        var len = hoverElements.length;\n        var hoverLayer = this._hoverlayer;\n        hoverLayer && hoverLayer.clear();\n\n        if (!len) {\n            return;\n        }\n        sort(hoverElements, this.storage.displayableSortFunc);\n\n        // Use a extream large zlevel\n        // FIXME?\n        if (!hoverLayer) {\n            hoverLayer = this._hoverlayer = this.getLayer(HOVER_LAYER_ZLEVEL);\n        }\n\n        var scope = {};\n        hoverLayer.ctx.save();\n        for (var i = 0; i < len;) {\n            var el = hoverElements[i];\n            var originalEl = el.__from;\n            // Original el is removed\n            // PENDING\n            if (!(originalEl && originalEl.__zr)) {\n                hoverElements.splice(i, 1);\n                originalEl.__hoverMir = null;\n                len--;\n                continue;\n            }\n            i++;\n\n            // Use transform\n            // FIXME style and shape ?\n            if (!originalEl.invisible) {\n                el.transform = originalEl.transform;\n                el.invTransform = originalEl.invTransform;\n                el.__clipPaths = originalEl.__clipPaths;\n                // el.\n                this._doPaintEl(el, hoverLayer, true, scope);\n            }\n        }\n\n        hoverLayer.ctx.restore();\n    },\n\n    getHoverLayer: function () {\n        return this.getLayer(HOVER_LAYER_ZLEVEL);\n    },\n\n    _paintList: function (list, paintAll, redrawId) {\n        if (this._redrawId !== redrawId) {\n            return;\n        }\n\n        paintAll = paintAll || false;\n\n        this._updateLayerStatus(list);\n\n        var finished = this._doPaintList(list, paintAll);\n\n        if (this._needsManuallyCompositing) {\n            this._compositeManually();\n        }\n\n        if (!finished) {\n            var self = this;\n            requestAnimationFrame(function () {\n                self._paintList(list, paintAll, redrawId);\n            });\n        }\n    },\n\n    _compositeManually: function () {\n        var ctx = this.getLayer(CANVAS_ZLEVEL).ctx;\n        var width = this._domRoot.width;\n        var height = this._domRoot.height;\n        ctx.clearRect(0, 0, width, height);\n        // PENDING, If only builtin layer?\n        this.eachBuiltinLayer(function (layer) {\n            if (layer.virtual) {\n                ctx.drawImage(layer.dom, 0, 0, width, height);\n            }\n        });\n    },\n\n    _doPaintList: function (list, paintAll) {\n        var layerList = [];\n        for (var zi = 0; zi < this._zlevelList.length; zi++) {\n            var zlevel = this._zlevelList[zi];\n            var layer = this._layers[zlevel];\n            if (layer.__builtin__\n                && layer !== this._hoverlayer\n                && (layer.__dirty || paintAll)\n            ) {\n                layerList.push(layer);\n            }\n        }\n\n        var finished = true;\n\n        for (var k = 0; k < layerList.length; k++) {\n            var layer = layerList[k];\n            var ctx = layer.ctx;\n            var scope = {};\n            ctx.save();\n\n            var start = paintAll ? layer.__startIndex : layer.__drawIndex;\n\n            var useTimer = !paintAll && layer.incremental && Date.now;\n            var startTime = useTimer && Date.now();\n\n            var clearColor = layer.zlevel === this._zlevelList[0]\n                ? this._backgroundColor : null;\n            // All elements in this layer are cleared.\n            if (layer.__startIndex === layer.__endIndex) {\n                layer.clear(false, clearColor);\n            }\n            else if (start === layer.__startIndex) {\n                var firstEl = list[start];\n                if (!firstEl.incremental || !firstEl.notClear || paintAll) {\n                    layer.clear(false, clearColor);\n                }\n            }\n            if (start === -1) {\n                console.error('For some unknown reason. drawIndex is -1');\n                start = layer.__startIndex;\n            }\n            for (var i = start; i < layer.__endIndex; i++) {\n                var el = list[i];\n                this._doPaintEl(el, layer, paintAll, scope);\n                el.__dirty = el.__dirtyText = false;\n\n                if (useTimer) {\n                    // Date.now can be executed in 13,025,305 ops/second.\n                    var dTime = Date.now() - startTime;\n                    // Give 15 millisecond to draw.\n                    // The rest elements will be drawn in the next frame.\n                    if (dTime > 15) {\n                        break;\n                    }\n                }\n            }\n\n            layer.__drawIndex = i;\n\n            if (layer.__drawIndex < layer.__endIndex) {\n                finished = false;\n            }\n\n            if (scope.prevElClipPaths) {\n                // Needs restore the state. If last drawn element is in the clipping area.\n                ctx.restore();\n            }\n\n            ctx.restore();\n        }\n\n        if (env$1.wxa) {\n            // Flush for weixin application\n            each$1(this._layers, function (layer) {\n                if (layer && layer.ctx && layer.ctx.draw) {\n                    layer.ctx.draw();\n                }\n            });\n        }\n\n        return finished;\n    },\n\n    _doPaintEl: function (el, currentLayer, forcePaint, scope) {\n        var ctx = currentLayer.ctx;\n        var m = el.transform;\n        if (\n            (currentLayer.__dirty || forcePaint)\n            // Ignore invisible element\n            && !el.invisible\n            // Ignore transparent element\n            && el.style.opacity !== 0\n            // Ignore scale 0 element, in some environment like node-canvas\n            // Draw a scale 0 element can cause all following draw wrong\n            // And setTransform with scale 0 will cause set back transform failed.\n            && !(m && !m[0] && !m[3])\n            // Ignore culled element\n            && !(el.culling && isDisplayableCulled(el, this._width, this._height))\n        ) {\n\n            var clipPaths = el.__clipPaths;\n\n            // Optimize when clipping on group with several elements\n            if (!scope.prevElClipPaths\n                || isClipPathChanged(clipPaths, scope.prevElClipPaths)\n            ) {\n                // If has previous clipping state, restore from it\n                if (scope.prevElClipPaths) {\n                    currentLayer.ctx.restore();\n                    scope.prevElClipPaths = null;\n\n                    // Reset prevEl since context has been restored\n                    scope.prevEl = null;\n                }\n                // New clipping state\n                if (clipPaths) {\n                    ctx.save();\n                    doClip(clipPaths, ctx);\n                    scope.prevElClipPaths = clipPaths;\n                }\n            }\n            el.beforeBrush && el.beforeBrush(ctx);\n\n            el.brush(ctx, scope.prevEl || null);\n            scope.prevEl = el;\n\n            el.afterBrush && el.afterBrush(ctx);\n        }\n    },\n\n    /**\n     * 获取 zlevel 所在层，如果不存在则会创建一个新的层\n     * @param {number} zlevel\n     * @param {boolean} virtual Virtual layer will not be inserted into dom.\n     * @return {module:zrender/Layer}\n     */\n    getLayer: function (zlevel, virtual) {\n        if (this._singleCanvas && !this._needsManuallyCompositing) {\n            zlevel = CANVAS_ZLEVEL;\n        }\n        var layer = this._layers[zlevel];\n        if (!layer) {\n            // Create a new layer\n            layer = new Layer('zr_' + zlevel, this, this.dpr);\n            layer.zlevel = zlevel;\n            layer.__builtin__ = true;\n\n            if (this._layerConfig[zlevel]) {\n                merge(layer, this._layerConfig[zlevel], true);\n            }\n\n            if (virtual) {\n                layer.virtual = virtual;\n            }\n\n            this.insertLayer(zlevel, layer);\n\n            // Context is created after dom inserted to document\n            // Or excanvas will get 0px clientWidth and clientHeight\n            layer.initContext();\n        }\n\n        return layer;\n    },\n\n    insertLayer: function (zlevel, layer) {\n\n        var layersMap = this._layers;\n        var zlevelList = this._zlevelList;\n        var len = zlevelList.length;\n        var prevLayer = null;\n        var i = -1;\n        var domRoot = this._domRoot;\n\n        if (layersMap[zlevel]) {\n            zrLog('ZLevel ' + zlevel + ' has been used already');\n            return;\n        }\n        // Check if is a valid layer\n        if (!isLayerValid(layer)) {\n            zrLog('Layer of zlevel ' + zlevel + ' is not valid');\n            return;\n        }\n\n        if (len > 0 && zlevel > zlevelList[0]) {\n            for (i = 0; i < len - 1; i++) {\n                if (\n                    zlevelList[i] < zlevel\n                    && zlevelList[i + 1] > zlevel\n                ) {\n                    break;\n                }\n            }\n            prevLayer = layersMap[zlevelList[i]];\n        }\n        zlevelList.splice(i + 1, 0, zlevel);\n\n        layersMap[zlevel] = layer;\n\n        // Vitual layer will not directly show on the screen.\n        // (It can be a WebGL layer and assigned to a ZImage element)\n        // But it still under management of zrender.\n        if (!layer.virtual) {\n            if (prevLayer) {\n                var prevDom = prevLayer.dom;\n                if (prevDom.nextSibling) {\n                    domRoot.insertBefore(\n                        layer.dom,\n                        prevDom.nextSibling\n                    );\n                }\n                else {\n                    domRoot.appendChild(layer.dom);\n                }\n            }\n            else {\n                if (domRoot.firstChild) {\n                    domRoot.insertBefore(layer.dom, domRoot.firstChild);\n                }\n                else {\n                    domRoot.appendChild(layer.dom);\n                }\n            }\n        }\n    },\n\n    // Iterate each layer\n    eachLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            cb.call(context, this._layers[z], z);\n        }\n    },\n\n    // Iterate each buildin layer\n    eachBuiltinLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var layer;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            layer = this._layers[z];\n            if (layer.__builtin__) {\n                cb.call(context, layer, z);\n            }\n        }\n    },\n\n    // Iterate each other layer except buildin layer\n    eachOtherLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var layer;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            layer = this._layers[z];\n            if (!layer.__builtin__) {\n                cb.call(context, layer, z);\n            }\n        }\n    },\n\n    /**\n     * 获取所有已创建的层\n     * @param {Array.<module:zrender/Layer>} [prevLayer]\n     */\n    getLayers: function () {\n        return this._layers;\n    },\n\n    _updateLayerStatus: function (list) {\n\n        this.eachBuiltinLayer(function (layer, z) {\n            layer.__dirty = layer.__used = false;\n        });\n\n        function updatePrevLayer(idx) {\n            if (prevLayer) {\n                if (prevLayer.__endIndex !== idx) {\n                    prevLayer.__dirty = true;\n                }\n                prevLayer.__endIndex = idx;\n            }\n        }\n\n        if (this._singleCanvas) {\n            for (var i = 1; i < list.length; i++) {\n                var el = list[i];\n                if (el.zlevel !== list[i - 1].zlevel || el.incremental) {\n                    this._needsManuallyCompositing = true;\n                    break;\n                }\n            }\n        }\n\n        var prevLayer = null;\n        var incrementalLayerCount = 0;\n        for (var i = 0; i < list.length; i++) {\n            var el = list[i];\n            var zlevel = el.zlevel;\n            var layer;\n            // PENDING If change one incremental element style ?\n            // TODO Where there are non-incremental elements between incremental elements.\n            if (el.incremental) {\n                layer = this.getLayer(zlevel + INCREMENTAL_INC, this._needsManuallyCompositing);\n                layer.incremental = true;\n                incrementalLayerCount = 1;\n            }\n            else {\n                layer = this.getLayer(zlevel + (incrementalLayerCount > 0 ? EL_AFTER_INCREMENTAL_INC : 0), this._needsManuallyCompositing);\n            }\n\n            if (!layer.__builtin__) {\n                zrLog('ZLevel ' + zlevel + ' has been used by unkown layer ' + layer.id);\n            }\n\n            if (layer !== prevLayer) {\n                layer.__used = true;\n                if (layer.__startIndex !== i) {\n                    layer.__dirty = true;\n                }\n                layer.__startIndex = i;\n                if (!layer.incremental) {\n                    layer.__drawIndex = i;\n                }\n                else {\n                    // Mark layer draw index needs to update.\n                    layer.__drawIndex = -1;\n                }\n                updatePrevLayer(i);\n                prevLayer = layer;\n            }\n            if (el.__dirty) {\n                layer.__dirty = true;\n                if (layer.incremental && layer.__drawIndex < 0) {\n                    // Start draw from the first dirty element.\n                    layer.__drawIndex = i;\n                }\n            }\n        }\n\n        updatePrevLayer(i);\n\n        this.eachBuiltinLayer(function (layer, z) {\n            // Used in last frame but not in this frame. Needs clear\n            if (!layer.__used && layer.getElementCount() > 0) {\n                layer.__dirty = true;\n                layer.__startIndex = layer.__endIndex = layer.__drawIndex = 0;\n            }\n            // For incremental layer. In case start index changed and no elements are dirty.\n            if (layer.__dirty && layer.__drawIndex < 0) {\n                layer.__drawIndex = layer.__startIndex;\n            }\n        });\n    },\n\n    /**\n     * 清除hover层外所有内容\n     */\n    clear: function () {\n        this.eachBuiltinLayer(this._clearLayer);\n        return this;\n    },\n\n    _clearLayer: function (layer) {\n        layer.clear();\n    },\n\n    setBackgroundColor: function (backgroundColor) {\n        this._backgroundColor = backgroundColor;\n    },\n\n    /**\n     * 修改指定zlevel的绘制参数\n     *\n     * @param {string} zlevel\n     * @param {Object} config 配置对象\n     * @param {string} [config.clearColor=0] 每次清空画布的颜色\n     * @param {string} [config.motionBlur=false] 是否开启动态模糊\n     * @param {number} [config.lastFrameAlpha=0.7]\n     *                 在开启动态模糊的时候使用，与上一帧混合的alpha值，值越大尾迹越明显\n     */\n    configLayer: function (zlevel, config) {\n        if (config) {\n            var layerConfig = this._layerConfig;\n            if (!layerConfig[zlevel]) {\n                layerConfig[zlevel] = config;\n            }\n            else {\n                merge(layerConfig[zlevel], config, true);\n            }\n\n            for (var i = 0; i < this._zlevelList.length; i++) {\n                var _zlevel = this._zlevelList[i];\n                if (_zlevel === zlevel || _zlevel === zlevel + EL_AFTER_INCREMENTAL_INC) {\n                    var layer = this._layers[_zlevel];\n                    merge(layer, layerConfig[zlevel], true);\n                }\n            }\n        }\n    },\n\n    /**\n     * 删除指定层\n     * @param {number} zlevel 层所在的zlevel\n     */\n    delLayer: function (zlevel) {\n        var layers = this._layers;\n        var zlevelList = this._zlevelList;\n        var layer = layers[zlevel];\n        if (!layer) {\n            return;\n        }\n        layer.dom.parentNode.removeChild(layer.dom);\n        delete layers[zlevel];\n\n        zlevelList.splice(indexOf(zlevelList, zlevel), 1);\n    },\n\n    /**\n     * 区域大小变化后重绘\n     */\n    resize: function (width, height) {\n        if (!this._domRoot.style) { // Maybe in node or worker\n            if (width == null || height == null) {\n                return;\n            }\n            this._width = width;\n            this._height = height;\n\n            this.getLayer(CANVAS_ZLEVEL).resize(width, height);\n        }\n        else {\n            var domRoot = this._domRoot;\n            // FIXME Why ?\n            domRoot.style.display = 'none';\n\n            // Save input w/h\n            var opts = this._opts;\n            width != null && (opts.width = width);\n            height != null && (opts.height = height);\n\n            width = this._getSize(0);\n            height = this._getSize(1);\n\n            domRoot.style.display = '';\n\n            // 优化没有实际改变的resize\n            if (this._width !== width || height !== this._height) {\n                domRoot.style.width = width + 'px';\n                domRoot.style.height = height + 'px';\n\n                for (var id in this._layers) {\n                    if (this._layers.hasOwnProperty(id)) {\n                        this._layers[id].resize(width, height);\n                    }\n                }\n                each$1(this._progressiveLayers, function (layer) {\n                    layer.resize(width, height);\n                });\n\n                this.refresh(true);\n            }\n\n            this._width = width;\n            this._height = height;\n\n        }\n        return this;\n    },\n\n    /**\n     * 清除单独的一个层\n     * @param {number} zlevel\n     */\n    clearLayer: function (zlevel) {\n        var layer = this._layers[zlevel];\n        if (layer) {\n            layer.clear();\n        }\n    },\n\n    /**\n     * 释放\n     */\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this.root =\n        this.storage =\n\n        this._domRoot =\n        this._layers = null;\n    },\n\n    /**\n     * Get canvas which has all thing rendered\n     * @param {Object} opts\n     * @param {string} [opts.backgroundColor]\n     * @param {number} [opts.pixelRatio]\n     */\n    getRenderedCanvas: function (opts) {\n        opts = opts || {};\n        if (this._singleCanvas && !this._compositeManually) {\n            return this._layers[CANVAS_ZLEVEL].dom;\n        }\n\n        var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr);\n        imageLayer.initContext();\n        imageLayer.clear(false, opts.backgroundColor || this._backgroundColor);\n\n        if (opts.pixelRatio <= this.dpr) {\n            this.refresh();\n\n            var width = imageLayer.dom.width;\n            var height = imageLayer.dom.height;\n            var ctx = imageLayer.ctx;\n            this.eachLayer(function (layer) {\n                if (layer.__builtin__) {\n                    ctx.drawImage(layer.dom, 0, 0, width, height);\n                }\n                else if (layer.renderToCanvas) {\n                    imageLayer.ctx.save();\n                    layer.renderToCanvas(imageLayer.ctx);\n                    imageLayer.ctx.restore();\n                }\n            });\n        }\n        else {\n            // PENDING, echarts-gl and incremental rendering.\n            var scope = {};\n            var displayList = this.storage.getDisplayList(true);\n            for (var i = 0; i < displayList.length; i++) {\n                var el = displayList[i];\n                this._doPaintEl(el, imageLayer, true, scope);\n            }\n        }\n\n        return imageLayer.dom;\n    },\n    /**\n     * 获取绘图区域宽度\n     */\n    getWidth: function () {\n        return this._width;\n    },\n\n    /**\n     * 获取绘图区域高度\n     */\n    getHeight: function () {\n        return this._height;\n    },\n\n    _getSize: function (whIdx) {\n        var opts = this._opts;\n        var wh = ['width', 'height'][whIdx];\n        var cwh = ['clientWidth', 'clientHeight'][whIdx];\n        var plt = ['paddingLeft', 'paddingTop'][whIdx];\n        var prb = ['paddingRight', 'paddingBottom'][whIdx];\n\n        if (opts[wh] != null && opts[wh] !== 'auto') {\n            return parseFloat(opts[wh]);\n        }\n\n        var root = this.root;\n        // IE8 does not support getComputedStyle, but it use VML.\n        var stl = document.defaultView.getComputedStyle(root);\n\n        return (\n            (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh]))\n            - (parseInt10(stl[plt]) || 0)\n            - (parseInt10(stl[prb]) || 0)\n        ) | 0;\n    },\n\n    pathToImage: function (path, dpr) {\n        dpr = dpr || this.dpr;\n\n        var canvas = document.createElement('canvas');\n        var ctx = canvas.getContext('2d');\n        var rect = path.getBoundingRect();\n        var style = path.style;\n        var shadowBlurSize = style.shadowBlur * dpr;\n        var shadowOffsetX = style.shadowOffsetX * dpr;\n        var shadowOffsetY = style.shadowOffsetY * dpr;\n        var lineWidth = style.hasStroke() ? style.lineWidth : 0;\n\n        var leftMargin = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize);\n        var rightMargin = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize);\n        var topMargin = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize);\n        var bottomMargin = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize);\n        var width = rect.width + leftMargin + rightMargin;\n        var height = rect.height + topMargin + bottomMargin;\n\n        canvas.width = width * dpr;\n        canvas.height = height * dpr;\n\n        ctx.scale(dpr, dpr);\n        ctx.clearRect(0, 0, width, height);\n        ctx.dpr = dpr;\n\n        var pathTransform = {\n            position: path.position,\n            rotation: path.rotation,\n            scale: path.scale\n        };\n        path.position = [leftMargin - rect.x, topMargin - rect.y];\n        path.rotation = 0;\n        path.scale = [1, 1];\n        path.updateTransform();\n        if (path) {\n            path.brush(ctx);\n        }\n\n        var ImageShape = ZImage;\n        var imgShape = new ImageShape({\n            style: {\n                x: 0,\n                y: 0,\n                image: canvas\n            }\n        });\n\n        if (pathTransform.position != null) {\n            imgShape.position = path.position = pathTransform.position;\n        }\n\n        if (pathTransform.rotation != null) {\n            imgShape.rotation = path.rotation = pathTransform.rotation;\n        }\n\n        if (pathTransform.scale != null) {\n            imgShape.scale = path.scale = pathTransform.scale;\n        }\n\n        return imgShape;\n    }\n};\n\n/**\n * 动画主类, 调度和管理所有动画控制器\n *\n * @module zrender/animation/Animation\n * @author pissang(https://github.com/pissang)\n */\n// TODO Additive animation\n// http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/\n// https://developer.apple.com/videos/wwdc2014/#236\n\n/**\n * @typedef {Object} IZRenderStage\n * @property {Function} update\n */\n\n/**\n * @alias module:zrender/animation/Animation\n * @constructor\n * @param {Object} [options]\n * @param {Function} [options.onframe]\n * @param {IZRenderStage} [options.stage]\n * @example\n *     var animation = new Animation();\n *     var obj = {\n *         x: 100,\n *         y: 100\n *     };\n *     animation.animate(node.position)\n *         .when(1000, {\n *             x: 500,\n *             y: 500\n *         })\n *         .when(2000, {\n *             x: 100,\n *             y: 100\n *         })\n *         .start('spline');\n */\nvar Animation = function (options) {\n\n    options = options || {};\n\n    this.stage = options.stage || {};\n\n    this.onframe = options.onframe || function () {};\n\n    // private properties\n    this._clips = [];\n\n    this._running = false;\n\n    this._time;\n\n    this._pausedTime;\n\n    this._pauseStart;\n\n    this._paused = false;\n\n    Eventful.call(this);\n};\n\nAnimation.prototype = {\n\n    constructor: Animation,\n    /**\n     * 添加 clip\n     * @param {module:zrender/animation/Clip} clip\n     */\n    addClip: function (clip) {\n        this._clips.push(clip);\n    },\n    /**\n     * 添加 animator\n     * @param {module:zrender/animation/Animator} animator\n     */\n    addAnimator: function (animator) {\n        animator.animation = this;\n        var clips = animator.getClips();\n        for (var i = 0; i < clips.length; i++) {\n            this.addClip(clips[i]);\n        }\n    },\n    /**\n     * 删除动画片段\n     * @param {module:zrender/animation/Clip} clip\n     */\n    removeClip: function (clip) {\n        var idx = indexOf(this._clips, clip);\n        if (idx >= 0) {\n            this._clips.splice(idx, 1);\n        }\n    },\n\n    /**\n     * 删除动画片段\n     * @param {module:zrender/animation/Animator} animator\n     */\n    removeAnimator: function (animator) {\n        var clips = animator.getClips();\n        for (var i = 0; i < clips.length; i++) {\n            this.removeClip(clips[i]);\n        }\n        animator.animation = null;\n    },\n\n    _update: function () {\n        var time = new Date().getTime() - this._pausedTime;\n        var delta = time - this._time;\n        var clips = this._clips;\n        var len = clips.length;\n\n        var deferredEvents = [];\n        var deferredClips = [];\n        for (var i = 0; i < len; i++) {\n            var clip = clips[i];\n            var e = clip.step(time, delta);\n            // Throw out the events need to be called after\n            // stage.update, like destroy\n            if (e) {\n                deferredEvents.push(e);\n                deferredClips.push(clip);\n            }\n        }\n\n        // Remove the finished clip\n        for (var i = 0; i < len;) {\n            if (clips[i]._needsRemove) {\n                clips[i] = clips[len - 1];\n                clips.pop();\n                len--;\n            }\n            else {\n                i++;\n            }\n        }\n\n        len = deferredEvents.length;\n        for (var i = 0; i < len; i++) {\n            deferredClips[i].fire(deferredEvents[i]);\n        }\n\n        this._time = time;\n\n        this.onframe(delta);\n\n        // 'frame' should be triggered before stage, because upper application\n        // depends on the sequence (e.g., echarts-stream and finish\n        // event judge)\n        this.trigger('frame', delta);\n\n        if (this.stage.update) {\n            this.stage.update();\n        }\n    },\n\n    _startLoop: function () {\n        var self = this;\n\n        this._running = true;\n\n        function step() {\n            if (self._running) {\n\n                requestAnimationFrame(step);\n\n                !self._paused && self._update();\n            }\n        }\n\n        requestAnimationFrame(step);\n    },\n\n    /**\n     * Start animation.\n     */\n    start: function () {\n\n        this._time = new Date().getTime();\n        this._pausedTime = 0;\n\n        this._startLoop();\n    },\n\n    /**\n     * Stop animation.\n     */\n    stop: function () {\n        this._running = false;\n    },\n\n    /**\n     * Pause animation.\n     */\n    pause: function () {\n        if (!this._paused) {\n            this._pauseStart = new Date().getTime();\n            this._paused = true;\n        }\n    },\n\n    /**\n     * Resume animation.\n     */\n    resume: function () {\n        if (this._paused) {\n            this._pausedTime += (new Date().getTime()) - this._pauseStart;\n            this._paused = false;\n        }\n    },\n\n    /**\n     * Clear animation.\n     */\n    clear: function () {\n        this._clips = [];\n    },\n\n    /**\n     * Whether animation finished.\n     */\n    isFinished: function () {\n        return !this._clips.length;\n    },\n\n    /**\n     * Creat animator for a target, whose props can be animated.\n     *\n     * @param  {Object} target\n     * @param  {Object} options\n     * @param  {boolean} [options.loop=false] Whether loop animation.\n     * @param  {Function} [options.getter=null] Get value from target.\n     * @param  {Function} [options.setter=null] Set value to target.\n     * @return {module:zrender/animation/Animation~Animator}\n     */\n    // TODO Gap\n    animate: function (target, options) {\n        options = options || {};\n\n        var animator = new Animator(\n            target,\n            options.loop,\n            options.getter,\n            options.setter\n        );\n\n        this.addAnimator(animator);\n\n        return animator;\n    }\n};\n\nmixin(Animation, Eventful);\n\nvar TOUCH_CLICK_DELAY = 300;\n\nvar mouseHandlerNames = [\n    'click', 'dblclick', 'mousewheel', 'mouseout',\n    'mouseup', 'mousedown', 'mousemove', 'contextmenu'\n];\n\nvar touchHandlerNames = [\n    'touchstart', 'touchend', 'touchmove'\n];\n\nvar pointerEventNames = {\n    pointerdown: 1, pointerup: 1, pointermove: 1, pointerout: 1\n};\n\nvar pointerHandlerNames = map(mouseHandlerNames, function (name) {\n    var nm = name.replace('mouse', 'pointer');\n    return pointerEventNames[nm] ? nm : name;\n});\n\nfunction eventNameFix(name) {\n    return (name === 'mousewheel' && env$1.browser.firefox) ? 'DOMMouseScroll' : name;\n}\n\n// function onMSGestureChange(proxy, event) {\n//     if (event.translationX || event.translationY) {\n//         // mousemove is carried by MSGesture to reduce the sensitivity.\n//         proxy.handler.dispatchToElement(event.target, 'mousemove', event);\n//     }\n//     if (event.scale !== 1) {\n//         event.pinchX = event.offsetX;\n//         event.pinchY = event.offsetY;\n//         event.pinchScale = event.scale;\n//         proxy.handler.dispatchToElement(event.target, 'pinch', event);\n//     }\n// }\n\n/**\n * Prevent mouse event from being dispatched after Touch Events action\n * @see <https://github.com/deltakosh/handjs/blob/master/src/hand.base.js>\n * 1. Mobile browsers dispatch mouse events 300ms after touchend.\n * 2. Chrome for Android dispatch mousedown for long-touch about 650ms\n * Result: Blocking Mouse Events for 700ms.\n */\nfunction setTouchTimer(instance) {\n    instance._touching = true;\n    clearTimeout(instance._touchTimer);\n    instance._touchTimer = setTimeout(function () {\n        instance._touching = false;\n    }, 700);\n}\n\n\nvar domHandlers = {\n    /**\n     * Mouse move handler\n     * @inner\n     * @param {Event} event\n     */\n    mousemove: function (event) {\n        event = normalizeEvent(this.dom, event);\n\n        this.trigger('mousemove', event);\n    },\n\n    /**\n     * Mouse out handler\n     * @inner\n     * @param {Event} event\n     */\n    mouseout: function (event) {\n        event = normalizeEvent(this.dom, event);\n\n        var element = event.toElement || event.relatedTarget;\n        if (element !== this.dom) {\n            while (element && element.nodeType !== 9) {\n                // 忽略包含在root中的dom引起的mouseOut\n                if (element === this.dom) {\n                    return;\n                }\n\n                element = element.parentNode;\n            }\n        }\n\n        this.trigger('mouseout', event);\n    },\n\n    /**\n     * Touch开始响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchstart: function (event) {\n        // Default mouse behaviour should not be disabled here.\n        // For example, page may needs to be slided.\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this._lastTouchMoment = new Date();\n\n        this.handler.processGesture(this, event, 'start');\n\n        // In touch device, trigger `mousemove`(`mouseover`) should\n        // be triggered, and must before `mousedown` triggered.\n        domHandlers.mousemove.call(this, event);\n\n        domHandlers.mousedown.call(this, event);\n\n        setTouchTimer(this);\n    },\n\n    /**\n     * Touch移动响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchmove: function (event) {\n\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this.handler.processGesture(this, event, 'change');\n\n        // Mouse move should always be triggered no matter whether\n        // there is gestrue event, because mouse move and pinch may\n        // be used at the same time.\n        domHandlers.mousemove.call(this, event);\n\n        setTouchTimer(this);\n    },\n\n    /**\n     * Touch结束响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchend: function (event) {\n\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this.handler.processGesture(this, event, 'end');\n\n        domHandlers.mouseup.call(this, event);\n\n        // Do not trigger `mouseout` here, in spite of `mousemove`(`mouseover`) is\n        // triggered in `touchstart`. This seems to be illogical, but by this mechanism,\n        // we can conveniently implement \"hover style\" in both PC and touch device just\n        // by listening to `mouseover` to add \"hover style\" and listening to `mouseout`\n        // to remove \"hover style\" on an element, without any additional code for\n        // compatibility. (`mouseout` will not be triggered in `touchend`, so \"hover\n        // style\" will remain for user view)\n\n        // click event should always be triggered no matter whether\n        // there is gestrue event. System click can not be prevented.\n        if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) {\n            domHandlers.click.call(this, event);\n        }\n\n        setTouchTimer(this);\n    },\n\n    pointerdown: function (event) {\n        domHandlers.mousedown.call(this, event);\n\n        // if (useMSGuesture(this, event)) {\n        //     this._msGesture.addPointer(event.pointerId);\n        // }\n    },\n\n    pointermove: function (event) {\n        // FIXME\n        // pointermove is so sensitive that it always triggered when\n        // tap(click) on touch screen, which affect some judgement in\n        // upper application. So, we dont support mousemove on MS touch\n        // device yet.\n        if (!isPointerFromTouch(event)) {\n            domHandlers.mousemove.call(this, event);\n        }\n    },\n\n    pointerup: function (event) {\n        domHandlers.mouseup.call(this, event);\n    },\n\n    pointerout: function (event) {\n        // pointerout will be triggered when tap on touch screen\n        // (IE11+/Edge on MS Surface) after click event triggered,\n        // which is inconsistent with the mousout behavior we defined\n        // in touchend. So we unify them.\n        // (check domHandlers.touchend for detailed explanation)\n        if (!isPointerFromTouch(event)) {\n            domHandlers.mouseout.call(this, event);\n        }\n    }\n};\n\nfunction isPointerFromTouch(event) {\n    var pointerType = event.pointerType;\n    return pointerType === 'pen' || pointerType === 'touch';\n}\n\n// function useMSGuesture(handlerProxy, event) {\n//     return isPointerFromTouch(event) && !!handlerProxy._msGesture;\n// }\n\n// Common handlers\neach$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {\n    domHandlers[name] = function (event) {\n        event = normalizeEvent(this.dom, event);\n        this.trigger(name, event);\n    };\n});\n\n/**\n * 为控制类实例初始化dom 事件处理函数\n *\n * @inner\n * @param {module:zrender/Handler} instance 控制类实例\n */\nfunction initDomHandler(instance) {\n    each$1(touchHandlerNames, function (name) {\n        instance._handlers[name] = bind(domHandlers[name], instance);\n    });\n\n    each$1(pointerHandlerNames, function (name) {\n        instance._handlers[name] = bind(domHandlers[name], instance);\n    });\n\n    each$1(mouseHandlerNames, function (name) {\n        instance._handlers[name] = makeMouseHandler(domHandlers[name], instance);\n    });\n\n    function makeMouseHandler(fn, instance) {\n        return function () {\n            if (instance._touching) {\n                return;\n            }\n            return fn.apply(instance, arguments);\n        };\n    }\n}\n\n\nfunction HandlerDomProxy(dom) {\n    Eventful.call(this);\n\n    this.dom = dom;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._touching = false;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._touchTimer;\n\n    this._handlers = {};\n\n    initDomHandler(this);\n\n    if (env$1.pointerEventsSupported) { // Only IE11+/Edge\n        // 1. On devices that both enable touch and mouse (e.g., MS Surface and lenovo X240),\n        // IE11+/Edge do not trigger touch event, but trigger pointer event and mouse event\n        // at the same time.\n        // 2. On MS Surface, it probablely only trigger mousedown but no mouseup when tap on\n        // screen, which do not occurs in pointer event.\n        // So we use pointer event to both detect touch gesture and mouse behavior.\n        mountHandlers(pointerHandlerNames, this);\n\n        // FIXME\n        // Note: MS Gesture require CSS touch-action set. But touch-action is not reliable,\n        // which does not prevent defuault behavior occasionally (which may cause view port\n        // zoomed in but use can not zoom it back). And event.preventDefault() does not work.\n        // So we have to not to use MSGesture and not to support touchmove and pinch on MS\n        // touch screen. And we only support click behavior on MS touch screen now.\n\n        // MS Gesture Event is only supported on IE11+/Edge and on Windows 8+.\n        // We dont support touch on IE on win7.\n        // See <https://msdn.microsoft.com/en-us/library/dn433243(v=vs.85).aspx>\n        // if (typeof MSGesture === 'function') {\n        //     (this._msGesture = new MSGesture()).target = dom; // jshint ignore:line\n        //     dom.addEventListener('MSGestureChange', onMSGestureChange);\n        // }\n    }\n    else {\n        if (env$1.touchEventsSupported) {\n            mountHandlers(touchHandlerNames, this);\n            // Handler of 'mouseout' event is needed in touch mode, which will be mounted below.\n            // addEventListener(root, 'mouseout', this._mouseoutHandler);\n        }\n\n        // 1. Considering some devices that both enable touch and mouse event (like on MS Surface\n        // and lenovo X240, @see #2350), we make mouse event be always listened, otherwise\n        // mouse event can not be handle in those devices.\n        // 2. On MS Surface, Chrome will trigger both touch event and mouse event. How to prevent\n        // mouseevent after touch event triggered, see `setTouchTimer`.\n        mountHandlers(mouseHandlerNames, this);\n    }\n\n    function mountHandlers(handlerNames, instance) {\n        each$1(handlerNames, function (name) {\n            addEventListener(dom, eventNameFix(name), instance._handlers[name]);\n        }, instance);\n    }\n}\n\nvar handlerDomProxyProto = HandlerDomProxy.prototype;\nhandlerDomProxyProto.dispose = function () {\n    var handlerNames = mouseHandlerNames.concat(touchHandlerNames);\n\n    for (var i = 0; i < handlerNames.length; i++) {\n        var name = handlerNames[i];\n        removeEventListener(this.dom, eventNameFix(name), this._handlers[name]);\n    }\n};\n\nhandlerDomProxyProto.setCursor = function (cursorStyle) {\n    this.dom.style && (this.dom.style.cursor = cursorStyle || 'default');\n};\n\nmixin(HandlerDomProxy, Eventful);\n\n/*!\n* ZRender, a high performance 2d drawing library.\n*\n* Copyright (c) 2013, Baidu Inc.\n* All rights reserved.\n*\n* LICENSE\n* https://github.com/ecomfe/zrender/blob/master/LICENSE.txt\n*/\n\nvar useVML = !env$1.canvasSupported;\n\nvar painterCtors = {\n    canvas: Painter\n};\n\nvar instances$1 = {};    // ZRender实例map索引\n\n/**\n * @type {string}\n */\nvar version$1 = '4.0.7';\n\n/**\n * Initializing a zrender instance\n * @param {HTMLElement} dom\n * @param {Object} [opts]\n * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'\n * @param {number} [opts.devicePixelRatio]\n * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)\n * @return {module:zrender/ZRender}\n */\nfunction init$1(dom, opts) {\n    var zr = new ZRender(guid(), dom, opts);\n    instances$1[zr.id] = zr;\n    return zr;\n}\n\n/**\n * Dispose zrender instance\n * @param {module:zrender/ZRender} zr\n */\nfunction dispose$1(zr) {\n    if (zr) {\n        zr.dispose();\n    }\n    else {\n        for (var key in instances$1) {\n            if (instances$1.hasOwnProperty(key)) {\n                instances$1[key].dispose();\n            }\n        }\n        instances$1 = {};\n    }\n\n    return this;\n}\n\n/**\n * Get zrender instance by id\n * @param {string} id zrender instance id\n * @return {module:zrender/ZRender}\n */\nfunction getInstance(id) {\n    return instances$1[id];\n}\n\nfunction registerPainter(name, Ctor) {\n    painterCtors[name] = Ctor;\n}\n\nfunction delInstance(id) {\n    delete instances$1[id];\n}\n\n/**\n * @module zrender/ZRender\n */\n/**\n * @constructor\n * @alias module:zrender/ZRender\n * @param {string} id\n * @param {HTMLElement} dom\n * @param {Object} opts\n * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'\n * @param {number} [opts.devicePixelRatio]\n * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)\n */\nvar ZRender = function (id, dom, opts) {\n\n    opts = opts || {};\n\n    /**\n     * @type {HTMLDomElement}\n     */\n    this.dom = dom;\n\n    /**\n     * @type {string}\n     */\n    this.id = id;\n\n    var self = this;\n    var storage = new Storage();\n\n    var rendererType = opts.renderer;\n    // TODO WebGL\n    if (useVML) {\n        if (!painterCtors.vml) {\n            throw new Error('You need to require \\'zrender/vml/vml\\' to support IE8');\n        }\n        rendererType = 'vml';\n    }\n    else if (!rendererType || !painterCtors[rendererType]) {\n        rendererType = 'canvas';\n    }\n    var painter = new painterCtors[rendererType](dom, storage, opts, id);\n\n    this.storage = storage;\n    this.painter = painter;\n\n    var handerProxy = (!env$1.node && !env$1.worker) ? new HandlerDomProxy(painter.getViewportRoot()) : null;\n    this.handler = new Handler(storage, painter, handerProxy, painter.root);\n\n    /**\n     * @type {module:zrender/animation/Animation}\n     */\n    this.animation = new Animation({\n        stage: {\n            update: bind(this.flush, this)\n        }\n    });\n    this.animation.start();\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._needsRefresh;\n\n    // 修改 storage.delFromStorage, 每次删除元素之前删除动画\n    // FIXME 有点ugly\n    var oldDelFromStorage = storage.delFromStorage;\n    var oldAddToStorage = storage.addToStorage;\n\n    storage.delFromStorage = function (el) {\n        oldDelFromStorage.call(storage, el);\n\n        el && el.removeSelfFromZr(self);\n    };\n\n    storage.addToStorage = function (el) {\n        oldAddToStorage.call(storage, el);\n\n        el.addSelfToZr(self);\n    };\n};\n\nZRender.prototype = {\n\n    constructor: ZRender,\n    /**\n     * 获取实例唯一标识\n     * @return {string}\n     */\n    getId: function () {\n        return this.id;\n    },\n\n    /**\n     * 添加元素\n     * @param  {module:zrender/Element} el\n     */\n    add: function (el) {\n        this.storage.addRoot(el);\n        this._needsRefresh = true;\n    },\n\n    /**\n     * 删除元素\n     * @param  {module:zrender/Element} el\n     */\n    remove: function (el) {\n        this.storage.delRoot(el);\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Change configuration of layer\n     * @param {string} zLevel\n     * @param {Object} config\n     * @param {string} [config.clearColor=0] Clear color\n     * @param {string} [config.motionBlur=false] If enable motion blur\n     * @param {number} [config.lastFrameAlpha=0.7] Motion blur factor. Larger value cause longer trailer\n    */\n    configLayer: function (zLevel, config) {\n        if (this.painter.configLayer) {\n            this.painter.configLayer(zLevel, config);\n        }\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Set background color\n     * @param {string} backgroundColor\n     */\n    setBackgroundColor: function (backgroundColor) {\n        if (this.painter.setBackgroundColor) {\n            this.painter.setBackgroundColor(backgroundColor);\n        }\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Repaint the canvas immediately\n     */\n    refreshImmediately: function () {\n        // var start = new Date();\n        // Clear needsRefresh ahead to avoid something wrong happens in refresh\n        // Or it will cause zrender refreshes again and again.\n        this._needsRefresh = false;\n        this.painter.refresh();\n        /**\n         * Avoid trigger zr.refresh in Element#beforeUpdate hook\n         */\n        this._needsRefresh = false;\n        // var end = new Date();\n        // var log = document.getElementById('log');\n        // if (log) {\n        //     log.innerHTML = log.innerHTML + '<br>' + (end - start);\n        // }\n    },\n\n    /**\n     * Mark and repaint the canvas in the next frame of browser\n     */\n    refresh: function () {\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Perform all refresh\n     */\n    flush: function () {\n        var triggerRendered;\n\n        if (this._needsRefresh) {\n            triggerRendered = true;\n            this.refreshImmediately();\n        }\n        if (this._needsRefreshHover) {\n            triggerRendered = true;\n            this.refreshHoverImmediately();\n        }\n\n        triggerRendered && this.trigger('rendered');\n    },\n\n    /**\n     * Add element to hover layer\n     * @param  {module:zrender/Element} el\n     * @param {Object} style\n     */\n    addHover: function (el, style) {\n        if (this.painter.addHover) {\n            var elMirror = this.painter.addHover(el, style);\n            this.refreshHover();\n            return elMirror;\n        }\n    },\n\n    /**\n     * Add element from hover layer\n     * @param  {module:zrender/Element} el\n     */\n    removeHover: function (el) {\n        if (this.painter.removeHover) {\n            this.painter.removeHover(el);\n            this.refreshHover();\n        }\n    },\n\n    /**\n     * Clear all hover elements in hover layer\n     * @param  {module:zrender/Element} el\n     */\n    clearHover: function () {\n        if (this.painter.clearHover) {\n            this.painter.clearHover();\n            this.refreshHover();\n        }\n    },\n\n    /**\n     * Refresh hover in next frame\n     */\n    refreshHover: function () {\n        this._needsRefreshHover = true;\n    },\n\n    /**\n     * Refresh hover immediately\n     */\n    refreshHoverImmediately: function () {\n        this._needsRefreshHover = false;\n        this.painter.refreshHover && this.painter.refreshHover();\n    },\n\n    /**\n     * Resize the canvas.\n     * Should be invoked when container size is changed\n     * @param {Object} [opts]\n     * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)\n     * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)\n     */\n    resize: function (opts) {\n        opts = opts || {};\n        this.painter.resize(opts.width, opts.height);\n        this.handler.resize();\n    },\n\n    /**\n     * Stop and clear all animation immediately\n     */\n    clearAnimation: function () {\n        this.animation.clear();\n    },\n\n    /**\n     * Get container width\n     */\n    getWidth: function () {\n        return this.painter.getWidth();\n    },\n\n    /**\n     * Get container height\n     */\n    getHeight: function () {\n        return this.painter.getHeight();\n    },\n\n    /**\n     * Export the canvas as Base64 URL\n     * @param {string} type\n     * @param {string} [backgroundColor='#fff']\n     * @return {string} Base64 URL\n     */\n    // toDataURL: function(type, backgroundColor) {\n    //     return this.painter.getRenderedCanvas({\n    //         backgroundColor: backgroundColor\n    //     }).toDataURL(type);\n    // },\n\n    /**\n     * Converting a path to image.\n     * It has much better performance of drawing image rather than drawing a vector path.\n     * @param {module:zrender/graphic/Path} e\n     * @param {number} width\n     * @param {number} height\n     */\n    pathToImage: function (e, dpr) {\n        return this.painter.pathToImage(e, dpr);\n    },\n\n    /**\n     * Set default cursor\n     * @param {string} [cursorStyle='default'] 例如 crosshair\n     */\n    setCursorStyle: function (cursorStyle) {\n        this.handler.setCursorStyle(cursorStyle);\n    },\n\n    /**\n     * Find hovered element\n     * @param {number} x\n     * @param {number} y\n     * @return {Object} {target, topTarget}\n     */\n    findHover: function (x, y) {\n        return this.handler.findHover(x, y);\n    },\n\n    /**\n     * Bind event\n     *\n     * @param {string} eventName Event name\n     * @param {Function} eventHandler Handler function\n     * @param {Object} [context] Context object\n     */\n    on: function (eventName, eventHandler, context) {\n        this.handler.on(eventName, eventHandler, context);\n    },\n\n    /**\n     * Unbind event\n     * @param {string} eventName Event name\n     * @param {Function} [eventHandler] Handler function\n     */\n    off: function (eventName, eventHandler) {\n        this.handler.off(eventName, eventHandler);\n    },\n\n    /**\n     * Trigger event manually\n     *\n     * @param {string} eventName Event name\n     * @param {event=} event Event object\n     */\n    trigger: function (eventName, event) {\n        this.handler.trigger(eventName, event);\n    },\n\n\n    /**\n     * Clear all objects and the canvas.\n     */\n    clear: function () {\n        this.storage.delRoot();\n        this.painter.clear();\n    },\n\n    /**\n     * Dispose self.\n     */\n    dispose: function () {\n        this.animation.stop();\n\n        this.clear();\n        this.storage.dispose();\n        this.painter.dispose();\n        this.handler.dispose();\n\n        this.animation =\n        this.storage =\n        this.painter =\n        this.handler = null;\n\n        delInstance(this.id);\n    }\n};\n\n\n\nvar zrender = (Object.freeze || Object)({\n\tversion: version$1,\n\tinit: init$1,\n\tdispose: dispose$1,\n\tgetInstance: getInstance,\n\tregisterPainter: registerPainter\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$2 = each$1;\nvar isObject$2 = isObject$1;\nvar isArray$1 = isArray;\n\n/**\n * Make the name displayable. But we should\n * make sure it is not duplicated with user\n * specified name, so use '\\0';\n */\nvar DUMMY_COMPONENT_NAME_PREFIX = 'series\\0';\n\n/**\n * If value is not array, then translate it to array.\n * @param  {*} value\n * @return {Array} [value] or value\n */\nfunction normalizeToArray(value) {\n    return value instanceof Array\n        ? value\n        : value == null\n        ? []\n        : [value];\n}\n\n/**\n * Sync default option between normal and emphasis like `position` and `show`\n * In case some one will write code like\n *     label: {\n *          show: false,\n *          position: 'outside',\n *          fontSize: 18\n *     },\n *     emphasis: {\n *          label: { show: true }\n *     }\n * @param {Object} opt\n * @param {string} key\n * @param {Array.<string>} subOpts\n */\nfunction defaultEmphasis(opt, key, subOpts) {\n    // Caution: performance sensitive.\n    if (opt) {\n        opt[key] = opt[key] || {};\n        opt.emphasis = opt.emphasis || {};\n        opt.emphasis[key] = opt.emphasis[key] || {};\n\n        // Default emphasis option from normal\n        for (var i = 0, len = subOpts.length; i < len; i++) {\n            var subOptName = subOpts[i];\n            if (!opt.emphasis[key].hasOwnProperty(subOptName)\n                && opt[key].hasOwnProperty(subOptName)\n            ) {\n                opt.emphasis[key][subOptName] = opt[key][subOptName];\n            }\n        }\n    }\n}\n\nvar TEXT_STYLE_OPTIONS = [\n    'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',\n    'rich', 'tag', 'color', 'textBorderColor', 'textBorderWidth',\n    'width', 'height', 'lineHeight', 'align', 'verticalAlign', 'baseline',\n    'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY',\n    'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY',\n    'backgroundColor', 'borderColor', 'borderWidth', 'borderRadius', 'padding'\n];\n\n// modelUtil.LABEL_OPTIONS = modelUtil.TEXT_STYLE_OPTIONS.concat([\n//     'position', 'offset', 'rotate', 'origin', 'show', 'distance', 'formatter',\n//     'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',\n//     // FIXME: deprecated, check and remove it.\n//     'textStyle'\n// ]);\n\n/**\n * The method do not ensure performance.\n * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]\n * This helper method retieves value from data.\n * @param {string|number|Date|Array|Object} dataItem\n * @return {number|string|Date|Array.<number|string|Date>}\n */\nfunction getDataItemValue(dataItem) {\n    return (isObject$2(dataItem) && !isArray$1(dataItem) && !(dataItem instanceof Date))\n        ? dataItem.value : dataItem;\n}\n\n/**\n * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]\n * This helper method determine if dataItem has extra option besides value\n * @param {string|number|Date|Array|Object} dataItem\n */\nfunction isDataItemOption(dataItem) {\n    return isObject$2(dataItem)\n        && !(dataItem instanceof Array);\n        // // markLine data can be array\n        // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array));\n}\n\n/**\n * Mapping to exists for merge.\n *\n * @public\n * @param {Array.<Object>|Array.<module:echarts/model/Component>} exists\n * @param {Object|Array.<Object>} newCptOptions\n * @return {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],\n *                          index of which is the same as exists.\n */\nfunction mappingToExists(exists, newCptOptions) {\n    // Mapping by the order by original option (but not order of\n    // new option) in merge mode. Because we should ensure\n    // some specified index (like xAxisIndex) is consistent with\n    // original option, which is easy to understand, espatially in\n    // media query. And in most case, merge option is used to\n    // update partial option but not be expected to change order.\n    newCptOptions = (newCptOptions || []).slice();\n\n    var result = map(exists || [], function (obj, index) {\n        return {exist: obj};\n    });\n\n    // Mapping by id or name if specified.\n    each$2(newCptOptions, function (cptOption, index) {\n        if (!isObject$2(cptOption)) {\n            return;\n        }\n\n        // id has highest priority.\n        for (var i = 0; i < result.length; i++) {\n            if (!result[i].option // Consider name: two map to one.\n                && cptOption.id != null\n                && result[i].exist.id === cptOption.id + ''\n            ) {\n                result[i].option = cptOption;\n                newCptOptions[index] = null;\n                return;\n            }\n        }\n\n        for (var i = 0; i < result.length; i++) {\n            var exist = result[i].exist;\n            if (!result[i].option // Consider name: two map to one.\n                // Can not match when both ids exist but different.\n                && (exist.id == null || cptOption.id == null)\n                && cptOption.name != null\n                && !isIdInner(cptOption)\n                && !isIdInner(exist)\n                && exist.name === cptOption.name + ''\n            ) {\n                result[i].option = cptOption;\n                newCptOptions[index] = null;\n                return;\n            }\n        }\n    });\n\n    // Otherwise mapping by index.\n    each$2(newCptOptions, function (cptOption, index) {\n        if (!isObject$2(cptOption)) {\n            return;\n        }\n\n        var i = 0;\n        for (; i < result.length; i++) {\n            var exist = result[i].exist;\n            if (!result[i].option\n                // Existing model that already has id should be able to\n                // mapped to (because after mapping performed model may\n                // be assigned with a id, whish should not affect next\n                // mapping), except those has inner id.\n                && !isIdInner(exist)\n                // Caution:\n                // Do not overwrite id. But name can be overwritten,\n                // because axis use name as 'show label text'.\n                // 'exist' always has id and name and we dont\n                // need to check it.\n                && cptOption.id == null\n            ) {\n                result[i].option = cptOption;\n                break;\n            }\n        }\n\n        if (i >= result.length) {\n            result.push({option: cptOption});\n        }\n    });\n\n    return result;\n}\n\n/**\n * Make id and name for mapping result (result of mappingToExists)\n * into `keyInfo` field.\n *\n * @public\n * @param {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],\n *                          which order is the same as exists.\n * @return {Array.<Object>} The input.\n */\nfunction makeIdAndName(mapResult) {\n    // We use this id to hash component models and view instances\n    // in echarts. id can be specified by user, or auto generated.\n\n    // The id generation rule ensures new view instance are able\n    // to mapped to old instance when setOption are called in\n    // no-merge mode. So we generate model id by name and plus\n    // type in view id.\n\n    // name can be duplicated among components, which is convenient\n    // to specify multi components (like series) by one name.\n\n    // Ensure that each id is distinct.\n    var idMap = createHashMap();\n\n    each$2(mapResult, function (item, index) {\n        var existCpt = item.exist;\n        existCpt && idMap.set(existCpt.id, item);\n    });\n\n    each$2(mapResult, function (item, index) {\n        var opt = item.option;\n\n        assert$1(\n            !opt || opt.id == null || !idMap.get(opt.id) || idMap.get(opt.id) === item,\n            'id duplicates: ' + (opt && opt.id)\n        );\n\n        opt && opt.id != null && idMap.set(opt.id, item);\n        !item.keyInfo && (item.keyInfo = {});\n    });\n\n    // Make name and id.\n    each$2(mapResult, function (item, index) {\n        var existCpt = item.exist;\n        var opt = item.option;\n        var keyInfo = item.keyInfo;\n\n        if (!isObject$2(opt)) {\n            return;\n        }\n\n        // name can be overwitten. Consider case: axis.name = '20km'.\n        // But id generated by name will not be changed, which affect\n        // only in that case: setOption with 'not merge mode' and view\n        // instance will be recreated, which can be accepted.\n        keyInfo.name = opt.name != null\n            ? opt.name + ''\n            : existCpt\n            ? existCpt.name\n            // Avoid diffferent series has the same name,\n            // because name may be used like in color pallet.\n            : DUMMY_COMPONENT_NAME_PREFIX + index;\n\n        if (existCpt) {\n            keyInfo.id = existCpt.id;\n        }\n        else if (opt.id != null) {\n            keyInfo.id = opt.id + '';\n        }\n        else {\n            // Consider this situatoin:\n            //  optionA: [{name: 'a'}, {name: 'a'}, {..}]\n            //  optionB [{..}, {name: 'a'}, {name: 'a'}]\n            // Series with the same name between optionA and optionB\n            // should be mapped.\n            var idNum = 0;\n            do {\n                keyInfo.id = '\\0' + keyInfo.name + '\\0' + idNum++;\n            }\n            while (idMap.get(keyInfo.id));\n        }\n\n        idMap.set(keyInfo.id, item);\n    });\n}\n\nfunction isNameSpecified(componentModel) {\n    var name = componentModel.name;\n    // Is specified when `indexOf` get -1 or > 0.\n    return !!(name && name.indexOf(DUMMY_COMPONENT_NAME_PREFIX));\n}\n\n/**\n * @public\n * @param {Object} cptOption\n * @return {boolean}\n */\nfunction isIdInner(cptOption) {\n    return isObject$2(cptOption)\n        && cptOption.id\n        && (cptOption.id + '').indexOf('\\0_ec_\\0') === 0;\n}\n\n/**\n * A helper for removing duplicate items between batchA and batchB,\n * and in themselves, and categorize by series.\n *\n * @param {Array.<Object>} batchA Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]\n * @param {Array.<Object>} batchB Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]\n * @return {Array.<Array.<Object>, Array.<Object>>} result: [resultBatchA, resultBatchB]\n */\n\n\n/**\n * @param {module:echarts/data/List} data\n * @param {Object} payload Contains dataIndex (means rawIndex) / dataIndexInside / name\n *                         each of which can be Array or primary type.\n * @return {number|Array.<number>} dataIndex If not found, return undefined/null.\n */\nfunction queryDataIndex(data, payload) {\n    if (payload.dataIndexInside != null) {\n        return payload.dataIndexInside;\n    }\n    else if (payload.dataIndex != null) {\n        return isArray(payload.dataIndex)\n            ? map(payload.dataIndex, function (value) {\n                return data.indexOfRawIndex(value);\n            })\n            : data.indexOfRawIndex(payload.dataIndex);\n    }\n    else if (payload.name != null) {\n        return isArray(payload.name)\n            ? map(payload.name, function (value) {\n                return data.indexOfName(value);\n            })\n            : data.indexOfName(payload.name);\n    }\n}\n\n/**\n * Enable property storage to any host object.\n * Notice: Serialization is not supported.\n *\n * For example:\n * var inner = zrUitl.makeInner();\n *\n * function some1(hostObj) {\n *      inner(hostObj).someProperty = 1212;\n *      ...\n * }\n * function some2() {\n *      var fields = inner(this);\n *      fields.someProperty1 = 1212;\n *      fields.someProperty2 = 'xx';\n *      ...\n * }\n *\n * @return {Function}\n */\nfunction makeInner() {\n    // Consider different scope by es module import.\n    var key = '__\\0ec_inner_' + innerUniqueIndex++ + '_' + Math.random().toFixed(5);\n    return function (hostObj) {\n        return hostObj[key] || (hostObj[key] = {});\n    };\n}\nvar innerUniqueIndex = 0;\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex, seriesId, seriesName,\n *            geoIndex, geoId, geoName,\n *            bmapIndex, bmapId, bmapName,\n *            xAxisIndex, xAxisId, xAxisName,\n *            yAxisIndex, yAxisId, yAxisName,\n *            gridIndex, gridId, gridName,\n *            ... (can be extended)\n *        }\n *        Each properties can be number|string|Array.<number>|Array.<string>\n *        For example, a finder could be\n *        {\n *            seriesIndex: 3,\n *            geoId: ['aa', 'cc'],\n *            gridName: ['xx', 'rr']\n *        }\n *        xxxIndex can be set as 'all' (means all xxx) or 'none' (means not specify)\n *        If nothing or null/undefined specified, return nothing.\n * @param {Object} [opt]\n * @param {string} [opt.defaultMainType]\n * @param {Array.<string>} [opt.includeMainTypes]\n * @return {Object} result like:\n *        {\n *            seriesModels: [seriesModel1, seriesModel2],\n *            seriesModel: seriesModel1, // The first model\n *            geoModels: [geoModel1, geoModel2],\n *            geoModel: geoModel1, // The first model\n *            ...\n *        }\n */\nfunction parseFinder(ecModel, finder, opt) {\n    if (isString(finder)) {\n        var obj = {};\n        obj[finder + 'Index'] = 0;\n        finder = obj;\n    }\n\n    var defaultMainType = opt && opt.defaultMainType;\n    if (defaultMainType\n        && !has(finder, defaultMainType + 'Index')\n        && !has(finder, defaultMainType + 'Id')\n        && !has(finder, defaultMainType + 'Name')\n    ) {\n        finder[defaultMainType + 'Index'] = 0;\n    }\n\n    var result = {};\n\n    each$2(finder, function (value, key) {\n        var value = finder[key];\n\n        // Exclude 'dataIndex' and other illgal keys.\n        if (key === 'dataIndex' || key === 'dataIndexInside') {\n            result[key] = value;\n            return;\n        }\n\n        var parsedKey = key.match(/^(\\w+)(Index|Id|Name)$/) || [];\n        var mainType = parsedKey[1];\n        var queryType = (parsedKey[2] || '').toLowerCase();\n\n        if (!mainType\n            || !queryType\n            || value == null\n            || (queryType === 'index' && value === 'none')\n            || (opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0)\n        ) {\n            return;\n        }\n\n        var queryParam = {mainType: mainType};\n        if (queryType !== 'index' || value !== 'all') {\n            queryParam[queryType] = value;\n        }\n\n        var models = ecModel.queryComponents(queryParam);\n        result[mainType + 'Models'] = models;\n        result[mainType + 'Model'] = models[0];\n    });\n\n    return result;\n}\n\nfunction has(obj, prop) {\n    return obj && obj.hasOwnProperty(prop);\n}\n\nfunction setAttribute(dom, key, value) {\n    dom.setAttribute\n        ? dom.setAttribute(key, value)\n        : (dom[key] = value);\n}\n\nfunction getAttribute(dom, key) {\n    return dom.getAttribute\n        ? dom.getAttribute(key)\n        : dom[key];\n}\n\nfunction getTooltipRenderMode(renderModeOption) {\n    if (renderModeOption === 'auto') {\n        // Using html when `document` exists, use richText otherwise\n        return env$1.domSupported ? 'html' : 'richText';\n    }\n    else {\n        return renderModeOption || 'html';\n    }\n}\n\n/**\n * Group a list by key.\n *\n * @param {Array} array\n * @param {Function} getKey\n *        param {*} Array item\n *        return {string} key\n * @return {Object} Result\n *        {Array}: keys,\n *        {module:zrender/core/util/HashMap} buckets: {key -> Array}\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TYPE_DELIMITER = '.';\nvar IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';\n\n/**\n * Notice, parseClassType('') should returns {main: '', sub: ''}\n * @public\n */\nfunction parseClassType$1(componentType) {\n    var ret = {main: '', sub: ''};\n    if (componentType) {\n        componentType = componentType.split(TYPE_DELIMITER);\n        ret.main = componentType[0] || '';\n        ret.sub = componentType[1] || '';\n    }\n    return ret;\n}\n\n/**\n * @public\n */\nfunction checkClassType(componentType) {\n    assert$1(\n        /^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType),\n        'componentType \"' + componentType + '\" illegal'\n    );\n}\n\n/**\n * @public\n */\nfunction enableClassExtend(RootClass, mandatoryMethods) {\n\n    RootClass.$constructor = RootClass;\n    RootClass.extend = function (proto) {\n\n        if (__DEV__) {\n            each$1(mandatoryMethods, function (method) {\n                if (!proto[method]) {\n                    console.warn(\n                        'Method `' + method + '` should be implemented'\n                        + (proto.type ? ' in ' + proto.type : '') + '.'\n                    );\n                }\n            });\n        }\n\n        var superClass = this;\n        var ExtendedClass = function () {\n            if (!proto.$constructor) {\n                superClass.apply(this, arguments);\n            }\n            else {\n                proto.$constructor.apply(this, arguments);\n            }\n        };\n\n        extend(ExtendedClass.prototype, proto);\n\n        ExtendedClass.extend = this.extend;\n        ExtendedClass.superCall = superCall;\n        ExtendedClass.superApply = superApply;\n        inherits(ExtendedClass, this);\n        ExtendedClass.superClass = superClass;\n\n        return ExtendedClass;\n    };\n}\n\nvar classBase = 0;\n\n/**\n * Can not use instanceof, consider different scope by\n * cross domain or es module import in ec extensions.\n * Mount a method \"isInstance()\" to Clz.\n */\nfunction enableClassCheck(Clz) {\n    var classAttr = ['__\\0is_clz', classBase++, Math.random().toFixed(3)].join('_');\n    Clz.prototype[classAttr] = true;\n\n    if (__DEV__) {\n        assert$1(!Clz.isInstance, 'The method \"is\" can not be defined.');\n    }\n\n    Clz.isInstance = function (obj) {\n        return !!(obj && obj[classAttr]);\n    };\n}\n\n// superCall should have class info, which can not be fetch from 'this'.\n// Consider this case:\n// class A has method f,\n// class B inherits class A, overrides method f, f call superApply('f'),\n// class C inherits class B, do not overrides method f,\n// then when method of class C is called, dead loop occured.\nfunction superCall(context, methodName) {\n    var args = slice(arguments, 2);\n    return this.superClass.prototype[methodName].apply(context, args);\n}\n\nfunction superApply(context, methodName, args) {\n    return this.superClass.prototype[methodName].apply(context, args);\n}\n\n/**\n * @param {Object} entity\n * @param {Object} options\n * @param {boolean} [options.registerWhenExtend]\n * @public\n */\nfunction enableClassManagement(entity, options) {\n    options = options || {};\n\n    /**\n     * Component model classes\n     * key: componentType,\n     * value:\n     *     componentClass, when componentType is 'xxx'\n     *     or Object.<subKey, componentClass>, when componentType is 'xxx.yy'\n     * @type {Object}\n     */\n    var storage = {};\n\n    entity.registerClass = function (Clazz, componentType) {\n        if (componentType) {\n            checkClassType(componentType);\n            componentType = parseClassType$1(componentType);\n\n            if (!componentType.sub) {\n                if (__DEV__) {\n                    if (storage[componentType.main]) {\n                        console.warn(componentType.main + ' exists.');\n                    }\n                }\n                storage[componentType.main] = Clazz;\n            }\n            else if (componentType.sub !== IS_CONTAINER) {\n                var container = makeContainer(componentType);\n                container[componentType.sub] = Clazz;\n            }\n        }\n        return Clazz;\n    };\n\n    entity.getClass = function (componentMainType, subType, throwWhenNotFound) {\n        var Clazz = storage[componentMainType];\n\n        if (Clazz && Clazz[IS_CONTAINER]) {\n            Clazz = subType ? Clazz[subType] : null;\n        }\n\n        if (throwWhenNotFound && !Clazz) {\n            throw new Error(\n                !subType\n                    ? componentMainType + '.' + 'type should be specified.'\n                    : 'Component ' + componentMainType + '.' + (subType || '') + ' not exists. Load it first.'\n            );\n        }\n\n        return Clazz;\n    };\n\n    entity.getClassesByMainType = function (componentType) {\n        componentType = parseClassType$1(componentType);\n\n        var result = [];\n        var obj = storage[componentType.main];\n\n        if (obj && obj[IS_CONTAINER]) {\n            each$1(obj, function (o, type) {\n                type !== IS_CONTAINER && result.push(o);\n            });\n        }\n        else {\n            result.push(obj);\n        }\n\n        return result;\n    };\n\n    entity.hasClass = function (componentType) {\n        // Just consider componentType.main.\n        componentType = parseClassType$1(componentType);\n        return !!storage[componentType.main];\n    };\n\n    /**\n     * @return {Array.<string>} Like ['aa', 'bb'], but can not be ['aa.xx']\n     */\n    entity.getAllClassMainTypes = function () {\n        var types = [];\n        each$1(storage, function (obj, type) {\n            types.push(type);\n        });\n        return types;\n    };\n\n    /**\n     * If a main type is container and has sub types\n     * @param  {string}  mainType\n     * @return {boolean}\n     */\n    entity.hasSubTypes = function (componentType) {\n        componentType = parseClassType$1(componentType);\n        var obj = storage[componentType.main];\n        return obj && obj[IS_CONTAINER];\n    };\n\n    entity.parseClassType = parseClassType$1;\n\n    function makeContainer(componentType) {\n        var container = storage[componentType.main];\n        if (!container || !container[IS_CONTAINER]) {\n            container = storage[componentType.main] = {};\n            container[IS_CONTAINER] = true;\n        }\n        return container;\n    }\n\n    if (options.registerWhenExtend) {\n        var originalExtend = entity.extend;\n        if (originalExtend) {\n            entity.extend = function (proto) {\n                var ExtendedClass = originalExtend.call(this, proto);\n                return entity.registerClass(ExtendedClass, proto.type);\n            };\n        }\n    }\n\n    return entity;\n}\n\n/**\n * @param {string|Array.<string>} properties\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Parse shadow style\n// TODO Only shallow path support\nvar makeStyleMapper = function (properties) {\n    // Normalize\n    for (var i = 0; i < properties.length; i++) {\n        if (!properties[i][1]) {\n            properties[i][1] = properties[i][0];\n        }\n    }\n    return function (model, excludes, includes) {\n        var style = {};\n        for (var i = 0; i < properties.length; i++) {\n            var propName = properties[i][1];\n            if ((excludes && indexOf(excludes, propName) >= 0)\n                || (includes && indexOf(includes, propName) < 0)\n            ) {\n                continue;\n            }\n            var val = model.getShallow(propName);\n            if (val != null) {\n                style[properties[i][0]] = val;\n            }\n        }\n        return style;\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getLineStyle = makeStyleMapper(\n    [\n        ['lineWidth', 'width'],\n        ['stroke', 'color'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor']\n    ]\n);\n\nvar lineStyleMixin = {\n    getLineStyle: function (excludes) {\n        var style = getLineStyle(this, excludes);\n        var lineDash = this.getLineDash(style.lineWidth);\n        lineDash && (style.lineDash = lineDash);\n        return style;\n    },\n\n    getLineDash: function (lineWidth) {\n        if (lineWidth == null) {\n            lineWidth = 1;\n        }\n        var lineType = this.get('type');\n        var dotSize = Math.max(lineWidth, 2);\n        var dashSize = lineWidth * 4;\n        return (lineType === 'solid' || lineType == null) ? null\n            : (lineType === 'dashed' ? [dashSize, dashSize] : [dotSize, dotSize]);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getAreaStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['opacity'],\n        ['shadowColor']\n    ]\n);\n\nvar areaStyleMixin = {\n    getAreaStyle: function (excludes, includes) {\n        return getAreaStyle(this, excludes, includes);\n    }\n};\n\n/**\n * 曲线辅助模块\n * @module zrender/core/curve\n * @author pissang(https://www.github.com/pissang)\n */\n\nvar mathPow = Math.pow;\nvar mathSqrt$2 = Math.sqrt;\n\nvar EPSILON$1 = 1e-8;\nvar EPSILON_NUMERIC = 1e-4;\n\nvar THREE_SQRT = mathSqrt$2(3);\nvar ONE_THIRD = 1 / 3;\n\n// 临时变量\nvar _v0 = create();\nvar _v1 = create();\nvar _v2 = create();\n\nfunction isAroundZero(val) {\n    return val > -EPSILON$1 && val < EPSILON$1;\n}\nfunction isNotAroundZero$1(val) {\n    return val > EPSILON$1 || val < -EPSILON$1;\n}\n/**\n * 计算三次贝塞尔值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @return {number}\n */\nfunction cubicAt(p0, p1, p2, p3, t) {\n    var onet = 1 - t;\n    return onet * onet * (onet * p0 + 3 * t * p1)\n            + t * t * (t * p3 + 3 * onet * p2);\n}\n\n/**\n * 计算三次贝塞尔导数值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @return {number}\n */\nfunction cubicDerivativeAt(p0, p1, p2, p3, t) {\n    var onet = 1 - t;\n    return 3 * (\n        ((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet\n        + (p3 - p2) * t * t\n    );\n}\n\n/**\n * 计算三次贝塞尔方程根，使用盛金公式\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} val\n * @param  {Array.<number>} roots\n * @return {number} 有效根数目\n */\nfunction cubicRootAt(p0, p1, p2, p3, val, roots) {\n    // Evaluate roots of cubic functions\n    var a = p3 + 3 * (p1 - p2) - p0;\n    var b = 3 * (p2 - p1 * 2 + p0);\n    var c = 3 * (p1 - p0);\n    var d = p0 - val;\n\n    var A = b * b - 3 * a * c;\n    var B = b * c - 9 * a * d;\n    var C = c * c - 3 * b * d;\n\n    var n = 0;\n\n    if (isAroundZero(A) && isAroundZero(B)) {\n        if (isAroundZero(b)) {\n            roots[0] = 0;\n        }\n        else {\n            var t1 = -c / b;  //t1, t2, t3, b is not zero\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = B * B - 4 * A * C;\n\n        if (isAroundZero(disc)) {\n            var K = B / A;\n            var t1 = -b / a + K;  // t1, a is not zero\n            var t2 = -K / 2;  // t2, t3\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var Y1 = A * b + 1.5 * a * (-B + discSqrt);\n            var Y2 = A * b + 1.5 * a * (-B - discSqrt);\n            if (Y1 < 0) {\n                Y1 = -mathPow(-Y1, ONE_THIRD);\n            }\n            else {\n                Y1 = mathPow(Y1, ONE_THIRD);\n            }\n            if (Y2 < 0) {\n                Y2 = -mathPow(-Y2, ONE_THIRD);\n            }\n            else {\n                Y2 = mathPow(Y2, ONE_THIRD);\n            }\n            var t1 = (-b - (Y1 + Y2)) / (3 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n        else {\n            var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt$2(A * A * A));\n            var theta = Math.acos(T) / 3;\n            var ASqrt = mathSqrt$2(A);\n            var tmp = Math.cos(theta);\n\n            var t1 = (-b - 2 * ASqrt * tmp) / (3 * a);\n            var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a);\n            var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n            if (t3 >= 0 && t3 <= 1) {\n                roots[n++] = t3;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 计算三次贝塞尔方程极限值的位置\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {Array.<number>} extrema\n * @return {number} 有效数目\n */\nfunction cubicExtrema(p0, p1, p2, p3, extrema) {\n    var b = 6 * p2 - 12 * p1 + 6 * p0;\n    var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2;\n    var c = 3 * p1 - 3 * p0;\n\n    var n = 0;\n    if (isAroundZero(a)) {\n        if (isNotAroundZero$1(b)) {\n            var t1 = -c / b;\n            if (t1 >= 0 && t1 <= 1) {\n                extrema[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = b * b - 4 * a * c;\n        if (isAroundZero(disc)) {\n            extrema[0] = -b / (2 * a);\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var t1 = (-b + discSqrt) / (2 * a);\n            var t2 = (-b - discSqrt) / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                extrema[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                extrema[n++] = t2;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 细分三次贝塞尔曲线\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @param  {Array.<number>} out\n */\nfunction cubicSubdivide(p0, p1, p2, p3, t, out) {\n    var p01 = (p1 - p0) * t + p0;\n    var p12 = (p2 - p1) * t + p1;\n    var p23 = (p3 - p2) * t + p2;\n\n    var p012 = (p12 - p01) * t + p01;\n    var p123 = (p23 - p12) * t + p12;\n\n    var p0123 = (p123 - p012) * t + p012;\n    // Seg0\n    out[0] = p0;\n    out[1] = p01;\n    out[2] = p012;\n    out[3] = p0123;\n    // Seg1\n    out[4] = p0123;\n    out[5] = p123;\n    out[6] = p23;\n    out[7] = p3;\n}\n\n/**\n * 投射点到三次贝塞尔曲线上，返回投射距离。\n * 投射点有可能会有一个或者多个，这里只返回其中距离最短的一个。\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x3\n * @param {number} y3\n * @param {number} x\n * @param {number} y\n * @param {Array.<number>} [out] 投射点\n * @return {number}\n */\nfunction cubicProjectPoint(\n    x0, y0, x1, y1, x2, y2, x3, y3,\n    x, y, out\n) {\n    // http://pomax.github.io/bezierinfo/#projections\n    var t;\n    var interval = 0.005;\n    var d = Infinity;\n    var prev;\n    var next;\n    var d1;\n    var d2;\n\n    _v0[0] = x;\n    _v0[1] = y;\n\n    // 先粗略估计一下可能的最小距离的 t 值\n    // PENDING\n    for (var _t = 0; _t < 1; _t += 0.05) {\n        _v1[0] = cubicAt(x0, x1, x2, x3, _t);\n        _v1[1] = cubicAt(y0, y1, y2, y3, _t);\n        d1 = distSquare(_v0, _v1);\n        if (d1 < d) {\n            t = _t;\n            d = d1;\n        }\n    }\n    d = Infinity;\n\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        if (interval < EPSILON_NUMERIC) {\n            break;\n        }\n        prev = t - interval;\n        next = t + interval;\n        // t - interval\n        _v1[0] = cubicAt(x0, x1, x2, x3, prev);\n        _v1[1] = cubicAt(y0, y1, y2, y3, prev);\n\n        d1 = distSquare(_v1, _v0);\n\n        if (prev >= 0 && d1 < d) {\n            t = prev;\n            d = d1;\n        }\n        else {\n            // t + interval\n            _v2[0] = cubicAt(x0, x1, x2, x3, next);\n            _v2[1] = cubicAt(y0, y1, y2, y3, next);\n            d2 = distSquare(_v2, _v0);\n\n            if (next <= 1 && d2 < d) {\n                t = next;\n                d = d2;\n            }\n            else {\n                interval *= 0.5;\n            }\n        }\n    }\n    // t\n    if (out) {\n        out[0] = cubicAt(x0, x1, x2, x3, t);\n        out[1] = cubicAt(y0, y1, y2, y3, t);\n    }\n    // console.log(interval, i);\n    return mathSqrt$2(d);\n}\n\n/**\n * 计算二次方贝塞尔值\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @return {number}\n */\nfunction quadraticAt(p0, p1, p2, t) {\n    var onet = 1 - t;\n    return onet * (onet * p0 + 2 * t * p1) + t * t * p2;\n}\n\n/**\n * 计算二次方贝塞尔导数值\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @return {number}\n */\nfunction quadraticDerivativeAt(p0, p1, p2, t) {\n    return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1));\n}\n\n/**\n * 计算二次方贝塞尔方程根\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @param  {Array.<number>} roots\n * @return {number} 有效根数目\n */\nfunction quadraticRootAt(p0, p1, p2, val, roots) {\n    var a = p0 - 2 * p1 + p2;\n    var b = 2 * (p1 - p0);\n    var c = p0 - val;\n\n    var n = 0;\n    if (isAroundZero(a)) {\n        if (isNotAroundZero$1(b)) {\n            var t1 = -c / b;\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = b * b - 4 * a * c;\n        if (isAroundZero(disc)) {\n            var t1 = -b / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var t1 = (-b + discSqrt) / (2 * a);\n            var t2 = (-b - discSqrt) / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 计算二次贝塞尔方程极限值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @return {number}\n */\nfunction quadraticExtremum(p0, p1, p2) {\n    var divider = p0 + p2 - 2 * p1;\n    if (divider === 0) {\n        // p1 is center of p0 and p2\n        return 0.5;\n    }\n    else {\n        return (p0 - p1) / divider;\n    }\n}\n\n/**\n * 细分二次贝塞尔曲线\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @param  {Array.<number>} out\n */\nfunction quadraticSubdivide(p0, p1, p2, t, out) {\n    var p01 = (p1 - p0) * t + p0;\n    var p12 = (p2 - p1) * t + p1;\n    var p012 = (p12 - p01) * t + p01;\n\n    // Seg0\n    out[0] = p0;\n    out[1] = p01;\n    out[2] = p012;\n\n    // Seg1\n    out[3] = p012;\n    out[4] = p12;\n    out[5] = p2;\n}\n\n/**\n * 投射点到二次贝塞尔曲线上，返回投射距离。\n * 投射点有可能会有一个或者多个，这里只返回其中距离最短的一个。\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x\n * @param {number} y\n * @param {Array.<number>} out 投射点\n * @return {number}\n */\nfunction quadraticProjectPoint(\n    x0, y0, x1, y1, x2, y2,\n    x, y, out\n) {\n    // http://pomax.github.io/bezierinfo/#projections\n    var t;\n    var interval = 0.005;\n    var d = Infinity;\n\n    _v0[0] = x;\n    _v0[1] = y;\n\n    // 先粗略估计一下可能的最小距离的 t 值\n    // PENDING\n    for (var _t = 0; _t < 1; _t += 0.05) {\n        _v1[0] = quadraticAt(x0, x1, x2, _t);\n        _v1[1] = quadraticAt(y0, y1, y2, _t);\n        var d1 = distSquare(_v0, _v1);\n        if (d1 < d) {\n            t = _t;\n            d = d1;\n        }\n    }\n    d = Infinity;\n\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        if (interval < EPSILON_NUMERIC) {\n            break;\n        }\n        var prev = t - interval;\n        var next = t + interval;\n        // t - interval\n        _v1[0] = quadraticAt(x0, x1, x2, prev);\n        _v1[1] = quadraticAt(y0, y1, y2, prev);\n\n        var d1 = distSquare(_v1, _v0);\n\n        if (prev >= 0 && d1 < d) {\n            t = prev;\n            d = d1;\n        }\n        else {\n            // t + interval\n            _v2[0] = quadraticAt(x0, x1, x2, next);\n            _v2[1] = quadraticAt(y0, y1, y2, next);\n            var d2 = distSquare(_v2, _v0);\n            if (next <= 1 && d2 < d) {\n                t = next;\n                d = d2;\n            }\n            else {\n                interval *= 0.5;\n            }\n        }\n    }\n    // t\n    if (out) {\n        out[0] = quadraticAt(x0, x1, x2, t);\n        out[1] = quadraticAt(y0, y1, y2, t);\n    }\n    // console.log(interval, i);\n    return mathSqrt$2(d);\n}\n\n/**\n * @author Yi Shen(https://github.com/pissang)\n */\n\nvar mathMin$3 = Math.min;\nvar mathMax$3 = Math.max;\nvar mathSin$2 = Math.sin;\nvar mathCos$2 = Math.cos;\nvar PI2 = Math.PI * 2;\n\nvar start = create();\nvar end = create();\nvar extremity = create();\n\n/**\n * 从顶点数组中计算出最小包围盒，写入`min`和`max`中\n * @module zrender/core/bbox\n * @param {Array<Object>} points 顶点数组\n * @param {number} min\n * @param {number} max\n */\nfunction fromPoints(points, min$$1, max$$1) {\n    if (points.length === 0) {\n        return;\n    }\n    var p = points[0];\n    var left = p[0];\n    var right = p[0];\n    var top = p[1];\n    var bottom = p[1];\n    var i;\n\n    for (i = 1; i < points.length; i++) {\n        p = points[i];\n        left = mathMin$3(left, p[0]);\n        right = mathMax$3(right, p[0]);\n        top = mathMin$3(top, p[1]);\n        bottom = mathMax$3(bottom, p[1]);\n    }\n\n    min$$1[0] = left;\n    min$$1[1] = top;\n    max$$1[0] = right;\n    max$$1[1] = bottom;\n}\n\n/**\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromLine(x0, y0, x1, y1, min$$1, max$$1) {\n    min$$1[0] = mathMin$3(x0, x1);\n    min$$1[1] = mathMin$3(y0, y1);\n    max$$1[0] = mathMax$3(x0, x1);\n    max$$1[1] = mathMax$3(y0, y1);\n}\n\nvar xDim = [];\nvar yDim = [];\n/**\n * 从三阶贝塞尔曲线(p0, p1, p2, p3)中计算出最小包围盒，写入`min`和`max`中\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x3\n * @param {number} y3\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromCubic(\n    x0, y0, x1, y1, x2, y2, x3, y3, min$$1, max$$1\n) {\n    var cubicExtrema$$1 = cubicExtrema;\n    var cubicAt$$1 = cubicAt;\n    var i;\n    var n = cubicExtrema$$1(x0, x1, x2, x3, xDim);\n    min$$1[0] = Infinity;\n    min$$1[1] = Infinity;\n    max$$1[0] = -Infinity;\n    max$$1[1] = -Infinity;\n\n    for (i = 0; i < n; i++) {\n        var x = cubicAt$$1(x0, x1, x2, x3, xDim[i]);\n        min$$1[0] = mathMin$3(x, min$$1[0]);\n        max$$1[0] = mathMax$3(x, max$$1[0]);\n    }\n    n = cubicExtrema$$1(y0, y1, y2, y3, yDim);\n    for (i = 0; i < n; i++) {\n        var y = cubicAt$$1(y0, y1, y2, y3, yDim[i]);\n        min$$1[1] = mathMin$3(y, min$$1[1]);\n        max$$1[1] = mathMax$3(y, max$$1[1]);\n    }\n\n    min$$1[0] = mathMin$3(x0, min$$1[0]);\n    max$$1[0] = mathMax$3(x0, max$$1[0]);\n    min$$1[0] = mathMin$3(x3, min$$1[0]);\n    max$$1[0] = mathMax$3(x3, max$$1[0]);\n\n    min$$1[1] = mathMin$3(y0, min$$1[1]);\n    max$$1[1] = mathMax$3(y0, max$$1[1]);\n    min$$1[1] = mathMin$3(y3, min$$1[1]);\n    max$$1[1] = mathMax$3(y3, max$$1[1]);\n}\n\n/**\n * 从二阶贝塞尔曲线(p0, p1, p2)中计算出最小包围盒，写入`min`和`max`中\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromQuadratic(x0, y0, x1, y1, x2, y2, min$$1, max$$1) {\n    var quadraticExtremum$$1 = quadraticExtremum;\n    var quadraticAt$$1 = quadraticAt;\n    // Find extremities, where derivative in x dim or y dim is zero\n    var tx =\n        mathMax$3(\n            mathMin$3(quadraticExtremum$$1(x0, x1, x2), 1), 0\n        );\n    var ty =\n        mathMax$3(\n            mathMin$3(quadraticExtremum$$1(y0, y1, y2), 1), 0\n        );\n\n    var x = quadraticAt$$1(x0, x1, x2, tx);\n    var y = quadraticAt$$1(y0, y1, y2, ty);\n\n    min$$1[0] = mathMin$3(x0, x2, x);\n    min$$1[1] = mathMin$3(y0, y2, y);\n    max$$1[0] = mathMax$3(x0, x2, x);\n    max$$1[1] = mathMax$3(y0, y2, y);\n}\n\n/**\n * 从圆弧中计算出最小包围盒，写入`min`和`max`中\n * @method\n * @memberOf module:zrender/core/bbox\n * @param {number} x\n * @param {number} y\n * @param {number} rx\n * @param {number} ry\n * @param {number} startAngle\n * @param {number} endAngle\n * @param {number} anticlockwise\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromArc(\n    x, y, rx, ry, startAngle, endAngle, anticlockwise, min$$1, max$$1\n) {\n    var vec2Min = min;\n    var vec2Max = max;\n\n    var diff = Math.abs(startAngle - endAngle);\n\n\n    if (diff % PI2 < 1e-4 && diff > 1e-4) {\n        // Is a circle\n        min$$1[0] = x - rx;\n        min$$1[1] = y - ry;\n        max$$1[0] = x + rx;\n        max$$1[1] = y + ry;\n        return;\n    }\n\n    start[0] = mathCos$2(startAngle) * rx + x;\n    start[1] = mathSin$2(startAngle) * ry + y;\n\n    end[0] = mathCos$2(endAngle) * rx + x;\n    end[1] = mathSin$2(endAngle) * ry + y;\n\n    vec2Min(min$$1, start, end);\n    vec2Max(max$$1, start, end);\n\n    // Thresh to [0, Math.PI * 2]\n    startAngle = startAngle % (PI2);\n    if (startAngle < 0) {\n        startAngle = startAngle + PI2;\n    }\n    endAngle = endAngle % (PI2);\n    if (endAngle < 0) {\n        endAngle = endAngle + PI2;\n    }\n\n    if (startAngle > endAngle && !anticlockwise) {\n        endAngle += PI2;\n    }\n    else if (startAngle < endAngle && anticlockwise) {\n        startAngle += PI2;\n    }\n    if (anticlockwise) {\n        var tmp = endAngle;\n        endAngle = startAngle;\n        startAngle = tmp;\n    }\n\n    // var number = 0;\n    // var step = (anticlockwise ? -Math.PI : Math.PI) / 2;\n    for (var angle = 0; angle < endAngle; angle += Math.PI / 2) {\n        if (angle > startAngle) {\n            extremity[0] = mathCos$2(angle) * rx + x;\n            extremity[1] = mathSin$2(angle) * ry + y;\n\n            vec2Min(min$$1, extremity, min$$1);\n            vec2Max(max$$1, extremity, max$$1);\n        }\n    }\n}\n\n/**\n * Path 代理，可以在`buildPath`中用于替代`ctx`, 会保存每个path操作的命令到pathCommands属性中\n * 可以用于 isInsidePath 判断以及获取boundingRect\n *\n * @module zrender/core/PathProxy\n * @author Yi Shen (http://www.github.com/pissang)\n */\n\n// TODO getTotalLength, getPointAtLength\n\nvar CMD = {\n    M: 1,\n    L: 2,\n    C: 3,\n    Q: 4,\n    A: 5,\n    Z: 6,\n    // Rect\n    R: 7\n};\n\n// var CMD_MEM_SIZE = {\n//     M: 3,\n//     L: 3,\n//     C: 7,\n//     Q: 5,\n//     A: 9,\n//     R: 5,\n//     Z: 1\n// };\n\nvar min$1 = [];\nvar max$1 = [];\nvar min2 = [];\nvar max2 = [];\nvar mathMin$2 = Math.min;\nvar mathMax$2 = Math.max;\nvar mathCos$1 = Math.cos;\nvar mathSin$1 = Math.sin;\nvar mathSqrt$1 = Math.sqrt;\nvar mathAbs = Math.abs;\n\nvar hasTypedArray = typeof Float32Array !== 'undefined';\n\n/**\n * @alias module:zrender/core/PathProxy\n * @constructor\n */\nvar PathProxy = function (notSaveData) {\n\n    this._saveData = !(notSaveData || false);\n\n    if (this._saveData) {\n        /**\n         * Path data. Stored as flat array\n         * @type {Array.<Object>}\n         */\n        this.data = [];\n    }\n\n    this._ctx = null;\n};\n\n/**\n * 快速计算Path包围盒（并不是最小包围盒）\n * @return {Object}\n */\nPathProxy.prototype = {\n\n    constructor: PathProxy,\n\n    _xi: 0,\n    _yi: 0,\n\n    _x0: 0,\n    _y0: 0,\n    // Unit x, Unit y. Provide for avoiding drawing that too short line segment\n    _ux: 0,\n    _uy: 0,\n\n    _len: 0,\n\n    _lineDash: null,\n\n    _dashOffset: 0,\n\n    _dashIdx: 0,\n\n    _dashSum: 0,\n\n    /**\n     * @readOnly\n     */\n    setScale: function (sx, sy) {\n        this._ux = mathAbs(1 / devicePixelRatio / sx) || 0;\n        this._uy = mathAbs(1 / devicePixelRatio / sy) || 0;\n    },\n\n    getContext: function () {\n        return this._ctx;\n    },\n\n    /**\n     * @param  {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    beginPath: function (ctx) {\n\n        this._ctx = ctx;\n\n        ctx && ctx.beginPath();\n\n        ctx && (this.dpr = ctx.dpr);\n\n        // Reset\n        if (this._saveData) {\n            this._len = 0;\n        }\n\n        if (this._lineDash) {\n            this._lineDash = null;\n\n            this._dashOffset = 0;\n        }\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x\n     * @param  {number} y\n     * @return {module:zrender/core/PathProxy}\n     */\n    moveTo: function (x, y) {\n        this.addData(CMD.M, x, y);\n        this._ctx && this._ctx.moveTo(x, y);\n\n        // x0, y0, xi, yi 是记录在 _dashedXXXXTo 方法中使用\n        // xi, yi 记录当前点, x0, y0 在 closePath 的时候回到起始点。\n        // 有可能在 beginPath 之后直接调用 lineTo，这时候 x0, y0 需要\n        // 在 lineTo 方法中记录，这里先不考虑这种情况，dashed line 也只在 IE10- 中不支持\n        this._x0 = x;\n        this._y0 = y;\n\n        this._xi = x;\n        this._yi = y;\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x\n     * @param  {number} y\n     * @return {module:zrender/core/PathProxy}\n     */\n    lineTo: function (x, y) {\n        var exceedUnit = mathAbs(x - this._xi) > this._ux\n            || mathAbs(y - this._yi) > this._uy\n            // Force draw the first segment\n            || this._len < 5;\n\n        this.addData(CMD.L, x, y);\n\n        if (this._ctx && exceedUnit) {\n            this._needsDash() ? this._dashedLineTo(x, y)\n                : this._ctx.lineTo(x, y);\n        }\n        if (exceedUnit) {\n            this._xi = x;\n            this._yi = y;\n        }\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x1\n     * @param  {number} y1\n     * @param  {number} x2\n     * @param  {number} y2\n     * @param  {number} x3\n     * @param  {number} y3\n     * @return {module:zrender/core/PathProxy}\n     */\n    bezierCurveTo: function (x1, y1, x2, y2, x3, y3) {\n        this.addData(CMD.C, x1, y1, x2, y2, x3, y3);\n        if (this._ctx) {\n            this._needsDash() ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3)\n                : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);\n        }\n        this._xi = x3;\n        this._yi = y3;\n        return this;\n    },\n\n    /**\n     * @param  {number} x1\n     * @param  {number} y1\n     * @param  {number} x2\n     * @param  {number} y2\n     * @return {module:zrender/core/PathProxy}\n     */\n    quadraticCurveTo: function (x1, y1, x2, y2) {\n        this.addData(CMD.Q, x1, y1, x2, y2);\n        if (this._ctx) {\n            this._needsDash() ? this._dashedQuadraticTo(x1, y1, x2, y2)\n                : this._ctx.quadraticCurveTo(x1, y1, x2, y2);\n        }\n        this._xi = x2;\n        this._yi = y2;\n        return this;\n    },\n\n    /**\n     * @param  {number} cx\n     * @param  {number} cy\n     * @param  {number} r\n     * @param  {number} startAngle\n     * @param  {number} endAngle\n     * @param  {boolean} anticlockwise\n     * @return {module:zrender/core/PathProxy}\n     */\n    arc: function (cx, cy, r, startAngle, endAngle, anticlockwise) {\n        this.addData(\n            CMD.A, cx, cy, r, r, startAngle, endAngle - startAngle, 0, anticlockwise ? 0 : 1\n        );\n        this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);\n\n        this._xi = mathCos$1(endAngle) * r + cx;\n        this._yi = mathSin$1(endAngle) * r + cy;\n        return this;\n    },\n\n    // TODO\n    arcTo: function (x1, y1, x2, y2, radius) {\n        if (this._ctx) {\n            this._ctx.arcTo(x1, y1, x2, y2, radius);\n        }\n        return this;\n    },\n\n    // TODO\n    rect: function (x, y, w, h) {\n        this._ctx && this._ctx.rect(x, y, w, h);\n        this.addData(CMD.R, x, y, w, h);\n        return this;\n    },\n\n    /**\n     * @return {module:zrender/core/PathProxy}\n     */\n    closePath: function () {\n        this.addData(CMD.Z);\n\n        var ctx = this._ctx;\n        var x0 = this._x0;\n        var y0 = this._y0;\n        if (ctx) {\n            this._needsDash() && this._dashedLineTo(x0, y0);\n            ctx.closePath();\n        }\n\n        this._xi = x0;\n        this._yi = y0;\n        return this;\n    },\n\n    /**\n     * Context 从外部传入，因为有可能是 rebuildPath 完之后再 fill。\n     * stroke 同样\n     * @param {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    fill: function (ctx) {\n        ctx && ctx.fill();\n        this.toStatic();\n    },\n\n    /**\n     * @param {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    stroke: function (ctx) {\n        ctx && ctx.stroke();\n        this.toStatic();\n    },\n\n    /**\n     * 必须在其它绘制命令前调用\n     * Must be invoked before all other path drawing methods\n     * @return {module:zrender/core/PathProxy}\n     */\n    setLineDash: function (lineDash) {\n        if (lineDash instanceof Array) {\n            this._lineDash = lineDash;\n\n            this._dashIdx = 0;\n\n            var lineDashSum = 0;\n            for (var i = 0; i < lineDash.length; i++) {\n                lineDashSum += lineDash[i];\n            }\n            this._dashSum = lineDashSum;\n        }\n        return this;\n    },\n\n    /**\n     * 必须在其它绘制命令前调用\n     * Must be invoked before all other path drawing methods\n     * @return {module:zrender/core/PathProxy}\n     */\n    setLineDashOffset: function (offset) {\n        this._dashOffset = offset;\n        return this;\n    },\n\n    /**\n     *\n     * @return {boolean}\n     */\n    len: function () {\n        return this._len;\n    },\n\n    /**\n     * 直接设置 Path 数据\n     */\n    setData: function (data) {\n\n        var len$$1 = data.length;\n\n        if (!(this.data && this.data.length === len$$1) && hasTypedArray) {\n            this.data = new Float32Array(len$$1);\n        }\n\n        for (var i = 0; i < len$$1; i++) {\n            this.data[i] = data[i];\n        }\n\n        this._len = len$$1;\n    },\n\n    /**\n     * 添加子路径\n     * @param {module:zrender/core/PathProxy|Array.<module:zrender/core/PathProxy>} path\n     */\n    appendPath: function (path) {\n        if (!(path instanceof Array)) {\n            path = [path];\n        }\n        var len$$1 = path.length;\n        var appendSize = 0;\n        var offset = this._len;\n        for (var i = 0; i < len$$1; i++) {\n            appendSize += path[i].len();\n        }\n        if (hasTypedArray && (this.data instanceof Float32Array)) {\n            this.data = new Float32Array(offset + appendSize);\n        }\n        for (var i = 0; i < len$$1; i++) {\n            var appendPathData = path[i].data;\n            for (var k = 0; k < appendPathData.length; k++) {\n                this.data[offset++] = appendPathData[k];\n            }\n        }\n        this._len = offset;\n    },\n\n    /**\n     * 填充 Path 数据。\n     * 尽量复用而不申明新的数组。大部分图形重绘的指令数据长度都是不变的。\n     */\n    addData: function (cmd) {\n        if (!this._saveData) {\n            return;\n        }\n\n        var data = this.data;\n        if (this._len + arguments.length > data.length) {\n            // 因为之前的数组已经转换成静态的 Float32Array\n            // 所以不够用时需要扩展一个新的动态数组\n            this._expandData();\n            data = this.data;\n        }\n        for (var i = 0; i < arguments.length; i++) {\n            data[this._len++] = arguments[i];\n        }\n\n        this._prevCmd = cmd;\n    },\n\n    _expandData: function () {\n        // Only if data is Float32Array\n        if (!(this.data instanceof Array)) {\n            var newData = [];\n            for (var i = 0; i < this._len; i++) {\n                newData[i] = this.data[i];\n            }\n            this.data = newData;\n        }\n    },\n\n    /**\n     * If needs js implemented dashed line\n     * @return {boolean}\n     * @private\n     */\n    _needsDash: function () {\n        return this._lineDash;\n    },\n\n    _dashedLineTo: function (x1, y1) {\n        var dashSum = this._dashSum;\n        var offset = this._dashOffset;\n        var lineDash = this._lineDash;\n        var ctx = this._ctx;\n\n        var x0 = this._xi;\n        var y0 = this._yi;\n        var dx = x1 - x0;\n        var dy = y1 - y0;\n        var dist$$1 = mathSqrt$1(dx * dx + dy * dy);\n        var x = x0;\n        var y = y0;\n        var dash;\n        var nDash = lineDash.length;\n        var idx;\n        dx /= dist$$1;\n        dy /= dist$$1;\n\n        if (offset < 0) {\n            // Convert to positive offset\n            offset = dashSum + offset;\n        }\n        offset %= dashSum;\n        x -= offset * dx;\n        y -= offset * dy;\n\n        while ((dx > 0 && x <= x1) || (dx < 0 && x >= x1)\n        || (dx === 0 && ((dy > 0 && y <= y1) || (dy < 0 && y >= y1)))) {\n            idx = this._dashIdx;\n            dash = lineDash[idx];\n            x += dx * dash;\n            y += dy * dash;\n            this._dashIdx = (idx + 1) % nDash;\n            // Skip positive offset\n            if ((dx > 0 && x < x0) || (dx < 0 && x > x0) || (dy > 0 && y < y0) || (dy < 0 && y > y0)) {\n                continue;\n            }\n            ctx[idx % 2 ? 'moveTo' : 'lineTo'](\n                dx >= 0 ? mathMin$2(x, x1) : mathMax$2(x, x1),\n                dy >= 0 ? mathMin$2(y, y1) : mathMax$2(y, y1)\n            );\n        }\n        // Offset for next lineTo\n        dx = x - x1;\n        dy = y - y1;\n        this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);\n    },\n\n    // Not accurate dashed line to\n    _dashedBezierTo: function (x1, y1, x2, y2, x3, y3) {\n        var dashSum = this._dashSum;\n        var offset = this._dashOffset;\n        var lineDash = this._lineDash;\n        var ctx = this._ctx;\n\n        var x0 = this._xi;\n        var y0 = this._yi;\n        var t;\n        var dx;\n        var dy;\n        var cubicAt$$1 = cubicAt;\n        var bezierLen = 0;\n        var idx = this._dashIdx;\n        var nDash = lineDash.length;\n\n        var x;\n        var y;\n\n        var tmpLen = 0;\n\n        if (offset < 0) {\n            // Convert to positive offset\n            offset = dashSum + offset;\n        }\n        offset %= dashSum;\n        // Bezier approx length\n        for (t = 0; t < 1; t += 0.1) {\n            dx = cubicAt$$1(x0, x1, x2, x3, t + 0.1)\n                - cubicAt$$1(x0, x1, x2, x3, t);\n            dy = cubicAt$$1(y0, y1, y2, y3, t + 0.1)\n                - cubicAt$$1(y0, y1, y2, y3, t);\n            bezierLen += mathSqrt$1(dx * dx + dy * dy);\n        }\n\n        // Find idx after add offset\n        for (; idx < nDash; idx++) {\n            tmpLen += lineDash[idx];\n            if (tmpLen > offset) {\n                break;\n            }\n        }\n        t = (tmpLen - offset) / bezierLen;\n\n        while (t <= 1) {\n\n            x = cubicAt$$1(x0, x1, x2, x3, t);\n            y = cubicAt$$1(y0, y1, y2, y3, t);\n\n            // Use line to approximate dashed bezier\n            // Bad result if dash is long\n            idx % 2 ? ctx.moveTo(x, y)\n                : ctx.lineTo(x, y);\n\n            t += lineDash[idx] / bezierLen;\n\n            idx = (idx + 1) % nDash;\n        }\n\n        // Finish the last segment and calculate the new offset\n        (idx % 2 !== 0) && ctx.lineTo(x3, y3);\n        dx = x3 - x;\n        dy = y3 - y;\n        this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);\n    },\n\n    _dashedQuadraticTo: function (x1, y1, x2, y2) {\n        // Convert quadratic to cubic using degree elevation\n        var x3 = x2;\n        var y3 = y2;\n        x2 = (x2 + 2 * x1) / 3;\n        y2 = (y2 + 2 * y1) / 3;\n        x1 = (this._xi + 2 * x1) / 3;\n        y1 = (this._yi + 2 * y1) / 3;\n\n        this._dashedBezierTo(x1, y1, x2, y2, x3, y3);\n    },\n\n    /**\n     * 转成静态的 Float32Array 减少堆内存占用\n     * Convert dynamic array to static Float32Array\n     */\n    toStatic: function () {\n        var data = this.data;\n        if (data instanceof Array) {\n            data.length = this._len;\n            if (hasTypedArray) {\n                this.data = new Float32Array(data);\n            }\n        }\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function () {\n        min$1[0] = min$1[1] = min2[0] = min2[1] = Number.MAX_VALUE;\n        max$1[0] = max$1[1] = max2[0] = max2[1] = -Number.MAX_VALUE;\n\n        var data = this.data;\n        var xi = 0;\n        var yi = 0;\n        var x0 = 0;\n        var y0 = 0;\n\n        for (var i = 0; i < data.length;) {\n            var cmd = data[i++];\n\n            if (i === 1) {\n                // 如果第一个命令是 L, C, Q\n                // 则 previous point 同绘制命令的第一个 point\n                //\n                // 第一个命令为 Arc 的情况下会在后面特殊处理\n                xi = data[i];\n                yi = data[i + 1];\n\n                x0 = xi;\n                y0 = yi;\n            }\n\n            switch (cmd) {\n                case CMD.M:\n                    // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点\n                    // 在 closePath 的时候使用\n                    x0 = data[i++];\n                    y0 = data[i++];\n                    xi = x0;\n                    yi = y0;\n                    min2[0] = x0;\n                    min2[1] = y0;\n                    max2[0] = x0;\n                    max2[1] = y0;\n                    break;\n                case CMD.L:\n                    fromLine(xi, yi, data[i], data[i + 1], min2, max2);\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.C:\n                    fromCubic(\n                        xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        min2, max2\n                    );\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.Q:\n                    fromQuadratic(\n                        xi, yi, data[i++], data[i++], data[i], data[i + 1],\n                        min2, max2\n                    );\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.A:\n                    // TODO Arc 判断的开销比较大\n                    var cx = data[i++];\n                    var cy = data[i++];\n                    var rx = data[i++];\n                    var ry = data[i++];\n                    var startAngle = data[i++];\n                    var endAngle = data[i++] + startAngle;\n                    // TODO Arc 旋转\n                    i += 1;\n                    var anticlockwise = 1 - data[i++];\n\n                    if (i === 1) {\n                        // 直接使用 arc 命令\n                        // 第一个命令起点还未定义\n                        x0 = mathCos$1(startAngle) * rx + cx;\n                        y0 = mathSin$1(startAngle) * ry + cy;\n                    }\n\n                    fromArc(\n                        cx, cy, rx, ry, startAngle, endAngle,\n                        anticlockwise, min2, max2\n                    );\n\n                    xi = mathCos$1(endAngle) * rx + cx;\n                    yi = mathSin$1(endAngle) * ry + cy;\n                    break;\n                case CMD.R:\n                    x0 = xi = data[i++];\n                    y0 = yi = data[i++];\n                    var width = data[i++];\n                    var height = data[i++];\n                    // Use fromLine\n                    fromLine(x0, y0, x0 + width, y0 + height, min2, max2);\n                    break;\n                case CMD.Z:\n                    xi = x0;\n                    yi = y0;\n                    break;\n            }\n\n            // Union\n            min(min$1, min$1, min2);\n            max(max$1, max$1, max2);\n        }\n\n        // No data\n        if (i === 0) {\n            min$1[0] = min$1[1] = max$1[0] = max$1[1] = 0;\n        }\n\n        return new BoundingRect(\n            min$1[0], min$1[1], max$1[0] - min$1[0], max$1[1] - min$1[1]\n        );\n    },\n\n    /**\n     * Rebuild path from current data\n     * Rebuild path will not consider javascript implemented line dash.\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    rebuildPath: function (ctx) {\n        var d = this.data;\n        var x0, y0;\n        var xi, yi;\n        var x, y;\n        var ux = this._ux;\n        var uy = this._uy;\n        var len$$1 = this._len;\n        for (var i = 0; i < len$$1;) {\n            var cmd = d[i++];\n\n            if (i === 1) {\n                // 如果第一个命令是 L, C, Q\n                // 则 previous point 同绘制命令的第一个 point\n                //\n                // 第一个命令为 Arc 的情况下会在后面特殊处理\n                xi = d[i];\n                yi = d[i + 1];\n\n                x0 = xi;\n                y0 = yi;\n            }\n            switch (cmd) {\n                case CMD.M:\n                    x0 = xi = d[i++];\n                    y0 = yi = d[i++];\n                    ctx.moveTo(xi, yi);\n                    break;\n                case CMD.L:\n                    x = d[i++];\n                    y = d[i++];\n                    // Not draw too small seg between\n                    if (mathAbs(x - xi) > ux || mathAbs(y - yi) > uy || i === len$$1 - 1) {\n                        ctx.lineTo(x, y);\n                        xi = x;\n                        yi = y;\n                    }\n                    break;\n                case CMD.C:\n                    ctx.bezierCurveTo(\n                        d[i++], d[i++], d[i++], d[i++], d[i++], d[i++]\n                    );\n                    xi = d[i - 2];\n                    yi = d[i - 1];\n                    break;\n                case CMD.Q:\n                    ctx.quadraticCurveTo(d[i++], d[i++], d[i++], d[i++]);\n                    xi = d[i - 2];\n                    yi = d[i - 1];\n                    break;\n                case CMD.A:\n                    var cx = d[i++];\n                    var cy = d[i++];\n                    var rx = d[i++];\n                    var ry = d[i++];\n                    var theta = d[i++];\n                    var dTheta = d[i++];\n                    var psi = d[i++];\n                    var fs = d[i++];\n                    var r = (rx > ry) ? rx : ry;\n                    var scaleX = (rx > ry) ? 1 : rx / ry;\n                    var scaleY = (rx > ry) ? ry / rx : 1;\n                    var isEllipse = Math.abs(rx - ry) > 1e-3;\n                    var endAngle = theta + dTheta;\n                    if (isEllipse) {\n                        ctx.translate(cx, cy);\n                        ctx.rotate(psi);\n                        ctx.scale(scaleX, scaleY);\n                        ctx.arc(0, 0, r, theta, endAngle, 1 - fs);\n                        ctx.scale(1 / scaleX, 1 / scaleY);\n                        ctx.rotate(-psi);\n                        ctx.translate(-cx, -cy);\n                    }\n                    else {\n                        ctx.arc(cx, cy, r, theta, endAngle, 1 - fs);\n                    }\n\n                    if (i === 1) {\n                        // 直接使用 arc 命令\n                        // 第一个命令起点还未定义\n                        x0 = mathCos$1(theta) * rx + cx;\n                        y0 = mathSin$1(theta) * ry + cy;\n                    }\n                    xi = mathCos$1(endAngle) * rx + cx;\n                    yi = mathSin$1(endAngle) * ry + cy;\n                    break;\n                case CMD.R:\n                    x0 = xi = d[i];\n                    y0 = yi = d[i + 1];\n                    ctx.rect(d[i++], d[i++], d[i++], d[i++]);\n                    break;\n                case CMD.Z:\n                    ctx.closePath();\n                    xi = x0;\n                    yi = y0;\n            }\n        }\n    }\n};\n\nPathProxy.CMD = CMD;\n\n/**\n * 线段包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$1(x0, y0, x1, y1, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    var _a = 0;\n    var _b = x0;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l)\n        || (y < y0 - _l && y < y1 - _l)\n        || (x > x0 + _l && x > x1 + _l)\n        || (x < x0 - _l && x < x1 - _l)\n    ) {\n        return false;\n    }\n\n    if (x0 !== x1) {\n        _a = (y0 - y1) / (x0 - x1);\n        _b = (x0 * y1 - x1 * y0) / (x0 - x1);\n    }\n    else {\n        return Math.abs(x - x0) <= _l / 2;\n    }\n    var tmp = _a * x - y + _b;\n    var _s = tmp * tmp / (_a * _a + 1);\n    return _s <= _l / 2 * _l / 2;\n}\n\n/**\n * 三次贝塞尔曲线描边包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  x2\n * @param  {number}  y2\n * @param  {number}  x3\n * @param  {number}  y3\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$2(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l)\n        || (y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l)\n        || (x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l)\n        || (x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l)\n    ) {\n        return false;\n    }\n    var d = cubicProjectPoint(\n        x0, y0, x1, y1, x2, y2, x3, y3,\n        x, y, null\n    );\n    return d <= _l / 2;\n}\n\n/**\n * 二次贝塞尔曲线描边包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  x2\n * @param  {number}  y2\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$3(x0, y0, x1, y1, x2, y2, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l && y > y2 + _l)\n        || (y < y0 - _l && y < y1 - _l && y < y2 - _l)\n        || (x > x0 + _l && x > x1 + _l && x > x2 + _l)\n        || (x < x0 - _l && x < x1 - _l && x < x2 - _l)\n    ) {\n        return false;\n    }\n    var d = quadraticProjectPoint(\n        x0, y0, x1, y1, x2, y2,\n        x, y, null\n    );\n    return d <= _l / 2;\n}\n\nvar PI2$3 = Math.PI * 2;\n\nfunction normalizeRadian(angle) {\n    angle %= PI2$3;\n    if (angle < 0) {\n        angle += PI2$3;\n    }\n    return angle;\n}\n\nvar PI2$2 = Math.PI * 2;\n\n/**\n * 圆弧描边包含判断\n * @param  {number}  cx\n * @param  {number}  cy\n * @param  {number}  r\n * @param  {number}  startAngle\n * @param  {number}  endAngle\n * @param  {boolean}  anticlockwise\n * @param  {number} lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {Boolean}\n */\nfunction containStroke$4(\n    cx, cy, r, startAngle, endAngle, anticlockwise,\n    lineWidth, x, y\n) {\n\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n\n    x -= cx;\n    y -= cy;\n    var d = Math.sqrt(x * x + y * y);\n\n    if ((d - _l > r) || (d + _l < r)) {\n        return false;\n    }\n    if (Math.abs(startAngle - endAngle) % PI2$2 < 1e-4) {\n        // Is a circle\n        return true;\n    }\n    if (anticlockwise) {\n        var tmp = startAngle;\n        startAngle = normalizeRadian(endAngle);\n        endAngle = normalizeRadian(tmp);\n    }\n    else {\n        startAngle = normalizeRadian(startAngle);\n        endAngle = normalizeRadian(endAngle);\n    }\n    if (startAngle > endAngle) {\n        endAngle += PI2$2;\n    }\n\n    var angle = Math.atan2(y, x);\n    if (angle < 0) {\n        angle += PI2$2;\n    }\n    return (angle >= startAngle && angle <= endAngle)\n        || (angle + PI2$2 >= startAngle && angle + PI2$2 <= endAngle);\n}\n\nfunction windingLine(x0, y0, x1, y1, x, y) {\n    if ((y > y0 && y > y1) || (y < y0 && y < y1)) {\n        return 0;\n    }\n    // Ignore horizontal line\n    if (y1 === y0) {\n        return 0;\n    }\n    var dir = y1 < y0 ? 1 : -1;\n    var t = (y - y0) / (y1 - y0);\n\n    // Avoid winding error when intersection point is the connect point of two line of polygon\n    if (t === 1 || t === 0) {\n        dir = y1 < y0 ? 0.5 : -0.5;\n    }\n\n    var x_ = t * (x1 - x0) + x0;\n\n    // If (x, y) on the line, considered as \"contain\".\n    return x_ === x ? Infinity : x_ > x ? dir : 0;\n}\n\nvar CMD$1 = PathProxy.CMD;\nvar PI2$1 = Math.PI * 2;\n\nvar EPSILON$2 = 1e-4;\n\nfunction isAroundEqual(a, b) {\n    return Math.abs(a - b) < EPSILON$2;\n}\n\n// 临时数组\nvar roots = [-1, -1, -1];\nvar extrema = [-1, -1];\n\nfunction swapExtrema() {\n    var tmp = extrema[0];\n    extrema[0] = extrema[1];\n    extrema[1] = tmp;\n}\n\nfunction windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {\n    // Quick reject\n    if (\n        (y > y0 && y > y1 && y > y2 && y > y3)\n        || (y < y0 && y < y1 && y < y2 && y < y3)\n    ) {\n        return 0;\n    }\n    var nRoots = cubicRootAt(y0, y1, y2, y3, y, roots);\n    if (nRoots === 0) {\n        return 0;\n    }\n    else {\n        var w = 0;\n        var nExtrema = -1;\n        var y0_;\n        var y1_;\n        for (var i = 0; i < nRoots; i++) {\n            var t = roots[i];\n\n            // Avoid winding error when intersection point is the connect point of two line of polygon\n            var unit = (t === 0 || t === 1) ? 0.5 : 1;\n\n            var x_ = cubicAt(x0, x1, x2, x3, t);\n            if (x_ < x) { // Quick reject\n                continue;\n            }\n            if (nExtrema < 0) {\n                nExtrema = cubicExtrema(y0, y1, y2, y3, extrema);\n                if (extrema[1] < extrema[0] && nExtrema > 1) {\n                    swapExtrema();\n                }\n                y0_ = cubicAt(y0, y1, y2, y3, extrema[0]);\n                if (nExtrema > 1) {\n                    y1_ = cubicAt(y0, y1, y2, y3, extrema[1]);\n                }\n            }\n            if (nExtrema === 2) {\n                // 分成三段单调函数\n                if (t < extrema[0]) {\n                    w += y0_ < y0 ? unit : -unit;\n                }\n                else if (t < extrema[1]) {\n                    w += y1_ < y0_ ? unit : -unit;\n                }\n                else {\n                    w += y3 < y1_ ? unit : -unit;\n                }\n            }\n            else {\n                // 分成两段单调函数\n                if (t < extrema[0]) {\n                    w += y0_ < y0 ? unit : -unit;\n                }\n                else {\n                    w += y3 < y0_ ? unit : -unit;\n                }\n            }\n        }\n        return w;\n    }\n}\n\nfunction windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {\n    // Quick reject\n    if (\n        (y > y0 && y > y1 && y > y2)\n        || (y < y0 && y < y1 && y < y2)\n    ) {\n        return 0;\n    }\n    var nRoots = quadraticRootAt(y0, y1, y2, y, roots);\n    if (nRoots === 0) {\n        return 0;\n    }\n    else {\n        var t = quadraticExtremum(y0, y1, y2);\n        if (t >= 0 && t <= 1) {\n            var w = 0;\n            var y_ = quadraticAt(y0, y1, y2, t);\n            for (var i = 0; i < nRoots; i++) {\n                // Remove one endpoint.\n                var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1;\n\n                var x_ = quadraticAt(x0, x1, x2, roots[i]);\n                if (x_ < x) {   // Quick reject\n                    continue;\n                }\n                if (roots[i] < t) {\n                    w += y_ < y0 ? unit : -unit;\n                }\n                else {\n                    w += y2 < y_ ? unit : -unit;\n                }\n            }\n            return w;\n        }\n        else {\n            // Remove one endpoint.\n            var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1;\n\n            var x_ = quadraticAt(x0, x1, x2, roots[0]);\n            if (x_ < x) {   // Quick reject\n                return 0;\n            }\n            return y2 < y0 ? unit : -unit;\n        }\n    }\n}\n\n// TODO\n// Arc 旋转\nfunction windingArc(\n    cx, cy, r, startAngle, endAngle, anticlockwise, x, y\n) {\n    y -= cy;\n    if (y > r || y < -r) {\n        return 0;\n    }\n    var tmp = Math.sqrt(r * r - y * y);\n    roots[0] = -tmp;\n    roots[1] = tmp;\n\n    var diff = Math.abs(startAngle - endAngle);\n    if (diff < 1e-4) {\n        return 0;\n    }\n    if (diff % PI2$1 < 1e-4) {\n        // Is a circle\n        startAngle = 0;\n        endAngle = PI2$1;\n        var dir = anticlockwise ? 1 : -1;\n        if (x >= roots[0] + cx && x <= roots[1] + cx) {\n            return dir;\n        }\n        else {\n            return 0;\n        }\n    }\n\n    if (anticlockwise) {\n        var tmp = startAngle;\n        startAngle = normalizeRadian(endAngle);\n        endAngle = normalizeRadian(tmp);\n    }\n    else {\n        startAngle = normalizeRadian(startAngle);\n        endAngle = normalizeRadian(endAngle);\n    }\n    if (startAngle > endAngle) {\n        endAngle += PI2$1;\n    }\n\n    var w = 0;\n    for (var i = 0; i < 2; i++) {\n        var x_ = roots[i];\n        if (x_ + cx > x) {\n            var angle = Math.atan2(y, x_);\n            var dir = anticlockwise ? 1 : -1;\n            if (angle < 0) {\n                angle = PI2$1 + angle;\n            }\n            if (\n                (angle >= startAngle && angle <= endAngle)\n                || (angle + PI2$1 >= startAngle && angle + PI2$1 <= endAngle)\n            ) {\n                if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {\n                    dir = -dir;\n                }\n                w += dir;\n            }\n        }\n    }\n    return w;\n}\n\nfunction containPath(data, lineWidth, isStroke, x, y) {\n    var w = 0;\n    var xi = 0;\n    var yi = 0;\n    var x0 = 0;\n    var y0 = 0;\n\n    for (var i = 0; i < data.length;) {\n        var cmd = data[i++];\n        // Begin a new subpath\n        if (cmd === CMD$1.M && i > 1) {\n            // Close previous subpath\n            if (!isStroke) {\n                w += windingLine(xi, yi, x0, y0, x, y);\n            }\n            // 如果被任何一个 subpath 包含\n            // if (w !== 0) {\n            //     return true;\n            // }\n        }\n\n        if (i === 1) {\n            // 如果第一个命令是 L, C, Q\n            // 则 previous point 同绘制命令的第一个 point\n            //\n            // 第一个命令为 Arc 的情况下会在后面特殊处理\n            xi = data[i];\n            yi = data[i + 1];\n\n            x0 = xi;\n            y0 = yi;\n        }\n\n        switch (cmd) {\n            case CMD$1.M:\n                // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点\n                // 在 closePath 的时候使用\n                x0 = data[i++];\n                y0 = data[i++];\n                xi = x0;\n                yi = y0;\n                break;\n            case CMD$1.L:\n                if (isStroke) {\n                    if (containStroke$1(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {\n                        return true;\n                    }\n                }\n                else {\n                    // NOTE 在第一个命令为 L, C, Q 的时候会计算出 NaN\n                    w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.C:\n                if (isStroke) {\n                    if (containStroke$2(xi, yi,\n                        data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingCubic(\n                        xi, yi,\n                        data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        x, y\n                    ) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.Q:\n                if (isStroke) {\n                    if (containStroke$3(xi, yi,\n                        data[i++], data[i++], data[i], data[i + 1],\n                        lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingQuadratic(\n                        xi, yi,\n                        data[i++], data[i++], data[i], data[i + 1],\n                        x, y\n                    ) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.A:\n                // TODO Arc 判断的开销比较大\n                var cx = data[i++];\n                var cy = data[i++];\n                var rx = data[i++];\n                var ry = data[i++];\n                var theta = data[i++];\n                var dTheta = data[i++];\n                // TODO Arc 旋转\n                i += 1;\n                var anticlockwise = 1 - data[i++];\n                var x1 = Math.cos(theta) * rx + cx;\n                var y1 = Math.sin(theta) * ry + cy;\n                // 不是直接使用 arc 命令\n                if (i > 1) {\n                    w += windingLine(xi, yi, x1, y1, x, y);\n                }\n                else {\n                    // 第一个命令起点还未定义\n                    x0 = x1;\n                    y0 = y1;\n                }\n                // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放\n                var _x = (x - cx) * ry / rx + cx;\n                if (isStroke) {\n                    if (containStroke$4(\n                        cx, cy, ry, theta, theta + dTheta, anticlockwise,\n                        lineWidth, _x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingArc(\n                        cx, cy, ry, theta, theta + dTheta, anticlockwise,\n                        _x, y\n                    );\n                }\n                xi = Math.cos(theta + dTheta) * rx + cx;\n                yi = Math.sin(theta + dTheta) * ry + cy;\n                break;\n            case CMD$1.R:\n                x0 = xi = data[i++];\n                y0 = yi = data[i++];\n                var width = data[i++];\n                var height = data[i++];\n                var x1 = x0 + width;\n                var y1 = y0 + height;\n                if (isStroke) {\n                    if (containStroke$1(x0, y0, x1, y0, lineWidth, x, y)\n                        || containStroke$1(x1, y0, x1, y1, lineWidth, x, y)\n                        || containStroke$1(x1, y1, x0, y1, lineWidth, x, y)\n                        || containStroke$1(x0, y1, x0, y0, lineWidth, x, y)\n                    ) {\n                        return true;\n                    }\n                }\n                else {\n                    // FIXME Clockwise ?\n                    w += windingLine(x1, y0, x1, y1, x, y);\n                    w += windingLine(x0, y1, x0, y0, x, y);\n                }\n                break;\n            case CMD$1.Z:\n                if (isStroke) {\n                    if (containStroke$1(\n                        xi, yi, x0, y0, lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    // Close a subpath\n                    w += windingLine(xi, yi, x0, y0, x, y);\n                    // 如果被任何一个 subpath 包含\n                    // FIXME subpaths may overlap\n                    // if (w !== 0) {\n                    //     return true;\n                    // }\n                }\n                xi = x0;\n                yi = y0;\n                break;\n        }\n    }\n    if (!isStroke && !isAroundEqual(yi, y0)) {\n        w += windingLine(xi, yi, x0, y0, x, y) || 0;\n    }\n    return w !== 0;\n}\n\nfunction contain(pathData, x, y) {\n    return containPath(pathData, 0, false, x, y);\n}\n\nfunction containStroke(pathData, lineWidth, x, y) {\n    return containPath(pathData, lineWidth, true, x, y);\n}\n\nvar getCanvasPattern = Pattern.prototype.getCanvasPattern;\n\nvar abs = Math.abs;\n\nvar pathProxyForDraw = new PathProxy(true);\n/**\n * @alias module:zrender/graphic/Path\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nfunction Path(opts) {\n    Displayable.call(this, opts);\n\n    /**\n     * @type {module:zrender/core/PathProxy}\n     * @readOnly\n     */\n    this.path = null;\n}\n\nPath.prototype = {\n\n    constructor: Path,\n\n    type: 'path',\n\n    __dirtyPath: true,\n\n    strokeContainThreshold: 5,\n\n    /**\n     * See `module:zrender/src/graphic/helper/subPixelOptimize`.\n     * @type {boolean}\n     */\n    subPixelOptimize: false,\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n        var path = this.path || pathProxyForDraw;\n        var hasStroke = style.hasStroke();\n        var hasFill = style.hasFill();\n        var fill = style.fill;\n        var stroke = style.stroke;\n        var hasFillGradient = hasFill && !!(fill.colorStops);\n        var hasStrokeGradient = hasStroke && !!(stroke.colorStops);\n        var hasFillPattern = hasFill && !!(fill.image);\n        var hasStrokePattern = hasStroke && !!(stroke.image);\n\n        style.bind(ctx, this, prevEl);\n        this.setTransform(ctx);\n\n        if (this.__dirty) {\n            var rect;\n            // Update gradient because bounding rect may changed\n            if (hasFillGradient) {\n                rect = rect || this.getBoundingRect();\n                this._fillGradient = style.getGradient(ctx, fill, rect);\n            }\n            if (hasStrokeGradient) {\n                rect = rect || this.getBoundingRect();\n                this._strokeGradient = style.getGradient(ctx, stroke, rect);\n            }\n        }\n        // Use the gradient or pattern\n        if (hasFillGradient) {\n            // PENDING If may have affect the state\n            ctx.fillStyle = this._fillGradient;\n        }\n        else if (hasFillPattern) {\n            ctx.fillStyle = getCanvasPattern.call(fill, ctx);\n        }\n        if (hasStrokeGradient) {\n            ctx.strokeStyle = this._strokeGradient;\n        }\n        else if (hasStrokePattern) {\n            ctx.strokeStyle = getCanvasPattern.call(stroke, ctx);\n        }\n\n        var lineDash = style.lineDash;\n        var lineDashOffset = style.lineDashOffset;\n\n        var ctxLineDash = !!ctx.setLineDash;\n\n        // Update path sx, sy\n        var scale = this.getGlobalScale();\n        path.setScale(scale[0], scale[1]);\n\n        // Proxy context\n        // Rebuild path in following 2 cases\n        // 1. Path is dirty\n        // 2. Path needs javascript implemented lineDash stroking.\n        //    In this case, lineDash information will not be saved in PathProxy\n        if (this.__dirtyPath\n            || (lineDash && !ctxLineDash && hasStroke)\n        ) {\n            path.beginPath(ctx);\n\n            // Setting line dash before build path\n            if (lineDash && !ctxLineDash) {\n                path.setLineDash(lineDash);\n                path.setLineDashOffset(lineDashOffset);\n            }\n\n            this.buildPath(path, this.shape, false);\n\n            // Clear path dirty flag\n            if (this.path) {\n                this.__dirtyPath = false;\n            }\n        }\n        else {\n            // Replay path building\n            ctx.beginPath();\n            this.path.rebuildPath(ctx);\n        }\n\n        if (hasFill) {\n            if (style.fillOpacity != null) {\n                var originalGlobalAlpha = ctx.globalAlpha;\n                ctx.globalAlpha = style.fillOpacity * style.opacity;\n                path.fill(ctx);\n                ctx.globalAlpha = originalGlobalAlpha;\n            }\n            else {\n                path.fill(ctx);\n            }\n        }\n\n        if (lineDash && ctxLineDash) {\n            ctx.setLineDash(lineDash);\n            ctx.lineDashOffset = lineDashOffset;\n        }\n\n        if (hasStroke) {\n            if (style.strokeOpacity != null) {\n                var originalGlobalAlpha = ctx.globalAlpha;\n                ctx.globalAlpha = style.strokeOpacity * style.opacity;\n                path.stroke(ctx);\n                ctx.globalAlpha = originalGlobalAlpha;\n            }\n            else {\n                path.stroke(ctx);\n            }\n        }\n\n        if (lineDash && ctxLineDash) {\n            // PENDING\n            // Remove lineDash\n            ctx.setLineDash([]);\n        }\n\n        // Draw rect text\n        if (style.text != null) {\n            // Only restore transform when needs draw text.\n            this.restoreTransform(ctx);\n            this.drawRectText(ctx, this.getBoundingRect());\n        }\n    },\n\n    // When bundling path, some shape may decide if use moveTo to begin a new subpath or closePath\n    // Like in circle\n    buildPath: function (ctx, shapeCfg, inBundle) {},\n\n    createPathProxy: function () {\n        this.path = new PathProxy();\n    },\n\n    getBoundingRect: function () {\n        var rect = this._rect;\n        var style = this.style;\n        var needsUpdateRect = !rect;\n        if (needsUpdateRect) {\n            var path = this.path;\n            if (!path) {\n                // Create path on demand.\n                path = this.path = new PathProxy();\n            }\n            if (this.__dirtyPath) {\n                path.beginPath();\n                this.buildPath(path, this.shape, false);\n            }\n            rect = path.getBoundingRect();\n        }\n        this._rect = rect;\n\n        if (style.hasStroke()) {\n            // Needs update rect with stroke lineWidth when\n            // 1. Element changes scale or lineWidth\n            // 2. Shape is changed\n            var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone());\n            if (this.__dirty || needsUpdateRect) {\n                rectWithStroke.copy(rect);\n                // FIXME Must after updateTransform\n                var w = style.lineWidth;\n                // PENDING, Min line width is needed when line is horizontal or vertical\n                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;\n\n                // Only add extra hover lineWidth when there are no fill\n                if (!style.hasFill()) {\n                    w = Math.max(w, this.strokeContainThreshold || 4);\n                }\n                // Consider line width\n                // Line scale can't be 0;\n                if (lineScale > 1e-10) {\n                    rectWithStroke.width += w / lineScale;\n                    rectWithStroke.height += w / lineScale;\n                    rectWithStroke.x -= w / lineScale / 2;\n                    rectWithStroke.y -= w / lineScale / 2;\n                }\n            }\n\n            // Return rect with stroke\n            return rectWithStroke;\n        }\n\n        return rect;\n    },\n\n    contain: function (x, y) {\n        var localPos = this.transformCoordToLocal(x, y);\n        var rect = this.getBoundingRect();\n        var style = this.style;\n        x = localPos[0];\n        y = localPos[1];\n\n        if (rect.contain(x, y)) {\n            var pathData = this.path.data;\n            if (style.hasStroke()) {\n                var lineWidth = style.lineWidth;\n                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;\n                // Line scale can't be 0;\n                if (lineScale > 1e-10) {\n                    // Only add extra hover lineWidth when there are no fill\n                    if (!style.hasFill()) {\n                        lineWidth = Math.max(lineWidth, this.strokeContainThreshold);\n                    }\n                    if (containStroke(\n                        pathData, lineWidth / lineScale, x, y\n                    )) {\n                        return true;\n                    }\n                }\n            }\n            if (style.hasFill()) {\n                return contain(pathData, x, y);\n            }\n        }\n        return false;\n    },\n\n    /**\n     * @param  {boolean} dirtyPath\n     */\n    dirty: function (dirtyPath) {\n        if (dirtyPath == null) {\n            dirtyPath = true;\n        }\n        // Only mark dirty, not mark clean\n        if (dirtyPath) {\n            this.__dirtyPath = dirtyPath;\n            this._rect = null;\n        }\n\n        this.__dirty = this.__dirtyText = true;\n\n        this.__zr && this.__zr.refresh();\n\n        // Used as a clipping path\n        if (this.__clipTarget) {\n            this.__clipTarget.dirty();\n        }\n    },\n\n    /**\n     * Alias for animate('shape')\n     * @param {boolean} loop\n     */\n    animateShape: function (loop) {\n        return this.animate('shape', loop);\n    },\n\n    // Overwrite attrKV\n    attrKV: function (key, value) {\n        // FIXME\n        if (key === 'shape') {\n            this.setShape(value);\n            this.__dirtyPath = true;\n            this._rect = null;\n        }\n        else {\n            Displayable.prototype.attrKV.call(this, key, value);\n        }\n    },\n\n    /**\n     * @param {Object|string} key\n     * @param {*} value\n     */\n    setShape: function (key, value) {\n        var shape = this.shape;\n        // Path from string may not have shape\n        if (shape) {\n            if (isObject$1(key)) {\n                for (var name in key) {\n                    if (key.hasOwnProperty(name)) {\n                        shape[name] = key[name];\n                    }\n                }\n            }\n            else {\n                shape[key] = value;\n            }\n            this.dirty(true);\n        }\n        return this;\n    },\n\n    getLineScale: function () {\n        var m = this.transform;\n        // Get the line scale.\n        // Determinant of `m` means how much the area is enlarged by the\n        // transformation. So its square root can be used as a scale factor\n        // for width.\n        return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10\n            ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1]))\n            : 1;\n    }\n};\n\n/**\n * 扩展一个 Path element, 比如星形，圆等。\n * Extend a path element\n * @param {Object} props\n * @param {string} props.type Path type\n * @param {Function} props.init Initialize\n * @param {Function} props.buildPath Overwrite buildPath method\n * @param {Object} [props.style] Extended default style config\n * @param {Object} [props.shape] Extended default shape config\n */\nPath.extend = function (defaults$$1) {\n    var Sub = function (opts) {\n        Path.call(this, opts);\n\n        if (defaults$$1.style) {\n            // Extend default style\n            this.style.extendFrom(defaults$$1.style, false);\n        }\n\n        // Extend default shape\n        var defaultShape = defaults$$1.shape;\n        if (defaultShape) {\n            this.shape = this.shape || {};\n            var thisShape = this.shape;\n            for (var name in defaultShape) {\n                if (\n                    !thisShape.hasOwnProperty(name)\n                    && defaultShape.hasOwnProperty(name)\n                ) {\n                    thisShape[name] = defaultShape[name];\n                }\n            }\n        }\n\n        defaults$$1.init && defaults$$1.init.call(this, opts);\n    };\n\n    inherits(Sub, Path);\n\n    // FIXME 不能 extend position, rotation 等引用对象\n    for (var name in defaults$$1) {\n        // Extending prototype values and methods\n        if (name !== 'style' && name !== 'shape') {\n            Sub.prototype[name] = defaults$$1[name];\n        }\n    }\n\n    return Sub;\n};\n\ninherits(Path, Displayable);\n\nvar CMD$2 = PathProxy.CMD;\n\nvar points = [[], [], []];\nvar mathSqrt$3 = Math.sqrt;\nvar mathAtan2 = Math.atan2;\n\nvar transformPath = function (path, m) {\n    var data = path.data;\n    var cmd;\n    var nPoint;\n    var i;\n    var j;\n    var k;\n    var p;\n\n    var M = CMD$2.M;\n    var C = CMD$2.C;\n    var L = CMD$2.L;\n    var R = CMD$2.R;\n    var A = CMD$2.A;\n    var Q = CMD$2.Q;\n\n    for (i = 0, j = 0; i < data.length;) {\n        cmd = data[i++];\n        j = i;\n        nPoint = 0;\n\n        switch (cmd) {\n            case M:\n                nPoint = 1;\n                break;\n            case L:\n                nPoint = 1;\n                break;\n            case C:\n                nPoint = 3;\n                break;\n            case Q:\n                nPoint = 2;\n                break;\n            case A:\n                var x = m[4];\n                var y = m[5];\n                var sx = mathSqrt$3(m[0] * m[0] + m[1] * m[1]);\n                var sy = mathSqrt$3(m[2] * m[2] + m[3] * m[3]);\n                var angle = mathAtan2(-m[1] / sy, m[0] / sx);\n                // cx\n                data[i] *= sx;\n                data[i++] += x;\n                // cy\n                data[i] *= sy;\n                data[i++] += y;\n                // Scale rx and ry\n                // FIXME Assume psi is 0 here\n                data[i++] *= sx;\n                data[i++] *= sy;\n\n                // Start angle\n                data[i++] += angle;\n                // end angle\n                data[i++] += angle;\n                // FIXME psi\n                i += 2;\n                j = i;\n                break;\n            case R:\n                // x0, y0\n                p[0] = data[i++];\n                p[1] = data[i++];\n                applyTransform(p, p, m);\n                data[j++] = p[0];\n                data[j++] = p[1];\n                // x1, y1\n                p[0] += data[i++];\n                p[1] += data[i++];\n                applyTransform(p, p, m);\n                data[j++] = p[0];\n                data[j++] = p[1];\n        }\n\n        for (k = 0; k < nPoint; k++) {\n            var p = points[k];\n            p[0] = data[i++];\n            p[1] = data[i++];\n\n            applyTransform(p, p, m);\n            // Write back\n            data[j++] = p[0];\n            data[j++] = p[1];\n        }\n    }\n};\n\n// command chars\n// var cc = [\n//     'm', 'M', 'l', 'L', 'v', 'V', 'h', 'H', 'z', 'Z',\n//     'c', 'C', 'q', 'Q', 't', 'T', 's', 'S', 'a', 'A'\n// ];\n\nvar mathSqrt = Math.sqrt;\nvar mathSin = Math.sin;\nvar mathCos = Math.cos;\nvar PI = Math.PI;\n\nvar vMag = function (v) {\n    return Math.sqrt(v[0] * v[0] + v[1] * v[1]);\n};\nvar vRatio = function (u, v) {\n    return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));\n};\nvar vAngle = function (u, v) {\n    return (u[0] * v[1] < u[1] * v[0] ? -1 : 1)\n            * Math.acos(vRatio(u, v));\n};\n\nfunction processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) {\n    var psi = psiDeg * (PI / 180.0);\n    var xp = mathCos(psi) * (x1 - x2) / 2.0\n                + mathSin(psi) * (y1 - y2) / 2.0;\n    var yp = -1 * mathSin(psi) * (x1 - x2) / 2.0\n                + mathCos(psi) * (y1 - y2) / 2.0;\n\n    var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);\n\n    if (lambda > 1) {\n        rx *= mathSqrt(lambda);\n        ry *= mathSqrt(lambda);\n    }\n\n    var f = (fa === fs ? -1 : 1)\n        * mathSqrt((((rx * rx) * (ry * ry))\n                - ((rx * rx) * (yp * yp))\n                - ((ry * ry) * (xp * xp))) / ((rx * rx) * (yp * yp)\n                + (ry * ry) * (xp * xp))\n            ) || 0;\n\n    var cxp = f * rx * yp / ry;\n    var cyp = f * -ry * xp / rx;\n\n    var cx = (x1 + x2) / 2.0\n                + mathCos(psi) * cxp\n                - mathSin(psi) * cyp;\n    var cy = (y1 + y2) / 2.0\n            + mathSin(psi) * cxp\n            + mathCos(psi) * cyp;\n\n    var theta = vAngle([ 1, 0 ], [ (xp - cxp) / rx, (yp - cyp) / ry ]);\n    var u = [ (xp - cxp) / rx, (yp - cyp) / ry ];\n    var v = [ (-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry ];\n    var dTheta = vAngle(u, v);\n\n    if (vRatio(u, v) <= -1) {\n        dTheta = PI;\n    }\n    if (vRatio(u, v) >= 1) {\n        dTheta = 0;\n    }\n    if (fs === 0 && dTheta > 0) {\n        dTheta = dTheta - 2 * PI;\n    }\n    if (fs === 1 && dTheta < 0) {\n        dTheta = dTheta + 2 * PI;\n    }\n\n    path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs);\n}\n\n\nvar commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig;\n// Consider case:\n// (1) delimiter can be comma or space, where continuous commas\n// or spaces should be seen as one comma.\n// (2) value can be like:\n// '2e-4', 'l.5.9' (ignore 0), 'M-10-10', 'l-2.43e-1,34.9983',\n// 'l-.5E1,54', '121-23-44-11' (no delimiter)\nvar numberReg = /-?([0-9]*\\.)?[0-9]+([eE]-?[0-9]+)?/g;\n// var valueSplitReg = /[\\s,]+/;\n\nfunction createPathProxyFromString(data) {\n    if (!data) {\n        return new PathProxy();\n    }\n\n    // var data = data.replace(/-/g, ' -')\n    //     .replace(/  /g, ' ')\n    //     .replace(/ /g, ',')\n    //     .replace(/,,/g, ',');\n\n    // var n;\n    // create pipes so that we can split the data\n    // for (n = 0; n < cc.length; n++) {\n    //     cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]);\n    // }\n\n    // data = data.replace(/-/g, ',-');\n\n    // create array\n    // var arr = cs.split('|');\n    // init context point\n    var cpx = 0;\n    var cpy = 0;\n    var subpathX = cpx;\n    var subpathY = cpy;\n    var prevCmd;\n\n    var path = new PathProxy();\n    var CMD = PathProxy.CMD;\n\n    // commandReg.lastIndex = 0;\n    // var cmdResult;\n    // while ((cmdResult = commandReg.exec(data)) != null) {\n    //     var cmdStr = cmdResult[1];\n    //     var cmdContent = cmdResult[2];\n\n    var cmdList = data.match(commandReg);\n    for (var l = 0; l < cmdList.length; l++) {\n        var cmdText = cmdList[l];\n        var cmdStr = cmdText.charAt(0);\n\n        var cmd;\n\n        // String#split is faster a little bit than String#replace or RegExp#exec.\n        // var p = cmdContent.split(valueSplitReg);\n        // var pLen = 0;\n        // for (var i = 0; i < p.length; i++) {\n        //     // '' and other invalid str => NaN\n        //     var val = parseFloat(p[i]);\n        //     !isNaN(val) && (p[pLen++] = val);\n        // }\n\n        var p = cmdText.match(numberReg) || [];\n        var pLen = p.length;\n        for (var i = 0; i < pLen; i++) {\n            p[i] = parseFloat(p[i]);\n        }\n\n        var off = 0;\n        while (off < pLen) {\n            var ctlPtx;\n            var ctlPty;\n\n            var rx;\n            var ry;\n            var psi;\n            var fa;\n            var fs;\n\n            var x1 = cpx;\n            var y1 = cpy;\n\n            // convert l, H, h, V, and v to L\n            switch (cmdStr) {\n                case 'l':\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'L':\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'm':\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.M;\n                    path.addData(cmd, cpx, cpy);\n                    subpathX = cpx;\n                    subpathY = cpy;\n                    cmdStr = 'l';\n                    break;\n                case 'M':\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.M;\n                    path.addData(cmd, cpx, cpy);\n                    subpathX = cpx;\n                    subpathY = cpy;\n                    cmdStr = 'L';\n                    break;\n                case 'h':\n                    cpx += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'H':\n                    cpx = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'v':\n                    cpy += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'V':\n                    cpy = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'C':\n                    cmd = CMD.C;\n                    path.addData(\n                        cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]\n                    );\n                    cpx = p[off - 2];\n                    cpy = p[off - 1];\n                    break;\n                case 'c':\n                    cmd = CMD.C;\n                    path.addData(\n                        cmd,\n                        p[off++] + cpx, p[off++] + cpy,\n                        p[off++] + cpx, p[off++] + cpy,\n                        p[off++] + cpx, p[off++] + cpy\n                    );\n                    cpx += p[off - 2];\n                    cpy += p[off - 1];\n                    break;\n                case 'S':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.C) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cmd = CMD.C;\n                    x1 = p[off++];\n                    y1 = p[off++];\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);\n                    break;\n                case 's':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.C) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cmd = CMD.C;\n                    x1 = cpx + p[off++];\n                    y1 = cpy + p[off++];\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);\n                    break;\n                case 'Q':\n                    x1 = p[off++];\n                    y1 = p[off++];\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, x1, y1, cpx, cpy);\n                    break;\n                case 'q':\n                    x1 = p[off++] + cpx;\n                    y1 = p[off++] + cpy;\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, x1, y1, cpx, cpy);\n                    break;\n                case 'T':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.Q) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);\n                    break;\n                case 't':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.Q) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);\n                    break;\n                case 'A':\n                    rx = p[off++];\n                    ry = p[off++];\n                    psi = p[off++];\n                    fa = p[off++];\n                    fs = p[off++];\n\n                    x1 = cpx, y1 = cpy;\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.A;\n                    processArc(\n                        x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path\n                    );\n                    break;\n                case 'a':\n                    rx = p[off++];\n                    ry = p[off++];\n                    psi = p[off++];\n                    fa = p[off++];\n                    fs = p[off++];\n\n                    x1 = cpx, y1 = cpy;\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.A;\n                    processArc(\n                        x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path\n                    );\n                    break;\n            }\n        }\n\n        if (cmdStr === 'z' || cmdStr === 'Z') {\n            cmd = CMD.Z;\n            path.addData(cmd);\n            // z may be in the middle of the path.\n            cpx = subpathX;\n            cpy = subpathY;\n        }\n\n        prevCmd = cmd;\n    }\n\n    path.toStatic();\n\n    return path;\n}\n\n// TODO Optimize double memory cost problem\nfunction createPathOptions(str, opts) {\n    var pathProxy = createPathProxyFromString(str);\n    opts = opts || {};\n    opts.buildPath = function (path) {\n        if (path.setData) {\n            path.setData(pathProxy.data);\n            // Svg and vml renderer don't have context\n            var ctx = path.getContext();\n            if (ctx) {\n                path.rebuildPath(ctx);\n            }\n        }\n        else {\n            var ctx = path;\n            pathProxy.rebuildPath(ctx);\n        }\n    };\n\n    opts.applyTransform = function (m) {\n        transformPath(pathProxy, m);\n        this.dirty(true);\n    };\n\n    return opts;\n}\n\n/**\n * Create a Path object from path string data\n * http://www.w3.org/TR/SVG/paths.html#PathData\n * @param  {Object} opts Other options\n */\nfunction createFromString(str, opts) {\n    return new Path(createPathOptions(str, opts));\n}\n\n/**\n * Create a Path class from path string data\n * @param  {string} str\n * @param  {Object} opts Other options\n */\nfunction extendFromString(str, opts) {\n    return Path.extend(createPathOptions(str, opts));\n}\n\n/**\n * Merge multiple paths\n */\n// TODO Apply transform\n// TODO stroke dash\n// TODO Optimize double memory cost problem\nfunction mergePath$1(pathEls, opts) {\n    var pathList = [];\n    var len = pathEls.length;\n    for (var i = 0; i < len; i++) {\n        var pathEl = pathEls[i];\n        if (!pathEl.path) {\n            pathEl.createPathProxy();\n        }\n        if (pathEl.__dirtyPath) {\n            pathEl.buildPath(pathEl.path, pathEl.shape, true);\n        }\n        pathList.push(pathEl.path);\n    }\n\n    var pathBundle = new Path(opts);\n    // Need path proxy.\n    pathBundle.createPathProxy();\n    pathBundle.buildPath = function (path) {\n        path.appendPath(pathList);\n        // Svg and vml renderer don't have context\n        var ctx = path.getContext();\n        if (ctx) {\n            path.rebuildPath(ctx);\n        }\n    };\n\n    return pathBundle;\n}\n\n/**\n * @alias zrender/graphic/Text\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nvar Text = function (opts) { // jshint ignore:line\n    Displayable.call(this, opts);\n};\n\nText.prototype = {\n\n    constructor: Text,\n\n    type: 'text',\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        // Use props with prefix 'text'.\n        style.fill = style.stroke = style.shadowBlur = style.shadowColor =\n            style.shadowOffsetX = style.shadowOffsetY = null;\n\n        var text = style.text;\n        // Convert to string\n        text != null && (text += '');\n\n        // Do not apply style.bind in Text node. Because the real bind job\n        // is in textHelper.renderText, and performance of text render should\n        // be considered.\n        // style.bind(ctx, this, prevEl);\n\n        if (!needDrawText(text, style)) {\n            // The current el.style is not applied\n            // and should not be used as cache.\n            ctx.__attrCachedBy = ContextCachedBy.NONE;\n            return;\n        }\n\n        this.setTransform(ctx);\n\n        renderText(this, ctx, text, style, null, prevEl);\n\n        this.restoreTransform(ctx);\n    },\n\n    getBoundingRect: function () {\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        if (!this._rect) {\n            var text = style.text;\n            text != null ? (text += '') : (text = '');\n\n            var rect = getBoundingRect(\n                style.text + '',\n                style.font,\n                style.textAlign,\n                style.textVerticalAlign,\n                style.textPadding,\n                style.textLineHeight,\n                style.rich\n            );\n\n            rect.x += style.x || 0;\n            rect.y += style.y || 0;\n\n            if (getStroke(style.textStroke, style.textStrokeWidth)) {\n                var w = style.textStrokeWidth;\n                rect.x -= w / 2;\n                rect.y -= w / 2;\n                rect.width += w;\n                rect.height += w;\n            }\n\n            this._rect = rect;\n        }\n\n        return this._rect;\n    }\n};\n\ninherits(Text, Displayable);\n\n/**\n * 圆形\n * @module zrender/shape/Circle\n */\n\nvar Circle = Path.extend({\n\n    type: 'circle',\n\n    shape: {\n        cx: 0,\n        cy: 0,\n        r: 0\n    },\n\n\n    buildPath: function (ctx, shape, inBundle) {\n        // Better stroking in ShapeBundle\n        // Always do it may have performence issue ( fill may be 2x more cost)\n        if (inBundle) {\n            ctx.moveTo(shape.cx + shape.r, shape.cy);\n        }\n        // else {\n        //     if (ctx.allocate && !ctx.data.length) {\n        //         ctx.allocate(ctx.CMD_MEM_SIZE.A);\n        //     }\n        // }\n        // Better stroking in ShapeBundle\n        // ctx.moveTo(shape.cx + shape.r, shape.cy);\n        ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true);\n    }\n});\n\n// Fix weird bug in some version of IE11 (like 11.0.9600.178**),\n// where exception \"unexpected call to method or property access\"\n// might be thrown when calling ctx.fill or ctx.stroke after a path\n// whose area size is zero is drawn and ctx.clip() is called and\n// shadowBlur is set. See #4572, #3112, #5777.\n// (e.g.,\n//  ctx.moveTo(10, 10);\n//  ctx.lineTo(20, 10);\n//  ctx.closePath();\n//  ctx.clip();\n//  ctx.shadowBlur = 10;\n//  ...\n//  ctx.fill();\n// )\n\nvar shadowTemp = [\n    ['shadowBlur', 0],\n    ['shadowColor', '#000'],\n    ['shadowOffsetX', 0],\n    ['shadowOffsetY', 0]\n];\n\nvar fixClipWithShadow = function (orignalBrush) {\n\n    // version string can be: '11.0'\n    return (env$1.browser.ie && env$1.browser.version >= 11)\n\n        ? function () {\n            var clipPaths = this.__clipPaths;\n            var style = this.style;\n            var modified;\n\n            if (clipPaths) {\n                for (var i = 0; i < clipPaths.length; i++) {\n                    var clipPath = clipPaths[i];\n                    var shape = clipPath && clipPath.shape;\n                    var type = clipPath && clipPath.type;\n\n                    if (shape && (\n                        (type === 'sector' && shape.startAngle === shape.endAngle)\n                        || (type === 'rect' && (!shape.width || !shape.height))\n                    )) {\n                        for (var j = 0; j < shadowTemp.length; j++) {\n                            // It is save to put shadowTemp static, because shadowTemp\n                            // will be all modified each item brush called.\n                            shadowTemp[j][2] = style[shadowTemp[j][0]];\n                            style[shadowTemp[j][0]] = shadowTemp[j][1];\n                        }\n                        modified = true;\n                        break;\n                    }\n                }\n            }\n\n            orignalBrush.apply(this, arguments);\n\n            if (modified) {\n                for (var j = 0; j < shadowTemp.length; j++) {\n                    style[shadowTemp[j][0]] = shadowTemp[j][2];\n                }\n            }\n        }\n\n        : orignalBrush;\n};\n\n/**\n * 扇形\n * @module zrender/graphic/shape/Sector\n */\n\nvar Sector = Path.extend({\n\n    type: 'sector',\n\n    shape: {\n\n        cx: 0,\n\n        cy: 0,\n\n        r0: 0,\n\n        r: 0,\n\n        startAngle: 0,\n\n        endAngle: Math.PI * 2,\n\n        clockwise: true\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n\n        var x = shape.cx;\n        var y = shape.cy;\n        var r0 = Math.max(shape.r0 || 0, 0);\n        var r = Math.max(shape.r, 0);\n        var startAngle = shape.startAngle;\n        var endAngle = shape.endAngle;\n        var clockwise = shape.clockwise;\n\n        var unitX = Math.cos(startAngle);\n        var unitY = Math.sin(startAngle);\n\n        ctx.moveTo(unitX * r0 + x, unitY * r0 + y);\n\n        ctx.lineTo(unitX * r + x, unitY * r + y);\n\n        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);\n\n        ctx.lineTo(\n            Math.cos(endAngle) * r0 + x,\n            Math.sin(endAngle) * r0 + y\n        );\n\n        if (r0 !== 0) {\n            ctx.arc(x, y, r0, endAngle, startAngle, clockwise);\n        }\n\n        ctx.closePath();\n    }\n});\n\n/**\n * 圆环\n * @module zrender/graphic/shape/Ring\n */\n\nvar Ring = Path.extend({\n\n    type: 'ring',\n\n    shape: {\n        cx: 0,\n        cy: 0,\n        r: 0,\n        r0: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var x = shape.cx;\n        var y = shape.cy;\n        var PI2 = Math.PI * 2;\n        ctx.moveTo(x + shape.r, y);\n        ctx.arc(x, y, shape.r, 0, PI2, false);\n        ctx.moveTo(x + shape.r0, y);\n        ctx.arc(x, y, shape.r0, 0, PI2, true);\n    }\n});\n\n/**\n * Catmull-Rom spline 插值折线\n * @module zrender/shape/util/smoothSpline\n * @author pissang (https://www.github.com/pissang)\n *         Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         errorrik (errorrik@gmail.com)\n */\n\n/**\n * @inner\n */\nfunction interpolate(p0, p1, p2, p3, t, t2, t3) {\n    var v0 = (p2 - p0) * 0.5;\n    var v1 = (p3 - p1) * 0.5;\n    return (2 * (p1 - p2) + v0 + v1) * t3\n            + (-3 * (p1 - p2) - 2 * v0 - v1) * t2\n            + v0 * t + p1;\n}\n\n/**\n * @alias module:zrender/shape/util/smoothSpline\n * @param {Array} points 线段顶点数组\n * @param {boolean} isLoop\n * @return {Array}\n */\nvar smoothSpline = function (points, isLoop) {\n    var len$$1 = points.length;\n    var ret = [];\n\n    var distance$$1 = 0;\n    for (var i = 1; i < len$$1; i++) {\n        distance$$1 += distance(points[i - 1], points[i]);\n    }\n\n    var segs = distance$$1 / 2;\n    segs = segs < len$$1 ? len$$1 : segs;\n    for (var i = 0; i < segs; i++) {\n        var pos = i / (segs - 1) * (isLoop ? len$$1 : len$$1 - 1);\n        var idx = Math.floor(pos);\n\n        var w = pos - idx;\n\n        var p0;\n        var p1 = points[idx % len$$1];\n        var p2;\n        var p3;\n        if (!isLoop) {\n            p0 = points[idx === 0 ? idx : idx - 1];\n            p2 = points[idx > len$$1 - 2 ? len$$1 - 1 : idx + 1];\n            p3 = points[idx > len$$1 - 3 ? len$$1 - 1 : idx + 2];\n        }\n        else {\n            p0 = points[(idx - 1 + len$$1) % len$$1];\n            p2 = points[(idx + 1) % len$$1];\n            p3 = points[(idx + 2) % len$$1];\n        }\n\n        var w2 = w * w;\n        var w3 = w * w2;\n\n        ret.push([\n            interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3),\n            interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3)\n        ]);\n    }\n    return ret;\n};\n\n/**\n * 贝塞尔平滑曲线\n * @module zrender/shape/util/smoothBezier\n * @author pissang (https://www.github.com/pissang)\n *         Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         errorrik (errorrik@gmail.com)\n */\n\n/**\n * 贝塞尔平滑曲线\n * @alias module:zrender/shape/util/smoothBezier\n * @param {Array} points 线段顶点数组\n * @param {number} smooth 平滑等级, 0-1\n * @param {boolean} isLoop\n * @param {Array} constraint 将计算出来的控制点约束在一个包围盒内\n *                           比如 [[0, 0], [100, 100]], 这个包围盒会与\n *                           整个折线的包围盒做一个并集用来约束控制点。\n * @param {Array} 计算出来的控制点数组\n */\nvar smoothBezier = function (points, smooth, isLoop, constraint) {\n    var cps = [];\n\n    var v = [];\n    var v1 = [];\n    var v2 = [];\n    var prevPoint;\n    var nextPoint;\n\n    var min$$1;\n    var max$$1;\n    if (constraint) {\n        min$$1 = [Infinity, Infinity];\n        max$$1 = [-Infinity, -Infinity];\n        for (var i = 0, len$$1 = points.length; i < len$$1; i++) {\n            min(min$$1, min$$1, points[i]);\n            max(max$$1, max$$1, points[i]);\n        }\n        // 与指定的包围盒做并集\n        min(min$$1, min$$1, constraint[0]);\n        max(max$$1, max$$1, constraint[1]);\n    }\n\n    for (var i = 0, len$$1 = points.length; i < len$$1; i++) {\n        var point = points[i];\n\n        if (isLoop) {\n            prevPoint = points[i ? i - 1 : len$$1 - 1];\n            nextPoint = points[(i + 1) % len$$1];\n        }\n        else {\n            if (i === 0 || i === len$$1 - 1) {\n                cps.push(clone$1(points[i]));\n                continue;\n            }\n            else {\n                prevPoint = points[i - 1];\n                nextPoint = points[i + 1];\n            }\n        }\n\n        sub(v, nextPoint, prevPoint);\n\n        // use degree to scale the handle length\n        scale(v, v, smooth);\n\n        var d0 = distance(point, prevPoint);\n        var d1 = distance(point, nextPoint);\n        var sum = d0 + d1;\n        if (sum !== 0) {\n            d0 /= sum;\n            d1 /= sum;\n        }\n\n        scale(v1, v, -d0);\n        scale(v2, v, d1);\n        var cp0 = add([], point, v1);\n        var cp1 = add([], point, v2);\n        if (constraint) {\n            max(cp0, cp0, min$$1);\n            min(cp0, cp0, max$$1);\n            max(cp1, cp1, min$$1);\n            min(cp1, cp1, max$$1);\n        }\n        cps.push(cp0);\n        cps.push(cp1);\n    }\n\n    if (isLoop) {\n        cps.push(cps.shift());\n    }\n\n    return cps;\n};\n\nfunction buildPath$1(ctx, shape, closePath) {\n    var points = shape.points;\n    var smooth = shape.smooth;\n    if (points && points.length >= 2) {\n        if (smooth && smooth !== 'spline') {\n            var controlPoints = smoothBezier(\n                points, smooth, closePath, shape.smoothConstraint\n            );\n\n            ctx.moveTo(points[0][0], points[0][1]);\n            var len = points.length;\n            for (var i = 0; i < (closePath ? len : len - 1); i++) {\n                var cp1 = controlPoints[i * 2];\n                var cp2 = controlPoints[i * 2 + 1];\n                var p = points[(i + 1) % len];\n                ctx.bezierCurveTo(\n                    cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]\n                );\n            }\n        }\n        else {\n            if (smooth === 'spline') {\n                points = smoothSpline(points, closePath);\n            }\n\n            ctx.moveTo(points[0][0], points[0][1]);\n            for (var i = 1, l = points.length; i < l; i++) {\n                ctx.lineTo(points[i][0], points[i][1]);\n            }\n        }\n\n        closePath && ctx.closePath();\n    }\n}\n\n/**\n * 多边形\n * @module zrender/shape/Polygon\n */\n\nvar Polygon = Path.extend({\n\n    type: 'polygon',\n\n    shape: {\n        points: null,\n\n        smooth: false,\n\n        smoothConstraint: null\n    },\n\n    buildPath: function (ctx, shape) {\n        buildPath$1(ctx, shape, true);\n    }\n});\n\n/**\n * @module zrender/graphic/shape/Polyline\n */\n\nvar Polyline = Path.extend({\n\n    type: 'polyline',\n\n    shape: {\n        points: null,\n\n        smooth: false,\n\n        smoothConstraint: null\n    },\n\n    style: {\n        stroke: '#000',\n\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        buildPath$1(ctx, shape, false);\n    }\n});\n\n/**\n * Sub-pixel optimize for canvas rendering, prevent from blur\n * when rendering a thin vertical/horizontal line.\n */\n\nvar round$1 = Math.round;\n\n/**\n * Sub pixel optimize line for canvas\n *\n * @param {Object} outputShape The modification will be performed on `outputShape`.\n *                 `outputShape` and `inputShape` can be the same object.\n *                 `outputShape` object can be used repeatly, because all of\n *                 the `x1`, `x2`, `y1`, `y2` will be assigned in this method.\n * @param {Object} [inputShape]\n * @param {number} [inputShape.x1]\n * @param {number} [inputShape.y1]\n * @param {number} [inputShape.x2]\n * @param {number} [inputShape.y2]\n * @param {Object} [style]\n * @param {number} [style.lineWidth]\n */\nfunction subPixelOptimizeLine$1(outputShape, inputShape, style) {\n    var lineWidth = style && style.lineWidth;\n\n    if (!inputShape || !lineWidth) {\n        return;\n    }\n\n    var x1 = inputShape.x1;\n    var x2 = inputShape.x2;\n    var y1 = inputShape.y1;\n    var y2 = inputShape.y2;\n\n    if (round$1(x1 * 2) === round$1(x2 * 2)) {\n        outputShape.x1 = outputShape.x2 = subPixelOptimize$1(x1, lineWidth, true);\n    }\n    else {\n        outputShape.x1 = x1;\n        outputShape.x2 = x2;\n    }\n    if (round$1(y1 * 2) === round$1(y2 * 2)) {\n        outputShape.y1 = outputShape.y2 = subPixelOptimize$1(y1, lineWidth, true);\n    }\n    else {\n        outputShape.y1 = y1;\n        outputShape.y2 = y2;\n    }\n}\n\n/**\n * Sub pixel optimize rect for canvas\n *\n * @param {Object} outputShape The modification will be performed on `outputShape`.\n *                 `outputShape` and `inputShape` can be the same object.\n *                 `outputShape` object can be used repeatly, because all of\n *                 the `x`, `y`, `width`, `height` will be assigned in this method.\n * @param {Object} [inputShape]\n * @param {number} [inputShape.x]\n * @param {number} [inputShape.y]\n * @param {number} [inputShape.width]\n * @param {number} [inputShape.height]\n * @param {Object} [style]\n * @param {number} [style.lineWidth]\n */\nfunction subPixelOptimizeRect$1(outputShape, inputShape, style) {\n    var lineWidth = style && style.lineWidth;\n\n    if (!inputShape || !lineWidth) {\n        return;\n    }\n\n    var originX = inputShape.x;\n    var originY = inputShape.y;\n    var originWidth = inputShape.width;\n    var originHeight = inputShape.height;\n\n    outputShape.x = subPixelOptimize$1(originX, lineWidth, true);\n    outputShape.y = subPixelOptimize$1(originY, lineWidth, true);\n    outputShape.width = Math.max(\n        subPixelOptimize$1(originX + originWidth, lineWidth, false) - outputShape.x,\n        originWidth === 0 ? 0 : 1\n    );\n    outputShape.height = Math.max(\n        subPixelOptimize$1(originY + originHeight, lineWidth, false) - outputShape.y,\n        originHeight === 0 ? 0 : 1\n    );\n}\n\n/**\n * Sub pixel optimize for canvas\n *\n * @param {number} position Coordinate, such as x, y\n * @param {number} lineWidth Should be nonnegative integer.\n * @param {boolean=} positiveOrNegative Default false (negative).\n * @return {number} Optimized position.\n */\nfunction subPixelOptimize$1(position, lineWidth, positiveOrNegative) {\n    // Assure that (position + lineWidth / 2) is near integer edge,\n    // otherwise line will be fuzzy in canvas.\n    var doubledPosition = round$1(position * 2);\n    return (doubledPosition + round$1(lineWidth)) % 2 === 0\n        ? doubledPosition / 2\n        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;\n}\n\n/**\n * 矩形\n * @module zrender/graphic/shape/Rect\n */\n\n// Avoid create repeatly.\nvar subPixelOptimizeOutputShape = {};\n\nvar Rect = Path.extend({\n\n    type: 'rect',\n\n    shape: {\n        // 左上、右上、右下、左下角的半径依次为r1、r2、r3、r4\n        // r缩写为1         相当于 [1, 1, 1, 1]\n        // r缩写为[1]       相当于 [1, 1, 1, 1]\n        // r缩写为[1, 2]    相当于 [1, 2, 1, 2]\n        // r缩写为[1, 2, 3] 相当于 [1, 2, 3, 2]\n        r: 0,\n\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var x;\n        var y;\n        var width;\n        var height;\n\n        if (this.subPixelOptimize) {\n            subPixelOptimizeRect$1(subPixelOptimizeOutputShape, shape, this.style);\n            x = subPixelOptimizeOutputShape.x;\n            y = subPixelOptimizeOutputShape.y;\n            width = subPixelOptimizeOutputShape.width;\n            height = subPixelOptimizeOutputShape.height;\n            subPixelOptimizeOutputShape.r = shape.r;\n            shape = subPixelOptimizeOutputShape;\n        }\n        else {\n            x = shape.x;\n            y = shape.y;\n            width = shape.width;\n            height = shape.height;\n        }\n\n        if (!shape.r) {\n            ctx.rect(x, y, width, height);\n        }\n        else {\n            buildPath(ctx, shape);\n        }\n        ctx.closePath();\n        return;\n    }\n});\n\n/**\n * 直线\n * @module zrender/graphic/shape/Line\n */\n\n// Avoid create repeatly.\nvar subPixelOptimizeOutputShape$1 = {};\n\nvar Line = Path.extend({\n\n    type: 'line',\n\n    shape: {\n        // Start point\n        x1: 0,\n        y1: 0,\n        // End point\n        x2: 0,\n        y2: 0,\n\n        percent: 1\n    },\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        var x1;\n        var y1;\n        var x2;\n        var y2;\n\n        if (this.subPixelOptimize) {\n            subPixelOptimizeLine$1(subPixelOptimizeOutputShape$1, shape, this.style);\n            x1 = subPixelOptimizeOutputShape$1.x1;\n            y1 = subPixelOptimizeOutputShape$1.y1;\n            x2 = subPixelOptimizeOutputShape$1.x2;\n            y2 = subPixelOptimizeOutputShape$1.y2;\n        }\n        else {\n            x1 = shape.x1;\n            y1 = shape.y1;\n            x2 = shape.x2;\n            y2 = shape.y2;\n        }\n\n        var percent = shape.percent;\n\n        if (percent === 0) {\n            return;\n        }\n\n        ctx.moveTo(x1, y1);\n\n        if (percent < 1) {\n            x2 = x1 * (1 - percent) + x2 * percent;\n            y2 = y1 * (1 - percent) + y2 * percent;\n        }\n        ctx.lineTo(x2, y2);\n    },\n\n    /**\n     * Get point at percent\n     * @param  {number} percent\n     * @return {Array.<number>}\n     */\n    pointAt: function (p) {\n        var shape = this.shape;\n        return [\n            shape.x1 * (1 - p) + shape.x2 * p,\n            shape.y1 * (1 - p) + shape.y2 * p\n        ];\n    }\n});\n\n/**\n * 贝塞尔曲线\n * @module zrender/shape/BezierCurve\n */\n\nvar out = [];\n\nfunction someVectorAt(shape, t, isTangent) {\n    var cpx2 = shape.cpx2;\n    var cpy2 = shape.cpy2;\n    if (cpx2 === null || cpy2 === null) {\n        return [\n            (isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t),\n            (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t)\n        ];\n    }\n    else {\n        return [\n            (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t),\n            (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t)\n        ];\n    }\n}\n\nvar BezierCurve = Path.extend({\n\n    type: 'bezier-curve',\n\n    shape: {\n        x1: 0,\n        y1: 0,\n        x2: 0,\n        y2: 0,\n        cpx1: 0,\n        cpy1: 0,\n        // cpx2: 0,\n        // cpy2: 0\n\n        // Curve show percent, for animating\n        percent: 1\n    },\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        var x1 = shape.x1;\n        var y1 = shape.y1;\n        var x2 = shape.x2;\n        var y2 = shape.y2;\n        var cpx1 = shape.cpx1;\n        var cpy1 = shape.cpy1;\n        var cpx2 = shape.cpx2;\n        var cpy2 = shape.cpy2;\n        var percent = shape.percent;\n        if (percent === 0) {\n            return;\n        }\n\n        ctx.moveTo(x1, y1);\n\n        if (cpx2 == null || cpy2 == null) {\n            if (percent < 1) {\n                quadraticSubdivide(\n                    x1, cpx1, x2, percent, out\n                );\n                cpx1 = out[1];\n                x2 = out[2];\n                quadraticSubdivide(\n                    y1, cpy1, y2, percent, out\n                );\n                cpy1 = out[1];\n                y2 = out[2];\n            }\n\n            ctx.quadraticCurveTo(\n                cpx1, cpy1,\n                x2, y2\n            );\n        }\n        else {\n            if (percent < 1) {\n                cubicSubdivide(\n                    x1, cpx1, cpx2, x2, percent, out\n                );\n                cpx1 = out[1];\n                cpx2 = out[2];\n                x2 = out[3];\n                cubicSubdivide(\n                    y1, cpy1, cpy2, y2, percent, out\n                );\n                cpy1 = out[1];\n                cpy2 = out[2];\n                y2 = out[3];\n            }\n            ctx.bezierCurveTo(\n                cpx1, cpy1,\n                cpx2, cpy2,\n                x2, y2\n            );\n        }\n    },\n\n    /**\n     * Get point at percent\n     * @param  {number} t\n     * @return {Array.<number>}\n     */\n    pointAt: function (t) {\n        return someVectorAt(this.shape, t, false);\n    },\n\n    /**\n     * Get tangent at percent\n     * @param  {number} t\n     * @return {Array.<number>}\n     */\n    tangentAt: function (t) {\n        var p = someVectorAt(this.shape, t, true);\n        return normalize(p, p);\n    }\n});\n\n/**\n * 圆弧\n * @module zrender/graphic/shape/Arc\n */\n\nvar Arc = Path.extend({\n\n    type: 'arc',\n\n    shape: {\n\n        cx: 0,\n\n        cy: 0,\n\n        r: 0,\n\n        startAngle: 0,\n\n        endAngle: Math.PI * 2,\n\n        clockwise: true\n    },\n\n    style: {\n\n        stroke: '#000',\n\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n\n        var x = shape.cx;\n        var y = shape.cy;\n        var r = Math.max(shape.r, 0);\n        var startAngle = shape.startAngle;\n        var endAngle = shape.endAngle;\n        var clockwise = shape.clockwise;\n\n        var unitX = Math.cos(startAngle);\n        var unitY = Math.sin(startAngle);\n\n        ctx.moveTo(unitX * r + x, unitY * r + y);\n        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);\n    }\n});\n\n// CompoundPath to improve performance\n\nvar CompoundPath = Path.extend({\n\n    type: 'compound',\n\n    shape: {\n\n        paths: null\n    },\n\n    _updatePathDirty: function () {\n        var dirtyPath = this.__dirtyPath;\n        var paths = this.shape.paths;\n        for (var i = 0; i < paths.length; i++) {\n            // Mark as dirty if any subpath is dirty\n            dirtyPath = dirtyPath || paths[i].__dirtyPath;\n        }\n        this.__dirtyPath = dirtyPath;\n        this.__dirty = this.__dirty || dirtyPath;\n    },\n\n    beforeBrush: function () {\n        this._updatePathDirty();\n        var paths = this.shape.paths || [];\n        var scale = this.getGlobalScale();\n        // Update path scale\n        for (var i = 0; i < paths.length; i++) {\n            if (!paths[i].path) {\n                paths[i].createPathProxy();\n            }\n            paths[i].path.setScale(scale[0], scale[1]);\n        }\n    },\n\n    buildPath: function (ctx, shape) {\n        var paths = shape.paths || [];\n        for (var i = 0; i < paths.length; i++) {\n            paths[i].buildPath(ctx, paths[i].shape, true);\n        }\n    },\n\n    afterBrush: function () {\n        var paths = this.shape.paths || [];\n        for (var i = 0; i < paths.length; i++) {\n            paths[i].__dirtyPath = false;\n        }\n    },\n\n    getBoundingRect: function () {\n        this._updatePathDirty();\n        return Path.prototype.getBoundingRect.call(this);\n    }\n});\n\n/**\n * @param {Array.<Object>} colorStops\n */\nvar Gradient = function (colorStops) {\n\n    this.colorStops = colorStops || [];\n\n};\n\nGradient.prototype = {\n\n    constructor: Gradient,\n\n    addColorStop: function (offset, color) {\n        this.colorStops.push({\n\n            offset: offset,\n\n            color: color\n        });\n    }\n\n};\n\n/**\n * x, y, x2, y2 are all percent from 0 to 1\n * @param {number} [x=0]\n * @param {number} [y=0]\n * @param {number} [x2=1]\n * @param {number} [y2=0]\n * @param {Array.<Object>} colorStops\n * @param {boolean} [globalCoord=false]\n */\nvar LinearGradient = function (x, y, x2, y2, colorStops, globalCoord) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {type: 'linear', colorStops: ...}`, where\n    // this constructor will not be called.\n\n    this.x = x == null ? 0 : x;\n\n    this.y = y == null ? 0 : y;\n\n    this.x2 = x2 == null ? 1 : x2;\n\n    this.y2 = y2 == null ? 0 : y2;\n\n    // Can be cloned\n    this.type = 'linear';\n\n    // If use global coord\n    this.global = globalCoord || false;\n\n    Gradient.call(this, colorStops);\n};\n\nLinearGradient.prototype = {\n\n    constructor: LinearGradient\n};\n\ninherits(LinearGradient, Gradient);\n\n/**\n * x, y, r are all percent from 0 to 1\n * @param {number} [x=0.5]\n * @param {number} [y=0.5]\n * @param {number} [r=0.5]\n * @param {Array.<Object>} [colorStops]\n * @param {boolean} [globalCoord=false]\n */\nvar RadialGradient = function (x, y, r, colorStops, globalCoord) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {type: 'radial', colorStops: ...}`, where\n    // this constructor will not be called.\n\n    this.x = x == null ? 0.5 : x;\n\n    this.y = y == null ? 0.5 : y;\n\n    this.r = r == null ? 0.5 : r;\n\n    // Can be cloned\n    this.type = 'radial';\n\n    // If use global coord\n    this.global = globalCoord || false;\n\n    Gradient.call(this, colorStops);\n};\n\nRadialGradient.prototype = {\n\n    constructor: RadialGradient\n};\n\ninherits(RadialGradient, Gradient);\n\n/**\n * Displayable for incremental rendering. It will be rendered in a separate layer\n * IncrementalDisplay have two main methods. `clearDisplayables` and `addDisplayables`\n * addDisplayables will render the added displayables incremetally.\n *\n * It use a not clearFlag to tell the painter don't clear the layer if it's the first element.\n */\n// TODO Style override ?\nfunction IncrementalDisplayble(opts) {\n\n    Displayable.call(this, opts);\n\n    this._displayables = [];\n\n    this._temporaryDisplayables = [];\n\n    this._cursor = 0;\n\n    this.notClear = true;\n}\n\nIncrementalDisplayble.prototype.incremental = true;\n\nIncrementalDisplayble.prototype.clearDisplaybles = function () {\n    this._displayables = [];\n    this._temporaryDisplayables = [];\n    this._cursor = 0;\n    this.dirty();\n\n    this.notClear = false;\n};\n\nIncrementalDisplayble.prototype.addDisplayable = function (displayable, notPersistent) {\n    if (notPersistent) {\n        this._temporaryDisplayables.push(displayable);\n    }\n    else {\n        this._displayables.push(displayable);\n    }\n    this.dirty();\n};\n\nIncrementalDisplayble.prototype.addDisplayables = function (displayables, notPersistent) {\n    notPersistent = notPersistent || false;\n    for (var i = 0; i < displayables.length; i++) {\n        this.addDisplayable(displayables[i], notPersistent);\n    }\n};\n\nIncrementalDisplayble.prototype.eachPendingDisplayable = function (cb) {\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        cb && cb(this._displayables[i]);\n    }\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        cb && cb(this._temporaryDisplayables[i]);\n    }\n};\n\nIncrementalDisplayble.prototype.update = function () {\n    this.updateTransform();\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        var displayable = this._displayables[i];\n        // PENDING\n        displayable.parent = this;\n        displayable.update();\n        displayable.parent = null;\n    }\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        var displayable = this._temporaryDisplayables[i];\n        // PENDING\n        displayable.parent = this;\n        displayable.update();\n        displayable.parent = null;\n    }\n};\n\nIncrementalDisplayble.prototype.brush = function (ctx, prevEl) {\n    // Render persistant displayables.\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        var displayable = this._displayables[i];\n        displayable.beforeBrush && displayable.beforeBrush(ctx);\n        displayable.brush(ctx, i === this._cursor ? null : this._displayables[i - 1]);\n        displayable.afterBrush && displayable.afterBrush(ctx);\n    }\n    this._cursor = i;\n    // Render temporary displayables.\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        var displayable = this._temporaryDisplayables[i];\n        displayable.beforeBrush && displayable.beforeBrush(ctx);\n        displayable.brush(ctx, i === 0 ? null : this._temporaryDisplayables[i - 1]);\n        displayable.afterBrush && displayable.afterBrush(ctx);\n    }\n\n    this._temporaryDisplayables = [];\n\n    this.notClear = true;\n};\n\nvar m = [];\nIncrementalDisplayble.prototype.getBoundingRect = function () {\n    if (!this._rect) {\n        var rect = new BoundingRect(Infinity, Infinity, -Infinity, -Infinity);\n        for (var i = 0; i < this._displayables.length; i++) {\n            var displayable = this._displayables[i];\n            var childRect = displayable.getBoundingRect().clone();\n            if (displayable.needLocalTransform()) {\n                childRect.applyTransform(displayable.getLocalTransform(m));\n            }\n            rect.union(childRect);\n        }\n        this._rect = rect;\n    }\n    return this._rect;\n};\n\nIncrementalDisplayble.prototype.contain = function (x, y) {\n    var localPos = this.transformCoordToLocal(x, y);\n    var rect = this.getBoundingRect();\n\n    if (rect.contain(localPos[0], localPos[1])) {\n        for (var i = 0; i < this._displayables.length; i++) {\n            var displayable = this._displayables[i];\n            if (displayable.contain(x, y)) {\n                return true;\n            }\n        }\n    }\n    return false;\n};\n\ninherits(IncrementalDisplayble, Displayable);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar round = Math.round;\nvar mathMax$1 = Math.max;\nvar mathMin$1 = Math.min;\n\nvar EMPTY_OBJ = {};\n\nvar Z2_EMPHASIS_LIFT = 1;\n\n/**\n * Extend shape with parameters\n */\nfunction extendShape(opts) {\n    return Path.extend(opts);\n}\n\n/**\n * Extend path\n */\nfunction extendPath(pathData, opts) {\n    return extendFromString(pathData, opts);\n}\n\n/**\n * Create a path element from path data string\n * @param {string} pathData\n * @param {Object} opts\n * @param {module:zrender/core/BoundingRect} rect\n * @param {string} [layout=cover] 'center' or 'cover'\n */\nfunction makePath(pathData, opts, rect, layout) {\n    var path = createFromString(pathData, opts);\n    if (rect) {\n        if (layout === 'center') {\n            rect = centerGraphic(rect, path.getBoundingRect());\n        }\n        resizePath(path, rect);\n    }\n    return path;\n}\n\n/**\n * Create a image element from image url\n * @param {string} imageUrl image url\n * @param {Object} opts options\n * @param {module:zrender/core/BoundingRect} rect constrain rect\n * @param {string} [layout=cover] 'center' or 'cover'\n */\nfunction makeImage(imageUrl, rect, layout) {\n    var path = new ZImage({\n        style: {\n            image: imageUrl,\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        },\n        onload: function (img) {\n            if (layout === 'center') {\n                var boundingRect = {\n                    width: img.width,\n                    height: img.height\n                };\n                path.setStyle(centerGraphic(rect, boundingRect));\n            }\n        }\n    });\n    return path;\n}\n\n/**\n * Get position of centered element in bounding box.\n *\n * @param  {Object} rect         element local bounding box\n * @param  {Object} boundingRect constraint bounding box\n * @return {Object} element position containing x, y, width, and height\n */\nfunction centerGraphic(rect, boundingRect) {\n    // Set rect to center, keep width / height ratio.\n    var aspect = boundingRect.width / boundingRect.height;\n    var width = rect.height * aspect;\n    var height;\n    if (width <= rect.width) {\n        height = rect.height;\n    }\n    else {\n        width = rect.width;\n        height = width / aspect;\n    }\n    var cx = rect.x + rect.width / 2;\n    var cy = rect.y + rect.height / 2;\n\n    return {\n        x: cx - width / 2,\n        y: cy - height / 2,\n        width: width,\n        height: height\n    };\n}\n\nvar mergePath = mergePath$1;\n\n/**\n * Resize a path to fit the rect\n * @param {module:zrender/graphic/Path} path\n * @param {Object} rect\n */\nfunction resizePath(path, rect) {\n    if (!path.applyTransform) {\n        return;\n    }\n\n    var pathRect = path.getBoundingRect();\n\n    var m = pathRect.calculateTransform(rect);\n\n    path.applyTransform(m);\n}\n\n/**\n * Sub pixel optimize line for canvas\n *\n * @param {Object} param\n * @param {Object} [param.shape]\n * @param {number} [param.shape.x1]\n * @param {number} [param.shape.y1]\n * @param {number} [param.shape.x2]\n * @param {number} [param.shape.y2]\n * @param {Object} [param.style]\n * @param {number} [param.style.lineWidth]\n * @return {Object} Modified param\n */\nfunction subPixelOptimizeLine(param) {\n    var shape = param.shape;\n    var lineWidth = param.style.lineWidth;\n\n    if (round(shape.x1 * 2) === round(shape.x2 * 2)) {\n        shape.x1 = shape.x2 = subPixelOptimize(shape.x1, lineWidth, true);\n    }\n    if (round(shape.y1 * 2) === round(shape.y2 * 2)) {\n        shape.y1 = shape.y2 = subPixelOptimize(shape.y1, lineWidth, true);\n    }\n    return param;\n}\n\n/**\n * Sub pixel optimize rect for canvas\n *\n * @param {Object} param\n * @param {Object} [param.shape]\n * @param {number} [param.shape.x]\n * @param {number} [param.shape.y]\n * @param {number} [param.shape.width]\n * @param {number} [param.shape.height]\n * @param {Object} [param.style]\n * @param {number} [param.style.lineWidth]\n * @return {Object} Modified param\n */\nfunction subPixelOptimizeRect(param) {\n    var shape = param.shape;\n    var lineWidth = param.style.lineWidth;\n    var originX = shape.x;\n    var originY = shape.y;\n    var originWidth = shape.width;\n    var originHeight = shape.height;\n    shape.x = subPixelOptimize(shape.x, lineWidth, true);\n    shape.y = subPixelOptimize(shape.y, lineWidth, true);\n    shape.width = Math.max(\n        subPixelOptimize(originX + originWidth, lineWidth, false) - shape.x,\n        originWidth === 0 ? 0 : 1\n    );\n    shape.height = Math.max(\n        subPixelOptimize(originY + originHeight, lineWidth, false) - shape.y,\n        originHeight === 0 ? 0 : 1\n    );\n    return param;\n}\n\n/**\n * Sub pixel optimize for canvas\n *\n * @param {number} position Coordinate, such as x, y\n * @param {number} lineWidth Should be nonnegative integer.\n * @param {boolean=} positiveOrNegative Default false (negative).\n * @return {number} Optimized position.\n */\nfunction subPixelOptimize(position, lineWidth, positiveOrNegative) {\n    // Assure that (position + lineWidth / 2) is near integer edge,\n    // otherwise line will be fuzzy in canvas.\n    var doubledPosition = round(position * 2);\n    return (doubledPosition + round(lineWidth)) % 2 === 0\n        ? doubledPosition / 2\n        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;\n}\n\nfunction hasFillOrStroke(fillOrStroke) {\n    return fillOrStroke != null && fillOrStroke !== 'none';\n}\n\n// Most lifted color are duplicated.\nvar liftedColorMap = createHashMap();\nvar liftedColorCount = 0;\n\nfunction liftColor(color) {\n    if (typeof color !== 'string') {\n        return color;\n    }\n    var liftedColor = liftedColorMap.get(color);\n    if (!liftedColor) {\n        liftedColor = lift(color, -0.1);\n        if (liftedColorCount < 10000) {\n            liftedColorMap.set(color, liftedColor);\n            liftedColorCount++;\n        }\n    }\n    return liftedColor;\n}\n\nfunction cacheElementStl(el) {\n    if (!el.__hoverStlDirty) {\n        return;\n    }\n    el.__hoverStlDirty = false;\n\n    var hoverStyle = el.__hoverStl;\n    if (!hoverStyle) {\n        el.__cachedNormalStl = el.__cachedNormalZ2 = null;\n        return;\n    }\n\n    var normalStyle = el.__cachedNormalStl = {};\n    el.__cachedNormalZ2 = el.z2;\n    var elStyle = el.style;\n\n    for (var name in hoverStyle) {\n        // See comment in `doSingleEnterHover`.\n        if (hoverStyle[name] != null) {\n            normalStyle[name] = elStyle[name];\n        }\n    }\n\n    // Always cache fill and stroke to normalStyle for lifting color.\n    normalStyle.fill = elStyle.fill;\n    normalStyle.stroke = elStyle.stroke;\n}\n\nfunction doSingleEnterHover(el) {\n    var hoverStl = el.__hoverStl;\n\n    if (!hoverStl || el.__highlighted) {\n        return;\n    }\n\n    var useHoverLayer = el.useHoverLayer;\n    el.__highlighted = useHoverLayer ? 'layer' : 'plain';\n\n    var zr = el.__zr;\n    if (!zr && useHoverLayer) {\n        return;\n    }\n\n    var elTarget = el;\n    var targetStyle = el.style;\n\n    if (useHoverLayer) {\n        elTarget = zr.addHover(el);\n        targetStyle = elTarget.style;\n    }\n\n    rollbackDefaultTextStyle(targetStyle);\n\n    if (!useHoverLayer) {\n        cacheElementStl(elTarget);\n    }\n\n    // styles can be:\n    // {\n    //    label: {\n    //        show: false,\n    //        position: 'outside',\n    //        fontSize: 18\n    //    },\n    //    emphasis: {\n    //        label: {\n    //            show: true\n    //        }\n    //    }\n    // },\n    // where properties of `emphasis` may not appear in `normal`. We previously use\n    // module:echarts/util/model#defaultEmphasis to merge `normal` to `emphasis`.\n    // But consider rich text and setOption in merge mode, it is impossible to cover\n    // all properties in merge. So we use merge mode when setting style here, where\n    // only properties that is not `null/undefined` can be set. The disadventage:\n    // null/undefined can not be used to remove style any more in `emphasis`.\n    targetStyle.extendFrom(hoverStl);\n\n    setDefaultHoverFillStroke(targetStyle, hoverStl, 'fill');\n    setDefaultHoverFillStroke(targetStyle, hoverStl, 'stroke');\n\n    applyDefaultTextStyle(targetStyle);\n\n    if (!useHoverLayer) {\n        el.dirty(false);\n        el.z2 += Z2_EMPHASIS_LIFT;\n    }\n}\n\nfunction setDefaultHoverFillStroke(targetStyle, hoverStyle, prop) {\n    if (!hasFillOrStroke(hoverStyle[prop]) && hasFillOrStroke(targetStyle[prop])) {\n        targetStyle[prop] = liftColor(targetStyle[prop]);\n    }\n}\n\nfunction doSingleLeaveHover(el) {\n    var highlighted = el.__highlighted;\n\n    if (!highlighted) {\n        return;\n    }\n\n    el.__highlighted = false;\n\n    if (highlighted === 'layer') {\n        el.__zr && el.__zr.removeHover(el);\n    }\n    else if (highlighted) {\n        var style = el.style;\n\n        var normalStl = el.__cachedNormalStl;\n        if (normalStl) {\n            rollbackDefaultTextStyle(style);\n            // Consider null/undefined value, should use\n            // `setStyle` but not `extendFrom(stl, true)`.\n            el.setStyle(normalStl);\n            applyDefaultTextStyle(style);\n        }\n        // `__cachedNormalZ2` will not be reset if calling `setElementHoverStyle`\n        // when `el` is on emphasis state. So here by comparing with 1, we try\n        // hard to make the bug case rare.\n        var normalZ2 = el.__cachedNormalZ2;\n        if (normalZ2 != null && el.z2 - normalZ2 === Z2_EMPHASIS_LIFT) {\n            el.z2 = normalZ2;\n        }\n    }\n}\n\nfunction traverseCall(el, method) {\n    el.isGroup\n        ? el.traverse(function (child) {\n            !child.isGroup && method(child);\n        })\n        : method(el);\n}\n\n/**\n * Set hover style (namely \"emphasis style\") of element, based on the current\n * style of the given `el`.\n * This method should be called after all of the normal styles have been adopted\n * to the `el`. See the reason on `setHoverStyle`.\n *\n * @param {module:zrender/Element} el Should not be `zrender/container/Group`.\n * @param {Object|boolean} [hoverStl] The specified hover style.\n *        If set as `false`, disable the hover style.\n *        Similarly, The `el.hoverStyle` can alse be set\n *        as `false` to disable the hover style.\n *        Otherwise, use the default hover style if not provided.\n * @param {Object} [opt]\n * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`\n */\nfunction setElementHoverStyle(el, hoverStl) {\n    // For performance consideration, it might be better to make the \"hover style\" only the\n    // difference properties from the \"normal style\", but not a entire copy of all styles.\n    hoverStl = el.__hoverStl = hoverStl !== false && (hoverStl || {});\n    el.__hoverStlDirty = true;\n\n    // FIXME\n    // It is not completely right to save \"normal\"/\"emphasis\" flag on elements.\n    // It probably should be saved on `data` of series. Consider the cases:\n    // (1) A highlighted elements are moved out of the view port and re-enter\n    // again by dataZoom.\n    // (2) call `setOption` and replace elements totally when they are highlighted.\n    if (el.__highlighted) {\n        // Consider the case:\n        // The styles of a highlighted `el` is being updated. The new \"emphasis style\"\n        // should be adapted to the `el`. Notice here new \"normal styles\" should have\n        // been set outside and the cached \"normal style\" is out of date.\n        el.__cachedNormalStl = null;\n        // Do not clear `__cachedNormalZ2` here, because setting `z2` is not a constraint\n        // of this method. In most cases, `z2` is not set and hover style should be able\n        // to rollback. Of course, that would bring bug, but only in a rare case, see\n        // `doSingleLeaveHover` for details.\n        doSingleLeaveHover(el);\n\n        doSingleEnterHover(el);\n    }\n}\n\n/**\n * Emphasis (called by API) has higher priority than `mouseover`.\n * When element has been called to be entered emphasis, mouse over\n * should not trigger the highlight effect (for example, animation\n * scale) again, and `mouseout` should not downplay the highlight\n * effect. So the listener of `mouseover` and `mouseout` should\n * check `isInEmphasis`.\n *\n * @param {module:zrender/Element} el\n * @return {boolean}\n */\nfunction isInEmphasis(el) {\n    return el && el.__isEmphasisEntered;\n}\n\nfunction onElementMouseOver(e) {\n    if (this.__hoverSilentOnTouch && e.zrByTouch) {\n        return;\n    }\n\n    // Only if element is not in emphasis status\n    !this.__isEmphasisEntered && traverseCall(this, doSingleEnterHover);\n}\n\nfunction onElementMouseOut(e) {\n    if (this.__hoverSilentOnTouch && e.zrByTouch) {\n        return;\n    }\n\n    // Only if element is not in emphasis status\n    !this.__isEmphasisEntered && traverseCall(this, doSingleLeaveHover);\n}\n\nfunction enterEmphasis() {\n    this.__isEmphasisEntered = true;\n    traverseCall(this, doSingleEnterHover);\n}\n\nfunction leaveEmphasis() {\n    this.__isEmphasisEntered = false;\n    traverseCall(this, doSingleLeaveHover);\n}\n\n/**\n * Set hover style (namely \"emphasis style\") of element,\n * based on the current style of the given `el`.\n *\n * (1)\n * **CONSTRAINTS** for this method:\n * <A> This method MUST be called after all of the normal styles having been adopted\n * to the `el`.\n * <B> The input `hoverStyle` (that is, \"emphasis style\") MUST be the subset of the\n * \"normal style\" having been set to the el.\n * <C> `color` MUST be one of the \"normal styles\" (because color might be lifted as\n * a default hover style).\n *\n * The reason: this method treat the current style of the `el` as the \"normal style\"\n * and cache them when enter/update the \"emphasis style\". Consider the case: the `el`\n * is in \"emphasis\" state and `setOption`/`dispatchAction` trigger the style updating\n * logic, where the el should shift from the original emphasis style to the new\n * \"emphasis style\" and should be able to \"downplay\" back to the new \"normal style\".\n *\n * Indeed, it is error-prone to make a interface has so many constraints, but I have\n * not found a better solution yet to fit the backward compatibility, performance and\n * the current programming style.\n *\n * (2)\n * Call the method for a \"root\" element once. Do not call it for each descendants.\n * If the descendants elemenets of a group has itself hover style different from the\n * root group, we can simply mount the style on `el.hoverStyle` for them, but should\n * not call this method for them.\n *\n * @param {module:zrender/Element} el\n * @param {Object|boolean} [hoverStyle] See `graphic.setElementHoverStyle`.\n * @param {Object} [opt]\n * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`.\n */\nfunction setHoverStyle(el, hoverStyle, opt) {\n    el.isGroup\n        ? el.traverse(function (child) {\n            // If element has sepcified hoverStyle, then use it instead of given hoverStyle\n            // Often used when item group has a label element and it's hoverStyle is different\n            !child.isGroup && setElementHoverStyle(child, child.hoverStyle || hoverStyle);\n        })\n        : setElementHoverStyle(el, el.hoverStyle || hoverStyle);\n\n    setAsHoverStyleTrigger(el, opt);\n}\n\n/**\n * @param {Object|boolean} [opt] If `false`, means disable trigger.\n * @param {boolean} [opt.hoverSilentOnTouch=false]\n *        In touch device, mouseover event will be trigger on touchstart event\n *        (see module:zrender/dom/HandlerProxy). By this mechanism, we can\n *        conveniently use hoverStyle when tap on touch screen without additional\n *        code for compatibility.\n *        But if the chart/component has select feature, which usually also use\n *        hoverStyle, there might be conflict between 'select-highlight' and\n *        'hover-highlight' especially when roam is enabled (see geo for example).\n *        In this case, hoverSilentOnTouch should be used to disable hover-highlight\n *        on touch device.\n */\nfunction setAsHoverStyleTrigger(el, opt) {\n    var disable = opt === false;\n    el.__hoverSilentOnTouch = opt != null && opt.hoverSilentOnTouch;\n\n    // Simple optimize, since this method might be\n    // called for each elements of a group in some cases.\n    if (!disable || el.__hoverStyleTrigger) {\n        var method = disable ? 'off' : 'on';\n\n        // Duplicated function will be auto-ignored, see Eventful.js.\n        el[method]('mouseover', onElementMouseOver)[method]('mouseout', onElementMouseOut);\n        // Emphasis, normal can be triggered manually\n        el[method]('emphasis', enterEmphasis)[method]('normal', leaveEmphasis);\n\n        el.__hoverStyleTrigger = !disable;\n    }\n}\n\n/**\n * See more info in `setTextStyleCommon`.\n * @param {Object|module:zrender/graphic/Style} normalStyle\n * @param {Object} emphasisStyle\n * @param {module:echarts/model/Model} normalModel\n * @param {module:echarts/model/Model} emphasisModel\n * @param {Object} opt Check `opt` of `setTextStyleCommon` to find other props.\n * @param {string|Function} [opt.defaultText]\n * @param {module:echarts/model/Model} [opt.labelFetcher] Fetch text by\n *      `opt.labelFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {module:echarts/model/Model} [opt.labelDataIndex] Fetch text by\n *      `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {module:echarts/model/Model} [opt.labelDimIndex] Fetch text by\n *      `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {Object} [normalSpecified]\n * @param {Object} [emphasisSpecified]\n */\nfunction setLabelStyle(\n    normalStyle, emphasisStyle,\n    normalModel, emphasisModel,\n    opt,\n    normalSpecified, emphasisSpecified\n) {\n    opt = opt || EMPTY_OBJ;\n    var labelFetcher = opt.labelFetcher;\n    var labelDataIndex = opt.labelDataIndex;\n    var labelDimIndex = opt.labelDimIndex;\n\n    // This scenario, `label.normal.show = true; label.emphasis.show = false`,\n    // is not supported util someone requests.\n\n    var showNormal = normalModel.getShallow('show');\n    var showEmphasis = emphasisModel.getShallow('show');\n\n    // Consider performance, only fetch label when necessary.\n    // If `normal.show` is `false` and `emphasis.show` is `true` and `emphasis.formatter` is not set,\n    // label should be displayed, where text is fetched by `normal.formatter` or `opt.defaultText`.\n    var baseText;\n    if (showNormal || showEmphasis) {\n        if (labelFetcher) {\n            baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex);\n        }\n        if (baseText == null) {\n            baseText = isFunction$1(opt.defaultText) ? opt.defaultText(labelDataIndex, opt) : opt.defaultText;\n        }\n    }\n    var normalStyleText = showNormal ? baseText : null;\n    var emphasisStyleText = showEmphasis\n        ? retrieve2(\n            labelFetcher\n                ? labelFetcher.getFormattedLabel(labelDataIndex, 'emphasis', null, labelDimIndex)\n                : null,\n            baseText\n        )\n        : null;\n\n    // Optimize: If style.text is null, text will not be drawn.\n    if (normalStyleText != null || emphasisStyleText != null) {\n        // Always set `textStyle` even if `normalStyle.text` is null, because default\n        // values have to be set on `normalStyle`.\n        // If we set default values on `emphasisStyle`, consider case:\n        // Firstly, `setOption(... label: {normal: {text: null}, emphasis: {show: true}} ...);`\n        // Secondly, `setOption(... label: {noraml: {show: true, text: 'abc', color: 'red'} ...);`\n        // Then the 'red' will not work on emphasis.\n        setTextStyle(normalStyle, normalModel, normalSpecified, opt);\n        setTextStyle(emphasisStyle, emphasisModel, emphasisSpecified, opt, true);\n    }\n\n    normalStyle.text = normalStyleText;\n    emphasisStyle.text = emphasisStyleText;\n}\n\n/**\n * Set basic textStyle properties.\n * See more info in `setTextStyleCommon`.\n * @param {Object|module:zrender/graphic/Style} textStyle\n * @param {module:echarts/model/Model} model\n * @param {Object} [specifiedTextStyle] Can be overrided by settings in model.\n * @param {Object} [opt] See `opt` of `setTextStyleCommon`.\n * @param {boolean} [isEmphasis]\n */\nfunction setTextStyle(\n    textStyle, textStyleModel, specifiedTextStyle, opt, isEmphasis\n) {\n    setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis);\n    specifiedTextStyle && extend(textStyle, specifiedTextStyle);\n    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);\n\n    return textStyle;\n}\n\n/**\n * Set text option in the style.\n * See more info in `setTextStyleCommon`.\n * @deprecated\n * @param {Object} textStyle\n * @param {module:echarts/model/Model} labelModel\n * @param {string|boolean} defaultColor Default text color.\n *        If set as false, it will be processed as a emphasis style.\n */\nfunction setText(textStyle, labelModel, defaultColor) {\n    var opt = {isRectText: true};\n    var isEmphasis;\n\n    if (defaultColor === false) {\n        isEmphasis = true;\n    }\n    else {\n        // Support setting color as 'auto' to get visual color.\n        opt.autoColor = defaultColor;\n    }\n    setTextStyleCommon(textStyle, labelModel, opt, isEmphasis);\n    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);\n}\n\n/**\n * The uniform entry of set text style, that is, retrieve style definitions\n * from `model` and set to `textStyle` object.\n *\n * Never in merge mode, but in overwrite mode, that is, all of the text style\n * properties will be set. (Consider the states of normal and emphasis and\n * default value can be adopted, merge would make the logic too complicated\n * to manage.)\n *\n * The `textStyle` object can either be a plain object or an instance of\n * `zrender/src/graphic/Style`, and either be the style of normal or emphasis.\n * After this mothod called, the `textStyle` object can then be used in\n * `el.setStyle(textStyle)` or `el.hoverStyle = textStyle`.\n *\n * Default value will be adopted and `insideRollbackOpt` will be created.\n * See `applyDefaultTextStyle` `rollbackDefaultTextStyle` for more details.\n *\n * opt: {\n *      disableBox: boolean, Whether diable drawing box of block (outer most).\n *      isRectText: boolean,\n *      autoColor: string, specify a color when color is 'auto',\n *              for textFill, textStroke, textBackgroundColor, and textBorderColor.\n *              If autoColor specified, it is used as default textFill.\n *      useInsideStyle:\n *              `true`: Use inside style (textFill, textStroke, textStrokeWidth)\n *                  if `textFill` is not specified.\n *              `false`: Do not use inside style.\n *              `null/undefined`: use inside style if `isRectText` is true and\n *                  `textFill` is not specified and textPosition contains `'inside'`.\n *      forceRich: boolean\n * }\n */\nfunction setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis) {\n    // Consider there will be abnormal when merge hover style to normal style if given default value.\n    opt = opt || EMPTY_OBJ;\n\n    if (opt.isRectText) {\n        var textPosition = textStyleModel.getShallow('position')\n            || (isEmphasis ? null : 'inside');\n        // 'outside' is not a valid zr textPostion value, but used\n        // in bar series, and magric type should be considered.\n        textPosition === 'outside' && (textPosition = 'top');\n        textStyle.textPosition = textPosition;\n        textStyle.textOffset = textStyleModel.getShallow('offset');\n        var labelRotate = textStyleModel.getShallow('rotate');\n        labelRotate != null && (labelRotate *= Math.PI / 180);\n        textStyle.textRotation = labelRotate;\n        textStyle.textDistance = retrieve2(\n            textStyleModel.getShallow('distance'), isEmphasis ? null : 5\n        );\n    }\n\n    var ecModel = textStyleModel.ecModel;\n    var globalTextStyle = ecModel && ecModel.option.textStyle;\n\n    // Consider case:\n    // {\n    //     data: [{\n    //         value: 12,\n    //         label: {\n    //             rich: {\n    //                 // no 'a' here but using parent 'a'.\n    //             }\n    //         }\n    //     }],\n    //     rich: {\n    //         a: { ... }\n    //     }\n    // }\n    var richItemNames = getRichItemNames(textStyleModel);\n    var richResult;\n    if (richItemNames) {\n        richResult = {};\n        for (var name in richItemNames) {\n            if (richItemNames.hasOwnProperty(name)) {\n                // Cascade is supported in rich.\n                var richTextStyle = textStyleModel.getModel(['rich', name]);\n                // In rich, never `disableBox`.\n                setTokenTextStyle(richResult[name] = {}, richTextStyle, globalTextStyle, opt, isEmphasis);\n            }\n        }\n    }\n    textStyle.rich = richResult;\n\n    setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, true);\n\n    if (opt.forceRich && !opt.textStyle) {\n        opt.textStyle = {};\n    }\n\n    return textStyle;\n}\n\n// Consider case:\n// {\n//     data: [{\n//         value: 12,\n//         label: {\n//             rich: {\n//                 // no 'a' here but using parent 'a'.\n//             }\n//         }\n//     }],\n//     rich: {\n//         a: { ... }\n//     }\n// }\nfunction getRichItemNames(textStyleModel) {\n    // Use object to remove duplicated names.\n    var richItemNameMap;\n    while (textStyleModel && textStyleModel !== textStyleModel.ecModel) {\n        var rich = (textStyleModel.option || EMPTY_OBJ).rich;\n        if (rich) {\n            richItemNameMap = richItemNameMap || {};\n            for (var name in rich) {\n                if (rich.hasOwnProperty(name)) {\n                    richItemNameMap[name] = 1;\n                }\n            }\n        }\n        textStyleModel = textStyleModel.parentModel;\n    }\n    return richItemNameMap;\n}\n\nfunction setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, isBlock) {\n    // In merge mode, default value should not be given.\n    globalTextStyle = !isEmphasis && globalTextStyle || EMPTY_OBJ;\n\n    textStyle.textFill = getAutoColor(textStyleModel.getShallow('color'), opt)\n        || globalTextStyle.color;\n    textStyle.textStroke = getAutoColor(textStyleModel.getShallow('textBorderColor'), opt)\n        || globalTextStyle.textBorderColor;\n    textStyle.textStrokeWidth = retrieve2(\n        textStyleModel.getShallow('textBorderWidth'),\n        globalTextStyle.textBorderWidth\n    );\n\n    // Save original textPosition, because style.textPosition will be repalced by\n    // real location (like [10, 30]) in zrender.\n    textStyle.insideRawTextPosition = textStyle.textPosition;\n\n    if (!isEmphasis) {\n        if (isBlock) {\n            textStyle.insideRollbackOpt = opt;\n            applyDefaultTextStyle(textStyle);\n        }\n\n        // Set default finally.\n        if (textStyle.textFill == null) {\n            textStyle.textFill = opt.autoColor;\n        }\n    }\n\n    // Do not use `getFont` here, because merge should be supported, where\n    // part of these properties may be changed in emphasis style, and the\n    // others should remain their original value got from normal style.\n    textStyle.fontStyle = textStyleModel.getShallow('fontStyle') || globalTextStyle.fontStyle;\n    textStyle.fontWeight = textStyleModel.getShallow('fontWeight') || globalTextStyle.fontWeight;\n    textStyle.fontSize = textStyleModel.getShallow('fontSize') || globalTextStyle.fontSize;\n    textStyle.fontFamily = textStyleModel.getShallow('fontFamily') || globalTextStyle.fontFamily;\n\n    textStyle.textAlign = textStyleModel.getShallow('align');\n    textStyle.textVerticalAlign = textStyleModel.getShallow('verticalAlign')\n        || textStyleModel.getShallow('baseline');\n\n    textStyle.textLineHeight = textStyleModel.getShallow('lineHeight');\n    textStyle.textWidth = textStyleModel.getShallow('width');\n    textStyle.textHeight = textStyleModel.getShallow('height');\n    textStyle.textTag = textStyleModel.getShallow('tag');\n\n    if (!isBlock || !opt.disableBox) {\n        textStyle.textBackgroundColor = getAutoColor(textStyleModel.getShallow('backgroundColor'), opt);\n        textStyle.textPadding = textStyleModel.getShallow('padding');\n        textStyle.textBorderColor = getAutoColor(textStyleModel.getShallow('borderColor'), opt);\n        textStyle.textBorderWidth = textStyleModel.getShallow('borderWidth');\n        textStyle.textBorderRadius = textStyleModel.getShallow('borderRadius');\n\n        textStyle.textBoxShadowColor = textStyleModel.getShallow('shadowColor');\n        textStyle.textBoxShadowBlur = textStyleModel.getShallow('shadowBlur');\n        textStyle.textBoxShadowOffsetX = textStyleModel.getShallow('shadowOffsetX');\n        textStyle.textBoxShadowOffsetY = textStyleModel.getShallow('shadowOffsetY');\n    }\n\n    textStyle.textShadowColor = textStyleModel.getShallow('textShadowColor')\n        || globalTextStyle.textShadowColor;\n    textStyle.textShadowBlur = textStyleModel.getShallow('textShadowBlur')\n        || globalTextStyle.textShadowBlur;\n    textStyle.textShadowOffsetX = textStyleModel.getShallow('textShadowOffsetX')\n        || globalTextStyle.textShadowOffsetX;\n    textStyle.textShadowOffsetY = textStyleModel.getShallow('textShadowOffsetY')\n        || globalTextStyle.textShadowOffsetY;\n}\n\nfunction getAutoColor(color, opt) {\n    return color !== 'auto' ? color : (opt && opt.autoColor) ? opt.autoColor : null;\n}\n\n/**\n * Give some default value to the input `textStyle` object, based on the current settings\n * in this `textStyle` object.\n *\n * The Scenario:\n * when text position is `inside` and `textFill` is not specified, we show\n * text border by default for better view. But it should be considered that text position\n * might be changed when hovering or being emphasis, where the `insideRollback` is used to\n * restore the style.\n *\n * Usage (& NOTICE):\n * When a style object (eithor plain object or instance of `zrender/src/graphic/Style`) is\n * about to be modified on its text related properties, `rollbackDefaultTextStyle` should\n * be called before the modification and `applyDefaultTextStyle` should be called after that.\n * (For the case that all of the text related properties is reset, like `setTextStyleCommon`\n * does, `rollbackDefaultTextStyle` is not needed to be called).\n */\nfunction applyDefaultTextStyle(textStyle) {\n    var opt = textStyle.insideRollbackOpt;\n\n    // Only `insideRollbackOpt` created (in `setTextStyleCommon`),\n    // applyDefaultTextStyle works.\n    if (!opt || textStyle.textFill != null) {\n        return;\n    }\n\n    var useInsideStyle = opt.useInsideStyle;\n    var textPosition = textStyle.insideRawTextPosition;\n    var insideRollback;\n    var autoColor = opt.autoColor;\n\n    if (useInsideStyle !== false\n        && (useInsideStyle === true\n            || (opt.isRectText\n                && textPosition\n                // textPosition can be [10, 30]\n                && typeof textPosition === 'string'\n                && textPosition.indexOf('inside') >= 0\n            )\n        )\n    ) {\n        insideRollback = {\n            textFill: null,\n            textStroke: textStyle.textStroke,\n            textStrokeWidth: textStyle.textStrokeWidth\n        };\n        textStyle.textFill = '#fff';\n        // Consider text with #fff overflow its container.\n        if (textStyle.textStroke == null) {\n            textStyle.textStroke = autoColor;\n            textStyle.textStrokeWidth == null && (textStyle.textStrokeWidth = 2);\n        }\n    }\n    else if (autoColor != null) {\n        insideRollback = {textFill: null};\n        textStyle.textFill = autoColor;\n    }\n\n    // Always set `insideRollback`, for clearing previous.\n    if (insideRollback) {\n        textStyle.insideRollback = insideRollback;\n    }\n}\n\n/**\n * Consider the case: in a scatter,\n * label: {\n *     normal: {position: 'inside'},\n *     emphasis: {position: 'top'}\n * }\n * In the normal state, the `textFill` will be set as '#fff' for pretty view (see\n * `applyDefaultTextStyle`), but when switching to emphasis state, the `textFill`\n * should be retured to 'autoColor', but not keep '#fff'.\n */\nfunction rollbackDefaultTextStyle(style) {\n    var insideRollback = style.insideRollback;\n    if (insideRollback) {\n        style.textFill = insideRollback.textFill;\n        style.textStroke = insideRollback.textStroke;\n        style.textStrokeWidth = insideRollback.textStrokeWidth;\n        style.insideRollback = null;\n    }\n}\n\nfunction getFont(opt, ecModel) {\n    // ecModel or default text style model.\n    var gTextStyleModel = ecModel || ecModel.getModel('textStyle');\n    return trim([\n        // FIXME in node-canvas fontWeight is before fontStyle\n        opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '',\n        opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '',\n        (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px',\n        opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'\n    ].join(' '));\n}\n\nfunction animateOrSetProps(isUpdate, el, props, animatableModel, dataIndex, cb) {\n    if (typeof dataIndex === 'function') {\n        cb = dataIndex;\n        dataIndex = null;\n    }\n    // Do not check 'animation' property directly here. Consider this case:\n    // animation model is an `itemModel`, whose does not have `isAnimationEnabled`\n    // but its parent model (`seriesModel`) does.\n    var animationEnabled = animatableModel && animatableModel.isAnimationEnabled();\n\n    if (animationEnabled) {\n        var postfix = isUpdate ? 'Update' : '';\n        var duration = animatableModel.getShallow('animationDuration' + postfix);\n        var animationEasing = animatableModel.getShallow('animationEasing' + postfix);\n        var animationDelay = animatableModel.getShallow('animationDelay' + postfix);\n        if (typeof animationDelay === 'function') {\n            animationDelay = animationDelay(\n                dataIndex,\n                animatableModel.getAnimationDelayParams\n                    ? animatableModel.getAnimationDelayParams(el, dataIndex)\n                    : null\n            );\n        }\n        if (typeof duration === 'function') {\n            duration = duration(dataIndex);\n        }\n\n        duration > 0\n            ? el.animateTo(props, duration, animationDelay || 0, animationEasing, cb, !!cb)\n            : (el.stopAnimation(), el.attr(props), cb && cb());\n    }\n    else {\n        el.stopAnimation();\n        el.attr(props);\n        cb && cb();\n    }\n}\n\n/**\n * Update graphic element properties with or without animation according to the\n * configuration in series.\n *\n * Caution: this method will stop previous animation.\n * So if do not use this method to one element twice before\n * animation starts, unless you know what you are doing.\n *\n * @param {module:zrender/Element} el\n * @param {Object} props\n * @param {module:echarts/model/Model} [animatableModel]\n * @param {number} [dataIndex]\n * @param {Function} [cb]\n * @example\n *     graphic.updateProps(el, {\n *         position: [100, 100]\n *     }, seriesModel, dataIndex, function () { console.log('Animation done!'); });\n *     // Or\n *     graphic.updateProps(el, {\n *         position: [100, 100]\n *     }, seriesModel, function () { console.log('Animation done!'); });\n */\nfunction updateProps(el, props, animatableModel, dataIndex, cb) {\n    animateOrSetProps(true, el, props, animatableModel, dataIndex, cb);\n}\n\n/**\n * Init graphic element properties with or without animation according to the\n * configuration in series.\n *\n * Caution: this method will stop previous animation.\n * So if do not use this method to one element twice before\n * animation starts, unless you know what you are doing.\n *\n * @param {module:zrender/Element} el\n * @param {Object} props\n * @param {module:echarts/model/Model} [animatableModel]\n * @param {number} [dataIndex]\n * @param {Function} cb\n */\nfunction initProps(el, props, animatableModel, dataIndex, cb) {\n    animateOrSetProps(false, el, props, animatableModel, dataIndex, cb);\n}\n\n/**\n * Get transform matrix of target (param target),\n * in coordinate of its ancestor (param ancestor)\n *\n * @param {module:zrender/mixin/Transformable} target\n * @param {module:zrender/mixin/Transformable} [ancestor]\n */\nfunction getTransform(target, ancestor) {\n    var mat = identity([]);\n\n    while (target && target !== ancestor) {\n        mul$1(mat, target.getLocalTransform(), mat);\n        target = target.parent;\n    }\n\n    return mat;\n}\n\n/**\n * Apply transform to an vertex.\n * @param {Array.<number>} target [x, y]\n * @param {Array.<number>|TypedArray.<number>|Object} transform Can be:\n *      + Transform matrix: like [1, 0, 0, 1, 0, 0]\n *      + {position, rotation, scale}, the same as `zrender/Transformable`.\n * @param {boolean=} invert Whether use invert matrix.\n * @return {Array.<number>} [x, y]\n */\nfunction applyTransform$1(target, transform, invert$$1) {\n    if (transform && !isArrayLike(transform)) {\n        transform = Transformable.getLocalTransform(transform);\n    }\n\n    if (invert$$1) {\n        transform = invert([], transform);\n    }\n    return applyTransform([], target, transform);\n}\n\n/**\n * @param {string} direction 'left' 'right' 'top' 'bottom'\n * @param {Array.<number>} transform Transform matrix: like [1, 0, 0, 1, 0, 0]\n * @param {boolean=} invert Whether use invert matrix.\n * @return {string} Transformed direction. 'left' 'right' 'top' 'bottom'\n */\nfunction transformDirection(direction, transform, invert$$1) {\n\n    // Pick a base, ensure that transform result will not be (0, 0).\n    var hBase = (transform[4] === 0 || transform[5] === 0 || transform[0] === 0)\n        ? 1 : Math.abs(2 * transform[4] / transform[0]);\n    var vBase = (transform[4] === 0 || transform[5] === 0 || transform[2] === 0)\n        ? 1 : Math.abs(2 * transform[4] / transform[2]);\n\n    var vertex = [\n        direction === 'left' ? -hBase : direction === 'right' ? hBase : 0,\n        direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0\n    ];\n\n    vertex = applyTransform$1(vertex, transform, invert$$1);\n\n    return Math.abs(vertex[0]) > Math.abs(vertex[1])\n        ? (vertex[0] > 0 ? 'right' : 'left')\n        : (vertex[1] > 0 ? 'bottom' : 'top');\n}\n\n/**\n * Apply group transition animation from g1 to g2.\n * If no animatableModel, no animation.\n */\nfunction groupTransition(g1, g2, animatableModel, cb) {\n    if (!g1 || !g2) {\n        return;\n    }\n\n    function getElMap(g) {\n        var elMap = {};\n        g.traverse(function (el) {\n            if (!el.isGroup && el.anid) {\n                elMap[el.anid] = el;\n            }\n        });\n        return elMap;\n    }\n    function getAnimatableProps(el) {\n        var obj = {\n            position: clone$1(el.position),\n            rotation: el.rotation\n        };\n        if (el.shape) {\n            obj.shape = extend({}, el.shape);\n        }\n        return obj;\n    }\n    var elMap1 = getElMap(g1);\n\n    g2.traverse(function (el) {\n        if (!el.isGroup && el.anid) {\n            var oldEl = elMap1[el.anid];\n            if (oldEl) {\n                var newProp = getAnimatableProps(el);\n                el.attr(getAnimatableProps(oldEl));\n                updateProps(el, newProp, animatableModel, el.dataIndex);\n            }\n            // else {\n            //     if (el.previousProps) {\n            //         graphic.updateProps\n            //     }\n            // }\n        }\n    });\n}\n\n/**\n * @param {Array.<Array.<number>>} points Like: [[23, 44], [53, 66], ...]\n * @param {Object} rect {x, y, width, height}\n * @return {Array.<Array.<number>>} A new clipped points.\n */\nfunction clipPointsByRect(points, rect) {\n    // FIXME: this way migth be incorrect when grpahic clipped by a corner.\n    // and when element have border.\n    return map(points, function (point) {\n        var x = point[0];\n        x = mathMax$1(x, rect.x);\n        x = mathMin$1(x, rect.x + rect.width);\n        var y = point[1];\n        y = mathMax$1(y, rect.y);\n        y = mathMin$1(y, rect.y + rect.height);\n        return [x, y];\n    });\n}\n\n/**\n * @param {Object} targetRect {x, y, width, height}\n * @param {Object} rect {x, y, width, height}\n * @return {Object} A new clipped rect. If rect size are negative, return undefined.\n */\nfunction clipRectByRect(targetRect, rect) {\n    var x = mathMax$1(targetRect.x, rect.x);\n    var x2 = mathMin$1(targetRect.x + targetRect.width, rect.x + rect.width);\n    var y = mathMax$1(targetRect.y, rect.y);\n    var y2 = mathMin$1(targetRect.y + targetRect.height, rect.y + rect.height);\n\n    // If the total rect is cliped, nothing, including the border,\n    // should be painted. So return undefined.\n    if (x2 >= x && y2 >= y) {\n        return {\n            x: x,\n            y: y,\n            width: x2 - x,\n            height: y2 - y\n        };\n    }\n}\n\n/**\n * @param {string} iconStr Support 'image://' or 'path://' or direct svg path.\n * @param {Object} [opt] Properties of `module:zrender/Element`, except `style`.\n * @param {Object} [rect] {x, y, width, height}\n * @return {module:zrender/Element} Icon path or image element.\n */\nfunction createIcon(iconStr, opt, rect) {\n    opt = extend({rectHover: true}, opt);\n    var style = opt.style = {strokeNoScale: true};\n    rect = rect || {x: -1, y: -1, width: 2, height: 2};\n\n    if (iconStr) {\n        return iconStr.indexOf('image://') === 0\n            ? (\n                style.image = iconStr.slice(8),\n                defaults(style, rect),\n                new ZImage(opt)\n            )\n            : (\n                makePath(\n                    iconStr.replace('path://', ''),\n                    opt,\n                    rect,\n                    'center'\n                )\n            );\n    }\n}\n\n\n\n\nvar graphic = (Object.freeze || Object)({\n\tZ2_EMPHASIS_LIFT: Z2_EMPHASIS_LIFT,\n\textendShape: extendShape,\n\textendPath: extendPath,\n\tmakePath: makePath,\n\tmakeImage: makeImage,\n\tmergePath: mergePath,\n\tresizePath: resizePath,\n\tsubPixelOptimizeLine: subPixelOptimizeLine,\n\tsubPixelOptimizeRect: subPixelOptimizeRect,\n\tsubPixelOptimize: subPixelOptimize,\n\tsetElementHoverStyle: setElementHoverStyle,\n\tisInEmphasis: isInEmphasis,\n\tsetHoverStyle: setHoverStyle,\n\tsetAsHoverStyleTrigger: setAsHoverStyleTrigger,\n\tsetLabelStyle: setLabelStyle,\n\tsetTextStyle: setTextStyle,\n\tsetText: setText,\n\tgetFont: getFont,\n\tupdateProps: updateProps,\n\tinitProps: initProps,\n\tgetTransform: getTransform,\n\tapplyTransform: applyTransform$1,\n\ttransformDirection: transformDirection,\n\tgroupTransition: groupTransition,\n\tclipPointsByRect: clipPointsByRect,\n\tclipRectByRect: clipRectByRect,\n\tcreateIcon: createIcon,\n\tGroup: Group,\n\tImage: ZImage,\n\tText: Text,\n\tCircle: Circle,\n\tSector: Sector,\n\tRing: Ring,\n\tPolygon: Polygon,\n\tPolyline: Polyline,\n\tRect: Rect,\n\tLine: Line,\n\tBezierCurve: BezierCurve,\n\tArc: Arc,\n\tIncrementalDisplayable: IncrementalDisplayble,\n\tCompoundPath: CompoundPath,\n\tLinearGradient: LinearGradient,\n\tRadialGradient: RadialGradient,\n\tBoundingRect: BoundingRect\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PATH_COLOR = ['textStyle', 'color'];\n\nvar textStyleMixin = {\n    /**\n     * Get color property or get color from option.textStyle.color\n     * @param {boolean} [isEmphasis]\n     * @return {string}\n     */\n    getTextColor: function (isEmphasis) {\n        var ecModel = this.ecModel;\n        return this.getShallow('color')\n            || (\n                (!isEmphasis && ecModel) ? ecModel.get(PATH_COLOR) : null\n            );\n    },\n\n    /**\n     * Create font string from fontStyle, fontWeight, fontSize, fontFamily\n     * @return {string}\n     */\n    getFont: function () {\n        return getFont({\n            fontStyle: this.getShallow('fontStyle'),\n            fontWeight: this.getShallow('fontWeight'),\n            fontSize: this.getShallow('fontSize'),\n            fontFamily: this.getShallow('fontFamily')\n        }, this.ecModel);\n    },\n\n    getTextRect: function (text) {\n        return getBoundingRect(\n            text,\n            this.getFont(),\n            this.getShallow('align'),\n            this.getShallow('verticalAlign') || this.getShallow('baseline'),\n            this.getShallow('padding'),\n            this.getShallow('lineHeight'),\n            this.getShallow('rich'),\n            this.getShallow('truncateText')\n        );\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getItemStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['stroke', 'borderColor'],\n        ['lineWidth', 'borderWidth'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor'],\n        ['textPosition'],\n        ['textAlign']\n    ]\n);\n\nvar itemStyleMixin = {\n    getItemStyle: function (excludes, includes) {\n        var style = getItemStyle(this, excludes, includes);\n        var lineDash = this.getBorderLineDash();\n        lineDash && (style.lineDash = lineDash);\n        return style;\n    },\n\n    getBorderLineDash: function () {\n        var lineType = this.get('borderType');\n        return (lineType === 'solid' || lineType == null) ? null\n            : (lineType === 'dashed' ? [5, 5] : [1, 1]);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/model/Model\n */\n\nvar mixin$1 = mixin;\nvar inner = makeInner();\n\n/**\n * @alias module:echarts/model/Model\n * @constructor\n * @param {Object} [option]\n * @param {module:echarts/model/Model} [parentModel]\n * @param {module:echarts/model/Global} [ecModel]\n */\nfunction Model(option, parentModel, ecModel) {\n    /**\n     * @type {module:echarts/model/Model}\n     * @readOnly\n     */\n    this.parentModel = parentModel;\n\n    /**\n     * @type {module:echarts/model/Global}\n     * @readOnly\n     */\n    this.ecModel = ecModel;\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    this.option = option;\n\n    // Simple optimization\n    // if (this.init) {\n    //     if (arguments.length <= 4) {\n    //         this.init(option, parentModel, ecModel, extraOpt);\n    //     }\n    //     else {\n    //         this.init.apply(this, arguments);\n    //     }\n    // }\n}\n\nModel.prototype = {\n\n    constructor: Model,\n\n    /**\n     * Model 的初始化函数\n     * @param {Object} option\n     */\n    init: null,\n\n    /**\n     * 从新的 Option merge\n     */\n    mergeOption: function (option) {\n        merge(this.option, option, true);\n    },\n\n    /**\n     * @param {string|Array.<string>} path\n     * @param {boolean} [ignoreParent=false]\n     * @return {*}\n     */\n    get: function (path, ignoreParent) {\n        if (path == null) {\n            return this.option;\n        }\n\n        return doGet(\n            this.option,\n            this.parsePath(path),\n            !ignoreParent && getParent(this, path)\n        );\n    },\n\n    /**\n     * @param {string} key\n     * @param {boolean} [ignoreParent=false]\n     * @return {*}\n     */\n    getShallow: function (key, ignoreParent) {\n        var option = this.option;\n\n        var val = option == null ? option : option[key];\n        var parentModel = !ignoreParent && getParent(this, key);\n        if (val == null && parentModel) {\n            val = parentModel.getShallow(key);\n        }\n        return val;\n    },\n\n    /**\n     * @param {string|Array.<string>} [path]\n     * @param {module:echarts/model/Model} [parentModel]\n     * @return {module:echarts/model/Model}\n     */\n    getModel: function (path, parentModel) {\n        var obj = path == null\n            ? this.option\n            : doGet(this.option, path = this.parsePath(path));\n\n        var thisParentModel;\n        parentModel = parentModel || (\n            (thisParentModel = getParent(this, path))\n                && thisParentModel.getModel(path)\n        );\n\n        return new Model(obj, parentModel, this.ecModel);\n    },\n\n    /**\n     * If model has option\n     */\n    isEmpty: function () {\n        return this.option == null;\n    },\n\n    restoreData: function () {},\n\n    // Pending\n    clone: function () {\n        var Ctor = this.constructor;\n        return new Ctor(clone(this.option));\n    },\n\n    setReadOnly: function (properties) {\n        // clazzUtil.setReadOnly(this, properties);\n    },\n\n    // If path is null/undefined, return null/undefined.\n    parsePath: function (path) {\n        if (typeof path === 'string') {\n            path = path.split('.');\n        }\n        return path;\n    },\n\n    /**\n     * @param {Function} getParentMethod\n     *        param {Array.<string>|string} path\n     *        return {module:echarts/model/Model}\n     */\n    customizeGetParent: function (getParentMethod) {\n        inner(this).getParent = getParentMethod;\n    },\n\n    isAnimationEnabled: function () {\n        if (!env$1.node) {\n            if (this.option.animation != null) {\n                return !!this.option.animation;\n            }\n            else if (this.parentModel) {\n                return this.parentModel.isAnimationEnabled();\n            }\n        }\n    }\n\n};\n\nfunction doGet(obj, pathArr, parentModel) {\n    for (var i = 0; i < pathArr.length; i++) {\n        // Ignore empty\n        if (!pathArr[i]) {\n            continue;\n        }\n        // obj could be number/string/... (like 0)\n        obj = (obj && typeof obj === 'object') ? obj[pathArr[i]] : null;\n        if (obj == null) {\n            break;\n        }\n    }\n    if (obj == null && parentModel) {\n        obj = parentModel.get(pathArr);\n    }\n    return obj;\n}\n\n// `path` can be null/undefined\nfunction getParent(model, path) {\n    var getParentMethod = inner(model).getParent;\n    return getParentMethod ? getParentMethod.call(model, path) : model.parentModel;\n}\n\n// Enable Model.extend.\nenableClassExtend(Model);\nenableClassCheck(Model);\n\nmixin$1(Model, lineStyleMixin);\nmixin$1(Model, areaStyleMixin);\nmixin$1(Model, textStyleMixin);\nmixin$1(Model, itemStyleMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar base = 0;\n\n/**\n * @public\n * @param {string} type\n * @return {string}\n */\nfunction getUID(type) {\n    // Considering the case of crossing js context,\n    // use Math.random to make id as unique as possible.\n    return [(type || ''), base++, Math.random().toFixed(5)].join('_');\n}\n\n/**\n * @inner\n */\nfunction enableSubTypeDefaulter(entity) {\n\n    var subTypeDefaulters = {};\n\n    entity.registerSubTypeDefaulter = function (componentType, defaulter) {\n        componentType = parseClassType$1(componentType);\n        subTypeDefaulters[componentType.main] = defaulter;\n    };\n\n    entity.determineSubType = function (componentType, option) {\n        var type = option.type;\n        if (!type) {\n            var componentTypeMain = parseClassType$1(componentType).main;\n            if (entity.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) {\n                type = subTypeDefaulters[componentTypeMain](option);\n            }\n        }\n        return type;\n    };\n\n    return entity;\n}\n\n/**\n * Topological travel on Activity Network (Activity On Vertices).\n * Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis'].\n *\n * If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology.\n *\n * If there is circle dependencey, Error will be thrown.\n *\n */\nfunction enableTopologicalTravel(entity, dependencyGetter) {\n\n    /**\n     * @public\n     * @param {Array.<string>} targetNameList Target Component type list.\n     *                                           Can be ['aa', 'bb', 'aa.xx']\n     * @param {Array.<string>} fullNameList By which we can build dependency graph.\n     * @param {Function} callback Params: componentType, dependencies.\n     * @param {Object} context Scope of callback.\n     */\n    entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) {\n        if (!targetNameList.length) {\n            return;\n        }\n\n        var result = makeDepndencyGraph(fullNameList);\n        var graph = result.graph;\n        var stack = result.noEntryList;\n\n        var targetNameSet = {};\n        each$1(targetNameList, function (name) {\n            targetNameSet[name] = true;\n        });\n\n        while (stack.length) {\n            var currComponentType = stack.pop();\n            var currVertex = graph[currComponentType];\n            var isInTargetNameSet = !!targetNameSet[currComponentType];\n            if (isInTargetNameSet) {\n                callback.call(context, currComponentType, currVertex.originalDeps.slice());\n                delete targetNameSet[currComponentType];\n            }\n            each$1(\n                currVertex.successor,\n                isInTargetNameSet ? removeEdgeAndAdd : removeEdge\n            );\n        }\n\n        each$1(targetNameSet, function () {\n            throw new Error('Circle dependency may exists');\n        });\n\n        function removeEdge(succComponentType) {\n            graph[succComponentType].entryCount--;\n            if (graph[succComponentType].entryCount === 0) {\n                stack.push(succComponentType);\n            }\n        }\n\n        // Consider this case: legend depends on series, and we call\n        // chart.setOption({series: [...]}), where only series is in option.\n        // If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will\n        // not be called, but only sereis.mergeOption is called. Thus legend\n        // have no chance to update its local record about series (like which\n        // name of series is available in legend).\n        function removeEdgeAndAdd(succComponentType) {\n            targetNameSet[succComponentType] = true;\n            removeEdge(succComponentType);\n        }\n    };\n\n    /**\n     * DepndencyGraph: {Object}\n     * key: conponentType,\n     * value: {\n     *     successor: [conponentTypes...],\n     *     originalDeps: [conponentTypes...],\n     *     entryCount: {number}\n     * }\n     */\n    function makeDepndencyGraph(fullNameList) {\n        var graph = {};\n        var noEntryList = [];\n\n        each$1(fullNameList, function (name) {\n\n            var thisItem = createDependencyGraphItem(graph, name);\n            var originalDeps = thisItem.originalDeps = dependencyGetter(name);\n\n            var availableDeps = getAvailableDependencies(originalDeps, fullNameList);\n            thisItem.entryCount = availableDeps.length;\n            if (thisItem.entryCount === 0) {\n                noEntryList.push(name);\n            }\n\n            each$1(availableDeps, function (dependentName) {\n                if (indexOf(thisItem.predecessor, dependentName) < 0) {\n                    thisItem.predecessor.push(dependentName);\n                }\n                var thatItem = createDependencyGraphItem(graph, dependentName);\n                if (indexOf(thatItem.successor, dependentName) < 0) {\n                    thatItem.successor.push(name);\n                }\n            });\n        });\n\n        return {graph: graph, noEntryList: noEntryList};\n    }\n\n    function createDependencyGraphItem(graph, name) {\n        if (!graph[name]) {\n            graph[name] = {predecessor: [], successor: []};\n        }\n        return graph[name];\n    }\n\n    function getAvailableDependencies(originalDeps, fullNameList) {\n        var availableDeps = [];\n        each$1(originalDeps, function (dep) {\n            indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep);\n        });\n        return availableDeps;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The method \"quantile\" was copied from \"d3.js\".\n* (See more details in the comment of the method below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\nvar RADIAN_EPSILON = 1e-4;\n\nfunction _trim(str) {\n    return str.replace(/^\\s+/, '').replace(/\\s+$/, '');\n}\n\n/**\n * Linear mapping a value from domain to range\n * @memberOf module:echarts/util/number\n * @param  {(number|Array.<number>)} val\n * @param  {Array.<number>} domain Domain extent domain[0] can be bigger than domain[1]\n * @param  {Array.<number>} range  Range extent range[0] can be bigger than range[1]\n * @param  {boolean} clamp\n * @return {(number|Array.<number>}\n */\nfunction linearMap(val, domain, range, clamp) {\n    var subDomain = domain[1] - domain[0];\n    var subRange = range[1] - range[0];\n\n    if (subDomain === 0) {\n        return subRange === 0\n            ? range[0]\n            : (range[0] + range[1]) / 2;\n    }\n\n    // Avoid accuracy problem in edge, such as\n    // 146.39 - 62.83 === 83.55999999999999.\n    // See echarts/test/ut/spec/util/number.js#linearMap#accuracyError\n    // It is a little verbose for efficiency considering this method\n    // is a hotspot.\n    if (clamp) {\n        if (subDomain > 0) {\n            if (val <= domain[0]) {\n                return range[0];\n            }\n            else if (val >= domain[1]) {\n                return range[1];\n            }\n        }\n        else {\n            if (val >= domain[0]) {\n                return range[0];\n            }\n            else if (val <= domain[1]) {\n                return range[1];\n            }\n        }\n    }\n    else {\n        if (val === domain[0]) {\n            return range[0];\n        }\n        if (val === domain[1]) {\n            return range[1];\n        }\n    }\n\n    return (val - domain[0]) / subDomain * subRange + range[0];\n}\n\n/**\n * Convert a percent string to absolute number.\n * Returns NaN if percent is not a valid string or number\n * @memberOf module:echarts/util/number\n * @param {string|number} percent\n * @param {number} all\n * @return {number}\n */\nfunction parsePercent$1(percent, all) {\n    switch (percent) {\n        case 'center':\n        case 'middle':\n            percent = '50%';\n            break;\n        case 'left':\n        case 'top':\n            percent = '0%';\n            break;\n        case 'right':\n        case 'bottom':\n            percent = '100%';\n            break;\n    }\n    if (typeof percent === 'string') {\n        if (_trim(percent).match(/%$/)) {\n            return parseFloat(percent) / 100 * all;\n        }\n\n        return parseFloat(percent);\n    }\n\n    return percent == null ? NaN : +percent;\n}\n\n/**\n * (1) Fix rounding error of float numbers.\n * (2) Support return string to avoid scientific notation like '3.5e-7'.\n *\n * @param {number} x\n * @param {number} [precision]\n * @param {boolean} [returnStr]\n * @return {number|string}\n */\nfunction round$2(x, precision, returnStr) {\n    if (precision == null) {\n        precision = 10;\n    }\n    // Avoid range error\n    precision = Math.min(Math.max(0, precision), 20);\n    x = (+x).toFixed(precision);\n    return returnStr ? x : +x;\n}\n\nfunction asc(arr) {\n    arr.sort(function (a, b) {\n        return a - b;\n    });\n    return arr;\n}\n\n/**\n * Get precision\n * @param {number} val\n */\nfunction getPrecision(val) {\n    val = +val;\n    if (isNaN(val)) {\n        return 0;\n    }\n    // It is much faster than methods converting number to string as follows\n    //      var tmp = val.toString();\n    //      return tmp.length - 1 - tmp.indexOf('.');\n    // especially when precision is low\n    var e = 1;\n    var count = 0;\n    while (Math.round(val * e) / e !== val) {\n        e *= 10;\n        count++;\n    }\n    return count;\n}\n\n/**\n * @param {string|number} val\n * @return {number}\n */\nfunction getPrecisionSafe(val) {\n    var str = val.toString();\n\n    // Consider scientific notation: '3.4e-12' '3.4e+12'\n    var eIndex = str.indexOf('e');\n    if (eIndex > 0) {\n        var precision = +str.slice(eIndex + 1);\n        return precision < 0 ? -precision : 0;\n    }\n    else {\n        var dotIndex = str.indexOf('.');\n        return dotIndex < 0 ? 0 : str.length - 1 - dotIndex;\n    }\n}\n\n/**\n * Minimal dicernible data precisioin according to a single pixel.\n *\n * @param {Array.<number>} dataExtent\n * @param {Array.<number>} pixelExtent\n * @return {number} precision\n */\nfunction getPixelPrecision(dataExtent, pixelExtent) {\n    var log = Math.log;\n    var LN10 = Math.LN10;\n    var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10);\n    var sizeQuantity = Math.round(log(Math.abs(pixelExtent[1] - pixelExtent[0])) / LN10);\n    // toFixed() digits argument must be between 0 and 20.\n    var precision = Math.min(Math.max(-dataQuantity + sizeQuantity, 0), 20);\n    return !isFinite(precision) ? 20 : precision;\n}\n\n/**\n * Get a data of given precision, assuring the sum of percentages\n * in valueList is 1.\n * The largest remainer method is used.\n * https://en.wikipedia.org/wiki/Largest_remainder_method\n *\n * @param {Array.<number>} valueList a list of all data\n * @param {number} idx index of the data to be processed in valueList\n * @param {number} precision integer number showing digits of precision\n * @return {number} percent ranging from 0 to 100\n */\nfunction getPercentWithPrecision(valueList, idx, precision) {\n    if (!valueList[idx]) {\n        return 0;\n    }\n\n    var sum = reduce(valueList, function (acc, val) {\n        return acc + (isNaN(val) ? 0 : val);\n    }, 0);\n    if (sum === 0) {\n        return 0;\n    }\n\n    var digits = Math.pow(10, precision);\n    var votesPerQuota = map(valueList, function (val) {\n        return (isNaN(val) ? 0 : val) / sum * digits * 100;\n    });\n    var targetSeats = digits * 100;\n\n    var seats = map(votesPerQuota, function (votes) {\n        // Assign automatic seats.\n        return Math.floor(votes);\n    });\n    var currentSum = reduce(seats, function (acc, val) {\n        return acc + val;\n    }, 0);\n\n    var remainder = map(votesPerQuota, function (votes, idx) {\n        return votes - seats[idx];\n    });\n\n    // Has remainding votes.\n    while (currentSum < targetSeats) {\n        // Find next largest remainder.\n        var max = Number.NEGATIVE_INFINITY;\n        var maxId = null;\n        for (var i = 0, len = remainder.length; i < len; ++i) {\n            if (remainder[i] > max) {\n                max = remainder[i];\n                maxId = i;\n            }\n        }\n\n        // Add a vote to max remainder.\n        ++seats[maxId];\n        remainder[maxId] = 0;\n        ++currentSum;\n    }\n\n    return seats[idx] / digits;\n}\n\n// Number.MAX_SAFE_INTEGER, ie do not support.\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * To 0 - 2 * PI, considering negative radian.\n * @param {number} radian\n * @return {number}\n */\nfunction remRadian(radian) {\n    var pi2 = Math.PI * 2;\n    return (radian % pi2 + pi2) % pi2;\n}\n\n/**\n * @param {type} radian\n * @return {boolean}\n */\nfunction isRadianAroundZero(val) {\n    return val > -RADIAN_EPSILON && val < RADIAN_EPSILON;\n}\n\n/* eslint-disable */\nvar TIME_REG = /^(?:(\\d{4})(?:[-\\/](\\d{1,2})(?:[-\\/](\\d{1,2})(?:[T ](\\d{1,2})(?::(\\d\\d)(?::(\\d\\d)(?:[.,](\\d+))?)?)?(Z|[\\+\\-]\\d\\d:?\\d\\d)?)?)?)?)?$/; // jshint ignore:line\n/* eslint-enable */\n\n/**\n * @param {string|Date|number} value These values can be accepted:\n *   + An instance of Date, represent a time in its own time zone.\n *   + Or string in a subset of ISO 8601, only including:\n *     + only year, month, date: '2012-03', '2012-03-01', '2012-03-01 05', '2012-03-01 05:06',\n *     + separated with T or space: '2012-03-01T12:22:33.123', '2012-03-01 12:22:33.123',\n *     + time zone: '2012-03-01T12:22:33Z', '2012-03-01T12:22:33+8000', '2012-03-01T12:22:33-05:00',\n *     all of which will be treated as local time if time zone is not specified\n *     (see <https://momentjs.com/>).\n *   + Or other string format, including (all of which will be treated as loacal time):\n *     '2012', '2012-3-1', '2012/3/1', '2012/03/01',\n *     '2009/6/12 2:00', '2009/6/12 2:05:08', '2009/6/12 2:05:08.123'\n *   + a timestamp, which represent a time in UTC.\n * @return {Date} date\n */\nfunction parseDate(value) {\n    if (value instanceof Date) {\n        return value;\n    }\n    else if (typeof value === 'string') {\n        // Different browsers parse date in different way, so we parse it manually.\n        // Some other issues:\n        // new Date('1970-01-01') is UTC,\n        // new Date('1970/01/01') and new Date('1970-1-01') is local.\n        // See issue #3623\n        var match = TIME_REG.exec(value);\n\n        if (!match) {\n            // return Invalid Date.\n            return new Date(NaN);\n        }\n\n        // Use local time when no timezone offset specifed.\n        if (!match[8]) {\n            // match[n] can only be string or undefined.\n            // But take care of '12' + 1 => '121'.\n            return new Date(\n                +match[1],\n                +(match[2] || 1) - 1,\n                +match[3] || 1,\n                +match[4] || 0,\n                +(match[5] || 0),\n                +match[6] || 0,\n                +match[7] || 0\n            );\n        }\n        // Timezoneoffset of Javascript Date has considered DST (Daylight Saving Time,\n        // https://tc39.github.io/ecma262/#sec-daylight-saving-time-adjustment).\n        // For example, system timezone is set as \"Time Zone: America/Toronto\",\n        // then these code will get different result:\n        // `new Date(1478411999999).getTimezoneOffset();  // get 240`\n        // `new Date(1478412000000).getTimezoneOffset();  // get 300`\n        // So we should not use `new Date`, but use `Date.UTC`.\n        else {\n            var hour = +match[4] || 0;\n            if (match[8].toUpperCase() !== 'Z') {\n                hour -= match[8].slice(0, 3);\n            }\n            return new Date(Date.UTC(\n                +match[1],\n                +(match[2] || 1) - 1,\n                +match[3] || 1,\n                hour,\n                +(match[5] || 0),\n                +match[6] || 0,\n                +match[7] || 0\n            ));\n        }\n    }\n    else if (value == null) {\n        return new Date(NaN);\n    }\n\n    return new Date(Math.round(value));\n}\n\n/**\n * Quantity of a number. e.g. 0.1, 1, 10, 100\n *\n * @param  {number} val\n * @return {number}\n */\nfunction quantity(val) {\n    return Math.pow(10, quantityExponent(val));\n}\n\nfunction quantityExponent(val) {\n    return Math.floor(Math.log(val) / Math.LN10);\n}\n\n/**\n * find a “nice” number approximately equal to x. Round the number if round = true,\n * take ceiling if round = false. The primary observation is that the “nicest”\n * numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers.\n *\n * See \"Nice Numbers for Graph Labels\" of Graphic Gems.\n *\n * @param  {number} val Non-negative value.\n * @param  {boolean} round\n * @return {number}\n */\nfunction nice(val, round) {\n    var exponent = quantityExponent(val);\n    var exp10 = Math.pow(10, exponent);\n    var f = val / exp10; // 1 <= f < 10\n    var nf;\n    if (round) {\n        if (f < 1.5) {\n            nf = 1;\n        }\n        else if (f < 2.5) {\n            nf = 2;\n        }\n        else if (f < 4) {\n            nf = 3;\n        }\n        else if (f < 7) {\n            nf = 5;\n        }\n        else {\n            nf = 10;\n        }\n    }\n    else {\n        if (f < 1) {\n            nf = 1;\n        }\n        else if (f < 2) {\n            nf = 2;\n        }\n        else if (f < 3) {\n            nf = 3;\n        }\n        else if (f < 5) {\n            nf = 5;\n        }\n        else {\n            nf = 10;\n        }\n    }\n    val = nf * exp10;\n\n    // Fix 3 * 0.1 === 0.30000000000000004 issue (see IEEE 754).\n    // 20 is the uppper bound of toFixed.\n    return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val;\n}\n\n/**\n * This code was copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/9cc9a875e636a1dcf36cc1e07bdf77e1ad6e2c74/src/arrays/quantile.js>.\n * See the license statement at the head of this file.\n * @param {Array.<number>} ascArr\n */\nfunction quantile(ascArr, p) {\n    var H = (ascArr.length - 1) * p + 1;\n    var h = Math.floor(H);\n    var v = +ascArr[h - 1];\n    var e = H - h;\n    return e ? v + e * (ascArr[h] - v) : v;\n}\n\n/**\n * Order intervals asc, and split them when overlap.\n * expect(numberUtil.reformIntervals([\n *     {interval: [18, 62], close: [1, 1]},\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [1, 1]},\n *     {interval: [62, 150], close: [1, 1]},\n *     {interval: [106, 150], close: [1, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ])).toEqual([\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [0, 1]},\n *     {interval: [18, 62], close: [0, 1]},\n *     {interval: [62, 150], close: [0, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ]);\n * @param {Array.<Object>} list, where `close` mean open or close\n *        of the interval, and Infinity can be used.\n * @return {Array.<Object>} The origin list, which has been reformed.\n */\nfunction reformIntervals(list) {\n    list.sort(function (a, b) {\n        return littleThan(a, b, 0) ? -1 : 1;\n    });\n\n    var curr = -Infinity;\n    var currClose = 1;\n    for (var i = 0; i < list.length;) {\n        var interval = list[i].interval;\n        var close = list[i].close;\n\n        for (var lg = 0; lg < 2; lg++) {\n            if (interval[lg] <= curr) {\n                interval[lg] = curr;\n                close[lg] = !lg ? 1 - currClose : 1;\n            }\n            curr = interval[lg];\n            currClose = close[lg];\n        }\n\n        if (interval[0] === interval[1] && close[0] * close[1] !== 1) {\n            list.splice(i, 1);\n        }\n        else {\n            i++;\n        }\n    }\n\n    return list;\n\n    function littleThan(a, b, lg) {\n        return a.interval[lg] < b.interval[lg]\n            || (\n                a.interval[lg] === b.interval[lg]\n                && (\n                    (a.close[lg] - b.close[lg] === (!lg ? 1 : -1))\n                    || (!lg && littleThan(a, b, 1))\n                )\n            );\n    }\n}\n\n/**\n * parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n * ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n * subtraction forces infinities to NaN\n *\n * @param {*} v\n * @return {boolean}\n */\nfunction isNumeric(v) {\n    return v - parseFloat(v) >= 0;\n}\n\n\nvar number = (Object.freeze || Object)({\n\tlinearMap: linearMap,\n\tparsePercent: parsePercent$1,\n\tround: round$2,\n\tasc: asc,\n\tgetPrecision: getPrecision,\n\tgetPrecisionSafe: getPrecisionSafe,\n\tgetPixelPrecision: getPixelPrecision,\n\tgetPercentWithPrecision: getPercentWithPrecision,\n\tMAX_SAFE_INTEGER: MAX_SAFE_INTEGER,\n\tremRadian: remRadian,\n\tisRadianAroundZero: isRadianAroundZero,\n\tparseDate: parseDate,\n\tquantity: quantity,\n\tnice: nice,\n\tquantile: quantile,\n\treformIntervals: reformIntervals,\n\tisNumeric: isNumeric\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import Text from 'zrender/src/graphic/Text';\n\n/**\n * 每三位默认加,格式化\n * @param {string|number} x\n * @return {string}\n */\nfunction addCommas(x) {\n    if (isNaN(x)) {\n        return '-';\n    }\n    x = (x + '').split('.');\n    return x[0].replace(/(\\d{1,3})(?=(?:\\d{3})+(?!\\d))/g, '$1,')\n            + (x.length > 1 ? ('.' + x[1]) : '');\n}\n\n/**\n * @param {string} str\n * @param {boolean} [upperCaseFirst=false]\n * @return {string} str\n */\nfunction toCamelCase(str, upperCaseFirst) {\n    str = (str || '').toLowerCase().replace(/-(.)/g, function (match, group1) {\n        return group1.toUpperCase();\n    });\n\n    if (upperCaseFirst && str) {\n        str = str.charAt(0).toUpperCase() + str.slice(1);\n    }\n\n    return str;\n}\n\nvar normalizeCssArray$1 = normalizeCssArray;\n\n\nvar replaceReg = /([&<>\"'])/g;\nvar replaceMap = {\n    '&': '&amp;',\n    '<': '&lt;',\n    '>': '&gt;',\n    '\"': '&quot;',\n    '\\'': '&#39;'\n};\n\nfunction encodeHTML(source) {\n    return source == null\n        ? ''\n        : (source + '').replace(replaceReg, function (str, c) {\n            return replaceMap[c];\n        });\n}\n\nvar TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];\n\nvar wrapVar = function (varName, seriesIdx) {\n    return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}';\n};\n\n/**\n * Template formatter\n * @param {string} tpl\n * @param {Array.<Object>|Object} paramsList\n * @param {boolean} [encode=false]\n * @return {string}\n */\nfunction formatTpl(tpl, paramsList, encode) {\n    if (!isArray(paramsList)) {\n        paramsList = [paramsList];\n    }\n    var seriesLen = paramsList.length;\n    if (!seriesLen) {\n        return '';\n    }\n\n    var $vars = paramsList[0].$vars || [];\n    for (var i = 0; i < $vars.length; i++) {\n        var alias = TPL_VAR_ALIAS[i];\n        tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0));\n    }\n    for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) {\n        for (var k = 0; k < $vars.length; k++) {\n            var val = paramsList[seriesIdx][$vars[k]];\n            tpl = tpl.replace(\n                wrapVar(TPL_VAR_ALIAS[k], seriesIdx),\n                encode ? encodeHTML(val) : val\n            );\n        }\n    }\n\n    return tpl;\n}\n\n/**\n * simple Template formatter\n *\n * @param {string} tpl\n * @param {Object} param\n * @param {boolean} [encode=false]\n * @return {string}\n */\nfunction formatTplSimple(tpl, param, encode) {\n    each$1(param, function (value, key) {\n        tpl = tpl.replace(\n            '{' + key + '}',\n            encode ? encodeHTML(value) : value\n        );\n    });\n    return tpl;\n}\n\n/**\n * @param {Object|string} [opt] If string, means color.\n * @param {string} [opt.color]\n * @param {string} [opt.extraCssText]\n * @param {string} [opt.type='item'] 'item' or 'subItem'\n * @param {string} [opt.renderMode='html'] render mode of tooltip, 'html' or 'richText'\n * @param {string} [opt.markerId='X'] id name for marker. If only one marker is in a rich text, this can be omitted.\n * @return {string}\n */\nfunction getTooltipMarker(opt, extraCssText) {\n    opt = isString(opt) ? {color: opt, extraCssText: extraCssText} : (opt || {});\n    var color = opt.color;\n    var type = opt.type;\n    var extraCssText = opt.extraCssText;\n    var renderMode = opt.renderMode || 'html';\n    var markerId = opt.markerId || 'X';\n\n    if (!color) {\n        return '';\n    }\n\n    if (renderMode === 'html') {\n        return type === 'subItem'\n        ? '<span style=\"display:inline-block;vertical-align:middle;margin-right:8px;margin-left:3px;'\n            + 'border-radius:4px;width:4px;height:4px;background-color:'\n            + encodeHTML(color) + ';' + (extraCssText || '') + '\"></span>'\n        : '<span style=\"display:inline-block;margin-right:5px;'\n            + 'border-radius:10px;width:10px;height:10px;background-color:'\n            + encodeHTML(color) + ';' + (extraCssText || '') + '\"></span>';\n    }\n    else {\n        // Space for rich element marker\n        return {\n            renderMode: renderMode,\n            content: '{marker' + markerId + '|}  ',\n            style: {\n                color: color\n            }\n        };\n    }\n}\n\nfunction pad(str, len) {\n    str += '';\n    return '0000'.substr(0, len - str.length) + str;\n}\n\n\n/**\n * ISO Date format\n * @param {string} tpl\n * @param {number} value\n * @param {boolean} [isUTC=false] Default in local time.\n *           see `module:echarts/scale/Time`\n *           and `module:echarts/util/number#parseDate`.\n * @inner\n */\nfunction formatTime(tpl, value, isUTC) {\n    if (tpl === 'week'\n        || tpl === 'month'\n        || tpl === 'quarter'\n        || tpl === 'half-year'\n        || tpl === 'year'\n    ) {\n        tpl = 'MM-dd\\nyyyy';\n    }\n\n    var date = parseDate(value);\n    var utc = isUTC ? 'UTC' : '';\n    var y = date['get' + utc + 'FullYear']();\n    var M = date['get' + utc + 'Month']() + 1;\n    var d = date['get' + utc + 'Date']();\n    var h = date['get' + utc + 'Hours']();\n    var m = date['get' + utc + 'Minutes']();\n    var s = date['get' + utc + 'Seconds']();\n    var S = date['get' + utc + 'Milliseconds']();\n\n    tpl = tpl.replace('MM', pad(M, 2))\n        .replace('M', M)\n        .replace('yyyy', y)\n        .replace('yy', y % 100)\n        .replace('dd', pad(d, 2))\n        .replace('d', d)\n        .replace('hh', pad(h, 2))\n        .replace('h', h)\n        .replace('mm', pad(m, 2))\n        .replace('m', m)\n        .replace('ss', pad(s, 2))\n        .replace('s', s)\n        .replace('SSS', pad(S, 3));\n\n    return tpl;\n}\n\n/**\n * Capital first\n * @param {string} str\n * @return {string}\n */\nfunction capitalFirst(str) {\n    return str ? str.charAt(0).toUpperCase() + str.substr(1) : str;\n}\n\nvar truncateText$1 = truncateText;\n\n/**\n * @public\n * @param {Object} opt\n * @param {string} opt.text\n * @param {string} opt.font\n * @param {string} [opt.textAlign='left']\n * @param {string} [opt.textVerticalAlign='top']\n * @param {Array.<number>} [opt.textPadding]\n * @param {number} [opt.textLineHeight]\n * @param {Object} [opt.rich]\n * @param {Object} [opt.truncate]\n * @return {Object} {x, y, width, height, lineHeight}\n */\nfunction getTextBoundingRect(opt) {\n    return getBoundingRect(\n        opt.text,\n        opt.font,\n        opt.textAlign,\n        opt.textVerticalAlign,\n        opt.textPadding,\n        opt.textLineHeight,\n        opt.rich,\n        opt.truncate\n    );\n}\n\n/**\n * @deprecated\n * the `textLineHeight` was added later.\n * For backward compatiblility, put it as the last parameter.\n * But deprecated this interface. Please use `getTextBoundingRect` instead.\n */\nfunction getTextRect(\n    text, font, textAlign, textVerticalAlign, textPadding, rich, truncate, textLineHeight\n) {\n    return getBoundingRect(\n        text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate\n    );\n}\n\n\nvar format = (Object.freeze || Object)({\n\taddCommas: addCommas,\n\ttoCamelCase: toCamelCase,\n\tnormalizeCssArray: normalizeCssArray$1,\n\tencodeHTML: encodeHTML,\n\tformatTpl: formatTpl,\n\tformatTplSimple: formatTplSimple,\n\tgetTooltipMarker: getTooltipMarker,\n\tformatTime: formatTime,\n\tcapitalFirst: capitalFirst,\n\ttruncateText: truncateText$1,\n\tgetTextBoundingRect: getTextBoundingRect,\n\tgetTextRect: getTextRect\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Layout helpers for each component positioning\n\nvar each$3 = each$1;\n\n/**\n * @public\n */\nvar LOCATION_PARAMS = [\n    'left', 'right', 'top', 'bottom', 'width', 'height'\n];\n\n/**\n * @public\n */\nvar HV_NAMES = [\n    ['width', 'left', 'right'],\n    ['height', 'top', 'bottom']\n];\n\nfunction boxLayout(orient, group, gap, maxWidth, maxHeight) {\n    var x = 0;\n    var y = 0;\n\n    if (maxWidth == null) {\n        maxWidth = Infinity;\n    }\n    if (maxHeight == null) {\n        maxHeight = Infinity;\n    }\n    var currentLineMaxSize = 0;\n\n    group.eachChild(function (child, idx) {\n        var position = child.position;\n        var rect = child.getBoundingRect();\n        var nextChild = group.childAt(idx + 1);\n        var nextChildRect = nextChild && nextChild.getBoundingRect();\n        var nextX;\n        var nextY;\n\n        if (orient === 'horizontal') {\n            var moveX = rect.width + (nextChildRect ? (-nextChildRect.x + rect.x) : 0);\n            nextX = x + moveX;\n            // Wrap when width exceeds maxWidth or meet a `newline` group\n            // FIXME compare before adding gap?\n            if (nextX > maxWidth || child.newline) {\n                x = 0;\n                nextX = moveX;\n                y += currentLineMaxSize + gap;\n                currentLineMaxSize = rect.height;\n            }\n            else {\n                // FIXME: consider rect.y is not `0`?\n                currentLineMaxSize = Math.max(currentLineMaxSize, rect.height);\n            }\n        }\n        else {\n            var moveY = rect.height + (nextChildRect ? (-nextChildRect.y + rect.y) : 0);\n            nextY = y + moveY;\n            // Wrap when width exceeds maxHeight or meet a `newline` group\n            if (nextY > maxHeight || child.newline) {\n                x += currentLineMaxSize + gap;\n                y = 0;\n                nextY = moveY;\n                currentLineMaxSize = rect.width;\n            }\n            else {\n                currentLineMaxSize = Math.max(currentLineMaxSize, rect.width);\n            }\n        }\n\n        if (child.newline) {\n            return;\n        }\n\n        position[0] = x;\n        position[1] = y;\n\n        orient === 'horizontal'\n            ? (x = nextX + gap)\n            : (y = nextY + gap);\n    });\n}\n\n/**\n * VBox or HBox layouting\n * @param {string} orient\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar box = boxLayout;\n\n/**\n * VBox layouting\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar vbox = curry(boxLayout, 'vertical');\n\n/**\n * HBox layouting\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar hbox = curry(boxLayout, 'horizontal');\n\n/**\n * If x or x2 is not specified or 'center' 'left' 'right',\n * the width would be as long as possible.\n * If y or y2 is not specified or 'middle' 'top' 'bottom',\n * the height would be as long as possible.\n *\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.x]\n * @param {number|string} [positionInfo.y]\n * @param {number|string} [positionInfo.x2]\n * @param {number|string} [positionInfo.y2]\n * @param {Object} containerRect {width, height}\n * @param {string|number} margin\n * @return {Object} {width, height}\n */\n\n\n/**\n * Parse position info.\n *\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.left]\n * @param {number|string} [positionInfo.top]\n * @param {number|string} [positionInfo.right]\n * @param {number|string} [positionInfo.bottom]\n * @param {number|string} [positionInfo.width]\n * @param {number|string} [positionInfo.height]\n * @param {number|string} [positionInfo.aspect] Aspect is width / height\n * @param {Object} containerRect\n * @param {string|number} [margin]\n *\n * @return {module:zrender/core/BoundingRect}\n */\nfunction getLayoutRect(\n    positionInfo, containerRect, margin\n) {\n    margin = normalizeCssArray$1(margin || 0);\n\n    var containerWidth = containerRect.width;\n    var containerHeight = containerRect.height;\n\n    var left = parsePercent$1(positionInfo.left, containerWidth);\n    var top = parsePercent$1(positionInfo.top, containerHeight);\n    var right = parsePercent$1(positionInfo.right, containerWidth);\n    var bottom = parsePercent$1(positionInfo.bottom, containerHeight);\n    var width = parsePercent$1(positionInfo.width, containerWidth);\n    var height = parsePercent$1(positionInfo.height, containerHeight);\n\n    var verticalMargin = margin[2] + margin[0];\n    var horizontalMargin = margin[1] + margin[3];\n    var aspect = positionInfo.aspect;\n\n    // If width is not specified, calculate width from left and right\n    if (isNaN(width)) {\n        width = containerWidth - right - horizontalMargin - left;\n    }\n    if (isNaN(height)) {\n        height = containerHeight - bottom - verticalMargin - top;\n    }\n\n    if (aspect != null) {\n        // If width and height are not given\n        // 1. Graph should not exceeds the container\n        // 2. Aspect must be keeped\n        // 3. Graph should take the space as more as possible\n        // FIXME\n        // Margin is not considered, because there is no case that both\n        // using margin and aspect so far.\n        if (isNaN(width) && isNaN(height)) {\n            if (aspect > containerWidth / containerHeight) {\n                width = containerWidth * 0.8;\n            }\n            else {\n                height = containerHeight * 0.8;\n            }\n        }\n\n        // Calculate width or height with given aspect\n        if (isNaN(width)) {\n            width = aspect * height;\n        }\n        if (isNaN(height)) {\n            height = width / aspect;\n        }\n    }\n\n    // If left is not specified, calculate left from right and width\n    if (isNaN(left)) {\n        left = containerWidth - right - width - horizontalMargin;\n    }\n    if (isNaN(top)) {\n        top = containerHeight - bottom - height - verticalMargin;\n    }\n\n    // Align left and top\n    switch (positionInfo.left || positionInfo.right) {\n        case 'center':\n            left = containerWidth / 2 - width / 2 - margin[3];\n            break;\n        case 'right':\n            left = containerWidth - width - horizontalMargin;\n            break;\n    }\n    switch (positionInfo.top || positionInfo.bottom) {\n        case 'middle':\n        case 'center':\n            top = containerHeight / 2 - height / 2 - margin[0];\n            break;\n        case 'bottom':\n            top = containerHeight - height - verticalMargin;\n            break;\n    }\n    // If something is wrong and left, top, width, height are calculated as NaN\n    left = left || 0;\n    top = top || 0;\n    if (isNaN(width)) {\n        // Width may be NaN if only one value is given except width\n        width = containerWidth - horizontalMargin - left - (right || 0);\n    }\n    if (isNaN(height)) {\n        // Height may be NaN if only one value is given except height\n        height = containerHeight - verticalMargin - top - (bottom || 0);\n    }\n\n    var rect = new BoundingRect(left + margin[3], top + margin[0], width, height);\n    rect.margin = margin;\n    return rect;\n}\n\n\n/**\n * Position a zr element in viewport\n *  Group position is specified by either\n *  {left, top}, {right, bottom}\n *  If all properties exists, right and bottom will be igonred.\n *\n * Logic:\n *     1. Scale (against origin point in parent coord)\n *     2. Rotate (against origin point in parent coord)\n *     3. Traslate (with el.position by this method)\n * So this method only fixes the last step 'Traslate', which does not affect\n * scaling and rotating.\n *\n * If be called repeatly with the same input el, the same result will be gotten.\n *\n * @param {module:zrender/Element} el Should have `getBoundingRect` method.\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.left]\n * @param {number|string} [positionInfo.top]\n * @param {number|string} [positionInfo.right]\n * @param {number|string} [positionInfo.bottom]\n * @param {number|string} [positionInfo.width] Only for opt.boundingModel: 'raw'\n * @param {number|string} [positionInfo.height] Only for opt.boundingModel: 'raw'\n * @param {Object} containerRect\n * @param {string|number} margin\n * @param {Object} [opt]\n * @param {Array.<number>} [opt.hv=[1,1]] Only horizontal or only vertical.\n * @param {Array.<number>} [opt.boundingMode='all']\n *        Specify how to calculate boundingRect when locating.\n *        'all': Position the boundingRect that is transformed and uioned\n *               both itself and its descendants.\n *               This mode simplies confine the elements in the bounding\n *               of their container (e.g., using 'right: 0').\n *        'raw': Position the boundingRect that is not transformed and only itself.\n *               This mode is useful when you want a element can overflow its\n *               container. (Consider a rotated circle needs to be located in a corner.)\n *               In this mode positionInfo.width/height can only be number.\n */\nfunction positionElement(el, positionInfo, containerRect, margin, opt) {\n    var h = !opt || !opt.hv || opt.hv[0];\n    var v = !opt || !opt.hv || opt.hv[1];\n    var boundingMode = opt && opt.boundingMode || 'all';\n\n    if (!h && !v) {\n        return;\n    }\n\n    var rect;\n    if (boundingMode === 'raw') {\n        rect = el.type === 'group'\n            ? new BoundingRect(0, 0, +positionInfo.width || 0, +positionInfo.height || 0)\n            : el.getBoundingRect();\n    }\n    else {\n        rect = el.getBoundingRect();\n        if (el.needLocalTransform()) {\n            var transform = el.getLocalTransform();\n            // Notice: raw rect may be inner object of el,\n            // which should not be modified.\n            rect = rect.clone();\n            rect.applyTransform(transform);\n        }\n    }\n\n    // The real width and height can not be specified but calculated by the given el.\n    positionInfo = getLayoutRect(\n        defaults(\n            {width: rect.width, height: rect.height},\n            positionInfo\n        ),\n        containerRect,\n        margin\n    );\n\n    // Because 'tranlate' is the last step in transform\n    // (see zrender/core/Transformable#getLocalTransform),\n    // we can just only modify el.position to get final result.\n    var elPos = el.position;\n    var dx = h ? positionInfo.x - rect.x : 0;\n    var dy = v ? positionInfo.y - rect.y : 0;\n\n    el.attr('position', boundingMode === 'raw' ? [dx, dy] : [elPos[0] + dx, elPos[1] + dy]);\n}\n\n/**\n * @param {Object} option Contains some of the properties in HV_NAMES.\n * @param {number} hvIdx 0: horizontal; 1: vertical.\n */\n\n\n/**\n * Consider Case:\n * When defulat option has {left: 0, width: 100}, and we set {right: 0}\n * through setOption or media query, using normal zrUtil.merge will cause\n * {right: 0} does not take effect.\n *\n * @example\n * ComponentModel.extend({\n *     init: function () {\n *         ...\n *         var inputPositionParams = layout.getLayoutParams(option);\n *         this.mergeOption(inputPositionParams);\n *     },\n *     mergeOption: function (newOption) {\n *         newOption && zrUtil.merge(thisOption, newOption, true);\n *         layout.mergeLayoutParam(thisOption, newOption);\n *     }\n * });\n *\n * @param {Object} targetOption\n * @param {Object} newOption\n * @param {Object|string} [opt]\n * @param {boolean|Array.<boolean>} [opt.ignoreSize=false] Used for the components\n *  that width (or height) should not be calculated by left and right (or top and bottom).\n */\nfunction mergeLayoutParam(targetOption, newOption, opt) {\n    !isObject$1(opt) && (opt = {});\n\n    var ignoreSize = opt.ignoreSize;\n    !isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]);\n\n    var hResult = merge$$1(HV_NAMES[0], 0);\n    var vResult = merge$$1(HV_NAMES[1], 1);\n\n    copy(HV_NAMES[0], targetOption, hResult);\n    copy(HV_NAMES[1], targetOption, vResult);\n\n    function merge$$1(names, hvIdx) {\n        var newParams = {};\n        var newValueCount = 0;\n        var merged = {};\n        var mergedValueCount = 0;\n        var enoughParamNumber = 2;\n\n        each$3(names, function (name) {\n            merged[name] = targetOption[name];\n        });\n        each$3(names, function (name) {\n            // Consider case: newOption.width is null, which is\n            // set by user for removing width setting.\n            hasProp(newOption, name) && (newParams[name] = merged[name] = newOption[name]);\n            hasValue(newParams, name) && newValueCount++;\n            hasValue(merged, name) && mergedValueCount++;\n        });\n\n        if (ignoreSize[hvIdx]) {\n            // Only one of left/right is premitted to exist.\n            if (hasValue(newOption, names[1])) {\n                merged[names[2]] = null;\n            }\n            else if (hasValue(newOption, names[2])) {\n                merged[names[1]] = null;\n            }\n            return merged;\n        }\n\n        // Case: newOption: {width: ..., right: ...},\n        // or targetOption: {right: ...} and newOption: {width: ...},\n        // There is no conflict when merged only has params count\n        // little than enoughParamNumber.\n        if (mergedValueCount === enoughParamNumber || !newValueCount) {\n            return merged;\n        }\n        // Case: newOption: {width: ..., right: ...},\n        // Than we can make sure user only want those two, and ignore\n        // all origin params in targetOption.\n        else if (newValueCount >= enoughParamNumber) {\n            return newParams;\n        }\n        else {\n            // Chose another param from targetOption by priority.\n            for (var i = 0; i < names.length; i++) {\n                var name = names[i];\n                if (!hasProp(newParams, name) && hasProp(targetOption, name)) {\n                    newParams[name] = targetOption[name];\n                    break;\n                }\n            }\n            return newParams;\n        }\n    }\n\n    function hasProp(obj, name) {\n        return obj.hasOwnProperty(name);\n    }\n\n    function hasValue(obj, name) {\n        return obj[name] != null && obj[name] !== 'auto';\n    }\n\n    function copy(names, target, source) {\n        each$3(names, function (name) {\n            target[name] = source[name];\n        });\n    }\n}\n\n/**\n * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.\n * @param {Object} source\n * @return {Object} Result contains those props.\n */\nfunction getLayoutParams(source) {\n    return copyLayoutParams({}, source);\n}\n\n/**\n * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.\n * @param {Object} source\n * @return {Object} Result contains those props.\n */\nfunction copyLayoutParams(target, source) {\n    source && target && each$3(LOCATION_PARAMS, function (name) {\n        source.hasOwnProperty(name) && (target[name] = source[name]);\n    });\n    return target;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar boxLayoutMixin = {\n    getBoxLayoutParams: function () {\n        return {\n            left: this.get('left'),\n            top: this.get('top'),\n            right: this.get('right'),\n            bottom: this.get('bottom'),\n            width: this.get('width'),\n            height: this.get('height')\n        };\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Component model\n *\n * @module echarts/model/Component\n */\n\nvar inner$1 = makeInner();\n\n/**\n * @alias module:echarts/model/Component\n * @constructor\n * @param {Object} option\n * @param {module:echarts/model/Model} parentModel\n * @param {module:echarts/model/Model} ecModel\n */\nvar ComponentModel = Model.extend({\n\n    type: 'component',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    id: '',\n\n    /**\n     * Because simplified concept is probably better, series.name (or component.name)\n     * has been having too many resposibilities:\n     * (1) Generating id (which requires name in option should not be modified).\n     * (2) As an index to mapping series when merging option or calling API (a name\n     * can refer to more then one components, which is convinient is some case).\n     * (3) Display.\n     * @readOnly\n     */\n    name: '',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    mainType: '',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    subType: '',\n\n    /**\n     * @readOnly\n     * @type {number}\n     */\n    componentIndex: 0,\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    defaultOption: null,\n\n    /**\n     * @type {module:echarts/model/Global}\n     * @readOnly\n     */\n    ecModel: null,\n\n    /**\n     * key: componentType\n     * value:  Component model list, can not be null.\n     * @type {Object.<string, Array.<module:echarts/model/Model>>}\n     * @readOnly\n     */\n    dependentModels: [],\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    uid: null,\n\n    /**\n     * Support merge layout params.\n     * Only support 'box' now (left/right/top/bottom/width/height).\n     * @type {string|Object} Object can be {ignoreSize: true}\n     * @readOnly\n     */\n    layoutMode: null,\n\n    $constructor: function (option, parentModel, ecModel, extraOpt) {\n        Model.call(this, option, parentModel, ecModel, extraOpt);\n\n        this.uid = getUID('ec_cpt_model');\n    },\n\n    init: function (option, parentModel, ecModel, extraOpt) {\n        this.mergeDefaultAndTheme(option, ecModel);\n    },\n\n    mergeDefaultAndTheme: function (option, ecModel) {\n        var layoutMode = this.layoutMode;\n        var inputPositionParams = layoutMode\n            ? getLayoutParams(option) : {};\n\n        var themeModel = ecModel.getTheme();\n        merge(option, themeModel.get(this.mainType));\n        merge(option, this.getDefaultOption());\n\n        if (layoutMode) {\n            mergeLayoutParam(option, inputPositionParams, layoutMode);\n        }\n    },\n\n    mergeOption: function (option, extraOpt) {\n        merge(this.option, option, true);\n\n        var layoutMode = this.layoutMode;\n        if (layoutMode) {\n            mergeLayoutParam(this.option, option, layoutMode);\n        }\n    },\n\n    // Hooker after init or mergeOption\n    optionUpdated: function (newCptOption, isInit) {},\n\n    getDefaultOption: function () {\n        var fields = inner$1(this);\n        if (!fields.defaultOption) {\n            var optList = [];\n            var Class = this.constructor;\n            while (Class) {\n                var opt = Class.prototype.defaultOption;\n                opt && optList.push(opt);\n                Class = Class.superClass;\n            }\n\n            var defaultOption = {};\n            for (var i = optList.length - 1; i >= 0; i--) {\n                defaultOption = merge(defaultOption, optList[i], true);\n            }\n            fields.defaultOption = defaultOption;\n        }\n        return fields.defaultOption;\n    },\n\n    getReferringComponents: function (mainType) {\n        return this.ecModel.queryComponents({\n            mainType: mainType,\n            index: this.get(mainType + 'Index', true),\n            id: this.get(mainType + 'Id', true)\n        });\n    }\n\n});\n\n// Reset ComponentModel.extend, add preConstruct.\n// clazzUtil.enableClassExtend(\n//     ComponentModel,\n//     function (option, parentModel, ecModel, extraOpt) {\n//         // Set dependentModels, componentIndex, name, id, mainType, subType.\n//         zrUtil.extend(this, extraOpt);\n\n//         this.uid = componentUtil.getUID('componentModel');\n\n//         // this.setReadOnly([\n//         //     'type', 'id', 'uid', 'name', 'mainType', 'subType',\n//         //     'dependentModels', 'componentIndex'\n//         // ]);\n//     }\n// );\n\n// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(\n    ComponentModel, {registerWhenExtend: true}\n);\nenableSubTypeDefaulter(ComponentModel);\n\n// Add capability of ComponentModel.topologicalTravel.\nenableTopologicalTravel(ComponentModel, getDependencies);\n\nfunction getDependencies(componentType) {\n    var deps = [];\n    each$1(ComponentModel.getClassesByMainType(componentType), function (Clazz) {\n        deps = deps.concat(Clazz.prototype.dependencies || []);\n    });\n\n    // Ensure main type.\n    deps = map(deps, function (type) {\n        return parseClassType$1(type).main;\n    });\n\n    // Hack dataset for convenience.\n    if (componentType !== 'dataset' && indexOf(deps, 'dataset') <= 0) {\n        deps.unshift('dataset');\n    }\n\n    return deps;\n}\n\nmixin(ComponentModel, boxLayoutMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar platform = '';\n// Navigator not exists in node\nif (typeof navigator !== 'undefined') {\n    platform = navigator.platform || '';\n}\n\nvar globalDefault = {\n    // backgroundColor: 'rgba(0,0,0,0)',\n\n    // https://dribbble.com/shots/1065960-Infographic-Pie-chart-visualization\n    // color: ['#5793f3', '#d14a61', '#fd9c35', '#675bba', '#fec42c', '#dd4444', '#d4df5a', '#cd4870'],\n    // Light colors:\n    // color: ['#bcd3bb', '#e88f70', '#edc1a5', '#9dc5c8', '#e1e8c8', '#7b7c68', '#e5b5b5', '#f0b489', '#928ea8', '#bda29a'],\n    // color: ['#cc5664', '#9bd6ec', '#ea946e', '#8acaaa', '#f1ec64', '#ee8686', '#a48dc1', '#5da6bc', '#b9dcae'],\n    // Dark colors:\n    color: [\n        '#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83',\n        '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'\n    ],\n\n    gradientColor: ['#f6efa6', '#d88273', '#bf444c'],\n\n    // If xAxis and yAxis declared, grid is created by default.\n    // grid: {},\n\n    textStyle: {\n        // color: '#000',\n        // decoration: 'none',\n        // PENDING\n        fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif',\n        // fontFamily: 'Arial, Verdana, sans-serif',\n        fontSize: 12,\n        fontStyle: 'normal',\n        fontWeight: 'normal'\n    },\n\n    // http://blogs.adobe.com/webplatform/2014/02/24/using-blend-modes-in-html-canvas/\n    // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation\n    // Default is source-over\n    blendMode: null,\n\n    animation: 'auto',\n    animationDuration: 1000,\n    animationDurationUpdate: 300,\n    animationEasing: 'exponentialOut',\n    animationEasingUpdate: 'cubicOut',\n\n    animationThreshold: 2000,\n    // Configuration for progressive/incremental rendering\n    progressiveThreshold: 3000,\n    progressive: 400,\n\n    // Threshold of if use single hover layer to optimize.\n    // It is recommended that `hoverLayerThreshold` is equivalent to or less than\n    // `progressiveThreshold`, otherwise hover will cause restart of progressive,\n    // which is unexpected.\n    // see example <echarts/test/heatmap-large.html>.\n    hoverLayerThreshold: 3000,\n\n    // See: module:echarts/scale/Time\n    useUTC: false\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$2 = makeInner();\n\nfunction getNearestColorPalette(colors, requestColorNum) {\n    var paletteNum = colors.length;\n    // TODO colors must be in order\n    for (var i = 0; i < paletteNum; i++) {\n        if (colors[i].length > requestColorNum) {\n            return colors[i];\n        }\n    }\n    return colors[paletteNum - 1];\n}\n\nvar colorPaletteMixin = {\n    clearColorPalette: function () {\n        inner$2(this).colorIdx = 0;\n        inner$2(this).colorNameMap = {};\n    },\n\n    /**\n     * @param {string} name MUST NOT be null/undefined. Otherwise call this function\n     *                 twise with the same parameters will get different result.\n     * @param {Object} [scope=this]\n     * @param {Object} [requestColorNum]\n     * @return {string} color string.\n     */\n    getColorFromPalette: function (name, scope, requestColorNum) {\n        scope = scope || this;\n        var scopeFields = inner$2(scope);\n        var colorIdx = scopeFields.colorIdx || 0;\n        var colorNameMap = scopeFields.colorNameMap = scopeFields.colorNameMap || {};\n        // Use `hasOwnProperty` to avoid conflict with Object.prototype.\n        if (colorNameMap.hasOwnProperty(name)) {\n            return colorNameMap[name];\n        }\n        var defaultColorPalette = normalizeToArray(this.get('color', true));\n        var layeredColorPalette = this.get('colorLayer', true);\n        var colorPalette = ((requestColorNum == null || !layeredColorPalette)\n            ? defaultColorPalette : getNearestColorPalette(layeredColorPalette, requestColorNum));\n\n        // In case can't find in layered color palette.\n        colorPalette = colorPalette || defaultColorPalette;\n\n        if (!colorPalette || !colorPalette.length) {\n            return;\n        }\n\n        var color = colorPalette[colorIdx];\n        if (name) {\n            colorNameMap[name] = color;\n        }\n        scopeFields.colorIdx = (colorIdx + 1) % colorPalette.length;\n\n        return color;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Helper for model references.\n * There are many manners to refer axis/coordSys.\n */\n\n// TODO\n// merge relevant logic to this file?\n// check: \"modelHelper\" of tooltip and \"BrushTargetManager\".\n\n/**\n * @return {Object} For example:\n * {\n *     coordSysName: 'cartesian2d',\n *     coordSysDims: ['x', 'y', ...],\n *     axisMap: HashMap({\n *         x: xAxisModel,\n *         y: yAxisModel\n *     }),\n *     categoryAxisMap: HashMap({\n *         x: xAxisModel,\n *         y: undefined\n *     }),\n *     // It also indicate that whether there is category axis.\n *     firstCategoryDimIndex: 1,\n *     // To replace user specified encode.\n * }\n */\nfunction getCoordSysDefineBySeries(seriesModel) {\n    var coordSysName = seriesModel.get('coordinateSystem');\n    var result = {\n        coordSysName: coordSysName,\n        coordSysDims: [],\n        axisMap: createHashMap(),\n        categoryAxisMap: createHashMap()\n    };\n    var fetch = fetchers[coordSysName];\n    if (fetch) {\n        fetch(seriesModel, result, result.axisMap, result.categoryAxisMap);\n        return result;\n    }\n}\n\nvar fetchers = {\n\n    cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var xAxisModel = seriesModel.getReferringComponents('xAxis')[0];\n        var yAxisModel = seriesModel.getReferringComponents('yAxis')[0];\n\n        if (__DEV__) {\n            if (!xAxisModel) {\n                throw new Error('xAxis \"' + retrieve(\n                    seriesModel.get('xAxisIndex'),\n                    seriesModel.get('xAxisId'),\n                    0\n                ) + '\" not found');\n            }\n            if (!yAxisModel) {\n                throw new Error('yAxis \"' + retrieve(\n                    seriesModel.get('xAxisIndex'),\n                    seriesModel.get('yAxisId'),\n                    0\n                ) + '\" not found');\n            }\n        }\n\n        result.coordSysDims = ['x', 'y'];\n        axisMap.set('x', xAxisModel);\n        axisMap.set('y', yAxisModel);\n\n        if (isCategory(xAxisModel)) {\n            categoryAxisMap.set('x', xAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n        if (isCategory(yAxisModel)) {\n            categoryAxisMap.set('y', yAxisModel);\n            result.firstCategoryDimIndex = 1;\n        }\n    },\n\n    singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var singleAxisModel = seriesModel.getReferringComponents('singleAxis')[0];\n\n        if (__DEV__) {\n            if (!singleAxisModel) {\n                throw new Error('singleAxis should be specified.');\n            }\n        }\n\n        result.coordSysDims = ['single'];\n        axisMap.set('single', singleAxisModel);\n\n        if (isCategory(singleAxisModel)) {\n            categoryAxisMap.set('single', singleAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n    },\n\n    polar: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var polarModel = seriesModel.getReferringComponents('polar')[0];\n        var radiusAxisModel = polarModel.findAxisModel('radiusAxis');\n        var angleAxisModel = polarModel.findAxisModel('angleAxis');\n\n        if (__DEV__) {\n            if (!angleAxisModel) {\n                throw new Error('angleAxis option not found');\n            }\n            if (!radiusAxisModel) {\n                throw new Error('radiusAxis option not found');\n            }\n        }\n\n        result.coordSysDims = ['radius', 'angle'];\n        axisMap.set('radius', radiusAxisModel);\n        axisMap.set('angle', angleAxisModel);\n\n        if (isCategory(radiusAxisModel)) {\n            categoryAxisMap.set('radius', radiusAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n        if (isCategory(angleAxisModel)) {\n            categoryAxisMap.set('angle', angleAxisModel);\n            result.firstCategoryDimIndex = 1;\n        }\n    },\n\n    geo: function (seriesModel, result, axisMap, categoryAxisMap) {\n        result.coordSysDims = ['lng', 'lat'];\n    },\n\n    parallel: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var ecModel = seriesModel.ecModel;\n        var parallelModel = ecModel.getComponent(\n            'parallel', seriesModel.get('parallelIndex')\n        );\n        var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice();\n\n        each$1(parallelModel.parallelAxisIndex, function (axisIndex, index) {\n            var axisModel = ecModel.getComponent('parallelAxis', axisIndex);\n            var axisDim = coordSysDims[index];\n            axisMap.set(axisDim, axisModel);\n\n            if (isCategory(axisModel) && result.firstCategoryDimIndex == null) {\n                categoryAxisMap.set(axisDim, axisModel);\n                result.firstCategoryDimIndex = index;\n            }\n        });\n    }\n};\n\nfunction isCategory(axisModel) {\n    return axisModel.get('type') === 'category';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Avoid typo.\nvar SOURCE_FORMAT_ORIGINAL = 'original';\nvar SOURCE_FORMAT_ARRAY_ROWS = 'arrayRows';\nvar SOURCE_FORMAT_OBJECT_ROWS = 'objectRows';\nvar SOURCE_FORMAT_KEYED_COLUMNS = 'keyedColumns';\nvar SOURCE_FORMAT_UNKNOWN = 'unknown';\n// ??? CHANGE A NAME\nvar SOURCE_FORMAT_TYPED_ARRAY = 'typedArray';\n\nvar SERIES_LAYOUT_BY_COLUMN = 'column';\nvar SERIES_LAYOUT_BY_ROW = 'row';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * [sourceFormat]\n *\n * + \"original\":\n * This format is only used in series.data, where\n * itemStyle can be specified in data item.\n *\n * + \"arrayRows\":\n * [\n *     ['product', 'score', 'amount'],\n *     ['Matcha Latte', 89.3, 95.8],\n *     ['Milk Tea', 92.1, 89.4],\n *     ['Cheese Cocoa', 94.4, 91.2],\n *     ['Walnut Brownie', 85.4, 76.9]\n * ]\n *\n * + \"objectRows\":\n * [\n *     {product: 'Matcha Latte', score: 89.3, amount: 95.8},\n *     {product: 'Milk Tea', score: 92.1, amount: 89.4},\n *     {product: 'Cheese Cocoa', score: 94.4, amount: 91.2},\n *     {product: 'Walnut Brownie', score: 85.4, amount: 76.9}\n * ]\n *\n * + \"keyedColumns\":\n * {\n *     'product': ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie'],\n *     'count': [823, 235, 1042, 988],\n *     'score': [95.8, 81.4, 91.2, 76.9]\n * }\n *\n * + \"typedArray\"\n *\n * + \"unknown\"\n */\n\n/**\n * @constructor\n * @param {Object} fields\n * @param {string} fields.sourceFormat\n * @param {Array|Object} fields.fromDataset\n * @param {Array|Object} [fields.data]\n * @param {string} [seriesLayoutBy='column']\n * @param {Array.<Object|string>} [dimensionsDefine]\n * @param {Objet|HashMap} [encodeDefine]\n * @param {number} [startIndex=0]\n * @param {number} [dimensionsDetectCount]\n */\nfunction Source(fields) {\n\n    /**\n     * @type {boolean}\n     */\n    this.fromDataset = fields.fromDataset;\n\n    /**\n     * Not null/undefined.\n     * @type {Array|Object}\n     */\n    this.data = fields.data || (\n        fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []\n    );\n\n    /**\n     * See also \"detectSourceFormat\".\n     * Not null/undefined.\n     * @type {string}\n     */\n    this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN;\n\n    /**\n     * 'row' or 'column'\n     * Not null/undefined.\n     * @type {string} seriesLayoutBy\n     */\n    this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN;\n\n    /**\n     * dimensions definition in option.\n     * can be null/undefined.\n     * @type {Array.<Object|string>}\n     */\n    this.dimensionsDefine = fields.dimensionsDefine;\n\n    /**\n     * encode definition in option.\n     * can be null/undefined.\n     * @type {Objet|HashMap}\n     */\n    this.encodeDefine = fields.encodeDefine && createHashMap(fields.encodeDefine);\n\n    /**\n     * Not null/undefined, uint.\n     * @type {number}\n     */\n    this.startIndex = fields.startIndex || 0;\n\n    /**\n     * Can be null/undefined (when unknown), uint.\n     * @type {number}\n     */\n    this.dimensionsDetectCount = fields.dimensionsDetectCount;\n}\n\n/**\n * Wrap original series data for some compatibility cases.\n */\nSource.seriesDataToSource = function (data) {\n    return new Source({\n        data: data,\n        sourceFormat: isTypedArray(data)\n            ? SOURCE_FORMAT_TYPED_ARRAY\n            : SOURCE_FORMAT_ORIGINAL,\n        fromDataset: false\n    });\n};\n\nenableClassCheck(Source);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$3 = makeInner();\n\n/**\n * @see {module:echarts/data/Source}\n * @param {module:echarts/component/dataset/DatasetModel} datasetModel\n * @return {string} sourceFormat\n */\nfunction detectSourceFormat(datasetModel) {\n    var data = datasetModel.option.source;\n    var sourceFormat = SOURCE_FORMAT_UNKNOWN;\n\n    if (isTypedArray(data)) {\n        sourceFormat = SOURCE_FORMAT_TYPED_ARRAY;\n    }\n    else if (isArray(data)) {\n        // FIXME Whether tolerate null in top level array?\n        if (data.length === 0) {\n            sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;\n        }\n\n        for (var i = 0, len = data.length; i < len; i++) {\n            var item = data[i];\n\n            if (item == null) {\n                continue;\n            }\n            else if (isArray(item)) {\n                sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;\n                break;\n            }\n            else if (isObject$1(item)) {\n                sourceFormat = SOURCE_FORMAT_OBJECT_ROWS;\n                break;\n            }\n        }\n    }\n    else if (isObject$1(data)) {\n        for (var key in data) {\n            if (data.hasOwnProperty(key) && isArrayLike(data[key])) {\n                sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS;\n                break;\n            }\n        }\n    }\n    else if (data != null) {\n        throw new Error('Invalid data');\n    }\n\n    inner$3(datasetModel).sourceFormat = sourceFormat;\n}\n\n/**\n * [Scenarios]:\n * (1) Provide source data directly:\n *     series: {\n *         encode: {...},\n *         dimensions: [...]\n *         seriesLayoutBy: 'row',\n *         data: [[...]]\n *     }\n * (2) Refer to datasetModel.\n *     series: [{\n *         encode: {...}\n *         // Ignore datasetIndex means `datasetIndex: 0`\n *         // and the dimensions defination in dataset is used\n *     }, {\n *         encode: {...},\n *         seriesLayoutBy: 'column',\n *         datasetIndex: 1\n *     }]\n *\n * Get data from series itself or datset.\n * @return {module:echarts/data/Source} source\n */\nfunction getSource(seriesModel) {\n    return inner$3(seriesModel).source;\n}\n\n/**\n * MUST be called before mergeOption of all series.\n * @param {module:echarts/model/Global} ecModel\n */\nfunction resetSourceDefaulter(ecModel) {\n    // `datasetMap` is used to make default encode.\n    inner$3(ecModel).datasetMap = createHashMap();\n}\n\n/**\n * [Caution]:\n * MUST be called after series option merged and\n * before \"series.getInitailData()\" called.\n *\n * [The rule of making default encode]:\n * Category axis (if exists) alway map to the first dimension.\n * Each other axis occupies a subsequent dimension.\n *\n * [Why make default encode]:\n * Simplify the typing of encode in option, avoiding the case like that:\n * series: [{encode: {x: 0, y: 1}}, {encode: {x: 0, y: 2}}, {encode: {x: 0, y: 3}}],\n * where the \"y\" have to be manually typed as \"1, 2, 3, ...\".\n *\n * @param {module:echarts/model/Series} seriesModel\n */\nfunction prepareSource(seriesModel) {\n    var seriesOption = seriesModel.option;\n\n    var data = seriesOption.data;\n    var sourceFormat = isTypedArray(data)\n        ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL;\n    var fromDataset = false;\n\n    var seriesLayoutBy = seriesOption.seriesLayoutBy;\n    var sourceHeader = seriesOption.sourceHeader;\n    var dimensionsDefine = seriesOption.dimensions;\n\n    var datasetModel = getDatasetModel(seriesModel);\n    if (datasetModel) {\n        var datasetOption = datasetModel.option;\n\n        data = datasetOption.source;\n        sourceFormat = inner$3(datasetModel).sourceFormat;\n        fromDataset = true;\n\n        // These settings from series has higher priority.\n        seriesLayoutBy = seriesLayoutBy || datasetOption.seriesLayoutBy;\n        sourceHeader == null && (sourceHeader = datasetOption.sourceHeader);\n        dimensionsDefine = dimensionsDefine || datasetOption.dimensions;\n    }\n\n    var completeResult = completeBySourceData(\n        data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine\n    );\n\n    // Note: dataset option does not have `encode`.\n    var encodeDefine = seriesOption.encode;\n    if (!encodeDefine && datasetModel) {\n        encodeDefine = makeDefaultEncode(\n            seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult\n        );\n    }\n\n    inner$3(seriesModel).source = new Source({\n        data: data,\n        fromDataset: fromDataset,\n        seriesLayoutBy: seriesLayoutBy,\n        sourceFormat: sourceFormat,\n        dimensionsDefine: completeResult.dimensionsDefine,\n        startIndex: completeResult.startIndex,\n        dimensionsDetectCount: completeResult.dimensionsDetectCount,\n        encodeDefine: encodeDefine\n    });\n}\n\n// return {startIndex, dimensionsDefine, dimensionsCount}\nfunction completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine) {\n    if (!data) {\n        return {dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine)};\n    }\n\n    var dimensionsDetectCount;\n    var startIndex;\n    var findPotentialName;\n\n    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {\n        // Rule: Most of the first line are string: it is header.\n        // Caution: consider a line with 5 string and 1 number,\n        // it still can not be sure it is a head, because the\n        // 5 string may be 5 values of category columns.\n        if (sourceHeader === 'auto' || sourceHeader == null) {\n            arrayRowsTravelFirst(function (val) {\n                // '-' is regarded as null/undefined.\n                if (val != null && val !== '-') {\n                    if (isString(val)) {\n                        startIndex == null && (startIndex = 1);\n                    }\n                    else {\n                        startIndex = 0;\n                    }\n                }\n            // 10 is an experience number, avoid long loop.\n            }, seriesLayoutBy, data, 10);\n        }\n        else {\n            startIndex = sourceHeader ? 1 : 0;\n        }\n\n        if (!dimensionsDefine && startIndex === 1) {\n            dimensionsDefine = [];\n            arrayRowsTravelFirst(function (val, index) {\n                dimensionsDefine[index] = val != null ? val : '';\n            }, seriesLayoutBy, data);\n        }\n\n        dimensionsDetectCount = dimensionsDefine\n            ? dimensionsDefine.length\n            : seriesLayoutBy === SERIES_LAYOUT_BY_ROW\n            ? data.length\n            : data[0]\n            ? data[0].length\n            : null;\n    }\n    else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {\n        if (!dimensionsDefine) {\n            dimensionsDefine = objectRowsCollectDimensions(data);\n            findPotentialName = true;\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {\n        if (!dimensionsDefine) {\n            dimensionsDefine = [];\n            findPotentialName = true;\n            each$1(data, function (colArr, key) {\n                dimensionsDefine.push(key);\n            });\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        var value0 = getDataItemValue(data[0]);\n        dimensionsDetectCount = isArray(value0) && value0.length || 1;\n    }\n    else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {\n        if (__DEV__) {\n            assert$1(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.');\n        }\n    }\n\n    var potentialNameDimIndex;\n    if (findPotentialName) {\n        each$1(dimensionsDefine, function (dim, idx) {\n            if ((isObject$1(dim) ? dim.name : dim) === 'name') {\n                potentialNameDimIndex = idx;\n            }\n        });\n    }\n\n    return {\n        startIndex: startIndex,\n        dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine),\n        dimensionsDetectCount: dimensionsDetectCount,\n        potentialNameDimIndex: potentialNameDimIndex\n        // TODO: potentialIdDimIdx\n    };\n}\n\n// Consider dimensions defined like ['A', 'price', 'B', 'price', 'C', 'price'],\n// which is reasonable. But dimension name is duplicated.\n// Returns undefined or an array contains only object without null/undefiend or string.\nfunction normalizeDimensionsDefine(dimensionsDefine) {\n    if (!dimensionsDefine) {\n        // The meaning of null/undefined is different from empty array.\n        return;\n    }\n    var nameMap = createHashMap();\n    return map(dimensionsDefine, function (item, index) {\n        item = extend({}, isObject$1(item) ? item : {name: item});\n\n        // User can set null in dimensions.\n        // We dont auto specify name, othewise a given name may\n        // cause it be refered unexpectedly.\n        if (item.name == null) {\n            return item;\n        }\n\n        // Also consider number form like 2012.\n        item.name += '';\n        // User may also specify displayName.\n        // displayName will always exists except user not\n        // specified or dim name is not specified or detected.\n        // (A auto generated dim name will not be used as\n        // displayName).\n        if (item.displayName == null) {\n            item.displayName = item.name;\n        }\n\n        var exist = nameMap.get(item.name);\n        if (!exist) {\n            nameMap.set(item.name, {count: 1});\n        }\n        else {\n            item.name += '-' + exist.count++;\n        }\n\n        return item;\n    });\n}\n\nfunction arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) {\n    maxLoop == null && (maxLoop = Infinity);\n    if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            cb(data[i] ? data[i][0] : null, i);\n        }\n    }\n    else {\n        var value0 = data[0] || [];\n        for (var i = 0; i < value0.length && i < maxLoop; i++) {\n            cb(value0[i], i);\n        }\n    }\n}\n\nfunction objectRowsCollectDimensions(data) {\n    var firstIndex = 0;\n    var obj;\n    while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line\n    if (obj) {\n        var dimensions = [];\n        each$1(obj, function (value, key) {\n            dimensions.push(key);\n        });\n        return dimensions;\n    }\n}\n\n// ??? TODO merge to completedimensions, where also has\n// default encode making logic. And the default rule\n// should depends on series? consider 'map'.\nfunction makeDefaultEncode(\n    seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult\n) {\n    var coordSysDefine = getCoordSysDefineBySeries(seriesModel);\n    var encode = {};\n    // var encodeTooltip = [];\n    // var encodeLabel = [];\n    var encodeItemName = [];\n    var encodeSeriesName = [];\n    var seriesType = seriesModel.subType;\n\n    // ??? TODO refactor: provide by series itself.\n    // Consider the case: 'map' series is based on geo coordSys,\n    // 'graph', 'heatmap' can be based on cartesian. But can not\n    // give default rule simply here.\n    var nSeriesMap = createHashMap(['pie', 'map', 'funnel']);\n    var cSeriesMap = createHashMap([\n        'line', 'bar', 'pictorialBar', 'scatter', 'effectScatter', 'candlestick', 'boxplot'\n    ]);\n\n    // Usually in this case series will use the first data\n    // dimension as the \"value\" dimension, or other default\n    // processes respectively.\n    if (coordSysDefine && cSeriesMap.get(seriesType) != null) {\n        var ecModel = seriesModel.ecModel;\n        var datasetMap = inner$3(ecModel).datasetMap;\n        var key = datasetModel.uid + '_' + seriesLayoutBy;\n        var datasetRecord = datasetMap.get(key)\n            || datasetMap.set(key, {categoryWayDim: 1, valueWayDim: 0});\n\n        // TODO\n        // Auto detect first time axis and do arrangement.\n        each$1(coordSysDefine.coordSysDims, function (coordDim) {\n            // In value way.\n            if (coordSysDefine.firstCategoryDimIndex == null) {\n                var dataDim = datasetRecord.valueWayDim++;\n                encode[coordDim] = dataDim;\n\n                // ??? TODO give a better default series name rule?\n                // especially when encode x y specified.\n                // consider: when mutiple series share one dimension\n                // category axis, series name should better use\n                // the other dimsion name. On the other hand, use\n                // both dimensions name.\n\n                encodeSeriesName.push(dataDim);\n                // encodeTooltip.push(dataDim);\n                // encodeLabel.push(dataDim);\n            }\n            // In category way, category axis.\n            else if (coordSysDefine.categoryAxisMap.get(coordDim)) {\n                encode[coordDim] = 0;\n                encodeItemName.push(0);\n            }\n            // In category way, non-category axis.\n            else {\n                var dataDim = datasetRecord.categoryWayDim++;\n                encode[coordDim] = dataDim;\n                // encodeTooltip.push(dataDim);\n                // encodeLabel.push(dataDim);\n                encodeSeriesName.push(dataDim);\n            }\n        });\n    }\n    // Do not make a complex rule! Hard to code maintain and not necessary.\n    // ??? TODO refactor: provide by series itself.\n    // [{name: ..., value: ...}, ...] like:\n    else if (nSeriesMap.get(seriesType) != null) {\n        // Find the first not ordinal. (5 is an experience value)\n        var firstNotOrdinal;\n        for (var i = 0; i < 5 && firstNotOrdinal == null; i++) {\n            if (!doGuessOrdinal(\n                data, sourceFormat, seriesLayoutBy,\n                completeResult.dimensionsDefine, completeResult.startIndex, i\n            )) {\n                firstNotOrdinal = i;\n            }\n        }\n        if (firstNotOrdinal != null) {\n            encode.value = firstNotOrdinal;\n            var nameDimIndex = completeResult.potentialNameDimIndex\n                || Math.max(firstNotOrdinal - 1, 0);\n            // By default, label use itemName in charts.\n            // So we dont set encodeLabel here.\n            encodeSeriesName.push(nameDimIndex);\n            encodeItemName.push(nameDimIndex);\n            // encodeTooltip.push(firstNotOrdinal);\n        }\n    }\n\n    // encodeTooltip.length && (encode.tooltip = encodeTooltip);\n    // encodeLabel.length && (encode.label = encodeLabel);\n    encodeItemName.length && (encode.itemName = encodeItemName);\n    encodeSeriesName.length && (encode.seriesName = encodeSeriesName);\n\n    return encode;\n}\n\n/**\n * If return null/undefined, indicate that should not use datasetModel.\n */\nfunction getDatasetModel(seriesModel) {\n    var option = seriesModel.option;\n    // Caution: consider the scenario:\n    // A dataset is declared and a series is not expected to use the dataset,\n    // and at the beginning `setOption({series: { noData })` (just prepare other\n    // option but no data), then `setOption({series: {data: [...]}); In this case,\n    // the user should set an empty array to avoid that dataset is used by default.\n    var thisData = option.data;\n    if (!thisData) {\n        return seriesModel.ecModel.getComponent('dataset', option.datasetIndex || 0);\n    }\n}\n\n/**\n * The rule should not be complex, otherwise user might not\n * be able to known where the data is wrong.\n * The code is ugly, but how to make it neat?\n *\n * @param {module:echars/data/Source} source\n * @param {number} dimIndex\n * @return {boolean} Whether ordinal.\n */\nfunction guessOrdinal(source, dimIndex) {\n    return doGuessOrdinal(\n        source.data,\n        source.sourceFormat,\n        source.seriesLayoutBy,\n        source.dimensionsDefine,\n        source.startIndex,\n        dimIndex\n    );\n}\n\n// dimIndex may be overflow source data.\nfunction doGuessOrdinal(\n    data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex\n) {\n    var result;\n    // Experience value.\n    var maxLoop = 5;\n\n    if (isTypedArray(data)) {\n        return false;\n    }\n\n    // When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine\n    // always exists in source.\n    var dimName;\n    if (dimensionsDefine) {\n        dimName = dimensionsDefine[dimIndex];\n        dimName = isObject$1(dimName) ? dimName.name : dimName;\n    }\n\n    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {\n        if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {\n            var sample = data[dimIndex];\n            for (var i = 0; i < (sample || []).length && i < maxLoop; i++) {\n                if ((result = detectValue(sample[startIndex + i])) != null) {\n                    return result;\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < data.length && i < maxLoop; i++) {\n                var row = data[startIndex + i];\n                if (row && (result = detectValue(row[dimIndex])) != null) {\n                    return result;\n                }\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {\n        if (!dimName) {\n            return;\n        }\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            var item = data[i];\n            if (item && (result = detectValue(item[dimName])) != null) {\n                return result;\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {\n        if (!dimName) {\n            return;\n        }\n        var sample = data[dimName];\n        if (!sample || isTypedArray(sample)) {\n            return false;\n        }\n        for (var i = 0; i < sample.length && i < maxLoop; i++) {\n            if ((result = detectValue(sample[i])) != null) {\n                return result;\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            var item = data[i];\n            var val = getDataItemValue(item);\n            if (!isArray(val)) {\n                return false;\n            }\n            if ((result = detectValue(val[dimIndex])) != null) {\n                return result;\n            }\n        }\n    }\n\n    function detectValue(val) {\n        // Consider usage convenience, '1', '2' will be treated as \"number\".\n        // `isFinit('')` get `true`.\n        if (val != null && isFinite(val) && val !== '') {\n            return false;\n        }\n        else if (isString(val) && val !== '-') {\n            return true;\n        }\n    }\n\n    return false;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * ECharts global model\n *\n * @module {echarts/model/Global}\n */\n\n\n/**\n * Caution: If the mechanism should be changed some day, these cases\n * should be considered:\n *\n * (1) In `merge option` mode, if using the same option to call `setOption`\n * many times, the result should be the same (try our best to ensure that).\n * (2) In `merge option` mode, if a component has no id/name specified, it\n * will be merged by index, and the result sequence of the components is\n * consistent to the original sequence.\n * (3) `reset` feature (in toolbox). Find detailed info in comments about\n * `mergeOption` in module:echarts/model/OptionManager.\n */\n\nvar OPTION_INNER_KEY = '\\0_ec_inner';\n\n/**\n * @alias module:echarts/model/Global\n *\n * @param {Object} option\n * @param {module:echarts/model/Model} parentModel\n * @param {Object} theme\n */\nvar GlobalModel = Model.extend({\n\n    init: function (option, parentModel, theme, optionManager) {\n        theme = theme || {};\n\n        this.option = null; // Mark as not initialized.\n\n        /**\n         * @type {module:echarts/model/Model}\n         * @private\n         */\n        this._theme = new Model(theme);\n\n        /**\n         * @type {module:echarts/model/OptionManager}\n         */\n        this._optionManager = optionManager;\n    },\n\n    setOption: function (option, optionPreprocessorFuncs) {\n        assert$1(\n            !(OPTION_INNER_KEY in option),\n            'please use chart.getOption()'\n        );\n\n        this._optionManager.setOption(option, optionPreprocessorFuncs);\n\n        this.resetOption(null);\n    },\n\n    /**\n     * @param {string} type null/undefined: reset all.\n     *                      'recreate': force recreate all.\n     *                      'timeline': only reset timeline option\n     *                      'media': only reset media query option\n     * @return {boolean} Whether option changed.\n     */\n    resetOption: function (type) {\n        var optionChanged = false;\n        var optionManager = this._optionManager;\n\n        if (!type || type === 'recreate') {\n            var baseOption = optionManager.mountOption(type === 'recreate');\n\n            if (!this.option || type === 'recreate') {\n                initBase.call(this, baseOption);\n            }\n            else {\n                this.restoreData();\n                this.mergeOption(baseOption);\n            }\n            optionChanged = true;\n        }\n\n        if (type === 'timeline' || type === 'media') {\n            this.restoreData();\n        }\n\n        if (!type || type === 'recreate' || type === 'timeline') {\n            var timelineOption = optionManager.getTimelineOption(this);\n            timelineOption && (this.mergeOption(timelineOption), optionChanged = true);\n        }\n\n        if (!type || type === 'recreate' || type === 'media') {\n            var mediaOptions = optionManager.getMediaOption(this, this._api);\n            if (mediaOptions.length) {\n                each$1(mediaOptions, function (mediaOption) {\n                    this.mergeOption(mediaOption, optionChanged = true);\n                }, this);\n            }\n        }\n\n        return optionChanged;\n    },\n\n    /**\n     * @protected\n     */\n    mergeOption: function (newOption) {\n        var option = this.option;\n        var componentsMap = this._componentsMap;\n        var newCptTypes = [];\n\n        resetSourceDefaulter(this);\n\n        // If no component class, merge directly.\n        // For example: color, animaiton options, etc.\n        each$1(newOption, function (componentOption, mainType) {\n            if (componentOption == null) {\n                return;\n            }\n\n            if (!ComponentModel.hasClass(mainType)) {\n                // globalSettingTask.dirty();\n                option[mainType] = option[mainType] == null\n                    ? clone(componentOption)\n                    : merge(option[mainType], componentOption, true);\n            }\n            else if (mainType) {\n                newCptTypes.push(mainType);\n            }\n        });\n\n        ComponentModel.topologicalTravel(\n            newCptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this\n        );\n\n        function visitComponent(mainType, dependencies) {\n\n            var newCptOptionList = normalizeToArray(newOption[mainType]);\n\n            var mapResult = mappingToExists(\n                componentsMap.get(mainType), newCptOptionList\n            );\n\n            makeIdAndName(mapResult);\n\n            // Set mainType and complete subType.\n            each$1(mapResult, function (item, index) {\n                var opt = item.option;\n                if (isObject$1(opt)) {\n                    item.keyInfo.mainType = mainType;\n                    item.keyInfo.subType = determineSubType(mainType, opt, item.exist);\n                }\n            });\n\n            var dependentModels = getComponentsByTypes(\n                componentsMap, dependencies\n            );\n\n            option[mainType] = [];\n            componentsMap.set(mainType, []);\n\n            each$1(mapResult, function (resultItem, index) {\n                var componentModel = resultItem.exist;\n                var newCptOption = resultItem.option;\n\n                assert$1(\n                    isObject$1(newCptOption) || componentModel,\n                    'Empty component definition'\n                );\n\n                // Consider where is no new option and should be merged using {},\n                // see removeEdgeAndAdd in topologicalTravel and\n                // ComponentModel.getAllClassMainTypes.\n                if (!newCptOption) {\n                    componentModel.mergeOption({}, this);\n                    componentModel.optionUpdated({}, false);\n                }\n                else {\n                    var ComponentModelClass = ComponentModel.getClass(\n                        mainType, resultItem.keyInfo.subType, true\n                    );\n\n                    if (componentModel && componentModel instanceof ComponentModelClass) {\n                        componentModel.name = resultItem.keyInfo.name;\n                        // componentModel.settingTask && componentModel.settingTask.dirty();\n                        componentModel.mergeOption(newCptOption, this);\n                        componentModel.optionUpdated(newCptOption, false);\n                    }\n                    else {\n                        // PENDING Global as parent ?\n                        var extraOpt = extend(\n                            {\n                                dependentModels: dependentModels,\n                                componentIndex: index\n                            },\n                            resultItem.keyInfo\n                        );\n                        componentModel = new ComponentModelClass(\n                            newCptOption, this, this, extraOpt\n                        );\n                        extend(componentModel, extraOpt);\n                        componentModel.init(newCptOption, this, this, extraOpt);\n\n                        // Call optionUpdated after init.\n                        // newCptOption has been used as componentModel.option\n                        // and may be merged with theme and default, so pass null\n                        // to avoid confusion.\n                        componentModel.optionUpdated(null, true);\n                    }\n                }\n\n                componentsMap.get(mainType)[index] = componentModel;\n                option[mainType][index] = componentModel.option;\n            }, this);\n\n            // Backup series for filtering.\n            if (mainType === 'series') {\n                createSeriesIndices(this, componentsMap.get('series'));\n            }\n        }\n\n        this._seriesIndicesMap = createHashMap(\n            this._seriesIndices = this._seriesIndices || []\n        );\n    },\n\n    /**\n     * Get option for output (cloned option and inner info removed)\n     * @public\n     * @return {Object}\n     */\n    getOption: function () {\n        var option = clone(this.option);\n\n        each$1(option, function (opts, mainType) {\n            if (ComponentModel.hasClass(mainType)) {\n                var opts = normalizeToArray(opts);\n                for (var i = opts.length - 1; i >= 0; i--) {\n                    // Remove options with inner id.\n                    if (isIdInner(opts[i])) {\n                        opts.splice(i, 1);\n                    }\n                }\n                option[mainType] = opts;\n            }\n        });\n\n        delete option[OPTION_INNER_KEY];\n\n        return option;\n    },\n\n    /**\n     * @return {module:echarts/model/Model}\n     */\n    getTheme: function () {\n        return this._theme;\n    },\n\n    /**\n     * @param {string} mainType\n     * @param {number} [idx=0]\n     * @return {module:echarts/model/Component}\n     */\n    getComponent: function (mainType, idx) {\n        var list = this._componentsMap.get(mainType);\n        if (list) {\n            return list[idx || 0];\n        }\n    },\n\n    /**\n     * If none of index and id and name used, return all components with mainType.\n     * @param {Object} condition\n     * @param {string} condition.mainType\n     * @param {string} [condition.subType] If ignore, only query by mainType\n     * @param {number|Array.<number>} [condition.index] Either input index or id or name.\n     * @param {string|Array.<string>} [condition.id] Either input index or id or name.\n     * @param {string|Array.<string>} [condition.name] Either input index or id or name.\n     * @return {Array.<module:echarts/model/Component>}\n     */\n    queryComponents: function (condition) {\n        var mainType = condition.mainType;\n        if (!mainType) {\n            return [];\n        }\n\n        var index = condition.index;\n        var id = condition.id;\n        var name = condition.name;\n\n        var cpts = this._componentsMap.get(mainType);\n\n        if (!cpts || !cpts.length) {\n            return [];\n        }\n\n        var result;\n\n        if (index != null) {\n            if (!isArray(index)) {\n                index = [index];\n            }\n            result = filter(map(index, function (idx) {\n                return cpts[idx];\n            }), function (val) {\n                return !!val;\n            });\n        }\n        else if (id != null) {\n            var isIdArray = isArray(id);\n            result = filter(cpts, function (cpt) {\n                return (isIdArray && indexOf(id, cpt.id) >= 0)\n                    || (!isIdArray && cpt.id === id);\n            });\n        }\n        else if (name != null) {\n            var isNameArray = isArray(name);\n            result = filter(cpts, function (cpt) {\n                return (isNameArray && indexOf(name, cpt.name) >= 0)\n                    || (!isNameArray && cpt.name === name);\n            });\n        }\n        else {\n            // Return all components with mainType\n            result = cpts.slice();\n        }\n\n        return filterBySubType(result, condition);\n    },\n\n    /**\n     * The interface is different from queryComponents,\n     * which is convenient for inner usage.\n     *\n     * @usage\n     * var result = findComponents(\n     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}}\n     * );\n     * var result = findComponents(\n     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}}\n     * );\n     * var result = findComponents(\n     *     {mainType: 'series'},\n     *     function (model, index) {...}\n     * );\n     * // result like [component0, componnet1, ...]\n     *\n     * @param {Object} condition\n     * @param {string} condition.mainType Mandatory.\n     * @param {string} [condition.subType] Optional.\n     * @param {Object} [condition.query] like {xxxIndex, xxxId, xxxName},\n     *        where xxx is mainType.\n     *        If query attribute is null/undefined or has no index/id/name,\n     *        do not filtering by query conditions, which is convenient for\n     *        no-payload situations or when target of action is global.\n     * @param {Function} [condition.filter] parameter: component, return boolean.\n     * @return {Array.<module:echarts/model/Component>}\n     */\n    findComponents: function (condition) {\n        var query = condition.query;\n        var mainType = condition.mainType;\n\n        var queryCond = getQueryCond(query);\n        var result = queryCond\n            ? this.queryComponents(queryCond)\n            : this._componentsMap.get(mainType);\n\n        return doFilter(filterBySubType(result, condition));\n\n        function getQueryCond(q) {\n            var indexAttr = mainType + 'Index';\n            var idAttr = mainType + 'Id';\n            var nameAttr = mainType + 'Name';\n            return q && (\n                    q[indexAttr] != null\n                    || q[idAttr] != null\n                    || q[nameAttr] != null\n                )\n                ? {\n                    mainType: mainType,\n                    // subType will be filtered finally.\n                    index: q[indexAttr],\n                    id: q[idAttr],\n                    name: q[nameAttr]\n                }\n                : null;\n        }\n\n        function doFilter(res) {\n            return condition.filter\n                    ? filter(res, condition.filter)\n                    : res;\n        }\n    },\n\n    /**\n     * @usage\n     * eachComponent('legend', function (legendModel, index) {\n     *     ...\n     * });\n     * eachComponent(function (componentType, model, index) {\n     *     // componentType does not include subType\n     *     // (componentType is 'xxx' but not 'xxx.aa')\n     * });\n     * eachComponent(\n     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}},\n     *     function (model, index) {...}\n     * );\n     * eachComponent(\n     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}},\n     *     function (model, index) {...}\n     * );\n     *\n     * @param {string|Object=} mainType When mainType is object, the definition\n     *                                  is the same as the method 'findComponents'.\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachComponent: function (mainType, cb, context) {\n        var componentsMap = this._componentsMap;\n\n        if (typeof mainType === 'function') {\n            context = cb;\n            cb = mainType;\n            componentsMap.each(function (components, componentType) {\n                each$1(components, function (component, index) {\n                    cb.call(context, componentType, component, index);\n                });\n            });\n        }\n        else if (isString(mainType)) {\n            each$1(componentsMap.get(mainType), cb, context);\n        }\n        else if (isObject$1(mainType)) {\n            var queryResult = this.findComponents(mainType);\n            each$1(queryResult, cb, context);\n        }\n    },\n\n    /**\n     * @param {string} name\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeriesByName: function (name) {\n        var series = this._componentsMap.get('series');\n        return filter(series, function (oneSeries) {\n            return oneSeries.name === name;\n        });\n    },\n\n    /**\n     * @param {number} seriesIndex\n     * @return {module:echarts/model/Series}\n     */\n    getSeriesByIndex: function (seriesIndex) {\n        return this._componentsMap.get('series')[seriesIndex];\n    },\n\n    /**\n     * Get series list before filtered by type.\n     * FIXME: rename to getRawSeriesByType?\n     *\n     * @param {string} subType\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeriesByType: function (subType) {\n        var series = this._componentsMap.get('series');\n        return filter(series, function (oneSeries) {\n            return oneSeries.subType === subType;\n        });\n    },\n\n    /**\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeries: function () {\n        return this._componentsMap.get('series').slice();\n    },\n\n    /**\n     * @return {number}\n     */\n    getSeriesCount: function () {\n        return this._componentsMap.get('series').length;\n    },\n\n    /**\n     * After filtering, series may be different\n     * frome raw series.\n     *\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachSeries: function (cb, context) {\n        assertSeriesInitialized(this);\n        each$1(this._seriesIndices, function (rawSeriesIndex) {\n            var series = this._componentsMap.get('series')[rawSeriesIndex];\n            cb.call(context, series, rawSeriesIndex);\n        }, this);\n    },\n\n    /**\n     * Iterate raw series before filtered.\n     *\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachRawSeries: function (cb, context) {\n        each$1(this._componentsMap.get('series'), cb, context);\n    },\n\n    /**\n     * After filtering, series may be different.\n     * frome raw series.\n     *\n     * @parma {string} subType\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachSeriesByType: function (subType, cb, context) {\n        assertSeriesInitialized(this);\n        each$1(this._seriesIndices, function (rawSeriesIndex) {\n            var series = this._componentsMap.get('series')[rawSeriesIndex];\n            if (series.subType === subType) {\n                cb.call(context, series, rawSeriesIndex);\n            }\n        }, this);\n    },\n\n    /**\n     * Iterate raw series before filtered of given type.\n     *\n     * @parma {string} subType\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachRawSeriesByType: function (subType, cb, context) {\n        return each$1(this.getSeriesByType(subType), cb, context);\n    },\n\n    /**\n     * @param {module:echarts/model/Series} seriesModel\n     */\n    isSeriesFiltered: function (seriesModel) {\n        assertSeriesInitialized(this);\n        return this._seriesIndicesMap.get(seriesModel.componentIndex) == null;\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getCurrentSeriesIndices: function () {\n        return (this._seriesIndices || []).slice();\n    },\n\n    /**\n     * @param {Function} cb\n     * @param {*} context\n     */\n    filterSeries: function (cb, context) {\n        assertSeriesInitialized(this);\n        var filteredSeries = filter(\n            this._componentsMap.get('series'), cb, context\n        );\n        createSeriesIndices(this, filteredSeries);\n    },\n\n    restoreData: function (payload) {\n        var componentsMap = this._componentsMap;\n\n        createSeriesIndices(this, componentsMap.get('series'));\n\n        var componentTypes = [];\n        componentsMap.each(function (components, componentType) {\n            componentTypes.push(componentType);\n        });\n\n        ComponentModel.topologicalTravel(\n            componentTypes,\n            ComponentModel.getAllClassMainTypes(),\n            function (componentType, dependencies) {\n                each$1(componentsMap.get(componentType), function (component) {\n                    (componentType !== 'series' || !isNotTargetSeries(component, payload))\n                        && component.restoreData();\n                });\n            }\n        );\n    }\n\n});\n\nfunction isNotTargetSeries(seriesModel, payload) {\n    if (payload) {\n        var index = payload.seiresIndex;\n        var id = payload.seriesId;\n        var name = payload.seriesName;\n        return (index != null && seriesModel.componentIndex !== index)\n            || (id != null && seriesModel.id !== id)\n            || (name != null && seriesModel.name !== name);\n    }\n}\n\n/**\n * @inner\n */\nfunction mergeTheme(option, theme) {\n    // PENDING\n    // NOT use `colorLayer` in theme if option has `color`\n    var notMergeColorLayer = option.color && !option.colorLayer;\n\n    each$1(theme, function (themeItem, name) {\n        if (name === 'colorLayer' && notMergeColorLayer) {\n            return;\n        }\n        // 如果有 component model 则把具体的 merge 逻辑交给该 model 处理\n        if (!ComponentModel.hasClass(name)) {\n            if (typeof themeItem === 'object') {\n                option[name] = !option[name]\n                    ? clone(themeItem)\n                    : merge(option[name], themeItem, false);\n            }\n            else {\n                if (option[name] == null) {\n                    option[name] = themeItem;\n                }\n            }\n        }\n    });\n}\n\nfunction initBase(baseOption) {\n    baseOption = baseOption;\n\n    // Using OPTION_INNER_KEY to mark that this option can not be used outside,\n    // i.e. `chart.setOption(chart.getModel().option);` is forbiden.\n    this.option = {};\n    this.option[OPTION_INNER_KEY] = 1;\n\n    /**\n     * Init with series: [], in case of calling findSeries method\n     * before series initialized.\n     * @type {Object.<string, Array.<module:echarts/model/Model>>}\n     * @private\n     */\n    this._componentsMap = createHashMap({series: []});\n\n    /**\n     * Mapping between filtered series list and raw series list.\n     * key: filtered series indices, value: raw series indices.\n     * @type {Array.<nubmer>}\n     * @private\n     */\n    this._seriesIndices;\n\n    this._seriesIndicesMap;\n\n    mergeTheme(baseOption, this._theme.option);\n\n    // TODO Needs clone when merging to the unexisted property\n    merge(baseOption, globalDefault, false);\n\n    this.mergeOption(baseOption);\n}\n\n/**\n * @inner\n * @param {Array.<string>|string} types model types\n * @return {Object} key: {string} type, value: {Array.<Object>} models\n */\nfunction getComponentsByTypes(componentsMap, types) {\n    if (!isArray(types)) {\n        types = types ? [types] : [];\n    }\n\n    var ret = {};\n    each$1(types, function (type) {\n        ret[type] = (componentsMap.get(type) || []).slice();\n    });\n\n    return ret;\n}\n\n/**\n * @inner\n */\nfunction determineSubType(mainType, newCptOption, existComponent) {\n    var subType = newCptOption.type\n        ? newCptOption.type\n        : existComponent\n        ? existComponent.subType\n        // Use determineSubType only when there is no existComponent.\n        : ComponentModel.determineSubType(mainType, newCptOption);\n\n    // tooltip, markline, markpoint may always has no subType\n    return subType;\n}\n\n/**\n * @inner\n */\nfunction createSeriesIndices(ecModel, seriesModels) {\n    ecModel._seriesIndicesMap = createHashMap(\n        ecModel._seriesIndices = map(seriesModels, function (series) {\n            return series.componentIndex;\n        }) || []\n    );\n}\n\n/**\n * @inner\n */\nfunction filterBySubType(components, condition) {\n    // Using hasOwnProperty for restrict. Consider\n    // subType is undefined in user payload.\n    return condition.hasOwnProperty('subType')\n        ? filter(components, function (cpt) {\n            return cpt.subType === condition.subType;\n        })\n        : components;\n}\n\n/**\n * @inner\n */\nfunction assertSeriesInitialized(ecModel) {\n    // Components that use _seriesIndices should depends on series component,\n    // which make sure that their initialization is after series.\n    if (__DEV__) {\n        if (!ecModel._seriesIndices) {\n            throw new Error('Option should contains series.');\n        }\n    }\n}\n\nmixin(GlobalModel, colorPaletteMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar echartsAPIList = [\n    'getDom', 'getZr', 'getWidth', 'getHeight', 'getDevicePixelRatio', 'dispatchAction', 'isDisposed',\n    'on', 'off', 'getDataURL', 'getConnectedDataURL', 'getModel', 'getOption',\n    'getViewOfComponentModel', 'getViewOfSeriesModel'\n];\n// And `getCoordinateSystems` and `getComponentByElement` will be injected in echarts.js\n\nfunction ExtensionAPI(chartInstance) {\n    each$1(echartsAPIList, function (name) {\n        this[name] = bind(chartInstance[name], chartInstance);\n    }, this);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar coordinateSystemCreators = {};\n\nfunction CoordinateSystemManager() {\n\n    this._coordinateSystems = [];\n}\n\nCoordinateSystemManager.prototype = {\n\n    constructor: CoordinateSystemManager,\n\n    create: function (ecModel, api) {\n        var coordinateSystems = [];\n        each$1(coordinateSystemCreators, function (creater, type) {\n            var list = creater.create(ecModel, api);\n            coordinateSystems = coordinateSystems.concat(list || []);\n        });\n\n        this._coordinateSystems = coordinateSystems;\n    },\n\n    update: function (ecModel, api) {\n        each$1(this._coordinateSystems, function (coordSys) {\n            coordSys.update && coordSys.update(ecModel, api);\n        });\n    },\n\n    getCoordinateSystems: function () {\n        return this._coordinateSystems.slice();\n    }\n};\n\nCoordinateSystemManager.register = function (type, coordinateSystemCreator) {\n    coordinateSystemCreators[type] = coordinateSystemCreator;\n};\n\nCoordinateSystemManager.get = function (type) {\n    return coordinateSystemCreators[type];\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * ECharts option manager\n *\n * @module {echarts/model/OptionManager}\n */\n\n\nvar each$4 = each$1;\nvar clone$3 = clone;\nvar map$1 = map;\nvar merge$1 = merge;\n\nvar QUERY_REG = /^(min|max)?(.+)$/;\n\n/**\n * TERM EXPLANATIONS:\n *\n * [option]:\n *\n *     An object that contains definitions of components. For example:\n *     var option = {\n *         title: {...},\n *         legend: {...},\n *         visualMap: {...},\n *         series: [\n *             {data: [...]},\n *             {data: [...]},\n *             ...\n *         ]\n *     };\n *\n * [rawOption]:\n *\n *     An object input to echarts.setOption. 'rawOption' may be an\n *     'option', or may be an object contains multi-options. For example:\n *     var option = {\n *         baseOption: {\n *             title: {...},\n *             legend: {...},\n *             series: [\n *                 {data: [...]},\n *                 {data: [...]},\n *                 ...\n *             ]\n *         },\n *         timeline: {...},\n *         options: [\n *             {title: {...}, series: {data: [...]}},\n *             {title: {...}, series: {data: [...]}},\n *             ...\n *         ],\n *         media: [\n *             {\n *                 query: {maxWidth: 320},\n *                 option: {series: {x: 20}, visualMap: {show: false}}\n *             },\n *             {\n *                 query: {minWidth: 320, maxWidth: 720},\n *                 option: {series: {x: 500}, visualMap: {show: true}}\n *             },\n *             {\n *                 option: {series: {x: 1200}, visualMap: {show: true}}\n *             }\n *         ]\n *     };\n *\n * @alias module:echarts/model/OptionManager\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction OptionManager(api) {\n\n    /**\n     * @private\n     * @type {module:echarts/ExtensionAPI}\n     */\n    this._api = api;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._timelineOptions = [];\n\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    this._mediaList = [];\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._mediaDefault;\n\n    /**\n     * -1, means default.\n     * empty means no media.\n     * @private\n     * @type {Array.<number>}\n     */\n    this._currentMediaIndices = [];\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._optionBackup;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._newBaseOption;\n}\n\n// timeline.notMerge is not supported in ec3. Firstly there is rearly\n// case that notMerge is needed. Secondly supporting 'notMerge' requires\n// rawOption cloned and backuped when timeline changed, which does no\n// good to performance. What's more, that both timeline and setOption\n// method supply 'notMerge' brings complex and some problems.\n// Consider this case:\n// (step1) chart.setOption({timeline: {notMerge: false}, ...}, false);\n// (step2) chart.setOption({timeline: {notMerge: true}, ...}, false);\n\nOptionManager.prototype = {\n\n    constructor: OptionManager,\n\n    /**\n     * @public\n     * @param {Object} rawOption Raw option.\n     * @param {module:echarts/model/Global} ecModel\n     * @param {Array.<Function>} optionPreprocessorFuncs\n     * @return {Object} Init option\n     */\n    setOption: function (rawOption, optionPreprocessorFuncs) {\n        if (rawOption) {\n            // That set dat primitive is dangerous if user reuse the data when setOption again.\n            each$1(normalizeToArray(rawOption.series), function (series) {\n                series && series.data && isTypedArray(series.data) && setAsPrimitive(series.data);\n            });\n        }\n\n        // Caution: some series modify option data, if do not clone,\n        // it should ensure that the repeat modify correctly\n        // (create a new object when modify itself).\n        rawOption = clone$3(rawOption, true);\n\n        // FIXME\n        // 如果 timeline options 或者 media 中设置了某个属性，而baseOption中没有设置，则进行警告。\n\n        var oldOptionBackup = this._optionBackup;\n        var newParsedOption = parseRawOption.call(\n            this, rawOption, optionPreprocessorFuncs, !oldOptionBackup\n        );\n        this._newBaseOption = newParsedOption.baseOption;\n\n        // For setOption at second time (using merge mode);\n        if (oldOptionBackup) {\n            // Only baseOption can be merged.\n            mergeOption(oldOptionBackup.baseOption, newParsedOption.baseOption);\n\n            // For simplicity, timeline options and media options do not support merge,\n            // that is, if you `setOption` twice and both has timeline options, the latter\n            // timeline opitons will not be merged to the formers, but just substitude them.\n            if (newParsedOption.timelineOptions.length) {\n                oldOptionBackup.timelineOptions = newParsedOption.timelineOptions;\n            }\n            if (newParsedOption.mediaList.length) {\n                oldOptionBackup.mediaList = newParsedOption.mediaList;\n            }\n            if (newParsedOption.mediaDefault) {\n                oldOptionBackup.mediaDefault = newParsedOption.mediaDefault;\n            }\n        }\n        else {\n            this._optionBackup = newParsedOption;\n        }\n    },\n\n    /**\n     * @param {boolean} isRecreate\n     * @return {Object}\n     */\n    mountOption: function (isRecreate) {\n        var optionBackup = this._optionBackup;\n\n        // TODO\n        // 如果没有reset功能则不clone。\n\n        this._timelineOptions = map$1(optionBackup.timelineOptions, clone$3);\n        this._mediaList = map$1(optionBackup.mediaList, clone$3);\n        this._mediaDefault = clone$3(optionBackup.mediaDefault);\n        this._currentMediaIndices = [];\n\n        return clone$3(isRecreate\n            // this._optionBackup.baseOption, which is created at the first `setOption`\n            // called, and is merged into every new option by inner method `mergeOption`\n            // each time `setOption` called, can be only used in `isRecreate`, because\n            // its reliability is under suspicion. In other cases option merge is\n            // performed by `model.mergeOption`.\n            ? optionBackup.baseOption : this._newBaseOption\n        );\n    },\n\n    /**\n     * @param {module:echarts/model/Global} ecModel\n     * @return {Object}\n     */\n    getTimelineOption: function (ecModel) {\n        var option;\n        var timelineOptions = this._timelineOptions;\n\n        if (timelineOptions.length) {\n            // getTimelineOption can only be called after ecModel inited,\n            // so we can get currentIndex from timelineModel.\n            var timelineModel = ecModel.getComponent('timeline');\n            if (timelineModel) {\n                option = clone$3(\n                    timelineOptions[timelineModel.getCurrentIndex()],\n                    true\n                );\n            }\n        }\n\n        return option;\n    },\n\n    /**\n     * @param {module:echarts/model/Global} ecModel\n     * @return {Array.<Object>}\n     */\n    getMediaOption: function (ecModel) {\n        var ecWidth = this._api.getWidth();\n        var ecHeight = this._api.getHeight();\n        var mediaList = this._mediaList;\n        var mediaDefault = this._mediaDefault;\n        var indices = [];\n        var result = [];\n\n        // No media defined.\n        if (!mediaList.length && !mediaDefault) {\n            return result;\n        }\n\n        // Multi media may be applied, the latter defined media has higher priority.\n        for (var i = 0, len = mediaList.length; i < len; i++) {\n            if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) {\n                indices.push(i);\n            }\n        }\n\n        // FIXME\n        // 是否mediaDefault应该强制用户设置，否则可能修改不能回归。\n        if (!indices.length && mediaDefault) {\n            indices = [-1];\n        }\n\n        if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) {\n            result = map$1(indices, function (index) {\n                return clone$3(\n                    index === -1 ? mediaDefault.option : mediaList[index].option\n                );\n            });\n        }\n        // Otherwise return nothing.\n\n        this._currentMediaIndices = indices;\n\n        return result;\n    }\n};\n\nfunction parseRawOption(rawOption, optionPreprocessorFuncs, isNew) {\n    var timelineOptions = [];\n    var mediaList = [];\n    var mediaDefault;\n    var baseOption;\n\n    // Compatible with ec2.\n    var timelineOpt = rawOption.timeline;\n\n    if (rawOption.baseOption) {\n        baseOption = rawOption.baseOption;\n    }\n\n    // For timeline\n    if (timelineOpt || rawOption.options) {\n        baseOption = baseOption || {};\n        timelineOptions = (rawOption.options || []).slice();\n    }\n\n    // For media query\n    if (rawOption.media) {\n        baseOption = baseOption || {};\n        var media = rawOption.media;\n        each$4(media, function (singleMedia) {\n            if (singleMedia && singleMedia.option) {\n                if (singleMedia.query) {\n                    mediaList.push(singleMedia);\n                }\n                else if (!mediaDefault) {\n                    // Use the first media default.\n                    mediaDefault = singleMedia;\n                }\n            }\n        });\n    }\n\n    // For normal option\n    if (!baseOption) {\n        baseOption = rawOption;\n    }\n\n    // Set timelineOpt to baseOption in ec3,\n    // which is convenient for merge option.\n    if (!baseOption.timeline) {\n        baseOption.timeline = timelineOpt;\n    }\n\n    // Preprocess.\n    each$4([baseOption].concat(timelineOptions)\n        .concat(map(mediaList, function (media) {\n            return media.option;\n        })),\n        function (option) {\n            each$4(optionPreprocessorFuncs, function (preProcess) {\n                preProcess(option, isNew);\n            });\n        }\n    );\n\n    return {\n        baseOption: baseOption,\n        timelineOptions: timelineOptions,\n        mediaDefault: mediaDefault,\n        mediaList: mediaList\n    };\n}\n\n/**\n * @see <http://www.w3.org/TR/css3-mediaqueries/#media1>\n * Support: width, height, aspectRatio\n * Can use max or min as prefix.\n */\nfunction applyMediaQuery(query, ecWidth, ecHeight) {\n    var realMap = {\n        width: ecWidth,\n        height: ecHeight,\n        aspectratio: ecWidth / ecHeight // lowser case for convenientce.\n    };\n\n    var applicatable = true;\n\n    each$1(query, function (value, attr) {\n        var matched = attr.match(QUERY_REG);\n\n        if (!matched || !matched[1] || !matched[2]) {\n            return;\n        }\n\n        var operator = matched[1];\n        var realAttr = matched[2].toLowerCase();\n\n        if (!compare(realMap[realAttr], value, operator)) {\n            applicatable = false;\n        }\n    });\n\n    return applicatable;\n}\n\nfunction compare(real, expect, operator) {\n    if (operator === 'min') {\n        return real >= expect;\n    }\n    else if (operator === 'max') {\n        return real <= expect;\n    }\n    else { // Equals\n        return real === expect;\n    }\n}\n\nfunction indicesEquals(indices1, indices2) {\n    // indices is always order by asc and has only finite number.\n    return indices1.join(',') === indices2.join(',');\n}\n\n/**\n * Consider case:\n * `chart.setOption(opt1);`\n * Then user do some interaction like dataZoom, dataView changing.\n * `chart.setOption(opt2);`\n * Then user press 'reset button' in toolbox.\n *\n * After doing that all of the interaction effects should be reset, the\n * chart should be the same as the result of invoke\n * `chart.setOption(opt1); chart.setOption(opt2);`.\n *\n * Although it is not able ensure that\n * `chart.setOption(opt1); chart.setOption(opt2);` is equivalents to\n * `chart.setOption(merge(opt1, opt2));` exactly,\n * this might be the only simple way to implement that feature.\n *\n * MEMO: We've considered some other approaches:\n * 1. Each model handle its self restoration but not uniform treatment.\n *     (Too complex in logic and error-prone)\n * 2. Use a shadow ecModel. (Performace expensive)\n */\nfunction mergeOption(oldOption, newOption) {\n    newOption = newOption || {};\n\n    each$4(newOption, function (newCptOpt, mainType) {\n        if (newCptOpt == null) {\n            return;\n        }\n\n        var oldCptOpt = oldOption[mainType];\n\n        if (!ComponentModel.hasClass(mainType)) {\n            oldOption[mainType] = merge$1(oldCptOpt, newCptOpt, true);\n        }\n        else {\n            newCptOpt = normalizeToArray(newCptOpt);\n            oldCptOpt = normalizeToArray(oldCptOpt);\n\n            var mapResult = mappingToExists(oldCptOpt, newCptOpt);\n\n            oldOption[mainType] = map$1(mapResult, function (item) {\n                return (item.option && item.exist)\n                    ? merge$1(item.exist, item.option, true)\n                    : (item.exist || item.option);\n            });\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$5 = each$1;\nvar isObject$3 = isObject$1;\n\nvar POSSIBLE_STYLES = [\n    'areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle',\n    'chordStyle', 'label', 'labelLine'\n];\n\nfunction compatEC2ItemStyle(opt) {\n    var itemStyleOpt = opt && opt.itemStyle;\n    if (!itemStyleOpt) {\n        return;\n    }\n    for (var i = 0, len = POSSIBLE_STYLES.length; i < len; i++) {\n        var styleName = POSSIBLE_STYLES[i];\n        var normalItemStyleOpt = itemStyleOpt.normal;\n        var emphasisItemStyleOpt = itemStyleOpt.emphasis;\n        if (normalItemStyleOpt && normalItemStyleOpt[styleName]) {\n            opt[styleName] = opt[styleName] || {};\n            if (!opt[styleName].normal) {\n                opt[styleName].normal = normalItemStyleOpt[styleName];\n            }\n            else {\n                merge(opt[styleName].normal, normalItemStyleOpt[styleName]);\n            }\n            normalItemStyleOpt[styleName] = null;\n        }\n        if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) {\n            opt[styleName] = opt[styleName] || {};\n            if (!opt[styleName].emphasis) {\n                opt[styleName].emphasis = emphasisItemStyleOpt[styleName];\n            }\n            else {\n                merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]);\n            }\n            emphasisItemStyleOpt[styleName] = null;\n        }\n    }\n}\n\nfunction convertNormalEmphasis(opt, optType, useExtend) {\n    if (opt && opt[optType] && (opt[optType].normal || opt[optType].emphasis)) {\n        var normalOpt = opt[optType].normal;\n        var emphasisOpt = opt[optType].emphasis;\n\n        if (normalOpt) {\n            // Timeline controlStyle has other properties besides normal and emphasis\n            if (useExtend) {\n                opt[optType].normal = opt[optType].emphasis = null;\n                defaults(opt[optType], normalOpt);\n            }\n            else {\n                opt[optType] = normalOpt;\n            }\n        }\n        if (emphasisOpt) {\n            opt.emphasis = opt.emphasis || {};\n            opt.emphasis[optType] = emphasisOpt;\n        }\n    }\n}\nfunction removeEC3NormalStatus(opt) {\n    convertNormalEmphasis(opt, 'itemStyle');\n    convertNormalEmphasis(opt, 'lineStyle');\n    convertNormalEmphasis(opt, 'areaStyle');\n    convertNormalEmphasis(opt, 'label');\n    convertNormalEmphasis(opt, 'labelLine');\n    // treemap\n    convertNormalEmphasis(opt, 'upperLabel');\n    // graph\n    convertNormalEmphasis(opt, 'edgeLabel');\n}\n\nfunction compatTextStyle(opt, propName) {\n    // Check whether is not object (string\\null\\undefined ...)\n    var labelOptSingle = isObject$3(opt) && opt[propName];\n    var textStyle = isObject$3(labelOptSingle) && labelOptSingle.textStyle;\n    if (textStyle) {\n        for (var i = 0, len = TEXT_STYLE_OPTIONS.length; i < len; i++) {\n            var propName = TEXT_STYLE_OPTIONS[i];\n            if (textStyle.hasOwnProperty(propName)) {\n                labelOptSingle[propName] = textStyle[propName];\n            }\n        }\n    }\n}\n\nfunction compatEC3CommonStyles(opt) {\n    if (opt) {\n        removeEC3NormalStatus(opt);\n        compatTextStyle(opt, 'label');\n        opt.emphasis && compatTextStyle(opt.emphasis, 'label');\n    }\n}\n\nfunction processSeries(seriesOpt) {\n    if (!isObject$3(seriesOpt)) {\n        return;\n    }\n\n    compatEC2ItemStyle(seriesOpt);\n    removeEC3NormalStatus(seriesOpt);\n\n    compatTextStyle(seriesOpt, 'label');\n    // treemap\n    compatTextStyle(seriesOpt, 'upperLabel');\n    // graph\n    compatTextStyle(seriesOpt, 'edgeLabel');\n    if (seriesOpt.emphasis) {\n        compatTextStyle(seriesOpt.emphasis, 'label');\n        // treemap\n        compatTextStyle(seriesOpt.emphasis, 'upperLabel');\n        // graph\n        compatTextStyle(seriesOpt.emphasis, 'edgeLabel');\n    }\n\n    var markPoint = seriesOpt.markPoint;\n    if (markPoint) {\n        compatEC2ItemStyle(markPoint);\n        compatEC3CommonStyles(markPoint);\n    }\n\n    var markLine = seriesOpt.markLine;\n    if (markLine) {\n        compatEC2ItemStyle(markLine);\n        compatEC3CommonStyles(markLine);\n    }\n\n    var markArea = seriesOpt.markArea;\n    if (markArea) {\n        compatEC3CommonStyles(markArea);\n    }\n\n    var data = seriesOpt.data;\n\n    // Break with ec3: if `setOption` again, there may be no `type` in option,\n    // then the backward compat based on option type will not be performed.\n\n    if (seriesOpt.type === 'graph') {\n        data = data || seriesOpt.nodes;\n        var edgeData = seriesOpt.links || seriesOpt.edges;\n        if (edgeData && !isTypedArray(edgeData)) {\n            for (var i = 0; i < edgeData.length; i++) {\n                compatEC3CommonStyles(edgeData[i]);\n            }\n        }\n        each$1(seriesOpt.categories, function (opt) {\n            removeEC3NormalStatus(opt);\n        });\n    }\n\n    if (data && !isTypedArray(data)) {\n        for (var i = 0; i < data.length; i++) {\n            compatEC3CommonStyles(data[i]);\n        }\n    }\n\n    // mark point data\n    var markPoint = seriesOpt.markPoint;\n    if (markPoint && markPoint.data) {\n        var mpData = markPoint.data;\n        for (var i = 0; i < mpData.length; i++) {\n            compatEC3CommonStyles(mpData[i]);\n        }\n    }\n    // mark line data\n    var markLine = seriesOpt.markLine;\n    if (markLine && markLine.data) {\n        var mlData = markLine.data;\n        for (var i = 0; i < mlData.length; i++) {\n            if (isArray(mlData[i])) {\n                compatEC3CommonStyles(mlData[i][0]);\n                compatEC3CommonStyles(mlData[i][1]);\n            }\n            else {\n                compatEC3CommonStyles(mlData[i]);\n            }\n        }\n    }\n\n    // Series\n    if (seriesOpt.type === 'gauge') {\n        compatTextStyle(seriesOpt, 'axisLabel');\n        compatTextStyle(seriesOpt, 'title');\n        compatTextStyle(seriesOpt, 'detail');\n    }\n    else if (seriesOpt.type === 'treemap') {\n        convertNormalEmphasis(seriesOpt.breadcrumb, 'itemStyle');\n        each$1(seriesOpt.levels, function (opt) {\n            removeEC3NormalStatus(opt);\n        });\n    }\n    else if (seriesOpt.type === 'tree') {\n        removeEC3NormalStatus(seriesOpt.leaves);\n    }\n    // sunburst starts from ec4, so it does not need to compat levels.\n}\n\nfunction toArr(o) {\n    return isArray(o) ? o : o ? [o] : [];\n}\n\nfunction toObj(o) {\n    return (isArray(o) ? o[0] : o) || {};\n}\n\nvar compatStyle = function (option, isTheme) {\n    each$5(toArr(option.series), function (seriesOpt) {\n        isObject$3(seriesOpt) && processSeries(seriesOpt);\n    });\n\n    var axes = ['xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'parallelAxis', 'radar'];\n    isTheme && axes.push('valueAxis', 'categoryAxis', 'logAxis', 'timeAxis');\n\n    each$5(\n        axes,\n        function (axisName) {\n            each$5(toArr(option[axisName]), function (axisOpt) {\n                if (axisOpt) {\n                    compatTextStyle(axisOpt, 'axisLabel');\n                    compatTextStyle(axisOpt.axisPointer, 'label');\n                }\n            });\n        }\n    );\n\n    each$5(toArr(option.parallel), function (parallelOpt) {\n        var parallelAxisDefault = parallelOpt && parallelOpt.parallelAxisDefault;\n        compatTextStyle(parallelAxisDefault, 'axisLabel');\n        compatTextStyle(parallelAxisDefault && parallelAxisDefault.axisPointer, 'label');\n    });\n\n    each$5(toArr(option.calendar), function (calendarOpt) {\n        convertNormalEmphasis(calendarOpt, 'itemStyle');\n        compatTextStyle(calendarOpt, 'dayLabel');\n        compatTextStyle(calendarOpt, 'monthLabel');\n        compatTextStyle(calendarOpt, 'yearLabel');\n    });\n\n    // radar.name.textStyle\n    each$5(toArr(option.radar), function (radarOpt) {\n        compatTextStyle(radarOpt, 'name');\n    });\n\n    each$5(toArr(option.geo), function (geoOpt) {\n        if (isObject$3(geoOpt)) {\n            compatEC3CommonStyles(geoOpt);\n            each$5(toArr(geoOpt.regions), function (regionObj) {\n                compatEC3CommonStyles(regionObj);\n            });\n        }\n    });\n\n    each$5(toArr(option.timeline), function (timelineOpt) {\n        compatEC3CommonStyles(timelineOpt);\n        convertNormalEmphasis(timelineOpt, 'label');\n        convertNormalEmphasis(timelineOpt, 'itemStyle');\n        convertNormalEmphasis(timelineOpt, 'controlStyle', true);\n\n        var data = timelineOpt.data;\n        isArray(data) && each$1(data, function (item) {\n            if (isObject$1(item)) {\n                convertNormalEmphasis(item, 'label');\n                convertNormalEmphasis(item, 'itemStyle');\n            }\n        });\n    });\n\n    each$5(toArr(option.toolbox), function (toolboxOpt) {\n        convertNormalEmphasis(toolboxOpt, 'iconStyle');\n        each$5(toolboxOpt.feature, function (featureOpt) {\n            convertNormalEmphasis(featureOpt, 'iconStyle');\n        });\n    });\n\n    compatTextStyle(toObj(option.axisPointer), 'label');\n    compatTextStyle(toObj(option.tooltip).axisPointer, 'label');\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Compatitable with 2.0\n\nfunction get(opt, path) {\n    path = path.split(',');\n    var obj = opt;\n    for (var i = 0; i < path.length; i++) {\n        obj = obj && obj[path[i]];\n        if (obj == null) {\n            break;\n        }\n    }\n    return obj;\n}\n\nfunction set$1(opt, path, val, overwrite) {\n    path = path.split(',');\n    var obj = opt;\n    var key;\n    for (var i = 0; i < path.length - 1; i++) {\n        key = path[i];\n        if (obj[key] == null) {\n            obj[key] = {};\n        }\n        obj = obj[key];\n    }\n    if (overwrite || obj[path[i]] == null) {\n        obj[path[i]] = val;\n    }\n}\n\nfunction compatLayoutProperties(option) {\n    each$1(LAYOUT_PROPERTIES, function (prop) {\n        if (prop[0] in option && !(prop[1] in option)) {\n            option[prop[1]] = option[prop[0]];\n        }\n    });\n}\n\nvar LAYOUT_PROPERTIES = [\n    ['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom']\n];\n\nvar COMPATITABLE_COMPONENTS = [\n    'grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline'\n];\n\nvar backwardCompat = function (option, isTheme) {\n    compatStyle(option, isTheme);\n\n    // Make sure series array for model initialization.\n    option.series = normalizeToArray(option.series);\n\n    each$1(option.series, function (seriesOpt) {\n        if (!isObject$1(seriesOpt)) {\n            return;\n        }\n\n        var seriesType = seriesOpt.type;\n\n        if (seriesType === 'pie' || seriesType === 'gauge') {\n            if (seriesOpt.clockWise != null) {\n                seriesOpt.clockwise = seriesOpt.clockWise;\n            }\n        }\n        if (seriesType === 'gauge') {\n            var pointerColor = get(seriesOpt, 'pointer.color');\n            pointerColor != null\n                && set$1(seriesOpt, 'itemStyle.normal.color', pointerColor);\n        }\n\n        compatLayoutProperties(seriesOpt);\n    });\n\n    // dataRange has changed to visualMap\n    if (option.dataRange) {\n        option.visualMap = option.dataRange;\n    }\n\n    each$1(COMPATITABLE_COMPONENTS, function (componentName) {\n        var options = option[componentName];\n        if (options) {\n            if (!isArray(options)) {\n                options = [options];\n            }\n            each$1(options, function (option) {\n                compatLayoutProperties(option);\n            });\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (1) [Caution]: the logic is correct based on the premises:\n//     data processing stage is blocked in stream.\n//     See <module:echarts/stream/Scheduler#performDataProcessorTasks>\n// (2) Only register once when import repeatly.\n//     Should be executed before after series filtered and before stack calculation.\nvar dataStack = function (ecModel) {\n    var stackInfoMap = createHashMap();\n    ecModel.eachSeries(function (seriesModel) {\n        var stack = seriesModel.get('stack');\n        // Compatibal: when `stack` is set as '', do not stack.\n        if (stack) {\n            var stackInfoList = stackInfoMap.get(stack) || stackInfoMap.set(stack, []);\n            var data = seriesModel.getData();\n\n            var stackInfo = {\n                // Used for calculate axis extent automatically.\n                stackResultDimension: data.getCalculationInfo('stackResultDimension'),\n                stackedOverDimension: data.getCalculationInfo('stackedOverDimension'),\n                stackedDimension: data.getCalculationInfo('stackedDimension'),\n                stackedByDimension: data.getCalculationInfo('stackedByDimension'),\n                isStackedByIndex: data.getCalculationInfo('isStackedByIndex'),\n                data: data,\n                seriesModel: seriesModel\n            };\n\n            // If stacked on axis that do not support data stack.\n            if (!stackInfo.stackedDimension\n                || !(stackInfo.isStackedByIndex || stackInfo.stackedByDimension)\n            ) {\n                return;\n            }\n\n            stackInfoList.length && data.setCalculationInfo(\n                'stackedOnSeries', stackInfoList[stackInfoList.length - 1].seriesModel\n            );\n\n            stackInfoList.push(stackInfo);\n        }\n    });\n\n    stackInfoMap.each(calculateStack);\n};\n\nfunction calculateStack(stackInfoList) {\n    each$1(stackInfoList, function (targetStackInfo, idxInStack) {\n        var resultVal = [];\n        var resultNaN = [NaN, NaN];\n        var dims = [targetStackInfo.stackResultDimension, targetStackInfo.stackedOverDimension];\n        var targetData = targetStackInfo.data;\n        var isStackedByIndex = targetStackInfo.isStackedByIndex;\n\n        // Should not write on raw data, because stack series model list changes\n        // depending on legend selection.\n        var newData = targetData.map(dims, function (v0, v1, dataIndex) {\n            var sum = targetData.get(targetStackInfo.stackedDimension, dataIndex);\n\n            // Consider `connectNulls` of line area, if value is NaN, stackedOver\n            // should also be NaN, to draw a appropriate belt area.\n            if (isNaN(sum)) {\n                return resultNaN;\n            }\n\n            var byValue;\n            var stackedDataRawIndex;\n\n            if (isStackedByIndex) {\n                stackedDataRawIndex = targetData.getRawIndex(dataIndex);\n            }\n            else {\n                byValue = targetData.get(targetStackInfo.stackedByDimension, dataIndex);\n            }\n\n            // If stackOver is NaN, chart view will render point on value start.\n            var stackedOver = NaN;\n\n            for (var j = idxInStack - 1; j >= 0; j--) {\n                var stackInfo = stackInfoList[j];\n\n                // Has been optimized by inverted indices on `stackedByDimension`.\n                if (!isStackedByIndex) {\n                    stackedDataRawIndex = stackInfo.data.rawIndexOf(stackInfo.stackedByDimension, byValue);\n                }\n\n                if (stackedDataRawIndex >= 0) {\n                    var val = stackInfo.data.getByRawIndex(stackInfo.stackResultDimension, stackedDataRawIndex);\n\n                    // Considering positive stack, negative stack and empty data\n                    if ((sum >= 0 && val > 0) // Positive stack\n                        || (sum <= 0 && val < 0) // Negative stack\n                    ) {\n                        sum += val;\n                        stackedOver = val;\n                        break;\n                    }\n                }\n            }\n\n            resultVal[0] = sum;\n            resultVal[1] = stackedOver;\n\n            return resultVal;\n        });\n\n        targetData.hostModel.setData(newData);\n        // Update for consequent calculation\n        targetStackInfo.data = newData;\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO\n// ??? refactor? check the outer usage of data provider.\n// merge with defaultDimValueGetter?\n\n/**\n * If normal array used, mutable chunk size is supported.\n * If typed array used, chunk size must be fixed.\n */\nfunction DefaultDataProvider(source, dimSize) {\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n    this._source = source;\n\n    var data = this._data = source.data;\n    var sourceFormat = source.sourceFormat;\n\n    // Typed array. TODO IE10+?\n    if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {\n        if (__DEV__) {\n            if (dimSize == null) {\n                throw new Error('Typed array data must specify dimension size');\n            }\n        }\n        this._offset = 0;\n        this._dimSize = dimSize;\n        this._data = data;\n    }\n\n    var methods = providerMethods[\n        sourceFormat === SOURCE_FORMAT_ARRAY_ROWS\n        ? sourceFormat + '_' + source.seriesLayoutBy\n        : sourceFormat\n    ];\n\n    if (__DEV__) {\n        assert$1(methods, 'Invalide sourceFormat: ' + sourceFormat);\n    }\n\n    extend(this, methods);\n}\n\nvar providerProto = DefaultDataProvider.prototype;\n// If data is pure without style configuration\nproviderProto.pure = false;\n// If data is persistent and will not be released after use.\nproviderProto.persistent = true;\n\n// ???! FIXME legacy data provider do not has method getSource\nproviderProto.getSource = function () {\n    return this._source;\n};\n\nvar providerMethods = {\n\n    'arrayRows_column': {\n        pure: true,\n        count: function () {\n            return Math.max(0, this._data.length - this._source.startIndex);\n        },\n        getItem: function (idx) {\n            return this._data[idx + this._source.startIndex];\n        },\n        appendData: appendDataSimply\n    },\n\n    'arrayRows_row': {\n        pure: true,\n        count: function () {\n            var row = this._data[0];\n            return row ? Math.max(0, row.length - this._source.startIndex) : 0;\n        },\n        getItem: function (idx) {\n            idx += this._source.startIndex;\n            var item = [];\n            var data = this._data;\n            for (var i = 0; i < data.length; i++) {\n                var row = data[i];\n                item.push(row ? row[idx] : null);\n            }\n            return item;\n        },\n        appendData: function () {\n            throw new Error('Do not support appendData when set seriesLayoutBy: \"row\".');\n        }\n    },\n\n    'objectRows': {\n        pure: true,\n        count: countSimply,\n        getItem: getItemSimply,\n        appendData: appendDataSimply\n    },\n\n    'keyedColumns': {\n        pure: true,\n        count: function () {\n            var dimName = this._source.dimensionsDefine[0].name;\n            var col = this._data[dimName];\n            return col ? col.length : 0;\n        },\n        getItem: function (idx) {\n            var item = [];\n            var dims = this._source.dimensionsDefine;\n            for (var i = 0; i < dims.length; i++) {\n                var col = this._data[dims[i].name];\n                item.push(col ? col[idx] : null);\n            }\n            return item;\n        },\n        appendData: function (newData) {\n            var data = this._data;\n            each$1(newData, function (newCol, key) {\n                var oldCol = data[key] || (data[key] = []);\n                for (var i = 0; i < (newCol || []).length; i++) {\n                    oldCol.push(newCol[i]);\n                }\n            });\n        }\n    },\n\n    'original': {\n        count: countSimply,\n        getItem: getItemSimply,\n        appendData: appendDataSimply\n    },\n\n    'typedArray': {\n        persistent: false,\n        pure: true,\n        count: function () {\n            return this._data ? (this._data.length / this._dimSize) : 0;\n        },\n        getItem: function (idx, out) {\n            idx = idx - this._offset;\n            out = out || [];\n            var offset = this._dimSize * idx;\n            for (var i = 0; i < this._dimSize; i++) {\n                out[i] = this._data[offset + i];\n            }\n            return out;\n        },\n        appendData: function (newData) {\n            if (__DEV__) {\n                assert$1(\n                    isTypedArray(newData),\n                    'Added data must be TypedArray if data in initialization is TypedArray'\n                );\n            }\n\n            this._data = newData;\n        },\n\n        // Clean self if data is already used.\n        clean: function () {\n            // PENDING\n            this._offset += this.count();\n            this._data = null;\n        }\n    }\n};\n\nfunction countSimply() {\n    return this._data.length;\n}\nfunction getItemSimply(idx) {\n    return this._data[idx];\n}\nfunction appendDataSimply(newData) {\n    for (var i = 0; i < newData.length; i++) {\n        this._data.push(newData[i]);\n    }\n}\n\n\n\nvar rawValueGetters = {\n\n    arrayRows: getRawValueSimply,\n\n    objectRows: function (dataItem, dataIndex, dimIndex, dimName) {\n        return dimIndex != null ? dataItem[dimName] : dataItem;\n    },\n\n    keyedColumns: getRawValueSimply,\n\n    original: function (dataItem, dataIndex, dimIndex, dimName) {\n        // FIXME\n        // In some case (markpoint in geo (geo-map.html)), dataItem\n        // is {coord: [...]}\n        var value = getDataItemValue(dataItem);\n        return (dimIndex == null || !(value instanceof Array))\n            ? value\n            : value[dimIndex];\n    },\n\n    typedArray: getRawValueSimply\n};\n\nfunction getRawValueSimply(dataItem, dataIndex, dimIndex, dimName) {\n    return dimIndex != null ? dataItem[dimIndex] : dataItem;\n}\n\n\nvar defaultDimValueGetters = {\n\n    arrayRows: getDimValueSimply,\n\n    objectRows: function (dataItem, dimName, dataIndex, dimIndex) {\n        return converDataValue(dataItem[dimName], this._dimensionInfos[dimName]);\n    },\n\n    keyedColumns: getDimValueSimply,\n\n    original: function (dataItem, dimName, dataIndex, dimIndex) {\n        // Performance sensitive, do not use modelUtil.getDataItemValue.\n        // If dataItem is an plain object with no value field, the var `value`\n        // will be assigned with the object, but it will be tread correctly\n        // in the `convertDataValue`.\n        var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value);\n\n        // If any dataItem is like { value: 10 }\n        if (!this._rawData.pure && isDataItemOption(dataItem)) {\n            this.hasItemOption = true;\n        }\n        return converDataValue(\n            (value instanceof Array)\n                ? value[dimIndex]\n                // If value is a single number or something else not array.\n                : value,\n            this._dimensionInfos[dimName]\n        );\n    },\n\n    typedArray: function (dataItem, dimName, dataIndex, dimIndex) {\n        return dataItem[dimIndex];\n    }\n\n};\n\nfunction getDimValueSimply(dataItem, dimName, dataIndex, dimIndex) {\n    return converDataValue(dataItem[dimIndex], this._dimensionInfos[dimName]);\n}\n\n/**\n * This helper method convert value in data.\n * @param {string|number|Date} value\n * @param {Object|string} [dimInfo] If string (like 'x'), dimType defaults 'number'.\n *        If \"dimInfo.ordinalParseAndSave\", ordinal value can be parsed.\n */\nfunction converDataValue(value, dimInfo) {\n    // Performance sensitive.\n    var dimType = dimInfo && dimInfo.type;\n    if (dimType === 'ordinal') {\n        // If given value is a category string\n        var ordinalMeta = dimInfo && dimInfo.ordinalMeta;\n        return ordinalMeta\n            ? ordinalMeta.parseAndCollect(value)\n            : value;\n    }\n\n    if (dimType === 'time'\n        // spead up when using timestamp\n        && typeof value !== 'number'\n        && value != null\n        && value !== '-'\n    ) {\n        value = +parseDate(value);\n    }\n\n    // dimType defaults 'number'.\n    // If dimType is not ordinal and value is null or undefined or NaN or '-',\n    // parse to NaN.\n    return (value == null || value === '')\n        ? NaN\n        // If string (like '-'), using '+' parse to NaN\n        // If object, also parse to NaN\n        : +value;\n}\n\n// ??? FIXME can these logic be more neat: getRawValue, getRawDataItem,\n// Consider persistent.\n// Caution: why use raw value to display on label or tooltip?\n// A reason is to avoid format. For example time value we do not know\n// how to format is expected. More over, if stack is used, calculated\n// value may be 0.91000000001, which have brings trouble to display.\n// TODO: consider how to treat null/undefined/NaN when display?\n/**\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @param {string|number} [dim] dimName or dimIndex\n * @return {Array.<number>|string|number} can be null/undefined.\n */\nfunction retrieveRawValue(data, dataIndex, dim) {\n    if (!data) {\n        return;\n    }\n\n    // Consider data may be not persistent.\n    var dataItem = data.getRawDataItem(dataIndex);\n\n    if (dataItem == null) {\n        return;\n    }\n\n    var sourceFormat = data.getProvider().getSource().sourceFormat;\n    var dimName;\n    var dimIndex;\n\n    var dimInfo = data.getDimensionInfo(dim);\n    if (dimInfo) {\n        dimName = dimInfo.name;\n        dimIndex = dimInfo.index;\n    }\n\n    return rawValueGetters[sourceFormat](dataItem, dataIndex, dimIndex, dimName);\n}\n\n/**\n * Compatible with some cases (in pie, map) like:\n * data: [{name: 'xx', value: 5, selected: true}, ...]\n * where only sourceFormat is 'original' and 'objectRows' supported.\n *\n * ??? TODO\n * Supported detail options in data item when using 'arrayRows'.\n *\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @param {string} attr like 'selected'\n */\nfunction retrieveRawAttr(data, dataIndex, attr) {\n    if (!data) {\n        return;\n    }\n\n    var sourceFormat = data.getProvider().getSource().sourceFormat;\n\n    if (sourceFormat !== SOURCE_FORMAT_ORIGINAL\n        && sourceFormat !== SOURCE_FORMAT_OBJECT_ROWS\n    ) {\n        return;\n    }\n\n    var dataItem = data.getRawDataItem(dataIndex);\n    if (sourceFormat === SOURCE_FORMAT_ORIGINAL && !isObject$1(dataItem)) {\n        dataItem = null;\n    }\n    if (dataItem) {\n        return dataItem[attr];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DIMENSION_LABEL_REG = /\\{@(.+?)\\}/g;\n\n// PENDING A little ugly\nvar dataFormatMixin = {\n    /**\n     * Get params for formatter\n     * @param {number} dataIndex\n     * @param {string} [dataType]\n     * @return {Object}\n     */\n    getDataParams: function (dataIndex, dataType) {\n        var data = this.getData(dataType);\n        var rawValue = this.getRawValue(dataIndex, dataType);\n        var rawDataIndex = data.getRawIndex(dataIndex);\n        var name = data.getName(dataIndex);\n        var itemOpt = data.getRawDataItem(dataIndex);\n        var color = data.getItemVisual(dataIndex, 'color');\n        var tooltipModel = this.ecModel.getComponent('tooltip');\n        var renderModeOption = tooltipModel && tooltipModel.get('renderMode');\n        var renderMode = getTooltipRenderMode(renderModeOption);\n        var mainType = this.mainType;\n        var isSeries = mainType === 'series';\n\n        return {\n            componentType: mainType,\n            componentSubType: this.subType,\n            componentIndex: this.componentIndex,\n            seriesType: isSeries ? this.subType : null,\n            seriesIndex: this.seriesIndex,\n            seriesId: isSeries ? this.id : null,\n            seriesName: isSeries ? this.name : null,\n            name: name,\n            dataIndex: rawDataIndex,\n            data: itemOpt,\n            dataType: dataType,\n            value: rawValue,\n            color: color,\n            marker: getTooltipMarker({\n                color: color,\n                renderMode: renderMode\n            }),\n\n            // Param name list for mapping `a`, `b`, `c`, `d`, `e`\n            $vars: ['seriesName', 'name', 'value']\n        };\n    },\n\n    /**\n     * Format label\n     * @param {number} dataIndex\n     * @param {string} [status='normal'] 'normal' or 'emphasis'\n     * @param {string} [dataType]\n     * @param {number} [dimIndex]\n     * @param {string} [labelProp='label']\n     * @return {string} If not formatter, return null/undefined\n     */\n    getFormattedLabel: function (dataIndex, status, dataType, dimIndex, labelProp) {\n        status = status || 'normal';\n        var data = this.getData(dataType);\n        var itemModel = data.getItemModel(dataIndex);\n\n        var params = this.getDataParams(dataIndex, dataType);\n        if (dimIndex != null && (params.value instanceof Array)) {\n            params.value = params.value[dimIndex];\n        }\n\n        var formatter = itemModel.get(\n            status === 'normal'\n            ? [labelProp || 'label', 'formatter']\n            : [status, labelProp || 'label', 'formatter']\n        );\n\n        if (typeof formatter === 'function') {\n            params.status = status;\n            return formatter(params);\n        }\n        else if (typeof formatter === 'string') {\n            var str = formatTpl(formatter, params);\n\n            // Support 'aaa{@[3]}bbb{@product}ccc'.\n            // Do not support '}' in dim name util have to.\n            return str.replace(DIMENSION_LABEL_REG, function (origin, dim) {\n                var len = dim.length;\n                if (dim.charAt(0) === '[' && dim.charAt(len - 1) === ']') {\n                    dim = +dim.slice(1, len - 1); // Also: '[]' => 0\n                }\n                return retrieveRawValue(data, dataIndex, dim);\n            });\n        }\n    },\n\n    /**\n     * Get raw value in option\n     * @param {number} idx\n     * @param {string} [dataType]\n     * @return {Array|number|string}\n     */\n    getRawValue: function (idx, dataType) {\n        return retrieveRawValue(this.getData(dataType), idx);\n    },\n\n    /**\n     * Should be implemented.\n     * @param {number} dataIndex\n     * @param {boolean} [multipleSeries=false]\n     * @param {number} [dataType]\n     * @return {string} tooltip string\n     */\n    formatTooltip: function () {\n        // Empty function\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} define\n * @return See the return of `createTask`.\n */\nfunction createTask(define) {\n    return new Task(define);\n}\n\n/**\n * @constructor\n * @param {Object} define\n * @param {Function} define.reset Custom reset\n * @param {Function} [define.plan] Returns 'reset' indicate reset immediately.\n * @param {Function} [define.count] count is used to determin data task.\n * @param {Function} [define.onDirty] count is used to determin data task.\n */\nfunction Task(define) {\n    define = define || {};\n\n    this._reset = define.reset;\n    this._plan = define.plan;\n    this._count = define.count;\n    this._onDirty = define.onDirty;\n\n    this._dirty = true;\n\n    // Context must be specified implicitly, to\n    // avoid miss update context when model changed.\n    this.context;\n}\n\nvar taskProto = Task.prototype;\n\n/**\n * @param {Object} performArgs\n * @param {number} [performArgs.step] Specified step.\n * @param {number} [performArgs.skip] Skip customer perform call.\n * @param {number} [performArgs.modBy] Sampling window size.\n * @param {number} [performArgs.modDataCount] Sampling count.\n */\ntaskProto.perform = function (performArgs) {\n    var upTask = this._upstream;\n    var skip = performArgs && performArgs.skip;\n\n    // TODO some refactor.\n    // Pull data. Must pull data each time, because context.data\n    // may be updated by Series.setData.\n    if (this._dirty && upTask) {\n        var context = this.context;\n        context.data = context.outputData = upTask.context.outputData;\n    }\n\n    if (this.__pipeline) {\n        this.__pipeline.currentTask = this;\n    }\n\n    var planResult;\n    if (this._plan && !skip) {\n        planResult = this._plan(this.context);\n    }\n\n    // Support sharding by mod, which changes the render sequence and makes the rendered graphic\n    // elements uniformed distributed when progress, especially when moving or zooming.\n    var lastModBy = normalizeModBy(this._modBy);\n    var lastModDataCount = this._modDataCount || 0;\n    var modBy = normalizeModBy(performArgs && performArgs.modBy);\n    var modDataCount = performArgs && performArgs.modDataCount || 0;\n    if (lastModBy !== modBy || lastModDataCount !== modDataCount) {\n        planResult = 'reset';\n    }\n\n    function normalizeModBy(val) {\n        !(val >= 1) && (val = 1); // jshint ignore:line\n        return val;\n    }\n\n    var forceFirstProgress;\n    if (this._dirty || planResult === 'reset') {\n        this._dirty = false;\n        forceFirstProgress = reset(this, skip);\n    }\n\n    this._modBy = modBy;\n    this._modDataCount = modDataCount;\n\n    var step = performArgs && performArgs.step;\n\n    if (upTask) {\n\n        if (__DEV__) {\n            assert$1(upTask._outputDueEnd != null);\n        }\n        this._dueEnd = upTask._outputDueEnd;\n    }\n    // DataTask or overallTask\n    else {\n        if (__DEV__) {\n            assert$1(!this._progress || this._count);\n        }\n        this._dueEnd = this._count ? this._count(this.context) : Infinity;\n    }\n\n    // Note: Stubs, that its host overall task let it has progress, has progress.\n    // If no progress, pass index from upstream to downstream each time plan called.\n    if (this._progress) {\n        var start = this._dueIndex;\n        var end = Math.min(\n            step != null ? this._dueIndex + step : Infinity,\n            this._dueEnd\n        );\n\n        if (!skip && (forceFirstProgress || start < end)) {\n            var progress = this._progress;\n            if (isArray(progress)) {\n                for (var i = 0; i < progress.length; i++) {\n                    doProgress(this, progress[i], start, end, modBy, modDataCount);\n                }\n            }\n            else {\n                doProgress(this, progress, start, end, modBy, modDataCount);\n            }\n        }\n\n        this._dueIndex = end;\n        // If no `outputDueEnd`, assume that output data and\n        // input data is the same, so use `dueIndex` as `outputDueEnd`.\n        var outputDueEnd = this._settedOutputEnd != null\n            ? this._settedOutputEnd : end;\n\n        if (__DEV__) {\n            // ??? Can not rollback.\n            assert$1(outputDueEnd >= this._outputDueEnd);\n        }\n\n        this._outputDueEnd = outputDueEnd;\n    }\n    else {\n        // (1) Some overall task has no progress.\n        // (2) Stubs, that its host overall task do not let it has progress, has no progress.\n        // This should always be performed so it can be passed to downstream.\n        this._dueIndex = this._outputDueEnd = this._settedOutputEnd != null\n            ? this._settedOutputEnd : this._dueEnd;\n    }\n\n    return this.unfinished();\n};\n\nvar iterator = (function () {\n\n    var end;\n    var current;\n    var modBy;\n    var modDataCount;\n    var winCount;\n\n    var it = {\n        reset: function (s, e, sStep, sCount) {\n            current = s;\n            end = e;\n\n            modBy = sStep;\n            modDataCount = sCount;\n            winCount = Math.ceil(modDataCount / modBy);\n\n            it.next = (modBy > 1 && modDataCount > 0) ? modNext : sequentialNext;\n        }\n    };\n\n    return it;\n\n    function sequentialNext() {\n        return current < end ? current++ : null;\n    }\n\n    function modNext() {\n        var dataIndex = (current % winCount) * modBy + Math.ceil(current / winCount);\n        var result = current >= end\n            ? null\n            : dataIndex < modDataCount\n            ? dataIndex\n            // If modDataCount is smaller than data.count() (consider `appendData` case),\n            // Use normal linear rendering mode.\n            : current;\n        current++;\n        return result;\n    }\n})();\n\ntaskProto.dirty = function () {\n    this._dirty = true;\n    this._onDirty && this._onDirty(this.context);\n};\n\nfunction doProgress(taskIns, progress, start, end, modBy, modDataCount) {\n    iterator.reset(start, end, modBy, modDataCount);\n    taskIns._callingProgress = progress;\n    taskIns._callingProgress({\n        start: start, end: end, count: end - start, next: iterator.next\n    }, taskIns.context);\n}\n\nfunction reset(taskIns, skip) {\n    taskIns._dueIndex = taskIns._outputDueEnd = taskIns._dueEnd = 0;\n    taskIns._settedOutputEnd = null;\n\n    var progress;\n    var forceFirstProgress;\n\n    if (!skip && taskIns._reset) {\n        progress = taskIns._reset(taskIns.context);\n        if (progress && progress.progress) {\n            forceFirstProgress = progress.forceFirstProgress;\n            progress = progress.progress;\n        }\n        // To simplify no progress checking, array must has item.\n        if (isArray(progress) && !progress.length) {\n            progress = null;\n        }\n    }\n\n    taskIns._progress = progress;\n    taskIns._modBy = taskIns._modDataCount = null;\n\n    var downstream = taskIns._downstream;\n    downstream && downstream.dirty();\n\n    return forceFirstProgress;\n}\n\n/**\n * @return {boolean}\n */\ntaskProto.unfinished = function () {\n    return this._progress && this._dueIndex < this._dueEnd;\n};\n\n/**\n * @param {Object} downTask The downstream task.\n * @return {Object} The downstream task.\n */\ntaskProto.pipe = function (downTask) {\n    if (__DEV__) {\n        assert$1(downTask && !downTask._disposed && downTask !== this);\n    }\n\n    // If already downstream, do not dirty downTask.\n    if (this._downstream !== downTask || this._dirty) {\n        this._downstream = downTask;\n        downTask._upstream = this;\n        downTask.dirty();\n    }\n};\n\ntaskProto.dispose = function () {\n    if (this._disposed) {\n        return;\n    }\n\n    this._upstream && (this._upstream._downstream = null);\n    this._downstream && (this._downstream._upstream = null);\n\n    this._dirty = false;\n    this._disposed = true;\n};\n\ntaskProto.getUpstream = function () {\n    return this._upstream;\n};\n\ntaskProto.getDownstream = function () {\n    return this._downstream;\n};\n\ntaskProto.setOutputEnd = function (end) {\n    // This only happend in dataTask, dataZoom, map, currently.\n    // where dataZoom do not set end each time, but only set\n    // when reset. So we should record the setted end, in case\n    // that the stub of dataZoom perform again and earse the\n    // setted end by upstream.\n    this._outputDueEnd = this._settedOutputEnd = end;\n};\n\n\n///////////////////////////////////////////////////////////\n// For stream debug (Should be commented out after used!)\n// Usage: printTask(this, 'begin');\n// Usage: printTask(this, null, {someExtraProp});\n// function printTask(task, prefix, extra) {\n//     window.ecTaskUID == null && (window.ecTaskUID = 0);\n//     task.uidDebug == null && (task.uidDebug = `task_${window.ecTaskUID++}`);\n//     task.agent && task.agent.uidDebug == null && (task.agent.uidDebug = `task_${window.ecTaskUID++}`);\n//     var props = [];\n//     if (task.__pipeline) {\n//         var val = `${task.__idxInPipeline}/${task.__pipeline.tail.__idxInPipeline} ${task.agent ? '(stub)' : ''}`;\n//         props.push({text: 'idx', value: val});\n//     } else {\n//         var stubCount = 0;\n//         task.agentStubMap.each(() => stubCount++);\n//         props.push({text: 'idx', value: `overall (stubs: ${stubCount})`});\n//     }\n//     props.push({text: 'uid', value: task.uidDebug});\n//     if (task.__pipeline) {\n//         props.push({text: 'pid', value: task.__pipeline.id});\n//         task.agent && props.push(\n//             {text: 'stubFor', value: task.agent.uidDebug}\n//         );\n//     }\n//     props.push(\n//         {text: 'dirty', value: task._dirty},\n//         {text: 'dueIndex', value: task._dueIndex},\n//         {text: 'dueEnd', value: task._dueEnd},\n//         {text: 'outputDueEnd', value: task._outputDueEnd}\n//     );\n//     if (extra) {\n//         Object.keys(extra).forEach(key => {\n//             props.push({text: key, value: extra[key]});\n//         });\n//     }\n//     var args = ['color: blue'];\n//     var msg = `%c[${prefix || 'T'}] %c` + props.map(item => (\n//         args.push('color: black', 'color: red'),\n//         `${item.text}: %c${item.value}`\n//     )).join('%c, ');\n//     console.log.apply(console, [msg].concat(args));\n//     // console.log(this);\n// }\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$4 = makeInner();\n\nvar SeriesModel = ComponentModel.extend({\n\n    type: 'series.__base__',\n\n    /**\n     * @readOnly\n     */\n    seriesIndex: 0,\n\n    // coodinateSystem will be injected in the echarts/CoordinateSystem\n    coordinateSystem: null,\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    defaultOption: null,\n\n    /**\n     * Data provided for legend\n     * @type {Function}\n     */\n    // PENDING\n    legendDataProvider: null,\n\n    /**\n     * Access path of color for visual\n     */\n    visualColorAccessPath: 'itemStyle.color',\n\n    /**\n     * Support merge layout params.\n     * Only support 'box' now (left/right/top/bottom/width/height).\n     * @type {string|Object} Object can be {ignoreSize: true}\n     * @readOnly\n     */\n    layoutMode: null,\n\n    init: function (option, parentModel, ecModel, extraOpt) {\n\n        /**\n         * @type {number}\n         * @readOnly\n         */\n        this.seriesIndex = this.componentIndex;\n\n        this.dataTask = createTask({\n            count: dataTaskCount,\n            reset: dataTaskReset\n        });\n        this.dataTask.context = {model: this};\n\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        prepareSource(this);\n\n\n        var data = this.getInitialData(option, ecModel);\n        wrapData(data, this);\n        this.dataTask.context.data = data;\n\n        if (__DEV__) {\n            assert$1(data, 'getInitialData returned invalid data.');\n        }\n\n        /**\n         * @type {module:echarts/data/List|module:echarts/data/Tree|module:echarts/data/Graph}\n         * @private\n         */\n        inner$4(this).dataBeforeProcessed = data;\n\n        // If we reverse the order (make data firstly, and then make\n        // dataBeforeProcessed by cloneShallow), cloneShallow will\n        // cause data.graph.data !== data when using\n        // module:echarts/data/Graph or module:echarts/data/Tree.\n        // See module:echarts/data/helper/linkList\n\n        // Theoretically, it is unreasonable to call `seriesModel.getData()` in the model\n        // init or merge stage, because the data can be restored. So we do not `restoreData`\n        // and `setData` here, which forbids calling `seriesModel.getData()` in this stage.\n        // Call `seriesModel.getRawData()` instead.\n        // this.restoreData();\n\n        autoSeriesName(this);\n    },\n\n    /**\n     * Util for merge default and theme to option\n     * @param  {Object} option\n     * @param  {module:echarts/model/Global} ecModel\n     */\n    mergeDefaultAndTheme: function (option, ecModel) {\n        var layoutMode = this.layoutMode;\n        var inputPositionParams = layoutMode\n            ? getLayoutParams(option) : {};\n\n        // Backward compat: using subType on theme.\n        // But if name duplicate between series subType\n        // (for example: parallel) add component mainType,\n        // add suffix 'Series'.\n        var themeSubType = this.subType;\n        if (ComponentModel.hasClass(themeSubType)) {\n            themeSubType += 'Series';\n        }\n        merge(\n            option,\n            ecModel.getTheme().get(this.subType)\n        );\n        merge(option, this.getDefaultOption());\n\n        // Default label emphasis `show`\n        defaultEmphasis(option, 'label', ['show']);\n\n        this.fillDataTextStyle(option.data);\n\n        if (layoutMode) {\n            mergeLayoutParam(option, inputPositionParams, layoutMode);\n        }\n    },\n\n    mergeOption: function (newSeriesOption, ecModel) {\n        // this.settingTask.dirty();\n\n        newSeriesOption = merge(this.option, newSeriesOption, true);\n        this.fillDataTextStyle(newSeriesOption.data);\n\n        var layoutMode = this.layoutMode;\n        if (layoutMode) {\n            mergeLayoutParam(this.option, newSeriesOption, layoutMode);\n        }\n\n        prepareSource(this);\n\n        var data = this.getInitialData(newSeriesOption, ecModel);\n        wrapData(data, this);\n        this.dataTask.dirty();\n        this.dataTask.context.data = data;\n\n        inner$4(this).dataBeforeProcessed = data;\n\n        autoSeriesName(this);\n    },\n\n    fillDataTextStyle: function (data) {\n        // Default data label emphasis `show`\n        // FIXME Tree structure data ?\n        // FIXME Performance ?\n        if (data && !isTypedArray(data)) {\n            var props = ['show'];\n            for (var i = 0; i < data.length; i++) {\n                if (data[i] && data[i].label) {\n                    defaultEmphasis(data[i], 'label', props);\n                }\n            }\n        }\n    },\n\n    /**\n     * Init a data structure from data related option in series\n     * Must be overwritten\n     */\n    getInitialData: function () {},\n\n    /**\n     * Append data to list\n     * @param {Object} params\n     * @param {Array|TypedArray} params.data\n     */\n    appendData: function (params) {\n        // FIXME ???\n        // (1) If data from dataset, forbidden append.\n        // (2) support append data of dataset.\n        var data = this.getRawData();\n        data.appendData(params.data);\n    },\n\n    /**\n     * Consider some method like `filter`, `map` need make new data,\n     * We should make sure that `seriesModel.getData()` get correct\n     * data in the stream procedure. So we fetch data from upstream\n     * each time `task.perform` called.\n     * @param {string} [dataType]\n     * @return {module:echarts/data/List}\n     */\n    getData: function (dataType) {\n        var task = getCurrentTask(this);\n        if (task) {\n            var data = task.context.data;\n            return dataType == null ? data : data.getLinkedData(dataType);\n        }\n        else {\n            // When series is not alive (that may happen when click toolbox\n            // restore or setOption with not merge mode), series data may\n            // be still need to judge animation or something when graphic\n            // elements want to know whether fade out.\n            return inner$4(this).data;\n        }\n    },\n\n    /**\n     * @param {module:echarts/data/List} data\n     */\n    setData: function (data) {\n        var task = getCurrentTask(this);\n        if (task) {\n            var context = task.context;\n            // Consider case: filter, data sample.\n            if (context.data !== data && task.modifyOutputEnd) {\n                task.setOutputEnd(data.count());\n            }\n            context.outputData = data;\n            // Caution: setData should update context.data,\n            // Because getData may be called multiply in a\n            // single stage and expect to get the data just\n            // set. (For example, AxisProxy, x y both call\n            // getData and setDate sequentially).\n            // So the context.data should be fetched from\n            // upstream each time when a stage starts to be\n            // performed.\n            if (task !== this.dataTask) {\n                context.data = data;\n            }\n        }\n        inner$4(this).data = data;\n    },\n\n    /**\n     * @see {module:echarts/data/helper/sourceHelper#getSource}\n     * @return {module:echarts/data/Source} source\n     */\n    getSource: function () {\n        return getSource(this);\n    },\n\n    /**\n     * Get data before processed\n     * @return {module:echarts/data/List}\n     */\n    getRawData: function () {\n        return inner$4(this).dataBeforeProcessed;\n    },\n\n    /**\n     * Get base axis if has coordinate system and has axis.\n     * By default use coordSys.getBaseAxis();\n     * Can be overrided for some chart.\n     * @return {type} description\n     */\n    getBaseAxis: function () {\n        var coordSys = this.coordinateSystem;\n        return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis();\n    },\n\n    // FIXME\n    /**\n     * Default tooltip formatter\n     *\n     * @param {number} dataIndex\n     * @param {boolean} [multipleSeries=false]\n     * @param {number} [dataType]\n     * @param {string} [renderMode='html'] valid values: 'html' and 'richText'.\n     *                                     'html' is used for rendering tooltip in extra DOM form, and the result\n     *                                     string is used as DOM HTML content.\n     *                                     'richText' is used for rendering tooltip in rich text form, for those where\n     *                                     DOM operation is not supported.\n     * @return {Object} formatted tooltip with `html` and `markers`\n     */\n    formatTooltip: function (dataIndex, multipleSeries, dataType, renderMode) {\n\n        var series = this;\n        renderMode = renderMode || 'html';\n        var newLine = renderMode === 'html' ? '<br/>' : '\\n';\n        var isRichText = renderMode === 'richText';\n        var markers = {};\n        var markerId = 0;\n\n        function formatArrayValue(value) {\n            // ??? TODO refactor these logic.\n            // check: category-no-encode-has-axis-data in dataset.html\n            var vertially = reduce(value, function (vertially, val, idx) {\n                var dimItem = data.getDimensionInfo(idx);\n                return vertially |= dimItem && dimItem.tooltip !== false && dimItem.displayName != null;\n            }, 0);\n\n            var result = [];\n\n            tooltipDims.length\n                ? each$1(tooltipDims, function (dim) {\n                    setEachItem(retrieveRawValue(data, dataIndex, dim), dim);\n                })\n                // By default, all dims is used on tooltip.\n                : each$1(value, setEachItem);\n\n            function setEachItem(val, dim) {\n                var dimInfo = data.getDimensionInfo(dim);\n                // If `dimInfo.tooltip` is not set, show tooltip.\n                if (!dimInfo || dimInfo.otherDims.tooltip === false) {\n                    return;\n                }\n                var dimType = dimInfo.type;\n                var markName = 'sub' + series.seriesIndex + 'at' + markerId;\n                var dimHead = getTooltipMarker({\n                    color: color,\n                    type: 'subItem',\n                    renderMode: renderMode,\n                    markerId: markName\n                });\n\n                var dimHeadStr = typeof dimHead === 'string' ? dimHead : dimHead.content;\n                var valStr = (vertially\n                        ? dimHeadStr + encodeHTML(dimInfo.displayName || '-') + ': '\n                        : ''\n                    )\n                    // FIXME should not format time for raw data?\n                    + encodeHTML(dimType === 'ordinal'\n                        ? val + ''\n                        : dimType === 'time'\n                        ? (multipleSeries ? '' : formatTime('yyyy/MM/dd hh:mm:ss', val))\n                        : addCommas(val)\n                    );\n                valStr && result.push(valStr);\n\n                if (isRichText) {\n                    markers[markName] = color;\n                    ++markerId;\n                }\n            }\n\n            var newLine = vertially ? (isRichText ? '\\n' : '<br/>') : '';\n            var content = newLine + result.join(newLine || ', ');\n            return {\n                renderMode: renderMode,\n                content: content,\n                style: markers\n            };\n        }\n\n        function formatSingleValue(val) {\n            // return encodeHTML(addCommas(val));\n            return {\n                renderMode: renderMode,\n                content: encodeHTML(addCommas(val)),\n                style: markers\n            };\n        }\n\n        var data = this.getData();\n        var tooltipDims = data.mapDimension('defaultedTooltip', true);\n        var tooltipDimLen = tooltipDims.length;\n        var value = this.getRawValue(dataIndex);\n        var isValueArr = isArray(value);\n\n        var color = data.getItemVisual(dataIndex, 'color');\n        if (isObject$1(color) && color.colorStops) {\n            color = (color.colorStops[0] || {}).color;\n        }\n        color = color || 'transparent';\n\n        // Complicated rule for pretty tooltip.\n        var formattedValue = (tooltipDimLen > 1 || (isValueArr && !tooltipDimLen))\n            ? formatArrayValue(value)\n            : tooltipDimLen\n            ? formatSingleValue(retrieveRawValue(data, dataIndex, tooltipDims[0]))\n            : formatSingleValue(isValueArr ? value[0] : value);\n        var content = formattedValue.content;\n\n        var markName = series.seriesIndex + 'at' + markerId;\n        var colorEl = getTooltipMarker({\n            color: color,\n            type: 'item',\n            renderMode: renderMode,\n            markerId: markName\n        });\n        markers[markName] = color;\n        ++markerId;\n\n        var name = data.getName(dataIndex);\n\n        var seriesName = this.name;\n        if (!isNameSpecified(this)) {\n            seriesName = '';\n        }\n        seriesName = seriesName\n            ? encodeHTML(seriesName) + (!multipleSeries ? newLine : ': ')\n            : '';\n\n        var colorStr = typeof colorEl === 'string' ? colorEl : colorEl.content;\n        var html = !multipleSeries\n            ? seriesName + colorStr\n                + (name\n                    ? encodeHTML(name) + ': ' + content\n                    : content\n                )\n            : colorStr + seriesName + content;\n\n        return {\n            html: html,\n            markers: markers\n        };\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isAnimationEnabled: function () {\n        if (env$1.node) {\n            return false;\n        }\n\n        var animationEnabled = this.getShallow('animation');\n        if (animationEnabled) {\n            if (this.getData().count() > this.getShallow('animationThreshold')) {\n                animationEnabled = false;\n            }\n        }\n        return animationEnabled;\n    },\n\n    restoreData: function () {\n        this.dataTask.dirty();\n    },\n\n    getColorFromPalette: function (name, scope, requestColorNum) {\n        var ecModel = this.ecModel;\n        // PENDING\n        var color = colorPaletteMixin.getColorFromPalette.call(this, name, scope, requestColorNum);\n        if (!color) {\n            color = ecModel.getColorFromPalette(name, scope, requestColorNum);\n        }\n        return color;\n    },\n\n    /**\n     * Use `data.mapDimension(coordDim, true)` instead.\n     * @deprecated\n     */\n    coordDimToDataDim: function (coordDim) {\n        return this.getRawData().mapDimension(coordDim, true);\n    },\n\n    /**\n     * Get progressive rendering count each step\n     * @return {number}\n     */\n    getProgressive: function () {\n        return this.get('progressive');\n    },\n\n    /**\n     * Get progressive rendering count each step\n     * @return {number}\n     */\n    getProgressiveThreshold: function () {\n        return this.get('progressiveThreshold');\n    },\n\n    /**\n     * Get data indices for show tooltip content. See tooltip.\n     * @abstract\n     * @param {Array.<string>|string} dim\n     * @param {Array.<number>} value\n     * @param {module:echarts/coord/single/SingleAxis} baseAxis\n     * @return {Object} {dataIndices, nestestValue}.\n     */\n    getAxisTooltipData: null,\n\n    /**\n     * See tooltip.\n     * @abstract\n     * @param {number} dataIndex\n     * @return {Array.<number>} Point of tooltip. null/undefined can be returned.\n     */\n    getTooltipPosition: null,\n\n    /**\n     * @see {module:echarts/stream/Scheduler}\n     */\n    pipeTask: null,\n\n    /**\n     * Convinient for override in extended class.\n     * @protected\n     * @type {Function}\n     */\n    preventIncremental: null,\n\n    /**\n     * @public\n     * @readOnly\n     * @type {Object}\n     */\n    pipelineContext: null\n\n});\n\n\nmixin(SeriesModel, dataFormatMixin);\nmixin(SeriesModel, colorPaletteMixin);\n\n/**\n * MUST be called after `prepareSource` called\n * Here we need to make auto series, especially for auto legend. But we\n * do not modify series.name in option to avoid side effects.\n */\nfunction autoSeriesName(seriesModel) {\n    // User specified name has higher priority, otherwise it may cause\n    // series can not be queried unexpectedly.\n    var name = seriesModel.name;\n    if (!isNameSpecified(seriesModel)) {\n        seriesModel.name = getSeriesAutoName(seriesModel) || name;\n    }\n}\n\nfunction getSeriesAutoName(seriesModel) {\n    var data = seriesModel.getRawData();\n    var dataDims = data.mapDimension('seriesName', true);\n    var nameArr = [];\n    each$1(dataDims, function (dataDim) {\n        var dimInfo = data.getDimensionInfo(dataDim);\n        dimInfo.displayName && nameArr.push(dimInfo.displayName);\n    });\n    return nameArr.join(' ');\n}\n\nfunction dataTaskCount(context) {\n    return context.model.getRawData().count();\n}\n\nfunction dataTaskReset(context) {\n    var seriesModel = context.model;\n    seriesModel.setData(seriesModel.getRawData().cloneShallow());\n    return dataTaskProgress;\n}\n\nfunction dataTaskProgress(param, context) {\n    // Avoid repead cloneShallow when data just created in reset.\n    if (param.end > context.outputData.count()) {\n        context.model.getRawData().cloneShallow(context.outputData);\n    }\n}\n\n// TODO refactor\nfunction wrapData(data, seriesModel) {\n    each$1(data.CHANGABLE_METHODS, function (methodName) {\n        data.wrapMethod(methodName, curry(onDataSelfChange, seriesModel));\n    });\n}\n\nfunction onDataSelfChange(seriesModel) {\n    var task = getCurrentTask(seriesModel);\n    if (task) {\n        // Consider case: filter, selectRange\n        task.setOutputEnd(this.count());\n    }\n}\n\nfunction getCurrentTask(seriesModel) {\n    var scheduler = (seriesModel.ecModel || {}).scheduler;\n    var pipeline = scheduler && scheduler.getPipeline(seriesModel.uid);\n\n    if (pipeline) {\n        // When pipline finished, the currrentTask keep the last\n        // task (renderTask).\n        var task = pipeline.currentTask;\n        if (task) {\n            var agentStubMap = task.agentStubMap;\n            if (agentStubMap) {\n                task = agentStubMap.get(seriesModel.uid);\n            }\n        }\n        return task;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar Component$1 = function () {\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.uid = getUID('viewComponent');\n};\n\nComponent$1.prototype = {\n\n    constructor: Component$1,\n\n    init: function (ecModel, api) {},\n\n    render: function (componentModel, ecModel, api, payload) {},\n\n    dispose: function () {},\n\n    /**\n     * @param {string} eventType\n     * @param {Object} query\n     * @param {module:zrender/Element} targetEl\n     * @param {Object} packedEvent\n     * @return {boolen} Pass only when return `true`.\n     */\n    filterForExposedEvent: null\n\n};\n\nvar componentProto = Component$1.prototype;\ncomponentProto.updateView\n    = componentProto.updateLayout\n    = componentProto.updateVisual\n    = function (seriesModel, ecModel, api, payload) {\n        // Do nothing;\n    };\n// Enable Component.extend.\nenableClassExtend(Component$1);\n\n// Enable capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(Component$1, {registerWhenExtend: true});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @return {string} If large mode changed, return string 'reset';\n */\nvar createRenderPlanner = function () {\n    var inner = makeInner();\n\n    return function (seriesModel) {\n        var fields = inner(seriesModel);\n        var pipelineContext = seriesModel.pipelineContext;\n\n        var originalLarge = fields.large;\n        var originalProgressive = fields.progressiveRender;\n\n        var large = fields.large = pipelineContext.large;\n        var progressive = fields.progressiveRender = pipelineContext.progressiveRender;\n\n        return !!((originalLarge ^ large) || (originalProgressive ^ progressive)) && 'reset';\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$5 = makeInner();\nvar renderPlanner = createRenderPlanner();\n\nfunction Chart() {\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.uid = getUID('viewChart');\n\n    this.renderTask = createTask({\n        plan: renderTaskPlan,\n        reset: renderTaskReset\n    });\n    this.renderTask.context = {view: this};\n}\n\nChart.prototype = {\n\n    type: 'chart',\n\n    /**\n     * Init the chart.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    init: function (ecModel, api) {},\n\n    /**\n     * Render the chart.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    render: function (seriesModel, ecModel, api, payload) {},\n\n    /**\n     * Highlight series or specified data item.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    highlight: function (seriesModel, ecModel, api, payload) {\n        toggleHighlight(seriesModel.getData(), payload, 'emphasis');\n    },\n\n    /**\n     * Downplay series or specified data item.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    downplay: function (seriesModel, ecModel, api, payload) {\n        toggleHighlight(seriesModel.getData(), payload, 'normal');\n    },\n\n    /**\n     * Remove self.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    remove: function (ecModel, api) {\n        this.group.removeAll();\n    },\n\n    /**\n     * Dispose self.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    dispose: function () {},\n\n    /**\n     * Rendering preparation in progressive mode.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    incrementalPrepareRender: null,\n\n    /**\n     * Render in progressive mode.\n     * @param  {Object} params See taskParams in `stream/task.js`\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    incrementalRender: null,\n\n    /**\n     * Update transform directly.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     * @return {Object} {update: true}\n     */\n    updateTransform: null,\n\n    /**\n     * The view contains the given point.\n     * @interface\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    // containPoint: function () {}\n\n    /**\n     * @param {string} eventType\n     * @param {Object} query\n     * @param {module:zrender/Element} targetEl\n     * @param {Object} packedEvent\n     * @return {boolen} Pass only when return `true`.\n     */\n    filterForExposedEvent: null\n\n};\n\nvar chartProto = Chart.prototype;\nchartProto.updateView\n    = chartProto.updateLayout\n    = chartProto.updateVisual\n    = function (seriesModel, ecModel, api, payload) {\n        this.render(seriesModel, ecModel, api, payload);\n    };\n\n/**\n * Set state of single element\n * @param  {module:zrender/Element} el\n * @param  {string} state\n */\nfunction elSetState(el, state) {\n    if (el) {\n        el.trigger(state);\n        if (el.type === 'group') {\n            for (var i = 0; i < el.childCount(); i++) {\n                elSetState(el.childAt(i), state);\n            }\n        }\n    }\n}\n/**\n * @param  {module:echarts/data/List} data\n * @param  {Object} payload\n * @param  {string} state 'normal'|'emphasis'\n */\nfunction toggleHighlight(data, payload, state) {\n    var dataIndex = queryDataIndex(data, payload);\n\n    if (dataIndex != null) {\n        each$1(normalizeToArray(dataIndex), function (dataIdx) {\n            elSetState(data.getItemGraphicEl(dataIdx), state);\n        });\n    }\n    else {\n        data.eachItemGraphicEl(function (el) {\n            elSetState(el, state);\n        });\n    }\n}\n\n// Enable Chart.extend.\nenableClassExtend(Chart, ['dispose']);\n\n// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(Chart, {registerWhenExtend: true});\n\nChart.markUpdateMethod = function (payload, methodName) {\n    inner$5(payload).updateMethod = methodName;\n};\n\nfunction renderTaskPlan(context) {\n    return renderPlanner(context.model);\n}\n\nfunction renderTaskReset(context) {\n    var seriesModel = context.model;\n    var ecModel = context.ecModel;\n    var api = context.api;\n    var payload = context.payload;\n    // ???! remove updateView updateVisual\n    var progressiveRender = seriesModel.pipelineContext.progressiveRender;\n    var view = context.view;\n\n    var updateMethod = payload && inner$5(payload).updateMethod;\n    var methodName = progressiveRender\n        ? 'incrementalPrepareRender'\n        : (updateMethod && view[updateMethod])\n        ? updateMethod\n        // `appendData` is also supported when data amount\n        // is less than progressive threshold.\n        : 'render';\n\n    if (methodName !== 'render') {\n        view[methodName](seriesModel, ecModel, api, payload);\n    }\n\n    return progressMethodMap[methodName];\n}\n\nvar progressMethodMap = {\n    incrementalPrepareRender: {\n        progress: function (params, context) {\n            context.view.incrementalRender(\n                params, context.model, context.ecModel, context.api, context.payload\n            );\n        }\n    },\n    render: {\n        // Put view.render in `progress` to support appendData. But in this case\n        // view.render should not be called in reset, otherwise it will be called\n        // twise. Use `forceFirstProgress` to make sure that view.render is called\n        // in any cases.\n        forceFirstProgress: true,\n        progress: function (params, context) {\n            context.view.render(\n                context.model, context.ecModel, context.api, context.payload\n            );\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar ORIGIN_METHOD = '\\0__throttleOriginMethod';\nvar RATE = '\\0__throttleRate';\nvar THROTTLE_TYPE = '\\0__throttleType';\n\n/**\n * @public\n * @param {(Function)} fn\n * @param {number} [delay=0] Unit: ms.\n * @param {boolean} [debounce=false]\n *        true: If call interval less than `delay`, only the last call works.\n *        false: If call interval less than `delay, call works on fixed rate.\n * @return {(Function)} throttled fn.\n */\nfunction throttle(fn, delay, debounce) {\n\n    var currCall;\n    var lastCall = 0;\n    var lastExec = 0;\n    var timer = null;\n    var diff;\n    var scope;\n    var args;\n    var debounceNextCall;\n\n    delay = delay || 0;\n\n    function exec() {\n        lastExec = (new Date()).getTime();\n        timer = null;\n        fn.apply(scope, args || []);\n    }\n\n    var cb = function () {\n        currCall = (new Date()).getTime();\n        scope = this;\n        args = arguments;\n        var thisDelay = debounceNextCall || delay;\n        var thisDebounce = debounceNextCall || debounce;\n        debounceNextCall = null;\n        diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay;\n\n        clearTimeout(timer);\n\n        // Here we should make sure that: the `exec` SHOULD NOT be called later\n        // than a new call of `cb`, that is, preserving the command order. Consider\n        // calculating \"scale rate\" when roaming as an example. When a call of `cb`\n        // happens, either the `exec` is called dierectly, or the call is delayed.\n        // But the delayed call should never be later than next call of `cb`. Under\n        // this assurance, we can simply update view state each time `dispatchAction`\n        // triggered by user roaming, but not need to add extra code to avoid the\n        // state being \"rolled-back\".\n        if (thisDebounce) {\n            timer = setTimeout(exec, thisDelay);\n        }\n        else {\n            if (diff >= 0) {\n                exec();\n            }\n            else {\n                timer = setTimeout(exec, -diff);\n            }\n        }\n\n        lastCall = currCall;\n    };\n\n    /**\n     * Clear throttle.\n     * @public\n     */\n    cb.clear = function () {\n        if (timer) {\n            clearTimeout(timer);\n            timer = null;\n        }\n    };\n\n    /**\n     * Enable debounce once.\n     */\n    cb.debounceNextCall = function (debounceDelay) {\n        debounceNextCall = debounceDelay;\n    };\n\n    return cb;\n}\n\n/**\n * Create throttle method or update throttle rate.\n *\n * @example\n * ComponentView.prototype.render = function () {\n *     ...\n *     throttle.createOrUpdate(\n *         this,\n *         '_dispatchAction',\n *         this.model.get('throttle'),\n *         'fixRate'\n *     );\n * };\n * ComponentView.prototype.remove = function () {\n *     throttle.clear(this, '_dispatchAction');\n * };\n * ComponentView.prototype.dispose = function () {\n *     throttle.clear(this, '_dispatchAction');\n * };\n *\n * @public\n * @param {Object} obj\n * @param {string} fnAttr\n * @param {number} [rate]\n * @param {string} [throttleType='fixRate'] 'fixRate' or 'debounce'\n * @return {Function} throttled function.\n */\nfunction createOrUpdate(obj, fnAttr, rate, throttleType) {\n    var fn = obj[fnAttr];\n\n    if (!fn) {\n        return;\n    }\n\n    var originFn = fn[ORIGIN_METHOD] || fn;\n    var lastThrottleType = fn[THROTTLE_TYPE];\n    var lastRate = fn[RATE];\n\n    if (lastRate !== rate || lastThrottleType !== throttleType) {\n        if (rate == null || !throttleType) {\n            return (obj[fnAttr] = originFn);\n        }\n\n        fn = obj[fnAttr] = throttle(\n            originFn, rate, throttleType === 'debounce'\n        );\n        fn[ORIGIN_METHOD] = originFn;\n        fn[THROTTLE_TYPE] = throttleType;\n        fn[RATE] = rate;\n    }\n\n    return fn;\n}\n\n/**\n * Clear throttle. Example see throttle.createOrUpdate.\n *\n * @public\n * @param {Object} obj\n * @param {string} fnAttr\n */\nfunction clear(obj, fnAttr) {\n    var fn = obj[fnAttr];\n    if (fn && fn[ORIGIN_METHOD]) {\n        obj[fnAttr] = fn[ORIGIN_METHOD];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar seriesColor = {\n    createOnAllSeries: true,\n    performRawSeries: true,\n    reset: function (seriesModel, ecModel) {\n        var data = seriesModel.getData();\n        var colorAccessPath = (seriesModel.visualColorAccessPath || 'itemStyle.color').split('.');\n        var color = seriesModel.get(colorAccessPath) // Set in itemStyle\n            || seriesModel.getColorFromPalette(\n                // TODO series count changed.\n                seriesModel.name, null, ecModel.getSeriesCount()\n            );  // Default color\n\n        // FIXME Set color function or use the platte color\n        data.setVisual('color', color);\n\n        // Only visible series has each data be visual encoded\n        if (!ecModel.isSeriesFiltered(seriesModel)) {\n            if (typeof color === 'function' && !(color instanceof Gradient)) {\n                data.each(function (idx) {\n                    data.setItemVisual(\n                        idx, 'color', color(seriesModel.getDataParams(idx))\n                    );\n                });\n            }\n\n            // itemStyle in each data item\n            var dataEach = function (data, idx) {\n                var itemModel = data.getItemModel(idx);\n                var color = itemModel.get(colorAccessPath, true);\n                if (color != null) {\n                    data.setItemVisual(idx, 'color', color);\n                }\n            };\n\n            return { dataEach: data.hasItemOption ? dataEach : null };\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar lang = {\n    toolbox: {\n        brush: {\n            title: {\n                rect: '矩形选择',\n                polygon: '圈选',\n                lineX: '横向选择',\n                lineY: '纵向选择',\n                keep: '保持选择',\n                clear: '清除选择'\n            }\n        },\n        dataView: {\n            title: '数据视图',\n            lang: ['数据视图', '关闭', '刷新']\n        },\n        dataZoom: {\n            title: {\n                zoom: '区域缩放',\n                back: '区域缩放还原'\n            }\n        },\n        magicType: {\n            title: {\n                line: '切换为折线图',\n                bar: '切换为柱状图',\n                stack: '切换为堆叠',\n                tiled: '切换为平铺'\n            }\n        },\n        restore: {\n            title: '还原'\n        },\n        saveAsImage: {\n            title: '保存为图片',\n            lang: ['右键另存为图片']\n        }\n    },\n    series: {\n        typeNames: {\n            pie: '饼图',\n            bar: '柱状图',\n            line: '折线图',\n            scatter: '散点图',\n            effectScatter: '涟漪散点图',\n            radar: '雷达图',\n            tree: '树图',\n            treemap: '矩形树图',\n            boxplot: '箱型图',\n            candlestick: 'K线图',\n            k: 'K线图',\n            heatmap: '热力图',\n            map: '地图',\n            parallel: '平行坐标图',\n            lines: '线图',\n            graph: '关系图',\n            sankey: '桑基图',\n            funnel: '漏斗图',\n            gauge: '仪表盘图',\n            pictorialBar: '象形柱图',\n            themeRiver: '主题河流图',\n            sunburst: '旭日图'\n        }\n    },\n    aria: {\n        general: {\n            withTitle: '这是一个关于“{title}”的图表。',\n            withoutTitle: '这是一个图表，'\n        },\n        series: {\n            single: {\n                prefix: '',\n                withName: '图表类型是{seriesType}，表示{seriesName}。',\n                withoutName: '图表类型是{seriesType}。'\n            },\n            multiple: {\n                prefix: '它由{seriesCount}个图表系列组成。',\n                withName: '第{seriesId}个系列是一个表示{seriesName}的{seriesType}，',\n                withoutName: '第{seriesId}个系列是一个{seriesType}，',\n                separator: {\n                    middle: '；',\n                    end: '。'\n                }\n            }\n        },\n        data: {\n            allData: '其数据是——',\n            partialData: '其中，前{displayCnt}项是——',\n            withName: '{name}的数据是{value}',\n            withoutName: '{value}',\n            separator: {\n                middle: '，',\n                end: ''\n            }\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar aria = function (dom, ecModel) {\n    var ariaModel = ecModel.getModel('aria');\n    if (!ariaModel.get('show')) {\n        return;\n    }\n    else if (ariaModel.get('description')) {\n        dom.setAttribute('aria-label', ariaModel.get('description'));\n        return;\n    }\n\n    var seriesCnt = 0;\n    ecModel.eachSeries(function (seriesModel, idx) {\n        ++seriesCnt;\n    }, this);\n\n    var maxDataCnt = ariaModel.get('data.maxCount') || 10;\n    var maxSeriesCnt = ariaModel.get('series.maxCount') || 10;\n    var displaySeriesCnt = Math.min(seriesCnt, maxSeriesCnt);\n\n    var ariaLabel;\n    if (seriesCnt < 1) {\n        // No series, no aria label\n        return;\n    }\n    else {\n        var title = getTitle();\n        if (title) {\n            ariaLabel = replace(getConfig('general.withTitle'), {\n                title: title\n            });\n        }\n        else {\n            ariaLabel = getConfig('general.withoutTitle');\n        }\n\n        var seriesLabels = [];\n        var prefix = seriesCnt > 1\n            ? 'series.multiple.prefix'\n            : 'series.single.prefix';\n        ariaLabel += replace(getConfig(prefix), { seriesCount: seriesCnt });\n\n        ecModel.eachSeries(function (seriesModel, idx) {\n            if (idx < displaySeriesCnt) {\n                var seriesLabel;\n\n                var seriesName = seriesModel.get('name');\n                var seriesTpl = 'series.'\n                    + (seriesCnt > 1 ? 'multiple' : 'single') + '.';\n                seriesLabel = getConfig(seriesName\n                    ? seriesTpl + 'withName'\n                    : seriesTpl + 'withoutName');\n\n                seriesLabel = replace(seriesLabel, {\n                    seriesId: seriesModel.seriesIndex,\n                    seriesName: seriesModel.get('name'),\n                    seriesType: getSeriesTypeName(seriesModel.subType)\n                });\n\n                var data = seriesModel.getData();\n                window.data = data;\n                if (data.count() > maxDataCnt) {\n                    // Show part of data\n                    seriesLabel += replace(getConfig('data.partialData'), {\n                        displayCnt: maxDataCnt\n                    });\n                }\n                else {\n                    seriesLabel += getConfig('data.allData');\n                }\n\n                var dataLabels = [];\n                for (var i = 0; i < data.count(); i++) {\n                    if (i < maxDataCnt) {\n                        var name = data.getName(i);\n                        var value = retrieveRawValue(data, i);\n                        dataLabels.push(\n                            replace(\n                                name\n                                    ? getConfig('data.withName')\n                                    : getConfig('data.withoutName'),\n                                {\n                                    name: name,\n                                    value: value\n                                }\n                            )\n                        );\n                    }\n                }\n                seriesLabel += dataLabels\n                    .join(getConfig('data.separator.middle'))\n                    + getConfig('data.separator.end');\n\n                seriesLabels.push(seriesLabel);\n            }\n        });\n\n        ariaLabel += seriesLabels\n            .join(getConfig('series.multiple.separator.middle'))\n            + getConfig('series.multiple.separator.end');\n\n        dom.setAttribute('aria-label', ariaLabel);\n    }\n\n    function replace(str, keyValues) {\n        if (typeof str !== 'string') {\n            return str;\n        }\n\n        var result = str;\n        each$1(keyValues, function (value, key) {\n            result = result.replace(\n                new RegExp('\\\\{\\\\s*' + key + '\\\\s*\\\\}', 'g'),\n                value\n            );\n        });\n        return result;\n    }\n\n    function getConfig(path) {\n        var userConfig = ariaModel.get(path);\n        if (userConfig == null) {\n            var pathArr = path.split('.');\n            var result = lang.aria;\n            for (var i = 0; i < pathArr.length; ++i) {\n                result = result[pathArr[i]];\n            }\n            return result;\n        }\n        else {\n            return userConfig;\n        }\n    }\n\n    function getTitle() {\n        var title = ecModel.getModel('title').option;\n        if (title && title.length) {\n            title = title[0];\n        }\n        return title && title.text;\n    }\n\n    function getSeriesTypeName(type) {\n        return lang.series.typeNames[type] || '自定义图';\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PI$1 = Math.PI;\n\n/**\n * @param {module:echarts/ExtensionAPI} api\n * @param {Object} [opts]\n * @param {string} [opts.text]\n * @param {string} [opts.color]\n * @param {string} [opts.textColor]\n * @return {module:zrender/Element}\n */\nvar loadingDefault = function (api, opts) {\n    opts = opts || {};\n    defaults(opts, {\n        text: 'loading',\n        color: '#c23531',\n        textColor: '#000',\n        maskColor: 'rgba(255, 255, 255, 0.8)',\n        zlevel: 0\n    });\n    var mask = new Rect({\n        style: {\n            fill: opts.maskColor\n        },\n        zlevel: opts.zlevel,\n        z: 10000\n    });\n    var arc = new Arc({\n        shape: {\n            startAngle: -PI$1 / 2,\n            endAngle: -PI$1 / 2 + 0.1,\n            r: 10\n        },\n        style: {\n            stroke: opts.color,\n            lineCap: 'round',\n            lineWidth: 5\n        },\n        zlevel: opts.zlevel,\n        z: 10001\n    });\n    var labelRect = new Rect({\n        style: {\n            fill: 'none',\n            text: opts.text,\n            textPosition: 'right',\n            textDistance: 10,\n            textFill: opts.textColor\n        },\n        zlevel: opts.zlevel,\n        z: 10001\n    });\n\n    arc.animateShape(true)\n        .when(1000, {\n            endAngle: PI$1 * 3 / 2\n        })\n        .start('circularInOut');\n    arc.animateShape(true)\n        .when(1000, {\n            startAngle: PI$1 * 3 / 2\n        })\n        .delay(300)\n        .start('circularInOut');\n\n    var group = new Group();\n    group.add(arc);\n    group.add(labelRect);\n    group.add(mask);\n    // Inject resize\n    group.resize = function () {\n        var cx = api.getWidth() / 2;\n        var cy = api.getHeight() / 2;\n        arc.setShape({\n            cx: cx,\n            cy: cy\n        });\n        var r = arc.shape.r;\n        labelRect.setShape({\n            x: cx - r,\n            y: cy - r,\n            width: r * 2,\n            height: r * 2\n        });\n\n        mask.setShape({\n            x: 0,\n            y: 0,\n            width: api.getWidth(),\n            height: api.getHeight()\n        });\n    };\n    group.resize();\n    return group;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/stream/Scheduler\n */\n\n/**\n * @constructor\n */\nfunction Scheduler(ecInstance, api, dataProcessorHandlers, visualHandlers) {\n    this.ecInstance = ecInstance;\n    this.api = api;\n    this.unfinished;\n\n    // Fix current processors in case that in some rear cases that\n    // processors might be registered after echarts instance created.\n    // Register processors incrementally for a echarts instance is\n    // not supported by this stream architecture.\n    var dataProcessorHandlers = this._dataProcessorHandlers = dataProcessorHandlers.slice();\n    var visualHandlers = this._visualHandlers = visualHandlers.slice();\n    this._allHandlers = dataProcessorHandlers.concat(visualHandlers);\n\n    /**\n     * @private\n     * @type {\n     *     [handlerUID: string]: {\n     *         seriesTaskMap?: {\n     *             [seriesUID: string]: Task\n     *         },\n     *         overallTask?: Task\n     *     }\n     * }\n     */\n    this._stageTaskMap = createHashMap();\n}\n\nvar proto = Scheduler.prototype;\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} payload\n */\nproto.restoreData = function (ecModel, payload) {\n    // TODO: Only restroe needed series and components, but not all components.\n    // Currently `restoreData` of all of the series and component will be called.\n    // But some independent components like `title`, `legend`, `graphic`, `toolbox`,\n    // `tooltip`, `axisPointer`, etc, do not need series refresh when `setOption`,\n    // and some components like coordinate system, axes, dataZoom, visualMap only\n    // need their target series refresh.\n    // (1) If we are implementing this feature some day, we should consider these cases:\n    // if a data processor depends on a component (e.g., dataZoomProcessor depends\n    // on the settings of `dataZoom`), it should be re-performed if the component\n    // is modified by `setOption`.\n    // (2) If a processor depends on sevral series, speicified by its `getTargetSeries`,\n    // it should be re-performed when the result array of `getTargetSeries` changed.\n    // We use `dependencies` to cover these issues.\n    // (3) How to update target series when coordinate system related components modified.\n\n    // TODO: simply the dirty mechanism? Check whether only the case here can set tasks dirty,\n    // and this case all of the tasks will be set as dirty.\n\n    ecModel.restoreData(payload);\n\n    // Theoretically an overall task not only depends on each of its target series, but also\n    // depends on all of the series.\n    // The overall task is not in pipeline, and `ecModel.restoreData` only set pipeline tasks\n    // dirty. If `getTargetSeries` of an overall task returns nothing, we should also ensure\n    // that the overall task is set as dirty and to be performed, otherwise it probably cause\n    // state chaos. So we have to set dirty of all of the overall tasks manually, otherwise it\n    // probably cause state chaos (consider `dataZoomProcessor`).\n    this._stageTaskMap.each(function (taskRecord) {\n        var overallTask = taskRecord.overallTask;\n        overallTask && overallTask.dirty();\n    });\n};\n\n// If seriesModel provided, incremental threshold is check by series data.\nproto.getPerformArgs = function (task, isBlock) {\n    // For overall task\n    if (!task.__pipeline) {\n        return;\n    }\n\n    var pipeline = this._pipelineMap.get(task.__pipeline.id);\n    var pCtx = pipeline.context;\n    var incremental = !isBlock\n        && pipeline.progressiveEnabled\n        && (!pCtx || pCtx.progressiveRender)\n        && task.__idxInPipeline > pipeline.blockIndex;\n\n    var step = incremental ? pipeline.step : null;\n    var modDataCount = pCtx && pCtx.modDataCount;\n    var modBy = modDataCount != null ? Math.ceil(modDataCount / step) : null;\n\n    return {step: step, modBy: modBy, modDataCount: modDataCount};\n};\n\nproto.getPipeline = function (pipelineId) {\n    return this._pipelineMap.get(pipelineId);\n};\n\n/**\n * Current, progressive rendering starts from visual and layout.\n * Always detect render mode in the same stage, avoiding that incorrect\n * detection caused by data filtering.\n * Caution:\n * `updateStreamModes` use `seriesModel.getData()`.\n */\nproto.updateStreamModes = function (seriesModel, view) {\n    var pipeline = this._pipelineMap.get(seriesModel.uid);\n    var data = seriesModel.getData();\n    var dataLen = data.count();\n\n    // `progressiveRender` means that can render progressively in each\n    // animation frame. Note that some types of series do not provide\n    // `view.incrementalPrepareRender` but support `chart.appendData`. We\n    // use the term `incremental` but not `progressive` to describe the\n    // case that `chart.appendData`.\n    var progressiveRender = pipeline.progressiveEnabled\n        && view.incrementalPrepareRender\n        && dataLen >= pipeline.threshold;\n\n    var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold');\n\n    // TODO: modDataCount should not updated if `appendData`, otherwise cause whole repaint.\n    // see `test/candlestick-large3.html`\n    var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null;\n\n    seriesModel.pipelineContext = pipeline.context = {\n        progressiveRender: progressiveRender,\n        modDataCount: modDataCount,\n        large: large\n    };\n};\n\nproto.restorePipelines = function (ecModel) {\n    var scheduler = this;\n    var pipelineMap = scheduler._pipelineMap = createHashMap();\n\n    ecModel.eachSeries(function (seriesModel) {\n        var progressive = seriesModel.getProgressive();\n        var pipelineId = seriesModel.uid;\n\n        pipelineMap.set(pipelineId, {\n            id: pipelineId,\n            head: null,\n            tail: null,\n            threshold: seriesModel.getProgressiveThreshold(),\n            progressiveEnabled: progressive\n                && !(seriesModel.preventIncremental && seriesModel.preventIncremental()),\n            blockIndex: -1,\n            step: Math.round(progressive || 700),\n            count: 0\n        });\n\n        pipe(scheduler, seriesModel, seriesModel.dataTask);\n    });\n};\n\nproto.prepareStageTasks = function () {\n    var stageTaskMap = this._stageTaskMap;\n    var ecModel = this.ecInstance.getModel();\n    var api = this.api;\n\n    each$1(this._allHandlers, function (handler) {\n        var record = stageTaskMap.get(handler.uid) || stageTaskMap.set(handler.uid, []);\n\n        handler.reset && createSeriesStageTask(this, handler, record, ecModel, api);\n        handler.overallReset && createOverallStageTask(this, handler, record, ecModel, api);\n    }, this);\n};\n\nproto.prepareView = function (view, model, ecModel, api) {\n    var renderTask = view.renderTask;\n    var context = renderTask.context;\n\n    context.model = model;\n    context.ecModel = ecModel;\n    context.api = api;\n\n    renderTask.__block = !view.incrementalPrepareRender;\n\n    pipe(this, model, renderTask);\n};\n\n\nproto.performDataProcessorTasks = function (ecModel, payload) {\n    // If we do not use `block` here, it should be considered when to update modes.\n    performStageTasks(this, this._dataProcessorHandlers, ecModel, payload, {block: true});\n};\n\n// opt\n// opt.visualType: 'visual' or 'layout'\n// opt.setDirty\nproto.performVisualTasks = function (ecModel, payload, opt) {\n    performStageTasks(this, this._visualHandlers, ecModel, payload, opt);\n};\n\nfunction performStageTasks(scheduler, stageHandlers, ecModel, payload, opt) {\n    opt = opt || {};\n    var unfinished;\n\n    each$1(stageHandlers, function (stageHandler, idx) {\n        if (opt.visualType && opt.visualType !== stageHandler.visualType) {\n            return;\n        }\n\n        var stageHandlerRecord = scheduler._stageTaskMap.get(stageHandler.uid);\n        var seriesTaskMap = stageHandlerRecord.seriesTaskMap;\n        var overallTask = stageHandlerRecord.overallTask;\n\n        if (overallTask) {\n            var overallNeedDirty;\n            var agentStubMap = overallTask.agentStubMap;\n            agentStubMap.each(function (stub) {\n                if (needSetDirty(opt, stub)) {\n                    stub.dirty();\n                    overallNeedDirty = true;\n                }\n            });\n            overallNeedDirty && overallTask.dirty();\n            updatePayload(overallTask, payload);\n            var performArgs = scheduler.getPerformArgs(overallTask, opt.block);\n            // Execute stubs firstly, which may set the overall task dirty,\n            // then execute the overall task. And stub will call seriesModel.setData,\n            // which ensures that in the overallTask seriesModel.getData() will not\n            // return incorrect data.\n            agentStubMap.each(function (stub) {\n                stub.perform(performArgs);\n            });\n            unfinished |= overallTask.perform(performArgs);\n        }\n        else if (seriesTaskMap) {\n            seriesTaskMap.each(function (task, pipelineId) {\n                if (needSetDirty(opt, task)) {\n                    task.dirty();\n                }\n                var performArgs = scheduler.getPerformArgs(task, opt.block);\n                performArgs.skip = !stageHandler.performRawSeries\n                    && ecModel.isSeriesFiltered(task.context.model);\n                updatePayload(task, payload);\n                unfinished |= task.perform(performArgs);\n            });\n        }\n    });\n\n    function needSetDirty(opt, task) {\n        return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id));\n    }\n\n    scheduler.unfinished |= unfinished;\n}\n\nproto.performSeriesTasks = function (ecModel) {\n    var unfinished;\n\n    ecModel.eachSeries(function (seriesModel) {\n        // Progress to the end for dataInit and dataRestore.\n        unfinished |= seriesModel.dataTask.perform();\n    });\n\n    this.unfinished |= unfinished;\n};\n\nproto.plan = function () {\n    // Travel pipelines, check block.\n    this._pipelineMap.each(function (pipeline) {\n        var task = pipeline.tail;\n        do {\n            if (task.__block) {\n                pipeline.blockIndex = task.__idxInPipeline;\n                break;\n            }\n            task = task.getUpstream();\n        }\n        while (task);\n    });\n};\n\nvar updatePayload = proto.updatePayload = function (task, payload) {\n    payload !== 'remain' && (task.context.payload = payload);\n};\n\nfunction createSeriesStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) {\n    var seriesTaskMap = stageHandlerRecord.seriesTaskMap\n        || (stageHandlerRecord.seriesTaskMap = createHashMap());\n    var seriesType = stageHandler.seriesType;\n    var getTargetSeries = stageHandler.getTargetSeries;\n\n    // If a stageHandler should cover all series, `createOnAllSeries` should be declared mandatorily,\n    // to avoid some typo or abuse. Otherwise if an extension do not specify a `seriesType`,\n    // it works but it may cause other irrelevant charts blocked.\n    if (stageHandler.createOnAllSeries) {\n        ecModel.eachRawSeries(create);\n    }\n    else if (seriesType) {\n        ecModel.eachRawSeriesByType(seriesType, create);\n    }\n    else if (getTargetSeries) {\n        getTargetSeries(ecModel, api).each(create);\n    }\n\n    function create(seriesModel) {\n        var pipelineId = seriesModel.uid;\n\n        // Init tasks for each seriesModel only once.\n        // Reuse original task instance.\n        var task = seriesTaskMap.get(pipelineId)\n            || seriesTaskMap.set(pipelineId, createTask({\n                plan: seriesTaskPlan,\n                reset: seriesTaskReset,\n                count: seriesTaskCount\n            }));\n        task.context = {\n            model: seriesModel,\n            ecModel: ecModel,\n            api: api,\n            useClearVisual: stageHandler.isVisual && !stageHandler.isLayout,\n            plan: stageHandler.plan,\n            reset: stageHandler.reset,\n            scheduler: scheduler\n        };\n        pipe(scheduler, seriesModel, task);\n    }\n\n    // Clear unused series tasks.\n    var pipelineMap = scheduler._pipelineMap;\n    seriesTaskMap.each(function (task, pipelineId) {\n        if (!pipelineMap.get(pipelineId)) {\n            task.dispose();\n            seriesTaskMap.removeKey(pipelineId);\n        }\n    });\n}\n\nfunction createOverallStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) {\n    var overallTask = stageHandlerRecord.overallTask = stageHandlerRecord.overallTask\n        // For overall task, the function only be called on reset stage.\n        || createTask({reset: overallTaskReset});\n\n    overallTask.context = {\n        ecModel: ecModel,\n        api: api,\n        overallReset: stageHandler.overallReset,\n        scheduler: scheduler\n    };\n\n    // Reuse orignal stubs.\n    var agentStubMap = overallTask.agentStubMap = overallTask.agentStubMap || createHashMap();\n\n    var seriesType = stageHandler.seriesType;\n    var getTargetSeries = stageHandler.getTargetSeries;\n    var overallProgress = true;\n    var modifyOutputEnd = stageHandler.modifyOutputEnd;\n\n    // An overall task with seriesType detected or has `getTargetSeries`, we add\n    // stub in each pipelines, it will set the overall task dirty when the pipeline\n    // progress. Moreover, to avoid call the overall task each frame (too frequent),\n    // we set the pipeline block.\n    if (seriesType) {\n        ecModel.eachRawSeriesByType(seriesType, createStub);\n    }\n    else if (getTargetSeries) {\n        getTargetSeries(ecModel, api).each(createStub);\n    }\n    // Otherwise, (usually it is legancy case), the overall task will only be\n    // executed when upstream dirty. Otherwise the progressive rendering of all\n    // pipelines will be disabled unexpectedly. But it still needs stubs to receive\n    // dirty info from upsteam.\n    else {\n        overallProgress = false;\n        each$1(ecModel.getSeries(), createStub);\n    }\n\n    function createStub(seriesModel) {\n        var pipelineId = seriesModel.uid;\n        var stub = agentStubMap.get(pipelineId);\n        if (!stub) {\n            stub = agentStubMap.set(pipelineId, createTask(\n                {reset: stubReset, onDirty: stubOnDirty}\n            ));\n            // When the result of `getTargetSeries` changed, the overallTask\n            // should be set as dirty and re-performed.\n            overallTask.dirty();\n        }\n        stub.context = {\n            model: seriesModel,\n            overallProgress: overallProgress,\n            modifyOutputEnd: modifyOutputEnd\n        };\n        stub.agent = overallTask;\n        stub.__block = overallProgress;\n\n        pipe(scheduler, seriesModel, stub);\n    }\n\n    // Clear unused stubs.\n    var pipelineMap = scheduler._pipelineMap;\n    agentStubMap.each(function (stub, pipelineId) {\n        if (!pipelineMap.get(pipelineId)) {\n            stub.dispose();\n            // When the result of `getTargetSeries` changed, the overallTask\n            // should be set as dirty and re-performed.\n            overallTask.dirty();\n            agentStubMap.removeKey(pipelineId);\n        }\n    });\n}\n\nfunction overallTaskReset(context) {\n    context.overallReset(\n        context.ecModel, context.api, context.payload\n    );\n}\n\nfunction stubReset(context, upstreamContext) {\n    return context.overallProgress && stubProgress;\n}\n\nfunction stubProgress() {\n    this.agent.dirty();\n    this.getDownstream().dirty();\n}\n\nfunction stubOnDirty() {\n    this.agent && this.agent.dirty();\n}\n\nfunction seriesTaskPlan(context) {\n    return context.plan && context.plan(\n        context.model, context.ecModel, context.api, context.payload\n    );\n}\n\nfunction seriesTaskReset(context) {\n    if (context.useClearVisual) {\n        context.data.clearAllVisual();\n    }\n    var resetDefines = context.resetDefines = normalizeToArray(context.reset(\n        context.model, context.ecModel, context.api, context.payload\n    ));\n    return resetDefines.length > 1\n        ? map(resetDefines, function (v, idx) {\n            return makeSeriesTaskProgress(idx);\n        })\n        : singleSeriesTaskProgress;\n}\n\nvar singleSeriesTaskProgress = makeSeriesTaskProgress(0);\n\nfunction makeSeriesTaskProgress(resetDefineIdx) {\n    return function (params, context) {\n        var data = context.data;\n        var resetDefine = context.resetDefines[resetDefineIdx];\n\n        if (resetDefine && resetDefine.dataEach) {\n            for (var i = params.start; i < params.end; i++) {\n                resetDefine.dataEach(data, i);\n            }\n        }\n        else if (resetDefine && resetDefine.progress) {\n            resetDefine.progress(params, data);\n        }\n    };\n}\n\nfunction seriesTaskCount(context) {\n    return context.data.count();\n}\n\nfunction pipe(scheduler, seriesModel, task) {\n    var pipelineId = seriesModel.uid;\n    var pipeline = scheduler._pipelineMap.get(pipelineId);\n    !pipeline.head && (pipeline.head = task);\n    pipeline.tail && pipeline.tail.pipe(task);\n    pipeline.tail = task;\n    task.__idxInPipeline = pipeline.count++;\n    task.__pipeline = pipeline;\n}\n\nScheduler.wrapStageHandler = function (stageHandler, visualType) {\n    if (isFunction$1(stageHandler)) {\n        stageHandler = {\n            overallReset: stageHandler,\n            seriesType: detectSeriseType(stageHandler)\n        };\n    }\n\n    stageHandler.uid = getUID('stageHandler');\n    visualType && (stageHandler.visualType = visualType);\n\n    return stageHandler;\n};\n\n\n\n/**\n * Only some legacy stage handlers (usually in echarts extensions) are pure function.\n * To ensure that they can work normally, they should work in block mode, that is,\n * they should not be started util the previous tasks finished. So they cause the\n * progressive rendering disabled. We try to detect the series type, to narrow down\n * the block range to only the series type they concern, but not all series.\n */\nfunction detectSeriseType(legacyFunc) {\n    seriesType = null;\n    try {\n        // Assume there is no async when calling `eachSeriesByType`.\n        legacyFunc(ecModelMock, apiMock);\n    }\n    catch (e) {\n    }\n    return seriesType;\n}\n\nvar ecModelMock = {};\nvar apiMock = {};\nvar seriesType;\n\nmockMethods(ecModelMock, GlobalModel);\nmockMethods(apiMock, ExtensionAPI);\necModelMock.eachSeriesByType = ecModelMock.eachRawSeriesByType = function (type) {\n    seriesType = type;\n};\necModelMock.eachComponent = function (cond) {\n    if (cond.mainType === 'series' && cond.subType) {\n        seriesType = cond.subType;\n    }\n};\n\nfunction mockMethods(target, Clz) {\n    /* eslint-disable */\n    for (var name in Clz.prototype) {\n        // Do not use hasOwnProperty\n        target[name] = noop;\n    }\n    /* eslint-enable */\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar colorAll = [\n    '#37A2DA', '#32C5E9', '#67E0E3', '#9FE6B8', '#FFDB5C', '#ff9f7f',\n    '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF'\n];\n\nvar lightTheme = {\n\n    color: colorAll,\n\n    colorLayer: [\n        ['#37A2DA', '#ffd85c', '#fd7b5f'],\n        ['#37A2DA', '#67E0E3', '#FFDB5C', '#ff9f7f', '#E062AE', '#9d96f5'],\n        ['#37A2DA', '#32C5E9', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#e7bcf3', '#8378EA', '#96BFFF'],\n        colorAll\n    ]\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar contrastColor = '#eee';\nvar axisCommon = function () {\n    return {\n        axisLine: {\n            lineStyle: {\n                color: contrastColor\n            }\n        },\n        axisTick: {\n            lineStyle: {\n                color: contrastColor\n            }\n        },\n        axisLabel: {\n            textStyle: {\n                color: contrastColor\n            }\n        },\n        splitLine: {\n            lineStyle: {\n                type: 'dashed',\n                color: '#aaa'\n            }\n        },\n        splitArea: {\n            areaStyle: {\n                color: contrastColor\n            }\n        }\n    };\n};\n\nvar colorPalette = [\n    '#dd6b66', '#759aa0', '#e69d87', '#8dc1a9', '#ea7e53',\n    '#eedd78', '#73a373', '#73b9bc', '#7289ab', '#91ca8c', '#f49f42'\n];\nvar theme = {\n    color: colorPalette,\n    backgroundColor: '#333',\n    tooltip: {\n        axisPointer: {\n            lineStyle: {\n                color: contrastColor\n            },\n            crossStyle: {\n                color: contrastColor\n            }\n        }\n    },\n    legend: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    textStyle: {\n        color: contrastColor\n    },\n    title: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    toolbox: {\n        iconStyle: {\n            normal: {\n                borderColor: contrastColor\n            }\n        }\n    },\n    dataZoom: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    visualMap: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    timeline: {\n        lineStyle: {\n            color: contrastColor\n        },\n        itemStyle: {\n            normal: {\n                color: colorPalette[1]\n            }\n        },\n        label: {\n            normal: {\n                textStyle: {\n                    color: contrastColor\n                }\n            }\n        },\n        controlStyle: {\n            normal: {\n                color: contrastColor,\n                borderColor: contrastColor\n            }\n        }\n    },\n    timeAxis: axisCommon(),\n    logAxis: axisCommon(),\n    valueAxis: axisCommon(),\n    categoryAxis: axisCommon(),\n\n    line: {\n        symbol: 'circle'\n    },\n    graph: {\n        color: colorPalette\n    },\n    gauge: {\n        title: {\n            textStyle: {\n                color: contrastColor\n            }\n        }\n    },\n    candlestick: {\n        itemStyle: {\n            normal: {\n                color: '#FD1050',\n                color0: '#0CF49B',\n                borderColor: '#FD1050',\n                borderColor0: '#0CF49B'\n            }\n        }\n    }\n};\ntheme.categoryAxis.splitLine.show = false;\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * This module is imported by echarts directly.\n *\n * Notice:\n * Always keep this file exists for backward compatibility.\n * Because before 4.1.0, dataset is an optional component,\n * some users may import this module manually.\n */\n\nComponentModel.extend({\n\n    type: 'dataset',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n\n        // 'row', 'column'\n        seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN,\n\n        // null/'auto': auto detect header, see \"module:echarts/data/helper/sourceHelper\"\n        sourceHeader: null,\n\n        dimensions: null,\n\n        source: null\n    },\n\n    optionUpdated: function () {\n        detectSourceFormat(this);\n    }\n\n});\n\nComponent$1.extend({\n\n    type: 'dataset'\n\n});\n\n/**\n * 椭圆形状\n * @module zrender/graphic/shape/Ellipse\n */\n\nvar Ellipse = Path.extend({\n\n    type: 'ellipse',\n\n    shape: {\n        cx: 0, cy: 0,\n        rx: 0, ry: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var k = 0.5522848;\n        var x = shape.cx;\n        var y = shape.cy;\n        var a = shape.rx;\n        var b = shape.ry;\n        var ox = a * k; // 水平控制点偏移量\n        var oy = b * k; // 垂直控制点偏移量\n        // 从椭圆的左端点开始顺时针绘制四条三次贝塞尔曲线\n        ctx.moveTo(x - a, y);\n        ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b);\n        ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y);\n        ctx.bezierCurveTo(x + a, y + oy, x + ox, y + b, x, y + b);\n        ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y);\n        ctx.closePath();\n    }\n});\n\n// import RadialGradient from '../graphic/RadialGradient';\n// import Pattern from '../graphic/Pattern';\n// import * as vector from '../core/vector';\n// Most of the values can be separated by comma and/or white space.\nvar DILIMITER_REG = /[\\s,]+/;\n\n/**\n * For big svg string, this method might be time consuming.\n *\n * @param {string} svg xml string\n * @return {Object} xml root.\n */\nfunction parseXML(svg) {\n    if (isString(svg)) {\n        var parser = new DOMParser();\n        svg = parser.parseFromString(svg, 'text/xml');\n    }\n\n    // Document node. If using $.get, doc node may be input.\n    if (svg.nodeType === 9) {\n        svg = svg.firstChild;\n    }\n    // nodeName of <!DOCTYPE svg> is also 'svg'.\n    while (svg.nodeName.toLowerCase() !== 'svg' || svg.nodeType !== 1) {\n        svg = svg.nextSibling;\n    }\n\n    return svg;\n}\n\nfunction SVGParser() {\n    this._defs = {};\n    this._root = null;\n\n    this._isDefine = false;\n    this._isText = false;\n}\n\nSVGParser.prototype.parse = function (xml, opt) {\n    opt = opt || {};\n\n    var svg = parseXML(xml);\n\n    if (!svg) {\n        throw new Error('Illegal svg');\n    }\n\n    var root = new Group();\n    this._root = root;\n    // parse view port\n    var viewBox = svg.getAttribute('viewBox') || '';\n\n    // If width/height not specified, means \"100%\" of `opt.width/height`.\n    // TODO: Other percent value not supported yet.\n    var width = parseFloat(svg.getAttribute('width') || opt.width);\n    var height = parseFloat(svg.getAttribute('height') || opt.height);\n    // If width/height not specified, set as null for output.\n    isNaN(width) && (width = null);\n    isNaN(height) && (height = null);\n\n    // Apply inline style on svg element.\n    parseAttributes(svg, root, null, true);\n\n    var child = svg.firstChild;\n    while (child) {\n        this._parseNode(child, root);\n        child = child.nextSibling;\n    }\n\n    var viewBoxRect;\n    var viewBoxTransform;\n\n    if (viewBox) {\n        var viewBoxArr = trim(viewBox).split(DILIMITER_REG);\n        // Some invalid case like viewBox: 'none'.\n        if (viewBoxArr.length >= 4) {\n            viewBoxRect = {\n                x: parseFloat(viewBoxArr[0] || 0),\n                y: parseFloat(viewBoxArr[1] || 0),\n                width: parseFloat(viewBoxArr[2]),\n                height: parseFloat(viewBoxArr[3])\n            };\n        }\n    }\n\n    if (viewBoxRect && width != null && height != null) {\n        viewBoxTransform = makeViewBoxTransform(viewBoxRect, width, height);\n\n        if (!opt.ignoreViewBox) {\n            // If set transform on the output group, it probably bring trouble when\n            // some users only intend to show the clipped content inside the viewBox,\n            // but not intend to transform the output group. So we keep the output\n            // group no transform. If the user intend to use the viewBox as a\n            // camera, just set `opt.ignoreViewBox` as `true` and set transfrom\n            // manually according to the viewBox info in the output of this method.\n            var elRoot = root;\n            root = new Group();\n            root.add(elRoot);\n            elRoot.scale = viewBoxTransform.scale.slice();\n            elRoot.position = viewBoxTransform.position.slice();\n        }\n    }\n\n    // Some shapes might be overflow the viewport, which should be\n    // clipped despite whether the viewBox is used, as the SVG does.\n    if (!opt.ignoreRootClip && width != null && height != null) {\n        root.setClipPath(new Rect({\n            shape: {x: 0, y: 0, width: width, height: height}\n        }));\n    }\n\n    // Set width/height on group just for output the viewport size.\n    return {\n        root: root,\n        width: width,\n        height: height,\n        viewBoxRect: viewBoxRect,\n        viewBoxTransform: viewBoxTransform\n    };\n};\n\nSVGParser.prototype._parseNode = function (xmlNode, parentGroup) {\n\n    var nodeName = xmlNode.nodeName.toLowerCase();\n\n    // TODO\n    // support <style>...</style> in svg, where nodeName is 'style',\n    // CSS classes is defined globally wherever the style tags are declared.\n\n    if (nodeName === 'defs') {\n        // define flag\n        this._isDefine = true;\n    }\n    else if (nodeName === 'text') {\n        this._isText = true;\n    }\n\n    var el;\n    if (this._isDefine) {\n        var parser = defineParsers[nodeName];\n        if (parser) {\n            var def = parser.call(this, xmlNode);\n            var id = xmlNode.getAttribute('id');\n            if (id) {\n                this._defs[id] = def;\n            }\n        }\n    }\n    else {\n        var parser = nodeParsers[nodeName];\n        if (parser) {\n            el = parser.call(this, xmlNode, parentGroup);\n            parentGroup.add(el);\n        }\n    }\n\n    var child = xmlNode.firstChild;\n    while (child) {\n        if (child.nodeType === 1) {\n            this._parseNode(child, el);\n        }\n        // Is text\n        if (child.nodeType === 3 && this._isText) {\n            this._parseText(child, el);\n        }\n        child = child.nextSibling;\n    }\n\n    // Quit define\n    if (nodeName === 'defs') {\n        this._isDefine = false;\n    }\n    else if (nodeName === 'text') {\n        this._isText = false;\n    }\n};\n\nSVGParser.prototype._parseText = function (xmlNode, parentGroup) {\n    if (xmlNode.nodeType === 1) {\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n        this._textX += parseFloat(dx);\n        this._textY += parseFloat(dy);\n    }\n\n    var text = new Text({\n        style: {\n            text: xmlNode.textContent,\n            transformText: true\n        },\n        position: [this._textX || 0, this._textY || 0]\n    });\n\n    inheritStyle(parentGroup, text);\n    parseAttributes(xmlNode, text, this._defs);\n\n    var fontSize = text.style.fontSize;\n    if (fontSize && fontSize < 9) {\n        // PENDING\n        text.style.fontSize = 9;\n        text.scale = text.scale || [1, 1];\n        text.scale[0] *= fontSize / 9;\n        text.scale[1] *= fontSize / 9;\n    }\n\n    var rect = text.getBoundingRect();\n    this._textX += rect.width;\n\n    parentGroup.add(text);\n\n    return text;\n};\n\nvar nodeParsers = {\n    'g': function (xmlNode, parentGroup) {\n        var g = new Group();\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n        return g;\n    },\n    'rect': function (xmlNode, parentGroup) {\n        var rect = new Rect();\n        inheritStyle(parentGroup, rect);\n        parseAttributes(xmlNode, rect, this._defs);\n\n        rect.setShape({\n            x: parseFloat(xmlNode.getAttribute('x') || 0),\n            y: parseFloat(xmlNode.getAttribute('y') || 0),\n            width: parseFloat(xmlNode.getAttribute('width') || 0),\n            height: parseFloat(xmlNode.getAttribute('height') || 0)\n        });\n\n        // console.log(xmlNode.getAttribute('transform'));\n        // console.log(rect.transform);\n\n        return rect;\n    },\n    'circle': function (xmlNode, parentGroup) {\n        var circle = new Circle();\n        inheritStyle(parentGroup, circle);\n        parseAttributes(xmlNode, circle, this._defs);\n\n        circle.setShape({\n            cx: parseFloat(xmlNode.getAttribute('cx') || 0),\n            cy: parseFloat(xmlNode.getAttribute('cy') || 0),\n            r: parseFloat(xmlNode.getAttribute('r') || 0)\n        });\n\n        return circle;\n    },\n    'line': function (xmlNode, parentGroup) {\n        var line = new Line();\n        inheritStyle(parentGroup, line);\n        parseAttributes(xmlNode, line, this._defs);\n\n        line.setShape({\n            x1: parseFloat(xmlNode.getAttribute('x1') || 0),\n            y1: parseFloat(xmlNode.getAttribute('y1') || 0),\n            x2: parseFloat(xmlNode.getAttribute('x2') || 0),\n            y2: parseFloat(xmlNode.getAttribute('y2') || 0)\n        });\n\n        return line;\n    },\n    'ellipse': function (xmlNode, parentGroup) {\n        var ellipse = new Ellipse();\n        inheritStyle(parentGroup, ellipse);\n        parseAttributes(xmlNode, ellipse, this._defs);\n\n        ellipse.setShape({\n            cx: parseFloat(xmlNode.getAttribute('cx') || 0),\n            cy: parseFloat(xmlNode.getAttribute('cy') || 0),\n            rx: parseFloat(xmlNode.getAttribute('rx') || 0),\n            ry: parseFloat(xmlNode.getAttribute('ry') || 0)\n        });\n        return ellipse;\n    },\n    'polygon': function (xmlNode, parentGroup) {\n        var points = xmlNode.getAttribute('points');\n        if (points) {\n            points = parsePoints(points);\n        }\n        var polygon = new Polygon({\n            shape: {\n                points: points || []\n            }\n        });\n\n        inheritStyle(parentGroup, polygon);\n        parseAttributes(xmlNode, polygon, this._defs);\n\n        return polygon;\n    },\n    'polyline': function (xmlNode, parentGroup) {\n        var path = new Path();\n        inheritStyle(parentGroup, path);\n        parseAttributes(xmlNode, path, this._defs);\n\n        var points = xmlNode.getAttribute('points');\n        if (points) {\n            points = parsePoints(points);\n        }\n        var polyline = new Polyline({\n            shape: {\n                points: points || []\n            }\n        });\n\n        return polyline;\n    },\n    'image': function (xmlNode, parentGroup) {\n        var img = new ZImage();\n        inheritStyle(parentGroup, img);\n        parseAttributes(xmlNode, img, this._defs);\n\n        img.setStyle({\n            image: xmlNode.getAttribute('xlink:href'),\n            x: xmlNode.getAttribute('x'),\n            y: xmlNode.getAttribute('y'),\n            width: xmlNode.getAttribute('width'),\n            height: xmlNode.getAttribute('height')\n        });\n\n        return img;\n    },\n    'text': function (xmlNode, parentGroup) {\n        var x = xmlNode.getAttribute('x') || 0;\n        var y = xmlNode.getAttribute('y') || 0;\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n\n        this._textX = parseFloat(x) + parseFloat(dx);\n        this._textY = parseFloat(y) + parseFloat(dy);\n\n        var g = new Group();\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n        return g;\n    },\n    'tspan': function (xmlNode, parentGroup) {\n        var x = xmlNode.getAttribute('x');\n        var y = xmlNode.getAttribute('y');\n        if (x != null) {\n            // new offset x\n            this._textX = parseFloat(x);\n        }\n        if (y != null) {\n            // new offset y\n            this._textY = parseFloat(y);\n        }\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n\n        var g = new Group();\n\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n\n        this._textX += dx;\n        this._textY += dy;\n\n        return g;\n    },\n    'path': function (xmlNode, parentGroup) {\n        // TODO svg fill rule\n        // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule\n        // path.style.globalCompositeOperation = 'xor';\n        var d = xmlNode.getAttribute('d') || '';\n\n        // Performance sensitive.\n\n        var path = createFromString(d);\n\n        inheritStyle(parentGroup, path);\n        parseAttributes(xmlNode, path, this._defs);\n\n        return path;\n    }\n};\n\nvar defineParsers = {\n\n    'lineargradient': function (xmlNode) {\n        var x1 = parseInt(xmlNode.getAttribute('x1') || 0, 10);\n        var y1 = parseInt(xmlNode.getAttribute('y1') || 0, 10);\n        var x2 = parseInt(xmlNode.getAttribute('x2') || 10, 10);\n        var y2 = parseInt(xmlNode.getAttribute('y2') || 0, 10);\n\n        var gradient = new LinearGradient(x1, y1, x2, y2);\n\n        _parseGradientColorStops(xmlNode, gradient);\n\n        return gradient;\n    },\n\n    'radialgradient': function (xmlNode) {\n\n    }\n};\n\nfunction _parseGradientColorStops(xmlNode, gradient) {\n\n    var stop = xmlNode.firstChild;\n\n    while (stop) {\n        if (stop.nodeType === 1) {\n            var offset = stop.getAttribute('offset');\n            if (offset.indexOf('%') > 0) {  // percentage\n                offset = parseInt(offset, 10) / 100;\n            }\n            else if (offset) {    // number from 0 to 1\n                offset = parseFloat(offset);\n            }\n            else {\n                offset = 0;\n            }\n\n            var stopColor = stop.getAttribute('stop-color') || '#000000';\n\n            gradient.addColorStop(offset, stopColor);\n        }\n        stop = stop.nextSibling;\n    }\n}\n\nfunction inheritStyle(parent, child) {\n    if (parent && parent.__inheritedStyle) {\n        if (!child.__inheritedStyle) {\n            child.__inheritedStyle = {};\n        }\n        defaults(child.__inheritedStyle, parent.__inheritedStyle);\n    }\n}\n\nfunction parsePoints(pointsString) {\n    var list = trim(pointsString).split(DILIMITER_REG);\n    var points = [];\n\n    for (var i = 0; i < list.length; i += 2) {\n        var x = parseFloat(list[i]);\n        var y = parseFloat(list[i + 1]);\n        points.push([x, y]);\n    }\n    return points;\n}\n\nvar attributesMap = {\n    'fill': 'fill',\n    'stroke': 'stroke',\n    'stroke-width': 'lineWidth',\n    'opacity': 'opacity',\n    'fill-opacity': 'fillOpacity',\n    'stroke-opacity': 'strokeOpacity',\n    'stroke-dasharray': 'lineDash',\n    'stroke-dashoffset': 'lineDashOffset',\n    'stroke-linecap': 'lineCap',\n    'stroke-linejoin': 'lineJoin',\n    'stroke-miterlimit': 'miterLimit',\n    'font-family': 'fontFamily',\n    'font-size': 'fontSize',\n    'font-style': 'fontStyle',\n    'font-weight': 'fontWeight',\n\n    'text-align': 'textAlign',\n    'alignment-baseline': 'textBaseline'\n};\n\nfunction parseAttributes(xmlNode, el, defs, onlyInlineStyle) {\n    var zrStyle = el.__inheritedStyle || {};\n    var isTextEl = el.type === 'text';\n\n    // TODO Shadow\n    if (xmlNode.nodeType === 1) {\n        parseTransformAttribute(xmlNode, el);\n\n        extend(zrStyle, parseStyleAttribute(xmlNode));\n\n        if (!onlyInlineStyle) {\n            for (var svgAttrName in attributesMap) {\n                if (attributesMap.hasOwnProperty(svgAttrName)) {\n                    var attrValue = xmlNode.getAttribute(svgAttrName);\n                    if (attrValue != null) {\n                        zrStyle[attributesMap[svgAttrName]] = attrValue;\n                    }\n                }\n            }\n        }\n    }\n\n    var elFillProp = isTextEl ? 'textFill' : 'fill';\n    var elStrokeProp = isTextEl ? 'textStroke' : 'stroke';\n\n    el.style = el.style || new Style();\n    var elStyle = el.style;\n\n    zrStyle.fill != null && elStyle.set(elFillProp, getPaint(zrStyle.fill, defs));\n    zrStyle.stroke != null && elStyle.set(elStrokeProp, getPaint(zrStyle.stroke, defs));\n\n    each$1([\n        'lineWidth', 'opacity', 'fillOpacity', 'strokeOpacity', 'miterLimit', 'fontSize'\n    ], function (propName) {\n        var elPropName = (propName === 'lineWidth' && isTextEl) ? 'textStrokeWidth' : propName;\n        zrStyle[propName] != null && elStyle.set(elPropName, parseFloat(zrStyle[propName]));\n    });\n\n    if (!zrStyle.textBaseline || zrStyle.textBaseline === 'auto') {\n        zrStyle.textBaseline = 'alphabetic';\n    }\n    if (zrStyle.textBaseline === 'alphabetic') {\n        zrStyle.textBaseline = 'bottom';\n    }\n    if (zrStyle.textAlign === 'start') {\n        zrStyle.textAlign = 'left';\n    }\n    if (zrStyle.textAlign === 'end') {\n        zrStyle.textAlign = 'right';\n    }\n\n    each$1(['lineDashOffset', 'lineCap', 'lineJoin',\n        'fontWeight', 'fontFamily', 'fontStyle', 'textAlign', 'textBaseline'\n    ], function (propName) {\n        zrStyle[propName] != null && elStyle.set(propName, zrStyle[propName]);\n    });\n\n    if (zrStyle.lineDash) {\n        el.style.lineDash = trim(zrStyle.lineDash).split(DILIMITER_REG);\n    }\n\n    if (elStyle[elStrokeProp] && elStyle[elStrokeProp] !== 'none') {\n        // enable stroke\n        el[elStrokeProp] = true;\n    }\n\n    el.__inheritedStyle = zrStyle;\n}\n\n\nvar urlRegex = /url\\(\\s*#(.*?)\\)/;\nfunction getPaint(str, defs) {\n    // if (str === 'none') {\n    //     return;\n    // }\n    var urlMatch = defs && str && str.match(urlRegex);\n    if (urlMatch) {\n        var url = trim(urlMatch[1]);\n        var def = defs[url];\n        return def;\n    }\n    return str;\n}\n\nvar transformRegex = /(translate|scale|rotate|skewX|skewY|matrix)\\(([\\-\\s0-9\\.e,]*)\\)/g;\n\nfunction parseTransformAttribute(xmlNode, node) {\n    var transform = xmlNode.getAttribute('transform');\n    if (transform) {\n        transform = transform.replace(/,/g, ' ');\n        var m = null;\n        var transformOps = [];\n        transform.replace(transformRegex, function (str, type, value) {\n            transformOps.push(type, value);\n        });\n        for (var i = transformOps.length - 1; i > 0; i -= 2) {\n            var value = transformOps[i];\n            var type = transformOps[i - 1];\n            m = m || create$1();\n            switch (type) {\n                case 'translate':\n                    value = trim(value).split(DILIMITER_REG);\n                    translate(m, m, [parseFloat(value[0]), parseFloat(value[1] || 0)]);\n                    break;\n                case 'scale':\n                    value = trim(value).split(DILIMITER_REG);\n                    scale$1(m, m, [parseFloat(value[0]), parseFloat(value[1] || value[0])]);\n                    break;\n                case 'rotate':\n                    value = trim(value).split(DILIMITER_REG);\n                    rotate(m, m, parseFloat(value[0]));\n                    break;\n                case 'skew':\n                    value = trim(value).split(DILIMITER_REG);\n                    console.warn('Skew transform is not supported yet');\n                    break;\n                case 'matrix':\n                    var value = trim(value).split(DILIMITER_REG);\n                    m[0] = parseFloat(value[0]);\n                    m[1] = parseFloat(value[1]);\n                    m[2] = parseFloat(value[2]);\n                    m[3] = parseFloat(value[3]);\n                    m[4] = parseFloat(value[4]);\n                    m[5] = parseFloat(value[5]);\n                    break;\n            }\n        }\n        node.setLocalTransform(m);\n    }\n}\n\n// Value may contain space.\nvar styleRegex = /([^\\s:;]+)\\s*:\\s*([^:;]+)/g;\nfunction parseStyleAttribute(xmlNode) {\n    var style = xmlNode.getAttribute('style');\n    var result = {};\n\n    if (!style) {\n        return result;\n    }\n\n    var styleList = {};\n    styleRegex.lastIndex = 0;\n    var styleRegResult;\n    while ((styleRegResult = styleRegex.exec(style)) != null) {\n        styleList[styleRegResult[1]] = styleRegResult[2];\n    }\n\n    for (var svgAttrName in attributesMap) {\n        if (attributesMap.hasOwnProperty(svgAttrName) && styleList[svgAttrName] != null) {\n            result[attributesMap[svgAttrName]] = styleList[svgAttrName];\n        }\n    }\n\n    return result;\n}\n\n/**\n * @param {Array.<number>} viewBoxRect\n * @param {number} width\n * @param {number} height\n * @return {Object} {scale, position}\n */\nfunction makeViewBoxTransform(viewBoxRect, width, height) {\n    var scaleX = width / viewBoxRect.width;\n    var scaleY = height / viewBoxRect.height;\n    var scale = Math.min(scaleX, scaleY);\n    // preserveAspectRatio 'xMidYMid'\n    var viewBoxScale = [scale, scale];\n    var viewBoxPosition = [\n        -(viewBoxRect.x + viewBoxRect.width / 2) * scale + width / 2,\n        -(viewBoxRect.y + viewBoxRect.height / 2) * scale + height / 2\n    ];\n\n    return {\n        scale: viewBoxScale,\n        position: viewBoxPosition\n    };\n}\n\n/**\n * @param {string|XMLElement} xml\n * @param {Object} [opt]\n * @param {number} [opt.width] Default width if svg width not specified or is a percent value.\n * @param {number} [opt.height] Default height if svg height not specified or is a percent value.\n * @param {boolean} [opt.ignoreViewBox]\n * @param {boolean} [opt.ignoreRootClip]\n * @return {Object} result:\n * {\n *     root: Group, The root of the the result tree of zrender shapes,\n *     width: number, the viewport width of the SVG,\n *     height: number, the viewport height of the SVG,\n *     viewBoxRect: {x, y, width, height}, the declared viewBox rect of the SVG, if exists,\n *     viewBoxTransform: the {scale, position} calculated by viewBox and viewport, is exists.\n * }\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar storage = createHashMap();\n\n// For minimize the code size of common echarts package,\n// do not put too much logic in this module.\n\nvar mapDataStorage = {\n\n    // The format of record: see `echarts.registerMap`.\n    // Compatible with previous `echarts.registerMap`.\n    registerMap: function (mapName, rawGeoJson, rawSpecialAreas) {\n\n        var records;\n\n        if (isArray(rawGeoJson)) {\n            records = rawGeoJson;\n        }\n        else if (rawGeoJson.svg) {\n            records = [{\n                type: 'svg',\n                source: rawGeoJson.svg,\n                specialAreas: rawGeoJson.specialAreas\n            }];\n        }\n        else {\n            // Backward compatibility.\n            if (rawGeoJson.geoJson && !rawGeoJson.features) {\n                rawSpecialAreas = rawGeoJson.specialAreas;\n                rawGeoJson = rawGeoJson.geoJson;\n            }\n            records = [{\n                type: 'geoJSON',\n                source: rawGeoJson,\n                specialAreas: rawSpecialAreas\n            }];\n        }\n\n        each$1(records, function (record) {\n            var type = record.type;\n            type === 'geoJson' && (type = record.type = 'geoJSON');\n\n            var parse = parsers[type];\n\n            if (__DEV__) {\n                assert$1(parse, 'Illegal map type: ' + type);\n            }\n\n            parse(record);\n        });\n\n        return storage.set(mapName, records);\n    },\n\n    retrieveMap: function (mapName) {\n        return storage.get(mapName);\n    }\n\n};\n\nvar parsers = {\n\n    geoJSON: function (record) {\n        var source = record.source;\n        record.geoJSON = !isString(source)\n            ? source\n            : (typeof JSON !== 'undefined' && JSON.parse)\n            ? JSON.parse(source)\n            : (new Function('return (' + source + ');'))();\n    },\n\n    // Only perform parse to XML object here, which might be time\n    // consiming for large SVG.\n    // Although convert XML to zrender element is also time consiming,\n    // if we do it here, the clone of zrender elements has to be\n    // required. So we do it once for each geo instance, util real\n    // performance issues call for optimizing it.\n    svg: function (record) {\n        record.svgXML = parseXML(record.source);\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\nvar assert = assert$1;\nvar each = each$1;\nvar isFunction = isFunction$1;\nvar isObject = isObject$1;\nvar parseClassType = ComponentModel.parseClassType;\n\nvar version = '4.2.1';\n\nvar dependencies = {\n    zrender: '4.0.6'\n};\n\nvar TEST_FRAME_REMAIN_TIME = 1;\n\nvar PRIORITY_PROCESSOR_FILTER = 1000;\nvar PRIORITY_PROCESSOR_STATISTIC = 5000;\n\nvar PRIORITY_VISUAL_LAYOUT = 1000;\nvar PRIORITY_VISUAL_GLOBAL = 2000;\nvar PRIORITY_VISUAL_CHART = 3000;\nvar PRIORITY_VISUAL_COMPONENT = 4000;\n// FIXME\n// necessary?\nvar PRIORITY_VISUAL_BRUSH = 5000;\n\nvar PRIORITY = {\n    PROCESSOR: {\n        FILTER: PRIORITY_PROCESSOR_FILTER,\n        STATISTIC: PRIORITY_PROCESSOR_STATISTIC\n    },\n    VISUAL: {\n        LAYOUT: PRIORITY_VISUAL_LAYOUT,\n        GLOBAL: PRIORITY_VISUAL_GLOBAL,\n        CHART: PRIORITY_VISUAL_CHART,\n        COMPONENT: PRIORITY_VISUAL_COMPONENT,\n        BRUSH: PRIORITY_VISUAL_BRUSH\n    }\n};\n\n// Main process have three entries: `setOption`, `dispatchAction` and `resize`,\n// where they must not be invoked nestedly, except the only case: invoke\n// dispatchAction with updateMethod \"none\" in main process.\n// This flag is used to carry out this rule.\n// All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]).\nvar IN_MAIN_PROCESS = '__flagInMainProcess';\nvar OPTION_UPDATED = '__optionUpdated';\nvar ACTION_REG = /^[a-zA-Z0-9_]+$/;\n\n\nfunction createRegisterEventWithLowercaseName(method) {\n    return function (eventName, handler, context) {\n        // Event name is all lowercase\n        eventName = eventName && eventName.toLowerCase();\n        Eventful.prototype[method].call(this, eventName, handler, context);\n    };\n}\n\n/**\n * @module echarts~MessageCenter\n */\nfunction MessageCenter() {\n    Eventful.call(this);\n}\nMessageCenter.prototype.on = createRegisterEventWithLowercaseName('on');\nMessageCenter.prototype.off = createRegisterEventWithLowercaseName('off');\nMessageCenter.prototype.one = createRegisterEventWithLowercaseName('one');\nmixin(MessageCenter, Eventful);\n\n/**\n * @module echarts~ECharts\n */\nfunction ECharts(dom, theme$$1, opts) {\n    opts = opts || {};\n\n    // Get theme by name\n    if (typeof theme$$1 === 'string') {\n        theme$$1 = themeStorage[theme$$1];\n    }\n\n    /**\n     * @type {string}\n     */\n    this.id;\n\n    /**\n     * Group id\n     * @type {string}\n     */\n    this.group;\n\n    /**\n     * @type {HTMLElement}\n     * @private\n     */\n    this._dom = dom;\n\n    var defaultRenderer = 'canvas';\n    if (__DEV__) {\n        defaultRenderer = (\n            typeof window === 'undefined' ? global : window\n        ).__ECHARTS__DEFAULT__RENDERER__ || defaultRenderer;\n    }\n\n    /**\n     * @type {module:zrender/ZRender}\n     * @private\n     */\n    var zr = this._zr = init$1(dom, {\n        renderer: opts.renderer || defaultRenderer,\n        devicePixelRatio: opts.devicePixelRatio,\n        width: opts.width,\n        height: opts.height\n    });\n\n    /**\n     * Expect 60 pfs.\n     * @type {Function}\n     * @private\n     */\n    this._throttledZrFlush = throttle(bind(zr.flush, zr), 17);\n\n    var theme$$1 = clone(theme$$1);\n    theme$$1 && backwardCompat(theme$$1, true);\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._theme = theme$$1;\n\n    /**\n     * @type {Array.<module:echarts/view/Chart>}\n     * @private\n     */\n    this._chartsViews = [];\n\n    /**\n     * @type {Object.<string, module:echarts/view/Chart>}\n     * @private\n     */\n    this._chartsMap = {};\n\n    /**\n     * @type {Array.<module:echarts/view/Component>}\n     * @private\n     */\n    this._componentsViews = [];\n\n    /**\n     * @type {Object.<string, module:echarts/view/Component>}\n     * @private\n     */\n    this._componentsMap = {};\n\n    /**\n     * @type {module:echarts/CoordinateSystem}\n     * @private\n     */\n    this._coordSysMgr = new CoordinateSystemManager();\n\n    /**\n     * @type {module:echarts/ExtensionAPI}\n     * @private\n     */\n    var api = this._api = createExtensionAPI(this);\n\n    // Sort on demand\n    function prioritySortFunc(a, b) {\n        return a.__prio - b.__prio;\n    }\n    sort(visualFuncs, prioritySortFunc);\n    sort(dataProcessorFuncs, prioritySortFunc);\n\n    /**\n     * @type {module:echarts/stream/Scheduler}\n     */\n    this._scheduler = new Scheduler(this, api, dataProcessorFuncs, visualFuncs);\n\n    Eventful.call(this, this._ecEventProcessor = new EventProcessor());\n\n    /**\n     * @type {module:echarts~MessageCenter}\n     * @private\n     */\n    this._messageCenter = new MessageCenter();\n\n    // Init mouse events\n    this._initEvents();\n\n    // In case some people write `window.onresize = chart.resize`\n    this.resize = bind(this.resize, this);\n\n    // Can't dispatch action during rendering procedure\n    this._pendingActions = [];\n\n    zr.animation.on('frame', this._onframe, this);\n\n    bindRenderedEvent(zr, this);\n\n    // ECharts instance can be used as value.\n    setAsPrimitive(this);\n}\n\nvar echartsProto = ECharts.prototype;\n\nechartsProto._onframe = function () {\n    if (this._disposed) {\n        return;\n    }\n\n    var scheduler = this._scheduler;\n\n    // Lazy update\n    if (this[OPTION_UPDATED]) {\n        var silent = this[OPTION_UPDATED].silent;\n\n        this[IN_MAIN_PROCESS] = true;\n\n        prepare(this);\n        updateMethods.update.call(this);\n\n        this[IN_MAIN_PROCESS] = false;\n\n        this[OPTION_UPDATED] = false;\n\n        flushPendingActions.call(this, silent);\n\n        triggerUpdatedEvent.call(this, silent);\n    }\n    // Avoid do both lazy update and progress in one frame.\n    else if (scheduler.unfinished) {\n        // Stream progress.\n        var remainTime = TEST_FRAME_REMAIN_TIME;\n        var ecModel = this._model;\n        var api = this._api;\n        scheduler.unfinished = false;\n        do {\n            var startTime = +new Date();\n\n            scheduler.performSeriesTasks(ecModel);\n\n            // Currently dataProcessorFuncs do not check threshold.\n            scheduler.performDataProcessorTasks(ecModel);\n\n            updateStreamModes(this, ecModel);\n\n            // Do not update coordinate system here. Because that coord system update in\n            // each frame is not a good user experience. So we follow the rule that\n            // the extent of the coordinate system is determin in the first frame (the\n            // frame is executed immedietely after task reset.\n            // this._coordSysMgr.update(ecModel, api);\n\n            // console.log('--- ec frame visual ---', remainTime);\n            scheduler.performVisualTasks(ecModel);\n\n            renderSeries(this, this._model, api, 'remain');\n\n            remainTime -= (+new Date() - startTime);\n        }\n        while (remainTime > 0 && scheduler.unfinished);\n\n        // Call flush explicitly for trigger finished event.\n        if (!scheduler.unfinished) {\n            this._zr.flush();\n        }\n        // Else, zr flushing be ensue within the same frame,\n        // because zr flushing is after onframe event.\n    }\n};\n\n/**\n * @return {HTMLElement}\n */\nechartsProto.getDom = function () {\n    return this._dom;\n};\n\n/**\n * @return {module:zrender~ZRender}\n */\nechartsProto.getZr = function () {\n    return this._zr;\n};\n\n/**\n * Usage:\n * chart.setOption(option, notMerge, lazyUpdate);\n * chart.setOption(option, {\n *     notMerge: ...,\n *     lazyUpdate: ...,\n *     silent: ...\n * });\n *\n * @param {Object} option\n * @param {Object|boolean} [opts] opts or notMerge.\n * @param {boolean} [opts.notMerge=false]\n * @param {boolean} [opts.lazyUpdate=false] Useful when setOption frequently.\n */\nechartsProto.setOption = function (option, notMerge, lazyUpdate) {\n    if (__DEV__) {\n        assert(!this[IN_MAIN_PROCESS], '`setOption` should not be called during main process.');\n    }\n\n    var silent;\n    if (isObject(notMerge)) {\n        lazyUpdate = notMerge.lazyUpdate;\n        silent = notMerge.silent;\n        notMerge = notMerge.notMerge;\n    }\n\n    this[IN_MAIN_PROCESS] = true;\n\n    if (!this._model || notMerge) {\n        var optionManager = new OptionManager(this._api);\n        var theme$$1 = this._theme;\n        var ecModel = this._model = new GlobalModel(null, null, theme$$1, optionManager);\n        ecModel.scheduler = this._scheduler;\n        ecModel.init(null, null, theme$$1, optionManager);\n    }\n\n    this._model.setOption(option, optionPreprocessorFuncs);\n\n    if (lazyUpdate) {\n        this[OPTION_UPDATED] = {silent: silent};\n        this[IN_MAIN_PROCESS] = false;\n    }\n    else {\n        prepare(this);\n\n        updateMethods.update.call(this);\n\n        // Ensure zr refresh sychronously, and then pixel in canvas can be\n        // fetched after `setOption`.\n        this._zr.flush();\n\n        this[OPTION_UPDATED] = false;\n        this[IN_MAIN_PROCESS] = false;\n\n        flushPendingActions.call(this, silent);\n        triggerUpdatedEvent.call(this, silent);\n    }\n};\n\n/**\n * @DEPRECATED\n */\nechartsProto.setTheme = function () {\n    console.error('ECharts#setTheme() is DEPRECATED in ECharts 3.0');\n};\n\n/**\n * @return {module:echarts/model/Global}\n */\nechartsProto.getModel = function () {\n    return this._model;\n};\n\n/**\n * @return {Object}\n */\nechartsProto.getOption = function () {\n    return this._model && this._model.getOption();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getWidth = function () {\n    return this._zr.getWidth();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getHeight = function () {\n    return this._zr.getHeight();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getDevicePixelRatio = function () {\n    return this._zr.painter.dpr || window.devicePixelRatio || 1;\n};\n\n/**\n * Get canvas which has all thing rendered\n * @param {Object} opts\n * @param {string} [opts.backgroundColor]\n * @return {string}\n */\nechartsProto.getRenderedCanvas = function (opts) {\n    if (!env$1.canvasSupported) {\n        return;\n    }\n    opts = opts || {};\n    opts.pixelRatio = opts.pixelRatio || 1;\n    opts.backgroundColor = opts.backgroundColor\n        || this._model.get('backgroundColor');\n    var zr = this._zr;\n    // var list = zr.storage.getDisplayList();\n    // Stop animations\n    // Never works before in init animation, so remove it.\n    // zrUtil.each(list, function (el) {\n    //     el.stopAnimation(true);\n    // });\n    return zr.painter.getRenderedCanvas(opts);\n};\n\n/**\n * Get svg data url\n * @return {string}\n */\nechartsProto.getSvgDataUrl = function () {\n    if (!env$1.svgSupported) {\n        return;\n    }\n\n    var zr = this._zr;\n    var list = zr.storage.getDisplayList();\n    // Stop animations\n    each$1(list, function (el) {\n        el.stopAnimation(true);\n    });\n\n    return zr.painter.pathToDataUrl();\n};\n\n/**\n * @return {string}\n * @param {Object} opts\n * @param {string} [opts.type='png']\n * @param {string} [opts.pixelRatio=1]\n * @param {string} [opts.backgroundColor]\n * @param {string} [opts.excludeComponents]\n */\nechartsProto.getDataURL = function (opts) {\n    opts = opts || {};\n    var excludeComponents = opts.excludeComponents;\n    var ecModel = this._model;\n    var excludesComponentViews = [];\n    var self = this;\n\n    each(excludeComponents, function (componentType) {\n        ecModel.eachComponent({\n            mainType: componentType\n        }, function (component) {\n            var view = self._componentsMap[component.__viewId];\n            if (!view.group.ignore) {\n                excludesComponentViews.push(view);\n                view.group.ignore = true;\n            }\n        });\n    });\n\n    var url = this._zr.painter.getType() === 'svg'\n        ? this.getSvgDataUrl()\n        : this.getRenderedCanvas(opts).toDataURL(\n            'image/' + (opts && opts.type || 'png')\n        );\n\n    each(excludesComponentViews, function (view) {\n        view.group.ignore = false;\n    });\n\n    return url;\n};\n\n\n/**\n * @return {string}\n * @param {Object} opts\n * @param {string} [opts.type='png']\n * @param {string} [opts.pixelRatio=1]\n * @param {string} [opts.backgroundColor]\n */\nechartsProto.getConnectedDataURL = function (opts) {\n    if (!env$1.canvasSupported) {\n        return;\n    }\n    var groupId = this.group;\n    var mathMin = Math.min;\n    var mathMax = Math.max;\n    var MAX_NUMBER = Infinity;\n    if (connectedGroups[groupId]) {\n        var left = MAX_NUMBER;\n        var top = MAX_NUMBER;\n        var right = -MAX_NUMBER;\n        var bottom = -MAX_NUMBER;\n        var canvasList = [];\n        var dpr = (opts && opts.pixelRatio) || 1;\n\n        each$1(instances, function (chart, id) {\n            if (chart.group === groupId) {\n                var canvas = chart.getRenderedCanvas(\n                    clone(opts)\n                );\n                var boundingRect = chart.getDom().getBoundingClientRect();\n                left = mathMin(boundingRect.left, left);\n                top = mathMin(boundingRect.top, top);\n                right = mathMax(boundingRect.right, right);\n                bottom = mathMax(boundingRect.bottom, bottom);\n                canvasList.push({\n                    dom: canvas,\n                    left: boundingRect.left,\n                    top: boundingRect.top\n                });\n            }\n        });\n\n        left *= dpr;\n        top *= dpr;\n        right *= dpr;\n        bottom *= dpr;\n        var width = right - left;\n        var height = bottom - top;\n        var targetCanvas = createCanvas();\n        targetCanvas.width = width;\n        targetCanvas.height = height;\n        var zr = init$1(targetCanvas);\n\n        each(canvasList, function (item) {\n            var img = new ZImage({\n                style: {\n                    x: item.left * dpr - left,\n                    y: item.top * dpr - top,\n                    image: item.dom\n                }\n            });\n            zr.add(img);\n        });\n        zr.refreshImmediately();\n\n        return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png'));\n    }\n    else {\n        return this.getDataURL(opts);\n    }\n};\n\n/**\n * Convert from logical coordinate system to pixel coordinate system.\n * See CoordinateSystem#convertToPixel.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId, geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName,\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {Array|number} result\n */\nechartsProto.convertToPixel = curry(doConvertPixel, 'convertToPixel');\n\n/**\n * Convert from pixel coordinate system to logical coordinate system.\n * See CoordinateSystem#convertFromPixel.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId / geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {Array|number} result\n */\nechartsProto.convertFromPixel = curry(doConvertPixel, 'convertFromPixel');\n\nfunction doConvertPixel(methodName, finder, value) {\n    var ecModel = this._model;\n    var coordSysList = this._coordSysMgr.getCoordinateSystems();\n    var result;\n\n    finder = parseFinder(ecModel, finder);\n\n    for (var i = 0; i < coordSysList.length; i++) {\n        var coordSys = coordSysList[i];\n        if (coordSys[methodName]\n            && (result = coordSys[methodName](ecModel, finder, value)) != null\n        ) {\n            return result;\n        }\n    }\n\n    if (__DEV__) {\n        console.warn(\n            'No coordinate system that supports ' + methodName + ' found by the given finder.'\n        );\n    }\n}\n\n/**\n * Is the specified coordinate systems or components contain the given pixel point.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId / geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName,\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {boolean} result\n */\nechartsProto.containPixel = function (finder, value) {\n    var ecModel = this._model;\n    var result;\n\n    finder = parseFinder(ecModel, finder);\n\n    each$1(finder, function (models, key) {\n        key.indexOf('Models') >= 0 && each$1(models, function (model) {\n            var coordSys = model.coordinateSystem;\n            if (coordSys && coordSys.containPoint) {\n                result |= !!coordSys.containPoint(value);\n            }\n            else if (key === 'seriesModels') {\n                var view = this._chartsMap[model.__viewId];\n                if (view && view.containPoint) {\n                    result |= view.containPoint(value, model);\n                }\n                else {\n                    if (__DEV__) {\n                        console.warn(key + ': ' + (view\n                            ? 'The found component do not support containPoint.'\n                            : 'No view mapping to the found component.'\n                        ));\n                    }\n                }\n            }\n            else {\n                if (__DEV__) {\n                    console.warn(key + ': containPoint is not supported');\n                }\n            }\n        }, this);\n    }, this);\n\n    return !!result;\n};\n\n/**\n * Get visual from series or data.\n * @param {string|Object} finder\n *        If string, e.g., 'series', means {seriesIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            dataIndex / dataIndexInside\n *        }\n *        If dataIndex is not specified, series visual will be fetched,\n *        but not data item visual.\n *        If all of seriesIndex, seriesId, seriesName are not specified,\n *        visual will be fetched from first series.\n * @param {string} visualType 'color', 'symbol', 'symbolSize'\n */\nechartsProto.getVisual = function (finder, visualType) {\n    var ecModel = this._model;\n\n    finder = parseFinder(ecModel, finder, {defaultMainType: 'series'});\n\n    var seriesModel = finder.seriesModel;\n\n    if (__DEV__) {\n        if (!seriesModel) {\n            console.warn('There is no specified seires model');\n        }\n    }\n\n    var data = seriesModel.getData();\n\n    var dataIndexInside = finder.hasOwnProperty('dataIndexInside')\n        ? finder.dataIndexInside\n        : finder.hasOwnProperty('dataIndex')\n        ? data.indexOfRawIndex(finder.dataIndex)\n        : null;\n\n    return dataIndexInside != null\n        ? data.getItemVisual(dataIndexInside, visualType)\n        : data.getVisual(visualType);\n};\n\n/**\n * Get view of corresponding component model\n * @param  {module:echarts/model/Component} componentModel\n * @return {module:echarts/view/Component}\n */\nechartsProto.getViewOfComponentModel = function (componentModel) {\n    return this._componentsMap[componentModel.__viewId];\n};\n\n/**\n * Get view of corresponding series model\n * @param  {module:echarts/model/Series} seriesModel\n * @return {module:echarts/view/Chart}\n */\nechartsProto.getViewOfSeriesModel = function (seriesModel) {\n    return this._chartsMap[seriesModel.__viewId];\n};\n\nvar updateMethods = {\n\n    prepareAndUpdate: function (payload) {\n        prepare(this);\n        updateMethods.update.call(this, payload);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    update: function (payload) {\n        // console.profile && console.profile('update');\n\n        var ecModel = this._model;\n        var api = this._api;\n        var zr = this._zr;\n        var coordSysMgr = this._coordSysMgr;\n        var scheduler = this._scheduler;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        scheduler.restoreData(ecModel, payload);\n\n        scheduler.performSeriesTasks(ecModel);\n\n        // TODO\n        // Save total ecModel here for undo/redo (after restoring data and before processing data).\n        // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call.\n\n        // Create new coordinate system each update\n        // In LineView may save the old coordinate system and use it to get the orignal point\n        coordSysMgr.create(ecModel, api);\n\n        scheduler.performDataProcessorTasks(ecModel, payload);\n\n        // Current stream render is not supported in data process. So we can update\n        // stream modes after data processing, where the filtered data is used to\n        // deteming whether use progressive rendering.\n        updateStreamModes(this, ecModel);\n\n        // We update stream modes before coordinate system updated, then the modes info\n        // can be fetched when coord sys updating (consider the barGrid extent fix). But\n        // the drawback is the full coord info can not be fetched. Fortunately this full\n        // coord is not requied in stream mode updater currently.\n        coordSysMgr.update(ecModel, api);\n\n        clearColorPalette(ecModel);\n        scheduler.performVisualTasks(ecModel, payload);\n\n        render(this, ecModel, api, payload);\n\n        // Set background\n        var backgroundColor = ecModel.get('backgroundColor') || 'transparent';\n\n        // In IE8\n        if (!env$1.canvasSupported) {\n            var colorArr = parse(backgroundColor);\n            backgroundColor = stringify(colorArr, 'rgb');\n            if (colorArr[3] === 0) {\n                backgroundColor = 'transparent';\n            }\n        }\n        else {\n            zr.setBackgroundColor(backgroundColor);\n        }\n\n        performPostUpdateFuncs(ecModel, api);\n\n        // console.profile && console.profileEnd('update');\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateTransform: function (payload) {\n        var ecModel = this._model;\n        var ecIns = this;\n        var api = this._api;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        // ChartView.markUpdateMethod(payload, 'updateTransform');\n\n        var componentDirtyList = [];\n        ecModel.eachComponent(function (componentType, componentModel) {\n            var componentView = ecIns.getViewOfComponentModel(componentModel);\n            if (componentView && componentView.__alive) {\n                if (componentView.updateTransform) {\n                    var result = componentView.updateTransform(componentModel, ecModel, api, payload);\n                    result && result.update && componentDirtyList.push(componentView);\n                }\n                else {\n                    componentDirtyList.push(componentView);\n                }\n            }\n        });\n\n        var seriesDirtyMap = createHashMap();\n        ecModel.eachSeries(function (seriesModel) {\n            var chartView = ecIns._chartsMap[seriesModel.__viewId];\n            if (chartView.updateTransform) {\n                var result = chartView.updateTransform(seriesModel, ecModel, api, payload);\n                result && result.update && seriesDirtyMap.set(seriesModel.uid, 1);\n            }\n            else {\n                seriesDirtyMap.set(seriesModel.uid, 1);\n            }\n        });\n\n        clearColorPalette(ecModel);\n        // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);\n        this._scheduler.performVisualTasks(\n            ecModel, payload, {setDirty: true, dirtyMap: seriesDirtyMap}\n        );\n\n        // Currently, not call render of components. Geo render cost a lot.\n        // renderComponents(ecIns, ecModel, api, payload, componentDirtyList);\n        renderSeries(ecIns, ecModel, api, payload, seriesDirtyMap);\n\n        performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateView: function (payload) {\n        var ecModel = this._model;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        Chart.markUpdateMethod(payload, 'updateView');\n\n        clearColorPalette(ecModel);\n\n        // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});\n\n        render(this, this._model, this._api, payload);\n\n        performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateVisual: function (payload) {\n        updateMethods.update.call(this, payload);\n\n        // var ecModel = this._model;\n\n        // // update before setOption\n        // if (!ecModel) {\n        //     return;\n        // }\n\n        // ChartView.markUpdateMethod(payload, 'updateVisual');\n\n        // clearColorPalette(ecModel);\n\n        // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // this._scheduler.performVisualTasks(ecModel, payload, {visualType: 'visual', setDirty: true});\n\n        // render(this, this._model, this._api, payload);\n\n        // performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateLayout: function (payload) {\n        updateMethods.update.call(this, payload);\n\n        // var ecModel = this._model;\n\n        // // update before setOption\n        // if (!ecModel) {\n        //     return;\n        // }\n\n        // ChartView.markUpdateMethod(payload, 'updateLayout');\n\n        // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);\n        // this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});\n\n        // render(this, this._model, this._api, payload);\n\n        // performPostUpdateFuncs(ecModel, this._api);\n    }\n};\n\nfunction prepare(ecIns) {\n    var ecModel = ecIns._model;\n    var scheduler = ecIns._scheduler;\n\n    scheduler.restorePipelines(ecModel);\n\n    scheduler.prepareStageTasks();\n\n    prepareView(ecIns, 'component', ecModel, scheduler);\n\n    prepareView(ecIns, 'chart', ecModel, scheduler);\n\n    scheduler.plan();\n}\n\n/**\n * @private\n */\nfunction updateDirectly(ecIns, method, payload, mainType, subType) {\n    var ecModel = ecIns._model;\n\n    // broadcast\n    if (!mainType) {\n        // FIXME\n        // Chart will not be update directly here, except set dirty.\n        // But there is no such scenario now.\n        each(ecIns._componentsViews.concat(ecIns._chartsViews), callView);\n        return;\n    }\n\n    var query = {};\n    query[mainType + 'Id'] = payload[mainType + 'Id'];\n    query[mainType + 'Index'] = payload[mainType + 'Index'];\n    query[mainType + 'Name'] = payload[mainType + 'Name'];\n\n    var condition = {mainType: mainType, query: query};\n    subType && (condition.subType = subType); // subType may be '' by parseClassType;\n\n    var excludeSeriesId = payload.excludeSeriesId;\n    if (excludeSeriesId != null) {\n        excludeSeriesId = createHashMap(normalizeToArray(excludeSeriesId));\n    }\n\n    // If dispatchAction before setOption, do nothing.\n    ecModel && ecModel.eachComponent(condition, function (model) {\n        if (!excludeSeriesId || excludeSeriesId.get(model.id) == null) {\n            callView(ecIns[\n                mainType === 'series' ? '_chartsMap' : '_componentsMap'\n            ][model.__viewId]);\n        }\n    }, ecIns);\n\n    function callView(view) {\n        view && view.__alive && view[method] && view[method](\n            view.__model, ecModel, ecIns._api, payload\n        );\n    }\n}\n\n/**\n * Resize the chart\n * @param {Object} opts\n * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)\n * @param {boolean} [opts.silent=false]\n */\nechartsProto.resize = function (opts) {\n    if (__DEV__) {\n        assert(!this[IN_MAIN_PROCESS], '`resize` should not be called during main process.');\n    }\n\n    this._zr.resize(opts);\n\n    var ecModel = this._model;\n\n    // Resize loading effect\n    this._loadingFX && this._loadingFX.resize();\n\n    if (!ecModel) {\n        return;\n    }\n\n    var optionChanged = ecModel.resetOption('media');\n\n    var silent = opts && opts.silent;\n\n    this[IN_MAIN_PROCESS] = true;\n\n    optionChanged && prepare(this);\n    updateMethods.update.call(this);\n\n    this[IN_MAIN_PROCESS] = false;\n\n    flushPendingActions.call(this, silent);\n\n    triggerUpdatedEvent.call(this, silent);\n};\n\nfunction updateStreamModes(ecIns, ecModel) {\n    var chartsMap = ecIns._chartsMap;\n    var scheduler = ecIns._scheduler;\n    ecModel.eachSeries(function (seriesModel) {\n        scheduler.updateStreamModes(seriesModel, chartsMap[seriesModel.__viewId]);\n    });\n}\n\n/**\n * Show loading effect\n * @param  {string} [name='default']\n * @param  {Object} [cfg]\n */\nechartsProto.showLoading = function (name, cfg) {\n    if (isObject(name)) {\n        cfg = name;\n        name = '';\n    }\n    name = name || 'default';\n\n    this.hideLoading();\n    if (!loadingEffects[name]) {\n        if (__DEV__) {\n            console.warn('Loading effects ' + name + ' not exists.');\n        }\n        return;\n    }\n    var el = loadingEffects[name](this._api, cfg);\n    var zr = this._zr;\n    this._loadingFX = el;\n\n    zr.add(el);\n};\n\n/**\n * Hide loading effect\n */\nechartsProto.hideLoading = function () {\n    this._loadingFX && this._zr.remove(this._loadingFX);\n    this._loadingFX = null;\n};\n\n/**\n * @param {Object} eventObj\n * @return {Object}\n */\nechartsProto.makeActionFromEvent = function (eventObj) {\n    var payload = extend({}, eventObj);\n    payload.type = eventActionMap[eventObj.type];\n    return payload;\n};\n\n/**\n * @pubilc\n * @param {Object} payload\n * @param {string} [payload.type] Action type\n * @param {Object|boolean} [opt] If pass boolean, means opt.silent\n * @param {boolean} [opt.silent=false] Whether trigger events.\n * @param {boolean} [opt.flush=undefined]\n *                  true: Flush immediately, and then pixel in canvas can be fetched\n *                      immediately. Caution: it might affect performance.\n *                  false: Not not flush.\n *                  undefined: Auto decide whether perform flush.\n */\nechartsProto.dispatchAction = function (payload, opt) {\n    if (!isObject(opt)) {\n        opt = {silent: !!opt};\n    }\n\n    if (!actions[payload.type]) {\n        return;\n    }\n\n    // Avoid dispatch action before setOption. Especially in `connect`.\n    if (!this._model) {\n        return;\n    }\n\n    // May dispatchAction in rendering procedure\n    if (this[IN_MAIN_PROCESS]) {\n        this._pendingActions.push(payload);\n        return;\n    }\n\n    doDispatchAction.call(this, payload, opt.silent);\n\n    if (opt.flush) {\n        this._zr.flush(true);\n    }\n    else if (opt.flush !== false && env$1.browser.weChat) {\n        // In WeChat embeded browser, `requestAnimationFrame` and `setInterval`\n        // hang when sliding page (on touch event), which cause that zr does not\n        // refresh util user interaction finished, which is not expected.\n        // But `dispatchAction` may be called too frequently when pan on touch\n        // screen, which impacts performance if do not throttle them.\n        this._throttledZrFlush();\n    }\n\n    flushPendingActions.call(this, opt.silent);\n\n    triggerUpdatedEvent.call(this, opt.silent);\n};\n\nfunction doDispatchAction(payload, silent) {\n    var payloadType = payload.type;\n    var escapeConnect = payload.escapeConnect;\n    var actionWrap = actions[payloadType];\n    var actionInfo = actionWrap.actionInfo;\n\n    var cptType = (actionInfo.update || 'update').split(':');\n    var updateMethod = cptType.pop();\n    cptType = cptType[0] != null && parseClassType(cptType[0]);\n\n    this[IN_MAIN_PROCESS] = true;\n\n    var payloads = [payload];\n    var batched = false;\n    // Batch action\n    if (payload.batch) {\n        batched = true;\n        payloads = map(payload.batch, function (item) {\n            item = defaults(extend({}, item), payload);\n            item.batch = null;\n            return item;\n        });\n    }\n\n    var eventObjBatch = [];\n    var eventObj;\n    var isHighDown = payloadType === 'highlight' || payloadType === 'downplay';\n\n    each(payloads, function (batchItem) {\n        // Action can specify the event by return it.\n        eventObj = actionWrap.action(batchItem, this._model, this._api);\n        // Emit event outside\n        eventObj = eventObj || extend({}, batchItem);\n        // Convert type to eventType\n        eventObj.type = actionInfo.event || eventObj.type;\n        eventObjBatch.push(eventObj);\n\n        // light update does not perform data process, layout and visual.\n        if (isHighDown) {\n            // method, payload, mainType, subType\n            updateDirectly(this, updateMethod, batchItem, 'series');\n        }\n        else if (cptType) {\n            updateDirectly(this, updateMethod, batchItem, cptType.main, cptType.sub);\n        }\n    }, this);\n\n    if (updateMethod !== 'none' && !isHighDown && !cptType) {\n        // Still dirty\n        if (this[OPTION_UPDATED]) {\n            // FIXME Pass payload ?\n            prepare(this);\n            updateMethods.update.call(this, payload);\n            this[OPTION_UPDATED] = false;\n        }\n        else {\n            updateMethods[updateMethod].call(this, payload);\n        }\n    }\n\n    // Follow the rule of action batch\n    if (batched) {\n        eventObj = {\n            type: actionInfo.event || payloadType,\n            escapeConnect: escapeConnect,\n            batch: eventObjBatch\n        };\n    }\n    else {\n        eventObj = eventObjBatch[0];\n    }\n\n    this[IN_MAIN_PROCESS] = false;\n\n    !silent && this._messageCenter.trigger(eventObj.type, eventObj);\n}\n\nfunction flushPendingActions(silent) {\n    var pendingActions = this._pendingActions;\n    while (pendingActions.length) {\n        var payload = pendingActions.shift();\n        doDispatchAction.call(this, payload, silent);\n    }\n}\n\nfunction triggerUpdatedEvent(silent) {\n    !silent && this.trigger('updated');\n}\n\n/**\n * Event `rendered` is triggered when zr\n * rendered. It is useful for realtime\n * snapshot (reflect animation).\n *\n * Event `finished` is triggered when:\n * (1) zrender rendering finished.\n * (2) initial animation finished.\n * (3) progressive rendering finished.\n * (4) no pending action.\n * (5) no delayed setOption needs to be processed.\n */\nfunction bindRenderedEvent(zr, ecIns) {\n    zr.on('rendered', function () {\n\n        ecIns.trigger('rendered');\n\n        // The `finished` event should not be triggered repeatly,\n        // so it should only be triggered when rendering indeed happend\n        // in zrender. (Consider the case that dipatchAction is keep\n        // triggering when mouse move).\n        if (\n            // Although zr is dirty if initial animation is not finished\n            // and this checking is called on frame, we also check\n            // animation finished for robustness.\n            zr.animation.isFinished()\n            && !ecIns[OPTION_UPDATED]\n            && !ecIns._scheduler.unfinished\n            && !ecIns._pendingActions.length\n        ) {\n            ecIns.trigger('finished');\n        }\n    });\n}\n\n/**\n * @param {Object} params\n * @param {number} params.seriesIndex\n * @param {Array|TypedArray} params.data\n */\nechartsProto.appendData = function (params) {\n    var seriesIndex = params.seriesIndex;\n    var ecModel = this.getModel();\n    var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n\n    if (__DEV__) {\n        assert(params.data && seriesModel);\n    }\n\n    seriesModel.appendData(params);\n\n    // Note: `appendData` does not support that update extent of coordinate\n    // system, util some scenario require that. In the expected usage of\n    // `appendData`, the initial extent of coordinate system should better\n    // be fixed by axis `min`/`max` setting or initial data, otherwise if\n    // the extent changed while `appendData`, the location of the painted\n    // graphic elements have to be changed, which make the usage of\n    // `appendData` meaningless.\n\n    this._scheduler.unfinished = true;\n};\n\n/**\n * Register event\n * @method\n */\nechartsProto.on = createRegisterEventWithLowercaseName('on');\nechartsProto.off = createRegisterEventWithLowercaseName('off');\nechartsProto.one = createRegisterEventWithLowercaseName('one');\n\n/**\n * Prepare view instances of charts and components\n * @param  {module:echarts/model/Global} ecModel\n * @private\n */\nfunction prepareView(ecIns, type, ecModel, scheduler) {\n    var isComponent = type === 'component';\n    var viewList = isComponent ? ecIns._componentsViews : ecIns._chartsViews;\n    var viewMap = isComponent ? ecIns._componentsMap : ecIns._chartsMap;\n    var zr = ecIns._zr;\n    var api = ecIns._api;\n\n    for (var i = 0; i < viewList.length; i++) {\n        viewList[i].__alive = false;\n    }\n\n    isComponent\n        ? ecModel.eachComponent(function (componentType, model) {\n            componentType !== 'series' && doPrepare(model);\n        })\n        : ecModel.eachSeries(doPrepare);\n\n    function doPrepare(model) {\n        // Consider: id same and type changed.\n        var viewId = '_ec_' + model.id + '_' + model.type;\n        var view = viewMap[viewId];\n        if (!view) {\n            var classType = parseClassType(model.type);\n            var Clazz = isComponent\n                ? Component$1.getClass(classType.main, classType.sub)\n                : Chart.getClass(classType.sub);\n\n            if (__DEV__) {\n                assert(Clazz, classType.sub + ' does not exist.');\n            }\n\n            view = new Clazz();\n            view.init(ecModel, api);\n            viewMap[viewId] = view;\n            viewList.push(view);\n            zr.add(view.group);\n        }\n\n        model.__viewId = view.__id = viewId;\n        view.__alive = true;\n        view.__model = model;\n        view.group.__ecComponentInfo = {\n            mainType: model.mainType,\n            index: model.componentIndex\n        };\n        !isComponent && scheduler.prepareView(view, model, ecModel, api);\n    }\n\n    for (var i = 0; i < viewList.length;) {\n        var view = viewList[i];\n        if (!view.__alive) {\n            !isComponent && view.renderTask.dispose();\n            zr.remove(view.group);\n            view.dispose(ecModel, api);\n            viewList.splice(i, 1);\n            delete viewMap[view.__id];\n            view.__id = view.group.__ecComponentInfo = null;\n        }\n        else {\n            i++;\n        }\n    }\n}\n\n// /**\n//  * Encode visual infomation from data after data processing\n//  *\n//  * @param {module:echarts/model/Global} ecModel\n//  * @param {object} layout\n//  * @param {boolean} [layoutFilter] `true`: only layout,\n//  *                                 `false`: only not layout,\n//  *                                 `null`/`undefined`: all.\n//  * @param {string} taskBaseTag\n//  * @private\n//  */\n// function startVisualEncoding(ecIns, ecModel, api, payload, layoutFilter) {\n//     each(visualFuncs, function (visual, index) {\n//         var isLayout = visual.isLayout;\n//         if (layoutFilter == null\n//             || (layoutFilter === false && !isLayout)\n//             || (layoutFilter === true && isLayout)\n//         ) {\n//             visual.func(ecModel, api, payload);\n//         }\n//     });\n// }\n\nfunction clearColorPalette(ecModel) {\n    ecModel.clearColorPalette();\n    ecModel.eachSeries(function (seriesModel) {\n        seriesModel.clearColorPalette();\n    });\n}\n\nfunction render(ecIns, ecModel, api, payload) {\n\n    renderComponents(ecIns, ecModel, api, payload);\n\n    each(ecIns._chartsViews, function (chart) {\n        chart.__alive = false;\n    });\n\n    renderSeries(ecIns, ecModel, api, payload);\n\n    // Remove groups of unrendered charts\n    each(ecIns._chartsViews, function (chart) {\n        if (!chart.__alive) {\n            chart.remove(ecModel, api);\n        }\n    });\n}\n\nfunction renderComponents(ecIns, ecModel, api, payload, dirtyList) {\n    each(dirtyList || ecIns._componentsViews, function (componentView) {\n        var componentModel = componentView.__model;\n        componentView.render(componentModel, ecModel, api, payload);\n\n        updateZ(componentModel, componentView);\n    });\n}\n\n/**\n * Render each chart and component\n * @private\n */\nfunction renderSeries(ecIns, ecModel, api, payload, dirtyMap) {\n    // Render all charts\n    var scheduler = ecIns._scheduler;\n    var unfinished;\n    ecModel.eachSeries(function (seriesModel) {\n        var chartView = ecIns._chartsMap[seriesModel.__viewId];\n        chartView.__alive = true;\n\n        var renderTask = chartView.renderTask;\n        scheduler.updatePayload(renderTask, payload);\n\n        if (dirtyMap && dirtyMap.get(seriesModel.uid)) {\n            renderTask.dirty();\n        }\n\n        unfinished |= renderTask.perform(scheduler.getPerformArgs(renderTask));\n\n        chartView.group.silent = !!seriesModel.get('silent');\n\n        updateZ(seriesModel, chartView);\n\n        updateBlend(seriesModel, chartView);\n    });\n    scheduler.unfinished |= unfinished;\n\n    // If use hover layer\n    updateHoverLayerStatus(ecIns._zr, ecModel);\n\n    // Add aria\n    aria(ecIns._zr.dom, ecModel);\n}\n\nfunction performPostUpdateFuncs(ecModel, api) {\n    each(postUpdateFuncs, function (func) {\n        func(ecModel, api);\n    });\n}\n\n\nvar MOUSE_EVENT_NAMES = [\n    'click', 'dblclick', 'mouseover', 'mouseout', 'mousemove',\n    'mousedown', 'mouseup', 'globalout', 'contextmenu'\n];\n\n/**\n * @private\n */\nechartsProto._initEvents = function () {\n    each(MOUSE_EVENT_NAMES, function (eveName) {\n        var handler = function (e) {\n            var ecModel = this.getModel();\n            var el = e.target;\n            var params;\n            var isGlobalOut = eveName === 'globalout';\n\n            // no e.target when 'globalout'.\n            if (isGlobalOut) {\n                params = {};\n            }\n            else if (el && el.dataIndex != null) {\n                var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex);\n                params = dataModel && dataModel.getDataParams(el.dataIndex, el.dataType, el) || {};\n            }\n            // If element has custom eventData of components\n            else if (el && el.eventData) {\n                params = extend({}, el.eventData);\n            }\n\n            // Contract: if params prepared in mouse event,\n            // these properties must be specified:\n            // {\n            //    componentType: string (component main type)\n            //    componentIndex: number\n            // }\n            // Otherwise event query can not work.\n\n            if (params) {\n                var componentType = params.componentType;\n                var componentIndex = params.componentIndex;\n                // Special handling for historic reason: when trigger by\n                // markLine/markPoint/markArea, the componentType is\n                // 'markLine'/'markPoint'/'markArea', but we should better\n                // enable them to be queried by seriesIndex, since their\n                // option is set in each series.\n                if (componentType === 'markLine'\n                    || componentType === 'markPoint'\n                    || componentType === 'markArea'\n                ) {\n                    componentType = 'series';\n                    componentIndex = params.seriesIndex;\n                }\n                var model = componentType && componentIndex != null\n                    && ecModel.getComponent(componentType, componentIndex);\n                var view = model && this[\n                    model.mainType === 'series' ? '_chartsMap' : '_componentsMap'\n                ][model.__viewId];\n\n                if (__DEV__) {\n                    // `event.componentType` and `event[componentTpype + 'Index']` must not\n                    // be missed, otherwise there is no way to distinguish source component.\n                    // See `dataFormat.getDataParams`.\n                    if (!isGlobalOut && !(model && view)) {\n                        console.warn('model or view can not be found by params');\n                    }\n                }\n\n                params.event = e;\n                params.type = eveName;\n\n                this._ecEventProcessor.eventInfo = {\n                    targetEl: el,\n                    packedEvent: params,\n                    model: model,\n                    view: view\n                };\n\n                this.trigger(eveName, params);\n            }\n        };\n        // Consider that some component (like tooltip, brush, ...)\n        // register zr event handler, but user event handler might\n        // do anything, such as call `setOption` or `dispatchAction`,\n        // which probably update any of the content and probably\n        // cause problem if it is called previous other inner handlers.\n        handler.zrEventfulCallAtLast = true;\n        this._zr.on(eveName, handler, this);\n    }, this);\n\n    each(eventActionMap, function (actionType, eventType) {\n        this._messageCenter.on(eventType, function (event) {\n            this.trigger(eventType, event);\n        }, this);\n    }, this);\n};\n\n/**\n * @return {boolean}\n */\nechartsProto.isDisposed = function () {\n    return this._disposed;\n};\n\n/**\n * Clear\n */\nechartsProto.clear = function () {\n    this.setOption({ series: [] }, true);\n};\n\n/**\n * Dispose instance\n */\nechartsProto.dispose = function () {\n    if (this._disposed) {\n        if (__DEV__) {\n            console.warn('Instance ' + this.id + ' has been disposed');\n        }\n        return;\n    }\n    this._disposed = true;\n\n    setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, '');\n\n    var api = this._api;\n    var ecModel = this._model;\n\n    each(this._componentsViews, function (component) {\n        component.dispose(ecModel, api);\n    });\n    each(this._chartsViews, function (chart) {\n        chart.dispose(ecModel, api);\n    });\n\n    // Dispose after all views disposed\n    this._zr.dispose();\n\n    delete instances[this.id];\n};\n\nmixin(ECharts, Eventful);\n\nfunction updateHoverLayerStatus(zr, ecModel) {\n    var storage = zr.storage;\n    var elCount = 0;\n    storage.traverse(function (el) {\n        if (!el.isGroup) {\n            elCount++;\n        }\n    });\n    if (elCount > ecModel.get('hoverLayerThreshold') && !env$1.node) {\n        storage.traverse(function (el) {\n            if (!el.isGroup) {\n                // Don't switch back.\n                el.useHoverLayer = true;\n            }\n        });\n    }\n}\n\n/**\n * Update chart progressive and blend.\n * @param {module:echarts/model/Series|module:echarts/model/Component} model\n * @param {module:echarts/view/Component|module:echarts/view/Chart} view\n */\nfunction updateBlend(seriesModel, chartView) {\n    var blendMode = seriesModel.get('blendMode') || null;\n    if (__DEV__) {\n        if (!env$1.canvasSupported && blendMode && blendMode !== 'source-over') {\n            console.warn('Only canvas support blendMode');\n        }\n    }\n    chartView.group.traverse(function (el) {\n        // FIXME marker and other components\n        if (!el.isGroup) {\n            // Only set if blendMode is changed. In case element is incremental and don't wan't to rerender.\n            if (el.style.blend !== blendMode) {\n                el.setStyle('blend', blendMode);\n            }\n        }\n        if (el.eachPendingDisplayable) {\n            el.eachPendingDisplayable(function (displayable) {\n                displayable.setStyle('blend', blendMode);\n            });\n        }\n    });\n}\n\n/**\n * @param {module:echarts/model/Series|module:echarts/model/Component} model\n * @param {module:echarts/view/Component|module:echarts/view/Chart} view\n */\nfunction updateZ(model, view) {\n    var z = model.get('z');\n    var zlevel = model.get('zlevel');\n    // Set z and zlevel\n    view.group.traverse(function (el) {\n        if (el.type !== 'group') {\n            z != null && (el.z = z);\n            zlevel != null && (el.zlevel = zlevel);\n        }\n    });\n}\n\nfunction createExtensionAPI(ecInstance) {\n    var coordSysMgr = ecInstance._coordSysMgr;\n    return extend(new ExtensionAPI(ecInstance), {\n        // Inject methods\n        getCoordinateSystems: bind(\n            coordSysMgr.getCoordinateSystems, coordSysMgr\n        ),\n        getComponentByElement: function (el) {\n            while (el) {\n                var modelInfo = el.__ecComponentInfo;\n                if (modelInfo != null) {\n                    return ecInstance._model.getComponent(modelInfo.mainType, modelInfo.index);\n                }\n                el = el.parent;\n            }\n        }\n    });\n}\n\n\n/**\n * @class\n * Usage of query:\n * `chart.on('click', query, handler);`\n * The `query` can be:\n * + The component type query string, only `mainType` or `mainType.subType`,\n *   like: 'xAxis', 'series', 'xAxis.category' or 'series.line'.\n * + The component query object, like:\n *   `{seriesIndex: 2}`, `{seriesName: 'xx'}`, `{seriesId: 'some'}`,\n *   `{xAxisIndex: 2}`, `{xAxisName: 'xx'}`, `{xAxisId: 'some'}`.\n * + The data query object, like:\n *   `{dataIndex: 123}`, `{dataType: 'link'}`, `{name: 'some'}`.\n * + The other query object (cmponent customized query), like:\n *   `{element: 'some'}` (only available in custom series).\n *\n * Caveat: If a prop in the `query` object is `null/undefined`, it is the\n * same as there is no such prop in the `query` object.\n */\nfunction EventProcessor() {\n    // These info required: targetEl, packedEvent, model, view\n    this.eventInfo;\n}\nEventProcessor.prototype = {\n    constructor: EventProcessor,\n\n    normalizeQuery: function (query) {\n        var cptQuery = {};\n        var dataQuery = {};\n        var otherQuery = {};\n\n        // `query` is `mainType` or `mainType.subType` of component.\n        if (isString(query)) {\n            var condCptType = parseClassType(query);\n            // `.main` and `.sub` may be ''.\n            cptQuery.mainType = condCptType.main || null;\n            cptQuery.subType = condCptType.sub || null;\n        }\n        // `query` is an object, convert to {mainType, index, name, id}.\n        else {\n            // `xxxIndex`, `xxxName`, `xxxId`, `name`, `dataIndex`, `dataType` is reserved,\n            // can not be used in `compomentModel.filterForExposedEvent`.\n            var suffixes = ['Index', 'Name', 'Id'];\n            var dataKeys = {name: 1, dataIndex: 1, dataType: 1};\n            each$1(query, function (val, key) {\n                var reserved = false;\n                for (var i = 0; i < suffixes.length; i++) {\n                    var propSuffix = suffixes[i];\n                    var suffixPos = key.lastIndexOf(propSuffix);\n                    if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) {\n                        var mainType = key.slice(0, suffixPos);\n                        // Consider `dataIndex`.\n                        if (mainType !== 'data') {\n                            cptQuery.mainType = mainType;\n                            cptQuery[propSuffix.toLowerCase()] = val;\n                            reserved = true;\n                        }\n                    }\n                }\n                if (dataKeys.hasOwnProperty(key)) {\n                    dataQuery[key] = val;\n                    reserved = true;\n                }\n                if (!reserved) {\n                    otherQuery[key] = val;\n                }\n            });\n        }\n\n        return {\n            cptQuery: cptQuery,\n            dataQuery: dataQuery,\n            otherQuery: otherQuery\n        };\n    },\n\n    filter: function (eventType, query, args) {\n        // They should be assigned before each trigger call.\n        var eventInfo = this.eventInfo;\n\n        if (!eventInfo) {\n            return true;\n        }\n\n        var targetEl = eventInfo.targetEl;\n        var packedEvent = eventInfo.packedEvent;\n        var model = eventInfo.model;\n        var view = eventInfo.view;\n\n        // For event like 'globalout'.\n        if (!model || !view) {\n            return true;\n        }\n\n        var cptQuery = query.cptQuery;\n        var dataQuery = query.dataQuery;\n\n        return check(cptQuery, model, 'mainType')\n            && check(cptQuery, model, 'subType')\n            && check(cptQuery, model, 'index', 'componentIndex')\n            && check(cptQuery, model, 'name')\n            && check(cptQuery, model, 'id')\n            && check(dataQuery, packedEvent, 'name')\n            && check(dataQuery, packedEvent, 'dataIndex')\n            && check(dataQuery, packedEvent, 'dataType')\n            && (!view.filterForExposedEvent || view.filterForExposedEvent(\n                eventType, query.otherQuery, targetEl, packedEvent\n            ));\n\n        function check(query, host, prop, propOnHost) {\n            return query[prop] == null || host[propOnHost || prop] === query[prop];\n        }\n    },\n\n    afterTrigger: function () {\n        // Make sure the eventInfo wont be used in next trigger.\n        this.eventInfo = null;\n    }\n};\n\n\n/**\n * @type {Object} key: actionType.\n * @inner\n */\nvar actions = {};\n\n/**\n * Map eventType to actionType\n * @type {Object}\n */\nvar eventActionMap = {};\n\n/**\n * Data processor functions of each stage\n * @type {Array.<Object.<string, Function>>}\n * @inner\n */\nvar dataProcessorFuncs = [];\n\n/**\n * @type {Array.<Function>}\n * @inner\n */\nvar optionPreprocessorFuncs = [];\n\n/**\n * @type {Array.<Function>}\n * @inner\n */\nvar postUpdateFuncs = [];\n\n/**\n * Visual encoding functions of each stage\n * @type {Array.<Object.<string, Function>>}\n */\nvar visualFuncs = [];\n\n/**\n * Theme storage\n * @type {Object.<key, Object>}\n */\nvar themeStorage = {};\n/**\n * Loading effects\n */\nvar loadingEffects = {};\n\nvar instances = {};\nvar connectedGroups = {};\n\nvar idBase = new Date() - 0;\nvar groupIdBase = new Date() - 0;\nvar DOM_ATTRIBUTE_KEY = '_echarts_instance_';\n\nfunction enableConnect(chart) {\n    var STATUS_PENDING = 0;\n    var STATUS_UPDATING = 1;\n    var STATUS_UPDATED = 2;\n    var STATUS_KEY = '__connectUpdateStatus';\n\n    function updateConnectedChartsStatus(charts, status) {\n        for (var i = 0; i < charts.length; i++) {\n            var otherChart = charts[i];\n            otherChart[STATUS_KEY] = status;\n        }\n    }\n\n    each(eventActionMap, function (actionType, eventType) {\n        chart._messageCenter.on(eventType, function (event) {\n            if (connectedGroups[chart.group] && chart[STATUS_KEY] !== STATUS_PENDING) {\n                if (event && event.escapeConnect) {\n                    return;\n                }\n\n                var action = chart.makeActionFromEvent(event);\n                var otherCharts = [];\n\n                each(instances, function (otherChart) {\n                    if (otherChart !== chart && otherChart.group === chart.group) {\n                        otherCharts.push(otherChart);\n                    }\n                });\n\n                updateConnectedChartsStatus(otherCharts, STATUS_PENDING);\n                each(otherCharts, function (otherChart) {\n                    if (otherChart[STATUS_KEY] !== STATUS_UPDATING) {\n                        otherChart.dispatchAction(action);\n                    }\n                });\n                updateConnectedChartsStatus(otherCharts, STATUS_UPDATED);\n            }\n        });\n    });\n}\n\n/**\n * @param {HTMLElement} dom\n * @param {Object} [theme]\n * @param {Object} opts\n * @param {number} [opts.devicePixelRatio] Use window.devicePixelRatio by default\n * @param {string} [opts.renderer] Currently only 'canvas' is supported.\n * @param {number} [opts.width] Use clientWidth of the input `dom` by default.\n *                              Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Use clientHeight of the input `dom` by default.\n *                               Can be 'auto' (the same as null/undefined)\n */\nfunction init(dom, theme$$1, opts) {\n    if (__DEV__) {\n        // Check version\n        if ((version$1.replace('.', '') - 0) < (dependencies.zrender.replace('.', '') - 0)) {\n            throw new Error(\n                'zrender/src ' + version$1\n                + ' is too old for ECharts ' + version\n                + '. Current version need ZRender '\n                + dependencies.zrender + '+'\n            );\n        }\n\n        if (!dom) {\n            throw new Error('Initialize failed: invalid dom.');\n        }\n    }\n\n    var existInstance = getInstanceByDom(dom);\n    if (existInstance) {\n        if (__DEV__) {\n            console.warn('There is a chart instance already initialized on the dom.');\n        }\n        return existInstance;\n    }\n\n    if (__DEV__) {\n        if (isDom(dom)\n            && dom.nodeName.toUpperCase() !== 'CANVAS'\n            && (\n                (!dom.clientWidth && (!opts || opts.width == null))\n                || (!dom.clientHeight && (!opts || opts.height == null))\n            )\n        ) {\n            console.warn('Can\\'t get dom width or height');\n        }\n    }\n\n    var chart = new ECharts(dom, theme$$1, opts);\n    chart.id = 'ec_' + idBase++;\n    instances[chart.id] = chart;\n\n    setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id);\n\n    enableConnect(chart);\n\n    return chart;\n}\n\n/**\n * @return {string|Array.<module:echarts~ECharts>} groupId\n */\nfunction connect(groupId) {\n    // Is array of charts\n    if (isArray(groupId)) {\n        var charts = groupId;\n        groupId = null;\n        // If any chart has group\n        each(charts, function (chart) {\n            if (chart.group != null) {\n                groupId = chart.group;\n            }\n        });\n        groupId = groupId || ('g_' + groupIdBase++);\n        each(charts, function (chart) {\n            chart.group = groupId;\n        });\n    }\n    connectedGroups[groupId] = true;\n    return groupId;\n}\n\n/**\n * @DEPRECATED\n * @return {string} groupId\n */\nfunction disConnect(groupId) {\n    connectedGroups[groupId] = false;\n}\n\n/**\n * @return {string} groupId\n */\nvar disconnect = disConnect;\n\n/**\n * Dispose a chart instance\n * @param  {module:echarts~ECharts|HTMLDomElement|string} chart\n */\nfunction dispose(chart) {\n    if (typeof chart === 'string') {\n        chart = instances[chart];\n    }\n    else if (!(chart instanceof ECharts)) {\n        // Try to treat as dom\n        chart = getInstanceByDom(chart);\n    }\n    if ((chart instanceof ECharts) && !chart.isDisposed()) {\n        chart.dispose();\n    }\n}\n\n/**\n * @param  {HTMLElement} dom\n * @return {echarts~ECharts}\n */\nfunction getInstanceByDom(dom) {\n    return instances[getAttribute(dom, DOM_ATTRIBUTE_KEY)];\n}\n\n/**\n * @param {string} key\n * @return {echarts~ECharts}\n */\nfunction getInstanceById(key) {\n    return instances[key];\n}\n\n/**\n * Register theme\n */\nfunction registerTheme(name, theme$$1) {\n    themeStorage[name] = theme$$1;\n}\n\n/**\n * Register option preprocessor\n * @param {Function} preprocessorFunc\n */\nfunction registerPreprocessor(preprocessorFunc) {\n    optionPreprocessorFuncs.push(preprocessorFunc);\n}\n\n/**\n * @param {number} [priority=1000]\n * @param {Object|Function} processor\n */\nfunction registerProcessor(priority, processor) {\n    normalizeRegister(dataProcessorFuncs, priority, processor, PRIORITY_PROCESSOR_FILTER);\n}\n\n/**\n * Register postUpdater\n * @param {Function} postUpdateFunc\n */\nfunction registerPostUpdate(postUpdateFunc) {\n    postUpdateFuncs.push(postUpdateFunc);\n}\n\n/**\n * Usage:\n * registerAction('someAction', 'someEvent', function () { ... });\n * registerAction('someAction', function () { ... });\n * registerAction(\n *     {type: 'someAction', event: 'someEvent', update: 'updateView'},\n *     function () { ... }\n * );\n *\n * @param {(string|Object)} actionInfo\n * @param {string} actionInfo.type\n * @param {string} [actionInfo.event]\n * @param {string} [actionInfo.update]\n * @param {string} [eventName]\n * @param {Function} action\n */\nfunction registerAction(actionInfo, eventName, action) {\n    if (typeof eventName === 'function') {\n        action = eventName;\n        eventName = '';\n    }\n    var actionType = isObject(actionInfo)\n        ? actionInfo.type\n        : ([actionInfo, actionInfo = {\n            event: eventName\n        }][0]);\n\n    // Event name is all lowercase\n    actionInfo.event = (actionInfo.event || actionType).toLowerCase();\n    eventName = actionInfo.event;\n\n    // Validate action type and event name.\n    assert(ACTION_REG.test(actionType) && ACTION_REG.test(eventName));\n\n    if (!actions[actionType]) {\n        actions[actionType] = {action: action, actionInfo: actionInfo};\n    }\n    eventActionMap[eventName] = actionType;\n}\n\n/**\n * @param {string} type\n * @param {*} CoordinateSystem\n */\nfunction registerCoordinateSystem(type, CoordinateSystem$$1) {\n    CoordinateSystemManager.register(type, CoordinateSystem$$1);\n}\n\n/**\n * Get dimensions of specified coordinate system.\n * @param {string} type\n * @return {Array.<string|Object>}\n */\nfunction getCoordinateSystemDimensions(type) {\n    var coordSysCreator = CoordinateSystemManager.get(type);\n    if (coordSysCreator) {\n        return coordSysCreator.getDimensionsInfo\n                ? coordSysCreator.getDimensionsInfo()\n                : coordSysCreator.dimensions.slice();\n    }\n}\n\n/**\n * Layout is a special stage of visual encoding\n * Most visual encoding like color are common for different chart\n * But each chart has it's own layout algorithm\n *\n * @param {number} [priority=1000]\n * @param {Function} layoutTask\n */\nfunction registerLayout(priority, layoutTask) {\n    normalizeRegister(visualFuncs, priority, layoutTask, PRIORITY_VISUAL_LAYOUT, 'layout');\n}\n\n/**\n * @param {number} [priority=3000]\n * @param {module:echarts/stream/Task} visualTask\n */\nfunction registerVisual(priority, visualTask) {\n    normalizeRegister(visualFuncs, priority, visualTask, PRIORITY_VISUAL_CHART, 'visual');\n}\n\n/**\n * @param {Object|Function} fn: {seriesType, createOnAllSeries, performRawSeries, reset}\n */\nfunction normalizeRegister(targetList, priority, fn, defaultPriority, visualType) {\n    if (isFunction(priority) || isObject(priority)) {\n        fn = priority;\n        priority = defaultPriority;\n    }\n\n    if (__DEV__) {\n        if (isNaN(priority) || priority == null) {\n            throw new Error('Illegal priority');\n        }\n        // Check duplicate\n        each(targetList, function (wrap) {\n            assert(wrap.__raw !== fn);\n        });\n    }\n\n    var stageHandler = Scheduler.wrapStageHandler(fn, visualType);\n\n    stageHandler.__prio = priority;\n    stageHandler.__raw = fn;\n    targetList.push(stageHandler);\n\n    return stageHandler;\n}\n\n/**\n * @param {string} name\n */\nfunction registerLoading(name, loadingFx) {\n    loadingEffects[name] = loadingFx;\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendComponentModel(opts/*, superClass*/) {\n    // var Clazz = ComponentModel;\n    // if (superClass) {\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentModel.getClass(classType.main, classType.sub, true);\n    // }\n    return ComponentModel.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendComponentView(opts/*, superClass*/) {\n    // var Clazz = ComponentView;\n    // if (superClass) {\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentView.getClass(classType.main, classType.sub, true);\n    // }\n    return Component$1.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendSeriesModel(opts/*, superClass*/) {\n    // var Clazz = SeriesModel;\n    // if (superClass) {\n    //     superClass = 'series.' + superClass.replace('series.', '');\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentModel.getClass(classType.main, classType.sub, true);\n    // }\n    return SeriesModel.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendChartView(opts/*, superClass*/) {\n    // var Clazz = ChartView;\n    // if (superClass) {\n    //     superClass = superClass.replace('series.', '');\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ChartView.getClass(classType.main, true);\n    // }\n    return Chart.extend(opts);\n}\n\n/**\n * ZRender need a canvas context to do measureText.\n * But in node environment canvas may be created by node-canvas.\n * So we need to specify how to create a canvas instead of using document.createElement('canvas')\n *\n * Be careful of using it in the browser.\n *\n * @param {Function} creator\n * @example\n *     var Canvas = require('canvas');\n *     var echarts = require('echarts');\n *     echarts.setCanvasCreator(function () {\n *         // Small size is enough.\n *         return new Canvas(32, 32);\n *     });\n */\nfunction setCanvasCreator(creator) {\n    $override('createCanvas', creator);\n}\n\n/**\n * @param {string} mapName\n * @param {Array.<Object>|Object|string} geoJson\n * @param {Object} [specialAreas]\n *\n * @example GeoJSON\n *     $.get('USA.json', function (geoJson) {\n *         echarts.registerMap('USA', geoJson);\n *         // Or\n *         echarts.registerMap('USA', {\n *             geoJson: geoJson,\n *             specialAreas: {}\n *         })\n *     });\n *\n *     $.get('airport.svg', function (svg) {\n *         echarts.registerMap('airport', {\n *             svg: svg\n *         }\n *     });\n *\n *     echarts.registerMap('eu', [\n *         {svg: eu-topographic.svg},\n *         {geoJSON: eu.json}\n *     ])\n */\nfunction registerMap(mapName, geoJson, specialAreas) {\n    mapDataStorage.registerMap(mapName, geoJson, specialAreas);\n}\n\n/**\n * @param {string} mapName\n * @return {Object}\n */\nfunction getMap(mapName) {\n    // For backward compatibility, only return the first one.\n    var records = mapDataStorage.retrieveMap(mapName);\n    return records && records[0] && {\n        geoJson: records[0].geoJSON,\n        specialAreas: records[0].specialAreas\n    };\n}\n\nregisterVisual(PRIORITY_VISUAL_GLOBAL, seriesColor);\nregisterPreprocessor(backwardCompat);\nregisterProcessor(PRIORITY_PROCESSOR_STATISTIC, dataStack);\nregisterLoading('default', loadingDefault);\n\n// Default actions\n\nregisterAction({\n    type: 'highlight',\n    event: 'highlight',\n    update: 'highlight'\n}, noop);\n\nregisterAction({\n    type: 'downplay',\n    event: 'downplay',\n    update: 'downplay'\n}, noop);\n\n// Default theme\nregisterTheme('light', lightTheme);\nregisterTheme('dark', theme);\n\n// For backward compatibility, where the namespace `dataTool` will\n// be mounted on `echarts` is the extension `dataTool` is imported.\nvar dataTool = {};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction defaultKeyGetter(item) {\n    return item;\n}\n\n/**\n * @param {Array} oldArr\n * @param {Array} newArr\n * @param {Function} oldKeyGetter\n * @param {Function} newKeyGetter\n * @param {Object} [context] Can be visited by this.context in callback.\n */\nfunction DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter, context) {\n    this._old = oldArr;\n    this._new = newArr;\n\n    this._oldKeyGetter = oldKeyGetter || defaultKeyGetter;\n    this._newKeyGetter = newKeyGetter || defaultKeyGetter;\n\n    this.context = context;\n}\n\nDataDiffer.prototype = {\n\n    constructor: DataDiffer,\n\n    /**\n     * Callback function when add a data\n     */\n    add: function (func) {\n        this._add = func;\n        return this;\n    },\n\n    /**\n     * Callback function when update a data\n     */\n    update: function (func) {\n        this._update = func;\n        return this;\n    },\n\n    /**\n     * Callback function when remove a data\n     */\n    remove: function (func) {\n        this._remove = func;\n        return this;\n    },\n\n    execute: function () {\n        var oldArr = this._old;\n        var newArr = this._new;\n\n        var oldDataIndexMap = {};\n        var newDataIndexMap = {};\n        var oldDataKeyArr = [];\n        var newDataKeyArr = [];\n        var i;\n\n        initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, '_oldKeyGetter', this);\n        initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter', this);\n\n        // Travel by inverted order to make sure order consistency\n        // when duplicate keys exists (consider newDataIndex.pop() below).\n        // For performance consideration, these code below do not look neat.\n        for (i = 0; i < oldArr.length; i++) {\n            var key = oldDataKeyArr[i];\n            var idx = newDataIndexMap[key];\n\n            // idx can never be empty array here. see 'set null' logic below.\n            if (idx != null) {\n                // Consider there is duplicate key (for example, use dataItem.name as key).\n                // We should make sure every item in newArr and oldArr can be visited.\n                var len = idx.length;\n                if (len) {\n                    len === 1 && (newDataIndexMap[key] = null);\n                    idx = idx.unshift();\n                }\n                else {\n                    newDataIndexMap[key] = null;\n                }\n                this._update && this._update(idx, i);\n            }\n            else {\n                this._remove && this._remove(i);\n            }\n        }\n\n        for (var i = 0; i < newDataKeyArr.length; i++) {\n            var key = newDataKeyArr[i];\n            if (newDataIndexMap.hasOwnProperty(key)) {\n                var idx = newDataIndexMap[key];\n                if (idx == null) {\n                    continue;\n                }\n                // idx can never be empty array here. see 'set null' logic above.\n                if (!idx.length) {\n                    this._add && this._add(idx);\n                }\n                else {\n                    for (var j = 0, len = idx.length; j < len; j++) {\n                        this._add && this._add(idx[j]);\n                    }\n                }\n            }\n        }\n    }\n};\n\nfunction initIndexMap(arr, map, keyArr, keyGetterName, dataDiffer) {\n    for (var i = 0; i < arr.length; i++) {\n        // Add prefix to avoid conflict with Object.prototype.\n        var key = '_ec_' + dataDiffer[keyGetterName](arr[i], i);\n        var existence = map[key];\n        if (existence == null) {\n            keyArr.push(key);\n            map[key] = i;\n        }\n        else {\n            if (!existence.length) {\n                map[key] = existence = [existence];\n            }\n            existence.push(i);\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar OTHER_DIMENSIONS = createHashMap([\n    'tooltip', 'label', 'itemName', 'itemId', 'seriesName'\n]);\n\nfunction summarizeDimensions(data) {\n    var summary = {};\n    var encode = summary.encode = {};\n    var notExtraCoordDimMap = createHashMap();\n    var defaultedLabel = [];\n    var defaultedTooltip = [];\n\n    each$1(data.dimensions, function (dimName) {\n        var dimItem = data.getDimensionInfo(dimName);\n\n        var coordDim = dimItem.coordDim;\n        if (coordDim) {\n            if (__DEV__) {\n                assert$1(OTHER_DIMENSIONS.get(coordDim) == null);\n            }\n            var coordDimArr = encode[coordDim];\n            if (!encode.hasOwnProperty(coordDim)) {\n                coordDimArr = encode[coordDim] = [];\n            }\n            coordDimArr[dimItem.coordDimIndex] = dimName;\n\n            if (!dimItem.isExtraCoord) {\n                notExtraCoordDimMap.set(coordDim, 1);\n\n                // Use the last coord dim (and label friendly) as default label,\n                // because when dataset is used, it is hard to guess which dimension\n                // can be value dimension. If both show x, y on label is not look good,\n                // and conventionally y axis is focused more.\n                if (mayLabelDimType(dimItem.type)) {\n                    defaultedLabel[0] = dimName;\n                }\n            }\n            if (dimItem.defaultTooltip) {\n                defaultedTooltip.push(dimName);\n            }\n        }\n\n        OTHER_DIMENSIONS.each(function (v, otherDim) {\n            var otherDimArr = encode[otherDim];\n            if (!encode.hasOwnProperty(otherDim)) {\n                otherDimArr = encode[otherDim] = [];\n            }\n\n            var dimIndex = dimItem.otherDims[otherDim];\n            if (dimIndex != null && dimIndex !== false) {\n                otherDimArr[dimIndex] = dimItem.name;\n            }\n        });\n    });\n\n    var dataDimsOnCoord = [];\n    var encodeFirstDimNotExtra = {};\n\n    notExtraCoordDimMap.each(function (v, coordDim) {\n        var dimArr = encode[coordDim];\n        // ??? FIXME extra coord should not be set in dataDimsOnCoord.\n        // But should fix the case that radar axes: simplify the logic\n        // of `completeDimension`, remove `extraPrefix`.\n        encodeFirstDimNotExtra[coordDim] = dimArr[0];\n        // Not necessary to remove duplicate, because a data\n        // dim canot on more than one coordDim.\n        dataDimsOnCoord = dataDimsOnCoord.concat(dimArr);\n    });\n\n    summary.dataDimsOnCoord = dataDimsOnCoord;\n    summary.encodeFirstDimNotExtra = encodeFirstDimNotExtra;\n\n    var encodeLabel = encode.label;\n    // FIXME `encode.label` is not recommanded, because formatter can not be set\n    // in this way. Use label.formatter instead. May be remove this approach someday.\n    if (encodeLabel && encodeLabel.length) {\n        defaultedLabel = encodeLabel.slice();\n    }\n\n    var encodeTooltip = encode.tooltip;\n    if (encodeTooltip && encodeTooltip.length) {\n        defaultedTooltip = encodeTooltip.slice();\n    }\n    else if (!defaultedTooltip.length) {\n        defaultedTooltip = defaultedLabel.slice();\n    }\n\n    encode.defaultedLabel = defaultedLabel;\n    encode.defaultedTooltip = defaultedTooltip;\n\n    return summary;\n}\n\nfunction getDimensionTypeByAxis(axisType) {\n    return axisType === 'category'\n        ? 'ordinal'\n        : axisType === 'time'\n        ? 'time'\n        : 'float';\n}\n\nfunction mayLabelDimType(dimType) {\n    // In most cases, ordinal and time do not suitable for label.\n    // Ordinal info can be displayed on axis. Time is too long.\n    return !(dimType === 'ordinal' || dimType === 'time');\n}\n\n// function findTheLastDimMayLabel(data) {\n//     // Get last value dim\n//     var dimensions = data.dimensions.slice();\n//     var valueType;\n//     var valueDim;\n//     while (dimensions.length && (\n//         valueDim = dimensions.pop(),\n//         valueType = data.getDimensionInfo(valueDim).type,\n//         valueType === 'ordinal' || valueType === 'time'\n//     )) {} // jshint ignore:line\n//     return valueDim;\n// }\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float64Array, Int32Array, Uint32Array, Uint16Array */\n\n/**\n * List for data storage\n * @module echarts/data/List\n */\n\nvar isObject$4 = isObject$1;\n\nvar UNDEFINED = 'undefined';\nvar INDEX_NOT_FOUND = -1;\n\n// Use prefix to avoid index to be the same as otherIdList[idx],\n// which will cause weird udpate animation.\nvar ID_PREFIX = 'e\\0\\0';\n\nvar dataCtors = {\n    'float': typeof Float64Array === UNDEFINED\n        ? Array : Float64Array,\n    'int': typeof Int32Array === UNDEFINED\n        ? Array : Int32Array,\n    // Ordinal data type can be string or int\n    'ordinal': Array,\n    'number': Array,\n    'time': Array\n};\n\n// Caution: MUST not use `new CtorUint32Array(arr, 0, len)`, because the Ctor of array is\n// different from the Ctor of typed array.\nvar CtorUint32Array = typeof Uint32Array === UNDEFINED ? Array : Uint32Array;\nvar CtorInt32Array = typeof Int32Array === UNDEFINED ? Array : Int32Array;\nvar CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array;\n\nfunction getIndicesCtor(list) {\n    // The possible max value in this._indicies is always this._rawCount despite of filtering.\n    return list._rawCount > 65535 ? CtorUint32Array : CtorUint16Array;\n}\n\nfunction cloneChunk(originalChunk) {\n    var Ctor = originalChunk.constructor;\n    // Only shallow clone is enough when Array.\n    return Ctor === Array ? originalChunk.slice() : new Ctor(originalChunk);\n}\n\nvar TRANSFERABLE_PROPERTIES = [\n    'hasItemOption', '_nameList', '_idList', '_invertedIndicesMap',\n    '_rawData', '_chunkSize', '_chunkCount', '_dimValueGetter',\n    '_count', '_rawCount', '_nameDimIdx', '_idDimIdx'\n];\nvar CLONE_PROPERTIES = [\n    '_extent', '_approximateExtent', '_rawExtent'\n];\n\nfunction transferProperties(target, source) {\n    each$1(TRANSFERABLE_PROPERTIES.concat(source.__wrappedMethods || []), function (propName) {\n        if (source.hasOwnProperty(propName)) {\n            target[propName] = source[propName];\n        }\n    });\n\n    target.__wrappedMethods = source.__wrappedMethods;\n\n    each$1(CLONE_PROPERTIES, function (propName) {\n        target[propName] = clone(source[propName]);\n    });\n\n    target._calculationInfo = extend(source._calculationInfo);\n}\n\n\n\n\n\n/**\n * @constructor\n * @alias module:echarts/data/List\n *\n * @param {Array.<string|Object>} dimensions\n *      For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...].\n *      Dimensions should be concrete names like x, y, z, lng, lat, angle, radius\n *      Spetial fields: {\n *          ordinalMeta: <module:echarts/data/OrdinalMeta>\n *          createInvertedIndices: <boolean>\n *      }\n * @param {module:echarts/model/Model} hostModel\n */\nvar List = function (dimensions, hostModel) {\n\n    dimensions = dimensions || ['x', 'y'];\n\n    var dimensionInfos = {};\n    var dimensionNames = [];\n    var invertedIndicesMap = {};\n\n    for (var i = 0; i < dimensions.length; i++) {\n        // Use the original dimensions[i], where other flag props may exists.\n        var dimensionInfo = dimensions[i];\n\n        if (isString(dimensionInfo)) {\n            dimensionInfo = {name: dimensionInfo};\n        }\n\n        var dimensionName = dimensionInfo.name;\n        dimensionInfo.type = dimensionInfo.type || 'float';\n        if (!dimensionInfo.coordDim) {\n            dimensionInfo.coordDim = dimensionName;\n            dimensionInfo.coordDimIndex = 0;\n        }\n\n        dimensionInfo.otherDims = dimensionInfo.otherDims || {};\n        dimensionNames.push(dimensionName);\n        dimensionInfos[dimensionName] = dimensionInfo;\n\n        dimensionInfo.index = i;\n\n        if (dimensionInfo.createInvertedIndices) {\n            invertedIndicesMap[dimensionName] = [];\n        }\n    }\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    this.dimensions = dimensionNames;\n\n    /**\n     * Infomation of each data dimension, like data type.\n     * @type {Object}\n     */\n    this._dimensionInfos = dimensionInfos;\n\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.hostModel = hostModel;\n\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.dataType;\n\n    /**\n     * Indices stores the indices of data subset after filtered.\n     * This data subset will be used in chart.\n     * @type {Array.<number>}\n     * @readOnly\n     */\n    this._indices = null;\n\n    this._count = 0;\n    this._rawCount = 0;\n\n    /**\n     * Data storage\n     * @type {Object.<key, Array.<TypedArray|Array>>}\n     * @private\n     */\n    this._storage = {};\n\n    /**\n     * @type {Array.<string>}\n     */\n    this._nameList = [];\n    /**\n     * @type {Array.<string>}\n     */\n    this._idList = [];\n\n    /**\n     * Models of data option is stored sparse for optimizing memory cost\n     * @type {Array.<module:echarts/model/Model>}\n     * @private\n     */\n    this._optionModels = [];\n\n    /**\n     * Global visual properties after visual coding\n     * @type {Object}\n     * @private\n     */\n    this._visual = {};\n\n    /**\n     * Globel layout properties.\n     * @type {Object}\n     * @private\n     */\n    this._layout = {};\n\n    /**\n     * Item visual properties after visual coding\n     * @type {Array.<Object>}\n     * @private\n     */\n    this._itemVisuals = [];\n\n    /**\n     * Key: visual type, Value: boolean\n     * @type {Object}\n     * @readOnly\n     */\n    this.hasItemVisual = {};\n\n    /**\n     * Item layout properties after layout\n     * @type {Array.<Object>}\n     * @private\n     */\n    this._itemLayouts = [];\n\n    /**\n     * Graphic elemnents\n     * @type {Array.<module:zrender/Element>}\n     * @private\n     */\n    this._graphicEls = [];\n\n    /**\n     * Max size of each chunk.\n     * @type {number}\n     * @private\n     */\n    this._chunkSize = 1e5;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    this._chunkCount = 0;\n\n    /**\n     * @type {Array.<Array|Object>}\n     * @private\n     */\n    this._rawData;\n\n    /**\n     * Raw extent will not be cloned, but only transfered.\n     * It will not be calculated util needed.\n     * key: dim,\n     * value: {end: number, extent: Array.<number>}\n     * @type {Object}\n     * @private\n     */\n    this._rawExtent = {};\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._extent = {};\n\n    /**\n     * key: dim\n     * value: extent\n     * @type {Object}\n     * @private\n     */\n    this._approximateExtent = {};\n\n    /**\n     * Cache summary info for fast visit. See \"dimensionHelper\".\n     * @type {Object}\n     * @private\n     */\n    this._dimensionsSummary = summarizeDimensions(this);\n\n    /**\n     * @type {Object.<Array|TypedArray>}\n     * @private\n     */\n    this._invertedIndicesMap = invertedIndicesMap;\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._calculationInfo = {};\n};\n\nvar listProto = List.prototype;\n\nlistProto.type = 'list';\n\n/**\n * If each data item has it's own option\n * @type {boolean}\n */\nlistProto.hasItemOption = true;\n\n/**\n * Get dimension name\n * @param {string|number} dim\n *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius\n *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'\n * @return {string} Concrete dim name.\n */\nlistProto.getDimension = function (dim) {\n    if (!isNaN(dim)) {\n        dim = this.dimensions[dim] || dim;\n    }\n    return dim;\n};\n\n/**\n * Get type and calculation info of particular dimension\n * @param {string|number} dim\n *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius\n *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'\n */\nlistProto.getDimensionInfo = function (dim) {\n    // Do not clone, because there may be categories in dimInfo.\n    return this._dimensionInfos[this.getDimension(dim)];\n};\n\n/**\n * @return {Array.<string>} concrete dimension name list on coord.\n */\nlistProto.getDimensionsOnCoord = function () {\n    return this._dimensionsSummary.dataDimsOnCoord.slice();\n};\n\n/**\n * @param {string} coordDim\n * @param {number} [idx] A coordDim may map to more than one data dim.\n *        If idx is `true`, return a array of all mapped dims.\n *        If idx is not specified, return the first dim not extra.\n * @return {string|Array.<string>} concrete data dim.\n *        If idx is number, and not found, return null/undefined.\n *        If idx is `true`, and not found, return empty array (always return array).\n */\nlistProto.mapDimension = function (coordDim, idx) {\n    var dimensionsSummary = this._dimensionsSummary;\n\n    if (idx == null) {\n        return dimensionsSummary.encodeFirstDimNotExtra[coordDim];\n    }\n\n    var dims = dimensionsSummary.encode[coordDim];\n    return idx === true\n        // always return array if idx is `true`\n        ? (dims || []).slice()\n        : (dims && dims[idx]);\n};\n\n/**\n * Initialize from data\n * @param {Array.<Object|number|Array>} data source or data or data provider.\n * @param {Array.<string>} [nameLIst] The name of a datum is used on data diff and\n *        defualt label/tooltip.\n *        A name can be specified in encode.itemName,\n *        or dataItem.name (only for series option data),\n *        or provided in nameList from outside.\n * @param {Function} [dimValueGetter] (dataItem, dimName, dataIndex, dimIndex) => number\n */\nlistProto.initData = function (data, nameList, dimValueGetter) {\n\n    var notProvider = Source.isInstance(data) || isArrayLike(data);\n    if (notProvider) {\n        data = new DefaultDataProvider(data, this.dimensions.length);\n    }\n\n    if (__DEV__) {\n        if (!notProvider && (typeof data.getItem !== 'function' || typeof data.count !== 'function')) {\n            throw new Error('Inavlid data provider.');\n        }\n    }\n\n    this._rawData = data;\n\n    // Clear\n    this._storage = {};\n    this._indices = null;\n\n    this._nameList = nameList || [];\n\n    this._idList = [];\n\n    this._nameRepeatCount = {};\n\n    if (!dimValueGetter) {\n        this.hasItemOption = false;\n    }\n\n    /**\n     * @readOnly\n     */\n    this.defaultDimValueGetter = defaultDimValueGetters[\n        this._rawData.getSource().sourceFormat\n    ];\n    // Default dim value getter\n    this._dimValueGetter = dimValueGetter = dimValueGetter\n        || this.defaultDimValueGetter;\n    this._dimValueGetterArrayRows = defaultDimValueGetters.arrayRows;\n\n    // Reset raw extent.\n    this._rawExtent = {};\n\n    this._initDataFromProvider(0, data.count());\n\n    // If data has no item option.\n    if (data.pure) {\n        this.hasItemOption = false;\n    }\n};\n\nlistProto.getProvider = function () {\n    return this._rawData;\n};\n\n/**\n * Caution: Can be only called on raw data (before `this._indices` created).\n */\nlistProto.appendData = function (data) {\n    if (__DEV__) {\n        assert$1(!this._indices, 'appendData can only be called on raw data.');\n    }\n\n    var rawData = this._rawData;\n    var start = this.count();\n    rawData.appendData(data);\n    var end = rawData.count();\n    if (!rawData.persistent) {\n        end += start;\n    }\n    this._initDataFromProvider(start, end);\n};\n\n/**\n * Caution: Can be only called on raw data (before `this._indices` created).\n * This method does not modify `rawData` (`dataProvider`), but only\n * add values to storage.\n *\n * The final count will be increased by `Math.max(values.length, names.length)`.\n *\n * @param {Array.<Array.<*>>} values That is the SourceType: 'arrayRows', like\n *        [\n *            [12, 33, 44],\n *            [NaN, 43, 1],\n *            ['-', 'asdf', 0]\n *        ]\n *        Each item is exaclty cooresponding to a dimension.\n * @param {Array.<string>} [names]\n */\nlistProto.appendValues = function (values, names) {\n    var chunkSize = this._chunkSize;\n    var storage = this._storage;\n    var dimensions = this.dimensions;\n    var dimLen = dimensions.length;\n    var rawExtent = this._rawExtent;\n\n    var start = this.count();\n    var end = start + Math.max(values.length, names ? names.length : 0);\n    var originalChunkCount = this._chunkCount;\n\n    for (var i = 0; i < dimLen; i++) {\n        var dim = dimensions[i];\n        if (!rawExtent[dim]) {\n            rawExtent[dim] = getInitialExtent();\n        }\n        if (!storage[dim]) {\n            storage[dim] = [];\n        }\n        prepareChunks(storage, this._dimensionInfos[dim], chunkSize, originalChunkCount, end);\n        this._chunkCount = storage[dim].length;\n    }\n\n    var emptyDataItem = new Array(dimLen);\n    for (var idx = start; idx < end; idx++) {\n        var sourceIdx = idx - start;\n        var chunkIndex = Math.floor(idx / chunkSize);\n        var chunkOffset = idx % chunkSize;\n\n        // Store the data by dimensions\n        for (var k = 0; k < dimLen; k++) {\n            var dim = dimensions[k];\n            var val = this._dimValueGetterArrayRows(\n                values[sourceIdx] || emptyDataItem, dim, sourceIdx, k\n            );\n            storage[dim][chunkIndex][chunkOffset] = val;\n\n            var dimRawExtent = rawExtent[dim];\n            val < dimRawExtent[0] && (dimRawExtent[0] = val);\n            val > dimRawExtent[1] && (dimRawExtent[1] = val);\n        }\n\n        if (names) {\n            this._nameList[idx] = names[sourceIdx];\n        }\n    }\n\n    this._rawCount = this._count = end;\n\n    // Reset data extent\n    this._extent = {};\n\n    prepareInvertedIndex(this);\n};\n\nlistProto._initDataFromProvider = function (start, end) {\n    // Optimize.\n    if (start >= end) {\n        return;\n    }\n\n    var chunkSize = this._chunkSize;\n    var rawData = this._rawData;\n    var storage = this._storage;\n    var dimensions = this.dimensions;\n    var dimLen = dimensions.length;\n    var dimensionInfoMap = this._dimensionInfos;\n    var nameList = this._nameList;\n    var idList = this._idList;\n    var rawExtent = this._rawExtent;\n    var nameRepeatCount = this._nameRepeatCount = {};\n    var nameDimIdx;\n\n    var originalChunkCount = this._chunkCount;\n    for (var i = 0; i < dimLen; i++) {\n        var dim = dimensions[i];\n        if (!rawExtent[dim]) {\n            rawExtent[dim] = getInitialExtent();\n        }\n\n        var dimInfo = dimensionInfoMap[dim];\n        if (dimInfo.otherDims.itemName === 0) {\n            nameDimIdx = this._nameDimIdx = i;\n        }\n        if (dimInfo.otherDims.itemId === 0) {\n            this._idDimIdx = i;\n        }\n\n        if (!storage[dim]) {\n            storage[dim] = [];\n        }\n\n        prepareChunks(storage, dimInfo, chunkSize, originalChunkCount, end);\n\n        this._chunkCount = storage[dim].length;\n    }\n\n    var dataItem = new Array(dimLen);\n    for (var idx = start; idx < end; idx++) {\n        // NOTICE: Try not to write things into dataItem\n        dataItem = rawData.getItem(idx, dataItem);\n        // Each data item is value\n        // [1, 2]\n        // 2\n        // Bar chart, line chart which uses category axis\n        // only gives the 'y' value. 'x' value is the indices of category\n        // Use a tempValue to normalize the value to be a (x, y) value\n        var chunkIndex = Math.floor(idx / chunkSize);\n        var chunkOffset = idx % chunkSize;\n\n        // Store the data by dimensions\n        for (var k = 0; k < dimLen; k++) {\n            var dim = dimensions[k];\n            var dimStorage = storage[dim][chunkIndex];\n            // PENDING NULL is empty or zero\n            var val = this._dimValueGetter(dataItem, dim, idx, k);\n            dimStorage[chunkOffset] = val;\n\n            var dimRawExtent = rawExtent[dim];\n            val < dimRawExtent[0] && (dimRawExtent[0] = val);\n            val > dimRawExtent[1] && (dimRawExtent[1] = val);\n        }\n\n        // ??? FIXME not check by pure but sourceFormat?\n        // TODO refactor these logic.\n        if (!rawData.pure) {\n            var name = nameList[idx];\n\n            if (dataItem && name == null) {\n                // If dataItem is {name: ...}, it has highest priority.\n                // That is appropriate for many common cases.\n                if (dataItem.name != null) {\n                    // There is no other place to persistent dataItem.name,\n                    // so save it to nameList.\n                    nameList[idx] = name = dataItem.name;\n                }\n                else if (nameDimIdx != null) {\n                    var nameDim = dimensions[nameDimIdx];\n                    var nameDimChunk = storage[nameDim][chunkIndex];\n                    if (nameDimChunk) {\n                        name = nameDimChunk[chunkOffset];\n                        var ordinalMeta = dimensionInfoMap[nameDim].ordinalMeta;\n                        if (ordinalMeta && ordinalMeta.categories.length) {\n                            name = ordinalMeta.categories[name];\n                        }\n                    }\n                }\n            }\n\n            // Try using the id in option\n            // id or name is used on dynamical data, mapping old and new items.\n            var id = dataItem == null ? null : dataItem.id;\n\n            if (id == null && name != null) {\n                // Use name as id and add counter to avoid same name\n                nameRepeatCount[name] = nameRepeatCount[name] || 0;\n                id = name;\n                if (nameRepeatCount[name] > 0) {\n                    id += '__ec__' + nameRepeatCount[name];\n                }\n                nameRepeatCount[name]++;\n            }\n            id != null && (idList[idx] = id);\n        }\n    }\n\n    if (!rawData.persistent && rawData.clean) {\n        // Clean unused data if data source is typed array.\n        rawData.clean();\n    }\n\n    this._rawCount = this._count = end;\n\n    // Reset data extent\n    this._extent = {};\n\n    prepareInvertedIndex(this);\n};\n\nfunction prepareChunks(storage, dimInfo, chunkSize, chunkCount, end) {\n    var DataCtor = dataCtors[dimInfo.type];\n    var lastChunkIndex = chunkCount - 1;\n    var dim = dimInfo.name;\n    var resizeChunkArray = storage[dim][lastChunkIndex];\n    if (resizeChunkArray && resizeChunkArray.length < chunkSize) {\n        var newStore = new DataCtor(Math.min(end - lastChunkIndex * chunkSize, chunkSize));\n        // The cost of the copy is probably inconsiderable\n        // within the initial chunkSize.\n        for (var j = 0; j < resizeChunkArray.length; j++) {\n            newStore[j] = resizeChunkArray[j];\n        }\n        storage[dim][lastChunkIndex] = newStore;\n    }\n\n    // Create new chunks.\n    for (var k = chunkCount * chunkSize; k < end; k += chunkSize) {\n        storage[dim].push(new DataCtor(Math.min(end - k, chunkSize)));\n    }\n}\n\nfunction prepareInvertedIndex(list) {\n    var invertedIndicesMap = list._invertedIndicesMap;\n    each$1(invertedIndicesMap, function (invertedIndices, dim) {\n        var dimInfo = list._dimensionInfos[dim];\n\n        // Currently, only dimensions that has ordinalMeta can create inverted indices.\n        var ordinalMeta = dimInfo.ordinalMeta;\n        if (ordinalMeta) {\n            invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array(\n                ordinalMeta.categories.length\n            );\n            // The default value of TypedArray is 0. To avoid miss\n            // mapping to 0, we should set it as INDEX_NOT_FOUND.\n            for (var i = 0; i < invertedIndices.length; i++) {\n                invertedIndices[i] = INDEX_NOT_FOUND;\n            }\n            for (var i = 0; i < list._count; i++) {\n                // Only support the case that all values are distinct.\n                invertedIndices[list.get(dim, i)] = i;\n            }\n        }\n    });\n}\n\nfunction getRawValueFromStore(list, dimIndex, rawIndex) {\n    var val;\n    if (dimIndex != null) {\n        var chunkSize = list._chunkSize;\n        var chunkIndex = Math.floor(rawIndex / chunkSize);\n        var chunkOffset = rawIndex % chunkSize;\n        var dim = list.dimensions[dimIndex];\n        var chunk = list._storage[dim][chunkIndex];\n        if (chunk) {\n            val = chunk[chunkOffset];\n            var ordinalMeta = list._dimensionInfos[dim].ordinalMeta;\n            if (ordinalMeta && ordinalMeta.categories.length) {\n                val = ordinalMeta.categories[val];\n            }\n        }\n    }\n    return val;\n}\n\n/**\n * @return {number}\n */\nlistProto.count = function () {\n    return this._count;\n};\n\nlistProto.getIndices = function () {\n    var newIndices;\n\n    var indices = this._indices;\n    if (indices) {\n        var Ctor = indices.constructor;\n        var thisCount = this._count;\n        // `new Array(a, b, c)` is different from `new Uint32Array(a, b, c)`.\n        if (Ctor === Array) {\n            newIndices = new Ctor(thisCount);\n            for (var i = 0; i < thisCount; i++) {\n                newIndices[i] = indices[i];\n            }\n        }\n        else {\n            newIndices = new Ctor(indices.buffer, 0, thisCount);\n        }\n    }\n    else {\n        var Ctor = getIndicesCtor(this);\n        var newIndices = new Ctor(this.count());\n        for (var i = 0; i < newIndices.length; i++) {\n            newIndices[i] = i;\n        }\n    }\n\n    return newIndices;\n};\n\n/**\n * Get value. Return NaN if idx is out of range.\n * @param {string} dim Dim must be concrete name.\n * @param {number} idx\n * @param {boolean} stack\n * @return {number}\n */\nlistProto.get = function (dim, idx /*, stack */) {\n    if (!(idx >= 0 && idx < this._count)) {\n        return NaN;\n    }\n    var storage = this._storage;\n    if (!storage[dim]) {\n        // TODO Warn ?\n        return NaN;\n    }\n\n    idx = this.getRawIndex(idx);\n\n    var chunkIndex = Math.floor(idx / this._chunkSize);\n    var chunkOffset = idx % this._chunkSize;\n\n    var chunkStore = storage[dim][chunkIndex];\n    var value = chunkStore[chunkOffset];\n    // FIXME ordinal data type is not stackable\n    // if (stack) {\n    //     var dimensionInfo = this._dimensionInfos[dim];\n    //     if (dimensionInfo && dimensionInfo.stackable) {\n    //         var stackedOn = this.stackedOn;\n    //         while (stackedOn) {\n    //             // Get no stacked data of stacked on\n    //             var stackedValue = stackedOn.get(dim, idx);\n    //             // Considering positive stack, negative stack and empty data\n    //             if ((value >= 0 && stackedValue > 0)  // Positive stack\n    //                 || (value <= 0 && stackedValue < 0) // Negative stack\n    //             ) {\n    //                 value += stackedValue;\n    //             }\n    //             stackedOn = stackedOn.stackedOn;\n    //         }\n    //     }\n    // }\n\n    return value;\n};\n\n/**\n * @param {string} dim concrete dim\n * @param {number} rawIndex\n * @return {number|string}\n */\nlistProto.getByRawIndex = function (dim, rawIdx) {\n    if (!(rawIdx >= 0 && rawIdx < this._rawCount)) {\n        return NaN;\n    }\n    var dimStore = this._storage[dim];\n    if (!dimStore) {\n        // TODO Warn ?\n        return NaN;\n    }\n\n    var chunkIndex = Math.floor(rawIdx / this._chunkSize);\n    var chunkOffset = rawIdx % this._chunkSize;\n    var chunkStore = dimStore[chunkIndex];\n    return chunkStore[chunkOffset];\n};\n\n/**\n * FIXME Use `get` on chrome maybe slow(in filterSelf and selectRange).\n * Hack a much simpler _getFast\n * @private\n */\nlistProto._getFast = function (dim, rawIdx) {\n    var chunkIndex = Math.floor(rawIdx / this._chunkSize);\n    var chunkOffset = rawIdx % this._chunkSize;\n    var chunkStore = this._storage[dim][chunkIndex];\n    return chunkStore[chunkOffset];\n};\n\n/**\n * Get value for multi dimensions.\n * @param {Array.<string>} [dimensions] If ignored, using all dimensions.\n * @param {number} idx\n * @return {number}\n */\nlistProto.getValues = function (dimensions, idx /*, stack */) {\n    var values = [];\n\n    if (!isArray(dimensions)) {\n        // stack = idx;\n        idx = dimensions;\n        dimensions = this.dimensions;\n    }\n\n    for (var i = 0, len = dimensions.length; i < len; i++) {\n        values.push(this.get(dimensions[i], idx /*, stack */));\n    }\n\n    return values;\n};\n\n/**\n * If value is NaN. Inlcuding '-'\n * Only check the coord dimensions.\n * @param {string} dim\n * @param {number} idx\n * @return {number}\n */\nlistProto.hasValue = function (idx) {\n    var dataDimsOnCoord = this._dimensionsSummary.dataDimsOnCoord;\n    var dimensionInfos = this._dimensionInfos;\n    for (var i = 0, len = dataDimsOnCoord.length; i < len; i++) {\n        if (\n            // Ordinal type can be string or number\n            dimensionInfos[dataDimsOnCoord[i]].type !== 'ordinal'\n            // FIXME check ordinal when using index?\n            && isNaN(this.get(dataDimsOnCoord[i], idx))\n        ) {\n            return false;\n        }\n    }\n    return true;\n};\n\n/**\n * Get extent of data in one dimension\n * @param {string} dim\n * @param {boolean} stack\n */\nlistProto.getDataExtent = function (dim /*, stack */) {\n    // Make sure use concrete dim as cache name.\n    dim = this.getDimension(dim);\n    var dimData = this._storage[dim];\n    var initialExtent = getInitialExtent();\n\n    // stack = !!((stack || false) && this.getCalculationInfo(dim));\n\n    if (!dimData) {\n        return initialExtent;\n    }\n\n    // Make more strict checkings to ensure hitting cache.\n    var currEnd = this.count();\n    // var cacheName = [dim, !!stack].join('_');\n    // var cacheName = dim;\n\n    // Consider the most cases when using data zoom, `getDataExtent`\n    // happened before filtering. We cache raw extent, which is not\n    // necessary to be cleared and recalculated when restore data.\n    var useRaw = !this._indices; // && !stack;\n    var dimExtent;\n\n    if (useRaw) {\n        return this._rawExtent[dim].slice();\n    }\n    dimExtent = this._extent[dim];\n    if (dimExtent) {\n        return dimExtent.slice();\n    }\n    dimExtent = initialExtent;\n\n    var min = dimExtent[0];\n    var max = dimExtent[1];\n\n    for (var i = 0; i < currEnd; i++) {\n        // var value = stack ? this.get(dim, i, true) : this._getFast(dim, this.getRawIndex(i));\n        var value = this._getFast(dim, this.getRawIndex(i));\n        value < min && (min = value);\n        value > max && (max = value);\n    }\n\n    dimExtent = [min, max];\n\n    this._extent[dim] = dimExtent;\n\n    return dimExtent;\n};\n\n/**\n * Optimize for the scenario that data is filtered by a given extent.\n * Consider that if data amount is more than hundreds of thousand,\n * extent calculation will cost more than 10ms and the cache will\n * be erased because of the filtering.\n */\nlistProto.getApproximateExtent = function (dim /*, stack */) {\n    dim = this.getDimension(dim);\n    return this._approximateExtent[dim] || this.getDataExtent(dim /*, stack */);\n};\n\nlistProto.setApproximateExtent = function (extent, dim /*, stack */) {\n    dim = this.getDimension(dim);\n    this._approximateExtent[dim] = extent.slice();\n};\n\n/**\n * @param {string} key\n * @return {*}\n */\nlistProto.getCalculationInfo = function (key) {\n    return this._calculationInfo[key];\n};\n\n/**\n * @param {string|Object} key or k-v object\n * @param {*} [value]\n */\nlistProto.setCalculationInfo = function (key, value) {\n    isObject$4(key)\n        ? extend(this._calculationInfo, key)\n        : (this._calculationInfo[key] = value);\n};\n\n/**\n * Get sum of data in one dimension\n * @param {string} dim\n */\nlistProto.getSum = function (dim /*, stack */) {\n    var dimData = this._storage[dim];\n    var sum = 0;\n    if (dimData) {\n        for (var i = 0, len = this.count(); i < len; i++) {\n            var value = this.get(dim, i /*, stack */);\n            if (!isNaN(value)) {\n                sum += value;\n            }\n        }\n    }\n    return sum;\n};\n\n/**\n * Get median of data in one dimension\n * @param {string} dim\n */\nlistProto.getMedian = function (dim /*, stack */) {\n    var dimDataArray = [];\n    // map all data of one dimension\n    this.each(dim, function (val, idx) {\n        if (!isNaN(val)) {\n            dimDataArray.push(val);\n        }\n    });\n\n    // TODO\n    // Use quick select?\n\n    // immutability & sort\n    var sortedDimDataArray = [].concat(dimDataArray).sort(function (a, b) {\n        return a - b;\n    });\n    var len = this.count();\n    // calculate median\n    return len === 0\n        ? 0\n        : len % 2 === 1\n        ? sortedDimDataArray[(len - 1) / 2]\n        : (sortedDimDataArray[len / 2] + sortedDimDataArray[len / 2 - 1]) / 2;\n};\n\n// /**\n//  * Retreive the index with given value\n//  * @param {string} dim Concrete dimension.\n//  * @param {number} value\n//  * @return {number}\n//  */\n// Currently incorrect: should return dataIndex but not rawIndex.\n// Do not fix it until this method is to be used somewhere.\n// FIXME Precision of float value\n// listProto.indexOf = function (dim, value) {\n//     var storage = this._storage;\n//     var dimData = storage[dim];\n//     var chunkSize = this._chunkSize;\n//     if (dimData) {\n//         for (var i = 0, len = this.count(); i < len; i++) {\n//             var chunkIndex = Math.floor(i / chunkSize);\n//             var chunkOffset = i % chunkSize;\n//             if (dimData[chunkIndex][chunkOffset] === value) {\n//                 return i;\n//             }\n//         }\n//     }\n//     return -1;\n// };\n\n/**\n * Only support the dimension which inverted index created.\n * Do not support other cases until required.\n * @param {string} concrete dim\n * @param {number|string} value\n * @return {number} rawIndex\n */\nlistProto.rawIndexOf = function (dim, value) {\n    var invertedIndices = dim && this._invertedIndicesMap[dim];\n    if (__DEV__) {\n        if (!invertedIndices) {\n            throw new Error('Do not supported yet');\n        }\n    }\n    var rawIndex = invertedIndices[value];\n    if (rawIndex == null || isNaN(rawIndex)) {\n        return INDEX_NOT_FOUND;\n    }\n    return rawIndex;\n};\n\n/**\n * Retreive the index with given name\n * @param {number} idx\n * @param {number} name\n * @return {number}\n */\nlistProto.indexOfName = function (name) {\n    for (var i = 0, len = this.count(); i < len; i++) {\n        if (this.getName(i) === name) {\n            return i;\n        }\n    }\n\n    return -1;\n};\n\n/**\n * Retreive the index with given raw data index\n * @param {number} idx\n * @param {number} name\n * @return {number}\n */\nlistProto.indexOfRawIndex = function (rawIndex) {\n    if (!this._indices) {\n        return rawIndex;\n    }\n\n    if (rawIndex >= this._rawCount || rawIndex < 0) {\n        return -1;\n    }\n\n    // Indices are ascending\n    var indices = this._indices;\n\n    // If rawIndex === dataIndex\n    var rawDataIndex = indices[rawIndex];\n    if (rawDataIndex != null && rawDataIndex < this._count && rawDataIndex === rawIndex) {\n        return rawIndex;\n    }\n\n    var left = 0;\n    var right = this._count - 1;\n    while (left <= right) {\n        var mid = (left + right) / 2 | 0;\n        if (indices[mid] < rawIndex) {\n            left = mid + 1;\n        }\n        else if (indices[mid] > rawIndex) {\n            right = mid - 1;\n        }\n        else {\n            return mid;\n        }\n    }\n    return -1;\n};\n\n/**\n * Retreive the index of nearest value\n * @param {string} dim\n * @param {number} value\n * @param {number} [maxDistance=Infinity]\n * @return {Array.<number>} Considere multiple points has the same value.\n */\nlistProto.indicesOfNearest = function (dim, value, maxDistance) {\n    var storage = this._storage;\n    var dimData = storage[dim];\n    var nearestIndices = [];\n\n    if (!dimData) {\n        return nearestIndices;\n    }\n\n    if (maxDistance == null) {\n        maxDistance = Infinity;\n    }\n\n    var minDist = Number.MAX_VALUE;\n    var minDiff = -1;\n    for (var i = 0, len = this.count(); i < len; i++) {\n        var diff = value - this.get(dim, i /*, stack */);\n        var dist = Math.abs(diff);\n        if (diff <= maxDistance && dist <= minDist) {\n            // For the case of two data are same on xAxis, which has sequence data.\n            // Show the nearest index\n            // https://github.com/ecomfe/echarts/issues/2869\n            if (dist < minDist || (diff >= 0 && minDiff < 0)) {\n                minDist = dist;\n                minDiff = diff;\n                nearestIndices.length = 0;\n            }\n            nearestIndices.push(i);\n        }\n    }\n    return nearestIndices;\n};\n\n/**\n * Get raw data index\n * @param {number} idx\n * @return {number}\n */\nlistProto.getRawIndex = getRawIndexWithoutIndices;\n\nfunction getRawIndexWithoutIndices(idx) {\n    return idx;\n}\n\nfunction getRawIndexWithIndices(idx) {\n    if (idx < this._count && idx >= 0) {\n        return this._indices[idx];\n    }\n    return -1;\n}\n\n/**\n * Get raw data item\n * @param {number} idx\n * @return {number}\n */\nlistProto.getRawDataItem = function (idx) {\n    if (!this._rawData.persistent) {\n        var val = [];\n        for (var i = 0; i < this.dimensions.length; i++) {\n            var dim = this.dimensions[i];\n            val.push(this.get(dim, idx));\n        }\n        return val;\n    }\n    else {\n        return this._rawData.getItem(this.getRawIndex(idx));\n    }\n};\n\n/**\n * @param {number} idx\n * @param {boolean} [notDefaultIdx=false]\n * @return {string}\n */\nlistProto.getName = function (idx) {\n    var rawIndex = this.getRawIndex(idx);\n    return this._nameList[rawIndex]\n        || getRawValueFromStore(this, this._nameDimIdx, rawIndex)\n        || '';\n};\n\n/**\n * @param {number} idx\n * @param {boolean} [notDefaultIdx=false]\n * @return {string}\n */\nlistProto.getId = function (idx) {\n    return getId(this, this.getRawIndex(idx));\n};\n\nfunction getId(list, rawIndex) {\n    var id = list._idList[rawIndex];\n    if (id == null) {\n        id = getRawValueFromStore(list, list._idDimIdx, rawIndex);\n    }\n    if (id == null) {\n        // FIXME Check the usage in graph, should not use prefix.\n        id = ID_PREFIX + rawIndex;\n    }\n    return id;\n}\n\nfunction normalizeDimensions(dimensions) {\n    if (!isArray(dimensions)) {\n        dimensions = [dimensions];\n    }\n    return dimensions;\n}\n\nfunction validateDimensions(list, dims) {\n    for (var i = 0; i < dims.length; i++) {\n        // stroage may be empty when no data, so use\n        // dimensionInfos to check.\n        if (!list._dimensionInfos[dims[i]]) {\n            console.error('Unkown dimension ' + dims[i]);\n        }\n    }\n}\n\n/**\n * Data iteration\n * @param {string|Array.<string>}\n * @param {Function} cb\n * @param {*} [context=this]\n *\n * @example\n *  list.each('x', function (x, idx) {});\n *  list.each(['x', 'y'], function (x, y, idx) {});\n *  list.each(function (idx) {})\n */\nlistProto.each = function (dims, cb, context, contextCompat) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    if (typeof dims === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dims;\n        dims = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dims = map(normalizeDimensions(dims), this.getDimension, this);\n\n    if (__DEV__) {\n        validateDimensions(this, dims);\n    }\n\n    var dimSize = dims.length;\n\n    for (var i = 0; i < this.count(); i++) {\n        // Simple optimization\n        switch (dimSize) {\n            case 0:\n                cb.call(context, i);\n                break;\n            case 1:\n                cb.call(context, this.get(dims[0], i), i);\n                break;\n            case 2:\n                cb.call(context, this.get(dims[0], i), this.get(dims[1], i), i);\n                break;\n            default:\n                var k = 0;\n                var value = [];\n                for (; k < dimSize; k++) {\n                    value[k] = this.get(dims[k], i);\n                }\n                // Index\n                value[k] = i;\n                cb.apply(context, value);\n        }\n    }\n};\n\n/**\n * Data filter\n * @param {string|Array.<string>}\n * @param {Function} cb\n * @param {*} [context=this]\n */\nlistProto.filterSelf = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    if (typeof dimensions === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dimensions;\n        dimensions = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dimensions = map(\n        normalizeDimensions(dimensions), this.getDimension, this\n    );\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n\n    var count = this.count();\n    var Ctor = getIndicesCtor(this);\n    var newIndices = new Ctor(count);\n    var value = [];\n    var dimSize = dimensions.length;\n\n    var offset = 0;\n    var dim0 = dimensions[0];\n\n    for (var i = 0; i < count; i++) {\n        var keep;\n        var rawIdx = this.getRawIndex(i);\n        // Simple optimization\n        if (dimSize === 0) {\n            keep = cb.call(context, i);\n        }\n        else if (dimSize === 1) {\n            var val = this._getFast(dim0, rawIdx);\n            keep = cb.call(context, val, i);\n        }\n        else {\n            for (var k = 0; k < dimSize; k++) {\n                value[k] = this._getFast(dim0, rawIdx);\n            }\n            value[k] = i;\n            keep = cb.apply(context, value);\n        }\n        if (keep) {\n            newIndices[offset++] = rawIdx;\n        }\n    }\n\n    // Set indices after filtered.\n    if (offset < count) {\n        this._indices = newIndices;\n    }\n    this._count = offset;\n    // Reset data extent\n    this._extent = {};\n\n    this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return this;\n};\n\n/**\n * Select data in range. (For optimization of filter)\n * (Manually inline code, support 5 million data filtering in data zoom.)\n */\nlistProto.selectRange = function (range) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    var dimensions = [];\n    for (var dim in range) {\n        if (range.hasOwnProperty(dim)) {\n            dimensions.push(dim);\n        }\n    }\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n    var dimSize = dimensions.length;\n    if (!dimSize) {\n        return;\n    }\n\n    var originalCount = this.count();\n    var Ctor = getIndicesCtor(this);\n    var newIndices = new Ctor(originalCount);\n\n    var offset = 0;\n    var dim0 = dimensions[0];\n\n    var min = range[dim0][0];\n    var max = range[dim0][1];\n\n    var quickFinished = false;\n    if (!this._indices) {\n        // Extreme optimization for common case. About 2x faster in chrome.\n        var idx = 0;\n        if (dimSize === 1) {\n            var dimStorage = this._storage[dimensions[0]];\n            for (var k = 0; k < this._chunkCount; k++) {\n                var chunkStorage = dimStorage[k];\n                var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);\n                for (var i = 0; i < len; i++) {\n                    var val = chunkStorage[i];\n                    // NaN will not be filtered. Consider the case, in line chart, empty\n                    // value indicates the line should be broken. But for the case like\n                    // scatter plot, a data item with empty value will not be rendered,\n                    // but the axis extent may be effected if some other dim of the data\n                    // item has value. Fortunately it is not a significant negative effect.\n                    if (\n                        (val >= min && val <= max) || isNaN(val)\n                    ) {\n                        newIndices[offset++] = idx;\n                    }\n                    idx++;\n                }\n            }\n            quickFinished = true;\n        }\n        else if (dimSize === 2) {\n            var dimStorage = this._storage[dim0];\n            var dimStorage2 = this._storage[dimensions[1]];\n            var min2 = range[dimensions[1]][0];\n            var max2 = range[dimensions[1]][1];\n            for (var k = 0; k < this._chunkCount; k++) {\n                var chunkStorage = dimStorage[k];\n                var chunkStorage2 = dimStorage2[k];\n                var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);\n                for (var i = 0; i < len; i++) {\n                    var val = chunkStorage[i];\n                    var val2 = chunkStorage2[i];\n                    // Do not filter NaN, see comment above.\n                    if ((\n                            (val >= min && val <= max) || isNaN(val)\n                        )\n                        && (\n                            (val2 >= min2 && val2 <= max2) || isNaN(val2)\n                        )\n                    ) {\n                        newIndices[offset++] = idx;\n                    }\n                    idx++;\n                }\n            }\n            quickFinished = true;\n        }\n    }\n    if (!quickFinished) {\n        if (dimSize === 1) {\n            for (var i = 0; i < originalCount; i++) {\n                var rawIndex = this.getRawIndex(i);\n                var val = this._getFast(dim0, rawIndex);\n                // Do not filter NaN, see comment above.\n                if (\n                    (val >= min && val <= max) || isNaN(val)\n                ) {\n                    newIndices[offset++] = rawIndex;\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < originalCount; i++) {\n                var keep = true;\n                var rawIndex = this.getRawIndex(i);\n                for (var k = 0; k < dimSize; k++) {\n                    var dimk = dimensions[k];\n                    var val = this._getFast(dim, rawIndex);\n                    // Do not filter NaN, see comment above.\n                    if (val < range[dimk][0] || val > range[dimk][1]) {\n                        keep = false;\n                    }\n                }\n                if (keep) {\n                    newIndices[offset++] = this.getRawIndex(i);\n                }\n            }\n        }\n    }\n\n    // Set indices after filtered.\n    if (offset < originalCount) {\n        this._indices = newIndices;\n    }\n    this._count = offset;\n    // Reset data extent\n    this._extent = {};\n\n    this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return this;\n};\n\n/**\n * Data mapping to a plain array\n * @param {string|Array.<string>} [dimensions]\n * @param {Function} cb\n * @param {*} [context=this]\n * @return {Array}\n */\nlistProto.mapArray = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    if (typeof dimensions === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dimensions;\n        dimensions = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    var result = [];\n    this.each(dimensions, function () {\n        result.push(cb && cb.apply(this, arguments));\n    }, context);\n    return result;\n};\n\n// Data in excludeDimensions is copied, otherwise transfered.\nfunction cloneListForMapAndSample(original, excludeDimensions) {\n    var allDimensions = original.dimensions;\n    var list = new List(\n        map(allDimensions, original.getDimensionInfo, original),\n        original.hostModel\n    );\n    // FIXME If needs stackedOn, value may already been stacked\n    transferProperties(list, original);\n\n    var storage = list._storage = {};\n    var originalStorage = original._storage;\n\n    // Init storage\n    for (var i = 0; i < allDimensions.length; i++) {\n        var dim = allDimensions[i];\n        if (originalStorage[dim]) {\n            // Notice that we do not reset invertedIndicesMap here, becuase\n            // there is no scenario of mapping or sampling ordinal dimension.\n            if (indexOf(excludeDimensions, dim) >= 0) {\n                storage[dim] = cloneDimStore(originalStorage[dim]);\n                list._rawExtent[dim] = getInitialExtent();\n                list._extent[dim] = null;\n            }\n            else {\n                // Direct reference for other dimensions\n                storage[dim] = originalStorage[dim];\n            }\n        }\n    }\n    return list;\n}\n\nfunction cloneDimStore(originalDimStore) {\n    var newDimStore = new Array(originalDimStore.length);\n    for (var j = 0; j < originalDimStore.length; j++) {\n        newDimStore[j] = cloneChunk(originalDimStore[j]);\n    }\n    return newDimStore;\n}\n\nfunction getInitialExtent() {\n    return [Infinity, -Infinity];\n}\n\n/**\n * Data mapping to a new List with given dimensions\n * @param {string|Array.<string>} dimensions\n * @param {Function} cb\n * @param {*} [context=this]\n * @return {Array}\n */\nlistProto.map = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dimensions = map(\n        normalizeDimensions(dimensions), this.getDimension, this\n    );\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n    var list = cloneListForMapAndSample(this, dimensions);\n\n    // Following properties are all immutable.\n    // So we can reference to the same value\n    list._indices = this._indices;\n    list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    var storage = list._storage;\n\n    var tmpRetValue = [];\n    var chunkSize = this._chunkSize;\n    var dimSize = dimensions.length;\n    var dataCount = this.count();\n    var values = [];\n    var rawExtent = list._rawExtent;\n\n    for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) {\n        for (var dimIndex = 0; dimIndex < dimSize; dimIndex++) {\n            values[dimIndex] = this.get(dimensions[dimIndex], dataIndex /*, stack */);\n        }\n        values[dimSize] = dataIndex;\n\n        var retValue = cb && cb.apply(context, values);\n        if (retValue != null) {\n            // a number or string (in oridinal dimension)?\n            if (typeof retValue !== 'object') {\n                tmpRetValue[0] = retValue;\n                retValue = tmpRetValue;\n            }\n\n            var rawIndex = this.getRawIndex(dataIndex);\n            var chunkIndex = Math.floor(rawIndex / chunkSize);\n            var chunkOffset = rawIndex % chunkSize;\n\n            for (var i = 0; i < retValue.length; i++) {\n                var dim = dimensions[i];\n                var val = retValue[i];\n                var rawExtentOnDim = rawExtent[dim];\n\n                var dimStore = storage[dim];\n                if (dimStore) {\n                    dimStore[chunkIndex][chunkOffset] = val;\n                }\n\n                if (val < rawExtentOnDim[0]) {\n                    rawExtentOnDim[0] = val;\n                }\n                if (val > rawExtentOnDim[1]) {\n                    rawExtentOnDim[1] = val;\n                }\n            }\n        }\n    }\n\n    return list;\n};\n\n/**\n * Large data down sampling on given dimension\n * @param {string} dimension\n * @param {number} rate\n * @param {Function} sampleValue\n * @param {Function} sampleIndex Sample index for name and id\n */\nlistProto.downSample = function (dimension, rate, sampleValue, sampleIndex) {\n    var list = cloneListForMapAndSample(this, [dimension]);\n    var targetStorage = list._storage;\n\n    var frameValues = [];\n    var frameSize = Math.floor(1 / rate);\n\n    var dimStore = targetStorage[dimension];\n    var len = this.count();\n    var chunkSize = this._chunkSize;\n    var rawExtentOnDim = list._rawExtent[dimension];\n\n    var newIndices = new (getIndicesCtor(this))(len);\n\n    var offset = 0;\n    for (var i = 0; i < len; i += frameSize) {\n        // Last frame\n        if (frameSize > len - i) {\n            frameSize = len - i;\n            frameValues.length = frameSize;\n        }\n        for (var k = 0; k < frameSize; k++) {\n            var dataIdx = this.getRawIndex(i + k);\n            var originalChunkIndex = Math.floor(dataIdx / chunkSize);\n            var originalChunkOffset = dataIdx % chunkSize;\n            frameValues[k] = dimStore[originalChunkIndex][originalChunkOffset];\n        }\n        var value = sampleValue(frameValues);\n        var sampleFrameIdx = this.getRawIndex(\n            Math.min(i + sampleIndex(frameValues, value) || 0, len - 1)\n        );\n        var sampleChunkIndex = Math.floor(sampleFrameIdx / chunkSize);\n        var sampleChunkOffset = sampleFrameIdx % chunkSize;\n        // Only write value on the filtered data\n        dimStore[sampleChunkIndex][sampleChunkOffset] = value;\n\n        if (value < rawExtentOnDim[0]) {\n            rawExtentOnDim[0] = value;\n        }\n        if (value > rawExtentOnDim[1]) {\n            rawExtentOnDim[1] = value;\n        }\n\n        newIndices[offset++] = sampleFrameIdx;\n    }\n\n    list._count = offset;\n    list._indices = newIndices;\n\n    list.getRawIndex = getRawIndexWithIndices;\n\n    return list;\n};\n\n/**\n * Get model of one data item.\n *\n * @param {number} idx\n */\n// FIXME Model proxy ?\nlistProto.getItemModel = function (idx) {\n    var hostModel = this.hostModel;\n    return new Model(this.getRawDataItem(idx), hostModel, hostModel && hostModel.ecModel);\n};\n\n/**\n * Create a data differ\n * @param {module:echarts/data/List} otherList\n * @return {module:echarts/data/DataDiffer}\n */\nlistProto.diff = function (otherList) {\n    var thisList = this;\n\n    return new DataDiffer(\n        otherList ? otherList.getIndices() : [],\n        this.getIndices(),\n        function (idx) {\n            return getId(otherList, idx);\n        },\n        function (idx) {\n            return getId(thisList, idx);\n        }\n    );\n};\n/**\n * Get visual property.\n * @param {string} key\n */\nlistProto.getVisual = function (key) {\n    var visual = this._visual;\n    return visual && visual[key];\n};\n\n/**\n * Set visual property\n * @param {string|Object} key\n * @param {*} [value]\n *\n * @example\n *  setVisual('color', color);\n *  setVisual({\n *      'color': color\n *  });\n */\nlistProto.setVisual = function (key, val) {\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                this.setVisual(name, key[name]);\n            }\n        }\n        return;\n    }\n    this._visual = this._visual || {};\n    this._visual[key] = val;\n};\n\n/**\n * Set layout property.\n * @param {string|Object} key\n * @param {*} [val]\n */\nlistProto.setLayout = function (key, val) {\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                this.setLayout(name, key[name]);\n            }\n        }\n        return;\n    }\n    this._layout[key] = val;\n};\n\n/**\n * Get layout property.\n * @param  {string} key.\n * @return {*}\n */\nlistProto.getLayout = function (key) {\n    return this._layout[key];\n};\n\n/**\n * Get layout of single data item\n * @param {number} idx\n */\nlistProto.getItemLayout = function (idx) {\n    return this._itemLayouts[idx];\n};\n\n/**\n * Set layout of single data item\n * @param {number} idx\n * @param {Object} layout\n * @param {boolean=} [merge=false]\n */\nlistProto.setItemLayout = function (idx, layout, merge$$1) {\n    this._itemLayouts[idx] = merge$$1\n        ? extend(this._itemLayouts[idx] || {}, layout)\n        : layout;\n};\n\n/**\n * Clear all layout of single data item\n */\nlistProto.clearItemLayouts = function () {\n    this._itemLayouts.length = 0;\n};\n\n/**\n * Get visual property of single data item\n * @param {number} idx\n * @param {string} key\n * @param {boolean} [ignoreParent=false]\n */\nlistProto.getItemVisual = function (idx, key, ignoreParent) {\n    var itemVisual = this._itemVisuals[idx];\n    var val = itemVisual && itemVisual[key];\n    if (val == null && !ignoreParent) {\n        // Use global visual property\n        return this.getVisual(key);\n    }\n    return val;\n};\n\n/**\n * Set visual property of single data item\n *\n * @param {number} idx\n * @param {string|Object} key\n * @param {*} [value]\n *\n * @example\n *  setItemVisual(0, 'color', color);\n *  setItemVisual(0, {\n *      'color': color\n *  });\n */\nlistProto.setItemVisual = function (idx, key, value) {\n    var itemVisual = this._itemVisuals[idx] || {};\n    var hasItemVisual = this.hasItemVisual;\n    this._itemVisuals[idx] = itemVisual;\n\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                itemVisual[name] = key[name];\n                hasItemVisual[name] = true;\n            }\n        }\n        return;\n    }\n    itemVisual[key] = value;\n    hasItemVisual[key] = true;\n};\n\n/**\n * Clear itemVisuals and list visual.\n */\nlistProto.clearAllVisual = function () {\n    this._visual = {};\n    this._itemVisuals = [];\n    this.hasItemVisual = {};\n};\n\nvar setItemDataAndSeriesIndex = function (child) {\n    child.seriesIndex = this.seriesIndex;\n    child.dataIndex = this.dataIndex;\n    child.dataType = this.dataType;\n};\n/**\n * Set graphic element relative to data. It can be set as null\n * @param {number} idx\n * @param {module:zrender/Element} [el]\n */\nlistProto.setItemGraphicEl = function (idx, el) {\n    var hostModel = this.hostModel;\n\n    if (el) {\n        // Add data index and series index for indexing the data by element\n        // Useful in tooltip\n        el.dataIndex = idx;\n        el.dataType = this.dataType;\n        el.seriesIndex = hostModel && hostModel.seriesIndex;\n        if (el.type === 'group') {\n            el.traverse(setItemDataAndSeriesIndex, el);\n        }\n    }\n\n    this._graphicEls[idx] = el;\n};\n\n/**\n * @param {number} idx\n * @return {module:zrender/Element}\n */\nlistProto.getItemGraphicEl = function (idx) {\n    return this._graphicEls[idx];\n};\n\n/**\n * @param {Function} cb\n * @param {*} context\n */\nlistProto.eachItemGraphicEl = function (cb, context) {\n    each$1(this._graphicEls, function (el, idx) {\n        if (el) {\n            cb && cb.call(context, el, idx);\n        }\n    });\n};\n\n/**\n * Shallow clone a new list except visual and layout properties, and graph elements.\n * New list only change the indices.\n */\nlistProto.cloneShallow = function (list) {\n    if (!list) {\n        var dimensionInfoList = map(this.dimensions, this.getDimensionInfo, this);\n        list = new List(dimensionInfoList, this.hostModel);\n    }\n\n    // FIXME\n    list._storage = this._storage;\n\n    transferProperties(list, this);\n\n    // Clone will not change the data extent and indices\n    if (this._indices) {\n        var Ctor = this._indices.constructor;\n        list._indices = new Ctor(this._indices);\n    }\n    else {\n        list._indices = null;\n    }\n    list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return list;\n};\n\n/**\n * Wrap some method to add more feature\n * @param {string} methodName\n * @param {Function} injectFunction\n */\nlistProto.wrapMethod = function (methodName, injectFunction) {\n    var originalMethod = this[methodName];\n    if (typeof originalMethod !== 'function') {\n        return;\n    }\n    this.__wrappedMethods = this.__wrappedMethods || [];\n    this.__wrappedMethods.push(methodName);\n    this[methodName] = function () {\n        var res = originalMethod.apply(this, arguments);\n        return injectFunction.apply(this, [res].concat(slice(arguments)));\n    };\n};\n\n// Methods that create a new list based on this list should be listed here.\n// Notice that those method should `RETURN` the new list.\nlistProto.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'map'];\n// Methods that change indices of this list should be listed here.\nlistProto.CHANGABLE_METHODS = ['filterSelf', 'selectRange'];\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @deprecated\n * Use `echarts/data/helper/createDimensions` instead.\n */\n\n/**\n * @see {module:echarts/test/ut/spec/data/completeDimensions}\n *\n * Complete the dimensions array, by user defined `dimension` and `encode`,\n * and guessing from the data structure.\n * If no 'value' dimension specified, the first no-named dimension will be\n * named as 'value'.\n *\n * @param {Array.<string>} sysDims Necessary dimensions, like ['x', 'y'], which\n *      provides not only dim template, but also default order.\n *      properties: 'name', 'type', 'displayName'.\n *      `name` of each item provides default coord name.\n *      [{dimsDef: [string|Object, ...]}, ...] dimsDef of sysDim item provides default dim name, and\n *                                    provide dims count that the sysDim required.\n *      [{ordinalMeta}] can be specified.\n * @param {module:echarts/data/Source|Array|Object} source or data (for compatibal with pervious)\n * @param {Object} [opt]\n * @param {Array.<Object|string>} [opt.dimsDef] option.series.dimensions User defined dimensions\n *      For example: ['asdf', {name, type}, ...].\n * @param {Object|HashMap} [opt.encodeDef] option.series.encode {x: 2, y: [3, 1], tooltip: [1, 2], label: 3}\n * @param {string} [opt.generateCoord] Generate coord dim with the given name.\n *                 If not specified, extra dim names will be:\n *                 'value', 'value0', 'value1', ...\n * @param {number} [opt.generateCoordCount] By default, the generated dim name is `generateCoord`.\n *                 If `generateCoordCount` specified, the generated dim names will be:\n *                 `generateCoord` + 0, `generateCoord` + 1, ...\n *                 can be Infinity, indicate that use all of the remain columns.\n * @param {number} [opt.dimCount] If not specified, guess by the first data item.\n * @param {number} [opt.encodeDefaulter] If not specified, auto find the next available data dim.\n * @return {Array.<Object>} [{\n *      name: string mandatory,\n *      displayName: string, the origin name in dimsDef, see source helper.\n *                 If displayName given, the tooltip will displayed vertically.\n *      coordDim: string mandatory,\n *      coordDimIndex: number mandatory,\n *      type: string optional,\n *      otherDims: { never null/undefined\n *          tooltip: number optional,\n *          label: number optional,\n *          itemName: number optional,\n *          seriesName: number optional,\n *      },\n *      isExtraCoord: boolean true if coord is generated\n *          (not specified in encode and not series specified)\n *      other props ...\n * }]\n */\nfunction completeDimensions(sysDims, source, opt) {\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n\n    opt = opt || {};\n    sysDims = (sysDims || []).slice();\n    var dimsDef = (opt.dimsDef || []).slice();\n    var encodeDef = createHashMap(opt.encodeDef);\n    var dataDimNameMap = createHashMap();\n    var coordDimNameMap = createHashMap();\n    // var valueCandidate;\n    var result = [];\n\n    var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimCount);\n\n    // Apply user defined dims (`name` and `type`) and init result.\n    for (var i = 0; i < dimCount; i++) {\n        var dimDefItem = dimsDef[i] = extend(\n            {}, isObject$1(dimsDef[i]) ? dimsDef[i] : {name: dimsDef[i]}\n        );\n        var userDimName = dimDefItem.name;\n        var resultItem = result[i] = {otherDims: {}};\n        // Name will be applied later for avoiding duplication.\n        if (userDimName != null && dataDimNameMap.get(userDimName) == null) {\n            // Only if `series.dimensions` is defined in option\n            // displayName, will be set, and dimension will be diplayed vertically in\n            // tooltip by default.\n            resultItem.name = resultItem.displayName = userDimName;\n            dataDimNameMap.set(userDimName, i);\n        }\n        dimDefItem.type != null && (resultItem.type = dimDefItem.type);\n        dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);\n    }\n\n    // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.\n    encodeDef.each(function (dataDims, coordDim) {\n        dataDims = normalizeToArray(dataDims).slice();\n\n        // Note: It is allowed that `dataDims.length` is `0`, e.g., options is\n        // `{encode: {x: -1, y: 1}}`. Should not filter anything in\n        // this case.\n        if (dataDims.length === 1 && dataDims[0] < 0) {\n            encodeDef.set(coordDim, false);\n            return;\n        }\n\n        var validDataDims = encodeDef.set(coordDim, []);\n        each$1(dataDims, function (resultDimIdx, idx) {\n            // The input resultDimIdx can be dim name or index.\n            isString(resultDimIdx) && (resultDimIdx = dataDimNameMap.get(resultDimIdx));\n            if (resultDimIdx != null && resultDimIdx < dimCount) {\n                validDataDims[idx] = resultDimIdx;\n                applyDim(result[resultDimIdx], coordDim, idx);\n            }\n        });\n    });\n\n    // Apply templetes and default order from `sysDims`.\n    var availDimIdx = 0;\n    each$1(sysDims, function (sysDimItem, sysDimIndex) {\n        var coordDim;\n        var sysDimItem;\n        var sysDimItemDimsDef;\n        var sysDimItemOtherDims;\n        if (isString(sysDimItem)) {\n            coordDim = sysDimItem;\n            sysDimItem = {};\n        }\n        else {\n            coordDim = sysDimItem.name;\n            var ordinalMeta = sysDimItem.ordinalMeta;\n            sysDimItem.ordinalMeta = null;\n            sysDimItem = clone(sysDimItem);\n            sysDimItem.ordinalMeta = ordinalMeta;\n            // `coordDimIndex` should not be set directly.\n            sysDimItemDimsDef = sysDimItem.dimsDef;\n            sysDimItemOtherDims = sysDimItem.otherDims;\n            sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex\n                = sysDimItem.dimsDef = sysDimItem.otherDims = null;\n        }\n\n        var dataDims = encodeDef.get(coordDim);\n\n        // negative resultDimIdx means no need to mapping.\n        if (dataDims === false) {\n            return;\n        }\n\n        var dataDims = normalizeToArray(dataDims);\n\n        // dimensions provides default dim sequences.\n        if (!dataDims.length) {\n            for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {\n                while (availDimIdx < result.length && result[availDimIdx].coordDim != null) {\n                    availDimIdx++;\n                }\n                availDimIdx < result.length && dataDims.push(availDimIdx++);\n            }\n        }\n\n        // Apply templates.\n        each$1(dataDims, function (resultDimIdx, coordDimIndex) {\n            var resultItem = result[resultDimIdx];\n            applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);\n            if (resultItem.name == null && sysDimItemDimsDef) {\n                var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];\n                !isObject$1(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {name: sysDimItemDimsDefItem});\n                resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;\n                resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;\n            }\n            // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}\n            sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);\n        });\n    });\n\n    function applyDim(resultItem, coordDim, coordDimIndex) {\n        if (OTHER_DIMENSIONS.get(coordDim) != null) {\n            resultItem.otherDims[coordDim] = coordDimIndex;\n        }\n        else {\n            resultItem.coordDim = coordDim;\n            resultItem.coordDimIndex = coordDimIndex;\n            coordDimNameMap.set(coordDim, true);\n        }\n    }\n\n    // Make sure the first extra dim is 'value'.\n    var generateCoord = opt.generateCoord;\n    var generateCoordCount = opt.generateCoordCount;\n    var fromZero = generateCoordCount != null;\n    generateCoordCount = generateCoord ? (generateCoordCount || 1) : 0;\n    var extra = generateCoord || 'value';\n\n    // Set dim `name` and other `coordDim` and other props.\n    for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {\n        var resultItem = result[resultDimIdx] = result[resultDimIdx] || {};\n        var coordDim = resultItem.coordDim;\n\n        if (coordDim == null) {\n            resultItem.coordDim = genName(\n                extra, coordDimNameMap, fromZero\n            );\n            resultItem.coordDimIndex = 0;\n            if (!generateCoord || generateCoordCount <= 0) {\n                resultItem.isExtraCoord = true;\n            }\n            generateCoordCount--;\n        }\n\n        resultItem.name == null && (resultItem.name = genName(\n            resultItem.coordDim,\n            dataDimNameMap\n        ));\n\n        if (resultItem.type == null && guessOrdinal(source, resultDimIdx, resultItem.name)) {\n            resultItem.type = 'ordinal';\n        }\n    }\n\n    return result;\n}\n\n// ??? TODO\n// Originally detect dimCount by data[0]. Should we\n// optimize it to only by sysDims and dimensions and encode.\n// So only necessary dims will be initialized.\n// But\n// (1) custom series should be considered. where other dims\n// may be visited.\n// (2) sometimes user need to calcualte bubble size or use visualMap\n// on other dimensions besides coordSys needed.\n// So, dims that is not used by system, should be shared in storage?\nfunction getDimCount(source, sysDims, dimsDef, optDimCount) {\n    // Note that the result dimCount should not small than columns count\n    // of data, otherwise `dataDimNameMap` checking will be incorrect.\n    var dimCount = Math.max(\n        source.dimensionsDetectCount || 1,\n        sysDims.length,\n        dimsDef.length,\n        optDimCount || 0\n    );\n    each$1(sysDims, function (sysDimItem) {\n        var sysDimItemDimsDef = sysDimItem.dimsDef;\n        sysDimItemDimsDef && (dimCount = Math.max(dimCount, sysDimItemDimsDef.length));\n    });\n    return dimCount;\n}\n\nfunction genName(name, map$$1, fromZero) {\n    if (fromZero || map$$1.get(name) != null) {\n        var i = 0;\n        while (map$$1.get(name + i) != null) {\n            i++;\n        }\n        name += i;\n    }\n    map$$1.set(name, true);\n    return name;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Substitute `completeDimensions`.\n * `completeDimensions` is to be deprecated.\n */\n/**\n * @param {module:echarts/data/Source|module:echarts/data/List} source or data.\n * @param {Object|Array} [opt]\n * @param {Array.<string|Object>} [opt.coordDimensions=[]]\n * @param {number} [opt.dimensionsCount]\n * @param {string} [opt.generateCoord]\n * @param {string} [opt.generateCoordCount]\n * @param {Array.<string|Object>} [opt.dimensionsDefine=source.dimensionsDefine] Overwrite source define.\n * @param {Object|HashMap} [opt.encodeDefine=source.encodeDefine] Overwrite source define.\n * @return {Array.<Object>} dimensionsInfo\n */\nvar createDimensions = function (source, opt) {\n    opt = opt || {};\n    return completeDimensions(opt.coordDimensions || [], source, {\n        dimsDef: opt.dimensionsDefine || source.dimensionsDefine,\n        encodeDef: opt.encodeDefine || source.encodeDefine,\n        dimCount: opt.dimensionsCount,\n        generateCoord: opt.generateCoord,\n        generateCoordCount: opt.generateCoordCount\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Note that it is too complicated to support 3d stack by value\n * (have to create two-dimension inverted index), so in 3d case\n * we just support that stacked by index.\n *\n * @param {module:echarts/model/Series} seriesModel\n * @param {Array.<string|Object>} dimensionInfoList The same as the input of <module:echarts/data/List>.\n *        The input dimensionInfoList will be modified.\n * @param {Object} [opt]\n * @param {boolean} [opt.stackedCoordDimension=''] Specify a coord dimension if needed.\n * @param {boolean} [opt.byIndex=false]\n * @return {Object} calculationInfo\n * {\n *     stackedDimension: string\n *     stackedByDimension: string\n *     isStackedByIndex: boolean\n *     stackedOverDimension: string\n *     stackResultDimension: string\n * }\n */\nfunction enableDataStack(seriesModel, dimensionInfoList, opt) {\n    opt = opt || {};\n    var byIndex = opt.byIndex;\n    var stackedCoordDimension = opt.stackedCoordDimension;\n\n    // Compatibal: when `stack` is set as '', do not stack.\n    var mayStack = !!(seriesModel && seriesModel.get('stack'));\n    var stackedByDimInfo;\n    var stackedDimInfo;\n    var stackResultDimension;\n    var stackedOverDimension;\n\n    each$1(dimensionInfoList, function (dimensionInfo, index) {\n        if (isString(dimensionInfo)) {\n            dimensionInfoList[index] = dimensionInfo = {name: dimensionInfo};\n        }\n\n        if (mayStack && !dimensionInfo.isExtraCoord) {\n            // Find the first ordinal dimension as the stackedByDimInfo.\n            if (!byIndex && !stackedByDimInfo && dimensionInfo.ordinalMeta) {\n                stackedByDimInfo = dimensionInfo;\n            }\n            // Find the first stackable dimension as the stackedDimInfo.\n            if (!stackedDimInfo\n                && dimensionInfo.type !== 'ordinal'\n                && dimensionInfo.type !== 'time'\n                && (!stackedCoordDimension || stackedCoordDimension === dimensionInfo.coordDim)\n            ) {\n                stackedDimInfo = dimensionInfo;\n            }\n        }\n    });\n\n    if (stackedDimInfo && !byIndex && !stackedByDimInfo) {\n        // Compatible with previous design, value axis (time axis) only stack by index.\n        // It may make sense if the user provides elaborately constructed data.\n        byIndex = true;\n    }\n\n    // Add stack dimension, they can be both calculated by coordinate system in `unionExtent`.\n    // That put stack logic in List is for using conveniently in echarts extensions, but it\n    // might not be a good way.\n    if (stackedDimInfo) {\n        // Use a weird name that not duplicated with other names.\n        stackResultDimension = '__\\0ecstackresult';\n        stackedOverDimension = '__\\0ecstackedover';\n\n        // Create inverted index to fast query index by value.\n        if (stackedByDimInfo) {\n            stackedByDimInfo.createInvertedIndices = true;\n        }\n\n        var stackedDimCoordDim = stackedDimInfo.coordDim;\n        var stackedDimType = stackedDimInfo.type;\n        var stackedDimCoordIndex = 0;\n\n        each$1(dimensionInfoList, function (dimensionInfo) {\n            if (dimensionInfo.coordDim === stackedDimCoordDim) {\n                stackedDimCoordIndex++;\n            }\n        });\n\n        dimensionInfoList.push({\n            name: stackResultDimension,\n            coordDim: stackedDimCoordDim,\n            coordDimIndex: stackedDimCoordIndex,\n            type: stackedDimType,\n            isExtraCoord: true,\n            isCalculationCoord: true\n        });\n\n        stackedDimCoordIndex++;\n\n        dimensionInfoList.push({\n            name: stackedOverDimension,\n            // This dimension contains stack base (generally, 0), so do not set it as\n            // `stackedDimCoordDim` to avoid extent calculation, consider log scale.\n            coordDim: stackedOverDimension,\n            coordDimIndex: stackedDimCoordIndex,\n            type: stackedDimType,\n            isExtraCoord: true,\n            isCalculationCoord: true\n        });\n    }\n\n    return {\n        stackedDimension: stackedDimInfo && stackedDimInfo.name,\n        stackedByDimension: stackedByDimInfo && stackedByDimInfo.name,\n        isStackedByIndex: byIndex,\n        stackedOverDimension: stackedOverDimension,\n        stackResultDimension: stackResultDimension\n    };\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {string} stackedDim\n */\nfunction isDimensionStacked(data, stackedDim /*, stackedByDim*/) {\n    // Each single series only maps to one pair of axis. So we do not need to\n    // check stackByDim, whatever stacked by a dimension or stacked by index.\n    return !!stackedDim && stackedDim === data.getCalculationInfo('stackedDimension');\n        // && (\n        //     stackedByDim != null\n        //         ? stackedByDim === data.getCalculationInfo('stackedByDimension')\n        //         : data.getCalculationInfo('isStackedByIndex')\n        // );\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {string} targetDim\n * @param {string} [stackedByDim] If not input this parameter, check whether\n *                                stacked by index.\n * @return {string} dimension\n */\nfunction getStackedDimension(data, targetDim) {\n    return isDimensionStacked(data, targetDim)\n        ? data.getCalculationInfo('stackResultDimension')\n        : targetDim;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/data/Source|Array} source Or raw data.\n * @param {module:echarts/model/Series} seriesModel\n * @param {Object} [opt]\n * @param {string} [opt.generateCoord]\n */\nfunction createListFromArray(source, seriesModel, opt) {\n    opt = opt || {};\n\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n\n    var coordSysName = seriesModel.get('coordinateSystem');\n    var registeredCoordSys = CoordinateSystemManager.get(coordSysName);\n\n    var coordSysDefine = getCoordSysDefineBySeries(seriesModel);\n\n    var coordSysDimDefs;\n\n    if (coordSysDefine) {\n        coordSysDimDefs = map(coordSysDefine.coordSysDims, function (dim) {\n            var dimInfo = {name: dim};\n            var axisModel = coordSysDefine.axisMap.get(dim);\n            if (axisModel) {\n                var axisType = axisModel.get('type');\n                dimInfo.type = getDimensionTypeByAxis(axisType);\n                // dimInfo.stackable = isStackable(axisType);\n            }\n            return dimInfo;\n        });\n    }\n\n    if (!coordSysDimDefs) {\n        // Get dimensions from registered coordinate system\n        coordSysDimDefs = (registeredCoordSys && (\n            registeredCoordSys.getDimensionsInfo\n                ? registeredCoordSys.getDimensionsInfo()\n                : registeredCoordSys.dimensions.slice()\n        )) || ['x', 'y'];\n    }\n\n    var dimInfoList = createDimensions(source, {\n        coordDimensions: coordSysDimDefs,\n        generateCoord: opt.generateCoord\n    });\n\n    var firstCategoryDimIndex;\n    var hasNameEncode;\n    coordSysDefine && each$1(dimInfoList, function (dimInfo, dimIndex) {\n        var coordDim = dimInfo.coordDim;\n        var categoryAxisModel = coordSysDefine.categoryAxisMap.get(coordDim);\n        if (categoryAxisModel) {\n            if (firstCategoryDimIndex == null) {\n                firstCategoryDimIndex = dimIndex;\n            }\n            dimInfo.ordinalMeta = categoryAxisModel.getOrdinalMeta();\n        }\n        if (dimInfo.otherDims.itemName != null) {\n            hasNameEncode = true;\n        }\n    });\n    if (!hasNameEncode && firstCategoryDimIndex != null) {\n        dimInfoList[firstCategoryDimIndex].otherDims.itemName = 0;\n    }\n\n    var stackCalculationInfo = enableDataStack(seriesModel, dimInfoList);\n\n    var list = new List(dimInfoList, seriesModel);\n\n    list.setCalculationInfo(stackCalculationInfo);\n\n    var dimValueGetter = (firstCategoryDimIndex != null && isNeedCompleteOrdinalData(source))\n        ? function (itemOpt, dimName, dataIndex, dimIndex) {\n            // Use dataIndex as ordinal value in categoryAxis\n            return dimIndex === firstCategoryDimIndex\n                ? dataIndex\n                : this.defaultDimValueGetter(itemOpt, dimName, dataIndex, dimIndex);\n        }\n        : null;\n\n    list.hasItemOption = false;\n    list.initData(source, null, dimValueGetter);\n\n    return list;\n}\n\nfunction isNeedCompleteOrdinalData(source) {\n    if (source.sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        var sampleItem = firstDataNotNull(source.data || []);\n        return sampleItem != null\n            && !isArray(getDataItemValue(sampleItem));\n    }\n}\n\nfunction firstDataNotNull(data) {\n    var i = 0;\n    while (i < data.length && data[i] == null) {\n        i++;\n    }\n    return data[i];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * // Scale class management\n * @module echarts/scale/Scale\n */\n\n/**\n * @param {Object} [setting]\n */\nfunction Scale(setting) {\n    this._setting = setting || {};\n\n    /**\n     * Extent\n     * @type {Array.<number>}\n     * @protected\n     */\n    this._extent = [Infinity, -Infinity];\n\n    /**\n     * Step is calculated in adjustExtent\n     * @type {Array.<number>}\n     * @protected\n     */\n    this._interval = 0;\n\n    this.init && this.init.apply(this, arguments);\n}\n\n/**\n * Parse input val to valid inner number.\n * @param {*} val\n * @return {number}\n */\nScale.prototype.parse = function (val) {\n    // Notice: This would be a trap here, If the implementation\n    // of this method depends on extent, and this method is used\n    // before extent set (like in dataZoom), it would be wrong.\n    // Nevertheless, parse does not depend on extent generally.\n    return val;\n};\n\nScale.prototype.getSetting = function (name) {\n    return this._setting[name];\n};\n\nScale.prototype.contain = function (val) {\n    var extent = this._extent;\n    return val >= extent[0] && val <= extent[1];\n};\n\n/**\n * Normalize value to linear [0, 1], return 0.5 if extent span is 0\n * @param {number} val\n * @return {number}\n */\nScale.prototype.normalize = function (val) {\n    var extent = this._extent;\n    if (extent[1] === extent[0]) {\n        return 0.5;\n    }\n    return (val - extent[0]) / (extent[1] - extent[0]);\n};\n\n/**\n * Scale normalized value\n * @param {number} val\n * @return {number}\n */\nScale.prototype.scale = function (val) {\n    var extent = this._extent;\n    return val * (extent[1] - extent[0]) + extent[0];\n};\n\n/**\n * Set extent from data\n * @param {Array.<number>} other\n */\nScale.prototype.unionExtent = function (other) {\n    var extent = this._extent;\n    other[0] < extent[0] && (extent[0] = other[0]);\n    other[1] > extent[1] && (extent[1] = other[1]);\n    // not setExtent because in log axis it may transformed to power\n    // this.setExtent(extent[0], extent[1]);\n};\n\n/**\n * Set extent from data\n * @param {module:echarts/data/List} data\n * @param {string} dim\n */\nScale.prototype.unionExtentFromData = function (data, dim) {\n    this.unionExtent(data.getApproximateExtent(dim));\n};\n\n/**\n * Get extent\n * @return {Array.<number>}\n */\nScale.prototype.getExtent = function () {\n    return this._extent.slice();\n};\n\n/**\n * Set extent\n * @param {number} start\n * @param {number} end\n */\nScale.prototype.setExtent = function (start, end) {\n    var thisExtent = this._extent;\n    if (!isNaN(start)) {\n        thisExtent[0] = start;\n    }\n    if (!isNaN(end)) {\n        thisExtent[1] = end;\n    }\n};\n\n/**\n * When axis extent depends on data and no data exists,\n * axis ticks should not be drawn, which is named 'blank'.\n */\nScale.prototype.isBlank = function () {\n    return this._isBlank;\n},\n\n/**\n * When axis extent depends on data and no data exists,\n * axis ticks should not be drawn, which is named 'blank'.\n */\nScale.prototype.setBlank = function (isBlank) {\n    this._isBlank = isBlank;\n};\n\n/**\n * @abstract\n * @param {*} tick\n * @return {string} label of the tick.\n */\nScale.prototype.getLabel = null;\n\n\nenableClassExtend(Scale);\nenableClassManagement(Scale, {\n    registerWhenExtend: true\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @constructor\n * @param {Object} [opt]\n * @param {Object} [opt.categories=[]]\n * @param {Object} [opt.needCollect=false]\n * @param {Object} [opt.deduplication=false]\n */\nfunction OrdinalMeta(opt) {\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    this.categories = opt.categories || [];\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._needCollect = opt.needCollect;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._deduplication = opt.deduplication;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._map;\n}\n\n/**\n * @param {module:echarts/model/Model} axisModel\n * @return {module:echarts/data/OrdinalMeta}\n */\nOrdinalMeta.createByAxisModel = function (axisModel) {\n    var option = axisModel.option;\n    var data = option.data;\n    var categories = data && map(data, getName);\n\n    return new OrdinalMeta({\n        categories: categories,\n        needCollect: !categories,\n        // deduplication is default in axis.\n        deduplication: option.dedplication !== false\n    });\n};\n\nvar proto$1 = OrdinalMeta.prototype;\n\n/**\n * @param {string} category\n * @return {number} ordinal\n */\nproto$1.getOrdinal = function (category) {\n    return getOrCreateMap(this).get(category);\n};\n\n/**\n * @param {*} category\n * @return {number} The ordinal. If not found, return NaN.\n */\nproto$1.parseAndCollect = function (category) {\n    var index;\n    var needCollect = this._needCollect;\n\n    // The value of category dim can be the index of the given category set.\n    // This feature is only supported when !needCollect, because we should\n    // consider a common case: a value is 2017, which is a number but is\n    // expected to be tread as a category. This case usually happen in dataset,\n    // where it happent to be no need of the index feature.\n    if (typeof category !== 'string' && !needCollect) {\n        return category;\n    }\n\n    // Optimize for the scenario:\n    // category is ['2012-01-01', '2012-01-02', ...], where the input\n    // data has been ensured not duplicate and is large data.\n    // Notice, if a dataset dimension provide categroies, usually echarts\n    // should remove duplication except user tell echarts dont do that\n    // (set axis.deduplication = false), because echarts do not know whether\n    // the values in the category dimension has duplication (consider the\n    // parallel-aqi example)\n    if (needCollect && !this._deduplication) {\n        index = this.categories.length;\n        this.categories[index] = category;\n        return index;\n    }\n\n    var map$$1 = getOrCreateMap(this);\n    index = map$$1.get(category);\n\n    if (index == null) {\n        if (needCollect) {\n            index = this.categories.length;\n            this.categories[index] = category;\n            map$$1.set(category, index);\n        }\n        else {\n            index = NaN;\n        }\n    }\n\n    return index;\n};\n\n// Consider big data, do not create map until needed.\nfunction getOrCreateMap(ordinalMeta) {\n    return ordinalMeta._map || (\n        ordinalMeta._map = createHashMap(ordinalMeta.categories)\n    );\n}\n\nfunction getName(obj) {\n    if (isObject$1(obj) && obj.value != null) {\n        return obj.value;\n    }\n    else {\n        return obj + '';\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Linear continuous scale\n * @module echarts/coord/scale/Ordinal\n *\n * http://en.wikipedia.org/wiki/Level_of_measurement\n */\n\n// FIXME only one data\n\nvar scaleProto = Scale.prototype;\n\nvar OrdinalScale = Scale.extend({\n\n    type: 'ordinal',\n\n    /**\n     * @param {module:echarts/data/OrdianlMeta|Array.<string>} ordinalMeta\n     */\n    init: function (ordinalMeta, extent) {\n        // Caution: Should not use instanceof, consider ec-extensions using\n        // import approach to get OrdinalMeta class.\n        if (!ordinalMeta || isArray(ordinalMeta)) {\n            ordinalMeta = new OrdinalMeta({categories: ordinalMeta});\n        }\n        this._ordinalMeta = ordinalMeta;\n        this._extent = extent || [0, ordinalMeta.categories.length - 1];\n    },\n\n    parse: function (val) {\n        return typeof val === 'string'\n            ? this._ordinalMeta.getOrdinal(val)\n            // val might be float.\n            : Math.round(val);\n    },\n\n    contain: function (rank) {\n        rank = this.parse(rank);\n        return scaleProto.contain.call(this, rank)\n            && this._ordinalMeta.categories[rank] != null;\n    },\n\n    /**\n     * Normalize given rank or name to linear [0, 1]\n     * @param {number|string} [val]\n     * @return {number}\n     */\n    normalize: function (val) {\n        return scaleProto.normalize.call(this, this.parse(val));\n    },\n\n    scale: function (val) {\n        return Math.round(scaleProto.scale.call(this, val));\n    },\n\n    /**\n     * @return {Array}\n     */\n    getTicks: function () {\n        var ticks = [];\n        var extent = this._extent;\n        var rank = extent[0];\n\n        while (rank <= extent[1]) {\n            ticks.push(rank);\n            rank++;\n        }\n\n        return ticks;\n    },\n\n    /**\n     * Get item on rank n\n     * @param {number} n\n     * @return {string}\n     */\n    getLabel: function (n) {\n        if (!this.isBlank()) {\n            // Note that if no data, ordinalMeta.categories is an empty array.\n            return this._ordinalMeta.categories[n];\n        }\n    },\n\n    /**\n     * @return {number}\n     */\n    count: function () {\n        return this._extent[1] - this._extent[0] + 1;\n    },\n\n    /**\n     * @override\n     */\n    unionExtentFromData: function (data, dim) {\n        this.unionExtent(data.getApproximateExtent(dim));\n    },\n\n    getOrdinalMeta: function () {\n        return this._ordinalMeta;\n    },\n\n    niceTicks: noop,\n    niceExtent: noop\n});\n\n/**\n * @return {module:echarts/scale/Time}\n */\nOrdinalScale.create = function () {\n    return new OrdinalScale();\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * For testable.\n */\n\nvar roundNumber$1 = round$2;\n\n/**\n * @param {Array.<number>} extent Both extent[0] and extent[1] should be valid number.\n *                                Should be extent[0] < extent[1].\n * @param {number} splitNumber splitNumber should be >= 1.\n * @param {number} [minInterval]\n * @param {number} [maxInterval]\n * @return {Object} {interval, intervalPrecision, niceTickExtent}\n */\nfunction intervalScaleNiceTicks(extent, splitNumber, minInterval, maxInterval) {\n    var result = {};\n    var span = extent[1] - extent[0];\n\n    var interval = result.interval = nice(span / splitNumber, true);\n    if (minInterval != null && interval < minInterval) {\n        interval = result.interval = minInterval;\n    }\n    if (maxInterval != null && interval > maxInterval) {\n        interval = result.interval = maxInterval;\n    }\n    // Tow more digital for tick.\n    var precision = result.intervalPrecision = getIntervalPrecision(interval);\n    // Niced extent inside original extent\n    var niceTickExtent = result.niceTickExtent = [\n        roundNumber$1(Math.ceil(extent[0] / interval) * interval, precision),\n        roundNumber$1(Math.floor(extent[1] / interval) * interval, precision)\n    ];\n\n    fixExtent(niceTickExtent, extent);\n\n    return result;\n}\n\n/**\n * @param {number} interval\n * @return {number} interval precision\n */\nfunction getIntervalPrecision(interval) {\n    // Tow more digital for tick.\n    return getPrecisionSafe(interval) + 2;\n}\n\nfunction clamp(niceTickExtent, idx, extent) {\n    niceTickExtent[idx] = Math.max(Math.min(niceTickExtent[idx], extent[1]), extent[0]);\n}\n\n// In some cases (e.g., splitNumber is 1), niceTickExtent may be out of extent.\nfunction fixExtent(niceTickExtent, extent) {\n    !isFinite(niceTickExtent[0]) && (niceTickExtent[0] = extent[0]);\n    !isFinite(niceTickExtent[1]) && (niceTickExtent[1] = extent[1]);\n    clamp(niceTickExtent, 0, extent);\n    clamp(niceTickExtent, 1, extent);\n    if (niceTickExtent[0] > niceTickExtent[1]) {\n        niceTickExtent[0] = niceTickExtent[1];\n    }\n}\n\nfunction intervalScaleGetTicks(interval, extent, niceTickExtent, intervalPrecision) {\n    var ticks = [];\n\n    // If interval is 0, return [];\n    if (!interval) {\n        return ticks;\n    }\n\n    // Consider this case: using dataZoom toolbox, zoom and zoom.\n    var safeLimit = 10000;\n\n    if (extent[0] < niceTickExtent[0]) {\n        ticks.push(extent[0]);\n    }\n    var tick = niceTickExtent[0];\n\n    while (tick <= niceTickExtent[1]) {\n        ticks.push(tick);\n        // Avoid rounding error\n        tick = roundNumber$1(tick + interval, intervalPrecision);\n        if (tick === ticks[ticks.length - 1]) {\n            // Consider out of safe float point, e.g.,\n            // -3711126.9907707 + 2e-10 === -3711126.9907707\n            break;\n        }\n        if (ticks.length > safeLimit) {\n            return [];\n        }\n    }\n    // Consider this case: the last item of ticks is smaller\n    // than niceTickExtent[1] and niceTickExtent[1] === extent[1].\n    if (extent[1] > (ticks.length ? ticks[ticks.length - 1] : niceTickExtent[1])) {\n        ticks.push(extent[1]);\n    }\n\n    return ticks;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Interval scale\n * @module echarts/scale/Interval\n */\n\n\nvar roundNumber = round$2;\n\n/**\n * @alias module:echarts/coord/scale/Interval\n * @constructor\n */\nvar IntervalScale = Scale.extend({\n\n    type: 'interval',\n\n    _interval: 0,\n\n    _intervalPrecision: 2,\n\n    setExtent: function (start, end) {\n        var thisExtent = this._extent;\n        //start,end may be a Number like '25',so...\n        if (!isNaN(start)) {\n            thisExtent[0] = parseFloat(start);\n        }\n        if (!isNaN(end)) {\n            thisExtent[1] = parseFloat(end);\n        }\n    },\n\n    unionExtent: function (other) {\n        var extent = this._extent;\n        other[0] < extent[0] && (extent[0] = other[0]);\n        other[1] > extent[1] && (extent[1] = other[1]);\n\n        // unionExtent may called by it's sub classes\n        IntervalScale.prototype.setExtent.call(this, extent[0], extent[1]);\n    },\n    /**\n     * Get interval\n     */\n    getInterval: function () {\n        return this._interval;\n    },\n\n    /**\n     * Set interval\n     */\n    setInterval: function (interval) {\n        this._interval = interval;\n        // Dropped auto calculated niceExtent and use user setted extent\n        // We assume user wan't to set both interval, min, max to get a better result\n        this._niceExtent = this._extent.slice();\n\n        this._intervalPrecision = getIntervalPrecision(interval);\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getTicks: function () {\n        return intervalScaleGetTicks(\n            this._interval, this._extent, this._niceExtent, this._intervalPrecision\n        );\n    },\n\n    /**\n     * @param {number} data\n     * @param {Object} [opt]\n     * @param {number|string} [opt.precision] If 'auto', use nice presision.\n     * @param {boolean} [opt.pad] returns 1.50 but not 1.5 if precision is 2.\n     * @return {string}\n     */\n    getLabel: function (data, opt) {\n        if (data == null) {\n            return '';\n        }\n\n        var precision = opt && opt.precision;\n\n        if (precision == null) {\n            precision = getPrecisionSafe(data) || 0;\n        }\n        else if (precision === 'auto') {\n            // Should be more precise then tick.\n            precision = this._intervalPrecision;\n        }\n\n        // (1) If `precision` is set, 12.005 should be display as '12.00500'.\n        // (2) Use roundNumber (toFixed) to avoid scientific notation like '3.5e-7'.\n        data = roundNumber(data, precision, true);\n\n        return addCommas(data);\n    },\n\n    /**\n     * Update interval and extent of intervals for nice ticks\n     *\n     * @param {number} [splitNumber = 5] Desired number of ticks\n     * @param {number} [minInterval]\n     * @param {number} [maxInterval]\n     */\n    niceTicks: function (splitNumber, minInterval, maxInterval) {\n        splitNumber = splitNumber || 5;\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        if (!isFinite(span)) {\n            return;\n        }\n        // User may set axis min 0 and data are all negative\n        // FIXME If it needs to reverse ?\n        if (span < 0) {\n            span = -span;\n            extent.reverse();\n        }\n\n        var result = intervalScaleNiceTicks(\n            extent, splitNumber, minInterval, maxInterval\n        );\n\n        this._intervalPrecision = result.intervalPrecision;\n        this._interval = result.interval;\n        this._niceExtent = result.niceTickExtent;\n    },\n\n    /**\n     * Nice extent.\n     * @param {Object} opt\n     * @param {number} [opt.splitNumber = 5] Given approx tick number\n     * @param {boolean} [opt.fixMin=false]\n     * @param {boolean} [opt.fixMax=false]\n     * @param {boolean} [opt.minInterval]\n     * @param {boolean} [opt.maxInterval]\n     */\n    niceExtent: function (opt) {\n        var extent = this._extent;\n        // If extent start and end are same, expand them\n        if (extent[0] === extent[1]) {\n            if (extent[0] !== 0) {\n                // Expand extent\n                var expandSize = extent[0];\n                // In the fowllowing case\n                //      Axis has been fixed max 100\n                //      Plus data are all 100 and axis extent are [100, 100].\n                // Extend to the both side will cause expanded max is larger than fixed max.\n                // So only expand to the smaller side.\n                if (!opt.fixMax) {\n                    extent[1] += expandSize / 2;\n                    extent[0] -= expandSize / 2;\n                }\n                else {\n                    extent[0] -= expandSize / 2;\n                }\n            }\n            else {\n                extent[1] = 1;\n            }\n        }\n        var span = extent[1] - extent[0];\n        // If there are no data and extent are [Infinity, -Infinity]\n        if (!isFinite(span)) {\n            extent[0] = 0;\n            extent[1] = 1;\n        }\n\n        this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);\n\n        // var extent = this._extent;\n        var interval = this._interval;\n\n        if (!opt.fixMin) {\n            extent[0] = roundNumber(Math.floor(extent[0] / interval) * interval);\n        }\n        if (!opt.fixMax) {\n            extent[1] = roundNumber(Math.ceil(extent[1] / interval) * interval);\n        }\n    }\n});\n\n/**\n * @return {module:echarts/scale/Time}\n */\nIntervalScale.create = function () {\n    return new IntervalScale();\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar STACK_PREFIX = '__ec_stack_';\nvar LARGE_BAR_MIN_WIDTH = 0.5;\n\nvar LargeArr = typeof Float32Array !== 'undefined' ? Float32Array : Array;\n\nfunction getSeriesStackId(seriesModel) {\n    return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex;\n}\n\nfunction getAxisKey(axis) {\n    return axis.dim + axis.index;\n}\n\n/**\n * @param {Object} opt\n * @param {module:echarts/coord/Axis} opt.axis Only support category axis currently.\n * @param {number} opt.count Positive interger.\n * @param {number} [opt.barWidth]\n * @param {number} [opt.barMaxWidth]\n * @param {number} [opt.barGap]\n * @param {number} [opt.barCategoryGap]\n * @return {Object} {width, offset, offsetCenter} If axis.type is not 'category', return undefined.\n */\n\n\nfunction prepareLayoutBarSeries(seriesType, ecModel) {\n    var seriesModels = [];\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        // Check series coordinate, do layout for cartesian2d only\n        if (isOnCartesian(seriesModel) && !isInLargeMode(seriesModel)) {\n            seriesModels.push(seriesModel);\n        }\n    });\n    return seriesModels;\n}\n\nfunction makeColumnLayout(barSeries) {\n    var seriesInfoList = [];\n    each$1(barSeries, function (seriesModel) {\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var axisExtent = baseAxis.getExtent();\n        var bandWidth = baseAxis.type === 'category'\n            ? baseAxis.getBandWidth()\n            : (Math.abs(axisExtent[1] - axisExtent[0]) / data.count());\n\n        var barWidth = parsePercent$1(\n            seriesModel.get('barWidth'), bandWidth\n        );\n        var barMaxWidth = parsePercent$1(\n            seriesModel.get('barMaxWidth'), bandWidth\n        );\n        var barGap = seriesModel.get('barGap');\n        var barCategoryGap = seriesModel.get('barCategoryGap');\n\n        seriesInfoList.push({\n            bandWidth: bandWidth,\n            barWidth: barWidth,\n            barMaxWidth: barMaxWidth,\n            barGap: barGap,\n            barCategoryGap: barCategoryGap,\n            axisKey: getAxisKey(baseAxis),\n            stackId: getSeriesStackId(seriesModel)\n        });\n    });\n\n    return doCalBarWidthAndOffset(seriesInfoList);\n}\n\nfunction doCalBarWidthAndOffset(seriesInfoList) {\n    // Columns info on each category axis. Key is cartesian name\n    var columnsMap = {};\n\n    each$1(seriesInfoList, function (seriesInfo, idx) {\n        var axisKey = seriesInfo.axisKey;\n        var bandWidth = seriesInfo.bandWidth;\n        var columnsOnAxis = columnsMap[axisKey] || {\n            bandWidth: bandWidth,\n            remainedWidth: bandWidth,\n            autoWidthCount: 0,\n            categoryGap: '20%',\n            gap: '30%',\n            stacks: {}\n        };\n        var stacks = columnsOnAxis.stacks;\n        columnsMap[axisKey] = columnsOnAxis;\n\n        var stackId = seriesInfo.stackId;\n\n        if (!stacks[stackId]) {\n            columnsOnAxis.autoWidthCount++;\n        }\n        stacks[stackId] = stacks[stackId] || {\n            width: 0,\n            maxWidth: 0\n        };\n\n        // Caution: In a single coordinate system, these barGrid attributes\n        // will be shared by series. Consider that they have default values,\n        // only the attributes set on the last series will work.\n        // Do not change this fact unless there will be a break change.\n\n        // TODO\n        var barWidth = seriesInfo.barWidth;\n        if (barWidth && !stacks[stackId].width) {\n            // See #6312, do not restrict width.\n            stacks[stackId].width = barWidth;\n            barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);\n            columnsOnAxis.remainedWidth -= barWidth;\n        }\n\n        var barMaxWidth = seriesInfo.barMaxWidth;\n        barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);\n        var barGap = seriesInfo.barGap;\n        (barGap != null) && (columnsOnAxis.gap = barGap);\n        var barCategoryGap = seriesInfo.barCategoryGap;\n        (barCategoryGap != null) && (columnsOnAxis.categoryGap = barCategoryGap);\n    });\n\n    var result = {};\n\n    each$1(columnsMap, function (columnsOnAxis, coordSysName) {\n\n        result[coordSysName] = {};\n\n        var stacks = columnsOnAxis.stacks;\n        var bandWidth = columnsOnAxis.bandWidth;\n        var categoryGap = parsePercent$1(columnsOnAxis.categoryGap, bandWidth);\n        var barGapPercent = parsePercent$1(columnsOnAxis.gap, 1);\n\n        var remainedWidth = columnsOnAxis.remainedWidth;\n        var autoWidthCount = columnsOnAxis.autoWidthCount;\n        var autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        // Find if any auto calculated bar exceeded maxBarWidth\n        each$1(stacks, function (column, stack) {\n            var maxWidth = column.maxWidth;\n            if (maxWidth && maxWidth < autoWidth) {\n                maxWidth = Math.min(maxWidth, remainedWidth);\n                if (column.width) {\n                    maxWidth = Math.min(maxWidth, column.width);\n                }\n                remainedWidth -= maxWidth;\n                column.width = maxWidth;\n                autoWidthCount--;\n            }\n        });\n\n        // Recalculate width again\n        autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        var widthSum = 0;\n        var lastColumn;\n        each$1(stacks, function (column, idx) {\n            if (!column.width) {\n                column.width = autoWidth;\n            }\n            lastColumn = column;\n            widthSum += column.width * (1 + barGapPercent);\n        });\n        if (lastColumn) {\n            widthSum -= lastColumn.width * barGapPercent;\n        }\n\n        var offset = -widthSum / 2;\n        each$1(stacks, function (column, stackId) {\n            result[coordSysName][stackId] = result[coordSysName][stackId] || {\n                offset: offset,\n                width: column.width\n            };\n\n            offset += column.width * (1 + barGapPercent);\n        });\n    });\n\n    return result;\n}\n\n/**\n * @param {Object} barWidthAndOffset The result of makeColumnLayout\n * @param {module:echarts/coord/Axis} axis\n * @param {module:echarts/model/Series} [seriesModel] If not provided, return all.\n * @return {Object} {stackId: {offset, width}} or {offset, width} if seriesModel provided.\n */\nfunction retrieveColumnLayout(barWidthAndOffset, axis, seriesModel) {\n    if (barWidthAndOffset && axis) {\n        var result = barWidthAndOffset[getAxisKey(axis)];\n        if (result != null && seriesModel != null) {\n            result = result[getSeriesStackId(seriesModel)];\n        }\n        return result;\n    }\n}\n\n/**\n * @param {string} seriesType\n * @param {module:echarts/model/Global} ecModel\n */\nfunction layout(seriesType, ecModel) {\n\n    var seriesModels = prepareLayoutBarSeries(seriesType, ecModel);\n    var barWidthAndOffset = makeColumnLayout(seriesModels);\n\n    var lastStackCoords = {};\n    each$1(seriesModels, function (seriesModel) {\n\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n\n        var stackId = getSeriesStackId(seriesModel);\n        var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId];\n        var columnOffset = columnLayoutInfo.offset;\n        var columnWidth = columnLayoutInfo.width;\n        var valueAxis = cartesian.getOtherAxis(baseAxis);\n\n        var barMinHeight = seriesModel.get('barMinHeight') || 0;\n\n        lastStackCoords[stackId] = lastStackCoords[stackId] || [];\n        data.setLayout({\n            offset: columnOffset,\n            size: columnWidth\n        });\n\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var stacked = isDimensionStacked(data, valueDim /*, baseDim*/);\n        var isValueAxisH = valueAxis.isHorizontal();\n\n        var valueAxisStart = getValueAxisStart(baseAxis, valueAxis, stacked);\n\n        for (var idx = 0, len = data.count(); idx < len; idx++) {\n            var value = data.get(valueDim, idx);\n            var baseValue = data.get(baseDim, idx);\n\n            if (isNaN(value)) {\n                continue;\n            }\n\n            var sign = value >= 0 ? 'p' : 'n';\n            var baseCoord = valueAxisStart;\n\n            // Because of the barMinHeight, we can not use the value in\n            // stackResultDimension directly.\n            if (stacked) {\n                // Only ordinal axis can be stacked.\n                if (!lastStackCoords[stackId][baseValue]) {\n                    lastStackCoords[stackId][baseValue] = {\n                        p: valueAxisStart, // Positive stack\n                        n: valueAxisStart  // Negative stack\n                    };\n                }\n                // Should also consider #4243\n                baseCoord = lastStackCoords[stackId][baseValue][sign];\n            }\n\n            var x;\n            var y;\n            var width;\n            var height;\n\n            if (isValueAxisH) {\n                var coord = cartesian.dataToPoint([value, baseValue]);\n                x = baseCoord;\n                y = coord[1] + columnOffset;\n                width = coord[0] - valueAxisStart;\n                height = columnWidth;\n\n                if (Math.abs(width) < barMinHeight) {\n                    width = (width < 0 ? -1 : 1) * barMinHeight;\n                }\n                stacked && (lastStackCoords[stackId][baseValue][sign] += width);\n            }\n            else {\n                var coord = cartesian.dataToPoint([baseValue, value]);\n                x = coord[0] + columnOffset;\n                y = baseCoord;\n                width = columnWidth;\n                height = coord[1] - valueAxisStart;\n\n                if (Math.abs(height) < barMinHeight) {\n                    // Include zero to has a positive bar\n                    height = (height <= 0 ? -1 : 1) * barMinHeight;\n                }\n                stacked && (lastStackCoords[stackId][baseValue][sign] += height);\n            }\n\n            data.setItemLayout(idx, {\n                x: x,\n                y: y,\n                width: width,\n                height: height\n            });\n        }\n\n    }, this);\n}\n\n// TODO: Do not support stack in large mode yet.\nvar largeLayout = {\n\n    seriesType: 'bar',\n\n    plan: createRenderPlanner(),\n\n    reset: function (seriesModel) {\n        if (!isOnCartesian(seriesModel) || !isInLargeMode(seriesModel)) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var valueAxis = cartesian.getOtherAxis(baseAxis);\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var valueAxisHorizontal = valueAxis.isHorizontal();\n        var valueDimIdx = valueAxisHorizontal ? 0 : 1;\n\n        var barWidth = retrieveColumnLayout(\n            makeColumnLayout([seriesModel]), baseAxis, seriesModel\n        ).width;\n        if (!(barWidth > LARGE_BAR_MIN_WIDTH)) { // jshint ignore:line\n            barWidth = LARGE_BAR_MIN_WIDTH;\n        }\n\n        return {progress: progress};\n\n        function progress(params, data) {\n            var largePoints = new LargeArr(params.count * 2);\n            var dataIndex;\n            var coord = [];\n            var valuePair = [];\n            var offset = 0;\n\n            while ((dataIndex = params.next()) != null) {\n                valuePair[valueDimIdx] = data.get(valueDim, dataIndex);\n                valuePair[1 - valueDimIdx] = data.get(baseDim, dataIndex);\n\n                coord = cartesian.dataToPoint(valuePair, null, coord);\n                largePoints[offset++] = coord[0];\n                largePoints[offset++] = coord[1];\n            }\n\n            data.setLayout({\n                largePoints: largePoints,\n                barWidth: barWidth,\n                valueAxisStart: getValueAxisStart(baseAxis, valueAxis, false),\n                valueAxisHorizontal: valueAxisHorizontal\n            });\n        }\n    }\n};\n\nfunction isOnCartesian(seriesModel) {\n    return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d';\n}\n\nfunction isInLargeMode(seriesModel) {\n    return seriesModel.pipelineContext && seriesModel.pipelineContext.large;\n}\n\n// See cases in `test/bar-start.html` and `#7412`, `#8747`.\nfunction getValueAxisStart(baseAxis, valueAxis, stacked) {\n    var extent = valueAxis.getGlobalExtent();\n    var min;\n    var max;\n    if (extent[0] > extent[1]) {\n        min = extent[1];\n        max = extent[0];\n    }\n    else {\n        min = extent[0];\n        max = extent[1];\n    }\n\n    var valueStart = valueAxis.toGlobalCoord(valueAxis.dataToCoord(0));\n    valueStart < min && (valueStart = min);\n    valueStart > max && (valueStart = max);\n\n    return valueStart;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The \"scaleLevels\" was originally copied from \"d3.js\" with some\n* modifications made for this project.\n* (See more details in the comment on the definition of \"scaleLevels\" below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\n\n// [About UTC and local time zone]:\n// In most cases, `number.parseDate` will treat input data string as local time\n// (except time zone is specified in time string). And `format.formateTime` returns\n// local time by default. option.useUTC is false by default. This design have\n// concidered these common case:\n// (1) Time that is persistent in server is in UTC, but it is needed to be diplayed\n// in local time by default.\n// (2) By default, the input data string (e.g., '2011-01-02') should be displayed\n// as its original time, without any time difference.\n\nvar intervalScaleProto = IntervalScale.prototype;\n\nvar mathCeil = Math.ceil;\nvar mathFloor = Math.floor;\nvar ONE_SECOND = 1000;\nvar ONE_MINUTE = ONE_SECOND * 60;\nvar ONE_HOUR = ONE_MINUTE * 60;\nvar ONE_DAY = ONE_HOUR * 24;\n\n// FIXME 公用？\nvar bisect = function (a, x, lo, hi) {\n    while (lo < hi) {\n        var mid = lo + hi >>> 1;\n        if (a[mid][1] < x) {\n            lo = mid + 1;\n        }\n        else {\n            hi = mid;\n        }\n    }\n    return lo;\n};\n\n/**\n * @alias module:echarts/coord/scale/Time\n * @constructor\n */\nvar TimeScale = IntervalScale.extend({\n    type: 'time',\n\n    /**\n     * @override\n     */\n    getLabel: function (val) {\n        var stepLvl = this._stepLvl;\n\n        var date = new Date(val);\n\n        return formatTime(stepLvl[0], date, this.getSetting('useUTC'));\n    },\n\n    /**\n     * @override\n     */\n    niceExtent: function (opt) {\n        var extent = this._extent;\n        // If extent start and end are same, expand them\n        if (extent[0] === extent[1]) {\n            // Expand extent\n            extent[0] -= ONE_DAY;\n            extent[1] += ONE_DAY;\n        }\n        // If there are no data and extent are [Infinity, -Infinity]\n        if (extent[1] === -Infinity && extent[0] === Infinity) {\n            var d = new Date();\n            extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate());\n            extent[0] = extent[1] - ONE_DAY;\n        }\n\n        this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);\n\n        // var extent = this._extent;\n        var interval = this._interval;\n\n        if (!opt.fixMin) {\n            extent[0] = round$2(mathFloor(extent[0] / interval) * interval);\n        }\n        if (!opt.fixMax) {\n            extent[1] = round$2(mathCeil(extent[1] / interval) * interval);\n        }\n    },\n\n    /**\n     * @override\n     */\n    niceTicks: function (approxTickNum, minInterval, maxInterval) {\n        approxTickNum = approxTickNum || 10;\n\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        var approxInterval = span / approxTickNum;\n\n        if (minInterval != null && approxInterval < minInterval) {\n            approxInterval = minInterval;\n        }\n        if (maxInterval != null && approxInterval > maxInterval) {\n            approxInterval = maxInterval;\n        }\n\n        var scaleLevelsLen = scaleLevels.length;\n        var idx = bisect(scaleLevels, approxInterval, 0, scaleLevelsLen);\n\n        var level = scaleLevels[Math.min(idx, scaleLevelsLen - 1)];\n        var interval = level[1];\n        // Same with interval scale if span is much larger than 1 year\n        if (level[0] === 'year') {\n            var yearSpan = span / interval;\n\n            // From \"Nice Numbers for Graph Labels\" of Graphic Gems\n            // var niceYearSpan = numberUtil.nice(yearSpan, false);\n            var yearStep = nice(yearSpan / approxTickNum, true);\n\n            interval *= yearStep;\n        }\n\n        var timezoneOffset = this.getSetting('useUTC')\n            ? 0 : (new Date(+extent[0] || +extent[1])).getTimezoneOffset() * 60 * 1000;\n        var niceExtent = [\n            Math.round(mathCeil((extent[0] - timezoneOffset) / interval) * interval + timezoneOffset),\n            Math.round(mathFloor((extent[1] - timezoneOffset) / interval) * interval + timezoneOffset)\n        ];\n\n        fixExtent(niceExtent, extent);\n\n        this._stepLvl = level;\n        // Interval will be used in getTicks\n        this._interval = interval;\n        this._niceExtent = niceExtent;\n    },\n\n    parse: function (val) {\n        // val might be float.\n        return +parseDate(val);\n    }\n});\n\neach$1(['contain', 'normalize'], function (methodName) {\n    TimeScale.prototype[methodName] = function (val) {\n        return intervalScaleProto[methodName].call(this, this.parse(val));\n    };\n});\n\n/**\n * This implementation was originally copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/b516d77fb8566b576088e73410437494717ada26/src/time/scale.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n */\nvar scaleLevels = [\n    // Format              interval\n    ['hh:mm:ss', ONE_SECOND],          // 1s\n    ['hh:mm:ss', ONE_SECOND * 5],      // 5s\n    ['hh:mm:ss', ONE_SECOND * 10],     // 10s\n    ['hh:mm:ss', ONE_SECOND * 15],     // 15s\n    ['hh:mm:ss', ONE_SECOND * 30],     // 30s\n    ['hh:mm\\nMM-dd', ONE_MINUTE],      // 1m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 5],  // 5m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 10], // 10m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 15], // 15m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 30], // 30m\n    ['hh:mm\\nMM-dd', ONE_HOUR],        // 1h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 2],    // 2h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 6],    // 6h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 12],   // 12h\n    ['MM-dd\\nyyyy', ONE_DAY],          // 1d\n    ['MM-dd\\nyyyy', ONE_DAY * 2],      // 2d\n    ['MM-dd\\nyyyy', ONE_DAY * 3],      // 3d\n    ['MM-dd\\nyyyy', ONE_DAY * 4],      // 4d\n    ['MM-dd\\nyyyy', ONE_DAY * 5],      // 5d\n    ['MM-dd\\nyyyy', ONE_DAY * 6],      // 6d\n    ['week', ONE_DAY * 7],             // 7d\n    ['MM-dd\\nyyyy', ONE_DAY * 10],     // 10d\n    ['week', ONE_DAY * 14],            // 2w\n    ['week', ONE_DAY * 21],            // 3w\n    ['month', ONE_DAY * 31],           // 1M\n    ['week', ONE_DAY * 42],            // 6w\n    ['month', ONE_DAY * 62],           // 2M\n    ['week', ONE_DAY * 70],            // 10w\n    ['quarter', ONE_DAY * 95],         // 3M\n    ['month', ONE_DAY * 31 * 4],       // 4M\n    ['month', ONE_DAY * 31 * 5],       // 5M\n    ['half-year', ONE_DAY * 380 / 2],  // 6M\n    ['month', ONE_DAY * 31 * 8],       // 8M\n    ['month', ONE_DAY * 31 * 10],      // 10M\n    ['year', ONE_DAY * 380]            // 1Y\n];\n\n/**\n * @param {module:echarts/model/Model}\n * @return {module:echarts/scale/Time}\n */\nTimeScale.create = function (model) {\n    return new TimeScale({useUTC: model.ecModel.get('useUTC')});\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Log scale\n * @module echarts/scale/Log\n */\n\n// Use some method of IntervalScale\nvar scaleProto$1 = Scale.prototype;\nvar intervalScaleProto$1 = IntervalScale.prototype;\n\nvar getPrecisionSafe$1 = getPrecisionSafe;\nvar roundingErrorFix = round$2;\n\nvar mathFloor$1 = Math.floor;\nvar mathCeil$1 = Math.ceil;\nvar mathPow$1 = Math.pow;\n\nvar mathLog = Math.log;\n\nvar LogScale = Scale.extend({\n\n    type: 'log',\n\n    base: 10,\n\n    $constructor: function () {\n        Scale.apply(this, arguments);\n        this._originalScale = new IntervalScale();\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getTicks: function () {\n        var originalScale = this._originalScale;\n        var extent = this._extent;\n        var originalExtent = originalScale.getExtent();\n\n        return map(intervalScaleProto$1.getTicks.call(this), function (val) {\n            var powVal = round$2(mathPow$1(this.base, val));\n\n            // Fix #4158\n            powVal = (val === extent[0] && originalScale.__fixMin)\n                ? fixRoundingError(powVal, originalExtent[0])\n                : powVal;\n            powVal = (val === extent[1] && originalScale.__fixMax)\n                ? fixRoundingError(powVal, originalExtent[1])\n                : powVal;\n\n            return powVal;\n        }, this);\n    },\n\n    /**\n     * @param {number} val\n     * @return {string}\n     */\n    getLabel: intervalScaleProto$1.getLabel,\n\n    /**\n     * @param  {number} val\n     * @return {number}\n     */\n    scale: function (val) {\n        val = scaleProto$1.scale.call(this, val);\n        return mathPow$1(this.base, val);\n    },\n\n    /**\n     * @param {number} start\n     * @param {number} end\n     */\n    setExtent: function (start, end) {\n        var base = this.base;\n        start = mathLog(start) / mathLog(base);\n        end = mathLog(end) / mathLog(base);\n        intervalScaleProto$1.setExtent.call(this, start, end);\n    },\n\n    /**\n     * @return {number} end\n     */\n    getExtent: function () {\n        var base = this.base;\n        var extent = scaleProto$1.getExtent.call(this);\n        extent[0] = mathPow$1(base, extent[0]);\n        extent[1] = mathPow$1(base, extent[1]);\n\n        // Fix #4158\n        var originalScale = this._originalScale;\n        var originalExtent = originalScale.getExtent();\n        originalScale.__fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0]));\n        originalScale.__fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1]));\n\n        return extent;\n    },\n\n    /**\n     * @param  {Array.<number>} extent\n     */\n    unionExtent: function (extent) {\n        this._originalScale.unionExtent(extent);\n\n        var base = this.base;\n        extent[0] = mathLog(extent[0]) / mathLog(base);\n        extent[1] = mathLog(extent[1]) / mathLog(base);\n        scaleProto$1.unionExtent.call(this, extent);\n    },\n\n    /**\n     * @override\n     */\n    unionExtentFromData: function (data, dim) {\n        // TODO\n        // filter value that <= 0\n        this.unionExtent(data.getApproximateExtent(dim));\n    },\n\n    /**\n     * Update interval and extent of intervals for nice ticks\n     * @param  {number} [approxTickNum = 10] Given approx tick number\n     */\n    niceTicks: function (approxTickNum) {\n        approxTickNum = approxTickNum || 10;\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        if (span === Infinity || span <= 0) {\n            return;\n        }\n\n        var interval = quantity(span);\n        var err = approxTickNum / span * interval;\n\n        // Filter ticks to get closer to the desired count.\n        if (err <= 0.5) {\n            interval *= 10;\n        }\n\n        // Interval should be integer\n        while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) {\n            interval *= 10;\n        }\n\n        var niceExtent = [\n            round$2(mathCeil$1(extent[0] / interval) * interval),\n            round$2(mathFloor$1(extent[1] / interval) * interval)\n        ];\n\n        this._interval = interval;\n        this._niceExtent = niceExtent;\n    },\n\n    /**\n     * Nice extent.\n     * @override\n     */\n    niceExtent: function (opt) {\n        intervalScaleProto$1.niceExtent.call(this, opt);\n\n        var originalScale = this._originalScale;\n        originalScale.__fixMin = opt.fixMin;\n        originalScale.__fixMax = opt.fixMax;\n    }\n\n});\n\neach$1(['contain', 'normalize'], function (methodName) {\n    LogScale.prototype[methodName] = function (val) {\n        val = mathLog(val) / mathLog(this.base);\n        return scaleProto$1[methodName].call(this, val);\n    };\n});\n\nLogScale.create = function () {\n    return new LogScale();\n};\n\nfunction fixRoundingError(val, originalVal) {\n    return roundingErrorFix(val, getPrecisionSafe$1(originalVal));\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Get axis scale extent before niced.\n * Item of returned array can only be number (including Infinity and NaN).\n */\nfunction getScaleExtent(scale, model) {\n    var scaleType = scale.type;\n\n    var min = model.getMin();\n    var max = model.getMax();\n    var fixMin = min != null;\n    var fixMax = max != null;\n    var originalExtent = scale.getExtent();\n\n    var axisDataLen;\n    var boundaryGap;\n    var span;\n    if (scaleType === 'ordinal') {\n        axisDataLen = model.getCategories().length;\n    }\n    else {\n        boundaryGap = model.get('boundaryGap');\n        if (!isArray(boundaryGap)) {\n            boundaryGap = [boundaryGap || 0, boundaryGap || 0];\n        }\n        if (typeof boundaryGap[0] === 'boolean') {\n            if (__DEV__) {\n                console.warn('Boolean type for boundaryGap is only '\n                    + 'allowed for ordinal axis. Please use string in '\n                    + 'percentage instead, e.g., \"20%\". Currently, '\n                    + 'boundaryGap is set to be 0.');\n            }\n            boundaryGap = [0, 0];\n        }\n        boundaryGap[0] = parsePercent$1(boundaryGap[0], 1);\n        boundaryGap[1] = parsePercent$1(boundaryGap[1], 1);\n        span = (originalExtent[1] - originalExtent[0])\n            || Math.abs(originalExtent[0]);\n    }\n\n    // Notice: When min/max is not set (that is, when there are null/undefined,\n    // which is the most common case), these cases should be ensured:\n    // (1) For 'ordinal', show all axis.data.\n    // (2) For others:\n    //      + `boundaryGap` is applied (if min/max set, boundaryGap is\n    //      disabled).\n    //      + If `needCrossZero`, min/max should be zero, otherwise, min/max should\n    //      be the result that originalExtent enlarged by boundaryGap.\n    // (3) If no data, it should be ensured that `scale.setBlank` is set.\n\n    // FIXME\n    // (1) When min/max is 'dataMin' or 'dataMax', should boundaryGap be able to used?\n    // (2) When `needCrossZero` and all data is positive/negative, should it be ensured\n    // that the results processed by boundaryGap are positive/negative?\n\n    if (min == null) {\n        min = scaleType === 'ordinal'\n            ? (axisDataLen ? 0 : NaN)\n            : originalExtent[0] - boundaryGap[0] * span;\n    }\n    if (max == null) {\n        max = scaleType === 'ordinal'\n            ? (axisDataLen ? axisDataLen - 1 : NaN)\n            : originalExtent[1] + boundaryGap[1] * span;\n    }\n\n    if (min === 'dataMin') {\n        min = originalExtent[0];\n    }\n    else if (typeof min === 'function') {\n        min = min({\n            min: originalExtent[0],\n            max: originalExtent[1]\n        });\n    }\n\n    if (max === 'dataMax') {\n        max = originalExtent[1];\n    }\n    else if (typeof max === 'function') {\n        max = max({\n            min: originalExtent[0],\n            max: originalExtent[1]\n        });\n    }\n\n    (min == null || !isFinite(min)) && (min = NaN);\n    (max == null || !isFinite(max)) && (max = NaN);\n\n    scale.setBlank(\n        eqNaN(min)\n        || eqNaN(max)\n        || (scaleType === 'ordinal' && !scale.getOrdinalMeta().categories.length)\n    );\n\n    // Evaluate if axis needs cross zero\n    if (model.getNeedCrossZero()) {\n        // Axis is over zero and min is not set\n        if (min > 0 && max > 0 && !fixMin) {\n            min = 0;\n        }\n        // Axis is under zero and max is not set\n        if (min < 0 && max < 0 && !fixMax) {\n            max = 0;\n        }\n    }\n\n    // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis\n    // is base axis\n    // FIXME\n    // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly.\n    // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent?\n    //     Should not depend on series type `bar`?\n    // (3) Fix that might overlap when using dataZoom.\n    // (4) Consider other chart types using `barGrid`?\n    // See #6728, #4862, `test/bar-overflow-time-plot.html`\n    var ecModel = model.ecModel;\n    if (ecModel && (scaleType === 'time' /*|| scaleType === 'interval' */)) {\n        var barSeriesModels = prepareLayoutBarSeries('bar', ecModel);\n        var isBaseAxisAndHasBarSeries;\n\n        each$1(barSeriesModels, function (seriesModel) {\n            isBaseAxisAndHasBarSeries |= seriesModel.getBaseAxis() === model.axis;\n        });\n\n        if (isBaseAxisAndHasBarSeries) {\n            // Calculate placement of bars on axis\n            var barWidthAndOffset = makeColumnLayout(barSeriesModels);\n\n            // Adjust axis min and max to account for overflow\n            var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset);\n            min = adjustedScale.min;\n            max = adjustedScale.max;\n        }\n    }\n\n    return [min, max];\n}\n\nfunction adjustScaleForOverflow(min, max, model, barWidthAndOffset) {\n\n    // Get Axis Length\n    var axisExtent = model.axis.getExtent();\n    var axisLength = axisExtent[1] - axisExtent[0];\n\n    // Get bars on current base axis and calculate min and max overflow\n    var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis);\n    if (barsOnCurrentAxis === undefined) {\n        return {min: min, max: max};\n    }\n\n    var minOverflow = Infinity;\n    each$1(barsOnCurrentAxis, function (item) {\n        minOverflow = Math.min(item.offset, minOverflow);\n    });\n    var maxOverflow = -Infinity;\n    each$1(barsOnCurrentAxis, function (item) {\n        maxOverflow = Math.max(item.offset + item.width, maxOverflow);\n    });\n    minOverflow = Math.abs(minOverflow);\n    maxOverflow = Math.abs(maxOverflow);\n    var totalOverFlow = minOverflow + maxOverflow;\n\n    // Calulate required buffer based on old range and overflow\n    var oldRange = max - min;\n    var oldRangePercentOfNew = (1 - (minOverflow + maxOverflow) / axisLength);\n    var overflowBuffer = ((oldRange / oldRangePercentOfNew) - oldRange);\n\n    max += overflowBuffer * (maxOverflow / totalOverFlow);\n    min -= overflowBuffer * (minOverflow / totalOverFlow);\n\n    return {min: min, max: max};\n}\n\nfunction niceScaleExtent(scale, model) {\n    var extent = getScaleExtent(scale, model);\n    var fixMin = model.getMin() != null;\n    var fixMax = model.getMax() != null;\n    var splitNumber = model.get('splitNumber');\n\n    if (scale.type === 'log') {\n        scale.base = model.get('logBase');\n    }\n\n    var scaleType = scale.type;\n    scale.setExtent(extent[0], extent[1]);\n    scale.niceExtent({\n        splitNumber: splitNumber,\n        fixMin: fixMin,\n        fixMax: fixMax,\n        minInterval: (scaleType === 'interval' || scaleType === 'time')\n            ? model.get('minInterval') : null,\n        maxInterval: (scaleType === 'interval' || scaleType === 'time')\n            ? model.get('maxInterval') : null\n    });\n\n    // If some one specified the min, max. And the default calculated interval\n    // is not good enough. He can specify the interval. It is often appeared\n    // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard\n    // to be 60.\n    // FIXME\n    var interval = model.get('interval');\n    if (interval != null) {\n        scale.setInterval && scale.setInterval(interval);\n    }\n}\n\n/**\n * @param {module:echarts/model/Model} model\n * @param {string} [axisType] Default retrieve from model.type\n * @return {module:echarts/scale/*}\n */\nfunction createScaleByModel(model, axisType) {\n    axisType = axisType || model.get('type');\n    if (axisType) {\n        switch (axisType) {\n            // Buildin scale\n            case 'category':\n                return new OrdinalScale(\n                    model.getOrdinalMeta\n                        ? model.getOrdinalMeta()\n                        : model.getCategories(),\n                    [Infinity, -Infinity]\n                );\n            case 'value':\n                return new IntervalScale();\n            // Extended scale, like time and log\n            default:\n                return (Scale.getClass(axisType) || IntervalScale).create(model);\n        }\n    }\n}\n\n/**\n * Check if the axis corss 0\n */\nfunction ifAxisCrossZero(axis) {\n    var dataExtent = axis.scale.getExtent();\n    var min = dataExtent[0];\n    var max = dataExtent[1];\n    return !((min > 0 && max > 0) || (min < 0 && max < 0));\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @return {Function} Label formatter function.\n *         param: {number} tickValue,\n *         param: {number} idx, the index in all ticks.\n *                         If category axis, this param is not requied.\n *         return: {string} label string.\n */\nfunction makeLabelFormatter(axis) {\n    var labelFormatter = axis.getLabelModel().get('formatter');\n    var categoryTickStart = axis.type === 'category' ? axis.scale.getExtent()[0] : null;\n\n    if (typeof labelFormatter === 'string') {\n        labelFormatter = (function (tpl) {\n            return function (val) {\n                // For category axis, get raw value; for numeric axis,\n                // get foramtted label like '1,333,444'.\n                val = axis.scale.getLabel(val);\n                return tpl.replace('{value}', val != null ? val : '');\n            };\n        })(labelFormatter);\n        // Consider empty array\n        return labelFormatter;\n    }\n    else if (typeof labelFormatter === 'function') {\n        return function (tickValue, idx) {\n            // The original intention of `idx` is \"the index of the tick in all ticks\".\n            // But the previous implementation of category axis do not consider the\n            // `axisLabel.interval`, which cause that, for example, the `interval` is\n            // `1`, then the ticks \"name5\", \"name7\", \"name9\" are displayed, where the\n            // corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep\n            // the definition here for back compatibility.\n            if (categoryTickStart != null) {\n                idx = tickValue - categoryTickStart;\n            }\n            return labelFormatter(getAxisRawValue(axis, tickValue), idx);\n        };\n    }\n    else {\n        return function (tick) {\n            return axis.scale.getLabel(tick);\n        };\n    }\n}\n\nfunction getAxisRawValue(axis, value) {\n    // In category axis with data zoom, tick is not the original\n    // index of axis.data. So tick should not be exposed to user\n    // in category axis.\n    return axis.type === 'category' ? axis.scale.getLabel(value) : value;\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @return {module:zrender/core/BoundingRect} Be null/undefined if no labels.\n */\nfunction estimateLabelUnionRect(axis) {\n    var axisModel = axis.model;\n    var scale = axis.scale;\n\n    if (!axisModel.get('axisLabel.show') || scale.isBlank()) {\n        return;\n    }\n\n    var isCategory = axis.type === 'category';\n\n    var realNumberScaleTicks;\n    var tickCount;\n    var categoryScaleExtent = scale.getExtent();\n\n    // Optimize for large category data, avoid call `getTicks()`.\n    if (isCategory) {\n        tickCount = scale.count();\n    }\n    else {\n        realNumberScaleTicks = scale.getTicks();\n        tickCount = realNumberScaleTicks.length;\n    }\n\n    var axisLabelModel = axis.getLabelModel();\n    var labelFormatter = makeLabelFormatter(axis);\n\n    var rect;\n    var step = 1;\n    // Simple optimization for large amount of labels\n    if (tickCount > 40) {\n        step = Math.ceil(tickCount / 40);\n    }\n    for (var i = 0; i < tickCount; i += step) {\n        var tickValue = realNumberScaleTicks ? realNumberScaleTicks[i] : categoryScaleExtent[0] + i;\n        var label = labelFormatter(tickValue);\n        var unrotatedSingleRect = axisLabelModel.getTextRect(label);\n        var singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0);\n\n        rect ? rect.union(singleRect) : (rect = singleRect);\n    }\n\n    return rect;\n}\n\nfunction rotateTextRect(textRect, rotate) {\n    var rotateRadians = rotate * Math.PI / 180;\n    var boundingBox = textRect.plain();\n    var beforeWidth = boundingBox.width;\n    var beforeHeight = boundingBox.height;\n    var afterWidth = beforeWidth * Math.cos(rotateRadians) + beforeHeight * Math.sin(rotateRadians);\n    var afterHeight = beforeWidth * Math.sin(rotateRadians) + beforeHeight * Math.cos(rotateRadians);\n    var rotatedRect = new BoundingRect(boundingBox.x, boundingBox.y, afterWidth, afterHeight);\n\n    return rotatedRect;\n}\n\n/**\n * @param {module:echarts/src/model/Model} model axisLabelModel or axisTickModel\n * @return {number|String} Can be null|'auto'|number|function\n */\nfunction getOptionCategoryInterval(model) {\n    var interval = model.get('interval');\n    return interval == null ? 'auto' : interval;\n}\n\n/**\n * Set `categoryInterval` as 0 implicitly indicates that\n * show all labels reguardless of overlap.\n * @param {Object} axis axisModel.axis\n * @return {boolean}\n */\nfunction shouldShowAllLabels(axis) {\n    return axis.type === 'category'\n        && getOptionCategoryInterval(axis.getLabelModel()) === 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import * as axisHelper from './axisHelper';\n\nvar axisModelCommonMixin = {\n\n    /**\n     * @param {boolean} origin\n     * @return {number|string} min value or 'dataMin' or null/undefined (means auto) or NaN\n     */\n    getMin: function (origin) {\n        var option = this.option;\n        var min = (!origin && option.rangeStart != null)\n            ? option.rangeStart : option.min;\n\n        if (this.axis\n            && min != null\n            && min !== 'dataMin'\n            && typeof min !== 'function'\n            && !eqNaN(min)\n        ) {\n            min = this.axis.scale.parse(min);\n        }\n        return min;\n    },\n\n    /**\n     * @param {boolean} origin\n     * @return {number|string} max value or 'dataMax' or null/undefined (means auto) or NaN\n     */\n    getMax: function (origin) {\n        var option = this.option;\n        var max = (!origin && option.rangeEnd != null)\n            ? option.rangeEnd : option.max;\n\n        if (this.axis\n            && max != null\n            && max !== 'dataMax'\n            && typeof max !== 'function'\n            && !eqNaN(max)\n        ) {\n            max = this.axis.scale.parse(max);\n        }\n        return max;\n    },\n\n    /**\n     * @return {boolean}\n     */\n    getNeedCrossZero: function () {\n        var option = this.option;\n        return (option.rangeStart != null || option.rangeEnd != null)\n            ? false : !option.scale;\n    },\n\n    /**\n     * Should be implemented by each axis model if necessary.\n     * @return {module:echarts/model/Component} coordinate system model\n     */\n    getCoordSysModel: noop,\n\n    /**\n     * @param {number} rangeStart Can only be finite number or null/undefined or NaN.\n     * @param {number} rangeEnd Can only be finite number or null/undefined or NaN.\n     */\n    setRange: function (rangeStart, rangeEnd) {\n        this.option.rangeStart = rangeStart;\n        this.option.rangeEnd = rangeEnd;\n    },\n\n    /**\n     * Reset range\n     */\n    resetRange: function () {\n        // rangeStart and rangeEnd is readonly.\n        this.option.rangeStart = this.option.rangeEnd = null;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Symbol factory\n\n/**\n * Triangle shape\n * @inner\n */\nvar Triangle = extendShape({\n    type: 'triangle',\n    shape: {\n        cx: 0,\n        cy: 0,\n        width: 0,\n        height: 0\n    },\n    buildPath: function (path, shape) {\n        var cx = shape.cx;\n        var cy = shape.cy;\n        var width = shape.width / 2;\n        var height = shape.height / 2;\n        path.moveTo(cx, cy - height);\n        path.lineTo(cx + width, cy + height);\n        path.lineTo(cx - width, cy + height);\n        path.closePath();\n    }\n});\n\n/**\n * Diamond shape\n * @inner\n */\nvar Diamond = extendShape({\n    type: 'diamond',\n    shape: {\n        cx: 0,\n        cy: 0,\n        width: 0,\n        height: 0\n    },\n    buildPath: function (path, shape) {\n        var cx = shape.cx;\n        var cy = shape.cy;\n        var width = shape.width / 2;\n        var height = shape.height / 2;\n        path.moveTo(cx, cy - height);\n        path.lineTo(cx + width, cy);\n        path.lineTo(cx, cy + height);\n        path.lineTo(cx - width, cy);\n        path.closePath();\n    }\n});\n\n/**\n * Pin shape\n * @inner\n */\nvar Pin = extendShape({\n    type: 'pin',\n    shape: {\n        // x, y on the cusp\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (path, shape) {\n        var x = shape.x;\n        var y = shape.y;\n        var w = shape.width / 5 * 3;\n        // Height must be larger than width\n        var h = Math.max(w, shape.height);\n        var r = w / 2;\n\n        // Dist on y with tangent point and circle center\n        var dy = r * r / (h - r);\n        var cy = y - h + r + dy;\n        var angle = Math.asin(dy / r);\n        // Dist on x with tangent point and circle center\n        var dx = Math.cos(angle) * r;\n\n        var tanX = Math.sin(angle);\n        var tanY = Math.cos(angle);\n\n        var cpLen = r * 0.6;\n        var cpLen2 = r * 0.7;\n\n        path.moveTo(x - dx, cy + dy);\n\n        path.arc(\n            x, cy, r,\n            Math.PI - angle,\n            Math.PI * 2 + angle\n        );\n        path.bezierCurveTo(\n            x + dx - tanX * cpLen, cy + dy + tanY * cpLen,\n            x, y - cpLen2,\n            x, y\n        );\n        path.bezierCurveTo(\n            x, y - cpLen2,\n            x - dx + tanX * cpLen, cy + dy + tanY * cpLen,\n            x - dx, cy + dy\n        );\n        path.closePath();\n    }\n});\n\n/**\n * Arrow shape\n * @inner\n */\nvar Arrow = extendShape({\n\n    type: 'arrow',\n\n    shape: {\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var height = shape.height;\n        var width = shape.width;\n        var x = shape.x;\n        var y = shape.y;\n        var dx = width / 3 * 2;\n        ctx.moveTo(x, y);\n        ctx.lineTo(x + dx, y + height);\n        ctx.lineTo(x, y + height / 4 * 3);\n        ctx.lineTo(x - dx, y + height);\n        ctx.lineTo(x, y);\n        ctx.closePath();\n    }\n});\n\n/**\n * Map of path contructors\n * @type {Object.<string, module:zrender/graphic/Path>}\n */\nvar symbolCtors = {\n\n    line: Line,\n\n    rect: Rect,\n\n    roundRect: Rect,\n\n    square: Rect,\n\n    circle: Circle,\n\n    diamond: Diamond,\n\n    pin: Pin,\n\n    arrow: Arrow,\n\n    triangle: Triangle\n};\n\nvar symbolShapeMakers = {\n\n    line: function (x, y, w, h, shape) {\n        // FIXME\n        shape.x1 = x;\n        shape.y1 = y + h / 2;\n        shape.x2 = x + w;\n        shape.y2 = y + h / 2;\n    },\n\n    rect: function (x, y, w, h, shape) {\n        shape.x = x;\n        shape.y = y;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    roundRect: function (x, y, w, h, shape) {\n        shape.x = x;\n        shape.y = y;\n        shape.width = w;\n        shape.height = h;\n        shape.r = Math.min(w, h) / 4;\n    },\n\n    square: function (x, y, w, h, shape) {\n        var size = Math.min(w, h);\n        shape.x = x;\n        shape.y = y;\n        shape.width = size;\n        shape.height = size;\n    },\n\n    circle: function (x, y, w, h, shape) {\n        // Put circle in the center of square\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.r = Math.min(w, h) / 2;\n    },\n\n    diamond: function (x, y, w, h, shape) {\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    pin: function (x, y, w, h, shape) {\n        shape.x = x + w / 2;\n        shape.y = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    arrow: function (x, y, w, h, shape) {\n        shape.x = x + w / 2;\n        shape.y = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    triangle: function (x, y, w, h, shape) {\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    }\n};\n\nvar symbolBuildProxies = {};\neach$1(symbolCtors, function (Ctor, name) {\n    symbolBuildProxies[name] = new Ctor();\n});\n\nvar SymbolClz = extendShape({\n\n    type: 'symbol',\n\n    shape: {\n        symbolType: '',\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    beforeBrush: function () {\n        var style = this.style;\n        var shape = this.shape;\n        // FIXME\n        if (shape.symbolType === 'pin' && style.textPosition === 'inside') {\n            style.textPosition = ['50%', '40%'];\n            style.textAlign = 'center';\n            style.textVerticalAlign = 'middle';\n        }\n    },\n\n    buildPath: function (ctx, shape, inBundle) {\n        var symbolType = shape.symbolType;\n        var proxySymbol = symbolBuildProxies[symbolType];\n        if (shape.symbolType !== 'none') {\n            if (!proxySymbol) {\n                // Default rect\n                symbolType = 'rect';\n                proxySymbol = symbolBuildProxies[symbolType];\n            }\n            symbolShapeMakers[symbolType](\n                shape.x, shape.y, shape.width, shape.height, proxySymbol.shape\n            );\n            proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle);\n        }\n    }\n});\n\n// Provide setColor helper method to avoid determine if set the fill or stroke outside\nfunction symbolPathSetColor(color, innerColor) {\n    if (this.type !== 'image') {\n        var symbolStyle = this.style;\n        var symbolShape = this.shape;\n        if (symbolShape && symbolShape.symbolType === 'line') {\n            symbolStyle.stroke = color;\n        }\n        else if (this.__isEmptyBrush) {\n            symbolStyle.stroke = color;\n            symbolStyle.fill = innerColor || '#fff';\n        }\n        else {\n            // FIXME 判断图形默认是填充还是描边，使用 onlyStroke ?\n            symbolStyle.fill && (symbolStyle.fill = color);\n            symbolStyle.stroke && (symbolStyle.stroke = color);\n        }\n        this.dirty(false);\n    }\n}\n\n/**\n * Create a symbol element with given symbol configuration: shape, x, y, width, height, color\n * @param {string} symbolType\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n * @param {string} color\n * @param {boolean} [keepAspect=false] whether to keep the ratio of w/h,\n *                            for path and image only.\n */\nfunction createSymbol(symbolType, x, y, w, h, color, keepAspect) {\n    // TODO Support image object, DynamicImage.\n\n    var isEmpty = symbolType.indexOf('empty') === 0;\n    if (isEmpty) {\n        symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6);\n    }\n    var symbolPath;\n\n    if (symbolType.indexOf('image://') === 0) {\n        symbolPath = makeImage(\n            symbolType.slice(8),\n            new BoundingRect(x, y, w, h),\n            keepAspect ? 'center' : 'cover'\n        );\n    }\n    else if (symbolType.indexOf('path://') === 0) {\n        symbolPath = makePath(\n            symbolType.slice(7),\n            {},\n            new BoundingRect(x, y, w, h),\n            keepAspect ? 'center' : 'cover'\n        );\n    }\n    else {\n        symbolPath = new SymbolClz({\n            shape: {\n                symbolType: symbolType,\n                x: x,\n                y: y,\n                width: w,\n                height: h\n            }\n        });\n    }\n\n    symbolPath.__isEmptyBrush = isEmpty;\n\n    symbolPath.setColor = symbolPathSetColor;\n\n    symbolPath.setColor(color);\n\n    return symbolPath;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import createGraphFromNodeEdge from './chart/helper/createGraphFromNodeEdge';\n/**\n * Create a muti dimension List structure from seriesModel.\n * @param  {module:echarts/model/Model} seriesModel\n * @return {module:echarts/data/List} list\n */\nfunction createList(seriesModel) {\n    return createListFromArray(seriesModel.getSource(), seriesModel);\n}\n\nvar dataStack$1 = {\n    isDimensionStacked: isDimensionStacked,\n    enableDataStack: enableDataStack,\n    getStackedDimension: getStackedDimension\n};\n\n/**\n * Create scale\n * @param {Array.<number>} dataExtent\n * @param {Object|module:echarts/Model} option\n */\nfunction createScale(dataExtent, option) {\n    var axisModel = option;\n    if (!Model.isInstance(option)) {\n        axisModel = new Model(option);\n        mixin(axisModel, axisModelCommonMixin);\n    }\n\n    var scale = createScaleByModel(axisModel);\n    scale.setExtent(dataExtent[0], dataExtent[1]);\n\n    niceScaleExtent(scale, axisModel);\n    return scale;\n}\n\n/**\n * Mixin common methods to axis model,\n *\n * Inlcude methods\n * `getFormattedLabels() => Array.<string>`\n * `getCategories() => Array.<string>`\n * `getMin(origin: boolean) => number`\n * `getMax(origin: boolean) => number`\n * `getNeedCrossZero() => boolean`\n * `setRange(start: number, end: number)`\n * `resetRange()`\n */\nfunction mixinAxisModelCommonMethods(Model$$1) {\n    mixin(Model$$1, axisModelCommonMixin);\n}\n\nvar helper = (Object.freeze || Object)({\n\tcreateList: createList,\n\tgetLayoutRect: getLayoutRect,\n\tdataStack: dataStack$1,\n\tcreateScale: createScale,\n\tmixinAxisModelCommonMethods: mixinAxisModelCommonMethods,\n\tcompleteDimensions: completeDimensions,\n\tcreateDimensions: createDimensions,\n\tcreateSymbol: createSymbol\n});\n\nvar EPSILON$3 = 1e-8;\n\nfunction isAroundEqual$1(a, b) {\n    return Math.abs(a - b) < EPSILON$3;\n}\n\nfunction contain$1(points, x, y) {\n    var w = 0;\n    var p = points[0];\n\n    if (!p) {\n        return false;\n    }\n\n    for (var i = 1; i < points.length; i++) {\n        var p2 = points[i];\n        w += windingLine(p[0], p[1], p2[0], p2[1], x, y);\n        p = p2;\n    }\n\n    // Close polygon\n    var p0 = points[0];\n    if (!isAroundEqual$1(p[0], p0[0]) || !isAroundEqual$1(p[1], p0[1])) {\n        w += windingLine(p[0], p[1], p0[0], p0[1], x, y);\n    }\n\n    return w !== 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/coord/geo/Region\n */\n\n/**\n * @param {string|Region} name\n * @param {Array} geometries\n * @param {Array.<number>} cp\n */\nfunction Region(name, geometries, cp) {\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.name = name;\n\n    /**\n     * @type {Array.<Array>}\n     * @readOnly\n     */\n    this.geometries = geometries;\n\n    if (!cp) {\n        var rect = this.getBoundingRect();\n        cp = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    }\n    else {\n        cp = [cp[0], cp[1]];\n    }\n    /**\n     * @type {Array.<number>}\n     */\n    this.center = cp;\n}\n\nRegion.prototype = {\n\n    constructor: Region,\n\n    properties: null,\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function () {\n        var rect = this._rect;\n        if (rect) {\n            return rect;\n        }\n\n        var MAX_NUMBER = Number.MAX_VALUE;\n        var min$$1 = [MAX_NUMBER, MAX_NUMBER];\n        var max$$1 = [-MAX_NUMBER, -MAX_NUMBER];\n        var min2 = [];\n        var max2 = [];\n        var geometries = this.geometries;\n        for (var i = 0; i < geometries.length; i++) {\n            // Only support polygon\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            // Doesn't consider hole\n            var exterior = geometries[i].exterior;\n            fromPoints(exterior, min2, max2);\n            min(min$$1, min$$1, min2);\n            max(max$$1, max$$1, max2);\n        }\n        // No data\n        if (i === 0) {\n            min$$1[0] = min$$1[1] = max$$1[0] = max$$1[1] = 0;\n        }\n\n        return (this._rect = new BoundingRect(\n            min$$1[0], min$$1[1], max$$1[0] - min$$1[0], max$$1[1] - min$$1[1]\n        ));\n    },\n\n    /**\n     * @param {<Array.<number>} coord\n     * @return {boolean}\n     */\n    contain: function (coord) {\n        var rect = this.getBoundingRect();\n        var geometries = this.geometries;\n        if (!rect.contain(coord[0], coord[1])) {\n            return false;\n        }\n        loopGeo: for (var i = 0, len$$1 = geometries.length; i < len$$1; i++) {\n            // Only support polygon.\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            var exterior = geometries[i].exterior;\n            var interiors = geometries[i].interiors;\n            if (contain$1(exterior, coord[0], coord[1])) {\n                // Not in the region if point is in the hole.\n                for (var k = 0; k < (interiors ? interiors.length : 0); k++) {\n                    if (contain$1(interiors[k])) {\n                        continue loopGeo;\n                    }\n                }\n                return true;\n            }\n        }\n        return false;\n    },\n\n    transformTo: function (x, y, width, height) {\n        var rect = this.getBoundingRect();\n        var aspect = rect.width / rect.height;\n        if (!width) {\n            width = aspect * height;\n        }\n        else if (!height) {\n            height = width / aspect;\n        }\n        var target = new BoundingRect(x, y, width, height);\n        var transform = rect.calculateTransform(target);\n        var geometries = this.geometries;\n        for (var i = 0; i < geometries.length; i++) {\n            // Only support polygon.\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            var exterior = geometries[i].exterior;\n            var interiors = geometries[i].interiors;\n            for (var p = 0; p < exterior.length; p++) {\n                applyTransform(exterior[p], exterior[p], transform);\n            }\n            for (var h = 0; h < (interiors ? interiors.length : 0); h++) {\n                for (var p = 0; p < interiors[h].length; p++) {\n                    applyTransform(interiors[h][p], interiors[h][p], transform);\n                }\n            }\n        }\n        rect = this._rect;\n        rect.copy(target);\n        // Update center\n        this.center = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    },\n\n    cloneShallow: function (name) {\n        name == null && (name = this.name);\n        var newRegion = new Region(name, this.geometries, this.center);\n        newRegion._rect = this._rect;\n        newRegion.transformTo = null; // Simply avoid to be called.\n        return newRegion;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Parse and decode geo json\n * @module echarts/coord/geo/parseGeoJson\n */\n\nfunction decode(json) {\n    if (!json.UTF8Encoding) {\n        return json;\n    }\n    var encodeScale = json.UTF8Scale;\n    if (encodeScale == null) {\n        encodeScale = 1024;\n    }\n\n    var features = json.features;\n\n    for (var f = 0; f < features.length; f++) {\n        var feature = features[f];\n        var geometry = feature.geometry;\n        var coordinates = geometry.coordinates;\n        var encodeOffsets = geometry.encodeOffsets;\n\n        for (var c = 0; c < coordinates.length; c++) {\n            var coordinate = coordinates[c];\n\n            if (geometry.type === 'Polygon') {\n                coordinates[c] = decodePolygon(\n                    coordinate,\n                    encodeOffsets[c],\n                    encodeScale\n                );\n            }\n            else if (geometry.type === 'MultiPolygon') {\n                for (var c2 = 0; c2 < coordinate.length; c2++) {\n                    var polygon = coordinate[c2];\n                    coordinate[c2] = decodePolygon(\n                        polygon,\n                        encodeOffsets[c][c2],\n                        encodeScale\n                    );\n                }\n            }\n        }\n    }\n    // Has been decoded\n    json.UTF8Encoding = false;\n    return json;\n}\n\nfunction decodePolygon(coordinate, encodeOffsets, encodeScale) {\n    var result = [];\n    var prevX = encodeOffsets[0];\n    var prevY = encodeOffsets[1];\n\n    for (var i = 0; i < coordinate.length; i += 2) {\n        var x = coordinate.charCodeAt(i) - 64;\n        var y = coordinate.charCodeAt(i + 1) - 64;\n        // ZigZag decoding\n        x = (x >> 1) ^ (-(x & 1));\n        y = (y >> 1) ^ (-(y & 1));\n        // Delta deocding\n        x += prevX;\n        y += prevY;\n\n        prevX = x;\n        prevY = y;\n        // Dequantize\n        result.push([x / encodeScale, y / encodeScale]);\n    }\n\n    return result;\n}\n\n/**\n * @alias module:echarts/coord/geo/parseGeoJson\n * @param {Object} geoJson\n * @return {module:zrender/container/Group}\n */\nvar parseGeoJSON = function (geoJson) {\n\n    decode(geoJson);\n\n    return map(filter(geoJson.features, function (featureObj) {\n        // Output of mapshaper may have geometry null\n        return featureObj.geometry\n            && featureObj.properties\n            && featureObj.geometry.coordinates.length > 0;\n    }), function (featureObj) {\n        var properties = featureObj.properties;\n        var geo = featureObj.geometry;\n\n        var coordinates = geo.coordinates;\n\n        var geometries = [];\n        if (geo.type === 'Polygon') {\n            geometries.push({\n                type: 'polygon',\n                // According to the GeoJSON specification.\n                // First must be exterior, and the rest are all interior(holes).\n                exterior: coordinates[0],\n                interiors: coordinates.slice(1)\n            });\n        }\n        if (geo.type === 'MultiPolygon') {\n            each$1(coordinates, function (item) {\n                if (item[0]) {\n                    geometries.push({\n                        type: 'polygon',\n                        exterior: item[0],\n                        interiors: item.slice(1)\n                    });\n                }\n            });\n        }\n\n        var region = new Region(\n            properties.name,\n            geometries,\n            properties.cp\n        );\n        region.properties = properties;\n        return region;\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$6 = makeInner();\n\n/**\n * @param {module:echats/coord/Axis} axis\n * @return {Object} {\n *     labels: [{\n *         formattedLabel: string,\n *         rawLabel: string,\n *         tickValue: number\n *     }, ...],\n *     labelCategoryInterval: number\n * }\n */\nfunction createAxisLabels(axis) {\n    // Only ordinal scale support tick interval\n    return axis.type === 'category'\n        ? makeCategoryLabels(axis)\n        : makeRealNumberLabels(axis);\n}\n\n/**\n * @param {module:echats/coord/Axis} axis\n * @param {module:echarts/model/Model} tickModel For example, can be axisTick, splitLine, splitArea.\n * @return {Object} {\n *     ticks: Array.<number>\n *     tickCategoryInterval: number\n * }\n */\nfunction createAxisTicks(axis, tickModel) {\n    // Only ordinal scale support tick interval\n    return axis.type === 'category'\n        ? makeCategoryTicks(axis, tickModel)\n        : {ticks: axis.scale.getTicks()};\n}\n\nfunction makeCategoryLabels(axis) {\n    var labelModel = axis.getLabelModel();\n    var result = makeCategoryLabelsActually(axis, labelModel);\n\n    return (!labelModel.get('show') || axis.scale.isBlank())\n        ? {labels: [], labelCategoryInterval: result.labelCategoryInterval}\n        : result;\n}\n\nfunction makeCategoryLabelsActually(axis, labelModel) {\n    var labelsCache = getListCache(axis, 'labels');\n    var optionLabelInterval = getOptionCategoryInterval(labelModel);\n    var result = listCacheGet(labelsCache, optionLabelInterval);\n\n    if (result) {\n        return result;\n    }\n\n    var labels;\n    var numericLabelInterval;\n\n    if (isFunction$1(optionLabelInterval)) {\n        labels = makeLabelsByCustomizedCategoryInterval(axis, optionLabelInterval);\n    }\n    else {\n        numericLabelInterval = optionLabelInterval === 'auto'\n            ? makeAutoCategoryInterval(axis) : optionLabelInterval;\n        labels = makeLabelsByNumericCategoryInterval(axis, numericLabelInterval);\n    }\n\n    // Cache to avoid calling interval function repeatly.\n    return listCacheSet(labelsCache, optionLabelInterval, {\n        labels: labels, labelCategoryInterval: numericLabelInterval\n    });\n}\n\nfunction makeCategoryTicks(axis, tickModel) {\n    var ticksCache = getListCache(axis, 'ticks');\n    var optionTickInterval = getOptionCategoryInterval(tickModel);\n    var result = listCacheGet(ticksCache, optionTickInterval);\n\n    if (result) {\n        return result;\n    }\n\n    var ticks;\n    var tickCategoryInterval;\n\n    // Optimize for the case that large category data and no label displayed,\n    // we should not return all ticks.\n    if (!tickModel.get('show') || axis.scale.isBlank()) {\n        ticks = [];\n    }\n\n    if (isFunction$1(optionTickInterval)) {\n        ticks = makeLabelsByCustomizedCategoryInterval(axis, optionTickInterval, true);\n    }\n    // Always use label interval by default despite label show. Consider this\n    // scenario, Use multiple grid with the xAxis sync, and only one xAxis shows\n    // labels. `splitLine` and `axisTick` should be consistent in this case.\n    else if (optionTickInterval === 'auto') {\n        var labelsResult = makeCategoryLabelsActually(axis, axis.getLabelModel());\n        tickCategoryInterval = labelsResult.labelCategoryInterval;\n        ticks = map(labelsResult.labels, function (labelItem) {\n            return labelItem.tickValue;\n        });\n    }\n    else {\n        tickCategoryInterval = optionTickInterval;\n        ticks = makeLabelsByNumericCategoryInterval(axis, tickCategoryInterval, true);\n    }\n\n    // Cache to avoid calling interval function repeatly.\n    return listCacheSet(ticksCache, optionTickInterval, {\n        ticks: ticks, tickCategoryInterval: tickCategoryInterval\n    });\n}\n\nfunction makeRealNumberLabels(axis) {\n    var ticks = axis.scale.getTicks();\n    var labelFormatter = makeLabelFormatter(axis);\n    return {\n        labels: map(ticks, function (tickValue, idx) {\n            return {\n                formattedLabel: labelFormatter(tickValue, idx),\n                rawLabel: axis.scale.getLabel(tickValue),\n                tickValue: tickValue\n            };\n        })\n    };\n}\n\n// Large category data calculation is performence sensitive, and ticks and label\n// probably be fetched by multiple times. So we cache the result.\n// axis is created each time during a ec process, so we do not need to clear cache.\nfunction getListCache(axis, prop) {\n    // Because key can be funciton, and cache size always be small, we use array cache.\n    return inner$6(axis)[prop] || (inner$6(axis)[prop] = []);\n}\n\nfunction listCacheGet(cache, key) {\n    for (var i = 0; i < cache.length; i++) {\n        if (cache[i].key === key) {\n            return cache[i].value;\n        }\n    }\n}\n\nfunction listCacheSet(cache, key, value) {\n    cache.push({key: key, value: value});\n    return value;\n}\n\nfunction makeAutoCategoryInterval(axis) {\n    var result = inner$6(axis).autoInterval;\n    return result != null\n        ? result\n        : (inner$6(axis).autoInterval = axis.calculateCategoryInterval());\n}\n\n/**\n * Calculate interval for category axis ticks and labels.\n * To get precise result, at least one of `getRotate` and `isHorizontal`\n * should be implemented in axis.\n */\nfunction calculateCategoryInterval(axis) {\n    var params = fetchAutoCategoryIntervalCalculationParams(axis);\n    var labelFormatter = makeLabelFormatter(axis);\n    var rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI;\n\n    var ordinalScale = axis.scale;\n    var ordinalExtent = ordinalScale.getExtent();\n    // Providing this method is for optimization:\n    // avoid generating a long array by `getTicks`\n    // in large category data case.\n    var tickCount = ordinalScale.count();\n\n    if (ordinalExtent[1] - ordinalExtent[0] < 1) {\n        return 0;\n    }\n\n    var step = 1;\n    // Simple optimization. Empirical value: tick count should less than 40.\n    if (tickCount > 40) {\n        step = Math.max(1, Math.floor(tickCount / 40));\n    }\n    var tickValue = ordinalExtent[0];\n    var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue);\n    var unitW = Math.abs(unitSpan * Math.cos(rotation));\n    var unitH = Math.abs(unitSpan * Math.sin(rotation));\n\n    var maxW = 0;\n    var maxH = 0;\n\n    // Caution: Performance sensitive for large category data.\n    // Consider dataZoom, we should make appropriate step to avoid O(n) loop.\n    for (; tickValue <= ordinalExtent[1]; tickValue += step) {\n        var width = 0;\n        var height = 0;\n\n        // Not precise, do not consider align and vertical align\n        // and each distance from axis line yet.\n        var rect = getBoundingRect(\n            labelFormatter(tickValue), params.font, 'center', 'top'\n        );\n        // Magic number\n        width = rect.width * 1.3;\n        height = rect.height * 1.3;\n\n        // Min size, void long loop.\n        maxW = Math.max(maxW, width, 7);\n        maxH = Math.max(maxH, height, 7);\n    }\n\n    var dw = maxW / unitW;\n    var dh = maxH / unitH;\n    // 0/0 is NaN, 1/0 is Infinity.\n    isNaN(dw) && (dw = Infinity);\n    isNaN(dh) && (dh = Infinity);\n    var interval = Math.max(0, Math.floor(Math.min(dw, dh)));\n\n    var cache = inner$6(axis.model);\n    var lastAutoInterval = cache.lastAutoInterval;\n    var lastTickCount = cache.lastTickCount;\n\n    // Use cache to keep interval stable while moving zoom window,\n    // otherwise the calculated interval might jitter when the zoom\n    // window size is close to the interval-changing size.\n    if (lastAutoInterval != null\n        && lastTickCount != null\n        && Math.abs(lastAutoInterval - interval) <= 1\n        && Math.abs(lastTickCount - tickCount) <= 1\n        // Always choose the bigger one, otherwise the critical\n        // point is not the same when zooming in or zooming out.\n        && lastAutoInterval > interval\n    ) {\n        interval = lastAutoInterval;\n    }\n    // Only update cache if cache not used, otherwise the\n    // changing of interval is too insensitive.\n    else {\n        cache.lastTickCount = tickCount;\n        cache.lastAutoInterval = interval;\n    }\n\n    return interval;\n}\n\nfunction fetchAutoCategoryIntervalCalculationParams(axis) {\n    var labelModel = axis.getLabelModel();\n    return {\n        axisRotate: axis.getRotate\n            ? axis.getRotate()\n            : (axis.isHorizontal && !axis.isHorizontal())\n            ? 90\n            : 0,\n        labelRotate: labelModel.get('rotate') || 0,\n        font: labelModel.getFont()\n    };\n}\n\nfunction makeLabelsByNumericCategoryInterval(axis, categoryInterval, onlyTick) {\n    var labelFormatter = makeLabelFormatter(axis);\n    var ordinalScale = axis.scale;\n    var ordinalExtent = ordinalScale.getExtent();\n    var labelModel = axis.getLabelModel();\n    var result = [];\n\n    // TODO: axisType: ordinalTime, pick the tick from each month/day/year/...\n\n    var step = Math.max((categoryInterval || 0) + 1, 1);\n    var startTick = ordinalExtent[0];\n    var tickCount = ordinalScale.count();\n\n    // Calculate start tick based on zero if possible to keep label consistent\n    // while zooming and moving while interval > 0. Otherwise the selection\n    // of displayable ticks and symbols probably keep changing.\n    // 3 is empirical value.\n    if (startTick !== 0 && step > 1 && tickCount / step > 2) {\n        startTick = Math.round(Math.ceil(startTick / step) * step);\n    }\n\n    // (1) Only add min max label here but leave overlap checking\n    // to render stage, which also ensure the returned list\n    // suitable for splitLine and splitArea rendering.\n    // (2) Scales except category always contain min max label so\n    // do not need to perform this process.\n    var showAllLabel = shouldShowAllLabels(axis);\n    var includeMinLabel = labelModel.get('showMinLabel') || showAllLabel;\n    var includeMaxLabel = labelModel.get('showMaxLabel') || showAllLabel;\n\n    if (includeMinLabel && startTick !== ordinalExtent[0]) {\n        addItem(ordinalExtent[0]);\n    }\n\n    // Optimize: avoid generating large array by `ordinalScale.getTicks()`.\n    var tickValue = startTick;\n    for (; tickValue <= ordinalExtent[1]; tickValue += step) {\n        addItem(tickValue);\n    }\n\n    if (includeMaxLabel && tickValue !== ordinalExtent[1]) {\n        addItem(ordinalExtent[1]);\n    }\n\n    function addItem(tVal) {\n        result.push(onlyTick\n            ? tVal\n            : {\n                formattedLabel: labelFormatter(tVal),\n                rawLabel: ordinalScale.getLabel(tVal),\n                tickValue: tVal\n            }\n        );\n    }\n\n    return result;\n}\n\n// When interval is function, the result `false` means ignore the tick.\n// It is time consuming for large category data.\nfunction makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) {\n    var ordinalScale = axis.scale;\n    var labelFormatter = makeLabelFormatter(axis);\n    var result = [];\n\n    each$1(ordinalScale.getTicks(), function (tickValue) {\n        var rawLabel = ordinalScale.getLabel(tickValue);\n        if (categoryInterval(tickValue, rawLabel)) {\n            result.push(onlyTick\n                ? tickValue\n                : {\n                    formattedLabel: labelFormatter(tickValue),\n                    rawLabel: rawLabel,\n                    tickValue: tickValue\n                }\n            );\n        }\n    });\n\n    return result;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar NORMALIZED_EXTENT = [0, 1];\n\n/**\n * Base class of Axis.\n * @constructor\n */\nvar Axis = function (dim, scale, extent) {\n\n    /**\n     * Axis dimension. Such as 'x', 'y', 'z', 'angle', 'radius'.\n     * @type {string}\n     */\n    this.dim = dim;\n\n    /**\n     * Axis scale\n     * @type {module:echarts/coord/scale/*}\n     */\n    this.scale = scale;\n\n    /**\n     * @type {Array.<number>}\n     * @private\n     */\n    this._extent = extent || [0, 0];\n\n    /**\n     * @type {boolean}\n     */\n    this.inverse = false;\n\n    /**\n     * Usually true when axis has a ordinal scale\n     * @type {boolean}\n     */\n    this.onBand = false;\n};\n\nAxis.prototype = {\n\n    constructor: Axis,\n\n    /**\n     * If axis extent contain given coord\n     * @param {number} coord\n     * @return {boolean}\n     */\n    contain: function (coord) {\n        var extent = this._extent;\n        var min = Math.min(extent[0], extent[1]);\n        var max = Math.max(extent[0], extent[1]);\n        return coord >= min && coord <= max;\n    },\n\n    /**\n     * If axis extent contain given data\n     * @param {number} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this.contain(this.dataToCoord(data));\n    },\n\n    /**\n     * Get coord extent.\n     * @return {Array.<number>}\n     */\n    getExtent: function () {\n        return this._extent.slice();\n    },\n\n    /**\n     * Get precision used for formatting\n     * @param {Array.<number>} [dataExtent]\n     * @return {number}\n     */\n    getPixelPrecision: function (dataExtent) {\n        return getPixelPrecision(\n            dataExtent || this.scale.getExtent(),\n            this._extent\n        );\n    },\n\n    /**\n     * Set coord extent\n     * @param {number} start\n     * @param {number} end\n     */\n    setExtent: function (start, end) {\n        var extent = this._extent;\n        extent[0] = start;\n        extent[1] = end;\n    },\n\n    /**\n     * Convert data to coord. Data is the rank if it has an ordinal scale\n     * @param {number} data\n     * @param  {boolean} clamp\n     * @return {number}\n     */\n    dataToCoord: function (data, clamp) {\n        var extent = this._extent;\n        var scale = this.scale;\n        data = scale.normalize(data);\n\n        if (this.onBand && scale.type === 'ordinal') {\n            extent = extent.slice();\n            fixExtentWithBands(extent, scale.count());\n        }\n\n        return linearMap(data, NORMALIZED_EXTENT, extent, clamp);\n    },\n\n    /**\n     * Convert coord to data. Data is the rank if it has an ordinal scale\n     * @param {number} coord\n     * @param  {boolean} clamp\n     * @return {number}\n     */\n    coordToData: function (coord, clamp) {\n        var extent = this._extent;\n        var scale = this.scale;\n\n        if (this.onBand && scale.type === 'ordinal') {\n            extent = extent.slice();\n            fixExtentWithBands(extent, scale.count());\n        }\n\n        var t = linearMap(coord, extent, NORMALIZED_EXTENT, clamp);\n\n        return this.scale.scale(t);\n    },\n\n    /**\n     * Convert pixel point to data in axis\n     * @param {Array.<number>} point\n     * @param  {boolean} clamp\n     * @return {number} data\n     */\n    pointToData: function (point, clamp) {\n        // Should be implemented in derived class if necessary.\n    },\n\n    /**\n     * Different from `zrUtil.map(axis.getTicks(), axis.dataToCoord, axis)`,\n     * `axis.getTicksCoords` considers `onBand`, which is used by\n     * `boundaryGap:true` of category axis and splitLine and splitArea.\n     * @param {Object} [opt]\n     * @param {number} [opt.tickModel=axis.model.getModel('axisTick')]\n     * @param {boolean} [opt.clamp] If `true`, the first and the last\n     *        tick must be at the axis end points. Otherwise, clip ticks\n     *        that outside the axis extent.\n     * @return {Array.<Object>} [{\n     *     coord: ...,\n     *     tickValue: ...\n     * }, ...]\n     */\n    getTicksCoords: function (opt) {\n        opt = opt || {};\n\n        var tickModel = opt.tickModel || this.getTickModel();\n\n        var result = createAxisTicks(this, tickModel);\n        var ticks = result.ticks;\n\n        var ticksCoords = map(ticks, function (tickValue) {\n            return {\n                coord: this.dataToCoord(tickValue),\n                tickValue: tickValue\n            };\n        }, this);\n\n        var alignWithLabel = tickModel.get('alignWithLabel');\n        fixOnBandTicksCoords(\n            this, ticksCoords, result.tickCategoryInterval, alignWithLabel, opt.clamp\n        );\n\n        return ticksCoords;\n    },\n\n    /**\n     * @return {Array.<Object>} [{\n     *     formattedLabel: string,\n     *     rawLabel: axis.scale.getLabel(tickValue)\n     *     tickValue: number\n     * }, ...]\n     */\n    getViewLabels: function () {\n        return createAxisLabels(this).labels;\n    },\n\n    /**\n     * @return {module:echarts/coord/model/Model}\n     */\n    getLabelModel: function () {\n        return this.model.getModel('axisLabel');\n    },\n\n    /**\n     * Notice here we only get the default tick model. For splitLine\n     * or splitArea, we should pass the splitLineModel or splitAreaModel\n     * manually when calling `getTicksCoords`.\n     * In GL, this method may be overrided to:\n     * `axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));`\n     * @return {module:echarts/coord/model/Model}\n     */\n    getTickModel: function () {\n        return this.model.getModel('axisTick');\n    },\n\n    /**\n     * Get width of band\n     * @return {number}\n     */\n    getBandWidth: function () {\n        var axisExtent = this._extent;\n        var dataExtent = this.scale.getExtent();\n\n        var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0);\n        // Fix #2728, avoid NaN when only one data.\n        len === 0 && (len = 1);\n\n        var size = Math.abs(axisExtent[1] - axisExtent[0]);\n\n        return Math.abs(size) / len;\n    },\n\n    /**\n     * @abstract\n     * @return {boolean} Is horizontal\n     */\n    isHorizontal: null,\n\n    /**\n     * @abstract\n     * @return {number} Get axis rotate, by degree.\n     */\n    getRotate: null,\n\n    /**\n     * Only be called in category axis.\n     * Can be overrided, consider other axes like in 3D.\n     * @return {number} Auto interval for cateogry axis tick and label\n     */\n    calculateCategoryInterval: function () {\n        return calculateCategoryInterval(this);\n    }\n\n};\n\nfunction fixExtentWithBands(extent, nTick) {\n    var size = extent[1] - extent[0];\n    var len = nTick;\n    var margin = size / len / 2;\n    extent[0] += margin;\n    extent[1] -= margin;\n}\n\n// If axis has labels [1, 2, 3, 4]. Bands on the axis are\n// |---1---|---2---|---3---|---4---|.\n// So the displayed ticks and splitLine/splitArea should between\n// each data item, otherwise cause misleading (e.g., split tow bars\n// of a single data item when there are two bar series).\n// Also consider if tickCategoryInterval > 0 and onBand, ticks and\n// splitLine/spliteArea should layout appropriately corresponding\n// to displayed labels. (So we should not use `getBandWidth` in this\n// case).\nfunction fixOnBandTicksCoords(axis, ticksCoords, tickCategoryInterval, alignWithLabel, clamp) {\n    var ticksLen = ticksCoords.length;\n\n    if (!axis.onBand || alignWithLabel || !ticksLen) {\n        return;\n    }\n\n    var axisExtent = axis.getExtent();\n    var last;\n    if (ticksLen === 1) {\n        ticksCoords[0].coord = axisExtent[0];\n        last = ticksCoords[1] = {coord: axisExtent[0]};\n    }\n    else {\n        var shift = (ticksCoords[1].coord - ticksCoords[0].coord);\n        each$1(ticksCoords, function (ticksItem) {\n            ticksItem.coord -= shift / 2;\n            var tickCategoryInterval = tickCategoryInterval || 0;\n            // Avoid split a single data item when odd interval.\n            if (tickCategoryInterval % 2 > 0) {\n                ticksItem.coord -= shift / ((tickCategoryInterval + 1) * 2);\n            }\n        });\n        last = {coord: ticksCoords[ticksLen - 1].coord + shift};\n        ticksCoords.push(last);\n    }\n\n    var inverse = axisExtent[0] > axisExtent[1];\n\n    if (littleThan(ticksCoords[0].coord, axisExtent[0])) {\n        clamp ? (ticksCoords[0].coord = axisExtent[0]) : ticksCoords.shift();\n    }\n    if (clamp && littleThan(axisExtent[0], ticksCoords[0].coord)) {\n        ticksCoords.unshift({coord: axisExtent[0]});\n    }\n    if (littleThan(axisExtent[1], last.coord)) {\n        clamp ? (last.coord = axisExtent[1]) : ticksCoords.pop();\n    }\n    if (clamp && littleThan(last.coord, axisExtent[1])) {\n        ticksCoords.push({coord: axisExtent[1]});\n    }\n\n    function littleThan(a, b) {\n        return inverse ? a > b : a < b;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Do not mount those modules on 'src/echarts' for better tree shaking.\n */\n\nvar parseGeoJson = parseGeoJSON;\n\nvar ecUtil = {};\neach$1(\n    [\n        'map', 'each', 'filter', 'indexOf', 'inherits', 'reduce', 'filter',\n        'bind', 'curry', 'isArray', 'isString', 'isObject', 'isFunction',\n        'extend', 'defaults', 'clone', 'merge'\n    ],\n    function (name) {\n        ecUtil[name] = zrUtil[name];\n    }\n);\nvar graphic$1 = {};\neach$1(\n    [\n        'extendShape', 'extendPath', 'makePath', 'makeImage',\n        'mergePath', 'resizePath', 'createIcon',\n        'setHoverStyle', 'setLabelStyle', 'setTextStyle', 'setText',\n        'getFont', 'updateProps', 'initProps', 'getTransform',\n        'clipPointsByRect', 'clipRectByRect',\n        'Group',\n        'Image',\n        'Text',\n        'Circle',\n        'Sector',\n        'Ring',\n        'Polygon',\n        'Polyline',\n        'Rect',\n        'Line',\n        'BezierCurve',\n        'Arc',\n        'IncrementalDisplayable',\n        'CompoundPath',\n        'LinearGradient',\n        'RadialGradient',\n        'BoundingRect'\n    ],\n    function (name) {\n        graphic$1[name] = graphic[name];\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.line',\n\n    dependencies: ['grid', 'polar'],\n\n    getInitialData: function (option, ecModel) {\n        if (__DEV__) {\n            var coordSys = option.coordinateSystem;\n            if (coordSys !== 'polar' && coordSys !== 'cartesian2d') {\n                throw new Error('Line not support coordinateSystem besides cartesian and polar');\n            }\n        }\n        return createListFromArray(this.getSource(), this);\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // stack: null\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // polarIndex: 0,\n\n        // If clip the overflow value\n        clipOverflow: true,\n        // cursor: null,\n\n        label: {\n            position: 'top'\n        },\n        // itemStyle: {\n        // },\n\n        lineStyle: {\n            width: 2,\n            type: 'solid'\n        },\n        // areaStyle: {\n            // origin of areaStyle. Valid values:\n            // `'auto'/null/undefined`: from axisLine to data\n            // `'start'`: from min to data\n            // `'end'`: from data to max\n            // origin: 'auto'\n        // },\n        // false, 'start', 'end', 'middle'\n        step: false,\n\n        // Disabled if step is true\n        smooth: false,\n        smoothMonotone: null,\n        symbol: 'emptyCircle',\n        symbolSize: 4,\n        symbolRotate: null,\n\n        showSymbol: true,\n        // `false`: follow the label interval strategy.\n        // `true`: show all symbols.\n        // `'auto'`: If possible, show all symbols, otherwise\n        //           follow the label interval strategy.\n        showAllSymbol: 'auto',\n\n        // Whether to connect break point.\n        connectNulls: false,\n\n        // Sampling for large data. Can be: 'average', 'max', 'min', 'sum'.\n        sampling: 'none',\n\n        animationEasing: 'linear',\n\n        // Disable progressive\n        progressive: 0,\n        hoverLayerThreshold: Infinity\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @return {string} label string. Not null/undefined\n */\nfunction getDefaultLabel(data, dataIndex) {\n    var labelDims = data.mapDimension('defaultedLabel', true);\n    var len = labelDims.length;\n\n    // Simple optimization (in lots of cases, label dims length is 1)\n    if (len === 1) {\n        return retrieveRawValue(data, dataIndex, labelDims[0]);\n    }\n    else if (len) {\n        var vals = [];\n        for (var i = 0; i < labelDims.length; i++) {\n            var val = retrieveRawValue(data, dataIndex, labelDims[i]);\n            vals.push(val);\n        }\n        return vals.join(' ');\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Symbol\n */\n\n/**\n * @constructor\n * @alias {module:echarts/chart/helper/Symbol}\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @extends {module:zrender/graphic/Group}\n */\nfunction SymbolClz$1(data, idx, seriesScope) {\n    Group.call(this);\n    this.updateData(data, idx, seriesScope);\n}\n\nvar symbolProto = SymbolClz$1.prototype;\n\n/**\n * @public\n * @static\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @return {Array.<number>} [width, height]\n */\nvar getSymbolSize = SymbolClz$1.getSymbolSize = function (data, idx) {\n    var symbolSize = data.getItemVisual(idx, 'symbolSize');\n    return symbolSize instanceof Array\n        ? symbolSize.slice()\n        : [+symbolSize, +symbolSize];\n};\n\nfunction getScale(symbolSize) {\n    return [symbolSize[0] / 2, symbolSize[1] / 2];\n}\n\nfunction driftSymbol(dx, dy) {\n    this.parent.drift(dx, dy);\n}\n\nsymbolProto._createSymbol = function (\n    symbolType,\n    data,\n    idx,\n    symbolSize,\n    keepAspect\n) {\n    // Remove paths created before\n    this.removeAll();\n\n    var color = data.getItemVisual(idx, 'color');\n\n    // var symbolPath = createSymbol(\n    //     symbolType, -0.5, -0.5, 1, 1, color\n    // );\n    // If width/height are set too small (e.g., set to 1) on ios10\n    // and macOS Sierra, a circle stroke become a rect, no matter what\n    // the scale is set. So we set width/height as 2. See #4150.\n    var symbolPath = createSymbol(\n        symbolType, -1, -1, 2, 2, color, keepAspect\n    );\n\n    symbolPath.attr({\n        z2: 100,\n        culling: true,\n        scale: getScale(symbolSize)\n    });\n    // Rewrite drift method\n    symbolPath.drift = driftSymbol;\n\n    this._symbolType = symbolType;\n\n    this.add(symbolPath);\n};\n\n/**\n * Stop animation\n * @param {boolean} toLastFrame\n */\nsymbolProto.stopSymbolAnimation = function (toLastFrame) {\n    this.childAt(0).stopAnimation(toLastFrame);\n};\n\n/**\n * FIXME:\n * Caution: This method breaks the encapsulation of this module,\n * but it indeed brings convenience. So do not use the method\n * unless you detailedly know all the implements of `Symbol`,\n * especially animation.\n *\n * Get symbol path element.\n */\nsymbolProto.getSymbolPath = function () {\n    return this.childAt(0);\n};\n\n/**\n * Get scale(aka, current symbol size).\n * Including the change caused by animation\n */\nsymbolProto.getScale = function () {\n    return this.childAt(0).scale;\n};\n\n/**\n * Highlight symbol\n */\nsymbolProto.highlight = function () {\n    this.childAt(0).trigger('emphasis');\n};\n\n/**\n * Downplay symbol\n */\nsymbolProto.downplay = function () {\n    this.childAt(0).trigger('normal');\n};\n\n/**\n * @param {number} zlevel\n * @param {number} z\n */\nsymbolProto.setZ = function (zlevel, z) {\n    var symbolPath = this.childAt(0);\n    symbolPath.zlevel = zlevel;\n    symbolPath.z = z;\n};\n\nsymbolProto.setDraggable = function (draggable) {\n    var symbolPath = this.childAt(0);\n    symbolPath.draggable = draggable;\n    symbolPath.cursor = draggable ? 'move' : 'pointer';\n};\n\n/**\n * Update symbol properties\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @param {Object} [seriesScope]\n * @param {Object} [seriesScope.itemStyle]\n * @param {Object} [seriesScope.hoverItemStyle]\n * @param {Object} [seriesScope.symbolRotate]\n * @param {Object} [seriesScope.symbolOffset]\n * @param {module:echarts/model/Model} [seriesScope.labelModel]\n * @param {module:echarts/model/Model} [seriesScope.hoverLabelModel]\n * @param {boolean} [seriesScope.hoverAnimation]\n * @param {Object} [seriesScope.cursorStyle]\n * @param {module:echarts/model/Model} [seriesScope.itemModel]\n * @param {string} [seriesScope.symbolInnerColor]\n * @param {Object} [seriesScope.fadeIn=false]\n */\nsymbolProto.updateData = function (data, idx, seriesScope) {\n    this.silent = false;\n\n    var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';\n    var seriesModel = data.hostModel;\n    var symbolSize = getSymbolSize(data, idx);\n    var isInit = symbolType !== this._symbolType;\n\n    if (isInit) {\n        var keepAspect = data.getItemVisual(idx, 'symbolKeepAspect');\n        this._createSymbol(symbolType, data, idx, symbolSize, keepAspect);\n    }\n    else {\n        var symbolPath = this.childAt(0);\n        symbolPath.silent = false;\n        updateProps(symbolPath, {\n            scale: getScale(symbolSize)\n        }, seriesModel, idx);\n    }\n\n    this._updateCommon(data, idx, symbolSize, seriesScope);\n\n    if (isInit) {\n        var symbolPath = this.childAt(0);\n        var fadeIn = seriesScope && seriesScope.fadeIn;\n\n        var target = {scale: symbolPath.scale.slice()};\n        fadeIn && (target.style = {opacity: symbolPath.style.opacity});\n\n        symbolPath.scale = [0, 0];\n        fadeIn && (symbolPath.style.opacity = 0);\n\n        initProps(symbolPath, target, seriesModel, idx);\n    }\n\n    this._seriesModel = seriesModel;\n};\n\n// Update common properties\nvar normalStyleAccessPath = ['itemStyle'];\nvar emphasisStyleAccessPath = ['emphasis', 'itemStyle'];\nvar normalLabelAccessPath = ['label'];\nvar emphasisLabelAccessPath = ['emphasis', 'label'];\n\n/**\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @param {Array.<number>} symbolSize\n * @param {Object} [seriesScope]\n */\nsymbolProto._updateCommon = function (data, idx, symbolSize, seriesScope) {\n    var symbolPath = this.childAt(0);\n    var seriesModel = data.hostModel;\n    var color = data.getItemVisual(idx, 'color');\n\n    // Reset style\n    if (symbolPath.type !== 'image') {\n        symbolPath.useStyle({\n            strokeNoScale: true\n        });\n    }\n\n    var itemStyle = seriesScope && seriesScope.itemStyle;\n    var hoverItemStyle = seriesScope && seriesScope.hoverItemStyle;\n    var symbolRotate = seriesScope && seriesScope.symbolRotate;\n    var symbolOffset = seriesScope && seriesScope.symbolOffset;\n    var labelModel = seriesScope && seriesScope.labelModel;\n    var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;\n    var hoverAnimation = seriesScope && seriesScope.hoverAnimation;\n    var cursorStyle = seriesScope && seriesScope.cursorStyle;\n\n    if (!seriesScope || data.hasItemOption) {\n        var itemModel = (seriesScope && seriesScope.itemModel)\n            ? seriesScope.itemModel : data.getItemModel(idx);\n\n        // Color must be excluded.\n        // Because symbol provide setColor individually to set fill and stroke\n        itemStyle = itemModel.getModel(normalStyleAccessPath).getItemStyle(['color']);\n        hoverItemStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();\n\n        symbolRotate = itemModel.getShallow('symbolRotate');\n        symbolOffset = itemModel.getShallow('symbolOffset');\n\n        labelModel = itemModel.getModel(normalLabelAccessPath);\n        hoverLabelModel = itemModel.getModel(emphasisLabelAccessPath);\n        hoverAnimation = itemModel.getShallow('hoverAnimation');\n        cursorStyle = itemModel.getShallow('cursor');\n    }\n    else {\n        hoverItemStyle = extend({}, hoverItemStyle);\n    }\n\n    var elStyle = symbolPath.style;\n\n    symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0);\n\n    if (symbolOffset) {\n        symbolPath.attr('position', [\n            parsePercent$1(symbolOffset[0], symbolSize[0]),\n            parsePercent$1(symbolOffset[1], symbolSize[1])\n        ]);\n    }\n\n    cursorStyle && symbolPath.attr('cursor', cursorStyle);\n\n    // PENDING setColor before setStyle!!!\n    symbolPath.setColor(color, seriesScope && seriesScope.symbolInnerColor);\n\n    symbolPath.setStyle(itemStyle);\n\n    var opacity = data.getItemVisual(idx, 'opacity');\n    if (opacity != null) {\n        elStyle.opacity = opacity;\n    }\n\n    var liftZ = data.getItemVisual(idx, 'liftZ');\n    var z2Origin = symbolPath.__z2Origin;\n    if (liftZ != null) {\n        if (z2Origin == null) {\n            symbolPath.__z2Origin = symbolPath.z2;\n            symbolPath.z2 += liftZ;\n        }\n    }\n    else if (z2Origin != null) {\n        symbolPath.z2 = z2Origin;\n        symbolPath.__z2Origin = null;\n    }\n\n    var useNameLabel = seriesScope && seriesScope.useNameLabel;\n\n    setLabelStyle(\n        elStyle, hoverItemStyle, labelModel, hoverLabelModel,\n        {\n            labelFetcher: seriesModel,\n            labelDataIndex: idx,\n            defaultText: getLabelDefaultText,\n            isRectText: true,\n            autoColor: color\n        }\n    );\n\n    // Do not execute util needed.\n    function getLabelDefaultText(idx, opt) {\n        return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx);\n    }\n\n    symbolPath.off('mouseover')\n        .off('mouseout')\n        .off('emphasis')\n        .off('normal');\n\n    symbolPath.hoverStyle = hoverItemStyle;\n\n    // FIXME\n    // Do not use symbol.trigger('emphasis'), but use symbol.highlight() instead.\n    setHoverStyle(symbolPath);\n\n    symbolPath.__symbolOriginalScale = getScale(symbolSize);\n\n    if (hoverAnimation && seriesModel.isAnimationEnabled()) {\n        // Note: consider `off`, should use static function here.\n        symbolPath.on('mouseover', onMouseOver)\n            .on('mouseout', onMouseOut)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal);\n    }\n};\n\nfunction onMouseOver() {\n    // see comment in `graphic.isInEmphasis`\n    !isInEmphasis(this) && onEmphasis.call(this);\n}\n\nfunction onMouseOut() {\n    // see comment in `graphic.isInEmphasis`\n    !isInEmphasis(this) && onNormal.call(this);\n}\n\nfunction onEmphasis() {\n    // Do not support this hover animation util some scenario required.\n    // Animation can only be supported in hover layer when using `el.incremetal`.\n    if (this.incremental || this.useHoverLayer) {\n        return;\n    }\n    var scale = this.__symbolOriginalScale;\n    var ratio = scale[1] / scale[0];\n    this.animateTo({\n        scale: [\n            Math.max(scale[0] * 1.1, scale[0] + 3),\n            Math.max(scale[1] * 1.1, scale[1] + 3 * ratio)\n        ]\n    }, 400, 'elasticOut');\n}\n\nfunction onNormal() {\n    if (this.incremental || this.useHoverLayer) {\n        return;\n    }\n    this.animateTo({\n        scale: this.__symbolOriginalScale\n    }, 400, 'elasticOut');\n}\n\n\n/**\n * @param {Function} cb\n * @param {Object} [opt]\n * @param {Object} [opt.keepLabel=true]\n */\nsymbolProto.fadeOut = function (cb, opt) {\n    var symbolPath = this.childAt(0);\n    // Avoid mistaken hover when fading out\n    this.silent = symbolPath.silent = true;\n    // Not show text when animating\n    !(opt && opt.keepLabel) && (symbolPath.style.text = null);\n\n    updateProps(\n        symbolPath,\n        {\n            style: {opacity: 0},\n            scale: [0, 0]\n        },\n        this._seriesModel,\n        this.dataIndex,\n        cb\n    );\n};\n\ninherits(SymbolClz$1, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/SymbolDraw\n */\n\n/**\n * @constructor\n * @alias module:echarts/chart/helper/SymbolDraw\n * @param {module:zrender/graphic/Group} [symbolCtor]\n */\nfunction SymbolDraw(symbolCtor) {\n    this.group = new Group();\n\n    this._symbolCtor = symbolCtor || SymbolClz$1;\n}\n\nvar symbolDrawProto = SymbolDraw.prototype;\n\nfunction symbolNeedsDraw(data, point, idx, opt) {\n    return point && !isNaN(point[0]) && !isNaN(point[1])\n        && !(opt.isIgnore && opt.isIgnore(idx))\n        // We do not set clipShape on group, because it will cut part of\n        // the symbol element shape. We use the same clip shape here as\n        // the line clip.\n        && !(opt.clipShape && !opt.clipShape.contain(point[0], point[1]))\n        && data.getItemVisual(idx, 'symbol') !== 'none';\n}\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n * @param {Object} [opt] Or isIgnore\n * @param {Function} [opt.isIgnore]\n * @param {Object} [opt.clipShape]\n */\nsymbolDrawProto.updateData = function (data, opt) {\n    opt = normalizeUpdateOpt(opt);\n\n    var group = this.group;\n    var seriesModel = data.hostModel;\n    var oldData = this._data;\n    var SymbolCtor = this._symbolCtor;\n\n    var seriesScope = makeSeriesScope(data);\n\n    // There is no oldLineData only when first rendering or switching from\n    // stream mode to normal mode, where previous elements should be removed.\n    if (!oldData) {\n        group.removeAll();\n    }\n\n    data.diff(oldData)\n        .add(function (newIdx) {\n            var point = data.getItemLayout(newIdx);\n            if (symbolNeedsDraw(data, point, newIdx, opt)) {\n                var symbolEl = new SymbolCtor(data, newIdx, seriesScope);\n                symbolEl.attr('position', point);\n                data.setItemGraphicEl(newIdx, symbolEl);\n                group.add(symbolEl);\n            }\n        })\n        .update(function (newIdx, oldIdx) {\n            var symbolEl = oldData.getItemGraphicEl(oldIdx);\n            var point = data.getItemLayout(newIdx);\n            if (!symbolNeedsDraw(data, point, newIdx, opt)) {\n                group.remove(symbolEl);\n                return;\n            }\n            if (!symbolEl) {\n                symbolEl = new SymbolCtor(data, newIdx);\n                symbolEl.attr('position', point);\n            }\n            else {\n                symbolEl.updateData(data, newIdx, seriesScope);\n                updateProps(symbolEl, {\n                    position: point\n                }, seriesModel);\n            }\n\n            // Add back\n            group.add(symbolEl);\n\n            data.setItemGraphicEl(newIdx, symbolEl);\n        })\n        .remove(function (oldIdx) {\n            var el = oldData.getItemGraphicEl(oldIdx);\n            el && el.fadeOut(function () {\n                group.remove(el);\n            });\n        })\n        .execute();\n\n    this._data = data;\n};\n\nsymbolDrawProto.isPersistent = function () {\n    return true;\n};\n\nsymbolDrawProto.updateLayout = function () {\n    var data = this._data;\n    if (data) {\n        // Not use animation\n        data.eachItemGraphicEl(function (el, idx) {\n            var point = data.getItemLayout(idx);\n            el.attr('position', point);\n        });\n    }\n};\n\nsymbolDrawProto.incrementalPrepareUpdate = function (data) {\n    this._seriesScope = makeSeriesScope(data);\n    this._data = null;\n    this.group.removeAll();\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n * @param {Object} [opt] Or isIgnore\n * @param {Function} [opt.isIgnore]\n * @param {Object} [opt.clipShape]\n */\nsymbolDrawProto.incrementalUpdate = function (taskParams, data, opt) {\n    opt = normalizeUpdateOpt(opt);\n\n    function updateIncrementalAndHover(el) {\n        if (!el.isGroup) {\n            el.incremental = el.useHoverLayer = true;\n        }\n    }\n    for (var idx = taskParams.start; idx < taskParams.end; idx++) {\n        var point = data.getItemLayout(idx);\n        if (symbolNeedsDraw(data, point, idx, opt)) {\n            var el = new this._symbolCtor(data, idx, this._seriesScope);\n            el.traverse(updateIncrementalAndHover);\n            el.attr('position', point);\n            this.group.add(el);\n            data.setItemGraphicEl(idx, el);\n        }\n    }\n};\n\nfunction normalizeUpdateOpt(opt) {\n    if (opt != null && !isObject$1(opt)) {\n        opt = {isIgnore: opt};\n    }\n    return opt || {};\n}\n\nsymbolDrawProto.remove = function (enableAnimation) {\n    var group = this.group;\n    var data = this._data;\n    // Incremental model do not have this._data.\n    if (data && enableAnimation) {\n        data.eachItemGraphicEl(function (el) {\n            el.fadeOut(function () {\n                group.remove(el);\n            });\n        });\n    }\n    else {\n        group.removeAll();\n    }\n};\n\nfunction makeSeriesScope(data) {\n    var seriesModel = data.hostModel;\n    return {\n        itemStyle: seriesModel.getModel('itemStyle').getItemStyle(['color']),\n        hoverItemStyle: seriesModel.getModel('emphasis.itemStyle').getItemStyle(),\n        symbolRotate: seriesModel.get('symbolRotate'),\n        symbolOffset: seriesModel.get('symbolOffset'),\n        hoverAnimation: seriesModel.get('hoverAnimation'),\n        labelModel: seriesModel.getModel('label'),\n        hoverLabelModel: seriesModel.getModel('emphasis.label'),\n        cursorStyle: seriesModel.get('cursor')\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} coordSys\n * @param {module:echarts/data/List} data\n * @param {string} valueOrigin lineSeries.option.areaStyle.origin\n */\nfunction prepareDataCoordInfo(coordSys, data, valueOrigin) {\n    var baseAxis = coordSys.getBaseAxis();\n    var valueAxis = coordSys.getOtherAxis(baseAxis);\n    var valueStart = getValueStart(valueAxis, valueOrigin);\n\n    var baseAxisDim = baseAxis.dim;\n    var valueAxisDim = valueAxis.dim;\n    var valueDim = data.mapDimension(valueAxisDim);\n    var baseDim = data.mapDimension(baseAxisDim);\n    var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0;\n\n    var dims = map(coordSys.dimensions, function (coordDim) {\n        return data.mapDimension(coordDim);\n    });\n\n    var stacked;\n    var stackResultDim = data.getCalculationInfo('stackResultDimension');\n    if (stacked |= isDimensionStacked(data, dims[0] /*, dims[1]*/)) { // jshint ignore:line\n        dims[0] = stackResultDim;\n    }\n    if (stacked |= isDimensionStacked(data, dims[1] /*, dims[0]*/)) { // jshint ignore:line\n        dims[1] = stackResultDim;\n    }\n\n    return {\n        dataDimsForPoint: dims,\n        valueStart: valueStart,\n        valueAxisDim: valueAxisDim,\n        baseAxisDim: baseAxisDim,\n        stacked: !!stacked,\n        valueDim: valueDim,\n        baseDim: baseDim,\n        baseDataOffset: baseDataOffset,\n        stackedOverDimension: data.getCalculationInfo('stackedOverDimension')\n    };\n}\n\nfunction getValueStart(valueAxis, valueOrigin) {\n    var valueStart = 0;\n    var extent = valueAxis.scale.getExtent();\n\n    if (valueOrigin === 'start') {\n        valueStart = extent[0];\n    }\n    else if (valueOrigin === 'end') {\n        valueStart = extent[1];\n    }\n    // auto\n    else {\n        // Both positive\n        if (extent[0] > 0) {\n            valueStart = extent[0];\n        }\n        // Both negative\n        else if (extent[1] < 0) {\n            valueStart = extent[1];\n        }\n        // If is one positive, and one negative, onZero shall be true\n    }\n\n    return valueStart;\n}\n\nfunction getStackedOnPoint(dataCoordInfo, coordSys, data, idx) {\n    var value = NaN;\n    if (dataCoordInfo.stacked) {\n        value = data.get(data.getCalculationInfo('stackedOverDimension'), idx);\n    }\n    if (isNaN(value)) {\n        value = dataCoordInfo.valueStart;\n    }\n\n    var baseDataOffset = dataCoordInfo.baseDataOffset;\n    var stackedData = [];\n    stackedData[baseDataOffset] = data.get(dataCoordInfo.baseDim, idx);\n    stackedData[1 - baseDataOffset] = value;\n\n    return coordSys.dataToPoint(stackedData);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// var arrayDiff = require('zrender/src/core/arrayDiff');\n// 'zrender/src/core/arrayDiff' has been used before, but it did\n// not do well in performance when roam with fixed dataZoom window.\n\n// function convertToIntId(newIdList, oldIdList) {\n//     // Generate int id instead of string id.\n//     // Compare string maybe slow in score function of arrDiff\n\n//     // Assume id in idList are all unique\n//     var idIndicesMap = {};\n//     var idx = 0;\n//     for (var i = 0; i < newIdList.length; i++) {\n//         idIndicesMap[newIdList[i]] = idx;\n//         newIdList[i] = idx++;\n//     }\n//     for (var i = 0; i < oldIdList.length; i++) {\n//         var oldId = oldIdList[i];\n//         // Same with newIdList\n//         if (idIndicesMap[oldId]) {\n//             oldIdList[i] = idIndicesMap[oldId];\n//         }\n//         else {\n//             oldIdList[i] = idx++;\n//         }\n//     }\n// }\n\nfunction diffData(oldData, newData) {\n    var diffResult = [];\n\n    newData.diff(oldData)\n        .add(function (idx) {\n            diffResult.push({cmd: '+', idx: idx});\n        })\n        .update(function (newIdx, oldIdx) {\n            diffResult.push({cmd: '=', idx: oldIdx, idx1: newIdx});\n        })\n        .remove(function (idx) {\n            diffResult.push({cmd: '-', idx: idx});\n        })\n        .execute();\n\n    return diffResult;\n}\n\nvar lineAnimationDiff = function (\n    oldData, newData,\n    oldStackedOnPoints, newStackedOnPoints,\n    oldCoordSys, newCoordSys,\n    oldValueOrigin, newValueOrigin\n) {\n    var diff = diffData(oldData, newData);\n\n    // var newIdList = newData.mapArray(newData.getId);\n    // var oldIdList = oldData.mapArray(oldData.getId);\n\n    // convertToIntId(newIdList, oldIdList);\n\n    // // FIXME One data ?\n    // diff = arrayDiff(oldIdList, newIdList);\n\n    var currPoints = [];\n    var nextPoints = [];\n    // Points for stacking base line\n    var currStackedPoints = [];\n    var nextStackedPoints = [];\n\n    var status = [];\n    var sortedIndices = [];\n    var rawIndices = [];\n\n    var newDataOldCoordInfo = prepareDataCoordInfo(oldCoordSys, newData, oldValueOrigin);\n    var oldDataNewCoordInfo = prepareDataCoordInfo(newCoordSys, oldData, newValueOrigin);\n\n    for (var i = 0; i < diff.length; i++) {\n        var diffItem = diff[i];\n        var pointAdded = true;\n\n        // FIXME, animation is not so perfect when dataZoom window moves fast\n        // Which is in case remvoing or add more than one data in the tail or head\n        switch (diffItem.cmd) {\n            case '=':\n                var currentPt = oldData.getItemLayout(diffItem.idx);\n                var nextPt = newData.getItemLayout(diffItem.idx1);\n                // If previous data is NaN, use next point directly\n                if (isNaN(currentPt[0]) || isNaN(currentPt[1])) {\n                    currentPt = nextPt.slice();\n                }\n                currPoints.push(currentPt);\n                nextPoints.push(nextPt);\n\n                currStackedPoints.push(oldStackedOnPoints[diffItem.idx]);\n                nextStackedPoints.push(newStackedOnPoints[diffItem.idx1]);\n\n                rawIndices.push(newData.getRawIndex(diffItem.idx1));\n                break;\n            case '+':\n                var idx = diffItem.idx;\n                currPoints.push(\n                    oldCoordSys.dataToPoint([\n                        newData.get(newDataOldCoordInfo.dataDimsForPoint[0], idx),\n                        newData.get(newDataOldCoordInfo.dataDimsForPoint[1], idx)\n                    ])\n                );\n\n                nextPoints.push(newData.getItemLayout(idx).slice());\n\n                currStackedPoints.push(\n                    getStackedOnPoint(newDataOldCoordInfo, oldCoordSys, newData, idx)\n                );\n                nextStackedPoints.push(newStackedOnPoints[idx]);\n\n                rawIndices.push(newData.getRawIndex(idx));\n                break;\n            case '-':\n                var idx = diffItem.idx;\n                var rawIndex = oldData.getRawIndex(idx);\n                // Data is replaced. In the case of dynamic data queue\n                // FIXME FIXME FIXME\n                if (rawIndex !== idx) {\n                    currPoints.push(oldData.getItemLayout(idx));\n                    nextPoints.push(newCoordSys.dataToPoint([\n                        oldData.get(oldDataNewCoordInfo.dataDimsForPoint[0], idx),\n                        oldData.get(oldDataNewCoordInfo.dataDimsForPoint[1], idx)\n                    ]));\n\n                    currStackedPoints.push(oldStackedOnPoints[idx]);\n                    nextStackedPoints.push(\n                        getStackedOnPoint(oldDataNewCoordInfo, newCoordSys, oldData, idx)\n                    );\n\n                    rawIndices.push(rawIndex);\n                }\n                else {\n                    pointAdded = false;\n                }\n        }\n\n        // Original indices\n        if (pointAdded) {\n            status.push(diffItem);\n            sortedIndices.push(sortedIndices.length);\n        }\n    }\n\n    // Diff result may be crossed if all items are changed\n    // Sort by data index\n    sortedIndices.sort(function (a, b) {\n        return rawIndices[a] - rawIndices[b];\n    });\n\n    var sortedCurrPoints = [];\n    var sortedNextPoints = [];\n\n    var sortedCurrStackedPoints = [];\n    var sortedNextStackedPoints = [];\n\n    var sortedStatus = [];\n    for (var i = 0; i < sortedIndices.length; i++) {\n        var idx = sortedIndices[i];\n        sortedCurrPoints[i] = currPoints[idx];\n        sortedNextPoints[i] = nextPoints[idx];\n\n        sortedCurrStackedPoints[i] = currStackedPoints[idx];\n        sortedNextStackedPoints[i] = nextStackedPoints[idx];\n\n        sortedStatus[i] = status[idx];\n    }\n\n    return {\n        current: sortedCurrPoints,\n        next: sortedNextPoints,\n\n        stackedOnCurrent: sortedCurrStackedPoints,\n        stackedOnNext: sortedNextStackedPoints,\n\n        status: sortedStatus\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Poly path support NaN point\n\nvar vec2Min = min;\nvar vec2Max = max;\n\nvar scaleAndAdd$1 = scaleAndAdd;\nvar v2Copy = copy;\n\n// Temporary variable\nvar v = [];\nvar cp0 = [];\nvar cp1 = [];\n\nfunction isPointNull(p) {\n    return isNaN(p[0]) || isNaN(p[1]);\n}\n\nfunction drawSegment(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    // if (smoothMonotone == null) {\n    //     if (isMono(points, 'x')) {\n    //         return drawMono(ctx, points, start, segLen, allLen,\n    //             dir, smoothMin, smoothMax, smooth, 'x', connectNulls);\n    //     }\n    //     else if (isMono(points, 'y')) {\n    //         return drawMono(ctx, points, start, segLen, allLen,\n    //             dir, smoothMin, smoothMax, smooth, 'y', connectNulls);\n    //     }\n    //     else {\n    //         return drawNonMono.apply(this, arguments);\n    //     }\n    // }\n    // else if (smoothMonotone !== 'none' && isMono(points, smoothMonotone)) {\n    //     return drawMono.apply(this, arguments);\n    // }\n    // else {\n    //     return drawNonMono.apply(this, arguments);\n    // }\n    if (smoothMonotone === 'none' || !smoothMonotone) {\n        return drawNonMono.apply(this, arguments);\n    }\n    else {\n        return drawMono.apply(this, arguments);\n    }\n}\n\n/**\n * Check if points is in monotone.\n *\n * @param {number[][]} points         Array of points which is in [x, y] form\n * @param {string}     smoothMonotone 'x', 'y', or 'none', stating for which\n *                                    dimension that is checking.\n *                                    If is 'none', `drawNonMono` should be\n *                                    called.\n *                                    If is undefined, either being monotone\n *                                    in 'x' or 'y' will call `drawMono`.\n */\n// function isMono(points, smoothMonotone) {\n//     if (points.length <= 1) {\n//         return true;\n//     }\n\n//     var dim = smoothMonotone === 'x' ? 0 : 1;\n//     var last = points[0][dim];\n//     var lastDiff = 0;\n//     for (var i = 1; i < points.length; ++i) {\n//         var diff = points[i][dim] - last;\n//         if (!isNaN(diff) && !isNaN(lastDiff)\n//             && diff !== 0 && lastDiff !== 0\n//             && ((diff >= 0) !== (lastDiff >= 0))\n//         ) {\n//             return false;\n//         }\n//         if (!isNaN(diff) && diff !== 0) {\n//             lastDiff = diff;\n//             last = points[i][dim];\n//         }\n//     }\n//     return true;\n// }\n\n/**\n * Draw smoothed line in monotone, in which only vertical or horizontal bezier\n * control points will be used. This should be used when points are monotone\n * either in x or y dimension.\n */\nfunction drawMono(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    var prevIdx = 0;\n    var idx = start;\n    for (var k = 0; k < segLen; k++) {\n        var p = points[idx];\n        if (idx >= allLen || idx < 0) {\n            break;\n        }\n        if (isPointNull(p)) {\n            if (connectNulls) {\n                idx += dir;\n                continue;\n            }\n            break;\n        }\n\n        if (idx === start) {\n            ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);\n        }\n        else {\n            if (smooth > 0) {\n                var prevP = points[prevIdx];\n                var dim = smoothMonotone === 'y' ? 1 : 0;\n\n                // Length of control point to p, either in x or y, but not both\n                var ctrlLen = (p[dim] - prevP[dim]) * smooth;\n\n                v2Copy(cp0, prevP);\n                cp0[dim] = prevP[dim] + ctrlLen;\n\n                v2Copy(cp1, p);\n                cp1[dim] = p[dim] - ctrlLen;\n\n                ctx.bezierCurveTo(\n                    cp0[0], cp0[1],\n                    cp1[0], cp1[1],\n                    p[0], p[1]\n                );\n            }\n            else {\n                ctx.lineTo(p[0], p[1]);\n            }\n        }\n\n        prevIdx = idx;\n        idx += dir;\n    }\n\n    return k;\n}\n\n/**\n * Draw smoothed line in non-monotone, in may cause undesired curve in extreme\n * situations. This should be used when points are non-monotone neither in x or\n * y dimension.\n */\nfunction drawNonMono(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    var prevIdx = 0;\n    var idx = start;\n    for (var k = 0; k < segLen; k++) {\n        var p = points[idx];\n        if (idx >= allLen || idx < 0) {\n            break;\n        }\n        if (isPointNull(p)) {\n            if (connectNulls) {\n                idx += dir;\n                continue;\n            }\n            break;\n        }\n\n        if (idx === start) {\n            ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);\n            v2Copy(cp0, p);\n        }\n        else {\n            if (smooth > 0) {\n                var nextIdx = idx + dir;\n                var nextP = points[nextIdx];\n                if (connectNulls) {\n                    // Find next point not null\n                    while (nextP && isPointNull(points[nextIdx])) {\n                        nextIdx += dir;\n                        nextP = points[nextIdx];\n                    }\n                }\n\n                var ratioNextSeg = 0.5;\n                var prevP = points[prevIdx];\n                var nextP = points[nextIdx];\n                // Last point\n                if (!nextP || isPointNull(nextP)) {\n                    v2Copy(cp1, p);\n                }\n                else {\n                    // If next data is null in not connect case\n                    if (isPointNull(nextP) && !connectNulls) {\n                        nextP = p;\n                    }\n\n                    sub(v, nextP, prevP);\n\n                    var lenPrevSeg;\n                    var lenNextSeg;\n                    if (smoothMonotone === 'x' || smoothMonotone === 'y') {\n                        var dim = smoothMonotone === 'x' ? 0 : 1;\n                        lenPrevSeg = Math.abs(p[dim] - prevP[dim]);\n                        lenNextSeg = Math.abs(p[dim] - nextP[dim]);\n                    }\n                    else {\n                        lenPrevSeg = dist(p, prevP);\n                        lenNextSeg = dist(p, nextP);\n                    }\n\n                    // Use ratio of seg length\n                    ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg);\n\n                    scaleAndAdd$1(cp1, p, v, -smooth * (1 - ratioNextSeg));\n                }\n                // Smooth constraint\n                vec2Min(cp0, cp0, smoothMax);\n                vec2Max(cp0, cp0, smoothMin);\n                vec2Min(cp1, cp1, smoothMax);\n                vec2Max(cp1, cp1, smoothMin);\n\n                ctx.bezierCurveTo(\n                    cp0[0], cp0[1],\n                    cp1[0], cp1[1],\n                    p[0], p[1]\n                );\n                // cp0 of next segment\n                scaleAndAdd$1(cp0, p, v, smooth * ratioNextSeg);\n            }\n            else {\n                ctx.lineTo(p[0], p[1]);\n            }\n        }\n\n        prevIdx = idx;\n        idx += dir;\n    }\n\n    return k;\n}\n\nfunction getBoundingBox(points, smoothConstraint) {\n    var ptMin = [Infinity, Infinity];\n    var ptMax = [-Infinity, -Infinity];\n    if (smoothConstraint) {\n        for (var i = 0; i < points.length; i++) {\n            var pt = points[i];\n            if (pt[0] < ptMin[0]) {\n                ptMin[0] = pt[0];\n            }\n            if (pt[1] < ptMin[1]) {\n                ptMin[1] = pt[1];\n            }\n            if (pt[0] > ptMax[0]) {\n                ptMax[0] = pt[0];\n            }\n            if (pt[1] > ptMax[1]) {\n                ptMax[1] = pt[1];\n            }\n        }\n    }\n    return {\n        min: smoothConstraint ? ptMin : ptMax,\n        max: smoothConstraint ? ptMax : ptMin\n    };\n}\n\nvar Polyline$1 = Path.extend({\n\n    type: 'ec-polyline',\n\n    shape: {\n        points: [],\n\n        smooth: 0,\n\n        smoothConstraint: true,\n\n        smoothMonotone: null,\n\n        connectNulls: false\n    },\n\n    style: {\n        fill: null,\n\n        stroke: '#000'\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n        var points = shape.points;\n\n        var i = 0;\n        var len$$1 = points.length;\n\n        var result = getBoundingBox(points, shape.smoothConstraint);\n\n        if (shape.connectNulls) {\n            // Must remove first and last null values avoid draw error in polygon\n            for (; len$$1 > 0; len$$1--) {\n                if (!isPointNull(points[len$$1 - 1])) {\n                    break;\n                }\n            }\n            for (; i < len$$1; i++) {\n                if (!isPointNull(points[i])) {\n                    break;\n                }\n            }\n        }\n        while (i < len$$1) {\n            i += drawSegment(\n                ctx, points, i, len$$1, len$$1,\n                1, result.min, result.max, shape.smooth,\n                shape.smoothMonotone, shape.connectNulls\n            ) + 1;\n        }\n    }\n});\n\nvar Polygon$1 = Path.extend({\n\n    type: 'ec-polygon',\n\n    shape: {\n        points: [],\n\n        // Offset between stacked base points and points\n        stackedOnPoints: [],\n\n        smooth: 0,\n\n        stackedOnSmooth: 0,\n\n        smoothConstraint: true,\n\n        smoothMonotone: null,\n\n        connectNulls: false\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n        var points = shape.points;\n        var stackedOnPoints = shape.stackedOnPoints;\n\n        var i = 0;\n        var len$$1 = points.length;\n        var smoothMonotone = shape.smoothMonotone;\n        var bbox = getBoundingBox(points, shape.smoothConstraint);\n        var stackedOnBBox = getBoundingBox(stackedOnPoints, shape.smoothConstraint);\n\n        if (shape.connectNulls) {\n            // Must remove first and last null values avoid draw error in polygon\n            for (; len$$1 > 0; len$$1--) {\n                if (!isPointNull(points[len$$1 - 1])) {\n                    break;\n                }\n            }\n            for (; i < len$$1; i++) {\n                if (!isPointNull(points[i])) {\n                    break;\n                }\n            }\n        }\n        while (i < len$$1) {\n            var k = drawSegment(\n                ctx, points, i, len$$1, len$$1,\n                1, bbox.min, bbox.max, shape.smooth,\n                smoothMonotone, shape.connectNulls\n            );\n            drawSegment(\n                ctx, stackedOnPoints, i + k - 1, k, len$$1,\n                -1, stackedOnBBox.min, stackedOnBBox.max, shape.stackedOnSmooth,\n                smoothMonotone, shape.connectNulls\n            );\n            i += k + 1;\n\n            ctx.closePath();\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME step not support polar\n\nfunction isPointsSame(points1, points2) {\n    if (points1.length !== points2.length) {\n        return;\n    }\n    for (var i = 0; i < points1.length; i++) {\n        var p1 = points1[i];\n        var p2 = points2[i];\n        if (p1[0] !== p2[0] || p1[1] !== p2[1]) {\n            return;\n        }\n    }\n    return true;\n}\n\nfunction getSmooth(smooth) {\n    return typeof (smooth) === 'number' ? smooth : (smooth ? 0.5 : 0);\n}\n\nfunction getAxisExtentWithGap(axis) {\n    var extent = axis.getGlobalExtent();\n    if (axis.onBand) {\n        // Remove extra 1px to avoid line miter in clipped edge\n        var halfBandWidth = axis.getBandWidth() / 2 - 1;\n        var dir = extent[1] > extent[0] ? 1 : -1;\n        extent[0] += dir * halfBandWidth;\n        extent[1] -= dir * halfBandWidth;\n    }\n    return extent;\n}\n\n/**\n * @param {module:echarts/coord/cartesian/Cartesian2D|module:echarts/coord/polar/Polar} coordSys\n * @param {module:echarts/data/List} data\n * @param {Object} dataCoordInfo\n * @param {Array.<Array.<number>>} points\n */\nfunction getStackedOnPoints(coordSys, data, dataCoordInfo) {\n    if (!dataCoordInfo.valueDim) {\n        return [];\n    }\n\n    var points = [];\n    for (var idx = 0, len = data.count(); idx < len; idx++) {\n        points.push(getStackedOnPoint(dataCoordInfo, coordSys, data, idx));\n    }\n\n    return points;\n}\n\nfunction createGridClipShape(cartesian, hasAnimation, forSymbol, seriesModel) {\n    var xExtent = getAxisExtentWithGap(cartesian.getAxis('x'));\n    var yExtent = getAxisExtentWithGap(cartesian.getAxis('y'));\n    var isHorizontal = cartesian.getBaseAxis().isHorizontal();\n\n    var x = Math.min(xExtent[0], xExtent[1]);\n    var y = Math.min(yExtent[0], yExtent[1]);\n    var width = Math.max(xExtent[0], xExtent[1]) - x;\n    var height = Math.max(yExtent[0], yExtent[1]) - y;\n\n    // Avoid float number rounding error for symbol on the edge of axis extent.\n    // See #7913 and `test/dataZoom-clip.html`.\n    if (forSymbol) {\n        x -= 0.5;\n        width += 0.5;\n        y -= 0.5;\n        height += 0.5;\n    }\n    else {\n        var lineWidth = seriesModel.get('lineStyle.width') || 2;\n        // Expand clip shape to avoid clipping when line value exceeds axis\n        var expandSize = seriesModel.get('clipOverflow') ? lineWidth / 2 : Math.max(width, height);\n        if (isHorizontal) {\n            y -= expandSize;\n            height += expandSize * 2;\n        }\n        else {\n            x -= expandSize;\n            width += expandSize * 2;\n        }\n    }\n\n    var clipPath = new Rect({\n        shape: {\n            x: x,\n            y: y,\n            width: width,\n            height: height\n        }\n    });\n\n    if (hasAnimation) {\n        clipPath.shape[isHorizontal ? 'width' : 'height'] = 0;\n        initProps(clipPath, {\n            shape: {\n                width: width,\n                height: height\n            }\n        }, seriesModel);\n    }\n\n    return clipPath;\n}\n\nfunction createPolarClipShape(polar, hasAnimation, forSymbol, seriesModel) {\n    var angleAxis = polar.getAngleAxis();\n    var radiusAxis = polar.getRadiusAxis();\n\n    var radiusExtent = radiusAxis.getExtent().slice();\n    radiusExtent[0] > radiusExtent[1] && radiusExtent.reverse();\n    var angleExtent = angleAxis.getExtent();\n\n    var RADIAN = Math.PI / 180;\n\n    // Avoid float number rounding error for symbol on the edge of axis extent.\n    if (forSymbol) {\n        radiusExtent[0] -= 0.5;\n        radiusExtent[1] += 0.5;\n    }\n\n    var clipPath = new Sector({\n        shape: {\n            cx: round$2(polar.cx, 1),\n            cy: round$2(polar.cy, 1),\n            r0: round$2(radiusExtent[0], 1),\n            r: round$2(radiusExtent[1], 1),\n            startAngle: -angleExtent[0] * RADIAN,\n            endAngle: -angleExtent[1] * RADIAN,\n            clockwise: angleAxis.inverse\n        }\n    });\n\n    if (hasAnimation) {\n        clipPath.shape.endAngle = -angleExtent[0] * RADIAN;\n        initProps(clipPath, {\n            shape: {\n                endAngle: -angleExtent[1] * RADIAN\n            }\n        }, seriesModel);\n    }\n\n    return clipPath;\n}\n\nfunction createClipShape(coordSys, hasAnimation, forSymbol, seriesModel) {\n    return coordSys.type === 'polar'\n        ? createPolarClipShape(coordSys, hasAnimation, forSymbol, seriesModel)\n        : createGridClipShape(coordSys, hasAnimation, forSymbol, seriesModel);\n}\n\nfunction turnPointsIntoStep(points, coordSys, stepTurnAt) {\n    var baseAxis = coordSys.getBaseAxis();\n    var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1;\n\n    var stepPoints = [];\n    for (var i = 0; i < points.length - 1; i++) {\n        var nextPt = points[i + 1];\n        var pt = points[i];\n        stepPoints.push(pt);\n\n        var stepPt = [];\n        switch (stepTurnAt) {\n            case 'end':\n                stepPt[baseIndex] = nextPt[baseIndex];\n                stepPt[1 - baseIndex] = pt[1 - baseIndex];\n                // default is start\n                stepPoints.push(stepPt);\n                break;\n            case 'middle':\n                // default is start\n                var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2;\n                var stepPt2 = [];\n                stepPt[baseIndex] = stepPt2[baseIndex] = middle;\n                stepPt[1 - baseIndex] = pt[1 - baseIndex];\n                stepPt2[1 - baseIndex] = nextPt[1 - baseIndex];\n                stepPoints.push(stepPt);\n                stepPoints.push(stepPt2);\n                break;\n            default:\n                stepPt[baseIndex] = pt[baseIndex];\n                stepPt[1 - baseIndex] = nextPt[1 - baseIndex];\n                // default is start\n                stepPoints.push(stepPt);\n        }\n    }\n    // Last points\n    points[i] && stepPoints.push(points[i]);\n    return stepPoints;\n}\n\nfunction getVisualGradient(data, coordSys) {\n    var visualMetaList = data.getVisual('visualMeta');\n    if (!visualMetaList || !visualMetaList.length || !data.count()) {\n        // When data.count() is 0, gradient range can not be calculated.\n        return;\n    }\n\n    if (coordSys.type !== 'cartesian2d') {\n        if (__DEV__) {\n            console.warn('Visual map on line style is only supported on cartesian2d.');\n        }\n        return;\n    }\n\n    var coordDim;\n    var visualMeta;\n\n    for (var i = visualMetaList.length - 1; i >= 0; i--) {\n        var dimIndex = visualMetaList[i].dimension;\n        var dimName = data.dimensions[dimIndex];\n        var dimInfo = data.getDimensionInfo(dimName);\n        coordDim = dimInfo && dimInfo.coordDim;\n        // Can only be x or y\n        if (coordDim === 'x' || coordDim === 'y') {\n            visualMeta = visualMetaList[i];\n            break;\n        }\n    }\n\n    if (!visualMeta) {\n        if (__DEV__) {\n            console.warn('Visual map on line style only support x or y dimension.');\n        }\n        return;\n    }\n\n    // If the area to be rendered is bigger than area defined by LinearGradient,\n    // the canvas spec prescribes that the color of the first stop and the last\n    // stop should be used. But if two stops are added at offset 0, in effect\n    // browsers use the color of the second stop to render area outside\n    // LinearGradient. So we can only infinitesimally extend area defined in\n    // LinearGradient to render `outerColors`.\n\n    var axis = coordSys.getAxis(coordDim);\n\n    // dataToCoor mapping may not be linear, but must be monotonic.\n    var colorStops = map(visualMeta.stops, function (stop) {\n        return {\n            coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)),\n            color: stop.color\n        };\n    });\n    var stopLen = colorStops.length;\n    var outerColors = visualMeta.outerColors.slice();\n\n    if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) {\n        colorStops.reverse();\n        outerColors.reverse();\n    }\n\n    var tinyExtent = 10; // Arbitrary value: 10px\n    var minCoord = colorStops[0].coord - tinyExtent;\n    var maxCoord = colorStops[stopLen - 1].coord + tinyExtent;\n    var coordSpan = maxCoord - minCoord;\n\n    if (coordSpan < 1e-3) {\n        return 'transparent';\n    }\n\n    each$1(colorStops, function (stop) {\n        stop.offset = (stop.coord - minCoord) / coordSpan;\n    });\n    colorStops.push({\n        offset: stopLen ? colorStops[stopLen - 1].offset : 0.5,\n        color: outerColors[1] || 'transparent'\n    });\n    colorStops.unshift({ // notice colorStops.length have been changed.\n        offset: stopLen ? colorStops[0].offset : 0.5,\n        color: outerColors[0] || 'transparent'\n    });\n\n    // zrUtil.each(colorStops, function (colorStop) {\n    //     // Make sure each offset has rounded px to avoid not sharp edge\n    //     colorStop.offset = (Math.round(colorStop.offset * (end - start) + start) - start) / (end - start);\n    // });\n\n    var gradient = new LinearGradient(0, 0, 0, 0, colorStops, true);\n    gradient[coordDim] = minCoord;\n    gradient[coordDim + '2'] = maxCoord;\n\n    return gradient;\n}\n\nfunction getIsIgnoreFunc(seriesModel, data, coordSys) {\n    var showAllSymbol = seriesModel.get('showAllSymbol');\n    var isAuto = showAllSymbol === 'auto';\n\n    if (showAllSymbol && !isAuto) {\n        return;\n    }\n\n    var categoryAxis = coordSys.getAxesByScale('ordinal')[0];\n    if (!categoryAxis) {\n        return;\n    }\n\n    // Note that category label interval strategy might bring some weird effect\n    // in some scenario: users may wonder why some of the symbols are not\n    // displayed. So we show all symbols as possible as we can.\n    if (isAuto\n        // Simplify the logic, do not determine label overlap here.\n        && canShowAllSymbolForCategory(categoryAxis, data)\n    ) {\n        return;\n    }\n\n    // Otherwise follow the label interval strategy on category axis.\n    var categoryDataDim = data.mapDimension(categoryAxis.dim);\n    var labelMap = {};\n\n    each$1(categoryAxis.getViewLabels(), function (labelItem) {\n        labelMap[labelItem.tickValue] = 1;\n    });\n\n    return function (dataIndex) {\n        return !labelMap.hasOwnProperty(data.get(categoryDataDim, dataIndex));\n    };\n}\n\nfunction canShowAllSymbolForCategory(categoryAxis, data) {\n    // In mose cases, line is monotonous on category axis, and the label size\n    // is close with each other. So we check the symbol size and some of the\n    // label size alone with the category axis to estimate whether all symbol\n    // can be shown without overlap.\n    var axisExtent = categoryAxis.getExtent();\n    var availSize = Math.abs(axisExtent[1] - axisExtent[0]) / categoryAxis.scale.count();\n    isNaN(availSize) && (availSize = 0); // 0/0 is NaN.\n\n    // Sampling some points, max 5.\n    var dataLen = data.count();\n    var step = Math.max(1, Math.round(dataLen / 5));\n    for (var dataIndex = 0; dataIndex < dataLen; dataIndex += step) {\n        if (SymbolClz$1.getSymbolSize(\n                data, dataIndex\n            // Only for cartesian, where `isHorizontal` exists.\n            )[categoryAxis.isHorizontal() ? 1 : 0]\n            // Empirical number\n            * 1.5 > availSize\n        ) {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nChart.extend({\n\n    type: 'line',\n\n    init: function () {\n        var lineGroup = new Group();\n\n        var symbolDraw = new SymbolDraw();\n        this.group.add(symbolDraw.group);\n\n        this._symbolDraw = symbolDraw;\n        this._lineGroup = lineGroup;\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var group = this.group;\n        var data = seriesModel.getData();\n        var lineStyleModel = seriesModel.getModel('lineStyle');\n        var areaStyleModel = seriesModel.getModel('areaStyle');\n\n        var points = data.mapArray(data.getItemLayout);\n\n        var isCoordSysPolar = coordSys.type === 'polar';\n        var prevCoordSys = this._coordSys;\n\n        var symbolDraw = this._symbolDraw;\n        var polyline = this._polyline;\n        var polygon = this._polygon;\n\n        var lineGroup = this._lineGroup;\n\n        var hasAnimation = seriesModel.get('animation');\n\n        var isAreaChart = !areaStyleModel.isEmpty();\n\n        var valueOrigin = areaStyleModel.get('origin');\n        var dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin);\n\n        var stackedOnPoints = getStackedOnPoints(coordSys, data, dataCoordInfo);\n\n        var showSymbol = seriesModel.get('showSymbol');\n\n        var isIgnoreFunc = showSymbol && !isCoordSysPolar\n            && getIsIgnoreFunc(seriesModel, data, coordSys);\n\n        // Remove temporary symbols\n        var oldData = this._data;\n        oldData && oldData.eachItemGraphicEl(function (el, idx) {\n            if (el.__temp) {\n                group.remove(el);\n                oldData.setItemGraphicEl(idx, null);\n            }\n        });\n\n        // Remove previous created symbols if showSymbol changed to false\n        if (!showSymbol) {\n            symbolDraw.remove();\n        }\n\n        group.add(lineGroup);\n\n        // FIXME step not support polar\n        var step = !isCoordSysPolar && seriesModel.get('step');\n        // Initialization animation or coordinate system changed\n        if (\n            !(polyline && prevCoordSys.type === coordSys.type && step === this._step)\n        ) {\n            showSymbol && symbolDraw.updateData(data, {\n                isIgnore: isIgnoreFunc,\n                clipShape: createClipShape(coordSys, false, true, seriesModel)\n            });\n\n            if (step) {\n                // TODO If stacked series is not step\n                points = turnPointsIntoStep(points, coordSys, step);\n                stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);\n            }\n\n            polyline = this._newPolyline(points, coordSys, hasAnimation);\n            if (isAreaChart) {\n                polygon = this._newPolygon(\n                    points, stackedOnPoints,\n                    coordSys, hasAnimation\n                );\n            }\n            lineGroup.setClipPath(createClipShape(coordSys, true, false, seriesModel));\n        }\n        else {\n            if (isAreaChart && !polygon) {\n                // If areaStyle is added\n                polygon = this._newPolygon(\n                    points, stackedOnPoints,\n                    coordSys, hasAnimation\n                );\n            }\n            else if (polygon && !isAreaChart) {\n                // If areaStyle is removed\n                lineGroup.remove(polygon);\n                polygon = this._polygon = null;\n            }\n\n            // Update clipPath\n            lineGroup.setClipPath(createClipShape(coordSys, false, false, seriesModel));\n\n            // Always update, or it is wrong in the case turning on legend\n            // because points are not changed\n            showSymbol && symbolDraw.updateData(data, {\n                isIgnore: isIgnoreFunc,\n                clipShape: createClipShape(coordSys, false, true, seriesModel)\n            });\n\n            // Stop symbol animation and sync with line points\n            // FIXME performance?\n            data.eachItemGraphicEl(function (el) {\n                el.stopAnimation(true);\n            });\n\n            // In the case data zoom triggerred refreshing frequently\n            // Data may not change if line has a category axis. So it should animate nothing\n            if (!isPointsSame(this._stackedOnPoints, stackedOnPoints)\n                || !isPointsSame(this._points, points)\n            ) {\n                if (hasAnimation) {\n                    this._updateAnimation(\n                        data, stackedOnPoints, coordSys, api, step, valueOrigin\n                    );\n                }\n                else {\n                    // Not do it in update with animation\n                    if (step) {\n                        // TODO If stacked series is not step\n                        points = turnPointsIntoStep(points, coordSys, step);\n                        stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);\n                    }\n\n                    polyline.setShape({\n                        points: points\n                    });\n                    polygon && polygon.setShape({\n                        points: points,\n                        stackedOnPoints: stackedOnPoints\n                    });\n                }\n            }\n        }\n\n        var visualColor = getVisualGradient(data, coordSys) || data.getVisual('color');\n\n        polyline.useStyle(defaults(\n            // Use color in lineStyle first\n            lineStyleModel.getLineStyle(),\n            {\n                fill: 'none',\n                stroke: visualColor,\n                lineJoin: 'bevel'\n            }\n        ));\n\n        var smooth = seriesModel.get('smooth');\n        smooth = getSmooth(seriesModel.get('smooth'));\n        polyline.setShape({\n            smooth: smooth,\n            smoothMonotone: seriesModel.get('smoothMonotone'),\n            connectNulls: seriesModel.get('connectNulls')\n        });\n\n        if (polygon) {\n            var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');\n            var stackedOnSmooth = 0;\n\n            polygon.useStyle(defaults(\n                areaStyleModel.getAreaStyle(),\n                {\n                    fill: visualColor,\n                    opacity: 0.7,\n                    lineJoin: 'bevel'\n                }\n            ));\n\n            if (stackedOnSeries) {\n                stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth'));\n            }\n\n            polygon.setShape({\n                smooth: smooth,\n                stackedOnSmooth: stackedOnSmooth,\n                smoothMonotone: seriesModel.get('smoothMonotone'),\n                connectNulls: seriesModel.get('connectNulls')\n            });\n        }\n\n        this._data = data;\n        // Save the coordinate system for transition animation when data changed\n        this._coordSys = coordSys;\n        this._stackedOnPoints = stackedOnPoints;\n        this._points = points;\n        this._step = step;\n        this._valueOrigin = valueOrigin;\n    },\n\n    dispose: function () {},\n\n    highlight: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n        var dataIndex = queryDataIndex(data, payload);\n\n        if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) {\n            var symbol = data.getItemGraphicEl(dataIndex);\n            if (!symbol) {\n                // Create a temporary symbol if it is not exists\n                var pt = data.getItemLayout(dataIndex);\n                if (!pt) {\n                    // Null data\n                    return;\n                }\n                symbol = new SymbolClz$1(data, dataIndex);\n                symbol.position = pt;\n                symbol.setZ(\n                    seriesModel.get('zlevel'),\n                    seriesModel.get('z')\n                );\n                symbol.ignore = isNaN(pt[0]) || isNaN(pt[1]);\n                symbol.__temp = true;\n                data.setItemGraphicEl(dataIndex, symbol);\n\n                // Stop scale animation\n                symbol.stopSymbolAnimation(true);\n\n                this.group.add(symbol);\n            }\n            symbol.highlight();\n        }\n        else {\n            // Highlight whole series\n            Chart.prototype.highlight.call(\n                this, seriesModel, ecModel, api, payload\n            );\n        }\n    },\n\n    downplay: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n        var dataIndex = queryDataIndex(data, payload);\n        if (dataIndex != null && dataIndex >= 0) {\n            var symbol = data.getItemGraphicEl(dataIndex);\n            if (symbol) {\n                if (symbol.__temp) {\n                    data.setItemGraphicEl(dataIndex, null);\n                    this.group.remove(symbol);\n                }\n                else {\n                    symbol.downplay();\n                }\n            }\n        }\n        else {\n            // FIXME\n            // can not downplay completely.\n            // Downplay whole series\n            Chart.prototype.downplay.call(\n                this, seriesModel, ecModel, api, payload\n            );\n        }\n    },\n\n    /**\n     * @param {module:zrender/container/Group} group\n     * @param {Array.<Array.<number>>} points\n     * @private\n     */\n    _newPolyline: function (points) {\n        var polyline = this._polyline;\n        // Remove previous created polyline\n        if (polyline) {\n            this._lineGroup.remove(polyline);\n        }\n\n        polyline = new Polyline$1({\n            shape: {\n                points: points\n            },\n            silent: true,\n            z2: 10\n        });\n\n        this._lineGroup.add(polyline);\n\n        this._polyline = polyline;\n\n        return polyline;\n    },\n\n    /**\n     * @param {module:zrender/container/Group} group\n     * @param {Array.<Array.<number>>} stackedOnPoints\n     * @param {Array.<Array.<number>>} points\n     * @private\n     */\n    _newPolygon: function (points, stackedOnPoints) {\n        var polygon = this._polygon;\n        // Remove previous created polygon\n        if (polygon) {\n            this._lineGroup.remove(polygon);\n        }\n\n        polygon = new Polygon$1({\n            shape: {\n                points: points,\n                stackedOnPoints: stackedOnPoints\n            },\n            silent: true\n        });\n\n        this._lineGroup.add(polygon);\n\n        this._polygon = polygon;\n        return polygon;\n    },\n\n    /**\n     * @private\n     */\n    // FIXME Two value axis\n    _updateAnimation: function (data, stackedOnPoints, coordSys, api, step, valueOrigin) {\n        var polyline = this._polyline;\n        var polygon = this._polygon;\n        var seriesModel = data.hostModel;\n\n        var diff = lineAnimationDiff(\n            this._data, data,\n            this._stackedOnPoints, stackedOnPoints,\n            this._coordSys, coordSys,\n            this._valueOrigin, valueOrigin\n        );\n\n        var current = diff.current;\n        var stackedOnCurrent = diff.stackedOnCurrent;\n        var next = diff.next;\n        var stackedOnNext = diff.stackedOnNext;\n        if (step) {\n            // TODO If stacked series is not step\n            current = turnPointsIntoStep(diff.current, coordSys, step);\n            stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step);\n            next = turnPointsIntoStep(diff.next, coordSys, step);\n            stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step);\n        }\n        // `diff.current` is subset of `current` (which should be ensured by\n        // turnPointsIntoStep), so points in `__points` can be updated when\n        // points in `current` are update during animation.\n        polyline.shape.__points = diff.current;\n        polyline.shape.points = current;\n\n        updateProps(polyline, {\n            shape: {\n                points: next\n            }\n        }, seriesModel);\n\n        if (polygon) {\n            polygon.setShape({\n                points: current,\n                stackedOnPoints: stackedOnCurrent\n            });\n            updateProps(polygon, {\n                shape: {\n                    points: next,\n                    stackedOnPoints: stackedOnNext\n                }\n            }, seriesModel);\n        }\n\n        var updatedDataInfo = [];\n        var diffStatus = diff.status;\n\n        for (var i = 0; i < diffStatus.length; i++) {\n            var cmd = diffStatus[i].cmd;\n            if (cmd === '=') {\n                var el = data.getItemGraphicEl(diffStatus[i].idx1);\n                if (el) {\n                    updatedDataInfo.push({\n                        el: el,\n                        ptIdx: i    // Index of points\n                    });\n                }\n            }\n        }\n\n        if (polyline.animators && polyline.animators.length) {\n            polyline.animators[0].during(function () {\n                for (var i = 0; i < updatedDataInfo.length; i++) {\n                    var el = updatedDataInfo[i].el;\n                    el.attr('position', polyline.shape.__points[updatedDataInfo[i].ptIdx]);\n                }\n            });\n        }\n    },\n\n    remove: function (ecModel) {\n        var group = this.group;\n        var oldData = this._data;\n        this._lineGroup.removeAll();\n        this._symbolDraw.remove(true);\n        // Remove temporary created elements when highlighting\n        oldData && oldData.eachItemGraphicEl(function (el, idx) {\n            if (el.__temp) {\n                group.remove(el);\n                oldData.setItemGraphicEl(idx, null);\n            }\n        });\n\n        this._polyline\n            = this._polygon\n            = this._coordSys\n            = this._points\n            = this._stackedOnPoints\n            = this._data = null;\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar visualSymbol = function (seriesType, defaultSymbolType, legendSymbol) {\n    // Encoding visual for all series include which is filtered for legend drawing\n    return {\n        seriesType: seriesType,\n\n        // For legend.\n        performRawSeries: true,\n\n        reset: function (seriesModel, ecModel, api) {\n            var data = seriesModel.getData();\n\n            var symbolType = seriesModel.get('symbol') || defaultSymbolType;\n            var symbolSize = seriesModel.get('symbolSize');\n            var keepAspect = seriesModel.get('symbolKeepAspect');\n\n            data.setVisual({\n                legendSymbol: legendSymbol || symbolType,\n                symbol: symbolType,\n                symbolSize: symbolSize,\n                symbolKeepAspect: keepAspect\n            });\n\n            // Only visible series has each data be visual encoded\n            if (ecModel.isSeriesFiltered(seriesModel)) {\n                return;\n            }\n\n            var hasCallback = typeof symbolSize === 'function';\n\n            function dataEach(data, idx) {\n                if (typeof symbolSize === 'function') {\n                    var rawValue = seriesModel.getRawValue(idx);\n                    // FIXME\n                    var params = seriesModel.getDataParams(idx);\n                    data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params));\n                }\n\n                if (data.hasItemOption) {\n                    var itemModel = data.getItemModel(idx);\n                    var itemSymbolType = itemModel.getShallow('symbol', true);\n                    var itemSymbolSize = itemModel.getShallow('symbolSize',\n                        true);\n                    var itemSymbolKeepAspect\n                        = itemModel.getShallow('symbolKeepAspect', true);\n\n                    // If has item symbol\n                    if (itemSymbolType != null) {\n                        data.setItemVisual(idx, 'symbol', itemSymbolType);\n                    }\n                    if (itemSymbolSize != null) {\n                        // PENDING Transform symbolSize ?\n                        data.setItemVisual(idx, 'symbolSize', itemSymbolSize);\n                    }\n                    if (itemSymbolKeepAspect != null) {\n                        data.setItemVisual(idx, 'symbolKeepAspect',\n                            itemSymbolKeepAspect);\n                    }\n                }\n            }\n\n            return { dataEach: (data.hasItemOption || hasCallback) ? dataEach : null };\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar pointsLayout = function (seriesType) {\n    return {\n        seriesType: seriesType,\n\n        plan: createRenderPlanner(),\n\n        reset: function (seriesModel) {\n            var data = seriesModel.getData();\n            var coordSys = seriesModel.coordinateSystem;\n            var pipelineContext = seriesModel.pipelineContext;\n            var isLargeRender = pipelineContext.large;\n\n            if (!coordSys) {\n                return;\n            }\n\n            var dims = map(coordSys.dimensions, function (dim) {\n                return data.mapDimension(dim);\n            }).slice(0, 2);\n            var dimLen = dims.length;\n\n            var stackResultDim = data.getCalculationInfo('stackResultDimension');\n            if (isDimensionStacked(data, dims[0] /*, dims[1]*/)) {\n                dims[0] = stackResultDim;\n            }\n            if (isDimensionStacked(data, dims[1] /*, dims[0]*/)) {\n                dims[1] = stackResultDim;\n            }\n\n            function progress(params, data) {\n                var segCount = params.end - params.start;\n                var points = isLargeRender && new Float32Array(segCount * dimLen);\n\n                for (var i = params.start, offset = 0, tmpIn = [], tmpOut = []; i < params.end; i++) {\n                    var point;\n\n                    if (dimLen === 1) {\n                        var x = data.get(dims[0], i);\n                        point = !isNaN(x) && coordSys.dataToPoint(x, null, tmpOut);\n                    }\n                    else {\n                        var x = tmpIn[0] = data.get(dims[0], i);\n                        var y = tmpIn[1] = data.get(dims[1], i);\n                        // Also {Array.<number>}, not undefined to avoid if...else... statement\n                        point = !isNaN(x) && !isNaN(y) && coordSys.dataToPoint(tmpIn, null, tmpOut);\n                    }\n\n                    if (isLargeRender) {\n                        points[offset++] = point ? point[0] : NaN;\n                        points[offset++] = point ? point[1] : NaN;\n                    }\n                    else {\n                        data.setItemLayout(i, (point && point.slice()) || [NaN, NaN]);\n                    }\n                }\n\n                isLargeRender && data.setLayout('symbolPoints', points);\n            }\n\n            return dimLen && {progress: progress};\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar samplers = {\n    average: function (frame) {\n        var sum = 0;\n        var count = 0;\n        for (var i = 0; i < frame.length; i++) {\n            if (!isNaN(frame[i])) {\n                sum += frame[i];\n                count++;\n            }\n        }\n        // Return NaN if count is 0\n        return count === 0 ? NaN : sum / count;\n    },\n    sum: function (frame) {\n        var sum = 0;\n        for (var i = 0; i < frame.length; i++) {\n            // Ignore NaN\n            sum += frame[i] || 0;\n        }\n        return sum;\n    },\n    max: function (frame) {\n        var max = -Infinity;\n        for (var i = 0; i < frame.length; i++) {\n            frame[i] > max && (max = frame[i]);\n        }\n        // NaN will cause illegal axis extent.\n        return isFinite(max) ? max : NaN;\n    },\n    min: function (frame) {\n        var min = Infinity;\n        for (var i = 0; i < frame.length; i++) {\n            frame[i] < min && (min = frame[i]);\n        }\n        // NaN will cause illegal axis extent.\n        return isFinite(min) ? min : NaN;\n    },\n    // TODO\n    // Median\n    nearest: function (frame) {\n        return frame[0];\n    }\n};\n\nvar indexSampler = function (frame, value) {\n    return Math.round(frame.length / 2);\n};\n\nvar dataSample = function (seriesType) {\n    return {\n\n        seriesType: seriesType,\n\n        modifyOutputEnd: true,\n\n        reset: function (seriesModel, ecModel, api) {\n            var data = seriesModel.getData();\n            var sampling = seriesModel.get('sampling');\n            var coordSys = seriesModel.coordinateSystem;\n            // Only cartesian2d support down sampling\n            if (coordSys.type === 'cartesian2d' && sampling) {\n                var baseAxis = coordSys.getBaseAxis();\n                var valueAxis = coordSys.getOtherAxis(baseAxis);\n                var extent = baseAxis.getExtent();\n                // Coordinste system has been resized\n                var size = extent[1] - extent[0];\n                var rate = Math.round(data.count() / size);\n                if (rate > 1) {\n                    var sampler;\n                    if (typeof sampling === 'string') {\n                        sampler = samplers[sampling];\n                    }\n                    else if (typeof sampling === 'function') {\n                        sampler = sampling;\n                    }\n                    if (sampler) {\n                        // Only support sample the first dim mapped from value axis.\n                        seriesModel.setData(data.downSample(\n                            data.mapDimension(valueAxis.dim), 1 / rate, sampler, indexSampler\n                        ));\n                    }\n                }\n            }\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Cartesian coordinate system\n * @module  echarts/coord/Cartesian\n *\n */\n\nfunction dimAxisMapper(dim) {\n    return this._axes[dim];\n}\n\n/**\n * @alias module:echarts/coord/Cartesian\n * @constructor\n */\nvar Cartesian = function (name) {\n    this._axes = {};\n\n    this._dimList = [];\n\n    /**\n     * @type {string}\n     */\n    this.name = name || '';\n};\n\nCartesian.prototype = {\n\n    constructor: Cartesian,\n\n    type: 'cartesian',\n\n    /**\n     * Get axis\n     * @param  {number|string} dim\n     * @return {module:echarts/coord/Cartesian~Axis}\n     */\n    getAxis: function (dim) {\n        return this._axes[dim];\n    },\n\n    /**\n     * Get axes list\n     * @return {Array.<module:echarts/coord/Cartesian~Axis>}\n     */\n    getAxes: function () {\n        return map(this._dimList, dimAxisMapper, this);\n    },\n\n    /**\n     * Get axes list by given scale type\n     */\n    getAxesByScale: function (scaleType) {\n        scaleType = scaleType.toLowerCase();\n        return filter(\n            this.getAxes(),\n            function (axis) {\n                return axis.scale.type === scaleType;\n            }\n        );\n    },\n\n    /**\n     * Add axis\n     * @param {module:echarts/coord/Cartesian.Axis}\n     */\n    addAxis: function (axis) {\n        var dim = axis.dim;\n\n        this._axes[dim] = axis;\n\n        this._dimList.push(dim);\n    },\n\n    /**\n     * Convert data to coord in nd space\n     * @param {Array.<number>|Object.<string, number>} val\n     * @return {Array.<number>|Object.<string, number>}\n     */\n    dataToCoord: function (val) {\n        return this._dataCoordConvert(val, 'dataToCoord');\n    },\n\n    /**\n     * Convert coord in nd space to data\n     * @param  {Array.<number>|Object.<string, number>} val\n     * @return {Array.<number>|Object.<string, number>}\n     */\n    coordToData: function (val) {\n        return this._dataCoordConvert(val, 'coordToData');\n    },\n\n    _dataCoordConvert: function (input, method) {\n        var dimList = this._dimList;\n\n        var output = input instanceof Array ? [] : {};\n\n        for (var i = 0; i < dimList.length; i++) {\n            var dim = dimList[i];\n            var axis = this._axes[dim];\n\n            output[dim] = axis[method](input[dim]);\n        }\n\n        return output;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction Cartesian2D(name) {\n\n    Cartesian.call(this, name);\n}\n\nCartesian2D.prototype = {\n\n    constructor: Cartesian2D,\n\n    type: 'cartesian2d',\n\n    /**\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['x', 'y'],\n\n    /**\n     * Base axis will be used on stacking.\n     *\n     * @return {module:echarts/coord/cartesian/Axis2D}\n     */\n    getBaseAxis: function () {\n        return this.getAxesByScale('ordinal')[0]\n            || this.getAxesByScale('time')[0]\n            || this.getAxis('x');\n    },\n\n    /**\n     * If contain point\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    containPoint: function (point) {\n        var axisX = this.getAxis('x');\n        var axisY = this.getAxis('y');\n        return axisX.contain(axisX.toLocalCoord(point[0]))\n            && axisY.contain(axisY.toLocalCoord(point[1]));\n    },\n\n    /**\n     * If contain data\n     * @param {Array.<number>} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this.getAxis('x').containData(data[0])\n            && this.getAxis('y').containData(data[1]);\n    },\n\n    /**\n     * @param {Array.<number>} data\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, reserved, out) {\n        var xAxis = this.getAxis('x');\n        var yAxis = this.getAxis('y');\n        out = out || [];\n        out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(data[0]));\n        out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(data[1]));\n        return out;\n    },\n\n    /**\n     * @param {Array.<number>} data\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    clampData: function (data, out) {\n        var xScale = this.getAxis('x').scale;\n        var yScale = this.getAxis('y').scale;\n        var xAxisExtent = xScale.getExtent();\n        var yAxisExtent = yScale.getExtent();\n        var x = xScale.parse(data[0]);\n        var y = yScale.parse(data[1]);\n        out = out || [];\n        out[0] = Math.min(\n            Math.max(Math.min(xAxisExtent[0], xAxisExtent[1]), x),\n            Math.max(xAxisExtent[0], xAxisExtent[1])\n        );\n        out[1] = Math.min(\n            Math.max(Math.min(yAxisExtent[0], yAxisExtent[1]), y),\n            Math.max(yAxisExtent[0], yAxisExtent[1])\n        );\n\n        return out;\n    },\n\n    /**\n     * @param {Array.<number>} point\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    pointToData: function (point, out) {\n        var xAxis = this.getAxis('x');\n        var yAxis = this.getAxis('y');\n        out = out || [];\n        out[0] = xAxis.coordToData(xAxis.toLocalCoord(point[0]));\n        out[1] = yAxis.coordToData(yAxis.toLocalCoord(point[1]));\n        return out;\n    },\n\n    /**\n     * Get other axis\n     * @param {module:echarts/coord/cartesian/Axis2D} axis\n     */\n    getOtherAxis: function (axis) {\n        return this.getAxis(axis.dim === 'x' ? 'y' : 'x');\n    }\n\n};\n\ninherits(Cartesian2D, Cartesian);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Extend axis 2d\n * @constructor module:echarts/coord/cartesian/Axis2D\n * @extends {module:echarts/coord/cartesian/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n * @param {string} position\n */\nvar Axis2D = function (dim, scale, coordExtent, axisType, position) {\n    Axis.call(this, dim, scale, coordExtent);\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * Axis position\n     *  - 'top'\n     *  - 'bottom'\n     *  - 'left'\n     *  - 'right'\n     */\n    this.position = position || 'bottom';\n};\n\nAxis2D.prototype = {\n\n    constructor: Axis2D,\n\n    /**\n     * Index of axis, can be used as key\n     */\n    index: 0,\n\n    /**\n     * Implemented in <module:echarts/coord/cartesian/Grid>.\n     * @return {Array.<module:echarts/coord/cartesian/Axis2D>}\n     *         If not on zero of other axis, return null/undefined.\n     *         If no axes, return an empty array.\n     */\n    getAxesOnZeroOf: null,\n\n    /**\n     * Axis model\n     * @param {module:echarts/coord/cartesian/AxisModel}\n     */\n    model: null,\n\n    isHorizontal: function () {\n        var position = this.position;\n        return position === 'top' || position === 'bottom';\n    },\n\n    /**\n     * Each item cooresponds to this.getExtent(), which\n     * means globalExtent[0] may greater than globalExtent[1],\n     * unless `asc` is input.\n     *\n     * @param {boolean} [asc]\n     * @return {Array.<number>}\n     */\n    getGlobalExtent: function (asc) {\n        var ret = this.getExtent();\n        ret[0] = this.toGlobalCoord(ret[0]);\n        ret[1] = this.toGlobalCoord(ret[1]);\n        asc && ret[0] > ret[1] && ret.reverse();\n        return ret;\n    },\n\n    getOtherAxis: function () {\n        this.grid.getOtherAxis();\n    },\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.coordToData(this.toLocalCoord(point[this.dim === 'x' ? 0 : 1]), clamp);\n    },\n\n    /**\n     * Transform global coord to local coord,\n     * i.e. var localCoord = axis.toLocalCoord(80);\n     * designate by module:echarts/coord/cartesian/Grid.\n     * @type {Function}\n     */\n    toLocalCoord: null,\n\n    /**\n     * Transform global coord to local coord,\n     * i.e. var globalCoord = axis.toLocalCoord(40);\n     * designate by module:echarts/coord/cartesian/Grid.\n     * @type {Function}\n     */\n    toGlobalCoord: null\n\n};\n\ninherits(Axis2D, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar defaultOption = {\n    show: true,\n    zlevel: 0,\n    z: 0,\n    // Inverse the axis.\n    inverse: false,\n\n    // Axis name displayed.\n    name: '',\n    // 'start' | 'middle' | 'end'\n    nameLocation: 'end',\n    // By degree. By defualt auto rotate by nameLocation.\n    nameRotate: null,\n    nameTruncate: {\n        maxWidth: null,\n        ellipsis: '...',\n        placeholder: '.'\n    },\n    // Use global text style by default.\n    nameTextStyle: {},\n    // The gap between axisName and axisLine.\n    nameGap: 15,\n\n    // Default `false` to support tooltip.\n    silent: false,\n    // Default `false` to avoid legacy user event listener fail.\n    triggerEvent: false,\n\n    tooltip: {\n        show: false\n    },\n\n    axisPointer: {},\n\n    axisLine: {\n        show: true,\n        onZero: true,\n        onZeroAxisIndex: null,\n        lineStyle: {\n            color: '#333',\n            width: 1,\n            type: 'solid'\n        },\n        // The arrow at both ends the the axis.\n        symbol: ['none', 'none'],\n        symbolSize: [10, 15]\n    },\n    axisTick: {\n        show: true,\n        // Whether axisTick is inside the grid or outside the grid.\n        inside: false,\n        // The length of axisTick.\n        length: 5,\n        lineStyle: {\n            width: 1\n        }\n    },\n    axisLabel: {\n        show: true,\n        // Whether axisLabel is inside the grid or outside the grid.\n        inside: false,\n        rotate: 0,\n        // true | false | null/undefined (auto)\n        showMinLabel: null,\n        // true | false | null/undefined (auto)\n        showMaxLabel: null,\n        margin: 8,\n        // formatter: null,\n        fontSize: 12\n    },\n    splitLine: {\n        show: true,\n        lineStyle: {\n            color: ['#ccc'],\n            width: 1,\n            type: 'solid'\n        }\n    },\n    splitArea: {\n        show: false,\n        areaStyle: {\n            color: ['rgba(250,250,250,0.3)', 'rgba(200,200,200,0.3)']\n        }\n    }\n};\n\nvar axisDefault = {};\n\naxisDefault.categoryAxis = merge({\n    // The gap at both ends of the axis. For categoryAxis, boolean.\n    boundaryGap: true,\n    // Set false to faster category collection.\n    // Only usefull in the case like: category is\n    // ['2012-01-01', '2012-01-02', ...], where the input\n    // data has been ensured not duplicate and is large data.\n    // null means \"auto\":\n    // if axis.data provided, do not deduplication,\n    // else do deduplication.\n    deduplication: null,\n    // splitArea: {\n        // show: false\n    // },\n    splitLine: {\n        show: false\n    },\n    axisTick: {\n        // If tick is align with label when boundaryGap is true\n        alignWithLabel: false,\n        interval: 'auto'\n    },\n    axisLabel: {\n        interval: 'auto'\n    }\n}, defaultOption);\n\naxisDefault.valueAxis = merge({\n    // The gap at both ends of the axis. For value axis, [GAP, GAP], where\n    // `GAP` can be an absolute pixel number (like `35`), or percent (like `'30%'`)\n    boundaryGap: [0, 0],\n\n    // TODO\n    // min/max: [30, datamin, 60] or [20, datamin] or [datamin, 60]\n\n    // Min value of the axis. can be:\n    // + a number\n    // + 'dataMin': use the min value in data.\n    // + null/undefined: auto decide min value (consider pretty look and boundaryGap).\n    // min: null,\n\n    // Max value of the axis. can be:\n    // + a number\n    // + 'dataMax': use the max value in data.\n    // + null/undefined: auto decide max value (consider pretty look and boundaryGap).\n    // max: null,\n\n    // Readonly prop, specifies start value of the range when using data zoom.\n    // rangeStart: null\n\n    // Readonly prop, specifies end value of the range when using data zoom.\n    // rangeEnd: null\n\n    // Optional value can be:\n    // + `false`: always include value 0.\n    // + `true`: the extent do not consider value 0.\n    // scale: false,\n\n    // AxisTick and axisLabel and splitLine are caculated based on splitNumber.\n    splitNumber: 5\n\n    // Interval specifies the span of the ticks is mandatorily.\n    // interval: null\n\n    // Specify min interval when auto calculate tick interval.\n    // minInterval: null\n\n    // Specify max interval when auto calculate tick interval.\n    // maxInterval: null\n\n}, defaultOption);\n\naxisDefault.timeAxis = defaults({\n    scale: true,\n    min: 'dataMin',\n    max: 'dataMax'\n}, axisDefault.valueAxis);\n\naxisDefault.logAxis = defaults({\n    scale: true,\n    logBase: 10\n}, axisDefault.valueAxis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME axisType is fixed ?\nvar AXIS_TYPES = ['value', 'category', 'time', 'log'];\n\n/**\n * Generate sub axis model class\n * @param {string} axisName 'x' 'y' 'radius' 'angle' 'parallel'\n * @param {module:echarts/model/Component} BaseAxisModelClass\n * @param {Function} axisTypeDefaulter\n * @param {Object} [extraDefaultOption]\n */\nvar axisModelCreator = function (axisName, BaseAxisModelClass, axisTypeDefaulter, extraDefaultOption) {\n\n    each$1(AXIS_TYPES, function (axisType) {\n\n        BaseAxisModelClass.extend({\n\n            /**\n             * @readOnly\n             */\n            type: axisName + 'Axis.' + axisType,\n\n            mergeDefaultAndTheme: function (option, ecModel) {\n                var layoutMode = this.layoutMode;\n                var inputPositionParams = layoutMode\n                    ? getLayoutParams(option) : {};\n\n                var themeModel = ecModel.getTheme();\n                merge(option, themeModel.get(axisType + 'Axis'));\n                merge(option, this.getDefaultOption());\n\n                option.type = axisTypeDefaulter(axisName, option);\n\n                if (layoutMode) {\n                    mergeLayoutParam(option, inputPositionParams, layoutMode);\n                }\n            },\n\n            /**\n             * @override\n             */\n            optionUpdated: function () {\n                var thisOption = this.option;\n                if (thisOption.type === 'category') {\n                    this.__ordinalMeta = OrdinalMeta.createByAxisModel(this);\n                }\n            },\n\n            /**\n             * Should not be called before all of 'getInitailData' finished.\n             * Because categories are collected during initializing data.\n             */\n            getCategories: function (rawData) {\n                var option = this.option;\n                // FIXME\n                // warning if called before all of 'getInitailData' finished.\n                if (option.type === 'category') {\n                    if (rawData) {\n                        return option.data;\n                    }\n                    return this.__ordinalMeta.categories;\n                }\n            },\n\n            getOrdinalMeta: function () {\n                return this.__ordinalMeta;\n            },\n\n            defaultOption: mergeAll(\n                [\n                    {},\n                    axisDefault[axisType + 'Axis'],\n                    extraDefaultOption\n                ],\n                true\n            )\n        });\n    });\n\n    ComponentModel.registerSubTypeDefaulter(\n        axisName + 'Axis',\n        curry(axisTypeDefaulter, axisName)\n    );\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisModel = ComponentModel.extend({\n\n    type: 'cartesian2dAxis',\n\n    /**\n     * @type {module:echarts/coord/cartesian/Axis2D}\n     */\n    axis: null,\n\n    /**\n     * @override\n     */\n    init: function () {\n        AxisModel.superApply(this, 'init', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function () {\n        AxisModel.superApply(this, 'mergeOption', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     */\n    restoreData: function () {\n        AxisModel.superApply(this, 'restoreData', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     * @return {module:echarts/model/Component}\n     */\n    getCoordSysModel: function () {\n        return this.ecModel.queryComponents({\n            mainType: 'grid',\n            index: this.option.gridIndex,\n            id: this.option.gridId\n        })[0];\n    }\n\n});\n\nfunction getAxisType(axisDim, option) {\n    // Default axis with data is category axis\n    return option.type || (option.data ? 'category' : 'value');\n}\n\nmerge(AxisModel.prototype, axisModelCommonMixin);\n\nvar extraOption = {\n    // gridIndex: 0,\n    // gridId: '',\n\n    // Offset is for multiple axis on the same position\n    offset: 0\n};\n\naxisModelCreator('x', AxisModel, getAxisType, extraOption);\naxisModelCreator('y', AxisModel, getAxisType, extraOption);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Grid 是在有直角坐标系的时候必须要存在的\n// 所以这里也要被 Cartesian2D 依赖\n\nComponentModel.extend({\n\n    type: 'grid',\n\n    dependencies: ['xAxis', 'yAxis'],\n\n    layoutMode: 'box',\n\n    /**\n     * @type {module:echarts/coord/cartesian/Grid}\n     */\n    coordinateSystem: null,\n\n    defaultOption: {\n        show: false,\n        zlevel: 0,\n        z: 0,\n        left: '10%',\n        top: 60,\n        right: '10%',\n        bottom: 60,\n        // If grid size contain label\n        containLabel: false,\n        // width: {totalWidth} - left - right,\n        // height: {totalHeight} - top - bottom,\n        backgroundColor: 'rgba(0,0,0,0)',\n        borderWidth: 1,\n        borderColor: '#ccc'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Grid is a region which contains at most 4 cartesian systems\n *\n * TODO Default cartesian\n */\n\n// Depends on GridModel, AxisModel, which performs preprocess.\n/**\n * Check if the axis is used in the specified grid\n * @inner\n */\nfunction isAxisUsedInTheGrid(axisModel, gridModel, ecModel) {\n    return axisModel.getCoordSysModel() === gridModel;\n}\n\nfunction Grid(gridModel, ecModel, api) {\n    /**\n     * @type {Object.<string, module:echarts/coord/cartesian/Cartesian2D>}\n     * @private\n     */\n    this._coordsMap = {};\n\n    /**\n     * @type {Array.<module:echarts/coord/cartesian/Cartesian>}\n     * @private\n     */\n    this._coordsList = [];\n\n    /**\n     * @type {Object.<string, module:echarts/coord/cartesian/Axis2D>}\n     * @private\n     */\n    this._axesMap = {};\n\n    /**\n     * @type {Array.<module:echarts/coord/cartesian/Axis2D>}\n     * @private\n     */\n    this._axesList = [];\n\n    this._initCartesian(gridModel, ecModel, api);\n\n    this.model = gridModel;\n}\n\nvar gridProto = Grid.prototype;\n\ngridProto.type = 'grid';\n\ngridProto.axisPointerEnabled = true;\n\ngridProto.getRect = function () {\n    return this._rect;\n};\n\ngridProto.update = function (ecModel, api) {\n\n    var axesMap = this._axesMap;\n\n    this._updateScale(ecModel, this.model);\n\n    each$1(axesMap.x, function (xAxis) {\n        niceScaleExtent(xAxis.scale, xAxis.model);\n    });\n    each$1(axesMap.y, function (yAxis) {\n        niceScaleExtent(yAxis.scale, yAxis.model);\n    });\n\n    // Key: axisDim_axisIndex, value: boolean, whether onZero target.\n    var onZeroRecords = {};\n\n    each$1(axesMap.x, function (xAxis) {\n        fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords);\n    });\n    each$1(axesMap.y, function (yAxis) {\n        fixAxisOnZero(axesMap, 'x', yAxis, onZeroRecords);\n    });\n\n    // Resize again if containLabel is enabled\n    // FIXME It may cause getting wrong grid size in data processing stage\n    this.resize(this.model, api);\n};\n\nfunction fixAxisOnZero(axesMap, otherAxisDim, axis, onZeroRecords) {\n\n    axis.getAxesOnZeroOf = function () {\n        // TODO: onZero of multiple axes.\n        return otherAxisOnZeroOf ? [otherAxisOnZeroOf] : [];\n    };\n\n    // onZero can not be enabled in these two situations:\n    // 1. When any other axis is a category axis.\n    // 2. When no axis is cross 0 point.\n    var otherAxes = axesMap[otherAxisDim];\n\n    var otherAxisOnZeroOf;\n    var axisModel = axis.model;\n    var onZero = axisModel.get('axisLine.onZero');\n    var onZeroAxisIndex = axisModel.get('axisLine.onZeroAxisIndex');\n\n    if (!onZero) {\n        return;\n    }\n\n    // If target axis is specified.\n    if (onZeroAxisIndex != null) {\n        if (canOnZeroToAxis(otherAxes[onZeroAxisIndex])) {\n            otherAxisOnZeroOf = otherAxes[onZeroAxisIndex];\n        }\n    }\n    else {\n        // Find the first available other axis.\n        for (var idx in otherAxes) {\n            if (otherAxes.hasOwnProperty(idx)\n                && canOnZeroToAxis(otherAxes[idx])\n                // Consider that two Y axes on one value axis,\n                // if both onZero, the two Y axes overlap.\n                && !onZeroRecords[getOnZeroRecordKey(otherAxes[idx])]\n            ) {\n                otherAxisOnZeroOf = otherAxes[idx];\n                break;\n            }\n        }\n    }\n\n    if (otherAxisOnZeroOf) {\n        onZeroRecords[getOnZeroRecordKey(otherAxisOnZeroOf)] = true;\n    }\n\n    function getOnZeroRecordKey(axis) {\n        return axis.dim + '_' + axis.index;\n    }\n}\n\nfunction canOnZeroToAxis(axis) {\n    return axis && axis.type !== 'category' && axis.type !== 'time' && ifAxisCrossZero(axis);\n}\n\n/**\n * Resize the grid\n * @param {module:echarts/coord/cartesian/GridModel} gridModel\n * @param {module:echarts/ExtensionAPI} api\n */\ngridProto.resize = function (gridModel, api, ignoreContainLabel) {\n\n    var gridRect = getLayoutRect(\n        gridModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        });\n\n    this._rect = gridRect;\n\n    var axesList = this._axesList;\n\n    adjustAxes();\n\n    // Minus label size\n    if (!ignoreContainLabel && gridModel.get('containLabel')) {\n        each$1(axesList, function (axis) {\n            if (!axis.model.get('axisLabel.inside')) {\n                var labelUnionRect = estimateLabelUnionRect(axis);\n                if (labelUnionRect) {\n                    var dim = axis.isHorizontal() ? 'height' : 'width';\n                    var margin = axis.model.get('axisLabel.margin');\n                    gridRect[dim] -= labelUnionRect[dim] + margin;\n                    if (axis.position === 'top') {\n                        gridRect.y += labelUnionRect.height + margin;\n                    }\n                    else if (axis.position === 'left') {\n                        gridRect.x += labelUnionRect.width + margin;\n                    }\n                }\n            }\n        });\n\n        adjustAxes();\n    }\n\n    function adjustAxes() {\n        each$1(axesList, function (axis) {\n            var isHorizontal = axis.isHorizontal();\n            var extent = isHorizontal ? [0, gridRect.width] : [0, gridRect.height];\n            var idx = axis.inverse ? 1 : 0;\n            axis.setExtent(extent[idx], extent[1 - idx]);\n            updateAxisTransform(axis, isHorizontal ? gridRect.x : gridRect.y);\n        });\n    }\n};\n\n/**\n * @param {string} axisType\n * @param {number} [axisIndex]\n */\ngridProto.getAxis = function (axisType, axisIndex) {\n    var axesMapOnDim = this._axesMap[axisType];\n    if (axesMapOnDim != null) {\n        if (axisIndex == null) {\n            // Find first axis\n            for (var name in axesMapOnDim) {\n                if (axesMapOnDim.hasOwnProperty(name)) {\n                    return axesMapOnDim[name];\n                }\n            }\n        }\n        return axesMapOnDim[axisIndex];\n    }\n};\n\n/**\n * @return {Array.<module:echarts/coord/Axis>}\n */\ngridProto.getAxes = function () {\n    return this._axesList.slice();\n};\n\n/**\n * Usage:\n *      grid.getCartesian(xAxisIndex, yAxisIndex);\n *      grid.getCartesian(xAxisIndex);\n *      grid.getCartesian(null, yAxisIndex);\n *      grid.getCartesian({xAxisIndex: ..., yAxisIndex: ...});\n *\n * @param {number|Object} [xAxisIndex]\n * @param {number} [yAxisIndex]\n */\ngridProto.getCartesian = function (xAxisIndex, yAxisIndex) {\n    if (xAxisIndex != null && yAxisIndex != null) {\n        var key = 'x' + xAxisIndex + 'y' + yAxisIndex;\n        return this._coordsMap[key];\n    }\n\n    if (isObject$1(xAxisIndex)) {\n        yAxisIndex = xAxisIndex.yAxisIndex;\n        xAxisIndex = xAxisIndex.xAxisIndex;\n    }\n    // When only xAxisIndex or yAxisIndex given, find its first cartesian.\n    for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) {\n        if (coordList[i].getAxis('x').index === xAxisIndex\n            || coordList[i].getAxis('y').index === yAxisIndex\n        ) {\n            return coordList[i];\n        }\n    }\n};\n\ngridProto.getCartesians = function () {\n    return this._coordsList.slice();\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.convertToPixel = function (ecModel, finder, value) {\n    var target = this._findConvertTarget(ecModel, finder);\n\n    return target.cartesian\n        ? target.cartesian.dataToPoint(value)\n        : target.axis\n        ? target.axis.toGlobalCoord(target.axis.dataToCoord(value))\n        : null;\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.convertFromPixel = function (ecModel, finder, value) {\n    var target = this._findConvertTarget(ecModel, finder);\n\n    return target.cartesian\n        ? target.cartesian.pointToData(value)\n        : target.axis\n        ? target.axis.coordToData(target.axis.toLocalCoord(value))\n        : null;\n};\n\n/**\n * @inner\n */\ngridProto._findConvertTarget = function (ecModel, finder) {\n    var seriesModel = finder.seriesModel;\n    var xAxisModel = finder.xAxisModel\n        || (seriesModel && seriesModel.getReferringComponents('xAxis')[0]);\n    var yAxisModel = finder.yAxisModel\n        || (seriesModel && seriesModel.getReferringComponents('yAxis')[0]);\n    var gridModel = finder.gridModel;\n    var coordsList = this._coordsList;\n    var cartesian;\n    var axis;\n\n    if (seriesModel) {\n        cartesian = seriesModel.coordinateSystem;\n        indexOf(coordsList, cartesian) < 0 && (cartesian = null);\n    }\n    else if (xAxisModel && yAxisModel) {\n        cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);\n    }\n    else if (xAxisModel) {\n        axis = this.getAxis('x', xAxisModel.componentIndex);\n    }\n    else if (yAxisModel) {\n        axis = this.getAxis('y', yAxisModel.componentIndex);\n    }\n    // Lowest priority.\n    else if (gridModel) {\n        var grid = gridModel.coordinateSystem;\n        if (grid === this) {\n            cartesian = this._coordsList[0];\n        }\n    }\n\n    return {cartesian: cartesian, axis: axis};\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.containPoint = function (point) {\n    var coord = this._coordsList[0];\n    if (coord) {\n        return coord.containPoint(point);\n    }\n};\n\n/**\n * Initialize cartesian coordinate systems\n * @private\n */\ngridProto._initCartesian = function (gridModel, ecModel, api) {\n    var axisPositionUsed = {\n        left: false,\n        right: false,\n        top: false,\n        bottom: false\n    };\n\n    var axesMap = {\n        x: {},\n        y: {}\n    };\n    var axesCount = {\n        x: 0,\n        y: 0\n    };\n\n    /// Create axis\n    ecModel.eachComponent('xAxis', createAxisCreator('x'), this);\n    ecModel.eachComponent('yAxis', createAxisCreator('y'), this);\n\n    if (!axesCount.x || !axesCount.y) {\n        // Roll back when there no either x or y axis\n        this._axesMap = {};\n        this._axesList = [];\n        return;\n    }\n\n    this._axesMap = axesMap;\n\n    /// Create cartesian2d\n    each$1(axesMap.x, function (xAxis, xAxisIndex) {\n        each$1(axesMap.y, function (yAxis, yAxisIndex) {\n            var key = 'x' + xAxisIndex + 'y' + yAxisIndex;\n            var cartesian = new Cartesian2D(key);\n\n            cartesian.grid = this;\n            cartesian.model = gridModel;\n\n            this._coordsMap[key] = cartesian;\n            this._coordsList.push(cartesian);\n\n            cartesian.addAxis(xAxis);\n            cartesian.addAxis(yAxis);\n        }, this);\n    }, this);\n\n    function createAxisCreator(axisType) {\n        return function (axisModel, idx) {\n            if (!isAxisUsedInTheGrid(axisModel, gridModel, ecModel)) {\n                return;\n            }\n\n            var axisPosition = axisModel.get('position');\n            if (axisType === 'x') {\n                // Fix position\n                if (axisPosition !== 'top' && axisPosition !== 'bottom') {\n                    // Default bottom of X\n                    axisPosition = 'bottom';\n                    if (axisPositionUsed[axisPosition]) {\n                        axisPosition = axisPosition === 'top' ? 'bottom' : 'top';\n                    }\n                }\n            }\n            else {\n                // Fix position\n                if (axisPosition !== 'left' && axisPosition !== 'right') {\n                    // Default left of Y\n                    axisPosition = 'left';\n                    if (axisPositionUsed[axisPosition]) {\n                        axisPosition = axisPosition === 'left' ? 'right' : 'left';\n                    }\n                }\n            }\n            axisPositionUsed[axisPosition] = true;\n\n            var axis = new Axis2D(\n                axisType, createScaleByModel(axisModel),\n                [0, 0],\n                axisModel.get('type'),\n                axisPosition\n            );\n\n            var isCategory = axis.type === 'category';\n            axis.onBand = isCategory && axisModel.get('boundaryGap');\n            axis.inverse = axisModel.get('inverse');\n\n            // Inject axis into axisModel\n            axisModel.axis = axis;\n\n            // Inject axisModel into axis\n            axis.model = axisModel;\n\n            // Inject grid info axis\n            axis.grid = this;\n\n            // Index of axis, can be used as key\n            axis.index = idx;\n\n            this._axesList.push(axis);\n\n            axesMap[axisType][idx] = axis;\n            axesCount[axisType]++;\n        };\n    }\n};\n\n/**\n * Update cartesian properties from series\n * @param  {module:echarts/model/Option} option\n * @private\n */\ngridProto._updateScale = function (ecModel, gridModel) {\n    // Reset scale\n    each$1(this._axesList, function (axis) {\n        axis.scale.setExtent(Infinity, -Infinity);\n    });\n    ecModel.eachSeries(function (seriesModel) {\n        if (isCartesian2D(seriesModel)) {\n            var axesModels = findAxesModels(seriesModel, ecModel);\n            var xAxisModel = axesModels[0];\n            var yAxisModel = axesModels[1];\n\n            if (!isAxisUsedInTheGrid(xAxisModel, gridModel, ecModel)\n                || !isAxisUsedInTheGrid(yAxisModel, gridModel, ecModel)\n            ) {\n                return;\n            }\n\n            var cartesian = this.getCartesian(\n                xAxisModel.componentIndex, yAxisModel.componentIndex\n            );\n            var data = seriesModel.getData();\n            var xAxis = cartesian.getAxis('x');\n            var yAxis = cartesian.getAxis('y');\n\n            if (data.type === 'list') {\n                unionExtent(data, xAxis, seriesModel);\n                unionExtent(data, yAxis, seriesModel);\n            }\n        }\n    }, this);\n\n    function unionExtent(data, axis, seriesModel) {\n        each$1(data.mapDimension(axis.dim, true), function (dim) {\n            axis.scale.unionExtentFromData(\n                // For example, the extent of the orginal dimension\n                // is [0.1, 0.5], the extent of the `stackResultDimension`\n                // is [7, 9], the final extent should not include [0.1, 0.5].\n                data, getStackedDimension(data, dim)\n            );\n        });\n    }\n};\n\n/**\n * @param {string} [dim] 'x' or 'y' or 'auto' or null/undefined\n * @return {Object} {baseAxes: [], otherAxes: []}\n */\ngridProto.getTooltipAxes = function (dim) {\n    var baseAxes = [];\n    var otherAxes = [];\n\n    each$1(this.getCartesians(), function (cartesian) {\n        var baseAxis = (dim != null && dim !== 'auto')\n            ? cartesian.getAxis(dim) : cartesian.getBaseAxis();\n        var otherAxis = cartesian.getOtherAxis(baseAxis);\n        indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis);\n        indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis);\n    });\n\n    return {baseAxes: baseAxes, otherAxes: otherAxes};\n};\n\n/**\n * @inner\n */\nfunction updateAxisTransform(axis, coordBase) {\n    var axisExtent = axis.getExtent();\n    var axisExtentSum = axisExtent[0] + axisExtent[1];\n\n    // Fast transform\n    axis.toGlobalCoord = axis.dim === 'x'\n        ? function (coord) {\n            return coord + coordBase;\n        }\n        : function (coord) {\n            return axisExtentSum - coord + coordBase;\n        };\n    axis.toLocalCoord = axis.dim === 'x'\n        ? function (coord) {\n            return coord - coordBase;\n        }\n        : function (coord) {\n            return axisExtentSum - coord + coordBase;\n        };\n}\n\nvar axesTypes = ['xAxis', 'yAxis'];\n/**\n * @inner\n */\nfunction findAxesModels(seriesModel, ecModel) {\n    return map(axesTypes, function (axisType) {\n        var axisModel = seriesModel.getReferringComponents(axisType)[0];\n\n        if (__DEV__) {\n            if (!axisModel) {\n                throw new Error(axisType + ' \"' + retrieve(\n                    seriesModel.get(axisType + 'Index'),\n                    seriesModel.get(axisType + 'Id'),\n                    0\n                ) + '\" not found');\n            }\n        }\n        return axisModel;\n    });\n}\n\n/**\n * @inner\n */\nfunction isCartesian2D(seriesModel) {\n    return seriesModel.get('coordinateSystem') === 'cartesian2d';\n}\n\nGrid.create = function (ecModel, api) {\n    var grids = [];\n    ecModel.eachComponent('grid', function (gridModel, idx) {\n        var grid = new Grid(gridModel, ecModel, api);\n        grid.name = 'grid_' + idx;\n        // dataSampling requires axis extent, so resize\n        // should be performed in create stage.\n        grid.resize(gridModel, api, true);\n\n        gridModel.coordinateSystem = grid;\n\n        grids.push(grid);\n    });\n\n    // Inject the coordinateSystems into seriesModel\n    ecModel.eachSeries(function (seriesModel) {\n        if (!isCartesian2D(seriesModel)) {\n            return;\n        }\n\n        var axesModels = findAxesModels(seriesModel, ecModel);\n        var xAxisModel = axesModels[0];\n        var yAxisModel = axesModels[1];\n\n        var gridModel = xAxisModel.getCoordSysModel();\n\n        if (__DEV__) {\n            if (!gridModel) {\n                throw new Error(\n                    'Grid \"' + retrieve(\n                        xAxisModel.get('gridIndex'),\n                        xAxisModel.get('gridId'),\n                        0\n                    ) + '\" not found'\n                );\n            }\n            if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) {\n                throw new Error('xAxis and yAxis must use the same grid');\n            }\n        }\n\n        var grid = gridModel.coordinateSystem;\n\n        seriesModel.coordinateSystem = grid.getCartesian(\n            xAxisModel.componentIndex, yAxisModel.componentIndex\n        );\n    });\n\n    return grids;\n};\n\n// For deciding which dimensions to use when creating list data\nGrid.dimensions = Grid.prototype.dimensions = Cartesian2D.prototype.dimensions;\n\nCoordinateSystemManager.register('cartesian2d', Grid);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PI$2 = Math.PI;\n\nfunction makeAxisEventDataBase(axisModel) {\n    var eventData = {\n        componentType: axisModel.mainType,\n        componentIndex: axisModel.componentIndex\n    };\n    eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex;\n    return eventData;\n}\n\n/**\n * A final axis is translated and rotated from a \"standard axis\".\n * So opt.position and opt.rotation is required.\n *\n * A standard axis is and axis from [0, 0] to [0, axisExtent[1]],\n * for example: (0, 0) ------------> (0, 50)\n *\n * nameDirection or tickDirection or labelDirection is 1 means tick\n * or label is below the standard axis, whereas is -1 means above\n * the standard axis. labelOffset means offset between label and axis,\n * which is useful when 'onZero', where axisLabel is in the grid and\n * label in outside grid.\n *\n * Tips: like always,\n * positive rotation represents anticlockwise, and negative rotation\n * represents clockwise.\n * The direction of position coordinate is the same as the direction\n * of screen coordinate.\n *\n * Do not need to consider axis 'inverse', which is auto processed by\n * axis extent.\n *\n * @param {module:zrender/container/Group} group\n * @param {Object} axisModel\n * @param {Object} opt Standard axis parameters.\n * @param {Array.<number>} opt.position [x, y]\n * @param {number} opt.rotation by radian\n * @param {number} [opt.nameDirection=1] 1 or -1 Used when nameLocation is 'middle' or 'center'.\n * @param {number} [opt.tickDirection=1] 1 or -1\n * @param {number} [opt.labelDirection=1] 1 or -1\n * @param {number} [opt.labelOffset=0] Usefull when onZero.\n * @param {string} [opt.axisLabelShow] default get from axisModel.\n * @param {string} [opt.axisName] default get from axisModel.\n * @param {number} [opt.axisNameAvailableWidth]\n * @param {number} [opt.labelRotate] by degree, default get from axisModel.\n * @param {number} [opt.strokeContainThreshold] Default label interval when label\n * @param {number} [opt.nameTruncateMaxWidth]\n */\nvar AxisBuilder = function (axisModel, opt) {\n\n    /**\n     * @readOnly\n     */\n    this.opt = opt;\n\n    /**\n     * @readOnly\n     */\n    this.axisModel = axisModel;\n\n    // Default value\n    defaults(\n        opt,\n        {\n            labelOffset: 0,\n            nameDirection: 1,\n            tickDirection: 1,\n            labelDirection: 1,\n            silent: true\n        }\n    );\n\n    /**\n     * @readOnly\n     */\n    this.group = new Group();\n\n    // FIXME Not use a seperate text group?\n    var dumbGroup = new Group({\n        position: opt.position.slice(),\n        rotation: opt.rotation\n    });\n\n    // this.group.add(dumbGroup);\n    // this._dumbGroup = dumbGroup;\n\n    dumbGroup.updateTransform();\n    this._transform = dumbGroup.transform;\n\n    this._dumbGroup = dumbGroup;\n};\n\nAxisBuilder.prototype = {\n\n    constructor: AxisBuilder,\n\n    hasBuilder: function (name) {\n        return !!builders[name];\n    },\n\n    add: function (name) {\n        builders[name].call(this);\n    },\n\n    getGroup: function () {\n        return this.group;\n    }\n\n};\n\nvar builders = {\n\n    /**\n     * @private\n     */\n    axisLine: function () {\n        var opt = this.opt;\n        var axisModel = this.axisModel;\n\n        if (!axisModel.get('axisLine.show')) {\n            return;\n        }\n\n        var extent = this.axisModel.axis.getExtent();\n\n        var matrix = this._transform;\n        var pt1 = [extent[0], 0];\n        var pt2 = [extent[1], 0];\n        if (matrix) {\n            applyTransform(pt1, pt1, matrix);\n            applyTransform(pt2, pt2, matrix);\n        }\n\n        var lineStyle = extend(\n            {\n                lineCap: 'round'\n            },\n            axisModel.getModel('axisLine.lineStyle').getLineStyle()\n        );\n\n        this.group.add(new Line(subPixelOptimizeLine({\n            // Id for animation\n            anid: 'line',\n\n            shape: {\n                x1: pt1[0],\n                y1: pt1[1],\n                x2: pt2[0],\n                y2: pt2[1]\n            },\n            style: lineStyle,\n            strokeContainThreshold: opt.strokeContainThreshold || 5,\n            silent: true,\n            z2: 1\n        })));\n\n        var arrows = axisModel.get('axisLine.symbol');\n        var arrowSize = axisModel.get('axisLine.symbolSize');\n\n        var arrowOffset = axisModel.get('axisLine.symbolOffset') || 0;\n        if (typeof arrowOffset === 'number') {\n            arrowOffset = [arrowOffset, arrowOffset];\n        }\n\n        if (arrows != null) {\n            if (typeof arrows === 'string') {\n                // Use the same arrow for start and end point\n                arrows = [arrows, arrows];\n            }\n            if (typeof arrowSize === 'string'\n                || typeof arrowSize === 'number'\n            ) {\n                // Use the same size for width and height\n                arrowSize = [arrowSize, arrowSize];\n            }\n\n            var symbolWidth = arrowSize[0];\n            var symbolHeight = arrowSize[1];\n\n            each$1([{\n                rotate: opt.rotation + Math.PI / 2,\n                offset: arrowOffset[0],\n                r: 0\n            }, {\n                rotate: opt.rotation - Math.PI / 2,\n                offset: arrowOffset[1],\n                r: Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0])\n                    + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1]))\n            }], function (point, index) {\n                if (arrows[index] !== 'none' && arrows[index] != null) {\n                    var symbol = createSymbol(\n                        arrows[index],\n                        -symbolWidth / 2,\n                        -symbolHeight / 2,\n                        symbolWidth,\n                        symbolHeight,\n                        lineStyle.stroke,\n                        true\n                    );\n\n                    // Calculate arrow position with offset\n                    var r = point.r + point.offset;\n                    var pos = [\n                        pt1[0] + r * Math.cos(opt.rotation),\n                        pt1[1] - r * Math.sin(opt.rotation)\n                    ];\n\n                    symbol.attr({\n                        rotation: point.rotate,\n                        position: pos,\n                        silent: true,\n                        z2: 11\n                    });\n                    this.group.add(symbol);\n                }\n            }, this);\n        }\n    },\n\n    /**\n     * @private\n     */\n    axisTickLabel: function () {\n        var axisModel = this.axisModel;\n        var opt = this.opt;\n\n        var tickEls = buildAxisTick(this, axisModel, opt);\n        var labelEls = buildAxisLabel(this, axisModel, opt);\n\n        fixMinMaxLabelShow(axisModel, labelEls, tickEls);\n    },\n\n    /**\n     * @private\n     */\n    axisName: function () {\n        var opt = this.opt;\n        var axisModel = this.axisModel;\n        var name = retrieve(opt.axisName, axisModel.get('name'));\n\n        if (!name) {\n            return;\n        }\n\n        var nameLocation = axisModel.get('nameLocation');\n        var nameDirection = opt.nameDirection;\n        var textStyleModel = axisModel.getModel('nameTextStyle');\n        var gap = axisModel.get('nameGap') || 0;\n\n        var extent = this.axisModel.axis.getExtent();\n        var gapSignal = extent[0] > extent[1] ? -1 : 1;\n        var pos = [\n            nameLocation === 'start'\n                ? extent[0] - gapSignal * gap\n                : nameLocation === 'end'\n                ? extent[1] + gapSignal * gap\n                : (extent[0] + extent[1]) / 2, // 'middle'\n            // Reuse labelOffset.\n            isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * gap : 0\n        ];\n\n        var labelLayout;\n\n        var nameRotation = axisModel.get('nameRotate');\n        if (nameRotation != null) {\n            nameRotation = nameRotation * PI$2 / 180; // To radian.\n        }\n\n        var axisNameAvailableWidth;\n\n        if (isNameLocationCenter(nameLocation)) {\n            labelLayout = innerTextLayout(\n                opt.rotation,\n                nameRotation != null ? nameRotation : opt.rotation, // Adapt to axis.\n                nameDirection\n            );\n        }\n        else {\n            labelLayout = endTextLayout(\n                opt, nameLocation, nameRotation || 0, extent\n            );\n\n            axisNameAvailableWidth = opt.axisNameAvailableWidth;\n            if (axisNameAvailableWidth != null) {\n                axisNameAvailableWidth = Math.abs(\n                    axisNameAvailableWidth / Math.sin(labelLayout.rotation)\n                );\n                !isFinite(axisNameAvailableWidth) && (axisNameAvailableWidth = null);\n            }\n        }\n\n        var textFont = textStyleModel.getFont();\n\n        var truncateOpt = axisModel.get('nameTruncate', true) || {};\n        var ellipsis = truncateOpt.ellipsis;\n        var maxWidth = retrieve(\n            opt.nameTruncateMaxWidth, truncateOpt.maxWidth, axisNameAvailableWidth\n        );\n        // FIXME\n        // truncate rich text? (consider performance)\n        var truncatedText = (ellipsis != null && maxWidth != null)\n            ? truncateText$1(\n                name, maxWidth, textFont, ellipsis,\n                {minChar: 2, placeholder: truncateOpt.placeholder}\n            )\n            : name;\n\n        var tooltipOpt = axisModel.get('tooltip', true);\n\n        var mainType = axisModel.mainType;\n        var formatterParams = {\n            componentType: mainType,\n            name: name,\n            $vars: ['name']\n        };\n        formatterParams[mainType + 'Index'] = axisModel.componentIndex;\n\n        var textEl = new Text({\n            // Id for animation\n            anid: 'name',\n\n            __fullText: name,\n            __truncatedText: truncatedText,\n\n            position: pos,\n            rotation: labelLayout.rotation,\n            silent: isSilent(axisModel),\n            z2: 1,\n            tooltip: (tooltipOpt && tooltipOpt.show)\n                ? extend({\n                    content: name,\n                    formatter: function () {\n                        return name;\n                    },\n                    formatterParams: formatterParams\n                }, tooltipOpt)\n                : null\n        });\n\n        setTextStyle(textEl.style, textStyleModel, {\n            text: truncatedText,\n            textFont: textFont,\n            textFill: textStyleModel.getTextColor()\n                || axisModel.get('axisLine.lineStyle.color'),\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.textVerticalAlign\n        });\n\n        if (axisModel.get('triggerEvent')) {\n            textEl.eventData = makeAxisEventDataBase(axisModel);\n            textEl.eventData.targetType = 'axisName';\n            textEl.eventData.name = name;\n        }\n\n        // FIXME\n        this._dumbGroup.add(textEl);\n        textEl.updateTransform();\n\n        this.group.add(textEl);\n\n        textEl.decomposeTransform();\n    }\n\n};\n\n/**\n * @public\n * @static\n * @param {Object} opt\n * @param {number} axisRotation in radian\n * @param {number} textRotation in radian\n * @param {number} direction\n * @return {Object} {\n *  rotation, // according to axis\n *  textAlign,\n *  textVerticalAlign\n * }\n */\nvar innerTextLayout = AxisBuilder.innerTextLayout = function (axisRotation, textRotation, direction) {\n    var rotationDiff = remRadian(textRotation - axisRotation);\n    var textAlign;\n    var textVerticalAlign;\n\n    if (isRadianAroundZero(rotationDiff)) { // Label is parallel with axis line.\n        textVerticalAlign = direction > 0 ? 'top' : 'bottom';\n        textAlign = 'center';\n    }\n    else if (isRadianAroundZero(rotationDiff - PI$2)) { // Label is inverse parallel with axis line.\n        textVerticalAlign = direction > 0 ? 'bottom' : 'top';\n        textAlign = 'center';\n    }\n    else {\n        textVerticalAlign = 'middle';\n\n        if (rotationDiff > 0 && rotationDiff < PI$2) {\n            textAlign = direction > 0 ? 'right' : 'left';\n        }\n        else {\n            textAlign = direction > 0 ? 'left' : 'right';\n        }\n    }\n\n    return {\n        rotation: rotationDiff,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n};\n\nfunction endTextLayout(opt, textPosition, textRotate, extent) {\n    var rotationDiff = remRadian(textRotate - opt.rotation);\n    var textAlign;\n    var textVerticalAlign;\n    var inverse = extent[0] > extent[1];\n    var onLeft = (textPosition === 'start' && !inverse)\n        || (textPosition !== 'start' && inverse);\n\n    if (isRadianAroundZero(rotationDiff - PI$2 / 2)) {\n        textVerticalAlign = onLeft ? 'bottom' : 'top';\n        textAlign = 'center';\n    }\n    else if (isRadianAroundZero(rotationDiff - PI$2 * 1.5)) {\n        textVerticalAlign = onLeft ? 'top' : 'bottom';\n        textAlign = 'center';\n    }\n    else {\n        textVerticalAlign = 'middle';\n        if (rotationDiff < PI$2 * 1.5 && rotationDiff > PI$2 / 2) {\n            textAlign = onLeft ? 'left' : 'right';\n        }\n        else {\n            textAlign = onLeft ? 'right' : 'left';\n        }\n    }\n\n    return {\n        rotation: rotationDiff,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\nfunction isSilent(axisModel) {\n    var tooltipOpt = axisModel.get('tooltip');\n    return axisModel.get('silent')\n        // Consider mouse cursor, add these restrictions.\n        || !(\n            axisModel.get('triggerEvent') || (tooltipOpt && tooltipOpt.show)\n        );\n}\n\nfunction fixMinMaxLabelShow(axisModel, labelEls, tickEls) {\n    if (shouldShowAllLabels(axisModel.axis)) {\n        return;\n    }\n\n    // If min or max are user set, we need to check\n    // If the tick on min(max) are overlap on their neighbour tick\n    // If they are overlapped, we need to hide the min(max) tick label\n    var showMinLabel = axisModel.get('axisLabel.showMinLabel');\n    var showMaxLabel = axisModel.get('axisLabel.showMaxLabel');\n\n    // FIXME\n    // Have not consider onBand yet, where tick els is more than label els.\n\n    labelEls = labelEls || [];\n    tickEls = tickEls || [];\n\n    var firstLabel = labelEls[0];\n    var nextLabel = labelEls[1];\n    var lastLabel = labelEls[labelEls.length - 1];\n    var prevLabel = labelEls[labelEls.length - 2];\n\n    var firstTick = tickEls[0];\n    var nextTick = tickEls[1];\n    var lastTick = tickEls[tickEls.length - 1];\n    var prevTick = tickEls[tickEls.length - 2];\n\n    if (showMinLabel === false) {\n        ignoreEl(firstLabel);\n        ignoreEl(firstTick);\n    }\n    else if (isTwoLabelOverlapped(firstLabel, nextLabel)) {\n        if (showMinLabel) {\n            ignoreEl(nextLabel);\n            ignoreEl(nextTick);\n        }\n        else {\n            ignoreEl(firstLabel);\n            ignoreEl(firstTick);\n        }\n    }\n\n    if (showMaxLabel === false) {\n        ignoreEl(lastLabel);\n        ignoreEl(lastTick);\n    }\n    else if (isTwoLabelOverlapped(prevLabel, lastLabel)) {\n        if (showMaxLabel) {\n            ignoreEl(prevLabel);\n            ignoreEl(prevTick);\n        }\n        else {\n            ignoreEl(lastLabel);\n            ignoreEl(lastTick);\n        }\n    }\n}\n\nfunction ignoreEl(el) {\n    el && (el.ignore = true);\n}\n\nfunction isTwoLabelOverlapped(current, next, labelLayout) {\n    // current and next has the same rotation.\n    var firstRect = current && current.getBoundingRect().clone();\n    var nextRect = next && next.getBoundingRect().clone();\n\n    if (!firstRect || !nextRect) {\n        return;\n    }\n\n    // When checking intersect of two rotated labels, we use mRotationBack\n    // to avoid that boundingRect is enlarge when using `boundingRect.applyTransform`.\n    var mRotationBack = identity([]);\n    rotate(mRotationBack, mRotationBack, -current.rotation);\n\n    firstRect.applyTransform(mul$1([], mRotationBack, current.getLocalTransform()));\n    nextRect.applyTransform(mul$1([], mRotationBack, next.getLocalTransform()));\n\n    return firstRect.intersect(nextRect);\n}\n\nfunction isNameLocationCenter(nameLocation) {\n    return nameLocation === 'middle' || nameLocation === 'center';\n}\n\nfunction buildAxisTick(axisBuilder, axisModel, opt) {\n    var axis = axisModel.axis;\n\n    if (!axisModel.get('axisTick.show') || axis.scale.isBlank()) {\n        return;\n    }\n\n    var tickModel = axisModel.getModel('axisTick');\n\n    var lineStyleModel = tickModel.getModel('lineStyle');\n    var tickLen = tickModel.get('length');\n\n    var ticksCoords = axis.getTicksCoords();\n\n    var pt1 = [];\n    var pt2 = [];\n    var matrix = axisBuilder._transform;\n\n    var tickEls = [];\n\n    for (var i = 0; i < ticksCoords.length; i++) {\n        var tickCoord = ticksCoords[i].coord;\n\n        pt1[0] = tickCoord;\n        pt1[1] = 0;\n        pt2[0] = tickCoord;\n        pt2[1] = opt.tickDirection * tickLen;\n\n        if (matrix) {\n            applyTransform(pt1, pt1, matrix);\n            applyTransform(pt2, pt2, matrix);\n        }\n        // Tick line, Not use group transform to have better line draw\n        var tickEl = new Line(subPixelOptimizeLine({\n            // Id for animation\n            anid: 'tick_' + ticksCoords[i].tickValue,\n\n            shape: {\n                x1: pt1[0],\n                y1: pt1[1],\n                x2: pt2[0],\n                y2: pt2[1]\n            },\n            style: defaults(\n                lineStyleModel.getLineStyle(),\n                {\n                    stroke: axisModel.get('axisLine.lineStyle.color')\n                }\n            ),\n            z2: 2,\n            silent: true\n        }));\n        axisBuilder.group.add(tickEl);\n        tickEls.push(tickEl);\n    }\n\n    return tickEls;\n}\n\nfunction buildAxisLabel(axisBuilder, axisModel, opt) {\n    var axis = axisModel.axis;\n    var show = retrieve(opt.axisLabelShow, axisModel.get('axisLabel.show'));\n\n    if (!show || axis.scale.isBlank()) {\n        return;\n    }\n\n    var labelModel = axisModel.getModel('axisLabel');\n    var labelMargin = labelModel.get('margin');\n    var labels = axis.getViewLabels();\n\n    // Special label rotate.\n    var labelRotation = (\n        retrieve(opt.labelRotate, labelModel.get('rotate')) || 0\n    ) * PI$2 / 180;\n\n    var labelLayout = innerTextLayout(opt.rotation, labelRotation, opt.labelDirection);\n    var rawCategoryData = axisModel.getCategories(true);\n\n    var labelEls = [];\n    var silent = isSilent(axisModel);\n    var triggerEvent = axisModel.get('triggerEvent');\n\n    each$1(labels, function (labelItem, index) {\n        var tickValue = labelItem.tickValue;\n        var formattedLabel = labelItem.formattedLabel;\n        var rawLabel = labelItem.rawLabel;\n\n        var itemLabelModel = labelModel;\n        if (rawCategoryData && rawCategoryData[tickValue] && rawCategoryData[tickValue].textStyle) {\n            itemLabelModel = new Model(\n                rawCategoryData[tickValue].textStyle, labelModel, axisModel.ecModel\n            );\n        }\n\n        var textColor = itemLabelModel.getTextColor()\n            || axisModel.get('axisLine.lineStyle.color');\n\n        var tickCoord = axis.dataToCoord(tickValue);\n        var pos = [\n            tickCoord,\n            opt.labelOffset + opt.labelDirection * labelMargin\n        ];\n\n        var textEl = new Text({\n            // Id for animation\n            anid: 'label_' + tickValue,\n            position: pos,\n            rotation: labelLayout.rotation,\n            silent: silent,\n            z2: 10\n        });\n\n        setTextStyle(textEl.style, itemLabelModel, {\n            text: formattedLabel,\n            textAlign: itemLabelModel.getShallow('align', true)\n                || labelLayout.textAlign,\n            textVerticalAlign: itemLabelModel.getShallow('verticalAlign', true)\n                || itemLabelModel.getShallow('baseline', true)\n                || labelLayout.textVerticalAlign,\n            textFill: typeof textColor === 'function'\n                ? textColor(\n                    // (1) In category axis with data zoom, tick is not the original\n                    // index of axis.data. So tick should not be exposed to user\n                    // in category axis.\n                    // (2) Compatible with previous version, which always use formatted label as\n                    // input. But in interval scale the formatted label is like '223,445', which\n                    // maked user repalce ','. So we modify it to return original val but remain\n                    // it as 'string' to avoid error in replacing.\n                    axis.type === 'category'\n                        ? rawLabel\n                        : axis.type === 'value'\n                        ? tickValue + ''\n                        : tickValue,\n                    index\n                )\n                : textColor\n        });\n\n        // Pack data for mouse event\n        if (triggerEvent) {\n            textEl.eventData = makeAxisEventDataBase(axisModel);\n            textEl.eventData.targetType = 'axisLabel';\n            textEl.eventData.value = rawLabel;\n        }\n\n        // FIXME\n        axisBuilder._dumbGroup.add(textEl);\n        textEl.updateTransform();\n\n        labelEls.push(textEl);\n        axisBuilder.group.add(textEl);\n\n        textEl.decomposeTransform();\n\n    });\n\n    return labelEls;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$6 = each$1;\nvar curry$1 = curry;\n\n// Build axisPointerModel, mergin tooltip.axisPointer model for each axis.\n// allAxesInfo should be updated when setOption performed.\nfunction collect(ecModel, api) {\n    var result = {\n        /**\n         * key: makeKey(axis.model)\n         * value: {\n         *      axis,\n         *      coordSys,\n         *      axisPointerModel,\n         *      triggerTooltip,\n         *      involveSeries,\n         *      snap,\n         *      seriesModels,\n         *      seriesDataCount\n         * }\n         */\n        axesInfo: {},\n        seriesInvolved: false,\n        /**\n         * key: makeKey(coordSys.model)\n         * value: Object: key makeKey(axis.model), value: axisInfo\n         */\n        coordSysAxesInfo: {},\n        coordSysMap: {}\n    };\n\n    collectAxesInfo(result, ecModel, api);\n\n    // Check seriesInvolved for performance, in case too many series in some chart.\n    result.seriesInvolved && collectSeriesInfo(result, ecModel);\n\n    return result;\n}\n\nfunction collectAxesInfo(result, ecModel, api) {\n    var globalTooltipModel = ecModel.getComponent('tooltip');\n    var globalAxisPointerModel = ecModel.getComponent('axisPointer');\n    // links can only be set on global.\n    var linksOption = globalAxisPointerModel.get('link', true) || [];\n    var linkGroups = [];\n\n    // Collect axes info.\n    each$6(api.getCoordinateSystems(), function (coordSys) {\n        // Some coordinate system do not support axes, like geo.\n        if (!coordSys.axisPointerEnabled) {\n            return;\n        }\n\n        var coordSysKey = makeKey(coordSys.model);\n        var axesInfoInCoordSys = result.coordSysAxesInfo[coordSysKey] = {};\n        result.coordSysMap[coordSysKey] = coordSys;\n\n        // Set tooltip (like 'cross') is a convienent way to show axisPointer\n        // for user. So we enable seting tooltip on coordSys model.\n        var coordSysModel = coordSys.model;\n        var baseTooltipModel = coordSysModel.getModel('tooltip', globalTooltipModel);\n\n        each$6(coordSys.getAxes(), curry$1(saveTooltipAxisInfo, false, null));\n\n        // If axis tooltip used, choose tooltip axis for each coordSys.\n        // Notice this case: coordSys is `grid` but not `cartesian2D` here.\n        if (coordSys.getTooltipAxes\n            && globalTooltipModel\n            // If tooltip.showContent is set as false, tooltip will not\n            // show but axisPointer will show as normal.\n            && baseTooltipModel.get('show')\n        ) {\n            // Compatible with previous logic. But series.tooltip.trigger: 'axis'\n            // or series.data[n].tooltip.trigger: 'axis' are not support any more.\n            var triggerAxis = baseTooltipModel.get('trigger') === 'axis';\n            var cross = baseTooltipModel.get('axisPointer.type') === 'cross';\n            var tooltipAxes = coordSys.getTooltipAxes(baseTooltipModel.get('axisPointer.axis'));\n            if (triggerAxis || cross) {\n                each$6(tooltipAxes.baseAxes, curry$1(\n                    saveTooltipAxisInfo, cross ? 'cross' : true, triggerAxis\n                ));\n            }\n            if (cross) {\n                each$6(tooltipAxes.otherAxes, curry$1(saveTooltipAxisInfo, 'cross', false));\n            }\n        }\n\n        // fromTooltip: true | false | 'cross'\n        // triggerTooltip: true | false | null\n        function saveTooltipAxisInfo(fromTooltip, triggerTooltip, axis) {\n            var axisPointerModel = axis.model.getModel('axisPointer', globalAxisPointerModel);\n\n            var axisPointerShow = axisPointerModel.get('show');\n            if (!axisPointerShow || (\n                axisPointerShow === 'auto'\n                && !fromTooltip\n                && !isHandleTrigger(axisPointerModel)\n            )) {\n                return;\n            }\n\n            if (triggerTooltip == null) {\n                triggerTooltip = axisPointerModel.get('triggerTooltip');\n            }\n\n            axisPointerModel = fromTooltip\n                ? makeAxisPointerModel(\n                    axis, baseTooltipModel, globalAxisPointerModel, ecModel,\n                    fromTooltip, triggerTooltip\n                )\n                : axisPointerModel;\n\n            var snap = axisPointerModel.get('snap');\n            var key = makeKey(axis.model);\n            var involveSeries = triggerTooltip || snap || axis.type === 'category';\n\n            // If result.axesInfo[key] exist, override it (tooltip has higher priority).\n            var axisInfo = result.axesInfo[key] = {\n                key: key,\n                axis: axis,\n                coordSys: coordSys,\n                axisPointerModel: axisPointerModel,\n                triggerTooltip: triggerTooltip,\n                involveSeries: involveSeries,\n                snap: snap,\n                useHandle: isHandleTrigger(axisPointerModel),\n                seriesModels: []\n            };\n            axesInfoInCoordSys[key] = axisInfo;\n            result.seriesInvolved |= involveSeries;\n\n            var groupIndex = getLinkGroupIndex(linksOption, axis);\n            if (groupIndex != null) {\n                var linkGroup = linkGroups[groupIndex] || (linkGroups[groupIndex] = {axesInfo: {}});\n                linkGroup.axesInfo[key] = axisInfo;\n                linkGroup.mapper = linksOption[groupIndex].mapper;\n                axisInfo.linkGroup = linkGroup;\n            }\n        }\n    });\n}\n\nfunction makeAxisPointerModel(\n    axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip\n) {\n    var tooltipAxisPointerModel = baseTooltipModel.getModel('axisPointer');\n    var volatileOption = {};\n\n    each$6(\n        [\n            'type', 'snap', 'lineStyle', 'shadowStyle', 'label',\n            'animation', 'animationDurationUpdate', 'animationEasingUpdate', 'z'\n        ],\n        function (field) {\n            volatileOption[field] = clone(tooltipAxisPointerModel.get(field));\n        }\n    );\n\n    // category axis do not auto snap, otherwise some tick that do not\n    // has value can not be hovered. value/time/log axis default snap if\n    // triggered from tooltip and trigger tooltip.\n    volatileOption.snap = axis.type !== 'category' && !!triggerTooltip;\n\n    // Compatibel with previous behavior, tooltip axis do not show label by default.\n    // Only these properties can be overrided from tooltip to axisPointer.\n    if (tooltipAxisPointerModel.get('type') === 'cross') {\n        volatileOption.type = 'line';\n    }\n    var labelOption = volatileOption.label || (volatileOption.label = {});\n    // Follow the convention, do not show label when triggered by tooltip by default.\n    labelOption.show == null && (labelOption.show = false);\n\n    if (fromTooltip === 'cross') {\n        // When 'cross', both axes show labels.\n        var tooltipAxisPointerLabelShow = tooltipAxisPointerModel.get('label.show');\n        labelOption.show = tooltipAxisPointerLabelShow != null ? tooltipAxisPointerLabelShow : true;\n        // If triggerTooltip, this is a base axis, which should better not use cross style\n        // (cross style is dashed by default)\n        if (!triggerTooltip) {\n            var crossStyle = volatileOption.lineStyle = tooltipAxisPointerModel.get('crossStyle');\n            crossStyle && defaults(labelOption, crossStyle.textStyle);\n        }\n    }\n\n    return axis.model.getModel(\n        'axisPointer',\n        new Model(volatileOption, globalAxisPointerModel, ecModel)\n    );\n}\n\nfunction collectSeriesInfo(result, ecModel) {\n    // Prepare data for axis trigger\n    ecModel.eachSeries(function (seriesModel) {\n\n        // Notice this case: this coordSys is `cartesian2D` but not `grid`.\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesTooltipTrigger = seriesModel.get('tooltip.trigger', true);\n        var seriesTooltipShow = seriesModel.get('tooltip.show', true);\n        if (!coordSys\n            || seriesTooltipTrigger === 'none'\n            || seriesTooltipTrigger === false\n            || seriesTooltipTrigger === 'item'\n            || seriesTooltipShow === false\n            || seriesModel.get('axisPointer.show', true) === false\n        ) {\n            return;\n        }\n\n        each$6(result.coordSysAxesInfo[makeKey(coordSys.model)], function (axisInfo) {\n            var axis = axisInfo.axis;\n            if (coordSys.getAxis(axis.dim) === axis) {\n                axisInfo.seriesModels.push(seriesModel);\n                axisInfo.seriesDataCount == null && (axisInfo.seriesDataCount = 0);\n                axisInfo.seriesDataCount += seriesModel.getData().count();\n            }\n        });\n\n    }, this);\n}\n\n/**\n * For example:\n * {\n *     axisPointer: {\n *         links: [{\n *             xAxisIndex: [2, 4],\n *             yAxisIndex: 'all'\n *         }, {\n *             xAxisId: ['a5', 'a7'],\n *             xAxisName: 'xxx'\n *         }]\n *     }\n * }\n */\nfunction getLinkGroupIndex(linksOption, axis) {\n    var axisModel = axis.model;\n    var dim = axis.dim;\n    for (var i = 0; i < linksOption.length; i++) {\n        var linkOption = linksOption[i] || {};\n        if (checkPropInLink(linkOption[dim + 'AxisId'], axisModel.id)\n            || checkPropInLink(linkOption[dim + 'AxisIndex'], axisModel.componentIndex)\n            || checkPropInLink(linkOption[dim + 'AxisName'], axisModel.name)\n        ) {\n            return i;\n        }\n    }\n}\n\nfunction checkPropInLink(linkPropValue, axisPropValue) {\n    return linkPropValue === 'all'\n        || (isArray(linkPropValue) && indexOf(linkPropValue, axisPropValue) >= 0)\n        || linkPropValue === axisPropValue;\n}\n\nfunction fixValue(axisModel) {\n    var axisInfo = getAxisInfo(axisModel);\n    if (!axisInfo) {\n        return;\n    }\n\n    var axisPointerModel = axisInfo.axisPointerModel;\n    var scale = axisInfo.axis.scale;\n    var option = axisPointerModel.option;\n    var status = axisPointerModel.get('status');\n    var value = axisPointerModel.get('value');\n\n    // Parse init value for category and time axis.\n    if (value != null) {\n        value = scale.parse(value);\n    }\n\n    var useHandle = isHandleTrigger(axisPointerModel);\n    // If `handle` used, `axisPointer` will always be displayed, so value\n    // and status should be initialized.\n    if (status == null) {\n        option.status = useHandle ? 'show' : 'hide';\n    }\n\n    var extent = scale.getExtent().slice();\n    extent[0] > extent[1] && extent.reverse();\n\n    if (// Pick a value on axis when initializing.\n        value == null\n        // If both `handle` and `dataZoom` are used, value may be out of axis extent,\n        // where we should re-pick a value to keep `handle` displaying normally.\n        || value > extent[1]\n    ) {\n        // Make handle displayed on the end of the axis when init, which looks better.\n        value = extent[1];\n    }\n    if (value < extent[0]) {\n        value = extent[0];\n    }\n\n    option.value = value;\n\n    if (useHandle) {\n        option.status = axisInfo.axis.scale.isBlank() ? 'hide' : 'show';\n    }\n}\n\nfunction getAxisInfo(axisModel) {\n    var coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') || {}).coordSysAxesInfo;\n    return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)];\n}\n\nfunction getAxisPointerModel(axisModel) {\n    var axisInfo = getAxisInfo(axisModel);\n    return axisInfo && axisInfo.axisPointerModel;\n}\n\nfunction isHandleTrigger(axisPointerModel) {\n    return !!axisPointerModel.get('handle.show');\n}\n\n/**\n * @param {module:echarts/model/Model} model\n * @return {string} unique key\n */\nfunction makeKey(model) {\n    return model.type + '||' + model.id;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Base class of AxisView.\n */\nvar AxisView = extendComponentView({\n\n    type: 'axis',\n\n    /**\n     * @private\n     */\n    _axisPointer: null,\n\n    /**\n     * @protected\n     * @type {string}\n     */\n    axisPointerClass: null,\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n        // FIXME\n        // This process should proformed after coordinate systems updated\n        // (axis scale updated), and should be performed each time update.\n        // So put it here temporarily, although it is not appropriate to\n        // put a model-writing procedure in `view`.\n        this.axisPointerClass && fixValue(axisModel);\n\n        AxisView.superApply(this, 'render', arguments);\n\n        updateAxisPointer(this, axisModel, ecModel, api, payload, true);\n    },\n\n    /**\n     * Action handler.\n     * @public\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/model/Global} ecModel\n     * @param {module:echarts/ExtensionAPI} api\n     * @param {Object} payload\n     */\n    updateAxisPointer: function (axisModel, ecModel, api, payload, force) {\n        updateAxisPointer(this, axisModel, ecModel, api, payload, false);\n    },\n\n    /**\n     * @override\n     */\n    remove: function (ecModel, api) {\n        var axisPointer = this._axisPointer;\n        axisPointer && axisPointer.remove(api);\n        AxisView.superApply(this, 'remove', arguments);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function (ecModel, api) {\n        disposeAxisPointer(this, api);\n        AxisView.superApply(this, 'dispose', arguments);\n    }\n\n});\n\nfunction updateAxisPointer(axisView, axisModel, ecModel, api, payload, forceRender) {\n    var Clazz = AxisView.getAxisPointerClass(axisView.axisPointerClass);\n    if (!Clazz) {\n        return;\n    }\n    var axisPointerModel = getAxisPointerModel(axisModel);\n    axisPointerModel\n        ? (axisView._axisPointer || (axisView._axisPointer = new Clazz()))\n            .render(axisModel, axisPointerModel, api, forceRender)\n        : disposeAxisPointer(axisView, api);\n}\n\nfunction disposeAxisPointer(axisView, ecModel, api) {\n    var axisPointer = axisView._axisPointer;\n    axisPointer && axisPointer.dispose(ecModel, api);\n    axisView._axisPointer = null;\n}\n\nvar axisPointerClazz = [];\n\nAxisView.registerAxisPointerClass = function (type, clazz) {\n    if (__DEV__) {\n        if (axisPointerClazz[type]) {\n            throw new Error('axisPointer ' + type + ' exists');\n        }\n    }\n    axisPointerClazz[type] = clazz;\n};\n\nAxisView.getAxisPointerClass = function (type) {\n    return type && axisPointerClazz[type];\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Can only be called after coordinate system creation stage.\n * (Can be called before coordinate system update stage).\n *\n * @param {Object} opt {labelInside}\n * @return {Object} {\n *  position, rotation, labelDirection, labelOffset,\n *  tickDirection, labelRotate, z2\n * }\n */\nfunction layout$1(gridModel, axisModel, opt) {\n    opt = opt || {};\n    var grid = gridModel.coordinateSystem;\n    var axis = axisModel.axis;\n    var layout = {};\n    var otherAxisOnZeroOf = axis.getAxesOnZeroOf()[0];\n\n    var rawAxisPosition = axis.position;\n    var axisPosition = otherAxisOnZeroOf ? 'onZero' : rawAxisPosition;\n    var axisDim = axis.dim;\n\n    var rect = grid.getRect();\n    var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];\n    var idx = {left: 0, right: 1, top: 0, bottom: 1, onZero: 2};\n    var axisOffset = axisModel.get('offset') || 0;\n\n    var posBound = axisDim === 'x'\n        ? [rectBound[2] - axisOffset, rectBound[3] + axisOffset]\n        : [rectBound[0] - axisOffset, rectBound[1] + axisOffset];\n\n    if (otherAxisOnZeroOf) {\n        var onZeroCoord = otherAxisOnZeroOf.toGlobalCoord(otherAxisOnZeroOf.dataToCoord(0));\n        posBound[idx.onZero] = Math.max(Math.min(onZeroCoord, posBound[1]), posBound[0]);\n    }\n\n    // Axis position\n    layout.position = [\n        axisDim === 'y' ? posBound[idx[axisPosition]] : rectBound[0],\n        axisDim === 'x' ? posBound[idx[axisPosition]] : rectBound[3]\n    ];\n\n    // Axis rotation\n    layout.rotation = Math.PI / 2 * (axisDim === 'x' ? 0 : 1);\n\n    // Tick and label direction, x y is axisDim\n    var dirMap = {top: -1, bottom: 1, left: -1, right: 1};\n\n    layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition];\n    layout.labelOffset = otherAxisOnZeroOf ? posBound[idx[rawAxisPosition]] - posBound[idx.onZero] : 0;\n\n    if (axisModel.get('axisTick.inside')) {\n        layout.tickDirection = -layout.tickDirection;\n    }\n    if (retrieve(opt.labelInside, axisModel.get('axisLabel.inside'))) {\n        layout.labelDirection = -layout.labelDirection;\n    }\n\n    // Special label rotation\n    var labelRotate = axisModel.get('axisLabel.rotate');\n    layout.labelRotate = axisPosition === 'top' ? -labelRotate : labelRotate;\n\n    // Over splitLine and splitArea\n    layout.z2 = 1;\n\n    return layout;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar axisBuilderAttrs = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\nvar selfBuilderAttrs = [\n    'splitArea', 'splitLine'\n];\n\n// function getAlignWithLabel(model, axisModel) {\n//     var alignWithLabel = model.get('alignWithLabel');\n//     if (alignWithLabel === 'auto') {\n//         alignWithLabel = axisModel.get('axisTick.alignWithLabel');\n//     }\n//     return alignWithLabel;\n// }\n\nvar CartesianAxisView = AxisView.extend({\n\n    type: 'cartesianAxis',\n\n    axisPointerClass: 'CartesianAxisPointer',\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n\n        this.group.removeAll();\n\n        var oldAxisGroup = this._axisGroup;\n        this._axisGroup = new Group();\n\n        this.group.add(this._axisGroup);\n\n        if (!axisModel.get('show')) {\n            return;\n        }\n\n        var gridModel = axisModel.getCoordSysModel();\n\n        var layout = layout$1(gridModel, axisModel);\n\n        var axisBuilder = new AxisBuilder(axisModel, layout);\n\n        each$1(axisBuilderAttrs, axisBuilder.add, axisBuilder);\n\n        this._axisGroup.add(axisBuilder.getGroup());\n\n        each$1(selfBuilderAttrs, function (name) {\n            if (axisModel.get(name + '.show')) {\n                this['_' + name](axisModel, gridModel);\n            }\n        }, this);\n\n        groupTransition(oldAxisGroup, this._axisGroup, axisModel);\n\n        CartesianAxisView.superCall(this, 'render', axisModel, ecModel, api, payload);\n    },\n\n    remove: function () {\n        this._splitAreaColors = null;\n    },\n\n    /**\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/coord/cartesian/GridModel} gridModel\n     * @private\n     */\n    _splitLine: function (axisModel, gridModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitLineModel = axisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineColors = lineStyleModel.get('color');\n\n        lineColors = isArray(lineColors) ? lineColors : [lineColors];\n\n        var gridRect = gridModel.coordinateSystem.getRect();\n        var isHorizontal = axis.isHorizontal();\n\n        var lineCount = 0;\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitLineModel\n        });\n\n        var p1 = [];\n        var p2 = [];\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        var lineStyle = lineStyleModel.getLineStyle();\n        for (var i = 0; i < ticksCoords.length; i++) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n\n            if (isHorizontal) {\n                p1[0] = tickCoord;\n                p1[1] = gridRect.y;\n                p2[0] = tickCoord;\n                p2[1] = gridRect.y + gridRect.height;\n            }\n            else {\n                p1[0] = gridRect.x;\n                p1[1] = tickCoord;\n                p2[0] = gridRect.x + gridRect.width;\n                p2[1] = tickCoord;\n            }\n\n            var colorIndex = (lineCount++) % lineColors.length;\n            var tickValue = ticksCoords[i].tickValue;\n            this._axisGroup.add(new Line(subPixelOptimizeLine({\n                anid: tickValue != null ? 'line_' + ticksCoords[i].tickValue : null,\n                shape: {\n                    x1: p1[0],\n                    y1: p1[1],\n                    x2: p2[0],\n                    y2: p2[1]\n                },\n                style: defaults({\n                    stroke: lineColors[colorIndex]\n                }, lineStyle),\n                silent: true\n            })));\n        }\n    },\n\n    /**\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/coord/cartesian/GridModel} gridModel\n     * @private\n     */\n    _splitArea: function (axisModel, gridModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitAreaModel = axisModel.getModel('splitArea');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n        var areaColors = areaStyleModel.get('color');\n\n        var gridRect = gridModel.coordinateSystem.getRect();\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitAreaModel,\n            clamp: true\n        });\n\n        if (!ticksCoords.length) {\n            return;\n        }\n\n        // For Making appropriate splitArea animation, the color and anid\n        // should be corresponding to previous one if possible.\n        var areaColorsLen = areaColors.length;\n        var lastSplitAreaColors = this._splitAreaColors;\n        var newSplitAreaColors = createHashMap();\n        var colorIndex = 0;\n        if (lastSplitAreaColors) {\n            for (var i = 0; i < ticksCoords.length; i++) {\n                var cIndex = lastSplitAreaColors.get(ticksCoords[i].tickValue);\n                if (cIndex != null) {\n                    colorIndex = (cIndex + (areaColorsLen - 1) * i) % areaColorsLen;\n                    break;\n                }\n            }\n        }\n\n        var prev = axis.toGlobalCoord(ticksCoords[0].coord);\n\n        var areaStyle = areaStyleModel.getAreaStyle();\n        areaColors = isArray(areaColors) ? areaColors : [areaColors];\n\n        for (var i = 1; i < ticksCoords.length; i++) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n\n            var x;\n            var y;\n            var width;\n            var height;\n            if (axis.isHorizontal()) {\n                x = prev;\n                y = gridRect.y;\n                width = tickCoord - x;\n                height = gridRect.height;\n                prev = x + width;\n            }\n            else {\n                x = gridRect.x;\n                y = prev;\n                width = gridRect.width;\n                height = tickCoord - y;\n                prev = y + height;\n            }\n\n            var tickValue = ticksCoords[i - 1].tickValue;\n            tickValue != null && newSplitAreaColors.set(tickValue, colorIndex);\n\n            this._axisGroup.add(new Rect({\n                anid: tickValue != null ? 'area_' + tickValue : null,\n                shape: {\n                    x: x,\n                    y: y,\n                    width: width,\n                    height: height\n                },\n                style: defaults({\n                    fill: areaColors[colorIndex]\n                }, areaStyle),\n                silent: true\n            }));\n\n            colorIndex = (colorIndex + 1) % areaColorsLen;\n        }\n\n        this._splitAreaColors = newSplitAreaColors;\n    }\n});\n\nCartesianAxisView.extend({\n    type: 'xAxis'\n});\nCartesianAxisView.extend({\n    type: 'yAxis'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Grid view\nextendComponentView({\n\n    type: 'grid',\n\n    render: function (gridModel, ecModel) {\n        this.group.removeAll();\n        if (gridModel.get('show')) {\n            this.group.add(new Rect({\n                shape: gridModel.coordinateSystem.getRect(),\n                style: defaults({\n                    fill: gridModel.get('backgroundColor')\n                }, gridModel.getItemStyle()),\n                silent: true,\n                z2: -1\n            }));\n        }\n    }\n\n});\n\nregisterPreprocessor(function (option) {\n    // Only create grid when need\n    if (option.xAxis && option.yAxis && !option.grid) {\n        option.grid = {};\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterVisual(visualSymbol('line', 'circle', 'line'));\nregisterLayout(pointsLayout('line'));\n\n// Down sample after filter\nregisterProcessor(\n    PRIORITY.PROCESSOR.STATISTIC,\n    dataSample('line')\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BaseBarSeries = SeriesModel.extend({\n\n    type: 'series.__base_bar__',\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    getMarkerPosition: function (value) {\n        var coordSys = this.coordinateSystem;\n        if (coordSys) {\n            // PENDING if clamp ?\n            var pt = coordSys.dataToPoint(coordSys.clampData(value));\n            var data = this.getData();\n            var offset = data.getLayout('offset');\n            var size = data.getLayout('size');\n            var offsetIndex = coordSys.getBaseAxis().isHorizontal() ? 0 : 1;\n            pt[offsetIndex] += offset + size / 2;\n            return pt;\n        }\n        return [NaN, NaN];\n    },\n\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n        // stack: null\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // 最小高度改为0\n        barMinHeight: 0,\n        // 最小角度为0，仅对极坐标系下的柱状图有效\n        barMinAngle: 0,\n        // cursor: null,\n\n        large: false,\n        largeThreshold: 400,\n        progressive: 3e3,\n        progressiveChunkMode: 'mod',\n\n        // barMaxWidth: null,\n        // 默认自适应\n        // barWidth: null,\n        // 柱间距离，默认为柱形宽度的30%，可设固定值\n        // barGap: '30%',\n        // 类目间柱形距离，默认为类目间距的20%，可设固定值\n        // barCategoryGap: '20%',\n        // label: {\n        //      show: false\n        // },\n        itemStyle: {},\n        emphasis: {}\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nBaseBarSeries.extend({\n\n    type: 'series.bar',\n\n    dependencies: ['grid', 'polar'],\n\n    brushSelector: 'rect',\n\n    /**\n     * @override\n     */\n    getProgressive: function () {\n        // Do not support progressive in normal mode.\n        return this.get('large')\n            ? this.get('progressive')\n            : false;\n    },\n\n    /**\n     * @override\n     */\n    getProgressiveThreshold: function () {\n        // Do not support progressive in normal mode.\n        var progressiveThreshold = this.get('progressiveThreshold');\n        var largeThreshold = this.get('largeThreshold');\n        if (largeThreshold > progressiveThreshold) {\n            progressiveThreshold = largeThreshold;\n        }\n        return progressiveThreshold;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction setLabel(\n    normalStyle, hoverStyle, itemModel, color, seriesModel, dataIndex, labelPositionOutside\n) {\n    var labelModel = itemModel.getModel('label');\n    var hoverLabelModel = itemModel.getModel('emphasis.label');\n\n    setLabelStyle(\n        normalStyle, hoverStyle, labelModel, hoverLabelModel,\n        {\n            labelFetcher: seriesModel,\n            labelDataIndex: dataIndex,\n            defaultText: getDefaultLabel(seriesModel.getData(), dataIndex),\n            isRectText: true,\n            autoColor: color\n        }\n    );\n\n    fixPosition(normalStyle);\n    fixPosition(hoverStyle);\n}\n\nfunction fixPosition(style, labelPositionOutside) {\n    if (style.textPosition === 'outside') {\n        style.textPosition = labelPositionOutside;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getBarItemStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['stroke', 'borderColor'],\n        ['lineWidth', 'borderWidth'],\n        // Compatitable with 2\n        ['stroke', 'barBorderColor'],\n        ['lineWidth', 'barBorderWidth'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor']\n    ]\n);\n\nvar barItemStyle = {\n    getBarItemStyle: function (excludes) {\n        var style = getBarItemStyle(this, excludes);\n        if (this.getBorderLineDash) {\n            var lineDash = this.getBorderLineDash();\n            lineDash && (style.lineDash = lineDash);\n        }\n        return style;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'barBorderWidth'];\n\n// FIXME\n// Just for compatible with ec2.\nextend(Model.prototype, barItemStyle);\n\nextendChartView({\n\n    type: 'bar',\n\n    render: function (seriesModel, ecModel, api) {\n        this._updateDrawMode(seriesModel);\n\n        var coordinateSystemType = seriesModel.get('coordinateSystem');\n\n        if (coordinateSystemType === 'cartesian2d'\n            || coordinateSystemType === 'polar'\n        ) {\n            this._isLargeDraw\n                ? this._renderLarge(seriesModel, ecModel, api)\n                : this._renderNormal(seriesModel, ecModel, api);\n        }\n        else if (__DEV__) {\n            console.warn('Only cartesian2d and polar supported for bar.');\n        }\n\n        return this.group;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this._clear();\n        this._updateDrawMode(seriesModel);\n    },\n\n    incrementalRender: function (params, seriesModel, ecModel, api) {\n        // Do not support progressive in normal mode.\n        this._incrementalRenderLarge(params, seriesModel);\n    },\n\n    _updateDrawMode: function (seriesModel) {\n        var isLargeDraw = seriesModel.pipelineContext.large;\n        if (this._isLargeDraw == null || isLargeDraw ^ this._isLargeDraw) {\n            this._isLargeDraw = isLargeDraw;\n            this._clear();\n        }\n    },\n\n    _renderNormal: function (seriesModel, ecModel, api) {\n        var group = this.group;\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        var coord = seriesModel.coordinateSystem;\n        var baseAxis = coord.getBaseAxis();\n        var isHorizontalOrRadial;\n\n        if (coord.type === 'cartesian2d') {\n            isHorizontalOrRadial = baseAxis.isHorizontal();\n        }\n        else if (coord.type === 'polar') {\n            isHorizontalOrRadial = baseAxis.dim === 'angle';\n        }\n\n        var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null;\n\n        data.diff(oldData)\n            .add(function (dataIndex) {\n                if (!data.hasValue(dataIndex)) {\n                    return;\n                }\n\n                var itemModel = data.getItemModel(dataIndex);\n                var layout = getLayout[coord.type](data, dataIndex, itemModel);\n                var el = elementCreator[coord.type](\n                    data, dataIndex, itemModel, layout, isHorizontalOrRadial, animationModel\n                );\n                data.setItemGraphicEl(dataIndex, el);\n                group.add(el);\n\n                updateStyle(\n                    el, data, dataIndex, itemModel, layout,\n                    seriesModel, isHorizontalOrRadial, coord.type === 'polar'\n                );\n            })\n            .update(function (newIndex, oldIndex) {\n                var el = oldData.getItemGraphicEl(oldIndex);\n\n                if (!data.hasValue(newIndex)) {\n                    group.remove(el);\n                    return;\n                }\n\n                var itemModel = data.getItemModel(newIndex);\n                var layout = getLayout[coord.type](data, newIndex, itemModel);\n\n                if (el) {\n                    updateProps(el, {shape: layout}, animationModel, newIndex);\n                }\n                else {\n                    el = elementCreator[coord.type](\n                        data, newIndex, itemModel, layout, isHorizontalOrRadial, animationModel, true\n                    );\n                }\n\n                data.setItemGraphicEl(newIndex, el);\n                // Add back\n                group.add(el);\n\n                updateStyle(\n                    el, data, newIndex, itemModel, layout,\n                    seriesModel, isHorizontalOrRadial, coord.type === 'polar'\n                );\n            })\n            .remove(function (dataIndex) {\n                var el = oldData.getItemGraphicEl(dataIndex);\n                if (coord.type === 'cartesian2d') {\n                    el && removeRect(dataIndex, animationModel, el);\n                }\n                else {\n                    el && removeSector(dataIndex, animationModel, el);\n                }\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    _renderLarge: function (seriesModel, ecModel, api) {\n        this._clear();\n        createLarge(seriesModel, this.group);\n    },\n\n    _incrementalRenderLarge: function (params, seriesModel) {\n        createLarge(seriesModel, this.group, true);\n    },\n\n    dispose: noop,\n\n    remove: function (ecModel) {\n        this._clear(ecModel);\n    },\n\n    _clear: function (ecModel) {\n        var group = this.group;\n        var data = this._data;\n        if (ecModel && ecModel.get('animation') && data && !this._isLargeDraw) {\n            data.eachItemGraphicEl(function (el) {\n                if (el.type === 'sector') {\n                    removeSector(el.dataIndex, ecModel, el);\n                }\n                else {\n                    removeRect(el.dataIndex, ecModel, el);\n                }\n            });\n        }\n        else {\n            group.removeAll();\n        }\n        this._data = null;\n    }\n\n});\n\nvar elementCreator = {\n\n    cartesian2d: function (\n        data, dataIndex, itemModel, layout, isHorizontal,\n        animationModel, isUpdate\n    ) {\n        var rect = new Rect({shape: extend({}, layout)});\n\n        // Animation\n        if (animationModel) {\n            var rectShape = rect.shape;\n            var animateProperty = isHorizontal ? 'height' : 'width';\n            var animateTarget = {};\n            rectShape[animateProperty] = 0;\n            animateTarget[animateProperty] = layout[animateProperty];\n            graphic[isUpdate ? 'updateProps' : 'initProps'](rect, {\n                shape: animateTarget\n            }, animationModel, dataIndex);\n        }\n\n        return rect;\n    },\n\n    polar: function (\n        data, dataIndex, itemModel, layout, isRadial,\n        animationModel, isUpdate\n    ) {\n        // Keep the same logic with bar in catesion: use end value to control\n        // direction. Notice that if clockwise is true (by default), the sector\n        // will always draw clockwisely, no matter whether endAngle is greater\n        // or less than startAngle.\n        var clockwise = layout.startAngle < layout.endAngle;\n        var sector = new Sector({\n            shape: defaults({clockwise: clockwise}, layout)\n        });\n\n        // Animation\n        if (animationModel) {\n            var sectorShape = sector.shape;\n            var animateProperty = isRadial ? 'r' : 'endAngle';\n            var animateTarget = {};\n            sectorShape[animateProperty] = isRadial ? 0 : layout.startAngle;\n            animateTarget[animateProperty] = layout[animateProperty];\n            graphic[isUpdate ? 'updateProps' : 'initProps'](sector, {\n                shape: animateTarget\n            }, animationModel, dataIndex);\n        }\n\n        return sector;\n    }\n};\n\nfunction removeRect(dataIndex, animationModel, el) {\n    // Not show text when animating\n    el.style.text = null;\n    updateProps(el, {\n        shape: {\n            width: 0\n        }\n    }, animationModel, dataIndex, function () {\n        el.parent && el.parent.remove(el);\n    });\n}\n\nfunction removeSector(dataIndex, animationModel, el) {\n    // Not show text when animating\n    el.style.text = null;\n    updateProps(el, {\n        shape: {\n            r: el.shape.r0\n        }\n    }, animationModel, dataIndex, function () {\n        el.parent && el.parent.remove(el);\n    });\n}\n\nvar getLayout = {\n    cartesian2d: function (data, dataIndex, itemModel) {\n        var layout = data.getItemLayout(dataIndex);\n        var fixedLineWidth = getLineWidth(itemModel, layout);\n\n        // fix layout with lineWidth\n        var signX = layout.width > 0 ? 1 : -1;\n        var signY = layout.height > 0 ? 1 : -1;\n        return {\n            x: layout.x + signX * fixedLineWidth / 2,\n            y: layout.y + signY * fixedLineWidth / 2,\n            width: layout.width - signX * fixedLineWidth,\n            height: layout.height - signY * fixedLineWidth\n        };\n    },\n\n    polar: function (data, dataIndex, itemModel) {\n        var layout = data.getItemLayout(dataIndex);\n        return {\n            cx: layout.cx,\n            cy: layout.cy,\n            r0: layout.r0,\n            r: layout.r,\n            startAngle: layout.startAngle,\n            endAngle: layout.endAngle\n        };\n    }\n};\n\nfunction updateStyle(\n    el, data, dataIndex, itemModel, layout, seriesModel, isHorizontal, isPolar\n) {\n    var color = data.getItemVisual(dataIndex, 'color');\n    var opacity = data.getItemVisual(dataIndex, 'opacity');\n    var itemStyleModel = itemModel.getModel('itemStyle');\n    var hoverStyle = itemModel.getModel('emphasis.itemStyle').getBarItemStyle();\n\n    if (!isPolar) {\n        el.setShape('r', itemStyleModel.get('barBorderRadius') || 0);\n    }\n\n    el.useStyle(defaults(\n        {\n            fill: color,\n            opacity: opacity\n        },\n        itemStyleModel.getBarItemStyle()\n    ));\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && el.attr('cursor', cursorStyle);\n\n    var labelPositionOutside = isHorizontal\n        ? (layout.height > 0 ? 'bottom' : 'top')\n        : (layout.width > 0 ? 'left' : 'right');\n\n    if (!isPolar) {\n        setLabel(\n            el.style, hoverStyle, itemModel, color,\n            seriesModel, dataIndex, labelPositionOutside\n        );\n    }\n\n    setHoverStyle(el, hoverStyle);\n}\n\n// In case width or height are too small.\nfunction getLineWidth(itemModel, rawLayout) {\n    var lineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY) || 0;\n    return Math.min(lineWidth, Math.abs(rawLayout.width), Math.abs(rawLayout.height));\n}\n\n\nvar LargePath = Path.extend({\n\n    type: 'largeBar',\n\n    shape: {points: []},\n\n    buildPath: function (ctx, shape) {\n        // Drawing lines is more efficient than drawing\n        // a whole line or drawing rects.\n        var points = shape.points;\n        var startPoint = this.__startPoint;\n        var valueIdx = this.__valueIdx;\n\n        for (var i = 0; i < points.length; i += 2) {\n            startPoint[this.__valueIdx] = points[i + valueIdx];\n            ctx.moveTo(startPoint[0], startPoint[1]);\n            ctx.lineTo(points[i], points[i + 1]);\n        }\n    }\n});\n\nfunction createLarge(seriesModel, group, incremental) {\n    // TODO support polar\n    var data = seriesModel.getData();\n    var startPoint = [];\n    var valueIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0;\n    startPoint[1 - valueIdx] = data.getLayout('valueAxisStart');\n\n    var el = new LargePath({\n        shape: {points: data.getLayout('largePoints')},\n        incremental: !!incremental,\n        __startPoint: startPoint,\n        __valueIdx: valueIdx\n    });\n    group.add(el);\n    setLargeStyle(el, seriesModel, data);\n}\n\nfunction setLargeStyle(el, seriesModel, data) {\n    var borderColor = data.getVisual('borderColor') || data.getVisual('color');\n    var itemStyle = seriesModel.getModel('itemStyle').getItemStyle(['color', 'borderColor']);\n\n    el.useStyle(itemStyle);\n    el.style.fill = null;\n    el.style.stroke = borderColor;\n    el.style.lineWidth = data.getLayout('barWidth');\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterLayout(curry(layout, 'bar'));\n// Should after normal bar layout, otherwise it is blocked by normal bar layout.\nregisterLayout(largeLayout);\n\nregisterVisual({\n    seriesType: 'bar',\n    reset: function (seriesModel) {\n        // Visual coding for legend\n        seriesModel.getData().setVisual('legendSymbol', 'roundRect');\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * [Usage]:\n * (1)\n * createListSimply(seriesModel, ['value']);\n * (2)\n * createListSimply(seriesModel, {\n *     coordDimensions: ['value'],\n *     dimensionsCount: 5\n * });\n *\n * @param {module:echarts/model/Series} seriesModel\n * @param {Object|Array.<string|Object>} opt opt or coordDimensions\n *        The options in opt, see `echarts/data/helper/createDimensions`\n * @param {Array.<string>} [nameList]\n * @return {module:echarts/data/List}\n */\nvar createListSimply = function (seriesModel, opt, nameList) {\n    opt = isArray(opt) && {coordDimensions: opt} || extend({}, opt);\n\n    var source = seriesModel.getSource();\n\n    var dimensionsInfo = createDimensions(source, opt);\n\n    var list = new List(dimensionsInfo, seriesModel);\n    list.initData(source, nameList);\n\n    return list;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Data selectable mixin for chart series.\n * To eanble data select, option of series must have `selectedMode`.\n * And each data item will use `selected` to toggle itself selected status\n */\n\nvar dataSelectableMixin = {\n\n    /**\n     * @param {Array.<Object>} targetList [{name, value, selected}, ...]\n     *        If targetList is an array, it should like [{name: ..., value: ...}, ...].\n     *        If targetList is a \"List\", it must have coordDim: 'value' dimension and name.\n     */\n    updateSelectedMap: function (targetList) {\n        this._targetList = isArray(targetList) ? targetList.slice() : [];\n\n        this._selectTargetMap = reduce(targetList || [], function (targetMap, target) {\n            targetMap.set(target.name, target);\n            return targetMap;\n        }, createHashMap());\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    // PENGING If selectedMode is null ?\n    select: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        var selectedMode = this.get('selectedMode');\n        if (selectedMode === 'single') {\n            this._selectTargetMap.each(function (target) {\n                target.selected = false;\n            });\n        }\n        target && (target.selected = true);\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    unSelect: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        // var selectedMode = this.get('selectedMode');\n        // selectedMode !== 'single' && target && (target.selected = false);\n        target && (target.selected = false);\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    toggleSelected: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        if (target != null) {\n            this[target.selected ? 'unSelect' : 'select'](name, id);\n            return target.selected;\n        }\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    isSelected: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        return target && target.selected;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PieSeries = extendSeriesModel({\n\n    type: 'series.pie',\n\n    // Overwrite\n    init: function (option) {\n        PieSeries.superApply(this, 'init', arguments);\n\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n\n        this.updateSelectedMap(this._createSelectableList());\n\n        this._defaultLabelLine(option);\n    },\n\n    // Overwrite\n    mergeOption: function (newOption) {\n        PieSeries.superCall(this, 'mergeOption', newOption);\n\n        this.updateSelectedMap(this._createSelectableList());\n    },\n\n    getInitialData: function (option, ecModel) {\n        return createListSimply(this, ['value']);\n    },\n\n    _createSelectableList: function () {\n        var data = this.getRawData();\n        var valueDim = data.mapDimension('value');\n        var targetList = [];\n        for (var i = 0, len = data.count(); i < len; i++) {\n            targetList.push({\n                name: data.getName(i),\n                value: data.get(valueDim, i),\n                selected: retrieveRawAttr(data, i, 'selected')\n            });\n        }\n        return targetList;\n    },\n\n    // Overwrite\n    getDataParams: function (dataIndex) {\n        var data = this.getData();\n        var params = PieSeries.superCall(this, 'getDataParams', dataIndex);\n        // FIXME toFixed?\n\n        var valueList = [];\n        data.each(data.mapDimension('value'), function (value) {\n            valueList.push(value);\n        });\n\n        params.percent = getPercentWithPrecision(\n            valueList,\n            dataIndex,\n            data.hostModel.get('percentPrecision')\n        );\n\n        params.$vars.push('percent');\n        return params;\n    },\n\n    _defaultLabelLine: function (option) {\n        // Extend labelLine emphasis\n        defaultEmphasis(option, 'labelLine', ['show']);\n\n        var labelLineNormalOpt = option.labelLine;\n        var labelLineEmphasisOpt = option.emphasis.labelLine;\n        // Not show label line if `label.normal.show = false`\n        labelLineNormalOpt.show = labelLineNormalOpt.show\n            && option.label.show;\n        labelLineEmphasisOpt.show = labelLineEmphasisOpt.show\n            && option.emphasis.label.show;\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // 默认全局居中\n        center: ['50%', '50%'],\n        radius: [0, '75%'],\n        // 默认顺时针\n        clockwise: true,\n        startAngle: 90,\n        // 最小角度改为0\n        minAngle: 0,\n        // 选中时扇区偏移量\n        selectedOffset: 10,\n        // 高亮扇区偏移量\n        hoverOffset: 10,\n\n        // If use strategy to avoid label overlapping\n        avoidLabelOverlap: true,\n        // 选择模式，默认关闭，可选single，multiple\n        // selectedMode: false,\n        // 南丁格尔玫瑰图模式，'radius'（半径） | 'area'（面积）\n        // roseType: null,\n\n        percentPrecision: 2,\n\n        // If still show when all data zero.\n        stillShowZeroSum: true,\n\n        // cursor: null,\n\n        label: {\n            // If rotate around circle\n            rotate: false,\n            show: true,\n            // 'outer', 'inside', 'center'\n            position: 'outer'\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n            // 默认使用全局文本样式，详见TEXTSTYLE\n            // distance: 当position为inner时有效，为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数\n        },\n        // Enabled when label.normal.position is 'outer'\n        labelLine: {\n            show: true,\n            // 引导线两段中的第一段长度\n            length: 15,\n            // 引导线两段中的第二段长度\n            length2: 15,\n            smooth: false,\n            lineStyle: {\n                // color: 各异,\n                width: 1,\n                type: 'solid'\n            }\n        },\n        itemStyle: {\n            borderWidth: 1\n        },\n\n        // Animation type canbe expansion, scale\n        animationType: 'expansion',\n\n        animationEasing: 'cubicOut'\n    }\n});\n\nmixin(PieSeries, dataSelectableMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/model/Series} seriesModel\n * @param {boolean} hasAnimation\n * @inner\n */\nfunction updateDataSelected(uid, seriesModel, hasAnimation, api) {\n    var data = seriesModel.getData();\n    var dataIndex = this.dataIndex;\n    var name = data.getName(dataIndex);\n    var selectedOffset = seriesModel.get('selectedOffset');\n\n    api.dispatchAction({\n        type: 'pieToggleSelect',\n        from: uid,\n        name: name,\n        seriesId: seriesModel.id\n    });\n\n    data.each(function (idx) {\n        toggleItemSelected(\n            data.getItemGraphicEl(idx),\n            data.getItemLayout(idx),\n            seriesModel.isSelected(data.getName(idx)),\n            selectedOffset,\n            hasAnimation\n        );\n    });\n}\n\n/**\n * @param {module:zrender/graphic/Sector} el\n * @param {Object} layout\n * @param {boolean} isSelected\n * @param {number} selectedOffset\n * @param {boolean} hasAnimation\n * @inner\n */\nfunction toggleItemSelected(el, layout, isSelected, selectedOffset, hasAnimation) {\n    var midAngle = (layout.startAngle + layout.endAngle) / 2;\n\n    var dx = Math.cos(midAngle);\n    var dy = Math.sin(midAngle);\n\n    var offset = isSelected ? selectedOffset : 0;\n    var position = [dx * offset, dy * offset];\n\n    hasAnimation\n        // animateTo will stop revious animation like update transition\n        ? el.animate()\n            .when(200, {\n                position: position\n            })\n            .start('bounceOut')\n        : el.attr('position', position);\n}\n\n/**\n * Piece of pie including Sector, Label, LabelLine\n * @constructor\n * @extends {module:zrender/graphic/Group}\n */\nfunction PiePiece(data, idx) {\n\n    Group.call(this);\n\n    var sector = new Sector({\n        z2: 2\n    });\n    var polyline = new Polyline();\n    var text = new Text();\n    this.add(sector);\n    this.add(polyline);\n    this.add(text);\n\n    this.updateData(data, idx, true);\n\n    // Hover to change label and labelLine\n    function onEmphasis() {\n        polyline.ignore = polyline.hoverIgnore;\n        text.ignore = text.hoverIgnore;\n    }\n    function onNormal() {\n        polyline.ignore = polyline.normalIgnore;\n        text.ignore = text.normalIgnore;\n    }\n    this.on('emphasis', onEmphasis)\n        .on('normal', onNormal)\n        .on('mouseover', onEmphasis)\n        .on('mouseout', onNormal);\n}\n\nvar piePieceProto = PiePiece.prototype;\n\npiePieceProto.updateData = function (data, idx, firstCreate) {\n\n    var sector = this.childAt(0);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var sectorShape = extend({}, layout);\n    sectorShape.label = null;\n\n    if (firstCreate) {\n        sector.setShape(sectorShape);\n\n        var animationType = seriesModel.getShallow('animationType');\n        if (animationType === 'scale') {\n            sector.shape.r = layout.r0;\n            initProps(sector, {\n                shape: {\n                    r: layout.r\n                }\n            }, seriesModel, idx);\n        }\n        // Expansion\n        else {\n            sector.shape.endAngle = layout.startAngle;\n            updateProps(sector, {\n                shape: {\n                    endAngle: layout.endAngle\n                }\n            }, seriesModel, idx);\n        }\n\n    }\n    else {\n        updateProps(sector, {\n            shape: sectorShape\n        }, seriesModel, idx);\n    }\n\n    // Update common style\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    sector.useStyle(\n        defaults(\n            {\n                lineJoin: 'bevel',\n                fill: visualColor\n            },\n            itemModel.getModel('itemStyle').getItemStyle()\n        )\n    );\n    sector.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && sector.attr('cursor', cursorStyle);\n\n    // Toggle selected\n    toggleItemSelected(\n        this,\n        data.getItemLayout(idx),\n        seriesModel.isSelected(null, idx),\n        seriesModel.get('selectedOffset'),\n        seriesModel.get('animation')\n    );\n\n    function onEmphasis() {\n        // Sector may has animation of updating data. Force to move to the last frame\n        // Or it may stopped on the wrong shape\n        sector.stopAnimation(true);\n        sector.animateTo({\n            shape: {\n                r: layout.r + seriesModel.get('hoverOffset')\n            }\n        }, 300, 'elasticOut');\n    }\n    function onNormal() {\n        sector.stopAnimation(true);\n        sector.animateTo({\n            shape: {\n                r: layout.r\n            }\n        }, 300, 'elasticOut');\n    }\n    sector.off('mouseover').off('mouseout').off('emphasis').off('normal');\n    if (itemModel.get('hoverAnimation') && seriesModel.isAnimationEnabled()) {\n        sector\n            .on('mouseover', onEmphasis)\n            .on('mouseout', onNormal)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal);\n    }\n\n    this._updateLabel(data, idx);\n\n    setHoverStyle(this);\n};\n\npiePieceProto._updateLabel = function (data, idx) {\n\n    var labelLine = this.childAt(1);\n    var labelText = this.childAt(2);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var labelLayout = layout.label;\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    updateProps(labelLine, {\n        shape: {\n            points: labelLayout.linePoints || [\n                [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y]\n            ]\n        }\n    }, seriesModel, idx);\n\n    updateProps(labelText, {\n        style: {\n            x: labelLayout.x,\n            y: labelLayout.y\n        }\n    }, seriesModel, idx);\n    labelText.attr({\n        rotation: labelLayout.rotation,\n        origin: [labelLayout.x, labelLayout.y],\n        z2: 10\n    });\n\n    var labelModel = itemModel.getModel('label');\n    var labelHoverModel = itemModel.getModel('emphasis.label');\n    var labelLineModel = itemModel.getModel('labelLine');\n    var labelLineHoverModel = itemModel.getModel('emphasis.labelLine');\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    setLabelStyle(\n        labelText.style, labelText.hoverStyle = {}, labelModel, labelHoverModel,\n        {\n            labelFetcher: data.hostModel,\n            labelDataIndex: idx,\n            defaultText: data.getName(idx),\n            autoColor: visualColor,\n            useInsideStyle: !!labelLayout.inside\n        },\n        {\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.verticalAlign,\n            opacity: data.getItemVisual(idx, 'opacity')\n        }\n    );\n\n    labelText.ignore = labelText.normalIgnore = !labelModel.get('show');\n    labelText.hoverIgnore = !labelHoverModel.get('show');\n\n    labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show');\n    labelLine.hoverIgnore = !labelLineHoverModel.get('show');\n\n    // Default use item visual color\n    labelLine.setStyle({\n        stroke: visualColor,\n        opacity: data.getItemVisual(idx, 'opacity')\n    });\n    labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());\n\n    labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();\n\n    var smooth = labelLineModel.get('smooth');\n    if (smooth && smooth === true) {\n        smooth = 0.4;\n    }\n    labelLine.setShape({\n        smooth: smooth\n    });\n};\n\ninherits(PiePiece, Group);\n\n\n// Pie view\nvar PieView = Chart.extend({\n\n    type: 'pie',\n\n    init: function () {\n        var sectorGroup = new Group();\n        this._sectorGroup = sectorGroup;\n    },\n\n    render: function (seriesModel, ecModel, api, payload) {\n        if (payload && (payload.from === this.uid)) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var oldData = this._data;\n        var group = this.group;\n\n        var hasAnimation = ecModel.get('animation');\n        var isFirstRender = !oldData;\n        var animationType = seriesModel.get('animationType');\n\n        var onSectorClick = curry(\n            updateDataSelected, this.uid, seriesModel, hasAnimation, api\n        );\n\n        var selectedMode = seriesModel.get('selectedMode');\n\n        data.diff(oldData)\n            .add(function (idx) {\n                var piePiece = new PiePiece(data, idx);\n                // Default expansion animation\n                if (isFirstRender && animationType !== 'scale') {\n                    piePiece.eachChild(function (child) {\n                        child.stopAnimation(true);\n                    });\n                }\n\n                selectedMode && piePiece.on('click', onSectorClick);\n\n                data.setItemGraphicEl(idx, piePiece);\n\n                group.add(piePiece);\n            })\n            .update(function (newIdx, oldIdx) {\n                var piePiece = oldData.getItemGraphicEl(oldIdx);\n\n                piePiece.updateData(data, newIdx);\n\n                piePiece.off('click');\n                selectedMode && piePiece.on('click', onSectorClick);\n                group.add(piePiece);\n                data.setItemGraphicEl(newIdx, piePiece);\n            })\n            .remove(function (idx) {\n                var piePiece = oldData.getItemGraphicEl(idx);\n                group.remove(piePiece);\n            })\n            .execute();\n\n        if (\n            hasAnimation && isFirstRender && data.count() > 0\n            // Default expansion animation\n            && animationType !== 'scale'\n        ) {\n            var shape = data.getItemLayout(0);\n            var r = Math.max(api.getWidth(), api.getHeight()) / 2;\n\n            var removeClipPath = bind(group.removeClipPath, group);\n            group.setClipPath(this._createClipPath(\n                shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel\n            ));\n        }\n        else {\n            // clipPath is used in first-time animation, so remove it when otherwise. See: #8994\n            group.removeClipPath();\n        }\n\n        this._data = data;\n    },\n\n    dispose: function () {},\n\n    _createClipPath: function (\n        cx, cy, r, startAngle, clockwise, cb, seriesModel\n    ) {\n        var clipPath = new Sector({\n            shape: {\n                cx: cx,\n                cy: cy,\n                r0: 0,\n                r: r,\n                startAngle: startAngle,\n                endAngle: startAngle,\n                clockwise: clockwise\n            }\n        });\n\n        initProps(clipPath, {\n            shape: {\n                endAngle: startAngle + (clockwise ? 1 : -1) * Math.PI * 2\n            }\n        }, seriesModel, cb);\n\n        return clipPath;\n    },\n\n    /**\n     * @implement\n     */\n    containPoint: function (point, seriesModel) {\n        var data = seriesModel.getData();\n        var itemLayout = data.getItemLayout(0);\n        if (itemLayout) {\n            var dx = point[0] - itemLayout.cx;\n            var dy = point[1] - itemLayout.cy;\n            var radius = Math.sqrt(dx * dx + dy * dy);\n            return radius <= itemLayout.r && radius >= itemLayout.r0;\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar createDataSelectAction = function (seriesType, actionInfos) {\n    each$1(actionInfos, function (actionInfo) {\n        actionInfo.update = 'updateView';\n        /**\n         * @payload\n         * @property {string} seriesName\n         * @property {string} name\n         */\n        registerAction(actionInfo, function (payload, ecModel) {\n            var selected = {};\n            ecModel.eachComponent(\n                {mainType: 'series', subType: seriesType, query: payload},\n                function (seriesModel) {\n                    if (seriesModel[actionInfo.method]) {\n                        seriesModel[actionInfo.method](\n                            payload.name,\n                            payload.dataIndex\n                        );\n                    }\n                    var data = seriesModel.getData();\n                    // Create selected map\n                    data.each(function (idx) {\n                        var name = data.getName(idx);\n                        selected[name] = seriesModel.isSelected(name)\n                            || false;\n                    });\n                }\n            );\n            return {\n                name: payload.name,\n                selected: selected\n            };\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Pick color from palette for each data item.\n// Applicable for charts that require applying color palette\n// in data level (like pie, funnel, chord).\nvar dataColor = function (seriesType) {\n    return {\n        getTargetSeries: function (ecModel) {\n            // Pie and funnel may use diferrent scope\n            var paletteScope = {};\n            var seiresModelMap = createHashMap();\n\n            ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n                seriesModel.__paletteScope = paletteScope;\n                seiresModelMap.set(seriesModel.uid, seriesModel);\n            });\n\n            return seiresModelMap;\n        },\n        reset: function (seriesModel, ecModel) {\n            var dataAll = seriesModel.getRawData();\n            var idxMap = {};\n            var data = seriesModel.getData();\n\n            data.each(function (idx) {\n                var rawIdx = data.getRawIndex(idx);\n                idxMap[rawIdx] = idx;\n            });\n\n            dataAll.each(function (rawIdx) {\n                var filteredIdx = idxMap[rawIdx];\n\n                // If series.itemStyle.normal.color is a function. itemVisual may be encoded\n                var singleDataColor = filteredIdx != null\n                    && data.getItemVisual(filteredIdx, 'color', true);\n\n                if (!singleDataColor) {\n                    // FIXME Performance\n                    var itemModel = dataAll.getItemModel(rawIdx);\n\n                    var color = itemModel.get('itemStyle.color')\n                        || seriesModel.getColorFromPalette(\n                            dataAll.getName(rawIdx) || (rawIdx + ''), seriesModel.__paletteScope,\n                            dataAll.count()\n                        );\n                    // Legend may use the visual info in data before processed\n                    dataAll.setItemVisual(rawIdx, 'color', color);\n\n                    // Data is not filtered\n                    if (filteredIdx != null) {\n                        data.setItemVisual(filteredIdx, 'color', color);\n                    }\n                }\n                else {\n                    // Set data all color for legend\n                    dataAll.setItemVisual(rawIdx, 'color', singleDataColor);\n                }\n            });\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME emphasis label position is not same with normal label position\n\nfunction adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {\n    list.sort(function (a, b) {\n        return a.y - b.y;\n    });\n\n    function shiftDown(start, end, delta, dir) {\n        for (var j = start; j < end; j++) {\n            list[j].y += delta;\n            if (j > start\n                && j + 1 < end\n                && list[j + 1].y > list[j].y + list[j].height\n            ) {\n                shiftUp(j, delta / 2);\n                return;\n            }\n        }\n\n        shiftUp(end - 1, delta / 2);\n    }\n\n    function shiftUp(end, delta) {\n        for (var j = end; j >= 0; j--) {\n            list[j].y -= delta;\n            if (j > 0\n                && list[j].y > list[j - 1].y + list[j - 1].height\n            ) {\n                break;\n            }\n        }\n    }\n\n    function changeX(list, isDownList, cx, cy, r, dir) {\n        var lastDeltaX = dir > 0\n            ? isDownList                // right-side\n                ? Number.MAX_VALUE      // down\n                : 0                     // up\n            : isDownList                // left-side\n                ? Number.MAX_VALUE      // down\n                : 0;                    // up\n\n        for (var i = 0, l = list.length; i < l; i++) {\n            var deltaY = Math.abs(list[i].y - cy);\n            var length = list[i].len;\n            var length2 = list[i].len2;\n            var deltaX = (deltaY < r + length)\n                ? Math.sqrt(\n                        (r + length + length2) * (r + length + length2)\n                        - deltaY * deltaY\n                    )\n                : Math.abs(list[i].x - cx);\n            if (isDownList && deltaX >= lastDeltaX) {\n                // right-down, left-down\n                deltaX = lastDeltaX - 10;\n            }\n            if (!isDownList && deltaX <= lastDeltaX) {\n                // right-up, left-up\n                deltaX = lastDeltaX + 10;\n            }\n\n            list[i].x = cx + deltaX * dir;\n            lastDeltaX = deltaX;\n        }\n    }\n\n    var lastY = 0;\n    var delta;\n    var len = list.length;\n    var upList = [];\n    var downList = [];\n    for (var i = 0; i < len; i++) {\n        delta = list[i].y - lastY;\n        if (delta < 0) {\n            shiftDown(i, len, -delta, dir);\n        }\n        lastY = list[i].y + list[i].height;\n    }\n    if (viewHeight - lastY < 0) {\n        shiftUp(len - 1, lastY - viewHeight);\n    }\n    for (var i = 0; i < len; i++) {\n        if (list[i].y >= cy) {\n            downList.push(list[i]);\n        }\n        else {\n            upList.push(list[i]);\n        }\n    }\n    changeX(upList, false, cx, cy, r, dir);\n    changeX(downList, true, cx, cy, r, dir);\n}\n\nfunction avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) {\n    var leftList = [];\n    var rightList = [];\n    for (var i = 0; i < labelLayoutList.length; i++) {\n        if (isPositionCenter(labelLayoutList[i])) {\n            continue;\n        }\n        if (labelLayoutList[i].x < cx) {\n            leftList.push(labelLayoutList[i]);\n        }\n        else {\n            rightList.push(labelLayoutList[i]);\n        }\n    }\n\n    adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight);\n    adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight);\n\n    for (var i = 0; i < labelLayoutList.length; i++) {\n        if (isPositionCenter(labelLayoutList[i])) {\n            continue;\n        }\n        var linePoints = labelLayoutList[i].linePoints;\n        if (linePoints) {\n            var dist = linePoints[1][0] - linePoints[2][0];\n            if (labelLayoutList[i].x < cx) {\n                linePoints[2][0] = labelLayoutList[i].x + 3;\n            }\n            else {\n                linePoints[2][0] = labelLayoutList[i].x - 3;\n            }\n            linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y;\n            linePoints[1][0] = linePoints[2][0] + dist;\n        }\n    }\n}\n\nfunction isPositionCenter(layout) {\n    // Not change x for center label\n    return layout.position === 'center';\n}\n\nvar labelLayout = function (seriesModel, r, viewWidth, viewHeight) {\n    var data = seriesModel.getData();\n    var labelLayoutList = [];\n    var cx;\n    var cy;\n    var hasLabelRotate = false;\n\n    data.each(function (idx) {\n        var layout = data.getItemLayout(idx);\n\n        var itemModel = data.getItemModel(idx);\n        var labelModel = itemModel.getModel('label');\n        // Use position in normal or emphasis\n        var labelPosition = labelModel.get('position') || itemModel.get('emphasis.label.position');\n\n        var labelLineModel = itemModel.getModel('labelLine');\n        var labelLineLen = labelLineModel.get('length');\n        var labelLineLen2 = labelLineModel.get('length2');\n\n        var midAngle = (layout.startAngle + layout.endAngle) / 2;\n        var dx = Math.cos(midAngle);\n        var dy = Math.sin(midAngle);\n\n        var textX;\n        var textY;\n        var linePoints;\n        var textAlign;\n\n        cx = layout.cx;\n        cy = layout.cy;\n\n        var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';\n        if (labelPosition === 'center') {\n            textX = layout.cx;\n            textY = layout.cy;\n            textAlign = 'center';\n        }\n        else {\n            var x1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dx : layout.r * dx) + cx;\n            var y1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dy : layout.r * dy) + cy;\n\n            textX = x1 + dx * 3;\n            textY = y1 + dy * 3;\n\n            if (!isLabelInside) {\n                // For roseType\n                var x2 = x1 + dx * (labelLineLen + r - layout.r);\n                var y2 = y1 + dy * (labelLineLen + r - layout.r);\n                var x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2);\n                var y3 = y2;\n\n                textX = x3 + (dx < 0 ? -5 : 5);\n                textY = y3;\n                linePoints = [[x1, y1], [x2, y2], [x3, y3]];\n            }\n\n            textAlign = isLabelInside ? 'center' : (dx > 0 ? 'left' : 'right');\n        }\n        var font = labelModel.getFont();\n\n        var labelRotate = labelModel.get('rotate')\n            ? (dx < 0 ? -midAngle + Math.PI : -midAngle) : 0;\n        var text = seriesModel.getFormattedLabel(idx, 'normal')\n                    || data.getName(idx);\n        var textRect = getBoundingRect(\n            text, font, textAlign, 'top'\n        );\n        hasLabelRotate = !!labelRotate;\n        layout.label = {\n            x: textX,\n            y: textY,\n            position: labelPosition,\n            height: textRect.height,\n            len: labelLineLen,\n            len2: labelLineLen2,\n            linePoints: linePoints,\n            textAlign: textAlign,\n            verticalAlign: 'middle',\n            rotation: labelRotate,\n            inside: isLabelInside\n        };\n\n        // Not layout the inside label\n        if (!isLabelInside) {\n            labelLayoutList.push(layout.label);\n        }\n    });\n    if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {\n        avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar PI2$4 = Math.PI * 2;\nvar RADIAN = Math.PI / 180;\n\nvar pieLayout = function (seriesType, ecModel, api, payload) {\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n\n        var center = seriesModel.get('center');\n        var radius = seriesModel.get('radius');\n\n        if (!isArray(radius)) {\n            radius = [0, radius];\n        }\n        if (!isArray(center)) {\n            center = [center, center];\n        }\n\n        var width = api.getWidth();\n        var height = api.getHeight();\n        var size = Math.min(width, height);\n        var cx = parsePercent$1(center[0], width);\n        var cy = parsePercent$1(center[1], height);\n        var r0 = parsePercent$1(radius[0], size / 2);\n        var r = parsePercent$1(radius[1], size / 2);\n\n        var startAngle = -seriesModel.get('startAngle') * RADIAN;\n\n        var minAngle = seriesModel.get('minAngle') * RADIAN;\n\n        var validDataCount = 0;\n        data.each(valueDim, function (value) {\n            !isNaN(value) && validDataCount++;\n        });\n\n        var sum = data.getSum(valueDim);\n        // Sum may be 0\n        var unitRadian = Math.PI / (sum || validDataCount) * 2;\n\n        var clockwise = seriesModel.get('clockwise');\n\n        var roseType = seriesModel.get('roseType');\n        var stillShowZeroSum = seriesModel.get('stillShowZeroSum');\n\n        // [0...max]\n        var extent = data.getDataExtent(valueDim);\n        extent[0] = 0;\n\n        // In the case some sector angle is smaller than minAngle\n        var restAngle = PI2$4;\n        var valueSumLargerThanMinAngle = 0;\n\n        var currentAngle = startAngle;\n        var dir = clockwise ? 1 : -1;\n\n        data.each(valueDim, function (value, idx) {\n            var angle;\n            if (isNaN(value)) {\n                data.setItemLayout(idx, {\n                    angle: NaN,\n                    startAngle: NaN,\n                    endAngle: NaN,\n                    clockwise: clockwise,\n                    cx: cx,\n                    cy: cy,\n                    r0: r0,\n                    r: roseType\n                        ? NaN\n                        : r\n                });\n                return;\n            }\n\n            // FIXME 兼容 2.0 但是 roseType 是 area 的时候才是这样？\n            if (roseType !== 'area') {\n                angle = (sum === 0 && stillShowZeroSum)\n                    ? unitRadian : (value * unitRadian);\n            }\n            else {\n                angle = PI2$4 / validDataCount;\n            }\n\n            if (angle < minAngle) {\n                angle = minAngle;\n                restAngle -= minAngle;\n            }\n            else {\n                valueSumLargerThanMinAngle += value;\n            }\n\n            var endAngle = currentAngle + dir * angle;\n            data.setItemLayout(idx, {\n                angle: angle,\n                startAngle: currentAngle,\n                endAngle: endAngle,\n                clockwise: clockwise,\n                cx: cx,\n                cy: cy,\n                r0: r0,\n                r: roseType\n                    ? linearMap(value, extent, [r0, r])\n                    : r\n            });\n\n            currentAngle = endAngle;\n        });\n\n        // Some sector is constrained by minAngle\n        // Rest sectors needs recalculate angle\n        if (restAngle < PI2$4 && validDataCount) {\n            // Average the angle if rest angle is not enough after all angles is\n            // Constrained by minAngle\n            if (restAngle <= 1e-3) {\n                var angle = PI2$4 / validDataCount;\n                data.each(valueDim, function (value, idx) {\n                    if (!isNaN(value)) {\n                        var layout = data.getItemLayout(idx);\n                        layout.angle = angle;\n                        layout.startAngle = startAngle + dir * idx * angle;\n                        layout.endAngle = startAngle + dir * (idx + 1) * angle;\n                    }\n                });\n            }\n            else {\n                unitRadian = restAngle / valueSumLargerThanMinAngle;\n                currentAngle = startAngle;\n                data.each(valueDim, function (value, idx) {\n                    if (!isNaN(value)) {\n                        var layout = data.getItemLayout(idx);\n                        var angle = layout.angle === minAngle\n                            ? minAngle : value * unitRadian;\n                        layout.startAngle = currentAngle;\n                        layout.endAngle = currentAngle + dir * angle;\n                        currentAngle += dir * angle;\n                    }\n                });\n            }\n        }\n\n        labelLayout(seriesModel, r, width, height);\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar dataFilter = function (seriesType) {\n    return {\n        seriesType: seriesType,\n        reset: function (seriesModel, ecModel) {\n            var legendModels = ecModel.findComponents({\n                mainType: 'legend'\n            });\n            if (!legendModels || !legendModels.length) {\n                return;\n            }\n            var data = seriesModel.getData();\n            data.filterSelf(function (idx) {\n                var name = data.getName(idx);\n                // If in any legend component the status is not selected.\n                for (var i = 0; i < legendModels.length; i++) {\n                    if (!legendModels[i].isSelected(name)) {\n                        return false;\n                    }\n                }\n                return true;\n            });\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\ncreateDataSelectAction('pie', [{\n    type: 'pieToggleSelect',\n    event: 'pieselectchanged',\n    method: 'toggleSelected'\n}, {\n    type: 'pieSelect',\n    event: 'pieselected',\n    method: 'select'\n}, {\n    type: 'pieUnSelect',\n    event: 'pieunselected',\n    method: 'unSelect'\n}]);\n\nregisterVisual(dataColor('pie'));\nregisterLayout(curry(pieLayout, 'pie'));\nregisterProcessor(dataFilter('pie'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.scatter',\n\n    dependencies: ['grid', 'polar', 'geo', 'singleAxis', 'calendar'],\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    brushSelector: 'point',\n\n    getProgressive: function () {\n        var progressive = this.option.progressive;\n        if (progressive == null) {\n            // PENDING\n            return this.option.large ? 5e3 : this.get('progressive');\n        }\n        return progressive;\n    },\n\n    getProgressiveThreshold: function () {\n        var progressiveThreshold = this.option.progressiveThreshold;\n        if (progressiveThreshold == null) {\n            // PENDING\n            return this.option.large ? 1e4 : this.get('progressiveThreshold');\n        }\n        return progressiveThreshold;\n    },\n\n    defaultOption: {\n        coordinateSystem: 'cartesian2d',\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // Polar coordinate system\n        // polarIndex: 0,\n\n        // Geo coordinate system\n        // geoIndex: 0,\n\n        // symbol: null,        // 图形类型\n        symbolSize: 10,          // 图形大小，半宽（半径）参数，当图形为方向或菱形则总宽度为symbolSize * 2\n        // symbolRotate: null,  // 图形旋转控制\n\n        large: false,\n        // Available when large is true\n        largeThreshold: 2000,\n        // cursor: null,\n\n        // label: {\n            // show: false\n            // distance: 5,\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n            // position: 默认自适应，水平布局为'top'，垂直布局为'right'，可选为\n            //           'inside'|'left'|'right'|'top'|'bottom'\n            // 默认使用全局文本样式，详见TEXTSTYLE\n        // },\n        itemStyle: {\n            opacity: 0.8\n            // color: 各异\n        }\n\n        // progressive: null\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\n// TODO Batch by color\n\nvar BOOST_SIZE_THRESHOLD = 4;\n\nvar LargeSymbolPath = extendShape({\n\n    shape: {\n        points: null\n    },\n\n    symbolProxy: null,\n\n    buildPath: function (path, shape) {\n        var points = shape.points;\n        var size = shape.size;\n\n        var symbolProxy = this.symbolProxy;\n        var symbolProxyShape = symbolProxy.shape;\n        var ctx = path.getContext ? path.getContext() : path;\n        var canBoost = ctx && size[0] < BOOST_SIZE_THRESHOLD;\n\n        // Do draw in afterBrush.\n        if (canBoost) {\n            return;\n        }\n\n        for (var i = 0; i < points.length;) {\n            var x = points[i++];\n            var y = points[i++];\n\n            if (isNaN(x) || isNaN(y)) {\n                continue;\n            }\n\n            symbolProxyShape.x = x - size[0] / 2;\n            symbolProxyShape.y = y - size[1] / 2;\n            symbolProxyShape.width = size[0];\n            symbolProxyShape.height = size[1];\n\n            symbolProxy.buildPath(path, symbolProxyShape, true);\n        }\n    },\n\n    afterBrush: function (ctx) {\n        var shape = this.shape;\n        var points = shape.points;\n        var size = shape.size;\n        var canBoost = size[0] < BOOST_SIZE_THRESHOLD;\n\n        if (!canBoost) {\n            return;\n        }\n\n        this.setTransform(ctx);\n        // PENDING If style or other canvas status changed?\n        for (var i = 0; i < points.length;) {\n            var x = points[i++];\n            var y = points[i++];\n            if (isNaN(x) || isNaN(y)) {\n                continue;\n            }\n            // fillRect is faster than building a rect path and draw.\n            // And it support light globalCompositeOperation.\n            ctx.fillRect(\n                x - size[0] / 2, y - size[1] / 2,\n                size[0], size[1]\n            );\n        }\n\n        this.restoreTransform(ctx);\n    },\n\n    findDataIndex: function (x, y) {\n        // TODO ???\n        // Consider transform\n\n        var shape = this.shape;\n        var points = shape.points;\n        var size = shape.size;\n\n        var w = Math.max(size[0], 4);\n        var h = Math.max(size[1], 4);\n\n        // Not consider transform\n        // Treat each element as a rect\n        // top down traverse\n        for (var idx = points.length / 2 - 1; idx >= 0; idx--) {\n            var i = idx * 2;\n            var x0 = points[i] - w / 2;\n            var y0 = points[i + 1] - h / 2;\n            if (x >= x0 && y >= y0 && x <= x0 + w && y <= y0 + h) {\n                return idx;\n            }\n        }\n\n        return -1;\n    }\n});\n\nfunction LargeSymbolDraw() {\n    this.group = new Group();\n}\n\nvar largeSymbolProto = LargeSymbolDraw.prototype;\n\nlargeSymbolProto.isPersistent = function () {\n    return !this._incremental;\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n */\nlargeSymbolProto.updateData = function (data) {\n    this.group.removeAll();\n    var symbolEl = new LargeSymbolPath({\n        rectHover: true,\n        cursor: 'default'\n    });\n\n    symbolEl.setShape({\n        points: data.getLayout('symbolPoints')\n    });\n    this._setCommon(symbolEl, data);\n    this.group.add(symbolEl);\n\n    this._incremental = null;\n};\n\nlargeSymbolProto.updateLayout = function (data) {\n    if (this._incremental) {\n        return;\n    }\n\n    var points = data.getLayout('symbolPoints');\n    this.group.eachChild(function (child) {\n        if (child.startIndex != null) {\n            var len = (child.endIndex - child.startIndex) * 2;\n            var byteOffset = child.startIndex * 4 * 2;\n            points = new Float32Array(points.buffer, byteOffset, len);\n        }\n        child.setShape('points', points);\n    });\n};\n\nlargeSymbolProto.incrementalPrepareUpdate = function (data) {\n    this.group.removeAll();\n\n    this._clearIncremental();\n    // Only use incremental displayables when data amount is larger than 2 million.\n    // PENDING Incremental data?\n    if (data.count() > 2e6) {\n        if (!this._incremental) {\n            this._incremental = new IncrementalDisplayble({\n                silent: true\n            });\n        }\n        this.group.add(this._incremental);\n    }\n    else {\n        this._incremental = null;\n    }\n};\n\nlargeSymbolProto.incrementalUpdate = function (taskParams, data) {\n    var symbolEl;\n    if (this._incremental) {\n        symbolEl = new LargeSymbolPath();\n        this._incremental.addDisplayable(symbolEl, true);\n    }\n    else {\n        symbolEl = new LargeSymbolPath({\n            rectHover: true,\n            cursor: 'default',\n            startIndex: taskParams.start,\n            endIndex: taskParams.end\n        });\n        symbolEl.incremental = true;\n        this.group.add(symbolEl);\n    }\n\n    symbolEl.setShape({\n        points: data.getLayout('symbolPoints')\n    });\n    this._setCommon(symbolEl, data, !!this._incremental);\n};\n\nlargeSymbolProto._setCommon = function (symbolEl, data, isIncremental) {\n    var hostModel = data.hostModel;\n\n    // TODO\n    // if (data.hasItemVisual.symbolSize) {\n    //     // TODO typed array?\n    //     symbolEl.setShape('sizes', data.mapArray(\n    //         function (idx) {\n    //             var size = data.getItemVisual(idx, 'symbolSize');\n    //             return (size instanceof Array) ? size : [size, size];\n    //         }\n    //     ));\n    // }\n    // else {\n    var size = data.getVisual('symbolSize');\n    symbolEl.setShape('size', (size instanceof Array) ? size : [size, size]);\n    // }\n\n    // Create symbolProxy to build path for each data\n    symbolEl.symbolProxy = createSymbol(\n        data.getVisual('symbol'), 0, 0, 0, 0\n    );\n    // Use symbolProxy setColor method\n    symbolEl.setColor = symbolEl.symbolProxy.setColor;\n\n    var extrudeShadow = symbolEl.shape.size[0] < BOOST_SIZE_THRESHOLD;\n    symbolEl.useStyle(\n        // Draw shadow when doing fillRect is extremely slow.\n        hostModel.getModel('itemStyle').getItemStyle(extrudeShadow ? ['color', 'shadowBlur', 'shadowColor'] : ['color'])\n    );\n\n    var visualColor = data.getVisual('color');\n    if (visualColor) {\n        symbolEl.setColor(visualColor);\n    }\n\n    if (!isIncremental) {\n        // Enable tooltip\n        // PENDING May have performance issue when path is extremely large\n        symbolEl.seriesIndex = hostModel.seriesIndex;\n        symbolEl.on('mousemove', function (e) {\n            symbolEl.dataIndex = null;\n            var dataIndex = symbolEl.findDataIndex(e.offsetX, e.offsetY);\n            if (dataIndex >= 0) {\n                // Provide dataIndex for tooltip\n                symbolEl.dataIndex = dataIndex + (symbolEl.startIndex || 0);\n            }\n        });\n    }\n};\n\nlargeSymbolProto.remove = function () {\n    this._clearIncremental();\n    this._incremental = null;\n    this.group.removeAll();\n};\n\nlargeSymbolProto._clearIncremental = function () {\n    var incremental = this._incremental;\n    if (incremental) {\n        incremental.clearDisplaybles();\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendChartView({\n\n    type: 'scatter',\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        var symbolDraw = this._updateSymbolDraw(data, seriesModel);\n        symbolDraw.updateData(data);\n\n        this._finished = true;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var symbolDraw = this._updateSymbolDraw(data, seriesModel);\n\n        symbolDraw.incrementalPrepareUpdate(data);\n\n        this._finished = false;\n    },\n\n    incrementalRender: function (taskParams, seriesModel, ecModel) {\n        this._symbolDraw.incrementalUpdate(taskParams, seriesModel.getData());\n\n        this._finished = taskParams.end === seriesModel.getData().count();\n    },\n\n    updateTransform: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        // Must mark group dirty and make sure the incremental layer will be cleared\n        // PENDING\n        this.group.dirty();\n\n        if (!this._finished || data.count() > 1e4 || !this._symbolDraw.isPersistent()) {\n            return {\n                update: true\n            };\n        }\n        else {\n            var res = pointsLayout().reset(seriesModel);\n            if (res.progress) {\n                res.progress({ start: 0, end: data.count() }, data);\n            }\n\n            this._symbolDraw.updateLayout(data);\n        }\n    },\n\n    _updateSymbolDraw: function (data, seriesModel) {\n        var symbolDraw = this._symbolDraw;\n        var pipelineContext = seriesModel.pipelineContext;\n        var isLargeDraw = pipelineContext.large;\n\n        if (!symbolDraw || isLargeDraw !== this._isLargeDraw) {\n            symbolDraw && symbolDraw.remove();\n            symbolDraw = this._symbolDraw = isLargeDraw\n                ? new LargeSymbolDraw()\n                : new SymbolDraw();\n            this._isLargeDraw = isLargeDraw;\n            this.group.removeAll();\n        }\n\n        this.group.add(symbolDraw.group);\n\n        return symbolDraw;\n    },\n\n    remove: function (ecModel, api) {\n        this._symbolDraw && this._symbolDraw.remove(true);\n        this._symbolDraw = null;\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import * as zrUtil from 'zrender/src/core/util';\n\n// In case developer forget to include grid component\nregisterVisual(visualSymbol('scatter', 'circle'));\nregisterLayout(pointsLayout('scatter'));\n\n// echarts.registerProcessor(function (ecModel, api) {\n//     ecModel.eachSeriesByType('scatter', function (seriesModel) {\n//         var data = seriesModel.getData();\n//         var coordSys = seriesModel.coordinateSystem;\n//         if (coordSys.type !== 'geo') {\n//             return;\n//         }\n//         var startPt = coordSys.pointToData([0, 0]);\n//         var endPt = coordSys.pointToData([api.getWidth(), api.getHeight()]);\n\n//         var dims = zrUtil.map(coordSys.dimensions, function (dim) {\n//             return data.mapDimension(dim);\n//         });\n//         var range = {};\n//         range[dims[0]] = [Math.min(startPt[0], endPt[0]), Math.max(startPt[0], endPt[0])];\n//         range[dims[1]] = [Math.min(startPt[1], endPt[1]), Math.max(startPt[1], endPt[1])];\n\n//         data.selectRange(range);\n//     });\n// });\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// -------------\n// Preprocessor\n// -------------\n\nregisterPreprocessor(function (option) {\n    var graphicOption = option.graphic;\n\n    // Convert\n    // {graphic: [{left: 10, type: 'circle'}, ...]}\n    // or\n    // {graphic: {left: 10, type: 'circle'}}\n    // to\n    // {graphic: [{elements: [{left: 10, type: 'circle'}, ...]}]}\n    if (isArray(graphicOption)) {\n        if (!graphicOption[0] || !graphicOption[0].elements) {\n            option.graphic = [{elements: graphicOption}];\n        }\n        else {\n            // Only one graphic instance can be instantiated. (We dont\n            // want that too many views are created in echarts._viewMap)\n            option.graphic = [option.graphic[0]];\n        }\n    }\n    else if (graphicOption && !graphicOption.elements) {\n        option.graphic = [{elements: [graphicOption]}];\n    }\n});\n\n// ------\n// Model\n// ------\n\nvar GraphicModel = extendComponentModel({\n\n    type: 'graphic',\n\n    defaultOption: {\n\n        // Extra properties for each elements:\n        //\n        // left/right/top/bottom: (like 12, '22%', 'center', default undefined)\n        //      If left/rigth is set, shape.x/shape.cx/position will not be used.\n        //      If top/bottom is set, shape.y/shape.cy/position will not be used.\n        //      This mechanism is useful when you want to position a group/element\n        //      against the right side or the center of this container.\n        //\n        // width/height: (can only be pixel value, default 0)\n        //      Only be used to specify contianer(group) size, if needed. And\n        //      can not be percentage value (like '33%'). See the reason in the\n        //      layout algorithm below.\n        //\n        // bounding: (enum: 'all' (default) | 'raw')\n        //      Specify how to calculate boundingRect when locating.\n        //      'all': Get uioned and transformed boundingRect\n        //          from both itself and its descendants.\n        //          This mode simplies confining a group of elements in the bounding\n        //          of their ancester container (e.g., using 'right: 0').\n        //      'raw': Only use the boundingRect of itself and before transformed.\n        //          This mode is similar to css behavior, which is useful when you\n        //          want an element to be able to overflow its container. (Consider\n        //          a rotated circle needs to be located in a corner.)\n        // info: custom info. enables user to mount some info on elements and use them\n        //      in event handlers. Update them only when user specified, otherwise, remain.\n\n        // Note: elements is always behind its ancestors in this elements array.\n        elements: [],\n        parentId: null\n    },\n\n    /**\n     * Save el options for the sake of the performance (only update modified graphics).\n     * The order is the same as those in option. (ancesters -> descendants)\n     *\n     * @private\n     * @type {Array.<Object>}\n     */\n    _elOptionsToUpdate: null,\n\n    /**\n     * @override\n     */\n    mergeOption: function (option) {\n        // Prevent default merge to elements\n        var elements = this.option.elements;\n        this.option.elements = null;\n\n        GraphicModel.superApply(this, 'mergeOption', arguments);\n\n        this.option.elements = elements;\n    },\n\n    /**\n     * @override\n     */\n    optionUpdated: function (newOption, isInit) {\n        var thisOption = this.option;\n        var newList = (isInit ? thisOption : newOption).elements;\n        var existList = thisOption.elements = isInit ? [] : thisOption.elements;\n\n        var flattenedList = [];\n        this._flatten(newList, flattenedList);\n\n        var mappingResult = mappingToExists(existList, flattenedList);\n        makeIdAndName(mappingResult);\n\n        // Clear elOptionsToUpdate\n        var elOptionsToUpdate = this._elOptionsToUpdate = [];\n\n        each$1(mappingResult, function (resultItem, index) {\n            var newElOption = resultItem.option;\n\n            if (__DEV__) {\n                assert$1(\n                    isObject$1(newElOption) || resultItem.exist,\n                    'Empty graphic option definition'\n                );\n            }\n\n            if (!newElOption) {\n                return;\n            }\n\n            elOptionsToUpdate.push(newElOption);\n\n            setKeyInfoToNewElOption(resultItem, newElOption);\n\n            mergeNewElOptionToExist(existList, index, newElOption);\n\n            setLayoutInfoToExist(existList[index], newElOption);\n\n        }, this);\n\n        // Clean\n        for (var i = existList.length - 1; i >= 0; i--) {\n            if (existList[i] == null) {\n                existList.splice(i, 1);\n            }\n            else {\n                // $action should be volatile, otherwise option gotten from\n                // `getOption` will contain unexpected $action.\n                delete existList[i].$action;\n            }\n        }\n    },\n\n    /**\n     * Convert\n     * [{\n     *  type: 'group',\n     *  id: 'xx',\n     *  children: [{type: 'circle'}, {type: 'polygon'}]\n     * }]\n     * to\n     * [\n     *  {type: 'group', id: 'xx'},\n     *  {type: 'circle', parentId: 'xx'},\n     *  {type: 'polygon', parentId: 'xx'}\n     * ]\n     *\n     * @private\n     * @param {Array.<Object>} optionList option list\n     * @param {Array.<Object>} result result of flatten\n     * @param {Object} parentOption parent option\n     */\n    _flatten: function (optionList, result, parentOption) {\n        each$1(optionList, function (option) {\n            if (!option) {\n                return;\n            }\n\n            if (parentOption) {\n                option.parentOption = parentOption;\n            }\n\n            result.push(option);\n\n            var children = option.children;\n            if (option.type === 'group' && children) {\n                this._flatten(children, result, option);\n            }\n            // Deleting for JSON output, and for not affecting group creation.\n            delete option.children;\n        }, this);\n    },\n\n    // FIXME\n    // Pass to view using payload? setOption has a payload?\n    useElOptionsToUpdate: function () {\n        var els = this._elOptionsToUpdate;\n        // Clear to avoid render duplicately when zooming.\n        this._elOptionsToUpdate = null;\n        return els;\n    }\n});\n\n// -----\n// View\n// -----\n\nextendComponentView({\n\n    type: 'graphic',\n\n    /**\n     * @override\n     */\n    init: function (ecModel, api) {\n\n        /**\n         * @private\n         * @type {module:zrender/core/util.HashMap}\n         */\n        this._elMap = createHashMap();\n\n        /**\n         * @private\n         * @type {module:echarts/graphic/GraphicModel}\n         */\n        this._lastGraphicModel;\n    },\n\n    /**\n     * @override\n     */\n    render: function (graphicModel, ecModel, api) {\n\n        // Having leveraged between use cases and algorithm complexity, a very\n        // simple layout mechanism is used:\n        // The size(width/height) can be determined by itself or its parent (not\n        // implemented yet), but can not by its children. (Top-down travel)\n        // The location(x/y) can be determined by the bounding rect of itself\n        // (can including its descendants or not) and the size of its parent.\n        // (Bottom-up travel)\n\n        // When `chart.clear()` or `chart.setOption({...}, true)` with the same id,\n        // view will be reused.\n        if (graphicModel !== this._lastGraphicModel) {\n            this._clear();\n        }\n        this._lastGraphicModel = graphicModel;\n\n        this._updateElements(graphicModel);\n        this._relocate(graphicModel, api);\n    },\n\n    /**\n     * Update graphic elements.\n     *\n     * @private\n     * @param {Object} graphicModel graphic model\n     */\n    _updateElements: function (graphicModel) {\n        var elOptionsToUpdate = graphicModel.useElOptionsToUpdate();\n\n        if (!elOptionsToUpdate) {\n            return;\n        }\n\n        var elMap = this._elMap;\n        var rootGroup = this.group;\n\n        // Top-down tranverse to assign graphic settings to each elements.\n        each$1(elOptionsToUpdate, function (elOption) {\n            var $action = elOption.$action;\n            var id = elOption.id;\n            var existEl = elMap.get(id);\n            var parentId = elOption.parentId;\n            var targetElParent = parentId != null ? elMap.get(parentId) : rootGroup;\n\n            var elOptionStyle = elOption.style;\n            if (elOption.type === 'text' && elOptionStyle) {\n                // In top/bottom mode, textVerticalAlign should not be used, which cause\n                // inaccurately locating.\n                if (elOption.hv && elOption.hv[1]) {\n                    elOptionStyle.textVerticalAlign = elOptionStyle.textBaseline = null;\n                }\n\n                // Compatible with previous setting: both support fill and textFill,\n                // stroke and textStroke.\n                !elOptionStyle.hasOwnProperty('textFill') && elOptionStyle.fill && (\n                    elOptionStyle.textFill = elOptionStyle.fill\n                );\n                !elOptionStyle.hasOwnProperty('textStroke') && elOptionStyle.stroke && (\n                    elOptionStyle.textStroke = elOptionStyle.stroke\n                );\n            }\n\n            // Remove unnecessary props to avoid potential problems.\n            var elOptionCleaned = getCleanedElOption(elOption);\n\n            // For simple, do not support parent change, otherwise reorder is needed.\n            if (__DEV__) {\n                existEl && assert$1(\n                    targetElParent === existEl.parent,\n                    'Changing parent is not supported.'\n                );\n            }\n\n            if (!$action || $action === 'merge') {\n                existEl\n                    ? existEl.attr(elOptionCleaned)\n                    : createEl(id, targetElParent, elOptionCleaned, elMap);\n            }\n            else if ($action === 'replace') {\n                removeEl(existEl, elMap);\n                createEl(id, targetElParent, elOptionCleaned, elMap);\n            }\n            else if ($action === 'remove') {\n                removeEl(existEl, elMap);\n            }\n\n            var el = elMap.get(id);\n            if (el) {\n                el.__ecGraphicWidth = elOption.width;\n                el.__ecGraphicHeight = elOption.height;\n                setEventData(el, graphicModel, elOption);\n            }\n        });\n    },\n\n    /**\n     * Locate graphic elements.\n     *\n     * @private\n     * @param {Object} graphicModel graphic model\n     * @param {module:echarts/ExtensionAPI} api extension API\n     */\n    _relocate: function (graphicModel, api) {\n        var elOptions = graphicModel.option.elements;\n        var rootGroup = this.group;\n        var elMap = this._elMap;\n\n        // Bottom-up tranvese all elements (consider ec resize) to locate elements.\n        for (var i = elOptions.length - 1; i >= 0; i--) {\n            var elOption = elOptions[i];\n            var el = elMap.get(elOption.id);\n\n            if (!el) {\n                continue;\n            }\n\n            var parentEl = el.parent;\n            var containerInfo = parentEl === rootGroup\n                ? {\n                    width: api.getWidth(),\n                    height: api.getHeight()\n                }\n                : { // Like 'position:absolut' in css, default 0.\n                    width: parentEl.__ecGraphicWidth || 0,\n                    height: parentEl.__ecGraphicHeight || 0\n                };\n\n            positionElement(\n                el, elOption, containerInfo, null,\n                {hv: elOption.hv, boundingMode: elOption.bounding}\n            );\n        }\n    },\n\n    /**\n     * Clear all elements.\n     *\n     * @private\n     */\n    _clear: function () {\n        var elMap = this._elMap;\n        elMap.each(function (el) {\n            removeEl(el, elMap);\n        });\n        this._elMap = createHashMap();\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._clear();\n    }\n});\n\nfunction createEl(id, targetElParent, elOption, elMap) {\n    var graphicType = elOption.type;\n\n    if (__DEV__) {\n        assert$1(graphicType, 'graphic type MUST be set');\n    }\n\n    var Clz = graphic[graphicType.charAt(0).toUpperCase() + graphicType.slice(1)];\n\n    if (__DEV__) {\n        assert$1(Clz, 'graphic type can not be found');\n    }\n\n    var el = new Clz(elOption);\n    targetElParent.add(el);\n    elMap.set(id, el);\n    el.__ecGraphicId = id;\n}\n\nfunction removeEl(existEl, elMap) {\n    var existElParent = existEl && existEl.parent;\n    if (existElParent) {\n        existEl.type === 'group' && existEl.traverse(function (el) {\n            removeEl(el, elMap);\n        });\n        elMap.removeKey(existEl.__ecGraphicId);\n        existElParent.remove(existEl);\n    }\n}\n\n// Remove unnecessary props to avoid potential problems.\nfunction getCleanedElOption(elOption) {\n    elOption = extend({}, elOption);\n    each$1(\n        ['id', 'parentId', '$action', 'hv', 'bounding'].concat(LOCATION_PARAMS),\n        function (name) {\n            delete elOption[name];\n        }\n    );\n    return elOption;\n}\n\nfunction isSetLoc(obj, props) {\n    var isSet;\n    each$1(props, function (prop) {\n        obj[prop] != null && obj[prop] !== 'auto' && (isSet = true);\n    });\n    return isSet;\n}\n\nfunction setKeyInfoToNewElOption(resultItem, newElOption) {\n    var existElOption = resultItem.exist;\n\n    // Set id and type after id assigned.\n    newElOption.id = resultItem.keyInfo.id;\n    !newElOption.type && existElOption && (newElOption.type = existElOption.type);\n\n    // Set parent id if not specified\n    if (newElOption.parentId == null) {\n        var newElParentOption = newElOption.parentOption;\n        if (newElParentOption) {\n            newElOption.parentId = newElParentOption.id;\n        }\n        else if (existElOption) {\n            newElOption.parentId = existElOption.parentId;\n        }\n    }\n\n    // Clear\n    newElOption.parentOption = null;\n}\n\nfunction mergeNewElOptionToExist(existList, index, newElOption) {\n    // Update existing options, for `getOption` feature.\n    var newElOptCopy = extend({}, newElOption);\n    var existElOption = existList[index];\n\n    var $action = newElOption.$action || 'merge';\n    if ($action === 'merge') {\n        if (existElOption) {\n\n            if (__DEV__) {\n                var newType = newElOption.type;\n                assert$1(\n                    !newType || existElOption.type === newType,\n                    'Please set $action: \"replace\" to change `type`'\n                );\n            }\n\n            // We can ensure that newElOptCopy and existElOption are not\n            // the same object, so `merge` will not change newElOptCopy.\n            merge(existElOption, newElOptCopy, true);\n            // Rigid body, use ignoreSize.\n            mergeLayoutParam(existElOption, newElOptCopy, {ignoreSize: true});\n            // Will be used in render.\n            copyLayoutParams(newElOption, existElOption);\n        }\n        else {\n            existList[index] = newElOptCopy;\n        }\n    }\n    else if ($action === 'replace') {\n        existList[index] = newElOptCopy;\n    }\n    else if ($action === 'remove') {\n        // null will be cleaned later.\n        existElOption && (existList[index] = null);\n    }\n}\n\nfunction setLayoutInfoToExist(existItem, newElOption) {\n    if (!existItem) {\n        return;\n    }\n    existItem.hv = newElOption.hv = [\n        // Rigid body, dont care `width`.\n        isSetLoc(newElOption, ['left', 'right']),\n        // Rigid body, dont care `height`.\n        isSetLoc(newElOption, ['top', 'bottom'])\n    ];\n    // Give default group size. Otherwise layout error may occur.\n    if (existItem.type === 'group') {\n        existItem.width == null && (existItem.width = newElOption.width = 0);\n        existItem.height == null && (existItem.height = newElOption.height = 0);\n    }\n}\n\nfunction setEventData(el, graphicModel, elOption) {\n    var eventData = el.eventData;\n    // Simple optimize for large amount of elements that no need event.\n    if (!el.silent && !el.ignore && !eventData) {\n        eventData = el.eventData = {\n            componentType: 'graphic',\n            componentIndex: graphicModel.componentIndex,\n            name: el.name\n        };\n    }\n\n    // `elOption.info` enables user to mount some info on\n    // elements and use them in event handlers.\n    if (eventData) {\n        eventData.info = el.info;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} finder contains {seriesIndex, dataIndex, dataIndexInside}\n * @param {module:echarts/model/Global} ecModel\n * @return {Object} {point: [x, y], el: ...} point Will not be null.\n */\nvar findPointFromSeries = function (finder, ecModel) {\n    var point = [];\n    var seriesIndex = finder.seriesIndex;\n    var seriesModel;\n    if (seriesIndex == null || !(\n        seriesModel = ecModel.getSeriesByIndex(seriesIndex)\n    )) {\n        return {point: []};\n    }\n\n    var data = seriesModel.getData();\n    var dataIndex = queryDataIndex(data, finder);\n    if (dataIndex == null || dataIndex < 0 || isArray(dataIndex)) {\n        return {point: []};\n    }\n\n    var el = data.getItemGraphicEl(dataIndex);\n    var coordSys = seriesModel.coordinateSystem;\n\n    if (seriesModel.getTooltipPosition) {\n        point = seriesModel.getTooltipPosition(dataIndex) || [];\n    }\n    else if (coordSys && coordSys.dataToPoint) {\n        point = coordSys.dataToPoint(\n            data.getValues(\n                map(coordSys.dimensions, function (dim) {\n                    return data.mapDimension(dim);\n                }), dataIndex, true\n            )\n        ) || [];\n    }\n    else if (el) {\n        // Use graphic bounding rect\n        var rect = el.getBoundingRect().clone();\n        rect.applyTransform(el.transform);\n        point = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    }\n\n    return {point: point, el: el};\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$7 = each$1;\nvar curry$2 = curry;\nvar inner$7 = makeInner();\n\n/**\n * Basic logic: check all axis, if they do not demand show/highlight,\n * then hide/downplay them.\n *\n * @param {Object} coordSysAxesInfo\n * @param {Object} payload\n * @param {string} [payload.currTrigger] 'click' | 'mousemove' | 'leave'\n * @param {Array.<number>} [payload.x] x and y, which are mandatory, specify a point to\n *              trigger axisPointer and tooltip.\n * @param {Array.<number>} [payload.y] x and y, which are mandatory, specify a point to\n *              trigger axisPointer and tooltip.\n * @param {Object} [payload.seriesIndex] finder, optional, restrict target axes.\n * @param {Object} [payload.dataIndex] finder, restrict target axes.\n * @param {Object} [payload.axesInfo] finder, restrict target axes.\n *        [{\n *          axisDim: 'x'|'y'|'angle'|...,\n *          axisIndex: ...,\n *          value: ...\n *        }, ...]\n * @param {Function} [payload.dispatchAction]\n * @param {Object} [payload.tooltipOption]\n * @param {Object|Array.<number>|Function} [payload.position] Tooltip position,\n *        which can be specified in dispatchAction\n * @param {module:echarts/model/Global} ecModel\n * @param {module:echarts/ExtensionAPI} api\n * @return {Object} content of event obj for echarts.connect.\n */\nvar axisTrigger = function (payload, ecModel, api) {\n    var currTrigger = payload.currTrigger;\n    var point = [payload.x, payload.y];\n    var finder = payload;\n    var dispatchAction = payload.dispatchAction || bind(api.dispatchAction, api);\n    var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo;\n\n    // Pending\n    // See #6121. But we are not able to reproduce it yet.\n    if (!coordSysAxesInfo) {\n        return;\n    }\n\n    if (illegalPoint(point)) {\n        // Used in the default behavior of `connection`: use the sample seriesIndex\n        // and dataIndex. And also used in the tooltipView trigger.\n        point = findPointFromSeries({\n            seriesIndex: finder.seriesIndex,\n            // Do not use dataIndexInside from other ec instance.\n            // FIXME: auto detect it?\n            dataIndex: finder.dataIndex\n        }, ecModel).point;\n    }\n    var isIllegalPoint = illegalPoint(point);\n\n    // Axis and value can be specified when calling dispatchAction({type: 'updateAxisPointer'}).\n    // Notice: In this case, it is difficult to get the `point` (which is necessary to show\n    // tooltip, so if point is not given, we just use the point found by sample seriesIndex\n    // and dataIndex.\n    var inputAxesInfo = finder.axesInfo;\n\n    var axesInfo = coordSysAxesInfo.axesInfo;\n    var shouldHide = currTrigger === 'leave' || illegalPoint(point);\n    var outputFinder = {};\n\n    var showValueMap = {};\n    var dataByCoordSys = {list: [], map: {}};\n    var updaters = {\n        showPointer: curry$2(showPointer, showValueMap),\n        showTooltip: curry$2(showTooltip, dataByCoordSys)\n    };\n\n    // Process for triggered axes.\n    each$7(coordSysAxesInfo.coordSysMap, function (coordSys, coordSysKey) {\n        // If a point given, it must be contained by the coordinate system.\n        var coordSysContainsPoint = isIllegalPoint || coordSys.containPoint(point);\n\n        each$7(coordSysAxesInfo.coordSysAxesInfo[coordSysKey], function (axisInfo, key) {\n            var axis = axisInfo.axis;\n            var inputAxisInfo = findInputAxisInfo(inputAxesInfo, axisInfo);\n            // If no inputAxesInfo, no axis is restricted.\n            if (!shouldHide && coordSysContainsPoint && (!inputAxesInfo || inputAxisInfo)) {\n                var val = inputAxisInfo && inputAxisInfo.value;\n                if (val == null && !isIllegalPoint) {\n                    val = axis.pointToData(point);\n                }\n                val != null && processOnAxis(axisInfo, val, updaters, false, outputFinder);\n            }\n        });\n    });\n\n    // Process for linked axes.\n    var linkTriggers = {};\n    each$7(axesInfo, function (tarAxisInfo, tarKey) {\n        var linkGroup = tarAxisInfo.linkGroup;\n\n        // If axis has been triggered in the previous stage, it should not be triggered by link.\n        if (linkGroup && !showValueMap[tarKey]) {\n            each$7(linkGroup.axesInfo, function (srcAxisInfo, srcKey) {\n                var srcValItem = showValueMap[srcKey];\n                // If srcValItem exist, source axis is triggered, so link to target axis.\n                if (srcAxisInfo !== tarAxisInfo && srcValItem) {\n                    var val = srcValItem.value;\n                    linkGroup.mapper && (val = tarAxisInfo.axis.scale.parse(linkGroup.mapper(\n                        val, makeMapperParam(srcAxisInfo), makeMapperParam(tarAxisInfo)\n                    )));\n                    linkTriggers[tarAxisInfo.key] = val;\n                }\n            });\n        }\n    });\n    each$7(linkTriggers, function (val, tarKey) {\n        processOnAxis(axesInfo[tarKey], val, updaters, true, outputFinder);\n    });\n\n    updateModelActually(showValueMap, axesInfo, outputFinder);\n    dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction);\n    dispatchHighDownActually(axesInfo, dispatchAction, api);\n\n    return outputFinder;\n};\n\nfunction processOnAxis(axisInfo, newValue, updaters, dontSnap, outputFinder) {\n    var axis = axisInfo.axis;\n\n    if (axis.scale.isBlank() || !axis.containData(newValue)) {\n        return;\n    }\n\n    if (!axisInfo.involveSeries) {\n        updaters.showPointer(axisInfo, newValue);\n        return;\n    }\n\n    // Heavy calculation. So put it after axis.containData checking.\n    var payloadInfo = buildPayloadsBySeries(newValue, axisInfo);\n    var payloadBatch = payloadInfo.payloadBatch;\n    var snapToValue = payloadInfo.snapToValue;\n\n    // Fill content of event obj for echarts.connect.\n    // By defualt use the first involved series data as a sample to connect.\n    if (payloadBatch[0] && outputFinder.seriesIndex == null) {\n        extend(outputFinder, payloadBatch[0]);\n    }\n\n    // If no linkSource input, this process is for collecting link\n    // target, where snap should not be accepted.\n    if (!dontSnap && axisInfo.snap) {\n        if (axis.containData(snapToValue) && snapToValue != null) {\n            newValue = snapToValue;\n        }\n    }\n\n    updaters.showPointer(axisInfo, newValue, payloadBatch, outputFinder);\n    // Tooltip should always be snapToValue, otherwise there will be\n    // incorrect \"axis value ~ series value\" mapping displayed in tooltip.\n    updaters.showTooltip(axisInfo, payloadInfo, snapToValue);\n}\n\nfunction buildPayloadsBySeries(value, axisInfo) {\n    var axis = axisInfo.axis;\n    var dim = axis.dim;\n    var snapToValue = value;\n    var payloadBatch = [];\n    var minDist = Number.MAX_VALUE;\n    var minDiff = -1;\n\n    each$7(axisInfo.seriesModels, function (series, idx) {\n        var dataDim = series.getData().mapDimension(dim, true);\n        var seriesNestestValue;\n        var dataIndices;\n\n        if (series.getAxisTooltipData) {\n            var result = series.getAxisTooltipData(dataDim, value, axis);\n            dataIndices = result.dataIndices;\n            seriesNestestValue = result.nestestValue;\n        }\n        else {\n            dataIndices = series.getData().indicesOfNearest(\n                dataDim[0],\n                value,\n                // Add a threshold to avoid find the wrong dataIndex\n                // when data length is not same.\n                // false,\n                axis.type === 'category' ? 0.5 : null\n            );\n            if (!dataIndices.length) {\n                return;\n            }\n            seriesNestestValue = series.getData().get(dataDim[0], dataIndices[0]);\n        }\n\n        if (seriesNestestValue == null || !isFinite(seriesNestestValue)) {\n            return;\n        }\n\n        var diff = value - seriesNestestValue;\n        var dist = Math.abs(diff);\n        // Consider category case\n        if (dist <= minDist) {\n            if (dist < minDist || (diff >= 0 && minDiff < 0)) {\n                minDist = dist;\n                minDiff = diff;\n                snapToValue = seriesNestestValue;\n                payloadBatch.length = 0;\n            }\n            each$7(dataIndices, function (dataIndex) {\n                payloadBatch.push({\n                    seriesIndex: series.seriesIndex,\n                    dataIndexInside: dataIndex,\n                    dataIndex: series.getData().getRawIndex(dataIndex)\n                });\n            });\n        }\n    });\n\n    return {\n        payloadBatch: payloadBatch,\n        snapToValue: snapToValue\n    };\n}\n\nfunction showPointer(showValueMap, axisInfo, value, payloadBatch) {\n    showValueMap[axisInfo.key] = {value: value, payloadBatch: payloadBatch};\n}\n\nfunction showTooltip(dataByCoordSys, axisInfo, payloadInfo, value) {\n    var payloadBatch = payloadInfo.payloadBatch;\n    var axis = axisInfo.axis;\n    var axisModel = axis.model;\n    var axisPointerModel = axisInfo.axisPointerModel;\n\n    // If no data, do not create anything in dataByCoordSys,\n    // whose length will be used to judge whether dispatch action.\n    if (!axisInfo.triggerTooltip || !payloadBatch.length) {\n        return;\n    }\n\n    var coordSysModel = axisInfo.coordSys.model;\n    var coordSysKey = makeKey(coordSysModel);\n    var coordSysItem = dataByCoordSys.map[coordSysKey];\n    if (!coordSysItem) {\n        coordSysItem = dataByCoordSys.map[coordSysKey] = {\n            coordSysId: coordSysModel.id,\n            coordSysIndex: coordSysModel.componentIndex,\n            coordSysType: coordSysModel.type,\n            coordSysMainType: coordSysModel.mainType,\n            dataByAxis: []\n        };\n        dataByCoordSys.list.push(coordSysItem);\n    }\n\n    coordSysItem.dataByAxis.push({\n        axisDim: axis.dim,\n        axisIndex: axisModel.componentIndex,\n        axisType: axisModel.type,\n        axisId: axisModel.id,\n        value: value,\n        // Caustion: viewHelper.getValueLabel is actually on \"view stage\", which\n        // depends that all models have been updated. So it should not be performed\n        // here. Considering axisPointerModel used here is volatile, which is hard\n        // to be retrieve in TooltipView, we prepare parameters here.\n        valueLabelOpt: {\n            precision: axisPointerModel.get('label.precision'),\n            formatter: axisPointerModel.get('label.formatter')\n        },\n        seriesDataIndices: payloadBatch.slice()\n    });\n}\n\nfunction updateModelActually(showValueMap, axesInfo, outputFinder) {\n    var outputAxesInfo = outputFinder.axesInfo = [];\n    // Basic logic: If no 'show' required, 'hide' this axisPointer.\n    each$7(axesInfo, function (axisInfo, key) {\n        var option = axisInfo.axisPointerModel.option;\n        var valItem = showValueMap[key];\n\n        if (valItem) {\n            !axisInfo.useHandle && (option.status = 'show');\n            option.value = valItem.value;\n            // For label formatter param and highlight.\n            option.seriesDataIndices = (valItem.payloadBatch || []).slice();\n        }\n        // When always show (e.g., handle used), remain\n        // original value and status.\n        else {\n            // If hide, value still need to be set, consider\n            // click legend to toggle axis blank.\n            !axisInfo.useHandle && (option.status = 'hide');\n        }\n\n        // If status is 'hide', should be no info in payload.\n        option.status === 'show' && outputAxesInfo.push({\n            axisDim: axisInfo.axis.dim,\n            axisIndex: axisInfo.axis.model.componentIndex,\n            value: option.value\n        });\n    });\n}\n\nfunction dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction) {\n    // Basic logic: If no showTip required, hideTip will be dispatched.\n    if (illegalPoint(point) || !dataByCoordSys.list.length) {\n        dispatchAction({type: 'hideTip'});\n        return;\n    }\n\n    // In most case only one axis (or event one series is used). It is\n    // convinient to fetch payload.seriesIndex and payload.dataIndex\n    // dirtectly. So put the first seriesIndex and dataIndex of the first\n    // axis on the payload.\n    var sampleItem = ((dataByCoordSys.list[0].dataByAxis[0] || {}).seriesDataIndices || [])[0] || {};\n\n    dispatchAction({\n        type: 'showTip',\n        escapeConnect: true,\n        x: point[0],\n        y: point[1],\n        tooltipOption: payload.tooltipOption,\n        position: payload.position,\n        dataIndexInside: sampleItem.dataIndexInside,\n        dataIndex: sampleItem.dataIndex,\n        seriesIndex: sampleItem.seriesIndex,\n        dataByCoordSys: dataByCoordSys.list\n    });\n}\n\nfunction dispatchHighDownActually(axesInfo, dispatchAction, api) {\n    // FIXME\n    // highlight status modification shoule be a stage of main process?\n    // (Consider confilct (e.g., legend and axisPointer) and setOption)\n\n    var zr = api.getZr();\n    var highDownKey = 'axisPointerLastHighlights';\n    var lastHighlights = inner$7(zr)[highDownKey] || {};\n    var newHighlights = inner$7(zr)[highDownKey] = {};\n\n    // Update highlight/downplay status according to axisPointer model.\n    // Build hash map and remove duplicate incidentally.\n    each$7(axesInfo, function (axisInfo, key) {\n        var option = axisInfo.axisPointerModel.option;\n        option.status === 'show' && each$7(option.seriesDataIndices, function (batchItem) {\n            var key = batchItem.seriesIndex + ' | ' + batchItem.dataIndex;\n            newHighlights[key] = batchItem;\n        });\n    });\n\n    // Diff.\n    var toHighlight = [];\n    var toDownplay = [];\n    each$1(lastHighlights, function (batchItem, key) {\n        !newHighlights[key] && toDownplay.push(batchItem);\n    });\n    each$1(newHighlights, function (batchItem, key) {\n        !lastHighlights[key] && toHighlight.push(batchItem);\n    });\n\n    toDownplay.length && api.dispatchAction({\n        type: 'downplay', escapeConnect: true, batch: toDownplay\n    });\n    toHighlight.length && api.dispatchAction({\n        type: 'highlight', escapeConnect: true, batch: toHighlight\n    });\n}\n\nfunction findInputAxisInfo(inputAxesInfo, axisInfo) {\n    for (var i = 0; i < (inputAxesInfo || []).length; i++) {\n        var inputAxisInfo = inputAxesInfo[i];\n        if (axisInfo.axis.dim === inputAxisInfo.axisDim\n            && axisInfo.axis.model.componentIndex === inputAxisInfo.axisIndex\n        ) {\n            return inputAxisInfo;\n        }\n    }\n}\n\nfunction makeMapperParam(axisInfo) {\n    var axisModel = axisInfo.axis.model;\n    var item = {};\n    var dim = item.axisDim = axisInfo.axis.dim;\n    item.axisIndex = item[dim + 'AxisIndex'] = axisModel.componentIndex;\n    item.axisName = item[dim + 'AxisName'] = axisModel.name;\n    item.axisId = item[dim + 'AxisId'] = axisModel.id;\n    return item;\n}\n\nfunction illegalPoint(point) {\n    return !point || point[0] == null || isNaN(point[0]) || point[1] == null || isNaN(point[1]);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisPointerModel = extendComponentModel({\n\n    type: 'axisPointer',\n\n    coordSysAxesInfo: null,\n\n    defaultOption: {\n        // 'auto' means that show when triggered by tooltip or handle.\n        show: 'auto',\n        // 'click' | 'mousemove' | 'none'\n        triggerOn: null, // set default in AxisPonterView.js\n\n        zlevel: 0,\n        z: 50,\n\n        type: 'line', // 'line' 'shadow' 'cross' 'none'.\n        // axispointer triggered by tootip determine snap automatically,\n        // see `modelHelper`.\n        snap: false,\n        triggerTooltip: true,\n\n        value: null,\n        status: null, // Init value depends on whether handle is used.\n\n        // [group0, group1, ...]\n        // Each group can be: {\n        //      mapper: function () {},\n        //      singleTooltip: 'multiple',  // 'multiple' or 'single'\n        //      xAxisId: ...,\n        //      yAxisName: ...,\n        //      angleAxisIndex: ...\n        // }\n        // mapper: can be ignored.\n        //      input: {axisInfo, value}\n        //      output: {axisInfo, value}\n        link: [],\n\n        // Do not set 'auto' here, otherwise global animation: false\n        // will not effect at this axispointer.\n        animation: null,\n        animationDurationUpdate: 200,\n\n        lineStyle: {\n            color: '#aaa',\n            width: 1,\n            type: 'solid'\n        },\n\n        shadowStyle: {\n            color: 'rgba(150,150,150,0.3)'\n        },\n\n        label: {\n            show: true,\n            formatter: null, // string | Function\n            precision: 'auto', // Or a number like 0, 1, 2 ...\n            margin: 3,\n            color: '#fff',\n            padding: [5, 7, 5, 7],\n            backgroundColor: 'auto', // default: axis line color\n            borderColor: null,\n            borderWidth: 0,\n            shadowBlur: 3,\n            shadowColor: '#aaa'\n            // Considering applicability, common style should\n            // better not have shadowOffset.\n            // shadowOffsetX: 0,\n            // shadowOffsetY: 2\n        },\n\n        handle: {\n            show: false,\n            /* eslint-disable */\n            icon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z', // jshint ignore:line\n            /* eslint-enable */\n            size: 45,\n            // handle margin is from symbol center to axis, which is stable when circular move.\n            margin: 50,\n            // color: '#1b8bbd'\n            // color: '#2f4554'\n            color: '#333',\n            shadowBlur: 3,\n            shadowColor: '#aaa',\n            shadowOffsetX: 0,\n            shadowOffsetY: 2,\n\n            // For mobile performance\n            throttle: 40\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$8 = makeInner();\nvar each$8 = each$1;\n\n/**\n * @param {string} key\n * @param {module:echarts/ExtensionAPI} api\n * @param {Function} handler\n *      param: {string} currTrigger\n *      param: {Array.<number>} point\n */\nfunction register(key, api, handler) {\n    if (env$1.node) {\n        return;\n    }\n\n    var zr = api.getZr();\n    inner$8(zr).records || (inner$8(zr).records = {});\n\n    initGlobalListeners(zr, api);\n\n    var record = inner$8(zr).records[key] || (inner$8(zr).records[key] = {});\n    record.handler = handler;\n}\n\nfunction initGlobalListeners(zr, api) {\n    if (inner$8(zr).initialized) {\n        return;\n    }\n\n    inner$8(zr).initialized = true;\n\n    useHandler('click', curry(doEnter, 'click'));\n    useHandler('mousemove', curry(doEnter, 'mousemove'));\n    // useHandler('mouseout', onLeave);\n    useHandler('globalout', onLeave);\n\n    function useHandler(eventType, cb) {\n        zr.on(eventType, function (e) {\n            var dis = makeDispatchAction(api);\n\n            each$8(inner$8(zr).records, function (record) {\n                record && cb(record, e, dis.dispatchAction);\n            });\n\n            dispatchTooltipFinally(dis.pendings, api);\n        });\n    }\n}\n\nfunction dispatchTooltipFinally(pendings, api) {\n    var showLen = pendings.showTip.length;\n    var hideLen = pendings.hideTip.length;\n\n    var actuallyPayload;\n    if (showLen) {\n        actuallyPayload = pendings.showTip[showLen - 1];\n    }\n    else if (hideLen) {\n        actuallyPayload = pendings.hideTip[hideLen - 1];\n    }\n    if (actuallyPayload) {\n        actuallyPayload.dispatchAction = null;\n        api.dispatchAction(actuallyPayload);\n    }\n}\n\nfunction onLeave(record, e, dispatchAction) {\n    record.handler('leave', null, dispatchAction);\n}\n\nfunction doEnter(currTrigger, record, e, dispatchAction) {\n    record.handler(currTrigger, e, dispatchAction);\n}\n\nfunction makeDispatchAction(api) {\n    var pendings = {\n        showTip: [],\n        hideTip: []\n    };\n    // FIXME\n    // better approach?\n    // 'showTip' and 'hideTip' can be triggered by axisPointer and tooltip,\n    // which may be conflict, (axisPointer call showTip but tooltip call hideTip);\n    // So we have to add \"final stage\" to merge those dispatched actions.\n    var dispatchAction = function (payload) {\n        var pendingList = pendings[payload.type];\n        if (pendingList) {\n            pendingList.push(payload);\n        }\n        else {\n            payload.dispatchAction = dispatchAction;\n            api.dispatchAction(payload);\n        }\n    };\n\n    return {\n        dispatchAction: dispatchAction,\n        pendings: pendings\n    };\n}\n\n/**\n * @param {string} key\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction unregister(key, api) {\n    if (env$1.node) {\n        return;\n    }\n    var zr = api.getZr();\n    var record = (inner$8(zr).records || {})[key];\n    if (record) {\n        inner$8(zr).records[key] = null;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisPointerView = extendComponentView({\n\n    type: 'axisPointer',\n\n    render: function (globalAxisPointerModel, ecModel, api) {\n        var globalTooltipModel = ecModel.getComponent('tooltip');\n        var triggerOn = globalAxisPointerModel.get('triggerOn')\n            || (globalTooltipModel && globalTooltipModel.get('triggerOn') || 'mousemove|click');\n\n        // Register global listener in AxisPointerView to enable\n        // AxisPointerView to be independent to Tooltip.\n        register(\n            'axisPointer',\n            api,\n            function (currTrigger, e, dispatchAction) {\n                // If 'none', it is not controlled by mouse totally.\n                if (triggerOn !== 'none'\n                    && (currTrigger === 'leave' || triggerOn.indexOf(currTrigger) >= 0)\n                ) {\n                    dispatchAction({\n                        type: 'updateAxisPointer',\n                        currTrigger: currTrigger,\n                        x: e && e.offsetX,\n                        y: e && e.offsetY\n                    });\n                }\n            }\n        );\n    },\n\n    /**\n     * @override\n     */\n    remove: function (ecModel, api) {\n        unregister(api.getZr(), 'axisPointer');\n        AxisPointerView.superApply(this._model, 'remove', arguments);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function (ecModel, api) {\n        unregister('axisPointer', api);\n        AxisPointerView.superApply(this._model, 'dispose', arguments);\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$9 = makeInner();\nvar clone$4 = clone;\nvar bind$1 = bind;\n\n/**\n * Base axis pointer class in 2D.\n * Implemenents {module:echarts/component/axis/IAxisPointer}.\n */\nfunction BaseAxisPointer() {\n}\n\nBaseAxisPointer.prototype = {\n\n    /**\n     * @private\n     */\n    _group: null,\n\n    /**\n     * @private\n     */\n    _lastGraphicKey: null,\n\n    /**\n     * @private\n     */\n    _handle: null,\n\n    /**\n     * @private\n     */\n    _dragging: false,\n\n    /**\n     * @private\n     */\n    _lastValue: null,\n\n    /**\n     * @private\n     */\n    _lastStatus: null,\n\n    /**\n     * @private\n     */\n    _payloadInfo: null,\n\n    /**\n     * In px, arbitrary value. Do not set too small,\n     * no animation is ok for most cases.\n     * @protected\n     */\n    animationThreshold: 15,\n\n    /**\n     * @implement\n     */\n    render: function (axisModel, axisPointerModel, api, forceRender) {\n        var value = axisPointerModel.get('value');\n        var status = axisPointerModel.get('status');\n\n        // Bind them to `this`, not in closure, otherwise they will not\n        // be replaced when user calling setOption in not merge mode.\n        this._axisModel = axisModel;\n        this._axisPointerModel = axisPointerModel;\n        this._api = api;\n\n        // Optimize: `render` will be called repeatly during mouse move.\n        // So it is power consuming if performing `render` each time,\n        // especially on mobile device.\n        if (!forceRender\n            && this._lastValue === value\n            && this._lastStatus === status\n        ) {\n            return;\n        }\n        this._lastValue = value;\n        this._lastStatus = status;\n\n        var group = this._group;\n        var handle = this._handle;\n\n        if (!status || status === 'hide') {\n            // Do not clear here, for animation better.\n            group && group.hide();\n            handle && handle.hide();\n            return;\n        }\n        group && group.show();\n        handle && handle.show();\n\n        // Otherwise status is 'show'\n        var elOption = {};\n        this.makeElOption(elOption, value, axisModel, axisPointerModel, api);\n\n        // Enable change axis pointer type.\n        var graphicKey = elOption.graphicKey;\n        if (graphicKey !== this._lastGraphicKey) {\n            this.clear(api);\n        }\n        this._lastGraphicKey = graphicKey;\n\n        var moveAnimation = this._moveAnimation\n            = this.determineAnimation(axisModel, axisPointerModel);\n\n        if (!group) {\n            group = this._group = new Group();\n            this.createPointerEl(group, elOption, axisModel, axisPointerModel);\n            this.createLabelEl(group, elOption, axisModel, axisPointerModel);\n            api.getZr().add(group);\n        }\n        else {\n            var doUpdateProps = curry(updateProps$1, axisPointerModel, moveAnimation);\n            this.updatePointerEl(group, elOption, doUpdateProps, axisPointerModel);\n            this.updateLabelEl(group, elOption, doUpdateProps, axisPointerModel);\n        }\n\n        updateMandatoryProps(group, axisPointerModel, true);\n\n        this._renderHandle(value);\n    },\n\n    /**\n     * @implement\n     */\n    remove: function (api) {\n        this.clear(api);\n    },\n\n    /**\n     * @implement\n     */\n    dispose: function (api) {\n        this.clear(api);\n    },\n\n    /**\n     * @protected\n     */\n    determineAnimation: function (axisModel, axisPointerModel) {\n        var animation = axisPointerModel.get('animation');\n        var axis = axisModel.axis;\n        var isCategoryAxis = axis.type === 'category';\n        var useSnap = axisPointerModel.get('snap');\n\n        // Value axis without snap always do not snap.\n        if (!useSnap && !isCategoryAxis) {\n            return false;\n        }\n\n        if (animation === 'auto' || animation == null) {\n            var animationThreshold = this.animationThreshold;\n            if (isCategoryAxis && axis.getBandWidth() > animationThreshold) {\n                return true;\n            }\n\n            // It is important to auto animation when snap used. Consider if there is\n            // a dataZoom, animation will be disabled when too many points exist, while\n            // it will be enabled for better visual effect when little points exist.\n            if (useSnap) {\n                var seriesDataCount = getAxisInfo(axisModel).seriesDataCount;\n                var axisExtent = axis.getExtent();\n                // Approximate band width\n                return Math.abs(axisExtent[0] - axisExtent[1]) / seriesDataCount > animationThreshold;\n            }\n\n            return false;\n        }\n\n        return animation === true;\n    },\n\n    /**\n     * add {pointer, label, graphicKey} to elOption\n     * @protected\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        // Shoule be implemenented by sub-class.\n    },\n\n    /**\n     * @protected\n     */\n    createPointerEl: function (group, elOption, axisModel, axisPointerModel) {\n        var pointerOption = elOption.pointer;\n        if (pointerOption) {\n            var pointerEl = inner$9(group).pointerEl = new graphic[pointerOption.type](\n                clone$4(elOption.pointer)\n            );\n            group.add(pointerEl);\n        }\n    },\n\n    /**\n     * @protected\n     */\n    createLabelEl: function (group, elOption, axisModel, axisPointerModel) {\n        if (elOption.label) {\n            var labelEl = inner$9(group).labelEl = new Rect(\n                clone$4(elOption.label)\n            );\n\n            group.add(labelEl);\n            updateLabelShowHide(labelEl, axisPointerModel);\n        }\n    },\n\n    /**\n     * @protected\n     */\n    updatePointerEl: function (group, elOption, updateProps$$1) {\n        var pointerEl = inner$9(group).pointerEl;\n        if (pointerEl) {\n            pointerEl.setStyle(elOption.pointer.style);\n            updateProps$$1(pointerEl, {shape: elOption.pointer.shape});\n        }\n    },\n\n    /**\n     * @protected\n     */\n    updateLabelEl: function (group, elOption, updateProps$$1, axisPointerModel) {\n        var labelEl = inner$9(group).labelEl;\n        if (labelEl) {\n            labelEl.setStyle(elOption.label.style);\n            updateProps$$1(labelEl, {\n                // Consider text length change in vertical axis, animation should\n                // be used on shape, otherwise the effect will be weird.\n                shape: elOption.label.shape,\n                position: elOption.label.position\n            });\n\n            updateLabelShowHide(labelEl, axisPointerModel);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _renderHandle: function (value) {\n        if (this._dragging || !this.updateHandleTransform) {\n            return;\n        }\n\n        var axisPointerModel = this._axisPointerModel;\n        var zr = this._api.getZr();\n        var handle = this._handle;\n        var handleModel = axisPointerModel.getModel('handle');\n\n        var status = axisPointerModel.get('status');\n        if (!handleModel.get('show') || !status || status === 'hide') {\n            handle && zr.remove(handle);\n            this._handle = null;\n            return;\n        }\n\n        var isInit;\n        if (!this._handle) {\n            isInit = true;\n            handle = this._handle = createIcon(\n                handleModel.get('icon'),\n                {\n                    cursor: 'move',\n                    draggable: true,\n                    onmousemove: function (e) {\n                        // Fot mobile devicem, prevent screen slider on the button.\n                        stop(e.event);\n                    },\n                    onmousedown: bind$1(this._onHandleDragMove, this, 0, 0),\n                    drift: bind$1(this._onHandleDragMove, this),\n                    ondragend: bind$1(this._onHandleDragEnd, this)\n                }\n            );\n            zr.add(handle);\n        }\n\n        updateMandatoryProps(handle, axisPointerModel, false);\n\n        // update style\n        var includeStyles = [\n            'color', 'borderColor', 'borderWidth', 'opacity',\n            'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'\n        ];\n        handle.setStyle(handleModel.getItemStyle(null, includeStyles));\n\n        // update position\n        var handleSize = handleModel.get('size');\n        if (!isArray(handleSize)) {\n            handleSize = [handleSize, handleSize];\n        }\n        handle.attr('scale', [handleSize[0] / 2, handleSize[1] / 2]);\n\n        createOrUpdate(\n            this,\n            '_doDispatchAxisPointer',\n            handleModel.get('throttle') || 0,\n            'fixRate'\n        );\n\n        this._moveHandleToValue(value, isInit);\n    },\n\n    /**\n     * @private\n     */\n    _moveHandleToValue: function (value, isInit) {\n        updateProps$1(\n            this._axisPointerModel,\n            !isInit && this._moveAnimation,\n            this._handle,\n            getHandleTransProps(this.getHandleTransform(\n                value, this._axisModel, this._axisPointerModel\n            ))\n        );\n    },\n\n    /**\n     * @private\n     */\n    _onHandleDragMove: function (dx, dy) {\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        this._dragging = true;\n\n        // Persistent for throttle.\n        var trans = this.updateHandleTransform(\n            getHandleTransProps(handle),\n            [dx, dy],\n            this._axisModel,\n            this._axisPointerModel\n        );\n        this._payloadInfo = trans;\n\n        handle.stopAnimation();\n        handle.attr(getHandleTransProps(trans));\n        inner$9(handle).lastProp = null;\n\n        this._doDispatchAxisPointer();\n    },\n\n    /**\n     * Throttled method.\n     * @private\n     */\n    _doDispatchAxisPointer: function () {\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        var payloadInfo = this._payloadInfo;\n        var axisModel = this._axisModel;\n        this._api.dispatchAction({\n            type: 'updateAxisPointer',\n            x: payloadInfo.cursorPoint[0],\n            y: payloadInfo.cursorPoint[1],\n            tooltipOption: payloadInfo.tooltipOption,\n            axesInfo: [{\n                axisDim: axisModel.axis.dim,\n                axisIndex: axisModel.componentIndex\n            }]\n        });\n    },\n\n    /**\n     * @private\n     */\n    _onHandleDragEnd: function (moveAnimation) {\n        this._dragging = false;\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        var value = this._axisPointerModel.get('value');\n        // Consider snap or categroy axis, handle may be not consistent with\n        // axisPointer. So move handle to align the exact value position when\n        // drag ended.\n        this._moveHandleToValue(value);\n\n        // For the effect: tooltip will be shown when finger holding on handle\n        // button, and will be hidden after finger left handle button.\n        this._api.dispatchAction({\n            type: 'hideTip'\n        });\n    },\n\n    /**\n     * Should be implemenented by sub-class if support `handle`.\n     * @protected\n     * @param {number} value\n     * @param {module:echarts/model/Model} axisModel\n     * @param {module:echarts/model/Model} axisPointerModel\n     * @return {Object} {position: [x, y], rotation: 0}\n     */\n    getHandleTransform: null,\n\n    /**\n     * * Should be implemenented by sub-class if support `handle`.\n     * @protected\n     * @param {Object} transform {position, rotation}\n     * @param {Array.<number>} delta [dx, dy]\n     * @param {module:echarts/model/Model} axisModel\n     * @param {module:echarts/model/Model} axisPointerModel\n     * @return {Object} {position: [x, y], rotation: 0, cursorPoint: [x, y]}\n     */\n    updateHandleTransform: null,\n\n    /**\n     * @private\n     */\n    clear: function (api) {\n        this._lastValue = null;\n        this._lastStatus = null;\n\n        var zr = api.getZr();\n        var group = this._group;\n        var handle = this._handle;\n        if (zr && group) {\n            this._lastGraphicKey = null;\n            group && zr.remove(group);\n            handle && zr.remove(handle);\n            this._group = null;\n            this._handle = null;\n            this._payloadInfo = null;\n        }\n    },\n\n    /**\n     * @protected\n     */\n    doClear: function () {\n        // Implemented by sub-class if necessary.\n    },\n\n    /**\n     * @protected\n     * @param {Array.<number>} xy\n     * @param {Array.<number>} wh\n     * @param {number} [xDimIndex=0] or 1\n     */\n    buildLabel: function (xy, wh, xDimIndex) {\n        xDimIndex = xDimIndex || 0;\n        return {\n            x: xy[xDimIndex],\n            y: xy[1 - xDimIndex],\n            width: wh[xDimIndex],\n            height: wh[1 - xDimIndex]\n        };\n    }\n};\n\nBaseAxisPointer.prototype.constructor = BaseAxisPointer;\n\n\nfunction updateProps$1(animationModel, moveAnimation, el, props) {\n    // Animation optimize.\n    if (!propsEqual(inner$9(el).lastProp, props)) {\n        inner$9(el).lastProp = props;\n        moveAnimation\n            ? updateProps(el, props, animationModel)\n            : (el.stopAnimation(), el.attr(props));\n    }\n}\n\nfunction propsEqual(lastProps, newProps) {\n    if (isObject$1(lastProps) && isObject$1(newProps)) {\n        var equals = true;\n        each$1(newProps, function (item, key) {\n            equals = equals && propsEqual(lastProps[key], item);\n        });\n        return !!equals;\n    }\n    else {\n        return lastProps === newProps;\n    }\n}\n\nfunction updateLabelShowHide(labelEl, axisPointerModel) {\n    labelEl[axisPointerModel.get('label.show') ? 'show' : 'hide']();\n}\n\nfunction getHandleTransProps(trans) {\n    return {\n        position: trans.position.slice(),\n        rotation: trans.rotation || 0\n    };\n}\n\nfunction updateMandatoryProps(group, axisPointerModel, silent) {\n    var z = axisPointerModel.get('z');\n    var zlevel = axisPointerModel.get('zlevel');\n\n    group && group.traverse(function (el) {\n        if (el.type !== 'group') {\n            z != null && (el.z = z);\n            zlevel != null && (el.zlevel = zlevel);\n            el.silent = silent;\n        }\n    });\n}\n\nenableClassExtend(BaseAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/model/Model} axisPointerModel\n */\nfunction buildElStyle(axisPointerModel) {\n    var axisPointerType = axisPointerModel.get('type');\n    var styleModel = axisPointerModel.getModel(axisPointerType + 'Style');\n    var style;\n    if (axisPointerType === 'line') {\n        style = styleModel.getLineStyle();\n        style.fill = null;\n    }\n    else if (axisPointerType === 'shadow') {\n        style = styleModel.getAreaStyle();\n        style.stroke = null;\n    }\n    return style;\n}\n\n/**\n * @param {Function} labelPos {align, verticalAlign, position}\n */\nfunction buildLabelElOption(\n    elOption, axisModel, axisPointerModel, api, labelPos\n) {\n    var value = axisPointerModel.get('value');\n    var text = getValueLabel(\n        value, axisModel.axis, axisModel.ecModel,\n        axisPointerModel.get('seriesDataIndices'),\n        {\n            precision: axisPointerModel.get('label.precision'),\n            formatter: axisPointerModel.get('label.formatter')\n        }\n    );\n    var labelModel = axisPointerModel.getModel('label');\n    var paddings = normalizeCssArray$1(labelModel.get('padding') || 0);\n\n    var font = labelModel.getFont();\n    var textRect = getBoundingRect(text, font);\n\n    var position = labelPos.position;\n    var width = textRect.width + paddings[1] + paddings[3];\n    var height = textRect.height + paddings[0] + paddings[2];\n\n    // Adjust by align.\n    var align = labelPos.align;\n    align === 'right' && (position[0] -= width);\n    align === 'center' && (position[0] -= width / 2);\n    var verticalAlign = labelPos.verticalAlign;\n    verticalAlign === 'bottom' && (position[1] -= height);\n    verticalAlign === 'middle' && (position[1] -= height / 2);\n\n    // Not overflow ec container\n    confineInContainer(position, width, height, api);\n\n    var bgColor = labelModel.get('backgroundColor');\n    if (!bgColor || bgColor === 'auto') {\n        bgColor = axisModel.get('axisLine.lineStyle.color');\n    }\n\n    elOption.label = {\n        shape: {x: 0, y: 0, width: width, height: height, r: labelModel.get('borderRadius')},\n        position: position.slice(),\n        // TODO: rich\n        style: {\n            text: text,\n            textFont: font,\n            textFill: labelModel.getTextColor(),\n            textPosition: 'inside',\n            fill: bgColor,\n            stroke: labelModel.get('borderColor') || 'transparent',\n            lineWidth: labelModel.get('borderWidth') || 0,\n            shadowBlur: labelModel.get('shadowBlur'),\n            shadowColor: labelModel.get('shadowColor'),\n            shadowOffsetX: labelModel.get('shadowOffsetX'),\n            shadowOffsetY: labelModel.get('shadowOffsetY')\n        },\n        // Lable should be over axisPointer.\n        z2: 10\n    };\n}\n\n// Do not overflow ec container\nfunction confineInContainer(position, width, height, api) {\n    var viewWidth = api.getWidth();\n    var viewHeight = api.getHeight();\n    position[0] = Math.min(position[0] + width, viewWidth) - width;\n    position[1] = Math.min(position[1] + height, viewHeight) - height;\n    position[0] = Math.max(position[0], 0);\n    position[1] = Math.max(position[1], 0);\n}\n\n/**\n * @param {number} value\n * @param {module:echarts/coord/Axis} axis\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} opt\n * @param {Array.<Object>} seriesDataIndices\n * @param {number|string} opt.precision 'auto' or a number\n * @param {string|Function} opt.formatter label formatter\n */\nfunction getValueLabel(value, axis, ecModel, seriesDataIndices, opt) {\n    value = axis.scale.parse(value);\n    var text = axis.scale.getLabel(\n        // If `precision` is set, width can be fixed (like '12.00500'), which\n        // helps to debounce when when moving label.\n        value, {precision: opt.precision}\n    );\n    var formatter = opt.formatter;\n\n    if (formatter) {\n        var params = {\n            value: getAxisRawValue(axis, value),\n            seriesData: []\n        };\n        each$1(seriesDataIndices, function (idxItem) {\n            var series = ecModel.getSeriesByIndex(idxItem.seriesIndex);\n            var dataIndex = idxItem.dataIndexInside;\n            var dataParams = series && series.getDataParams(dataIndex);\n            dataParams && params.seriesData.push(dataParams);\n        });\n\n        if (isString(formatter)) {\n            text = formatter.replace('{value}', text);\n        }\n        else if (isFunction$1(formatter)) {\n            text = formatter(params);\n        }\n    }\n\n    return text;\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @param {number} value\n * @param {Object} layoutInfo {\n *  rotation, position, labelOffset, labelDirection, labelMargin\n * }\n */\nfunction getTransformedPosition(axis, value, layoutInfo) {\n    var transform = create$1();\n    rotate(transform, transform, layoutInfo.rotation);\n    translate(transform, transform, layoutInfo.position);\n\n    return applyTransform$1([\n        axis.dataToCoord(value),\n        (layoutInfo.labelOffset || 0)\n            + (layoutInfo.labelDirection || 1) * (layoutInfo.labelMargin || 0)\n    ], transform);\n}\n\nfunction buildCartesianSingleLabelElOption(\n    value, elOption, layoutInfo, axisModel, axisPointerModel, api\n) {\n    var textLayout = AxisBuilder.innerTextLayout(\n        layoutInfo.rotation, 0, layoutInfo.labelDirection\n    );\n    layoutInfo.labelMargin = axisPointerModel.get('label.margin');\n    buildLabelElOption(elOption, axisModel, axisPointerModel, api, {\n        position: getTransformedPosition(axisModel.axis, value, layoutInfo),\n        align: textLayout.textAlign,\n        verticalAlign: textLayout.textVerticalAlign\n    });\n}\n\n/**\n * @param {Array.<number>} p1\n * @param {Array.<number>} p2\n * @param {number} [xDimIndex=0] or 1\n */\nfunction makeLineShape(p1, p2, xDimIndex) {\n    xDimIndex = xDimIndex || 0;\n    return {\n        x1: p1[xDimIndex],\n        y1: p1[1 - xDimIndex],\n        x2: p2[xDimIndex],\n        y2: p2[1 - xDimIndex]\n    };\n}\n\n/**\n * @param {Array.<number>} xy\n * @param {Array.<number>} wh\n * @param {number} [xDimIndex=0] or 1\n */\nfunction makeRectShape(xy, wh, xDimIndex) {\n    xDimIndex = xDimIndex || 0;\n    return {\n        x: xy[xDimIndex],\n        y: xy[1 - xDimIndex],\n        width: wh[xDimIndex],\n        height: wh[1 - xDimIndex]\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar CartesianAxisPointer = BaseAxisPointer.extend({\n\n    /**\n     * @override\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        var axis = axisModel.axis;\n        var grid = axis.grid;\n        var axisPointerType = axisPointerModel.get('type');\n        var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent();\n        var pixelValue = axis.toGlobalCoord(axis.dataToCoord(value, true));\n\n        if (axisPointerType && axisPointerType !== 'none') {\n            var elStyle = buildElStyle(axisPointerModel);\n            var pointerOption = pointerShapeBuilder[axisPointerType](\n                axis, pixelValue, otherExtent, elStyle\n            );\n            pointerOption.style = elStyle;\n            elOption.graphicKey = pointerOption.type;\n            elOption.pointer = pointerOption;\n        }\n\n        var layoutInfo = layout$1(grid.model, axisModel);\n        buildCartesianSingleLabelElOption(\n            value, elOption, layoutInfo, axisModel, axisPointerModel, api\n        );\n    },\n\n    /**\n     * @override\n     */\n    getHandleTransform: function (value, axisModel, axisPointerModel) {\n        var layoutInfo = layout$1(axisModel.axis.grid.model, axisModel, {\n            labelInside: false\n        });\n        layoutInfo.labelMargin = axisPointerModel.get('handle.margin');\n        return {\n            position: getTransformedPosition(axisModel.axis, value, layoutInfo),\n            rotation: layoutInfo.rotation + (layoutInfo.labelDirection < 0 ? Math.PI : 0)\n        };\n    },\n\n    /**\n     * @override\n     */\n    updateHandleTransform: function (transform, delta, axisModel, axisPointerModel) {\n        var axis = axisModel.axis;\n        var grid = axis.grid;\n        var axisExtent = axis.getGlobalExtent(true);\n        var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent();\n        var dimIndex = axis.dim === 'x' ? 0 : 1;\n\n        var currPosition = transform.position;\n        currPosition[dimIndex] += delta[dimIndex];\n        currPosition[dimIndex] = Math.min(axisExtent[1], currPosition[dimIndex]);\n        currPosition[dimIndex] = Math.max(axisExtent[0], currPosition[dimIndex]);\n\n        var cursorOtherValue = (otherExtent[1] + otherExtent[0]) / 2;\n        var cursorPoint = [cursorOtherValue, cursorOtherValue];\n        cursorPoint[dimIndex] = currPosition[dimIndex];\n\n        // Make tooltip do not overlap axisPointer and in the middle of the grid.\n        var tooltipOptions = [{verticalAlign: 'middle'}, {align: 'center'}];\n\n        return {\n            position: currPosition,\n            rotation: transform.rotation,\n            cursorPoint: cursorPoint,\n            tooltipOption: tooltipOptions[dimIndex]\n        };\n    }\n\n});\n\nfunction getCartesian(grid, axis) {\n    var opt = {};\n    opt[axis.dim + 'AxisIndex'] = axis.index;\n    return grid.getCartesian(opt);\n}\n\nvar pointerShapeBuilder = {\n\n    line: function (axis, pixelValue, otherExtent, elStyle) {\n        var targetShape = makeLineShape(\n            [pixelValue, otherExtent[0]],\n            [pixelValue, otherExtent[1]],\n            getAxisDimIndex(axis)\n        );\n        subPixelOptimizeLine({\n            shape: targetShape,\n            style: elStyle\n        });\n        return {\n            type: 'Line',\n            shape: targetShape\n        };\n    },\n\n    shadow: function (axis, pixelValue, otherExtent, elStyle) {\n        var bandWidth = Math.max(1, axis.getBandWidth());\n        var span = otherExtent[1] - otherExtent[0];\n        return {\n            type: 'Rect',\n            shape: makeRectShape(\n                [pixelValue - bandWidth / 2, otherExtent[0]],\n                [bandWidth, span],\n                getAxisDimIndex(axis)\n            )\n        };\n    }\n};\n\nfunction getAxisDimIndex(axis) {\n    return axis.dim === 'x' ? 0 : 1;\n}\n\nAxisView.registerAxisPointerClass('CartesianAxisPointer', CartesianAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// CartesianAxisPointer is not supposed to be required here. But consider\n// echarts.simple.js and online build tooltip, which only require gridSimple,\n// CartesianAxisPointer should be able to required somewhere.\nregisterPreprocessor(function (option) {\n    // Always has a global axisPointerModel for default setting.\n    if (option) {\n        (!option.axisPointer || option.axisPointer.length === 0)\n            && (option.axisPointer = {});\n\n        var link = option.axisPointer.link;\n        // Normalize to array to avoid object mergin. But if link\n        // is not set, remain null/undefined, otherwise it will\n        // override existent link setting.\n        if (link && !isArray(link)) {\n            option.axisPointer.link = [link];\n        }\n    }\n});\n\n// This process should proformed after coordinate systems created\n// and series data processed. So put it on statistic processing stage.\nregisterProcessor(PRIORITY.PROCESSOR.STATISTIC, function (ecModel, api) {\n    // Build axisPointerModel, mergin tooltip.axisPointer model for each axis.\n    // allAxesInfo should be updated when setOption performed.\n    ecModel.getComponent('axisPointer').coordSysAxesInfo\n        = collect(ecModel, api);\n});\n\n// Broadcast to all views.\nregisterAction({\n    type: 'updateAxisPointer',\n    event: 'updateAxisPointer',\n    update: ':updateAxisPointer'\n}, axisTrigger);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentModel({\n\n    type: 'tooltip',\n\n    dependencies: ['axisPointer'],\n\n    defaultOption: {\n        zlevel: 0,\n\n        z: 60,\n\n        show: true,\n\n        // tooltip主体内容\n        showContent: true,\n\n        // 'trigger' only works on coordinate system.\n        // 'item' | 'axis' | 'none'\n        trigger: 'item',\n\n        // 'click' | 'mousemove' | 'none'\n        triggerOn: 'mousemove|click',\n\n        alwaysShowContent: false,\n\n        displayMode: 'single', // 'single' | 'multipleByCoordSys'\n\n        renderMode: 'auto', // 'auto' | 'html' | 'richText'\n        // 'auto': use html by default, and use non-html if `document` is not defined\n        // 'html': use html for tooltip\n        // 'richText': use canvas, svg, and etc. for tooltip\n\n        // 位置 {Array} | {Function}\n        // position: null\n        // Consider triggered from axisPointer handle, verticalAlign should be 'middle'\n        // align: null,\n        // verticalAlign: null,\n\n        // 是否约束 content 在 viewRect 中。默认 false 是为了兼容以前版本。\n        confine: false,\n\n        // 内容格式器：{string}（Template） ¦ {Function}\n        // formatter: null\n\n        showDelay: 0,\n\n        // 隐藏延迟，单位ms\n        hideDelay: 100,\n\n        // 动画变换时间，单位s\n        transitionDuration: 0.4,\n\n        enterable: false,\n\n        // 提示背景颜色，默认为透明度为0.7的黑色\n        backgroundColor: 'rgba(50,50,50,0.7)',\n\n        // 提示边框颜色\n        borderColor: '#333',\n\n        // 提示边框圆角，单位px，默认为4\n        borderRadius: 4,\n\n        // 提示边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n\n        // 提示内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n\n        // Extra css text\n        extraCssText: '',\n\n        // 坐标轴指示器，坐标轴触发有效\n        axisPointer: {\n            // 默认为直线\n            // 可选为：'line' | 'shadow' | 'cross'\n            type: 'line',\n\n            // type 为 line 的时候有效，指定 tooltip line 所在的轴，可选\n            // 可选 'x' | 'y' | 'angle' | 'radius' | 'auto'\n            // 默认 'auto'，会选择类型为 category 的轴，对于双数值轴，笛卡尔坐标系会默认选择 x 轴\n            // 极坐标系会默认选择 angle 轴\n            axis: 'auto',\n\n            animation: 'auto',\n            animationDurationUpdate: 200,\n            animationEasingUpdate: 'exponentialOut',\n\n            crossStyle: {\n                color: '#999',\n                width: 1,\n                type: 'dashed',\n\n                // TODO formatter\n                textStyle: {}\n            }\n\n            // lineStyle and shadowStyle should not be specified here,\n            // otherwise it will always override those styles on option.axisPointer.\n        },\n        textStyle: {\n            color: '#fff',\n            fontSize: 14\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$10 = each$1;\nvar toCamelCase$1 = toCamelCase;\n\nvar vendors = ['', '-webkit-', '-moz-', '-o-'];\n\nvar gCssText = 'position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;';\n\n/**\n * @param {number} duration\n * @return {string}\n * @inner\n */\nfunction assembleTransition(duration) {\n    var transitionCurve = 'cubic-bezier(0.23, 1, 0.32, 1)';\n    var transitionText = 'left ' + duration + 's ' + transitionCurve + ','\n                        + 'top ' + duration + 's ' + transitionCurve;\n    return map(vendors, function (vendorPrefix) {\n        return vendorPrefix + 'transition:' + transitionText;\n    }).join(';');\n}\n\n/**\n * @param {Object} textStyle\n * @return {string}\n * @inner\n */\nfunction assembleFont(textStyleModel) {\n    var cssText = [];\n\n    var fontSize = textStyleModel.get('fontSize');\n    var color = textStyleModel.getTextColor();\n\n    color && cssText.push('color:' + color);\n\n    cssText.push('font:' + textStyleModel.getFont());\n\n    fontSize\n        && cssText.push('line-height:' + Math.round(fontSize * 3 / 2) + 'px');\n\n    each$10(['decoration', 'align'], function (name) {\n        var val = textStyleModel.get(name);\n        val && cssText.push('text-' + name + ':' + val);\n    });\n\n    return cssText.join(';');\n}\n\n/**\n * @param {Object} tooltipModel\n * @return {string}\n * @inner\n */\nfunction assembleCssText(tooltipModel) {\n\n    var cssText = [];\n\n    var transitionDuration = tooltipModel.get('transitionDuration');\n    var backgroundColor = tooltipModel.get('backgroundColor');\n    var textStyleModel = tooltipModel.getModel('textStyle');\n    var padding = tooltipModel.get('padding');\n\n    // Animation transition. Do not animate when transitionDuration is 0.\n    transitionDuration\n        && cssText.push(assembleTransition(transitionDuration));\n\n    if (backgroundColor) {\n        if (env$1.canvasSupported) {\n            cssText.push('background-Color:' + backgroundColor);\n        }\n        else {\n            // for ie\n            cssText.push(\n                'background-Color:#' + toHex(backgroundColor)\n            );\n            cssText.push('filter:alpha(opacity=70)');\n        }\n    }\n\n    // Border style\n    each$10(['width', 'color', 'radius'], function (name) {\n        var borderName = 'border-' + name;\n        var camelCase = toCamelCase$1(borderName);\n        var val = tooltipModel.get(camelCase);\n        val != null\n            && cssText.push(borderName + ':' + val + (name === 'color' ? '' : 'px'));\n    });\n\n    // Text style\n    cssText.push(assembleFont(textStyleModel));\n\n    // Padding\n    if (padding != null) {\n        cssText.push('padding:' + normalizeCssArray$1(padding).join('px ') + 'px');\n    }\n\n    return cssText.join(';') + ';';\n}\n\n/**\n * @alias module:echarts/component/tooltip/TooltipContent\n * @constructor\n */\nfunction TooltipContent(container, api) {\n    if (env$1.wxa) {\n        return null;\n    }\n\n    var el = document.createElement('div');\n    var zr = this._zr = api.getZr();\n\n    this.el = el;\n\n    this._x = api.getWidth() / 2;\n    this._y = api.getHeight() / 2;\n\n    container.appendChild(el);\n\n    this._container = container;\n\n    this._show = false;\n\n    /**\n     * @private\n     */\n    this._hideTimeout;\n\n    var self = this;\n    el.onmouseenter = function () {\n        // clear the timeout in hideLater and keep showing tooltip\n        if (self._enterable) {\n            clearTimeout(self._hideTimeout);\n            self._show = true;\n        }\n        self._inContent = true;\n    };\n    el.onmousemove = function (e) {\n        e = e || window.event;\n        if (!self._enterable) {\n            // Try trigger zrender event to avoid mouse\n            // in and out shape too frequently\n            var handler = zr.handler;\n            normalizeEvent(container, e, true);\n            handler.dispatch('mousemove', e);\n        }\n    };\n    el.onmouseleave = function () {\n        if (self._enterable) {\n            if (self._show) {\n                self.hideLater(self._hideDelay);\n            }\n        }\n        self._inContent = false;\n    };\n}\n\nTooltipContent.prototype = {\n\n    constructor: TooltipContent,\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    _enterable: true,\n\n    /**\n     * Update when tooltip is rendered\n     */\n    update: function () {\n        // FIXME\n        // Move this logic to ec main?\n        var container = this._container;\n        var stl = container.currentStyle\n            || document.defaultView.getComputedStyle(container);\n        var domStyle = container.style;\n        if (domStyle.position !== 'absolute' && stl.position !== 'absolute') {\n            domStyle.position = 'relative';\n        }\n        // Hide the tooltip\n        // PENDING\n        // this.hide();\n    },\n\n    show: function (tooltipModel) {\n        clearTimeout(this._hideTimeout);\n        var el = this.el;\n\n        el.style.cssText = gCssText + assembleCssText(tooltipModel)\n            // http://stackoverflow.com/questions/21125587/css3-transition-not-working-in-chrome-anymore\n            + ';left:' + this._x + 'px;top:' + this._y + 'px;'\n            + (tooltipModel.get('extraCssText') || '');\n\n        el.style.display = el.innerHTML ? 'block' : 'none';\n\n        // If mouse occsionally move over the tooltip, a mouseout event will be\n        // triggered by canvas, and cuase some unexpectable result like dragging\n        // stop, \"unfocusAdjacency\". Here `pointer-events: none` is used to solve\n        // it. Although it is not suppored by IE8~IE10, fortunately it is a rare\n        // scenario.\n        el.style.pointerEvents = this._enterable ? 'auto' : 'none';\n\n        this._show = true;\n    },\n\n    setContent: function (content) {\n        this.el.innerHTML = content == null ? '' : content;\n    },\n\n    setEnterable: function (enterable) {\n        this._enterable = enterable;\n    },\n\n    getSize: function () {\n        var el = this.el;\n        return [el.clientWidth, el.clientHeight];\n    },\n\n    moveTo: function (x, y) {\n        // xy should be based on canvas root. But tooltipContent is\n        // the sibling of canvas root. So padding of ec container\n        // should be considered here.\n        var zr = this._zr;\n        var viewportRootOffset;\n        if (zr && zr.painter && (viewportRootOffset = zr.painter.getViewportRootOffset())) {\n            x += viewportRootOffset.offsetLeft;\n            y += viewportRootOffset.offsetTop;\n        }\n\n        var style = this.el.style;\n        style.left = x + 'px';\n        style.top = y + 'px';\n\n        this._x = x;\n        this._y = y;\n    },\n\n    hide: function () {\n        this.el.style.display = 'none';\n        this._show = false;\n    },\n\n    hideLater: function (time) {\n        if (this._show && !(this._inContent && this._enterable)) {\n            if (time) {\n                this._hideDelay = time;\n                // Set show false to avoid invoke hideLater mutiple times\n                this._show = false;\n                this._hideTimeout = setTimeout(bind(this.hide, this), time);\n            }\n            else {\n                this.hide();\n            }\n        }\n    },\n\n    isShow: function () {\n        return this._show;\n    },\n\n    getOuterSize: function () {\n        var width = this.el.clientWidth;\n        var height = this.el.clientHeight;\n\n        // Consider browser compatibility.\n        // IE8 does not support getComputedStyle.\n        if (document.defaultView && document.defaultView.getComputedStyle) {\n            var stl = document.defaultView.getComputedStyle(this.el);\n            if (stl) {\n                width += parseInt(stl.paddingLeft, 10) + parseInt(stl.paddingRight, 10)\n                    + parseInt(stl.borderLeftWidth, 10) + parseInt(stl.borderRightWidth, 10);\n                height += parseInt(stl.paddingTop, 10) + parseInt(stl.paddingBottom, 10)\n                    + parseInt(stl.borderTopWidth, 10) + parseInt(stl.borderBottomWidth, 10);\n            }\n        }\n\n        return {width: width, height: height};\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import Group from 'zrender/src/container/Group';\n/**\n * @alias module:echarts/component/tooltip/TooltipRichContent\n * @constructor\n */\nfunction TooltipRichContent(api) {\n\n    this._zr = api.getZr();\n\n    this._show = false;\n\n    /**\n     * @private\n     */\n    this._hideTimeout;\n}\n\nTooltipRichContent.prototype = {\n\n    constructor: TooltipRichContent,\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    _enterable: true,\n\n    /**\n     * Update when tooltip is rendered\n     */\n    update: function () {\n        // noop\n    },\n\n    show: function (tooltipModel) {\n        if (this._hideTimeout) {\n            clearTimeout(this._hideTimeout);\n        }\n\n        this.el.attr('show', true);\n        this._show = true;\n    },\n\n    /**\n     * Set tooltip content\n     *\n     * @param {string} content rich text string of content\n     * @param {Object} markerRich rich text style\n     * @param {Object} tooltipModel tooltip model\n     */\n    setContent: function (content, markerRich, tooltipModel) {\n        if (this.el) {\n            this._zr.remove(this.el);\n        }\n\n        var markers = {};\n        var text = content;\n        var prefix = '{marker';\n        var suffix = '|}';\n        var startId = text.indexOf(prefix);\n        while (startId >= 0) {\n            var endId = text.indexOf(suffix);\n            var name = text.substr(startId + prefix.length, endId - startId - prefix.length);\n            if (name.indexOf('sub') > -1) {\n                markers['marker' + name] = {\n                    textWidth: 4,\n                    textHeight: 4,\n                    textBorderRadius: 2,\n                    textBackgroundColor: markerRich[name],\n                    // TODO: textOffset is not implemented for rich text\n                    textOffset: [3, 0]\n                };\n            }\n            else {\n                markers['marker' + name] = {\n                    textWidth: 10,\n                    textHeight: 10,\n                    textBorderRadius: 5,\n                    textBackgroundColor: markerRich[name]\n                };\n            }\n\n            text = text.substr(endId + 1);\n            startId = text.indexOf('{marker');\n        }\n\n        this.el = new Text({\n            style: {\n                rich: markers,\n                text: content,\n                textLineHeight: 20,\n                textBackgroundColor: tooltipModel.get('backgroundColor'),\n                textBorderRadius: tooltipModel.get('borderRadius'),\n                textFill: tooltipModel.get('textStyle.color'),\n                textPadding: tooltipModel.get('padding')\n            },\n            z: tooltipModel.get('z')\n        });\n        this._zr.add(this.el);\n\n        var self = this;\n        this.el.on('mouseover', function () {\n            // clear the timeout in hideLater and keep showing tooltip\n            if (self._enterable) {\n                clearTimeout(self._hideTimeout);\n                self._show = true;\n            }\n            self._inContent = true;\n        });\n        this.el.on('mouseout', function () {\n            if (self._enterable) {\n                if (self._show) {\n                    self.hideLater(self._hideDelay);\n                }\n            }\n            self._inContent = false;\n        });\n    },\n\n    setEnterable: function (enterable) {\n        this._enterable = enterable;\n    },\n\n    getSize: function () {\n        var bounding = this.el.getBoundingRect();\n        return [bounding.width, bounding.height];\n    },\n\n    moveTo: function (x, y) {\n        if (this.el) {\n            this.el.attr('position', [x, y]);\n        }\n    },\n\n    hide: function () {\n        this.el.hide();\n        this._show = false;\n    },\n\n    hideLater: function (time) {\n        if (this._show && !(this._inContent && this._enterable)) {\n            if (time) {\n                this._hideDelay = time;\n                // Set show false to avoid invoke hideLater mutiple times\n                this._show = false;\n                this._hideTimeout = setTimeout(bind(this.hide, this), time);\n            }\n            else {\n                this.hide();\n            }\n        }\n    },\n\n    isShow: function () {\n        return this._show;\n    },\n\n    getOuterSize: function () {\n        return this.getSize();\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$2 = bind;\nvar each$9 = each$1;\nvar parsePercent$2 = parsePercent$1;\n\nvar proxyRect = new Rect({\n    shape: {x: -1, y: -1, width: 2, height: 2}\n});\n\nextendComponentView({\n\n    type: 'tooltip',\n\n    init: function (ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n\n        var tooltipModel = ecModel.getComponent('tooltip');\n        var renderMode = tooltipModel.get('renderMode');\n        this._renderMode = getTooltipRenderMode(renderMode);\n\n        var tooltipContent;\n        if (this._renderMode === 'html') {\n            tooltipContent = new TooltipContent(api.getDom(), api);\n            this._newLine = '<br/>';\n        }\n        else {\n            tooltipContent = new TooltipRichContent(api);\n            this._newLine = '\\n';\n        }\n\n        this._tooltipContent = tooltipContent;\n    },\n\n    render: function (tooltipModel, ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n\n        // Reset\n        this.group.removeAll();\n\n        /**\n         * @private\n         * @type {module:echarts/component/tooltip/TooltipModel}\n         */\n        this._tooltipModel = tooltipModel;\n\n        /**\n         * @private\n         * @type {module:echarts/model/Global}\n         */\n        this._ecModel = ecModel;\n\n        /**\n         * @private\n         * @type {module:echarts/ExtensionAPI}\n         */\n        this._api = api;\n\n        /**\n         * Should be cleaned when render.\n         * @private\n         * @type {Array.<Array.<Object>>}\n         */\n        this._lastDataByCoordSys = null;\n\n        /**\n         * @private\n         * @type {boolean}\n         */\n        this._alwaysShowContent = tooltipModel.get('alwaysShowContent');\n\n        var tooltipContent = this._tooltipContent;\n        tooltipContent.update();\n        tooltipContent.setEnterable(tooltipModel.get('enterable'));\n\n        this._initGlobalListener();\n\n        this._keepShow();\n    },\n\n    _initGlobalListener: function () {\n        var tooltipModel = this._tooltipModel;\n        var triggerOn = tooltipModel.get('triggerOn');\n\n        register(\n            'itemTooltip',\n            this._api,\n            bind$2(function (currTrigger, e, dispatchAction) {\n                // If 'none', it is not controlled by mouse totally.\n                if (triggerOn !== 'none') {\n                    if (triggerOn.indexOf(currTrigger) >= 0) {\n                        this._tryShow(e, dispatchAction);\n                    }\n                    else if (currTrigger === 'leave') {\n                        this._hide(dispatchAction);\n                    }\n                }\n            }, this)\n        );\n    },\n\n    _keepShow: function () {\n        var tooltipModel = this._tooltipModel;\n        var ecModel = this._ecModel;\n        var api = this._api;\n\n        // Try to keep the tooltip show when refreshing\n        if (this._lastX != null\n            && this._lastY != null\n            // When user is willing to control tooltip totally using API,\n            // self.manuallyShowTip({x, y}) might cause tooltip hide,\n            // which is not expected.\n            && tooltipModel.get('triggerOn') !== 'none'\n        ) {\n            var self = this;\n            clearTimeout(this._refreshUpdateTimeout);\n            this._refreshUpdateTimeout = setTimeout(function () {\n                // Show tip next tick after other charts are rendered\n                // In case highlight action has wrong result\n                // FIXME\n                self.manuallyShowTip(tooltipModel, ecModel, api, {\n                    x: self._lastX,\n                    y: self._lastY\n                });\n            });\n        }\n    },\n\n    /**\n     * Show tip manually by\n     * dispatchAction({\n     *     type: 'showTip',\n     *     x: 10,\n     *     y: 10\n     * });\n     * Or\n     * dispatchAction({\n     *      type: 'showTip',\n     *      seriesIndex: 0,\n     *      dataIndex or dataIndexInside or name\n     * });\n     *\n     *  TODO Batch\n     */\n    manuallyShowTip: function (tooltipModel, ecModel, api, payload) {\n        if (payload.from === this.uid || env$1.node) {\n            return;\n        }\n\n        var dispatchAction = makeDispatchAction$1(payload, api);\n\n        // Reset ticket\n        this._ticket = '';\n\n        // When triggered from axisPointer.\n        var dataByCoordSys = payload.dataByCoordSys;\n\n        if (payload.tooltip && payload.x != null && payload.y != null) {\n            var el = proxyRect;\n            el.position = [payload.x, payload.y];\n            el.update();\n            el.tooltip = payload.tooltip;\n            // Manually show tooltip while view is not using zrender elements.\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                target: el\n            }, dispatchAction);\n        }\n        else if (dataByCoordSys) {\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                position: payload.position,\n                event: {},\n                dataByCoordSys: payload.dataByCoordSys,\n                tooltipOption: payload.tooltipOption\n            }, dispatchAction);\n        }\n        else if (payload.seriesIndex != null) {\n\n            if (this._manuallyAxisShowTip(tooltipModel, ecModel, api, payload)) {\n                return;\n            }\n\n            var pointInfo = findPointFromSeries(payload, ecModel);\n            var cx = pointInfo.point[0];\n            var cy = pointInfo.point[1];\n            if (cx != null && cy != null) {\n                this._tryShow({\n                    offsetX: cx,\n                    offsetY: cy,\n                    position: payload.position,\n                    target: pointInfo.el,\n                    event: {}\n                }, dispatchAction);\n            }\n        }\n        else if (payload.x != null && payload.y != null) {\n            // FIXME\n            // should wrap dispatchAction like `axisPointer/globalListener` ?\n            api.dispatchAction({\n                type: 'updateAxisPointer',\n                x: payload.x,\n                y: payload.y\n            });\n\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                position: payload.position,\n                target: api.getZr().findHover(payload.x, payload.y).target,\n                event: {}\n            }, dispatchAction);\n        }\n    },\n\n    manuallyHideTip: function (tooltipModel, ecModel, api, payload) {\n        var tooltipContent = this._tooltipContent;\n\n        if (!this._alwaysShowContent && this._tooltipModel) {\n            tooltipContent.hideLater(this._tooltipModel.get('hideDelay'));\n        }\n\n        this._lastX = this._lastY = null;\n\n        if (payload.from !== this.uid) {\n            this._hide(makeDispatchAction$1(payload, api));\n        }\n    },\n\n    // Be compatible with previous design, that is, when tooltip.type is 'axis' and\n    // dispatchAction 'showTip' with seriesIndex and dataIndex will trigger axis pointer\n    // and tooltip.\n    _manuallyAxisShowTip: function (tooltipModel, ecModel, api, payload) {\n        var seriesIndex = payload.seriesIndex;\n        var dataIndex = payload.dataIndex;\n        var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo;\n\n        if (seriesIndex == null || dataIndex == null || coordSysAxesInfo == null) {\n            return;\n        }\n\n        var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n        if (!seriesModel) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var tooltipModel = buildTooltipModel([\n            data.getItemModel(dataIndex),\n            seriesModel,\n            (seriesModel.coordinateSystem || {}).model,\n            tooltipModel\n        ]);\n\n        if (tooltipModel.get('trigger') !== 'axis') {\n            return;\n        }\n\n        api.dispatchAction({\n            type: 'updateAxisPointer',\n            seriesIndex: seriesIndex,\n            dataIndex: dataIndex,\n            position: payload.position\n        });\n\n        return true;\n    },\n\n    _tryShow: function (e, dispatchAction) {\n        var el = e.target;\n        var tooltipModel = this._tooltipModel;\n\n        if (!tooltipModel) {\n            return;\n        }\n\n        // Save mouse x, mouse y. So we can try to keep showing the tip if chart is refreshed\n        this._lastX = e.offsetX;\n        this._lastY = e.offsetY;\n\n        var dataByCoordSys = e.dataByCoordSys;\n        if (dataByCoordSys && dataByCoordSys.length) {\n            this._showAxisTooltip(dataByCoordSys, e);\n        }\n        // Always show item tooltip if mouse is on the element with dataIndex\n        else if (el && el.dataIndex != null) {\n            this._lastDataByCoordSys = null;\n            this._showSeriesItemTooltip(e, el, dispatchAction);\n        }\n        // Tooltip provided directly. Like legend.\n        else if (el && el.tooltip) {\n            this._lastDataByCoordSys = null;\n            this._showComponentItemTooltip(e, el, dispatchAction);\n        }\n        else {\n            this._lastDataByCoordSys = null;\n            this._hide(dispatchAction);\n        }\n    },\n\n    _showOrMove: function (tooltipModel, cb) {\n        // showDelay is used in this case: tooltip.enterable is set\n        // as true. User intent to move mouse into tooltip and click\n        // something. `showDelay` makes it easyer to enter the content\n        // but tooltip do not move immediately.\n        var delay = tooltipModel.get('showDelay');\n        cb = bind(cb, this);\n        clearTimeout(this._showTimout);\n        delay > 0\n            ? (this._showTimout = setTimeout(cb, delay))\n            : cb();\n    },\n\n    _showAxisTooltip: function (dataByCoordSys, e) {\n        var ecModel = this._ecModel;\n        var globalTooltipModel = this._tooltipModel;\n        var point = [e.offsetX, e.offsetY];\n        var singleDefaultHTML = [];\n        var singleParamsList = [];\n        var singleTooltipModel = buildTooltipModel([\n            e.tooltipOption,\n            globalTooltipModel\n        ]);\n\n        var renderMode = this._renderMode;\n        var newLine = this._newLine;\n\n        var markers = {};\n\n        each$9(dataByCoordSys, function (itemCoordSys) {\n            // var coordParamList = [];\n            // var coordDefaultHTML = [];\n            // var coordTooltipModel = buildTooltipModel([\n            //     e.tooltipOption,\n            //     itemCoordSys.tooltipOption,\n            //     ecModel.getComponent(itemCoordSys.coordSysMainType, itemCoordSys.coordSysIndex),\n            //     globalTooltipModel\n            // ]);\n            // var displayMode = coordTooltipModel.get('displayMode');\n            // var paramsList = displayMode === 'single' ? singleParamsList : [];\n\n            each$9(itemCoordSys.dataByAxis, function (item) {\n                var axisModel = ecModel.getComponent(item.axisDim + 'Axis', item.axisIndex);\n                var axisValue = item.value;\n                var seriesDefaultHTML = [];\n\n                if (!axisModel || axisValue == null) {\n                    return;\n                }\n\n                var valueLabel = getValueLabel(\n                    axisValue, axisModel.axis, ecModel,\n                    item.seriesDataIndices,\n                    item.valueLabelOpt\n                );\n\n                each$1(item.seriesDataIndices, function (idxItem) {\n                    var series = ecModel.getSeriesByIndex(idxItem.seriesIndex);\n                    var dataIndex = idxItem.dataIndexInside;\n                    var dataParams = series && series.getDataParams(dataIndex);\n                    dataParams.axisDim = item.axisDim;\n                    dataParams.axisIndex = item.axisIndex;\n                    dataParams.axisType = item.axisType;\n                    dataParams.axisId = item.axisId;\n                    dataParams.axisValue = getAxisRawValue(axisModel.axis, axisValue);\n                    dataParams.axisValueLabel = valueLabel;\n\n                    if (dataParams) {\n                        singleParamsList.push(dataParams);\n                        var seriesTooltip = series.formatTooltip(dataIndex, true, null, renderMode);\n\n                        var html;\n                        if (isObject$1(seriesTooltip)) {\n                            html = seriesTooltip.html;\n                            var newMarkers = seriesTooltip.markers;\n                            merge(markers, newMarkers);\n                        }\n                        else {\n                            html = seriesTooltip;\n                        }\n                        seriesDefaultHTML.push(html);\n                    }\n                });\n\n                // Default tooltip content\n                // FIXME\n                // (1) shold be the first data which has name?\n                // (2) themeRiver, firstDataIndex is array, and first line is unnecessary.\n                var firstLine = valueLabel;\n                if (renderMode !== 'html') {\n                    singleDefaultHTML.push(seriesDefaultHTML.join(newLine));\n                }\n                else {\n                    singleDefaultHTML.push(\n                        (firstLine ? encodeHTML(firstLine) + newLine : '')\n                        + seriesDefaultHTML.join(newLine)\n                    );\n                }\n            });\n        }, this);\n\n        // In most case, the second axis is shown upper than the first one.\n        singleDefaultHTML.reverse();\n        singleDefaultHTML = singleDefaultHTML.join(this._newLine + this._newLine);\n\n        var positionExpr = e.position;\n        this._showOrMove(singleTooltipModel, function () {\n            if (this._updateContentNotChangedOnAxis(dataByCoordSys)) {\n                this._updatePosition(\n                    singleTooltipModel,\n                    positionExpr,\n                    point[0], point[1],\n                    this._tooltipContent,\n                    singleParamsList\n                );\n            }\n            else {\n                this._showTooltipContent(\n                    singleTooltipModel, singleDefaultHTML, singleParamsList, Math.random(),\n                    point[0], point[1], positionExpr, undefined, markers\n                );\n            }\n        });\n\n        // Do not trigger events here, because this branch only be entered\n        // from dispatchAction.\n    },\n\n    _showSeriesItemTooltip: function (e, el, dispatchAction) {\n        var ecModel = this._ecModel;\n        // Use dataModel in element if possible\n        // Used when mouseover on a element like markPoint or edge\n        // In which case, the data is not main data in series.\n        var seriesIndex = el.seriesIndex;\n        var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n\n        // For example, graph link.\n        var dataModel = el.dataModel || seriesModel;\n        var dataIndex = el.dataIndex;\n        var dataType = el.dataType;\n        var data = dataModel.getData();\n\n        var tooltipModel = buildTooltipModel([\n            data.getItemModel(dataIndex),\n            dataModel,\n            seriesModel && (seriesModel.coordinateSystem || {}).model,\n            this._tooltipModel\n        ]);\n\n        var tooltipTrigger = tooltipModel.get('trigger');\n        if (tooltipTrigger != null && tooltipTrigger !== 'item') {\n            return;\n        }\n\n        var params = dataModel.getDataParams(dataIndex, dataType);\n        var seriesTooltip = dataModel.formatTooltip(dataIndex, false, dataType, this._renderMode);\n        var defaultHtml;\n        var markers;\n        if (isObject$1(seriesTooltip)) {\n            defaultHtml = seriesTooltip.html;\n            markers = seriesTooltip.markers;\n        }\n        else {\n            defaultHtml = seriesTooltip;\n            markers = null;\n        }\n\n        var asyncTicket = 'item_' + dataModel.name + '_' + dataIndex;\n\n        this._showOrMove(tooltipModel, function () {\n            this._showTooltipContent(\n                tooltipModel, defaultHtml, params, asyncTicket,\n                e.offsetX, e.offsetY, e.position, e.target, markers\n            );\n        });\n\n        // FIXME\n        // duplicated showtip if manuallyShowTip is called from dispatchAction.\n        dispatchAction({\n            type: 'showTip',\n            dataIndexInside: dataIndex,\n            dataIndex: data.getRawIndex(dataIndex),\n            seriesIndex: seriesIndex,\n            from: this.uid\n        });\n    },\n\n    _showComponentItemTooltip: function (e, el, dispatchAction) {\n        var tooltipOpt = el.tooltip;\n        if (typeof tooltipOpt === 'string') {\n            var content = tooltipOpt;\n            tooltipOpt = {\n                content: content,\n                // Fixed formatter\n                formatter: content\n            };\n        }\n        var subTooltipModel = new Model(tooltipOpt, this._tooltipModel, this._ecModel);\n        var defaultHtml = subTooltipModel.get('content');\n        var asyncTicket = Math.random();\n\n        // Do not check whether `trigger` is 'none' here, because `trigger`\n        // only works on cooridinate system. In fact, we have not found case\n        // that requires setting `trigger` nothing on component yet.\n\n        this._showOrMove(subTooltipModel, function () {\n            this._showTooltipContent(\n                subTooltipModel, defaultHtml, subTooltipModel.get('formatterParams') || {},\n                asyncTicket, e.offsetX, e.offsetY, e.position, el\n            );\n        });\n\n        // If not dispatch showTip, tip may be hide triggered by axis.\n        dispatchAction({\n            type: 'showTip',\n            from: this.uid\n        });\n    },\n\n    _showTooltipContent: function (\n        tooltipModel, defaultHtml, params, asyncTicket, x, y, positionExpr, el, markers\n    ) {\n        // Reset ticket\n        this._ticket = '';\n\n        if (!tooltipModel.get('showContent') || !tooltipModel.get('show')) {\n            return;\n        }\n\n        var tooltipContent = this._tooltipContent;\n\n        var formatter = tooltipModel.get('formatter');\n        positionExpr = positionExpr || tooltipModel.get('position');\n        var html = defaultHtml;\n\n        if (formatter && typeof formatter === 'string') {\n            html = formatTpl(formatter, params, true);\n        }\n        else if (typeof formatter === 'function') {\n            var callback = bind$2(function (cbTicket, html) {\n                if (cbTicket === this._ticket) {\n                    tooltipContent.setContent(html, markers, tooltipModel);\n                    this._updatePosition(\n                        tooltipModel, positionExpr, x, y, tooltipContent, params, el\n                    );\n                }\n            }, this);\n            this._ticket = asyncTicket;\n            html = formatter(params, asyncTicket, callback);\n        }\n\n        tooltipContent.setContent(html, markers, tooltipModel);\n        tooltipContent.show(tooltipModel);\n\n        this._updatePosition(\n            tooltipModel, positionExpr, x, y, tooltipContent, params, el\n        );\n    },\n\n    /**\n     * @param  {string|Function|Array.<number>|Object} positionExpr\n     * @param  {number} x Mouse x\n     * @param  {number} y Mouse y\n     * @param  {boolean} confine Whether confine tooltip content in view rect.\n     * @param  {Object|<Array.<Object>} params\n     * @param  {module:zrender/Element} el target element\n     * @param  {module:echarts/ExtensionAPI} api\n     * @return {Array.<number>}\n     */\n    _updatePosition: function (tooltipModel, positionExpr, x, y, content, params, el) {\n        var viewWidth = this._api.getWidth();\n        var viewHeight = this._api.getHeight();\n        positionExpr = positionExpr || tooltipModel.get('position');\n\n        var contentSize = content.getSize();\n        var align = tooltipModel.get('align');\n        var vAlign = tooltipModel.get('verticalAlign');\n        var rect = el && el.getBoundingRect().clone();\n        el && rect.applyTransform(el.transform);\n\n        if (typeof positionExpr === 'function') {\n            // Callback of position can be an array or a string specify the position\n            positionExpr = positionExpr([x, y], params, content.el, rect, {\n                viewSize: [viewWidth, viewHeight],\n                contentSize: contentSize.slice()\n            });\n        }\n\n        if (isArray(positionExpr)) {\n            x = parsePercent$2(positionExpr[0], viewWidth);\n            y = parsePercent$2(positionExpr[1], viewHeight);\n        }\n        else if (isObject$1(positionExpr)) {\n            positionExpr.width = contentSize[0];\n            positionExpr.height = contentSize[1];\n            var layoutRect = getLayoutRect(\n                positionExpr, {width: viewWidth, height: viewHeight}\n            );\n            x = layoutRect.x;\n            y = layoutRect.y;\n            align = null;\n            // When positionExpr is left/top/right/bottom,\n            // align and verticalAlign will not work.\n            vAlign = null;\n        }\n        // Specify tooltip position by string 'top' 'bottom' 'left' 'right' around graphic element\n        else if (typeof positionExpr === 'string' && el) {\n            var pos = calcTooltipPosition(\n                positionExpr, rect, contentSize\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n        else {\n            var pos = refixTooltipPosition(\n                x, y, content, viewWidth, viewHeight, align ? null : 20, vAlign ? null : 20\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n\n        align && (x -= isCenterAlign(align) ? contentSize[0] / 2 : align === 'right' ? contentSize[0] : 0);\n        vAlign && (y -= isCenterAlign(vAlign) ? contentSize[1] / 2 : vAlign === 'bottom' ? contentSize[1] : 0);\n\n        if (tooltipModel.get('confine')) {\n            var pos = confineTooltipPosition(\n                x, y, content, viewWidth, viewHeight\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n\n        content.moveTo(x, y);\n    },\n\n    // FIXME\n    // Should we remove this but leave this to user?\n    _updateContentNotChangedOnAxis: function (dataByCoordSys) {\n        var lastCoordSys = this._lastDataByCoordSys;\n        var contentNotChanged = !!lastCoordSys\n            && lastCoordSys.length === dataByCoordSys.length;\n\n        contentNotChanged && each$9(lastCoordSys, function (lastItemCoordSys, indexCoordSys) {\n            var lastDataByAxis = lastItemCoordSys.dataByAxis || {};\n            var thisItemCoordSys = dataByCoordSys[indexCoordSys] || {};\n            var thisDataByAxis = thisItemCoordSys.dataByAxis || [];\n            contentNotChanged &= lastDataByAxis.length === thisDataByAxis.length;\n\n            contentNotChanged && each$9(lastDataByAxis, function (lastItem, indexAxis) {\n                var thisItem = thisDataByAxis[indexAxis] || {};\n                var lastIndices = lastItem.seriesDataIndices || [];\n                var newIndices = thisItem.seriesDataIndices || [];\n\n                contentNotChanged\n                    &= lastItem.value === thisItem.value\n                    && lastItem.axisType === thisItem.axisType\n                    && lastItem.axisId === thisItem.axisId\n                    && lastIndices.length === newIndices.length;\n\n                contentNotChanged && each$9(lastIndices, function (lastIdxItem, j) {\n                    var newIdxItem = newIndices[j];\n                    contentNotChanged\n                        &= lastIdxItem.seriesIndex === newIdxItem.seriesIndex\n                        && lastIdxItem.dataIndex === newIdxItem.dataIndex;\n                });\n            });\n        });\n\n        this._lastDataByCoordSys = dataByCoordSys;\n\n        return !!contentNotChanged;\n    },\n\n    _hide: function (dispatchAction) {\n        // Do not directly hideLater here, because this behavior may be prevented\n        // in dispatchAction when showTip is dispatched.\n\n        // FIXME\n        // duplicated hideTip if manuallyHideTip is called from dispatchAction.\n        this._lastDataByCoordSys = null;\n        dispatchAction({\n            type: 'hideTip',\n            from: this.uid\n        });\n    },\n\n    dispose: function (ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n        this._tooltipContent.hide();\n        unregister('itemTooltip', api);\n    }\n});\n\n\n/**\n * @param {Array.<Object|module:echarts/model/Model>} modelCascade\n * From top to bottom. (the last one should be globalTooltipModel);\n */\nfunction buildTooltipModel(modelCascade) {\n    var resultModel = modelCascade.pop();\n    while (modelCascade.length) {\n        var tooltipOpt = modelCascade.pop();\n        if (tooltipOpt) {\n            if (Model.isInstance(tooltipOpt)) {\n                tooltipOpt = tooltipOpt.get('tooltip', true);\n            }\n            // In each data item tooltip can be simply write:\n            // {\n            //  value: 10,\n            //  tooltip: 'Something you need to know'\n            // }\n            if (typeof tooltipOpt === 'string') {\n                tooltipOpt = {formatter: tooltipOpt};\n            }\n            resultModel = new Model(tooltipOpt, resultModel, resultModel.ecModel);\n        }\n    }\n    return resultModel;\n}\n\nfunction makeDispatchAction$1(payload, api) {\n    return payload.dispatchAction || bind(api.dispatchAction, api);\n}\n\nfunction refixTooltipPosition(x, y, content, viewWidth, viewHeight, gapH, gapV) {\n    var size = content.getOuterSize();\n    var width = size.width;\n    var height = size.height;\n\n    if (gapH != null) {\n        if (x + width + gapH > viewWidth) {\n            x -= width + gapH;\n        }\n        else {\n            x += gapH;\n        }\n    }\n    if (gapV != null) {\n        if (y + height + gapV > viewHeight) {\n            y -= height + gapV;\n        }\n        else {\n            y += gapV;\n        }\n    }\n    return [x, y];\n}\n\nfunction confineTooltipPosition(x, y, content, viewWidth, viewHeight) {\n    var size = content.getOuterSize();\n    var width = size.width;\n    var height = size.height;\n\n    x = Math.min(x + width, viewWidth) - width;\n    y = Math.min(y + height, viewHeight) - height;\n    x = Math.max(x, 0);\n    y = Math.max(y, 0);\n\n    return [x, y];\n}\n\nfunction calcTooltipPosition(position, rect, contentSize) {\n    var domWidth = contentSize[0];\n    var domHeight = contentSize[1];\n    var gap = 5;\n    var x = 0;\n    var y = 0;\n    var rectWidth = rect.width;\n    var rectHeight = rect.height;\n    switch (position) {\n        case 'inside':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n            break;\n        case 'top':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y - domHeight - gap;\n            break;\n        case 'bottom':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y + rectHeight + gap;\n            break;\n        case 'left':\n            x = rect.x - domWidth - gap;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n            break;\n        case 'right':\n            x = rect.x + rectWidth + gap;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n    }\n    return [x, y];\n}\n\nfunction isCenterAlign(align) {\n    return align === 'center' || align === 'middle';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME Better way to pack data in graphic element\n\n/**\n * @action\n * @property {string} type\n * @property {number} seriesIndex\n * @property {number} dataIndex\n * @property {number} [x]\n * @property {number} [y]\n */\nregisterAction(\n    {\n        type: 'showTip',\n        event: 'showTip',\n        update: 'tooltip:manuallyShowTip'\n    },\n    // noop\n    function () {}\n);\n\nregisterAction(\n    {\n        type: 'hideTip',\n        event: 'hideTip',\n        update: 'tooltip:manuallyHideTip'\n    },\n    // noop\n    function () {}\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar LegendModel = extendComponentModel({\n\n    type: 'legend.plain',\n\n    dependencies: ['series'],\n\n    layoutMode: {\n        type: 'box',\n        // legend.width/height are maxWidth/maxHeight actually,\n        // whereas realy width/height is calculated by its content.\n        // (Setting {left: 10, right: 10} does not make sense).\n        // So consider the case:\n        // `setOption({legend: {left: 10});`\n        // then `setOption({legend: {right: 10});`\n        // The previous `left` should be cleared by setting `ignoreSize`.\n        ignoreSize: true\n    },\n\n    init: function (option, parentModel, ecModel) {\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        option.selected = option.selected || {};\n    },\n\n    mergeOption: function (option) {\n        LegendModel.superCall(this, 'mergeOption', option);\n    },\n\n    optionUpdated: function () {\n        this._updateData(this.ecModel);\n\n        var legendData = this._data;\n\n        // If selectedMode is single, try to select one\n        if (legendData[0] && this.get('selectedMode') === 'single') {\n            var hasSelected = false;\n            // If has any selected in option.selected\n            for (var i = 0; i < legendData.length; i++) {\n                var name = legendData[i].get('name');\n                if (this.isSelected(name)) {\n                    // Force to unselect others\n                    this.select(name);\n                    hasSelected = true;\n                    break;\n                }\n            }\n            // Try select the first if selectedMode is single\n            !hasSelected && this.select(legendData[0].get('name'));\n        }\n    },\n\n    _updateData: function (ecModel) {\n        var potentialData = [];\n        var availableNames = [];\n\n        ecModel.eachRawSeries(function (seriesModel) {\n            var seriesName = seriesModel.name;\n            availableNames.push(seriesName);\n            var isPotential;\n\n            if (seriesModel.legendDataProvider) {\n                var data = seriesModel.legendDataProvider();\n                var names = data.mapArray(data.getName);\n\n                if (!ecModel.isSeriesFiltered(seriesModel)) {\n                    availableNames = availableNames.concat(names);\n                }\n\n                if (names.length) {\n                    potentialData = potentialData.concat(names);\n                }\n                else {\n                    isPotential = true;\n                }\n            }\n            else {\n                isPotential = true;\n            }\n\n            if (isPotential && isNameSpecified(seriesModel)) {\n                potentialData.push(seriesModel.name);\n            }\n        });\n\n        /**\n         * @type {Array.<string>}\n         * @private\n         */\n        this._availableNames = availableNames;\n\n        // If legend.data not specified in option, use availableNames as data,\n        // which is convinient for user preparing option.\n        var rawData = this.get('data') || potentialData;\n\n        var legendData = map(rawData, function (dataItem) {\n            // Can be string or number\n            if (typeof dataItem === 'string' || typeof dataItem === 'number') {\n                dataItem = {\n                    name: dataItem\n                };\n            }\n            return new Model(dataItem, this, this.ecModel);\n        }, this);\n\n        /**\n         * @type {Array.<module:echarts/model/Model>}\n         * @private\n         */\n        this._data = legendData;\n    },\n\n    /**\n     * @return {Array.<module:echarts/model/Model>}\n     */\n    getData: function () {\n        return this._data;\n    },\n\n    /**\n     * @param {string} name\n     */\n    select: function (name) {\n        var selected = this.option.selected;\n        var selectedMode = this.get('selectedMode');\n        if (selectedMode === 'single') {\n            var data = this._data;\n            each$1(data, function (dataItem) {\n                selected[dataItem.get('name')] = false;\n            });\n        }\n        selected[name] = true;\n    },\n\n    /**\n     * @param {string} name\n     */\n    unSelect: function (name) {\n        if (this.get('selectedMode') !== 'single') {\n            this.option.selected[name] = false;\n        }\n    },\n\n    /**\n     * @param {string} name\n     */\n    toggleSelected: function (name) {\n        var selected = this.option.selected;\n        // Default is true\n        if (!selected.hasOwnProperty(name)) {\n            selected[name] = true;\n        }\n        this[selected[name] ? 'unSelect' : 'select'](name);\n    },\n\n    /**\n     * @param {string} name\n     */\n    isSelected: function (name) {\n        var selected = this.option.selected;\n        return !(selected.hasOwnProperty(name) && !selected[name])\n            && indexOf(this._availableNames, name) >= 0;\n    },\n\n    defaultOption: {\n        // 一级层叠\n        zlevel: 0,\n        // 二级层叠\n        z: 4,\n        show: true,\n\n        // 布局方式，默认为水平布局，可选为：\n        // 'horizontal' | 'vertical'\n        orient: 'horizontal',\n\n        left: 'center',\n        // right: 'center',\n\n        top: 0,\n        // bottom: null,\n\n        // 水平对齐\n        // 'auto' | 'left' | 'right'\n        // 默认为 'auto', 根据 x 的位置判断是左对齐还是右对齐\n        align: 'auto',\n\n        backgroundColor: 'rgba(0,0,0,0)',\n        // 图例边框颜色\n        borderColor: '#ccc',\n        borderRadius: 0,\n        // 图例边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n        // 图例内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n        // 各个item之间的间隔，单位px，默认为10，\n        // 横向布局时为水平间隔，纵向布局时为纵向间隔\n        itemGap: 10,\n        // 图例图形宽度\n        itemWidth: 25,\n        // 图例图形高度\n        itemHeight: 14,\n\n        // 图例关闭时候的颜色\n        inactiveColor: '#ccc',\n\n        textStyle: {\n            // 图例文字颜色\n            color: '#333'\n        },\n        // formatter: '',\n        // 选择模式，默认开启图例开关\n        selectedMode: true,\n        // 配置默认选中状态，可配合LEGEND.SELECTED事件做动态数据载入\n        // selected: null,\n        // 图例内容（详见legend.data，数组中每一项代表一个item\n        // data: [],\n\n        // Tooltip 相关配置\n        tooltip: {\n            show: false\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction legendSelectActionHandler(methodName, payload, ecModel) {\n    var selectedMap = {};\n    var isToggleSelect = methodName === 'toggleSelected';\n    var isSelected;\n    // Update all legend components\n    ecModel.eachComponent('legend', function (legendModel) {\n        if (isToggleSelect && isSelected != null) {\n            // Force other legend has same selected status\n            // Or the first is toggled to true and other are toggled to false\n            // In the case one legend has some item unSelected in option. And if other legend\n            // doesn't has the item, they will assume it is selected.\n            legendModel[isSelected ? 'select' : 'unSelect'](payload.name);\n        }\n        else {\n            legendModel[methodName](payload.name);\n            isSelected = legendModel.isSelected(payload.name);\n        }\n        var legendData = legendModel.getData();\n        each$1(legendData, function (model) {\n            var name = model.get('name');\n            // Wrap element\n            if (name === '\\n' || name === '') {\n                return;\n            }\n            var isItemSelected = legendModel.isSelected(name);\n            if (selectedMap.hasOwnProperty(name)) {\n                // Unselected if any legend is unselected\n                selectedMap[name] = selectedMap[name] && isItemSelected;\n            }\n            else {\n                selectedMap[name] = isItemSelected;\n            }\n        });\n    });\n    // Return the event explicitly\n    return {\n        name: payload.name,\n        selected: selectedMap\n    };\n}\n/**\n * @event legendToggleSelect\n * @type {Object}\n * @property {string} type 'legendToggleSelect'\n * @property {string} [from]\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendToggleSelect', 'legendselectchanged',\n    curry(legendSelectActionHandler, 'toggleSelected')\n);\n\n/**\n * @event legendSelect\n * @type {Object}\n * @property {string} type 'legendSelect'\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendSelect', 'legendselected',\n    curry(legendSelectActionHandler, 'select')\n);\n\n/**\n * @event legendUnSelect\n * @type {Object}\n * @property {string} type 'legendUnSelect'\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendUnSelect', 'legendunselected',\n    curry(legendSelectActionHandler, 'unSelect')\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Layout list like component.\n * It will box layout each items in group of component and then position the whole group in the viewport\n * @param {module:zrender/group/Group} group\n * @param {module:echarts/model/Component} componentModel\n * @param {module:echarts/ExtensionAPI}\n */\nfunction layout$2(group, componentModel, api) {\n    var boxLayoutParams = componentModel.getBoxLayoutParams();\n    var padding = componentModel.get('padding');\n    var viewportSize = {width: api.getWidth(), height: api.getHeight()};\n\n    var rect = getLayoutRect(\n        boxLayoutParams,\n        viewportSize,\n        padding\n    );\n\n    box(\n        componentModel.get('orient'),\n        group,\n        componentModel.get('itemGap'),\n        rect.width,\n        rect.height\n    );\n\n    positionElement(\n        group,\n        boxLayoutParams,\n        viewportSize,\n        padding\n    );\n}\n\nfunction makeBackground(rect, componentModel) {\n    var padding = normalizeCssArray$1(\n        componentModel.get('padding')\n    );\n    var style = componentModel.getItemStyle(['color', 'opacity']);\n    style.fill = componentModel.get('backgroundColor');\n    var rect = new Rect({\n        shape: {\n            x: rect.x - padding[3],\n            y: rect.y - padding[0],\n            width: rect.width + padding[1] + padding[3],\n            height: rect.height + padding[0] + padding[2],\n            r: componentModel.get('borderRadius')\n        },\n        style: style,\n        silent: true,\n        z2: -1\n    });\n    // FIXME\n    // `subPixelOptimizeRect` may bring some gap between edge of viewpart\n    // and background rect when setting like `left: 0`, `top: 0`.\n    // graphic.subPixelOptimizeRect(rect);\n\n    return rect;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar curry$3 = curry;\nvar each$11 = each$1;\nvar Group$2 = Group;\n\nvar LegendView = extendComponentView({\n\n    type: 'legend.plain',\n\n    newlineDisabled: false,\n\n    /**\n     * @override\n     */\n    init: function () {\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._contentGroup = new Group$2());\n\n        /**\n         * @private\n         * @type {module:zrender/Element}\n         */\n        this._backgroundEl;\n\n        /**\n         * If first rendering, `contentGroup.position` is [0, 0], which\n         * does not make sense and may cause unexepcted animation if adopted.\n         * @private\n         * @type {boolean}\n         */\n        this._isFirstRender = true;\n    },\n\n    /**\n     * @protected\n     */\n    getContentGroup: function () {\n        return this._contentGroup;\n    },\n\n    /**\n     * @override\n     */\n    render: function (legendModel, ecModel, api) {\n        var isFirstRender = this._isFirstRender;\n        this._isFirstRender = false;\n\n        this.resetInner();\n\n        if (!legendModel.get('show', true)) {\n            return;\n        }\n\n        var itemAlign = legendModel.get('align');\n        if (!itemAlign || itemAlign === 'auto') {\n            itemAlign = (\n                legendModel.get('left') === 'right'\n                && legendModel.get('orient') === 'vertical'\n            ) ? 'right' : 'left';\n        }\n\n        this.renderInner(itemAlign, legendModel, ecModel, api);\n\n        // Perform layout.\n        var positionInfo = legendModel.getBoxLayoutParams();\n        var viewportSize = {width: api.getWidth(), height: api.getHeight()};\n        var padding = legendModel.get('padding');\n\n        var maxSize = getLayoutRect(positionInfo, viewportSize, padding);\n\n        var mainRect = this.layoutInner(legendModel, itemAlign, maxSize, isFirstRender);\n\n        // Place mainGroup, based on the calculated `mainRect`.\n        var layoutRect = getLayoutRect(\n            defaults({width: mainRect.width, height: mainRect.height}, positionInfo),\n            viewportSize,\n            padding\n        );\n        this.group.attr('position', [layoutRect.x - mainRect.x, layoutRect.y - mainRect.y]);\n\n        // Render background after group is layout.\n        this.group.add(\n            this._backgroundEl = makeBackground(mainRect, legendModel)\n        );\n    },\n\n    /**\n     * @protected\n     */\n    resetInner: function () {\n        this.getContentGroup().removeAll();\n        this._backgroundEl && this.group.remove(this._backgroundEl);\n    },\n\n    /**\n     * @protected\n     */\n    renderInner: function (itemAlign, legendModel, ecModel, api) {\n        var contentGroup = this.getContentGroup();\n        var legendDrawnMap = createHashMap();\n        var selectMode = legendModel.get('selectedMode');\n\n        var excludeSeriesId = [];\n        ecModel.eachRawSeries(function (seriesModel) {\n            !seriesModel.get('legendHoverLink') && excludeSeriesId.push(seriesModel.id);\n        });\n\n        each$11(legendModel.getData(), function (itemModel, dataIndex) {\n            var name = itemModel.get('name');\n\n            // Use empty string or \\n as a newline string\n            if (!this.newlineDisabled && (name === '' || name === '\\n')) {\n                contentGroup.add(new Group$2({\n                    newline: true\n                }));\n                return;\n            }\n\n            // Representitive series.\n            var seriesModel = ecModel.getSeriesByName(name)[0];\n\n            if (legendDrawnMap.get(name)) {\n                // Have been drawed\n                return;\n            }\n\n            // Series legend\n            if (seriesModel) {\n                var data = seriesModel.getData();\n                var color = data.getVisual('color');\n\n                // If color is a callback function\n                if (typeof color === 'function') {\n                    // Use the first data\n                    color = color(seriesModel.getDataParams(0));\n                }\n\n                // Using rect symbol defaultly\n                var legendSymbolType = data.getVisual('legendSymbol') || 'roundRect';\n                var symbolType = data.getVisual('symbol');\n\n                var itemGroup = this._createItem(\n                    name, dataIndex, itemModel, legendModel,\n                    legendSymbolType, symbolType,\n                    itemAlign, color,\n                    selectMode\n                );\n\n                itemGroup.on('click', curry$3(dispatchSelectAction, name, api))\n                    .on('mouseover', curry$3(dispatchHighlightAction, seriesModel.name, null, api, excludeSeriesId))\n                    .on('mouseout', curry$3(dispatchDownplayAction, seriesModel.name, null, api, excludeSeriesId));\n\n                legendDrawnMap.set(name, true);\n            }\n            else {\n                // Data legend of pie, funnel\n                ecModel.eachRawSeries(function (seriesModel) {\n                    // In case multiple series has same data name\n                    if (legendDrawnMap.get(name)) {\n                        return;\n                    }\n\n                    if (seriesModel.legendDataProvider) {\n                        var data = seriesModel.legendDataProvider();\n                        var idx = data.indexOfName(name);\n                        if (idx < 0) {\n                            return;\n                        }\n\n                        var color = data.getItemVisual(idx, 'color');\n\n                        var legendSymbolType = 'roundRect';\n\n                        var itemGroup = this._createItem(\n                            name, dataIndex, itemModel, legendModel,\n                            legendSymbolType, null,\n                            itemAlign, color,\n                            selectMode\n                        );\n\n                        // FIXME: consider different series has items with the same name.\n                        itemGroup.on('click', curry$3(dispatchSelectAction, name, api))\n                            // Should not specify the series name, consider legend controls\n                            // more than one pie series.\n                            .on('mouseover', curry$3(dispatchHighlightAction, null, name, api, excludeSeriesId))\n                            .on('mouseout', curry$3(dispatchDownplayAction, null, name, api, excludeSeriesId));\n\n                        legendDrawnMap.set(name, true);\n                    }\n\n                }, this);\n            }\n\n            if (__DEV__) {\n                if (!legendDrawnMap.get(name)) {\n                    console.warn(\n                        name + ' series not exists. Legend data should be same with series name or data name.'\n                    );\n                }\n            }\n        }, this);\n    },\n\n    _createItem: function (\n        name, dataIndex, itemModel, legendModel,\n        legendSymbolType, symbolType,\n        itemAlign, color, selectMode\n    ) {\n        var itemWidth = legendModel.get('itemWidth');\n        var itemHeight = legendModel.get('itemHeight');\n        var inactiveColor = legendModel.get('inactiveColor');\n        var symbolKeepAspect = legendModel.get('symbolKeepAspect');\n\n        var isSelected = legendModel.isSelected(name);\n        var itemGroup = new Group$2();\n\n        var textStyleModel = itemModel.getModel('textStyle');\n\n        var itemIcon = itemModel.get('icon');\n\n        var tooltipModel = itemModel.getModel('tooltip');\n        var legendGlobalTooltipModel = tooltipModel.parentModel;\n\n        // Use user given icon first\n        legendSymbolType = itemIcon || legendSymbolType;\n        itemGroup.add(createSymbol(\n            legendSymbolType,\n            0,\n            0,\n            itemWidth,\n            itemHeight,\n            isSelected ? color : inactiveColor,\n            // symbolKeepAspect default true for legend\n            symbolKeepAspect == null ? true : symbolKeepAspect\n        ));\n\n        // Compose symbols\n        // PENDING\n        if (!itemIcon && symbolType\n            // At least show one symbol, can't be all none\n            && ((symbolType !== legendSymbolType) || symbolType === 'none')\n        ) {\n            var size = itemHeight * 0.8;\n            if (symbolType === 'none') {\n                symbolType = 'circle';\n            }\n            // Put symbol in the center\n            itemGroup.add(createSymbol(\n                symbolType,\n                (itemWidth - size) / 2,\n                (itemHeight - size) / 2,\n                size,\n                size,\n                isSelected ? color : inactiveColor,\n                // symbolKeepAspect default true for legend\n                symbolKeepAspect == null ? true : symbolKeepAspect\n            ));\n        }\n\n        var textX = itemAlign === 'left' ? itemWidth + 5 : -5;\n        var textAlign = itemAlign;\n\n        var formatter = legendModel.get('formatter');\n        var content = name;\n        if (typeof formatter === 'string' && formatter) {\n            content = formatter.replace('{name}', name != null ? name : '');\n        }\n        else if (typeof formatter === 'function') {\n            content = formatter(name);\n        }\n\n        itemGroup.add(new Text({\n            style: setTextStyle({}, textStyleModel, {\n                text: content,\n                x: textX,\n                y: itemHeight / 2,\n                textFill: isSelected ? textStyleModel.getTextColor() : inactiveColor,\n                textAlign: textAlign,\n                textVerticalAlign: 'middle'\n            })\n        }));\n\n        // Add a invisible rect to increase the area of mouse hover\n        var hitRect = new Rect({\n            shape: itemGroup.getBoundingRect(),\n            invisible: true,\n            tooltip: tooltipModel.get('show') ? extend({\n                content: name,\n                // Defaul formatter\n                formatter: legendGlobalTooltipModel.get('formatter', true) || function () {\n                    return name;\n                },\n                formatterParams: {\n                    componentType: 'legend',\n                    legendIndex: legendModel.componentIndex,\n                    name: name,\n                    $vars: ['name']\n                }\n            }, tooltipModel.option) : null\n        });\n        itemGroup.add(hitRect);\n\n        itemGroup.eachChild(function (child) {\n            child.silent = true;\n        });\n\n        hitRect.silent = !selectMode;\n\n        this.getContentGroup().add(itemGroup);\n\n        setHoverStyle(itemGroup);\n\n        itemGroup.__legendDataIndex = dataIndex;\n\n        return itemGroup;\n    },\n\n    /**\n     * @protected\n     */\n    layoutInner: function (legendModel, itemAlign, maxSize) {\n        var contentGroup = this.getContentGroup();\n\n        // Place items in contentGroup.\n        box(\n            legendModel.get('orient'),\n            contentGroup,\n            legendModel.get('itemGap'),\n            maxSize.width,\n            maxSize.height\n        );\n\n        var contentRect = contentGroup.getBoundingRect();\n        contentGroup.attr('position', [-contentRect.x, -contentRect.y]);\n\n        return this.group.getBoundingRect();\n    },\n\n    /**\n     * @protected\n     */\n    remove: function () {\n        this.getContentGroup().removeAll();\n        this._isFirstRender = true;\n    }\n\n});\n\nfunction dispatchSelectAction(name, api) {\n    api.dispatchAction({\n        type: 'legendToggleSelect',\n        name: name\n    });\n}\n\nfunction dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId) {\n    // If element hover will move to a hoverLayer.\n    var el = api.getZr().storage.getDisplayList()[0];\n    if (!(el && el.useHoverLayer)) {\n        api.dispatchAction({\n            type: 'highlight',\n            seriesName: seriesName,\n            name: dataName,\n            excludeSeriesId: excludeSeriesId\n        });\n    }\n}\n\nfunction dispatchDownplayAction(seriesName, dataName, api, excludeSeriesId) {\n    // If element hover will move to a hoverLayer.\n    var el = api.getZr().storage.getDisplayList()[0];\n    if (!(el && el.useHoverLayer)) {\n        api.dispatchAction({\n            type: 'downplay',\n            seriesName: seriesName,\n            name: dataName,\n            excludeSeriesId: excludeSeriesId\n        });\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar legendFilter = function (ecModel) {\n\n    var legendModels = ecModel.findComponents({\n        mainType: 'legend'\n    });\n    if (legendModels && legendModels.length) {\n        ecModel.filterSeries(function (series) {\n            // If in any legend component the status is not selected.\n            // Because in legend series is assumed selected when it is not in the legend data.\n            for (var i = 0; i < legendModels.length; i++) {\n                if (!legendModels[i].isSelected(series.name)) {\n                    return false;\n                }\n            }\n            return true;\n        });\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n// Do not contain scrollable legend, for sake of file size.\n\n// Series Filter\nregisterProcessor(legendFilter);\n\nComponentModel.registerSubTypeDefaulter('legend', function () {\n    // Default 'plain' when no type specified.\n    return 'plain';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ScrollableLegendModel = LegendModel.extend({\n\n    type: 'legend.scroll',\n\n    /**\n     * @param {number} scrollDataIndex\n     */\n    setScrollDataIndex: function (scrollDataIndex) {\n        this.option.scrollDataIndex = scrollDataIndex;\n    },\n\n    defaultOption: {\n        scrollDataIndex: 0,\n        pageButtonItemGap: 5,\n        pageButtonGap: null,\n        pageButtonPosition: 'end', // 'start' or 'end'\n        pageFormatter: '{current}/{total}', // If null/undefined, do not show page.\n        pageIcons: {\n            horizontal: ['M0,0L12,-10L12,10z', 'M0,0L-12,-10L-12,10z'],\n            vertical: ['M0,0L20,0L10,-20z', 'M0,0L20,0L10,20z']\n        },\n        pageIconColor: '#2f4554',\n        pageIconInactiveColor: '#aaa',\n        pageIconSize: 15, // Can be [10, 3], which represents [width, height]\n        pageTextStyle: {\n            color: '#333'\n        },\n\n        animationDurationUpdate: 800\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel, extraOpt) {\n        var inputPositionParams = getLayoutParams(option);\n\n        ScrollableLegendModel.superCall(this, 'init', option, parentModel, ecModel, extraOpt);\n\n        mergeAndNormalizeLayoutParams(this, option, inputPositionParams);\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (option, extraOpt) {\n        ScrollableLegendModel.superCall(this, 'mergeOption', option, extraOpt);\n\n        mergeAndNormalizeLayoutParams(this, this.option, option);\n    },\n\n    getOrient: function () {\n        return this.get('orient') === 'vertical'\n            ? {index: 1, name: 'vertical'}\n            : {index: 0, name: 'horizontal'};\n    }\n\n});\n\n// Do not `ignoreSize` to enable setting {left: 10, right: 10}.\nfunction mergeAndNormalizeLayoutParams(legendModel, target, raw) {\n    var orient = legendModel.getOrient();\n    var ignoreSize = [1, 1];\n    ignoreSize[orient.index] = 0;\n    mergeLayoutParam(target, raw, {\n        type: 'box', ignoreSize: ignoreSize\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Separate legend and scrollable legend to reduce package size.\n */\n\nvar Group$3 = Group;\n\nvar WH = ['width', 'height'];\nvar XY = ['x', 'y'];\n\nvar ScrollableLegendView = LegendView.extend({\n\n    type: 'legend.scroll',\n\n    newlineDisabled: true,\n\n    init: function () {\n\n        ScrollableLegendView.superCall(this, 'init');\n\n        /**\n         * @private\n         * @type {number} For `scroll`.\n         */\n        this._currentIndex = 0;\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._containerGroup = new Group$3());\n        this._containerGroup.add(this.getContentGroup());\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._controllerGroup = new Group$3());\n\n        /**\n         *\n         * @private\n         */\n        this._showController;\n    },\n\n    /**\n     * @override\n     */\n    resetInner: function () {\n        ScrollableLegendView.superCall(this, 'resetInner');\n\n        this._controllerGroup.removeAll();\n        this._containerGroup.removeClipPath();\n        this._containerGroup.__rectSize = null;\n    },\n\n    /**\n     * @override\n     */\n    renderInner: function (itemAlign, legendModel, ecModel, api) {\n        var me = this;\n\n        // Render content items.\n        ScrollableLegendView.superCall(this, 'renderInner', itemAlign, legendModel, ecModel, api);\n\n        var controllerGroup = this._controllerGroup;\n\n        // FIXME: support be 'auto' adapt to size number text length,\n        // e.g., '3/12345' should not overlap with the control arrow button.\n        var pageIconSize = legendModel.get('pageIconSize', true);\n        if (!isArray(pageIconSize)) {\n            pageIconSize = [pageIconSize, pageIconSize];\n        }\n\n        createPageButton('pagePrev', 0);\n\n        var pageTextStyleModel = legendModel.getModel('pageTextStyle');\n        controllerGroup.add(new Text({\n            name: 'pageText',\n            style: {\n                textFill: pageTextStyleModel.getTextColor(),\n                font: pageTextStyleModel.getFont(),\n                textVerticalAlign: 'middle',\n                textAlign: 'center'\n            },\n            silent: true\n        }));\n\n        createPageButton('pageNext', 1);\n\n        function createPageButton(name, iconIdx) {\n            var pageDataIndexName = name + 'DataIndex';\n            var icon = createIcon(\n                legendModel.get('pageIcons', true)[legendModel.getOrient().name][iconIdx],\n                {\n                    // Buttons will be created in each render, so we do not need\n                    // to worry about avoiding using legendModel kept in scope.\n                    onclick: bind(\n                        me._pageGo, me, pageDataIndexName, legendModel, api\n                    )\n                },\n                {\n                    x: -pageIconSize[0] / 2,\n                    y: -pageIconSize[1] / 2,\n                    width: pageIconSize[0],\n                    height: pageIconSize[1]\n                }\n            );\n            icon.name = name;\n            controllerGroup.add(icon);\n        }\n    },\n\n    /**\n     * @override\n     */\n    layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender) {\n        var contentGroup = this.getContentGroup();\n        var containerGroup = this._containerGroup;\n        var controllerGroup = this._controllerGroup;\n\n        var orientIdx = legendModel.getOrient().index;\n        var wh = WH[orientIdx];\n        var hw = WH[1 - orientIdx];\n        var yx = XY[1 - orientIdx];\n\n        // Place items in contentGroup.\n        box(\n            legendModel.get('orient'),\n            contentGroup,\n            legendModel.get('itemGap'),\n            !orientIdx ? null : maxSize.width,\n            orientIdx ? null : maxSize.height\n        );\n\n        box(\n            // Buttons in controller are layout always horizontally.\n            'horizontal',\n            controllerGroup,\n            legendModel.get('pageButtonItemGap', true)\n        );\n\n        var contentRect = contentGroup.getBoundingRect();\n        var controllerRect = controllerGroup.getBoundingRect();\n        var showController = this._showController = contentRect[wh] > maxSize[wh];\n\n        var contentPos = [-contentRect.x, -contentRect.y];\n        // Remain contentPos when scroll animation perfroming.\n        // If first rendering, `contentGroup.position` is [0, 0], which\n        // does not make sense and may cause unexepcted animation if adopted.\n        if (!isFirstRender) {\n            contentPos[orientIdx] = contentGroup.position[orientIdx];\n        }\n\n        // Layout container group based on 0.\n        var containerPos = [0, 0];\n        var controllerPos = [-controllerRect.x, -controllerRect.y];\n        var pageButtonGap = retrieve2(\n            legendModel.get('pageButtonGap', true), legendModel.get('itemGap', true)\n        );\n\n        // Place containerGroup and controllerGroup and contentGroup.\n        if (showController) {\n            var pageButtonPosition = legendModel.get('pageButtonPosition', true);\n            // controller is on the right / bottom.\n            if (pageButtonPosition === 'end') {\n                controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh];\n            }\n            // controller is on the left / top.\n            else {\n                containerPos[orientIdx] += controllerRect[wh] + pageButtonGap;\n            }\n        }\n\n        // Always align controller to content as 'middle'.\n        controllerPos[1 - orientIdx] += contentRect[hw] / 2 - controllerRect[hw] / 2;\n\n        contentGroup.attr('position', contentPos);\n        containerGroup.attr('position', containerPos);\n        controllerGroup.attr('position', controllerPos);\n\n        // Calculate `mainRect` and set `clipPath`.\n        // mainRect should not be calculated by `this.group.getBoundingRect()`\n        // for sake of the overflow.\n        var mainRect = this.group.getBoundingRect();\n        var mainRect = {x: 0, y: 0};\n        // Consider content may be overflow (should be clipped).\n        mainRect[wh] = showController ? maxSize[wh] : contentRect[wh];\n        mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw]);\n        // `containerRect[yx] + containerPos[1 - orientIdx]` is 0.\n        mainRect[yx] = Math.min(0, controllerRect[yx] + controllerPos[1 - orientIdx]);\n\n        containerGroup.__rectSize = maxSize[wh];\n        if (showController) {\n            var clipShape = {x: 0, y: 0};\n            clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap, 0);\n            clipShape[hw] = mainRect[hw];\n            containerGroup.setClipPath(new Rect({shape: clipShape}));\n            // Consider content may be larger than container, container rect\n            // can not be obtained from `containerGroup.getBoundingRect()`.\n            containerGroup.__rectSize = clipShape[wh];\n        }\n        else {\n            // Do not remove or ignore controller. Keep them set as place holders.\n            controllerGroup.eachChild(function (child) {\n                child.attr({invisible: true, silent: true});\n            });\n        }\n\n        // Content translate animation.\n        var pageInfo = this._getPageInfo(legendModel);\n        pageInfo.pageIndex != null && updateProps(\n            contentGroup,\n            {position: pageInfo.contentPosition},\n            // When switch from \"show controller\" to \"not show controller\", view should be\n            // updated immediately without animation, otherwise causes weird efffect.\n            showController ? legendModel : false\n        );\n\n        this._updatePageInfoView(legendModel, pageInfo);\n\n        return mainRect;\n    },\n\n    _pageGo: function (to, legendModel, api) {\n        var scrollDataIndex = this._getPageInfo(legendModel)[to];\n\n        scrollDataIndex != null && api.dispatchAction({\n            type: 'legendScroll',\n            scrollDataIndex: scrollDataIndex,\n            legendId: legendModel.id\n        });\n    },\n\n    _updatePageInfoView: function (legendModel, pageInfo) {\n        var controllerGroup = this._controllerGroup;\n\n        each$1(['pagePrev', 'pageNext'], function (name) {\n            var canJump = pageInfo[name + 'DataIndex'] != null;\n            var icon = controllerGroup.childOfName(name);\n            if (icon) {\n                icon.setStyle(\n                    'fill',\n                    canJump\n                        ? legendModel.get('pageIconColor', true)\n                        : legendModel.get('pageIconInactiveColor', true)\n                );\n                icon.cursor = canJump ? 'pointer' : 'default';\n            }\n        });\n\n        var pageText = controllerGroup.childOfName('pageText');\n        var pageFormatter = legendModel.get('pageFormatter');\n        var pageIndex = pageInfo.pageIndex;\n        var current = pageIndex != null ? pageIndex + 1 : 0;\n        var total = pageInfo.pageCount;\n\n        pageText && pageFormatter && pageText.setStyle(\n            'text',\n            isString(pageFormatter)\n                ? pageFormatter.replace('{current}', current).replace('{total}', total)\n                : pageFormatter({current: current, total: total})\n        );\n    },\n\n    /**\n     * @param {module:echarts/model/Model} legendModel\n     * @return {Object} {\n     *  contentPosition: Array.<number>, null when data item not found.\n     *  pageIndex: number, null when data item not found.\n     *  pageCount: number, always be a number, can be 0.\n     *  pagePrevDataIndex: number, null when no next page.\n     *  pageNextDataIndex: number, null when no previous page.\n     * }\n     */\n    _getPageInfo: function (legendModel) {\n        var scrollDataIndex = legendModel.get('scrollDataIndex', true);\n        var contentGroup = this.getContentGroup();\n        var containerRectSize = this._containerGroup.__rectSize;\n        var orientIdx = legendModel.getOrient().index;\n        var wh = WH[orientIdx];\n        var xy = XY[orientIdx];\n        var targetItemIndex = this._findTargetItemIndex(scrollDataIndex);\n        var children = contentGroup.children();\n        var targetItem = children[targetItemIndex];\n        var itemCount = children.length;\n        var pCount = !itemCount ? 0 : 1;\n\n        var result = {\n            contentPosition: contentGroup.position.slice(),\n            pageCount: pCount,\n            pageIndex: pCount - 1,\n            pagePrevDataIndex: null,\n            pageNextDataIndex: null\n        };\n\n        if (!targetItem) {\n            return result;\n        }\n\n        var targetItemInfo = getItemInfo(targetItem);\n        result.contentPosition[orientIdx] = -targetItemInfo.s;\n\n        // Strategy:\n        // (1) Always align based on the left/top most item.\n        // (2) It is user-friendly that the last item shown in the\n        // current window is shown at the begining of next window.\n        // Otherwise if half of the last item is cut by the window,\n        // it will have no chance to display entirely.\n        // (3) Consider that item size probably be different, we\n        // have calculate pageIndex by size rather than item index,\n        // and we can not get page index directly by division.\n        // (4) The window is to narrow to contain more than\n        // one item, we should make sure that the page can be fliped.\n\n        for (var i = targetItemIndex + 1,\n            winStartItemInfo = targetItemInfo,\n            winEndItemInfo = targetItemInfo,\n            currItemInfo = null;\n            i <= itemCount;\n            ++i\n        ) {\n            currItemInfo = getItemInfo(children[i]);\n            if (\n                // Half of the last item is out of the window.\n                (!currItemInfo && winEndItemInfo.e > winStartItemInfo.s + containerRectSize)\n                // If the current item does not intersect with the window, the new page\n                // can be started at the current item or the last item.\n                || (currItemInfo && !intersect(currItemInfo, winStartItemInfo.s))\n            ) {\n                if (winEndItemInfo.i > winStartItemInfo.i) {\n                    winStartItemInfo = winEndItemInfo;\n                }\n                else { // e.g., when page size is smaller than item size.\n                    winStartItemInfo = currItemInfo;\n                }\n                if (winStartItemInfo) {\n                    if (result.pageNextDataIndex == null) {\n                        result.pageNextDataIndex = winStartItemInfo.i;\n                    }\n                    ++result.pageCount;\n                }\n            }\n            winEndItemInfo = currItemInfo;\n        }\n\n        for (var i = targetItemIndex - 1,\n            winStartItemInfo = targetItemInfo,\n            winEndItemInfo = targetItemInfo,\n            currItemInfo = null;\n            i >= -1;\n            --i\n        ) {\n            currItemInfo = getItemInfo(children[i]);\n            if (\n                // If the the end item does not intersect with the window started\n                // from the current item, a page can be settled.\n                (!currItemInfo || !intersect(winEndItemInfo, currItemInfo.s))\n                // e.g., when page size is smaller than item size.\n                && winStartItemInfo.i < winEndItemInfo.i\n            ) {\n                winEndItemInfo = winStartItemInfo;\n                if (result.pagePrevDataIndex == null) {\n                    result.pagePrevDataIndex = winStartItemInfo.i;\n                }\n                ++result.pageCount;\n                ++result.pageIndex;\n            }\n            winStartItemInfo = currItemInfo;\n        }\n\n        return result;\n\n        function getItemInfo(el) {\n            if (el) {\n                var itemRect = el.getBoundingRect();\n                var start = itemRect[xy] + el.position[orientIdx];\n                return {\n                    s: start,\n                    e: start + itemRect[wh],\n                    i: el.__legendDataIndex\n                };\n            }\n        }\n\n        function intersect(itemInfo, winStart) {\n            return itemInfo.e >= winStart && itemInfo.s <= winStart + containerRectSize;\n        }\n    },\n\n    _findTargetItemIndex: function (targetDataIndex) {\n        var index;\n        var contentGroup = this.getContentGroup();\n        if (this._showController) {\n            contentGroup.eachChild(function (child, idx) {\n                if (child.__legendDataIndex === targetDataIndex) {\n                    index = idx;\n                }\n            });\n        }\n        else {\n            index = 0;\n        }\n        return index;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @event legendScroll\n * @type {Object}\n * @property {string} type 'legendScroll'\n * @property {string} scrollDataIndex\n */\nregisterAction(\n    'legendScroll', 'legendscroll',\n    function (payload, ecModel) {\n        var scrollDataIndex = payload.scrollDataIndex;\n\n        scrollDataIndex != null && ecModel.eachComponent(\n            {mainType: 'legend', subType: 'scroll', query: payload},\n            function (legendModel) {\n                legendModel.setScrollDataIndex(scrollDataIndex);\n            }\n        );\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Legend component entry file8\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Model\nextendComponentModel({\n\n    type: 'title',\n\n    layoutMode: {type: 'box', ignoreSize: true},\n\n    defaultOption: {\n        // 一级层叠\n        zlevel: 0,\n        // 二级层叠\n        z: 6,\n        show: true,\n\n        text: '',\n        // 超链接跳转\n        // link: null,\n        // 仅支持self | blank\n        target: 'blank',\n        subtext: '',\n\n        // 超链接跳转\n        // sublink: null,\n        // 仅支持self | blank\n        subtarget: 'blank',\n\n        // 'center' ¦ 'left' ¦ 'right'\n        // ¦ {number}（x坐标，单位px）\n        left: 0,\n        // 'top' ¦ 'bottom' ¦ 'center'\n        // ¦ {number}（y坐标，单位px）\n        top: 0,\n\n        // 水平对齐\n        // 'auto' | 'left' | 'right' | 'center'\n        // 默认根据 left 的位置判断是左对齐还是右对齐\n        // textAlign: null\n        //\n        // 垂直对齐\n        // 'auto' | 'top' | 'bottom' | 'middle'\n        // 默认根据 top 位置判断是上对齐还是下对齐\n        // textBaseline: null\n\n        backgroundColor: 'rgba(0,0,0,0)',\n\n        // 标题边框颜色\n        borderColor: '#ccc',\n\n        // 标题边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n\n        // 标题内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n\n        // 主副标题纵向间隔，单位px，默认为10，\n        itemGap: 10,\n        textStyle: {\n            fontSize: 18,\n            fontWeight: 'bolder',\n            color: '#333'\n        },\n        subtextStyle: {\n            color: '#aaa'\n        }\n    }\n});\n\n// View\nextendComponentView({\n\n    type: 'title',\n\n    render: function (titleModel, ecModel, api) {\n        this.group.removeAll();\n\n        if (!titleModel.get('show')) {\n            return;\n        }\n\n        var group = this.group;\n\n        var textStyleModel = titleModel.getModel('textStyle');\n        var subtextStyleModel = titleModel.getModel('subtextStyle');\n\n        var textAlign = titleModel.get('textAlign');\n        var textBaseline = titleModel.get('textBaseline');\n\n        var textEl = new Text({\n            style: setTextStyle({}, textStyleModel, {\n                text: titleModel.get('text'),\n                textFill: textStyleModel.getTextColor()\n            }, {disableBox: true}),\n            z2: 10\n        });\n\n        var textRect = textEl.getBoundingRect();\n\n        var subText = titleModel.get('subtext');\n        var subTextEl = new Text({\n            style: setTextStyle({}, subtextStyleModel, {\n                text: subText,\n                textFill: subtextStyleModel.getTextColor(),\n                y: textRect.height + titleModel.get('itemGap'),\n                textVerticalAlign: 'top'\n            }, {disableBox: true}),\n            z2: 10\n        });\n\n        var link = titleModel.get('link');\n        var sublink = titleModel.get('sublink');\n        var triggerEvent = titleModel.get('triggerEvent', true);\n\n        textEl.silent = !link && !triggerEvent;\n        subTextEl.silent = !sublink && !triggerEvent;\n\n        if (link) {\n            textEl.on('click', function () {\n                window.open(link, '_' + titleModel.get('target'));\n            });\n        }\n        if (sublink) {\n            subTextEl.on('click', function () {\n                window.open(sublink, '_' + titleModel.get('subtarget'));\n            });\n        }\n\n        textEl.eventData = subTextEl.eventData = triggerEvent\n            ? {\n                componentType: 'title',\n                componentIndex: titleModel.componentIndex\n            }\n            : null;\n\n        group.add(textEl);\n        subText && group.add(subTextEl);\n        // If no subText, but add subTextEl, there will be an empty line.\n\n        var groupRect = group.getBoundingRect();\n        var layoutOption = titleModel.getBoxLayoutParams();\n        layoutOption.width = groupRect.width;\n        layoutOption.height = groupRect.height;\n        var layoutRect = getLayoutRect(\n            layoutOption, {\n                width: api.getWidth(),\n                height: api.getHeight()\n            }, titleModel.get('padding')\n        );\n        // Adjust text align based on position\n        if (!textAlign) {\n            // Align left if title is on the left. center and right is same\n            textAlign = titleModel.get('left') || titleModel.get('right');\n            if (textAlign === 'middle') {\n                textAlign = 'center';\n            }\n            // Adjust layout by text align\n            if (textAlign === 'right') {\n                layoutRect.x += layoutRect.width;\n            }\n            else if (textAlign === 'center') {\n                layoutRect.x += layoutRect.width / 2;\n            }\n        }\n        if (!textBaseline) {\n            textBaseline = titleModel.get('top') || titleModel.get('bottom');\n            if (textBaseline === 'center') {\n                textBaseline = 'middle';\n            }\n            if (textBaseline === 'bottom') {\n                layoutRect.y += layoutRect.height;\n            }\n            else if (textBaseline === 'middle') {\n                layoutRect.y += layoutRect.height / 2;\n            }\n\n            textBaseline = textBaseline || 'top';\n        }\n\n        group.attr('position', [layoutRect.x, layoutRect.y]);\n        var alignStyle = {\n            textAlign: textAlign,\n            textVerticalAlign: textBaseline\n        };\n        textEl.setStyle(alignStyle);\n        subTextEl.setStyle(alignStyle);\n\n        // Render background\n        // Get groupRect again because textAlign has been changed\n        groupRect = group.getBoundingRect();\n        var padding = layoutRect.margin;\n        var style = titleModel.getItemStyle(['color', 'opacity']);\n        style.fill = titleModel.get('backgroundColor');\n        var rect = new Rect({\n            shape: {\n                x: groupRect.x - padding[3],\n                y: groupRect.y - padding[0],\n                width: groupRect.width + padding[1] + padding[3],\n                height: groupRect.height + padding[0] + padding[2],\n                r: titleModel.get('borderRadius')\n            },\n            style: style,\n            silent: true\n        });\n        subPixelOptimizeRect(rect);\n\n        group.add(rect);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar addCommas$1 = addCommas;\nvar encodeHTML$1 = encodeHTML;\n\nfunction fillLabel(opt) {\n    defaultEmphasis(opt, 'label', ['show']);\n}\nvar MarkerModel = extendComponentModel({\n\n    type: 'marker',\n\n    dependencies: ['series', 'grid', 'polar', 'geo'],\n\n    /**\n     * @overrite\n     */\n    init: function (option, parentModel, ecModel, extraOpt) {\n\n        if (__DEV__) {\n            if (this.type === 'marker') {\n                throw new Error('Marker component is abstract component. Use markLine, markPoint, markArea instead.');\n            }\n        }\n        this.mergeDefaultAndTheme(option, ecModel);\n        this.mergeOption(option, ecModel, extraOpt.createdBySelf, true);\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isAnimationEnabled: function () {\n        if (env$1.node) {\n            return false;\n        }\n\n        var hostSeries = this.__hostSeries;\n        return this.getShallow('animation') && hostSeries && hostSeries.isAnimationEnabled();\n    },\n\n    mergeOption: function (newOpt, ecModel, createdBySelf, isInit) {\n        var MarkerModel = this.constructor;\n        var modelPropName = this.mainType + 'Model';\n        if (!createdBySelf) {\n            ecModel.eachSeries(function (seriesModel) {\n\n                var markerOpt = seriesModel.get(this.mainType, true);\n\n                var markerModel = seriesModel[modelPropName];\n                if (!markerOpt || !markerOpt.data) {\n                    seriesModel[modelPropName] = null;\n                    return;\n                }\n                if (!markerModel) {\n                    if (isInit) {\n                        // Default label emphasis `position` and `show`\n                        fillLabel(markerOpt);\n                    }\n                    each$1(markerOpt.data, function (item) {\n                        // FIXME Overwrite fillLabel method ?\n                        if (item instanceof Array) {\n                            fillLabel(item[0]);\n                            fillLabel(item[1]);\n                        }\n                        else {\n                            fillLabel(item);\n                        }\n                    });\n\n                    markerModel = new MarkerModel(\n                        markerOpt, this, ecModel\n                    );\n\n                    extend(markerModel, {\n                        mainType: this.mainType,\n                        // Use the same series index and name\n                        seriesIndex: seriesModel.seriesIndex,\n                        name: seriesModel.name,\n                        createdBySelf: true\n                    });\n\n                    markerModel.__hostSeries = seriesModel;\n                }\n                else {\n                    markerModel.mergeOption(markerOpt, ecModel, true);\n                }\n                seriesModel[modelPropName] = markerModel;\n            }, this);\n        }\n    },\n\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var value = this.getRawValue(dataIndex);\n        var formattedValue = isArray(value)\n            ? map(value, addCommas$1).join(', ') : addCommas$1(value);\n        var name = data.getName(dataIndex);\n        var html = encodeHTML$1(this.name);\n        if (value != null || name) {\n            html += '<br />';\n        }\n        if (name) {\n            html += encodeHTML$1(name);\n            if (value != null) {\n                html += ' : ';\n            }\n        }\n        if (value != null) {\n            html += encodeHTML$1(formattedValue);\n        }\n        return html;\n    },\n\n    getData: function () {\n        return this._data;\n    },\n\n    setData: function (data) {\n        this._data = data;\n    }\n});\n\nmixin(MarkerModel, dataFormatMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markPoint',\n\n    defaultOption: {\n        zlevel: 0,\n        z: 5,\n        symbol: 'pin',\n        symbolSize: 50,\n        //symbolRotate: 0,\n        //symbolOffset: [0, 0]\n        tooltip: {\n            trigger: 'item'\n        },\n        label: {\n            show: true,\n            position: 'inside'\n        },\n        itemStyle: {\n            borderWidth: 2\n        },\n        emphasis: {\n            label: {\n                show: true\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar indexOf$1 = indexOf;\n\nfunction hasXOrY(item) {\n    return !(isNaN(parseFloat(item.x)) && isNaN(parseFloat(item.y)));\n}\n\nfunction hasXAndY(item) {\n    return !isNaN(parseFloat(item.x)) && !isNaN(parseFloat(item.y));\n}\n\n// Make it simple, do not visit all stacked value to count precision.\n// function getPrecision(data, valueAxisDim, dataIndex) {\n//     var precision = -1;\n//     var stackedDim = data.mapDimension(valueAxisDim);\n//     do {\n//         precision = Math.max(\n//             numberUtil.getPrecision(data.get(stackedDim, dataIndex)),\n//             precision\n//         );\n//         var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');\n//         if (stackedOnSeries) {\n//             var byValue = data.get(data.getCalculationInfo('stackedByDimension'), dataIndex);\n//             data = stackedOnSeries.getData();\n//             dataIndex = data.indexOf(data.getCalculationInfo('stackedByDimension'), byValue);\n//             stackedDim = data.getCalculationInfo('stackedDimension');\n//         }\n//         else {\n//             data = null;\n//         }\n//     } while (data);\n\n//     return precision;\n// }\n\nfunction markerTypeCalculatorWithExtent(\n    mlType, data, otherDataDim, targetDataDim, otherCoordIndex, targetCoordIndex\n) {\n    var coordArr = [];\n\n    var stacked = isDimensionStacked(data, targetDataDim /*, otherDataDim*/);\n    var calcDataDim = stacked\n        ? data.getCalculationInfo('stackResultDimension')\n        : targetDataDim;\n\n    var value = numCalculate(data, calcDataDim, mlType);\n\n    var dataIndex = data.indicesOfNearest(calcDataDim, value)[0];\n    coordArr[otherCoordIndex] = data.get(otherDataDim, dataIndex);\n    coordArr[targetCoordIndex] = data.get(targetDataDim, dataIndex);\n\n    // Make it simple, do not visit all stacked value to count precision.\n    var precision = getPrecision(data.get(targetDataDim, dataIndex));\n    precision = Math.min(precision, 20);\n    if (precision >= 0) {\n        coordArr[targetCoordIndex] = +coordArr[targetCoordIndex].toFixed(precision);\n    }\n\n    return coordArr;\n}\n\nvar curry$4 = curry;\n// TODO Specified percent\nvar markerTypeCalculator = {\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    min: curry$4(markerTypeCalculatorWithExtent, 'min'),\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    max: curry$4(markerTypeCalculatorWithExtent, 'max'),\n\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    average: curry$4(markerTypeCalculatorWithExtent, 'average')\n};\n\n/**\n * Transform markPoint data item to format used in List by do the following\n * 1. Calculate statistic like `max`, `min`, `average`\n * 2. Convert `item.xAxis`, `item.yAxis` to `item.coord` array\n * @param  {module:echarts/model/Series} seriesModel\n * @param  {module:echarts/coord/*} [coordSys]\n * @param  {Object} item\n * @return {Object}\n */\nfunction dataTransform(seriesModel, item) {\n    var data = seriesModel.getData();\n    var coordSys = seriesModel.coordinateSystem;\n\n    // 1. If not specify the position with pixel directly\n    // 2. If `coord` is not a data array. Which uses `xAxis`,\n    // `yAxis` to specify the coord on each dimension\n\n    // parseFloat first because item.x and item.y can be percent string like '20%'\n    if (item && !hasXAndY(item) && !isArray(item.coord) && coordSys) {\n        var dims = coordSys.dimensions;\n        var axisInfo = getAxisInfo$1(item, data, coordSys, seriesModel);\n\n        // Clone the option\n        // Transform the properties xAxis, yAxis, radiusAxis, angleAxis, geoCoord to value\n        item = clone(item);\n\n        if (item.type\n            && markerTypeCalculator[item.type]\n            && axisInfo.baseAxis && axisInfo.valueAxis\n        ) {\n            var otherCoordIndex = indexOf$1(dims, axisInfo.baseAxis.dim);\n            var targetCoordIndex = indexOf$1(dims, axisInfo.valueAxis.dim);\n\n            item.coord = markerTypeCalculator[item.type](\n                data, axisInfo.baseDataDim, axisInfo.valueDataDim,\n                otherCoordIndex, targetCoordIndex\n            );\n            // Force to use the value of calculated value.\n            item.value = item.coord[targetCoordIndex];\n        }\n        else {\n            // FIXME Only has one of xAxis and yAxis.\n            var coord = [\n                item.xAxis != null ? item.xAxis : item.radiusAxis,\n                item.yAxis != null ? item.yAxis : item.angleAxis\n            ];\n            // Each coord support max, min, average\n            for (var i = 0; i < 2; i++) {\n                if (markerTypeCalculator[coord[i]]) {\n                    coord[i] = numCalculate(data, data.mapDimension(dims[i]), coord[i]);\n                }\n            }\n            item.coord = coord;\n        }\n    }\n    return item;\n}\n\nfunction getAxisInfo$1(item, data, coordSys, seriesModel) {\n    var ret = {};\n\n    if (item.valueIndex != null || item.valueDim != null) {\n        ret.valueDataDim = item.valueIndex != null\n            ? data.getDimension(item.valueIndex) : item.valueDim;\n        ret.valueAxis = coordSys.getAxis(dataDimToCoordDim(seriesModel, ret.valueDataDim));\n        ret.baseAxis = coordSys.getOtherAxis(ret.valueAxis);\n        ret.baseDataDim = data.mapDimension(ret.baseAxis.dim);\n    }\n    else {\n        ret.baseAxis = seriesModel.getBaseAxis();\n        ret.valueAxis = coordSys.getOtherAxis(ret.baseAxis);\n        ret.baseDataDim = data.mapDimension(ret.baseAxis.dim);\n        ret.valueDataDim = data.mapDimension(ret.valueAxis.dim);\n    }\n\n    return ret;\n}\n\nfunction dataDimToCoordDim(seriesModel, dataDim) {\n    var data = seriesModel.getData();\n    var dimensions = data.dimensions;\n    dataDim = data.getDimension(dataDim);\n    for (var i = 0; i < dimensions.length; i++) {\n        var dimItem = data.getDimensionInfo(dimensions[i]);\n        if (dimItem.name === dataDim) {\n            return dimItem.coordDim;\n        }\n    }\n}\n\n/**\n * Filter data which is out of coordinateSystem range\n * [dataFilter description]\n * @param  {module:echarts/coord/*} [coordSys]\n * @param  {Object} item\n * @return {boolean}\n */\nfunction dataFilter$1(coordSys, item) {\n    // Alwalys return true if there is no coordSys\n    return (coordSys && coordSys.containData && item.coord && !hasXOrY(item))\n        ? coordSys.containData(item.coord) : true;\n}\n\nfunction dimValueGetter(item, dimName, dataIndex, dimIndex) {\n    // x, y, radius, angle\n    if (dimIndex < 2) {\n        return item.coord && item.coord[dimIndex];\n    }\n    return item.value;\n}\n\nfunction numCalculate(data, valueDataDim, type) {\n    if (type === 'average') {\n        var sum = 0;\n        var count = 0;\n        data.each(valueDataDim, function (val, idx) {\n            if (!isNaN(val)) {\n                sum += val;\n                count++;\n            }\n        });\n        return sum / count;\n    }\n    else if (type === 'median') {\n        return data.getMedian(valueDataDim);\n    }\n    else {\n        // max & min\n        return data.getDataExtent(valueDataDim, true)[type === 'max' ? 1 : 0];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar MarkerView = extendComponentView({\n\n    type: 'marker',\n\n    init: function () {\n        /**\n         * Markline grouped by series\n         * @private\n         * @type {module:zrender/core/util.HashMap}\n         */\n        this.markerGroupMap = createHashMap();\n    },\n\n    render: function (markerModel, ecModel, api) {\n        var markerGroupMap = this.markerGroupMap;\n        markerGroupMap.each(function (item) {\n            item.__keep = false;\n        });\n\n        var markerModelKey = this.type + 'Model';\n        ecModel.eachSeries(function (seriesModel) {\n            var markerModel = seriesModel[markerModelKey];\n            markerModel && this.renderSeries(seriesModel, markerModel, ecModel, api);\n        }, this);\n\n        markerGroupMap.each(function (item) {\n            !item.__keep && this.group.remove(item.group);\n        }, this);\n    },\n\n    renderSeries: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction updateMarkerLayout(mpData, seriesModel, api) {\n    var coordSys = seriesModel.coordinateSystem;\n    mpData.each(function (idx) {\n        var itemModel = mpData.getItemModel(idx);\n        var point;\n        var xPx = parsePercent$1(itemModel.get('x'), api.getWidth());\n        var yPx = parsePercent$1(itemModel.get('y'), api.getHeight());\n        if (!isNaN(xPx) && !isNaN(yPx)) {\n            point = [xPx, yPx];\n        }\n        // Chart like bar may have there own marker positioning logic\n        else if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                mpData.getValues(mpData.dimensions, idx)\n            );\n        }\n        else if (coordSys) {\n            var x = mpData.get(coordSys.dimensions[0], idx);\n            var y = mpData.get(coordSys.dimensions[1], idx);\n            point = coordSys.dataToPoint([x, y]);\n\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n\n        mpData.setItemLayout(idx, point);\n    });\n}\n\nMarkerView.extend({\n\n    type: 'markPoint',\n\n    // updateLayout: function (markPointModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var mpModel = seriesModel.markPointModel;\n    //         if (mpModel) {\n    //             updateMarkerLayout(mpModel.getData(), seriesModel, api);\n    //             this.markerGroupMap.get(seriesModel.id).updateLayout(mpModel);\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markPointModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var mpModel = seriesModel.markPointModel;\n            if (mpModel) {\n                updateMarkerLayout(mpModel.getData(), seriesModel, api);\n                this.markerGroupMap.get(seriesModel.id).updateLayout(mpModel);\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, mpModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var symbolDrawMap = this.markerGroupMap;\n        var symbolDraw = symbolDrawMap.get(seriesId)\n            || symbolDrawMap.set(seriesId, new SymbolDraw());\n\n        var mpData = createList$1(coordSys, seriesModel, mpModel);\n\n        // FIXME\n        mpModel.setData(mpData);\n\n        updateMarkerLayout(mpModel.getData(), seriesModel, api);\n\n        mpData.each(function (idx) {\n            var itemModel = mpData.getItemModel(idx);\n            var symbolSize = itemModel.getShallow('symbolSize');\n            if (typeof symbolSize === 'function') {\n                // FIXME 这里不兼容 ECharts 2.x，2.x 貌似参数是整个数据？\n                symbolSize = symbolSize(\n                    mpModel.getRawValue(idx), mpModel.getDataParams(idx)\n                );\n            }\n            mpData.setItemVisual(idx, {\n                symbolSize: symbolSize,\n                color: itemModel.get('itemStyle.color')\n                    || seriesData.getVisual('color'),\n                symbol: itemModel.getShallow('symbol')\n            });\n        });\n\n        // TODO Text are wrong\n        symbolDraw.updateData(mpData);\n        this.group.add(symbolDraw.group);\n\n        // Set host model for tooltip\n        // FIXME\n        mpData.eachItemGraphicEl(function (el) {\n            el.traverse(function (child) {\n                child.dataModel = mpModel;\n            });\n        });\n\n        symbolDraw.__keep = true;\n\n        symbolDraw.group.silent = mpModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} [coordSys]\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$1(coordSys, seriesModel, mpModel) {\n    var coordDimsInfos;\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var info = seriesModel.getData().getDimensionInfo(\n                seriesModel.getData().mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n    }\n\n    var mpData = new List(coordDimsInfos, mpModel);\n    var dataOpt = map(mpModel.get('data'), curry(\n            dataTransform, seriesModel\n        ));\n    if (coordSys) {\n        dataOpt = filter(\n            dataOpt, curry(dataFilter$1, coordSys)\n        );\n    }\n\n    mpData.initData(dataOpt, null,\n        coordSys ? dimValueGetter : function (item) {\n            return item.value;\n        }\n    );\n\n    return mpData;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// HINT Markpoint can't be used too much\nregisterPreprocessor(function (opt) {\n    // Make sure markPoint component is enabled\n    opt.markPoint = opt.markPoint || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markLine',\n\n    defaultOption: {\n        zlevel: 0,\n        z: 5,\n\n        symbol: ['circle', 'arrow'],\n        symbolSize: [8, 16],\n\n        //symbolRotate: 0,\n\n        precision: 2,\n        tooltip: {\n            trigger: 'item'\n        },\n        label: {\n            show: true,\n            position: 'end'\n        },\n        lineStyle: {\n            type: 'dashed'\n        },\n        emphasis: {\n            label: {\n                show: true\n            },\n            lineStyle: {\n                width: 3\n            }\n        },\n        animationEasing: 'linear'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Line path for bezier and straight line draw\n */\n\nvar straightLineProto = Line.prototype;\nvar bezierCurveProto = BezierCurve.prototype;\n\nfunction isLine(shape) {\n    return isNaN(+shape.cpx1) || isNaN(+shape.cpy1);\n}\n\nvar LinePath = extendShape({\n\n    type: 'ec-line',\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    shape: {\n        x1: 0,\n        y1: 0,\n        x2: 0,\n        y2: 0,\n        percent: 1,\n        cpx1: null,\n        cpy1: null\n    },\n\n    buildPath: function (ctx, shape) {\n        (isLine(shape) ? straightLineProto : bezierCurveProto).buildPath(ctx, shape);\n    },\n\n    pointAt: function (t) {\n        return isLine(this.shape)\n            ? straightLineProto.pointAt.call(this, t)\n            : bezierCurveProto.pointAt.call(this, t);\n    },\n\n    tangentAt: function (t) {\n        var shape = this.shape;\n        var p = isLine(shape)\n            ? [shape.x2 - shape.x1, shape.y2 - shape.y1]\n            : bezierCurveProto.tangentAt.call(this, t);\n        return normalize(p, p);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Line\n */\n\nvar SYMBOL_CATEGORIES = ['fromSymbol', 'toSymbol'];\n\nfunction makeSymbolTypeKey(symbolCategory) {\n    return '_' + symbolCategory + 'Type';\n}\n/**\n * @inner\n */\nfunction createSymbol$1(name, lineData, idx) {\n    var color = lineData.getItemVisual(idx, 'color');\n    var symbolType = lineData.getItemVisual(idx, name);\n    var symbolSize = lineData.getItemVisual(idx, name + 'Size');\n\n    if (!symbolType || symbolType === 'none') {\n        return;\n    }\n\n    if (!isArray(symbolSize)) {\n        symbolSize = [symbolSize, symbolSize];\n    }\n    var symbolPath = createSymbol(\n        symbolType, -symbolSize[0] / 2, -symbolSize[1] / 2,\n        symbolSize[0], symbolSize[1], color\n    );\n\n    symbolPath.name = name;\n\n    return symbolPath;\n}\n\nfunction createLine(points) {\n    var line = new LinePath({\n        name: 'line'\n    });\n    setLinePoints(line.shape, points);\n    return line;\n}\n\nfunction setLinePoints(targetShape, points) {\n    var p1 = points[0];\n    var p2 = points[1];\n    var cp1 = points[2];\n    targetShape.x1 = p1[0];\n    targetShape.y1 = p1[1];\n    targetShape.x2 = p2[0];\n    targetShape.y2 = p2[1];\n    targetShape.percent = 1;\n\n    if (cp1) {\n        targetShape.cpx1 = cp1[0];\n        targetShape.cpy1 = cp1[1];\n    }\n    else {\n        targetShape.cpx1 = NaN;\n        targetShape.cpy1 = NaN;\n    }\n}\n\nfunction updateSymbolAndLabelBeforeLineUpdate() {\n    var lineGroup = this;\n    var symbolFrom = lineGroup.childOfName('fromSymbol');\n    var symbolTo = lineGroup.childOfName('toSymbol');\n    var label = lineGroup.childOfName('label');\n    // Quick reject\n    if (!symbolFrom && !symbolTo && label.ignore) {\n        return;\n    }\n\n    var invScale = 1;\n    var parentNode = this.parent;\n    while (parentNode) {\n        if (parentNode.scale) {\n            invScale /= parentNode.scale[0];\n        }\n        parentNode = parentNode.parent;\n    }\n\n    var line = lineGroup.childOfName('line');\n    // If line not changed\n    // FIXME Parent scale changed\n    if (!this.__dirty && !line.__dirty) {\n        return;\n    }\n\n    var percent = line.shape.percent;\n    var fromPos = line.pointAt(0);\n    var toPos = line.pointAt(percent);\n\n    var d = sub([], toPos, fromPos);\n    normalize(d, d);\n\n    if (symbolFrom) {\n        symbolFrom.attr('position', fromPos);\n        var tangent = line.tangentAt(0);\n        symbolFrom.attr('rotation', Math.PI / 2 - Math.atan2(\n            tangent[1], tangent[0]\n        ));\n        symbolFrom.attr('scale', [invScale * percent, invScale * percent]);\n    }\n    if (symbolTo) {\n        symbolTo.attr('position', toPos);\n        var tangent = line.tangentAt(1);\n        symbolTo.attr('rotation', -Math.PI / 2 - Math.atan2(\n            tangent[1], tangent[0]\n        ));\n        symbolTo.attr('scale', [invScale * percent, invScale * percent]);\n    }\n\n    if (!label.ignore) {\n        label.attr('position', toPos);\n\n        var textPosition;\n        var textAlign;\n        var textVerticalAlign;\n\n        var distance$$1 = 5 * invScale;\n        // End\n        if (label.__position === 'end') {\n            textPosition = [d[0] * distance$$1 + toPos[0], d[1] * distance$$1 + toPos[1]];\n            textAlign = d[0] > 0.8 ? 'left' : (d[0] < -0.8 ? 'right' : 'center');\n            textVerticalAlign = d[1] > 0.8 ? 'top' : (d[1] < -0.8 ? 'bottom' : 'middle');\n        }\n        // Middle\n        else if (label.__position === 'middle') {\n            var halfPercent = percent / 2;\n            var tangent = line.tangentAt(halfPercent);\n            var n = [tangent[1], -tangent[0]];\n            var cp = line.pointAt(halfPercent);\n            if (n[1] > 0) {\n                n[0] = -n[0];\n                n[1] = -n[1];\n            }\n            textPosition = [cp[0] + n[0] * distance$$1, cp[1] + n[1] * distance$$1];\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            var rotation = -Math.atan2(tangent[1], tangent[0]);\n            if (toPos[0] < fromPos[0]) {\n                rotation = Math.PI + rotation;\n            }\n            label.attr('rotation', rotation);\n        }\n        // Start\n        else {\n            textPosition = [-d[0] * distance$$1 + fromPos[0], -d[1] * distance$$1 + fromPos[1]];\n            textAlign = d[0] > 0.8 ? 'right' : (d[0] < -0.8 ? 'left' : 'center');\n            textVerticalAlign = d[1] > 0.8 ? 'bottom' : (d[1] < -0.8 ? 'top' : 'middle');\n        }\n        label.attr({\n            style: {\n                // Use the user specified text align and baseline first\n                textVerticalAlign: label.__verticalAlign || textVerticalAlign,\n                textAlign: label.__textAlign || textAlign\n            },\n            position: textPosition,\n            scale: [invScale, invScale]\n        });\n    }\n}\n\n/**\n * @constructor\n * @extends {module:zrender/graphic/Group}\n * @alias {module:echarts/chart/helper/Line}\n */\nfunction Line$1(lineData, idx, seriesScope) {\n    Group.call(this);\n\n    this._createLine(lineData, idx, seriesScope);\n}\n\nvar lineProto = Line$1.prototype;\n\n// Update symbol position and rotation\nlineProto.beforeUpdate = updateSymbolAndLabelBeforeLineUpdate;\n\nlineProto._createLine = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n    var linePoints = lineData.getItemLayout(idx);\n\n    var line = createLine(linePoints);\n    line.shape.percent = 0;\n    initProps(line, {\n        shape: {\n            percent: 1\n        }\n    }, seriesModel, idx);\n\n    this.add(line);\n\n    var label = new Text({\n        name: 'label',\n        // FIXME\n        // Temporary solution for `focusNodeAdjacency`.\n        // line label do not use the opacity of lineStyle.\n        lineLabelOriginalOpacity: 1\n    });\n    this.add(label);\n\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbol = createSymbol$1(symbolCategory, lineData, idx);\n        // symbols must added after line to make sure\n        // it will be updated after line#update.\n        // Or symbol position and rotation update in line#beforeUpdate will be one frame slow\n        this.add(symbol);\n        this[makeSymbolTypeKey(symbolCategory)] = lineData.getItemVisual(idx, symbolCategory);\n    }, this);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\nlineProto.updateData = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n\n    var line = this.childOfName('line');\n    var linePoints = lineData.getItemLayout(idx);\n    var target = {\n        shape: {}\n    };\n    setLinePoints(target.shape, linePoints);\n    updateProps(line, target, seriesModel, idx);\n\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbolType = lineData.getItemVisual(idx, symbolCategory);\n        var key = makeSymbolTypeKey(symbolCategory);\n        // Symbol changed\n        if (this[key] !== symbolType) {\n            this.remove(this.childOfName(symbolCategory));\n            var symbol = createSymbol$1(symbolCategory, lineData, idx);\n            this.add(symbol);\n        }\n        this[key] = symbolType;\n    }, this);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\nlineProto._updateCommonStl = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n\n    var line = this.childOfName('line');\n\n    var lineStyle = seriesScope && seriesScope.lineStyle;\n    var hoverLineStyle = seriesScope && seriesScope.hoverLineStyle;\n    var labelModel = seriesScope && seriesScope.labelModel;\n    var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;\n\n    // Optimization for large dataset\n    if (!seriesScope || lineData.hasItemOption) {\n        var itemModel = lineData.getItemModel(idx);\n\n        lineStyle = itemModel.getModel('lineStyle').getLineStyle();\n        hoverLineStyle = itemModel.getModel('emphasis.lineStyle').getLineStyle();\n\n        labelModel = itemModel.getModel('label');\n        hoverLabelModel = itemModel.getModel('emphasis.label');\n    }\n\n    var visualColor = lineData.getItemVisual(idx, 'color');\n    var visualOpacity = retrieve3(\n        lineData.getItemVisual(idx, 'opacity'),\n        lineStyle.opacity,\n        1\n    );\n\n    line.useStyle(defaults(\n        {\n            strokeNoScale: true,\n            fill: 'none',\n            stroke: visualColor,\n            opacity: visualOpacity\n        },\n        lineStyle\n    ));\n    line.hoverStyle = hoverLineStyle;\n\n    // Update symbol\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbol = this.childOfName(symbolCategory);\n        if (symbol) {\n            symbol.setColor(visualColor);\n            symbol.setStyle({\n                opacity: visualOpacity\n            });\n        }\n    }, this);\n\n    var showLabel = labelModel.getShallow('show');\n    var hoverShowLabel = hoverLabelModel.getShallow('show');\n\n    var label = this.childOfName('label');\n    var defaultLabelColor;\n    var baseText;\n\n    // FIXME: the logic below probably should be merged to `graphic.setLabelStyle`.\n    if (showLabel || hoverShowLabel) {\n        defaultLabelColor = visualColor || '#000';\n\n        baseText = seriesModel.getFormattedLabel(idx, 'normal', lineData.dataType);\n        if (baseText == null) {\n            var rawVal = seriesModel.getRawValue(idx);\n            baseText = rawVal == null\n                ? lineData.getName(idx)\n                : isFinite(rawVal)\n                ? round$2(rawVal)\n                : rawVal;\n        }\n    }\n    var normalText = showLabel ? baseText : null;\n    var emphasisText = hoverShowLabel\n        ? retrieve2(\n            seriesModel.getFormattedLabel(idx, 'emphasis', lineData.dataType),\n            baseText\n        )\n        : null;\n\n    var labelStyle = label.style;\n\n    // Always set `textStyle` even if `normalStyle.text` is null, because default\n    // values have to be set on `normalStyle`.\n    if (normalText != null || emphasisText != null) {\n        setTextStyle(label.style, labelModel, {\n            text: normalText\n        }, {\n            autoColor: defaultLabelColor\n        });\n\n        label.__textAlign = labelStyle.textAlign;\n        label.__verticalAlign = labelStyle.textVerticalAlign;\n        // 'start', 'middle', 'end'\n        label.__position = labelModel.get('position') || 'middle';\n    }\n\n    if (emphasisText != null) {\n        // Only these properties supported in this emphasis style here.\n        label.hoverStyle = {\n            text: emphasisText,\n            textFill: hoverLabelModel.getTextColor(true),\n            // For merging hover style to normal style, do not use\n            // `hoverLabelModel.getFont()` here.\n            fontStyle: hoverLabelModel.getShallow('fontStyle'),\n            fontWeight: hoverLabelModel.getShallow('fontWeight'),\n            fontSize: hoverLabelModel.getShallow('fontSize'),\n            fontFamily: hoverLabelModel.getShallow('fontFamily')\n        };\n    }\n    else {\n        label.hoverStyle = {\n            text: null\n        };\n    }\n\n    label.ignore = !showLabel && !hoverShowLabel;\n\n    setHoverStyle(this);\n};\n\nlineProto.highlight = function () {\n    this.trigger('emphasis');\n};\n\nlineProto.downplay = function () {\n    this.trigger('normal');\n};\n\nlineProto.updateLayout = function (lineData, idx) {\n    this.setLinePoints(lineData.getItemLayout(idx));\n};\n\nlineProto.setLinePoints = function (points) {\n    var linePath = this.childOfName('line');\n    setLinePoints(linePath.shape, points);\n    linePath.dirty();\n};\n\ninherits(Line$1, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/LineDraw\n */\n\n// import IncrementalDisplayable from 'zrender/src/graphic/IncrementalDisplayable';\n\n/**\n * @alias module:echarts/component/marker/LineDraw\n * @constructor\n */\nfunction LineDraw(ctor) {\n    this._ctor = ctor || Line$1;\n\n    this.group = new Group();\n}\n\nvar lineDrawProto = LineDraw.prototype;\n\nlineDrawProto.isPersistent = function () {\n    return true;\n};\n\n/**\n * @param {module:echarts/data/List} lineData\n */\nlineDrawProto.updateData = function (lineData) {\n    var lineDraw = this;\n    var group = lineDraw.group;\n\n    var oldLineData = lineDraw._lineData;\n    lineDraw._lineData = lineData;\n\n    // There is no oldLineData only when first rendering or switching from\n    // stream mode to normal mode, where previous elements should be removed.\n    if (!oldLineData) {\n        group.removeAll();\n    }\n\n    var seriesScope = makeSeriesScope$1(lineData);\n\n    lineData.diff(oldLineData)\n        .add(function (idx) {\n            doAdd(lineDraw, lineData, idx, seriesScope);\n        })\n        .update(function (newIdx, oldIdx) {\n            doUpdate(lineDraw, oldLineData, lineData, oldIdx, newIdx, seriesScope);\n        })\n        .remove(function (idx) {\n            group.remove(oldLineData.getItemGraphicEl(idx));\n        })\n        .execute();\n};\n\nfunction doAdd(lineDraw, lineData, idx, seriesScope) {\n    var itemLayout = lineData.getItemLayout(idx);\n\n    if (!lineNeedsDraw(itemLayout)) {\n        return;\n    }\n\n    var el = new lineDraw._ctor(lineData, idx, seriesScope);\n    lineData.setItemGraphicEl(idx, el);\n    lineDraw.group.add(el);\n}\n\nfunction doUpdate(lineDraw, oldLineData, newLineData, oldIdx, newIdx, seriesScope) {\n    var itemEl = oldLineData.getItemGraphicEl(oldIdx);\n\n    if (!lineNeedsDraw(newLineData.getItemLayout(newIdx))) {\n        lineDraw.group.remove(itemEl);\n        return;\n    }\n\n    if (!itemEl) {\n        itemEl = new lineDraw._ctor(newLineData, newIdx, seriesScope);\n    }\n    else {\n        itemEl.updateData(newLineData, newIdx, seriesScope);\n    }\n\n    newLineData.setItemGraphicEl(newIdx, itemEl);\n\n    lineDraw.group.add(itemEl);\n}\n\nlineDrawProto.updateLayout = function () {\n    var lineData = this._lineData;\n\n    // Do not support update layout in incremental mode.\n    if (!lineData) {\n        return;\n    }\n\n    lineData.eachItemGraphicEl(function (el, idx) {\n        el.updateLayout(lineData, idx);\n    }, this);\n};\n\nlineDrawProto.incrementalPrepareUpdate = function (lineData) {\n    this._seriesScope = makeSeriesScope$1(lineData);\n    this._lineData = null;\n    this.group.removeAll();\n};\n\nlineDrawProto.incrementalUpdate = function (taskParams, lineData) {\n    function updateIncrementalAndHover(el) {\n        if (!el.isGroup) {\n            el.incremental = el.useHoverLayer = true;\n        }\n    }\n\n    for (var idx = taskParams.start; idx < taskParams.end; idx++) {\n        var itemLayout = lineData.getItemLayout(idx);\n\n        if (lineNeedsDraw(itemLayout)) {\n            var el = new this._ctor(lineData, idx, this._seriesScope);\n            el.traverse(updateIncrementalAndHover);\n\n            this.group.add(el);\n            lineData.setItemGraphicEl(idx, el);\n        }\n    }\n};\n\nfunction makeSeriesScope$1(lineData) {\n    var hostModel = lineData.hostModel;\n    return {\n        lineStyle: hostModel.getModel('lineStyle').getLineStyle(),\n        hoverLineStyle: hostModel.getModel('emphasis.lineStyle').getLineStyle(),\n        labelModel: hostModel.getModel('label'),\n        hoverLabelModel: hostModel.getModel('emphasis.label')\n    };\n}\n\nlineDrawProto.remove = function () {\n    this._clearIncremental();\n    this._incremental = null;\n    this.group.removeAll();\n};\n\nlineDrawProto._clearIncremental = function () {\n    var incremental = this._incremental;\n    if (incremental) {\n        incremental.clearDisplaybles();\n    }\n};\n\nfunction isPointNaN(pt) {\n    return isNaN(pt[0]) || isNaN(pt[1]);\n}\n\nfunction lineNeedsDraw(pts) {\n    return !isPointNaN(pts[0]) && !isPointNaN(pts[1]);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar markLineTransform = function (seriesModel, coordSys, mlModel, item) {\n    var data = seriesModel.getData();\n    // Special type markLine like 'min', 'max', 'average', 'median'\n    var mlType = item.type;\n\n    if (!isArray(item)\n        && (\n            mlType === 'min' || mlType === 'max' || mlType === 'average' || mlType === 'median'\n            // In case\n            // data: [{\n            //   yAxis: 10\n            // }]\n            || (item.xAxis != null || item.yAxis != null)\n        )\n    ) {\n        var valueAxis;\n        var valueDataDim;\n        var value;\n\n        if (item.yAxis != null || item.xAxis != null) {\n            valueDataDim = item.yAxis != null ? 'y' : 'x';\n            valueAxis = coordSys.getAxis(valueDataDim);\n\n            value = retrieve(item.yAxis, item.xAxis);\n        }\n        else {\n            var axisInfo = getAxisInfo$1(item, data, coordSys, seriesModel);\n            valueDataDim = axisInfo.valueDataDim;\n            valueAxis = axisInfo.valueAxis;\n            value = numCalculate(data, valueDataDim, mlType);\n        }\n        var valueIndex = valueDataDim === 'x' ? 0 : 1;\n        var baseIndex = 1 - valueIndex;\n\n        var mlFrom = clone(item);\n        var mlTo = {};\n\n        mlFrom.type = null;\n\n        mlFrom.coord = [];\n        mlTo.coord = [];\n        mlFrom.coord[baseIndex] = -Infinity;\n        mlTo.coord[baseIndex] = Infinity;\n\n        var precision = mlModel.get('precision');\n        if (precision >= 0 && typeof value === 'number') {\n            value = +value.toFixed(Math.min(precision, 20));\n        }\n\n        mlFrom.coord[valueIndex] = mlTo.coord[valueIndex] = value;\n\n        item = [mlFrom, mlTo, { // Extra option for tooltip and label\n            type: mlType,\n            valueIndex: item.valueIndex,\n            // Force to use the value of calculated value.\n            value: value\n        }];\n    }\n\n    item = [\n        dataTransform(seriesModel, item[0]),\n        dataTransform(seriesModel, item[1]),\n        extend({}, item[2])\n    ];\n\n    // Avoid line data type is extended by from(to) data type\n    item[2].type = item[2].type || '';\n\n    // Merge from option and to option into line option\n    merge(item[2], item[0]);\n    merge(item[2], item[1]);\n\n    return item;\n};\n\nfunction isInifinity(val) {\n    return !isNaN(val) && !isFinite(val);\n}\n\n// If a markLine has one dim\nfunction ifMarkLineHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) {\n    var otherDimIndex = 1 - dimIndex;\n    var dimName = coordSys.dimensions[dimIndex];\n    return isInifinity(fromCoord[otherDimIndex]) && isInifinity(toCoord[otherDimIndex])\n        && fromCoord[dimIndex] === toCoord[dimIndex] && coordSys.getAxis(dimName).containData(fromCoord[dimIndex]);\n}\n\nfunction markLineFilter(coordSys, item) {\n    if (coordSys.type === 'cartesian2d') {\n        var fromCoord = item[0].coord;\n        var toCoord = item[1].coord;\n        // In case\n        // {\n        //  markLine: {\n        //    data: [{ yAxis: 2 }]\n        //  }\n        // }\n        if (\n            fromCoord && toCoord\n            && (ifMarkLineHasOnlyDim(1, fromCoord, toCoord, coordSys)\n            || ifMarkLineHasOnlyDim(0, fromCoord, toCoord, coordSys))\n        ) {\n            return true;\n        }\n    }\n    return dataFilter$1(coordSys, item[0])\n        && dataFilter$1(coordSys, item[1]);\n}\n\nfunction updateSingleMarkerEndLayout(\n    data, idx, isFrom, seriesModel, api\n) {\n    var coordSys = seriesModel.coordinateSystem;\n    var itemModel = data.getItemModel(idx);\n\n    var point;\n    var xPx = parsePercent$1(itemModel.get('x'), api.getWidth());\n    var yPx = parsePercent$1(itemModel.get('y'), api.getHeight());\n    if (!isNaN(xPx) && !isNaN(yPx)) {\n        point = [xPx, yPx];\n    }\n    else {\n        // Chart like bar may have there own marker positioning logic\n        if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                data.getValues(data.dimensions, idx)\n            );\n        }\n        else {\n            var dims = coordSys.dimensions;\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            point = coordSys.dataToPoint([x, y]);\n        }\n        // Expand line to the edge of grid if value on one axis is Inifnity\n        // In case\n        //  markLine: {\n        //    data: [{\n        //      yAxis: 2\n        //      // or\n        //      type: 'average'\n        //    }]\n        //  }\n        if (coordSys.type === 'cartesian2d') {\n            var xAxis = coordSys.getAxis('x');\n            var yAxis = coordSys.getAxis('y');\n            var dims = coordSys.dimensions;\n            if (isInifinity(data.get(dims[0], idx))) {\n                point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[isFrom ? 0 : 1]);\n            }\n            else if (isInifinity(data.get(dims[1], idx))) {\n                point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[isFrom ? 0 : 1]);\n            }\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n    }\n\n    data.setItemLayout(idx, point);\n}\n\nMarkerView.extend({\n\n    type: 'markLine',\n\n    // updateLayout: function (markLineModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var mlModel = seriesModel.markLineModel;\n    //         if (mlModel) {\n    //             var mlData = mlModel.getData();\n    //             var fromData = mlModel.__from;\n    //             var toData = mlModel.__to;\n    //             // Update visual and layout of from symbol and to symbol\n    //             fromData.each(function (idx) {\n    //                 updateSingleMarkerEndLayout(fromData, idx, true, seriesModel, api);\n    //                 updateSingleMarkerEndLayout(toData, idx, false, seriesModel, api);\n    //             });\n    //             // Update layout of line\n    //             mlData.each(function (idx) {\n    //                 mlData.setItemLayout(idx, [\n    //                     fromData.getItemLayout(idx),\n    //                     toData.getItemLayout(idx)\n    //                 ]);\n    //             });\n\n    //             this.markerGroupMap.get(seriesModel.id).updateLayout();\n\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markLineModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var mlModel = seriesModel.markLineModel;\n            if (mlModel) {\n                var mlData = mlModel.getData();\n                var fromData = mlModel.__from;\n                var toData = mlModel.__to;\n                // Update visual and layout of from symbol and to symbol\n                fromData.each(function (idx) {\n                    updateSingleMarkerEndLayout(fromData, idx, true, seriesModel, api);\n                    updateSingleMarkerEndLayout(toData, idx, false, seriesModel, api);\n                });\n                // Update layout of line\n                mlData.each(function (idx) {\n                    mlData.setItemLayout(idx, [\n                        fromData.getItemLayout(idx),\n                        toData.getItemLayout(idx)\n                    ]);\n                });\n\n                this.markerGroupMap.get(seriesModel.id).updateLayout();\n\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, mlModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var lineDrawMap = this.markerGroupMap;\n        var lineDraw = lineDrawMap.get(seriesId)\n            || lineDrawMap.set(seriesId, new LineDraw());\n        this.group.add(lineDraw.group);\n\n        var mlData = createList$2(coordSys, seriesModel, mlModel);\n\n        var fromData = mlData.from;\n        var toData = mlData.to;\n        var lineData = mlData.line;\n\n        mlModel.__from = fromData;\n        mlModel.__to = toData;\n        // Line data for tooltip and formatter\n        mlModel.setData(lineData);\n\n        var symbolType = mlModel.get('symbol');\n        var symbolSize = mlModel.get('symbolSize');\n        if (!isArray(symbolType)) {\n            symbolType = [symbolType, symbolType];\n        }\n        if (typeof symbolSize === 'number') {\n            symbolSize = [symbolSize, symbolSize];\n        }\n\n        // Update visual and layout of from symbol and to symbol\n        mlData.from.each(function (idx) {\n            updateDataVisualAndLayout(fromData, idx, true);\n            updateDataVisualAndLayout(toData, idx, false);\n        });\n\n        // Update visual and layout of line\n        lineData.each(function (idx) {\n            var lineColor = lineData.getItemModel(idx).get('lineStyle.color');\n            lineData.setItemVisual(idx, {\n                color: lineColor || fromData.getItemVisual(idx, 'color')\n            });\n            lineData.setItemLayout(idx, [\n                fromData.getItemLayout(idx),\n                toData.getItemLayout(idx)\n            ]);\n\n            lineData.setItemVisual(idx, {\n                'fromSymbolSize': fromData.getItemVisual(idx, 'symbolSize'),\n                'fromSymbol': fromData.getItemVisual(idx, 'symbol'),\n                'toSymbolSize': toData.getItemVisual(idx, 'symbolSize'),\n                'toSymbol': toData.getItemVisual(idx, 'symbol')\n            });\n        });\n\n        lineDraw.updateData(lineData);\n\n        // Set host model for tooltip\n        // FIXME\n        mlData.line.eachItemGraphicEl(function (el, idx) {\n            el.traverse(function (child) {\n                child.dataModel = mlModel;\n            });\n        });\n\n        function updateDataVisualAndLayout(data, idx, isFrom) {\n            var itemModel = data.getItemModel(idx);\n\n            updateSingleMarkerEndLayout(\n                data, idx, isFrom, seriesModel, api\n            );\n\n            data.setItemVisual(idx, {\n                symbolSize: itemModel.get('symbolSize') || symbolSize[isFrom ? 0 : 1],\n                symbol: itemModel.get('symbol', true) || symbolType[isFrom ? 0 : 1],\n                color: itemModel.get('itemStyle.color') || seriesData.getVisual('color')\n            });\n        }\n\n        lineDraw.__keep = true;\n\n        lineDraw.group.silent = mlModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} coordSys\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$2(coordSys, seriesModel, mlModel) {\n\n    var coordDimsInfos;\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var info = seriesModel.getData().getDimensionInfo(\n                seriesModel.getData().mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n    }\n\n    var fromData = new List(coordDimsInfos, mlModel);\n    var toData = new List(coordDimsInfos, mlModel);\n    // No dimensions\n    var lineData = new List([], mlModel);\n\n    var optData = map(mlModel.get('data'), curry(\n        markLineTransform, seriesModel, coordSys, mlModel\n    ));\n    if (coordSys) {\n        optData = filter(\n            optData, curry(markLineFilter, coordSys)\n        );\n    }\n    var dimValueGetter$$1 = coordSys ? dimValueGetter : function (item) {\n        return item.value;\n    };\n    fromData.initData(\n        map(optData, function (item) {\n            return item[0];\n        }),\n        null,\n        dimValueGetter$$1\n    );\n    toData.initData(\n        map(optData, function (item) {\n            return item[1];\n        }),\n        null,\n        dimValueGetter$$1\n    );\n    lineData.initData(\n        map(optData, function (item) {\n            return item[2];\n        })\n    );\n    lineData.hasItemOption = true;\n\n    return {\n        from: fromData,\n        to: toData,\n        line: lineData\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterPreprocessor(function (opt) {\n    // Make sure markLine component is enabled\n    opt.markLine = opt.markLine || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markArea',\n\n    defaultOption: {\n        zlevel: 0,\n        // PENDING\n        z: 1,\n        tooltip: {\n            trigger: 'item'\n        },\n        // markArea should fixed on the coordinate system\n        animation: false,\n        label: {\n            show: true,\n            position: 'top'\n        },\n        itemStyle: {\n            // color and borderColor default to use color from series\n            // color: 'auto'\n            // borderColor: 'auto'\n            borderWidth: 0\n        },\n\n        emphasis: {\n            label: {\n                show: true,\n                position: 'top'\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Better on polar\n\nvar markAreaTransform = function (seriesModel, coordSys, maModel, item) {\n    var lt = dataTransform(seriesModel, item[0]);\n    var rb = dataTransform(seriesModel, item[1]);\n    var retrieve$$1 = retrieve;\n\n    // FIXME make sure lt is less than rb\n    var ltCoord = lt.coord;\n    var rbCoord = rb.coord;\n    ltCoord[0] = retrieve$$1(ltCoord[0], -Infinity);\n    ltCoord[1] = retrieve$$1(ltCoord[1], -Infinity);\n\n    rbCoord[0] = retrieve$$1(rbCoord[0], Infinity);\n    rbCoord[1] = retrieve$$1(rbCoord[1], Infinity);\n\n    // Merge option into one\n    var result = mergeAll([{}, lt, rb]);\n\n    result.coord = [\n        lt.coord, rb.coord\n    ];\n    result.x0 = lt.x;\n    result.y0 = lt.y;\n    result.x1 = rb.x;\n    result.y1 = rb.y;\n    return result;\n};\n\nfunction isInifinity$1(val) {\n    return !isNaN(val) && !isFinite(val);\n}\n\n// If a markArea has one dim\nfunction ifMarkLineHasOnlyDim$1(dimIndex, fromCoord, toCoord, coordSys) {\n    var otherDimIndex = 1 - dimIndex;\n    return isInifinity$1(fromCoord[otherDimIndex]) && isInifinity$1(toCoord[otherDimIndex]);\n}\n\nfunction markAreaFilter(coordSys, item) {\n    var fromCoord = item.coord[0];\n    var toCoord = item.coord[1];\n    if (coordSys.type === 'cartesian2d') {\n        // In case\n        // {\n        //  markArea: {\n        //    data: [{ yAxis: 2 }]\n        //  }\n        // }\n        if (\n            fromCoord && toCoord\n            && (ifMarkLineHasOnlyDim$1(1, fromCoord, toCoord, coordSys)\n            || ifMarkLineHasOnlyDim$1(0, fromCoord, toCoord, coordSys))\n        ) {\n            return true;\n        }\n    }\n    return dataFilter$1(coordSys, {\n            coord: fromCoord,\n            x: item.x0,\n            y: item.y0\n        })\n        || dataFilter$1(coordSys, {\n            coord: toCoord,\n            x: item.x1,\n            y: item.y1\n        });\n}\n\n// dims can be ['x0', 'y0'], ['x1', 'y1'], ['x0', 'y1'], ['x1', 'y0']\nfunction getSingleMarkerEndPoint(data, idx, dims, seriesModel, api) {\n    var coordSys = seriesModel.coordinateSystem;\n    var itemModel = data.getItemModel(idx);\n\n    var point;\n    var xPx = parsePercent$1(itemModel.get(dims[0]), api.getWidth());\n    var yPx = parsePercent$1(itemModel.get(dims[1]), api.getHeight());\n    if (!isNaN(xPx) && !isNaN(yPx)) {\n        point = [xPx, yPx];\n    }\n    else {\n        // Chart like bar may have there own marker positioning logic\n        if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                data.getValues(dims, idx)\n            );\n        }\n        else {\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            var pt = [x, y];\n            coordSys.clampData && coordSys.clampData(pt, pt);\n            point = coordSys.dataToPoint(pt, true);\n        }\n        if (coordSys.type === 'cartesian2d') {\n            var xAxis = coordSys.getAxis('x');\n            var yAxis = coordSys.getAxis('y');\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            if (isInifinity$1(x)) {\n                point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[dims[0] === 'x0' ? 0 : 1]);\n            }\n            else if (isInifinity$1(y)) {\n                point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[dims[1] === 'y0' ? 0 : 1]);\n            }\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n    }\n\n    return point;\n}\n\nvar dimPermutations = [['x0', 'y0'], ['x1', 'y0'], ['x1', 'y1'], ['x0', 'y1']];\n\nMarkerView.extend({\n\n    type: 'markArea',\n\n    // updateLayout: function (markAreaModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var maModel = seriesModel.markAreaModel;\n    //         if (maModel) {\n    //             var areaData = maModel.getData();\n    //             areaData.each(function (idx) {\n    //                 var points = zrUtil.map(dimPermutations, function (dim) {\n    //                     return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n    //                 });\n    //                 // Layout\n    //                 areaData.setItemLayout(idx, points);\n    //                 var el = areaData.getItemGraphicEl(idx);\n    //                 el.setShape('points', points);\n    //             });\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markAreaModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var maModel = seriesModel.markAreaModel;\n            if (maModel) {\n                var areaData = maModel.getData();\n                areaData.each(function (idx) {\n                    var points = map(dimPermutations, function (dim) {\n                        return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n                    });\n                    // Layout\n                    areaData.setItemLayout(idx, points);\n                    var el = areaData.getItemGraphicEl(idx);\n                    el.setShape('points', points);\n                });\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, maModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var areaGroupMap = this.markerGroupMap;\n        var polygonGroup = areaGroupMap.get(seriesId)\n            || areaGroupMap.set(seriesId, {group: new Group()});\n\n        this.group.add(polygonGroup.group);\n        polygonGroup.__keep = true;\n\n        var areaData = createList$3(coordSys, seriesModel, maModel);\n\n        // Line data for tooltip and formatter\n        maModel.setData(areaData);\n\n        // Update visual and layout of line\n        areaData.each(function (idx) {\n            // Layout\n            areaData.setItemLayout(idx, map(dimPermutations, function (dim) {\n                return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n            }));\n\n            // Visual\n            areaData.setItemVisual(idx, {\n                color: seriesData.getVisual('color')\n            });\n        });\n\n\n        areaData.diff(polygonGroup.__data)\n            .add(function (idx) {\n                var polygon = new Polygon({\n                    shape: {\n                        points: areaData.getItemLayout(idx)\n                    }\n                });\n                areaData.setItemGraphicEl(idx, polygon);\n                polygonGroup.group.add(polygon);\n            })\n            .update(function (newIdx, oldIdx) {\n                var polygon = polygonGroup.__data.getItemGraphicEl(oldIdx);\n                updateProps(polygon, {\n                    shape: {\n                        points: areaData.getItemLayout(newIdx)\n                    }\n                }, maModel, newIdx);\n                polygonGroup.group.add(polygon);\n                areaData.setItemGraphicEl(newIdx, polygon);\n            })\n            .remove(function (idx) {\n                var polygon = polygonGroup.__data.getItemGraphicEl(idx);\n                polygonGroup.group.remove(polygon);\n            })\n            .execute();\n\n        areaData.eachItemGraphicEl(function (polygon, idx) {\n            var itemModel = areaData.getItemModel(idx);\n            var labelModel = itemModel.getModel('label');\n            var labelHoverModel = itemModel.getModel('emphasis.label');\n            var color = areaData.getItemVisual(idx, 'color');\n            polygon.useStyle(\n                defaults(\n                    itemModel.getModel('itemStyle').getItemStyle(),\n                    {\n                        fill: modifyAlpha(color, 0.4),\n                        stroke: color\n                    }\n                )\n            );\n\n            polygon.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n\n            setLabelStyle(\n                polygon.style, polygon.hoverStyle, labelModel, labelHoverModel,\n                {\n                    labelFetcher: maModel,\n                    labelDataIndex: idx,\n                    defaultText: areaData.getName(idx) || '',\n                    isRectText: true,\n                    autoColor: color\n                }\n            );\n\n            setHoverStyle(polygon, {});\n\n            polygon.dataModel = maModel;\n        });\n\n        polygonGroup.__data = areaData;\n\n        polygonGroup.group.silent = maModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} coordSys\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$3(coordSys, seriesModel, maModel) {\n\n    var coordDimsInfos;\n    var areaData;\n    var dims = ['x0', 'y0', 'x1', 'y1'];\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var data = seriesModel.getData();\n            var info = data.getDimensionInfo(\n                data.mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n        areaData = new List(map(dims, function (dim, idx) {\n            return {\n                name: dim,\n                type: coordDimsInfos[idx % 2].type\n            };\n        }), maModel);\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n        areaData = new List(coordDimsInfos, maModel);\n    }\n\n    var optData = map(maModel.get('data'), curry(\n        markAreaTransform, seriesModel, coordSys, maModel\n    ));\n    if (coordSys) {\n        optData = filter(\n            optData, curry(markAreaFilter, coordSys)\n        );\n    }\n\n    var dimValueGetter$$1 = coordSys ? function (item, dimName, dataIndex, dimIndex) {\n        return item.coord[Math.floor(dimIndex / 2)][dimIndex % 2];\n    } : function (item) {\n        return item.value;\n    };\n    areaData.initData(optData, null, dimValueGetter$$1);\n    areaData.hasItemOption = true;\n    return areaData;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterPreprocessor(function (opt) {\n    // Make sure markArea component is enabled\n    opt.markArea = opt.markArea || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nComponentModel.registerSubTypeDefaulter('dataZoom', function () {\n    // Default 'slider' when no type specified.\n    return 'slider';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AXIS_DIMS = ['x', 'y', 'z', 'radius', 'angle', 'single'];\n// Supported coords.\nvar COORDS = ['cartesian2d', 'polar', 'singleAxis'];\n\n/**\n * @param {string} coordType\n * @return {boolean}\n */\nfunction isCoordSupported(coordType) {\n    return indexOf(COORDS, coordType) >= 0;\n}\n\n/**\n * Create \"each\" method to iterate names.\n *\n * @pubilc\n * @param  {Array.<string>} names\n * @param  {Array.<string>=} attrs\n * @return {Function}\n */\nfunction createNameEach(names, attrs) {\n    names = names.slice();\n    var capitalNames = map(names, capitalFirst);\n    attrs = (attrs || []).slice();\n    var capitalAttrs = map(attrs, capitalFirst);\n\n    return function (callback, context) {\n        each$1(names, function (name, index) {\n            var nameObj = {name: name, capital: capitalNames[index]};\n\n            for (var j = 0; j < attrs.length; j++) {\n                nameObj[attrs[j]] = name + capitalAttrs[j];\n            }\n\n            callback.call(context, nameObj);\n        });\n    };\n}\n\n/**\n * Iterate each dimension name.\n *\n * @public\n * @param {Function} callback The parameter is like:\n *                            {\n *                                name: 'angle',\n *                                capital: 'Angle',\n *                                axis: 'angleAxis',\n *                                axisIndex: 'angleAixs',\n *                                index: 'angleIndex'\n *                            }\n * @param {Object} context\n */\nvar eachAxisDim$1 = createNameEach(AXIS_DIMS, ['axisIndex', 'axis', 'index', 'id']);\n\n/**\n * If tow dataZoomModels has the same axis controlled, we say that they are 'linked'.\n * dataZoomModels and 'links' make up one or more graphics.\n * This function finds the graphic where the source dataZoomModel is in.\n *\n * @public\n * @param {Function} forEachNode Node iterator.\n * @param {Function} forEachEdgeType edgeType iterator\n * @param {Function} edgeIdGetter Giving node and edgeType, return an array of edge id.\n * @return {Function} Input: sourceNode, Output: Like {nodes: [], dims: {}}\n */\nfunction createLinkedNodesFinder(forEachNode, forEachEdgeType, edgeIdGetter) {\n\n    return function (sourceNode) {\n        var result = {\n            nodes: [],\n            records: {} // key: edgeType.name, value: Object (key: edge id, value: boolean).\n        };\n\n        forEachEdgeType(function (edgeType) {\n            result.records[edgeType.name] = {};\n        });\n\n        if (!sourceNode) {\n            return result;\n        }\n\n        absorb(sourceNode, result);\n\n        var existsLink;\n        do {\n            existsLink = false;\n            forEachNode(processSingleNode);\n        }\n        while (existsLink);\n\n        function processSingleNode(node) {\n            if (!isNodeAbsorded(node, result) && isLinked(node, result)) {\n                absorb(node, result);\n                existsLink = true;\n            }\n        }\n\n        return result;\n    };\n\n    function isNodeAbsorded(node, result) {\n        return indexOf(result.nodes, node) >= 0;\n    }\n\n    function isLinked(node, result) {\n        var hasLink = false;\n        forEachEdgeType(function (edgeType) {\n            each$1(edgeIdGetter(node, edgeType) || [], function (edgeId) {\n                result.records[edgeType.name][edgeId] && (hasLink = true);\n            });\n        });\n        return hasLink;\n    }\n\n    function absorb(node, result) {\n        result.nodes.push(node);\n        forEachEdgeType(function (edgeType) {\n            each$1(edgeIdGetter(node, edgeType) || [], function (edgeId) {\n                result.records[edgeType.name][edgeId] = true;\n            });\n        });\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$13 = each$1;\nvar asc$1 = asc;\n\n/**\n * Operate single axis.\n * One axis can only operated by one axis operator.\n * Different dataZoomModels may be defined to operate the same axis.\n * (i.e. 'inside' data zoom and 'slider' data zoom components)\n * So dataZoomModels share one axisProxy in that case.\n *\n * @class\n */\nvar AxisProxy = function (dimName, axisIndex, dataZoomModel, ecModel) {\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._dimName = dimName;\n\n    /**\n     * @private\n     */\n    this._axisIndex = axisIndex;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._valueWindow;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._percentWindow;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._dataExtent;\n\n    /**\n     * {minSpan, maxSpan, minValueSpan, maxValueSpan}\n     * @private\n     * @type {Object}\n     */\n    this._minMaxSpan;\n\n    /**\n     * @readOnly\n     * @type {module: echarts/model/Global}\n     */\n    this.ecModel = ecModel;\n\n    /**\n     * @private\n     * @type {module: echarts/component/dataZoom/DataZoomModel}\n     */\n    this._dataZoomModel = dataZoomModel;\n\n    // /**\n    //  * @readOnly\n    //  * @private\n    //  */\n    // this.hasSeriesStacked;\n};\n\nAxisProxy.prototype = {\n\n    constructor: AxisProxy,\n\n    /**\n     * Whether the axisProxy is hosted by dataZoomModel.\n     *\n     * @public\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     * @return {boolean}\n     */\n    hostedBy: function (dataZoomModel) {\n        return this._dataZoomModel === dataZoomModel;\n    },\n\n    /**\n     * @return {Array.<number>} Value can only be NaN or finite value.\n     */\n    getDataValueWindow: function () {\n        return this._valueWindow.slice();\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getDataPercentWindow: function () {\n        return this._percentWindow.slice();\n    },\n\n    /**\n     * @public\n     * @param {number} axisIndex\n     * @return {Array} seriesModels\n     */\n    getTargetSeriesModels: function () {\n        var seriesModels = [];\n        var ecModel = this.ecModel;\n\n        ecModel.eachSeries(function (seriesModel) {\n            if (isCoordSupported(seriesModel.get('coordinateSystem'))) {\n                var dimName = this._dimName;\n                var axisModel = ecModel.queryComponents({\n                    mainType: dimName + 'Axis',\n                    index: seriesModel.get(dimName + 'AxisIndex'),\n                    id: seriesModel.get(dimName + 'AxisId')\n                })[0];\n                if (this._axisIndex === (axisModel && axisModel.componentIndex)) {\n                    seriesModels.push(seriesModel);\n                }\n            }\n        }, this);\n\n        return seriesModels;\n    },\n\n    getAxisModel: function () {\n        return this.ecModel.getComponent(this._dimName + 'Axis', this._axisIndex);\n    },\n\n    getOtherAxisModel: function () {\n        var axisDim = this._dimName;\n        var ecModel = this.ecModel;\n        var axisModel = this.getAxisModel();\n        var isCartesian = axisDim === 'x' || axisDim === 'y';\n        var otherAxisDim;\n        var coordSysIndexName;\n        if (isCartesian) {\n            coordSysIndexName = 'gridIndex';\n            otherAxisDim = axisDim === 'x' ? 'y' : 'x';\n        }\n        else {\n            coordSysIndexName = 'polarIndex';\n            otherAxisDim = axisDim === 'angle' ? 'radius' : 'angle';\n        }\n        var foundOtherAxisModel;\n        ecModel.eachComponent(otherAxisDim + 'Axis', function (otherAxisModel) {\n            if ((otherAxisModel.get(coordSysIndexName) || 0)\n                === (axisModel.get(coordSysIndexName) || 0)\n            ) {\n                foundOtherAxisModel = otherAxisModel;\n            }\n        });\n        return foundOtherAxisModel;\n    },\n\n    getMinMaxSpan: function () {\n        return clone(this._minMaxSpan);\n    },\n\n    /**\n     * Only calculate by given range and this._dataExtent, do not change anything.\n     *\n     * @param {Object} opt\n     * @param {number} [opt.start]\n     * @param {number} [opt.end]\n     * @param {number} [opt.startValue]\n     * @param {number} [opt.endValue]\n     */\n    calculateDataWindow: function (opt) {\n        var dataExtent = this._dataExtent;\n        var axisModel = this.getAxisModel();\n        var scale = axisModel.axis.scale;\n        var rangePropMode = this._dataZoomModel.getRangePropMode();\n        var percentExtent = [0, 100];\n        var percentWindow = [\n            opt.start,\n            opt.end\n        ];\n        var valueWindow = [];\n\n        each$13(['startValue', 'endValue'], function (prop) {\n            valueWindow.push(opt[prop] != null ? scale.parse(opt[prop]) : null);\n        });\n\n        // Normalize bound.\n        each$13([0, 1], function (idx) {\n            var boundValue = valueWindow[idx];\n            var boundPercent = percentWindow[idx];\n\n            // Notice: dataZoom is based either on `percentProp` ('start', 'end') or\n            // on `valueProp` ('startValue', 'endValue'). The former one is suitable\n            // for cases that a dataZoom component controls multiple axes with different\n            // unit or extent, and the latter one is suitable for accurate zoom by pixel\n            // (e.g., in dataZoomSelect). `valueProp` can be calculated from `percentProp`,\n            // but it is awkward that `percentProp` can not be obtained from `valueProp`\n            // accurately (because all of values that are overflow the `dataExtent` will\n            // be calculated to percent '100%'). So we have to use\n            // `dataZoom.getRangePropMode()` to mark which prop is used.\n            // `rangePropMode` is updated only when setOption or dispatchAction, otherwise\n            // it remains its original value.\n\n            if (rangePropMode[idx] === 'percent') {\n                if (boundPercent == null) {\n                    boundPercent = percentExtent[idx];\n                }\n                // Use scale.parse to math round for category or time axis.\n                boundValue = scale.parse(linearMap(\n                    boundPercent, percentExtent, dataExtent, true\n                ));\n            }\n            else {\n                // Calculating `percent` from `value` may be not accurate, because\n                // This calculation can not be inversed, because all of values that\n                // are overflow the `dataExtent` will be calculated to percent '100%'\n                boundPercent = linearMap(\n                    boundValue, dataExtent, percentExtent, true\n                );\n            }\n\n            // valueWindow[idx] = round(boundValue);\n            // percentWindow[idx] = round(boundPercent);\n            valueWindow[idx] = boundValue;\n            percentWindow[idx] = boundPercent;\n        });\n\n        return {\n            valueWindow: asc$1(valueWindow),\n            percentWindow: asc$1(percentWindow)\n        };\n    },\n\n    /**\n     * Notice: reset should not be called before series.restoreData() called,\n     * so it is recommanded to be called in \"process stage\" but not \"model init\n     * stage\".\n     *\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    reset: function (dataZoomModel) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        var targetSeries = this.getTargetSeriesModels();\n        // Culculate data window and data extent, and record them.\n        this._dataExtent = calculateDataExtent(this, this._dimName, targetSeries);\n\n        // this.hasSeriesStacked = false;\n        // each(targetSeries, function (series) {\n            // var data = series.getData();\n            // var dataDim = data.mapDimension(this._dimName);\n            // var stackedDimension = data.getCalculationInfo('stackedDimension');\n            // if (stackedDimension && stackedDimension === dataDim) {\n                // this.hasSeriesStacked = true;\n            // }\n        // }, this);\n\n        var dataWindow = this.calculateDataWindow(dataZoomModel.option);\n\n        this._valueWindow = dataWindow.valueWindow;\n        this._percentWindow = dataWindow.percentWindow;\n\n        setMinMaxSpan(this);\n\n        // Update axis setting then.\n        setAxisModel(this);\n    },\n\n    /**\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    restore: function (dataZoomModel) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        this._valueWindow = this._percentWindow = null;\n        setAxisModel(this, true);\n    },\n\n    /**\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    filterData: function (dataZoomModel, api) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        var axisDim = this._dimName;\n        var seriesModels = this.getTargetSeriesModels();\n        var filterMode = dataZoomModel.get('filterMode');\n        var valueWindow = this._valueWindow;\n\n        if (filterMode === 'none') {\n            return;\n        }\n\n        // FIXME\n        // Toolbox may has dataZoom injected. And if there are stacked bar chart\n        // with NaN data, NaN will be filtered and stack will be wrong.\n        // So we need to force the mode to be set empty.\n        // In fect, it is not a big deal that do not support filterMode-'filter'\n        // when using toolbox#dataZoom, utill tooltip#dataZoom support \"single axis\n        // selection\" some day, which might need \"adapt to data extent on the\n        // otherAxis\", which is disabled by filterMode-'empty'.\n        // But currently, stack has been fixed to based on value but not index,\n        // so this is not an issue any more.\n        // var otherAxisModel = this.getOtherAxisModel();\n        // if (dataZoomModel.get('$fromToolbox')\n        //     && otherAxisModel\n        //     && otherAxisModel.hasSeriesStacked\n        // ) {\n        //     filterMode = 'empty';\n        // }\n\n        // TODO\n        // filterMode 'weakFilter' and 'empty' is not optimized for huge data yet.\n\n        each$13(seriesModels, function (seriesModel) {\n            var seriesData = seriesModel.getData();\n            var dataDims = seriesData.mapDimension(axisDim, true);\n\n            if (!dataDims.length) {\n                return;\n            }\n\n            if (filterMode === 'weakFilter') {\n                seriesData.filterSelf(function (dataIndex) {\n                    var leftOut;\n                    var rightOut;\n                    var hasValue;\n                    for (var i = 0; i < dataDims.length; i++) {\n                        var value = seriesData.get(dataDims[i], dataIndex);\n                        var thisHasValue = !isNaN(value);\n                        var thisLeftOut = value < valueWindow[0];\n                        var thisRightOut = value > valueWindow[1];\n                        if (thisHasValue && !thisLeftOut && !thisRightOut) {\n                            return true;\n                        }\n                        thisHasValue && (hasValue = true);\n                        thisLeftOut && (leftOut = true);\n                        thisRightOut && (rightOut = true);\n                    }\n                    // If both left out and right out, do not filter.\n                    return hasValue && leftOut && rightOut;\n                });\n            }\n            else {\n                each$13(dataDims, function (dim) {\n                    if (filterMode === 'empty') {\n                        seriesModel.setData(\n                            seriesData.map(dim, function (value) {\n                                return !isInWindow(value) ? NaN : value;\n                            })\n                        );\n                    }\n                    else {\n                        var range = {};\n                        range[dim] = valueWindow;\n\n                        // console.time('select');\n                        seriesData.selectRange(range);\n                        // console.timeEnd('select');\n                    }\n                });\n            }\n\n            each$13(dataDims, function (dim) {\n                seriesData.setApproximateExtent(valueWindow, dim);\n            });\n        });\n\n        function isInWindow(value) {\n            return value >= valueWindow[0] && value <= valueWindow[1];\n        }\n    }\n};\n\nfunction calculateDataExtent(axisProxy, axisDim, seriesModels) {\n    var dataExtent = [Infinity, -Infinity];\n\n    each$13(seriesModels, function (seriesModel) {\n        var seriesData = seriesModel.getData();\n        if (seriesData) {\n            each$13(seriesData.mapDimension(axisDim, true), function (dim) {\n                var seriesExtent = seriesData.getApproximateExtent(dim);\n                seriesExtent[0] < dataExtent[0] && (dataExtent[0] = seriesExtent[0]);\n                seriesExtent[1] > dataExtent[1] && (dataExtent[1] = seriesExtent[1]);\n            });\n        }\n    });\n\n    if (dataExtent[1] < dataExtent[0]) {\n        dataExtent = [NaN, NaN];\n    }\n\n    // It is important to get \"consistent\" extent when more then one axes is\n    // controlled by a `dataZoom`, otherwise those axes will not be synchronized\n    // when zooming. But it is difficult to know what is \"consistent\", considering\n    // axes have different type or even different meanings (For example, two\n    // time axes are used to compare data of the same date in different years).\n    // So basically dataZoom just obtains extent by series.data (in category axis\n    // extent can be obtained from axis.data).\n    // Nevertheless, user can set min/max/scale on axes to make extent of axes\n    // consistent.\n    fixExtentByAxis(axisProxy, dataExtent);\n\n    return dataExtent;\n}\n\nfunction fixExtentByAxis(axisProxy, dataExtent) {\n    var axisModel = axisProxy.getAxisModel();\n    var min = axisModel.getMin(true);\n\n    // For category axis, if min/max/scale are not set, extent is determined\n    // by axis.data by default.\n    var isCategoryAxis = axisModel.get('type') === 'category';\n    var axisDataLen = isCategoryAxis && axisModel.getCategories().length;\n\n    if (min != null && min !== 'dataMin' && typeof min !== 'function') {\n        dataExtent[0] = min;\n    }\n    else if (isCategoryAxis) {\n        dataExtent[0] = axisDataLen > 0 ? 0 : NaN;\n    }\n\n    var max = axisModel.getMax(true);\n    if (max != null && max !== 'dataMax' && typeof max !== 'function') {\n        dataExtent[1] = max;\n    }\n    else if (isCategoryAxis) {\n        dataExtent[1] = axisDataLen > 0 ? axisDataLen - 1 : NaN;\n    }\n\n    if (!axisModel.get('scale', true)) {\n        dataExtent[0] > 0 && (dataExtent[0] = 0);\n        dataExtent[1] < 0 && (dataExtent[1] = 0);\n    }\n\n    // For value axis, if min/max/scale are not set, we just use the extent obtained\n    // by series data, which may be a little different from the extent calculated by\n    // `axisHelper.getScaleExtent`. But the different just affects the experience a\n    // little when zooming. So it will not be fixed until some users require it strongly.\n\n    return dataExtent;\n}\n\nfunction setAxisModel(axisProxy, isRestore) {\n    var axisModel = axisProxy.getAxisModel();\n\n    var percentWindow = axisProxy._percentWindow;\n    var valueWindow = axisProxy._valueWindow;\n\n    if (!percentWindow) {\n        return;\n    }\n\n    // [0, 500]: arbitrary value, guess axis extent.\n    var precision = getPixelPrecision(valueWindow, [0, 500]);\n    precision = Math.min(precision, 20);\n    // isRestore or isFull\n    var useOrigin = isRestore || (percentWindow[0] === 0 && percentWindow[1] === 100);\n\n    axisModel.setRange(\n        useOrigin ? null : +valueWindow[0].toFixed(precision),\n        useOrigin ? null : +valueWindow[1].toFixed(precision)\n    );\n}\n\nfunction setMinMaxSpan(axisProxy) {\n    var minMaxSpan = axisProxy._minMaxSpan = {};\n    var dataZoomModel = axisProxy._dataZoomModel;\n\n    each$13(['min', 'max'], function (minMax) {\n        minMaxSpan[minMax + 'Span'] = dataZoomModel.get(minMax + 'Span');\n\n        // minValueSpan and maxValueSpan has higher priority than minSpan and maxSpan\n        var valueSpan = dataZoomModel.get(minMax + 'ValueSpan');\n\n        if (valueSpan != null) {\n            minMaxSpan[minMax + 'ValueSpan'] = valueSpan;\n            valueSpan = axisProxy.getAxisModel().axis.scale.parse(valueSpan);\n\n            if (valueSpan != null) {\n                var dataExtent = axisProxy._dataExtent;\n                minMaxSpan[minMax + 'Span'] = linearMap(\n                    dataExtent[0] + valueSpan, dataExtent, [0, 100], true\n                );\n            }\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$12 = each$1;\nvar eachAxisDim = eachAxisDim$1;\n\nvar DataZoomModel = extendComponentModel({\n\n    type: 'dataZoom',\n\n    dependencies: [\n        'xAxis', 'yAxis', 'zAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'series'\n    ],\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        zlevel: 0,\n        z: 4,                   // Higher than normal component (z: 2).\n        orient: null,           // Default auto by axisIndex. Possible value: 'horizontal', 'vertical'.\n        xAxisIndex: null,       // Default the first horizontal category axis.\n        yAxisIndex: null,       // Default the first vertical category axis.\n\n        filterMode: 'filter',   // Possible values: 'filter' or 'empty' or 'weakFilter'.\n                                // 'filter': data items which are out of window will be removed. This option is\n                                //          applicable when filtering outliers. For each data item, it will be\n                                //          filtered if one of the relevant dimensions is out of the window.\n                                // 'weakFilter': data items which are out of window will be removed. This option\n                                //          is applicable when filtering outliers. For each data item, it will be\n                                //          filtered only if all  of the relevant dimensions are out of the same\n                                //          side of the window.\n                                // 'empty': data items which are out of window will be set to empty.\n                                //          This option is applicable when user should not neglect\n                                //          that there are some data items out of window.\n                                // 'none': Do not filter.\n                                // Taking line chart as an example, line will be broken in\n                                // the filtered points when filterModel is set to 'empty', but\n                                // be connected when set to 'filter'.\n\n        throttle: null,         // Dispatch action by the fixed rate, avoid frequency.\n                                // default 100. Do not throttle when use null/undefined.\n                                // If animation === true and animationDurationUpdate > 0,\n                                // default value is 100, otherwise 20.\n        start: 0,               // Start percent. 0 ~ 100\n        end: 100,               // End percent. 0 ~ 100\n        startValue: null,       // Start value. If startValue specified, start is ignored.\n        endValue: null,         // End value. If endValue specified, end is ignored.\n        minSpan: null,          // 0 ~ 100\n        maxSpan: null,          // 0 ~ 100\n        minValueSpan: null,     // The range of dataZoom can not be smaller than that.\n        maxValueSpan: null,     // The range of dataZoom can not be larger than that.\n        rangeMode: null         // Array, can be 'value' or 'percent'.\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel) {\n\n        /**\n         * key like x_0, y_1\n         * @private\n         * @type {Object}\n         */\n        this._dataIntervalByAxis = {};\n\n        /**\n         * @private\n         */\n        this._dataInfo = {};\n\n        /**\n         * key like x_0, y_1\n         * @private\n         */\n        this._axisProxies = {};\n\n        /**\n         * @readOnly\n         */\n        this.textStyleModel;\n\n        /**\n         * @private\n         */\n        this._autoThrottle = true;\n\n        /**\n         * 'percent' or 'value'\n         * @private\n         */\n        this._rangePropMode = ['percent', 'percent'];\n\n        var rawOption = retrieveRaw(option);\n\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        this.doInit(rawOption);\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (newOption) {\n        var rawOption = retrieveRaw(newOption);\n\n        //FIX #2591\n        merge(this.option, newOption, true);\n\n        this.doInit(rawOption);\n    },\n\n    /**\n     * @protected\n     */\n    doInit: function (rawOption) {\n        var thisOption = this.option;\n\n        // Disable realtime view update if canvas is not supported.\n        if (!env$1.canvasSupported) {\n            thisOption.realtime = false;\n        }\n\n        this._setDefaultThrottle(rawOption);\n\n        updateRangeUse(this, rawOption);\n\n        each$12([['start', 'startValue'], ['end', 'endValue']], function (names, index) {\n            // start/end has higher priority over startValue/endValue if they\n            // both set, but we should make chart.setOption({endValue: 1000})\n            // effective, rather than chart.setOption({endValue: 1000, end: null}).\n            if (this._rangePropMode[index] === 'value') {\n                thisOption[names[0]] = null;\n            }\n            // Otherwise do nothing and use the merge result.\n        }, this);\n\n        this.textStyleModel = this.getModel('textStyle');\n\n        this._resetTarget();\n\n        this._giveAxisProxies();\n    },\n\n    /**\n     * @private\n     */\n    _giveAxisProxies: function () {\n        var axisProxies = this._axisProxies;\n\n        this.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel, ecModel) {\n            var axisModel = this.dependentModels[dimNames.axis][axisIndex];\n\n            // If exists, share axisProxy with other dataZoomModels.\n            var axisProxy = axisModel.__dzAxisProxy || (\n                // Use the first dataZoomModel as the main model of axisProxy.\n                axisModel.__dzAxisProxy = new AxisProxy(\n                    dimNames.name, axisIndex, this, ecModel\n                )\n            );\n            // FIXME\n            // dispose __dzAxisProxy\n\n            axisProxies[dimNames.name + '_' + axisIndex] = axisProxy;\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _resetTarget: function () {\n        var thisOption = this.option;\n\n        var autoMode = this._judgeAutoMode();\n\n        eachAxisDim(function (dimNames) {\n            var axisIndexName = dimNames.axisIndex;\n            thisOption[axisIndexName] = normalizeToArray(\n                thisOption[axisIndexName]\n            );\n        }, this);\n\n        if (autoMode === 'axisIndex') {\n            this._autoSetAxisIndex();\n        }\n        else if (autoMode === 'orient') {\n            this._autoSetOrient();\n        }\n    },\n\n    /**\n     * @private\n     */\n    _judgeAutoMode: function () {\n        // Auto set only works for setOption at the first time.\n        // The following is user's reponsibility. So using merged\n        // option is OK.\n        var thisOption = this.option;\n\n        var hasIndexSpecified = false;\n        eachAxisDim(function (dimNames) {\n            // When user set axisIndex as a empty array, we think that user specify axisIndex\n            // but do not want use auto mode. Because empty array may be encountered when\n            // some error occured.\n            if (thisOption[dimNames.axisIndex] != null) {\n                hasIndexSpecified = true;\n            }\n        }, this);\n\n        var orient = thisOption.orient;\n\n        if (orient == null && hasIndexSpecified) {\n            return 'orient';\n        }\n        else if (!hasIndexSpecified) {\n            if (orient == null) {\n                thisOption.orient = 'horizontal';\n            }\n            return 'axisIndex';\n        }\n    },\n\n    /**\n     * @private\n     */\n    _autoSetAxisIndex: function () {\n        var autoAxisIndex = true;\n        var orient = this.get('orient', true);\n        var thisOption = this.option;\n        var dependentModels = this.dependentModels;\n\n        if (autoAxisIndex) {\n            // Find axis that parallel to dataZoom as default.\n            var dimName = orient === 'vertical' ? 'y' : 'x';\n\n            if (dependentModels[dimName + 'Axis'].length) {\n                thisOption[dimName + 'AxisIndex'] = [0];\n                autoAxisIndex = false;\n            }\n            else {\n                each$12(dependentModels.singleAxis, function (singleAxisModel) {\n                    if (autoAxisIndex && singleAxisModel.get('orient', true) === orient) {\n                        thisOption.singleAxisIndex = [singleAxisModel.componentIndex];\n                        autoAxisIndex = false;\n                    }\n                });\n            }\n        }\n\n        if (autoAxisIndex) {\n            // Find the first category axis as default. (consider polar)\n            eachAxisDim(function (dimNames) {\n                if (!autoAxisIndex) {\n                    return;\n                }\n                var axisIndices = [];\n                var axisModels = this.dependentModels[dimNames.axis];\n                if (axisModels.length && !axisIndices.length) {\n                    for (var i = 0, len = axisModels.length; i < len; i++) {\n                        if (axisModels[i].get('type') === 'category') {\n                            axisIndices.push(i);\n                        }\n                    }\n                }\n                thisOption[dimNames.axisIndex] = axisIndices;\n                if (axisIndices.length) {\n                    autoAxisIndex = false;\n                }\n            }, this);\n        }\n\n        if (autoAxisIndex) {\n            // FIXME\n            // 这里是兼容ec2的写法（没指定xAxisIndex和yAxisIndex时把scatter和双数值轴折柱纳入dataZoom控制），\n            // 但是实际是否需要Grid.js#getScaleByOption来判断（考虑time，log等axis type）？\n\n            // If both dataZoom.xAxisIndex and dataZoom.yAxisIndex is not specified,\n            // dataZoom component auto adopts series that reference to\n            // both xAxis and yAxis which type is 'value'.\n            this.ecModel.eachSeries(function (seriesModel) {\n                if (this._isSeriesHasAllAxesTypeOf(seriesModel, 'value')) {\n                    eachAxisDim(function (dimNames) {\n                        var axisIndices = thisOption[dimNames.axisIndex];\n\n                        var axisIndex = seriesModel.get(dimNames.axisIndex);\n                        var axisId = seriesModel.get(dimNames.axisId);\n\n                        var axisModel = seriesModel.ecModel.queryComponents({\n                            mainType: dimNames.axis,\n                            index: axisIndex,\n                            id: axisId\n                        })[0];\n\n                        if (__DEV__) {\n                            if (!axisModel) {\n                                throw new Error(\n                                    dimNames.axis + ' \"' + retrieve(\n                                        axisIndex,\n                                        axisId,\n                                        0\n                                    ) + '\" not found'\n                                );\n                            }\n                        }\n                        axisIndex = axisModel.componentIndex;\n\n                        if (indexOf(axisIndices, axisIndex) < 0) {\n                            axisIndices.push(axisIndex);\n                        }\n                    });\n                }\n            }, this);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _autoSetOrient: function () {\n        var dim;\n\n        // Find the first axis\n        this.eachTargetAxis(function (dimNames) {\n            !dim && (dim = dimNames.name);\n        }, this);\n\n        this.option.orient = dim === 'y' ? 'vertical' : 'horizontal';\n    },\n\n    /**\n     * @private\n     */\n    _isSeriesHasAllAxesTypeOf: function (seriesModel, axisType) {\n        // FIXME\n        // 需要series的xAxisIndex和yAxisIndex都首先自动设置上。\n        // 例如series.type === scatter时。\n\n        var is = true;\n        eachAxisDim(function (dimNames) {\n            var seriesAxisIndex = seriesModel.get(dimNames.axisIndex);\n            var axisModel = this.dependentModels[dimNames.axis][seriesAxisIndex];\n\n            if (!axisModel || axisModel.get('type') !== axisType) {\n                is = false;\n            }\n        }, this);\n        return is;\n    },\n\n    /**\n     * @private\n     */\n    _setDefaultThrottle: function (rawOption) {\n        // When first time user set throttle, auto throttle ends.\n        if (rawOption.hasOwnProperty('throttle')) {\n            this._autoThrottle = false;\n        }\n        if (this._autoThrottle) {\n            var globalOption = this.ecModel.option;\n            this.option.throttle\n                = (globalOption.animation && globalOption.animationDurationUpdate > 0)\n                ? 100 : 20;\n        }\n    },\n\n    /**\n     * @public\n     */\n    getFirstTargetAxisModel: function () {\n        var firstAxisModel;\n        eachAxisDim(function (dimNames) {\n            if (firstAxisModel == null) {\n                var indices = this.get(dimNames.axisIndex);\n                if (indices.length) {\n                    firstAxisModel = this.dependentModels[dimNames.axis][indices[0]];\n                }\n            }\n        }, this);\n\n        return firstAxisModel;\n    },\n\n    /**\n     * @public\n     * @param {Function} callback param: axisModel, dimNames, axisIndex, dataZoomModel, ecModel\n     */\n    eachTargetAxis: function (callback, context) {\n        var ecModel = this.ecModel;\n        eachAxisDim(function (dimNames) {\n            each$12(\n                this.get(dimNames.axisIndex),\n                function (axisIndex) {\n                    callback.call(context, dimNames, axisIndex, this, ecModel);\n                },\n                this\n            );\n        }, this);\n    },\n\n    /**\n     * @param {string} dimName\n     * @param {number} axisIndex\n     * @return {module:echarts/component/dataZoom/AxisProxy} If not found, return null/undefined.\n     */\n    getAxisProxy: function (dimName, axisIndex) {\n        return this._axisProxies[dimName + '_' + axisIndex];\n    },\n\n    /**\n     * @param {string} dimName\n     * @param {number} axisIndex\n     * @return {module:echarts/model/Model} If not found, return null/undefined.\n     */\n    getAxisModel: function (dimName, axisIndex) {\n        var axisProxy = this.getAxisProxy(dimName, axisIndex);\n        return axisProxy && axisProxy.getAxisModel();\n    },\n\n    /**\n     * If not specified, set to undefined.\n     *\n     * @public\n     * @param {Object} opt\n     * @param {number} [opt.start]\n     * @param {number} [opt.end]\n     * @param {number} [opt.startValue]\n     * @param {number} [opt.endValue]\n     * @param {boolean} [ignoreUpdateRangeUsg=false]\n     */\n    setRawRange: function (opt, ignoreUpdateRangeUsg) {\n        var option = this.option;\n        each$12([['start', 'startValue'], ['end', 'endValue']], function (names) {\n            // If only one of 'start' and 'startValue' is not null/undefined, the other\n            // should be cleared, which enable clear the option.\n            // If both of them are not set, keep option with the original value, which\n            // enable use only set start but not set end when calling `dispatchAction`.\n            // The same as 'end' and 'endValue'.\n            if (opt[names[0]] != null || opt[names[1]] != null) {\n                option[names[0]] = opt[names[0]];\n                option[names[1]] = opt[names[1]];\n            }\n        }, this);\n\n        !ignoreUpdateRangeUsg && updateRangeUse(this, opt);\n    },\n\n    /**\n     * @public\n     * @return {Array.<number>} [startPercent, endPercent]\n     */\n    getPercentRange: function () {\n        var axisProxy = this.findRepresentativeAxisProxy();\n        if (axisProxy) {\n            return axisProxy.getDataPercentWindow();\n        }\n    },\n\n    /**\n     * @public\n     * For example, chart.getModel().getComponent('dataZoom').getValueRange('y', 0);\n     *\n     * @param {string} [axisDimName]\n     * @param {number} [axisIndex]\n     * @return {Array.<number>} [startValue, endValue] value can only be '-' or finite number.\n     */\n    getValueRange: function (axisDimName, axisIndex) {\n        if (axisDimName == null && axisIndex == null) {\n            var axisProxy = this.findRepresentativeAxisProxy();\n            if (axisProxy) {\n                return axisProxy.getDataValueWindow();\n            }\n        }\n        else {\n            return this.getAxisProxy(axisDimName, axisIndex).getDataValueWindow();\n        }\n    },\n\n    /**\n     * @public\n     * @param {module:echarts/model/Model} [axisModel] If axisModel given, find axisProxy\n     *      corresponding to the axisModel\n     * @return {module:echarts/component/dataZoom/AxisProxy}\n     */\n    findRepresentativeAxisProxy: function (axisModel) {\n        if (axisModel) {\n            return axisModel.__dzAxisProxy;\n        }\n\n        // Find the first hosted axisProxy\n        var axisProxies = this._axisProxies;\n        for (var key in axisProxies) {\n            if (axisProxies.hasOwnProperty(key) && axisProxies[key].hostedBy(this)) {\n                return axisProxies[key];\n            }\n        }\n\n        // If no hosted axis find not hosted axisProxy.\n        // Consider this case: dataZoomModel1 and dataZoomModel2 control the same axis,\n        // and the option.start or option.end settings are different. The percentRange\n        // should follow axisProxy.\n        // (We encounter this problem in toolbox data zoom.)\n        for (var key in axisProxies) {\n            if (axisProxies.hasOwnProperty(key) && !axisProxies[key].hostedBy(this)) {\n                return axisProxies[key];\n            }\n        }\n    },\n\n    /**\n     * @return {Array.<string>}\n     */\n    getRangePropMode: function () {\n        return this._rangePropMode.slice();\n    }\n\n});\n\nfunction retrieveRaw(option) {\n    var ret = {};\n    each$12(\n        ['start', 'end', 'startValue', 'endValue', 'throttle'],\n        function (name) {\n            option.hasOwnProperty(name) && (ret[name] = option[name]);\n        }\n    );\n    return ret;\n}\n\nfunction updateRangeUse(dataZoomModel, rawOption) {\n    var rangePropMode = dataZoomModel._rangePropMode;\n    var rangeModeInOption = dataZoomModel.get('rangeMode');\n\n    each$12([['start', 'startValue'], ['end', 'endValue']], function (names, index) {\n        var percentSpecified = rawOption[names[0]] != null;\n        var valueSpecified = rawOption[names[1]] != null;\n        if (percentSpecified && !valueSpecified) {\n            rangePropMode[index] = 'percent';\n        }\n        else if (!percentSpecified && valueSpecified) {\n            rangePropMode[index] = 'value';\n        }\n        else if (rangeModeInOption) {\n            rangePropMode[index] = rangeModeInOption[index];\n        }\n        else if (percentSpecified) { // percentSpecified && valueSpecified\n            rangePropMode[index] = 'percent';\n        }\n        // else remain its original setting.\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DataZoomView = Component$1.extend({\n\n    type: 'dataZoom',\n\n    render: function (dataZoomModel, ecModel, api, payload) {\n        this.dataZoomModel = dataZoomModel;\n        this.ecModel = ecModel;\n        this.api = api;\n    },\n\n    /**\n     * Find the first target coordinate system.\n     *\n     * @protected\n     * @return {Object} {\n     *                   grid: [\n     *                       {model: coord0, axisModels: [axis1, axis3], coordIndex: 1},\n     *                       {model: coord1, axisModels: [axis0, axis2], coordIndex: 0},\n     *                       ...\n     *                   ],  // cartesians must not be null/undefined.\n     *                   polar: [\n     *                       {model: coord0, axisModels: [axis4], coordIndex: 0},\n     *                       ...\n     *                   ],  // polars must not be null/undefined.\n     *                   singleAxis: [\n     *                       {model: coord0, axisModels: [], coordIndex: 0}\n     *                   ]\n     */\n    getTargetCoordInfo: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var ecModel = this.ecModel;\n        var coordSysLists = {};\n\n        dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {\n            var axisModel = ecModel.getComponent(dimNames.axis, axisIndex);\n            if (axisModel) {\n                var coordModel = axisModel.getCoordSysModel();\n                coordModel && save(\n                    coordModel,\n                    axisModel,\n                    coordSysLists[coordModel.mainType] || (coordSysLists[coordModel.mainType] = []),\n                    coordModel.componentIndex\n                );\n            }\n        }, this);\n\n        function save(coordModel, axisModel, store, coordIndex) {\n            var item;\n            for (var i = 0; i < store.length; i++) {\n                if (store[i].model === coordModel) {\n                    item = store[i];\n                    break;\n                }\n            }\n            if (!item) {\n                store.push(item = {\n                    model: coordModel, axisModels: [], coordIndex: coordIndex\n                });\n            }\n            item.axisModels.push(axisModel);\n        }\n\n        return coordSysLists;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar SliderZoomModel = DataZoomModel.extend({\n\n    type: 'dataZoom.slider',\n\n    layoutMode: 'box',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        show: true,\n\n        // ph => placeholder. Using placehoder here because\n        // deault value can only be drived in view stage.\n        right: 'ph',  // Default align to grid rect.\n        top: 'ph',    // Default align to grid rect.\n        width: 'ph',  // Default align to grid rect.\n        height: 'ph', // Default align to grid rect.\n        left: null,   // Default align to grid rect.\n        bottom: null, // Default align to grid rect.\n\n        backgroundColor: 'rgba(47,69,84,0)',    // Background of slider zoom component.\n        // dataBackgroundColor: '#ddd',         // Background coor of data shadow and border of box,\n                                                // highest priority, remain for compatibility of\n                                                // previous version, but not recommended any more.\n        dataBackground: {\n            lineStyle: {\n                color: '#2f4554',\n                width: 0.5,\n                opacity: 0.3\n            },\n            areaStyle: {\n                color: 'rgba(47,69,84,0.3)',\n                opacity: 0.3\n            }\n        },\n        borderColor: '#ddd',                    // border color of the box. For compatibility,\n                                                // if dataBackgroundColor is set, borderColor\n                                                // is ignored.\n\n        fillerColor: 'rgba(167,183,204,0.4)',     // Color of selected area.\n        // handleColor: 'rgba(89,170,216,0.95)',     // Color of handle.\n        // handleIcon: 'path://M4.9,17.8c0-1.4,4.5-10.5,5.5-12.4c0-0.1,0.6-1.1,0.9-1.1c0.4,0,0.9,1,0.9,1.1c1.1,2.2,5.4,11,5.4,12.4v17.8c0,1.5-0.6,2.1-1.3,2.1H6.1c-0.7,0-1.3-0.6-1.3-2.1V17.8z',\n        /* eslint-disable */\n        handleIcon: 'M8.2,13.6V3.9H6.3v9.7H3.1v14.9h3.3v9.7h1.8v-9.7h3.3V13.6H8.2z M9.7,24.4H4.8v-1.4h4.9V24.4z M9.7,19.1H4.8v-1.4h4.9V19.1z',\n        /* eslint-enable */\n        // Percent of the slider height\n        handleSize: '100%',\n\n        handleStyle: {\n            color: '#a7b7cc'\n        },\n\n        labelPrecision: null,\n        labelFormatter: null,\n        showDetail: true,\n        showDataShadow: 'auto',                 // Default auto decision.\n        realtime: true,\n        zoomLock: false,                        // Whether disable zoom.\n        textStyle: {\n            color: '#333'\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Calculate slider move result.\n * Usage:\n * (1) If both handle0 and handle1 are needed to be moved, set minSpan the same as\n * maxSpan and the same as `Math.abs(handleEnd[1] - handleEnds[0])`.\n * (2) If handle0 is forbidden to cross handle1, set minSpan as `0`.\n *\n * @param {number} delta Move length.\n * @param {Array.<number>} handleEnds handleEnds[0] can be bigger then handleEnds[1].\n *              handleEnds will be modified in this method.\n * @param {Array.<number>} extent handleEnds is restricted by extent.\n *              extent[0] should less or equals than extent[1].\n * @param {number|string} handleIndex Can be 'all', means that both move the two handleEnds,\n *              where the input minSpan and maxSpan will not work.\n * @param {number} [minSpan] The range of dataZoom can not be smaller than that.\n *              If not set, handle0 and cross handle1. If set as a non-negative\n *              number (including `0`), handles will push each other when reaching\n *              the minSpan.\n * @param {number} [maxSpan] The range of dataZoom can not be larger than that.\n * @return {Array.<number>} The input handleEnds.\n */\nvar sliderMove = function (delta, handleEnds, extent, handleIndex, minSpan, maxSpan) {\n    // Normalize firstly.\n    handleEnds[0] = restrict(handleEnds[0], extent);\n    handleEnds[1] = restrict(handleEnds[1], extent);\n\n    delta = delta || 0;\n\n    var extentSpan = extent[1] - extent[0];\n\n    // Notice maxSpan and minSpan can be null/undefined.\n    if (minSpan != null) {\n        minSpan = restrict(minSpan, [0, extentSpan]);\n    }\n    if (maxSpan != null) {\n        maxSpan = Math.max(maxSpan, minSpan != null ? minSpan : 0);\n    }\n    if (handleIndex === 'all') {\n        minSpan = maxSpan = Math.abs(handleEnds[1] - handleEnds[0]);\n        handleIndex = 0;\n    }\n\n    var originalDistSign = getSpanSign(handleEnds, handleIndex);\n\n    handleEnds[handleIndex] += delta;\n\n    // Restrict in extent.\n    var extentMinSpan = minSpan || 0;\n    var realExtent = extent.slice();\n    originalDistSign.sign < 0 ? (realExtent[0] += extentMinSpan) : (realExtent[1] -= extentMinSpan);\n    handleEnds[handleIndex] = restrict(handleEnds[handleIndex], realExtent);\n\n    // Expand span.\n    var currDistSign = getSpanSign(handleEnds, handleIndex);\n    if (minSpan != null && (\n        currDistSign.sign !== originalDistSign.sign || currDistSign.span < minSpan\n    )) {\n        // If minSpan exists, 'cross' is forbinden.\n        handleEnds[1 - handleIndex] = handleEnds[handleIndex] + originalDistSign.sign * minSpan;\n    }\n\n    // Shrink span.\n    var currDistSign = getSpanSign(handleEnds, handleIndex);\n    if (maxSpan != null && currDistSign.span > maxSpan) {\n        handleEnds[1 - handleIndex] = handleEnds[handleIndex] + currDistSign.sign * maxSpan;\n    }\n\n    return handleEnds;\n};\n\nfunction getSpanSign(handleEnds, handleIndex) {\n    var dist = handleEnds[handleIndex] - handleEnds[1 - handleIndex];\n    // If `handleEnds[0] === handleEnds[1]`, always believe that handleEnd[0]\n    // is at left of handleEnds[1] for non-cross case.\n    return {span: Math.abs(dist), sign: dist > 0 ? -1 : dist < 0 ? 1 : handleIndex ? -1 : 1};\n}\n\nfunction restrict(value, extend) {\n    return Math.min(extend[1], Math.max(extend[0], value));\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar Rect$1 = Rect;\nvar linearMap$1 = linearMap;\nvar asc$2 = asc;\nvar bind$3 = bind;\nvar each$14 = each$1;\n\n// Constants\nvar DEFAULT_LOCATION_EDGE_GAP = 7;\nvar DEFAULT_FRAME_BORDER_WIDTH = 1;\nvar DEFAULT_FILLER_SIZE = 30;\nvar HORIZONTAL = 'horizontal';\nvar VERTICAL = 'vertical';\nvar LABEL_GAP = 5;\nvar SHOW_DATA_SHADOW_SERIES_TYPE = ['line', 'bar', 'candlestick', 'scatter'];\n\nvar SliderZoomView = DataZoomView.extend({\n\n    type: 'dataZoom.slider',\n\n    init: function (ecModel, api) {\n\n        /**\n         * @private\n         * @type {Object}\n         */\n        this._displayables = {};\n\n        /**\n         * @private\n         * @type {string}\n         */\n        this._orient;\n\n        /**\n         * [0, 100]\n         * @private\n         */\n        this._range;\n\n        /**\n         * [coord of the first handle, coord of the second handle]\n         * @private\n         */\n        this._handleEnds;\n\n        /**\n         * [length, thick]\n         * @private\n         * @type {Array.<number>}\n         */\n        this._size;\n\n        /**\n         * @private\n         * @type {number}\n         */\n        this._handleWidth;\n\n        /**\n         * @private\n         * @type {number}\n         */\n        this._handleHeight;\n\n        /**\n         * @private\n         */\n        this._location;\n\n        /**\n         * @private\n         */\n        this._dragging;\n\n        /**\n         * @private\n         */\n        this._dataShadowInfo;\n\n        this.api = api;\n    },\n\n    /**\n     * @override\n     */\n    render: function (dataZoomModel, ecModel, api, payload) {\n        SliderZoomView.superApply(this, 'render', arguments);\n\n        createOrUpdate(\n            this,\n            '_dispatchZoomAction',\n            this.dataZoomModel.get('throttle'),\n            'fixRate'\n        );\n\n        this._orient = dataZoomModel.get('orient');\n\n        if (this.dataZoomModel.get('show') === false) {\n            this.group.removeAll();\n            return;\n        }\n\n        // Notice: this._resetInterval() should not be executed when payload.type\n        // is 'dataZoom', origin this._range should be maintained, otherwise 'pan'\n        // or 'zoom' info will be missed because of 'throttle' of this.dispatchAction,\n        if (!payload || payload.type !== 'dataZoom' || payload.from !== this.uid) {\n            this._buildView();\n        }\n\n        this._updateView();\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        SliderZoomView.superApply(this, 'remove', arguments);\n        clear(this, '_dispatchZoomAction');\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        SliderZoomView.superApply(this, 'dispose', arguments);\n        clear(this, '_dispatchZoomAction');\n    },\n\n    _buildView: function () {\n        var thisGroup = this.group;\n\n        thisGroup.removeAll();\n\n        this._resetLocation();\n        this._resetInterval();\n\n        var barGroup = this._displayables.barGroup = new Group();\n\n        this._renderBackground();\n\n        this._renderHandle();\n\n        this._renderDataShadow();\n\n        thisGroup.add(barGroup);\n\n        this._positionGroup();\n    },\n\n    /**\n     * @private\n     */\n    _resetLocation: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var api = this.api;\n\n        // If some of x/y/width/height are not specified,\n        // auto-adapt according to target grid.\n        var coordRect = this._findCoordRect();\n        var ecSize = {width: api.getWidth(), height: api.getHeight()};\n        // Default align by coordinate system rect.\n        var positionInfo = this._orient === HORIZONTAL\n            ? {\n                // Why using 'right', because right should be used in vertical,\n                // and it is better to be consistent for dealing with position param merge.\n                right: ecSize.width - coordRect.x - coordRect.width,\n                top: (ecSize.height - DEFAULT_FILLER_SIZE - DEFAULT_LOCATION_EDGE_GAP),\n                width: coordRect.width,\n                height: DEFAULT_FILLER_SIZE\n            }\n            : { // vertical\n                right: DEFAULT_LOCATION_EDGE_GAP,\n                top: coordRect.y,\n                width: DEFAULT_FILLER_SIZE,\n                height: coordRect.height\n            };\n\n        // Do not write back to option and replace value 'ph', because\n        // the 'ph' value should be recalculated when resize.\n        var layoutParams = getLayoutParams(dataZoomModel.option);\n\n        // Replace the placeholder value.\n        each$1(['right', 'top', 'width', 'height'], function (name) {\n            if (layoutParams[name] === 'ph') {\n                layoutParams[name] = positionInfo[name];\n            }\n        });\n\n        var layoutRect = getLayoutRect(\n            layoutParams,\n            ecSize,\n            dataZoomModel.padding\n        );\n\n        this._location = {x: layoutRect.x, y: layoutRect.y};\n        this._size = [layoutRect.width, layoutRect.height];\n        this._orient === VERTICAL && this._size.reverse();\n    },\n\n    /**\n     * @private\n     */\n    _positionGroup: function () {\n        var thisGroup = this.group;\n        var location = this._location;\n        var orient = this._orient;\n\n        // Just use the first axis to determine mapping.\n        var targetAxisModel = this.dataZoomModel.getFirstTargetAxisModel();\n        var inverse = targetAxisModel && targetAxisModel.get('inverse');\n\n        var barGroup = this._displayables.barGroup;\n        var otherAxisInverse = (this._dataShadowInfo || {}).otherAxisInverse;\n\n        // Transform barGroup.\n        barGroup.attr(\n            (orient === HORIZONTAL && !inverse)\n            ? {scale: otherAxisInverse ? [1, 1] : [1, -1]}\n            : (orient === HORIZONTAL && inverse)\n            ? {scale: otherAxisInverse ? [-1, 1] : [-1, -1]}\n            : (orient === VERTICAL && !inverse)\n            ? {scale: otherAxisInverse ? [1, -1] : [1, 1], rotation: Math.PI / 2}\n            // Dont use Math.PI, considering shadow direction.\n            : {scale: otherAxisInverse ? [-1, -1] : [-1, 1], rotation: Math.PI / 2}\n        );\n\n        // Position barGroup\n        var rect = thisGroup.getBoundingRect([barGroup]);\n        thisGroup.attr('position', [location.x - rect.x, location.y - rect.y]);\n    },\n\n    /**\n     * @private\n     */\n    _getViewExtent: function () {\n        return [0, this._size[0]];\n    },\n\n    _renderBackground: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var size = this._size;\n        var barGroup = this._displayables.barGroup;\n\n        barGroup.add(new Rect$1({\n            silent: true,\n            shape: {\n                x: 0, y: 0, width: size[0], height: size[1]\n            },\n            style: {\n                fill: dataZoomModel.get('backgroundColor')\n            },\n            z2: -40\n        }));\n\n        // Click panel, over shadow, below handles.\n        barGroup.add(new Rect$1({\n            shape: {\n                x: 0, y: 0, width: size[0], height: size[1]\n            },\n            style: {\n                fill: 'transparent'\n            },\n            z2: 0,\n            onclick: bind(this._onClickPanelClick, this)\n        }));\n    },\n\n    _renderDataShadow: function () {\n        var info = this._dataShadowInfo = this._prepareDataShadowInfo();\n\n        if (!info) {\n            return;\n        }\n\n        var size = this._size;\n        var seriesModel = info.series;\n        var data = seriesModel.getRawData();\n\n        var otherDim = seriesModel.getShadowDim\n            ? seriesModel.getShadowDim() // @see candlestick\n            : info.otherDim;\n\n        if (otherDim == null) {\n            return;\n        }\n\n        var otherDataExtent = data.getDataExtent(otherDim);\n        // Nice extent.\n        var otherOffset = (otherDataExtent[1] - otherDataExtent[0]) * 0.3;\n        otherDataExtent = [\n            otherDataExtent[0] - otherOffset,\n            otherDataExtent[1] + otherOffset\n        ];\n        var otherShadowExtent = [0, size[1]];\n\n        var thisShadowExtent = [0, size[0]];\n\n        var areaPoints = [[size[0], 0], [0, 0]];\n        var linePoints = [];\n        var step = thisShadowExtent[1] / (data.count() - 1);\n        var thisCoord = 0;\n\n        // Optimize for large data shadow\n        var stride = Math.round(data.count() / size[0]);\n        var lastIsEmpty;\n        data.each([otherDim], function (value, index) {\n            if (stride > 0 && (index % stride)) {\n                thisCoord += step;\n                return;\n            }\n\n            // FIXME\n            // Should consider axis.min/axis.max when drawing dataShadow.\n\n            // FIXME\n            // 应该使用统一的空判断？还是在list里进行空判断？\n            var isEmpty = value == null || isNaN(value) || value === '';\n            // See #4235.\n            var otherCoord = isEmpty\n                ? 0 : linearMap$1(value, otherDataExtent, otherShadowExtent, true);\n\n            // Attempt to draw data shadow precisely when there are empty value.\n            if (isEmpty && !lastIsEmpty && index) {\n                areaPoints.push([areaPoints[areaPoints.length - 1][0], 0]);\n                linePoints.push([linePoints[linePoints.length - 1][0], 0]);\n            }\n            else if (!isEmpty && lastIsEmpty) {\n                areaPoints.push([thisCoord, 0]);\n                linePoints.push([thisCoord, 0]);\n            }\n\n            areaPoints.push([thisCoord, otherCoord]);\n            linePoints.push([thisCoord, otherCoord]);\n\n            thisCoord += step;\n            lastIsEmpty = isEmpty;\n        });\n\n        var dataZoomModel = this.dataZoomModel;\n        // var dataBackgroundModel = dataZoomModel.getModel('dataBackground');\n        this._displayables.barGroup.add(new Polygon({\n            shape: {points: areaPoints},\n            style: defaults(\n                {fill: dataZoomModel.get('dataBackgroundColor')},\n                dataZoomModel.getModel('dataBackground.areaStyle').getAreaStyle()\n            ),\n            silent: true,\n            z2: -20\n        }));\n        this._displayables.barGroup.add(new Polyline({\n            shape: {points: linePoints},\n            style: dataZoomModel.getModel('dataBackground.lineStyle').getLineStyle(),\n            silent: true,\n            z2: -19\n        }));\n    },\n\n    _prepareDataShadowInfo: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var showDataShadow = dataZoomModel.get('showDataShadow');\n\n        if (showDataShadow === false) {\n            return;\n        }\n\n        // Find a representative series.\n        var result;\n        var ecModel = this.ecModel;\n\n        dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {\n            var seriesModels = dataZoomModel\n                .getAxisProxy(dimNames.name, axisIndex)\n                .getTargetSeriesModels();\n\n            each$1(seriesModels, function (seriesModel) {\n                if (result) {\n                    return;\n                }\n\n                if (showDataShadow !== true && indexOf(\n                        SHOW_DATA_SHADOW_SERIES_TYPE, seriesModel.get('type')\n                    ) < 0\n                ) {\n                    return;\n                }\n\n                var thisAxis = ecModel.getComponent(dimNames.axis, axisIndex).axis;\n                var otherDim = getOtherDim(dimNames.name);\n                var otherAxisInverse;\n                var coordSys = seriesModel.coordinateSystem;\n\n                if (otherDim != null && coordSys.getOtherAxis) {\n                    otherAxisInverse = coordSys.getOtherAxis(thisAxis).inverse;\n                }\n\n                otherDim = seriesModel.getData().mapDimension(otherDim);\n\n                result = {\n                    thisAxis: thisAxis,\n                    series: seriesModel,\n                    thisDim: dimNames.name,\n                    otherDim: otherDim,\n                    otherAxisInverse: otherAxisInverse\n                };\n\n            }, this);\n\n        }, this);\n\n        return result;\n    },\n\n    _renderHandle: function () {\n        var displaybles = this._displayables;\n        var handles = displaybles.handles = [];\n        var handleLabels = displaybles.handleLabels = [];\n        var barGroup = this._displayables.barGroup;\n        var size = this._size;\n        var dataZoomModel = this.dataZoomModel;\n\n        barGroup.add(displaybles.filler = new Rect$1({\n            draggable: true,\n            cursor: getCursor(this._orient),\n            drift: bind$3(this._onDragMove, this, 'all'),\n            onmousemove: function (e) {\n                // Fot mobile devicem, prevent screen slider on the button.\n                stop(e.event);\n            },\n            ondragstart: bind$3(this._showDataInfo, this, true),\n            ondragend: bind$3(this._onDragEnd, this),\n            onmouseover: bind$3(this._showDataInfo, this, true),\n            onmouseout: bind$3(this._showDataInfo, this, false),\n            style: {\n                fill: dataZoomModel.get('fillerColor'),\n                textPosition: 'inside'\n            }\n        }));\n\n        // Frame border.\n        barGroup.add(new Rect$1(subPixelOptimizeRect({\n            silent: true,\n            shape: {\n                x: 0,\n                y: 0,\n                width: size[0],\n                height: size[1]\n            },\n            style: {\n                stroke: dataZoomModel.get('dataBackgroundColor')\n                    || dataZoomModel.get('borderColor'),\n                lineWidth: DEFAULT_FRAME_BORDER_WIDTH,\n                fill: 'rgba(0,0,0,0)'\n            }\n        })));\n\n        each$14([0, 1], function (handleIndex) {\n            var path = createIcon(\n                dataZoomModel.get('handleIcon'),\n                {\n                    cursor: getCursor(this._orient),\n                    draggable: true,\n                    drift: bind$3(this._onDragMove, this, handleIndex),\n                    onmousemove: function (e) {\n                        // Fot mobile devicem, prevent screen slider on the button.\n                        stop(e.event);\n                    },\n                    ondragend: bind$3(this._onDragEnd, this),\n                    onmouseover: bind$3(this._showDataInfo, this, true),\n                    onmouseout: bind$3(this._showDataInfo, this, false)\n                },\n                {x: -1, y: 0, width: 2, height: 2}\n            );\n\n            var bRect = path.getBoundingRect();\n            this._handleHeight = parsePercent$1(dataZoomModel.get('handleSize'), this._size[1]);\n            this._handleWidth = bRect.width / bRect.height * this._handleHeight;\n\n            path.setStyle(dataZoomModel.getModel('handleStyle').getItemStyle());\n            var handleColor = dataZoomModel.get('handleColor');\n            // Compatitable with previous version\n            if (handleColor != null) {\n                path.style.fill = handleColor;\n            }\n\n            barGroup.add(handles[handleIndex] = path);\n\n            var textStyleModel = dataZoomModel.textStyleModel;\n\n            this.group.add(\n                handleLabels[handleIndex] = new Text({\n                silent: true,\n                invisible: true,\n                style: {\n                    x: 0, y: 0, text: '',\n                    textVerticalAlign: 'middle',\n                    textAlign: 'center',\n                    textFill: textStyleModel.getTextColor(),\n                    textFont: textStyleModel.getFont()\n                },\n                z2: 10\n            }));\n\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _resetInterval: function () {\n        var range = this._range = this.dataZoomModel.getPercentRange();\n        var viewExtent = this._getViewExtent();\n\n        this._handleEnds = [\n            linearMap$1(range[0], [0, 100], viewExtent, true),\n            linearMap$1(range[1], [0, 100], viewExtent, true)\n        ];\n    },\n\n    /**\n     * @private\n     * @param {(number|string)} handleIndex 0 or 1 or 'all'\n     * @param {number} delta\n     * @return {boolean} changed\n     */\n    _updateInterval: function (handleIndex, delta) {\n        var dataZoomModel = this.dataZoomModel;\n        var handleEnds = this._handleEnds;\n        var viewExtend = this._getViewExtent();\n        var minMaxSpan = dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan();\n        var percentExtent = [0, 100];\n\n        sliderMove(\n            delta,\n            handleEnds,\n            viewExtend,\n            dataZoomModel.get('zoomLock') ? 'all' : handleIndex,\n            minMaxSpan.minSpan != null\n                ? linearMap$1(minMaxSpan.minSpan, percentExtent, viewExtend, true) : null,\n            minMaxSpan.maxSpan != null\n                ? linearMap$1(minMaxSpan.maxSpan, percentExtent, viewExtend, true) : null\n        );\n\n        var lastRange = this._range;\n        var range = this._range = asc$2([\n            linearMap$1(handleEnds[0], viewExtend, percentExtent, true),\n            linearMap$1(handleEnds[1], viewExtend, percentExtent, true)\n        ]);\n\n        return !lastRange || lastRange[0] !== range[0] || lastRange[1] !== range[1];\n    },\n\n    /**\n     * @private\n     */\n    _updateView: function (nonRealtime) {\n        var displaybles = this._displayables;\n        var handleEnds = this._handleEnds;\n        var handleInterval = asc$2(handleEnds.slice());\n        var size = this._size;\n\n        each$14([0, 1], function (handleIndex) {\n            // Handles\n            var handle = displaybles.handles[handleIndex];\n            var handleHeight = this._handleHeight;\n            handle.attr({\n                scale: [handleHeight / 2, handleHeight / 2],\n                position: [handleEnds[handleIndex], size[1] / 2 - handleHeight / 2]\n            });\n        }, this);\n\n        // Filler\n        displaybles.filler.setShape({\n            x: handleInterval[0],\n            y: 0,\n            width: handleInterval[1] - handleInterval[0],\n            height: size[1]\n        });\n\n        this._updateDataInfo(nonRealtime);\n    },\n\n    /**\n     * @private\n     */\n    _updateDataInfo: function (nonRealtime) {\n        var dataZoomModel = this.dataZoomModel;\n        var displaybles = this._displayables;\n        var handleLabels = displaybles.handleLabels;\n        var orient = this._orient;\n        var labelTexts = ['', ''];\n\n        // FIXME\n        // date型，支持formatter，autoformatter（ec2 date.getAutoFormatter）\n        if (dataZoomModel.get('showDetail')) {\n            var axisProxy = dataZoomModel.findRepresentativeAxisProxy();\n\n            if (axisProxy) {\n                var axis = axisProxy.getAxisModel().axis;\n                var range = this._range;\n\n                var dataInterval = nonRealtime\n                    // See #4434, data and axis are not processed and reset yet in non-realtime mode.\n                    ? axisProxy.calculateDataWindow({\n                        start: range[0], end: range[1]\n                    }).valueWindow\n                    : axisProxy.getDataValueWindow();\n\n                labelTexts = [\n                    this._formatLabel(dataInterval[0], axis),\n                    this._formatLabel(dataInterval[1], axis)\n                ];\n            }\n        }\n\n        var orderedHandleEnds = asc$2(this._handleEnds.slice());\n\n        setLabel.call(this, 0);\n        setLabel.call(this, 1);\n\n        function setLabel(handleIndex) {\n            // Label\n            // Text should not transform by barGroup.\n            // Ignore handlers transform\n            var barTransform = getTransform(\n                displaybles.handles[handleIndex].parent, this.group\n            );\n            var direction = transformDirection(\n                handleIndex === 0 ? 'right' : 'left', barTransform\n            );\n            var offset = this._handleWidth / 2 + LABEL_GAP;\n            var textPoint = applyTransform$1(\n                [\n                    orderedHandleEnds[handleIndex] + (handleIndex === 0 ? -offset : offset),\n                    this._size[1] / 2\n                ],\n                barTransform\n            );\n            handleLabels[handleIndex].setStyle({\n                x: textPoint[0],\n                y: textPoint[1],\n                textVerticalAlign: orient === HORIZONTAL ? 'middle' : direction,\n                textAlign: orient === HORIZONTAL ? direction : 'center',\n                text: labelTexts[handleIndex]\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _formatLabel: function (value, axis) {\n        var dataZoomModel = this.dataZoomModel;\n        var labelFormatter = dataZoomModel.get('labelFormatter');\n\n        var labelPrecision = dataZoomModel.get('labelPrecision');\n        if (labelPrecision == null || labelPrecision === 'auto') {\n            labelPrecision = axis.getPixelPrecision();\n        }\n\n        var valueStr = (value == null || isNaN(value))\n            ? ''\n            // FIXME Glue code\n            : (axis.type === 'category' || axis.type === 'time')\n                ? axis.scale.getLabel(Math.round(value))\n                // param of toFixed should less then 20.\n                : value.toFixed(Math.min(labelPrecision, 20));\n\n        return isFunction$1(labelFormatter)\n            ? labelFormatter(value, valueStr)\n            : isString(labelFormatter)\n            ? labelFormatter.replace('{value}', valueStr)\n            : valueStr;\n    },\n\n    /**\n     * @private\n     * @param {boolean} showOrHide true: show, false: hide\n     */\n    _showDataInfo: function (showOrHide) {\n        // Always show when drgging.\n        showOrHide = this._dragging || showOrHide;\n\n        var handleLabels = this._displayables.handleLabels;\n        handleLabels[0].attr('invisible', !showOrHide);\n        handleLabels[1].attr('invisible', !showOrHide);\n    },\n\n    _onDragMove: function (handleIndex, dx, dy) {\n        this._dragging = true;\n\n        // Transform dx, dy to bar coordination.\n        var barTransform = this._displayables.barGroup.getLocalTransform();\n        var vertex = applyTransform$1([dx, dy], barTransform, true);\n\n        var changed = this._updateInterval(handleIndex, vertex[0]);\n\n        var realtime = this.dataZoomModel.get('realtime');\n\n        this._updateView(!realtime);\n\n        // Avoid dispatch dataZoom repeatly but range not changed,\n        // which cause bad visual effect when progressive enabled.\n        changed && realtime && this._dispatchZoomAction();\n    },\n\n    _onDragEnd: function () {\n        this._dragging = false;\n        this._showDataInfo(false);\n\n        // While in realtime mode and stream mode, dispatch action when\n        // drag end will cause the whole view rerender, which is unnecessary.\n        var realtime = this.dataZoomModel.get('realtime');\n        !realtime && this._dispatchZoomAction();\n    },\n\n    _onClickPanelClick: function (e) {\n        var size = this._size;\n        var localPoint = this._displayables.barGroup.transformCoordToLocal(e.offsetX, e.offsetY);\n\n        if (localPoint[0] < 0 || localPoint[0] > size[0]\n            || localPoint[1] < 0 || localPoint[1] > size[1]\n        ) {\n            return;\n        }\n\n        var handleEnds = this._handleEnds;\n        var center = (handleEnds[0] + handleEnds[1]) / 2;\n\n        var changed = this._updateInterval('all', localPoint[0] - center);\n        this._updateView();\n        changed && this._dispatchZoomAction();\n    },\n\n    /**\n     * This action will be throttled.\n     * @private\n     */\n    _dispatchZoomAction: function () {\n        var range = this._range;\n\n        this.api.dispatchAction({\n            type: 'dataZoom',\n            from: this.uid,\n            dataZoomId: this.dataZoomModel.id,\n            start: range[0],\n            end: range[1]\n        });\n    },\n\n    /**\n     * @private\n     */\n    _findCoordRect: function () {\n        // Find the grid coresponding to the first axis referred by dataZoom.\n        var rect;\n        each$14(this.getTargetCoordInfo(), function (coordInfoList) {\n            if (!rect && coordInfoList.length) {\n                var coordSys = coordInfoList[0].model.coordinateSystem;\n                rect = coordSys.getRect && coordSys.getRect();\n            }\n        });\n        if (!rect) {\n            var width = this.api.getWidth();\n            var height = this.api.getHeight();\n            rect = {\n                x: width * 0.2,\n                y: height * 0.2,\n                width: width * 0.6,\n                height: height * 0.6\n            };\n        }\n\n        return rect;\n    }\n\n});\n\nfunction getOtherDim(thisDim) {\n    // FIXME\n    // 这个逻辑和getOtherAxis里一致，但是写在这里是否不好\n    var map$$1 = {x: 'y', y: 'x', radius: 'angle', angle: 'radius'};\n    return map$$1[thisDim];\n}\n\nfunction getCursor(orient) {\n    return orient === 'vertical' ? 'ns-resize' : 'ew-resize';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomModel.extend({\n\n    type: 'dataZoom.inside',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        disabled: false,   // Whether disable this inside zoom.\n        zoomLock: false,   // Whether disable zoom but only pan.\n        zoomOnMouseWheel: true, // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        moveOnMouseMove: true,   // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        moveOnMouseWheel: false, // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        preventDefaultMouseMove: true\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ATTR$1 = '\\0_ec_interaction_mutex';\n\nfunction take(zr, resourceKey, userKey) {\n    var store = getStore(zr);\n    store[resourceKey] = userKey;\n}\n\nfunction release(zr, resourceKey, userKey) {\n    var store = getStore(zr);\n    var uKey = store[resourceKey];\n\n    if (uKey === userKey) {\n        store[resourceKey] = null;\n    }\n}\n\nfunction isTaken(zr, resourceKey) {\n    return !!getStore(zr)[resourceKey];\n}\n\nfunction getStore(zr) {\n    return zr[ATTR$1] || (zr[ATTR$1] = {});\n}\n\n/**\n * payload: {\n *     type: 'takeGlobalCursor',\n *     key: 'dataZoomSelect', or 'brush', or ...,\n *         If no userKey, release global cursor.\n * }\n */\nregisterAction(\n    {type: 'takeGlobalCursor', event: 'globalCursorTaken', update: 'update'},\n    function () {}\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @alias module:echarts/component/helper/RoamController\n * @constructor\n * @mixin {module:zrender/mixin/Eventful}\n *\n * @param {module:zrender/zrender~ZRender} zr\n */\nfunction RoamController(zr) {\n\n    /**\n     * @type {Function}\n     */\n    this.pointerChecker;\n\n    /**\n     * @type {module:zrender}\n     */\n    this._zr = zr;\n\n    /**\n     * @type {Object}\n     */\n    this._opt = {};\n\n    // Avoid two roamController bind the same handler\n    var bind$$1 = bind;\n    var mousedownHandler = bind$$1(mousedown, this);\n    var mousemoveHandler = bind$$1(mousemove, this);\n    var mouseupHandler = bind$$1(mouseup, this);\n    var mousewheelHandler = bind$$1(mousewheel, this);\n    var pinchHandler = bind$$1(pinch, this);\n\n    Eventful.call(this);\n\n    /**\n     * @param {Function} pointerChecker\n     *                   input: x, y\n     *                   output: boolean\n     */\n    this.setPointerChecker = function (pointerChecker) {\n        this.pointerChecker = pointerChecker;\n    };\n\n    /**\n     * Notice: only enable needed types. For example, if 'zoom'\n     * is not needed, 'zoom' should not be enabled, otherwise\n     * default mousewheel behaviour (scroll page) will be disabled.\n     *\n     * @param  {boolean|string} [controlType=true] Specify the control type,\n     *                          which can be null/undefined or true/false\n     *                          or 'pan/move' or 'zoom'/'scale'\n     * @param {Object} [opt]\n     * @param {Object} [opt.zoomOnMouseWheel=true] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.moveOnMouseMove=true] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.moveOnMouseWheel=false] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.preventDefaultMouseMove=true] When pan.\n     */\n    this.enable = function (controlType, opt) {\n\n        // Disable previous first\n        this.disable();\n\n        this._opt = defaults(clone(opt) || {}, {\n            zoomOnMouseWheel: true,\n            moveOnMouseMove: true,\n            // By default, wheel do not trigger move.\n            moveOnMouseWheel: false,\n            preventDefaultMouseMove: true\n        });\n\n        if (controlType == null) {\n            controlType = true;\n        }\n\n        if (controlType === true || (controlType === 'move' || controlType === 'pan')) {\n            zr.on('mousedown', mousedownHandler);\n            zr.on('mousemove', mousemoveHandler);\n            zr.on('mouseup', mouseupHandler);\n        }\n        if (controlType === true || (controlType === 'scale' || controlType === 'zoom')) {\n            zr.on('mousewheel', mousewheelHandler);\n            zr.on('pinch', pinchHandler);\n        }\n    };\n\n    this.disable = function () {\n        zr.off('mousedown', mousedownHandler);\n        zr.off('mousemove', mousemoveHandler);\n        zr.off('mouseup', mouseupHandler);\n        zr.off('mousewheel', mousewheelHandler);\n        zr.off('pinch', pinchHandler);\n    };\n\n    this.dispose = this.disable;\n\n    this.isDragging = function () {\n        return this._dragging;\n    };\n\n    this.isPinching = function () {\n        return this._pinching;\n    };\n}\n\nmixin(RoamController, Eventful);\n\n\nfunction mousedown(e) {\n    if (isMiddleOrRightButtonOnMouseUpDown(e)\n        || (e.target && e.target.draggable)\n    ) {\n        return;\n    }\n\n    var x = e.offsetX;\n    var y = e.offsetY;\n\n    // Only check on mosedown, but not mousemove.\n    // Mouse can be out of target when mouse moving.\n    if (this.pointerChecker && this.pointerChecker(e, x, y)) {\n        this._x = x;\n        this._y = y;\n        this._dragging = true;\n    }\n}\n\nfunction mousemove(e) {\n    if (!this._dragging\n        || !isAvailableBehavior('moveOnMouseMove', e, this._opt)\n        || e.gestureEvent === 'pinch'\n        || isTaken(this._zr, 'globalPan')\n    ) {\n        return;\n    }\n\n    var x = e.offsetX;\n    var y = e.offsetY;\n\n    var oldX = this._x;\n    var oldY = this._y;\n\n    var dx = x - oldX;\n    var dy = y - oldY;\n\n    this._x = x;\n    this._y = y;\n\n    this._opt.preventDefaultMouseMove && stop(e.event);\n\n    trigger(this, 'pan', 'moveOnMouseMove', e, {\n        dx: dx, dy: dy, oldX: oldX, oldY: oldY, newX: x, newY: y\n    });\n}\n\nfunction mouseup(e) {\n    if (!isMiddleOrRightButtonOnMouseUpDown(e)) {\n        this._dragging = false;\n    }\n}\n\nfunction mousewheel(e) {\n    var shouldZoom = isAvailableBehavior('zoomOnMouseWheel', e, this._opt);\n    var shouldMove = isAvailableBehavior('moveOnMouseWheel', e, this._opt);\n    var wheelDelta = e.wheelDelta;\n    var absWheelDeltaDelta = Math.abs(wheelDelta);\n    var originX = e.offsetX;\n    var originY = e.offsetY;\n\n    // wheelDelta maybe -0 in chrome mac.\n    if (wheelDelta === 0 || (!shouldZoom && !shouldMove)) {\n        return;\n    }\n\n    // If both `shouldZoom` and `shouldMove` is true, trigger\n    // their event both, and the final behavior is determined\n    // by event listener themselves.\n\n    if (shouldZoom) {\n        // Convenience:\n        // Mac and VM Windows on Mac: scroll up: zoom out.\n        // Windows: scroll up: zoom in.\n\n        // FIXME: Should do more test in different environment.\n        // wheelDelta is too complicated in difference nvironment\n        // (https://developer.mozilla.org/en-US/docs/Web/Events/mousewheel),\n        // although it has been normallized by zrender.\n        // wheelDelta of mouse wheel is bigger than touch pad.\n        var factor = absWheelDeltaDelta > 3 ? 1.4 : absWheelDeltaDelta > 1 ? 1.2 : 1.1;\n        var scale = wheelDelta > 0 ? factor : 1 / factor;\n        checkPointerAndTrigger(this, 'zoom', 'zoomOnMouseWheel', e, {\n            scale: scale, originX: originX, originY: originY\n        });\n    }\n\n    if (shouldMove) {\n        // FIXME: Should do more test in different environment.\n        var absDelta = Math.abs(wheelDelta);\n        // wheelDelta of mouse wheel is bigger than touch pad.\n        var scrollDelta = (wheelDelta > 0 ? 1 : -1) * (absDelta > 3 ? 0.4 : absDelta > 1 ? 0.15 : 0.05);\n        checkPointerAndTrigger(this, 'scrollMove', 'moveOnMouseWheel', e, {\n            scrollDelta: scrollDelta, originX: originX, originY: originY\n        });\n    }\n}\n\nfunction pinch(e) {\n    if (isTaken(this._zr, 'globalPan')) {\n        return;\n    }\n    var scale = e.pinchScale > 1 ? 1.1 : 1 / 1.1;\n    checkPointerAndTrigger(this, 'zoom', null, e, {\n        scale: scale, originX: e.pinchX, originY: e.pinchY\n    });\n}\n\nfunction checkPointerAndTrigger(controller, eventName, behaviorToCheck, e, contollerEvent) {\n    if (controller.pointerChecker\n        && controller.pointerChecker(e, contollerEvent.originX, contollerEvent.originY)\n    ) {\n        // When mouse is out of roamController rect,\n        // default befavoius should not be be disabled, otherwise\n        // page sliding is disabled, contrary to expectation.\n        stop(e.event);\n\n        trigger(controller, eventName, behaviorToCheck, e, contollerEvent);\n    }\n}\n\nfunction trigger(controller, eventName, behaviorToCheck, e, contollerEvent) {\n    // Also provide behavior checker for event listener, for some case that\n    // multiple components share one listener.\n    contollerEvent.isAvailableBehavior = bind(isAvailableBehavior, null, behaviorToCheck, e);\n    controller.trigger(eventName, contollerEvent);\n}\n\n// settings: {\n//     zoomOnMouseWheel\n//     moveOnMouseMove\n//     moveOnMouseWheel\n// }\n// The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\nfunction isAvailableBehavior(behaviorToCheck, e, settings) {\n    var setting = settings[behaviorToCheck];\n    return !behaviorToCheck || (\n        setting && (!isString(setting) || e.event[setting + 'Key'])\n    );\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Only create one roam controller for each coordinate system.\n// one roam controller might be refered by two inside data zoom\n// components (for example, one for x and one for y). When user\n// pan or zoom, only dispatch one action for those data zoom\n// components.\n\nvar ATTR = '\\0_ec_dataZoom_roams';\n\n\n/**\n * @public\n * @param {module:echarts/ExtensionAPI} api\n * @param {Object} dataZoomInfo\n * @param {string} dataZoomInfo.coordId\n * @param {Function} dataZoomInfo.containsPoint\n * @param {Array.<string>} dataZoomInfo.allCoordIds\n * @param {string} dataZoomInfo.dataZoomId\n * @param {Object} dataZoomInfo.getRange\n * @param {Function} dataZoomInfo.getRange.pan\n * @param {Function} dataZoomInfo.getRange.zoom\n * @param {Function} dataZoomInfo.getRange.scrollMove\n * @param {boolean} dataZoomInfo.dataZoomModel\n */\nfunction register$1(api, dataZoomInfo) {\n    var store = giveStore(api);\n    var theDataZoomId = dataZoomInfo.dataZoomId;\n    var theCoordId = dataZoomInfo.coordId;\n\n    // Do clean when a dataZoom changes its target coordnate system.\n    // Avoid memory leak, dispose all not-used-registered.\n    each$1(store, function (record, coordId) {\n        var dataZoomInfos = record.dataZoomInfos;\n        if (dataZoomInfos[theDataZoomId]\n            && indexOf(dataZoomInfo.allCoordIds, theCoordId) < 0\n        ) {\n            delete dataZoomInfos[theDataZoomId];\n            record.count--;\n        }\n    });\n\n    cleanStore(store);\n\n    var record = store[theCoordId];\n    // Create if needed.\n    if (!record) {\n        record = store[theCoordId] = {\n            coordId: theCoordId,\n            dataZoomInfos: {},\n            count: 0\n        };\n        record.controller = createController(api, record);\n        record.dispatchAction = curry(dispatchAction, api);\n    }\n\n    // Update reference of dataZoom.\n    !(record.dataZoomInfos[theDataZoomId]) && record.count++;\n    record.dataZoomInfos[theDataZoomId] = dataZoomInfo;\n\n    var controllerParams = mergeControllerParams(record.dataZoomInfos);\n    record.controller.enable(controllerParams.controlType, controllerParams.opt);\n\n    // Consider resize, area should be always updated.\n    record.controller.setPointerChecker(dataZoomInfo.containsPoint);\n\n    // Update throttle.\n    createOrUpdate(\n        record,\n        'dispatchAction',\n        dataZoomInfo.dataZoomModel.get('throttle', true),\n        'fixRate'\n    );\n}\n\n/**\n * @public\n * @param {module:echarts/ExtensionAPI} api\n * @param {string} dataZoomId\n */\nfunction unregister$1(api, dataZoomId) {\n    var store = giveStore(api);\n\n    each$1(store, function (record) {\n        record.controller.dispose();\n        var dataZoomInfos = record.dataZoomInfos;\n        if (dataZoomInfos[dataZoomId]) {\n            delete dataZoomInfos[dataZoomId];\n            record.count--;\n        }\n    });\n\n    cleanStore(store);\n}\n\n/**\n * @public\n */\nfunction generateCoordId(coordModel) {\n    return coordModel.type + '\\0_' + coordModel.id;\n}\n\n/**\n * Key: coordId, value: {dataZoomInfos: [], count, controller}\n * @type {Array.<Object>}\n */\nfunction giveStore(api) {\n    // Mount store on zrender instance, so that we do not\n    // need to worry about dispose.\n    var zr = api.getZr();\n    return zr[ATTR] || (zr[ATTR] = {});\n}\n\nfunction createController(api, newRecord) {\n    var controller = new RoamController(api.getZr());\n\n    each$1(['pan', 'zoom', 'scrollMove'], function (eventName) {\n        controller.on(eventName, function (event) {\n            var batch = [];\n\n            each$1(newRecord.dataZoomInfos, function (info) {\n                // Check whether the behaviors (zoomOnMouseWheel, moveOnMouseMove,\n                // moveOnMouseWheel, ...) enabled.\n                if (!event.isAvailableBehavior(info.dataZoomModel.option)) {\n                    return;\n                }\n\n                var method = (info.getRange || {})[eventName];\n                var range = method && method(newRecord.controller, event);\n\n                !info.dataZoomModel.get('disabled', true) && range && batch.push({\n                    dataZoomId: info.dataZoomId,\n                    start: range[0],\n                    end: range[1]\n                });\n            });\n\n            batch.length && newRecord.dispatchAction(batch);\n        });\n    });\n\n    return controller;\n}\n\nfunction cleanStore(store) {\n    each$1(store, function (record, coordId) {\n        if (!record.count) {\n            record.controller.dispose();\n            delete store[coordId];\n        }\n    });\n}\n\n/**\n * This action will be throttled.\n */\nfunction dispatchAction(api, batch) {\n    api.dispatchAction({\n        type: 'dataZoom',\n        batch: batch\n    });\n}\n\n/**\n * Merge roamController settings when multiple dataZooms share one roamController.\n */\nfunction mergeControllerParams(dataZoomInfos) {\n    var controlType;\n    // DO NOT use reserved word (true, false, undefined) as key literally. Even if encapsulated\n    // as string, it is probably revert to reserved word by compress tool. See #7411.\n    var prefix = 'type_';\n    var typePriority = {\n        'type_true': 2,\n        'type_move': 1,\n        'type_false': 0,\n        'type_undefined': -1\n    };\n    var preventDefaultMouseMove = true;\n\n    each$1(dataZoomInfos, function (dataZoomInfo) {\n        var dataZoomModel = dataZoomInfo.dataZoomModel;\n        var oneType = dataZoomModel.get('disabled', true)\n            ? false\n            : dataZoomModel.get('zoomLock', true)\n            ? 'move'\n            : true;\n        if (typePriority[prefix + oneType] > typePriority[prefix + controlType]) {\n            controlType = oneType;\n        }\n\n        // Prevent default move event by default. If one false, do not prevent. Otherwise\n        // users may be confused why it does not work when multiple insideZooms exist.\n        preventDefaultMouseMove &= dataZoomModel.get('preventDefaultMouseMove', true);\n    });\n\n    return {\n        controlType: controlType,\n        opt: {\n            // RoamController will enable all of these functionalities,\n            // and the final behavior is determined by its event listener\n            // provided by each inside zoom.\n            zoomOnMouseWheel: true,\n            moveOnMouseMove: true,\n            moveOnMouseWheel: true,\n            preventDefaultMouseMove: !!preventDefaultMouseMove\n        }\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$4 = bind;\n\nvar InsideZoomView = DataZoomView.extend({\n\n    type: 'dataZoom.inside',\n\n    /**\n     * @override\n     */\n    init: function (ecModel, api) {\n        /**\n         * 'throttle' is used in this.dispatchAction, so we save range\n         * to avoid missing some 'pan' info.\n         * @private\n         * @type {Array.<number>}\n         */\n        this._range;\n    },\n\n    /**\n     * @override\n     */\n    render: function (dataZoomModel, ecModel, api, payload) {\n        InsideZoomView.superApply(this, 'render', arguments);\n\n        // Hance the `throttle` util ensures to preserve command order,\n        // here simply updating range all the time will not cause missing\n        // any of the the roam change.\n        this._range = dataZoomModel.getPercentRange();\n\n        // Reset controllers.\n        each$1(this.getTargetCoordInfo(), function (coordInfoList, coordSysName) {\n\n            var allCoordIds = map(coordInfoList, function (coordInfo) {\n                return generateCoordId(coordInfo.model);\n            });\n\n            each$1(coordInfoList, function (coordInfo) {\n                var coordModel = coordInfo.model;\n\n                var getRange = {};\n                each$1(['pan', 'zoom', 'scrollMove'], function (eventName) {\n                    getRange[eventName] = bind$4(roamHandlers[eventName], this, coordInfo, coordSysName);\n                }, this);\n\n                register$1(\n                    api,\n                    {\n                        coordId: generateCoordId(coordModel),\n                        allCoordIds: allCoordIds,\n                        containsPoint: function (e, x, y) {\n                            return coordModel.coordinateSystem.containPoint([x, y]);\n                        },\n                        dataZoomId: dataZoomModel.id,\n                        dataZoomModel: dataZoomModel,\n                        getRange: getRange\n                    }\n                );\n            }, this);\n\n        }, this);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        unregister$1(this.api, this.dataZoomModel.id);\n        InsideZoomView.superApply(this, 'dispose', arguments);\n        this._range = null;\n    }\n\n});\n\nvar roamHandlers = {\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    zoom: function (coordInfo, coordSysName, controller, e) {\n        var lastRange = this._range;\n        var range = lastRange.slice();\n\n        // Calculate transform by the first axis.\n        var axisModel = coordInfo.axisModels[0];\n        if (!axisModel) {\n            return;\n        }\n\n        var directionInfo = getDirectionInfo[coordSysName](\n            null, [e.originX, e.originY], axisModel, controller, coordInfo\n        );\n        var percentPoint = (\n            directionInfo.signal > 0\n                ? (directionInfo.pixelStart + directionInfo.pixelLength - directionInfo.pixel)\n                : (directionInfo.pixel - directionInfo.pixelStart)\n            ) / directionInfo.pixelLength * (range[1] - range[0]) + range[0];\n\n        var scale = Math.max(1 / e.scale, 0);\n        range[0] = (range[0] - percentPoint) * scale + percentPoint;\n        range[1] = (range[1] - percentPoint) * scale + percentPoint;\n\n        // Restrict range.\n        var minMaxSpan = this.dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan();\n\n        sliderMove(0, range, [0, 100], 0, minMaxSpan.minSpan, minMaxSpan.maxSpan);\n\n        this._range = range;\n\n        if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) {\n            return range;\n        }\n    },\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    pan: makeMover(function (range, axisModel, coordInfo, coordSysName, controller, e) {\n        var directionInfo = getDirectionInfo[coordSysName](\n            [e.oldX, e.oldY], [e.newX, e.newY], axisModel, controller, coordInfo\n        );\n\n        return directionInfo.signal\n            * (range[1] - range[0])\n            * directionInfo.pixel / directionInfo.pixelLength;\n    }),\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    scrollMove: makeMover(function (range, axisModel, coordInfo, coordSysName, controller, e) {\n        var directionInfo = getDirectionInfo[coordSysName](\n            [0, 0], [e.scrollDelta, e.scrollDelta], axisModel, controller, coordInfo\n        );\n        return directionInfo.signal * (range[1] - range[0]) * e.scrollDelta;\n    })\n};\n\nfunction makeMover(getPercentDelta) {\n    return function (coordInfo, coordSysName, controller, e) {\n        var lastRange = this._range;\n        var range = lastRange.slice();\n\n        // Calculate transform by the first axis.\n        var axisModel = coordInfo.axisModels[0];\n        if (!axisModel) {\n            return;\n        }\n\n        var percentDelta = getPercentDelta(\n            range, axisModel, coordInfo, coordSysName, controller, e\n        );\n\n        sliderMove(percentDelta, range, [0, 100], 'all');\n\n        this._range = range;\n\n        if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) {\n            return range;\n        }\n    };\n}\n\nvar getDirectionInfo = {\n\n    grid: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var ret = {};\n        var rect = coordInfo.model.coordinateSystem.getRect();\n        oldPoint = oldPoint || [0, 0];\n\n        if (axis.dim === 'x') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            ret.pixelLength = rect.width;\n            ret.pixelStart = rect.x;\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // axis.dim === 'y'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            ret.pixelLength = rect.height;\n            ret.pixelStart = rect.y;\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    },\n\n    polar: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var ret = {};\n        var polar = coordInfo.model.coordinateSystem;\n        var radiusExtent = polar.getRadiusAxis().getExtent();\n        var angleExtent = polar.getAngleAxis().getExtent();\n\n        oldPoint = oldPoint ? polar.pointToCoord(oldPoint) : [0, 0];\n        newPoint = polar.pointToCoord(newPoint);\n\n        if (axisModel.mainType === 'radiusAxis') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            // ret.pixelLength = Math.abs(radiusExtent[1] - radiusExtent[0]);\n            // ret.pixelStart = Math.min(radiusExtent[0], radiusExtent[1]);\n            ret.pixelLength = radiusExtent[1] - radiusExtent[0];\n            ret.pixelStart = radiusExtent[0];\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // 'angleAxis'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            // ret.pixelLength = Math.abs(angleExtent[1] - angleExtent[0]);\n            // ret.pixelStart = Math.min(angleExtent[0], angleExtent[1]);\n            ret.pixelLength = angleExtent[1] - angleExtent[0];\n            ret.pixelStart = angleExtent[0];\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    },\n\n    singleAxis: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var rect = coordInfo.model.coordinateSystem.getRect();\n        var ret = {};\n\n        oldPoint = oldPoint || [0, 0];\n\n        if (axis.orient === 'horizontal') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            ret.pixelLength = rect.width;\n            ret.pixelStart = rect.x;\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // 'vertical'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            ret.pixelLength = rect.height;\n            ret.pixelStart = rect.y;\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterProcessor({\n\n    // `dataZoomProcessor` will only be performed in needed series. Consider if\n    // there is a line series and a pie series, it is better not to update the\n    // line series if only pie series is needed to be updated.\n    getTargetSeries: function (ecModel) {\n        var seriesModelMap = createHashMap();\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                var axisProxy = dataZoomModel.getAxisProxy(dimNames.name, axisIndex);\n                each$1(axisProxy.getTargetSeriesModels(), function (seriesModel) {\n                    seriesModelMap.set(seriesModel.uid, seriesModel);\n                });\n            });\n        });\n\n        return seriesModelMap;\n    },\n\n    modifyOutputEnd: true,\n\n    // Consider appendData, where filter should be performed. Because data process is\n    // in block mode currently, it is not need to worry about that the overallProgress\n    // execute every frame.\n    overallReset: function (ecModel, api) {\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            // We calculate window and reset axis here but not in model\n            // init stage and not after action dispatch handler, because\n            // reset should be called after seriesData.restoreData.\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                dataZoomModel.getAxisProxy(dimNames.name, axisIndex).reset(dataZoomModel, api);\n            });\n\n            // Caution: data zoom filtering is order sensitive when using\n            // percent range and no min/max/scale set on axis.\n            // For example, we have dataZoom definition:\n            // [\n            //      {xAxisIndex: 0, start: 30, end: 70},\n            //      {yAxisIndex: 0, start: 20, end: 80}\n            // ]\n            // In this case, [20, 80] of y-dataZoom should be based on data\n            // that have filtered by x-dataZoom using range of [30, 70],\n            // but should not be based on full raw data. Thus sliding\n            // x-dataZoom will change both ranges of xAxis and yAxis,\n            // while sliding y-dataZoom will only change the range of yAxis.\n            // So we should filter x-axis after reset x-axis immediately,\n            // and then reset y-axis and filter y-axis.\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                dataZoomModel.getAxisProxy(dimNames.name, axisIndex).filterData(dataZoomModel, api);\n            });\n        });\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            // Fullfill all of the range props so that user\n            // is able to get them from chart.getOption().\n            var axisProxy = dataZoomModel.findRepresentativeAxisProxy();\n            var percentRange = axisProxy.getDataPercentWindow();\n            var valueRange = axisProxy.getDataValueWindow();\n\n            dataZoomModel.setRawRange({\n                start: percentRange[0],\n                end: percentRange[1],\n                startValue: valueRange[0],\n                endValue: valueRange[1]\n            }, true);\n        });\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterAction('dataZoom', function (payload, ecModel) {\n\n    var linkedNodesFinder = createLinkedNodesFinder(\n        bind(ecModel.eachComponent, ecModel, 'dataZoom'),\n        eachAxisDim$1,\n        function (model, dimNames) {\n            return model.get(dimNames.axisIndex);\n        }\n    );\n\n    var effectedModels = [];\n\n    ecModel.eachComponent(\n        {mainType: 'dataZoom', query: payload},\n        function (model, index) {\n            effectedModels.push.apply(\n                effectedModels, linkedNodesFinder(model).nodes\n            );\n        }\n    );\n\n    each$1(effectedModels, function (dataZoomModel, index) {\n        dataZoomModel.setRawRange({\n            start: payload.start,\n            end: payload.end,\n            startValue: payload.startValue,\n            endValue: payload.endValue\n        });\n    });\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar features = {};\n\nfunction register$2(name, ctor) {\n    features[name] = ctor;\n}\n\nfunction get$1(name) {\n    return features[name];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ToolboxModel = extendComponentModel({\n\n    type: 'toolbox',\n\n    layoutMode: {\n        type: 'box',\n        ignoreSize: true\n    },\n\n    optionUpdated: function () {\n        ToolboxModel.superApply(this, 'optionUpdated', arguments);\n\n        each$1(this.option.feature, function (featureOpt, featureName) {\n            var Feature = get$1(featureName);\n            Feature && merge(featureOpt, Feature.defaultOption);\n        });\n    },\n\n    defaultOption: {\n\n        show: true,\n\n        z: 6,\n\n        zlevel: 0,\n\n        orient: 'horizontal',\n\n        left: 'right',\n\n        top: 'top',\n\n        // right\n        // bottom\n\n        backgroundColor: 'transparent',\n\n        borderColor: '#ccc',\n\n        borderRadius: 0,\n\n        borderWidth: 0,\n\n        padding: 5,\n\n        itemSize: 15,\n\n        itemGap: 8,\n\n        showTitle: true,\n\n        iconStyle: {\n            borderColor: '#666',\n            color: 'none'\n        },\n        emphasis: {\n            iconStyle: {\n                borderColor: '#3E98C5'\n            }\n        }\n        // textStyle: {},\n\n        // feature\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentView({\n\n    type: 'toolbox',\n\n    render: function (toolboxModel, ecModel, api, payload) {\n        var group = this.group;\n        group.removeAll();\n\n        if (!toolboxModel.get('show')) {\n            return;\n        }\n\n        var itemSize = +toolboxModel.get('itemSize');\n        var featureOpts = toolboxModel.get('feature') || {};\n        var features = this._features || (this._features = {});\n\n        var featureNames = [];\n        each$1(featureOpts, function (opt, name) {\n            featureNames.push(name);\n        });\n\n        (new DataDiffer(this._featureNames || [], featureNames))\n            .add(processFeature)\n            .update(processFeature)\n            .remove(curry(processFeature, null))\n            .execute();\n\n        // Keep for diff.\n        this._featureNames = featureNames;\n\n        function processFeature(newIndex, oldIndex) {\n            var featureName = featureNames[newIndex];\n            var oldName = featureNames[oldIndex];\n            var featureOpt = featureOpts[featureName];\n            var featureModel = new Model(featureOpt, toolboxModel, toolboxModel.ecModel);\n            var feature;\n\n            if (featureName && !oldName) { // Create\n                if (isUserFeatureName(featureName)) {\n                    feature = {\n                        model: featureModel,\n                        onclick: featureModel.option.onclick,\n                        featureName: featureName\n                    };\n                }\n                else {\n                    var Feature = get$1(featureName);\n                    if (!Feature) {\n                        return;\n                    }\n                    feature = new Feature(featureModel, ecModel, api);\n                }\n                features[featureName] = feature;\n            }\n            else {\n                feature = features[oldName];\n                // If feature does not exsit.\n                if (!feature) {\n                    return;\n                }\n                feature.model = featureModel;\n                feature.ecModel = ecModel;\n                feature.api = api;\n            }\n\n            if (!featureName && oldName) {\n                feature.dispose && feature.dispose(ecModel, api);\n                return;\n            }\n\n            if (!featureModel.get('show') || feature.unusable) {\n                feature.remove && feature.remove(ecModel, api);\n                return;\n            }\n\n            createIconPaths(featureModel, feature, featureName);\n\n            featureModel.setIconStatus = function (iconName, status) {\n                var option = this.option;\n                var iconPaths = this.iconPaths;\n                option.iconStatus = option.iconStatus || {};\n                option.iconStatus[iconName] = status;\n                // FIXME\n                iconPaths[iconName] && iconPaths[iconName].trigger(status);\n            };\n\n            if (feature.render) {\n                feature.render(featureModel, ecModel, api, payload);\n            }\n        }\n\n        function createIconPaths(featureModel, feature, featureName) {\n            var iconStyleModel = featureModel.getModel('iconStyle');\n            var iconStyleEmphasisModel = featureModel.getModel('emphasis.iconStyle');\n\n            // If one feature has mutiple icon. they are orginaized as\n            // {\n            //     icon: {\n            //         foo: '',\n            //         bar: ''\n            //     },\n            //     title: {\n            //         foo: '',\n            //         bar: ''\n            //     }\n            // }\n            var icons = feature.getIcons ? feature.getIcons() : featureModel.get('icon');\n            var titles = featureModel.get('title') || {};\n            if (typeof icons === 'string') {\n                var icon = icons;\n                var title = titles;\n                icons = {};\n                titles = {};\n                icons[featureName] = icon;\n                titles[featureName] = title;\n            }\n            var iconPaths = featureModel.iconPaths = {};\n            each$1(icons, function (iconStr, iconName) {\n                var path = createIcon(\n                    iconStr,\n                    {},\n                    {\n                        x: -itemSize / 2,\n                        y: -itemSize / 2,\n                        width: itemSize,\n                        height: itemSize\n                    }\n                );\n                path.setStyle(iconStyleModel.getItemStyle());\n                path.hoverStyle = iconStyleEmphasisModel.getItemStyle();\n\n                setHoverStyle(path);\n\n                if (toolboxModel.get('showTitle')) {\n                    path.__title = titles[iconName];\n                    path.on('mouseover', function () {\n                            // Should not reuse above hoverStyle, which might be modified.\n                            var hoverStyle = iconStyleEmphasisModel.getItemStyle();\n                            path.setStyle({\n                                text: titles[iconName],\n                                textPosition: hoverStyle.textPosition || 'bottom',\n                                textFill: hoverStyle.fill || hoverStyle.stroke || '#000',\n                                textAlign: hoverStyle.textAlign || 'center'\n                            });\n                        })\n                        .on('mouseout', function () {\n                            path.setStyle({\n                                textFill: null\n                            });\n                        });\n                }\n                path.trigger(featureModel.get('iconStatus.' + iconName) || 'normal');\n\n                group.add(path);\n                path.on('click', bind(\n                    feature.onclick, feature, ecModel, api, iconName\n                ));\n\n                iconPaths[iconName] = path;\n            });\n        }\n\n        layout$2(group, toolboxModel, api);\n        // Render background after group is layout\n        // FIXME\n        group.add(makeBackground(group.getBoundingRect(), toolboxModel));\n\n        // Adjust icon title positions to avoid them out of screen\n        group.eachChild(function (icon) {\n            var titleText = icon.__title;\n            var hoverStyle = icon.hoverStyle;\n            // May be background element\n            if (hoverStyle && titleText) {\n                var rect = getBoundingRect(\n                    titleText, makeFont(hoverStyle)\n                );\n                var offsetX = icon.position[0] + group.position[0];\n                var offsetY = icon.position[1] + group.position[1] + itemSize;\n\n                var needPutOnTop = false;\n                if (offsetY + rect.height > api.getHeight()) {\n                    hoverStyle.textPosition = 'top';\n                    needPutOnTop = true;\n                }\n                var topOffset = needPutOnTop ? (-5 - rect.height) : (itemSize + 8);\n                if (offsetX + rect.width / 2 > api.getWidth()) {\n                    hoverStyle.textPosition = ['100%', topOffset];\n                    hoverStyle.textAlign = 'right';\n                }\n                else if (offsetX - rect.width / 2 < 0) {\n                    hoverStyle.textPosition = [0, topOffset];\n                    hoverStyle.textAlign = 'left';\n                }\n            }\n        });\n    },\n\n    updateView: function (toolboxModel, ecModel, api, payload) {\n        each$1(this._features, function (feature) {\n            feature.updateView && feature.updateView(feature.model, ecModel, api, payload);\n        });\n    },\n\n    // updateLayout: function (toolboxModel, ecModel, api, payload) {\n    //     zrUtil.each(this._features, function (feature) {\n    //         feature.updateLayout && feature.updateLayout(feature.model, ecModel, api, payload);\n    //     });\n    // },\n\n    remove: function (ecModel, api) {\n        each$1(this._features, function (feature) {\n            feature.remove && feature.remove(ecModel, api);\n        });\n        this.group.removeAll();\n    },\n\n    dispose: function (ecModel, api) {\n        each$1(this._features, function (feature) {\n            feature.dispose && feature.dispose(ecModel, api);\n        });\n    }\n});\n\nfunction isUserFeatureName(featureName) {\n    return featureName.indexOf('my') === 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Uint8Array */\n\nvar saveAsImageLang = lang.toolbox.saveAsImage;\n\nfunction SaveAsImage(model) {\n    this.model = model;\n}\n\nSaveAsImage.defaultOption = {\n    show: true,\n    icon: 'M4.7,22.9L29.3,45.5L54.7,23.4M4.6,43.6L4.6,58L53.8,58L53.8,43.6M29.2,45.1L29.2,0',\n    title: saveAsImageLang.title,\n    type: 'png',\n    // Default use option.backgroundColor\n    // backgroundColor: '#fff',\n    name: '',\n    excludeComponents: ['toolbox'],\n    pixelRatio: 1,\n    lang: saveAsImageLang.lang.slice()\n};\n\nSaveAsImage.prototype.unusable = !env$1.canvasSupported;\n\nvar proto$2 = SaveAsImage.prototype;\n\nproto$2.onclick = function (ecModel, api) {\n    var model = this.model;\n    var title = model.get('name') || ecModel.get('title.0.text') || 'echarts';\n    var $a = document.createElement('a');\n    var type = model.get('type', true) || 'png';\n    $a.download = title + '.' + type;\n    $a.target = '_blank';\n    var url = api.getConnectedDataURL({\n        type: type,\n        backgroundColor: model.get('backgroundColor', true)\n            || ecModel.get('backgroundColor') || '#fff',\n        excludeComponents: model.get('excludeComponents'),\n        pixelRatio: model.get('pixelRatio')\n    });\n    $a.href = url;\n    // Chrome and Firefox\n    if (typeof MouseEvent === 'function' && !env$1.browser.ie && !env$1.browser.edge) {\n        var evt = new MouseEvent('click', {\n            view: window,\n            bubbles: true,\n            cancelable: false\n        });\n        $a.dispatchEvent(evt);\n    }\n    // IE\n    else {\n        if (window.navigator.msSaveOrOpenBlob) {\n            var bstr = atob(url.split(',')[1]);\n            var n = bstr.length;\n            var u8arr = new Uint8Array(n);\n            while (n--) {\n                u8arr[n] = bstr.charCodeAt(n);\n            }\n            var blob = new Blob([u8arr]);\n            window.navigator.msSaveOrOpenBlob(blob, title + '.' + type);\n        }\n        else {\n            var lang$$1 = model.get('lang');\n            var html = ''\n                + '<body style=\"margin:0;\">'\n                + '<img src=\"' + url + '\" style=\"max-width:100%;\" title=\"' + ((lang$$1 && lang$$1[0]) || '') + '\" />'\n                + '</body>';\n            var tab = window.open();\n            tab.document.write(html);\n        }\n    }\n};\n\nregister$2(\n    'saveAsImage', SaveAsImage\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar magicTypeLang = lang.toolbox.magicType;\n\nfunction MagicType(model) {\n    this.model = model;\n}\n\nMagicType.defaultOption = {\n    show: true,\n    type: [],\n    // Icon group\n    icon: {\n        /* eslint-disable */\n        line: 'M4.1,28.9h7.1l9.3-22l7.4,38l9.7-19.7l3,12.8h14.9M4.1,58h51.4',\n        bar: 'M6.7,22.9h10V48h-10V22.9zM24.9,13h10v35h-10V13zM43.2,2h10v46h-10V2zM3.1,58h53.7',\n        stack: 'M8.2,38.4l-8.4,4.1l30.6,15.3L60,42.5l-8.1-4.1l-21.5,11L8.2,38.4z M51.9,30l-8.1,4.2l-13.4,6.9l-13.9-6.9L8.2,30l-8.4,4.2l8.4,4.2l22.2,11l21.5-11l8.1-4.2L51.9,30z M51.9,21.7l-8.1,4.2L35.7,30l-5.3,2.8L24.9,30l-8.4-4.1l-8.3-4.2l-8.4,4.2L8.2,30l8.3,4.2l13.9,6.9l13.4-6.9l8.1-4.2l8.1-4.1L51.9,21.7zM30.4,2.2L-0.2,17.5l8.4,4.1l8.3,4.2l8.4,4.2l5.5,2.7l5.3-2.7l8.1-4.2l8.1-4.2l8.1-4.1L30.4,2.2z', // jshint ignore:line\n        tiled: 'M2.3,2.2h22.8V25H2.3V2.2z M35,2.2h22.8V25H35V2.2zM2.3,35h22.8v22.8H2.3V35z M35,35h22.8v22.8H35V35z'\n        /* eslint-enable */\n    },\n    // `line`, `bar`, `stack`, `tiled`\n    title: clone(magicTypeLang.title),\n    option: {},\n    seriesIndex: {}\n};\n\nvar proto$3 = MagicType.prototype;\n\nproto$3.getIcons = function () {\n    var model = this.model;\n    var availableIcons = model.get('icon');\n    var icons = {};\n    each$1(model.get('type'), function (type) {\n        if (availableIcons[type]) {\n            icons[type] = availableIcons[type];\n        }\n    });\n    return icons;\n};\n\nvar seriesOptGenreator = {\n    'line': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                type: 'line',\n                // Preserve data related option\n                data: seriesModel.get('data'),\n                stack: seriesModel.get('stack'),\n                markPoint: seriesModel.get('markPoint'),\n                markLine: seriesModel.get('markLine')\n            }, model.get('option.line') || {}, true);\n        }\n    },\n    'bar': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line') {\n            return merge({\n                id: seriesId,\n                type: 'bar',\n                // Preserve data related option\n                data: seriesModel.get('data'),\n                stack: seriesModel.get('stack'),\n                markPoint: seriesModel.get('markPoint'),\n                markLine: seriesModel.get('markLine')\n            }, model.get('option.bar') || {}, true);\n        }\n    },\n    'stack': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line' || seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                stack: '__ec_magicType_stack__'\n            }, model.get('option.stack') || {}, true);\n        }\n    },\n    'tiled': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line' || seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                stack: ''\n            }, model.get('option.tiled') || {}, true);\n        }\n    }\n};\n\nvar radioTypes = [\n    ['line', 'bar'],\n    ['stack', 'tiled']\n];\n\nproto$3.onclick = function (ecModel, api, type) {\n    var model = this.model;\n    var seriesIndex = model.get('seriesIndex.' + type);\n    // Not supported magicType\n    if (!seriesOptGenreator[type]) {\n        return;\n    }\n    var newOption = {\n        series: []\n    };\n    var generateNewSeriesTypes = function (seriesModel) {\n        var seriesType = seriesModel.subType;\n        var seriesId = seriesModel.id;\n        var newSeriesOpt = seriesOptGenreator[type](\n            seriesType, seriesId, seriesModel, model\n        );\n        if (newSeriesOpt) {\n            // PENDING If merge original option?\n            defaults(newSeriesOpt, seriesModel.option);\n            newOption.series.push(newSeriesOpt);\n        }\n        // Modify boundaryGap\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys && coordSys.type === 'cartesian2d' && (type === 'line' || type === 'bar')) {\n            var categoryAxis = coordSys.getAxesByScale('ordinal')[0];\n            if (categoryAxis) {\n                var axisDim = categoryAxis.dim;\n                var axisType = axisDim + 'Axis';\n                var axisModel = ecModel.queryComponents({\n                    mainType: axisType,\n                    index: seriesModel.get(name + 'Index'),\n                    id: seriesModel.get(name + 'Id')\n                })[0];\n                var axisIndex = axisModel.componentIndex;\n\n                newOption[axisType] = newOption[axisType] || [];\n                for (var i = 0; i <= axisIndex; i++) {\n                    newOption[axisType][axisIndex] = newOption[axisType][axisIndex] || {};\n                }\n                newOption[axisType][axisIndex].boundaryGap = type === 'bar';\n            }\n        }\n    };\n\n    each$1(radioTypes, function (radio) {\n        if (indexOf(radio, type) >= 0) {\n            each$1(radio, function (item) {\n                model.setIconStatus(item, 'normal');\n            });\n        }\n    });\n\n    model.setIconStatus(type, 'emphasis');\n\n    ecModel.eachComponent(\n        {\n            mainType: 'series',\n            query: seriesIndex == null ? null : {\n                seriesIndex: seriesIndex\n            }\n        }, generateNewSeriesTypes\n    );\n    api.dispatchAction({\n        type: 'changeMagicType',\n        currentType: type,\n        newOption: newOption\n    });\n};\n\nregisterAction({\n    type: 'changeMagicType',\n    event: 'magicTypeChanged',\n    update: 'prepareAndUpdate'\n}, function (payload, ecModel) {\n    ecModel.mergeOption(payload.newOption);\n});\n\nregister$2('magicType', MagicType);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar dataViewLang = lang.toolbox.dataView;\n\nvar BLOCK_SPLITER = new Array(60).join('-');\nvar ITEM_SPLITER = '\\t';\n/**\n * Group series into two types\n *  1. on category axis, like line, bar\n *  2. others, like scatter, pie\n * @param {module:echarts/model/Global} ecModel\n * @return {Object}\n * @inner\n */\nfunction groupSeries(ecModel) {\n    var seriesGroupByCategoryAxis = {};\n    var otherSeries = [];\n    var meta = [];\n    ecModel.eachRawSeries(function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n\n        if (coordSys && (coordSys.type === 'cartesian2d' || coordSys.type === 'polar')) {\n            var baseAxis = coordSys.getBaseAxis();\n            if (baseAxis.type === 'category') {\n                var key = baseAxis.dim + '_' + baseAxis.index;\n                if (!seriesGroupByCategoryAxis[key]) {\n                    seriesGroupByCategoryAxis[key] = {\n                        categoryAxis: baseAxis,\n                        valueAxis: coordSys.getOtherAxis(baseAxis),\n                        series: []\n                    };\n                    meta.push({\n                        axisDim: baseAxis.dim,\n                        axisIndex: baseAxis.index\n                    });\n                }\n                seriesGroupByCategoryAxis[key].series.push(seriesModel);\n            }\n            else {\n                otherSeries.push(seriesModel);\n            }\n        }\n        else {\n            otherSeries.push(seriesModel);\n        }\n    });\n\n    return {\n        seriesGroupByCategoryAxis: seriesGroupByCategoryAxis,\n        other: otherSeries,\n        meta: meta\n    };\n}\n\n/**\n * Assemble content of series on cateogory axis\n * @param {Array.<module:echarts/model/Series>} series\n * @return {string}\n * @inner\n */\nfunction assembleSeriesWithCategoryAxis(series) {\n    var tables = [];\n    each$1(series, function (group, key) {\n        var categoryAxis = group.categoryAxis;\n        var valueAxis = group.valueAxis;\n        var valueAxisDim = valueAxis.dim;\n\n        var headers = [' '].concat(map(group.series, function (series) {\n            return series.name;\n        }));\n        var columns = [categoryAxis.model.getCategories()];\n        each$1(group.series, function (series) {\n            columns.push(series.getRawData().mapArray(valueAxisDim, function (val) {\n                return val;\n            }));\n        });\n        // Assemble table content\n        var lines = [headers.join(ITEM_SPLITER)];\n        for (var i = 0; i < columns[0].length; i++) {\n            var items = [];\n            for (var j = 0; j < columns.length; j++) {\n                items.push(columns[j][i]);\n            }\n            lines.push(items.join(ITEM_SPLITER));\n        }\n        tables.push(lines.join('\\n'));\n    });\n    return tables.join('\\n\\n' + BLOCK_SPLITER + '\\n\\n');\n}\n\n/**\n * Assemble content of other series\n * @param {Array.<module:echarts/model/Series>} series\n * @return {string}\n * @inner\n */\nfunction assembleOtherSeries(series) {\n    return map(series, function (series) {\n        var data = series.getRawData();\n        var lines = [series.name];\n        var vals = [];\n        data.each(data.dimensions, function () {\n            var argLen = arguments.length;\n            var dataIndex = arguments[argLen - 1];\n            var name = data.getName(dataIndex);\n            for (var i = 0; i < argLen - 1; i++) {\n                vals[i] = arguments[i];\n            }\n            lines.push((name ? (name + ITEM_SPLITER) : '') + vals.join(ITEM_SPLITER));\n        });\n        return lines.join('\\n');\n    }).join('\\n\\n' + BLOCK_SPLITER + '\\n\\n');\n}\n\n/**\n * @param {module:echarts/model/Global}\n * @return {Object}\n * @inner\n */\nfunction getContentFromModel(ecModel) {\n\n    var result = groupSeries(ecModel);\n\n    return {\n        value: filter([\n                assembleSeriesWithCategoryAxis(result.seriesGroupByCategoryAxis),\n                assembleOtherSeries(result.other)\n            ], function (str) {\n                return str.replace(/[\\n\\t\\s]/g, '');\n            }).join('\\n\\n' + BLOCK_SPLITER + '\\n\\n'),\n\n        meta: result.meta\n    };\n}\n\n\nfunction trim$1(str) {\n    return str.replace(/^\\s\\s*/, '').replace(/\\s\\s*$/, '');\n}\n/**\n * If a block is tsv format\n */\nfunction isTSVFormat(block) {\n    // Simple method to find out if a block is tsv format\n    var firstLine = block.slice(0, block.indexOf('\\n'));\n    if (firstLine.indexOf(ITEM_SPLITER) >= 0) {\n        return true;\n    }\n}\n\nvar itemSplitRegex = new RegExp('[' + ITEM_SPLITER + ']+', 'g');\n/**\n * @param {string} tsv\n * @return {Object}\n */\nfunction parseTSVContents(tsv) {\n    var tsvLines = tsv.split(/\\n+/g);\n    var headers = trim$1(tsvLines.shift()).split(itemSplitRegex);\n\n    var categories = [];\n    var series = map(headers, function (header) {\n        return {\n            name: header,\n            data: []\n        };\n    });\n    for (var i = 0; i < tsvLines.length; i++) {\n        var items = trim$1(tsvLines[i]).split(itemSplitRegex);\n        categories.push(items.shift());\n        for (var j = 0; j < items.length; j++) {\n            series[j] && (series[j].data[i] = items[j]);\n        }\n    }\n    return {\n        series: series,\n        categories: categories\n    };\n}\n\n/**\n * @param {string} str\n * @return {Array.<Object>}\n * @inner\n */\nfunction parseListContents(str) {\n    var lines = str.split(/\\n+/g);\n    var seriesName = trim$1(lines.shift());\n\n    var data = [];\n    for (var i = 0; i < lines.length; i++) {\n        var items = trim$1(lines[i]).split(itemSplitRegex);\n        var name = '';\n        var value;\n        var hasName = false;\n        if (isNaN(items[0])) { // First item is name\n            hasName = true;\n            name = items[0];\n            items = items.slice(1);\n            data[i] = {\n                name: name,\n                value: []\n            };\n            value = data[i].value;\n        }\n        else {\n            value = data[i] = [];\n        }\n        for (var j = 0; j < items.length; j++) {\n            value.push(+items[j]);\n        }\n        if (value.length === 1) {\n            hasName ? (data[i].value = value[0]) : (data[i] = value[0]);\n        }\n    }\n\n    return {\n        name: seriesName,\n        data: data\n    };\n}\n\n/**\n * @param {string} str\n * @param {Array.<Object>} blockMetaList\n * @return {Object}\n * @inner\n */\nfunction parseContents(str, blockMetaList) {\n    var blocks = str.split(new RegExp('\\n*' + BLOCK_SPLITER + '\\n*', 'g'));\n    var newOption = {\n        series: []\n    };\n    each$1(blocks, function (block, idx) {\n        if (isTSVFormat(block)) {\n            var result = parseTSVContents(block);\n            var blockMeta = blockMetaList[idx];\n            var axisKey = blockMeta.axisDim + 'Axis';\n\n            if (blockMeta) {\n                newOption[axisKey] = newOption[axisKey] || [];\n                newOption[axisKey][blockMeta.axisIndex] = {\n                    data: result.categories\n                };\n                newOption.series = newOption.series.concat(result.series);\n            }\n        }\n        else {\n            var result = parseListContents(block);\n            newOption.series.push(result);\n        }\n    });\n    return newOption;\n}\n\n/**\n * @alias {module:echarts/component/toolbox/feature/DataView}\n * @constructor\n * @param {module:echarts/model/Model} model\n */\nfunction DataView(model) {\n\n    this._dom = null;\n\n    this.model = model;\n}\n\nDataView.defaultOption = {\n    show: true,\n    readOnly: false,\n    optionToContent: null,\n    contentToOption: null,\n\n    icon: 'M17.5,17.3H33 M17.5,17.3H33 M45.4,29.5h-28 M11.5,2v56H51V14.8L38.4,2H11.5z M38.4,2.2v12.7H51 M45.4,41.7h-28',\n    title: clone(dataViewLang.title),\n    lang: clone(dataViewLang.lang),\n    backgroundColor: '#fff',\n    textColor: '#000',\n    textareaColor: '#fff',\n    textareaBorderColor: '#333',\n    buttonColor: '#c23531',\n    buttonTextColor: '#fff'\n};\n\nDataView.prototype.onclick = function (ecModel, api) {\n    var container = api.getDom();\n    var model = this.model;\n    if (this._dom) {\n        container.removeChild(this._dom);\n    }\n    var root = document.createElement('div');\n    root.style.cssText = 'position:absolute;left:5px;top:5px;bottom:5px;right:5px;';\n    root.style.backgroundColor = model.get('backgroundColor') || '#fff';\n\n    // Create elements\n    var header = document.createElement('h4');\n    var lang$$1 = model.get('lang') || [];\n    header.innerHTML = lang$$1[0] || model.get('title');\n    header.style.cssText = 'margin: 10px 20px;';\n    header.style.color = model.get('textColor');\n\n    var viewMain = document.createElement('div');\n    var textarea = document.createElement('textarea');\n    viewMain.style.cssText = 'display:block;width:100%;overflow:auto;';\n\n    var optionToContent = model.get('optionToContent');\n    var contentToOption = model.get('contentToOption');\n    var result = getContentFromModel(ecModel);\n    if (typeof optionToContent === 'function') {\n        var htmlOrDom = optionToContent(api.getOption());\n        if (typeof htmlOrDom === 'string') {\n            viewMain.innerHTML = htmlOrDom;\n        }\n        else if (isDom(htmlOrDom)) {\n            viewMain.appendChild(htmlOrDom);\n        }\n    }\n    else {\n        // Use default textarea\n        viewMain.appendChild(textarea);\n        textarea.readOnly = model.get('readOnly');\n        textarea.style.cssText = 'width:100%;height:100%;font-family:monospace;font-size:14px;line-height:1.6rem;';\n        textarea.style.color = model.get('textColor');\n        textarea.style.borderColor = model.get('textareaBorderColor');\n        textarea.style.backgroundColor = model.get('textareaColor');\n        textarea.value = result.value;\n    }\n\n    var blockMetaList = result.meta;\n\n    var buttonContainer = document.createElement('div');\n    buttonContainer.style.cssText = 'position:absolute;bottom:0;left:0;right:0;';\n\n    var buttonStyle = 'float:right;margin-right:20px;border:none;'\n        + 'cursor:pointer;padding:2px 5px;font-size:12px;border-radius:3px';\n    var closeButton = document.createElement('div');\n    var refreshButton = document.createElement('div');\n\n    buttonStyle += ';background-color:' + model.get('buttonColor');\n    buttonStyle += ';color:' + model.get('buttonTextColor');\n\n    var self = this;\n\n    function close() {\n        container.removeChild(root);\n        self._dom = null;\n    }\n    addEventListener(closeButton, 'click', close);\n\n    addEventListener(refreshButton, 'click', function () {\n        var newOption;\n        try {\n            if (typeof contentToOption === 'function') {\n                newOption = contentToOption(viewMain, api.getOption());\n            }\n            else {\n                newOption = parseContents(textarea.value, blockMetaList);\n            }\n        }\n        catch (e) {\n            close();\n            throw new Error('Data view format error ' + e);\n        }\n        if (newOption) {\n            api.dispatchAction({\n                type: 'changeDataView',\n                newOption: newOption\n            });\n        }\n\n        close();\n    });\n\n    closeButton.innerHTML = lang$$1[1];\n    refreshButton.innerHTML = lang$$1[2];\n    refreshButton.style.cssText = buttonStyle;\n    closeButton.style.cssText = buttonStyle;\n\n    !model.get('readOnly') && buttonContainer.appendChild(refreshButton);\n    buttonContainer.appendChild(closeButton);\n\n    // http://stackoverflow.com/questions/6637341/use-tab-to-indent-in-textarea\n    addEventListener(textarea, 'keydown', function (e) {\n        if ((e.keyCode || e.which) === 9) {\n            // get caret position/selection\n            var val = this.value;\n            var start = this.selectionStart;\n            var end = this.selectionEnd;\n\n            // set textarea value to: text before caret + tab + text after caret\n            this.value = val.substring(0, start) + ITEM_SPLITER + val.substring(end);\n\n            // put caret at right position again\n            this.selectionStart = this.selectionEnd = start + 1;\n\n            // prevent the focus lose\n            stop(e);\n        }\n    });\n\n    root.appendChild(header);\n    root.appendChild(viewMain);\n    root.appendChild(buttonContainer);\n\n    viewMain.style.height = (container.clientHeight - 80) + 'px';\n\n    container.appendChild(root);\n    this._dom = root;\n};\n\nDataView.prototype.remove = function (ecModel, api) {\n    this._dom && api.getDom().removeChild(this._dom);\n};\n\nDataView.prototype.dispose = function (ecModel, api) {\n    this.remove(ecModel, api);\n};\n\n/**\n * @inner\n */\nfunction tryMergeDataOption(newData, originalData) {\n    return map(newData, function (newVal, idx) {\n        var original = originalData && originalData[idx];\n        if (isObject$1(original) && !isArray(original)) {\n            if (isObject$1(newVal) && !isArray(newVal)) {\n                newVal = newVal.value;\n            }\n            // Original data has option\n            return defaults({\n                value: newVal\n            }, original);\n        }\n        else {\n            return newVal;\n        }\n    });\n}\n\nregister$2('dataView', DataView);\n\nregisterAction({\n    type: 'changeDataView',\n    event: 'dataViewChanged',\n    update: 'prepareAndUpdate'\n}, function (payload, ecModel) {\n    var newSeriesOptList = [];\n    each$1(payload.newOption.series, function (seriesOpt) {\n        var seriesModel = ecModel.getSeriesByName(seriesOpt.name)[0];\n        if (!seriesModel) {\n            // New created series\n            // Geuss the series type\n            newSeriesOptList.push(extend({\n                // Default is scatter\n                type: 'scatter'\n            }, seriesOpt));\n        }\n        else {\n            var originalData = seriesModel.get('data');\n            newSeriesOptList.push({\n                name: seriesOpt.name,\n                data: tryMergeDataOption(seriesOpt.data, originalData)\n            });\n        }\n    });\n\n    ecModel.mergeOption(defaults({\n        series: newSeriesOptList\n    }, payload.newOption));\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar curry$5 = curry;\nvar each$16 = each$1;\nvar map$2 = map;\nvar mathMin$4 = Math.min;\nvar mathMax$4 = Math.max;\nvar mathPow$2 = Math.pow;\n\nvar COVER_Z = 10000;\nvar UNSELECT_THRESHOLD = 6;\nvar MIN_RESIZE_LINE_WIDTH = 6;\nvar MUTEX_RESOURCE_KEY = 'globalPan';\n\nvar DIRECTION_MAP = {\n    w: [0, 0],\n    e: [0, 1],\n    n: [1, 0],\n    s: [1, 1]\n};\nvar CURSOR_MAP = {\n    w: 'ew',\n    e: 'ew',\n    n: 'ns',\n    s: 'ns',\n    ne: 'nesw',\n    sw: 'nesw',\n    nw: 'nwse',\n    se: 'nwse'\n};\nvar DEFAULT_BRUSH_OPT = {\n    brushStyle: {\n        lineWidth: 2,\n        stroke: 'rgba(0,0,0,0.3)',\n        fill: 'rgba(0,0,0,0.1)'\n    },\n    transformable: true,\n    brushMode: 'single',\n    removeOnClick: false\n};\n\nvar baseUID = 0;\n\n/**\n * @alias module:echarts/component/helper/BrushController\n * @constructor\n * @mixin {module:zrender/mixin/Eventful}\n * @event module:echarts/component/helper/BrushController#brush\n *        params:\n *            areas: Array.<Array>, coord relates to container group,\n *                                    If no container specified, to global.\n *            opt {\n *                isEnd: boolean,\n *                removeOnClick: boolean\n *            }\n *\n * @param {module:zrender/zrender~ZRender} zr\n */\nfunction BrushController(zr) {\n\n    if (__DEV__) {\n        assert$1(zr);\n    }\n\n    Eventful.call(this);\n\n    /**\n     * @type {module:zrender/zrender~ZRender}\n     * @private\n     */\n    this._zr = zr;\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * Only for drawing (after enabledBrush).\n     *     'line', 'rect', 'polygon' or false\n     *     If passing false/null/undefined, disable brush.\n     *     If passing 'auto', determined by panel.defaultBrushType\n     * @private\n     * @type {string}\n     */\n    this._brushType;\n\n    /**\n     * Only for drawing (after enabledBrush).\n     *\n     * @private\n     * @type {Object}\n     */\n    this._brushOption;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._panels;\n\n    /**\n     * @private\n     * @type {Array.<nubmer>}\n     */\n    this._track = [];\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._dragging;\n\n    /**\n     * @private\n     * @type {Array}\n     */\n    this._covers = [];\n\n    /**\n     * @private\n     * @type {moudule:zrender/container/Group}\n     */\n    this._creatingCover;\n\n    /**\n     * `true` means global panel\n     * @private\n     * @type {module:zrender/container/Group|boolean}\n     */\n    this._creatingPanel;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._enableGlobalPan;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    if (__DEV__) {\n        this._mounted;\n    }\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._uid = 'brushController_' + baseUID++;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._handlers = {};\n    each$16(mouseHandlers, function (handler, eventName) {\n        this._handlers[eventName] = bind(handler, this);\n    }, this);\n}\n\nBrushController.prototype = {\n\n    constructor: BrushController,\n\n    /**\n     * If set to null/undefined/false, select disabled.\n     * @param {Object} brushOption\n     * @param {string|boolean} brushOption.brushType 'line', 'rect', 'polygon' or false\n     *                          If passing false/null/undefined, disable brush.\n     *                          If passing 'auto', determined by panel.defaultBrushType.\n     *                              ('auto' can not be used in global panel)\n     * @param {number} [brushOption.brushMode='single'] 'single' or 'multiple'\n     * @param {boolean} [brushOption.transformable=true]\n     * @param {boolean} [brushOption.removeOnClick=false]\n     * @param {Object} [brushOption.brushStyle]\n     * @param {number} [brushOption.brushStyle.width]\n     * @param {number} [brushOption.brushStyle.lineWidth]\n     * @param {string} [brushOption.brushStyle.stroke]\n     * @param {string} [brushOption.brushStyle.fill]\n     * @param {number} [brushOption.z]\n     */\n    enableBrush: function (brushOption) {\n        if (__DEV__) {\n            assert$1(this._mounted);\n        }\n\n        this._brushType && doDisableBrush(this);\n        brushOption.brushType && doEnableBrush(this, brushOption);\n\n        return this;\n    },\n\n    /**\n     * @param {Array.<Object>} panelOpts If not pass, it is global brush.\n     *        Each items: {\n     *            panelId, // mandatory.\n     *            clipPath, // mandatory. function.\n     *            isTargetByCursor, // mandatory. function.\n     *            defaultBrushType, // optional, only used when brushType is 'auto'.\n     *            getLinearBrushOtherExtent, // optional. function.\n     *        }\n     */\n    setPanels: function (panelOpts) {\n        if (panelOpts && panelOpts.length) {\n            var panels = this._panels = {};\n            each$1(panelOpts, function (panelOpts) {\n                panels[panelOpts.panelId] = clone(panelOpts);\n            });\n        }\n        else {\n            this._panels = null;\n        }\n        return this;\n    },\n\n    /**\n     * @param {Object} [opt]\n     * @return {boolean} [opt.enableGlobalPan=false]\n     */\n    mount: function (opt) {\n        opt = opt || {};\n\n        if (__DEV__) {\n            this._mounted = true; // should be at first.\n        }\n\n        this._enableGlobalPan = opt.enableGlobalPan;\n\n        var thisGroup = this.group;\n        this._zr.add(thisGroup);\n\n        thisGroup.attr({\n            position: opt.position || [0, 0],\n            rotation: opt.rotation || 0,\n            scale: opt.scale || [1, 1]\n        });\n        this._transform = thisGroup.getLocalTransform();\n\n        return this;\n    },\n\n    eachCover: function (cb, context) {\n        each$16(this._covers, cb, context);\n    },\n\n    /**\n     * Update covers.\n     * @param {Array.<Object>} brushOptionList Like:\n     *        [\n     *            {id: 'xx', brushType: 'line', range: [23, 44], brushStyle, transformable},\n     *            {id: 'yy', brushType: 'rect', range: [[23, 44], [23, 54]]},\n     *            ...\n     *        ]\n     *        `brushType` is required in each cover info. (can not be 'auto')\n     *        `id` is not mandatory.\n     *        `brushStyle`, `transformable` is not mandatory, use DEFAULT_BRUSH_OPT by default.\n     *        If brushOptionList is null/undefined, all covers removed.\n     */\n    updateCovers: function (brushOptionList) {\n        if (__DEV__) {\n            assert$1(this._mounted);\n        }\n\n        brushOptionList = map(brushOptionList, function (brushOption) {\n            return merge(clone(DEFAULT_BRUSH_OPT), brushOption, true);\n        });\n\n        var tmpIdPrefix = '\\0-brush-index-';\n        var oldCovers = this._covers;\n        var newCovers = this._covers = [];\n        var controller = this;\n        var creatingCover = this._creatingCover;\n\n        (new DataDiffer(oldCovers, brushOptionList, oldGetKey, getKey))\n            .add(addOrUpdate)\n            .update(addOrUpdate)\n            .remove(remove)\n            .execute();\n\n        return this;\n\n        function getKey(brushOption, index) {\n            return (brushOption.id != null ? brushOption.id : tmpIdPrefix + index)\n                + '-' + brushOption.brushType;\n        }\n\n        function oldGetKey(cover, index) {\n            return getKey(cover.__brushOption, index);\n        }\n\n        function addOrUpdate(newIndex, oldIndex) {\n            var newBrushOption = brushOptionList[newIndex];\n            // Consider setOption in event listener of brushSelect,\n            // where updating cover when creating should be forbiden.\n            if (oldIndex != null && oldCovers[oldIndex] === creatingCover) {\n                newCovers[newIndex] = oldCovers[oldIndex];\n            }\n            else {\n                var cover = newCovers[newIndex] = oldIndex != null\n                    ? (\n                        oldCovers[oldIndex].__brushOption = newBrushOption,\n                        oldCovers[oldIndex]\n                    )\n                    : endCreating(controller, createCover(controller, newBrushOption));\n                updateCoverAfterCreation(controller, cover);\n            }\n        }\n\n        function remove(oldIndex) {\n            if (oldCovers[oldIndex] !== creatingCover) {\n                controller.group.remove(oldCovers[oldIndex]);\n            }\n        }\n    },\n\n    unmount: function () {\n        if (__DEV__) {\n            if (!this._mounted) {\n                return;\n            }\n        }\n\n        this.enableBrush(false);\n\n        // container may 'removeAll' outside.\n        clearCovers(this);\n        this._zr.remove(this.group);\n\n        if (__DEV__) {\n            this._mounted = false; // should be at last.\n        }\n\n        return this;\n    },\n\n    dispose: function () {\n        this.unmount();\n        this.off();\n    }\n};\n\nmixin(BrushController, Eventful);\n\nfunction doEnableBrush(controller, brushOption) {\n    var zr = controller._zr;\n\n    // Consider roam, which takes globalPan too.\n    if (!controller._enableGlobalPan) {\n        take(zr, MUTEX_RESOURCE_KEY, controller._uid);\n    }\n\n    each$16(controller._handlers, function (handler, eventName) {\n        zr.on(eventName, handler);\n    });\n\n    controller._brushType = brushOption.brushType;\n    controller._brushOption = merge(clone(DEFAULT_BRUSH_OPT), brushOption, true);\n}\n\nfunction doDisableBrush(controller) {\n    var zr = controller._zr;\n\n    release(zr, MUTEX_RESOURCE_KEY, controller._uid);\n\n    each$16(controller._handlers, function (handler, eventName) {\n        zr.off(eventName, handler);\n    });\n\n    controller._brushType = controller._brushOption = null;\n}\n\nfunction createCover(controller, brushOption) {\n    var cover = coverRenderers[brushOption.brushType].createCover(controller, brushOption);\n    cover.__brushOption = brushOption;\n    updateZ$1(cover, brushOption);\n    controller.group.add(cover);\n    return cover;\n}\n\nfunction endCreating(controller, creatingCover) {\n    var coverRenderer = getCoverRenderer(creatingCover);\n    if (coverRenderer.endCreating) {\n        coverRenderer.endCreating(controller, creatingCover);\n        updateZ$1(creatingCover, creatingCover.__brushOption);\n    }\n    return creatingCover;\n}\n\nfunction updateCoverShape(controller, cover) {\n    var brushOption = cover.__brushOption;\n    getCoverRenderer(cover).updateCoverShape(\n        controller, cover, brushOption.range, brushOption\n    );\n}\n\nfunction updateZ$1(cover, brushOption) {\n    var z = brushOption.z;\n    z == null && (z = COVER_Z);\n    cover.traverse(function (el) {\n        el.z = z;\n        el.z2 = z; // Consider in given container.\n    });\n}\n\nfunction updateCoverAfterCreation(controller, cover) {\n    getCoverRenderer(cover).updateCommon(controller, cover);\n    updateCoverShape(controller, cover);\n}\n\nfunction getCoverRenderer(cover) {\n    return coverRenderers[cover.__brushOption.brushType];\n}\n\n// return target panel or `true` (means global panel)\nfunction getPanelByPoint(controller, e, localCursorPoint) {\n    var panels = controller._panels;\n    if (!panels) {\n        return true; // Global panel\n    }\n    var panel;\n    var transform = controller._transform;\n    each$16(panels, function (pn) {\n        pn.isTargetByCursor(e, localCursorPoint, transform) && (panel = pn);\n    });\n    return panel;\n}\n\n// Return a panel or true\nfunction getPanelByCover(controller, cover) {\n    var panels = controller._panels;\n    if (!panels) {\n        return true; // Global panel\n    }\n    var panelId = cover.__brushOption.panelId;\n    // User may give cover without coord sys info,\n    // which is then treated as global panel.\n    return panelId != null ? panels[panelId] : true;\n}\n\nfunction clearCovers(controller) {\n    var covers = controller._covers;\n    var originalLength = covers.length;\n    each$16(covers, function (cover) {\n        controller.group.remove(cover);\n    }, controller);\n    covers.length = 0;\n\n    return !!originalLength;\n}\n\nfunction trigger$1(controller, opt) {\n    var areas = map$2(controller._covers, function (cover) {\n        var brushOption = cover.__brushOption;\n        var range = clone(brushOption.range);\n        return {\n            brushType: brushOption.brushType,\n            panelId: brushOption.panelId,\n            range: range\n        };\n    });\n\n    controller.trigger('brush', areas, {\n        isEnd: !!opt.isEnd,\n        removeOnClick: !!opt.removeOnClick\n    });\n}\n\nfunction shouldShowCover(controller) {\n    var track = controller._track;\n\n    if (!track.length) {\n        return false;\n    }\n\n    var p2 = track[track.length - 1];\n    var p1 = track[0];\n    var dx = p2[0] - p1[0];\n    var dy = p2[1] - p1[1];\n    var dist = mathPow$2(dx * dx + dy * dy, 0.5);\n\n    return dist > UNSELECT_THRESHOLD;\n}\n\nfunction getTrackEnds(track) {\n    var tail = track.length - 1;\n    tail < 0 && (tail = 0);\n    return [track[0], track[tail]];\n}\n\nfunction createBaseRectCover(doDrift, controller, brushOption, edgeNames) {\n    var cover = new Group();\n\n    cover.add(new Rect({\n        name: 'main',\n        style: makeStyle(brushOption),\n        silent: true,\n        draggable: true,\n        cursor: 'move',\n        drift: curry$5(doDrift, controller, cover, 'nswe'),\n        ondragend: curry$5(trigger$1, controller, {isEnd: true})\n    }));\n\n    each$16(\n        edgeNames,\n        function (name) {\n            cover.add(new Rect({\n                name: name,\n                style: {opacity: 0},\n                draggable: true,\n                silent: true,\n                invisible: true,\n                drift: curry$5(doDrift, controller, cover, name),\n                ondragend: curry$5(trigger$1, controller, {isEnd: true})\n            }));\n        }\n    );\n\n    return cover;\n}\n\nfunction updateBaseRect(controller, cover, localRange, brushOption) {\n    var lineWidth = brushOption.brushStyle.lineWidth || 0;\n    var handleSize = mathMax$4(lineWidth, MIN_RESIZE_LINE_WIDTH);\n    var x = localRange[0][0];\n    var y = localRange[1][0];\n    var xa = x - lineWidth / 2;\n    var ya = y - lineWidth / 2;\n    var x2 = localRange[0][1];\n    var y2 = localRange[1][1];\n    var x2a = x2 - handleSize + lineWidth / 2;\n    var y2a = y2 - handleSize + lineWidth / 2;\n    var width = x2 - x;\n    var height = y2 - y;\n    var widtha = width + lineWidth;\n    var heighta = height + lineWidth;\n\n    updateRectShape(controller, cover, 'main', x, y, width, height);\n\n    if (brushOption.transformable) {\n        updateRectShape(controller, cover, 'w', xa, ya, handleSize, heighta);\n        updateRectShape(controller, cover, 'e', x2a, ya, handleSize, heighta);\n        updateRectShape(controller, cover, 'n', xa, ya, widtha, handleSize);\n        updateRectShape(controller, cover, 's', xa, y2a, widtha, handleSize);\n\n        updateRectShape(controller, cover, 'nw', xa, ya, handleSize, handleSize);\n        updateRectShape(controller, cover, 'ne', x2a, ya, handleSize, handleSize);\n        updateRectShape(controller, cover, 'sw', xa, y2a, handleSize, handleSize);\n        updateRectShape(controller, cover, 'se', x2a, y2a, handleSize, handleSize);\n    }\n}\n\nfunction updateCommon(controller, cover) {\n    var brushOption = cover.__brushOption;\n    var transformable = brushOption.transformable;\n\n    var mainEl = cover.childAt(0);\n    mainEl.useStyle(makeStyle(brushOption));\n    mainEl.attr({\n        silent: !transformable,\n        cursor: transformable ? 'move' : 'default'\n    });\n\n    each$16(\n        ['w', 'e', 'n', 's', 'se', 'sw', 'ne', 'nw'],\n        function (name) {\n            var el = cover.childOfName(name);\n            var globalDir = getGlobalDirection(controller, name);\n\n            el && el.attr({\n                silent: !transformable,\n                invisible: !transformable,\n                cursor: transformable ? CURSOR_MAP[globalDir] + '-resize' : null\n            });\n        }\n    );\n}\n\nfunction updateRectShape(controller, cover, name, x, y, w, h) {\n    var el = cover.childOfName(name);\n    el && el.setShape(pointsToRect(\n        clipByPanel(controller, cover, [[x, y], [x + w, y + h]])\n    ));\n}\n\nfunction makeStyle(brushOption) {\n    return defaults({strokeNoScale: true}, brushOption.brushStyle);\n}\n\nfunction formatRectRange(x, y, x2, y2) {\n    var min = [mathMin$4(x, x2), mathMin$4(y, y2)];\n    var max = [mathMax$4(x, x2), mathMax$4(y, y2)];\n\n    return [\n        [min[0], max[0]], // x range\n        [min[1], max[1]] // y range\n    ];\n}\n\nfunction getTransform$1(controller) {\n    return getTransform(controller.group);\n}\n\nfunction getGlobalDirection(controller, localDirection) {\n    if (localDirection.length > 1) {\n        localDirection = localDirection.split('');\n        var globalDir = [\n            getGlobalDirection(controller, localDirection[0]),\n            getGlobalDirection(controller, localDirection[1])\n        ];\n        (globalDir[0] === 'e' || globalDir[0] === 'w') && globalDir.reverse();\n        return globalDir.join('');\n    }\n    else {\n        var map$$1 = {w: 'left', e: 'right', n: 'top', s: 'bottom'};\n        var inverseMap = {left: 'w', right: 'e', top: 'n', bottom: 's'};\n        var globalDir = transformDirection(\n            map$$1[localDirection], getTransform$1(controller)\n        );\n        return inverseMap[globalDir];\n    }\n}\n\nfunction driftRect(toRectRange, fromRectRange, controller, cover, name, dx, dy, e) {\n    var brushOption = cover.__brushOption;\n    var rectRange = toRectRange(brushOption.range);\n    var localDelta = toLocalDelta(controller, dx, dy);\n\n    each$16(name.split(''), function (namePart) {\n        var ind = DIRECTION_MAP[namePart];\n        rectRange[ind[0]][ind[1]] += localDelta[ind[0]];\n    });\n\n    brushOption.range = fromRectRange(formatRectRange(\n        rectRange[0][0], rectRange[1][0], rectRange[0][1], rectRange[1][1]\n    ));\n\n    updateCoverAfterCreation(controller, cover);\n    trigger$1(controller, {isEnd: false});\n}\n\nfunction driftPolygon(controller, cover, dx, dy, e) {\n    var range = cover.__brushOption.range;\n    var localDelta = toLocalDelta(controller, dx, dy);\n\n    each$16(range, function (point) {\n        point[0] += localDelta[0];\n        point[1] += localDelta[1];\n    });\n\n    updateCoverAfterCreation(controller, cover);\n    trigger$1(controller, {isEnd: false});\n}\n\nfunction toLocalDelta(controller, dx, dy) {\n    var thisGroup = controller.group;\n    var localD = thisGroup.transformCoordToLocal(dx, dy);\n    var localZero = thisGroup.transformCoordToLocal(0, 0);\n\n    return [localD[0] - localZero[0], localD[1] - localZero[1]];\n}\n\nfunction clipByPanel(controller, cover, data) {\n    var panel = getPanelByCover(controller, cover);\n\n    return (panel && panel !== true)\n        ? panel.clipPath(data, controller._transform)\n        : clone(data);\n}\n\nfunction pointsToRect(points) {\n    var xmin = mathMin$4(points[0][0], points[1][0]);\n    var ymin = mathMin$4(points[0][1], points[1][1]);\n    var xmax = mathMax$4(points[0][0], points[1][0]);\n    var ymax = mathMax$4(points[0][1], points[1][1]);\n\n    return {\n        x: xmin,\n        y: ymin,\n        width: xmax - xmin,\n        height: ymax - ymin\n    };\n}\n\nfunction resetCursor(controller, e, localCursorPoint) {\n    // Check active\n    if (!controller._brushType) {\n        return;\n    }\n\n    var zr = controller._zr;\n    var covers = controller._covers;\n    var currPanel = getPanelByPoint(controller, e, localCursorPoint);\n\n    // Check whether in covers.\n    if (!controller._dragging) {\n        for (var i = 0; i < covers.length; i++) {\n            var brushOption = covers[i].__brushOption;\n            if (currPanel\n                && (currPanel === true || brushOption.panelId === currPanel.panelId)\n                && coverRenderers[brushOption.brushType].contain(\n                    covers[i], localCursorPoint[0], localCursorPoint[1]\n                )\n            ) {\n                // Use cursor style set on cover.\n                return;\n            }\n        }\n    }\n\n    currPanel && zr.setCursorStyle('crosshair');\n}\n\nfunction preventDefault(e) {\n    var rawE = e.event;\n    rawE.preventDefault && rawE.preventDefault();\n}\n\nfunction mainShapeContain(cover, x, y) {\n    return cover.childOfName('main').contain(x, y);\n}\n\nfunction updateCoverByMouse(controller, e, localCursorPoint, isEnd) {\n    var creatingCover = controller._creatingCover;\n    var panel = controller._creatingPanel;\n    var thisBrushOption = controller._brushOption;\n    var eventParams;\n\n    controller._track.push(localCursorPoint.slice());\n\n    if (shouldShowCover(controller) || creatingCover) {\n\n        if (panel && !creatingCover) {\n            thisBrushOption.brushMode === 'single' && clearCovers(controller);\n            var brushOption = clone(thisBrushOption);\n            brushOption.brushType = determineBrushType(brushOption.brushType, panel);\n            brushOption.panelId = panel === true ? null : panel.panelId;\n            creatingCover = controller._creatingCover = createCover(controller, brushOption);\n            controller._covers.push(creatingCover);\n        }\n\n        if (creatingCover) {\n            var coverRenderer = coverRenderers[determineBrushType(controller._brushType, panel)];\n            var coverBrushOption = creatingCover.__brushOption;\n\n            coverBrushOption.range = coverRenderer.getCreatingRange(\n                clipByPanel(controller, creatingCover, controller._track)\n            );\n\n            if (isEnd) {\n                endCreating(controller, creatingCover);\n                coverRenderer.updateCommon(controller, creatingCover);\n            }\n\n            updateCoverShape(controller, creatingCover);\n\n            eventParams = {isEnd: isEnd};\n        }\n    }\n    else if (\n        isEnd\n        && thisBrushOption.brushMode === 'single'\n        && thisBrushOption.removeOnClick\n    ) {\n        // Help user to remove covers easily, only by a tiny drag, in 'single' mode.\n        // But a single click do not clear covers, because user may have casual\n        // clicks (for example, click on other component and do not expect covers\n        // disappear).\n        // Only some cover removed, trigger action, but not every click trigger action.\n        if (getPanelByPoint(controller, e, localCursorPoint) && clearCovers(controller)) {\n            eventParams = {isEnd: isEnd, removeOnClick: true};\n        }\n    }\n\n    return eventParams;\n}\n\nfunction determineBrushType(brushType, panel) {\n    if (brushType === 'auto') {\n        if (__DEV__) {\n            assert$1(\n                panel && panel.defaultBrushType,\n                'MUST have defaultBrushType when brushType is \"atuo\"'\n            );\n        }\n        return panel.defaultBrushType;\n    }\n    return brushType;\n}\n\nvar mouseHandlers = {\n\n    mousedown: function (e) {\n        if (this._dragging) {\n            // In case some browser do not support globalOut,\n            // and release mose out side the browser.\n            handleDragEnd.call(this, e);\n        }\n        else if (!e.target || !e.target.draggable) {\n\n            preventDefault(e);\n\n            var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n\n            this._creatingCover = null;\n            var panel = this._creatingPanel = getPanelByPoint(this, e, localCursorPoint);\n\n            if (panel) {\n                this._dragging = true;\n                this._track = [localCursorPoint.slice()];\n            }\n        }\n    },\n\n    mousemove: function (e) {\n        var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n\n        resetCursor(this, e, localCursorPoint);\n\n        if (this._dragging) {\n\n            preventDefault(e);\n\n            var eventParams = updateCoverByMouse(this, e, localCursorPoint, false);\n\n            eventParams && trigger$1(this, eventParams);\n        }\n    },\n\n    mouseup: handleDragEnd //,\n\n    // FIXME\n    // in tooltip, globalout should not be triggered.\n    // globalout: handleDragEnd\n};\n\nfunction handleDragEnd(e) {\n    if (this._dragging) {\n\n        preventDefault(e);\n\n        var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n        var eventParams = updateCoverByMouse(this, e, localCursorPoint, true);\n\n        this._dragging = false;\n        this._track = [];\n        this._creatingCover = null;\n\n        // trigger event shoule be at final, after procedure will be nested.\n        eventParams && trigger$1(this, eventParams);\n    }\n}\n\n/**\n * key: brushType\n * @type {Object}\n */\nvar coverRenderers = {\n\n    lineX: getLineRenderer(0),\n\n    lineY: getLineRenderer(1),\n\n    rect: {\n        createCover: function (controller, brushOption) {\n            return createBaseRectCover(\n                curry$5(\n                    driftRect,\n                    function (range) {\n                        return range;\n                    },\n                    function (range) {\n                        return range;\n                    }\n                ),\n                controller,\n                brushOption,\n                ['w', 'e', 'n', 's', 'se', 'sw', 'ne', 'nw']\n            );\n        },\n        getCreatingRange: function (localTrack) {\n            var ends = getTrackEnds(localTrack);\n            return formatRectRange(ends[1][0], ends[1][1], ends[0][0], ends[0][1]);\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            updateBaseRect(controller, cover, localRange, brushOption);\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    },\n\n    polygon: {\n        createCover: function (controller, brushOption) {\n            var cover = new Group();\n\n            // Do not use graphic.Polygon because graphic.Polyline do not close the\n            // border of the shape when drawing, which is a better experience for user.\n            cover.add(new Polyline({\n                name: 'main',\n                style: makeStyle(brushOption),\n                silent: true\n            }));\n\n            return cover;\n        },\n        getCreatingRange: function (localTrack) {\n            return localTrack;\n        },\n        endCreating: function (controller, cover) {\n            cover.remove(cover.childAt(0));\n            // Use graphic.Polygon close the shape.\n            cover.add(new Polygon({\n                name: 'main',\n                draggable: true,\n                drift: curry$5(driftPolygon, controller, cover),\n                ondragend: curry$5(trigger$1, controller, {isEnd: true})\n            }));\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            cover.childAt(0).setShape({\n                points: clipByPanel(controller, cover, localRange)\n            });\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    }\n};\n\nfunction getLineRenderer(xyIndex) {\n    return {\n        createCover: function (controller, brushOption) {\n            return createBaseRectCover(\n                curry$5(\n                    driftRect,\n                    function (range) {\n                        var rectRange = [range, [0, 100]];\n                        xyIndex && rectRange.reverse();\n                        return rectRange;\n                    },\n                    function (rectRange) {\n                        return rectRange[xyIndex];\n                    }\n                ),\n                controller,\n                brushOption,\n                [['w', 'e'], ['n', 's']][xyIndex]\n            );\n        },\n        getCreatingRange: function (localTrack) {\n            var ends = getTrackEnds(localTrack);\n            var min = mathMin$4(ends[0][xyIndex], ends[1][xyIndex]);\n            var max = mathMax$4(ends[0][xyIndex], ends[1][xyIndex]);\n\n            return [min, max];\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            var otherExtent;\n            // If brushWidth not specified, fit the panel.\n            var panel = getPanelByCover(controller, cover);\n            if (panel !== true && panel.getLinearBrushOtherExtent) {\n                otherExtent = panel.getLinearBrushOtherExtent(\n                    xyIndex, controller._transform\n                );\n            }\n            else {\n                var zr = controller._zr;\n                otherExtent = [0, [zr.getWidth(), zr.getHeight()][1 - xyIndex]];\n            }\n            var rectRange = [localRange, otherExtent];\n            xyIndex && rectRange.reverse();\n\n            updateBaseRect(controller, cover, rectRange, brushOption);\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar IRRELEVANT_EXCLUDES = {'axisPointer': 1, 'tooltip': 1, 'brush': 1};\n\n/**\n * Avoid that: mouse click on a elements that is over geo or graph,\n * but roam is triggered.\n */\nfunction onIrrelevantElement(e, api, targetCoordSysModel) {\n    var model = api.getComponentByElement(e.topTarget);\n    // If model is axisModel, it works only if it is injected with coordinateSystem.\n    var coordSys = model && model.coordinateSystem;\n    return model\n        && model !== targetCoordSysModel\n        && !IRRELEVANT_EXCLUDES[model.mainType]\n        && (coordSys && coordSys.model !== targetCoordSysModel);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction makeRectPanelClipPath(rect) {\n    rect = normalizeRect(rect);\n    return function (localPoints, transform) {\n        return clipPointsByRect(localPoints, rect);\n    };\n}\n\nfunction makeLinearBrushOtherExtent(rect, specifiedXYIndex) {\n    rect = normalizeRect(rect);\n    return function (xyIndex) {\n        var idx = specifiedXYIndex != null ? specifiedXYIndex : xyIndex;\n        var brushWidth = idx ? rect.width : rect.height;\n        var base = idx ? rect.x : rect.y;\n        return [base, base + (brushWidth || 0)];\n    };\n}\n\nfunction makeRectIsTargetByCursor(rect, api, targetModel) {\n    rect = normalizeRect(rect);\n    return function (e, localCursorPoint, transform) {\n        return rect.contain(localCursorPoint[0], localCursorPoint[1])\n            && !onIrrelevantElement(e, api, targetModel);\n    };\n}\n\n// Consider width/height is negative.\nfunction normalizeRect(rect) {\n    return BoundingRect.create(rect);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$17 = each$1;\nvar indexOf$2 = indexOf;\nvar curry$6 = curry;\n\nvar COORD_CONVERTS = ['dataToPoint', 'pointToData'];\n\n// FIXME\n// how to genarialize to more coordinate systems.\nvar INCLUDE_FINDER_MAIN_TYPES = [\n    'grid', 'xAxis', 'yAxis', 'geo', 'graph',\n    'polar', 'radiusAxis', 'angleAxis', 'bmap'\n];\n\n/**\n * [option in constructor]:\n * {\n *     Index/Id/Name of geo, xAxis, yAxis, grid: See util/model#parseFinder.\n * }\n *\n *\n * [targetInfo]:\n *\n * There can be multiple axes in a single targetInfo. Consider the case\n * of `grid` component, a targetInfo represents a grid which contains one or more\n * cartesian and one or more axes. And consider the case of parallel system,\n * which has multiple axes in a coordinate system.\n * Can be {\n *     panelId: ...,\n *     coordSys: <a representitive cartesian in grid (first cartesian by default)>,\n *     coordSyses: all cartesians.\n *     gridModel: <grid component>\n *     xAxes: correspond to coordSyses on index\n *     yAxes: correspond to coordSyses on index\n * }\n * or {\n *     panelId: ...,\n *     coordSys: <geo coord sys>\n *     coordSyses: [<geo coord sys>]\n *     geoModel: <geo component>\n * }\n *\n *\n * [panelOpt]:\n *\n * Make from targetInfo. Input to BrushController.\n * {\n *     panelId: ...,\n *     rect: ...\n * }\n *\n *\n * [area]:\n *\n * Generated by BrushController or user input.\n * {\n *     panelId: Used to locate coordInfo directly. If user inpput, no panelId.\n *     brushType: determine how to convert to/from coord('rect' or 'polygon' or 'lineX/Y').\n *     Index/Id/Name of geo, xAxis, yAxis, grid: See util/model#parseFinder.\n *     range: pixel range.\n *     coordRange: representitive coord range (the first one of coordRanges).\n *     coordRanges: <Array> coord ranges, used in multiple cartesian in one grid.\n * }\n */\n\n/**\n * @param {Object} option contains Index/Id/Name of xAxis/yAxis/geo/grid\n *        Each can be {number|Array.<number>}. like: {xAxisIndex: [3, 4]}\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} [opt]\n * @param {Array.<string>} [opt.include] include coordinate system types.\n */\nfunction BrushTargetManager(option, ecModel, opt) {\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    var targetInfoList = this._targetInfoList = [];\n    var info = {};\n    var foundCpts = parseFinder$1(ecModel, option);\n\n    each$17(targetInfoBuilders, function (builder, type) {\n        if (!opt || !opt.include || indexOf$2(opt.include, type) >= 0) {\n            builder(foundCpts, targetInfoList, info);\n        }\n    });\n}\n\nvar proto$5 = BrushTargetManager.prototype;\n\nproto$5.setOutputRanges = function (areas, ecModel) {\n    this.matchOutputRanges(areas, ecModel, function (area, coordRange, coordSys) {\n        (area.coordRanges || (area.coordRanges = [])).push(coordRange);\n        // area.coordRange is the first of area.coordRanges\n        if (!area.coordRange) {\n            area.coordRange = coordRange;\n            // In 'category' axis, coord to pixel is not reversible, so we can not\n            // rebuild range by coordRange accrately, which may bring trouble when\n            // brushing only one item. So we use __rangeOffset to rebuilding range\n            // by coordRange. And this it only used in brush component so it is no\n            // need to be adapted to coordRanges.\n            var result = coordConvert[area.brushType](0, coordSys, coordRange);\n            area.__rangeOffset = {\n                offset: diffProcessor[area.brushType](result.values, area.range, [1, 1]),\n                xyMinMax: result.xyMinMax\n            };\n        }\n    });\n};\n\nproto$5.matchOutputRanges = function (areas, ecModel, cb) {\n    each$17(areas, function (area) {\n        var targetInfo = this.findTargetInfo(area, ecModel);\n\n        if (targetInfo && targetInfo !== true) {\n            each$1(\n                targetInfo.coordSyses,\n                function (coordSys) {\n                    var result = coordConvert[area.brushType](1, coordSys, area.range);\n                    cb(area, result.values, coordSys, ecModel);\n                }\n            );\n        }\n    }, this);\n};\n\nproto$5.setInputRanges = function (areas, ecModel) {\n    each$17(areas, function (area) {\n        var targetInfo = this.findTargetInfo(area, ecModel);\n\n        if (__DEV__) {\n            assert$1(\n                !targetInfo || targetInfo === true || area.coordRange,\n                'coordRange must be specified when coord index specified.'\n            );\n            assert$1(\n                !targetInfo || targetInfo !== true || area.range,\n                'range must be specified in global brush.'\n            );\n        }\n\n        area.range = area.range || [];\n\n        // convert coordRange to global range and set panelId.\n        if (targetInfo && targetInfo !== true) {\n            area.panelId = targetInfo.panelId;\n            // (1) area.range shoule always be calculate from coordRange but does\n            // not keep its original value, for the sake of the dataZoom scenario,\n            // where area.coordRange remains unchanged but area.range may be changed.\n            // (2) Only support converting one coordRange to pixel range in brush\n            // component. So do not consider `coordRanges`.\n            // (3) About __rangeOffset, see comment above.\n            var result = coordConvert[area.brushType](0, targetInfo.coordSys, area.coordRange);\n            var rangeOffset = area.__rangeOffset;\n            area.range = rangeOffset\n                ? diffProcessor[area.brushType](\n                    result.values,\n                    rangeOffset.offset,\n                    getScales(result.xyMinMax, rangeOffset.xyMinMax)\n                )\n                : result.values;\n        }\n    }, this);\n};\n\nproto$5.makePanelOpts = function (api, getDefaultBrushType) {\n    return map(this._targetInfoList, function (targetInfo) {\n        var rect = targetInfo.getPanelRect();\n        return {\n            panelId: targetInfo.panelId,\n            defaultBrushType: getDefaultBrushType && getDefaultBrushType(targetInfo),\n            clipPath: makeRectPanelClipPath(rect),\n            isTargetByCursor: makeRectIsTargetByCursor(\n                rect, api, targetInfo.coordSysModel\n            ),\n            getLinearBrushOtherExtent: makeLinearBrushOtherExtent(rect)\n        };\n    });\n};\n\nproto$5.controlSeries = function (area, seriesModel, ecModel) {\n    // Check whether area is bound in coord, and series do not belong to that coord.\n    // If do not do this check, some brush (like lineX) will controll all axes.\n    var targetInfo = this.findTargetInfo(area, ecModel);\n    return targetInfo === true || (\n        targetInfo && indexOf$2(targetInfo.coordSyses, seriesModel.coordinateSystem) >= 0\n    );\n};\n\n/**\n * If return Object, a coord found.\n * If reutrn true, global found.\n * Otherwise nothing found.\n *\n * @param {Object} area\n * @param {Array} targetInfoList\n * @return {Object|boolean}\n */\nproto$5.findTargetInfo = function (area, ecModel) {\n    var targetInfoList = this._targetInfoList;\n    var foundCpts = parseFinder$1(ecModel, area);\n\n    for (var i = 0; i < targetInfoList.length; i++) {\n        var targetInfo = targetInfoList[i];\n        var areaPanelId = area.panelId;\n        if (areaPanelId) {\n            if (targetInfo.panelId === areaPanelId) {\n                return targetInfo;\n            }\n        }\n        else {\n            for (var i = 0; i < targetInfoMatchers.length; i++) {\n                if (targetInfoMatchers[i](foundCpts, targetInfo)) {\n                    return targetInfo;\n                }\n            }\n        }\n    }\n\n    return true;\n};\n\nfunction formatMinMax(minMax) {\n    minMax[0] > minMax[1] && minMax.reverse();\n    return minMax;\n}\n\nfunction parseFinder$1(ecModel, option) {\n    return parseFinder(\n        ecModel, option, {includeMainTypes: INCLUDE_FINDER_MAIN_TYPES}\n    );\n}\n\nvar targetInfoBuilders = {\n\n    grid: function (foundCpts, targetInfoList) {\n        var xAxisModels = foundCpts.xAxisModels;\n        var yAxisModels = foundCpts.yAxisModels;\n        var gridModels = foundCpts.gridModels;\n        // Remove duplicated.\n        var gridModelMap = createHashMap();\n        var xAxesHas = {};\n        var yAxesHas = {};\n\n        if (!xAxisModels && !yAxisModels && !gridModels) {\n            return;\n        }\n\n        each$17(xAxisModels, function (axisModel) {\n            var gridModel = axisModel.axis.grid.model;\n            gridModelMap.set(gridModel.id, gridModel);\n            xAxesHas[gridModel.id] = true;\n        });\n        each$17(yAxisModels, function (axisModel) {\n            var gridModel = axisModel.axis.grid.model;\n            gridModelMap.set(gridModel.id, gridModel);\n            yAxesHas[gridModel.id] = true;\n        });\n        each$17(gridModels, function (gridModel) {\n            gridModelMap.set(gridModel.id, gridModel);\n            xAxesHas[gridModel.id] = true;\n            yAxesHas[gridModel.id] = true;\n        });\n\n        gridModelMap.each(function (gridModel) {\n            var grid = gridModel.coordinateSystem;\n            var cartesians = [];\n\n            each$17(grid.getCartesians(), function (cartesian, index) {\n                if (indexOf$2(xAxisModels, cartesian.getAxis('x').model) >= 0\n                    || indexOf$2(yAxisModels, cartesian.getAxis('y').model) >= 0\n                ) {\n                    cartesians.push(cartesian);\n                }\n            });\n            targetInfoList.push({\n                panelId: 'grid--' + gridModel.id,\n                gridModel: gridModel,\n                coordSysModel: gridModel,\n                // Use the first one as the representitive coordSys.\n                coordSys: cartesians[0],\n                coordSyses: cartesians,\n                getPanelRect: panelRectBuilder.grid,\n                xAxisDeclared: xAxesHas[gridModel.id],\n                yAxisDeclared: yAxesHas[gridModel.id]\n            });\n        });\n    },\n\n    geo: function (foundCpts, targetInfoList) {\n        each$17(foundCpts.geoModels, function (geoModel) {\n            var coordSys = geoModel.coordinateSystem;\n            targetInfoList.push({\n                panelId: 'geo--' + geoModel.id,\n                geoModel: geoModel,\n                coordSysModel: geoModel,\n                coordSys: coordSys,\n                coordSyses: [coordSys],\n                getPanelRect: panelRectBuilder.geo\n            });\n        });\n    }\n};\n\nvar targetInfoMatchers = [\n\n    // grid\n    function (foundCpts, targetInfo) {\n        var xAxisModel = foundCpts.xAxisModel;\n        var yAxisModel = foundCpts.yAxisModel;\n        var gridModel = foundCpts.gridModel;\n\n        !gridModel && xAxisModel && (gridModel = xAxisModel.axis.grid.model);\n        !gridModel && yAxisModel && (gridModel = yAxisModel.axis.grid.model);\n\n        return gridModel && gridModel === targetInfo.gridModel;\n    },\n\n    // geo\n    function (foundCpts, targetInfo) {\n        var geoModel = foundCpts.geoModel;\n        return geoModel && geoModel === targetInfo.geoModel;\n    }\n];\n\nvar panelRectBuilder = {\n\n    grid: function () {\n        // grid is not Transformable.\n        return this.coordSys.grid.getRect().clone();\n    },\n\n    geo: function () {\n        var coordSys = this.coordSys;\n        var rect = coordSys.getBoundingRect().clone();\n        // geo roam and zoom transform\n        rect.applyTransform(getTransform(coordSys));\n        return rect;\n    }\n};\n\nvar coordConvert = {\n\n    lineX: curry$6(axisConvert, 0),\n\n    lineY: curry$6(axisConvert, 1),\n\n    rect: function (to, coordSys, rangeOrCoordRange) {\n        var xminymin = coordSys[COORD_CONVERTS[to]]([rangeOrCoordRange[0][0], rangeOrCoordRange[1][0]]);\n        var xmaxymax = coordSys[COORD_CONVERTS[to]]([rangeOrCoordRange[0][1], rangeOrCoordRange[1][1]]);\n        var values = [\n            formatMinMax([xminymin[0], xmaxymax[0]]),\n            formatMinMax([xminymin[1], xmaxymax[1]])\n        ];\n        return {values: values, xyMinMax: values};\n    },\n\n    polygon: function (to, coordSys, rangeOrCoordRange) {\n        var xyMinMax = [[Infinity, -Infinity], [Infinity, -Infinity]];\n        var values = map(rangeOrCoordRange, function (item) {\n            var p = coordSys[COORD_CONVERTS[to]](item);\n            xyMinMax[0][0] = Math.min(xyMinMax[0][0], p[0]);\n            xyMinMax[1][0] = Math.min(xyMinMax[1][0], p[1]);\n            xyMinMax[0][1] = Math.max(xyMinMax[0][1], p[0]);\n            xyMinMax[1][1] = Math.max(xyMinMax[1][1], p[1]);\n            return p;\n        });\n        return {values: values, xyMinMax: xyMinMax};\n    }\n};\n\nfunction axisConvert(axisNameIndex, to, coordSys, rangeOrCoordRange) {\n    if (__DEV__) {\n        assert$1(\n            coordSys.type === 'cartesian2d',\n            'lineX/lineY brush is available only in cartesian2d.'\n        );\n    }\n\n    var axis = coordSys.getAxis(['x', 'y'][axisNameIndex]);\n    var values = formatMinMax(map([0, 1], function (i) {\n        return to\n            ? axis.coordToData(axis.toLocalCoord(rangeOrCoordRange[i]))\n            : axis.toGlobalCoord(axis.dataToCoord(rangeOrCoordRange[i]));\n    }));\n    var xyMinMax = [];\n    xyMinMax[axisNameIndex] = values;\n    xyMinMax[1 - axisNameIndex] = [NaN, NaN];\n\n    return {values: values, xyMinMax: xyMinMax};\n}\n\nvar diffProcessor = {\n    lineX: curry$6(axisDiffProcessor, 0),\n\n    lineY: curry$6(axisDiffProcessor, 1),\n\n    rect: function (values, refer, scales) {\n        return [\n            [values[0][0] - scales[0] * refer[0][0], values[0][1] - scales[0] * refer[0][1]],\n            [values[1][0] - scales[1] * refer[1][0], values[1][1] - scales[1] * refer[1][1]]\n        ];\n    },\n\n    polygon: function (values, refer, scales) {\n        return map(values, function (item, idx) {\n            return [item[0] - scales[0] * refer[idx][0], item[1] - scales[1] * refer[idx][1]];\n        });\n    }\n};\n\nfunction axisDiffProcessor(axisNameIndex, values, refer, scales) {\n    return [\n        values[0] - scales[axisNameIndex] * refer[0],\n        values[1] - scales[axisNameIndex] * refer[1]\n    ];\n}\n\n// We have to process scale caused by dataZoom manually,\n// although it might be not accurate.\nfunction getScales(xyMinMaxCurr, xyMinMaxOrigin) {\n    var sizeCurr = getSize(xyMinMaxCurr);\n    var sizeOrigin = getSize(xyMinMaxOrigin);\n    var scales = [sizeCurr[0] / sizeOrigin[0], sizeCurr[1] / sizeOrigin[1]];\n    isNaN(scales[0]) && (scales[0] = 1);\n    isNaN(scales[1]) && (scales[1] = 1);\n    return scales;\n}\n\nfunction getSize(xyMinMax) {\n    return xyMinMax\n        ? [xyMinMax[0][1] - xyMinMax[0][0], xyMinMax[1][1] - xyMinMax[1][0]]\n        : [NaN, NaN];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$18 = each$1;\n\nvar ATTR$2 = '\\0_ec_hist_store';\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} newSnapshot {dataZoomId, batch: [payloadInfo, ...]}\n */\nfunction push(ecModel, newSnapshot) {\n    var store = giveStore$1(ecModel);\n\n    // If previous dataZoom can not be found,\n    // complete an range with current range.\n    each$18(newSnapshot, function (batchItem, dataZoomId) {\n        var i = store.length - 1;\n        for (; i >= 0; i--) {\n            var snapshot = store[i];\n            if (snapshot[dataZoomId]) {\n                break;\n            }\n        }\n        if (i < 0) {\n            // No origin range set, create one by current range.\n            var dataZoomModel = ecModel.queryComponents(\n                {mainType: 'dataZoom', subType: 'select', id: dataZoomId}\n            )[0];\n            if (dataZoomModel) {\n                var percentRange = dataZoomModel.getPercentRange();\n                store[0][dataZoomId] = {\n                    dataZoomId: dataZoomId,\n                    start: percentRange[0],\n                    end: percentRange[1]\n                };\n            }\n        }\n    });\n\n    store.push(newSnapshot);\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @return {Object} snapshot\n */\nfunction pop(ecModel) {\n    var store = giveStore$1(ecModel);\n    var head = store[store.length - 1];\n    store.length > 1 && store.pop();\n\n    // Find top for all dataZoom.\n    var snapshot = {};\n    each$18(head, function (batchItem, dataZoomId) {\n        for (var i = store.length - 1; i >= 0; i--) {\n            var batchItem = store[i][dataZoomId];\n            if (batchItem) {\n                snapshot[dataZoomId] = batchItem;\n                break;\n            }\n        }\n    });\n\n    return snapshot;\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n */\nfunction clear$1(ecModel) {\n    ecModel[ATTR$2] = null;\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @return {number} records. always >= 1.\n */\nfunction count(ecModel) {\n    return giveStore$1(ecModel).length;\n}\n\n/**\n * [{key: dataZoomId, value: {dataZoomId, range}}, ...]\n * History length of each dataZoom may be different.\n * this._history[0] is used to store origin range.\n * @type {Array.<Object>}\n */\nfunction giveStore$1(ecModel) {\n    var store = ecModel[ATTR$2];\n    if (!store) {\n        store = ecModel[ATTR$2] = [{}];\n    }\n    return store;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomModel.extend({\n    type: 'dataZoom.select'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomView.extend({\n    type: 'dataZoom.select'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Use dataZoomSelect\nvar dataZoomLang = lang.toolbox.dataZoom;\nvar each$15 = each$1;\n\n// Spectial component id start with \\0ec\\0, see echarts/model/Global.js~hasInnerId\nvar DATA_ZOOM_ID_BASE = '\\0_ec_\\0toolbox-dataZoom_';\n\nfunction DataZoom(model, ecModel, api) {\n\n    /**\n     * @private\n     * @type {module:echarts/component/helper/BrushController}\n     */\n    (this._brushController = new BrushController(api.getZr()))\n        .on('brush', bind(this._onBrush, this))\n        .mount();\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._isZoomActive;\n}\n\nDataZoom.defaultOption = {\n    show: true,\n    // Icon group\n    icon: {\n        zoom: 'M0,13.5h26.9 M13.5,26.9V0 M32.1,13.5H58V58H13.5 V32.1',\n        back: 'M22,1.4L9.9,13.5l12.3,12.3 M10.3,13.5H54.9v44.6 H10.3v-26'\n    },\n    // `zoom`, `back`\n    title: clone(dataZoomLang.title)\n};\n\nvar proto$4 = DataZoom.prototype;\n\nproto$4.render = function (featureModel, ecModel, api, payload) {\n    this.model = featureModel;\n    this.ecModel = ecModel;\n    this.api = api;\n\n    updateZoomBtnStatus(featureModel, ecModel, this, payload, api);\n    updateBackBtnStatus(featureModel, ecModel);\n};\n\nproto$4.onclick = function (ecModel, api, type) {\n    handlers[type].call(this);\n};\n\nproto$4.remove = function (ecModel, api) {\n    this._brushController.unmount();\n};\n\nproto$4.dispose = function (ecModel, api) {\n    this._brushController.dispose();\n};\n\n/**\n * @private\n */\nvar handlers = {\n\n    zoom: function () {\n        var nextActive = !this._isZoomActive;\n\n        this.api.dispatchAction({\n            type: 'takeGlobalCursor',\n            key: 'dataZoomSelect',\n            dataZoomSelectActive: nextActive\n        });\n    },\n\n    back: function () {\n        this._dispatchZoomAction(pop(this.ecModel));\n    }\n};\n\n/**\n * @private\n */\nproto$4._onBrush = function (areas, opt) {\n    if (!opt.isEnd || !areas.length) {\n        return;\n    }\n    var snapshot = {};\n    var ecModel = this.ecModel;\n\n    this._brushController.updateCovers([]); // remove cover\n\n    var brushTargetManager = new BrushTargetManager(\n        retrieveAxisSetting(this.model.option), ecModel, {include: ['grid']}\n    );\n    brushTargetManager.matchOutputRanges(areas, ecModel, function (area, coordRange, coordSys) {\n        if (coordSys.type !== 'cartesian2d') {\n            return;\n        }\n\n        var brushType = area.brushType;\n        if (brushType === 'rect') {\n            setBatch('x', coordSys, coordRange[0]);\n            setBatch('y', coordSys, coordRange[1]);\n        }\n        else {\n            setBatch(({lineX: 'x', lineY: 'y'})[brushType], coordSys, coordRange);\n        }\n    });\n\n    push(ecModel, snapshot);\n\n    this._dispatchZoomAction(snapshot);\n\n    function setBatch(dimName, coordSys, minMax) {\n        var axis = coordSys.getAxis(dimName);\n        var axisModel = axis.model;\n        var dataZoomModel = findDataZoom(dimName, axisModel, ecModel);\n\n        // Restrict range.\n        var minMaxSpan = dataZoomModel.findRepresentativeAxisProxy(axisModel).getMinMaxSpan();\n        if (minMaxSpan.minValueSpan != null || minMaxSpan.maxValueSpan != null) {\n            minMax = sliderMove(\n                0, minMax.slice(), axis.scale.getExtent(), 0,\n                minMaxSpan.minValueSpan, minMaxSpan.maxValueSpan\n            );\n        }\n\n        dataZoomModel && (snapshot[dataZoomModel.id] = {\n            dataZoomId: dataZoomModel.id,\n            startValue: minMax[0],\n            endValue: minMax[1]\n        });\n    }\n\n    function findDataZoom(dimName, axisModel, ecModel) {\n        var found;\n        ecModel.eachComponent({mainType: 'dataZoom', subType: 'select'}, function (dzModel) {\n            var has = dzModel.getAxisModel(dimName, axisModel.componentIndex);\n            has && (found = dzModel);\n        });\n        return found;\n    }\n};\n\n/**\n * @private\n */\nproto$4._dispatchZoomAction = function (snapshot) {\n    var batch = [];\n\n    // Convert from hash map to array.\n    each$15(snapshot, function (batchItem, dataZoomId) {\n        batch.push(clone(batchItem));\n    });\n\n    batch.length && this.api.dispatchAction({\n        type: 'dataZoom',\n        from: this.uid,\n        batch: batch\n    });\n};\n\nfunction retrieveAxisSetting(option) {\n    var setting = {};\n    // Compatible with previous setting: null => all axis, false => no axis.\n    each$1(['xAxisIndex', 'yAxisIndex'], function (name) {\n        setting[name] = option[name];\n        setting[name] == null && (setting[name] = 'all');\n        (setting[name] === false || setting[name] === 'none') && (setting[name] = []);\n    });\n    return setting;\n}\n\nfunction updateBackBtnStatus(featureModel, ecModel) {\n    featureModel.setIconStatus(\n        'back',\n        count(ecModel) > 1 ? 'emphasis' : 'normal'\n    );\n}\n\nfunction updateZoomBtnStatus(featureModel, ecModel, view, payload, api) {\n    var zoomActive = view._isZoomActive;\n\n    if (payload && payload.type === 'takeGlobalCursor') {\n        zoomActive = payload.key === 'dataZoomSelect'\n            ? payload.dataZoomSelectActive : false;\n    }\n\n    view._isZoomActive = zoomActive;\n\n    featureModel.setIconStatus('zoom', zoomActive ? 'emphasis' : 'normal');\n\n    var brushTargetManager = new BrushTargetManager(\n        retrieveAxisSetting(featureModel.option), ecModel, {include: ['grid']}\n    );\n\n    view._brushController\n        .setPanels(brushTargetManager.makePanelOpts(api, function (targetInfo) {\n            return (targetInfo.xAxisDeclared && !targetInfo.yAxisDeclared)\n                ? 'lineX'\n                : (!targetInfo.xAxisDeclared && targetInfo.yAxisDeclared)\n                ? 'lineY'\n                : 'rect';\n        }))\n        .enableBrush(\n            zoomActive\n            ? {\n                brushType: 'auto',\n                brushStyle: {\n                    // FIXME user customized?\n                    lineWidth: 0,\n                    fill: 'rgba(0,0,0,0.2)'\n                }\n            }\n            : false\n        );\n}\n\n\nregister$2('dataZoom', DataZoom);\n\n\n// Create special dataZoom option for select\n// FIXME consider the case of merge option, where axes options are not exists.\nregisterPreprocessor(function (option) {\n    if (!option) {\n        return;\n    }\n\n    var dataZoomOpts = option.dataZoom || (option.dataZoom = []);\n    if (!isArray(dataZoomOpts)) {\n        option.dataZoom = dataZoomOpts = [dataZoomOpts];\n    }\n\n    var toolboxOpt = option.toolbox;\n    if (toolboxOpt) {\n        // Assume there is only one toolbox\n        if (isArray(toolboxOpt)) {\n            toolboxOpt = toolboxOpt[0];\n        }\n\n        if (toolboxOpt && toolboxOpt.feature) {\n            var dataZoomOpt = toolboxOpt.feature.dataZoom;\n            // FIXME: If add dataZoom when setOption in merge mode,\n            // no axis info to be added. See `test/dataZoom-extreme.html`\n            addForAxis('xAxis', dataZoomOpt);\n            addForAxis('yAxis', dataZoomOpt);\n        }\n    }\n\n    function addForAxis(axisName, dataZoomOpt) {\n        if (!dataZoomOpt) {\n            return;\n        }\n\n        // Try not to modify model, because it is not merged yet.\n        var axisIndicesName = axisName + 'Index';\n        var givenAxisIndices = dataZoomOpt[axisIndicesName];\n        if (givenAxisIndices != null\n            && givenAxisIndices !== 'all'\n            && !isArray(givenAxisIndices)\n        ) {\n            givenAxisIndices = (givenAxisIndices === false || givenAxisIndices === 'none') ? [] : [givenAxisIndices];\n        }\n\n        forEachComponent(axisName, function (axisOpt, axisIndex) {\n            if (givenAxisIndices != null\n                && givenAxisIndices !== 'all'\n                && indexOf(givenAxisIndices, axisIndex) === -1\n            ) {\n                return;\n            }\n            var newOpt = {\n                type: 'select',\n                $fromToolbox: true,\n                // Id for merge mapping.\n                id: DATA_ZOOM_ID_BASE + axisName + axisIndex\n            };\n            // FIXME\n            // Only support one axis now.\n            newOpt[axisIndicesName] = axisIndex;\n            dataZoomOpts.push(newOpt);\n        });\n    }\n\n    function forEachComponent(mainType, cb) {\n        var opts = option[mainType];\n        if (!isArray(opts)) {\n            opts = opts ? [opts] : [];\n        }\n        each$15(opts, cb);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar restoreLang = lang.toolbox.restore;\n\nfunction Restore(model) {\n    this.model = model;\n}\n\nRestore.defaultOption = {\n    show: true,\n    /* eslint-disable */\n    icon: 'M3.8,33.4 M47,18.9h9.8V8.7 M56.3,20.1 C52.1,9,40.5,0.6,26.8,2.1C12.6,3.7,1.6,16.2,2.1,30.6 M13,41.1H3.1v10.2 M3.7,39.9c4.2,11.1,15.8,19.5,29.5,18 c14.2-1.6,25.2-14.1,24.7-28.5',\n    /* eslint-enable */\n    title: restoreLang.title\n};\n\nvar proto$6 = Restore.prototype;\n\nproto$6.onclick = function (ecModel, api, type) {\n    clear$1(ecModel);\n\n    api.dispatchAction({\n        type: 'restore',\n        from: this.uid\n    });\n};\n\nregister$2('restore', Restore);\n\nregisterAction(\n    {type: 'restore', event: 'restore', update: 'prepareAndUpdate'},\n    function (payload, ecModel) {\n        ecModel.resetOption('recreate');\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar urn = 'urn:schemas-microsoft-com:vml';\nvar win = typeof window === 'undefined' ? null : window;\n\nvar vmlInited = false;\n\nvar doc = win && win.document;\n\nfunction createNode(tagName) {\n    return doCreateNode(tagName);\n}\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar doCreateNode;\n\nif (doc && !env$1.canvasSupported) {\n    try {\n        !doc.namespaces.zrvml && doc.namespaces.add('zrvml', urn);\n        doCreateNode = function (tagName) {\n            return doc.createElement('<zrvml:' + tagName + ' class=\"zrvml\">');\n        };\n    }\n    catch (e) {\n        doCreateNode = function (tagName) {\n            return doc.createElement('<' + tagName + ' xmlns=\"' + urn + '\" class=\"zrvml\">');\n        };\n    }\n}\n\n// From raphael\nfunction initVML() {\n    if (vmlInited || !doc) {\n        return;\n    }\n    vmlInited = true;\n\n    var styleSheets = doc.styleSheets;\n    if (styleSheets.length < 31) {\n        doc.createStyleSheet().addRule('.zrvml', 'behavior:url(#default#VML)');\n    }\n    else {\n        // http://msdn.microsoft.com/en-us/library/ms531194%28VS.85%29.aspx\n        styleSheets[0].addRule('.zrvml', 'behavior:url(#default#VML)');\n    }\n}\n\n// http://www.w3.org/TR/NOTE-VML\n// TODO Use proxy like svg instead of overwrite brush methods\n\nvar CMD$3 = PathProxy.CMD;\nvar round$3 = Math.round;\nvar sqrt = Math.sqrt;\nvar abs$1 = Math.abs;\nvar cos = Math.cos;\nvar sin = Math.sin;\nvar mathMax$5 = Math.max;\n\nif (!env$1.canvasSupported) {\n\n    var comma = ',';\n    var imageTransformPrefix = 'progid:DXImageTransform.Microsoft';\n\n    var Z = 21600;\n    var Z2 = Z / 2;\n\n    var ZLEVEL_BASE = 100000;\n    var Z_BASE = 1000;\n\n    var initRootElStyle = function (el) {\n        el.style.cssText = 'position:absolute;left:0;top:0;width:1px;height:1px;';\n        el.coordsize = Z + ',' + Z;\n        el.coordorigin = '0,0';\n    };\n\n    var encodeHtmlAttribute = function (s) {\n        return String(s).replace(/&/g, '&amp;').replace(/\"/g, '&quot;');\n    };\n\n    var rgb2Str = function (r, g, b) {\n        return 'rgb(' + [r, g, b].join(',') + ')';\n    };\n\n    var append = function (parent, child) {\n        if (child && parent && child.parentNode !== parent) {\n            parent.appendChild(child);\n        }\n    };\n\n    var remove = function (parent, child) {\n        if (child && parent && child.parentNode === parent) {\n            parent.removeChild(child);\n        }\n    };\n\n    var getZIndex = function (zlevel, z, z2) {\n        // z 的取值范围为 [0, 1000]\n        return (parseFloat(zlevel) || 0) * ZLEVEL_BASE + (parseFloat(z) || 0) * Z_BASE + z2;\n    };\n\n    var parsePercent$3 = function (value, maxValue) {\n        if (typeof value === 'string') {\n            if (value.lastIndexOf('%') >= 0) {\n                return parseFloat(value) / 100 * maxValue;\n            }\n            return parseFloat(value);\n        }\n        return value;\n    };\n\n    /***************************************************\n     * PATH\n     **************************************************/\n\n    var setColorAndOpacity = function (el, color, opacity) {\n        var colorArr = parse(color);\n        opacity = +opacity;\n        if (isNaN(opacity)) {\n            opacity = 1;\n        }\n        if (colorArr) {\n            el.color = rgb2Str(colorArr[0], colorArr[1], colorArr[2]);\n            el.opacity = opacity * colorArr[3];\n        }\n    };\n\n    var getColorAndAlpha = function (color) {\n        var colorArr = parse(color);\n        return [\n            rgb2Str(colorArr[0], colorArr[1], colorArr[2]),\n            colorArr[3]\n        ];\n    };\n\n    var updateFillNode = function (el, style, zrEl) {\n        // TODO pattern\n        var fill = style.fill;\n        if (fill != null) {\n            // Modified from excanvas\n            if (fill instanceof Gradient) {\n                var gradientType;\n                var angle = 0;\n                var focus = [0, 0];\n                // additional offset\n                var shift = 0;\n                // scale factor for offset\n                var expansion = 1;\n                var rect = zrEl.getBoundingRect();\n                var rectWidth = rect.width;\n                var rectHeight = rect.height;\n                if (fill.type === 'linear') {\n                    gradientType = 'gradient';\n                    var transform = zrEl.transform;\n                    var p0 = [fill.x * rectWidth, fill.y * rectHeight];\n                    var p1 = [fill.x2 * rectWidth, fill.y2 * rectHeight];\n                    if (transform) {\n                        applyTransform(p0, p0, transform);\n                        applyTransform(p1, p1, transform);\n                    }\n                    var dx = p1[0] - p0[0];\n                    var dy = p1[1] - p0[1];\n                    angle = Math.atan2(dx, dy) * 180 / Math.PI;\n                    // The angle should be a non-negative number.\n                    if (angle < 0) {\n                        angle += 360;\n                    }\n\n                    // Very small angles produce an unexpected result because they are\n                    // converted to a scientific notation string.\n                    if (angle < 1e-6) {\n                        angle = 0;\n                    }\n                }\n                else {\n                    gradientType = 'gradientradial';\n                    var p0 = [fill.x * rectWidth, fill.y * rectHeight];\n                    var transform = zrEl.transform;\n                    var scale$$1 = zrEl.scale;\n                    var width = rectWidth;\n                    var height = rectHeight;\n                    focus = [\n                        // Percent in bounding rect\n                        (p0[0] - rect.x) / width,\n                        (p0[1] - rect.y) / height\n                    ];\n                    if (transform) {\n                        applyTransform(p0, p0, transform);\n                    }\n\n                    width /= scale$$1[0] * Z;\n                    height /= scale$$1[1] * Z;\n                    var dimension = mathMax$5(width, height);\n                    shift = 2 * 0 / dimension;\n                    expansion = 2 * fill.r / dimension - shift;\n                }\n\n                // We need to sort the color stops in ascending order by offset,\n                // otherwise IE won't interpret it correctly.\n                var stops = fill.colorStops.slice();\n                stops.sort(function (cs1, cs2) {\n                    return cs1.offset - cs2.offset;\n                });\n\n                var length$$1 = stops.length;\n                // Color and alpha list of first and last stop\n                var colorAndAlphaList = [];\n                var colors = [];\n                for (var i = 0; i < length$$1; i++) {\n                    var stop = stops[i];\n                    var colorAndAlpha = getColorAndAlpha(stop.color);\n                    colors.push(stop.offset * expansion + shift + ' ' + colorAndAlpha[0]);\n                    if (i === 0 || i === length$$1 - 1) {\n                        colorAndAlphaList.push(colorAndAlpha);\n                    }\n                }\n\n                if (length$$1 >= 2) {\n                    var color1 = colorAndAlphaList[0][0];\n                    var color2 = colorAndAlphaList[1][0];\n                    var opacity1 = colorAndAlphaList[0][1] * style.opacity;\n                    var opacity2 = colorAndAlphaList[1][1] * style.opacity;\n\n                    el.type = gradientType;\n                    el.method = 'none';\n                    el.focus = '100%';\n                    el.angle = angle;\n                    el.color = color1;\n                    el.color2 = color2;\n                    el.colors = colors.join(',');\n                    // When colors attribute is used, the meanings of opacity and o:opacity2\n                    // are reversed.\n                    el.opacity = opacity2;\n                    // FIXME g_o_:opacity ?\n                    el.opacity2 = opacity1;\n                }\n                if (gradientType === 'radial') {\n                    el.focusposition = focus.join(',');\n                }\n            }\n            else {\n                // FIXME Change from Gradient fill to color fill\n                setColorAndOpacity(el, fill, style.opacity);\n            }\n        }\n    };\n\n    var updateStrokeNode = function (el, style) {\n        // if (style.lineJoin != null) {\n        //     el.joinstyle = style.lineJoin;\n        // }\n        // if (style.miterLimit != null) {\n        //     el.miterlimit = style.miterLimit * Z;\n        // }\n        // if (style.lineCap != null) {\n        //     el.endcap = style.lineCap;\n        // }\n        if (style.lineDash != null) {\n            el.dashstyle = style.lineDash.join(' ');\n        }\n        if (style.stroke != null && !(style.stroke instanceof Gradient)) {\n            setColorAndOpacity(el, style.stroke, style.opacity);\n        }\n    };\n\n    var updateFillAndStroke = function (vmlEl, type, style, zrEl) {\n        var isFill = type === 'fill';\n        var el = vmlEl.getElementsByTagName(type)[0];\n        // Stroke must have lineWidth\n        if (style[type] != null && style[type] !== 'none' && (isFill || (!isFill && style.lineWidth))) {\n            vmlEl[isFill ? 'filled' : 'stroked'] = 'true';\n            // FIXME Remove before updating, or set `colors` will throw error\n            if (style[type] instanceof Gradient) {\n                remove(vmlEl, el);\n            }\n            if (!el) {\n                el = createNode(type);\n            }\n\n            isFill ? updateFillNode(el, style, zrEl) : updateStrokeNode(el, style);\n            append(vmlEl, el);\n        }\n        else {\n            vmlEl[isFill ? 'filled' : 'stroked'] = 'false';\n            remove(vmlEl, el);\n        }\n    };\n\n    var points$1 = [[], [], []];\n    var pathDataToString = function (path, m) {\n        var M = CMD$3.M;\n        var C = CMD$3.C;\n        var L = CMD$3.L;\n        var A = CMD$3.A;\n        var Q = CMD$3.Q;\n\n        var str = [];\n        var nPoint;\n        var cmdStr;\n        var cmd;\n        var i;\n        var xi;\n        var yi;\n        var data = path.data;\n        var dataLength = path.len();\n        for (i = 0; i < dataLength;) {\n            cmd = data[i++];\n            cmdStr = '';\n            nPoint = 0;\n            switch (cmd) {\n                case M:\n                    cmdStr = ' m ';\n                    nPoint = 1;\n                    xi = data[i++];\n                    yi = data[i++];\n                    points$1[0][0] = xi;\n                    points$1[0][1] = yi;\n                    break;\n                case L:\n                    cmdStr = ' l ';\n                    nPoint = 1;\n                    xi = data[i++];\n                    yi = data[i++];\n                    points$1[0][0] = xi;\n                    points$1[0][1] = yi;\n                    break;\n                case Q:\n                case C:\n                    cmdStr = ' c ';\n                    nPoint = 3;\n                    var x1 = data[i++];\n                    var y1 = data[i++];\n                    var x2 = data[i++];\n                    var y2 = data[i++];\n                    var x3;\n                    var y3;\n                    if (cmd === Q) {\n                        // Convert quadratic to cubic using degree elevation\n                        x3 = x2;\n                        y3 = y2;\n                        x2 = (x2 + 2 * x1) / 3;\n                        y2 = (y2 + 2 * y1) / 3;\n                        x1 = (xi + 2 * x1) / 3;\n                        y1 = (yi + 2 * y1) / 3;\n                    }\n                    else {\n                        x3 = data[i++];\n                        y3 = data[i++];\n                    }\n                    points$1[0][0] = x1;\n                    points$1[0][1] = y1;\n                    points$1[1][0] = x2;\n                    points$1[1][1] = y2;\n                    points$1[2][0] = x3;\n                    points$1[2][1] = y3;\n\n                    xi = x3;\n                    yi = y3;\n                    break;\n                case A:\n                    var x = 0;\n                    var y = 0;\n                    var sx = 1;\n                    var sy = 1;\n                    var angle = 0;\n                    if (m) {\n                        // Extract SRT from matrix\n                        x = m[4];\n                        y = m[5];\n                        sx = sqrt(m[0] * m[0] + m[1] * m[1]);\n                        sy = sqrt(m[2] * m[2] + m[3] * m[3]);\n                        angle = Math.atan2(-m[1] / sy, m[0] / sx);\n                    }\n\n                    var cx = data[i++];\n                    var cy = data[i++];\n                    var rx = data[i++];\n                    var ry = data[i++];\n                    var startAngle = data[i++] + angle;\n                    var endAngle = data[i++] + startAngle + angle;\n                    // FIXME\n                    // var psi = data[i++];\n                    i++;\n                    var clockwise = data[i++];\n\n                    var x0 = cx + cos(startAngle) * rx;\n                    var y0 = cy + sin(startAngle) * ry;\n\n                    var x1 = cx + cos(endAngle) * rx;\n                    var y1 = cy + sin(endAngle) * ry;\n\n                    var type = clockwise ? ' wa ' : ' at ';\n                    if (Math.abs(x0 - x1) < 1e-4) {\n                        // IE won't render arches drawn counter clockwise if x0 == x1.\n                        if (Math.abs(endAngle - startAngle) > 1e-2) {\n                            // Offset x0 by 1/80 of a pixel. Use something\n                            // that can be represented in binary\n                            if (clockwise) {\n                                x0 += 270 / Z;\n                            }\n                        }\n                        else {\n                            // Avoid case draw full circle\n                            if (Math.abs(y0 - cy) < 1e-4) {\n                                if ((clockwise && x0 < cx) || (!clockwise && x0 > cx)) {\n                                    y1 -= 270 / Z;\n                                }\n                                else {\n                                    y1 += 270 / Z;\n                                }\n                            }\n                            else if ((clockwise && y0 < cy) || (!clockwise && y0 > cy)) {\n                                x1 += 270 / Z;\n                            }\n                            else {\n                                x1 -= 270 / Z;\n                            }\n                        }\n                    }\n                    str.push(\n                        type,\n                        round$3(((cx - rx) * sx + x) * Z - Z2), comma,\n                        round$3(((cy - ry) * sy + y) * Z - Z2), comma,\n                        round$3(((cx + rx) * sx + x) * Z - Z2), comma,\n                        round$3(((cy + ry) * sy + y) * Z - Z2), comma,\n                        round$3((x0 * sx + x) * Z - Z2), comma,\n                        round$3((y0 * sy + y) * Z - Z2), comma,\n                        round$3((x1 * sx + x) * Z - Z2), comma,\n                        round$3((y1 * sy + y) * Z - Z2)\n                    );\n\n                    xi = x1;\n                    yi = y1;\n                    break;\n                case CMD$3.R:\n                    var p0 = points$1[0];\n                    var p1 = points$1[1];\n                    // x0, y0\n                    p0[0] = data[i++];\n                    p0[1] = data[i++];\n                    // x1, y1\n                    p1[0] = p0[0] + data[i++];\n                    p1[1] = p0[1] + data[i++];\n\n                    if (m) {\n                        applyTransform(p0, p0, m);\n                        applyTransform(p1, p1, m);\n                    }\n\n                    p0[0] = round$3(p0[0] * Z - Z2);\n                    p1[0] = round$3(p1[0] * Z - Z2);\n                    p0[1] = round$3(p0[1] * Z - Z2);\n                    p1[1] = round$3(p1[1] * Z - Z2);\n                    str.push(\n                        // x0, y0\n                        ' m ', p0[0], comma, p0[1],\n                        // x1, y0\n                        ' l ', p1[0], comma, p0[1],\n                        // x1, y1\n                        ' l ', p1[0], comma, p1[1],\n                        // x0, y1\n                        ' l ', p0[0], comma, p1[1]\n                    );\n                    break;\n                case CMD$3.Z:\n                    // FIXME Update xi, yi\n                    str.push(' x ');\n            }\n\n            if (nPoint > 0) {\n                str.push(cmdStr);\n                for (var k = 0; k < nPoint; k++) {\n                    var p = points$1[k];\n\n                    m && applyTransform(p, p, m);\n                    // 不 round 会非常慢\n                    str.push(\n                        round$3(p[0] * Z - Z2), comma, round$3(p[1] * Z - Z2),\n                        k < nPoint - 1 ? comma : ''\n                    );\n                }\n            }\n        }\n\n        return str.join('');\n    };\n\n    // Rewrite the original path method\n    Path.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n\n        var vmlEl = this._vmlEl;\n        if (!vmlEl) {\n            vmlEl = createNode('shape');\n            initRootElStyle(vmlEl);\n\n            this._vmlEl = vmlEl;\n        }\n\n        updateFillAndStroke(vmlEl, 'fill', style, this);\n        updateFillAndStroke(vmlEl, 'stroke', style, this);\n\n        var m = this.transform;\n        var needTransform = m != null;\n        var strokeEl = vmlEl.getElementsByTagName('stroke')[0];\n        if (strokeEl) {\n            var lineWidth = style.lineWidth;\n            // Get the line scale.\n            // Determinant of this.m_ means how much the area is enlarged by the\n            // transformation. So its square root can be used as a scale factor\n            // for width.\n            if (needTransform && !style.strokeNoScale) {\n                var det = m[0] * m[3] - m[1] * m[2];\n                lineWidth *= sqrt(abs$1(det));\n            }\n            strokeEl.weight = lineWidth + 'px';\n        }\n\n        var path = this.path || (this.path = new PathProxy());\n        if (this.__dirtyPath) {\n            path.beginPath();\n            path.subPixelOptimize = false;\n            this.buildPath(path, this.shape);\n            path.toStatic();\n            this.__dirtyPath = false;\n        }\n\n        vmlEl.path = pathDataToString(path, this.transform);\n\n        vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Append to root\n        append(vmlRoot, vmlEl);\n\n        // Text\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, this.getBoundingRect());\n        }\n        else {\n            this.removeRectText(vmlRoot);\n        }\n    };\n\n    Path.prototype.onRemove = function (vmlRoot) {\n        remove(vmlRoot, this._vmlEl);\n        this.removeRectText(vmlRoot);\n    };\n\n    Path.prototype.onAdd = function (vmlRoot) {\n        append(vmlRoot, this._vmlEl);\n        this.appendRectText(vmlRoot);\n    };\n\n    /***************************************************\n     * IMAGE\n     **************************************************/\n    var isImage = function (img) {\n        // FIXME img instanceof Image 如果 img 是一个字符串的时候，IE8 下会报错\n        return (typeof img === 'object') && img.tagName && img.tagName.toUpperCase() === 'IMG';\n        // return img instanceof Image;\n    };\n\n    // Rewrite the original path method\n    ZImage.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n        var image = style.image;\n\n        // Image original width, height\n        var ow;\n        var oh;\n\n        if (isImage(image)) {\n            var src = image.src;\n            if (src === this._imageSrc) {\n                ow = this._imageWidth;\n                oh = this._imageHeight;\n            }\n            else {\n                var imageRuntimeStyle = image.runtimeStyle;\n                var oldRuntimeWidth = imageRuntimeStyle.width;\n                var oldRuntimeHeight = imageRuntimeStyle.height;\n                imageRuntimeStyle.width = 'auto';\n                imageRuntimeStyle.height = 'auto';\n\n                // get the original size\n                ow = image.width;\n                oh = image.height;\n\n                // and remove overides\n                imageRuntimeStyle.width = oldRuntimeWidth;\n                imageRuntimeStyle.height = oldRuntimeHeight;\n\n                // Caching image original width, height and src\n                this._imageSrc = src;\n                this._imageWidth = ow;\n                this._imageHeight = oh;\n            }\n            image = src;\n        }\n        else {\n            if (image === this._imageSrc) {\n                ow = this._imageWidth;\n                oh = this._imageHeight;\n            }\n        }\n        if (!image) {\n            return;\n        }\n\n        var x = style.x || 0;\n        var y = style.y || 0;\n\n        var dw = style.width;\n        var dh = style.height;\n\n        var sw = style.sWidth;\n        var sh = style.sHeight;\n        var sx = style.sx || 0;\n        var sy = style.sy || 0;\n\n        var hasCrop = sw && sh;\n\n        var vmlEl = this._vmlEl;\n        if (!vmlEl) {\n            // FIXME 使用 group 在 left, top 都不是 0 的时候就无法显示了。\n            // vmlEl = vmlCore.createNode('group');\n            vmlEl = doc.createElement('div');\n            initRootElStyle(vmlEl);\n\n            this._vmlEl = vmlEl;\n        }\n\n        var vmlElStyle = vmlEl.style;\n        var hasRotation = false;\n        var m;\n        var scaleX = 1;\n        var scaleY = 1;\n        if (this.transform) {\n            m = this.transform;\n            scaleX = sqrt(m[0] * m[0] + m[1] * m[1]);\n            scaleY = sqrt(m[2] * m[2] + m[3] * m[3]);\n\n            hasRotation = m[1] || m[2];\n        }\n        if (hasRotation) {\n            // If filters are necessary (rotation exists), create them\n            // filters are bog-slow, so only create them if abbsolutely necessary\n            // The following check doesn't account for skews (which don't exist\n            // in the canvas spec (yet) anyway.\n            // From excanvas\n            var p0 = [x, y];\n            var p1 = [x + dw, y];\n            var p2 = [x, y + dh];\n            var p3 = [x + dw, y + dh];\n            applyTransform(p0, p0, m);\n            applyTransform(p1, p1, m);\n            applyTransform(p2, p2, m);\n            applyTransform(p3, p3, m);\n\n            var maxX = mathMax$5(p0[0], p1[0], p2[0], p3[0]);\n            var maxY = mathMax$5(p0[1], p1[1], p2[1], p3[1]);\n\n            var transformFilter = [];\n            transformFilter.push('M11=', m[0] / scaleX, comma,\n                        'M12=', m[2] / scaleY, comma,\n                        'M21=', m[1] / scaleX, comma,\n                        'M22=', m[3] / scaleY, comma,\n                        'Dx=', round$3(x * scaleX + m[4]), comma,\n                        'Dy=', round$3(y * scaleY + m[5]));\n\n            vmlElStyle.padding = '0 ' + round$3(maxX) + 'px ' + round$3(maxY) + 'px 0';\n            // FIXME DXImageTransform 在 IE11 的兼容模式下不起作用\n            vmlElStyle.filter = imageTransformPrefix + '.Matrix('\n                + transformFilter.join('') + ', SizingMethod=clip)';\n\n        }\n        else {\n            if (m) {\n                x = x * scaleX + m[4];\n                y = y * scaleY + m[5];\n            }\n            vmlElStyle.filter = '';\n            vmlElStyle.left = round$3(x) + 'px';\n            vmlElStyle.top = round$3(y) + 'px';\n        }\n\n        var imageEl = this._imageEl;\n        var cropEl = this._cropEl;\n\n        if (!imageEl) {\n            imageEl = doc.createElement('div');\n            this._imageEl = imageEl;\n        }\n        var imageELStyle = imageEl.style;\n        if (hasCrop) {\n            // Needs know image original width and height\n            if (!(ow && oh)) {\n                var tmpImage = new Image();\n                var self = this;\n                tmpImage.onload = function () {\n                    tmpImage.onload = null;\n                    ow = tmpImage.width;\n                    oh = tmpImage.height;\n                    // Adjust image width and height to fit the ratio destinationSize / sourceSize\n                    imageELStyle.width = round$3(scaleX * ow * dw / sw) + 'px';\n                    imageELStyle.height = round$3(scaleY * oh * dh / sh) + 'px';\n\n                    // Caching image original width, height and src\n                    self._imageWidth = ow;\n                    self._imageHeight = oh;\n                    self._imageSrc = image;\n                };\n                tmpImage.src = image;\n            }\n            else {\n                imageELStyle.width = round$3(scaleX * ow * dw / sw) + 'px';\n                imageELStyle.height = round$3(scaleY * oh * dh / sh) + 'px';\n            }\n\n            if (!cropEl) {\n                cropEl = doc.createElement('div');\n                cropEl.style.overflow = 'hidden';\n                this._cropEl = cropEl;\n            }\n            var cropElStyle = cropEl.style;\n            cropElStyle.width = round$3((dw + sx * dw / sw) * scaleX);\n            cropElStyle.height = round$3((dh + sy * dh / sh) * scaleY);\n            cropElStyle.filter = imageTransformPrefix + '.Matrix(Dx='\n                    + (-sx * dw / sw * scaleX) + ',Dy=' + (-sy * dh / sh * scaleY) + ')';\n\n            if (!cropEl.parentNode) {\n                vmlEl.appendChild(cropEl);\n            }\n            if (imageEl.parentNode !== cropEl) {\n                cropEl.appendChild(imageEl);\n            }\n        }\n        else {\n            imageELStyle.width = round$3(scaleX * dw) + 'px';\n            imageELStyle.height = round$3(scaleY * dh) + 'px';\n\n            vmlEl.appendChild(imageEl);\n\n            if (cropEl && cropEl.parentNode) {\n                vmlEl.removeChild(cropEl);\n                this._cropEl = null;\n            }\n        }\n\n        var filterStr = '';\n        var alpha = style.opacity;\n        if (alpha < 1) {\n            filterStr += '.Alpha(opacity=' + round$3(alpha * 100) + ') ';\n        }\n        filterStr += imageTransformPrefix + '.AlphaImageLoader(src=' + image + ', SizingMethod=scale)';\n\n        imageELStyle.filter = filterStr;\n\n        vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Append to root\n        append(vmlRoot, vmlEl);\n\n        // Text\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, this.getBoundingRect());\n        }\n    };\n\n    ZImage.prototype.onRemove = function (vmlRoot) {\n        remove(vmlRoot, this._vmlEl);\n\n        this._vmlEl = null;\n        this._cropEl = null;\n        this._imageEl = null;\n\n        this.removeRectText(vmlRoot);\n    };\n\n    ZImage.prototype.onAdd = function (vmlRoot) {\n        append(vmlRoot, this._vmlEl);\n        this.appendRectText(vmlRoot);\n    };\n\n\n    /***************************************************\n     * TEXT\n     **************************************************/\n\n    var DEFAULT_STYLE_NORMAL = 'normal';\n\n    var fontStyleCache = {};\n    var fontStyleCacheCount = 0;\n    var MAX_FONT_CACHE_SIZE = 100;\n    var fontEl = document.createElement('div');\n\n    var getFontStyle = function (fontString) {\n        var fontStyle = fontStyleCache[fontString];\n        if (!fontStyle) {\n            // Clear cache\n            if (fontStyleCacheCount > MAX_FONT_CACHE_SIZE) {\n                fontStyleCacheCount = 0;\n                fontStyleCache = {};\n            }\n\n            var style = fontEl.style;\n            var fontFamily;\n            try {\n                style.font = fontString;\n                fontFamily = style.fontFamily.split(',')[0];\n            }\n            catch (e) {\n            }\n\n            fontStyle = {\n                style: style.fontStyle || DEFAULT_STYLE_NORMAL,\n                variant: style.fontVariant || DEFAULT_STYLE_NORMAL,\n                weight: style.fontWeight || DEFAULT_STYLE_NORMAL,\n                size: parseFloat(style.fontSize || 12) | 0,\n                family: fontFamily || 'Microsoft YaHei'\n            };\n\n            fontStyleCache[fontString] = fontStyle;\n            fontStyleCacheCount++;\n        }\n        return fontStyle;\n    };\n\n    var textMeasureEl;\n    // Overwrite measure text method\n    $override$1('measureText', function (text, textFont) {\n        var doc$$1 = doc;\n        if (!textMeasureEl) {\n            textMeasureEl = doc$$1.createElement('div');\n            textMeasureEl.style.cssText = 'position:absolute;top:-20000px;left:0;'\n                + 'padding:0;margin:0;border:none;white-space:pre;';\n            doc.body.appendChild(textMeasureEl);\n        }\n\n        try {\n            textMeasureEl.style.font = textFont;\n        }\n        catch (ex) {\n            // Ignore failures to set to invalid font.\n        }\n        textMeasureEl.innerHTML = '';\n        // Don't use innerHTML or innerText because they allow markup/whitespace.\n        textMeasureEl.appendChild(doc$$1.createTextNode(text));\n        return {\n            width: textMeasureEl.offsetWidth\n        };\n    });\n\n    var tmpRect$2 = new BoundingRect();\n\n    var drawRectText = function (vmlRoot, rect, textRect, fromTextEl) {\n\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        var text = style.text;\n        // Convert to string\n        text != null && (text += '');\n        if (!text) {\n            return;\n        }\n\n        // Convert rich text to plain text. Rich text is not supported in\n        // IE8-, but tags in rich text template will be removed.\n        if (style.rich) {\n            var contentBlock = parseRichText(text, style);\n            text = [];\n            for (var i = 0; i < contentBlock.lines.length; i++) {\n                var tokens = contentBlock.lines[i].tokens;\n                var textLine = [];\n                for (var j = 0; j < tokens.length; j++) {\n                    textLine.push(tokens[j].text);\n                }\n                text.push(textLine.join(''));\n            }\n            text = text.join('\\n');\n        }\n\n        var x;\n        var y;\n        var align = style.textAlign;\n        var verticalAlign = style.textVerticalAlign;\n\n        var fontStyle = getFontStyle(style.font);\n        // FIXME encodeHtmlAttribute ?\n        var font = fontStyle.style + ' ' + fontStyle.variant + ' ' + fontStyle.weight + ' '\n            + fontStyle.size + 'px \"' + fontStyle.family + '\"';\n\n        textRect = textRect || getBoundingRect(\n            text, font, align, verticalAlign, style.textPadding, style.textLineHeight\n        );\n\n        // Transform rect to view space\n        var m = this.transform;\n        // Ignore transform for text in other element\n        if (m && !fromTextEl) {\n            tmpRect$2.copy(rect);\n            tmpRect$2.applyTransform(m);\n            rect = tmpRect$2;\n        }\n\n        if (!fromTextEl) {\n            var textPosition = style.textPosition;\n            var distance$$1 = style.textDistance;\n            // Text position represented by coord\n            if (textPosition instanceof Array) {\n                x = rect.x + parsePercent$3(textPosition[0], rect.width);\n                y = rect.y + parsePercent$3(textPosition[1], rect.height);\n\n                align = align || 'left';\n            }\n            else {\n                var res = adjustTextPositionOnRect(\n                    textPosition, rect, distance$$1\n                );\n                x = res.x;\n                y = res.y;\n\n                // Default align and baseline when has textPosition\n                align = align || res.textAlign;\n                verticalAlign = verticalAlign || res.textVerticalAlign;\n            }\n        }\n        else {\n            x = rect.x;\n            y = rect.y;\n        }\n\n        x = adjustTextX(x, textRect.width, align);\n        y = adjustTextY(y, textRect.height, verticalAlign);\n\n        // Force baseline 'middle'\n        y += textRect.height / 2;\n\n        // var fontSize = fontStyle.size;\n        // 1.75 is an arbitrary number, as there is no info about the text baseline\n        // switch (baseline) {\n            // case 'hanging':\n            // case 'top':\n            //     y += fontSize / 1.75;\n            //     break;\n        //     case 'middle':\n        //         break;\n        //     default:\n        //     // case null:\n        //     // case 'alphabetic':\n        //     // case 'ideographic':\n        //     // case 'bottom':\n        //         y -= fontSize / 2.25;\n        //         break;\n        // }\n\n        // switch (align) {\n        //     case 'left':\n        //         break;\n        //     case 'center':\n        //         x -= textRect.width / 2;\n        //         break;\n        //     case 'right':\n        //         x -= textRect.width;\n        //         break;\n            // case 'end':\n                // align = elementStyle.direction == 'ltr' ? 'right' : 'left';\n                // break;\n            // case 'start':\n                // align = elementStyle.direction == 'rtl' ? 'right' : 'left';\n                // break;\n            // default:\n            //     align = 'left';\n        // }\n\n        var createNode$$1 = createNode;\n\n        var textVmlEl = this._textVmlEl;\n        var pathEl;\n        var textPathEl;\n        var skewEl;\n        if (!textVmlEl) {\n            textVmlEl = createNode$$1('line');\n            pathEl = createNode$$1('path');\n            textPathEl = createNode$$1('textpath');\n            skewEl = createNode$$1('skew');\n\n            // FIXME Why here is not cammel case\n            // Align 'center' seems wrong\n            textPathEl.style['v-text-align'] = 'left';\n\n            initRootElStyle(textVmlEl);\n\n            pathEl.textpathok = true;\n            textPathEl.on = true;\n\n            textVmlEl.from = '0 0';\n            textVmlEl.to = '1000 0.05';\n\n            append(textVmlEl, skewEl);\n            append(textVmlEl, pathEl);\n            append(textVmlEl, textPathEl);\n\n            this._textVmlEl = textVmlEl;\n        }\n        else {\n            // 这里是在前面 appendChild 保证顺序的前提下\n            skewEl = textVmlEl.firstChild;\n            pathEl = skewEl.nextSibling;\n            textPathEl = pathEl.nextSibling;\n        }\n\n        var coords = [x, y];\n        var textVmlElStyle = textVmlEl.style;\n        // Ignore transform for text in other element\n        if (m && fromTextEl) {\n            applyTransform(coords, coords, m);\n\n            skewEl.on = true;\n\n            skewEl.matrix = m[0].toFixed(3) + comma + m[2].toFixed(3) + comma\n                            + m[1].toFixed(3) + comma + m[3].toFixed(3) + ',0,0';\n\n            // Text position\n            skewEl.offset = (round$3(coords[0]) || 0) + ',' + (round$3(coords[1]) || 0);\n            // Left top point as origin\n            skewEl.origin = '0 0';\n\n            textVmlElStyle.left = '0px';\n            textVmlElStyle.top = '0px';\n        }\n        else {\n            skewEl.on = false;\n            textVmlElStyle.left = round$3(x) + 'px';\n            textVmlElStyle.top = round$3(y) + 'px';\n        }\n\n        textPathEl.string = encodeHtmlAttribute(text);\n        // TODO\n        try {\n            textPathEl.style.font = font;\n        }\n        // Error font format\n        catch (e) {}\n\n        updateFillAndStroke(textVmlEl, 'fill', {\n            fill: style.textFill,\n            opacity: style.opacity\n        }, this);\n        updateFillAndStroke(textVmlEl, 'stroke', {\n            stroke: style.textStroke,\n            opacity: style.opacity,\n            lineDash: style.lineDash\n        }, this);\n\n        textVmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Attached to root\n        append(vmlRoot, textVmlEl);\n    };\n\n    var removeRectText = function (vmlRoot) {\n        remove(vmlRoot, this._textVmlEl);\n        this._textVmlEl = null;\n    };\n\n    var appendRectText = function (vmlRoot) {\n        append(vmlRoot, this._textVmlEl);\n    };\n\n    var list = [RectText, Displayable, ZImage, Path, Text];\n\n    // In case Displayable has been mixed in RectText\n    for (var i$1 = 0; i$1 < list.length; i$1++) {\n        var proto$7 = list[i$1].prototype;\n        proto$7.drawRectText = drawRectText;\n        proto$7.removeRectText = removeRectText;\n        proto$7.appendRectText = appendRectText;\n    }\n\n    Text.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, {\n                x: style.x || 0, y: style.y || 0,\n                width: 0, height: 0\n            }, this.getBoundingRect(), true);\n        }\n        else {\n            this.removeRectText(vmlRoot);\n        }\n    };\n\n    Text.prototype.onRemove = function (vmlRoot) {\n        this.removeRectText(vmlRoot);\n    };\n\n    Text.prototype.onAdd = function (vmlRoot) {\n        this.appendRectText(vmlRoot);\n    };\n}\n\n/**\n * VML Painter.\n *\n * @module zrender/vml/Painter\n */\n\nfunction parseInt10$1(val) {\n    return parseInt(val, 10);\n}\n\n/**\n * @alias module:zrender/vml/Painter\n */\nfunction VMLPainter(root, storage) {\n\n    initVML();\n\n    this.root = root;\n\n    this.storage = storage;\n\n    var vmlViewport = document.createElement('div');\n\n    var vmlRoot = document.createElement('div');\n\n    vmlViewport.style.cssText = 'display:inline-block;overflow:hidden;position:relative;width:300px;height:150px;';\n\n    vmlRoot.style.cssText = 'position:absolute;left:0;top:0;';\n\n    root.appendChild(vmlViewport);\n\n    this._vmlRoot = vmlRoot;\n    this._vmlViewport = vmlViewport;\n\n    this.resize();\n\n    // Modify storage\n    var oldDelFromStorage = storage.delFromStorage;\n    var oldAddToStorage = storage.addToStorage;\n    storage.delFromStorage = function (el) {\n        oldDelFromStorage.call(storage, el);\n\n        if (el) {\n            el.onRemove && el.onRemove(vmlRoot);\n        }\n    };\n\n    storage.addToStorage = function (el) {\n        // Displayable already has a vml node\n        el.onAdd && el.onAdd(vmlRoot);\n\n        oldAddToStorage.call(storage, el);\n    };\n\n    this._firstPaint = true;\n}\n\nVMLPainter.prototype = {\n\n    constructor: VMLPainter,\n\n    getType: function () {\n        return 'vml';\n    },\n\n    /**\n     * @return {HTMLDivElement}\n     */\n    getViewportRoot: function () {\n        return this._vmlViewport;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    /**\n     * 刷新\n     */\n    refresh: function () {\n\n        var list = this.storage.getDisplayList(true, true);\n\n        this._paintList(list);\n    },\n\n    _paintList: function (list) {\n        var vmlRoot = this._vmlRoot;\n        for (var i = 0; i < list.length; i++) {\n            var el = list[i];\n            if (el.invisible || el.ignore) {\n                if (!el.__alreadyNotVisible) {\n                    el.onRemove(vmlRoot);\n                }\n                // Set as already invisible\n                el.__alreadyNotVisible = true;\n            }\n            else {\n                if (el.__alreadyNotVisible) {\n                    el.onAdd(vmlRoot);\n                }\n                el.__alreadyNotVisible = false;\n                if (el.__dirty) {\n                    el.beforeBrush && el.beforeBrush();\n                    (el.brushVML || el.brush).call(el, vmlRoot);\n                    el.afterBrush && el.afterBrush();\n                }\n            }\n            el.__dirty = false;\n        }\n\n        if (this._firstPaint) {\n            // Detached from document at first time\n            // to avoid page refreshing too many times\n\n            // FIXME 如果每次都先 removeChild 可能会导致一些填充和描边的效果改变\n            this._vmlViewport.appendChild(vmlRoot);\n            this._firstPaint = false;\n        }\n    },\n\n    resize: function (width, height) {\n        var width = width == null ? this._getWidth() : width;\n        var height = height == null ? this._getHeight() : height;\n\n        if (this._width !== width || this._height !== height) {\n            this._width = width;\n            this._height = height;\n\n            var vmlViewportStyle = this._vmlViewport.style;\n            vmlViewportStyle.width = width + 'px';\n            vmlViewportStyle.height = height + 'px';\n        }\n    },\n\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this._vmlRoot =\n        this._vmlViewport =\n        this.storage = null;\n    },\n\n    getWidth: function () {\n        return this._width;\n    },\n\n    getHeight: function () {\n        return this._height;\n    },\n\n    clear: function () {\n        if (this._vmlViewport) {\n            this.root.removeChild(this._vmlViewport);\n        }\n    },\n\n    _getWidth: function () {\n        var root = this.root;\n        var stl = root.currentStyle;\n\n        return ((root.clientWidth || parseInt10$1(stl.width))\n                - parseInt10$1(stl.paddingLeft)\n                - parseInt10$1(stl.paddingRight)) | 0;\n    },\n\n    _getHeight: function () {\n        var root = this.root;\n        var stl = root.currentStyle;\n\n        return ((root.clientHeight || parseInt10$1(stl.height))\n                - parseInt10$1(stl.paddingTop)\n                - parseInt10$1(stl.paddingBottom)) | 0;\n    }\n};\n\n// Not supported methods\nfunction createMethodNotSupport(method) {\n    return function () {\n        zrLog('In IE8.0 VML mode painter not support method \"' + method + '\"');\n    };\n}\n\n// Unsupported methods\neach$1([\n    'getLayer', 'insertLayer', 'eachLayer', 'eachBuiltinLayer', 'eachOtherLayer', 'getLayers',\n    'modLayer', 'delLayer', 'clearLayer', 'toDataURL', 'pathToImage'\n], function (name) {\n    VMLPainter.prototype[name] = createMethodNotSupport(name);\n});\n\nregisterPainter('vml', VMLPainter);\n\nvar svgURI = 'http://www.w3.org/2000/svg';\n\nfunction createElement(name) {\n    return document.createElementNS(svgURI, name);\n}\n\n// TODO\n// 1. shadow\n// 2. Image: sx, sy, sw, sh\n\nvar CMD$4 = PathProxy.CMD;\nvar arrayJoin = Array.prototype.join;\n\nvar NONE = 'none';\nvar mathRound = Math.round;\nvar mathSin$3 = Math.sin;\nvar mathCos$3 = Math.cos;\nvar PI$3 = Math.PI;\nvar PI2$5 = Math.PI * 2;\nvar degree = 180 / PI$3;\n\nvar EPSILON$4 = 1e-4;\n\nfunction round4(val) {\n    return mathRound(val * 1e4) / 1e4;\n}\n\nfunction isAroundZero$1(val) {\n    return val < EPSILON$4 && val > -EPSILON$4;\n}\n\nfunction pathHasFill(style, isText) {\n    var fill = isText ? style.textFill : style.fill;\n    return fill != null && fill !== NONE;\n}\n\nfunction pathHasStroke(style, isText) {\n    var stroke = isText ? style.textStroke : style.stroke;\n    return stroke != null && stroke !== NONE;\n}\n\nfunction setTransform(svgEl, m) {\n    if (m) {\n        attr(svgEl, 'transform', 'matrix(' + arrayJoin.call(m, ',') + ')');\n    }\n}\n\nfunction attr(el, key, val) {\n    if (!val || val.type !== 'linear' && val.type !== 'radial') {\n        // Don't set attribute for gradient, since it need new dom nodes\n        el.setAttribute(key, val);\n    }\n}\n\nfunction attrXLink(el, key, val) {\n    el.setAttributeNS('http://www.w3.org/1999/xlink', key, val);\n}\n\nfunction bindStyle(svgEl, style, isText, el) {\n    if (pathHasFill(style, isText)) {\n        var fill = isText ? style.textFill : style.fill;\n        fill = fill === 'transparent' ? NONE : fill;\n\n        /**\n         * FIXME:\n         * This is a temporary fix for Chrome's clipping bug\n         * that happens when a clip-path is referring another one.\n         * This fix should be used before Chrome's bug is fixed.\n         * For an element that has clip-path, and fill is none,\n         * set it to be \"rgba(0, 0, 0, 0.002)\" will hide the element.\n         * Otherwise, it will show black fill color.\n         * 0.002 is used because this won't work for alpha values smaller\n         * than 0.002.\n         *\n         * See\n         * https://bugs.chromium.org/p/chromium/issues/detail?id=659790\n         * for more information.\n         */\n        if (svgEl.getAttribute('clip-path') !== 'none' && fill === NONE) {\n            fill = 'rgba(0, 0, 0, 0.002)';\n        }\n\n        attr(svgEl, 'fill', fill);\n        attr(svgEl, 'fill-opacity', style.fillOpacity != null ? style.fillOpacity * style.opacity : style.opacity);\n    }\n    else {\n        attr(svgEl, 'fill', NONE);\n    }\n\n    if (pathHasStroke(style, isText)) {\n        var stroke = isText ? style.textStroke : style.stroke;\n        stroke = stroke === 'transparent' ? NONE : stroke;\n        attr(svgEl, 'stroke', stroke);\n        var strokeWidth = isText\n            ? style.textStrokeWidth\n            : style.lineWidth;\n        var strokeScale = !isText && style.strokeNoScale\n            ? el.getLineScale()\n            : 1;\n        attr(svgEl, 'stroke-width', strokeWidth / strokeScale);\n        // stroke then fill for text; fill then stroke for others\n        attr(svgEl, 'paint-order', isText ? 'stroke' : 'fill');\n        attr(svgEl, 'stroke-opacity', style.strokeOpacity != null ? style.strokeOpacity : style.opacity);\n        var lineDash = style.lineDash;\n        if (lineDash) {\n            attr(svgEl, 'stroke-dasharray', style.lineDash.join(','));\n            attr(svgEl, 'stroke-dashoffset', mathRound(style.lineDashOffset || 0));\n        }\n        else {\n            attr(svgEl, 'stroke-dasharray', '');\n        }\n\n        // PENDING\n        style.lineCap && attr(svgEl, 'stroke-linecap', style.lineCap);\n        style.lineJoin && attr(svgEl, 'stroke-linejoin', style.lineJoin);\n        style.miterLimit && attr(svgEl, 'stroke-miterlimit', style.miterLimit);\n    }\n    else {\n        attr(svgEl, 'stroke', NONE);\n    }\n}\n\n/***************************************************\n * PATH\n **************************************************/\nfunction pathDataToString$1(path) {\n    var str = [];\n    var data = path.data;\n    var dataLength = path.len();\n    for (var i = 0; i < dataLength;) {\n        var cmd = data[i++];\n        var cmdStr = '';\n        var nData = 0;\n        switch (cmd) {\n            case CMD$4.M:\n                cmdStr = 'M';\n                nData = 2;\n                break;\n            case CMD$4.L:\n                cmdStr = 'L';\n                nData = 2;\n                break;\n            case CMD$4.Q:\n                cmdStr = 'Q';\n                nData = 4;\n                break;\n            case CMD$4.C:\n                cmdStr = 'C';\n                nData = 6;\n                break;\n            case CMD$4.A:\n                var cx = data[i++];\n                var cy = data[i++];\n                var rx = data[i++];\n                var ry = data[i++];\n                var theta = data[i++];\n                var dTheta = data[i++];\n                var psi = data[i++];\n                var clockwise = data[i++];\n\n                var dThetaPositive = Math.abs(dTheta);\n                var isCircle = isAroundZero$1(dThetaPositive - PI2$5)\n                    && !isAroundZero$1(dThetaPositive);\n\n                var large = false;\n                if (dThetaPositive >= PI2$5) {\n                    large = true;\n                }\n                else if (isAroundZero$1(dThetaPositive)) {\n                    large = false;\n                }\n                else {\n                    large = (dTheta > -PI$3 && dTheta < 0 || dTheta > PI$3)\n                        === !!clockwise;\n                }\n\n                var x0 = round4(cx + rx * mathCos$3(theta));\n                var y0 = round4(cy + ry * mathSin$3(theta));\n\n                // It will not draw if start point and end point are exactly the same\n                // We need to shift the end point with a small value\n                // FIXME A better way to draw circle ?\n                if (isCircle) {\n                    if (clockwise) {\n                        dTheta = PI2$5 - 1e-4;\n                    }\n                    else {\n                        dTheta = -PI2$5 + 1e-4;\n                    }\n\n                    large = true;\n\n                    if (i === 9) {\n                        // Move to (x0, y0) only when CMD.A comes at the\n                        // first position of a shape.\n                        // For instance, when drawing a ring, CMD.A comes\n                        // after CMD.M, so it's unnecessary to move to\n                        // (x0, y0).\n                        str.push('M', x0, y0);\n                    }\n                }\n\n                var x = round4(cx + rx * mathCos$3(theta + dTheta));\n                var y = round4(cy + ry * mathSin$3(theta + dTheta));\n\n                // FIXME Ellipse\n                str.push('A', round4(rx), round4(ry),\n                    mathRound(psi * degree), +large, +clockwise, x, y);\n                break;\n            case CMD$4.Z:\n                cmdStr = 'Z';\n                break;\n            case CMD$4.R:\n                var x = round4(data[i++]);\n                var y = round4(data[i++]);\n                var w = round4(data[i++]);\n                var h = round4(data[i++]);\n                str.push(\n                    'M', x, y,\n                    'L', x + w, y,\n                    'L', x + w, y + h,\n                    'L', x, y + h,\n                    'L', x, y\n                );\n                break;\n        }\n        cmdStr && str.push(cmdStr);\n        for (var j = 0; j < nData; j++) {\n            // PENDING With scale\n            str.push(round4(data[i++]));\n        }\n    }\n    return str.join(' ');\n}\n\nvar svgPath = {};\nsvgPath.brush = function (el) {\n    var style = el.style;\n\n    var svgEl = el.__svgEl;\n    if (!svgEl) {\n        svgEl = createElement('path');\n        el.__svgEl = svgEl;\n    }\n\n    if (!el.path) {\n        el.createPathProxy();\n    }\n    var path = el.path;\n\n    if (el.__dirtyPath) {\n        path.beginPath();\n        path.subPixelOptimize = false;\n        el.buildPath(path, el.shape);\n        el.__dirtyPath = false;\n\n        var pathStr = pathDataToString$1(path);\n        if (pathStr.indexOf('NaN') < 0) {\n            // Ignore illegal path, which may happen such in out-of-range\n            // data in Calendar series.\n            attr(svgEl, 'd', pathStr);\n        }\n    }\n\n    bindStyle(svgEl, style, false, el);\n    setTransform(svgEl, el.transform);\n\n    if (style.text != null) {\n        svgTextDrawRectText(el, el.getBoundingRect());\n    }\n};\n\n/***************************************************\n * IMAGE\n **************************************************/\nvar svgImage = {};\nsvgImage.brush = function (el) {\n    var style = el.style;\n    var image = style.image;\n\n    if (image instanceof HTMLImageElement) {\n        var src = image.src;\n        image = src;\n    }\n    if (!image) {\n        return;\n    }\n\n    var x = style.x || 0;\n    var y = style.y || 0;\n\n    var dw = style.width;\n    var dh = style.height;\n\n    var svgEl = el.__svgEl;\n    if (!svgEl) {\n        svgEl = createElement('image');\n        el.__svgEl = svgEl;\n    }\n\n    if (image !== el.__imageSrc) {\n        attrXLink(svgEl, 'href', image);\n        // Caching image src\n        el.__imageSrc = image;\n    }\n\n    attr(svgEl, 'width', dw);\n    attr(svgEl, 'height', dh);\n\n    attr(svgEl, 'x', x);\n    attr(svgEl, 'y', y);\n\n    setTransform(svgEl, el.transform);\n\n    if (style.text != null) {\n        svgTextDrawRectText(el, el.getBoundingRect());\n    }\n};\n\n/***************************************************\n * TEXT\n **************************************************/\nvar svgText = {};\nvar tmpRect$3 = new BoundingRect();\n\nvar svgTextDrawRectText = function (el, rect, textRect) {\n    var style = el.style;\n\n    el.__dirty && normalizeTextStyle(style, true);\n\n    var text = style.text;\n    // Convert to string\n    if (text == null) {\n        // Draw no text only when text is set to null, but not ''\n        return;\n    }\n    else {\n        text += '';\n    }\n\n    var textSvgEl = el.__textSvgEl;\n    if (!textSvgEl) {\n        textSvgEl = createElement('text');\n        el.__textSvgEl = textSvgEl;\n    }\n\n    var x;\n    var y;\n    var textPosition = style.textPosition;\n    var distance = style.textDistance;\n    var align = style.textAlign || 'left';\n\n    if (typeof style.fontSize === 'number') {\n        style.fontSize += 'px';\n    }\n    var font = style.font\n        || [\n            style.fontStyle || '',\n            style.fontWeight || '',\n            style.fontSize || '',\n            style.fontFamily || ''\n        ].join(' ')\n        || DEFAULT_FONT$1;\n\n    var verticalAlign = getVerticalAlignForSvg(style.textVerticalAlign);\n\n    textRect = getBoundingRect(\n        text, font, align,\n        verticalAlign, style.textPadding, style.textLineHeight\n    );\n\n    var lineHeight = textRect.lineHeight;\n    // Text position represented by coord\n    if (textPosition instanceof Array) {\n        x = rect.x + textPosition[0];\n        y = rect.y + textPosition[1];\n    }\n    else {\n        var newPos = adjustTextPositionOnRect(\n            textPosition, rect, distance\n        );\n        x = newPos.x;\n        y = newPos.y;\n        verticalAlign = getVerticalAlignForSvg(newPos.textVerticalAlign);\n        align = newPos.textAlign;\n    }\n\n    attr(textSvgEl, 'alignment-baseline', verticalAlign);\n\n    if (font) {\n        textSvgEl.style.font = font;\n    }\n\n    var textPadding = style.textPadding;\n\n    // Make baseline top\n    attr(textSvgEl, 'x', x);\n    attr(textSvgEl, 'y', y);\n\n    bindStyle(textSvgEl, style, true, el);\n    if (el instanceof Text || el.style.transformText) {\n        // Transform text with element\n        setTransform(textSvgEl, el.transform);\n    }\n    else {\n        if (el.transform) {\n            tmpRect$3.copy(rect);\n            tmpRect$3.applyTransform(el.transform);\n            rect = tmpRect$3;\n        }\n        else {\n            var pos = el.transformCoordToGlobal(rect.x, rect.y);\n            rect.x = pos[0];\n            rect.y = pos[1];\n            el.transform = identity(create$1());\n        }\n\n        // Text rotation, but no element transform\n        var origin = style.textOrigin;\n        if (origin === 'center') {\n            x = textRect.width / 2 + x;\n            y = textRect.height / 2 + y;\n        }\n        else if (origin) {\n            x = origin[0] + x;\n            y = origin[1] + y;\n        }\n        var rotate$$1 = -style.textRotation || 0;\n        var transform = create$1();\n        // Apply textRotate to element matrix\n        rotate(transform, transform, rotate$$1);\n\n        var pos = [el.transform[4], el.transform[5]];\n        translate(transform, transform, pos);\n        setTransform(textSvgEl, transform);\n    }\n\n    var textLines = text.split('\\n');\n    var nTextLines = textLines.length;\n    var textAnchor = align;\n    // PENDING\n    if (textAnchor === 'left') {\n        textAnchor = 'start';\n        textPadding && (x += textPadding[3]);\n    }\n    else if (textAnchor === 'right') {\n        textAnchor = 'end';\n        textPadding && (x -= textPadding[1]);\n    }\n    else if (textAnchor === 'center') {\n        textAnchor = 'middle';\n        textPadding && (x += (textPadding[3] - textPadding[1]) / 2);\n    }\n\n    var dy = 0;\n    if (verticalAlign === 'after-edge') {\n        dy = -textRect.height + lineHeight;\n        textPadding && (dy -= textPadding[2]);\n    }\n    else if (verticalAlign === 'middle') {\n        dy = (-textRect.height + lineHeight) / 2;\n        textPadding && (y += (textPadding[0] - textPadding[2]) / 2);\n    }\n    else {\n        textPadding && (dy += textPadding[0]);\n    }\n\n    // Font may affect position of each tspan elements\n    if (el.__text !== text || el.__textFont !== font) {\n        var tspanList = el.__tspanList || [];\n        el.__tspanList = tspanList;\n        for (var i = 0; i < nTextLines; i++) {\n            // Using cached tspan elements\n            var tspan = tspanList[i];\n            if (!tspan) {\n                tspan = tspanList[i] = createElement('tspan');\n                textSvgEl.appendChild(tspan);\n                attr(tspan, 'alignment-baseline', verticalAlign);\n                attr(tspan, 'text-anchor', textAnchor);\n            }\n            else {\n                tspan.innerHTML = '';\n            }\n            attr(tspan, 'x', x);\n            attr(tspan, 'y', y + i * lineHeight + dy);\n            tspan.appendChild(document.createTextNode(textLines[i]));\n        }\n        // Remove unsed tspan elements\n        for (; i < tspanList.length; i++) {\n            textSvgEl.removeChild(tspanList[i]);\n        }\n        tspanList.length = nTextLines;\n\n        el.__text = text;\n        el.__textFont = font;\n    }\n    else if (el.__tspanList.length) {\n        // Update span x and y\n        var len = el.__tspanList.length;\n        for (var i = 0; i < len; ++i) {\n            var tspan = el.__tspanList[i];\n            if (tspan) {\n                attr(tspan, 'x', x);\n                attr(tspan, 'y', y + i * lineHeight + dy);\n            }\n        }\n    }\n};\n\nfunction getVerticalAlignForSvg(verticalAlign) {\n    if (verticalAlign === 'middle') {\n        return 'middle';\n    }\n    else if (verticalAlign === 'bottom') {\n        return 'after-edge';\n    }\n    else {\n        return 'hanging';\n    }\n}\n\nsvgText.drawRectText = svgTextDrawRectText;\n\nsvgText.brush = function (el) {\n    var style = el.style;\n    if (style.text != null) {\n        // 强制设置 textPosition\n        style.textPosition = [0, 0];\n        svgTextDrawRectText(el, {\n            x: style.x || 0, y: style.y || 0,\n            width: 0, height: 0\n        }, el.getBoundingRect());\n    }\n};\n\n// Myers' Diff Algorithm\n// Modified from https://github.com/kpdecker/jsdiff/blob/master/src/diff/base.js\n\nfunction Diff() {}\n\nDiff.prototype = {\n    diff: function (oldArr, newArr, equals) {\n        if (!equals) {\n            equals = function (a, b) {\n                return a === b;\n            };\n        }\n        this.equals = equals;\n\n        var self = this;\n\n        oldArr = oldArr.slice();\n        newArr = newArr.slice();\n        // Allow subclasses to massage the input prior to running\n        var newLen = newArr.length;\n        var oldLen = oldArr.length;\n        var editLength = 1;\n        var maxEditLength = newLen + oldLen;\n        var bestPath = [{ newPos: -1, components: [] }];\n\n        // Seed editLength = 0, i.e. the content starts with the same values\n        var oldPos = this.extractCommon(bestPath[0], newArr, oldArr, 0);\n        if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) {\n            var indices = [];\n            for (var i = 0; i < newArr.length; i++) {\n                indices.push(i);\n            }\n            // Identity per the equality and tokenizer\n            return [{\n                indices: indices, count: newArr.length\n            }];\n        }\n\n        // Main worker method. checks all permutations of a given edit length for acceptance.\n        function execEditLength() {\n            for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) {\n                var basePath;\n                var addPath = bestPath[diagonalPath - 1];\n                var removePath = bestPath[diagonalPath + 1];\n                var oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;\n                if (addPath) {\n                    // No one else is going to attempt to use this value, clear it\n                    bestPath[diagonalPath - 1] = undefined;\n                }\n\n                var canAdd = addPath && addPath.newPos + 1 < newLen;\n                var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;\n                if (!canAdd && !canRemove) {\n                    // If this path is a terminal then prune\n                    bestPath[diagonalPath] = undefined;\n                    continue;\n                }\n\n                // Select the diagonal that we want to branch from. We select the prior\n                // path whose position in the new string is the farthest from the origin\n                // and does not pass the bounds of the diff graph\n                if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {\n                    basePath = clonePath(removePath);\n                    self.pushComponent(basePath.components, undefined, true);\n                }\n                else {\n                    basePath = addPath;   // No need to clone, we've pulled it from the list\n                    basePath.newPos++;\n                    self.pushComponent(basePath.components, true, undefined);\n                }\n\n                oldPos = self.extractCommon(basePath, newArr, oldArr, diagonalPath);\n\n                // If we have hit the end of both strings, then we are done\n                if (basePath.newPos + 1 >= newLen && oldPos + 1 >= oldLen) {\n                    return buildValues(self, basePath.components, newArr, oldArr);\n                }\n                else {\n                    // Otherwise track this path as a potential candidate and continue.\n                    bestPath[diagonalPath] = basePath;\n                }\n            }\n\n            editLength++;\n        }\n\n        while (editLength <= maxEditLength) {\n            var ret = execEditLength();\n            if (ret) {\n                return ret;\n            }\n        }\n    },\n\n    pushComponent: function (components, added, removed) {\n        var last = components[components.length - 1];\n        if (last && last.added === added && last.removed === removed) {\n            // We need to clone here as the component clone operation is just\n            // as shallow array clone\n            components[components.length - 1] = {count: last.count + 1, added: added, removed: removed };\n        }\n        else {\n            components.push({count: 1, added: added, removed: removed });\n        }\n    },\n    extractCommon: function (basePath, newArr, oldArr, diagonalPath) {\n        var newLen = newArr.length;\n        var oldLen = oldArr.length;\n        var newPos = basePath.newPos;\n        var oldPos = newPos - diagonalPath;\n        var commonCount = 0;\n\n        while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newArr[newPos + 1], oldArr[oldPos + 1])) {\n            newPos++;\n            oldPos++;\n            commonCount++;\n        }\n\n        if (commonCount) {\n            basePath.components.push({count: commonCount});\n        }\n\n        basePath.newPos = newPos;\n        return oldPos;\n    },\n    tokenize: function (value) {\n        return value.slice();\n    },\n    join: function (value) {\n        return value.slice();\n    }\n};\n\nfunction buildValues(diff, components, newArr, oldArr) {\n    var componentPos = 0;\n    var componentLen = components.length;\n    var newPos = 0;\n    var oldPos = 0;\n\n    for (; componentPos < componentLen; componentPos++) {\n        var component = components[componentPos];\n        if (!component.removed) {\n            var indices = [];\n            for (var i = newPos; i < newPos + component.count; i++) {\n                indices.push(i);\n            }\n            component.indices = indices;\n            newPos += component.count;\n            // Common case\n            if (!component.added) {\n                oldPos += component.count;\n            }\n        }\n        else {\n            var indices = [];\n            for (var i = oldPos; i < oldPos + component.count; i++) {\n                indices.push(i);\n            }\n            component.indices = indices;\n            oldPos += component.count;\n        }\n    }\n\n    return components;\n}\n\nfunction clonePath(path) {\n    return { newPos: path.newPos, components: path.components.slice(0) };\n}\n\nvar arrayDiff = new Diff();\n\nvar arrayDiff$1 = function (oldArr, newArr, callback) {\n    return arrayDiff.diff(oldArr, newArr, callback);\n};\n\n/**\n * @file Manages elements that can be defined in <defs> in SVG,\n *       e.g., gradients, clip path, etc.\n * @author Zhang Wenli\n */\n\nvar MARK_UNUSED = '0';\nvar MARK_USED = '1';\n\n/**\n * Manages elements that can be defined in <defs> in SVG,\n * e.g., gradients, clip path, etc.\n *\n * @class\n * @param {number}          zrId      zrender instance id\n * @param {SVGElement}      svgRoot   root of SVG document\n * @param {string|string[]} tagNames  possible tag names\n * @param {string}          markLabel label name to make if the element\n *                                    is used\n */\nfunction Definable(\n    zrId,\n    svgRoot,\n    tagNames,\n    markLabel,\n    domName\n) {\n    this._zrId = zrId;\n    this._svgRoot = svgRoot;\n    this._tagNames = typeof tagNames === 'string' ? [tagNames] : tagNames;\n    this._markLabel = markLabel;\n    this._domName = domName || '_dom';\n\n    this.nextId = 0;\n}\n\n\nDefinable.prototype.createElement = createElement;\n\n\n/**\n * Get the <defs> tag for svgRoot; optionally creates one if not exists.\n *\n * @param {boolean} isForceCreating if need to create when not exists\n * @return {SVGDefsElement} SVG <defs> element, null if it doesn't\n * exist and isForceCreating is false\n */\nDefinable.prototype.getDefs = function (isForceCreating) {\n    var svgRoot = this._svgRoot;\n    var defs = this._svgRoot.getElementsByTagName('defs');\n    if (defs.length === 0) {\n        // Not exist\n        if (isForceCreating) {\n            defs = svgRoot.insertBefore(\n                this.createElement('defs'), // Create new tag\n                svgRoot.firstChild // Insert in the front of svg\n            );\n            if (!defs.contains) {\n                // IE doesn't support contains method\n                defs.contains = function (el) {\n                    var children = defs.children;\n                    if (!children) {\n                        return false;\n                    }\n                    for (var i = children.length - 1; i >= 0; --i) {\n                        if (children[i] === el) {\n                            return true;\n                        }\n                    }\n                    return false;\n                };\n            }\n            return defs;\n        }\n        else {\n            return null;\n        }\n    }\n    else {\n        return defs[0];\n    }\n};\n\n\n/**\n * Update DOM element if necessary.\n *\n * @param {Object|string} element style element. e.g., for gradient,\n *                                it may be '#ccc' or {type: 'linear', ...}\n * @param {Function|undefined} onUpdate update callback\n */\nDefinable.prototype.update = function (element, onUpdate) {\n    if (!element) {\n        return;\n    }\n\n    var defs = this.getDefs(false);\n    if (element[this._domName] && defs.contains(element[this._domName])) {\n        // Update DOM\n        if (typeof onUpdate === 'function') {\n            onUpdate(element);\n        }\n    }\n    else {\n        // No previous dom, create new\n        var dom = this.add(element);\n        if (dom) {\n            element[this._domName] = dom;\n        }\n    }\n};\n\n\n/**\n * Add gradient dom to defs\n *\n * @param {SVGElement} dom DOM to be added to <defs>\n */\nDefinable.prototype.addDom = function (dom) {\n    var defs = this.getDefs(true);\n    defs.appendChild(dom);\n};\n\n\n/**\n * Remove DOM of a given element.\n *\n * @param {SVGElement} element element to remove dom\n */\nDefinable.prototype.removeDom = function (element) {\n    var defs = this.getDefs(false);\n    if (defs && element[this._domName]) {\n        defs.removeChild(element[this._domName]);\n        element[this._domName] = null;\n    }\n};\n\n\n/**\n * Get DOMs of this element.\n *\n * @return {HTMLDomElement} doms of this defineable elements in <defs>\n */\nDefinable.prototype.getDoms = function () {\n    var defs = this.getDefs(false);\n    if (!defs) {\n        // No dom when defs is not defined\n        return [];\n    }\n\n    var doms = [];\n    each$1(this._tagNames, function (tagName) {\n        var tags = defs.getElementsByTagName(tagName);\n        // Note that tags is HTMLCollection, which is array-like\n        // rather than real array.\n        // So `doms.concat(tags)` add tags as one object.\n        doms = doms.concat([].slice.call(tags));\n    });\n\n    return doms;\n};\n\n\n/**\n * Mark DOMs to be unused before painting, and clear unused ones at the end\n * of the painting.\n */\nDefinable.prototype.markAllUnused = function () {\n    var doms = this.getDoms();\n    var that = this;\n    each$1(doms, function (dom) {\n        dom[that._markLabel] = MARK_UNUSED;\n    });\n};\n\n\n/**\n * Mark a single DOM to be used.\n *\n * @param {SVGElement} dom DOM to mark\n */\nDefinable.prototype.markUsed = function (dom) {\n    if (dom) {\n        dom[this._markLabel] = MARK_USED;\n    }\n};\n\n\n/**\n * Remove unused DOMs defined in <defs>\n */\nDefinable.prototype.removeUnused = function () {\n    var defs = this.getDefs(false);\n    if (!defs) {\n        // Nothing to remove\n        return;\n    }\n\n    var doms = this.getDoms();\n    var that = this;\n    each$1(doms, function (dom) {\n        if (dom[that._markLabel] !== MARK_USED) {\n            // Remove gradient\n            defs.removeChild(dom);\n        }\n    });\n};\n\n\n/**\n * Get SVG proxy.\n *\n * @param {Displayable} displayable displayable element\n * @return {Path|Image|Text} svg proxy of given element\n */\nDefinable.prototype.getSvgProxy = function (displayable) {\n    if (displayable instanceof Path) {\n        return svgPath;\n    }\n    else if (displayable instanceof ZImage) {\n        return svgImage;\n    }\n    else if (displayable instanceof Text) {\n        return svgText;\n    }\n    else {\n        return svgPath;\n    }\n};\n\n\n/**\n * Get text SVG element.\n *\n * @param {Displayable} displayable displayable element\n * @return {SVGElement} SVG element of text\n */\nDefinable.prototype.getTextSvgElement = function (displayable) {\n    return displayable.__textSvgEl;\n};\n\n\n/**\n * Get SVG element.\n *\n * @param {Displayable} displayable displayable element\n * @return {SVGElement} SVG element\n */\nDefinable.prototype.getSvgElement = function (displayable) {\n    return displayable.__svgEl;\n};\n\n/**\n * @file Manages SVG gradient elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG gradient elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction GradientManager(zrId, svgRoot) {\n    Definable.call(\n        this,\n        zrId,\n        svgRoot,\n        ['linearGradient', 'radialGradient'],\n        '__gradient_in_use__'\n    );\n}\n\n\ninherits(GradientManager, Definable);\n\n\n/**\n * Create new gradient DOM for fill or stroke if not exist,\n * but will not update gradient if exists.\n *\n * @param {SvgElement}  svgElement   SVG element to paint\n * @param {Displayable} displayable  zrender displayable element\n */\nGradientManager.prototype.addWithoutUpdate = function (\n    svgElement,\n    displayable\n) {\n    if (displayable && displayable.style) {\n        var that = this;\n        each$1(['fill', 'stroke'], function (fillOrStroke) {\n            if (displayable.style[fillOrStroke]\n                && (displayable.style[fillOrStroke].type === 'linear'\n                || displayable.style[fillOrStroke].type === 'radial')\n            ) {\n                var gradient = displayable.style[fillOrStroke];\n                var defs = that.getDefs(true);\n\n                // Create dom in <defs> if not exists\n                var dom;\n                if (gradient._dom) {\n                    // Gradient exists\n                    dom = gradient._dom;\n                    if (!defs.contains(gradient._dom)) {\n                        // _dom is no longer in defs, recreate\n                        that.addDom(dom);\n                    }\n                }\n                else {\n                    // New dom\n                    dom = that.add(gradient);\n                }\n\n                that.markUsed(displayable);\n\n                var id = dom.getAttribute('id');\n                svgElement.setAttribute(fillOrStroke, 'url(#' + id + ')');\n            }\n        });\n    }\n};\n\n\n/**\n * Add a new gradient tag in <defs>\n *\n * @param   {Gradient} gradient zr gradient instance\n * @return {SVGLinearGradientElement | SVGRadialGradientElement}\n *                            created DOM\n */\nGradientManager.prototype.add = function (gradient) {\n    var dom;\n    if (gradient.type === 'linear') {\n        dom = this.createElement('linearGradient');\n    }\n    else if (gradient.type === 'radial') {\n        dom = this.createElement('radialGradient');\n    }\n    else {\n        zrLog('Illegal gradient type.');\n        return null;\n    }\n\n    // Set dom id with gradient id, since each gradient instance\n    // will have no more than one dom element.\n    // id may exists before for those dirty elements, in which case\n    // id should remain the same, and other attributes should be\n    // updated.\n    gradient.id = gradient.id || this.nextId++;\n    dom.setAttribute('id', 'zr' + this._zrId\n        + '-gradient-' + gradient.id);\n\n    this.updateDom(gradient, dom);\n    this.addDom(dom);\n\n    return dom;\n};\n\n\n/**\n * Update gradient.\n *\n * @param {Gradient} gradient zr gradient instance\n */\nGradientManager.prototype.update = function (gradient) {\n    var that = this;\n    Definable.prototype.update.call(this, gradient, function () {\n        var type = gradient.type;\n        var tagName = gradient._dom.tagName;\n        if (type === 'linear' && tagName === 'linearGradient'\n            || type === 'radial' && tagName === 'radialGradient'\n        ) {\n            // Gradient type is not changed, update gradient\n            that.updateDom(gradient, gradient._dom);\n        }\n        else {\n            // Remove and re-create if type is changed\n            that.removeDom(gradient);\n            that.add(gradient);\n        }\n    });\n};\n\n\n/**\n * Update gradient dom\n *\n * @param {Gradient} gradient zr gradient instance\n * @param {SVGLinearGradientElement | SVGRadialGradientElement} dom\n *                            DOM to update\n */\nGradientManager.prototype.updateDom = function (gradient, dom) {\n    if (gradient.type === 'linear') {\n        dom.setAttribute('x1', gradient.x);\n        dom.setAttribute('y1', gradient.y);\n        dom.setAttribute('x2', gradient.x2);\n        dom.setAttribute('y2', gradient.y2);\n    }\n    else if (gradient.type === 'radial') {\n        dom.setAttribute('cx', gradient.x);\n        dom.setAttribute('cy', gradient.y);\n        dom.setAttribute('r', gradient.r);\n    }\n    else {\n        zrLog('Illegal gradient type.');\n        return;\n    }\n\n    if (gradient.global) {\n        // x1, x2, y1, y2 in range of 0 to canvas width or height\n        dom.setAttribute('gradientUnits', 'userSpaceOnUse');\n    }\n    else {\n        // x1, x2, y1, y2 in range of 0 to 1\n        dom.setAttribute('gradientUnits', 'objectBoundingBox');\n    }\n\n    // Remove color stops if exists\n    dom.innerHTML = '';\n\n    // Add color stops\n    var colors = gradient.colorStops;\n    for (var i = 0, len = colors.length; i < len; ++i) {\n        var stop = this.createElement('stop');\n        stop.setAttribute('offset', colors[i].offset * 100 + '%');\n\n        var color = colors[i].color;\n        if (color.indexOf('rgba' > -1)) {\n            // Fix Safari bug that stop-color not recognizing alpha #9014\n            var opacity = parse(color)[3];\n            var hex = toHex(color);\n\n            // stop-color cannot be color, since:\n            // The opacity value used for the gradient calculation is the\n            // *product* of the value of stop-opacity and the opacity of the\n            // value of stop-color.\n            // See https://www.w3.org/TR/SVG2/pservers.html#StopOpacityProperty\n            stop.setAttribute('stop-color', '#' + hex);\n            stop.setAttribute('stop-opacity', opacity);\n        }\n        else {\n            stop.setAttribute('stop-color', colors[i].color);\n        }\n\n        dom.appendChild(stop);\n    }\n\n    // Store dom element in gradient, to avoid creating multiple\n    // dom instances for the same gradient element\n    gradient._dom = dom;\n};\n\n/**\n * Mark a single gradient to be used\n *\n * @param {Displayable} displayable displayable element\n */\nGradientManager.prototype.markUsed = function (displayable) {\n    if (displayable.style) {\n        var gradient = displayable.style.fill;\n        if (gradient && gradient._dom) {\n            Definable.prototype.markUsed.call(this, gradient._dom);\n        }\n\n        gradient = displayable.style.stroke;\n        if (gradient && gradient._dom) {\n            Definable.prototype.markUsed.call(this, gradient._dom);\n        }\n    }\n};\n\n/**\n * @file Manages SVG clipPath elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG clipPath elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction ClippathManager(zrId, svgRoot) {\n    Definable.call(this, zrId, svgRoot, 'clipPath', '__clippath_in_use__');\n}\n\n\ninherits(ClippathManager, Definable);\n\n\n/**\n * Update clipPath.\n *\n * @param {Displayable} displayable displayable element\n */\nClippathManager.prototype.update = function (displayable) {\n    var svgEl = this.getSvgElement(displayable);\n    if (svgEl) {\n        this.updateDom(svgEl, displayable.__clipPaths, false);\n    }\n\n    var textEl = this.getTextSvgElement(displayable);\n    if (textEl) {\n        // Make another clipPath for text, since it's transform\n        // matrix is not the same with svgElement\n        this.updateDom(textEl, displayable.__clipPaths, true);\n    }\n\n    this.markUsed(displayable);\n};\n\n\n/**\n * Create an SVGElement of displayable and create a <clipPath> of its\n * clipPath\n *\n * @param {Displayable} parentEl  parent element\n * @param {ClipPath[]}  clipPaths clipPaths of parent element\n * @param {boolean}     isText    if parent element is Text\n */\nClippathManager.prototype.updateDom = function (\n    parentEl,\n    clipPaths,\n    isText\n) {\n    if (clipPaths && clipPaths.length > 0) {\n        // Has clipPath, create <clipPath> with the first clipPath\n        var defs = this.getDefs(true);\n        var clipPath = clipPaths[0];\n        var clipPathEl;\n        var id;\n\n        var dom = isText ? '_textDom' : '_dom';\n\n        if (clipPath[dom]) {\n            // Use a dom that is already in <defs>\n            id = clipPath[dom].getAttribute('id');\n            clipPathEl = clipPath[dom];\n\n            // Use a dom that is already in <defs>\n            if (!defs.contains(clipPathEl)) {\n                // This happens when set old clipPath that has\n                // been previously removed\n                defs.appendChild(clipPathEl);\n            }\n        }\n        else {\n            // New <clipPath>\n            id = 'zr' + this._zrId + '-clip-' + this.nextId;\n            ++this.nextId;\n            clipPathEl = this.createElement('clipPath');\n            clipPathEl.setAttribute('id', id);\n            defs.appendChild(clipPathEl);\n\n            clipPath[dom] = clipPathEl;\n        }\n\n        // Build path and add to <clipPath>\n        var svgProxy = this.getSvgProxy(clipPath);\n        if (clipPath.transform\n            && clipPath.parent.invTransform\n            && !isText\n        ) {\n            /**\n             * If a clipPath has a parent with transform, the transform\n             * of parent should not be considered when setting transform\n             * of clipPath. So we need to transform back from parent's\n             * transform, which is done by multiplying parent's inverse\n             * transform.\n             */\n            // Store old transform\n            var transform = Array.prototype.slice.call(\n                clipPath.transform\n            );\n\n            // Transform back from parent, and brush path\n            mul$1(\n                clipPath.transform,\n                clipPath.parent.invTransform,\n                clipPath.transform\n            );\n            svgProxy.brush(clipPath);\n\n            // Set back transform of clipPath\n            clipPath.transform = transform;\n        }\n        else {\n            svgProxy.brush(clipPath);\n        }\n\n        var pathEl = this.getSvgElement(clipPath);\n\n        clipPathEl.innerHTML = '';\n        /**\n         * Use `cloneNode()` here to appendChild to multiple parents,\n         * which may happend when Text and other shapes are using the same\n         * clipPath. Since Text will create an extra clipPath DOM due to\n         * different transform rules.\n         */\n        clipPathEl.appendChild(pathEl.cloneNode());\n\n        parentEl.setAttribute('clip-path', 'url(#' + id + ')');\n\n        if (clipPaths.length > 1) {\n            // Make the other clipPaths recursively\n            this.updateDom(clipPathEl, clipPaths.slice(1), isText);\n        }\n    }\n    else {\n        // No clipPath\n        if (parentEl) {\n            parentEl.setAttribute('clip-path', 'none');\n        }\n    }\n};\n\n/**\n * Mark a single clipPath to be used\n *\n * @param {Displayable} displayable displayable element\n */\nClippathManager.prototype.markUsed = function (displayable) {\n    var that = this;\n    if (displayable.__clipPaths && displayable.__clipPaths.length > 0) {\n        each$1(displayable.__clipPaths, function (clipPath) {\n            if (clipPath._dom) {\n                Definable.prototype.markUsed.call(that, clipPath._dom);\n            }\n            if (clipPath._textDom) {\n                Definable.prototype.markUsed.call(that, clipPath._textDom);\n            }\n        });\n    }\n};\n\n/**\n * @file Manages SVG shadow elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG shadow elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction ShadowManager(zrId, svgRoot) {\n    Definable.call(\n        this,\n        zrId,\n        svgRoot,\n        ['filter'],\n        '__filter_in_use__',\n        '_shadowDom'\n    );\n}\n\n\ninherits(ShadowManager, Definable);\n\n\n/**\n * Create new shadow DOM for fill or stroke if not exist,\n * but will not update shadow if exists.\n *\n * @param {SvgElement}  svgElement   SVG element to paint\n * @param {Displayable} displayable  zrender displayable element\n */\nShadowManager.prototype.addWithoutUpdate = function (\n    svgElement,\n    displayable\n) {\n    if (displayable && hasShadow(displayable.style)) {\n        var style = displayable.style;\n\n        // Create dom in <defs> if not exists\n        var dom;\n        if (style._shadowDom) {\n            // Gradient exists\n            dom = style._shadowDom;\n\n            var defs = this.getDefs(true);\n            if (!defs.contains(style._shadowDom)) {\n                // _shadowDom is no longer in defs, recreate\n                this.addDom(dom);\n            }\n        }\n        else {\n            // New dom\n            dom = this.add(displayable);\n        }\n\n        this.markUsed(displayable);\n\n        var id = dom.getAttribute('id');\n        svgElement.style.filter = 'url(#' + id + ')';\n    }\n};\n\n\n/**\n * Add a new shadow tag in <defs>\n *\n * @param {Displayable} displayable  zrender displayable element\n * @return {SVGFilterElement} created DOM\n */\nShadowManager.prototype.add = function (displayable) {\n    var dom = this.createElement('filter');\n    var style = displayable.style;\n\n    // Set dom id with shadow id, since each shadow instance\n    // will have no more than one dom element.\n    // id may exists before for those dirty elements, in which case\n    // id should remain the same, and other attributes should be\n    // updated.\n    style._shadowDomId = style._shadowDomId || this.nextId++;\n    dom.setAttribute('id', 'zr' + this._zrId\n        + '-shadow-' + style._shadowDomId);\n\n    this.updateDom(displayable, dom);\n    this.addDom(dom);\n\n    return dom;\n};\n\n\n/**\n * Update shadow.\n *\n * @param {Displayable} displayable  zrender displayable element\n */\nShadowManager.prototype.update = function (svgElement, displayable) {\n    var style = displayable.style;\n    if (hasShadow(style)) {\n        var that = this;\n        Definable.prototype.update.call(this, displayable, function (style) {\n            that.updateDom(displayable, style._shadowDom);\n        });\n    }\n    else {\n        // Remove shadow\n        this.remove(svgElement, style);\n    }\n};\n\n\n/**\n * Remove DOM and clear parent filter\n */\nShadowManager.prototype.remove = function (svgElement, style) {\n    if (style._shadowDomId != null) {\n        this.removeDom(style);\n        svgElement.style.filter = '';\n    }\n};\n\n\n/**\n * Update shadow dom\n *\n * @param {Displayable} displayable  zrender displayable element\n * @param {SVGFilterElement} dom DOM to update\n */\nShadowManager.prototype.updateDom = function (displayable, dom) {\n    var domChild = dom.getElementsByTagName('feDropShadow');\n    if (domChild.length === 0) {\n        domChild = this.createElement('feDropShadow');\n    }\n    else {\n        domChild = domChild[0];\n    }\n\n    var style = displayable.style;\n    var scaleX = displayable.scale ? (displayable.scale[0] || 1) : 1;\n    var scaleY = displayable.scale ? (displayable.scale[1] || 1) : 1;\n\n    // TODO: textBoxShadowBlur is not supported yet\n    var offsetX, offsetY, blur, color;\n    if (style.shadowBlur || style.shadowOffsetX || style.shadowOffsetY) {\n        offsetX = style.shadowOffsetX || 0;\n        offsetY = style.shadowOffsetY || 0;\n        blur = style.shadowBlur;\n        color = style.shadowColor;\n    }\n    else if (style.textShadowBlur) {\n        offsetX = style.textShadowOffsetX || 0;\n        offsetY = style.textShadowOffsetY || 0;\n        blur = style.textShadowBlur;\n        color = style.textShadowColor;\n    }\n    else {\n        // Remove shadow\n        this.removeDom(dom, style);\n        return;\n    }\n\n    domChild.setAttribute('dx', offsetX / scaleX);\n    domChild.setAttribute('dy', offsetY / scaleY);\n    domChild.setAttribute('flood-color', color);\n\n    // Divide by two here so that it looks the same as in canvas\n    // See: https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-shadowblur\n    var stdDx = blur / 2 / scaleX;\n    var stdDy = blur / 2 / scaleY;\n    var stdDeviation = stdDx + ' ' + stdDy;\n    domChild.setAttribute('stdDeviation', stdDeviation);\n\n    // Fix filter clipping problem\n    dom.setAttribute('x', '-100%');\n    dom.setAttribute('y', '-100%');\n    dom.setAttribute('width', Math.ceil(blur / 2 * 200) + '%');\n    dom.setAttribute('height', Math.ceil(blur / 2 * 200) + '%');\n\n    dom.appendChild(domChild);\n\n    // Store dom element in shadow, to avoid creating multiple\n    // dom instances for the same shadow element\n    style._shadowDom = dom;\n};\n\n/**\n * Mark a single shadow to be used\n *\n * @param {Displayable} displayable displayable element\n */\nShadowManager.prototype.markUsed = function (displayable) {\n    var style = displayable.style;\n    if (style && style._shadowDom) {\n        Definable.prototype.markUsed.call(this, style._shadowDom);\n    }\n};\n\nfunction hasShadow(style) {\n    // TODO: textBoxShadowBlur is not supported yet\n    return style\n        && (style.shadowBlur || style.shadowOffsetX || style.shadowOffsetY\n            || style.textShadowBlur || style.textShadowOffsetX\n            || style.textShadowOffsetY);\n}\n\n/**\n * SVG Painter\n * @module zrender/svg/Painter\n */\n\nfunction parseInt10$2(val) {\n    return parseInt(val, 10);\n}\n\nfunction getSvgProxy(el) {\n    if (el instanceof Path) {\n        return svgPath;\n    }\n    else if (el instanceof ZImage) {\n        return svgImage;\n    }\n    else if (el instanceof Text) {\n        return svgText;\n    }\n    else {\n        return svgPath;\n    }\n}\n\nfunction checkParentAvailable(parent, child) {\n    return child && parent && child.parentNode !== parent;\n}\n\nfunction insertAfter(parent, child, prevSibling) {\n    if (checkParentAvailable(parent, child) && prevSibling) {\n        var nextSibling = prevSibling.nextSibling;\n        nextSibling ? parent.insertBefore(child, nextSibling)\n            : parent.appendChild(child);\n    }\n}\n\nfunction prepend(parent, child) {\n    if (checkParentAvailable(parent, child)) {\n        var firstChild = parent.firstChild;\n        firstChild ? parent.insertBefore(child, firstChild)\n            : parent.appendChild(child);\n    }\n}\n\nfunction remove$1(parent, child) {\n    if (child && parent && child.parentNode === parent) {\n        parent.removeChild(child);\n    }\n}\n\nfunction getTextSvgElement(displayable) {\n    return displayable.__textSvgEl;\n}\n\nfunction getSvgElement(displayable) {\n    return displayable.__svgEl;\n}\n\n/**\n * @alias module:zrender/svg/Painter\n * @constructor\n * @param {HTMLElement} root 绘图容器\n * @param {module:zrender/Storage} storage\n * @param {Object} opts\n */\nvar SVGPainter = function (root, storage, opts, zrId) {\n\n    this.root = root;\n    this.storage = storage;\n    this._opts = opts = extend({}, opts || {});\n\n    var svgRoot = createElement('svg');\n    svgRoot.setAttribute('xmlns', 'http://www.w3.org/2000/svg');\n    svgRoot.setAttribute('version', '1.1');\n    svgRoot.setAttribute('baseProfile', 'full');\n    svgRoot.style.cssText = 'user-select:none;position:absolute;left:0;top:0;';\n\n    this.gradientManager = new GradientManager(zrId, svgRoot);\n    this.clipPathManager = new ClippathManager(zrId, svgRoot);\n    this.shadowManager = new ShadowManager(zrId, svgRoot);\n\n    var viewport = document.createElement('div');\n    viewport.style.cssText = 'overflow:hidden;position:relative';\n\n    this._svgRoot = svgRoot;\n    this._viewport = viewport;\n\n    root.appendChild(viewport);\n    viewport.appendChild(svgRoot);\n\n    this.resize(opts.width, opts.height);\n\n    this._visibleList = [];\n};\n\nSVGPainter.prototype = {\n\n    constructor: SVGPainter,\n\n    getType: function () {\n        return 'svg';\n    },\n\n    getViewportRoot: function () {\n        return this._viewport;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    refresh: function () {\n\n        var list = this.storage.getDisplayList(true);\n\n        this._paintList(list);\n    },\n\n    setBackgroundColor: function (backgroundColor) {\n        // TODO gradient\n        this._viewport.style.background = backgroundColor;\n    },\n\n    _paintList: function (list) {\n        this.gradientManager.markAllUnused();\n        this.clipPathManager.markAllUnused();\n        this.shadowManager.markAllUnused();\n\n        var svgRoot = this._svgRoot;\n        var visibleList = this._visibleList;\n        var listLen = list.length;\n\n        var newVisibleList = [];\n        var i;\n        for (i = 0; i < listLen; i++) {\n            var displayable = list[i];\n            var svgProxy = getSvgProxy(displayable);\n            var svgElement = getSvgElement(displayable)\n                || getTextSvgElement(displayable);\n            if (!displayable.invisible) {\n                if (displayable.__dirty) {\n                    svgProxy && svgProxy.brush(displayable);\n\n                    // Update clipPath\n                    this.clipPathManager.update(displayable);\n\n                    // Update gradient and shadow\n                    if (displayable.style) {\n                        this.gradientManager\n                            .update(displayable.style.fill);\n                        this.gradientManager\n                            .update(displayable.style.stroke);\n\n                        this.shadowManager\n                            .update(svgElement, displayable);\n                    }\n\n                    displayable.__dirty = false;\n                }\n                newVisibleList.push(displayable);\n            }\n        }\n\n        var diff = arrayDiff$1(visibleList, newVisibleList);\n        var prevSvgElement;\n\n        // First do remove, in case element moved to the head and do remove\n        // after add\n        for (i = 0; i < diff.length; i++) {\n            var item = diff[i];\n            if (item.removed) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = visibleList[item.indices[k]];\n                    var svgElement = getSvgElement(displayable);\n                    var textSvgElement = getTextSvgElement(displayable);\n                    remove$1(svgRoot, svgElement);\n                    remove$1(svgRoot, textSvgElement);\n                }\n            }\n        }\n        for (i = 0; i < diff.length; i++) {\n            var item = diff[i];\n            if (item.added) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = newVisibleList[item.indices[k]];\n                    var svgElement = getSvgElement(displayable);\n                    var textSvgElement = getTextSvgElement(displayable);\n                    prevSvgElement\n                        ? insertAfter(svgRoot, svgElement, prevSvgElement)\n                        : prepend(svgRoot, svgElement);\n                    if (svgElement) {\n                        insertAfter(svgRoot, textSvgElement, svgElement);\n                    }\n                    else if (prevSvgElement) {\n                        insertAfter(\n                            svgRoot, textSvgElement, prevSvgElement\n                        );\n                    }\n                    else {\n                        prepend(svgRoot, textSvgElement);\n                    }\n                    // Insert text\n                    insertAfter(svgRoot, textSvgElement, svgElement);\n                    prevSvgElement = textSvgElement || svgElement\n                        || prevSvgElement;\n\n                    this.gradientManager\n                        .addWithoutUpdate(svgElement, displayable);\n                    this.shadowManager\n                        .addWithoutUpdate(prevSvgElement, displayable);\n                    this.clipPathManager.markUsed(displayable);\n                }\n            }\n            else if (!item.removed) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = newVisibleList[item.indices[k]];\n                    prevSvgElement =\n                        svgElement =\n                        getTextSvgElement(displayable)\n                        || getSvgElement(displayable)\n                        || prevSvgElement;\n\n                    this.gradientManager.markUsed(displayable);\n                    this.gradientManager\n                        .addWithoutUpdate(svgElement, displayable);\n\n                    this.shadowManager.markUsed(displayable);\n                    this.shadowManager\n                        .addWithoutUpdate(svgElement, displayable);\n\n                    this.clipPathManager.markUsed(displayable);\n                }\n            }\n        }\n\n        this.gradientManager.removeUnused();\n        this.clipPathManager.removeUnused();\n        this.shadowManager.removeUnused();\n\n        this._visibleList = newVisibleList;\n    },\n\n    _getDefs: function (isForceCreating) {\n        var svgRoot = this._svgRoot;\n        var defs = this._svgRoot.getElementsByTagName('defs');\n        if (defs.length === 0) {\n            // Not exist\n            if (isForceCreating) {\n                var defs = svgRoot.insertBefore(\n                    createElement('defs'), // Create new tag\n                    svgRoot.firstChild // Insert in the front of svg\n                );\n                if (!defs.contains) {\n                    // IE doesn't support contains method\n                    defs.contains = function (el) {\n                        var children = defs.children;\n                        if (!children) {\n                            return false;\n                        }\n                        for (var i = children.length - 1; i >= 0; --i) {\n                            if (children[i] === el) {\n                                return true;\n                            }\n                        }\n                        return false;\n                    };\n                }\n                return defs;\n            }\n            else {\n                return null;\n            }\n        }\n        else {\n            return defs[0];\n        }\n    },\n\n    resize: function (width, height) {\n        var viewport = this._viewport;\n        // FIXME Why ?\n        viewport.style.display = 'none';\n\n        // Save input w/h\n        var opts = this._opts;\n        width != null && (opts.width = width);\n        height != null && (opts.height = height);\n\n        width = this._getSize(0);\n        height = this._getSize(1);\n\n        viewport.style.display = '';\n\n        if (this._width !== width || this._height !== height) {\n            this._width = width;\n            this._height = height;\n\n            var viewportStyle = viewport.style;\n            viewportStyle.width = width + 'px';\n            viewportStyle.height = height + 'px';\n\n            var svgRoot = this._svgRoot;\n            // Set width by 'svgRoot.width = width' is invalid\n            svgRoot.setAttribute('width', width);\n            svgRoot.setAttribute('height', height);\n        }\n    },\n\n    /**\n     * 获取绘图区域宽度\n     */\n    getWidth: function () {\n        return this._width;\n    },\n\n    /**\n     * 获取绘图区域高度\n     */\n    getHeight: function () {\n        return this._height;\n    },\n\n    _getSize: function (whIdx) {\n        var opts = this._opts;\n        var wh = ['width', 'height'][whIdx];\n        var cwh = ['clientWidth', 'clientHeight'][whIdx];\n        var plt = ['paddingLeft', 'paddingTop'][whIdx];\n        var prb = ['paddingRight', 'paddingBottom'][whIdx];\n\n        if (opts[wh] != null && opts[wh] !== 'auto') {\n            return parseFloat(opts[wh]);\n        }\n\n        var root = this.root;\n        // IE8 does not support getComputedStyle, but it use VML.\n        var stl = document.defaultView.getComputedStyle(root);\n\n        return (\n            (root[cwh] || parseInt10$2(stl[wh]) || parseInt10$2(root.style[wh]))\n            - (parseInt10$2(stl[plt]) || 0)\n            - (parseInt10$2(stl[prb]) || 0)\n        ) | 0;\n    },\n\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this._svgRoot =\n            this._viewport =\n            this.storage =\n            null;\n    },\n\n    clear: function () {\n        if (this._viewport) {\n            this.root.removeChild(this._viewport);\n        }\n    },\n\n    pathToDataUrl: function () {\n        this.refresh();\n        var html = this._svgRoot.outerHTML;\n        return 'data:image/svg+xml;charset=UTF-8,' + html;\n    }\n};\n\n// Not supported methods\nfunction createMethodNotSupport$1(method) {\n    return function () {\n        zrLog('In SVG mode painter not support method \"' + method + '\"');\n    };\n}\n\n// Unsuppoted methods\neach$1([\n    'getLayer', 'insertLayer', 'eachLayer', 'eachBuiltinLayer',\n    'eachOtherLayer', 'getLayers', 'modLayer', 'delLayer', 'clearLayer',\n    'toDataURL', 'pathToImage'\n], function (name) {\n    SVGPainter.prototype[name] = createMethodNotSupport$1(name);\n});\n\nregisterPainter('svg', SVGPainter);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nexports.version = version;\nexports.dependencies = dependencies;\nexports.PRIORITY = PRIORITY;\nexports.init = init;\nexports.connect = connect;\nexports.disConnect = disConnect;\nexports.disconnect = disconnect;\nexports.dispose = dispose;\nexports.getInstanceByDom = getInstanceByDom;\nexports.getInstanceById = getInstanceById;\nexports.registerTheme = registerTheme;\nexports.registerPreprocessor = registerPreprocessor;\nexports.registerProcessor = registerProcessor;\nexports.registerPostUpdate = registerPostUpdate;\nexports.registerAction = registerAction;\nexports.registerCoordinateSystem = registerCoordinateSystem;\nexports.getCoordinateSystemDimensions = getCoordinateSystemDimensions;\nexports.registerLayout = registerLayout;\nexports.registerVisual = registerVisual;\nexports.registerLoading = registerLoading;\nexports.extendComponentModel = extendComponentModel;\nexports.extendComponentView = extendComponentView;\nexports.extendSeriesModel = extendSeriesModel;\nexports.extendChartView = extendChartView;\nexports.setCanvasCreator = setCanvasCreator;\nexports.registerMap = registerMap;\nexports.getMap = getMap;\nexports.dataTool = dataTool;\nexports.zrender = zrender;\nexports.number = number;\nexports.format = format;\nexports.throttle = throttle;\nexports.helper = helper;\nexports.matrix = matrix;\nexports.vector = vector;\nexports.color = color;\nexports.parseGeoJSON = parseGeoJSON;\nexports.parseGeoJson = parseGeoJson;\nexports.util = ecUtil;\nexports.graphic = graphic$1;\nexports.List = List;\nexports.Model = Model;\nexports.Axis = Axis;\nexports.env = env$1;\n\n})));\n"
  },
  {
    "path": "static/js/Echarts/echarts.js",
    "content": "(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n\ttypeof define === 'function' && define.amd ? define(['exports'], factory) :\n\t(factory((global.echarts = {})));\n}(this, (function (exports) { 'use strict';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (1) The code `if (__DEV__) ...` can be removed by build tool.\n// (2) If intend to use `__DEV__`, this module should be imported. Use a global\n// variable `__DEV__` may cause that miss the declaration (see #6535), or the\n// declaration is behind of the using position (for example in `Model.extent`,\n// And tools like rollup can not analysis the dependency if not import).\n\nvar dev;\n\n// In browser\nif (typeof window !== 'undefined') {\n    dev = window.__DEV__;\n}\n// In node\nelse if (typeof global !== 'undefined') {\n    dev = global.__DEV__;\n}\n\nif (typeof dev === 'undefined') {\n    dev = true;\n}\n\nvar __DEV__ = dev;\n\n/**\n * zrender: 生成唯一id\n *\n * @author errorrik (errorrik@gmail.com)\n */\n\nvar idStart = 0x0907;\n\nvar guid = function () {\n    return idStart++;\n};\n\n/**\n * echarts设备环境识别\n *\n * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。\n * @author firede[firede@firede.us]\n * @desc thanks zepto.\n */\n\nvar env = {};\n\nif (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') {\n    // In Weixin Application\n    env = {\n        browser: {},\n        os: {},\n        node: false,\n        wxa: true, // Weixin Application\n        canvasSupported: true,\n        svgSupported: false,\n        touchEventsSupported: true,\n        domSupported: false\n    };\n}\nelse if (typeof document === 'undefined' && typeof self !== 'undefined') {\n    // In worker\n    env = {\n        browser: {},\n        os: {},\n        node: false,\n        worker: true,\n        canvasSupported: true,\n        domSupported: false\n    };\n}\nelse if (typeof navigator === 'undefined') {\n    // In node\n    env = {\n        browser: {},\n        os: {},\n        node: true,\n        worker: false,\n        // Assume canvas is supported\n        canvasSupported: true,\n        svgSupported: true,\n        domSupported: false\n    };\n}\nelse {\n    env = detect(navigator.userAgent);\n}\n\nvar env$1 = env;\n\n// Zepto.js\n// (c) 2010-2013 Thomas Fuchs\n// Zepto.js may be freely distributed under the MIT license.\n\nfunction detect(ua) {\n    var os = {};\n    var browser = {};\n    // var webkit = ua.match(/Web[kK]it[\\/]{0,1}([\\d.]+)/);\n    // var android = ua.match(/(Android);?[\\s\\/]+([\\d.]+)?/);\n    // var ipad = ua.match(/(iPad).*OS\\s([\\d_]+)/);\n    // var ipod = ua.match(/(iPod)(.*OS\\s([\\d_]+))?/);\n    // var iphone = !ipad && ua.match(/(iPhone\\sOS)\\s([\\d_]+)/);\n    // var webos = ua.match(/(webOS|hpwOS)[\\s\\/]([\\d.]+)/);\n    // var touchpad = webos && ua.match(/TouchPad/);\n    // var kindle = ua.match(/Kindle\\/([\\d.]+)/);\n    // var silk = ua.match(/Silk\\/([\\d._]+)/);\n    // var blackberry = ua.match(/(BlackBerry).*Version\\/([\\d.]+)/);\n    // var bb10 = ua.match(/(BB10).*Version\\/([\\d.]+)/);\n    // var rimtabletos = ua.match(/(RIM\\sTablet\\sOS)\\s([\\d.]+)/);\n    // var playbook = ua.match(/PlayBook/);\n    // var chrome = ua.match(/Chrome\\/([\\d.]+)/) || ua.match(/CriOS\\/([\\d.]+)/);\n    var firefox = ua.match(/Firefox\\/([\\d.]+)/);\n    // var safari = webkit && ua.match(/Mobile\\//) && !chrome;\n    // var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome;\n    var ie = ua.match(/MSIE\\s([\\d.]+)/)\n        // IE 11 Trident/7.0; rv:11.0\n        || ua.match(/Trident\\/.+?rv:(([\\d.]+))/);\n    var edge = ua.match(/Edge\\/([\\d.]+)/); // IE 12 and 12+\n\n    var weChat = (/micromessenger/i).test(ua);\n\n    // Todo: clean this up with a better OS/browser seperation:\n    // - discern (more) between multiple browsers on android\n    // - decide if kindle fire in silk mode is android or not\n    // - Firefox on Android doesn't specify the Android version\n    // - possibly devide in os, device and browser hashes\n\n    // if (browser.webkit = !!webkit) browser.version = webkit[1];\n\n    // if (android) os.android = true, os.version = android[2];\n    // if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.');\n    // if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.');\n    // if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null;\n    // if (webos) os.webos = true, os.version = webos[2];\n    // if (touchpad) os.touchpad = true;\n    // if (blackberry) os.blackberry = true, os.version = blackberry[2];\n    // if (bb10) os.bb10 = true, os.version = bb10[2];\n    // if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2];\n    // if (playbook) browser.playbook = true;\n    // if (kindle) os.kindle = true, os.version = kindle[1];\n    // if (silk) browser.silk = true, browser.version = silk[1];\n    // if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true;\n    // if (chrome) browser.chrome = true, browser.version = chrome[1];\n    if (firefox) {\n        browser.firefox = true;\n        browser.version = firefox[1];\n    }\n    // if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true;\n    // if (webview) browser.webview = true;\n\n    if (ie) {\n        browser.ie = true;\n        browser.version = ie[1];\n    }\n\n    if (edge) {\n        browser.edge = true;\n        browser.version = edge[1];\n    }\n\n    // It is difficult to detect WeChat in Win Phone precisely, because ua can\n    // not be set on win phone. So we do not consider Win Phone.\n    if (weChat) {\n        browser.weChat = true;\n    }\n\n    // os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) ||\n    //     (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/)));\n    // os.phone  = !!(!os.tablet && !os.ipod && (android || iphone || webos ||\n    //     (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\\/([\\d.]+)/)) ||\n    //     (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/))));\n\n    return {\n        browser: browser,\n        os: os,\n        node: false,\n        // 原生canvas支持，改极端点了\n        // canvasSupported : !(browser.ie && parseFloat(browser.version) < 9)\n        canvasSupported: !!document.createElement('canvas').getContext,\n        svgSupported: typeof SVGRect !== 'undefined',\n        // works on most browsers\n        // IE10/11 does not support touch event, and MS Edge supports them but not by\n        // default, so we dont check navigator.maxTouchPoints for them here.\n        touchEventsSupported: 'ontouchstart' in window && !browser.ie && !browser.edge,\n        // <http://caniuse.com/#search=pointer%20event>.\n        pointerEventsSupported: 'onpointerdown' in window\n            // Firefox supports pointer but not by default, only MS browsers are reliable on pointer\n            // events currently. So we dont use that on other browsers unless tested sufficiently.\n            // Although IE 10 supports pointer event, it use old style and is different from the\n            // standard. So we exclude that. (IE 10 is hardly used on touch device)\n            && (browser.edge || (browser.ie && browser.version >= 11)),\n        // passiveSupported: detectPassiveSupport()\n        domSupported: typeof document !== 'undefined'\n    };\n}\n\n// See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection\n// function detectPassiveSupport() {\n//     // Test via a getter in the options object to see if the passive property is accessed\n//     var supportsPassive = false;\n//     try {\n//         var opts = Object.defineProperty({}, 'passive', {\n//             get: function() {\n//                 supportsPassive = true;\n//             }\n//         });\n//         window.addEventListener('testPassive', function() {}, opts);\n//     } catch (e) {\n//     }\n//     return supportsPassive;\n// }\n\n/**\n * @module zrender/core/util\n */\n\n// 用于处理merge时无法遍历Date等对象的问题\nvar BUILTIN_OBJECT = {\n    '[object Function]': 1,\n    '[object RegExp]': 1,\n    '[object Date]': 1,\n    '[object Error]': 1,\n    '[object CanvasGradient]': 1,\n    '[object CanvasPattern]': 1,\n    // For node-canvas\n    '[object Image]': 1,\n    '[object Canvas]': 1\n};\n\nvar TYPED_ARRAY = {\n    '[object Int8Array]': 1,\n    '[object Uint8Array]': 1,\n    '[object Uint8ClampedArray]': 1,\n    '[object Int16Array]': 1,\n    '[object Uint16Array]': 1,\n    '[object Int32Array]': 1,\n    '[object Uint32Array]': 1,\n    '[object Float32Array]': 1,\n    '[object Float64Array]': 1\n};\n\nvar objToString = Object.prototype.toString;\n\nvar arrayProto = Array.prototype;\nvar nativeForEach = arrayProto.forEach;\nvar nativeFilter = arrayProto.filter;\nvar nativeSlice = arrayProto.slice;\nvar nativeMap = arrayProto.map;\nvar nativeReduce = arrayProto.reduce;\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar methods = {};\n\nfunction $override(name, fn) {\n    // Clear ctx instance for different environment\n    if (name === 'createCanvas') {\n        _ctx = null;\n    }\n\n    methods[name] = fn;\n}\n\n/**\n * Those data types can be cloned:\n *     Plain object, Array, TypedArray, number, string, null, undefined.\n * Those data types will be assgined using the orginal data:\n *     BUILTIN_OBJECT\n * Instance of user defined class will be cloned to a plain object, without\n * properties in prototype.\n * Other data types is not supported (not sure what will happen).\n *\n * Caution: do not support clone Date, for performance consideration.\n * (There might be a large number of date in `series.data`).\n * So date should not be modified in and out of echarts.\n *\n * @param {*} source\n * @return {*} new\n */\nfunction clone(source) {\n    if (source == null || typeof source !== 'object') {\n        return source;\n    }\n\n    var result = source;\n    var typeStr = objToString.call(source);\n\n    if (typeStr === '[object Array]') {\n        if (!isPrimitive(source)) {\n            result = [];\n            for (var i = 0, len = source.length; i < len; i++) {\n                result[i] = clone(source[i]);\n            }\n        }\n    }\n    else if (TYPED_ARRAY[typeStr]) {\n        if (!isPrimitive(source)) {\n            var Ctor = source.constructor;\n            if (source.constructor.from) {\n                result = Ctor.from(source);\n            }\n            else {\n                result = new Ctor(source.length);\n                for (var i = 0, len = source.length; i < len; i++) {\n                    result[i] = clone(source[i]);\n                }\n            }\n        }\n    }\n    else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) {\n        result = {};\n        for (var key in source) {\n            if (source.hasOwnProperty(key)) {\n                result[key] = clone(source[key]);\n            }\n        }\n    }\n\n    return result;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overwrite=false]\n */\nfunction merge(target, source, overwrite) {\n    // We should escapse that source is string\n    // and enter for ... in ...\n    if (!isObject$1(source) || !isObject$1(target)) {\n        return overwrite ? clone(source) : target;\n    }\n\n    for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n            var targetProp = target[key];\n            var sourceProp = source[key];\n\n            if (isObject$1(sourceProp)\n                && isObject$1(targetProp)\n                && !isArray(sourceProp)\n                && !isArray(targetProp)\n                && !isDom(sourceProp)\n                && !isDom(targetProp)\n                && !isBuiltInObject(sourceProp)\n                && !isBuiltInObject(targetProp)\n                && !isPrimitive(sourceProp)\n                && !isPrimitive(targetProp)\n            ) {\n                // 如果需要递归覆盖，就递归调用merge\n                merge(targetProp, sourceProp, overwrite);\n            }\n            else if (overwrite || !(key in target)) {\n                // 否则只处理overwrite为true，或者在目标对象中没有此属性的情况\n                // NOTE，在 target[key] 不存在的时候也是直接覆盖\n                target[key] = clone(source[key], true);\n            }\n        }\n    }\n\n    return target;\n}\n\n/**\n * @param {Array} targetAndSources The first item is target, and the rests are source.\n * @param {boolean} [overwrite=false]\n * @return {*} target\n */\nfunction mergeAll(targetAndSources, overwrite) {\n    var result = targetAndSources[0];\n    for (var i = 1, len = targetAndSources.length; i < len; i++) {\n        result = merge(result, targetAndSources[i], overwrite);\n    }\n    return result;\n}\n\n/**\n * @param {*} target\n * @param {*} source\n * @memberOf module:zrender/core/util\n */\nfunction extend(target, source) {\n    for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n            target[key] = source[key];\n        }\n    }\n    return target;\n}\n\n/**\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overlay=false]\n * @memberOf module:zrender/core/util\n */\nfunction defaults(target, source, overlay) {\n    for (var key in source) {\n        if (source.hasOwnProperty(key)\n            && (overlay ? source[key] != null : target[key] == null)\n        ) {\n            target[key] = source[key];\n        }\n    }\n    return target;\n}\n\nvar createCanvas = function () {\n    return methods.createCanvas();\n};\n\nmethods.createCanvas = function () {\n    return document.createElement('canvas');\n};\n\n// FIXME\nvar _ctx;\n\nfunction getContext() {\n    if (!_ctx) {\n        // Use util.createCanvas instead of createCanvas\n        // because createCanvas may be overwritten in different environment\n        _ctx = createCanvas().getContext('2d');\n    }\n    return _ctx;\n}\n\n/**\n * 查询数组中元素的index\n * @memberOf module:zrender/core/util\n */\nfunction indexOf(array, value) {\n    if (array) {\n        if (array.indexOf) {\n            return array.indexOf(value);\n        }\n        for (var i = 0, len = array.length; i < len; i++) {\n            if (array[i] === value) {\n                return i;\n            }\n        }\n    }\n    return -1;\n}\n\n/**\n * 构造类继承关系\n *\n * @memberOf module:zrender/core/util\n * @param {Function} clazz 源类\n * @param {Function} baseClazz 基类\n */\nfunction inherits(clazz, baseClazz) {\n    var clazzPrototype = clazz.prototype;\n    function F() {}\n    F.prototype = baseClazz.prototype;\n    clazz.prototype = new F();\n\n    for (var prop in clazzPrototype) {\n        clazz.prototype[prop] = clazzPrototype[prop];\n    }\n    clazz.prototype.constructor = clazz;\n    clazz.superClass = baseClazz;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Object|Function} target\n * @param {Object|Function} sorce\n * @param {boolean} overlay\n */\nfunction mixin(target, source, overlay) {\n    target = 'prototype' in target ? target.prototype : target;\n    source = 'prototype' in source ? source.prototype : source;\n\n    defaults(target, source, overlay);\n}\n\n/**\n * Consider typed array.\n * @param {Array|TypedArray} data\n */\nfunction isArrayLike(data) {\n    if (!data) {\n        return;\n    }\n    if (typeof data === 'string') {\n        return false;\n    }\n    return typeof data.length === 'number';\n}\n\n/**\n * 数组或对象遍历\n * @memberOf module:zrender/core/util\n * @param {Object|Array} obj\n * @param {Function} cb\n * @param {*} [context]\n */\nfunction each$1(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.forEach && obj.forEach === nativeForEach) {\n        obj.forEach(cb, context);\n    }\n    else if (obj.length === +obj.length) {\n        for (var i = 0, len = obj.length; i < len; i++) {\n            cb.call(context, obj[i], i, obj);\n        }\n    }\n    else {\n        for (var key in obj) {\n            if (obj.hasOwnProperty(key)) {\n                cb.call(context, obj[key], key, obj);\n            }\n        }\n    }\n}\n\n/**\n * 数组映射\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction map(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.map && obj.map === nativeMap) {\n        return obj.map(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            result.push(cb.call(context, obj[i], i, obj));\n        }\n        return result;\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {Object} [memo]\n * @param {*} [context]\n * @return {Array}\n */\nfunction reduce(obj, cb, memo, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.reduce && obj.reduce === nativeReduce) {\n        return obj.reduce(cb, memo, context);\n    }\n    else {\n        for (var i = 0, len = obj.length; i < len; i++) {\n            memo = cb.call(context, memo, obj[i], i, obj);\n        }\n        return memo;\n    }\n}\n\n/**\n * 数组过滤\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction filter(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.filter && obj.filter === nativeFilter) {\n        return obj.filter(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            if (cb.call(context, obj[i], i, obj)) {\n                result.push(obj[i]);\n            }\n        }\n        return result;\n    }\n}\n\n/**\n * 数组项查找\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {*}\n */\nfunction find(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    for (var i = 0, len = obj.length; i < len; i++) {\n        if (cb.call(context, obj[i], i, obj)) {\n            return obj[i];\n        }\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @param {*} context\n * @return {Function}\n */\nfunction bind(func, context) {\n    var args = nativeSlice.call(arguments, 2);\n    return function () {\n        return func.apply(context, args.concat(nativeSlice.call(arguments)));\n    };\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @return {Function}\n */\nfunction curry(func) {\n    var args = nativeSlice.call(arguments, 1);\n    return function () {\n        return func.apply(this, args.concat(nativeSlice.call(arguments)));\n    };\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isArray(value) {\n    return objToString.call(value) === '[object Array]';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isFunction$1(value) {\n    return typeof value === 'function';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isString(value) {\n    return objToString.call(value) === '[object String]';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isObject$1(value) {\n    // Avoid a V8 JIT bug in Chrome 19-20.\n    // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.\n    var type = typeof value;\n    return type === 'function' || (!!value && type === 'object');\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isBuiltInObject(value) {\n    return !!BUILTIN_OBJECT[objToString.call(value)];\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isTypedArray(value) {\n    return !!TYPED_ARRAY[objToString.call(value)];\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isDom(value) {\n    return typeof value === 'object'\n        && typeof value.nodeType === 'number'\n        && typeof value.ownerDocument === 'object';\n}\n\n/**\n * Whether is exactly NaN. Notice isNaN('a') returns true.\n * @param {*} value\n * @return {boolean}\n */\nfunction eqNaN(value) {\n    return value !== value;\n}\n\n/**\n * If value1 is not null, then return value1, otherwise judget rest of values.\n * Low performance.\n * @memberOf module:zrender/core/util\n * @return {*} Final value\n */\nfunction retrieve(values) {\n    for (var i = 0, len = arguments.length; i < len; i++) {\n        if (arguments[i] != null) {\n            return arguments[i];\n        }\n    }\n}\n\nfunction retrieve2(value0, value1) {\n    return value0 != null\n        ? value0\n        : value1;\n}\n\nfunction retrieve3(value0, value1, value2) {\n    return value0 != null\n        ? value0\n        : value1 != null\n        ? value1\n        : value2;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} arr\n * @param {number} startIndex\n * @param {number} endIndex\n * @return {Array}\n */\nfunction slice() {\n    return Function.call.apply(nativeSlice, arguments);\n}\n\n/**\n * Normalize css liked array configuration\n * e.g.\n *  3 => [3, 3, 3, 3]\n *  [4, 2] => [4, 2, 4, 2]\n *  [4, 3, 2] => [4, 3, 2, 3]\n * @param {number|Array.<number>} val\n * @return {Array.<number>}\n */\nfunction normalizeCssArray(val) {\n    if (typeof (val) === 'number') {\n        return [val, val, val, val];\n    }\n    var len = val.length;\n    if (len === 2) {\n        // vertical | horizontal\n        return [val[0], val[1], val[0], val[1]];\n    }\n    else if (len === 3) {\n        // top | horizontal | bottom\n        return [val[0], val[1], val[2], val[1]];\n    }\n    return val;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {boolean} condition\n * @param {string} message\n */\nfunction assert$1(condition, message) {\n    if (!condition) {\n        throw new Error(message);\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {string} str string to be trimed\n * @return {string} trimed string\n */\nfunction trim(str) {\n    if (str == null) {\n        return null;\n    }\n    else if (typeof str.trim === 'function') {\n        return str.trim();\n    }\n    else {\n        return str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n    }\n}\n\nvar primitiveKey = '__ec_primitive__';\n/**\n * Set an object as primitive to be ignored traversing children in clone or merge\n */\nfunction setAsPrimitive(obj) {\n    obj[primitiveKey] = true;\n}\n\nfunction isPrimitive(obj) {\n    return obj[primitiveKey];\n}\n\n/**\n * @constructor\n * @param {Object} obj Only apply `ownProperty`.\n */\nfunction HashMap(obj) {\n    var isArr = isArray(obj);\n    // Key should not be set on this, otherwise\n    // methods get/set/... may be overrided.\n    this.data = {};\n    var thisMap = this;\n\n    (obj instanceof HashMap)\n        ? obj.each(visit)\n        : (obj && each$1(obj, visit));\n\n    function visit(value, key) {\n        isArr ? thisMap.set(value, key) : thisMap.set(key, value);\n    }\n}\n\nHashMap.prototype = {\n    constructor: HashMap,\n    // Do not provide `has` method to avoid defining what is `has`.\n    // (We usually treat `null` and `undefined` as the same, different\n    // from ES6 Map).\n    get: function (key) {\n        return this.data.hasOwnProperty(key) ? this.data[key] : null;\n    },\n    set: function (key, value) {\n        // Comparing with invocation chaining, `return value` is more commonly\n        // used in this case: `var someVal = map.set('a', genVal());`\n        return (this.data[key] = value);\n    },\n    // Although util.each can be performed on this hashMap directly, user\n    // should not use the exposed keys, who are prefixed.\n    each: function (cb, context) {\n        context !== void 0 && (cb = bind(cb, context));\n        for (var key in this.data) {\n            this.data.hasOwnProperty(key) && cb(this.data[key], key);\n        }\n    },\n    // Do not use this method if performance sensitive.\n    removeKey: function (key) {\n        delete this.data[key];\n    }\n};\n\nfunction createHashMap(obj) {\n    return new HashMap(obj);\n}\n\nfunction concatArray(a, b) {\n    var newArray = new a.constructor(a.length + b.length);\n    for (var i = 0; i < a.length; i++) {\n        newArray[i] = a[i];\n    }\n    var offset = a.length;\n    for (i = 0; i < b.length; i++) {\n        newArray[i + offset] = b[i];\n    }\n    return newArray;\n}\n\n\nfunction noop() {}\n\n\nvar zrUtil = (Object.freeze || Object)({\n\t$override: $override,\n\tclone: clone,\n\tmerge: merge,\n\tmergeAll: mergeAll,\n\textend: extend,\n\tdefaults: defaults,\n\tcreateCanvas: createCanvas,\n\tgetContext: getContext,\n\tindexOf: indexOf,\n\tinherits: inherits,\n\tmixin: mixin,\n\tisArrayLike: isArrayLike,\n\teach: each$1,\n\tmap: map,\n\treduce: reduce,\n\tfilter: filter,\n\tfind: find,\n\tbind: bind,\n\tcurry: curry,\n\tisArray: isArray,\n\tisFunction: isFunction$1,\n\tisString: isString,\n\tisObject: isObject$1,\n\tisBuiltInObject: isBuiltInObject,\n\tisTypedArray: isTypedArray,\n\tisDom: isDom,\n\teqNaN: eqNaN,\n\tretrieve: retrieve,\n\tretrieve2: retrieve2,\n\tretrieve3: retrieve3,\n\tslice: slice,\n\tnormalizeCssArray: normalizeCssArray,\n\tassert: assert$1,\n\ttrim: trim,\n\tsetAsPrimitive: setAsPrimitive,\n\tisPrimitive: isPrimitive,\n\tcreateHashMap: createHashMap,\n\tconcatArray: concatArray,\n\tnoop: noop\n});\n\nvar ArrayCtor = typeof Float32Array === 'undefined'\n    ? Array\n    : Float32Array;\n\n/**\n * 创建一个向量\n * @param {number} [x=0]\n * @param {number} [y=0]\n * @return {Vector2}\n */\nfunction create(x, y) {\n    var out = new ArrayCtor(2);\n    if (x == null) {\n        x = 0;\n    }\n    if (y == null) {\n        y = 0;\n    }\n    out[0] = x;\n    out[1] = y;\n    return out;\n}\n\n/**\n * 复制向量数据\n * @param {Vector2} out\n * @param {Vector2} v\n * @return {Vector2}\n */\nfunction copy(out, v) {\n    out[0] = v[0];\n    out[1] = v[1];\n    return out;\n}\n\n/**\n * 克隆一个向量\n * @param {Vector2} v\n * @return {Vector2}\n */\nfunction clone$1(v) {\n    var out = new ArrayCtor(2);\n    out[0] = v[0];\n    out[1] = v[1];\n    return out;\n}\n\n/**\n * 设置向量的两个项\n * @param {Vector2} out\n * @param {number} a\n * @param {number} b\n * @return {Vector2} 结果\n */\nfunction set(out, a, b) {\n    out[0] = a;\n    out[1] = b;\n    return out;\n}\n\n/**\n * 向量相加\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction add(out, v1, v2) {\n    out[0] = v1[0] + v2[0];\n    out[1] = v1[1] + v2[1];\n    return out;\n}\n\n/**\n * 向量缩放后相加\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @param {number} a\n */\nfunction scaleAndAdd(out, v1, v2, a) {\n    out[0] = v1[0] + v2[0] * a;\n    out[1] = v1[1] + v2[1] * a;\n    return out;\n}\n\n/**\n * 向量相减\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction sub(out, v1, v2) {\n    out[0] = v1[0] - v2[0];\n    out[1] = v1[1] - v2[1];\n    return out;\n}\n\n/**\n * 向量长度\n * @param {Vector2} v\n * @return {number}\n */\nfunction len(v) {\n    return Math.sqrt(lenSquare(v));\n}\nvar length = len; // jshint ignore:line\n\n/**\n * 向量长度平方\n * @param {Vector2} v\n * @return {number}\n */\nfunction lenSquare(v) {\n    return v[0] * v[0] + v[1] * v[1];\n}\nvar lengthSquare = lenSquare;\n\n/**\n * 向量乘法\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction mul(out, v1, v2) {\n    out[0] = v1[0] * v2[0];\n    out[1] = v1[1] * v2[1];\n    return out;\n}\n\n/**\n * 向量除法\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction div(out, v1, v2) {\n    out[0] = v1[0] / v2[0];\n    out[1] = v1[1] / v2[1];\n    return out;\n}\n\n/**\n * 向量点乘\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction dot(v1, v2) {\n    return v1[0] * v2[0] + v1[1] * v2[1];\n}\n\n/**\n * 向量缩放\n * @param {Vector2} out\n * @param {Vector2} v\n * @param {number} s\n */\nfunction scale(out, v, s) {\n    out[0] = v[0] * s;\n    out[1] = v[1] * s;\n    return out;\n}\n\n/**\n * 向量归一化\n * @param {Vector2} out\n * @param {Vector2} v\n */\nfunction normalize(out, v) {\n    var d = len(v);\n    if (d === 0) {\n        out[0] = 0;\n        out[1] = 0;\n    }\n    else {\n        out[0] = v[0] / d;\n        out[1] = v[1] / d;\n    }\n    return out;\n}\n\n/**\n * 计算向量间距离\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction distance(v1, v2) {\n    return Math.sqrt(\n        (v1[0] - v2[0]) * (v1[0] - v2[0])\n        + (v1[1] - v2[1]) * (v1[1] - v2[1])\n    );\n}\nvar dist = distance;\n\n/**\n * 向量距离平方\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction distanceSquare(v1, v2) {\n    return (v1[0] - v2[0]) * (v1[0] - v2[0])\n        + (v1[1] - v2[1]) * (v1[1] - v2[1]);\n}\nvar distSquare = distanceSquare;\n\n/**\n * 求负向量\n * @param {Vector2} out\n * @param {Vector2} v\n */\nfunction negate(out, v) {\n    out[0] = -v[0];\n    out[1] = -v[1];\n    return out;\n}\n\n/**\n * 插值两个点\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @param {number} t\n */\nfunction lerp(out, v1, v2, t) {\n    out[0] = v1[0] + t * (v2[0] - v1[0]);\n    out[1] = v1[1] + t * (v2[1] - v1[1]);\n    return out;\n}\n\n/**\n * 矩阵左乘向量\n * @param {Vector2} out\n * @param {Vector2} v\n * @param {Vector2} m\n */\nfunction applyTransform(out, v, m) {\n    var x = v[0];\n    var y = v[1];\n    out[0] = m[0] * x + m[2] * y + m[4];\n    out[1] = m[1] * x + m[3] * y + m[5];\n    return out;\n}\n\n/**\n * 求两个向量最小值\n * @param  {Vector2} out\n * @param  {Vector2} v1\n * @param  {Vector2} v2\n */\nfunction min(out, v1, v2) {\n    out[0] = Math.min(v1[0], v2[0]);\n    out[1] = Math.min(v1[1], v2[1]);\n    return out;\n}\n\n/**\n * 求两个向量最大值\n * @param  {Vector2} out\n * @param  {Vector2} v1\n * @param  {Vector2} v2\n */\nfunction max(out, v1, v2) {\n    out[0] = Math.max(v1[0], v2[0]);\n    out[1] = Math.max(v1[1], v2[1]);\n    return out;\n}\n\n\nvar vector = (Object.freeze || Object)({\n\tcreate: create,\n\tcopy: copy,\n\tclone: clone$1,\n\tset: set,\n\tadd: add,\n\tscaleAndAdd: scaleAndAdd,\n\tsub: sub,\n\tlen: len,\n\tlength: length,\n\tlenSquare: lenSquare,\n\tlengthSquare: lengthSquare,\n\tmul: mul,\n\tdiv: div,\n\tdot: dot,\n\tscale: scale,\n\tnormalize: normalize,\n\tdistance: distance,\n\tdist: dist,\n\tdistanceSquare: distanceSquare,\n\tdistSquare: distSquare,\n\tnegate: negate,\n\tlerp: lerp,\n\tapplyTransform: applyTransform,\n\tmin: min,\n\tmax: max\n});\n\n// TODO Draggable for group\n// FIXME Draggable on element which has parent rotation or scale\nfunction Draggable() {\n\n    this.on('mousedown', this._dragStart, this);\n    this.on('mousemove', this._drag, this);\n    this.on('mouseup', this._dragEnd, this);\n    this.on('globalout', this._dragEnd, this);\n    // this._dropTarget = null;\n    // this._draggingTarget = null;\n\n    // this._x = 0;\n    // this._y = 0;\n}\n\nDraggable.prototype = {\n\n    constructor: Draggable,\n\n    _dragStart: function (e) {\n        var draggingTarget = e.target;\n        if (draggingTarget && draggingTarget.draggable) {\n            this._draggingTarget = draggingTarget;\n            draggingTarget.dragging = true;\n            this._x = e.offsetX;\n            this._y = e.offsetY;\n\n            this.dispatchToElement(param(draggingTarget, e), 'dragstart', e.event);\n        }\n    },\n\n    _drag: function (e) {\n        var draggingTarget = this._draggingTarget;\n        if (draggingTarget) {\n\n            var x = e.offsetX;\n            var y = e.offsetY;\n\n            var dx = x - this._x;\n            var dy = y - this._y;\n            this._x = x;\n            this._y = y;\n\n            draggingTarget.drift(dx, dy, e);\n            this.dispatchToElement(param(draggingTarget, e), 'drag', e.event);\n\n            var dropTarget = this.findHover(x, y, draggingTarget).target;\n            var lastDropTarget = this._dropTarget;\n            this._dropTarget = dropTarget;\n\n            if (draggingTarget !== dropTarget) {\n                if (lastDropTarget && dropTarget !== lastDropTarget) {\n                    this.dispatchToElement(param(lastDropTarget, e), 'dragleave', e.event);\n                }\n                if (dropTarget && dropTarget !== lastDropTarget) {\n                    this.dispatchToElement(param(dropTarget, e), 'dragenter', e.event);\n                }\n            }\n        }\n    },\n\n    _dragEnd: function (e) {\n        var draggingTarget = this._draggingTarget;\n\n        if (draggingTarget) {\n            draggingTarget.dragging = false;\n        }\n\n        this.dispatchToElement(param(draggingTarget, e), 'dragend', e.event);\n\n        if (this._dropTarget) {\n            this.dispatchToElement(param(this._dropTarget, e), 'drop', e.event);\n        }\n\n        this._draggingTarget = null;\n        this._dropTarget = null;\n    }\n\n};\n\nfunction param(target, e) {\n    return {target: target, topTarget: e && e.topTarget};\n}\n\n/**\n * Event Mixin\n * @module zrender/mixin/Eventful\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         pissang (https://www.github.com/pissang)\n */\n\nvar arrySlice = Array.prototype.slice;\n\n/**\n * Event dispatcher.\n *\n * @alias module:zrender/mixin/Eventful\n * @constructor\n * @param {Object} [eventProcessor] The object eventProcessor is the scope when\n *        `eventProcessor.xxx` called.\n * @param {Function} [eventProcessor.normalizeQuery]\n *        param: {string|Object} Raw query.\n *        return: {string|Object} Normalized query.\n * @param {Function} [eventProcessor.filter] Event will be dispatched only\n *        if it returns `true`.\n *        param: {string} eventType\n *        param: {string|Object} query\n *        return: {boolean}\n * @param {Function} [eventProcessor.afterTrigger] Call after all handlers called.\n *        param: {string} eventType\n */\nvar Eventful = function (eventProcessor) {\n    this._$handlers = {};\n    this._$eventProcessor = eventProcessor;\n};\n\nEventful.prototype = {\n\n    constructor: Eventful,\n\n    /**\n     * The handler can only be triggered once, then removed.\n     *\n     * @param {string} event The event name.\n     * @param {string|Object} [query] Condition used on event filter.\n     * @param {Function} handler The event handler.\n     * @param {Object} context\n     */\n    one: function (event, query, handler, context) {\n        return on(this, event, query, handler, context, true);\n    },\n\n    /**\n     * Bind a handler.\n     *\n     * @param {string} event The event name.\n     * @param {string|Object} [query] Condition used on event filter.\n     * @param {Function} handler The event handler.\n     * @param {Object} [context]\n     */\n    on: function (event, query, handler, context) {\n        return on(this, event, query, handler, context, false);\n    },\n\n    /**\n     * Whether any handler has bound.\n     *\n     * @param  {string}  event\n     * @return {boolean}\n     */\n    isSilent: function (event) {\n        var _h = this._$handlers;\n        return !_h[event] || !_h[event].length;\n    },\n\n    /**\n     * Unbind a event.\n     *\n     * @param {string} event The event name.\n     * @param {Function} [handler] The event handler.\n     */\n    off: function (event, handler) {\n        var _h = this._$handlers;\n\n        if (!event) {\n            this._$handlers = {};\n            return this;\n        }\n\n        if (handler) {\n            if (_h[event]) {\n                var newList = [];\n                for (var i = 0, l = _h[event].length; i < l; i++) {\n                    if (_h[event][i].h !== handler) {\n                        newList.push(_h[event][i]);\n                    }\n                }\n                _h[event] = newList;\n            }\n\n            if (_h[event] && _h[event].length === 0) {\n                delete _h[event];\n            }\n        }\n        else {\n            delete _h[event];\n        }\n\n        return this;\n    },\n\n    /**\n     * Dispatch a event.\n     *\n     * @param {string} type The event name.\n     */\n    trigger: function (type) {\n        var _h = this._$handlers[type];\n        var eventProcessor = this._$eventProcessor;\n\n        if (_h) {\n            var args = arguments;\n            var argLen = args.length;\n\n            if (argLen > 3) {\n                args = arrySlice.call(args, 1);\n            }\n\n            var len = _h.length;\n            for (var i = 0; i < len;) {\n                var hItem = _h[i];\n                if (eventProcessor\n                    && eventProcessor.filter\n                    && hItem.query != null\n                    && !eventProcessor.filter(type, hItem.query)\n                ) {\n                    i++;\n                    continue;\n                }\n\n                // Optimize advise from backbone\n                switch (argLen) {\n                    case 1:\n                        hItem.h.call(hItem.ctx);\n                        break;\n                    case 2:\n                        hItem.h.call(hItem.ctx, args[1]);\n                        break;\n                    case 3:\n                        hItem.h.call(hItem.ctx, args[1], args[2]);\n                        break;\n                    default:\n                        // have more than 2 given arguments\n                        hItem.h.apply(hItem.ctx, args);\n                        break;\n                }\n\n                if (hItem.one) {\n                    _h.splice(i, 1);\n                    len--;\n                }\n                else {\n                    i++;\n                }\n            }\n        }\n\n        eventProcessor && eventProcessor.afterTrigger\n            && eventProcessor.afterTrigger(type);\n\n        return this;\n    },\n\n    /**\n     * Dispatch a event with context, which is specified at the last parameter.\n     *\n     * @param {string} type The event name.\n     */\n    triggerWithContext: function (type) {\n        var _h = this._$handlers[type];\n        var eventProcessor = this._$eventProcessor;\n\n        if (_h) {\n            var args = arguments;\n            var argLen = args.length;\n\n            if (argLen > 4) {\n                args = arrySlice.call(args, 1, args.length - 1);\n            }\n            var ctx = args[args.length - 1];\n\n            var len = _h.length;\n            for (var i = 0; i < len;) {\n                var hItem = _h[i];\n                if (eventProcessor\n                    && eventProcessor.filter\n                    && hItem.query != null\n                    && !eventProcessor.filter(type, hItem.query)\n                ) {\n                    i++;\n                    continue;\n                }\n\n                // Optimize advise from backbone\n                switch (argLen) {\n                    case 1:\n                        hItem.h.call(ctx);\n                        break;\n                    case 2:\n                        hItem.h.call(ctx, args[1]);\n                        break;\n                    case 3:\n                        hItem.h.call(ctx, args[1], args[2]);\n                        break;\n                    default:\n                        // have more than 2 given arguments\n                        hItem.h.apply(ctx, args);\n                        break;\n                }\n\n                if (hItem.one) {\n                    _h.splice(i, 1);\n                    len--;\n                }\n                else {\n                    i++;\n                }\n            }\n        }\n\n        eventProcessor && eventProcessor.afterTrigger\n            && eventProcessor.afterTrigger(type);\n\n        return this;\n    }\n};\n\nfunction normalizeQuery(host, query) {\n    var eventProcessor = host._$eventProcessor;\n    if (query != null && eventProcessor && eventProcessor.normalizeQuery) {\n        query = eventProcessor.normalizeQuery(query);\n    }\n    return query;\n}\n\nfunction on(eventful, event, query, handler, context, isOnce) {\n    var _h = eventful._$handlers;\n\n    if (typeof query === 'function') {\n        context = handler;\n        handler = query;\n        query = null;\n    }\n\n    if (!handler || !event) {\n        return eventful;\n    }\n\n    query = normalizeQuery(eventful, query);\n\n    if (!_h[event]) {\n        _h[event] = [];\n    }\n\n    for (var i = 0; i < _h[event].length; i++) {\n        if (_h[event][i].h === handler) {\n            return eventful;\n        }\n    }\n\n    var wrap = {\n        h: handler,\n        one: isOnce,\n        query: query,\n        ctx: context || eventful,\n        // FIXME\n        // Do not publish this feature util it is proved that it makes sense.\n        callAtLast: handler.zrEventfulCallAtLast\n    };\n\n    var lastIndex = _h[event].length - 1;\n    var lastWrap = _h[event][lastIndex];\n    (lastWrap && lastWrap.callAtLast)\n        ? _h[event].splice(lastIndex, 0, wrap)\n        : _h[event].push(wrap);\n\n    return eventful;\n}\n\n/**\n * 事件辅助类\n * @module zrender/core/event\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n */\n\nvar isDomLevel2 = (typeof window !== 'undefined') && !!window.addEventListener;\n\nvar MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;\n\nfunction getBoundingClientRect(el) {\n    // BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect\n    return el.getBoundingClientRect ? el.getBoundingClientRect() : {left: 0, top: 0};\n}\n\n// `calculate` is optional, default false\nfunction clientToLocal(el, e, out, calculate) {\n    out = out || {};\n\n    // According to the W3C Working Draft, offsetX and offsetY should be relative\n    // to the padding edge of the target element. The only browser using this convention\n    // is IE. Webkit uses the border edge, Opera uses the content edge, and FireFox does\n    // not support the properties.\n    // (see http://www.jacklmoore.com/notes/mouse-position/)\n    // In zr painter.dom, padding edge equals to border edge.\n\n    // FIXME\n    // When mousemove event triggered on ec tooltip, target is not zr painter.dom, and\n    // offsetX/Y is relative to e.target, where the calculation of zrX/Y via offsetX/Y\n    // is too complex. So css-transfrom dont support in this case temporarily.\n    if (calculate || !env$1.canvasSupported) {\n        defaultGetZrXY(el, e, out);\n    }\n    // Caution: In FireFox, layerX/layerY Mouse position relative to the closest positioned\n    // ancestor element, so we should make sure el is positioned (e.g., not position:static).\n    // BTW1, Webkit don't return the same results as FF in non-simple cases (like add\n    // zoom-factor, overflow / opacity layers, transforms ...)\n    // BTW2, (ev.offsetY || ev.pageY - $(ev.target).offset().top) is not correct in preserve-3d.\n    // <https://bugs.jquery.com/ticket/8523#comment:14>\n    // BTW3, In ff, offsetX/offsetY is always 0.\n    else if (env$1.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) {\n        out.zrX = e.layerX;\n        out.zrY = e.layerY;\n    }\n    // For IE6+, chrome, safari, opera. (When will ff support offsetX?)\n    else if (e.offsetX != null) {\n        out.zrX = e.offsetX;\n        out.zrY = e.offsetY;\n    }\n    // For some other device, e.g., IOS safari.\n    else {\n        defaultGetZrXY(el, e, out);\n    }\n\n    return out;\n}\n\nfunction defaultGetZrXY(el, e, out) {\n    // This well-known method below does not support css transform.\n    var box = getBoundingClientRect(el);\n    out.zrX = e.clientX - box.left;\n    out.zrY = e.clientY - box.top;\n}\n\n/**\n * 如果存在第三方嵌入的一些dom触发的事件，或touch事件，需要转换一下事件坐标.\n * `calculate` is optional, default false.\n */\nfunction normalizeEvent(el, e, calculate) {\n\n    e = e || window.event;\n\n    if (e.zrX != null) {\n        return e;\n    }\n\n    var eventType = e.type;\n    var isTouch = eventType && eventType.indexOf('touch') >= 0;\n\n    if (!isTouch) {\n        clientToLocal(el, e, e, calculate);\n        e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3;\n    }\n    else {\n        var touch = eventType !== 'touchend'\n            ? e.targetTouches[0]\n            : e.changedTouches[0];\n        touch && clientToLocal(el, touch, e, calculate);\n    }\n\n    // Add which for click: 1 === left; 2 === middle; 3 === right; otherwise: 0;\n    // See jQuery: https://github.com/jquery/jquery/blob/master/src/event.js\n    // If e.which has been defined, if may be readonly,\n    // see: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which\n    var button = e.button;\n    if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) {\n        e.which = (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));\n    }\n    // [Caution]: `e.which` from browser is not always reliable. For example,\n    // when press left button and `mousemove (pointermove)` in Edge, the `e.which`\n    // is 65536 and the `e.button` is -1. But the `mouseup (pointerup)` and\n    // `mousedown (pointerdown)` is the same as Chrome does.\n\n    return e;\n}\n\n/**\n * @param {HTMLElement} el\n * @param {string} name\n * @param {Function} handler\n */\nfunction addEventListener(el, name, handler) {\n    if (isDomLevel2) {\n        // Reproduct the console warning:\n        // [Violation] Added non-passive event listener to a scroll-blocking <some> event.\n        // Consider marking event handler as 'passive' to make the page more responsive.\n        // Just set console log level: verbose in chrome dev tool.\n        // then the warning log will be printed when addEventListener called.\n        // See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md\n        // We have not yet found a neat way to using passive. Because in zrender the dom event\n        // listener delegate all of the upper events of element. Some of those events need\n        // to prevent default. For example, the feature `preventDefaultMouseMove` of echarts.\n        // Before passive can be adopted, these issues should be considered:\n        // (1) Whether and how a zrender user specifies an event listener passive. And by default,\n        // passive or not.\n        // (2) How to tread that some zrender event listener is passive, and some is not. If\n        // we use other way but not preventDefault of mousewheel and touchmove, browser\n        // compatibility should be handled.\n\n        // var opts = (env.passiveSupported && name === 'mousewheel')\n        //     ? {passive: true}\n        //     // By default, the third param of el.addEventListener is `capture: false`.\n        //     : void 0;\n        // el.addEventListener(name, handler /* , opts */);\n        el.addEventListener(name, handler);\n    }\n    else {\n        el.attachEvent('on' + name, handler);\n    }\n}\n\nfunction removeEventListener(el, name, handler) {\n    if (isDomLevel2) {\n        el.removeEventListener(name, handler);\n    }\n    else {\n        el.detachEvent('on' + name, handler);\n    }\n}\n\n/**\n * preventDefault and stopPropagation.\n * Notice: do not do that in zrender. Upper application\n * do that if necessary.\n *\n * @memberOf module:zrender/core/event\n * @method\n * @param {Event} e : event对象\n */\nvar stop = isDomLevel2\n    ? function (e) {\n        e.preventDefault();\n        e.stopPropagation();\n        e.cancelBubble = true;\n    }\n    : function (e) {\n        e.returnValue = false;\n        e.cancelBubble = true;\n    };\n\n/**\n * This method only works for mouseup and mousedown. The functionality is restricted\n * for fault tolerance, See the `e.which` compatibility above.\n *\n * @param {MouseEvent} e\n * @return {boolean}\n */\nfunction isMiddleOrRightButtonOnMouseUpDown(e) {\n    return e.which === 2 || e.which === 3;\n}\n\n/**\n * To be removed.\n * @deprecated\n */\n\n/**\n * Only implements needed gestures for mobile.\n */\n\nvar GestureMgr = function () {\n\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    this._track = [];\n};\n\nGestureMgr.prototype = {\n\n    constructor: GestureMgr,\n\n    recognize: function (event, target, root) {\n        this._doTrack(event, target, root);\n        return this._recognize(event);\n    },\n\n    clear: function () {\n        this._track.length = 0;\n        return this;\n    },\n\n    _doTrack: function (event, target, root) {\n        var touches = event.touches;\n\n        if (!touches) {\n            return;\n        }\n\n        var trackItem = {\n            points: [],\n            touches: [],\n            target: target,\n            event: event\n        };\n\n        for (var i = 0, len = touches.length; i < len; i++) {\n            var touch = touches[i];\n            var pos = clientToLocal(root, touch, {});\n            trackItem.points.push([pos.zrX, pos.zrY]);\n            trackItem.touches.push(touch);\n        }\n\n        this._track.push(trackItem);\n    },\n\n    _recognize: function (event) {\n        for (var eventName in recognizers) {\n            if (recognizers.hasOwnProperty(eventName)) {\n                var gestureInfo = recognizers[eventName](this._track, event);\n                if (gestureInfo) {\n                    return gestureInfo;\n                }\n            }\n        }\n    }\n};\n\nfunction dist$1(pointPair) {\n    var dx = pointPair[1][0] - pointPair[0][0];\n    var dy = pointPair[1][1] - pointPair[0][1];\n\n    return Math.sqrt(dx * dx + dy * dy);\n}\n\nfunction center(pointPair) {\n    return [\n        (pointPair[0][0] + pointPair[1][0]) / 2,\n        (pointPair[0][1] + pointPair[1][1]) / 2\n    ];\n}\n\nvar recognizers = {\n\n    pinch: function (track, event) {\n        var trackLen = track.length;\n\n        if (!trackLen) {\n            return;\n        }\n\n        var pinchEnd = (track[trackLen - 1] || {}).points;\n        var pinchPre = (track[trackLen - 2] || {}).points || pinchEnd;\n\n        if (pinchPre\n            && pinchPre.length > 1\n            && pinchEnd\n            && pinchEnd.length > 1\n        ) {\n            var pinchScale = dist$1(pinchEnd) / dist$1(pinchPre);\n            !isFinite(pinchScale) && (pinchScale = 1);\n\n            event.pinchScale = pinchScale;\n\n            var pinchCenter = center(pinchEnd);\n            event.pinchX = pinchCenter[0];\n            event.pinchY = pinchCenter[1];\n\n            return {\n                type: 'pinch',\n                target: track[0].target,\n                event: event\n            };\n        }\n    }\n\n    // Only pinch currently.\n};\n\nvar SILENT = 'silent';\n\nfunction makeEventPacket(eveType, targetInfo, event) {\n    return {\n        type: eveType,\n        event: event,\n        // target can only be an element that is not silent.\n        target: targetInfo.target,\n        // topTarget can be a silent element.\n        topTarget: targetInfo.topTarget,\n        cancelBubble: false,\n        offsetX: event.zrX,\n        offsetY: event.zrY,\n        gestureEvent: event.gestureEvent,\n        pinchX: event.pinchX,\n        pinchY: event.pinchY,\n        pinchScale: event.pinchScale,\n        wheelDelta: event.zrDelta,\n        zrByTouch: event.zrByTouch,\n        which: event.which,\n        stop: stopEvent\n    };\n}\n\nfunction stopEvent(event) {\n    stop(this.event);\n}\n\nfunction EmptyProxy() {}\nEmptyProxy.prototype.dispose = function () {};\n\nvar handlerNames = [\n    'click', 'dblclick', 'mousewheel', 'mouseout',\n    'mouseup', 'mousedown', 'mousemove', 'contextmenu'\n];\n/**\n * @alias module:zrender/Handler\n * @constructor\n * @extends module:zrender/mixin/Eventful\n * @param {module:zrender/Storage} storage Storage instance.\n * @param {module:zrender/Painter} painter Painter instance.\n * @param {module:zrender/dom/HandlerProxy} proxy HandlerProxy instance.\n * @param {HTMLElement} painterRoot painter.root (not painter.getViewportRoot()).\n */\nvar Handler = function (storage, painter, proxy, painterRoot) {\n    Eventful.call(this);\n\n    this.storage = storage;\n\n    this.painter = painter;\n\n    this.painterRoot = painterRoot;\n\n    proxy = proxy || new EmptyProxy();\n\n    /**\n     * Proxy of event. can be Dom, WebGLSurface, etc.\n     */\n    this.proxy = null;\n\n    /**\n     * {target, topTarget, x, y}\n     * @private\n     * @type {Object}\n     */\n    this._hovered = {};\n\n    /**\n     * @private\n     * @type {Date}\n     */\n    this._lastTouchMoment;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._lastX;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._lastY;\n\n    /**\n     * @private\n     * @type {module:zrender/core/GestureMgr}\n     */\n    this._gestureMgr;\n\n\n    Draggable.call(this);\n\n    this.setHandlerProxy(proxy);\n};\n\nHandler.prototype = {\n\n    constructor: Handler,\n\n    setHandlerProxy: function (proxy) {\n        if (this.proxy) {\n            this.proxy.dispose();\n        }\n\n        if (proxy) {\n            each$1(handlerNames, function (name) {\n                proxy.on && proxy.on(name, this[name], this);\n            }, this);\n            // Attach handler\n            proxy.handler = this;\n        }\n        this.proxy = proxy;\n    },\n\n    mousemove: function (event) {\n        var x = event.zrX;\n        var y = event.zrY;\n\n        var lastHovered = this._hovered;\n        var lastHoveredTarget = lastHovered.target;\n\n        // If lastHoveredTarget is removed from zr (detected by '__zr') by some API call\n        // (like 'setOption' or 'dispatchAction') in event handlers, we should find\n        // lastHovered again here. Otherwise 'mouseout' can not be triggered normally.\n        // See #6198.\n        if (lastHoveredTarget && !lastHoveredTarget.__zr) {\n            lastHovered = this.findHover(lastHovered.x, lastHovered.y);\n            lastHoveredTarget = lastHovered.target;\n        }\n\n        var hovered = this._hovered = this.findHover(x, y);\n        var hoveredTarget = hovered.target;\n\n        var proxy = this.proxy;\n        proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default');\n\n        // Mouse out on previous hovered element\n        if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget) {\n            this.dispatchToElement(lastHovered, 'mouseout', event);\n        }\n\n        // Mouse moving on one element\n        this.dispatchToElement(hovered, 'mousemove', event);\n\n        // Mouse over on a new element\n        if (hoveredTarget && hoveredTarget !== lastHoveredTarget) {\n            this.dispatchToElement(hovered, 'mouseover', event);\n        }\n    },\n\n    mouseout: function (event) {\n        this.dispatchToElement(this._hovered, 'mouseout', event);\n\n        // There might be some doms created by upper layer application\n        // at the same level of painter.getViewportRoot() (e.g., tooltip\n        // dom created by echarts), where 'globalout' event should not\n        // be triggered when mouse enters these doms. (But 'mouseout'\n        // should be triggered at the original hovered element as usual).\n        var element = event.toElement || event.relatedTarget;\n        var innerDom;\n        do {\n            element = element && element.parentNode;\n        }\n        while (element && element.nodeType !== 9 && !(\n            innerDom = element === this.painterRoot\n        ));\n\n        !innerDom && this.trigger('globalout', {event: event});\n    },\n\n    /**\n     * Resize\n     */\n    resize: function (event) {\n        this._hovered = {};\n    },\n\n    /**\n     * Dispatch event\n     * @param {string} eventName\n     * @param {event=} eventArgs\n     */\n    dispatch: function (eventName, eventArgs) {\n        var handler = this[eventName];\n        handler && handler.call(this, eventArgs);\n    },\n\n    /**\n     * Dispose\n     */\n    dispose: function () {\n\n        this.proxy.dispose();\n\n        this.storage =\n        this.proxy =\n        this.painter = null;\n    },\n\n    /**\n     * 设置默认的cursor style\n     * @param {string} [cursorStyle='default'] 例如 crosshair\n     */\n    setCursorStyle: function (cursorStyle) {\n        var proxy = this.proxy;\n        proxy.setCursor && proxy.setCursor(cursorStyle);\n    },\n\n    /**\n     * 事件分发代理\n     *\n     * @private\n     * @param {Object} targetInfo {target, topTarget} 目标图形元素\n     * @param {string} eventName 事件名称\n     * @param {Object} event 事件对象\n     */\n    dispatchToElement: function (targetInfo, eventName, event) {\n        targetInfo = targetInfo || {};\n        var el = targetInfo.target;\n        if (el && el.silent) {\n            return;\n        }\n        var eventHandler = 'on' + eventName;\n        var eventPacket = makeEventPacket(eventName, targetInfo, event);\n\n        while (el) {\n            el[eventHandler]\n                && (eventPacket.cancelBubble = el[eventHandler].call(el, eventPacket));\n\n            el.trigger(eventName, eventPacket);\n\n            el = el.parent;\n\n            if (eventPacket.cancelBubble) {\n                break;\n            }\n        }\n\n        if (!eventPacket.cancelBubble) {\n            // 冒泡到顶级 zrender 对象\n            this.trigger(eventName, eventPacket);\n            // 分发事件到用户自定义层\n            // 用户有可能在全局 click 事件中 dispose，所以需要判断下 painter 是否存在\n            this.painter && this.painter.eachOtherLayer(function (layer) {\n                if (typeof (layer[eventHandler]) === 'function') {\n                    layer[eventHandler].call(layer, eventPacket);\n                }\n                if (layer.trigger) {\n                    layer.trigger(eventName, eventPacket);\n                }\n            });\n        }\n    },\n\n    /**\n     * @private\n     * @param {number} x\n     * @param {number} y\n     * @param {module:zrender/graphic/Displayable} exclude\n     * @return {model:zrender/Element}\n     * @method\n     */\n    findHover: function (x, y, exclude) {\n        var list = this.storage.getDisplayList();\n        var out = {x: x, y: y};\n\n        for (var i = list.length - 1; i >= 0; i--) {\n            var hoverCheckResult;\n            if (list[i] !== exclude\n                // getDisplayList may include ignored item in VML mode\n                && !list[i].ignore\n                && (hoverCheckResult = isHover(list[i], x, y))\n            ) {\n                !out.topTarget && (out.topTarget = list[i]);\n                if (hoverCheckResult !== SILENT) {\n                    out.target = list[i];\n                    break;\n                }\n            }\n        }\n\n        return out;\n    },\n\n    processGesture: function (event, stage) {\n        if (!this._gestureMgr) {\n            this._gestureMgr = new GestureMgr();\n        }\n        var gestureMgr = this._gestureMgr;\n\n        stage === 'start' && gestureMgr.clear();\n\n        var gestureInfo = gestureMgr.recognize(\n            event,\n            this.findHover(event.zrX, event.zrY, null).target,\n            this.proxy.dom\n        );\n\n        stage === 'end' && gestureMgr.clear();\n\n        // Do not do any preventDefault here. Upper application do that if necessary.\n        if (gestureInfo) {\n            var type = gestureInfo.type;\n            event.gestureEvent = type;\n\n            this.dispatchToElement({target: gestureInfo.target}, type, gestureInfo.event);\n        }\n    }\n};\n\n// Common handlers\neach$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {\n    Handler.prototype[name] = function (event) {\n        // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover\n        var hovered = this.findHover(event.zrX, event.zrY);\n        var hoveredTarget = hovered.target;\n\n        if (name === 'mousedown') {\n            this._downEl = hoveredTarget;\n            this._downPoint = [event.zrX, event.zrY];\n            // In case click triggered before mouseup\n            this._upEl = hoveredTarget;\n        }\n        else if (name === 'mouseup') {\n            this._upEl = hoveredTarget;\n        }\n        else if (name === 'click') {\n            if (this._downEl !== this._upEl\n                // Original click event is triggered on the whole canvas element,\n                // including the case that `mousedown` - `mousemove` - `mouseup`,\n                // which should be filtered, otherwise it will bring trouble to\n                // pan and zoom.\n                || !this._downPoint\n                // Arbitrary value\n                || dist(this._downPoint, [event.zrX, event.zrY]) > 4\n            ) {\n                return;\n            }\n            this._downPoint = null;\n        }\n\n        this.dispatchToElement(hovered, name, event);\n    };\n});\n\nfunction isHover(displayable, x, y) {\n    if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) {\n        var el = displayable;\n        var isSilent;\n        while (el) {\n            // If clipped by ancestor.\n            // FIXME: If clipPath has neither stroke nor fill,\n            // el.clipPath.contain(x, y) will always return false.\n            if (el.clipPath && !el.clipPath.contain(x, y)) {\n                return false;\n            }\n            if (el.silent) {\n                isSilent = true;\n            }\n            el = el.parent;\n        }\n        return isSilent ? SILENT : true;\n    }\n\n    return false;\n}\n\nmixin(Handler, Eventful);\nmixin(Handler, Draggable);\n\n/**\n * 3x2矩阵操作类\n * @exports zrender/tool/matrix\n */\n\nvar ArrayCtor$1 = typeof Float32Array === 'undefined'\n    ? Array\n    : Float32Array;\n\n/**\n * Create a identity matrix.\n * @return {Float32Array|Array.<number>}\n */\nfunction create$1() {\n    var out = new ArrayCtor$1(6);\n    identity(out);\n\n    return out;\n}\n\n/**\n * 设置矩阵为单位矩阵\n * @param {Float32Array|Array.<number>} out\n */\nfunction identity(out) {\n    out[0] = 1;\n    out[1] = 0;\n    out[2] = 0;\n    out[3] = 1;\n    out[4] = 0;\n    out[5] = 0;\n    return out;\n}\n\n/**\n * 复制矩阵\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} m\n */\nfunction copy$1(out, m) {\n    out[0] = m[0];\n    out[1] = m[1];\n    out[2] = m[2];\n    out[3] = m[3];\n    out[4] = m[4];\n    out[5] = m[5];\n    return out;\n}\n\n/**\n * 矩阵相乘\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} m1\n * @param {Float32Array|Array.<number>} m2\n */\nfunction mul$1(out, m1, m2) {\n    // Consider matrix.mul(m, m2, m);\n    // where out is the same as m2.\n    // So use temp variable to escape error.\n    var out0 = m1[0] * m2[0] + m1[2] * m2[1];\n    var out1 = m1[1] * m2[0] + m1[3] * m2[1];\n    var out2 = m1[0] * m2[2] + m1[2] * m2[3];\n    var out3 = m1[1] * m2[2] + m1[3] * m2[3];\n    var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];\n    var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];\n    out[0] = out0;\n    out[1] = out1;\n    out[2] = out2;\n    out[3] = out3;\n    out[4] = out4;\n    out[5] = out5;\n    return out;\n}\n\n/**\n * 平移变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {Float32Array|Array.<number>} v\n */\nfunction translate(out, a, v) {\n    out[0] = a[0];\n    out[1] = a[1];\n    out[2] = a[2];\n    out[3] = a[3];\n    out[4] = a[4] + v[0];\n    out[5] = a[5] + v[1];\n    return out;\n}\n\n/**\n * 旋转变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {number} rad\n */\nfunction rotate(out, a, rad) {\n    var aa = a[0];\n    var ac = a[2];\n    var atx = a[4];\n    var ab = a[1];\n    var ad = a[3];\n    var aty = a[5];\n    var st = Math.sin(rad);\n    var ct = Math.cos(rad);\n\n    out[0] = aa * ct + ab * st;\n    out[1] = -aa * st + ab * ct;\n    out[2] = ac * ct + ad * st;\n    out[3] = -ac * st + ct * ad;\n    out[4] = ct * atx + st * aty;\n    out[5] = ct * aty - st * atx;\n    return out;\n}\n\n/**\n * 缩放变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {Float32Array|Array.<number>} v\n */\nfunction scale$1(out, a, v) {\n    var vx = v[0];\n    var vy = v[1];\n    out[0] = a[0] * vx;\n    out[1] = a[1] * vy;\n    out[2] = a[2] * vx;\n    out[3] = a[3] * vy;\n    out[4] = a[4] * vx;\n    out[5] = a[5] * vy;\n    return out;\n}\n\n/**\n * 求逆矩阵\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n */\nfunction invert(out, a) {\n\n    var aa = a[0];\n    var ac = a[2];\n    var atx = a[4];\n    var ab = a[1];\n    var ad = a[3];\n    var aty = a[5];\n\n    var det = aa * ad - ab * ac;\n    if (!det) {\n        return null;\n    }\n    det = 1.0 / det;\n\n    out[0] = ad * det;\n    out[1] = -ab * det;\n    out[2] = -ac * det;\n    out[3] = aa * det;\n    out[4] = (ac * aty - ad * atx) * det;\n    out[5] = (ab * atx - aa * aty) * det;\n    return out;\n}\n\n/**\n * Clone a new matrix.\n * @param {Float32Array|Array.<number>} a\n */\nfunction clone$2(a) {\n    var b = create$1();\n    copy$1(b, a);\n    return b;\n}\n\nvar matrix = (Object.freeze || Object)({\n\tcreate: create$1,\n\tidentity: identity,\n\tcopy: copy$1,\n\tmul: mul$1,\n\ttranslate: translate,\n\trotate: rotate,\n\tscale: scale$1,\n\tinvert: invert,\n\tclone: clone$2\n});\n\n/**\n * 提供变换扩展\n * @module zrender/mixin/Transformable\n * @author pissang (https://www.github.com/pissang)\n */\n\nvar mIdentity = identity;\n\nvar EPSILON = 5e-5;\n\nfunction isNotAroundZero(val) {\n    return val > EPSILON || val < -EPSILON;\n}\n\n/**\n * @alias module:zrender/mixin/Transformable\n * @constructor\n */\nvar Transformable = function (opts) {\n    opts = opts || {};\n    // If there are no given position, rotation, scale\n    if (!opts.position) {\n        /**\n         * 平移\n         * @type {Array.<number>}\n         * @default [0, 0]\n         */\n        this.position = [0, 0];\n    }\n    if (opts.rotation == null) {\n        /**\n         * 旋转\n         * @type {Array.<number>}\n         * @default 0\n         */\n        this.rotation = 0;\n    }\n    if (!opts.scale) {\n        /**\n         * 缩放\n         * @type {Array.<number>}\n         * @default [1, 1]\n         */\n        this.scale = [1, 1];\n    }\n    /**\n     * 旋转和缩放的原点\n     * @type {Array.<number>}\n     * @default null\n     */\n    this.origin = this.origin || null;\n};\n\nvar transformableProto = Transformable.prototype;\ntransformableProto.transform = null;\n\n/**\n * 判断是否需要有坐标变换\n * 如果有坐标变换, 则从position, rotation, scale以及父节点的transform计算出自身的transform矩阵\n */\ntransformableProto.needLocalTransform = function () {\n    return isNotAroundZero(this.rotation)\n        || isNotAroundZero(this.position[0])\n        || isNotAroundZero(this.position[1])\n        || isNotAroundZero(this.scale[0] - 1)\n        || isNotAroundZero(this.scale[1] - 1);\n};\n\nvar scaleTmp = [];\ntransformableProto.updateTransform = function () {\n    var parent = this.parent;\n    var parentHasTransform = parent && parent.transform;\n    var needLocalTransform = this.needLocalTransform();\n\n    var m = this.transform;\n    if (!(needLocalTransform || parentHasTransform)) {\n        m && mIdentity(m);\n        return;\n    }\n\n    m = m || create$1();\n\n    if (needLocalTransform) {\n        this.getLocalTransform(m);\n    }\n    else {\n        mIdentity(m);\n    }\n\n    // 应用父节点变换\n    if (parentHasTransform) {\n        if (needLocalTransform) {\n            mul$1(m, parent.transform, m);\n        }\n        else {\n            copy$1(m, parent.transform);\n        }\n    }\n    // 保存这个变换矩阵\n    this.transform = m;\n\n    var globalScaleRatio = this.globalScaleRatio;\n    if (globalScaleRatio != null && globalScaleRatio !== 1) {\n        this.getGlobalScale(scaleTmp);\n        var relX = scaleTmp[0] < 0 ? -1 : 1;\n        var relY = scaleTmp[1] < 0 ? -1 : 1;\n        var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0;\n        var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0;\n\n        m[0] *= sx;\n        m[1] *= sx;\n        m[2] *= sy;\n        m[3] *= sy;\n    }\n\n    this.invTransform = this.invTransform || create$1();\n    invert(this.invTransform, m);\n};\n\ntransformableProto.getLocalTransform = function (m) {\n    return Transformable.getLocalTransform(this, m);\n};\n\n/**\n * 将自己的transform应用到context上\n * @param {CanvasRenderingContext2D} ctx\n */\ntransformableProto.setTransform = function (ctx) {\n    var m = this.transform;\n    var dpr = ctx.dpr || 1;\n    if (m) {\n        ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]);\n    }\n    else {\n        ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    }\n};\n\ntransformableProto.restoreTransform = function (ctx) {\n    var dpr = ctx.dpr || 1;\n    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n};\n\nvar tmpTransform = [];\nvar originTransform = create$1();\n\ntransformableProto.setLocalTransform = function (m) {\n    if (!m) {\n        // TODO return or set identity?\n        return;\n    }\n    var sx = m[0] * m[0] + m[1] * m[1];\n    var sy = m[2] * m[2] + m[3] * m[3];\n    var position = this.position;\n    var scale$$1 = this.scale;\n    if (isNotAroundZero(sx - 1)) {\n        sx = Math.sqrt(sx);\n    }\n    if (isNotAroundZero(sy - 1)) {\n        sy = Math.sqrt(sy);\n    }\n    if (m[0] < 0) {\n        sx = -sx;\n    }\n    if (m[3] < 0) {\n        sy = -sy;\n    }\n\n    position[0] = m[4];\n    position[1] = m[5];\n    scale$$1[0] = sx;\n    scale$$1[1] = sy;\n    this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);\n};\n/**\n * 分解`transform`矩阵到`position`, `rotation`, `scale`\n */\ntransformableProto.decomposeTransform = function () {\n    if (!this.transform) {\n        return;\n    }\n    var parent = this.parent;\n    var m = this.transform;\n    if (parent && parent.transform) {\n        // Get local transform and decompose them to position, scale, rotation\n        mul$1(tmpTransform, parent.invTransform, m);\n        m = tmpTransform;\n    }\n    var origin = this.origin;\n    if (origin && (origin[0] || origin[1])) {\n        originTransform[4] = origin[0];\n        originTransform[5] = origin[1];\n        mul$1(tmpTransform, m, originTransform);\n        tmpTransform[4] -= origin[0];\n        tmpTransform[5] -= origin[1];\n        m = tmpTransform;\n    }\n\n    this.setLocalTransform(m);\n};\n\n/**\n * Get global scale\n * @return {Array.<number>}\n */\ntransformableProto.getGlobalScale = function (out) {\n    var m = this.transform;\n    out = out || [];\n    if (!m) {\n        out[0] = 1;\n        out[1] = 1;\n        return out;\n    }\n    out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]);\n    out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]);\n    if (m[0] < 0) {\n        out[0] = -out[0];\n    }\n    if (m[3] < 0) {\n        out[1] = -out[1];\n    }\n    return out;\n};\n/**\n * 变换坐标位置到 shape 的局部坐标空间\n * @method\n * @param {number} x\n * @param {number} y\n * @return {Array.<number>}\n */\ntransformableProto.transformCoordToLocal = function (x, y) {\n    var v2 = [x, y];\n    var invTransform = this.invTransform;\n    if (invTransform) {\n        applyTransform(v2, v2, invTransform);\n    }\n    return v2;\n};\n\n/**\n * 变换局部坐标位置到全局坐标空间\n * @method\n * @param {number} x\n * @param {number} y\n * @return {Array.<number>}\n */\ntransformableProto.transformCoordToGlobal = function (x, y) {\n    var v2 = [x, y];\n    var transform = this.transform;\n    if (transform) {\n        applyTransform(v2, v2, transform);\n    }\n    return v2;\n};\n\n/**\n * @static\n * @param {Object} target\n * @param {Array.<number>} target.origin\n * @param {number} target.rotation\n * @param {Array.<number>} target.position\n * @param {Array.<number>} [m]\n */\nTransformable.getLocalTransform = function (target, m) {\n    m = m || [];\n    mIdentity(m);\n\n    var origin = target.origin;\n    var scale$$1 = target.scale || [1, 1];\n    var rotation = target.rotation || 0;\n    var position = target.position || [0, 0];\n\n    if (origin) {\n        // Translate to origin\n        m[4] -= origin[0];\n        m[5] -= origin[1];\n    }\n    scale$1(m, m, scale$$1);\n    if (rotation) {\n        rotate(m, m, rotation);\n    }\n    if (origin) {\n        // Translate back from origin\n        m[4] += origin[0];\n        m[5] += origin[1];\n    }\n\n    m[4] += position[0];\n    m[5] += position[1];\n\n    return m;\n};\n\n/**\n * 缓动代码来自 https://github.com/sole/tween.js/blob/master/src/Tween.js\n * @see http://sole.github.io/tween.js/examples/03_graphs.html\n * @exports zrender/animation/easing\n */\nvar easing = {\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    linear: function (k) {\n        return k;\n    },\n\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticIn: function (k) {\n        return k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticOut: function (k) {\n        return k * (2 - k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k;\n        }\n        return -0.5 * (--k * (k - 2) - 1);\n    },\n\n    // 三次方的缓动（t^3）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicIn: function (k) {\n        return k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicOut: function (k) {\n        return --k * k * k + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k;\n        }\n        return 0.5 * ((k -= 2) * k * k + 2);\n    },\n\n    // 四次方的缓动（t^4）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticIn: function (k) {\n        return k * k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticOut: function (k) {\n        return 1 - (--k * k * k * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k * k;\n        }\n        return -0.5 * ((k -= 2) * k * k * k - 2);\n    },\n\n    // 五次方的缓动（t^5）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticIn: function (k) {\n        return k * k * k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticOut: function (k) {\n        return --k * k * k * k * k + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k * k * k;\n        }\n        return 0.5 * ((k -= 2) * k * k * k * k + 2);\n    },\n\n    // 正弦曲线的缓动（sin(t)）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalIn: function (k) {\n        return 1 - Math.cos(k * Math.PI / 2);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalOut: function (k) {\n        return Math.sin(k * Math.PI / 2);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalInOut: function (k) {\n        return 0.5 * (1 - Math.cos(Math.PI * k));\n    },\n\n    // 指数曲线的缓动（2^t）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialIn: function (k) {\n        return k === 0 ? 0 : Math.pow(1024, k - 1);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialOut: function (k) {\n        return k === 1 ? 1 : 1 - Math.pow(2, -10 * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialInOut: function (k) {\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if ((k *= 2) < 1) {\n            return 0.5 * Math.pow(1024, k - 1);\n        }\n        return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);\n    },\n\n    // 圆形曲线的缓动（sqrt(1-t^2)）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularIn: function (k) {\n        return 1 - Math.sqrt(1 - k * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularOut: function (k) {\n        return Math.sqrt(1 - (--k * k));\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return -0.5 * (Math.sqrt(1 - k * k) - 1);\n        }\n        return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);\n    },\n\n    // 创建类似于弹簧在停止前来回振荡的动画\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticIn: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        return -(a * Math.pow(2, 10 * (k -= 1))\n                    * Math.sin((k - s) * (2 * Math.PI) / p));\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticOut: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        return (a * Math.pow(2, -10 * k)\n                    * Math.sin((k - s) * (2 * Math.PI) / p) + 1);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticInOut: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        if ((k *= 2) < 1) {\n            return -0.5 * (a * Math.pow(2, 10 * (k -= 1))\n                * Math.sin((k - s) * (2 * Math.PI) / p));\n        }\n        return a * Math.pow(2, -10 * (k -= 1))\n                * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;\n\n    },\n\n    // 在某一动画开始沿指示的路径进行动画处理前稍稍收回该动画的移动\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backIn: function (k) {\n        var s = 1.70158;\n        return k * k * ((s + 1) * k - s);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backOut: function (k) {\n        var s = 1.70158;\n        return --k * k * ((s + 1) * k + s) + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backInOut: function (k) {\n        var s = 1.70158 * 1.525;\n        if ((k *= 2) < 1) {\n            return 0.5 * (k * k * ((s + 1) * k - s));\n        }\n        return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);\n    },\n\n    // 创建弹跳效果\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceIn: function (k) {\n        return 1 - easing.bounceOut(1 - k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceOut: function (k) {\n        if (k < (1 / 2.75)) {\n            return 7.5625 * k * k;\n        }\n        else if (k < (2 / 2.75)) {\n            return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;\n        }\n        else if (k < (2.5 / 2.75)) {\n            return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;\n        }\n        else {\n            return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;\n        }\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceInOut: function (k) {\n        if (k < 0.5) {\n            return easing.bounceIn(k * 2) * 0.5;\n        }\n        return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;\n    }\n};\n\n/**\n * 动画主控制器\n * @config target 动画对象，可以是数组，如果是数组的话会批量分发onframe等事件\n * @config life(1000) 动画时长\n * @config delay(0) 动画延迟时间\n * @config loop(true)\n * @config gap(0) 循环的间隔时间\n * @config onframe\n * @config easing(optional)\n * @config ondestroy(optional)\n * @config onrestart(optional)\n *\n * TODO pause\n */\n\nfunction Clip(options) {\n\n    this._target = options.target;\n\n    // 生命周期\n    this._life = options.life || 1000;\n    // 延时\n    this._delay = options.delay || 0;\n    // 开始时间\n    // this._startTime = new Date().getTime() + this._delay;// 单位毫秒\n    this._initialized = false;\n\n    // 是否循环\n    this.loop = options.loop == null ? false : options.loop;\n\n    this.gap = options.gap || 0;\n\n    this.easing = options.easing || 'Linear';\n\n    this.onframe = options.onframe;\n    this.ondestroy = options.ondestroy;\n    this.onrestart = options.onrestart;\n\n    this._pausedTime = 0;\n    this._paused = false;\n}\n\nClip.prototype = {\n\n    constructor: Clip,\n\n    step: function (globalTime, deltaTime) {\n        // Set startTime on first step, or _startTime may has milleseconds different between clips\n        // PENDING\n        if (!this._initialized) {\n            this._startTime = globalTime + this._delay;\n            this._initialized = true;\n        }\n\n        if (this._paused) {\n            this._pausedTime += deltaTime;\n            return;\n        }\n\n        var percent = (globalTime - this._startTime - this._pausedTime) / this._life;\n\n        // 还没开始\n        if (percent < 0) {\n            return;\n        }\n\n        percent = Math.min(percent, 1);\n\n        var easing$$1 = this.easing;\n        var easingFunc = typeof easing$$1 === 'string' ? easing[easing$$1] : easing$$1;\n        var schedule = typeof easingFunc === 'function'\n            ? easingFunc(percent)\n            : percent;\n\n        this.fire('frame', schedule);\n\n        // 结束\n        if (percent === 1) {\n            if (this.loop) {\n                this.restart(globalTime);\n                // 重新开始周期\n                // 抛出而不是直接调用事件直到 stage.update 后再统一调用这些事件\n                return 'restart';\n            }\n\n            // 动画完成将这个控制器标识为待删除\n            // 在Animation.update中进行批量删除\n            this._needsRemove = true;\n            return 'destroy';\n        }\n\n        return null;\n    },\n\n    restart: function (globalTime) {\n        var remainder = (globalTime - this._startTime - this._pausedTime) % this._life;\n        this._startTime = globalTime - remainder + this.gap;\n        this._pausedTime = 0;\n\n        this._needsRemove = false;\n    },\n\n    fire: function (eventType, arg) {\n        eventType = 'on' + eventType;\n        if (this[eventType]) {\n            this[eventType](this._target, arg);\n        }\n    },\n\n    pause: function () {\n        this._paused = true;\n    },\n\n    resume: function () {\n        this._paused = false;\n    }\n};\n\n// Simple LRU cache use doubly linked list\n// @module zrender/core/LRU\n\n/**\n * Simple double linked list. Compared with array, it has O(1) remove operation.\n * @constructor\n */\nvar LinkedList = function () {\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.head = null;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.tail = null;\n\n    this._len = 0;\n};\n\nvar linkedListProto = LinkedList.prototype;\n/**\n * Insert a new value at the tail\n * @param  {} val\n * @return {module:zrender/core/LRU~Entry}\n */\nlinkedListProto.insert = function (val) {\n    var entry = new Entry(val);\n    this.insertEntry(entry);\n    return entry;\n};\n\n/**\n * Insert an entry at the tail\n * @param  {module:zrender/core/LRU~Entry} entry\n */\nlinkedListProto.insertEntry = function (entry) {\n    if (!this.head) {\n        this.head = this.tail = entry;\n    }\n    else {\n        this.tail.next = entry;\n        entry.prev = this.tail;\n        entry.next = null;\n        this.tail = entry;\n    }\n    this._len++;\n};\n\n/**\n * Remove entry.\n * @param  {module:zrender/core/LRU~Entry} entry\n */\nlinkedListProto.remove = function (entry) {\n    var prev = entry.prev;\n    var next = entry.next;\n    if (prev) {\n        prev.next = next;\n    }\n    else {\n        // Is head\n        this.head = next;\n    }\n    if (next) {\n        next.prev = prev;\n    }\n    else {\n        // Is tail\n        this.tail = prev;\n    }\n    entry.next = entry.prev = null;\n    this._len--;\n};\n\n/**\n * @return {number}\n */\nlinkedListProto.len = function () {\n    return this._len;\n};\n\n/**\n * Clear list\n */\nlinkedListProto.clear = function () {\n    this.head = this.tail = null;\n    this._len = 0;\n};\n\n/**\n * @constructor\n * @param {} val\n */\nvar Entry = function (val) {\n    /**\n     * @type {}\n     */\n    this.value = val;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.next;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.prev;\n};\n\n/**\n * LRU Cache\n * @constructor\n * @alias module:zrender/core/LRU\n */\nvar LRU = function (maxSize) {\n\n    this._list = new LinkedList();\n\n    this._map = {};\n\n    this._maxSize = maxSize || 10;\n\n    this._lastRemovedEntry = null;\n};\n\nvar LRUProto = LRU.prototype;\n\n/**\n * @param  {string} key\n * @param  {} value\n * @return {} Removed value\n */\nLRUProto.put = function (key, value) {\n    var list = this._list;\n    var map = this._map;\n    var removed = null;\n    if (map[key] == null) {\n        var len = list.len();\n        // Reuse last removed entry\n        var entry = this._lastRemovedEntry;\n\n        if (len >= this._maxSize && len > 0) {\n            // Remove the least recently used\n            var leastUsedEntry = list.head;\n            list.remove(leastUsedEntry);\n            delete map[leastUsedEntry.key];\n\n            removed = leastUsedEntry.value;\n            this._lastRemovedEntry = leastUsedEntry;\n        }\n\n        if (entry) {\n            entry.value = value;\n        }\n        else {\n            entry = new Entry(value);\n        }\n        entry.key = key;\n        list.insertEntry(entry);\n        map[key] = entry;\n    }\n\n    return removed;\n};\n\n/**\n * @param  {string} key\n * @return {}\n */\nLRUProto.get = function (key) {\n    var entry = this._map[key];\n    var list = this._list;\n    if (entry != null) {\n        // Put the latest used entry in the tail\n        if (entry !== list.tail) {\n            list.remove(entry);\n            list.insertEntry(entry);\n        }\n\n        return entry.value;\n    }\n};\n\n/**\n * Clear the cache\n */\nLRUProto.clear = function () {\n    this._list.clear();\n    this._map = {};\n};\n\nvar kCSSColorTable = {\n    'transparent': [0, 0, 0, 0], 'aliceblue': [240, 248, 255, 1],\n    'antiquewhite': [250, 235, 215, 1], 'aqua': [0, 255, 255, 1],\n    'aquamarine': [127, 255, 212, 1], 'azure': [240, 255, 255, 1],\n    'beige': [245, 245, 220, 1], 'bisque': [255, 228, 196, 1],\n    'black': [0, 0, 0, 1], 'blanchedalmond': [255, 235, 205, 1],\n    'blue': [0, 0, 255, 1], 'blueviolet': [138, 43, 226, 1],\n    'brown': [165, 42, 42, 1], 'burlywood': [222, 184, 135, 1],\n    'cadetblue': [95, 158, 160, 1], 'chartreuse': [127, 255, 0, 1],\n    'chocolate': [210, 105, 30, 1], 'coral': [255, 127, 80, 1],\n    'cornflowerblue': [100, 149, 237, 1], 'cornsilk': [255, 248, 220, 1],\n    'crimson': [220, 20, 60, 1], 'cyan': [0, 255, 255, 1],\n    'darkblue': [0, 0, 139, 1], 'darkcyan': [0, 139, 139, 1],\n    'darkgoldenrod': [184, 134, 11, 1], 'darkgray': [169, 169, 169, 1],\n    'darkgreen': [0, 100, 0, 1], 'darkgrey': [169, 169, 169, 1],\n    'darkkhaki': [189, 183, 107, 1], 'darkmagenta': [139, 0, 139, 1],\n    'darkolivegreen': [85, 107, 47, 1], 'darkorange': [255, 140, 0, 1],\n    'darkorchid': [153, 50, 204, 1], 'darkred': [139, 0, 0, 1],\n    'darksalmon': [233, 150, 122, 1], 'darkseagreen': [143, 188, 143, 1],\n    'darkslateblue': [72, 61, 139, 1], 'darkslategray': [47, 79, 79, 1],\n    'darkslategrey': [47, 79, 79, 1], 'darkturquoise': [0, 206, 209, 1],\n    'darkviolet': [148, 0, 211, 1], 'deeppink': [255, 20, 147, 1],\n    'deepskyblue': [0, 191, 255, 1], 'dimgray': [105, 105, 105, 1],\n    'dimgrey': [105, 105, 105, 1], 'dodgerblue': [30, 144, 255, 1],\n    'firebrick': [178, 34, 34, 1], 'floralwhite': [255, 250, 240, 1],\n    'forestgreen': [34, 139, 34, 1], 'fuchsia': [255, 0, 255, 1],\n    'gainsboro': [220, 220, 220, 1], 'ghostwhite': [248, 248, 255, 1],\n    'gold': [255, 215, 0, 1], 'goldenrod': [218, 165, 32, 1],\n    'gray': [128, 128, 128, 1], 'green': [0, 128, 0, 1],\n    'greenyellow': [173, 255, 47, 1], 'grey': [128, 128, 128, 1],\n    'honeydew': [240, 255, 240, 1], 'hotpink': [255, 105, 180, 1],\n    'indianred': [205, 92, 92, 1], 'indigo': [75, 0, 130, 1],\n    'ivory': [255, 255, 240, 1], 'khaki': [240, 230, 140, 1],\n    'lavender': [230, 230, 250, 1], 'lavenderblush': [255, 240, 245, 1],\n    'lawngreen': [124, 252, 0, 1], 'lemonchiffon': [255, 250, 205, 1],\n    'lightblue': [173, 216, 230, 1], 'lightcoral': [240, 128, 128, 1],\n    'lightcyan': [224, 255, 255, 1], 'lightgoldenrodyellow': [250, 250, 210, 1],\n    'lightgray': [211, 211, 211, 1], 'lightgreen': [144, 238, 144, 1],\n    'lightgrey': [211, 211, 211, 1], 'lightpink': [255, 182, 193, 1],\n    'lightsalmon': [255, 160, 122, 1], 'lightseagreen': [32, 178, 170, 1],\n    'lightskyblue': [135, 206, 250, 1], 'lightslategray': [119, 136, 153, 1],\n    'lightslategrey': [119, 136, 153, 1], 'lightsteelblue': [176, 196, 222, 1],\n    'lightyellow': [255, 255, 224, 1], 'lime': [0, 255, 0, 1],\n    'limegreen': [50, 205, 50, 1], 'linen': [250, 240, 230, 1],\n    'magenta': [255, 0, 255, 1], 'maroon': [128, 0, 0, 1],\n    'mediumaquamarine': [102, 205, 170, 1], 'mediumblue': [0, 0, 205, 1],\n    'mediumorchid': [186, 85, 211, 1], 'mediumpurple': [147, 112, 219, 1],\n    'mediumseagreen': [60, 179, 113, 1], 'mediumslateblue': [123, 104, 238, 1],\n    'mediumspringgreen': [0, 250, 154, 1], 'mediumturquoise': [72, 209, 204, 1],\n    'mediumvioletred': [199, 21, 133, 1], 'midnightblue': [25, 25, 112, 1],\n    'mintcream': [245, 255, 250, 1], 'mistyrose': [255, 228, 225, 1],\n    'moccasin': [255, 228, 181, 1], 'navajowhite': [255, 222, 173, 1],\n    'navy': [0, 0, 128, 1], 'oldlace': [253, 245, 230, 1],\n    'olive': [128, 128, 0, 1], 'olivedrab': [107, 142, 35, 1],\n    'orange': [255, 165, 0, 1], 'orangered': [255, 69, 0, 1],\n    'orchid': [218, 112, 214, 1], 'palegoldenrod': [238, 232, 170, 1],\n    'palegreen': [152, 251, 152, 1], 'paleturquoise': [175, 238, 238, 1],\n    'palevioletred': [219, 112, 147, 1], 'papayawhip': [255, 239, 213, 1],\n    'peachpuff': [255, 218, 185, 1], 'peru': [205, 133, 63, 1],\n    'pink': [255, 192, 203, 1], 'plum': [221, 160, 221, 1],\n    'powderblue': [176, 224, 230, 1], 'purple': [128, 0, 128, 1],\n    'red': [255, 0, 0, 1], 'rosybrown': [188, 143, 143, 1],\n    'royalblue': [65, 105, 225, 1], 'saddlebrown': [139, 69, 19, 1],\n    'salmon': [250, 128, 114, 1], 'sandybrown': [244, 164, 96, 1],\n    'seagreen': [46, 139, 87, 1], 'seashell': [255, 245, 238, 1],\n    'sienna': [160, 82, 45, 1], 'silver': [192, 192, 192, 1],\n    'skyblue': [135, 206, 235, 1], 'slateblue': [106, 90, 205, 1],\n    'slategray': [112, 128, 144, 1], 'slategrey': [112, 128, 144, 1],\n    'snow': [255, 250, 250, 1], 'springgreen': [0, 255, 127, 1],\n    'steelblue': [70, 130, 180, 1], 'tan': [210, 180, 140, 1],\n    'teal': [0, 128, 128, 1], 'thistle': [216, 191, 216, 1],\n    'tomato': [255, 99, 71, 1], 'turquoise': [64, 224, 208, 1],\n    'violet': [238, 130, 238, 1], 'wheat': [245, 222, 179, 1],\n    'white': [255, 255, 255, 1], 'whitesmoke': [245, 245, 245, 1],\n    'yellow': [255, 255, 0, 1], 'yellowgreen': [154, 205, 50, 1]\n};\n\nfunction clampCssByte(i) {  // Clamp to integer 0 .. 255.\n    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).\n    return i < 0 ? 0 : i > 255 ? 255 : i;\n}\n\nfunction clampCssAngle(i) {  // Clamp to integer 0 .. 360.\n    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).\n    return i < 0 ? 0 : i > 360 ? 360 : i;\n}\n\nfunction clampCssFloat(f) {  // Clamp to float 0.0 .. 1.0.\n    return f < 0 ? 0 : f > 1 ? 1 : f;\n}\n\nfunction parseCssInt(str) {  // int or percentage.\n    if (str.length && str.charAt(str.length - 1) === '%') {\n        return clampCssByte(parseFloat(str) / 100 * 255);\n    }\n    return clampCssByte(parseInt(str, 10));\n}\n\nfunction parseCssFloat(str) {  // float or percentage.\n    if (str.length && str.charAt(str.length - 1) === '%') {\n        return clampCssFloat(parseFloat(str) / 100);\n    }\n    return clampCssFloat(parseFloat(str));\n}\n\nfunction cssHueToRgb(m1, m2, h) {\n    if (h < 0) {\n        h += 1;\n    }\n    else if (h > 1) {\n        h -= 1;\n    }\n\n    if (h * 6 < 1) {\n        return m1 + (m2 - m1) * h * 6;\n    }\n    if (h * 2 < 1) {\n        return m2;\n    }\n    if (h * 3 < 2) {\n        return m1 + (m2 - m1) * (2 / 3 - h) * 6;\n    }\n    return m1;\n}\n\nfunction lerpNumber(a, b, p) {\n    return a + (b - a) * p;\n}\n\nfunction setRgba(out, r, g, b, a) {\n    out[0] = r; out[1] = g; out[2] = b; out[3] = a;\n    return out;\n}\nfunction copyRgba(out, a) {\n    out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3];\n    return out;\n}\n\nvar colorCache = new LRU(20);\nvar lastRemovedArr = null;\n\nfunction putToCache(colorStr, rgbaArr) {\n    // Reuse removed array\n    if (lastRemovedArr) {\n        copyRgba(lastRemovedArr, rgbaArr);\n    }\n    lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice()));\n}\n\n/**\n * @param {string} colorStr\n * @param {Array.<number>} out\n * @return {Array.<number>}\n * @memberOf module:zrender/util/color\n */\nfunction parse(colorStr, rgbaArr) {\n    if (!colorStr) {\n        return;\n    }\n    rgbaArr = rgbaArr || [];\n\n    var cached = colorCache.get(colorStr);\n    if (cached) {\n        return copyRgba(rgbaArr, cached);\n    }\n\n    // colorStr may be not string\n    colorStr = colorStr + '';\n    // Remove all whitespace, not compliant, but should just be more accepting.\n    var str = colorStr.replace(/ /g, '').toLowerCase();\n\n    // Color keywords (and transparent) lookup.\n    if (str in kCSSColorTable) {\n        copyRgba(rgbaArr, kCSSColorTable[str]);\n        putToCache(colorStr, rgbaArr);\n        return rgbaArr;\n    }\n\n    // #abc and #abc123 syntax.\n    if (str.charAt(0) === '#') {\n        if (str.length === 4) {\n            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n            if (!(iv >= 0 && iv <= 0xfff)) {\n                setRgba(rgbaArr, 0, 0, 0, 1);\n                return;  // Covers NaN.\n            }\n            setRgba(rgbaArr,\n                ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8),\n                (iv & 0xf0) | ((iv & 0xf0) >> 4),\n                (iv & 0xf) | ((iv & 0xf) << 4),\n                1\n            );\n            putToCache(colorStr, rgbaArr);\n            return rgbaArr;\n        }\n        else if (str.length === 7) {\n            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n            if (!(iv >= 0 && iv <= 0xffffff)) {\n                setRgba(rgbaArr, 0, 0, 0, 1);\n                return;  // Covers NaN.\n            }\n            setRgba(rgbaArr,\n                (iv & 0xff0000) >> 16,\n                (iv & 0xff00) >> 8,\n                iv & 0xff,\n                1\n            );\n            putToCache(colorStr, rgbaArr);\n            return rgbaArr;\n        }\n\n        return;\n    }\n    var op = str.indexOf('(');\n    var ep = str.indexOf(')');\n    if (op !== -1 && ep + 1 === str.length) {\n        var fname = str.substr(0, op);\n        var params = str.substr(op + 1, ep - (op + 1)).split(',');\n        var alpha = 1;  // To allow case fallthrough.\n        switch (fname) {\n            case 'rgba':\n                if (params.length !== 4) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                alpha = parseCssFloat(params.pop()); // jshint ignore:line\n            // Fall through.\n            case 'rgb':\n                if (params.length !== 3) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                setRgba(rgbaArr,\n                    parseCssInt(params[0]),\n                    parseCssInt(params[1]),\n                    parseCssInt(params[2]),\n                    alpha\n                );\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            case 'hsla':\n                if (params.length !== 4) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                params[3] = parseCssFloat(params[3]);\n                hsla2rgba(params, rgbaArr);\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            case 'hsl':\n                if (params.length !== 3) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                hsla2rgba(params, rgbaArr);\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            default:\n                return;\n        }\n    }\n\n    setRgba(rgbaArr, 0, 0, 0, 1);\n    return;\n}\n\n/**\n * @param {Array.<number>} hsla\n * @param {Array.<number>} rgba\n * @return {Array.<number>} rgba\n */\nfunction hsla2rgba(hsla, rgba) {\n    var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360;  // 0 .. 1\n    // NOTE(deanm): According to the CSS spec s/l should only be\n    // percentages, but we don't bother and let float or percentage.\n    var s = parseCssFloat(hsla[1]);\n    var l = parseCssFloat(hsla[2]);\n    var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;\n    var m1 = l * 2 - m2;\n\n    rgba = rgba || [];\n    setRgba(rgba,\n        clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255),\n        clampCssByte(cssHueToRgb(m1, m2, h) * 255),\n        clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255),\n        1\n    );\n\n    if (hsla.length === 4) {\n        rgba[3] = hsla[3];\n    }\n\n    return rgba;\n}\n\n/**\n * @param {Array.<number>} rgba\n * @return {Array.<number>} hsla\n */\nfunction rgba2hsla(rgba) {\n    if (!rgba) {\n        return;\n    }\n\n    // RGB from 0 to 255\n    var R = rgba[0] / 255;\n    var G = rgba[1] / 255;\n    var B = rgba[2] / 255;\n\n    var vMin = Math.min(R, G, B); // Min. value of RGB\n    var vMax = Math.max(R, G, B); // Max. value of RGB\n    var delta = vMax - vMin; // Delta RGB value\n\n    var L = (vMax + vMin) / 2;\n    var H;\n    var S;\n    // HSL results from 0 to 1\n    if (delta === 0) {\n        H = 0;\n        S = 0;\n    }\n    else {\n        if (L < 0.5) {\n            S = delta / (vMax + vMin);\n        }\n        else {\n            S = delta / (2 - vMax - vMin);\n        }\n\n        var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta;\n        var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta;\n        var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta;\n\n        if (R === vMax) {\n            H = deltaB - deltaG;\n        }\n        else if (G === vMax) {\n            H = (1 / 3) + deltaR - deltaB;\n        }\n        else if (B === vMax) {\n            H = (2 / 3) + deltaG - deltaR;\n        }\n\n        if (H < 0) {\n            H += 1;\n        }\n\n        if (H > 1) {\n            H -= 1;\n        }\n    }\n\n    var hsla = [H * 360, S, L];\n\n    if (rgba[3] != null) {\n        hsla.push(rgba[3]);\n    }\n\n    return hsla;\n}\n\n/**\n * @param {string} color\n * @param {number} level\n * @return {string}\n * @memberOf module:zrender/util/color\n */\nfunction lift(color, level) {\n    var colorArr = parse(color);\n    if (colorArr) {\n        for (var i = 0; i < 3; i++) {\n            if (level < 0) {\n                colorArr[i] = colorArr[i] * (1 - level) | 0;\n            }\n            else {\n                colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0;\n            }\n            if (colorArr[i] > 255) {\n                colorArr[i] = 255;\n            }\n            else if (color[i] < 0) {\n                colorArr[i] = 0;\n            }\n        }\n        return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');\n    }\n}\n\n/**\n * @param {string} color\n * @return {string}\n * @memberOf module:zrender/util/color\n */\nfunction toHex(color) {\n    var colorArr = parse(color);\n    if (colorArr) {\n        return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1);\n    }\n}\n\n/**\n * Map value to color. Faster than lerp methods because color is represented by rgba array.\n * @param {number} normalizedValue A float between 0 and 1.\n * @param {Array.<Array.<number>>} colors List of rgba color array\n * @param {Array.<number>} [out] Mapped gba color array\n * @return {Array.<number>} will be null/undefined if input illegal.\n */\nfunction fastLerp(normalizedValue, colors, out) {\n    if (!(colors && colors.length)\n        || !(normalizedValue >= 0 && normalizedValue <= 1)\n    ) {\n        return;\n    }\n\n    out = out || [];\n\n    var value = normalizedValue * (colors.length - 1);\n    var leftIndex = Math.floor(value);\n    var rightIndex = Math.ceil(value);\n    var leftColor = colors[leftIndex];\n    var rightColor = colors[rightIndex];\n    var dv = value - leftIndex;\n    out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv));\n    out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv));\n    out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv));\n    out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv));\n\n    return out;\n}\n\n/**\n * @deprecated\n */\nvar fastMapToColor = fastLerp;\n\n/**\n * @param {number} normalizedValue A float between 0 and 1.\n * @param {Array.<string>} colors Color list.\n * @param {boolean=} fullOutput Default false.\n * @return {(string|Object)} Result color. If fullOutput,\n *                           return {color: ..., leftIndex: ..., rightIndex: ..., value: ...},\n * @memberOf module:zrender/util/color\n */\nfunction lerp$1(normalizedValue, colors, fullOutput) {\n    if (!(colors && colors.length)\n        || !(normalizedValue >= 0 && normalizedValue <= 1)\n    ) {\n        return;\n    }\n\n    var value = normalizedValue * (colors.length - 1);\n    var leftIndex = Math.floor(value);\n    var rightIndex = Math.ceil(value);\n    var leftColor = parse(colors[leftIndex]);\n    var rightColor = parse(colors[rightIndex]);\n    var dv = value - leftIndex;\n\n    var color = stringify(\n        [\n            clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)),\n            clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)),\n            clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)),\n            clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv))\n        ],\n        'rgba'\n    );\n\n    return fullOutput\n        ? {\n            color: color,\n            leftIndex: leftIndex,\n            rightIndex: rightIndex,\n            value: value\n        }\n        : color;\n}\n\n/**\n * @deprecated\n */\nvar mapToColor = lerp$1;\n\n/**\n * @param {string} color\n * @param {number=} h 0 ~ 360, ignore when null.\n * @param {number=} s 0 ~ 1, ignore when null.\n * @param {number=} l 0 ~ 1, ignore when null.\n * @return {string} Color string in rgba format.\n * @memberOf module:zrender/util/color\n */\nfunction modifyHSL(color, h, s, l) {\n    color = parse(color);\n\n    if (color) {\n        color = rgba2hsla(color);\n        h != null && (color[0] = clampCssAngle(h));\n        s != null && (color[1] = parseCssFloat(s));\n        l != null && (color[2] = parseCssFloat(l));\n\n        return stringify(hsla2rgba(color), 'rgba');\n    }\n}\n\n/**\n * @param {string} color\n * @param {number=} alpha 0 ~ 1\n * @return {string} Color string in rgba format.\n * @memberOf module:zrender/util/color\n */\nfunction modifyAlpha(color, alpha) {\n    color = parse(color);\n\n    if (color && alpha != null) {\n        color[3] = clampCssFloat(alpha);\n        return stringify(color, 'rgba');\n    }\n}\n\n/**\n * @param {Array.<number>} arrColor like [12,33,44,0.4]\n * @param {string} type 'rgba', 'hsva', ...\n * @return {string} Result color. (If input illegal, return undefined).\n */\nfunction stringify(arrColor, type) {\n    if (!arrColor || !arrColor.length) {\n        return;\n    }\n    var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];\n    if (type === 'rgba' || type === 'hsva' || type === 'hsla') {\n        colorStr += ',' + arrColor[3];\n    }\n    return type + '(' + colorStr + ')';\n}\n\n\nvar color = (Object.freeze || Object)({\n\tparse: parse,\n\tlift: lift,\n\ttoHex: toHex,\n\tfastLerp: fastLerp,\n\tfastMapToColor: fastMapToColor,\n\tlerp: lerp$1,\n\tmapToColor: mapToColor,\n\tmodifyHSL: modifyHSL,\n\tmodifyAlpha: modifyAlpha,\n\tstringify: stringify\n});\n\n/**\n * @module echarts/animation/Animator\n */\n\nvar arraySlice = Array.prototype.slice;\n\nfunction defaultGetter(target, key) {\n    return target[key];\n}\n\nfunction defaultSetter(target, key, value) {\n    target[key] = value;\n}\n\n/**\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} percent\n * @return {number}\n */\nfunction interpolateNumber(p0, p1, percent) {\n    return (p1 - p0) * percent + p0;\n}\n\n/**\n * @param  {string} p0\n * @param  {string} p1\n * @param  {number} percent\n * @return {string}\n */\nfunction interpolateString(p0, p1, percent) {\n    return percent > 0.5 ? p1 : p0;\n}\n\n/**\n * @param  {Array} p0\n * @param  {Array} p1\n * @param  {number} percent\n * @param  {Array} out\n * @param  {number} arrDim\n */\nfunction interpolateArray(p0, p1, percent, out, arrDim) {\n    var len = p0.length;\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            out[i] = interpolateNumber(p0[i], p1[i], percent);\n        }\n    }\n    else {\n        var len2 = len && p0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                out[i][j] = interpolateNumber(\n                    p0[i][j], p1[i][j], percent\n                );\n            }\n        }\n    }\n}\n\n// arr0 is source array, arr1 is target array.\n// Do some preprocess to avoid error happened when interpolating from arr0 to arr1\nfunction fillArr(arr0, arr1, arrDim) {\n    var arr0Len = arr0.length;\n    var arr1Len = arr1.length;\n    if (arr0Len !== arr1Len) {\n        // FIXME Not work for TypedArray\n        var isPreviousLarger = arr0Len > arr1Len;\n        if (isPreviousLarger) {\n            // Cut the previous\n            arr0.length = arr1Len;\n        }\n        else {\n            // Fill the previous\n            for (var i = arr0Len; i < arr1Len; i++) {\n                arr0.push(\n                    arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i])\n                );\n            }\n        }\n    }\n    // Handling NaN value\n    var len2 = arr0[0] && arr0[0].length;\n    for (var i = 0; i < arr0.length; i++) {\n        if (arrDim === 1) {\n            if (isNaN(arr0[i])) {\n                arr0[i] = arr1[i];\n            }\n        }\n        else {\n            for (var j = 0; j < len2; j++) {\n                if (isNaN(arr0[i][j])) {\n                    arr0[i][j] = arr1[i][j];\n                }\n            }\n        }\n    }\n}\n\n/**\n * @param  {Array} arr0\n * @param  {Array} arr1\n * @param  {number} arrDim\n * @return {boolean}\n */\nfunction isArraySame(arr0, arr1, arrDim) {\n    if (arr0 === arr1) {\n        return true;\n    }\n    var len = arr0.length;\n    if (len !== arr1.length) {\n        return false;\n    }\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            if (arr0[i] !== arr1[i]) {\n                return false;\n            }\n        }\n    }\n    else {\n        var len2 = arr0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                if (arr0[i][j] !== arr1[i][j]) {\n                    return false;\n                }\n            }\n        }\n    }\n    return true;\n}\n\n/**\n * Catmull Rom interpolate array\n * @param  {Array} p0\n * @param  {Array} p1\n * @param  {Array} p2\n * @param  {Array} p3\n * @param  {number} t\n * @param  {number} t2\n * @param  {number} t3\n * @param  {Array} out\n * @param  {number} arrDim\n */\nfunction catmullRomInterpolateArray(\n    p0, p1, p2, p3, t, t2, t3, out, arrDim\n) {\n    var len = p0.length;\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            out[i] = catmullRomInterpolate(\n                p0[i], p1[i], p2[i], p3[i], t, t2, t3\n            );\n        }\n    }\n    else {\n        var len2 = p0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                out[i][j] = catmullRomInterpolate(\n                    p0[i][j], p1[i][j], p2[i][j], p3[i][j],\n                    t, t2, t3\n                );\n            }\n        }\n    }\n}\n\n/**\n * Catmull Rom interpolate number\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @param  {number} t2\n * @param  {number} t3\n * @return {number}\n */\nfunction catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {\n    var v0 = (p2 - p0) * 0.5;\n    var v1 = (p3 - p1) * 0.5;\n    return (2 * (p1 - p2) + v0 + v1) * t3\n            + (-3 * (p1 - p2) - 2 * v0 - v1) * t2\n            + v0 * t + p1;\n}\n\nfunction cloneValue(value) {\n    if (isArrayLike(value)) {\n        var len = value.length;\n        if (isArrayLike(value[0])) {\n            var ret = [];\n            for (var i = 0; i < len; i++) {\n                ret.push(arraySlice.call(value[i]));\n            }\n            return ret;\n        }\n\n        return arraySlice.call(value);\n    }\n\n    return value;\n}\n\nfunction rgba2String(rgba) {\n    rgba[0] = Math.floor(rgba[0]);\n    rgba[1] = Math.floor(rgba[1]);\n    rgba[2] = Math.floor(rgba[2]);\n\n    return 'rgba(' + rgba.join(',') + ')';\n}\n\nfunction getArrayDim(keyframes) {\n    var lastValue = keyframes[keyframes.length - 1].value;\n    return isArrayLike(lastValue && lastValue[0]) ? 2 : 1;\n}\n\nfunction createTrackClip(animator, easing, oneTrackDone, keyframes, propName, forceAnimate) {\n    var getter = animator._getter;\n    var setter = animator._setter;\n    var useSpline = easing === 'spline';\n\n    var trackLen = keyframes.length;\n    if (!trackLen) {\n        return;\n    }\n    // Guess data type\n    var firstVal = keyframes[0].value;\n    var isValueArray = isArrayLike(firstVal);\n    var isValueColor = false;\n    var isValueString = false;\n\n    // For vertices morphing\n    var arrDim = isValueArray ? getArrayDim(keyframes) : 0;\n\n    var trackMaxTime;\n    // Sort keyframe as ascending\n    keyframes.sort(function (a, b) {\n        return a.time - b.time;\n    });\n\n    trackMaxTime = keyframes[trackLen - 1].time;\n    // Percents of each keyframe\n    var kfPercents = [];\n    // Value of each keyframe\n    var kfValues = [];\n    var prevValue = keyframes[0].value;\n    var isAllValueEqual = true;\n    for (var i = 0; i < trackLen; i++) {\n        kfPercents.push(keyframes[i].time / trackMaxTime);\n        // Assume value is a color when it is a string\n        var value = keyframes[i].value;\n\n        // Check if value is equal, deep check if value is array\n        if (!((isValueArray && isArraySame(value, prevValue, arrDim))\n            || (!isValueArray && value === prevValue))) {\n            isAllValueEqual = false;\n        }\n        prevValue = value;\n\n        // Try converting a string to a color array\n        if (typeof value === 'string') {\n            var colorArray = parse(value);\n            if (colorArray) {\n                value = colorArray;\n                isValueColor = true;\n            }\n            else {\n                isValueString = true;\n            }\n        }\n        kfValues.push(value);\n    }\n    if (!forceAnimate && isAllValueEqual) {\n        return;\n    }\n\n    var lastValue = kfValues[trackLen - 1];\n    // Polyfill array and NaN value\n    for (var i = 0; i < trackLen - 1; i++) {\n        if (isValueArray) {\n            fillArr(kfValues[i], lastValue, arrDim);\n        }\n        else {\n            if (isNaN(kfValues[i]) && !isNaN(lastValue) && !isValueString && !isValueColor) {\n                kfValues[i] = lastValue;\n            }\n        }\n    }\n    isValueArray && fillArr(getter(animator._target, propName), lastValue, arrDim);\n\n    // Cache the key of last frame to speed up when\n    // animation playback is sequency\n    var lastFrame = 0;\n    var lastFramePercent = 0;\n    var start;\n    var w;\n    var p0;\n    var p1;\n    var p2;\n    var p3;\n\n    if (isValueColor) {\n        var rgba = [0, 0, 0, 0];\n    }\n\n    var onframe = function (target, percent) {\n        // Find the range keyframes\n        // kf1-----kf2---------current--------kf3\n        // find kf2 and kf3 and do interpolation\n        var frame;\n        // In the easing function like elasticOut, percent may less than 0\n        if (percent < 0) {\n            frame = 0;\n        }\n        else if (percent < lastFramePercent) {\n            // Start from next key\n            // PENDING start from lastFrame ?\n            start = Math.min(lastFrame + 1, trackLen - 1);\n            for (frame = start; frame >= 0; frame--) {\n                if (kfPercents[frame] <= percent) {\n                    break;\n                }\n            }\n            // PENDING really need to do this ?\n            frame = Math.min(frame, trackLen - 2);\n        }\n        else {\n            for (frame = lastFrame; frame < trackLen; frame++) {\n                if (kfPercents[frame] > percent) {\n                    break;\n                }\n            }\n            frame = Math.min(frame - 1, trackLen - 2);\n        }\n        lastFrame = frame;\n        lastFramePercent = percent;\n\n        var range = (kfPercents[frame + 1] - kfPercents[frame]);\n        if (range === 0) {\n            return;\n        }\n        else {\n            w = (percent - kfPercents[frame]) / range;\n        }\n        if (useSpline) {\n            p1 = kfValues[frame];\n            p0 = kfValues[frame === 0 ? frame : frame - 1];\n            p2 = kfValues[frame > trackLen - 2 ? trackLen - 1 : frame + 1];\n            p3 = kfValues[frame > trackLen - 3 ? trackLen - 1 : frame + 2];\n            if (isValueArray) {\n                catmullRomInterpolateArray(\n                    p0, p1, p2, p3, w, w * w, w * w * w,\n                    getter(target, propName),\n                    arrDim\n                );\n            }\n            else {\n                var value;\n                if (isValueColor) {\n                    value = catmullRomInterpolateArray(\n                        p0, p1, p2, p3, w, w * w, w * w * w,\n                        rgba, 1\n                    );\n                    value = rgba2String(rgba);\n                }\n                else if (isValueString) {\n                    // String is step(0.5)\n                    return interpolateString(p1, p2, w);\n                }\n                else {\n                    value = catmullRomInterpolate(\n                        p0, p1, p2, p3, w, w * w, w * w * w\n                    );\n                }\n                setter(\n                    target,\n                    propName,\n                    value\n                );\n            }\n        }\n        else {\n            if (isValueArray) {\n                interpolateArray(\n                    kfValues[frame], kfValues[frame + 1], w,\n                    getter(target, propName),\n                    arrDim\n                );\n            }\n            else {\n                var value;\n                if (isValueColor) {\n                    interpolateArray(\n                        kfValues[frame], kfValues[frame + 1], w,\n                        rgba, 1\n                    );\n                    value = rgba2String(rgba);\n                }\n                else if (isValueString) {\n                    // String is step(0.5)\n                    return interpolateString(kfValues[frame], kfValues[frame + 1], w);\n                }\n                else {\n                    value = interpolateNumber(kfValues[frame], kfValues[frame + 1], w);\n                }\n                setter(\n                    target,\n                    propName,\n                    value\n                );\n            }\n        }\n    };\n\n    var clip = new Clip({\n        target: animator._target,\n        life: trackMaxTime,\n        loop: animator._loop,\n        delay: animator._delay,\n        onframe: onframe,\n        ondestroy: oneTrackDone\n    });\n\n    if (easing && easing !== 'spline') {\n        clip.easing = easing;\n    }\n\n    return clip;\n}\n\n/**\n * @alias module:zrender/animation/Animator\n * @constructor\n * @param {Object} target\n * @param {boolean} loop\n * @param {Function} getter\n * @param {Function} setter\n */\nvar Animator = function (target, loop, getter, setter) {\n    this._tracks = {};\n    this._target = target;\n\n    this._loop = loop || false;\n\n    this._getter = getter || defaultGetter;\n    this._setter = setter || defaultSetter;\n\n    this._clipCount = 0;\n\n    this._delay = 0;\n\n    this._doneList = [];\n\n    this._onframeList = [];\n\n    this._clipList = [];\n};\n\nAnimator.prototype = {\n    /**\n     * 设置动画关键帧\n     * @param  {number} time 关键帧时间，单位是ms\n     * @param  {Object} props 关键帧的属性值，key-value表示\n     * @return {module:zrender/animation/Animator}\n     */\n    when: function (time /* ms */, props) {\n        var tracks = this._tracks;\n        for (var propName in props) {\n            if (!props.hasOwnProperty(propName)) {\n                continue;\n            }\n\n            if (!tracks[propName]) {\n                tracks[propName] = [];\n                // Invalid value\n                var value = this._getter(this._target, propName);\n                if (value == null) {\n                    // zrLog('Invalid property ' + propName);\n                    continue;\n                }\n                // If time is 0\n                //  Then props is given initialize value\n                // Else\n                //  Initialize value from current prop value\n                if (time !== 0) {\n                    tracks[propName].push({\n                        time: 0,\n                        value: cloneValue(value)\n                    });\n                }\n            }\n            tracks[propName].push({\n                time: time,\n                value: props[propName]\n            });\n        }\n        return this;\n    },\n    /**\n     * 添加动画每一帧的回调函数\n     * @param  {Function} callback\n     * @return {module:zrender/animation/Animator}\n     */\n    during: function (callback) {\n        this._onframeList.push(callback);\n        return this;\n    },\n\n    pause: function () {\n        for (var i = 0; i < this._clipList.length; i++) {\n            this._clipList[i].pause();\n        }\n        this._paused = true;\n    },\n\n    resume: function () {\n        for (var i = 0; i < this._clipList.length; i++) {\n            this._clipList[i].resume();\n        }\n        this._paused = false;\n    },\n\n    isPaused: function () {\n        return !!this._paused;\n    },\n\n    _doneCallback: function () {\n        // Clear all tracks\n        this._tracks = {};\n        // Clear all clips\n        this._clipList.length = 0;\n\n        var doneList = this._doneList;\n        var len = doneList.length;\n        for (var i = 0; i < len; i++) {\n            doneList[i].call(this);\n        }\n    },\n    /**\n     * 开始执行动画\n     * @param  {string|Function} [easing]\n     *         动画缓动函数，详见{@link module:zrender/animation/easing}\n     * @param  {boolean} forceAnimate\n     * @return {module:zrender/animation/Animator}\n     */\n    start: function (easing, forceAnimate) {\n\n        var self = this;\n        var clipCount = 0;\n\n        var oneTrackDone = function () {\n            clipCount--;\n            if (!clipCount) {\n                self._doneCallback();\n            }\n        };\n\n        var lastClip;\n        for (var propName in this._tracks) {\n            if (!this._tracks.hasOwnProperty(propName)) {\n                continue;\n            }\n            var clip = createTrackClip(\n                this, easing, oneTrackDone,\n                this._tracks[propName], propName, forceAnimate\n            );\n            if (clip) {\n                this._clipList.push(clip);\n                clipCount++;\n\n                // If start after added to animation\n                if (this.animation) {\n                    this.animation.addClip(clip);\n                }\n\n                lastClip = clip;\n            }\n        }\n\n        // Add during callback on the last clip\n        if (lastClip) {\n            var oldOnFrame = lastClip.onframe;\n            lastClip.onframe = function (target, percent) {\n                oldOnFrame(target, percent);\n\n                for (var i = 0; i < self._onframeList.length; i++) {\n                    self._onframeList[i](target, percent);\n                }\n            };\n        }\n\n        // This optimization will help the case that in the upper application\n        // the view may be refreshed frequently, where animation will be\n        // called repeatly but nothing changed.\n        if (!clipCount) {\n            this._doneCallback();\n        }\n        return this;\n    },\n    /**\n     * 停止动画\n     * @param {boolean} forwardToLast If move to last frame before stop\n     */\n    stop: function (forwardToLast) {\n        var clipList = this._clipList;\n        var animation = this.animation;\n        for (var i = 0; i < clipList.length; i++) {\n            var clip = clipList[i];\n            if (forwardToLast) {\n                // Move to last frame before stop\n                clip.onframe(this._target, 1);\n            }\n            animation && animation.removeClip(clip);\n        }\n        clipList.length = 0;\n    },\n    /**\n     * 设置动画延迟开始的时间\n     * @param  {number} time 单位ms\n     * @return {module:zrender/animation/Animator}\n     */\n    delay: function (time) {\n        this._delay = time;\n        return this;\n    },\n    /**\n     * 添加动画结束的回调\n     * @param  {Function} cb\n     * @return {module:zrender/animation/Animator}\n     */\n    done: function (cb) {\n        if (cb) {\n            this._doneList.push(cb);\n        }\n        return this;\n    },\n\n    /**\n     * @return {Array.<module:zrender/animation/Clip>}\n     */\n    getClips: function () {\n        return this._clipList;\n    }\n};\n\nvar dpr = 1;\n\n// If in browser environment\nif (typeof window !== 'undefined') {\n    dpr = Math.max(window.devicePixelRatio || 1, 1);\n}\n\n/**\n * config默认配置项\n * @exports zrender/config\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n */\n\n/**\n * debug日志选项：catchBrushException为true下有效\n * 0 : 不生成debug数据，发布用\n * 1 : 异常抛出，调试用\n * 2 : 控制台输出，调试用\n */\nvar debugMode = 0;\n\n// retina 屏幕优化\nvar devicePixelRatio = dpr;\n\nvar log = function () {\n};\n\nif (debugMode === 1) {\n    log = function () {\n        for (var k in arguments) {\n            throw new Error(arguments[k]);\n        }\n    };\n}\nelse if (debugMode > 1) {\n    log = function () {\n        for (var k in arguments) {\n            console.log(arguments[k]);\n        }\n    };\n}\n\nvar zrLog = log;\n\n/**\n * @alias modue:zrender/mixin/Animatable\n * @constructor\n */\nvar Animatable = function () {\n\n    /**\n     * @type {Array.<module:zrender/animation/Animator>}\n     * @readOnly\n     */\n    this.animators = [];\n};\n\nAnimatable.prototype = {\n\n    constructor: Animatable,\n\n    /**\n     * 动画\n     *\n     * @param {string} path The path to fetch value from object, like 'a.b.c'.\n     * @param {boolean} [loop] Whether to loop animation.\n     * @return {module:zrender/animation/Animator}\n     * @example:\n     *     el.animate('style', false)\n     *         .when(1000, {x: 10} )\n     *         .done(function(){ // Animation done })\n     *         .start()\n     */\n    animate: function (path, loop) {\n        var target;\n        var animatingShape = false;\n        var el = this;\n        var zr = this.__zr;\n        if (path) {\n            var pathSplitted = path.split('.');\n            var prop = el;\n            // If animating shape\n            animatingShape = pathSplitted[0] === 'shape';\n            for (var i = 0, l = pathSplitted.length; i < l; i++) {\n                if (!prop) {\n                    continue;\n                }\n                prop = prop[pathSplitted[i]];\n            }\n            if (prop) {\n                target = prop;\n            }\n        }\n        else {\n            target = el;\n        }\n\n        if (!target) {\n            zrLog(\n                'Property \"'\n                + path\n                + '\" is not existed in element '\n                + el.id\n            );\n            return;\n        }\n\n        var animators = el.animators;\n\n        var animator = new Animator(target, loop);\n\n        animator.during(function (target) {\n            el.dirty(animatingShape);\n        })\n        .done(function () {\n            // FIXME Animator will not be removed if use `Animator#stop` to stop animation\n            animators.splice(indexOf(animators, animator), 1);\n        });\n\n        animators.push(animator);\n\n        // If animate after added to the zrender\n        if (zr) {\n            zr.animation.addAnimator(animator);\n        }\n\n        return animator;\n    },\n\n    /**\n     * 停止动画\n     * @param {boolean} forwardToLast If move to last frame before stop\n     */\n    stopAnimation: function (forwardToLast) {\n        var animators = this.animators;\n        var len = animators.length;\n        for (var i = 0; i < len; i++) {\n            animators[i].stop(forwardToLast);\n        }\n        animators.length = 0;\n\n        return this;\n    },\n\n    /**\n     * Caution: this method will stop previous animation.\n     * So do not use this method to one element twice before\n     * animation starts, unless you know what you are doing.\n     * @param {Object} target\n     * @param {number} [time=500] Time in ms\n     * @param {string} [easing='linear']\n     * @param {number} [delay=0]\n     * @param {Function} [callback]\n     * @param {Function} [forceAnimate] Prevent stop animation and callback\n     *        immediently when target values are the same as current values.\n     *\n     * @example\n     *  // Animate position\n     *  el.animateTo({\n     *      position: [10, 10]\n     *  }, function () { // done })\n     *\n     *  // Animate shape, style and position in 100ms, delayed 100ms, with cubicOut easing\n     *  el.animateTo({\n     *      shape: {\n     *          width: 500\n     *      },\n     *      style: {\n     *          fill: 'red'\n     *      }\n     *      position: [10, 10]\n     *  }, 100, 100, 'cubicOut', function () { // done })\n     */\n    // TODO Return animation key\n    animateTo: function (target, time, delay, easing, callback, forceAnimate) {\n        animateTo(this, target, time, delay, easing, callback, forceAnimate);\n    },\n\n    /**\n     * Animate from the target state to current state.\n     * The params and the return value are the same as `this.animateTo`.\n     */\n    animateFrom: function (target, time, delay, easing, callback, forceAnimate) {\n        animateTo(this, target, time, delay, easing, callback, forceAnimate, true);\n    }\n};\n\nfunction animateTo(animatable, target, time, delay, easing, callback, forceAnimate, reverse) {\n    // animateTo(target, time, easing, callback);\n    if (isString(delay)) {\n        callback = easing;\n        easing = delay;\n        delay = 0;\n    }\n    // animateTo(target, time, delay, callback);\n    else if (isFunction$1(easing)) {\n        callback = easing;\n        easing = 'linear';\n        delay = 0;\n    }\n    // animateTo(target, time, callback);\n    else if (isFunction$1(delay)) {\n        callback = delay;\n        delay = 0;\n    }\n    // animateTo(target, callback)\n    else if (isFunction$1(time)) {\n        callback = time;\n        time = 500;\n    }\n    // animateTo(target)\n    else if (!time) {\n        time = 500;\n    }\n    // Stop all previous animations\n    animatable.stopAnimation();\n    animateToShallow(animatable, '', animatable, target, time, delay, reverse);\n\n    // Animators may be removed immediately after start\n    // if there is nothing to animate\n    var animators = animatable.animators.slice();\n    var count = animators.length;\n    function done() {\n        count--;\n        if (!count) {\n            callback && callback();\n        }\n    }\n\n    // No animators. This should be checked before animators[i].start(),\n    // because 'done' may be executed immediately if no need to animate.\n    if (!count) {\n        callback && callback();\n    }\n    // Start after all animators created\n    // Incase any animator is done immediately when all animation properties are not changed\n    for (var i = 0; i < animators.length; i++) {\n        animators[i]\n            .done(done)\n            .start(easing, forceAnimate);\n    }\n}\n\n/**\n * @param {string} path=''\n * @param {Object} source=animatable\n * @param {Object} target\n * @param {number} [time=500]\n * @param {number} [delay=0]\n * @param {boolean} [reverse] If `true`, animate\n *        from the `target` to current state.\n *\n * @example\n *  // Animate position\n *  el._animateToShallow({\n *      position: [10, 10]\n *  })\n *\n *  // Animate shape, style and position in 100ms, delayed 100ms\n *  el._animateToShallow({\n *      shape: {\n *          width: 500\n *      },\n *      style: {\n *          fill: 'red'\n *      }\n *      position: [10, 10]\n *  }, 100, 100)\n */\nfunction animateToShallow(animatable, path, source, target, time, delay, reverse) {\n    var objShallow = {};\n    var propertyCount = 0;\n    for (var name in target) {\n        if (!target.hasOwnProperty(name)) {\n            continue;\n        }\n\n        if (source[name] != null) {\n            if (isObject$1(target[name]) && !isArrayLike(target[name])) {\n                animateToShallow(\n                    animatable,\n                    path ? path + '.' + name : name,\n                    source[name],\n                    target[name],\n                    time,\n                    delay,\n                    reverse\n                );\n            }\n            else {\n                if (reverse) {\n                    objShallow[name] = source[name];\n                    setAttrByPath(animatable, path, name, target[name]);\n                }\n                else {\n                    objShallow[name] = target[name];\n                }\n                propertyCount++;\n            }\n        }\n        else if (target[name] != null && !reverse) {\n            setAttrByPath(animatable, path, name, target[name]);\n        }\n    }\n\n    if (propertyCount > 0) {\n        animatable.animate(path, false)\n            .when(time == null ? 500 : time, objShallow)\n            .delay(delay || 0);\n    }\n}\n\nfunction setAttrByPath(el, path, name, value) {\n    // Attr directly if not has property\n    // FIXME, if some property not needed for element ?\n    if (!path) {\n        el.attr(name, value);\n    }\n    else {\n        // Only support set shape or style\n        var props = {};\n        props[path] = {};\n        props[path][name] = value;\n        el.attr(props);\n    }\n}\n\n/**\n * @alias module:zrender/Element\n * @constructor\n * @extends {module:zrender/mixin/Animatable}\n * @extends {module:zrender/mixin/Transformable}\n * @extends {module:zrender/mixin/Eventful}\n */\nvar Element = function (opts) { // jshint ignore:line\n\n    Transformable.call(this, opts);\n    Eventful.call(this, opts);\n    Animatable.call(this, opts);\n\n    /**\n     * 画布元素ID\n     * @type {string}\n     */\n    this.id = opts.id || guid();\n};\n\nElement.prototype = {\n\n    /**\n     * 元素类型\n     * Element type\n     * @type {string}\n     */\n    type: 'element',\n\n    /**\n     * 元素名字\n     * Element name\n     * @type {string}\n     */\n    name: '',\n\n    /**\n     * ZRender 实例对象，会在 element 添加到 zrender 实例中后自动赋值\n     * ZRender instance will be assigned when element is associated with zrender\n     * @name module:/zrender/Element#__zr\n     * @type {module:zrender/ZRender}\n     */\n    __zr: null,\n\n    /**\n     * 图形是否忽略，为true时忽略图形的绘制以及事件触发\n     * If ignore drawing and events of the element object\n     * @name module:/zrender/Element#ignore\n     * @type {boolean}\n     * @default false\n     */\n    ignore: false,\n\n    /**\n     * 用于裁剪的路径(shape)，所有 Group 内的路径在绘制时都会被这个路径裁剪\n     * 该路径会继承被裁减对象的变换\n     * @type {module:zrender/graphic/Path}\n     * @see http://www.w3.org/TR/2dcontext/#clipping-region\n     * @readOnly\n     */\n    clipPath: null,\n\n    /**\n     * 是否是 Group\n     * @type {boolean}\n     */\n    isGroup: false,\n\n    /**\n     * Drift element\n     * @param  {number} dx dx on the global space\n     * @param  {number} dy dy on the global space\n     */\n    drift: function (dx, dy) {\n        switch (this.draggable) {\n            case 'horizontal':\n                dy = 0;\n                break;\n            case 'vertical':\n                dx = 0;\n                break;\n        }\n\n        var m = this.transform;\n        if (!m) {\n            m = this.transform = [1, 0, 0, 1, 0, 0];\n        }\n        m[4] += dx;\n        m[5] += dy;\n\n        this.decomposeTransform();\n        this.dirty(false);\n    },\n\n    /**\n     * Hook before update\n     */\n    beforeUpdate: function () {},\n    /**\n     * Hook after update\n     */\n    afterUpdate: function () {},\n    /**\n     * Update each frame\n     */\n    update: function () {\n        this.updateTransform();\n    },\n\n    /**\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {},\n\n    /**\n     * @protected\n     */\n    attrKV: function (key, value) {\n        if (key === 'position' || key === 'scale' || key === 'origin') {\n            // Copy the array\n            if (value) {\n                var target = this[key];\n                if (!target) {\n                    target = this[key] = [];\n                }\n                target[0] = value[0];\n                target[1] = value[1];\n            }\n        }\n        else {\n            this[key] = value;\n        }\n    },\n\n    /**\n     * Hide the element\n     */\n    hide: function () {\n        this.ignore = true;\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * Show the element\n     */\n    show: function () {\n        this.ignore = false;\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * @param {string|Object} key\n     * @param {*} value\n     */\n    attr: function (key, value) {\n        if (typeof key === 'string') {\n            this.attrKV(key, value);\n        }\n        else if (isObject$1(key)) {\n            for (var name in key) {\n                if (key.hasOwnProperty(name)) {\n                    this.attrKV(name, key[name]);\n                }\n            }\n        }\n\n        this.dirty(false);\n\n        return this;\n    },\n\n    /**\n     * @param {module:zrender/graphic/Path} clipPath\n     */\n    setClipPath: function (clipPath) {\n        var zr = this.__zr;\n        if (zr) {\n            clipPath.addSelfToZr(zr);\n        }\n\n        // Remove previous clip path\n        if (this.clipPath && this.clipPath !== clipPath) {\n            this.removeClipPath();\n        }\n\n        this.clipPath = clipPath;\n        clipPath.__zr = zr;\n        clipPath.__clipTarget = this;\n\n        this.dirty(false);\n    },\n\n    /**\n     */\n    removeClipPath: function () {\n        var clipPath = this.clipPath;\n        if (clipPath) {\n            if (clipPath.__zr) {\n                clipPath.removeSelfFromZr(clipPath.__zr);\n            }\n\n            clipPath.__zr = null;\n            clipPath.__clipTarget = null;\n            this.clipPath = null;\n\n            this.dirty(false);\n        }\n    },\n\n    /**\n     * Add self from zrender instance.\n     * Not recursively because it will be invoked when element added to storage.\n     * @param {module:zrender/ZRender} zr\n     */\n    addSelfToZr: function (zr) {\n        this.__zr = zr;\n        // 添加动画\n        var animators = this.animators;\n        if (animators) {\n            for (var i = 0; i < animators.length; i++) {\n                zr.animation.addAnimator(animators[i]);\n            }\n        }\n\n        if (this.clipPath) {\n            this.clipPath.addSelfToZr(zr);\n        }\n    },\n\n    /**\n     * Remove self from zrender instance.\n     * Not recursively because it will be invoked when element added to storage.\n     * @param {module:zrender/ZRender} zr\n     */\n    removeSelfFromZr: function (zr) {\n        this.__zr = null;\n        // 移除动画\n        var animators = this.animators;\n        if (animators) {\n            for (var i = 0; i < animators.length; i++) {\n                zr.animation.removeAnimator(animators[i]);\n            }\n        }\n\n        if (this.clipPath) {\n            this.clipPath.removeSelfFromZr(zr);\n        }\n    }\n};\n\nmixin(Element, Animatable);\nmixin(Element, Transformable);\nmixin(Element, Eventful);\n\n/**\n * @module echarts/core/BoundingRect\n */\n\nvar v2ApplyTransform = applyTransform;\nvar mathMin = Math.min;\nvar mathMax = Math.max;\n\n/**\n * @alias module:echarts/core/BoundingRect\n */\nfunction BoundingRect(x, y, width, height) {\n\n    if (width < 0) {\n        x = x + width;\n        width = -width;\n    }\n    if (height < 0) {\n        y = y + height;\n        height = -height;\n    }\n\n    /**\n     * @type {number}\n     */\n    this.x = x;\n    /**\n     * @type {number}\n     */\n    this.y = y;\n    /**\n     * @type {number}\n     */\n    this.width = width;\n    /**\n     * @type {number}\n     */\n    this.height = height;\n}\n\nBoundingRect.prototype = {\n\n    constructor: BoundingRect,\n\n    /**\n     * @param {module:echarts/core/BoundingRect} other\n     */\n    union: function (other) {\n        var x = mathMin(other.x, this.x);\n        var y = mathMin(other.y, this.y);\n\n        this.width = mathMax(\n                other.x + other.width,\n                this.x + this.width\n            ) - x;\n        this.height = mathMax(\n                other.y + other.height,\n                this.y + this.height\n            ) - y;\n        this.x = x;\n        this.y = y;\n    },\n\n    /**\n     * @param {Array.<number>} m\n     * @methods\n     */\n    applyTransform: (function () {\n        var lt = [];\n        var rb = [];\n        var lb = [];\n        var rt = [];\n        return function (m) {\n            // In case usage like this\n            // el.getBoundingRect().applyTransform(el.transform)\n            // And element has no transform\n            if (!m) {\n                return;\n            }\n            lt[0] = lb[0] = this.x;\n            lt[1] = rt[1] = this.y;\n            rb[0] = rt[0] = this.x + this.width;\n            rb[1] = lb[1] = this.y + this.height;\n\n            v2ApplyTransform(lt, lt, m);\n            v2ApplyTransform(rb, rb, m);\n            v2ApplyTransform(lb, lb, m);\n            v2ApplyTransform(rt, rt, m);\n\n            this.x = mathMin(lt[0], rb[0], lb[0], rt[0]);\n            this.y = mathMin(lt[1], rb[1], lb[1], rt[1]);\n            var maxX = mathMax(lt[0], rb[0], lb[0], rt[0]);\n            var maxY = mathMax(lt[1], rb[1], lb[1], rt[1]);\n            this.width = maxX - this.x;\n            this.height = maxY - this.y;\n        };\n    })(),\n\n    /**\n     * Calculate matrix of transforming from self to target rect\n     * @param  {module:zrender/core/BoundingRect} b\n     * @return {Array.<number>}\n     */\n    calculateTransform: function (b) {\n        var a = this;\n        var sx = b.width / a.width;\n        var sy = b.height / a.height;\n\n        var m = create$1();\n\n        // 矩阵右乘\n        translate(m, m, [-a.x, -a.y]);\n        scale$1(m, m, [sx, sy]);\n        translate(m, m, [b.x, b.y]);\n\n        return m;\n    },\n\n    /**\n     * @param {(module:echarts/core/BoundingRect|Object)} b\n     * @return {boolean}\n     */\n    intersect: function (b) {\n        if (!b) {\n            return false;\n        }\n\n        if (!(b instanceof BoundingRect)) {\n            // Normalize negative width/height.\n            b = BoundingRect.create(b);\n        }\n\n        var a = this;\n        var ax0 = a.x;\n        var ax1 = a.x + a.width;\n        var ay0 = a.y;\n        var ay1 = a.y + a.height;\n\n        var bx0 = b.x;\n        var bx1 = b.x + b.width;\n        var by0 = b.y;\n        var by1 = b.y + b.height;\n\n        return !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);\n    },\n\n    contain: function (x, y) {\n        var rect = this;\n        return x >= rect.x\n            && x <= (rect.x + rect.width)\n            && y >= rect.y\n            && y <= (rect.y + rect.height);\n    },\n\n    /**\n     * @return {module:echarts/core/BoundingRect}\n     */\n    clone: function () {\n        return new BoundingRect(this.x, this.y, this.width, this.height);\n    },\n\n    /**\n     * Copy from another rect\n     */\n    copy: function (other) {\n        this.x = other.x;\n        this.y = other.y;\n        this.width = other.width;\n        this.height = other.height;\n    },\n\n    plain: function () {\n        return {\n            x: this.x,\n            y: this.y,\n            width: this.width,\n            height: this.height\n        };\n    }\n};\n\n/**\n * @param {Object|module:zrender/core/BoundingRect} rect\n * @param {number} rect.x\n * @param {number} rect.y\n * @param {number} rect.width\n * @param {number} rect.height\n * @return {module:zrender/core/BoundingRect}\n */\nBoundingRect.create = function (rect) {\n    return new BoundingRect(rect.x, rect.y, rect.width, rect.height);\n};\n\n/**\n * Group是一个容器，可以插入子节点，Group的变换也会被应用到子节点上\n * @module zrender/graphic/Group\n * @example\n *     var Group = require('zrender/container/Group');\n *     var Circle = require('zrender/graphic/shape/Circle');\n *     var g = new Group();\n *     g.position[0] = 100;\n *     g.position[1] = 100;\n *     g.add(new Circle({\n *         style: {\n *             x: 100,\n *             y: 100,\n *             r: 20,\n *         }\n *     }));\n *     zr.add(g);\n */\n\n/**\n * @alias module:zrender/graphic/Group\n * @constructor\n * @extends module:zrender/mixin/Transformable\n * @extends module:zrender/mixin/Eventful\n */\nvar Group = function (opts) {\n\n    opts = opts || {};\n\n    Element.call(this, opts);\n\n    for (var key in opts) {\n        if (opts.hasOwnProperty(key)) {\n            this[key] = opts[key];\n        }\n    }\n\n    this._children = [];\n\n    this.__storage = null;\n\n    this.__dirty = true;\n};\n\nGroup.prototype = {\n\n    constructor: Group,\n\n    isGroup: true,\n\n    /**\n     * @type {string}\n     */\n    type: 'group',\n\n    /**\n     * 所有子孙元素是否响应鼠标事件\n     * @name module:/zrender/container/Group#silent\n     * @type {boolean}\n     * @default false\n     */\n    silent: false,\n\n    /**\n     * @return {Array.<module:zrender/Element>}\n     */\n    children: function () {\n        return this._children.slice();\n    },\n\n    /**\n     * 获取指定 index 的儿子节点\n     * @param  {number} idx\n     * @return {module:zrender/Element}\n     */\n    childAt: function (idx) {\n        return this._children[idx];\n    },\n\n    /**\n     * 获取指定名字的儿子节点\n     * @param  {string} name\n     * @return {module:zrender/Element}\n     */\n    childOfName: function (name) {\n        var children = this._children;\n        for (var i = 0; i < children.length; i++) {\n            if (children[i].name === name) {\n                return children[i];\n            }\n            }\n    },\n\n    /**\n     * @return {number}\n     */\n    childCount: function () {\n        return this._children.length;\n    },\n\n    /**\n     * 添加子节点到最后\n     * @param {module:zrender/Element} child\n     */\n    add: function (child) {\n        if (child && child !== this && child.parent !== this) {\n\n            this._children.push(child);\n\n            this._doAdd(child);\n        }\n\n        return this;\n    },\n\n    /**\n     * 添加子节点在 nextSibling 之前\n     * @param {module:zrender/Element} child\n     * @param {module:zrender/Element} nextSibling\n     */\n    addBefore: function (child, nextSibling) {\n        if (child && child !== this && child.parent !== this\n            && nextSibling && nextSibling.parent === this) {\n\n            var children = this._children;\n            var idx = children.indexOf(nextSibling);\n\n            if (idx >= 0) {\n                children.splice(idx, 0, child);\n                this._doAdd(child);\n            }\n        }\n\n        return this;\n    },\n\n    _doAdd: function (child) {\n        if (child.parent) {\n            child.parent.remove(child);\n        }\n\n        child.parent = this;\n\n        var storage = this.__storage;\n        var zr = this.__zr;\n        if (storage && storage !== child.__storage) {\n\n            storage.addToStorage(child);\n\n            if (child instanceof Group) {\n                child.addChildrenToStorage(storage);\n            }\n        }\n\n        zr && zr.refresh();\n    },\n\n    /**\n     * 移除子节点\n     * @param {module:zrender/Element} child\n     */\n    remove: function (child) {\n        var zr = this.__zr;\n        var storage = this.__storage;\n        var children = this._children;\n\n        var idx = indexOf(children, child);\n        if (idx < 0) {\n            return this;\n        }\n        children.splice(idx, 1);\n\n        child.parent = null;\n\n        if (storage) {\n\n            storage.delFromStorage(child);\n\n            if (child instanceof Group) {\n                child.delChildrenFromStorage(storage);\n            }\n        }\n\n        zr && zr.refresh();\n\n        return this;\n    },\n\n    /**\n     * 移除所有子节点\n     */\n    removeAll: function () {\n        var children = this._children;\n        var storage = this.__storage;\n        var child;\n        var i;\n        for (i = 0; i < children.length; i++) {\n            child = children[i];\n            if (storage) {\n                storage.delFromStorage(child);\n                if (child instanceof Group) {\n                    child.delChildrenFromStorage(storage);\n                }\n            }\n            child.parent = null;\n        }\n        children.length = 0;\n\n        return this;\n    },\n\n    /**\n     * 遍历所有子节点\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    eachChild: function (cb, context) {\n        var children = this._children;\n        for (var i = 0; i < children.length; i++) {\n            var child = children[i];\n            cb.call(context, child, i);\n        }\n        return this;\n    },\n\n    /**\n     * 深度优先遍历所有子孙节点\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            cb.call(context, child);\n\n            if (child.type === 'group') {\n                child.traverse(cb, context);\n            }\n        }\n        return this;\n    },\n\n    addChildrenToStorage: function (storage) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            storage.addToStorage(child);\n            if (child instanceof Group) {\n                child.addChildrenToStorage(storage);\n            }\n        }\n    },\n\n    delChildrenFromStorage: function (storage) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            storage.delFromStorage(child);\n            if (child instanceof Group) {\n                child.delChildrenFromStorage(storage);\n            }\n        }\n    },\n\n    dirty: function () {\n        this.__dirty = true;\n        this.__zr && this.__zr.refresh();\n        return this;\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function (includeChildren) {\n        // TODO Caching\n        var rect = null;\n        var tmpRect = new BoundingRect(0, 0, 0, 0);\n        var children = includeChildren || this._children;\n        var tmpMat = [];\n\n        for (var i = 0; i < children.length; i++) {\n            var child = children[i];\n            if (child.ignore || child.invisible) {\n                continue;\n            }\n\n            var childRect = child.getBoundingRect();\n            var transform = child.getLocalTransform(tmpMat);\n            // TODO\n            // The boundingRect cacluated by transforming original\n            // rect may be bigger than the actual bundingRect when rotation\n            // is used. (Consider a circle rotated aginst its center, where\n            // the actual boundingRect should be the same as that not be\n            // rotated.) But we can not find better approach to calculate\n            // actual boundingRect yet, considering performance.\n            if (transform) {\n                tmpRect.copy(childRect);\n                tmpRect.applyTransform(transform);\n                rect = rect || tmpRect.clone();\n                rect.union(tmpRect);\n            }\n            else {\n                rect = rect || childRect.clone();\n                rect.union(childRect);\n            }\n        }\n        return rect || tmpRect;\n    }\n};\n\ninherits(Group, Element);\n\n// https://github.com/mziccard/node-timsort\nvar DEFAULT_MIN_MERGE = 32;\n\nvar DEFAULT_MIN_GALLOPING = 7;\n\nfunction minRunLength(n) {\n    var r = 0;\n\n    while (n >= DEFAULT_MIN_MERGE) {\n        r |= n & 1;\n        n >>= 1;\n    }\n\n    return n + r;\n}\n\nfunction makeAscendingRun(array, lo, hi, compare) {\n    var runHi = lo + 1;\n\n    if (runHi === hi) {\n        return 1;\n    }\n\n    if (compare(array[runHi++], array[lo]) < 0) {\n        while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {\n            runHi++;\n        }\n\n        reverseRun(array, lo, runHi);\n    }\n    else {\n        while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {\n            runHi++;\n        }\n    }\n\n    return runHi - lo;\n}\n\nfunction reverseRun(array, lo, hi) {\n    hi--;\n\n    while (lo < hi) {\n        var t = array[lo];\n        array[lo++] = array[hi];\n        array[hi--] = t;\n    }\n}\n\nfunction binaryInsertionSort(array, lo, hi, start, compare) {\n    if (start === lo) {\n        start++;\n    }\n\n    for (; start < hi; start++) {\n        var pivot = array[start];\n\n        var left = lo;\n        var right = start;\n        var mid;\n\n        while (left < right) {\n            mid = left + right >>> 1;\n\n            if (compare(pivot, array[mid]) < 0) {\n                right = mid;\n            }\n            else {\n                left = mid + 1;\n            }\n        }\n\n        var n = start - left;\n\n        switch (n) {\n            case 3:\n                array[left + 3] = array[left + 2];\n\n            case 2:\n                array[left + 2] = array[left + 1];\n\n            case 1:\n                array[left + 1] = array[left];\n                break;\n            default:\n                while (n > 0) {\n                    array[left + n] = array[left + n - 1];\n                    n--;\n                }\n        }\n\n        array[left] = pivot;\n    }\n}\n\nfunction gallopLeft(value, array, start, length, hint, compare) {\n    var lastOffset = 0;\n    var maxOffset = 0;\n    var offset = 1;\n\n    if (compare(value, array[start + hint]) > 0) {\n        maxOffset = length - hint;\n\n        while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        lastOffset += hint;\n        offset += hint;\n    }\n    else {\n        maxOffset = hint + 1;\n        while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        var tmp = lastOffset;\n        lastOffset = hint - offset;\n        offset = hint - tmp;\n    }\n\n    lastOffset++;\n    while (lastOffset < offset) {\n        var m = lastOffset + (offset - lastOffset >>> 1);\n\n        if (compare(value, array[start + m]) > 0) {\n            lastOffset = m + 1;\n        }\n        else {\n            offset = m;\n        }\n    }\n    return offset;\n}\n\nfunction gallopRight(value, array, start, length, hint, compare) {\n    var lastOffset = 0;\n    var maxOffset = 0;\n    var offset = 1;\n\n    if (compare(value, array[start + hint]) < 0) {\n        maxOffset = hint + 1;\n\n        while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        var tmp = lastOffset;\n        lastOffset = hint - offset;\n        offset = hint - tmp;\n    }\n    else {\n        maxOffset = length - hint;\n\n        while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        lastOffset += hint;\n        offset += hint;\n    }\n\n    lastOffset++;\n\n    while (lastOffset < offset) {\n        var m = lastOffset + (offset - lastOffset >>> 1);\n\n        if (compare(value, array[start + m]) < 0) {\n            offset = m;\n        }\n        else {\n            lastOffset = m + 1;\n        }\n    }\n\n    return offset;\n}\n\nfunction TimSort(array, compare) {\n    var minGallop = DEFAULT_MIN_GALLOPING;\n    var runStart;\n    var runLength;\n    var stackSize = 0;\n\n    var tmp = [];\n\n    runStart = [];\n    runLength = [];\n\n    function pushRun(_runStart, _runLength) {\n        runStart[stackSize] = _runStart;\n        runLength[stackSize] = _runLength;\n        stackSize += 1;\n    }\n\n    function mergeRuns() {\n        while (stackSize > 1) {\n            var n = stackSize - 2;\n\n            if (n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1] || n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1]) {\n                if (runLength[n - 1] < runLength[n + 1]) {\n                    n--;\n                }\n            }\n            else if (runLength[n] > runLength[n + 1]) {\n                break;\n            }\n            mergeAt(n);\n        }\n    }\n\n    function forceMergeRuns() {\n        while (stackSize > 1) {\n            var n = stackSize - 2;\n\n            if (n > 0 && runLength[n - 1] < runLength[n + 1]) {\n                n--;\n            }\n\n            mergeAt(n);\n        }\n    }\n\n    function mergeAt(i) {\n        var start1 = runStart[i];\n        var length1 = runLength[i];\n        var start2 = runStart[i + 1];\n        var length2 = runLength[i + 1];\n\n        runLength[i] = length1 + length2;\n\n        if (i === stackSize - 3) {\n            runStart[i + 1] = runStart[i + 2];\n            runLength[i + 1] = runLength[i + 2];\n        }\n\n        stackSize--;\n\n        var k = gallopRight(array[start2], array, start1, length1, 0, compare);\n        start1 += k;\n        length1 -= k;\n\n        if (length1 === 0) {\n            return;\n        }\n\n        length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);\n\n        if (length2 === 0) {\n            return;\n        }\n\n        if (length1 <= length2) {\n            mergeLow(start1, length1, start2, length2);\n        }\n        else {\n            mergeHigh(start1, length1, start2, length2);\n        }\n    }\n\n    function mergeLow(start1, length1, start2, length2) {\n        var i = 0;\n\n        for (i = 0; i < length1; i++) {\n            tmp[i] = array[start1 + i];\n        }\n\n        var cursor1 = 0;\n        var cursor2 = start2;\n        var dest = start1;\n\n        array[dest++] = array[cursor2++];\n\n        if (--length2 === 0) {\n            for (i = 0; i < length1; i++) {\n                array[dest + i] = tmp[cursor1 + i];\n            }\n            return;\n        }\n\n        if (length1 === 1) {\n            for (i = 0; i < length2; i++) {\n                array[dest + i] = array[cursor2 + i];\n            }\n            array[dest + length2] = tmp[cursor1];\n            return;\n        }\n\n        var _minGallop = minGallop;\n        var count1, count2, exit;\n\n        while (1) {\n            count1 = 0;\n            count2 = 0;\n            exit = false;\n\n            do {\n                if (compare(array[cursor2], tmp[cursor1]) < 0) {\n                    array[dest++] = array[cursor2++];\n                    count2++;\n                    count1 = 0;\n\n                    if (--length2 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                else {\n                    array[dest++] = tmp[cursor1++];\n                    count1++;\n                    count2 = 0;\n                    if (--length1 === 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n            } while ((count1 | count2) < _minGallop);\n\n            if (exit) {\n                break;\n            }\n\n            do {\n                count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);\n\n                if (count1 !== 0) {\n                    for (i = 0; i < count1; i++) {\n                        array[dest + i] = tmp[cursor1 + i];\n                    }\n\n                    dest += count1;\n                    cursor1 += count1;\n                    length1 -= count1;\n                    if (length1 <= 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest++] = array[cursor2++];\n\n                if (--length2 === 0) {\n                    exit = true;\n                    break;\n                }\n\n                count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);\n\n                if (count2 !== 0) {\n                    for (i = 0; i < count2; i++) {\n                        array[dest + i] = array[cursor2 + i];\n                    }\n\n                    dest += count2;\n                    cursor2 += count2;\n                    length2 -= count2;\n\n                    if (length2 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                array[dest++] = tmp[cursor1++];\n\n                if (--length1 === 1) {\n                    exit = true;\n                    break;\n                }\n\n                _minGallop--;\n            } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);\n\n            if (exit) {\n                break;\n            }\n\n            if (_minGallop < 0) {\n                _minGallop = 0;\n            }\n\n            _minGallop += 2;\n        }\n\n        minGallop = _minGallop;\n\n        minGallop < 1 && (minGallop = 1);\n\n        if (length1 === 1) {\n            for (i = 0; i < length2; i++) {\n                array[dest + i] = array[cursor2 + i];\n            }\n            array[dest + length2] = tmp[cursor1];\n        }\n        else if (length1 === 0) {\n            throw new Error();\n            // throw new Error('mergeLow preconditions were not respected');\n        }\n        else {\n            for (i = 0; i < length1; i++) {\n                array[dest + i] = tmp[cursor1 + i];\n            }\n        }\n    }\n\n    function mergeHigh(start1, length1, start2, length2) {\n        var i = 0;\n\n        for (i = 0; i < length2; i++) {\n            tmp[i] = array[start2 + i];\n        }\n\n        var cursor1 = start1 + length1 - 1;\n        var cursor2 = length2 - 1;\n        var dest = start2 + length2 - 1;\n        var customCursor = 0;\n        var customDest = 0;\n\n        array[dest--] = array[cursor1--];\n\n        if (--length1 === 0) {\n            customCursor = dest - (length2 - 1);\n\n            for (i = 0; i < length2; i++) {\n                array[customCursor + i] = tmp[i];\n            }\n\n            return;\n        }\n\n        if (length2 === 1) {\n            dest -= length1;\n            cursor1 -= length1;\n            customDest = dest + 1;\n            customCursor = cursor1 + 1;\n\n            for (i = length1 - 1; i >= 0; i--) {\n                array[customDest + i] = array[customCursor + i];\n            }\n\n            array[dest] = tmp[cursor2];\n            return;\n        }\n\n        var _minGallop = minGallop;\n\n        while (true) {\n            var count1 = 0;\n            var count2 = 0;\n            var exit = false;\n\n            do {\n                if (compare(tmp[cursor2], array[cursor1]) < 0) {\n                    array[dest--] = array[cursor1--];\n                    count1++;\n                    count2 = 0;\n                    if (--length1 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                else {\n                    array[dest--] = tmp[cursor2--];\n                    count2++;\n                    count1 = 0;\n                    if (--length2 === 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n            } while ((count1 | count2) < _minGallop);\n\n            if (exit) {\n                break;\n            }\n\n            do {\n                count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);\n\n                if (count1 !== 0) {\n                    dest -= count1;\n                    cursor1 -= count1;\n                    length1 -= count1;\n                    customDest = dest + 1;\n                    customCursor = cursor1 + 1;\n\n                    for (i = count1 - 1; i >= 0; i--) {\n                        array[customDest + i] = array[customCursor + i];\n                    }\n\n                    if (length1 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest--] = tmp[cursor2--];\n\n                if (--length2 === 1) {\n                    exit = true;\n                    break;\n                }\n\n                count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);\n\n                if (count2 !== 0) {\n                    dest -= count2;\n                    cursor2 -= count2;\n                    length2 -= count2;\n                    customDest = dest + 1;\n                    customCursor = cursor2 + 1;\n\n                    for (i = 0; i < count2; i++) {\n                        array[customDest + i] = tmp[customCursor + i];\n                    }\n\n                    if (length2 <= 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest--] = array[cursor1--];\n\n                if (--length1 === 0) {\n                    exit = true;\n                    break;\n                }\n\n                _minGallop--;\n            } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);\n\n            if (exit) {\n                break;\n            }\n\n            if (_minGallop < 0) {\n                _minGallop = 0;\n            }\n\n            _minGallop += 2;\n        }\n\n        minGallop = _minGallop;\n\n        if (minGallop < 1) {\n            minGallop = 1;\n        }\n\n        if (length2 === 1) {\n            dest -= length1;\n            cursor1 -= length1;\n            customDest = dest + 1;\n            customCursor = cursor1 + 1;\n\n            for (i = length1 - 1; i >= 0; i--) {\n                array[customDest + i] = array[customCursor + i];\n            }\n\n            array[dest] = tmp[cursor2];\n        }\n        else if (length2 === 0) {\n            throw new Error();\n            // throw new Error('mergeHigh preconditions were not respected');\n        }\n        else {\n            customCursor = dest - (length2 - 1);\n            for (i = 0; i < length2; i++) {\n                array[customCursor + i] = tmp[i];\n            }\n        }\n    }\n\n    this.mergeRuns = mergeRuns;\n    this.forceMergeRuns = forceMergeRuns;\n    this.pushRun = pushRun;\n}\n\nfunction sort(array, compare, lo, hi) {\n    if (!lo) {\n        lo = 0;\n    }\n    if (!hi) {\n        hi = array.length;\n    }\n\n    var remaining = hi - lo;\n\n    if (remaining < 2) {\n        return;\n    }\n\n    var runLength = 0;\n\n    if (remaining < DEFAULT_MIN_MERGE) {\n        runLength = makeAscendingRun(array, lo, hi, compare);\n        binaryInsertionSort(array, lo, hi, lo + runLength, compare);\n        return;\n    }\n\n    var ts = new TimSort(array, compare);\n\n    var minRun = minRunLength(remaining);\n\n    do {\n        runLength = makeAscendingRun(array, lo, hi, compare);\n        if (runLength < minRun) {\n            var force = remaining;\n            if (force > minRun) {\n                force = minRun;\n            }\n\n            binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);\n            runLength = force;\n        }\n\n        ts.pushRun(lo, runLength);\n        ts.mergeRuns();\n\n        remaining -= runLength;\n        lo += runLength;\n    } while (remaining !== 0);\n\n    ts.forceMergeRuns();\n}\n\n// Use timsort because in most case elements are partially sorted\n// https://jsfiddle.net/pissang/jr4x7mdm/8/\nfunction shapeCompareFunc(a, b) {\n    if (a.zlevel === b.zlevel) {\n        if (a.z === b.z) {\n            // if (a.z2 === b.z2) {\n            //     // FIXME Slow has renderidx compare\n            //     // http://stackoverflow.com/questions/20883421/sorting-in-javascript-should-every-compare-function-have-a-return-0-statement\n            //     // https://github.com/v8/v8/blob/47cce544a31ed5577ffe2963f67acb4144ee0232/src/js/array.js#L1012\n            //     return a.__renderidx - b.__renderidx;\n            // }\n            return a.z2 - b.z2;\n        }\n        return a.z - b.z;\n    }\n    return a.zlevel - b.zlevel;\n}\n/**\n * 内容仓库 (M)\n * @alias module:zrender/Storage\n * @constructor\n */\nvar Storage = function () { // jshint ignore:line\n    this._roots = [];\n\n    this._displayList = [];\n\n    this._displayListLen = 0;\n};\n\nStorage.prototype = {\n\n    constructor: Storage,\n\n    /**\n     * @param  {Function} cb\n     *\n     */\n    traverse: function (cb, context) {\n        for (var i = 0; i < this._roots.length; i++) {\n            this._roots[i].traverse(cb, context);\n        }\n    },\n\n    /**\n     * 返回所有图形的绘制队列\n     * @param {boolean} [update=false] 是否在返回前更新该数组\n     * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组, 在 update 为 true 的时候有效\n     *\n     * 详见{@link module:zrender/graphic/Displayable.prototype.updateDisplayList}\n     * @return {Array.<module:zrender/graphic/Displayable>}\n     */\n    getDisplayList: function (update, includeIgnore) {\n        includeIgnore = includeIgnore || false;\n        if (update) {\n            this.updateDisplayList(includeIgnore);\n        }\n        return this._displayList;\n    },\n\n    /**\n     * 更新图形的绘制队列。\n     * 每次绘制前都会调用，该方法会先深度优先遍历整个树，更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中，\n     * 最后根据绘制的优先级（zlevel > z > 插入顺序）排序得到绘制队列\n     * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组\n     */\n    updateDisplayList: function (includeIgnore) {\n        this._displayListLen = 0;\n\n        var roots = this._roots;\n        var displayList = this._displayList;\n        for (var i = 0, len = roots.length; i < len; i++) {\n            this._updateAndAddDisplayable(roots[i], null, includeIgnore);\n        }\n\n        displayList.length = this._displayListLen;\n\n        env$1.canvasSupported && sort(displayList, shapeCompareFunc);\n    },\n\n    _updateAndAddDisplayable: function (el, clipPaths, includeIgnore) {\n\n        if (el.ignore && !includeIgnore) {\n            return;\n        }\n\n        el.beforeUpdate();\n\n        if (el.__dirty) {\n\n            el.update();\n\n        }\n\n        el.afterUpdate();\n\n        var userSetClipPath = el.clipPath;\n        if (userSetClipPath) {\n\n            // FIXME 效率影响\n            if (clipPaths) {\n                clipPaths = clipPaths.slice();\n            }\n            else {\n                clipPaths = [];\n            }\n\n            var currentClipPath = userSetClipPath;\n            var parentClipPath = el;\n            // Recursively add clip path\n            while (currentClipPath) {\n                // clipPath 的变换是基于使用这个 clipPath 的元素\n                currentClipPath.parent = parentClipPath;\n                currentClipPath.updateTransform();\n\n                clipPaths.push(currentClipPath);\n\n                parentClipPath = currentClipPath;\n                currentClipPath = currentClipPath.clipPath;\n            }\n        }\n\n        if (el.isGroup) {\n            var children = el._children;\n\n            for (var i = 0; i < children.length; i++) {\n                var child = children[i];\n\n                // Force to mark as dirty if group is dirty\n                // FIXME __dirtyPath ?\n                if (el.__dirty) {\n                    child.__dirty = true;\n                }\n\n                this._updateAndAddDisplayable(child, clipPaths, includeIgnore);\n            }\n\n            // Mark group clean here\n            el.__dirty = false;\n\n        }\n        else {\n            el.__clipPaths = clipPaths;\n\n            this._displayList[this._displayListLen++] = el;\n        }\n    },\n\n    /**\n     * 添加图形(Shape)或者组(Group)到根节点\n     * @param {module:zrender/Element} el\n     */\n    addRoot: function (el) {\n        if (el.__storage === this) {\n            return;\n        }\n\n        if (el instanceof Group) {\n            el.addChildrenToStorage(this);\n        }\n\n        this.addToStorage(el);\n        this._roots.push(el);\n    },\n\n    /**\n     * 删除指定的图形(Shape)或者组(Group)\n     * @param {string|Array.<string>} [el] 如果为空清空整个Storage\n     */\n    delRoot: function (el) {\n        if (el == null) {\n            // 不指定el清空\n            for (var i = 0; i < this._roots.length; i++) {\n                var root = this._roots[i];\n                if (root instanceof Group) {\n                    root.delChildrenFromStorage(this);\n                }\n            }\n\n            this._roots = [];\n            this._displayList = [];\n            this._displayListLen = 0;\n\n            return;\n        }\n\n        if (el instanceof Array) {\n            for (var i = 0, l = el.length; i < l; i++) {\n                this.delRoot(el[i]);\n            }\n            return;\n        }\n\n\n        var idx = indexOf(this._roots, el);\n        if (idx >= 0) {\n            this.delFromStorage(el);\n            this._roots.splice(idx, 1);\n            if (el instanceof Group) {\n                el.delChildrenFromStorage(this);\n            }\n        }\n    },\n\n    addToStorage: function (el) {\n        if (el) {\n            el.__storage = this;\n            el.dirty(false);\n        }\n        return this;\n    },\n\n    delFromStorage: function (el) {\n        if (el) {\n            el.__storage = null;\n        }\n\n        return this;\n    },\n\n    /**\n     * 清空并且释放Storage\n     */\n    dispose: function () {\n        this._renderList =\n        this._roots = null;\n    },\n\n    displayableSortFunc: shapeCompareFunc\n};\n\nvar SHADOW_PROPS = {\n    'shadowBlur': 1,\n    'shadowOffsetX': 1,\n    'shadowOffsetY': 1,\n    'textShadowBlur': 1,\n    'textShadowOffsetX': 1,\n    'textShadowOffsetY': 1,\n    'textBoxShadowBlur': 1,\n    'textBoxShadowOffsetX': 1,\n    'textBoxShadowOffsetY': 1\n};\n\nvar fixShadow = function (ctx, propName, value) {\n    if (SHADOW_PROPS.hasOwnProperty(propName)) {\n        return value *= ctx.dpr;\n    }\n    return value;\n};\n\nvar ContextCachedBy = {\n    NONE: 0,\n    STYLE_BIND: 1,\n    PLAIN_TEXT: 2\n};\n\n// Avoid confused with 0/false.\nvar WILL_BE_RESTORED = 9;\n\nvar STYLE_COMMON_PROPS = [\n    ['shadowBlur', 0], ['shadowOffsetX', 0], ['shadowOffsetY', 0], ['shadowColor', '#000'],\n    ['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]\n];\n\n// var SHADOW_PROPS = STYLE_COMMON_PROPS.slice(0, 4);\n// var LINE_PROPS = STYLE_COMMON_PROPS.slice(4);\n\nvar Style = function (opts) {\n    this.extendFrom(opts, false);\n};\n\nfunction createLinearGradient(ctx, obj, rect) {\n    var x = obj.x == null ? 0 : obj.x;\n    var x2 = obj.x2 == null ? 1 : obj.x2;\n    var y = obj.y == null ? 0 : obj.y;\n    var y2 = obj.y2 == null ? 0 : obj.y2;\n\n    if (!obj.global) {\n        x = x * rect.width + rect.x;\n        x2 = x2 * rect.width + rect.x;\n        y = y * rect.height + rect.y;\n        y2 = y2 * rect.height + rect.y;\n    }\n\n    // Fix NaN when rect is Infinity\n    x = isNaN(x) ? 0 : x;\n    x2 = isNaN(x2) ? 1 : x2;\n    y = isNaN(y) ? 0 : y;\n    y2 = isNaN(y2) ? 0 : y2;\n\n    var canvasGradient = ctx.createLinearGradient(x, y, x2, y2);\n\n    return canvasGradient;\n}\n\nfunction createRadialGradient(ctx, obj, rect) {\n    var width = rect.width;\n    var height = rect.height;\n    var min = Math.min(width, height);\n\n    var x = obj.x == null ? 0.5 : obj.x;\n    var y = obj.y == null ? 0.5 : obj.y;\n    var r = obj.r == null ? 0.5 : obj.r;\n    if (!obj.global) {\n        x = x * width + rect.x;\n        y = y * height + rect.y;\n        r = r * min;\n    }\n\n    var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r);\n\n    return canvasGradient;\n}\n\n\nStyle.prototype = {\n\n    constructor: Style,\n\n    /**\n     * @type {string}\n     */\n    fill: '#000',\n\n    /**\n     * @type {string}\n     */\n    stroke: null,\n\n    /**\n     * @type {number}\n     */\n    opacity: 1,\n\n    /**\n     * @type {number}\n     */\n    fillOpacity: null,\n\n    /**\n     * @type {number}\n     */\n    strokeOpacity: null,\n\n    /**\n     * @type {Array.<number>}\n     */\n    lineDash: null,\n\n    /**\n     * @type {number}\n     */\n    lineDashOffset: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowOffsetY: 0,\n\n    /**\n     * @type {number}\n     */\n    lineWidth: 1,\n\n    /**\n     * If stroke ignore scale\n     * @type {Boolean}\n     */\n    strokeNoScale: false,\n\n    // Bounding rect text configuration\n    // Not affected by element transform\n    /**\n     * @type {string}\n     */\n    text: null,\n\n    /**\n     * If `fontSize` or `fontFamily` exists, `font` will be reset by\n     * `fontSize`, `fontStyle`, `fontWeight`, `fontFamily`.\n     * So do not visit it directly in upper application (like echarts),\n     * but use `contain/text#makeFont` instead.\n     * @type {string}\n     */\n    font: null,\n\n    /**\n     * The same as font. Use font please.\n     * @deprecated\n     * @type {string}\n     */\n    textFont: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontStyle: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontWeight: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * Should be 12 but not '12px'.\n     * @type {number}\n     */\n    fontSize: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontFamily: null,\n\n    /**\n     * Reserved for special functinality, like 'hr'.\n     * @type {string}\n     */\n    textTag: null,\n\n    /**\n     * @type {string}\n     */\n    textFill: '#000',\n\n    /**\n     * @type {string}\n     */\n    textStroke: null,\n\n    /**\n     * @type {number}\n     */\n    textWidth: null,\n\n    /**\n     * Only for textBackground.\n     * @type {number}\n     */\n    textHeight: null,\n\n    /**\n     * textStroke may be set as some color as a default\n     * value in upper applicaion, where the default value\n     * of textStrokeWidth should be 0 to make sure that\n     * user can choose to do not use text stroke.\n     * @type {number}\n     */\n    textStrokeWidth: 0,\n\n    /**\n     * @type {number}\n     */\n    textLineHeight: null,\n\n    /**\n     * 'inside', 'left', 'right', 'top', 'bottom'\n     * [x, y]\n     * Based on x, y of rect.\n     * @type {string|Array.<number>}\n     * @default 'inside'\n     */\n    textPosition: 'inside',\n\n    /**\n     * If not specified, use the boundingRect of a `displayable`.\n     * @type {Object}\n     */\n    textRect: null,\n\n    /**\n     * [x, y]\n     * @type {Array.<number>}\n     */\n    textOffset: null,\n\n    /**\n     * @type {string}\n     */\n    textAlign: null,\n\n    /**\n     * @type {string}\n     */\n    textVerticalAlign: null,\n\n    /**\n     * @type {number}\n     */\n    textDistance: 5,\n\n    /**\n     * @type {string}\n     */\n    textShadowColor: 'transparent',\n\n    /**\n     * @type {number}\n     */\n    textShadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    textShadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    textShadowOffsetY: 0,\n\n    /**\n     * @type {string}\n     */\n    textBoxShadowColor: 'transparent',\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowOffsetY: 0,\n\n    /**\n     * Whether transform text.\n     * Only useful in Path and Image element\n     * @type {boolean}\n     */\n    transformText: false,\n\n    /**\n     * Text rotate around position of Path or Image\n     * Only useful in Path and Image element and transformText is false.\n     */\n    textRotation: 0,\n\n    /**\n     * Text origin of text rotation, like [10, 40].\n     * Based on x, y of rect.\n     * Useful in label rotation of circular symbol.\n     * By default, this origin is textPosition.\n     * Can be 'center'.\n     * @type {string|Array.<number>}\n     */\n    textOrigin: null,\n\n    /**\n     * @type {string}\n     */\n    textBackgroundColor: null,\n\n    /**\n     * @type {string}\n     */\n    textBorderColor: null,\n\n    /**\n     * @type {number}\n     */\n    textBorderWidth: 0,\n\n    /**\n     * @type {number}\n     */\n    textBorderRadius: 0,\n\n    /**\n     * Can be `2` or `[2, 4]` or `[2, 3, 4, 5]`\n     * @type {number|Array.<number>}\n     */\n    textPadding: null,\n\n    /**\n     * Text styles for rich text.\n     * @type {Object}\n     */\n    rich: null,\n\n    /**\n     * {outerWidth, outerHeight, ellipsis, placeholder}\n     * @type {Object}\n     */\n    truncate: null,\n\n    /**\n     * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation\n     * @type {string}\n     */\n    blend: null,\n\n    /**\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    bind: function (ctx, el, prevEl) {\n        var style = this;\n        var prevStyle = prevEl && prevEl.style;\n        // If no prevStyle, it means first draw.\n        // Only apply cache if the last time cachced by this function.\n        var notCheckCache = !prevStyle || ctx.__attrCachedBy !== ContextCachedBy.STYLE_BIND;\n\n        ctx.__attrCachedBy = ContextCachedBy.STYLE_BIND;\n\n        for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {\n            var prop = STYLE_COMMON_PROPS[i];\n            var styleName = prop[0];\n\n            if (notCheckCache || style[styleName] !== prevStyle[styleName]) {\n                // FIXME Invalid property value will cause style leak from previous element.\n                ctx[styleName] =\n                    fixShadow(ctx, styleName, style[styleName] || prop[1]);\n            }\n        }\n\n        if ((notCheckCache || style.fill !== prevStyle.fill)) {\n            ctx.fillStyle = style.fill;\n        }\n        if ((notCheckCache || style.stroke !== prevStyle.stroke)) {\n            ctx.strokeStyle = style.stroke;\n        }\n        if ((notCheckCache || style.opacity !== prevStyle.opacity)) {\n            ctx.globalAlpha = style.opacity == null ? 1 : style.opacity;\n        }\n\n        if ((notCheckCache || style.blend !== prevStyle.blend)) {\n            ctx.globalCompositeOperation = style.blend || 'source-over';\n        }\n        if (this.hasStroke()) {\n            var lineWidth = style.lineWidth;\n            ctx.lineWidth = lineWidth / (\n                (this.strokeNoScale && el && el.getLineScale) ? el.getLineScale() : 1\n            );\n        }\n    },\n\n    hasFill: function () {\n        var fill = this.fill;\n        return fill != null && fill !== 'none';\n    },\n\n    hasStroke: function () {\n        var stroke = this.stroke;\n        return stroke != null && stroke !== 'none' && this.lineWidth > 0;\n    },\n\n    /**\n     * Extend from other style\n     * @param {zrender/graphic/Style} otherStyle\n     * @param {boolean} overwrite true: overwrirte any way.\n     *                            false: overwrite only when !target.hasOwnProperty\n     *                            others: overwrite when property is not null/undefined.\n     */\n    extendFrom: function (otherStyle, overwrite) {\n        if (otherStyle) {\n            for (var name in otherStyle) {\n                if (otherStyle.hasOwnProperty(name)\n                    && (overwrite === true\n                        || (\n                            overwrite === false\n                                ? !this.hasOwnProperty(name)\n                                : otherStyle[name] != null\n                        )\n                    )\n                ) {\n                    this[name] = otherStyle[name];\n                }\n            }\n        }\n    },\n\n    /**\n     * Batch setting style with a given object\n     * @param {Object|string} obj\n     * @param {*} [obj]\n     */\n    set: function (obj, value) {\n        if (typeof obj === 'string') {\n            this[obj] = value;\n        }\n        else {\n            this.extendFrom(obj, true);\n        }\n    },\n\n    /**\n     * Clone\n     * @return {zrender/graphic/Style} [description]\n     */\n    clone: function () {\n        var newStyle = new this.constructor();\n        newStyle.extendFrom(this, true);\n        return newStyle;\n    },\n\n    getGradient: function (ctx, obj, rect) {\n        var method = obj.type === 'radial' ? createRadialGradient : createLinearGradient;\n        var canvasGradient = method(ctx, obj, rect);\n        var colorStops = obj.colorStops;\n        for (var i = 0; i < colorStops.length; i++) {\n            canvasGradient.addColorStop(\n                colorStops[i].offset, colorStops[i].color\n            );\n        }\n        return canvasGradient;\n    }\n\n};\n\nvar styleProto = Style.prototype;\nfor (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {\n    var prop = STYLE_COMMON_PROPS[i];\n    if (!(prop[0] in styleProto)) {\n        styleProto[prop[0]] = prop[1];\n    }\n}\n\n// Provide for others\nStyle.getGradient = styleProto.getGradient;\n\nvar Pattern = function (image, repeat) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {image: ...}`, where this constructor will not be called.\n\n    this.image = image;\n    this.repeat = repeat;\n\n    // Can be cloned\n    this.type = 'pattern';\n};\n\nPattern.prototype.getCanvasPattern = function (ctx) {\n    return ctx.createPattern(this.image, this.repeat || 'repeat');\n};\n\n/**\n * @module zrender/Layer\n * @author pissang(https://www.github.com/pissang)\n */\n\nfunction returnFalse() {\n    return false;\n}\n\n/**\n * 创建dom\n *\n * @inner\n * @param {string} id dom id 待用\n * @param {Painter} painter painter instance\n * @param {number} number\n */\nfunction createDom(id, painter, dpr) {\n    var newDom = createCanvas();\n    var width = painter.getWidth();\n    var height = painter.getHeight();\n\n    var newDomStyle = newDom.style;\n    if (newDomStyle) {  // In node or some other non-browser environment\n        newDomStyle.position = 'absolute';\n        newDomStyle.left = 0;\n        newDomStyle.top = 0;\n        newDomStyle.width = width + 'px';\n        newDomStyle.height = height + 'px';\n\n        newDom.setAttribute('data-zr-dom-id', id);\n    }\n\n    newDom.width = width * dpr;\n    newDom.height = height * dpr;\n\n    return newDom;\n}\n\n/**\n * @alias module:zrender/Layer\n * @constructor\n * @extends module:zrender/mixin/Transformable\n * @param {string} id\n * @param {module:zrender/Painter} painter\n * @param {number} [dpr]\n */\nvar Layer = function (id, painter, dpr) {\n    var dom;\n    dpr = dpr || devicePixelRatio;\n    if (typeof id === 'string') {\n        dom = createDom(id, painter, dpr);\n    }\n    // Not using isDom because in node it will return false\n    else if (isObject$1(id)) {\n        dom = id;\n        id = dom.id;\n    }\n    this.id = id;\n    this.dom = dom;\n\n    var domStyle = dom.style;\n    if (domStyle) { // Not in node\n        dom.onselectstart = returnFalse; // 避免页面选中的尴尬\n        domStyle['-webkit-user-select'] = 'none';\n        domStyle['user-select'] = 'none';\n        domStyle['-webkit-touch-callout'] = 'none';\n        domStyle['-webkit-tap-highlight-color'] = 'rgba(0,0,0,0)';\n        domStyle['padding'] = 0;\n        domStyle['margin'] = 0;\n        domStyle['border-width'] = 0;\n    }\n\n    this.domBack = null;\n    this.ctxBack = null;\n\n    this.painter = painter;\n\n    this.config = null;\n\n    // Configs\n    /**\n     * 每次清空画布的颜色\n     * @type {string}\n     * @default 0\n     */\n    this.clearColor = 0;\n    /**\n     * 是否开启动态模糊\n     * @type {boolean}\n     * @default false\n     */\n    this.motionBlur = false;\n    /**\n     * 在开启动态模糊的时候使用，与上一帧混合的alpha值，值越大尾迹越明显\n     * @type {number}\n     * @default 0.7\n     */\n    this.lastFrameAlpha = 0.7;\n\n    /**\n     * Layer dpr\n     * @type {number}\n     */\n    this.dpr = dpr;\n};\n\nLayer.prototype = {\n\n    constructor: Layer,\n\n    __dirty: true,\n\n    __used: false,\n\n    __drawIndex: 0,\n    __startIndex: 0,\n    __endIndex: 0,\n\n    incremental: false,\n\n    getElementCount: function () {\n        return this.__endIndex - this.__startIndex;\n    },\n\n    initContext: function () {\n        this.ctx = this.dom.getContext('2d');\n        this.ctx.dpr = this.dpr;\n    },\n\n    createBackBuffer: function () {\n        var dpr = this.dpr;\n\n        this.domBack = createDom('back-' + this.id, this.painter, dpr);\n        this.ctxBack = this.domBack.getContext('2d');\n\n        if (dpr !== 1) {\n            this.ctxBack.scale(dpr, dpr);\n        }\n    },\n\n    /**\n     * @param  {number} width\n     * @param  {number} height\n     */\n    resize: function (width, height) {\n        var dpr = this.dpr;\n\n        var dom = this.dom;\n        var domStyle = dom.style;\n        var domBack = this.domBack;\n\n        if (domStyle) {\n            domStyle.width = width + 'px';\n            domStyle.height = height + 'px';\n        }\n\n        dom.width = width * dpr;\n        dom.height = height * dpr;\n\n        if (domBack) {\n            domBack.width = width * dpr;\n            domBack.height = height * dpr;\n\n            if (dpr !== 1) {\n                this.ctxBack.scale(dpr, dpr);\n            }\n        }\n    },\n\n    /**\n     * 清空该层画布\n     * @param {boolean} [clearAll]=false Clear all with out motion blur\n     * @param {Color} [clearColor]\n     */\n    clear: function (clearAll, clearColor) {\n        var dom = this.dom;\n        var ctx = this.ctx;\n        var width = dom.width;\n        var height = dom.height;\n\n        var clearColor = clearColor || this.clearColor;\n        var haveMotionBLur = this.motionBlur && !clearAll;\n        var lastFrameAlpha = this.lastFrameAlpha;\n\n        var dpr = this.dpr;\n\n        if (haveMotionBLur) {\n            if (!this.domBack) {\n                this.createBackBuffer();\n            }\n\n            this.ctxBack.globalCompositeOperation = 'copy';\n            this.ctxBack.drawImage(\n                dom, 0, 0,\n                width / dpr,\n                height / dpr\n            );\n        }\n\n        ctx.clearRect(0, 0, width, height);\n        if (clearColor && clearColor !== 'transparent') {\n            var clearColorGradientOrPattern;\n            // Gradient\n            if (clearColor.colorStops) {\n                // Cache canvas gradient\n                clearColorGradientOrPattern = clearColor.__canvasGradient || Style.getGradient(ctx, clearColor, {\n                    x: 0,\n                    y: 0,\n                    width: width,\n                    height: height\n                });\n\n                clearColor.__canvasGradient = clearColorGradientOrPattern;\n            }\n            // Pattern\n            else if (clearColor.image) {\n                clearColorGradientOrPattern = Pattern.prototype.getCanvasPattern.call(clearColor, ctx);\n            }\n            ctx.save();\n            ctx.fillStyle = clearColorGradientOrPattern || clearColor;\n            ctx.fillRect(0, 0, width, height);\n            ctx.restore();\n        }\n\n        if (haveMotionBLur) {\n            var domBack = this.domBack;\n            ctx.save();\n            ctx.globalAlpha = lastFrameAlpha;\n            ctx.drawImage(domBack, 0, 0, width, height);\n            ctx.restore();\n        }\n    }\n};\n\nvar requestAnimationFrame = (\n    typeof window !== 'undefined'\n    && (\n        (window.requestAnimationFrame && window.requestAnimationFrame.bind(window))\n        // https://github.com/ecomfe/zrender/issues/189#issuecomment-224919809\n        || (window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window))\n        || window.mozRequestAnimationFrame\n        || window.webkitRequestAnimationFrame\n    )\n) || function (func) {\n    setTimeout(func, 16);\n};\n\nvar globalImageCache = new LRU(50);\n\n/**\n * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc\n * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image\n */\nfunction findExistImage(newImageOrSrc) {\n    if (typeof newImageOrSrc === 'string') {\n        var cachedImgObj = globalImageCache.get(newImageOrSrc);\n        return cachedImgObj && cachedImgObj.image;\n    }\n    else {\n        return newImageOrSrc;\n    }\n}\n\n/**\n * Caution: User should cache loaded images, but not just count on LRU.\n * Consider if required images more than LRU size, will dead loop occur?\n *\n * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc\n * @param {HTMLImageElement|HTMLCanvasElement|Canvas} image Existent image.\n * @param {module:zrender/Element} [hostEl] For calling `dirty`.\n * @param {Function} [cb] params: (image, cbPayload)\n * @param {Object} [cbPayload] Payload on cb calling.\n * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image\n */\nfunction createOrUpdateImage(newImageOrSrc, image, hostEl, cb, cbPayload) {\n    if (!newImageOrSrc) {\n        return image;\n    }\n    else if (typeof newImageOrSrc === 'string') {\n\n        // Image should not be loaded repeatly.\n        if ((image && image.__zrImageSrc === newImageOrSrc) || !hostEl) {\n            return image;\n        }\n\n        // Only when there is no existent image or existent image src\n        // is different, this method is responsible for load.\n        var cachedImgObj = globalImageCache.get(newImageOrSrc);\n\n        var pendingWrap = {hostEl: hostEl, cb: cb, cbPayload: cbPayload};\n\n        if (cachedImgObj) {\n            image = cachedImgObj.image;\n            !isImageReady(image) && cachedImgObj.pending.push(pendingWrap);\n        }\n        else {\n            image = new Image();\n            image.onload = image.onerror = imageOnLoad;\n\n            globalImageCache.put(\n                newImageOrSrc,\n                image.__cachedImgObj = {\n                    image: image,\n                    pending: [pendingWrap]\n                }\n            );\n\n            image.src = image.__zrImageSrc = newImageOrSrc;\n        }\n\n        return image;\n    }\n    // newImageOrSrc is an HTMLImageElement or HTMLCanvasElement or Canvas\n    else {\n        return newImageOrSrc;\n    }\n}\n\nfunction imageOnLoad() {\n    var cachedImgObj = this.__cachedImgObj;\n    this.onload = this.onerror = this.__cachedImgObj = null;\n\n    for (var i = 0; i < cachedImgObj.pending.length; i++) {\n        var pendingWrap = cachedImgObj.pending[i];\n        var cb = pendingWrap.cb;\n        cb && cb(this, pendingWrap.cbPayload);\n        pendingWrap.hostEl.dirty();\n    }\n    cachedImgObj.pending.length = 0;\n}\n\nfunction isImageReady(image) {\n    return image && image.width && image.height;\n}\n\nvar textWidthCache = {};\nvar textWidthCacheCounter = 0;\n\nvar TEXT_CACHE_MAX = 5000;\nvar STYLE_REG = /\\{([a-zA-Z0-9_]+)\\|([^}]*)\\}/g;\n\nvar DEFAULT_FONT$1 = '12px sans-serif';\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar methods$1 = {};\n\nfunction $override$1(name, fn) {\n    methods$1[name] = fn;\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @return {number} width\n */\nfunction getWidth(text, font) {\n    font = font || DEFAULT_FONT$1;\n    var key = text + ':' + font;\n    if (textWidthCache[key]) {\n        return textWidthCache[key];\n    }\n\n    var textLines = (text + '').split('\\n');\n    var width = 0;\n\n    for (var i = 0, l = textLines.length; i < l; i++) {\n        // textContain.measureText may be overrided in SVG or VML\n        width = Math.max(measureText(textLines[i], font).width, width);\n    }\n\n    if (textWidthCacheCounter > TEXT_CACHE_MAX) {\n        textWidthCacheCounter = 0;\n        textWidthCache = {};\n    }\n    textWidthCacheCounter++;\n    textWidthCache[key] = width;\n\n    return width;\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @param {string} [textAlign='left']\n * @param {string} [textVerticalAlign='top']\n * @param {Array.<number>} [textPadding]\n * @param {Object} [rich]\n * @param {Object} [truncate]\n * @return {Object} {x, y, width, height, lineHeight}\n */\nfunction getBoundingRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) {\n    return rich\n        ? getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate)\n        : getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate);\n}\n\nfunction getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate) {\n    var contentBlock = parsePlainText(text, font, textPadding, textLineHeight, truncate);\n    var outerWidth = getWidth(text, font);\n    if (textPadding) {\n        outerWidth += textPadding[1] + textPadding[3];\n    }\n    var outerHeight = contentBlock.outerHeight;\n\n    var x = adjustTextX(0, outerWidth, textAlign);\n    var y = adjustTextY(0, outerHeight, textVerticalAlign);\n\n    var rect = new BoundingRect(x, y, outerWidth, outerHeight);\n    rect.lineHeight = contentBlock.lineHeight;\n\n    return rect;\n}\n\nfunction getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) {\n    var contentBlock = parseRichText(text, {\n        rich: rich,\n        truncate: truncate,\n        font: font,\n        textAlign: textAlign,\n        textPadding: textPadding,\n        textLineHeight: textLineHeight\n    });\n    var outerWidth = contentBlock.outerWidth;\n    var outerHeight = contentBlock.outerHeight;\n\n    var x = adjustTextX(0, outerWidth, textAlign);\n    var y = adjustTextY(0, outerHeight, textVerticalAlign);\n\n    return new BoundingRect(x, y, outerWidth, outerHeight);\n}\n\n/**\n * @public\n * @param {number} x\n * @param {number} width\n * @param {string} [textAlign='left']\n * @return {number} Adjusted x.\n */\nfunction adjustTextX(x, width, textAlign) {\n    // FIXME Right to left language\n    if (textAlign === 'right') {\n        x -= width;\n    }\n    else if (textAlign === 'center') {\n        x -= width / 2;\n    }\n    return x;\n}\n\n/**\n * @public\n * @param {number} y\n * @param {number} height\n * @param {string} [textVerticalAlign='top']\n * @return {number} Adjusted y.\n */\nfunction adjustTextY(y, height, textVerticalAlign) {\n    if (textVerticalAlign === 'middle') {\n        y -= height / 2;\n    }\n    else if (textVerticalAlign === 'bottom') {\n        y -= height;\n    }\n    return y;\n}\n\n/**\n * @public\n * @param {stirng} textPosition\n * @param {Object} rect {x, y, width, height}\n * @param {number} distance\n * @return {Object} {x, y, textAlign, textVerticalAlign}\n */\nfunction adjustTextPositionOnRect(textPosition, rect, distance) {\n\n    var x = rect.x;\n    var y = rect.y;\n\n    var height = rect.height;\n    var width = rect.width;\n    var halfHeight = height / 2;\n\n    var textAlign = 'left';\n    var textVerticalAlign = 'top';\n\n    switch (textPosition) {\n        case 'left':\n            x -= distance;\n            y += halfHeight;\n            textAlign = 'right';\n            textVerticalAlign = 'middle';\n            break;\n        case 'right':\n            x += distance + width;\n            y += halfHeight;\n            textVerticalAlign = 'middle';\n            break;\n        case 'top':\n            x += width / 2;\n            y -= distance;\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            break;\n        case 'bottom':\n            x += width / 2;\n            y += height + distance;\n            textAlign = 'center';\n            break;\n        case 'inside':\n            x += width / 2;\n            y += halfHeight;\n            textAlign = 'center';\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideLeft':\n            x += distance;\n            y += halfHeight;\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideRight':\n            x += width - distance;\n            y += halfHeight;\n            textAlign = 'right';\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideTop':\n            x += width / 2;\n            y += distance;\n            textAlign = 'center';\n            break;\n        case 'insideBottom':\n            x += width / 2;\n            y += height - distance;\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            break;\n        case 'insideTopLeft':\n            x += distance;\n            y += distance;\n            break;\n        case 'insideTopRight':\n            x += width - distance;\n            y += distance;\n            textAlign = 'right';\n            break;\n        case 'insideBottomLeft':\n            x += distance;\n            y += height - distance;\n            textVerticalAlign = 'bottom';\n            break;\n        case 'insideBottomRight':\n            x += width - distance;\n            y += height - distance;\n            textAlign = 'right';\n            textVerticalAlign = 'bottom';\n            break;\n    }\n\n    return {\n        x: x,\n        y: y,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\n/**\n * Show ellipsis if overflow.\n *\n * @public\n * @param  {string} text\n * @param  {string} containerWidth\n * @param  {string} font\n * @param  {number} [ellipsis='...']\n * @param  {Object} [options]\n * @param  {number} [options.maxIterations=3]\n * @param  {number} [options.minChar=0] If truncate result are less\n *                  then minChar, ellipsis will not show, which is\n *                  better for user hint in some cases.\n * @param  {number} [options.placeholder=''] When all truncated, use the placeholder.\n * @return {string}\n */\nfunction truncateText(text, containerWidth, font, ellipsis, options) {\n    if (!containerWidth) {\n        return '';\n    }\n\n    var textLines = (text + '').split('\\n');\n    options = prepareTruncateOptions(containerWidth, font, ellipsis, options);\n\n    // FIXME\n    // It is not appropriate that every line has '...' when truncate multiple lines.\n    for (var i = 0, len = textLines.length; i < len; i++) {\n        textLines[i] = truncateSingleLine(textLines[i], options);\n    }\n\n    return textLines.join('\\n');\n}\n\nfunction prepareTruncateOptions(containerWidth, font, ellipsis, options) {\n    options = extend({}, options);\n\n    options.font = font;\n    var ellipsis = retrieve2(ellipsis, '...');\n    options.maxIterations = retrieve2(options.maxIterations, 2);\n    var minChar = options.minChar = retrieve2(options.minChar, 0);\n    // FIXME\n    // Other languages?\n    options.cnCharWidth = getWidth('国', font);\n    // FIXME\n    // Consider proportional font?\n    var ascCharWidth = options.ascCharWidth = getWidth('a', font);\n    options.placeholder = retrieve2(options.placeholder, '');\n\n    // Example 1: minChar: 3, text: 'asdfzxcv', truncate result: 'asdf', but not: 'a...'.\n    // Example 2: minChar: 3, text: '维度', truncate result: '维', but not: '...'.\n    var contentWidth = containerWidth = Math.max(0, containerWidth - 1); // Reserve some gap.\n    for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) {\n        contentWidth -= ascCharWidth;\n    }\n\n    var ellipsisWidth = getWidth(ellipsis, font);\n    if (ellipsisWidth > contentWidth) {\n        ellipsis = '';\n        ellipsisWidth = 0;\n    }\n\n    contentWidth = containerWidth - ellipsisWidth;\n\n    options.ellipsis = ellipsis;\n    options.ellipsisWidth = ellipsisWidth;\n    options.contentWidth = contentWidth;\n    options.containerWidth = containerWidth;\n\n    return options;\n}\n\nfunction truncateSingleLine(textLine, options) {\n    var containerWidth = options.containerWidth;\n    var font = options.font;\n    var contentWidth = options.contentWidth;\n\n    if (!containerWidth) {\n        return '';\n    }\n\n    var lineWidth = getWidth(textLine, font);\n\n    if (lineWidth <= containerWidth) {\n        return textLine;\n    }\n\n    for (var j = 0; ; j++) {\n        if (lineWidth <= contentWidth || j >= options.maxIterations) {\n            textLine += options.ellipsis;\n            break;\n        }\n\n        var subLength = j === 0\n            ? estimateLength(textLine, contentWidth, options.ascCharWidth, options.cnCharWidth)\n            : lineWidth > 0\n            ? Math.floor(textLine.length * contentWidth / lineWidth)\n            : 0;\n\n        textLine = textLine.substr(0, subLength);\n        lineWidth = getWidth(textLine, font);\n    }\n\n    if (textLine === '') {\n        textLine = options.placeholder;\n    }\n\n    return textLine;\n}\n\nfunction estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) {\n    var width = 0;\n    var i = 0;\n    for (var len = text.length; i < len && width < contentWidth; i++) {\n        var charCode = text.charCodeAt(i);\n        width += (0 <= charCode && charCode <= 127) ? ascCharWidth : cnCharWidth;\n    }\n    return i;\n}\n\n/**\n * @public\n * @param {string} font\n * @return {number} line height\n */\nfunction getLineHeight(font) {\n    // FIXME A rough approach.\n    return getWidth('国', font);\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @return {Object} width\n */\nfunction measureText(text, font) {\n    return methods$1.measureText(text, font);\n}\n\n// Avoid assign to an exported variable, for transforming to cjs.\nmethods$1.measureText = function (text, font) {\n    var ctx = getContext();\n    ctx.font = font || DEFAULT_FONT$1;\n    return ctx.measureText(text);\n};\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @param {Object} [truncate]\n * @return {Object} block: {lineHeight, lines, height, outerHeight}\n *  Notice: for performance, do not calculate outerWidth util needed.\n */\nfunction parsePlainText(text, font, padding, textLineHeight, truncate) {\n    text != null && (text += '');\n\n    var lineHeight = retrieve2(textLineHeight, getLineHeight(font));\n    var lines = text ? text.split('\\n') : [];\n    var height = lines.length * lineHeight;\n    var outerHeight = height;\n\n    if (padding) {\n        outerHeight += padding[0] + padding[2];\n    }\n\n    if (text && truncate) {\n        var truncOuterHeight = truncate.outerHeight;\n        var truncOuterWidth = truncate.outerWidth;\n        if (truncOuterHeight != null && outerHeight > truncOuterHeight) {\n            text = '';\n            lines = [];\n        }\n        else if (truncOuterWidth != null) {\n            var options = prepareTruncateOptions(\n                truncOuterWidth - (padding ? padding[1] + padding[3] : 0),\n                font,\n                truncate.ellipsis,\n                {minChar: truncate.minChar, placeholder: truncate.placeholder}\n            );\n\n            // FIXME\n            // It is not appropriate that every line has '...' when truncate multiple lines.\n            for (var i = 0, len = lines.length; i < len; i++) {\n                lines[i] = truncateSingleLine(lines[i], options);\n            }\n        }\n    }\n\n    return {\n        lines: lines,\n        height: height,\n        outerHeight: outerHeight,\n        lineHeight: lineHeight\n    };\n}\n\n/**\n * For example: 'some text {a|some text}other text{b|some text}xxx{c|}xxx'\n * Also consider 'bbbb{a|xxx\\nzzz}xxxx\\naaaa'.\n *\n * @public\n * @param {string} text\n * @param {Object} style\n * @return {Object} block\n * {\n *      width,\n *      height,\n *      lines: [{\n *          lineHeight,\n *          width,\n *          tokens: [[{\n *              styleName,\n *              text,\n *              width,      // include textPadding\n *              height,     // include textPadding\n *              textWidth, // pure text width\n *              textHeight, // pure text height\n *              lineHeihgt,\n *              font,\n *              textAlign,\n *              textVerticalAlign\n *          }], [...], ...]\n *      }, ...]\n * }\n * If styleName is undefined, it is plain text.\n */\nfunction parseRichText(text, style) {\n    var contentBlock = {lines: [], width: 0, height: 0};\n\n    text != null && (text += '');\n    if (!text) {\n        return contentBlock;\n    }\n\n    var lastIndex = STYLE_REG.lastIndex = 0;\n    var result;\n    while ((result = STYLE_REG.exec(text)) != null) {\n        var matchedIndex = result.index;\n        if (matchedIndex > lastIndex) {\n            pushTokens(contentBlock, text.substring(lastIndex, matchedIndex));\n        }\n        pushTokens(contentBlock, result[2], result[1]);\n        lastIndex = STYLE_REG.lastIndex;\n    }\n\n    if (lastIndex < text.length) {\n        pushTokens(contentBlock, text.substring(lastIndex, text.length));\n    }\n\n    var lines = contentBlock.lines;\n    var contentHeight = 0;\n    var contentWidth = 0;\n    // For `textWidth: 100%`\n    var pendingList = [];\n\n    var stlPadding = style.textPadding;\n\n    var truncate = style.truncate;\n    var truncateWidth = truncate && truncate.outerWidth;\n    var truncateHeight = truncate && truncate.outerHeight;\n    if (stlPadding) {\n        truncateWidth != null && (truncateWidth -= stlPadding[1] + stlPadding[3]);\n        truncateHeight != null && (truncateHeight -= stlPadding[0] + stlPadding[2]);\n    }\n\n    // Calculate layout info of tokens.\n    for (var i = 0; i < lines.length; i++) {\n        var line = lines[i];\n        var lineHeight = 0;\n        var lineWidth = 0;\n\n        for (var j = 0; j < line.tokens.length; j++) {\n            var token = line.tokens[j];\n            var tokenStyle = token.styleName && style.rich[token.styleName] || {};\n            // textPadding should not inherit from style.\n            var textPadding = token.textPadding = tokenStyle.textPadding;\n\n            // textFont has been asigned to font by `normalizeStyle`.\n            var font = token.font = tokenStyle.font || style.font;\n\n            // textHeight can be used when textVerticalAlign is specified in token.\n            var tokenHeight = token.textHeight = retrieve2(\n                // textHeight should not be inherited, consider it can be specified\n                // as box height of the block.\n                tokenStyle.textHeight, getLineHeight(font)\n            );\n            textPadding && (tokenHeight += textPadding[0] + textPadding[2]);\n            token.height = tokenHeight;\n            token.lineHeight = retrieve3(\n                tokenStyle.textLineHeight, style.textLineHeight, tokenHeight\n            );\n\n            token.textAlign = tokenStyle && tokenStyle.textAlign || style.textAlign;\n            token.textVerticalAlign = tokenStyle && tokenStyle.textVerticalAlign || 'middle';\n\n            if (truncateHeight != null && contentHeight + token.lineHeight > truncateHeight) {\n                return {lines: [], width: 0, height: 0};\n            }\n\n            token.textWidth = getWidth(token.text, font);\n            var tokenWidth = tokenStyle.textWidth;\n            var tokenWidthNotSpecified = tokenWidth == null || tokenWidth === 'auto';\n\n            // Percent width, can be `100%`, can be used in drawing separate\n            // line when box width is needed to be auto.\n            if (typeof tokenWidth === 'string' && tokenWidth.charAt(tokenWidth.length - 1) === '%') {\n                token.percentWidth = tokenWidth;\n                pendingList.push(token);\n                tokenWidth = 0;\n                // Do not truncate in this case, because there is no user case\n                // and it is too complicated.\n            }\n            else {\n                if (tokenWidthNotSpecified) {\n                    tokenWidth = token.textWidth;\n\n                    // FIXME: If image is not loaded and textWidth is not specified, calling\n                    // `getBoundingRect()` will not get correct result.\n                    var textBackgroundColor = tokenStyle.textBackgroundColor;\n                    var bgImg = textBackgroundColor && textBackgroundColor.image;\n\n                    // Use cases:\n                    // (1) If image is not loaded, it will be loaded at render phase and call\n                    // `dirty()` and `textBackgroundColor.image` will be replaced with the loaded\n                    // image, and then the right size will be calculated here at the next tick.\n                    // See `graphic/helper/text.js`.\n                    // (2) If image loaded, and `textBackgroundColor.image` is image src string,\n                    // use `imageHelper.findExistImage` to find cached image.\n                    // `imageHelper.findExistImage` will always be called here before\n                    // `imageHelper.createOrUpdateImage` in `graphic/helper/text.js#renderRichText`\n                    // which ensures that image will not be rendered before correct size calcualted.\n                    if (bgImg) {\n                        bgImg = findExistImage(bgImg);\n                        if (isImageReady(bgImg)) {\n                            tokenWidth = Math.max(tokenWidth, bgImg.width * tokenHeight / bgImg.height);\n                        }\n                    }\n                }\n\n                var paddingW = textPadding ? textPadding[1] + textPadding[3] : 0;\n                tokenWidth += paddingW;\n\n                var remianTruncWidth = truncateWidth != null ? truncateWidth - lineWidth : null;\n\n                if (remianTruncWidth != null && remianTruncWidth < tokenWidth) {\n                    if (!tokenWidthNotSpecified || remianTruncWidth < paddingW) {\n                        token.text = '';\n                        token.textWidth = tokenWidth = 0;\n                    }\n                    else {\n                        token.text = truncateText(\n                            token.text, remianTruncWidth - paddingW, font, truncate.ellipsis,\n                            {minChar: truncate.minChar}\n                        );\n                        token.textWidth = getWidth(token.text, font);\n                        tokenWidth = token.textWidth + paddingW;\n                    }\n                }\n            }\n\n            lineWidth += (token.width = tokenWidth);\n            tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight));\n        }\n\n        line.width = lineWidth;\n        line.lineHeight = lineHeight;\n        contentHeight += lineHeight;\n        contentWidth = Math.max(contentWidth, lineWidth);\n    }\n\n    contentBlock.outerWidth = contentBlock.width = retrieve2(style.textWidth, contentWidth);\n    contentBlock.outerHeight = contentBlock.height = retrieve2(style.textHeight, contentHeight);\n\n    if (stlPadding) {\n        contentBlock.outerWidth += stlPadding[1] + stlPadding[3];\n        contentBlock.outerHeight += stlPadding[0] + stlPadding[2];\n    }\n\n    for (var i = 0; i < pendingList.length; i++) {\n        var token = pendingList[i];\n        var percentWidth = token.percentWidth;\n        // Should not base on outerWidth, because token can not be placed out of padding.\n        token.width = parseInt(percentWidth, 10) / 100 * contentWidth;\n    }\n\n    return contentBlock;\n}\n\nfunction pushTokens(block, str, styleName) {\n    var isEmptyStr = str === '';\n    var strs = str.split('\\n');\n    var lines = block.lines;\n\n    for (var i = 0; i < strs.length; i++) {\n        var text = strs[i];\n        var token = {\n            styleName: styleName,\n            text: text,\n            isLineHolder: !text && !isEmptyStr\n        };\n\n        // The first token should be appended to the last line.\n        if (!i) {\n            var tokens = (lines[lines.length - 1] || (lines[0] = {tokens: []})).tokens;\n\n            // Consider cases:\n            // (1) ''.split('\\n') => ['', '\\n', ''], the '' at the first item\n            // (which is a placeholder) should be replaced by new token.\n            // (2) A image backage, where token likes {a|}.\n            // (3) A redundant '' will affect textAlign in line.\n            // (4) tokens with the same tplName should not be merged, because\n            // they should be displayed in different box (with border and padding).\n            var tokensLen = tokens.length;\n            (tokensLen === 1 && tokens[0].isLineHolder)\n                ? (tokens[0] = token)\n                // Consider text is '', only insert when it is the \"lineHolder\" or\n                // \"emptyStr\". Otherwise a redundant '' will affect textAlign in line.\n                : ((text || !tokensLen || isEmptyStr) && tokens.push(token));\n        }\n        // Other tokens always start a new line.\n        else {\n            // If there is '', insert it as a placeholder.\n            lines.push({tokens: [token]});\n        }\n    }\n}\n\nfunction makeFont(style) {\n    // FIXME in node-canvas fontWeight is before fontStyle\n    // Use `fontSize` `fontFamily` to check whether font properties are defined.\n    var font = (style.fontSize || style.fontFamily) && [\n        style.fontStyle,\n        style.fontWeight,\n        (style.fontSize || 12) + 'px',\n        // If font properties are defined, `fontFamily` should not be ignored.\n        style.fontFamily || 'sans-serif'\n    ].join(' ');\n    return font && trim(font) || style.textFont || style.font;\n}\n\n/**\n * @param {Object} ctx\n * @param {Object} shape\n * @param {number} shape.x\n * @param {number} shape.y\n * @param {number} shape.width\n * @param {number} shape.height\n * @param {number} shape.r\n */\nfunction buildPath(ctx, shape) {\n    var x = shape.x;\n    var y = shape.y;\n    var width = shape.width;\n    var height = shape.height;\n    var r = shape.r;\n    var r1;\n    var r2;\n    var r3;\n    var r4;\n\n    // Convert width and height to positive for better borderRadius\n    if (width < 0) {\n        x = x + width;\n        width = -width;\n    }\n    if (height < 0) {\n        y = y + height;\n        height = -height;\n    }\n\n    if (typeof r === 'number') {\n        r1 = r2 = r3 = r4 = r;\n    }\n    else if (r instanceof Array) {\n        if (r.length === 1) {\n            r1 = r2 = r3 = r4 = r[0];\n        }\n        else if (r.length === 2) {\n            r1 = r3 = r[0];\n            r2 = r4 = r[1];\n        }\n        else if (r.length === 3) {\n            r1 = r[0];\n            r2 = r4 = r[1];\n            r3 = r[2];\n        }\n        else {\n            r1 = r[0];\n            r2 = r[1];\n            r3 = r[2];\n            r4 = r[3];\n        }\n    }\n    else {\n        r1 = r2 = r3 = r4 = 0;\n    }\n\n    var total;\n    if (r1 + r2 > width) {\n        total = r1 + r2;\n        r1 *= width / total;\n        r2 *= width / total;\n    }\n    if (r3 + r4 > width) {\n        total = r3 + r4;\n        r3 *= width / total;\n        r4 *= width / total;\n    }\n    if (r2 + r3 > height) {\n        total = r2 + r3;\n        r2 *= height / total;\n        r3 *= height / total;\n    }\n    if (r1 + r4 > height) {\n        total = r1 + r4;\n        r1 *= height / total;\n        r4 *= height / total;\n    }\n    ctx.moveTo(x + r1, y);\n    ctx.lineTo(x + width - r2, y);\n    r2 !== 0 && ctx.arc(x + width - r2, y + r2, r2, -Math.PI / 2, 0);\n    ctx.lineTo(x + width, y + height - r3);\n    r3 !== 0 && ctx.arc(x + width - r3, y + height - r3, r3, 0, Math.PI / 2);\n    ctx.lineTo(x + r4, y + height);\n    r4 !== 0 && ctx.arc(x + r4, y + height - r4, r4, Math.PI / 2, Math.PI);\n    ctx.lineTo(x, y + r1);\n    r1 !== 0 && ctx.arc(x + r1, y + r1, r1, Math.PI, Math.PI * 1.5);\n}\n\nvar DEFAULT_FONT = DEFAULT_FONT$1;\n\n// TODO: Have not support 'start', 'end' yet.\nvar VALID_TEXT_ALIGN = {left: 1, right: 1, center: 1};\nvar VALID_TEXT_VERTICAL_ALIGN = {top: 1, bottom: 1, middle: 1};\n// Different from `STYLE_COMMON_PROPS` of `graphic/Style`,\n// the default value of shadowColor is `'transparent'`.\nvar SHADOW_STYLE_COMMON_PROPS = [\n    ['textShadowBlur', 'shadowBlur', 0],\n    ['textShadowOffsetX', 'shadowOffsetX', 0],\n    ['textShadowOffsetY', 'shadowOffsetY', 0],\n    ['textShadowColor', 'shadowColor', 'transparent']\n];\n\n/**\n * @param {module:zrender/graphic/Style} style\n * @return {module:zrender/graphic/Style} The input style.\n */\nfunction normalizeTextStyle(style) {\n    normalizeStyle(style);\n    each$1(style.rich, normalizeStyle);\n    return style;\n}\n\nfunction normalizeStyle(style) {\n    if (style) {\n\n        style.font = makeFont(style);\n\n        var textAlign = style.textAlign;\n        textAlign === 'middle' && (textAlign = 'center');\n        style.textAlign = (\n            textAlign == null || VALID_TEXT_ALIGN[textAlign]\n        ) ? textAlign : 'left';\n\n        // Compatible with textBaseline.\n        var textVerticalAlign = style.textVerticalAlign || style.textBaseline;\n        textVerticalAlign === 'center' && (textVerticalAlign = 'middle');\n        style.textVerticalAlign = (\n            textVerticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[textVerticalAlign]\n        ) ? textVerticalAlign : 'top';\n\n        var textPadding = style.textPadding;\n        if (textPadding) {\n            style.textPadding = normalizeCssArray(style.textPadding);\n        }\n    }\n}\n\n/**\n * @param {CanvasRenderingContext2D} ctx\n * @param {string} text\n * @param {module:zrender/graphic/Style} style\n * @param {Object|boolean} [rect] {x, y, width, height}\n *                  If set false, rect text is not used.\n * @param {Element|module:zrender/graphic/helper/constant.WILL_BE_RESTORED} [prevEl] For ctx prop cache.\n */\nfunction renderText(hostEl, ctx, text, style, rect, prevEl) {\n    style.rich\n        ? renderRichText(hostEl, ctx, text, style, rect, prevEl)\n        : renderPlainText(hostEl, ctx, text, style, rect, prevEl);\n}\n\n// Avoid setting to ctx according to prevEl if possible for\n// performance in scenarios of large amount text.\nfunction renderPlainText(hostEl, ctx, text, style, rect, prevEl) {\n    'use strict';\n\n    var needDrawBg = needDrawBackground(style);\n\n    var prevStyle;\n    var checkCache = false;\n    var cachedByMe = ctx.__attrCachedBy === ContextCachedBy.PLAIN_TEXT;\n\n    // Only take and check cache for `Text` el, but not RectText.\n    if (prevEl !== WILL_BE_RESTORED) {\n        if (prevEl) {\n            prevStyle = prevEl.style;\n            checkCache = !needDrawBg && cachedByMe && prevStyle;\n        }\n\n        // Prevent from using cache in `Style::bind`, because of the case:\n        // ctx property is modified by other properties than `Style::bind`\n        // used, and Style::bind is called next.\n        ctx.__attrCachedBy = needDrawBg ? ContextCachedBy.NONE : ContextCachedBy.PLAIN_TEXT;\n    }\n    // Since this will be restored, prevent from using these props to check cache in the next\n    // entering of this method. But do not need to clear other cache like `Style::bind`.\n    else if (cachedByMe) {\n        ctx.__attrCachedBy = ContextCachedBy.NONE;\n    }\n\n    var styleFont = style.font || DEFAULT_FONT;\n    // PENDING\n    // Only `Text` el set `font` and keep it (`RectText` will restore). So theoretically\n    // we can make font cache on ctx, which can cache for text el that are discontinuous.\n    // But layer save/restore needed to be considered.\n    // if (styleFont !== ctx.__fontCache) {\n    //     ctx.font = styleFont;\n    //     if (prevEl !== WILL_BE_RESTORED) {\n    //         ctx.__fontCache = styleFont;\n    //     }\n    // }\n    if (!checkCache || styleFont !== (prevStyle.font || DEFAULT_FONT)) {\n        ctx.font = styleFont;\n    }\n\n    // Use the final font from context-2d, because the final\n    // font might not be the style.font when it is illegal.\n    // But get `ctx.font` might be time consuming.\n    var computedFont = hostEl.__computedFont;\n    if (hostEl.__styleFont !== styleFont) {\n        hostEl.__styleFont = styleFont;\n        computedFont = hostEl.__computedFont = ctx.font;\n    }\n\n    var textPadding = style.textPadding;\n    var textLineHeight = style.textLineHeight;\n\n    var contentBlock = hostEl.__textCotentBlock;\n    if (!contentBlock || hostEl.__dirtyText) {\n        contentBlock = hostEl.__textCotentBlock = parsePlainText(\n            text, computedFont, textPadding, textLineHeight, style.truncate\n        );\n    }\n\n    var outerHeight = contentBlock.outerHeight;\n\n    var textLines = contentBlock.lines;\n    var lineHeight = contentBlock.lineHeight;\n\n    var boxPos = getBoxPosition(outerHeight, style, rect);\n    var baseX = boxPos.baseX;\n    var baseY = boxPos.baseY;\n    var textAlign = boxPos.textAlign || 'left';\n    var textVerticalAlign = boxPos.textVerticalAlign;\n\n    // Origin of textRotation should be the base point of text drawing.\n    applyTextRotation(ctx, style, rect, baseX, baseY);\n\n    var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);\n    var textX = baseX;\n    var textY = boxY;\n\n    if (needDrawBg || textPadding) {\n        // Consider performance, do not call getTextWidth util necessary.\n        var textWidth = getWidth(text, computedFont);\n        var outerWidth = textWidth;\n        textPadding && (outerWidth += textPadding[1] + textPadding[3]);\n        var boxX = adjustTextX(baseX, outerWidth, textAlign);\n\n        needDrawBg && drawBackground(hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight);\n\n        if (textPadding) {\n            textX = getTextXForPadding(baseX, textAlign, textPadding);\n            textY += textPadding[0];\n        }\n    }\n\n    // Always set textAlign and textBase line, because it is difficute to calculate\n    // textAlign from prevEl, and we dont sure whether textAlign will be reset if\n    // font set happened.\n    ctx.textAlign = textAlign;\n    // Force baseline to be \"middle\". Otherwise, if using \"top\", the\n    // text will offset downward a little bit in font \"Microsoft YaHei\".\n    ctx.textBaseline = 'middle';\n    // Set text opacity\n    ctx.globalAlpha = style.opacity || 1;\n\n    // Always set shadowBlur and shadowOffset to avoid leak from displayable.\n    for (var i = 0; i < SHADOW_STYLE_COMMON_PROPS.length; i++) {\n        var propItem = SHADOW_STYLE_COMMON_PROPS[i];\n        var styleProp = propItem[0];\n        var ctxProp = propItem[1];\n        var val = style[styleProp];\n        if (!checkCache || val !== prevStyle[styleProp]) {\n            ctx[ctxProp] = fixShadow(ctx, ctxProp, val || propItem[2]);\n        }\n    }\n\n    // `textBaseline` is set as 'middle'.\n    textY += lineHeight / 2;\n\n    var textStrokeWidth = style.textStrokeWidth;\n    var textStrokeWidthPrev = checkCache ? prevStyle.textStrokeWidth : null;\n    var strokeWidthChanged = !checkCache || textStrokeWidth !== textStrokeWidthPrev;\n    var strokeChanged = !checkCache || strokeWidthChanged || style.textStroke !== prevStyle.textStroke;\n    var textStroke = getStroke(style.textStroke, textStrokeWidth);\n    var textFill = getFill(style.textFill);\n\n    if (textStroke) {\n        if (strokeWidthChanged) {\n            ctx.lineWidth = textStrokeWidth;\n        }\n        if (strokeChanged) {\n            ctx.strokeStyle = textStroke;\n        }\n    }\n    if (textFill) {\n        if (!checkCache || style.textFill !== prevStyle.textFill) {\n            ctx.fillStyle = textFill;\n        }\n    }\n\n    // Optimize simply, in most cases only one line exists.\n    if (textLines.length === 1) {\n        // Fill after stroke so the outline will not cover the main part.\n        textStroke && ctx.strokeText(textLines[0], textX, textY);\n        textFill && ctx.fillText(textLines[0], textX, textY);\n    }\n    else {\n        for (var i = 0; i < textLines.length; i++) {\n            // Fill after stroke so the outline will not cover the main part.\n            textStroke && ctx.strokeText(textLines[i], textX, textY);\n            textFill && ctx.fillText(textLines[i], textX, textY);\n            textY += lineHeight;\n        }\n    }\n}\n\nfunction renderRichText(hostEl, ctx, text, style, rect, prevEl) {\n    // Do not do cache for rich text because of the complexity.\n    // But `RectText` this will be restored, do not need to clear other cache like `Style::bind`.\n    if (prevEl !== WILL_BE_RESTORED) {\n        ctx.__attrCachedBy = ContextCachedBy.NONE;\n    }\n\n    var contentBlock = hostEl.__textCotentBlock;\n\n    if (!contentBlock || hostEl.__dirtyText) {\n        contentBlock = hostEl.__textCotentBlock = parseRichText(text, style);\n    }\n\n    drawRichText(hostEl, ctx, contentBlock, style, rect);\n}\n\nfunction drawRichText(hostEl, ctx, contentBlock, style, rect) {\n    var contentWidth = contentBlock.width;\n    var outerWidth = contentBlock.outerWidth;\n    var outerHeight = contentBlock.outerHeight;\n    var textPadding = style.textPadding;\n\n    var boxPos = getBoxPosition(outerHeight, style, rect);\n    var baseX = boxPos.baseX;\n    var baseY = boxPos.baseY;\n    var textAlign = boxPos.textAlign;\n    var textVerticalAlign = boxPos.textVerticalAlign;\n\n    // Origin of textRotation should be the base point of text drawing.\n    applyTextRotation(ctx, style, rect, baseX, baseY);\n\n    var boxX = adjustTextX(baseX, outerWidth, textAlign);\n    var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);\n    var xLeft = boxX;\n    var lineTop = boxY;\n    if (textPadding) {\n        xLeft += textPadding[3];\n        lineTop += textPadding[0];\n    }\n    var xRight = xLeft + contentWidth;\n\n    needDrawBackground(style) && drawBackground(\n        hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight\n    );\n\n    for (var i = 0; i < contentBlock.lines.length; i++) {\n        var line = contentBlock.lines[i];\n        var tokens = line.tokens;\n        var tokenCount = tokens.length;\n        var lineHeight = line.lineHeight;\n        var usedWidth = line.width;\n\n        var leftIndex = 0;\n        var lineXLeft = xLeft;\n        var lineXRight = xRight;\n        var rightIndex = tokenCount - 1;\n        var token;\n\n        while (\n            leftIndex < tokenCount\n            && (token = tokens[leftIndex], !token.textAlign || token.textAlign === 'left')\n        ) {\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft, 'left');\n            usedWidth -= token.width;\n            lineXLeft += token.width;\n            leftIndex++;\n        }\n\n        while (\n            rightIndex >= 0\n            && (token = tokens[rightIndex], token.textAlign === 'right')\n        ) {\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXRight, 'right');\n            usedWidth -= token.width;\n            lineXRight -= token.width;\n            rightIndex--;\n        }\n\n        // The other tokens are placed as textAlign 'center' if there is enough space.\n        lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - usedWidth) / 2;\n        while (leftIndex <= rightIndex) {\n            token = tokens[leftIndex];\n            // Consider width specified by user, use 'center' rather than 'left'.\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center');\n            lineXLeft += token.width;\n            leftIndex++;\n        }\n\n        lineTop += lineHeight;\n    }\n}\n\nfunction applyTextRotation(ctx, style, rect, x, y) {\n    // textRotation only apply in RectText.\n    if (rect && style.textRotation) {\n        var origin = style.textOrigin;\n        if (origin === 'center') {\n            x = rect.width / 2 + rect.x;\n            y = rect.height / 2 + rect.y;\n        }\n        else if (origin) {\n            x = origin[0] + rect.x;\n            y = origin[1] + rect.y;\n        }\n\n        ctx.translate(x, y);\n        // Positive: anticlockwise\n        ctx.rotate(-style.textRotation);\n        ctx.translate(-x, -y);\n    }\n}\n\nfunction placeToken(hostEl, ctx, token, style, lineHeight, lineTop, x, textAlign) {\n    var tokenStyle = style.rich[token.styleName] || {};\n    tokenStyle.text = token.text;\n\n    // 'ctx.textBaseline' is always set as 'middle', for sake of\n    // the bias of \"Microsoft YaHei\".\n    var textVerticalAlign = token.textVerticalAlign;\n    var y = lineTop + lineHeight / 2;\n    if (textVerticalAlign === 'top') {\n        y = lineTop + token.height / 2;\n    }\n    else if (textVerticalAlign === 'bottom') {\n        y = lineTop + lineHeight - token.height / 2;\n    }\n\n    !token.isLineHolder && needDrawBackground(tokenStyle) && drawBackground(\n        hostEl,\n        ctx,\n        tokenStyle,\n        textAlign === 'right'\n            ? x - token.width\n            : textAlign === 'center'\n            ? x - token.width / 2\n            : x,\n        y - token.height / 2,\n        token.width,\n        token.height\n    );\n\n    var textPadding = token.textPadding;\n    if (textPadding) {\n        x = getTextXForPadding(x, textAlign, textPadding);\n        y -= token.height / 2 - textPadding[2] - token.textHeight / 2;\n    }\n\n    setCtx(ctx, 'shadowBlur', retrieve3(tokenStyle.textShadowBlur, style.textShadowBlur, 0));\n    setCtx(ctx, 'shadowColor', tokenStyle.textShadowColor || style.textShadowColor || 'transparent');\n    setCtx(ctx, 'shadowOffsetX', retrieve3(tokenStyle.textShadowOffsetX, style.textShadowOffsetX, 0));\n    setCtx(ctx, 'shadowOffsetY', retrieve3(tokenStyle.textShadowOffsetY, style.textShadowOffsetY, 0));\n\n    setCtx(ctx, 'textAlign', textAlign);\n    // Force baseline to be \"middle\". Otherwise, if using \"top\", the\n    // text will offset downward a little bit in font \"Microsoft YaHei\".\n    setCtx(ctx, 'textBaseline', 'middle');\n\n    setCtx(ctx, 'font', token.font || DEFAULT_FONT);\n\n    var textStroke = getStroke(tokenStyle.textStroke || style.textStroke, textStrokeWidth);\n    var textFill = getFill(tokenStyle.textFill || style.textFill);\n    var textStrokeWidth = retrieve2(tokenStyle.textStrokeWidth, style.textStrokeWidth);\n\n    // Fill after stroke so the outline will not cover the main part.\n    if (textStroke) {\n        setCtx(ctx, 'lineWidth', textStrokeWidth);\n        setCtx(ctx, 'strokeStyle', textStroke);\n        ctx.strokeText(token.text, x, y);\n    }\n    if (textFill) {\n        setCtx(ctx, 'fillStyle', textFill);\n        ctx.fillText(token.text, x, y);\n    }\n}\n\nfunction needDrawBackground(style) {\n    return !!(\n        style.textBackgroundColor\n        || (style.textBorderWidth && style.textBorderColor)\n    );\n}\n\n// style: {textBackgroundColor, textBorderWidth, textBorderColor, textBorderRadius, text}\n// shape: {x, y, width, height}\nfunction drawBackground(hostEl, ctx, style, x, y, width, height) {\n    var textBackgroundColor = style.textBackgroundColor;\n    var textBorderWidth = style.textBorderWidth;\n    var textBorderColor = style.textBorderColor;\n    var isPlainBg = isString(textBackgroundColor);\n\n    setCtx(ctx, 'shadowBlur', style.textBoxShadowBlur || 0);\n    setCtx(ctx, 'shadowColor', style.textBoxShadowColor || 'transparent');\n    setCtx(ctx, 'shadowOffsetX', style.textBoxShadowOffsetX || 0);\n    setCtx(ctx, 'shadowOffsetY', style.textBoxShadowOffsetY || 0);\n\n    if (isPlainBg || (textBorderWidth && textBorderColor)) {\n        ctx.beginPath();\n        var textBorderRadius = style.textBorderRadius;\n        if (!textBorderRadius) {\n            ctx.rect(x, y, width, height);\n        }\n        else {\n            buildPath(ctx, {\n                x: x, y: y, width: width, height: height, r: textBorderRadius\n            });\n        }\n        ctx.closePath();\n    }\n\n    if (isPlainBg) {\n        setCtx(ctx, 'fillStyle', textBackgroundColor);\n\n        if (style.fillOpacity != null) {\n            var originalGlobalAlpha = ctx.globalAlpha;\n            ctx.globalAlpha = style.fillOpacity * style.opacity;\n            ctx.fill();\n            ctx.globalAlpha = originalGlobalAlpha;\n        }\n        else {\n            ctx.fill();\n        }\n    }\n    else if (isObject$1(textBackgroundColor)) {\n        var image = textBackgroundColor.image;\n\n        image = createOrUpdateImage(\n            image, null, hostEl, onBgImageLoaded, textBackgroundColor\n        );\n        if (image && isImageReady(image)) {\n            ctx.drawImage(image, x, y, width, height);\n        }\n    }\n\n    if (textBorderWidth && textBorderColor) {\n        setCtx(ctx, 'lineWidth', textBorderWidth);\n        setCtx(ctx, 'strokeStyle', textBorderColor);\n\n        if (style.strokeOpacity != null) {\n            var originalGlobalAlpha = ctx.globalAlpha;\n            ctx.globalAlpha = style.strokeOpacity * style.opacity;\n            ctx.stroke();\n            ctx.globalAlpha = originalGlobalAlpha;\n        }\n        else {\n            ctx.stroke();\n        }\n    }\n}\n\nfunction onBgImageLoaded(image, textBackgroundColor) {\n    // Replace image, so that `contain/text.js#parseRichText`\n    // will get correct result in next tick.\n    textBackgroundColor.image = image;\n}\n\nfunction getBoxPosition(blockHeiht, style, rect) {\n    var baseX = style.x || 0;\n    var baseY = style.y || 0;\n    var textAlign = style.textAlign;\n    var textVerticalAlign = style.textVerticalAlign;\n\n    // Text position represented by coord\n    if (rect) {\n        var textPosition = style.textPosition;\n        if (textPosition instanceof Array) {\n            // Percent\n            baseX = rect.x + parsePercent(textPosition[0], rect.width);\n            baseY = rect.y + parsePercent(textPosition[1], rect.height);\n        }\n        else {\n            var res = adjustTextPositionOnRect(\n                textPosition, rect, style.textDistance\n            );\n            baseX = res.x;\n            baseY = res.y;\n            // Default align and baseline when has textPosition\n            textAlign = textAlign || res.textAlign;\n            textVerticalAlign = textVerticalAlign || res.textVerticalAlign;\n        }\n\n        // textOffset is only support in RectText, otherwise\n        // we have to adjust boundingRect for textOffset.\n        var textOffset = style.textOffset;\n        if (textOffset) {\n            baseX += textOffset[0];\n            baseY += textOffset[1];\n        }\n    }\n\n    return {\n        baseX: baseX,\n        baseY: baseY,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\nfunction setCtx(ctx, prop, value) {\n    ctx[prop] = fixShadow(ctx, prop, value);\n    return ctx[prop];\n}\n\n/**\n * @param {string} [stroke] If specified, do not check style.textStroke.\n * @param {string} [lineWidth] If specified, do not check style.textStroke.\n * @param {number} style\n */\nfunction getStroke(stroke, lineWidth) {\n    return (stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none')\n        ? null\n        // TODO pattern and gradient?\n        : (stroke.image || stroke.colorStops)\n        ? '#000'\n        : stroke;\n}\n\nfunction getFill(fill) {\n    return (fill == null || fill === 'none')\n        ? null\n        // TODO pattern and gradient?\n        : (fill.image || fill.colorStops)\n        ? '#000'\n        : fill;\n}\n\nfunction parsePercent(value, maxValue) {\n    if (typeof value === 'string') {\n        if (value.lastIndexOf('%') >= 0) {\n            return parseFloat(value) / 100 * maxValue;\n        }\n        return parseFloat(value);\n    }\n    return value;\n}\n\nfunction getTextXForPadding(x, textAlign, textPadding) {\n    return textAlign === 'right'\n        ? (x - textPadding[1])\n        : textAlign === 'center'\n        ? (x + textPadding[3] / 2 - textPadding[1] / 2)\n        : (x + textPadding[3]);\n}\n\n/**\n * @param {string} text\n * @param {module:zrender/Style} style\n * @return {boolean}\n */\nfunction needDrawText(text, style) {\n    return text != null\n        && (text\n            || style.textBackgroundColor\n            || (style.textBorderWidth && style.textBorderColor)\n            || style.textPadding\n        );\n}\n\n/**\n * Mixin for drawing text in a element bounding rect\n * @module zrender/mixin/RectText\n */\n\nvar tmpRect$1 = new BoundingRect();\n\nvar RectText = function () {};\n\nRectText.prototype = {\n\n    constructor: RectText,\n\n    /**\n     * Draw text in a rect with specified position.\n     * @param  {CanvasRenderingContext2D} ctx\n     * @param  {Object} rect Displayable rect\n     */\n    drawRectText: function (ctx, rect) {\n        var style = this.style;\n\n        rect = style.textRect || rect;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        var text = style.text;\n\n        // Convert to string\n        text != null && (text += '');\n\n        if (!needDrawText(text, style)) {\n            return;\n        }\n\n        // FIXME\n        // Do not provide prevEl to `textHelper.renderText` for ctx prop cache,\n        // but use `ctx.save()` and `ctx.restore()`. Because the cache for rect\n        // text propably break the cache for its host elements.\n        ctx.save();\n\n        // Transform rect to view space\n        var transform = this.transform;\n        if (!style.transformText) {\n            if (transform) {\n                tmpRect$1.copy(rect);\n                tmpRect$1.applyTransform(transform);\n                rect = tmpRect$1;\n            }\n        }\n        else {\n            this.setTransform(ctx);\n        }\n\n        // transformText and textRotation can not be used at the same time.\n        renderText(this, ctx, text, style, rect, WILL_BE_RESTORED);\n\n        ctx.restore();\n    }\n};\n\n/**\n * 可绘制的图形基类\n * Base class of all displayable graphic objects\n * @module zrender/graphic/Displayable\n */\n\n\n/**\n * @alias module:zrender/graphic/Displayable\n * @extends module:zrender/Element\n * @extends module:zrender/graphic/mixin/RectText\n */\nfunction Displayable(opts) {\n\n    opts = opts || {};\n\n    Element.call(this, opts);\n\n    // Extend properties\n    for (var name in opts) {\n        if (\n            opts.hasOwnProperty(name)\n                && name !== 'style'\n        ) {\n            this[name] = opts[name];\n        }\n    }\n\n    /**\n     * @type {module:zrender/graphic/Style}\n     */\n    this.style = new Style(opts.style, this);\n\n    this._rect = null;\n    // Shapes for cascade clipping.\n    this.__clipPaths = [];\n\n    // FIXME Stateful must be mixined after style is setted\n    // Stateful.call(this, opts);\n}\n\nDisplayable.prototype = {\n\n    constructor: Displayable,\n\n    type: 'displayable',\n\n    /**\n     * Displayable 是否为脏，Painter 中会根据该标记判断是否需要是否需要重新绘制\n     * Dirty flag. From which painter will determine if this displayable object needs brush\n     * @name module:zrender/graphic/Displayable#__dirty\n     * @type {boolean}\n     */\n    __dirty: true,\n\n    /**\n     * 图形是否可见，为true时不绘制图形，但是仍能触发鼠标事件\n     * If ignore drawing of the displayable object. Mouse event will still be triggered\n     * @name module:/zrender/graphic/Displayable#invisible\n     * @type {boolean}\n     * @default false\n     */\n    invisible: false,\n\n    /**\n     * @name module:/zrender/graphic/Displayable#z\n     * @type {number}\n     * @default 0\n     */\n    z: 0,\n\n    /**\n     * @name module:/zrender/graphic/Displayable#z\n     * @type {number}\n     * @default 0\n     */\n    z2: 0,\n\n    /**\n     * z层level，决定绘画在哪层canvas中\n     * @name module:/zrender/graphic/Displayable#zlevel\n     * @type {number}\n     * @default 0\n     */\n    zlevel: 0,\n\n    /**\n     * 是否可拖拽\n     * @name module:/zrender/graphic/Displayable#draggable\n     * @type {boolean}\n     * @default false\n     */\n    draggable: false,\n\n    /**\n     * 是否正在拖拽\n     * @name module:/zrender/graphic/Displayable#draggable\n     * @type {boolean}\n     * @default false\n     */\n    dragging: false,\n\n    /**\n     * 是否相应鼠标事件\n     * @name module:/zrender/graphic/Displayable#silent\n     * @type {boolean}\n     * @default false\n     */\n    silent: false,\n\n    /**\n     * If enable culling\n     * @type {boolean}\n     * @default false\n     */\n    culling: false,\n\n    /**\n     * Mouse cursor when hovered\n     * @name module:/zrender/graphic/Displayable#cursor\n     * @type {string}\n     */\n    cursor: 'pointer',\n\n    /**\n     * If hover area is bounding rect\n     * @name module:/zrender/graphic/Displayable#rectHover\n     * @type {string}\n     */\n    rectHover: false,\n\n    /**\n     * Render the element progressively when the value >= 0,\n     * usefull for large data.\n     * @type {boolean}\n     */\n    progressive: false,\n\n    /**\n     * @type {boolean}\n     */\n    incremental: false,\n    /**\n     * Scale ratio for global scale.\n     * @type {boolean}\n     */\n    globalScaleRatio: 1,\n\n    beforeBrush: function (ctx) {},\n\n    afterBrush: function (ctx) {},\n\n    /**\n     * 图形绘制方法\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    // Interface\n    brush: function (ctx, prevEl) {},\n\n    /**\n     * 获取最小包围盒\n     * @return {module:zrender/core/BoundingRect}\n     */\n    // Interface\n    getBoundingRect: function () {},\n\n    /**\n     * 判断坐标 x, y 是否在图形上\n     * If displayable element contain coord x, y\n     * @param  {number} x\n     * @param  {number} y\n     * @return {boolean}\n     */\n    contain: function (x, y) {\n        return this.rectContain(x, y);\n    },\n\n    /**\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {\n        cb.call(context, this);\n    },\n\n    /**\n     * 判断坐标 x, y 是否在图形的包围盒上\n     * If bounding rect of element contain coord x, y\n     * @param  {number} x\n     * @param  {number} y\n     * @return {boolean}\n     */\n    rectContain: function (x, y) {\n        var coord = this.transformCoordToLocal(x, y);\n        var rect = this.getBoundingRect();\n        return rect.contain(coord[0], coord[1]);\n    },\n\n    /**\n     * 标记图形元素为脏，并且在下一帧重绘\n     * Mark displayable element dirty and refresh next frame\n     */\n    dirty: function () {\n        this.__dirty = this.__dirtyText = true;\n\n        this._rect = null;\n\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * 图形是否会触发事件\n     * If displayable object binded any event\n     * @return {boolean}\n     */\n    // TODO, 通过 bind 绑定的事件\n    // isSilent: function () {\n    //     return !(\n    //         this.hoverable || this.draggable\n    //         || this.onmousemove || this.onmouseover || this.onmouseout\n    //         || this.onmousedown || this.onmouseup || this.onclick\n    //         || this.ondragenter || this.ondragover || this.ondragleave\n    //         || this.ondrop\n    //     );\n    // },\n    /**\n     * Alias for animate('style')\n     * @param {boolean} loop\n     */\n    animateStyle: function (loop) {\n        return this.animate('style', loop);\n    },\n\n    attrKV: function (key, value) {\n        if (key !== 'style') {\n            Element.prototype.attrKV.call(this, key, value);\n        }\n        else {\n            this.style.set(value);\n        }\n    },\n\n    /**\n     * @param {Object|string} key\n     * @param {*} value\n     */\n    setStyle: function (key, value) {\n        this.style.set(key, value);\n        this.dirty(false);\n        return this;\n    },\n\n    /**\n     * Use given style object\n     * @param  {Object} obj\n     */\n    useStyle: function (obj) {\n        this.style = new Style(obj, this);\n        this.dirty(false);\n        return this;\n    }\n};\n\ninherits(Displayable, Element);\n\nmixin(Displayable, RectText);\n\n/**\n * @alias zrender/graphic/Image\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nfunction ZImage(opts) {\n    Displayable.call(this, opts);\n}\n\nZImage.prototype = {\n\n    constructor: ZImage,\n\n    type: 'image',\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n        var src = style.image;\n\n        // Must bind each time\n        style.bind(ctx, this, prevEl);\n\n        var image = this._image = createOrUpdateImage(\n            src,\n            this._image,\n            this,\n            this.onload\n        );\n\n        if (!image || !isImageReady(image)) {\n            return;\n        }\n\n        // 图片已经加载完成\n        // if (image.nodeName.toUpperCase() == 'IMG') {\n        //     if (!image.complete) {\n        //         return;\n        //     }\n        // }\n        // Else is canvas\n\n        var x = style.x || 0;\n        var y = style.y || 0;\n        var width = style.width;\n        var height = style.height;\n        var aspect = image.width / image.height;\n        if (width == null && height != null) {\n            // Keep image/height ratio\n            width = height * aspect;\n        }\n        else if (height == null && width != null) {\n            height = width / aspect;\n        }\n        else if (width == null && height == null) {\n            width = image.width;\n            height = image.height;\n        }\n\n        // 设置transform\n        this.setTransform(ctx);\n\n        if (style.sWidth && style.sHeight) {\n            var sx = style.sx || 0;\n            var sy = style.sy || 0;\n            ctx.drawImage(\n                image,\n                sx, sy, style.sWidth, style.sHeight,\n                x, y, width, height\n            );\n        }\n        else if (style.sx && style.sy) {\n            var sx = style.sx;\n            var sy = style.sy;\n            var sWidth = width - sx;\n            var sHeight = height - sy;\n            ctx.drawImage(\n                image,\n                sx, sy, sWidth, sHeight,\n                x, y, width, height\n            );\n        }\n        else {\n            ctx.drawImage(image, x, y, width, height);\n        }\n\n        // Draw rect text\n        if (style.text != null) {\n            // Only restore transform when needs draw text.\n            this.restoreTransform(ctx);\n            this.drawRectText(ctx, this.getBoundingRect());\n        }\n    },\n\n    getBoundingRect: function () {\n        var style = this.style;\n        if (!this._rect) {\n            this._rect = new BoundingRect(\n                style.x || 0, style.y || 0, style.width || 0, style.height || 0\n            );\n        }\n        return this._rect;\n    }\n};\n\ninherits(ZImage, Displayable);\n\nvar HOVER_LAYER_ZLEVEL = 1e5;\nvar CANVAS_ZLEVEL = 314159;\n\nvar EL_AFTER_INCREMENTAL_INC = 0.01;\nvar INCREMENTAL_INC = 0.001;\n\nfunction parseInt10(val) {\n    return parseInt(val, 10);\n}\n\nfunction isLayerValid(layer) {\n    if (!layer) {\n        return false;\n    }\n\n    if (layer.__builtin__) {\n        return true;\n    }\n\n    if (typeof (layer.resize) !== 'function'\n        || typeof (layer.refresh) !== 'function'\n    ) {\n        return false;\n    }\n\n    return true;\n}\n\nvar tmpRect = new BoundingRect(0, 0, 0, 0);\nvar viewRect = new BoundingRect(0, 0, 0, 0);\nfunction isDisplayableCulled(el, width, height) {\n    tmpRect.copy(el.getBoundingRect());\n    if (el.transform) {\n        tmpRect.applyTransform(el.transform);\n    }\n    viewRect.width = width;\n    viewRect.height = height;\n    return !tmpRect.intersect(viewRect);\n}\n\nfunction isClipPathChanged(clipPaths, prevClipPaths) {\n    if (clipPaths === prevClipPaths) { // Can both be null or undefined\n        return false;\n    }\n\n    if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) {\n        return true;\n    }\n    for (var i = 0; i < clipPaths.length; i++) {\n        if (clipPaths[i] !== prevClipPaths[i]) {\n            return true;\n        }\n    }\n}\n\nfunction doClip(clipPaths, ctx) {\n    for (var i = 0; i < clipPaths.length; i++) {\n        var clipPath = clipPaths[i];\n\n        clipPath.setTransform(ctx);\n        ctx.beginPath();\n        clipPath.buildPath(ctx, clipPath.shape);\n        ctx.clip();\n        // Transform back\n        clipPath.restoreTransform(ctx);\n    }\n}\n\nfunction createRoot(width, height) {\n    var domRoot = document.createElement('div');\n\n    // domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬\n    domRoot.style.cssText = [\n        'position:relative',\n        'overflow:hidden',\n        'width:' + width + 'px',\n        'height:' + height + 'px',\n        'padding:0',\n        'margin:0',\n        'border-width:0'\n    ].join(';') + ';';\n\n    return domRoot;\n}\n\n\n/**\n * @alias module:zrender/Painter\n * @constructor\n * @param {HTMLElement} root 绘图容器\n * @param {module:zrender/Storage} storage\n * @param {Object} opts\n */\nvar Painter = function (root, storage, opts) {\n\n    this.type = 'canvas';\n\n    // In node environment using node-canvas\n    var singleCanvas = !root.nodeName // In node ?\n        || root.nodeName.toUpperCase() === 'CANVAS';\n\n    this._opts = opts = extend({}, opts || {});\n\n    /**\n     * @type {number}\n     */\n    this.dpr = opts.devicePixelRatio || devicePixelRatio;\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._singleCanvas = singleCanvas;\n    /**\n     * 绘图容器\n     * @type {HTMLElement}\n     */\n    this.root = root;\n\n    var rootStyle = root.style;\n\n    if (rootStyle) {\n        rootStyle['-webkit-tap-highlight-color'] = 'transparent';\n        rootStyle['-webkit-user-select'] =\n        rootStyle['user-select'] =\n        rootStyle['-webkit-touch-callout'] = 'none';\n\n        root.innerHTML = '';\n    }\n\n    /**\n     * @type {module:zrender/Storage}\n     */\n    this.storage = storage;\n\n    /**\n     * @type {Array.<number>}\n     * @private\n     */\n    var zlevelList = this._zlevelList = [];\n\n    /**\n     * @type {Object.<string, module:zrender/Layer>}\n     * @private\n     */\n    var layers = this._layers = {};\n\n    /**\n     * @type {Object.<string, Object>}\n     * @private\n     */\n    this._layerConfig = {};\n\n    /**\n     * zrender will do compositing when root is a canvas and have multiple zlevels.\n     */\n    this._needsManuallyCompositing = false;\n\n    if (!singleCanvas) {\n        this._width = this._getSize(0);\n        this._height = this._getSize(1);\n\n        var domRoot = this._domRoot = createRoot(\n            this._width, this._height\n        );\n        root.appendChild(domRoot);\n    }\n    else {\n        var width = root.width;\n        var height = root.height;\n\n        if (opts.width != null) {\n            width = opts.width;\n        }\n        if (opts.height != null) {\n            height = opts.height;\n        }\n        this.dpr = opts.devicePixelRatio || 1;\n\n        // Use canvas width and height directly\n        root.width = width * this.dpr;\n        root.height = height * this.dpr;\n\n        this._width = width;\n        this._height = height;\n\n        // Create layer if only one given canvas\n        // Device can be specified to create a high dpi image.\n        var mainLayer = new Layer(root, this, this.dpr);\n        mainLayer.__builtin__ = true;\n        mainLayer.initContext();\n        // FIXME Use canvas width and height\n        // mainLayer.resize(width, height);\n        layers[CANVAS_ZLEVEL] = mainLayer;\n        mainLayer.zlevel = CANVAS_ZLEVEL;\n        // Not use common zlevel.\n        zlevelList.push(CANVAS_ZLEVEL);\n\n        this._domRoot = root;\n    }\n\n    /**\n     * @type {module:zrender/Layer}\n     * @private\n     */\n    this._hoverlayer = null;\n\n    this._hoverElements = [];\n};\n\nPainter.prototype = {\n\n    constructor: Painter,\n\n    getType: function () {\n        return 'canvas';\n    },\n\n    /**\n     * If painter use a single canvas\n     * @return {boolean}\n     */\n    isSingleCanvas: function () {\n        return this._singleCanvas;\n    },\n    /**\n     * @return {HTMLDivElement}\n     */\n    getViewportRoot: function () {\n        return this._domRoot;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    /**\n     * 刷新\n     * @param {boolean} [paintAll=false] 强制绘制所有displayable\n     */\n    refresh: function (paintAll) {\n\n        var list = this.storage.getDisplayList(true);\n\n        var zlevelList = this._zlevelList;\n\n        this._redrawId = Math.random();\n\n        this._paintList(list, paintAll, this._redrawId);\n\n        // Paint custum layers\n        for (var i = 0; i < zlevelList.length; i++) {\n            var z = zlevelList[i];\n            var layer = this._layers[z];\n            if (!layer.__builtin__ && layer.refresh) {\n                var clearColor = i === 0 ? this._backgroundColor : null;\n                layer.refresh(clearColor);\n            }\n        }\n\n        this.refreshHover();\n\n        return this;\n    },\n\n    addHover: function (el, hoverStyle) {\n        if (el.__hoverMir) {\n            return;\n        }\n        var elMirror = new el.constructor({\n            style: el.style,\n            shape: el.shape,\n            z: el.z,\n            z2: el.z2,\n            silent: el.silent\n        });\n        elMirror.__from = el;\n        el.__hoverMir = elMirror;\n        hoverStyle && elMirror.setStyle(hoverStyle);\n        this._hoverElements.push(elMirror);\n\n        return elMirror;\n    },\n\n    removeHover: function (el) {\n        var elMirror = el.__hoverMir;\n        var hoverElements = this._hoverElements;\n        var idx = indexOf(hoverElements, elMirror);\n        if (idx >= 0) {\n            hoverElements.splice(idx, 1);\n        }\n        el.__hoverMir = null;\n    },\n\n    clearHover: function (el) {\n        var hoverElements = this._hoverElements;\n        for (var i = 0; i < hoverElements.length; i++) {\n            var from = hoverElements[i].__from;\n            if (from) {\n                from.__hoverMir = null;\n            }\n        }\n        hoverElements.length = 0;\n    },\n\n    refreshHover: function () {\n        var hoverElements = this._hoverElements;\n        var len = hoverElements.length;\n        var hoverLayer = this._hoverlayer;\n        hoverLayer && hoverLayer.clear();\n\n        if (!len) {\n            return;\n        }\n        sort(hoverElements, this.storage.displayableSortFunc);\n\n        // Use a extream large zlevel\n        // FIXME?\n        if (!hoverLayer) {\n            hoverLayer = this._hoverlayer = this.getLayer(HOVER_LAYER_ZLEVEL);\n        }\n\n        var scope = {};\n        hoverLayer.ctx.save();\n        for (var i = 0; i < len;) {\n            var el = hoverElements[i];\n            var originalEl = el.__from;\n            // Original el is removed\n            // PENDING\n            if (!(originalEl && originalEl.__zr)) {\n                hoverElements.splice(i, 1);\n                originalEl.__hoverMir = null;\n                len--;\n                continue;\n            }\n            i++;\n\n            // Use transform\n            // FIXME style and shape ?\n            if (!originalEl.invisible) {\n                el.transform = originalEl.transform;\n                el.invTransform = originalEl.invTransform;\n                el.__clipPaths = originalEl.__clipPaths;\n                // el.\n                this._doPaintEl(el, hoverLayer, true, scope);\n            }\n        }\n\n        hoverLayer.ctx.restore();\n    },\n\n    getHoverLayer: function () {\n        return this.getLayer(HOVER_LAYER_ZLEVEL);\n    },\n\n    _paintList: function (list, paintAll, redrawId) {\n        if (this._redrawId !== redrawId) {\n            return;\n        }\n\n        paintAll = paintAll || false;\n\n        this._updateLayerStatus(list);\n\n        var finished = this._doPaintList(list, paintAll);\n\n        if (this._needsManuallyCompositing) {\n            this._compositeManually();\n        }\n\n        if (!finished) {\n            var self = this;\n            requestAnimationFrame(function () {\n                self._paintList(list, paintAll, redrawId);\n            });\n        }\n    },\n\n    _compositeManually: function () {\n        var ctx = this.getLayer(CANVAS_ZLEVEL).ctx;\n        var width = this._domRoot.width;\n        var height = this._domRoot.height;\n        ctx.clearRect(0, 0, width, height);\n        // PENDING, If only builtin layer?\n        this.eachBuiltinLayer(function (layer) {\n            if (layer.virtual) {\n                ctx.drawImage(layer.dom, 0, 0, width, height);\n            }\n        });\n    },\n\n    _doPaintList: function (list, paintAll) {\n        var layerList = [];\n        for (var zi = 0; zi < this._zlevelList.length; zi++) {\n            var zlevel = this._zlevelList[zi];\n            var layer = this._layers[zlevel];\n            if (layer.__builtin__\n                && layer !== this._hoverlayer\n                && (layer.__dirty || paintAll)\n            ) {\n                layerList.push(layer);\n            }\n        }\n\n        var finished = true;\n\n        for (var k = 0; k < layerList.length; k++) {\n            var layer = layerList[k];\n            var ctx = layer.ctx;\n            var scope = {};\n            ctx.save();\n\n            var start = paintAll ? layer.__startIndex : layer.__drawIndex;\n\n            var useTimer = !paintAll && layer.incremental && Date.now;\n            var startTime = useTimer && Date.now();\n\n            var clearColor = layer.zlevel === this._zlevelList[0]\n                ? this._backgroundColor : null;\n            // All elements in this layer are cleared.\n            if (layer.__startIndex === layer.__endIndex) {\n                layer.clear(false, clearColor);\n            }\n            else if (start === layer.__startIndex) {\n                var firstEl = list[start];\n                if (!firstEl.incremental || !firstEl.notClear || paintAll) {\n                    layer.clear(false, clearColor);\n                }\n            }\n            if (start === -1) {\n                console.error('For some unknown reason. drawIndex is -1');\n                start = layer.__startIndex;\n            }\n            for (var i = start; i < layer.__endIndex; i++) {\n                var el = list[i];\n                this._doPaintEl(el, layer, paintAll, scope);\n                el.__dirty = el.__dirtyText = false;\n\n                if (useTimer) {\n                    // Date.now can be executed in 13,025,305 ops/second.\n                    var dTime = Date.now() - startTime;\n                    // Give 15 millisecond to draw.\n                    // The rest elements will be drawn in the next frame.\n                    if (dTime > 15) {\n                        break;\n                    }\n                }\n            }\n\n            layer.__drawIndex = i;\n\n            if (layer.__drawIndex < layer.__endIndex) {\n                finished = false;\n            }\n\n            if (scope.prevElClipPaths) {\n                // Needs restore the state. If last drawn element is in the clipping area.\n                ctx.restore();\n            }\n\n            ctx.restore();\n        }\n\n        if (env$1.wxa) {\n            // Flush for weixin application\n            each$1(this._layers, function (layer) {\n                if (layer && layer.ctx && layer.ctx.draw) {\n                    layer.ctx.draw();\n                }\n            });\n        }\n\n        return finished;\n    },\n\n    _doPaintEl: function (el, currentLayer, forcePaint, scope) {\n        var ctx = currentLayer.ctx;\n        var m = el.transform;\n        if (\n            (currentLayer.__dirty || forcePaint)\n            // Ignore invisible element\n            && !el.invisible\n            // Ignore transparent element\n            && el.style.opacity !== 0\n            // Ignore scale 0 element, in some environment like node-canvas\n            // Draw a scale 0 element can cause all following draw wrong\n            // And setTransform with scale 0 will cause set back transform failed.\n            && !(m && !m[0] && !m[3])\n            // Ignore culled element\n            && !(el.culling && isDisplayableCulled(el, this._width, this._height))\n        ) {\n\n            var clipPaths = el.__clipPaths;\n\n            // Optimize when clipping on group with several elements\n            if (!scope.prevElClipPaths\n                || isClipPathChanged(clipPaths, scope.prevElClipPaths)\n            ) {\n                // If has previous clipping state, restore from it\n                if (scope.prevElClipPaths) {\n                    currentLayer.ctx.restore();\n                    scope.prevElClipPaths = null;\n\n                    // Reset prevEl since context has been restored\n                    scope.prevEl = null;\n                }\n                // New clipping state\n                if (clipPaths) {\n                    ctx.save();\n                    doClip(clipPaths, ctx);\n                    scope.prevElClipPaths = clipPaths;\n                }\n            }\n            el.beforeBrush && el.beforeBrush(ctx);\n\n            el.brush(ctx, scope.prevEl || null);\n            scope.prevEl = el;\n\n            el.afterBrush && el.afterBrush(ctx);\n        }\n    },\n\n    /**\n     * 获取 zlevel 所在层，如果不存在则会创建一个新的层\n     * @param {number} zlevel\n     * @param {boolean} virtual Virtual layer will not be inserted into dom.\n     * @return {module:zrender/Layer}\n     */\n    getLayer: function (zlevel, virtual) {\n        if (this._singleCanvas && !this._needsManuallyCompositing) {\n            zlevel = CANVAS_ZLEVEL;\n        }\n        var layer = this._layers[zlevel];\n        if (!layer) {\n            // Create a new layer\n            layer = new Layer('zr_' + zlevel, this, this.dpr);\n            layer.zlevel = zlevel;\n            layer.__builtin__ = true;\n\n            if (this._layerConfig[zlevel]) {\n                merge(layer, this._layerConfig[zlevel], true);\n            }\n\n            if (virtual) {\n                layer.virtual = virtual;\n            }\n\n            this.insertLayer(zlevel, layer);\n\n            // Context is created after dom inserted to document\n            // Or excanvas will get 0px clientWidth and clientHeight\n            layer.initContext();\n        }\n\n        return layer;\n    },\n\n    insertLayer: function (zlevel, layer) {\n\n        var layersMap = this._layers;\n        var zlevelList = this._zlevelList;\n        var len = zlevelList.length;\n        var prevLayer = null;\n        var i = -1;\n        var domRoot = this._domRoot;\n\n        if (layersMap[zlevel]) {\n            zrLog('ZLevel ' + zlevel + ' has been used already');\n            return;\n        }\n        // Check if is a valid layer\n        if (!isLayerValid(layer)) {\n            zrLog('Layer of zlevel ' + zlevel + ' is not valid');\n            return;\n        }\n\n        if (len > 0 && zlevel > zlevelList[0]) {\n            for (i = 0; i < len - 1; i++) {\n                if (\n                    zlevelList[i] < zlevel\n                    && zlevelList[i + 1] > zlevel\n                ) {\n                    break;\n                }\n            }\n            prevLayer = layersMap[zlevelList[i]];\n        }\n        zlevelList.splice(i + 1, 0, zlevel);\n\n        layersMap[zlevel] = layer;\n\n        // Vitual layer will not directly show on the screen.\n        // (It can be a WebGL layer and assigned to a ZImage element)\n        // But it still under management of zrender.\n        if (!layer.virtual) {\n            if (prevLayer) {\n                var prevDom = prevLayer.dom;\n                if (prevDom.nextSibling) {\n                    domRoot.insertBefore(\n                        layer.dom,\n                        prevDom.nextSibling\n                    );\n                }\n                else {\n                    domRoot.appendChild(layer.dom);\n                }\n            }\n            else {\n                if (domRoot.firstChild) {\n                    domRoot.insertBefore(layer.dom, domRoot.firstChild);\n                }\n                else {\n                    domRoot.appendChild(layer.dom);\n                }\n            }\n        }\n    },\n\n    // Iterate each layer\n    eachLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            cb.call(context, this._layers[z], z);\n        }\n    },\n\n    // Iterate each buildin layer\n    eachBuiltinLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var layer;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            layer = this._layers[z];\n            if (layer.__builtin__) {\n                cb.call(context, layer, z);\n            }\n        }\n    },\n\n    // Iterate each other layer except buildin layer\n    eachOtherLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var layer;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            layer = this._layers[z];\n            if (!layer.__builtin__) {\n                cb.call(context, layer, z);\n            }\n        }\n    },\n\n    /**\n     * 获取所有已创建的层\n     * @param {Array.<module:zrender/Layer>} [prevLayer]\n     */\n    getLayers: function () {\n        return this._layers;\n    },\n\n    _updateLayerStatus: function (list) {\n\n        this.eachBuiltinLayer(function (layer, z) {\n            layer.__dirty = layer.__used = false;\n        });\n\n        function updatePrevLayer(idx) {\n            if (prevLayer) {\n                if (prevLayer.__endIndex !== idx) {\n                    prevLayer.__dirty = true;\n                }\n                prevLayer.__endIndex = idx;\n            }\n        }\n\n        if (this._singleCanvas) {\n            for (var i = 1; i < list.length; i++) {\n                var el = list[i];\n                if (el.zlevel !== list[i - 1].zlevel || el.incremental) {\n                    this._needsManuallyCompositing = true;\n                    break;\n                }\n            }\n        }\n\n        var prevLayer = null;\n        var incrementalLayerCount = 0;\n        for (var i = 0; i < list.length; i++) {\n            var el = list[i];\n            var zlevel = el.zlevel;\n            var layer;\n            // PENDING If change one incremental element style ?\n            // TODO Where there are non-incremental elements between incremental elements.\n            if (el.incremental) {\n                layer = this.getLayer(zlevel + INCREMENTAL_INC, this._needsManuallyCompositing);\n                layer.incremental = true;\n                incrementalLayerCount = 1;\n            }\n            else {\n                layer = this.getLayer(zlevel + (incrementalLayerCount > 0 ? EL_AFTER_INCREMENTAL_INC : 0), this._needsManuallyCompositing);\n            }\n\n            if (!layer.__builtin__) {\n                zrLog('ZLevel ' + zlevel + ' has been used by unkown layer ' + layer.id);\n            }\n\n            if (layer !== prevLayer) {\n                layer.__used = true;\n                if (layer.__startIndex !== i) {\n                    layer.__dirty = true;\n                }\n                layer.__startIndex = i;\n                if (!layer.incremental) {\n                    layer.__drawIndex = i;\n                }\n                else {\n                    // Mark layer draw index needs to update.\n                    layer.__drawIndex = -1;\n                }\n                updatePrevLayer(i);\n                prevLayer = layer;\n            }\n            if (el.__dirty) {\n                layer.__dirty = true;\n                if (layer.incremental && layer.__drawIndex < 0) {\n                    // Start draw from the first dirty element.\n                    layer.__drawIndex = i;\n                }\n            }\n        }\n\n        updatePrevLayer(i);\n\n        this.eachBuiltinLayer(function (layer, z) {\n            // Used in last frame but not in this frame. Needs clear\n            if (!layer.__used && layer.getElementCount() > 0) {\n                layer.__dirty = true;\n                layer.__startIndex = layer.__endIndex = layer.__drawIndex = 0;\n            }\n            // For incremental layer. In case start index changed and no elements are dirty.\n            if (layer.__dirty && layer.__drawIndex < 0) {\n                layer.__drawIndex = layer.__startIndex;\n            }\n        });\n    },\n\n    /**\n     * 清除hover层外所有内容\n     */\n    clear: function () {\n        this.eachBuiltinLayer(this._clearLayer);\n        return this;\n    },\n\n    _clearLayer: function (layer) {\n        layer.clear();\n    },\n\n    setBackgroundColor: function (backgroundColor) {\n        this._backgroundColor = backgroundColor;\n    },\n\n    /**\n     * 修改指定zlevel的绘制参数\n     *\n     * @param {string} zlevel\n     * @param {Object} config 配置对象\n     * @param {string} [config.clearColor=0] 每次清空画布的颜色\n     * @param {string} [config.motionBlur=false] 是否开启动态模糊\n     * @param {number} [config.lastFrameAlpha=0.7]\n     *                 在开启动态模糊的时候使用，与上一帧混合的alpha值，值越大尾迹越明显\n     */\n    configLayer: function (zlevel, config) {\n        if (config) {\n            var layerConfig = this._layerConfig;\n            if (!layerConfig[zlevel]) {\n                layerConfig[zlevel] = config;\n            }\n            else {\n                merge(layerConfig[zlevel], config, true);\n            }\n\n            for (var i = 0; i < this._zlevelList.length; i++) {\n                var _zlevel = this._zlevelList[i];\n                if (_zlevel === zlevel || _zlevel === zlevel + EL_AFTER_INCREMENTAL_INC) {\n                    var layer = this._layers[_zlevel];\n                    merge(layer, layerConfig[zlevel], true);\n                }\n            }\n        }\n    },\n\n    /**\n     * 删除指定层\n     * @param {number} zlevel 层所在的zlevel\n     */\n    delLayer: function (zlevel) {\n        var layers = this._layers;\n        var zlevelList = this._zlevelList;\n        var layer = layers[zlevel];\n        if (!layer) {\n            return;\n        }\n        layer.dom.parentNode.removeChild(layer.dom);\n        delete layers[zlevel];\n\n        zlevelList.splice(indexOf(zlevelList, zlevel), 1);\n    },\n\n    /**\n     * 区域大小变化后重绘\n     */\n    resize: function (width, height) {\n        if (!this._domRoot.style) { // Maybe in node or worker\n            if (width == null || height == null) {\n                return;\n            }\n            this._width = width;\n            this._height = height;\n\n            this.getLayer(CANVAS_ZLEVEL).resize(width, height);\n        }\n        else {\n            var domRoot = this._domRoot;\n            // FIXME Why ?\n            domRoot.style.display = 'none';\n\n            // Save input w/h\n            var opts = this._opts;\n            width != null && (opts.width = width);\n            height != null && (opts.height = height);\n\n            width = this._getSize(0);\n            height = this._getSize(1);\n\n            domRoot.style.display = '';\n\n            // 优化没有实际改变的resize\n            if (this._width !== width || height !== this._height) {\n                domRoot.style.width = width + 'px';\n                domRoot.style.height = height + 'px';\n\n                for (var id in this._layers) {\n                    if (this._layers.hasOwnProperty(id)) {\n                        this._layers[id].resize(width, height);\n                    }\n                }\n                each$1(this._progressiveLayers, function (layer) {\n                    layer.resize(width, height);\n                });\n\n                this.refresh(true);\n            }\n\n            this._width = width;\n            this._height = height;\n\n        }\n        return this;\n    },\n\n    /**\n     * 清除单独的一个层\n     * @param {number} zlevel\n     */\n    clearLayer: function (zlevel) {\n        var layer = this._layers[zlevel];\n        if (layer) {\n            layer.clear();\n        }\n    },\n\n    /**\n     * 释放\n     */\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this.root =\n        this.storage =\n\n        this._domRoot =\n        this._layers = null;\n    },\n\n    /**\n     * Get canvas which has all thing rendered\n     * @param {Object} opts\n     * @param {string} [opts.backgroundColor]\n     * @param {number} [opts.pixelRatio]\n     */\n    getRenderedCanvas: function (opts) {\n        opts = opts || {};\n        if (this._singleCanvas && !this._compositeManually) {\n            return this._layers[CANVAS_ZLEVEL].dom;\n        }\n\n        var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr);\n        imageLayer.initContext();\n        imageLayer.clear(false, opts.backgroundColor || this._backgroundColor);\n\n        if (opts.pixelRatio <= this.dpr) {\n            this.refresh();\n\n            var width = imageLayer.dom.width;\n            var height = imageLayer.dom.height;\n            var ctx = imageLayer.ctx;\n            this.eachLayer(function (layer) {\n                if (layer.__builtin__) {\n                    ctx.drawImage(layer.dom, 0, 0, width, height);\n                }\n                else if (layer.renderToCanvas) {\n                    imageLayer.ctx.save();\n                    layer.renderToCanvas(imageLayer.ctx);\n                    imageLayer.ctx.restore();\n                }\n            });\n        }\n        else {\n            // PENDING, echarts-gl and incremental rendering.\n            var scope = {};\n            var displayList = this.storage.getDisplayList(true);\n            for (var i = 0; i < displayList.length; i++) {\n                var el = displayList[i];\n                this._doPaintEl(el, imageLayer, true, scope);\n            }\n        }\n\n        return imageLayer.dom;\n    },\n    /**\n     * 获取绘图区域宽度\n     */\n    getWidth: function () {\n        return this._width;\n    },\n\n    /**\n     * 获取绘图区域高度\n     */\n    getHeight: function () {\n        return this._height;\n    },\n\n    _getSize: function (whIdx) {\n        var opts = this._opts;\n        var wh = ['width', 'height'][whIdx];\n        var cwh = ['clientWidth', 'clientHeight'][whIdx];\n        var plt = ['paddingLeft', 'paddingTop'][whIdx];\n        var prb = ['paddingRight', 'paddingBottom'][whIdx];\n\n        if (opts[wh] != null && opts[wh] !== 'auto') {\n            return parseFloat(opts[wh]);\n        }\n\n        var root = this.root;\n        // IE8 does not support getComputedStyle, but it use VML.\n        var stl = document.defaultView.getComputedStyle(root);\n\n        return (\n            (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh]))\n            - (parseInt10(stl[plt]) || 0)\n            - (parseInt10(stl[prb]) || 0)\n        ) | 0;\n    },\n\n    pathToImage: function (path, dpr) {\n        dpr = dpr || this.dpr;\n\n        var canvas = document.createElement('canvas');\n        var ctx = canvas.getContext('2d');\n        var rect = path.getBoundingRect();\n        var style = path.style;\n        var shadowBlurSize = style.shadowBlur * dpr;\n        var shadowOffsetX = style.shadowOffsetX * dpr;\n        var shadowOffsetY = style.shadowOffsetY * dpr;\n        var lineWidth = style.hasStroke() ? style.lineWidth : 0;\n\n        var leftMargin = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize);\n        var rightMargin = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize);\n        var topMargin = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize);\n        var bottomMargin = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize);\n        var width = rect.width + leftMargin + rightMargin;\n        var height = rect.height + topMargin + bottomMargin;\n\n        canvas.width = width * dpr;\n        canvas.height = height * dpr;\n\n        ctx.scale(dpr, dpr);\n        ctx.clearRect(0, 0, width, height);\n        ctx.dpr = dpr;\n\n        var pathTransform = {\n            position: path.position,\n            rotation: path.rotation,\n            scale: path.scale\n        };\n        path.position = [leftMargin - rect.x, topMargin - rect.y];\n        path.rotation = 0;\n        path.scale = [1, 1];\n        path.updateTransform();\n        if (path) {\n            path.brush(ctx);\n        }\n\n        var ImageShape = ZImage;\n        var imgShape = new ImageShape({\n            style: {\n                x: 0,\n                y: 0,\n                image: canvas\n            }\n        });\n\n        if (pathTransform.position != null) {\n            imgShape.position = path.position = pathTransform.position;\n        }\n\n        if (pathTransform.rotation != null) {\n            imgShape.rotation = path.rotation = pathTransform.rotation;\n        }\n\n        if (pathTransform.scale != null) {\n            imgShape.scale = path.scale = pathTransform.scale;\n        }\n\n        return imgShape;\n    }\n};\n\n/**\n * 动画主类, 调度和管理所有动画控制器\n *\n * @module zrender/animation/Animation\n * @author pissang(https://github.com/pissang)\n */\n// TODO Additive animation\n// http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/\n// https://developer.apple.com/videos/wwdc2014/#236\n\n/**\n * @typedef {Object} IZRenderStage\n * @property {Function} update\n */\n\n/**\n * @alias module:zrender/animation/Animation\n * @constructor\n * @param {Object} [options]\n * @param {Function} [options.onframe]\n * @param {IZRenderStage} [options.stage]\n * @example\n *     var animation = new Animation();\n *     var obj = {\n *         x: 100,\n *         y: 100\n *     };\n *     animation.animate(node.position)\n *         .when(1000, {\n *             x: 500,\n *             y: 500\n *         })\n *         .when(2000, {\n *             x: 100,\n *             y: 100\n *         })\n *         .start('spline');\n */\nvar Animation = function (options) {\n\n    options = options || {};\n\n    this.stage = options.stage || {};\n\n    this.onframe = options.onframe || function () {};\n\n    // private properties\n    this._clips = [];\n\n    this._running = false;\n\n    this._time;\n\n    this._pausedTime;\n\n    this._pauseStart;\n\n    this._paused = false;\n\n    Eventful.call(this);\n};\n\nAnimation.prototype = {\n\n    constructor: Animation,\n    /**\n     * 添加 clip\n     * @param {module:zrender/animation/Clip} clip\n     */\n    addClip: function (clip) {\n        this._clips.push(clip);\n    },\n    /**\n     * 添加 animator\n     * @param {module:zrender/animation/Animator} animator\n     */\n    addAnimator: function (animator) {\n        animator.animation = this;\n        var clips = animator.getClips();\n        for (var i = 0; i < clips.length; i++) {\n            this.addClip(clips[i]);\n        }\n    },\n    /**\n     * 删除动画片段\n     * @param {module:zrender/animation/Clip} clip\n     */\n    removeClip: function (clip) {\n        var idx = indexOf(this._clips, clip);\n        if (idx >= 0) {\n            this._clips.splice(idx, 1);\n        }\n    },\n\n    /**\n     * 删除动画片段\n     * @param {module:zrender/animation/Animator} animator\n     */\n    removeAnimator: function (animator) {\n        var clips = animator.getClips();\n        for (var i = 0; i < clips.length; i++) {\n            this.removeClip(clips[i]);\n        }\n        animator.animation = null;\n    },\n\n    _update: function () {\n        var time = new Date().getTime() - this._pausedTime;\n        var delta = time - this._time;\n        var clips = this._clips;\n        var len = clips.length;\n\n        var deferredEvents = [];\n        var deferredClips = [];\n        for (var i = 0; i < len; i++) {\n            var clip = clips[i];\n            var e = clip.step(time, delta);\n            // Throw out the events need to be called after\n            // stage.update, like destroy\n            if (e) {\n                deferredEvents.push(e);\n                deferredClips.push(clip);\n            }\n        }\n\n        // Remove the finished clip\n        for (var i = 0; i < len;) {\n            if (clips[i]._needsRemove) {\n                clips[i] = clips[len - 1];\n                clips.pop();\n                len--;\n            }\n            else {\n                i++;\n            }\n        }\n\n        len = deferredEvents.length;\n        for (var i = 0; i < len; i++) {\n            deferredClips[i].fire(deferredEvents[i]);\n        }\n\n        this._time = time;\n\n        this.onframe(delta);\n\n        // 'frame' should be triggered before stage, because upper application\n        // depends on the sequence (e.g., echarts-stream and finish\n        // event judge)\n        this.trigger('frame', delta);\n\n        if (this.stage.update) {\n            this.stage.update();\n        }\n    },\n\n    _startLoop: function () {\n        var self = this;\n\n        this._running = true;\n\n        function step() {\n            if (self._running) {\n\n                requestAnimationFrame(step);\n\n                !self._paused && self._update();\n            }\n        }\n\n        requestAnimationFrame(step);\n    },\n\n    /**\n     * Start animation.\n     */\n    start: function () {\n\n        this._time = new Date().getTime();\n        this._pausedTime = 0;\n\n        this._startLoop();\n    },\n\n    /**\n     * Stop animation.\n     */\n    stop: function () {\n        this._running = false;\n    },\n\n    /**\n     * Pause animation.\n     */\n    pause: function () {\n        if (!this._paused) {\n            this._pauseStart = new Date().getTime();\n            this._paused = true;\n        }\n    },\n\n    /**\n     * Resume animation.\n     */\n    resume: function () {\n        if (this._paused) {\n            this._pausedTime += (new Date().getTime()) - this._pauseStart;\n            this._paused = false;\n        }\n    },\n\n    /**\n     * Clear animation.\n     */\n    clear: function () {\n        this._clips = [];\n    },\n\n    /**\n     * Whether animation finished.\n     */\n    isFinished: function () {\n        return !this._clips.length;\n    },\n\n    /**\n     * Creat animator for a target, whose props can be animated.\n     *\n     * @param  {Object} target\n     * @param  {Object} options\n     * @param  {boolean} [options.loop=false] Whether loop animation.\n     * @param  {Function} [options.getter=null] Get value from target.\n     * @param  {Function} [options.setter=null] Set value to target.\n     * @return {module:zrender/animation/Animation~Animator}\n     */\n    // TODO Gap\n    animate: function (target, options) {\n        options = options || {};\n\n        var animator = new Animator(\n            target,\n            options.loop,\n            options.getter,\n            options.setter\n        );\n\n        this.addAnimator(animator);\n\n        return animator;\n    }\n};\n\nmixin(Animation, Eventful);\n\nvar TOUCH_CLICK_DELAY = 300;\n\nvar mouseHandlerNames = [\n    'click', 'dblclick', 'mousewheel', 'mouseout',\n    'mouseup', 'mousedown', 'mousemove', 'contextmenu'\n];\n\nvar touchHandlerNames = [\n    'touchstart', 'touchend', 'touchmove'\n];\n\nvar pointerEventNames = {\n    pointerdown: 1, pointerup: 1, pointermove: 1, pointerout: 1\n};\n\nvar pointerHandlerNames = map(mouseHandlerNames, function (name) {\n    var nm = name.replace('mouse', 'pointer');\n    return pointerEventNames[nm] ? nm : name;\n});\n\nfunction eventNameFix(name) {\n    return (name === 'mousewheel' && env$1.browser.firefox) ? 'DOMMouseScroll' : name;\n}\n\n// function onMSGestureChange(proxy, event) {\n//     if (event.translationX || event.translationY) {\n//         // mousemove is carried by MSGesture to reduce the sensitivity.\n//         proxy.handler.dispatchToElement(event.target, 'mousemove', event);\n//     }\n//     if (event.scale !== 1) {\n//         event.pinchX = event.offsetX;\n//         event.pinchY = event.offsetY;\n//         event.pinchScale = event.scale;\n//         proxy.handler.dispatchToElement(event.target, 'pinch', event);\n//     }\n// }\n\n/**\n * Prevent mouse event from being dispatched after Touch Events action\n * @see <https://github.com/deltakosh/handjs/blob/master/src/hand.base.js>\n * 1. Mobile browsers dispatch mouse events 300ms after touchend.\n * 2. Chrome for Android dispatch mousedown for long-touch about 650ms\n * Result: Blocking Mouse Events for 700ms.\n */\nfunction setTouchTimer(instance) {\n    instance._touching = true;\n    clearTimeout(instance._touchTimer);\n    instance._touchTimer = setTimeout(function () {\n        instance._touching = false;\n    }, 700);\n}\n\n\nvar domHandlers = {\n    /**\n     * Mouse move handler\n     * @inner\n     * @param {Event} event\n     */\n    mousemove: function (event) {\n        event = normalizeEvent(this.dom, event);\n\n        this.trigger('mousemove', event);\n    },\n\n    /**\n     * Mouse out handler\n     * @inner\n     * @param {Event} event\n     */\n    mouseout: function (event) {\n        event = normalizeEvent(this.dom, event);\n\n        var element = event.toElement || event.relatedTarget;\n        if (element !== this.dom) {\n            while (element && element.nodeType !== 9) {\n                // 忽略包含在root中的dom引起的mouseOut\n                if (element === this.dom) {\n                    return;\n                }\n\n                element = element.parentNode;\n            }\n        }\n\n        this.trigger('mouseout', event);\n    },\n\n    /**\n     * Touch开始响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchstart: function (event) {\n        // Default mouse behaviour should not be disabled here.\n        // For example, page may needs to be slided.\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this._lastTouchMoment = new Date();\n\n        this.handler.processGesture(this, event, 'start');\n\n        // In touch device, trigger `mousemove`(`mouseover`) should\n        // be triggered, and must before `mousedown` triggered.\n        domHandlers.mousemove.call(this, event);\n\n        domHandlers.mousedown.call(this, event);\n\n        setTouchTimer(this);\n    },\n\n    /**\n     * Touch移动响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchmove: function (event) {\n\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this.handler.processGesture(this, event, 'change');\n\n        // Mouse move should always be triggered no matter whether\n        // there is gestrue event, because mouse move and pinch may\n        // be used at the same time.\n        domHandlers.mousemove.call(this, event);\n\n        setTouchTimer(this);\n    },\n\n    /**\n     * Touch结束响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchend: function (event) {\n\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this.handler.processGesture(this, event, 'end');\n\n        domHandlers.mouseup.call(this, event);\n\n        // Do not trigger `mouseout` here, in spite of `mousemove`(`mouseover`) is\n        // triggered in `touchstart`. This seems to be illogical, but by this mechanism,\n        // we can conveniently implement \"hover style\" in both PC and touch device just\n        // by listening to `mouseover` to add \"hover style\" and listening to `mouseout`\n        // to remove \"hover style\" on an element, without any additional code for\n        // compatibility. (`mouseout` will not be triggered in `touchend`, so \"hover\n        // style\" will remain for user view)\n\n        // click event should always be triggered no matter whether\n        // there is gestrue event. System click can not be prevented.\n        if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) {\n            domHandlers.click.call(this, event);\n        }\n\n        setTouchTimer(this);\n    },\n\n    pointerdown: function (event) {\n        domHandlers.mousedown.call(this, event);\n\n        // if (useMSGuesture(this, event)) {\n        //     this._msGesture.addPointer(event.pointerId);\n        // }\n    },\n\n    pointermove: function (event) {\n        // FIXME\n        // pointermove is so sensitive that it always triggered when\n        // tap(click) on touch screen, which affect some judgement in\n        // upper application. So, we dont support mousemove on MS touch\n        // device yet.\n        if (!isPointerFromTouch(event)) {\n            domHandlers.mousemove.call(this, event);\n        }\n    },\n\n    pointerup: function (event) {\n        domHandlers.mouseup.call(this, event);\n    },\n\n    pointerout: function (event) {\n        // pointerout will be triggered when tap on touch screen\n        // (IE11+/Edge on MS Surface) after click event triggered,\n        // which is inconsistent with the mousout behavior we defined\n        // in touchend. So we unify them.\n        // (check domHandlers.touchend for detailed explanation)\n        if (!isPointerFromTouch(event)) {\n            domHandlers.mouseout.call(this, event);\n        }\n    }\n};\n\nfunction isPointerFromTouch(event) {\n    var pointerType = event.pointerType;\n    return pointerType === 'pen' || pointerType === 'touch';\n}\n\n// function useMSGuesture(handlerProxy, event) {\n//     return isPointerFromTouch(event) && !!handlerProxy._msGesture;\n// }\n\n// Common handlers\neach$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {\n    domHandlers[name] = function (event) {\n        event = normalizeEvent(this.dom, event);\n        this.trigger(name, event);\n    };\n});\n\n/**\n * 为控制类实例初始化dom 事件处理函数\n *\n * @inner\n * @param {module:zrender/Handler} instance 控制类实例\n */\nfunction initDomHandler(instance) {\n    each$1(touchHandlerNames, function (name) {\n        instance._handlers[name] = bind(domHandlers[name], instance);\n    });\n\n    each$1(pointerHandlerNames, function (name) {\n        instance._handlers[name] = bind(domHandlers[name], instance);\n    });\n\n    each$1(mouseHandlerNames, function (name) {\n        instance._handlers[name] = makeMouseHandler(domHandlers[name], instance);\n    });\n\n    function makeMouseHandler(fn, instance) {\n        return function () {\n            if (instance._touching) {\n                return;\n            }\n            return fn.apply(instance, arguments);\n        };\n    }\n}\n\n\nfunction HandlerDomProxy(dom) {\n    Eventful.call(this);\n\n    this.dom = dom;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._touching = false;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._touchTimer;\n\n    this._handlers = {};\n\n    initDomHandler(this);\n\n    if (env$1.pointerEventsSupported) { // Only IE11+/Edge\n        // 1. On devices that both enable touch and mouse (e.g., MS Surface and lenovo X240),\n        // IE11+/Edge do not trigger touch event, but trigger pointer event and mouse event\n        // at the same time.\n        // 2. On MS Surface, it probablely only trigger mousedown but no mouseup when tap on\n        // screen, which do not occurs in pointer event.\n        // So we use pointer event to both detect touch gesture and mouse behavior.\n        mountHandlers(pointerHandlerNames, this);\n\n        // FIXME\n        // Note: MS Gesture require CSS touch-action set. But touch-action is not reliable,\n        // which does not prevent defuault behavior occasionally (which may cause view port\n        // zoomed in but use can not zoom it back). And event.preventDefault() does not work.\n        // So we have to not to use MSGesture and not to support touchmove and pinch on MS\n        // touch screen. And we only support click behavior on MS touch screen now.\n\n        // MS Gesture Event is only supported on IE11+/Edge and on Windows 8+.\n        // We dont support touch on IE on win7.\n        // See <https://msdn.microsoft.com/en-us/library/dn433243(v=vs.85).aspx>\n        // if (typeof MSGesture === 'function') {\n        //     (this._msGesture = new MSGesture()).target = dom; // jshint ignore:line\n        //     dom.addEventListener('MSGestureChange', onMSGestureChange);\n        // }\n    }\n    else {\n        if (env$1.touchEventsSupported) {\n            mountHandlers(touchHandlerNames, this);\n            // Handler of 'mouseout' event is needed in touch mode, which will be mounted below.\n            // addEventListener(root, 'mouseout', this._mouseoutHandler);\n        }\n\n        // 1. Considering some devices that both enable touch and mouse event (like on MS Surface\n        // and lenovo X240, @see #2350), we make mouse event be always listened, otherwise\n        // mouse event can not be handle in those devices.\n        // 2. On MS Surface, Chrome will trigger both touch event and mouse event. How to prevent\n        // mouseevent after touch event triggered, see `setTouchTimer`.\n        mountHandlers(mouseHandlerNames, this);\n    }\n\n    function mountHandlers(handlerNames, instance) {\n        each$1(handlerNames, function (name) {\n            addEventListener(dom, eventNameFix(name), instance._handlers[name]);\n        }, instance);\n    }\n}\n\nvar handlerDomProxyProto = HandlerDomProxy.prototype;\nhandlerDomProxyProto.dispose = function () {\n    var handlerNames = mouseHandlerNames.concat(touchHandlerNames);\n\n    for (var i = 0; i < handlerNames.length; i++) {\n        var name = handlerNames[i];\n        removeEventListener(this.dom, eventNameFix(name), this._handlers[name]);\n    }\n};\n\nhandlerDomProxyProto.setCursor = function (cursorStyle) {\n    this.dom.style && (this.dom.style.cursor = cursorStyle || 'default');\n};\n\nmixin(HandlerDomProxy, Eventful);\n\n/*!\n* ZRender, a high performance 2d drawing library.\n*\n* Copyright (c) 2013, Baidu Inc.\n* All rights reserved.\n*\n* LICENSE\n* https://github.com/ecomfe/zrender/blob/master/LICENSE.txt\n*/\n\nvar useVML = !env$1.canvasSupported;\n\nvar painterCtors = {\n    canvas: Painter\n};\n\nvar instances$1 = {};    // ZRender实例map索引\n\n/**\n * @type {string}\n */\nvar version$1 = '4.0.7';\n\n/**\n * Initializing a zrender instance\n * @param {HTMLElement} dom\n * @param {Object} [opts]\n * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'\n * @param {number} [opts.devicePixelRatio]\n * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)\n * @return {module:zrender/ZRender}\n */\nfunction init$1(dom, opts) {\n    var zr = new ZRender(guid(), dom, opts);\n    instances$1[zr.id] = zr;\n    return zr;\n}\n\n/**\n * Dispose zrender instance\n * @param {module:zrender/ZRender} zr\n */\nfunction dispose$1(zr) {\n    if (zr) {\n        zr.dispose();\n    }\n    else {\n        for (var key in instances$1) {\n            if (instances$1.hasOwnProperty(key)) {\n                instances$1[key].dispose();\n            }\n        }\n        instances$1 = {};\n    }\n\n    return this;\n}\n\n/**\n * Get zrender instance by id\n * @param {string} id zrender instance id\n * @return {module:zrender/ZRender}\n */\nfunction getInstance(id) {\n    return instances$1[id];\n}\n\nfunction registerPainter(name, Ctor) {\n    painterCtors[name] = Ctor;\n}\n\nfunction delInstance(id) {\n    delete instances$1[id];\n}\n\n/**\n * @module zrender/ZRender\n */\n/**\n * @constructor\n * @alias module:zrender/ZRender\n * @param {string} id\n * @param {HTMLElement} dom\n * @param {Object} opts\n * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'\n * @param {number} [opts.devicePixelRatio]\n * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)\n */\nvar ZRender = function (id, dom, opts) {\n\n    opts = opts || {};\n\n    /**\n     * @type {HTMLDomElement}\n     */\n    this.dom = dom;\n\n    /**\n     * @type {string}\n     */\n    this.id = id;\n\n    var self = this;\n    var storage = new Storage();\n\n    var rendererType = opts.renderer;\n    // TODO WebGL\n    if (useVML) {\n        if (!painterCtors.vml) {\n            throw new Error('You need to require \\'zrender/vml/vml\\' to support IE8');\n        }\n        rendererType = 'vml';\n    }\n    else if (!rendererType || !painterCtors[rendererType]) {\n        rendererType = 'canvas';\n    }\n    var painter = new painterCtors[rendererType](dom, storage, opts, id);\n\n    this.storage = storage;\n    this.painter = painter;\n\n    var handerProxy = (!env$1.node && !env$1.worker) ? new HandlerDomProxy(painter.getViewportRoot()) : null;\n    this.handler = new Handler(storage, painter, handerProxy, painter.root);\n\n    /**\n     * @type {module:zrender/animation/Animation}\n     */\n    this.animation = new Animation({\n        stage: {\n            update: bind(this.flush, this)\n        }\n    });\n    this.animation.start();\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._needsRefresh;\n\n    // 修改 storage.delFromStorage, 每次删除元素之前删除动画\n    // FIXME 有点ugly\n    var oldDelFromStorage = storage.delFromStorage;\n    var oldAddToStorage = storage.addToStorage;\n\n    storage.delFromStorage = function (el) {\n        oldDelFromStorage.call(storage, el);\n\n        el && el.removeSelfFromZr(self);\n    };\n\n    storage.addToStorage = function (el) {\n        oldAddToStorage.call(storage, el);\n\n        el.addSelfToZr(self);\n    };\n};\n\nZRender.prototype = {\n\n    constructor: ZRender,\n    /**\n     * 获取实例唯一标识\n     * @return {string}\n     */\n    getId: function () {\n        return this.id;\n    },\n\n    /**\n     * 添加元素\n     * @param  {module:zrender/Element} el\n     */\n    add: function (el) {\n        this.storage.addRoot(el);\n        this._needsRefresh = true;\n    },\n\n    /**\n     * 删除元素\n     * @param  {module:zrender/Element} el\n     */\n    remove: function (el) {\n        this.storage.delRoot(el);\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Change configuration of layer\n     * @param {string} zLevel\n     * @param {Object} config\n     * @param {string} [config.clearColor=0] Clear color\n     * @param {string} [config.motionBlur=false] If enable motion blur\n     * @param {number} [config.lastFrameAlpha=0.7] Motion blur factor. Larger value cause longer trailer\n    */\n    configLayer: function (zLevel, config) {\n        if (this.painter.configLayer) {\n            this.painter.configLayer(zLevel, config);\n        }\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Set background color\n     * @param {string} backgroundColor\n     */\n    setBackgroundColor: function (backgroundColor) {\n        if (this.painter.setBackgroundColor) {\n            this.painter.setBackgroundColor(backgroundColor);\n        }\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Repaint the canvas immediately\n     */\n    refreshImmediately: function () {\n        // var start = new Date();\n        // Clear needsRefresh ahead to avoid something wrong happens in refresh\n        // Or it will cause zrender refreshes again and again.\n        this._needsRefresh = false;\n        this.painter.refresh();\n        /**\n         * Avoid trigger zr.refresh in Element#beforeUpdate hook\n         */\n        this._needsRefresh = false;\n        // var end = new Date();\n        // var log = document.getElementById('log');\n        // if (log) {\n        //     log.innerHTML = log.innerHTML + '<br>' + (end - start);\n        // }\n    },\n\n    /**\n     * Mark and repaint the canvas in the next frame of browser\n     */\n    refresh: function () {\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Perform all refresh\n     */\n    flush: function () {\n        var triggerRendered;\n\n        if (this._needsRefresh) {\n            triggerRendered = true;\n            this.refreshImmediately();\n        }\n        if (this._needsRefreshHover) {\n            triggerRendered = true;\n            this.refreshHoverImmediately();\n        }\n\n        triggerRendered && this.trigger('rendered');\n    },\n\n    /**\n     * Add element to hover layer\n     * @param  {module:zrender/Element} el\n     * @param {Object} style\n     */\n    addHover: function (el, style) {\n        if (this.painter.addHover) {\n            var elMirror = this.painter.addHover(el, style);\n            this.refreshHover();\n            return elMirror;\n        }\n    },\n\n    /**\n     * Add element from hover layer\n     * @param  {module:zrender/Element} el\n     */\n    removeHover: function (el) {\n        if (this.painter.removeHover) {\n            this.painter.removeHover(el);\n            this.refreshHover();\n        }\n    },\n\n    /**\n     * Clear all hover elements in hover layer\n     * @param  {module:zrender/Element} el\n     */\n    clearHover: function () {\n        if (this.painter.clearHover) {\n            this.painter.clearHover();\n            this.refreshHover();\n        }\n    },\n\n    /**\n     * Refresh hover in next frame\n     */\n    refreshHover: function () {\n        this._needsRefreshHover = true;\n    },\n\n    /**\n     * Refresh hover immediately\n     */\n    refreshHoverImmediately: function () {\n        this._needsRefreshHover = false;\n        this.painter.refreshHover && this.painter.refreshHover();\n    },\n\n    /**\n     * Resize the canvas.\n     * Should be invoked when container size is changed\n     * @param {Object} [opts]\n     * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)\n     * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)\n     */\n    resize: function (opts) {\n        opts = opts || {};\n        this.painter.resize(opts.width, opts.height);\n        this.handler.resize();\n    },\n\n    /**\n     * Stop and clear all animation immediately\n     */\n    clearAnimation: function () {\n        this.animation.clear();\n    },\n\n    /**\n     * Get container width\n     */\n    getWidth: function () {\n        return this.painter.getWidth();\n    },\n\n    /**\n     * Get container height\n     */\n    getHeight: function () {\n        return this.painter.getHeight();\n    },\n\n    /**\n     * Export the canvas as Base64 URL\n     * @param {string} type\n     * @param {string} [backgroundColor='#fff']\n     * @return {string} Base64 URL\n     */\n    // toDataURL: function(type, backgroundColor) {\n    //     return this.painter.getRenderedCanvas({\n    //         backgroundColor: backgroundColor\n    //     }).toDataURL(type);\n    // },\n\n    /**\n     * Converting a path to image.\n     * It has much better performance of drawing image rather than drawing a vector path.\n     * @param {module:zrender/graphic/Path} e\n     * @param {number} width\n     * @param {number} height\n     */\n    pathToImage: function (e, dpr) {\n        return this.painter.pathToImage(e, dpr);\n    },\n\n    /**\n     * Set default cursor\n     * @param {string} [cursorStyle='default'] 例如 crosshair\n     */\n    setCursorStyle: function (cursorStyle) {\n        this.handler.setCursorStyle(cursorStyle);\n    },\n\n    /**\n     * Find hovered element\n     * @param {number} x\n     * @param {number} y\n     * @return {Object} {target, topTarget}\n     */\n    findHover: function (x, y) {\n        return this.handler.findHover(x, y);\n    },\n\n    /**\n     * Bind event\n     *\n     * @param {string} eventName Event name\n     * @param {Function} eventHandler Handler function\n     * @param {Object} [context] Context object\n     */\n    on: function (eventName, eventHandler, context) {\n        this.handler.on(eventName, eventHandler, context);\n    },\n\n    /**\n     * Unbind event\n     * @param {string} eventName Event name\n     * @param {Function} [eventHandler] Handler function\n     */\n    off: function (eventName, eventHandler) {\n        this.handler.off(eventName, eventHandler);\n    },\n\n    /**\n     * Trigger event manually\n     *\n     * @param {string} eventName Event name\n     * @param {event=} event Event object\n     */\n    trigger: function (eventName, event) {\n        this.handler.trigger(eventName, event);\n    },\n\n\n    /**\n     * Clear all objects and the canvas.\n     */\n    clear: function () {\n        this.storage.delRoot();\n        this.painter.clear();\n    },\n\n    /**\n     * Dispose self.\n     */\n    dispose: function () {\n        this.animation.stop();\n\n        this.clear();\n        this.storage.dispose();\n        this.painter.dispose();\n        this.handler.dispose();\n\n        this.animation =\n        this.storage =\n        this.painter =\n        this.handler = null;\n\n        delInstance(this.id);\n    }\n};\n\n\n\nvar zrender = (Object.freeze || Object)({\n\tversion: version$1,\n\tinit: init$1,\n\tdispose: dispose$1,\n\tgetInstance: getInstance,\n\tregisterPainter: registerPainter\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$2 = each$1;\nvar isObject$2 = isObject$1;\nvar isArray$1 = isArray;\n\n/**\n * Make the name displayable. But we should\n * make sure it is not duplicated with user\n * specified name, so use '\\0';\n */\nvar DUMMY_COMPONENT_NAME_PREFIX = 'series\\0';\n\n/**\n * If value is not array, then translate it to array.\n * @param  {*} value\n * @return {Array} [value] or value\n */\nfunction normalizeToArray(value) {\n    return value instanceof Array\n        ? value\n        : value == null\n        ? []\n        : [value];\n}\n\n/**\n * Sync default option between normal and emphasis like `position` and `show`\n * In case some one will write code like\n *     label: {\n *          show: false,\n *          position: 'outside',\n *          fontSize: 18\n *     },\n *     emphasis: {\n *          label: { show: true }\n *     }\n * @param {Object} opt\n * @param {string} key\n * @param {Array.<string>} subOpts\n */\nfunction defaultEmphasis(opt, key, subOpts) {\n    // Caution: performance sensitive.\n    if (opt) {\n        opt[key] = opt[key] || {};\n        opt.emphasis = opt.emphasis || {};\n        opt.emphasis[key] = opt.emphasis[key] || {};\n\n        // Default emphasis option from normal\n        for (var i = 0, len = subOpts.length; i < len; i++) {\n            var subOptName = subOpts[i];\n            if (!opt.emphasis[key].hasOwnProperty(subOptName)\n                && opt[key].hasOwnProperty(subOptName)\n            ) {\n                opt.emphasis[key][subOptName] = opt[key][subOptName];\n            }\n        }\n    }\n}\n\nvar TEXT_STYLE_OPTIONS = [\n    'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',\n    'rich', 'tag', 'color', 'textBorderColor', 'textBorderWidth',\n    'width', 'height', 'lineHeight', 'align', 'verticalAlign', 'baseline',\n    'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY',\n    'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY',\n    'backgroundColor', 'borderColor', 'borderWidth', 'borderRadius', 'padding'\n];\n\n// modelUtil.LABEL_OPTIONS = modelUtil.TEXT_STYLE_OPTIONS.concat([\n//     'position', 'offset', 'rotate', 'origin', 'show', 'distance', 'formatter',\n//     'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',\n//     // FIXME: deprecated, check and remove it.\n//     'textStyle'\n// ]);\n\n/**\n * The method do not ensure performance.\n * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]\n * This helper method retieves value from data.\n * @param {string|number|Date|Array|Object} dataItem\n * @return {number|string|Date|Array.<number|string|Date>}\n */\nfunction getDataItemValue(dataItem) {\n    return (isObject$2(dataItem) && !isArray$1(dataItem) && !(dataItem instanceof Date))\n        ? dataItem.value : dataItem;\n}\n\n/**\n * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]\n * This helper method determine if dataItem has extra option besides value\n * @param {string|number|Date|Array|Object} dataItem\n */\nfunction isDataItemOption(dataItem) {\n    return isObject$2(dataItem)\n        && !(dataItem instanceof Array);\n        // // markLine data can be array\n        // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array));\n}\n\n/**\n * Mapping to exists for merge.\n *\n * @public\n * @param {Array.<Object>|Array.<module:echarts/model/Component>} exists\n * @param {Object|Array.<Object>} newCptOptions\n * @return {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],\n *                          index of which is the same as exists.\n */\nfunction mappingToExists(exists, newCptOptions) {\n    // Mapping by the order by original option (but not order of\n    // new option) in merge mode. Because we should ensure\n    // some specified index (like xAxisIndex) is consistent with\n    // original option, which is easy to understand, espatially in\n    // media query. And in most case, merge option is used to\n    // update partial option but not be expected to change order.\n    newCptOptions = (newCptOptions || []).slice();\n\n    var result = map(exists || [], function (obj, index) {\n        return {exist: obj};\n    });\n\n    // Mapping by id or name if specified.\n    each$2(newCptOptions, function (cptOption, index) {\n        if (!isObject$2(cptOption)) {\n            return;\n        }\n\n        // id has highest priority.\n        for (var i = 0; i < result.length; i++) {\n            if (!result[i].option // Consider name: two map to one.\n                && cptOption.id != null\n                && result[i].exist.id === cptOption.id + ''\n            ) {\n                result[i].option = cptOption;\n                newCptOptions[index] = null;\n                return;\n            }\n        }\n\n        for (var i = 0; i < result.length; i++) {\n            var exist = result[i].exist;\n            if (!result[i].option // Consider name: two map to one.\n                // Can not match when both ids exist but different.\n                && (exist.id == null || cptOption.id == null)\n                && cptOption.name != null\n                && !isIdInner(cptOption)\n                && !isIdInner(exist)\n                && exist.name === cptOption.name + ''\n            ) {\n                result[i].option = cptOption;\n                newCptOptions[index] = null;\n                return;\n            }\n        }\n    });\n\n    // Otherwise mapping by index.\n    each$2(newCptOptions, function (cptOption, index) {\n        if (!isObject$2(cptOption)) {\n            return;\n        }\n\n        var i = 0;\n        for (; i < result.length; i++) {\n            var exist = result[i].exist;\n            if (!result[i].option\n                // Existing model that already has id should be able to\n                // mapped to (because after mapping performed model may\n                // be assigned with a id, whish should not affect next\n                // mapping), except those has inner id.\n                && !isIdInner(exist)\n                // Caution:\n                // Do not overwrite id. But name can be overwritten,\n                // because axis use name as 'show label text'.\n                // 'exist' always has id and name and we dont\n                // need to check it.\n                && cptOption.id == null\n            ) {\n                result[i].option = cptOption;\n                break;\n            }\n        }\n\n        if (i >= result.length) {\n            result.push({option: cptOption});\n        }\n    });\n\n    return result;\n}\n\n/**\n * Make id and name for mapping result (result of mappingToExists)\n * into `keyInfo` field.\n *\n * @public\n * @param {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],\n *                          which order is the same as exists.\n * @return {Array.<Object>} The input.\n */\nfunction makeIdAndName(mapResult) {\n    // We use this id to hash component models and view instances\n    // in echarts. id can be specified by user, or auto generated.\n\n    // The id generation rule ensures new view instance are able\n    // to mapped to old instance when setOption are called in\n    // no-merge mode. So we generate model id by name and plus\n    // type in view id.\n\n    // name can be duplicated among components, which is convenient\n    // to specify multi components (like series) by one name.\n\n    // Ensure that each id is distinct.\n    var idMap = createHashMap();\n\n    each$2(mapResult, function (item, index) {\n        var existCpt = item.exist;\n        existCpt && idMap.set(existCpt.id, item);\n    });\n\n    each$2(mapResult, function (item, index) {\n        var opt = item.option;\n\n        assert$1(\n            !opt || opt.id == null || !idMap.get(opt.id) || idMap.get(opt.id) === item,\n            'id duplicates: ' + (opt && opt.id)\n        );\n\n        opt && opt.id != null && idMap.set(opt.id, item);\n        !item.keyInfo && (item.keyInfo = {});\n    });\n\n    // Make name and id.\n    each$2(mapResult, function (item, index) {\n        var existCpt = item.exist;\n        var opt = item.option;\n        var keyInfo = item.keyInfo;\n\n        if (!isObject$2(opt)) {\n            return;\n        }\n\n        // name can be overwitten. Consider case: axis.name = '20km'.\n        // But id generated by name will not be changed, which affect\n        // only in that case: setOption with 'not merge mode' and view\n        // instance will be recreated, which can be accepted.\n        keyInfo.name = opt.name != null\n            ? opt.name + ''\n            : existCpt\n            ? existCpt.name\n            // Avoid diffferent series has the same name,\n            // because name may be used like in color pallet.\n            : DUMMY_COMPONENT_NAME_PREFIX + index;\n\n        if (existCpt) {\n            keyInfo.id = existCpt.id;\n        }\n        else if (opt.id != null) {\n            keyInfo.id = opt.id + '';\n        }\n        else {\n            // Consider this situatoin:\n            //  optionA: [{name: 'a'}, {name: 'a'}, {..}]\n            //  optionB [{..}, {name: 'a'}, {name: 'a'}]\n            // Series with the same name between optionA and optionB\n            // should be mapped.\n            var idNum = 0;\n            do {\n                keyInfo.id = '\\0' + keyInfo.name + '\\0' + idNum++;\n            }\n            while (idMap.get(keyInfo.id));\n        }\n\n        idMap.set(keyInfo.id, item);\n    });\n}\n\nfunction isNameSpecified(componentModel) {\n    var name = componentModel.name;\n    // Is specified when `indexOf` get -1 or > 0.\n    return !!(name && name.indexOf(DUMMY_COMPONENT_NAME_PREFIX));\n}\n\n/**\n * @public\n * @param {Object} cptOption\n * @return {boolean}\n */\nfunction isIdInner(cptOption) {\n    return isObject$2(cptOption)\n        && cptOption.id\n        && (cptOption.id + '').indexOf('\\0_ec_\\0') === 0;\n}\n\n/**\n * A helper for removing duplicate items between batchA and batchB,\n * and in themselves, and categorize by series.\n *\n * @param {Array.<Object>} batchA Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]\n * @param {Array.<Object>} batchB Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]\n * @return {Array.<Array.<Object>, Array.<Object>>} result: [resultBatchA, resultBatchB]\n */\nfunction compressBatches(batchA, batchB) {\n    var mapA = {};\n    var mapB = {};\n\n    makeMap(batchA || [], mapA);\n    makeMap(batchB || [], mapB, mapA);\n\n    return [mapToArray(mapA), mapToArray(mapB)];\n\n    function makeMap(sourceBatch, map$$1, otherMap) {\n        for (var i = 0, len = sourceBatch.length; i < len; i++) {\n            var seriesId = sourceBatch[i].seriesId;\n            var dataIndices = normalizeToArray(sourceBatch[i].dataIndex);\n            var otherDataIndices = otherMap && otherMap[seriesId];\n\n            for (var j = 0, lenj = dataIndices.length; j < lenj; j++) {\n                var dataIndex = dataIndices[j];\n\n                if (otherDataIndices && otherDataIndices[dataIndex]) {\n                    otherDataIndices[dataIndex] = null;\n                }\n                else {\n                    (map$$1[seriesId] || (map$$1[seriesId] = {}))[dataIndex] = 1;\n                }\n            }\n        }\n    }\n\n    function mapToArray(map$$1, isData) {\n        var result = [];\n        for (var i in map$$1) {\n            if (map$$1.hasOwnProperty(i) && map$$1[i] != null) {\n                if (isData) {\n                    result.push(+i);\n                }\n                else {\n                    var dataIndices = mapToArray(map$$1[i], true);\n                    dataIndices.length && result.push({seriesId: i, dataIndex: dataIndices});\n                }\n            }\n        }\n        return result;\n    }\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {Object} payload Contains dataIndex (means rawIndex) / dataIndexInside / name\n *                         each of which can be Array or primary type.\n * @return {number|Array.<number>} dataIndex If not found, return undefined/null.\n */\nfunction queryDataIndex(data, payload) {\n    if (payload.dataIndexInside != null) {\n        return payload.dataIndexInside;\n    }\n    else if (payload.dataIndex != null) {\n        return isArray(payload.dataIndex)\n            ? map(payload.dataIndex, function (value) {\n                return data.indexOfRawIndex(value);\n            })\n            : data.indexOfRawIndex(payload.dataIndex);\n    }\n    else if (payload.name != null) {\n        return isArray(payload.name)\n            ? map(payload.name, function (value) {\n                return data.indexOfName(value);\n            })\n            : data.indexOfName(payload.name);\n    }\n}\n\n/**\n * Enable property storage to any host object.\n * Notice: Serialization is not supported.\n *\n * For example:\n * var inner = zrUitl.makeInner();\n *\n * function some1(hostObj) {\n *      inner(hostObj).someProperty = 1212;\n *      ...\n * }\n * function some2() {\n *      var fields = inner(this);\n *      fields.someProperty1 = 1212;\n *      fields.someProperty2 = 'xx';\n *      ...\n * }\n *\n * @return {Function}\n */\nfunction makeInner() {\n    // Consider different scope by es module import.\n    var key = '__\\0ec_inner_' + innerUniqueIndex++ + '_' + Math.random().toFixed(5);\n    return function (hostObj) {\n        return hostObj[key] || (hostObj[key] = {});\n    };\n}\nvar innerUniqueIndex = 0;\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex, seriesId, seriesName,\n *            geoIndex, geoId, geoName,\n *            bmapIndex, bmapId, bmapName,\n *            xAxisIndex, xAxisId, xAxisName,\n *            yAxisIndex, yAxisId, yAxisName,\n *            gridIndex, gridId, gridName,\n *            ... (can be extended)\n *        }\n *        Each properties can be number|string|Array.<number>|Array.<string>\n *        For example, a finder could be\n *        {\n *            seriesIndex: 3,\n *            geoId: ['aa', 'cc'],\n *            gridName: ['xx', 'rr']\n *        }\n *        xxxIndex can be set as 'all' (means all xxx) or 'none' (means not specify)\n *        If nothing or null/undefined specified, return nothing.\n * @param {Object} [opt]\n * @param {string} [opt.defaultMainType]\n * @param {Array.<string>} [opt.includeMainTypes]\n * @return {Object} result like:\n *        {\n *            seriesModels: [seriesModel1, seriesModel2],\n *            seriesModel: seriesModel1, // The first model\n *            geoModels: [geoModel1, geoModel2],\n *            geoModel: geoModel1, // The first model\n *            ...\n *        }\n */\nfunction parseFinder(ecModel, finder, opt) {\n    if (isString(finder)) {\n        var obj = {};\n        obj[finder + 'Index'] = 0;\n        finder = obj;\n    }\n\n    var defaultMainType = opt && opt.defaultMainType;\n    if (defaultMainType\n        && !has(finder, defaultMainType + 'Index')\n        && !has(finder, defaultMainType + 'Id')\n        && !has(finder, defaultMainType + 'Name')\n    ) {\n        finder[defaultMainType + 'Index'] = 0;\n    }\n\n    var result = {};\n\n    each$2(finder, function (value, key) {\n        var value = finder[key];\n\n        // Exclude 'dataIndex' and other illgal keys.\n        if (key === 'dataIndex' || key === 'dataIndexInside') {\n            result[key] = value;\n            return;\n        }\n\n        var parsedKey = key.match(/^(\\w+)(Index|Id|Name)$/) || [];\n        var mainType = parsedKey[1];\n        var queryType = (parsedKey[2] || '').toLowerCase();\n\n        if (!mainType\n            || !queryType\n            || value == null\n            || (queryType === 'index' && value === 'none')\n            || (opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0)\n        ) {\n            return;\n        }\n\n        var queryParam = {mainType: mainType};\n        if (queryType !== 'index' || value !== 'all') {\n            queryParam[queryType] = value;\n        }\n\n        var models = ecModel.queryComponents(queryParam);\n        result[mainType + 'Models'] = models;\n        result[mainType + 'Model'] = models[0];\n    });\n\n    return result;\n}\n\nfunction has(obj, prop) {\n    return obj && obj.hasOwnProperty(prop);\n}\n\nfunction setAttribute(dom, key, value) {\n    dom.setAttribute\n        ? dom.setAttribute(key, value)\n        : (dom[key] = value);\n}\n\nfunction getAttribute(dom, key) {\n    return dom.getAttribute\n        ? dom.getAttribute(key)\n        : dom[key];\n}\n\nfunction getTooltipRenderMode(renderModeOption) {\n    if (renderModeOption === 'auto') {\n        // Using html when `document` exists, use richText otherwise\n        return env$1.domSupported ? 'html' : 'richText';\n    }\n    else {\n        return renderModeOption || 'html';\n    }\n}\n\n/**\n * Group a list by key.\n *\n * @param {Array} array\n * @param {Function} getKey\n *        param {*} Array item\n *        return {string} key\n * @return {Object} Result\n *        {Array}: keys,\n *        {module:zrender/core/util/HashMap} buckets: {key -> Array}\n */\nfunction groupData(array, getKey) {\n    var buckets = createHashMap();\n    var keys = [];\n\n    each$1(array, function (item) {\n        var key = getKey(item);\n        (buckets.get(key)\n            || (keys.push(key), buckets.set(key, []))\n        ).push(item);\n    });\n\n    return {keys: keys, buckets: buckets};\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TYPE_DELIMITER = '.';\nvar IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';\n\n/**\n * Notice, parseClassType('') should returns {main: '', sub: ''}\n * @public\n */\nfunction parseClassType$1(componentType) {\n    var ret = {main: '', sub: ''};\n    if (componentType) {\n        componentType = componentType.split(TYPE_DELIMITER);\n        ret.main = componentType[0] || '';\n        ret.sub = componentType[1] || '';\n    }\n    return ret;\n}\n\n/**\n * @public\n */\nfunction checkClassType(componentType) {\n    assert$1(\n        /^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType),\n        'componentType \"' + componentType + '\" illegal'\n    );\n}\n\n/**\n * @public\n */\nfunction enableClassExtend(RootClass, mandatoryMethods) {\n\n    RootClass.$constructor = RootClass;\n    RootClass.extend = function (proto) {\n\n        if (__DEV__) {\n            each$1(mandatoryMethods, function (method) {\n                if (!proto[method]) {\n                    console.warn(\n                        'Method `' + method + '` should be implemented'\n                        + (proto.type ? ' in ' + proto.type : '') + '.'\n                    );\n                }\n            });\n        }\n\n        var superClass = this;\n        var ExtendedClass = function () {\n            if (!proto.$constructor) {\n                superClass.apply(this, arguments);\n            }\n            else {\n                proto.$constructor.apply(this, arguments);\n            }\n        };\n\n        extend(ExtendedClass.prototype, proto);\n\n        ExtendedClass.extend = this.extend;\n        ExtendedClass.superCall = superCall;\n        ExtendedClass.superApply = superApply;\n        inherits(ExtendedClass, this);\n        ExtendedClass.superClass = superClass;\n\n        return ExtendedClass;\n    };\n}\n\nvar classBase = 0;\n\n/**\n * Can not use instanceof, consider different scope by\n * cross domain or es module import in ec extensions.\n * Mount a method \"isInstance()\" to Clz.\n */\nfunction enableClassCheck(Clz) {\n    var classAttr = ['__\\0is_clz', classBase++, Math.random().toFixed(3)].join('_');\n    Clz.prototype[classAttr] = true;\n\n    if (__DEV__) {\n        assert$1(!Clz.isInstance, 'The method \"is\" can not be defined.');\n    }\n\n    Clz.isInstance = function (obj) {\n        return !!(obj && obj[classAttr]);\n    };\n}\n\n// superCall should have class info, which can not be fetch from 'this'.\n// Consider this case:\n// class A has method f,\n// class B inherits class A, overrides method f, f call superApply('f'),\n// class C inherits class B, do not overrides method f,\n// then when method of class C is called, dead loop occured.\nfunction superCall(context, methodName) {\n    var args = slice(arguments, 2);\n    return this.superClass.prototype[methodName].apply(context, args);\n}\n\nfunction superApply(context, methodName, args) {\n    return this.superClass.prototype[methodName].apply(context, args);\n}\n\n/**\n * @param {Object} entity\n * @param {Object} options\n * @param {boolean} [options.registerWhenExtend]\n * @public\n */\nfunction enableClassManagement(entity, options) {\n    options = options || {};\n\n    /**\n     * Component model classes\n     * key: componentType,\n     * value:\n     *     componentClass, when componentType is 'xxx'\n     *     or Object.<subKey, componentClass>, when componentType is 'xxx.yy'\n     * @type {Object}\n     */\n    var storage = {};\n\n    entity.registerClass = function (Clazz, componentType) {\n        if (componentType) {\n            checkClassType(componentType);\n            componentType = parseClassType$1(componentType);\n\n            if (!componentType.sub) {\n                if (__DEV__) {\n                    if (storage[componentType.main]) {\n                        console.warn(componentType.main + ' exists.');\n                    }\n                }\n                storage[componentType.main] = Clazz;\n            }\n            else if (componentType.sub !== IS_CONTAINER) {\n                var container = makeContainer(componentType);\n                container[componentType.sub] = Clazz;\n            }\n        }\n        return Clazz;\n    };\n\n    entity.getClass = function (componentMainType, subType, throwWhenNotFound) {\n        var Clazz = storage[componentMainType];\n\n        if (Clazz && Clazz[IS_CONTAINER]) {\n            Clazz = subType ? Clazz[subType] : null;\n        }\n\n        if (throwWhenNotFound && !Clazz) {\n            throw new Error(\n                !subType\n                    ? componentMainType + '.' + 'type should be specified.'\n                    : 'Component ' + componentMainType + '.' + (subType || '') + ' not exists. Load it first.'\n            );\n        }\n\n        return Clazz;\n    };\n\n    entity.getClassesByMainType = function (componentType) {\n        componentType = parseClassType$1(componentType);\n\n        var result = [];\n        var obj = storage[componentType.main];\n\n        if (obj && obj[IS_CONTAINER]) {\n            each$1(obj, function (o, type) {\n                type !== IS_CONTAINER && result.push(o);\n            });\n        }\n        else {\n            result.push(obj);\n        }\n\n        return result;\n    };\n\n    entity.hasClass = function (componentType) {\n        // Just consider componentType.main.\n        componentType = parseClassType$1(componentType);\n        return !!storage[componentType.main];\n    };\n\n    /**\n     * @return {Array.<string>} Like ['aa', 'bb'], but can not be ['aa.xx']\n     */\n    entity.getAllClassMainTypes = function () {\n        var types = [];\n        each$1(storage, function (obj, type) {\n            types.push(type);\n        });\n        return types;\n    };\n\n    /**\n     * If a main type is container and has sub types\n     * @param  {string}  mainType\n     * @return {boolean}\n     */\n    entity.hasSubTypes = function (componentType) {\n        componentType = parseClassType$1(componentType);\n        var obj = storage[componentType.main];\n        return obj && obj[IS_CONTAINER];\n    };\n\n    entity.parseClassType = parseClassType$1;\n\n    function makeContainer(componentType) {\n        var container = storage[componentType.main];\n        if (!container || !container[IS_CONTAINER]) {\n            container = storage[componentType.main] = {};\n            container[IS_CONTAINER] = true;\n        }\n        return container;\n    }\n\n    if (options.registerWhenExtend) {\n        var originalExtend = entity.extend;\n        if (originalExtend) {\n            entity.extend = function (proto) {\n                var ExtendedClass = originalExtend.call(this, proto);\n                return entity.registerClass(ExtendedClass, proto.type);\n            };\n        }\n    }\n\n    return entity;\n}\n\n/**\n * @param {string|Array.<string>} properties\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Parse shadow style\n// TODO Only shallow path support\nvar makeStyleMapper = function (properties) {\n    // Normalize\n    for (var i = 0; i < properties.length; i++) {\n        if (!properties[i][1]) {\n            properties[i][1] = properties[i][0];\n        }\n    }\n    return function (model, excludes, includes) {\n        var style = {};\n        for (var i = 0; i < properties.length; i++) {\n            var propName = properties[i][1];\n            if ((excludes && indexOf(excludes, propName) >= 0)\n                || (includes && indexOf(includes, propName) < 0)\n            ) {\n                continue;\n            }\n            var val = model.getShallow(propName);\n            if (val != null) {\n                style[properties[i][0]] = val;\n            }\n        }\n        return style;\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getLineStyle = makeStyleMapper(\n    [\n        ['lineWidth', 'width'],\n        ['stroke', 'color'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor']\n    ]\n);\n\nvar lineStyleMixin = {\n    getLineStyle: function (excludes) {\n        var style = getLineStyle(this, excludes);\n        var lineDash = this.getLineDash(style.lineWidth);\n        lineDash && (style.lineDash = lineDash);\n        return style;\n    },\n\n    getLineDash: function (lineWidth) {\n        if (lineWidth == null) {\n            lineWidth = 1;\n        }\n        var lineType = this.get('type');\n        var dotSize = Math.max(lineWidth, 2);\n        var dashSize = lineWidth * 4;\n        return (lineType === 'solid' || lineType == null) ? null\n            : (lineType === 'dashed' ? [dashSize, dashSize] : [dotSize, dotSize]);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getAreaStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['opacity'],\n        ['shadowColor']\n    ]\n);\n\nvar areaStyleMixin = {\n    getAreaStyle: function (excludes, includes) {\n        return getAreaStyle(this, excludes, includes);\n    }\n};\n\n/**\n * 曲线辅助模块\n * @module zrender/core/curve\n * @author pissang(https://www.github.com/pissang)\n */\n\nvar mathPow = Math.pow;\nvar mathSqrt$2 = Math.sqrt;\n\nvar EPSILON$1 = 1e-8;\nvar EPSILON_NUMERIC = 1e-4;\n\nvar THREE_SQRT = mathSqrt$2(3);\nvar ONE_THIRD = 1 / 3;\n\n// 临时变量\nvar _v0 = create();\nvar _v1 = create();\nvar _v2 = create();\n\nfunction isAroundZero(val) {\n    return val > -EPSILON$1 && val < EPSILON$1;\n}\nfunction isNotAroundZero$1(val) {\n    return val > EPSILON$1 || val < -EPSILON$1;\n}\n/**\n * 计算三次贝塞尔值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @return {number}\n */\nfunction cubicAt(p0, p1, p2, p3, t) {\n    var onet = 1 - t;\n    return onet * onet * (onet * p0 + 3 * t * p1)\n            + t * t * (t * p3 + 3 * onet * p2);\n}\n\n/**\n * 计算三次贝塞尔导数值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @return {number}\n */\nfunction cubicDerivativeAt(p0, p1, p2, p3, t) {\n    var onet = 1 - t;\n    return 3 * (\n        ((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet\n        + (p3 - p2) * t * t\n    );\n}\n\n/**\n * 计算三次贝塞尔方程根，使用盛金公式\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} val\n * @param  {Array.<number>} roots\n * @return {number} 有效根数目\n */\nfunction cubicRootAt(p0, p1, p2, p3, val, roots) {\n    // Evaluate roots of cubic functions\n    var a = p3 + 3 * (p1 - p2) - p0;\n    var b = 3 * (p2 - p1 * 2 + p0);\n    var c = 3 * (p1 - p0);\n    var d = p0 - val;\n\n    var A = b * b - 3 * a * c;\n    var B = b * c - 9 * a * d;\n    var C = c * c - 3 * b * d;\n\n    var n = 0;\n\n    if (isAroundZero(A) && isAroundZero(B)) {\n        if (isAroundZero(b)) {\n            roots[0] = 0;\n        }\n        else {\n            var t1 = -c / b;  //t1, t2, t3, b is not zero\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = B * B - 4 * A * C;\n\n        if (isAroundZero(disc)) {\n            var K = B / A;\n            var t1 = -b / a + K;  // t1, a is not zero\n            var t2 = -K / 2;  // t2, t3\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var Y1 = A * b + 1.5 * a * (-B + discSqrt);\n            var Y2 = A * b + 1.5 * a * (-B - discSqrt);\n            if (Y1 < 0) {\n                Y1 = -mathPow(-Y1, ONE_THIRD);\n            }\n            else {\n                Y1 = mathPow(Y1, ONE_THIRD);\n            }\n            if (Y2 < 0) {\n                Y2 = -mathPow(-Y2, ONE_THIRD);\n            }\n            else {\n                Y2 = mathPow(Y2, ONE_THIRD);\n            }\n            var t1 = (-b - (Y1 + Y2)) / (3 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n        else {\n            var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt$2(A * A * A));\n            var theta = Math.acos(T) / 3;\n            var ASqrt = mathSqrt$2(A);\n            var tmp = Math.cos(theta);\n\n            var t1 = (-b - 2 * ASqrt * tmp) / (3 * a);\n            var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a);\n            var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n            if (t3 >= 0 && t3 <= 1) {\n                roots[n++] = t3;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 计算三次贝塞尔方程极限值的位置\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {Array.<number>} extrema\n * @return {number} 有效数目\n */\nfunction cubicExtrema(p0, p1, p2, p3, extrema) {\n    var b = 6 * p2 - 12 * p1 + 6 * p0;\n    var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2;\n    var c = 3 * p1 - 3 * p0;\n\n    var n = 0;\n    if (isAroundZero(a)) {\n        if (isNotAroundZero$1(b)) {\n            var t1 = -c / b;\n            if (t1 >= 0 && t1 <= 1) {\n                extrema[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = b * b - 4 * a * c;\n        if (isAroundZero(disc)) {\n            extrema[0] = -b / (2 * a);\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var t1 = (-b + discSqrt) / (2 * a);\n            var t2 = (-b - discSqrt) / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                extrema[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                extrema[n++] = t2;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 细分三次贝塞尔曲线\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @param  {Array.<number>} out\n */\nfunction cubicSubdivide(p0, p1, p2, p3, t, out) {\n    var p01 = (p1 - p0) * t + p0;\n    var p12 = (p2 - p1) * t + p1;\n    var p23 = (p3 - p2) * t + p2;\n\n    var p012 = (p12 - p01) * t + p01;\n    var p123 = (p23 - p12) * t + p12;\n\n    var p0123 = (p123 - p012) * t + p012;\n    // Seg0\n    out[0] = p0;\n    out[1] = p01;\n    out[2] = p012;\n    out[3] = p0123;\n    // Seg1\n    out[4] = p0123;\n    out[5] = p123;\n    out[6] = p23;\n    out[7] = p3;\n}\n\n/**\n * 投射点到三次贝塞尔曲线上，返回投射距离。\n * 投射点有可能会有一个或者多个，这里只返回其中距离最短的一个。\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x3\n * @param {number} y3\n * @param {number} x\n * @param {number} y\n * @param {Array.<number>} [out] 投射点\n * @return {number}\n */\nfunction cubicProjectPoint(\n    x0, y0, x1, y1, x2, y2, x3, y3,\n    x, y, out\n) {\n    // http://pomax.github.io/bezierinfo/#projections\n    var t;\n    var interval = 0.005;\n    var d = Infinity;\n    var prev;\n    var next;\n    var d1;\n    var d2;\n\n    _v0[0] = x;\n    _v0[1] = y;\n\n    // 先粗略估计一下可能的最小距离的 t 值\n    // PENDING\n    for (var _t = 0; _t < 1; _t += 0.05) {\n        _v1[0] = cubicAt(x0, x1, x2, x3, _t);\n        _v1[1] = cubicAt(y0, y1, y2, y3, _t);\n        d1 = distSquare(_v0, _v1);\n        if (d1 < d) {\n            t = _t;\n            d = d1;\n        }\n    }\n    d = Infinity;\n\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        if (interval < EPSILON_NUMERIC) {\n            break;\n        }\n        prev = t - interval;\n        next = t + interval;\n        // t - interval\n        _v1[0] = cubicAt(x0, x1, x2, x3, prev);\n        _v1[1] = cubicAt(y0, y1, y2, y3, prev);\n\n        d1 = distSquare(_v1, _v0);\n\n        if (prev >= 0 && d1 < d) {\n            t = prev;\n            d = d1;\n        }\n        else {\n            // t + interval\n            _v2[0] = cubicAt(x0, x1, x2, x3, next);\n            _v2[1] = cubicAt(y0, y1, y2, y3, next);\n            d2 = distSquare(_v2, _v0);\n\n            if (next <= 1 && d2 < d) {\n                t = next;\n                d = d2;\n            }\n            else {\n                interval *= 0.5;\n            }\n        }\n    }\n    // t\n    if (out) {\n        out[0] = cubicAt(x0, x1, x2, x3, t);\n        out[1] = cubicAt(y0, y1, y2, y3, t);\n    }\n    // console.log(interval, i);\n    return mathSqrt$2(d);\n}\n\n/**\n * 计算二次方贝塞尔值\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @return {number}\n */\nfunction quadraticAt(p0, p1, p2, t) {\n    var onet = 1 - t;\n    return onet * (onet * p0 + 2 * t * p1) + t * t * p2;\n}\n\n/**\n * 计算二次方贝塞尔导数值\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @return {number}\n */\nfunction quadraticDerivativeAt(p0, p1, p2, t) {\n    return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1));\n}\n\n/**\n * 计算二次方贝塞尔方程根\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @param  {Array.<number>} roots\n * @return {number} 有效根数目\n */\nfunction quadraticRootAt(p0, p1, p2, val, roots) {\n    var a = p0 - 2 * p1 + p2;\n    var b = 2 * (p1 - p0);\n    var c = p0 - val;\n\n    var n = 0;\n    if (isAroundZero(a)) {\n        if (isNotAroundZero$1(b)) {\n            var t1 = -c / b;\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = b * b - 4 * a * c;\n        if (isAroundZero(disc)) {\n            var t1 = -b / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var t1 = (-b + discSqrt) / (2 * a);\n            var t2 = (-b - discSqrt) / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 计算二次贝塞尔方程极限值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @return {number}\n */\nfunction quadraticExtremum(p0, p1, p2) {\n    var divider = p0 + p2 - 2 * p1;\n    if (divider === 0) {\n        // p1 is center of p0 and p2\n        return 0.5;\n    }\n    else {\n        return (p0 - p1) / divider;\n    }\n}\n\n/**\n * 细分二次贝塞尔曲线\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @param  {Array.<number>} out\n */\nfunction quadraticSubdivide(p0, p1, p2, t, out) {\n    var p01 = (p1 - p0) * t + p0;\n    var p12 = (p2 - p1) * t + p1;\n    var p012 = (p12 - p01) * t + p01;\n\n    // Seg0\n    out[0] = p0;\n    out[1] = p01;\n    out[2] = p012;\n\n    // Seg1\n    out[3] = p012;\n    out[4] = p12;\n    out[5] = p2;\n}\n\n/**\n * 投射点到二次贝塞尔曲线上，返回投射距离。\n * 投射点有可能会有一个或者多个，这里只返回其中距离最短的一个。\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x\n * @param {number} y\n * @param {Array.<number>} out 投射点\n * @return {number}\n */\nfunction quadraticProjectPoint(\n    x0, y0, x1, y1, x2, y2,\n    x, y, out\n) {\n    // http://pomax.github.io/bezierinfo/#projections\n    var t;\n    var interval = 0.005;\n    var d = Infinity;\n\n    _v0[0] = x;\n    _v0[1] = y;\n\n    // 先粗略估计一下可能的最小距离的 t 值\n    // PENDING\n    for (var _t = 0; _t < 1; _t += 0.05) {\n        _v1[0] = quadraticAt(x0, x1, x2, _t);\n        _v1[1] = quadraticAt(y0, y1, y2, _t);\n        var d1 = distSquare(_v0, _v1);\n        if (d1 < d) {\n            t = _t;\n            d = d1;\n        }\n    }\n    d = Infinity;\n\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        if (interval < EPSILON_NUMERIC) {\n            break;\n        }\n        var prev = t - interval;\n        var next = t + interval;\n        // t - interval\n        _v1[0] = quadraticAt(x0, x1, x2, prev);\n        _v1[1] = quadraticAt(y0, y1, y2, prev);\n\n        var d1 = distSquare(_v1, _v0);\n\n        if (prev >= 0 && d1 < d) {\n            t = prev;\n            d = d1;\n        }\n        else {\n            // t + interval\n            _v2[0] = quadraticAt(x0, x1, x2, next);\n            _v2[1] = quadraticAt(y0, y1, y2, next);\n            var d2 = distSquare(_v2, _v0);\n            if (next <= 1 && d2 < d) {\n                t = next;\n                d = d2;\n            }\n            else {\n                interval *= 0.5;\n            }\n        }\n    }\n    // t\n    if (out) {\n        out[0] = quadraticAt(x0, x1, x2, t);\n        out[1] = quadraticAt(y0, y1, y2, t);\n    }\n    // console.log(interval, i);\n    return mathSqrt$2(d);\n}\n\n/**\n * @author Yi Shen(https://github.com/pissang)\n */\n\nvar mathMin$3 = Math.min;\nvar mathMax$3 = Math.max;\nvar mathSin$2 = Math.sin;\nvar mathCos$2 = Math.cos;\nvar PI2 = Math.PI * 2;\n\nvar start = create();\nvar end = create();\nvar extremity = create();\n\n/**\n * 从顶点数组中计算出最小包围盒，写入`min`和`max`中\n * @module zrender/core/bbox\n * @param {Array<Object>} points 顶点数组\n * @param {number} min\n * @param {number} max\n */\nfunction fromPoints(points, min$$1, max$$1) {\n    if (points.length === 0) {\n        return;\n    }\n    var p = points[0];\n    var left = p[0];\n    var right = p[0];\n    var top = p[1];\n    var bottom = p[1];\n    var i;\n\n    for (i = 1; i < points.length; i++) {\n        p = points[i];\n        left = mathMin$3(left, p[0]);\n        right = mathMax$3(right, p[0]);\n        top = mathMin$3(top, p[1]);\n        bottom = mathMax$3(bottom, p[1]);\n    }\n\n    min$$1[0] = left;\n    min$$1[1] = top;\n    max$$1[0] = right;\n    max$$1[1] = bottom;\n}\n\n/**\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromLine(x0, y0, x1, y1, min$$1, max$$1) {\n    min$$1[0] = mathMin$3(x0, x1);\n    min$$1[1] = mathMin$3(y0, y1);\n    max$$1[0] = mathMax$3(x0, x1);\n    max$$1[1] = mathMax$3(y0, y1);\n}\n\nvar xDim = [];\nvar yDim = [];\n/**\n * 从三阶贝塞尔曲线(p0, p1, p2, p3)中计算出最小包围盒，写入`min`和`max`中\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x3\n * @param {number} y3\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromCubic(\n    x0, y0, x1, y1, x2, y2, x3, y3, min$$1, max$$1\n) {\n    var cubicExtrema$$1 = cubicExtrema;\n    var cubicAt$$1 = cubicAt;\n    var i;\n    var n = cubicExtrema$$1(x0, x1, x2, x3, xDim);\n    min$$1[0] = Infinity;\n    min$$1[1] = Infinity;\n    max$$1[0] = -Infinity;\n    max$$1[1] = -Infinity;\n\n    for (i = 0; i < n; i++) {\n        var x = cubicAt$$1(x0, x1, x2, x3, xDim[i]);\n        min$$1[0] = mathMin$3(x, min$$1[0]);\n        max$$1[0] = mathMax$3(x, max$$1[0]);\n    }\n    n = cubicExtrema$$1(y0, y1, y2, y3, yDim);\n    for (i = 0; i < n; i++) {\n        var y = cubicAt$$1(y0, y1, y2, y3, yDim[i]);\n        min$$1[1] = mathMin$3(y, min$$1[1]);\n        max$$1[1] = mathMax$3(y, max$$1[1]);\n    }\n\n    min$$1[0] = mathMin$3(x0, min$$1[0]);\n    max$$1[0] = mathMax$3(x0, max$$1[0]);\n    min$$1[0] = mathMin$3(x3, min$$1[0]);\n    max$$1[0] = mathMax$3(x3, max$$1[0]);\n\n    min$$1[1] = mathMin$3(y0, min$$1[1]);\n    max$$1[1] = mathMax$3(y0, max$$1[1]);\n    min$$1[1] = mathMin$3(y3, min$$1[1]);\n    max$$1[1] = mathMax$3(y3, max$$1[1]);\n}\n\n/**\n * 从二阶贝塞尔曲线(p0, p1, p2)中计算出最小包围盒，写入`min`和`max`中\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromQuadratic(x0, y0, x1, y1, x2, y2, min$$1, max$$1) {\n    var quadraticExtremum$$1 = quadraticExtremum;\n    var quadraticAt$$1 = quadraticAt;\n    // Find extremities, where derivative in x dim or y dim is zero\n    var tx =\n        mathMax$3(\n            mathMin$3(quadraticExtremum$$1(x0, x1, x2), 1), 0\n        );\n    var ty =\n        mathMax$3(\n            mathMin$3(quadraticExtremum$$1(y0, y1, y2), 1), 0\n        );\n\n    var x = quadraticAt$$1(x0, x1, x2, tx);\n    var y = quadraticAt$$1(y0, y1, y2, ty);\n\n    min$$1[0] = mathMin$3(x0, x2, x);\n    min$$1[1] = mathMin$3(y0, y2, y);\n    max$$1[0] = mathMax$3(x0, x2, x);\n    max$$1[1] = mathMax$3(y0, y2, y);\n}\n\n/**\n * 从圆弧中计算出最小包围盒，写入`min`和`max`中\n * @method\n * @memberOf module:zrender/core/bbox\n * @param {number} x\n * @param {number} y\n * @param {number} rx\n * @param {number} ry\n * @param {number} startAngle\n * @param {number} endAngle\n * @param {number} anticlockwise\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromArc(\n    x, y, rx, ry, startAngle, endAngle, anticlockwise, min$$1, max$$1\n) {\n    var vec2Min = min;\n    var vec2Max = max;\n\n    var diff = Math.abs(startAngle - endAngle);\n\n\n    if (diff % PI2 < 1e-4 && diff > 1e-4) {\n        // Is a circle\n        min$$1[0] = x - rx;\n        min$$1[1] = y - ry;\n        max$$1[0] = x + rx;\n        max$$1[1] = y + ry;\n        return;\n    }\n\n    start[0] = mathCos$2(startAngle) * rx + x;\n    start[1] = mathSin$2(startAngle) * ry + y;\n\n    end[0] = mathCos$2(endAngle) * rx + x;\n    end[1] = mathSin$2(endAngle) * ry + y;\n\n    vec2Min(min$$1, start, end);\n    vec2Max(max$$1, start, end);\n\n    // Thresh to [0, Math.PI * 2]\n    startAngle = startAngle % (PI2);\n    if (startAngle < 0) {\n        startAngle = startAngle + PI2;\n    }\n    endAngle = endAngle % (PI2);\n    if (endAngle < 0) {\n        endAngle = endAngle + PI2;\n    }\n\n    if (startAngle > endAngle && !anticlockwise) {\n        endAngle += PI2;\n    }\n    else if (startAngle < endAngle && anticlockwise) {\n        startAngle += PI2;\n    }\n    if (anticlockwise) {\n        var tmp = endAngle;\n        endAngle = startAngle;\n        startAngle = tmp;\n    }\n\n    // var number = 0;\n    // var step = (anticlockwise ? -Math.PI : Math.PI) / 2;\n    for (var angle = 0; angle < endAngle; angle += Math.PI / 2) {\n        if (angle > startAngle) {\n            extremity[0] = mathCos$2(angle) * rx + x;\n            extremity[1] = mathSin$2(angle) * ry + y;\n\n            vec2Min(min$$1, extremity, min$$1);\n            vec2Max(max$$1, extremity, max$$1);\n        }\n    }\n}\n\n/**\n * Path 代理，可以在`buildPath`中用于替代`ctx`, 会保存每个path操作的命令到pathCommands属性中\n * 可以用于 isInsidePath 判断以及获取boundingRect\n *\n * @module zrender/core/PathProxy\n * @author Yi Shen (http://www.github.com/pissang)\n */\n\n// TODO getTotalLength, getPointAtLength\n\nvar CMD = {\n    M: 1,\n    L: 2,\n    C: 3,\n    Q: 4,\n    A: 5,\n    Z: 6,\n    // Rect\n    R: 7\n};\n\n// var CMD_MEM_SIZE = {\n//     M: 3,\n//     L: 3,\n//     C: 7,\n//     Q: 5,\n//     A: 9,\n//     R: 5,\n//     Z: 1\n// };\n\nvar min$1 = [];\nvar max$1 = [];\nvar min2 = [];\nvar max2 = [];\nvar mathMin$2 = Math.min;\nvar mathMax$2 = Math.max;\nvar mathCos$1 = Math.cos;\nvar mathSin$1 = Math.sin;\nvar mathSqrt$1 = Math.sqrt;\nvar mathAbs = Math.abs;\n\nvar hasTypedArray = typeof Float32Array !== 'undefined';\n\n/**\n * @alias module:zrender/core/PathProxy\n * @constructor\n */\nvar PathProxy = function (notSaveData) {\n\n    this._saveData = !(notSaveData || false);\n\n    if (this._saveData) {\n        /**\n         * Path data. Stored as flat array\n         * @type {Array.<Object>}\n         */\n        this.data = [];\n    }\n\n    this._ctx = null;\n};\n\n/**\n * 快速计算Path包围盒（并不是最小包围盒）\n * @return {Object}\n */\nPathProxy.prototype = {\n\n    constructor: PathProxy,\n\n    _xi: 0,\n    _yi: 0,\n\n    _x0: 0,\n    _y0: 0,\n    // Unit x, Unit y. Provide for avoiding drawing that too short line segment\n    _ux: 0,\n    _uy: 0,\n\n    _len: 0,\n\n    _lineDash: null,\n\n    _dashOffset: 0,\n\n    _dashIdx: 0,\n\n    _dashSum: 0,\n\n    /**\n     * @readOnly\n     */\n    setScale: function (sx, sy) {\n        this._ux = mathAbs(1 / devicePixelRatio / sx) || 0;\n        this._uy = mathAbs(1 / devicePixelRatio / sy) || 0;\n    },\n\n    getContext: function () {\n        return this._ctx;\n    },\n\n    /**\n     * @param  {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    beginPath: function (ctx) {\n\n        this._ctx = ctx;\n\n        ctx && ctx.beginPath();\n\n        ctx && (this.dpr = ctx.dpr);\n\n        // Reset\n        if (this._saveData) {\n            this._len = 0;\n        }\n\n        if (this._lineDash) {\n            this._lineDash = null;\n\n            this._dashOffset = 0;\n        }\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x\n     * @param  {number} y\n     * @return {module:zrender/core/PathProxy}\n     */\n    moveTo: function (x, y) {\n        this.addData(CMD.M, x, y);\n        this._ctx && this._ctx.moveTo(x, y);\n\n        // x0, y0, xi, yi 是记录在 _dashedXXXXTo 方法中使用\n        // xi, yi 记录当前点, x0, y0 在 closePath 的时候回到起始点。\n        // 有可能在 beginPath 之后直接调用 lineTo，这时候 x0, y0 需要\n        // 在 lineTo 方法中记录，这里先不考虑这种情况，dashed line 也只在 IE10- 中不支持\n        this._x0 = x;\n        this._y0 = y;\n\n        this._xi = x;\n        this._yi = y;\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x\n     * @param  {number} y\n     * @return {module:zrender/core/PathProxy}\n     */\n    lineTo: function (x, y) {\n        var exceedUnit = mathAbs(x - this._xi) > this._ux\n            || mathAbs(y - this._yi) > this._uy\n            // Force draw the first segment\n            || this._len < 5;\n\n        this.addData(CMD.L, x, y);\n\n        if (this._ctx && exceedUnit) {\n            this._needsDash() ? this._dashedLineTo(x, y)\n                : this._ctx.lineTo(x, y);\n        }\n        if (exceedUnit) {\n            this._xi = x;\n            this._yi = y;\n        }\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x1\n     * @param  {number} y1\n     * @param  {number} x2\n     * @param  {number} y2\n     * @param  {number} x3\n     * @param  {number} y3\n     * @return {module:zrender/core/PathProxy}\n     */\n    bezierCurveTo: function (x1, y1, x2, y2, x3, y3) {\n        this.addData(CMD.C, x1, y1, x2, y2, x3, y3);\n        if (this._ctx) {\n            this._needsDash() ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3)\n                : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);\n        }\n        this._xi = x3;\n        this._yi = y3;\n        return this;\n    },\n\n    /**\n     * @param  {number} x1\n     * @param  {number} y1\n     * @param  {number} x2\n     * @param  {number} y2\n     * @return {module:zrender/core/PathProxy}\n     */\n    quadraticCurveTo: function (x1, y1, x2, y2) {\n        this.addData(CMD.Q, x1, y1, x2, y2);\n        if (this._ctx) {\n            this._needsDash() ? this._dashedQuadraticTo(x1, y1, x2, y2)\n                : this._ctx.quadraticCurveTo(x1, y1, x2, y2);\n        }\n        this._xi = x2;\n        this._yi = y2;\n        return this;\n    },\n\n    /**\n     * @param  {number} cx\n     * @param  {number} cy\n     * @param  {number} r\n     * @param  {number} startAngle\n     * @param  {number} endAngle\n     * @param  {boolean} anticlockwise\n     * @return {module:zrender/core/PathProxy}\n     */\n    arc: function (cx, cy, r, startAngle, endAngle, anticlockwise) {\n        this.addData(\n            CMD.A, cx, cy, r, r, startAngle, endAngle - startAngle, 0, anticlockwise ? 0 : 1\n        );\n        this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);\n\n        this._xi = mathCos$1(endAngle) * r + cx;\n        this._yi = mathSin$1(endAngle) * r + cy;\n        return this;\n    },\n\n    // TODO\n    arcTo: function (x1, y1, x2, y2, radius) {\n        if (this._ctx) {\n            this._ctx.arcTo(x1, y1, x2, y2, radius);\n        }\n        return this;\n    },\n\n    // TODO\n    rect: function (x, y, w, h) {\n        this._ctx && this._ctx.rect(x, y, w, h);\n        this.addData(CMD.R, x, y, w, h);\n        return this;\n    },\n\n    /**\n     * @return {module:zrender/core/PathProxy}\n     */\n    closePath: function () {\n        this.addData(CMD.Z);\n\n        var ctx = this._ctx;\n        var x0 = this._x0;\n        var y0 = this._y0;\n        if (ctx) {\n            this._needsDash() && this._dashedLineTo(x0, y0);\n            ctx.closePath();\n        }\n\n        this._xi = x0;\n        this._yi = y0;\n        return this;\n    },\n\n    /**\n     * Context 从外部传入，因为有可能是 rebuildPath 完之后再 fill。\n     * stroke 同样\n     * @param {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    fill: function (ctx) {\n        ctx && ctx.fill();\n        this.toStatic();\n    },\n\n    /**\n     * @param {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    stroke: function (ctx) {\n        ctx && ctx.stroke();\n        this.toStatic();\n    },\n\n    /**\n     * 必须在其它绘制命令前调用\n     * Must be invoked before all other path drawing methods\n     * @return {module:zrender/core/PathProxy}\n     */\n    setLineDash: function (lineDash) {\n        if (lineDash instanceof Array) {\n            this._lineDash = lineDash;\n\n            this._dashIdx = 0;\n\n            var lineDashSum = 0;\n            for (var i = 0; i < lineDash.length; i++) {\n                lineDashSum += lineDash[i];\n            }\n            this._dashSum = lineDashSum;\n        }\n        return this;\n    },\n\n    /**\n     * 必须在其它绘制命令前调用\n     * Must be invoked before all other path drawing methods\n     * @return {module:zrender/core/PathProxy}\n     */\n    setLineDashOffset: function (offset) {\n        this._dashOffset = offset;\n        return this;\n    },\n\n    /**\n     *\n     * @return {boolean}\n     */\n    len: function () {\n        return this._len;\n    },\n\n    /**\n     * 直接设置 Path 数据\n     */\n    setData: function (data) {\n\n        var len$$1 = data.length;\n\n        if (!(this.data && this.data.length === len$$1) && hasTypedArray) {\n            this.data = new Float32Array(len$$1);\n        }\n\n        for (var i = 0; i < len$$1; i++) {\n            this.data[i] = data[i];\n        }\n\n        this._len = len$$1;\n    },\n\n    /**\n     * 添加子路径\n     * @param {module:zrender/core/PathProxy|Array.<module:zrender/core/PathProxy>} path\n     */\n    appendPath: function (path) {\n        if (!(path instanceof Array)) {\n            path = [path];\n        }\n        var len$$1 = path.length;\n        var appendSize = 0;\n        var offset = this._len;\n        for (var i = 0; i < len$$1; i++) {\n            appendSize += path[i].len();\n        }\n        if (hasTypedArray && (this.data instanceof Float32Array)) {\n            this.data = new Float32Array(offset + appendSize);\n        }\n        for (var i = 0; i < len$$1; i++) {\n            var appendPathData = path[i].data;\n            for (var k = 0; k < appendPathData.length; k++) {\n                this.data[offset++] = appendPathData[k];\n            }\n        }\n        this._len = offset;\n    },\n\n    /**\n     * 填充 Path 数据。\n     * 尽量复用而不申明新的数组。大部分图形重绘的指令数据长度都是不变的。\n     */\n    addData: function (cmd) {\n        if (!this._saveData) {\n            return;\n        }\n\n        var data = this.data;\n        if (this._len + arguments.length > data.length) {\n            // 因为之前的数组已经转换成静态的 Float32Array\n            // 所以不够用时需要扩展一个新的动态数组\n            this._expandData();\n            data = this.data;\n        }\n        for (var i = 0; i < arguments.length; i++) {\n            data[this._len++] = arguments[i];\n        }\n\n        this._prevCmd = cmd;\n    },\n\n    _expandData: function () {\n        // Only if data is Float32Array\n        if (!(this.data instanceof Array)) {\n            var newData = [];\n            for (var i = 0; i < this._len; i++) {\n                newData[i] = this.data[i];\n            }\n            this.data = newData;\n        }\n    },\n\n    /**\n     * If needs js implemented dashed line\n     * @return {boolean}\n     * @private\n     */\n    _needsDash: function () {\n        return this._lineDash;\n    },\n\n    _dashedLineTo: function (x1, y1) {\n        var dashSum = this._dashSum;\n        var offset = this._dashOffset;\n        var lineDash = this._lineDash;\n        var ctx = this._ctx;\n\n        var x0 = this._xi;\n        var y0 = this._yi;\n        var dx = x1 - x0;\n        var dy = y1 - y0;\n        var dist$$1 = mathSqrt$1(dx * dx + dy * dy);\n        var x = x0;\n        var y = y0;\n        var dash;\n        var nDash = lineDash.length;\n        var idx;\n        dx /= dist$$1;\n        dy /= dist$$1;\n\n        if (offset < 0) {\n            // Convert to positive offset\n            offset = dashSum + offset;\n        }\n        offset %= dashSum;\n        x -= offset * dx;\n        y -= offset * dy;\n\n        while ((dx > 0 && x <= x1) || (dx < 0 && x >= x1)\n        || (dx === 0 && ((dy > 0 && y <= y1) || (dy < 0 && y >= y1)))) {\n            idx = this._dashIdx;\n            dash = lineDash[idx];\n            x += dx * dash;\n            y += dy * dash;\n            this._dashIdx = (idx + 1) % nDash;\n            // Skip positive offset\n            if ((dx > 0 && x < x0) || (dx < 0 && x > x0) || (dy > 0 && y < y0) || (dy < 0 && y > y0)) {\n                continue;\n            }\n            ctx[idx % 2 ? 'moveTo' : 'lineTo'](\n                dx >= 0 ? mathMin$2(x, x1) : mathMax$2(x, x1),\n                dy >= 0 ? mathMin$2(y, y1) : mathMax$2(y, y1)\n            );\n        }\n        // Offset for next lineTo\n        dx = x - x1;\n        dy = y - y1;\n        this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);\n    },\n\n    // Not accurate dashed line to\n    _dashedBezierTo: function (x1, y1, x2, y2, x3, y3) {\n        var dashSum = this._dashSum;\n        var offset = this._dashOffset;\n        var lineDash = this._lineDash;\n        var ctx = this._ctx;\n\n        var x0 = this._xi;\n        var y0 = this._yi;\n        var t;\n        var dx;\n        var dy;\n        var cubicAt$$1 = cubicAt;\n        var bezierLen = 0;\n        var idx = this._dashIdx;\n        var nDash = lineDash.length;\n\n        var x;\n        var y;\n\n        var tmpLen = 0;\n\n        if (offset < 0) {\n            // Convert to positive offset\n            offset = dashSum + offset;\n        }\n        offset %= dashSum;\n        // Bezier approx length\n        for (t = 0; t < 1; t += 0.1) {\n            dx = cubicAt$$1(x0, x1, x2, x3, t + 0.1)\n                - cubicAt$$1(x0, x1, x2, x3, t);\n            dy = cubicAt$$1(y0, y1, y2, y3, t + 0.1)\n                - cubicAt$$1(y0, y1, y2, y3, t);\n            bezierLen += mathSqrt$1(dx * dx + dy * dy);\n        }\n\n        // Find idx after add offset\n        for (; idx < nDash; idx++) {\n            tmpLen += lineDash[idx];\n            if (tmpLen > offset) {\n                break;\n            }\n        }\n        t = (tmpLen - offset) / bezierLen;\n\n        while (t <= 1) {\n\n            x = cubicAt$$1(x0, x1, x2, x3, t);\n            y = cubicAt$$1(y0, y1, y2, y3, t);\n\n            // Use line to approximate dashed bezier\n            // Bad result if dash is long\n            idx % 2 ? ctx.moveTo(x, y)\n                : ctx.lineTo(x, y);\n\n            t += lineDash[idx] / bezierLen;\n\n            idx = (idx + 1) % nDash;\n        }\n\n        // Finish the last segment and calculate the new offset\n        (idx % 2 !== 0) && ctx.lineTo(x3, y3);\n        dx = x3 - x;\n        dy = y3 - y;\n        this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);\n    },\n\n    _dashedQuadraticTo: function (x1, y1, x2, y2) {\n        // Convert quadratic to cubic using degree elevation\n        var x3 = x2;\n        var y3 = y2;\n        x2 = (x2 + 2 * x1) / 3;\n        y2 = (y2 + 2 * y1) / 3;\n        x1 = (this._xi + 2 * x1) / 3;\n        y1 = (this._yi + 2 * y1) / 3;\n\n        this._dashedBezierTo(x1, y1, x2, y2, x3, y3);\n    },\n\n    /**\n     * 转成静态的 Float32Array 减少堆内存占用\n     * Convert dynamic array to static Float32Array\n     */\n    toStatic: function () {\n        var data = this.data;\n        if (data instanceof Array) {\n            data.length = this._len;\n            if (hasTypedArray) {\n                this.data = new Float32Array(data);\n            }\n        }\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function () {\n        min$1[0] = min$1[1] = min2[0] = min2[1] = Number.MAX_VALUE;\n        max$1[0] = max$1[1] = max2[0] = max2[1] = -Number.MAX_VALUE;\n\n        var data = this.data;\n        var xi = 0;\n        var yi = 0;\n        var x0 = 0;\n        var y0 = 0;\n\n        for (var i = 0; i < data.length;) {\n            var cmd = data[i++];\n\n            if (i === 1) {\n                // 如果第一个命令是 L, C, Q\n                // 则 previous point 同绘制命令的第一个 point\n                //\n                // 第一个命令为 Arc 的情况下会在后面特殊处理\n                xi = data[i];\n                yi = data[i + 1];\n\n                x0 = xi;\n                y0 = yi;\n            }\n\n            switch (cmd) {\n                case CMD.M:\n                    // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点\n                    // 在 closePath 的时候使用\n                    x0 = data[i++];\n                    y0 = data[i++];\n                    xi = x0;\n                    yi = y0;\n                    min2[0] = x0;\n                    min2[1] = y0;\n                    max2[0] = x0;\n                    max2[1] = y0;\n                    break;\n                case CMD.L:\n                    fromLine(xi, yi, data[i], data[i + 1], min2, max2);\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.C:\n                    fromCubic(\n                        xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        min2, max2\n                    );\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.Q:\n                    fromQuadratic(\n                        xi, yi, data[i++], data[i++], data[i], data[i + 1],\n                        min2, max2\n                    );\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.A:\n                    // TODO Arc 判断的开销比较大\n                    var cx = data[i++];\n                    var cy = data[i++];\n                    var rx = data[i++];\n                    var ry = data[i++];\n                    var startAngle = data[i++];\n                    var endAngle = data[i++] + startAngle;\n                    // TODO Arc 旋转\n                    i += 1;\n                    var anticlockwise = 1 - data[i++];\n\n                    if (i === 1) {\n                        // 直接使用 arc 命令\n                        // 第一个命令起点还未定义\n                        x0 = mathCos$1(startAngle) * rx + cx;\n                        y0 = mathSin$1(startAngle) * ry + cy;\n                    }\n\n                    fromArc(\n                        cx, cy, rx, ry, startAngle, endAngle,\n                        anticlockwise, min2, max2\n                    );\n\n                    xi = mathCos$1(endAngle) * rx + cx;\n                    yi = mathSin$1(endAngle) * ry + cy;\n                    break;\n                case CMD.R:\n                    x0 = xi = data[i++];\n                    y0 = yi = data[i++];\n                    var width = data[i++];\n                    var height = data[i++];\n                    // Use fromLine\n                    fromLine(x0, y0, x0 + width, y0 + height, min2, max2);\n                    break;\n                case CMD.Z:\n                    xi = x0;\n                    yi = y0;\n                    break;\n            }\n\n            // Union\n            min(min$1, min$1, min2);\n            max(max$1, max$1, max2);\n        }\n\n        // No data\n        if (i === 0) {\n            min$1[0] = min$1[1] = max$1[0] = max$1[1] = 0;\n        }\n\n        return new BoundingRect(\n            min$1[0], min$1[1], max$1[0] - min$1[0], max$1[1] - min$1[1]\n        );\n    },\n\n    /**\n     * Rebuild path from current data\n     * Rebuild path will not consider javascript implemented line dash.\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    rebuildPath: function (ctx) {\n        var d = this.data;\n        var x0, y0;\n        var xi, yi;\n        var x, y;\n        var ux = this._ux;\n        var uy = this._uy;\n        var len$$1 = this._len;\n        for (var i = 0; i < len$$1;) {\n            var cmd = d[i++];\n\n            if (i === 1) {\n                // 如果第一个命令是 L, C, Q\n                // 则 previous point 同绘制命令的第一个 point\n                //\n                // 第一个命令为 Arc 的情况下会在后面特殊处理\n                xi = d[i];\n                yi = d[i + 1];\n\n                x0 = xi;\n                y0 = yi;\n            }\n            switch (cmd) {\n                case CMD.M:\n                    x0 = xi = d[i++];\n                    y0 = yi = d[i++];\n                    ctx.moveTo(xi, yi);\n                    break;\n                case CMD.L:\n                    x = d[i++];\n                    y = d[i++];\n                    // Not draw too small seg between\n                    if (mathAbs(x - xi) > ux || mathAbs(y - yi) > uy || i === len$$1 - 1) {\n                        ctx.lineTo(x, y);\n                        xi = x;\n                        yi = y;\n                    }\n                    break;\n                case CMD.C:\n                    ctx.bezierCurveTo(\n                        d[i++], d[i++], d[i++], d[i++], d[i++], d[i++]\n                    );\n                    xi = d[i - 2];\n                    yi = d[i - 1];\n                    break;\n                case CMD.Q:\n                    ctx.quadraticCurveTo(d[i++], d[i++], d[i++], d[i++]);\n                    xi = d[i - 2];\n                    yi = d[i - 1];\n                    break;\n                case CMD.A:\n                    var cx = d[i++];\n                    var cy = d[i++];\n                    var rx = d[i++];\n                    var ry = d[i++];\n                    var theta = d[i++];\n                    var dTheta = d[i++];\n                    var psi = d[i++];\n                    var fs = d[i++];\n                    var r = (rx > ry) ? rx : ry;\n                    var scaleX = (rx > ry) ? 1 : rx / ry;\n                    var scaleY = (rx > ry) ? ry / rx : 1;\n                    var isEllipse = Math.abs(rx - ry) > 1e-3;\n                    var endAngle = theta + dTheta;\n                    if (isEllipse) {\n                        ctx.translate(cx, cy);\n                        ctx.rotate(psi);\n                        ctx.scale(scaleX, scaleY);\n                        ctx.arc(0, 0, r, theta, endAngle, 1 - fs);\n                        ctx.scale(1 / scaleX, 1 / scaleY);\n                        ctx.rotate(-psi);\n                        ctx.translate(-cx, -cy);\n                    }\n                    else {\n                        ctx.arc(cx, cy, r, theta, endAngle, 1 - fs);\n                    }\n\n                    if (i === 1) {\n                        // 直接使用 arc 命令\n                        // 第一个命令起点还未定义\n                        x0 = mathCos$1(theta) * rx + cx;\n                        y0 = mathSin$1(theta) * ry + cy;\n                    }\n                    xi = mathCos$1(endAngle) * rx + cx;\n                    yi = mathSin$1(endAngle) * ry + cy;\n                    break;\n                case CMD.R:\n                    x0 = xi = d[i];\n                    y0 = yi = d[i + 1];\n                    ctx.rect(d[i++], d[i++], d[i++], d[i++]);\n                    break;\n                case CMD.Z:\n                    ctx.closePath();\n                    xi = x0;\n                    yi = y0;\n            }\n        }\n    }\n};\n\nPathProxy.CMD = CMD;\n\n/**\n * 线段包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$1(x0, y0, x1, y1, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    var _a = 0;\n    var _b = x0;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l)\n        || (y < y0 - _l && y < y1 - _l)\n        || (x > x0 + _l && x > x1 + _l)\n        || (x < x0 - _l && x < x1 - _l)\n    ) {\n        return false;\n    }\n\n    if (x0 !== x1) {\n        _a = (y0 - y1) / (x0 - x1);\n        _b = (x0 * y1 - x1 * y0) / (x0 - x1);\n    }\n    else {\n        return Math.abs(x - x0) <= _l / 2;\n    }\n    var tmp = _a * x - y + _b;\n    var _s = tmp * tmp / (_a * _a + 1);\n    return _s <= _l / 2 * _l / 2;\n}\n\n/**\n * 三次贝塞尔曲线描边包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  x2\n * @param  {number}  y2\n * @param  {number}  x3\n * @param  {number}  y3\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$2(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l)\n        || (y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l)\n        || (x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l)\n        || (x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l)\n    ) {\n        return false;\n    }\n    var d = cubicProjectPoint(\n        x0, y0, x1, y1, x2, y2, x3, y3,\n        x, y, null\n    );\n    return d <= _l / 2;\n}\n\n/**\n * 二次贝塞尔曲线描边包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  x2\n * @param  {number}  y2\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$3(x0, y0, x1, y1, x2, y2, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l && y > y2 + _l)\n        || (y < y0 - _l && y < y1 - _l && y < y2 - _l)\n        || (x > x0 + _l && x > x1 + _l && x > x2 + _l)\n        || (x < x0 - _l && x < x1 - _l && x < x2 - _l)\n    ) {\n        return false;\n    }\n    var d = quadraticProjectPoint(\n        x0, y0, x1, y1, x2, y2,\n        x, y, null\n    );\n    return d <= _l / 2;\n}\n\nvar PI2$3 = Math.PI * 2;\n\nfunction normalizeRadian(angle) {\n    angle %= PI2$3;\n    if (angle < 0) {\n        angle += PI2$3;\n    }\n    return angle;\n}\n\nvar PI2$2 = Math.PI * 2;\n\n/**\n * 圆弧描边包含判断\n * @param  {number}  cx\n * @param  {number}  cy\n * @param  {number}  r\n * @param  {number}  startAngle\n * @param  {number}  endAngle\n * @param  {boolean}  anticlockwise\n * @param  {number} lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {Boolean}\n */\nfunction containStroke$4(\n    cx, cy, r, startAngle, endAngle, anticlockwise,\n    lineWidth, x, y\n) {\n\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n\n    x -= cx;\n    y -= cy;\n    var d = Math.sqrt(x * x + y * y);\n\n    if ((d - _l > r) || (d + _l < r)) {\n        return false;\n    }\n    if (Math.abs(startAngle - endAngle) % PI2$2 < 1e-4) {\n        // Is a circle\n        return true;\n    }\n    if (anticlockwise) {\n        var tmp = startAngle;\n        startAngle = normalizeRadian(endAngle);\n        endAngle = normalizeRadian(tmp);\n    }\n    else {\n        startAngle = normalizeRadian(startAngle);\n        endAngle = normalizeRadian(endAngle);\n    }\n    if (startAngle > endAngle) {\n        endAngle += PI2$2;\n    }\n\n    var angle = Math.atan2(y, x);\n    if (angle < 0) {\n        angle += PI2$2;\n    }\n    return (angle >= startAngle && angle <= endAngle)\n        || (angle + PI2$2 >= startAngle && angle + PI2$2 <= endAngle);\n}\n\nfunction windingLine(x0, y0, x1, y1, x, y) {\n    if ((y > y0 && y > y1) || (y < y0 && y < y1)) {\n        return 0;\n    }\n    // Ignore horizontal line\n    if (y1 === y0) {\n        return 0;\n    }\n    var dir = y1 < y0 ? 1 : -1;\n    var t = (y - y0) / (y1 - y0);\n\n    // Avoid winding error when intersection point is the connect point of two line of polygon\n    if (t === 1 || t === 0) {\n        dir = y1 < y0 ? 0.5 : -0.5;\n    }\n\n    var x_ = t * (x1 - x0) + x0;\n\n    // If (x, y) on the line, considered as \"contain\".\n    return x_ === x ? Infinity : x_ > x ? dir : 0;\n}\n\nvar CMD$1 = PathProxy.CMD;\nvar PI2$1 = Math.PI * 2;\n\nvar EPSILON$2 = 1e-4;\n\nfunction isAroundEqual(a, b) {\n    return Math.abs(a - b) < EPSILON$2;\n}\n\n// 临时数组\nvar roots = [-1, -1, -1];\nvar extrema = [-1, -1];\n\nfunction swapExtrema() {\n    var tmp = extrema[0];\n    extrema[0] = extrema[1];\n    extrema[1] = tmp;\n}\n\nfunction windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {\n    // Quick reject\n    if (\n        (y > y0 && y > y1 && y > y2 && y > y3)\n        || (y < y0 && y < y1 && y < y2 && y < y3)\n    ) {\n        return 0;\n    }\n    var nRoots = cubicRootAt(y0, y1, y2, y3, y, roots);\n    if (nRoots === 0) {\n        return 0;\n    }\n    else {\n        var w = 0;\n        var nExtrema = -1;\n        var y0_;\n        var y1_;\n        for (var i = 0; i < nRoots; i++) {\n            var t = roots[i];\n\n            // Avoid winding error when intersection point is the connect point of two line of polygon\n            var unit = (t === 0 || t === 1) ? 0.5 : 1;\n\n            var x_ = cubicAt(x0, x1, x2, x3, t);\n            if (x_ < x) { // Quick reject\n                continue;\n            }\n            if (nExtrema < 0) {\n                nExtrema = cubicExtrema(y0, y1, y2, y3, extrema);\n                if (extrema[1] < extrema[0] && nExtrema > 1) {\n                    swapExtrema();\n                }\n                y0_ = cubicAt(y0, y1, y2, y3, extrema[0]);\n                if (nExtrema > 1) {\n                    y1_ = cubicAt(y0, y1, y2, y3, extrema[1]);\n                }\n            }\n            if (nExtrema === 2) {\n                // 分成三段单调函数\n                if (t < extrema[0]) {\n                    w += y0_ < y0 ? unit : -unit;\n                }\n                else if (t < extrema[1]) {\n                    w += y1_ < y0_ ? unit : -unit;\n                }\n                else {\n                    w += y3 < y1_ ? unit : -unit;\n                }\n            }\n            else {\n                // 分成两段单调函数\n                if (t < extrema[0]) {\n                    w += y0_ < y0 ? unit : -unit;\n                }\n                else {\n                    w += y3 < y0_ ? unit : -unit;\n                }\n            }\n        }\n        return w;\n    }\n}\n\nfunction windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {\n    // Quick reject\n    if (\n        (y > y0 && y > y1 && y > y2)\n        || (y < y0 && y < y1 && y < y2)\n    ) {\n        return 0;\n    }\n    var nRoots = quadraticRootAt(y0, y1, y2, y, roots);\n    if (nRoots === 0) {\n        return 0;\n    }\n    else {\n        var t = quadraticExtremum(y0, y1, y2);\n        if (t >= 0 && t <= 1) {\n            var w = 0;\n            var y_ = quadraticAt(y0, y1, y2, t);\n            for (var i = 0; i < nRoots; i++) {\n                // Remove one endpoint.\n                var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1;\n\n                var x_ = quadraticAt(x0, x1, x2, roots[i]);\n                if (x_ < x) {   // Quick reject\n                    continue;\n                }\n                if (roots[i] < t) {\n                    w += y_ < y0 ? unit : -unit;\n                }\n                else {\n                    w += y2 < y_ ? unit : -unit;\n                }\n            }\n            return w;\n        }\n        else {\n            // Remove one endpoint.\n            var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1;\n\n            var x_ = quadraticAt(x0, x1, x2, roots[0]);\n            if (x_ < x) {   // Quick reject\n                return 0;\n            }\n            return y2 < y0 ? unit : -unit;\n        }\n    }\n}\n\n// TODO\n// Arc 旋转\nfunction windingArc(\n    cx, cy, r, startAngle, endAngle, anticlockwise, x, y\n) {\n    y -= cy;\n    if (y > r || y < -r) {\n        return 0;\n    }\n    var tmp = Math.sqrt(r * r - y * y);\n    roots[0] = -tmp;\n    roots[1] = tmp;\n\n    var diff = Math.abs(startAngle - endAngle);\n    if (diff < 1e-4) {\n        return 0;\n    }\n    if (diff % PI2$1 < 1e-4) {\n        // Is a circle\n        startAngle = 0;\n        endAngle = PI2$1;\n        var dir = anticlockwise ? 1 : -1;\n        if (x >= roots[0] + cx && x <= roots[1] + cx) {\n            return dir;\n        }\n        else {\n            return 0;\n        }\n    }\n\n    if (anticlockwise) {\n        var tmp = startAngle;\n        startAngle = normalizeRadian(endAngle);\n        endAngle = normalizeRadian(tmp);\n    }\n    else {\n        startAngle = normalizeRadian(startAngle);\n        endAngle = normalizeRadian(endAngle);\n    }\n    if (startAngle > endAngle) {\n        endAngle += PI2$1;\n    }\n\n    var w = 0;\n    for (var i = 0; i < 2; i++) {\n        var x_ = roots[i];\n        if (x_ + cx > x) {\n            var angle = Math.atan2(y, x_);\n            var dir = anticlockwise ? 1 : -1;\n            if (angle < 0) {\n                angle = PI2$1 + angle;\n            }\n            if (\n                (angle >= startAngle && angle <= endAngle)\n                || (angle + PI2$1 >= startAngle && angle + PI2$1 <= endAngle)\n            ) {\n                if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {\n                    dir = -dir;\n                }\n                w += dir;\n            }\n        }\n    }\n    return w;\n}\n\nfunction containPath(data, lineWidth, isStroke, x, y) {\n    var w = 0;\n    var xi = 0;\n    var yi = 0;\n    var x0 = 0;\n    var y0 = 0;\n\n    for (var i = 0; i < data.length;) {\n        var cmd = data[i++];\n        // Begin a new subpath\n        if (cmd === CMD$1.M && i > 1) {\n            // Close previous subpath\n            if (!isStroke) {\n                w += windingLine(xi, yi, x0, y0, x, y);\n            }\n            // 如果被任何一个 subpath 包含\n            // if (w !== 0) {\n            //     return true;\n            // }\n        }\n\n        if (i === 1) {\n            // 如果第一个命令是 L, C, Q\n            // 则 previous point 同绘制命令的第一个 point\n            //\n            // 第一个命令为 Arc 的情况下会在后面特殊处理\n            xi = data[i];\n            yi = data[i + 1];\n\n            x0 = xi;\n            y0 = yi;\n        }\n\n        switch (cmd) {\n            case CMD$1.M:\n                // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点\n                // 在 closePath 的时候使用\n                x0 = data[i++];\n                y0 = data[i++];\n                xi = x0;\n                yi = y0;\n                break;\n            case CMD$1.L:\n                if (isStroke) {\n                    if (containStroke$1(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {\n                        return true;\n                    }\n                }\n                else {\n                    // NOTE 在第一个命令为 L, C, Q 的时候会计算出 NaN\n                    w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.C:\n                if (isStroke) {\n                    if (containStroke$2(xi, yi,\n                        data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingCubic(\n                        xi, yi,\n                        data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        x, y\n                    ) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.Q:\n                if (isStroke) {\n                    if (containStroke$3(xi, yi,\n                        data[i++], data[i++], data[i], data[i + 1],\n                        lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingQuadratic(\n                        xi, yi,\n                        data[i++], data[i++], data[i], data[i + 1],\n                        x, y\n                    ) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.A:\n                // TODO Arc 判断的开销比较大\n                var cx = data[i++];\n                var cy = data[i++];\n                var rx = data[i++];\n                var ry = data[i++];\n                var theta = data[i++];\n                var dTheta = data[i++];\n                // TODO Arc 旋转\n                i += 1;\n                var anticlockwise = 1 - data[i++];\n                var x1 = Math.cos(theta) * rx + cx;\n                var y1 = Math.sin(theta) * ry + cy;\n                // 不是直接使用 arc 命令\n                if (i > 1) {\n                    w += windingLine(xi, yi, x1, y1, x, y);\n                }\n                else {\n                    // 第一个命令起点还未定义\n                    x0 = x1;\n                    y0 = y1;\n                }\n                // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放\n                var _x = (x - cx) * ry / rx + cx;\n                if (isStroke) {\n                    if (containStroke$4(\n                        cx, cy, ry, theta, theta + dTheta, anticlockwise,\n                        lineWidth, _x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingArc(\n                        cx, cy, ry, theta, theta + dTheta, anticlockwise,\n                        _x, y\n                    );\n                }\n                xi = Math.cos(theta + dTheta) * rx + cx;\n                yi = Math.sin(theta + dTheta) * ry + cy;\n                break;\n            case CMD$1.R:\n                x0 = xi = data[i++];\n                y0 = yi = data[i++];\n                var width = data[i++];\n                var height = data[i++];\n                var x1 = x0 + width;\n                var y1 = y0 + height;\n                if (isStroke) {\n                    if (containStroke$1(x0, y0, x1, y0, lineWidth, x, y)\n                        || containStroke$1(x1, y0, x1, y1, lineWidth, x, y)\n                        || containStroke$1(x1, y1, x0, y1, lineWidth, x, y)\n                        || containStroke$1(x0, y1, x0, y0, lineWidth, x, y)\n                    ) {\n                        return true;\n                    }\n                }\n                else {\n                    // FIXME Clockwise ?\n                    w += windingLine(x1, y0, x1, y1, x, y);\n                    w += windingLine(x0, y1, x0, y0, x, y);\n                }\n                break;\n            case CMD$1.Z:\n                if (isStroke) {\n                    if (containStroke$1(\n                        xi, yi, x0, y0, lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    // Close a subpath\n                    w += windingLine(xi, yi, x0, y0, x, y);\n                    // 如果被任何一个 subpath 包含\n                    // FIXME subpaths may overlap\n                    // if (w !== 0) {\n                    //     return true;\n                    // }\n                }\n                xi = x0;\n                yi = y0;\n                break;\n        }\n    }\n    if (!isStroke && !isAroundEqual(yi, y0)) {\n        w += windingLine(xi, yi, x0, y0, x, y) || 0;\n    }\n    return w !== 0;\n}\n\nfunction contain(pathData, x, y) {\n    return containPath(pathData, 0, false, x, y);\n}\n\nfunction containStroke(pathData, lineWidth, x, y) {\n    return containPath(pathData, lineWidth, true, x, y);\n}\n\nvar getCanvasPattern = Pattern.prototype.getCanvasPattern;\n\nvar abs = Math.abs;\n\nvar pathProxyForDraw = new PathProxy(true);\n/**\n * @alias module:zrender/graphic/Path\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nfunction Path(opts) {\n    Displayable.call(this, opts);\n\n    /**\n     * @type {module:zrender/core/PathProxy}\n     * @readOnly\n     */\n    this.path = null;\n}\n\nPath.prototype = {\n\n    constructor: Path,\n\n    type: 'path',\n\n    __dirtyPath: true,\n\n    strokeContainThreshold: 5,\n\n    /**\n     * See `module:zrender/src/graphic/helper/subPixelOptimize`.\n     * @type {boolean}\n     */\n    subPixelOptimize: false,\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n        var path = this.path || pathProxyForDraw;\n        var hasStroke = style.hasStroke();\n        var hasFill = style.hasFill();\n        var fill = style.fill;\n        var stroke = style.stroke;\n        var hasFillGradient = hasFill && !!(fill.colorStops);\n        var hasStrokeGradient = hasStroke && !!(stroke.colorStops);\n        var hasFillPattern = hasFill && !!(fill.image);\n        var hasStrokePattern = hasStroke && !!(stroke.image);\n\n        style.bind(ctx, this, prevEl);\n        this.setTransform(ctx);\n\n        if (this.__dirty) {\n            var rect;\n            // Update gradient because bounding rect may changed\n            if (hasFillGradient) {\n                rect = rect || this.getBoundingRect();\n                this._fillGradient = style.getGradient(ctx, fill, rect);\n            }\n            if (hasStrokeGradient) {\n                rect = rect || this.getBoundingRect();\n                this._strokeGradient = style.getGradient(ctx, stroke, rect);\n            }\n        }\n        // Use the gradient or pattern\n        if (hasFillGradient) {\n            // PENDING If may have affect the state\n            ctx.fillStyle = this._fillGradient;\n        }\n        else if (hasFillPattern) {\n            ctx.fillStyle = getCanvasPattern.call(fill, ctx);\n        }\n        if (hasStrokeGradient) {\n            ctx.strokeStyle = this._strokeGradient;\n        }\n        else if (hasStrokePattern) {\n            ctx.strokeStyle = getCanvasPattern.call(stroke, ctx);\n        }\n\n        var lineDash = style.lineDash;\n        var lineDashOffset = style.lineDashOffset;\n\n        var ctxLineDash = !!ctx.setLineDash;\n\n        // Update path sx, sy\n        var scale = this.getGlobalScale();\n        path.setScale(scale[0], scale[1]);\n\n        // Proxy context\n        // Rebuild path in following 2 cases\n        // 1. Path is dirty\n        // 2. Path needs javascript implemented lineDash stroking.\n        //    In this case, lineDash information will not be saved in PathProxy\n        if (this.__dirtyPath\n            || (lineDash && !ctxLineDash && hasStroke)\n        ) {\n            path.beginPath(ctx);\n\n            // Setting line dash before build path\n            if (lineDash && !ctxLineDash) {\n                path.setLineDash(lineDash);\n                path.setLineDashOffset(lineDashOffset);\n            }\n\n            this.buildPath(path, this.shape, false);\n\n            // Clear path dirty flag\n            if (this.path) {\n                this.__dirtyPath = false;\n            }\n        }\n        else {\n            // Replay path building\n            ctx.beginPath();\n            this.path.rebuildPath(ctx);\n        }\n\n        if (hasFill) {\n            if (style.fillOpacity != null) {\n                var originalGlobalAlpha = ctx.globalAlpha;\n                ctx.globalAlpha = style.fillOpacity * style.opacity;\n                path.fill(ctx);\n                ctx.globalAlpha = originalGlobalAlpha;\n            }\n            else {\n                path.fill(ctx);\n            }\n        }\n\n        if (lineDash && ctxLineDash) {\n            ctx.setLineDash(lineDash);\n            ctx.lineDashOffset = lineDashOffset;\n        }\n\n        if (hasStroke) {\n            if (style.strokeOpacity != null) {\n                var originalGlobalAlpha = ctx.globalAlpha;\n                ctx.globalAlpha = style.strokeOpacity * style.opacity;\n                path.stroke(ctx);\n                ctx.globalAlpha = originalGlobalAlpha;\n            }\n            else {\n                path.stroke(ctx);\n            }\n        }\n\n        if (lineDash && ctxLineDash) {\n            // PENDING\n            // Remove lineDash\n            ctx.setLineDash([]);\n        }\n\n        // Draw rect text\n        if (style.text != null) {\n            // Only restore transform when needs draw text.\n            this.restoreTransform(ctx);\n            this.drawRectText(ctx, this.getBoundingRect());\n        }\n    },\n\n    // When bundling path, some shape may decide if use moveTo to begin a new subpath or closePath\n    // Like in circle\n    buildPath: function (ctx, shapeCfg, inBundle) {},\n\n    createPathProxy: function () {\n        this.path = new PathProxy();\n    },\n\n    getBoundingRect: function () {\n        var rect = this._rect;\n        var style = this.style;\n        var needsUpdateRect = !rect;\n        if (needsUpdateRect) {\n            var path = this.path;\n            if (!path) {\n                // Create path on demand.\n                path = this.path = new PathProxy();\n            }\n            if (this.__dirtyPath) {\n                path.beginPath();\n                this.buildPath(path, this.shape, false);\n            }\n            rect = path.getBoundingRect();\n        }\n        this._rect = rect;\n\n        if (style.hasStroke()) {\n            // Needs update rect with stroke lineWidth when\n            // 1. Element changes scale or lineWidth\n            // 2. Shape is changed\n            var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone());\n            if (this.__dirty || needsUpdateRect) {\n                rectWithStroke.copy(rect);\n                // FIXME Must after updateTransform\n                var w = style.lineWidth;\n                // PENDING, Min line width is needed when line is horizontal or vertical\n                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;\n\n                // Only add extra hover lineWidth when there are no fill\n                if (!style.hasFill()) {\n                    w = Math.max(w, this.strokeContainThreshold || 4);\n                }\n                // Consider line width\n                // Line scale can't be 0;\n                if (lineScale > 1e-10) {\n                    rectWithStroke.width += w / lineScale;\n                    rectWithStroke.height += w / lineScale;\n                    rectWithStroke.x -= w / lineScale / 2;\n                    rectWithStroke.y -= w / lineScale / 2;\n                }\n            }\n\n            // Return rect with stroke\n            return rectWithStroke;\n        }\n\n        return rect;\n    },\n\n    contain: function (x, y) {\n        var localPos = this.transformCoordToLocal(x, y);\n        var rect = this.getBoundingRect();\n        var style = this.style;\n        x = localPos[0];\n        y = localPos[1];\n\n        if (rect.contain(x, y)) {\n            var pathData = this.path.data;\n            if (style.hasStroke()) {\n                var lineWidth = style.lineWidth;\n                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;\n                // Line scale can't be 0;\n                if (lineScale > 1e-10) {\n                    // Only add extra hover lineWidth when there are no fill\n                    if (!style.hasFill()) {\n                        lineWidth = Math.max(lineWidth, this.strokeContainThreshold);\n                    }\n                    if (containStroke(\n                        pathData, lineWidth / lineScale, x, y\n                    )) {\n                        return true;\n                    }\n                }\n            }\n            if (style.hasFill()) {\n                return contain(pathData, x, y);\n            }\n        }\n        return false;\n    },\n\n    /**\n     * @param  {boolean} dirtyPath\n     */\n    dirty: function (dirtyPath) {\n        if (dirtyPath == null) {\n            dirtyPath = true;\n        }\n        // Only mark dirty, not mark clean\n        if (dirtyPath) {\n            this.__dirtyPath = dirtyPath;\n            this._rect = null;\n        }\n\n        this.__dirty = this.__dirtyText = true;\n\n        this.__zr && this.__zr.refresh();\n\n        // Used as a clipping path\n        if (this.__clipTarget) {\n            this.__clipTarget.dirty();\n        }\n    },\n\n    /**\n     * Alias for animate('shape')\n     * @param {boolean} loop\n     */\n    animateShape: function (loop) {\n        return this.animate('shape', loop);\n    },\n\n    // Overwrite attrKV\n    attrKV: function (key, value) {\n        // FIXME\n        if (key === 'shape') {\n            this.setShape(value);\n            this.__dirtyPath = true;\n            this._rect = null;\n        }\n        else {\n            Displayable.prototype.attrKV.call(this, key, value);\n        }\n    },\n\n    /**\n     * @param {Object|string} key\n     * @param {*} value\n     */\n    setShape: function (key, value) {\n        var shape = this.shape;\n        // Path from string may not have shape\n        if (shape) {\n            if (isObject$1(key)) {\n                for (var name in key) {\n                    if (key.hasOwnProperty(name)) {\n                        shape[name] = key[name];\n                    }\n                }\n            }\n            else {\n                shape[key] = value;\n            }\n            this.dirty(true);\n        }\n        return this;\n    },\n\n    getLineScale: function () {\n        var m = this.transform;\n        // Get the line scale.\n        // Determinant of `m` means how much the area is enlarged by the\n        // transformation. So its square root can be used as a scale factor\n        // for width.\n        return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10\n            ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1]))\n            : 1;\n    }\n};\n\n/**\n * 扩展一个 Path element, 比如星形，圆等。\n * Extend a path element\n * @param {Object} props\n * @param {string} props.type Path type\n * @param {Function} props.init Initialize\n * @param {Function} props.buildPath Overwrite buildPath method\n * @param {Object} [props.style] Extended default style config\n * @param {Object} [props.shape] Extended default shape config\n */\nPath.extend = function (defaults$$1) {\n    var Sub = function (opts) {\n        Path.call(this, opts);\n\n        if (defaults$$1.style) {\n            // Extend default style\n            this.style.extendFrom(defaults$$1.style, false);\n        }\n\n        // Extend default shape\n        var defaultShape = defaults$$1.shape;\n        if (defaultShape) {\n            this.shape = this.shape || {};\n            var thisShape = this.shape;\n            for (var name in defaultShape) {\n                if (\n                    !thisShape.hasOwnProperty(name)\n                    && defaultShape.hasOwnProperty(name)\n                ) {\n                    thisShape[name] = defaultShape[name];\n                }\n            }\n        }\n\n        defaults$$1.init && defaults$$1.init.call(this, opts);\n    };\n\n    inherits(Sub, Path);\n\n    // FIXME 不能 extend position, rotation 等引用对象\n    for (var name in defaults$$1) {\n        // Extending prototype values and methods\n        if (name !== 'style' && name !== 'shape') {\n            Sub.prototype[name] = defaults$$1[name];\n        }\n    }\n\n    return Sub;\n};\n\ninherits(Path, Displayable);\n\nvar CMD$2 = PathProxy.CMD;\n\nvar points = [[], [], []];\nvar mathSqrt$3 = Math.sqrt;\nvar mathAtan2 = Math.atan2;\n\nvar transformPath = function (path, m) {\n    var data = path.data;\n    var cmd;\n    var nPoint;\n    var i;\n    var j;\n    var k;\n    var p;\n\n    var M = CMD$2.M;\n    var C = CMD$2.C;\n    var L = CMD$2.L;\n    var R = CMD$2.R;\n    var A = CMD$2.A;\n    var Q = CMD$2.Q;\n\n    for (i = 0, j = 0; i < data.length;) {\n        cmd = data[i++];\n        j = i;\n        nPoint = 0;\n\n        switch (cmd) {\n            case M:\n                nPoint = 1;\n                break;\n            case L:\n                nPoint = 1;\n                break;\n            case C:\n                nPoint = 3;\n                break;\n            case Q:\n                nPoint = 2;\n                break;\n            case A:\n                var x = m[4];\n                var y = m[5];\n                var sx = mathSqrt$3(m[0] * m[0] + m[1] * m[1]);\n                var sy = mathSqrt$3(m[2] * m[2] + m[3] * m[3]);\n                var angle = mathAtan2(-m[1] / sy, m[0] / sx);\n                // cx\n                data[i] *= sx;\n                data[i++] += x;\n                // cy\n                data[i] *= sy;\n                data[i++] += y;\n                // Scale rx and ry\n                // FIXME Assume psi is 0 here\n                data[i++] *= sx;\n                data[i++] *= sy;\n\n                // Start angle\n                data[i++] += angle;\n                // end angle\n                data[i++] += angle;\n                // FIXME psi\n                i += 2;\n                j = i;\n                break;\n            case R:\n                // x0, y0\n                p[0] = data[i++];\n                p[1] = data[i++];\n                applyTransform(p, p, m);\n                data[j++] = p[0];\n                data[j++] = p[1];\n                // x1, y1\n                p[0] += data[i++];\n                p[1] += data[i++];\n                applyTransform(p, p, m);\n                data[j++] = p[0];\n                data[j++] = p[1];\n        }\n\n        for (k = 0; k < nPoint; k++) {\n            var p = points[k];\n            p[0] = data[i++];\n            p[1] = data[i++];\n\n            applyTransform(p, p, m);\n            // Write back\n            data[j++] = p[0];\n            data[j++] = p[1];\n        }\n    }\n};\n\n// command chars\n// var cc = [\n//     'm', 'M', 'l', 'L', 'v', 'V', 'h', 'H', 'z', 'Z',\n//     'c', 'C', 'q', 'Q', 't', 'T', 's', 'S', 'a', 'A'\n// ];\n\nvar mathSqrt = Math.sqrt;\nvar mathSin = Math.sin;\nvar mathCos = Math.cos;\nvar PI = Math.PI;\n\nvar vMag = function (v) {\n    return Math.sqrt(v[0] * v[0] + v[1] * v[1]);\n};\nvar vRatio = function (u, v) {\n    return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));\n};\nvar vAngle = function (u, v) {\n    return (u[0] * v[1] < u[1] * v[0] ? -1 : 1)\n            * Math.acos(vRatio(u, v));\n};\n\nfunction processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) {\n    var psi = psiDeg * (PI / 180.0);\n    var xp = mathCos(psi) * (x1 - x2) / 2.0\n                + mathSin(psi) * (y1 - y2) / 2.0;\n    var yp = -1 * mathSin(psi) * (x1 - x2) / 2.0\n                + mathCos(psi) * (y1 - y2) / 2.0;\n\n    var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);\n\n    if (lambda > 1) {\n        rx *= mathSqrt(lambda);\n        ry *= mathSqrt(lambda);\n    }\n\n    var f = (fa === fs ? -1 : 1)\n        * mathSqrt((((rx * rx) * (ry * ry))\n                - ((rx * rx) * (yp * yp))\n                - ((ry * ry) * (xp * xp))) / ((rx * rx) * (yp * yp)\n                + (ry * ry) * (xp * xp))\n            ) || 0;\n\n    var cxp = f * rx * yp / ry;\n    var cyp = f * -ry * xp / rx;\n\n    var cx = (x1 + x2) / 2.0\n                + mathCos(psi) * cxp\n                - mathSin(psi) * cyp;\n    var cy = (y1 + y2) / 2.0\n            + mathSin(psi) * cxp\n            + mathCos(psi) * cyp;\n\n    var theta = vAngle([ 1, 0 ], [ (xp - cxp) / rx, (yp - cyp) / ry ]);\n    var u = [ (xp - cxp) / rx, (yp - cyp) / ry ];\n    var v = [ (-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry ];\n    var dTheta = vAngle(u, v);\n\n    if (vRatio(u, v) <= -1) {\n        dTheta = PI;\n    }\n    if (vRatio(u, v) >= 1) {\n        dTheta = 0;\n    }\n    if (fs === 0 && dTheta > 0) {\n        dTheta = dTheta - 2 * PI;\n    }\n    if (fs === 1 && dTheta < 0) {\n        dTheta = dTheta + 2 * PI;\n    }\n\n    path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs);\n}\n\n\nvar commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig;\n// Consider case:\n// (1) delimiter can be comma or space, where continuous commas\n// or spaces should be seen as one comma.\n// (2) value can be like:\n// '2e-4', 'l.5.9' (ignore 0), 'M-10-10', 'l-2.43e-1,34.9983',\n// 'l-.5E1,54', '121-23-44-11' (no delimiter)\nvar numberReg = /-?([0-9]*\\.)?[0-9]+([eE]-?[0-9]+)?/g;\n// var valueSplitReg = /[\\s,]+/;\n\nfunction createPathProxyFromString(data) {\n    if (!data) {\n        return new PathProxy();\n    }\n\n    // var data = data.replace(/-/g, ' -')\n    //     .replace(/  /g, ' ')\n    //     .replace(/ /g, ',')\n    //     .replace(/,,/g, ',');\n\n    // var n;\n    // create pipes so that we can split the data\n    // for (n = 0; n < cc.length; n++) {\n    //     cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]);\n    // }\n\n    // data = data.replace(/-/g, ',-');\n\n    // create array\n    // var arr = cs.split('|');\n    // init context point\n    var cpx = 0;\n    var cpy = 0;\n    var subpathX = cpx;\n    var subpathY = cpy;\n    var prevCmd;\n\n    var path = new PathProxy();\n    var CMD = PathProxy.CMD;\n\n    // commandReg.lastIndex = 0;\n    // var cmdResult;\n    // while ((cmdResult = commandReg.exec(data)) != null) {\n    //     var cmdStr = cmdResult[1];\n    //     var cmdContent = cmdResult[2];\n\n    var cmdList = data.match(commandReg);\n    for (var l = 0; l < cmdList.length; l++) {\n        var cmdText = cmdList[l];\n        var cmdStr = cmdText.charAt(0);\n\n        var cmd;\n\n        // String#split is faster a little bit than String#replace or RegExp#exec.\n        // var p = cmdContent.split(valueSplitReg);\n        // var pLen = 0;\n        // for (var i = 0; i < p.length; i++) {\n        //     // '' and other invalid str => NaN\n        //     var val = parseFloat(p[i]);\n        //     !isNaN(val) && (p[pLen++] = val);\n        // }\n\n        var p = cmdText.match(numberReg) || [];\n        var pLen = p.length;\n        for (var i = 0; i < pLen; i++) {\n            p[i] = parseFloat(p[i]);\n        }\n\n        var off = 0;\n        while (off < pLen) {\n            var ctlPtx;\n            var ctlPty;\n\n            var rx;\n            var ry;\n            var psi;\n            var fa;\n            var fs;\n\n            var x1 = cpx;\n            var y1 = cpy;\n\n            // convert l, H, h, V, and v to L\n            switch (cmdStr) {\n                case 'l':\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'L':\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'm':\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.M;\n                    path.addData(cmd, cpx, cpy);\n                    subpathX = cpx;\n                    subpathY = cpy;\n                    cmdStr = 'l';\n                    break;\n                case 'M':\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.M;\n                    path.addData(cmd, cpx, cpy);\n                    subpathX = cpx;\n                    subpathY = cpy;\n                    cmdStr = 'L';\n                    break;\n                case 'h':\n                    cpx += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'H':\n                    cpx = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'v':\n                    cpy += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'V':\n                    cpy = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'C':\n                    cmd = CMD.C;\n                    path.addData(\n                        cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]\n                    );\n                    cpx = p[off - 2];\n                    cpy = p[off - 1];\n                    break;\n                case 'c':\n                    cmd = CMD.C;\n                    path.addData(\n                        cmd,\n                        p[off++] + cpx, p[off++] + cpy,\n                        p[off++] + cpx, p[off++] + cpy,\n                        p[off++] + cpx, p[off++] + cpy\n                    );\n                    cpx += p[off - 2];\n                    cpy += p[off - 1];\n                    break;\n                case 'S':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.C) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cmd = CMD.C;\n                    x1 = p[off++];\n                    y1 = p[off++];\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);\n                    break;\n                case 's':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.C) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cmd = CMD.C;\n                    x1 = cpx + p[off++];\n                    y1 = cpy + p[off++];\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);\n                    break;\n                case 'Q':\n                    x1 = p[off++];\n                    y1 = p[off++];\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, x1, y1, cpx, cpy);\n                    break;\n                case 'q':\n                    x1 = p[off++] + cpx;\n                    y1 = p[off++] + cpy;\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, x1, y1, cpx, cpy);\n                    break;\n                case 'T':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.Q) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);\n                    break;\n                case 't':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.Q) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);\n                    break;\n                case 'A':\n                    rx = p[off++];\n                    ry = p[off++];\n                    psi = p[off++];\n                    fa = p[off++];\n                    fs = p[off++];\n\n                    x1 = cpx, y1 = cpy;\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.A;\n                    processArc(\n                        x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path\n                    );\n                    break;\n                case 'a':\n                    rx = p[off++];\n                    ry = p[off++];\n                    psi = p[off++];\n                    fa = p[off++];\n                    fs = p[off++];\n\n                    x1 = cpx, y1 = cpy;\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.A;\n                    processArc(\n                        x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path\n                    );\n                    break;\n            }\n        }\n\n        if (cmdStr === 'z' || cmdStr === 'Z') {\n            cmd = CMD.Z;\n            path.addData(cmd);\n            // z may be in the middle of the path.\n            cpx = subpathX;\n            cpy = subpathY;\n        }\n\n        prevCmd = cmd;\n    }\n\n    path.toStatic();\n\n    return path;\n}\n\n// TODO Optimize double memory cost problem\nfunction createPathOptions(str, opts) {\n    var pathProxy = createPathProxyFromString(str);\n    opts = opts || {};\n    opts.buildPath = function (path) {\n        if (path.setData) {\n            path.setData(pathProxy.data);\n            // Svg and vml renderer don't have context\n            var ctx = path.getContext();\n            if (ctx) {\n                path.rebuildPath(ctx);\n            }\n        }\n        else {\n            var ctx = path;\n            pathProxy.rebuildPath(ctx);\n        }\n    };\n\n    opts.applyTransform = function (m) {\n        transformPath(pathProxy, m);\n        this.dirty(true);\n    };\n\n    return opts;\n}\n\n/**\n * Create a Path object from path string data\n * http://www.w3.org/TR/SVG/paths.html#PathData\n * @param  {Object} opts Other options\n */\nfunction createFromString(str, opts) {\n    return new Path(createPathOptions(str, opts));\n}\n\n/**\n * Create a Path class from path string data\n * @param  {string} str\n * @param  {Object} opts Other options\n */\nfunction extendFromString(str, opts) {\n    return Path.extend(createPathOptions(str, opts));\n}\n\n/**\n * Merge multiple paths\n */\n// TODO Apply transform\n// TODO stroke dash\n// TODO Optimize double memory cost problem\nfunction mergePath$1(pathEls, opts) {\n    var pathList = [];\n    var len = pathEls.length;\n    for (var i = 0; i < len; i++) {\n        var pathEl = pathEls[i];\n        if (!pathEl.path) {\n            pathEl.createPathProxy();\n        }\n        if (pathEl.__dirtyPath) {\n            pathEl.buildPath(pathEl.path, pathEl.shape, true);\n        }\n        pathList.push(pathEl.path);\n    }\n\n    var pathBundle = new Path(opts);\n    // Need path proxy.\n    pathBundle.createPathProxy();\n    pathBundle.buildPath = function (path) {\n        path.appendPath(pathList);\n        // Svg and vml renderer don't have context\n        var ctx = path.getContext();\n        if (ctx) {\n            path.rebuildPath(ctx);\n        }\n    };\n\n    return pathBundle;\n}\n\n/**\n * @alias zrender/graphic/Text\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nvar Text = function (opts) { // jshint ignore:line\n    Displayable.call(this, opts);\n};\n\nText.prototype = {\n\n    constructor: Text,\n\n    type: 'text',\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        // Use props with prefix 'text'.\n        style.fill = style.stroke = style.shadowBlur = style.shadowColor =\n            style.shadowOffsetX = style.shadowOffsetY = null;\n\n        var text = style.text;\n        // Convert to string\n        text != null && (text += '');\n\n        // Do not apply style.bind in Text node. Because the real bind job\n        // is in textHelper.renderText, and performance of text render should\n        // be considered.\n        // style.bind(ctx, this, prevEl);\n\n        if (!needDrawText(text, style)) {\n            // The current el.style is not applied\n            // and should not be used as cache.\n            ctx.__attrCachedBy = ContextCachedBy.NONE;\n            return;\n        }\n\n        this.setTransform(ctx);\n\n        renderText(this, ctx, text, style, null, prevEl);\n\n        this.restoreTransform(ctx);\n    },\n\n    getBoundingRect: function () {\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        if (!this._rect) {\n            var text = style.text;\n            text != null ? (text += '') : (text = '');\n\n            var rect = getBoundingRect(\n                style.text + '',\n                style.font,\n                style.textAlign,\n                style.textVerticalAlign,\n                style.textPadding,\n                style.textLineHeight,\n                style.rich\n            );\n\n            rect.x += style.x || 0;\n            rect.y += style.y || 0;\n\n            if (getStroke(style.textStroke, style.textStrokeWidth)) {\n                var w = style.textStrokeWidth;\n                rect.x -= w / 2;\n                rect.y -= w / 2;\n                rect.width += w;\n                rect.height += w;\n            }\n\n            this._rect = rect;\n        }\n\n        return this._rect;\n    }\n};\n\ninherits(Text, Displayable);\n\n/**\n * 圆形\n * @module zrender/shape/Circle\n */\n\nvar Circle = Path.extend({\n\n    type: 'circle',\n\n    shape: {\n        cx: 0,\n        cy: 0,\n        r: 0\n    },\n\n\n    buildPath: function (ctx, shape, inBundle) {\n        // Better stroking in ShapeBundle\n        // Always do it may have performence issue ( fill may be 2x more cost)\n        if (inBundle) {\n            ctx.moveTo(shape.cx + shape.r, shape.cy);\n        }\n        // else {\n        //     if (ctx.allocate && !ctx.data.length) {\n        //         ctx.allocate(ctx.CMD_MEM_SIZE.A);\n        //     }\n        // }\n        // Better stroking in ShapeBundle\n        // ctx.moveTo(shape.cx + shape.r, shape.cy);\n        ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true);\n    }\n});\n\n// Fix weird bug in some version of IE11 (like 11.0.9600.178**),\n// where exception \"unexpected call to method or property access\"\n// might be thrown when calling ctx.fill or ctx.stroke after a path\n// whose area size is zero is drawn and ctx.clip() is called and\n// shadowBlur is set. See #4572, #3112, #5777.\n// (e.g.,\n//  ctx.moveTo(10, 10);\n//  ctx.lineTo(20, 10);\n//  ctx.closePath();\n//  ctx.clip();\n//  ctx.shadowBlur = 10;\n//  ...\n//  ctx.fill();\n// )\n\nvar shadowTemp = [\n    ['shadowBlur', 0],\n    ['shadowColor', '#000'],\n    ['shadowOffsetX', 0],\n    ['shadowOffsetY', 0]\n];\n\nvar fixClipWithShadow = function (orignalBrush) {\n\n    // version string can be: '11.0'\n    return (env$1.browser.ie && env$1.browser.version >= 11)\n\n        ? function () {\n            var clipPaths = this.__clipPaths;\n            var style = this.style;\n            var modified;\n\n            if (clipPaths) {\n                for (var i = 0; i < clipPaths.length; i++) {\n                    var clipPath = clipPaths[i];\n                    var shape = clipPath && clipPath.shape;\n                    var type = clipPath && clipPath.type;\n\n                    if (shape && (\n                        (type === 'sector' && shape.startAngle === shape.endAngle)\n                        || (type === 'rect' && (!shape.width || !shape.height))\n                    )) {\n                        for (var j = 0; j < shadowTemp.length; j++) {\n                            // It is save to put shadowTemp static, because shadowTemp\n                            // will be all modified each item brush called.\n                            shadowTemp[j][2] = style[shadowTemp[j][0]];\n                            style[shadowTemp[j][0]] = shadowTemp[j][1];\n                        }\n                        modified = true;\n                        break;\n                    }\n                }\n            }\n\n            orignalBrush.apply(this, arguments);\n\n            if (modified) {\n                for (var j = 0; j < shadowTemp.length; j++) {\n                    style[shadowTemp[j][0]] = shadowTemp[j][2];\n                }\n            }\n        }\n\n        : orignalBrush;\n};\n\n/**\n * 扇形\n * @module zrender/graphic/shape/Sector\n */\n\nvar Sector = Path.extend({\n\n    type: 'sector',\n\n    shape: {\n\n        cx: 0,\n\n        cy: 0,\n\n        r0: 0,\n\n        r: 0,\n\n        startAngle: 0,\n\n        endAngle: Math.PI * 2,\n\n        clockwise: true\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n\n        var x = shape.cx;\n        var y = shape.cy;\n        var r0 = Math.max(shape.r0 || 0, 0);\n        var r = Math.max(shape.r, 0);\n        var startAngle = shape.startAngle;\n        var endAngle = shape.endAngle;\n        var clockwise = shape.clockwise;\n\n        var unitX = Math.cos(startAngle);\n        var unitY = Math.sin(startAngle);\n\n        ctx.moveTo(unitX * r0 + x, unitY * r0 + y);\n\n        ctx.lineTo(unitX * r + x, unitY * r + y);\n\n        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);\n\n        ctx.lineTo(\n            Math.cos(endAngle) * r0 + x,\n            Math.sin(endAngle) * r0 + y\n        );\n\n        if (r0 !== 0) {\n            ctx.arc(x, y, r0, endAngle, startAngle, clockwise);\n        }\n\n        ctx.closePath();\n    }\n});\n\n/**\n * 圆环\n * @module zrender/graphic/shape/Ring\n */\n\nvar Ring = Path.extend({\n\n    type: 'ring',\n\n    shape: {\n        cx: 0,\n        cy: 0,\n        r: 0,\n        r0: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var x = shape.cx;\n        var y = shape.cy;\n        var PI2 = Math.PI * 2;\n        ctx.moveTo(x + shape.r, y);\n        ctx.arc(x, y, shape.r, 0, PI2, false);\n        ctx.moveTo(x + shape.r0, y);\n        ctx.arc(x, y, shape.r0, 0, PI2, true);\n    }\n});\n\n/**\n * Catmull-Rom spline 插值折线\n * @module zrender/shape/util/smoothSpline\n * @author pissang (https://www.github.com/pissang)\n *         Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         errorrik (errorrik@gmail.com)\n */\n\n/**\n * @inner\n */\nfunction interpolate(p0, p1, p2, p3, t, t2, t3) {\n    var v0 = (p2 - p0) * 0.5;\n    var v1 = (p3 - p1) * 0.5;\n    return (2 * (p1 - p2) + v0 + v1) * t3\n            + (-3 * (p1 - p2) - 2 * v0 - v1) * t2\n            + v0 * t + p1;\n}\n\n/**\n * @alias module:zrender/shape/util/smoothSpline\n * @param {Array} points 线段顶点数组\n * @param {boolean} isLoop\n * @return {Array}\n */\nvar smoothSpline = function (points, isLoop) {\n    var len$$1 = points.length;\n    var ret = [];\n\n    var distance$$1 = 0;\n    for (var i = 1; i < len$$1; i++) {\n        distance$$1 += distance(points[i - 1], points[i]);\n    }\n\n    var segs = distance$$1 / 2;\n    segs = segs < len$$1 ? len$$1 : segs;\n    for (var i = 0; i < segs; i++) {\n        var pos = i / (segs - 1) * (isLoop ? len$$1 : len$$1 - 1);\n        var idx = Math.floor(pos);\n\n        var w = pos - idx;\n\n        var p0;\n        var p1 = points[idx % len$$1];\n        var p2;\n        var p3;\n        if (!isLoop) {\n            p0 = points[idx === 0 ? idx : idx - 1];\n            p2 = points[idx > len$$1 - 2 ? len$$1 - 1 : idx + 1];\n            p3 = points[idx > len$$1 - 3 ? len$$1 - 1 : idx + 2];\n        }\n        else {\n            p0 = points[(idx - 1 + len$$1) % len$$1];\n            p2 = points[(idx + 1) % len$$1];\n            p3 = points[(idx + 2) % len$$1];\n        }\n\n        var w2 = w * w;\n        var w3 = w * w2;\n\n        ret.push([\n            interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3),\n            interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3)\n        ]);\n    }\n    return ret;\n};\n\n/**\n * 贝塞尔平滑曲线\n * @module zrender/shape/util/smoothBezier\n * @author pissang (https://www.github.com/pissang)\n *         Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         errorrik (errorrik@gmail.com)\n */\n\n/**\n * 贝塞尔平滑曲线\n * @alias module:zrender/shape/util/smoothBezier\n * @param {Array} points 线段顶点数组\n * @param {number} smooth 平滑等级, 0-1\n * @param {boolean} isLoop\n * @param {Array} constraint 将计算出来的控制点约束在一个包围盒内\n *                           比如 [[0, 0], [100, 100]], 这个包围盒会与\n *                           整个折线的包围盒做一个并集用来约束控制点。\n * @param {Array} 计算出来的控制点数组\n */\nvar smoothBezier = function (points, smooth, isLoop, constraint) {\n    var cps = [];\n\n    var v = [];\n    var v1 = [];\n    var v2 = [];\n    var prevPoint;\n    var nextPoint;\n\n    var min$$1;\n    var max$$1;\n    if (constraint) {\n        min$$1 = [Infinity, Infinity];\n        max$$1 = [-Infinity, -Infinity];\n        for (var i = 0, len$$1 = points.length; i < len$$1; i++) {\n            min(min$$1, min$$1, points[i]);\n            max(max$$1, max$$1, points[i]);\n        }\n        // 与指定的包围盒做并集\n        min(min$$1, min$$1, constraint[0]);\n        max(max$$1, max$$1, constraint[1]);\n    }\n\n    for (var i = 0, len$$1 = points.length; i < len$$1; i++) {\n        var point = points[i];\n\n        if (isLoop) {\n            prevPoint = points[i ? i - 1 : len$$1 - 1];\n            nextPoint = points[(i + 1) % len$$1];\n        }\n        else {\n            if (i === 0 || i === len$$1 - 1) {\n                cps.push(clone$1(points[i]));\n                continue;\n            }\n            else {\n                prevPoint = points[i - 1];\n                nextPoint = points[i + 1];\n            }\n        }\n\n        sub(v, nextPoint, prevPoint);\n\n        // use degree to scale the handle length\n        scale(v, v, smooth);\n\n        var d0 = distance(point, prevPoint);\n        var d1 = distance(point, nextPoint);\n        var sum = d0 + d1;\n        if (sum !== 0) {\n            d0 /= sum;\n            d1 /= sum;\n        }\n\n        scale(v1, v, -d0);\n        scale(v2, v, d1);\n        var cp0 = add([], point, v1);\n        var cp1 = add([], point, v2);\n        if (constraint) {\n            max(cp0, cp0, min$$1);\n            min(cp0, cp0, max$$1);\n            max(cp1, cp1, min$$1);\n            min(cp1, cp1, max$$1);\n        }\n        cps.push(cp0);\n        cps.push(cp1);\n    }\n\n    if (isLoop) {\n        cps.push(cps.shift());\n    }\n\n    return cps;\n};\n\nfunction buildPath$1(ctx, shape, closePath) {\n    var points = shape.points;\n    var smooth = shape.smooth;\n    if (points && points.length >= 2) {\n        if (smooth && smooth !== 'spline') {\n            var controlPoints = smoothBezier(\n                points, smooth, closePath, shape.smoothConstraint\n            );\n\n            ctx.moveTo(points[0][0], points[0][1]);\n            var len = points.length;\n            for (var i = 0; i < (closePath ? len : len - 1); i++) {\n                var cp1 = controlPoints[i * 2];\n                var cp2 = controlPoints[i * 2 + 1];\n                var p = points[(i + 1) % len];\n                ctx.bezierCurveTo(\n                    cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]\n                );\n            }\n        }\n        else {\n            if (smooth === 'spline') {\n                points = smoothSpline(points, closePath);\n            }\n\n            ctx.moveTo(points[0][0], points[0][1]);\n            for (var i = 1, l = points.length; i < l; i++) {\n                ctx.lineTo(points[i][0], points[i][1]);\n            }\n        }\n\n        closePath && ctx.closePath();\n    }\n}\n\n/**\n * 多边形\n * @module zrender/shape/Polygon\n */\n\nvar Polygon = Path.extend({\n\n    type: 'polygon',\n\n    shape: {\n        points: null,\n\n        smooth: false,\n\n        smoothConstraint: null\n    },\n\n    buildPath: function (ctx, shape) {\n        buildPath$1(ctx, shape, true);\n    }\n});\n\n/**\n * @module zrender/graphic/shape/Polyline\n */\n\nvar Polyline = Path.extend({\n\n    type: 'polyline',\n\n    shape: {\n        points: null,\n\n        smooth: false,\n\n        smoothConstraint: null\n    },\n\n    style: {\n        stroke: '#000',\n\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        buildPath$1(ctx, shape, false);\n    }\n});\n\n/**\n * Sub-pixel optimize for canvas rendering, prevent from blur\n * when rendering a thin vertical/horizontal line.\n */\n\nvar round$1 = Math.round;\n\n/**\n * Sub pixel optimize line for canvas\n *\n * @param {Object} outputShape The modification will be performed on `outputShape`.\n *                 `outputShape` and `inputShape` can be the same object.\n *                 `outputShape` object can be used repeatly, because all of\n *                 the `x1`, `x2`, `y1`, `y2` will be assigned in this method.\n * @param {Object} [inputShape]\n * @param {number} [inputShape.x1]\n * @param {number} [inputShape.y1]\n * @param {number} [inputShape.x2]\n * @param {number} [inputShape.y2]\n * @param {Object} [style]\n * @param {number} [style.lineWidth]\n */\nfunction subPixelOptimizeLine$1(outputShape, inputShape, style) {\n    var lineWidth = style && style.lineWidth;\n\n    if (!inputShape || !lineWidth) {\n        return;\n    }\n\n    var x1 = inputShape.x1;\n    var x2 = inputShape.x2;\n    var y1 = inputShape.y1;\n    var y2 = inputShape.y2;\n\n    if (round$1(x1 * 2) === round$1(x2 * 2)) {\n        outputShape.x1 = outputShape.x2 = subPixelOptimize$1(x1, lineWidth, true);\n    }\n    else {\n        outputShape.x1 = x1;\n        outputShape.x2 = x2;\n    }\n    if (round$1(y1 * 2) === round$1(y2 * 2)) {\n        outputShape.y1 = outputShape.y2 = subPixelOptimize$1(y1, lineWidth, true);\n    }\n    else {\n        outputShape.y1 = y1;\n        outputShape.y2 = y2;\n    }\n}\n\n/**\n * Sub pixel optimize rect for canvas\n *\n * @param {Object} outputShape The modification will be performed on `outputShape`.\n *                 `outputShape` and `inputShape` can be the same object.\n *                 `outputShape` object can be used repeatly, because all of\n *                 the `x`, `y`, `width`, `height` will be assigned in this method.\n * @param {Object} [inputShape]\n * @param {number} [inputShape.x]\n * @param {number} [inputShape.y]\n * @param {number} [inputShape.width]\n * @param {number} [inputShape.height]\n * @param {Object} [style]\n * @param {number} [style.lineWidth]\n */\nfunction subPixelOptimizeRect$1(outputShape, inputShape, style) {\n    var lineWidth = style && style.lineWidth;\n\n    if (!inputShape || !lineWidth) {\n        return;\n    }\n\n    var originX = inputShape.x;\n    var originY = inputShape.y;\n    var originWidth = inputShape.width;\n    var originHeight = inputShape.height;\n\n    outputShape.x = subPixelOptimize$1(originX, lineWidth, true);\n    outputShape.y = subPixelOptimize$1(originY, lineWidth, true);\n    outputShape.width = Math.max(\n        subPixelOptimize$1(originX + originWidth, lineWidth, false) - outputShape.x,\n        originWidth === 0 ? 0 : 1\n    );\n    outputShape.height = Math.max(\n        subPixelOptimize$1(originY + originHeight, lineWidth, false) - outputShape.y,\n        originHeight === 0 ? 0 : 1\n    );\n}\n\n/**\n * Sub pixel optimize for canvas\n *\n * @param {number} position Coordinate, such as x, y\n * @param {number} lineWidth Should be nonnegative integer.\n * @param {boolean=} positiveOrNegative Default false (negative).\n * @return {number} Optimized position.\n */\nfunction subPixelOptimize$1(position, lineWidth, positiveOrNegative) {\n    // Assure that (position + lineWidth / 2) is near integer edge,\n    // otherwise line will be fuzzy in canvas.\n    var doubledPosition = round$1(position * 2);\n    return (doubledPosition + round$1(lineWidth)) % 2 === 0\n        ? doubledPosition / 2\n        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;\n}\n\n/**\n * 矩形\n * @module zrender/graphic/shape/Rect\n */\n\n// Avoid create repeatly.\nvar subPixelOptimizeOutputShape = {};\n\nvar Rect = Path.extend({\n\n    type: 'rect',\n\n    shape: {\n        // 左上、右上、右下、左下角的半径依次为r1、r2、r3、r4\n        // r缩写为1         相当于 [1, 1, 1, 1]\n        // r缩写为[1]       相当于 [1, 1, 1, 1]\n        // r缩写为[1, 2]    相当于 [1, 2, 1, 2]\n        // r缩写为[1, 2, 3] 相当于 [1, 2, 3, 2]\n        r: 0,\n\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var x;\n        var y;\n        var width;\n        var height;\n\n        if (this.subPixelOptimize) {\n            subPixelOptimizeRect$1(subPixelOptimizeOutputShape, shape, this.style);\n            x = subPixelOptimizeOutputShape.x;\n            y = subPixelOptimizeOutputShape.y;\n            width = subPixelOptimizeOutputShape.width;\n            height = subPixelOptimizeOutputShape.height;\n            subPixelOptimizeOutputShape.r = shape.r;\n            shape = subPixelOptimizeOutputShape;\n        }\n        else {\n            x = shape.x;\n            y = shape.y;\n            width = shape.width;\n            height = shape.height;\n        }\n\n        if (!shape.r) {\n            ctx.rect(x, y, width, height);\n        }\n        else {\n            buildPath(ctx, shape);\n        }\n        ctx.closePath();\n        return;\n    }\n});\n\n/**\n * 直线\n * @module zrender/graphic/shape/Line\n */\n\n// Avoid create repeatly.\nvar subPixelOptimizeOutputShape$1 = {};\n\nvar Line = Path.extend({\n\n    type: 'line',\n\n    shape: {\n        // Start point\n        x1: 0,\n        y1: 0,\n        // End point\n        x2: 0,\n        y2: 0,\n\n        percent: 1\n    },\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        var x1;\n        var y1;\n        var x2;\n        var y2;\n\n        if (this.subPixelOptimize) {\n            subPixelOptimizeLine$1(subPixelOptimizeOutputShape$1, shape, this.style);\n            x1 = subPixelOptimizeOutputShape$1.x1;\n            y1 = subPixelOptimizeOutputShape$1.y1;\n            x2 = subPixelOptimizeOutputShape$1.x2;\n            y2 = subPixelOptimizeOutputShape$1.y2;\n        }\n        else {\n            x1 = shape.x1;\n            y1 = shape.y1;\n            x2 = shape.x2;\n            y2 = shape.y2;\n        }\n\n        var percent = shape.percent;\n\n        if (percent === 0) {\n            return;\n        }\n\n        ctx.moveTo(x1, y1);\n\n        if (percent < 1) {\n            x2 = x1 * (1 - percent) + x2 * percent;\n            y2 = y1 * (1 - percent) + y2 * percent;\n        }\n        ctx.lineTo(x2, y2);\n    },\n\n    /**\n     * Get point at percent\n     * @param  {number} percent\n     * @return {Array.<number>}\n     */\n    pointAt: function (p) {\n        var shape = this.shape;\n        return [\n            shape.x1 * (1 - p) + shape.x2 * p,\n            shape.y1 * (1 - p) + shape.y2 * p\n        ];\n    }\n});\n\n/**\n * 贝塞尔曲线\n * @module zrender/shape/BezierCurve\n */\n\nvar out = [];\n\nfunction someVectorAt(shape, t, isTangent) {\n    var cpx2 = shape.cpx2;\n    var cpy2 = shape.cpy2;\n    if (cpx2 === null || cpy2 === null) {\n        return [\n            (isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t),\n            (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t)\n        ];\n    }\n    else {\n        return [\n            (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t),\n            (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t)\n        ];\n    }\n}\n\nvar BezierCurve = Path.extend({\n\n    type: 'bezier-curve',\n\n    shape: {\n        x1: 0,\n        y1: 0,\n        x2: 0,\n        y2: 0,\n        cpx1: 0,\n        cpy1: 0,\n        // cpx2: 0,\n        // cpy2: 0\n\n        // Curve show percent, for animating\n        percent: 1\n    },\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        var x1 = shape.x1;\n        var y1 = shape.y1;\n        var x2 = shape.x2;\n        var y2 = shape.y2;\n        var cpx1 = shape.cpx1;\n        var cpy1 = shape.cpy1;\n        var cpx2 = shape.cpx2;\n        var cpy2 = shape.cpy2;\n        var percent = shape.percent;\n        if (percent === 0) {\n            return;\n        }\n\n        ctx.moveTo(x1, y1);\n\n        if (cpx2 == null || cpy2 == null) {\n            if (percent < 1) {\n                quadraticSubdivide(\n                    x1, cpx1, x2, percent, out\n                );\n                cpx1 = out[1];\n                x2 = out[2];\n                quadraticSubdivide(\n                    y1, cpy1, y2, percent, out\n                );\n                cpy1 = out[1];\n                y2 = out[2];\n            }\n\n            ctx.quadraticCurveTo(\n                cpx1, cpy1,\n                x2, y2\n            );\n        }\n        else {\n            if (percent < 1) {\n                cubicSubdivide(\n                    x1, cpx1, cpx2, x2, percent, out\n                );\n                cpx1 = out[1];\n                cpx2 = out[2];\n                x2 = out[3];\n                cubicSubdivide(\n                    y1, cpy1, cpy2, y2, percent, out\n                );\n                cpy1 = out[1];\n                cpy2 = out[2];\n                y2 = out[3];\n            }\n            ctx.bezierCurveTo(\n                cpx1, cpy1,\n                cpx2, cpy2,\n                x2, y2\n            );\n        }\n    },\n\n    /**\n     * Get point at percent\n     * @param  {number} t\n     * @return {Array.<number>}\n     */\n    pointAt: function (t) {\n        return someVectorAt(this.shape, t, false);\n    },\n\n    /**\n     * Get tangent at percent\n     * @param  {number} t\n     * @return {Array.<number>}\n     */\n    tangentAt: function (t) {\n        var p = someVectorAt(this.shape, t, true);\n        return normalize(p, p);\n    }\n});\n\n/**\n * 圆弧\n * @module zrender/graphic/shape/Arc\n */\n\nvar Arc = Path.extend({\n\n    type: 'arc',\n\n    shape: {\n\n        cx: 0,\n\n        cy: 0,\n\n        r: 0,\n\n        startAngle: 0,\n\n        endAngle: Math.PI * 2,\n\n        clockwise: true\n    },\n\n    style: {\n\n        stroke: '#000',\n\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n\n        var x = shape.cx;\n        var y = shape.cy;\n        var r = Math.max(shape.r, 0);\n        var startAngle = shape.startAngle;\n        var endAngle = shape.endAngle;\n        var clockwise = shape.clockwise;\n\n        var unitX = Math.cos(startAngle);\n        var unitY = Math.sin(startAngle);\n\n        ctx.moveTo(unitX * r + x, unitY * r + y);\n        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);\n    }\n});\n\n// CompoundPath to improve performance\n\nvar CompoundPath = Path.extend({\n\n    type: 'compound',\n\n    shape: {\n\n        paths: null\n    },\n\n    _updatePathDirty: function () {\n        var dirtyPath = this.__dirtyPath;\n        var paths = this.shape.paths;\n        for (var i = 0; i < paths.length; i++) {\n            // Mark as dirty if any subpath is dirty\n            dirtyPath = dirtyPath || paths[i].__dirtyPath;\n        }\n        this.__dirtyPath = dirtyPath;\n        this.__dirty = this.__dirty || dirtyPath;\n    },\n\n    beforeBrush: function () {\n        this._updatePathDirty();\n        var paths = this.shape.paths || [];\n        var scale = this.getGlobalScale();\n        // Update path scale\n        for (var i = 0; i < paths.length; i++) {\n            if (!paths[i].path) {\n                paths[i].createPathProxy();\n            }\n            paths[i].path.setScale(scale[0], scale[1]);\n        }\n    },\n\n    buildPath: function (ctx, shape) {\n        var paths = shape.paths || [];\n        for (var i = 0; i < paths.length; i++) {\n            paths[i].buildPath(ctx, paths[i].shape, true);\n        }\n    },\n\n    afterBrush: function () {\n        var paths = this.shape.paths || [];\n        for (var i = 0; i < paths.length; i++) {\n            paths[i].__dirtyPath = false;\n        }\n    },\n\n    getBoundingRect: function () {\n        this._updatePathDirty();\n        return Path.prototype.getBoundingRect.call(this);\n    }\n});\n\n/**\n * @param {Array.<Object>} colorStops\n */\nvar Gradient = function (colorStops) {\n\n    this.colorStops = colorStops || [];\n\n};\n\nGradient.prototype = {\n\n    constructor: Gradient,\n\n    addColorStop: function (offset, color) {\n        this.colorStops.push({\n\n            offset: offset,\n\n            color: color\n        });\n    }\n\n};\n\n/**\n * x, y, x2, y2 are all percent from 0 to 1\n * @param {number} [x=0]\n * @param {number} [y=0]\n * @param {number} [x2=1]\n * @param {number} [y2=0]\n * @param {Array.<Object>} colorStops\n * @param {boolean} [globalCoord=false]\n */\nvar LinearGradient = function (x, y, x2, y2, colorStops, globalCoord) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {type: 'linear', colorStops: ...}`, where\n    // this constructor will not be called.\n\n    this.x = x == null ? 0 : x;\n\n    this.y = y == null ? 0 : y;\n\n    this.x2 = x2 == null ? 1 : x2;\n\n    this.y2 = y2 == null ? 0 : y2;\n\n    // Can be cloned\n    this.type = 'linear';\n\n    // If use global coord\n    this.global = globalCoord || false;\n\n    Gradient.call(this, colorStops);\n};\n\nLinearGradient.prototype = {\n\n    constructor: LinearGradient\n};\n\ninherits(LinearGradient, Gradient);\n\n/**\n * x, y, r are all percent from 0 to 1\n * @param {number} [x=0.5]\n * @param {number} [y=0.5]\n * @param {number} [r=0.5]\n * @param {Array.<Object>} [colorStops]\n * @param {boolean} [globalCoord=false]\n */\nvar RadialGradient = function (x, y, r, colorStops, globalCoord) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {type: 'radial', colorStops: ...}`, where\n    // this constructor will not be called.\n\n    this.x = x == null ? 0.5 : x;\n\n    this.y = y == null ? 0.5 : y;\n\n    this.r = r == null ? 0.5 : r;\n\n    // Can be cloned\n    this.type = 'radial';\n\n    // If use global coord\n    this.global = globalCoord || false;\n\n    Gradient.call(this, colorStops);\n};\n\nRadialGradient.prototype = {\n\n    constructor: RadialGradient\n};\n\ninherits(RadialGradient, Gradient);\n\n/**\n * Displayable for incremental rendering. It will be rendered in a separate layer\n * IncrementalDisplay have two main methods. `clearDisplayables` and `addDisplayables`\n * addDisplayables will render the added displayables incremetally.\n *\n * It use a not clearFlag to tell the painter don't clear the layer if it's the first element.\n */\n// TODO Style override ?\nfunction IncrementalDisplayble(opts) {\n\n    Displayable.call(this, opts);\n\n    this._displayables = [];\n\n    this._temporaryDisplayables = [];\n\n    this._cursor = 0;\n\n    this.notClear = true;\n}\n\nIncrementalDisplayble.prototype.incremental = true;\n\nIncrementalDisplayble.prototype.clearDisplaybles = function () {\n    this._displayables = [];\n    this._temporaryDisplayables = [];\n    this._cursor = 0;\n    this.dirty();\n\n    this.notClear = false;\n};\n\nIncrementalDisplayble.prototype.addDisplayable = function (displayable, notPersistent) {\n    if (notPersistent) {\n        this._temporaryDisplayables.push(displayable);\n    }\n    else {\n        this._displayables.push(displayable);\n    }\n    this.dirty();\n};\n\nIncrementalDisplayble.prototype.addDisplayables = function (displayables, notPersistent) {\n    notPersistent = notPersistent || false;\n    for (var i = 0; i < displayables.length; i++) {\n        this.addDisplayable(displayables[i], notPersistent);\n    }\n};\n\nIncrementalDisplayble.prototype.eachPendingDisplayable = function (cb) {\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        cb && cb(this._displayables[i]);\n    }\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        cb && cb(this._temporaryDisplayables[i]);\n    }\n};\n\nIncrementalDisplayble.prototype.update = function () {\n    this.updateTransform();\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        var displayable = this._displayables[i];\n        // PENDING\n        displayable.parent = this;\n        displayable.update();\n        displayable.parent = null;\n    }\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        var displayable = this._temporaryDisplayables[i];\n        // PENDING\n        displayable.parent = this;\n        displayable.update();\n        displayable.parent = null;\n    }\n};\n\nIncrementalDisplayble.prototype.brush = function (ctx, prevEl) {\n    // Render persistant displayables.\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        var displayable = this._displayables[i];\n        displayable.beforeBrush && displayable.beforeBrush(ctx);\n        displayable.brush(ctx, i === this._cursor ? null : this._displayables[i - 1]);\n        displayable.afterBrush && displayable.afterBrush(ctx);\n    }\n    this._cursor = i;\n    // Render temporary displayables.\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        var displayable = this._temporaryDisplayables[i];\n        displayable.beforeBrush && displayable.beforeBrush(ctx);\n        displayable.brush(ctx, i === 0 ? null : this._temporaryDisplayables[i - 1]);\n        displayable.afterBrush && displayable.afterBrush(ctx);\n    }\n\n    this._temporaryDisplayables = [];\n\n    this.notClear = true;\n};\n\nvar m = [];\nIncrementalDisplayble.prototype.getBoundingRect = function () {\n    if (!this._rect) {\n        var rect = new BoundingRect(Infinity, Infinity, -Infinity, -Infinity);\n        for (var i = 0; i < this._displayables.length; i++) {\n            var displayable = this._displayables[i];\n            var childRect = displayable.getBoundingRect().clone();\n            if (displayable.needLocalTransform()) {\n                childRect.applyTransform(displayable.getLocalTransform(m));\n            }\n            rect.union(childRect);\n        }\n        this._rect = rect;\n    }\n    return this._rect;\n};\n\nIncrementalDisplayble.prototype.contain = function (x, y) {\n    var localPos = this.transformCoordToLocal(x, y);\n    var rect = this.getBoundingRect();\n\n    if (rect.contain(localPos[0], localPos[1])) {\n        for (var i = 0; i < this._displayables.length; i++) {\n            var displayable = this._displayables[i];\n            if (displayable.contain(x, y)) {\n                return true;\n            }\n        }\n    }\n    return false;\n};\n\ninherits(IncrementalDisplayble, Displayable);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar round = Math.round;\nvar mathMax$1 = Math.max;\nvar mathMin$1 = Math.min;\n\nvar EMPTY_OBJ = {};\n\nvar Z2_EMPHASIS_LIFT = 1;\n\n/**\n * Extend shape with parameters\n */\nfunction extendShape(opts) {\n    return Path.extend(opts);\n}\n\n/**\n * Extend path\n */\nfunction extendPath(pathData, opts) {\n    return extendFromString(pathData, opts);\n}\n\n/**\n * Create a path element from path data string\n * @param {string} pathData\n * @param {Object} opts\n * @param {module:zrender/core/BoundingRect} rect\n * @param {string} [layout=cover] 'center' or 'cover'\n */\nfunction makePath(pathData, opts, rect, layout) {\n    var path = createFromString(pathData, opts);\n    if (rect) {\n        if (layout === 'center') {\n            rect = centerGraphic(rect, path.getBoundingRect());\n        }\n        resizePath(path, rect);\n    }\n    return path;\n}\n\n/**\n * Create a image element from image url\n * @param {string} imageUrl image url\n * @param {Object} opts options\n * @param {module:zrender/core/BoundingRect} rect constrain rect\n * @param {string} [layout=cover] 'center' or 'cover'\n */\nfunction makeImage(imageUrl, rect, layout) {\n    var path = new ZImage({\n        style: {\n            image: imageUrl,\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        },\n        onload: function (img) {\n            if (layout === 'center') {\n                var boundingRect = {\n                    width: img.width,\n                    height: img.height\n                };\n                path.setStyle(centerGraphic(rect, boundingRect));\n            }\n        }\n    });\n    return path;\n}\n\n/**\n * Get position of centered element in bounding box.\n *\n * @param  {Object} rect         element local bounding box\n * @param  {Object} boundingRect constraint bounding box\n * @return {Object} element position containing x, y, width, and height\n */\nfunction centerGraphic(rect, boundingRect) {\n    // Set rect to center, keep width / height ratio.\n    var aspect = boundingRect.width / boundingRect.height;\n    var width = rect.height * aspect;\n    var height;\n    if (width <= rect.width) {\n        height = rect.height;\n    }\n    else {\n        width = rect.width;\n        height = width / aspect;\n    }\n    var cx = rect.x + rect.width / 2;\n    var cy = rect.y + rect.height / 2;\n\n    return {\n        x: cx - width / 2,\n        y: cy - height / 2,\n        width: width,\n        height: height\n    };\n}\n\nvar mergePath = mergePath$1;\n\n/**\n * Resize a path to fit the rect\n * @param {module:zrender/graphic/Path} path\n * @param {Object} rect\n */\nfunction resizePath(path, rect) {\n    if (!path.applyTransform) {\n        return;\n    }\n\n    var pathRect = path.getBoundingRect();\n\n    var m = pathRect.calculateTransform(rect);\n\n    path.applyTransform(m);\n}\n\n/**\n * Sub pixel optimize line for canvas\n *\n * @param {Object} param\n * @param {Object} [param.shape]\n * @param {number} [param.shape.x1]\n * @param {number} [param.shape.y1]\n * @param {number} [param.shape.x2]\n * @param {number} [param.shape.y2]\n * @param {Object} [param.style]\n * @param {number} [param.style.lineWidth]\n * @return {Object} Modified param\n */\nfunction subPixelOptimizeLine(param) {\n    var shape = param.shape;\n    var lineWidth = param.style.lineWidth;\n\n    if (round(shape.x1 * 2) === round(shape.x2 * 2)) {\n        shape.x1 = shape.x2 = subPixelOptimize(shape.x1, lineWidth, true);\n    }\n    if (round(shape.y1 * 2) === round(shape.y2 * 2)) {\n        shape.y1 = shape.y2 = subPixelOptimize(shape.y1, lineWidth, true);\n    }\n    return param;\n}\n\n/**\n * Sub pixel optimize rect for canvas\n *\n * @param {Object} param\n * @param {Object} [param.shape]\n * @param {number} [param.shape.x]\n * @param {number} [param.shape.y]\n * @param {number} [param.shape.width]\n * @param {number} [param.shape.height]\n * @param {Object} [param.style]\n * @param {number} [param.style.lineWidth]\n * @return {Object} Modified param\n */\nfunction subPixelOptimizeRect(param) {\n    var shape = param.shape;\n    var lineWidth = param.style.lineWidth;\n    var originX = shape.x;\n    var originY = shape.y;\n    var originWidth = shape.width;\n    var originHeight = shape.height;\n    shape.x = subPixelOptimize(shape.x, lineWidth, true);\n    shape.y = subPixelOptimize(shape.y, lineWidth, true);\n    shape.width = Math.max(\n        subPixelOptimize(originX + originWidth, lineWidth, false) - shape.x,\n        originWidth === 0 ? 0 : 1\n    );\n    shape.height = Math.max(\n        subPixelOptimize(originY + originHeight, lineWidth, false) - shape.y,\n        originHeight === 0 ? 0 : 1\n    );\n    return param;\n}\n\n/**\n * Sub pixel optimize for canvas\n *\n * @param {number} position Coordinate, such as x, y\n * @param {number} lineWidth Should be nonnegative integer.\n * @param {boolean=} positiveOrNegative Default false (negative).\n * @return {number} Optimized position.\n */\nfunction subPixelOptimize(position, lineWidth, positiveOrNegative) {\n    // Assure that (position + lineWidth / 2) is near integer edge,\n    // otherwise line will be fuzzy in canvas.\n    var doubledPosition = round(position * 2);\n    return (doubledPosition + round(lineWidth)) % 2 === 0\n        ? doubledPosition / 2\n        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;\n}\n\nfunction hasFillOrStroke(fillOrStroke) {\n    return fillOrStroke != null && fillOrStroke !== 'none';\n}\n\n// Most lifted color are duplicated.\nvar liftedColorMap = createHashMap();\nvar liftedColorCount = 0;\n\nfunction liftColor(color) {\n    if (typeof color !== 'string') {\n        return color;\n    }\n    var liftedColor = liftedColorMap.get(color);\n    if (!liftedColor) {\n        liftedColor = lift(color, -0.1);\n        if (liftedColorCount < 10000) {\n            liftedColorMap.set(color, liftedColor);\n            liftedColorCount++;\n        }\n    }\n    return liftedColor;\n}\n\nfunction cacheElementStl(el) {\n    if (!el.__hoverStlDirty) {\n        return;\n    }\n    el.__hoverStlDirty = false;\n\n    var hoverStyle = el.__hoverStl;\n    if (!hoverStyle) {\n        el.__cachedNormalStl = el.__cachedNormalZ2 = null;\n        return;\n    }\n\n    var normalStyle = el.__cachedNormalStl = {};\n    el.__cachedNormalZ2 = el.z2;\n    var elStyle = el.style;\n\n    for (var name in hoverStyle) {\n        // See comment in `doSingleEnterHover`.\n        if (hoverStyle[name] != null) {\n            normalStyle[name] = elStyle[name];\n        }\n    }\n\n    // Always cache fill and stroke to normalStyle for lifting color.\n    normalStyle.fill = elStyle.fill;\n    normalStyle.stroke = elStyle.stroke;\n}\n\nfunction doSingleEnterHover(el) {\n    var hoverStl = el.__hoverStl;\n\n    if (!hoverStl || el.__highlighted) {\n        return;\n    }\n\n    var useHoverLayer = el.useHoverLayer;\n    el.__highlighted = useHoverLayer ? 'layer' : 'plain';\n\n    var zr = el.__zr;\n    if (!zr && useHoverLayer) {\n        return;\n    }\n\n    var elTarget = el;\n    var targetStyle = el.style;\n\n    if (useHoverLayer) {\n        elTarget = zr.addHover(el);\n        targetStyle = elTarget.style;\n    }\n\n    rollbackDefaultTextStyle(targetStyle);\n\n    if (!useHoverLayer) {\n        cacheElementStl(elTarget);\n    }\n\n    // styles can be:\n    // {\n    //    label: {\n    //        show: false,\n    //        position: 'outside',\n    //        fontSize: 18\n    //    },\n    //    emphasis: {\n    //        label: {\n    //            show: true\n    //        }\n    //    }\n    // },\n    // where properties of `emphasis` may not appear in `normal`. We previously use\n    // module:echarts/util/model#defaultEmphasis to merge `normal` to `emphasis`.\n    // But consider rich text and setOption in merge mode, it is impossible to cover\n    // all properties in merge. So we use merge mode when setting style here, where\n    // only properties that is not `null/undefined` can be set. The disadventage:\n    // null/undefined can not be used to remove style any more in `emphasis`.\n    targetStyle.extendFrom(hoverStl);\n\n    setDefaultHoverFillStroke(targetStyle, hoverStl, 'fill');\n    setDefaultHoverFillStroke(targetStyle, hoverStl, 'stroke');\n\n    applyDefaultTextStyle(targetStyle);\n\n    if (!useHoverLayer) {\n        el.dirty(false);\n        el.z2 += Z2_EMPHASIS_LIFT;\n    }\n}\n\nfunction setDefaultHoverFillStroke(targetStyle, hoverStyle, prop) {\n    if (!hasFillOrStroke(hoverStyle[prop]) && hasFillOrStroke(targetStyle[prop])) {\n        targetStyle[prop] = liftColor(targetStyle[prop]);\n    }\n}\n\nfunction doSingleLeaveHover(el) {\n    var highlighted = el.__highlighted;\n\n    if (!highlighted) {\n        return;\n    }\n\n    el.__highlighted = false;\n\n    if (highlighted === 'layer') {\n        el.__zr && el.__zr.removeHover(el);\n    }\n    else if (highlighted) {\n        var style = el.style;\n\n        var normalStl = el.__cachedNormalStl;\n        if (normalStl) {\n            rollbackDefaultTextStyle(style);\n            // Consider null/undefined value, should use\n            // `setStyle` but not `extendFrom(stl, true)`.\n            el.setStyle(normalStl);\n            applyDefaultTextStyle(style);\n        }\n        // `__cachedNormalZ2` will not be reset if calling `setElementHoverStyle`\n        // when `el` is on emphasis state. So here by comparing with 1, we try\n        // hard to make the bug case rare.\n        var normalZ2 = el.__cachedNormalZ2;\n        if (normalZ2 != null && el.z2 - normalZ2 === Z2_EMPHASIS_LIFT) {\n            el.z2 = normalZ2;\n        }\n    }\n}\n\nfunction traverseCall(el, method) {\n    el.isGroup\n        ? el.traverse(function (child) {\n            !child.isGroup && method(child);\n        })\n        : method(el);\n}\n\n/**\n * Set hover style (namely \"emphasis style\") of element, based on the current\n * style of the given `el`.\n * This method should be called after all of the normal styles have been adopted\n * to the `el`. See the reason on `setHoverStyle`.\n *\n * @param {module:zrender/Element} el Should not be `zrender/container/Group`.\n * @param {Object|boolean} [hoverStl] The specified hover style.\n *        If set as `false`, disable the hover style.\n *        Similarly, The `el.hoverStyle` can alse be set\n *        as `false` to disable the hover style.\n *        Otherwise, use the default hover style if not provided.\n * @param {Object} [opt]\n * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`\n */\nfunction setElementHoverStyle(el, hoverStl) {\n    // For performance consideration, it might be better to make the \"hover style\" only the\n    // difference properties from the \"normal style\", but not a entire copy of all styles.\n    hoverStl = el.__hoverStl = hoverStl !== false && (hoverStl || {});\n    el.__hoverStlDirty = true;\n\n    // FIXME\n    // It is not completely right to save \"normal\"/\"emphasis\" flag on elements.\n    // It probably should be saved on `data` of series. Consider the cases:\n    // (1) A highlighted elements are moved out of the view port and re-enter\n    // again by dataZoom.\n    // (2) call `setOption` and replace elements totally when they are highlighted.\n    if (el.__highlighted) {\n        // Consider the case:\n        // The styles of a highlighted `el` is being updated. The new \"emphasis style\"\n        // should be adapted to the `el`. Notice here new \"normal styles\" should have\n        // been set outside and the cached \"normal style\" is out of date.\n        el.__cachedNormalStl = null;\n        // Do not clear `__cachedNormalZ2` here, because setting `z2` is not a constraint\n        // of this method. In most cases, `z2` is not set and hover style should be able\n        // to rollback. Of course, that would bring bug, but only in a rare case, see\n        // `doSingleLeaveHover` for details.\n        doSingleLeaveHover(el);\n\n        doSingleEnterHover(el);\n    }\n}\n\n/**\n * Emphasis (called by API) has higher priority than `mouseover`.\n * When element has been called to be entered emphasis, mouse over\n * should not trigger the highlight effect (for example, animation\n * scale) again, and `mouseout` should not downplay the highlight\n * effect. So the listener of `mouseover` and `mouseout` should\n * check `isInEmphasis`.\n *\n * @param {module:zrender/Element} el\n * @return {boolean}\n */\nfunction isInEmphasis(el) {\n    return el && el.__isEmphasisEntered;\n}\n\nfunction onElementMouseOver(e) {\n    if (this.__hoverSilentOnTouch && e.zrByTouch) {\n        return;\n    }\n\n    // Only if element is not in emphasis status\n    !this.__isEmphasisEntered && traverseCall(this, doSingleEnterHover);\n}\n\nfunction onElementMouseOut(e) {\n    if (this.__hoverSilentOnTouch && e.zrByTouch) {\n        return;\n    }\n\n    // Only if element is not in emphasis status\n    !this.__isEmphasisEntered && traverseCall(this, doSingleLeaveHover);\n}\n\nfunction enterEmphasis() {\n    this.__isEmphasisEntered = true;\n    traverseCall(this, doSingleEnterHover);\n}\n\nfunction leaveEmphasis() {\n    this.__isEmphasisEntered = false;\n    traverseCall(this, doSingleLeaveHover);\n}\n\n/**\n * Set hover style (namely \"emphasis style\") of element,\n * based on the current style of the given `el`.\n *\n * (1)\n * **CONSTRAINTS** for this method:\n * <A> This method MUST be called after all of the normal styles having been adopted\n * to the `el`.\n * <B> The input `hoverStyle` (that is, \"emphasis style\") MUST be the subset of the\n * \"normal style\" having been set to the el.\n * <C> `color` MUST be one of the \"normal styles\" (because color might be lifted as\n * a default hover style).\n *\n * The reason: this method treat the current style of the `el` as the \"normal style\"\n * and cache them when enter/update the \"emphasis style\". Consider the case: the `el`\n * is in \"emphasis\" state and `setOption`/`dispatchAction` trigger the style updating\n * logic, where the el should shift from the original emphasis style to the new\n * \"emphasis style\" and should be able to \"downplay\" back to the new \"normal style\".\n *\n * Indeed, it is error-prone to make a interface has so many constraints, but I have\n * not found a better solution yet to fit the backward compatibility, performance and\n * the current programming style.\n *\n * (2)\n * Call the method for a \"root\" element once. Do not call it for each descendants.\n * If the descendants elemenets of a group has itself hover style different from the\n * root group, we can simply mount the style on `el.hoverStyle` for them, but should\n * not call this method for them.\n *\n * @param {module:zrender/Element} el\n * @param {Object|boolean} [hoverStyle] See `graphic.setElementHoverStyle`.\n * @param {Object} [opt]\n * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`.\n */\nfunction setHoverStyle(el, hoverStyle, opt) {\n    el.isGroup\n        ? el.traverse(function (child) {\n            // If element has sepcified hoverStyle, then use it instead of given hoverStyle\n            // Often used when item group has a label element and it's hoverStyle is different\n            !child.isGroup && setElementHoverStyle(child, child.hoverStyle || hoverStyle);\n        })\n        : setElementHoverStyle(el, el.hoverStyle || hoverStyle);\n\n    setAsHoverStyleTrigger(el, opt);\n}\n\n/**\n * @param {Object|boolean} [opt] If `false`, means disable trigger.\n * @param {boolean} [opt.hoverSilentOnTouch=false]\n *        In touch device, mouseover event will be trigger on touchstart event\n *        (see module:zrender/dom/HandlerProxy). By this mechanism, we can\n *        conveniently use hoverStyle when tap on touch screen without additional\n *        code for compatibility.\n *        But if the chart/component has select feature, which usually also use\n *        hoverStyle, there might be conflict between 'select-highlight' and\n *        'hover-highlight' especially when roam is enabled (see geo for example).\n *        In this case, hoverSilentOnTouch should be used to disable hover-highlight\n *        on touch device.\n */\nfunction setAsHoverStyleTrigger(el, opt) {\n    var disable = opt === false;\n    el.__hoverSilentOnTouch = opt != null && opt.hoverSilentOnTouch;\n\n    // Simple optimize, since this method might be\n    // called for each elements of a group in some cases.\n    if (!disable || el.__hoverStyleTrigger) {\n        var method = disable ? 'off' : 'on';\n\n        // Duplicated function will be auto-ignored, see Eventful.js.\n        el[method]('mouseover', onElementMouseOver)[method]('mouseout', onElementMouseOut);\n        // Emphasis, normal can be triggered manually\n        el[method]('emphasis', enterEmphasis)[method]('normal', leaveEmphasis);\n\n        el.__hoverStyleTrigger = !disable;\n    }\n}\n\n/**\n * See more info in `setTextStyleCommon`.\n * @param {Object|module:zrender/graphic/Style} normalStyle\n * @param {Object} emphasisStyle\n * @param {module:echarts/model/Model} normalModel\n * @param {module:echarts/model/Model} emphasisModel\n * @param {Object} opt Check `opt` of `setTextStyleCommon` to find other props.\n * @param {string|Function} [opt.defaultText]\n * @param {module:echarts/model/Model} [opt.labelFetcher] Fetch text by\n *      `opt.labelFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {module:echarts/model/Model} [opt.labelDataIndex] Fetch text by\n *      `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {module:echarts/model/Model} [opt.labelDimIndex] Fetch text by\n *      `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {Object} [normalSpecified]\n * @param {Object} [emphasisSpecified]\n */\nfunction setLabelStyle(\n    normalStyle, emphasisStyle,\n    normalModel, emphasisModel,\n    opt,\n    normalSpecified, emphasisSpecified\n) {\n    opt = opt || EMPTY_OBJ;\n    var labelFetcher = opt.labelFetcher;\n    var labelDataIndex = opt.labelDataIndex;\n    var labelDimIndex = opt.labelDimIndex;\n\n    // This scenario, `label.normal.show = true; label.emphasis.show = false`,\n    // is not supported util someone requests.\n\n    var showNormal = normalModel.getShallow('show');\n    var showEmphasis = emphasisModel.getShallow('show');\n\n    // Consider performance, only fetch label when necessary.\n    // If `normal.show` is `false` and `emphasis.show` is `true` and `emphasis.formatter` is not set,\n    // label should be displayed, where text is fetched by `normal.formatter` or `opt.defaultText`.\n    var baseText;\n    if (showNormal || showEmphasis) {\n        if (labelFetcher) {\n            baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex);\n        }\n        if (baseText == null) {\n            baseText = isFunction$1(opt.defaultText) ? opt.defaultText(labelDataIndex, opt) : opt.defaultText;\n        }\n    }\n    var normalStyleText = showNormal ? baseText : null;\n    var emphasisStyleText = showEmphasis\n        ? retrieve2(\n            labelFetcher\n                ? labelFetcher.getFormattedLabel(labelDataIndex, 'emphasis', null, labelDimIndex)\n                : null,\n            baseText\n        )\n        : null;\n\n    // Optimize: If style.text is null, text will not be drawn.\n    if (normalStyleText != null || emphasisStyleText != null) {\n        // Always set `textStyle` even if `normalStyle.text` is null, because default\n        // values have to be set on `normalStyle`.\n        // If we set default values on `emphasisStyle`, consider case:\n        // Firstly, `setOption(... label: {normal: {text: null}, emphasis: {show: true}} ...);`\n        // Secondly, `setOption(... label: {noraml: {show: true, text: 'abc', color: 'red'} ...);`\n        // Then the 'red' will not work on emphasis.\n        setTextStyle(normalStyle, normalModel, normalSpecified, opt);\n        setTextStyle(emphasisStyle, emphasisModel, emphasisSpecified, opt, true);\n    }\n\n    normalStyle.text = normalStyleText;\n    emphasisStyle.text = emphasisStyleText;\n}\n\n/**\n * Set basic textStyle properties.\n * See more info in `setTextStyleCommon`.\n * @param {Object|module:zrender/graphic/Style} textStyle\n * @param {module:echarts/model/Model} model\n * @param {Object} [specifiedTextStyle] Can be overrided by settings in model.\n * @param {Object} [opt] See `opt` of `setTextStyleCommon`.\n * @param {boolean} [isEmphasis]\n */\nfunction setTextStyle(\n    textStyle, textStyleModel, specifiedTextStyle, opt, isEmphasis\n) {\n    setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis);\n    specifiedTextStyle && extend(textStyle, specifiedTextStyle);\n    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);\n\n    return textStyle;\n}\n\n/**\n * Set text option in the style.\n * See more info in `setTextStyleCommon`.\n * @deprecated\n * @param {Object} textStyle\n * @param {module:echarts/model/Model} labelModel\n * @param {string|boolean} defaultColor Default text color.\n *        If set as false, it will be processed as a emphasis style.\n */\nfunction setText(textStyle, labelModel, defaultColor) {\n    var opt = {isRectText: true};\n    var isEmphasis;\n\n    if (defaultColor === false) {\n        isEmphasis = true;\n    }\n    else {\n        // Support setting color as 'auto' to get visual color.\n        opt.autoColor = defaultColor;\n    }\n    setTextStyleCommon(textStyle, labelModel, opt, isEmphasis);\n    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);\n}\n\n/**\n * The uniform entry of set text style, that is, retrieve style definitions\n * from `model` and set to `textStyle` object.\n *\n * Never in merge mode, but in overwrite mode, that is, all of the text style\n * properties will be set. (Consider the states of normal and emphasis and\n * default value can be adopted, merge would make the logic too complicated\n * to manage.)\n *\n * The `textStyle` object can either be a plain object or an instance of\n * `zrender/src/graphic/Style`, and either be the style of normal or emphasis.\n * After this mothod called, the `textStyle` object can then be used in\n * `el.setStyle(textStyle)` or `el.hoverStyle = textStyle`.\n *\n * Default value will be adopted and `insideRollbackOpt` will be created.\n * See `applyDefaultTextStyle` `rollbackDefaultTextStyle` for more details.\n *\n * opt: {\n *      disableBox: boolean, Whether diable drawing box of block (outer most).\n *      isRectText: boolean,\n *      autoColor: string, specify a color when color is 'auto',\n *              for textFill, textStroke, textBackgroundColor, and textBorderColor.\n *              If autoColor specified, it is used as default textFill.\n *      useInsideStyle:\n *              `true`: Use inside style (textFill, textStroke, textStrokeWidth)\n *                  if `textFill` is not specified.\n *              `false`: Do not use inside style.\n *              `null/undefined`: use inside style if `isRectText` is true and\n *                  `textFill` is not specified and textPosition contains `'inside'`.\n *      forceRich: boolean\n * }\n */\nfunction setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis) {\n    // Consider there will be abnormal when merge hover style to normal style if given default value.\n    opt = opt || EMPTY_OBJ;\n\n    if (opt.isRectText) {\n        var textPosition = textStyleModel.getShallow('position')\n            || (isEmphasis ? null : 'inside');\n        // 'outside' is not a valid zr textPostion value, but used\n        // in bar series, and magric type should be considered.\n        textPosition === 'outside' && (textPosition = 'top');\n        textStyle.textPosition = textPosition;\n        textStyle.textOffset = textStyleModel.getShallow('offset');\n        var labelRotate = textStyleModel.getShallow('rotate');\n        labelRotate != null && (labelRotate *= Math.PI / 180);\n        textStyle.textRotation = labelRotate;\n        textStyle.textDistance = retrieve2(\n            textStyleModel.getShallow('distance'), isEmphasis ? null : 5\n        );\n    }\n\n    var ecModel = textStyleModel.ecModel;\n    var globalTextStyle = ecModel && ecModel.option.textStyle;\n\n    // Consider case:\n    // {\n    //     data: [{\n    //         value: 12,\n    //         label: {\n    //             rich: {\n    //                 // no 'a' here but using parent 'a'.\n    //             }\n    //         }\n    //     }],\n    //     rich: {\n    //         a: { ... }\n    //     }\n    // }\n    var richItemNames = getRichItemNames(textStyleModel);\n    var richResult;\n    if (richItemNames) {\n        richResult = {};\n        for (var name in richItemNames) {\n            if (richItemNames.hasOwnProperty(name)) {\n                // Cascade is supported in rich.\n                var richTextStyle = textStyleModel.getModel(['rich', name]);\n                // In rich, never `disableBox`.\n                setTokenTextStyle(richResult[name] = {}, richTextStyle, globalTextStyle, opt, isEmphasis);\n            }\n        }\n    }\n    textStyle.rich = richResult;\n\n    setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, true);\n\n    if (opt.forceRich && !opt.textStyle) {\n        opt.textStyle = {};\n    }\n\n    return textStyle;\n}\n\n// Consider case:\n// {\n//     data: [{\n//         value: 12,\n//         label: {\n//             rich: {\n//                 // no 'a' here but using parent 'a'.\n//             }\n//         }\n//     }],\n//     rich: {\n//         a: { ... }\n//     }\n// }\nfunction getRichItemNames(textStyleModel) {\n    // Use object to remove duplicated names.\n    var richItemNameMap;\n    while (textStyleModel && textStyleModel !== textStyleModel.ecModel) {\n        var rich = (textStyleModel.option || EMPTY_OBJ).rich;\n        if (rich) {\n            richItemNameMap = richItemNameMap || {};\n            for (var name in rich) {\n                if (rich.hasOwnProperty(name)) {\n                    richItemNameMap[name] = 1;\n                }\n            }\n        }\n        textStyleModel = textStyleModel.parentModel;\n    }\n    return richItemNameMap;\n}\n\nfunction setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, isBlock) {\n    // In merge mode, default value should not be given.\n    globalTextStyle = !isEmphasis && globalTextStyle || EMPTY_OBJ;\n\n    textStyle.textFill = getAutoColor(textStyleModel.getShallow('color'), opt)\n        || globalTextStyle.color;\n    textStyle.textStroke = getAutoColor(textStyleModel.getShallow('textBorderColor'), opt)\n        || globalTextStyle.textBorderColor;\n    textStyle.textStrokeWidth = retrieve2(\n        textStyleModel.getShallow('textBorderWidth'),\n        globalTextStyle.textBorderWidth\n    );\n\n    // Save original textPosition, because style.textPosition will be repalced by\n    // real location (like [10, 30]) in zrender.\n    textStyle.insideRawTextPosition = textStyle.textPosition;\n\n    if (!isEmphasis) {\n        if (isBlock) {\n            textStyle.insideRollbackOpt = opt;\n            applyDefaultTextStyle(textStyle);\n        }\n\n        // Set default finally.\n        if (textStyle.textFill == null) {\n            textStyle.textFill = opt.autoColor;\n        }\n    }\n\n    // Do not use `getFont` here, because merge should be supported, where\n    // part of these properties may be changed in emphasis style, and the\n    // others should remain their original value got from normal style.\n    textStyle.fontStyle = textStyleModel.getShallow('fontStyle') || globalTextStyle.fontStyle;\n    textStyle.fontWeight = textStyleModel.getShallow('fontWeight') || globalTextStyle.fontWeight;\n    textStyle.fontSize = textStyleModel.getShallow('fontSize') || globalTextStyle.fontSize;\n    textStyle.fontFamily = textStyleModel.getShallow('fontFamily') || globalTextStyle.fontFamily;\n\n    textStyle.textAlign = textStyleModel.getShallow('align');\n    textStyle.textVerticalAlign = textStyleModel.getShallow('verticalAlign')\n        || textStyleModel.getShallow('baseline');\n\n    textStyle.textLineHeight = textStyleModel.getShallow('lineHeight');\n    textStyle.textWidth = textStyleModel.getShallow('width');\n    textStyle.textHeight = textStyleModel.getShallow('height');\n    textStyle.textTag = textStyleModel.getShallow('tag');\n\n    if (!isBlock || !opt.disableBox) {\n        textStyle.textBackgroundColor = getAutoColor(textStyleModel.getShallow('backgroundColor'), opt);\n        textStyle.textPadding = textStyleModel.getShallow('padding');\n        textStyle.textBorderColor = getAutoColor(textStyleModel.getShallow('borderColor'), opt);\n        textStyle.textBorderWidth = textStyleModel.getShallow('borderWidth');\n        textStyle.textBorderRadius = textStyleModel.getShallow('borderRadius');\n\n        textStyle.textBoxShadowColor = textStyleModel.getShallow('shadowColor');\n        textStyle.textBoxShadowBlur = textStyleModel.getShallow('shadowBlur');\n        textStyle.textBoxShadowOffsetX = textStyleModel.getShallow('shadowOffsetX');\n        textStyle.textBoxShadowOffsetY = textStyleModel.getShallow('shadowOffsetY');\n    }\n\n    textStyle.textShadowColor = textStyleModel.getShallow('textShadowColor')\n        || globalTextStyle.textShadowColor;\n    textStyle.textShadowBlur = textStyleModel.getShallow('textShadowBlur')\n        || globalTextStyle.textShadowBlur;\n    textStyle.textShadowOffsetX = textStyleModel.getShallow('textShadowOffsetX')\n        || globalTextStyle.textShadowOffsetX;\n    textStyle.textShadowOffsetY = textStyleModel.getShallow('textShadowOffsetY')\n        || globalTextStyle.textShadowOffsetY;\n}\n\nfunction getAutoColor(color, opt) {\n    return color !== 'auto' ? color : (opt && opt.autoColor) ? opt.autoColor : null;\n}\n\n/**\n * Give some default value to the input `textStyle` object, based on the current settings\n * in this `textStyle` object.\n *\n * The Scenario:\n * when text position is `inside` and `textFill` is not specified, we show\n * text border by default for better view. But it should be considered that text position\n * might be changed when hovering or being emphasis, where the `insideRollback` is used to\n * restore the style.\n *\n * Usage (& NOTICE):\n * When a style object (eithor plain object or instance of `zrender/src/graphic/Style`) is\n * about to be modified on its text related properties, `rollbackDefaultTextStyle` should\n * be called before the modification and `applyDefaultTextStyle` should be called after that.\n * (For the case that all of the text related properties is reset, like `setTextStyleCommon`\n * does, `rollbackDefaultTextStyle` is not needed to be called).\n */\nfunction applyDefaultTextStyle(textStyle) {\n    var opt = textStyle.insideRollbackOpt;\n\n    // Only `insideRollbackOpt` created (in `setTextStyleCommon`),\n    // applyDefaultTextStyle works.\n    if (!opt || textStyle.textFill != null) {\n        return;\n    }\n\n    var useInsideStyle = opt.useInsideStyle;\n    var textPosition = textStyle.insideRawTextPosition;\n    var insideRollback;\n    var autoColor = opt.autoColor;\n\n    if (useInsideStyle !== false\n        && (useInsideStyle === true\n            || (opt.isRectText\n                && textPosition\n                // textPosition can be [10, 30]\n                && typeof textPosition === 'string'\n                && textPosition.indexOf('inside') >= 0\n            )\n        )\n    ) {\n        insideRollback = {\n            textFill: null,\n            textStroke: textStyle.textStroke,\n            textStrokeWidth: textStyle.textStrokeWidth\n        };\n        textStyle.textFill = '#fff';\n        // Consider text with #fff overflow its container.\n        if (textStyle.textStroke == null) {\n            textStyle.textStroke = autoColor;\n            textStyle.textStrokeWidth == null && (textStyle.textStrokeWidth = 2);\n        }\n    }\n    else if (autoColor != null) {\n        insideRollback = {textFill: null};\n        textStyle.textFill = autoColor;\n    }\n\n    // Always set `insideRollback`, for clearing previous.\n    if (insideRollback) {\n        textStyle.insideRollback = insideRollback;\n    }\n}\n\n/**\n * Consider the case: in a scatter,\n * label: {\n *     normal: {position: 'inside'},\n *     emphasis: {position: 'top'}\n * }\n * In the normal state, the `textFill` will be set as '#fff' for pretty view (see\n * `applyDefaultTextStyle`), but when switching to emphasis state, the `textFill`\n * should be retured to 'autoColor', but not keep '#fff'.\n */\nfunction rollbackDefaultTextStyle(style) {\n    var insideRollback = style.insideRollback;\n    if (insideRollback) {\n        style.textFill = insideRollback.textFill;\n        style.textStroke = insideRollback.textStroke;\n        style.textStrokeWidth = insideRollback.textStrokeWidth;\n        style.insideRollback = null;\n    }\n}\n\nfunction getFont(opt, ecModel) {\n    // ecModel or default text style model.\n    var gTextStyleModel = ecModel || ecModel.getModel('textStyle');\n    return trim([\n        // FIXME in node-canvas fontWeight is before fontStyle\n        opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '',\n        opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '',\n        (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px',\n        opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'\n    ].join(' '));\n}\n\nfunction animateOrSetProps(isUpdate, el, props, animatableModel, dataIndex, cb) {\n    if (typeof dataIndex === 'function') {\n        cb = dataIndex;\n        dataIndex = null;\n    }\n    // Do not check 'animation' property directly here. Consider this case:\n    // animation model is an `itemModel`, whose does not have `isAnimationEnabled`\n    // but its parent model (`seriesModel`) does.\n    var animationEnabled = animatableModel && animatableModel.isAnimationEnabled();\n\n    if (animationEnabled) {\n        var postfix = isUpdate ? 'Update' : '';\n        var duration = animatableModel.getShallow('animationDuration' + postfix);\n        var animationEasing = animatableModel.getShallow('animationEasing' + postfix);\n        var animationDelay = animatableModel.getShallow('animationDelay' + postfix);\n        if (typeof animationDelay === 'function') {\n            animationDelay = animationDelay(\n                dataIndex,\n                animatableModel.getAnimationDelayParams\n                    ? animatableModel.getAnimationDelayParams(el, dataIndex)\n                    : null\n            );\n        }\n        if (typeof duration === 'function') {\n            duration = duration(dataIndex);\n        }\n\n        duration > 0\n            ? el.animateTo(props, duration, animationDelay || 0, animationEasing, cb, !!cb)\n            : (el.stopAnimation(), el.attr(props), cb && cb());\n    }\n    else {\n        el.stopAnimation();\n        el.attr(props);\n        cb && cb();\n    }\n}\n\n/**\n * Update graphic element properties with or without animation according to the\n * configuration in series.\n *\n * Caution: this method will stop previous animation.\n * So if do not use this method to one element twice before\n * animation starts, unless you know what you are doing.\n *\n * @param {module:zrender/Element} el\n * @param {Object} props\n * @param {module:echarts/model/Model} [animatableModel]\n * @param {number} [dataIndex]\n * @param {Function} [cb]\n * @example\n *     graphic.updateProps(el, {\n *         position: [100, 100]\n *     }, seriesModel, dataIndex, function () { console.log('Animation done!'); });\n *     // Or\n *     graphic.updateProps(el, {\n *         position: [100, 100]\n *     }, seriesModel, function () { console.log('Animation done!'); });\n */\nfunction updateProps(el, props, animatableModel, dataIndex, cb) {\n    animateOrSetProps(true, el, props, animatableModel, dataIndex, cb);\n}\n\n/**\n * Init graphic element properties with or without animation according to the\n * configuration in series.\n *\n * Caution: this method will stop previous animation.\n * So if do not use this method to one element twice before\n * animation starts, unless you know what you are doing.\n *\n * @param {module:zrender/Element} el\n * @param {Object} props\n * @param {module:echarts/model/Model} [animatableModel]\n * @param {number} [dataIndex]\n * @param {Function} cb\n */\nfunction initProps(el, props, animatableModel, dataIndex, cb) {\n    animateOrSetProps(false, el, props, animatableModel, dataIndex, cb);\n}\n\n/**\n * Get transform matrix of target (param target),\n * in coordinate of its ancestor (param ancestor)\n *\n * @param {module:zrender/mixin/Transformable} target\n * @param {module:zrender/mixin/Transformable} [ancestor]\n */\nfunction getTransform(target, ancestor) {\n    var mat = identity([]);\n\n    while (target && target !== ancestor) {\n        mul$1(mat, target.getLocalTransform(), mat);\n        target = target.parent;\n    }\n\n    return mat;\n}\n\n/**\n * Apply transform to an vertex.\n * @param {Array.<number>} target [x, y]\n * @param {Array.<number>|TypedArray.<number>|Object} transform Can be:\n *      + Transform matrix: like [1, 0, 0, 1, 0, 0]\n *      + {position, rotation, scale}, the same as `zrender/Transformable`.\n * @param {boolean=} invert Whether use invert matrix.\n * @return {Array.<number>} [x, y]\n */\nfunction applyTransform$1(target, transform, invert$$1) {\n    if (transform && !isArrayLike(transform)) {\n        transform = Transformable.getLocalTransform(transform);\n    }\n\n    if (invert$$1) {\n        transform = invert([], transform);\n    }\n    return applyTransform([], target, transform);\n}\n\n/**\n * @param {string} direction 'left' 'right' 'top' 'bottom'\n * @param {Array.<number>} transform Transform matrix: like [1, 0, 0, 1, 0, 0]\n * @param {boolean=} invert Whether use invert matrix.\n * @return {string} Transformed direction. 'left' 'right' 'top' 'bottom'\n */\nfunction transformDirection(direction, transform, invert$$1) {\n\n    // Pick a base, ensure that transform result will not be (0, 0).\n    var hBase = (transform[4] === 0 || transform[5] === 0 || transform[0] === 0)\n        ? 1 : Math.abs(2 * transform[4] / transform[0]);\n    var vBase = (transform[4] === 0 || transform[5] === 0 || transform[2] === 0)\n        ? 1 : Math.abs(2 * transform[4] / transform[2]);\n\n    var vertex = [\n        direction === 'left' ? -hBase : direction === 'right' ? hBase : 0,\n        direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0\n    ];\n\n    vertex = applyTransform$1(vertex, transform, invert$$1);\n\n    return Math.abs(vertex[0]) > Math.abs(vertex[1])\n        ? (vertex[0] > 0 ? 'right' : 'left')\n        : (vertex[1] > 0 ? 'bottom' : 'top');\n}\n\n/**\n * Apply group transition animation from g1 to g2.\n * If no animatableModel, no animation.\n */\nfunction groupTransition(g1, g2, animatableModel, cb) {\n    if (!g1 || !g2) {\n        return;\n    }\n\n    function getElMap(g) {\n        var elMap = {};\n        g.traverse(function (el) {\n            if (!el.isGroup && el.anid) {\n                elMap[el.anid] = el;\n            }\n        });\n        return elMap;\n    }\n    function getAnimatableProps(el) {\n        var obj = {\n            position: clone$1(el.position),\n            rotation: el.rotation\n        };\n        if (el.shape) {\n            obj.shape = extend({}, el.shape);\n        }\n        return obj;\n    }\n    var elMap1 = getElMap(g1);\n\n    g2.traverse(function (el) {\n        if (!el.isGroup && el.anid) {\n            var oldEl = elMap1[el.anid];\n            if (oldEl) {\n                var newProp = getAnimatableProps(el);\n                el.attr(getAnimatableProps(oldEl));\n                updateProps(el, newProp, animatableModel, el.dataIndex);\n            }\n            // else {\n            //     if (el.previousProps) {\n            //         graphic.updateProps\n            //     }\n            // }\n        }\n    });\n}\n\n/**\n * @param {Array.<Array.<number>>} points Like: [[23, 44], [53, 66], ...]\n * @param {Object} rect {x, y, width, height}\n * @return {Array.<Array.<number>>} A new clipped points.\n */\nfunction clipPointsByRect(points, rect) {\n    // FIXME: this way migth be incorrect when grpahic clipped by a corner.\n    // and when element have border.\n    return map(points, function (point) {\n        var x = point[0];\n        x = mathMax$1(x, rect.x);\n        x = mathMin$1(x, rect.x + rect.width);\n        var y = point[1];\n        y = mathMax$1(y, rect.y);\n        y = mathMin$1(y, rect.y + rect.height);\n        return [x, y];\n    });\n}\n\n/**\n * @param {Object} targetRect {x, y, width, height}\n * @param {Object} rect {x, y, width, height}\n * @return {Object} A new clipped rect. If rect size are negative, return undefined.\n */\nfunction clipRectByRect(targetRect, rect) {\n    var x = mathMax$1(targetRect.x, rect.x);\n    var x2 = mathMin$1(targetRect.x + targetRect.width, rect.x + rect.width);\n    var y = mathMax$1(targetRect.y, rect.y);\n    var y2 = mathMin$1(targetRect.y + targetRect.height, rect.y + rect.height);\n\n    // If the total rect is cliped, nothing, including the border,\n    // should be painted. So return undefined.\n    if (x2 >= x && y2 >= y) {\n        return {\n            x: x,\n            y: y,\n            width: x2 - x,\n            height: y2 - y\n        };\n    }\n}\n\n/**\n * @param {string} iconStr Support 'image://' or 'path://' or direct svg path.\n * @param {Object} [opt] Properties of `module:zrender/Element`, except `style`.\n * @param {Object} [rect] {x, y, width, height}\n * @return {module:zrender/Element} Icon path or image element.\n */\nfunction createIcon(iconStr, opt, rect) {\n    opt = extend({rectHover: true}, opt);\n    var style = opt.style = {strokeNoScale: true};\n    rect = rect || {x: -1, y: -1, width: 2, height: 2};\n\n    if (iconStr) {\n        return iconStr.indexOf('image://') === 0\n            ? (\n                style.image = iconStr.slice(8),\n                defaults(style, rect),\n                new ZImage(opt)\n            )\n            : (\n                makePath(\n                    iconStr.replace('path://', ''),\n                    opt,\n                    rect,\n                    'center'\n                )\n            );\n    }\n}\n\n\n\n\nvar graphic = (Object.freeze || Object)({\n\tZ2_EMPHASIS_LIFT: Z2_EMPHASIS_LIFT,\n\textendShape: extendShape,\n\textendPath: extendPath,\n\tmakePath: makePath,\n\tmakeImage: makeImage,\n\tmergePath: mergePath,\n\tresizePath: resizePath,\n\tsubPixelOptimizeLine: subPixelOptimizeLine,\n\tsubPixelOptimizeRect: subPixelOptimizeRect,\n\tsubPixelOptimize: subPixelOptimize,\n\tsetElementHoverStyle: setElementHoverStyle,\n\tisInEmphasis: isInEmphasis,\n\tsetHoverStyle: setHoverStyle,\n\tsetAsHoverStyleTrigger: setAsHoverStyleTrigger,\n\tsetLabelStyle: setLabelStyle,\n\tsetTextStyle: setTextStyle,\n\tsetText: setText,\n\tgetFont: getFont,\n\tupdateProps: updateProps,\n\tinitProps: initProps,\n\tgetTransform: getTransform,\n\tapplyTransform: applyTransform$1,\n\ttransformDirection: transformDirection,\n\tgroupTransition: groupTransition,\n\tclipPointsByRect: clipPointsByRect,\n\tclipRectByRect: clipRectByRect,\n\tcreateIcon: createIcon,\n\tGroup: Group,\n\tImage: ZImage,\n\tText: Text,\n\tCircle: Circle,\n\tSector: Sector,\n\tRing: Ring,\n\tPolygon: Polygon,\n\tPolyline: Polyline,\n\tRect: Rect,\n\tLine: Line,\n\tBezierCurve: BezierCurve,\n\tArc: Arc,\n\tIncrementalDisplayable: IncrementalDisplayble,\n\tCompoundPath: CompoundPath,\n\tLinearGradient: LinearGradient,\n\tRadialGradient: RadialGradient,\n\tBoundingRect: BoundingRect\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PATH_COLOR = ['textStyle', 'color'];\n\nvar textStyleMixin = {\n    /**\n     * Get color property or get color from option.textStyle.color\n     * @param {boolean} [isEmphasis]\n     * @return {string}\n     */\n    getTextColor: function (isEmphasis) {\n        var ecModel = this.ecModel;\n        return this.getShallow('color')\n            || (\n                (!isEmphasis && ecModel) ? ecModel.get(PATH_COLOR) : null\n            );\n    },\n\n    /**\n     * Create font string from fontStyle, fontWeight, fontSize, fontFamily\n     * @return {string}\n     */\n    getFont: function () {\n        return getFont({\n            fontStyle: this.getShallow('fontStyle'),\n            fontWeight: this.getShallow('fontWeight'),\n            fontSize: this.getShallow('fontSize'),\n            fontFamily: this.getShallow('fontFamily')\n        }, this.ecModel);\n    },\n\n    getTextRect: function (text) {\n        return getBoundingRect(\n            text,\n            this.getFont(),\n            this.getShallow('align'),\n            this.getShallow('verticalAlign') || this.getShallow('baseline'),\n            this.getShallow('padding'),\n            this.getShallow('lineHeight'),\n            this.getShallow('rich'),\n            this.getShallow('truncateText')\n        );\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getItemStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['stroke', 'borderColor'],\n        ['lineWidth', 'borderWidth'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor'],\n        ['textPosition'],\n        ['textAlign']\n    ]\n);\n\nvar itemStyleMixin = {\n    getItemStyle: function (excludes, includes) {\n        var style = getItemStyle(this, excludes, includes);\n        var lineDash = this.getBorderLineDash();\n        lineDash && (style.lineDash = lineDash);\n        return style;\n    },\n\n    getBorderLineDash: function () {\n        var lineType = this.get('borderType');\n        return (lineType === 'solid' || lineType == null) ? null\n            : (lineType === 'dashed' ? [5, 5] : [1, 1]);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/model/Model\n */\n\nvar mixin$1 = mixin;\nvar inner = makeInner();\n\n/**\n * @alias module:echarts/model/Model\n * @constructor\n * @param {Object} [option]\n * @param {module:echarts/model/Model} [parentModel]\n * @param {module:echarts/model/Global} [ecModel]\n */\nfunction Model(option, parentModel, ecModel) {\n    /**\n     * @type {module:echarts/model/Model}\n     * @readOnly\n     */\n    this.parentModel = parentModel;\n\n    /**\n     * @type {module:echarts/model/Global}\n     * @readOnly\n     */\n    this.ecModel = ecModel;\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    this.option = option;\n\n    // Simple optimization\n    // if (this.init) {\n    //     if (arguments.length <= 4) {\n    //         this.init(option, parentModel, ecModel, extraOpt);\n    //     }\n    //     else {\n    //         this.init.apply(this, arguments);\n    //     }\n    // }\n}\n\nModel.prototype = {\n\n    constructor: Model,\n\n    /**\n     * Model 的初始化函数\n     * @param {Object} option\n     */\n    init: null,\n\n    /**\n     * 从新的 Option merge\n     */\n    mergeOption: function (option) {\n        merge(this.option, option, true);\n    },\n\n    /**\n     * @param {string|Array.<string>} path\n     * @param {boolean} [ignoreParent=false]\n     * @return {*}\n     */\n    get: function (path, ignoreParent) {\n        if (path == null) {\n            return this.option;\n        }\n\n        return doGet(\n            this.option,\n            this.parsePath(path),\n            !ignoreParent && getParent(this, path)\n        );\n    },\n\n    /**\n     * @param {string} key\n     * @param {boolean} [ignoreParent=false]\n     * @return {*}\n     */\n    getShallow: function (key, ignoreParent) {\n        var option = this.option;\n\n        var val = option == null ? option : option[key];\n        var parentModel = !ignoreParent && getParent(this, key);\n        if (val == null && parentModel) {\n            val = parentModel.getShallow(key);\n        }\n        return val;\n    },\n\n    /**\n     * @param {string|Array.<string>} [path]\n     * @param {module:echarts/model/Model} [parentModel]\n     * @return {module:echarts/model/Model}\n     */\n    getModel: function (path, parentModel) {\n        var obj = path == null\n            ? this.option\n            : doGet(this.option, path = this.parsePath(path));\n\n        var thisParentModel;\n        parentModel = parentModel || (\n            (thisParentModel = getParent(this, path))\n                && thisParentModel.getModel(path)\n        );\n\n        return new Model(obj, parentModel, this.ecModel);\n    },\n\n    /**\n     * If model has option\n     */\n    isEmpty: function () {\n        return this.option == null;\n    },\n\n    restoreData: function () {},\n\n    // Pending\n    clone: function () {\n        var Ctor = this.constructor;\n        return new Ctor(clone(this.option));\n    },\n\n    setReadOnly: function (properties) {\n        // clazzUtil.setReadOnly(this, properties);\n    },\n\n    // If path is null/undefined, return null/undefined.\n    parsePath: function (path) {\n        if (typeof path === 'string') {\n            path = path.split('.');\n        }\n        return path;\n    },\n\n    /**\n     * @param {Function} getParentMethod\n     *        param {Array.<string>|string} path\n     *        return {module:echarts/model/Model}\n     */\n    customizeGetParent: function (getParentMethod) {\n        inner(this).getParent = getParentMethod;\n    },\n\n    isAnimationEnabled: function () {\n        if (!env$1.node) {\n            if (this.option.animation != null) {\n                return !!this.option.animation;\n            }\n            else if (this.parentModel) {\n                return this.parentModel.isAnimationEnabled();\n            }\n        }\n    }\n\n};\n\nfunction doGet(obj, pathArr, parentModel) {\n    for (var i = 0; i < pathArr.length; i++) {\n        // Ignore empty\n        if (!pathArr[i]) {\n            continue;\n        }\n        // obj could be number/string/... (like 0)\n        obj = (obj && typeof obj === 'object') ? obj[pathArr[i]] : null;\n        if (obj == null) {\n            break;\n        }\n    }\n    if (obj == null && parentModel) {\n        obj = parentModel.get(pathArr);\n    }\n    return obj;\n}\n\n// `path` can be null/undefined\nfunction getParent(model, path) {\n    var getParentMethod = inner(model).getParent;\n    return getParentMethod ? getParentMethod.call(model, path) : model.parentModel;\n}\n\n// Enable Model.extend.\nenableClassExtend(Model);\nenableClassCheck(Model);\n\nmixin$1(Model, lineStyleMixin);\nmixin$1(Model, areaStyleMixin);\nmixin$1(Model, textStyleMixin);\nmixin$1(Model, itemStyleMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar base = 0;\n\n/**\n * @public\n * @param {string} type\n * @return {string}\n */\nfunction getUID(type) {\n    // Considering the case of crossing js context,\n    // use Math.random to make id as unique as possible.\n    return [(type || ''), base++, Math.random().toFixed(5)].join('_');\n}\n\n/**\n * @inner\n */\nfunction enableSubTypeDefaulter(entity) {\n\n    var subTypeDefaulters = {};\n\n    entity.registerSubTypeDefaulter = function (componentType, defaulter) {\n        componentType = parseClassType$1(componentType);\n        subTypeDefaulters[componentType.main] = defaulter;\n    };\n\n    entity.determineSubType = function (componentType, option) {\n        var type = option.type;\n        if (!type) {\n            var componentTypeMain = parseClassType$1(componentType).main;\n            if (entity.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) {\n                type = subTypeDefaulters[componentTypeMain](option);\n            }\n        }\n        return type;\n    };\n\n    return entity;\n}\n\n/**\n * Topological travel on Activity Network (Activity On Vertices).\n * Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis'].\n *\n * If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology.\n *\n * If there is circle dependencey, Error will be thrown.\n *\n */\nfunction enableTopologicalTravel(entity, dependencyGetter) {\n\n    /**\n     * @public\n     * @param {Array.<string>} targetNameList Target Component type list.\n     *                                           Can be ['aa', 'bb', 'aa.xx']\n     * @param {Array.<string>} fullNameList By which we can build dependency graph.\n     * @param {Function} callback Params: componentType, dependencies.\n     * @param {Object} context Scope of callback.\n     */\n    entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) {\n        if (!targetNameList.length) {\n            return;\n        }\n\n        var result = makeDepndencyGraph(fullNameList);\n        var graph = result.graph;\n        var stack = result.noEntryList;\n\n        var targetNameSet = {};\n        each$1(targetNameList, function (name) {\n            targetNameSet[name] = true;\n        });\n\n        while (stack.length) {\n            var currComponentType = stack.pop();\n            var currVertex = graph[currComponentType];\n            var isInTargetNameSet = !!targetNameSet[currComponentType];\n            if (isInTargetNameSet) {\n                callback.call(context, currComponentType, currVertex.originalDeps.slice());\n                delete targetNameSet[currComponentType];\n            }\n            each$1(\n                currVertex.successor,\n                isInTargetNameSet ? removeEdgeAndAdd : removeEdge\n            );\n        }\n\n        each$1(targetNameSet, function () {\n            throw new Error('Circle dependency may exists');\n        });\n\n        function removeEdge(succComponentType) {\n            graph[succComponentType].entryCount--;\n            if (graph[succComponentType].entryCount === 0) {\n                stack.push(succComponentType);\n            }\n        }\n\n        // Consider this case: legend depends on series, and we call\n        // chart.setOption({series: [...]}), where only series is in option.\n        // If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will\n        // not be called, but only sereis.mergeOption is called. Thus legend\n        // have no chance to update its local record about series (like which\n        // name of series is available in legend).\n        function removeEdgeAndAdd(succComponentType) {\n            targetNameSet[succComponentType] = true;\n            removeEdge(succComponentType);\n        }\n    };\n\n    /**\n     * DepndencyGraph: {Object}\n     * key: conponentType,\n     * value: {\n     *     successor: [conponentTypes...],\n     *     originalDeps: [conponentTypes...],\n     *     entryCount: {number}\n     * }\n     */\n    function makeDepndencyGraph(fullNameList) {\n        var graph = {};\n        var noEntryList = [];\n\n        each$1(fullNameList, function (name) {\n\n            var thisItem = createDependencyGraphItem(graph, name);\n            var originalDeps = thisItem.originalDeps = dependencyGetter(name);\n\n            var availableDeps = getAvailableDependencies(originalDeps, fullNameList);\n            thisItem.entryCount = availableDeps.length;\n            if (thisItem.entryCount === 0) {\n                noEntryList.push(name);\n            }\n\n            each$1(availableDeps, function (dependentName) {\n                if (indexOf(thisItem.predecessor, dependentName) < 0) {\n                    thisItem.predecessor.push(dependentName);\n                }\n                var thatItem = createDependencyGraphItem(graph, dependentName);\n                if (indexOf(thatItem.successor, dependentName) < 0) {\n                    thatItem.successor.push(name);\n                }\n            });\n        });\n\n        return {graph: graph, noEntryList: noEntryList};\n    }\n\n    function createDependencyGraphItem(graph, name) {\n        if (!graph[name]) {\n            graph[name] = {predecessor: [], successor: []};\n        }\n        return graph[name];\n    }\n\n    function getAvailableDependencies(originalDeps, fullNameList) {\n        var availableDeps = [];\n        each$1(originalDeps, function (dep) {\n            indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep);\n        });\n        return availableDeps;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The method \"quantile\" was copied from \"d3.js\".\n* (See more details in the comment of the method below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\nvar RADIAN_EPSILON = 1e-4;\n\nfunction _trim(str) {\n    return str.replace(/^\\s+/, '').replace(/\\s+$/, '');\n}\n\n/**\n * Linear mapping a value from domain to range\n * @memberOf module:echarts/util/number\n * @param  {(number|Array.<number>)} val\n * @param  {Array.<number>} domain Domain extent domain[0] can be bigger than domain[1]\n * @param  {Array.<number>} range  Range extent range[0] can be bigger than range[1]\n * @param  {boolean} clamp\n * @return {(number|Array.<number>}\n */\nfunction linearMap(val, domain, range, clamp) {\n    var subDomain = domain[1] - domain[0];\n    var subRange = range[1] - range[0];\n\n    if (subDomain === 0) {\n        return subRange === 0\n            ? range[0]\n            : (range[0] + range[1]) / 2;\n    }\n\n    // Avoid accuracy problem in edge, such as\n    // 146.39 - 62.83 === 83.55999999999999.\n    // See echarts/test/ut/spec/util/number.js#linearMap#accuracyError\n    // It is a little verbose for efficiency considering this method\n    // is a hotspot.\n    if (clamp) {\n        if (subDomain > 0) {\n            if (val <= domain[0]) {\n                return range[0];\n            }\n            else if (val >= domain[1]) {\n                return range[1];\n            }\n        }\n        else {\n            if (val >= domain[0]) {\n                return range[0];\n            }\n            else if (val <= domain[1]) {\n                return range[1];\n            }\n        }\n    }\n    else {\n        if (val === domain[0]) {\n            return range[0];\n        }\n        if (val === domain[1]) {\n            return range[1];\n        }\n    }\n\n    return (val - domain[0]) / subDomain * subRange + range[0];\n}\n\n/**\n * Convert a percent string to absolute number.\n * Returns NaN if percent is not a valid string or number\n * @memberOf module:echarts/util/number\n * @param {string|number} percent\n * @param {number} all\n * @return {number}\n */\nfunction parsePercent$1(percent, all) {\n    switch (percent) {\n        case 'center':\n        case 'middle':\n            percent = '50%';\n            break;\n        case 'left':\n        case 'top':\n            percent = '0%';\n            break;\n        case 'right':\n        case 'bottom':\n            percent = '100%';\n            break;\n    }\n    if (typeof percent === 'string') {\n        if (_trim(percent).match(/%$/)) {\n            return parseFloat(percent) / 100 * all;\n        }\n\n        return parseFloat(percent);\n    }\n\n    return percent == null ? NaN : +percent;\n}\n\n/**\n * (1) Fix rounding error of float numbers.\n * (2) Support return string to avoid scientific notation like '3.5e-7'.\n *\n * @param {number} x\n * @param {number} [precision]\n * @param {boolean} [returnStr]\n * @return {number|string}\n */\nfunction round$2(x, precision, returnStr) {\n    if (precision == null) {\n        precision = 10;\n    }\n    // Avoid range error\n    precision = Math.min(Math.max(0, precision), 20);\n    x = (+x).toFixed(precision);\n    return returnStr ? x : +x;\n}\n\nfunction asc(arr) {\n    arr.sort(function (a, b) {\n        return a - b;\n    });\n    return arr;\n}\n\n/**\n * Get precision\n * @param {number} val\n */\nfunction getPrecision(val) {\n    val = +val;\n    if (isNaN(val)) {\n        return 0;\n    }\n    // It is much faster than methods converting number to string as follows\n    //      var tmp = val.toString();\n    //      return tmp.length - 1 - tmp.indexOf('.');\n    // especially when precision is low\n    var e = 1;\n    var count = 0;\n    while (Math.round(val * e) / e !== val) {\n        e *= 10;\n        count++;\n    }\n    return count;\n}\n\n/**\n * @param {string|number} val\n * @return {number}\n */\nfunction getPrecisionSafe(val) {\n    var str = val.toString();\n\n    // Consider scientific notation: '3.4e-12' '3.4e+12'\n    var eIndex = str.indexOf('e');\n    if (eIndex > 0) {\n        var precision = +str.slice(eIndex + 1);\n        return precision < 0 ? -precision : 0;\n    }\n    else {\n        var dotIndex = str.indexOf('.');\n        return dotIndex < 0 ? 0 : str.length - 1 - dotIndex;\n    }\n}\n\n/**\n * Minimal dicernible data precisioin according to a single pixel.\n *\n * @param {Array.<number>} dataExtent\n * @param {Array.<number>} pixelExtent\n * @return {number} precision\n */\nfunction getPixelPrecision(dataExtent, pixelExtent) {\n    var log = Math.log;\n    var LN10 = Math.LN10;\n    var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10);\n    var sizeQuantity = Math.round(log(Math.abs(pixelExtent[1] - pixelExtent[0])) / LN10);\n    // toFixed() digits argument must be between 0 and 20.\n    var precision = Math.min(Math.max(-dataQuantity + sizeQuantity, 0), 20);\n    return !isFinite(precision) ? 20 : precision;\n}\n\n/**\n * Get a data of given precision, assuring the sum of percentages\n * in valueList is 1.\n * The largest remainer method is used.\n * https://en.wikipedia.org/wiki/Largest_remainder_method\n *\n * @param {Array.<number>} valueList a list of all data\n * @param {number} idx index of the data to be processed in valueList\n * @param {number} precision integer number showing digits of precision\n * @return {number} percent ranging from 0 to 100\n */\nfunction getPercentWithPrecision(valueList, idx, precision) {\n    if (!valueList[idx]) {\n        return 0;\n    }\n\n    var sum = reduce(valueList, function (acc, val) {\n        return acc + (isNaN(val) ? 0 : val);\n    }, 0);\n    if (sum === 0) {\n        return 0;\n    }\n\n    var digits = Math.pow(10, precision);\n    var votesPerQuota = map(valueList, function (val) {\n        return (isNaN(val) ? 0 : val) / sum * digits * 100;\n    });\n    var targetSeats = digits * 100;\n\n    var seats = map(votesPerQuota, function (votes) {\n        // Assign automatic seats.\n        return Math.floor(votes);\n    });\n    var currentSum = reduce(seats, function (acc, val) {\n        return acc + val;\n    }, 0);\n\n    var remainder = map(votesPerQuota, function (votes, idx) {\n        return votes - seats[idx];\n    });\n\n    // Has remainding votes.\n    while (currentSum < targetSeats) {\n        // Find next largest remainder.\n        var max = Number.NEGATIVE_INFINITY;\n        var maxId = null;\n        for (var i = 0, len = remainder.length; i < len; ++i) {\n            if (remainder[i] > max) {\n                max = remainder[i];\n                maxId = i;\n            }\n        }\n\n        // Add a vote to max remainder.\n        ++seats[maxId];\n        remainder[maxId] = 0;\n        ++currentSum;\n    }\n\n    return seats[idx] / digits;\n}\n\n// Number.MAX_SAFE_INTEGER, ie do not support.\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * To 0 - 2 * PI, considering negative radian.\n * @param {number} radian\n * @return {number}\n */\nfunction remRadian(radian) {\n    var pi2 = Math.PI * 2;\n    return (radian % pi2 + pi2) % pi2;\n}\n\n/**\n * @param {type} radian\n * @return {boolean}\n */\nfunction isRadianAroundZero(val) {\n    return val > -RADIAN_EPSILON && val < RADIAN_EPSILON;\n}\n\n/* eslint-disable */\nvar TIME_REG = /^(?:(\\d{4})(?:[-\\/](\\d{1,2})(?:[-\\/](\\d{1,2})(?:[T ](\\d{1,2})(?::(\\d\\d)(?::(\\d\\d)(?:[.,](\\d+))?)?)?(Z|[\\+\\-]\\d\\d:?\\d\\d)?)?)?)?)?$/; // jshint ignore:line\n/* eslint-enable */\n\n/**\n * @param {string|Date|number} value These values can be accepted:\n *   + An instance of Date, represent a time in its own time zone.\n *   + Or string in a subset of ISO 8601, only including:\n *     + only year, month, date: '2012-03', '2012-03-01', '2012-03-01 05', '2012-03-01 05:06',\n *     + separated with T or space: '2012-03-01T12:22:33.123', '2012-03-01 12:22:33.123',\n *     + time zone: '2012-03-01T12:22:33Z', '2012-03-01T12:22:33+8000', '2012-03-01T12:22:33-05:00',\n *     all of which will be treated as local time if time zone is not specified\n *     (see <https://momentjs.com/>).\n *   + Or other string format, including (all of which will be treated as loacal time):\n *     '2012', '2012-3-1', '2012/3/1', '2012/03/01',\n *     '2009/6/12 2:00', '2009/6/12 2:05:08', '2009/6/12 2:05:08.123'\n *   + a timestamp, which represent a time in UTC.\n * @return {Date} date\n */\nfunction parseDate(value) {\n    if (value instanceof Date) {\n        return value;\n    }\n    else if (typeof value === 'string') {\n        // Different browsers parse date in different way, so we parse it manually.\n        // Some other issues:\n        // new Date('1970-01-01') is UTC,\n        // new Date('1970/01/01') and new Date('1970-1-01') is local.\n        // See issue #3623\n        var match = TIME_REG.exec(value);\n\n        if (!match) {\n            // return Invalid Date.\n            return new Date(NaN);\n        }\n\n        // Use local time when no timezone offset specifed.\n        if (!match[8]) {\n            // match[n] can only be string or undefined.\n            // But take care of '12' + 1 => '121'.\n            return new Date(\n                +match[1],\n                +(match[2] || 1) - 1,\n                +match[3] || 1,\n                +match[4] || 0,\n                +(match[5] || 0),\n                +match[6] || 0,\n                +match[7] || 0\n            );\n        }\n        // Timezoneoffset of Javascript Date has considered DST (Daylight Saving Time,\n        // https://tc39.github.io/ecma262/#sec-daylight-saving-time-adjustment).\n        // For example, system timezone is set as \"Time Zone: America/Toronto\",\n        // then these code will get different result:\n        // `new Date(1478411999999).getTimezoneOffset();  // get 240`\n        // `new Date(1478412000000).getTimezoneOffset();  // get 300`\n        // So we should not use `new Date`, but use `Date.UTC`.\n        else {\n            var hour = +match[4] || 0;\n            if (match[8].toUpperCase() !== 'Z') {\n                hour -= match[8].slice(0, 3);\n            }\n            return new Date(Date.UTC(\n                +match[1],\n                +(match[2] || 1) - 1,\n                +match[3] || 1,\n                hour,\n                +(match[5] || 0),\n                +match[6] || 0,\n                +match[7] || 0\n            ));\n        }\n    }\n    else if (value == null) {\n        return new Date(NaN);\n    }\n\n    return new Date(Math.round(value));\n}\n\n/**\n * Quantity of a number. e.g. 0.1, 1, 10, 100\n *\n * @param  {number} val\n * @return {number}\n */\nfunction quantity(val) {\n    return Math.pow(10, quantityExponent(val));\n}\n\nfunction quantityExponent(val) {\n    return Math.floor(Math.log(val) / Math.LN10);\n}\n\n/**\n * find a “nice” number approximately equal to x. Round the number if round = true,\n * take ceiling if round = false. The primary observation is that the “nicest”\n * numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers.\n *\n * See \"Nice Numbers for Graph Labels\" of Graphic Gems.\n *\n * @param  {number} val Non-negative value.\n * @param  {boolean} round\n * @return {number}\n */\nfunction nice(val, round) {\n    var exponent = quantityExponent(val);\n    var exp10 = Math.pow(10, exponent);\n    var f = val / exp10; // 1 <= f < 10\n    var nf;\n    if (round) {\n        if (f < 1.5) {\n            nf = 1;\n        }\n        else if (f < 2.5) {\n            nf = 2;\n        }\n        else if (f < 4) {\n            nf = 3;\n        }\n        else if (f < 7) {\n            nf = 5;\n        }\n        else {\n            nf = 10;\n        }\n    }\n    else {\n        if (f < 1) {\n            nf = 1;\n        }\n        else if (f < 2) {\n            nf = 2;\n        }\n        else if (f < 3) {\n            nf = 3;\n        }\n        else if (f < 5) {\n            nf = 5;\n        }\n        else {\n            nf = 10;\n        }\n    }\n    val = nf * exp10;\n\n    // Fix 3 * 0.1 === 0.30000000000000004 issue (see IEEE 754).\n    // 20 is the uppper bound of toFixed.\n    return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val;\n}\n\n/**\n * This code was copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/9cc9a875e636a1dcf36cc1e07bdf77e1ad6e2c74/src/arrays/quantile.js>.\n * See the license statement at the head of this file.\n * @param {Array.<number>} ascArr\n */\nfunction quantile(ascArr, p) {\n    var H = (ascArr.length - 1) * p + 1;\n    var h = Math.floor(H);\n    var v = +ascArr[h - 1];\n    var e = H - h;\n    return e ? v + e * (ascArr[h] - v) : v;\n}\n\n/**\n * Order intervals asc, and split them when overlap.\n * expect(numberUtil.reformIntervals([\n *     {interval: [18, 62], close: [1, 1]},\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [1, 1]},\n *     {interval: [62, 150], close: [1, 1]},\n *     {interval: [106, 150], close: [1, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ])).toEqual([\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [0, 1]},\n *     {interval: [18, 62], close: [0, 1]},\n *     {interval: [62, 150], close: [0, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ]);\n * @param {Array.<Object>} list, where `close` mean open or close\n *        of the interval, and Infinity can be used.\n * @return {Array.<Object>} The origin list, which has been reformed.\n */\nfunction reformIntervals(list) {\n    list.sort(function (a, b) {\n        return littleThan(a, b, 0) ? -1 : 1;\n    });\n\n    var curr = -Infinity;\n    var currClose = 1;\n    for (var i = 0; i < list.length;) {\n        var interval = list[i].interval;\n        var close = list[i].close;\n\n        for (var lg = 0; lg < 2; lg++) {\n            if (interval[lg] <= curr) {\n                interval[lg] = curr;\n                close[lg] = !lg ? 1 - currClose : 1;\n            }\n            curr = interval[lg];\n            currClose = close[lg];\n        }\n\n        if (interval[0] === interval[1] && close[0] * close[1] !== 1) {\n            list.splice(i, 1);\n        }\n        else {\n            i++;\n        }\n    }\n\n    return list;\n\n    function littleThan(a, b, lg) {\n        return a.interval[lg] < b.interval[lg]\n            || (\n                a.interval[lg] === b.interval[lg]\n                && (\n                    (a.close[lg] - b.close[lg] === (!lg ? 1 : -1))\n                    || (!lg && littleThan(a, b, 1))\n                )\n            );\n    }\n}\n\n/**\n * parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n * ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n * subtraction forces infinities to NaN\n *\n * @param {*} v\n * @return {boolean}\n */\nfunction isNumeric(v) {\n    return v - parseFloat(v) >= 0;\n}\n\n\nvar number = (Object.freeze || Object)({\n\tlinearMap: linearMap,\n\tparsePercent: parsePercent$1,\n\tround: round$2,\n\tasc: asc,\n\tgetPrecision: getPrecision,\n\tgetPrecisionSafe: getPrecisionSafe,\n\tgetPixelPrecision: getPixelPrecision,\n\tgetPercentWithPrecision: getPercentWithPrecision,\n\tMAX_SAFE_INTEGER: MAX_SAFE_INTEGER,\n\tremRadian: remRadian,\n\tisRadianAroundZero: isRadianAroundZero,\n\tparseDate: parseDate,\n\tquantity: quantity,\n\tnice: nice,\n\tquantile: quantile,\n\treformIntervals: reformIntervals,\n\tisNumeric: isNumeric\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import Text from 'zrender/src/graphic/Text';\n\n/**\n * 每三位默认加,格式化\n * @param {string|number} x\n * @return {string}\n */\nfunction addCommas(x) {\n    if (isNaN(x)) {\n        return '-';\n    }\n    x = (x + '').split('.');\n    return x[0].replace(/(\\d{1,3})(?=(?:\\d{3})+(?!\\d))/g, '$1,')\n            + (x.length > 1 ? ('.' + x[1]) : '');\n}\n\n/**\n * @param {string} str\n * @param {boolean} [upperCaseFirst=false]\n * @return {string} str\n */\nfunction toCamelCase(str, upperCaseFirst) {\n    str = (str || '').toLowerCase().replace(/-(.)/g, function (match, group1) {\n        return group1.toUpperCase();\n    });\n\n    if (upperCaseFirst && str) {\n        str = str.charAt(0).toUpperCase() + str.slice(1);\n    }\n\n    return str;\n}\n\nvar normalizeCssArray$1 = normalizeCssArray;\n\n\nvar replaceReg = /([&<>\"'])/g;\nvar replaceMap = {\n    '&': '&amp;',\n    '<': '&lt;',\n    '>': '&gt;',\n    '\"': '&quot;',\n    '\\'': '&#39;'\n};\n\nfunction encodeHTML(source) {\n    return source == null\n        ? ''\n        : (source + '').replace(replaceReg, function (str, c) {\n            return replaceMap[c];\n        });\n}\n\nvar TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];\n\nvar wrapVar = function (varName, seriesIdx) {\n    return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}';\n};\n\n/**\n * Template formatter\n * @param {string} tpl\n * @param {Array.<Object>|Object} paramsList\n * @param {boolean} [encode=false]\n * @return {string}\n */\nfunction formatTpl(tpl, paramsList, encode) {\n    if (!isArray(paramsList)) {\n        paramsList = [paramsList];\n    }\n    var seriesLen = paramsList.length;\n    if (!seriesLen) {\n        return '';\n    }\n\n    var $vars = paramsList[0].$vars || [];\n    for (var i = 0; i < $vars.length; i++) {\n        var alias = TPL_VAR_ALIAS[i];\n        tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0));\n    }\n    for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) {\n        for (var k = 0; k < $vars.length; k++) {\n            var val = paramsList[seriesIdx][$vars[k]];\n            tpl = tpl.replace(\n                wrapVar(TPL_VAR_ALIAS[k], seriesIdx),\n                encode ? encodeHTML(val) : val\n            );\n        }\n    }\n\n    return tpl;\n}\n\n/**\n * simple Template formatter\n *\n * @param {string} tpl\n * @param {Object} param\n * @param {boolean} [encode=false]\n * @return {string}\n */\nfunction formatTplSimple(tpl, param, encode) {\n    each$1(param, function (value, key) {\n        tpl = tpl.replace(\n            '{' + key + '}',\n            encode ? encodeHTML(value) : value\n        );\n    });\n    return tpl;\n}\n\n/**\n * @param {Object|string} [opt] If string, means color.\n * @param {string} [opt.color]\n * @param {string} [opt.extraCssText]\n * @param {string} [opt.type='item'] 'item' or 'subItem'\n * @param {string} [opt.renderMode='html'] render mode of tooltip, 'html' or 'richText'\n * @param {string} [opt.markerId='X'] id name for marker. If only one marker is in a rich text, this can be omitted.\n * @return {string}\n */\nfunction getTooltipMarker(opt, extraCssText) {\n    opt = isString(opt) ? {color: opt, extraCssText: extraCssText} : (opt || {});\n    var color = opt.color;\n    var type = opt.type;\n    var extraCssText = opt.extraCssText;\n    var renderMode = opt.renderMode || 'html';\n    var markerId = opt.markerId || 'X';\n\n    if (!color) {\n        return '';\n    }\n\n    if (renderMode === 'html') {\n        return type === 'subItem'\n        ? '<span style=\"display:inline-block;vertical-align:middle;margin-right:8px;margin-left:3px;'\n            + 'border-radius:4px;width:4px;height:4px;background-color:'\n            + encodeHTML(color) + ';' + (extraCssText || '') + '\"></span>'\n        : '<span style=\"display:inline-block;margin-right:5px;'\n            + 'border-radius:10px;width:10px;height:10px;background-color:'\n            + encodeHTML(color) + ';' + (extraCssText || '') + '\"></span>';\n    }\n    else {\n        // Space for rich element marker\n        return {\n            renderMode: renderMode,\n            content: '{marker' + markerId + '|}  ',\n            style: {\n                color: color\n            }\n        };\n    }\n}\n\nfunction pad(str, len) {\n    str += '';\n    return '0000'.substr(0, len - str.length) + str;\n}\n\n\n/**\n * ISO Date format\n * @param {string} tpl\n * @param {number} value\n * @param {boolean} [isUTC=false] Default in local time.\n *           see `module:echarts/scale/Time`\n *           and `module:echarts/util/number#parseDate`.\n * @inner\n */\nfunction formatTime(tpl, value, isUTC) {\n    if (tpl === 'week'\n        || tpl === 'month'\n        || tpl === 'quarter'\n        || tpl === 'half-year'\n        || tpl === 'year'\n    ) {\n        tpl = 'MM-dd\\nyyyy';\n    }\n\n    var date = parseDate(value);\n    var utc = isUTC ? 'UTC' : '';\n    var y = date['get' + utc + 'FullYear']();\n    var M = date['get' + utc + 'Month']() + 1;\n    var d = date['get' + utc + 'Date']();\n    var h = date['get' + utc + 'Hours']();\n    var m = date['get' + utc + 'Minutes']();\n    var s = date['get' + utc + 'Seconds']();\n    var S = date['get' + utc + 'Milliseconds']();\n\n    tpl = tpl.replace('MM', pad(M, 2))\n        .replace('M', M)\n        .replace('yyyy', y)\n        .replace('yy', y % 100)\n        .replace('dd', pad(d, 2))\n        .replace('d', d)\n        .replace('hh', pad(h, 2))\n        .replace('h', h)\n        .replace('mm', pad(m, 2))\n        .replace('m', m)\n        .replace('ss', pad(s, 2))\n        .replace('s', s)\n        .replace('SSS', pad(S, 3));\n\n    return tpl;\n}\n\n/**\n * Capital first\n * @param {string} str\n * @return {string}\n */\nfunction capitalFirst(str) {\n    return str ? str.charAt(0).toUpperCase() + str.substr(1) : str;\n}\n\nvar truncateText$1 = truncateText;\n\n/**\n * @public\n * @param {Object} opt\n * @param {string} opt.text\n * @param {string} opt.font\n * @param {string} [opt.textAlign='left']\n * @param {string} [opt.textVerticalAlign='top']\n * @param {Array.<number>} [opt.textPadding]\n * @param {number} [opt.textLineHeight]\n * @param {Object} [opt.rich]\n * @param {Object} [opt.truncate]\n * @return {Object} {x, y, width, height, lineHeight}\n */\nfunction getTextBoundingRect(opt) {\n    return getBoundingRect(\n        opt.text,\n        opt.font,\n        opt.textAlign,\n        opt.textVerticalAlign,\n        opt.textPadding,\n        opt.textLineHeight,\n        opt.rich,\n        opt.truncate\n    );\n}\n\n/**\n * @deprecated\n * the `textLineHeight` was added later.\n * For backward compatiblility, put it as the last parameter.\n * But deprecated this interface. Please use `getTextBoundingRect` instead.\n */\nfunction getTextRect(\n    text, font, textAlign, textVerticalAlign, textPadding, rich, truncate, textLineHeight\n) {\n    return getBoundingRect(\n        text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate\n    );\n}\n\n\nvar format = (Object.freeze || Object)({\n\taddCommas: addCommas,\n\ttoCamelCase: toCamelCase,\n\tnormalizeCssArray: normalizeCssArray$1,\n\tencodeHTML: encodeHTML,\n\tformatTpl: formatTpl,\n\tformatTplSimple: formatTplSimple,\n\tgetTooltipMarker: getTooltipMarker,\n\tformatTime: formatTime,\n\tcapitalFirst: capitalFirst,\n\ttruncateText: truncateText$1,\n\tgetTextBoundingRect: getTextBoundingRect,\n\tgetTextRect: getTextRect\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Layout helpers for each component positioning\n\nvar each$3 = each$1;\n\n/**\n * @public\n */\nvar LOCATION_PARAMS = [\n    'left', 'right', 'top', 'bottom', 'width', 'height'\n];\n\n/**\n * @public\n */\nvar HV_NAMES = [\n    ['width', 'left', 'right'],\n    ['height', 'top', 'bottom']\n];\n\nfunction boxLayout(orient, group, gap, maxWidth, maxHeight) {\n    var x = 0;\n    var y = 0;\n\n    if (maxWidth == null) {\n        maxWidth = Infinity;\n    }\n    if (maxHeight == null) {\n        maxHeight = Infinity;\n    }\n    var currentLineMaxSize = 0;\n\n    group.eachChild(function (child, idx) {\n        var position = child.position;\n        var rect = child.getBoundingRect();\n        var nextChild = group.childAt(idx + 1);\n        var nextChildRect = nextChild && nextChild.getBoundingRect();\n        var nextX;\n        var nextY;\n\n        if (orient === 'horizontal') {\n            var moveX = rect.width + (nextChildRect ? (-nextChildRect.x + rect.x) : 0);\n            nextX = x + moveX;\n            // Wrap when width exceeds maxWidth or meet a `newline` group\n            // FIXME compare before adding gap?\n            if (nextX > maxWidth || child.newline) {\n                x = 0;\n                nextX = moveX;\n                y += currentLineMaxSize + gap;\n                currentLineMaxSize = rect.height;\n            }\n            else {\n                // FIXME: consider rect.y is not `0`?\n                currentLineMaxSize = Math.max(currentLineMaxSize, rect.height);\n            }\n        }\n        else {\n            var moveY = rect.height + (nextChildRect ? (-nextChildRect.y + rect.y) : 0);\n            nextY = y + moveY;\n            // Wrap when width exceeds maxHeight or meet a `newline` group\n            if (nextY > maxHeight || child.newline) {\n                x += currentLineMaxSize + gap;\n                y = 0;\n                nextY = moveY;\n                currentLineMaxSize = rect.width;\n            }\n            else {\n                currentLineMaxSize = Math.max(currentLineMaxSize, rect.width);\n            }\n        }\n\n        if (child.newline) {\n            return;\n        }\n\n        position[0] = x;\n        position[1] = y;\n\n        orient === 'horizontal'\n            ? (x = nextX + gap)\n            : (y = nextY + gap);\n    });\n}\n\n/**\n * VBox or HBox layouting\n * @param {string} orient\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar box = boxLayout;\n\n/**\n * VBox layouting\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar vbox = curry(boxLayout, 'vertical');\n\n/**\n * HBox layouting\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar hbox = curry(boxLayout, 'horizontal');\n\n/**\n * If x or x2 is not specified or 'center' 'left' 'right',\n * the width would be as long as possible.\n * If y or y2 is not specified or 'middle' 'top' 'bottom',\n * the height would be as long as possible.\n *\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.x]\n * @param {number|string} [positionInfo.y]\n * @param {number|string} [positionInfo.x2]\n * @param {number|string} [positionInfo.y2]\n * @param {Object} containerRect {width, height}\n * @param {string|number} margin\n * @return {Object} {width, height}\n */\nfunction getAvailableSize(positionInfo, containerRect, margin) {\n    var containerWidth = containerRect.width;\n    var containerHeight = containerRect.height;\n\n    var x = parsePercent$1(positionInfo.x, containerWidth);\n    var y = parsePercent$1(positionInfo.y, containerHeight);\n    var x2 = parsePercent$1(positionInfo.x2, containerWidth);\n    var y2 = parsePercent$1(positionInfo.y2, containerHeight);\n\n    (isNaN(x) || isNaN(parseFloat(positionInfo.x))) && (x = 0);\n    (isNaN(x2) || isNaN(parseFloat(positionInfo.x2))) && (x2 = containerWidth);\n    (isNaN(y) || isNaN(parseFloat(positionInfo.y))) && (y = 0);\n    (isNaN(y2) || isNaN(parseFloat(positionInfo.y2))) && (y2 = containerHeight);\n\n    margin = normalizeCssArray$1(margin || 0);\n\n    return {\n        width: Math.max(x2 - x - margin[1] - margin[3], 0),\n        height: Math.max(y2 - y - margin[0] - margin[2], 0)\n    };\n}\n\n/**\n * Parse position info.\n *\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.left]\n * @param {number|string} [positionInfo.top]\n * @param {number|string} [positionInfo.right]\n * @param {number|string} [positionInfo.bottom]\n * @param {number|string} [positionInfo.width]\n * @param {number|string} [positionInfo.height]\n * @param {number|string} [positionInfo.aspect] Aspect is width / height\n * @param {Object} containerRect\n * @param {string|number} [margin]\n *\n * @return {module:zrender/core/BoundingRect}\n */\nfunction getLayoutRect(\n    positionInfo, containerRect, margin\n) {\n    margin = normalizeCssArray$1(margin || 0);\n\n    var containerWidth = containerRect.width;\n    var containerHeight = containerRect.height;\n\n    var left = parsePercent$1(positionInfo.left, containerWidth);\n    var top = parsePercent$1(positionInfo.top, containerHeight);\n    var right = parsePercent$1(positionInfo.right, containerWidth);\n    var bottom = parsePercent$1(positionInfo.bottom, containerHeight);\n    var width = parsePercent$1(positionInfo.width, containerWidth);\n    var height = parsePercent$1(positionInfo.height, containerHeight);\n\n    var verticalMargin = margin[2] + margin[0];\n    var horizontalMargin = margin[1] + margin[3];\n    var aspect = positionInfo.aspect;\n\n    // If width is not specified, calculate width from left and right\n    if (isNaN(width)) {\n        width = containerWidth - right - horizontalMargin - left;\n    }\n    if (isNaN(height)) {\n        height = containerHeight - bottom - verticalMargin - top;\n    }\n\n    if (aspect != null) {\n        // If width and height are not given\n        // 1. Graph should not exceeds the container\n        // 2. Aspect must be keeped\n        // 3. Graph should take the space as more as possible\n        // FIXME\n        // Margin is not considered, because there is no case that both\n        // using margin and aspect so far.\n        if (isNaN(width) && isNaN(height)) {\n            if (aspect > containerWidth / containerHeight) {\n                width = containerWidth * 0.8;\n            }\n            else {\n                height = containerHeight * 0.8;\n            }\n        }\n\n        // Calculate width or height with given aspect\n        if (isNaN(width)) {\n            width = aspect * height;\n        }\n        if (isNaN(height)) {\n            height = width / aspect;\n        }\n    }\n\n    // If left is not specified, calculate left from right and width\n    if (isNaN(left)) {\n        left = containerWidth - right - width - horizontalMargin;\n    }\n    if (isNaN(top)) {\n        top = containerHeight - bottom - height - verticalMargin;\n    }\n\n    // Align left and top\n    switch (positionInfo.left || positionInfo.right) {\n        case 'center':\n            left = containerWidth / 2 - width / 2 - margin[3];\n            break;\n        case 'right':\n            left = containerWidth - width - horizontalMargin;\n            break;\n    }\n    switch (positionInfo.top || positionInfo.bottom) {\n        case 'middle':\n        case 'center':\n            top = containerHeight / 2 - height / 2 - margin[0];\n            break;\n        case 'bottom':\n            top = containerHeight - height - verticalMargin;\n            break;\n    }\n    // If something is wrong and left, top, width, height are calculated as NaN\n    left = left || 0;\n    top = top || 0;\n    if (isNaN(width)) {\n        // Width may be NaN if only one value is given except width\n        width = containerWidth - horizontalMargin - left - (right || 0);\n    }\n    if (isNaN(height)) {\n        // Height may be NaN if only one value is given except height\n        height = containerHeight - verticalMargin - top - (bottom || 0);\n    }\n\n    var rect = new BoundingRect(left + margin[3], top + margin[0], width, height);\n    rect.margin = margin;\n    return rect;\n}\n\n\n/**\n * Position a zr element in viewport\n *  Group position is specified by either\n *  {left, top}, {right, bottom}\n *  If all properties exists, right and bottom will be igonred.\n *\n * Logic:\n *     1. Scale (against origin point in parent coord)\n *     2. Rotate (against origin point in parent coord)\n *     3. Traslate (with el.position by this method)\n * So this method only fixes the last step 'Traslate', which does not affect\n * scaling and rotating.\n *\n * If be called repeatly with the same input el, the same result will be gotten.\n *\n * @param {module:zrender/Element} el Should have `getBoundingRect` method.\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.left]\n * @param {number|string} [positionInfo.top]\n * @param {number|string} [positionInfo.right]\n * @param {number|string} [positionInfo.bottom]\n * @param {number|string} [positionInfo.width] Only for opt.boundingModel: 'raw'\n * @param {number|string} [positionInfo.height] Only for opt.boundingModel: 'raw'\n * @param {Object} containerRect\n * @param {string|number} margin\n * @param {Object} [opt]\n * @param {Array.<number>} [opt.hv=[1,1]] Only horizontal or only vertical.\n * @param {Array.<number>} [opt.boundingMode='all']\n *        Specify how to calculate boundingRect when locating.\n *        'all': Position the boundingRect that is transformed and uioned\n *               both itself and its descendants.\n *               This mode simplies confine the elements in the bounding\n *               of their container (e.g., using 'right: 0').\n *        'raw': Position the boundingRect that is not transformed and only itself.\n *               This mode is useful when you want a element can overflow its\n *               container. (Consider a rotated circle needs to be located in a corner.)\n *               In this mode positionInfo.width/height can only be number.\n */\nfunction positionElement(el, positionInfo, containerRect, margin, opt) {\n    var h = !opt || !opt.hv || opt.hv[0];\n    var v = !opt || !opt.hv || opt.hv[1];\n    var boundingMode = opt && opt.boundingMode || 'all';\n\n    if (!h && !v) {\n        return;\n    }\n\n    var rect;\n    if (boundingMode === 'raw') {\n        rect = el.type === 'group'\n            ? new BoundingRect(0, 0, +positionInfo.width || 0, +positionInfo.height || 0)\n            : el.getBoundingRect();\n    }\n    else {\n        rect = el.getBoundingRect();\n        if (el.needLocalTransform()) {\n            var transform = el.getLocalTransform();\n            // Notice: raw rect may be inner object of el,\n            // which should not be modified.\n            rect = rect.clone();\n            rect.applyTransform(transform);\n        }\n    }\n\n    // The real width and height can not be specified but calculated by the given el.\n    positionInfo = getLayoutRect(\n        defaults(\n            {width: rect.width, height: rect.height},\n            positionInfo\n        ),\n        containerRect,\n        margin\n    );\n\n    // Because 'tranlate' is the last step in transform\n    // (see zrender/core/Transformable#getLocalTransform),\n    // we can just only modify el.position to get final result.\n    var elPos = el.position;\n    var dx = h ? positionInfo.x - rect.x : 0;\n    var dy = v ? positionInfo.y - rect.y : 0;\n\n    el.attr('position', boundingMode === 'raw' ? [dx, dy] : [elPos[0] + dx, elPos[1] + dy]);\n}\n\n/**\n * @param {Object} option Contains some of the properties in HV_NAMES.\n * @param {number} hvIdx 0: horizontal; 1: vertical.\n */\nfunction sizeCalculable(option, hvIdx) {\n    return option[HV_NAMES[hvIdx][0]] != null\n        || (option[HV_NAMES[hvIdx][1]] != null && option[HV_NAMES[hvIdx][2]] != null);\n}\n\n/**\n * Consider Case:\n * When defulat option has {left: 0, width: 100}, and we set {right: 0}\n * through setOption or media query, using normal zrUtil.merge will cause\n * {right: 0} does not take effect.\n *\n * @example\n * ComponentModel.extend({\n *     init: function () {\n *         ...\n *         var inputPositionParams = layout.getLayoutParams(option);\n *         this.mergeOption(inputPositionParams);\n *     },\n *     mergeOption: function (newOption) {\n *         newOption && zrUtil.merge(thisOption, newOption, true);\n *         layout.mergeLayoutParam(thisOption, newOption);\n *     }\n * });\n *\n * @param {Object} targetOption\n * @param {Object} newOption\n * @param {Object|string} [opt]\n * @param {boolean|Array.<boolean>} [opt.ignoreSize=false] Used for the components\n *  that width (or height) should not be calculated by left and right (or top and bottom).\n */\nfunction mergeLayoutParam(targetOption, newOption, opt) {\n    !isObject$1(opt) && (opt = {});\n\n    var ignoreSize = opt.ignoreSize;\n    !isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]);\n\n    var hResult = merge$$1(HV_NAMES[0], 0);\n    var vResult = merge$$1(HV_NAMES[1], 1);\n\n    copy(HV_NAMES[0], targetOption, hResult);\n    copy(HV_NAMES[1], targetOption, vResult);\n\n    function merge$$1(names, hvIdx) {\n        var newParams = {};\n        var newValueCount = 0;\n        var merged = {};\n        var mergedValueCount = 0;\n        var enoughParamNumber = 2;\n\n        each$3(names, function (name) {\n            merged[name] = targetOption[name];\n        });\n        each$3(names, function (name) {\n            // Consider case: newOption.width is null, which is\n            // set by user for removing width setting.\n            hasProp(newOption, name) && (newParams[name] = merged[name] = newOption[name]);\n            hasValue(newParams, name) && newValueCount++;\n            hasValue(merged, name) && mergedValueCount++;\n        });\n\n        if (ignoreSize[hvIdx]) {\n            // Only one of left/right is premitted to exist.\n            if (hasValue(newOption, names[1])) {\n                merged[names[2]] = null;\n            }\n            else if (hasValue(newOption, names[2])) {\n                merged[names[1]] = null;\n            }\n            return merged;\n        }\n\n        // Case: newOption: {width: ..., right: ...},\n        // or targetOption: {right: ...} and newOption: {width: ...},\n        // There is no conflict when merged only has params count\n        // little than enoughParamNumber.\n        if (mergedValueCount === enoughParamNumber || !newValueCount) {\n            return merged;\n        }\n        // Case: newOption: {width: ..., right: ...},\n        // Than we can make sure user only want those two, and ignore\n        // all origin params in targetOption.\n        else if (newValueCount >= enoughParamNumber) {\n            return newParams;\n        }\n        else {\n            // Chose another param from targetOption by priority.\n            for (var i = 0; i < names.length; i++) {\n                var name = names[i];\n                if (!hasProp(newParams, name) && hasProp(targetOption, name)) {\n                    newParams[name] = targetOption[name];\n                    break;\n                }\n            }\n            return newParams;\n        }\n    }\n\n    function hasProp(obj, name) {\n        return obj.hasOwnProperty(name);\n    }\n\n    function hasValue(obj, name) {\n        return obj[name] != null && obj[name] !== 'auto';\n    }\n\n    function copy(names, target, source) {\n        each$3(names, function (name) {\n            target[name] = source[name];\n        });\n    }\n}\n\n/**\n * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.\n * @param {Object} source\n * @return {Object} Result contains those props.\n */\nfunction getLayoutParams(source) {\n    return copyLayoutParams({}, source);\n}\n\n/**\n * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.\n * @param {Object} source\n * @return {Object} Result contains those props.\n */\nfunction copyLayoutParams(target, source) {\n    source && target && each$3(LOCATION_PARAMS, function (name) {\n        source.hasOwnProperty(name) && (target[name] = source[name]);\n    });\n    return target;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar boxLayoutMixin = {\n    getBoxLayoutParams: function () {\n        return {\n            left: this.get('left'),\n            top: this.get('top'),\n            right: this.get('right'),\n            bottom: this.get('bottom'),\n            width: this.get('width'),\n            height: this.get('height')\n        };\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Component model\n *\n * @module echarts/model/Component\n */\n\nvar inner$1 = makeInner();\n\n/**\n * @alias module:echarts/model/Component\n * @constructor\n * @param {Object} option\n * @param {module:echarts/model/Model} parentModel\n * @param {module:echarts/model/Model} ecModel\n */\nvar ComponentModel = Model.extend({\n\n    type: 'component',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    id: '',\n\n    /**\n     * Because simplified concept is probably better, series.name (or component.name)\n     * has been having too many resposibilities:\n     * (1) Generating id (which requires name in option should not be modified).\n     * (2) As an index to mapping series when merging option or calling API (a name\n     * can refer to more then one components, which is convinient is some case).\n     * (3) Display.\n     * @readOnly\n     */\n    name: '',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    mainType: '',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    subType: '',\n\n    /**\n     * @readOnly\n     * @type {number}\n     */\n    componentIndex: 0,\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    defaultOption: null,\n\n    /**\n     * @type {module:echarts/model/Global}\n     * @readOnly\n     */\n    ecModel: null,\n\n    /**\n     * key: componentType\n     * value:  Component model list, can not be null.\n     * @type {Object.<string, Array.<module:echarts/model/Model>>}\n     * @readOnly\n     */\n    dependentModels: [],\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    uid: null,\n\n    /**\n     * Support merge layout params.\n     * Only support 'box' now (left/right/top/bottom/width/height).\n     * @type {string|Object} Object can be {ignoreSize: true}\n     * @readOnly\n     */\n    layoutMode: null,\n\n    $constructor: function (option, parentModel, ecModel, extraOpt) {\n        Model.call(this, option, parentModel, ecModel, extraOpt);\n\n        this.uid = getUID('ec_cpt_model');\n    },\n\n    init: function (option, parentModel, ecModel, extraOpt) {\n        this.mergeDefaultAndTheme(option, ecModel);\n    },\n\n    mergeDefaultAndTheme: function (option, ecModel) {\n        var layoutMode = this.layoutMode;\n        var inputPositionParams = layoutMode\n            ? getLayoutParams(option) : {};\n\n        var themeModel = ecModel.getTheme();\n        merge(option, themeModel.get(this.mainType));\n        merge(option, this.getDefaultOption());\n\n        if (layoutMode) {\n            mergeLayoutParam(option, inputPositionParams, layoutMode);\n        }\n    },\n\n    mergeOption: function (option, extraOpt) {\n        merge(this.option, option, true);\n\n        var layoutMode = this.layoutMode;\n        if (layoutMode) {\n            mergeLayoutParam(this.option, option, layoutMode);\n        }\n    },\n\n    // Hooker after init or mergeOption\n    optionUpdated: function (newCptOption, isInit) {},\n\n    getDefaultOption: function () {\n        var fields = inner$1(this);\n        if (!fields.defaultOption) {\n            var optList = [];\n            var Class = this.constructor;\n            while (Class) {\n                var opt = Class.prototype.defaultOption;\n                opt && optList.push(opt);\n                Class = Class.superClass;\n            }\n\n            var defaultOption = {};\n            for (var i = optList.length - 1; i >= 0; i--) {\n                defaultOption = merge(defaultOption, optList[i], true);\n            }\n            fields.defaultOption = defaultOption;\n        }\n        return fields.defaultOption;\n    },\n\n    getReferringComponents: function (mainType) {\n        return this.ecModel.queryComponents({\n            mainType: mainType,\n            index: this.get(mainType + 'Index', true),\n            id: this.get(mainType + 'Id', true)\n        });\n    }\n\n});\n\n// Reset ComponentModel.extend, add preConstruct.\n// clazzUtil.enableClassExtend(\n//     ComponentModel,\n//     function (option, parentModel, ecModel, extraOpt) {\n//         // Set dependentModels, componentIndex, name, id, mainType, subType.\n//         zrUtil.extend(this, extraOpt);\n\n//         this.uid = componentUtil.getUID('componentModel');\n\n//         // this.setReadOnly([\n//         //     'type', 'id', 'uid', 'name', 'mainType', 'subType',\n//         //     'dependentModels', 'componentIndex'\n//         // ]);\n//     }\n// );\n\n// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(\n    ComponentModel, {registerWhenExtend: true}\n);\nenableSubTypeDefaulter(ComponentModel);\n\n// Add capability of ComponentModel.topologicalTravel.\nenableTopologicalTravel(ComponentModel, getDependencies);\n\nfunction getDependencies(componentType) {\n    var deps = [];\n    each$1(ComponentModel.getClassesByMainType(componentType), function (Clazz) {\n        deps = deps.concat(Clazz.prototype.dependencies || []);\n    });\n\n    // Ensure main type.\n    deps = map(deps, function (type) {\n        return parseClassType$1(type).main;\n    });\n\n    // Hack dataset for convenience.\n    if (componentType !== 'dataset' && indexOf(deps, 'dataset') <= 0) {\n        deps.unshift('dataset');\n    }\n\n    return deps;\n}\n\nmixin(ComponentModel, boxLayoutMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar platform = '';\n// Navigator not exists in node\nif (typeof navigator !== 'undefined') {\n    platform = navigator.platform || '';\n}\n\nvar globalDefault = {\n    // backgroundColor: 'rgba(0,0,0,0)',\n\n    // https://dribbble.com/shots/1065960-Infographic-Pie-chart-visualization\n    // color: ['#5793f3', '#d14a61', '#fd9c35', '#675bba', '#fec42c', '#dd4444', '#d4df5a', '#cd4870'],\n    // Light colors:\n    // color: ['#bcd3bb', '#e88f70', '#edc1a5', '#9dc5c8', '#e1e8c8', '#7b7c68', '#e5b5b5', '#f0b489', '#928ea8', '#bda29a'],\n    // color: ['#cc5664', '#9bd6ec', '#ea946e', '#8acaaa', '#f1ec64', '#ee8686', '#a48dc1', '#5da6bc', '#b9dcae'],\n    // Dark colors:\n    color: [\n        '#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83',\n        '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'\n    ],\n\n    gradientColor: ['#f6efa6', '#d88273', '#bf444c'],\n\n    // If xAxis and yAxis declared, grid is created by default.\n    // grid: {},\n\n    textStyle: {\n        // color: '#000',\n        // decoration: 'none',\n        // PENDING\n        fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif',\n        // fontFamily: 'Arial, Verdana, sans-serif',\n        fontSize: 12,\n        fontStyle: 'normal',\n        fontWeight: 'normal'\n    },\n\n    // http://blogs.adobe.com/webplatform/2014/02/24/using-blend-modes-in-html-canvas/\n    // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation\n    // Default is source-over\n    blendMode: null,\n\n    animation: 'auto',\n    animationDuration: 1000,\n    animationDurationUpdate: 300,\n    animationEasing: 'exponentialOut',\n    animationEasingUpdate: 'cubicOut',\n\n    animationThreshold: 2000,\n    // Configuration for progressive/incremental rendering\n    progressiveThreshold: 3000,\n    progressive: 400,\n\n    // Threshold of if use single hover layer to optimize.\n    // It is recommended that `hoverLayerThreshold` is equivalent to or less than\n    // `progressiveThreshold`, otherwise hover will cause restart of progressive,\n    // which is unexpected.\n    // see example <echarts/test/heatmap-large.html>.\n    hoverLayerThreshold: 3000,\n\n    // See: module:echarts/scale/Time\n    useUTC: false\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$2 = makeInner();\n\nfunction getNearestColorPalette(colors, requestColorNum) {\n    var paletteNum = colors.length;\n    // TODO colors must be in order\n    for (var i = 0; i < paletteNum; i++) {\n        if (colors[i].length > requestColorNum) {\n            return colors[i];\n        }\n    }\n    return colors[paletteNum - 1];\n}\n\nvar colorPaletteMixin = {\n    clearColorPalette: function () {\n        inner$2(this).colorIdx = 0;\n        inner$2(this).colorNameMap = {};\n    },\n\n    /**\n     * @param {string} name MUST NOT be null/undefined. Otherwise call this function\n     *                 twise with the same parameters will get different result.\n     * @param {Object} [scope=this]\n     * @param {Object} [requestColorNum]\n     * @return {string} color string.\n     */\n    getColorFromPalette: function (name, scope, requestColorNum) {\n        scope = scope || this;\n        var scopeFields = inner$2(scope);\n        var colorIdx = scopeFields.colorIdx || 0;\n        var colorNameMap = scopeFields.colorNameMap = scopeFields.colorNameMap || {};\n        // Use `hasOwnProperty` to avoid conflict with Object.prototype.\n        if (colorNameMap.hasOwnProperty(name)) {\n            return colorNameMap[name];\n        }\n        var defaultColorPalette = normalizeToArray(this.get('color', true));\n        var layeredColorPalette = this.get('colorLayer', true);\n        var colorPalette = ((requestColorNum == null || !layeredColorPalette)\n            ? defaultColorPalette : getNearestColorPalette(layeredColorPalette, requestColorNum));\n\n        // In case can't find in layered color palette.\n        colorPalette = colorPalette || defaultColorPalette;\n\n        if (!colorPalette || !colorPalette.length) {\n            return;\n        }\n\n        var color = colorPalette[colorIdx];\n        if (name) {\n            colorNameMap[name] = color;\n        }\n        scopeFields.colorIdx = (colorIdx + 1) % colorPalette.length;\n\n        return color;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Helper for model references.\n * There are many manners to refer axis/coordSys.\n */\n\n// TODO\n// merge relevant logic to this file?\n// check: \"modelHelper\" of tooltip and \"BrushTargetManager\".\n\n/**\n * @return {Object} For example:\n * {\n *     coordSysName: 'cartesian2d',\n *     coordSysDims: ['x', 'y', ...],\n *     axisMap: HashMap({\n *         x: xAxisModel,\n *         y: yAxisModel\n *     }),\n *     categoryAxisMap: HashMap({\n *         x: xAxisModel,\n *         y: undefined\n *     }),\n *     // It also indicate that whether there is category axis.\n *     firstCategoryDimIndex: 1,\n *     // To replace user specified encode.\n * }\n */\nfunction getCoordSysDefineBySeries(seriesModel) {\n    var coordSysName = seriesModel.get('coordinateSystem');\n    var result = {\n        coordSysName: coordSysName,\n        coordSysDims: [],\n        axisMap: createHashMap(),\n        categoryAxisMap: createHashMap()\n    };\n    var fetch = fetchers[coordSysName];\n    if (fetch) {\n        fetch(seriesModel, result, result.axisMap, result.categoryAxisMap);\n        return result;\n    }\n}\n\nvar fetchers = {\n\n    cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var xAxisModel = seriesModel.getReferringComponents('xAxis')[0];\n        var yAxisModel = seriesModel.getReferringComponents('yAxis')[0];\n\n        if (__DEV__) {\n            if (!xAxisModel) {\n                throw new Error('xAxis \"' + retrieve(\n                    seriesModel.get('xAxisIndex'),\n                    seriesModel.get('xAxisId'),\n                    0\n                ) + '\" not found');\n            }\n            if (!yAxisModel) {\n                throw new Error('yAxis \"' + retrieve(\n                    seriesModel.get('xAxisIndex'),\n                    seriesModel.get('yAxisId'),\n                    0\n                ) + '\" not found');\n            }\n        }\n\n        result.coordSysDims = ['x', 'y'];\n        axisMap.set('x', xAxisModel);\n        axisMap.set('y', yAxisModel);\n\n        if (isCategory(xAxisModel)) {\n            categoryAxisMap.set('x', xAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n        if (isCategory(yAxisModel)) {\n            categoryAxisMap.set('y', yAxisModel);\n            result.firstCategoryDimIndex = 1;\n        }\n    },\n\n    singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var singleAxisModel = seriesModel.getReferringComponents('singleAxis')[0];\n\n        if (__DEV__) {\n            if (!singleAxisModel) {\n                throw new Error('singleAxis should be specified.');\n            }\n        }\n\n        result.coordSysDims = ['single'];\n        axisMap.set('single', singleAxisModel);\n\n        if (isCategory(singleAxisModel)) {\n            categoryAxisMap.set('single', singleAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n    },\n\n    polar: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var polarModel = seriesModel.getReferringComponents('polar')[0];\n        var radiusAxisModel = polarModel.findAxisModel('radiusAxis');\n        var angleAxisModel = polarModel.findAxisModel('angleAxis');\n\n        if (__DEV__) {\n            if (!angleAxisModel) {\n                throw new Error('angleAxis option not found');\n            }\n            if (!radiusAxisModel) {\n                throw new Error('radiusAxis option not found');\n            }\n        }\n\n        result.coordSysDims = ['radius', 'angle'];\n        axisMap.set('radius', radiusAxisModel);\n        axisMap.set('angle', angleAxisModel);\n\n        if (isCategory(radiusAxisModel)) {\n            categoryAxisMap.set('radius', radiusAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n        if (isCategory(angleAxisModel)) {\n            categoryAxisMap.set('angle', angleAxisModel);\n            result.firstCategoryDimIndex = 1;\n        }\n    },\n\n    geo: function (seriesModel, result, axisMap, categoryAxisMap) {\n        result.coordSysDims = ['lng', 'lat'];\n    },\n\n    parallel: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var ecModel = seriesModel.ecModel;\n        var parallelModel = ecModel.getComponent(\n            'parallel', seriesModel.get('parallelIndex')\n        );\n        var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice();\n\n        each$1(parallelModel.parallelAxisIndex, function (axisIndex, index) {\n            var axisModel = ecModel.getComponent('parallelAxis', axisIndex);\n            var axisDim = coordSysDims[index];\n            axisMap.set(axisDim, axisModel);\n\n            if (isCategory(axisModel) && result.firstCategoryDimIndex == null) {\n                categoryAxisMap.set(axisDim, axisModel);\n                result.firstCategoryDimIndex = index;\n            }\n        });\n    }\n};\n\nfunction isCategory(axisModel) {\n    return axisModel.get('type') === 'category';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Avoid typo.\nvar SOURCE_FORMAT_ORIGINAL = 'original';\nvar SOURCE_FORMAT_ARRAY_ROWS = 'arrayRows';\nvar SOURCE_FORMAT_OBJECT_ROWS = 'objectRows';\nvar SOURCE_FORMAT_KEYED_COLUMNS = 'keyedColumns';\nvar SOURCE_FORMAT_UNKNOWN = 'unknown';\n// ??? CHANGE A NAME\nvar SOURCE_FORMAT_TYPED_ARRAY = 'typedArray';\n\nvar SERIES_LAYOUT_BY_COLUMN = 'column';\nvar SERIES_LAYOUT_BY_ROW = 'row';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * [sourceFormat]\n *\n * + \"original\":\n * This format is only used in series.data, where\n * itemStyle can be specified in data item.\n *\n * + \"arrayRows\":\n * [\n *     ['product', 'score', 'amount'],\n *     ['Matcha Latte', 89.3, 95.8],\n *     ['Milk Tea', 92.1, 89.4],\n *     ['Cheese Cocoa', 94.4, 91.2],\n *     ['Walnut Brownie', 85.4, 76.9]\n * ]\n *\n * + \"objectRows\":\n * [\n *     {product: 'Matcha Latte', score: 89.3, amount: 95.8},\n *     {product: 'Milk Tea', score: 92.1, amount: 89.4},\n *     {product: 'Cheese Cocoa', score: 94.4, amount: 91.2},\n *     {product: 'Walnut Brownie', score: 85.4, amount: 76.9}\n * ]\n *\n * + \"keyedColumns\":\n * {\n *     'product': ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie'],\n *     'count': [823, 235, 1042, 988],\n *     'score': [95.8, 81.4, 91.2, 76.9]\n * }\n *\n * + \"typedArray\"\n *\n * + \"unknown\"\n */\n\n/**\n * @constructor\n * @param {Object} fields\n * @param {string} fields.sourceFormat\n * @param {Array|Object} fields.fromDataset\n * @param {Array|Object} [fields.data]\n * @param {string} [seriesLayoutBy='column']\n * @param {Array.<Object|string>} [dimensionsDefine]\n * @param {Objet|HashMap} [encodeDefine]\n * @param {number} [startIndex=0]\n * @param {number} [dimensionsDetectCount]\n */\nfunction Source(fields) {\n\n    /**\n     * @type {boolean}\n     */\n    this.fromDataset = fields.fromDataset;\n\n    /**\n     * Not null/undefined.\n     * @type {Array|Object}\n     */\n    this.data = fields.data || (\n        fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []\n    );\n\n    /**\n     * See also \"detectSourceFormat\".\n     * Not null/undefined.\n     * @type {string}\n     */\n    this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN;\n\n    /**\n     * 'row' or 'column'\n     * Not null/undefined.\n     * @type {string} seriesLayoutBy\n     */\n    this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN;\n\n    /**\n     * dimensions definition in option.\n     * can be null/undefined.\n     * @type {Array.<Object|string>}\n     */\n    this.dimensionsDefine = fields.dimensionsDefine;\n\n    /**\n     * encode definition in option.\n     * can be null/undefined.\n     * @type {Objet|HashMap}\n     */\n    this.encodeDefine = fields.encodeDefine && createHashMap(fields.encodeDefine);\n\n    /**\n     * Not null/undefined, uint.\n     * @type {number}\n     */\n    this.startIndex = fields.startIndex || 0;\n\n    /**\n     * Can be null/undefined (when unknown), uint.\n     * @type {number}\n     */\n    this.dimensionsDetectCount = fields.dimensionsDetectCount;\n}\n\n/**\n * Wrap original series data for some compatibility cases.\n */\nSource.seriesDataToSource = function (data) {\n    return new Source({\n        data: data,\n        sourceFormat: isTypedArray(data)\n            ? SOURCE_FORMAT_TYPED_ARRAY\n            : SOURCE_FORMAT_ORIGINAL,\n        fromDataset: false\n    });\n};\n\nenableClassCheck(Source);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$3 = makeInner();\n\n/**\n * @see {module:echarts/data/Source}\n * @param {module:echarts/component/dataset/DatasetModel} datasetModel\n * @return {string} sourceFormat\n */\nfunction detectSourceFormat(datasetModel) {\n    var data = datasetModel.option.source;\n    var sourceFormat = SOURCE_FORMAT_UNKNOWN;\n\n    if (isTypedArray(data)) {\n        sourceFormat = SOURCE_FORMAT_TYPED_ARRAY;\n    }\n    else if (isArray(data)) {\n        // FIXME Whether tolerate null in top level array?\n        if (data.length === 0) {\n            sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;\n        }\n\n        for (var i = 0, len = data.length; i < len; i++) {\n            var item = data[i];\n\n            if (item == null) {\n                continue;\n            }\n            else if (isArray(item)) {\n                sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;\n                break;\n            }\n            else if (isObject$1(item)) {\n                sourceFormat = SOURCE_FORMAT_OBJECT_ROWS;\n                break;\n            }\n        }\n    }\n    else if (isObject$1(data)) {\n        for (var key in data) {\n            if (data.hasOwnProperty(key) && isArrayLike(data[key])) {\n                sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS;\n                break;\n            }\n        }\n    }\n    else if (data != null) {\n        throw new Error('Invalid data');\n    }\n\n    inner$3(datasetModel).sourceFormat = sourceFormat;\n}\n\n/**\n * [Scenarios]:\n * (1) Provide source data directly:\n *     series: {\n *         encode: {...},\n *         dimensions: [...]\n *         seriesLayoutBy: 'row',\n *         data: [[...]]\n *     }\n * (2) Refer to datasetModel.\n *     series: [{\n *         encode: {...}\n *         // Ignore datasetIndex means `datasetIndex: 0`\n *         // and the dimensions defination in dataset is used\n *     }, {\n *         encode: {...},\n *         seriesLayoutBy: 'column',\n *         datasetIndex: 1\n *     }]\n *\n * Get data from series itself or datset.\n * @return {module:echarts/data/Source} source\n */\nfunction getSource(seriesModel) {\n    return inner$3(seriesModel).source;\n}\n\n/**\n * MUST be called before mergeOption of all series.\n * @param {module:echarts/model/Global} ecModel\n */\nfunction resetSourceDefaulter(ecModel) {\n    // `datasetMap` is used to make default encode.\n    inner$3(ecModel).datasetMap = createHashMap();\n}\n\n/**\n * [Caution]:\n * MUST be called after series option merged and\n * before \"series.getInitailData()\" called.\n *\n * [The rule of making default encode]:\n * Category axis (if exists) alway map to the first dimension.\n * Each other axis occupies a subsequent dimension.\n *\n * [Why make default encode]:\n * Simplify the typing of encode in option, avoiding the case like that:\n * series: [{encode: {x: 0, y: 1}}, {encode: {x: 0, y: 2}}, {encode: {x: 0, y: 3}}],\n * where the \"y\" have to be manually typed as \"1, 2, 3, ...\".\n *\n * @param {module:echarts/model/Series} seriesModel\n */\nfunction prepareSource(seriesModel) {\n    var seriesOption = seriesModel.option;\n\n    var data = seriesOption.data;\n    var sourceFormat = isTypedArray(data)\n        ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL;\n    var fromDataset = false;\n\n    var seriesLayoutBy = seriesOption.seriesLayoutBy;\n    var sourceHeader = seriesOption.sourceHeader;\n    var dimensionsDefine = seriesOption.dimensions;\n\n    var datasetModel = getDatasetModel(seriesModel);\n    if (datasetModel) {\n        var datasetOption = datasetModel.option;\n\n        data = datasetOption.source;\n        sourceFormat = inner$3(datasetModel).sourceFormat;\n        fromDataset = true;\n\n        // These settings from series has higher priority.\n        seriesLayoutBy = seriesLayoutBy || datasetOption.seriesLayoutBy;\n        sourceHeader == null && (sourceHeader = datasetOption.sourceHeader);\n        dimensionsDefine = dimensionsDefine || datasetOption.dimensions;\n    }\n\n    var completeResult = completeBySourceData(\n        data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine\n    );\n\n    // Note: dataset option does not have `encode`.\n    var encodeDefine = seriesOption.encode;\n    if (!encodeDefine && datasetModel) {\n        encodeDefine = makeDefaultEncode(\n            seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult\n        );\n    }\n\n    inner$3(seriesModel).source = new Source({\n        data: data,\n        fromDataset: fromDataset,\n        seriesLayoutBy: seriesLayoutBy,\n        sourceFormat: sourceFormat,\n        dimensionsDefine: completeResult.dimensionsDefine,\n        startIndex: completeResult.startIndex,\n        dimensionsDetectCount: completeResult.dimensionsDetectCount,\n        encodeDefine: encodeDefine\n    });\n}\n\n// return {startIndex, dimensionsDefine, dimensionsCount}\nfunction completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine) {\n    if (!data) {\n        return {dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine)};\n    }\n\n    var dimensionsDetectCount;\n    var startIndex;\n    var findPotentialName;\n\n    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {\n        // Rule: Most of the first line are string: it is header.\n        // Caution: consider a line with 5 string and 1 number,\n        // it still can not be sure it is a head, because the\n        // 5 string may be 5 values of category columns.\n        if (sourceHeader === 'auto' || sourceHeader == null) {\n            arrayRowsTravelFirst(function (val) {\n                // '-' is regarded as null/undefined.\n                if (val != null && val !== '-') {\n                    if (isString(val)) {\n                        startIndex == null && (startIndex = 1);\n                    }\n                    else {\n                        startIndex = 0;\n                    }\n                }\n            // 10 is an experience number, avoid long loop.\n            }, seriesLayoutBy, data, 10);\n        }\n        else {\n            startIndex = sourceHeader ? 1 : 0;\n        }\n\n        if (!dimensionsDefine && startIndex === 1) {\n            dimensionsDefine = [];\n            arrayRowsTravelFirst(function (val, index) {\n                dimensionsDefine[index] = val != null ? val : '';\n            }, seriesLayoutBy, data);\n        }\n\n        dimensionsDetectCount = dimensionsDefine\n            ? dimensionsDefine.length\n            : seriesLayoutBy === SERIES_LAYOUT_BY_ROW\n            ? data.length\n            : data[0]\n            ? data[0].length\n            : null;\n    }\n    else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {\n        if (!dimensionsDefine) {\n            dimensionsDefine = objectRowsCollectDimensions(data);\n            findPotentialName = true;\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {\n        if (!dimensionsDefine) {\n            dimensionsDefine = [];\n            findPotentialName = true;\n            each$1(data, function (colArr, key) {\n                dimensionsDefine.push(key);\n            });\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        var value0 = getDataItemValue(data[0]);\n        dimensionsDetectCount = isArray(value0) && value0.length || 1;\n    }\n    else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {\n        if (__DEV__) {\n            assert$1(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.');\n        }\n    }\n\n    var potentialNameDimIndex;\n    if (findPotentialName) {\n        each$1(dimensionsDefine, function (dim, idx) {\n            if ((isObject$1(dim) ? dim.name : dim) === 'name') {\n                potentialNameDimIndex = idx;\n            }\n        });\n    }\n\n    return {\n        startIndex: startIndex,\n        dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine),\n        dimensionsDetectCount: dimensionsDetectCount,\n        potentialNameDimIndex: potentialNameDimIndex\n        // TODO: potentialIdDimIdx\n    };\n}\n\n// Consider dimensions defined like ['A', 'price', 'B', 'price', 'C', 'price'],\n// which is reasonable. But dimension name is duplicated.\n// Returns undefined or an array contains only object without null/undefiend or string.\nfunction normalizeDimensionsDefine(dimensionsDefine) {\n    if (!dimensionsDefine) {\n        // The meaning of null/undefined is different from empty array.\n        return;\n    }\n    var nameMap = createHashMap();\n    return map(dimensionsDefine, function (item, index) {\n        item = extend({}, isObject$1(item) ? item : {name: item});\n\n        // User can set null in dimensions.\n        // We dont auto specify name, othewise a given name may\n        // cause it be refered unexpectedly.\n        if (item.name == null) {\n            return item;\n        }\n\n        // Also consider number form like 2012.\n        item.name += '';\n        // User may also specify displayName.\n        // displayName will always exists except user not\n        // specified or dim name is not specified or detected.\n        // (A auto generated dim name will not be used as\n        // displayName).\n        if (item.displayName == null) {\n            item.displayName = item.name;\n        }\n\n        var exist = nameMap.get(item.name);\n        if (!exist) {\n            nameMap.set(item.name, {count: 1});\n        }\n        else {\n            item.name += '-' + exist.count++;\n        }\n\n        return item;\n    });\n}\n\nfunction arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) {\n    maxLoop == null && (maxLoop = Infinity);\n    if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            cb(data[i] ? data[i][0] : null, i);\n        }\n    }\n    else {\n        var value0 = data[0] || [];\n        for (var i = 0; i < value0.length && i < maxLoop; i++) {\n            cb(value0[i], i);\n        }\n    }\n}\n\nfunction objectRowsCollectDimensions(data) {\n    var firstIndex = 0;\n    var obj;\n    while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line\n    if (obj) {\n        var dimensions = [];\n        each$1(obj, function (value, key) {\n            dimensions.push(key);\n        });\n        return dimensions;\n    }\n}\n\n// ??? TODO merge to completedimensions, where also has\n// default encode making logic. And the default rule\n// should depends on series? consider 'map'.\nfunction makeDefaultEncode(\n    seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult\n) {\n    var coordSysDefine = getCoordSysDefineBySeries(seriesModel);\n    var encode = {};\n    // var encodeTooltip = [];\n    // var encodeLabel = [];\n    var encodeItemName = [];\n    var encodeSeriesName = [];\n    var seriesType = seriesModel.subType;\n\n    // ??? TODO refactor: provide by series itself.\n    // Consider the case: 'map' series is based on geo coordSys,\n    // 'graph', 'heatmap' can be based on cartesian. But can not\n    // give default rule simply here.\n    var nSeriesMap = createHashMap(['pie', 'map', 'funnel']);\n    var cSeriesMap = createHashMap([\n        'line', 'bar', 'pictorialBar', 'scatter', 'effectScatter', 'candlestick', 'boxplot'\n    ]);\n\n    // Usually in this case series will use the first data\n    // dimension as the \"value\" dimension, or other default\n    // processes respectively.\n    if (coordSysDefine && cSeriesMap.get(seriesType) != null) {\n        var ecModel = seriesModel.ecModel;\n        var datasetMap = inner$3(ecModel).datasetMap;\n        var key = datasetModel.uid + '_' + seriesLayoutBy;\n        var datasetRecord = datasetMap.get(key)\n            || datasetMap.set(key, {categoryWayDim: 1, valueWayDim: 0});\n\n        // TODO\n        // Auto detect first time axis and do arrangement.\n        each$1(coordSysDefine.coordSysDims, function (coordDim) {\n            // In value way.\n            if (coordSysDefine.firstCategoryDimIndex == null) {\n                var dataDim = datasetRecord.valueWayDim++;\n                encode[coordDim] = dataDim;\n\n                // ??? TODO give a better default series name rule?\n                // especially when encode x y specified.\n                // consider: when mutiple series share one dimension\n                // category axis, series name should better use\n                // the other dimsion name. On the other hand, use\n                // both dimensions name.\n\n                encodeSeriesName.push(dataDim);\n                // encodeTooltip.push(dataDim);\n                // encodeLabel.push(dataDim);\n            }\n            // In category way, category axis.\n            else if (coordSysDefine.categoryAxisMap.get(coordDim)) {\n                encode[coordDim] = 0;\n                encodeItemName.push(0);\n            }\n            // In category way, non-category axis.\n            else {\n                var dataDim = datasetRecord.categoryWayDim++;\n                encode[coordDim] = dataDim;\n                // encodeTooltip.push(dataDim);\n                // encodeLabel.push(dataDim);\n                encodeSeriesName.push(dataDim);\n            }\n        });\n    }\n    // Do not make a complex rule! Hard to code maintain and not necessary.\n    // ??? TODO refactor: provide by series itself.\n    // [{name: ..., value: ...}, ...] like:\n    else if (nSeriesMap.get(seriesType) != null) {\n        // Find the first not ordinal. (5 is an experience value)\n        var firstNotOrdinal;\n        for (var i = 0; i < 5 && firstNotOrdinal == null; i++) {\n            if (!doGuessOrdinal(\n                data, sourceFormat, seriesLayoutBy,\n                completeResult.dimensionsDefine, completeResult.startIndex, i\n            )) {\n                firstNotOrdinal = i;\n            }\n        }\n        if (firstNotOrdinal != null) {\n            encode.value = firstNotOrdinal;\n            var nameDimIndex = completeResult.potentialNameDimIndex\n                || Math.max(firstNotOrdinal - 1, 0);\n            // By default, label use itemName in charts.\n            // So we dont set encodeLabel here.\n            encodeSeriesName.push(nameDimIndex);\n            encodeItemName.push(nameDimIndex);\n            // encodeTooltip.push(firstNotOrdinal);\n        }\n    }\n\n    // encodeTooltip.length && (encode.tooltip = encodeTooltip);\n    // encodeLabel.length && (encode.label = encodeLabel);\n    encodeItemName.length && (encode.itemName = encodeItemName);\n    encodeSeriesName.length && (encode.seriesName = encodeSeriesName);\n\n    return encode;\n}\n\n/**\n * If return null/undefined, indicate that should not use datasetModel.\n */\nfunction getDatasetModel(seriesModel) {\n    var option = seriesModel.option;\n    // Caution: consider the scenario:\n    // A dataset is declared and a series is not expected to use the dataset,\n    // and at the beginning `setOption({series: { noData })` (just prepare other\n    // option but no data), then `setOption({series: {data: [...]}); In this case,\n    // the user should set an empty array to avoid that dataset is used by default.\n    var thisData = option.data;\n    if (!thisData) {\n        return seriesModel.ecModel.getComponent('dataset', option.datasetIndex || 0);\n    }\n}\n\n/**\n * The rule should not be complex, otherwise user might not\n * be able to known where the data is wrong.\n * The code is ugly, but how to make it neat?\n *\n * @param {module:echars/data/Source} source\n * @param {number} dimIndex\n * @return {boolean} Whether ordinal.\n */\nfunction guessOrdinal(source, dimIndex) {\n    return doGuessOrdinal(\n        source.data,\n        source.sourceFormat,\n        source.seriesLayoutBy,\n        source.dimensionsDefine,\n        source.startIndex,\n        dimIndex\n    );\n}\n\n// dimIndex may be overflow source data.\nfunction doGuessOrdinal(\n    data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex\n) {\n    var result;\n    // Experience value.\n    var maxLoop = 5;\n\n    if (isTypedArray(data)) {\n        return false;\n    }\n\n    // When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine\n    // always exists in source.\n    var dimName;\n    if (dimensionsDefine) {\n        dimName = dimensionsDefine[dimIndex];\n        dimName = isObject$1(dimName) ? dimName.name : dimName;\n    }\n\n    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {\n        if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {\n            var sample = data[dimIndex];\n            for (var i = 0; i < (sample || []).length && i < maxLoop; i++) {\n                if ((result = detectValue(sample[startIndex + i])) != null) {\n                    return result;\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < data.length && i < maxLoop; i++) {\n                var row = data[startIndex + i];\n                if (row && (result = detectValue(row[dimIndex])) != null) {\n                    return result;\n                }\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {\n        if (!dimName) {\n            return;\n        }\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            var item = data[i];\n            if (item && (result = detectValue(item[dimName])) != null) {\n                return result;\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {\n        if (!dimName) {\n            return;\n        }\n        var sample = data[dimName];\n        if (!sample || isTypedArray(sample)) {\n            return false;\n        }\n        for (var i = 0; i < sample.length && i < maxLoop; i++) {\n            if ((result = detectValue(sample[i])) != null) {\n                return result;\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            var item = data[i];\n            var val = getDataItemValue(item);\n            if (!isArray(val)) {\n                return false;\n            }\n            if ((result = detectValue(val[dimIndex])) != null) {\n                return result;\n            }\n        }\n    }\n\n    function detectValue(val) {\n        // Consider usage convenience, '1', '2' will be treated as \"number\".\n        // `isFinit('')` get `true`.\n        if (val != null && isFinite(val) && val !== '') {\n            return false;\n        }\n        else if (isString(val) && val !== '-') {\n            return true;\n        }\n    }\n\n    return false;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * ECharts global model\n *\n * @module {echarts/model/Global}\n */\n\n\n/**\n * Caution: If the mechanism should be changed some day, these cases\n * should be considered:\n *\n * (1) In `merge option` mode, if using the same option to call `setOption`\n * many times, the result should be the same (try our best to ensure that).\n * (2) In `merge option` mode, if a component has no id/name specified, it\n * will be merged by index, and the result sequence of the components is\n * consistent to the original sequence.\n * (3) `reset` feature (in toolbox). Find detailed info in comments about\n * `mergeOption` in module:echarts/model/OptionManager.\n */\n\nvar OPTION_INNER_KEY = '\\0_ec_inner';\n\n/**\n * @alias module:echarts/model/Global\n *\n * @param {Object} option\n * @param {module:echarts/model/Model} parentModel\n * @param {Object} theme\n */\nvar GlobalModel = Model.extend({\n\n    init: function (option, parentModel, theme, optionManager) {\n        theme = theme || {};\n\n        this.option = null; // Mark as not initialized.\n\n        /**\n         * @type {module:echarts/model/Model}\n         * @private\n         */\n        this._theme = new Model(theme);\n\n        /**\n         * @type {module:echarts/model/OptionManager}\n         */\n        this._optionManager = optionManager;\n    },\n\n    setOption: function (option, optionPreprocessorFuncs) {\n        assert$1(\n            !(OPTION_INNER_KEY in option),\n            'please use chart.getOption()'\n        );\n\n        this._optionManager.setOption(option, optionPreprocessorFuncs);\n\n        this.resetOption(null);\n    },\n\n    /**\n     * @param {string} type null/undefined: reset all.\n     *                      'recreate': force recreate all.\n     *                      'timeline': only reset timeline option\n     *                      'media': only reset media query option\n     * @return {boolean} Whether option changed.\n     */\n    resetOption: function (type) {\n        var optionChanged = false;\n        var optionManager = this._optionManager;\n\n        if (!type || type === 'recreate') {\n            var baseOption = optionManager.mountOption(type === 'recreate');\n\n            if (!this.option || type === 'recreate') {\n                initBase.call(this, baseOption);\n            }\n            else {\n                this.restoreData();\n                this.mergeOption(baseOption);\n            }\n            optionChanged = true;\n        }\n\n        if (type === 'timeline' || type === 'media') {\n            this.restoreData();\n        }\n\n        if (!type || type === 'recreate' || type === 'timeline') {\n            var timelineOption = optionManager.getTimelineOption(this);\n            timelineOption && (this.mergeOption(timelineOption), optionChanged = true);\n        }\n\n        if (!type || type === 'recreate' || type === 'media') {\n            var mediaOptions = optionManager.getMediaOption(this, this._api);\n            if (mediaOptions.length) {\n                each$1(mediaOptions, function (mediaOption) {\n                    this.mergeOption(mediaOption, optionChanged = true);\n                }, this);\n            }\n        }\n\n        return optionChanged;\n    },\n\n    /**\n     * @protected\n     */\n    mergeOption: function (newOption) {\n        var option = this.option;\n        var componentsMap = this._componentsMap;\n        var newCptTypes = [];\n\n        resetSourceDefaulter(this);\n\n        // If no component class, merge directly.\n        // For example: color, animaiton options, etc.\n        each$1(newOption, function (componentOption, mainType) {\n            if (componentOption == null) {\n                return;\n            }\n\n            if (!ComponentModel.hasClass(mainType)) {\n                // globalSettingTask.dirty();\n                option[mainType] = option[mainType] == null\n                    ? clone(componentOption)\n                    : merge(option[mainType], componentOption, true);\n            }\n            else if (mainType) {\n                newCptTypes.push(mainType);\n            }\n        });\n\n        ComponentModel.topologicalTravel(\n            newCptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this\n        );\n\n        function visitComponent(mainType, dependencies) {\n\n            var newCptOptionList = normalizeToArray(newOption[mainType]);\n\n            var mapResult = mappingToExists(\n                componentsMap.get(mainType), newCptOptionList\n            );\n\n            makeIdAndName(mapResult);\n\n            // Set mainType and complete subType.\n            each$1(mapResult, function (item, index) {\n                var opt = item.option;\n                if (isObject$1(opt)) {\n                    item.keyInfo.mainType = mainType;\n                    item.keyInfo.subType = determineSubType(mainType, opt, item.exist);\n                }\n            });\n\n            var dependentModels = getComponentsByTypes(\n                componentsMap, dependencies\n            );\n\n            option[mainType] = [];\n            componentsMap.set(mainType, []);\n\n            each$1(mapResult, function (resultItem, index) {\n                var componentModel = resultItem.exist;\n                var newCptOption = resultItem.option;\n\n                assert$1(\n                    isObject$1(newCptOption) || componentModel,\n                    'Empty component definition'\n                );\n\n                // Consider where is no new option and should be merged using {},\n                // see removeEdgeAndAdd in topologicalTravel and\n                // ComponentModel.getAllClassMainTypes.\n                if (!newCptOption) {\n                    componentModel.mergeOption({}, this);\n                    componentModel.optionUpdated({}, false);\n                }\n                else {\n                    var ComponentModelClass = ComponentModel.getClass(\n                        mainType, resultItem.keyInfo.subType, true\n                    );\n\n                    if (componentModel && componentModel instanceof ComponentModelClass) {\n                        componentModel.name = resultItem.keyInfo.name;\n                        // componentModel.settingTask && componentModel.settingTask.dirty();\n                        componentModel.mergeOption(newCptOption, this);\n                        componentModel.optionUpdated(newCptOption, false);\n                    }\n                    else {\n                        // PENDING Global as parent ?\n                        var extraOpt = extend(\n                            {\n                                dependentModels: dependentModels,\n                                componentIndex: index\n                            },\n                            resultItem.keyInfo\n                        );\n                        componentModel = new ComponentModelClass(\n                            newCptOption, this, this, extraOpt\n                        );\n                        extend(componentModel, extraOpt);\n                        componentModel.init(newCptOption, this, this, extraOpt);\n\n                        // Call optionUpdated after init.\n                        // newCptOption has been used as componentModel.option\n                        // and may be merged with theme and default, so pass null\n                        // to avoid confusion.\n                        componentModel.optionUpdated(null, true);\n                    }\n                }\n\n                componentsMap.get(mainType)[index] = componentModel;\n                option[mainType][index] = componentModel.option;\n            }, this);\n\n            // Backup series for filtering.\n            if (mainType === 'series') {\n                createSeriesIndices(this, componentsMap.get('series'));\n            }\n        }\n\n        this._seriesIndicesMap = createHashMap(\n            this._seriesIndices = this._seriesIndices || []\n        );\n    },\n\n    /**\n     * Get option for output (cloned option and inner info removed)\n     * @public\n     * @return {Object}\n     */\n    getOption: function () {\n        var option = clone(this.option);\n\n        each$1(option, function (opts, mainType) {\n            if (ComponentModel.hasClass(mainType)) {\n                var opts = normalizeToArray(opts);\n                for (var i = opts.length - 1; i >= 0; i--) {\n                    // Remove options with inner id.\n                    if (isIdInner(opts[i])) {\n                        opts.splice(i, 1);\n                    }\n                }\n                option[mainType] = opts;\n            }\n        });\n\n        delete option[OPTION_INNER_KEY];\n\n        return option;\n    },\n\n    /**\n     * @return {module:echarts/model/Model}\n     */\n    getTheme: function () {\n        return this._theme;\n    },\n\n    /**\n     * @param {string} mainType\n     * @param {number} [idx=0]\n     * @return {module:echarts/model/Component}\n     */\n    getComponent: function (mainType, idx) {\n        var list = this._componentsMap.get(mainType);\n        if (list) {\n            return list[idx || 0];\n        }\n    },\n\n    /**\n     * If none of index and id and name used, return all components with mainType.\n     * @param {Object} condition\n     * @param {string} condition.mainType\n     * @param {string} [condition.subType] If ignore, only query by mainType\n     * @param {number|Array.<number>} [condition.index] Either input index or id or name.\n     * @param {string|Array.<string>} [condition.id] Either input index or id or name.\n     * @param {string|Array.<string>} [condition.name] Either input index or id or name.\n     * @return {Array.<module:echarts/model/Component>}\n     */\n    queryComponents: function (condition) {\n        var mainType = condition.mainType;\n        if (!mainType) {\n            return [];\n        }\n\n        var index = condition.index;\n        var id = condition.id;\n        var name = condition.name;\n\n        var cpts = this._componentsMap.get(mainType);\n\n        if (!cpts || !cpts.length) {\n            return [];\n        }\n\n        var result;\n\n        if (index != null) {\n            if (!isArray(index)) {\n                index = [index];\n            }\n            result = filter(map(index, function (idx) {\n                return cpts[idx];\n            }), function (val) {\n                return !!val;\n            });\n        }\n        else if (id != null) {\n            var isIdArray = isArray(id);\n            result = filter(cpts, function (cpt) {\n                return (isIdArray && indexOf(id, cpt.id) >= 0)\n                    || (!isIdArray && cpt.id === id);\n            });\n        }\n        else if (name != null) {\n            var isNameArray = isArray(name);\n            result = filter(cpts, function (cpt) {\n                return (isNameArray && indexOf(name, cpt.name) >= 0)\n                    || (!isNameArray && cpt.name === name);\n            });\n        }\n        else {\n            // Return all components with mainType\n            result = cpts.slice();\n        }\n\n        return filterBySubType(result, condition);\n    },\n\n    /**\n     * The interface is different from queryComponents,\n     * which is convenient for inner usage.\n     *\n     * @usage\n     * var result = findComponents(\n     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}}\n     * );\n     * var result = findComponents(\n     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}}\n     * );\n     * var result = findComponents(\n     *     {mainType: 'series'},\n     *     function (model, index) {...}\n     * );\n     * // result like [component0, componnet1, ...]\n     *\n     * @param {Object} condition\n     * @param {string} condition.mainType Mandatory.\n     * @param {string} [condition.subType] Optional.\n     * @param {Object} [condition.query] like {xxxIndex, xxxId, xxxName},\n     *        where xxx is mainType.\n     *        If query attribute is null/undefined or has no index/id/name,\n     *        do not filtering by query conditions, which is convenient for\n     *        no-payload situations or when target of action is global.\n     * @param {Function} [condition.filter] parameter: component, return boolean.\n     * @return {Array.<module:echarts/model/Component>}\n     */\n    findComponents: function (condition) {\n        var query = condition.query;\n        var mainType = condition.mainType;\n\n        var queryCond = getQueryCond(query);\n        var result = queryCond\n            ? this.queryComponents(queryCond)\n            : this._componentsMap.get(mainType);\n\n        return doFilter(filterBySubType(result, condition));\n\n        function getQueryCond(q) {\n            var indexAttr = mainType + 'Index';\n            var idAttr = mainType + 'Id';\n            var nameAttr = mainType + 'Name';\n            return q && (\n                    q[indexAttr] != null\n                    || q[idAttr] != null\n                    || q[nameAttr] != null\n                )\n                ? {\n                    mainType: mainType,\n                    // subType will be filtered finally.\n                    index: q[indexAttr],\n                    id: q[idAttr],\n                    name: q[nameAttr]\n                }\n                : null;\n        }\n\n        function doFilter(res) {\n            return condition.filter\n                    ? filter(res, condition.filter)\n                    : res;\n        }\n    },\n\n    /**\n     * @usage\n     * eachComponent('legend', function (legendModel, index) {\n     *     ...\n     * });\n     * eachComponent(function (componentType, model, index) {\n     *     // componentType does not include subType\n     *     // (componentType is 'xxx' but not 'xxx.aa')\n     * });\n     * eachComponent(\n     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}},\n     *     function (model, index) {...}\n     * );\n     * eachComponent(\n     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}},\n     *     function (model, index) {...}\n     * );\n     *\n     * @param {string|Object=} mainType When mainType is object, the definition\n     *                                  is the same as the method 'findComponents'.\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachComponent: function (mainType, cb, context) {\n        var componentsMap = this._componentsMap;\n\n        if (typeof mainType === 'function') {\n            context = cb;\n            cb = mainType;\n            componentsMap.each(function (components, componentType) {\n                each$1(components, function (component, index) {\n                    cb.call(context, componentType, component, index);\n                });\n            });\n        }\n        else if (isString(mainType)) {\n            each$1(componentsMap.get(mainType), cb, context);\n        }\n        else if (isObject$1(mainType)) {\n            var queryResult = this.findComponents(mainType);\n            each$1(queryResult, cb, context);\n        }\n    },\n\n    /**\n     * @param {string} name\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeriesByName: function (name) {\n        var series = this._componentsMap.get('series');\n        return filter(series, function (oneSeries) {\n            return oneSeries.name === name;\n        });\n    },\n\n    /**\n     * @param {number} seriesIndex\n     * @return {module:echarts/model/Series}\n     */\n    getSeriesByIndex: function (seriesIndex) {\n        return this._componentsMap.get('series')[seriesIndex];\n    },\n\n    /**\n     * Get series list before filtered by type.\n     * FIXME: rename to getRawSeriesByType?\n     *\n     * @param {string} subType\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeriesByType: function (subType) {\n        var series = this._componentsMap.get('series');\n        return filter(series, function (oneSeries) {\n            return oneSeries.subType === subType;\n        });\n    },\n\n    /**\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeries: function () {\n        return this._componentsMap.get('series').slice();\n    },\n\n    /**\n     * @return {number}\n     */\n    getSeriesCount: function () {\n        return this._componentsMap.get('series').length;\n    },\n\n    /**\n     * After filtering, series may be different\n     * frome raw series.\n     *\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachSeries: function (cb, context) {\n        assertSeriesInitialized(this);\n        each$1(this._seriesIndices, function (rawSeriesIndex) {\n            var series = this._componentsMap.get('series')[rawSeriesIndex];\n            cb.call(context, series, rawSeriesIndex);\n        }, this);\n    },\n\n    /**\n     * Iterate raw series before filtered.\n     *\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachRawSeries: function (cb, context) {\n        each$1(this._componentsMap.get('series'), cb, context);\n    },\n\n    /**\n     * After filtering, series may be different.\n     * frome raw series.\n     *\n     * @parma {string} subType\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachSeriesByType: function (subType, cb, context) {\n        assertSeriesInitialized(this);\n        each$1(this._seriesIndices, function (rawSeriesIndex) {\n            var series = this._componentsMap.get('series')[rawSeriesIndex];\n            if (series.subType === subType) {\n                cb.call(context, series, rawSeriesIndex);\n            }\n        }, this);\n    },\n\n    /**\n     * Iterate raw series before filtered of given type.\n     *\n     * @parma {string} subType\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachRawSeriesByType: function (subType, cb, context) {\n        return each$1(this.getSeriesByType(subType), cb, context);\n    },\n\n    /**\n     * @param {module:echarts/model/Series} seriesModel\n     */\n    isSeriesFiltered: function (seriesModel) {\n        assertSeriesInitialized(this);\n        return this._seriesIndicesMap.get(seriesModel.componentIndex) == null;\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getCurrentSeriesIndices: function () {\n        return (this._seriesIndices || []).slice();\n    },\n\n    /**\n     * @param {Function} cb\n     * @param {*} context\n     */\n    filterSeries: function (cb, context) {\n        assertSeriesInitialized(this);\n        var filteredSeries = filter(\n            this._componentsMap.get('series'), cb, context\n        );\n        createSeriesIndices(this, filteredSeries);\n    },\n\n    restoreData: function (payload) {\n        var componentsMap = this._componentsMap;\n\n        createSeriesIndices(this, componentsMap.get('series'));\n\n        var componentTypes = [];\n        componentsMap.each(function (components, componentType) {\n            componentTypes.push(componentType);\n        });\n\n        ComponentModel.topologicalTravel(\n            componentTypes,\n            ComponentModel.getAllClassMainTypes(),\n            function (componentType, dependencies) {\n                each$1(componentsMap.get(componentType), function (component) {\n                    (componentType !== 'series' || !isNotTargetSeries(component, payload))\n                        && component.restoreData();\n                });\n            }\n        );\n    }\n\n});\n\nfunction isNotTargetSeries(seriesModel, payload) {\n    if (payload) {\n        var index = payload.seiresIndex;\n        var id = payload.seriesId;\n        var name = payload.seriesName;\n        return (index != null && seriesModel.componentIndex !== index)\n            || (id != null && seriesModel.id !== id)\n            || (name != null && seriesModel.name !== name);\n    }\n}\n\n/**\n * @inner\n */\nfunction mergeTheme(option, theme) {\n    // PENDING\n    // NOT use `colorLayer` in theme if option has `color`\n    var notMergeColorLayer = option.color && !option.colorLayer;\n\n    each$1(theme, function (themeItem, name) {\n        if (name === 'colorLayer' && notMergeColorLayer) {\n            return;\n        }\n        // 如果有 component model 则把具体的 merge 逻辑交给该 model 处理\n        if (!ComponentModel.hasClass(name)) {\n            if (typeof themeItem === 'object') {\n                option[name] = !option[name]\n                    ? clone(themeItem)\n                    : merge(option[name], themeItem, false);\n            }\n            else {\n                if (option[name] == null) {\n                    option[name] = themeItem;\n                }\n            }\n        }\n    });\n}\n\nfunction initBase(baseOption) {\n    baseOption = baseOption;\n\n    // Using OPTION_INNER_KEY to mark that this option can not be used outside,\n    // i.e. `chart.setOption(chart.getModel().option);` is forbiden.\n    this.option = {};\n    this.option[OPTION_INNER_KEY] = 1;\n\n    /**\n     * Init with series: [], in case of calling findSeries method\n     * before series initialized.\n     * @type {Object.<string, Array.<module:echarts/model/Model>>}\n     * @private\n     */\n    this._componentsMap = createHashMap({series: []});\n\n    /**\n     * Mapping between filtered series list and raw series list.\n     * key: filtered series indices, value: raw series indices.\n     * @type {Array.<nubmer>}\n     * @private\n     */\n    this._seriesIndices;\n\n    this._seriesIndicesMap;\n\n    mergeTheme(baseOption, this._theme.option);\n\n    // TODO Needs clone when merging to the unexisted property\n    merge(baseOption, globalDefault, false);\n\n    this.mergeOption(baseOption);\n}\n\n/**\n * @inner\n * @param {Array.<string>|string} types model types\n * @return {Object} key: {string} type, value: {Array.<Object>} models\n */\nfunction getComponentsByTypes(componentsMap, types) {\n    if (!isArray(types)) {\n        types = types ? [types] : [];\n    }\n\n    var ret = {};\n    each$1(types, function (type) {\n        ret[type] = (componentsMap.get(type) || []).slice();\n    });\n\n    return ret;\n}\n\n/**\n * @inner\n */\nfunction determineSubType(mainType, newCptOption, existComponent) {\n    var subType = newCptOption.type\n        ? newCptOption.type\n        : existComponent\n        ? existComponent.subType\n        // Use determineSubType only when there is no existComponent.\n        : ComponentModel.determineSubType(mainType, newCptOption);\n\n    // tooltip, markline, markpoint may always has no subType\n    return subType;\n}\n\n/**\n * @inner\n */\nfunction createSeriesIndices(ecModel, seriesModels) {\n    ecModel._seriesIndicesMap = createHashMap(\n        ecModel._seriesIndices = map(seriesModels, function (series) {\n            return series.componentIndex;\n        }) || []\n    );\n}\n\n/**\n * @inner\n */\nfunction filterBySubType(components, condition) {\n    // Using hasOwnProperty for restrict. Consider\n    // subType is undefined in user payload.\n    return condition.hasOwnProperty('subType')\n        ? filter(components, function (cpt) {\n            return cpt.subType === condition.subType;\n        })\n        : components;\n}\n\n/**\n * @inner\n */\nfunction assertSeriesInitialized(ecModel) {\n    // Components that use _seriesIndices should depends on series component,\n    // which make sure that their initialization is after series.\n    if (__DEV__) {\n        if (!ecModel._seriesIndices) {\n            throw new Error('Option should contains series.');\n        }\n    }\n}\n\nmixin(GlobalModel, colorPaletteMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar echartsAPIList = [\n    'getDom', 'getZr', 'getWidth', 'getHeight', 'getDevicePixelRatio', 'dispatchAction', 'isDisposed',\n    'on', 'off', 'getDataURL', 'getConnectedDataURL', 'getModel', 'getOption',\n    'getViewOfComponentModel', 'getViewOfSeriesModel'\n];\n// And `getCoordinateSystems` and `getComponentByElement` will be injected in echarts.js\n\nfunction ExtensionAPI(chartInstance) {\n    each$1(echartsAPIList, function (name) {\n        this[name] = bind(chartInstance[name], chartInstance);\n    }, this);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar coordinateSystemCreators = {};\n\nfunction CoordinateSystemManager() {\n\n    this._coordinateSystems = [];\n}\n\nCoordinateSystemManager.prototype = {\n\n    constructor: CoordinateSystemManager,\n\n    create: function (ecModel, api) {\n        var coordinateSystems = [];\n        each$1(coordinateSystemCreators, function (creater, type) {\n            var list = creater.create(ecModel, api);\n            coordinateSystems = coordinateSystems.concat(list || []);\n        });\n\n        this._coordinateSystems = coordinateSystems;\n    },\n\n    update: function (ecModel, api) {\n        each$1(this._coordinateSystems, function (coordSys) {\n            coordSys.update && coordSys.update(ecModel, api);\n        });\n    },\n\n    getCoordinateSystems: function () {\n        return this._coordinateSystems.slice();\n    }\n};\n\nCoordinateSystemManager.register = function (type, coordinateSystemCreator) {\n    coordinateSystemCreators[type] = coordinateSystemCreator;\n};\n\nCoordinateSystemManager.get = function (type) {\n    return coordinateSystemCreators[type];\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * ECharts option manager\n *\n * @module {echarts/model/OptionManager}\n */\n\n\nvar each$4 = each$1;\nvar clone$3 = clone;\nvar map$1 = map;\nvar merge$1 = merge;\n\nvar QUERY_REG = /^(min|max)?(.+)$/;\n\n/**\n * TERM EXPLANATIONS:\n *\n * [option]:\n *\n *     An object that contains definitions of components. For example:\n *     var option = {\n *         title: {...},\n *         legend: {...},\n *         visualMap: {...},\n *         series: [\n *             {data: [...]},\n *             {data: [...]},\n *             ...\n *         ]\n *     };\n *\n * [rawOption]:\n *\n *     An object input to echarts.setOption. 'rawOption' may be an\n *     'option', or may be an object contains multi-options. For example:\n *     var option = {\n *         baseOption: {\n *             title: {...},\n *             legend: {...},\n *             series: [\n *                 {data: [...]},\n *                 {data: [...]},\n *                 ...\n *             ]\n *         },\n *         timeline: {...},\n *         options: [\n *             {title: {...}, series: {data: [...]}},\n *             {title: {...}, series: {data: [...]}},\n *             ...\n *         ],\n *         media: [\n *             {\n *                 query: {maxWidth: 320},\n *                 option: {series: {x: 20}, visualMap: {show: false}}\n *             },\n *             {\n *                 query: {minWidth: 320, maxWidth: 720},\n *                 option: {series: {x: 500}, visualMap: {show: true}}\n *             },\n *             {\n *                 option: {series: {x: 1200}, visualMap: {show: true}}\n *             }\n *         ]\n *     };\n *\n * @alias module:echarts/model/OptionManager\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction OptionManager(api) {\n\n    /**\n     * @private\n     * @type {module:echarts/ExtensionAPI}\n     */\n    this._api = api;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._timelineOptions = [];\n\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    this._mediaList = [];\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._mediaDefault;\n\n    /**\n     * -1, means default.\n     * empty means no media.\n     * @private\n     * @type {Array.<number>}\n     */\n    this._currentMediaIndices = [];\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._optionBackup;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._newBaseOption;\n}\n\n// timeline.notMerge is not supported in ec3. Firstly there is rearly\n// case that notMerge is needed. Secondly supporting 'notMerge' requires\n// rawOption cloned and backuped when timeline changed, which does no\n// good to performance. What's more, that both timeline and setOption\n// method supply 'notMerge' brings complex and some problems.\n// Consider this case:\n// (step1) chart.setOption({timeline: {notMerge: false}, ...}, false);\n// (step2) chart.setOption({timeline: {notMerge: true}, ...}, false);\n\nOptionManager.prototype = {\n\n    constructor: OptionManager,\n\n    /**\n     * @public\n     * @param {Object} rawOption Raw option.\n     * @param {module:echarts/model/Global} ecModel\n     * @param {Array.<Function>} optionPreprocessorFuncs\n     * @return {Object} Init option\n     */\n    setOption: function (rawOption, optionPreprocessorFuncs) {\n        if (rawOption) {\n            // That set dat primitive is dangerous if user reuse the data when setOption again.\n            each$1(normalizeToArray(rawOption.series), function (series) {\n                series && series.data && isTypedArray(series.data) && setAsPrimitive(series.data);\n            });\n        }\n\n        // Caution: some series modify option data, if do not clone,\n        // it should ensure that the repeat modify correctly\n        // (create a new object when modify itself).\n        rawOption = clone$3(rawOption, true);\n\n        // FIXME\n        // 如果 timeline options 或者 media 中设置了某个属性，而baseOption中没有设置，则进行警告。\n\n        var oldOptionBackup = this._optionBackup;\n        var newParsedOption = parseRawOption.call(\n            this, rawOption, optionPreprocessorFuncs, !oldOptionBackup\n        );\n        this._newBaseOption = newParsedOption.baseOption;\n\n        // For setOption at second time (using merge mode);\n        if (oldOptionBackup) {\n            // Only baseOption can be merged.\n            mergeOption(oldOptionBackup.baseOption, newParsedOption.baseOption);\n\n            // For simplicity, timeline options and media options do not support merge,\n            // that is, if you `setOption` twice and both has timeline options, the latter\n            // timeline opitons will not be merged to the formers, but just substitude them.\n            if (newParsedOption.timelineOptions.length) {\n                oldOptionBackup.timelineOptions = newParsedOption.timelineOptions;\n            }\n            if (newParsedOption.mediaList.length) {\n                oldOptionBackup.mediaList = newParsedOption.mediaList;\n            }\n            if (newParsedOption.mediaDefault) {\n                oldOptionBackup.mediaDefault = newParsedOption.mediaDefault;\n            }\n        }\n        else {\n            this._optionBackup = newParsedOption;\n        }\n    },\n\n    /**\n     * @param {boolean} isRecreate\n     * @return {Object}\n     */\n    mountOption: function (isRecreate) {\n        var optionBackup = this._optionBackup;\n\n        // TODO\n        // 如果没有reset功能则不clone。\n\n        this._timelineOptions = map$1(optionBackup.timelineOptions, clone$3);\n        this._mediaList = map$1(optionBackup.mediaList, clone$3);\n        this._mediaDefault = clone$3(optionBackup.mediaDefault);\n        this._currentMediaIndices = [];\n\n        return clone$3(isRecreate\n            // this._optionBackup.baseOption, which is created at the first `setOption`\n            // called, and is merged into every new option by inner method `mergeOption`\n            // each time `setOption` called, can be only used in `isRecreate`, because\n            // its reliability is under suspicion. In other cases option merge is\n            // performed by `model.mergeOption`.\n            ? optionBackup.baseOption : this._newBaseOption\n        );\n    },\n\n    /**\n     * @param {module:echarts/model/Global} ecModel\n     * @return {Object}\n     */\n    getTimelineOption: function (ecModel) {\n        var option;\n        var timelineOptions = this._timelineOptions;\n\n        if (timelineOptions.length) {\n            // getTimelineOption can only be called after ecModel inited,\n            // so we can get currentIndex from timelineModel.\n            var timelineModel = ecModel.getComponent('timeline');\n            if (timelineModel) {\n                option = clone$3(\n                    timelineOptions[timelineModel.getCurrentIndex()],\n                    true\n                );\n            }\n        }\n\n        return option;\n    },\n\n    /**\n     * @param {module:echarts/model/Global} ecModel\n     * @return {Array.<Object>}\n     */\n    getMediaOption: function (ecModel) {\n        var ecWidth = this._api.getWidth();\n        var ecHeight = this._api.getHeight();\n        var mediaList = this._mediaList;\n        var mediaDefault = this._mediaDefault;\n        var indices = [];\n        var result = [];\n\n        // No media defined.\n        if (!mediaList.length && !mediaDefault) {\n            return result;\n        }\n\n        // Multi media may be applied, the latter defined media has higher priority.\n        for (var i = 0, len = mediaList.length; i < len; i++) {\n            if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) {\n                indices.push(i);\n            }\n        }\n\n        // FIXME\n        // 是否mediaDefault应该强制用户设置，否则可能修改不能回归。\n        if (!indices.length && mediaDefault) {\n            indices = [-1];\n        }\n\n        if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) {\n            result = map$1(indices, function (index) {\n                return clone$3(\n                    index === -1 ? mediaDefault.option : mediaList[index].option\n                );\n            });\n        }\n        // Otherwise return nothing.\n\n        this._currentMediaIndices = indices;\n\n        return result;\n    }\n};\n\nfunction parseRawOption(rawOption, optionPreprocessorFuncs, isNew) {\n    var timelineOptions = [];\n    var mediaList = [];\n    var mediaDefault;\n    var baseOption;\n\n    // Compatible with ec2.\n    var timelineOpt = rawOption.timeline;\n\n    if (rawOption.baseOption) {\n        baseOption = rawOption.baseOption;\n    }\n\n    // For timeline\n    if (timelineOpt || rawOption.options) {\n        baseOption = baseOption || {};\n        timelineOptions = (rawOption.options || []).slice();\n    }\n\n    // For media query\n    if (rawOption.media) {\n        baseOption = baseOption || {};\n        var media = rawOption.media;\n        each$4(media, function (singleMedia) {\n            if (singleMedia && singleMedia.option) {\n                if (singleMedia.query) {\n                    mediaList.push(singleMedia);\n                }\n                else if (!mediaDefault) {\n                    // Use the first media default.\n                    mediaDefault = singleMedia;\n                }\n            }\n        });\n    }\n\n    // For normal option\n    if (!baseOption) {\n        baseOption = rawOption;\n    }\n\n    // Set timelineOpt to baseOption in ec3,\n    // which is convenient for merge option.\n    if (!baseOption.timeline) {\n        baseOption.timeline = timelineOpt;\n    }\n\n    // Preprocess.\n    each$4([baseOption].concat(timelineOptions)\n        .concat(map(mediaList, function (media) {\n            return media.option;\n        })),\n        function (option) {\n            each$4(optionPreprocessorFuncs, function (preProcess) {\n                preProcess(option, isNew);\n            });\n        }\n    );\n\n    return {\n        baseOption: baseOption,\n        timelineOptions: timelineOptions,\n        mediaDefault: mediaDefault,\n        mediaList: mediaList\n    };\n}\n\n/**\n * @see <http://www.w3.org/TR/css3-mediaqueries/#media1>\n * Support: width, height, aspectRatio\n * Can use max or min as prefix.\n */\nfunction applyMediaQuery(query, ecWidth, ecHeight) {\n    var realMap = {\n        width: ecWidth,\n        height: ecHeight,\n        aspectratio: ecWidth / ecHeight // lowser case for convenientce.\n    };\n\n    var applicatable = true;\n\n    each$1(query, function (value, attr) {\n        var matched = attr.match(QUERY_REG);\n\n        if (!matched || !matched[1] || !matched[2]) {\n            return;\n        }\n\n        var operator = matched[1];\n        var realAttr = matched[2].toLowerCase();\n\n        if (!compare(realMap[realAttr], value, operator)) {\n            applicatable = false;\n        }\n    });\n\n    return applicatable;\n}\n\nfunction compare(real, expect, operator) {\n    if (operator === 'min') {\n        return real >= expect;\n    }\n    else if (operator === 'max') {\n        return real <= expect;\n    }\n    else { // Equals\n        return real === expect;\n    }\n}\n\nfunction indicesEquals(indices1, indices2) {\n    // indices is always order by asc and has only finite number.\n    return indices1.join(',') === indices2.join(',');\n}\n\n/**\n * Consider case:\n * `chart.setOption(opt1);`\n * Then user do some interaction like dataZoom, dataView changing.\n * `chart.setOption(opt2);`\n * Then user press 'reset button' in toolbox.\n *\n * After doing that all of the interaction effects should be reset, the\n * chart should be the same as the result of invoke\n * `chart.setOption(opt1); chart.setOption(opt2);`.\n *\n * Although it is not able ensure that\n * `chart.setOption(opt1); chart.setOption(opt2);` is equivalents to\n * `chart.setOption(merge(opt1, opt2));` exactly,\n * this might be the only simple way to implement that feature.\n *\n * MEMO: We've considered some other approaches:\n * 1. Each model handle its self restoration but not uniform treatment.\n *     (Too complex in logic and error-prone)\n * 2. Use a shadow ecModel. (Performace expensive)\n */\nfunction mergeOption(oldOption, newOption) {\n    newOption = newOption || {};\n\n    each$4(newOption, function (newCptOpt, mainType) {\n        if (newCptOpt == null) {\n            return;\n        }\n\n        var oldCptOpt = oldOption[mainType];\n\n        if (!ComponentModel.hasClass(mainType)) {\n            oldOption[mainType] = merge$1(oldCptOpt, newCptOpt, true);\n        }\n        else {\n            newCptOpt = normalizeToArray(newCptOpt);\n            oldCptOpt = normalizeToArray(oldCptOpt);\n\n            var mapResult = mappingToExists(oldCptOpt, newCptOpt);\n\n            oldOption[mainType] = map$1(mapResult, function (item) {\n                return (item.option && item.exist)\n                    ? merge$1(item.exist, item.option, true)\n                    : (item.exist || item.option);\n            });\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$5 = each$1;\nvar isObject$3 = isObject$1;\n\nvar POSSIBLE_STYLES = [\n    'areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle',\n    'chordStyle', 'label', 'labelLine'\n];\n\nfunction compatEC2ItemStyle(opt) {\n    var itemStyleOpt = opt && opt.itemStyle;\n    if (!itemStyleOpt) {\n        return;\n    }\n    for (var i = 0, len = POSSIBLE_STYLES.length; i < len; i++) {\n        var styleName = POSSIBLE_STYLES[i];\n        var normalItemStyleOpt = itemStyleOpt.normal;\n        var emphasisItemStyleOpt = itemStyleOpt.emphasis;\n        if (normalItemStyleOpt && normalItemStyleOpt[styleName]) {\n            opt[styleName] = opt[styleName] || {};\n            if (!opt[styleName].normal) {\n                opt[styleName].normal = normalItemStyleOpt[styleName];\n            }\n            else {\n                merge(opt[styleName].normal, normalItemStyleOpt[styleName]);\n            }\n            normalItemStyleOpt[styleName] = null;\n        }\n        if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) {\n            opt[styleName] = opt[styleName] || {};\n            if (!opt[styleName].emphasis) {\n                opt[styleName].emphasis = emphasisItemStyleOpt[styleName];\n            }\n            else {\n                merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]);\n            }\n            emphasisItemStyleOpt[styleName] = null;\n        }\n    }\n}\n\nfunction convertNormalEmphasis(opt, optType, useExtend) {\n    if (opt && opt[optType] && (opt[optType].normal || opt[optType].emphasis)) {\n        var normalOpt = opt[optType].normal;\n        var emphasisOpt = opt[optType].emphasis;\n\n        if (normalOpt) {\n            // Timeline controlStyle has other properties besides normal and emphasis\n            if (useExtend) {\n                opt[optType].normal = opt[optType].emphasis = null;\n                defaults(opt[optType], normalOpt);\n            }\n            else {\n                opt[optType] = normalOpt;\n            }\n        }\n        if (emphasisOpt) {\n            opt.emphasis = opt.emphasis || {};\n            opt.emphasis[optType] = emphasisOpt;\n        }\n    }\n}\nfunction removeEC3NormalStatus(opt) {\n    convertNormalEmphasis(opt, 'itemStyle');\n    convertNormalEmphasis(opt, 'lineStyle');\n    convertNormalEmphasis(opt, 'areaStyle');\n    convertNormalEmphasis(opt, 'label');\n    convertNormalEmphasis(opt, 'labelLine');\n    // treemap\n    convertNormalEmphasis(opt, 'upperLabel');\n    // graph\n    convertNormalEmphasis(opt, 'edgeLabel');\n}\n\nfunction compatTextStyle(opt, propName) {\n    // Check whether is not object (string\\null\\undefined ...)\n    var labelOptSingle = isObject$3(opt) && opt[propName];\n    var textStyle = isObject$3(labelOptSingle) && labelOptSingle.textStyle;\n    if (textStyle) {\n        for (var i = 0, len = TEXT_STYLE_OPTIONS.length; i < len; i++) {\n            var propName = TEXT_STYLE_OPTIONS[i];\n            if (textStyle.hasOwnProperty(propName)) {\n                labelOptSingle[propName] = textStyle[propName];\n            }\n        }\n    }\n}\n\nfunction compatEC3CommonStyles(opt) {\n    if (opt) {\n        removeEC3NormalStatus(opt);\n        compatTextStyle(opt, 'label');\n        opt.emphasis && compatTextStyle(opt.emphasis, 'label');\n    }\n}\n\nfunction processSeries(seriesOpt) {\n    if (!isObject$3(seriesOpt)) {\n        return;\n    }\n\n    compatEC2ItemStyle(seriesOpt);\n    removeEC3NormalStatus(seriesOpt);\n\n    compatTextStyle(seriesOpt, 'label');\n    // treemap\n    compatTextStyle(seriesOpt, 'upperLabel');\n    // graph\n    compatTextStyle(seriesOpt, 'edgeLabel');\n    if (seriesOpt.emphasis) {\n        compatTextStyle(seriesOpt.emphasis, 'label');\n        // treemap\n        compatTextStyle(seriesOpt.emphasis, 'upperLabel');\n        // graph\n        compatTextStyle(seriesOpt.emphasis, 'edgeLabel');\n    }\n\n    var markPoint = seriesOpt.markPoint;\n    if (markPoint) {\n        compatEC2ItemStyle(markPoint);\n        compatEC3CommonStyles(markPoint);\n    }\n\n    var markLine = seriesOpt.markLine;\n    if (markLine) {\n        compatEC2ItemStyle(markLine);\n        compatEC3CommonStyles(markLine);\n    }\n\n    var markArea = seriesOpt.markArea;\n    if (markArea) {\n        compatEC3CommonStyles(markArea);\n    }\n\n    var data = seriesOpt.data;\n\n    // Break with ec3: if `setOption` again, there may be no `type` in option,\n    // then the backward compat based on option type will not be performed.\n\n    if (seriesOpt.type === 'graph') {\n        data = data || seriesOpt.nodes;\n        var edgeData = seriesOpt.links || seriesOpt.edges;\n        if (edgeData && !isTypedArray(edgeData)) {\n            for (var i = 0; i < edgeData.length; i++) {\n                compatEC3CommonStyles(edgeData[i]);\n            }\n        }\n        each$1(seriesOpt.categories, function (opt) {\n            removeEC3NormalStatus(opt);\n        });\n    }\n\n    if (data && !isTypedArray(data)) {\n        for (var i = 0; i < data.length; i++) {\n            compatEC3CommonStyles(data[i]);\n        }\n    }\n\n    // mark point data\n    var markPoint = seriesOpt.markPoint;\n    if (markPoint && markPoint.data) {\n        var mpData = markPoint.data;\n        for (var i = 0; i < mpData.length; i++) {\n            compatEC3CommonStyles(mpData[i]);\n        }\n    }\n    // mark line data\n    var markLine = seriesOpt.markLine;\n    if (markLine && markLine.data) {\n        var mlData = markLine.data;\n        for (var i = 0; i < mlData.length; i++) {\n            if (isArray(mlData[i])) {\n                compatEC3CommonStyles(mlData[i][0]);\n                compatEC3CommonStyles(mlData[i][1]);\n            }\n            else {\n                compatEC3CommonStyles(mlData[i]);\n            }\n        }\n    }\n\n    // Series\n    if (seriesOpt.type === 'gauge') {\n        compatTextStyle(seriesOpt, 'axisLabel');\n        compatTextStyle(seriesOpt, 'title');\n        compatTextStyle(seriesOpt, 'detail');\n    }\n    else if (seriesOpt.type === 'treemap') {\n        convertNormalEmphasis(seriesOpt.breadcrumb, 'itemStyle');\n        each$1(seriesOpt.levels, function (opt) {\n            removeEC3NormalStatus(opt);\n        });\n    }\n    else if (seriesOpt.type === 'tree') {\n        removeEC3NormalStatus(seriesOpt.leaves);\n    }\n    // sunburst starts from ec4, so it does not need to compat levels.\n}\n\nfunction toArr(o) {\n    return isArray(o) ? o : o ? [o] : [];\n}\n\nfunction toObj(o) {\n    return (isArray(o) ? o[0] : o) || {};\n}\n\nvar compatStyle = function (option, isTheme) {\n    each$5(toArr(option.series), function (seriesOpt) {\n        isObject$3(seriesOpt) && processSeries(seriesOpt);\n    });\n\n    var axes = ['xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'parallelAxis', 'radar'];\n    isTheme && axes.push('valueAxis', 'categoryAxis', 'logAxis', 'timeAxis');\n\n    each$5(\n        axes,\n        function (axisName) {\n            each$5(toArr(option[axisName]), function (axisOpt) {\n                if (axisOpt) {\n                    compatTextStyle(axisOpt, 'axisLabel');\n                    compatTextStyle(axisOpt.axisPointer, 'label');\n                }\n            });\n        }\n    );\n\n    each$5(toArr(option.parallel), function (parallelOpt) {\n        var parallelAxisDefault = parallelOpt && parallelOpt.parallelAxisDefault;\n        compatTextStyle(parallelAxisDefault, 'axisLabel');\n        compatTextStyle(parallelAxisDefault && parallelAxisDefault.axisPointer, 'label');\n    });\n\n    each$5(toArr(option.calendar), function (calendarOpt) {\n        convertNormalEmphasis(calendarOpt, 'itemStyle');\n        compatTextStyle(calendarOpt, 'dayLabel');\n        compatTextStyle(calendarOpt, 'monthLabel');\n        compatTextStyle(calendarOpt, 'yearLabel');\n    });\n\n    // radar.name.textStyle\n    each$5(toArr(option.radar), function (radarOpt) {\n        compatTextStyle(radarOpt, 'name');\n    });\n\n    each$5(toArr(option.geo), function (geoOpt) {\n        if (isObject$3(geoOpt)) {\n            compatEC3CommonStyles(geoOpt);\n            each$5(toArr(geoOpt.regions), function (regionObj) {\n                compatEC3CommonStyles(regionObj);\n            });\n        }\n    });\n\n    each$5(toArr(option.timeline), function (timelineOpt) {\n        compatEC3CommonStyles(timelineOpt);\n        convertNormalEmphasis(timelineOpt, 'label');\n        convertNormalEmphasis(timelineOpt, 'itemStyle');\n        convertNormalEmphasis(timelineOpt, 'controlStyle', true);\n\n        var data = timelineOpt.data;\n        isArray(data) && each$1(data, function (item) {\n            if (isObject$1(item)) {\n                convertNormalEmphasis(item, 'label');\n                convertNormalEmphasis(item, 'itemStyle');\n            }\n        });\n    });\n\n    each$5(toArr(option.toolbox), function (toolboxOpt) {\n        convertNormalEmphasis(toolboxOpt, 'iconStyle');\n        each$5(toolboxOpt.feature, function (featureOpt) {\n            convertNormalEmphasis(featureOpt, 'iconStyle');\n        });\n    });\n\n    compatTextStyle(toObj(option.axisPointer), 'label');\n    compatTextStyle(toObj(option.tooltip).axisPointer, 'label');\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Compatitable with 2.0\n\nfunction get(opt, path) {\n    path = path.split(',');\n    var obj = opt;\n    for (var i = 0; i < path.length; i++) {\n        obj = obj && obj[path[i]];\n        if (obj == null) {\n            break;\n        }\n    }\n    return obj;\n}\n\nfunction set$1(opt, path, val, overwrite) {\n    path = path.split(',');\n    var obj = opt;\n    var key;\n    for (var i = 0; i < path.length - 1; i++) {\n        key = path[i];\n        if (obj[key] == null) {\n            obj[key] = {};\n        }\n        obj = obj[key];\n    }\n    if (overwrite || obj[path[i]] == null) {\n        obj[path[i]] = val;\n    }\n}\n\nfunction compatLayoutProperties(option) {\n    each$1(LAYOUT_PROPERTIES, function (prop) {\n        if (prop[0] in option && !(prop[1] in option)) {\n            option[prop[1]] = option[prop[0]];\n        }\n    });\n}\n\nvar LAYOUT_PROPERTIES = [\n    ['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom']\n];\n\nvar COMPATITABLE_COMPONENTS = [\n    'grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline'\n];\n\nvar backwardCompat = function (option, isTheme) {\n    compatStyle(option, isTheme);\n\n    // Make sure series array for model initialization.\n    option.series = normalizeToArray(option.series);\n\n    each$1(option.series, function (seriesOpt) {\n        if (!isObject$1(seriesOpt)) {\n            return;\n        }\n\n        var seriesType = seriesOpt.type;\n\n        if (seriesType === 'pie' || seriesType === 'gauge') {\n            if (seriesOpt.clockWise != null) {\n                seriesOpt.clockwise = seriesOpt.clockWise;\n            }\n        }\n        if (seriesType === 'gauge') {\n            var pointerColor = get(seriesOpt, 'pointer.color');\n            pointerColor != null\n                && set$1(seriesOpt, 'itemStyle.normal.color', pointerColor);\n        }\n\n        compatLayoutProperties(seriesOpt);\n    });\n\n    // dataRange has changed to visualMap\n    if (option.dataRange) {\n        option.visualMap = option.dataRange;\n    }\n\n    each$1(COMPATITABLE_COMPONENTS, function (componentName) {\n        var options = option[componentName];\n        if (options) {\n            if (!isArray(options)) {\n                options = [options];\n            }\n            each$1(options, function (option) {\n                compatLayoutProperties(option);\n            });\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (1) [Caution]: the logic is correct based on the premises:\n//     data processing stage is blocked in stream.\n//     See <module:echarts/stream/Scheduler#performDataProcessorTasks>\n// (2) Only register once when import repeatly.\n//     Should be executed before after series filtered and before stack calculation.\nvar dataStack = function (ecModel) {\n    var stackInfoMap = createHashMap();\n    ecModel.eachSeries(function (seriesModel) {\n        var stack = seriesModel.get('stack');\n        // Compatibal: when `stack` is set as '', do not stack.\n        if (stack) {\n            var stackInfoList = stackInfoMap.get(stack) || stackInfoMap.set(stack, []);\n            var data = seriesModel.getData();\n\n            var stackInfo = {\n                // Used for calculate axis extent automatically.\n                stackResultDimension: data.getCalculationInfo('stackResultDimension'),\n                stackedOverDimension: data.getCalculationInfo('stackedOverDimension'),\n                stackedDimension: data.getCalculationInfo('stackedDimension'),\n                stackedByDimension: data.getCalculationInfo('stackedByDimension'),\n                isStackedByIndex: data.getCalculationInfo('isStackedByIndex'),\n                data: data,\n                seriesModel: seriesModel\n            };\n\n            // If stacked on axis that do not support data stack.\n            if (!stackInfo.stackedDimension\n                || !(stackInfo.isStackedByIndex || stackInfo.stackedByDimension)\n            ) {\n                return;\n            }\n\n            stackInfoList.length && data.setCalculationInfo(\n                'stackedOnSeries', stackInfoList[stackInfoList.length - 1].seriesModel\n            );\n\n            stackInfoList.push(stackInfo);\n        }\n    });\n\n    stackInfoMap.each(calculateStack);\n};\n\nfunction calculateStack(stackInfoList) {\n    each$1(stackInfoList, function (targetStackInfo, idxInStack) {\n        var resultVal = [];\n        var resultNaN = [NaN, NaN];\n        var dims = [targetStackInfo.stackResultDimension, targetStackInfo.stackedOverDimension];\n        var targetData = targetStackInfo.data;\n        var isStackedByIndex = targetStackInfo.isStackedByIndex;\n\n        // Should not write on raw data, because stack series model list changes\n        // depending on legend selection.\n        var newData = targetData.map(dims, function (v0, v1, dataIndex) {\n            var sum = targetData.get(targetStackInfo.stackedDimension, dataIndex);\n\n            // Consider `connectNulls` of line area, if value is NaN, stackedOver\n            // should also be NaN, to draw a appropriate belt area.\n            if (isNaN(sum)) {\n                return resultNaN;\n            }\n\n            var byValue;\n            var stackedDataRawIndex;\n\n            if (isStackedByIndex) {\n                stackedDataRawIndex = targetData.getRawIndex(dataIndex);\n            }\n            else {\n                byValue = targetData.get(targetStackInfo.stackedByDimension, dataIndex);\n            }\n\n            // If stackOver is NaN, chart view will render point on value start.\n            var stackedOver = NaN;\n\n            for (var j = idxInStack - 1; j >= 0; j--) {\n                var stackInfo = stackInfoList[j];\n\n                // Has been optimized by inverted indices on `stackedByDimension`.\n                if (!isStackedByIndex) {\n                    stackedDataRawIndex = stackInfo.data.rawIndexOf(stackInfo.stackedByDimension, byValue);\n                }\n\n                if (stackedDataRawIndex >= 0) {\n                    var val = stackInfo.data.getByRawIndex(stackInfo.stackResultDimension, stackedDataRawIndex);\n\n                    // Considering positive stack, negative stack and empty data\n                    if ((sum >= 0 && val > 0) // Positive stack\n                        || (sum <= 0 && val < 0) // Negative stack\n                    ) {\n                        sum += val;\n                        stackedOver = val;\n                        break;\n                    }\n                }\n            }\n\n            resultVal[0] = sum;\n            resultVal[1] = stackedOver;\n\n            return resultVal;\n        });\n\n        targetData.hostModel.setData(newData);\n        // Update for consequent calculation\n        targetStackInfo.data = newData;\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO\n// ??? refactor? check the outer usage of data provider.\n// merge with defaultDimValueGetter?\n\n/**\n * If normal array used, mutable chunk size is supported.\n * If typed array used, chunk size must be fixed.\n */\nfunction DefaultDataProvider(source, dimSize) {\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n    this._source = source;\n\n    var data = this._data = source.data;\n    var sourceFormat = source.sourceFormat;\n\n    // Typed array. TODO IE10+?\n    if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {\n        if (__DEV__) {\n            if (dimSize == null) {\n                throw new Error('Typed array data must specify dimension size');\n            }\n        }\n        this._offset = 0;\n        this._dimSize = dimSize;\n        this._data = data;\n    }\n\n    var methods = providerMethods[\n        sourceFormat === SOURCE_FORMAT_ARRAY_ROWS\n        ? sourceFormat + '_' + source.seriesLayoutBy\n        : sourceFormat\n    ];\n\n    if (__DEV__) {\n        assert$1(methods, 'Invalide sourceFormat: ' + sourceFormat);\n    }\n\n    extend(this, methods);\n}\n\nvar providerProto = DefaultDataProvider.prototype;\n// If data is pure without style configuration\nproviderProto.pure = false;\n// If data is persistent and will not be released after use.\nproviderProto.persistent = true;\n\n// ???! FIXME legacy data provider do not has method getSource\nproviderProto.getSource = function () {\n    return this._source;\n};\n\nvar providerMethods = {\n\n    'arrayRows_column': {\n        pure: true,\n        count: function () {\n            return Math.max(0, this._data.length - this._source.startIndex);\n        },\n        getItem: function (idx) {\n            return this._data[idx + this._source.startIndex];\n        },\n        appendData: appendDataSimply\n    },\n\n    'arrayRows_row': {\n        pure: true,\n        count: function () {\n            var row = this._data[0];\n            return row ? Math.max(0, row.length - this._source.startIndex) : 0;\n        },\n        getItem: function (idx) {\n            idx += this._source.startIndex;\n            var item = [];\n            var data = this._data;\n            for (var i = 0; i < data.length; i++) {\n                var row = data[i];\n                item.push(row ? row[idx] : null);\n            }\n            return item;\n        },\n        appendData: function () {\n            throw new Error('Do not support appendData when set seriesLayoutBy: \"row\".');\n        }\n    },\n\n    'objectRows': {\n        pure: true,\n        count: countSimply,\n        getItem: getItemSimply,\n        appendData: appendDataSimply\n    },\n\n    'keyedColumns': {\n        pure: true,\n        count: function () {\n            var dimName = this._source.dimensionsDefine[0].name;\n            var col = this._data[dimName];\n            return col ? col.length : 0;\n        },\n        getItem: function (idx) {\n            var item = [];\n            var dims = this._source.dimensionsDefine;\n            for (var i = 0; i < dims.length; i++) {\n                var col = this._data[dims[i].name];\n                item.push(col ? col[idx] : null);\n            }\n            return item;\n        },\n        appendData: function (newData) {\n            var data = this._data;\n            each$1(newData, function (newCol, key) {\n                var oldCol = data[key] || (data[key] = []);\n                for (var i = 0; i < (newCol || []).length; i++) {\n                    oldCol.push(newCol[i]);\n                }\n            });\n        }\n    },\n\n    'original': {\n        count: countSimply,\n        getItem: getItemSimply,\n        appendData: appendDataSimply\n    },\n\n    'typedArray': {\n        persistent: false,\n        pure: true,\n        count: function () {\n            return this._data ? (this._data.length / this._dimSize) : 0;\n        },\n        getItem: function (idx, out) {\n            idx = idx - this._offset;\n            out = out || [];\n            var offset = this._dimSize * idx;\n            for (var i = 0; i < this._dimSize; i++) {\n                out[i] = this._data[offset + i];\n            }\n            return out;\n        },\n        appendData: function (newData) {\n            if (__DEV__) {\n                assert$1(\n                    isTypedArray(newData),\n                    'Added data must be TypedArray if data in initialization is TypedArray'\n                );\n            }\n\n            this._data = newData;\n        },\n\n        // Clean self if data is already used.\n        clean: function () {\n            // PENDING\n            this._offset += this.count();\n            this._data = null;\n        }\n    }\n};\n\nfunction countSimply() {\n    return this._data.length;\n}\nfunction getItemSimply(idx) {\n    return this._data[idx];\n}\nfunction appendDataSimply(newData) {\n    for (var i = 0; i < newData.length; i++) {\n        this._data.push(newData[i]);\n    }\n}\n\n\n\nvar rawValueGetters = {\n\n    arrayRows: getRawValueSimply,\n\n    objectRows: function (dataItem, dataIndex, dimIndex, dimName) {\n        return dimIndex != null ? dataItem[dimName] : dataItem;\n    },\n\n    keyedColumns: getRawValueSimply,\n\n    original: function (dataItem, dataIndex, dimIndex, dimName) {\n        // FIXME\n        // In some case (markpoint in geo (geo-map.html)), dataItem\n        // is {coord: [...]}\n        var value = getDataItemValue(dataItem);\n        return (dimIndex == null || !(value instanceof Array))\n            ? value\n            : value[dimIndex];\n    },\n\n    typedArray: getRawValueSimply\n};\n\nfunction getRawValueSimply(dataItem, dataIndex, dimIndex, dimName) {\n    return dimIndex != null ? dataItem[dimIndex] : dataItem;\n}\n\n\nvar defaultDimValueGetters = {\n\n    arrayRows: getDimValueSimply,\n\n    objectRows: function (dataItem, dimName, dataIndex, dimIndex) {\n        return converDataValue(dataItem[dimName], this._dimensionInfos[dimName]);\n    },\n\n    keyedColumns: getDimValueSimply,\n\n    original: function (dataItem, dimName, dataIndex, dimIndex) {\n        // Performance sensitive, do not use modelUtil.getDataItemValue.\n        // If dataItem is an plain object with no value field, the var `value`\n        // will be assigned with the object, but it will be tread correctly\n        // in the `convertDataValue`.\n        var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value);\n\n        // If any dataItem is like { value: 10 }\n        if (!this._rawData.pure && isDataItemOption(dataItem)) {\n            this.hasItemOption = true;\n        }\n        return converDataValue(\n            (value instanceof Array)\n                ? value[dimIndex]\n                // If value is a single number or something else not array.\n                : value,\n            this._dimensionInfos[dimName]\n        );\n    },\n\n    typedArray: function (dataItem, dimName, dataIndex, dimIndex) {\n        return dataItem[dimIndex];\n    }\n\n};\n\nfunction getDimValueSimply(dataItem, dimName, dataIndex, dimIndex) {\n    return converDataValue(dataItem[dimIndex], this._dimensionInfos[dimName]);\n}\n\n/**\n * This helper method convert value in data.\n * @param {string|number|Date} value\n * @param {Object|string} [dimInfo] If string (like 'x'), dimType defaults 'number'.\n *        If \"dimInfo.ordinalParseAndSave\", ordinal value can be parsed.\n */\nfunction converDataValue(value, dimInfo) {\n    // Performance sensitive.\n    var dimType = dimInfo && dimInfo.type;\n    if (dimType === 'ordinal') {\n        // If given value is a category string\n        var ordinalMeta = dimInfo && dimInfo.ordinalMeta;\n        return ordinalMeta\n            ? ordinalMeta.parseAndCollect(value)\n            : value;\n    }\n\n    if (dimType === 'time'\n        // spead up when using timestamp\n        && typeof value !== 'number'\n        && value != null\n        && value !== '-'\n    ) {\n        value = +parseDate(value);\n    }\n\n    // dimType defaults 'number'.\n    // If dimType is not ordinal and value is null or undefined or NaN or '-',\n    // parse to NaN.\n    return (value == null || value === '')\n        ? NaN\n        // If string (like '-'), using '+' parse to NaN\n        // If object, also parse to NaN\n        : +value;\n}\n\n// ??? FIXME can these logic be more neat: getRawValue, getRawDataItem,\n// Consider persistent.\n// Caution: why use raw value to display on label or tooltip?\n// A reason is to avoid format. For example time value we do not know\n// how to format is expected. More over, if stack is used, calculated\n// value may be 0.91000000001, which have brings trouble to display.\n// TODO: consider how to treat null/undefined/NaN when display?\n/**\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @param {string|number} [dim] dimName or dimIndex\n * @return {Array.<number>|string|number} can be null/undefined.\n */\nfunction retrieveRawValue(data, dataIndex, dim) {\n    if (!data) {\n        return;\n    }\n\n    // Consider data may be not persistent.\n    var dataItem = data.getRawDataItem(dataIndex);\n\n    if (dataItem == null) {\n        return;\n    }\n\n    var sourceFormat = data.getProvider().getSource().sourceFormat;\n    var dimName;\n    var dimIndex;\n\n    var dimInfo = data.getDimensionInfo(dim);\n    if (dimInfo) {\n        dimName = dimInfo.name;\n        dimIndex = dimInfo.index;\n    }\n\n    return rawValueGetters[sourceFormat](dataItem, dataIndex, dimIndex, dimName);\n}\n\n/**\n * Compatible with some cases (in pie, map) like:\n * data: [{name: 'xx', value: 5, selected: true}, ...]\n * where only sourceFormat is 'original' and 'objectRows' supported.\n *\n * ??? TODO\n * Supported detail options in data item when using 'arrayRows'.\n *\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @param {string} attr like 'selected'\n */\nfunction retrieveRawAttr(data, dataIndex, attr) {\n    if (!data) {\n        return;\n    }\n\n    var sourceFormat = data.getProvider().getSource().sourceFormat;\n\n    if (sourceFormat !== SOURCE_FORMAT_ORIGINAL\n        && sourceFormat !== SOURCE_FORMAT_OBJECT_ROWS\n    ) {\n        return;\n    }\n\n    var dataItem = data.getRawDataItem(dataIndex);\n    if (sourceFormat === SOURCE_FORMAT_ORIGINAL && !isObject$1(dataItem)) {\n        dataItem = null;\n    }\n    if (dataItem) {\n        return dataItem[attr];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DIMENSION_LABEL_REG = /\\{@(.+?)\\}/g;\n\n// PENDING A little ugly\nvar dataFormatMixin = {\n    /**\n     * Get params for formatter\n     * @param {number} dataIndex\n     * @param {string} [dataType]\n     * @return {Object}\n     */\n    getDataParams: function (dataIndex, dataType) {\n        var data = this.getData(dataType);\n        var rawValue = this.getRawValue(dataIndex, dataType);\n        var rawDataIndex = data.getRawIndex(dataIndex);\n        var name = data.getName(dataIndex);\n        var itemOpt = data.getRawDataItem(dataIndex);\n        var color = data.getItemVisual(dataIndex, 'color');\n        var tooltipModel = this.ecModel.getComponent('tooltip');\n        var renderModeOption = tooltipModel && tooltipModel.get('renderMode');\n        var renderMode = getTooltipRenderMode(renderModeOption);\n        var mainType = this.mainType;\n        var isSeries = mainType === 'series';\n\n        return {\n            componentType: mainType,\n            componentSubType: this.subType,\n            componentIndex: this.componentIndex,\n            seriesType: isSeries ? this.subType : null,\n            seriesIndex: this.seriesIndex,\n            seriesId: isSeries ? this.id : null,\n            seriesName: isSeries ? this.name : null,\n            name: name,\n            dataIndex: rawDataIndex,\n            data: itemOpt,\n            dataType: dataType,\n            value: rawValue,\n            color: color,\n            marker: getTooltipMarker({\n                color: color,\n                renderMode: renderMode\n            }),\n\n            // Param name list for mapping `a`, `b`, `c`, `d`, `e`\n            $vars: ['seriesName', 'name', 'value']\n        };\n    },\n\n    /**\n     * Format label\n     * @param {number} dataIndex\n     * @param {string} [status='normal'] 'normal' or 'emphasis'\n     * @param {string} [dataType]\n     * @param {number} [dimIndex]\n     * @param {string} [labelProp='label']\n     * @return {string} If not formatter, return null/undefined\n     */\n    getFormattedLabel: function (dataIndex, status, dataType, dimIndex, labelProp) {\n        status = status || 'normal';\n        var data = this.getData(dataType);\n        var itemModel = data.getItemModel(dataIndex);\n\n        var params = this.getDataParams(dataIndex, dataType);\n        if (dimIndex != null && (params.value instanceof Array)) {\n            params.value = params.value[dimIndex];\n        }\n\n        var formatter = itemModel.get(\n            status === 'normal'\n            ? [labelProp || 'label', 'formatter']\n            : [status, labelProp || 'label', 'formatter']\n        );\n\n        if (typeof formatter === 'function') {\n            params.status = status;\n            return formatter(params);\n        }\n        else if (typeof formatter === 'string') {\n            var str = formatTpl(formatter, params);\n\n            // Support 'aaa{@[3]}bbb{@product}ccc'.\n            // Do not support '}' in dim name util have to.\n            return str.replace(DIMENSION_LABEL_REG, function (origin, dim) {\n                var len = dim.length;\n                if (dim.charAt(0) === '[' && dim.charAt(len - 1) === ']') {\n                    dim = +dim.slice(1, len - 1); // Also: '[]' => 0\n                }\n                return retrieveRawValue(data, dataIndex, dim);\n            });\n        }\n    },\n\n    /**\n     * Get raw value in option\n     * @param {number} idx\n     * @param {string} [dataType]\n     * @return {Array|number|string}\n     */\n    getRawValue: function (idx, dataType) {\n        return retrieveRawValue(this.getData(dataType), idx);\n    },\n\n    /**\n     * Should be implemented.\n     * @param {number} dataIndex\n     * @param {boolean} [multipleSeries=false]\n     * @param {number} [dataType]\n     * @return {string} tooltip string\n     */\n    formatTooltip: function () {\n        // Empty function\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} define\n * @return See the return of `createTask`.\n */\nfunction createTask(define) {\n    return new Task(define);\n}\n\n/**\n * @constructor\n * @param {Object} define\n * @param {Function} define.reset Custom reset\n * @param {Function} [define.plan] Returns 'reset' indicate reset immediately.\n * @param {Function} [define.count] count is used to determin data task.\n * @param {Function} [define.onDirty] count is used to determin data task.\n */\nfunction Task(define) {\n    define = define || {};\n\n    this._reset = define.reset;\n    this._plan = define.plan;\n    this._count = define.count;\n    this._onDirty = define.onDirty;\n\n    this._dirty = true;\n\n    // Context must be specified implicitly, to\n    // avoid miss update context when model changed.\n    this.context;\n}\n\nvar taskProto = Task.prototype;\n\n/**\n * @param {Object} performArgs\n * @param {number} [performArgs.step] Specified step.\n * @param {number} [performArgs.skip] Skip customer perform call.\n * @param {number} [performArgs.modBy] Sampling window size.\n * @param {number} [performArgs.modDataCount] Sampling count.\n */\ntaskProto.perform = function (performArgs) {\n    var upTask = this._upstream;\n    var skip = performArgs && performArgs.skip;\n\n    // TODO some refactor.\n    // Pull data. Must pull data each time, because context.data\n    // may be updated by Series.setData.\n    if (this._dirty && upTask) {\n        var context = this.context;\n        context.data = context.outputData = upTask.context.outputData;\n    }\n\n    if (this.__pipeline) {\n        this.__pipeline.currentTask = this;\n    }\n\n    var planResult;\n    if (this._plan && !skip) {\n        planResult = this._plan(this.context);\n    }\n\n    // Support sharding by mod, which changes the render sequence and makes the rendered graphic\n    // elements uniformed distributed when progress, especially when moving or zooming.\n    var lastModBy = normalizeModBy(this._modBy);\n    var lastModDataCount = this._modDataCount || 0;\n    var modBy = normalizeModBy(performArgs && performArgs.modBy);\n    var modDataCount = performArgs && performArgs.modDataCount || 0;\n    if (lastModBy !== modBy || lastModDataCount !== modDataCount) {\n        planResult = 'reset';\n    }\n\n    function normalizeModBy(val) {\n        !(val >= 1) && (val = 1); // jshint ignore:line\n        return val;\n    }\n\n    var forceFirstProgress;\n    if (this._dirty || planResult === 'reset') {\n        this._dirty = false;\n        forceFirstProgress = reset(this, skip);\n    }\n\n    this._modBy = modBy;\n    this._modDataCount = modDataCount;\n\n    var step = performArgs && performArgs.step;\n\n    if (upTask) {\n\n        if (__DEV__) {\n            assert$1(upTask._outputDueEnd != null);\n        }\n        this._dueEnd = upTask._outputDueEnd;\n    }\n    // DataTask or overallTask\n    else {\n        if (__DEV__) {\n            assert$1(!this._progress || this._count);\n        }\n        this._dueEnd = this._count ? this._count(this.context) : Infinity;\n    }\n\n    // Note: Stubs, that its host overall task let it has progress, has progress.\n    // If no progress, pass index from upstream to downstream each time plan called.\n    if (this._progress) {\n        var start = this._dueIndex;\n        var end = Math.min(\n            step != null ? this._dueIndex + step : Infinity,\n            this._dueEnd\n        );\n\n        if (!skip && (forceFirstProgress || start < end)) {\n            var progress = this._progress;\n            if (isArray(progress)) {\n                for (var i = 0; i < progress.length; i++) {\n                    doProgress(this, progress[i], start, end, modBy, modDataCount);\n                }\n            }\n            else {\n                doProgress(this, progress, start, end, modBy, modDataCount);\n            }\n        }\n\n        this._dueIndex = end;\n        // If no `outputDueEnd`, assume that output data and\n        // input data is the same, so use `dueIndex` as `outputDueEnd`.\n        var outputDueEnd = this._settedOutputEnd != null\n            ? this._settedOutputEnd : end;\n\n        if (__DEV__) {\n            // ??? Can not rollback.\n            assert$1(outputDueEnd >= this._outputDueEnd);\n        }\n\n        this._outputDueEnd = outputDueEnd;\n    }\n    else {\n        // (1) Some overall task has no progress.\n        // (2) Stubs, that its host overall task do not let it has progress, has no progress.\n        // This should always be performed so it can be passed to downstream.\n        this._dueIndex = this._outputDueEnd = this._settedOutputEnd != null\n            ? this._settedOutputEnd : this._dueEnd;\n    }\n\n    return this.unfinished();\n};\n\nvar iterator = (function () {\n\n    var end;\n    var current;\n    var modBy;\n    var modDataCount;\n    var winCount;\n\n    var it = {\n        reset: function (s, e, sStep, sCount) {\n            current = s;\n            end = e;\n\n            modBy = sStep;\n            modDataCount = sCount;\n            winCount = Math.ceil(modDataCount / modBy);\n\n            it.next = (modBy > 1 && modDataCount > 0) ? modNext : sequentialNext;\n        }\n    };\n\n    return it;\n\n    function sequentialNext() {\n        return current < end ? current++ : null;\n    }\n\n    function modNext() {\n        var dataIndex = (current % winCount) * modBy + Math.ceil(current / winCount);\n        var result = current >= end\n            ? null\n            : dataIndex < modDataCount\n            ? dataIndex\n            // If modDataCount is smaller than data.count() (consider `appendData` case),\n            // Use normal linear rendering mode.\n            : current;\n        current++;\n        return result;\n    }\n})();\n\ntaskProto.dirty = function () {\n    this._dirty = true;\n    this._onDirty && this._onDirty(this.context);\n};\n\nfunction doProgress(taskIns, progress, start, end, modBy, modDataCount) {\n    iterator.reset(start, end, modBy, modDataCount);\n    taskIns._callingProgress = progress;\n    taskIns._callingProgress({\n        start: start, end: end, count: end - start, next: iterator.next\n    }, taskIns.context);\n}\n\nfunction reset(taskIns, skip) {\n    taskIns._dueIndex = taskIns._outputDueEnd = taskIns._dueEnd = 0;\n    taskIns._settedOutputEnd = null;\n\n    var progress;\n    var forceFirstProgress;\n\n    if (!skip && taskIns._reset) {\n        progress = taskIns._reset(taskIns.context);\n        if (progress && progress.progress) {\n            forceFirstProgress = progress.forceFirstProgress;\n            progress = progress.progress;\n        }\n        // To simplify no progress checking, array must has item.\n        if (isArray(progress) && !progress.length) {\n            progress = null;\n        }\n    }\n\n    taskIns._progress = progress;\n    taskIns._modBy = taskIns._modDataCount = null;\n\n    var downstream = taskIns._downstream;\n    downstream && downstream.dirty();\n\n    return forceFirstProgress;\n}\n\n/**\n * @return {boolean}\n */\ntaskProto.unfinished = function () {\n    return this._progress && this._dueIndex < this._dueEnd;\n};\n\n/**\n * @param {Object} downTask The downstream task.\n * @return {Object} The downstream task.\n */\ntaskProto.pipe = function (downTask) {\n    if (__DEV__) {\n        assert$1(downTask && !downTask._disposed && downTask !== this);\n    }\n\n    // If already downstream, do not dirty downTask.\n    if (this._downstream !== downTask || this._dirty) {\n        this._downstream = downTask;\n        downTask._upstream = this;\n        downTask.dirty();\n    }\n};\n\ntaskProto.dispose = function () {\n    if (this._disposed) {\n        return;\n    }\n\n    this._upstream && (this._upstream._downstream = null);\n    this._downstream && (this._downstream._upstream = null);\n\n    this._dirty = false;\n    this._disposed = true;\n};\n\ntaskProto.getUpstream = function () {\n    return this._upstream;\n};\n\ntaskProto.getDownstream = function () {\n    return this._downstream;\n};\n\ntaskProto.setOutputEnd = function (end) {\n    // This only happend in dataTask, dataZoom, map, currently.\n    // where dataZoom do not set end each time, but only set\n    // when reset. So we should record the setted end, in case\n    // that the stub of dataZoom perform again and earse the\n    // setted end by upstream.\n    this._outputDueEnd = this._settedOutputEnd = end;\n};\n\n\n///////////////////////////////////////////////////////////\n// For stream debug (Should be commented out after used!)\n// Usage: printTask(this, 'begin');\n// Usage: printTask(this, null, {someExtraProp});\n// function printTask(task, prefix, extra) {\n//     window.ecTaskUID == null && (window.ecTaskUID = 0);\n//     task.uidDebug == null && (task.uidDebug = `task_${window.ecTaskUID++}`);\n//     task.agent && task.agent.uidDebug == null && (task.agent.uidDebug = `task_${window.ecTaskUID++}`);\n//     var props = [];\n//     if (task.__pipeline) {\n//         var val = `${task.__idxInPipeline}/${task.__pipeline.tail.__idxInPipeline} ${task.agent ? '(stub)' : ''}`;\n//         props.push({text: 'idx', value: val});\n//     } else {\n//         var stubCount = 0;\n//         task.agentStubMap.each(() => stubCount++);\n//         props.push({text: 'idx', value: `overall (stubs: ${stubCount})`});\n//     }\n//     props.push({text: 'uid', value: task.uidDebug});\n//     if (task.__pipeline) {\n//         props.push({text: 'pid', value: task.__pipeline.id});\n//         task.agent && props.push(\n//             {text: 'stubFor', value: task.agent.uidDebug}\n//         );\n//     }\n//     props.push(\n//         {text: 'dirty', value: task._dirty},\n//         {text: 'dueIndex', value: task._dueIndex},\n//         {text: 'dueEnd', value: task._dueEnd},\n//         {text: 'outputDueEnd', value: task._outputDueEnd}\n//     );\n//     if (extra) {\n//         Object.keys(extra).forEach(key => {\n//             props.push({text: key, value: extra[key]});\n//         });\n//     }\n//     var args = ['color: blue'];\n//     var msg = `%c[${prefix || 'T'}] %c` + props.map(item => (\n//         args.push('color: black', 'color: red'),\n//         `${item.text}: %c${item.value}`\n//     )).join('%c, ');\n//     console.log.apply(console, [msg].concat(args));\n//     // console.log(this);\n// }\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$4 = makeInner();\n\nvar SeriesModel = ComponentModel.extend({\n\n    type: 'series.__base__',\n\n    /**\n     * @readOnly\n     */\n    seriesIndex: 0,\n\n    // coodinateSystem will be injected in the echarts/CoordinateSystem\n    coordinateSystem: null,\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    defaultOption: null,\n\n    /**\n     * Data provided for legend\n     * @type {Function}\n     */\n    // PENDING\n    legendDataProvider: null,\n\n    /**\n     * Access path of color for visual\n     */\n    visualColorAccessPath: 'itemStyle.color',\n\n    /**\n     * Support merge layout params.\n     * Only support 'box' now (left/right/top/bottom/width/height).\n     * @type {string|Object} Object can be {ignoreSize: true}\n     * @readOnly\n     */\n    layoutMode: null,\n\n    init: function (option, parentModel, ecModel, extraOpt) {\n\n        /**\n         * @type {number}\n         * @readOnly\n         */\n        this.seriesIndex = this.componentIndex;\n\n        this.dataTask = createTask({\n            count: dataTaskCount,\n            reset: dataTaskReset\n        });\n        this.dataTask.context = {model: this};\n\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        prepareSource(this);\n\n\n        var data = this.getInitialData(option, ecModel);\n        wrapData(data, this);\n        this.dataTask.context.data = data;\n\n        if (__DEV__) {\n            assert$1(data, 'getInitialData returned invalid data.');\n        }\n\n        /**\n         * @type {module:echarts/data/List|module:echarts/data/Tree|module:echarts/data/Graph}\n         * @private\n         */\n        inner$4(this).dataBeforeProcessed = data;\n\n        // If we reverse the order (make data firstly, and then make\n        // dataBeforeProcessed by cloneShallow), cloneShallow will\n        // cause data.graph.data !== data when using\n        // module:echarts/data/Graph or module:echarts/data/Tree.\n        // See module:echarts/data/helper/linkList\n\n        // Theoretically, it is unreasonable to call `seriesModel.getData()` in the model\n        // init or merge stage, because the data can be restored. So we do not `restoreData`\n        // and `setData` here, which forbids calling `seriesModel.getData()` in this stage.\n        // Call `seriesModel.getRawData()` instead.\n        // this.restoreData();\n\n        autoSeriesName(this);\n    },\n\n    /**\n     * Util for merge default and theme to option\n     * @param  {Object} option\n     * @param  {module:echarts/model/Global} ecModel\n     */\n    mergeDefaultAndTheme: function (option, ecModel) {\n        var layoutMode = this.layoutMode;\n        var inputPositionParams = layoutMode\n            ? getLayoutParams(option) : {};\n\n        // Backward compat: using subType on theme.\n        // But if name duplicate between series subType\n        // (for example: parallel) add component mainType,\n        // add suffix 'Series'.\n        var themeSubType = this.subType;\n        if (ComponentModel.hasClass(themeSubType)) {\n            themeSubType += 'Series';\n        }\n        merge(\n            option,\n            ecModel.getTheme().get(this.subType)\n        );\n        merge(option, this.getDefaultOption());\n\n        // Default label emphasis `show`\n        defaultEmphasis(option, 'label', ['show']);\n\n        this.fillDataTextStyle(option.data);\n\n        if (layoutMode) {\n            mergeLayoutParam(option, inputPositionParams, layoutMode);\n        }\n    },\n\n    mergeOption: function (newSeriesOption, ecModel) {\n        // this.settingTask.dirty();\n\n        newSeriesOption = merge(this.option, newSeriesOption, true);\n        this.fillDataTextStyle(newSeriesOption.data);\n\n        var layoutMode = this.layoutMode;\n        if (layoutMode) {\n            mergeLayoutParam(this.option, newSeriesOption, layoutMode);\n        }\n\n        prepareSource(this);\n\n        var data = this.getInitialData(newSeriesOption, ecModel);\n        wrapData(data, this);\n        this.dataTask.dirty();\n        this.dataTask.context.data = data;\n\n        inner$4(this).dataBeforeProcessed = data;\n\n        autoSeriesName(this);\n    },\n\n    fillDataTextStyle: function (data) {\n        // Default data label emphasis `show`\n        // FIXME Tree structure data ?\n        // FIXME Performance ?\n        if (data && !isTypedArray(data)) {\n            var props = ['show'];\n            for (var i = 0; i < data.length; i++) {\n                if (data[i] && data[i].label) {\n                    defaultEmphasis(data[i], 'label', props);\n                }\n            }\n        }\n    },\n\n    /**\n     * Init a data structure from data related option in series\n     * Must be overwritten\n     */\n    getInitialData: function () {},\n\n    /**\n     * Append data to list\n     * @param {Object} params\n     * @param {Array|TypedArray} params.data\n     */\n    appendData: function (params) {\n        // FIXME ???\n        // (1) If data from dataset, forbidden append.\n        // (2) support append data of dataset.\n        var data = this.getRawData();\n        data.appendData(params.data);\n    },\n\n    /**\n     * Consider some method like `filter`, `map` need make new data,\n     * We should make sure that `seriesModel.getData()` get correct\n     * data in the stream procedure. So we fetch data from upstream\n     * each time `task.perform` called.\n     * @param {string} [dataType]\n     * @return {module:echarts/data/List}\n     */\n    getData: function (dataType) {\n        var task = getCurrentTask(this);\n        if (task) {\n            var data = task.context.data;\n            return dataType == null ? data : data.getLinkedData(dataType);\n        }\n        else {\n            // When series is not alive (that may happen when click toolbox\n            // restore or setOption with not merge mode), series data may\n            // be still need to judge animation or something when graphic\n            // elements want to know whether fade out.\n            return inner$4(this).data;\n        }\n    },\n\n    /**\n     * @param {module:echarts/data/List} data\n     */\n    setData: function (data) {\n        var task = getCurrentTask(this);\n        if (task) {\n            var context = task.context;\n            // Consider case: filter, data sample.\n            if (context.data !== data && task.modifyOutputEnd) {\n                task.setOutputEnd(data.count());\n            }\n            context.outputData = data;\n            // Caution: setData should update context.data,\n            // Because getData may be called multiply in a\n            // single stage and expect to get the data just\n            // set. (For example, AxisProxy, x y both call\n            // getData and setDate sequentially).\n            // So the context.data should be fetched from\n            // upstream each time when a stage starts to be\n            // performed.\n            if (task !== this.dataTask) {\n                context.data = data;\n            }\n        }\n        inner$4(this).data = data;\n    },\n\n    /**\n     * @see {module:echarts/data/helper/sourceHelper#getSource}\n     * @return {module:echarts/data/Source} source\n     */\n    getSource: function () {\n        return getSource(this);\n    },\n\n    /**\n     * Get data before processed\n     * @return {module:echarts/data/List}\n     */\n    getRawData: function () {\n        return inner$4(this).dataBeforeProcessed;\n    },\n\n    /**\n     * Get base axis if has coordinate system and has axis.\n     * By default use coordSys.getBaseAxis();\n     * Can be overrided for some chart.\n     * @return {type} description\n     */\n    getBaseAxis: function () {\n        var coordSys = this.coordinateSystem;\n        return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis();\n    },\n\n    // FIXME\n    /**\n     * Default tooltip formatter\n     *\n     * @param {number} dataIndex\n     * @param {boolean} [multipleSeries=false]\n     * @param {number} [dataType]\n     * @param {string} [renderMode='html'] valid values: 'html' and 'richText'.\n     *                                     'html' is used for rendering tooltip in extra DOM form, and the result\n     *                                     string is used as DOM HTML content.\n     *                                     'richText' is used for rendering tooltip in rich text form, for those where\n     *                                     DOM operation is not supported.\n     * @return {Object} formatted tooltip with `html` and `markers`\n     */\n    formatTooltip: function (dataIndex, multipleSeries, dataType, renderMode) {\n\n        var series = this;\n        renderMode = renderMode || 'html';\n        var newLine = renderMode === 'html' ? '<br/>' : '\\n';\n        var isRichText = renderMode === 'richText';\n        var markers = {};\n        var markerId = 0;\n\n        function formatArrayValue(value) {\n            // ??? TODO refactor these logic.\n            // check: category-no-encode-has-axis-data in dataset.html\n            var vertially = reduce(value, function (vertially, val, idx) {\n                var dimItem = data.getDimensionInfo(idx);\n                return vertially |= dimItem && dimItem.tooltip !== false && dimItem.displayName != null;\n            }, 0);\n\n            var result = [];\n\n            tooltipDims.length\n                ? each$1(tooltipDims, function (dim) {\n                    setEachItem(retrieveRawValue(data, dataIndex, dim), dim);\n                })\n                // By default, all dims is used on tooltip.\n                : each$1(value, setEachItem);\n\n            function setEachItem(val, dim) {\n                var dimInfo = data.getDimensionInfo(dim);\n                // If `dimInfo.tooltip` is not set, show tooltip.\n                if (!dimInfo || dimInfo.otherDims.tooltip === false) {\n                    return;\n                }\n                var dimType = dimInfo.type;\n                var markName = 'sub' + series.seriesIndex + 'at' + markerId;\n                var dimHead = getTooltipMarker({\n                    color: color,\n                    type: 'subItem',\n                    renderMode: renderMode,\n                    markerId: markName\n                });\n\n                var dimHeadStr = typeof dimHead === 'string' ? dimHead : dimHead.content;\n                var valStr = (vertially\n                        ? dimHeadStr + encodeHTML(dimInfo.displayName || '-') + ': '\n                        : ''\n                    )\n                    // FIXME should not format time for raw data?\n                    + encodeHTML(dimType === 'ordinal'\n                        ? val + ''\n                        : dimType === 'time'\n                        ? (multipleSeries ? '' : formatTime('yyyy/MM/dd hh:mm:ss', val))\n                        : addCommas(val)\n                    );\n                valStr && result.push(valStr);\n\n                if (isRichText) {\n                    markers[markName] = color;\n                    ++markerId;\n                }\n            }\n\n            var newLine = vertially ? (isRichText ? '\\n' : '<br/>') : '';\n            var content = newLine + result.join(newLine || ', ');\n            return {\n                renderMode: renderMode,\n                content: content,\n                style: markers\n            };\n        }\n\n        function formatSingleValue(val) {\n            // return encodeHTML(addCommas(val));\n            return {\n                renderMode: renderMode,\n                content: encodeHTML(addCommas(val)),\n                style: markers\n            };\n        }\n\n        var data = this.getData();\n        var tooltipDims = data.mapDimension('defaultedTooltip', true);\n        var tooltipDimLen = tooltipDims.length;\n        var value = this.getRawValue(dataIndex);\n        var isValueArr = isArray(value);\n\n        var color = data.getItemVisual(dataIndex, 'color');\n        if (isObject$1(color) && color.colorStops) {\n            color = (color.colorStops[0] || {}).color;\n        }\n        color = color || 'transparent';\n\n        // Complicated rule for pretty tooltip.\n        var formattedValue = (tooltipDimLen > 1 || (isValueArr && !tooltipDimLen))\n            ? formatArrayValue(value)\n            : tooltipDimLen\n            ? formatSingleValue(retrieveRawValue(data, dataIndex, tooltipDims[0]))\n            : formatSingleValue(isValueArr ? value[0] : value);\n        var content = formattedValue.content;\n\n        var markName = series.seriesIndex + 'at' + markerId;\n        var colorEl = getTooltipMarker({\n            color: color,\n            type: 'item',\n            renderMode: renderMode,\n            markerId: markName\n        });\n        markers[markName] = color;\n        ++markerId;\n\n        var name = data.getName(dataIndex);\n\n        var seriesName = this.name;\n        if (!isNameSpecified(this)) {\n            seriesName = '';\n        }\n        seriesName = seriesName\n            ? encodeHTML(seriesName) + (!multipleSeries ? newLine : ': ')\n            : '';\n\n        var colorStr = typeof colorEl === 'string' ? colorEl : colorEl.content;\n        var html = !multipleSeries\n            ? seriesName + colorStr\n                + (name\n                    ? encodeHTML(name) + ': ' + content\n                    : content\n                )\n            : colorStr + seriesName + content;\n\n        return {\n            html: html,\n            markers: markers\n        };\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isAnimationEnabled: function () {\n        if (env$1.node) {\n            return false;\n        }\n\n        var animationEnabled = this.getShallow('animation');\n        if (animationEnabled) {\n            if (this.getData().count() > this.getShallow('animationThreshold')) {\n                animationEnabled = false;\n            }\n        }\n        return animationEnabled;\n    },\n\n    restoreData: function () {\n        this.dataTask.dirty();\n    },\n\n    getColorFromPalette: function (name, scope, requestColorNum) {\n        var ecModel = this.ecModel;\n        // PENDING\n        var color = colorPaletteMixin.getColorFromPalette.call(this, name, scope, requestColorNum);\n        if (!color) {\n            color = ecModel.getColorFromPalette(name, scope, requestColorNum);\n        }\n        return color;\n    },\n\n    /**\n     * Use `data.mapDimension(coordDim, true)` instead.\n     * @deprecated\n     */\n    coordDimToDataDim: function (coordDim) {\n        return this.getRawData().mapDimension(coordDim, true);\n    },\n\n    /**\n     * Get progressive rendering count each step\n     * @return {number}\n     */\n    getProgressive: function () {\n        return this.get('progressive');\n    },\n\n    /**\n     * Get progressive rendering count each step\n     * @return {number}\n     */\n    getProgressiveThreshold: function () {\n        return this.get('progressiveThreshold');\n    },\n\n    /**\n     * Get data indices for show tooltip content. See tooltip.\n     * @abstract\n     * @param {Array.<string>|string} dim\n     * @param {Array.<number>} value\n     * @param {module:echarts/coord/single/SingleAxis} baseAxis\n     * @return {Object} {dataIndices, nestestValue}.\n     */\n    getAxisTooltipData: null,\n\n    /**\n     * See tooltip.\n     * @abstract\n     * @param {number} dataIndex\n     * @return {Array.<number>} Point of tooltip. null/undefined can be returned.\n     */\n    getTooltipPosition: null,\n\n    /**\n     * @see {module:echarts/stream/Scheduler}\n     */\n    pipeTask: null,\n\n    /**\n     * Convinient for override in extended class.\n     * @protected\n     * @type {Function}\n     */\n    preventIncremental: null,\n\n    /**\n     * @public\n     * @readOnly\n     * @type {Object}\n     */\n    pipelineContext: null\n\n});\n\n\nmixin(SeriesModel, dataFormatMixin);\nmixin(SeriesModel, colorPaletteMixin);\n\n/**\n * MUST be called after `prepareSource` called\n * Here we need to make auto series, especially for auto legend. But we\n * do not modify series.name in option to avoid side effects.\n */\nfunction autoSeriesName(seriesModel) {\n    // User specified name has higher priority, otherwise it may cause\n    // series can not be queried unexpectedly.\n    var name = seriesModel.name;\n    if (!isNameSpecified(seriesModel)) {\n        seriesModel.name = getSeriesAutoName(seriesModel) || name;\n    }\n}\n\nfunction getSeriesAutoName(seriesModel) {\n    var data = seriesModel.getRawData();\n    var dataDims = data.mapDimension('seriesName', true);\n    var nameArr = [];\n    each$1(dataDims, function (dataDim) {\n        var dimInfo = data.getDimensionInfo(dataDim);\n        dimInfo.displayName && nameArr.push(dimInfo.displayName);\n    });\n    return nameArr.join(' ');\n}\n\nfunction dataTaskCount(context) {\n    return context.model.getRawData().count();\n}\n\nfunction dataTaskReset(context) {\n    var seriesModel = context.model;\n    seriesModel.setData(seriesModel.getRawData().cloneShallow());\n    return dataTaskProgress;\n}\n\nfunction dataTaskProgress(param, context) {\n    // Avoid repead cloneShallow when data just created in reset.\n    if (param.end > context.outputData.count()) {\n        context.model.getRawData().cloneShallow(context.outputData);\n    }\n}\n\n// TODO refactor\nfunction wrapData(data, seriesModel) {\n    each$1(data.CHANGABLE_METHODS, function (methodName) {\n        data.wrapMethod(methodName, curry(onDataSelfChange, seriesModel));\n    });\n}\n\nfunction onDataSelfChange(seriesModel) {\n    var task = getCurrentTask(seriesModel);\n    if (task) {\n        // Consider case: filter, selectRange\n        task.setOutputEnd(this.count());\n    }\n}\n\nfunction getCurrentTask(seriesModel) {\n    var scheduler = (seriesModel.ecModel || {}).scheduler;\n    var pipeline = scheduler && scheduler.getPipeline(seriesModel.uid);\n\n    if (pipeline) {\n        // When pipline finished, the currrentTask keep the last\n        // task (renderTask).\n        var task = pipeline.currentTask;\n        if (task) {\n            var agentStubMap = task.agentStubMap;\n            if (agentStubMap) {\n                task = agentStubMap.get(seriesModel.uid);\n            }\n        }\n        return task;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar Component = function () {\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.uid = getUID('viewComponent');\n};\n\nComponent.prototype = {\n\n    constructor: Component,\n\n    init: function (ecModel, api) {},\n\n    render: function (componentModel, ecModel, api, payload) {},\n\n    dispose: function () {},\n\n    /**\n     * @param {string} eventType\n     * @param {Object} query\n     * @param {module:zrender/Element} targetEl\n     * @param {Object} packedEvent\n     * @return {boolen} Pass only when return `true`.\n     */\n    filterForExposedEvent: null\n\n};\n\nvar componentProto = Component.prototype;\ncomponentProto.updateView\n    = componentProto.updateLayout\n    = componentProto.updateVisual\n    = function (seriesModel, ecModel, api, payload) {\n        // Do nothing;\n    };\n// Enable Component.extend.\nenableClassExtend(Component);\n\n// Enable capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(Component, {registerWhenExtend: true});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @return {string} If large mode changed, return string 'reset';\n */\nvar createRenderPlanner = function () {\n    var inner = makeInner();\n\n    return function (seriesModel) {\n        var fields = inner(seriesModel);\n        var pipelineContext = seriesModel.pipelineContext;\n\n        var originalLarge = fields.large;\n        var originalProgressive = fields.progressiveRender;\n\n        var large = fields.large = pipelineContext.large;\n        var progressive = fields.progressiveRender = pipelineContext.progressiveRender;\n\n        return !!((originalLarge ^ large) || (originalProgressive ^ progressive)) && 'reset';\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$5 = makeInner();\nvar renderPlanner = createRenderPlanner();\n\nfunction Chart() {\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.uid = getUID('viewChart');\n\n    this.renderTask = createTask({\n        plan: renderTaskPlan,\n        reset: renderTaskReset\n    });\n    this.renderTask.context = {view: this};\n}\n\nChart.prototype = {\n\n    type: 'chart',\n\n    /**\n     * Init the chart.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    init: function (ecModel, api) {},\n\n    /**\n     * Render the chart.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    render: function (seriesModel, ecModel, api, payload) {},\n\n    /**\n     * Highlight series or specified data item.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    highlight: function (seriesModel, ecModel, api, payload) {\n        toggleHighlight(seriesModel.getData(), payload, 'emphasis');\n    },\n\n    /**\n     * Downplay series or specified data item.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    downplay: function (seriesModel, ecModel, api, payload) {\n        toggleHighlight(seriesModel.getData(), payload, 'normal');\n    },\n\n    /**\n     * Remove self.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    remove: function (ecModel, api) {\n        this.group.removeAll();\n    },\n\n    /**\n     * Dispose self.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    dispose: function () {},\n\n    /**\n     * Rendering preparation in progressive mode.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    incrementalPrepareRender: null,\n\n    /**\n     * Render in progressive mode.\n     * @param  {Object} params See taskParams in `stream/task.js`\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    incrementalRender: null,\n\n    /**\n     * Update transform directly.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     * @return {Object} {update: true}\n     */\n    updateTransform: null,\n\n    /**\n     * The view contains the given point.\n     * @interface\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    // containPoint: function () {}\n\n    /**\n     * @param {string} eventType\n     * @param {Object} query\n     * @param {module:zrender/Element} targetEl\n     * @param {Object} packedEvent\n     * @return {boolen} Pass only when return `true`.\n     */\n    filterForExposedEvent: null\n\n};\n\nvar chartProto = Chart.prototype;\nchartProto.updateView\n    = chartProto.updateLayout\n    = chartProto.updateVisual\n    = function (seriesModel, ecModel, api, payload) {\n        this.render(seriesModel, ecModel, api, payload);\n    };\n\n/**\n * Set state of single element\n * @param  {module:zrender/Element} el\n * @param  {string} state\n */\nfunction elSetState(el, state) {\n    if (el) {\n        el.trigger(state);\n        if (el.type === 'group') {\n            for (var i = 0; i < el.childCount(); i++) {\n                elSetState(el.childAt(i), state);\n            }\n        }\n    }\n}\n/**\n * @param  {module:echarts/data/List} data\n * @param  {Object} payload\n * @param  {string} state 'normal'|'emphasis'\n */\nfunction toggleHighlight(data, payload, state) {\n    var dataIndex = queryDataIndex(data, payload);\n\n    if (dataIndex != null) {\n        each$1(normalizeToArray(dataIndex), function (dataIdx) {\n            elSetState(data.getItemGraphicEl(dataIdx), state);\n        });\n    }\n    else {\n        data.eachItemGraphicEl(function (el) {\n            elSetState(el, state);\n        });\n    }\n}\n\n// Enable Chart.extend.\nenableClassExtend(Chart, ['dispose']);\n\n// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(Chart, {registerWhenExtend: true});\n\nChart.markUpdateMethod = function (payload, methodName) {\n    inner$5(payload).updateMethod = methodName;\n};\n\nfunction renderTaskPlan(context) {\n    return renderPlanner(context.model);\n}\n\nfunction renderTaskReset(context) {\n    var seriesModel = context.model;\n    var ecModel = context.ecModel;\n    var api = context.api;\n    var payload = context.payload;\n    // ???! remove updateView updateVisual\n    var progressiveRender = seriesModel.pipelineContext.progressiveRender;\n    var view = context.view;\n\n    var updateMethod = payload && inner$5(payload).updateMethod;\n    var methodName = progressiveRender\n        ? 'incrementalPrepareRender'\n        : (updateMethod && view[updateMethod])\n        ? updateMethod\n        // `appendData` is also supported when data amount\n        // is less than progressive threshold.\n        : 'render';\n\n    if (methodName !== 'render') {\n        view[methodName](seriesModel, ecModel, api, payload);\n    }\n\n    return progressMethodMap[methodName];\n}\n\nvar progressMethodMap = {\n    incrementalPrepareRender: {\n        progress: function (params, context) {\n            context.view.incrementalRender(\n                params, context.model, context.ecModel, context.api, context.payload\n            );\n        }\n    },\n    render: {\n        // Put view.render in `progress` to support appendData. But in this case\n        // view.render should not be called in reset, otherwise it will be called\n        // twise. Use `forceFirstProgress` to make sure that view.render is called\n        // in any cases.\n        forceFirstProgress: true,\n        progress: function (params, context) {\n            context.view.render(\n                context.model, context.ecModel, context.api, context.payload\n            );\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar ORIGIN_METHOD = '\\0__throttleOriginMethod';\nvar RATE = '\\0__throttleRate';\nvar THROTTLE_TYPE = '\\0__throttleType';\n\n/**\n * @public\n * @param {(Function)} fn\n * @param {number} [delay=0] Unit: ms.\n * @param {boolean} [debounce=false]\n *        true: If call interval less than `delay`, only the last call works.\n *        false: If call interval less than `delay, call works on fixed rate.\n * @return {(Function)} throttled fn.\n */\nfunction throttle(fn, delay, debounce) {\n\n    var currCall;\n    var lastCall = 0;\n    var lastExec = 0;\n    var timer = null;\n    var diff;\n    var scope;\n    var args;\n    var debounceNextCall;\n\n    delay = delay || 0;\n\n    function exec() {\n        lastExec = (new Date()).getTime();\n        timer = null;\n        fn.apply(scope, args || []);\n    }\n\n    var cb = function () {\n        currCall = (new Date()).getTime();\n        scope = this;\n        args = arguments;\n        var thisDelay = debounceNextCall || delay;\n        var thisDebounce = debounceNextCall || debounce;\n        debounceNextCall = null;\n        diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay;\n\n        clearTimeout(timer);\n\n        // Here we should make sure that: the `exec` SHOULD NOT be called later\n        // than a new call of `cb`, that is, preserving the command order. Consider\n        // calculating \"scale rate\" when roaming as an example. When a call of `cb`\n        // happens, either the `exec` is called dierectly, or the call is delayed.\n        // But the delayed call should never be later than next call of `cb`. Under\n        // this assurance, we can simply update view state each time `dispatchAction`\n        // triggered by user roaming, but not need to add extra code to avoid the\n        // state being \"rolled-back\".\n        if (thisDebounce) {\n            timer = setTimeout(exec, thisDelay);\n        }\n        else {\n            if (diff >= 0) {\n                exec();\n            }\n            else {\n                timer = setTimeout(exec, -diff);\n            }\n        }\n\n        lastCall = currCall;\n    };\n\n    /**\n     * Clear throttle.\n     * @public\n     */\n    cb.clear = function () {\n        if (timer) {\n            clearTimeout(timer);\n            timer = null;\n        }\n    };\n\n    /**\n     * Enable debounce once.\n     */\n    cb.debounceNextCall = function (debounceDelay) {\n        debounceNextCall = debounceDelay;\n    };\n\n    return cb;\n}\n\n/**\n * Create throttle method or update throttle rate.\n *\n * @example\n * ComponentView.prototype.render = function () {\n *     ...\n *     throttle.createOrUpdate(\n *         this,\n *         '_dispatchAction',\n *         this.model.get('throttle'),\n *         'fixRate'\n *     );\n * };\n * ComponentView.prototype.remove = function () {\n *     throttle.clear(this, '_dispatchAction');\n * };\n * ComponentView.prototype.dispose = function () {\n *     throttle.clear(this, '_dispatchAction');\n * };\n *\n * @public\n * @param {Object} obj\n * @param {string} fnAttr\n * @param {number} [rate]\n * @param {string} [throttleType='fixRate'] 'fixRate' or 'debounce'\n * @return {Function} throttled function.\n */\nfunction createOrUpdate(obj, fnAttr, rate, throttleType) {\n    var fn = obj[fnAttr];\n\n    if (!fn) {\n        return;\n    }\n\n    var originFn = fn[ORIGIN_METHOD] || fn;\n    var lastThrottleType = fn[THROTTLE_TYPE];\n    var lastRate = fn[RATE];\n\n    if (lastRate !== rate || lastThrottleType !== throttleType) {\n        if (rate == null || !throttleType) {\n            return (obj[fnAttr] = originFn);\n        }\n\n        fn = obj[fnAttr] = throttle(\n            originFn, rate, throttleType === 'debounce'\n        );\n        fn[ORIGIN_METHOD] = originFn;\n        fn[THROTTLE_TYPE] = throttleType;\n        fn[RATE] = rate;\n    }\n\n    return fn;\n}\n\n/**\n * Clear throttle. Example see throttle.createOrUpdate.\n *\n * @public\n * @param {Object} obj\n * @param {string} fnAttr\n */\nfunction clear(obj, fnAttr) {\n    var fn = obj[fnAttr];\n    if (fn && fn[ORIGIN_METHOD]) {\n        obj[fnAttr] = fn[ORIGIN_METHOD];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar seriesColor = {\n    createOnAllSeries: true,\n    performRawSeries: true,\n    reset: function (seriesModel, ecModel) {\n        var data = seriesModel.getData();\n        var colorAccessPath = (seriesModel.visualColorAccessPath || 'itemStyle.color').split('.');\n        var color = seriesModel.get(colorAccessPath) // Set in itemStyle\n            || seriesModel.getColorFromPalette(\n                // TODO series count changed.\n                seriesModel.name, null, ecModel.getSeriesCount()\n            );  // Default color\n\n        // FIXME Set color function or use the platte color\n        data.setVisual('color', color);\n\n        // Only visible series has each data be visual encoded\n        if (!ecModel.isSeriesFiltered(seriesModel)) {\n            if (typeof color === 'function' && !(color instanceof Gradient)) {\n                data.each(function (idx) {\n                    data.setItemVisual(\n                        idx, 'color', color(seriesModel.getDataParams(idx))\n                    );\n                });\n            }\n\n            // itemStyle in each data item\n            var dataEach = function (data, idx) {\n                var itemModel = data.getItemModel(idx);\n                var color = itemModel.get(colorAccessPath, true);\n                if (color != null) {\n                    data.setItemVisual(idx, 'color', color);\n                }\n            };\n\n            return { dataEach: data.hasItemOption ? dataEach : null };\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar lang = {\n    toolbox: {\n        brush: {\n            title: {\n                rect: '矩形选择',\n                polygon: '圈选',\n                lineX: '横向选择',\n                lineY: '纵向选择',\n                keep: '保持选择',\n                clear: '清除选择'\n            }\n        },\n        dataView: {\n            title: '数据视图',\n            lang: ['数据视图', '关闭', '刷新']\n        },\n        dataZoom: {\n            title: {\n                zoom: '区域缩放',\n                back: '区域缩放还原'\n            }\n        },\n        magicType: {\n            title: {\n                line: '切换为折线图',\n                bar: '切换为柱状图',\n                stack: '切换为堆叠',\n                tiled: '切换为平铺'\n            }\n        },\n        restore: {\n            title: '还原'\n        },\n        saveAsImage: {\n            title: '保存为图片',\n            lang: ['右键另存为图片']\n        }\n    },\n    series: {\n        typeNames: {\n            pie: '饼图',\n            bar: '柱状图',\n            line: '折线图',\n            scatter: '散点图',\n            effectScatter: '涟漪散点图',\n            radar: '雷达图',\n            tree: '树图',\n            treemap: '矩形树图',\n            boxplot: '箱型图',\n            candlestick: 'K线图',\n            k: 'K线图',\n            heatmap: '热力图',\n            map: '地图',\n            parallel: '平行坐标图',\n            lines: '线图',\n            graph: '关系图',\n            sankey: '桑基图',\n            funnel: '漏斗图',\n            gauge: '仪表盘图',\n            pictorialBar: '象形柱图',\n            themeRiver: '主题河流图',\n            sunburst: '旭日图'\n        }\n    },\n    aria: {\n        general: {\n            withTitle: '这是一个关于“{title}”的图表。',\n            withoutTitle: '这是一个图表，'\n        },\n        series: {\n            single: {\n                prefix: '',\n                withName: '图表类型是{seriesType}，表示{seriesName}。',\n                withoutName: '图表类型是{seriesType}。'\n            },\n            multiple: {\n                prefix: '它由{seriesCount}个图表系列组成。',\n                withName: '第{seriesId}个系列是一个表示{seriesName}的{seriesType}，',\n                withoutName: '第{seriesId}个系列是一个{seriesType}，',\n                separator: {\n                    middle: '；',\n                    end: '。'\n                }\n            }\n        },\n        data: {\n            allData: '其数据是——',\n            partialData: '其中，前{displayCnt}项是——',\n            withName: '{name}的数据是{value}',\n            withoutName: '{value}',\n            separator: {\n                middle: '，',\n                end: ''\n            }\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar aria = function (dom, ecModel) {\n    var ariaModel = ecModel.getModel('aria');\n    if (!ariaModel.get('show')) {\n        return;\n    }\n    else if (ariaModel.get('description')) {\n        dom.setAttribute('aria-label', ariaModel.get('description'));\n        return;\n    }\n\n    var seriesCnt = 0;\n    ecModel.eachSeries(function (seriesModel, idx) {\n        ++seriesCnt;\n    }, this);\n\n    var maxDataCnt = ariaModel.get('data.maxCount') || 10;\n    var maxSeriesCnt = ariaModel.get('series.maxCount') || 10;\n    var displaySeriesCnt = Math.min(seriesCnt, maxSeriesCnt);\n\n    var ariaLabel;\n    if (seriesCnt < 1) {\n        // No series, no aria label\n        return;\n    }\n    else {\n        var title = getTitle();\n        if (title) {\n            ariaLabel = replace(getConfig('general.withTitle'), {\n                title: title\n            });\n        }\n        else {\n            ariaLabel = getConfig('general.withoutTitle');\n        }\n\n        var seriesLabels = [];\n        var prefix = seriesCnt > 1\n            ? 'series.multiple.prefix'\n            : 'series.single.prefix';\n        ariaLabel += replace(getConfig(prefix), { seriesCount: seriesCnt });\n\n        ecModel.eachSeries(function (seriesModel, idx) {\n            if (idx < displaySeriesCnt) {\n                var seriesLabel;\n\n                var seriesName = seriesModel.get('name');\n                var seriesTpl = 'series.'\n                    + (seriesCnt > 1 ? 'multiple' : 'single') + '.';\n                seriesLabel = getConfig(seriesName\n                    ? seriesTpl + 'withName'\n                    : seriesTpl + 'withoutName');\n\n                seriesLabel = replace(seriesLabel, {\n                    seriesId: seriesModel.seriesIndex,\n                    seriesName: seriesModel.get('name'),\n                    seriesType: getSeriesTypeName(seriesModel.subType)\n                });\n\n                var data = seriesModel.getData();\n                window.data = data;\n                if (data.count() > maxDataCnt) {\n                    // Show part of data\n                    seriesLabel += replace(getConfig('data.partialData'), {\n                        displayCnt: maxDataCnt\n                    });\n                }\n                else {\n                    seriesLabel += getConfig('data.allData');\n                }\n\n                var dataLabels = [];\n                for (var i = 0; i < data.count(); i++) {\n                    if (i < maxDataCnt) {\n                        var name = data.getName(i);\n                        var value = retrieveRawValue(data, i);\n                        dataLabels.push(\n                            replace(\n                                name\n                                    ? getConfig('data.withName')\n                                    : getConfig('data.withoutName'),\n                                {\n                                    name: name,\n                                    value: value\n                                }\n                            )\n                        );\n                    }\n                }\n                seriesLabel += dataLabels\n                    .join(getConfig('data.separator.middle'))\n                    + getConfig('data.separator.end');\n\n                seriesLabels.push(seriesLabel);\n            }\n        });\n\n        ariaLabel += seriesLabels\n            .join(getConfig('series.multiple.separator.middle'))\n            + getConfig('series.multiple.separator.end');\n\n        dom.setAttribute('aria-label', ariaLabel);\n    }\n\n    function replace(str, keyValues) {\n        if (typeof str !== 'string') {\n            return str;\n        }\n\n        var result = str;\n        each$1(keyValues, function (value, key) {\n            result = result.replace(\n                new RegExp('\\\\{\\\\s*' + key + '\\\\s*\\\\}', 'g'),\n                value\n            );\n        });\n        return result;\n    }\n\n    function getConfig(path) {\n        var userConfig = ariaModel.get(path);\n        if (userConfig == null) {\n            var pathArr = path.split('.');\n            var result = lang.aria;\n            for (var i = 0; i < pathArr.length; ++i) {\n                result = result[pathArr[i]];\n            }\n            return result;\n        }\n        else {\n            return userConfig;\n        }\n    }\n\n    function getTitle() {\n        var title = ecModel.getModel('title').option;\n        if (title && title.length) {\n            title = title[0];\n        }\n        return title && title.text;\n    }\n\n    function getSeriesTypeName(type) {\n        return lang.series.typeNames[type] || '自定义图';\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PI$1 = Math.PI;\n\n/**\n * @param {module:echarts/ExtensionAPI} api\n * @param {Object} [opts]\n * @param {string} [opts.text]\n * @param {string} [opts.color]\n * @param {string} [opts.textColor]\n * @return {module:zrender/Element}\n */\nvar loadingDefault = function (api, opts) {\n    opts = opts || {};\n    defaults(opts, {\n        text: 'loading',\n        color: '#c23531',\n        textColor: '#000',\n        maskColor: 'rgba(255, 255, 255, 0.8)',\n        zlevel: 0\n    });\n    var mask = new Rect({\n        style: {\n            fill: opts.maskColor\n        },\n        zlevel: opts.zlevel,\n        z: 10000\n    });\n    var arc = new Arc({\n        shape: {\n            startAngle: -PI$1 / 2,\n            endAngle: -PI$1 / 2 + 0.1,\n            r: 10\n        },\n        style: {\n            stroke: opts.color,\n            lineCap: 'round',\n            lineWidth: 5\n        },\n        zlevel: opts.zlevel,\n        z: 10001\n    });\n    var labelRect = new Rect({\n        style: {\n            fill: 'none',\n            text: opts.text,\n            textPosition: 'right',\n            textDistance: 10,\n            textFill: opts.textColor\n        },\n        zlevel: opts.zlevel,\n        z: 10001\n    });\n\n    arc.animateShape(true)\n        .when(1000, {\n            endAngle: PI$1 * 3 / 2\n        })\n        .start('circularInOut');\n    arc.animateShape(true)\n        .when(1000, {\n            startAngle: PI$1 * 3 / 2\n        })\n        .delay(300)\n        .start('circularInOut');\n\n    var group = new Group();\n    group.add(arc);\n    group.add(labelRect);\n    group.add(mask);\n    // Inject resize\n    group.resize = function () {\n        var cx = api.getWidth() / 2;\n        var cy = api.getHeight() / 2;\n        arc.setShape({\n            cx: cx,\n            cy: cy\n        });\n        var r = arc.shape.r;\n        labelRect.setShape({\n            x: cx - r,\n            y: cy - r,\n            width: r * 2,\n            height: r * 2\n        });\n\n        mask.setShape({\n            x: 0,\n            y: 0,\n            width: api.getWidth(),\n            height: api.getHeight()\n        });\n    };\n    group.resize();\n    return group;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/stream/Scheduler\n */\n\n/**\n * @constructor\n */\nfunction Scheduler(ecInstance, api, dataProcessorHandlers, visualHandlers) {\n    this.ecInstance = ecInstance;\n    this.api = api;\n    this.unfinished;\n\n    // Fix current processors in case that in some rear cases that\n    // processors might be registered after echarts instance created.\n    // Register processors incrementally for a echarts instance is\n    // not supported by this stream architecture.\n    var dataProcessorHandlers = this._dataProcessorHandlers = dataProcessorHandlers.slice();\n    var visualHandlers = this._visualHandlers = visualHandlers.slice();\n    this._allHandlers = dataProcessorHandlers.concat(visualHandlers);\n\n    /**\n     * @private\n     * @type {\n     *     [handlerUID: string]: {\n     *         seriesTaskMap?: {\n     *             [seriesUID: string]: Task\n     *         },\n     *         overallTask?: Task\n     *     }\n     * }\n     */\n    this._stageTaskMap = createHashMap();\n}\n\nvar proto = Scheduler.prototype;\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} payload\n */\nproto.restoreData = function (ecModel, payload) {\n    // TODO: Only restroe needed series and components, but not all components.\n    // Currently `restoreData` of all of the series and component will be called.\n    // But some independent components like `title`, `legend`, `graphic`, `toolbox`,\n    // `tooltip`, `axisPointer`, etc, do not need series refresh when `setOption`,\n    // and some components like coordinate system, axes, dataZoom, visualMap only\n    // need their target series refresh.\n    // (1) If we are implementing this feature some day, we should consider these cases:\n    // if a data processor depends on a component (e.g., dataZoomProcessor depends\n    // on the settings of `dataZoom`), it should be re-performed if the component\n    // is modified by `setOption`.\n    // (2) If a processor depends on sevral series, speicified by its `getTargetSeries`,\n    // it should be re-performed when the result array of `getTargetSeries` changed.\n    // We use `dependencies` to cover these issues.\n    // (3) How to update target series when coordinate system related components modified.\n\n    // TODO: simply the dirty mechanism? Check whether only the case here can set tasks dirty,\n    // and this case all of the tasks will be set as dirty.\n\n    ecModel.restoreData(payload);\n\n    // Theoretically an overall task not only depends on each of its target series, but also\n    // depends on all of the series.\n    // The overall task is not in pipeline, and `ecModel.restoreData` only set pipeline tasks\n    // dirty. If `getTargetSeries` of an overall task returns nothing, we should also ensure\n    // that the overall task is set as dirty and to be performed, otherwise it probably cause\n    // state chaos. So we have to set dirty of all of the overall tasks manually, otherwise it\n    // probably cause state chaos (consider `dataZoomProcessor`).\n    this._stageTaskMap.each(function (taskRecord) {\n        var overallTask = taskRecord.overallTask;\n        overallTask && overallTask.dirty();\n    });\n};\n\n// If seriesModel provided, incremental threshold is check by series data.\nproto.getPerformArgs = function (task, isBlock) {\n    // For overall task\n    if (!task.__pipeline) {\n        return;\n    }\n\n    var pipeline = this._pipelineMap.get(task.__pipeline.id);\n    var pCtx = pipeline.context;\n    var incremental = !isBlock\n        && pipeline.progressiveEnabled\n        && (!pCtx || pCtx.progressiveRender)\n        && task.__idxInPipeline > pipeline.blockIndex;\n\n    var step = incremental ? pipeline.step : null;\n    var modDataCount = pCtx && pCtx.modDataCount;\n    var modBy = modDataCount != null ? Math.ceil(modDataCount / step) : null;\n\n    return {step: step, modBy: modBy, modDataCount: modDataCount};\n};\n\nproto.getPipeline = function (pipelineId) {\n    return this._pipelineMap.get(pipelineId);\n};\n\n/**\n * Current, progressive rendering starts from visual and layout.\n * Always detect render mode in the same stage, avoiding that incorrect\n * detection caused by data filtering.\n * Caution:\n * `updateStreamModes` use `seriesModel.getData()`.\n */\nproto.updateStreamModes = function (seriesModel, view) {\n    var pipeline = this._pipelineMap.get(seriesModel.uid);\n    var data = seriesModel.getData();\n    var dataLen = data.count();\n\n    // `progressiveRender` means that can render progressively in each\n    // animation frame. Note that some types of series do not provide\n    // `view.incrementalPrepareRender` but support `chart.appendData`. We\n    // use the term `incremental` but not `progressive` to describe the\n    // case that `chart.appendData`.\n    var progressiveRender = pipeline.progressiveEnabled\n        && view.incrementalPrepareRender\n        && dataLen >= pipeline.threshold;\n\n    var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold');\n\n    // TODO: modDataCount should not updated if `appendData`, otherwise cause whole repaint.\n    // see `test/candlestick-large3.html`\n    var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null;\n\n    seriesModel.pipelineContext = pipeline.context = {\n        progressiveRender: progressiveRender,\n        modDataCount: modDataCount,\n        large: large\n    };\n};\n\nproto.restorePipelines = function (ecModel) {\n    var scheduler = this;\n    var pipelineMap = scheduler._pipelineMap = createHashMap();\n\n    ecModel.eachSeries(function (seriesModel) {\n        var progressive = seriesModel.getProgressive();\n        var pipelineId = seriesModel.uid;\n\n        pipelineMap.set(pipelineId, {\n            id: pipelineId,\n            head: null,\n            tail: null,\n            threshold: seriesModel.getProgressiveThreshold(),\n            progressiveEnabled: progressive\n                && !(seriesModel.preventIncremental && seriesModel.preventIncremental()),\n            blockIndex: -1,\n            step: Math.round(progressive || 700),\n            count: 0\n        });\n\n        pipe(scheduler, seriesModel, seriesModel.dataTask);\n    });\n};\n\nproto.prepareStageTasks = function () {\n    var stageTaskMap = this._stageTaskMap;\n    var ecModel = this.ecInstance.getModel();\n    var api = this.api;\n\n    each$1(this._allHandlers, function (handler) {\n        var record = stageTaskMap.get(handler.uid) || stageTaskMap.set(handler.uid, []);\n\n        handler.reset && createSeriesStageTask(this, handler, record, ecModel, api);\n        handler.overallReset && createOverallStageTask(this, handler, record, ecModel, api);\n    }, this);\n};\n\nproto.prepareView = function (view, model, ecModel, api) {\n    var renderTask = view.renderTask;\n    var context = renderTask.context;\n\n    context.model = model;\n    context.ecModel = ecModel;\n    context.api = api;\n\n    renderTask.__block = !view.incrementalPrepareRender;\n\n    pipe(this, model, renderTask);\n};\n\n\nproto.performDataProcessorTasks = function (ecModel, payload) {\n    // If we do not use `block` here, it should be considered when to update modes.\n    performStageTasks(this, this._dataProcessorHandlers, ecModel, payload, {block: true});\n};\n\n// opt\n// opt.visualType: 'visual' or 'layout'\n// opt.setDirty\nproto.performVisualTasks = function (ecModel, payload, opt) {\n    performStageTasks(this, this._visualHandlers, ecModel, payload, opt);\n};\n\nfunction performStageTasks(scheduler, stageHandlers, ecModel, payload, opt) {\n    opt = opt || {};\n    var unfinished;\n\n    each$1(stageHandlers, function (stageHandler, idx) {\n        if (opt.visualType && opt.visualType !== stageHandler.visualType) {\n            return;\n        }\n\n        var stageHandlerRecord = scheduler._stageTaskMap.get(stageHandler.uid);\n        var seriesTaskMap = stageHandlerRecord.seriesTaskMap;\n        var overallTask = stageHandlerRecord.overallTask;\n\n        if (overallTask) {\n            var overallNeedDirty;\n            var agentStubMap = overallTask.agentStubMap;\n            agentStubMap.each(function (stub) {\n                if (needSetDirty(opt, stub)) {\n                    stub.dirty();\n                    overallNeedDirty = true;\n                }\n            });\n            overallNeedDirty && overallTask.dirty();\n            updatePayload(overallTask, payload);\n            var performArgs = scheduler.getPerformArgs(overallTask, opt.block);\n            // Execute stubs firstly, which may set the overall task dirty,\n            // then execute the overall task. And stub will call seriesModel.setData,\n            // which ensures that in the overallTask seriesModel.getData() will not\n            // return incorrect data.\n            agentStubMap.each(function (stub) {\n                stub.perform(performArgs);\n            });\n            unfinished |= overallTask.perform(performArgs);\n        }\n        else if (seriesTaskMap) {\n            seriesTaskMap.each(function (task, pipelineId) {\n                if (needSetDirty(opt, task)) {\n                    task.dirty();\n                }\n                var performArgs = scheduler.getPerformArgs(task, opt.block);\n                performArgs.skip = !stageHandler.performRawSeries\n                    && ecModel.isSeriesFiltered(task.context.model);\n                updatePayload(task, payload);\n                unfinished |= task.perform(performArgs);\n            });\n        }\n    });\n\n    function needSetDirty(opt, task) {\n        return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id));\n    }\n\n    scheduler.unfinished |= unfinished;\n}\n\nproto.performSeriesTasks = function (ecModel) {\n    var unfinished;\n\n    ecModel.eachSeries(function (seriesModel) {\n        // Progress to the end for dataInit and dataRestore.\n        unfinished |= seriesModel.dataTask.perform();\n    });\n\n    this.unfinished |= unfinished;\n};\n\nproto.plan = function () {\n    // Travel pipelines, check block.\n    this._pipelineMap.each(function (pipeline) {\n        var task = pipeline.tail;\n        do {\n            if (task.__block) {\n                pipeline.blockIndex = task.__idxInPipeline;\n                break;\n            }\n            task = task.getUpstream();\n        }\n        while (task);\n    });\n};\n\nvar updatePayload = proto.updatePayload = function (task, payload) {\n    payload !== 'remain' && (task.context.payload = payload);\n};\n\nfunction createSeriesStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) {\n    var seriesTaskMap = stageHandlerRecord.seriesTaskMap\n        || (stageHandlerRecord.seriesTaskMap = createHashMap());\n    var seriesType = stageHandler.seriesType;\n    var getTargetSeries = stageHandler.getTargetSeries;\n\n    // If a stageHandler should cover all series, `createOnAllSeries` should be declared mandatorily,\n    // to avoid some typo or abuse. Otherwise if an extension do not specify a `seriesType`,\n    // it works but it may cause other irrelevant charts blocked.\n    if (stageHandler.createOnAllSeries) {\n        ecModel.eachRawSeries(create);\n    }\n    else if (seriesType) {\n        ecModel.eachRawSeriesByType(seriesType, create);\n    }\n    else if (getTargetSeries) {\n        getTargetSeries(ecModel, api).each(create);\n    }\n\n    function create(seriesModel) {\n        var pipelineId = seriesModel.uid;\n\n        // Init tasks for each seriesModel only once.\n        // Reuse original task instance.\n        var task = seriesTaskMap.get(pipelineId)\n            || seriesTaskMap.set(pipelineId, createTask({\n                plan: seriesTaskPlan,\n                reset: seriesTaskReset,\n                count: seriesTaskCount\n            }));\n        task.context = {\n            model: seriesModel,\n            ecModel: ecModel,\n            api: api,\n            useClearVisual: stageHandler.isVisual && !stageHandler.isLayout,\n            plan: stageHandler.plan,\n            reset: stageHandler.reset,\n            scheduler: scheduler\n        };\n        pipe(scheduler, seriesModel, task);\n    }\n\n    // Clear unused series tasks.\n    var pipelineMap = scheduler._pipelineMap;\n    seriesTaskMap.each(function (task, pipelineId) {\n        if (!pipelineMap.get(pipelineId)) {\n            task.dispose();\n            seriesTaskMap.removeKey(pipelineId);\n        }\n    });\n}\n\nfunction createOverallStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) {\n    var overallTask = stageHandlerRecord.overallTask = stageHandlerRecord.overallTask\n        // For overall task, the function only be called on reset stage.\n        || createTask({reset: overallTaskReset});\n\n    overallTask.context = {\n        ecModel: ecModel,\n        api: api,\n        overallReset: stageHandler.overallReset,\n        scheduler: scheduler\n    };\n\n    // Reuse orignal stubs.\n    var agentStubMap = overallTask.agentStubMap = overallTask.agentStubMap || createHashMap();\n\n    var seriesType = stageHandler.seriesType;\n    var getTargetSeries = stageHandler.getTargetSeries;\n    var overallProgress = true;\n    var modifyOutputEnd = stageHandler.modifyOutputEnd;\n\n    // An overall task with seriesType detected or has `getTargetSeries`, we add\n    // stub in each pipelines, it will set the overall task dirty when the pipeline\n    // progress. Moreover, to avoid call the overall task each frame (too frequent),\n    // we set the pipeline block.\n    if (seriesType) {\n        ecModel.eachRawSeriesByType(seriesType, createStub);\n    }\n    else if (getTargetSeries) {\n        getTargetSeries(ecModel, api).each(createStub);\n    }\n    // Otherwise, (usually it is legancy case), the overall task will only be\n    // executed when upstream dirty. Otherwise the progressive rendering of all\n    // pipelines will be disabled unexpectedly. But it still needs stubs to receive\n    // dirty info from upsteam.\n    else {\n        overallProgress = false;\n        each$1(ecModel.getSeries(), createStub);\n    }\n\n    function createStub(seriesModel) {\n        var pipelineId = seriesModel.uid;\n        var stub = agentStubMap.get(pipelineId);\n        if (!stub) {\n            stub = agentStubMap.set(pipelineId, createTask(\n                {reset: stubReset, onDirty: stubOnDirty}\n            ));\n            // When the result of `getTargetSeries` changed, the overallTask\n            // should be set as dirty and re-performed.\n            overallTask.dirty();\n        }\n        stub.context = {\n            model: seriesModel,\n            overallProgress: overallProgress,\n            modifyOutputEnd: modifyOutputEnd\n        };\n        stub.agent = overallTask;\n        stub.__block = overallProgress;\n\n        pipe(scheduler, seriesModel, stub);\n    }\n\n    // Clear unused stubs.\n    var pipelineMap = scheduler._pipelineMap;\n    agentStubMap.each(function (stub, pipelineId) {\n        if (!pipelineMap.get(pipelineId)) {\n            stub.dispose();\n            // When the result of `getTargetSeries` changed, the overallTask\n            // should be set as dirty and re-performed.\n            overallTask.dirty();\n            agentStubMap.removeKey(pipelineId);\n        }\n    });\n}\n\nfunction overallTaskReset(context) {\n    context.overallReset(\n        context.ecModel, context.api, context.payload\n    );\n}\n\nfunction stubReset(context, upstreamContext) {\n    return context.overallProgress && stubProgress;\n}\n\nfunction stubProgress() {\n    this.agent.dirty();\n    this.getDownstream().dirty();\n}\n\nfunction stubOnDirty() {\n    this.agent && this.agent.dirty();\n}\n\nfunction seriesTaskPlan(context) {\n    return context.plan && context.plan(\n        context.model, context.ecModel, context.api, context.payload\n    );\n}\n\nfunction seriesTaskReset(context) {\n    if (context.useClearVisual) {\n        context.data.clearAllVisual();\n    }\n    var resetDefines = context.resetDefines = normalizeToArray(context.reset(\n        context.model, context.ecModel, context.api, context.payload\n    ));\n    return resetDefines.length > 1\n        ? map(resetDefines, function (v, idx) {\n            return makeSeriesTaskProgress(idx);\n        })\n        : singleSeriesTaskProgress;\n}\n\nvar singleSeriesTaskProgress = makeSeriesTaskProgress(0);\n\nfunction makeSeriesTaskProgress(resetDefineIdx) {\n    return function (params, context) {\n        var data = context.data;\n        var resetDefine = context.resetDefines[resetDefineIdx];\n\n        if (resetDefine && resetDefine.dataEach) {\n            for (var i = params.start; i < params.end; i++) {\n                resetDefine.dataEach(data, i);\n            }\n        }\n        else if (resetDefine && resetDefine.progress) {\n            resetDefine.progress(params, data);\n        }\n    };\n}\n\nfunction seriesTaskCount(context) {\n    return context.data.count();\n}\n\nfunction pipe(scheduler, seriesModel, task) {\n    var pipelineId = seriesModel.uid;\n    var pipeline = scheduler._pipelineMap.get(pipelineId);\n    !pipeline.head && (pipeline.head = task);\n    pipeline.tail && pipeline.tail.pipe(task);\n    pipeline.tail = task;\n    task.__idxInPipeline = pipeline.count++;\n    task.__pipeline = pipeline;\n}\n\nScheduler.wrapStageHandler = function (stageHandler, visualType) {\n    if (isFunction$1(stageHandler)) {\n        stageHandler = {\n            overallReset: stageHandler,\n            seriesType: detectSeriseType(stageHandler)\n        };\n    }\n\n    stageHandler.uid = getUID('stageHandler');\n    visualType && (stageHandler.visualType = visualType);\n\n    return stageHandler;\n};\n\n\n\n/**\n * Only some legacy stage handlers (usually in echarts extensions) are pure function.\n * To ensure that they can work normally, they should work in block mode, that is,\n * they should not be started util the previous tasks finished. So they cause the\n * progressive rendering disabled. We try to detect the series type, to narrow down\n * the block range to only the series type they concern, but not all series.\n */\nfunction detectSeriseType(legacyFunc) {\n    seriesType = null;\n    try {\n        // Assume there is no async when calling `eachSeriesByType`.\n        legacyFunc(ecModelMock, apiMock);\n    }\n    catch (e) {\n    }\n    return seriesType;\n}\n\nvar ecModelMock = {};\nvar apiMock = {};\nvar seriesType;\n\nmockMethods(ecModelMock, GlobalModel);\nmockMethods(apiMock, ExtensionAPI);\necModelMock.eachSeriesByType = ecModelMock.eachRawSeriesByType = function (type) {\n    seriesType = type;\n};\necModelMock.eachComponent = function (cond) {\n    if (cond.mainType === 'series' && cond.subType) {\n        seriesType = cond.subType;\n    }\n};\n\nfunction mockMethods(target, Clz) {\n    /* eslint-disable */\n    for (var name in Clz.prototype) {\n        // Do not use hasOwnProperty\n        target[name] = noop;\n    }\n    /* eslint-enable */\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar colorAll = [\n    '#37A2DA', '#32C5E9', '#67E0E3', '#9FE6B8', '#FFDB5C', '#ff9f7f',\n    '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF'\n];\n\nvar lightTheme = {\n\n    color: colorAll,\n\n    colorLayer: [\n        ['#37A2DA', '#ffd85c', '#fd7b5f'],\n        ['#37A2DA', '#67E0E3', '#FFDB5C', '#ff9f7f', '#E062AE', '#9d96f5'],\n        ['#37A2DA', '#32C5E9', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#e7bcf3', '#8378EA', '#96BFFF'],\n        colorAll\n    ]\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar contrastColor = '#eee';\nvar axisCommon = function () {\n    return {\n        axisLine: {\n            lineStyle: {\n                color: contrastColor\n            }\n        },\n        axisTick: {\n            lineStyle: {\n                color: contrastColor\n            }\n        },\n        axisLabel: {\n            textStyle: {\n                color: contrastColor\n            }\n        },\n        splitLine: {\n            lineStyle: {\n                type: 'dashed',\n                color: '#aaa'\n            }\n        },\n        splitArea: {\n            areaStyle: {\n                color: contrastColor\n            }\n        }\n    };\n};\n\nvar colorPalette = [\n    '#dd6b66', '#759aa0', '#e69d87', '#8dc1a9', '#ea7e53',\n    '#eedd78', '#73a373', '#73b9bc', '#7289ab', '#91ca8c', '#f49f42'\n];\nvar theme = {\n    color: colorPalette,\n    backgroundColor: '#333',\n    tooltip: {\n        axisPointer: {\n            lineStyle: {\n                color: contrastColor\n            },\n            crossStyle: {\n                color: contrastColor\n            }\n        }\n    },\n    legend: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    textStyle: {\n        color: contrastColor\n    },\n    title: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    toolbox: {\n        iconStyle: {\n            normal: {\n                borderColor: contrastColor\n            }\n        }\n    },\n    dataZoom: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    visualMap: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    timeline: {\n        lineStyle: {\n            color: contrastColor\n        },\n        itemStyle: {\n            normal: {\n                color: colorPalette[1]\n            }\n        },\n        label: {\n            normal: {\n                textStyle: {\n                    color: contrastColor\n                }\n            }\n        },\n        controlStyle: {\n            normal: {\n                color: contrastColor,\n                borderColor: contrastColor\n            }\n        }\n    },\n    timeAxis: axisCommon(),\n    logAxis: axisCommon(),\n    valueAxis: axisCommon(),\n    categoryAxis: axisCommon(),\n\n    line: {\n        symbol: 'circle'\n    },\n    graph: {\n        color: colorPalette\n    },\n    gauge: {\n        title: {\n            textStyle: {\n                color: contrastColor\n            }\n        }\n    },\n    candlestick: {\n        itemStyle: {\n            normal: {\n                color: '#FD1050',\n                color0: '#0CF49B',\n                borderColor: '#FD1050',\n                borderColor0: '#0CF49B'\n            }\n        }\n    }\n};\ntheme.categoryAxis.splitLine.show = false;\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * This module is imported by echarts directly.\n *\n * Notice:\n * Always keep this file exists for backward compatibility.\n * Because before 4.1.0, dataset is an optional component,\n * some users may import this module manually.\n */\n\nComponentModel.extend({\n\n    type: 'dataset',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n\n        // 'row', 'column'\n        seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN,\n\n        // null/'auto': auto detect header, see \"module:echarts/data/helper/sourceHelper\"\n        sourceHeader: null,\n\n        dimensions: null,\n\n        source: null\n    },\n\n    optionUpdated: function () {\n        detectSourceFormat(this);\n    }\n\n});\n\nComponent.extend({\n\n    type: 'dataset'\n\n});\n\n/**\n * 椭圆形状\n * @module zrender/graphic/shape/Ellipse\n */\n\nvar Ellipse = Path.extend({\n\n    type: 'ellipse',\n\n    shape: {\n        cx: 0, cy: 0,\n        rx: 0, ry: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var k = 0.5522848;\n        var x = shape.cx;\n        var y = shape.cy;\n        var a = shape.rx;\n        var b = shape.ry;\n        var ox = a * k; // 水平控制点偏移量\n        var oy = b * k; // 垂直控制点偏移量\n        // 从椭圆的左端点开始顺时针绘制四条三次贝塞尔曲线\n        ctx.moveTo(x - a, y);\n        ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b);\n        ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y);\n        ctx.bezierCurveTo(x + a, y + oy, x + ox, y + b, x, y + b);\n        ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y);\n        ctx.closePath();\n    }\n});\n\n// import RadialGradient from '../graphic/RadialGradient';\n// import Pattern from '../graphic/Pattern';\n// import * as vector from '../core/vector';\n// Most of the values can be separated by comma and/or white space.\nvar DILIMITER_REG = /[\\s,]+/;\n\n/**\n * For big svg string, this method might be time consuming.\n *\n * @param {string} svg xml string\n * @return {Object} xml root.\n */\nfunction parseXML(svg) {\n    if (isString(svg)) {\n        var parser = new DOMParser();\n        svg = parser.parseFromString(svg, 'text/xml');\n    }\n\n    // Document node. If using $.get, doc node may be input.\n    if (svg.nodeType === 9) {\n        svg = svg.firstChild;\n    }\n    // nodeName of <!DOCTYPE svg> is also 'svg'.\n    while (svg.nodeName.toLowerCase() !== 'svg' || svg.nodeType !== 1) {\n        svg = svg.nextSibling;\n    }\n\n    return svg;\n}\n\nfunction SVGParser() {\n    this._defs = {};\n    this._root = null;\n\n    this._isDefine = false;\n    this._isText = false;\n}\n\nSVGParser.prototype.parse = function (xml, opt) {\n    opt = opt || {};\n\n    var svg = parseXML(xml);\n\n    if (!svg) {\n        throw new Error('Illegal svg');\n    }\n\n    var root = new Group();\n    this._root = root;\n    // parse view port\n    var viewBox = svg.getAttribute('viewBox') || '';\n\n    // If width/height not specified, means \"100%\" of `opt.width/height`.\n    // TODO: Other percent value not supported yet.\n    var width = parseFloat(svg.getAttribute('width') || opt.width);\n    var height = parseFloat(svg.getAttribute('height') || opt.height);\n    // If width/height not specified, set as null for output.\n    isNaN(width) && (width = null);\n    isNaN(height) && (height = null);\n\n    // Apply inline style on svg element.\n    parseAttributes(svg, root, null, true);\n\n    var child = svg.firstChild;\n    while (child) {\n        this._parseNode(child, root);\n        child = child.nextSibling;\n    }\n\n    var viewBoxRect;\n    var viewBoxTransform;\n\n    if (viewBox) {\n        var viewBoxArr = trim(viewBox).split(DILIMITER_REG);\n        // Some invalid case like viewBox: 'none'.\n        if (viewBoxArr.length >= 4) {\n            viewBoxRect = {\n                x: parseFloat(viewBoxArr[0] || 0),\n                y: parseFloat(viewBoxArr[1] || 0),\n                width: parseFloat(viewBoxArr[2]),\n                height: parseFloat(viewBoxArr[3])\n            };\n        }\n    }\n\n    if (viewBoxRect && width != null && height != null) {\n        viewBoxTransform = makeViewBoxTransform(viewBoxRect, width, height);\n\n        if (!opt.ignoreViewBox) {\n            // If set transform on the output group, it probably bring trouble when\n            // some users only intend to show the clipped content inside the viewBox,\n            // but not intend to transform the output group. So we keep the output\n            // group no transform. If the user intend to use the viewBox as a\n            // camera, just set `opt.ignoreViewBox` as `true` and set transfrom\n            // manually according to the viewBox info in the output of this method.\n            var elRoot = root;\n            root = new Group();\n            root.add(elRoot);\n            elRoot.scale = viewBoxTransform.scale.slice();\n            elRoot.position = viewBoxTransform.position.slice();\n        }\n    }\n\n    // Some shapes might be overflow the viewport, which should be\n    // clipped despite whether the viewBox is used, as the SVG does.\n    if (!opt.ignoreRootClip && width != null && height != null) {\n        root.setClipPath(new Rect({\n            shape: {x: 0, y: 0, width: width, height: height}\n        }));\n    }\n\n    // Set width/height on group just for output the viewport size.\n    return {\n        root: root,\n        width: width,\n        height: height,\n        viewBoxRect: viewBoxRect,\n        viewBoxTransform: viewBoxTransform\n    };\n};\n\nSVGParser.prototype._parseNode = function (xmlNode, parentGroup) {\n\n    var nodeName = xmlNode.nodeName.toLowerCase();\n\n    // TODO\n    // support <style>...</style> in svg, where nodeName is 'style',\n    // CSS classes is defined globally wherever the style tags are declared.\n\n    if (nodeName === 'defs') {\n        // define flag\n        this._isDefine = true;\n    }\n    else if (nodeName === 'text') {\n        this._isText = true;\n    }\n\n    var el;\n    if (this._isDefine) {\n        var parser = defineParsers[nodeName];\n        if (parser) {\n            var def = parser.call(this, xmlNode);\n            var id = xmlNode.getAttribute('id');\n            if (id) {\n                this._defs[id] = def;\n            }\n        }\n    }\n    else {\n        var parser = nodeParsers[nodeName];\n        if (parser) {\n            el = parser.call(this, xmlNode, parentGroup);\n            parentGroup.add(el);\n        }\n    }\n\n    var child = xmlNode.firstChild;\n    while (child) {\n        if (child.nodeType === 1) {\n            this._parseNode(child, el);\n        }\n        // Is text\n        if (child.nodeType === 3 && this._isText) {\n            this._parseText(child, el);\n        }\n        child = child.nextSibling;\n    }\n\n    // Quit define\n    if (nodeName === 'defs') {\n        this._isDefine = false;\n    }\n    else if (nodeName === 'text') {\n        this._isText = false;\n    }\n};\n\nSVGParser.prototype._parseText = function (xmlNode, parentGroup) {\n    if (xmlNode.nodeType === 1) {\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n        this._textX += parseFloat(dx);\n        this._textY += parseFloat(dy);\n    }\n\n    var text = new Text({\n        style: {\n            text: xmlNode.textContent,\n            transformText: true\n        },\n        position: [this._textX || 0, this._textY || 0]\n    });\n\n    inheritStyle(parentGroup, text);\n    parseAttributes(xmlNode, text, this._defs);\n\n    var fontSize = text.style.fontSize;\n    if (fontSize && fontSize < 9) {\n        // PENDING\n        text.style.fontSize = 9;\n        text.scale = text.scale || [1, 1];\n        text.scale[0] *= fontSize / 9;\n        text.scale[1] *= fontSize / 9;\n    }\n\n    var rect = text.getBoundingRect();\n    this._textX += rect.width;\n\n    parentGroup.add(text);\n\n    return text;\n};\n\nvar nodeParsers = {\n    'g': function (xmlNode, parentGroup) {\n        var g = new Group();\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n        return g;\n    },\n    'rect': function (xmlNode, parentGroup) {\n        var rect = new Rect();\n        inheritStyle(parentGroup, rect);\n        parseAttributes(xmlNode, rect, this._defs);\n\n        rect.setShape({\n            x: parseFloat(xmlNode.getAttribute('x') || 0),\n            y: parseFloat(xmlNode.getAttribute('y') || 0),\n            width: parseFloat(xmlNode.getAttribute('width') || 0),\n            height: parseFloat(xmlNode.getAttribute('height') || 0)\n        });\n\n        // console.log(xmlNode.getAttribute('transform'));\n        // console.log(rect.transform);\n\n        return rect;\n    },\n    'circle': function (xmlNode, parentGroup) {\n        var circle = new Circle();\n        inheritStyle(parentGroup, circle);\n        parseAttributes(xmlNode, circle, this._defs);\n\n        circle.setShape({\n            cx: parseFloat(xmlNode.getAttribute('cx') || 0),\n            cy: parseFloat(xmlNode.getAttribute('cy') || 0),\n            r: parseFloat(xmlNode.getAttribute('r') || 0)\n        });\n\n        return circle;\n    },\n    'line': function (xmlNode, parentGroup) {\n        var line = new Line();\n        inheritStyle(parentGroup, line);\n        parseAttributes(xmlNode, line, this._defs);\n\n        line.setShape({\n            x1: parseFloat(xmlNode.getAttribute('x1') || 0),\n            y1: parseFloat(xmlNode.getAttribute('y1') || 0),\n            x2: parseFloat(xmlNode.getAttribute('x2') || 0),\n            y2: parseFloat(xmlNode.getAttribute('y2') || 0)\n        });\n\n        return line;\n    },\n    'ellipse': function (xmlNode, parentGroup) {\n        var ellipse = new Ellipse();\n        inheritStyle(parentGroup, ellipse);\n        parseAttributes(xmlNode, ellipse, this._defs);\n\n        ellipse.setShape({\n            cx: parseFloat(xmlNode.getAttribute('cx') || 0),\n            cy: parseFloat(xmlNode.getAttribute('cy') || 0),\n            rx: parseFloat(xmlNode.getAttribute('rx') || 0),\n            ry: parseFloat(xmlNode.getAttribute('ry') || 0)\n        });\n        return ellipse;\n    },\n    'polygon': function (xmlNode, parentGroup) {\n        var points = xmlNode.getAttribute('points');\n        if (points) {\n            points = parsePoints(points);\n        }\n        var polygon = new Polygon({\n            shape: {\n                points: points || []\n            }\n        });\n\n        inheritStyle(parentGroup, polygon);\n        parseAttributes(xmlNode, polygon, this._defs);\n\n        return polygon;\n    },\n    'polyline': function (xmlNode, parentGroup) {\n        var path = new Path();\n        inheritStyle(parentGroup, path);\n        parseAttributes(xmlNode, path, this._defs);\n\n        var points = xmlNode.getAttribute('points');\n        if (points) {\n            points = parsePoints(points);\n        }\n        var polyline = new Polyline({\n            shape: {\n                points: points || []\n            }\n        });\n\n        return polyline;\n    },\n    'image': function (xmlNode, parentGroup) {\n        var img = new ZImage();\n        inheritStyle(parentGroup, img);\n        parseAttributes(xmlNode, img, this._defs);\n\n        img.setStyle({\n            image: xmlNode.getAttribute('xlink:href'),\n            x: xmlNode.getAttribute('x'),\n            y: xmlNode.getAttribute('y'),\n            width: xmlNode.getAttribute('width'),\n            height: xmlNode.getAttribute('height')\n        });\n\n        return img;\n    },\n    'text': function (xmlNode, parentGroup) {\n        var x = xmlNode.getAttribute('x') || 0;\n        var y = xmlNode.getAttribute('y') || 0;\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n\n        this._textX = parseFloat(x) + parseFloat(dx);\n        this._textY = parseFloat(y) + parseFloat(dy);\n\n        var g = new Group();\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n        return g;\n    },\n    'tspan': function (xmlNode, parentGroup) {\n        var x = xmlNode.getAttribute('x');\n        var y = xmlNode.getAttribute('y');\n        if (x != null) {\n            // new offset x\n            this._textX = parseFloat(x);\n        }\n        if (y != null) {\n            // new offset y\n            this._textY = parseFloat(y);\n        }\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n\n        var g = new Group();\n\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n\n        this._textX += dx;\n        this._textY += dy;\n\n        return g;\n    },\n    'path': function (xmlNode, parentGroup) {\n        // TODO svg fill rule\n        // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule\n        // path.style.globalCompositeOperation = 'xor';\n        var d = xmlNode.getAttribute('d') || '';\n\n        // Performance sensitive.\n\n        var path = createFromString(d);\n\n        inheritStyle(parentGroup, path);\n        parseAttributes(xmlNode, path, this._defs);\n\n        return path;\n    }\n};\n\nvar defineParsers = {\n\n    'lineargradient': function (xmlNode) {\n        var x1 = parseInt(xmlNode.getAttribute('x1') || 0, 10);\n        var y1 = parseInt(xmlNode.getAttribute('y1') || 0, 10);\n        var x2 = parseInt(xmlNode.getAttribute('x2') || 10, 10);\n        var y2 = parseInt(xmlNode.getAttribute('y2') || 0, 10);\n\n        var gradient = new LinearGradient(x1, y1, x2, y2);\n\n        _parseGradientColorStops(xmlNode, gradient);\n\n        return gradient;\n    },\n\n    'radialgradient': function (xmlNode) {\n\n    }\n};\n\nfunction _parseGradientColorStops(xmlNode, gradient) {\n\n    var stop = xmlNode.firstChild;\n\n    while (stop) {\n        if (stop.nodeType === 1) {\n            var offset = stop.getAttribute('offset');\n            if (offset.indexOf('%') > 0) {  // percentage\n                offset = parseInt(offset, 10) / 100;\n            }\n            else if (offset) {    // number from 0 to 1\n                offset = parseFloat(offset);\n            }\n            else {\n                offset = 0;\n            }\n\n            var stopColor = stop.getAttribute('stop-color') || '#000000';\n\n            gradient.addColorStop(offset, stopColor);\n        }\n        stop = stop.nextSibling;\n    }\n}\n\nfunction inheritStyle(parent, child) {\n    if (parent && parent.__inheritedStyle) {\n        if (!child.__inheritedStyle) {\n            child.__inheritedStyle = {};\n        }\n        defaults(child.__inheritedStyle, parent.__inheritedStyle);\n    }\n}\n\nfunction parsePoints(pointsString) {\n    var list = trim(pointsString).split(DILIMITER_REG);\n    var points = [];\n\n    for (var i = 0; i < list.length; i += 2) {\n        var x = parseFloat(list[i]);\n        var y = parseFloat(list[i + 1]);\n        points.push([x, y]);\n    }\n    return points;\n}\n\nvar attributesMap = {\n    'fill': 'fill',\n    'stroke': 'stroke',\n    'stroke-width': 'lineWidth',\n    'opacity': 'opacity',\n    'fill-opacity': 'fillOpacity',\n    'stroke-opacity': 'strokeOpacity',\n    'stroke-dasharray': 'lineDash',\n    'stroke-dashoffset': 'lineDashOffset',\n    'stroke-linecap': 'lineCap',\n    'stroke-linejoin': 'lineJoin',\n    'stroke-miterlimit': 'miterLimit',\n    'font-family': 'fontFamily',\n    'font-size': 'fontSize',\n    'font-style': 'fontStyle',\n    'font-weight': 'fontWeight',\n\n    'text-align': 'textAlign',\n    'alignment-baseline': 'textBaseline'\n};\n\nfunction parseAttributes(xmlNode, el, defs, onlyInlineStyle) {\n    var zrStyle = el.__inheritedStyle || {};\n    var isTextEl = el.type === 'text';\n\n    // TODO Shadow\n    if (xmlNode.nodeType === 1) {\n        parseTransformAttribute(xmlNode, el);\n\n        extend(zrStyle, parseStyleAttribute(xmlNode));\n\n        if (!onlyInlineStyle) {\n            for (var svgAttrName in attributesMap) {\n                if (attributesMap.hasOwnProperty(svgAttrName)) {\n                    var attrValue = xmlNode.getAttribute(svgAttrName);\n                    if (attrValue != null) {\n                        zrStyle[attributesMap[svgAttrName]] = attrValue;\n                    }\n                }\n            }\n        }\n    }\n\n    var elFillProp = isTextEl ? 'textFill' : 'fill';\n    var elStrokeProp = isTextEl ? 'textStroke' : 'stroke';\n\n    el.style = el.style || new Style();\n    var elStyle = el.style;\n\n    zrStyle.fill != null && elStyle.set(elFillProp, getPaint(zrStyle.fill, defs));\n    zrStyle.stroke != null && elStyle.set(elStrokeProp, getPaint(zrStyle.stroke, defs));\n\n    each$1([\n        'lineWidth', 'opacity', 'fillOpacity', 'strokeOpacity', 'miterLimit', 'fontSize'\n    ], function (propName) {\n        var elPropName = (propName === 'lineWidth' && isTextEl) ? 'textStrokeWidth' : propName;\n        zrStyle[propName] != null && elStyle.set(elPropName, parseFloat(zrStyle[propName]));\n    });\n\n    if (!zrStyle.textBaseline || zrStyle.textBaseline === 'auto') {\n        zrStyle.textBaseline = 'alphabetic';\n    }\n    if (zrStyle.textBaseline === 'alphabetic') {\n        zrStyle.textBaseline = 'bottom';\n    }\n    if (zrStyle.textAlign === 'start') {\n        zrStyle.textAlign = 'left';\n    }\n    if (zrStyle.textAlign === 'end') {\n        zrStyle.textAlign = 'right';\n    }\n\n    each$1(['lineDashOffset', 'lineCap', 'lineJoin',\n        'fontWeight', 'fontFamily', 'fontStyle', 'textAlign', 'textBaseline'\n    ], function (propName) {\n        zrStyle[propName] != null && elStyle.set(propName, zrStyle[propName]);\n    });\n\n    if (zrStyle.lineDash) {\n        el.style.lineDash = trim(zrStyle.lineDash).split(DILIMITER_REG);\n    }\n\n    if (elStyle[elStrokeProp] && elStyle[elStrokeProp] !== 'none') {\n        // enable stroke\n        el[elStrokeProp] = true;\n    }\n\n    el.__inheritedStyle = zrStyle;\n}\n\n\nvar urlRegex = /url\\(\\s*#(.*?)\\)/;\nfunction getPaint(str, defs) {\n    // if (str === 'none') {\n    //     return;\n    // }\n    var urlMatch = defs && str && str.match(urlRegex);\n    if (urlMatch) {\n        var url = trim(urlMatch[1]);\n        var def = defs[url];\n        return def;\n    }\n    return str;\n}\n\nvar transformRegex = /(translate|scale|rotate|skewX|skewY|matrix)\\(([\\-\\s0-9\\.e,]*)\\)/g;\n\nfunction parseTransformAttribute(xmlNode, node) {\n    var transform = xmlNode.getAttribute('transform');\n    if (transform) {\n        transform = transform.replace(/,/g, ' ');\n        var m = null;\n        var transformOps = [];\n        transform.replace(transformRegex, function (str, type, value) {\n            transformOps.push(type, value);\n        });\n        for (var i = transformOps.length - 1; i > 0; i -= 2) {\n            var value = transformOps[i];\n            var type = transformOps[i - 1];\n            m = m || create$1();\n            switch (type) {\n                case 'translate':\n                    value = trim(value).split(DILIMITER_REG);\n                    translate(m, m, [parseFloat(value[0]), parseFloat(value[1] || 0)]);\n                    break;\n                case 'scale':\n                    value = trim(value).split(DILIMITER_REG);\n                    scale$1(m, m, [parseFloat(value[0]), parseFloat(value[1] || value[0])]);\n                    break;\n                case 'rotate':\n                    value = trim(value).split(DILIMITER_REG);\n                    rotate(m, m, parseFloat(value[0]));\n                    break;\n                case 'skew':\n                    value = trim(value).split(DILIMITER_REG);\n                    console.warn('Skew transform is not supported yet');\n                    break;\n                case 'matrix':\n                    var value = trim(value).split(DILIMITER_REG);\n                    m[0] = parseFloat(value[0]);\n                    m[1] = parseFloat(value[1]);\n                    m[2] = parseFloat(value[2]);\n                    m[3] = parseFloat(value[3]);\n                    m[4] = parseFloat(value[4]);\n                    m[5] = parseFloat(value[5]);\n                    break;\n            }\n        }\n        node.setLocalTransform(m);\n    }\n}\n\n// Value may contain space.\nvar styleRegex = /([^\\s:;]+)\\s*:\\s*([^:;]+)/g;\nfunction parseStyleAttribute(xmlNode) {\n    var style = xmlNode.getAttribute('style');\n    var result = {};\n\n    if (!style) {\n        return result;\n    }\n\n    var styleList = {};\n    styleRegex.lastIndex = 0;\n    var styleRegResult;\n    while ((styleRegResult = styleRegex.exec(style)) != null) {\n        styleList[styleRegResult[1]] = styleRegResult[2];\n    }\n\n    for (var svgAttrName in attributesMap) {\n        if (attributesMap.hasOwnProperty(svgAttrName) && styleList[svgAttrName] != null) {\n            result[attributesMap[svgAttrName]] = styleList[svgAttrName];\n        }\n    }\n\n    return result;\n}\n\n/**\n * @param {Array.<number>} viewBoxRect\n * @param {number} width\n * @param {number} height\n * @return {Object} {scale, position}\n */\nfunction makeViewBoxTransform(viewBoxRect, width, height) {\n    var scaleX = width / viewBoxRect.width;\n    var scaleY = height / viewBoxRect.height;\n    var scale = Math.min(scaleX, scaleY);\n    // preserveAspectRatio 'xMidYMid'\n    var viewBoxScale = [scale, scale];\n    var viewBoxPosition = [\n        -(viewBoxRect.x + viewBoxRect.width / 2) * scale + width / 2,\n        -(viewBoxRect.y + viewBoxRect.height / 2) * scale + height / 2\n    ];\n\n    return {\n        scale: viewBoxScale,\n        position: viewBoxPosition\n    };\n}\n\n/**\n * @param {string|XMLElement} xml\n * @param {Object} [opt]\n * @param {number} [opt.width] Default width if svg width not specified or is a percent value.\n * @param {number} [opt.height] Default height if svg height not specified or is a percent value.\n * @param {boolean} [opt.ignoreViewBox]\n * @param {boolean} [opt.ignoreRootClip]\n * @return {Object} result:\n * {\n *     root: Group, The root of the the result tree of zrender shapes,\n *     width: number, the viewport width of the SVG,\n *     height: number, the viewport height of the SVG,\n *     viewBoxRect: {x, y, width, height}, the declared viewBox rect of the SVG, if exists,\n *     viewBoxTransform: the {scale, position} calculated by viewBox and viewport, is exists.\n * }\n */\nfunction parseSVG(xml, opt) {\n    var parser = new SVGParser();\n    return parser.parse(xml, opt);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar storage = createHashMap();\n\n// For minimize the code size of common echarts package,\n// do not put too much logic in this module.\n\nvar mapDataStorage = {\n\n    // The format of record: see `echarts.registerMap`.\n    // Compatible with previous `echarts.registerMap`.\n    registerMap: function (mapName, rawGeoJson, rawSpecialAreas) {\n\n        var records;\n\n        if (isArray(rawGeoJson)) {\n            records = rawGeoJson;\n        }\n        else if (rawGeoJson.svg) {\n            records = [{\n                type: 'svg',\n                source: rawGeoJson.svg,\n                specialAreas: rawGeoJson.specialAreas\n            }];\n        }\n        else {\n            // Backward compatibility.\n            if (rawGeoJson.geoJson && !rawGeoJson.features) {\n                rawSpecialAreas = rawGeoJson.specialAreas;\n                rawGeoJson = rawGeoJson.geoJson;\n            }\n            records = [{\n                type: 'geoJSON',\n                source: rawGeoJson,\n                specialAreas: rawSpecialAreas\n            }];\n        }\n\n        each$1(records, function (record) {\n            var type = record.type;\n            type === 'geoJson' && (type = record.type = 'geoJSON');\n\n            var parse = parsers[type];\n\n            if (__DEV__) {\n                assert$1(parse, 'Illegal map type: ' + type);\n            }\n\n            parse(record);\n        });\n\n        return storage.set(mapName, records);\n    },\n\n    retrieveMap: function (mapName) {\n        return storage.get(mapName);\n    }\n\n};\n\nvar parsers = {\n\n    geoJSON: function (record) {\n        var source = record.source;\n        record.geoJSON = !isString(source)\n            ? source\n            : (typeof JSON !== 'undefined' && JSON.parse)\n            ? JSON.parse(source)\n            : (new Function('return (' + source + ');'))();\n    },\n\n    // Only perform parse to XML object here, which might be time\n    // consiming for large SVG.\n    // Although convert XML to zrender element is also time consiming,\n    // if we do it here, the clone of zrender elements has to be\n    // required. So we do it once for each geo instance, util real\n    // performance issues call for optimizing it.\n    svg: function (record) {\n        record.svgXML = parseXML(record.source);\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\nvar assert = assert$1;\nvar each = each$1;\nvar isFunction = isFunction$1;\nvar isObject = isObject$1;\nvar parseClassType = ComponentModel.parseClassType;\n\nvar version = '4.2.1';\n\nvar dependencies = {\n    zrender: '4.0.6'\n};\n\nvar TEST_FRAME_REMAIN_TIME = 1;\n\nvar PRIORITY_PROCESSOR_FILTER = 1000;\nvar PRIORITY_PROCESSOR_STATISTIC = 5000;\n\nvar PRIORITY_VISUAL_LAYOUT = 1000;\nvar PRIORITY_VISUAL_GLOBAL = 2000;\nvar PRIORITY_VISUAL_CHART = 3000;\nvar PRIORITY_VISUAL_COMPONENT = 4000;\n// FIXME\n// necessary?\nvar PRIORITY_VISUAL_BRUSH = 5000;\n\nvar PRIORITY = {\n    PROCESSOR: {\n        FILTER: PRIORITY_PROCESSOR_FILTER,\n        STATISTIC: PRIORITY_PROCESSOR_STATISTIC\n    },\n    VISUAL: {\n        LAYOUT: PRIORITY_VISUAL_LAYOUT,\n        GLOBAL: PRIORITY_VISUAL_GLOBAL,\n        CHART: PRIORITY_VISUAL_CHART,\n        COMPONENT: PRIORITY_VISUAL_COMPONENT,\n        BRUSH: PRIORITY_VISUAL_BRUSH\n    }\n};\n\n// Main process have three entries: `setOption`, `dispatchAction` and `resize`,\n// where they must not be invoked nestedly, except the only case: invoke\n// dispatchAction with updateMethod \"none\" in main process.\n// This flag is used to carry out this rule.\n// All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]).\nvar IN_MAIN_PROCESS = '__flagInMainProcess';\nvar OPTION_UPDATED = '__optionUpdated';\nvar ACTION_REG = /^[a-zA-Z0-9_]+$/;\n\n\nfunction createRegisterEventWithLowercaseName(method) {\n    return function (eventName, handler, context) {\n        // Event name is all lowercase\n        eventName = eventName && eventName.toLowerCase();\n        Eventful.prototype[method].call(this, eventName, handler, context);\n    };\n}\n\n/**\n * @module echarts~MessageCenter\n */\nfunction MessageCenter() {\n    Eventful.call(this);\n}\nMessageCenter.prototype.on = createRegisterEventWithLowercaseName('on');\nMessageCenter.prototype.off = createRegisterEventWithLowercaseName('off');\nMessageCenter.prototype.one = createRegisterEventWithLowercaseName('one');\nmixin(MessageCenter, Eventful);\n\n/**\n * @module echarts~ECharts\n */\nfunction ECharts(dom, theme$$1, opts) {\n    opts = opts || {};\n\n    // Get theme by name\n    if (typeof theme$$1 === 'string') {\n        theme$$1 = themeStorage[theme$$1];\n    }\n\n    /**\n     * @type {string}\n     */\n    this.id;\n\n    /**\n     * Group id\n     * @type {string}\n     */\n    this.group;\n\n    /**\n     * @type {HTMLElement}\n     * @private\n     */\n    this._dom = dom;\n\n    var defaultRenderer = 'canvas';\n    if (__DEV__) {\n        defaultRenderer = (\n            typeof window === 'undefined' ? global : window\n        ).__ECHARTS__DEFAULT__RENDERER__ || defaultRenderer;\n    }\n\n    /**\n     * @type {module:zrender/ZRender}\n     * @private\n     */\n    var zr = this._zr = init$1(dom, {\n        renderer: opts.renderer || defaultRenderer,\n        devicePixelRatio: opts.devicePixelRatio,\n        width: opts.width,\n        height: opts.height\n    });\n\n    /**\n     * Expect 60 pfs.\n     * @type {Function}\n     * @private\n     */\n    this._throttledZrFlush = throttle(bind(zr.flush, zr), 17);\n\n    var theme$$1 = clone(theme$$1);\n    theme$$1 && backwardCompat(theme$$1, true);\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._theme = theme$$1;\n\n    /**\n     * @type {Array.<module:echarts/view/Chart>}\n     * @private\n     */\n    this._chartsViews = [];\n\n    /**\n     * @type {Object.<string, module:echarts/view/Chart>}\n     * @private\n     */\n    this._chartsMap = {};\n\n    /**\n     * @type {Array.<module:echarts/view/Component>}\n     * @private\n     */\n    this._componentsViews = [];\n\n    /**\n     * @type {Object.<string, module:echarts/view/Component>}\n     * @private\n     */\n    this._componentsMap = {};\n\n    /**\n     * @type {module:echarts/CoordinateSystem}\n     * @private\n     */\n    this._coordSysMgr = new CoordinateSystemManager();\n\n    /**\n     * @type {module:echarts/ExtensionAPI}\n     * @private\n     */\n    var api = this._api = createExtensionAPI(this);\n\n    // Sort on demand\n    function prioritySortFunc(a, b) {\n        return a.__prio - b.__prio;\n    }\n    sort(visualFuncs, prioritySortFunc);\n    sort(dataProcessorFuncs, prioritySortFunc);\n\n    /**\n     * @type {module:echarts/stream/Scheduler}\n     */\n    this._scheduler = new Scheduler(this, api, dataProcessorFuncs, visualFuncs);\n\n    Eventful.call(this, this._ecEventProcessor = new EventProcessor());\n\n    /**\n     * @type {module:echarts~MessageCenter}\n     * @private\n     */\n    this._messageCenter = new MessageCenter();\n\n    // Init mouse events\n    this._initEvents();\n\n    // In case some people write `window.onresize = chart.resize`\n    this.resize = bind(this.resize, this);\n\n    // Can't dispatch action during rendering procedure\n    this._pendingActions = [];\n\n    zr.animation.on('frame', this._onframe, this);\n\n    bindRenderedEvent(zr, this);\n\n    // ECharts instance can be used as value.\n    setAsPrimitive(this);\n}\n\nvar echartsProto = ECharts.prototype;\n\nechartsProto._onframe = function () {\n    if (this._disposed) {\n        return;\n    }\n\n    var scheduler = this._scheduler;\n\n    // Lazy update\n    if (this[OPTION_UPDATED]) {\n        var silent = this[OPTION_UPDATED].silent;\n\n        this[IN_MAIN_PROCESS] = true;\n\n        prepare(this);\n        updateMethods.update.call(this);\n\n        this[IN_MAIN_PROCESS] = false;\n\n        this[OPTION_UPDATED] = false;\n\n        flushPendingActions.call(this, silent);\n\n        triggerUpdatedEvent.call(this, silent);\n    }\n    // Avoid do both lazy update and progress in one frame.\n    else if (scheduler.unfinished) {\n        // Stream progress.\n        var remainTime = TEST_FRAME_REMAIN_TIME;\n        var ecModel = this._model;\n        var api = this._api;\n        scheduler.unfinished = false;\n        do {\n            var startTime = +new Date();\n\n            scheduler.performSeriesTasks(ecModel);\n\n            // Currently dataProcessorFuncs do not check threshold.\n            scheduler.performDataProcessorTasks(ecModel);\n\n            updateStreamModes(this, ecModel);\n\n            // Do not update coordinate system here. Because that coord system update in\n            // each frame is not a good user experience. So we follow the rule that\n            // the extent of the coordinate system is determin in the first frame (the\n            // frame is executed immedietely after task reset.\n            // this._coordSysMgr.update(ecModel, api);\n\n            // console.log('--- ec frame visual ---', remainTime);\n            scheduler.performVisualTasks(ecModel);\n\n            renderSeries(this, this._model, api, 'remain');\n\n            remainTime -= (+new Date() - startTime);\n        }\n        while (remainTime > 0 && scheduler.unfinished);\n\n        // Call flush explicitly for trigger finished event.\n        if (!scheduler.unfinished) {\n            this._zr.flush();\n        }\n        // Else, zr flushing be ensue within the same frame,\n        // because zr flushing is after onframe event.\n    }\n};\n\n/**\n * @return {HTMLElement}\n */\nechartsProto.getDom = function () {\n    return this._dom;\n};\n\n/**\n * @return {module:zrender~ZRender}\n */\nechartsProto.getZr = function () {\n    return this._zr;\n};\n\n/**\n * Usage:\n * chart.setOption(option, notMerge, lazyUpdate);\n * chart.setOption(option, {\n *     notMerge: ...,\n *     lazyUpdate: ...,\n *     silent: ...\n * });\n *\n * @param {Object} option\n * @param {Object|boolean} [opts] opts or notMerge.\n * @param {boolean} [opts.notMerge=false]\n * @param {boolean} [opts.lazyUpdate=false] Useful when setOption frequently.\n */\nechartsProto.setOption = function (option, notMerge, lazyUpdate) {\n    if (__DEV__) {\n        assert(!this[IN_MAIN_PROCESS], '`setOption` should not be called during main process.');\n    }\n\n    var silent;\n    if (isObject(notMerge)) {\n        lazyUpdate = notMerge.lazyUpdate;\n        silent = notMerge.silent;\n        notMerge = notMerge.notMerge;\n    }\n\n    this[IN_MAIN_PROCESS] = true;\n\n    if (!this._model || notMerge) {\n        var optionManager = new OptionManager(this._api);\n        var theme$$1 = this._theme;\n        var ecModel = this._model = new GlobalModel(null, null, theme$$1, optionManager);\n        ecModel.scheduler = this._scheduler;\n        ecModel.init(null, null, theme$$1, optionManager);\n    }\n\n    this._model.setOption(option, optionPreprocessorFuncs);\n\n    if (lazyUpdate) {\n        this[OPTION_UPDATED] = {silent: silent};\n        this[IN_MAIN_PROCESS] = false;\n    }\n    else {\n        prepare(this);\n\n        updateMethods.update.call(this);\n\n        // Ensure zr refresh sychronously, and then pixel in canvas can be\n        // fetched after `setOption`.\n        this._zr.flush();\n\n        this[OPTION_UPDATED] = false;\n        this[IN_MAIN_PROCESS] = false;\n\n        flushPendingActions.call(this, silent);\n        triggerUpdatedEvent.call(this, silent);\n    }\n};\n\n/**\n * @DEPRECATED\n */\nechartsProto.setTheme = function () {\n    console.error('ECharts#setTheme() is DEPRECATED in ECharts 3.0');\n};\n\n/**\n * @return {module:echarts/model/Global}\n */\nechartsProto.getModel = function () {\n    return this._model;\n};\n\n/**\n * @return {Object}\n */\nechartsProto.getOption = function () {\n    return this._model && this._model.getOption();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getWidth = function () {\n    return this._zr.getWidth();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getHeight = function () {\n    return this._zr.getHeight();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getDevicePixelRatio = function () {\n    return this._zr.painter.dpr || window.devicePixelRatio || 1;\n};\n\n/**\n * Get canvas which has all thing rendered\n * @param {Object} opts\n * @param {string} [opts.backgroundColor]\n * @return {string}\n */\nechartsProto.getRenderedCanvas = function (opts) {\n    if (!env$1.canvasSupported) {\n        return;\n    }\n    opts = opts || {};\n    opts.pixelRatio = opts.pixelRatio || 1;\n    opts.backgroundColor = opts.backgroundColor\n        || this._model.get('backgroundColor');\n    var zr = this._zr;\n    // var list = zr.storage.getDisplayList();\n    // Stop animations\n    // Never works before in init animation, so remove it.\n    // zrUtil.each(list, function (el) {\n    //     el.stopAnimation(true);\n    // });\n    return zr.painter.getRenderedCanvas(opts);\n};\n\n/**\n * Get svg data url\n * @return {string}\n */\nechartsProto.getSvgDataUrl = function () {\n    if (!env$1.svgSupported) {\n        return;\n    }\n\n    var zr = this._zr;\n    var list = zr.storage.getDisplayList();\n    // Stop animations\n    each$1(list, function (el) {\n        el.stopAnimation(true);\n    });\n\n    return zr.painter.pathToDataUrl();\n};\n\n/**\n * @return {string}\n * @param {Object} opts\n * @param {string} [opts.type='png']\n * @param {string} [opts.pixelRatio=1]\n * @param {string} [opts.backgroundColor]\n * @param {string} [opts.excludeComponents]\n */\nechartsProto.getDataURL = function (opts) {\n    opts = opts || {};\n    var excludeComponents = opts.excludeComponents;\n    var ecModel = this._model;\n    var excludesComponentViews = [];\n    var self = this;\n\n    each(excludeComponents, function (componentType) {\n        ecModel.eachComponent({\n            mainType: componentType\n        }, function (component) {\n            var view = self._componentsMap[component.__viewId];\n            if (!view.group.ignore) {\n                excludesComponentViews.push(view);\n                view.group.ignore = true;\n            }\n        });\n    });\n\n    var url = this._zr.painter.getType() === 'svg'\n        ? this.getSvgDataUrl()\n        : this.getRenderedCanvas(opts).toDataURL(\n            'image/' + (opts && opts.type || 'png')\n        );\n\n    each(excludesComponentViews, function (view) {\n        view.group.ignore = false;\n    });\n\n    return url;\n};\n\n\n/**\n * @return {string}\n * @param {Object} opts\n * @param {string} [opts.type='png']\n * @param {string} [opts.pixelRatio=1]\n * @param {string} [opts.backgroundColor]\n */\nechartsProto.getConnectedDataURL = function (opts) {\n    if (!env$1.canvasSupported) {\n        return;\n    }\n    var groupId = this.group;\n    var mathMin = Math.min;\n    var mathMax = Math.max;\n    var MAX_NUMBER = Infinity;\n    if (connectedGroups[groupId]) {\n        var left = MAX_NUMBER;\n        var top = MAX_NUMBER;\n        var right = -MAX_NUMBER;\n        var bottom = -MAX_NUMBER;\n        var canvasList = [];\n        var dpr = (opts && opts.pixelRatio) || 1;\n\n        each$1(instances, function (chart, id) {\n            if (chart.group === groupId) {\n                var canvas = chart.getRenderedCanvas(\n                    clone(opts)\n                );\n                var boundingRect = chart.getDom().getBoundingClientRect();\n                left = mathMin(boundingRect.left, left);\n                top = mathMin(boundingRect.top, top);\n                right = mathMax(boundingRect.right, right);\n                bottom = mathMax(boundingRect.bottom, bottom);\n                canvasList.push({\n                    dom: canvas,\n                    left: boundingRect.left,\n                    top: boundingRect.top\n                });\n            }\n        });\n\n        left *= dpr;\n        top *= dpr;\n        right *= dpr;\n        bottom *= dpr;\n        var width = right - left;\n        var height = bottom - top;\n        var targetCanvas = createCanvas();\n        targetCanvas.width = width;\n        targetCanvas.height = height;\n        var zr = init$1(targetCanvas);\n\n        each(canvasList, function (item) {\n            var img = new ZImage({\n                style: {\n                    x: item.left * dpr - left,\n                    y: item.top * dpr - top,\n                    image: item.dom\n                }\n            });\n            zr.add(img);\n        });\n        zr.refreshImmediately();\n\n        return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png'));\n    }\n    else {\n        return this.getDataURL(opts);\n    }\n};\n\n/**\n * Convert from logical coordinate system to pixel coordinate system.\n * See CoordinateSystem#convertToPixel.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId, geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName,\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {Array|number} result\n */\nechartsProto.convertToPixel = curry(doConvertPixel, 'convertToPixel');\n\n/**\n * Convert from pixel coordinate system to logical coordinate system.\n * See CoordinateSystem#convertFromPixel.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId / geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {Array|number} result\n */\nechartsProto.convertFromPixel = curry(doConvertPixel, 'convertFromPixel');\n\nfunction doConvertPixel(methodName, finder, value) {\n    var ecModel = this._model;\n    var coordSysList = this._coordSysMgr.getCoordinateSystems();\n    var result;\n\n    finder = parseFinder(ecModel, finder);\n\n    for (var i = 0; i < coordSysList.length; i++) {\n        var coordSys = coordSysList[i];\n        if (coordSys[methodName]\n            && (result = coordSys[methodName](ecModel, finder, value)) != null\n        ) {\n            return result;\n        }\n    }\n\n    if (__DEV__) {\n        console.warn(\n            'No coordinate system that supports ' + methodName + ' found by the given finder.'\n        );\n    }\n}\n\n/**\n * Is the specified coordinate systems or components contain the given pixel point.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId / geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName,\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {boolean} result\n */\nechartsProto.containPixel = function (finder, value) {\n    var ecModel = this._model;\n    var result;\n\n    finder = parseFinder(ecModel, finder);\n\n    each$1(finder, function (models, key) {\n        key.indexOf('Models') >= 0 && each$1(models, function (model) {\n            var coordSys = model.coordinateSystem;\n            if (coordSys && coordSys.containPoint) {\n                result |= !!coordSys.containPoint(value);\n            }\n            else if (key === 'seriesModels') {\n                var view = this._chartsMap[model.__viewId];\n                if (view && view.containPoint) {\n                    result |= view.containPoint(value, model);\n                }\n                else {\n                    if (__DEV__) {\n                        console.warn(key + ': ' + (view\n                            ? 'The found component do not support containPoint.'\n                            : 'No view mapping to the found component.'\n                        ));\n                    }\n                }\n            }\n            else {\n                if (__DEV__) {\n                    console.warn(key + ': containPoint is not supported');\n                }\n            }\n        }, this);\n    }, this);\n\n    return !!result;\n};\n\n/**\n * Get visual from series or data.\n * @param {string|Object} finder\n *        If string, e.g., 'series', means {seriesIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            dataIndex / dataIndexInside\n *        }\n *        If dataIndex is not specified, series visual will be fetched,\n *        but not data item visual.\n *        If all of seriesIndex, seriesId, seriesName are not specified,\n *        visual will be fetched from first series.\n * @param {string} visualType 'color', 'symbol', 'symbolSize'\n */\nechartsProto.getVisual = function (finder, visualType) {\n    var ecModel = this._model;\n\n    finder = parseFinder(ecModel, finder, {defaultMainType: 'series'});\n\n    var seriesModel = finder.seriesModel;\n\n    if (__DEV__) {\n        if (!seriesModel) {\n            console.warn('There is no specified seires model');\n        }\n    }\n\n    var data = seriesModel.getData();\n\n    var dataIndexInside = finder.hasOwnProperty('dataIndexInside')\n        ? finder.dataIndexInside\n        : finder.hasOwnProperty('dataIndex')\n        ? data.indexOfRawIndex(finder.dataIndex)\n        : null;\n\n    return dataIndexInside != null\n        ? data.getItemVisual(dataIndexInside, visualType)\n        : data.getVisual(visualType);\n};\n\n/**\n * Get view of corresponding component model\n * @param  {module:echarts/model/Component} componentModel\n * @return {module:echarts/view/Component}\n */\nechartsProto.getViewOfComponentModel = function (componentModel) {\n    return this._componentsMap[componentModel.__viewId];\n};\n\n/**\n * Get view of corresponding series model\n * @param  {module:echarts/model/Series} seriesModel\n * @return {module:echarts/view/Chart}\n */\nechartsProto.getViewOfSeriesModel = function (seriesModel) {\n    return this._chartsMap[seriesModel.__viewId];\n};\n\nvar updateMethods = {\n\n    prepareAndUpdate: function (payload) {\n        prepare(this);\n        updateMethods.update.call(this, payload);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    update: function (payload) {\n        // console.profile && console.profile('update');\n\n        var ecModel = this._model;\n        var api = this._api;\n        var zr = this._zr;\n        var coordSysMgr = this._coordSysMgr;\n        var scheduler = this._scheduler;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        scheduler.restoreData(ecModel, payload);\n\n        scheduler.performSeriesTasks(ecModel);\n\n        // TODO\n        // Save total ecModel here for undo/redo (after restoring data and before processing data).\n        // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call.\n\n        // Create new coordinate system each update\n        // In LineView may save the old coordinate system and use it to get the orignal point\n        coordSysMgr.create(ecModel, api);\n\n        scheduler.performDataProcessorTasks(ecModel, payload);\n\n        // Current stream render is not supported in data process. So we can update\n        // stream modes after data processing, where the filtered data is used to\n        // deteming whether use progressive rendering.\n        updateStreamModes(this, ecModel);\n\n        // We update stream modes before coordinate system updated, then the modes info\n        // can be fetched when coord sys updating (consider the barGrid extent fix). But\n        // the drawback is the full coord info can not be fetched. Fortunately this full\n        // coord is not requied in stream mode updater currently.\n        coordSysMgr.update(ecModel, api);\n\n        clearColorPalette(ecModel);\n        scheduler.performVisualTasks(ecModel, payload);\n\n        render(this, ecModel, api, payload);\n\n        // Set background\n        var backgroundColor = ecModel.get('backgroundColor') || 'transparent';\n\n        // In IE8\n        if (!env$1.canvasSupported) {\n            var colorArr = parse(backgroundColor);\n            backgroundColor = stringify(colorArr, 'rgb');\n            if (colorArr[3] === 0) {\n                backgroundColor = 'transparent';\n            }\n        }\n        else {\n            zr.setBackgroundColor(backgroundColor);\n        }\n\n        performPostUpdateFuncs(ecModel, api);\n\n        // console.profile && console.profileEnd('update');\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateTransform: function (payload) {\n        var ecModel = this._model;\n        var ecIns = this;\n        var api = this._api;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        // ChartView.markUpdateMethod(payload, 'updateTransform');\n\n        var componentDirtyList = [];\n        ecModel.eachComponent(function (componentType, componentModel) {\n            var componentView = ecIns.getViewOfComponentModel(componentModel);\n            if (componentView && componentView.__alive) {\n                if (componentView.updateTransform) {\n                    var result = componentView.updateTransform(componentModel, ecModel, api, payload);\n                    result && result.update && componentDirtyList.push(componentView);\n                }\n                else {\n                    componentDirtyList.push(componentView);\n                }\n            }\n        });\n\n        var seriesDirtyMap = createHashMap();\n        ecModel.eachSeries(function (seriesModel) {\n            var chartView = ecIns._chartsMap[seriesModel.__viewId];\n            if (chartView.updateTransform) {\n                var result = chartView.updateTransform(seriesModel, ecModel, api, payload);\n                result && result.update && seriesDirtyMap.set(seriesModel.uid, 1);\n            }\n            else {\n                seriesDirtyMap.set(seriesModel.uid, 1);\n            }\n        });\n\n        clearColorPalette(ecModel);\n        // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);\n        this._scheduler.performVisualTasks(\n            ecModel, payload, {setDirty: true, dirtyMap: seriesDirtyMap}\n        );\n\n        // Currently, not call render of components. Geo render cost a lot.\n        // renderComponents(ecIns, ecModel, api, payload, componentDirtyList);\n        renderSeries(ecIns, ecModel, api, payload, seriesDirtyMap);\n\n        performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateView: function (payload) {\n        var ecModel = this._model;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        Chart.markUpdateMethod(payload, 'updateView');\n\n        clearColorPalette(ecModel);\n\n        // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});\n\n        render(this, this._model, this._api, payload);\n\n        performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateVisual: function (payload) {\n        updateMethods.update.call(this, payload);\n\n        // var ecModel = this._model;\n\n        // // update before setOption\n        // if (!ecModel) {\n        //     return;\n        // }\n\n        // ChartView.markUpdateMethod(payload, 'updateVisual');\n\n        // clearColorPalette(ecModel);\n\n        // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // this._scheduler.performVisualTasks(ecModel, payload, {visualType: 'visual', setDirty: true});\n\n        // render(this, this._model, this._api, payload);\n\n        // performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateLayout: function (payload) {\n        updateMethods.update.call(this, payload);\n\n        // var ecModel = this._model;\n\n        // // update before setOption\n        // if (!ecModel) {\n        //     return;\n        // }\n\n        // ChartView.markUpdateMethod(payload, 'updateLayout');\n\n        // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);\n        // this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});\n\n        // render(this, this._model, this._api, payload);\n\n        // performPostUpdateFuncs(ecModel, this._api);\n    }\n};\n\nfunction prepare(ecIns) {\n    var ecModel = ecIns._model;\n    var scheduler = ecIns._scheduler;\n\n    scheduler.restorePipelines(ecModel);\n\n    scheduler.prepareStageTasks();\n\n    prepareView(ecIns, 'component', ecModel, scheduler);\n\n    prepareView(ecIns, 'chart', ecModel, scheduler);\n\n    scheduler.plan();\n}\n\n/**\n * @private\n */\nfunction updateDirectly(ecIns, method, payload, mainType, subType) {\n    var ecModel = ecIns._model;\n\n    // broadcast\n    if (!mainType) {\n        // FIXME\n        // Chart will not be update directly here, except set dirty.\n        // But there is no such scenario now.\n        each(ecIns._componentsViews.concat(ecIns._chartsViews), callView);\n        return;\n    }\n\n    var query = {};\n    query[mainType + 'Id'] = payload[mainType + 'Id'];\n    query[mainType + 'Index'] = payload[mainType + 'Index'];\n    query[mainType + 'Name'] = payload[mainType + 'Name'];\n\n    var condition = {mainType: mainType, query: query};\n    subType && (condition.subType = subType); // subType may be '' by parseClassType;\n\n    var excludeSeriesId = payload.excludeSeriesId;\n    if (excludeSeriesId != null) {\n        excludeSeriesId = createHashMap(normalizeToArray(excludeSeriesId));\n    }\n\n    // If dispatchAction before setOption, do nothing.\n    ecModel && ecModel.eachComponent(condition, function (model) {\n        if (!excludeSeriesId || excludeSeriesId.get(model.id) == null) {\n            callView(ecIns[\n                mainType === 'series' ? '_chartsMap' : '_componentsMap'\n            ][model.__viewId]);\n        }\n    }, ecIns);\n\n    function callView(view) {\n        view && view.__alive && view[method] && view[method](\n            view.__model, ecModel, ecIns._api, payload\n        );\n    }\n}\n\n/**\n * Resize the chart\n * @param {Object} opts\n * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)\n * @param {boolean} [opts.silent=false]\n */\nechartsProto.resize = function (opts) {\n    if (__DEV__) {\n        assert(!this[IN_MAIN_PROCESS], '`resize` should not be called during main process.');\n    }\n\n    this._zr.resize(opts);\n\n    var ecModel = this._model;\n\n    // Resize loading effect\n    this._loadingFX && this._loadingFX.resize();\n\n    if (!ecModel) {\n        return;\n    }\n\n    var optionChanged = ecModel.resetOption('media');\n\n    var silent = opts && opts.silent;\n\n    this[IN_MAIN_PROCESS] = true;\n\n    optionChanged && prepare(this);\n    updateMethods.update.call(this);\n\n    this[IN_MAIN_PROCESS] = false;\n\n    flushPendingActions.call(this, silent);\n\n    triggerUpdatedEvent.call(this, silent);\n};\n\nfunction updateStreamModes(ecIns, ecModel) {\n    var chartsMap = ecIns._chartsMap;\n    var scheduler = ecIns._scheduler;\n    ecModel.eachSeries(function (seriesModel) {\n        scheduler.updateStreamModes(seriesModel, chartsMap[seriesModel.__viewId]);\n    });\n}\n\n/**\n * Show loading effect\n * @param  {string} [name='default']\n * @param  {Object} [cfg]\n */\nechartsProto.showLoading = function (name, cfg) {\n    if (isObject(name)) {\n        cfg = name;\n        name = '';\n    }\n    name = name || 'default';\n\n    this.hideLoading();\n    if (!loadingEffects[name]) {\n        if (__DEV__) {\n            console.warn('Loading effects ' + name + ' not exists.');\n        }\n        return;\n    }\n    var el = loadingEffects[name](this._api, cfg);\n    var zr = this._zr;\n    this._loadingFX = el;\n\n    zr.add(el);\n};\n\n/**\n * Hide loading effect\n */\nechartsProto.hideLoading = function () {\n    this._loadingFX && this._zr.remove(this._loadingFX);\n    this._loadingFX = null;\n};\n\n/**\n * @param {Object} eventObj\n * @return {Object}\n */\nechartsProto.makeActionFromEvent = function (eventObj) {\n    var payload = extend({}, eventObj);\n    payload.type = eventActionMap[eventObj.type];\n    return payload;\n};\n\n/**\n * @pubilc\n * @param {Object} payload\n * @param {string} [payload.type] Action type\n * @param {Object|boolean} [opt] If pass boolean, means opt.silent\n * @param {boolean} [opt.silent=false] Whether trigger events.\n * @param {boolean} [opt.flush=undefined]\n *                  true: Flush immediately, and then pixel in canvas can be fetched\n *                      immediately. Caution: it might affect performance.\n *                  false: Not not flush.\n *                  undefined: Auto decide whether perform flush.\n */\nechartsProto.dispatchAction = function (payload, opt) {\n    if (!isObject(opt)) {\n        opt = {silent: !!opt};\n    }\n\n    if (!actions[payload.type]) {\n        return;\n    }\n\n    // Avoid dispatch action before setOption. Especially in `connect`.\n    if (!this._model) {\n        return;\n    }\n\n    // May dispatchAction in rendering procedure\n    if (this[IN_MAIN_PROCESS]) {\n        this._pendingActions.push(payload);\n        return;\n    }\n\n    doDispatchAction.call(this, payload, opt.silent);\n\n    if (opt.flush) {\n        this._zr.flush(true);\n    }\n    else if (opt.flush !== false && env$1.browser.weChat) {\n        // In WeChat embeded browser, `requestAnimationFrame` and `setInterval`\n        // hang when sliding page (on touch event), which cause that zr does not\n        // refresh util user interaction finished, which is not expected.\n        // But `dispatchAction` may be called too frequently when pan on touch\n        // screen, which impacts performance if do not throttle them.\n        this._throttledZrFlush();\n    }\n\n    flushPendingActions.call(this, opt.silent);\n\n    triggerUpdatedEvent.call(this, opt.silent);\n};\n\nfunction doDispatchAction(payload, silent) {\n    var payloadType = payload.type;\n    var escapeConnect = payload.escapeConnect;\n    var actionWrap = actions[payloadType];\n    var actionInfo = actionWrap.actionInfo;\n\n    var cptType = (actionInfo.update || 'update').split(':');\n    var updateMethod = cptType.pop();\n    cptType = cptType[0] != null && parseClassType(cptType[0]);\n\n    this[IN_MAIN_PROCESS] = true;\n\n    var payloads = [payload];\n    var batched = false;\n    // Batch action\n    if (payload.batch) {\n        batched = true;\n        payloads = map(payload.batch, function (item) {\n            item = defaults(extend({}, item), payload);\n            item.batch = null;\n            return item;\n        });\n    }\n\n    var eventObjBatch = [];\n    var eventObj;\n    var isHighDown = payloadType === 'highlight' || payloadType === 'downplay';\n\n    each(payloads, function (batchItem) {\n        // Action can specify the event by return it.\n        eventObj = actionWrap.action(batchItem, this._model, this._api);\n        // Emit event outside\n        eventObj = eventObj || extend({}, batchItem);\n        // Convert type to eventType\n        eventObj.type = actionInfo.event || eventObj.type;\n        eventObjBatch.push(eventObj);\n\n        // light update does not perform data process, layout and visual.\n        if (isHighDown) {\n            // method, payload, mainType, subType\n            updateDirectly(this, updateMethod, batchItem, 'series');\n        }\n        else if (cptType) {\n            updateDirectly(this, updateMethod, batchItem, cptType.main, cptType.sub);\n        }\n    }, this);\n\n    if (updateMethod !== 'none' && !isHighDown && !cptType) {\n        // Still dirty\n        if (this[OPTION_UPDATED]) {\n            // FIXME Pass payload ?\n            prepare(this);\n            updateMethods.update.call(this, payload);\n            this[OPTION_UPDATED] = false;\n        }\n        else {\n            updateMethods[updateMethod].call(this, payload);\n        }\n    }\n\n    // Follow the rule of action batch\n    if (batched) {\n        eventObj = {\n            type: actionInfo.event || payloadType,\n            escapeConnect: escapeConnect,\n            batch: eventObjBatch\n        };\n    }\n    else {\n        eventObj = eventObjBatch[0];\n    }\n\n    this[IN_MAIN_PROCESS] = false;\n\n    !silent && this._messageCenter.trigger(eventObj.type, eventObj);\n}\n\nfunction flushPendingActions(silent) {\n    var pendingActions = this._pendingActions;\n    while (pendingActions.length) {\n        var payload = pendingActions.shift();\n        doDispatchAction.call(this, payload, silent);\n    }\n}\n\nfunction triggerUpdatedEvent(silent) {\n    !silent && this.trigger('updated');\n}\n\n/**\n * Event `rendered` is triggered when zr\n * rendered. It is useful for realtime\n * snapshot (reflect animation).\n *\n * Event `finished` is triggered when:\n * (1) zrender rendering finished.\n * (2) initial animation finished.\n * (3) progressive rendering finished.\n * (4) no pending action.\n * (5) no delayed setOption needs to be processed.\n */\nfunction bindRenderedEvent(zr, ecIns) {\n    zr.on('rendered', function () {\n\n        ecIns.trigger('rendered');\n\n        // The `finished` event should not be triggered repeatly,\n        // so it should only be triggered when rendering indeed happend\n        // in zrender. (Consider the case that dipatchAction is keep\n        // triggering when mouse move).\n        if (\n            // Although zr is dirty if initial animation is not finished\n            // and this checking is called on frame, we also check\n            // animation finished for robustness.\n            zr.animation.isFinished()\n            && !ecIns[OPTION_UPDATED]\n            && !ecIns._scheduler.unfinished\n            && !ecIns._pendingActions.length\n        ) {\n            ecIns.trigger('finished');\n        }\n    });\n}\n\n/**\n * @param {Object} params\n * @param {number} params.seriesIndex\n * @param {Array|TypedArray} params.data\n */\nechartsProto.appendData = function (params) {\n    var seriesIndex = params.seriesIndex;\n    var ecModel = this.getModel();\n    var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n\n    if (__DEV__) {\n        assert(params.data && seriesModel);\n    }\n\n    seriesModel.appendData(params);\n\n    // Note: `appendData` does not support that update extent of coordinate\n    // system, util some scenario require that. In the expected usage of\n    // `appendData`, the initial extent of coordinate system should better\n    // be fixed by axis `min`/`max` setting or initial data, otherwise if\n    // the extent changed while `appendData`, the location of the painted\n    // graphic elements have to be changed, which make the usage of\n    // `appendData` meaningless.\n\n    this._scheduler.unfinished = true;\n};\n\n/**\n * Register event\n * @method\n */\nechartsProto.on = createRegisterEventWithLowercaseName('on');\nechartsProto.off = createRegisterEventWithLowercaseName('off');\nechartsProto.one = createRegisterEventWithLowercaseName('one');\n\n/**\n * Prepare view instances of charts and components\n * @param  {module:echarts/model/Global} ecModel\n * @private\n */\nfunction prepareView(ecIns, type, ecModel, scheduler) {\n    var isComponent = type === 'component';\n    var viewList = isComponent ? ecIns._componentsViews : ecIns._chartsViews;\n    var viewMap = isComponent ? ecIns._componentsMap : ecIns._chartsMap;\n    var zr = ecIns._zr;\n    var api = ecIns._api;\n\n    for (var i = 0; i < viewList.length; i++) {\n        viewList[i].__alive = false;\n    }\n\n    isComponent\n        ? ecModel.eachComponent(function (componentType, model) {\n            componentType !== 'series' && doPrepare(model);\n        })\n        : ecModel.eachSeries(doPrepare);\n\n    function doPrepare(model) {\n        // Consider: id same and type changed.\n        var viewId = '_ec_' + model.id + '_' + model.type;\n        var view = viewMap[viewId];\n        if (!view) {\n            var classType = parseClassType(model.type);\n            var Clazz = isComponent\n                ? Component.getClass(classType.main, classType.sub)\n                : Chart.getClass(classType.sub);\n\n            if (__DEV__) {\n                assert(Clazz, classType.sub + ' does not exist.');\n            }\n\n            view = new Clazz();\n            view.init(ecModel, api);\n            viewMap[viewId] = view;\n            viewList.push(view);\n            zr.add(view.group);\n        }\n\n        model.__viewId = view.__id = viewId;\n        view.__alive = true;\n        view.__model = model;\n        view.group.__ecComponentInfo = {\n            mainType: model.mainType,\n            index: model.componentIndex\n        };\n        !isComponent && scheduler.prepareView(view, model, ecModel, api);\n    }\n\n    for (var i = 0; i < viewList.length;) {\n        var view = viewList[i];\n        if (!view.__alive) {\n            !isComponent && view.renderTask.dispose();\n            zr.remove(view.group);\n            view.dispose(ecModel, api);\n            viewList.splice(i, 1);\n            delete viewMap[view.__id];\n            view.__id = view.group.__ecComponentInfo = null;\n        }\n        else {\n            i++;\n        }\n    }\n}\n\n// /**\n//  * Encode visual infomation from data after data processing\n//  *\n//  * @param {module:echarts/model/Global} ecModel\n//  * @param {object} layout\n//  * @param {boolean} [layoutFilter] `true`: only layout,\n//  *                                 `false`: only not layout,\n//  *                                 `null`/`undefined`: all.\n//  * @param {string} taskBaseTag\n//  * @private\n//  */\n// function startVisualEncoding(ecIns, ecModel, api, payload, layoutFilter) {\n//     each(visualFuncs, function (visual, index) {\n//         var isLayout = visual.isLayout;\n//         if (layoutFilter == null\n//             || (layoutFilter === false && !isLayout)\n//             || (layoutFilter === true && isLayout)\n//         ) {\n//             visual.func(ecModel, api, payload);\n//         }\n//     });\n// }\n\nfunction clearColorPalette(ecModel) {\n    ecModel.clearColorPalette();\n    ecModel.eachSeries(function (seriesModel) {\n        seriesModel.clearColorPalette();\n    });\n}\n\nfunction render(ecIns, ecModel, api, payload) {\n\n    renderComponents(ecIns, ecModel, api, payload);\n\n    each(ecIns._chartsViews, function (chart) {\n        chart.__alive = false;\n    });\n\n    renderSeries(ecIns, ecModel, api, payload);\n\n    // Remove groups of unrendered charts\n    each(ecIns._chartsViews, function (chart) {\n        if (!chart.__alive) {\n            chart.remove(ecModel, api);\n        }\n    });\n}\n\nfunction renderComponents(ecIns, ecModel, api, payload, dirtyList) {\n    each(dirtyList || ecIns._componentsViews, function (componentView) {\n        var componentModel = componentView.__model;\n        componentView.render(componentModel, ecModel, api, payload);\n\n        updateZ(componentModel, componentView);\n    });\n}\n\n/**\n * Render each chart and component\n * @private\n */\nfunction renderSeries(ecIns, ecModel, api, payload, dirtyMap) {\n    // Render all charts\n    var scheduler = ecIns._scheduler;\n    var unfinished;\n    ecModel.eachSeries(function (seriesModel) {\n        var chartView = ecIns._chartsMap[seriesModel.__viewId];\n        chartView.__alive = true;\n\n        var renderTask = chartView.renderTask;\n        scheduler.updatePayload(renderTask, payload);\n\n        if (dirtyMap && dirtyMap.get(seriesModel.uid)) {\n            renderTask.dirty();\n        }\n\n        unfinished |= renderTask.perform(scheduler.getPerformArgs(renderTask));\n\n        chartView.group.silent = !!seriesModel.get('silent');\n\n        updateZ(seriesModel, chartView);\n\n        updateBlend(seriesModel, chartView);\n    });\n    scheduler.unfinished |= unfinished;\n\n    // If use hover layer\n    updateHoverLayerStatus(ecIns._zr, ecModel);\n\n    // Add aria\n    aria(ecIns._zr.dom, ecModel);\n}\n\nfunction performPostUpdateFuncs(ecModel, api) {\n    each(postUpdateFuncs, function (func) {\n        func(ecModel, api);\n    });\n}\n\n\nvar MOUSE_EVENT_NAMES = [\n    'click', 'dblclick', 'mouseover', 'mouseout', 'mousemove',\n    'mousedown', 'mouseup', 'globalout', 'contextmenu'\n];\n\n/**\n * @private\n */\nechartsProto._initEvents = function () {\n    each(MOUSE_EVENT_NAMES, function (eveName) {\n        var handler = function (e) {\n            var ecModel = this.getModel();\n            var el = e.target;\n            var params;\n            var isGlobalOut = eveName === 'globalout';\n\n            // no e.target when 'globalout'.\n            if (isGlobalOut) {\n                params = {};\n            }\n            else if (el && el.dataIndex != null) {\n                var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex);\n                params = dataModel && dataModel.getDataParams(el.dataIndex, el.dataType, el) || {};\n            }\n            // If element has custom eventData of components\n            else if (el && el.eventData) {\n                params = extend({}, el.eventData);\n            }\n\n            // Contract: if params prepared in mouse event,\n            // these properties must be specified:\n            // {\n            //    componentType: string (component main type)\n            //    componentIndex: number\n            // }\n            // Otherwise event query can not work.\n\n            if (params) {\n                var componentType = params.componentType;\n                var componentIndex = params.componentIndex;\n                // Special handling for historic reason: when trigger by\n                // markLine/markPoint/markArea, the componentType is\n                // 'markLine'/'markPoint'/'markArea', but we should better\n                // enable them to be queried by seriesIndex, since their\n                // option is set in each series.\n                if (componentType === 'markLine'\n                    || componentType === 'markPoint'\n                    || componentType === 'markArea'\n                ) {\n                    componentType = 'series';\n                    componentIndex = params.seriesIndex;\n                }\n                var model = componentType && componentIndex != null\n                    && ecModel.getComponent(componentType, componentIndex);\n                var view = model && this[\n                    model.mainType === 'series' ? '_chartsMap' : '_componentsMap'\n                ][model.__viewId];\n\n                if (__DEV__) {\n                    // `event.componentType` and `event[componentTpype + 'Index']` must not\n                    // be missed, otherwise there is no way to distinguish source component.\n                    // See `dataFormat.getDataParams`.\n                    if (!isGlobalOut && !(model && view)) {\n                        console.warn('model or view can not be found by params');\n                    }\n                }\n\n                params.event = e;\n                params.type = eveName;\n\n                this._ecEventProcessor.eventInfo = {\n                    targetEl: el,\n                    packedEvent: params,\n                    model: model,\n                    view: view\n                };\n\n                this.trigger(eveName, params);\n            }\n        };\n        // Consider that some component (like tooltip, brush, ...)\n        // register zr event handler, but user event handler might\n        // do anything, such as call `setOption` or `dispatchAction`,\n        // which probably update any of the content and probably\n        // cause problem if it is called previous other inner handlers.\n        handler.zrEventfulCallAtLast = true;\n        this._zr.on(eveName, handler, this);\n    }, this);\n\n    each(eventActionMap, function (actionType, eventType) {\n        this._messageCenter.on(eventType, function (event) {\n            this.trigger(eventType, event);\n        }, this);\n    }, this);\n};\n\n/**\n * @return {boolean}\n */\nechartsProto.isDisposed = function () {\n    return this._disposed;\n};\n\n/**\n * Clear\n */\nechartsProto.clear = function () {\n    this.setOption({ series: [] }, true);\n};\n\n/**\n * Dispose instance\n */\nechartsProto.dispose = function () {\n    if (this._disposed) {\n        if (__DEV__) {\n            console.warn('Instance ' + this.id + ' has been disposed');\n        }\n        return;\n    }\n    this._disposed = true;\n\n    setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, '');\n\n    var api = this._api;\n    var ecModel = this._model;\n\n    each(this._componentsViews, function (component) {\n        component.dispose(ecModel, api);\n    });\n    each(this._chartsViews, function (chart) {\n        chart.dispose(ecModel, api);\n    });\n\n    // Dispose after all views disposed\n    this._zr.dispose();\n\n    delete instances[this.id];\n};\n\nmixin(ECharts, Eventful);\n\nfunction updateHoverLayerStatus(zr, ecModel) {\n    var storage = zr.storage;\n    var elCount = 0;\n    storage.traverse(function (el) {\n        if (!el.isGroup) {\n            elCount++;\n        }\n    });\n    if (elCount > ecModel.get('hoverLayerThreshold') && !env$1.node) {\n        storage.traverse(function (el) {\n            if (!el.isGroup) {\n                // Don't switch back.\n                el.useHoverLayer = true;\n            }\n        });\n    }\n}\n\n/**\n * Update chart progressive and blend.\n * @param {module:echarts/model/Series|module:echarts/model/Component} model\n * @param {module:echarts/view/Component|module:echarts/view/Chart} view\n */\nfunction updateBlend(seriesModel, chartView) {\n    var blendMode = seriesModel.get('blendMode') || null;\n    if (__DEV__) {\n        if (!env$1.canvasSupported && blendMode && blendMode !== 'source-over') {\n            console.warn('Only canvas support blendMode');\n        }\n    }\n    chartView.group.traverse(function (el) {\n        // FIXME marker and other components\n        if (!el.isGroup) {\n            // Only set if blendMode is changed. In case element is incremental and don't wan't to rerender.\n            if (el.style.blend !== blendMode) {\n                el.setStyle('blend', blendMode);\n            }\n        }\n        if (el.eachPendingDisplayable) {\n            el.eachPendingDisplayable(function (displayable) {\n                displayable.setStyle('blend', blendMode);\n            });\n        }\n    });\n}\n\n/**\n * @param {module:echarts/model/Series|module:echarts/model/Component} model\n * @param {module:echarts/view/Component|module:echarts/view/Chart} view\n */\nfunction updateZ(model, view) {\n    var z = model.get('z');\n    var zlevel = model.get('zlevel');\n    // Set z and zlevel\n    view.group.traverse(function (el) {\n        if (el.type !== 'group') {\n            z != null && (el.z = z);\n            zlevel != null && (el.zlevel = zlevel);\n        }\n    });\n}\n\nfunction createExtensionAPI(ecInstance) {\n    var coordSysMgr = ecInstance._coordSysMgr;\n    return extend(new ExtensionAPI(ecInstance), {\n        // Inject methods\n        getCoordinateSystems: bind(\n            coordSysMgr.getCoordinateSystems, coordSysMgr\n        ),\n        getComponentByElement: function (el) {\n            while (el) {\n                var modelInfo = el.__ecComponentInfo;\n                if (modelInfo != null) {\n                    return ecInstance._model.getComponent(modelInfo.mainType, modelInfo.index);\n                }\n                el = el.parent;\n            }\n        }\n    });\n}\n\n\n/**\n * @class\n * Usage of query:\n * `chart.on('click', query, handler);`\n * The `query` can be:\n * + The component type query string, only `mainType` or `mainType.subType`,\n *   like: 'xAxis', 'series', 'xAxis.category' or 'series.line'.\n * + The component query object, like:\n *   `{seriesIndex: 2}`, `{seriesName: 'xx'}`, `{seriesId: 'some'}`,\n *   `{xAxisIndex: 2}`, `{xAxisName: 'xx'}`, `{xAxisId: 'some'}`.\n * + The data query object, like:\n *   `{dataIndex: 123}`, `{dataType: 'link'}`, `{name: 'some'}`.\n * + The other query object (cmponent customized query), like:\n *   `{element: 'some'}` (only available in custom series).\n *\n * Caveat: If a prop in the `query` object is `null/undefined`, it is the\n * same as there is no such prop in the `query` object.\n */\nfunction EventProcessor() {\n    // These info required: targetEl, packedEvent, model, view\n    this.eventInfo;\n}\nEventProcessor.prototype = {\n    constructor: EventProcessor,\n\n    normalizeQuery: function (query) {\n        var cptQuery = {};\n        var dataQuery = {};\n        var otherQuery = {};\n\n        // `query` is `mainType` or `mainType.subType` of component.\n        if (isString(query)) {\n            var condCptType = parseClassType(query);\n            // `.main` and `.sub` may be ''.\n            cptQuery.mainType = condCptType.main || null;\n            cptQuery.subType = condCptType.sub || null;\n        }\n        // `query` is an object, convert to {mainType, index, name, id}.\n        else {\n            // `xxxIndex`, `xxxName`, `xxxId`, `name`, `dataIndex`, `dataType` is reserved,\n            // can not be used in `compomentModel.filterForExposedEvent`.\n            var suffixes = ['Index', 'Name', 'Id'];\n            var dataKeys = {name: 1, dataIndex: 1, dataType: 1};\n            each$1(query, function (val, key) {\n                var reserved = false;\n                for (var i = 0; i < suffixes.length; i++) {\n                    var propSuffix = suffixes[i];\n                    var suffixPos = key.lastIndexOf(propSuffix);\n                    if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) {\n                        var mainType = key.slice(0, suffixPos);\n                        // Consider `dataIndex`.\n                        if (mainType !== 'data') {\n                            cptQuery.mainType = mainType;\n                            cptQuery[propSuffix.toLowerCase()] = val;\n                            reserved = true;\n                        }\n                    }\n                }\n                if (dataKeys.hasOwnProperty(key)) {\n                    dataQuery[key] = val;\n                    reserved = true;\n                }\n                if (!reserved) {\n                    otherQuery[key] = val;\n                }\n            });\n        }\n\n        return {\n            cptQuery: cptQuery,\n            dataQuery: dataQuery,\n            otherQuery: otherQuery\n        };\n    },\n\n    filter: function (eventType, query, args) {\n        // They should be assigned before each trigger call.\n        var eventInfo = this.eventInfo;\n\n        if (!eventInfo) {\n            return true;\n        }\n\n        var targetEl = eventInfo.targetEl;\n        var packedEvent = eventInfo.packedEvent;\n        var model = eventInfo.model;\n        var view = eventInfo.view;\n\n        // For event like 'globalout'.\n        if (!model || !view) {\n            return true;\n        }\n\n        var cptQuery = query.cptQuery;\n        var dataQuery = query.dataQuery;\n\n        return check(cptQuery, model, 'mainType')\n            && check(cptQuery, model, 'subType')\n            && check(cptQuery, model, 'index', 'componentIndex')\n            && check(cptQuery, model, 'name')\n            && check(cptQuery, model, 'id')\n            && check(dataQuery, packedEvent, 'name')\n            && check(dataQuery, packedEvent, 'dataIndex')\n            && check(dataQuery, packedEvent, 'dataType')\n            && (!view.filterForExposedEvent || view.filterForExposedEvent(\n                eventType, query.otherQuery, targetEl, packedEvent\n            ));\n\n        function check(query, host, prop, propOnHost) {\n            return query[prop] == null || host[propOnHost || prop] === query[prop];\n        }\n    },\n\n    afterTrigger: function () {\n        // Make sure the eventInfo wont be used in next trigger.\n        this.eventInfo = null;\n    }\n};\n\n\n/**\n * @type {Object} key: actionType.\n * @inner\n */\nvar actions = {};\n\n/**\n * Map eventType to actionType\n * @type {Object}\n */\nvar eventActionMap = {};\n\n/**\n * Data processor functions of each stage\n * @type {Array.<Object.<string, Function>>}\n * @inner\n */\nvar dataProcessorFuncs = [];\n\n/**\n * @type {Array.<Function>}\n * @inner\n */\nvar optionPreprocessorFuncs = [];\n\n/**\n * @type {Array.<Function>}\n * @inner\n */\nvar postUpdateFuncs = [];\n\n/**\n * Visual encoding functions of each stage\n * @type {Array.<Object.<string, Function>>}\n */\nvar visualFuncs = [];\n\n/**\n * Theme storage\n * @type {Object.<key, Object>}\n */\nvar themeStorage = {};\n/**\n * Loading effects\n */\nvar loadingEffects = {};\n\nvar instances = {};\nvar connectedGroups = {};\n\nvar idBase = new Date() - 0;\nvar groupIdBase = new Date() - 0;\nvar DOM_ATTRIBUTE_KEY = '_echarts_instance_';\n\nfunction enableConnect(chart) {\n    var STATUS_PENDING = 0;\n    var STATUS_UPDATING = 1;\n    var STATUS_UPDATED = 2;\n    var STATUS_KEY = '__connectUpdateStatus';\n\n    function updateConnectedChartsStatus(charts, status) {\n        for (var i = 0; i < charts.length; i++) {\n            var otherChart = charts[i];\n            otherChart[STATUS_KEY] = status;\n        }\n    }\n\n    each(eventActionMap, function (actionType, eventType) {\n        chart._messageCenter.on(eventType, function (event) {\n            if (connectedGroups[chart.group] && chart[STATUS_KEY] !== STATUS_PENDING) {\n                if (event && event.escapeConnect) {\n                    return;\n                }\n\n                var action = chart.makeActionFromEvent(event);\n                var otherCharts = [];\n\n                each(instances, function (otherChart) {\n                    if (otherChart !== chart && otherChart.group === chart.group) {\n                        otherCharts.push(otherChart);\n                    }\n                });\n\n                updateConnectedChartsStatus(otherCharts, STATUS_PENDING);\n                each(otherCharts, function (otherChart) {\n                    if (otherChart[STATUS_KEY] !== STATUS_UPDATING) {\n                        otherChart.dispatchAction(action);\n                    }\n                });\n                updateConnectedChartsStatus(otherCharts, STATUS_UPDATED);\n            }\n        });\n    });\n}\n\n/**\n * @param {HTMLElement} dom\n * @param {Object} [theme]\n * @param {Object} opts\n * @param {number} [opts.devicePixelRatio] Use window.devicePixelRatio by default\n * @param {string} [opts.renderer] Currently only 'canvas' is supported.\n * @param {number} [opts.width] Use clientWidth of the input `dom` by default.\n *                              Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Use clientHeight of the input `dom` by default.\n *                               Can be 'auto' (the same as null/undefined)\n */\nfunction init(dom, theme$$1, opts) {\n    if (__DEV__) {\n        // Check version\n        if ((version$1.replace('.', '') - 0) < (dependencies.zrender.replace('.', '') - 0)) {\n            throw new Error(\n                'zrender/src ' + version$1\n                + ' is too old for ECharts ' + version\n                + '. Current version need ZRender '\n                + dependencies.zrender + '+'\n            );\n        }\n\n        if (!dom) {\n            throw new Error('Initialize failed: invalid dom.');\n        }\n    }\n\n    var existInstance = getInstanceByDom(dom);\n    if (existInstance) {\n        if (__DEV__) {\n            console.warn('There is a chart instance already initialized on the dom.');\n        }\n        return existInstance;\n    }\n\n    if (__DEV__) {\n        if (isDom(dom)\n            && dom.nodeName.toUpperCase() !== 'CANVAS'\n            && (\n                (!dom.clientWidth && (!opts || opts.width == null))\n                || (!dom.clientHeight && (!opts || opts.height == null))\n            )\n        ) {\n            console.warn('Can\\'t get dom width or height');\n        }\n    }\n\n    var chart = new ECharts(dom, theme$$1, opts);\n    chart.id = 'ec_' + idBase++;\n    instances[chart.id] = chart;\n\n    setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id);\n\n    enableConnect(chart);\n\n    return chart;\n}\n\n/**\n * @return {string|Array.<module:echarts~ECharts>} groupId\n */\nfunction connect(groupId) {\n    // Is array of charts\n    if (isArray(groupId)) {\n        var charts = groupId;\n        groupId = null;\n        // If any chart has group\n        each(charts, function (chart) {\n            if (chart.group != null) {\n                groupId = chart.group;\n            }\n        });\n        groupId = groupId || ('g_' + groupIdBase++);\n        each(charts, function (chart) {\n            chart.group = groupId;\n        });\n    }\n    connectedGroups[groupId] = true;\n    return groupId;\n}\n\n/**\n * @DEPRECATED\n * @return {string} groupId\n */\nfunction disConnect(groupId) {\n    connectedGroups[groupId] = false;\n}\n\n/**\n * @return {string} groupId\n */\nvar disconnect = disConnect;\n\n/**\n * Dispose a chart instance\n * @param  {module:echarts~ECharts|HTMLDomElement|string} chart\n */\nfunction dispose(chart) {\n    if (typeof chart === 'string') {\n        chart = instances[chart];\n    }\n    else if (!(chart instanceof ECharts)) {\n        // Try to treat as dom\n        chart = getInstanceByDom(chart);\n    }\n    if ((chart instanceof ECharts) && !chart.isDisposed()) {\n        chart.dispose();\n    }\n}\n\n/**\n * @param  {HTMLElement} dom\n * @return {echarts~ECharts}\n */\nfunction getInstanceByDom(dom) {\n    return instances[getAttribute(dom, DOM_ATTRIBUTE_KEY)];\n}\n\n/**\n * @param {string} key\n * @return {echarts~ECharts}\n */\nfunction getInstanceById(key) {\n    return instances[key];\n}\n\n/**\n * Register theme\n */\nfunction registerTheme(name, theme$$1) {\n    themeStorage[name] = theme$$1;\n}\n\n/**\n * Register option preprocessor\n * @param {Function} preprocessorFunc\n */\nfunction registerPreprocessor(preprocessorFunc) {\n    optionPreprocessorFuncs.push(preprocessorFunc);\n}\n\n/**\n * @param {number} [priority=1000]\n * @param {Object|Function} processor\n */\nfunction registerProcessor(priority, processor) {\n    normalizeRegister(dataProcessorFuncs, priority, processor, PRIORITY_PROCESSOR_FILTER);\n}\n\n/**\n * Register postUpdater\n * @param {Function} postUpdateFunc\n */\nfunction registerPostUpdate(postUpdateFunc) {\n    postUpdateFuncs.push(postUpdateFunc);\n}\n\n/**\n * Usage:\n * registerAction('someAction', 'someEvent', function () { ... });\n * registerAction('someAction', function () { ... });\n * registerAction(\n *     {type: 'someAction', event: 'someEvent', update: 'updateView'},\n *     function () { ... }\n * );\n *\n * @param {(string|Object)} actionInfo\n * @param {string} actionInfo.type\n * @param {string} [actionInfo.event]\n * @param {string} [actionInfo.update]\n * @param {string} [eventName]\n * @param {Function} action\n */\nfunction registerAction(actionInfo, eventName, action) {\n    if (typeof eventName === 'function') {\n        action = eventName;\n        eventName = '';\n    }\n    var actionType = isObject(actionInfo)\n        ? actionInfo.type\n        : ([actionInfo, actionInfo = {\n            event: eventName\n        }][0]);\n\n    // Event name is all lowercase\n    actionInfo.event = (actionInfo.event || actionType).toLowerCase();\n    eventName = actionInfo.event;\n\n    // Validate action type and event name.\n    assert(ACTION_REG.test(actionType) && ACTION_REG.test(eventName));\n\n    if (!actions[actionType]) {\n        actions[actionType] = {action: action, actionInfo: actionInfo};\n    }\n    eventActionMap[eventName] = actionType;\n}\n\n/**\n * @param {string} type\n * @param {*} CoordinateSystem\n */\nfunction registerCoordinateSystem(type, CoordinateSystem$$1) {\n    CoordinateSystemManager.register(type, CoordinateSystem$$1);\n}\n\n/**\n * Get dimensions of specified coordinate system.\n * @param {string} type\n * @return {Array.<string|Object>}\n */\nfunction getCoordinateSystemDimensions(type) {\n    var coordSysCreator = CoordinateSystemManager.get(type);\n    if (coordSysCreator) {\n        return coordSysCreator.getDimensionsInfo\n                ? coordSysCreator.getDimensionsInfo()\n                : coordSysCreator.dimensions.slice();\n    }\n}\n\n/**\n * Layout is a special stage of visual encoding\n * Most visual encoding like color are common for different chart\n * But each chart has it's own layout algorithm\n *\n * @param {number} [priority=1000]\n * @param {Function} layoutTask\n */\nfunction registerLayout(priority, layoutTask) {\n    normalizeRegister(visualFuncs, priority, layoutTask, PRIORITY_VISUAL_LAYOUT, 'layout');\n}\n\n/**\n * @param {number} [priority=3000]\n * @param {module:echarts/stream/Task} visualTask\n */\nfunction registerVisual(priority, visualTask) {\n    normalizeRegister(visualFuncs, priority, visualTask, PRIORITY_VISUAL_CHART, 'visual');\n}\n\n/**\n * @param {Object|Function} fn: {seriesType, createOnAllSeries, performRawSeries, reset}\n */\nfunction normalizeRegister(targetList, priority, fn, defaultPriority, visualType) {\n    if (isFunction(priority) || isObject(priority)) {\n        fn = priority;\n        priority = defaultPriority;\n    }\n\n    if (__DEV__) {\n        if (isNaN(priority) || priority == null) {\n            throw new Error('Illegal priority');\n        }\n        // Check duplicate\n        each(targetList, function (wrap) {\n            assert(wrap.__raw !== fn);\n        });\n    }\n\n    var stageHandler = Scheduler.wrapStageHandler(fn, visualType);\n\n    stageHandler.__prio = priority;\n    stageHandler.__raw = fn;\n    targetList.push(stageHandler);\n\n    return stageHandler;\n}\n\n/**\n * @param {string} name\n */\nfunction registerLoading(name, loadingFx) {\n    loadingEffects[name] = loadingFx;\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendComponentModel(opts/*, superClass*/) {\n    // var Clazz = ComponentModel;\n    // if (superClass) {\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentModel.getClass(classType.main, classType.sub, true);\n    // }\n    return ComponentModel.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendComponentView(opts/*, superClass*/) {\n    // var Clazz = ComponentView;\n    // if (superClass) {\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentView.getClass(classType.main, classType.sub, true);\n    // }\n    return Component.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendSeriesModel(opts/*, superClass*/) {\n    // var Clazz = SeriesModel;\n    // if (superClass) {\n    //     superClass = 'series.' + superClass.replace('series.', '');\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentModel.getClass(classType.main, classType.sub, true);\n    // }\n    return SeriesModel.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendChartView(opts/*, superClass*/) {\n    // var Clazz = ChartView;\n    // if (superClass) {\n    //     superClass = superClass.replace('series.', '');\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ChartView.getClass(classType.main, true);\n    // }\n    return Chart.extend(opts);\n}\n\n/**\n * ZRender need a canvas context to do measureText.\n * But in node environment canvas may be created by node-canvas.\n * So we need to specify how to create a canvas instead of using document.createElement('canvas')\n *\n * Be careful of using it in the browser.\n *\n * @param {Function} creator\n * @example\n *     var Canvas = require('canvas');\n *     var echarts = require('echarts');\n *     echarts.setCanvasCreator(function () {\n *         // Small size is enough.\n *         return new Canvas(32, 32);\n *     });\n */\nfunction setCanvasCreator(creator) {\n    $override('createCanvas', creator);\n}\n\n/**\n * @param {string} mapName\n * @param {Array.<Object>|Object|string} geoJson\n * @param {Object} [specialAreas]\n *\n * @example GeoJSON\n *     $.get('USA.json', function (geoJson) {\n *         echarts.registerMap('USA', geoJson);\n *         // Or\n *         echarts.registerMap('USA', {\n *             geoJson: geoJson,\n *             specialAreas: {}\n *         })\n *     });\n *\n *     $.get('airport.svg', function (svg) {\n *         echarts.registerMap('airport', {\n *             svg: svg\n *         }\n *     });\n *\n *     echarts.registerMap('eu', [\n *         {svg: eu-topographic.svg},\n *         {geoJSON: eu.json}\n *     ])\n */\nfunction registerMap(mapName, geoJson, specialAreas) {\n    mapDataStorage.registerMap(mapName, geoJson, specialAreas);\n}\n\n/**\n * @param {string} mapName\n * @return {Object}\n */\nfunction getMap(mapName) {\n    // For backward compatibility, only return the first one.\n    var records = mapDataStorage.retrieveMap(mapName);\n    return records && records[0] && {\n        geoJson: records[0].geoJSON,\n        specialAreas: records[0].specialAreas\n    };\n}\n\nregisterVisual(PRIORITY_VISUAL_GLOBAL, seriesColor);\nregisterPreprocessor(backwardCompat);\nregisterProcessor(PRIORITY_PROCESSOR_STATISTIC, dataStack);\nregisterLoading('default', loadingDefault);\n\n// Default actions\n\nregisterAction({\n    type: 'highlight',\n    event: 'highlight',\n    update: 'highlight'\n}, noop);\n\nregisterAction({\n    type: 'downplay',\n    event: 'downplay',\n    update: 'downplay'\n}, noop);\n\n// Default theme\nregisterTheme('light', lightTheme);\nregisterTheme('dark', theme);\n\n// For backward compatibility, where the namespace `dataTool` will\n// be mounted on `echarts` is the extension `dataTool` is imported.\nvar dataTool = {};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction defaultKeyGetter(item) {\n    return item;\n}\n\n/**\n * @param {Array} oldArr\n * @param {Array} newArr\n * @param {Function} oldKeyGetter\n * @param {Function} newKeyGetter\n * @param {Object} [context] Can be visited by this.context in callback.\n */\nfunction DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter, context) {\n    this._old = oldArr;\n    this._new = newArr;\n\n    this._oldKeyGetter = oldKeyGetter || defaultKeyGetter;\n    this._newKeyGetter = newKeyGetter || defaultKeyGetter;\n\n    this.context = context;\n}\n\nDataDiffer.prototype = {\n\n    constructor: DataDiffer,\n\n    /**\n     * Callback function when add a data\n     */\n    add: function (func) {\n        this._add = func;\n        return this;\n    },\n\n    /**\n     * Callback function when update a data\n     */\n    update: function (func) {\n        this._update = func;\n        return this;\n    },\n\n    /**\n     * Callback function when remove a data\n     */\n    remove: function (func) {\n        this._remove = func;\n        return this;\n    },\n\n    execute: function () {\n        var oldArr = this._old;\n        var newArr = this._new;\n\n        var oldDataIndexMap = {};\n        var newDataIndexMap = {};\n        var oldDataKeyArr = [];\n        var newDataKeyArr = [];\n        var i;\n\n        initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, '_oldKeyGetter', this);\n        initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter', this);\n\n        // Travel by inverted order to make sure order consistency\n        // when duplicate keys exists (consider newDataIndex.pop() below).\n        // For performance consideration, these code below do not look neat.\n        for (i = 0; i < oldArr.length; i++) {\n            var key = oldDataKeyArr[i];\n            var idx = newDataIndexMap[key];\n\n            // idx can never be empty array here. see 'set null' logic below.\n            if (idx != null) {\n                // Consider there is duplicate key (for example, use dataItem.name as key).\n                // We should make sure every item in newArr and oldArr can be visited.\n                var len = idx.length;\n                if (len) {\n                    len === 1 && (newDataIndexMap[key] = null);\n                    idx = idx.unshift();\n                }\n                else {\n                    newDataIndexMap[key] = null;\n                }\n                this._update && this._update(idx, i);\n            }\n            else {\n                this._remove && this._remove(i);\n            }\n        }\n\n        for (var i = 0; i < newDataKeyArr.length; i++) {\n            var key = newDataKeyArr[i];\n            if (newDataIndexMap.hasOwnProperty(key)) {\n                var idx = newDataIndexMap[key];\n                if (idx == null) {\n                    continue;\n                }\n                // idx can never be empty array here. see 'set null' logic above.\n                if (!idx.length) {\n                    this._add && this._add(idx);\n                }\n                else {\n                    for (var j = 0, len = idx.length; j < len; j++) {\n                        this._add && this._add(idx[j]);\n                    }\n                }\n            }\n        }\n    }\n};\n\nfunction initIndexMap(arr, map, keyArr, keyGetterName, dataDiffer) {\n    for (var i = 0; i < arr.length; i++) {\n        // Add prefix to avoid conflict with Object.prototype.\n        var key = '_ec_' + dataDiffer[keyGetterName](arr[i], i);\n        var existence = map[key];\n        if (existence == null) {\n            keyArr.push(key);\n            map[key] = i;\n        }\n        else {\n            if (!existence.length) {\n                map[key] = existence = [existence];\n            }\n            existence.push(i);\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar OTHER_DIMENSIONS = createHashMap([\n    'tooltip', 'label', 'itemName', 'itemId', 'seriesName'\n]);\n\nfunction summarizeDimensions(data) {\n    var summary = {};\n    var encode = summary.encode = {};\n    var notExtraCoordDimMap = createHashMap();\n    var defaultedLabel = [];\n    var defaultedTooltip = [];\n\n    each$1(data.dimensions, function (dimName) {\n        var dimItem = data.getDimensionInfo(dimName);\n\n        var coordDim = dimItem.coordDim;\n        if (coordDim) {\n            if (__DEV__) {\n                assert$1(OTHER_DIMENSIONS.get(coordDim) == null);\n            }\n            var coordDimArr = encode[coordDim];\n            if (!encode.hasOwnProperty(coordDim)) {\n                coordDimArr = encode[coordDim] = [];\n            }\n            coordDimArr[dimItem.coordDimIndex] = dimName;\n\n            if (!dimItem.isExtraCoord) {\n                notExtraCoordDimMap.set(coordDim, 1);\n\n                // Use the last coord dim (and label friendly) as default label,\n                // because when dataset is used, it is hard to guess which dimension\n                // can be value dimension. If both show x, y on label is not look good,\n                // and conventionally y axis is focused more.\n                if (mayLabelDimType(dimItem.type)) {\n                    defaultedLabel[0] = dimName;\n                }\n            }\n            if (dimItem.defaultTooltip) {\n                defaultedTooltip.push(dimName);\n            }\n        }\n\n        OTHER_DIMENSIONS.each(function (v, otherDim) {\n            var otherDimArr = encode[otherDim];\n            if (!encode.hasOwnProperty(otherDim)) {\n                otherDimArr = encode[otherDim] = [];\n            }\n\n            var dimIndex = dimItem.otherDims[otherDim];\n            if (dimIndex != null && dimIndex !== false) {\n                otherDimArr[dimIndex] = dimItem.name;\n            }\n        });\n    });\n\n    var dataDimsOnCoord = [];\n    var encodeFirstDimNotExtra = {};\n\n    notExtraCoordDimMap.each(function (v, coordDim) {\n        var dimArr = encode[coordDim];\n        // ??? FIXME extra coord should not be set in dataDimsOnCoord.\n        // But should fix the case that radar axes: simplify the logic\n        // of `completeDimension`, remove `extraPrefix`.\n        encodeFirstDimNotExtra[coordDim] = dimArr[0];\n        // Not necessary to remove duplicate, because a data\n        // dim canot on more than one coordDim.\n        dataDimsOnCoord = dataDimsOnCoord.concat(dimArr);\n    });\n\n    summary.dataDimsOnCoord = dataDimsOnCoord;\n    summary.encodeFirstDimNotExtra = encodeFirstDimNotExtra;\n\n    var encodeLabel = encode.label;\n    // FIXME `encode.label` is not recommanded, because formatter can not be set\n    // in this way. Use label.formatter instead. May be remove this approach someday.\n    if (encodeLabel && encodeLabel.length) {\n        defaultedLabel = encodeLabel.slice();\n    }\n\n    var encodeTooltip = encode.tooltip;\n    if (encodeTooltip && encodeTooltip.length) {\n        defaultedTooltip = encodeTooltip.slice();\n    }\n    else if (!defaultedTooltip.length) {\n        defaultedTooltip = defaultedLabel.slice();\n    }\n\n    encode.defaultedLabel = defaultedLabel;\n    encode.defaultedTooltip = defaultedTooltip;\n\n    return summary;\n}\n\nfunction getDimensionTypeByAxis(axisType) {\n    return axisType === 'category'\n        ? 'ordinal'\n        : axisType === 'time'\n        ? 'time'\n        : 'float';\n}\n\nfunction mayLabelDimType(dimType) {\n    // In most cases, ordinal and time do not suitable for label.\n    // Ordinal info can be displayed on axis. Time is too long.\n    return !(dimType === 'ordinal' || dimType === 'time');\n}\n\n// function findTheLastDimMayLabel(data) {\n//     // Get last value dim\n//     var dimensions = data.dimensions.slice();\n//     var valueType;\n//     var valueDim;\n//     while (dimensions.length && (\n//         valueDim = dimensions.pop(),\n//         valueType = data.getDimensionInfo(valueDim).type,\n//         valueType === 'ordinal' || valueType === 'time'\n//     )) {} // jshint ignore:line\n//     return valueDim;\n// }\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float64Array, Int32Array, Uint32Array, Uint16Array */\n\n/**\n * List for data storage\n * @module echarts/data/List\n */\n\nvar isObject$4 = isObject$1;\n\nvar UNDEFINED = 'undefined';\nvar INDEX_NOT_FOUND = -1;\n\n// Use prefix to avoid index to be the same as otherIdList[idx],\n// which will cause weird udpate animation.\nvar ID_PREFIX = 'e\\0\\0';\n\nvar dataCtors = {\n    'float': typeof Float64Array === UNDEFINED\n        ? Array : Float64Array,\n    'int': typeof Int32Array === UNDEFINED\n        ? Array : Int32Array,\n    // Ordinal data type can be string or int\n    'ordinal': Array,\n    'number': Array,\n    'time': Array\n};\n\n// Caution: MUST not use `new CtorUint32Array(arr, 0, len)`, because the Ctor of array is\n// different from the Ctor of typed array.\nvar CtorUint32Array = typeof Uint32Array === UNDEFINED ? Array : Uint32Array;\nvar CtorInt32Array = typeof Int32Array === UNDEFINED ? Array : Int32Array;\nvar CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array;\n\nfunction getIndicesCtor(list) {\n    // The possible max value in this._indicies is always this._rawCount despite of filtering.\n    return list._rawCount > 65535 ? CtorUint32Array : CtorUint16Array;\n}\n\nfunction cloneChunk(originalChunk) {\n    var Ctor = originalChunk.constructor;\n    // Only shallow clone is enough when Array.\n    return Ctor === Array ? originalChunk.slice() : new Ctor(originalChunk);\n}\n\nvar TRANSFERABLE_PROPERTIES = [\n    'hasItemOption', '_nameList', '_idList', '_invertedIndicesMap',\n    '_rawData', '_chunkSize', '_chunkCount', '_dimValueGetter',\n    '_count', '_rawCount', '_nameDimIdx', '_idDimIdx'\n];\nvar CLONE_PROPERTIES = [\n    '_extent', '_approximateExtent', '_rawExtent'\n];\n\nfunction transferProperties(target, source) {\n    each$1(TRANSFERABLE_PROPERTIES.concat(source.__wrappedMethods || []), function (propName) {\n        if (source.hasOwnProperty(propName)) {\n            target[propName] = source[propName];\n        }\n    });\n\n    target.__wrappedMethods = source.__wrappedMethods;\n\n    each$1(CLONE_PROPERTIES, function (propName) {\n        target[propName] = clone(source[propName]);\n    });\n\n    target._calculationInfo = extend(source._calculationInfo);\n}\n\n\n\n\n\n/**\n * @constructor\n * @alias module:echarts/data/List\n *\n * @param {Array.<string|Object>} dimensions\n *      For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...].\n *      Dimensions should be concrete names like x, y, z, lng, lat, angle, radius\n *      Spetial fields: {\n *          ordinalMeta: <module:echarts/data/OrdinalMeta>\n *          createInvertedIndices: <boolean>\n *      }\n * @param {module:echarts/model/Model} hostModel\n */\nvar List = function (dimensions, hostModel) {\n\n    dimensions = dimensions || ['x', 'y'];\n\n    var dimensionInfos = {};\n    var dimensionNames = [];\n    var invertedIndicesMap = {};\n\n    for (var i = 0; i < dimensions.length; i++) {\n        // Use the original dimensions[i], where other flag props may exists.\n        var dimensionInfo = dimensions[i];\n\n        if (isString(dimensionInfo)) {\n            dimensionInfo = {name: dimensionInfo};\n        }\n\n        var dimensionName = dimensionInfo.name;\n        dimensionInfo.type = dimensionInfo.type || 'float';\n        if (!dimensionInfo.coordDim) {\n            dimensionInfo.coordDim = dimensionName;\n            dimensionInfo.coordDimIndex = 0;\n        }\n\n        dimensionInfo.otherDims = dimensionInfo.otherDims || {};\n        dimensionNames.push(dimensionName);\n        dimensionInfos[dimensionName] = dimensionInfo;\n\n        dimensionInfo.index = i;\n\n        if (dimensionInfo.createInvertedIndices) {\n            invertedIndicesMap[dimensionName] = [];\n        }\n    }\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    this.dimensions = dimensionNames;\n\n    /**\n     * Infomation of each data dimension, like data type.\n     * @type {Object}\n     */\n    this._dimensionInfos = dimensionInfos;\n\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.hostModel = hostModel;\n\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.dataType;\n\n    /**\n     * Indices stores the indices of data subset after filtered.\n     * This data subset will be used in chart.\n     * @type {Array.<number>}\n     * @readOnly\n     */\n    this._indices = null;\n\n    this._count = 0;\n    this._rawCount = 0;\n\n    /**\n     * Data storage\n     * @type {Object.<key, Array.<TypedArray|Array>>}\n     * @private\n     */\n    this._storage = {};\n\n    /**\n     * @type {Array.<string>}\n     */\n    this._nameList = [];\n    /**\n     * @type {Array.<string>}\n     */\n    this._idList = [];\n\n    /**\n     * Models of data option is stored sparse for optimizing memory cost\n     * @type {Array.<module:echarts/model/Model>}\n     * @private\n     */\n    this._optionModels = [];\n\n    /**\n     * Global visual properties after visual coding\n     * @type {Object}\n     * @private\n     */\n    this._visual = {};\n\n    /**\n     * Globel layout properties.\n     * @type {Object}\n     * @private\n     */\n    this._layout = {};\n\n    /**\n     * Item visual properties after visual coding\n     * @type {Array.<Object>}\n     * @private\n     */\n    this._itemVisuals = [];\n\n    /**\n     * Key: visual type, Value: boolean\n     * @type {Object}\n     * @readOnly\n     */\n    this.hasItemVisual = {};\n\n    /**\n     * Item layout properties after layout\n     * @type {Array.<Object>}\n     * @private\n     */\n    this._itemLayouts = [];\n\n    /**\n     * Graphic elemnents\n     * @type {Array.<module:zrender/Element>}\n     * @private\n     */\n    this._graphicEls = [];\n\n    /**\n     * Max size of each chunk.\n     * @type {number}\n     * @private\n     */\n    this._chunkSize = 1e5;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    this._chunkCount = 0;\n\n    /**\n     * @type {Array.<Array|Object>}\n     * @private\n     */\n    this._rawData;\n\n    /**\n     * Raw extent will not be cloned, but only transfered.\n     * It will not be calculated util needed.\n     * key: dim,\n     * value: {end: number, extent: Array.<number>}\n     * @type {Object}\n     * @private\n     */\n    this._rawExtent = {};\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._extent = {};\n\n    /**\n     * key: dim\n     * value: extent\n     * @type {Object}\n     * @private\n     */\n    this._approximateExtent = {};\n\n    /**\n     * Cache summary info for fast visit. See \"dimensionHelper\".\n     * @type {Object}\n     * @private\n     */\n    this._dimensionsSummary = summarizeDimensions(this);\n\n    /**\n     * @type {Object.<Array|TypedArray>}\n     * @private\n     */\n    this._invertedIndicesMap = invertedIndicesMap;\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._calculationInfo = {};\n};\n\nvar listProto = List.prototype;\n\nlistProto.type = 'list';\n\n/**\n * If each data item has it's own option\n * @type {boolean}\n */\nlistProto.hasItemOption = true;\n\n/**\n * Get dimension name\n * @param {string|number} dim\n *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius\n *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'\n * @return {string} Concrete dim name.\n */\nlistProto.getDimension = function (dim) {\n    if (!isNaN(dim)) {\n        dim = this.dimensions[dim] || dim;\n    }\n    return dim;\n};\n\n/**\n * Get type and calculation info of particular dimension\n * @param {string|number} dim\n *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius\n *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'\n */\nlistProto.getDimensionInfo = function (dim) {\n    // Do not clone, because there may be categories in dimInfo.\n    return this._dimensionInfos[this.getDimension(dim)];\n};\n\n/**\n * @return {Array.<string>} concrete dimension name list on coord.\n */\nlistProto.getDimensionsOnCoord = function () {\n    return this._dimensionsSummary.dataDimsOnCoord.slice();\n};\n\n/**\n * @param {string} coordDim\n * @param {number} [idx] A coordDim may map to more than one data dim.\n *        If idx is `true`, return a array of all mapped dims.\n *        If idx is not specified, return the first dim not extra.\n * @return {string|Array.<string>} concrete data dim.\n *        If idx is number, and not found, return null/undefined.\n *        If idx is `true`, and not found, return empty array (always return array).\n */\nlistProto.mapDimension = function (coordDim, idx) {\n    var dimensionsSummary = this._dimensionsSummary;\n\n    if (idx == null) {\n        return dimensionsSummary.encodeFirstDimNotExtra[coordDim];\n    }\n\n    var dims = dimensionsSummary.encode[coordDim];\n    return idx === true\n        // always return array if idx is `true`\n        ? (dims || []).slice()\n        : (dims && dims[idx]);\n};\n\n/**\n * Initialize from data\n * @param {Array.<Object|number|Array>} data source or data or data provider.\n * @param {Array.<string>} [nameLIst] The name of a datum is used on data diff and\n *        defualt label/tooltip.\n *        A name can be specified in encode.itemName,\n *        or dataItem.name (only for series option data),\n *        or provided in nameList from outside.\n * @param {Function} [dimValueGetter] (dataItem, dimName, dataIndex, dimIndex) => number\n */\nlistProto.initData = function (data, nameList, dimValueGetter) {\n\n    var notProvider = Source.isInstance(data) || isArrayLike(data);\n    if (notProvider) {\n        data = new DefaultDataProvider(data, this.dimensions.length);\n    }\n\n    if (__DEV__) {\n        if (!notProvider && (typeof data.getItem !== 'function' || typeof data.count !== 'function')) {\n            throw new Error('Inavlid data provider.');\n        }\n    }\n\n    this._rawData = data;\n\n    // Clear\n    this._storage = {};\n    this._indices = null;\n\n    this._nameList = nameList || [];\n\n    this._idList = [];\n\n    this._nameRepeatCount = {};\n\n    if (!dimValueGetter) {\n        this.hasItemOption = false;\n    }\n\n    /**\n     * @readOnly\n     */\n    this.defaultDimValueGetter = defaultDimValueGetters[\n        this._rawData.getSource().sourceFormat\n    ];\n    // Default dim value getter\n    this._dimValueGetter = dimValueGetter = dimValueGetter\n        || this.defaultDimValueGetter;\n    this._dimValueGetterArrayRows = defaultDimValueGetters.arrayRows;\n\n    // Reset raw extent.\n    this._rawExtent = {};\n\n    this._initDataFromProvider(0, data.count());\n\n    // If data has no item option.\n    if (data.pure) {\n        this.hasItemOption = false;\n    }\n};\n\nlistProto.getProvider = function () {\n    return this._rawData;\n};\n\n/**\n * Caution: Can be only called on raw data (before `this._indices` created).\n */\nlistProto.appendData = function (data) {\n    if (__DEV__) {\n        assert$1(!this._indices, 'appendData can only be called on raw data.');\n    }\n\n    var rawData = this._rawData;\n    var start = this.count();\n    rawData.appendData(data);\n    var end = rawData.count();\n    if (!rawData.persistent) {\n        end += start;\n    }\n    this._initDataFromProvider(start, end);\n};\n\n/**\n * Caution: Can be only called on raw data (before `this._indices` created).\n * This method does not modify `rawData` (`dataProvider`), but only\n * add values to storage.\n *\n * The final count will be increased by `Math.max(values.length, names.length)`.\n *\n * @param {Array.<Array.<*>>} values That is the SourceType: 'arrayRows', like\n *        [\n *            [12, 33, 44],\n *            [NaN, 43, 1],\n *            ['-', 'asdf', 0]\n *        ]\n *        Each item is exaclty cooresponding to a dimension.\n * @param {Array.<string>} [names]\n */\nlistProto.appendValues = function (values, names) {\n    var chunkSize = this._chunkSize;\n    var storage = this._storage;\n    var dimensions = this.dimensions;\n    var dimLen = dimensions.length;\n    var rawExtent = this._rawExtent;\n\n    var start = this.count();\n    var end = start + Math.max(values.length, names ? names.length : 0);\n    var originalChunkCount = this._chunkCount;\n\n    for (var i = 0; i < dimLen; i++) {\n        var dim = dimensions[i];\n        if (!rawExtent[dim]) {\n            rawExtent[dim] = getInitialExtent();\n        }\n        if (!storage[dim]) {\n            storage[dim] = [];\n        }\n        prepareChunks(storage, this._dimensionInfos[dim], chunkSize, originalChunkCount, end);\n        this._chunkCount = storage[dim].length;\n    }\n\n    var emptyDataItem = new Array(dimLen);\n    for (var idx = start; idx < end; idx++) {\n        var sourceIdx = idx - start;\n        var chunkIndex = Math.floor(idx / chunkSize);\n        var chunkOffset = idx % chunkSize;\n\n        // Store the data by dimensions\n        for (var k = 0; k < dimLen; k++) {\n            var dim = dimensions[k];\n            var val = this._dimValueGetterArrayRows(\n                values[sourceIdx] || emptyDataItem, dim, sourceIdx, k\n            );\n            storage[dim][chunkIndex][chunkOffset] = val;\n\n            var dimRawExtent = rawExtent[dim];\n            val < dimRawExtent[0] && (dimRawExtent[0] = val);\n            val > dimRawExtent[1] && (dimRawExtent[1] = val);\n        }\n\n        if (names) {\n            this._nameList[idx] = names[sourceIdx];\n        }\n    }\n\n    this._rawCount = this._count = end;\n\n    // Reset data extent\n    this._extent = {};\n\n    prepareInvertedIndex(this);\n};\n\nlistProto._initDataFromProvider = function (start, end) {\n    // Optimize.\n    if (start >= end) {\n        return;\n    }\n\n    var chunkSize = this._chunkSize;\n    var rawData = this._rawData;\n    var storage = this._storage;\n    var dimensions = this.dimensions;\n    var dimLen = dimensions.length;\n    var dimensionInfoMap = this._dimensionInfos;\n    var nameList = this._nameList;\n    var idList = this._idList;\n    var rawExtent = this._rawExtent;\n    var nameRepeatCount = this._nameRepeatCount = {};\n    var nameDimIdx;\n\n    var originalChunkCount = this._chunkCount;\n    for (var i = 0; i < dimLen; i++) {\n        var dim = dimensions[i];\n        if (!rawExtent[dim]) {\n            rawExtent[dim] = getInitialExtent();\n        }\n\n        var dimInfo = dimensionInfoMap[dim];\n        if (dimInfo.otherDims.itemName === 0) {\n            nameDimIdx = this._nameDimIdx = i;\n        }\n        if (dimInfo.otherDims.itemId === 0) {\n            this._idDimIdx = i;\n        }\n\n        if (!storage[dim]) {\n            storage[dim] = [];\n        }\n\n        prepareChunks(storage, dimInfo, chunkSize, originalChunkCount, end);\n\n        this._chunkCount = storage[dim].length;\n    }\n\n    var dataItem = new Array(dimLen);\n    for (var idx = start; idx < end; idx++) {\n        // NOTICE: Try not to write things into dataItem\n        dataItem = rawData.getItem(idx, dataItem);\n        // Each data item is value\n        // [1, 2]\n        // 2\n        // Bar chart, line chart which uses category axis\n        // only gives the 'y' value. 'x' value is the indices of category\n        // Use a tempValue to normalize the value to be a (x, y) value\n        var chunkIndex = Math.floor(idx / chunkSize);\n        var chunkOffset = idx % chunkSize;\n\n        // Store the data by dimensions\n        for (var k = 0; k < dimLen; k++) {\n            var dim = dimensions[k];\n            var dimStorage = storage[dim][chunkIndex];\n            // PENDING NULL is empty or zero\n            var val = this._dimValueGetter(dataItem, dim, idx, k);\n            dimStorage[chunkOffset] = val;\n\n            var dimRawExtent = rawExtent[dim];\n            val < dimRawExtent[0] && (dimRawExtent[0] = val);\n            val > dimRawExtent[1] && (dimRawExtent[1] = val);\n        }\n\n        // ??? FIXME not check by pure but sourceFormat?\n        // TODO refactor these logic.\n        if (!rawData.pure) {\n            var name = nameList[idx];\n\n            if (dataItem && name == null) {\n                // If dataItem is {name: ...}, it has highest priority.\n                // That is appropriate for many common cases.\n                if (dataItem.name != null) {\n                    // There is no other place to persistent dataItem.name,\n                    // so save it to nameList.\n                    nameList[idx] = name = dataItem.name;\n                }\n                else if (nameDimIdx != null) {\n                    var nameDim = dimensions[nameDimIdx];\n                    var nameDimChunk = storage[nameDim][chunkIndex];\n                    if (nameDimChunk) {\n                        name = nameDimChunk[chunkOffset];\n                        var ordinalMeta = dimensionInfoMap[nameDim].ordinalMeta;\n                        if (ordinalMeta && ordinalMeta.categories.length) {\n                            name = ordinalMeta.categories[name];\n                        }\n                    }\n                }\n            }\n\n            // Try using the id in option\n            // id or name is used on dynamical data, mapping old and new items.\n            var id = dataItem == null ? null : dataItem.id;\n\n            if (id == null && name != null) {\n                // Use name as id and add counter to avoid same name\n                nameRepeatCount[name] = nameRepeatCount[name] || 0;\n                id = name;\n                if (nameRepeatCount[name] > 0) {\n                    id += '__ec__' + nameRepeatCount[name];\n                }\n                nameRepeatCount[name]++;\n            }\n            id != null && (idList[idx] = id);\n        }\n    }\n\n    if (!rawData.persistent && rawData.clean) {\n        // Clean unused data if data source is typed array.\n        rawData.clean();\n    }\n\n    this._rawCount = this._count = end;\n\n    // Reset data extent\n    this._extent = {};\n\n    prepareInvertedIndex(this);\n};\n\nfunction prepareChunks(storage, dimInfo, chunkSize, chunkCount, end) {\n    var DataCtor = dataCtors[dimInfo.type];\n    var lastChunkIndex = chunkCount - 1;\n    var dim = dimInfo.name;\n    var resizeChunkArray = storage[dim][lastChunkIndex];\n    if (resizeChunkArray && resizeChunkArray.length < chunkSize) {\n        var newStore = new DataCtor(Math.min(end - lastChunkIndex * chunkSize, chunkSize));\n        // The cost of the copy is probably inconsiderable\n        // within the initial chunkSize.\n        for (var j = 0; j < resizeChunkArray.length; j++) {\n            newStore[j] = resizeChunkArray[j];\n        }\n        storage[dim][lastChunkIndex] = newStore;\n    }\n\n    // Create new chunks.\n    for (var k = chunkCount * chunkSize; k < end; k += chunkSize) {\n        storage[dim].push(new DataCtor(Math.min(end - k, chunkSize)));\n    }\n}\n\nfunction prepareInvertedIndex(list) {\n    var invertedIndicesMap = list._invertedIndicesMap;\n    each$1(invertedIndicesMap, function (invertedIndices, dim) {\n        var dimInfo = list._dimensionInfos[dim];\n\n        // Currently, only dimensions that has ordinalMeta can create inverted indices.\n        var ordinalMeta = dimInfo.ordinalMeta;\n        if (ordinalMeta) {\n            invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array(\n                ordinalMeta.categories.length\n            );\n            // The default value of TypedArray is 0. To avoid miss\n            // mapping to 0, we should set it as INDEX_NOT_FOUND.\n            for (var i = 0; i < invertedIndices.length; i++) {\n                invertedIndices[i] = INDEX_NOT_FOUND;\n            }\n            for (var i = 0; i < list._count; i++) {\n                // Only support the case that all values are distinct.\n                invertedIndices[list.get(dim, i)] = i;\n            }\n        }\n    });\n}\n\nfunction getRawValueFromStore(list, dimIndex, rawIndex) {\n    var val;\n    if (dimIndex != null) {\n        var chunkSize = list._chunkSize;\n        var chunkIndex = Math.floor(rawIndex / chunkSize);\n        var chunkOffset = rawIndex % chunkSize;\n        var dim = list.dimensions[dimIndex];\n        var chunk = list._storage[dim][chunkIndex];\n        if (chunk) {\n            val = chunk[chunkOffset];\n            var ordinalMeta = list._dimensionInfos[dim].ordinalMeta;\n            if (ordinalMeta && ordinalMeta.categories.length) {\n                val = ordinalMeta.categories[val];\n            }\n        }\n    }\n    return val;\n}\n\n/**\n * @return {number}\n */\nlistProto.count = function () {\n    return this._count;\n};\n\nlistProto.getIndices = function () {\n    var newIndices;\n\n    var indices = this._indices;\n    if (indices) {\n        var Ctor = indices.constructor;\n        var thisCount = this._count;\n        // `new Array(a, b, c)` is different from `new Uint32Array(a, b, c)`.\n        if (Ctor === Array) {\n            newIndices = new Ctor(thisCount);\n            for (var i = 0; i < thisCount; i++) {\n                newIndices[i] = indices[i];\n            }\n        }\n        else {\n            newIndices = new Ctor(indices.buffer, 0, thisCount);\n        }\n    }\n    else {\n        var Ctor = getIndicesCtor(this);\n        var newIndices = new Ctor(this.count());\n        for (var i = 0; i < newIndices.length; i++) {\n            newIndices[i] = i;\n        }\n    }\n\n    return newIndices;\n};\n\n/**\n * Get value. Return NaN if idx is out of range.\n * @param {string} dim Dim must be concrete name.\n * @param {number} idx\n * @param {boolean} stack\n * @return {number}\n */\nlistProto.get = function (dim, idx /*, stack */) {\n    if (!(idx >= 0 && idx < this._count)) {\n        return NaN;\n    }\n    var storage = this._storage;\n    if (!storage[dim]) {\n        // TODO Warn ?\n        return NaN;\n    }\n\n    idx = this.getRawIndex(idx);\n\n    var chunkIndex = Math.floor(idx / this._chunkSize);\n    var chunkOffset = idx % this._chunkSize;\n\n    var chunkStore = storage[dim][chunkIndex];\n    var value = chunkStore[chunkOffset];\n    // FIXME ordinal data type is not stackable\n    // if (stack) {\n    //     var dimensionInfo = this._dimensionInfos[dim];\n    //     if (dimensionInfo && dimensionInfo.stackable) {\n    //         var stackedOn = this.stackedOn;\n    //         while (stackedOn) {\n    //             // Get no stacked data of stacked on\n    //             var stackedValue = stackedOn.get(dim, idx);\n    //             // Considering positive stack, negative stack and empty data\n    //             if ((value >= 0 && stackedValue > 0)  // Positive stack\n    //                 || (value <= 0 && stackedValue < 0) // Negative stack\n    //             ) {\n    //                 value += stackedValue;\n    //             }\n    //             stackedOn = stackedOn.stackedOn;\n    //         }\n    //     }\n    // }\n\n    return value;\n};\n\n/**\n * @param {string} dim concrete dim\n * @param {number} rawIndex\n * @return {number|string}\n */\nlistProto.getByRawIndex = function (dim, rawIdx) {\n    if (!(rawIdx >= 0 && rawIdx < this._rawCount)) {\n        return NaN;\n    }\n    var dimStore = this._storage[dim];\n    if (!dimStore) {\n        // TODO Warn ?\n        return NaN;\n    }\n\n    var chunkIndex = Math.floor(rawIdx / this._chunkSize);\n    var chunkOffset = rawIdx % this._chunkSize;\n    var chunkStore = dimStore[chunkIndex];\n    return chunkStore[chunkOffset];\n};\n\n/**\n * FIXME Use `get` on chrome maybe slow(in filterSelf and selectRange).\n * Hack a much simpler _getFast\n * @private\n */\nlistProto._getFast = function (dim, rawIdx) {\n    var chunkIndex = Math.floor(rawIdx / this._chunkSize);\n    var chunkOffset = rawIdx % this._chunkSize;\n    var chunkStore = this._storage[dim][chunkIndex];\n    return chunkStore[chunkOffset];\n};\n\n/**\n * Get value for multi dimensions.\n * @param {Array.<string>} [dimensions] If ignored, using all dimensions.\n * @param {number} idx\n * @return {number}\n */\nlistProto.getValues = function (dimensions, idx /*, stack */) {\n    var values = [];\n\n    if (!isArray(dimensions)) {\n        // stack = idx;\n        idx = dimensions;\n        dimensions = this.dimensions;\n    }\n\n    for (var i = 0, len = dimensions.length; i < len; i++) {\n        values.push(this.get(dimensions[i], idx /*, stack */));\n    }\n\n    return values;\n};\n\n/**\n * If value is NaN. Inlcuding '-'\n * Only check the coord dimensions.\n * @param {string} dim\n * @param {number} idx\n * @return {number}\n */\nlistProto.hasValue = function (idx) {\n    var dataDimsOnCoord = this._dimensionsSummary.dataDimsOnCoord;\n    var dimensionInfos = this._dimensionInfos;\n    for (var i = 0, len = dataDimsOnCoord.length; i < len; i++) {\n        if (\n            // Ordinal type can be string or number\n            dimensionInfos[dataDimsOnCoord[i]].type !== 'ordinal'\n            // FIXME check ordinal when using index?\n            && isNaN(this.get(dataDimsOnCoord[i], idx))\n        ) {\n            return false;\n        }\n    }\n    return true;\n};\n\n/**\n * Get extent of data in one dimension\n * @param {string} dim\n * @param {boolean} stack\n */\nlistProto.getDataExtent = function (dim /*, stack */) {\n    // Make sure use concrete dim as cache name.\n    dim = this.getDimension(dim);\n    var dimData = this._storage[dim];\n    var initialExtent = getInitialExtent();\n\n    // stack = !!((stack || false) && this.getCalculationInfo(dim));\n\n    if (!dimData) {\n        return initialExtent;\n    }\n\n    // Make more strict checkings to ensure hitting cache.\n    var currEnd = this.count();\n    // var cacheName = [dim, !!stack].join('_');\n    // var cacheName = dim;\n\n    // Consider the most cases when using data zoom, `getDataExtent`\n    // happened before filtering. We cache raw extent, which is not\n    // necessary to be cleared and recalculated when restore data.\n    var useRaw = !this._indices; // && !stack;\n    var dimExtent;\n\n    if (useRaw) {\n        return this._rawExtent[dim].slice();\n    }\n    dimExtent = this._extent[dim];\n    if (dimExtent) {\n        return dimExtent.slice();\n    }\n    dimExtent = initialExtent;\n\n    var min = dimExtent[0];\n    var max = dimExtent[1];\n\n    for (var i = 0; i < currEnd; i++) {\n        // var value = stack ? this.get(dim, i, true) : this._getFast(dim, this.getRawIndex(i));\n        var value = this._getFast(dim, this.getRawIndex(i));\n        value < min && (min = value);\n        value > max && (max = value);\n    }\n\n    dimExtent = [min, max];\n\n    this._extent[dim] = dimExtent;\n\n    return dimExtent;\n};\n\n/**\n * Optimize for the scenario that data is filtered by a given extent.\n * Consider that if data amount is more than hundreds of thousand,\n * extent calculation will cost more than 10ms and the cache will\n * be erased because of the filtering.\n */\nlistProto.getApproximateExtent = function (dim /*, stack */) {\n    dim = this.getDimension(dim);\n    return this._approximateExtent[dim] || this.getDataExtent(dim /*, stack */);\n};\n\nlistProto.setApproximateExtent = function (extent, dim /*, stack */) {\n    dim = this.getDimension(dim);\n    this._approximateExtent[dim] = extent.slice();\n};\n\n/**\n * @param {string} key\n * @return {*}\n */\nlistProto.getCalculationInfo = function (key) {\n    return this._calculationInfo[key];\n};\n\n/**\n * @param {string|Object} key or k-v object\n * @param {*} [value]\n */\nlistProto.setCalculationInfo = function (key, value) {\n    isObject$4(key)\n        ? extend(this._calculationInfo, key)\n        : (this._calculationInfo[key] = value);\n};\n\n/**\n * Get sum of data in one dimension\n * @param {string} dim\n */\nlistProto.getSum = function (dim /*, stack */) {\n    var dimData = this._storage[dim];\n    var sum = 0;\n    if (dimData) {\n        for (var i = 0, len = this.count(); i < len; i++) {\n            var value = this.get(dim, i /*, stack */);\n            if (!isNaN(value)) {\n                sum += value;\n            }\n        }\n    }\n    return sum;\n};\n\n/**\n * Get median of data in one dimension\n * @param {string} dim\n */\nlistProto.getMedian = function (dim /*, stack */) {\n    var dimDataArray = [];\n    // map all data of one dimension\n    this.each(dim, function (val, idx) {\n        if (!isNaN(val)) {\n            dimDataArray.push(val);\n        }\n    });\n\n    // TODO\n    // Use quick select?\n\n    // immutability & sort\n    var sortedDimDataArray = [].concat(dimDataArray).sort(function (a, b) {\n        return a - b;\n    });\n    var len = this.count();\n    // calculate median\n    return len === 0\n        ? 0\n        : len % 2 === 1\n        ? sortedDimDataArray[(len - 1) / 2]\n        : (sortedDimDataArray[len / 2] + sortedDimDataArray[len / 2 - 1]) / 2;\n};\n\n// /**\n//  * Retreive the index with given value\n//  * @param {string} dim Concrete dimension.\n//  * @param {number} value\n//  * @return {number}\n//  */\n// Currently incorrect: should return dataIndex but not rawIndex.\n// Do not fix it until this method is to be used somewhere.\n// FIXME Precision of float value\n// listProto.indexOf = function (dim, value) {\n//     var storage = this._storage;\n//     var dimData = storage[dim];\n//     var chunkSize = this._chunkSize;\n//     if (dimData) {\n//         for (var i = 0, len = this.count(); i < len; i++) {\n//             var chunkIndex = Math.floor(i / chunkSize);\n//             var chunkOffset = i % chunkSize;\n//             if (dimData[chunkIndex][chunkOffset] === value) {\n//                 return i;\n//             }\n//         }\n//     }\n//     return -1;\n// };\n\n/**\n * Only support the dimension which inverted index created.\n * Do not support other cases until required.\n * @param {string} concrete dim\n * @param {number|string} value\n * @return {number} rawIndex\n */\nlistProto.rawIndexOf = function (dim, value) {\n    var invertedIndices = dim && this._invertedIndicesMap[dim];\n    if (__DEV__) {\n        if (!invertedIndices) {\n            throw new Error('Do not supported yet');\n        }\n    }\n    var rawIndex = invertedIndices[value];\n    if (rawIndex == null || isNaN(rawIndex)) {\n        return INDEX_NOT_FOUND;\n    }\n    return rawIndex;\n};\n\n/**\n * Retreive the index with given name\n * @param {number} idx\n * @param {number} name\n * @return {number}\n */\nlistProto.indexOfName = function (name) {\n    for (var i = 0, len = this.count(); i < len; i++) {\n        if (this.getName(i) === name) {\n            return i;\n        }\n    }\n\n    return -1;\n};\n\n/**\n * Retreive the index with given raw data index\n * @param {number} idx\n * @param {number} name\n * @return {number}\n */\nlistProto.indexOfRawIndex = function (rawIndex) {\n    if (!this._indices) {\n        return rawIndex;\n    }\n\n    if (rawIndex >= this._rawCount || rawIndex < 0) {\n        return -1;\n    }\n\n    // Indices are ascending\n    var indices = this._indices;\n\n    // If rawIndex === dataIndex\n    var rawDataIndex = indices[rawIndex];\n    if (rawDataIndex != null && rawDataIndex < this._count && rawDataIndex === rawIndex) {\n        return rawIndex;\n    }\n\n    var left = 0;\n    var right = this._count - 1;\n    while (left <= right) {\n        var mid = (left + right) / 2 | 0;\n        if (indices[mid] < rawIndex) {\n            left = mid + 1;\n        }\n        else if (indices[mid] > rawIndex) {\n            right = mid - 1;\n        }\n        else {\n            return mid;\n        }\n    }\n    return -1;\n};\n\n/**\n * Retreive the index of nearest value\n * @param {string} dim\n * @param {number} value\n * @param {number} [maxDistance=Infinity]\n * @return {Array.<number>} Considere multiple points has the same value.\n */\nlistProto.indicesOfNearest = function (dim, value, maxDistance) {\n    var storage = this._storage;\n    var dimData = storage[dim];\n    var nearestIndices = [];\n\n    if (!dimData) {\n        return nearestIndices;\n    }\n\n    if (maxDistance == null) {\n        maxDistance = Infinity;\n    }\n\n    var minDist = Number.MAX_VALUE;\n    var minDiff = -1;\n    for (var i = 0, len = this.count(); i < len; i++) {\n        var diff = value - this.get(dim, i /*, stack */);\n        var dist = Math.abs(diff);\n        if (diff <= maxDistance && dist <= minDist) {\n            // For the case of two data are same on xAxis, which has sequence data.\n            // Show the nearest index\n            // https://github.com/ecomfe/echarts/issues/2869\n            if (dist < minDist || (diff >= 0 && minDiff < 0)) {\n                minDist = dist;\n                minDiff = diff;\n                nearestIndices.length = 0;\n            }\n            nearestIndices.push(i);\n        }\n    }\n    return nearestIndices;\n};\n\n/**\n * Get raw data index\n * @param {number} idx\n * @return {number}\n */\nlistProto.getRawIndex = getRawIndexWithoutIndices;\n\nfunction getRawIndexWithoutIndices(idx) {\n    return idx;\n}\n\nfunction getRawIndexWithIndices(idx) {\n    if (idx < this._count && idx >= 0) {\n        return this._indices[idx];\n    }\n    return -1;\n}\n\n/**\n * Get raw data item\n * @param {number} idx\n * @return {number}\n */\nlistProto.getRawDataItem = function (idx) {\n    if (!this._rawData.persistent) {\n        var val = [];\n        for (var i = 0; i < this.dimensions.length; i++) {\n            var dim = this.dimensions[i];\n            val.push(this.get(dim, idx));\n        }\n        return val;\n    }\n    else {\n        return this._rawData.getItem(this.getRawIndex(idx));\n    }\n};\n\n/**\n * @param {number} idx\n * @param {boolean} [notDefaultIdx=false]\n * @return {string}\n */\nlistProto.getName = function (idx) {\n    var rawIndex = this.getRawIndex(idx);\n    return this._nameList[rawIndex]\n        || getRawValueFromStore(this, this._nameDimIdx, rawIndex)\n        || '';\n};\n\n/**\n * @param {number} idx\n * @param {boolean} [notDefaultIdx=false]\n * @return {string}\n */\nlistProto.getId = function (idx) {\n    return getId(this, this.getRawIndex(idx));\n};\n\nfunction getId(list, rawIndex) {\n    var id = list._idList[rawIndex];\n    if (id == null) {\n        id = getRawValueFromStore(list, list._idDimIdx, rawIndex);\n    }\n    if (id == null) {\n        // FIXME Check the usage in graph, should not use prefix.\n        id = ID_PREFIX + rawIndex;\n    }\n    return id;\n}\n\nfunction normalizeDimensions(dimensions) {\n    if (!isArray(dimensions)) {\n        dimensions = [dimensions];\n    }\n    return dimensions;\n}\n\nfunction validateDimensions(list, dims) {\n    for (var i = 0; i < dims.length; i++) {\n        // stroage may be empty when no data, so use\n        // dimensionInfos to check.\n        if (!list._dimensionInfos[dims[i]]) {\n            console.error('Unkown dimension ' + dims[i]);\n        }\n    }\n}\n\n/**\n * Data iteration\n * @param {string|Array.<string>}\n * @param {Function} cb\n * @param {*} [context=this]\n *\n * @example\n *  list.each('x', function (x, idx) {});\n *  list.each(['x', 'y'], function (x, y, idx) {});\n *  list.each(function (idx) {})\n */\nlistProto.each = function (dims, cb, context, contextCompat) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    if (typeof dims === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dims;\n        dims = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dims = map(normalizeDimensions(dims), this.getDimension, this);\n\n    if (__DEV__) {\n        validateDimensions(this, dims);\n    }\n\n    var dimSize = dims.length;\n\n    for (var i = 0; i < this.count(); i++) {\n        // Simple optimization\n        switch (dimSize) {\n            case 0:\n                cb.call(context, i);\n                break;\n            case 1:\n                cb.call(context, this.get(dims[0], i), i);\n                break;\n            case 2:\n                cb.call(context, this.get(dims[0], i), this.get(dims[1], i), i);\n                break;\n            default:\n                var k = 0;\n                var value = [];\n                for (; k < dimSize; k++) {\n                    value[k] = this.get(dims[k], i);\n                }\n                // Index\n                value[k] = i;\n                cb.apply(context, value);\n        }\n    }\n};\n\n/**\n * Data filter\n * @param {string|Array.<string>}\n * @param {Function} cb\n * @param {*} [context=this]\n */\nlistProto.filterSelf = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    if (typeof dimensions === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dimensions;\n        dimensions = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dimensions = map(\n        normalizeDimensions(dimensions), this.getDimension, this\n    );\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n\n    var count = this.count();\n    var Ctor = getIndicesCtor(this);\n    var newIndices = new Ctor(count);\n    var value = [];\n    var dimSize = dimensions.length;\n\n    var offset = 0;\n    var dim0 = dimensions[0];\n\n    for (var i = 0; i < count; i++) {\n        var keep;\n        var rawIdx = this.getRawIndex(i);\n        // Simple optimization\n        if (dimSize === 0) {\n            keep = cb.call(context, i);\n        }\n        else if (dimSize === 1) {\n            var val = this._getFast(dim0, rawIdx);\n            keep = cb.call(context, val, i);\n        }\n        else {\n            for (var k = 0; k < dimSize; k++) {\n                value[k] = this._getFast(dim0, rawIdx);\n            }\n            value[k] = i;\n            keep = cb.apply(context, value);\n        }\n        if (keep) {\n            newIndices[offset++] = rawIdx;\n        }\n    }\n\n    // Set indices after filtered.\n    if (offset < count) {\n        this._indices = newIndices;\n    }\n    this._count = offset;\n    // Reset data extent\n    this._extent = {};\n\n    this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return this;\n};\n\n/**\n * Select data in range. (For optimization of filter)\n * (Manually inline code, support 5 million data filtering in data zoom.)\n */\nlistProto.selectRange = function (range) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    var dimensions = [];\n    for (var dim in range) {\n        if (range.hasOwnProperty(dim)) {\n            dimensions.push(dim);\n        }\n    }\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n    var dimSize = dimensions.length;\n    if (!dimSize) {\n        return;\n    }\n\n    var originalCount = this.count();\n    var Ctor = getIndicesCtor(this);\n    var newIndices = new Ctor(originalCount);\n\n    var offset = 0;\n    var dim0 = dimensions[0];\n\n    var min = range[dim0][0];\n    var max = range[dim0][1];\n\n    var quickFinished = false;\n    if (!this._indices) {\n        // Extreme optimization for common case. About 2x faster in chrome.\n        var idx = 0;\n        if (dimSize === 1) {\n            var dimStorage = this._storage[dimensions[0]];\n            for (var k = 0; k < this._chunkCount; k++) {\n                var chunkStorage = dimStorage[k];\n                var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);\n                for (var i = 0; i < len; i++) {\n                    var val = chunkStorage[i];\n                    // NaN will not be filtered. Consider the case, in line chart, empty\n                    // value indicates the line should be broken. But for the case like\n                    // scatter plot, a data item with empty value will not be rendered,\n                    // but the axis extent may be effected if some other dim of the data\n                    // item has value. Fortunately it is not a significant negative effect.\n                    if (\n                        (val >= min && val <= max) || isNaN(val)\n                    ) {\n                        newIndices[offset++] = idx;\n                    }\n                    idx++;\n                }\n            }\n            quickFinished = true;\n        }\n        else if (dimSize === 2) {\n            var dimStorage = this._storage[dim0];\n            var dimStorage2 = this._storage[dimensions[1]];\n            var min2 = range[dimensions[1]][0];\n            var max2 = range[dimensions[1]][1];\n            for (var k = 0; k < this._chunkCount; k++) {\n                var chunkStorage = dimStorage[k];\n                var chunkStorage2 = dimStorage2[k];\n                var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);\n                for (var i = 0; i < len; i++) {\n                    var val = chunkStorage[i];\n                    var val2 = chunkStorage2[i];\n                    // Do not filter NaN, see comment above.\n                    if ((\n                            (val >= min && val <= max) || isNaN(val)\n                        )\n                        && (\n                            (val2 >= min2 && val2 <= max2) || isNaN(val2)\n                        )\n                    ) {\n                        newIndices[offset++] = idx;\n                    }\n                    idx++;\n                }\n            }\n            quickFinished = true;\n        }\n    }\n    if (!quickFinished) {\n        if (dimSize === 1) {\n            for (var i = 0; i < originalCount; i++) {\n                var rawIndex = this.getRawIndex(i);\n                var val = this._getFast(dim0, rawIndex);\n                // Do not filter NaN, see comment above.\n                if (\n                    (val >= min && val <= max) || isNaN(val)\n                ) {\n                    newIndices[offset++] = rawIndex;\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < originalCount; i++) {\n                var keep = true;\n                var rawIndex = this.getRawIndex(i);\n                for (var k = 0; k < dimSize; k++) {\n                    var dimk = dimensions[k];\n                    var val = this._getFast(dim, rawIndex);\n                    // Do not filter NaN, see comment above.\n                    if (val < range[dimk][0] || val > range[dimk][1]) {\n                        keep = false;\n                    }\n                }\n                if (keep) {\n                    newIndices[offset++] = this.getRawIndex(i);\n                }\n            }\n        }\n    }\n\n    // Set indices after filtered.\n    if (offset < originalCount) {\n        this._indices = newIndices;\n    }\n    this._count = offset;\n    // Reset data extent\n    this._extent = {};\n\n    this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return this;\n};\n\n/**\n * Data mapping to a plain array\n * @param {string|Array.<string>} [dimensions]\n * @param {Function} cb\n * @param {*} [context=this]\n * @return {Array}\n */\nlistProto.mapArray = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    if (typeof dimensions === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dimensions;\n        dimensions = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    var result = [];\n    this.each(dimensions, function () {\n        result.push(cb && cb.apply(this, arguments));\n    }, context);\n    return result;\n};\n\n// Data in excludeDimensions is copied, otherwise transfered.\nfunction cloneListForMapAndSample(original, excludeDimensions) {\n    var allDimensions = original.dimensions;\n    var list = new List(\n        map(allDimensions, original.getDimensionInfo, original),\n        original.hostModel\n    );\n    // FIXME If needs stackedOn, value may already been stacked\n    transferProperties(list, original);\n\n    var storage = list._storage = {};\n    var originalStorage = original._storage;\n\n    // Init storage\n    for (var i = 0; i < allDimensions.length; i++) {\n        var dim = allDimensions[i];\n        if (originalStorage[dim]) {\n            // Notice that we do not reset invertedIndicesMap here, becuase\n            // there is no scenario of mapping or sampling ordinal dimension.\n            if (indexOf(excludeDimensions, dim) >= 0) {\n                storage[dim] = cloneDimStore(originalStorage[dim]);\n                list._rawExtent[dim] = getInitialExtent();\n                list._extent[dim] = null;\n            }\n            else {\n                // Direct reference for other dimensions\n                storage[dim] = originalStorage[dim];\n            }\n        }\n    }\n    return list;\n}\n\nfunction cloneDimStore(originalDimStore) {\n    var newDimStore = new Array(originalDimStore.length);\n    for (var j = 0; j < originalDimStore.length; j++) {\n        newDimStore[j] = cloneChunk(originalDimStore[j]);\n    }\n    return newDimStore;\n}\n\nfunction getInitialExtent() {\n    return [Infinity, -Infinity];\n}\n\n/**\n * Data mapping to a new List with given dimensions\n * @param {string|Array.<string>} dimensions\n * @param {Function} cb\n * @param {*} [context=this]\n * @return {Array}\n */\nlistProto.map = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dimensions = map(\n        normalizeDimensions(dimensions), this.getDimension, this\n    );\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n    var list = cloneListForMapAndSample(this, dimensions);\n\n    // Following properties are all immutable.\n    // So we can reference to the same value\n    list._indices = this._indices;\n    list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    var storage = list._storage;\n\n    var tmpRetValue = [];\n    var chunkSize = this._chunkSize;\n    var dimSize = dimensions.length;\n    var dataCount = this.count();\n    var values = [];\n    var rawExtent = list._rawExtent;\n\n    for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) {\n        for (var dimIndex = 0; dimIndex < dimSize; dimIndex++) {\n            values[dimIndex] = this.get(dimensions[dimIndex], dataIndex /*, stack */);\n        }\n        values[dimSize] = dataIndex;\n\n        var retValue = cb && cb.apply(context, values);\n        if (retValue != null) {\n            // a number or string (in oridinal dimension)?\n            if (typeof retValue !== 'object') {\n                tmpRetValue[0] = retValue;\n                retValue = tmpRetValue;\n            }\n\n            var rawIndex = this.getRawIndex(dataIndex);\n            var chunkIndex = Math.floor(rawIndex / chunkSize);\n            var chunkOffset = rawIndex % chunkSize;\n\n            for (var i = 0; i < retValue.length; i++) {\n                var dim = dimensions[i];\n                var val = retValue[i];\n                var rawExtentOnDim = rawExtent[dim];\n\n                var dimStore = storage[dim];\n                if (dimStore) {\n                    dimStore[chunkIndex][chunkOffset] = val;\n                }\n\n                if (val < rawExtentOnDim[0]) {\n                    rawExtentOnDim[0] = val;\n                }\n                if (val > rawExtentOnDim[1]) {\n                    rawExtentOnDim[1] = val;\n                }\n            }\n        }\n    }\n\n    return list;\n};\n\n/**\n * Large data down sampling on given dimension\n * @param {string} dimension\n * @param {number} rate\n * @param {Function} sampleValue\n * @param {Function} sampleIndex Sample index for name and id\n */\nlistProto.downSample = function (dimension, rate, sampleValue, sampleIndex) {\n    var list = cloneListForMapAndSample(this, [dimension]);\n    var targetStorage = list._storage;\n\n    var frameValues = [];\n    var frameSize = Math.floor(1 / rate);\n\n    var dimStore = targetStorage[dimension];\n    var len = this.count();\n    var chunkSize = this._chunkSize;\n    var rawExtentOnDim = list._rawExtent[dimension];\n\n    var newIndices = new (getIndicesCtor(this))(len);\n\n    var offset = 0;\n    for (var i = 0; i < len; i += frameSize) {\n        // Last frame\n        if (frameSize > len - i) {\n            frameSize = len - i;\n            frameValues.length = frameSize;\n        }\n        for (var k = 0; k < frameSize; k++) {\n            var dataIdx = this.getRawIndex(i + k);\n            var originalChunkIndex = Math.floor(dataIdx / chunkSize);\n            var originalChunkOffset = dataIdx % chunkSize;\n            frameValues[k] = dimStore[originalChunkIndex][originalChunkOffset];\n        }\n        var value = sampleValue(frameValues);\n        var sampleFrameIdx = this.getRawIndex(\n            Math.min(i + sampleIndex(frameValues, value) || 0, len - 1)\n        );\n        var sampleChunkIndex = Math.floor(sampleFrameIdx / chunkSize);\n        var sampleChunkOffset = sampleFrameIdx % chunkSize;\n        // Only write value on the filtered data\n        dimStore[sampleChunkIndex][sampleChunkOffset] = value;\n\n        if (value < rawExtentOnDim[0]) {\n            rawExtentOnDim[0] = value;\n        }\n        if (value > rawExtentOnDim[1]) {\n            rawExtentOnDim[1] = value;\n        }\n\n        newIndices[offset++] = sampleFrameIdx;\n    }\n\n    list._count = offset;\n    list._indices = newIndices;\n\n    list.getRawIndex = getRawIndexWithIndices;\n\n    return list;\n};\n\n/**\n * Get model of one data item.\n *\n * @param {number} idx\n */\n// FIXME Model proxy ?\nlistProto.getItemModel = function (idx) {\n    var hostModel = this.hostModel;\n    return new Model(this.getRawDataItem(idx), hostModel, hostModel && hostModel.ecModel);\n};\n\n/**\n * Create a data differ\n * @param {module:echarts/data/List} otherList\n * @return {module:echarts/data/DataDiffer}\n */\nlistProto.diff = function (otherList) {\n    var thisList = this;\n\n    return new DataDiffer(\n        otherList ? otherList.getIndices() : [],\n        this.getIndices(),\n        function (idx) {\n            return getId(otherList, idx);\n        },\n        function (idx) {\n            return getId(thisList, idx);\n        }\n    );\n};\n/**\n * Get visual property.\n * @param {string} key\n */\nlistProto.getVisual = function (key) {\n    var visual = this._visual;\n    return visual && visual[key];\n};\n\n/**\n * Set visual property\n * @param {string|Object} key\n * @param {*} [value]\n *\n * @example\n *  setVisual('color', color);\n *  setVisual({\n *      'color': color\n *  });\n */\nlistProto.setVisual = function (key, val) {\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                this.setVisual(name, key[name]);\n            }\n        }\n        return;\n    }\n    this._visual = this._visual || {};\n    this._visual[key] = val;\n};\n\n/**\n * Set layout property.\n * @param {string|Object} key\n * @param {*} [val]\n */\nlistProto.setLayout = function (key, val) {\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                this.setLayout(name, key[name]);\n            }\n        }\n        return;\n    }\n    this._layout[key] = val;\n};\n\n/**\n * Get layout property.\n * @param  {string} key.\n * @return {*}\n */\nlistProto.getLayout = function (key) {\n    return this._layout[key];\n};\n\n/**\n * Get layout of single data item\n * @param {number} idx\n */\nlistProto.getItemLayout = function (idx) {\n    return this._itemLayouts[idx];\n};\n\n/**\n * Set layout of single data item\n * @param {number} idx\n * @param {Object} layout\n * @param {boolean=} [merge=false]\n */\nlistProto.setItemLayout = function (idx, layout, merge$$1) {\n    this._itemLayouts[idx] = merge$$1\n        ? extend(this._itemLayouts[idx] || {}, layout)\n        : layout;\n};\n\n/**\n * Clear all layout of single data item\n */\nlistProto.clearItemLayouts = function () {\n    this._itemLayouts.length = 0;\n};\n\n/**\n * Get visual property of single data item\n * @param {number} idx\n * @param {string} key\n * @param {boolean} [ignoreParent=false]\n */\nlistProto.getItemVisual = function (idx, key, ignoreParent) {\n    var itemVisual = this._itemVisuals[idx];\n    var val = itemVisual && itemVisual[key];\n    if (val == null && !ignoreParent) {\n        // Use global visual property\n        return this.getVisual(key);\n    }\n    return val;\n};\n\n/**\n * Set visual property of single data item\n *\n * @param {number} idx\n * @param {string|Object} key\n * @param {*} [value]\n *\n * @example\n *  setItemVisual(0, 'color', color);\n *  setItemVisual(0, {\n *      'color': color\n *  });\n */\nlistProto.setItemVisual = function (idx, key, value) {\n    var itemVisual = this._itemVisuals[idx] || {};\n    var hasItemVisual = this.hasItemVisual;\n    this._itemVisuals[idx] = itemVisual;\n\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                itemVisual[name] = key[name];\n                hasItemVisual[name] = true;\n            }\n        }\n        return;\n    }\n    itemVisual[key] = value;\n    hasItemVisual[key] = true;\n};\n\n/**\n * Clear itemVisuals and list visual.\n */\nlistProto.clearAllVisual = function () {\n    this._visual = {};\n    this._itemVisuals = [];\n    this.hasItemVisual = {};\n};\n\nvar setItemDataAndSeriesIndex = function (child) {\n    child.seriesIndex = this.seriesIndex;\n    child.dataIndex = this.dataIndex;\n    child.dataType = this.dataType;\n};\n/**\n * Set graphic element relative to data. It can be set as null\n * @param {number} idx\n * @param {module:zrender/Element} [el]\n */\nlistProto.setItemGraphicEl = function (idx, el) {\n    var hostModel = this.hostModel;\n\n    if (el) {\n        // Add data index and series index for indexing the data by element\n        // Useful in tooltip\n        el.dataIndex = idx;\n        el.dataType = this.dataType;\n        el.seriesIndex = hostModel && hostModel.seriesIndex;\n        if (el.type === 'group') {\n            el.traverse(setItemDataAndSeriesIndex, el);\n        }\n    }\n\n    this._graphicEls[idx] = el;\n};\n\n/**\n * @param {number} idx\n * @return {module:zrender/Element}\n */\nlistProto.getItemGraphicEl = function (idx) {\n    return this._graphicEls[idx];\n};\n\n/**\n * @param {Function} cb\n * @param {*} context\n */\nlistProto.eachItemGraphicEl = function (cb, context) {\n    each$1(this._graphicEls, function (el, idx) {\n        if (el) {\n            cb && cb.call(context, el, idx);\n        }\n    });\n};\n\n/**\n * Shallow clone a new list except visual and layout properties, and graph elements.\n * New list only change the indices.\n */\nlistProto.cloneShallow = function (list) {\n    if (!list) {\n        var dimensionInfoList = map(this.dimensions, this.getDimensionInfo, this);\n        list = new List(dimensionInfoList, this.hostModel);\n    }\n\n    // FIXME\n    list._storage = this._storage;\n\n    transferProperties(list, this);\n\n    // Clone will not change the data extent and indices\n    if (this._indices) {\n        var Ctor = this._indices.constructor;\n        list._indices = new Ctor(this._indices);\n    }\n    else {\n        list._indices = null;\n    }\n    list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return list;\n};\n\n/**\n * Wrap some method to add more feature\n * @param {string} methodName\n * @param {Function} injectFunction\n */\nlistProto.wrapMethod = function (methodName, injectFunction) {\n    var originalMethod = this[methodName];\n    if (typeof originalMethod !== 'function') {\n        return;\n    }\n    this.__wrappedMethods = this.__wrappedMethods || [];\n    this.__wrappedMethods.push(methodName);\n    this[methodName] = function () {\n        var res = originalMethod.apply(this, arguments);\n        return injectFunction.apply(this, [res].concat(slice(arguments)));\n    };\n};\n\n// Methods that create a new list based on this list should be listed here.\n// Notice that those method should `RETURN` the new list.\nlistProto.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'map'];\n// Methods that change indices of this list should be listed here.\nlistProto.CHANGABLE_METHODS = ['filterSelf', 'selectRange'];\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @deprecated\n * Use `echarts/data/helper/createDimensions` instead.\n */\n\n/**\n * @see {module:echarts/test/ut/spec/data/completeDimensions}\n *\n * Complete the dimensions array, by user defined `dimension` and `encode`,\n * and guessing from the data structure.\n * If no 'value' dimension specified, the first no-named dimension will be\n * named as 'value'.\n *\n * @param {Array.<string>} sysDims Necessary dimensions, like ['x', 'y'], which\n *      provides not only dim template, but also default order.\n *      properties: 'name', 'type', 'displayName'.\n *      `name` of each item provides default coord name.\n *      [{dimsDef: [string|Object, ...]}, ...] dimsDef of sysDim item provides default dim name, and\n *                                    provide dims count that the sysDim required.\n *      [{ordinalMeta}] can be specified.\n * @param {module:echarts/data/Source|Array|Object} source or data (for compatibal with pervious)\n * @param {Object} [opt]\n * @param {Array.<Object|string>} [opt.dimsDef] option.series.dimensions User defined dimensions\n *      For example: ['asdf', {name, type}, ...].\n * @param {Object|HashMap} [opt.encodeDef] option.series.encode {x: 2, y: [3, 1], tooltip: [1, 2], label: 3}\n * @param {string} [opt.generateCoord] Generate coord dim with the given name.\n *                 If not specified, extra dim names will be:\n *                 'value', 'value0', 'value1', ...\n * @param {number} [opt.generateCoordCount] By default, the generated dim name is `generateCoord`.\n *                 If `generateCoordCount` specified, the generated dim names will be:\n *                 `generateCoord` + 0, `generateCoord` + 1, ...\n *                 can be Infinity, indicate that use all of the remain columns.\n * @param {number} [opt.dimCount] If not specified, guess by the first data item.\n * @param {number} [opt.encodeDefaulter] If not specified, auto find the next available data dim.\n * @return {Array.<Object>} [{\n *      name: string mandatory,\n *      displayName: string, the origin name in dimsDef, see source helper.\n *                 If displayName given, the tooltip will displayed vertically.\n *      coordDim: string mandatory,\n *      coordDimIndex: number mandatory,\n *      type: string optional,\n *      otherDims: { never null/undefined\n *          tooltip: number optional,\n *          label: number optional,\n *          itemName: number optional,\n *          seriesName: number optional,\n *      },\n *      isExtraCoord: boolean true if coord is generated\n *          (not specified in encode and not series specified)\n *      other props ...\n * }]\n */\nfunction completeDimensions(sysDims, source, opt) {\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n\n    opt = opt || {};\n    sysDims = (sysDims || []).slice();\n    var dimsDef = (opt.dimsDef || []).slice();\n    var encodeDef = createHashMap(opt.encodeDef);\n    var dataDimNameMap = createHashMap();\n    var coordDimNameMap = createHashMap();\n    // var valueCandidate;\n    var result = [];\n\n    var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimCount);\n\n    // Apply user defined dims (`name` and `type`) and init result.\n    for (var i = 0; i < dimCount; i++) {\n        var dimDefItem = dimsDef[i] = extend(\n            {}, isObject$1(dimsDef[i]) ? dimsDef[i] : {name: dimsDef[i]}\n        );\n        var userDimName = dimDefItem.name;\n        var resultItem = result[i] = {otherDims: {}};\n        // Name will be applied later for avoiding duplication.\n        if (userDimName != null && dataDimNameMap.get(userDimName) == null) {\n            // Only if `series.dimensions` is defined in option\n            // displayName, will be set, and dimension will be diplayed vertically in\n            // tooltip by default.\n            resultItem.name = resultItem.displayName = userDimName;\n            dataDimNameMap.set(userDimName, i);\n        }\n        dimDefItem.type != null && (resultItem.type = dimDefItem.type);\n        dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);\n    }\n\n    // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.\n    encodeDef.each(function (dataDims, coordDim) {\n        dataDims = normalizeToArray(dataDims).slice();\n\n        // Note: It is allowed that `dataDims.length` is `0`, e.g., options is\n        // `{encode: {x: -1, y: 1}}`. Should not filter anything in\n        // this case.\n        if (dataDims.length === 1 && dataDims[0] < 0) {\n            encodeDef.set(coordDim, false);\n            return;\n        }\n\n        var validDataDims = encodeDef.set(coordDim, []);\n        each$1(dataDims, function (resultDimIdx, idx) {\n            // The input resultDimIdx can be dim name or index.\n            isString(resultDimIdx) && (resultDimIdx = dataDimNameMap.get(resultDimIdx));\n            if (resultDimIdx != null && resultDimIdx < dimCount) {\n                validDataDims[idx] = resultDimIdx;\n                applyDim(result[resultDimIdx], coordDim, idx);\n            }\n        });\n    });\n\n    // Apply templetes and default order from `sysDims`.\n    var availDimIdx = 0;\n    each$1(sysDims, function (sysDimItem, sysDimIndex) {\n        var coordDim;\n        var sysDimItem;\n        var sysDimItemDimsDef;\n        var sysDimItemOtherDims;\n        if (isString(sysDimItem)) {\n            coordDim = sysDimItem;\n            sysDimItem = {};\n        }\n        else {\n            coordDim = sysDimItem.name;\n            var ordinalMeta = sysDimItem.ordinalMeta;\n            sysDimItem.ordinalMeta = null;\n            sysDimItem = clone(sysDimItem);\n            sysDimItem.ordinalMeta = ordinalMeta;\n            // `coordDimIndex` should not be set directly.\n            sysDimItemDimsDef = sysDimItem.dimsDef;\n            sysDimItemOtherDims = sysDimItem.otherDims;\n            sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex\n                = sysDimItem.dimsDef = sysDimItem.otherDims = null;\n        }\n\n        var dataDims = encodeDef.get(coordDim);\n\n        // negative resultDimIdx means no need to mapping.\n        if (dataDims === false) {\n            return;\n        }\n\n        var dataDims = normalizeToArray(dataDims);\n\n        // dimensions provides default dim sequences.\n        if (!dataDims.length) {\n            for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {\n                while (availDimIdx < result.length && result[availDimIdx].coordDim != null) {\n                    availDimIdx++;\n                }\n                availDimIdx < result.length && dataDims.push(availDimIdx++);\n            }\n        }\n\n        // Apply templates.\n        each$1(dataDims, function (resultDimIdx, coordDimIndex) {\n            var resultItem = result[resultDimIdx];\n            applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);\n            if (resultItem.name == null && sysDimItemDimsDef) {\n                var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];\n                !isObject$1(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {name: sysDimItemDimsDefItem});\n                resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;\n                resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;\n            }\n            // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}\n            sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);\n        });\n    });\n\n    function applyDim(resultItem, coordDim, coordDimIndex) {\n        if (OTHER_DIMENSIONS.get(coordDim) != null) {\n            resultItem.otherDims[coordDim] = coordDimIndex;\n        }\n        else {\n            resultItem.coordDim = coordDim;\n            resultItem.coordDimIndex = coordDimIndex;\n            coordDimNameMap.set(coordDim, true);\n        }\n    }\n\n    // Make sure the first extra dim is 'value'.\n    var generateCoord = opt.generateCoord;\n    var generateCoordCount = opt.generateCoordCount;\n    var fromZero = generateCoordCount != null;\n    generateCoordCount = generateCoord ? (generateCoordCount || 1) : 0;\n    var extra = generateCoord || 'value';\n\n    // Set dim `name` and other `coordDim` and other props.\n    for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {\n        var resultItem = result[resultDimIdx] = result[resultDimIdx] || {};\n        var coordDim = resultItem.coordDim;\n\n        if (coordDim == null) {\n            resultItem.coordDim = genName(\n                extra, coordDimNameMap, fromZero\n            );\n            resultItem.coordDimIndex = 0;\n            if (!generateCoord || generateCoordCount <= 0) {\n                resultItem.isExtraCoord = true;\n            }\n            generateCoordCount--;\n        }\n\n        resultItem.name == null && (resultItem.name = genName(\n            resultItem.coordDim,\n            dataDimNameMap\n        ));\n\n        if (resultItem.type == null && guessOrdinal(source, resultDimIdx, resultItem.name)) {\n            resultItem.type = 'ordinal';\n        }\n    }\n\n    return result;\n}\n\n// ??? TODO\n// Originally detect dimCount by data[0]. Should we\n// optimize it to only by sysDims and dimensions and encode.\n// So only necessary dims will be initialized.\n// But\n// (1) custom series should be considered. where other dims\n// may be visited.\n// (2) sometimes user need to calcualte bubble size or use visualMap\n// on other dimensions besides coordSys needed.\n// So, dims that is not used by system, should be shared in storage?\nfunction getDimCount(source, sysDims, dimsDef, optDimCount) {\n    // Note that the result dimCount should not small than columns count\n    // of data, otherwise `dataDimNameMap` checking will be incorrect.\n    var dimCount = Math.max(\n        source.dimensionsDetectCount || 1,\n        sysDims.length,\n        dimsDef.length,\n        optDimCount || 0\n    );\n    each$1(sysDims, function (sysDimItem) {\n        var sysDimItemDimsDef = sysDimItem.dimsDef;\n        sysDimItemDimsDef && (dimCount = Math.max(dimCount, sysDimItemDimsDef.length));\n    });\n    return dimCount;\n}\n\nfunction genName(name, map$$1, fromZero) {\n    if (fromZero || map$$1.get(name) != null) {\n        var i = 0;\n        while (map$$1.get(name + i) != null) {\n            i++;\n        }\n        name += i;\n    }\n    map$$1.set(name, true);\n    return name;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Substitute `completeDimensions`.\n * `completeDimensions` is to be deprecated.\n */\n/**\n * @param {module:echarts/data/Source|module:echarts/data/List} source or data.\n * @param {Object|Array} [opt]\n * @param {Array.<string|Object>} [opt.coordDimensions=[]]\n * @param {number} [opt.dimensionsCount]\n * @param {string} [opt.generateCoord]\n * @param {string} [opt.generateCoordCount]\n * @param {Array.<string|Object>} [opt.dimensionsDefine=source.dimensionsDefine] Overwrite source define.\n * @param {Object|HashMap} [opt.encodeDefine=source.encodeDefine] Overwrite source define.\n * @return {Array.<Object>} dimensionsInfo\n */\nvar createDimensions = function (source, opt) {\n    opt = opt || {};\n    return completeDimensions(opt.coordDimensions || [], source, {\n        dimsDef: opt.dimensionsDefine || source.dimensionsDefine,\n        encodeDef: opt.encodeDefine || source.encodeDefine,\n        dimCount: opt.dimensionsCount,\n        generateCoord: opt.generateCoord,\n        generateCoordCount: opt.generateCoordCount\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Note that it is too complicated to support 3d stack by value\n * (have to create two-dimension inverted index), so in 3d case\n * we just support that stacked by index.\n *\n * @param {module:echarts/model/Series} seriesModel\n * @param {Array.<string|Object>} dimensionInfoList The same as the input of <module:echarts/data/List>.\n *        The input dimensionInfoList will be modified.\n * @param {Object} [opt]\n * @param {boolean} [opt.stackedCoordDimension=''] Specify a coord dimension if needed.\n * @param {boolean} [opt.byIndex=false]\n * @return {Object} calculationInfo\n * {\n *     stackedDimension: string\n *     stackedByDimension: string\n *     isStackedByIndex: boolean\n *     stackedOverDimension: string\n *     stackResultDimension: string\n * }\n */\nfunction enableDataStack(seriesModel, dimensionInfoList, opt) {\n    opt = opt || {};\n    var byIndex = opt.byIndex;\n    var stackedCoordDimension = opt.stackedCoordDimension;\n\n    // Compatibal: when `stack` is set as '', do not stack.\n    var mayStack = !!(seriesModel && seriesModel.get('stack'));\n    var stackedByDimInfo;\n    var stackedDimInfo;\n    var stackResultDimension;\n    var stackedOverDimension;\n\n    each$1(dimensionInfoList, function (dimensionInfo, index) {\n        if (isString(dimensionInfo)) {\n            dimensionInfoList[index] = dimensionInfo = {name: dimensionInfo};\n        }\n\n        if (mayStack && !dimensionInfo.isExtraCoord) {\n            // Find the first ordinal dimension as the stackedByDimInfo.\n            if (!byIndex && !stackedByDimInfo && dimensionInfo.ordinalMeta) {\n                stackedByDimInfo = dimensionInfo;\n            }\n            // Find the first stackable dimension as the stackedDimInfo.\n            if (!stackedDimInfo\n                && dimensionInfo.type !== 'ordinal'\n                && dimensionInfo.type !== 'time'\n                && (!stackedCoordDimension || stackedCoordDimension === dimensionInfo.coordDim)\n            ) {\n                stackedDimInfo = dimensionInfo;\n            }\n        }\n    });\n\n    if (stackedDimInfo && !byIndex && !stackedByDimInfo) {\n        // Compatible with previous design, value axis (time axis) only stack by index.\n        // It may make sense if the user provides elaborately constructed data.\n        byIndex = true;\n    }\n\n    // Add stack dimension, they can be both calculated by coordinate system in `unionExtent`.\n    // That put stack logic in List is for using conveniently in echarts extensions, but it\n    // might not be a good way.\n    if (stackedDimInfo) {\n        // Use a weird name that not duplicated with other names.\n        stackResultDimension = '__\\0ecstackresult';\n        stackedOverDimension = '__\\0ecstackedover';\n\n        // Create inverted index to fast query index by value.\n        if (stackedByDimInfo) {\n            stackedByDimInfo.createInvertedIndices = true;\n        }\n\n        var stackedDimCoordDim = stackedDimInfo.coordDim;\n        var stackedDimType = stackedDimInfo.type;\n        var stackedDimCoordIndex = 0;\n\n        each$1(dimensionInfoList, function (dimensionInfo) {\n            if (dimensionInfo.coordDim === stackedDimCoordDim) {\n                stackedDimCoordIndex++;\n            }\n        });\n\n        dimensionInfoList.push({\n            name: stackResultDimension,\n            coordDim: stackedDimCoordDim,\n            coordDimIndex: stackedDimCoordIndex,\n            type: stackedDimType,\n            isExtraCoord: true,\n            isCalculationCoord: true\n        });\n\n        stackedDimCoordIndex++;\n\n        dimensionInfoList.push({\n            name: stackedOverDimension,\n            // This dimension contains stack base (generally, 0), so do not set it as\n            // `stackedDimCoordDim` to avoid extent calculation, consider log scale.\n            coordDim: stackedOverDimension,\n            coordDimIndex: stackedDimCoordIndex,\n            type: stackedDimType,\n            isExtraCoord: true,\n            isCalculationCoord: true\n        });\n    }\n\n    return {\n        stackedDimension: stackedDimInfo && stackedDimInfo.name,\n        stackedByDimension: stackedByDimInfo && stackedByDimInfo.name,\n        isStackedByIndex: byIndex,\n        stackedOverDimension: stackedOverDimension,\n        stackResultDimension: stackResultDimension\n    };\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {string} stackedDim\n */\nfunction isDimensionStacked(data, stackedDim /*, stackedByDim*/) {\n    // Each single series only maps to one pair of axis. So we do not need to\n    // check stackByDim, whatever stacked by a dimension or stacked by index.\n    return !!stackedDim && stackedDim === data.getCalculationInfo('stackedDimension');\n        // && (\n        //     stackedByDim != null\n        //         ? stackedByDim === data.getCalculationInfo('stackedByDimension')\n        //         : data.getCalculationInfo('isStackedByIndex')\n        // );\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {string} targetDim\n * @param {string} [stackedByDim] If not input this parameter, check whether\n *                                stacked by index.\n * @return {string} dimension\n */\nfunction getStackedDimension(data, targetDim) {\n    return isDimensionStacked(data, targetDim)\n        ? data.getCalculationInfo('stackResultDimension')\n        : targetDim;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/data/Source|Array} source Or raw data.\n * @param {module:echarts/model/Series} seriesModel\n * @param {Object} [opt]\n * @param {string} [opt.generateCoord]\n */\nfunction createListFromArray(source, seriesModel, opt) {\n    opt = opt || {};\n\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n\n    var coordSysName = seriesModel.get('coordinateSystem');\n    var registeredCoordSys = CoordinateSystemManager.get(coordSysName);\n\n    var coordSysDefine = getCoordSysDefineBySeries(seriesModel);\n\n    var coordSysDimDefs;\n\n    if (coordSysDefine) {\n        coordSysDimDefs = map(coordSysDefine.coordSysDims, function (dim) {\n            var dimInfo = {name: dim};\n            var axisModel = coordSysDefine.axisMap.get(dim);\n            if (axisModel) {\n                var axisType = axisModel.get('type');\n                dimInfo.type = getDimensionTypeByAxis(axisType);\n                // dimInfo.stackable = isStackable(axisType);\n            }\n            return dimInfo;\n        });\n    }\n\n    if (!coordSysDimDefs) {\n        // Get dimensions from registered coordinate system\n        coordSysDimDefs = (registeredCoordSys && (\n            registeredCoordSys.getDimensionsInfo\n                ? registeredCoordSys.getDimensionsInfo()\n                : registeredCoordSys.dimensions.slice()\n        )) || ['x', 'y'];\n    }\n\n    var dimInfoList = createDimensions(source, {\n        coordDimensions: coordSysDimDefs,\n        generateCoord: opt.generateCoord\n    });\n\n    var firstCategoryDimIndex;\n    var hasNameEncode;\n    coordSysDefine && each$1(dimInfoList, function (dimInfo, dimIndex) {\n        var coordDim = dimInfo.coordDim;\n        var categoryAxisModel = coordSysDefine.categoryAxisMap.get(coordDim);\n        if (categoryAxisModel) {\n            if (firstCategoryDimIndex == null) {\n                firstCategoryDimIndex = dimIndex;\n            }\n            dimInfo.ordinalMeta = categoryAxisModel.getOrdinalMeta();\n        }\n        if (dimInfo.otherDims.itemName != null) {\n            hasNameEncode = true;\n        }\n    });\n    if (!hasNameEncode && firstCategoryDimIndex != null) {\n        dimInfoList[firstCategoryDimIndex].otherDims.itemName = 0;\n    }\n\n    var stackCalculationInfo = enableDataStack(seriesModel, dimInfoList);\n\n    var list = new List(dimInfoList, seriesModel);\n\n    list.setCalculationInfo(stackCalculationInfo);\n\n    var dimValueGetter = (firstCategoryDimIndex != null && isNeedCompleteOrdinalData(source))\n        ? function (itemOpt, dimName, dataIndex, dimIndex) {\n            // Use dataIndex as ordinal value in categoryAxis\n            return dimIndex === firstCategoryDimIndex\n                ? dataIndex\n                : this.defaultDimValueGetter(itemOpt, dimName, dataIndex, dimIndex);\n        }\n        : null;\n\n    list.hasItemOption = false;\n    list.initData(source, null, dimValueGetter);\n\n    return list;\n}\n\nfunction isNeedCompleteOrdinalData(source) {\n    if (source.sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        var sampleItem = firstDataNotNull(source.data || []);\n        return sampleItem != null\n            && !isArray(getDataItemValue(sampleItem));\n    }\n}\n\nfunction firstDataNotNull(data) {\n    var i = 0;\n    while (i < data.length && data[i] == null) {\n        i++;\n    }\n    return data[i];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * // Scale class management\n * @module echarts/scale/Scale\n */\n\n/**\n * @param {Object} [setting]\n */\nfunction Scale(setting) {\n    this._setting = setting || {};\n\n    /**\n     * Extent\n     * @type {Array.<number>}\n     * @protected\n     */\n    this._extent = [Infinity, -Infinity];\n\n    /**\n     * Step is calculated in adjustExtent\n     * @type {Array.<number>}\n     * @protected\n     */\n    this._interval = 0;\n\n    this.init && this.init.apply(this, arguments);\n}\n\n/**\n * Parse input val to valid inner number.\n * @param {*} val\n * @return {number}\n */\nScale.prototype.parse = function (val) {\n    // Notice: This would be a trap here, If the implementation\n    // of this method depends on extent, and this method is used\n    // before extent set (like in dataZoom), it would be wrong.\n    // Nevertheless, parse does not depend on extent generally.\n    return val;\n};\n\nScale.prototype.getSetting = function (name) {\n    return this._setting[name];\n};\n\nScale.prototype.contain = function (val) {\n    var extent = this._extent;\n    return val >= extent[0] && val <= extent[1];\n};\n\n/**\n * Normalize value to linear [0, 1], return 0.5 if extent span is 0\n * @param {number} val\n * @return {number}\n */\nScale.prototype.normalize = function (val) {\n    var extent = this._extent;\n    if (extent[1] === extent[0]) {\n        return 0.5;\n    }\n    return (val - extent[0]) / (extent[1] - extent[0]);\n};\n\n/**\n * Scale normalized value\n * @param {number} val\n * @return {number}\n */\nScale.prototype.scale = function (val) {\n    var extent = this._extent;\n    return val * (extent[1] - extent[0]) + extent[0];\n};\n\n/**\n * Set extent from data\n * @param {Array.<number>} other\n */\nScale.prototype.unionExtent = function (other) {\n    var extent = this._extent;\n    other[0] < extent[0] && (extent[0] = other[0]);\n    other[1] > extent[1] && (extent[1] = other[1]);\n    // not setExtent because in log axis it may transformed to power\n    // this.setExtent(extent[0], extent[1]);\n};\n\n/**\n * Set extent from data\n * @param {module:echarts/data/List} data\n * @param {string} dim\n */\nScale.prototype.unionExtentFromData = function (data, dim) {\n    this.unionExtent(data.getApproximateExtent(dim));\n};\n\n/**\n * Get extent\n * @return {Array.<number>}\n */\nScale.prototype.getExtent = function () {\n    return this._extent.slice();\n};\n\n/**\n * Set extent\n * @param {number} start\n * @param {number} end\n */\nScale.prototype.setExtent = function (start, end) {\n    var thisExtent = this._extent;\n    if (!isNaN(start)) {\n        thisExtent[0] = start;\n    }\n    if (!isNaN(end)) {\n        thisExtent[1] = end;\n    }\n};\n\n/**\n * When axis extent depends on data and no data exists,\n * axis ticks should not be drawn, which is named 'blank'.\n */\nScale.prototype.isBlank = function () {\n    return this._isBlank;\n},\n\n/**\n * When axis extent depends on data and no data exists,\n * axis ticks should not be drawn, which is named 'blank'.\n */\nScale.prototype.setBlank = function (isBlank) {\n    this._isBlank = isBlank;\n};\n\n/**\n * @abstract\n * @param {*} tick\n * @return {string} label of the tick.\n */\nScale.prototype.getLabel = null;\n\n\nenableClassExtend(Scale);\nenableClassManagement(Scale, {\n    registerWhenExtend: true\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @constructor\n * @param {Object} [opt]\n * @param {Object} [opt.categories=[]]\n * @param {Object} [opt.needCollect=false]\n * @param {Object} [opt.deduplication=false]\n */\nfunction OrdinalMeta(opt) {\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    this.categories = opt.categories || [];\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._needCollect = opt.needCollect;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._deduplication = opt.deduplication;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._map;\n}\n\n/**\n * @param {module:echarts/model/Model} axisModel\n * @return {module:echarts/data/OrdinalMeta}\n */\nOrdinalMeta.createByAxisModel = function (axisModel) {\n    var option = axisModel.option;\n    var data = option.data;\n    var categories = data && map(data, getName);\n\n    return new OrdinalMeta({\n        categories: categories,\n        needCollect: !categories,\n        // deduplication is default in axis.\n        deduplication: option.dedplication !== false\n    });\n};\n\nvar proto$1 = OrdinalMeta.prototype;\n\n/**\n * @param {string} category\n * @return {number} ordinal\n */\nproto$1.getOrdinal = function (category) {\n    return getOrCreateMap(this).get(category);\n};\n\n/**\n * @param {*} category\n * @return {number} The ordinal. If not found, return NaN.\n */\nproto$1.parseAndCollect = function (category) {\n    var index;\n    var needCollect = this._needCollect;\n\n    // The value of category dim can be the index of the given category set.\n    // This feature is only supported when !needCollect, because we should\n    // consider a common case: a value is 2017, which is a number but is\n    // expected to be tread as a category. This case usually happen in dataset,\n    // where it happent to be no need of the index feature.\n    if (typeof category !== 'string' && !needCollect) {\n        return category;\n    }\n\n    // Optimize for the scenario:\n    // category is ['2012-01-01', '2012-01-02', ...], where the input\n    // data has been ensured not duplicate and is large data.\n    // Notice, if a dataset dimension provide categroies, usually echarts\n    // should remove duplication except user tell echarts dont do that\n    // (set axis.deduplication = false), because echarts do not know whether\n    // the values in the category dimension has duplication (consider the\n    // parallel-aqi example)\n    if (needCollect && !this._deduplication) {\n        index = this.categories.length;\n        this.categories[index] = category;\n        return index;\n    }\n\n    var map$$1 = getOrCreateMap(this);\n    index = map$$1.get(category);\n\n    if (index == null) {\n        if (needCollect) {\n            index = this.categories.length;\n            this.categories[index] = category;\n            map$$1.set(category, index);\n        }\n        else {\n            index = NaN;\n        }\n    }\n\n    return index;\n};\n\n// Consider big data, do not create map until needed.\nfunction getOrCreateMap(ordinalMeta) {\n    return ordinalMeta._map || (\n        ordinalMeta._map = createHashMap(ordinalMeta.categories)\n    );\n}\n\nfunction getName(obj) {\n    if (isObject$1(obj) && obj.value != null) {\n        return obj.value;\n    }\n    else {\n        return obj + '';\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Linear continuous scale\n * @module echarts/coord/scale/Ordinal\n *\n * http://en.wikipedia.org/wiki/Level_of_measurement\n */\n\n// FIXME only one data\n\nvar scaleProto = Scale.prototype;\n\nvar OrdinalScale = Scale.extend({\n\n    type: 'ordinal',\n\n    /**\n     * @param {module:echarts/data/OrdianlMeta|Array.<string>} ordinalMeta\n     */\n    init: function (ordinalMeta, extent) {\n        // Caution: Should not use instanceof, consider ec-extensions using\n        // import approach to get OrdinalMeta class.\n        if (!ordinalMeta || isArray(ordinalMeta)) {\n            ordinalMeta = new OrdinalMeta({categories: ordinalMeta});\n        }\n        this._ordinalMeta = ordinalMeta;\n        this._extent = extent || [0, ordinalMeta.categories.length - 1];\n    },\n\n    parse: function (val) {\n        return typeof val === 'string'\n            ? this._ordinalMeta.getOrdinal(val)\n            // val might be float.\n            : Math.round(val);\n    },\n\n    contain: function (rank) {\n        rank = this.parse(rank);\n        return scaleProto.contain.call(this, rank)\n            && this._ordinalMeta.categories[rank] != null;\n    },\n\n    /**\n     * Normalize given rank or name to linear [0, 1]\n     * @param {number|string} [val]\n     * @return {number}\n     */\n    normalize: function (val) {\n        return scaleProto.normalize.call(this, this.parse(val));\n    },\n\n    scale: function (val) {\n        return Math.round(scaleProto.scale.call(this, val));\n    },\n\n    /**\n     * @return {Array}\n     */\n    getTicks: function () {\n        var ticks = [];\n        var extent = this._extent;\n        var rank = extent[0];\n\n        while (rank <= extent[1]) {\n            ticks.push(rank);\n            rank++;\n        }\n\n        return ticks;\n    },\n\n    /**\n     * Get item on rank n\n     * @param {number} n\n     * @return {string}\n     */\n    getLabel: function (n) {\n        if (!this.isBlank()) {\n            // Note that if no data, ordinalMeta.categories is an empty array.\n            return this._ordinalMeta.categories[n];\n        }\n    },\n\n    /**\n     * @return {number}\n     */\n    count: function () {\n        return this._extent[1] - this._extent[0] + 1;\n    },\n\n    /**\n     * @override\n     */\n    unionExtentFromData: function (data, dim) {\n        this.unionExtent(data.getApproximateExtent(dim));\n    },\n\n    getOrdinalMeta: function () {\n        return this._ordinalMeta;\n    },\n\n    niceTicks: noop,\n    niceExtent: noop\n});\n\n/**\n * @return {module:echarts/scale/Time}\n */\nOrdinalScale.create = function () {\n    return new OrdinalScale();\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * For testable.\n */\n\nvar roundNumber$1 = round$2;\n\n/**\n * @param {Array.<number>} extent Both extent[0] and extent[1] should be valid number.\n *                                Should be extent[0] < extent[1].\n * @param {number} splitNumber splitNumber should be >= 1.\n * @param {number} [minInterval]\n * @param {number} [maxInterval]\n * @return {Object} {interval, intervalPrecision, niceTickExtent}\n */\nfunction intervalScaleNiceTicks(extent, splitNumber, minInterval, maxInterval) {\n    var result = {};\n    var span = extent[1] - extent[0];\n\n    var interval = result.interval = nice(span / splitNumber, true);\n    if (minInterval != null && interval < minInterval) {\n        interval = result.interval = minInterval;\n    }\n    if (maxInterval != null && interval > maxInterval) {\n        interval = result.interval = maxInterval;\n    }\n    // Tow more digital for tick.\n    var precision = result.intervalPrecision = getIntervalPrecision(interval);\n    // Niced extent inside original extent\n    var niceTickExtent = result.niceTickExtent = [\n        roundNumber$1(Math.ceil(extent[0] / interval) * interval, precision),\n        roundNumber$1(Math.floor(extent[1] / interval) * interval, precision)\n    ];\n\n    fixExtent(niceTickExtent, extent);\n\n    return result;\n}\n\n/**\n * @param {number} interval\n * @return {number} interval precision\n */\nfunction getIntervalPrecision(interval) {\n    // Tow more digital for tick.\n    return getPrecisionSafe(interval) + 2;\n}\n\nfunction clamp(niceTickExtent, idx, extent) {\n    niceTickExtent[idx] = Math.max(Math.min(niceTickExtent[idx], extent[1]), extent[0]);\n}\n\n// In some cases (e.g., splitNumber is 1), niceTickExtent may be out of extent.\nfunction fixExtent(niceTickExtent, extent) {\n    !isFinite(niceTickExtent[0]) && (niceTickExtent[0] = extent[0]);\n    !isFinite(niceTickExtent[1]) && (niceTickExtent[1] = extent[1]);\n    clamp(niceTickExtent, 0, extent);\n    clamp(niceTickExtent, 1, extent);\n    if (niceTickExtent[0] > niceTickExtent[1]) {\n        niceTickExtent[0] = niceTickExtent[1];\n    }\n}\n\nfunction intervalScaleGetTicks(interval, extent, niceTickExtent, intervalPrecision) {\n    var ticks = [];\n\n    // If interval is 0, return [];\n    if (!interval) {\n        return ticks;\n    }\n\n    // Consider this case: using dataZoom toolbox, zoom and zoom.\n    var safeLimit = 10000;\n\n    if (extent[0] < niceTickExtent[0]) {\n        ticks.push(extent[0]);\n    }\n    var tick = niceTickExtent[0];\n\n    while (tick <= niceTickExtent[1]) {\n        ticks.push(tick);\n        // Avoid rounding error\n        tick = roundNumber$1(tick + interval, intervalPrecision);\n        if (tick === ticks[ticks.length - 1]) {\n            // Consider out of safe float point, e.g.,\n            // -3711126.9907707 + 2e-10 === -3711126.9907707\n            break;\n        }\n        if (ticks.length > safeLimit) {\n            return [];\n        }\n    }\n    // Consider this case: the last item of ticks is smaller\n    // than niceTickExtent[1] and niceTickExtent[1] === extent[1].\n    if (extent[1] > (ticks.length ? ticks[ticks.length - 1] : niceTickExtent[1])) {\n        ticks.push(extent[1]);\n    }\n\n    return ticks;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Interval scale\n * @module echarts/scale/Interval\n */\n\n\nvar roundNumber = round$2;\n\n/**\n * @alias module:echarts/coord/scale/Interval\n * @constructor\n */\nvar IntervalScale = Scale.extend({\n\n    type: 'interval',\n\n    _interval: 0,\n\n    _intervalPrecision: 2,\n\n    setExtent: function (start, end) {\n        var thisExtent = this._extent;\n        //start,end may be a Number like '25',so...\n        if (!isNaN(start)) {\n            thisExtent[0] = parseFloat(start);\n        }\n        if (!isNaN(end)) {\n            thisExtent[1] = parseFloat(end);\n        }\n    },\n\n    unionExtent: function (other) {\n        var extent = this._extent;\n        other[0] < extent[0] && (extent[0] = other[0]);\n        other[1] > extent[1] && (extent[1] = other[1]);\n\n        // unionExtent may called by it's sub classes\n        IntervalScale.prototype.setExtent.call(this, extent[0], extent[1]);\n    },\n    /**\n     * Get interval\n     */\n    getInterval: function () {\n        return this._interval;\n    },\n\n    /**\n     * Set interval\n     */\n    setInterval: function (interval) {\n        this._interval = interval;\n        // Dropped auto calculated niceExtent and use user setted extent\n        // We assume user wan't to set both interval, min, max to get a better result\n        this._niceExtent = this._extent.slice();\n\n        this._intervalPrecision = getIntervalPrecision(interval);\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getTicks: function () {\n        return intervalScaleGetTicks(\n            this._interval, this._extent, this._niceExtent, this._intervalPrecision\n        );\n    },\n\n    /**\n     * @param {number} data\n     * @param {Object} [opt]\n     * @param {number|string} [opt.precision] If 'auto', use nice presision.\n     * @param {boolean} [opt.pad] returns 1.50 but not 1.5 if precision is 2.\n     * @return {string}\n     */\n    getLabel: function (data, opt) {\n        if (data == null) {\n            return '';\n        }\n\n        var precision = opt && opt.precision;\n\n        if (precision == null) {\n            precision = getPrecisionSafe(data) || 0;\n        }\n        else if (precision === 'auto') {\n            // Should be more precise then tick.\n            precision = this._intervalPrecision;\n        }\n\n        // (1) If `precision` is set, 12.005 should be display as '12.00500'.\n        // (2) Use roundNumber (toFixed) to avoid scientific notation like '3.5e-7'.\n        data = roundNumber(data, precision, true);\n\n        return addCommas(data);\n    },\n\n    /**\n     * Update interval and extent of intervals for nice ticks\n     *\n     * @param {number} [splitNumber = 5] Desired number of ticks\n     * @param {number} [minInterval]\n     * @param {number} [maxInterval]\n     */\n    niceTicks: function (splitNumber, minInterval, maxInterval) {\n        splitNumber = splitNumber || 5;\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        if (!isFinite(span)) {\n            return;\n        }\n        // User may set axis min 0 and data are all negative\n        // FIXME If it needs to reverse ?\n        if (span < 0) {\n            span = -span;\n            extent.reverse();\n        }\n\n        var result = intervalScaleNiceTicks(\n            extent, splitNumber, minInterval, maxInterval\n        );\n\n        this._intervalPrecision = result.intervalPrecision;\n        this._interval = result.interval;\n        this._niceExtent = result.niceTickExtent;\n    },\n\n    /**\n     * Nice extent.\n     * @param {Object} opt\n     * @param {number} [opt.splitNumber = 5] Given approx tick number\n     * @param {boolean} [opt.fixMin=false]\n     * @param {boolean} [opt.fixMax=false]\n     * @param {boolean} [opt.minInterval]\n     * @param {boolean} [opt.maxInterval]\n     */\n    niceExtent: function (opt) {\n        var extent = this._extent;\n        // If extent start and end are same, expand them\n        if (extent[0] === extent[1]) {\n            if (extent[0] !== 0) {\n                // Expand extent\n                var expandSize = extent[0];\n                // In the fowllowing case\n                //      Axis has been fixed max 100\n                //      Plus data are all 100 and axis extent are [100, 100].\n                // Extend to the both side will cause expanded max is larger than fixed max.\n                // So only expand to the smaller side.\n                if (!opt.fixMax) {\n                    extent[1] += expandSize / 2;\n                    extent[0] -= expandSize / 2;\n                }\n                else {\n                    extent[0] -= expandSize / 2;\n                }\n            }\n            else {\n                extent[1] = 1;\n            }\n        }\n        var span = extent[1] - extent[0];\n        // If there are no data and extent are [Infinity, -Infinity]\n        if (!isFinite(span)) {\n            extent[0] = 0;\n            extent[1] = 1;\n        }\n\n        this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);\n\n        // var extent = this._extent;\n        var interval = this._interval;\n\n        if (!opt.fixMin) {\n            extent[0] = roundNumber(Math.floor(extent[0] / interval) * interval);\n        }\n        if (!opt.fixMax) {\n            extent[1] = roundNumber(Math.ceil(extent[1] / interval) * interval);\n        }\n    }\n});\n\n/**\n * @return {module:echarts/scale/Time}\n */\nIntervalScale.create = function () {\n    return new IntervalScale();\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar STACK_PREFIX = '__ec_stack_';\nvar LARGE_BAR_MIN_WIDTH = 0.5;\n\nvar LargeArr = typeof Float32Array !== 'undefined' ? Float32Array : Array;\n\nfunction getSeriesStackId(seriesModel) {\n    return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex;\n}\n\nfunction getAxisKey(axis) {\n    return axis.dim + axis.index;\n}\n\n/**\n * @param {Object} opt\n * @param {module:echarts/coord/Axis} opt.axis Only support category axis currently.\n * @param {number} opt.count Positive interger.\n * @param {number} [opt.barWidth]\n * @param {number} [opt.barMaxWidth]\n * @param {number} [opt.barGap]\n * @param {number} [opt.barCategoryGap]\n * @return {Object} {width, offset, offsetCenter} If axis.type is not 'category', return undefined.\n */\nfunction getLayoutOnAxis(opt) {\n    var params = [];\n    var baseAxis = opt.axis;\n    var axisKey = 'axis0';\n\n    if (baseAxis.type !== 'category') {\n        return;\n    }\n    var bandWidth = baseAxis.getBandWidth();\n\n    for (var i = 0; i < opt.count || 0; i++) {\n        params.push(defaults({\n            bandWidth: bandWidth,\n            axisKey: axisKey,\n            stackId: STACK_PREFIX + i\n        }, opt));\n    }\n    var widthAndOffsets = doCalBarWidthAndOffset(params);\n\n    var result = [];\n    for (var i = 0; i < opt.count; i++) {\n        var item = widthAndOffsets[axisKey][STACK_PREFIX + i];\n        item.offsetCenter = item.offset + item.width / 2;\n        result.push(item);\n    }\n\n    return result;\n}\n\nfunction prepareLayoutBarSeries(seriesType, ecModel) {\n    var seriesModels = [];\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        // Check series coordinate, do layout for cartesian2d only\n        if (isOnCartesian(seriesModel) && !isInLargeMode(seriesModel)) {\n            seriesModels.push(seriesModel);\n        }\n    });\n    return seriesModels;\n}\n\nfunction makeColumnLayout(barSeries) {\n    var seriesInfoList = [];\n    each$1(barSeries, function (seriesModel) {\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var axisExtent = baseAxis.getExtent();\n        var bandWidth = baseAxis.type === 'category'\n            ? baseAxis.getBandWidth()\n            : (Math.abs(axisExtent[1] - axisExtent[0]) / data.count());\n\n        var barWidth = parsePercent$1(\n            seriesModel.get('barWidth'), bandWidth\n        );\n        var barMaxWidth = parsePercent$1(\n            seriesModel.get('barMaxWidth'), bandWidth\n        );\n        var barGap = seriesModel.get('barGap');\n        var barCategoryGap = seriesModel.get('barCategoryGap');\n\n        seriesInfoList.push({\n            bandWidth: bandWidth,\n            barWidth: barWidth,\n            barMaxWidth: barMaxWidth,\n            barGap: barGap,\n            barCategoryGap: barCategoryGap,\n            axisKey: getAxisKey(baseAxis),\n            stackId: getSeriesStackId(seriesModel)\n        });\n    });\n\n    return doCalBarWidthAndOffset(seriesInfoList);\n}\n\nfunction doCalBarWidthAndOffset(seriesInfoList) {\n    // Columns info on each category axis. Key is cartesian name\n    var columnsMap = {};\n\n    each$1(seriesInfoList, function (seriesInfo, idx) {\n        var axisKey = seriesInfo.axisKey;\n        var bandWidth = seriesInfo.bandWidth;\n        var columnsOnAxis = columnsMap[axisKey] || {\n            bandWidth: bandWidth,\n            remainedWidth: bandWidth,\n            autoWidthCount: 0,\n            categoryGap: '20%',\n            gap: '30%',\n            stacks: {}\n        };\n        var stacks = columnsOnAxis.stacks;\n        columnsMap[axisKey] = columnsOnAxis;\n\n        var stackId = seriesInfo.stackId;\n\n        if (!stacks[stackId]) {\n            columnsOnAxis.autoWidthCount++;\n        }\n        stacks[stackId] = stacks[stackId] || {\n            width: 0,\n            maxWidth: 0\n        };\n\n        // Caution: In a single coordinate system, these barGrid attributes\n        // will be shared by series. Consider that they have default values,\n        // only the attributes set on the last series will work.\n        // Do not change this fact unless there will be a break change.\n\n        // TODO\n        var barWidth = seriesInfo.barWidth;\n        if (barWidth && !stacks[stackId].width) {\n            // See #6312, do not restrict width.\n            stacks[stackId].width = barWidth;\n            barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);\n            columnsOnAxis.remainedWidth -= barWidth;\n        }\n\n        var barMaxWidth = seriesInfo.barMaxWidth;\n        barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);\n        var barGap = seriesInfo.barGap;\n        (barGap != null) && (columnsOnAxis.gap = barGap);\n        var barCategoryGap = seriesInfo.barCategoryGap;\n        (barCategoryGap != null) && (columnsOnAxis.categoryGap = barCategoryGap);\n    });\n\n    var result = {};\n\n    each$1(columnsMap, function (columnsOnAxis, coordSysName) {\n\n        result[coordSysName] = {};\n\n        var stacks = columnsOnAxis.stacks;\n        var bandWidth = columnsOnAxis.bandWidth;\n        var categoryGap = parsePercent$1(columnsOnAxis.categoryGap, bandWidth);\n        var barGapPercent = parsePercent$1(columnsOnAxis.gap, 1);\n\n        var remainedWidth = columnsOnAxis.remainedWidth;\n        var autoWidthCount = columnsOnAxis.autoWidthCount;\n        var autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        // Find if any auto calculated bar exceeded maxBarWidth\n        each$1(stacks, function (column, stack) {\n            var maxWidth = column.maxWidth;\n            if (maxWidth && maxWidth < autoWidth) {\n                maxWidth = Math.min(maxWidth, remainedWidth);\n                if (column.width) {\n                    maxWidth = Math.min(maxWidth, column.width);\n                }\n                remainedWidth -= maxWidth;\n                column.width = maxWidth;\n                autoWidthCount--;\n            }\n        });\n\n        // Recalculate width again\n        autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        var widthSum = 0;\n        var lastColumn;\n        each$1(stacks, function (column, idx) {\n            if (!column.width) {\n                column.width = autoWidth;\n            }\n            lastColumn = column;\n            widthSum += column.width * (1 + barGapPercent);\n        });\n        if (lastColumn) {\n            widthSum -= lastColumn.width * barGapPercent;\n        }\n\n        var offset = -widthSum / 2;\n        each$1(stacks, function (column, stackId) {\n            result[coordSysName][stackId] = result[coordSysName][stackId] || {\n                offset: offset,\n                width: column.width\n            };\n\n            offset += column.width * (1 + barGapPercent);\n        });\n    });\n\n    return result;\n}\n\n/**\n * @param {Object} barWidthAndOffset The result of makeColumnLayout\n * @param {module:echarts/coord/Axis} axis\n * @param {module:echarts/model/Series} [seriesModel] If not provided, return all.\n * @return {Object} {stackId: {offset, width}} or {offset, width} if seriesModel provided.\n */\nfunction retrieveColumnLayout(barWidthAndOffset, axis, seriesModel) {\n    if (barWidthAndOffset && axis) {\n        var result = barWidthAndOffset[getAxisKey(axis)];\n        if (result != null && seriesModel != null) {\n            result = result[getSeriesStackId(seriesModel)];\n        }\n        return result;\n    }\n}\n\n/**\n * @param {string} seriesType\n * @param {module:echarts/model/Global} ecModel\n */\nfunction layout(seriesType, ecModel) {\n\n    var seriesModels = prepareLayoutBarSeries(seriesType, ecModel);\n    var barWidthAndOffset = makeColumnLayout(seriesModels);\n\n    var lastStackCoords = {};\n    each$1(seriesModels, function (seriesModel) {\n\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n\n        var stackId = getSeriesStackId(seriesModel);\n        var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId];\n        var columnOffset = columnLayoutInfo.offset;\n        var columnWidth = columnLayoutInfo.width;\n        var valueAxis = cartesian.getOtherAxis(baseAxis);\n\n        var barMinHeight = seriesModel.get('barMinHeight') || 0;\n\n        lastStackCoords[stackId] = lastStackCoords[stackId] || [];\n        data.setLayout({\n            offset: columnOffset,\n            size: columnWidth\n        });\n\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var stacked = isDimensionStacked(data, valueDim /*, baseDim*/);\n        var isValueAxisH = valueAxis.isHorizontal();\n\n        var valueAxisStart = getValueAxisStart(baseAxis, valueAxis, stacked);\n\n        for (var idx = 0, len = data.count(); idx < len; idx++) {\n            var value = data.get(valueDim, idx);\n            var baseValue = data.get(baseDim, idx);\n\n            if (isNaN(value)) {\n                continue;\n            }\n\n            var sign = value >= 0 ? 'p' : 'n';\n            var baseCoord = valueAxisStart;\n\n            // Because of the barMinHeight, we can not use the value in\n            // stackResultDimension directly.\n            if (stacked) {\n                // Only ordinal axis can be stacked.\n                if (!lastStackCoords[stackId][baseValue]) {\n                    lastStackCoords[stackId][baseValue] = {\n                        p: valueAxisStart, // Positive stack\n                        n: valueAxisStart  // Negative stack\n                    };\n                }\n                // Should also consider #4243\n                baseCoord = lastStackCoords[stackId][baseValue][sign];\n            }\n\n            var x;\n            var y;\n            var width;\n            var height;\n\n            if (isValueAxisH) {\n                var coord = cartesian.dataToPoint([value, baseValue]);\n                x = baseCoord;\n                y = coord[1] + columnOffset;\n                width = coord[0] - valueAxisStart;\n                height = columnWidth;\n\n                if (Math.abs(width) < barMinHeight) {\n                    width = (width < 0 ? -1 : 1) * barMinHeight;\n                }\n                stacked && (lastStackCoords[stackId][baseValue][sign] += width);\n            }\n            else {\n                var coord = cartesian.dataToPoint([baseValue, value]);\n                x = coord[0] + columnOffset;\n                y = baseCoord;\n                width = columnWidth;\n                height = coord[1] - valueAxisStart;\n\n                if (Math.abs(height) < barMinHeight) {\n                    // Include zero to has a positive bar\n                    height = (height <= 0 ? -1 : 1) * barMinHeight;\n                }\n                stacked && (lastStackCoords[stackId][baseValue][sign] += height);\n            }\n\n            data.setItemLayout(idx, {\n                x: x,\n                y: y,\n                width: width,\n                height: height\n            });\n        }\n\n    }, this);\n}\n\n// TODO: Do not support stack in large mode yet.\nvar largeLayout = {\n\n    seriesType: 'bar',\n\n    plan: createRenderPlanner(),\n\n    reset: function (seriesModel) {\n        if (!isOnCartesian(seriesModel) || !isInLargeMode(seriesModel)) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var valueAxis = cartesian.getOtherAxis(baseAxis);\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var valueAxisHorizontal = valueAxis.isHorizontal();\n        var valueDimIdx = valueAxisHorizontal ? 0 : 1;\n\n        var barWidth = retrieveColumnLayout(\n            makeColumnLayout([seriesModel]), baseAxis, seriesModel\n        ).width;\n        if (!(barWidth > LARGE_BAR_MIN_WIDTH)) { // jshint ignore:line\n            barWidth = LARGE_BAR_MIN_WIDTH;\n        }\n\n        return {progress: progress};\n\n        function progress(params, data) {\n            var largePoints = new LargeArr(params.count * 2);\n            var dataIndex;\n            var coord = [];\n            var valuePair = [];\n            var offset = 0;\n\n            while ((dataIndex = params.next()) != null) {\n                valuePair[valueDimIdx] = data.get(valueDim, dataIndex);\n                valuePair[1 - valueDimIdx] = data.get(baseDim, dataIndex);\n\n                coord = cartesian.dataToPoint(valuePair, null, coord);\n                largePoints[offset++] = coord[0];\n                largePoints[offset++] = coord[1];\n            }\n\n            data.setLayout({\n                largePoints: largePoints,\n                barWidth: barWidth,\n                valueAxisStart: getValueAxisStart(baseAxis, valueAxis, false),\n                valueAxisHorizontal: valueAxisHorizontal\n            });\n        }\n    }\n};\n\nfunction isOnCartesian(seriesModel) {\n    return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d';\n}\n\nfunction isInLargeMode(seriesModel) {\n    return seriesModel.pipelineContext && seriesModel.pipelineContext.large;\n}\n\n// See cases in `test/bar-start.html` and `#7412`, `#8747`.\nfunction getValueAxisStart(baseAxis, valueAxis, stacked) {\n    var extent = valueAxis.getGlobalExtent();\n    var min;\n    var max;\n    if (extent[0] > extent[1]) {\n        min = extent[1];\n        max = extent[0];\n    }\n    else {\n        min = extent[0];\n        max = extent[1];\n    }\n\n    var valueStart = valueAxis.toGlobalCoord(valueAxis.dataToCoord(0));\n    valueStart < min && (valueStart = min);\n    valueStart > max && (valueStart = max);\n\n    return valueStart;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The \"scaleLevels\" was originally copied from \"d3.js\" with some\n* modifications made for this project.\n* (See more details in the comment on the definition of \"scaleLevels\" below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\n\n// [About UTC and local time zone]:\n// In most cases, `number.parseDate` will treat input data string as local time\n// (except time zone is specified in time string). And `format.formateTime` returns\n// local time by default. option.useUTC is false by default. This design have\n// concidered these common case:\n// (1) Time that is persistent in server is in UTC, but it is needed to be diplayed\n// in local time by default.\n// (2) By default, the input data string (e.g., '2011-01-02') should be displayed\n// as its original time, without any time difference.\n\nvar intervalScaleProto = IntervalScale.prototype;\n\nvar mathCeil = Math.ceil;\nvar mathFloor = Math.floor;\nvar ONE_SECOND = 1000;\nvar ONE_MINUTE = ONE_SECOND * 60;\nvar ONE_HOUR = ONE_MINUTE * 60;\nvar ONE_DAY = ONE_HOUR * 24;\n\n// FIXME 公用？\nvar bisect = function (a, x, lo, hi) {\n    while (lo < hi) {\n        var mid = lo + hi >>> 1;\n        if (a[mid][1] < x) {\n            lo = mid + 1;\n        }\n        else {\n            hi = mid;\n        }\n    }\n    return lo;\n};\n\n/**\n * @alias module:echarts/coord/scale/Time\n * @constructor\n */\nvar TimeScale = IntervalScale.extend({\n    type: 'time',\n\n    /**\n     * @override\n     */\n    getLabel: function (val) {\n        var stepLvl = this._stepLvl;\n\n        var date = new Date(val);\n\n        return formatTime(stepLvl[0], date, this.getSetting('useUTC'));\n    },\n\n    /**\n     * @override\n     */\n    niceExtent: function (opt) {\n        var extent = this._extent;\n        // If extent start and end are same, expand them\n        if (extent[0] === extent[1]) {\n            // Expand extent\n            extent[0] -= ONE_DAY;\n            extent[1] += ONE_DAY;\n        }\n        // If there are no data and extent are [Infinity, -Infinity]\n        if (extent[1] === -Infinity && extent[0] === Infinity) {\n            var d = new Date();\n            extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate());\n            extent[0] = extent[1] - ONE_DAY;\n        }\n\n        this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);\n\n        // var extent = this._extent;\n        var interval = this._interval;\n\n        if (!opt.fixMin) {\n            extent[0] = round$2(mathFloor(extent[0] / interval) * interval);\n        }\n        if (!opt.fixMax) {\n            extent[1] = round$2(mathCeil(extent[1] / interval) * interval);\n        }\n    },\n\n    /**\n     * @override\n     */\n    niceTicks: function (approxTickNum, minInterval, maxInterval) {\n        approxTickNum = approxTickNum || 10;\n\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        var approxInterval = span / approxTickNum;\n\n        if (minInterval != null && approxInterval < minInterval) {\n            approxInterval = minInterval;\n        }\n        if (maxInterval != null && approxInterval > maxInterval) {\n            approxInterval = maxInterval;\n        }\n\n        var scaleLevelsLen = scaleLevels.length;\n        var idx = bisect(scaleLevels, approxInterval, 0, scaleLevelsLen);\n\n        var level = scaleLevels[Math.min(idx, scaleLevelsLen - 1)];\n        var interval = level[1];\n        // Same with interval scale if span is much larger than 1 year\n        if (level[0] === 'year') {\n            var yearSpan = span / interval;\n\n            // From \"Nice Numbers for Graph Labels\" of Graphic Gems\n            // var niceYearSpan = numberUtil.nice(yearSpan, false);\n            var yearStep = nice(yearSpan / approxTickNum, true);\n\n            interval *= yearStep;\n        }\n\n        var timezoneOffset = this.getSetting('useUTC')\n            ? 0 : (new Date(+extent[0] || +extent[1])).getTimezoneOffset() * 60 * 1000;\n        var niceExtent = [\n            Math.round(mathCeil((extent[0] - timezoneOffset) / interval) * interval + timezoneOffset),\n            Math.round(mathFloor((extent[1] - timezoneOffset) / interval) * interval + timezoneOffset)\n        ];\n\n        fixExtent(niceExtent, extent);\n\n        this._stepLvl = level;\n        // Interval will be used in getTicks\n        this._interval = interval;\n        this._niceExtent = niceExtent;\n    },\n\n    parse: function (val) {\n        // val might be float.\n        return +parseDate(val);\n    }\n});\n\neach$1(['contain', 'normalize'], function (methodName) {\n    TimeScale.prototype[methodName] = function (val) {\n        return intervalScaleProto[methodName].call(this, this.parse(val));\n    };\n});\n\n/**\n * This implementation was originally copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/b516d77fb8566b576088e73410437494717ada26/src/time/scale.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n */\nvar scaleLevels = [\n    // Format              interval\n    ['hh:mm:ss', ONE_SECOND],          // 1s\n    ['hh:mm:ss', ONE_SECOND * 5],      // 5s\n    ['hh:mm:ss', ONE_SECOND * 10],     // 10s\n    ['hh:mm:ss', ONE_SECOND * 15],     // 15s\n    ['hh:mm:ss', ONE_SECOND * 30],     // 30s\n    ['hh:mm\\nMM-dd', ONE_MINUTE],      // 1m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 5],  // 5m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 10], // 10m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 15], // 15m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 30], // 30m\n    ['hh:mm\\nMM-dd', ONE_HOUR],        // 1h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 2],    // 2h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 6],    // 6h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 12],   // 12h\n    ['MM-dd\\nyyyy', ONE_DAY],          // 1d\n    ['MM-dd\\nyyyy', ONE_DAY * 2],      // 2d\n    ['MM-dd\\nyyyy', ONE_DAY * 3],      // 3d\n    ['MM-dd\\nyyyy', ONE_DAY * 4],      // 4d\n    ['MM-dd\\nyyyy', ONE_DAY * 5],      // 5d\n    ['MM-dd\\nyyyy', ONE_DAY * 6],      // 6d\n    ['week', ONE_DAY * 7],             // 7d\n    ['MM-dd\\nyyyy', ONE_DAY * 10],     // 10d\n    ['week', ONE_DAY * 14],            // 2w\n    ['week', ONE_DAY * 21],            // 3w\n    ['month', ONE_DAY * 31],           // 1M\n    ['week', ONE_DAY * 42],            // 6w\n    ['month', ONE_DAY * 62],           // 2M\n    ['week', ONE_DAY * 70],            // 10w\n    ['quarter', ONE_DAY * 95],         // 3M\n    ['month', ONE_DAY * 31 * 4],       // 4M\n    ['month', ONE_DAY * 31 * 5],       // 5M\n    ['half-year', ONE_DAY * 380 / 2],  // 6M\n    ['month', ONE_DAY * 31 * 8],       // 8M\n    ['month', ONE_DAY * 31 * 10],      // 10M\n    ['year', ONE_DAY * 380]            // 1Y\n];\n\n/**\n * @param {module:echarts/model/Model}\n * @return {module:echarts/scale/Time}\n */\nTimeScale.create = function (model) {\n    return new TimeScale({useUTC: model.ecModel.get('useUTC')});\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Log scale\n * @module echarts/scale/Log\n */\n\n// Use some method of IntervalScale\nvar scaleProto$1 = Scale.prototype;\nvar intervalScaleProto$1 = IntervalScale.prototype;\n\nvar getPrecisionSafe$1 = getPrecisionSafe;\nvar roundingErrorFix = round$2;\n\nvar mathFloor$1 = Math.floor;\nvar mathCeil$1 = Math.ceil;\nvar mathPow$1 = Math.pow;\n\nvar mathLog = Math.log;\n\nvar LogScale = Scale.extend({\n\n    type: 'log',\n\n    base: 10,\n\n    $constructor: function () {\n        Scale.apply(this, arguments);\n        this._originalScale = new IntervalScale();\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getTicks: function () {\n        var originalScale = this._originalScale;\n        var extent = this._extent;\n        var originalExtent = originalScale.getExtent();\n\n        return map(intervalScaleProto$1.getTicks.call(this), function (val) {\n            var powVal = round$2(mathPow$1(this.base, val));\n\n            // Fix #4158\n            powVal = (val === extent[0] && originalScale.__fixMin)\n                ? fixRoundingError(powVal, originalExtent[0])\n                : powVal;\n            powVal = (val === extent[1] && originalScale.__fixMax)\n                ? fixRoundingError(powVal, originalExtent[1])\n                : powVal;\n\n            return powVal;\n        }, this);\n    },\n\n    /**\n     * @param {number} val\n     * @return {string}\n     */\n    getLabel: intervalScaleProto$1.getLabel,\n\n    /**\n     * @param  {number} val\n     * @return {number}\n     */\n    scale: function (val) {\n        val = scaleProto$1.scale.call(this, val);\n        return mathPow$1(this.base, val);\n    },\n\n    /**\n     * @param {number} start\n     * @param {number} end\n     */\n    setExtent: function (start, end) {\n        var base = this.base;\n        start = mathLog(start) / mathLog(base);\n        end = mathLog(end) / mathLog(base);\n        intervalScaleProto$1.setExtent.call(this, start, end);\n    },\n\n    /**\n     * @return {number} end\n     */\n    getExtent: function () {\n        var base = this.base;\n        var extent = scaleProto$1.getExtent.call(this);\n        extent[0] = mathPow$1(base, extent[0]);\n        extent[1] = mathPow$1(base, extent[1]);\n\n        // Fix #4158\n        var originalScale = this._originalScale;\n        var originalExtent = originalScale.getExtent();\n        originalScale.__fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0]));\n        originalScale.__fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1]));\n\n        return extent;\n    },\n\n    /**\n     * @param  {Array.<number>} extent\n     */\n    unionExtent: function (extent) {\n        this._originalScale.unionExtent(extent);\n\n        var base = this.base;\n        extent[0] = mathLog(extent[0]) / mathLog(base);\n        extent[1] = mathLog(extent[1]) / mathLog(base);\n        scaleProto$1.unionExtent.call(this, extent);\n    },\n\n    /**\n     * @override\n     */\n    unionExtentFromData: function (data, dim) {\n        // TODO\n        // filter value that <= 0\n        this.unionExtent(data.getApproximateExtent(dim));\n    },\n\n    /**\n     * Update interval and extent of intervals for nice ticks\n     * @param  {number} [approxTickNum = 10] Given approx tick number\n     */\n    niceTicks: function (approxTickNum) {\n        approxTickNum = approxTickNum || 10;\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        if (span === Infinity || span <= 0) {\n            return;\n        }\n\n        var interval = quantity(span);\n        var err = approxTickNum / span * interval;\n\n        // Filter ticks to get closer to the desired count.\n        if (err <= 0.5) {\n            interval *= 10;\n        }\n\n        // Interval should be integer\n        while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) {\n            interval *= 10;\n        }\n\n        var niceExtent = [\n            round$2(mathCeil$1(extent[0] / interval) * interval),\n            round$2(mathFloor$1(extent[1] / interval) * interval)\n        ];\n\n        this._interval = interval;\n        this._niceExtent = niceExtent;\n    },\n\n    /**\n     * Nice extent.\n     * @override\n     */\n    niceExtent: function (opt) {\n        intervalScaleProto$1.niceExtent.call(this, opt);\n\n        var originalScale = this._originalScale;\n        originalScale.__fixMin = opt.fixMin;\n        originalScale.__fixMax = opt.fixMax;\n    }\n\n});\n\neach$1(['contain', 'normalize'], function (methodName) {\n    LogScale.prototype[methodName] = function (val) {\n        val = mathLog(val) / mathLog(this.base);\n        return scaleProto$1[methodName].call(this, val);\n    };\n});\n\nLogScale.create = function () {\n    return new LogScale();\n};\n\nfunction fixRoundingError(val, originalVal) {\n    return roundingErrorFix(val, getPrecisionSafe$1(originalVal));\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Get axis scale extent before niced.\n * Item of returned array can only be number (including Infinity and NaN).\n */\nfunction getScaleExtent(scale, model) {\n    var scaleType = scale.type;\n\n    var min = model.getMin();\n    var max = model.getMax();\n    var fixMin = min != null;\n    var fixMax = max != null;\n    var originalExtent = scale.getExtent();\n\n    var axisDataLen;\n    var boundaryGap;\n    var span;\n    if (scaleType === 'ordinal') {\n        axisDataLen = model.getCategories().length;\n    }\n    else {\n        boundaryGap = model.get('boundaryGap');\n        if (!isArray(boundaryGap)) {\n            boundaryGap = [boundaryGap || 0, boundaryGap || 0];\n        }\n        if (typeof boundaryGap[0] === 'boolean') {\n            if (__DEV__) {\n                console.warn('Boolean type for boundaryGap is only '\n                    + 'allowed for ordinal axis. Please use string in '\n                    + 'percentage instead, e.g., \"20%\". Currently, '\n                    + 'boundaryGap is set to be 0.');\n            }\n            boundaryGap = [0, 0];\n        }\n        boundaryGap[0] = parsePercent$1(boundaryGap[0], 1);\n        boundaryGap[1] = parsePercent$1(boundaryGap[1], 1);\n        span = (originalExtent[1] - originalExtent[0])\n            || Math.abs(originalExtent[0]);\n    }\n\n    // Notice: When min/max is not set (that is, when there are null/undefined,\n    // which is the most common case), these cases should be ensured:\n    // (1) For 'ordinal', show all axis.data.\n    // (2) For others:\n    //      + `boundaryGap` is applied (if min/max set, boundaryGap is\n    //      disabled).\n    //      + If `needCrossZero`, min/max should be zero, otherwise, min/max should\n    //      be the result that originalExtent enlarged by boundaryGap.\n    // (3) If no data, it should be ensured that `scale.setBlank` is set.\n\n    // FIXME\n    // (1) When min/max is 'dataMin' or 'dataMax', should boundaryGap be able to used?\n    // (2) When `needCrossZero` and all data is positive/negative, should it be ensured\n    // that the results processed by boundaryGap are positive/negative?\n\n    if (min == null) {\n        min = scaleType === 'ordinal'\n            ? (axisDataLen ? 0 : NaN)\n            : originalExtent[0] - boundaryGap[0] * span;\n    }\n    if (max == null) {\n        max = scaleType === 'ordinal'\n            ? (axisDataLen ? axisDataLen - 1 : NaN)\n            : originalExtent[1] + boundaryGap[1] * span;\n    }\n\n    if (min === 'dataMin') {\n        min = originalExtent[0];\n    }\n    else if (typeof min === 'function') {\n        min = min({\n            min: originalExtent[0],\n            max: originalExtent[1]\n        });\n    }\n\n    if (max === 'dataMax') {\n        max = originalExtent[1];\n    }\n    else if (typeof max === 'function') {\n        max = max({\n            min: originalExtent[0],\n            max: originalExtent[1]\n        });\n    }\n\n    (min == null || !isFinite(min)) && (min = NaN);\n    (max == null || !isFinite(max)) && (max = NaN);\n\n    scale.setBlank(\n        eqNaN(min)\n        || eqNaN(max)\n        || (scaleType === 'ordinal' && !scale.getOrdinalMeta().categories.length)\n    );\n\n    // Evaluate if axis needs cross zero\n    if (model.getNeedCrossZero()) {\n        // Axis is over zero and min is not set\n        if (min > 0 && max > 0 && !fixMin) {\n            min = 0;\n        }\n        // Axis is under zero and max is not set\n        if (min < 0 && max < 0 && !fixMax) {\n            max = 0;\n        }\n    }\n\n    // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis\n    // is base axis\n    // FIXME\n    // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly.\n    // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent?\n    //     Should not depend on series type `bar`?\n    // (3) Fix that might overlap when using dataZoom.\n    // (4) Consider other chart types using `barGrid`?\n    // See #6728, #4862, `test/bar-overflow-time-plot.html`\n    var ecModel = model.ecModel;\n    if (ecModel && (scaleType === 'time' /*|| scaleType === 'interval' */)) {\n        var barSeriesModels = prepareLayoutBarSeries('bar', ecModel);\n        var isBaseAxisAndHasBarSeries;\n\n        each$1(barSeriesModels, function (seriesModel) {\n            isBaseAxisAndHasBarSeries |= seriesModel.getBaseAxis() === model.axis;\n        });\n\n        if (isBaseAxisAndHasBarSeries) {\n            // Calculate placement of bars on axis\n            var barWidthAndOffset = makeColumnLayout(barSeriesModels);\n\n            // Adjust axis min and max to account for overflow\n            var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset);\n            min = adjustedScale.min;\n            max = adjustedScale.max;\n        }\n    }\n\n    return [min, max];\n}\n\nfunction adjustScaleForOverflow(min, max, model, barWidthAndOffset) {\n\n    // Get Axis Length\n    var axisExtent = model.axis.getExtent();\n    var axisLength = axisExtent[1] - axisExtent[0];\n\n    // Get bars on current base axis and calculate min and max overflow\n    var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis);\n    if (barsOnCurrentAxis === undefined) {\n        return {min: min, max: max};\n    }\n\n    var minOverflow = Infinity;\n    each$1(barsOnCurrentAxis, function (item) {\n        minOverflow = Math.min(item.offset, minOverflow);\n    });\n    var maxOverflow = -Infinity;\n    each$1(barsOnCurrentAxis, function (item) {\n        maxOverflow = Math.max(item.offset + item.width, maxOverflow);\n    });\n    minOverflow = Math.abs(minOverflow);\n    maxOverflow = Math.abs(maxOverflow);\n    var totalOverFlow = minOverflow + maxOverflow;\n\n    // Calulate required buffer based on old range and overflow\n    var oldRange = max - min;\n    var oldRangePercentOfNew = (1 - (minOverflow + maxOverflow) / axisLength);\n    var overflowBuffer = ((oldRange / oldRangePercentOfNew) - oldRange);\n\n    max += overflowBuffer * (maxOverflow / totalOverFlow);\n    min -= overflowBuffer * (minOverflow / totalOverFlow);\n\n    return {min: min, max: max};\n}\n\nfunction niceScaleExtent(scale, model) {\n    var extent = getScaleExtent(scale, model);\n    var fixMin = model.getMin() != null;\n    var fixMax = model.getMax() != null;\n    var splitNumber = model.get('splitNumber');\n\n    if (scale.type === 'log') {\n        scale.base = model.get('logBase');\n    }\n\n    var scaleType = scale.type;\n    scale.setExtent(extent[0], extent[1]);\n    scale.niceExtent({\n        splitNumber: splitNumber,\n        fixMin: fixMin,\n        fixMax: fixMax,\n        minInterval: (scaleType === 'interval' || scaleType === 'time')\n            ? model.get('minInterval') : null,\n        maxInterval: (scaleType === 'interval' || scaleType === 'time')\n            ? model.get('maxInterval') : null\n    });\n\n    // If some one specified the min, max. And the default calculated interval\n    // is not good enough. He can specify the interval. It is often appeared\n    // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard\n    // to be 60.\n    // FIXME\n    var interval = model.get('interval');\n    if (interval != null) {\n        scale.setInterval && scale.setInterval(interval);\n    }\n}\n\n/**\n * @param {module:echarts/model/Model} model\n * @param {string} [axisType] Default retrieve from model.type\n * @return {module:echarts/scale/*}\n */\nfunction createScaleByModel(model, axisType) {\n    axisType = axisType || model.get('type');\n    if (axisType) {\n        switch (axisType) {\n            // Buildin scale\n            case 'category':\n                return new OrdinalScale(\n                    model.getOrdinalMeta\n                        ? model.getOrdinalMeta()\n                        : model.getCategories(),\n                    [Infinity, -Infinity]\n                );\n            case 'value':\n                return new IntervalScale();\n            // Extended scale, like time and log\n            default:\n                return (Scale.getClass(axisType) || IntervalScale).create(model);\n        }\n    }\n}\n\n/**\n * Check if the axis corss 0\n */\nfunction ifAxisCrossZero(axis) {\n    var dataExtent = axis.scale.getExtent();\n    var min = dataExtent[0];\n    var max = dataExtent[1];\n    return !((min > 0 && max > 0) || (min < 0 && max < 0));\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @return {Function} Label formatter function.\n *         param: {number} tickValue,\n *         param: {number} idx, the index in all ticks.\n *                         If category axis, this param is not requied.\n *         return: {string} label string.\n */\nfunction makeLabelFormatter(axis) {\n    var labelFormatter = axis.getLabelModel().get('formatter');\n    var categoryTickStart = axis.type === 'category' ? axis.scale.getExtent()[0] : null;\n\n    if (typeof labelFormatter === 'string') {\n        labelFormatter = (function (tpl) {\n            return function (val) {\n                // For category axis, get raw value; for numeric axis,\n                // get foramtted label like '1,333,444'.\n                val = axis.scale.getLabel(val);\n                return tpl.replace('{value}', val != null ? val : '');\n            };\n        })(labelFormatter);\n        // Consider empty array\n        return labelFormatter;\n    }\n    else if (typeof labelFormatter === 'function') {\n        return function (tickValue, idx) {\n            // The original intention of `idx` is \"the index of the tick in all ticks\".\n            // But the previous implementation of category axis do not consider the\n            // `axisLabel.interval`, which cause that, for example, the `interval` is\n            // `1`, then the ticks \"name5\", \"name7\", \"name9\" are displayed, where the\n            // corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep\n            // the definition here for back compatibility.\n            if (categoryTickStart != null) {\n                idx = tickValue - categoryTickStart;\n            }\n            return labelFormatter(getAxisRawValue(axis, tickValue), idx);\n        };\n    }\n    else {\n        return function (tick) {\n            return axis.scale.getLabel(tick);\n        };\n    }\n}\n\nfunction getAxisRawValue(axis, value) {\n    // In category axis with data zoom, tick is not the original\n    // index of axis.data. So tick should not be exposed to user\n    // in category axis.\n    return axis.type === 'category' ? axis.scale.getLabel(value) : value;\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @return {module:zrender/core/BoundingRect} Be null/undefined if no labels.\n */\nfunction estimateLabelUnionRect(axis) {\n    var axisModel = axis.model;\n    var scale = axis.scale;\n\n    if (!axisModel.get('axisLabel.show') || scale.isBlank()) {\n        return;\n    }\n\n    var isCategory = axis.type === 'category';\n\n    var realNumberScaleTicks;\n    var tickCount;\n    var categoryScaleExtent = scale.getExtent();\n\n    // Optimize for large category data, avoid call `getTicks()`.\n    if (isCategory) {\n        tickCount = scale.count();\n    }\n    else {\n        realNumberScaleTicks = scale.getTicks();\n        tickCount = realNumberScaleTicks.length;\n    }\n\n    var axisLabelModel = axis.getLabelModel();\n    var labelFormatter = makeLabelFormatter(axis);\n\n    var rect;\n    var step = 1;\n    // Simple optimization for large amount of labels\n    if (tickCount > 40) {\n        step = Math.ceil(tickCount / 40);\n    }\n    for (var i = 0; i < tickCount; i += step) {\n        var tickValue = realNumberScaleTicks ? realNumberScaleTicks[i] : categoryScaleExtent[0] + i;\n        var label = labelFormatter(tickValue);\n        var unrotatedSingleRect = axisLabelModel.getTextRect(label);\n        var singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0);\n\n        rect ? rect.union(singleRect) : (rect = singleRect);\n    }\n\n    return rect;\n}\n\nfunction rotateTextRect(textRect, rotate) {\n    var rotateRadians = rotate * Math.PI / 180;\n    var boundingBox = textRect.plain();\n    var beforeWidth = boundingBox.width;\n    var beforeHeight = boundingBox.height;\n    var afterWidth = beforeWidth * Math.cos(rotateRadians) + beforeHeight * Math.sin(rotateRadians);\n    var afterHeight = beforeWidth * Math.sin(rotateRadians) + beforeHeight * Math.cos(rotateRadians);\n    var rotatedRect = new BoundingRect(boundingBox.x, boundingBox.y, afterWidth, afterHeight);\n\n    return rotatedRect;\n}\n\n/**\n * @param {module:echarts/src/model/Model} model axisLabelModel or axisTickModel\n * @return {number|String} Can be null|'auto'|number|function\n */\nfunction getOptionCategoryInterval(model) {\n    var interval = model.get('interval');\n    return interval == null ? 'auto' : interval;\n}\n\n/**\n * Set `categoryInterval` as 0 implicitly indicates that\n * show all labels reguardless of overlap.\n * @param {Object} axis axisModel.axis\n * @return {boolean}\n */\nfunction shouldShowAllLabels(axis) {\n    return axis.type === 'category'\n        && getOptionCategoryInterval(axis.getLabelModel()) === 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import * as axisHelper from './axisHelper';\n\nvar axisModelCommonMixin = {\n\n    /**\n     * @param {boolean} origin\n     * @return {number|string} min value or 'dataMin' or null/undefined (means auto) or NaN\n     */\n    getMin: function (origin) {\n        var option = this.option;\n        var min = (!origin && option.rangeStart != null)\n            ? option.rangeStart : option.min;\n\n        if (this.axis\n            && min != null\n            && min !== 'dataMin'\n            && typeof min !== 'function'\n            && !eqNaN(min)\n        ) {\n            min = this.axis.scale.parse(min);\n        }\n        return min;\n    },\n\n    /**\n     * @param {boolean} origin\n     * @return {number|string} max value or 'dataMax' or null/undefined (means auto) or NaN\n     */\n    getMax: function (origin) {\n        var option = this.option;\n        var max = (!origin && option.rangeEnd != null)\n            ? option.rangeEnd : option.max;\n\n        if (this.axis\n            && max != null\n            && max !== 'dataMax'\n            && typeof max !== 'function'\n            && !eqNaN(max)\n        ) {\n            max = this.axis.scale.parse(max);\n        }\n        return max;\n    },\n\n    /**\n     * @return {boolean}\n     */\n    getNeedCrossZero: function () {\n        var option = this.option;\n        return (option.rangeStart != null || option.rangeEnd != null)\n            ? false : !option.scale;\n    },\n\n    /**\n     * Should be implemented by each axis model if necessary.\n     * @return {module:echarts/model/Component} coordinate system model\n     */\n    getCoordSysModel: noop,\n\n    /**\n     * @param {number} rangeStart Can only be finite number or null/undefined or NaN.\n     * @param {number} rangeEnd Can only be finite number or null/undefined or NaN.\n     */\n    setRange: function (rangeStart, rangeEnd) {\n        this.option.rangeStart = rangeStart;\n        this.option.rangeEnd = rangeEnd;\n    },\n\n    /**\n     * Reset range\n     */\n    resetRange: function () {\n        // rangeStart and rangeEnd is readonly.\n        this.option.rangeStart = this.option.rangeEnd = null;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Symbol factory\n\n/**\n * Triangle shape\n * @inner\n */\nvar Triangle = extendShape({\n    type: 'triangle',\n    shape: {\n        cx: 0,\n        cy: 0,\n        width: 0,\n        height: 0\n    },\n    buildPath: function (path, shape) {\n        var cx = shape.cx;\n        var cy = shape.cy;\n        var width = shape.width / 2;\n        var height = shape.height / 2;\n        path.moveTo(cx, cy - height);\n        path.lineTo(cx + width, cy + height);\n        path.lineTo(cx - width, cy + height);\n        path.closePath();\n    }\n});\n\n/**\n * Diamond shape\n * @inner\n */\nvar Diamond = extendShape({\n    type: 'diamond',\n    shape: {\n        cx: 0,\n        cy: 0,\n        width: 0,\n        height: 0\n    },\n    buildPath: function (path, shape) {\n        var cx = shape.cx;\n        var cy = shape.cy;\n        var width = shape.width / 2;\n        var height = shape.height / 2;\n        path.moveTo(cx, cy - height);\n        path.lineTo(cx + width, cy);\n        path.lineTo(cx, cy + height);\n        path.lineTo(cx - width, cy);\n        path.closePath();\n    }\n});\n\n/**\n * Pin shape\n * @inner\n */\nvar Pin = extendShape({\n    type: 'pin',\n    shape: {\n        // x, y on the cusp\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (path, shape) {\n        var x = shape.x;\n        var y = shape.y;\n        var w = shape.width / 5 * 3;\n        // Height must be larger than width\n        var h = Math.max(w, shape.height);\n        var r = w / 2;\n\n        // Dist on y with tangent point and circle center\n        var dy = r * r / (h - r);\n        var cy = y - h + r + dy;\n        var angle = Math.asin(dy / r);\n        // Dist on x with tangent point and circle center\n        var dx = Math.cos(angle) * r;\n\n        var tanX = Math.sin(angle);\n        var tanY = Math.cos(angle);\n\n        var cpLen = r * 0.6;\n        var cpLen2 = r * 0.7;\n\n        path.moveTo(x - dx, cy + dy);\n\n        path.arc(\n            x, cy, r,\n            Math.PI - angle,\n            Math.PI * 2 + angle\n        );\n        path.bezierCurveTo(\n            x + dx - tanX * cpLen, cy + dy + tanY * cpLen,\n            x, y - cpLen2,\n            x, y\n        );\n        path.bezierCurveTo(\n            x, y - cpLen2,\n            x - dx + tanX * cpLen, cy + dy + tanY * cpLen,\n            x - dx, cy + dy\n        );\n        path.closePath();\n    }\n});\n\n/**\n * Arrow shape\n * @inner\n */\nvar Arrow = extendShape({\n\n    type: 'arrow',\n\n    shape: {\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var height = shape.height;\n        var width = shape.width;\n        var x = shape.x;\n        var y = shape.y;\n        var dx = width / 3 * 2;\n        ctx.moveTo(x, y);\n        ctx.lineTo(x + dx, y + height);\n        ctx.lineTo(x, y + height / 4 * 3);\n        ctx.lineTo(x - dx, y + height);\n        ctx.lineTo(x, y);\n        ctx.closePath();\n    }\n});\n\n/**\n * Map of path contructors\n * @type {Object.<string, module:zrender/graphic/Path>}\n */\nvar symbolCtors = {\n\n    line: Line,\n\n    rect: Rect,\n\n    roundRect: Rect,\n\n    square: Rect,\n\n    circle: Circle,\n\n    diamond: Diamond,\n\n    pin: Pin,\n\n    arrow: Arrow,\n\n    triangle: Triangle\n};\n\nvar symbolShapeMakers = {\n\n    line: function (x, y, w, h, shape) {\n        // FIXME\n        shape.x1 = x;\n        shape.y1 = y + h / 2;\n        shape.x2 = x + w;\n        shape.y2 = y + h / 2;\n    },\n\n    rect: function (x, y, w, h, shape) {\n        shape.x = x;\n        shape.y = y;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    roundRect: function (x, y, w, h, shape) {\n        shape.x = x;\n        shape.y = y;\n        shape.width = w;\n        shape.height = h;\n        shape.r = Math.min(w, h) / 4;\n    },\n\n    square: function (x, y, w, h, shape) {\n        var size = Math.min(w, h);\n        shape.x = x;\n        shape.y = y;\n        shape.width = size;\n        shape.height = size;\n    },\n\n    circle: function (x, y, w, h, shape) {\n        // Put circle in the center of square\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.r = Math.min(w, h) / 2;\n    },\n\n    diamond: function (x, y, w, h, shape) {\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    pin: function (x, y, w, h, shape) {\n        shape.x = x + w / 2;\n        shape.y = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    arrow: function (x, y, w, h, shape) {\n        shape.x = x + w / 2;\n        shape.y = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    triangle: function (x, y, w, h, shape) {\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    }\n};\n\nvar symbolBuildProxies = {};\neach$1(symbolCtors, function (Ctor, name) {\n    symbolBuildProxies[name] = new Ctor();\n});\n\nvar SymbolClz = extendShape({\n\n    type: 'symbol',\n\n    shape: {\n        symbolType: '',\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    beforeBrush: function () {\n        var style = this.style;\n        var shape = this.shape;\n        // FIXME\n        if (shape.symbolType === 'pin' && style.textPosition === 'inside') {\n            style.textPosition = ['50%', '40%'];\n            style.textAlign = 'center';\n            style.textVerticalAlign = 'middle';\n        }\n    },\n\n    buildPath: function (ctx, shape, inBundle) {\n        var symbolType = shape.symbolType;\n        var proxySymbol = symbolBuildProxies[symbolType];\n        if (shape.symbolType !== 'none') {\n            if (!proxySymbol) {\n                // Default rect\n                symbolType = 'rect';\n                proxySymbol = symbolBuildProxies[symbolType];\n            }\n            symbolShapeMakers[symbolType](\n                shape.x, shape.y, shape.width, shape.height, proxySymbol.shape\n            );\n            proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle);\n        }\n    }\n});\n\n// Provide setColor helper method to avoid determine if set the fill or stroke outside\nfunction symbolPathSetColor(color, innerColor) {\n    if (this.type !== 'image') {\n        var symbolStyle = this.style;\n        var symbolShape = this.shape;\n        if (symbolShape && symbolShape.symbolType === 'line') {\n            symbolStyle.stroke = color;\n        }\n        else if (this.__isEmptyBrush) {\n            symbolStyle.stroke = color;\n            symbolStyle.fill = innerColor || '#fff';\n        }\n        else {\n            // FIXME 判断图形默认是填充还是描边，使用 onlyStroke ?\n            symbolStyle.fill && (symbolStyle.fill = color);\n            symbolStyle.stroke && (symbolStyle.stroke = color);\n        }\n        this.dirty(false);\n    }\n}\n\n/**\n * Create a symbol element with given symbol configuration: shape, x, y, width, height, color\n * @param {string} symbolType\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n * @param {string} color\n * @param {boolean} [keepAspect=false] whether to keep the ratio of w/h,\n *                            for path and image only.\n */\nfunction createSymbol(symbolType, x, y, w, h, color, keepAspect) {\n    // TODO Support image object, DynamicImage.\n\n    var isEmpty = symbolType.indexOf('empty') === 0;\n    if (isEmpty) {\n        symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6);\n    }\n    var symbolPath;\n\n    if (symbolType.indexOf('image://') === 0) {\n        symbolPath = makeImage(\n            symbolType.slice(8),\n            new BoundingRect(x, y, w, h),\n            keepAspect ? 'center' : 'cover'\n        );\n    }\n    else if (symbolType.indexOf('path://') === 0) {\n        symbolPath = makePath(\n            symbolType.slice(7),\n            {},\n            new BoundingRect(x, y, w, h),\n            keepAspect ? 'center' : 'cover'\n        );\n    }\n    else {\n        symbolPath = new SymbolClz({\n            shape: {\n                symbolType: symbolType,\n                x: x,\n                y: y,\n                width: w,\n                height: h\n            }\n        });\n    }\n\n    symbolPath.__isEmptyBrush = isEmpty;\n\n    symbolPath.setColor = symbolPathSetColor;\n\n    symbolPath.setColor(color);\n\n    return symbolPath;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import createGraphFromNodeEdge from './chart/helper/createGraphFromNodeEdge';\n/**\n * Create a muti dimension List structure from seriesModel.\n * @param  {module:echarts/model/Model} seriesModel\n * @return {module:echarts/data/List} list\n */\nfunction createList(seriesModel) {\n    return createListFromArray(seriesModel.getSource(), seriesModel);\n}\n\nvar dataStack$1 = {\n    isDimensionStacked: isDimensionStacked,\n    enableDataStack: enableDataStack,\n    getStackedDimension: getStackedDimension\n};\n\n/**\n * Create scale\n * @param {Array.<number>} dataExtent\n * @param {Object|module:echarts/Model} option\n */\nfunction createScale(dataExtent, option) {\n    var axisModel = option;\n    if (!Model.isInstance(option)) {\n        axisModel = new Model(option);\n        mixin(axisModel, axisModelCommonMixin);\n    }\n\n    var scale = createScaleByModel(axisModel);\n    scale.setExtent(dataExtent[0], dataExtent[1]);\n\n    niceScaleExtent(scale, axisModel);\n    return scale;\n}\n\n/**\n * Mixin common methods to axis model,\n *\n * Inlcude methods\n * `getFormattedLabels() => Array.<string>`\n * `getCategories() => Array.<string>`\n * `getMin(origin: boolean) => number`\n * `getMax(origin: boolean) => number`\n * `getNeedCrossZero() => boolean`\n * `setRange(start: number, end: number)`\n * `resetRange()`\n */\nfunction mixinAxisModelCommonMethods(Model$$1) {\n    mixin(Model$$1, axisModelCommonMixin);\n}\n\nvar helper = (Object.freeze || Object)({\n\tcreateList: createList,\n\tgetLayoutRect: getLayoutRect,\n\tdataStack: dataStack$1,\n\tcreateScale: createScale,\n\tmixinAxisModelCommonMethods: mixinAxisModelCommonMethods,\n\tcompleteDimensions: completeDimensions,\n\tcreateDimensions: createDimensions,\n\tcreateSymbol: createSymbol\n});\n\nvar EPSILON$3 = 1e-8;\n\nfunction isAroundEqual$1(a, b) {\n    return Math.abs(a - b) < EPSILON$3;\n}\n\nfunction contain$1(points, x, y) {\n    var w = 0;\n    var p = points[0];\n\n    if (!p) {\n        return false;\n    }\n\n    for (var i = 1; i < points.length; i++) {\n        var p2 = points[i];\n        w += windingLine(p[0], p[1], p2[0], p2[1], x, y);\n        p = p2;\n    }\n\n    // Close polygon\n    var p0 = points[0];\n    if (!isAroundEqual$1(p[0], p0[0]) || !isAroundEqual$1(p[1], p0[1])) {\n        w += windingLine(p[0], p[1], p0[0], p0[1], x, y);\n    }\n\n    return w !== 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/coord/geo/Region\n */\n\n/**\n * @param {string|Region} name\n * @param {Array} geometries\n * @param {Array.<number>} cp\n */\nfunction Region(name, geometries, cp) {\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.name = name;\n\n    /**\n     * @type {Array.<Array>}\n     * @readOnly\n     */\n    this.geometries = geometries;\n\n    if (!cp) {\n        var rect = this.getBoundingRect();\n        cp = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    }\n    else {\n        cp = [cp[0], cp[1]];\n    }\n    /**\n     * @type {Array.<number>}\n     */\n    this.center = cp;\n}\n\nRegion.prototype = {\n\n    constructor: Region,\n\n    properties: null,\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function () {\n        var rect = this._rect;\n        if (rect) {\n            return rect;\n        }\n\n        var MAX_NUMBER = Number.MAX_VALUE;\n        var min$$1 = [MAX_NUMBER, MAX_NUMBER];\n        var max$$1 = [-MAX_NUMBER, -MAX_NUMBER];\n        var min2 = [];\n        var max2 = [];\n        var geometries = this.geometries;\n        for (var i = 0; i < geometries.length; i++) {\n            // Only support polygon\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            // Doesn't consider hole\n            var exterior = geometries[i].exterior;\n            fromPoints(exterior, min2, max2);\n            min(min$$1, min$$1, min2);\n            max(max$$1, max$$1, max2);\n        }\n        // No data\n        if (i === 0) {\n            min$$1[0] = min$$1[1] = max$$1[0] = max$$1[1] = 0;\n        }\n\n        return (this._rect = new BoundingRect(\n            min$$1[0], min$$1[1], max$$1[0] - min$$1[0], max$$1[1] - min$$1[1]\n        ));\n    },\n\n    /**\n     * @param {<Array.<number>} coord\n     * @return {boolean}\n     */\n    contain: function (coord) {\n        var rect = this.getBoundingRect();\n        var geometries = this.geometries;\n        if (!rect.contain(coord[0], coord[1])) {\n            return false;\n        }\n        loopGeo: for (var i = 0, len$$1 = geometries.length; i < len$$1; i++) {\n            // Only support polygon.\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            var exterior = geometries[i].exterior;\n            var interiors = geometries[i].interiors;\n            if (contain$1(exterior, coord[0], coord[1])) {\n                // Not in the region if point is in the hole.\n                for (var k = 0; k < (interiors ? interiors.length : 0); k++) {\n                    if (contain$1(interiors[k])) {\n                        continue loopGeo;\n                    }\n                }\n                return true;\n            }\n        }\n        return false;\n    },\n\n    transformTo: function (x, y, width, height) {\n        var rect = this.getBoundingRect();\n        var aspect = rect.width / rect.height;\n        if (!width) {\n            width = aspect * height;\n        }\n        else if (!height) {\n            height = width / aspect;\n        }\n        var target = new BoundingRect(x, y, width, height);\n        var transform = rect.calculateTransform(target);\n        var geometries = this.geometries;\n        for (var i = 0; i < geometries.length; i++) {\n            // Only support polygon.\n            if (geometries[i].type !== 'polygon') {\n                continue;\n            }\n            var exterior = geometries[i].exterior;\n            var interiors = geometries[i].interiors;\n            for (var p = 0; p < exterior.length; p++) {\n                applyTransform(exterior[p], exterior[p], transform);\n            }\n            for (var h = 0; h < (interiors ? interiors.length : 0); h++) {\n                for (var p = 0; p < interiors[h].length; p++) {\n                    applyTransform(interiors[h][p], interiors[h][p], transform);\n                }\n            }\n        }\n        rect = this._rect;\n        rect.copy(target);\n        // Update center\n        this.center = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    },\n\n    cloneShallow: function (name) {\n        name == null && (name = this.name);\n        var newRegion = new Region(name, this.geometries, this.center);\n        newRegion._rect = this._rect;\n        newRegion.transformTo = null; // Simply avoid to be called.\n        return newRegion;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Parse and decode geo json\n * @module echarts/coord/geo/parseGeoJson\n */\n\nfunction decode(json) {\n    if (!json.UTF8Encoding) {\n        return json;\n    }\n    var encodeScale = json.UTF8Scale;\n    if (encodeScale == null) {\n        encodeScale = 1024;\n    }\n\n    var features = json.features;\n\n    for (var f = 0; f < features.length; f++) {\n        var feature = features[f];\n        var geometry = feature.geometry;\n        var coordinates = geometry.coordinates;\n        var encodeOffsets = geometry.encodeOffsets;\n\n        for (var c = 0; c < coordinates.length; c++) {\n            var coordinate = coordinates[c];\n\n            if (geometry.type === 'Polygon') {\n                coordinates[c] = decodePolygon(\n                    coordinate,\n                    encodeOffsets[c],\n                    encodeScale\n                );\n            }\n            else if (geometry.type === 'MultiPolygon') {\n                for (var c2 = 0; c2 < coordinate.length; c2++) {\n                    var polygon = coordinate[c2];\n                    coordinate[c2] = decodePolygon(\n                        polygon,\n                        encodeOffsets[c][c2],\n                        encodeScale\n                    );\n                }\n            }\n        }\n    }\n    // Has been decoded\n    json.UTF8Encoding = false;\n    return json;\n}\n\nfunction decodePolygon(coordinate, encodeOffsets, encodeScale) {\n    var result = [];\n    var prevX = encodeOffsets[0];\n    var prevY = encodeOffsets[1];\n\n    for (var i = 0; i < coordinate.length; i += 2) {\n        var x = coordinate.charCodeAt(i) - 64;\n        var y = coordinate.charCodeAt(i + 1) - 64;\n        // ZigZag decoding\n        x = (x >> 1) ^ (-(x & 1));\n        y = (y >> 1) ^ (-(y & 1));\n        // Delta deocding\n        x += prevX;\n        y += prevY;\n\n        prevX = x;\n        prevY = y;\n        // Dequantize\n        result.push([x / encodeScale, y / encodeScale]);\n    }\n\n    return result;\n}\n\n/**\n * @alias module:echarts/coord/geo/parseGeoJson\n * @param {Object} geoJson\n * @return {module:zrender/container/Group}\n */\nvar parseGeoJson$1 = function (geoJson) {\n\n    decode(geoJson);\n\n    return map(filter(geoJson.features, function (featureObj) {\n        // Output of mapshaper may have geometry null\n        return featureObj.geometry\n            && featureObj.properties\n            && featureObj.geometry.coordinates.length > 0;\n    }), function (featureObj) {\n        var properties = featureObj.properties;\n        var geo = featureObj.geometry;\n\n        var coordinates = geo.coordinates;\n\n        var geometries = [];\n        if (geo.type === 'Polygon') {\n            geometries.push({\n                type: 'polygon',\n                // According to the GeoJSON specification.\n                // First must be exterior, and the rest are all interior(holes).\n                exterior: coordinates[0],\n                interiors: coordinates.slice(1)\n            });\n        }\n        if (geo.type === 'MultiPolygon') {\n            each$1(coordinates, function (item) {\n                if (item[0]) {\n                    geometries.push({\n                        type: 'polygon',\n                        exterior: item[0],\n                        interiors: item.slice(1)\n                    });\n                }\n            });\n        }\n\n        var region = new Region(\n            properties.name,\n            geometries,\n            properties.cp\n        );\n        region.properties = properties;\n        return region;\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$6 = makeInner();\n\n/**\n * @param {module:echats/coord/Axis} axis\n * @return {Object} {\n *     labels: [{\n *         formattedLabel: string,\n *         rawLabel: string,\n *         tickValue: number\n *     }, ...],\n *     labelCategoryInterval: number\n * }\n */\nfunction createAxisLabels(axis) {\n    // Only ordinal scale support tick interval\n    return axis.type === 'category'\n        ? makeCategoryLabels(axis)\n        : makeRealNumberLabels(axis);\n}\n\n/**\n * @param {module:echats/coord/Axis} axis\n * @param {module:echarts/model/Model} tickModel For example, can be axisTick, splitLine, splitArea.\n * @return {Object} {\n *     ticks: Array.<number>\n *     tickCategoryInterval: number\n * }\n */\nfunction createAxisTicks(axis, tickModel) {\n    // Only ordinal scale support tick interval\n    return axis.type === 'category'\n        ? makeCategoryTicks(axis, tickModel)\n        : {ticks: axis.scale.getTicks()};\n}\n\nfunction makeCategoryLabels(axis) {\n    var labelModel = axis.getLabelModel();\n    var result = makeCategoryLabelsActually(axis, labelModel);\n\n    return (!labelModel.get('show') || axis.scale.isBlank())\n        ? {labels: [], labelCategoryInterval: result.labelCategoryInterval}\n        : result;\n}\n\nfunction makeCategoryLabelsActually(axis, labelModel) {\n    var labelsCache = getListCache(axis, 'labels');\n    var optionLabelInterval = getOptionCategoryInterval(labelModel);\n    var result = listCacheGet(labelsCache, optionLabelInterval);\n\n    if (result) {\n        return result;\n    }\n\n    var labels;\n    var numericLabelInterval;\n\n    if (isFunction$1(optionLabelInterval)) {\n        labels = makeLabelsByCustomizedCategoryInterval(axis, optionLabelInterval);\n    }\n    else {\n        numericLabelInterval = optionLabelInterval === 'auto'\n            ? makeAutoCategoryInterval(axis) : optionLabelInterval;\n        labels = makeLabelsByNumericCategoryInterval(axis, numericLabelInterval);\n    }\n\n    // Cache to avoid calling interval function repeatly.\n    return listCacheSet(labelsCache, optionLabelInterval, {\n        labels: labels, labelCategoryInterval: numericLabelInterval\n    });\n}\n\nfunction makeCategoryTicks(axis, tickModel) {\n    var ticksCache = getListCache(axis, 'ticks');\n    var optionTickInterval = getOptionCategoryInterval(tickModel);\n    var result = listCacheGet(ticksCache, optionTickInterval);\n\n    if (result) {\n        return result;\n    }\n\n    var ticks;\n    var tickCategoryInterval;\n\n    // Optimize for the case that large category data and no label displayed,\n    // we should not return all ticks.\n    if (!tickModel.get('show') || axis.scale.isBlank()) {\n        ticks = [];\n    }\n\n    if (isFunction$1(optionTickInterval)) {\n        ticks = makeLabelsByCustomizedCategoryInterval(axis, optionTickInterval, true);\n    }\n    // Always use label interval by default despite label show. Consider this\n    // scenario, Use multiple grid with the xAxis sync, and only one xAxis shows\n    // labels. `splitLine` and `axisTick` should be consistent in this case.\n    else if (optionTickInterval === 'auto') {\n        var labelsResult = makeCategoryLabelsActually(axis, axis.getLabelModel());\n        tickCategoryInterval = labelsResult.labelCategoryInterval;\n        ticks = map(labelsResult.labels, function (labelItem) {\n            return labelItem.tickValue;\n        });\n    }\n    else {\n        tickCategoryInterval = optionTickInterval;\n        ticks = makeLabelsByNumericCategoryInterval(axis, tickCategoryInterval, true);\n    }\n\n    // Cache to avoid calling interval function repeatly.\n    return listCacheSet(ticksCache, optionTickInterval, {\n        ticks: ticks, tickCategoryInterval: tickCategoryInterval\n    });\n}\n\nfunction makeRealNumberLabels(axis) {\n    var ticks = axis.scale.getTicks();\n    var labelFormatter = makeLabelFormatter(axis);\n    return {\n        labels: map(ticks, function (tickValue, idx) {\n            return {\n                formattedLabel: labelFormatter(tickValue, idx),\n                rawLabel: axis.scale.getLabel(tickValue),\n                tickValue: tickValue\n            };\n        })\n    };\n}\n\n// Large category data calculation is performence sensitive, and ticks and label\n// probably be fetched by multiple times. So we cache the result.\n// axis is created each time during a ec process, so we do not need to clear cache.\nfunction getListCache(axis, prop) {\n    // Because key can be funciton, and cache size always be small, we use array cache.\n    return inner$6(axis)[prop] || (inner$6(axis)[prop] = []);\n}\n\nfunction listCacheGet(cache, key) {\n    for (var i = 0; i < cache.length; i++) {\n        if (cache[i].key === key) {\n            return cache[i].value;\n        }\n    }\n}\n\nfunction listCacheSet(cache, key, value) {\n    cache.push({key: key, value: value});\n    return value;\n}\n\nfunction makeAutoCategoryInterval(axis) {\n    var result = inner$6(axis).autoInterval;\n    return result != null\n        ? result\n        : (inner$6(axis).autoInterval = axis.calculateCategoryInterval());\n}\n\n/**\n * Calculate interval for category axis ticks and labels.\n * To get precise result, at least one of `getRotate` and `isHorizontal`\n * should be implemented in axis.\n */\nfunction calculateCategoryInterval(axis) {\n    var params = fetchAutoCategoryIntervalCalculationParams(axis);\n    var labelFormatter = makeLabelFormatter(axis);\n    var rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI;\n\n    var ordinalScale = axis.scale;\n    var ordinalExtent = ordinalScale.getExtent();\n    // Providing this method is for optimization:\n    // avoid generating a long array by `getTicks`\n    // in large category data case.\n    var tickCount = ordinalScale.count();\n\n    if (ordinalExtent[1] - ordinalExtent[0] < 1) {\n        return 0;\n    }\n\n    var step = 1;\n    // Simple optimization. Empirical value: tick count should less than 40.\n    if (tickCount > 40) {\n        step = Math.max(1, Math.floor(tickCount / 40));\n    }\n    var tickValue = ordinalExtent[0];\n    var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue);\n    var unitW = Math.abs(unitSpan * Math.cos(rotation));\n    var unitH = Math.abs(unitSpan * Math.sin(rotation));\n\n    var maxW = 0;\n    var maxH = 0;\n\n    // Caution: Performance sensitive for large category data.\n    // Consider dataZoom, we should make appropriate step to avoid O(n) loop.\n    for (; tickValue <= ordinalExtent[1]; tickValue += step) {\n        var width = 0;\n        var height = 0;\n\n        // Not precise, do not consider align and vertical align\n        // and each distance from axis line yet.\n        var rect = getBoundingRect(\n            labelFormatter(tickValue), params.font, 'center', 'top'\n        );\n        // Magic number\n        width = rect.width * 1.3;\n        height = rect.height * 1.3;\n\n        // Min size, void long loop.\n        maxW = Math.max(maxW, width, 7);\n        maxH = Math.max(maxH, height, 7);\n    }\n\n    var dw = maxW / unitW;\n    var dh = maxH / unitH;\n    // 0/0 is NaN, 1/0 is Infinity.\n    isNaN(dw) && (dw = Infinity);\n    isNaN(dh) && (dh = Infinity);\n    var interval = Math.max(0, Math.floor(Math.min(dw, dh)));\n\n    var cache = inner$6(axis.model);\n    var lastAutoInterval = cache.lastAutoInterval;\n    var lastTickCount = cache.lastTickCount;\n\n    // Use cache to keep interval stable while moving zoom window,\n    // otherwise the calculated interval might jitter when the zoom\n    // window size is close to the interval-changing size.\n    if (lastAutoInterval != null\n        && lastTickCount != null\n        && Math.abs(lastAutoInterval - interval) <= 1\n        && Math.abs(lastTickCount - tickCount) <= 1\n        // Always choose the bigger one, otherwise the critical\n        // point is not the same when zooming in or zooming out.\n        && lastAutoInterval > interval\n    ) {\n        interval = lastAutoInterval;\n    }\n    // Only update cache if cache not used, otherwise the\n    // changing of interval is too insensitive.\n    else {\n        cache.lastTickCount = tickCount;\n        cache.lastAutoInterval = interval;\n    }\n\n    return interval;\n}\n\nfunction fetchAutoCategoryIntervalCalculationParams(axis) {\n    var labelModel = axis.getLabelModel();\n    return {\n        axisRotate: axis.getRotate\n            ? axis.getRotate()\n            : (axis.isHorizontal && !axis.isHorizontal())\n            ? 90\n            : 0,\n        labelRotate: labelModel.get('rotate') || 0,\n        font: labelModel.getFont()\n    };\n}\n\nfunction makeLabelsByNumericCategoryInterval(axis, categoryInterval, onlyTick) {\n    var labelFormatter = makeLabelFormatter(axis);\n    var ordinalScale = axis.scale;\n    var ordinalExtent = ordinalScale.getExtent();\n    var labelModel = axis.getLabelModel();\n    var result = [];\n\n    // TODO: axisType: ordinalTime, pick the tick from each month/day/year/...\n\n    var step = Math.max((categoryInterval || 0) + 1, 1);\n    var startTick = ordinalExtent[0];\n    var tickCount = ordinalScale.count();\n\n    // Calculate start tick based on zero if possible to keep label consistent\n    // while zooming and moving while interval > 0. Otherwise the selection\n    // of displayable ticks and symbols probably keep changing.\n    // 3 is empirical value.\n    if (startTick !== 0 && step > 1 && tickCount / step > 2) {\n        startTick = Math.round(Math.ceil(startTick / step) * step);\n    }\n\n    // (1) Only add min max label here but leave overlap checking\n    // to render stage, which also ensure the returned list\n    // suitable for splitLine and splitArea rendering.\n    // (2) Scales except category always contain min max label so\n    // do not need to perform this process.\n    var showAllLabel = shouldShowAllLabels(axis);\n    var includeMinLabel = labelModel.get('showMinLabel') || showAllLabel;\n    var includeMaxLabel = labelModel.get('showMaxLabel') || showAllLabel;\n\n    if (includeMinLabel && startTick !== ordinalExtent[0]) {\n        addItem(ordinalExtent[0]);\n    }\n\n    // Optimize: avoid generating large array by `ordinalScale.getTicks()`.\n    var tickValue = startTick;\n    for (; tickValue <= ordinalExtent[1]; tickValue += step) {\n        addItem(tickValue);\n    }\n\n    if (includeMaxLabel && tickValue !== ordinalExtent[1]) {\n        addItem(ordinalExtent[1]);\n    }\n\n    function addItem(tVal) {\n        result.push(onlyTick\n            ? tVal\n            : {\n                formattedLabel: labelFormatter(tVal),\n                rawLabel: ordinalScale.getLabel(tVal),\n                tickValue: tVal\n            }\n        );\n    }\n\n    return result;\n}\n\n// When interval is function, the result `false` means ignore the tick.\n// It is time consuming for large category data.\nfunction makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) {\n    var ordinalScale = axis.scale;\n    var labelFormatter = makeLabelFormatter(axis);\n    var result = [];\n\n    each$1(ordinalScale.getTicks(), function (tickValue) {\n        var rawLabel = ordinalScale.getLabel(tickValue);\n        if (categoryInterval(tickValue, rawLabel)) {\n            result.push(onlyTick\n                ? tickValue\n                : {\n                    formattedLabel: labelFormatter(tickValue),\n                    rawLabel: rawLabel,\n                    tickValue: tickValue\n                }\n            );\n        }\n    });\n\n    return result;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar NORMALIZED_EXTENT = [0, 1];\n\n/**\n * Base class of Axis.\n * @constructor\n */\nvar Axis = function (dim, scale, extent) {\n\n    /**\n     * Axis dimension. Such as 'x', 'y', 'z', 'angle', 'radius'.\n     * @type {string}\n     */\n    this.dim = dim;\n\n    /**\n     * Axis scale\n     * @type {module:echarts/coord/scale/*}\n     */\n    this.scale = scale;\n\n    /**\n     * @type {Array.<number>}\n     * @private\n     */\n    this._extent = extent || [0, 0];\n\n    /**\n     * @type {boolean}\n     */\n    this.inverse = false;\n\n    /**\n     * Usually true when axis has a ordinal scale\n     * @type {boolean}\n     */\n    this.onBand = false;\n};\n\nAxis.prototype = {\n\n    constructor: Axis,\n\n    /**\n     * If axis extent contain given coord\n     * @param {number} coord\n     * @return {boolean}\n     */\n    contain: function (coord) {\n        var extent = this._extent;\n        var min = Math.min(extent[0], extent[1]);\n        var max = Math.max(extent[0], extent[1]);\n        return coord >= min && coord <= max;\n    },\n\n    /**\n     * If axis extent contain given data\n     * @param {number} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this.contain(this.dataToCoord(data));\n    },\n\n    /**\n     * Get coord extent.\n     * @return {Array.<number>}\n     */\n    getExtent: function () {\n        return this._extent.slice();\n    },\n\n    /**\n     * Get precision used for formatting\n     * @param {Array.<number>} [dataExtent]\n     * @return {number}\n     */\n    getPixelPrecision: function (dataExtent) {\n        return getPixelPrecision(\n            dataExtent || this.scale.getExtent(),\n            this._extent\n        );\n    },\n\n    /**\n     * Set coord extent\n     * @param {number} start\n     * @param {number} end\n     */\n    setExtent: function (start, end) {\n        var extent = this._extent;\n        extent[0] = start;\n        extent[1] = end;\n    },\n\n    /**\n     * Convert data to coord. Data is the rank if it has an ordinal scale\n     * @param {number} data\n     * @param  {boolean} clamp\n     * @return {number}\n     */\n    dataToCoord: function (data, clamp) {\n        var extent = this._extent;\n        var scale = this.scale;\n        data = scale.normalize(data);\n\n        if (this.onBand && scale.type === 'ordinal') {\n            extent = extent.slice();\n            fixExtentWithBands(extent, scale.count());\n        }\n\n        return linearMap(data, NORMALIZED_EXTENT, extent, clamp);\n    },\n\n    /**\n     * Convert coord to data. Data is the rank if it has an ordinal scale\n     * @param {number} coord\n     * @param  {boolean} clamp\n     * @return {number}\n     */\n    coordToData: function (coord, clamp) {\n        var extent = this._extent;\n        var scale = this.scale;\n\n        if (this.onBand && scale.type === 'ordinal') {\n            extent = extent.slice();\n            fixExtentWithBands(extent, scale.count());\n        }\n\n        var t = linearMap(coord, extent, NORMALIZED_EXTENT, clamp);\n\n        return this.scale.scale(t);\n    },\n\n    /**\n     * Convert pixel point to data in axis\n     * @param {Array.<number>} point\n     * @param  {boolean} clamp\n     * @return {number} data\n     */\n    pointToData: function (point, clamp) {\n        // Should be implemented in derived class if necessary.\n    },\n\n    /**\n     * Different from `zrUtil.map(axis.getTicks(), axis.dataToCoord, axis)`,\n     * `axis.getTicksCoords` considers `onBand`, which is used by\n     * `boundaryGap:true` of category axis and splitLine and splitArea.\n     * @param {Object} [opt]\n     * @param {number} [opt.tickModel=axis.model.getModel('axisTick')]\n     * @param {boolean} [opt.clamp] If `true`, the first and the last\n     *        tick must be at the axis end points. Otherwise, clip ticks\n     *        that outside the axis extent.\n     * @return {Array.<Object>} [{\n     *     coord: ...,\n     *     tickValue: ...\n     * }, ...]\n     */\n    getTicksCoords: function (opt) {\n        opt = opt || {};\n\n        var tickModel = opt.tickModel || this.getTickModel();\n\n        var result = createAxisTicks(this, tickModel);\n        var ticks = result.ticks;\n\n        var ticksCoords = map(ticks, function (tickValue) {\n            return {\n                coord: this.dataToCoord(tickValue),\n                tickValue: tickValue\n            };\n        }, this);\n\n        var alignWithLabel = tickModel.get('alignWithLabel');\n        fixOnBandTicksCoords(\n            this, ticksCoords, result.tickCategoryInterval, alignWithLabel, opt.clamp\n        );\n\n        return ticksCoords;\n    },\n\n    /**\n     * @return {Array.<Object>} [{\n     *     formattedLabel: string,\n     *     rawLabel: axis.scale.getLabel(tickValue)\n     *     tickValue: number\n     * }, ...]\n     */\n    getViewLabels: function () {\n        return createAxisLabels(this).labels;\n    },\n\n    /**\n     * @return {module:echarts/coord/model/Model}\n     */\n    getLabelModel: function () {\n        return this.model.getModel('axisLabel');\n    },\n\n    /**\n     * Notice here we only get the default tick model. For splitLine\n     * or splitArea, we should pass the splitLineModel or splitAreaModel\n     * manually when calling `getTicksCoords`.\n     * In GL, this method may be overrided to:\n     * `axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));`\n     * @return {module:echarts/coord/model/Model}\n     */\n    getTickModel: function () {\n        return this.model.getModel('axisTick');\n    },\n\n    /**\n     * Get width of band\n     * @return {number}\n     */\n    getBandWidth: function () {\n        var axisExtent = this._extent;\n        var dataExtent = this.scale.getExtent();\n\n        var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0);\n        // Fix #2728, avoid NaN when only one data.\n        len === 0 && (len = 1);\n\n        var size = Math.abs(axisExtent[1] - axisExtent[0]);\n\n        return Math.abs(size) / len;\n    },\n\n    /**\n     * @abstract\n     * @return {boolean} Is horizontal\n     */\n    isHorizontal: null,\n\n    /**\n     * @abstract\n     * @return {number} Get axis rotate, by degree.\n     */\n    getRotate: null,\n\n    /**\n     * Only be called in category axis.\n     * Can be overrided, consider other axes like in 3D.\n     * @return {number} Auto interval for cateogry axis tick and label\n     */\n    calculateCategoryInterval: function () {\n        return calculateCategoryInterval(this);\n    }\n\n};\n\nfunction fixExtentWithBands(extent, nTick) {\n    var size = extent[1] - extent[0];\n    var len = nTick;\n    var margin = size / len / 2;\n    extent[0] += margin;\n    extent[1] -= margin;\n}\n\n// If axis has labels [1, 2, 3, 4]. Bands on the axis are\n// |---1---|---2---|---3---|---4---|.\n// So the displayed ticks and splitLine/splitArea should between\n// each data item, otherwise cause misleading (e.g., split tow bars\n// of a single data item when there are two bar series).\n// Also consider if tickCategoryInterval > 0 and onBand, ticks and\n// splitLine/spliteArea should layout appropriately corresponding\n// to displayed labels. (So we should not use `getBandWidth` in this\n// case).\nfunction fixOnBandTicksCoords(axis, ticksCoords, tickCategoryInterval, alignWithLabel, clamp) {\n    var ticksLen = ticksCoords.length;\n\n    if (!axis.onBand || alignWithLabel || !ticksLen) {\n        return;\n    }\n\n    var axisExtent = axis.getExtent();\n    var last;\n    if (ticksLen === 1) {\n        ticksCoords[0].coord = axisExtent[0];\n        last = ticksCoords[1] = {coord: axisExtent[0]};\n    }\n    else {\n        var shift = (ticksCoords[1].coord - ticksCoords[0].coord);\n        each$1(ticksCoords, function (ticksItem) {\n            ticksItem.coord -= shift / 2;\n            var tickCategoryInterval = tickCategoryInterval || 0;\n            // Avoid split a single data item when odd interval.\n            if (tickCategoryInterval % 2 > 0) {\n                ticksItem.coord -= shift / ((tickCategoryInterval + 1) * 2);\n            }\n        });\n        last = {coord: ticksCoords[ticksLen - 1].coord + shift};\n        ticksCoords.push(last);\n    }\n\n    var inverse = axisExtent[0] > axisExtent[1];\n\n    if (littleThan(ticksCoords[0].coord, axisExtent[0])) {\n        clamp ? (ticksCoords[0].coord = axisExtent[0]) : ticksCoords.shift();\n    }\n    if (clamp && littleThan(axisExtent[0], ticksCoords[0].coord)) {\n        ticksCoords.unshift({coord: axisExtent[0]});\n    }\n    if (littleThan(axisExtent[1], last.coord)) {\n        clamp ? (last.coord = axisExtent[1]) : ticksCoords.pop();\n    }\n    if (clamp && littleThan(last.coord, axisExtent[1])) {\n        ticksCoords.push({coord: axisExtent[1]});\n    }\n\n    function littleThan(a, b) {\n        return inverse ? a > b : a < b;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Do not mount those modules on 'src/echarts' for better tree shaking.\n */\n\nvar parseGeoJson = parseGeoJson$1;\n\nvar ecUtil = {};\neach$1(\n    [\n        'map', 'each', 'filter', 'indexOf', 'inherits', 'reduce', 'filter',\n        'bind', 'curry', 'isArray', 'isString', 'isObject', 'isFunction',\n        'extend', 'defaults', 'clone', 'merge'\n    ],\n    function (name) {\n        ecUtil[name] = zrUtil[name];\n    }\n);\nvar graphic$1 = {};\neach$1(\n    [\n        'extendShape', 'extendPath', 'makePath', 'makeImage',\n        'mergePath', 'resizePath', 'createIcon',\n        'setHoverStyle', 'setLabelStyle', 'setTextStyle', 'setText',\n        'getFont', 'updateProps', 'initProps', 'getTransform',\n        'clipPointsByRect', 'clipRectByRect',\n        'Group',\n        'Image',\n        'Text',\n        'Circle',\n        'Sector',\n        'Ring',\n        'Polygon',\n        'Polyline',\n        'Rect',\n        'Line',\n        'BezierCurve',\n        'Arc',\n        'IncrementalDisplayable',\n        'CompoundPath',\n        'LinearGradient',\n        'RadialGradient',\n        'BoundingRect'\n    ],\n    function (name) {\n        graphic$1[name] = graphic[name];\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.line',\n\n    dependencies: ['grid', 'polar'],\n\n    getInitialData: function (option, ecModel) {\n        if (__DEV__) {\n            var coordSys = option.coordinateSystem;\n            if (coordSys !== 'polar' && coordSys !== 'cartesian2d') {\n                throw new Error('Line not support coordinateSystem besides cartesian and polar');\n            }\n        }\n        return createListFromArray(this.getSource(), this);\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // stack: null\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // polarIndex: 0,\n\n        // If clip the overflow value\n        clipOverflow: true,\n        // cursor: null,\n\n        label: {\n            position: 'top'\n        },\n        // itemStyle: {\n        // },\n\n        lineStyle: {\n            width: 2,\n            type: 'solid'\n        },\n        // areaStyle: {\n            // origin of areaStyle. Valid values:\n            // `'auto'/null/undefined`: from axisLine to data\n            // `'start'`: from min to data\n            // `'end'`: from data to max\n            // origin: 'auto'\n        // },\n        // false, 'start', 'end', 'middle'\n        step: false,\n\n        // Disabled if step is true\n        smooth: false,\n        smoothMonotone: null,\n        symbol: 'emptyCircle',\n        symbolSize: 4,\n        symbolRotate: null,\n\n        showSymbol: true,\n        // `false`: follow the label interval strategy.\n        // `true`: show all symbols.\n        // `'auto'`: If possible, show all symbols, otherwise\n        //           follow the label interval strategy.\n        showAllSymbol: 'auto',\n\n        // Whether to connect break point.\n        connectNulls: false,\n\n        // Sampling for large data. Can be: 'average', 'max', 'min', 'sum'.\n        sampling: 'none',\n\n        animationEasing: 'linear',\n\n        // Disable progressive\n        progressive: 0,\n        hoverLayerThreshold: Infinity\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @return {string} label string. Not null/undefined\n */\nfunction getDefaultLabel(data, dataIndex) {\n    var labelDims = data.mapDimension('defaultedLabel', true);\n    var len = labelDims.length;\n\n    // Simple optimization (in lots of cases, label dims length is 1)\n    if (len === 1) {\n        return retrieveRawValue(data, dataIndex, labelDims[0]);\n    }\n    else if (len) {\n        var vals = [];\n        for (var i = 0; i < labelDims.length; i++) {\n            var val = retrieveRawValue(data, dataIndex, labelDims[i]);\n            vals.push(val);\n        }\n        return vals.join(' ');\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Symbol\n */\n\n/**\n * @constructor\n * @alias {module:echarts/chart/helper/Symbol}\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @extends {module:zrender/graphic/Group}\n */\nfunction SymbolClz$1(data, idx, seriesScope) {\n    Group.call(this);\n    this.updateData(data, idx, seriesScope);\n}\n\nvar symbolProto = SymbolClz$1.prototype;\n\n/**\n * @public\n * @static\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @return {Array.<number>} [width, height]\n */\nvar getSymbolSize = SymbolClz$1.getSymbolSize = function (data, idx) {\n    var symbolSize = data.getItemVisual(idx, 'symbolSize');\n    return symbolSize instanceof Array\n        ? symbolSize.slice()\n        : [+symbolSize, +symbolSize];\n};\n\nfunction getScale(symbolSize) {\n    return [symbolSize[0] / 2, symbolSize[1] / 2];\n}\n\nfunction driftSymbol(dx, dy) {\n    this.parent.drift(dx, dy);\n}\n\nsymbolProto._createSymbol = function (\n    symbolType,\n    data,\n    idx,\n    symbolSize,\n    keepAspect\n) {\n    // Remove paths created before\n    this.removeAll();\n\n    var color = data.getItemVisual(idx, 'color');\n\n    // var symbolPath = createSymbol(\n    //     symbolType, -0.5, -0.5, 1, 1, color\n    // );\n    // If width/height are set too small (e.g., set to 1) on ios10\n    // and macOS Sierra, a circle stroke become a rect, no matter what\n    // the scale is set. So we set width/height as 2. See #4150.\n    var symbolPath = createSymbol(\n        symbolType, -1, -1, 2, 2, color, keepAspect\n    );\n\n    symbolPath.attr({\n        z2: 100,\n        culling: true,\n        scale: getScale(symbolSize)\n    });\n    // Rewrite drift method\n    symbolPath.drift = driftSymbol;\n\n    this._symbolType = symbolType;\n\n    this.add(symbolPath);\n};\n\n/**\n * Stop animation\n * @param {boolean} toLastFrame\n */\nsymbolProto.stopSymbolAnimation = function (toLastFrame) {\n    this.childAt(0).stopAnimation(toLastFrame);\n};\n\n/**\n * FIXME:\n * Caution: This method breaks the encapsulation of this module,\n * but it indeed brings convenience. So do not use the method\n * unless you detailedly know all the implements of `Symbol`,\n * especially animation.\n *\n * Get symbol path element.\n */\nsymbolProto.getSymbolPath = function () {\n    return this.childAt(0);\n};\n\n/**\n * Get scale(aka, current symbol size).\n * Including the change caused by animation\n */\nsymbolProto.getScale = function () {\n    return this.childAt(0).scale;\n};\n\n/**\n * Highlight symbol\n */\nsymbolProto.highlight = function () {\n    this.childAt(0).trigger('emphasis');\n};\n\n/**\n * Downplay symbol\n */\nsymbolProto.downplay = function () {\n    this.childAt(0).trigger('normal');\n};\n\n/**\n * @param {number} zlevel\n * @param {number} z\n */\nsymbolProto.setZ = function (zlevel, z) {\n    var symbolPath = this.childAt(0);\n    symbolPath.zlevel = zlevel;\n    symbolPath.z = z;\n};\n\nsymbolProto.setDraggable = function (draggable) {\n    var symbolPath = this.childAt(0);\n    symbolPath.draggable = draggable;\n    symbolPath.cursor = draggable ? 'move' : 'pointer';\n};\n\n/**\n * Update symbol properties\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @param {Object} [seriesScope]\n * @param {Object} [seriesScope.itemStyle]\n * @param {Object} [seriesScope.hoverItemStyle]\n * @param {Object} [seriesScope.symbolRotate]\n * @param {Object} [seriesScope.symbolOffset]\n * @param {module:echarts/model/Model} [seriesScope.labelModel]\n * @param {module:echarts/model/Model} [seriesScope.hoverLabelModel]\n * @param {boolean} [seriesScope.hoverAnimation]\n * @param {Object} [seriesScope.cursorStyle]\n * @param {module:echarts/model/Model} [seriesScope.itemModel]\n * @param {string} [seriesScope.symbolInnerColor]\n * @param {Object} [seriesScope.fadeIn=false]\n */\nsymbolProto.updateData = function (data, idx, seriesScope) {\n    this.silent = false;\n\n    var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';\n    var seriesModel = data.hostModel;\n    var symbolSize = getSymbolSize(data, idx);\n    var isInit = symbolType !== this._symbolType;\n\n    if (isInit) {\n        var keepAspect = data.getItemVisual(idx, 'symbolKeepAspect');\n        this._createSymbol(symbolType, data, idx, symbolSize, keepAspect);\n    }\n    else {\n        var symbolPath = this.childAt(0);\n        symbolPath.silent = false;\n        updateProps(symbolPath, {\n            scale: getScale(symbolSize)\n        }, seriesModel, idx);\n    }\n\n    this._updateCommon(data, idx, symbolSize, seriesScope);\n\n    if (isInit) {\n        var symbolPath = this.childAt(0);\n        var fadeIn = seriesScope && seriesScope.fadeIn;\n\n        var target = {scale: symbolPath.scale.slice()};\n        fadeIn && (target.style = {opacity: symbolPath.style.opacity});\n\n        symbolPath.scale = [0, 0];\n        fadeIn && (symbolPath.style.opacity = 0);\n\n        initProps(symbolPath, target, seriesModel, idx);\n    }\n\n    this._seriesModel = seriesModel;\n};\n\n// Update common properties\nvar normalStyleAccessPath = ['itemStyle'];\nvar emphasisStyleAccessPath = ['emphasis', 'itemStyle'];\nvar normalLabelAccessPath = ['label'];\nvar emphasisLabelAccessPath = ['emphasis', 'label'];\n\n/**\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @param {Array.<number>} symbolSize\n * @param {Object} [seriesScope]\n */\nsymbolProto._updateCommon = function (data, idx, symbolSize, seriesScope) {\n    var symbolPath = this.childAt(0);\n    var seriesModel = data.hostModel;\n    var color = data.getItemVisual(idx, 'color');\n\n    // Reset style\n    if (symbolPath.type !== 'image') {\n        symbolPath.useStyle({\n            strokeNoScale: true\n        });\n    }\n\n    var itemStyle = seriesScope && seriesScope.itemStyle;\n    var hoverItemStyle = seriesScope && seriesScope.hoverItemStyle;\n    var symbolRotate = seriesScope && seriesScope.symbolRotate;\n    var symbolOffset = seriesScope && seriesScope.symbolOffset;\n    var labelModel = seriesScope && seriesScope.labelModel;\n    var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;\n    var hoverAnimation = seriesScope && seriesScope.hoverAnimation;\n    var cursorStyle = seriesScope && seriesScope.cursorStyle;\n\n    if (!seriesScope || data.hasItemOption) {\n        var itemModel = (seriesScope && seriesScope.itemModel)\n            ? seriesScope.itemModel : data.getItemModel(idx);\n\n        // Color must be excluded.\n        // Because symbol provide setColor individually to set fill and stroke\n        itemStyle = itemModel.getModel(normalStyleAccessPath).getItemStyle(['color']);\n        hoverItemStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();\n\n        symbolRotate = itemModel.getShallow('symbolRotate');\n        symbolOffset = itemModel.getShallow('symbolOffset');\n\n        labelModel = itemModel.getModel(normalLabelAccessPath);\n        hoverLabelModel = itemModel.getModel(emphasisLabelAccessPath);\n        hoverAnimation = itemModel.getShallow('hoverAnimation');\n        cursorStyle = itemModel.getShallow('cursor');\n    }\n    else {\n        hoverItemStyle = extend({}, hoverItemStyle);\n    }\n\n    var elStyle = symbolPath.style;\n\n    symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0);\n\n    if (symbolOffset) {\n        symbolPath.attr('position', [\n            parsePercent$1(symbolOffset[0], symbolSize[0]),\n            parsePercent$1(symbolOffset[1], symbolSize[1])\n        ]);\n    }\n\n    cursorStyle && symbolPath.attr('cursor', cursorStyle);\n\n    // PENDING setColor before setStyle!!!\n    symbolPath.setColor(color, seriesScope && seriesScope.symbolInnerColor);\n\n    symbolPath.setStyle(itemStyle);\n\n    var opacity = data.getItemVisual(idx, 'opacity');\n    if (opacity != null) {\n        elStyle.opacity = opacity;\n    }\n\n    var liftZ = data.getItemVisual(idx, 'liftZ');\n    var z2Origin = symbolPath.__z2Origin;\n    if (liftZ != null) {\n        if (z2Origin == null) {\n            symbolPath.__z2Origin = symbolPath.z2;\n            symbolPath.z2 += liftZ;\n        }\n    }\n    else if (z2Origin != null) {\n        symbolPath.z2 = z2Origin;\n        symbolPath.__z2Origin = null;\n    }\n\n    var useNameLabel = seriesScope && seriesScope.useNameLabel;\n\n    setLabelStyle(\n        elStyle, hoverItemStyle, labelModel, hoverLabelModel,\n        {\n            labelFetcher: seriesModel,\n            labelDataIndex: idx,\n            defaultText: getLabelDefaultText,\n            isRectText: true,\n            autoColor: color\n        }\n    );\n\n    // Do not execute util needed.\n    function getLabelDefaultText(idx, opt) {\n        return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx);\n    }\n\n    symbolPath.off('mouseover')\n        .off('mouseout')\n        .off('emphasis')\n        .off('normal');\n\n    symbolPath.hoverStyle = hoverItemStyle;\n\n    // FIXME\n    // Do not use symbol.trigger('emphasis'), but use symbol.highlight() instead.\n    setHoverStyle(symbolPath);\n\n    symbolPath.__symbolOriginalScale = getScale(symbolSize);\n\n    if (hoverAnimation && seriesModel.isAnimationEnabled()) {\n        // Note: consider `off`, should use static function here.\n        symbolPath.on('mouseover', onMouseOver)\n            .on('mouseout', onMouseOut)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal);\n    }\n};\n\nfunction onMouseOver() {\n    // see comment in `graphic.isInEmphasis`\n    !isInEmphasis(this) && onEmphasis.call(this);\n}\n\nfunction onMouseOut() {\n    // see comment in `graphic.isInEmphasis`\n    !isInEmphasis(this) && onNormal.call(this);\n}\n\nfunction onEmphasis() {\n    // Do not support this hover animation util some scenario required.\n    // Animation can only be supported in hover layer when using `el.incremetal`.\n    if (this.incremental || this.useHoverLayer) {\n        return;\n    }\n    var scale = this.__symbolOriginalScale;\n    var ratio = scale[1] / scale[0];\n    this.animateTo({\n        scale: [\n            Math.max(scale[0] * 1.1, scale[0] + 3),\n            Math.max(scale[1] * 1.1, scale[1] + 3 * ratio)\n        ]\n    }, 400, 'elasticOut');\n}\n\nfunction onNormal() {\n    if (this.incremental || this.useHoverLayer) {\n        return;\n    }\n    this.animateTo({\n        scale: this.__symbolOriginalScale\n    }, 400, 'elasticOut');\n}\n\n\n/**\n * @param {Function} cb\n * @param {Object} [opt]\n * @param {Object} [opt.keepLabel=true]\n */\nsymbolProto.fadeOut = function (cb, opt) {\n    var symbolPath = this.childAt(0);\n    // Avoid mistaken hover when fading out\n    this.silent = symbolPath.silent = true;\n    // Not show text when animating\n    !(opt && opt.keepLabel) && (symbolPath.style.text = null);\n\n    updateProps(\n        symbolPath,\n        {\n            style: {opacity: 0},\n            scale: [0, 0]\n        },\n        this._seriesModel,\n        this.dataIndex,\n        cb\n    );\n};\n\ninherits(SymbolClz$1, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/SymbolDraw\n */\n\n/**\n * @constructor\n * @alias module:echarts/chart/helper/SymbolDraw\n * @param {module:zrender/graphic/Group} [symbolCtor]\n */\nfunction SymbolDraw(symbolCtor) {\n    this.group = new Group();\n\n    this._symbolCtor = symbolCtor || SymbolClz$1;\n}\n\nvar symbolDrawProto = SymbolDraw.prototype;\n\nfunction symbolNeedsDraw(data, point, idx, opt) {\n    return point && !isNaN(point[0]) && !isNaN(point[1])\n        && !(opt.isIgnore && opt.isIgnore(idx))\n        // We do not set clipShape on group, because it will cut part of\n        // the symbol element shape. We use the same clip shape here as\n        // the line clip.\n        && !(opt.clipShape && !opt.clipShape.contain(point[0], point[1]))\n        && data.getItemVisual(idx, 'symbol') !== 'none';\n}\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n * @param {Object} [opt] Or isIgnore\n * @param {Function} [opt.isIgnore]\n * @param {Object} [opt.clipShape]\n */\nsymbolDrawProto.updateData = function (data, opt) {\n    opt = normalizeUpdateOpt(opt);\n\n    var group = this.group;\n    var seriesModel = data.hostModel;\n    var oldData = this._data;\n    var SymbolCtor = this._symbolCtor;\n\n    var seriesScope = makeSeriesScope(data);\n\n    // There is no oldLineData only when first rendering or switching from\n    // stream mode to normal mode, where previous elements should be removed.\n    if (!oldData) {\n        group.removeAll();\n    }\n\n    data.diff(oldData)\n        .add(function (newIdx) {\n            var point = data.getItemLayout(newIdx);\n            if (symbolNeedsDraw(data, point, newIdx, opt)) {\n                var symbolEl = new SymbolCtor(data, newIdx, seriesScope);\n                symbolEl.attr('position', point);\n                data.setItemGraphicEl(newIdx, symbolEl);\n                group.add(symbolEl);\n            }\n        })\n        .update(function (newIdx, oldIdx) {\n            var symbolEl = oldData.getItemGraphicEl(oldIdx);\n            var point = data.getItemLayout(newIdx);\n            if (!symbolNeedsDraw(data, point, newIdx, opt)) {\n                group.remove(symbolEl);\n                return;\n            }\n            if (!symbolEl) {\n                symbolEl = new SymbolCtor(data, newIdx);\n                symbolEl.attr('position', point);\n            }\n            else {\n                symbolEl.updateData(data, newIdx, seriesScope);\n                updateProps(symbolEl, {\n                    position: point\n                }, seriesModel);\n            }\n\n            // Add back\n            group.add(symbolEl);\n\n            data.setItemGraphicEl(newIdx, symbolEl);\n        })\n        .remove(function (oldIdx) {\n            var el = oldData.getItemGraphicEl(oldIdx);\n            el && el.fadeOut(function () {\n                group.remove(el);\n            });\n        })\n        .execute();\n\n    this._data = data;\n};\n\nsymbolDrawProto.isPersistent = function () {\n    return true;\n};\n\nsymbolDrawProto.updateLayout = function () {\n    var data = this._data;\n    if (data) {\n        // Not use animation\n        data.eachItemGraphicEl(function (el, idx) {\n            var point = data.getItemLayout(idx);\n            el.attr('position', point);\n        });\n    }\n};\n\nsymbolDrawProto.incrementalPrepareUpdate = function (data) {\n    this._seriesScope = makeSeriesScope(data);\n    this._data = null;\n    this.group.removeAll();\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n * @param {Object} [opt] Or isIgnore\n * @param {Function} [opt.isIgnore]\n * @param {Object} [opt.clipShape]\n */\nsymbolDrawProto.incrementalUpdate = function (taskParams, data, opt) {\n    opt = normalizeUpdateOpt(opt);\n\n    function updateIncrementalAndHover(el) {\n        if (!el.isGroup) {\n            el.incremental = el.useHoverLayer = true;\n        }\n    }\n    for (var idx = taskParams.start; idx < taskParams.end; idx++) {\n        var point = data.getItemLayout(idx);\n        if (symbolNeedsDraw(data, point, idx, opt)) {\n            var el = new this._symbolCtor(data, idx, this._seriesScope);\n            el.traverse(updateIncrementalAndHover);\n            el.attr('position', point);\n            this.group.add(el);\n            data.setItemGraphicEl(idx, el);\n        }\n    }\n};\n\nfunction normalizeUpdateOpt(opt) {\n    if (opt != null && !isObject$1(opt)) {\n        opt = {isIgnore: opt};\n    }\n    return opt || {};\n}\n\nsymbolDrawProto.remove = function (enableAnimation) {\n    var group = this.group;\n    var data = this._data;\n    // Incremental model do not have this._data.\n    if (data && enableAnimation) {\n        data.eachItemGraphicEl(function (el) {\n            el.fadeOut(function () {\n                group.remove(el);\n            });\n        });\n    }\n    else {\n        group.removeAll();\n    }\n};\n\nfunction makeSeriesScope(data) {\n    var seriesModel = data.hostModel;\n    return {\n        itemStyle: seriesModel.getModel('itemStyle').getItemStyle(['color']),\n        hoverItemStyle: seriesModel.getModel('emphasis.itemStyle').getItemStyle(),\n        symbolRotate: seriesModel.get('symbolRotate'),\n        symbolOffset: seriesModel.get('symbolOffset'),\n        hoverAnimation: seriesModel.get('hoverAnimation'),\n        labelModel: seriesModel.getModel('label'),\n        hoverLabelModel: seriesModel.getModel('emphasis.label'),\n        cursorStyle: seriesModel.get('cursor')\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} coordSys\n * @param {module:echarts/data/List} data\n * @param {string} valueOrigin lineSeries.option.areaStyle.origin\n */\nfunction prepareDataCoordInfo(coordSys, data, valueOrigin) {\n    var baseAxis = coordSys.getBaseAxis();\n    var valueAxis = coordSys.getOtherAxis(baseAxis);\n    var valueStart = getValueStart(valueAxis, valueOrigin);\n\n    var baseAxisDim = baseAxis.dim;\n    var valueAxisDim = valueAxis.dim;\n    var valueDim = data.mapDimension(valueAxisDim);\n    var baseDim = data.mapDimension(baseAxisDim);\n    var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0;\n\n    var dims = map(coordSys.dimensions, function (coordDim) {\n        return data.mapDimension(coordDim);\n    });\n\n    var stacked;\n    var stackResultDim = data.getCalculationInfo('stackResultDimension');\n    if (stacked |= isDimensionStacked(data, dims[0] /*, dims[1]*/)) { // jshint ignore:line\n        dims[0] = stackResultDim;\n    }\n    if (stacked |= isDimensionStacked(data, dims[1] /*, dims[0]*/)) { // jshint ignore:line\n        dims[1] = stackResultDim;\n    }\n\n    return {\n        dataDimsForPoint: dims,\n        valueStart: valueStart,\n        valueAxisDim: valueAxisDim,\n        baseAxisDim: baseAxisDim,\n        stacked: !!stacked,\n        valueDim: valueDim,\n        baseDim: baseDim,\n        baseDataOffset: baseDataOffset,\n        stackedOverDimension: data.getCalculationInfo('stackedOverDimension')\n    };\n}\n\nfunction getValueStart(valueAxis, valueOrigin) {\n    var valueStart = 0;\n    var extent = valueAxis.scale.getExtent();\n\n    if (valueOrigin === 'start') {\n        valueStart = extent[0];\n    }\n    else if (valueOrigin === 'end') {\n        valueStart = extent[1];\n    }\n    // auto\n    else {\n        // Both positive\n        if (extent[0] > 0) {\n            valueStart = extent[0];\n        }\n        // Both negative\n        else if (extent[1] < 0) {\n            valueStart = extent[1];\n        }\n        // If is one positive, and one negative, onZero shall be true\n    }\n\n    return valueStart;\n}\n\nfunction getStackedOnPoint(dataCoordInfo, coordSys, data, idx) {\n    var value = NaN;\n    if (dataCoordInfo.stacked) {\n        value = data.get(data.getCalculationInfo('stackedOverDimension'), idx);\n    }\n    if (isNaN(value)) {\n        value = dataCoordInfo.valueStart;\n    }\n\n    var baseDataOffset = dataCoordInfo.baseDataOffset;\n    var stackedData = [];\n    stackedData[baseDataOffset] = data.get(dataCoordInfo.baseDim, idx);\n    stackedData[1 - baseDataOffset] = value;\n\n    return coordSys.dataToPoint(stackedData);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// var arrayDiff = require('zrender/src/core/arrayDiff');\n// 'zrender/src/core/arrayDiff' has been used before, but it did\n// not do well in performance when roam with fixed dataZoom window.\n\n// function convertToIntId(newIdList, oldIdList) {\n//     // Generate int id instead of string id.\n//     // Compare string maybe slow in score function of arrDiff\n\n//     // Assume id in idList are all unique\n//     var idIndicesMap = {};\n//     var idx = 0;\n//     for (var i = 0; i < newIdList.length; i++) {\n//         idIndicesMap[newIdList[i]] = idx;\n//         newIdList[i] = idx++;\n//     }\n//     for (var i = 0; i < oldIdList.length; i++) {\n//         var oldId = oldIdList[i];\n//         // Same with newIdList\n//         if (idIndicesMap[oldId]) {\n//             oldIdList[i] = idIndicesMap[oldId];\n//         }\n//         else {\n//             oldIdList[i] = idx++;\n//         }\n//     }\n// }\n\nfunction diffData(oldData, newData) {\n    var diffResult = [];\n\n    newData.diff(oldData)\n        .add(function (idx) {\n            diffResult.push({cmd: '+', idx: idx});\n        })\n        .update(function (newIdx, oldIdx) {\n            diffResult.push({cmd: '=', idx: oldIdx, idx1: newIdx});\n        })\n        .remove(function (idx) {\n            diffResult.push({cmd: '-', idx: idx});\n        })\n        .execute();\n\n    return diffResult;\n}\n\nvar lineAnimationDiff = function (\n    oldData, newData,\n    oldStackedOnPoints, newStackedOnPoints,\n    oldCoordSys, newCoordSys,\n    oldValueOrigin, newValueOrigin\n) {\n    var diff = diffData(oldData, newData);\n\n    // var newIdList = newData.mapArray(newData.getId);\n    // var oldIdList = oldData.mapArray(oldData.getId);\n\n    // convertToIntId(newIdList, oldIdList);\n\n    // // FIXME One data ?\n    // diff = arrayDiff(oldIdList, newIdList);\n\n    var currPoints = [];\n    var nextPoints = [];\n    // Points for stacking base line\n    var currStackedPoints = [];\n    var nextStackedPoints = [];\n\n    var status = [];\n    var sortedIndices = [];\n    var rawIndices = [];\n\n    var newDataOldCoordInfo = prepareDataCoordInfo(oldCoordSys, newData, oldValueOrigin);\n    var oldDataNewCoordInfo = prepareDataCoordInfo(newCoordSys, oldData, newValueOrigin);\n\n    for (var i = 0; i < diff.length; i++) {\n        var diffItem = diff[i];\n        var pointAdded = true;\n\n        // FIXME, animation is not so perfect when dataZoom window moves fast\n        // Which is in case remvoing or add more than one data in the tail or head\n        switch (diffItem.cmd) {\n            case '=':\n                var currentPt = oldData.getItemLayout(diffItem.idx);\n                var nextPt = newData.getItemLayout(diffItem.idx1);\n                // If previous data is NaN, use next point directly\n                if (isNaN(currentPt[0]) || isNaN(currentPt[1])) {\n                    currentPt = nextPt.slice();\n                }\n                currPoints.push(currentPt);\n                nextPoints.push(nextPt);\n\n                currStackedPoints.push(oldStackedOnPoints[diffItem.idx]);\n                nextStackedPoints.push(newStackedOnPoints[diffItem.idx1]);\n\n                rawIndices.push(newData.getRawIndex(diffItem.idx1));\n                break;\n            case '+':\n                var idx = diffItem.idx;\n                currPoints.push(\n                    oldCoordSys.dataToPoint([\n                        newData.get(newDataOldCoordInfo.dataDimsForPoint[0], idx),\n                        newData.get(newDataOldCoordInfo.dataDimsForPoint[1], idx)\n                    ])\n                );\n\n                nextPoints.push(newData.getItemLayout(idx).slice());\n\n                currStackedPoints.push(\n                    getStackedOnPoint(newDataOldCoordInfo, oldCoordSys, newData, idx)\n                );\n                nextStackedPoints.push(newStackedOnPoints[idx]);\n\n                rawIndices.push(newData.getRawIndex(idx));\n                break;\n            case '-':\n                var idx = diffItem.idx;\n                var rawIndex = oldData.getRawIndex(idx);\n                // Data is replaced. In the case of dynamic data queue\n                // FIXME FIXME FIXME\n                if (rawIndex !== idx) {\n                    currPoints.push(oldData.getItemLayout(idx));\n                    nextPoints.push(newCoordSys.dataToPoint([\n                        oldData.get(oldDataNewCoordInfo.dataDimsForPoint[0], idx),\n                        oldData.get(oldDataNewCoordInfo.dataDimsForPoint[1], idx)\n                    ]));\n\n                    currStackedPoints.push(oldStackedOnPoints[idx]);\n                    nextStackedPoints.push(\n                        getStackedOnPoint(oldDataNewCoordInfo, newCoordSys, oldData, idx)\n                    );\n\n                    rawIndices.push(rawIndex);\n                }\n                else {\n                    pointAdded = false;\n                }\n        }\n\n        // Original indices\n        if (pointAdded) {\n            status.push(diffItem);\n            sortedIndices.push(sortedIndices.length);\n        }\n    }\n\n    // Diff result may be crossed if all items are changed\n    // Sort by data index\n    sortedIndices.sort(function (a, b) {\n        return rawIndices[a] - rawIndices[b];\n    });\n\n    var sortedCurrPoints = [];\n    var sortedNextPoints = [];\n\n    var sortedCurrStackedPoints = [];\n    var sortedNextStackedPoints = [];\n\n    var sortedStatus = [];\n    for (var i = 0; i < sortedIndices.length; i++) {\n        var idx = sortedIndices[i];\n        sortedCurrPoints[i] = currPoints[idx];\n        sortedNextPoints[i] = nextPoints[idx];\n\n        sortedCurrStackedPoints[i] = currStackedPoints[idx];\n        sortedNextStackedPoints[i] = nextStackedPoints[idx];\n\n        sortedStatus[i] = status[idx];\n    }\n\n    return {\n        current: sortedCurrPoints,\n        next: sortedNextPoints,\n\n        stackedOnCurrent: sortedCurrStackedPoints,\n        stackedOnNext: sortedNextStackedPoints,\n\n        status: sortedStatus\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Poly path support NaN point\n\nvar vec2Min = min;\nvar vec2Max = max;\n\nvar scaleAndAdd$1 = scaleAndAdd;\nvar v2Copy = copy;\n\n// Temporary variable\nvar v = [];\nvar cp0 = [];\nvar cp1 = [];\n\nfunction isPointNull(p) {\n    return isNaN(p[0]) || isNaN(p[1]);\n}\n\nfunction drawSegment(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    // if (smoothMonotone == null) {\n    //     if (isMono(points, 'x')) {\n    //         return drawMono(ctx, points, start, segLen, allLen,\n    //             dir, smoothMin, smoothMax, smooth, 'x', connectNulls);\n    //     }\n    //     else if (isMono(points, 'y')) {\n    //         return drawMono(ctx, points, start, segLen, allLen,\n    //             dir, smoothMin, smoothMax, smooth, 'y', connectNulls);\n    //     }\n    //     else {\n    //         return drawNonMono.apply(this, arguments);\n    //     }\n    // }\n    // else if (smoothMonotone !== 'none' && isMono(points, smoothMonotone)) {\n    //     return drawMono.apply(this, arguments);\n    // }\n    // else {\n    //     return drawNonMono.apply(this, arguments);\n    // }\n    if (smoothMonotone === 'none' || !smoothMonotone) {\n        return drawNonMono.apply(this, arguments);\n    }\n    else {\n        return drawMono.apply(this, arguments);\n    }\n}\n\n/**\n * Check if points is in monotone.\n *\n * @param {number[][]} points         Array of points which is in [x, y] form\n * @param {string}     smoothMonotone 'x', 'y', or 'none', stating for which\n *                                    dimension that is checking.\n *                                    If is 'none', `drawNonMono` should be\n *                                    called.\n *                                    If is undefined, either being monotone\n *                                    in 'x' or 'y' will call `drawMono`.\n */\n// function isMono(points, smoothMonotone) {\n//     if (points.length <= 1) {\n//         return true;\n//     }\n\n//     var dim = smoothMonotone === 'x' ? 0 : 1;\n//     var last = points[0][dim];\n//     var lastDiff = 0;\n//     for (var i = 1; i < points.length; ++i) {\n//         var diff = points[i][dim] - last;\n//         if (!isNaN(diff) && !isNaN(lastDiff)\n//             && diff !== 0 && lastDiff !== 0\n//             && ((diff >= 0) !== (lastDiff >= 0))\n//         ) {\n//             return false;\n//         }\n//         if (!isNaN(diff) && diff !== 0) {\n//             lastDiff = diff;\n//             last = points[i][dim];\n//         }\n//     }\n//     return true;\n// }\n\n/**\n * Draw smoothed line in monotone, in which only vertical or horizontal bezier\n * control points will be used. This should be used when points are monotone\n * either in x or y dimension.\n */\nfunction drawMono(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    var prevIdx = 0;\n    var idx = start;\n    for (var k = 0; k < segLen; k++) {\n        var p = points[idx];\n        if (idx >= allLen || idx < 0) {\n            break;\n        }\n        if (isPointNull(p)) {\n            if (connectNulls) {\n                idx += dir;\n                continue;\n            }\n            break;\n        }\n\n        if (idx === start) {\n            ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);\n        }\n        else {\n            if (smooth > 0) {\n                var prevP = points[prevIdx];\n                var dim = smoothMonotone === 'y' ? 1 : 0;\n\n                // Length of control point to p, either in x or y, but not both\n                var ctrlLen = (p[dim] - prevP[dim]) * smooth;\n\n                v2Copy(cp0, prevP);\n                cp0[dim] = prevP[dim] + ctrlLen;\n\n                v2Copy(cp1, p);\n                cp1[dim] = p[dim] - ctrlLen;\n\n                ctx.bezierCurveTo(\n                    cp0[0], cp0[1],\n                    cp1[0], cp1[1],\n                    p[0], p[1]\n                );\n            }\n            else {\n                ctx.lineTo(p[0], p[1]);\n            }\n        }\n\n        prevIdx = idx;\n        idx += dir;\n    }\n\n    return k;\n}\n\n/**\n * Draw smoothed line in non-monotone, in may cause undesired curve in extreme\n * situations. This should be used when points are non-monotone neither in x or\n * y dimension.\n */\nfunction drawNonMono(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    var prevIdx = 0;\n    var idx = start;\n    for (var k = 0; k < segLen; k++) {\n        var p = points[idx];\n        if (idx >= allLen || idx < 0) {\n            break;\n        }\n        if (isPointNull(p)) {\n            if (connectNulls) {\n                idx += dir;\n                continue;\n            }\n            break;\n        }\n\n        if (idx === start) {\n            ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);\n            v2Copy(cp0, p);\n        }\n        else {\n            if (smooth > 0) {\n                var nextIdx = idx + dir;\n                var nextP = points[nextIdx];\n                if (connectNulls) {\n                    // Find next point not null\n                    while (nextP && isPointNull(points[nextIdx])) {\n                        nextIdx += dir;\n                        nextP = points[nextIdx];\n                    }\n                }\n\n                var ratioNextSeg = 0.5;\n                var prevP = points[prevIdx];\n                var nextP = points[nextIdx];\n                // Last point\n                if (!nextP || isPointNull(nextP)) {\n                    v2Copy(cp1, p);\n                }\n                else {\n                    // If next data is null in not connect case\n                    if (isPointNull(nextP) && !connectNulls) {\n                        nextP = p;\n                    }\n\n                    sub(v, nextP, prevP);\n\n                    var lenPrevSeg;\n                    var lenNextSeg;\n                    if (smoothMonotone === 'x' || smoothMonotone === 'y') {\n                        var dim = smoothMonotone === 'x' ? 0 : 1;\n                        lenPrevSeg = Math.abs(p[dim] - prevP[dim]);\n                        lenNextSeg = Math.abs(p[dim] - nextP[dim]);\n                    }\n                    else {\n                        lenPrevSeg = dist(p, prevP);\n                        lenNextSeg = dist(p, nextP);\n                    }\n\n                    // Use ratio of seg length\n                    ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg);\n\n                    scaleAndAdd$1(cp1, p, v, -smooth * (1 - ratioNextSeg));\n                }\n                // Smooth constraint\n                vec2Min(cp0, cp0, smoothMax);\n                vec2Max(cp0, cp0, smoothMin);\n                vec2Min(cp1, cp1, smoothMax);\n                vec2Max(cp1, cp1, smoothMin);\n\n                ctx.bezierCurveTo(\n                    cp0[0], cp0[1],\n                    cp1[0], cp1[1],\n                    p[0], p[1]\n                );\n                // cp0 of next segment\n                scaleAndAdd$1(cp0, p, v, smooth * ratioNextSeg);\n            }\n            else {\n                ctx.lineTo(p[0], p[1]);\n            }\n        }\n\n        prevIdx = idx;\n        idx += dir;\n    }\n\n    return k;\n}\n\nfunction getBoundingBox(points, smoothConstraint) {\n    var ptMin = [Infinity, Infinity];\n    var ptMax = [-Infinity, -Infinity];\n    if (smoothConstraint) {\n        for (var i = 0; i < points.length; i++) {\n            var pt = points[i];\n            if (pt[0] < ptMin[0]) {\n                ptMin[0] = pt[0];\n            }\n            if (pt[1] < ptMin[1]) {\n                ptMin[1] = pt[1];\n            }\n            if (pt[0] > ptMax[0]) {\n                ptMax[0] = pt[0];\n            }\n            if (pt[1] > ptMax[1]) {\n                ptMax[1] = pt[1];\n            }\n        }\n    }\n    return {\n        min: smoothConstraint ? ptMin : ptMax,\n        max: smoothConstraint ? ptMax : ptMin\n    };\n}\n\nvar Polyline$1 = Path.extend({\n\n    type: 'ec-polyline',\n\n    shape: {\n        points: [],\n\n        smooth: 0,\n\n        smoothConstraint: true,\n\n        smoothMonotone: null,\n\n        connectNulls: false\n    },\n\n    style: {\n        fill: null,\n\n        stroke: '#000'\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n        var points = shape.points;\n\n        var i = 0;\n        var len$$1 = points.length;\n\n        var result = getBoundingBox(points, shape.smoothConstraint);\n\n        if (shape.connectNulls) {\n            // Must remove first and last null values avoid draw error in polygon\n            for (; len$$1 > 0; len$$1--) {\n                if (!isPointNull(points[len$$1 - 1])) {\n                    break;\n                }\n            }\n            for (; i < len$$1; i++) {\n                if (!isPointNull(points[i])) {\n                    break;\n                }\n            }\n        }\n        while (i < len$$1) {\n            i += drawSegment(\n                ctx, points, i, len$$1, len$$1,\n                1, result.min, result.max, shape.smooth,\n                shape.smoothMonotone, shape.connectNulls\n            ) + 1;\n        }\n    }\n});\n\nvar Polygon$1 = Path.extend({\n\n    type: 'ec-polygon',\n\n    shape: {\n        points: [],\n\n        // Offset between stacked base points and points\n        stackedOnPoints: [],\n\n        smooth: 0,\n\n        stackedOnSmooth: 0,\n\n        smoothConstraint: true,\n\n        smoothMonotone: null,\n\n        connectNulls: false\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n        var points = shape.points;\n        var stackedOnPoints = shape.stackedOnPoints;\n\n        var i = 0;\n        var len$$1 = points.length;\n        var smoothMonotone = shape.smoothMonotone;\n        var bbox = getBoundingBox(points, shape.smoothConstraint);\n        var stackedOnBBox = getBoundingBox(stackedOnPoints, shape.smoothConstraint);\n\n        if (shape.connectNulls) {\n            // Must remove first and last null values avoid draw error in polygon\n            for (; len$$1 > 0; len$$1--) {\n                if (!isPointNull(points[len$$1 - 1])) {\n                    break;\n                }\n            }\n            for (; i < len$$1; i++) {\n                if (!isPointNull(points[i])) {\n                    break;\n                }\n            }\n        }\n        while (i < len$$1) {\n            var k = drawSegment(\n                ctx, points, i, len$$1, len$$1,\n                1, bbox.min, bbox.max, shape.smooth,\n                smoothMonotone, shape.connectNulls\n            );\n            drawSegment(\n                ctx, stackedOnPoints, i + k - 1, k, len$$1,\n                -1, stackedOnBBox.min, stackedOnBBox.max, shape.stackedOnSmooth,\n                smoothMonotone, shape.connectNulls\n            );\n            i += k + 1;\n\n            ctx.closePath();\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME step not support polar\n\nfunction isPointsSame(points1, points2) {\n    if (points1.length !== points2.length) {\n        return;\n    }\n    for (var i = 0; i < points1.length; i++) {\n        var p1 = points1[i];\n        var p2 = points2[i];\n        if (p1[0] !== p2[0] || p1[1] !== p2[1]) {\n            return;\n        }\n    }\n    return true;\n}\n\nfunction getSmooth(smooth) {\n    return typeof (smooth) === 'number' ? smooth : (smooth ? 0.5 : 0);\n}\n\nfunction getAxisExtentWithGap(axis) {\n    var extent = axis.getGlobalExtent();\n    if (axis.onBand) {\n        // Remove extra 1px to avoid line miter in clipped edge\n        var halfBandWidth = axis.getBandWidth() / 2 - 1;\n        var dir = extent[1] > extent[0] ? 1 : -1;\n        extent[0] += dir * halfBandWidth;\n        extent[1] -= dir * halfBandWidth;\n    }\n    return extent;\n}\n\n/**\n * @param {module:echarts/coord/cartesian/Cartesian2D|module:echarts/coord/polar/Polar} coordSys\n * @param {module:echarts/data/List} data\n * @param {Object} dataCoordInfo\n * @param {Array.<Array.<number>>} points\n */\nfunction getStackedOnPoints(coordSys, data, dataCoordInfo) {\n    if (!dataCoordInfo.valueDim) {\n        return [];\n    }\n\n    var points = [];\n    for (var idx = 0, len = data.count(); idx < len; idx++) {\n        points.push(getStackedOnPoint(dataCoordInfo, coordSys, data, idx));\n    }\n\n    return points;\n}\n\nfunction createGridClipShape(cartesian, hasAnimation, forSymbol, seriesModel) {\n    var xExtent = getAxisExtentWithGap(cartesian.getAxis('x'));\n    var yExtent = getAxisExtentWithGap(cartesian.getAxis('y'));\n    var isHorizontal = cartesian.getBaseAxis().isHorizontal();\n\n    var x = Math.min(xExtent[0], xExtent[1]);\n    var y = Math.min(yExtent[0], yExtent[1]);\n    var width = Math.max(xExtent[0], xExtent[1]) - x;\n    var height = Math.max(yExtent[0], yExtent[1]) - y;\n\n    // Avoid float number rounding error for symbol on the edge of axis extent.\n    // See #7913 and `test/dataZoom-clip.html`.\n    if (forSymbol) {\n        x -= 0.5;\n        width += 0.5;\n        y -= 0.5;\n        height += 0.5;\n    }\n    else {\n        var lineWidth = seriesModel.get('lineStyle.width') || 2;\n        // Expand clip shape to avoid clipping when line value exceeds axis\n        var expandSize = seriesModel.get('clipOverflow') ? lineWidth / 2 : Math.max(width, height);\n        if (isHorizontal) {\n            y -= expandSize;\n            height += expandSize * 2;\n        }\n        else {\n            x -= expandSize;\n            width += expandSize * 2;\n        }\n    }\n\n    var clipPath = new Rect({\n        shape: {\n            x: x,\n            y: y,\n            width: width,\n            height: height\n        }\n    });\n\n    if (hasAnimation) {\n        clipPath.shape[isHorizontal ? 'width' : 'height'] = 0;\n        initProps(clipPath, {\n            shape: {\n                width: width,\n                height: height\n            }\n        }, seriesModel);\n    }\n\n    return clipPath;\n}\n\nfunction createPolarClipShape(polar, hasAnimation, forSymbol, seriesModel) {\n    var angleAxis = polar.getAngleAxis();\n    var radiusAxis = polar.getRadiusAxis();\n\n    var radiusExtent = radiusAxis.getExtent().slice();\n    radiusExtent[0] > radiusExtent[1] && radiusExtent.reverse();\n    var angleExtent = angleAxis.getExtent();\n\n    var RADIAN = Math.PI / 180;\n\n    // Avoid float number rounding error for symbol on the edge of axis extent.\n    if (forSymbol) {\n        radiusExtent[0] -= 0.5;\n        radiusExtent[1] += 0.5;\n    }\n\n    var clipPath = new Sector({\n        shape: {\n            cx: round$2(polar.cx, 1),\n            cy: round$2(polar.cy, 1),\n            r0: round$2(radiusExtent[0], 1),\n            r: round$2(radiusExtent[1], 1),\n            startAngle: -angleExtent[0] * RADIAN,\n            endAngle: -angleExtent[1] * RADIAN,\n            clockwise: angleAxis.inverse\n        }\n    });\n\n    if (hasAnimation) {\n        clipPath.shape.endAngle = -angleExtent[0] * RADIAN;\n        initProps(clipPath, {\n            shape: {\n                endAngle: -angleExtent[1] * RADIAN\n            }\n        }, seriesModel);\n    }\n\n    return clipPath;\n}\n\nfunction createClipShape(coordSys, hasAnimation, forSymbol, seriesModel) {\n    return coordSys.type === 'polar'\n        ? createPolarClipShape(coordSys, hasAnimation, forSymbol, seriesModel)\n        : createGridClipShape(coordSys, hasAnimation, forSymbol, seriesModel);\n}\n\nfunction turnPointsIntoStep(points, coordSys, stepTurnAt) {\n    var baseAxis = coordSys.getBaseAxis();\n    var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1;\n\n    var stepPoints = [];\n    for (var i = 0; i < points.length - 1; i++) {\n        var nextPt = points[i + 1];\n        var pt = points[i];\n        stepPoints.push(pt);\n\n        var stepPt = [];\n        switch (stepTurnAt) {\n            case 'end':\n                stepPt[baseIndex] = nextPt[baseIndex];\n                stepPt[1 - baseIndex] = pt[1 - baseIndex];\n                // default is start\n                stepPoints.push(stepPt);\n                break;\n            case 'middle':\n                // default is start\n                var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2;\n                var stepPt2 = [];\n                stepPt[baseIndex] = stepPt2[baseIndex] = middle;\n                stepPt[1 - baseIndex] = pt[1 - baseIndex];\n                stepPt2[1 - baseIndex] = nextPt[1 - baseIndex];\n                stepPoints.push(stepPt);\n                stepPoints.push(stepPt2);\n                break;\n            default:\n                stepPt[baseIndex] = pt[baseIndex];\n                stepPt[1 - baseIndex] = nextPt[1 - baseIndex];\n                // default is start\n                stepPoints.push(stepPt);\n        }\n    }\n    // Last points\n    points[i] && stepPoints.push(points[i]);\n    return stepPoints;\n}\n\nfunction getVisualGradient(data, coordSys) {\n    var visualMetaList = data.getVisual('visualMeta');\n    if (!visualMetaList || !visualMetaList.length || !data.count()) {\n        // When data.count() is 0, gradient range can not be calculated.\n        return;\n    }\n\n    if (coordSys.type !== 'cartesian2d') {\n        if (__DEV__) {\n            console.warn('Visual map on line style is only supported on cartesian2d.');\n        }\n        return;\n    }\n\n    var coordDim;\n    var visualMeta;\n\n    for (var i = visualMetaList.length - 1; i >= 0; i--) {\n        var dimIndex = visualMetaList[i].dimension;\n        var dimName = data.dimensions[dimIndex];\n        var dimInfo = data.getDimensionInfo(dimName);\n        coordDim = dimInfo && dimInfo.coordDim;\n        // Can only be x or y\n        if (coordDim === 'x' || coordDim === 'y') {\n            visualMeta = visualMetaList[i];\n            break;\n        }\n    }\n\n    if (!visualMeta) {\n        if (__DEV__) {\n            console.warn('Visual map on line style only support x or y dimension.');\n        }\n        return;\n    }\n\n    // If the area to be rendered is bigger than area defined by LinearGradient,\n    // the canvas spec prescribes that the color of the first stop and the last\n    // stop should be used. But if two stops are added at offset 0, in effect\n    // browsers use the color of the second stop to render area outside\n    // LinearGradient. So we can only infinitesimally extend area defined in\n    // LinearGradient to render `outerColors`.\n\n    var axis = coordSys.getAxis(coordDim);\n\n    // dataToCoor mapping may not be linear, but must be monotonic.\n    var colorStops = map(visualMeta.stops, function (stop) {\n        return {\n            coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)),\n            color: stop.color\n        };\n    });\n    var stopLen = colorStops.length;\n    var outerColors = visualMeta.outerColors.slice();\n\n    if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) {\n        colorStops.reverse();\n        outerColors.reverse();\n    }\n\n    var tinyExtent = 10; // Arbitrary value: 10px\n    var minCoord = colorStops[0].coord - tinyExtent;\n    var maxCoord = colorStops[stopLen - 1].coord + tinyExtent;\n    var coordSpan = maxCoord - minCoord;\n\n    if (coordSpan < 1e-3) {\n        return 'transparent';\n    }\n\n    each$1(colorStops, function (stop) {\n        stop.offset = (stop.coord - minCoord) / coordSpan;\n    });\n    colorStops.push({\n        offset: stopLen ? colorStops[stopLen - 1].offset : 0.5,\n        color: outerColors[1] || 'transparent'\n    });\n    colorStops.unshift({ // notice colorStops.length have been changed.\n        offset: stopLen ? colorStops[0].offset : 0.5,\n        color: outerColors[0] || 'transparent'\n    });\n\n    // zrUtil.each(colorStops, function (colorStop) {\n    //     // Make sure each offset has rounded px to avoid not sharp edge\n    //     colorStop.offset = (Math.round(colorStop.offset * (end - start) + start) - start) / (end - start);\n    // });\n\n    var gradient = new LinearGradient(0, 0, 0, 0, colorStops, true);\n    gradient[coordDim] = minCoord;\n    gradient[coordDim + '2'] = maxCoord;\n\n    return gradient;\n}\n\nfunction getIsIgnoreFunc(seriesModel, data, coordSys) {\n    var showAllSymbol = seriesModel.get('showAllSymbol');\n    var isAuto = showAllSymbol === 'auto';\n\n    if (showAllSymbol && !isAuto) {\n        return;\n    }\n\n    var categoryAxis = coordSys.getAxesByScale('ordinal')[0];\n    if (!categoryAxis) {\n        return;\n    }\n\n    // Note that category label interval strategy might bring some weird effect\n    // in some scenario: users may wonder why some of the symbols are not\n    // displayed. So we show all symbols as possible as we can.\n    if (isAuto\n        // Simplify the logic, do not determine label overlap here.\n        && canShowAllSymbolForCategory(categoryAxis, data)\n    ) {\n        return;\n    }\n\n    // Otherwise follow the label interval strategy on category axis.\n    var categoryDataDim = data.mapDimension(categoryAxis.dim);\n    var labelMap = {};\n\n    each$1(categoryAxis.getViewLabels(), function (labelItem) {\n        labelMap[labelItem.tickValue] = 1;\n    });\n\n    return function (dataIndex) {\n        return !labelMap.hasOwnProperty(data.get(categoryDataDim, dataIndex));\n    };\n}\n\nfunction canShowAllSymbolForCategory(categoryAxis, data) {\n    // In mose cases, line is monotonous on category axis, and the label size\n    // is close with each other. So we check the symbol size and some of the\n    // label size alone with the category axis to estimate whether all symbol\n    // can be shown without overlap.\n    var axisExtent = categoryAxis.getExtent();\n    var availSize = Math.abs(axisExtent[1] - axisExtent[0]) / categoryAxis.scale.count();\n    isNaN(availSize) && (availSize = 0); // 0/0 is NaN.\n\n    // Sampling some points, max 5.\n    var dataLen = data.count();\n    var step = Math.max(1, Math.round(dataLen / 5));\n    for (var dataIndex = 0; dataIndex < dataLen; dataIndex += step) {\n        if (SymbolClz$1.getSymbolSize(\n                data, dataIndex\n            // Only for cartesian, where `isHorizontal` exists.\n            )[categoryAxis.isHorizontal() ? 1 : 0]\n            // Empirical number\n            * 1.5 > availSize\n        ) {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nChart.extend({\n\n    type: 'line',\n\n    init: function () {\n        var lineGroup = new Group();\n\n        var symbolDraw = new SymbolDraw();\n        this.group.add(symbolDraw.group);\n\n        this._symbolDraw = symbolDraw;\n        this._lineGroup = lineGroup;\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var group = this.group;\n        var data = seriesModel.getData();\n        var lineStyleModel = seriesModel.getModel('lineStyle');\n        var areaStyleModel = seriesModel.getModel('areaStyle');\n\n        var points = data.mapArray(data.getItemLayout);\n\n        var isCoordSysPolar = coordSys.type === 'polar';\n        var prevCoordSys = this._coordSys;\n\n        var symbolDraw = this._symbolDraw;\n        var polyline = this._polyline;\n        var polygon = this._polygon;\n\n        var lineGroup = this._lineGroup;\n\n        var hasAnimation = seriesModel.get('animation');\n\n        var isAreaChart = !areaStyleModel.isEmpty();\n\n        var valueOrigin = areaStyleModel.get('origin');\n        var dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin);\n\n        var stackedOnPoints = getStackedOnPoints(coordSys, data, dataCoordInfo);\n\n        var showSymbol = seriesModel.get('showSymbol');\n\n        var isIgnoreFunc = showSymbol && !isCoordSysPolar\n            && getIsIgnoreFunc(seriesModel, data, coordSys);\n\n        // Remove temporary symbols\n        var oldData = this._data;\n        oldData && oldData.eachItemGraphicEl(function (el, idx) {\n            if (el.__temp) {\n                group.remove(el);\n                oldData.setItemGraphicEl(idx, null);\n            }\n        });\n\n        // Remove previous created symbols if showSymbol changed to false\n        if (!showSymbol) {\n            symbolDraw.remove();\n        }\n\n        group.add(lineGroup);\n\n        // FIXME step not support polar\n        var step = !isCoordSysPolar && seriesModel.get('step');\n        // Initialization animation or coordinate system changed\n        if (\n            !(polyline && prevCoordSys.type === coordSys.type && step === this._step)\n        ) {\n            showSymbol && symbolDraw.updateData(data, {\n                isIgnore: isIgnoreFunc,\n                clipShape: createClipShape(coordSys, false, true, seriesModel)\n            });\n\n            if (step) {\n                // TODO If stacked series is not step\n                points = turnPointsIntoStep(points, coordSys, step);\n                stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);\n            }\n\n            polyline = this._newPolyline(points, coordSys, hasAnimation);\n            if (isAreaChart) {\n                polygon = this._newPolygon(\n                    points, stackedOnPoints,\n                    coordSys, hasAnimation\n                );\n            }\n            lineGroup.setClipPath(createClipShape(coordSys, true, false, seriesModel));\n        }\n        else {\n            if (isAreaChart && !polygon) {\n                // If areaStyle is added\n                polygon = this._newPolygon(\n                    points, stackedOnPoints,\n                    coordSys, hasAnimation\n                );\n            }\n            else if (polygon && !isAreaChart) {\n                // If areaStyle is removed\n                lineGroup.remove(polygon);\n                polygon = this._polygon = null;\n            }\n\n            // Update clipPath\n            lineGroup.setClipPath(createClipShape(coordSys, false, false, seriesModel));\n\n            // Always update, or it is wrong in the case turning on legend\n            // because points are not changed\n            showSymbol && symbolDraw.updateData(data, {\n                isIgnore: isIgnoreFunc,\n                clipShape: createClipShape(coordSys, false, true, seriesModel)\n            });\n\n            // Stop symbol animation and sync with line points\n            // FIXME performance?\n            data.eachItemGraphicEl(function (el) {\n                el.stopAnimation(true);\n            });\n\n            // In the case data zoom triggerred refreshing frequently\n            // Data may not change if line has a category axis. So it should animate nothing\n            if (!isPointsSame(this._stackedOnPoints, stackedOnPoints)\n                || !isPointsSame(this._points, points)\n            ) {\n                if (hasAnimation) {\n                    this._updateAnimation(\n                        data, stackedOnPoints, coordSys, api, step, valueOrigin\n                    );\n                }\n                else {\n                    // Not do it in update with animation\n                    if (step) {\n                        // TODO If stacked series is not step\n                        points = turnPointsIntoStep(points, coordSys, step);\n                        stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);\n                    }\n\n                    polyline.setShape({\n                        points: points\n                    });\n                    polygon && polygon.setShape({\n                        points: points,\n                        stackedOnPoints: stackedOnPoints\n                    });\n                }\n            }\n        }\n\n        var visualColor = getVisualGradient(data, coordSys) || data.getVisual('color');\n\n        polyline.useStyle(defaults(\n            // Use color in lineStyle first\n            lineStyleModel.getLineStyle(),\n            {\n                fill: 'none',\n                stroke: visualColor,\n                lineJoin: 'bevel'\n            }\n        ));\n\n        var smooth = seriesModel.get('smooth');\n        smooth = getSmooth(seriesModel.get('smooth'));\n        polyline.setShape({\n            smooth: smooth,\n            smoothMonotone: seriesModel.get('smoothMonotone'),\n            connectNulls: seriesModel.get('connectNulls')\n        });\n\n        if (polygon) {\n            var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');\n            var stackedOnSmooth = 0;\n\n            polygon.useStyle(defaults(\n                areaStyleModel.getAreaStyle(),\n                {\n                    fill: visualColor,\n                    opacity: 0.7,\n                    lineJoin: 'bevel'\n                }\n            ));\n\n            if (stackedOnSeries) {\n                stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth'));\n            }\n\n            polygon.setShape({\n                smooth: smooth,\n                stackedOnSmooth: stackedOnSmooth,\n                smoothMonotone: seriesModel.get('smoothMonotone'),\n                connectNulls: seriesModel.get('connectNulls')\n            });\n        }\n\n        this._data = data;\n        // Save the coordinate system for transition animation when data changed\n        this._coordSys = coordSys;\n        this._stackedOnPoints = stackedOnPoints;\n        this._points = points;\n        this._step = step;\n        this._valueOrigin = valueOrigin;\n    },\n\n    dispose: function () {},\n\n    highlight: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n        var dataIndex = queryDataIndex(data, payload);\n\n        if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) {\n            var symbol = data.getItemGraphicEl(dataIndex);\n            if (!symbol) {\n                // Create a temporary symbol if it is not exists\n                var pt = data.getItemLayout(dataIndex);\n                if (!pt) {\n                    // Null data\n                    return;\n                }\n                symbol = new SymbolClz$1(data, dataIndex);\n                symbol.position = pt;\n                symbol.setZ(\n                    seriesModel.get('zlevel'),\n                    seriesModel.get('z')\n                );\n                symbol.ignore = isNaN(pt[0]) || isNaN(pt[1]);\n                symbol.__temp = true;\n                data.setItemGraphicEl(dataIndex, symbol);\n\n                // Stop scale animation\n                symbol.stopSymbolAnimation(true);\n\n                this.group.add(symbol);\n            }\n            symbol.highlight();\n        }\n        else {\n            // Highlight whole series\n            Chart.prototype.highlight.call(\n                this, seriesModel, ecModel, api, payload\n            );\n        }\n    },\n\n    downplay: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n        var dataIndex = queryDataIndex(data, payload);\n        if (dataIndex != null && dataIndex >= 0) {\n            var symbol = data.getItemGraphicEl(dataIndex);\n            if (symbol) {\n                if (symbol.__temp) {\n                    data.setItemGraphicEl(dataIndex, null);\n                    this.group.remove(symbol);\n                }\n                else {\n                    symbol.downplay();\n                }\n            }\n        }\n        else {\n            // FIXME\n            // can not downplay completely.\n            // Downplay whole series\n            Chart.prototype.downplay.call(\n                this, seriesModel, ecModel, api, payload\n            );\n        }\n    },\n\n    /**\n     * @param {module:zrender/container/Group} group\n     * @param {Array.<Array.<number>>} points\n     * @private\n     */\n    _newPolyline: function (points) {\n        var polyline = this._polyline;\n        // Remove previous created polyline\n        if (polyline) {\n            this._lineGroup.remove(polyline);\n        }\n\n        polyline = new Polyline$1({\n            shape: {\n                points: points\n            },\n            silent: true,\n            z2: 10\n        });\n\n        this._lineGroup.add(polyline);\n\n        this._polyline = polyline;\n\n        return polyline;\n    },\n\n    /**\n     * @param {module:zrender/container/Group} group\n     * @param {Array.<Array.<number>>} stackedOnPoints\n     * @param {Array.<Array.<number>>} points\n     * @private\n     */\n    _newPolygon: function (points, stackedOnPoints) {\n        var polygon = this._polygon;\n        // Remove previous created polygon\n        if (polygon) {\n            this._lineGroup.remove(polygon);\n        }\n\n        polygon = new Polygon$1({\n            shape: {\n                points: points,\n                stackedOnPoints: stackedOnPoints\n            },\n            silent: true\n        });\n\n        this._lineGroup.add(polygon);\n\n        this._polygon = polygon;\n        return polygon;\n    },\n\n    /**\n     * @private\n     */\n    // FIXME Two value axis\n    _updateAnimation: function (data, stackedOnPoints, coordSys, api, step, valueOrigin) {\n        var polyline = this._polyline;\n        var polygon = this._polygon;\n        var seriesModel = data.hostModel;\n\n        var diff = lineAnimationDiff(\n            this._data, data,\n            this._stackedOnPoints, stackedOnPoints,\n            this._coordSys, coordSys,\n            this._valueOrigin, valueOrigin\n        );\n\n        var current = diff.current;\n        var stackedOnCurrent = diff.stackedOnCurrent;\n        var next = diff.next;\n        var stackedOnNext = diff.stackedOnNext;\n        if (step) {\n            // TODO If stacked series is not step\n            current = turnPointsIntoStep(diff.current, coordSys, step);\n            stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step);\n            next = turnPointsIntoStep(diff.next, coordSys, step);\n            stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step);\n        }\n        // `diff.current` is subset of `current` (which should be ensured by\n        // turnPointsIntoStep), so points in `__points` can be updated when\n        // points in `current` are update during animation.\n        polyline.shape.__points = diff.current;\n        polyline.shape.points = current;\n\n        updateProps(polyline, {\n            shape: {\n                points: next\n            }\n        }, seriesModel);\n\n        if (polygon) {\n            polygon.setShape({\n                points: current,\n                stackedOnPoints: stackedOnCurrent\n            });\n            updateProps(polygon, {\n                shape: {\n                    points: next,\n                    stackedOnPoints: stackedOnNext\n                }\n            }, seriesModel);\n        }\n\n        var updatedDataInfo = [];\n        var diffStatus = diff.status;\n\n        for (var i = 0; i < diffStatus.length; i++) {\n            var cmd = diffStatus[i].cmd;\n            if (cmd === '=') {\n                var el = data.getItemGraphicEl(diffStatus[i].idx1);\n                if (el) {\n                    updatedDataInfo.push({\n                        el: el,\n                        ptIdx: i    // Index of points\n                    });\n                }\n            }\n        }\n\n        if (polyline.animators && polyline.animators.length) {\n            polyline.animators[0].during(function () {\n                for (var i = 0; i < updatedDataInfo.length; i++) {\n                    var el = updatedDataInfo[i].el;\n                    el.attr('position', polyline.shape.__points[updatedDataInfo[i].ptIdx]);\n                }\n            });\n        }\n    },\n\n    remove: function (ecModel) {\n        var group = this.group;\n        var oldData = this._data;\n        this._lineGroup.removeAll();\n        this._symbolDraw.remove(true);\n        // Remove temporary created elements when highlighting\n        oldData && oldData.eachItemGraphicEl(function (el, idx) {\n            if (el.__temp) {\n                group.remove(el);\n                oldData.setItemGraphicEl(idx, null);\n            }\n        });\n\n        this._polyline\n            = this._polygon\n            = this._coordSys\n            = this._points\n            = this._stackedOnPoints\n            = this._data = null;\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar visualSymbol = function (seriesType, defaultSymbolType, legendSymbol) {\n    // Encoding visual for all series include which is filtered for legend drawing\n    return {\n        seriesType: seriesType,\n\n        // For legend.\n        performRawSeries: true,\n\n        reset: function (seriesModel, ecModel, api) {\n            var data = seriesModel.getData();\n\n            var symbolType = seriesModel.get('symbol') || defaultSymbolType;\n            var symbolSize = seriesModel.get('symbolSize');\n            var keepAspect = seriesModel.get('symbolKeepAspect');\n\n            data.setVisual({\n                legendSymbol: legendSymbol || symbolType,\n                symbol: symbolType,\n                symbolSize: symbolSize,\n                symbolKeepAspect: keepAspect\n            });\n\n            // Only visible series has each data be visual encoded\n            if (ecModel.isSeriesFiltered(seriesModel)) {\n                return;\n            }\n\n            var hasCallback = typeof symbolSize === 'function';\n\n            function dataEach(data, idx) {\n                if (typeof symbolSize === 'function') {\n                    var rawValue = seriesModel.getRawValue(idx);\n                    // FIXME\n                    var params = seriesModel.getDataParams(idx);\n                    data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params));\n                }\n\n                if (data.hasItemOption) {\n                    var itemModel = data.getItemModel(idx);\n                    var itemSymbolType = itemModel.getShallow('symbol', true);\n                    var itemSymbolSize = itemModel.getShallow('symbolSize',\n                        true);\n                    var itemSymbolKeepAspect\n                        = itemModel.getShallow('symbolKeepAspect', true);\n\n                    // If has item symbol\n                    if (itemSymbolType != null) {\n                        data.setItemVisual(idx, 'symbol', itemSymbolType);\n                    }\n                    if (itemSymbolSize != null) {\n                        // PENDING Transform symbolSize ?\n                        data.setItemVisual(idx, 'symbolSize', itemSymbolSize);\n                    }\n                    if (itemSymbolKeepAspect != null) {\n                        data.setItemVisual(idx, 'symbolKeepAspect',\n                            itemSymbolKeepAspect);\n                    }\n                }\n            }\n\n            return { dataEach: (data.hasItemOption || hasCallback) ? dataEach : null };\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar pointsLayout = function (seriesType) {\n    return {\n        seriesType: seriesType,\n\n        plan: createRenderPlanner(),\n\n        reset: function (seriesModel) {\n            var data = seriesModel.getData();\n            var coordSys = seriesModel.coordinateSystem;\n            var pipelineContext = seriesModel.pipelineContext;\n            var isLargeRender = pipelineContext.large;\n\n            if (!coordSys) {\n                return;\n            }\n\n            var dims = map(coordSys.dimensions, function (dim) {\n                return data.mapDimension(dim);\n            }).slice(0, 2);\n            var dimLen = dims.length;\n\n            var stackResultDim = data.getCalculationInfo('stackResultDimension');\n            if (isDimensionStacked(data, dims[0] /*, dims[1]*/)) {\n                dims[0] = stackResultDim;\n            }\n            if (isDimensionStacked(data, dims[1] /*, dims[0]*/)) {\n                dims[1] = stackResultDim;\n            }\n\n            function progress(params, data) {\n                var segCount = params.end - params.start;\n                var points = isLargeRender && new Float32Array(segCount * dimLen);\n\n                for (var i = params.start, offset = 0, tmpIn = [], tmpOut = []; i < params.end; i++) {\n                    var point;\n\n                    if (dimLen === 1) {\n                        var x = data.get(dims[0], i);\n                        point = !isNaN(x) && coordSys.dataToPoint(x, null, tmpOut);\n                    }\n                    else {\n                        var x = tmpIn[0] = data.get(dims[0], i);\n                        var y = tmpIn[1] = data.get(dims[1], i);\n                        // Also {Array.<number>}, not undefined to avoid if...else... statement\n                        point = !isNaN(x) && !isNaN(y) && coordSys.dataToPoint(tmpIn, null, tmpOut);\n                    }\n\n                    if (isLargeRender) {\n                        points[offset++] = point ? point[0] : NaN;\n                        points[offset++] = point ? point[1] : NaN;\n                    }\n                    else {\n                        data.setItemLayout(i, (point && point.slice()) || [NaN, NaN]);\n                    }\n                }\n\n                isLargeRender && data.setLayout('symbolPoints', points);\n            }\n\n            return dimLen && {progress: progress};\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar samplers = {\n    average: function (frame) {\n        var sum = 0;\n        var count = 0;\n        for (var i = 0; i < frame.length; i++) {\n            if (!isNaN(frame[i])) {\n                sum += frame[i];\n                count++;\n            }\n        }\n        // Return NaN if count is 0\n        return count === 0 ? NaN : sum / count;\n    },\n    sum: function (frame) {\n        var sum = 0;\n        for (var i = 0; i < frame.length; i++) {\n            // Ignore NaN\n            sum += frame[i] || 0;\n        }\n        return sum;\n    },\n    max: function (frame) {\n        var max = -Infinity;\n        for (var i = 0; i < frame.length; i++) {\n            frame[i] > max && (max = frame[i]);\n        }\n        // NaN will cause illegal axis extent.\n        return isFinite(max) ? max : NaN;\n    },\n    min: function (frame) {\n        var min = Infinity;\n        for (var i = 0; i < frame.length; i++) {\n            frame[i] < min && (min = frame[i]);\n        }\n        // NaN will cause illegal axis extent.\n        return isFinite(min) ? min : NaN;\n    },\n    // TODO\n    // Median\n    nearest: function (frame) {\n        return frame[0];\n    }\n};\n\nvar indexSampler = function (frame, value) {\n    return Math.round(frame.length / 2);\n};\n\nvar dataSample = function (seriesType) {\n    return {\n\n        seriesType: seriesType,\n\n        modifyOutputEnd: true,\n\n        reset: function (seriesModel, ecModel, api) {\n            var data = seriesModel.getData();\n            var sampling = seriesModel.get('sampling');\n            var coordSys = seriesModel.coordinateSystem;\n            // Only cartesian2d support down sampling\n            if (coordSys.type === 'cartesian2d' && sampling) {\n                var baseAxis = coordSys.getBaseAxis();\n                var valueAxis = coordSys.getOtherAxis(baseAxis);\n                var extent = baseAxis.getExtent();\n                // Coordinste system has been resized\n                var size = extent[1] - extent[0];\n                var rate = Math.round(data.count() / size);\n                if (rate > 1) {\n                    var sampler;\n                    if (typeof sampling === 'string') {\n                        sampler = samplers[sampling];\n                    }\n                    else if (typeof sampling === 'function') {\n                        sampler = sampling;\n                    }\n                    if (sampler) {\n                        // Only support sample the first dim mapped from value axis.\n                        seriesModel.setData(data.downSample(\n                            data.mapDimension(valueAxis.dim), 1 / rate, sampler, indexSampler\n                        ));\n                    }\n                }\n            }\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Cartesian coordinate system\n * @module  echarts/coord/Cartesian\n *\n */\n\nfunction dimAxisMapper(dim) {\n    return this._axes[dim];\n}\n\n/**\n * @alias module:echarts/coord/Cartesian\n * @constructor\n */\nvar Cartesian = function (name) {\n    this._axes = {};\n\n    this._dimList = [];\n\n    /**\n     * @type {string}\n     */\n    this.name = name || '';\n};\n\nCartesian.prototype = {\n\n    constructor: Cartesian,\n\n    type: 'cartesian',\n\n    /**\n     * Get axis\n     * @param  {number|string} dim\n     * @return {module:echarts/coord/Cartesian~Axis}\n     */\n    getAxis: function (dim) {\n        return this._axes[dim];\n    },\n\n    /**\n     * Get axes list\n     * @return {Array.<module:echarts/coord/Cartesian~Axis>}\n     */\n    getAxes: function () {\n        return map(this._dimList, dimAxisMapper, this);\n    },\n\n    /**\n     * Get axes list by given scale type\n     */\n    getAxesByScale: function (scaleType) {\n        scaleType = scaleType.toLowerCase();\n        return filter(\n            this.getAxes(),\n            function (axis) {\n                return axis.scale.type === scaleType;\n            }\n        );\n    },\n\n    /**\n     * Add axis\n     * @param {module:echarts/coord/Cartesian.Axis}\n     */\n    addAxis: function (axis) {\n        var dim = axis.dim;\n\n        this._axes[dim] = axis;\n\n        this._dimList.push(dim);\n    },\n\n    /**\n     * Convert data to coord in nd space\n     * @param {Array.<number>|Object.<string, number>} val\n     * @return {Array.<number>|Object.<string, number>}\n     */\n    dataToCoord: function (val) {\n        return this._dataCoordConvert(val, 'dataToCoord');\n    },\n\n    /**\n     * Convert coord in nd space to data\n     * @param  {Array.<number>|Object.<string, number>} val\n     * @return {Array.<number>|Object.<string, number>}\n     */\n    coordToData: function (val) {\n        return this._dataCoordConvert(val, 'coordToData');\n    },\n\n    _dataCoordConvert: function (input, method) {\n        var dimList = this._dimList;\n\n        var output = input instanceof Array ? [] : {};\n\n        for (var i = 0; i < dimList.length; i++) {\n            var dim = dimList[i];\n            var axis = this._axes[dim];\n\n            output[dim] = axis[method](input[dim]);\n        }\n\n        return output;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction Cartesian2D(name) {\n\n    Cartesian.call(this, name);\n}\n\nCartesian2D.prototype = {\n\n    constructor: Cartesian2D,\n\n    type: 'cartesian2d',\n\n    /**\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['x', 'y'],\n\n    /**\n     * Base axis will be used on stacking.\n     *\n     * @return {module:echarts/coord/cartesian/Axis2D}\n     */\n    getBaseAxis: function () {\n        return this.getAxesByScale('ordinal')[0]\n            || this.getAxesByScale('time')[0]\n            || this.getAxis('x');\n    },\n\n    /**\n     * If contain point\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    containPoint: function (point) {\n        var axisX = this.getAxis('x');\n        var axisY = this.getAxis('y');\n        return axisX.contain(axisX.toLocalCoord(point[0]))\n            && axisY.contain(axisY.toLocalCoord(point[1]));\n    },\n\n    /**\n     * If contain data\n     * @param {Array.<number>} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this.getAxis('x').containData(data[0])\n            && this.getAxis('y').containData(data[1]);\n    },\n\n    /**\n     * @param {Array.<number>} data\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, reserved, out) {\n        var xAxis = this.getAxis('x');\n        var yAxis = this.getAxis('y');\n        out = out || [];\n        out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(data[0]));\n        out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(data[1]));\n        return out;\n    },\n\n    /**\n     * @param {Array.<number>} data\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    clampData: function (data, out) {\n        var xScale = this.getAxis('x').scale;\n        var yScale = this.getAxis('y').scale;\n        var xAxisExtent = xScale.getExtent();\n        var yAxisExtent = yScale.getExtent();\n        var x = xScale.parse(data[0]);\n        var y = yScale.parse(data[1]);\n        out = out || [];\n        out[0] = Math.min(\n            Math.max(Math.min(xAxisExtent[0], xAxisExtent[1]), x),\n            Math.max(xAxisExtent[0], xAxisExtent[1])\n        );\n        out[1] = Math.min(\n            Math.max(Math.min(yAxisExtent[0], yAxisExtent[1]), y),\n            Math.max(yAxisExtent[0], yAxisExtent[1])\n        );\n\n        return out;\n    },\n\n    /**\n     * @param {Array.<number>} point\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    pointToData: function (point, out) {\n        var xAxis = this.getAxis('x');\n        var yAxis = this.getAxis('y');\n        out = out || [];\n        out[0] = xAxis.coordToData(xAxis.toLocalCoord(point[0]));\n        out[1] = yAxis.coordToData(yAxis.toLocalCoord(point[1]));\n        return out;\n    },\n\n    /**\n     * Get other axis\n     * @param {module:echarts/coord/cartesian/Axis2D} axis\n     */\n    getOtherAxis: function (axis) {\n        return this.getAxis(axis.dim === 'x' ? 'y' : 'x');\n    }\n\n};\n\ninherits(Cartesian2D, Cartesian);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Extend axis 2d\n * @constructor module:echarts/coord/cartesian/Axis2D\n * @extends {module:echarts/coord/cartesian/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n * @param {string} position\n */\nvar Axis2D = function (dim, scale, coordExtent, axisType, position) {\n    Axis.call(this, dim, scale, coordExtent);\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * Axis position\n     *  - 'top'\n     *  - 'bottom'\n     *  - 'left'\n     *  - 'right'\n     */\n    this.position = position || 'bottom';\n};\n\nAxis2D.prototype = {\n\n    constructor: Axis2D,\n\n    /**\n     * Index of axis, can be used as key\n     */\n    index: 0,\n\n    /**\n     * Implemented in <module:echarts/coord/cartesian/Grid>.\n     * @return {Array.<module:echarts/coord/cartesian/Axis2D>}\n     *         If not on zero of other axis, return null/undefined.\n     *         If no axes, return an empty array.\n     */\n    getAxesOnZeroOf: null,\n\n    /**\n     * Axis model\n     * @param {module:echarts/coord/cartesian/AxisModel}\n     */\n    model: null,\n\n    isHorizontal: function () {\n        var position = this.position;\n        return position === 'top' || position === 'bottom';\n    },\n\n    /**\n     * Each item cooresponds to this.getExtent(), which\n     * means globalExtent[0] may greater than globalExtent[1],\n     * unless `asc` is input.\n     *\n     * @param {boolean} [asc]\n     * @return {Array.<number>}\n     */\n    getGlobalExtent: function (asc) {\n        var ret = this.getExtent();\n        ret[0] = this.toGlobalCoord(ret[0]);\n        ret[1] = this.toGlobalCoord(ret[1]);\n        asc && ret[0] > ret[1] && ret.reverse();\n        return ret;\n    },\n\n    getOtherAxis: function () {\n        this.grid.getOtherAxis();\n    },\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.coordToData(this.toLocalCoord(point[this.dim === 'x' ? 0 : 1]), clamp);\n    },\n\n    /**\n     * Transform global coord to local coord,\n     * i.e. var localCoord = axis.toLocalCoord(80);\n     * designate by module:echarts/coord/cartesian/Grid.\n     * @type {Function}\n     */\n    toLocalCoord: null,\n\n    /**\n     * Transform global coord to local coord,\n     * i.e. var globalCoord = axis.toLocalCoord(40);\n     * designate by module:echarts/coord/cartesian/Grid.\n     * @type {Function}\n     */\n    toGlobalCoord: null\n\n};\n\ninherits(Axis2D, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar defaultOption = {\n    show: true,\n    zlevel: 0,\n    z: 0,\n    // Inverse the axis.\n    inverse: false,\n\n    // Axis name displayed.\n    name: '',\n    // 'start' | 'middle' | 'end'\n    nameLocation: 'end',\n    // By degree. By defualt auto rotate by nameLocation.\n    nameRotate: null,\n    nameTruncate: {\n        maxWidth: null,\n        ellipsis: '...',\n        placeholder: '.'\n    },\n    // Use global text style by default.\n    nameTextStyle: {},\n    // The gap between axisName and axisLine.\n    nameGap: 15,\n\n    // Default `false` to support tooltip.\n    silent: false,\n    // Default `false` to avoid legacy user event listener fail.\n    triggerEvent: false,\n\n    tooltip: {\n        show: false\n    },\n\n    axisPointer: {},\n\n    axisLine: {\n        show: true,\n        onZero: true,\n        onZeroAxisIndex: null,\n        lineStyle: {\n            color: '#333',\n            width: 1,\n            type: 'solid'\n        },\n        // The arrow at both ends the the axis.\n        symbol: ['none', 'none'],\n        symbolSize: [10, 15]\n    },\n    axisTick: {\n        show: true,\n        // Whether axisTick is inside the grid or outside the grid.\n        inside: false,\n        // The length of axisTick.\n        length: 5,\n        lineStyle: {\n            width: 1\n        }\n    },\n    axisLabel: {\n        show: true,\n        // Whether axisLabel is inside the grid or outside the grid.\n        inside: false,\n        rotate: 0,\n        // true | false | null/undefined (auto)\n        showMinLabel: null,\n        // true | false | null/undefined (auto)\n        showMaxLabel: null,\n        margin: 8,\n        // formatter: null,\n        fontSize: 12\n    },\n    splitLine: {\n        show: true,\n        lineStyle: {\n            color: ['#ccc'],\n            width: 1,\n            type: 'solid'\n        }\n    },\n    splitArea: {\n        show: false,\n        areaStyle: {\n            color: ['rgba(250,250,250,0.3)', 'rgba(200,200,200,0.3)']\n        }\n    }\n};\n\nvar axisDefault = {};\n\naxisDefault.categoryAxis = merge({\n    // The gap at both ends of the axis. For categoryAxis, boolean.\n    boundaryGap: true,\n    // Set false to faster category collection.\n    // Only usefull in the case like: category is\n    // ['2012-01-01', '2012-01-02', ...], where the input\n    // data has been ensured not duplicate and is large data.\n    // null means \"auto\":\n    // if axis.data provided, do not deduplication,\n    // else do deduplication.\n    deduplication: null,\n    // splitArea: {\n        // show: false\n    // },\n    splitLine: {\n        show: false\n    },\n    axisTick: {\n        // If tick is align with label when boundaryGap is true\n        alignWithLabel: false,\n        interval: 'auto'\n    },\n    axisLabel: {\n        interval: 'auto'\n    }\n}, defaultOption);\n\naxisDefault.valueAxis = merge({\n    // The gap at both ends of the axis. For value axis, [GAP, GAP], where\n    // `GAP` can be an absolute pixel number (like `35`), or percent (like `'30%'`)\n    boundaryGap: [0, 0],\n\n    // TODO\n    // min/max: [30, datamin, 60] or [20, datamin] or [datamin, 60]\n\n    // Min value of the axis. can be:\n    // + a number\n    // + 'dataMin': use the min value in data.\n    // + null/undefined: auto decide min value (consider pretty look and boundaryGap).\n    // min: null,\n\n    // Max value of the axis. can be:\n    // + a number\n    // + 'dataMax': use the max value in data.\n    // + null/undefined: auto decide max value (consider pretty look and boundaryGap).\n    // max: null,\n\n    // Readonly prop, specifies start value of the range when using data zoom.\n    // rangeStart: null\n\n    // Readonly prop, specifies end value of the range when using data zoom.\n    // rangeEnd: null\n\n    // Optional value can be:\n    // + `false`: always include value 0.\n    // + `true`: the extent do not consider value 0.\n    // scale: false,\n\n    // AxisTick and axisLabel and splitLine are caculated based on splitNumber.\n    splitNumber: 5\n\n    // Interval specifies the span of the ticks is mandatorily.\n    // interval: null\n\n    // Specify min interval when auto calculate tick interval.\n    // minInterval: null\n\n    // Specify max interval when auto calculate tick interval.\n    // maxInterval: null\n\n}, defaultOption);\n\naxisDefault.timeAxis = defaults({\n    scale: true,\n    min: 'dataMin',\n    max: 'dataMax'\n}, axisDefault.valueAxis);\n\naxisDefault.logAxis = defaults({\n    scale: true,\n    logBase: 10\n}, axisDefault.valueAxis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME axisType is fixed ?\nvar AXIS_TYPES = ['value', 'category', 'time', 'log'];\n\n/**\n * Generate sub axis model class\n * @param {string} axisName 'x' 'y' 'radius' 'angle' 'parallel'\n * @param {module:echarts/model/Component} BaseAxisModelClass\n * @param {Function} axisTypeDefaulter\n * @param {Object} [extraDefaultOption]\n */\nvar axisModelCreator = function (axisName, BaseAxisModelClass, axisTypeDefaulter, extraDefaultOption) {\n\n    each$1(AXIS_TYPES, function (axisType) {\n\n        BaseAxisModelClass.extend({\n\n            /**\n             * @readOnly\n             */\n            type: axisName + 'Axis.' + axisType,\n\n            mergeDefaultAndTheme: function (option, ecModel) {\n                var layoutMode = this.layoutMode;\n                var inputPositionParams = layoutMode\n                    ? getLayoutParams(option) : {};\n\n                var themeModel = ecModel.getTheme();\n                merge(option, themeModel.get(axisType + 'Axis'));\n                merge(option, this.getDefaultOption());\n\n                option.type = axisTypeDefaulter(axisName, option);\n\n                if (layoutMode) {\n                    mergeLayoutParam(option, inputPositionParams, layoutMode);\n                }\n            },\n\n            /**\n             * @override\n             */\n            optionUpdated: function () {\n                var thisOption = this.option;\n                if (thisOption.type === 'category') {\n                    this.__ordinalMeta = OrdinalMeta.createByAxisModel(this);\n                }\n            },\n\n            /**\n             * Should not be called before all of 'getInitailData' finished.\n             * Because categories are collected during initializing data.\n             */\n            getCategories: function (rawData) {\n                var option = this.option;\n                // FIXME\n                // warning if called before all of 'getInitailData' finished.\n                if (option.type === 'category') {\n                    if (rawData) {\n                        return option.data;\n                    }\n                    return this.__ordinalMeta.categories;\n                }\n            },\n\n            getOrdinalMeta: function () {\n                return this.__ordinalMeta;\n            },\n\n            defaultOption: mergeAll(\n                [\n                    {},\n                    axisDefault[axisType + 'Axis'],\n                    extraDefaultOption\n                ],\n                true\n            )\n        });\n    });\n\n    ComponentModel.registerSubTypeDefaulter(\n        axisName + 'Axis',\n        curry(axisTypeDefaulter, axisName)\n    );\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisModel = ComponentModel.extend({\n\n    type: 'cartesian2dAxis',\n\n    /**\n     * @type {module:echarts/coord/cartesian/Axis2D}\n     */\n    axis: null,\n\n    /**\n     * @override\n     */\n    init: function () {\n        AxisModel.superApply(this, 'init', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function () {\n        AxisModel.superApply(this, 'mergeOption', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     */\n    restoreData: function () {\n        AxisModel.superApply(this, 'restoreData', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     * @return {module:echarts/model/Component}\n     */\n    getCoordSysModel: function () {\n        return this.ecModel.queryComponents({\n            mainType: 'grid',\n            index: this.option.gridIndex,\n            id: this.option.gridId\n        })[0];\n    }\n\n});\n\nfunction getAxisType(axisDim, option) {\n    // Default axis with data is category axis\n    return option.type || (option.data ? 'category' : 'value');\n}\n\nmerge(AxisModel.prototype, axisModelCommonMixin);\n\nvar extraOption = {\n    // gridIndex: 0,\n    // gridId: '',\n\n    // Offset is for multiple axis on the same position\n    offset: 0\n};\n\naxisModelCreator('x', AxisModel, getAxisType, extraOption);\naxisModelCreator('y', AxisModel, getAxisType, extraOption);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Grid 是在有直角坐标系的时候必须要存在的\n// 所以这里也要被 Cartesian2D 依赖\n\nComponentModel.extend({\n\n    type: 'grid',\n\n    dependencies: ['xAxis', 'yAxis'],\n\n    layoutMode: 'box',\n\n    /**\n     * @type {module:echarts/coord/cartesian/Grid}\n     */\n    coordinateSystem: null,\n\n    defaultOption: {\n        show: false,\n        zlevel: 0,\n        z: 0,\n        left: '10%',\n        top: 60,\n        right: '10%',\n        bottom: 60,\n        // If grid size contain label\n        containLabel: false,\n        // width: {totalWidth} - left - right,\n        // height: {totalHeight} - top - bottom,\n        backgroundColor: 'rgba(0,0,0,0)',\n        borderWidth: 1,\n        borderColor: '#ccc'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Grid is a region which contains at most 4 cartesian systems\n *\n * TODO Default cartesian\n */\n\n// Depends on GridModel, AxisModel, which performs preprocess.\n/**\n * Check if the axis is used in the specified grid\n * @inner\n */\nfunction isAxisUsedInTheGrid(axisModel, gridModel, ecModel) {\n    return axisModel.getCoordSysModel() === gridModel;\n}\n\nfunction Grid(gridModel, ecModel, api) {\n    /**\n     * @type {Object.<string, module:echarts/coord/cartesian/Cartesian2D>}\n     * @private\n     */\n    this._coordsMap = {};\n\n    /**\n     * @type {Array.<module:echarts/coord/cartesian/Cartesian>}\n     * @private\n     */\n    this._coordsList = [];\n\n    /**\n     * @type {Object.<string, module:echarts/coord/cartesian/Axis2D>}\n     * @private\n     */\n    this._axesMap = {};\n\n    /**\n     * @type {Array.<module:echarts/coord/cartesian/Axis2D>}\n     * @private\n     */\n    this._axesList = [];\n\n    this._initCartesian(gridModel, ecModel, api);\n\n    this.model = gridModel;\n}\n\nvar gridProto = Grid.prototype;\n\ngridProto.type = 'grid';\n\ngridProto.axisPointerEnabled = true;\n\ngridProto.getRect = function () {\n    return this._rect;\n};\n\ngridProto.update = function (ecModel, api) {\n\n    var axesMap = this._axesMap;\n\n    this._updateScale(ecModel, this.model);\n\n    each$1(axesMap.x, function (xAxis) {\n        niceScaleExtent(xAxis.scale, xAxis.model);\n    });\n    each$1(axesMap.y, function (yAxis) {\n        niceScaleExtent(yAxis.scale, yAxis.model);\n    });\n\n    // Key: axisDim_axisIndex, value: boolean, whether onZero target.\n    var onZeroRecords = {};\n\n    each$1(axesMap.x, function (xAxis) {\n        fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords);\n    });\n    each$1(axesMap.y, function (yAxis) {\n        fixAxisOnZero(axesMap, 'x', yAxis, onZeroRecords);\n    });\n\n    // Resize again if containLabel is enabled\n    // FIXME It may cause getting wrong grid size in data processing stage\n    this.resize(this.model, api);\n};\n\nfunction fixAxisOnZero(axesMap, otherAxisDim, axis, onZeroRecords) {\n\n    axis.getAxesOnZeroOf = function () {\n        // TODO: onZero of multiple axes.\n        return otherAxisOnZeroOf ? [otherAxisOnZeroOf] : [];\n    };\n\n    // onZero can not be enabled in these two situations:\n    // 1. When any other axis is a category axis.\n    // 2. When no axis is cross 0 point.\n    var otherAxes = axesMap[otherAxisDim];\n\n    var otherAxisOnZeroOf;\n    var axisModel = axis.model;\n    var onZero = axisModel.get('axisLine.onZero');\n    var onZeroAxisIndex = axisModel.get('axisLine.onZeroAxisIndex');\n\n    if (!onZero) {\n        return;\n    }\n\n    // If target axis is specified.\n    if (onZeroAxisIndex != null) {\n        if (canOnZeroToAxis(otherAxes[onZeroAxisIndex])) {\n            otherAxisOnZeroOf = otherAxes[onZeroAxisIndex];\n        }\n    }\n    else {\n        // Find the first available other axis.\n        for (var idx in otherAxes) {\n            if (otherAxes.hasOwnProperty(idx)\n                && canOnZeroToAxis(otherAxes[idx])\n                // Consider that two Y axes on one value axis,\n                // if both onZero, the two Y axes overlap.\n                && !onZeroRecords[getOnZeroRecordKey(otherAxes[idx])]\n            ) {\n                otherAxisOnZeroOf = otherAxes[idx];\n                break;\n            }\n        }\n    }\n\n    if (otherAxisOnZeroOf) {\n        onZeroRecords[getOnZeroRecordKey(otherAxisOnZeroOf)] = true;\n    }\n\n    function getOnZeroRecordKey(axis) {\n        return axis.dim + '_' + axis.index;\n    }\n}\n\nfunction canOnZeroToAxis(axis) {\n    return axis && axis.type !== 'category' && axis.type !== 'time' && ifAxisCrossZero(axis);\n}\n\n/**\n * Resize the grid\n * @param {module:echarts/coord/cartesian/GridModel} gridModel\n * @param {module:echarts/ExtensionAPI} api\n */\ngridProto.resize = function (gridModel, api, ignoreContainLabel) {\n\n    var gridRect = getLayoutRect(\n        gridModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        });\n\n    this._rect = gridRect;\n\n    var axesList = this._axesList;\n\n    adjustAxes();\n\n    // Minus label size\n    if (!ignoreContainLabel && gridModel.get('containLabel')) {\n        each$1(axesList, function (axis) {\n            if (!axis.model.get('axisLabel.inside')) {\n                var labelUnionRect = estimateLabelUnionRect(axis);\n                if (labelUnionRect) {\n                    var dim = axis.isHorizontal() ? 'height' : 'width';\n                    var margin = axis.model.get('axisLabel.margin');\n                    gridRect[dim] -= labelUnionRect[dim] + margin;\n                    if (axis.position === 'top') {\n                        gridRect.y += labelUnionRect.height + margin;\n                    }\n                    else if (axis.position === 'left') {\n                        gridRect.x += labelUnionRect.width + margin;\n                    }\n                }\n            }\n        });\n\n        adjustAxes();\n    }\n\n    function adjustAxes() {\n        each$1(axesList, function (axis) {\n            var isHorizontal = axis.isHorizontal();\n            var extent = isHorizontal ? [0, gridRect.width] : [0, gridRect.height];\n            var idx = axis.inverse ? 1 : 0;\n            axis.setExtent(extent[idx], extent[1 - idx]);\n            updateAxisTransform(axis, isHorizontal ? gridRect.x : gridRect.y);\n        });\n    }\n};\n\n/**\n * @param {string} axisType\n * @param {number} [axisIndex]\n */\ngridProto.getAxis = function (axisType, axisIndex) {\n    var axesMapOnDim = this._axesMap[axisType];\n    if (axesMapOnDim != null) {\n        if (axisIndex == null) {\n            // Find first axis\n            for (var name in axesMapOnDim) {\n                if (axesMapOnDim.hasOwnProperty(name)) {\n                    return axesMapOnDim[name];\n                }\n            }\n        }\n        return axesMapOnDim[axisIndex];\n    }\n};\n\n/**\n * @return {Array.<module:echarts/coord/Axis>}\n */\ngridProto.getAxes = function () {\n    return this._axesList.slice();\n};\n\n/**\n * Usage:\n *      grid.getCartesian(xAxisIndex, yAxisIndex);\n *      grid.getCartesian(xAxisIndex);\n *      grid.getCartesian(null, yAxisIndex);\n *      grid.getCartesian({xAxisIndex: ..., yAxisIndex: ...});\n *\n * @param {number|Object} [xAxisIndex]\n * @param {number} [yAxisIndex]\n */\ngridProto.getCartesian = function (xAxisIndex, yAxisIndex) {\n    if (xAxisIndex != null && yAxisIndex != null) {\n        var key = 'x' + xAxisIndex + 'y' + yAxisIndex;\n        return this._coordsMap[key];\n    }\n\n    if (isObject$1(xAxisIndex)) {\n        yAxisIndex = xAxisIndex.yAxisIndex;\n        xAxisIndex = xAxisIndex.xAxisIndex;\n    }\n    // When only xAxisIndex or yAxisIndex given, find its first cartesian.\n    for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) {\n        if (coordList[i].getAxis('x').index === xAxisIndex\n            || coordList[i].getAxis('y').index === yAxisIndex\n        ) {\n            return coordList[i];\n        }\n    }\n};\n\ngridProto.getCartesians = function () {\n    return this._coordsList.slice();\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.convertToPixel = function (ecModel, finder, value) {\n    var target = this._findConvertTarget(ecModel, finder);\n\n    return target.cartesian\n        ? target.cartesian.dataToPoint(value)\n        : target.axis\n        ? target.axis.toGlobalCoord(target.axis.dataToCoord(value))\n        : null;\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.convertFromPixel = function (ecModel, finder, value) {\n    var target = this._findConvertTarget(ecModel, finder);\n\n    return target.cartesian\n        ? target.cartesian.pointToData(value)\n        : target.axis\n        ? target.axis.coordToData(target.axis.toLocalCoord(value))\n        : null;\n};\n\n/**\n * @inner\n */\ngridProto._findConvertTarget = function (ecModel, finder) {\n    var seriesModel = finder.seriesModel;\n    var xAxisModel = finder.xAxisModel\n        || (seriesModel && seriesModel.getReferringComponents('xAxis')[0]);\n    var yAxisModel = finder.yAxisModel\n        || (seriesModel && seriesModel.getReferringComponents('yAxis')[0]);\n    var gridModel = finder.gridModel;\n    var coordsList = this._coordsList;\n    var cartesian;\n    var axis;\n\n    if (seriesModel) {\n        cartesian = seriesModel.coordinateSystem;\n        indexOf(coordsList, cartesian) < 0 && (cartesian = null);\n    }\n    else if (xAxisModel && yAxisModel) {\n        cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);\n    }\n    else if (xAxisModel) {\n        axis = this.getAxis('x', xAxisModel.componentIndex);\n    }\n    else if (yAxisModel) {\n        axis = this.getAxis('y', yAxisModel.componentIndex);\n    }\n    // Lowest priority.\n    else if (gridModel) {\n        var grid = gridModel.coordinateSystem;\n        if (grid === this) {\n            cartesian = this._coordsList[0];\n        }\n    }\n\n    return {cartesian: cartesian, axis: axis};\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.containPoint = function (point) {\n    var coord = this._coordsList[0];\n    if (coord) {\n        return coord.containPoint(point);\n    }\n};\n\n/**\n * Initialize cartesian coordinate systems\n * @private\n */\ngridProto._initCartesian = function (gridModel, ecModel, api) {\n    var axisPositionUsed = {\n        left: false,\n        right: false,\n        top: false,\n        bottom: false\n    };\n\n    var axesMap = {\n        x: {},\n        y: {}\n    };\n    var axesCount = {\n        x: 0,\n        y: 0\n    };\n\n    /// Create axis\n    ecModel.eachComponent('xAxis', createAxisCreator('x'), this);\n    ecModel.eachComponent('yAxis', createAxisCreator('y'), this);\n\n    if (!axesCount.x || !axesCount.y) {\n        // Roll back when there no either x or y axis\n        this._axesMap = {};\n        this._axesList = [];\n        return;\n    }\n\n    this._axesMap = axesMap;\n\n    /// Create cartesian2d\n    each$1(axesMap.x, function (xAxis, xAxisIndex) {\n        each$1(axesMap.y, function (yAxis, yAxisIndex) {\n            var key = 'x' + xAxisIndex + 'y' + yAxisIndex;\n            var cartesian = new Cartesian2D(key);\n\n            cartesian.grid = this;\n            cartesian.model = gridModel;\n\n            this._coordsMap[key] = cartesian;\n            this._coordsList.push(cartesian);\n\n            cartesian.addAxis(xAxis);\n            cartesian.addAxis(yAxis);\n        }, this);\n    }, this);\n\n    function createAxisCreator(axisType) {\n        return function (axisModel, idx) {\n            if (!isAxisUsedInTheGrid(axisModel, gridModel, ecModel)) {\n                return;\n            }\n\n            var axisPosition = axisModel.get('position');\n            if (axisType === 'x') {\n                // Fix position\n                if (axisPosition !== 'top' && axisPosition !== 'bottom') {\n                    // Default bottom of X\n                    axisPosition = 'bottom';\n                    if (axisPositionUsed[axisPosition]) {\n                        axisPosition = axisPosition === 'top' ? 'bottom' : 'top';\n                    }\n                }\n            }\n            else {\n                // Fix position\n                if (axisPosition !== 'left' && axisPosition !== 'right') {\n                    // Default left of Y\n                    axisPosition = 'left';\n                    if (axisPositionUsed[axisPosition]) {\n                        axisPosition = axisPosition === 'left' ? 'right' : 'left';\n                    }\n                }\n            }\n            axisPositionUsed[axisPosition] = true;\n\n            var axis = new Axis2D(\n                axisType, createScaleByModel(axisModel),\n                [0, 0],\n                axisModel.get('type'),\n                axisPosition\n            );\n\n            var isCategory = axis.type === 'category';\n            axis.onBand = isCategory && axisModel.get('boundaryGap');\n            axis.inverse = axisModel.get('inverse');\n\n            // Inject axis into axisModel\n            axisModel.axis = axis;\n\n            // Inject axisModel into axis\n            axis.model = axisModel;\n\n            // Inject grid info axis\n            axis.grid = this;\n\n            // Index of axis, can be used as key\n            axis.index = idx;\n\n            this._axesList.push(axis);\n\n            axesMap[axisType][idx] = axis;\n            axesCount[axisType]++;\n        };\n    }\n};\n\n/**\n * Update cartesian properties from series\n * @param  {module:echarts/model/Option} option\n * @private\n */\ngridProto._updateScale = function (ecModel, gridModel) {\n    // Reset scale\n    each$1(this._axesList, function (axis) {\n        axis.scale.setExtent(Infinity, -Infinity);\n    });\n    ecModel.eachSeries(function (seriesModel) {\n        if (isCartesian2D(seriesModel)) {\n            var axesModels = findAxesModels(seriesModel, ecModel);\n            var xAxisModel = axesModels[0];\n            var yAxisModel = axesModels[1];\n\n            if (!isAxisUsedInTheGrid(xAxisModel, gridModel, ecModel)\n                || !isAxisUsedInTheGrid(yAxisModel, gridModel, ecModel)\n            ) {\n                return;\n            }\n\n            var cartesian = this.getCartesian(\n                xAxisModel.componentIndex, yAxisModel.componentIndex\n            );\n            var data = seriesModel.getData();\n            var xAxis = cartesian.getAxis('x');\n            var yAxis = cartesian.getAxis('y');\n\n            if (data.type === 'list') {\n                unionExtent(data, xAxis, seriesModel);\n                unionExtent(data, yAxis, seriesModel);\n            }\n        }\n    }, this);\n\n    function unionExtent(data, axis, seriesModel) {\n        each$1(data.mapDimension(axis.dim, true), function (dim) {\n            axis.scale.unionExtentFromData(\n                // For example, the extent of the orginal dimension\n                // is [0.1, 0.5], the extent of the `stackResultDimension`\n                // is [7, 9], the final extent should not include [0.1, 0.5].\n                data, getStackedDimension(data, dim)\n            );\n        });\n    }\n};\n\n/**\n * @param {string} [dim] 'x' or 'y' or 'auto' or null/undefined\n * @return {Object} {baseAxes: [], otherAxes: []}\n */\ngridProto.getTooltipAxes = function (dim) {\n    var baseAxes = [];\n    var otherAxes = [];\n\n    each$1(this.getCartesians(), function (cartesian) {\n        var baseAxis = (dim != null && dim !== 'auto')\n            ? cartesian.getAxis(dim) : cartesian.getBaseAxis();\n        var otherAxis = cartesian.getOtherAxis(baseAxis);\n        indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis);\n        indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis);\n    });\n\n    return {baseAxes: baseAxes, otherAxes: otherAxes};\n};\n\n/**\n * @inner\n */\nfunction updateAxisTransform(axis, coordBase) {\n    var axisExtent = axis.getExtent();\n    var axisExtentSum = axisExtent[0] + axisExtent[1];\n\n    // Fast transform\n    axis.toGlobalCoord = axis.dim === 'x'\n        ? function (coord) {\n            return coord + coordBase;\n        }\n        : function (coord) {\n            return axisExtentSum - coord + coordBase;\n        };\n    axis.toLocalCoord = axis.dim === 'x'\n        ? function (coord) {\n            return coord - coordBase;\n        }\n        : function (coord) {\n            return axisExtentSum - coord + coordBase;\n        };\n}\n\nvar axesTypes = ['xAxis', 'yAxis'];\n/**\n * @inner\n */\nfunction findAxesModels(seriesModel, ecModel) {\n    return map(axesTypes, function (axisType) {\n        var axisModel = seriesModel.getReferringComponents(axisType)[0];\n\n        if (__DEV__) {\n            if (!axisModel) {\n                throw new Error(axisType + ' \"' + retrieve(\n                    seriesModel.get(axisType + 'Index'),\n                    seriesModel.get(axisType + 'Id'),\n                    0\n                ) + '\" not found');\n            }\n        }\n        return axisModel;\n    });\n}\n\n/**\n * @inner\n */\nfunction isCartesian2D(seriesModel) {\n    return seriesModel.get('coordinateSystem') === 'cartesian2d';\n}\n\nGrid.create = function (ecModel, api) {\n    var grids = [];\n    ecModel.eachComponent('grid', function (gridModel, idx) {\n        var grid = new Grid(gridModel, ecModel, api);\n        grid.name = 'grid_' + idx;\n        // dataSampling requires axis extent, so resize\n        // should be performed in create stage.\n        grid.resize(gridModel, api, true);\n\n        gridModel.coordinateSystem = grid;\n\n        grids.push(grid);\n    });\n\n    // Inject the coordinateSystems into seriesModel\n    ecModel.eachSeries(function (seriesModel) {\n        if (!isCartesian2D(seriesModel)) {\n            return;\n        }\n\n        var axesModels = findAxesModels(seriesModel, ecModel);\n        var xAxisModel = axesModels[0];\n        var yAxisModel = axesModels[1];\n\n        var gridModel = xAxisModel.getCoordSysModel();\n\n        if (__DEV__) {\n            if (!gridModel) {\n                throw new Error(\n                    'Grid \"' + retrieve(\n                        xAxisModel.get('gridIndex'),\n                        xAxisModel.get('gridId'),\n                        0\n                    ) + '\" not found'\n                );\n            }\n            if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) {\n                throw new Error('xAxis and yAxis must use the same grid');\n            }\n        }\n\n        var grid = gridModel.coordinateSystem;\n\n        seriesModel.coordinateSystem = grid.getCartesian(\n            xAxisModel.componentIndex, yAxisModel.componentIndex\n        );\n    });\n\n    return grids;\n};\n\n// For deciding which dimensions to use when creating list data\nGrid.dimensions = Grid.prototype.dimensions = Cartesian2D.prototype.dimensions;\n\nCoordinateSystemManager.register('cartesian2d', Grid);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PI$2 = Math.PI;\n\nfunction makeAxisEventDataBase(axisModel) {\n    var eventData = {\n        componentType: axisModel.mainType,\n        componentIndex: axisModel.componentIndex\n    };\n    eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex;\n    return eventData;\n}\n\n/**\n * A final axis is translated and rotated from a \"standard axis\".\n * So opt.position and opt.rotation is required.\n *\n * A standard axis is and axis from [0, 0] to [0, axisExtent[1]],\n * for example: (0, 0) ------------> (0, 50)\n *\n * nameDirection or tickDirection or labelDirection is 1 means tick\n * or label is below the standard axis, whereas is -1 means above\n * the standard axis. labelOffset means offset between label and axis,\n * which is useful when 'onZero', where axisLabel is in the grid and\n * label in outside grid.\n *\n * Tips: like always,\n * positive rotation represents anticlockwise, and negative rotation\n * represents clockwise.\n * The direction of position coordinate is the same as the direction\n * of screen coordinate.\n *\n * Do not need to consider axis 'inverse', which is auto processed by\n * axis extent.\n *\n * @param {module:zrender/container/Group} group\n * @param {Object} axisModel\n * @param {Object} opt Standard axis parameters.\n * @param {Array.<number>} opt.position [x, y]\n * @param {number} opt.rotation by radian\n * @param {number} [opt.nameDirection=1] 1 or -1 Used when nameLocation is 'middle' or 'center'.\n * @param {number} [opt.tickDirection=1] 1 or -1\n * @param {number} [opt.labelDirection=1] 1 or -1\n * @param {number} [opt.labelOffset=0] Usefull when onZero.\n * @param {string} [opt.axisLabelShow] default get from axisModel.\n * @param {string} [opt.axisName] default get from axisModel.\n * @param {number} [opt.axisNameAvailableWidth]\n * @param {number} [opt.labelRotate] by degree, default get from axisModel.\n * @param {number} [opt.strokeContainThreshold] Default label interval when label\n * @param {number} [opt.nameTruncateMaxWidth]\n */\nvar AxisBuilder = function (axisModel, opt) {\n\n    /**\n     * @readOnly\n     */\n    this.opt = opt;\n\n    /**\n     * @readOnly\n     */\n    this.axisModel = axisModel;\n\n    // Default value\n    defaults(\n        opt,\n        {\n            labelOffset: 0,\n            nameDirection: 1,\n            tickDirection: 1,\n            labelDirection: 1,\n            silent: true\n        }\n    );\n\n    /**\n     * @readOnly\n     */\n    this.group = new Group();\n\n    // FIXME Not use a seperate text group?\n    var dumbGroup = new Group({\n        position: opt.position.slice(),\n        rotation: opt.rotation\n    });\n\n    // this.group.add(dumbGroup);\n    // this._dumbGroup = dumbGroup;\n\n    dumbGroup.updateTransform();\n    this._transform = dumbGroup.transform;\n\n    this._dumbGroup = dumbGroup;\n};\n\nAxisBuilder.prototype = {\n\n    constructor: AxisBuilder,\n\n    hasBuilder: function (name) {\n        return !!builders[name];\n    },\n\n    add: function (name) {\n        builders[name].call(this);\n    },\n\n    getGroup: function () {\n        return this.group;\n    }\n\n};\n\nvar builders = {\n\n    /**\n     * @private\n     */\n    axisLine: function () {\n        var opt = this.opt;\n        var axisModel = this.axisModel;\n\n        if (!axisModel.get('axisLine.show')) {\n            return;\n        }\n\n        var extent = this.axisModel.axis.getExtent();\n\n        var matrix = this._transform;\n        var pt1 = [extent[0], 0];\n        var pt2 = [extent[1], 0];\n        if (matrix) {\n            applyTransform(pt1, pt1, matrix);\n            applyTransform(pt2, pt2, matrix);\n        }\n\n        var lineStyle = extend(\n            {\n                lineCap: 'round'\n            },\n            axisModel.getModel('axisLine.lineStyle').getLineStyle()\n        );\n\n        this.group.add(new Line(subPixelOptimizeLine({\n            // Id for animation\n            anid: 'line',\n\n            shape: {\n                x1: pt1[0],\n                y1: pt1[1],\n                x2: pt2[0],\n                y2: pt2[1]\n            },\n            style: lineStyle,\n            strokeContainThreshold: opt.strokeContainThreshold || 5,\n            silent: true,\n            z2: 1\n        })));\n\n        var arrows = axisModel.get('axisLine.symbol');\n        var arrowSize = axisModel.get('axisLine.symbolSize');\n\n        var arrowOffset = axisModel.get('axisLine.symbolOffset') || 0;\n        if (typeof arrowOffset === 'number') {\n            arrowOffset = [arrowOffset, arrowOffset];\n        }\n\n        if (arrows != null) {\n            if (typeof arrows === 'string') {\n                // Use the same arrow for start and end point\n                arrows = [arrows, arrows];\n            }\n            if (typeof arrowSize === 'string'\n                || typeof arrowSize === 'number'\n            ) {\n                // Use the same size for width and height\n                arrowSize = [arrowSize, arrowSize];\n            }\n\n            var symbolWidth = arrowSize[0];\n            var symbolHeight = arrowSize[1];\n\n            each$1([{\n                rotate: opt.rotation + Math.PI / 2,\n                offset: arrowOffset[0],\n                r: 0\n            }, {\n                rotate: opt.rotation - Math.PI / 2,\n                offset: arrowOffset[1],\n                r: Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0])\n                    + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1]))\n            }], function (point, index) {\n                if (arrows[index] !== 'none' && arrows[index] != null) {\n                    var symbol = createSymbol(\n                        arrows[index],\n                        -symbolWidth / 2,\n                        -symbolHeight / 2,\n                        symbolWidth,\n                        symbolHeight,\n                        lineStyle.stroke,\n                        true\n                    );\n\n                    // Calculate arrow position with offset\n                    var r = point.r + point.offset;\n                    var pos = [\n                        pt1[0] + r * Math.cos(opt.rotation),\n                        pt1[1] - r * Math.sin(opt.rotation)\n                    ];\n\n                    symbol.attr({\n                        rotation: point.rotate,\n                        position: pos,\n                        silent: true,\n                        z2: 11\n                    });\n                    this.group.add(symbol);\n                }\n            }, this);\n        }\n    },\n\n    /**\n     * @private\n     */\n    axisTickLabel: function () {\n        var axisModel = this.axisModel;\n        var opt = this.opt;\n\n        var tickEls = buildAxisTick(this, axisModel, opt);\n        var labelEls = buildAxisLabel(this, axisModel, opt);\n\n        fixMinMaxLabelShow(axisModel, labelEls, tickEls);\n    },\n\n    /**\n     * @private\n     */\n    axisName: function () {\n        var opt = this.opt;\n        var axisModel = this.axisModel;\n        var name = retrieve(opt.axisName, axisModel.get('name'));\n\n        if (!name) {\n            return;\n        }\n\n        var nameLocation = axisModel.get('nameLocation');\n        var nameDirection = opt.nameDirection;\n        var textStyleModel = axisModel.getModel('nameTextStyle');\n        var gap = axisModel.get('nameGap') || 0;\n\n        var extent = this.axisModel.axis.getExtent();\n        var gapSignal = extent[0] > extent[1] ? -1 : 1;\n        var pos = [\n            nameLocation === 'start'\n                ? extent[0] - gapSignal * gap\n                : nameLocation === 'end'\n                ? extent[1] + gapSignal * gap\n                : (extent[0] + extent[1]) / 2, // 'middle'\n            // Reuse labelOffset.\n            isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * gap : 0\n        ];\n\n        var labelLayout;\n\n        var nameRotation = axisModel.get('nameRotate');\n        if (nameRotation != null) {\n            nameRotation = nameRotation * PI$2 / 180; // To radian.\n        }\n\n        var axisNameAvailableWidth;\n\n        if (isNameLocationCenter(nameLocation)) {\n            labelLayout = innerTextLayout(\n                opt.rotation,\n                nameRotation != null ? nameRotation : opt.rotation, // Adapt to axis.\n                nameDirection\n            );\n        }\n        else {\n            labelLayout = endTextLayout(\n                opt, nameLocation, nameRotation || 0, extent\n            );\n\n            axisNameAvailableWidth = opt.axisNameAvailableWidth;\n            if (axisNameAvailableWidth != null) {\n                axisNameAvailableWidth = Math.abs(\n                    axisNameAvailableWidth / Math.sin(labelLayout.rotation)\n                );\n                !isFinite(axisNameAvailableWidth) && (axisNameAvailableWidth = null);\n            }\n        }\n\n        var textFont = textStyleModel.getFont();\n\n        var truncateOpt = axisModel.get('nameTruncate', true) || {};\n        var ellipsis = truncateOpt.ellipsis;\n        var maxWidth = retrieve(\n            opt.nameTruncateMaxWidth, truncateOpt.maxWidth, axisNameAvailableWidth\n        );\n        // FIXME\n        // truncate rich text? (consider performance)\n        var truncatedText = (ellipsis != null && maxWidth != null)\n            ? truncateText$1(\n                name, maxWidth, textFont, ellipsis,\n                {minChar: 2, placeholder: truncateOpt.placeholder}\n            )\n            : name;\n\n        var tooltipOpt = axisModel.get('tooltip', true);\n\n        var mainType = axisModel.mainType;\n        var formatterParams = {\n            componentType: mainType,\n            name: name,\n            $vars: ['name']\n        };\n        formatterParams[mainType + 'Index'] = axisModel.componentIndex;\n\n        var textEl = new Text({\n            // Id for animation\n            anid: 'name',\n\n            __fullText: name,\n            __truncatedText: truncatedText,\n\n            position: pos,\n            rotation: labelLayout.rotation,\n            silent: isSilent(axisModel),\n            z2: 1,\n            tooltip: (tooltipOpt && tooltipOpt.show)\n                ? extend({\n                    content: name,\n                    formatter: function () {\n                        return name;\n                    },\n                    formatterParams: formatterParams\n                }, tooltipOpt)\n                : null\n        });\n\n        setTextStyle(textEl.style, textStyleModel, {\n            text: truncatedText,\n            textFont: textFont,\n            textFill: textStyleModel.getTextColor()\n                || axisModel.get('axisLine.lineStyle.color'),\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.textVerticalAlign\n        });\n\n        if (axisModel.get('triggerEvent')) {\n            textEl.eventData = makeAxisEventDataBase(axisModel);\n            textEl.eventData.targetType = 'axisName';\n            textEl.eventData.name = name;\n        }\n\n        // FIXME\n        this._dumbGroup.add(textEl);\n        textEl.updateTransform();\n\n        this.group.add(textEl);\n\n        textEl.decomposeTransform();\n    }\n\n};\n\n/**\n * @public\n * @static\n * @param {Object} opt\n * @param {number} axisRotation in radian\n * @param {number} textRotation in radian\n * @param {number} direction\n * @return {Object} {\n *  rotation, // according to axis\n *  textAlign,\n *  textVerticalAlign\n * }\n */\nvar innerTextLayout = AxisBuilder.innerTextLayout = function (axisRotation, textRotation, direction) {\n    var rotationDiff = remRadian(textRotation - axisRotation);\n    var textAlign;\n    var textVerticalAlign;\n\n    if (isRadianAroundZero(rotationDiff)) { // Label is parallel with axis line.\n        textVerticalAlign = direction > 0 ? 'top' : 'bottom';\n        textAlign = 'center';\n    }\n    else if (isRadianAroundZero(rotationDiff - PI$2)) { // Label is inverse parallel with axis line.\n        textVerticalAlign = direction > 0 ? 'bottom' : 'top';\n        textAlign = 'center';\n    }\n    else {\n        textVerticalAlign = 'middle';\n\n        if (rotationDiff > 0 && rotationDiff < PI$2) {\n            textAlign = direction > 0 ? 'right' : 'left';\n        }\n        else {\n            textAlign = direction > 0 ? 'left' : 'right';\n        }\n    }\n\n    return {\n        rotation: rotationDiff,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n};\n\nfunction endTextLayout(opt, textPosition, textRotate, extent) {\n    var rotationDiff = remRadian(textRotate - opt.rotation);\n    var textAlign;\n    var textVerticalAlign;\n    var inverse = extent[0] > extent[1];\n    var onLeft = (textPosition === 'start' && !inverse)\n        || (textPosition !== 'start' && inverse);\n\n    if (isRadianAroundZero(rotationDiff - PI$2 / 2)) {\n        textVerticalAlign = onLeft ? 'bottom' : 'top';\n        textAlign = 'center';\n    }\n    else if (isRadianAroundZero(rotationDiff - PI$2 * 1.5)) {\n        textVerticalAlign = onLeft ? 'top' : 'bottom';\n        textAlign = 'center';\n    }\n    else {\n        textVerticalAlign = 'middle';\n        if (rotationDiff < PI$2 * 1.5 && rotationDiff > PI$2 / 2) {\n            textAlign = onLeft ? 'left' : 'right';\n        }\n        else {\n            textAlign = onLeft ? 'right' : 'left';\n        }\n    }\n\n    return {\n        rotation: rotationDiff,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\nfunction isSilent(axisModel) {\n    var tooltipOpt = axisModel.get('tooltip');\n    return axisModel.get('silent')\n        // Consider mouse cursor, add these restrictions.\n        || !(\n            axisModel.get('triggerEvent') || (tooltipOpt && tooltipOpt.show)\n        );\n}\n\nfunction fixMinMaxLabelShow(axisModel, labelEls, tickEls) {\n    if (shouldShowAllLabels(axisModel.axis)) {\n        return;\n    }\n\n    // If min or max are user set, we need to check\n    // If the tick on min(max) are overlap on their neighbour tick\n    // If they are overlapped, we need to hide the min(max) tick label\n    var showMinLabel = axisModel.get('axisLabel.showMinLabel');\n    var showMaxLabel = axisModel.get('axisLabel.showMaxLabel');\n\n    // FIXME\n    // Have not consider onBand yet, where tick els is more than label els.\n\n    labelEls = labelEls || [];\n    tickEls = tickEls || [];\n\n    var firstLabel = labelEls[0];\n    var nextLabel = labelEls[1];\n    var lastLabel = labelEls[labelEls.length - 1];\n    var prevLabel = labelEls[labelEls.length - 2];\n\n    var firstTick = tickEls[0];\n    var nextTick = tickEls[1];\n    var lastTick = tickEls[tickEls.length - 1];\n    var prevTick = tickEls[tickEls.length - 2];\n\n    if (showMinLabel === false) {\n        ignoreEl(firstLabel);\n        ignoreEl(firstTick);\n    }\n    else if (isTwoLabelOverlapped(firstLabel, nextLabel)) {\n        if (showMinLabel) {\n            ignoreEl(nextLabel);\n            ignoreEl(nextTick);\n        }\n        else {\n            ignoreEl(firstLabel);\n            ignoreEl(firstTick);\n        }\n    }\n\n    if (showMaxLabel === false) {\n        ignoreEl(lastLabel);\n        ignoreEl(lastTick);\n    }\n    else if (isTwoLabelOverlapped(prevLabel, lastLabel)) {\n        if (showMaxLabel) {\n            ignoreEl(prevLabel);\n            ignoreEl(prevTick);\n        }\n        else {\n            ignoreEl(lastLabel);\n            ignoreEl(lastTick);\n        }\n    }\n}\n\nfunction ignoreEl(el) {\n    el && (el.ignore = true);\n}\n\nfunction isTwoLabelOverlapped(current, next, labelLayout) {\n    // current and next has the same rotation.\n    var firstRect = current && current.getBoundingRect().clone();\n    var nextRect = next && next.getBoundingRect().clone();\n\n    if (!firstRect || !nextRect) {\n        return;\n    }\n\n    // When checking intersect of two rotated labels, we use mRotationBack\n    // to avoid that boundingRect is enlarge when using `boundingRect.applyTransform`.\n    var mRotationBack = identity([]);\n    rotate(mRotationBack, mRotationBack, -current.rotation);\n\n    firstRect.applyTransform(mul$1([], mRotationBack, current.getLocalTransform()));\n    nextRect.applyTransform(mul$1([], mRotationBack, next.getLocalTransform()));\n\n    return firstRect.intersect(nextRect);\n}\n\nfunction isNameLocationCenter(nameLocation) {\n    return nameLocation === 'middle' || nameLocation === 'center';\n}\n\nfunction buildAxisTick(axisBuilder, axisModel, opt) {\n    var axis = axisModel.axis;\n\n    if (!axisModel.get('axisTick.show') || axis.scale.isBlank()) {\n        return;\n    }\n\n    var tickModel = axisModel.getModel('axisTick');\n\n    var lineStyleModel = tickModel.getModel('lineStyle');\n    var tickLen = tickModel.get('length');\n\n    var ticksCoords = axis.getTicksCoords();\n\n    var pt1 = [];\n    var pt2 = [];\n    var matrix = axisBuilder._transform;\n\n    var tickEls = [];\n\n    for (var i = 0; i < ticksCoords.length; i++) {\n        var tickCoord = ticksCoords[i].coord;\n\n        pt1[0] = tickCoord;\n        pt1[1] = 0;\n        pt2[0] = tickCoord;\n        pt2[1] = opt.tickDirection * tickLen;\n\n        if (matrix) {\n            applyTransform(pt1, pt1, matrix);\n            applyTransform(pt2, pt2, matrix);\n        }\n        // Tick line, Not use group transform to have better line draw\n        var tickEl = new Line(subPixelOptimizeLine({\n            // Id for animation\n            anid: 'tick_' + ticksCoords[i].tickValue,\n\n            shape: {\n                x1: pt1[0],\n                y1: pt1[1],\n                x2: pt2[0],\n                y2: pt2[1]\n            },\n            style: defaults(\n                lineStyleModel.getLineStyle(),\n                {\n                    stroke: axisModel.get('axisLine.lineStyle.color')\n                }\n            ),\n            z2: 2,\n            silent: true\n        }));\n        axisBuilder.group.add(tickEl);\n        tickEls.push(tickEl);\n    }\n\n    return tickEls;\n}\n\nfunction buildAxisLabel(axisBuilder, axisModel, opt) {\n    var axis = axisModel.axis;\n    var show = retrieve(opt.axisLabelShow, axisModel.get('axisLabel.show'));\n\n    if (!show || axis.scale.isBlank()) {\n        return;\n    }\n\n    var labelModel = axisModel.getModel('axisLabel');\n    var labelMargin = labelModel.get('margin');\n    var labels = axis.getViewLabels();\n\n    // Special label rotate.\n    var labelRotation = (\n        retrieve(opt.labelRotate, labelModel.get('rotate')) || 0\n    ) * PI$2 / 180;\n\n    var labelLayout = innerTextLayout(opt.rotation, labelRotation, opt.labelDirection);\n    var rawCategoryData = axisModel.getCategories(true);\n\n    var labelEls = [];\n    var silent = isSilent(axisModel);\n    var triggerEvent = axisModel.get('triggerEvent');\n\n    each$1(labels, function (labelItem, index) {\n        var tickValue = labelItem.tickValue;\n        var formattedLabel = labelItem.formattedLabel;\n        var rawLabel = labelItem.rawLabel;\n\n        var itemLabelModel = labelModel;\n        if (rawCategoryData && rawCategoryData[tickValue] && rawCategoryData[tickValue].textStyle) {\n            itemLabelModel = new Model(\n                rawCategoryData[tickValue].textStyle, labelModel, axisModel.ecModel\n            );\n        }\n\n        var textColor = itemLabelModel.getTextColor()\n            || axisModel.get('axisLine.lineStyle.color');\n\n        var tickCoord = axis.dataToCoord(tickValue);\n        var pos = [\n            tickCoord,\n            opt.labelOffset + opt.labelDirection * labelMargin\n        ];\n\n        var textEl = new Text({\n            // Id for animation\n            anid: 'label_' + tickValue,\n            position: pos,\n            rotation: labelLayout.rotation,\n            silent: silent,\n            z2: 10\n        });\n\n        setTextStyle(textEl.style, itemLabelModel, {\n            text: formattedLabel,\n            textAlign: itemLabelModel.getShallow('align', true)\n                || labelLayout.textAlign,\n            textVerticalAlign: itemLabelModel.getShallow('verticalAlign', true)\n                || itemLabelModel.getShallow('baseline', true)\n                || labelLayout.textVerticalAlign,\n            textFill: typeof textColor === 'function'\n                ? textColor(\n                    // (1) In category axis with data zoom, tick is not the original\n                    // index of axis.data. So tick should not be exposed to user\n                    // in category axis.\n                    // (2) Compatible with previous version, which always use formatted label as\n                    // input. But in interval scale the formatted label is like '223,445', which\n                    // maked user repalce ','. So we modify it to return original val but remain\n                    // it as 'string' to avoid error in replacing.\n                    axis.type === 'category'\n                        ? rawLabel\n                        : axis.type === 'value'\n                        ? tickValue + ''\n                        : tickValue,\n                    index\n                )\n                : textColor\n        });\n\n        // Pack data for mouse event\n        if (triggerEvent) {\n            textEl.eventData = makeAxisEventDataBase(axisModel);\n            textEl.eventData.targetType = 'axisLabel';\n            textEl.eventData.value = rawLabel;\n        }\n\n        // FIXME\n        axisBuilder._dumbGroup.add(textEl);\n        textEl.updateTransform();\n\n        labelEls.push(textEl);\n        axisBuilder.group.add(textEl);\n\n        textEl.decomposeTransform();\n\n    });\n\n    return labelEls;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$6 = each$1;\nvar curry$1 = curry;\n\n// Build axisPointerModel, mergin tooltip.axisPointer model for each axis.\n// allAxesInfo should be updated when setOption performed.\nfunction collect(ecModel, api) {\n    var result = {\n        /**\n         * key: makeKey(axis.model)\n         * value: {\n         *      axis,\n         *      coordSys,\n         *      axisPointerModel,\n         *      triggerTooltip,\n         *      involveSeries,\n         *      snap,\n         *      seriesModels,\n         *      seriesDataCount\n         * }\n         */\n        axesInfo: {},\n        seriesInvolved: false,\n        /**\n         * key: makeKey(coordSys.model)\n         * value: Object: key makeKey(axis.model), value: axisInfo\n         */\n        coordSysAxesInfo: {},\n        coordSysMap: {}\n    };\n\n    collectAxesInfo(result, ecModel, api);\n\n    // Check seriesInvolved for performance, in case too many series in some chart.\n    result.seriesInvolved && collectSeriesInfo(result, ecModel);\n\n    return result;\n}\n\nfunction collectAxesInfo(result, ecModel, api) {\n    var globalTooltipModel = ecModel.getComponent('tooltip');\n    var globalAxisPointerModel = ecModel.getComponent('axisPointer');\n    // links can only be set on global.\n    var linksOption = globalAxisPointerModel.get('link', true) || [];\n    var linkGroups = [];\n\n    // Collect axes info.\n    each$6(api.getCoordinateSystems(), function (coordSys) {\n        // Some coordinate system do not support axes, like geo.\n        if (!coordSys.axisPointerEnabled) {\n            return;\n        }\n\n        var coordSysKey = makeKey(coordSys.model);\n        var axesInfoInCoordSys = result.coordSysAxesInfo[coordSysKey] = {};\n        result.coordSysMap[coordSysKey] = coordSys;\n\n        // Set tooltip (like 'cross') is a convienent way to show axisPointer\n        // for user. So we enable seting tooltip on coordSys model.\n        var coordSysModel = coordSys.model;\n        var baseTooltipModel = coordSysModel.getModel('tooltip', globalTooltipModel);\n\n        each$6(coordSys.getAxes(), curry$1(saveTooltipAxisInfo, false, null));\n\n        // If axis tooltip used, choose tooltip axis for each coordSys.\n        // Notice this case: coordSys is `grid` but not `cartesian2D` here.\n        if (coordSys.getTooltipAxes\n            && globalTooltipModel\n            // If tooltip.showContent is set as false, tooltip will not\n            // show but axisPointer will show as normal.\n            && baseTooltipModel.get('show')\n        ) {\n            // Compatible with previous logic. But series.tooltip.trigger: 'axis'\n            // or series.data[n].tooltip.trigger: 'axis' are not support any more.\n            var triggerAxis = baseTooltipModel.get('trigger') === 'axis';\n            var cross = baseTooltipModel.get('axisPointer.type') === 'cross';\n            var tooltipAxes = coordSys.getTooltipAxes(baseTooltipModel.get('axisPointer.axis'));\n            if (triggerAxis || cross) {\n                each$6(tooltipAxes.baseAxes, curry$1(\n                    saveTooltipAxisInfo, cross ? 'cross' : true, triggerAxis\n                ));\n            }\n            if (cross) {\n                each$6(tooltipAxes.otherAxes, curry$1(saveTooltipAxisInfo, 'cross', false));\n            }\n        }\n\n        // fromTooltip: true | false | 'cross'\n        // triggerTooltip: true | false | null\n        function saveTooltipAxisInfo(fromTooltip, triggerTooltip, axis) {\n            var axisPointerModel = axis.model.getModel('axisPointer', globalAxisPointerModel);\n\n            var axisPointerShow = axisPointerModel.get('show');\n            if (!axisPointerShow || (\n                axisPointerShow === 'auto'\n                && !fromTooltip\n                && !isHandleTrigger(axisPointerModel)\n            )) {\n                return;\n            }\n\n            if (triggerTooltip == null) {\n                triggerTooltip = axisPointerModel.get('triggerTooltip');\n            }\n\n            axisPointerModel = fromTooltip\n                ? makeAxisPointerModel(\n                    axis, baseTooltipModel, globalAxisPointerModel, ecModel,\n                    fromTooltip, triggerTooltip\n                )\n                : axisPointerModel;\n\n            var snap = axisPointerModel.get('snap');\n            var key = makeKey(axis.model);\n            var involveSeries = triggerTooltip || snap || axis.type === 'category';\n\n            // If result.axesInfo[key] exist, override it (tooltip has higher priority).\n            var axisInfo = result.axesInfo[key] = {\n                key: key,\n                axis: axis,\n                coordSys: coordSys,\n                axisPointerModel: axisPointerModel,\n                triggerTooltip: triggerTooltip,\n                involveSeries: involveSeries,\n                snap: snap,\n                useHandle: isHandleTrigger(axisPointerModel),\n                seriesModels: []\n            };\n            axesInfoInCoordSys[key] = axisInfo;\n            result.seriesInvolved |= involveSeries;\n\n            var groupIndex = getLinkGroupIndex(linksOption, axis);\n            if (groupIndex != null) {\n                var linkGroup = linkGroups[groupIndex] || (linkGroups[groupIndex] = {axesInfo: {}});\n                linkGroup.axesInfo[key] = axisInfo;\n                linkGroup.mapper = linksOption[groupIndex].mapper;\n                axisInfo.linkGroup = linkGroup;\n            }\n        }\n    });\n}\n\nfunction makeAxisPointerModel(\n    axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip\n) {\n    var tooltipAxisPointerModel = baseTooltipModel.getModel('axisPointer');\n    var volatileOption = {};\n\n    each$6(\n        [\n            'type', 'snap', 'lineStyle', 'shadowStyle', 'label',\n            'animation', 'animationDurationUpdate', 'animationEasingUpdate', 'z'\n        ],\n        function (field) {\n            volatileOption[field] = clone(tooltipAxisPointerModel.get(field));\n        }\n    );\n\n    // category axis do not auto snap, otherwise some tick that do not\n    // has value can not be hovered. value/time/log axis default snap if\n    // triggered from tooltip and trigger tooltip.\n    volatileOption.snap = axis.type !== 'category' && !!triggerTooltip;\n\n    // Compatibel with previous behavior, tooltip axis do not show label by default.\n    // Only these properties can be overrided from tooltip to axisPointer.\n    if (tooltipAxisPointerModel.get('type') === 'cross') {\n        volatileOption.type = 'line';\n    }\n    var labelOption = volatileOption.label || (volatileOption.label = {});\n    // Follow the convention, do not show label when triggered by tooltip by default.\n    labelOption.show == null && (labelOption.show = false);\n\n    if (fromTooltip === 'cross') {\n        // When 'cross', both axes show labels.\n        var tooltipAxisPointerLabelShow = tooltipAxisPointerModel.get('label.show');\n        labelOption.show = tooltipAxisPointerLabelShow != null ? tooltipAxisPointerLabelShow : true;\n        // If triggerTooltip, this is a base axis, which should better not use cross style\n        // (cross style is dashed by default)\n        if (!triggerTooltip) {\n            var crossStyle = volatileOption.lineStyle = tooltipAxisPointerModel.get('crossStyle');\n            crossStyle && defaults(labelOption, crossStyle.textStyle);\n        }\n    }\n\n    return axis.model.getModel(\n        'axisPointer',\n        new Model(volatileOption, globalAxisPointerModel, ecModel)\n    );\n}\n\nfunction collectSeriesInfo(result, ecModel) {\n    // Prepare data for axis trigger\n    ecModel.eachSeries(function (seriesModel) {\n\n        // Notice this case: this coordSys is `cartesian2D` but not `grid`.\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesTooltipTrigger = seriesModel.get('tooltip.trigger', true);\n        var seriesTooltipShow = seriesModel.get('tooltip.show', true);\n        if (!coordSys\n            || seriesTooltipTrigger === 'none'\n            || seriesTooltipTrigger === false\n            || seriesTooltipTrigger === 'item'\n            || seriesTooltipShow === false\n            || seriesModel.get('axisPointer.show', true) === false\n        ) {\n            return;\n        }\n\n        each$6(result.coordSysAxesInfo[makeKey(coordSys.model)], function (axisInfo) {\n            var axis = axisInfo.axis;\n            if (coordSys.getAxis(axis.dim) === axis) {\n                axisInfo.seriesModels.push(seriesModel);\n                axisInfo.seriesDataCount == null && (axisInfo.seriesDataCount = 0);\n                axisInfo.seriesDataCount += seriesModel.getData().count();\n            }\n        });\n\n    }, this);\n}\n\n/**\n * For example:\n * {\n *     axisPointer: {\n *         links: [{\n *             xAxisIndex: [2, 4],\n *             yAxisIndex: 'all'\n *         }, {\n *             xAxisId: ['a5', 'a7'],\n *             xAxisName: 'xxx'\n *         }]\n *     }\n * }\n */\nfunction getLinkGroupIndex(linksOption, axis) {\n    var axisModel = axis.model;\n    var dim = axis.dim;\n    for (var i = 0; i < linksOption.length; i++) {\n        var linkOption = linksOption[i] || {};\n        if (checkPropInLink(linkOption[dim + 'AxisId'], axisModel.id)\n            || checkPropInLink(linkOption[dim + 'AxisIndex'], axisModel.componentIndex)\n            || checkPropInLink(linkOption[dim + 'AxisName'], axisModel.name)\n        ) {\n            return i;\n        }\n    }\n}\n\nfunction checkPropInLink(linkPropValue, axisPropValue) {\n    return linkPropValue === 'all'\n        || (isArray(linkPropValue) && indexOf(linkPropValue, axisPropValue) >= 0)\n        || linkPropValue === axisPropValue;\n}\n\nfunction fixValue(axisModel) {\n    var axisInfo = getAxisInfo(axisModel);\n    if (!axisInfo) {\n        return;\n    }\n\n    var axisPointerModel = axisInfo.axisPointerModel;\n    var scale = axisInfo.axis.scale;\n    var option = axisPointerModel.option;\n    var status = axisPointerModel.get('status');\n    var value = axisPointerModel.get('value');\n\n    // Parse init value for category and time axis.\n    if (value != null) {\n        value = scale.parse(value);\n    }\n\n    var useHandle = isHandleTrigger(axisPointerModel);\n    // If `handle` used, `axisPointer` will always be displayed, so value\n    // and status should be initialized.\n    if (status == null) {\n        option.status = useHandle ? 'show' : 'hide';\n    }\n\n    var extent = scale.getExtent().slice();\n    extent[0] > extent[1] && extent.reverse();\n\n    if (// Pick a value on axis when initializing.\n        value == null\n        // If both `handle` and `dataZoom` are used, value may be out of axis extent,\n        // where we should re-pick a value to keep `handle` displaying normally.\n        || value > extent[1]\n    ) {\n        // Make handle displayed on the end of the axis when init, which looks better.\n        value = extent[1];\n    }\n    if (value < extent[0]) {\n        value = extent[0];\n    }\n\n    option.value = value;\n\n    if (useHandle) {\n        option.status = axisInfo.axis.scale.isBlank() ? 'hide' : 'show';\n    }\n}\n\nfunction getAxisInfo(axisModel) {\n    var coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') || {}).coordSysAxesInfo;\n    return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)];\n}\n\nfunction getAxisPointerModel(axisModel) {\n    var axisInfo = getAxisInfo(axisModel);\n    return axisInfo && axisInfo.axisPointerModel;\n}\n\nfunction isHandleTrigger(axisPointerModel) {\n    return !!axisPointerModel.get('handle.show');\n}\n\n/**\n * @param {module:echarts/model/Model} model\n * @return {string} unique key\n */\nfunction makeKey(model) {\n    return model.type + '||' + model.id;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Base class of AxisView.\n */\nvar AxisView = extendComponentView({\n\n    type: 'axis',\n\n    /**\n     * @private\n     */\n    _axisPointer: null,\n\n    /**\n     * @protected\n     * @type {string}\n     */\n    axisPointerClass: null,\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n        // FIXME\n        // This process should proformed after coordinate systems updated\n        // (axis scale updated), and should be performed each time update.\n        // So put it here temporarily, although it is not appropriate to\n        // put a model-writing procedure in `view`.\n        this.axisPointerClass && fixValue(axisModel);\n\n        AxisView.superApply(this, 'render', arguments);\n\n        updateAxisPointer(this, axisModel, ecModel, api, payload, true);\n    },\n\n    /**\n     * Action handler.\n     * @public\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/model/Global} ecModel\n     * @param {module:echarts/ExtensionAPI} api\n     * @param {Object} payload\n     */\n    updateAxisPointer: function (axisModel, ecModel, api, payload, force) {\n        updateAxisPointer(this, axisModel, ecModel, api, payload, false);\n    },\n\n    /**\n     * @override\n     */\n    remove: function (ecModel, api) {\n        var axisPointer = this._axisPointer;\n        axisPointer && axisPointer.remove(api);\n        AxisView.superApply(this, 'remove', arguments);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function (ecModel, api) {\n        disposeAxisPointer(this, api);\n        AxisView.superApply(this, 'dispose', arguments);\n    }\n\n});\n\nfunction updateAxisPointer(axisView, axisModel, ecModel, api, payload, forceRender) {\n    var Clazz = AxisView.getAxisPointerClass(axisView.axisPointerClass);\n    if (!Clazz) {\n        return;\n    }\n    var axisPointerModel = getAxisPointerModel(axisModel);\n    axisPointerModel\n        ? (axisView._axisPointer || (axisView._axisPointer = new Clazz()))\n            .render(axisModel, axisPointerModel, api, forceRender)\n        : disposeAxisPointer(axisView, api);\n}\n\nfunction disposeAxisPointer(axisView, ecModel, api) {\n    var axisPointer = axisView._axisPointer;\n    axisPointer && axisPointer.dispose(ecModel, api);\n    axisView._axisPointer = null;\n}\n\nvar axisPointerClazz = [];\n\nAxisView.registerAxisPointerClass = function (type, clazz) {\n    if (__DEV__) {\n        if (axisPointerClazz[type]) {\n            throw new Error('axisPointer ' + type + ' exists');\n        }\n    }\n    axisPointerClazz[type] = clazz;\n};\n\nAxisView.getAxisPointerClass = function (type) {\n    return type && axisPointerClazz[type];\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Can only be called after coordinate system creation stage.\n * (Can be called before coordinate system update stage).\n *\n * @param {Object} opt {labelInside}\n * @return {Object} {\n *  position, rotation, labelDirection, labelOffset,\n *  tickDirection, labelRotate, z2\n * }\n */\nfunction layout$1(gridModel, axisModel, opt) {\n    opt = opt || {};\n    var grid = gridModel.coordinateSystem;\n    var axis = axisModel.axis;\n    var layout = {};\n    var otherAxisOnZeroOf = axis.getAxesOnZeroOf()[0];\n\n    var rawAxisPosition = axis.position;\n    var axisPosition = otherAxisOnZeroOf ? 'onZero' : rawAxisPosition;\n    var axisDim = axis.dim;\n\n    var rect = grid.getRect();\n    var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];\n    var idx = {left: 0, right: 1, top: 0, bottom: 1, onZero: 2};\n    var axisOffset = axisModel.get('offset') || 0;\n\n    var posBound = axisDim === 'x'\n        ? [rectBound[2] - axisOffset, rectBound[3] + axisOffset]\n        : [rectBound[0] - axisOffset, rectBound[1] + axisOffset];\n\n    if (otherAxisOnZeroOf) {\n        var onZeroCoord = otherAxisOnZeroOf.toGlobalCoord(otherAxisOnZeroOf.dataToCoord(0));\n        posBound[idx.onZero] = Math.max(Math.min(onZeroCoord, posBound[1]), posBound[0]);\n    }\n\n    // Axis position\n    layout.position = [\n        axisDim === 'y' ? posBound[idx[axisPosition]] : rectBound[0],\n        axisDim === 'x' ? posBound[idx[axisPosition]] : rectBound[3]\n    ];\n\n    // Axis rotation\n    layout.rotation = Math.PI / 2 * (axisDim === 'x' ? 0 : 1);\n\n    // Tick and label direction, x y is axisDim\n    var dirMap = {top: -1, bottom: 1, left: -1, right: 1};\n\n    layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition];\n    layout.labelOffset = otherAxisOnZeroOf ? posBound[idx[rawAxisPosition]] - posBound[idx.onZero] : 0;\n\n    if (axisModel.get('axisTick.inside')) {\n        layout.tickDirection = -layout.tickDirection;\n    }\n    if (retrieve(opt.labelInside, axisModel.get('axisLabel.inside'))) {\n        layout.labelDirection = -layout.labelDirection;\n    }\n\n    // Special label rotation\n    var labelRotate = axisModel.get('axisLabel.rotate');\n    layout.labelRotate = axisPosition === 'top' ? -labelRotate : labelRotate;\n\n    // Over splitLine and splitArea\n    layout.z2 = 1;\n\n    return layout;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar axisBuilderAttrs = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\nvar selfBuilderAttrs = [\n    'splitArea', 'splitLine'\n];\n\n// function getAlignWithLabel(model, axisModel) {\n//     var alignWithLabel = model.get('alignWithLabel');\n//     if (alignWithLabel === 'auto') {\n//         alignWithLabel = axisModel.get('axisTick.alignWithLabel');\n//     }\n//     return alignWithLabel;\n// }\n\nvar CartesianAxisView = AxisView.extend({\n\n    type: 'cartesianAxis',\n\n    axisPointerClass: 'CartesianAxisPointer',\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n\n        this.group.removeAll();\n\n        var oldAxisGroup = this._axisGroup;\n        this._axisGroup = new Group();\n\n        this.group.add(this._axisGroup);\n\n        if (!axisModel.get('show')) {\n            return;\n        }\n\n        var gridModel = axisModel.getCoordSysModel();\n\n        var layout = layout$1(gridModel, axisModel);\n\n        var axisBuilder = new AxisBuilder(axisModel, layout);\n\n        each$1(axisBuilderAttrs, axisBuilder.add, axisBuilder);\n\n        this._axisGroup.add(axisBuilder.getGroup());\n\n        each$1(selfBuilderAttrs, function (name) {\n            if (axisModel.get(name + '.show')) {\n                this['_' + name](axisModel, gridModel);\n            }\n        }, this);\n\n        groupTransition(oldAxisGroup, this._axisGroup, axisModel);\n\n        CartesianAxisView.superCall(this, 'render', axisModel, ecModel, api, payload);\n    },\n\n    remove: function () {\n        this._splitAreaColors = null;\n    },\n\n    /**\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/coord/cartesian/GridModel} gridModel\n     * @private\n     */\n    _splitLine: function (axisModel, gridModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitLineModel = axisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineColors = lineStyleModel.get('color');\n\n        lineColors = isArray(lineColors) ? lineColors : [lineColors];\n\n        var gridRect = gridModel.coordinateSystem.getRect();\n        var isHorizontal = axis.isHorizontal();\n\n        var lineCount = 0;\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitLineModel\n        });\n\n        var p1 = [];\n        var p2 = [];\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        var lineStyle = lineStyleModel.getLineStyle();\n        for (var i = 0; i < ticksCoords.length; i++) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n\n            if (isHorizontal) {\n                p1[0] = tickCoord;\n                p1[1] = gridRect.y;\n                p2[0] = tickCoord;\n                p2[1] = gridRect.y + gridRect.height;\n            }\n            else {\n                p1[0] = gridRect.x;\n                p1[1] = tickCoord;\n                p2[0] = gridRect.x + gridRect.width;\n                p2[1] = tickCoord;\n            }\n\n            var colorIndex = (lineCount++) % lineColors.length;\n            var tickValue = ticksCoords[i].tickValue;\n            this._axisGroup.add(new Line(subPixelOptimizeLine({\n                anid: tickValue != null ? 'line_' + ticksCoords[i].tickValue : null,\n                shape: {\n                    x1: p1[0],\n                    y1: p1[1],\n                    x2: p2[0],\n                    y2: p2[1]\n                },\n                style: defaults({\n                    stroke: lineColors[colorIndex]\n                }, lineStyle),\n                silent: true\n            })));\n        }\n    },\n\n    /**\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/coord/cartesian/GridModel} gridModel\n     * @private\n     */\n    _splitArea: function (axisModel, gridModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitAreaModel = axisModel.getModel('splitArea');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n        var areaColors = areaStyleModel.get('color');\n\n        var gridRect = gridModel.coordinateSystem.getRect();\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitAreaModel,\n            clamp: true\n        });\n\n        if (!ticksCoords.length) {\n            return;\n        }\n\n        // For Making appropriate splitArea animation, the color and anid\n        // should be corresponding to previous one if possible.\n        var areaColorsLen = areaColors.length;\n        var lastSplitAreaColors = this._splitAreaColors;\n        var newSplitAreaColors = createHashMap();\n        var colorIndex = 0;\n        if (lastSplitAreaColors) {\n            for (var i = 0; i < ticksCoords.length; i++) {\n                var cIndex = lastSplitAreaColors.get(ticksCoords[i].tickValue);\n                if (cIndex != null) {\n                    colorIndex = (cIndex + (areaColorsLen - 1) * i) % areaColorsLen;\n                    break;\n                }\n            }\n        }\n\n        var prev = axis.toGlobalCoord(ticksCoords[0].coord);\n\n        var areaStyle = areaStyleModel.getAreaStyle();\n        areaColors = isArray(areaColors) ? areaColors : [areaColors];\n\n        for (var i = 1; i < ticksCoords.length; i++) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n\n            var x;\n            var y;\n            var width;\n            var height;\n            if (axis.isHorizontal()) {\n                x = prev;\n                y = gridRect.y;\n                width = tickCoord - x;\n                height = gridRect.height;\n                prev = x + width;\n            }\n            else {\n                x = gridRect.x;\n                y = prev;\n                width = gridRect.width;\n                height = tickCoord - y;\n                prev = y + height;\n            }\n\n            var tickValue = ticksCoords[i - 1].tickValue;\n            tickValue != null && newSplitAreaColors.set(tickValue, colorIndex);\n\n            this._axisGroup.add(new Rect({\n                anid: tickValue != null ? 'area_' + tickValue : null,\n                shape: {\n                    x: x,\n                    y: y,\n                    width: width,\n                    height: height\n                },\n                style: defaults({\n                    fill: areaColors[colorIndex]\n                }, areaStyle),\n                silent: true\n            }));\n\n            colorIndex = (colorIndex + 1) % areaColorsLen;\n        }\n\n        this._splitAreaColors = newSplitAreaColors;\n    }\n});\n\nCartesianAxisView.extend({\n    type: 'xAxis'\n});\nCartesianAxisView.extend({\n    type: 'yAxis'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Grid view\nextendComponentView({\n\n    type: 'grid',\n\n    render: function (gridModel, ecModel) {\n        this.group.removeAll();\n        if (gridModel.get('show')) {\n            this.group.add(new Rect({\n                shape: gridModel.coordinateSystem.getRect(),\n                style: defaults({\n                    fill: gridModel.get('backgroundColor')\n                }, gridModel.getItemStyle()),\n                silent: true,\n                z2: -1\n            }));\n        }\n    }\n\n});\n\nregisterPreprocessor(function (option) {\n    // Only create grid when need\n    if (option.xAxis && option.yAxis && !option.grid) {\n        option.grid = {};\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterVisual(visualSymbol('line', 'circle', 'line'));\nregisterLayout(pointsLayout('line'));\n\n// Down sample after filter\nregisterProcessor(\n    PRIORITY.PROCESSOR.STATISTIC,\n    dataSample('line')\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BaseBarSeries = SeriesModel.extend({\n\n    type: 'series.__base_bar__',\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    getMarkerPosition: function (value) {\n        var coordSys = this.coordinateSystem;\n        if (coordSys) {\n            // PENDING if clamp ?\n            var pt = coordSys.dataToPoint(coordSys.clampData(value));\n            var data = this.getData();\n            var offset = data.getLayout('offset');\n            var size = data.getLayout('size');\n            var offsetIndex = coordSys.getBaseAxis().isHorizontal() ? 0 : 1;\n            pt[offsetIndex] += offset + size / 2;\n            return pt;\n        }\n        return [NaN, NaN];\n    },\n\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n        // stack: null\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // 最小高度改为0\n        barMinHeight: 0,\n        // 最小角度为0，仅对极坐标系下的柱状图有效\n        barMinAngle: 0,\n        // cursor: null,\n\n        large: false,\n        largeThreshold: 400,\n        progressive: 3e3,\n        progressiveChunkMode: 'mod',\n\n        // barMaxWidth: null,\n        // 默认自适应\n        // barWidth: null,\n        // 柱间距离，默认为柱形宽度的30%，可设固定值\n        // barGap: '30%',\n        // 类目间柱形距离，默认为类目间距的20%，可设固定值\n        // barCategoryGap: '20%',\n        // label: {\n        //      show: false\n        // },\n        itemStyle: {},\n        emphasis: {}\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nBaseBarSeries.extend({\n\n    type: 'series.bar',\n\n    dependencies: ['grid', 'polar'],\n\n    brushSelector: 'rect',\n\n    /**\n     * @override\n     */\n    getProgressive: function () {\n        // Do not support progressive in normal mode.\n        return this.get('large')\n            ? this.get('progressive')\n            : false;\n    },\n\n    /**\n     * @override\n     */\n    getProgressiveThreshold: function () {\n        // Do not support progressive in normal mode.\n        var progressiveThreshold = this.get('progressiveThreshold');\n        var largeThreshold = this.get('largeThreshold');\n        if (largeThreshold > progressiveThreshold) {\n            progressiveThreshold = largeThreshold;\n        }\n        return progressiveThreshold;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction setLabel(\n    normalStyle, hoverStyle, itemModel, color, seriesModel, dataIndex, labelPositionOutside\n) {\n    var labelModel = itemModel.getModel('label');\n    var hoverLabelModel = itemModel.getModel('emphasis.label');\n\n    setLabelStyle(\n        normalStyle, hoverStyle, labelModel, hoverLabelModel,\n        {\n            labelFetcher: seriesModel,\n            labelDataIndex: dataIndex,\n            defaultText: getDefaultLabel(seriesModel.getData(), dataIndex),\n            isRectText: true,\n            autoColor: color\n        }\n    );\n\n    fixPosition(normalStyle);\n    fixPosition(hoverStyle);\n}\n\nfunction fixPosition(style, labelPositionOutside) {\n    if (style.textPosition === 'outside') {\n        style.textPosition = labelPositionOutside;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getBarItemStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['stroke', 'borderColor'],\n        ['lineWidth', 'borderWidth'],\n        // Compatitable with 2\n        ['stroke', 'barBorderColor'],\n        ['lineWidth', 'barBorderWidth'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor']\n    ]\n);\n\nvar barItemStyle = {\n    getBarItemStyle: function (excludes) {\n        var style = getBarItemStyle(this, excludes);\n        if (this.getBorderLineDash) {\n            var lineDash = this.getBorderLineDash();\n            lineDash && (style.lineDash = lineDash);\n        }\n        return style;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'barBorderWidth'];\n\n// FIXME\n// Just for compatible with ec2.\nextend(Model.prototype, barItemStyle);\n\nextendChartView({\n\n    type: 'bar',\n\n    render: function (seriesModel, ecModel, api) {\n        this._updateDrawMode(seriesModel);\n\n        var coordinateSystemType = seriesModel.get('coordinateSystem');\n\n        if (coordinateSystemType === 'cartesian2d'\n            || coordinateSystemType === 'polar'\n        ) {\n            this._isLargeDraw\n                ? this._renderLarge(seriesModel, ecModel, api)\n                : this._renderNormal(seriesModel, ecModel, api);\n        }\n        else if (__DEV__) {\n            console.warn('Only cartesian2d and polar supported for bar.');\n        }\n\n        return this.group;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this._clear();\n        this._updateDrawMode(seriesModel);\n    },\n\n    incrementalRender: function (params, seriesModel, ecModel, api) {\n        // Do not support progressive in normal mode.\n        this._incrementalRenderLarge(params, seriesModel);\n    },\n\n    _updateDrawMode: function (seriesModel) {\n        var isLargeDraw = seriesModel.pipelineContext.large;\n        if (this._isLargeDraw == null || isLargeDraw ^ this._isLargeDraw) {\n            this._isLargeDraw = isLargeDraw;\n            this._clear();\n        }\n    },\n\n    _renderNormal: function (seriesModel, ecModel, api) {\n        var group = this.group;\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        var coord = seriesModel.coordinateSystem;\n        var baseAxis = coord.getBaseAxis();\n        var isHorizontalOrRadial;\n\n        if (coord.type === 'cartesian2d') {\n            isHorizontalOrRadial = baseAxis.isHorizontal();\n        }\n        else if (coord.type === 'polar') {\n            isHorizontalOrRadial = baseAxis.dim === 'angle';\n        }\n\n        var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null;\n\n        data.diff(oldData)\n            .add(function (dataIndex) {\n                if (!data.hasValue(dataIndex)) {\n                    return;\n                }\n\n                var itemModel = data.getItemModel(dataIndex);\n                var layout = getLayout[coord.type](data, dataIndex, itemModel);\n                var el = elementCreator[coord.type](\n                    data, dataIndex, itemModel, layout, isHorizontalOrRadial, animationModel\n                );\n                data.setItemGraphicEl(dataIndex, el);\n                group.add(el);\n\n                updateStyle(\n                    el, data, dataIndex, itemModel, layout,\n                    seriesModel, isHorizontalOrRadial, coord.type === 'polar'\n                );\n            })\n            .update(function (newIndex, oldIndex) {\n                var el = oldData.getItemGraphicEl(oldIndex);\n\n                if (!data.hasValue(newIndex)) {\n                    group.remove(el);\n                    return;\n                }\n\n                var itemModel = data.getItemModel(newIndex);\n                var layout = getLayout[coord.type](data, newIndex, itemModel);\n\n                if (el) {\n                    updateProps(el, {shape: layout}, animationModel, newIndex);\n                }\n                else {\n                    el = elementCreator[coord.type](\n                        data, newIndex, itemModel, layout, isHorizontalOrRadial, animationModel, true\n                    );\n                }\n\n                data.setItemGraphicEl(newIndex, el);\n                // Add back\n                group.add(el);\n\n                updateStyle(\n                    el, data, newIndex, itemModel, layout,\n                    seriesModel, isHorizontalOrRadial, coord.type === 'polar'\n                );\n            })\n            .remove(function (dataIndex) {\n                var el = oldData.getItemGraphicEl(dataIndex);\n                if (coord.type === 'cartesian2d') {\n                    el && removeRect(dataIndex, animationModel, el);\n                }\n                else {\n                    el && removeSector(dataIndex, animationModel, el);\n                }\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    _renderLarge: function (seriesModel, ecModel, api) {\n        this._clear();\n        createLarge(seriesModel, this.group);\n    },\n\n    _incrementalRenderLarge: function (params, seriesModel) {\n        createLarge(seriesModel, this.group, true);\n    },\n\n    dispose: noop,\n\n    remove: function (ecModel) {\n        this._clear(ecModel);\n    },\n\n    _clear: function (ecModel) {\n        var group = this.group;\n        var data = this._data;\n        if (ecModel && ecModel.get('animation') && data && !this._isLargeDraw) {\n            data.eachItemGraphicEl(function (el) {\n                if (el.type === 'sector') {\n                    removeSector(el.dataIndex, ecModel, el);\n                }\n                else {\n                    removeRect(el.dataIndex, ecModel, el);\n                }\n            });\n        }\n        else {\n            group.removeAll();\n        }\n        this._data = null;\n    }\n\n});\n\nvar elementCreator = {\n\n    cartesian2d: function (\n        data, dataIndex, itemModel, layout, isHorizontal,\n        animationModel, isUpdate\n    ) {\n        var rect = new Rect({shape: extend({}, layout)});\n\n        // Animation\n        if (animationModel) {\n            var rectShape = rect.shape;\n            var animateProperty = isHorizontal ? 'height' : 'width';\n            var animateTarget = {};\n            rectShape[animateProperty] = 0;\n            animateTarget[animateProperty] = layout[animateProperty];\n            graphic[isUpdate ? 'updateProps' : 'initProps'](rect, {\n                shape: animateTarget\n            }, animationModel, dataIndex);\n        }\n\n        return rect;\n    },\n\n    polar: function (\n        data, dataIndex, itemModel, layout, isRadial,\n        animationModel, isUpdate\n    ) {\n        // Keep the same logic with bar in catesion: use end value to control\n        // direction. Notice that if clockwise is true (by default), the sector\n        // will always draw clockwisely, no matter whether endAngle is greater\n        // or less than startAngle.\n        var clockwise = layout.startAngle < layout.endAngle;\n        var sector = new Sector({\n            shape: defaults({clockwise: clockwise}, layout)\n        });\n\n        // Animation\n        if (animationModel) {\n            var sectorShape = sector.shape;\n            var animateProperty = isRadial ? 'r' : 'endAngle';\n            var animateTarget = {};\n            sectorShape[animateProperty] = isRadial ? 0 : layout.startAngle;\n            animateTarget[animateProperty] = layout[animateProperty];\n            graphic[isUpdate ? 'updateProps' : 'initProps'](sector, {\n                shape: animateTarget\n            }, animationModel, dataIndex);\n        }\n\n        return sector;\n    }\n};\n\nfunction removeRect(dataIndex, animationModel, el) {\n    // Not show text when animating\n    el.style.text = null;\n    updateProps(el, {\n        shape: {\n            width: 0\n        }\n    }, animationModel, dataIndex, function () {\n        el.parent && el.parent.remove(el);\n    });\n}\n\nfunction removeSector(dataIndex, animationModel, el) {\n    // Not show text when animating\n    el.style.text = null;\n    updateProps(el, {\n        shape: {\n            r: el.shape.r0\n        }\n    }, animationModel, dataIndex, function () {\n        el.parent && el.parent.remove(el);\n    });\n}\n\nvar getLayout = {\n    cartesian2d: function (data, dataIndex, itemModel) {\n        var layout = data.getItemLayout(dataIndex);\n        var fixedLineWidth = getLineWidth(itemModel, layout);\n\n        // fix layout with lineWidth\n        var signX = layout.width > 0 ? 1 : -1;\n        var signY = layout.height > 0 ? 1 : -1;\n        return {\n            x: layout.x + signX * fixedLineWidth / 2,\n            y: layout.y + signY * fixedLineWidth / 2,\n            width: layout.width - signX * fixedLineWidth,\n            height: layout.height - signY * fixedLineWidth\n        };\n    },\n\n    polar: function (data, dataIndex, itemModel) {\n        var layout = data.getItemLayout(dataIndex);\n        return {\n            cx: layout.cx,\n            cy: layout.cy,\n            r0: layout.r0,\n            r: layout.r,\n            startAngle: layout.startAngle,\n            endAngle: layout.endAngle\n        };\n    }\n};\n\nfunction updateStyle(\n    el, data, dataIndex, itemModel, layout, seriesModel, isHorizontal, isPolar\n) {\n    var color = data.getItemVisual(dataIndex, 'color');\n    var opacity = data.getItemVisual(dataIndex, 'opacity');\n    var itemStyleModel = itemModel.getModel('itemStyle');\n    var hoverStyle = itemModel.getModel('emphasis.itemStyle').getBarItemStyle();\n\n    if (!isPolar) {\n        el.setShape('r', itemStyleModel.get('barBorderRadius') || 0);\n    }\n\n    el.useStyle(defaults(\n        {\n            fill: color,\n            opacity: opacity\n        },\n        itemStyleModel.getBarItemStyle()\n    ));\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && el.attr('cursor', cursorStyle);\n\n    var labelPositionOutside = isHorizontal\n        ? (layout.height > 0 ? 'bottom' : 'top')\n        : (layout.width > 0 ? 'left' : 'right');\n\n    if (!isPolar) {\n        setLabel(\n            el.style, hoverStyle, itemModel, color,\n            seriesModel, dataIndex, labelPositionOutside\n        );\n    }\n\n    setHoverStyle(el, hoverStyle);\n}\n\n// In case width or height are too small.\nfunction getLineWidth(itemModel, rawLayout) {\n    var lineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY) || 0;\n    return Math.min(lineWidth, Math.abs(rawLayout.width), Math.abs(rawLayout.height));\n}\n\n\nvar LargePath = Path.extend({\n\n    type: 'largeBar',\n\n    shape: {points: []},\n\n    buildPath: function (ctx, shape) {\n        // Drawing lines is more efficient than drawing\n        // a whole line or drawing rects.\n        var points = shape.points;\n        var startPoint = this.__startPoint;\n        var valueIdx = this.__valueIdx;\n\n        for (var i = 0; i < points.length; i += 2) {\n            startPoint[this.__valueIdx] = points[i + valueIdx];\n            ctx.moveTo(startPoint[0], startPoint[1]);\n            ctx.lineTo(points[i], points[i + 1]);\n        }\n    }\n});\n\nfunction createLarge(seriesModel, group, incremental) {\n    // TODO support polar\n    var data = seriesModel.getData();\n    var startPoint = [];\n    var valueIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0;\n    startPoint[1 - valueIdx] = data.getLayout('valueAxisStart');\n\n    var el = new LargePath({\n        shape: {points: data.getLayout('largePoints')},\n        incremental: !!incremental,\n        __startPoint: startPoint,\n        __valueIdx: valueIdx\n    });\n    group.add(el);\n    setLargeStyle(el, seriesModel, data);\n}\n\nfunction setLargeStyle(el, seriesModel, data) {\n    var borderColor = data.getVisual('borderColor') || data.getVisual('color');\n    var itemStyle = seriesModel.getModel('itemStyle').getItemStyle(['color', 'borderColor']);\n\n    el.useStyle(itemStyle);\n    el.style.fill = null;\n    el.style.stroke = borderColor;\n    el.style.lineWidth = data.getLayout('barWidth');\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterLayout(curry(layout, 'bar'));\n// Should after normal bar layout, otherwise it is blocked by normal bar layout.\nregisterLayout(largeLayout);\n\nregisterVisual({\n    seriesType: 'bar',\n    reset: function (seriesModel) {\n        // Visual coding for legend\n        seriesModel.getData().setVisual('legendSymbol', 'roundRect');\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * [Usage]:\n * (1)\n * createListSimply(seriesModel, ['value']);\n * (2)\n * createListSimply(seriesModel, {\n *     coordDimensions: ['value'],\n *     dimensionsCount: 5\n * });\n *\n * @param {module:echarts/model/Series} seriesModel\n * @param {Object|Array.<string|Object>} opt opt or coordDimensions\n *        The options in opt, see `echarts/data/helper/createDimensions`\n * @param {Array.<string>} [nameList]\n * @return {module:echarts/data/List}\n */\nvar createListSimply = function (seriesModel, opt, nameList) {\n    opt = isArray(opt) && {coordDimensions: opt} || extend({}, opt);\n\n    var source = seriesModel.getSource();\n\n    var dimensionsInfo = createDimensions(source, opt);\n\n    var list = new List(dimensionsInfo, seriesModel);\n    list.initData(source, nameList);\n\n    return list;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Data selectable mixin for chart series.\n * To eanble data select, option of series must have `selectedMode`.\n * And each data item will use `selected` to toggle itself selected status\n */\n\nvar selectableMixin = {\n\n    /**\n     * @param {Array.<Object>} targetList [{name, value, selected}, ...]\n     *        If targetList is an array, it should like [{name: ..., value: ...}, ...].\n     *        If targetList is a \"List\", it must have coordDim: 'value' dimension and name.\n     */\n    updateSelectedMap: function (targetList) {\n        this._targetList = isArray(targetList) ? targetList.slice() : [];\n\n        this._selectTargetMap = reduce(targetList || [], function (targetMap, target) {\n            targetMap.set(target.name, target);\n            return targetMap;\n        }, createHashMap());\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    // PENGING If selectedMode is null ?\n    select: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        var selectedMode = this.get('selectedMode');\n        if (selectedMode === 'single') {\n            this._selectTargetMap.each(function (target) {\n                target.selected = false;\n            });\n        }\n        target && (target.selected = true);\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    unSelect: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        // var selectedMode = this.get('selectedMode');\n        // selectedMode !== 'single' && target && (target.selected = false);\n        target && (target.selected = false);\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    toggleSelected: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        if (target != null) {\n            this[target.selected ? 'unSelect' : 'select'](name, id);\n            return target.selected;\n        }\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    isSelected: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        return target && target.selected;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PieSeries = extendSeriesModel({\n\n    type: 'series.pie',\n\n    // Overwrite\n    init: function (option) {\n        PieSeries.superApply(this, 'init', arguments);\n\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n\n        this.updateSelectedMap(this._createSelectableList());\n\n        this._defaultLabelLine(option);\n    },\n\n    // Overwrite\n    mergeOption: function (newOption) {\n        PieSeries.superCall(this, 'mergeOption', newOption);\n\n        this.updateSelectedMap(this._createSelectableList());\n    },\n\n    getInitialData: function (option, ecModel) {\n        return createListSimply(this, ['value']);\n    },\n\n    _createSelectableList: function () {\n        var data = this.getRawData();\n        var valueDim = data.mapDimension('value');\n        var targetList = [];\n        for (var i = 0, len = data.count(); i < len; i++) {\n            targetList.push({\n                name: data.getName(i),\n                value: data.get(valueDim, i),\n                selected: retrieveRawAttr(data, i, 'selected')\n            });\n        }\n        return targetList;\n    },\n\n    // Overwrite\n    getDataParams: function (dataIndex) {\n        var data = this.getData();\n        var params = PieSeries.superCall(this, 'getDataParams', dataIndex);\n        // FIXME toFixed?\n\n        var valueList = [];\n        data.each(data.mapDimension('value'), function (value) {\n            valueList.push(value);\n        });\n\n        params.percent = getPercentWithPrecision(\n            valueList,\n            dataIndex,\n            data.hostModel.get('percentPrecision')\n        );\n\n        params.$vars.push('percent');\n        return params;\n    },\n\n    _defaultLabelLine: function (option) {\n        // Extend labelLine emphasis\n        defaultEmphasis(option, 'labelLine', ['show']);\n\n        var labelLineNormalOpt = option.labelLine;\n        var labelLineEmphasisOpt = option.emphasis.labelLine;\n        // Not show label line if `label.normal.show = false`\n        labelLineNormalOpt.show = labelLineNormalOpt.show\n            && option.label.show;\n        labelLineEmphasisOpt.show = labelLineEmphasisOpt.show\n            && option.emphasis.label.show;\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // 默认全局居中\n        center: ['50%', '50%'],\n        radius: [0, '75%'],\n        // 默认顺时针\n        clockwise: true,\n        startAngle: 90,\n        // 最小角度改为0\n        minAngle: 0,\n        // 选中时扇区偏移量\n        selectedOffset: 10,\n        // 高亮扇区偏移量\n        hoverOffset: 10,\n\n        // If use strategy to avoid label overlapping\n        avoidLabelOverlap: true,\n        // 选择模式，默认关闭，可选single，multiple\n        // selectedMode: false,\n        // 南丁格尔玫瑰图模式，'radius'（半径） | 'area'（面积）\n        // roseType: null,\n\n        percentPrecision: 2,\n\n        // If still show when all data zero.\n        stillShowZeroSum: true,\n\n        // cursor: null,\n\n        label: {\n            // If rotate around circle\n            rotate: false,\n            show: true,\n            // 'outer', 'inside', 'center'\n            position: 'outer'\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n            // 默认使用全局文本样式，详见TEXTSTYLE\n            // distance: 当position为inner时有效，为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数\n        },\n        // Enabled when label.normal.position is 'outer'\n        labelLine: {\n            show: true,\n            // 引导线两段中的第一段长度\n            length: 15,\n            // 引导线两段中的第二段长度\n            length2: 15,\n            smooth: false,\n            lineStyle: {\n                // color: 各异,\n                width: 1,\n                type: 'solid'\n            }\n        },\n        itemStyle: {\n            borderWidth: 1\n        },\n\n        // Animation type canbe expansion, scale\n        animationType: 'expansion',\n\n        animationEasing: 'cubicOut'\n    }\n});\n\nmixin(PieSeries, selectableMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/model/Series} seriesModel\n * @param {boolean} hasAnimation\n * @inner\n */\nfunction updateDataSelected(uid, seriesModel, hasAnimation, api) {\n    var data = seriesModel.getData();\n    var dataIndex = this.dataIndex;\n    var name = data.getName(dataIndex);\n    var selectedOffset = seriesModel.get('selectedOffset');\n\n    api.dispatchAction({\n        type: 'pieToggleSelect',\n        from: uid,\n        name: name,\n        seriesId: seriesModel.id\n    });\n\n    data.each(function (idx) {\n        toggleItemSelected(\n            data.getItemGraphicEl(idx),\n            data.getItemLayout(idx),\n            seriesModel.isSelected(data.getName(idx)),\n            selectedOffset,\n            hasAnimation\n        );\n    });\n}\n\n/**\n * @param {module:zrender/graphic/Sector} el\n * @param {Object} layout\n * @param {boolean} isSelected\n * @param {number} selectedOffset\n * @param {boolean} hasAnimation\n * @inner\n */\nfunction toggleItemSelected(el, layout, isSelected, selectedOffset, hasAnimation) {\n    var midAngle = (layout.startAngle + layout.endAngle) / 2;\n\n    var dx = Math.cos(midAngle);\n    var dy = Math.sin(midAngle);\n\n    var offset = isSelected ? selectedOffset : 0;\n    var position = [dx * offset, dy * offset];\n\n    hasAnimation\n        // animateTo will stop revious animation like update transition\n        ? el.animate()\n            .when(200, {\n                position: position\n            })\n            .start('bounceOut')\n        : el.attr('position', position);\n}\n\n/**\n * Piece of pie including Sector, Label, LabelLine\n * @constructor\n * @extends {module:zrender/graphic/Group}\n */\nfunction PiePiece(data, idx) {\n\n    Group.call(this);\n\n    var sector = new Sector({\n        z2: 2\n    });\n    var polyline = new Polyline();\n    var text = new Text();\n    this.add(sector);\n    this.add(polyline);\n    this.add(text);\n\n    this.updateData(data, idx, true);\n\n    // Hover to change label and labelLine\n    function onEmphasis() {\n        polyline.ignore = polyline.hoverIgnore;\n        text.ignore = text.hoverIgnore;\n    }\n    function onNormal() {\n        polyline.ignore = polyline.normalIgnore;\n        text.ignore = text.normalIgnore;\n    }\n    this.on('emphasis', onEmphasis)\n        .on('normal', onNormal)\n        .on('mouseover', onEmphasis)\n        .on('mouseout', onNormal);\n}\n\nvar piePieceProto = PiePiece.prototype;\n\npiePieceProto.updateData = function (data, idx, firstCreate) {\n\n    var sector = this.childAt(0);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var sectorShape = extend({}, layout);\n    sectorShape.label = null;\n\n    if (firstCreate) {\n        sector.setShape(sectorShape);\n\n        var animationType = seriesModel.getShallow('animationType');\n        if (animationType === 'scale') {\n            sector.shape.r = layout.r0;\n            initProps(sector, {\n                shape: {\n                    r: layout.r\n                }\n            }, seriesModel, idx);\n        }\n        // Expansion\n        else {\n            sector.shape.endAngle = layout.startAngle;\n            updateProps(sector, {\n                shape: {\n                    endAngle: layout.endAngle\n                }\n            }, seriesModel, idx);\n        }\n\n    }\n    else {\n        updateProps(sector, {\n            shape: sectorShape\n        }, seriesModel, idx);\n    }\n\n    // Update common style\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    sector.useStyle(\n        defaults(\n            {\n                lineJoin: 'bevel',\n                fill: visualColor\n            },\n            itemModel.getModel('itemStyle').getItemStyle()\n        )\n    );\n    sector.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && sector.attr('cursor', cursorStyle);\n\n    // Toggle selected\n    toggleItemSelected(\n        this,\n        data.getItemLayout(idx),\n        seriesModel.isSelected(null, idx),\n        seriesModel.get('selectedOffset'),\n        seriesModel.get('animation')\n    );\n\n    function onEmphasis() {\n        // Sector may has animation of updating data. Force to move to the last frame\n        // Or it may stopped on the wrong shape\n        sector.stopAnimation(true);\n        sector.animateTo({\n            shape: {\n                r: layout.r + seriesModel.get('hoverOffset')\n            }\n        }, 300, 'elasticOut');\n    }\n    function onNormal() {\n        sector.stopAnimation(true);\n        sector.animateTo({\n            shape: {\n                r: layout.r\n            }\n        }, 300, 'elasticOut');\n    }\n    sector.off('mouseover').off('mouseout').off('emphasis').off('normal');\n    if (itemModel.get('hoverAnimation') && seriesModel.isAnimationEnabled()) {\n        sector\n            .on('mouseover', onEmphasis)\n            .on('mouseout', onNormal)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal);\n    }\n\n    this._updateLabel(data, idx);\n\n    setHoverStyle(this);\n};\n\npiePieceProto._updateLabel = function (data, idx) {\n\n    var labelLine = this.childAt(1);\n    var labelText = this.childAt(2);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var labelLayout = layout.label;\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    updateProps(labelLine, {\n        shape: {\n            points: labelLayout.linePoints || [\n                [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y]\n            ]\n        }\n    }, seriesModel, idx);\n\n    updateProps(labelText, {\n        style: {\n            x: labelLayout.x,\n            y: labelLayout.y\n        }\n    }, seriesModel, idx);\n    labelText.attr({\n        rotation: labelLayout.rotation,\n        origin: [labelLayout.x, labelLayout.y],\n        z2: 10\n    });\n\n    var labelModel = itemModel.getModel('label');\n    var labelHoverModel = itemModel.getModel('emphasis.label');\n    var labelLineModel = itemModel.getModel('labelLine');\n    var labelLineHoverModel = itemModel.getModel('emphasis.labelLine');\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    setLabelStyle(\n        labelText.style, labelText.hoverStyle = {}, labelModel, labelHoverModel,\n        {\n            labelFetcher: data.hostModel,\n            labelDataIndex: idx,\n            defaultText: data.getName(idx),\n            autoColor: visualColor,\n            useInsideStyle: !!labelLayout.inside\n        },\n        {\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.verticalAlign,\n            opacity: data.getItemVisual(idx, 'opacity')\n        }\n    );\n\n    labelText.ignore = labelText.normalIgnore = !labelModel.get('show');\n    labelText.hoverIgnore = !labelHoverModel.get('show');\n\n    labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show');\n    labelLine.hoverIgnore = !labelLineHoverModel.get('show');\n\n    // Default use item visual color\n    labelLine.setStyle({\n        stroke: visualColor,\n        opacity: data.getItemVisual(idx, 'opacity')\n    });\n    labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());\n\n    labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();\n\n    var smooth = labelLineModel.get('smooth');\n    if (smooth && smooth === true) {\n        smooth = 0.4;\n    }\n    labelLine.setShape({\n        smooth: smooth\n    });\n};\n\ninherits(PiePiece, Group);\n\n\n// Pie view\nvar PieView = Chart.extend({\n\n    type: 'pie',\n\n    init: function () {\n        var sectorGroup = new Group();\n        this._sectorGroup = sectorGroup;\n    },\n\n    render: function (seriesModel, ecModel, api, payload) {\n        if (payload && (payload.from === this.uid)) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var oldData = this._data;\n        var group = this.group;\n\n        var hasAnimation = ecModel.get('animation');\n        var isFirstRender = !oldData;\n        var animationType = seriesModel.get('animationType');\n\n        var onSectorClick = curry(\n            updateDataSelected, this.uid, seriesModel, hasAnimation, api\n        );\n\n        var selectedMode = seriesModel.get('selectedMode');\n\n        data.diff(oldData)\n            .add(function (idx) {\n                var piePiece = new PiePiece(data, idx);\n                // Default expansion animation\n                if (isFirstRender && animationType !== 'scale') {\n                    piePiece.eachChild(function (child) {\n                        child.stopAnimation(true);\n                    });\n                }\n\n                selectedMode && piePiece.on('click', onSectorClick);\n\n                data.setItemGraphicEl(idx, piePiece);\n\n                group.add(piePiece);\n            })\n            .update(function (newIdx, oldIdx) {\n                var piePiece = oldData.getItemGraphicEl(oldIdx);\n\n                piePiece.updateData(data, newIdx);\n\n                piePiece.off('click');\n                selectedMode && piePiece.on('click', onSectorClick);\n                group.add(piePiece);\n                data.setItemGraphicEl(newIdx, piePiece);\n            })\n            .remove(function (idx) {\n                var piePiece = oldData.getItemGraphicEl(idx);\n                group.remove(piePiece);\n            })\n            .execute();\n\n        if (\n            hasAnimation && isFirstRender && data.count() > 0\n            // Default expansion animation\n            && animationType !== 'scale'\n        ) {\n            var shape = data.getItemLayout(0);\n            var r = Math.max(api.getWidth(), api.getHeight()) / 2;\n\n            var removeClipPath = bind(group.removeClipPath, group);\n            group.setClipPath(this._createClipPath(\n                shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel\n            ));\n        }\n        else {\n            // clipPath is used in first-time animation, so remove it when otherwise. See: #8994\n            group.removeClipPath();\n        }\n\n        this._data = data;\n    },\n\n    dispose: function () {},\n\n    _createClipPath: function (\n        cx, cy, r, startAngle, clockwise, cb, seriesModel\n    ) {\n        var clipPath = new Sector({\n            shape: {\n                cx: cx,\n                cy: cy,\n                r0: 0,\n                r: r,\n                startAngle: startAngle,\n                endAngle: startAngle,\n                clockwise: clockwise\n            }\n        });\n\n        initProps(clipPath, {\n            shape: {\n                endAngle: startAngle + (clockwise ? 1 : -1) * Math.PI * 2\n            }\n        }, seriesModel, cb);\n\n        return clipPath;\n    },\n\n    /**\n     * @implement\n     */\n    containPoint: function (point, seriesModel) {\n        var data = seriesModel.getData();\n        var itemLayout = data.getItemLayout(0);\n        if (itemLayout) {\n            var dx = point[0] - itemLayout.cx;\n            var dy = point[1] - itemLayout.cy;\n            var radius = Math.sqrt(dx * dx + dy * dy);\n            return radius <= itemLayout.r && radius >= itemLayout.r0;\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar createDataSelectAction = function (seriesType, actionInfos) {\n    each$1(actionInfos, function (actionInfo) {\n        actionInfo.update = 'updateView';\n        /**\n         * @payload\n         * @property {string} seriesName\n         * @property {string} name\n         */\n        registerAction(actionInfo, function (payload, ecModel) {\n            var selected = {};\n            ecModel.eachComponent(\n                {mainType: 'series', subType: seriesType, query: payload},\n                function (seriesModel) {\n                    if (seriesModel[actionInfo.method]) {\n                        seriesModel[actionInfo.method](\n                            payload.name,\n                            payload.dataIndex\n                        );\n                    }\n                    var data = seriesModel.getData();\n                    // Create selected map\n                    data.each(function (idx) {\n                        var name = data.getName(idx);\n                        selected[name] = seriesModel.isSelected(name)\n                            || false;\n                    });\n                }\n            );\n            return {\n                name: payload.name,\n                selected: selected\n            };\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Pick color from palette for each data item.\n// Applicable for charts that require applying color palette\n// in data level (like pie, funnel, chord).\nvar dataColor = function (seriesType) {\n    return {\n        getTargetSeries: function (ecModel) {\n            // Pie and funnel may use diferrent scope\n            var paletteScope = {};\n            var seiresModelMap = createHashMap();\n\n            ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n                seriesModel.__paletteScope = paletteScope;\n                seiresModelMap.set(seriesModel.uid, seriesModel);\n            });\n\n            return seiresModelMap;\n        },\n        reset: function (seriesModel, ecModel) {\n            var dataAll = seriesModel.getRawData();\n            var idxMap = {};\n            var data = seriesModel.getData();\n\n            data.each(function (idx) {\n                var rawIdx = data.getRawIndex(idx);\n                idxMap[rawIdx] = idx;\n            });\n\n            dataAll.each(function (rawIdx) {\n                var filteredIdx = idxMap[rawIdx];\n\n                // If series.itemStyle.normal.color is a function. itemVisual may be encoded\n                var singleDataColor = filteredIdx != null\n                    && data.getItemVisual(filteredIdx, 'color', true);\n\n                if (!singleDataColor) {\n                    // FIXME Performance\n                    var itemModel = dataAll.getItemModel(rawIdx);\n\n                    var color = itemModel.get('itemStyle.color')\n                        || seriesModel.getColorFromPalette(\n                            dataAll.getName(rawIdx) || (rawIdx + ''), seriesModel.__paletteScope,\n                            dataAll.count()\n                        );\n                    // Legend may use the visual info in data before processed\n                    dataAll.setItemVisual(rawIdx, 'color', color);\n\n                    // Data is not filtered\n                    if (filteredIdx != null) {\n                        data.setItemVisual(filteredIdx, 'color', color);\n                    }\n                }\n                else {\n                    // Set data all color for legend\n                    dataAll.setItemVisual(rawIdx, 'color', singleDataColor);\n                }\n            });\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME emphasis label position is not same with normal label position\n\nfunction adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {\n    list.sort(function (a, b) {\n        return a.y - b.y;\n    });\n\n    function shiftDown(start, end, delta, dir) {\n        for (var j = start; j < end; j++) {\n            list[j].y += delta;\n            if (j > start\n                && j + 1 < end\n                && list[j + 1].y > list[j].y + list[j].height\n            ) {\n                shiftUp(j, delta / 2);\n                return;\n            }\n        }\n\n        shiftUp(end - 1, delta / 2);\n    }\n\n    function shiftUp(end, delta) {\n        for (var j = end; j >= 0; j--) {\n            list[j].y -= delta;\n            if (j > 0\n                && list[j].y > list[j - 1].y + list[j - 1].height\n            ) {\n                break;\n            }\n        }\n    }\n\n    function changeX(list, isDownList, cx, cy, r, dir) {\n        var lastDeltaX = dir > 0\n            ? isDownList                // right-side\n                ? Number.MAX_VALUE      // down\n                : 0                     // up\n            : isDownList                // left-side\n                ? Number.MAX_VALUE      // down\n                : 0;                    // up\n\n        for (var i = 0, l = list.length; i < l; i++) {\n            var deltaY = Math.abs(list[i].y - cy);\n            var length = list[i].len;\n            var length2 = list[i].len2;\n            var deltaX = (deltaY < r + length)\n                ? Math.sqrt(\n                        (r + length + length2) * (r + length + length2)\n                        - deltaY * deltaY\n                    )\n                : Math.abs(list[i].x - cx);\n            if (isDownList && deltaX >= lastDeltaX) {\n                // right-down, left-down\n                deltaX = lastDeltaX - 10;\n            }\n            if (!isDownList && deltaX <= lastDeltaX) {\n                // right-up, left-up\n                deltaX = lastDeltaX + 10;\n            }\n\n            list[i].x = cx + deltaX * dir;\n            lastDeltaX = deltaX;\n        }\n    }\n\n    var lastY = 0;\n    var delta;\n    var len = list.length;\n    var upList = [];\n    var downList = [];\n    for (var i = 0; i < len; i++) {\n        delta = list[i].y - lastY;\n        if (delta < 0) {\n            shiftDown(i, len, -delta, dir);\n        }\n        lastY = list[i].y + list[i].height;\n    }\n    if (viewHeight - lastY < 0) {\n        shiftUp(len - 1, lastY - viewHeight);\n    }\n    for (var i = 0; i < len; i++) {\n        if (list[i].y >= cy) {\n            downList.push(list[i]);\n        }\n        else {\n            upList.push(list[i]);\n        }\n    }\n    changeX(upList, false, cx, cy, r, dir);\n    changeX(downList, true, cx, cy, r, dir);\n}\n\nfunction avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) {\n    var leftList = [];\n    var rightList = [];\n    for (var i = 0; i < labelLayoutList.length; i++) {\n        if (isPositionCenter(labelLayoutList[i])) {\n            continue;\n        }\n        if (labelLayoutList[i].x < cx) {\n            leftList.push(labelLayoutList[i]);\n        }\n        else {\n            rightList.push(labelLayoutList[i]);\n        }\n    }\n\n    adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight);\n    adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight);\n\n    for (var i = 0; i < labelLayoutList.length; i++) {\n        if (isPositionCenter(labelLayoutList[i])) {\n            continue;\n        }\n        var linePoints = labelLayoutList[i].linePoints;\n        if (linePoints) {\n            var dist = linePoints[1][0] - linePoints[2][0];\n            if (labelLayoutList[i].x < cx) {\n                linePoints[2][0] = labelLayoutList[i].x + 3;\n            }\n            else {\n                linePoints[2][0] = labelLayoutList[i].x - 3;\n            }\n            linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y;\n            linePoints[1][0] = linePoints[2][0] + dist;\n        }\n    }\n}\n\nfunction isPositionCenter(layout) {\n    // Not change x for center label\n    return layout.position === 'center';\n}\n\nvar labelLayout = function (seriesModel, r, viewWidth, viewHeight) {\n    var data = seriesModel.getData();\n    var labelLayoutList = [];\n    var cx;\n    var cy;\n    var hasLabelRotate = false;\n\n    data.each(function (idx) {\n        var layout = data.getItemLayout(idx);\n\n        var itemModel = data.getItemModel(idx);\n        var labelModel = itemModel.getModel('label');\n        // Use position in normal or emphasis\n        var labelPosition = labelModel.get('position') || itemModel.get('emphasis.label.position');\n\n        var labelLineModel = itemModel.getModel('labelLine');\n        var labelLineLen = labelLineModel.get('length');\n        var labelLineLen2 = labelLineModel.get('length2');\n\n        var midAngle = (layout.startAngle + layout.endAngle) / 2;\n        var dx = Math.cos(midAngle);\n        var dy = Math.sin(midAngle);\n\n        var textX;\n        var textY;\n        var linePoints;\n        var textAlign;\n\n        cx = layout.cx;\n        cy = layout.cy;\n\n        var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';\n        if (labelPosition === 'center') {\n            textX = layout.cx;\n            textY = layout.cy;\n            textAlign = 'center';\n        }\n        else {\n            var x1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dx : layout.r * dx) + cx;\n            var y1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dy : layout.r * dy) + cy;\n\n            textX = x1 + dx * 3;\n            textY = y1 + dy * 3;\n\n            if (!isLabelInside) {\n                // For roseType\n                var x2 = x1 + dx * (labelLineLen + r - layout.r);\n                var y2 = y1 + dy * (labelLineLen + r - layout.r);\n                var x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2);\n                var y3 = y2;\n\n                textX = x3 + (dx < 0 ? -5 : 5);\n                textY = y3;\n                linePoints = [[x1, y1], [x2, y2], [x3, y3]];\n            }\n\n            textAlign = isLabelInside ? 'center' : (dx > 0 ? 'left' : 'right');\n        }\n        var font = labelModel.getFont();\n\n        var labelRotate = labelModel.get('rotate')\n            ? (dx < 0 ? -midAngle + Math.PI : -midAngle) : 0;\n        var text = seriesModel.getFormattedLabel(idx, 'normal')\n                    || data.getName(idx);\n        var textRect = getBoundingRect(\n            text, font, textAlign, 'top'\n        );\n        hasLabelRotate = !!labelRotate;\n        layout.label = {\n            x: textX,\n            y: textY,\n            position: labelPosition,\n            height: textRect.height,\n            len: labelLineLen,\n            len2: labelLineLen2,\n            linePoints: linePoints,\n            textAlign: textAlign,\n            verticalAlign: 'middle',\n            rotation: labelRotate,\n            inside: isLabelInside\n        };\n\n        // Not layout the inside label\n        if (!isLabelInside) {\n            labelLayoutList.push(layout.label);\n        }\n    });\n    if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {\n        avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar PI2$4 = Math.PI * 2;\nvar RADIAN = Math.PI / 180;\n\nvar pieLayout = function (seriesType, ecModel, api, payload) {\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n\n        var center = seriesModel.get('center');\n        var radius = seriesModel.get('radius');\n\n        if (!isArray(radius)) {\n            radius = [0, radius];\n        }\n        if (!isArray(center)) {\n            center = [center, center];\n        }\n\n        var width = api.getWidth();\n        var height = api.getHeight();\n        var size = Math.min(width, height);\n        var cx = parsePercent$1(center[0], width);\n        var cy = parsePercent$1(center[1], height);\n        var r0 = parsePercent$1(radius[0], size / 2);\n        var r = parsePercent$1(radius[1], size / 2);\n\n        var startAngle = -seriesModel.get('startAngle') * RADIAN;\n\n        var minAngle = seriesModel.get('minAngle') * RADIAN;\n\n        var validDataCount = 0;\n        data.each(valueDim, function (value) {\n            !isNaN(value) && validDataCount++;\n        });\n\n        var sum = data.getSum(valueDim);\n        // Sum may be 0\n        var unitRadian = Math.PI / (sum || validDataCount) * 2;\n\n        var clockwise = seriesModel.get('clockwise');\n\n        var roseType = seriesModel.get('roseType');\n        var stillShowZeroSum = seriesModel.get('stillShowZeroSum');\n\n        // [0...max]\n        var extent = data.getDataExtent(valueDim);\n        extent[0] = 0;\n\n        // In the case some sector angle is smaller than minAngle\n        var restAngle = PI2$4;\n        var valueSumLargerThanMinAngle = 0;\n\n        var currentAngle = startAngle;\n        var dir = clockwise ? 1 : -1;\n\n        data.each(valueDim, function (value, idx) {\n            var angle;\n            if (isNaN(value)) {\n                data.setItemLayout(idx, {\n                    angle: NaN,\n                    startAngle: NaN,\n                    endAngle: NaN,\n                    clockwise: clockwise,\n                    cx: cx,\n                    cy: cy,\n                    r0: r0,\n                    r: roseType\n                        ? NaN\n                        : r\n                });\n                return;\n            }\n\n            // FIXME 兼容 2.0 但是 roseType 是 area 的时候才是这样？\n            if (roseType !== 'area') {\n                angle = (sum === 0 && stillShowZeroSum)\n                    ? unitRadian : (value * unitRadian);\n            }\n            else {\n                angle = PI2$4 / validDataCount;\n            }\n\n            if (angle < minAngle) {\n                angle = minAngle;\n                restAngle -= minAngle;\n            }\n            else {\n                valueSumLargerThanMinAngle += value;\n            }\n\n            var endAngle = currentAngle + dir * angle;\n            data.setItemLayout(idx, {\n                angle: angle,\n                startAngle: currentAngle,\n                endAngle: endAngle,\n                clockwise: clockwise,\n                cx: cx,\n                cy: cy,\n                r0: r0,\n                r: roseType\n                    ? linearMap(value, extent, [r0, r])\n                    : r\n            });\n\n            currentAngle = endAngle;\n        });\n\n        // Some sector is constrained by minAngle\n        // Rest sectors needs recalculate angle\n        if (restAngle < PI2$4 && validDataCount) {\n            // Average the angle if rest angle is not enough after all angles is\n            // Constrained by minAngle\n            if (restAngle <= 1e-3) {\n                var angle = PI2$4 / validDataCount;\n                data.each(valueDim, function (value, idx) {\n                    if (!isNaN(value)) {\n                        var layout = data.getItemLayout(idx);\n                        layout.angle = angle;\n                        layout.startAngle = startAngle + dir * idx * angle;\n                        layout.endAngle = startAngle + dir * (idx + 1) * angle;\n                    }\n                });\n            }\n            else {\n                unitRadian = restAngle / valueSumLargerThanMinAngle;\n                currentAngle = startAngle;\n                data.each(valueDim, function (value, idx) {\n                    if (!isNaN(value)) {\n                        var layout = data.getItemLayout(idx);\n                        var angle = layout.angle === minAngle\n                            ? minAngle : value * unitRadian;\n                        layout.startAngle = currentAngle;\n                        layout.endAngle = currentAngle + dir * angle;\n                        currentAngle += dir * angle;\n                    }\n                });\n            }\n        }\n\n        labelLayout(seriesModel, r, width, height);\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar dataFilter = function (seriesType) {\n    return {\n        seriesType: seriesType,\n        reset: function (seriesModel, ecModel) {\n            var legendModels = ecModel.findComponents({\n                mainType: 'legend'\n            });\n            if (!legendModels || !legendModels.length) {\n                return;\n            }\n            var data = seriesModel.getData();\n            data.filterSelf(function (idx) {\n                var name = data.getName(idx);\n                // If in any legend component the status is not selected.\n                for (var i = 0; i < legendModels.length; i++) {\n                    if (!legendModels[i].isSelected(name)) {\n                        return false;\n                    }\n                }\n                return true;\n            });\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\ncreateDataSelectAction('pie', [{\n    type: 'pieToggleSelect',\n    event: 'pieselectchanged',\n    method: 'toggleSelected'\n}, {\n    type: 'pieSelect',\n    event: 'pieselected',\n    method: 'select'\n}, {\n    type: 'pieUnSelect',\n    event: 'pieunselected',\n    method: 'unSelect'\n}]);\n\nregisterVisual(dataColor('pie'));\nregisterLayout(curry(pieLayout, 'pie'));\nregisterProcessor(dataFilter('pie'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.scatter',\n\n    dependencies: ['grid', 'polar', 'geo', 'singleAxis', 'calendar'],\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    brushSelector: 'point',\n\n    getProgressive: function () {\n        var progressive = this.option.progressive;\n        if (progressive == null) {\n            // PENDING\n            return this.option.large ? 5e3 : this.get('progressive');\n        }\n        return progressive;\n    },\n\n    getProgressiveThreshold: function () {\n        var progressiveThreshold = this.option.progressiveThreshold;\n        if (progressiveThreshold == null) {\n            // PENDING\n            return this.option.large ? 1e4 : this.get('progressiveThreshold');\n        }\n        return progressiveThreshold;\n    },\n\n    defaultOption: {\n        coordinateSystem: 'cartesian2d',\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // Polar coordinate system\n        // polarIndex: 0,\n\n        // Geo coordinate system\n        // geoIndex: 0,\n\n        // symbol: null,        // 图形类型\n        symbolSize: 10,          // 图形大小，半宽（半径）参数，当图形为方向或菱形则总宽度为symbolSize * 2\n        // symbolRotate: null,  // 图形旋转控制\n\n        large: false,\n        // Available when large is true\n        largeThreshold: 2000,\n        // cursor: null,\n\n        // label: {\n            // show: false\n            // distance: 5,\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n            // position: 默认自适应，水平布局为'top'，垂直布局为'right'，可选为\n            //           'inside'|'left'|'right'|'top'|'bottom'\n            // 默认使用全局文本样式，详见TEXTSTYLE\n        // },\n        itemStyle: {\n            opacity: 0.8\n            // color: 各异\n        }\n\n        // progressive: null\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\n// TODO Batch by color\n\nvar BOOST_SIZE_THRESHOLD = 4;\n\nvar LargeSymbolPath = extendShape({\n\n    shape: {\n        points: null\n    },\n\n    symbolProxy: null,\n\n    buildPath: function (path, shape) {\n        var points = shape.points;\n        var size = shape.size;\n\n        var symbolProxy = this.symbolProxy;\n        var symbolProxyShape = symbolProxy.shape;\n        var ctx = path.getContext ? path.getContext() : path;\n        var canBoost = ctx && size[0] < BOOST_SIZE_THRESHOLD;\n\n        // Do draw in afterBrush.\n        if (canBoost) {\n            return;\n        }\n\n        for (var i = 0; i < points.length;) {\n            var x = points[i++];\n            var y = points[i++];\n\n            if (isNaN(x) || isNaN(y)) {\n                continue;\n            }\n\n            symbolProxyShape.x = x - size[0] / 2;\n            symbolProxyShape.y = y - size[1] / 2;\n            symbolProxyShape.width = size[0];\n            symbolProxyShape.height = size[1];\n\n            symbolProxy.buildPath(path, symbolProxyShape, true);\n        }\n    },\n\n    afterBrush: function (ctx) {\n        var shape = this.shape;\n        var points = shape.points;\n        var size = shape.size;\n        var canBoost = size[0] < BOOST_SIZE_THRESHOLD;\n\n        if (!canBoost) {\n            return;\n        }\n\n        this.setTransform(ctx);\n        // PENDING If style or other canvas status changed?\n        for (var i = 0; i < points.length;) {\n            var x = points[i++];\n            var y = points[i++];\n            if (isNaN(x) || isNaN(y)) {\n                continue;\n            }\n            // fillRect is faster than building a rect path and draw.\n            // And it support light globalCompositeOperation.\n            ctx.fillRect(\n                x - size[0] / 2, y - size[1] / 2,\n                size[0], size[1]\n            );\n        }\n\n        this.restoreTransform(ctx);\n    },\n\n    findDataIndex: function (x, y) {\n        // TODO ???\n        // Consider transform\n\n        var shape = this.shape;\n        var points = shape.points;\n        var size = shape.size;\n\n        var w = Math.max(size[0], 4);\n        var h = Math.max(size[1], 4);\n\n        // Not consider transform\n        // Treat each element as a rect\n        // top down traverse\n        for (var idx = points.length / 2 - 1; idx >= 0; idx--) {\n            var i = idx * 2;\n            var x0 = points[i] - w / 2;\n            var y0 = points[i + 1] - h / 2;\n            if (x >= x0 && y >= y0 && x <= x0 + w && y <= y0 + h) {\n                return idx;\n            }\n        }\n\n        return -1;\n    }\n});\n\nfunction LargeSymbolDraw() {\n    this.group = new Group();\n}\n\nvar largeSymbolProto = LargeSymbolDraw.prototype;\n\nlargeSymbolProto.isPersistent = function () {\n    return !this._incremental;\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n */\nlargeSymbolProto.updateData = function (data) {\n    this.group.removeAll();\n    var symbolEl = new LargeSymbolPath({\n        rectHover: true,\n        cursor: 'default'\n    });\n\n    symbolEl.setShape({\n        points: data.getLayout('symbolPoints')\n    });\n    this._setCommon(symbolEl, data);\n    this.group.add(symbolEl);\n\n    this._incremental = null;\n};\n\nlargeSymbolProto.updateLayout = function (data) {\n    if (this._incremental) {\n        return;\n    }\n\n    var points = data.getLayout('symbolPoints');\n    this.group.eachChild(function (child) {\n        if (child.startIndex != null) {\n            var len = (child.endIndex - child.startIndex) * 2;\n            var byteOffset = child.startIndex * 4 * 2;\n            points = new Float32Array(points.buffer, byteOffset, len);\n        }\n        child.setShape('points', points);\n    });\n};\n\nlargeSymbolProto.incrementalPrepareUpdate = function (data) {\n    this.group.removeAll();\n\n    this._clearIncremental();\n    // Only use incremental displayables when data amount is larger than 2 million.\n    // PENDING Incremental data?\n    if (data.count() > 2e6) {\n        if (!this._incremental) {\n            this._incremental = new IncrementalDisplayble({\n                silent: true\n            });\n        }\n        this.group.add(this._incremental);\n    }\n    else {\n        this._incremental = null;\n    }\n};\n\nlargeSymbolProto.incrementalUpdate = function (taskParams, data) {\n    var symbolEl;\n    if (this._incremental) {\n        symbolEl = new LargeSymbolPath();\n        this._incremental.addDisplayable(symbolEl, true);\n    }\n    else {\n        symbolEl = new LargeSymbolPath({\n            rectHover: true,\n            cursor: 'default',\n            startIndex: taskParams.start,\n            endIndex: taskParams.end\n        });\n        symbolEl.incremental = true;\n        this.group.add(symbolEl);\n    }\n\n    symbolEl.setShape({\n        points: data.getLayout('symbolPoints')\n    });\n    this._setCommon(symbolEl, data, !!this._incremental);\n};\n\nlargeSymbolProto._setCommon = function (symbolEl, data, isIncremental) {\n    var hostModel = data.hostModel;\n\n    // TODO\n    // if (data.hasItemVisual.symbolSize) {\n    //     // TODO typed array?\n    //     symbolEl.setShape('sizes', data.mapArray(\n    //         function (idx) {\n    //             var size = data.getItemVisual(idx, 'symbolSize');\n    //             return (size instanceof Array) ? size : [size, size];\n    //         }\n    //     ));\n    // }\n    // else {\n    var size = data.getVisual('symbolSize');\n    symbolEl.setShape('size', (size instanceof Array) ? size : [size, size]);\n    // }\n\n    // Create symbolProxy to build path for each data\n    symbolEl.symbolProxy = createSymbol(\n        data.getVisual('symbol'), 0, 0, 0, 0\n    );\n    // Use symbolProxy setColor method\n    symbolEl.setColor = symbolEl.symbolProxy.setColor;\n\n    var extrudeShadow = symbolEl.shape.size[0] < BOOST_SIZE_THRESHOLD;\n    symbolEl.useStyle(\n        // Draw shadow when doing fillRect is extremely slow.\n        hostModel.getModel('itemStyle').getItemStyle(extrudeShadow ? ['color', 'shadowBlur', 'shadowColor'] : ['color'])\n    );\n\n    var visualColor = data.getVisual('color');\n    if (visualColor) {\n        symbolEl.setColor(visualColor);\n    }\n\n    if (!isIncremental) {\n        // Enable tooltip\n        // PENDING May have performance issue when path is extremely large\n        symbolEl.seriesIndex = hostModel.seriesIndex;\n        symbolEl.on('mousemove', function (e) {\n            symbolEl.dataIndex = null;\n            var dataIndex = symbolEl.findDataIndex(e.offsetX, e.offsetY);\n            if (dataIndex >= 0) {\n                // Provide dataIndex for tooltip\n                symbolEl.dataIndex = dataIndex + (symbolEl.startIndex || 0);\n            }\n        });\n    }\n};\n\nlargeSymbolProto.remove = function () {\n    this._clearIncremental();\n    this._incremental = null;\n    this.group.removeAll();\n};\n\nlargeSymbolProto._clearIncremental = function () {\n    var incremental = this._incremental;\n    if (incremental) {\n        incremental.clearDisplaybles();\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendChartView({\n\n    type: 'scatter',\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        var symbolDraw = this._updateSymbolDraw(data, seriesModel);\n        symbolDraw.updateData(data);\n\n        this._finished = true;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var symbolDraw = this._updateSymbolDraw(data, seriesModel);\n\n        symbolDraw.incrementalPrepareUpdate(data);\n\n        this._finished = false;\n    },\n\n    incrementalRender: function (taskParams, seriesModel, ecModel) {\n        this._symbolDraw.incrementalUpdate(taskParams, seriesModel.getData());\n\n        this._finished = taskParams.end === seriesModel.getData().count();\n    },\n\n    updateTransform: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        // Must mark group dirty and make sure the incremental layer will be cleared\n        // PENDING\n        this.group.dirty();\n\n        if (!this._finished || data.count() > 1e4 || !this._symbolDraw.isPersistent()) {\n            return {\n                update: true\n            };\n        }\n        else {\n            var res = pointsLayout().reset(seriesModel);\n            if (res.progress) {\n                res.progress({ start: 0, end: data.count() }, data);\n            }\n\n            this._symbolDraw.updateLayout(data);\n        }\n    },\n\n    _updateSymbolDraw: function (data, seriesModel) {\n        var symbolDraw = this._symbolDraw;\n        var pipelineContext = seriesModel.pipelineContext;\n        var isLargeDraw = pipelineContext.large;\n\n        if (!symbolDraw || isLargeDraw !== this._isLargeDraw) {\n            symbolDraw && symbolDraw.remove();\n            symbolDraw = this._symbolDraw = isLargeDraw\n                ? new LargeSymbolDraw()\n                : new SymbolDraw();\n            this._isLargeDraw = isLargeDraw;\n            this.group.removeAll();\n        }\n\n        this.group.add(symbolDraw.group);\n\n        return symbolDraw;\n    },\n\n    remove: function (ecModel, api) {\n        this._symbolDraw && this._symbolDraw.remove(true);\n        this._symbolDraw = null;\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import * as zrUtil from 'zrender/src/core/util';\n\n// In case developer forget to include grid component\nregisterVisual(visualSymbol('scatter', 'circle'));\nregisterLayout(pointsLayout('scatter'));\n\n// echarts.registerProcessor(function (ecModel, api) {\n//     ecModel.eachSeriesByType('scatter', function (seriesModel) {\n//         var data = seriesModel.getData();\n//         var coordSys = seriesModel.coordinateSystem;\n//         if (coordSys.type !== 'geo') {\n//             return;\n//         }\n//         var startPt = coordSys.pointToData([0, 0]);\n//         var endPt = coordSys.pointToData([api.getWidth(), api.getHeight()]);\n\n//         var dims = zrUtil.map(coordSys.dimensions, function (dim) {\n//             return data.mapDimension(dim);\n//         });\n//         var range = {};\n//         range[dims[0]] = [Math.min(startPt[0], endPt[0]), Math.max(startPt[0], endPt[0])];\n//         range[dims[1]] = [Math.min(startPt[1], endPt[1]), Math.max(startPt[1], endPt[1])];\n\n//         data.selectRange(range);\n//     });\n// });\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction IndicatorAxis(dim, scale, radiusExtent) {\n    Axis.call(this, dim, scale, radiusExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = 'value';\n\n    this.angle = 0;\n\n    /**\n     * Indicator name\n     * @type {string}\n     */\n    this.name = '';\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.model;\n}\n\ninherits(IndicatorAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO clockwise\n\nfunction Radar(radarModel, ecModel, api) {\n\n    this._model = radarModel;\n    /**\n     * Radar dimensions\n     * @type {Array.<string>}\n     */\n    this.dimensions = [];\n\n    this._indicatorAxes = map(radarModel.getIndicatorModels(), function (indicatorModel, idx) {\n        var dim = 'indicator_' + idx;\n        var indicatorAxis = new IndicatorAxis(dim, new IntervalScale());\n        indicatorAxis.name = indicatorModel.get('name');\n        // Inject model and axis\n        indicatorAxis.model = indicatorModel;\n        indicatorModel.axis = indicatorAxis;\n        this.dimensions.push(dim);\n        return indicatorAxis;\n    }, this);\n\n    this.resize(radarModel, api);\n\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.cx;\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.cy;\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.r;\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.r0;\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.startAngle;\n}\n\nRadar.prototype.getIndicatorAxes = function () {\n    return this._indicatorAxes;\n};\n\nRadar.prototype.dataToPoint = function (value, indicatorIndex) {\n    var indicatorAxis = this._indicatorAxes[indicatorIndex];\n\n    return this.coordToPoint(indicatorAxis.dataToCoord(value), indicatorIndex);\n};\n\nRadar.prototype.coordToPoint = function (coord, indicatorIndex) {\n    var indicatorAxis = this._indicatorAxes[indicatorIndex];\n    var angle = indicatorAxis.angle;\n    var x = this.cx + coord * Math.cos(angle);\n    var y = this.cy - coord * Math.sin(angle);\n    return [x, y];\n};\n\nRadar.prototype.pointToData = function (pt) {\n    var dx = pt[0] - this.cx;\n    var dy = pt[1] - this.cy;\n    var radius = Math.sqrt(dx * dx + dy * dy);\n    dx /= radius;\n    dy /= radius;\n\n    var radian = Math.atan2(-dy, dx);\n\n    // Find the closest angle\n    // FIXME index can calculated directly\n    var minRadianDiff = Infinity;\n    var closestAxis;\n    var closestAxisIdx = -1;\n    for (var i = 0; i < this._indicatorAxes.length; i++) {\n        var indicatorAxis = this._indicatorAxes[i];\n        var diff = Math.abs(radian - indicatorAxis.angle);\n        if (diff < minRadianDiff) {\n            closestAxis = indicatorAxis;\n            closestAxisIdx = i;\n            minRadianDiff = diff;\n        }\n    }\n\n    return [closestAxisIdx, +(closestAxis && closestAxis.coodToData(radius))];\n};\n\nRadar.prototype.resize = function (radarModel, api) {\n    var center = radarModel.get('center');\n    var viewWidth = api.getWidth();\n    var viewHeight = api.getHeight();\n    var viewSize = Math.min(viewWidth, viewHeight) / 2;\n    this.cx = parsePercent$1(center[0], viewWidth);\n    this.cy = parsePercent$1(center[1], viewHeight);\n\n    this.startAngle = radarModel.get('startAngle') * Math.PI / 180;\n\n    // radius may be single value like `20`, `'80%'`, or array like `[10, '80%']`\n    var radius = radarModel.get('radius');\n    if (typeof radius === 'string' || typeof radius === 'number') {\n        radius = [0, radius];\n    }\n    this.r0 = parsePercent$1(radius[0], viewSize);\n    this.r = parsePercent$1(radius[1], viewSize);\n\n    each$1(this._indicatorAxes, function (indicatorAxis, idx) {\n        indicatorAxis.setExtent(this.r0, this.r);\n        var angle = (this.startAngle + idx * Math.PI * 2 / this._indicatorAxes.length);\n        // Normalize to [-PI, PI]\n        angle = Math.atan2(Math.sin(angle), Math.cos(angle));\n        indicatorAxis.angle = angle;\n    }, this);\n};\n\nRadar.prototype.update = function (ecModel, api) {\n    var indicatorAxes = this._indicatorAxes;\n    var radarModel = this._model;\n    each$1(indicatorAxes, function (indicatorAxis) {\n        indicatorAxis.scale.setExtent(Infinity, -Infinity);\n    });\n    ecModel.eachSeriesByType('radar', function (radarSeries, idx) {\n        if (radarSeries.get('coordinateSystem') !== 'radar'\n            || ecModel.getComponent('radar', radarSeries.get('radarIndex')) !== radarModel\n        ) {\n            return;\n        }\n        var data = radarSeries.getData();\n        each$1(indicatorAxes, function (indicatorAxis) {\n            indicatorAxis.scale.unionExtentFromData(data, data.mapDimension(indicatorAxis.dim));\n        });\n    }, this);\n\n    var splitNumber = radarModel.get('splitNumber');\n\n    function increaseInterval(interval) {\n        var exp10 = Math.pow(10, Math.floor(Math.log(interval) / Math.LN10));\n        // Increase interval\n        var f = interval / exp10;\n        if (f === 2) {\n            f = 5;\n        }\n        else { // f is 2 or 5\n            f *= 2;\n        }\n        return f * exp10;\n    }\n    // Force all the axis fixing the maxSplitNumber.\n    each$1(indicatorAxes, function (indicatorAxis, idx) {\n        var rawExtent = getScaleExtent(indicatorAxis.scale, indicatorAxis.model);\n        niceScaleExtent(indicatorAxis.scale, indicatorAxis.model);\n\n        var axisModel = indicatorAxis.model;\n        var scale = indicatorAxis.scale;\n        var fixedMin = axisModel.getMin();\n        var fixedMax = axisModel.getMax();\n        var interval = scale.getInterval();\n\n        if (fixedMin != null && fixedMax != null) {\n            // User set min, max, divide to get new interval\n            scale.setExtent(+fixedMin, +fixedMax);\n            scale.setInterval(\n                (fixedMax - fixedMin) / splitNumber\n            );\n        }\n        else if (fixedMin != null) {\n            var max;\n            // User set min, expand extent on the other side\n            do {\n                max = fixedMin + interval * splitNumber;\n                scale.setExtent(+fixedMin, max);\n                // Interval must been set after extent\n                // FIXME\n                scale.setInterval(interval);\n\n                interval = increaseInterval(interval);\n            } while (max < rawExtent[1] && isFinite(max) && isFinite(rawExtent[1]));\n        }\n        else if (fixedMax != null) {\n            var min;\n            // User set min, expand extent on the other side\n            do {\n                min = fixedMax - interval * splitNumber;\n                scale.setExtent(min, +fixedMax);\n                scale.setInterval(interval);\n                interval = increaseInterval(interval);\n            } while (min > rawExtent[0] && isFinite(min) && isFinite(rawExtent[0]));\n        }\n        else {\n            var nicedSplitNumber = scale.getTicks().length - 1;\n            if (nicedSplitNumber > splitNumber) {\n                interval = increaseInterval(interval);\n            }\n            // PENDING\n            var center = Math.round((rawExtent[0] + rawExtent[1]) / 2 / interval) * interval;\n            var halfSplitNumber = Math.round(splitNumber / 2);\n            scale.setExtent(\n                round$2(center - halfSplitNumber * interval),\n                round$2(center + (splitNumber - halfSplitNumber) * interval)\n            );\n            scale.setInterval(interval);\n        }\n    });\n};\n\n/**\n * Radar dimensions is based on the data\n * @type {Array}\n */\nRadar.dimensions = [];\n\nRadar.create = function (ecModel, api) {\n    var radarList = [];\n    ecModel.eachComponent('radar', function (radarModel) {\n        var radar = new Radar(radarModel, ecModel, api);\n        radarList.push(radar);\n        radarModel.coordinateSystem = radar;\n    });\n    ecModel.eachSeriesByType('radar', function (radarSeries) {\n        if (radarSeries.get('coordinateSystem') === 'radar') {\n            // Inject coordinate system\n            radarSeries.coordinateSystem = radarList[radarSeries.get('radarIndex') || 0];\n        }\n    });\n    return radarList;\n};\n\nCoordinateSystemManager.register('radar', Radar);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar valueAxisDefault = axisDefault.valueAxis;\n\nfunction defaultsShow(opt, show) {\n    return defaults({\n        show: show\n    }, opt);\n}\n\nvar RadarModel = extendComponentModel({\n\n    type: 'radar',\n\n    optionUpdated: function () {\n        var boundaryGap = this.get('boundaryGap');\n        var splitNumber = this.get('splitNumber');\n        var scale = this.get('scale');\n        var axisLine = this.get('axisLine');\n        var axisTick = this.get('axisTick');\n        var axisLabel = this.get('axisLabel');\n        var nameTextStyle = this.get('name');\n        var showName = this.get('name.show');\n        var nameFormatter = this.get('name.formatter');\n        var nameGap = this.get('nameGap');\n        var triggerEvent = this.get('triggerEvent');\n\n        var indicatorModels = map(this.get('indicator') || [], function (indicatorOpt) {\n            // PENDING\n            if (indicatorOpt.max != null && indicatorOpt.max > 0 && !indicatorOpt.min) {\n                indicatorOpt.min = 0;\n            }\n            else if (indicatorOpt.min != null && indicatorOpt.min < 0 && !indicatorOpt.max) {\n                indicatorOpt.max = 0;\n            }\n            var iNameTextStyle = nameTextStyle;\n            if (indicatorOpt.color != null) {\n                iNameTextStyle = defaults({color: indicatorOpt.color}, nameTextStyle);\n            }\n            // Use same configuration\n            indicatorOpt = merge(clone(indicatorOpt), {\n                boundaryGap: boundaryGap,\n                splitNumber: splitNumber,\n                scale: scale,\n                axisLine: axisLine,\n                axisTick: axisTick,\n                axisLabel: axisLabel,\n                // Competitable with 2 and use text\n                name: indicatorOpt.text,\n                nameLocation: 'end',\n                nameGap: nameGap,\n                // min: 0,\n                nameTextStyle: iNameTextStyle,\n                triggerEvent: triggerEvent\n            }, false);\n            if (!showName) {\n                indicatorOpt.name = '';\n            }\n            if (typeof nameFormatter === 'string') {\n                var indName = indicatorOpt.name;\n                indicatorOpt.name = nameFormatter.replace('{value}', indName != null ? indName : '');\n            }\n            else if (typeof nameFormatter === 'function') {\n                indicatorOpt.name = nameFormatter(\n                    indicatorOpt.name, indicatorOpt\n                );\n            }\n            var model = extend(\n                new Model(indicatorOpt, null, this.ecModel),\n                axisModelCommonMixin\n            );\n\n            // For triggerEvent.\n            model.mainType = 'radar';\n            model.componentIndex = this.componentIndex;\n\n            return model;\n        }, this);\n\n        this.getIndicatorModels = function () {\n            return indicatorModels;\n        };\n    },\n\n    defaultOption: {\n\n        zlevel: 0,\n\n        z: 0,\n\n        center: ['50%', '50%'],\n\n        radius: '75%',\n\n        startAngle: 90,\n\n        name: {\n            show: true\n            // formatter: null\n            // textStyle: {}\n        },\n\n        boundaryGap: [0, 0],\n\n        splitNumber: 5,\n\n        nameGap: 15,\n\n        scale: false,\n\n        // Polygon or circle\n        shape: 'polygon',\n\n        axisLine: merge(\n            {\n                lineStyle: {\n                    color: '#bbb'\n                }\n            },\n            valueAxisDefault.axisLine\n        ),\n        axisLabel: defaultsShow(valueAxisDefault.axisLabel, false),\n        axisTick: defaultsShow(valueAxisDefault.axisTick, false),\n        splitLine: defaultsShow(valueAxisDefault.splitLine, true),\n        splitArea: defaultsShow(valueAxisDefault.splitArea, true),\n\n        // {text, min, max}\n        indicator: []\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar axisBuilderAttrs$1 = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\n\nextendComponentView({\n\n    type: 'radar',\n\n    render: function (radarModel, ecModel, api) {\n        var group = this.group;\n        group.removeAll();\n\n        this._buildAxes(radarModel);\n        this._buildSplitLineAndArea(radarModel);\n    },\n\n    _buildAxes: function (radarModel) {\n        var radar = radarModel.coordinateSystem;\n        var indicatorAxes = radar.getIndicatorAxes();\n        var axisBuilders = map(indicatorAxes, function (indicatorAxis) {\n            var axisBuilder = new AxisBuilder(indicatorAxis.model, {\n                position: [radar.cx, radar.cy],\n                rotation: indicatorAxis.angle,\n                labelDirection: -1,\n                tickDirection: -1,\n                nameDirection: 1\n            });\n            return axisBuilder;\n        });\n\n        each$1(axisBuilders, function (axisBuilder) {\n            each$1(axisBuilderAttrs$1, axisBuilder.add, axisBuilder);\n            this.group.add(axisBuilder.getGroup());\n        }, this);\n    },\n\n    _buildSplitLineAndArea: function (radarModel) {\n        var radar = radarModel.coordinateSystem;\n        var indicatorAxes = radar.getIndicatorAxes();\n        if (!indicatorAxes.length) {\n            return;\n        }\n        var shape = radarModel.get('shape');\n        var splitLineModel = radarModel.getModel('splitLine');\n        var splitAreaModel = radarModel.getModel('splitArea');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n\n        var showSplitLine = splitLineModel.get('show');\n        var showSplitArea = splitAreaModel.get('show');\n        var splitLineColors = lineStyleModel.get('color');\n        var splitAreaColors = areaStyleModel.get('color');\n\n        splitLineColors = isArray(splitLineColors) ? splitLineColors : [splitLineColors];\n        splitAreaColors = isArray(splitAreaColors) ? splitAreaColors : [splitAreaColors];\n\n        var splitLines = [];\n        var splitAreas = [];\n\n        function getColorIndex(areaOrLine, areaOrLineColorList, idx) {\n            var colorIndex = idx % areaOrLineColorList.length;\n            areaOrLine[colorIndex] = areaOrLine[colorIndex] || [];\n            return colorIndex;\n        }\n\n        if (shape === 'circle') {\n            var ticksRadius = indicatorAxes[0].getTicksCoords();\n            var cx = radar.cx;\n            var cy = radar.cy;\n            for (var i = 0; i < ticksRadius.length; i++) {\n                if (showSplitLine) {\n                    var colorIndex = getColorIndex(splitLines, splitLineColors, i);\n                    splitLines[colorIndex].push(new Circle({\n                        shape: {\n                            cx: cx,\n                            cy: cy,\n                            r: ticksRadius[i].coord\n                        }\n                    }));\n                }\n                if (showSplitArea && i < ticksRadius.length - 1) {\n                    var colorIndex = getColorIndex(splitAreas, splitAreaColors, i);\n                    splitAreas[colorIndex].push(new Ring({\n                        shape: {\n                            cx: cx,\n                            cy: cy,\n                            r0: ticksRadius[i].coord,\n                            r: ticksRadius[i + 1].coord\n                        }\n                    }));\n                }\n            }\n        }\n        // Polyyon\n        else {\n            var realSplitNumber;\n            var axesTicksPoints = map(indicatorAxes, function (indicatorAxis, idx) {\n                var ticksCoords = indicatorAxis.getTicksCoords();\n                realSplitNumber = realSplitNumber == null\n                    ? ticksCoords.length - 1\n                    : Math.min(ticksCoords.length - 1, realSplitNumber);\n                return map(ticksCoords, function (tickCoord) {\n                    return radar.coordToPoint(tickCoord.coord, idx);\n                });\n            });\n\n            var prevPoints = [];\n            for (var i = 0; i <= realSplitNumber; i++) {\n                var points = [];\n                for (var j = 0; j < indicatorAxes.length; j++) {\n                    points.push(axesTicksPoints[j][i]);\n                }\n                // Close\n                if (points[0]) {\n                    points.push(points[0].slice());\n                }\n                else {\n                    if (__DEV__) {\n                        console.error('Can\\'t draw value axis ' + i);\n                    }\n                }\n\n                if (showSplitLine) {\n                    var colorIndex = getColorIndex(splitLines, splitLineColors, i);\n                    splitLines[colorIndex].push(new Polyline({\n                        shape: {\n                            points: points\n                        }\n                    }));\n                }\n                if (showSplitArea && prevPoints) {\n                    var colorIndex = getColorIndex(splitAreas, splitAreaColors, i - 1);\n                    splitAreas[colorIndex].push(new Polygon({\n                        shape: {\n                            points: points.concat(prevPoints)\n                        }\n                    }));\n                }\n                prevPoints = points.slice().reverse();\n            }\n        }\n\n        var lineStyle = lineStyleModel.getLineStyle();\n        var areaStyle = areaStyleModel.getAreaStyle();\n        // Add splitArea before splitLine\n        each$1(splitAreas, function (splitAreas, idx) {\n            this.group.add(mergePath(\n                splitAreas, {\n                    style: defaults({\n                        stroke: 'none',\n                        fill: splitAreaColors[idx % splitAreaColors.length]\n                    }, areaStyle),\n                    silent: true\n                }\n            ));\n        }, this);\n\n        each$1(splitLines, function (splitLines, idx) {\n            this.group.add(mergePath(\n                splitLines, {\n                    style: defaults({\n                        fill: 'none',\n                        stroke: splitLineColors[idx % splitLineColors.length]\n                    }, lineStyle),\n                    silent: true\n                }\n            ));\n        }, this);\n\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar RadarSeries = SeriesModel.extend({\n\n    type: 'series.radar',\n\n    dependencies: ['radar'],\n\n\n    // Overwrite\n    init: function (option) {\n        RadarSeries.superApply(this, 'init', arguments);\n\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n    },\n\n    getInitialData: function (option, ecModel) {\n        return createListSimply(this, {\n            generateCoord: 'indicator_',\n            generateCoordCount: Infinity\n        });\n    },\n\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var coordSys = this.coordinateSystem;\n        var indicatorAxes = coordSys.getIndicatorAxes();\n        var name = this.getData().getName(dataIndex);\n        return encodeHTML(name === '' ? this.name : name) + '<br/>'\n            + map(indicatorAxes, function (axis, idx) {\n                var val = data.get(data.mapDimension(axis.dim), dataIndex);\n                return encodeHTML(axis.name + ' : ' + val);\n            }).join('<br />');\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'radar',\n        legendHoverLink: true,\n        radarIndex: 0,\n        lineStyle: {\n            width: 2,\n            type: 'solid'\n        },\n        label: {\n            position: 'top'\n        },\n        // areaStyle: {\n        // },\n        // itemStyle: {}\n        symbol: 'emptyCircle',\n        symbolSize: 4\n        // symbolRotate: null\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction normalizeSymbolSize(symbolSize) {\n    if (!isArray(symbolSize)) {\n        symbolSize = [+symbolSize, +symbolSize];\n    }\n    return symbolSize;\n}\n\nextendChartView({\n\n    type: 'radar',\n\n    render: function (seriesModel, ecModel, api) {\n        var polar = seriesModel.coordinateSystem;\n        var group = this.group;\n\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        function createSymbol$$1(data, idx) {\n            var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';\n            var color = data.getItemVisual(idx, 'color');\n            if (symbolType === 'none') {\n                return;\n            }\n            var symbolSize = normalizeSymbolSize(\n                data.getItemVisual(idx, 'symbolSize')\n            );\n            var symbolPath = createSymbol(\n                symbolType, -1, -1, 2, 2, color\n            );\n            symbolPath.attr({\n                style: {\n                    strokeNoScale: true\n                },\n                z2: 100,\n                scale: [symbolSize[0] / 2, symbolSize[1] / 2]\n            });\n            return symbolPath;\n        }\n\n        function updateSymbols(oldPoints, newPoints, symbolGroup, data, idx, isInit) {\n            // Simply rerender all\n            symbolGroup.removeAll();\n            for (var i = 0; i < newPoints.length - 1; i++) {\n                var symbolPath = createSymbol$$1(data, idx);\n                if (symbolPath) {\n                    symbolPath.__dimIdx = i;\n                    if (oldPoints[i]) {\n                        symbolPath.attr('position', oldPoints[i]);\n                        graphic[isInit ? 'initProps' : 'updateProps'](\n                            symbolPath, {\n                                position: newPoints[i]\n                            }, seriesModel, idx\n                        );\n                    }\n                    else {\n                        symbolPath.attr('position', newPoints[i]);\n                    }\n                    symbolGroup.add(symbolPath);\n                }\n            }\n        }\n\n        function getInitialPoints(points) {\n            return map(points, function (pt) {\n                return [polar.cx, polar.cy];\n            });\n        }\n        data.diff(oldData)\n            .add(function (idx) {\n                var points = data.getItemLayout(idx);\n                if (!points) {\n                    return;\n                }\n                var polygon = new Polygon();\n                var polyline = new Polyline();\n                var target = {\n                    shape: {\n                        points: points\n                    }\n                };\n                polygon.shape.points = getInitialPoints(points);\n                polyline.shape.points = getInitialPoints(points);\n                initProps(polygon, target, seriesModel, idx);\n                initProps(polyline, target, seriesModel, idx);\n\n                var itemGroup = new Group();\n                var symbolGroup = new Group();\n                itemGroup.add(polyline);\n                itemGroup.add(polygon);\n                itemGroup.add(symbolGroup);\n\n                updateSymbols(\n                    polyline.shape.points, points, symbolGroup, data, idx, true\n                );\n\n                data.setItemGraphicEl(idx, itemGroup);\n            })\n            .update(function (newIdx, oldIdx) {\n                var itemGroup = oldData.getItemGraphicEl(oldIdx);\n                var polyline = itemGroup.childAt(0);\n                var polygon = itemGroup.childAt(1);\n                var symbolGroup = itemGroup.childAt(2);\n                var target = {\n                    shape: {\n                        points: data.getItemLayout(newIdx)\n                    }\n                };\n                if (!target.shape.points) {\n                    return;\n                }\n                updateSymbols(\n                    polyline.shape.points, target.shape.points, symbolGroup, data, newIdx, false\n                );\n\n                updateProps(polyline, target, seriesModel);\n                updateProps(polygon, target, seriesModel);\n\n                data.setItemGraphicEl(newIdx, itemGroup);\n            })\n            .remove(function (idx) {\n                group.remove(oldData.getItemGraphicEl(idx));\n            })\n            .execute();\n\n        data.eachItemGraphicEl(function (itemGroup, idx) {\n            var itemModel = data.getItemModel(idx);\n            var polyline = itemGroup.childAt(0);\n            var polygon = itemGroup.childAt(1);\n            var symbolGroup = itemGroup.childAt(2);\n            var color = data.getItemVisual(idx, 'color');\n\n            group.add(itemGroup);\n\n            polyline.useStyle(\n                defaults(\n                    itemModel.getModel('lineStyle').getLineStyle(),\n                    {\n                        fill: 'none',\n                        stroke: color\n                    }\n                )\n            );\n            polyline.hoverStyle = itemModel.getModel('emphasis.lineStyle').getLineStyle();\n\n            var areaStyleModel = itemModel.getModel('areaStyle');\n            var hoverAreaStyleModel = itemModel.getModel('emphasis.areaStyle');\n            var polygonIgnore = areaStyleModel.isEmpty() && areaStyleModel.parentModel.isEmpty();\n            var hoverPolygonIgnore = hoverAreaStyleModel.isEmpty() && hoverAreaStyleModel.parentModel.isEmpty();\n\n            hoverPolygonIgnore = hoverPolygonIgnore && polygonIgnore;\n            polygon.ignore = polygonIgnore;\n\n            polygon.useStyle(\n                defaults(\n                    areaStyleModel.getAreaStyle(),\n                    {\n                        fill: color,\n                        opacity: 0.7\n                    }\n                )\n            );\n            polygon.hoverStyle = hoverAreaStyleModel.getAreaStyle();\n\n            var itemStyle = itemModel.getModel('itemStyle').getItemStyle(['color']);\n            var itemHoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n            var labelModel = itemModel.getModel('label');\n            var labelHoverModel = itemModel.getModel('emphasis.label');\n            symbolGroup.eachChild(function (symbolPath) {\n                symbolPath.setStyle(itemStyle);\n                symbolPath.hoverStyle = clone(itemHoverStyle);\n\n                setLabelStyle(\n                    symbolPath.style, symbolPath.hoverStyle, labelModel, labelHoverModel,\n                    {\n                        labelFetcher: data.hostModel,\n                        labelDataIndex: idx,\n                        labelDimIndex: symbolPath.__dimIdx,\n                        defaultText: data.get(data.dimensions[symbolPath.__dimIdx], idx),\n                        autoColor: color,\n                        isRectText: true\n                    }\n                );\n            });\n\n            function onEmphasis() {\n                polygon.attr('ignore', hoverPolygonIgnore);\n            }\n\n            function onNormal() {\n                polygon.attr('ignore', polygonIgnore);\n            }\n\n            itemGroup.off('mouseover').off('mouseout').off('normal').off('emphasis');\n            itemGroup.on('emphasis', onEmphasis)\n                .on('mouseover', onEmphasis)\n                .on('normal', onNormal)\n                .on('mouseout', onNormal);\n\n            setHoverStyle(itemGroup);\n        });\n\n        this._data = data;\n    },\n\n    remove: function () {\n        this.group.removeAll();\n        this._data = null;\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar radarLayout = function (ecModel) {\n    ecModel.eachSeriesByType('radar', function (seriesModel) {\n        var data = seriesModel.getData();\n        var points = [];\n        var coordSys = seriesModel.coordinateSystem;\n        if (!coordSys) {\n            return;\n        }\n\n        function pointsConverter(val, idx) {\n            points[idx] = points[idx] || [];\n            points[idx][i] = coordSys.dataToPoint(val, i);\n        }\n        var axes = coordSys.getIndicatorAxes();\n        for (var i = 0; i < axes.length; i++) {\n            data.each(data.mapDimension(axes[i].dim), pointsConverter);\n        }\n\n        data.each(function (idx) {\n            // Close polygon\n            points[idx][0] && points[idx].push(points[idx][0].slice());\n            data.setItemLayout(idx, points[idx]);\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Backward compat for radar chart in 2\nvar backwardCompat$1 = function (option) {\n    var polarOptArr = option.polar;\n    if (polarOptArr) {\n        if (!isArray(polarOptArr)) {\n            polarOptArr = [polarOptArr];\n        }\n        var polarNotRadar = [];\n        each$1(polarOptArr, function (polarOpt, idx) {\n            if (polarOpt.indicator) {\n                if (polarOpt.type && !polarOpt.shape) {\n                    polarOpt.shape = polarOpt.type;\n                }\n                option.radar = option.radar || [];\n                if (!isArray(option.radar)) {\n                    option.radar = [option.radar];\n                }\n                option.radar.push(polarOpt);\n            }\n            else {\n                polarNotRadar.push(polarOpt);\n            }\n        });\n        option.polar = polarNotRadar;\n    }\n    each$1(option.series, function (seriesOpt) {\n        if (seriesOpt && seriesOpt.type === 'radar' && seriesOpt.polarIndex) {\n            seriesOpt.radarIndex = seriesOpt.polarIndex;\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n// Must use radar component\nregisterVisual(dataColor('radar'));\nregisterVisual(visualSymbol('radar', 'circle'));\nregisterLayout(radarLayout);\nregisterProcessor(dataFilter('radar'));\nregisterPreprocessor(backwardCompat$1);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Fix for 南海诸岛\n\nvar geoCoord = [126, 25];\n\nvar points$1 = [\n    [[0, 3.5], [7, 11.2], [15, 11.9], [30, 7], [42, 0.7], [52, 0.7],\n        [56, 7.7], [59, 0.7], [64, 0.7], [64, 0], [5, 0], [0, 3.5]],\n    [[13, 16.1], [19, 14.7], [16, 21.7], [11, 23.1], [13, 16.1]],\n    [[12, 32.2], [14, 38.5], [15, 38.5], [13, 32.2], [12, 32.2]],\n    [[16, 47.6], [12, 53.2], [13, 53.2], [18, 47.6], [16, 47.6]],\n    [[6, 64.4], [8, 70], [9, 70], [8, 64.4], [6, 64.4]],\n    [[23, 82.6], [29, 79.8], [30, 79.8], [25, 82.6], [23, 82.6]],\n    [[37, 70.7], [43, 62.3], [44, 62.3], [39, 70.7], [37, 70.7]],\n    [[48, 51.1], [51, 45.5], [53, 45.5], [50, 51.1], [48, 51.1]],\n    [[51, 35], [51, 28.7], [53, 28.7], [53, 35], [51, 35]],\n    [[52, 22.4], [55, 17.5], [56, 17.5], [53, 22.4], [52, 22.4]],\n    [[58, 12.6], [62, 7], [63, 7], [60, 12.6], [58, 12.6]],\n    [[0, 3.5], [0, 93.1], [64, 93.1], [64, 0], [63, 0], [63, 92.4],\n        [1, 92.4], [1, 3.5], [0, 3.5]]\n];\n\nfor (var i$1 = 0; i$1 < points$1.length; i$1++) {\n    for (var k = 0; k < points$1[i$1].length; k++) {\n        points$1[i$1][k][0] /= 10.5;\n        points$1[i$1][k][1] /= -10.5 / 0.75;\n\n        points$1[i$1][k][0] += geoCoord[0];\n        points$1[i$1][k][1] += geoCoord[1];\n    }\n}\n\nvar fixNanhai = function (mapType, regions) {\n    if (mapType === 'china') {\n        regions.push(new Region(\n            '南海诸岛',\n            map(points$1, function (exterior) {\n                return {\n                    type: 'polygon',\n                    exterior: exterior\n                };\n            }), geoCoord\n        ));\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar coordsOffsetMap = {\n    '南海诸岛': [32, 80],\n    // 全国\n    '广东': [0, -10],\n    '香港': [10, 5],\n    '澳门': [-10, 10],\n    //'北京': [-10, 0],\n    '天津': [5, 5]\n};\n\nvar fixTextCoord = function (mapType, region) {\n    if (mapType === 'china') {\n        var coordFix = coordsOffsetMap[region.name];\n        if (coordFix) {\n            var cp = region.center;\n            cp[0] += coordFix[0] / 10.5;\n            cp[1] += -coordFix[1] / (10.5 / 0.75);\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar geoCoordMap = {\n    'Russia': [100, 60],\n    'United States': [-99, 38],\n    'United States of America': [-99, 38]\n};\n\nvar fixGeoCoord = function (mapType, region) {\n    if (mapType === 'world') {\n        var geoCoord = geoCoordMap[region.name];\n        if (geoCoord) {\n            var cp = region.center;\n            cp[0] = geoCoord[0];\n            cp[1] = geoCoord[1];\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Fix for 钓鱼岛\n\n// var Region = require('../Region');\n// var zrUtil = require('zrender/src/core/util');\n\n// var geoCoord = [126, 25];\n\nvar points$2 = [\n    [\n        [123.45165252685547, 25.73527164402261],\n        [123.49731445312499, 25.73527164402261],\n        [123.49731445312499, 25.750734064600884],\n        [123.45165252685547, 25.750734064600884],\n        [123.45165252685547, 25.73527164402261]\n    ]\n];\n\nvar fixDiaoyuIsland = function (mapType, region) {\n    if (mapType === 'china' && region.name === '台湾') {\n        region.geometries.push({\n            type: 'polygon',\n            exterior: points$2[0]\n        });\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Built-in GEO fixer.\nvar inner$7 = makeInner();\n\nvar geoJSONLoader = {\n\n    /**\n     * @param {string} mapName\n     * @param {Object} mapRecord {specialAreas, geoJSON}\n     * @return {Object} {regions, boundingRect}\n     */\n    load: function (mapName, mapRecord) {\n\n        var parsed = inner$7(mapRecord).parsed;\n\n        if (parsed) {\n            return parsed;\n        }\n\n        var specialAreas = mapRecord.specialAreas || {};\n        var geoJSON = mapRecord.geoJSON;\n        var regions;\n\n        // https://jsperf.com/try-catch-performance-overhead\n        try {\n            regions = geoJSON ? parseGeoJson$1(geoJSON) : [];\n        }\n        catch (e) {\n            throw new Error('Invalid geoJson format\\n' + e.message);\n        }\n\n        each$1(regions, function (region) {\n            var regionName = region.name;\n\n            fixTextCoord(mapName, region);\n            fixGeoCoord(mapName, region);\n            fixDiaoyuIsland(mapName, region);\n\n            // Some area like Alaska in USA map needs to be tansformed\n            // to look better\n            var specialArea = specialAreas[regionName];\n            if (specialArea) {\n                region.transformTo(\n                    specialArea.left, specialArea.top, specialArea.width, specialArea.height\n                );\n            }\n        });\n\n        fixNanhai(mapName, regions);\n\n        return (inner$7(mapRecord).parsed = {\n            regions: regions,\n            boundingRect: getBoundingRect$1(regions)\n        });\n    }\n};\n\nfunction getBoundingRect$1(regions) {\n    var rect;\n    for (var i = 0; i < regions.length; i++) {\n        var regionRect = regions[i].getBoundingRect();\n        rect = rect || regionRect.clone();\n        rect.union(regionRect);\n    }\n    return rect;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$8 = makeInner();\n\nvar geoSVGLoader = {\n\n    /**\n     * @param {string} mapName\n     * @param {Object} mapRecord {specialAreas, geoJSON}\n     * @return {Object} {root, boundingRect}\n     */\n    load: function (mapName, mapRecord) {\n        var originRoot = inner$8(mapRecord).originRoot;\n        if (originRoot) {\n            return {\n                root: originRoot,\n                boundingRect: inner$8(mapRecord).boundingRect\n            };\n        }\n\n        var graphic = buildGraphic(mapRecord);\n\n        inner$8(mapRecord).originRoot = graphic.root;\n        inner$8(mapRecord).boundingRect = graphic.boundingRect;\n\n        return graphic;\n    },\n\n    makeGraphic: function (mapName, mapRecord, hostKey) {\n        // For performance consideration (in large SVG), graphic only maked\n        // when necessary and reuse them according to hostKey.\n        var field = inner$8(mapRecord);\n        var rootMap = field.rootMap || (field.rootMap = createHashMap());\n\n        var root = rootMap.get(hostKey);\n        if (root) {\n            return root;\n        }\n\n        var originRoot = field.originRoot;\n        var boundingRect = field.boundingRect;\n\n        // For performance, if originRoot is not used by a view,\n        // assign it to a view, but not reproduce graphic elements.\n        if (!field.originRootHostKey) {\n            field.originRootHostKey = hostKey;\n            root = originRoot;\n        }\n        else {\n            root = buildGraphic(mapRecord, boundingRect).root;\n        }\n\n        return rootMap.set(hostKey, root);\n    },\n\n    removeGraphic: function (mapName, mapRecord, hostKey) {\n        var field = inner$8(mapRecord);\n        var rootMap = field.rootMap;\n        rootMap && rootMap.removeKey(hostKey);\n        if (hostKey === field.originRootHostKey) {\n            field.originRootHostKey = null;\n        }\n    }\n};\n\nfunction buildGraphic(mapRecord, boundingRect) {\n    var svgXML = mapRecord.svgXML;\n    var result;\n    var root;\n\n    try {\n        result = svgXML && parseSVG(svgXML, {\n            ignoreViewBox: true,\n            ignoreRootClip: true\n        }) || {};\n        root = result.root;\n        assert$1(root != null);\n    }\n    catch (e) {\n        throw new Error('Invalid svg format\\n' + e.message);\n    }\n\n    var svgWidth = result.width;\n    var svgHeight = result.height;\n    var viewBoxRect = result.viewBoxRect;\n\n    if (!boundingRect) {\n        boundingRect = (svgWidth == null || svgHeight == null)\n            // If svg width / height not specified, calculate\n            // bounding rect as the width / height\n            ? root.getBoundingRect()\n            : new BoundingRect(0, 0, 0, 0);\n\n        if (svgWidth != null) {\n            boundingRect.width = svgWidth;\n        }\n        if (svgHeight != null) {\n            boundingRect.height = svgHeight;\n        }\n    }\n\n    if (viewBoxRect) {\n        var viewBoxTransform = makeViewBoxTransform(viewBoxRect, boundingRect.width, boundingRect.height);\n        var elRoot = root;\n        root = new Group();\n        root.add(elRoot);\n        elRoot.scale = viewBoxTransform.scale;\n        elRoot.position = viewBoxTransform.position;\n    }\n\n    root.setClipPath(new Rect({\n        shape: boundingRect.plain()\n    }));\n\n    return {\n        root: root,\n        boundingRect: boundingRect\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar loaders = {\n    geoJSON: geoJSONLoader,\n    svg: geoSVGLoader\n};\n\nvar geoSourceManager = {\n\n    /**\n     * @param {string} mapName\n     * @param {Object} nameMap\n     * @return {Object} source {regions, regionsMap, nameCoordMap, boundingRect}\n     */\n    load: function (mapName, nameMap) {\n        var regions = [];\n        var regionsMap = createHashMap();\n        var nameCoordMap = createHashMap();\n        var boundingRect;\n        var mapRecords = retrieveMap(mapName);\n\n        each$1(mapRecords, function (record) {\n            var singleSource = loaders[record.type].load(mapName, record);\n\n            each$1(singleSource.regions, function (region) {\n                var regionName = region.name;\n\n                // Try use the alias in geoNameMap\n                if (nameMap && nameMap.hasOwnProperty(regionName)) {\n                    region = region.cloneShallow(regionName = nameMap[regionName]);\n                }\n\n                regions.push(region);\n                regionsMap.set(regionName, region);\n                nameCoordMap.set(regionName, region.center);\n            });\n\n            var rect = singleSource.boundingRect;\n            if (rect) {\n                boundingRect\n                    ? boundingRect.union(rect)\n                    : (boundingRect = rect.clone());\n            }\n        });\n\n        return {\n            regions: regions,\n            regionsMap: regionsMap,\n            nameCoordMap: nameCoordMap,\n            // FIXME Always return new ?\n            boundingRect: boundingRect || new BoundingRect(0, 0, 0, 0)\n        };\n    },\n\n    /**\n     * @param {string} mapName\n     * @param {string} hostKey For cache.\n     * @return {Array.<module:zrender/Element>} Roots.\n     */\n    makeGraphic: makeInvoker('makeGraphic'),\n\n    /**\n     * @param {string} mapName\n     * @param {string} hostKey For cache.\n     */\n    removeGraphic: makeInvoker('removeGraphic')\n};\n\nfunction makeInvoker(methodName) {\n    return function (mapName, hostKey) {\n        var mapRecords = retrieveMap(mapName);\n        var results = [];\n\n        each$1(mapRecords, function (record) {\n            var method = loaders[record.type][methodName];\n            method && results.push(method(mapName, record, hostKey));\n        });\n\n        return results;\n    };\n}\n\nfunction mapNotExistsError(mapName) {\n    if (__DEV__) {\n        console.error(\n            'Map ' + mapName + ' not exists. You can download map file on http://echarts.baidu.com/download-map.html'\n        );\n    }\n}\n\nfunction retrieveMap(mapName) {\n    var mapRecords = mapDataStorage.retrieveMap(mapName) || [];\n\n    if (__DEV__) {\n        if (!mapRecords.length) {\n            mapNotExistsError(mapName);\n        }\n    }\n\n    return mapRecords;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar MapSeries = SeriesModel.extend({\n\n    type: 'series.map',\n\n    dependencies: ['geo'],\n\n    layoutMode: 'box',\n\n    /**\n     * Only first map series of same mapType will drawMap\n     * @type {boolean}\n     */\n    needsDrawMap: false,\n\n    /**\n     * Group of all map series with same mapType\n     * @type {boolean}\n     */\n    seriesGroup: [],\n\n    getInitialData: function (option) {\n        var data = createListSimply(this, ['value']);\n        var valueDim = data.mapDimension('value');\n        var dataNameMap = createHashMap();\n        var selectTargetList = [];\n        var toAppendNames = [];\n\n        for (var i = 0, len = data.count(); i < len; i++) {\n            var name = data.getName(i);\n            dataNameMap.set(name, true);\n            selectTargetList.push({\n                name: name,\n                value: data.get(valueDim, i),\n                selected: retrieveRawAttr(data, i, 'selected')\n            });\n        }\n\n        var geoSource = geoSourceManager.load(this.getMapType(), this.option.nameMap);\n        each$1(geoSource.regions, function (region) {\n            var name = region.name;\n            if (!dataNameMap.get(name)) {\n                selectTargetList.push({name: name});\n                toAppendNames.push(name);\n            }\n        });\n\n        this.updateSelectedMap(selectTargetList);\n\n        // Complete data with missing regions. The consequent processes (like visual\n        // map and render) can not be performed without a \"full data\". For example,\n        // find `dataIndex` by name.\n        data.appendValues([], toAppendNames);\n\n        return data;\n    },\n\n    /**\n     * If no host geo model, return null, which means using a\n     * inner exclusive geo model.\n     */\n    getHostGeoModel: function () {\n        var geoIndex = this.option.geoIndex;\n        return geoIndex != null\n            ? this.dependentModels.geo[geoIndex]\n            : null;\n    },\n\n    getMapType: function () {\n        return (this.getHostGeoModel() || this).option.map;\n    },\n\n    // _fillOption: function (option, mapName) {\n        // Shallow clone\n        // option = zrUtil.extend({}, option);\n\n        // option.data = geoCreator.getFilledRegions(option.data, mapName, option.nameMap);\n\n        // return option;\n    // },\n\n    getRawValue: function (dataIndex) {\n        // Use value stored in data instead because it is calculated from multiple series\n        // FIXME Provide all value of multiple series ?\n        var data = this.getData();\n        return data.get(data.mapDimension('value'), dataIndex);\n    },\n\n    /**\n     * Get model of region\n     * @param  {string} name\n     * @return {module:echarts/model/Model}\n     */\n    getRegionModel: function (regionName) {\n        var data = this.getData();\n        return data.getItemModel(data.indexOfName(regionName));\n    },\n\n    /**\n     * Map tooltip formatter\n     *\n     * @param {number} dataIndex\n     */\n    formatTooltip: function (dataIndex) {\n        // FIXME orignalData and data is a bit confusing\n        var data = this.getData();\n        var formattedValue = addCommas(this.getRawValue(dataIndex));\n        var name = data.getName(dataIndex);\n\n        var seriesGroup = this.seriesGroup;\n        var seriesNames = [];\n        for (var i = 0; i < seriesGroup.length; i++) {\n            var otherIndex = seriesGroup[i].originalData.indexOfName(name);\n            var valueDim = data.mapDimension('value');\n            if (!isNaN(seriesGroup[i].originalData.get(valueDim, otherIndex))) {\n                seriesNames.push(\n                    encodeHTML(seriesGroup[i].name)\n                );\n            }\n        }\n\n        return seriesNames.join(', ') + '<br />'\n            + encodeHTML(name + ' : ' + formattedValue);\n    },\n\n    /**\n     * @implement\n     */\n    getTooltipPosition: function (dataIndex) {\n        if (dataIndex != null) {\n            var name = this.getData().getName(dataIndex);\n            var geo = this.coordinateSystem;\n            var region = geo.getRegion(name);\n\n            return region && geo.dataToPoint(region.center);\n        }\n    },\n\n    setZoom: function (zoom) {\n        this.option.zoom = zoom;\n    },\n\n    setCenter: function (center) {\n        this.option.center = center;\n    },\n\n    defaultOption: {\n        // 一级层叠\n        zlevel: 0,\n        // 二级层叠\n        z: 2,\n\n        coordinateSystem: 'geo',\n\n        // map should be explicitly specified since ec3.\n        map: '',\n\n        // If `geoIndex` is not specified, a exclusive geo will be\n        // created. Otherwise use the specified geo component, and\n        // `map` and `mapType` are ignored.\n        // geoIndex: 0,\n\n        // 'center' | 'left' | 'right' | 'x%' | {number}\n        left: 'center',\n        // 'center' | 'top' | 'bottom' | 'x%' | {number}\n        top: 'center',\n        // right\n        // bottom\n        // width:\n        // height\n\n        // Aspect is width / height. Inited to be geoJson bbox aspect\n        // This parameter is used for scale this aspect\n        aspectScale: 0.75,\n\n        ///// Layout with center and size\n        // If you wan't to put map in a fixed size box with right aspect ratio\n        // This two properties may more conveninet\n        // layoutCenter: [50%, 50%]\n        // layoutSize: 100\n\n\n        // 数值合并方式，默认加和，可选为：\n        // 'sum' | 'average' | 'max' | 'min'\n        // mapValueCalculation: 'sum',\n        // 地图数值计算结果小数精度\n        // mapValuePrecision: 0,\n\n\n        // 显示图例颜色标识（系列标识的小圆点），图例开启时有效\n        showLegendSymbol: true,\n        // 选择模式，默认关闭，可选single，multiple\n        // selectedMode: false,\n        dataRangeHoverLink: true,\n        // 是否开启缩放及漫游模式\n        // roam: false,\n\n        // Define left-top, right-bottom coords to control view\n        // For example, [ [180, 90], [-180, -90] ],\n        // higher priority than center and zoom\n        boundingCoords: null,\n\n        // Default on center of map\n        center: null,\n\n        zoom: 1,\n\n        scaleLimit: null,\n\n        label: {\n            show: false,\n            color: '#000'\n        },\n        // scaleLimit: null,\n        itemStyle: {\n            borderWidth: 0.5,\n            borderColor: '#444',\n            areaColor: '#eee'\n        },\n\n        emphasis: {\n            label: {\n                show: true,\n                color: 'rgb(100,0,0)'\n            },\n            itemStyle: {\n                areaColor: 'rgba(255,215,0,0.8)'\n            }\n        }\n    }\n\n});\n\nmixin(MapSeries, selectableMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ATTR = '\\0_ec_interaction_mutex';\n\nfunction take(zr, resourceKey, userKey) {\n    var store = getStore(zr);\n    store[resourceKey] = userKey;\n}\n\nfunction release(zr, resourceKey, userKey) {\n    var store = getStore(zr);\n    var uKey = store[resourceKey];\n\n    if (uKey === userKey) {\n        store[resourceKey] = null;\n    }\n}\n\nfunction isTaken(zr, resourceKey) {\n    return !!getStore(zr)[resourceKey];\n}\n\nfunction getStore(zr) {\n    return zr[ATTR] || (zr[ATTR] = {});\n}\n\n/**\n * payload: {\n *     type: 'takeGlobalCursor',\n *     key: 'dataZoomSelect', or 'brush', or ...,\n *         If no userKey, release global cursor.\n * }\n */\nregisterAction(\n    {type: 'takeGlobalCursor', event: 'globalCursorTaken', update: 'update'},\n    function () {}\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @alias module:echarts/component/helper/RoamController\n * @constructor\n * @mixin {module:zrender/mixin/Eventful}\n *\n * @param {module:zrender/zrender~ZRender} zr\n */\nfunction RoamController(zr) {\n\n    /**\n     * @type {Function}\n     */\n    this.pointerChecker;\n\n    /**\n     * @type {module:zrender}\n     */\n    this._zr = zr;\n\n    /**\n     * @type {Object}\n     */\n    this._opt = {};\n\n    // Avoid two roamController bind the same handler\n    var bind$$1 = bind;\n    var mousedownHandler = bind$$1(mousedown, this);\n    var mousemoveHandler = bind$$1(mousemove, this);\n    var mouseupHandler = bind$$1(mouseup, this);\n    var mousewheelHandler = bind$$1(mousewheel, this);\n    var pinchHandler = bind$$1(pinch, this);\n\n    Eventful.call(this);\n\n    /**\n     * @param {Function} pointerChecker\n     *                   input: x, y\n     *                   output: boolean\n     */\n    this.setPointerChecker = function (pointerChecker) {\n        this.pointerChecker = pointerChecker;\n    };\n\n    /**\n     * Notice: only enable needed types. For example, if 'zoom'\n     * is not needed, 'zoom' should not be enabled, otherwise\n     * default mousewheel behaviour (scroll page) will be disabled.\n     *\n     * @param  {boolean|string} [controlType=true] Specify the control type,\n     *                          which can be null/undefined or true/false\n     *                          or 'pan/move' or 'zoom'/'scale'\n     * @param {Object} [opt]\n     * @param {Object} [opt.zoomOnMouseWheel=true] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.moveOnMouseMove=true] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.moveOnMouseWheel=false] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\n     * @param {Object} [opt.preventDefaultMouseMove=true] When pan.\n     */\n    this.enable = function (controlType, opt) {\n\n        // Disable previous first\n        this.disable();\n\n        this._opt = defaults(clone(opt) || {}, {\n            zoomOnMouseWheel: true,\n            moveOnMouseMove: true,\n            // By default, wheel do not trigger move.\n            moveOnMouseWheel: false,\n            preventDefaultMouseMove: true\n        });\n\n        if (controlType == null) {\n            controlType = true;\n        }\n\n        if (controlType === true || (controlType === 'move' || controlType === 'pan')) {\n            zr.on('mousedown', mousedownHandler);\n            zr.on('mousemove', mousemoveHandler);\n            zr.on('mouseup', mouseupHandler);\n        }\n        if (controlType === true || (controlType === 'scale' || controlType === 'zoom')) {\n            zr.on('mousewheel', mousewheelHandler);\n            zr.on('pinch', pinchHandler);\n        }\n    };\n\n    this.disable = function () {\n        zr.off('mousedown', mousedownHandler);\n        zr.off('mousemove', mousemoveHandler);\n        zr.off('mouseup', mouseupHandler);\n        zr.off('mousewheel', mousewheelHandler);\n        zr.off('pinch', pinchHandler);\n    };\n\n    this.dispose = this.disable;\n\n    this.isDragging = function () {\n        return this._dragging;\n    };\n\n    this.isPinching = function () {\n        return this._pinching;\n    };\n}\n\nmixin(RoamController, Eventful);\n\n\nfunction mousedown(e) {\n    if (isMiddleOrRightButtonOnMouseUpDown(e)\n        || (e.target && e.target.draggable)\n    ) {\n        return;\n    }\n\n    var x = e.offsetX;\n    var y = e.offsetY;\n\n    // Only check on mosedown, but not mousemove.\n    // Mouse can be out of target when mouse moving.\n    if (this.pointerChecker && this.pointerChecker(e, x, y)) {\n        this._x = x;\n        this._y = y;\n        this._dragging = true;\n    }\n}\n\nfunction mousemove(e) {\n    if (!this._dragging\n        || !isAvailableBehavior('moveOnMouseMove', e, this._opt)\n        || e.gestureEvent === 'pinch'\n        || isTaken(this._zr, 'globalPan')\n    ) {\n        return;\n    }\n\n    var x = e.offsetX;\n    var y = e.offsetY;\n\n    var oldX = this._x;\n    var oldY = this._y;\n\n    var dx = x - oldX;\n    var dy = y - oldY;\n\n    this._x = x;\n    this._y = y;\n\n    this._opt.preventDefaultMouseMove && stop(e.event);\n\n    trigger(this, 'pan', 'moveOnMouseMove', e, {\n        dx: dx, dy: dy, oldX: oldX, oldY: oldY, newX: x, newY: y\n    });\n}\n\nfunction mouseup(e) {\n    if (!isMiddleOrRightButtonOnMouseUpDown(e)) {\n        this._dragging = false;\n    }\n}\n\nfunction mousewheel(e) {\n    var shouldZoom = isAvailableBehavior('zoomOnMouseWheel', e, this._opt);\n    var shouldMove = isAvailableBehavior('moveOnMouseWheel', e, this._opt);\n    var wheelDelta = e.wheelDelta;\n    var absWheelDeltaDelta = Math.abs(wheelDelta);\n    var originX = e.offsetX;\n    var originY = e.offsetY;\n\n    // wheelDelta maybe -0 in chrome mac.\n    if (wheelDelta === 0 || (!shouldZoom && !shouldMove)) {\n        return;\n    }\n\n    // If both `shouldZoom` and `shouldMove` is true, trigger\n    // their event both, and the final behavior is determined\n    // by event listener themselves.\n\n    if (shouldZoom) {\n        // Convenience:\n        // Mac and VM Windows on Mac: scroll up: zoom out.\n        // Windows: scroll up: zoom in.\n\n        // FIXME: Should do more test in different environment.\n        // wheelDelta is too complicated in difference nvironment\n        // (https://developer.mozilla.org/en-US/docs/Web/Events/mousewheel),\n        // although it has been normallized by zrender.\n        // wheelDelta of mouse wheel is bigger than touch pad.\n        var factor = absWheelDeltaDelta > 3 ? 1.4 : absWheelDeltaDelta > 1 ? 1.2 : 1.1;\n        var scale = wheelDelta > 0 ? factor : 1 / factor;\n        checkPointerAndTrigger(this, 'zoom', 'zoomOnMouseWheel', e, {\n            scale: scale, originX: originX, originY: originY\n        });\n    }\n\n    if (shouldMove) {\n        // FIXME: Should do more test in different environment.\n        var absDelta = Math.abs(wheelDelta);\n        // wheelDelta of mouse wheel is bigger than touch pad.\n        var scrollDelta = (wheelDelta > 0 ? 1 : -1) * (absDelta > 3 ? 0.4 : absDelta > 1 ? 0.15 : 0.05);\n        checkPointerAndTrigger(this, 'scrollMove', 'moveOnMouseWheel', e, {\n            scrollDelta: scrollDelta, originX: originX, originY: originY\n        });\n    }\n}\n\nfunction pinch(e) {\n    if (isTaken(this._zr, 'globalPan')) {\n        return;\n    }\n    var scale = e.pinchScale > 1 ? 1.1 : 1 / 1.1;\n    checkPointerAndTrigger(this, 'zoom', null, e, {\n        scale: scale, originX: e.pinchX, originY: e.pinchY\n    });\n}\n\nfunction checkPointerAndTrigger(controller, eventName, behaviorToCheck, e, contollerEvent) {\n    if (controller.pointerChecker\n        && controller.pointerChecker(e, contollerEvent.originX, contollerEvent.originY)\n    ) {\n        // When mouse is out of roamController rect,\n        // default befavoius should not be be disabled, otherwise\n        // page sliding is disabled, contrary to expectation.\n        stop(e.event);\n\n        trigger(controller, eventName, behaviorToCheck, e, contollerEvent);\n    }\n}\n\nfunction trigger(controller, eventName, behaviorToCheck, e, contollerEvent) {\n    // Also provide behavior checker for event listener, for some case that\n    // multiple components share one listener.\n    contollerEvent.isAvailableBehavior = bind(isAvailableBehavior, null, behaviorToCheck, e);\n    controller.trigger(eventName, contollerEvent);\n}\n\n// settings: {\n//     zoomOnMouseWheel\n//     moveOnMouseMove\n//     moveOnMouseWheel\n// }\n// The value can be: true / false / 'shift' / 'ctrl' / 'alt'.\nfunction isAvailableBehavior(behaviorToCheck, e, settings) {\n    var setting = settings[behaviorToCheck];\n    return !behaviorToCheck || (\n        setting && (!isString(setting) || e.event[setting + 'Key'])\n    );\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * For geo and graph.\n *\n * @param {Object} controllerHost\n * @param {module:zrender/Element} controllerHost.target\n */\nfunction updateViewOnPan(controllerHost, dx, dy) {\n    var target = controllerHost.target;\n    var pos = target.position;\n    pos[0] += dx;\n    pos[1] += dy;\n    target.dirty();\n}\n\n/**\n * For geo and graph.\n *\n * @param {Object} controllerHost\n * @param {module:zrender/Element} controllerHost.target\n * @param {number} controllerHost.zoom\n * @param {number} controllerHost.zoomLimit like: {min: 1, max: 2}\n */\nfunction updateViewOnZoom(controllerHost, zoomDelta, zoomX, zoomY) {\n    var target = controllerHost.target;\n    var zoomLimit = controllerHost.zoomLimit;\n    var pos = target.position;\n    var scale = target.scale;\n\n    var newZoom = controllerHost.zoom = controllerHost.zoom || 1;\n    newZoom *= zoomDelta;\n    if (zoomLimit) {\n        var zoomMin = zoomLimit.min || 0;\n        var zoomMax = zoomLimit.max || Infinity;\n        newZoom = Math.max(\n            Math.min(zoomMax, newZoom),\n            zoomMin\n        );\n    }\n    var zoomScale = newZoom / controllerHost.zoom;\n    controllerHost.zoom = newZoom;\n    // Keep the mouse center when scaling\n    pos[0] -= (zoomX - pos[0]) * (zoomScale - 1);\n    pos[1] -= (zoomY - pos[1]) * (zoomScale - 1);\n    scale[0] *= zoomScale;\n    scale[1] *= zoomScale;\n\n    target.dirty();\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar IRRELEVANT_EXCLUDES = {'axisPointer': 1, 'tooltip': 1, 'brush': 1};\n\n/**\n * Avoid that: mouse click on a elements that is over geo or graph,\n * but roam is triggered.\n */\nfunction onIrrelevantElement(e, api, targetCoordSysModel) {\n    var model = api.getComponentByElement(e.topTarget);\n    // If model is axisModel, it works only if it is injected with coordinateSystem.\n    var coordSys = model && model.coordinateSystem;\n    return model\n        && model !== targetCoordSysModel\n        && !IRRELEVANT_EXCLUDES[model.mainType]\n        && (coordSys && coordSys.model !== targetCoordSysModel);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction getFixedItemStyle(model, scale) {\n    var itemStyle = model.getItemStyle();\n    var areaColor = model.get('areaColor');\n\n    // If user want the color not to be changed when hover,\n    // they should both set areaColor and color to be null.\n    if (areaColor != null) {\n        itemStyle.fill = areaColor;\n    }\n\n    return itemStyle;\n}\n\nfunction updateMapSelectHandler(mapDraw, mapOrGeoModel, regionsGroup, api, fromView) {\n    regionsGroup.off('click');\n    regionsGroup.off('mousedown');\n\n    if (mapOrGeoModel.get('selectedMode')) {\n\n        regionsGroup.on('mousedown', function () {\n            mapDraw._mouseDownFlag = true;\n        });\n\n        regionsGroup.on('click', function (e) {\n            if (!mapDraw._mouseDownFlag) {\n                return;\n            }\n            mapDraw._mouseDownFlag = false;\n\n            var el = e.target;\n            while (!el.__regions) {\n                el = el.parent;\n            }\n            if (!el) {\n                return;\n            }\n\n            var action = {\n                type: (mapOrGeoModel.mainType === 'geo' ? 'geo' : 'map') + 'ToggleSelect',\n                batch: map(el.__regions, function (region) {\n                    return {\n                        name: region.name,\n                        from: fromView.uid\n                    };\n                })\n            };\n            action[mapOrGeoModel.mainType + 'Id'] = mapOrGeoModel.id;\n\n            api.dispatchAction(action);\n\n            updateMapSelected(mapOrGeoModel, regionsGroup);\n        });\n    }\n}\n\nfunction updateMapSelected(mapOrGeoModel, regionsGroup) {\n    // FIXME\n    regionsGroup.eachChild(function (otherRegionEl) {\n        each$1(otherRegionEl.__regions, function (region) {\n            otherRegionEl.trigger(mapOrGeoModel.isSelected(region.name) ? 'emphasis' : 'normal');\n        });\n    });\n}\n\n/**\n * @alias module:echarts/component/helper/MapDraw\n * @param {module:echarts/ExtensionAPI} api\n * @param {boolean} updateGroup\n */\nfunction MapDraw(api, updateGroup) {\n\n    var group = new Group();\n\n    /**\n     * @type {string}\n     * @private\n     */\n    this.uid = getUID('ec_map_draw');\n\n    /**\n     * @type {module:echarts/component/helper/RoamController}\n     * @private\n     */\n    this._controller = new RoamController(api.getZr());\n\n    /**\n     * @type {Object} {target, zoom, zoomLimit}\n     * @private\n     */\n    this._controllerHost = {target: updateGroup ? group : null};\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = group;\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._updateGroup = updateGroup;\n\n    /**\n     * This flag is used to make sure that only one among\n     * `pan`, `zoom`, `click` can occurs, otherwise 'selected'\n     * action may be triggered when `pan`, which is unexpected.\n     * @type {booelan}\n     */\n    this._mouseDownFlag;\n\n    /**\n     * @type {string}\n     */\n    this._mapName;\n\n    /**\n     * @type {boolean}\n     */\n    this._initialized;\n\n    /**\n     * @type {module:zrender/container/Group}\n     */\n    group.add(this._regionsGroup = new Group());\n\n    /**\n     * @type {module:zrender/container/Group}\n     */\n    group.add(this._backgroundGroup = new Group());\n}\n\nMapDraw.prototype = {\n\n    constructor: MapDraw,\n\n    draw: function (mapOrGeoModel, ecModel, api, fromView, payload) {\n\n        var isGeo = mapOrGeoModel.mainType === 'geo';\n\n        // Map series has data. GEO model that controlled by map series\n        // will be assigned with map data. Other GEO model has no data.\n        var data = mapOrGeoModel.getData && mapOrGeoModel.getData();\n        isGeo && ecModel.eachComponent({mainType: 'series', subType: 'map'}, function (mapSeries) {\n            if (!data && mapSeries.getHostGeoModel() === mapOrGeoModel) {\n                data = mapSeries.getData();\n            }\n        });\n\n        var geo = mapOrGeoModel.coordinateSystem;\n\n        this._updateBackground(geo);\n\n        var regionsGroup = this._regionsGroup;\n        var group = this.group;\n\n        var scale = geo.scale;\n        var transform = {\n            position: geo.position,\n            scale: scale\n        };\n\n        // No animation when first draw or in action\n        if (!regionsGroup.childAt(0) || payload) {\n            group.attr(transform);\n        }\n        else {\n            updateProps(group, transform, mapOrGeoModel);\n        }\n\n        regionsGroup.removeAll();\n\n        var itemStyleAccessPath = ['itemStyle'];\n        var hoverItemStyleAccessPath = ['emphasis', 'itemStyle'];\n        var labelAccessPath = ['label'];\n        var hoverLabelAccessPath = ['emphasis', 'label'];\n        var nameMap = createHashMap();\n\n        each$1(geo.regions, function (region) {\n\n            // Consider in GeoJson properties.name may be duplicated, for example,\n            // there is multiple region named \"United Kindom\" or \"France\" (so many\n            // colonies). And it is not appropriate to merge them in geo, which\n            // will make them share the same label and bring trouble in label\n            // location calculation.\n            var regionGroup = nameMap.get(region.name)\n                || nameMap.set(region.name, new Group());\n\n            var compoundPath = new CompoundPath({\n                shape: {\n                    paths: []\n                }\n            });\n            regionGroup.add(compoundPath);\n\n            var regionModel = mapOrGeoModel.getRegionModel(region.name) || mapOrGeoModel;\n\n            var itemStyleModel = regionModel.getModel(itemStyleAccessPath);\n            var hoverItemStyleModel = regionModel.getModel(hoverItemStyleAccessPath);\n            var itemStyle = getFixedItemStyle(itemStyleModel, scale);\n            var hoverItemStyle = getFixedItemStyle(hoverItemStyleModel, scale);\n\n            var labelModel = regionModel.getModel(labelAccessPath);\n            var hoverLabelModel = regionModel.getModel(hoverLabelAccessPath);\n\n            var dataIdx;\n            // Use the itemStyle in data if has data\n            if (data) {\n                dataIdx = data.indexOfName(region.name);\n                // Only visual color of each item will be used. It can be encoded by dataRange\n                // But visual color of series is used in symbol drawing\n                //\n                // Visual color for each series is for the symbol draw\n                var visualColor = data.getItemVisual(dataIdx, 'color', true);\n                if (visualColor) {\n                    itemStyle.fill = visualColor;\n                }\n            }\n\n            each$1(region.geometries, function (geometry) {\n                if (geometry.type !== 'polygon') {\n                    return;\n                }\n                compoundPath.shape.paths.push(new Polygon({\n                    shape: {\n                        points: geometry.exterior\n                    }\n                }));\n\n                for (var i = 0; i < (geometry.interiors ? geometry.interiors.length : 0); i++) {\n                    compoundPath.shape.paths.push(new Polygon({\n                        shape: {\n                            points: geometry.interiors[i]\n                        }\n                    }));\n                }\n            });\n\n            compoundPath.setStyle(itemStyle);\n            compoundPath.style.strokeNoScale = true;\n            compoundPath.culling = true;\n            // Label\n            var showLabel = labelModel.get('show');\n            var hoverShowLabel = hoverLabelModel.get('show');\n\n            var isDataNaN = data && isNaN(data.get(data.mapDimension('value'), dataIdx));\n            var itemLayout = data && data.getItemLayout(dataIdx);\n            // In the following cases label will be drawn\n            // 1. In map series and data value is NaN\n            // 2. In geo component\n            // 4. Region has no series legendSymbol, which will be add a showLabel flag in mapSymbolLayout\n            if (\n                (isGeo || isDataNaN && (showLabel || hoverShowLabel))\n                || (itemLayout && itemLayout.showLabel)\n            ) {\n                var query = !isGeo ? dataIdx : region.name;\n                var labelFetcher;\n\n                // Consider dataIdx not found.\n                if (!data || dataIdx >= 0) {\n                    labelFetcher = mapOrGeoModel;\n                }\n\n                var textEl = new Text({\n                    position: region.center.slice(),\n                    // FIXME\n                    // label rotation is not support yet in geo or regions of series-map\n                    // that has no data. The rotation will be effected by this `scale`.\n                    // So needed to change to RectText?\n                    scale: [1 / scale[0], 1 / scale[1]],\n                    z2: 10,\n                    silent: true\n                });\n\n                setLabelStyle(\n                    textEl.style, textEl.hoverStyle = {}, labelModel, hoverLabelModel,\n                    {\n                        labelFetcher: labelFetcher,\n                        labelDataIndex: query,\n                        defaultText: region.name,\n                        useInsideStyle: false\n                    },\n                    {\n                        textAlign: 'center',\n                        textVerticalAlign: 'middle'\n                    }\n                );\n\n                regionGroup.add(textEl);\n            }\n\n            // setItemGraphicEl, setHoverStyle after all polygons and labels\n            // are added to the rigionGroup\n            if (data) {\n                data.setItemGraphicEl(dataIdx, regionGroup);\n            }\n            else {\n                var regionModel = mapOrGeoModel.getRegionModel(region.name);\n                // Package custom mouse event for geo component\n                compoundPath.eventData = {\n                    componentType: 'geo',\n                    componentIndex: mapOrGeoModel.componentIndex,\n                    geoIndex: mapOrGeoModel.componentIndex,\n                    name: region.name,\n                    region: (regionModel && regionModel.option) || {}\n                };\n            }\n\n            var groupRegions = regionGroup.__regions || (regionGroup.__regions = []);\n            groupRegions.push(region);\n\n            setHoverStyle(\n                regionGroup,\n                hoverItemStyle,\n                {hoverSilentOnTouch: !!mapOrGeoModel.get('selectedMode')}\n            );\n\n            regionsGroup.add(regionGroup);\n        });\n\n        this._updateController(mapOrGeoModel, ecModel, api);\n\n        updateMapSelectHandler(this, mapOrGeoModel, regionsGroup, api, fromView);\n\n        updateMapSelected(mapOrGeoModel, regionsGroup);\n    },\n\n    remove: function () {\n        this._regionsGroup.removeAll();\n        this._backgroundGroup.removeAll();\n        this._controller.dispose();\n        this._mapName && geoSourceManager.removeGraphic(this._mapName, this.uid);\n        this._mapName = null;\n        this._controllerHost = {};\n    },\n\n    _updateBackground: function (geo) {\n        var mapName = geo.map;\n\n        if (this._mapName !== mapName) {\n            each$1(geoSourceManager.makeGraphic(mapName, this.uid), function (root) {\n                this._backgroundGroup.add(root);\n            }, this);\n        }\n\n        this._mapName = mapName;\n    },\n\n    _updateController: function (mapOrGeoModel, ecModel, api) {\n        var geo = mapOrGeoModel.coordinateSystem;\n        var controller = this._controller;\n        var controllerHost = this._controllerHost;\n\n        controllerHost.zoomLimit = mapOrGeoModel.get('scaleLimit');\n        controllerHost.zoom = geo.getZoom();\n\n        // roamType is will be set default true if it is null\n        controller.enable(mapOrGeoModel.get('roam') || false);\n        var mainType = mapOrGeoModel.mainType;\n\n        function makeActionBase() {\n            var action = {\n                type: 'geoRoam',\n                componentType: mainType\n            };\n            action[mainType + 'Id'] = mapOrGeoModel.id;\n            return action;\n        }\n\n        controller.off('pan').on('pan', function (e) {\n            this._mouseDownFlag = false;\n\n            updateViewOnPan(controllerHost, e.dx, e.dy);\n\n            api.dispatchAction(extend(makeActionBase(), {\n                dx: e.dx,\n                dy: e.dy\n            }));\n        }, this);\n\n        controller.off('zoom').on('zoom', function (e) {\n            this._mouseDownFlag = false;\n\n            updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY);\n\n            api.dispatchAction(extend(makeActionBase(), {\n                zoom: e.scale,\n                originX: e.originX,\n                originY: e.originY\n            }));\n\n            if (this._updateGroup) {\n                var scale = this.group.scale;\n                this._regionsGroup.traverse(function (el) {\n                    if (el.type === 'text') {\n                        el.attr('scale', [1 / scale[0], 1 / scale[1]]);\n                    }\n                });\n            }\n        }, this);\n\n        controller.setPointerChecker(function (e, x, y) {\n            return geo.getViewRectAfterRoam().contain(x, y)\n                && !onIrrelevantElement(e, api, mapOrGeoModel);\n        });\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar HIGH_DOWN_PROP = '__seriesMapHighDown';\nvar RECORD_VERSION_PROP = '__seriesMapCallKey';\n\nextendChartView({\n\n    type: 'map',\n\n    render: function (mapModel, ecModel, api, payload) {\n        // Not render if it is an toggleSelect action from self\n        if (payload && payload.type === 'mapToggleSelect'\n            && payload.from === this.uid\n        ) {\n            return;\n        }\n\n        var group = this.group;\n        group.removeAll();\n\n        if (mapModel.getHostGeoModel()) {\n            return;\n        }\n\n        // Not update map if it is an roam action from self\n        if (!(payload && payload.type === 'geoRoam'\n                && payload.componentType === 'series'\n                && payload.seriesId === mapModel.id\n            )\n        ) {\n            if (mapModel.needsDrawMap) {\n                var mapDraw = this._mapDraw || new MapDraw(api, true);\n                group.add(mapDraw.group);\n\n                mapDraw.draw(mapModel, ecModel, api, this, payload);\n\n                this._mapDraw = mapDraw;\n            }\n            else {\n                // Remove drawed map\n                this._mapDraw && this._mapDraw.remove();\n                this._mapDraw = null;\n            }\n        }\n        else {\n            var mapDraw = this._mapDraw;\n            mapDraw && group.add(mapDraw.group);\n        }\n\n        mapModel.get('showLegendSymbol') && ecModel.getComponent('legend')\n            && this._renderSymbols(mapModel, ecModel, api);\n    },\n\n    remove: function () {\n        this._mapDraw && this._mapDraw.remove();\n        this._mapDraw = null;\n        this.group.removeAll();\n    },\n\n    dispose: function () {\n        this._mapDraw && this._mapDraw.remove();\n        this._mapDraw = null;\n    },\n\n    _renderSymbols: function (mapModel, ecModel, api) {\n        var originalData = mapModel.originalData;\n        var group = this.group;\n\n        originalData.each(originalData.mapDimension('value'), function (value, originalDataIndex) {\n            if (isNaN(value)) {\n                return;\n            }\n\n            var layout = originalData.getItemLayout(originalDataIndex);\n\n            if (!layout || !layout.point) {\n                // Not exists in map\n                return;\n            }\n\n            var point = layout.point;\n            var offset = layout.offset;\n\n            var circle = new Circle({\n                style: {\n                    // Because the special of map draw.\n                    // Which needs statistic of multiple series and draw on one map.\n                    // And each series also need a symbol with legend color\n                    //\n                    // Layout and visual are put one the different data\n                    fill: mapModel.getData().getVisual('color')\n                },\n                shape: {\n                    cx: point[0] + offset * 9,\n                    cy: point[1],\n                    r: 3\n                },\n                silent: true,\n                // Do not overlap the first series, on which labels are displayed.\n                z2: 8 + (!offset ? Z2_EMPHASIS_LIFT + 1 : 0)\n            });\n\n            // Only the series that has the first value on the same region is in charge of rendering the label.\n            // But consider the case:\n            // series: [\n            //     {id: 'X', type: 'map', map: 'm', {data: [{name: 'A', value: 11}, {name: 'B', {value: 22}]},\n            //     {id: 'Y', type: 'map', map: 'm', {data: [{name: 'A', value: 21}, {name: 'C', {value: 33}]}\n            // ]\n            // The offset `0` of item `A` is at series `X`, but of item `C` is at series `Y`.\n            // For backward compatibility, we follow the rule that render label `A` by the\n            // settings on series `X` but render label `C` by the settings on series `Y`.\n            if (!offset) {\n\n                var fullData = mapModel.mainSeries.getData();\n                var name = originalData.getName(originalDataIndex);\n\n                var fullIndex = fullData.indexOfName(name);\n\n                var itemModel = originalData.getItemModel(originalDataIndex);\n                var labelModel = itemModel.getModel('label');\n                var hoverLabelModel = itemModel.getModel('emphasis.label');\n\n                var regionGroup = fullData.getItemGraphicEl(fullIndex);\n\n                // `getFormattedLabel` needs to use `getData` inside. Here\n                // `mapModel.getData()` is shallow cloned from `mainSeries.getData()`.\n                // FIXME\n                // If this is not the `mainSeries`, the item model (like label formatter)\n                // set on original data item will never get. But it has been working\n                // like that from the begining, and this scenario is rarely encountered.\n                // So it won't be fixed until have to.\n                var normalText = retrieve2(\n                    mapModel.getFormattedLabel(fullIndex, 'normal'),\n                    name\n                );\n                var emphasisText = retrieve2(\n                    mapModel.getFormattedLabel(fullIndex, 'emphasis'),\n                    normalText\n                );\n\n                var highDownRecord = regionGroup[HIGH_DOWN_PROP];\n                var recordVersion = Math.random();\n\n                // Prevent from register listeners duplicatedly when roaming.\n                if (!highDownRecord) {\n                    highDownRecord = regionGroup[HIGH_DOWN_PROP] = {};\n                    var onEmphasis = curry(onRegionHighDown, true);\n                    var onNormal = curry(onRegionHighDown, false);\n                    regionGroup.on('mouseover', onEmphasis)\n                        .on('mouseout', onNormal)\n                        .on('emphasis', onEmphasis)\n                        .on('normal', onNormal);\n                }\n\n                // Prevent removed regions effect current grapics.\n                regionGroup[RECORD_VERSION_PROP] = recordVersion;\n                extend(highDownRecord, {\n                    recordVersion: recordVersion,\n                    circle: circle,\n                    labelModel: labelModel,\n                    hoverLabelModel: hoverLabelModel,\n                    emphasisText: emphasisText,\n                    normalText: normalText\n                });\n\n                // FIXME\n                // Consider set option when emphasis.\n                enterRegionHighDown(highDownRecord, false);\n            }\n\n            group.add(circle);\n        });\n    }\n});\n\nfunction onRegionHighDown(toHighOrDown) {\n    var highDownRecord = this[HIGH_DOWN_PROP];\n    if (highDownRecord && highDownRecord.recordVersion === this[RECORD_VERSION_PROP]) {\n        enterRegionHighDown(highDownRecord, toHighOrDown);\n    }\n}\n\nfunction enterRegionHighDown(highDownRecord, toHighOrDown) {\n    var circle = highDownRecord.circle;\n    var labelModel = highDownRecord.labelModel;\n    var hoverLabelModel = highDownRecord.hoverLabelModel;\n    var emphasisText = highDownRecord.emphasisText;\n    var normalText = highDownRecord.normalText;\n\n    if (toHighOrDown) {\n        circle.style.extendFrom(\n            setTextStyle({}, hoverLabelModel, {\n                text: hoverLabelModel.get('show') ? emphasisText : null\n            }, {isRectText: true, useInsideStyle: false}, true)\n        );\n        // Make label upper than others if overlaps.\n        circle.__mapOriginalZ2 = circle.z2;\n        circle.z2 += Z2_EMPHASIS_LIFT;\n    }\n    else {\n        setTextStyle(circle.style, labelModel, {\n            text: labelModel.get('show') ? normalText : null,\n            textPosition: labelModel.getShallow('position') || 'bottom'\n        }, {isRectText: true, useInsideStyle: false});\n        // Trigger normalize style like padding.\n        circle.dirty(false);\n\n        if (circle.__mapOriginalZ2 != null) {\n            circle.z2 = circle.__mapOriginalZ2;\n            circle.__mapOriginalZ2 = null;\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/coord/View} view\n * @param {Object} payload\n * @param {Object} [zoomLimit]\n */\nfunction updateCenterAndZoom(\n    view, payload, zoomLimit\n) {\n    var previousZoom = view.getZoom();\n    var center = view.getCenter();\n    var zoom = payload.zoom;\n\n    var point = view.dataToPoint(center);\n\n    if (payload.dx != null && payload.dy != null) {\n        point[0] -= payload.dx;\n        point[1] -= payload.dy;\n\n        var center = view.pointToData(point);\n        view.setCenter(center);\n    }\n    if (zoom != null) {\n        if (zoomLimit) {\n            var zoomMin = zoomLimit.min || 0;\n            var zoomMax = zoomLimit.max || Infinity;\n            zoom = Math.max(\n                Math.min(previousZoom * zoom, zoomMax),\n                zoomMin\n            ) / previousZoom;\n        }\n\n        // Zoom on given point(originX, originY)\n        view.scale[0] *= zoom;\n        view.scale[1] *= zoom;\n        var position = view.position;\n        var fixX = (payload.originX - position[0]) * (zoom - 1);\n        var fixY = (payload.originY - position[1]) * (zoom - 1);\n\n        position[0] -= fixX;\n        position[1] -= fixY;\n\n        view.updateTransform();\n        // Get the new center\n        var center = view.pointToData(point);\n        view.setCenter(center);\n        view.setZoom(zoom * previousZoom);\n    }\n\n    return {\n        center: view.getCenter(),\n        zoom: view.getZoom()\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @payload\n * @property {string} [componentType=series]\n * @property {number} [dx]\n * @property {number} [dy]\n * @property {number} [zoom]\n * @property {number} [originX]\n * @property {number} [originY]\n */\nregisterAction({\n    type: 'geoRoam',\n    event: 'geoRoam',\n    update: 'updateTransform'\n}, function (payload, ecModel) {\n    var componentType = payload.componentType || 'series';\n\n    ecModel.eachComponent(\n        { mainType: componentType, query: payload },\n        function (componentModel) {\n            var geo = componentModel.coordinateSystem;\n            if (geo.type !== 'geo') {\n                return;\n            }\n\n            var res = updateCenterAndZoom(\n                geo, payload, componentModel.get('scaleLimit')\n            );\n\n            componentModel.setCenter\n                && componentModel.setCenter(res.center);\n\n            componentModel.setZoom\n                && componentModel.setZoom(res.zoom);\n\n            // All map series with same `map` use the same geo coordinate system\n            // So the center and zoom must be in sync. Include the series not selected by legend\n            if (componentType === 'series') {\n                each$1(componentModel.seriesGroup, function (seriesModel) {\n                    seriesModel.setCenter(res.center);\n                    seriesModel.setZoom(res.zoom);\n                });\n            }\n        }\n    );\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Simple view coordinate system\n * Mapping given x, y to transformd view x, y\n */\n\nvar v2ApplyTransform$1 = applyTransform;\n\n// Dummy transform node\nfunction TransformDummy() {\n    Transformable.call(this);\n}\nmixin(TransformDummy, Transformable);\n\nfunction View(name) {\n    /**\n     * @type {string}\n     */\n    this.name = name;\n\n    /**\n     * @type {Object}\n     */\n    this.zoomLimit;\n\n    Transformable.call(this);\n\n    this._roamTransformable = new TransformDummy();\n\n    this._rawTransformable = new TransformDummy();\n\n    this._center;\n    this._zoom;\n}\n\nView.prototype = {\n\n    constructor: View,\n\n    type: 'view',\n\n    /**\n     * @param {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['x', 'y'],\n\n    /**\n     * Set bounding rect\n     * @param {number} x\n     * @param {number} y\n     * @param {number} width\n     * @param {number} height\n     */\n\n    // PENDING to getRect\n    setBoundingRect: function (x, y, width, height) {\n        this._rect = new BoundingRect(x, y, width, height);\n        return this._rect;\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    // PENDING to getRect\n    getBoundingRect: function () {\n        return this._rect;\n    },\n\n    /**\n     * @param {number} x\n     * @param {number} y\n     * @param {number} width\n     * @param {number} height\n     */\n    setViewRect: function (x, y, width, height) {\n        this.transformTo(x, y, width, height);\n        this._viewRect = new BoundingRect(x, y, width, height);\n    },\n\n    /**\n     * Transformed to particular position and size\n     * @param {number} x\n     * @param {number} y\n     * @param {number} width\n     * @param {number} height\n     */\n    transformTo: function (x, y, width, height) {\n        var rect = this.getBoundingRect();\n        var rawTransform = this._rawTransformable;\n\n        rawTransform.transform = rect.calculateTransform(\n            new BoundingRect(x, y, width, height)\n        );\n\n        rawTransform.decomposeTransform();\n\n        this._updateTransform();\n    },\n\n    /**\n     * Set center of view\n     * @param {Array.<number>} [centerCoord]\n     */\n    setCenter: function (centerCoord) {\n        if (!centerCoord) {\n            return;\n        }\n        this._center = centerCoord;\n\n        this._updateCenterAndZoom();\n    },\n\n    /**\n     * @param {number} zoom\n     */\n    setZoom: function (zoom) {\n        zoom = zoom || 1;\n\n        var zoomLimit = this.zoomLimit;\n        if (zoomLimit) {\n            if (zoomLimit.max != null) {\n                zoom = Math.min(zoomLimit.max, zoom);\n            }\n            if (zoomLimit.min != null) {\n                zoom = Math.max(zoomLimit.min, zoom);\n            }\n        }\n        this._zoom = zoom;\n\n        this._updateCenterAndZoom();\n    },\n\n    /**\n     * Get default center without roam\n     */\n    getDefaultCenter: function () {\n        // Rect before any transform\n        var rawRect = this.getBoundingRect();\n        var cx = rawRect.x + rawRect.width / 2;\n        var cy = rawRect.y + rawRect.height / 2;\n\n        return [cx, cy];\n    },\n\n    getCenter: function () {\n        return this._center || this.getDefaultCenter();\n    },\n\n    getZoom: function () {\n        return this._zoom || 1;\n    },\n\n    /**\n     * @return {Array.<number}\n     */\n    getRoamTransform: function () {\n        return this._roamTransformable.getLocalTransform();\n    },\n\n    /**\n     * Remove roam\n     */\n\n    _updateCenterAndZoom: function () {\n        // Must update after view transform updated\n        var rawTransformMatrix = this._rawTransformable.getLocalTransform();\n        var roamTransform = this._roamTransformable;\n        var defaultCenter = this.getDefaultCenter();\n        var center = this.getCenter();\n        var zoom = this.getZoom();\n\n        center = applyTransform([], center, rawTransformMatrix);\n        defaultCenter = applyTransform([], defaultCenter, rawTransformMatrix);\n\n        roamTransform.origin = center;\n        roamTransform.position = [\n            defaultCenter[0] - center[0],\n            defaultCenter[1] - center[1]\n        ];\n        roamTransform.scale = [zoom, zoom];\n\n        this._updateTransform();\n    },\n\n    /**\n     * Update transform from roam and mapLocation\n     * @private\n     */\n    _updateTransform: function () {\n        var roamTransformable = this._roamTransformable;\n        var rawTransformable = this._rawTransformable;\n\n        rawTransformable.parent = roamTransformable;\n        roamTransformable.updateTransform();\n        rawTransformable.updateTransform();\n\n        copy$1(this.transform || (this.transform = []), rawTransformable.transform || create$1());\n\n        this._rawTransform = rawTransformable.getLocalTransform();\n\n        this.invTransform = this.invTransform || [];\n        invert(this.invTransform, this.transform);\n\n        this.decomposeTransform();\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getViewRect: function () {\n        return this._viewRect;\n    },\n\n    /**\n     * Get view rect after roam transform\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getViewRectAfterRoam: function () {\n        var rect = this.getBoundingRect().clone();\n        rect.applyTransform(this.transform);\n        return rect;\n    },\n\n    /**\n     * Convert a single (lon, lat) data item to (x, y) point.\n     * @param {Array.<number>} data\n     * @param {boolean} noRoam\n     * @param {Array.<number>} [out]\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, noRoam, out) {\n        var transform = noRoam ? this._rawTransform : this.transform;\n        out = out || [];\n        return transform\n            ? v2ApplyTransform$1(out, data, transform)\n            : copy(out, data);\n    },\n\n    /**\n     * Convert a (x, y) point to (lon, lat) data\n     * @param {Array.<number>} point\n     * @return {Array.<number>}\n     */\n    pointToData: function (point) {\n        var invTransform = this.invTransform;\n        return invTransform\n            ? v2ApplyTransform$1([], point, invTransform)\n            : [point[0], point[1]];\n    },\n\n    /**\n     * @implements\n     * see {module:echarts/CoodinateSystem}\n     */\n    convertToPixel: curry(doConvert$1, 'dataToPoint'),\n\n    /**\n     * @implements\n     * see {module:echarts/CoodinateSystem}\n     */\n    convertFromPixel: curry(doConvert$1, 'pointToData'),\n\n    /**\n     * @implements\n     * see {module:echarts/CoodinateSystem}\n     */\n    containPoint: function (point) {\n        return this.getViewRectAfterRoam().contain(point[0], point[1]);\n    }\n\n    /**\n     * @return {number}\n     */\n    // getScalarScale: function () {\n    //     // Use determinant square root of transform to mutiply scalar\n    //     var m = this.transform;\n    //     var det = Math.sqrt(Math.abs(m[0] * m[3] - m[2] * m[1]));\n    //     return det;\n    // }\n};\n\nmixin(View, Transformable);\n\nfunction doConvert$1(methodName, ecModel, finder, value) {\n    var seriesModel = finder.seriesModel;\n    var coordSys = seriesModel ? seriesModel.coordinateSystem : null; // e.g., graph.\n    return coordSys === this ? coordSys[methodName](value) : null;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * [Geo description]\n * For backward compatibility, the orginal interface:\n * `name, map, geoJson, specialAreas, nameMap` is kept.\n *\n * @param {string|Object} name\n * @param {string} map Map type\n *        Specify the positioned areas by left, top, width, height\n * @param {Object.<string, string>} [nameMap]\n *        Specify name alias\n * @param {boolean} [invertLongitute=true]\n */\nfunction Geo(name, map$$1, nameMap, invertLongitute) {\n\n    View.call(this, name);\n\n    /**\n     * Map type\n     * @type {string}\n     */\n    this.map = map$$1;\n\n    var source = geoSourceManager.load(map$$1, nameMap);\n\n    this._nameCoordMap = source.nameCoordMap;\n    this._regionsMap = source.regionsMap;\n    this._invertLongitute = invertLongitute == null ? true : invertLongitute;\n\n    /**\n     * @readOnly\n     */\n    this.regions = source.regions;\n\n    /**\n     * @type {module:zrender/src/core/BoundingRect}\n     */\n    this._rect = source.boundingRect;\n}\n\nGeo.prototype = {\n\n    constructor: Geo,\n\n    type: 'geo',\n\n    /**\n     * @param {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['lng', 'lat'],\n\n    /**\n     * If contain given lng,lat coord\n     * @param {Array.<number>}\n     * @readOnly\n     */\n    containCoord: function (coord) {\n        var regions = this.regions;\n        for (var i = 0; i < regions.length; i++) {\n            if (regions[i].contain(coord)) {\n                return true;\n            }\n        }\n        return false;\n    },\n\n    /**\n     * @override\n     */\n    transformTo: function (x, y, width, height) {\n        var rect = this.getBoundingRect();\n        var invertLongitute = this._invertLongitute;\n\n        rect = rect.clone();\n\n        if (invertLongitute) {\n            // Longitute is inverted\n            rect.y = -rect.y - rect.height;\n        }\n\n        var rawTransformable = this._rawTransformable;\n\n        rawTransformable.transform = rect.calculateTransform(\n            new BoundingRect(x, y, width, height)\n        );\n\n        rawTransformable.decomposeTransform();\n\n        if (invertLongitute) {\n            var scale = rawTransformable.scale;\n            scale[1] = -scale[1];\n        }\n\n        rawTransformable.updateTransform();\n\n        this._updateTransform();\n    },\n\n    /**\n     * @param {string} name\n     * @return {module:echarts/coord/geo/Region}\n     */\n    getRegion: function (name) {\n        return this._regionsMap.get(name);\n    },\n\n    getRegionByCoord: function (coord) {\n        var regions = this.regions;\n        for (var i = 0; i < regions.length; i++) {\n            if (regions[i].contain(coord)) {\n                return regions[i];\n            }\n        }\n    },\n\n    /**\n     * Add geoCoord for indexing by name\n     * @param {string} name\n     * @param {Array.<number>} geoCoord\n     */\n    addGeoCoord: function (name, geoCoord) {\n        this._nameCoordMap.set(name, geoCoord);\n    },\n\n    /**\n     * Get geoCoord by name\n     * @param {string} name\n     * @return {Array.<number>}\n     */\n    getGeoCoord: function (name) {\n        return this._nameCoordMap.get(name);\n    },\n\n    /**\n     * @override\n     */\n    getBoundingRect: function () {\n        return this._rect;\n    },\n\n    /**\n     * @param {string|Array.<number>} data\n     * @param {boolean} noRoam\n     * @param {Array.<number>} [out]\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, noRoam, out) {\n        if (typeof data === 'string') {\n            // Map area name to geoCoord\n            data = this.getGeoCoord(data);\n        }\n        if (data) {\n            return View.prototype.dataToPoint.call(this, data, noRoam, out);\n        }\n    },\n\n    /**\n     * @override\n     */\n    convertToPixel: curry(doConvert, 'dataToPoint'),\n\n    /**\n     * @override\n     */\n    convertFromPixel: curry(doConvert, 'pointToData')\n\n};\n\nmixin(Geo, View);\n\nfunction doConvert(methodName, ecModel, finder, value) {\n    var geoModel = finder.geoModel;\n    var seriesModel = finder.seriesModel;\n\n    var coordSys = geoModel\n        ? geoModel.coordinateSystem\n        : seriesModel\n        ? (\n            seriesModel.coordinateSystem // For map.\n            || (seriesModel.getReferringComponents('geo')[0] || {}).coordinateSystem\n        )\n        : null;\n\n    return coordSys === this ? coordSys[methodName](value) : null;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Resize method bound to the geo\n * @param {module:echarts/coord/geo/GeoModel|module:echarts/chart/map/MapModel} geoModel\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction resizeGeo(geoModel, api) {\n\n    var boundingCoords = geoModel.get('boundingCoords');\n    if (boundingCoords != null) {\n        var leftTop = boundingCoords[0];\n        var rightBottom = boundingCoords[1];\n        if (isNaN(leftTop[0]) || isNaN(leftTop[1]) || isNaN(rightBottom[0]) || isNaN(rightBottom[1])) {\n            if (__DEV__) {\n                console.error('Invalid boundingCoords');\n            }\n        }\n        else {\n            this.setBoundingRect(leftTop[0], leftTop[1], rightBottom[0] - leftTop[0], rightBottom[1] - leftTop[1]);\n        }\n    }\n\n    var rect = this.getBoundingRect();\n\n    var boxLayoutOption;\n\n    var center = geoModel.get('layoutCenter');\n    var size = geoModel.get('layoutSize');\n\n    var viewWidth = api.getWidth();\n    var viewHeight = api.getHeight();\n\n    var aspect = rect.width / rect.height * this.aspectScale;\n\n    var useCenterAndSize = false;\n\n    if (center && size) {\n        center = [\n            parsePercent$1(center[0], viewWidth),\n            parsePercent$1(center[1], viewHeight)\n        ];\n        size = parsePercent$1(size, Math.min(viewWidth, viewHeight));\n\n        if (!isNaN(center[0]) && !isNaN(center[1]) && !isNaN(size)) {\n            useCenterAndSize = true;\n        }\n        else {\n            if (__DEV__) {\n                console.warn('Given layoutCenter or layoutSize data are invalid. Use left/top/width/height instead.');\n            }\n        }\n    }\n\n    var viewRect;\n    if (useCenterAndSize) {\n        var viewRect = {};\n        if (aspect > 1) {\n            // Width is same with size\n            viewRect.width = size;\n            viewRect.height = size / aspect;\n        }\n        else {\n            viewRect.height = size;\n            viewRect.width = size * aspect;\n        }\n        viewRect.y = center[1] - viewRect.height / 2;\n        viewRect.x = center[0] - viewRect.width / 2;\n    }\n    else {\n        // Use left/top/width/height\n        boxLayoutOption = geoModel.getBoxLayoutParams();\n\n        // 0.75 rate\n        boxLayoutOption.aspect = aspect;\n\n        viewRect = getLayoutRect(boxLayoutOption, {\n            width: viewWidth,\n            height: viewHeight\n        });\n    }\n\n    this.setViewRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height);\n\n    this.setCenter(geoModel.get('center'));\n    this.setZoom(geoModel.get('zoom'));\n}\n\n/**\n * @param {module:echarts/coord/Geo} geo\n * @param {module:echarts/model/Model} model\n * @inner\n */\nfunction setGeoCoords(geo, model) {\n    each$1(model.get('geoCoord'), function (geoCoord, name) {\n        geo.addGeoCoord(name, geoCoord);\n    });\n}\n\nvar geoCreator = {\n\n    // For deciding which dimensions to use when creating list data\n    dimensions: Geo.prototype.dimensions,\n\n    create: function (ecModel, api) {\n        var geoList = [];\n\n        // FIXME Create each time may be slow\n        ecModel.eachComponent('geo', function (geoModel, idx) {\n            var name = geoModel.get('map');\n\n            var aspectScale = geoModel.get('aspectScale');\n            var invertLongitute = true;\n            var mapRecords = mapDataStorage.retrieveMap(name);\n            if (mapRecords && mapRecords[0] && mapRecords[0].type === 'svg') {\n                aspectScale == null && (aspectScale = 1);\n                invertLongitute = false;\n            }\n            else {\n                aspectScale == null && (aspectScale = 0.75);\n            }\n\n            var geo = new Geo(name + idx, name, geoModel.get('nameMap'), invertLongitute);\n\n            geo.aspectScale = aspectScale;\n            geo.zoomLimit = geoModel.get('scaleLimit');\n            geoList.push(geo);\n\n            setGeoCoords(geo, geoModel);\n\n            geoModel.coordinateSystem = geo;\n            geo.model = geoModel;\n\n            // Inject resize method\n            geo.resize = resizeGeo;\n\n            geo.resize(geoModel, api);\n        });\n\n        ecModel.eachSeries(function (seriesModel) {\n            var coordSys = seriesModel.get('coordinateSystem');\n            if (coordSys === 'geo') {\n                var geoIndex = seriesModel.get('geoIndex') || 0;\n                seriesModel.coordinateSystem = geoList[geoIndex];\n            }\n        });\n\n        // If has map series\n        var mapModelGroupBySeries = {};\n\n        ecModel.eachSeriesByType('map', function (seriesModel) {\n            if (!seriesModel.getHostGeoModel()) {\n                var mapType = seriesModel.getMapType();\n                mapModelGroupBySeries[mapType] = mapModelGroupBySeries[mapType] || [];\n                mapModelGroupBySeries[mapType].push(seriesModel);\n            }\n        });\n\n        each$1(mapModelGroupBySeries, function (mapSeries, mapType) {\n            var nameMapList = map(mapSeries, function (singleMapSeries) {\n                return singleMapSeries.get('nameMap');\n            });\n            var geo = new Geo(mapType, mapType, mergeAll(nameMapList));\n\n            geo.zoomLimit = retrieve.apply(null, map(mapSeries, function (singleMapSeries) {\n                return singleMapSeries.get('scaleLimit');\n            }));\n            geoList.push(geo);\n\n            // Inject resize method\n            geo.resize = resizeGeo;\n            geo.aspectScale = mapSeries[0].get('aspectScale');\n\n            geo.resize(mapSeries[0], api);\n\n            each$1(mapSeries, function (singleMapSeries) {\n                singleMapSeries.coordinateSystem = geo;\n\n                setGeoCoords(geo, singleMapSeries);\n            });\n        });\n\n        return geoList;\n    },\n\n    /**\n     * Fill given regions array\n     * @param  {Array.<Object>} originRegionArr\n     * @param  {string} mapName\n     * @param  {Object} [nameMap]\n     * @return {Array}\n     */\n    getFilledRegions: function (originRegionArr, mapName, nameMap) {\n        // Not use the original\n        var regionsArr = (originRegionArr || []).slice();\n\n        var dataNameMap = createHashMap();\n        for (var i = 0; i < regionsArr.length; i++) {\n            dataNameMap.set(regionsArr[i].name, regionsArr[i]);\n        }\n\n        var source = geoSourceManager.load(mapName, nameMap);\n        each$1(source.regions, function (region) {\n            var name = region.name;\n            !dataNameMap.get(name) && regionsArr.push({name: name});\n        });\n\n        return regionsArr;\n    }\n};\n\nregisterCoordinateSystem('geo', geoCreator);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar mapSymbolLayout = function (ecModel) {\n\n    var processedMapType = {};\n\n    ecModel.eachSeriesByType('map', function (mapSeries) {\n        var mapType = mapSeries.getMapType();\n        if (mapSeries.getHostGeoModel() || processedMapType[mapType]) {\n            return;\n        }\n\n        var mapSymbolOffsets = {};\n\n        each$1(mapSeries.seriesGroup, function (subMapSeries) {\n            var geo = subMapSeries.coordinateSystem;\n            var data = subMapSeries.originalData;\n            if (subMapSeries.get('showLegendSymbol') && ecModel.getComponent('legend')) {\n                data.each(data.mapDimension('value'), function (value, idx) {\n                    var name = data.getName(idx);\n                    var region = geo.getRegion(name);\n\n                    // If input series.data is [11, 22, '-'/null/undefined, 44],\n                    // it will be filled with NaN: [11, 22, NaN, 44] and NaN will\n                    // not be drawn. So here must validate if value is NaN.\n                    if (!region || isNaN(value)) {\n                        return;\n                    }\n\n                    var offset = mapSymbolOffsets[name] || 0;\n\n                    var point = geo.dataToPoint(region.center);\n\n                    mapSymbolOffsets[name] = offset + 1;\n\n                    data.setItemLayout(idx, {\n                        point: point,\n                        offset: offset\n                    });\n                });\n            }\n        });\n\n        // Show label of those region not has legendSymbol(which is offset 0)\n        var data = mapSeries.getData();\n        data.each(function (idx) {\n            var name = data.getName(idx);\n            var layout = data.getItemLayout(idx) || {};\n            layout.showLabel = !mapSymbolOffsets[name];\n            data.setItemLayout(idx, layout);\n        });\n\n        processedMapType[mapType] = true;\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar mapVisual = function (ecModel) {\n    ecModel.eachSeriesByType('map', function (seriesModel) {\n        var colorList = seriesModel.get('color');\n        var itemStyleModel = seriesModel.getModel('itemStyle');\n\n        var areaColor = itemStyleModel.get('areaColor');\n        var color = itemStyleModel.get('color')\n            || colorList[seriesModel.seriesIndex % colorList.length];\n\n        seriesModel.getData().setVisual({\n            'areaColor': areaColor,\n            'color': color\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME 公用？\n/**\n * @param {Array.<module:echarts/data/List>} datas\n * @param {string} statisticType 'average' 'sum'\n * @inner\n */\nfunction dataStatistics(datas, statisticType) {\n    var dataNameMap = {};\n\n    each$1(datas, function (data) {\n        data.each(data.mapDimension('value'), function (value, idx) {\n            // Add prefix to avoid conflict with Object.prototype.\n            var mapKey = 'ec-' + data.getName(idx);\n            dataNameMap[mapKey] = dataNameMap[mapKey] || [];\n            if (!isNaN(value)) {\n                dataNameMap[mapKey].push(value);\n            }\n        });\n    });\n\n    return datas[0].map(datas[0].mapDimension('value'), function (value, idx) {\n        var mapKey = 'ec-' + datas[0].getName(idx);\n        var sum = 0;\n        var min = Infinity;\n        var max = -Infinity;\n        var len = dataNameMap[mapKey].length;\n        for (var i = 0; i < len; i++) {\n            min = Math.min(min, dataNameMap[mapKey][i]);\n            max = Math.max(max, dataNameMap[mapKey][i]);\n            sum += dataNameMap[mapKey][i];\n        }\n        var result;\n        if (statisticType === 'min') {\n            result = min;\n        }\n        else if (statisticType === 'max') {\n            result = max;\n        }\n        else if (statisticType === 'average') {\n            result = sum / len;\n        }\n        else {\n            result = sum;\n        }\n        return len === 0 ? NaN : result;\n    });\n}\n\nvar mapDataStatistic = function (ecModel) {\n    var seriesGroups = {};\n    ecModel.eachSeriesByType('map', function (seriesModel) {\n        var hostGeoModel = seriesModel.getHostGeoModel();\n        var key = hostGeoModel ? 'o' + hostGeoModel.id : 'i' + seriesModel.getMapType();\n        (seriesGroups[key] = seriesGroups[key] || []).push(seriesModel);\n    });\n\n    each$1(seriesGroups, function (seriesList, key) {\n        var data = dataStatistics(\n            map(seriesList, function (seriesModel) {\n                return seriesModel.getData();\n            }),\n            seriesList[0].get('mapValueCalculation')\n        );\n\n        for (var i = 0; i < seriesList.length; i++) {\n            seriesList[i].originalData = seriesList[i].getData();\n        }\n\n        // FIXME Put where?\n        for (var i = 0; i < seriesList.length; i++) {\n            seriesList[i].seriesGroup = seriesList;\n            seriesList[i].needsDrawMap = i === 0 && !seriesList[i].getHostGeoModel();\n\n            seriesList[i].setData(data.cloneShallow());\n            seriesList[i].mainSeries = seriesList[0];\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar backwardCompat$2 = function (option) {\n    // Save geoCoord\n    var mapSeries = [];\n    each$1(option.series, function (seriesOpt) {\n        if (seriesOpt && seriesOpt.type === 'map') {\n            mapSeries.push(seriesOpt);\n            seriesOpt.map = seriesOpt.map || seriesOpt.mapType;\n            // Put x, y, width, height, x2, y2 in the top level\n            defaults(seriesOpt, seriesOpt.mapLocation);\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterLayout(mapSymbolLayout);\nregisterVisual(mapVisual);\nregisterProcessor(PRIORITY.PROCESSOR.STATISTIC, mapDataStatistic);\nregisterPreprocessor(backwardCompat$2);\n\ncreateDataSelectAction('map', [{\n    type: 'mapToggleSelect',\n    event: 'mapselectchanged',\n    method: 'toggleSelected'\n}, {\n    type: 'mapSelect',\n    event: 'mapselected',\n    method: 'select'\n}, {\n    type: 'mapUnSelect',\n    event: 'mapunselected',\n    method: 'unSelect'\n}]);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Link lists and struct (graph or tree)\n */\n\nvar each$7 = each$1;\n\nvar DATAS = '\\0__link_datas';\nvar MAIN_DATA = '\\0__link_mainData';\n\n// Caution:\n// In most case, either list or its shallow clones (see list.cloneShallow)\n// is active in echarts process. So considering heap memory consumption,\n// we do not clone tree or graph, but share them among list and its shallow clones.\n// But in some rare case, we have to keep old list (like do animation in chart). So\n// please take care that both the old list and the new list share the same tree/graph.\n\n/**\n * @param {Object} opt\n * @param {module:echarts/data/List} opt.mainData\n * @param {Object} [opt.struct] For example, instance of Graph or Tree.\n * @param {string} [opt.structAttr] designation: list[structAttr] = struct;\n * @param {Object} [opt.datas] {dataType: data},\n *                 like: {node: nodeList, edge: edgeList}.\n *                 Should contain mainData.\n * @param {Object} [opt.datasAttr] {dataType: attr},\n *                 designation: struct[datasAttr[dataType]] = list;\n */\nfunction linkList(opt) {\n    var mainData = opt.mainData;\n    var datas = opt.datas;\n\n    if (!datas) {\n        datas = {main: mainData};\n        opt.datasAttr = {main: 'data'};\n    }\n    opt.datas = opt.mainData = null;\n\n    linkAll(mainData, datas, opt);\n\n    // Porxy data original methods.\n    each$7(datas, function (data) {\n        each$7(mainData.TRANSFERABLE_METHODS, function (methodName) {\n            data.wrapMethod(methodName, curry(transferInjection, opt));\n        });\n\n    });\n\n    // Beyond transfer, additional features should be added to `cloneShallow`.\n    mainData.wrapMethod('cloneShallow', curry(cloneShallowInjection, opt));\n\n    // Only mainData trigger change, because struct.update may trigger\n    // another changable methods, which may bring about dead lock.\n    each$7(mainData.CHANGABLE_METHODS, function (methodName) {\n        mainData.wrapMethod(methodName, curry(changeInjection, opt));\n    });\n\n    // Make sure datas contains mainData.\n    assert$1(datas[mainData.dataType] === mainData);\n}\n\nfunction transferInjection(opt, res) {\n    if (isMainData(this)) {\n        // Transfer datas to new main data.\n        var datas = extend({}, this[DATAS]);\n        datas[this.dataType] = res;\n        linkAll(res, datas, opt);\n    }\n    else {\n        // Modify the reference in main data to point newData.\n        linkSingle(res, this.dataType, this[MAIN_DATA], opt);\n    }\n    return res;\n}\n\nfunction changeInjection(opt, res) {\n    opt.struct && opt.struct.update(this);\n    return res;\n}\n\nfunction cloneShallowInjection(opt, res) {\n    // cloneShallow, which brings about some fragilities, may be inappropriate\n    // to be exposed as an API. So for implementation simplicity we can make\n    // the restriction that cloneShallow of not-mainData should not be invoked\n    // outside, but only be invoked here.\n    each$7(res[DATAS], function (data, dataType) {\n        data !== res && linkSingle(data.cloneShallow(), dataType, res, opt);\n    });\n    return res;\n}\n\n/**\n * Supplement method to List.\n *\n * @public\n * @param {string} [dataType] If not specified, return mainData.\n * @return {module:echarts/data/List}\n */\nfunction getLinkedData(dataType) {\n    var mainData = this[MAIN_DATA];\n    return (dataType == null || mainData == null)\n        ? mainData\n        : mainData[DATAS][dataType];\n}\n\nfunction isMainData(data) {\n    return data[MAIN_DATA] === data;\n}\n\nfunction linkAll(mainData, datas, opt) {\n    mainData[DATAS] = {};\n    each$7(datas, function (data, dataType) {\n        linkSingle(data, dataType, mainData, opt);\n    });\n}\n\nfunction linkSingle(data, dataType, mainData, opt) {\n    mainData[DATAS][dataType] = data;\n    data[MAIN_DATA] = mainData;\n    data.dataType = dataType;\n\n    if (opt.struct) {\n        data[opt.structAttr] = opt.struct;\n        opt.struct[opt.datasAttr[dataType]] = data;\n    }\n\n    // Supplement method.\n    data.getLinkedData = getLinkedData;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Tree data structure\n *\n * @module echarts/data/Tree\n */\n\n/**\n * @constructor module:echarts/data/Tree~TreeNode\n * @param {string} name\n * @param {module:echarts/data/Tree} hostTree\n */\nvar TreeNode = function (name, hostTree) {\n    /**\n     * @type {string}\n     */\n    this.name = name || '';\n\n    /**\n     * Depth of node\n     *\n     * @type {number}\n     * @readOnly\n     */\n    this.depth = 0;\n\n    /**\n     * Height of the subtree rooted at this node.\n     * @type {number}\n     * @readOnly\n     */\n    this.height = 0;\n\n    /**\n     * @type {module:echarts/data/Tree~TreeNode}\n     * @readOnly\n     */\n    this.parentNode = null;\n\n    /**\n     * Reference to list item.\n     * Do not persistent dataIndex outside,\n     * besause it may be changed by list.\n     * If dataIndex -1,\n     * this node is logical deleted (filtered) in list.\n     *\n     * @type {Object}\n     * @readOnly\n     */\n    this.dataIndex = -1;\n\n    /**\n     * @type {Array.<module:echarts/data/Tree~TreeNode>}\n     * @readOnly\n     */\n    this.children = [];\n\n    /**\n     * @type {Array.<module:echarts/data/Tree~TreeNode>}\n     * @pubilc\n     */\n    this.viewChildren = [];\n\n    /**\n     * @type {moduel:echarts/data/Tree}\n     * @readOnly\n     */\n    this.hostTree = hostTree;\n};\n\nTreeNode.prototype = {\n\n    constructor: TreeNode,\n\n    /**\n     * The node is removed.\n     * @return {boolean} is removed.\n     */\n    isRemoved: function () {\n        return this.dataIndex < 0;\n    },\n\n    /**\n     * Travel this subtree (include this node).\n     * Usage:\n     *    node.eachNode(function () { ... }); // preorder\n     *    node.eachNode('preorder', function () { ... }); // preorder\n     *    node.eachNode('postorder', function () { ... }); // postorder\n     *    node.eachNode(\n     *        {order: 'postorder', attr: 'viewChildren'},\n     *        function () { ... }\n     *    ); // postorder\n     *\n     * @param {(Object|string)} options If string, means order.\n     * @param {string=} options.order 'preorder' or 'postorder'\n     * @param {string=} options.attr 'children' or 'viewChildren'\n     * @param {Function} cb If in preorder and return false,\n     *                      its subtree will not be visited.\n     * @param {Object} [context]\n     */\n    eachNode: function (options, cb, context) {\n        if (typeof options === 'function') {\n            context = cb;\n            cb = options;\n            options = null;\n        }\n\n        options = options || {};\n        if (isString(options)) {\n            options = {order: options};\n        }\n\n        var order = options.order || 'preorder';\n        var children = this[options.attr || 'children'];\n\n        var suppressVisitSub;\n        order === 'preorder' && (suppressVisitSub = cb.call(context, this));\n\n        for (var i = 0; !suppressVisitSub && i < children.length; i++) {\n            children[i].eachNode(options, cb, context);\n        }\n\n        order === 'postorder' && cb.call(context, this);\n    },\n\n    /**\n     * Update depth and height of this subtree.\n     *\n     * @param  {number} depth\n     */\n    updateDepthAndHeight: function (depth) {\n        var height = 0;\n        this.depth = depth;\n        for (var i = 0; i < this.children.length; i++) {\n            var child = this.children[i];\n            child.updateDepthAndHeight(depth + 1);\n            if (child.height > height) {\n                height = child.height;\n            }\n        }\n        this.height = height + 1;\n    },\n\n    /**\n     * @param  {string} id\n     * @return {module:echarts/data/Tree~TreeNode}\n     */\n    getNodeById: function (id) {\n        if (this.getId() === id) {\n            return this;\n        }\n        for (var i = 0, children = this.children, len = children.length; i < len; i++) {\n            var res = children[i].getNodeById(id);\n            if (res) {\n                return res;\n            }\n        }\n    },\n\n    /**\n     * @param {module:echarts/data/Tree~TreeNode} node\n     * @return {boolean}\n     */\n    contains: function (node) {\n        if (node === this) {\n            return true;\n        }\n        for (var i = 0, children = this.children, len = children.length; i < len; i++) {\n            var res = children[i].contains(node);\n            if (res) {\n                return res;\n            }\n        }\n    },\n\n    /**\n     * @param {boolean} includeSelf Default false.\n     * @return {Array.<module:echarts/data/Tree~TreeNode>} order: [root, child, grandchild, ...]\n     */\n    getAncestors: function (includeSelf) {\n        var ancestors = [];\n        var node = includeSelf ? this : this.parentNode;\n        while (node) {\n            ancestors.push(node);\n            node = node.parentNode;\n        }\n        ancestors.reverse();\n        return ancestors;\n    },\n\n    /**\n     * @param {string|Array=} [dimension='value'] Default 'value'. can be 0, 1, 2, 3\n     * @return {number} Value.\n     */\n    getValue: function (dimension) {\n        var data = this.hostTree.data;\n        return data.get(data.getDimension(dimension || 'value'), this.dataIndex);\n    },\n\n    /**\n     * @param {Object} layout\n     * @param {boolean=} [merge=false]\n     */\n    setLayout: function (layout, merge$$1) {\n        this.dataIndex >= 0\n            && this.hostTree.data.setItemLayout(this.dataIndex, layout, merge$$1);\n    },\n\n    /**\n     * @return {Object} layout\n     */\n    getLayout: function () {\n        return this.hostTree.data.getItemLayout(this.dataIndex);\n    },\n\n    /**\n     * @param {string} [path]\n     * @return {module:echarts/model/Model}\n     */\n    getModel: function (path) {\n        if (this.dataIndex < 0) {\n            return;\n        }\n        var hostTree = this.hostTree;\n        var itemModel = hostTree.data.getItemModel(this.dataIndex);\n        var levelModel = this.getLevelModel();\n        var leavesModel;\n        if (!levelModel && (this.children.length === 0 || (this.children.length !== 0 && this.isExpand === false))) {\n            leavesModel = this.getLeavesModel();\n        }\n        return itemModel.getModel(path, (levelModel || leavesModel || hostTree.hostModel).getModel(path));\n    },\n\n    /**\n     * @return {module:echarts/model/Model}\n     */\n    getLevelModel: function () {\n        return (this.hostTree.levelModels || [])[this.depth];\n    },\n\n    /**\n     * @return {module:echarts/model/Model}\n     */\n    getLeavesModel: function () {\n        return this.hostTree.leavesModel;\n    },\n\n    /**\n     * @example\n     *  setItemVisual('color', color);\n     *  setItemVisual({\n     *      'color': color\n     *  });\n     */\n    setVisual: function (key, value) {\n        this.dataIndex >= 0\n            && this.hostTree.data.setItemVisual(this.dataIndex, key, value);\n    },\n\n    /**\n     * Get item visual\n     */\n    getVisual: function (key, ignoreParent) {\n        return this.hostTree.data.getItemVisual(this.dataIndex, key, ignoreParent);\n    },\n\n    /**\n     * @public\n     * @return {number}\n     */\n    getRawIndex: function () {\n        return this.hostTree.data.getRawIndex(this.dataIndex);\n    },\n\n    /**\n     * @public\n     * @return {string}\n     */\n    getId: function () {\n        return this.hostTree.data.getId(this.dataIndex);\n    },\n\n    /**\n     * if this is an ancestor of another node\n     *\n     * @public\n     * @param {TreeNode} node another node\n     * @return {boolean} if is ancestor\n     */\n    isAncestorOf: function (node) {\n        var parent = node.parentNode;\n        while (parent) {\n            if (parent === this) {\n                return true;\n            }\n            parent = parent.parentNode;\n        }\n        return false;\n    },\n\n    /**\n     * if this is an descendant of another node\n     *\n     * @public\n     * @param {TreeNode} node another node\n     * @return {boolean} if is descendant\n     */\n    isDescendantOf: function (node) {\n        return node !== this && node.isAncestorOf(this);\n    }\n};\n\n/**\n * @constructor\n * @alias module:echarts/data/Tree\n * @param {module:echarts/model/Model} hostModel\n * @param {Array.<Object>} levelOptions\n * @param {Object} leavesOption\n */\nfunction Tree(hostModel, levelOptions, leavesOption) {\n    /**\n     * @type {module:echarts/data/Tree~TreeNode}\n     * @readOnly\n     */\n    this.root;\n\n    /**\n     * @type {module:echarts/data/List}\n     * @readOnly\n     */\n    this.data;\n\n    /**\n     * Index of each item is the same as the raw index of coresponding list item.\n     * @private\n     * @type {Array.<module:echarts/data/Tree~TreeNode}\n     */\n    this._nodes = [];\n\n    /**\n     * @private\n     * @readOnly\n     * @type {module:echarts/model/Model}\n     */\n    this.hostModel = hostModel;\n\n    /**\n     * @private\n     * @readOnly\n     * @type {Array.<module:echarts/model/Model}\n     */\n    this.levelModels = map(levelOptions || [], function (levelDefine) {\n        return new Model(levelDefine, hostModel, hostModel.ecModel);\n    });\n\n    this.leavesModel = new Model(leavesOption || {}, hostModel, hostModel.ecModel);\n}\n\nTree.prototype = {\n\n    constructor: Tree,\n\n    type: 'tree',\n\n    /**\n     * Travel this subtree (include this node).\n     * Usage:\n     *    node.eachNode(function () { ... }); // preorder\n     *    node.eachNode('preorder', function () { ... }); // preorder\n     *    node.eachNode('postorder', function () { ... }); // postorder\n     *    node.eachNode(\n     *        {order: 'postorder', attr: 'viewChildren'},\n     *        function () { ... }\n     *    ); // postorder\n     *\n     * @param {(Object|string)} options If string, means order.\n     * @param {string=} options.order 'preorder' or 'postorder'\n     * @param {string=} options.attr 'children' or 'viewChildren'\n     * @param {Function} cb\n     * @param {Object}   [context]\n     */\n    eachNode: function (options, cb, context) {\n        this.root.eachNode(options, cb, context);\n    },\n\n    /**\n     * @param {number} dataIndex\n     * @return {module:echarts/data/Tree~TreeNode}\n     */\n    getNodeByDataIndex: function (dataIndex) {\n        var rawIndex = this.data.getRawIndex(dataIndex);\n        return this._nodes[rawIndex];\n    },\n\n    /**\n     * @param {string} name\n     * @return {module:echarts/data/Tree~TreeNode}\n     */\n    getNodeByName: function (name) {\n        return this.root.getNodeByName(name);\n    },\n\n    /**\n     * Update item available by list,\n     * when list has been performed options like 'filterSelf' or 'map'.\n     */\n    update: function () {\n        var data = this.data;\n        var nodes = this._nodes;\n\n        for (var i = 0, len = nodes.length; i < len; i++) {\n            nodes[i].dataIndex = -1;\n        }\n\n        for (var i = 0, len = data.count(); i < len; i++) {\n            nodes[data.getRawIndex(i)].dataIndex = i;\n        }\n    },\n\n    /**\n     * Clear all layouts\n     */\n    clearLayouts: function () {\n        this.data.clearItemLayouts();\n    }\n};\n\n/**\n * data node format:\n * {\n *     name: ...\n *     value: ...\n *     children: [\n *         {\n *             name: ...\n *             value: ...\n *             children: ...\n *         },\n *         ...\n *     ]\n * }\n *\n * @static\n * @param {Object} dataRoot Root node.\n * @param {module:echarts/model/Model} hostModel\n * @param {Object} treeOptions\n * @param {Array.<Object>} treeOptions.levels\n * @param {Array.<Object>} treeOptions.leaves\n * @return module:echarts/data/Tree\n */\nTree.createTree = function (dataRoot, hostModel, treeOptions) {\n\n    var tree = new Tree(hostModel, treeOptions.levels, treeOptions.leaves);\n    var listData = [];\n    var dimMax = 1;\n\n    buildHierarchy(dataRoot);\n\n    function buildHierarchy(dataNode, parentNode) {\n        var value = dataNode.value;\n        dimMax = Math.max(dimMax, isArray(value) ? value.length : 1);\n\n        listData.push(dataNode);\n\n        var node = new TreeNode(dataNode.name, tree);\n        parentNode\n            ? addChild(node, parentNode)\n            : (tree.root = node);\n\n        tree._nodes.push(node);\n\n        var children = dataNode.children;\n        if (children) {\n            for (var i = 0; i < children.length; i++) {\n                buildHierarchy(children[i], node);\n            }\n        }\n    }\n\n    tree.root.updateDepthAndHeight(0);\n\n    var dimensionsInfo = createDimensions(listData, {\n        coordDimensions: ['value'],\n        dimensionsCount: dimMax\n    });\n\n    var list = new List(dimensionsInfo, hostModel);\n    list.initData(listData);\n\n    linkList({\n        mainData: list,\n        struct: tree,\n        structAttr: 'tree'\n    });\n\n    tree.update();\n\n    return tree;\n};\n\n/**\n * It is needed to consider the mess of 'list', 'hostModel' when creating a TreeNote,\n * so this function is not ready and not necessary to be public.\n *\n * @param {(module:echarts/data/Tree~TreeNode|Object)} child\n */\nfunction addChild(child, node) {\n    var children = node.children;\n    if (child.parentNode === node) {\n        return;\n    }\n\n    children.push(child);\n    child.parentNode = node;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Create data struct and define tree view's series model\n * @author Deqing Li(annong035@gmail.com)\n */\n\nSeriesModel.extend({\n\n    type: 'series.tree',\n\n    layoutInfo: null,\n\n    // can support the position parameters 'left', 'top','right','bottom', 'width',\n    // 'height' in the setOption() with 'merge' mode normal.\n    layoutMode: 'box',\n\n    /**\n     * Init a tree data structure from data in option series\n     * @param  {Object} option  the object used to config echarts view\n     * @return {module:echarts/data/List} storage initial data\n     */\n    getInitialData: function (option) {\n\n        //create an virtual root\n        var root = {name: option.name, children: option.data};\n\n        var leaves = option.leaves || {};\n\n        var treeOption = {};\n\n        treeOption.leaves = leaves;\n\n        var tree = Tree.createTree(root, this, treeOption);\n\n        var treeDepth = 0;\n\n        tree.eachNode('preorder', function (node) {\n            if (node.depth > treeDepth) {\n                treeDepth = node.depth;\n            }\n        });\n\n        var expandAndCollapse = option.expandAndCollapse;\n        var expandTreeDepth = (expandAndCollapse && option.initialTreeDepth >= 0)\n            ? option.initialTreeDepth : treeDepth;\n\n        tree.root.eachNode('preorder', function (node) {\n            var item = node.hostTree.data.getRawDataItem(node.dataIndex);\n            // Add item.collapsed != null, because users can collapse node original in the series.data.\n            node.isExpand = (item && item.collapsed != null)\n                ? !item.collapsed\n                : node.depth <= expandTreeDepth;\n        });\n\n        return tree.data;\n    },\n\n    /**\n     * Make the configuration 'orient' backward compatibly, with 'horizontal = LR', 'vertical = TB'.\n     * @returns {string} orient\n     */\n    getOrient: function () {\n        var orient = this.get('orient');\n        if (orient === 'horizontal') {\n            orient = 'LR';\n        }\n        else if (orient === 'vertical') {\n            orient = 'TB';\n        }\n        return orient;\n    },\n\n    setZoom: function (zoom) {\n        this.option.zoom = zoom;\n    },\n\n    setCenter: function (center) {\n        this.option.center = center;\n    },\n\n    /**\n     * @override\n     * @param {number} dataIndex\n     */\n    formatTooltip: function (dataIndex) {\n        var tree = this.getData().tree;\n        var realRoot = tree.root.children[0];\n        var node = tree.getNodeByDataIndex(dataIndex);\n        var value = node.getValue();\n        var name = node.name;\n        while (node && (node !== realRoot)) {\n            name = node.parentNode.name + '.' + name;\n            node = node.parentNode;\n        }\n        return encodeHTML(name + (\n            (isNaN(value) || value == null) ? '' : ' : ' + value\n        ));\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'view',\n\n        // the position of the whole view\n        left: '12%',\n        top: '12%',\n        right: '12%',\n        bottom: '12%',\n\n        // the layout of the tree, two value can be selected, 'orthogonal' or 'radial'\n        layout: 'orthogonal',\n\n        roam: false, // true | false | 'move' | 'scale', see module:component/helper/RoamController.\n        // Symbol size scale ratio in roam\n        nodeScaleRatio: 0.4,\n\n        // Default on center of graph\n        center: null,\n\n        zoom: 1,\n\n        // The orient of orthoginal layout, can be setted to 'LR', 'TB', 'RL', 'BT'.\n        // and the backward compatibility configuration 'horizontal = LR', 'vertical = TB'.\n        orient: 'LR',\n\n        symbol: 'emptyCircle',\n\n        symbolSize: 7,\n\n        expandAndCollapse: true,\n\n        initialTreeDepth: 2,\n\n        lineStyle: {\n            color: '#ccc',\n            width: 1.5,\n            curveness: 0.5\n        },\n\n        itemStyle: {\n            color: 'lightsteelblue',\n            borderColor: '#c23531',\n            borderWidth: 1.5\n        },\n\n        label: {\n            show: true,\n            color: '#555'\n        },\n\n        leaves: {\n            label: {\n                show: true\n            }\n        },\n\n        animationEasing: 'linear',\n\n        animationDuration: 700,\n\n        animationDurationUpdate: 1000\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The tree layoutHelper implementation was originally copied from\n* \"d3.js\"(https://github.com/d3/d3-hierarchy) with\n* some modifications made for this project.\n* (see more details in the comment of the specific method below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the licence of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\n/**\n * @file The layout algorithm of node-link tree diagrams. Here we using Reingold-Tilford algorithm to drawing\n *       the tree.\n */\n\n/**\n * Initialize all computational message for following algorithm.\n *\n * @param  {module:echarts/data/Tree~TreeNode} root   The virtual root of the tree.\n */\nfunction init$2(root) {\n    root.hierNode = {\n        defaultAncestor: null,\n        ancestor: root,\n        prelim: 0,\n        modifier: 0,\n        change: 0,\n        shift: 0,\n        i: 0,\n        thread: null\n    };\n\n    var nodes = [root];\n    var node;\n    var children;\n\n    while (node = nodes.pop()) { // jshint ignore:line\n        children = node.children;\n        if (node.isExpand && children.length) {\n            var n = children.length;\n            for (var i = n - 1; i >= 0; i--) {\n                var child = children[i];\n                child.hierNode = {\n                    defaultAncestor: null,\n                    ancestor: child,\n                    prelim: 0,\n                    modifier: 0,\n                    change: 0,\n                    shift: 0,\n                    i: i,\n                    thread: null\n                };\n                nodes.push(child);\n            }\n        }\n    }\n}\n\n/**\n * The implementation of this function was originally copied from \"d3.js\"\n * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n *\n * Computes a preliminary x coordinate for node. Before that, this function is\n * applied recursively to the children of node, as well as the function\n * apportion(). After spacing out the children by calling executeShifts(), the\n * node is placed to the midpoint of its outermost children.\n *\n * @param  {module:echarts/data/Tree~TreeNode} node\n * @param {Function} separation\n */\nfunction firstWalk(node, separation) {\n    var children = node.isExpand ? node.children : [];\n    var siblings = node.parentNode.children;\n    var subtreeW = node.hierNode.i ? siblings[node.hierNode.i - 1] : null;\n    if (children.length) {\n        executeShifts(node);\n        var midPoint = (children[0].hierNode.prelim + children[children.length - 1].hierNode.prelim) / 2;\n        if (subtreeW) {\n            node.hierNode.prelim = subtreeW.hierNode.prelim + separation(node, subtreeW);\n            node.hierNode.modifier = node.hierNode.prelim - midPoint;\n        }\n        else {\n            node.hierNode.prelim = midPoint;\n        }\n    }\n    else if (subtreeW) {\n        node.hierNode.prelim = subtreeW.hierNode.prelim + separation(node, subtreeW);\n    }\n    node.parentNode.hierNode.defaultAncestor = apportion(\n        node,\n        subtreeW,\n        node.parentNode.hierNode.defaultAncestor || siblings[0],\n        separation\n    );\n}\n\n\n/**\n * The implementation of this function was originally copied from \"d3.js\"\n * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n *\n * Computes all real x-coordinates by summing up the modifiers recursively.\n *\n * @param  {module:echarts/data/Tree~TreeNode} node\n */\nfunction secondWalk(node) {\n    var nodeX = node.hierNode.prelim + node.parentNode.hierNode.modifier;\n    node.setLayout({x: nodeX}, true);\n    node.hierNode.modifier += node.parentNode.hierNode.modifier;\n}\n\n\nfunction separation(cb) {\n    return arguments.length ? cb : defaultSeparation;\n}\n\n/**\n * Transform the common coordinate to radial coordinate.\n *\n * @param  {number} x\n * @param  {number} y\n * @return {Object}\n */\nfunction radialCoordinate(x, y) {\n    var radialCoor = {};\n    x -= Math.PI / 2;\n    radialCoor.x = y * Math.cos(x);\n    radialCoor.y = y * Math.sin(x);\n    return radialCoor;\n}\n\n/**\n * Get the layout position of the whole view.\n *\n * @param {module:echarts/model/Series} seriesModel  the model object of sankey series\n * @param {module:echarts/ExtensionAPI} api  provide the API list that the developer can call\n * @return {module:zrender/core/BoundingRect}  size of rect to draw the sankey view\n */\nfunction getViewRect(seriesModel, api) {\n    return getLayoutRect(\n        seriesModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        }\n    );\n}\n\n/**\n * All other shifts, applied to the smaller subtrees between w- and w+, are\n * performed by this function.\n *\n * The implementation of this function was originally copied from \"d3.js\"\n * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n *\n * @param  {module:echarts/data/Tree~TreeNode} node\n */\nfunction executeShifts(node) {\n    var children = node.children;\n    var n = children.length;\n    var shift = 0;\n    var change = 0;\n    while (--n >= 0) {\n        var child = children[n];\n        child.hierNode.prelim += shift;\n        child.hierNode.modifier += shift;\n        change += child.hierNode.change;\n        shift += child.hierNode.shift + change;\n    }\n}\n\n/**\n * The implementation of this function was originally copied from \"d3.js\"\n * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n *\n * The core of the algorithm. Here, a new subtree is combined with the\n * previous subtrees. Threads are used to traverse the inside and outside\n * contours of the left and right subtree up to the highest common level.\n * Whenever two nodes of the inside contours conflict, we compute the left\n * one of the greatest uncommon ancestors using the function nextAncestor()\n * and call moveSubtree() to shift the subtree and prepare the shifts of\n * smaller subtrees. Finally, we add a new thread (if necessary).\n *\n * @param  {module:echarts/data/Tree~TreeNode} subtreeV\n * @param  {module:echarts/data/Tree~TreeNode} subtreeW\n * @param  {module:echarts/data/Tree~TreeNode} ancestor\n * @param  {Function} separation\n * @return {module:echarts/data/Tree~TreeNode}\n */\nfunction apportion(subtreeV, subtreeW, ancestor, separation) {\n\n    if (subtreeW) {\n        var nodeOutRight = subtreeV;\n        var nodeInRight = subtreeV;\n        var nodeOutLeft = nodeInRight.parentNode.children[0];\n        var nodeInLeft = subtreeW;\n\n        var sumOutRight = nodeOutRight.hierNode.modifier;\n        var sumInRight = nodeInRight.hierNode.modifier;\n        var sumOutLeft = nodeOutLeft.hierNode.modifier;\n        var sumInLeft = nodeInLeft.hierNode.modifier;\n\n        while (nodeInLeft = nextRight(nodeInLeft), nodeInRight = nextLeft(nodeInRight), nodeInLeft && nodeInRight) {\n            nodeOutRight = nextRight(nodeOutRight);\n            nodeOutLeft = nextLeft(nodeOutLeft);\n            nodeOutRight.hierNode.ancestor = subtreeV;\n            var shift = nodeInLeft.hierNode.prelim + sumInLeft - nodeInRight.hierNode.prelim\n                    - sumInRight + separation(nodeInLeft, nodeInRight);\n            if (shift > 0) {\n                moveSubtree(nextAncestor(nodeInLeft, subtreeV, ancestor), subtreeV, shift);\n                sumInRight += shift;\n                sumOutRight += shift;\n            }\n            sumInLeft += nodeInLeft.hierNode.modifier;\n            sumInRight += nodeInRight.hierNode.modifier;\n            sumOutRight += nodeOutRight.hierNode.modifier;\n            sumOutLeft += nodeOutLeft.hierNode.modifier;\n        }\n        if (nodeInLeft && !nextRight(nodeOutRight)) {\n            nodeOutRight.hierNode.thread = nodeInLeft;\n            nodeOutRight.hierNode.modifier += sumInLeft - sumOutRight;\n\n        }\n        if (nodeInRight && !nextLeft(nodeOutLeft)) {\n            nodeOutLeft.hierNode.thread = nodeInRight;\n            nodeOutLeft.hierNode.modifier += sumInRight - sumOutLeft;\n            ancestor = subtreeV;\n        }\n    }\n    return ancestor;\n}\n\n/**\n * This function is used to traverse the right contour of a subtree.\n * It returns the rightmost child of node or the thread of node. The function\n * returns null if and only if node is on the highest depth of its subtree.\n *\n * @param  {module:echarts/data/Tree~TreeNode} node\n * @return {module:echarts/data/Tree~TreeNode}\n */\nfunction nextRight(node) {\n    var children = node.children;\n    return children.length && node.isExpand ? children[children.length - 1] : node.hierNode.thread;\n}\n\n/**\n * This function is used to traverse the left contour of a subtree (or a subforest).\n * It returns the leftmost child of node or the thread of node. The function\n * returns null if and only if node is on the highest depth of its subtree.\n *\n * @param  {module:echarts/data/Tree~TreeNode} node\n * @return {module:echarts/data/Tree~TreeNode}\n */\nfunction nextLeft(node) {\n    var children = node.children;\n    return children.length && node.isExpand ? children[0] : node.hierNode.thread;\n}\n\n/**\n * If nodeInLeft’s ancestor is a sibling of node, returns nodeInLeft’s ancestor.\n * Otherwise, returns the specified ancestor.\n *\n * @param  {module:echarts/data/Tree~TreeNode} nodeInLeft\n * @param  {module:echarts/data/Tree~TreeNode} node\n * @param  {module:echarts/data/Tree~TreeNode} ancestor\n * @return {module:echarts/data/Tree~TreeNode}\n */\nfunction nextAncestor(nodeInLeft, node, ancestor) {\n    return nodeInLeft.hierNode.ancestor.parentNode === node.parentNode\n        ? nodeInLeft.hierNode.ancestor : ancestor;\n}\n\n/**\n * The implementation of this function was originally copied from \"d3.js\"\n * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n *\n * Shifts the current subtree rooted at wr.\n * This is done by increasing prelim(w+) and modifier(w+) by shift.\n *\n * @param  {module:echarts/data/Tree~TreeNode} wl\n * @param  {module:echarts/data/Tree~TreeNode} wr\n * @param  {number} shift [description]\n */\nfunction moveSubtree(wl, wr, shift) {\n    var change = shift / (wr.hierNode.i - wl.hierNode.i);\n    wr.hierNode.change -= change;\n    wr.hierNode.shift += shift;\n    wr.hierNode.modifier += shift;\n    wr.hierNode.prelim += shift;\n    wl.hierNode.change += change;\n}\n\n/**\n * The implementation of this function was originally copied from \"d3.js\"\n * <https://github.com/d3/d3-hierarchy/blob/4c1f038f2725d6eae2e49b61d01456400694bac4/src/tree.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n */\nfunction defaultSeparation(node1, node2) {\n    return node1.parentNode === node2.parentNode ? 1 : 2;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file This file used to draw tree view.\n * @author Deqing Li(annong035@gmail.com)\n */\n\nextendChartView({\n\n    type: 'tree',\n\n    /**\n     * Init the chart\n     * @override\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    init: function (ecModel, api) {\n\n        /**\n         * @private\n         * @type {module:echarts/data/Tree}\n         */\n        this._oldTree;\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this._mainGroup = new Group();\n\n        /**\n         * @private\n         * @type {module:echarts/componet/helper/RoamController}\n         */\n        this._controller = new RoamController(api.getZr());\n\n        this._controllerHost = {target: this.group};\n\n        this.group.add(this._mainGroup);\n    },\n\n    render: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n\n        var layoutInfo = seriesModel.layoutInfo;\n\n        var group = this._mainGroup;\n\n        var layout = seriesModel.get('layout');\n\n        if (layout === 'radial') {\n            group.attr('position', [layoutInfo.x + layoutInfo.width / 2, layoutInfo.y + layoutInfo.height / 2]);\n        }\n        else {\n            group.attr('position', [layoutInfo.x, layoutInfo.y]);\n        }\n\n        this._updateViewCoordSys(seriesModel);\n        this._updateController(seriesModel, ecModel, api);\n\n        var oldData = this._data;\n\n        var seriesScope = {\n            expandAndCollapse: seriesModel.get('expandAndCollapse'),\n            layout: layout,\n            orient: seriesModel.getOrient(),\n            curvature: seriesModel.get('lineStyle.curveness'),\n            symbolRotate: seriesModel.get('symbolRotate'),\n            symbolOffset: seriesModel.get('symbolOffset'),\n            hoverAnimation: seriesModel.get('hoverAnimation'),\n            useNameLabel: true,\n            fadeIn: true\n        };\n\n        data.diff(oldData)\n            .add(function (newIdx) {\n                if (symbolNeedsDraw$1(data, newIdx)) {\n                    // Create node and edge\n                    updateNode(data, newIdx, null, group, seriesModel, seriesScope);\n                }\n            })\n            .update(function (newIdx, oldIdx) {\n                var symbolEl = oldData.getItemGraphicEl(oldIdx);\n                if (!symbolNeedsDraw$1(data, newIdx)) {\n                    symbolEl && removeNode(oldData, oldIdx, symbolEl, group, seriesModel, seriesScope);\n                    return;\n                }\n                // Update node and edge\n                updateNode(data, newIdx, symbolEl, group, seriesModel, seriesScope);\n            })\n            .remove(function (oldIdx) {\n                var symbolEl = oldData.getItemGraphicEl(oldIdx);\n                // When remove a collapsed node of subtree, since the collapsed\n                // node haven't been initialized with a symbol element,\n                // you can't found it's symbol element through index.\n                // so if we want to remove the symbol element we should insure\n                // that the symbol element is not null.\n                if (symbolEl) {\n                    removeNode(oldData, oldIdx, symbolEl, group, seriesModel, seriesScope);\n                }\n            })\n            .execute();\n\n        this._nodeScaleRatio = seriesModel.get('nodeScaleRatio');\n\n        this._updateNodeAndLinkScale(seriesModel);\n\n        if (seriesScope.expandAndCollapse === true) {\n            data.eachItemGraphicEl(function (el, dataIndex) {\n                el.off('click').on('click', function () {\n                    api.dispatchAction({\n                        type: 'treeExpandAndCollapse',\n                        seriesId: seriesModel.id,\n                        dataIndex: dataIndex\n                    });\n                });\n            });\n        }\n        this._data = data;\n    },\n\n    _updateViewCoordSys: function (seriesModel) {\n        var data = seriesModel.getData();\n        var points = [];\n        data.each(function (idx) {\n            var layout = data.getItemLayout(idx);\n            if (layout && !isNaN(layout.x) && !isNaN(layout.y)) {\n                points.push([+layout.x, +layout.y]);\n            }\n        });\n        var min = [];\n        var max = [];\n        fromPoints(points, min, max);\n        // If width or height is 0\n        if (max[0] - min[0] === 0) {\n            max[0] += 1;\n            min[0] -= 1;\n        }\n        if (max[1] - min[1] === 0) {\n            max[1] += 1;\n            min[1] -= 1;\n        }\n\n        var viewCoordSys = seriesModel.coordinateSystem = new View();\n        viewCoordSys.zoomLimit = seriesModel.get('scaleLimit');\n\n        viewCoordSys.setBoundingRect(min[0], min[1], max[0] - min[0], max[1] - min[1]);\n\n        viewCoordSys.setCenter(seriesModel.get('center'));\n        viewCoordSys.setZoom(seriesModel.get('zoom'));\n\n        // Here we use viewCoordSys just for computing the 'position' and 'scale' of the group\n        this.group.attr({\n            position: viewCoordSys.position,\n            scale: viewCoordSys.scale\n        });\n\n        this._viewCoordSys = viewCoordSys;\n    },\n\n    _updateController: function (seriesModel, ecModel, api) {\n        var controller = this._controller;\n        var controllerHost = this._controllerHost;\n        var group = this.group;\n        controller.setPointerChecker(function (e, x, y) {\n            var rect = group.getBoundingRect();\n            rect.applyTransform(group.transform);\n            return rect.contain(x, y)\n                && !onIrrelevantElement(e, api, seriesModel);\n        });\n\n        controller.enable(seriesModel.get('roam'));\n        controllerHost.zoomLimit = seriesModel.get('scaleLimit');\n        controllerHost.zoom = seriesModel.coordinateSystem.getZoom();\n\n        controller\n            .off('pan')\n            .off('zoom')\n            .on('pan', function (e) {\n                updateViewOnPan(controllerHost, e.dx, e.dy);\n                api.dispatchAction({\n                    seriesId: seriesModel.id,\n                    type: 'treeRoam',\n                    dx: e.dx,\n                    dy: e.dy\n                });\n            }, this)\n            .on('zoom', function (e) {\n                updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY);\n                api.dispatchAction({\n                    seriesId: seriesModel.id,\n                    type: 'treeRoam',\n                    zoom: e.scale,\n                    originX: e.originX,\n                    originY: e.originY\n                });\n                this._updateNodeAndLinkScale(seriesModel);\n            }, this);\n    },\n\n    _updateNodeAndLinkScale: function (seriesModel) {\n        var data = seriesModel.getData();\n\n        var nodeScale = this._getNodeGlobalScale(seriesModel);\n        var invScale = [nodeScale, nodeScale];\n\n        data.eachItemGraphicEl(function (el, idx) {\n            el.attr('scale', invScale);\n        });\n    },\n\n    _getNodeGlobalScale: function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys.type !== 'view') {\n            return 1;\n        }\n\n        var nodeScaleRatio = this._nodeScaleRatio;\n\n        var groupScale = coordSys.scale;\n        var groupZoom = (groupScale && groupScale[0]) || 1;\n        // Scale node when zoom changes\n        var roamZoom = coordSys.getZoom();\n        var nodeScale = (roamZoom - 1) * nodeScaleRatio + 1;\n\n        return nodeScale / groupZoom;\n    },\n\n    dispose: function () {\n        this._controller && this._controller.dispose();\n        this._controllerHost = {};\n    },\n\n    remove: function () {\n        this._mainGroup.removeAll();\n        this._data = null;\n    }\n\n});\n\nfunction symbolNeedsDraw$1(data, dataIndex) {\n    var layout = data.getItemLayout(dataIndex);\n\n    return layout\n        && !isNaN(layout.x) && !isNaN(layout.y)\n        && data.getItemVisual(dataIndex, 'symbol') !== 'none';\n}\n\nfunction getTreeNodeStyle(node, itemModel, seriesScope) {\n    seriesScope.itemModel = itemModel;\n    seriesScope.itemStyle = itemModel.getModel('itemStyle').getItemStyle();\n    seriesScope.hoverItemStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n    seriesScope.lineStyle = itemModel.getModel('lineStyle').getLineStyle();\n    seriesScope.labelModel = itemModel.getModel('label');\n    seriesScope.hoverLabelModel = itemModel.getModel('emphasis.label');\n\n    if (node.isExpand === false && node.children.length !== 0) {\n        seriesScope.symbolInnerColor = seriesScope.itemStyle.fill;\n    }\n    else {\n        seriesScope.symbolInnerColor = '#fff';\n    }\n\n    return seriesScope;\n}\n\nfunction updateNode(data, dataIndex, symbolEl, group, seriesModel, seriesScope) {\n    var isInit = !symbolEl;\n    var node = data.tree.getNodeByDataIndex(dataIndex);\n    var itemModel = node.getModel();\n    var seriesScope = getTreeNodeStyle(node, itemModel, seriesScope);\n    var virtualRoot = data.tree.root;\n\n    var source = node.parentNode === virtualRoot ? node : node.parentNode || node;\n    var sourceSymbolEl = data.getItemGraphicEl(source.dataIndex);\n    var sourceLayout = source.getLayout();\n    var sourceOldLayout = sourceSymbolEl\n        ? {\n            x: sourceSymbolEl.position[0],\n            y: sourceSymbolEl.position[1],\n            rawX: sourceSymbolEl.__radialOldRawX,\n            rawY: sourceSymbolEl.__radialOldRawY\n        }\n        : sourceLayout;\n    var targetLayout = node.getLayout();\n\n    if (isInit) {\n        symbolEl = new SymbolClz$1(data, dataIndex, seriesScope);\n        symbolEl.attr('position', [sourceOldLayout.x, sourceOldLayout.y]);\n    }\n    else {\n        symbolEl.updateData(data, dataIndex, seriesScope);\n    }\n\n    symbolEl.__radialOldRawX = symbolEl.__radialRawX;\n    symbolEl.__radialOldRawY = symbolEl.__radialRawY;\n    symbolEl.__radialRawX = targetLayout.rawX;\n    symbolEl.__radialRawY = targetLayout.rawY;\n\n    group.add(symbolEl);\n    data.setItemGraphicEl(dataIndex, symbolEl);\n    updateProps(symbolEl, {\n        position: [targetLayout.x, targetLayout.y]\n    }, seriesModel);\n\n    var symbolPath = symbolEl.getSymbolPath();\n\n    if (seriesScope.layout === 'radial') {\n        var realRoot = virtualRoot.children[0];\n        var rootLayout = realRoot.getLayout();\n        var length = realRoot.children.length;\n        var rad;\n        var isLeft;\n\n        if (targetLayout.x === rootLayout.x && node.isExpand === true) {\n            var center = {};\n            center.x = (realRoot.children[0].getLayout().x + realRoot.children[length - 1].getLayout().x) / 2;\n            center.y = (realRoot.children[0].getLayout().y + realRoot.children[length - 1].getLayout().y) / 2;\n            rad = Math.atan2(center.y - rootLayout.y, center.x - rootLayout.x);\n            if (rad < 0) {\n                rad = Math.PI * 2 + rad;\n            }\n            isLeft = center.x < rootLayout.x;\n            if (isLeft) {\n                rad = rad - Math.PI;\n            }\n        }\n        else {\n            rad = Math.atan2(targetLayout.y - rootLayout.y, targetLayout.x - rootLayout.x);\n            if (rad < 0) {\n                rad = Math.PI * 2 + rad;\n            }\n            if (node.children.length === 0 || (node.children.length !== 0 && node.isExpand === false)) {\n                isLeft = targetLayout.x < rootLayout.x;\n                if (isLeft) {\n                    rad = rad - Math.PI;\n                }\n            }\n            else {\n                isLeft = targetLayout.x > rootLayout.x;\n                if (!isLeft) {\n                    rad = rad - Math.PI;\n                }\n            }\n        }\n\n        var textPosition = isLeft ? 'left' : 'right';\n        symbolPath.setStyle({\n            textPosition: textPosition,\n            textRotation: -rad,\n            textOrigin: 'center',\n            verticalAlign: 'middle'\n        });\n    }\n\n    if (node.parentNode && node.parentNode !== virtualRoot) {\n        var edge = symbolEl.__edge;\n        if (!edge) {\n            edge = symbolEl.__edge = new BezierCurve({\n                shape: getEdgeShape(seriesScope, sourceOldLayout, sourceOldLayout),\n                style: defaults({opacity: 0, strokeNoScale: true}, seriesScope.lineStyle)\n            });\n        }\n\n        updateProps(edge, {\n            shape: getEdgeShape(seriesScope, sourceLayout, targetLayout),\n            style: {opacity: 1}\n        }, seriesModel);\n\n        group.add(edge);\n    }\n}\n\nfunction removeNode(data, dataIndex, symbolEl, group, seriesModel, seriesScope) {\n    var node = data.tree.getNodeByDataIndex(dataIndex);\n    var virtualRoot = data.tree.root;\n    var itemModel = node.getModel();\n    var seriesScope = getTreeNodeStyle(node, itemModel, seriesScope);\n\n    var source = node.parentNode === virtualRoot ? node : node.parentNode || node;\n    var sourceLayout;\n    while (sourceLayout = source.getLayout(), sourceLayout == null) {\n        source = source.parentNode === virtualRoot ? source : source.parentNode || source;\n    }\n\n    updateProps(symbolEl, {\n        position: [sourceLayout.x + 1, sourceLayout.y + 1]\n    }, seriesModel, function () {\n        group.remove(symbolEl);\n        data.setItemGraphicEl(dataIndex, null);\n    });\n\n    symbolEl.fadeOut(null, {keepLabel: true});\n\n    var edge = symbolEl.__edge;\n    if (edge) {\n        updateProps(edge, {\n            shape: getEdgeShape(seriesScope, sourceLayout, sourceLayout),\n            style: {\n                opacity: 0\n            }\n        }, seriesModel, function () {\n            group.remove(edge);\n        });\n    }\n}\n\nfunction getEdgeShape(seriesScope, sourceLayout, targetLayout) {\n    var cpx1;\n    var cpy1;\n    var cpx2;\n    var cpy2;\n    var orient = seriesScope.orient;\n    var x1;\n    var x2;\n    var y1;\n    var y2;\n\n    if (seriesScope.layout === 'radial') {\n        x1 = sourceLayout.rawX;\n        y1 = sourceLayout.rawY;\n        x2 = targetLayout.rawX;\n        y2 = targetLayout.rawY;\n\n        var radialCoor1 = radialCoordinate(x1, y1);\n        var radialCoor2 = radialCoordinate(x1, y1 + (y2 - y1) * seriesScope.curvature);\n        var radialCoor3 = radialCoordinate(x2, y2 + (y1 - y2) * seriesScope.curvature);\n        var radialCoor4 = radialCoordinate(x2, y2);\n\n        return {\n            x1: radialCoor1.x,\n            y1: radialCoor1.y,\n            x2: radialCoor4.x,\n            y2: radialCoor4.y,\n            cpx1: radialCoor2.x,\n            cpy1: radialCoor2.y,\n            cpx2: radialCoor3.x,\n            cpy2: radialCoor3.y\n        };\n    }\n    else {\n        x1 = sourceLayout.x;\n        y1 = sourceLayout.y;\n        x2 = targetLayout.x;\n        y2 = targetLayout.y;\n\n        if (orient === 'LR' || orient === 'RL') {\n            cpx1 = x1 + (x2 - x1) * seriesScope.curvature;\n            cpy1 = y1;\n            cpx2 = x2 + (x1 - x2) * seriesScope.curvature;\n            cpy2 = y2;\n        }\n        if (orient === 'TB' || orient === 'BT') {\n            cpx1 = x1;\n            cpy1 = y1 + (y2 - y1) * seriesScope.curvature;\n            cpx2 = x2;\n            cpy2 = y2 + (y1 - y2) * seriesScope.curvature;\n        }\n    }\n\n    return {\n        x1: x1,\n        y1: y1,\n        x2: x2,\n        y2: y2,\n        cpx1: cpx1,\n        cpy1: cpy1,\n        cpx2: cpx2,\n        cpy2: cpy2\n    };\n\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Register the actions of the tree\n * @author Deqing Li(annong035@gmail.com)\n */\n\nregisterAction({\n    type: 'treeExpandAndCollapse',\n    event: 'treeExpandAndCollapse',\n    update: 'update'\n}, function (payload, ecModel) {\n    ecModel.eachComponent({mainType: 'series', subType: 'tree', query: payload}, function (seriesModel) {\n        var dataIndex = payload.dataIndex;\n        var tree = seriesModel.getData().tree;\n        var node = tree.getNodeByDataIndex(dataIndex);\n        node.isExpand = !node.isExpand;\n\n    });\n});\n\nregisterAction({\n    type: 'treeRoam',\n    event: 'treeRoam',\n    // Here we set 'none' instead of 'update', because roam action\n    // just need to update the transform matrix without having to recalculate\n    // the layout. So don't need to go through the whole update process, such\n    // as 'dataPrcocess', 'coordSystemUpdate', 'layout' and so on.\n    update: 'none'\n}, function (payload, ecModel) {\n    ecModel.eachComponent({mainType: 'series', subType: 'tree', query: payload}, function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        var res = updateCenterAndZoom(coordSys, payload);\n\n        seriesModel.setCenter\n            && seriesModel.setCenter(res.center);\n\n        seriesModel.setZoom\n            && seriesModel.setZoom(res.zoom);\n    });\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * Traverse the tree from bottom to top and do something\n * @param  {module:echarts/data/Tree~TreeNode} root  The real root of the tree\n * @param  {Function} callback\n */\nfunction eachAfter(root, callback, separation) {\n    var nodes = [root];\n    var next = [];\n    var node;\n\n    while (node = nodes.pop()) { // jshint ignore:line\n        next.push(node);\n        if (node.isExpand) {\n            var children = node.children;\n            if (children.length) {\n                for (var i = 0; i < children.length; i++) {\n                    nodes.push(children[i]);\n                }\n            }\n        }\n    }\n\n    while (node = next.pop()) { // jshint ignore:line\n        callback(node, separation);\n    }\n}\n\n/**\n * Traverse the tree from top to bottom and do something\n * @param  {module:echarts/data/Tree~TreeNode} root  The real root of the tree\n * @param  {Function} callback\n */\nfunction eachBefore(root, callback) {\n    var nodes = [root];\n    var node;\n    while (node = nodes.pop()) { // jshint ignore:line\n        callback(node);\n        if (node.isExpand) {\n            var children = node.children;\n            if (children.length) {\n                for (var i = children.length - 1; i >= 0; i--) {\n                    nodes.push(children[i]);\n                }\n            }\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar treeLayout = function (ecModel, api) {\n    ecModel.eachSeriesByType('tree', function (seriesModel) {\n        commonLayout(seriesModel, api);\n    });\n};\n\nfunction commonLayout(seriesModel, api) {\n    var layoutInfo = getViewRect(seriesModel, api);\n    seriesModel.layoutInfo = layoutInfo;\n    var layout = seriesModel.get('layout');\n    var width = 0;\n    var height = 0;\n    var separation$$1 = null;\n\n    if (layout === 'radial') {\n        width = 2 * Math.PI;\n        height = Math.min(layoutInfo.height, layoutInfo.width) / 2;\n        separation$$1 = separation(function (node1, node2) {\n            return (node1.parentNode === node2.parentNode ? 1 : 2) / node1.depth;\n        });\n    }\n    else {\n        width = layoutInfo.width;\n        height = layoutInfo.height;\n        separation$$1 = separation();\n    }\n\n    var virtualRoot = seriesModel.getData().tree.root;\n    var realRoot = virtualRoot.children[0];\n\n    if (realRoot) {\n        init$2(virtualRoot);\n        eachAfter(realRoot, firstWalk, separation$$1);\n        virtualRoot.hierNode.modifier = -realRoot.hierNode.prelim;\n        eachBefore(realRoot, secondWalk);\n\n        var left = realRoot;\n        var right = realRoot;\n        var bottom = realRoot;\n        eachBefore(realRoot, function (node) {\n            var x = node.getLayout().x;\n            if (x < left.getLayout().x) {\n                left = node;\n            }\n            if (x > right.getLayout().x) {\n                right = node;\n            }\n            if (node.depth > bottom.depth) {\n                bottom = node;\n            }\n        });\n\n        var delta = left === right ? 1 : separation$$1(left, right) / 2;\n        var tx = delta - left.getLayout().x;\n        var kx = 0;\n        var ky = 0;\n        var coorX = 0;\n        var coorY = 0;\n        if (layout === 'radial') {\n            kx = width / (right.getLayout().x + delta + tx);\n            // here we use (node.depth - 1), bucause the real root's depth is 1\n            ky = height / ((bottom.depth - 1) || 1);\n            eachBefore(realRoot, function (node) {\n                coorX = (node.getLayout().x + tx) * kx;\n                coorY = (node.depth - 1) * ky;\n                var finalCoor = radialCoordinate(coorX, coorY);\n                node.setLayout({x: finalCoor.x, y: finalCoor.y, rawX: coorX, rawY: coorY}, true);\n            });\n        }\n        else {\n            var orient = seriesModel.getOrient();\n            if (orient === 'RL' || orient === 'LR') {\n                ky = height / (right.getLayout().x + delta + tx);\n                kx = width / ((bottom.depth - 1) || 1);\n                eachBefore(realRoot, function (node) {\n                    coorY = (node.getLayout().x + tx) * ky;\n                    coorX = orient === 'LR'\n                        ? (node.depth - 1) * kx\n                        : width - (node.depth - 1) * kx;\n                    node.setLayout({x: coorX, y: coorY}, true);\n                });\n            }\n            else if (orient === 'TB' || orient === 'BT') {\n                kx = width / (right.getLayout().x + delta + tx);\n                ky = height / ((bottom.depth - 1) || 1);\n                eachBefore(realRoot, function (node) {\n                    coorX = (node.getLayout().x + tx) * kx;\n                    coorY = orient === 'TB'\n                        ? (node.depth - 1) * ky\n                        : height - (node.depth - 1) * ky;\n                    node.setLayout({x: coorX, y: coorY}, true);\n                });\n            }\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(visualSymbol('tree', 'circle'));\nregisterLayout(treeLayout);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction retrieveTargetInfo(payload, validPayloadTypes, seriesModel) {\n    if (payload && indexOf(validPayloadTypes, payload.type) >= 0) {\n        var root = seriesModel.getData().tree.root;\n        var targetNode = payload.targetNode;\n\n        if (typeof targetNode === 'string') {\n            targetNode = root.getNodeById(targetNode);\n        }\n\n        if (targetNode && root.contains(targetNode)) {\n            return {node: targetNode};\n        }\n\n        var targetNodeId = payload.targetNodeId;\n        if (targetNodeId != null && (targetNode = root.getNodeById(targetNodeId))) {\n            return {node: targetNode};\n        }\n    }\n}\n\n// Not includes the given node at the last item.\nfunction getPathToRoot(node) {\n    var path = [];\n    while (node) {\n        node = node.parentNode;\n        node && path.push(node);\n    }\n    return path.reverse();\n}\n\nfunction aboveViewRoot(viewRoot, node) {\n    var viewPath = getPathToRoot(viewRoot);\n    return indexOf(viewPath, node) >= 0;\n}\n\n// From root to the input node (the input node will be included).\nfunction wrapTreePathInfo(node, seriesModel) {\n    var treePathInfo = [];\n\n    while (node) {\n        var nodeDataIndex = node.dataIndex;\n        treePathInfo.push({\n            name: node.name,\n            dataIndex: nodeDataIndex,\n            value: seriesModel.getRawValue(nodeDataIndex)\n        });\n        node = node.parentNode;\n    }\n\n    treePathInfo.reverse();\n\n    return treePathInfo;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.treemap',\n\n    layoutMode: 'box',\n\n    dependencies: ['grid', 'polar'],\n\n    /**\n     * @type {module:echarts/data/Tree~Node}\n     */\n    _viewRoot: null,\n\n    defaultOption: {\n        // Disable progressive rendering\n        progressive: 0,\n        hoverLayerThreshold: Infinity,\n        // center: ['50%', '50%'],          // not supported in ec3.\n        // size: ['80%', '80%'],            // deprecated, compatible with ec2.\n        left: 'center',\n        top: 'middle',\n        right: null,\n        bottom: null,\n        width: '80%',\n        height: '80%',\n        sort: true,                         // Can be null or false or true\n                                            // (order by desc default, asc not supported yet (strange effect))\n        clipWindow: 'origin',               // Size of clipped window when zooming. 'origin' or 'fullscreen'\n        squareRatio: 0.5 * (1 + Math.sqrt(5)), // golden ratio\n        leafDepth: null,                    // Nodes on depth from root are regarded as leaves.\n                                            // Count from zero (zero represents only view root).\n        drillDownIcon: '▶',                 // Use html character temporarily because it is complicated\n                                            // to align specialized icon. ▷▶❒❐▼✚\n\n        zoomToNodeRatio: 0.32 * 0.32,       // Be effective when using zoomToNode. Specify the proportion of the\n                                            // target node area in the view area.\n        roam: true,                         // true, false, 'scale' or 'zoom', 'move'.\n        nodeClick: 'zoomToNode',            // Leaf node click behaviour: 'zoomToNode', 'link', false.\n                                            // If leafDepth is set and clicking a node which has children but\n                                            // be on left depth, the behaviour would be changing root. Otherwise\n                                            // use behavious defined above.\n        animation: true,\n        animationDurationUpdate: 900,\n        animationEasing: 'quinticInOut',\n        breadcrumb: {\n            show: true,\n            height: 22,\n            left: 'center',\n            top: 'bottom',\n            // right\n            // bottom\n            emptyItemWidth: 25,             // Width of empty node.\n            itemStyle: {\n                color: 'rgba(0,0,0,0.7)', //'#5793f3',\n                borderColor: 'rgba(255,255,255,0.7)',\n                borderWidth: 1,\n                shadowColor: 'rgba(150,150,150,1)',\n                shadowBlur: 3,\n                shadowOffsetX: 0,\n                shadowOffsetY: 0,\n                textStyle: {\n                    color: '#fff'\n                }\n            },\n            emphasis: {\n                textStyle: {}\n            }\n        },\n        label: {\n            show: true,\n            // Do not use textDistance, for ellipsis rect just the same as treemap node rect.\n            distance: 0,\n            padding: 5,\n            position: 'inside', // Can be [5, '5%'] or position stirng like 'insideTopLeft', ...\n            // formatter: null,\n            color: '#fff',\n            ellipsis: true\n            // align\n            // verticalAlign\n        },\n        upperLabel: {                   // Label when node is parent.\n            show: false,\n            position: [0, '50%'],\n            height: 20,\n            // formatter: null,\n            color: '#fff',\n            ellipsis: true,\n            // align: null,\n            verticalAlign: 'middle'\n        },\n        itemStyle: {\n            color: null,            // Can be 'none' if not necessary.\n            colorAlpha: null,       // Can be 'none' if not necessary.\n            colorSaturation: null,  // Can be 'none' if not necessary.\n            borderWidth: 0,\n            gapWidth: 0,\n            borderColor: '#fff',\n            borderColorSaturation: null // If specified, borderColor will be ineffective, and the\n                                        // border color is evaluated by color of current node and\n                                        // borderColorSaturation.\n        },\n        emphasis: {\n            upperLabel: {\n                show: true,\n                position: [0, '50%'],\n                color: '#fff',\n                ellipsis: true,\n                verticalAlign: 'middle'\n            }\n        },\n\n        visualDimension: 0,                 // Can be 0, 1, 2, 3.\n        visualMin: null,\n        visualMax: null,\n\n        color: [],                  // + treemapSeries.color should not be modified. Please only modified\n                                    // level[n].color (if necessary).\n                                    // + Specify color list of each level. level[0].color would be global\n                                    // color list if not specified. (see method `setDefault`).\n                                    // + But set as a empty array to forbid fetch color from global palette\n                                    // when using nodeModel.get('color'), otherwise nodes on deep level\n                                    // will always has color palette set and are not able to inherit color\n                                    // from parent node.\n                                    // + TreemapSeries.color can not be set as 'none', otherwise effect\n                                    // legend color fetching (see seriesColor.js).\n        colorAlpha: null,           // Array. Specify color alpha range of each level, like [0.2, 0.8]\n        colorSaturation: null,      // Array. Specify color saturation of each level, like [0.2, 0.5]\n        colorMappingBy: 'index',    // 'value' or 'index' or 'id'.\n        visibleMin: 10,             // If area less than this threshold (unit: pixel^2), node will not\n                                    // be rendered. Only works when sort is 'asc' or 'desc'.\n        childrenVisibleMin: null,   // If area of a node less than this threshold (unit: pixel^2),\n                                    // grandchildren will not show.\n                                    // Why grandchildren? If not grandchildren but children,\n                                    // some siblings show children and some not,\n                                    // the appearance may be mess and not consistent,\n        levels: []                  // Each item: {\n                                    //     visibleMin, itemStyle, visualDimension, label\n                                    // }\n        // data: {\n        //      value: [],\n        //      children: [],\n        //      link: 'http://xxx.xxx.xxx',\n        //      target: 'blank' or 'self'\n        // }\n    },\n\n    /**\n     * @override\n     */\n    getInitialData: function (option, ecModel) {\n        // Create a virtual root.\n        var root = {name: option.name, children: option.data};\n\n        completeTreeValue(root);\n\n        var levels = option.levels || [];\n\n        levels = option.levels = setDefault(levels, ecModel);\n\n        var treeOption = {};\n\n        treeOption.levels = levels;\n\n        // Make sure always a new tree is created when setOption,\n        // in TreemapView, we check whether oldTree === newTree\n        // to choose mappings approach among old shapes and new shapes.\n        return Tree.createTree(root, this, treeOption).data;\n    },\n\n    optionUpdated: function () {\n        this.resetViewRoot();\n    },\n\n    /**\n     * @override\n     * @param {number} dataIndex\n     * @param {boolean} [mutipleSeries=false]\n     */\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var value = this.getRawValue(dataIndex);\n        var formattedValue = isArray(value)\n            ? addCommas(value[0]) : addCommas(value);\n        var name = data.getName(dataIndex);\n\n        return encodeHTML(name + ': ' + formattedValue);\n    },\n\n    /**\n     * Add tree path to tooltip param\n     *\n     * @override\n     * @param {number} dataIndex\n     * @return {Object}\n     */\n    getDataParams: function (dataIndex) {\n        var params = SeriesModel.prototype.getDataParams.apply(this, arguments);\n\n        var node = this.getData().tree.getNodeByDataIndex(dataIndex);\n        params.treePathInfo = wrapTreePathInfo(node, this);\n\n        return params;\n    },\n\n    /**\n     * @public\n     * @param {Object} layoutInfo {\n     *                                x: containerGroup x\n     *                                y: containerGroup y\n     *                                width: containerGroup width\n     *                                height: containerGroup height\n     *                            }\n     */\n    setLayoutInfo: function (layoutInfo) {\n        /**\n         * @readOnly\n         * @type {Object}\n         */\n        this.layoutInfo = this.layoutInfo || {};\n        extend(this.layoutInfo, layoutInfo);\n    },\n\n    /**\n     * @param  {string} id\n     * @return {number} index\n     */\n    mapIdToIndex: function (id) {\n        // A feature is implemented:\n        // index is monotone increasing with the sequence of\n        // input id at the first time.\n        // This feature can make sure that each data item and its\n        // mapped color have the same index between data list and\n        // color list at the beginning, which is useful for user\n        // to adjust data-color mapping.\n\n        /**\n         * @private\n         * @type {Object}\n         */\n        var idIndexMap = this._idIndexMap;\n\n        if (!idIndexMap) {\n            idIndexMap = this._idIndexMap = createHashMap();\n            /**\n             * @private\n             * @type {number}\n             */\n            this._idIndexMapCount = 0;\n        }\n\n        var index = idIndexMap.get(id);\n        if (index == null) {\n            idIndexMap.set(id, index = this._idIndexMapCount++);\n        }\n\n        return index;\n    },\n\n    getViewRoot: function () {\n        return this._viewRoot;\n    },\n\n    /**\n     * @param {module:echarts/data/Tree~Node} [viewRoot]\n     */\n    resetViewRoot: function (viewRoot) {\n        viewRoot\n            ? (this._viewRoot = viewRoot)\n            : (viewRoot = this._viewRoot);\n\n        var root = this.getRawData().tree.root;\n\n        if (!viewRoot\n            || (viewRoot !== root && !root.contains(viewRoot))\n        ) {\n            this._viewRoot = root;\n        }\n    }\n});\n\n/**\n * @param {Object} dataNode\n */\nfunction completeTreeValue(dataNode) {\n    // Postorder travel tree.\n    // If value of none-leaf node is not set,\n    // calculate it by suming up the value of all children.\n    var sum = 0;\n\n    each$1(dataNode.children, function (child) {\n\n        completeTreeValue(child);\n\n        var childValue = child.value;\n        isArray(childValue) && (childValue = childValue[0]);\n\n        sum += childValue;\n    });\n\n    var thisValue = dataNode.value;\n    if (isArray(thisValue)) {\n        thisValue = thisValue[0];\n    }\n\n    if (thisValue == null || isNaN(thisValue)) {\n        thisValue = sum;\n    }\n    // Value should not less than 0.\n    if (thisValue < 0) {\n        thisValue = 0;\n    }\n\n    isArray(dataNode.value)\n        ? (dataNode.value[0] = thisValue)\n        : (dataNode.value = thisValue);\n}\n\n/**\n * set default to level configuration\n */\nfunction setDefault(levels, ecModel) {\n    var globalColorList = ecModel.get('color');\n\n    if (!globalColorList) {\n        return;\n    }\n\n    levels = levels || [];\n    var hasColorDefine;\n    each$1(levels, function (levelDefine) {\n        var model = new Model(levelDefine);\n        var modelColor = model.get('color');\n\n        if (model.get('itemStyle.color')\n            || (modelColor && modelColor !== 'none')\n        ) {\n            hasColorDefine = true;\n        }\n    });\n\n    if (!hasColorDefine) {\n        var level0 = levels[0] || (levels[0] = {});\n        level0.color = globalColorList.slice();\n    }\n\n    return levels;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TEXT_PADDING = 8;\nvar ITEM_GAP = 8;\nvar ARRAY_LENGTH = 5;\n\nfunction Breadcrumb(containerGroup) {\n    /**\n     * @private\n     * @type {module:zrender/container/Group}\n     */\n    this.group = new Group();\n\n    containerGroup.add(this.group);\n}\n\nBreadcrumb.prototype = {\n\n    constructor: Breadcrumb,\n\n    render: function (seriesModel, api, targetNode, onSelect) {\n        var model = seriesModel.getModel('breadcrumb');\n        var thisGroup = this.group;\n\n        thisGroup.removeAll();\n\n        if (!model.get('show') || !targetNode) {\n            return;\n        }\n\n        var normalStyleModel = model.getModel('itemStyle');\n        // var emphasisStyleModel = model.getModel('emphasis.itemStyle');\n        var textStyleModel = normalStyleModel.getModel('textStyle');\n\n        var layoutParam = {\n            pos: {\n                left: model.get('left'),\n                right: model.get('right'),\n                top: model.get('top'),\n                bottom: model.get('bottom')\n            },\n            box: {\n                width: api.getWidth(),\n                height: api.getHeight()\n            },\n            emptyItemWidth: model.get('emptyItemWidth'),\n            totalWidth: 0,\n            renderList: []\n        };\n\n        this._prepare(targetNode, layoutParam, textStyleModel);\n        this._renderContent(seriesModel, layoutParam, normalStyleModel, textStyleModel, onSelect);\n\n        positionElement(thisGroup, layoutParam.pos, layoutParam.box);\n    },\n\n    /**\n     * Prepare render list and total width\n     * @private\n     */\n    _prepare: function (targetNode, layoutParam, textStyleModel) {\n        for (var node = targetNode; node; node = node.parentNode) {\n            var text = node.getModel().get('name');\n            var textRect = textStyleModel.getTextRect(text);\n            var itemWidth = Math.max(\n                textRect.width + TEXT_PADDING * 2,\n                layoutParam.emptyItemWidth\n            );\n            layoutParam.totalWidth += itemWidth + ITEM_GAP;\n            layoutParam.renderList.push({node: node, text: text, width: itemWidth});\n        }\n    },\n\n    /**\n     * @private\n     */\n    _renderContent: function (\n        seriesModel, layoutParam, normalStyleModel, textStyleModel, onSelect\n    ) {\n        // Start rendering.\n        var lastX = 0;\n        var emptyItemWidth = layoutParam.emptyItemWidth;\n        var height = seriesModel.get('breadcrumb.height');\n        var availableSize = getAvailableSize(layoutParam.pos, layoutParam.box);\n        var totalWidth = layoutParam.totalWidth;\n        var renderList = layoutParam.renderList;\n\n        for (var i = renderList.length - 1; i >= 0; i--) {\n            var item = renderList[i];\n            var itemNode = item.node;\n            var itemWidth = item.width;\n            var text = item.text;\n\n            // Hdie text and shorten width if necessary.\n            if (totalWidth > availableSize.width) {\n                totalWidth -= itemWidth - emptyItemWidth;\n                itemWidth = emptyItemWidth;\n                text = null;\n            }\n\n            var el = new Polygon({\n                shape: {\n                    points: makeItemPoints(\n                        lastX, 0, itemWidth, height,\n                        i === renderList.length - 1, i === 0\n                    )\n                },\n                style: defaults(\n                    normalStyleModel.getItemStyle(),\n                    {\n                        lineJoin: 'bevel',\n                        text: text,\n                        textFill: textStyleModel.getTextColor(),\n                        textFont: textStyleModel.getFont()\n                    }\n                ),\n                z: 10,\n                onclick: curry(onSelect, itemNode)\n            });\n            this.group.add(el);\n\n            packEventData(el, seriesModel, itemNode);\n\n            lastX += itemWidth + ITEM_GAP;\n        }\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this.group.removeAll();\n    }\n};\n\nfunction makeItemPoints(x, y, itemWidth, itemHeight, head, tail) {\n    var points = [\n        [head ? x : x - ARRAY_LENGTH, y],\n        [x + itemWidth, y],\n        [x + itemWidth, y + itemHeight],\n        [head ? x : x - ARRAY_LENGTH, y + itemHeight]\n    ];\n    !tail && points.splice(2, 0, [x + itemWidth + ARRAY_LENGTH, y + itemHeight / 2]);\n    !head && points.push([x, y + itemHeight / 2]);\n    return points;\n}\n\n// Package custom mouse event.\nfunction packEventData(el, seriesModel, itemNode) {\n    el.eventData = {\n        componentType: 'series',\n        componentSubType: 'treemap',\n        componentIndex: seriesModel.componentIndex,\n        seriesIndex: seriesModel.componentIndex,\n        seriesName: seriesModel.name,\n        seriesType: 'treemap',\n        selfType: 'breadcrumb', // Distinguish with click event on treemap node.\n        nodeData: {\n            dataIndex: itemNode && itemNode.dataIndex,\n            name: itemNode && itemNode.name\n        },\n        treePathInfo: itemNode && wrapTreePathInfo(itemNode, seriesModel)\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {number} [time=500] Time in ms\n * @param {string} [easing='linear']\n * @param {number} [delay=0]\n * @param {Function} [callback]\n *\n * @example\n *  // Animate position\n *  animation\n *      .createWrap()\n *      .add(el1, {position: [10, 10]})\n *      .add(el2, {shape: {width: 500}, style: {fill: 'red'}}, 400)\n *      .done(function () { // done })\n *      .start('cubicOut');\n */\nfunction createWrap() {\n\n    var storage = [];\n    var elExistsMap = {};\n    var doneCallback;\n\n    return {\n\n        /**\n         * Caution: a el can only be added once, otherwise 'done'\n         * might not be called. This method checks this (by el.id),\n         * suppresses adding and returns false when existing el found.\n         *\n         * @param {modele:zrender/Element} el\n         * @param {Object} target\n         * @param {number} [time=500]\n         * @param {number} [delay=0]\n         * @param {string} [easing='linear']\n         * @return {boolean} Whether adding succeeded.\n         *\n         * @example\n         *     add(el, target, time, delay, easing);\n         *     add(el, target, time, easing);\n         *     add(el, target, time);\n         *     add(el, target);\n         */\n        add: function (el, target, time, delay, easing) {\n            if (isString(delay)) {\n                easing = delay;\n                delay = 0;\n            }\n\n            if (elExistsMap[el.id]) {\n                return false;\n            }\n            elExistsMap[el.id] = 1;\n\n            storage.push(\n                {el: el, target: target, time: time, delay: delay, easing: easing}\n            );\n\n            return true;\n        },\n\n        /**\n         * Only execute when animation finished. Will not execute when any\n         * of 'stop' or 'stopAnimation' called.\n         *\n         * @param {Function} callback\n         */\n        done: function (callback) {\n            doneCallback = callback;\n            return this;\n        },\n\n        /**\n         * Will stop exist animation firstly.\n         */\n        start: function () {\n            var count = storage.length;\n\n            for (var i = 0, len = storage.length; i < len; i++) {\n                var item = storage[i];\n                item.el.animateTo(item.target, item.time, item.delay, item.easing, done);\n            }\n\n            return this;\n\n            function done() {\n                count--;\n                if (!count) {\n                    storage.length = 0;\n                    elExistsMap = {};\n                    doneCallback && doneCallback();\n                }\n            }\n        }\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$1 = bind;\nvar Group$2 = Group;\nvar Rect$1 = Rect;\nvar each$8 = each$1;\n\nvar DRAG_THRESHOLD = 3;\nvar PATH_LABEL_NOAMAL = ['label'];\nvar PATH_LABEL_EMPHASIS = ['emphasis', 'label'];\nvar PATH_UPPERLABEL_NORMAL = ['upperLabel'];\nvar PATH_UPPERLABEL_EMPHASIS = ['emphasis', 'upperLabel'];\nvar Z_BASE = 10; // Should bigger than every z.\nvar Z_BG = 1;\nvar Z_CONTENT = 2;\n\nvar getItemStyleEmphasis = makeStyleMapper([\n    ['fill', 'color'],\n    // `borderColor` and `borderWidth` has been occupied,\n    // so use `stroke` to indicate the stroke of the rect.\n    ['stroke', 'strokeColor'],\n    ['lineWidth', 'strokeWidth'],\n    ['shadowBlur'],\n    ['shadowOffsetX'],\n    ['shadowOffsetY'],\n    ['shadowColor']\n]);\nvar getItemStyleNormal = function (model) {\n    // Normal style props should include emphasis style props.\n    var itemStyle = getItemStyleEmphasis(model);\n    // Clear styles set by emphasis.\n    itemStyle.stroke = itemStyle.fill = itemStyle.lineWidth = null;\n    return itemStyle;\n};\n\nextendChartView({\n\n    type: 'treemap',\n\n    /**\n     * @override\n     */\n    init: function (o, api) {\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this._containerGroup;\n\n        /**\n         * @private\n         * @type {Object.<string, Array.<module:zrender/container/Group>>}\n         */\n        this._storage = createStorage();\n\n        /**\n         * @private\n         * @type {module:echarts/data/Tree}\n         */\n        this._oldTree;\n\n        /**\n         * @private\n         * @type {module:echarts/chart/treemap/Breadcrumb}\n         */\n        this._breadcrumb;\n\n        /**\n         * @private\n         * @type {module:echarts/component/helper/RoamController}\n         */\n        this._controller;\n\n        /**\n         * 'ready', 'animating'\n         * @private\n         */\n        this._state = 'ready';\n    },\n\n    /**\n     * @override\n     */\n    render: function (seriesModel, ecModel, api, payload) {\n\n        var models = ecModel.findComponents({\n            mainType: 'series', subType: 'treemap', query: payload\n        });\n        if (indexOf(models, seriesModel) < 0) {\n            return;\n        }\n\n        this.seriesModel = seriesModel;\n        this.api = api;\n        this.ecModel = ecModel;\n\n        var types = ['treemapZoomToNode', 'treemapRootToNode'];\n        var targetInfo = retrieveTargetInfo(payload, types, seriesModel);\n        var payloadType = payload && payload.type;\n        var layoutInfo = seriesModel.layoutInfo;\n        var isInit = !this._oldTree;\n        var thisStorage = this._storage;\n\n        // Mark new root when action is treemapRootToNode.\n        var reRoot = (payloadType === 'treemapRootToNode' && targetInfo && thisStorage)\n            ? {\n                rootNodeGroup: thisStorage.nodeGroup[targetInfo.node.getRawIndex()],\n                direction: payload.direction\n            }\n            : null;\n\n        var containerGroup = this._giveContainerGroup(layoutInfo);\n\n        var renderResult = this._doRender(containerGroup, seriesModel, reRoot);\n        (\n            !isInit && (\n                !payloadType\n                || payloadType === 'treemapZoomToNode'\n                || payloadType === 'treemapRootToNode'\n            )\n        )\n            ? this._doAnimation(containerGroup, renderResult, seriesModel, reRoot)\n            : renderResult.renderFinally();\n\n        this._resetController(api);\n\n        this._renderBreadcrumb(seriesModel, api, targetInfo);\n    },\n\n    /**\n     * @private\n     */\n    _giveContainerGroup: function (layoutInfo) {\n        var containerGroup = this._containerGroup;\n        if (!containerGroup) {\n            // FIXME\n            // 加一层containerGroup是为了clip，但是现在clip功能并没有实现。\n            containerGroup = this._containerGroup = new Group$2();\n            this._initEvents(containerGroup);\n            this.group.add(containerGroup);\n        }\n        containerGroup.attr('position', [layoutInfo.x, layoutInfo.y]);\n\n        return containerGroup;\n    },\n\n    /**\n     * @private\n     */\n    _doRender: function (containerGroup, seriesModel, reRoot) {\n        var thisTree = seriesModel.getData().tree;\n        var oldTree = this._oldTree;\n\n        // Clear last shape records.\n        var lastsForAnimation = createStorage();\n        var thisStorage = createStorage();\n        var oldStorage = this._storage;\n        var willInvisibleEls = [];\n        var doRenderNode = curry(\n            renderNode, seriesModel,\n            thisStorage, oldStorage, reRoot,\n            lastsForAnimation, willInvisibleEls\n        );\n\n        // Notice: when thisTree and oldTree are the same tree (see list.cloneShallow),\n        // the oldTree is actually losted, so we can not find all of the old graphic\n        // elements from tree. So we use this stragegy: make element storage, move\n        // from old storage to new storage, clear old storage.\n\n        dualTravel(\n            thisTree.root ? [thisTree.root] : [],\n            (oldTree && oldTree.root) ? [oldTree.root] : [],\n            containerGroup,\n            thisTree === oldTree || !oldTree,\n            0\n        );\n\n        // Process all removing.\n        var willDeleteEls = clearStorage(oldStorage);\n\n        this._oldTree = thisTree;\n        this._storage = thisStorage;\n\n        return {\n            lastsForAnimation: lastsForAnimation,\n            willDeleteEls: willDeleteEls,\n            renderFinally: renderFinally\n        };\n\n        function dualTravel(thisViewChildren, oldViewChildren, parentGroup, sameTree, depth) {\n            // When 'render' is triggered by action,\n            // 'this' and 'old' may be the same tree,\n            // we use rawIndex in that case.\n            if (sameTree) {\n                oldViewChildren = thisViewChildren;\n                each$8(thisViewChildren, function (child, index) {\n                    !child.isRemoved() && processNode(index, index);\n                });\n            }\n            // Diff hierarchically (diff only in each subtree, but not whole).\n            // because, consistency of view is important.\n            else {\n                (new DataDiffer(oldViewChildren, thisViewChildren, getKey, getKey))\n                    .add(processNode)\n                    .update(processNode)\n                    .remove(curry(processNode, null))\n                    .execute();\n            }\n\n            function getKey(node) {\n                // Identify by name or raw index.\n                return node.getId();\n            }\n\n            function processNode(newIndex, oldIndex) {\n                var thisNode = newIndex != null ? thisViewChildren[newIndex] : null;\n                var oldNode = oldIndex != null ? oldViewChildren[oldIndex] : null;\n\n                var group = doRenderNode(thisNode, oldNode, parentGroup, depth);\n\n                group && dualTravel(\n                    thisNode && thisNode.viewChildren || [],\n                    oldNode && oldNode.viewChildren || [],\n                    group,\n                    sameTree,\n                    depth + 1\n                );\n            }\n        }\n\n        function clearStorage(storage) {\n            var willDeleteEls = createStorage();\n            storage && each$8(storage, function (store, storageName) {\n                var delEls = willDeleteEls[storageName];\n                each$8(store, function (el) {\n                    el && (delEls.push(el), el.__tmWillDelete = 1);\n                });\n            });\n            return willDeleteEls;\n        }\n\n        function renderFinally() {\n            each$8(willDeleteEls, function (els) {\n                each$8(els, function (el) {\n                    el.parent && el.parent.remove(el);\n                });\n            });\n            each$8(willInvisibleEls, function (el) {\n                el.invisible = true;\n                // Setting invisible is for optimizing, so no need to set dirty,\n                // just mark as invisible.\n                el.dirty();\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _doAnimation: function (containerGroup, renderResult, seriesModel, reRoot) {\n        if (!seriesModel.get('animation')) {\n            return;\n        }\n\n        var duration = seriesModel.get('animationDurationUpdate');\n        var easing = seriesModel.get('animationEasing');\n        var animationWrap = createWrap();\n\n        // Make delete animations.\n        each$8(renderResult.willDeleteEls, function (store, storageName) {\n            each$8(store, function (el, rawIndex) {\n                if (el.invisible) {\n                    return;\n                }\n\n                var parent = el.parent; // Always has parent, and parent is nodeGroup.\n                var target;\n\n                if (reRoot && reRoot.direction === 'drillDown') {\n                    target = parent === reRoot.rootNodeGroup\n                        // This is the content element of view root.\n                        // Only `content` will enter this branch, because\n                        // `background` and `nodeGroup` will not be deleted.\n                        ? {\n                            shape: {\n                                x: 0,\n                                y: 0,\n                                width: parent.__tmNodeWidth,\n                                height: parent.__tmNodeHeight\n                            },\n                            style: {\n                                opacity: 0\n                            }\n                        }\n                        // Others.\n                        : {style: {opacity: 0}};\n                }\n                else {\n                    var targetX = 0;\n                    var targetY = 0;\n\n                    if (!parent.__tmWillDelete) {\n                        // Let node animate to right-bottom corner, cooperating with fadeout,\n                        // which is appropriate for user understanding.\n                        // Divided by 2 for reRoot rolling up effect.\n                        targetX = parent.__tmNodeWidth / 2;\n                        targetY = parent.__tmNodeHeight / 2;\n                    }\n\n                    target = storageName === 'nodeGroup'\n                        ? {position: [targetX, targetY], style: {opacity: 0}}\n                        : {\n                            shape: {x: targetX, y: targetY, width: 0, height: 0},\n                            style: {opacity: 0}\n                        };\n                }\n\n                target && animationWrap.add(el, target, duration, easing);\n            });\n        });\n\n        // Make other animations\n        each$8(this._storage, function (store, storageName) {\n            each$8(store, function (el, rawIndex) {\n                var last = renderResult.lastsForAnimation[storageName][rawIndex];\n                var target = {};\n\n                if (!last) {\n                    return;\n                }\n\n                if (storageName === 'nodeGroup') {\n                    if (last.old) {\n                        target.position = el.position.slice();\n                        el.attr('position', last.old);\n                    }\n                }\n                else {\n                    if (last.old) {\n                        target.shape = extend({}, el.shape);\n                        el.setShape(last.old);\n                    }\n\n                    if (last.fadein) {\n                        el.setStyle('opacity', 0);\n                        target.style = {opacity: 1};\n                    }\n                    // When animation is stopped for succedent animation starting,\n                    // el.style.opacity might not be 1\n                    else if (el.style.opacity !== 1) {\n                        target.style = {opacity: 1};\n                    }\n                }\n\n                animationWrap.add(el, target, duration, easing);\n            });\n        }, this);\n\n        this._state = 'animating';\n\n        animationWrap\n            .done(bind$1(function () {\n                this._state = 'ready';\n                renderResult.renderFinally();\n            }, this))\n            .start();\n    },\n\n    /**\n     * @private\n     */\n    _resetController: function (api) {\n        var controller = this._controller;\n\n        // Init controller.\n        if (!controller) {\n            controller = this._controller = new RoamController(api.getZr());\n            controller.enable(this.seriesModel.get('roam'));\n            controller.on('pan', bind$1(this._onPan, this));\n            controller.on('zoom', bind$1(this._onZoom, this));\n        }\n\n        var rect = new BoundingRect(0, 0, api.getWidth(), api.getHeight());\n        controller.setPointerChecker(function (e, x, y) {\n            return rect.contain(x, y);\n        });\n    },\n\n    /**\n     * @private\n     */\n    _clearController: function () {\n        var controller = this._controller;\n        if (controller) {\n            controller.dispose();\n            controller = null;\n        }\n    },\n\n    /**\n     * @private\n     */\n    _onPan: function (e) {\n        if (this._state !== 'animating'\n            && (Math.abs(e.dx) > DRAG_THRESHOLD || Math.abs(e.dy) > DRAG_THRESHOLD)\n        ) {\n            // These param must not be cached.\n            var root = this.seriesModel.getData().tree.root;\n\n            if (!root) {\n                return;\n            }\n\n            var rootLayout = root.getLayout();\n\n            if (!rootLayout) {\n                return;\n            }\n\n            this.api.dispatchAction({\n                type: 'treemapMove',\n                from: this.uid,\n                seriesId: this.seriesModel.id,\n                rootRect: {\n                    x: rootLayout.x + e.dx, y: rootLayout.y + e.dy,\n                    width: rootLayout.width, height: rootLayout.height\n                }\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _onZoom: function (e) {\n        var mouseX = e.originX;\n        var mouseY = e.originY;\n\n        if (this._state !== 'animating') {\n            // These param must not be cached.\n            var root = this.seriesModel.getData().tree.root;\n\n            if (!root) {\n                return;\n            }\n\n            var rootLayout = root.getLayout();\n\n            if (!rootLayout) {\n                return;\n            }\n\n            var rect = new BoundingRect(\n                rootLayout.x, rootLayout.y, rootLayout.width, rootLayout.height\n            );\n            var layoutInfo = this.seriesModel.layoutInfo;\n\n            // Transform mouse coord from global to containerGroup.\n            mouseX -= layoutInfo.x;\n            mouseY -= layoutInfo.y;\n\n            // Scale root bounding rect.\n            var m = create$1();\n            translate(m, m, [-mouseX, -mouseY]);\n            scale$1(m, m, [e.scale, e.scale]);\n            translate(m, m, [mouseX, mouseY]);\n\n            rect.applyTransform(m);\n\n            this.api.dispatchAction({\n                type: 'treemapRender',\n                from: this.uid,\n                seriesId: this.seriesModel.id,\n                rootRect: {\n                    x: rect.x, y: rect.y,\n                    width: rect.width, height: rect.height\n                }\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _initEvents: function (containerGroup) {\n        containerGroup.on('click', function (e) {\n            if (this._state !== 'ready') {\n                return;\n            }\n\n            var nodeClick = this.seriesModel.get('nodeClick', true);\n\n            if (!nodeClick) {\n                return;\n            }\n\n            var targetInfo = this.findTarget(e.offsetX, e.offsetY);\n\n            if (!targetInfo) {\n                return;\n            }\n\n            var node = targetInfo.node;\n            if (node.getLayout().isLeafRoot) {\n                this._rootToNode(targetInfo);\n            }\n            else {\n                if (nodeClick === 'zoomToNode') {\n                    this._zoomToNode(targetInfo);\n                }\n                else if (nodeClick === 'link') {\n                    var itemModel = node.hostTree.data.getItemModel(node.dataIndex);\n                    var link = itemModel.get('link', true);\n                    var linkTarget = itemModel.get('target', true) || 'blank';\n                    link && window.open(link, linkTarget);\n                }\n            }\n\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _renderBreadcrumb: function (seriesModel, api, targetInfo) {\n        if (!targetInfo) {\n            targetInfo = seriesModel.get('leafDepth', true) != null\n                ? {node: seriesModel.getViewRoot()}\n                // FIXME\n                // better way?\n                // Find breadcrumb tail on center of containerGroup.\n                : this.findTarget(api.getWidth() / 2, api.getHeight() / 2);\n\n            if (!targetInfo) {\n                targetInfo = {node: seriesModel.getData().tree.root};\n            }\n        }\n\n        (this._breadcrumb || (this._breadcrumb = new Breadcrumb(this.group)))\n            .render(seriesModel, api, targetInfo.node, bind$1(onSelect, this));\n\n        function onSelect(node) {\n            if (this._state !== 'animating') {\n                aboveViewRoot(seriesModel.getViewRoot(), node)\n                    ? this._rootToNode({node: node})\n                    : this._zoomToNode({node: node});\n            }\n        }\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this._clearController();\n        this._containerGroup && this._containerGroup.removeAll();\n        this._storage = createStorage();\n        this._state = 'ready';\n        this._breadcrumb && this._breadcrumb.remove();\n    },\n\n    dispose: function () {\n        this._clearController();\n    },\n\n    /**\n     * @private\n     */\n    _zoomToNode: function (targetInfo) {\n        this.api.dispatchAction({\n            type: 'treemapZoomToNode',\n            from: this.uid,\n            seriesId: this.seriesModel.id,\n            targetNode: targetInfo.node\n        });\n    },\n\n    /**\n     * @private\n     */\n    _rootToNode: function (targetInfo) {\n        this.api.dispatchAction({\n            type: 'treemapRootToNode',\n            from: this.uid,\n            seriesId: this.seriesModel.id,\n            targetNode: targetInfo.node\n        });\n    },\n\n    /**\n     * @public\n     * @param {number} x Global coord x.\n     * @param {number} y Global coord y.\n     * @return {Object} info If not found, return undefined;\n     * @return {number} info.node Target node.\n     * @return {number} info.offsetX x refer to target node.\n     * @return {number} info.offsetY y refer to target node.\n     */\n    findTarget: function (x, y) {\n        var targetInfo;\n        var viewRoot = this.seriesModel.getViewRoot();\n\n        viewRoot.eachNode({attr: 'viewChildren', order: 'preorder'}, function (node) {\n            var bgEl = this._storage.background[node.getRawIndex()];\n            // If invisible, there might be no element.\n            if (bgEl) {\n                var point = bgEl.transformCoordToLocal(x, y);\n                var shape = bgEl.shape;\n\n                // For performance consideration, dont use 'getBoundingRect'.\n                if (shape.x <= point[0]\n                    && point[0] <= shape.x + shape.width\n                    && shape.y <= point[1]\n                    && point[1] <= shape.y + shape.height\n                ) {\n                    targetInfo = {node: node, offsetX: point[0], offsetY: point[1]};\n                }\n                else {\n                    return false; // Suppress visit subtree.\n                }\n            }\n        }, this);\n\n        return targetInfo;\n    }\n\n});\n\n/**\n * @inner\n */\nfunction createStorage() {\n    return {nodeGroup: [], background: [], content: []};\n}\n\n/**\n * @inner\n * @return Return undefined means do not travel further.\n */\nfunction renderNode(\n    seriesModel, thisStorage, oldStorage, reRoot,\n    lastsForAnimation, willInvisibleEls,\n    thisNode, oldNode, parentGroup, depth\n) {\n    // Whether under viewRoot.\n    if (!thisNode) {\n        // Deleting nodes will be performed finally. This method just find\n        // element from old storage, or create new element, set them to new\n        // storage, and set styles.\n        return;\n    }\n\n    // -------------------------------------------------------------------\n    // Start of closure variables available in \"Procedures in renderNode\".\n\n    var thisLayout = thisNode.getLayout();\n\n    if (!thisLayout || !thisLayout.isInView) {\n        return;\n    }\n\n    var thisWidth = thisLayout.width;\n    var thisHeight = thisLayout.height;\n    var borderWidth = thisLayout.borderWidth;\n    var thisInvisible = thisLayout.invisible;\n\n    var thisRawIndex = thisNode.getRawIndex();\n    var oldRawIndex = oldNode && oldNode.getRawIndex();\n\n    var thisViewChildren = thisNode.viewChildren;\n    var upperHeight = thisLayout.upperHeight;\n    var isParent = thisViewChildren && thisViewChildren.length;\n    var itemStyleNormalModel = thisNode.getModel('itemStyle');\n    var itemStyleEmphasisModel = thisNode.getModel('emphasis.itemStyle');\n\n    // End of closure ariables available in \"Procedures in renderNode\".\n    // -----------------------------------------------------------------\n\n    // Node group\n    var group = giveGraphic('nodeGroup', Group$2);\n\n    if (!group) {\n        return;\n    }\n\n    parentGroup.add(group);\n    // x,y are not set when el is above view root.\n    group.attr('position', [thisLayout.x || 0, thisLayout.y || 0]);\n    group.__tmNodeWidth = thisWidth;\n    group.__tmNodeHeight = thisHeight;\n\n    if (thisLayout.isAboveViewRoot) {\n        return group;\n    }\n\n    // Background\n    var bg = giveGraphic('background', Rect$1, depth, Z_BG);\n    bg && renderBackground(group, bg, isParent && thisLayout.upperHeight);\n\n    // No children, render content.\n    if (!isParent) {\n        var content = giveGraphic('content', Rect$1, depth, Z_CONTENT);\n        content && renderContent(group, content);\n    }\n\n    return group;\n\n    // ----------------------------\n    // | Procedures in renderNode |\n    // ----------------------------\n\n    function renderBackground(group, bg, useUpperLabel) {\n        // For tooltip.\n        bg.dataIndex = thisNode.dataIndex;\n        bg.seriesIndex = seriesModel.seriesIndex;\n\n        bg.setShape({x: 0, y: 0, width: thisWidth, height: thisHeight});\n        var visualBorderColor = thisNode.getVisual('borderColor', true);\n        var emphasisBorderColor = itemStyleEmphasisModel.get('borderColor');\n\n        updateStyle(bg, function () {\n            var normalStyle = getItemStyleNormal(itemStyleNormalModel);\n            normalStyle.fill = visualBorderColor;\n            var emphasisStyle = getItemStyleEmphasis(itemStyleEmphasisModel);\n            emphasisStyle.fill = emphasisBorderColor;\n\n            if (useUpperLabel) {\n                var upperLabelWidth = thisWidth - 2 * borderWidth;\n\n                prepareText(\n                    normalStyle, emphasisStyle, visualBorderColor, upperLabelWidth, upperHeight,\n                    {x: borderWidth, y: 0, width: upperLabelWidth, height: upperHeight}\n                );\n            }\n            // For old bg.\n            else {\n                normalStyle.text = emphasisStyle.text = null;\n            }\n\n            bg.setStyle(normalStyle);\n            setHoverStyle(bg, emphasisStyle);\n        });\n\n        group.add(bg);\n    }\n\n    function renderContent(group, content) {\n        // For tooltip.\n        content.dataIndex = thisNode.dataIndex;\n        content.seriesIndex = seriesModel.seriesIndex;\n\n        var contentWidth = Math.max(thisWidth - 2 * borderWidth, 0);\n        var contentHeight = Math.max(thisHeight - 2 * borderWidth, 0);\n\n        content.culling = true;\n        content.setShape({\n            x: borderWidth,\n            y: borderWidth,\n            width: contentWidth,\n            height: contentHeight\n        });\n\n        var visualColor = thisNode.getVisual('color', true);\n        updateStyle(content, function () {\n            var normalStyle = getItemStyleNormal(itemStyleNormalModel);\n            normalStyle.fill = visualColor;\n            var emphasisStyle = getItemStyleEmphasis(itemStyleEmphasisModel);\n\n            prepareText(normalStyle, emphasisStyle, visualColor, contentWidth, contentHeight);\n\n            content.setStyle(normalStyle);\n            setHoverStyle(content, emphasisStyle);\n        });\n\n        group.add(content);\n    }\n\n    function updateStyle(element, cb) {\n        if (!thisInvisible) {\n            // If invisible, do not set visual, otherwise the element will\n            // change immediately before animation. We think it is OK to\n            // remain its origin color when moving out of the view window.\n            cb();\n\n            if (!element.__tmWillVisible) {\n                element.invisible = false;\n            }\n        }\n        else {\n            // Delay invisible setting utill animation finished,\n            // avoid element vanish suddenly before animation.\n            !element.invisible && willInvisibleEls.push(element);\n        }\n    }\n\n    function prepareText(normalStyle, emphasisStyle, visualColor, width, height, upperLabelRect) {\n        var nodeModel = thisNode.getModel();\n        var text = retrieve(\n            seriesModel.getFormattedLabel(\n                thisNode.dataIndex, 'normal', null, null, upperLabelRect ? 'upperLabel' : 'label'\n            ),\n            nodeModel.get('name')\n        );\n        if (!upperLabelRect && thisLayout.isLeafRoot) {\n            var iconChar = seriesModel.get('drillDownIcon', true);\n            text = iconChar ? iconChar + ' ' + text : text;\n        }\n\n        var normalLabelModel = nodeModel.getModel(\n            upperLabelRect ? PATH_UPPERLABEL_NORMAL : PATH_LABEL_NOAMAL\n        );\n        var emphasisLabelModel = nodeModel.getModel(\n            upperLabelRect ? PATH_UPPERLABEL_EMPHASIS : PATH_LABEL_EMPHASIS\n        );\n\n        var isShow = normalLabelModel.getShallow('show');\n\n        setLabelStyle(\n            normalStyle, emphasisStyle, normalLabelModel, emphasisLabelModel,\n            {\n                defaultText: isShow ? text : null,\n                autoColor: visualColor,\n                isRectText: true\n            }\n        );\n\n        upperLabelRect && (normalStyle.textRect = clone(upperLabelRect));\n\n        normalStyle.truncate = (isShow && normalLabelModel.get('ellipsis'))\n            ? {\n                outerWidth: width,\n                outerHeight: height,\n                minChar: 2\n            }\n            : null;\n    }\n\n    function giveGraphic(storageName, Ctor, depth, z) {\n        var element = oldRawIndex != null && oldStorage[storageName][oldRawIndex];\n        var lasts = lastsForAnimation[storageName];\n\n        if (element) {\n            // Remove from oldStorage\n            oldStorage[storageName][oldRawIndex] = null;\n            prepareAnimationWhenHasOld(lasts, element, storageName);\n        }\n        // If invisible and no old element, do not create new element (for optimizing).\n        else if (!thisInvisible) {\n            element = new Ctor({z: calculateZ(depth, z)});\n            element.__tmDepth = depth;\n            element.__tmStorageName = storageName;\n            prepareAnimationWhenNoOld(lasts, element, storageName);\n        }\n\n        // Set to thisStorage\n        return (thisStorage[storageName][thisRawIndex] = element);\n    }\n\n    function prepareAnimationWhenHasOld(lasts, element, storageName) {\n        var lastCfg = lasts[thisRawIndex] = {};\n        lastCfg.old = storageName === 'nodeGroup'\n            ? element.position.slice()\n            : extend({}, element.shape);\n    }\n\n    // If a element is new, we need to find the animation start point carefully,\n    // otherwise it will looks strange when 'zoomToNode'.\n    function prepareAnimationWhenNoOld(lasts, element, storageName) {\n        var lastCfg = lasts[thisRawIndex] = {};\n        var parentNode = thisNode.parentNode;\n\n        if (parentNode && (!reRoot || reRoot.direction === 'drillDown')) {\n            var parentOldX = 0;\n            var parentOldY = 0;\n\n            // New nodes appear from right-bottom corner in 'zoomToNode' animation.\n            // For convenience, get old bounding rect from background.\n            var parentOldBg = lastsForAnimation.background[parentNode.getRawIndex()];\n            if (!reRoot && parentOldBg && parentOldBg.old) {\n                parentOldX = parentOldBg.old.width;\n                parentOldY = parentOldBg.old.height;\n            }\n\n            // When no parent old shape found, its parent is new too,\n            // so we can just use {x:0, y:0}.\n            lastCfg.old = storageName === 'nodeGroup'\n                ? [0, parentOldY]\n                : {x: parentOldX, y: parentOldY, width: 0, height: 0};\n        }\n\n        // Fade in, user can be aware that these nodes are new.\n        lastCfg.fadein = storageName !== 'nodeGroup';\n    }\n}\n\n// We can not set all backgroud with the same z, Because the behaviour of\n// drill down and roll up differ background creation sequence from tree\n// hierarchy sequence, which cause that lowser background element overlap\n// upper ones. So we calculate z based on depth.\n// Moreover, we try to shrink down z interval to [0, 1] to avoid that\n// treemap with large z overlaps other components.\nfunction calculateZ(depth, zInLevel) {\n    var zb = depth * Z_BASE + zInLevel;\n    return (zb - 1) / zb;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Treemap action\n */\n\nvar noop$1 = function () {};\n\nvar actionTypes = [\n    'treemapZoomToNode',\n    'treemapRender',\n    'treemapMove'\n];\n\nfor (var i$2 = 0; i$2 < actionTypes.length; i$2++) {\n    registerAction({type: actionTypes[i$2], update: 'updateView'}, noop$1);\n}\n\nregisterAction(\n    {type: 'treemapRootToNode', update: 'updateView'},\n    function (payload, ecModel) {\n\n        ecModel.eachComponent(\n            {mainType: 'series', subType: 'treemap', query: payload},\n            handleRootToNode\n        );\n\n        function handleRootToNode(model, index) {\n            var types = ['treemapZoomToNode', 'treemapRootToNode'];\n            var targetInfo = retrieveTargetInfo(payload, types, model);\n\n            if (targetInfo) {\n                var originViewRoot = model.getViewRoot();\n                if (originViewRoot) {\n                    payload.direction = aboveViewRoot(originViewRoot, targetInfo.node)\n                        ? 'rollUp' : 'drillDown';\n                }\n                model.resetViewRoot(targetInfo.node);\n            }\n        }\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$9 = each$1;\nvar isObject$5 = isObject$1;\n\nvar CATEGORY_DEFAULT_VISUAL_INDEX = -1;\n\n/**\n * @param {Object} option\n * @param {string} [option.type] See visualHandlers.\n * @param {string} [option.mappingMethod] 'linear' or 'piecewise' or 'category' or 'fixed'\n * @param {Array.<number>=} [option.dataExtent] [minExtent, maxExtent],\n *                                              required when mappingMethod is 'linear'\n * @param {Array.<Object>=} [option.pieceList] [\n *                                             {value: someValue},\n *                                             {interval: [min1, max1], visual: {...}},\n *                                             {interval: [min2, max2]}\n *                                             ],\n *                                            required when mappingMethod is 'piecewise'.\n *                                            Visual for only each piece can be specified.\n * @param {Array.<string|Object>=} [option.categories] ['cate1', 'cate2']\n *                                            required when mappingMethod is 'category'.\n *                                            If no option.categories, categories is set\n *                                            as [0, 1, 2, ...].\n * @param {boolean} [option.loop=false] Whether loop mapping when mappingMethod is 'category'.\n * @param {(Array|Object|*)} [option.visual]  Visual data.\n *                                            when mappingMethod is 'category',\n *                                            visual data can be array or object\n *                                            (like: {cate1: '#222', none: '#fff'})\n *                                            or primary types (which represents\n *                                            defualt category visual), otherwise visual\n *                                            can be array or primary (which will be\n *                                            normalized to array).\n *\n */\nvar VisualMapping = function (option) {\n    var mappingMethod = option.mappingMethod;\n    var visualType = option.type;\n\n    /**\n     * @readOnly\n     * @type {Object}\n     */\n    var thisOption = this.option = clone(option);\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    this.type = visualType;\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    this.mappingMethod = mappingMethod;\n\n    /**\n     * @private\n     * @type {Function}\n     */\n    this._normalizeData = normalizers[mappingMethod];\n\n    var visualHandler = visualHandlers[visualType];\n\n    /**\n     * @public\n     * @type {Function}\n     */\n    this.applyVisual = visualHandler.applyVisual;\n\n    /**\n     * @public\n     * @type {Function}\n     */\n    this.getColorMapper = visualHandler.getColorMapper;\n\n    /**\n     * @private\n     * @type {Function}\n     */\n    this._doMap = visualHandler._doMap[mappingMethod];\n\n    if (mappingMethod === 'piecewise') {\n        normalizeVisualRange(thisOption);\n        preprocessForPiecewise(thisOption);\n    }\n    else if (mappingMethod === 'category') {\n        thisOption.categories\n            ? preprocessForSpecifiedCategory(thisOption)\n            // categories is ordinal when thisOption.categories not specified,\n            // which need no more preprocess except normalize visual.\n            : normalizeVisualRange(thisOption, true);\n    }\n    else { // mappingMethod === 'linear' or 'fixed'\n        assert$1(mappingMethod !== 'linear' || thisOption.dataExtent);\n        normalizeVisualRange(thisOption);\n    }\n};\n\nVisualMapping.prototype = {\n\n    constructor: VisualMapping,\n\n    mapValueToVisual: function (value) {\n        var normalized = this._normalizeData(value);\n        return this._doMap(normalized, value);\n    },\n\n    getNormalizer: function () {\n        return bind(this._normalizeData, this);\n    }\n};\n\nvar visualHandlers = VisualMapping.visualHandlers = {\n\n    color: {\n\n        applyVisual: makeApplyVisual('color'),\n\n        /**\n         * Create a mapper function\n         * @return {Function}\n         */\n        getColorMapper: function () {\n            var thisOption = this.option;\n\n            return bind(\n                thisOption.mappingMethod === 'category'\n                    ? function (value, isNormalized) {\n                        !isNormalized && (value = this._normalizeData(value));\n                        return doMapCategory.call(this, value);\n                    }\n                    : function (value, isNormalized, out) {\n                        // If output rgb array\n                        // which will be much faster and useful in pixel manipulation\n                        var returnRGBArray = !!out;\n                        !isNormalized && (value = this._normalizeData(value));\n                        out = fastLerp(value, thisOption.parsedVisual, out);\n                        return returnRGBArray ? out : stringify(out, 'rgba');\n                    },\n                this\n            );\n        },\n\n        _doMap: {\n            linear: function (normalized) {\n                return stringify(\n                    fastLerp(normalized, this.option.parsedVisual),\n                    'rgba'\n                );\n            },\n            category: doMapCategory,\n            piecewise: function (normalized, value) {\n                var result = getSpecifiedVisual.call(this, value);\n                if (result == null) {\n                    result = stringify(\n                        fastLerp(normalized, this.option.parsedVisual),\n                        'rgba'\n                    );\n                }\n                return result;\n            },\n            fixed: doMapFixed\n        }\n    },\n\n    colorHue: makePartialColorVisualHandler(function (color, value) {\n        return modifyHSL(color, value);\n    }),\n\n    colorSaturation: makePartialColorVisualHandler(function (color, value) {\n        return modifyHSL(color, null, value);\n    }),\n\n    colorLightness: makePartialColorVisualHandler(function (color, value) {\n        return modifyHSL(color, null, null, value);\n    }),\n\n    colorAlpha: makePartialColorVisualHandler(function (color, value) {\n        return modifyAlpha(color, value);\n    }),\n\n    opacity: {\n        applyVisual: makeApplyVisual('opacity'),\n        _doMap: makeDoMap([0, 1])\n    },\n\n    liftZ: {\n        applyVisual: makeApplyVisual('liftZ'),\n        _doMap: {\n            linear: doMapFixed,\n            category: doMapFixed,\n            piecewise: doMapFixed,\n            fixed: doMapFixed\n        }\n    },\n\n    symbol: {\n        applyVisual: function (value, getter, setter) {\n            var symbolCfg = this.mapValueToVisual(value);\n            if (isString(symbolCfg)) {\n                setter('symbol', symbolCfg);\n            }\n            else if (isObject$5(symbolCfg)) {\n                for (var name in symbolCfg) {\n                    if (symbolCfg.hasOwnProperty(name)) {\n                        setter(name, symbolCfg[name]);\n                    }\n                }\n            }\n        },\n        _doMap: {\n            linear: doMapToArray,\n            category: doMapCategory,\n            piecewise: function (normalized, value) {\n                var result = getSpecifiedVisual.call(this, value);\n                if (result == null) {\n                    result = doMapToArray.call(this, normalized);\n                }\n                return result;\n            },\n            fixed: doMapFixed\n        }\n    },\n\n    symbolSize: {\n        applyVisual: makeApplyVisual('symbolSize'),\n        _doMap: makeDoMap([0, 1])\n    }\n};\n\n\nfunction preprocessForPiecewise(thisOption) {\n    var pieceList = thisOption.pieceList;\n    thisOption.hasSpecialVisual = false;\n\n    each$1(pieceList, function (piece, index) {\n        piece.originIndex = index;\n        // piece.visual is \"result visual value\" but not\n        // a visual range, so it does not need to be normalized.\n        if (piece.visual != null) {\n            thisOption.hasSpecialVisual = true;\n        }\n    });\n}\n\nfunction preprocessForSpecifiedCategory(thisOption) {\n    // Hash categories.\n    var categories = thisOption.categories;\n    var visual = thisOption.visual;\n\n    var categoryMap = thisOption.categoryMap = {};\n    each$9(categories, function (cate, index) {\n        categoryMap[cate] = index;\n    });\n\n    // Process visual map input.\n    if (!isArray(visual)) {\n        var visualArr = [];\n\n        if (isObject$1(visual)) {\n            each$9(visual, function (v, cate) {\n                var index = categoryMap[cate];\n                visualArr[index != null ? index : CATEGORY_DEFAULT_VISUAL_INDEX] = v;\n            });\n        }\n        else { // Is primary type, represents default visual.\n            visualArr[CATEGORY_DEFAULT_VISUAL_INDEX] = visual;\n        }\n\n        visual = setVisualToOption(thisOption, visualArr);\n    }\n\n    // Remove categories that has no visual,\n    // then we can mapping them to CATEGORY_DEFAULT_VISUAL_INDEX.\n    for (var i = categories.length - 1; i >= 0; i--) {\n        if (visual[i] == null) {\n            delete categoryMap[categories[i]];\n            categories.pop();\n        }\n    }\n}\n\nfunction normalizeVisualRange(thisOption, isCategory) {\n    var visual = thisOption.visual;\n    var visualArr = [];\n\n    if (isObject$1(visual)) {\n        each$9(visual, function (v) {\n            visualArr.push(v);\n        });\n    }\n    else if (visual != null) {\n        visualArr.push(visual);\n    }\n\n    var doNotNeedPair = {color: 1, symbol: 1};\n\n    if (!isCategory\n        && visualArr.length === 1\n        && !doNotNeedPair.hasOwnProperty(thisOption.type)\n    ) {\n        // Do not care visualArr.length === 0, which is illegal.\n        visualArr[1] = visualArr[0];\n    }\n\n    setVisualToOption(thisOption, visualArr);\n}\n\nfunction makePartialColorVisualHandler(applyValue) {\n    return {\n        applyVisual: function (value, getter, setter) {\n            value = this.mapValueToVisual(value);\n            // Must not be array value\n            setter('color', applyValue(getter('color'), value));\n        },\n        _doMap: makeDoMap([0, 1])\n    };\n}\n\nfunction doMapToArray(normalized) {\n    var visual = this.option.visual;\n    return visual[\n        Math.round(linearMap(normalized, [0, 1], [0, visual.length - 1], true))\n    ] || {};\n}\n\nfunction makeApplyVisual(visualType) {\n    return function (value, getter, setter) {\n        setter(visualType, this.mapValueToVisual(value));\n    };\n}\n\nfunction doMapCategory(normalized) {\n    var visual = this.option.visual;\n    return visual[\n        (this.option.loop && normalized !== CATEGORY_DEFAULT_VISUAL_INDEX)\n            ? normalized % visual.length\n            : normalized\n    ];\n}\n\nfunction doMapFixed() {\n    return this.option.visual[0];\n}\n\nfunction makeDoMap(sourceExtent) {\n    return {\n        linear: function (normalized) {\n            return linearMap(normalized, sourceExtent, this.option.visual, true);\n        },\n        category: doMapCategory,\n        piecewise: function (normalized, value) {\n            var result = getSpecifiedVisual.call(this, value);\n            if (result == null) {\n                result = linearMap(normalized, sourceExtent, this.option.visual, true);\n            }\n            return result;\n        },\n        fixed: doMapFixed\n    };\n}\n\nfunction getSpecifiedVisual(value) {\n    var thisOption = this.option;\n    var pieceList = thisOption.pieceList;\n    if (thisOption.hasSpecialVisual) {\n        var pieceIndex = VisualMapping.findPieceIndex(value, pieceList);\n        var piece = pieceList[pieceIndex];\n        if (piece && piece.visual) {\n            return piece.visual[this.type];\n        }\n    }\n}\n\nfunction setVisualToOption(thisOption, visualArr) {\n    thisOption.visual = visualArr;\n    if (thisOption.type === 'color') {\n        thisOption.parsedVisual = map(visualArr, function (item) {\n            return parse(item);\n        });\n    }\n    return visualArr;\n}\n\n\n/**\n * Normalizers by mapping methods.\n */\nvar normalizers = {\n\n    linear: function (value) {\n        return linearMap(value, this.option.dataExtent, [0, 1], true);\n    },\n\n    piecewise: function (value) {\n        var pieceList = this.option.pieceList;\n        var pieceIndex = VisualMapping.findPieceIndex(value, pieceList, true);\n        if (pieceIndex != null) {\n            return linearMap(pieceIndex, [0, pieceList.length - 1], [0, 1], true);\n        }\n    },\n\n    category: function (value) {\n        var index = this.option.categories\n            ? this.option.categoryMap[value]\n            : value; // ordinal\n        return index == null ? CATEGORY_DEFAULT_VISUAL_INDEX : index;\n    },\n\n    fixed: noop\n};\n\n\n\n/**\n * List available visual types.\n *\n * @public\n * @return {Array.<string>}\n */\nVisualMapping.listVisualTypes = function () {\n    var visualTypes = [];\n    each$1(visualHandlers, function (handler, key) {\n        visualTypes.push(key);\n    });\n    return visualTypes;\n};\n\n/**\n * @public\n */\nVisualMapping.addVisualHandler = function (name, handler) {\n    visualHandlers[name] = handler;\n};\n\n/**\n * @public\n */\nVisualMapping.isValidType = function (visualType) {\n    return visualHandlers.hasOwnProperty(visualType);\n};\n\n/**\n * Convinent method.\n * Visual can be Object or Array or primary type.\n *\n * @public\n */\nVisualMapping.eachVisual = function (visual, callback, context) {\n    if (isObject$1(visual)) {\n        each$1(visual, callback, context);\n    }\n    else {\n        callback.call(context, visual);\n    }\n};\n\nVisualMapping.mapVisual = function (visual, callback, context) {\n    var isPrimary;\n    var newVisual = isArray(visual)\n        ? []\n        : isObject$1(visual)\n        ? {}\n        : (isPrimary = true, null);\n\n    VisualMapping.eachVisual(visual, function (v, key) {\n        var newVal = callback.call(context, v, key);\n        isPrimary ? (newVisual = newVal) : (newVisual[key] = newVal);\n    });\n    return newVisual;\n};\n\n/**\n * @public\n * @param {Object} obj\n * @return {Object} new object containers visual values.\n *                 If no visuals, return null.\n */\nVisualMapping.retrieveVisuals = function (obj) {\n    var ret = {};\n    var hasVisual;\n\n    obj && each$9(visualHandlers, function (h, visualType) {\n        if (obj.hasOwnProperty(visualType)) {\n            ret[visualType] = obj[visualType];\n            hasVisual = true;\n        }\n    });\n\n    return hasVisual ? ret : null;\n};\n\n/**\n * Give order to visual types, considering colorSaturation, colorAlpha depends on color.\n *\n * @public\n * @param {(Object|Array)} visualTypes If Object, like: {color: ..., colorSaturation: ...}\n *                                     IF Array, like: ['color', 'symbol', 'colorSaturation']\n * @return {Array.<string>} Sorted visual types.\n */\nVisualMapping.prepareVisualTypes = function (visualTypes) {\n    if (isObject$5(visualTypes)) {\n        var types = [];\n        each$9(visualTypes, function (item, type) {\n            types.push(type);\n        });\n        visualTypes = types;\n    }\n    else if (isArray(visualTypes)) {\n        visualTypes = visualTypes.slice();\n    }\n    else {\n        return [];\n    }\n\n    visualTypes.sort(function (type1, type2) {\n        // color should be front of colorSaturation, colorAlpha, ...\n        // symbol and symbolSize do not matter.\n        return (type2 === 'color' && type1 !== 'color' && type1.indexOf('color') === 0)\n            ? 1 : -1;\n    });\n\n    return visualTypes;\n};\n\n/**\n * 'color', 'colorSaturation', 'colorAlpha', ... are depends on 'color'.\n * Other visuals are only depends on themself.\n *\n * @public\n * @param {string} visualType1\n * @param {string} visualType2\n * @return {boolean}\n */\nVisualMapping.dependsOn = function (visualType1, visualType2) {\n    return visualType2 === 'color'\n        ? !!(visualType1 && visualType1.indexOf(visualType2) === 0)\n        : visualType1 === visualType2;\n};\n\n/**\n * @param {number} value\n * @param {Array.<Object>} pieceList [{value: ..., interval: [min, max]}, ...]\n *                         Always from small to big.\n * @param {boolean} [findClosestWhenOutside=false]\n * @return {number} index\n */\nVisualMapping.findPieceIndex = function (value, pieceList, findClosestWhenOutside) {\n    var possibleI;\n    var abs = Infinity;\n\n    // value has the higher priority.\n    for (var i = 0, len = pieceList.length; i < len; i++) {\n        var pieceValue = pieceList[i].value;\n        if (pieceValue != null) {\n            if (pieceValue === value\n                // FIXME\n                // It is supposed to compare value according to value type of dimension,\n                // but currently value type can exactly be string or number.\n                // Compromise for numeric-like string (like '12'), especially\n                // in the case that visualMap.categories is ['22', '33'].\n                || (typeof pieceValue === 'string' && pieceValue === value + '')\n            ) {\n                return i;\n            }\n            findClosestWhenOutside && updatePossible(pieceValue, i);\n        }\n    }\n\n    for (var i = 0, len = pieceList.length; i < len; i++) {\n        var piece = pieceList[i];\n        var interval = piece.interval;\n        var close = piece.close;\n\n        if (interval) {\n            if (interval[0] === -Infinity) {\n                if (littleThan(close[1], value, interval[1])) {\n                    return i;\n                }\n            }\n            else if (interval[1] === Infinity) {\n                if (littleThan(close[0], interval[0], value)) {\n                    return i;\n                }\n            }\n            else if (\n                littleThan(close[0], interval[0], value)\n                && littleThan(close[1], value, interval[1])\n            ) {\n                return i;\n            }\n            findClosestWhenOutside && updatePossible(interval[0], i);\n            findClosestWhenOutside && updatePossible(interval[1], i);\n        }\n    }\n\n    if (findClosestWhenOutside) {\n        return value === Infinity\n            ? pieceList.length - 1\n            : value === -Infinity\n            ? 0\n            : possibleI;\n    }\n\n    function updatePossible(val, index) {\n        var newAbs = Math.abs(val - value);\n        if (newAbs < abs) {\n            abs = newAbs;\n            possibleI = index;\n        }\n    }\n\n};\n\nfunction littleThan(close, a, b) {\n    return close ? a <= b : a < b;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar isArray$2 = isArray;\n\nvar ITEM_STYLE_NORMAL = 'itemStyle';\n\nvar treemapVisual = {\n    seriesType: 'treemap',\n    reset: function (seriesModel, ecModel, api, payload) {\n        var tree = seriesModel.getData().tree;\n        var root = tree.root;\n        var seriesItemStyleModel = seriesModel.getModel(ITEM_STYLE_NORMAL);\n\n        if (root.isRemoved()) {\n            return;\n        }\n\n        var levelItemStyles = map(tree.levelModels, function (levelModel) {\n            return levelModel ? levelModel.get(ITEM_STYLE_NORMAL) : null;\n        });\n\n        travelTree(\n            root, // Visual should calculate from tree root but not view root.\n            {},\n            levelItemStyles,\n            seriesItemStyleModel,\n            seriesModel.getViewRoot().getAncestors(),\n            seriesModel\n        );\n    }\n};\n\nfunction travelTree(\n    node, designatedVisual, levelItemStyles, seriesItemStyleModel,\n    viewRootAncestors, seriesModel\n) {\n    var nodeModel = node.getModel();\n    var nodeLayout = node.getLayout();\n\n    // Optimize\n    if (!nodeLayout || nodeLayout.invisible || !nodeLayout.isInView) {\n        return;\n    }\n\n    var nodeItemStyleModel = node.getModel(ITEM_STYLE_NORMAL);\n    var levelItemStyle = levelItemStyles[node.depth];\n    var visuals = buildVisuals(\n        nodeItemStyleModel, designatedVisual, levelItemStyle, seriesItemStyleModel\n    );\n\n    // calculate border color\n    var borderColor = nodeItemStyleModel.get('borderColor');\n    var borderColorSaturation = nodeItemStyleModel.get('borderColorSaturation');\n    var thisNodeColor;\n    if (borderColorSaturation != null) {\n        // For performance, do not always execute 'calculateColor'.\n        thisNodeColor = calculateColor(visuals, node);\n        borderColor = calculateBorderColor(borderColorSaturation, thisNodeColor);\n    }\n    node.setVisual('borderColor', borderColor);\n\n    var viewChildren = node.viewChildren;\n    if (!viewChildren || !viewChildren.length) {\n        thisNodeColor = calculateColor(visuals, node);\n        // Apply visual to this node.\n        node.setVisual('color', thisNodeColor);\n    }\n    else {\n        var mapping = buildVisualMapping(\n            node, nodeModel, nodeLayout, nodeItemStyleModel, visuals, viewChildren\n        );\n\n        // Designate visual to children.\n        each$1(viewChildren, function (child, index) {\n            // If higher than viewRoot, only ancestors of viewRoot is needed to visit.\n            if (child.depth >= viewRootAncestors.length\n                || child === viewRootAncestors[child.depth]\n            ) {\n                var childVisual = mapVisual$1(\n                    nodeModel, visuals, child, index, mapping, seriesModel\n                );\n                travelTree(\n                    child, childVisual, levelItemStyles, seriesItemStyleModel,\n                    viewRootAncestors, seriesModel\n                );\n            }\n        });\n    }\n}\n\nfunction buildVisuals(\n    nodeItemStyleModel, designatedVisual, levelItemStyle, seriesItemStyleModel\n) {\n    var visuals = extend({}, designatedVisual);\n\n    each$1(['color', 'colorAlpha', 'colorSaturation'], function (visualName) {\n        // Priority: thisNode > thisLevel > parentNodeDesignated > seriesModel\n        var val = nodeItemStyleModel.get(visualName, true); // Ignore parent\n        val == null && levelItemStyle && (val = levelItemStyle[visualName]);\n        val == null && (val = designatedVisual[visualName]);\n        val == null && (val = seriesItemStyleModel.get(visualName));\n\n        val != null && (visuals[visualName] = val);\n    });\n\n    return visuals;\n}\n\nfunction calculateColor(visuals) {\n    var color = getValueVisualDefine(visuals, 'color');\n\n    if (color) {\n        var colorAlpha = getValueVisualDefine(visuals, 'colorAlpha');\n        var colorSaturation = getValueVisualDefine(visuals, 'colorSaturation');\n        if (colorSaturation) {\n            color = modifyHSL(color, null, null, colorSaturation);\n        }\n        if (colorAlpha) {\n            color = modifyAlpha(color, colorAlpha);\n        }\n\n        return color;\n    }\n}\n\nfunction calculateBorderColor(borderColorSaturation, thisNodeColor) {\n    return thisNodeColor != null\n            ? modifyHSL(thisNodeColor, null, null, borderColorSaturation)\n            : null;\n}\n\nfunction getValueVisualDefine(visuals, name) {\n    var value = visuals[name];\n    if (value != null && value !== 'none') {\n        return value;\n    }\n}\n\nfunction buildVisualMapping(\n    node, nodeModel, nodeLayout, nodeItemStyleModel, visuals, viewChildren\n) {\n    if (!viewChildren || !viewChildren.length) {\n        return;\n    }\n\n    var rangeVisual = getRangeVisual(nodeModel, 'color')\n        || (\n            visuals.color != null\n            && visuals.color !== 'none'\n            && (\n                getRangeVisual(nodeModel, 'colorAlpha')\n                || getRangeVisual(nodeModel, 'colorSaturation')\n            )\n        );\n\n    if (!rangeVisual) {\n        return;\n    }\n\n    var visualMin = nodeModel.get('visualMin');\n    var visualMax = nodeModel.get('visualMax');\n    var dataExtent = nodeLayout.dataExtent.slice();\n    visualMin != null && visualMin < dataExtent[0] && (dataExtent[0] = visualMin);\n    visualMax != null && visualMax > dataExtent[1] && (dataExtent[1] = visualMax);\n\n    var colorMappingBy = nodeModel.get('colorMappingBy');\n    var opt = {\n        type: rangeVisual.name,\n        dataExtent: dataExtent,\n        visual: rangeVisual.range\n    };\n    if (opt.type === 'color'\n        && (colorMappingBy === 'index' || colorMappingBy === 'id')\n    ) {\n        opt.mappingMethod = 'category';\n        opt.loop = true;\n        // categories is ordinal, so do not set opt.categories.\n    }\n    else {\n        opt.mappingMethod = 'linear';\n    }\n\n    var mapping = new VisualMapping(opt);\n    mapping.__drColorMappingBy = colorMappingBy;\n\n    return mapping;\n}\n\n// Notice: If we dont have the attribute 'colorRange', but only use\n// attribute 'color' to represent both concepts of 'colorRange' and 'color',\n// (It means 'colorRange' when 'color' is Array, means 'color' when not array),\n// this problem will be encountered:\n// If a level-1 node dont have children, and its siblings has children,\n// and colorRange is set on level-1, then the node can not be colored.\n// So we separate 'colorRange' and 'color' to different attributes.\nfunction getRangeVisual(nodeModel, name) {\n    // 'colorRange', 'colorARange', 'colorSRange'.\n    // If not exsits on this node, fetch from levels and series.\n    var range = nodeModel.get(name);\n    return (isArray$2(range) && range.length) ? {name: name, range: range} : null;\n}\n\nfunction mapVisual$1(nodeModel, visuals, child, index, mapping, seriesModel) {\n    var childVisuals = extend({}, visuals);\n\n    if (mapping) {\n        var mappingType = mapping.type;\n        var colorMappingBy = mappingType === 'color' && mapping.__drColorMappingBy;\n        var value = colorMappingBy === 'index'\n            ? index\n            : colorMappingBy === 'id'\n            ? seriesModel.mapIdToIndex(child.getId())\n            : child.getValue(nodeModel.get('visualDimension'));\n\n        childVisuals[mappingType] = mapping.mapValueToVisual(value);\n    }\n\n    return childVisuals;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The treemap layout implementation was originally copied from\n* \"d3.js\" with some modifications made for this project.\n* (See more details in the comment of the method \"squarify\" below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\nvar mathMax$4 = Math.max;\nvar mathMin$4 = Math.min;\nvar retrieveValue = retrieve;\nvar each$10 = each$1;\n\nvar PATH_BORDER_WIDTH = ['itemStyle', 'borderWidth'];\nvar PATH_GAP_WIDTH = ['itemStyle', 'gapWidth'];\nvar PATH_UPPER_LABEL_SHOW = ['upperLabel', 'show'];\nvar PATH_UPPER_LABEL_HEIGHT = ['upperLabel', 'height'];\n\n/**\n * @public\n */\nvar treemapLayout = {\n    seriesType: 'treemap',\n    reset: function (seriesModel, ecModel, api, payload) {\n        // Layout result in each node:\n        // {x, y, width, height, area, borderWidth}\n        var ecWidth = api.getWidth();\n        var ecHeight = api.getHeight();\n        var seriesOption = seriesModel.option;\n\n        var layoutInfo = getLayoutRect(\n            seriesModel.getBoxLayoutParams(),\n            {\n                width: api.getWidth(),\n                height: api.getHeight()\n            }\n        );\n\n        var size = seriesOption.size || []; // Compatible with ec2.\n        var containerWidth = parsePercent$1(\n            retrieveValue(layoutInfo.width, size[0]),\n            ecWidth\n        );\n        var containerHeight = parsePercent$1(\n            retrieveValue(layoutInfo.height, size[1]),\n            ecHeight\n        );\n\n        // Fetch payload info.\n        var payloadType = payload && payload.type;\n        var types = ['treemapZoomToNode', 'treemapRootToNode'];\n        var targetInfo = retrieveTargetInfo(payload, types, seriesModel);\n        var rootRect = (payloadType === 'treemapRender' || payloadType === 'treemapMove')\n            ? payload.rootRect : null;\n        var viewRoot = seriesModel.getViewRoot();\n        var viewAbovePath = getPathToRoot(viewRoot);\n\n        if (payloadType !== 'treemapMove') {\n            var rootSize = payloadType === 'treemapZoomToNode'\n                ? estimateRootSize(\n                    seriesModel, targetInfo, viewRoot, containerWidth, containerHeight\n                )\n                : rootRect\n                ? [rootRect.width, rootRect.height]\n                : [containerWidth, containerHeight];\n\n            var sort = seriesOption.sort;\n            if (sort && sort !== 'asc' && sort !== 'desc') {\n                sort = 'desc';\n            }\n            var options = {\n                squareRatio: seriesOption.squareRatio,\n                sort: sort,\n                leafDepth: seriesOption.leafDepth\n            };\n\n            // layout should be cleared because using updateView but not update.\n            viewRoot.hostTree.clearLayouts();\n\n            // TODO\n            // optimize: if out of view clip, do not layout.\n            // But take care that if do not render node out of view clip,\n            // how to calculate start po\n\n            var viewRootLayout = {\n                x: 0, y: 0,\n                width: rootSize[0], height: rootSize[1],\n                area: rootSize[0] * rootSize[1]\n            };\n            viewRoot.setLayout(viewRootLayout);\n\n            squarify(viewRoot, options, false, 0);\n            // Supplement layout.\n            var viewRootLayout = viewRoot.getLayout();\n            each$10(viewAbovePath, function (node, index) {\n                var childValue = (viewAbovePath[index + 1] || viewRoot).getValue();\n                node.setLayout(extend(\n                    {dataExtent: [childValue, childValue], borderWidth: 0, upperHeight: 0},\n                    viewRootLayout\n                ));\n            });\n        }\n\n        var treeRoot = seriesModel.getData().tree.root;\n\n        treeRoot.setLayout(\n            calculateRootPosition(layoutInfo, rootRect, targetInfo),\n            true\n        );\n\n        seriesModel.setLayoutInfo(layoutInfo);\n\n        // FIXME\n        // 现在没有clip功能，暂时取ec高宽。\n        prunning(\n            treeRoot,\n            // Transform to base element coordinate system.\n            new BoundingRect(-layoutInfo.x, -layoutInfo.y, ecWidth, ecHeight),\n            viewAbovePath,\n            viewRoot,\n            0\n        );\n    }\n};\n\n/**\n * Layout treemap with squarify algorithm.\n * The original presentation of this algorithm\n * was made by Mark Bruls, Kees Huizing, and Jarke J. van Wijk\n * <https://graphics.ethz.ch/teaching/scivis_common/Literature/squarifiedTreeMaps.pdf>.\n * The implementation of this algorithm was originally copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/9cc9a875e636a1dcf36cc1e07bdf77e1ad6e2c74/src/layout/treemap.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n *\n * @protected\n * @param {module:echarts/data/Tree~TreeNode} node\n * @param {Object} options\n * @param {string} options.sort 'asc' or 'desc'\n * @param {number} options.squareRatio\n * @param {boolean} hideChildren\n * @param {number} depth\n */\nfunction squarify(node, options, hideChildren, depth) {\n    var width;\n    var height;\n\n    if (node.isRemoved()) {\n        return;\n    }\n\n    var thisLayout = node.getLayout();\n    width = thisLayout.width;\n    height = thisLayout.height;\n\n    // Considering border and gap\n    var nodeModel = node.getModel();\n    var borderWidth = nodeModel.get(PATH_BORDER_WIDTH);\n    var halfGapWidth = nodeModel.get(PATH_GAP_WIDTH) / 2;\n    var upperLabelHeight = getUpperLabelHeight(nodeModel);\n    var upperHeight = Math.max(borderWidth, upperLabelHeight);\n    var layoutOffset = borderWidth - halfGapWidth;\n    var layoutOffsetUpper = upperHeight - halfGapWidth;\n    var nodeModel = node.getModel();\n\n    node.setLayout({\n        borderWidth: borderWidth,\n        upperHeight: upperHeight,\n        upperLabelHeight: upperLabelHeight\n    }, true);\n\n    width = mathMax$4(width - 2 * layoutOffset, 0);\n    height = mathMax$4(height - layoutOffset - layoutOffsetUpper, 0);\n\n    var totalArea = width * height;\n    var viewChildren = initChildren(\n        node, nodeModel, totalArea, options, hideChildren, depth\n    );\n\n    if (!viewChildren.length) {\n        return;\n    }\n\n    var rect = {x: layoutOffset, y: layoutOffsetUpper, width: width, height: height};\n    var rowFixedLength = mathMin$4(width, height);\n    var best = Infinity; // the best row score so far\n    var row = [];\n    row.area = 0;\n\n    for (var i = 0, len = viewChildren.length; i < len;) {\n        var child = viewChildren[i];\n\n        row.push(child);\n        row.area += child.getLayout().area;\n        var score = worst(row, rowFixedLength, options.squareRatio);\n\n        // continue with this orientation\n        if (score <= best) {\n            i++;\n            best = score;\n        }\n        // abort, and try a different orientation\n        else {\n            row.area -= row.pop().getLayout().area;\n            position(row, rowFixedLength, rect, halfGapWidth, false);\n            rowFixedLength = mathMin$4(rect.width, rect.height);\n            row.length = row.area = 0;\n            best = Infinity;\n        }\n    }\n\n    if (row.length) {\n        position(row, rowFixedLength, rect, halfGapWidth, true);\n    }\n\n    if (!hideChildren) {\n        var childrenVisibleMin = nodeModel.get('childrenVisibleMin');\n        if (childrenVisibleMin != null && totalArea < childrenVisibleMin) {\n            hideChildren = true;\n        }\n    }\n\n    for (var i = 0, len = viewChildren.length; i < len; i++) {\n        squarify(viewChildren[i], options, hideChildren, depth + 1);\n    }\n}\n\n/**\n * Set area to each child, and calculate data extent for visual coding.\n */\nfunction initChildren(node, nodeModel, totalArea, options, hideChildren, depth) {\n    var viewChildren = node.children || [];\n    var orderBy = options.sort;\n    orderBy !== 'asc' && orderBy !== 'desc' && (orderBy = null);\n\n    var overLeafDepth = options.leafDepth != null && options.leafDepth <= depth;\n\n    // leafDepth has higher priority.\n    if (hideChildren && !overLeafDepth) {\n        return (node.viewChildren = []);\n    }\n\n    // Sort children, order by desc.\n    viewChildren = filter(viewChildren, function (child) {\n        return !child.isRemoved();\n    });\n\n    sort$1(viewChildren, orderBy);\n\n    var info = statistic(nodeModel, viewChildren, orderBy);\n\n    if (info.sum === 0) {\n        return (node.viewChildren = []);\n    }\n\n    info.sum = filterByThreshold(nodeModel, totalArea, info.sum, orderBy, viewChildren);\n\n    if (info.sum === 0) {\n        return (node.viewChildren = []);\n    }\n\n    // Set area to each child.\n    for (var i = 0, len = viewChildren.length; i < len; i++) {\n        var area = viewChildren[i].getValue() / info.sum * totalArea;\n        // Do not use setLayout({...}, true), because it is needed to clear last layout.\n        viewChildren[i].setLayout({area: area});\n    }\n\n    if (overLeafDepth) {\n        viewChildren.length && node.setLayout({isLeafRoot: true}, true);\n        viewChildren.length = 0;\n    }\n\n    node.viewChildren = viewChildren;\n    node.setLayout({dataExtent: info.dataExtent}, true);\n\n    return viewChildren;\n}\n\n/**\n * Consider 'visibleMin'. Modify viewChildren and get new sum.\n */\nfunction filterByThreshold(nodeModel, totalArea, sum, orderBy, orderedChildren) {\n\n    // visibleMin is not supported yet when no option.sort.\n    if (!orderBy) {\n        return sum;\n    }\n\n    var visibleMin = nodeModel.get('visibleMin');\n    var len = orderedChildren.length;\n    var deletePoint = len;\n\n    // Always travel from little value to big value.\n    for (var i = len - 1; i >= 0; i--) {\n        var value = orderedChildren[\n            orderBy === 'asc' ? len - i - 1 : i\n        ].getValue();\n\n        if (value / sum * totalArea < visibleMin) {\n            deletePoint = i;\n            sum -= value;\n        }\n    }\n\n    orderBy === 'asc'\n        ? orderedChildren.splice(0, len - deletePoint)\n        : orderedChildren.splice(deletePoint, len - deletePoint);\n\n    return sum;\n}\n\n/**\n * Sort\n */\nfunction sort$1(viewChildren, orderBy) {\n    if (orderBy) {\n        viewChildren.sort(function (a, b) {\n            var diff = orderBy === 'asc'\n                ? a.getValue() - b.getValue() : b.getValue() - a.getValue();\n            return diff === 0\n                ? (orderBy === 'asc'\n                    ? a.dataIndex - b.dataIndex : b.dataIndex - a.dataIndex\n                )\n                : diff;\n        });\n    }\n    return viewChildren;\n}\n\n/**\n * Statistic\n */\nfunction statistic(nodeModel, children, orderBy) {\n    // Calculate sum.\n    var sum = 0;\n    for (var i = 0, len = children.length; i < len; i++) {\n        sum += children[i].getValue();\n    }\n\n    // Statistic data extent for latter visual coding.\n    // Notice: data extent should be calculate based on raw children\n    // but not filtered view children, otherwise visual mapping will not\n    // be stable when zoom (where children is filtered by visibleMin).\n\n    var dimension = nodeModel.get('visualDimension');\n    var dataExtent;\n\n    // The same as area dimension.\n    if (!children || !children.length) {\n        dataExtent = [NaN, NaN];\n    }\n    else if (dimension === 'value' && orderBy) {\n        dataExtent = [\n            children[children.length - 1].getValue(),\n            children[0].getValue()\n        ];\n        orderBy === 'asc' && dataExtent.reverse();\n    }\n    // Other dimension.\n    else {\n        var dataExtent = [Infinity, -Infinity];\n        each$10(children, function (child) {\n            var value = child.getValue(dimension);\n            value < dataExtent[0] && (dataExtent[0] = value);\n            value > dataExtent[1] && (dataExtent[1] = value);\n        });\n    }\n\n    return {sum: sum, dataExtent: dataExtent};\n}\n\n/**\n * Computes the score for the specified row,\n * as the worst aspect ratio.\n */\nfunction worst(row, rowFixedLength, ratio) {\n    var areaMax = 0;\n    var areaMin = Infinity;\n\n    for (var i = 0, area, len = row.length; i < len; i++) {\n        area = row[i].getLayout().area;\n        if (area) {\n            area < areaMin && (areaMin = area);\n            area > areaMax && (areaMax = area);\n        }\n    }\n\n    var squareArea = row.area * row.area;\n    var f = rowFixedLength * rowFixedLength * ratio;\n\n    return squareArea\n        ? mathMax$4(\n            (f * areaMax) / squareArea,\n            squareArea / (f * areaMin)\n        )\n        : Infinity;\n}\n\n/**\n * Positions the specified row of nodes. Modifies `rect`.\n */\nfunction position(row, rowFixedLength, rect, halfGapWidth, flush) {\n    // When rowFixedLength === rect.width,\n    // it is horizontal subdivision,\n    // rowFixedLength is the width of the subdivision,\n    // rowOtherLength is the height of the subdivision,\n    // and nodes will be positioned from left to right.\n\n    // wh[idx0WhenH] means: when horizontal,\n    //      wh[idx0WhenH] => wh[0] => 'width'.\n    //      xy[idx1WhenH] => xy[1] => 'y'.\n    var idx0WhenH = rowFixedLength === rect.width ? 0 : 1;\n    var idx1WhenH = 1 - idx0WhenH;\n    var xy = ['x', 'y'];\n    var wh = ['width', 'height'];\n\n    var last = rect[xy[idx0WhenH]];\n    var rowOtherLength = rowFixedLength\n        ? row.area / rowFixedLength : 0;\n\n    if (flush || rowOtherLength > rect[wh[idx1WhenH]]) {\n        rowOtherLength = rect[wh[idx1WhenH]]; // over+underflow\n    }\n    for (var i = 0, rowLen = row.length; i < rowLen; i++) {\n        var node = row[i];\n        var nodeLayout = {};\n        var step = rowOtherLength\n            ? node.getLayout().area / rowOtherLength : 0;\n\n        var wh1 = nodeLayout[wh[idx1WhenH]] = mathMax$4(rowOtherLength - 2 * halfGapWidth, 0);\n\n        // We use Math.max/min to avoid negative width/height when considering gap width.\n        var remain = rect[xy[idx0WhenH]] + rect[wh[idx0WhenH]] - last;\n        var modWH = (i === rowLen - 1 || remain < step) ? remain : step;\n        var wh0 = nodeLayout[wh[idx0WhenH]] = mathMax$4(modWH - 2 * halfGapWidth, 0);\n\n        nodeLayout[xy[idx1WhenH]] = rect[xy[idx1WhenH]] + mathMin$4(halfGapWidth, wh1 / 2);\n        nodeLayout[xy[idx0WhenH]] = last + mathMin$4(halfGapWidth, wh0 / 2);\n\n        last += modWH;\n        node.setLayout(nodeLayout, true);\n    }\n\n    rect[xy[idx1WhenH]] += rowOtherLength;\n    rect[wh[idx1WhenH]] -= rowOtherLength;\n}\n\n// Return [containerWidth, containerHeight] as defualt.\nfunction estimateRootSize(seriesModel, targetInfo, viewRoot, containerWidth, containerHeight) {\n    // If targetInfo.node exists, we zoom to the node,\n    // so estimate whold width and heigth by target node.\n    var currNode = (targetInfo || {}).node;\n    var defaultSize = [containerWidth, containerHeight];\n\n    if (!currNode || currNode === viewRoot) {\n        return defaultSize;\n    }\n\n    var parent;\n    var viewArea = containerWidth * containerHeight;\n    var area = viewArea * seriesModel.option.zoomToNodeRatio;\n\n    while (parent = currNode.parentNode) { // jshint ignore:line\n        var sum = 0;\n        var siblings = parent.children;\n\n        for (var i = 0, len = siblings.length; i < len; i++) {\n            sum += siblings[i].getValue();\n        }\n        var currNodeValue = currNode.getValue();\n        if (currNodeValue === 0) {\n            return defaultSize;\n        }\n        area *= sum / currNodeValue;\n\n        // Considering border, suppose aspect ratio is 1.\n        var parentModel = parent.getModel();\n        var borderWidth = parentModel.get(PATH_BORDER_WIDTH);\n        var upperHeight = Math.max(borderWidth, getUpperLabelHeight(parentModel, borderWidth));\n        area += 4 * borderWidth * borderWidth\n            + (3 * borderWidth + upperHeight) * Math.pow(area, 0.5);\n\n        area > MAX_SAFE_INTEGER && (area = MAX_SAFE_INTEGER);\n\n        currNode = parent;\n    }\n\n    area < viewArea && (area = viewArea);\n    var scale = Math.pow(area / viewArea, 0.5);\n\n    return [containerWidth * scale, containerHeight * scale];\n}\n\n// Root postion base on coord of containerGroup\nfunction calculateRootPosition(layoutInfo, rootRect, targetInfo) {\n    if (rootRect) {\n        return {x: rootRect.x, y: rootRect.y};\n    }\n\n    var defaultPosition = {x: 0, y: 0};\n    if (!targetInfo) {\n        return defaultPosition;\n    }\n\n    // If targetInfo is fetched by 'retrieveTargetInfo',\n    // old tree and new tree are the same tree,\n    // so the node still exists and we can visit it.\n\n    var targetNode = targetInfo.node;\n    var layout = targetNode.getLayout();\n\n    if (!layout) {\n        return defaultPosition;\n    }\n\n    // Transform coord from local to container.\n    var targetCenter = [layout.width / 2, layout.height / 2];\n    var node = targetNode;\n    while (node) {\n        var nodeLayout = node.getLayout();\n        targetCenter[0] += nodeLayout.x;\n        targetCenter[1] += nodeLayout.y;\n        node = node.parentNode;\n    }\n\n    return {\n        x: layoutInfo.width / 2 - targetCenter[0],\n        y: layoutInfo.height / 2 - targetCenter[1]\n    };\n}\n\n// Mark nodes visible for prunning when visual coding and rendering.\n// Prunning depends on layout and root position, so we have to do it after layout.\nfunction prunning(node, clipRect, viewAbovePath, viewRoot, depth) {\n    var nodeLayout = node.getLayout();\n    var nodeInViewAbovePath = viewAbovePath[depth];\n    var isAboveViewRoot = nodeInViewAbovePath && nodeInViewAbovePath === node;\n\n    if (\n        (nodeInViewAbovePath && !isAboveViewRoot)\n        || (depth === viewAbovePath.length && node !== viewRoot)\n    ) {\n        return;\n    }\n\n    node.setLayout({\n        // isInView means: viewRoot sub tree + viewAbovePath\n        isInView: true,\n        // invisible only means: outside view clip so that the node can not\n        // see but still layout for animation preparation but not render.\n        invisible: !isAboveViewRoot && !clipRect.intersect(nodeLayout),\n        isAboveViewRoot: isAboveViewRoot\n    }, true);\n\n    // Transform to child coordinate.\n    var childClipRect = new BoundingRect(\n        clipRect.x - nodeLayout.x,\n        clipRect.y - nodeLayout.y,\n        clipRect.width,\n        clipRect.height\n    );\n\n    each$10(node.viewChildren || [], function (child) {\n        prunning(child, childClipRect, viewAbovePath, viewRoot, depth + 1);\n    });\n}\n\nfunction getUpperLabelHeight(model) {\n    return model.get(PATH_UPPER_LABEL_SHOW) ? model.get(PATH_UPPER_LABEL_HEIGHT) : 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(treemapVisual);\nregisterLayout(treemapLayout);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Graph data structure\n *\n * @module echarts/data/Graph\n * @author Yi Shen(https://www.github.com/pissang)\n */\n\n// id may be function name of Object, add a prefix to avoid this problem.\nfunction generateNodeKey(id) {\n    return '_EC_' + id;\n}\n/**\n * @alias module:echarts/data/Graph\n * @constructor\n * @param {boolean} directed\n */\nvar Graph = function (directed) {\n    /**\n     * 是否是有向图\n     * @type {boolean}\n     * @private\n     */\n    this._directed = directed || false;\n\n    /**\n     * @type {Array.<module:echarts/data/Graph.Node>}\n     * @readOnly\n     */\n    this.nodes = [];\n\n    /**\n     * @type {Array.<module:echarts/data/Graph.Edge>}\n     * @readOnly\n     */\n    this.edges = [];\n\n    /**\n     * @type {Object.<string, module:echarts/data/Graph.Node>}\n     * @private\n     */\n    this._nodesMap = {};\n    /**\n     * @type {Object.<string, module:echarts/data/Graph.Edge>}\n     * @private\n     */\n    this._edgesMap = {};\n\n    /**\n     * @type {module:echarts/data/List}\n     * @readOnly\n     */\n    this.data;\n\n    /**\n     * @type {module:echarts/data/List}\n     * @readOnly\n     */\n    this.edgeData;\n};\n\nvar graphProto = Graph.prototype;\n/**\n * @type {string}\n */\ngraphProto.type = 'graph';\n\n/**\n * If is directed graph\n * @return {boolean}\n */\ngraphProto.isDirected = function () {\n    return this._directed;\n};\n\n/**\n * Add a new node\n * @param {string} id\n * @param {number} [dataIndex]\n */\ngraphProto.addNode = function (id, dataIndex) {\n    id = id || ('' + dataIndex);\n\n    var nodesMap = this._nodesMap;\n\n    if (nodesMap[generateNodeKey(id)]) {\n        if (__DEV__) {\n            console.error('Graph nodes have duplicate name or id');\n        }\n        return;\n    }\n\n    var node = new Node(id, dataIndex);\n    node.hostGraph = this;\n\n    this.nodes.push(node);\n\n    nodesMap[generateNodeKey(id)] = node;\n    return node;\n};\n\n/**\n * Get node by data index\n * @param  {number} dataIndex\n * @return {module:echarts/data/Graph~Node}\n */\ngraphProto.getNodeByIndex = function (dataIndex) {\n    var rawIdx = this.data.getRawIndex(dataIndex);\n    return this.nodes[rawIdx];\n};\n/**\n * Get node by id\n * @param  {string} id\n * @return {module:echarts/data/Graph.Node}\n */\ngraphProto.getNodeById = function (id) {\n    return this._nodesMap[generateNodeKey(id)];\n};\n\n/**\n * Add a new edge\n * @param {number|string|module:echarts/data/Graph.Node} n1\n * @param {number|string|module:echarts/data/Graph.Node} n2\n * @param {number} [dataIndex=-1]\n * @return {module:echarts/data/Graph.Edge}\n */\ngraphProto.addEdge = function (n1, n2, dataIndex) {\n    var nodesMap = this._nodesMap;\n    var edgesMap = this._edgesMap;\n\n    // PNEDING\n    if (typeof n1 === 'number') {\n        n1 = this.nodes[n1];\n    }\n    if (typeof n2 === 'number') {\n        n2 = this.nodes[n2];\n    }\n\n    if (!Node.isInstance(n1)) {\n        n1 = nodesMap[generateNodeKey(n1)];\n    }\n    if (!Node.isInstance(n2)) {\n        n2 = nodesMap[generateNodeKey(n2)];\n    }\n    if (!n1 || !n2) {\n        return;\n    }\n\n    var key = n1.id + '-' + n2.id;\n    // PENDING\n    if (edgesMap[key]) {\n        return;\n    }\n\n    var edge = new Edge(n1, n2, dataIndex);\n    edge.hostGraph = this;\n\n    if (this._directed) {\n        n1.outEdges.push(edge);\n        n2.inEdges.push(edge);\n    }\n    n1.edges.push(edge);\n    if (n1 !== n2) {\n        n2.edges.push(edge);\n    }\n\n    this.edges.push(edge);\n    edgesMap[key] = edge;\n\n    return edge;\n};\n\n/**\n * Get edge by data index\n * @param  {number} dataIndex\n * @return {module:echarts/data/Graph~Node}\n */\ngraphProto.getEdgeByIndex = function (dataIndex) {\n    var rawIdx = this.edgeData.getRawIndex(dataIndex);\n    return this.edges[rawIdx];\n};\n/**\n * Get edge by two linked nodes\n * @param  {module:echarts/data/Graph.Node|string} n1\n * @param  {module:echarts/data/Graph.Node|string} n2\n * @return {module:echarts/data/Graph.Edge}\n */\ngraphProto.getEdge = function (n1, n2) {\n    if (Node.isInstance(n1)) {\n        n1 = n1.id;\n    }\n    if (Node.isInstance(n2)) {\n        n2 = n2.id;\n    }\n\n    var edgesMap = this._edgesMap;\n\n    if (this._directed) {\n        return edgesMap[n1 + '-' + n2];\n    }\n    else {\n        return edgesMap[n1 + '-' + n2]\n            || edgesMap[n2 + '-' + n1];\n    }\n};\n\n/**\n * Iterate all nodes\n * @param  {Function} cb\n * @param  {*} [context]\n */\ngraphProto.eachNode = function (cb, context) {\n    var nodes = this.nodes;\n    var len = nodes.length;\n    for (var i = 0; i < len; i++) {\n        if (nodes[i].dataIndex >= 0) {\n            cb.call(context, nodes[i], i);\n        }\n    }\n};\n\n/**\n * Iterate all edges\n * @param  {Function} cb\n * @param  {*} [context]\n */\ngraphProto.eachEdge = function (cb, context) {\n    var edges = this.edges;\n    var len = edges.length;\n    for (var i = 0; i < len; i++) {\n        if (edges[i].dataIndex >= 0\n            && edges[i].node1.dataIndex >= 0\n            && edges[i].node2.dataIndex >= 0\n        ) {\n            cb.call(context, edges[i], i);\n        }\n    }\n};\n\n/**\n * Breadth first traverse\n * @param {Function} cb\n * @param {module:echarts/data/Graph.Node} startNode\n * @param {string} [direction='none'] 'none'|'in'|'out'\n * @param {*} [context]\n */\ngraphProto.breadthFirstTraverse = function (\n    cb, startNode, direction, context\n) {\n    if (!Node.isInstance(startNode)) {\n        startNode = this._nodesMap[generateNodeKey(startNode)];\n    }\n    if (!startNode) {\n        return;\n    }\n\n    var edgeType = direction === 'out'\n        ? 'outEdges' : (direction === 'in' ? 'inEdges' : 'edges');\n\n    for (var i = 0; i < this.nodes.length; i++) {\n        this.nodes[i].__visited = false;\n    }\n\n    if (cb.call(context, startNode, null)) {\n        return;\n    }\n\n    var queue = [startNode];\n    while (queue.length) {\n        var currentNode = queue.shift();\n        var edges = currentNode[edgeType];\n\n        for (var i = 0; i < edges.length; i++) {\n            var e = edges[i];\n            var otherNode = e.node1 === currentNode\n                ? e.node2 : e.node1;\n            if (!otherNode.__visited) {\n                if (cb.call(context, otherNode, currentNode)) {\n                    // Stop traversing\n                    return;\n                }\n                queue.push(otherNode);\n                otherNode.__visited = true;\n            }\n        }\n    }\n};\n\n// TODO\n// graphProto.depthFirstTraverse = function (\n//     cb, startNode, direction, context\n// ) {\n\n// };\n\n// Filter update\ngraphProto.update = function () {\n    var data = this.data;\n    var edgeData = this.edgeData;\n    var nodes = this.nodes;\n    var edges = this.edges;\n\n    for (var i = 0, len = nodes.length; i < len; i++) {\n        nodes[i].dataIndex = -1;\n    }\n    for (var i = 0, len = data.count(); i < len; i++) {\n        nodes[data.getRawIndex(i)].dataIndex = i;\n    }\n\n    edgeData.filterSelf(function (idx) {\n        var edge = edges[edgeData.getRawIndex(idx)];\n        return edge.node1.dataIndex >= 0 && edge.node2.dataIndex >= 0;\n    });\n\n    // Update edge\n    for (var i = 0, len = edges.length; i < len; i++) {\n        edges[i].dataIndex = -1;\n    }\n    for (var i = 0, len = edgeData.count(); i < len; i++) {\n        edges[edgeData.getRawIndex(i)].dataIndex = i;\n    }\n};\n\n/**\n * @return {module:echarts/data/Graph}\n */\ngraphProto.clone = function () {\n    var graph = new Graph(this._directed);\n    var nodes = this.nodes;\n    var edges = this.edges;\n    for (var i = 0; i < nodes.length; i++) {\n        graph.addNode(nodes[i].id, nodes[i].dataIndex);\n    }\n    for (var i = 0; i < edges.length; i++) {\n        var e = edges[i];\n        graph.addEdge(e.node1.id, e.node2.id, e.dataIndex);\n    }\n    return graph;\n};\n\n\n/**\n * @alias module:echarts/data/Graph.Node\n */\nfunction Node(id, dataIndex) {\n    /**\n    * @type {string}\n    */\n    this.id = id == null ? '' : id;\n\n    /**\n    * @type {Array.<module:echarts/data/Graph.Edge>}\n    */\n    this.inEdges = [];\n    /**\n    * @type {Array.<module:echarts/data/Graph.Edge>}\n    */\n    this.outEdges = [];\n    /**\n    * @type {Array.<module:echarts/data/Graph.Edge>}\n    */\n    this.edges = [];\n    /**\n     * @type {module:echarts/data/Graph}\n     */\n    this.hostGraph;\n\n    /**\n     * @type {number}\n     */\n    this.dataIndex = dataIndex == null ? -1 : dataIndex;\n}\n\nNode.prototype = {\n\n    constructor: Node,\n\n    /**\n     * @return {number}\n     */\n    degree: function () {\n        return this.edges.length;\n    },\n\n    /**\n     * @return {number}\n     */\n    inDegree: function () {\n        return this.inEdges.length;\n    },\n\n    /**\n    * @return {number}\n    */\n    outDegree: function () {\n        return this.outEdges.length;\n    },\n\n    /**\n     * @param {string} [path]\n     * @return {module:echarts/model/Model}\n     */\n    getModel: function (path) {\n        if (this.dataIndex < 0) {\n            return;\n        }\n        var graph = this.hostGraph;\n        var itemModel = graph.data.getItemModel(this.dataIndex);\n\n        return itemModel.getModel(path);\n    }\n};\n\n/**\n * 图边\n * @alias module:echarts/data/Graph.Edge\n * @param {module:echarts/data/Graph.Node} n1\n * @param {module:echarts/data/Graph.Node} n2\n * @param {number} [dataIndex=-1]\n */\nfunction Edge(n1, n2, dataIndex) {\n\n    /**\n     * 节点1，如果是有向图则为源节点\n     * @type {module:echarts/data/Graph.Node}\n     */\n    this.node1 = n1;\n\n    /**\n     * 节点2，如果是有向图则为目标节点\n     * @type {module:echarts/data/Graph.Node}\n     */\n    this.node2 = n2;\n\n    this.dataIndex = dataIndex == null ? -1 : dataIndex;\n}\n\n/**\n * @param {string} [path]\n * @return {module:echarts/model/Model}\n */\nEdge.prototype.getModel = function (path) {\n    if (this.dataIndex < 0) {\n        return;\n    }\n    var graph = this.hostGraph;\n    var itemModel = graph.edgeData.getItemModel(this.dataIndex);\n\n    return itemModel.getModel(path);\n};\n\nvar createGraphDataProxyMixin = function (hostName, dataName) {\n    return {\n        /**\n         * @param {string=} [dimension='value'] Default 'value'. can be 'a', 'b', 'c', 'd', 'e'.\n         * @return {number}\n         */\n        getValue: function (dimension) {\n            var data = this[hostName][dataName];\n            return data.get(data.getDimension(dimension || 'value'), this.dataIndex);\n        },\n\n        /**\n         * @param {Object|string} key\n         * @param {*} [value]\n         */\n        setVisual: function (key, value) {\n            this.dataIndex >= 0\n                && this[hostName][dataName].setItemVisual(this.dataIndex, key, value);\n        },\n\n        /**\n         * @param {string} key\n         * @return {boolean}\n         */\n        getVisual: function (key, ignoreParent) {\n            return this[hostName][dataName].getItemVisual(this.dataIndex, key, ignoreParent);\n        },\n\n        /**\n         * @param {Object} layout\n         * @return {boolean} [merge=false]\n         */\n        setLayout: function (layout, merge$$1) {\n            this.dataIndex >= 0\n                && this[hostName][dataName].setItemLayout(this.dataIndex, layout, merge$$1);\n        },\n\n        /**\n         * @return {Object}\n         */\n        getLayout: function () {\n            return this[hostName][dataName].getItemLayout(this.dataIndex);\n        },\n\n        /**\n         * @return {module:zrender/Element}\n         */\n        getGraphicEl: function () {\n            return this[hostName][dataName].getItemGraphicEl(this.dataIndex);\n        },\n\n        /**\n         * @return {number}\n         */\n        getRawIndex: function () {\n            return this[hostName][dataName].getRawIndex(this.dataIndex);\n        }\n    };\n};\n\nmixin(Node, createGraphDataProxyMixin('hostGraph', 'data'));\nmixin(Edge, createGraphDataProxyMixin('hostGraph', 'edgeData'));\n\nGraph.Node = Node;\nGraph.Edge = Edge;\n\nenableClassCheck(Node);\nenableClassCheck(Edge);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar createGraphFromNodeEdge = function (nodes, edges, seriesModel, directed, beforeLink) {\n    // ??? TODO\n    // support dataset?\n    var graph = new Graph(directed);\n    for (var i = 0; i < nodes.length; i++) {\n        graph.addNode(retrieve(\n            // Id, name, dataIndex\n            nodes[i].id, nodes[i].name, i\n        ), i);\n    }\n\n    var linkNameList = [];\n    var validEdges = [];\n    var linkCount = 0;\n    for (var i = 0; i < edges.length; i++) {\n        var link = edges[i];\n        var source = link.source;\n        var target = link.target;\n        // addEdge may fail when source or target not exists\n        if (graph.addEdge(source, target, linkCount)) {\n            validEdges.push(link);\n            linkNameList.push(retrieve(link.id, source + ' > ' + target));\n            linkCount++;\n        }\n    }\n\n    var coordSys = seriesModel.get('coordinateSystem');\n    var nodeData;\n    if (coordSys === 'cartesian2d' || coordSys === 'polar') {\n        nodeData = createListFromArray(nodes, seriesModel);\n    }\n    else {\n        var coordSysCtor = CoordinateSystemManager.get(coordSys);\n        var coordDimensions = (coordSysCtor && coordSysCtor.type !== 'view')\n            ? (coordSysCtor.dimensions || []) : [];\n        // FIXME: Some geo do not need `value` dimenson, whereas `calendar` needs\n        // `value` dimension, but graph need `value` dimension. It's better to\n        // uniform this behavior.\n        if (indexOf(coordDimensions, 'value') < 0) {\n            coordDimensions.concat(['value']);\n        }\n\n        var dimensionNames = createDimensions(nodes, {\n            coordDimensions: coordDimensions\n        });\n        nodeData = new List(dimensionNames, seriesModel);\n        nodeData.initData(nodes);\n    }\n\n    var edgeData = new List(['value'], seriesModel);\n    edgeData.initData(validEdges, linkNameList);\n\n    beforeLink && beforeLink(nodeData, edgeData);\n\n    linkList({\n        mainData: nodeData,\n        struct: graph,\n        structAttr: 'graph',\n        datas: {node: nodeData, edge: edgeData},\n        datasAttr: {node: 'data', edge: 'edgeData'}\n    });\n\n    // Update dataIndex of nodes and edges because invalid edge may be removed\n    graph.update();\n\n    return graph;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar GraphSeries = extendSeriesModel({\n\n    type: 'series.graph',\n\n    init: function (option) {\n        GraphSeries.superApply(this, 'init', arguments);\n\n        // Provide data for legend select\n        this.legendDataProvider = function () {\n            return this._categoriesData;\n        };\n\n        this.fillDataTextStyle(option.edges || option.links);\n\n        this._updateCategoriesData();\n    },\n\n    mergeOption: function (option) {\n        GraphSeries.superApply(this, 'mergeOption', arguments);\n\n        this.fillDataTextStyle(option.edges || option.links);\n\n        this._updateCategoriesData();\n    },\n\n    mergeDefaultAndTheme: function (option) {\n        GraphSeries.superApply(this, 'mergeDefaultAndTheme', arguments);\n        defaultEmphasis(option, ['edgeLabel'], ['show']);\n    },\n\n    getInitialData: function (option, ecModel) {\n        var edges = option.edges || option.links || [];\n        var nodes = option.data || option.nodes || [];\n        var self = this;\n\n        if (nodes && edges) {\n            return createGraphFromNodeEdge(nodes, edges, this, true, beforeLink).data;\n        }\n\n        function beforeLink(nodeData, edgeData) {\n            // Overwrite nodeData.getItemModel to\n            nodeData.wrapMethod('getItemModel', function (model) {\n                var categoriesModels = self._categoriesModels;\n                var categoryIdx = model.getShallow('category');\n                var categoryModel = categoriesModels[categoryIdx];\n                if (categoryModel) {\n                    categoryModel.parentModel = model.parentModel;\n                    model.parentModel = categoryModel;\n                }\n                return model;\n            });\n\n            var edgeLabelModel = self.getModel('edgeLabel');\n            // For option `edgeLabel` can be found by label.xxx.xxx on item mode.\n            var fakeSeriesModel = new Model(\n                {label: edgeLabelModel.option},\n                edgeLabelModel.parentModel,\n                ecModel\n            );\n            var emphasisEdgeLabelModel = self.getModel('emphasis.edgeLabel');\n            var emphasisFakeSeriesModel = new Model(\n                {emphasis: {label: emphasisEdgeLabelModel.option}},\n                emphasisEdgeLabelModel.parentModel,\n                ecModel\n            );\n\n            edgeData.wrapMethod('getItemModel', function (model) {\n                model.customizeGetParent(edgeGetParent);\n                return model;\n            });\n\n            function edgeGetParent(path) {\n                path = this.parsePath(path);\n                return (path && path[0] === 'label')\n                    ? fakeSeriesModel\n                    : (path && path[0] === 'emphasis' && path[1] === 'label')\n                    ? emphasisFakeSeriesModel\n                    : this.parentModel;\n            }\n        }\n    },\n\n    /**\n     * @return {module:echarts/data/Graph}\n     */\n    getGraph: function () {\n        return this.getData().graph;\n    },\n\n    /**\n     * @return {module:echarts/data/List}\n     */\n    getEdgeData: function () {\n        return this.getGraph().edgeData;\n    },\n\n    /**\n     * @return {module:echarts/data/List}\n     */\n    getCategoriesData: function () {\n        return this._categoriesData;\n    },\n\n    /**\n     * @override\n     */\n    formatTooltip: function (dataIndex, multipleSeries, dataType) {\n        if (dataType === 'edge') {\n            var nodeData = this.getData();\n            var params = this.getDataParams(dataIndex, dataType);\n            var edge = nodeData.graph.getEdgeByIndex(dataIndex);\n            var sourceName = nodeData.getName(edge.node1.dataIndex);\n            var targetName = nodeData.getName(edge.node2.dataIndex);\n\n            var html = [];\n            sourceName != null && html.push(sourceName);\n            targetName != null && html.push(targetName);\n            html = encodeHTML(html.join(' > '));\n\n            if (params.value) {\n                html += ' : ' + encodeHTML(params.value);\n            }\n            return html;\n        }\n        else { // dataType === 'node' or empty\n            return GraphSeries.superApply(this, 'formatTooltip', arguments);\n        }\n    },\n\n    _updateCategoriesData: function () {\n        var categories = map(this.option.categories || [], function (category) {\n            // Data must has value\n            return category.value != null ? category : extend({\n                value: 0\n            }, category);\n        });\n        var categoriesData = new List(['value'], this);\n        categoriesData.initData(categories);\n\n        this._categoriesData = categoriesData;\n\n        this._categoriesModels = categoriesData.mapArray(function (idx) {\n            return categoriesData.getItemModel(idx, true);\n        });\n    },\n\n    setZoom: function (zoom) {\n        this.option.zoom = zoom;\n    },\n\n    setCenter: function (center) {\n        this.option.center = center;\n    },\n\n    isAnimationEnabled: function () {\n        return GraphSeries.superCall(this, 'isAnimationEnabled')\n            // Not enable animation when do force layout\n            && !(this.get('layout') === 'force' && this.get('force.layoutAnimation'));\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n\n        coordinateSystem: 'view',\n\n        // Default option for all coordinate systems\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n        // polarIndex: 0,\n        // geoIndex: 0,\n\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n\n        layout: null,\n\n        focusNodeAdjacency: false,\n\n        // Configuration of circular layout\n        circular: {\n            rotateLabel: false\n        },\n        // Configuration of force directed layout\n        force: {\n            initLayout: null,\n            // Node repulsion. Can be an array to represent range.\n            repulsion: [0, 50],\n            gravity: 0.1,\n\n            // Edge length. Can be an array to represent range.\n            edgeLength: 30,\n\n            layoutAnimation: true\n        },\n\n        left: 'center',\n        top: 'center',\n        // right: null,\n        // bottom: null,\n        // width: '80%',\n        // height: '80%',\n\n        symbol: 'circle',\n        symbolSize: 10,\n\n        edgeSymbol: ['none', 'none'],\n        edgeSymbolSize: 10,\n        edgeLabel: {\n            position: 'middle'\n        },\n\n        draggable: false,\n\n        roam: false,\n\n        // Default on center of graph\n        center: null,\n\n        zoom: 1,\n        // Symbol size scale ratio in roam\n        nodeScaleRatio: 0.6,\n        // cursor: null,\n\n        // categories: [],\n\n        // data: []\n        // Or\n        // nodes: []\n        //\n        // links: []\n        // Or\n        // edges: []\n\n        label: {\n            show: false,\n            formatter: '{b}'\n        },\n\n        itemStyle: {},\n\n        lineStyle: {\n            color: '#aaa',\n            width: 1,\n            curveness: 0,\n            opacity: 0.5\n        },\n        emphasis: {\n            label: {\n                show: true\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Line path for bezier and straight line draw\n */\n\nvar straightLineProto = Line.prototype;\nvar bezierCurveProto = BezierCurve.prototype;\n\nfunction isLine(shape) {\n    return isNaN(+shape.cpx1) || isNaN(+shape.cpy1);\n}\n\nvar LinePath = extendShape({\n\n    type: 'ec-line',\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    shape: {\n        x1: 0,\n        y1: 0,\n        x2: 0,\n        y2: 0,\n        percent: 1,\n        cpx1: null,\n        cpy1: null\n    },\n\n    buildPath: function (ctx, shape) {\n        (isLine(shape) ? straightLineProto : bezierCurveProto).buildPath(ctx, shape);\n    },\n\n    pointAt: function (t) {\n        return isLine(this.shape)\n            ? straightLineProto.pointAt.call(this, t)\n            : bezierCurveProto.pointAt.call(this, t);\n    },\n\n    tangentAt: function (t) {\n        var shape = this.shape;\n        var p = isLine(shape)\n            ? [shape.x2 - shape.x1, shape.y2 - shape.y1]\n            : bezierCurveProto.tangentAt.call(this, t);\n        return normalize(p, p);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Line\n */\n\nvar SYMBOL_CATEGORIES = ['fromSymbol', 'toSymbol'];\n\nfunction makeSymbolTypeKey(symbolCategory) {\n    return '_' + symbolCategory + 'Type';\n}\n/**\n * @inner\n */\nfunction createSymbol$1(name, lineData, idx) {\n    var color = lineData.getItemVisual(idx, 'color');\n    var symbolType = lineData.getItemVisual(idx, name);\n    var symbolSize = lineData.getItemVisual(idx, name + 'Size');\n\n    if (!symbolType || symbolType === 'none') {\n        return;\n    }\n\n    if (!isArray(symbolSize)) {\n        symbolSize = [symbolSize, symbolSize];\n    }\n    var symbolPath = createSymbol(\n        symbolType, -symbolSize[0] / 2, -symbolSize[1] / 2,\n        symbolSize[0], symbolSize[1], color\n    );\n\n    symbolPath.name = name;\n\n    return symbolPath;\n}\n\nfunction createLine(points) {\n    var line = new LinePath({\n        name: 'line'\n    });\n    setLinePoints(line.shape, points);\n    return line;\n}\n\nfunction setLinePoints(targetShape, points) {\n    var p1 = points[0];\n    var p2 = points[1];\n    var cp1 = points[2];\n    targetShape.x1 = p1[0];\n    targetShape.y1 = p1[1];\n    targetShape.x2 = p2[0];\n    targetShape.y2 = p2[1];\n    targetShape.percent = 1;\n\n    if (cp1) {\n        targetShape.cpx1 = cp1[0];\n        targetShape.cpy1 = cp1[1];\n    }\n    else {\n        targetShape.cpx1 = NaN;\n        targetShape.cpy1 = NaN;\n    }\n}\n\nfunction updateSymbolAndLabelBeforeLineUpdate() {\n    var lineGroup = this;\n    var symbolFrom = lineGroup.childOfName('fromSymbol');\n    var symbolTo = lineGroup.childOfName('toSymbol');\n    var label = lineGroup.childOfName('label');\n    // Quick reject\n    if (!symbolFrom && !symbolTo && label.ignore) {\n        return;\n    }\n\n    var invScale = 1;\n    var parentNode = this.parent;\n    while (parentNode) {\n        if (parentNode.scale) {\n            invScale /= parentNode.scale[0];\n        }\n        parentNode = parentNode.parent;\n    }\n\n    var line = lineGroup.childOfName('line');\n    // If line not changed\n    // FIXME Parent scale changed\n    if (!this.__dirty && !line.__dirty) {\n        return;\n    }\n\n    var percent = line.shape.percent;\n    var fromPos = line.pointAt(0);\n    var toPos = line.pointAt(percent);\n\n    var d = sub([], toPos, fromPos);\n    normalize(d, d);\n\n    if (symbolFrom) {\n        symbolFrom.attr('position', fromPos);\n        var tangent = line.tangentAt(0);\n        symbolFrom.attr('rotation', Math.PI / 2 - Math.atan2(\n            tangent[1], tangent[0]\n        ));\n        symbolFrom.attr('scale', [invScale * percent, invScale * percent]);\n    }\n    if (symbolTo) {\n        symbolTo.attr('position', toPos);\n        var tangent = line.tangentAt(1);\n        symbolTo.attr('rotation', -Math.PI / 2 - Math.atan2(\n            tangent[1], tangent[0]\n        ));\n        symbolTo.attr('scale', [invScale * percent, invScale * percent]);\n    }\n\n    if (!label.ignore) {\n        label.attr('position', toPos);\n\n        var textPosition;\n        var textAlign;\n        var textVerticalAlign;\n\n        var distance$$1 = 5 * invScale;\n        // End\n        if (label.__position === 'end') {\n            textPosition = [d[0] * distance$$1 + toPos[0], d[1] * distance$$1 + toPos[1]];\n            textAlign = d[0] > 0.8 ? 'left' : (d[0] < -0.8 ? 'right' : 'center');\n            textVerticalAlign = d[1] > 0.8 ? 'top' : (d[1] < -0.8 ? 'bottom' : 'middle');\n        }\n        // Middle\n        else if (label.__position === 'middle') {\n            var halfPercent = percent / 2;\n            var tangent = line.tangentAt(halfPercent);\n            var n = [tangent[1], -tangent[0]];\n            var cp = line.pointAt(halfPercent);\n            if (n[1] > 0) {\n                n[0] = -n[0];\n                n[1] = -n[1];\n            }\n            textPosition = [cp[0] + n[0] * distance$$1, cp[1] + n[1] * distance$$1];\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            var rotation = -Math.atan2(tangent[1], tangent[0]);\n            if (toPos[0] < fromPos[0]) {\n                rotation = Math.PI + rotation;\n            }\n            label.attr('rotation', rotation);\n        }\n        // Start\n        else {\n            textPosition = [-d[0] * distance$$1 + fromPos[0], -d[1] * distance$$1 + fromPos[1]];\n            textAlign = d[0] > 0.8 ? 'right' : (d[0] < -0.8 ? 'left' : 'center');\n            textVerticalAlign = d[1] > 0.8 ? 'bottom' : (d[1] < -0.8 ? 'top' : 'middle');\n        }\n        label.attr({\n            style: {\n                // Use the user specified text align and baseline first\n                textVerticalAlign: label.__verticalAlign || textVerticalAlign,\n                textAlign: label.__textAlign || textAlign\n            },\n            position: textPosition,\n            scale: [invScale, invScale]\n        });\n    }\n}\n\n/**\n * @constructor\n * @extends {module:zrender/graphic/Group}\n * @alias {module:echarts/chart/helper/Line}\n */\nfunction Line$1(lineData, idx, seriesScope) {\n    Group.call(this);\n\n    this._createLine(lineData, idx, seriesScope);\n}\n\nvar lineProto = Line$1.prototype;\n\n// Update symbol position and rotation\nlineProto.beforeUpdate = updateSymbolAndLabelBeforeLineUpdate;\n\nlineProto._createLine = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n    var linePoints = lineData.getItemLayout(idx);\n\n    var line = createLine(linePoints);\n    line.shape.percent = 0;\n    initProps(line, {\n        shape: {\n            percent: 1\n        }\n    }, seriesModel, idx);\n\n    this.add(line);\n\n    var label = new Text({\n        name: 'label',\n        // FIXME\n        // Temporary solution for `focusNodeAdjacency`.\n        // line label do not use the opacity of lineStyle.\n        lineLabelOriginalOpacity: 1\n    });\n    this.add(label);\n\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbol = createSymbol$1(symbolCategory, lineData, idx);\n        // symbols must added after line to make sure\n        // it will be updated after line#update.\n        // Or symbol position and rotation update in line#beforeUpdate will be one frame slow\n        this.add(symbol);\n        this[makeSymbolTypeKey(symbolCategory)] = lineData.getItemVisual(idx, symbolCategory);\n    }, this);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\nlineProto.updateData = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n\n    var line = this.childOfName('line');\n    var linePoints = lineData.getItemLayout(idx);\n    var target = {\n        shape: {}\n    };\n    setLinePoints(target.shape, linePoints);\n    updateProps(line, target, seriesModel, idx);\n\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbolType = lineData.getItemVisual(idx, symbolCategory);\n        var key = makeSymbolTypeKey(symbolCategory);\n        // Symbol changed\n        if (this[key] !== symbolType) {\n            this.remove(this.childOfName(symbolCategory));\n            var symbol = createSymbol$1(symbolCategory, lineData, idx);\n            this.add(symbol);\n        }\n        this[key] = symbolType;\n    }, this);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\nlineProto._updateCommonStl = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n\n    var line = this.childOfName('line');\n\n    var lineStyle = seriesScope && seriesScope.lineStyle;\n    var hoverLineStyle = seriesScope && seriesScope.hoverLineStyle;\n    var labelModel = seriesScope && seriesScope.labelModel;\n    var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;\n\n    // Optimization for large dataset\n    if (!seriesScope || lineData.hasItemOption) {\n        var itemModel = lineData.getItemModel(idx);\n\n        lineStyle = itemModel.getModel('lineStyle').getLineStyle();\n        hoverLineStyle = itemModel.getModel('emphasis.lineStyle').getLineStyle();\n\n        labelModel = itemModel.getModel('label');\n        hoverLabelModel = itemModel.getModel('emphasis.label');\n    }\n\n    var visualColor = lineData.getItemVisual(idx, 'color');\n    var visualOpacity = retrieve3(\n        lineData.getItemVisual(idx, 'opacity'),\n        lineStyle.opacity,\n        1\n    );\n\n    line.useStyle(defaults(\n        {\n            strokeNoScale: true,\n            fill: 'none',\n            stroke: visualColor,\n            opacity: visualOpacity\n        },\n        lineStyle\n    ));\n    line.hoverStyle = hoverLineStyle;\n\n    // Update symbol\n    each$1(SYMBOL_CATEGORIES, function (symbolCategory) {\n        var symbol = this.childOfName(symbolCategory);\n        if (symbol) {\n            symbol.setColor(visualColor);\n            symbol.setStyle({\n                opacity: visualOpacity\n            });\n        }\n    }, this);\n\n    var showLabel = labelModel.getShallow('show');\n    var hoverShowLabel = hoverLabelModel.getShallow('show');\n\n    var label = this.childOfName('label');\n    var defaultLabelColor;\n    var baseText;\n\n    // FIXME: the logic below probably should be merged to `graphic.setLabelStyle`.\n    if (showLabel || hoverShowLabel) {\n        defaultLabelColor = visualColor || '#000';\n\n        baseText = seriesModel.getFormattedLabel(idx, 'normal', lineData.dataType);\n        if (baseText == null) {\n            var rawVal = seriesModel.getRawValue(idx);\n            baseText = rawVal == null\n                ? lineData.getName(idx)\n                : isFinite(rawVal)\n                ? round$2(rawVal)\n                : rawVal;\n        }\n    }\n    var normalText = showLabel ? baseText : null;\n    var emphasisText = hoverShowLabel\n        ? retrieve2(\n            seriesModel.getFormattedLabel(idx, 'emphasis', lineData.dataType),\n            baseText\n        )\n        : null;\n\n    var labelStyle = label.style;\n\n    // Always set `textStyle` even if `normalStyle.text` is null, because default\n    // values have to be set on `normalStyle`.\n    if (normalText != null || emphasisText != null) {\n        setTextStyle(label.style, labelModel, {\n            text: normalText\n        }, {\n            autoColor: defaultLabelColor\n        });\n\n        label.__textAlign = labelStyle.textAlign;\n        label.__verticalAlign = labelStyle.textVerticalAlign;\n        // 'start', 'middle', 'end'\n        label.__position = labelModel.get('position') || 'middle';\n    }\n\n    if (emphasisText != null) {\n        // Only these properties supported in this emphasis style here.\n        label.hoverStyle = {\n            text: emphasisText,\n            textFill: hoverLabelModel.getTextColor(true),\n            // For merging hover style to normal style, do not use\n            // `hoverLabelModel.getFont()` here.\n            fontStyle: hoverLabelModel.getShallow('fontStyle'),\n            fontWeight: hoverLabelModel.getShallow('fontWeight'),\n            fontSize: hoverLabelModel.getShallow('fontSize'),\n            fontFamily: hoverLabelModel.getShallow('fontFamily')\n        };\n    }\n    else {\n        label.hoverStyle = {\n            text: null\n        };\n    }\n\n    label.ignore = !showLabel && !hoverShowLabel;\n\n    setHoverStyle(this);\n};\n\nlineProto.highlight = function () {\n    this.trigger('emphasis');\n};\n\nlineProto.downplay = function () {\n    this.trigger('normal');\n};\n\nlineProto.updateLayout = function (lineData, idx) {\n    this.setLinePoints(lineData.getItemLayout(idx));\n};\n\nlineProto.setLinePoints = function (points) {\n    var linePath = this.childOfName('line');\n    setLinePoints(linePath.shape, points);\n    linePath.dirty();\n};\n\ninherits(Line$1, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/LineDraw\n */\n\n// import IncrementalDisplayable from 'zrender/src/graphic/IncrementalDisplayable';\n\n/**\n * @alias module:echarts/component/marker/LineDraw\n * @constructor\n */\nfunction LineDraw(ctor) {\n    this._ctor = ctor || Line$1;\n\n    this.group = new Group();\n}\n\nvar lineDrawProto = LineDraw.prototype;\n\nlineDrawProto.isPersistent = function () {\n    return true;\n};\n\n/**\n * @param {module:echarts/data/List} lineData\n */\nlineDrawProto.updateData = function (lineData) {\n    var lineDraw = this;\n    var group = lineDraw.group;\n\n    var oldLineData = lineDraw._lineData;\n    lineDraw._lineData = lineData;\n\n    // There is no oldLineData only when first rendering or switching from\n    // stream mode to normal mode, where previous elements should be removed.\n    if (!oldLineData) {\n        group.removeAll();\n    }\n\n    var seriesScope = makeSeriesScope$1(lineData);\n\n    lineData.diff(oldLineData)\n        .add(function (idx) {\n            doAdd(lineDraw, lineData, idx, seriesScope);\n        })\n        .update(function (newIdx, oldIdx) {\n            doUpdate(lineDraw, oldLineData, lineData, oldIdx, newIdx, seriesScope);\n        })\n        .remove(function (idx) {\n            group.remove(oldLineData.getItemGraphicEl(idx));\n        })\n        .execute();\n};\n\nfunction doAdd(lineDraw, lineData, idx, seriesScope) {\n    var itemLayout = lineData.getItemLayout(idx);\n\n    if (!lineNeedsDraw(itemLayout)) {\n        return;\n    }\n\n    var el = new lineDraw._ctor(lineData, idx, seriesScope);\n    lineData.setItemGraphicEl(idx, el);\n    lineDraw.group.add(el);\n}\n\nfunction doUpdate(lineDraw, oldLineData, newLineData, oldIdx, newIdx, seriesScope) {\n    var itemEl = oldLineData.getItemGraphicEl(oldIdx);\n\n    if (!lineNeedsDraw(newLineData.getItemLayout(newIdx))) {\n        lineDraw.group.remove(itemEl);\n        return;\n    }\n\n    if (!itemEl) {\n        itemEl = new lineDraw._ctor(newLineData, newIdx, seriesScope);\n    }\n    else {\n        itemEl.updateData(newLineData, newIdx, seriesScope);\n    }\n\n    newLineData.setItemGraphicEl(newIdx, itemEl);\n\n    lineDraw.group.add(itemEl);\n}\n\nlineDrawProto.updateLayout = function () {\n    var lineData = this._lineData;\n\n    // Do not support update layout in incremental mode.\n    if (!lineData) {\n        return;\n    }\n\n    lineData.eachItemGraphicEl(function (el, idx) {\n        el.updateLayout(lineData, idx);\n    }, this);\n};\n\nlineDrawProto.incrementalPrepareUpdate = function (lineData) {\n    this._seriesScope = makeSeriesScope$1(lineData);\n    this._lineData = null;\n    this.group.removeAll();\n};\n\nlineDrawProto.incrementalUpdate = function (taskParams, lineData) {\n    function updateIncrementalAndHover(el) {\n        if (!el.isGroup) {\n            el.incremental = el.useHoverLayer = true;\n        }\n    }\n\n    for (var idx = taskParams.start; idx < taskParams.end; idx++) {\n        var itemLayout = lineData.getItemLayout(idx);\n\n        if (lineNeedsDraw(itemLayout)) {\n            var el = new this._ctor(lineData, idx, this._seriesScope);\n            el.traverse(updateIncrementalAndHover);\n\n            this.group.add(el);\n            lineData.setItemGraphicEl(idx, el);\n        }\n    }\n};\n\nfunction makeSeriesScope$1(lineData) {\n    var hostModel = lineData.hostModel;\n    return {\n        lineStyle: hostModel.getModel('lineStyle').getLineStyle(),\n        hoverLineStyle: hostModel.getModel('emphasis.lineStyle').getLineStyle(),\n        labelModel: hostModel.getModel('label'),\n        hoverLabelModel: hostModel.getModel('emphasis.label')\n    };\n}\n\nlineDrawProto.remove = function () {\n    this._clearIncremental();\n    this._incremental = null;\n    this.group.removeAll();\n};\n\nlineDrawProto._clearIncremental = function () {\n    var incremental = this._incremental;\n    if (incremental) {\n        incremental.clearDisplaybles();\n    }\n};\n\nfunction isPointNaN(pt) {\n    return isNaN(pt[0]) || isNaN(pt[1]);\n}\n\nfunction lineNeedsDraw(pts) {\n    return !isPointNaN(pts[0]) && !isPointNaN(pts[1]);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar v1 = [];\nvar v2 = [];\nvar v3 = [];\nvar quadraticAt$1 = quadraticAt;\nvar v2DistSquare = distSquare;\nvar mathAbs$1 = Math.abs;\nfunction intersectCurveCircle(curvePoints, center, radius) {\n    var p0 = curvePoints[0];\n    var p1 = curvePoints[1];\n    var p2 = curvePoints[2];\n\n    var d = Infinity;\n    var t;\n    var radiusSquare = radius * radius;\n    var interval = 0.1;\n\n    for (var _t = 0.1; _t <= 0.9; _t += 0.1) {\n        v1[0] = quadraticAt$1(p0[0], p1[0], p2[0], _t);\n        v1[1] = quadraticAt$1(p0[1], p1[1], p2[1], _t);\n        var diff = mathAbs$1(v2DistSquare(v1, center) - radiusSquare);\n        if (diff < d) {\n            d = diff;\n            t = _t;\n        }\n    }\n\n    // Assume the segment is monotone，Find root through Bisection method\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        // var prev = t - interval;\n        var next = t + interval;\n        // v1[0] = quadraticAt(p0[0], p1[0], p2[0], prev);\n        // v1[1] = quadraticAt(p0[1], p1[1], p2[1], prev);\n        v2[0] = quadraticAt$1(p0[0], p1[0], p2[0], t);\n        v2[1] = quadraticAt$1(p0[1], p1[1], p2[1], t);\n        v3[0] = quadraticAt$1(p0[0], p1[0], p2[0], next);\n        v3[1] = quadraticAt$1(p0[1], p1[1], p2[1], next);\n\n        var diff = v2DistSquare(v2, center) - radiusSquare;\n        if (mathAbs$1(diff) < 1e-2) {\n            break;\n        }\n\n        // var prevDiff = v2DistSquare(v1, center) - radiusSquare;\n        var nextDiff = v2DistSquare(v3, center) - radiusSquare;\n\n        interval /= 2;\n        if (diff < 0) {\n            if (nextDiff >= 0) {\n                t = t + interval;\n            }\n            else {\n                t = t - interval;\n            }\n        }\n        else {\n            if (nextDiff >= 0) {\n                t = t - interval;\n            }\n            else {\n                t = t + interval;\n            }\n        }\n    }\n\n    return t;\n}\n\n// Adjust edge to avoid\nvar adjustEdge = function (graph, scale$$1) {\n    var tmp0 = [];\n    var quadraticSubdivide$$1 = quadraticSubdivide;\n    var pts = [[], [], []];\n    var pts2 = [[], []];\n    var v = [];\n    scale$$1 /= 2;\n\n    function getSymbolSize(node) {\n        var symbolSize = node.getVisual('symbolSize');\n        if (symbolSize instanceof Array) {\n            symbolSize = (symbolSize[0] + symbolSize[1]) / 2;\n        }\n        return symbolSize;\n    }\n    graph.eachEdge(function (edge, idx) {\n        var linePoints = edge.getLayout();\n        var fromSymbol = edge.getVisual('fromSymbol');\n        var toSymbol = edge.getVisual('toSymbol');\n\n        if (!linePoints.__original) {\n            linePoints.__original = [\n                clone$1(linePoints[0]),\n                clone$1(linePoints[1])\n            ];\n            if (linePoints[2]) {\n                linePoints.__original.push(clone$1(linePoints[2]));\n            }\n        }\n        var originalPoints = linePoints.__original;\n        // Quadratic curve\n        if (linePoints[2] != null) {\n            copy(pts[0], originalPoints[0]);\n            copy(pts[1], originalPoints[2]);\n            copy(pts[2], originalPoints[1]);\n            if (fromSymbol && fromSymbol !== 'none') {\n                var symbolSize = getSymbolSize(edge.node1);\n\n                var t = intersectCurveCircle(pts, originalPoints[0], symbolSize * scale$$1);\n                // Subdivide and get the second\n                quadraticSubdivide$$1(pts[0][0], pts[1][0], pts[2][0], t, tmp0);\n                pts[0][0] = tmp0[3];\n                pts[1][0] = tmp0[4];\n                quadraticSubdivide$$1(pts[0][1], pts[1][1], pts[2][1], t, tmp0);\n                pts[0][1] = tmp0[3];\n                pts[1][1] = tmp0[4];\n            }\n            if (toSymbol && toSymbol !== 'none') {\n                var symbolSize = getSymbolSize(edge.node2);\n\n                var t = intersectCurveCircle(pts, originalPoints[1], symbolSize * scale$$1);\n                // Subdivide and get the first\n                quadraticSubdivide$$1(pts[0][0], pts[1][0], pts[2][0], t, tmp0);\n                pts[1][0] = tmp0[1];\n                pts[2][0] = tmp0[2];\n                quadraticSubdivide$$1(pts[0][1], pts[1][1], pts[2][1], t, tmp0);\n                pts[1][1] = tmp0[1];\n                pts[2][1] = tmp0[2];\n            }\n            // Copy back to layout\n            copy(linePoints[0], pts[0]);\n            copy(linePoints[1], pts[2]);\n            copy(linePoints[2], pts[1]);\n        }\n        // Line\n        else {\n            copy(pts2[0], originalPoints[0]);\n            copy(pts2[1], originalPoints[1]);\n\n            sub(v, pts2[1], pts2[0]);\n            normalize(v, v);\n            if (fromSymbol && fromSymbol !== 'none') {\n\n                var symbolSize = getSymbolSize(edge.node1);\n\n                scaleAndAdd(pts2[0], pts2[0], v, symbolSize * scale$$1);\n            }\n            if (toSymbol && toSymbol !== 'none') {\n                var symbolSize = getSymbolSize(edge.node2);\n\n                scaleAndAdd(pts2[1], pts2[1], v, -symbolSize * scale$$1);\n            }\n            copy(linePoints[0], pts2[0]);\n            copy(linePoints[1], pts2[1]);\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar FOCUS_ADJACENCY = '__focusNodeAdjacency';\nvar UNFOCUS_ADJACENCY = '__unfocusNodeAdjacency';\n\nvar nodeOpacityPath = ['itemStyle', 'opacity'];\nvar lineOpacityPath = ['lineStyle', 'opacity'];\n\nfunction getItemOpacity(item, opacityPath) {\n    return item.getVisual('opacity') || item.getModel().get(opacityPath);\n}\n\nfunction fadeOutItem(item, opacityPath, opacityRatio) {\n    var el = item.getGraphicEl();\n\n    var opacity = getItemOpacity(item, opacityPath);\n    if (opacityRatio != null) {\n        opacity == null && (opacity = 1);\n        opacity *= opacityRatio;\n    }\n\n    el.downplay && el.downplay();\n    el.traverse(function (child) {\n        if (child.type !== 'group') {\n            var opct = child.lineLabelOriginalOpacity;\n            if (opct == null || opacityRatio != null) {\n                opct = opacity;\n            }\n            child.setStyle('opacity', opct);\n        }\n    });\n}\n\nfunction fadeInItem(item, opacityPath) {\n    var opacity = getItemOpacity(item, opacityPath);\n    var el = item.getGraphicEl();\n\n    el.highlight && el.highlight();\n    el.traverse(function (child) {\n        if (child.type !== 'group') {\n            child.setStyle('opacity', opacity);\n        }\n    });\n}\n\nextendChartView({\n\n    type: 'graph',\n\n    init: function (ecModel, api) {\n        var symbolDraw = new SymbolDraw();\n        var lineDraw = new LineDraw();\n        var group = this.group;\n\n        this._controller = new RoamController(api.getZr());\n        this._controllerHost = {target: group};\n\n        group.add(symbolDraw.group);\n        group.add(lineDraw.group);\n\n        this._symbolDraw = symbolDraw;\n        this._lineDraw = lineDraw;\n\n        this._firstRender = true;\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n\n        this._model = seriesModel;\n        this._nodeScaleRatio = seriesModel.get('nodeScaleRatio');\n\n        var symbolDraw = this._symbolDraw;\n        var lineDraw = this._lineDraw;\n\n        var group = this.group;\n\n        if (coordSys.type === 'view') {\n            var groupNewProp = {\n                position: coordSys.position,\n                scale: coordSys.scale\n            };\n            if (this._firstRender) {\n                group.attr(groupNewProp);\n            }\n            else {\n                updateProps(group, groupNewProp, seriesModel);\n            }\n        }\n        // Fix edge contact point with node\n        adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel));\n\n        var data = seriesModel.getData();\n        symbolDraw.updateData(data);\n\n        var edgeData = seriesModel.getEdgeData();\n        lineDraw.updateData(edgeData);\n\n        this._updateNodeAndLinkScale();\n\n        this._updateController(seriesModel, ecModel, api);\n\n        clearTimeout(this._layoutTimeout);\n        var forceLayout = seriesModel.forceLayout;\n        var layoutAnimation = seriesModel.get('force.layoutAnimation');\n        if (forceLayout) {\n            this._startForceLayoutIteration(forceLayout, layoutAnimation);\n        }\n\n        data.eachItemGraphicEl(function (el, idx) {\n            var itemModel = data.getItemModel(idx);\n            // Update draggable\n            el.off('drag').off('dragend');\n            var draggable = itemModel.get('draggable');\n            if (draggable) {\n                el.on('drag', function () {\n                    if (forceLayout) {\n                        forceLayout.warmUp();\n                        !this._layouting\n                            && this._startForceLayoutIteration(forceLayout, layoutAnimation);\n                        forceLayout.setFixed(idx);\n                        // Write position back to layout\n                        data.setItemLayout(idx, el.position);\n                    }\n                }, this).on('dragend', function () {\n                    if (forceLayout) {\n                        forceLayout.setUnfixed(idx);\n                    }\n                }, this);\n            }\n            el.setDraggable(draggable && forceLayout);\n\n            el[FOCUS_ADJACENCY] && el.off('mouseover', el[FOCUS_ADJACENCY]);\n            el[UNFOCUS_ADJACENCY] && el.off('mouseout', el[UNFOCUS_ADJACENCY]);\n\n            if (itemModel.get('focusNodeAdjacency')) {\n                el.on('mouseover', el[FOCUS_ADJACENCY] = function () {\n                    api.dispatchAction({\n                        type: 'focusNodeAdjacency',\n                        seriesId: seriesModel.id,\n                        dataIndex: el.dataIndex\n                    });\n                });\n                el.on('mouseout', el[UNFOCUS_ADJACENCY] = function () {\n                    api.dispatchAction({\n                        type: 'unfocusNodeAdjacency',\n                        seriesId: seriesModel.id\n                    });\n                });\n            }\n\n        }, this);\n\n        data.graph.eachEdge(function (edge) {\n            var el = edge.getGraphicEl();\n\n            el[FOCUS_ADJACENCY] && el.off('mouseover', el[FOCUS_ADJACENCY]);\n            el[UNFOCUS_ADJACENCY] && el.off('mouseout', el[UNFOCUS_ADJACENCY]);\n\n            if (edge.getModel().get('focusNodeAdjacency')) {\n                el.on('mouseover', el[FOCUS_ADJACENCY] = function () {\n                    api.dispatchAction({\n                        type: 'focusNodeAdjacency',\n                        seriesId: seriesModel.id,\n                        edgeDataIndex: edge.dataIndex\n                    });\n                });\n                el.on('mouseout', el[UNFOCUS_ADJACENCY] = function () {\n                    api.dispatchAction({\n                        type: 'unfocusNodeAdjacency',\n                        seriesId: seriesModel.id\n                    });\n                });\n            }\n        });\n\n        var circularRotateLabel = seriesModel.get('layout') === 'circular'\n            && seriesModel.get('circular.rotateLabel');\n        var cx = data.getLayout('cx');\n        var cy = data.getLayout('cy');\n        data.eachItemGraphicEl(function (el, idx) {\n            var symbolPath = el.getSymbolPath();\n            if (circularRotateLabel) {\n                var pos = data.getItemLayout(idx);\n                var rad = Math.atan2(pos[1] - cy, pos[0] - cx);\n                if (rad < 0) {\n                    rad = Math.PI * 2 + rad;\n                }\n                var isLeft = pos[0] < cx;\n                if (isLeft) {\n                    rad = rad - Math.PI;\n                }\n                var textPosition = isLeft ? 'left' : 'right';\n                symbolPath.setStyle({\n                    textRotation: -rad,\n                    textPosition: textPosition,\n                    textOrigin: 'center'\n                });\n                symbolPath.hoverStyle && (symbolPath.hoverStyle.textPosition = textPosition);\n            }\n            else {\n                symbolPath.setStyle({\n                    textRotation: 0\n                });\n            }\n        });\n\n        this._firstRender = false;\n    },\n\n    dispose: function () {\n        this._controller && this._controller.dispose();\n        this._controllerHost = {};\n    },\n\n    focusNodeAdjacency: function (seriesModel, ecModel, api, payload) {\n        var data = this._model.getData();\n        var graph = data.graph;\n        var dataIndex = payload.dataIndex;\n        var edgeDataIndex = payload.edgeDataIndex;\n\n        var node = graph.getNodeByIndex(dataIndex);\n        var edge = graph.getEdgeByIndex(edgeDataIndex);\n\n        if (!node && !edge) {\n            return;\n        }\n\n        graph.eachNode(function (node) {\n            fadeOutItem(node, nodeOpacityPath, 0.1);\n        });\n        graph.eachEdge(function (edge) {\n            fadeOutItem(edge, lineOpacityPath, 0.1);\n        });\n\n        if (node) {\n            fadeInItem(node, nodeOpacityPath);\n            each$1(node.edges, function (adjacentEdge) {\n                if (adjacentEdge.dataIndex < 0) {\n                    return;\n                }\n                fadeInItem(adjacentEdge, lineOpacityPath);\n                fadeInItem(adjacentEdge.node1, nodeOpacityPath);\n                fadeInItem(adjacentEdge.node2, nodeOpacityPath);\n            });\n        }\n        if (edge) {\n            fadeInItem(edge, lineOpacityPath);\n            fadeInItem(edge.node1, nodeOpacityPath);\n            fadeInItem(edge.node2, nodeOpacityPath);\n        }\n    },\n\n    unfocusNodeAdjacency: function (seriesModel, ecModel, api, payload) {\n        var graph = this._model.getData().graph;\n\n        graph.eachNode(function (node) {\n            fadeOutItem(node, nodeOpacityPath);\n        });\n        graph.eachEdge(function (edge) {\n            fadeOutItem(edge, lineOpacityPath);\n        });\n    },\n\n    _startForceLayoutIteration: function (forceLayout, layoutAnimation) {\n        var self = this;\n        (function step() {\n            forceLayout.step(function (stopped) {\n                self.updateLayout(self._model);\n                (self._layouting = !stopped) && (\n                    layoutAnimation\n                        ? (self._layoutTimeout = setTimeout(step, 16))\n                        : step()\n                );\n            });\n        })();\n    },\n\n    _updateController: function (seriesModel, ecModel, api) {\n        var controller = this._controller;\n        var controllerHost = this._controllerHost;\n        var group = this.group;\n\n        controller.setPointerChecker(function (e, x, y) {\n            var rect = group.getBoundingRect();\n            rect.applyTransform(group.transform);\n            return rect.contain(x, y)\n                && !onIrrelevantElement(e, api, seriesModel);\n        });\n\n        if (seriesModel.coordinateSystem.type !== 'view') {\n            controller.disable();\n            return;\n        }\n        controller.enable(seriesModel.get('roam'));\n        controllerHost.zoomLimit = seriesModel.get('scaleLimit');\n        controllerHost.zoom = seriesModel.coordinateSystem.getZoom();\n\n        controller\n            .off('pan')\n            .off('zoom')\n            .on('pan', function (e) {\n                updateViewOnPan(controllerHost, e.dx, e.dy);\n                api.dispatchAction({\n                    seriesId: seriesModel.id,\n                    type: 'graphRoam',\n                    dx: e.dx,\n                    dy: e.dy\n                });\n            })\n            .on('zoom', function (e) {\n                updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY);\n                api.dispatchAction({\n                    seriesId: seriesModel.id,\n                    type: 'graphRoam',\n                    zoom: e.scale,\n                    originX: e.originX,\n                    originY: e.originY\n                });\n                this._updateNodeAndLinkScale();\n                adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel));\n                this._lineDraw.updateLayout();\n            }, this);\n    },\n\n    _updateNodeAndLinkScale: function () {\n        var seriesModel = this._model;\n        var data = seriesModel.getData();\n\n        var nodeScale = this._getNodeGlobalScale(seriesModel);\n        var invScale = [nodeScale, nodeScale];\n\n        data.eachItemGraphicEl(function (el, idx) {\n            el.attr('scale', invScale);\n        });\n    },\n\n    _getNodeGlobalScale: function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys.type !== 'view') {\n            return 1;\n        }\n\n        var nodeScaleRatio = this._nodeScaleRatio;\n\n        var groupScale = coordSys.scale;\n        var groupZoom = (groupScale && groupScale[0]) || 1;\n        // Scale node when zoom changes\n        var roamZoom = coordSys.getZoom();\n        var nodeScale = (roamZoom - 1) * nodeScaleRatio + 1;\n\n        return nodeScale / groupZoom;\n    },\n\n    updateLayout: function (seriesModel) {\n        adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel));\n\n        this._symbolDraw.updateLayout();\n        this._lineDraw.updateLayout();\n    },\n\n    remove: function (ecModel, api) {\n        this._symbolDraw && this._symbolDraw.remove();\n        this._lineDraw && this._lineDraw.remove();\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @payload\n * @property {number} [seriesIndex]\n * @property {string} [seriesId]\n * @property {string} [seriesName]\n * @property {number} [dataIndex]\n */\nregisterAction({\n    type: 'focusNodeAdjacency',\n    event: 'focusNodeAdjacency',\n    update: 'series:focusNodeAdjacency'\n}, function () {});\n\n/**\n * @payload\n * @property {number} [seriesIndex]\n * @property {string} [seriesId]\n * @property {string} [seriesName]\n */\nregisterAction({\n    type: 'unfocusNodeAdjacency',\n    event: 'unfocusNodeAdjacency',\n    update: 'series:unfocusNodeAdjacency'\n}, function () {});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar actionInfo = {\n    type: 'graphRoam',\n    event: 'graphRoam',\n    update: 'none'\n};\n\n/**\n * @payload\n * @property {string} name Series name\n * @property {number} [dx]\n * @property {number} [dy]\n * @property {number} [zoom]\n * @property {number} [originX]\n * @property {number} [originY]\n */\nregisterAction(actionInfo, function (payload, ecModel) {\n    ecModel.eachComponent({mainType: 'series', query: payload}, function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n\n        var res = updateCenterAndZoom(coordSys, payload);\n\n        seriesModel.setCenter\n            && seriesModel.setCenter(res.center);\n\n        seriesModel.setZoom\n            && seriesModel.setZoom(res.zoom);\n    });\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar categoryFilter = function (ecModel) {\n    var legendModels = ecModel.findComponents({\n        mainType: 'legend'\n    });\n    if (!legendModels || !legendModels.length) {\n        return;\n    }\n    ecModel.eachSeriesByType('graph', function (graphSeries) {\n        var categoriesData = graphSeries.getCategoriesData();\n        var graph = graphSeries.getGraph();\n        var data = graph.data;\n\n        var categoryNames = categoriesData.mapArray(categoriesData.getName);\n\n        data.filterSelf(function (idx) {\n            var model = data.getItemModel(idx);\n            var category = model.getShallow('category');\n            if (category != null) {\n                if (typeof category === 'number') {\n                    category = categoryNames[category];\n                }\n                // If in any legend component the status is not selected.\n                for (var i = 0; i < legendModels.length; i++) {\n                    if (!legendModels[i].isSelected(category)) {\n                        return false;\n                    }\n                }\n            }\n            return true;\n        });\n    }, this);\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar categoryVisual = function (ecModel) {\n\n    var paletteScope = {};\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        var categoriesData = seriesModel.getCategoriesData();\n        var data = seriesModel.getData();\n\n        var categoryNameIdxMap = {};\n\n        categoriesData.each(function (idx) {\n            var name = categoriesData.getName(idx);\n            // Add prefix to avoid conflict with Object.prototype.\n            categoryNameIdxMap['ec-' + name] = idx;\n\n            var itemModel = categoriesData.getItemModel(idx);\n            var color = itemModel.get('itemStyle.color')\n                || seriesModel.getColorFromPalette(name, paletteScope);\n            categoriesData.setItemVisual(idx, 'color', color);\n        });\n\n        // Assign category color to visual\n        if (categoriesData.count()) {\n            data.each(function (idx) {\n                var model = data.getItemModel(idx);\n                var category = model.getShallow('category');\n                if (category != null) {\n                    if (typeof category === 'string') {\n                        category = categoryNameIdxMap['ec-' + category];\n                    }\n                    if (!data.getItemVisual(idx, 'color', true)) {\n                        data.setItemVisual(\n                            idx, 'color',\n                            categoriesData.getItemVisual(category, 'color')\n                        );\n                    }\n                }\n            });\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction normalize$1(a) {\n    if (!(a instanceof Array)) {\n        a = [a, a];\n    }\n    return a;\n}\n\nvar edgeVisual = function (ecModel) {\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        var graph = seriesModel.getGraph();\n        var edgeData = seriesModel.getEdgeData();\n        var symbolType = normalize$1(seriesModel.get('edgeSymbol'));\n        var symbolSize = normalize$1(seriesModel.get('edgeSymbolSize'));\n\n        var colorQuery = 'lineStyle.color'.split('.');\n        var opacityQuery = 'lineStyle.opacity'.split('.');\n\n        edgeData.setVisual('fromSymbol', symbolType && symbolType[0]);\n        edgeData.setVisual('toSymbol', symbolType && symbolType[1]);\n        edgeData.setVisual('fromSymbolSize', symbolSize && symbolSize[0]);\n        edgeData.setVisual('toSymbolSize', symbolSize && symbolSize[1]);\n        edgeData.setVisual('color', seriesModel.get(colorQuery));\n        edgeData.setVisual('opacity', seriesModel.get(opacityQuery));\n\n        edgeData.each(function (idx) {\n            var itemModel = edgeData.getItemModel(idx);\n            var edge = graph.getEdgeByIndex(idx);\n            var symbolType = normalize$1(itemModel.getShallow('symbol', true));\n            var symbolSize = normalize$1(itemModel.getShallow('symbolSize', true));\n            // Edge visual must after node visual\n            var color = itemModel.get(colorQuery);\n            var opacity = itemModel.get(opacityQuery);\n            switch (color) {\n                case 'source':\n                    color = edge.node1.getVisual('color');\n                    break;\n                case 'target':\n                    color = edge.node2.getVisual('color');\n                    break;\n            }\n\n            symbolType[0] && edge.setVisual('fromSymbol', symbolType[0]);\n            symbolType[1] && edge.setVisual('toSymbol', symbolType[1]);\n            symbolSize[0] && edge.setVisual('fromSymbolSize', symbolSize[0]);\n            symbolSize[1] && edge.setVisual('toSymbolSize', symbolSize[1]);\n\n            edge.setVisual('color', color);\n            edge.setVisual('opacity', opacity);\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction simpleLayout$1(seriesModel) {\n    var coordSys = seriesModel.coordinateSystem;\n    if (coordSys && coordSys.type !== 'view') {\n        return;\n    }\n    var graph = seriesModel.getGraph();\n\n    graph.eachNode(function (node) {\n        var model = node.getModel();\n        node.setLayout([+model.get('x'), +model.get('y')]);\n    });\n\n    simpleLayoutEdge(graph);\n}\n\nfunction simpleLayoutEdge(graph) {\n    graph.eachEdge(function (edge) {\n        var curveness = edge.getModel().get('lineStyle.curveness') || 0;\n        var p1 = clone$1(edge.node1.getLayout());\n        var p2 = clone$1(edge.node2.getLayout());\n        var points = [p1, p2];\n        if (+curveness) {\n            points.push([\n                (p1[0] + p2[0]) / 2 - (p1[1] - p2[1]) * curveness,\n                (p1[1] + p2[1]) / 2 - (p2[0] - p1[0]) * curveness\n            ]);\n        }\n        edge.setLayout(points);\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar simpleLayout = function (ecModel, api) {\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        var layout = seriesModel.get('layout');\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys && coordSys.type !== 'view') {\n            var data = seriesModel.getData();\n\n            var dimensions = [];\n            each$1(coordSys.dimensions, function (coordDim) {\n                dimensions = dimensions.concat(data.mapDimension(coordDim, true));\n            });\n\n            for (var dataIndex = 0; dataIndex < data.count(); dataIndex++) {\n                var value = [];\n                var hasValue = false;\n                for (var i = 0; i < dimensions.length; i++) {\n                    var val = data.get(dimensions[i], dataIndex);\n                    if (!isNaN(val)) {\n                        hasValue = true;\n                    }\n                    value.push(val);\n                }\n                if (hasValue) {\n                    data.setItemLayout(dataIndex, coordSys.dataToPoint(value));\n                }\n                else {\n                    // Also {Array.<number>}, not undefined to avoid if...else... statement\n                    data.setItemLayout(dataIndex, [NaN, NaN]);\n                }\n            }\n\n            simpleLayoutEdge(data.graph);\n        }\n        else if (!layout || layout === 'none') {\n            simpleLayout$1(seriesModel);\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction circularLayout$1(seriesModel) {\n    var coordSys = seriesModel.coordinateSystem;\n    if (coordSys && coordSys.type !== 'view') {\n        return;\n    }\n\n    var rect = coordSys.getBoundingRect();\n\n    var nodeData = seriesModel.getData();\n    var graph = nodeData.graph;\n\n    var angle = 0;\n    var sum = nodeData.getSum('value');\n    var unitAngle = Math.PI * 2 / (sum || nodeData.count());\n\n    var cx = rect.width / 2 + rect.x;\n    var cy = rect.height / 2 + rect.y;\n\n    var r = Math.min(rect.width, rect.height) / 2;\n\n    graph.eachNode(function (node) {\n        var value = node.getValue('value');\n\n        angle += unitAngle * (sum ? value : 1) / 2;\n\n        node.setLayout([\n            r * Math.cos(angle) + cx,\n            r * Math.sin(angle) + cy\n        ]);\n\n        angle += unitAngle * (sum ? value : 1) / 2;\n    });\n\n    nodeData.setLayout({\n        cx: cx,\n        cy: cy\n    });\n\n    graph.eachEdge(function (edge) {\n        var curveness = edge.getModel().get('lineStyle.curveness') || 0;\n        var p1 = clone$1(edge.node1.getLayout());\n        var p2 = clone$1(edge.node2.getLayout());\n        var cp1;\n        var x12 = (p1[0] + p2[0]) / 2;\n        var y12 = (p1[1] + p2[1]) / 2;\n        if (+curveness) {\n            curveness *= 3;\n            cp1 = [\n                cx * curveness + x12 * (1 - curveness),\n                cy * curveness + y12 * (1 - curveness)\n            ];\n        }\n        edge.setLayout([p1, p2, cp1]);\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar circularLayout = function (ecModel) {\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        if (seriesModel.get('layout') === 'circular') {\n            circularLayout$1(seriesModel);\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* Some formulas were originally copied from \"d3.js\" with some\n* modifications made for this project.\n* (See more details in the comment of the method \"step\" below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\nvar scaleAndAdd$2 = scaleAndAdd;\n\n// function adjacentNode(n, e) {\n//     return e.n1 === n ? e.n2 : e.n1;\n// }\n\nfunction forceLayout$1(nodes, edges, opts) {\n    var rect = opts.rect;\n    var width = rect.width;\n    var height = rect.height;\n    var center = [rect.x + width / 2, rect.y + height / 2];\n    // var scale = opts.scale || 1;\n    var gravity = opts.gravity == null ? 0.1 : opts.gravity;\n\n    // for (var i = 0; i < edges.length; i++) {\n    //     var e = edges[i];\n    //     var n1 = e.n1;\n    //     var n2 = e.n2;\n    //     n1.edges = n1.edges || [];\n    //     n2.edges = n2.edges || [];\n    //     n1.edges.push(e);\n    //     n2.edges.push(e);\n    // }\n    // Init position\n    for (var i = 0; i < nodes.length; i++) {\n        var n = nodes[i];\n        if (!n.p) {\n            n.p = create(\n                width * (Math.random() - 0.5) + center[0],\n                height * (Math.random() - 0.5) + center[1]\n            );\n        }\n        n.pp = clone$1(n.p);\n        n.edges = null;\n    }\n\n    // Formula in 'Graph Drawing by Force-directed Placement'\n    // var k = scale * Math.sqrt(width * height / nodes.length);\n    // var k2 = k * k;\n\n    var friction = 0.6;\n\n    return {\n        warmUp: function () {\n            friction = 0.5;\n        },\n\n        setFixed: function (idx) {\n            nodes[idx].fixed = true;\n        },\n\n        setUnfixed: function (idx) {\n            nodes[idx].fixed = false;\n        },\n\n        /**\n         * Some formulas were originally copied from \"d3.js\"\n         * https://github.com/d3/d3/blob/b516d77fb8566b576088e73410437494717ada26/src/layout/force.js\n         * with some modifications made for this project.\n         * See the license statement at the head of this file.\n         */\n        step: function (cb) {\n            var v12 = [];\n            var nLen = nodes.length;\n            for (var i = 0; i < edges.length; i++) {\n                var e = edges[i];\n                var n1 = e.n1;\n                var n2 = e.n2;\n\n                sub(v12, n2.p, n1.p);\n                var d = len(v12) - e.d;\n                var w = n2.w / (n1.w + n2.w);\n\n                if (isNaN(w)) {\n                    w = 0;\n                }\n\n                normalize(v12, v12);\n\n                !n1.fixed && scaleAndAdd$2(n1.p, n1.p, v12, w * d * friction);\n                !n2.fixed && scaleAndAdd$2(n2.p, n2.p, v12, -(1 - w) * d * friction);\n            }\n            // Gravity\n            for (var i = 0; i < nLen; i++) {\n                var n = nodes[i];\n                if (!n.fixed) {\n                    sub(v12, center, n.p);\n                    // var d = vec2.len(v12);\n                    // vec2.scale(v12, v12, 1 / d);\n                    // var gravityFactor = gravity;\n                    scaleAndAdd$2(n.p, n.p, v12, gravity * friction);\n                }\n            }\n\n            // Repulsive\n            // PENDING\n            for (var i = 0; i < nLen; i++) {\n                var n1 = nodes[i];\n                for (var j = i + 1; j < nLen; j++) {\n                    var n2 = nodes[j];\n                    sub(v12, n2.p, n1.p);\n                    var d = len(v12);\n                    if (d === 0) {\n                        // Random repulse\n                        set(v12, Math.random() - 0.5, Math.random() - 0.5);\n                        d = 1;\n                    }\n                    var repFact = (n1.rep + n2.rep) / d / d;\n                    !n1.fixed && scaleAndAdd$2(n1.pp, n1.pp, v12, repFact);\n                    !n2.fixed && scaleAndAdd$2(n2.pp, n2.pp, v12, -repFact);\n                }\n            }\n            var v = [];\n            for (var i = 0; i < nLen; i++) {\n                var n = nodes[i];\n                if (!n.fixed) {\n                    sub(v, n.p, n.pp);\n                    scaleAndAdd$2(n.p, n.p, v, friction);\n                    copy(n.pp, n.p);\n                }\n            }\n\n            friction = friction * 0.992;\n\n            cb && cb(nodes, edges, friction < 0.01);\n        }\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar forceLayout = function (ecModel) {\n    ecModel.eachSeriesByType('graph', function (graphSeries) {\n        var coordSys = graphSeries.coordinateSystem;\n        if (coordSys && coordSys.type !== 'view') {\n            return;\n        }\n        if (graphSeries.get('layout') === 'force') {\n            var preservedPoints = graphSeries.preservedPoints || {};\n            var graph = graphSeries.getGraph();\n            var nodeData = graph.data;\n            var edgeData = graph.edgeData;\n            var forceModel = graphSeries.getModel('force');\n            var initLayout = forceModel.get('initLayout');\n            if (graphSeries.preservedPoints) {\n                nodeData.each(function (idx) {\n                    var id = nodeData.getId(idx);\n                    nodeData.setItemLayout(idx, preservedPoints[id] || [NaN, NaN]);\n                });\n            }\n            else if (!initLayout || initLayout === 'none') {\n                simpleLayout$1(graphSeries);\n            }\n            else if (initLayout === 'circular') {\n                circularLayout$1(graphSeries);\n            }\n\n            var nodeDataExtent = nodeData.getDataExtent('value');\n            var edgeDataExtent = edgeData.getDataExtent('value');\n            // var edgeDataExtent = edgeData.getDataExtent('value');\n            var repulsion = forceModel.get('repulsion');\n            var edgeLength = forceModel.get('edgeLength');\n            if (!isArray(repulsion)) {\n                repulsion = [repulsion, repulsion];\n            }\n            if (!isArray(edgeLength)) {\n                edgeLength = [edgeLength, edgeLength];\n            }\n            // Larger value has smaller length\n            edgeLength = [edgeLength[1], edgeLength[0]];\n\n            var nodes = nodeData.mapArray('value', function (value, idx) {\n                var point = nodeData.getItemLayout(idx);\n                var rep = linearMap(value, nodeDataExtent, repulsion);\n                if (isNaN(rep)) {\n                    rep = (repulsion[0] + repulsion[1]) / 2;\n                }\n                return {\n                    w: rep,\n                    rep: rep,\n                    fixed: nodeData.getItemModel(idx).get('fixed'),\n                    p: (!point || isNaN(point[0]) || isNaN(point[1])) ? null : point\n                };\n            });\n            var edges = edgeData.mapArray('value', function (value, idx) {\n                var edge = graph.getEdgeByIndex(idx);\n                var d = linearMap(value, edgeDataExtent, edgeLength);\n                if (isNaN(d)) {\n                    d = (edgeLength[0] + edgeLength[1]) / 2;\n                }\n                return {\n                    n1: nodes[edge.node1.dataIndex],\n                    n2: nodes[edge.node2.dataIndex],\n                    d: d,\n                    curveness: edge.getModel().get('lineStyle.curveness') || 0\n                };\n            });\n\n            var coordSys = graphSeries.coordinateSystem;\n            var rect = coordSys.getBoundingRect();\n            var forceInstance = forceLayout$1(nodes, edges, {\n                rect: rect,\n                gravity: forceModel.get('gravity')\n            });\n            var oldStep = forceInstance.step;\n            forceInstance.step = function (cb) {\n                for (var i = 0, l = nodes.length; i < l; i++) {\n                    if (nodes[i].fixed) {\n                        // Write back to layout instance\n                        copy(nodes[i].p, graph.getNodeByIndex(i).getLayout());\n                    }\n                }\n                oldStep(function (nodes, edges, stopped) {\n                    for (var i = 0, l = nodes.length; i < l; i++) {\n                        if (!nodes[i].fixed) {\n                            graph.getNodeByIndex(i).setLayout(nodes[i].p);\n                        }\n                        preservedPoints[nodeData.getId(i)] = nodes[i].p;\n                    }\n                    for (var i = 0, l = edges.length; i < l; i++) {\n                        var e = edges[i];\n                        var edge = graph.getEdgeByIndex(i);\n                        var p1 = e.n1.p;\n                        var p2 = e.n2.p;\n                        var points = edge.getLayout();\n                        points = points ? points.slice() : [];\n                        points[0] = points[0] || [];\n                        points[1] = points[1] || [];\n                        copy(points[0], p1);\n                        copy(points[1], p2);\n                        if (+e.curveness) {\n                            points[2] = [\n                                (p1[0] + p2[0]) / 2 - (p1[1] - p2[1]) * e.curveness,\n                                (p1[1] + p2[1]) / 2 - (p2[0] - p1[0]) * e.curveness\n                            ];\n                        }\n                        edge.setLayout(points);\n                    }\n                    // Update layout\n\n                    cb && cb(stopped);\n                });\n            };\n            graphSeries.forceLayout = forceInstance;\n            graphSeries.preservedPoints = preservedPoints;\n\n            // Step to get the layout\n            forceInstance.step();\n        }\n        else {\n            // Remove prev injected forceLayout instance\n            graphSeries.forceLayout = null;\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME Where to create the simple view coordinate system\nfunction getViewRect$1(seriesModel, api, aspect) {\n    var option = seriesModel.getBoxLayoutParams();\n    option.aspect = aspect;\n    return getLayoutRect(option, {\n        width: api.getWidth(),\n        height: api.getHeight()\n    });\n}\n\nvar createView = function (ecModel, api) {\n    var viewList = [];\n    ecModel.eachSeriesByType('graph', function (seriesModel) {\n        var coordSysType = seriesModel.get('coordinateSystem');\n        if (!coordSysType || coordSysType === 'view') {\n\n            var data = seriesModel.getData();\n            var positions = data.mapArray(function (idx) {\n                var itemModel = data.getItemModel(idx);\n                return [+itemModel.get('x'), +itemModel.get('y')];\n            });\n\n            var min = [];\n            var max = [];\n\n            fromPoints(positions, min, max);\n\n            // If width or height is 0\n            if (max[0] - min[0] === 0) {\n                max[0] += 1;\n                min[0] -= 1;\n            }\n            if (max[1] - min[1] === 0) {\n                max[1] += 1;\n                min[1] -= 1;\n            }\n            var aspect = (max[0] - min[0]) / (max[1] - min[1]);\n            // FIXME If get view rect after data processed?\n            var viewRect = getViewRect$1(seriesModel, api, aspect);\n            // Position may be NaN, use view rect instead\n            if (isNaN(aspect)) {\n                min = [viewRect.x, viewRect.y];\n                max = [viewRect.x + viewRect.width, viewRect.y + viewRect.height];\n            }\n\n            var bbWidth = max[0] - min[0];\n            var bbHeight = max[1] - min[1];\n\n            var viewWidth = viewRect.width;\n            var viewHeight = viewRect.height;\n\n            var viewCoordSys = seriesModel.coordinateSystem = new View();\n            viewCoordSys.zoomLimit = seriesModel.get('scaleLimit');\n\n            viewCoordSys.setBoundingRect(\n                min[0], min[1], bbWidth, bbHeight\n            );\n            viewCoordSys.setViewRect(\n                viewRect.x, viewRect.y, viewWidth, viewHeight\n            );\n\n            // Update roam info\n            viewCoordSys.setCenter(seriesModel.get('center'));\n            viewCoordSys.setZoom(seriesModel.get('zoom'));\n\n            viewList.push(viewCoordSys);\n        }\n    });\n\n    return viewList;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterProcessor(categoryFilter);\n\nregisterVisual(visualSymbol('graph', 'circle', null));\nregisterVisual(categoryVisual);\nregisterVisual(edgeVisual);\n\nregisterLayout(simpleLayout);\nregisterLayout(circularLayout);\nregisterLayout(forceLayout);\n\n// Graph view coordinate system\nregisterCoordinateSystem('graphView', {\n    create: createView\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar GaugeSeries = SeriesModel.extend({\n\n    type: 'series.gauge',\n\n    getInitialData: function (option, ecModel) {\n        var dataOpt = option.data || [];\n        if (!isArray(dataOpt)) {\n            dataOpt = [dataOpt];\n        }\n        option.data = dataOpt;\n        return createListSimply(this, ['value']);\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        // 默认全局居中\n        center: ['50%', '50%'],\n        legendHoverLink: true,\n        radius: '75%',\n        startAngle: 225,\n        endAngle: -45,\n        clockwise: true,\n        // 最小值\n        min: 0,\n        // 最大值\n        max: 100,\n        // 分割段数，默认为10\n        splitNumber: 10,\n        // 坐标轴线\n        axisLine: {\n            // 默认显示，属性show控制显示与否\n            show: true,\n            lineStyle: {       // 属性lineStyle控制线条样式\n                color: [[0.2, '#91c7ae'], [0.8, '#63869e'], [1, '#c23531']],\n                width: 30\n            }\n        },\n        // 分隔线\n        splitLine: {\n            // 默认显示，属性show控制显示与否\n            show: true,\n            // 属性length控制线长\n            length: 30,\n            // 属性lineStyle（详见lineStyle）控制线条样式\n            lineStyle: {\n                color: '#eee',\n                width: 2,\n                type: 'solid'\n            }\n        },\n        // 坐标轴小标记\n        axisTick: {\n            // 属性show控制显示与否，默认不显示\n            show: true,\n            // 每份split细分多少段\n            splitNumber: 5,\n            // 属性length控制线长\n            length: 8,\n            // 属性lineStyle控制线条样式\n            lineStyle: {\n                color: '#eee',\n                width: 1,\n                type: 'solid'\n            }\n        },\n        axisLabel: {\n            show: true,\n            distance: 5,\n            // formatter: null,\n            color: 'auto'\n        },\n        pointer: {\n            show: true,\n            length: '80%',\n            width: 8\n        },\n        itemStyle: {\n            color: 'auto'\n        },\n        title: {\n            show: true,\n            // x, y，单位px\n            offsetCenter: [0, '-40%'],\n            // 其余属性默认使用全局文本样式，详见TEXTSTYLE\n            color: '#333',\n            fontSize: 15\n        },\n        detail: {\n            show: true,\n            backgroundColor: 'rgba(0,0,0,0)',\n            borderWidth: 0,\n            borderColor: '#ccc',\n            width: 100,\n            height: null, // self-adaption\n            padding: [5, 10],\n            // x, y，单位px\n            offsetCenter: [0, '40%'],\n            // formatter: null,\n            // 其余属性默认使用全局文本样式，详见TEXTSTYLE\n            color: 'auto',\n            fontSize: 30\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PointerPath = Path.extend({\n\n    type: 'echartsGaugePointer',\n\n    shape: {\n        angle: 0,\n\n        width: 10,\n\n        r: 10,\n\n        x: 0,\n\n        y: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var mathCos = Math.cos;\n        var mathSin = Math.sin;\n\n        var r = shape.r;\n        var width = shape.width;\n        var angle = shape.angle;\n        var x = shape.x - mathCos(angle) * width * (width >= r / 3 ? 1 : 2);\n        var y = shape.y - mathSin(angle) * width * (width >= r / 3 ? 1 : 2);\n\n        angle = shape.angle - Math.PI / 2;\n        ctx.moveTo(x, y);\n        ctx.lineTo(\n            shape.x + mathCos(angle) * width,\n            shape.y + mathSin(angle) * width\n        );\n        ctx.lineTo(\n            shape.x + mathCos(shape.angle) * r,\n            shape.y + mathSin(shape.angle) * r\n        );\n        ctx.lineTo(\n            shape.x - mathCos(angle) * width,\n            shape.y - mathSin(angle) * width\n        );\n        ctx.lineTo(x, y);\n        return;\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction parsePosition(seriesModel, api) {\n    var center = seriesModel.get('center');\n    var width = api.getWidth();\n    var height = api.getHeight();\n    var size = Math.min(width, height);\n    var cx = parsePercent$1(center[0], api.getWidth());\n    var cy = parsePercent$1(center[1], api.getHeight());\n    var r = parsePercent$1(seriesModel.get('radius'), size / 2);\n\n    return {\n        cx: cx,\n        cy: cy,\n        r: r\n    };\n}\n\nfunction formatLabel(label, labelFormatter) {\n    if (labelFormatter) {\n        if (typeof labelFormatter === 'string') {\n            label = labelFormatter.replace('{value}', label != null ? label : '');\n        }\n        else if (typeof labelFormatter === 'function') {\n            label = labelFormatter(label);\n        }\n    }\n\n    return label;\n}\n\nvar PI2$5 = Math.PI * 2;\n\nvar GaugeView = Chart.extend({\n\n    type: 'gauge',\n\n    render: function (seriesModel, ecModel, api) {\n\n        this.group.removeAll();\n\n        var colorList = seriesModel.get('axisLine.lineStyle.color');\n        var posInfo = parsePosition(seriesModel, api);\n\n        this._renderMain(\n            seriesModel, ecModel, api, colorList, posInfo\n        );\n    },\n\n    dispose: function () {},\n\n    _renderMain: function (seriesModel, ecModel, api, colorList, posInfo) {\n        var group = this.group;\n\n        var axisLineModel = seriesModel.getModel('axisLine');\n        var lineStyleModel = axisLineModel.getModel('lineStyle');\n\n        var clockwise = seriesModel.get('clockwise');\n        var startAngle = -seriesModel.get('startAngle') / 180 * Math.PI;\n        var endAngle = -seriesModel.get('endAngle') / 180 * Math.PI;\n\n        var angleRangeSpan = (endAngle - startAngle) % PI2$5;\n\n        var prevEndAngle = startAngle;\n        var axisLineWidth = lineStyleModel.get('width');\n\n        for (var i = 0; i < colorList.length; i++) {\n            // Clamp\n            var percent = Math.min(Math.max(colorList[i][0], 0), 1);\n            var endAngle = startAngle + angleRangeSpan * percent;\n            var sector = new Sector({\n                shape: {\n                    startAngle: prevEndAngle,\n                    endAngle: endAngle,\n                    cx: posInfo.cx,\n                    cy: posInfo.cy,\n                    clockwise: clockwise,\n                    r0: posInfo.r - axisLineWidth,\n                    r: posInfo.r\n                },\n                silent: true\n            });\n\n            sector.setStyle({\n                fill: colorList[i][1]\n            });\n\n            sector.setStyle(lineStyleModel.getLineStyle(\n                // Because we use sector to simulate arc\n                // so the properties for stroking are useless\n                ['color', 'borderWidth', 'borderColor']\n            ));\n\n            group.add(sector);\n\n            prevEndAngle = endAngle;\n        }\n\n        var getColor = function (percent) {\n            // Less than 0\n            if (percent <= 0) {\n                return colorList[0][1];\n            }\n            for (var i = 0; i < colorList.length; i++) {\n                if (colorList[i][0] >= percent\n                    && (i === 0 ? 0 : colorList[i - 1][0]) < percent\n                ) {\n                    return colorList[i][1];\n                }\n            }\n            // More than 1\n            return colorList[i - 1][1];\n        };\n\n        if (!clockwise) {\n            var tmp = startAngle;\n            startAngle = endAngle;\n            endAngle = tmp;\n        }\n\n        this._renderTicks(\n            seriesModel, ecModel, api, getColor, posInfo,\n            startAngle, endAngle, clockwise\n        );\n\n        this._renderPointer(\n            seriesModel, ecModel, api, getColor, posInfo,\n            startAngle, endAngle, clockwise\n        );\n\n        this._renderTitle(\n            seriesModel, ecModel, api, getColor, posInfo\n        );\n        this._renderDetail(\n            seriesModel, ecModel, api, getColor, posInfo\n        );\n    },\n\n    _renderTicks: function (\n        seriesModel, ecModel, api, getColor, posInfo,\n        startAngle, endAngle, clockwise\n    ) {\n        var group = this.group;\n        var cx = posInfo.cx;\n        var cy = posInfo.cy;\n        var r = posInfo.r;\n\n        var minVal = +seriesModel.get('min');\n        var maxVal = +seriesModel.get('max');\n\n        var splitLineModel = seriesModel.getModel('splitLine');\n        var tickModel = seriesModel.getModel('axisTick');\n        var labelModel = seriesModel.getModel('axisLabel');\n\n        var splitNumber = seriesModel.get('splitNumber');\n        var subSplitNumber = tickModel.get('splitNumber');\n\n        var splitLineLen = parsePercent$1(\n            splitLineModel.get('length'), r\n        );\n        var tickLen = parsePercent$1(\n            tickModel.get('length'), r\n        );\n\n        var angle = startAngle;\n        var step = (endAngle - startAngle) / splitNumber;\n        var subStep = step / subSplitNumber;\n\n        var splitLineStyle = splitLineModel.getModel('lineStyle').getLineStyle();\n        var tickLineStyle = tickModel.getModel('lineStyle').getLineStyle();\n\n        for (var i = 0; i <= splitNumber; i++) {\n            var unitX = Math.cos(angle);\n            var unitY = Math.sin(angle);\n            // Split line\n            if (splitLineModel.get('show')) {\n                var splitLine = new Line({\n                    shape: {\n                        x1: unitX * r + cx,\n                        y1: unitY * r + cy,\n                        x2: unitX * (r - splitLineLen) + cx,\n                        y2: unitY * (r - splitLineLen) + cy\n                    },\n                    style: splitLineStyle,\n                    silent: true\n                });\n                if (splitLineStyle.stroke === 'auto') {\n                    splitLine.setStyle({\n                        stroke: getColor(i / splitNumber)\n                    });\n                }\n\n                group.add(splitLine);\n            }\n\n            // Label\n            if (labelModel.get('show')) {\n                var label = formatLabel(\n                    round$2(i / splitNumber * (maxVal - minVal) + minVal),\n                    labelModel.get('formatter')\n                );\n                var distance = labelModel.get('distance');\n                var autoColor = getColor(i / splitNumber);\n\n                group.add(new Text({\n                    style: setTextStyle({}, labelModel, {\n                        text: label,\n                        x: unitX * (r - splitLineLen - distance) + cx,\n                        y: unitY * (r - splitLineLen - distance) + cy,\n                        textVerticalAlign: unitY < -0.4 ? 'top' : (unitY > 0.4 ? 'bottom' : 'middle'),\n                        textAlign: unitX < -0.4 ? 'left' : (unitX > 0.4 ? 'right' : 'center')\n                    }, {autoColor: autoColor}),\n                    silent: true\n                }));\n            }\n\n            // Axis tick\n            if (tickModel.get('show') && i !== splitNumber) {\n                for (var j = 0; j <= subSplitNumber; j++) {\n                    var unitX = Math.cos(angle);\n                    var unitY = Math.sin(angle);\n                    var tickLine = new Line({\n                        shape: {\n                            x1: unitX * r + cx,\n                            y1: unitY * r + cy,\n                            x2: unitX * (r - tickLen) + cx,\n                            y2: unitY * (r - tickLen) + cy\n                        },\n                        silent: true,\n                        style: tickLineStyle\n                    });\n\n                    if (tickLineStyle.stroke === 'auto') {\n                        tickLine.setStyle({\n                            stroke: getColor((i + j / subSplitNumber) / splitNumber)\n                        });\n                    }\n\n                    group.add(tickLine);\n                    angle += subStep;\n                }\n                angle -= subStep;\n            }\n            else {\n                angle += step;\n            }\n        }\n    },\n\n    _renderPointer: function (\n        seriesModel, ecModel, api, getColor, posInfo,\n        startAngle, endAngle, clockwise\n    ) {\n\n        var group = this.group;\n        var oldData = this._data;\n\n        if (!seriesModel.get('pointer.show')) {\n            // Remove old element\n            oldData && oldData.eachItemGraphicEl(function (el) {\n                group.remove(el);\n            });\n            return;\n        }\n\n        var valueExtent = [+seriesModel.get('min'), +seriesModel.get('max')];\n        var angleExtent = [startAngle, endAngle];\n\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n\n        data.diff(oldData)\n            .add(function (idx) {\n                var pointer = new PointerPath({\n                    shape: {\n                        angle: startAngle\n                    }\n                });\n\n                initProps(pointer, {\n                    shape: {\n                        angle: linearMap(data.get(valueDim, idx), valueExtent, angleExtent, true)\n                    }\n                }, seriesModel);\n\n                group.add(pointer);\n                data.setItemGraphicEl(idx, pointer);\n            })\n            .update(function (newIdx, oldIdx) {\n                var pointer = oldData.getItemGraphicEl(oldIdx);\n\n                updateProps(pointer, {\n                    shape: {\n                        angle: linearMap(data.get(valueDim, newIdx), valueExtent, angleExtent, true)\n                    }\n                }, seriesModel);\n\n                group.add(pointer);\n                data.setItemGraphicEl(newIdx, pointer);\n            })\n            .remove(function (idx) {\n                var pointer = oldData.getItemGraphicEl(idx);\n                group.remove(pointer);\n            })\n            .execute();\n\n        data.eachItemGraphicEl(function (pointer, idx) {\n            var itemModel = data.getItemModel(idx);\n            var pointerModel = itemModel.getModel('pointer');\n\n            pointer.setShape({\n                x: posInfo.cx,\n                y: posInfo.cy,\n                width: parsePercent$1(\n                    pointerModel.get('width'), posInfo.r\n                ),\n                r: parsePercent$1(pointerModel.get('length'), posInfo.r)\n            });\n\n            pointer.useStyle(itemModel.getModel('itemStyle').getItemStyle());\n\n            if (pointer.style.fill === 'auto') {\n                pointer.setStyle('fill', getColor(\n                    linearMap(data.get(valueDim, idx), valueExtent, [0, 1], true)\n                ));\n            }\n\n            setHoverStyle(\n                pointer, itemModel.getModel('emphasis.itemStyle').getItemStyle()\n            );\n        });\n\n        this._data = data;\n    },\n\n    _renderTitle: function (\n        seriesModel, ecModel, api, getColor, posInfo\n    ) {\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n        var titleModel = seriesModel.getModel('title');\n        if (titleModel.get('show')) {\n            var offsetCenter = titleModel.get('offsetCenter');\n            var x = posInfo.cx + parsePercent$1(offsetCenter[0], posInfo.r);\n            var y = posInfo.cy + parsePercent$1(offsetCenter[1], posInfo.r);\n\n            var minVal = +seriesModel.get('min');\n            var maxVal = +seriesModel.get('max');\n            var value = seriesModel.getData().get(valueDim, 0);\n            var autoColor = getColor(\n                linearMap(value, [minVal, maxVal], [0, 1], true)\n            );\n\n            this.group.add(new Text({\n                silent: true,\n                style: setTextStyle({}, titleModel, {\n                    x: x,\n                    y: y,\n                    // FIXME First data name ?\n                    text: data.getName(0),\n                    textAlign: 'center',\n                    textVerticalAlign: 'middle'\n                }, {autoColor: autoColor, forceRich: true})\n            }));\n        }\n    },\n\n    _renderDetail: function (\n        seriesModel, ecModel, api, getColor, posInfo\n    ) {\n        var detailModel = seriesModel.getModel('detail');\n        var minVal = +seriesModel.get('min');\n        var maxVal = +seriesModel.get('max');\n        if (detailModel.get('show')) {\n            var offsetCenter = detailModel.get('offsetCenter');\n            var x = posInfo.cx + parsePercent$1(offsetCenter[0], posInfo.r);\n            var y = posInfo.cy + parsePercent$1(offsetCenter[1], posInfo.r);\n            var width = parsePercent$1(detailModel.get('width'), posInfo.r);\n            var height = parsePercent$1(detailModel.get('height'), posInfo.r);\n            var data = seriesModel.getData();\n            var value = data.get(data.mapDimension('value'), 0);\n            var autoColor = getColor(\n                linearMap(value, [minVal, maxVal], [0, 1], true)\n            );\n\n            this.group.add(new Text({\n                silent: true,\n                style: setTextStyle({}, detailModel, {\n                    x: x,\n                    y: y,\n                    text: formatLabel(\n                        // FIXME First data name ?\n                        value, detailModel.get('formatter')\n                    ),\n                    textWidth: isNaN(width) ? null : width,\n                    textHeight: isNaN(height) ? null : height,\n                    textAlign: 'center',\n                    textVerticalAlign: 'middle'\n                }, {autoColor: autoColor, forceRich: true})\n            }));\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar FunnelSeries = extendSeriesModel({\n\n    type: 'series.funnel',\n\n    init: function (option) {\n        FunnelSeries.superApply(this, 'init', arguments);\n\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n        // Extend labelLine emphasis\n        this._defaultLabelLine(option);\n    },\n\n    getInitialData: function (option, ecModel) {\n        return createListSimply(this, ['value']);\n    },\n\n    _defaultLabelLine: function (option) {\n        // Extend labelLine emphasis\n        defaultEmphasis(option, 'labelLine', ['show']);\n\n        var labelLineNormalOpt = option.labelLine;\n        var labelLineEmphasisOpt = option.emphasis.labelLine;\n        // Not show label line if `label.normal.show = false`\n        labelLineNormalOpt.show = labelLineNormalOpt.show\n            && option.label.show;\n        labelLineEmphasisOpt.show = labelLineEmphasisOpt.show\n            && option.emphasis.label.show;\n    },\n\n    // Overwrite\n    getDataParams: function (dataIndex) {\n        var data = this.getData();\n        var params = FunnelSeries.superCall(this, 'getDataParams', dataIndex);\n        var valueDim = data.mapDimension('value');\n        var sum = data.getSum(valueDim);\n        // Percent is 0 if sum is 0\n        params.percent = !sum ? 0 : +(data.get(valueDim, dataIndex) / sum * 100).toFixed(2);\n\n        params.$vars.push('percent');\n        return params;\n    },\n\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n        legendHoverLink: true,\n        left: 80,\n        top: 60,\n        right: 80,\n        bottom: 60,\n        // width: {totalWidth} - left - right,\n        // height: {totalHeight} - top - bottom,\n\n        // 默认取数据最小最大值\n        // min: 0,\n        // max: 100,\n        minSize: '0%',\n        maxSize: '100%',\n        sort: 'descending', // 'ascending', 'descending'\n        gap: 0,\n        funnelAlign: 'center',\n        label: {\n            show: true,\n            position: 'outer'\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n        },\n        labelLine: {\n            show: true,\n            length: 20,\n            lineStyle: {\n                // color: 各异,\n                width: 1,\n                type: 'solid'\n            }\n        },\n        itemStyle: {\n            // color: 各异,\n            borderColor: '#fff',\n            borderWidth: 1\n        },\n        emphasis: {\n            label: {\n                show: true\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Piece of pie including Sector, Label, LabelLine\n * @constructor\n * @extends {module:zrender/graphic/Group}\n */\nfunction FunnelPiece(data, idx) {\n\n    Group.call(this);\n\n    var polygon = new Polygon();\n    var labelLine = new Polyline();\n    var text = new Text();\n    this.add(polygon);\n    this.add(labelLine);\n    this.add(text);\n\n    this.updateData(data, idx, true);\n\n    // Hover to change label and labelLine\n    function onEmphasis() {\n        labelLine.ignore = labelLine.hoverIgnore;\n        text.ignore = text.hoverIgnore;\n    }\n    function onNormal() {\n        labelLine.ignore = labelLine.normalIgnore;\n        text.ignore = text.normalIgnore;\n    }\n    this.on('emphasis', onEmphasis)\n        .on('normal', onNormal)\n        .on('mouseover', onEmphasis)\n        .on('mouseout', onNormal);\n}\n\nvar funnelPieceProto = FunnelPiece.prototype;\n\nvar opacityAccessPath = ['itemStyle', 'opacity'];\nfunnelPieceProto.updateData = function (data, idx, firstCreate) {\n\n    var polygon = this.childAt(0);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var opacity = data.getItemModel(idx).get(opacityAccessPath);\n    opacity = opacity == null ? 1 : opacity;\n\n    // Reset style\n    polygon.useStyle({});\n\n    if (firstCreate) {\n        polygon.setShape({\n            points: layout.points\n        });\n        polygon.setStyle({opacity: 0});\n        initProps(polygon, {\n            style: {\n                opacity: opacity\n            }\n        }, seriesModel, idx);\n    }\n    else {\n        updateProps(polygon, {\n            style: {\n                opacity: opacity\n            },\n            shape: {\n                points: layout.points\n            }\n        }, seriesModel, idx);\n    }\n\n    // Update common style\n    var itemStyleModel = itemModel.getModel('itemStyle');\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    polygon.setStyle(\n        defaults(\n            {\n                lineJoin: 'round',\n                fill: visualColor\n            },\n            itemStyleModel.getItemStyle(['opacity'])\n        )\n    );\n    polygon.hoverStyle = itemStyleModel.getModel('emphasis').getItemStyle();\n\n    this._updateLabel(data, idx);\n\n    setHoverStyle(this);\n};\n\nfunnelPieceProto._updateLabel = function (data, idx) {\n\n    var labelLine = this.childAt(1);\n    var labelText = this.childAt(2);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var labelLayout = layout.label;\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    updateProps(labelLine, {\n        shape: {\n            points: labelLayout.linePoints || labelLayout.linePoints\n        }\n    }, seriesModel, idx);\n\n    updateProps(labelText, {\n        style: {\n            x: labelLayout.x,\n            y: labelLayout.y\n        }\n    }, seriesModel, idx);\n    labelText.attr({\n        rotation: labelLayout.rotation,\n        origin: [labelLayout.x, labelLayout.y],\n        z2: 10\n    });\n\n    var labelModel = itemModel.getModel('label');\n    var labelHoverModel = itemModel.getModel('emphasis.label');\n    var labelLineModel = itemModel.getModel('labelLine');\n    var labelLineHoverModel = itemModel.getModel('emphasis.labelLine');\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    setLabelStyle(\n        labelText.style, labelText.hoverStyle = {}, labelModel, labelHoverModel,\n        {\n            labelFetcher: data.hostModel,\n            labelDataIndex: idx,\n            defaultText: data.getName(idx),\n            autoColor: visualColor,\n            useInsideStyle: !!labelLayout.inside\n        },\n        {\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.verticalAlign\n        }\n    );\n\n    labelText.ignore = labelText.normalIgnore = !labelModel.get('show');\n    labelText.hoverIgnore = !labelHoverModel.get('show');\n\n    labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show');\n    labelLine.hoverIgnore = !labelLineHoverModel.get('show');\n\n    // Default use item visual color\n    labelLine.setStyle({\n        stroke: visualColor\n    });\n    labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());\n\n    labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();\n};\n\ninherits(FunnelPiece, Group);\n\n\nvar FunnelView = Chart.extend({\n\n    type: 'funnel',\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        var group = this.group;\n\n        data.diff(oldData)\n            .add(function (idx) {\n                var funnelPiece = new FunnelPiece(data, idx);\n\n                data.setItemGraphicEl(idx, funnelPiece);\n\n                group.add(funnelPiece);\n            })\n            .update(function (newIdx, oldIdx) {\n                var piePiece = oldData.getItemGraphicEl(oldIdx);\n\n                piePiece.updateData(data, newIdx);\n\n                group.add(piePiece);\n                data.setItemGraphicEl(newIdx, piePiece);\n            })\n            .remove(function (idx) {\n                var piePiece = oldData.getItemGraphicEl(idx);\n                group.remove(piePiece);\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    remove: function () {\n        this.group.removeAll();\n        this._data = null;\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction getViewRect$2(seriesModel, api) {\n    return getLayoutRect(\n        seriesModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        }\n    );\n}\n\nfunction getSortedIndices(data, sort) {\n    var valueDim = data.mapDimension('value');\n    var valueArr = data.mapArray(valueDim, function (val) {\n        return val;\n    });\n    var indices = [];\n    var isAscending = sort === 'ascending';\n    for (var i = 0, len = data.count(); i < len; i++) {\n        indices[i] = i;\n    }\n\n    // Add custom sortable function & none sortable opetion by \"options.sort\"\n    if (typeof sort === 'function') {\n        indices.sort(sort);\n    }\n    else if (sort !== 'none') {\n        indices.sort(function (a, b) {\n            return isAscending ? valueArr[a] - valueArr[b] : valueArr[b] - valueArr[a];\n        });\n    }\n    return indices;\n}\n\nfunction labelLayout$1(data) {\n    data.each(function (idx) {\n        var itemModel = data.getItemModel(idx);\n        var labelModel = itemModel.getModel('label');\n        var labelPosition = labelModel.get('position');\n\n        var labelLineModel = itemModel.getModel('labelLine');\n\n        var layout = data.getItemLayout(idx);\n        var points = layout.points;\n\n        var isLabelInside = labelPosition === 'inner'\n            || labelPosition === 'inside' || labelPosition === 'center';\n\n        var textAlign;\n        var textX;\n        var textY;\n        var linePoints;\n\n        if (isLabelInside) {\n            textX = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4;\n            textY = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4;\n            textAlign = 'center';\n            linePoints = [\n                [textX, textY], [textX, textY]\n            ];\n        }\n        else {\n            var x1;\n            var y1;\n            var x2;\n            var labelLineLen = labelLineModel.get('length');\n            if (labelPosition === 'left') {\n                // Left side\n                x1 = (points[3][0] + points[0][0]) / 2;\n                y1 = (points[3][1] + points[0][1]) / 2;\n                x2 = x1 - labelLineLen;\n                textX = x2 - 5;\n                textAlign = 'right';\n            }\n            else {\n                // Right side\n                x1 = (points[1][0] + points[2][0]) / 2;\n                y1 = (points[1][1] + points[2][1]) / 2;\n                x2 = x1 + labelLineLen;\n                textX = x2 + 5;\n                textAlign = 'left';\n            }\n            var y2 = y1;\n\n            linePoints = [[x1, y1], [x2, y2]];\n            textY = y2;\n        }\n\n        layout.label = {\n            linePoints: linePoints,\n            x: textX,\n            y: textY,\n            verticalAlign: 'middle',\n            textAlign: textAlign,\n            inside: isLabelInside\n        };\n    });\n}\n\nvar funnelLayout = function (ecModel, api, payload) {\n    ecModel.eachSeriesByType('funnel', function (seriesModel) {\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n        var sort = seriesModel.get('sort');\n        var viewRect = getViewRect$2(seriesModel, api);\n        var indices = getSortedIndices(data, sort);\n\n        var sizeExtent = [\n            parsePercent$1(seriesModel.get('minSize'), viewRect.width),\n            parsePercent$1(seriesModel.get('maxSize'), viewRect.width)\n        ];\n        var dataExtent = data.getDataExtent(valueDim);\n        var min = seriesModel.get('min');\n        var max = seriesModel.get('max');\n        if (min == null) {\n            min = Math.min(dataExtent[0], 0);\n        }\n        if (max == null) {\n            max = dataExtent[1];\n        }\n\n        var funnelAlign = seriesModel.get('funnelAlign');\n        var gap = seriesModel.get('gap');\n        var itemHeight = (viewRect.height - gap * (data.count() - 1)) / data.count();\n\n        var y = viewRect.y;\n\n        var getLinePoints = function (idx, offY) {\n            // End point index is data.count() and we assign it 0\n            var val = data.get(valueDim, idx) || 0;\n            var itemWidth = linearMap(val, [min, max], sizeExtent, true);\n            var x0;\n            switch (funnelAlign) {\n                case 'left':\n                    x0 = viewRect.x;\n                    break;\n                case 'center':\n                    x0 = viewRect.x + (viewRect.width - itemWidth) / 2;\n                    break;\n                case 'right':\n                    x0 = viewRect.x + viewRect.width - itemWidth;\n                    break;\n            }\n            return [\n                [x0, offY],\n                [x0 + itemWidth, offY]\n            ];\n        };\n\n        if (sort === 'ascending') {\n            // From bottom to top\n            itemHeight = -itemHeight;\n            gap = -gap;\n            y += viewRect.height;\n            indices = indices.reverse();\n        }\n\n        for (var i = 0; i < indices.length; i++) {\n            var idx = indices[i];\n            var nextIdx = indices[i + 1];\n\n            var itemModel = data.getItemModel(idx);\n            var height = itemModel.get('itemStyle.height');\n            if (height == null) {\n                height = itemHeight;\n            }\n            else {\n                height = parsePercent$1(height, viewRect.height);\n                if (sort === 'ascending') {\n                    height = -height;\n                }\n            }\n\n            var start = getLinePoints(idx, y);\n            var end = getLinePoints(nextIdx, y + height);\n\n            y += height + gap;\n\n            data.setItemLayout(idx, {\n                points: start.concat(end.slice().reverse())\n            });\n        }\n\n        labelLayout$1(data);\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(dataColor('funnel'));\nregisterLayout(funnelLayout);\nregisterProcessor(dataFilter('funnel'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar parallelPreprocessor = function (option) {\n    createParallelIfNeeded(option);\n    mergeAxisOptionFromParallel(option);\n};\n\n/**\n * Create a parallel coordinate if not exists.\n * @inner\n */\nfunction createParallelIfNeeded(option) {\n    if (option.parallel) {\n        return;\n    }\n\n    var hasParallelSeries = false;\n\n    each$1(option.series, function (seriesOpt) {\n        if (seriesOpt && seriesOpt.type === 'parallel') {\n            hasParallelSeries = true;\n        }\n    });\n\n    if (hasParallelSeries) {\n        option.parallel = [{}];\n    }\n}\n\n/**\n * Merge aixs definition from parallel option (if exists) to axis option.\n * @inner\n */\nfunction mergeAxisOptionFromParallel(option) {\n    var axes = normalizeToArray(option.parallelAxis);\n\n    each$1(axes, function (axisOption) {\n        if (!isObject$1(axisOption)) {\n            return;\n        }\n\n        var parallelIndex = axisOption.parallelIndex || 0;\n        var parallelOption = normalizeToArray(option.parallel)[parallelIndex];\n\n        if (parallelOption && parallelOption.parallelAxisDefault) {\n            merge(axisOption, parallelOption.parallelAxisDefault, false);\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @constructor module:echarts/coord/parallel/ParallelAxis\n * @extends {module:echarts/coord/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n */\nvar ParallelAxis = function (dim, scale, coordExtent, axisType, axisIndex) {\n\n    Axis.call(this, dim, scale, coordExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * @type {number}\n     * @readOnly\n     */\n    this.axisIndex = axisIndex;\n};\n\nParallelAxis.prototype = {\n\n    constructor: ParallelAxis,\n\n    /**\n     * Axis model\n     * @param {module:echarts/coord/parallel/AxisModel}\n     */\n    model: null,\n\n    /**\n     * @override\n     */\n    isHorizontal: function () {\n        return this.coordinateSystem.getModel().get('layout') !== 'horizontal';\n    }\n\n};\n\ninherits(ParallelAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Calculate slider move result.\n * Usage:\n * (1) If both handle0 and handle1 are needed to be moved, set minSpan the same as\n * maxSpan and the same as `Math.abs(handleEnd[1] - handleEnds[0])`.\n * (2) If handle0 is forbidden to cross handle1, set minSpan as `0`.\n *\n * @param {number} delta Move length.\n * @param {Array.<number>} handleEnds handleEnds[0] can be bigger then handleEnds[1].\n *              handleEnds will be modified in this method.\n * @param {Array.<number>} extent handleEnds is restricted by extent.\n *              extent[0] should less or equals than extent[1].\n * @param {number|string} handleIndex Can be 'all', means that both move the two handleEnds,\n *              where the input minSpan and maxSpan will not work.\n * @param {number} [minSpan] The range of dataZoom can not be smaller than that.\n *              If not set, handle0 and cross handle1. If set as a non-negative\n *              number (including `0`), handles will push each other when reaching\n *              the minSpan.\n * @param {number} [maxSpan] The range of dataZoom can not be larger than that.\n * @return {Array.<number>} The input handleEnds.\n */\nvar sliderMove = function (delta, handleEnds, extent, handleIndex, minSpan, maxSpan) {\n    // Normalize firstly.\n    handleEnds[0] = restrict$1(handleEnds[0], extent);\n    handleEnds[1] = restrict$1(handleEnds[1], extent);\n\n    delta = delta || 0;\n\n    var extentSpan = extent[1] - extent[0];\n\n    // Notice maxSpan and minSpan can be null/undefined.\n    if (minSpan != null) {\n        minSpan = restrict$1(minSpan, [0, extentSpan]);\n    }\n    if (maxSpan != null) {\n        maxSpan = Math.max(maxSpan, minSpan != null ? minSpan : 0);\n    }\n    if (handleIndex === 'all') {\n        minSpan = maxSpan = Math.abs(handleEnds[1] - handleEnds[0]);\n        handleIndex = 0;\n    }\n\n    var originalDistSign = getSpanSign(handleEnds, handleIndex);\n\n    handleEnds[handleIndex] += delta;\n\n    // Restrict in extent.\n    var extentMinSpan = minSpan || 0;\n    var realExtent = extent.slice();\n    originalDistSign.sign < 0 ? (realExtent[0] += extentMinSpan) : (realExtent[1] -= extentMinSpan);\n    handleEnds[handleIndex] = restrict$1(handleEnds[handleIndex], realExtent);\n\n    // Expand span.\n    var currDistSign = getSpanSign(handleEnds, handleIndex);\n    if (minSpan != null && (\n        currDistSign.sign !== originalDistSign.sign || currDistSign.span < minSpan\n    )) {\n        // If minSpan exists, 'cross' is forbinden.\n        handleEnds[1 - handleIndex] = handleEnds[handleIndex] + originalDistSign.sign * minSpan;\n    }\n\n    // Shrink span.\n    var currDistSign = getSpanSign(handleEnds, handleIndex);\n    if (maxSpan != null && currDistSign.span > maxSpan) {\n        handleEnds[1 - handleIndex] = handleEnds[handleIndex] + currDistSign.sign * maxSpan;\n    }\n\n    return handleEnds;\n};\n\nfunction getSpanSign(handleEnds, handleIndex) {\n    var dist = handleEnds[handleIndex] - handleEnds[1 - handleIndex];\n    // If `handleEnds[0] === handleEnds[1]`, always believe that handleEnd[0]\n    // is at left of handleEnds[1] for non-cross case.\n    return {span: Math.abs(dist), sign: dist > 0 ? -1 : dist < 0 ? 1 : handleIndex ? -1 : 1};\n}\n\nfunction restrict$1(value, extend) {\n    return Math.min(extend[1], Math.max(extend[0], value));\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Parallel Coordinates\n * <https://en.wikipedia.org/wiki/Parallel_coordinates>\n */\n\nvar each$11 = each$1;\nvar mathMin$5 = Math.min;\nvar mathMax$5 = Math.max;\nvar mathFloor$2 = Math.floor;\nvar mathCeil$2 = Math.ceil;\nvar round$3 = round$2;\n\nvar PI$3 = Math.PI;\n\nfunction Parallel(parallelModel, ecModel, api) {\n\n    /**\n     * key: dimension\n     * @type {Object.<string, module:echarts/coord/parallel/Axis>}\n     * @private\n     */\n    this._axesMap = createHashMap();\n\n    /**\n     * key: dimension\n     * value: {position: [], rotation, }\n     * @type {Object.<string, Object>}\n     * @private\n     */\n    this._axesLayout = {};\n\n    /**\n     * Always follow axis order.\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    this.dimensions = parallelModel.dimensions;\n\n    /**\n     * @type {module:zrender/core/BoundingRect}\n     */\n    this._rect;\n\n    /**\n     * @type {module:echarts/coord/parallel/ParallelModel}\n     */\n    this._model = parallelModel;\n\n    this._init(parallelModel, ecModel, api);\n}\n\nParallel.prototype = {\n\n    type: 'parallel',\n\n    constructor: Parallel,\n\n    /**\n     * Initialize cartesian coordinate systems\n     * @private\n     */\n    _init: function (parallelModel, ecModel, api) {\n\n        var dimensions = parallelModel.dimensions;\n        var parallelAxisIndex = parallelModel.parallelAxisIndex;\n\n        each$11(dimensions, function (dim, idx) {\n\n            var axisIndex = parallelAxisIndex[idx];\n            var axisModel = ecModel.getComponent('parallelAxis', axisIndex);\n\n            var axis = this._axesMap.set(dim, new ParallelAxis(\n                dim,\n                createScaleByModel(axisModel),\n                [0, 0],\n                axisModel.get('type'),\n                axisIndex\n            ));\n\n            var isCategory = axis.type === 'category';\n            axis.onBand = isCategory && axisModel.get('boundaryGap');\n            axis.inverse = axisModel.get('inverse');\n\n            // Injection\n            axisModel.axis = axis;\n            axis.model = axisModel;\n            axis.coordinateSystem = axisModel.coordinateSystem = this;\n\n        }, this);\n    },\n\n    /**\n     * Update axis scale after data processed\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    update: function (ecModel, api) {\n        this._updateAxesFromSeries(this._model, ecModel);\n    },\n\n    /**\n     * @override\n     */\n    containPoint: function (point) {\n        var layoutInfo = this._makeLayoutInfo();\n        var axisBase = layoutInfo.axisBase;\n        var layoutBase = layoutInfo.layoutBase;\n        var pixelDimIndex = layoutInfo.pixelDimIndex;\n        var pAxis = point[1 - pixelDimIndex];\n        var pLayout = point[pixelDimIndex];\n\n        return pAxis >= axisBase\n            && pAxis <= axisBase + layoutInfo.axisLength\n            && pLayout >= layoutBase\n            && pLayout <= layoutBase + layoutInfo.layoutLength;\n    },\n\n    getModel: function () {\n        return this._model;\n    },\n\n    /**\n     * Update properties from series\n     * @private\n     */\n    _updateAxesFromSeries: function (parallelModel, ecModel) {\n        ecModel.eachSeries(function (seriesModel) {\n\n            if (!parallelModel.contains(seriesModel, ecModel)) {\n                return;\n            }\n\n            var data = seriesModel.getData();\n\n            each$11(this.dimensions, function (dim) {\n                var axis = this._axesMap.get(dim);\n                axis.scale.unionExtentFromData(data, data.mapDimension(dim));\n                niceScaleExtent(axis.scale, axis.model);\n            }, this);\n        }, this);\n    },\n\n    /**\n     * Resize the parallel coordinate system.\n     * @param {module:echarts/coord/parallel/ParallelModel} parallelModel\n     * @param {module:echarts/ExtensionAPI} api\n     */\n    resize: function (parallelModel, api) {\n        this._rect = getLayoutRect(\n            parallelModel.getBoxLayoutParams(),\n            {\n                width: api.getWidth(),\n                height: api.getHeight()\n            }\n        );\n\n        this._layoutAxes();\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getRect: function () {\n        return this._rect;\n    },\n\n    /**\n     * @private\n     */\n    _makeLayoutInfo: function () {\n        var parallelModel = this._model;\n        var rect = this._rect;\n        var xy = ['x', 'y'];\n        var wh = ['width', 'height'];\n        var layout = parallelModel.get('layout');\n        var pixelDimIndex = layout === 'horizontal' ? 0 : 1;\n        var layoutLength = rect[wh[pixelDimIndex]];\n        var layoutExtent = [0, layoutLength];\n        var axisCount = this.dimensions.length;\n\n        var axisExpandWidth = restrict(parallelModel.get('axisExpandWidth'), layoutExtent);\n        var axisExpandCount = restrict(parallelModel.get('axisExpandCount') || 0, [0, axisCount]);\n        var axisExpandable = parallelModel.get('axisExpandable')\n            && axisCount > 3\n            && axisCount > axisExpandCount\n            && axisExpandCount > 1\n            && axisExpandWidth > 0\n            && layoutLength > 0;\n\n        // `axisExpandWindow` is According to the coordinates of [0, axisExpandLength],\n        // for sake of consider the case that axisCollapseWidth is 0 (when screen is narrow),\n        // where collapsed axes should be overlapped.\n        var axisExpandWindow = parallelModel.get('axisExpandWindow');\n        var winSize;\n        if (!axisExpandWindow) {\n            winSize = restrict(axisExpandWidth * (axisExpandCount - 1), layoutExtent);\n            var axisExpandCenter = parallelModel.get('axisExpandCenter') || mathFloor$2(axisCount / 2);\n            axisExpandWindow = [axisExpandWidth * axisExpandCenter - winSize / 2];\n            axisExpandWindow[1] = axisExpandWindow[0] + winSize;\n        }\n        else {\n                winSize = restrict(axisExpandWindow[1] - axisExpandWindow[0], layoutExtent);\n                axisExpandWindow[1] = axisExpandWindow[0] + winSize;\n        }\n\n        var axisCollapseWidth = (layoutLength - winSize) / (axisCount - axisExpandCount);\n        // Avoid axisCollapseWidth is too small.\n        axisCollapseWidth < 3 && (axisCollapseWidth = 0);\n\n        // Find the first and last indices > ewin[0] and < ewin[1].\n        var winInnerIndices = [\n            mathFloor$2(round$3(axisExpandWindow[0] / axisExpandWidth, 1)) + 1,\n            mathCeil$2(round$3(axisExpandWindow[1] / axisExpandWidth, 1)) - 1\n        ];\n\n        // Pos in ec coordinates.\n        var axisExpandWindow0Pos = axisCollapseWidth / axisExpandWidth * axisExpandWindow[0];\n\n        return {\n            layout: layout,\n            pixelDimIndex: pixelDimIndex,\n            layoutBase: rect[xy[pixelDimIndex]],\n            layoutLength: layoutLength,\n            axisBase: rect[xy[1 - pixelDimIndex]],\n            axisLength: rect[wh[1 - pixelDimIndex]],\n            axisExpandable: axisExpandable,\n            axisExpandWidth: axisExpandWidth,\n            axisCollapseWidth: axisCollapseWidth,\n            axisExpandWindow: axisExpandWindow,\n            axisCount: axisCount,\n            winInnerIndices: winInnerIndices,\n            axisExpandWindow0Pos: axisExpandWindow0Pos\n        };\n    },\n\n    /**\n     * @private\n     */\n    _layoutAxes: function () {\n        var rect = this._rect;\n        var axes = this._axesMap;\n        var dimensions = this.dimensions;\n        var layoutInfo = this._makeLayoutInfo();\n        var layout = layoutInfo.layout;\n\n        axes.each(function (axis) {\n            var axisExtent = [0, layoutInfo.axisLength];\n            var idx = axis.inverse ? 1 : 0;\n            axis.setExtent(axisExtent[idx], axisExtent[1 - idx]);\n        });\n\n        each$11(dimensions, function (dim, idx) {\n            var posInfo = (layoutInfo.axisExpandable\n                ? layoutAxisWithExpand : layoutAxisWithoutExpand\n            )(idx, layoutInfo);\n\n            var positionTable = {\n                horizontal: {\n                    x: posInfo.position,\n                    y: layoutInfo.axisLength\n                },\n                vertical: {\n                    x: 0,\n                    y: posInfo.position\n                }\n            };\n            var rotationTable = {\n                horizontal: PI$3 / 2,\n                vertical: 0\n            };\n\n            var position = [\n                positionTable[layout].x + rect.x,\n                positionTable[layout].y + rect.y\n            ];\n\n            var rotation = rotationTable[layout];\n            var transform = create$1();\n            rotate(transform, transform, rotation);\n            translate(transform, transform, position);\n\n            // TODO\n            // tick等排布信息。\n\n            // TODO\n            // 根据axis order 更新 dimensions顺序。\n\n            this._axesLayout[dim] = {\n                position: position,\n                rotation: rotation,\n                transform: transform,\n                axisNameAvailableWidth: posInfo.axisNameAvailableWidth,\n                axisLabelShow: posInfo.axisLabelShow,\n                nameTruncateMaxWidth: posInfo.nameTruncateMaxWidth,\n                tickDirection: 1,\n                labelDirection: 1\n            };\n        }, this);\n    },\n\n    /**\n     * Get axis by dim.\n     * @param {string} dim\n     * @return {module:echarts/coord/parallel/ParallelAxis} [description]\n     */\n    getAxis: function (dim) {\n        return this._axesMap.get(dim);\n    },\n\n    /**\n     * Convert a dim value of a single item of series data to Point.\n     * @param {*} value\n     * @param {string} dim\n     * @return {Array}\n     */\n    dataToPoint: function (value, dim) {\n        return this.axisCoordToPoint(\n            this._axesMap.get(dim).dataToCoord(value),\n            dim\n        );\n    },\n\n    /**\n     * Travel data for one time, get activeState of each data item.\n     * @param {module:echarts/data/List} data\n     * @param {Functio} cb param: {string} activeState 'active' or 'inactive' or 'normal'\n     *                            {number} dataIndex\n     * @param {number} [start=0] the start dataIndex that travel from.\n     * @param {number} [end=data.count()] the next dataIndex of the last dataIndex will be travel.\n     */\n    eachActiveState: function (data, callback, start, end) {\n        start == null && (start = 0);\n        end == null && (end = data.count());\n\n        var axesMap = this._axesMap;\n        var dimensions = this.dimensions;\n        var dataDimensions = [];\n        var axisModels = [];\n\n        each$1(dimensions, function (axisDim) {\n            dataDimensions.push(data.mapDimension(axisDim));\n            axisModels.push(axesMap.get(axisDim).model);\n        });\n\n        var hasActiveSet = this.hasAxisBrushed();\n\n        for (var dataIndex = start; dataIndex < end; dataIndex++) {\n            var activeState;\n\n            if (!hasActiveSet) {\n                activeState = 'normal';\n            }\n            else {\n                activeState = 'active';\n                var values = data.getValues(dataDimensions, dataIndex);\n                for (var j = 0, lenj = dimensions.length; j < lenj; j++) {\n                    var state = axisModels[j].getActiveState(values[j]);\n\n                    if (state === 'inactive') {\n                        activeState = 'inactive';\n                        break;\n                    }\n                }\n            }\n\n            callback(activeState, dataIndex);\n        }\n    },\n\n    /**\n     * Whether has any activeSet.\n     * @return {boolean}\n     */\n    hasAxisBrushed: function () {\n        var dimensions = this.dimensions;\n        var axesMap = this._axesMap;\n        var hasActiveSet = false;\n\n        for (var j = 0, lenj = dimensions.length; j < lenj; j++) {\n            if (axesMap.get(dimensions[j]).model.getActiveState() !== 'normal') {\n                hasActiveSet = true;\n            }\n        }\n\n        return hasActiveSet;\n    },\n\n    /**\n     * Convert coords of each axis to Point.\n     *  Return point. For example: [10, 20]\n     * @param {Array.<number>} coords\n     * @param {string} dim\n     * @return {Array.<number>}\n     */\n    axisCoordToPoint: function (coord, dim) {\n        var axisLayout = this._axesLayout[dim];\n        return applyTransform$1([coord, 0], axisLayout.transform);\n    },\n\n    /**\n     * Get axis layout.\n     */\n    getAxisLayout: function (dim) {\n        return clone(this._axesLayout[dim]);\n    },\n\n    /**\n     * @param {Array.<number>} point\n     * @return {Object} {axisExpandWindow, delta, behavior: 'jump' | 'slide' | 'none'}.\n     */\n    getSlidedAxisExpandWindow: function (point) {\n        var layoutInfo = this._makeLayoutInfo();\n        var pixelDimIndex = layoutInfo.pixelDimIndex;\n        var axisExpandWindow = layoutInfo.axisExpandWindow.slice();\n        var winSize = axisExpandWindow[1] - axisExpandWindow[0];\n        var extent = [0, layoutInfo.axisExpandWidth * (layoutInfo.axisCount - 1)];\n\n        // Out of the area of coordinate system.\n        if (!this.containPoint(point)) {\n            return {behavior: 'none', axisExpandWindow: axisExpandWindow};\n        }\n\n        // Conver the point from global to expand coordinates.\n        var pointCoord = point[pixelDimIndex] - layoutInfo.layoutBase - layoutInfo.axisExpandWindow0Pos;\n\n        // For dragging operation convenience, the window should not be\n        // slided when mouse is the center area of the window.\n        var delta;\n        var behavior = 'slide';\n        var axisCollapseWidth = layoutInfo.axisCollapseWidth;\n        var triggerArea = this._model.get('axisExpandSlideTriggerArea');\n        // But consider touch device, jump is necessary.\n        var useJump = triggerArea[0] != null;\n\n        if (axisCollapseWidth) {\n            if (useJump && axisCollapseWidth && pointCoord < winSize * triggerArea[0]) {\n                behavior = 'jump';\n                delta = pointCoord - winSize * triggerArea[2];\n            }\n            else if (useJump && axisCollapseWidth && pointCoord > winSize * (1 - triggerArea[0])) {\n                behavior = 'jump';\n                delta = pointCoord - winSize * (1 - triggerArea[2]);\n            }\n            else {\n                (delta = pointCoord - winSize * triggerArea[1]) >= 0\n                    && (delta = pointCoord - winSize * (1 - triggerArea[1])) <= 0\n                    && (delta = 0);\n            }\n            delta *= layoutInfo.axisExpandWidth / axisCollapseWidth;\n            delta\n                ? sliderMove(delta, axisExpandWindow, extent, 'all')\n                // Avoid nonsense triger on mousemove.\n                : (behavior = 'none');\n        }\n        // When screen is too narrow, make it visible and slidable, although it is hard to interact.\n        else {\n            var winSize = axisExpandWindow[1] - axisExpandWindow[0];\n            var pos = extent[1] * pointCoord / winSize;\n            axisExpandWindow = [mathMax$5(0, pos - winSize / 2)];\n            axisExpandWindow[1] = mathMin$5(extent[1], axisExpandWindow[0] + winSize);\n            axisExpandWindow[0] = axisExpandWindow[1] - winSize;\n        }\n\n        return {\n            axisExpandWindow: axisExpandWindow,\n            behavior: behavior\n        };\n    }\n};\n\nfunction restrict(len, extent) {\n    return mathMin$5(mathMax$5(len, extent[0]), extent[1]);\n}\n\nfunction layoutAxisWithoutExpand(axisIndex, layoutInfo) {\n    var step = layoutInfo.layoutLength / (layoutInfo.axisCount - 1);\n    return {\n        position: step * axisIndex,\n        axisNameAvailableWidth: step,\n        axisLabelShow: true\n    };\n}\n\nfunction layoutAxisWithExpand(axisIndex, layoutInfo) {\n    var layoutLength = layoutInfo.layoutLength;\n    var axisExpandWidth = layoutInfo.axisExpandWidth;\n    var axisCount = layoutInfo.axisCount;\n    var axisCollapseWidth = layoutInfo.axisCollapseWidth;\n    var winInnerIndices = layoutInfo.winInnerIndices;\n\n    var position;\n    var axisNameAvailableWidth = axisCollapseWidth;\n    var axisLabelShow = false;\n    var nameTruncateMaxWidth;\n\n    if (axisIndex < winInnerIndices[0]) {\n        position = axisIndex * axisCollapseWidth;\n        nameTruncateMaxWidth = axisCollapseWidth;\n    }\n    else if (axisIndex <= winInnerIndices[1]) {\n        position = layoutInfo.axisExpandWindow0Pos\n            + axisIndex * axisExpandWidth - layoutInfo.axisExpandWindow[0];\n        axisNameAvailableWidth = axisExpandWidth;\n        axisLabelShow = true;\n    }\n    else {\n        position = layoutLength - (axisCount - 1 - axisIndex) * axisCollapseWidth;\n        nameTruncateMaxWidth = axisCollapseWidth;\n    }\n\n    return {\n        position: position,\n        axisNameAvailableWidth: axisNameAvailableWidth,\n        axisLabelShow: axisLabelShow,\n        nameTruncateMaxWidth: nameTruncateMaxWidth\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Parallel coordinate system creater.\n */\n\nfunction create$2(ecModel, api) {\n    var coordSysList = [];\n\n    ecModel.eachComponent('parallel', function (parallelModel, idx) {\n        var coordSys = new Parallel(parallelModel, ecModel, api);\n\n        coordSys.name = 'parallel_' + idx;\n        coordSys.resize(parallelModel, api);\n\n        parallelModel.coordinateSystem = coordSys;\n        coordSys.model = parallelModel;\n\n        coordSysList.push(coordSys);\n    });\n\n    // Inject the coordinateSystems into seriesModel\n    ecModel.eachSeries(function (seriesModel) {\n        if (seriesModel.get('coordinateSystem') === 'parallel') {\n            var parallelModel = ecModel.queryComponents({\n                mainType: 'parallel',\n                index: seriesModel.get('parallelIndex'),\n                id: seriesModel.get('parallelId')\n            })[0];\n            seriesModel.coordinateSystem = parallelModel.coordinateSystem;\n        }\n    });\n\n    return coordSysList;\n}\n\nCoordinateSystemManager.register('parallel', {create: create$2});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisModel$2 = ComponentModel.extend({\n\n    type: 'baseParallelAxis',\n\n    /**\n     * @type {module:echarts/coord/parallel/Axis}\n     */\n    axis: null,\n\n    /**\n     * @type {Array.<Array.<number>}\n     * @readOnly\n     */\n    activeIntervals: [],\n\n    /**\n     * @return {Object}\n     */\n    getAreaSelectStyle: function () {\n        return makeStyleMapper(\n            [\n                ['fill', 'color'],\n                ['lineWidth', 'borderWidth'],\n                ['stroke', 'borderColor'],\n                ['width', 'width'],\n                ['opacity', 'opacity']\n            ]\n        )(this.getModel('areaSelectStyle'));\n    },\n\n    /**\n     * The code of this feature is put on AxisModel but not ParallelAxis,\n     * because axisModel can be alive after echarts updating but instance of\n     * ParallelAxis having been disposed. this._activeInterval should be kept\n     * when action dispatched (i.e. legend click).\n     *\n     * @param {Array.<Array<number>>} intervals interval.length === 0\n     *                                          means set all active.\n     * @public\n     */\n    setActiveIntervals: function (intervals) {\n        var activeIntervals = this.activeIntervals = clone(intervals);\n\n        // Normalize\n        if (activeIntervals) {\n            for (var i = activeIntervals.length - 1; i >= 0; i--) {\n                asc(activeIntervals[i]);\n            }\n        }\n    },\n\n    /**\n     * @param {number|string} [value] When attempting to detect 'no activeIntervals set',\n     *                         value can not be input.\n     * @return {string} 'normal': no activeIntervals set,\n     *                  'active',\n     *                  'inactive'.\n     * @public\n     */\n    getActiveState: function (value) {\n        var activeIntervals = this.activeIntervals;\n\n        if (!activeIntervals.length) {\n            return 'normal';\n        }\n\n        if (value == null || isNaN(value)) {\n            return 'inactive';\n        }\n\n        // Simple optimization\n        if (activeIntervals.length === 1) {\n            var interval = activeIntervals[0];\n            if (interval[0] <= value && value <= interval[1]) {\n                return 'active';\n            }\n        }\n        else {\n            for (var i = 0, len = activeIntervals.length; i < len; i++) {\n                if (activeIntervals[i][0] <= value && value <= activeIntervals[i][1]) {\n                    return 'active';\n                }\n            }\n        }\n\n        return 'inactive';\n    }\n\n});\n\nvar defaultOption$1 = {\n\n    type: 'value',\n\n    /**\n     * @type {Array.<number>}\n     */\n    dim: null, // 0, 1, 2, ...\n\n    // parallelIndex: null,\n\n    areaSelectStyle: {\n        width: 20,\n        borderWidth: 1,\n        borderColor: 'rgba(160,197,232)',\n        color: 'rgba(160,197,232)',\n        opacity: 0.3\n    },\n\n    realtime: true, // Whether realtime update view when select.\n\n    z: 10\n};\n\nmerge(AxisModel$2.prototype, axisModelCommonMixin);\n\nfunction getAxisType$1(axisName, option) {\n    return option.type || (option.data ? 'category' : 'value');\n}\n\naxisModelCreator('parallel', AxisModel$2, getAxisType$1, defaultOption$1);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nComponentModel.extend({\n\n    type: 'parallel',\n\n    dependencies: ['parallelAxis'],\n\n    /**\n     * @type {module:echarts/coord/parallel/Parallel}\n     */\n    coordinateSystem: null,\n\n    /**\n     * Each item like: 'dim0', 'dim1', 'dim2', ...\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: null,\n\n    /**\n     * Coresponding to dimensions.\n     * @type {Array.<number>}\n     * @readOnly\n     */\n    parallelAxisIndex: null,\n\n    layoutMode: 'box',\n\n    defaultOption: {\n        zlevel: 0,\n        z: 0,\n        left: 80,\n        top: 60,\n        right: 80,\n        bottom: 60,\n        // width: {totalWidth} - left - right,\n        // height: {totalHeight} - top - bottom,\n\n        layout: 'horizontal',      // 'horizontal' or 'vertical'\n\n        // FIXME\n        // naming?\n        axisExpandable: false,\n        axisExpandCenter: null,\n        axisExpandCount: 0,\n        axisExpandWidth: 50,      // FIXME '10%' ?\n        axisExpandRate: 17,\n        axisExpandDebounce: 50,\n        // [out, in, jumpTarget]. In percentage. If use [null, 0.05], null means full.\n        // Do not doc to user until necessary.\n        axisExpandSlideTriggerArea: [-0.15, 0.05, 0.4],\n        axisExpandTriggerOn: 'click', // 'mousemove' or 'click'\n\n        parallelAxisDefault: null\n    },\n\n    /**\n     * @override\n     */\n    init: function () {\n        ComponentModel.prototype.init.apply(this, arguments);\n\n        this.mergeOption({});\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (newOption) {\n        var thisOption = this.option;\n\n        newOption && merge(thisOption, newOption, true);\n\n        this._initDimensions();\n    },\n\n    /**\n     * Whether series or axis is in this coordinate system.\n     * @param {module:echarts/model/Series|module:echarts/coord/parallel/AxisModel} model\n     * @param {module:echarts/model/Global} ecModel\n     */\n    contains: function (model, ecModel) {\n        var parallelIndex = model.get('parallelIndex');\n        return parallelIndex != null\n            && ecModel.getComponent('parallel', parallelIndex) === this;\n    },\n\n    setAxisExpand: function (opt) {\n        each$1(\n            ['axisExpandable', 'axisExpandCenter', 'axisExpandCount', 'axisExpandWidth', 'axisExpandWindow'],\n            function (name) {\n                if (opt.hasOwnProperty(name)) {\n                    this.option[name] = opt[name];\n                }\n            },\n            this\n        );\n    },\n\n    /**\n     * @private\n     */\n    _initDimensions: function () {\n        var dimensions = this.dimensions = [];\n        var parallelAxisIndex = this.parallelAxisIndex = [];\n\n        var axisModels = filter(this.dependentModels.parallelAxis, function (axisModel) {\n            // Can not use this.contains here, because\n            // initialization has not been completed yet.\n            return (axisModel.get('parallelIndex') || 0) === this.componentIndex;\n        }, this);\n\n        each$1(axisModels, function (axisModel) {\n            dimensions.push('dim' + axisModel.get('dim'));\n            parallelAxisIndex.push(axisModel.componentIndex);\n        });\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @payload\n * @property {string} parallelAxisId\n * @property {Array.<Array.<number>>} intervals\n */\nvar actionInfo$1 = {\n    type: 'axisAreaSelect',\n    event: 'axisAreaSelected'\n    // update: 'updateVisual'\n};\n\nregisterAction(actionInfo$1, function (payload, ecModel) {\n    ecModel.eachComponent(\n        {mainType: 'parallelAxis', query: payload},\n        function (parallelAxisModel) {\n            parallelAxisModel.axis.model.setActiveIntervals(payload.intervals);\n        }\n    );\n});\n\n/**\n * @payload\n */\nregisterAction('parallelAxisExpand', function (payload, ecModel) {\n    ecModel.eachComponent(\n        {mainType: 'parallel', query: payload},\n        function (parallelModel) {\n            parallelModel.setAxisExpand(payload);\n        }\n    );\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar curry$2 = curry;\nvar each$12 = each$1;\nvar map$2 = map;\nvar mathMin$6 = Math.min;\nvar mathMax$6 = Math.max;\nvar mathPow$2 = Math.pow;\n\nvar COVER_Z = 10000;\nvar UNSELECT_THRESHOLD = 6;\nvar MIN_RESIZE_LINE_WIDTH = 6;\nvar MUTEX_RESOURCE_KEY = 'globalPan';\n\nvar DIRECTION_MAP = {\n    w: [0, 0],\n    e: [0, 1],\n    n: [1, 0],\n    s: [1, 1]\n};\nvar CURSOR_MAP = {\n    w: 'ew',\n    e: 'ew',\n    n: 'ns',\n    s: 'ns',\n    ne: 'nesw',\n    sw: 'nesw',\n    nw: 'nwse',\n    se: 'nwse'\n};\nvar DEFAULT_BRUSH_OPT = {\n    brushStyle: {\n        lineWidth: 2,\n        stroke: 'rgba(0,0,0,0.3)',\n        fill: 'rgba(0,0,0,0.1)'\n    },\n    transformable: true,\n    brushMode: 'single',\n    removeOnClick: false\n};\n\nvar baseUID = 0;\n\n/**\n * @alias module:echarts/component/helper/BrushController\n * @constructor\n * @mixin {module:zrender/mixin/Eventful}\n * @event module:echarts/component/helper/BrushController#brush\n *        params:\n *            areas: Array.<Array>, coord relates to container group,\n *                                    If no container specified, to global.\n *            opt {\n *                isEnd: boolean,\n *                removeOnClick: boolean\n *            }\n *\n * @param {module:zrender/zrender~ZRender} zr\n */\nfunction BrushController(zr) {\n\n    if (__DEV__) {\n        assert$1(zr);\n    }\n\n    Eventful.call(this);\n\n    /**\n     * @type {module:zrender/zrender~ZRender}\n     * @private\n     */\n    this._zr = zr;\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * Only for drawing (after enabledBrush).\n     *     'line', 'rect', 'polygon' or false\n     *     If passing false/null/undefined, disable brush.\n     *     If passing 'auto', determined by panel.defaultBrushType\n     * @private\n     * @type {string}\n     */\n    this._brushType;\n\n    /**\n     * Only for drawing (after enabledBrush).\n     *\n     * @private\n     * @type {Object}\n     */\n    this._brushOption;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._panels;\n\n    /**\n     * @private\n     * @type {Array.<nubmer>}\n     */\n    this._track = [];\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._dragging;\n\n    /**\n     * @private\n     * @type {Array}\n     */\n    this._covers = [];\n\n    /**\n     * @private\n     * @type {moudule:zrender/container/Group}\n     */\n    this._creatingCover;\n\n    /**\n     * `true` means global panel\n     * @private\n     * @type {module:zrender/container/Group|boolean}\n     */\n    this._creatingPanel;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._enableGlobalPan;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    if (__DEV__) {\n        this._mounted;\n    }\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._uid = 'brushController_' + baseUID++;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._handlers = {};\n    each$12(mouseHandlers, function (handler, eventName) {\n        this._handlers[eventName] = bind(handler, this);\n    }, this);\n}\n\nBrushController.prototype = {\n\n    constructor: BrushController,\n\n    /**\n     * If set to null/undefined/false, select disabled.\n     * @param {Object} brushOption\n     * @param {string|boolean} brushOption.brushType 'line', 'rect', 'polygon' or false\n     *                          If passing false/null/undefined, disable brush.\n     *                          If passing 'auto', determined by panel.defaultBrushType.\n     *                              ('auto' can not be used in global panel)\n     * @param {number} [brushOption.brushMode='single'] 'single' or 'multiple'\n     * @param {boolean} [brushOption.transformable=true]\n     * @param {boolean} [brushOption.removeOnClick=false]\n     * @param {Object} [brushOption.brushStyle]\n     * @param {number} [brushOption.brushStyle.width]\n     * @param {number} [brushOption.brushStyle.lineWidth]\n     * @param {string} [brushOption.brushStyle.stroke]\n     * @param {string} [brushOption.brushStyle.fill]\n     * @param {number} [brushOption.z]\n     */\n    enableBrush: function (brushOption) {\n        if (__DEV__) {\n            assert$1(this._mounted);\n        }\n\n        this._brushType && doDisableBrush(this);\n        brushOption.brushType && doEnableBrush(this, brushOption);\n\n        return this;\n    },\n\n    /**\n     * @param {Array.<Object>} panelOpts If not pass, it is global brush.\n     *        Each items: {\n     *            panelId, // mandatory.\n     *            clipPath, // mandatory. function.\n     *            isTargetByCursor, // mandatory. function.\n     *            defaultBrushType, // optional, only used when brushType is 'auto'.\n     *            getLinearBrushOtherExtent, // optional. function.\n     *        }\n     */\n    setPanels: function (panelOpts) {\n        if (panelOpts && panelOpts.length) {\n            var panels = this._panels = {};\n            each$1(panelOpts, function (panelOpts) {\n                panels[panelOpts.panelId] = clone(panelOpts);\n            });\n        }\n        else {\n            this._panels = null;\n        }\n        return this;\n    },\n\n    /**\n     * @param {Object} [opt]\n     * @return {boolean} [opt.enableGlobalPan=false]\n     */\n    mount: function (opt) {\n        opt = opt || {};\n\n        if (__DEV__) {\n            this._mounted = true; // should be at first.\n        }\n\n        this._enableGlobalPan = opt.enableGlobalPan;\n\n        var thisGroup = this.group;\n        this._zr.add(thisGroup);\n\n        thisGroup.attr({\n            position: opt.position || [0, 0],\n            rotation: opt.rotation || 0,\n            scale: opt.scale || [1, 1]\n        });\n        this._transform = thisGroup.getLocalTransform();\n\n        return this;\n    },\n\n    eachCover: function (cb, context) {\n        each$12(this._covers, cb, context);\n    },\n\n    /**\n     * Update covers.\n     * @param {Array.<Object>} brushOptionList Like:\n     *        [\n     *            {id: 'xx', brushType: 'line', range: [23, 44], brushStyle, transformable},\n     *            {id: 'yy', brushType: 'rect', range: [[23, 44], [23, 54]]},\n     *            ...\n     *        ]\n     *        `brushType` is required in each cover info. (can not be 'auto')\n     *        `id` is not mandatory.\n     *        `brushStyle`, `transformable` is not mandatory, use DEFAULT_BRUSH_OPT by default.\n     *        If brushOptionList is null/undefined, all covers removed.\n     */\n    updateCovers: function (brushOptionList) {\n        if (__DEV__) {\n            assert$1(this._mounted);\n        }\n\n        brushOptionList = map(brushOptionList, function (brushOption) {\n            return merge(clone(DEFAULT_BRUSH_OPT), brushOption, true);\n        });\n\n        var tmpIdPrefix = '\\0-brush-index-';\n        var oldCovers = this._covers;\n        var newCovers = this._covers = [];\n        var controller = this;\n        var creatingCover = this._creatingCover;\n\n        (new DataDiffer(oldCovers, brushOptionList, oldGetKey, getKey))\n            .add(addOrUpdate)\n            .update(addOrUpdate)\n            .remove(remove)\n            .execute();\n\n        return this;\n\n        function getKey(brushOption, index) {\n            return (brushOption.id != null ? brushOption.id : tmpIdPrefix + index)\n                + '-' + brushOption.brushType;\n        }\n\n        function oldGetKey(cover, index) {\n            return getKey(cover.__brushOption, index);\n        }\n\n        function addOrUpdate(newIndex, oldIndex) {\n            var newBrushOption = brushOptionList[newIndex];\n            // Consider setOption in event listener of brushSelect,\n            // where updating cover when creating should be forbiden.\n            if (oldIndex != null && oldCovers[oldIndex] === creatingCover) {\n                newCovers[newIndex] = oldCovers[oldIndex];\n            }\n            else {\n                var cover = newCovers[newIndex] = oldIndex != null\n                    ? (\n                        oldCovers[oldIndex].__brushOption = newBrushOption,\n                        oldCovers[oldIndex]\n                    )\n                    : endCreating(controller, createCover(controller, newBrushOption));\n                updateCoverAfterCreation(controller, cover);\n            }\n        }\n\n        function remove(oldIndex) {\n            if (oldCovers[oldIndex] !== creatingCover) {\n                controller.group.remove(oldCovers[oldIndex]);\n            }\n        }\n    },\n\n    unmount: function () {\n        if (__DEV__) {\n            if (!this._mounted) {\n                return;\n            }\n        }\n\n        this.enableBrush(false);\n\n        // container may 'removeAll' outside.\n        clearCovers(this);\n        this._zr.remove(this.group);\n\n        if (__DEV__) {\n            this._mounted = false; // should be at last.\n        }\n\n        return this;\n    },\n\n    dispose: function () {\n        this.unmount();\n        this.off();\n    }\n};\n\nmixin(BrushController, Eventful);\n\nfunction doEnableBrush(controller, brushOption) {\n    var zr = controller._zr;\n\n    // Consider roam, which takes globalPan too.\n    if (!controller._enableGlobalPan) {\n        take(zr, MUTEX_RESOURCE_KEY, controller._uid);\n    }\n\n    each$12(controller._handlers, function (handler, eventName) {\n        zr.on(eventName, handler);\n    });\n\n    controller._brushType = brushOption.brushType;\n    controller._brushOption = merge(clone(DEFAULT_BRUSH_OPT), brushOption, true);\n}\n\nfunction doDisableBrush(controller) {\n    var zr = controller._zr;\n\n    release(zr, MUTEX_RESOURCE_KEY, controller._uid);\n\n    each$12(controller._handlers, function (handler, eventName) {\n        zr.off(eventName, handler);\n    });\n\n    controller._brushType = controller._brushOption = null;\n}\n\nfunction createCover(controller, brushOption) {\n    var cover = coverRenderers[brushOption.brushType].createCover(controller, brushOption);\n    cover.__brushOption = brushOption;\n    updateZ$1(cover, brushOption);\n    controller.group.add(cover);\n    return cover;\n}\n\nfunction endCreating(controller, creatingCover) {\n    var coverRenderer = getCoverRenderer(creatingCover);\n    if (coverRenderer.endCreating) {\n        coverRenderer.endCreating(controller, creatingCover);\n        updateZ$1(creatingCover, creatingCover.__brushOption);\n    }\n    return creatingCover;\n}\n\nfunction updateCoverShape(controller, cover) {\n    var brushOption = cover.__brushOption;\n    getCoverRenderer(cover).updateCoverShape(\n        controller, cover, brushOption.range, brushOption\n    );\n}\n\nfunction updateZ$1(cover, brushOption) {\n    var z = brushOption.z;\n    z == null && (z = COVER_Z);\n    cover.traverse(function (el) {\n        el.z = z;\n        el.z2 = z; // Consider in given container.\n    });\n}\n\nfunction updateCoverAfterCreation(controller, cover) {\n    getCoverRenderer(cover).updateCommon(controller, cover);\n    updateCoverShape(controller, cover);\n}\n\nfunction getCoverRenderer(cover) {\n    return coverRenderers[cover.__brushOption.brushType];\n}\n\n// return target panel or `true` (means global panel)\nfunction getPanelByPoint(controller, e, localCursorPoint) {\n    var panels = controller._panels;\n    if (!panels) {\n        return true; // Global panel\n    }\n    var panel;\n    var transform = controller._transform;\n    each$12(panels, function (pn) {\n        pn.isTargetByCursor(e, localCursorPoint, transform) && (panel = pn);\n    });\n    return panel;\n}\n\n// Return a panel or true\nfunction getPanelByCover(controller, cover) {\n    var panels = controller._panels;\n    if (!panels) {\n        return true; // Global panel\n    }\n    var panelId = cover.__brushOption.panelId;\n    // User may give cover without coord sys info,\n    // which is then treated as global panel.\n    return panelId != null ? panels[panelId] : true;\n}\n\nfunction clearCovers(controller) {\n    var covers = controller._covers;\n    var originalLength = covers.length;\n    each$12(covers, function (cover) {\n        controller.group.remove(cover);\n    }, controller);\n    covers.length = 0;\n\n    return !!originalLength;\n}\n\nfunction trigger$1(controller, opt) {\n    var areas = map$2(controller._covers, function (cover) {\n        var brushOption = cover.__brushOption;\n        var range = clone(brushOption.range);\n        return {\n            brushType: brushOption.brushType,\n            panelId: brushOption.panelId,\n            range: range\n        };\n    });\n\n    controller.trigger('brush', areas, {\n        isEnd: !!opt.isEnd,\n        removeOnClick: !!opt.removeOnClick\n    });\n}\n\nfunction shouldShowCover(controller) {\n    var track = controller._track;\n\n    if (!track.length) {\n        return false;\n    }\n\n    var p2 = track[track.length - 1];\n    var p1 = track[0];\n    var dx = p2[0] - p1[0];\n    var dy = p2[1] - p1[1];\n    var dist = mathPow$2(dx * dx + dy * dy, 0.5);\n\n    return dist > UNSELECT_THRESHOLD;\n}\n\nfunction getTrackEnds(track) {\n    var tail = track.length - 1;\n    tail < 0 && (tail = 0);\n    return [track[0], track[tail]];\n}\n\nfunction createBaseRectCover(doDrift, controller, brushOption, edgeNames) {\n    var cover = new Group();\n\n    cover.add(new Rect({\n        name: 'main',\n        style: makeStyle(brushOption),\n        silent: true,\n        draggable: true,\n        cursor: 'move',\n        drift: curry$2(doDrift, controller, cover, 'nswe'),\n        ondragend: curry$2(trigger$1, controller, {isEnd: true})\n    }));\n\n    each$12(\n        edgeNames,\n        function (name) {\n            cover.add(new Rect({\n                name: name,\n                style: {opacity: 0},\n                draggable: true,\n                silent: true,\n                invisible: true,\n                drift: curry$2(doDrift, controller, cover, name),\n                ondragend: curry$2(trigger$1, controller, {isEnd: true})\n            }));\n        }\n    );\n\n    return cover;\n}\n\nfunction updateBaseRect(controller, cover, localRange, brushOption) {\n    var lineWidth = brushOption.brushStyle.lineWidth || 0;\n    var handleSize = mathMax$6(lineWidth, MIN_RESIZE_LINE_WIDTH);\n    var x = localRange[0][0];\n    var y = localRange[1][0];\n    var xa = x - lineWidth / 2;\n    var ya = y - lineWidth / 2;\n    var x2 = localRange[0][1];\n    var y2 = localRange[1][1];\n    var x2a = x2 - handleSize + lineWidth / 2;\n    var y2a = y2 - handleSize + lineWidth / 2;\n    var width = x2 - x;\n    var height = y2 - y;\n    var widtha = width + lineWidth;\n    var heighta = height + lineWidth;\n\n    updateRectShape(controller, cover, 'main', x, y, width, height);\n\n    if (brushOption.transformable) {\n        updateRectShape(controller, cover, 'w', xa, ya, handleSize, heighta);\n        updateRectShape(controller, cover, 'e', x2a, ya, handleSize, heighta);\n        updateRectShape(controller, cover, 'n', xa, ya, widtha, handleSize);\n        updateRectShape(controller, cover, 's', xa, y2a, widtha, handleSize);\n\n        updateRectShape(controller, cover, 'nw', xa, ya, handleSize, handleSize);\n        updateRectShape(controller, cover, 'ne', x2a, ya, handleSize, handleSize);\n        updateRectShape(controller, cover, 'sw', xa, y2a, handleSize, handleSize);\n        updateRectShape(controller, cover, 'se', x2a, y2a, handleSize, handleSize);\n    }\n}\n\nfunction updateCommon(controller, cover) {\n    var brushOption = cover.__brushOption;\n    var transformable = brushOption.transformable;\n\n    var mainEl = cover.childAt(0);\n    mainEl.useStyle(makeStyle(brushOption));\n    mainEl.attr({\n        silent: !transformable,\n        cursor: transformable ? 'move' : 'default'\n    });\n\n    each$12(\n        ['w', 'e', 'n', 's', 'se', 'sw', 'ne', 'nw'],\n        function (name) {\n            var el = cover.childOfName(name);\n            var globalDir = getGlobalDirection(controller, name);\n\n            el && el.attr({\n                silent: !transformable,\n                invisible: !transformable,\n                cursor: transformable ? CURSOR_MAP[globalDir] + '-resize' : null\n            });\n        }\n    );\n}\n\nfunction updateRectShape(controller, cover, name, x, y, w, h) {\n    var el = cover.childOfName(name);\n    el && el.setShape(pointsToRect(\n        clipByPanel(controller, cover, [[x, y], [x + w, y + h]])\n    ));\n}\n\nfunction makeStyle(brushOption) {\n    return defaults({strokeNoScale: true}, brushOption.brushStyle);\n}\n\nfunction formatRectRange(x, y, x2, y2) {\n    var min = [mathMin$6(x, x2), mathMin$6(y, y2)];\n    var max = [mathMax$6(x, x2), mathMax$6(y, y2)];\n\n    return [\n        [min[0], max[0]], // x range\n        [min[1], max[1]] // y range\n    ];\n}\n\nfunction getTransform$1(controller) {\n    return getTransform(controller.group);\n}\n\nfunction getGlobalDirection(controller, localDirection) {\n    if (localDirection.length > 1) {\n        localDirection = localDirection.split('');\n        var globalDir = [\n            getGlobalDirection(controller, localDirection[0]),\n            getGlobalDirection(controller, localDirection[1])\n        ];\n        (globalDir[0] === 'e' || globalDir[0] === 'w') && globalDir.reverse();\n        return globalDir.join('');\n    }\n    else {\n        var map$$1 = {w: 'left', e: 'right', n: 'top', s: 'bottom'};\n        var inverseMap = {left: 'w', right: 'e', top: 'n', bottom: 's'};\n        var globalDir = transformDirection(\n            map$$1[localDirection], getTransform$1(controller)\n        );\n        return inverseMap[globalDir];\n    }\n}\n\nfunction driftRect(toRectRange, fromRectRange, controller, cover, name, dx, dy, e) {\n    var brushOption = cover.__brushOption;\n    var rectRange = toRectRange(brushOption.range);\n    var localDelta = toLocalDelta(controller, dx, dy);\n\n    each$12(name.split(''), function (namePart) {\n        var ind = DIRECTION_MAP[namePart];\n        rectRange[ind[0]][ind[1]] += localDelta[ind[0]];\n    });\n\n    brushOption.range = fromRectRange(formatRectRange(\n        rectRange[0][0], rectRange[1][0], rectRange[0][1], rectRange[1][1]\n    ));\n\n    updateCoverAfterCreation(controller, cover);\n    trigger$1(controller, {isEnd: false});\n}\n\nfunction driftPolygon(controller, cover, dx, dy, e) {\n    var range = cover.__brushOption.range;\n    var localDelta = toLocalDelta(controller, dx, dy);\n\n    each$12(range, function (point) {\n        point[0] += localDelta[0];\n        point[1] += localDelta[1];\n    });\n\n    updateCoverAfterCreation(controller, cover);\n    trigger$1(controller, {isEnd: false});\n}\n\nfunction toLocalDelta(controller, dx, dy) {\n    var thisGroup = controller.group;\n    var localD = thisGroup.transformCoordToLocal(dx, dy);\n    var localZero = thisGroup.transformCoordToLocal(0, 0);\n\n    return [localD[0] - localZero[0], localD[1] - localZero[1]];\n}\n\nfunction clipByPanel(controller, cover, data) {\n    var panel = getPanelByCover(controller, cover);\n\n    return (panel && panel !== true)\n        ? panel.clipPath(data, controller._transform)\n        : clone(data);\n}\n\nfunction pointsToRect(points) {\n    var xmin = mathMin$6(points[0][0], points[1][0]);\n    var ymin = mathMin$6(points[0][1], points[1][1]);\n    var xmax = mathMax$6(points[0][0], points[1][0]);\n    var ymax = mathMax$6(points[0][1], points[1][1]);\n\n    return {\n        x: xmin,\n        y: ymin,\n        width: xmax - xmin,\n        height: ymax - ymin\n    };\n}\n\nfunction resetCursor(controller, e, localCursorPoint) {\n    // Check active\n    if (!controller._brushType) {\n        return;\n    }\n\n    var zr = controller._zr;\n    var covers = controller._covers;\n    var currPanel = getPanelByPoint(controller, e, localCursorPoint);\n\n    // Check whether in covers.\n    if (!controller._dragging) {\n        for (var i = 0; i < covers.length; i++) {\n            var brushOption = covers[i].__brushOption;\n            if (currPanel\n                && (currPanel === true || brushOption.panelId === currPanel.panelId)\n                && coverRenderers[brushOption.brushType].contain(\n                    covers[i], localCursorPoint[0], localCursorPoint[1]\n                )\n            ) {\n                // Use cursor style set on cover.\n                return;\n            }\n        }\n    }\n\n    currPanel && zr.setCursorStyle('crosshair');\n}\n\nfunction preventDefault(e) {\n    var rawE = e.event;\n    rawE.preventDefault && rawE.preventDefault();\n}\n\nfunction mainShapeContain(cover, x, y) {\n    return cover.childOfName('main').contain(x, y);\n}\n\nfunction updateCoverByMouse(controller, e, localCursorPoint, isEnd) {\n    var creatingCover = controller._creatingCover;\n    var panel = controller._creatingPanel;\n    var thisBrushOption = controller._brushOption;\n    var eventParams;\n\n    controller._track.push(localCursorPoint.slice());\n\n    if (shouldShowCover(controller) || creatingCover) {\n\n        if (panel && !creatingCover) {\n            thisBrushOption.brushMode === 'single' && clearCovers(controller);\n            var brushOption = clone(thisBrushOption);\n            brushOption.brushType = determineBrushType(brushOption.brushType, panel);\n            brushOption.panelId = panel === true ? null : panel.panelId;\n            creatingCover = controller._creatingCover = createCover(controller, brushOption);\n            controller._covers.push(creatingCover);\n        }\n\n        if (creatingCover) {\n            var coverRenderer = coverRenderers[determineBrushType(controller._brushType, panel)];\n            var coverBrushOption = creatingCover.__brushOption;\n\n            coverBrushOption.range = coverRenderer.getCreatingRange(\n                clipByPanel(controller, creatingCover, controller._track)\n            );\n\n            if (isEnd) {\n                endCreating(controller, creatingCover);\n                coverRenderer.updateCommon(controller, creatingCover);\n            }\n\n            updateCoverShape(controller, creatingCover);\n\n            eventParams = {isEnd: isEnd};\n        }\n    }\n    else if (\n        isEnd\n        && thisBrushOption.brushMode === 'single'\n        && thisBrushOption.removeOnClick\n    ) {\n        // Help user to remove covers easily, only by a tiny drag, in 'single' mode.\n        // But a single click do not clear covers, because user may have casual\n        // clicks (for example, click on other component and do not expect covers\n        // disappear).\n        // Only some cover removed, trigger action, but not every click trigger action.\n        if (getPanelByPoint(controller, e, localCursorPoint) && clearCovers(controller)) {\n            eventParams = {isEnd: isEnd, removeOnClick: true};\n        }\n    }\n\n    return eventParams;\n}\n\nfunction determineBrushType(brushType, panel) {\n    if (brushType === 'auto') {\n        if (__DEV__) {\n            assert$1(\n                panel && panel.defaultBrushType,\n                'MUST have defaultBrushType when brushType is \"atuo\"'\n            );\n        }\n        return panel.defaultBrushType;\n    }\n    return brushType;\n}\n\nvar mouseHandlers = {\n\n    mousedown: function (e) {\n        if (this._dragging) {\n            // In case some browser do not support globalOut,\n            // and release mose out side the browser.\n            handleDragEnd.call(this, e);\n        }\n        else if (!e.target || !e.target.draggable) {\n\n            preventDefault(e);\n\n            var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n\n            this._creatingCover = null;\n            var panel = this._creatingPanel = getPanelByPoint(this, e, localCursorPoint);\n\n            if (panel) {\n                this._dragging = true;\n                this._track = [localCursorPoint.slice()];\n            }\n        }\n    },\n\n    mousemove: function (e) {\n        var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n\n        resetCursor(this, e, localCursorPoint);\n\n        if (this._dragging) {\n\n            preventDefault(e);\n\n            var eventParams = updateCoverByMouse(this, e, localCursorPoint, false);\n\n            eventParams && trigger$1(this, eventParams);\n        }\n    },\n\n    mouseup: handleDragEnd //,\n\n    // FIXME\n    // in tooltip, globalout should not be triggered.\n    // globalout: handleDragEnd\n};\n\nfunction handleDragEnd(e) {\n    if (this._dragging) {\n\n        preventDefault(e);\n\n        var localCursorPoint = this.group.transformCoordToLocal(e.offsetX, e.offsetY);\n        var eventParams = updateCoverByMouse(this, e, localCursorPoint, true);\n\n        this._dragging = false;\n        this._track = [];\n        this._creatingCover = null;\n\n        // trigger event shoule be at final, after procedure will be nested.\n        eventParams && trigger$1(this, eventParams);\n    }\n}\n\n/**\n * key: brushType\n * @type {Object}\n */\nvar coverRenderers = {\n\n    lineX: getLineRenderer(0),\n\n    lineY: getLineRenderer(1),\n\n    rect: {\n        createCover: function (controller, brushOption) {\n            return createBaseRectCover(\n                curry$2(\n                    driftRect,\n                    function (range) {\n                        return range;\n                    },\n                    function (range) {\n                        return range;\n                    }\n                ),\n                controller,\n                brushOption,\n                ['w', 'e', 'n', 's', 'se', 'sw', 'ne', 'nw']\n            );\n        },\n        getCreatingRange: function (localTrack) {\n            var ends = getTrackEnds(localTrack);\n            return formatRectRange(ends[1][0], ends[1][1], ends[0][0], ends[0][1]);\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            updateBaseRect(controller, cover, localRange, brushOption);\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    },\n\n    polygon: {\n        createCover: function (controller, brushOption) {\n            var cover = new Group();\n\n            // Do not use graphic.Polygon because graphic.Polyline do not close the\n            // border of the shape when drawing, which is a better experience for user.\n            cover.add(new Polyline({\n                name: 'main',\n                style: makeStyle(brushOption),\n                silent: true\n            }));\n\n            return cover;\n        },\n        getCreatingRange: function (localTrack) {\n            return localTrack;\n        },\n        endCreating: function (controller, cover) {\n            cover.remove(cover.childAt(0));\n            // Use graphic.Polygon close the shape.\n            cover.add(new Polygon({\n                name: 'main',\n                draggable: true,\n                drift: curry$2(driftPolygon, controller, cover),\n                ondragend: curry$2(trigger$1, controller, {isEnd: true})\n            }));\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            cover.childAt(0).setShape({\n                points: clipByPanel(controller, cover, localRange)\n            });\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    }\n};\n\nfunction getLineRenderer(xyIndex) {\n    return {\n        createCover: function (controller, brushOption) {\n            return createBaseRectCover(\n                curry$2(\n                    driftRect,\n                    function (range) {\n                        var rectRange = [range, [0, 100]];\n                        xyIndex && rectRange.reverse();\n                        return rectRange;\n                    },\n                    function (rectRange) {\n                        return rectRange[xyIndex];\n                    }\n                ),\n                controller,\n                brushOption,\n                [['w', 'e'], ['n', 's']][xyIndex]\n            );\n        },\n        getCreatingRange: function (localTrack) {\n            var ends = getTrackEnds(localTrack);\n            var min = mathMin$6(ends[0][xyIndex], ends[1][xyIndex]);\n            var max = mathMax$6(ends[0][xyIndex], ends[1][xyIndex]);\n\n            return [min, max];\n        },\n        updateCoverShape: function (controller, cover, localRange, brushOption) {\n            var otherExtent;\n            // If brushWidth not specified, fit the panel.\n            var panel = getPanelByCover(controller, cover);\n            if (panel !== true && panel.getLinearBrushOtherExtent) {\n                otherExtent = panel.getLinearBrushOtherExtent(\n                    xyIndex, controller._transform\n                );\n            }\n            else {\n                var zr = controller._zr;\n                otherExtent = [0, [zr.getWidth(), zr.getHeight()][1 - xyIndex]];\n            }\n            var rectRange = [localRange, otherExtent];\n            xyIndex && rectRange.reverse();\n\n            updateBaseRect(controller, cover, rectRange, brushOption);\n        },\n        updateCommon: updateCommon,\n        contain: mainShapeContain\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction makeRectPanelClipPath(rect) {\n    rect = normalizeRect(rect);\n    return function (localPoints, transform) {\n        return clipPointsByRect(localPoints, rect);\n    };\n}\n\nfunction makeLinearBrushOtherExtent(rect, specifiedXYIndex) {\n    rect = normalizeRect(rect);\n    return function (xyIndex) {\n        var idx = specifiedXYIndex != null ? specifiedXYIndex : xyIndex;\n        var brushWidth = idx ? rect.width : rect.height;\n        var base = idx ? rect.x : rect.y;\n        return [base, base + (brushWidth || 0)];\n    };\n}\n\nfunction makeRectIsTargetByCursor(rect, api, targetModel) {\n    rect = normalizeRect(rect);\n    return function (e, localCursorPoint, transform) {\n        return rect.contain(localCursorPoint[0], localCursorPoint[1])\n            && !onIrrelevantElement(e, api, targetModel);\n    };\n}\n\n// Consider width/height is negative.\nfunction normalizeRect(rect) {\n    return BoundingRect.create(rect);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar elementList = ['axisLine', 'axisTickLabel', 'axisName'];\n\nvar AxisView$2 = extendComponentView({\n\n    type: 'parallelAxis',\n\n    /**\n     * @override\n     */\n    init: function (ecModel, api) {\n        AxisView$2.superApply(this, 'init', arguments);\n\n        /**\n         * @type {module:echarts/component/helper/BrushController}\n         */\n        (this._brushController = new BrushController(api.getZr()))\n            .on('brush', bind(this._onBrush, this));\n    },\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n        if (fromAxisAreaSelect(axisModel, ecModel, payload)) {\n            return;\n        }\n\n        this.axisModel = axisModel;\n        this.api = api;\n\n        this.group.removeAll();\n\n        var oldAxisGroup = this._axisGroup;\n        this._axisGroup = new Group();\n        this.group.add(this._axisGroup);\n\n        if (!axisModel.get('show')) {\n            return;\n        }\n\n        var coordSysModel = getCoordSysModel(axisModel, ecModel);\n        var coordSys = coordSysModel.coordinateSystem;\n\n        var areaSelectStyle = axisModel.getAreaSelectStyle();\n        var areaWidth = areaSelectStyle.width;\n\n        var dim = axisModel.axis.dim;\n        var axisLayout = coordSys.getAxisLayout(dim);\n\n        var builderOpt = extend(\n            {strokeContainThreshold: areaWidth},\n            axisLayout\n        );\n\n        var axisBuilder = new AxisBuilder(axisModel, builderOpt);\n\n        each$1(elementList, axisBuilder.add, axisBuilder);\n\n        this._axisGroup.add(axisBuilder.getGroup());\n\n        this._refreshBrushController(\n            builderOpt, areaSelectStyle, axisModel, coordSysModel, areaWidth, api\n        );\n\n        var animationModel = (payload && payload.animation === false) ? null : axisModel;\n        groupTransition(oldAxisGroup, this._axisGroup, animationModel);\n    },\n\n    // /**\n    //  * @override\n    //  */\n    // updateVisual: function (axisModel, ecModel, api, payload) {\n    //     this._brushController && this._brushController\n    //         .updateCovers(getCoverInfoList(axisModel));\n    // },\n\n    _refreshBrushController: function (\n        builderOpt, areaSelectStyle, axisModel, coordSysModel, areaWidth, api\n    ) {\n        // After filtering, axis may change, select area needs to be update.\n        var extent = axisModel.axis.getExtent();\n        var extentLen = extent[1] - extent[0];\n        var extra = Math.min(30, Math.abs(extentLen) * 0.1); // Arbitrary value.\n\n        // width/height might be negative, which will be\n        // normalized in BoundingRect.\n        var rect = BoundingRect.create({\n            x: extent[0],\n            y: -areaWidth / 2,\n            width: extentLen,\n            height: areaWidth\n        });\n        rect.x -= extra;\n        rect.width += 2 * extra;\n\n        this._brushController\n            .mount({\n                enableGlobalPan: true,\n                rotation: builderOpt.rotation,\n                position: builderOpt.position\n            })\n            .setPanels([{\n                panelId: 'pl',\n                clipPath: makeRectPanelClipPath(rect),\n                isTargetByCursor: makeRectIsTargetByCursor(rect, api, coordSysModel),\n                getLinearBrushOtherExtent: makeLinearBrushOtherExtent(rect, 0)\n            }])\n            .enableBrush({\n                brushType: 'lineX',\n                brushStyle: areaSelectStyle,\n                removeOnClick: true\n            })\n            .updateCovers(getCoverInfoList(axisModel));\n    },\n\n    _onBrush: function (coverInfoList, opt) {\n        // Do not cache these object, because the mey be changed.\n        var axisModel = this.axisModel;\n        var axis = axisModel.axis;\n        var intervals = map(coverInfoList, function (coverInfo) {\n            return [\n                axis.coordToData(coverInfo.range[0], true),\n                axis.coordToData(coverInfo.range[1], true)\n            ];\n        });\n\n        // If realtime is true, action is not dispatched on drag end, because\n        // the drag end emits the same params with the last drag move event,\n        // and may have some delay when using touch pad.\n        if (!axisModel.option.realtime === opt.isEnd || opt.removeOnClick) { // jshint ignore:line\n            this.api.dispatchAction({\n                type: 'axisAreaSelect',\n                parallelAxisId: axisModel.id,\n                intervals: intervals\n            });\n        }\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._brushController.dispose();\n    }\n});\n\nfunction fromAxisAreaSelect(axisModel, ecModel, payload) {\n    return payload\n        && payload.type === 'axisAreaSelect'\n        && ecModel.findComponents(\n            {mainType: 'parallelAxis', query: payload}\n        )[0] === axisModel;\n}\n\nfunction getCoverInfoList(axisModel) {\n    var axis = axisModel.axis;\n    return map(axisModel.activeIntervals, function (interval) {\n        return {\n            brushType: 'lineX',\n            panelId: 'pl',\n            range: [\n                axis.dataToCoord(interval[0], true),\n                axis.dataToCoord(interval[1], true)\n            ]\n        };\n    });\n}\n\nfunction getCoordSysModel(axisModel, ecModel) {\n    return ecModel.getComponent(\n        'parallel', axisModel.get('parallelIndex')\n    );\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar CLICK_THRESHOLD = 5; // > 4\n\n// Parallel view\nextendComponentView({\n    type: 'parallel',\n\n    render: function (parallelModel, ecModel, api) {\n        this._model = parallelModel;\n        this._api = api;\n\n        if (!this._handlers) {\n            this._handlers = {};\n            each$1(handlers, function (handler, eventName) {\n                api.getZr().on(eventName, this._handlers[eventName] = bind(handler, this));\n            }, this);\n        }\n\n        createOrUpdate(\n            this,\n            '_throttledDispatchExpand',\n            parallelModel.get('axisExpandRate'),\n            'fixRate'\n        );\n    },\n\n    dispose: function (ecModel, api) {\n        each$1(this._handlers, function (handler, eventName) {\n            api.getZr().off(eventName, handler);\n        });\n        this._handlers = null;\n    },\n\n    /**\n     * @param {Object} [opt] If null, cancle the last action triggering for debounce.\n     */\n    _throttledDispatchExpand: function (opt) {\n        this._dispatchExpand(opt);\n    },\n\n    _dispatchExpand: function (opt) {\n        opt && this._api.dispatchAction(\n            extend({type: 'parallelAxisExpand'}, opt)\n        );\n    }\n\n});\n\nvar handlers = {\n\n    mousedown: function (e) {\n        if (checkTrigger(this, 'click')) {\n            this._mouseDownPoint = [e.offsetX, e.offsetY];\n        }\n    },\n\n    mouseup: function (e) {\n        var mouseDownPoint = this._mouseDownPoint;\n\n        if (checkTrigger(this, 'click') && mouseDownPoint) {\n            var point = [e.offsetX, e.offsetY];\n            var dist = Math.pow(mouseDownPoint[0] - point[0], 2)\n                + Math.pow(mouseDownPoint[1] - point[1], 2);\n\n            if (dist > CLICK_THRESHOLD) {\n                return;\n            }\n\n            var result = this._model.coordinateSystem.getSlidedAxisExpandWindow(\n                [e.offsetX, e.offsetY]\n            );\n\n            result.behavior !== 'none' && this._dispatchExpand({\n                axisExpandWindow: result.axisExpandWindow\n            });\n        }\n\n        this._mouseDownPoint = null;\n    },\n\n    mousemove: function (e) {\n        // Should do nothing when brushing.\n        if (this._mouseDownPoint || !checkTrigger(this, 'mousemove')) {\n            return;\n        }\n        var model = this._model;\n        var result = model.coordinateSystem.getSlidedAxisExpandWindow(\n            [e.offsetX, e.offsetY]\n        );\n\n        var behavior = result.behavior;\n        behavior === 'jump' && this._throttledDispatchExpand.debounceNextCall(model.get('axisExpandDebounce'));\n        this._throttledDispatchExpand(\n            behavior === 'none'\n                ? null // Cancle the last trigger, in case that mouse slide out of the area quickly.\n                : {\n                    axisExpandWindow: result.axisExpandWindow,\n                    // Jumping uses animation, and sliding suppresses animation.\n                    animation: behavior === 'jump' ? null : false\n                }\n        );\n    }\n};\n\nfunction checkTrigger(view, triggerOn) {\n    var model = view._model;\n    return model.get('axisExpandable') && model.get('axisExpandTriggerOn') === triggerOn;\n}\n\nregisterPreprocessor(parallelPreprocessor);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.parallel',\n\n    dependencies: ['parallel'],\n\n    visualColorAccessPath: 'lineStyle.color',\n\n    getInitialData: function (option, ecModel) {\n        var source = this.getSource();\n\n        setEncodeAndDimensions(source, this);\n\n        return createListFromArray(source, this);\n    },\n\n    /**\n     * User can get data raw indices on 'axisAreaSelected' event received.\n     *\n     * @public\n     * @param {string} activeState 'active' or 'inactive' or 'normal'\n     * @return {Array.<number>} Raw indices\n     */\n    getRawIndicesByActiveState: function (activeState) {\n        var coordSys = this.coordinateSystem;\n        var data = this.getData();\n        var indices = [];\n\n        coordSys.eachActiveState(data, function (theActiveState, dataIndex) {\n            if (activeState === theActiveState) {\n                indices.push(data.getRawIndex(dataIndex));\n            }\n        });\n\n        return indices;\n    },\n\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n\n        coordinateSystem: 'parallel',\n        parallelIndex: 0,\n\n        label: {\n            show: false\n        },\n\n        inactiveOpacity: 0.05,\n        activeOpacity: 1,\n\n        lineStyle: {\n            width: 1,\n            opacity: 0.45,\n            type: 'solid'\n        },\n        emphasis: {\n            label: {\n                show: false\n            }\n        },\n\n        progressive: 500,\n        smooth: false, // true | false | number\n\n        animationEasing: 'linear'\n    }\n});\n\nfunction setEncodeAndDimensions(source, seriesModel) {\n    // The mapping of parallelAxis dimension to data dimension can\n    // be specified in parallelAxis.option.dim. For example, if\n    // parallelAxis.option.dim is 'dim3', it mapping to the third\n    // dimension of data. But `data.encode` has higher priority.\n    // Moreover, parallelModel.dimension should not be regarded as data\n    // dimensions. Consider dimensions = ['dim4', 'dim2', 'dim6'];\n\n    if (source.encodeDefine) {\n        return;\n    }\n\n    var parallelModel = seriesModel.ecModel.getComponent(\n        'parallel', seriesModel.get('parallelIndex')\n    );\n    if (!parallelModel) {\n        return;\n    }\n\n    var encodeDefine = source.encodeDefine = createHashMap();\n    each$1(parallelModel.dimensions, function (axisDim) {\n        var dataDimIndex = convertDimNameToNumber(axisDim);\n        encodeDefine.set(axisDim, dataDimIndex);\n    });\n}\n\nfunction convertDimNameToNumber(dimName) {\n    return +dimName.replace('dim', '');\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DEFAULT_SMOOTH = 0.3;\n\nvar ParallelView = Chart.extend({\n\n    type: 'parallel',\n\n    init: function () {\n\n        /**\n         * @type {module:zrender/container/Group}\n         * @private\n         */\n        this._dataGroup = new Group();\n\n        this.group.add(this._dataGroup);\n\n        /**\n         * @type {module:echarts/data/List}\n         */\n        this._data;\n\n        /**\n         * @type {boolean}\n         */\n        this._initialized;\n    },\n\n    /**\n     * @override\n     */\n    render: function (seriesModel, ecModel, api, payload) {\n        var dataGroup = this._dataGroup;\n        var data = seriesModel.getData();\n        var oldData = this._data;\n        var coordSys = seriesModel.coordinateSystem;\n        var dimensions = coordSys.dimensions;\n        var seriesScope = makeSeriesScope$2(seriesModel);\n\n        data.diff(oldData)\n            .add(add)\n            .update(update)\n            .remove(remove)\n            .execute();\n\n        function add(newDataIndex) {\n            var line = addEl(data, dataGroup, newDataIndex, dimensions, coordSys);\n            updateElCommon(line, data, newDataIndex, seriesScope);\n        }\n\n        function update(newDataIndex, oldDataIndex) {\n            var line = oldData.getItemGraphicEl(oldDataIndex);\n            var points = createLinePoints(data, newDataIndex, dimensions, coordSys);\n            data.setItemGraphicEl(newDataIndex, line);\n            var animationModel = (payload && payload.animation === false) ? null : seriesModel;\n            updateProps(line, {shape: {points: points}}, animationModel, newDataIndex);\n\n            updateElCommon(line, data, newDataIndex, seriesScope);\n        }\n\n        function remove(oldDataIndex) {\n            var line = oldData.getItemGraphicEl(oldDataIndex);\n            dataGroup.remove(line);\n        }\n\n        // First create\n        if (!this._initialized) {\n            this._initialized = true;\n            var clipPath = createGridClipShape$1(\n                coordSys, seriesModel, function () {\n                    // Callback will be invoked immediately if there is no animation\n                    setTimeout(function () {\n                        dataGroup.removeClipPath();\n                    });\n                }\n            );\n            dataGroup.setClipPath(clipPath);\n        }\n\n        this._data = data;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this._initialized = true;\n        this._data = null;\n        this._dataGroup.removeAll();\n    },\n\n    incrementalRender: function (taskParams, seriesModel, ecModel) {\n        var data = seriesModel.getData();\n        var coordSys = seriesModel.coordinateSystem;\n        var dimensions = coordSys.dimensions;\n        var seriesScope = makeSeriesScope$2(seriesModel);\n\n        for (var dataIndex = taskParams.start; dataIndex < taskParams.end; dataIndex++) {\n            var line = addEl(data, this._dataGroup, dataIndex, dimensions, coordSys);\n            line.incremental = true;\n            updateElCommon(line, data, dataIndex, seriesScope);\n        }\n    },\n\n    dispose: function () {},\n\n    // _renderForProgressive: function (seriesModel) {\n    //     var dataGroup = this._dataGroup;\n    //     var data = seriesModel.getData();\n    //     var oldData = this._data;\n    //     var coordSys = seriesModel.coordinateSystem;\n    //     var dimensions = coordSys.dimensions;\n    //     var option = seriesModel.option;\n    //     var progressive = option.progressive;\n    //     var smooth = option.smooth ? SMOOTH : null;\n\n    //     // In progressive animation is disabled, so use simple data diff,\n    //     // which effects performance less.\n    //     // (Typically performance for data with length 7000+ like:\n    //     // simpleDiff: 60ms, addEl: 184ms,\n    //     // in RMBP 2.4GHz intel i7, OSX 10.9 chrome 50.0.2661.102 (64-bit))\n    //     if (simpleDiff(oldData, data, dimensions)) {\n    //         dataGroup.removeAll();\n    //         data.each(function (dataIndex) {\n    //             addEl(data, dataGroup, dataIndex, dimensions, coordSys);\n    //         });\n    //     }\n\n    //     updateElCommon(data, progressive, smooth);\n\n    //     // Consider switch between progressive and not.\n    //     data.__plProgressive = true;\n    //     this._data = data;\n    // },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this._dataGroup && this._dataGroup.removeAll();\n        this._data = null;\n    }\n});\n\nfunction createGridClipShape$1(coordSys, seriesModel, cb) {\n    var parallelModel = coordSys.model;\n    var rect = coordSys.getRect();\n    var rectEl = new Rect({\n        shape: {\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        }\n    });\n\n    var dim = parallelModel.get('layout') === 'horizontal' ? 'width' : 'height';\n    rectEl.setShape(dim, 0);\n    initProps(rectEl, {\n        shape: {\n            width: rect.width,\n            height: rect.height\n        }\n    }, seriesModel, cb);\n    return rectEl;\n}\n\nfunction createLinePoints(data, dataIndex, dimensions, coordSys) {\n    var points = [];\n    for (var i = 0; i < dimensions.length; i++) {\n        var dimName = dimensions[i];\n        var value = data.get(data.mapDimension(dimName), dataIndex);\n        if (!isEmptyValue(value, coordSys.getAxis(dimName).type)) {\n            points.push(coordSys.dataToPoint(value, dimName));\n        }\n    }\n    return points;\n}\n\nfunction addEl(data, dataGroup, dataIndex, dimensions, coordSys) {\n    var points = createLinePoints(data, dataIndex, dimensions, coordSys);\n    var line = new Polyline({\n        shape: {points: points},\n        silent: true,\n        z2: 10\n    });\n    dataGroup.add(line);\n    data.setItemGraphicEl(dataIndex, line);\n    return line;\n}\n\nfunction makeSeriesScope$2(seriesModel) {\n    var smooth = seriesModel.get('smooth', true);\n    smooth === true && (smooth = DEFAULT_SMOOTH);\n    return {\n        lineStyle: seriesModel.getModel('lineStyle').getLineStyle(),\n        smooth: smooth != null ? smooth : DEFAULT_SMOOTH\n    };\n}\n\nfunction updateElCommon(el, data, dataIndex, seriesScope) {\n    var lineStyle = seriesScope.lineStyle;\n\n    if (data.hasItemOption) {\n        var lineStyleModel = data.getItemModel(dataIndex).getModel('lineStyle');\n        lineStyle = lineStyleModel.getLineStyle();\n    }\n\n    el.useStyle(lineStyle);\n\n    var elStyle = el.style;\n    elStyle.fill = null;\n    // lineStyle.color have been set to itemVisual in module:echarts/visual/seriesColor.\n    elStyle.stroke = data.getItemVisual(dataIndex, 'color');\n    // lineStyle.opacity have been set to itemVisual in parallelVisual.\n    elStyle.opacity = data.getItemVisual(dataIndex, 'opacity');\n\n    seriesScope.smooth && (el.shape.smooth = seriesScope.smooth);\n}\n\n// function simpleDiff(oldData, newData, dimensions) {\n//     var oldLen;\n//     if (!oldData\n//         || !oldData.__plProgressive\n//         || (oldLen = oldData.count()) !== newData.count()\n//     ) {\n//         return true;\n//     }\n\n//     var dimLen = dimensions.length;\n//     for (var i = 0; i < oldLen; i++) {\n//         for (var j = 0; j < dimLen; j++) {\n//             if (oldData.get(dimensions[j], i) !== newData.get(dimensions[j], i)) {\n//                 return true;\n//             }\n//         }\n//     }\n\n//     return false;\n// }\n\n// FIXME\n// 公用方法?\nfunction isEmptyValue(val, axisType) {\n    return axisType === 'category'\n        ? val == null\n        : (val == null || isNaN(val)); // axisType === 'value'\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar opacityAccessPath$1 = ['lineStyle', 'normal', 'opacity'];\n\nvar parallelVisual = {\n\n    seriesType: 'parallel',\n\n    reset: function (seriesModel, ecModel, api) {\n\n        var itemStyleModel = seriesModel.getModel('itemStyle');\n        var lineStyleModel = seriesModel.getModel('lineStyle');\n        var globalColors = ecModel.get('color');\n\n        var color = lineStyleModel.get('color')\n            || itemStyleModel.get('color')\n            || globalColors[seriesModel.seriesIndex % globalColors.length];\n        var inactiveOpacity = seriesModel.get('inactiveOpacity');\n        var activeOpacity = seriesModel.get('activeOpacity');\n        var lineStyle = seriesModel.getModel('lineStyle').getLineStyle();\n\n        var coordSys = seriesModel.coordinateSystem;\n        var data = seriesModel.getData();\n\n        var opacityMap = {\n            normal: lineStyle.opacity,\n            active: activeOpacity,\n            inactive: inactiveOpacity\n        };\n\n        data.setVisual('color', color);\n\n        function progress(params, data) {\n            coordSys.eachActiveState(data, function (activeState, dataIndex) {\n                var opacity = opacityMap[activeState];\n                if (activeState === 'normal' && data.hasItemOption) {\n                    var itemOpacity = data.getItemModel(dataIndex).get(opacityAccessPath$1, true);\n                    itemOpacity != null && (opacity = itemOpacity);\n                }\n                data.setItemVisual(dataIndex, 'opacity', opacity);\n            }, params.start, params.end);\n        }\n\n        return {progress: progress};\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(parallelVisual);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Get initial data and define sankey view's series model\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar SankeySeries = SeriesModel.extend({\n\n    type: 'series.sankey',\n\n    layoutInfo: null,\n\n    /**\n     * Init a graph data structure from data in option series\n     *\n     * @param  {Object} option  the object used to config echarts view\n     * @return {module:echarts/data/List} storage initial data\n     */\n    getInitialData: function (option) {\n        var links = option.edges || option.links;\n        var nodes = option.data || option.nodes;\n        if (nodes && links) {\n            var graph = createGraphFromNodeEdge(nodes, links, this, true);\n            return graph.data;\n        }\n    },\n\n    setNodePosition: function (dataIndex, localPosition) {\n        var dataItem = this.option.data[dataIndex];\n        dataItem.localX = localPosition[0];\n        dataItem.localY = localPosition[1];\n    },\n\n    /**\n     * Return the graphic data structure\n     *\n     * @return {module:echarts/data/Graph} graphic data structure\n     */\n    getGraph: function () {\n        return this.getData().graph;\n    },\n\n    /**\n     * Get edge data of graphic data structure\n     *\n     * @return {module:echarts/data/List} data structure of list\n     */\n    getEdgeData: function () {\n        return this.getGraph().edgeData;\n    },\n\n    /**\n     * @override\n     */\n    formatTooltip: function (dataIndex, multipleSeries, dataType) {\n        // dataType === 'node' or empty do not show tooltip by default\n        if (dataType === 'edge') {\n            var params = this.getDataParams(dataIndex, dataType);\n            var rawDataOpt = params.data;\n            var html = rawDataOpt.source + ' -- ' + rawDataOpt.target;\n            if (params.value) {\n                html += ' : ' + params.value;\n            }\n            return encodeHTML(html);\n        }\n\n        return SankeySeries.superCall(this, 'formatTooltip', dataIndex, multipleSeries);\n    },\n\n    optionUpdated: function () {\n        var option = this.option;\n        if (option.focusNodeAdjacency === true) {\n            option.focusNodeAdjacency = 'allEdges';\n        }\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n\n        coordinateSystem: 'view',\n\n        layout: null,\n\n        // The position of the whole view\n        left: '5%',\n        top: '5%',\n        right: '20%',\n        bottom: '5%',\n\n        // Value can be 'vertical'\n        orient: 'horizontal',\n\n        // The dx of the node\n        nodeWidth: 20,\n\n        // The vertical distance between two nodes\n        nodeGap: 8,\n\n        // Control if the node can move or not\n        draggable: true,\n\n        // Value can be 'inEdges', 'outEdges', 'allEdges', true (the same as 'allEdges').\n        focusNodeAdjacency: false,\n\n        // The number of iterations to change the position of the node\n        layoutIterations: 32,\n\n        label: {\n            show: true,\n            position: 'right',\n            color: '#000',\n            fontSize: 12\n        },\n\n        itemStyle: {\n            borderWidth: 1,\n            borderColor: '#333'\n        },\n\n        lineStyle: {\n            color: '#314656',\n            opacity: 0.2,\n            curveness: 0.5\n        },\n\n        emphasis: {\n            label: {\n                show: true\n            },\n            lineStyle: {\n                opacity: 0.6\n            }\n        },\n\n        animationEasing: 'linear',\n\n        animationDuration: 1000\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file  The file used to draw sankey view\n * @author  Deqing Li(annong035@gmail.com)\n */\n\nvar nodeOpacityPath$1 = ['itemStyle', 'opacity'];\nvar lineOpacityPath$1 = ['lineStyle', 'opacity'];\n\nfunction getItemOpacity$1(item, opacityPath) {\n    return item.getVisual('opacity') || item.getModel().get(opacityPath);\n}\n\nfunction fadeOutItem$1(item, opacityPath, opacityRatio) {\n    var el = item.getGraphicEl();\n\n    var opacity = getItemOpacity$1(item, opacityPath);\n    if (opacityRatio != null) {\n        opacity == null && (opacity = 1);\n        opacity *= opacityRatio;\n    }\n\n    el.downplay && el.downplay();\n    el.traverse(function (child) {\n        if (child.type !== 'group') {\n            child.setStyle('opacity', opacity);\n        }\n    });\n}\n\nfunction fadeInItem$1(item, opacityPath) {\n    var opacity = getItemOpacity$1(item, opacityPath);\n    var el = item.getGraphicEl();\n\n    el.highlight && el.highlight();\n    el.traverse(function (child) {\n        if (child.type !== 'group') {\n            child.setStyle('opacity', opacity);\n        }\n    });\n}\n\nvar SankeyShape = extendShape({\n    shape: {\n        x1: 0, y1: 0,\n        x2: 0, y2: 0,\n        cpx1: 0, cpy1: 0,\n        cpx2: 0, cpy2: 0,\n        extent: 0,\n        orient: ''\n    },\n\n    buildPath: function (ctx, shape) {\n        var extent = shape.extent;\n        var orient = shape.orient;\n        if (orient === 'vertical') {\n            ctx.moveTo(shape.x1, shape.y1);\n            ctx.bezierCurveTo(\n                shape.cpx1, shape.cpy1,\n                shape.cpx2, shape.cpy2,\n                shape.x2, shape.y2\n            );\n            ctx.lineTo(shape.x2 + extent, shape.y2);\n            ctx.bezierCurveTo(\n                shape.cpx2 + extent, shape.cpy2,\n                shape.cpx1 + extent, shape.cpy1,\n                shape.x1 + extent, shape.y1\n            );\n        }\n        else {\n            ctx.moveTo(shape.x1, shape.y1);\n            ctx.bezierCurveTo(\n                shape.cpx1, shape.cpy1,\n                shape.cpx2, shape.cpy2,\n                shape.x2, shape.y2\n            );\n            ctx.lineTo(shape.x2, shape.y2 + extent);\n            ctx.bezierCurveTo(\n                shape.cpx2, shape.cpy2 + extent,\n                shape.cpx1, shape.cpy1 + extent,\n                shape.x1, shape.y1 + extent\n            );\n        }\n        ctx.closePath();\n    }\n});\n\nextendChartView({\n\n    type: 'sankey',\n\n    /**\n     * @private\n     * @type {module:echarts/chart/sankey/SankeySeries}\n     */\n    _model: null,\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    _focusAdjacencyDisabled: false,\n\n    render: function (seriesModel, ecModel, api) {\n        var sankeyView = this;\n        var graph = seriesModel.getGraph();\n        var group = this.group;\n        var layoutInfo = seriesModel.layoutInfo;\n        // view width\n        var width = layoutInfo.width;\n        // view height\n        var height = layoutInfo.height;\n        var nodeData = seriesModel.getData();\n        var edgeData = seriesModel.getData('edge');\n        var orient = seriesModel.get('orient');\n\n        this._model = seriesModel;\n\n        group.removeAll();\n\n        group.attr('position', [layoutInfo.x, layoutInfo.y]);\n\n        // generate a bezire Curve for each edge\n        graph.eachEdge(function (edge) {\n            var curve = new SankeyShape();\n            curve.dataIndex = edge.dataIndex;\n            curve.seriesIndex = seriesModel.seriesIndex;\n            curve.dataType = 'edge';\n            var lineStyleModel = edge.getModel('lineStyle');\n            var curvature = lineStyleModel.get('curveness');\n            var n1Layout = edge.node1.getLayout();\n            var node1Model = edge.node1.getModel();\n            var dragX1 = node1Model.get('localX');\n            var dragY1 = node1Model.get('localY');\n            var n2Layout = edge.node2.getLayout();\n            var node2Model = edge.node2.getModel();\n            var dragX2 = node2Model.get('localX');\n            var dragY2 = node2Model.get('localY');\n            var edgeLayout = edge.getLayout();\n            var x1;\n            var y1;\n            var x2;\n            var y2;\n            var cpx1;\n            var cpy1;\n            var cpx2;\n            var cpy2;\n\n            curve.shape.extent = Math.max(1, edgeLayout.dy);\n            curve.shape.orient = orient;\n\n            if (orient === 'vertical') {\n                x1 = (dragX1 != null ? dragX1 * width : n1Layout.x) + edgeLayout.sy;\n                y1 = (dragY1 != null ? dragY1 * height : n1Layout.y) + n1Layout.dy;\n                x2 = (dragX2 != null ? dragX2 * width : n2Layout.x) + edgeLayout.ty;\n                y2 = dragY2 != null ? dragY2 * height : n2Layout.y;\n                cpx1 = x1;\n                cpy1 = y1 * (1 - curvature) + y2 * curvature;\n                cpx2 = x2;\n                cpy2 = y1 * curvature + y2 * (1 - curvature);\n            }\n            else {\n                x1 = (dragX1 != null ? dragX1 * width : n1Layout.x) + n1Layout.dx;\n                y1 = (dragY1 != null ? dragY1 * height : n1Layout.y) + edgeLayout.sy;\n                x2 = dragX2 != null ? dragX2 * width : n2Layout.x;\n                y2 = (dragY2 != null ? dragY2 * height : n2Layout.y) + edgeLayout.ty;\n                cpx1 = x1 * (1 - curvature) + x2 * curvature;\n                cpy1 = y1;\n                cpx2 = x1 * curvature + x2 * (1 - curvature);\n                cpy2 = y2;\n            }\n\n            curve.setShape({\n                x1: x1,\n                y1: y1,\n                x2: x2,\n                y2: y2,\n                cpx1: cpx1,\n                cpy1: cpy1,\n                cpx2: cpx2,\n                cpy2: cpy2\n            });\n\n            curve.setStyle(lineStyleModel.getItemStyle());\n            // Special color, use source node color or target node color\n            switch (curve.style.fill) {\n                case 'source':\n                    curve.style.fill = edge.node1.getVisual('color');\n                    break;\n                case 'target':\n                    curve.style.fill = edge.node2.getVisual('color');\n                    break;\n            }\n\n            setHoverStyle(curve, edge.getModel('emphasis.lineStyle').getItemStyle());\n\n            group.add(curve);\n\n            edgeData.setItemGraphicEl(edge.dataIndex, curve);\n        });\n\n        // Generate a rect for each node\n        graph.eachNode(function (node) {\n            var layout = node.getLayout();\n            var itemModel = node.getModel();\n            var dragX = itemModel.get('localX');\n            var dragY = itemModel.get('localY');\n            var labelModel = itemModel.getModel('label');\n            var labelHoverModel = itemModel.getModel('emphasis.label');\n\n            var rect = new Rect({\n                shape: {\n                    x: dragX != null ? dragX * width : layout.x,\n                    y: dragY != null ? dragY * height : layout.y,\n                    width: layout.dx,\n                    height: layout.dy\n                },\n                style: itemModel.getModel('itemStyle').getItemStyle()\n            });\n\n            var hoverStyle = node.getModel('emphasis.itemStyle').getItemStyle();\n\n            setLabelStyle(\n                rect.style, hoverStyle, labelModel, labelHoverModel,\n                {\n                    labelFetcher: seriesModel,\n                    labelDataIndex: node.dataIndex,\n                    defaultText: node.id,\n                    isRectText: true\n                }\n            );\n\n            rect.setStyle('fill', node.getVisual('color'));\n\n            setHoverStyle(rect, hoverStyle);\n\n            group.add(rect);\n\n            nodeData.setItemGraphicEl(node.dataIndex, rect);\n\n            rect.dataType = 'node';\n        });\n\n        nodeData.eachItemGraphicEl(function (el, dataIndex) {\n            var itemModel = nodeData.getItemModel(dataIndex);\n            if (itemModel.get('draggable')) {\n                el.drift = function (dx, dy) {\n                    sankeyView._focusAdjacencyDisabled = true;\n                    this.shape.x += dx;\n                    this.shape.y += dy;\n                    this.dirty();\n                    api.dispatchAction({\n                        type: 'dragNode',\n                        seriesId: seriesModel.id,\n                        dataIndex: nodeData.getRawIndex(dataIndex),\n                        localX: this.shape.x / width,\n                        localY: this.shape.y / height\n                    });\n                };\n                el.ondragend = function () {\n                    sankeyView._focusAdjacencyDisabled = false;\n                };\n                el.draggable = true;\n                el.cursor = 'move';\n            }\n\n            if (itemModel.get('focusNodeAdjacency')) {\n                el.off('mouseover').on('mouseover', function () {\n                    if (!sankeyView._focusAdjacencyDisabled) {\n                        api.dispatchAction({\n                            type: 'focusNodeAdjacency',\n                            seriesId: seriesModel.id,\n                            dataIndex: el.dataIndex\n                        });\n                    }\n                });\n                el.off('mouseout').on('mouseout', function () {\n                    if (!sankeyView._focusAdjacencyDisabled) {\n                        api.dispatchAction({\n                            type: 'unfocusNodeAdjacency',\n                            seriesId: seriesModel.id\n                        });\n                    }\n                });\n            }\n        });\n\n        edgeData.eachItemGraphicEl(function (el, dataIndex) {\n            var edgeModel = edgeData.getItemModel(dataIndex);\n            if (edgeModel.get('focusNodeAdjacency')) {\n                el.off('mouseover').on('mouseover', function () {\n                    if (!sankeyView._focusAdjacencyDisabled) {\n                        api.dispatchAction({\n                            type: 'focusNodeAdjacency',\n                            seriesId: seriesModel.id,\n                            edgeDataIndex: el.dataIndex\n                        });\n                    }\n                });\n                el.off('mouseout').on('mouseout', function () {\n                    if (!sankeyView._focusAdjacencyDisabled) {\n                        api.dispatchAction({\n                            type: 'unfocusNodeAdjacency',\n                            seriesId: seriesModel.id\n                        });\n                    }\n                });\n            }\n        });\n\n        if (!this._data && seriesModel.get('animation')) {\n            group.setClipPath(createGridClipShape$2(group.getBoundingRect(), seriesModel, function () {\n                group.removeClipPath();\n            }));\n        }\n\n        this._data = seriesModel.getData();\n    },\n\n    dispose: function () {},\n\n    focusNodeAdjacency: function (seriesModel, ecModel, api, payload) {\n        var data = this._model.getData();\n        var graph = data.graph;\n        var dataIndex = payload.dataIndex;\n        var itemModel = data.getItemModel(dataIndex);\n        var edgeDataIndex = payload.edgeDataIndex;\n\n        if (dataIndex == null && edgeDataIndex == null) {\n            return;\n        }\n        var node = graph.getNodeByIndex(dataIndex);\n        var edge = graph.getEdgeByIndex(edgeDataIndex);\n\n        graph.eachNode(function (node) {\n            fadeOutItem$1(node, nodeOpacityPath$1, 0.1);\n        });\n        graph.eachEdge(function (edge) {\n            fadeOutItem$1(edge, lineOpacityPath$1, 0.1);\n        });\n\n        if (node) {\n            fadeInItem$1(node, nodeOpacityPath$1);\n            var focusNodeAdj = itemModel.get('focusNodeAdjacency');\n            if (focusNodeAdj === 'outEdges') {\n                each$1(node.outEdges, function (edge) {\n                    if (edge.dataIndex < 0) {\n                        return;\n                    }\n                    fadeInItem$1(edge, lineOpacityPath$1);\n                    fadeInItem$1(edge.node2, nodeOpacityPath$1);\n                });\n            }\n            else if (focusNodeAdj === 'inEdges') {\n                each$1(node.inEdges, function (edge) {\n                    if (edge.dataIndex < 0) {\n                        return;\n                    }\n                    fadeInItem$1(edge, lineOpacityPath$1);\n                    fadeInItem$1(edge.node1, nodeOpacityPath$1);\n                });\n            }\n            else if (focusNodeAdj === 'allEdges') {\n                each$1(node.edges, function (edge) {\n                    if (edge.dataIndex < 0) {\n                        return;\n                    }\n                    fadeInItem$1(edge, lineOpacityPath$1);\n                    fadeInItem$1(edge.node1, nodeOpacityPath$1);\n                    fadeInItem$1(edge.node2, nodeOpacityPath$1);\n                });\n            }\n        }\n        if (edge) {\n            fadeInItem$1(edge, lineOpacityPath$1);\n            fadeInItem$1(edge.node1, nodeOpacityPath$1);\n            fadeInItem$1(edge.node2, nodeOpacityPath$1);\n        }\n    },\n\n    unfocusNodeAdjacency: function (seriesModel, ecModel, api, payload) {\n        var graph = this._model.getGraph();\n\n        graph.eachNode(function (node) {\n            fadeOutItem$1(node, nodeOpacityPath$1);\n        });\n        graph.eachEdge(function (edge) {\n            fadeOutItem$1(edge, lineOpacityPath$1);\n        });\n    }\n});\n\n// Add animation to the view\nfunction createGridClipShape$2(rect, seriesModel, cb) {\n    var rectEl = new Rect({\n        shape: {\n            x: rect.x - 10,\n            y: rect.y - 10,\n            width: 0,\n            height: rect.height + 20\n        }\n    });\n    initProps(rectEl, {\n        shape: {\n            width: rect.width + 20,\n            height: rect.height + 20\n        }\n    }, seriesModel, cb);\n\n    return rectEl;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file The interactive action of sankey view\n * @author Deqing Li(annong035@gmail.com)\n */\n\nregisterAction({\n    type: 'dragNode',\n    event: 'dragNode',\n    // here can only use 'update' now, other value is not support in echarts.\n    update: 'update'\n}, function (payload, ecModel) {\n    ecModel.eachComponent({mainType: 'series', subType: 'sankey', query: payload}, function (seriesModel) {\n        seriesModel.setNodePosition(payload.dataIndex, [payload.localX, payload.localY]);\n    });\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file The layout algorithm of sankey view\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar sankeyLayout = function (ecModel, api, payload) {\n\n    ecModel.eachSeriesByType('sankey', function (seriesModel) {\n\n        var nodeWidth = seriesModel.get('nodeWidth');\n        var nodeGap = seriesModel.get('nodeGap');\n\n        var layoutInfo = getViewRect$3(seriesModel, api);\n\n        seriesModel.layoutInfo = layoutInfo;\n\n        var width = layoutInfo.width;\n        var height = layoutInfo.height;\n\n        var graph = seriesModel.getGraph();\n\n        var nodes = graph.nodes;\n        var edges = graph.edges;\n\n        computeNodeValues(nodes);\n\n        var filteredNodes = filter(nodes, function (node) {\n            return node.getLayout().value === 0;\n        });\n\n        var iterations = filteredNodes.length !== 0\n            ? 0 : seriesModel.get('layoutIterations');\n\n        var orient = seriesModel.get('orient');\n\n        layoutSankey(nodes, edges, nodeWidth, nodeGap, width, height, iterations, orient);\n    });\n};\n\n/**\n * Get the layout position of the whole view\n *\n * @param {module:echarts/model/Series} seriesModel  the model object of sankey series\n * @param {module:echarts/ExtensionAPI} api  provide the API list that the developer can call\n * @return {module:zrender/core/BoundingRect}  size of rect to draw the sankey view\n */\nfunction getViewRect$3(seriesModel, api) {\n    return getLayoutRect(\n        seriesModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        }\n    );\n}\n\nfunction layoutSankey(nodes, edges, nodeWidth, nodeGap, width, height, iterations, orient) {\n    computeNodeBreadths(nodes, edges, nodeWidth, width, height, orient);\n    computeNodeDepths(nodes, edges, height, width, nodeGap, iterations, orient);\n    computeEdgeDepths(nodes, orient);\n}\n\n/**\n * Compute the value of each node by summing the associated edge's value\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n */\nfunction computeNodeValues(nodes) {\n    each$1(nodes, function (node) {\n        var value1 = sum(node.outEdges, getEdgeValue);\n        var value2 = sum(node.inEdges, getEdgeValue);\n        var value = Math.max(value1, value2);\n        node.setLayout({value: value}, true);\n    });\n}\n\n/**\n * Compute the x-position for each node.\n *\n * Here we use Kahn algorithm to detect cycle when we traverse\n * the node to computer the initial x position.\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param  {number} nodeWidth  the dx of the node\n * @param  {number} width  the whole width of the area to draw the view\n */\nfunction computeNodeBreadths(nodes, edges, nodeWidth, width, height, orient) {\n    // Used to mark whether the edge is deleted. if it is deleted,\n    // the value is 0, otherwise it is 1.\n    var remainEdges = [];\n\n    // Storage each node's indegree.\n    var indegreeArr = [];\n\n    //Used to storage the node with indegree is equal to 0.\n    var zeroIndegrees = [];\n\n    var nextNode = [];\n    var x = 0;\n    var kx = 0;\n\n    for (var i = 0; i < edges.length; i++) {\n        remainEdges[i] = 1;\n    }\n\n    for (i = 0; i < nodes.length; i++) {\n        indegreeArr[i] = nodes[i].inEdges.length;\n        if (indegreeArr[i] === 0) {\n            zeroIndegrees.push(nodes[i]);\n        }\n    }\n\n    while (zeroIndegrees.length) {\n        for (var idx = 0; idx < zeroIndegrees.length; idx++) {\n            var node = zeroIndegrees[idx];\n            if (orient === 'vertical') {\n                node.setLayout({y: x}, true);\n                node.setLayout({dy: nodeWidth}, true);\n            }\n            else {\n                node.setLayout({x: x}, true);\n                node.setLayout({dx: nodeWidth}, true);\n            }\n            for (var oidx = 0; oidx < node.outEdges.length; oidx++) {\n                var edge = node.outEdges[oidx];\n                var indexEdge = edges.indexOf(edge);\n                remainEdges[indexEdge] = 0;\n                var targetNode = edge.node2;\n                var nodeIndex = nodes.indexOf(targetNode);\n                if (--indegreeArr[nodeIndex] === 0) {\n                    nextNode.push(targetNode);\n                }\n            }\n        }\n        ++x;\n        zeroIndegrees = nextNode;\n        nextNode = [];\n    }\n\n    for (i = 0; i < remainEdges.length; i++) {\n        if (__DEV__) {\n            if (remainEdges[i] === 1) {\n                throw new Error('Sankey is a DAG, the original data has cycle!');\n            }\n        }\n    }\n\n    moveSinksRight(nodes, x, orient);\n\n    if (orient === 'vertical') {\n        kx = (height - nodeWidth) / (x - 1);\n    }\n    else {\n        kx = (width - nodeWidth) / (x - 1);\n    }\n    scaleNodeBreadths(nodes, kx, orient);\n}\n\n/**\n * All the node without outEgdes are assigned maximum x-position and\n *     be aligned in the last column.\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param {number} x  value (x-1) use to assign to node without outEdges\n *     as x-position\n */\nfunction moveSinksRight(nodes, x, orient) {\n    each$1(nodes, function (node) {\n        if (!node.outEdges.length) {\n            if (orient === 'vertical') {\n                node.setLayout({y: x - 1}, true);\n            }\n            else {\n                node.setLayout({x: x - 1}, true);\n            }\n        }\n    });\n}\n\n/**\n * Scale node x-position to the width\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param {number} kx   multiple used to scale nodes\n */\nfunction scaleNodeBreadths(nodes, kx, orient) {\n    each$1(nodes, function (node) {\n        if (orient === 'vertical') {\n            var nodeY = node.getLayout().y * kx;\n            node.setLayout({y: nodeY}, true);\n        }\n        else {\n            var nodeX = node.getLayout().x * kx;\n            node.setLayout({x: nodeX}, true);\n        }\n    });\n}\n\n/**\n * Using Gauss-Seidel iterations method to compute the node depth(y-position)\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param {module:echarts/data/Graph~Edge} edges  edge of sankey view\n * @param {number} height  the whole height of the area to draw the view\n * @param {number} nodeGap  the vertical distance between two nodes\n *     in the same column.\n * @param {number} iterations  the number of iterations for the algorithm\n */\nfunction computeNodeDepths(nodes, edges, height, width, nodeGap, iterations, orient) {\n    var nodesByBreadth = prepareNodesByBreadth(nodes, orient);\n\n    initializeNodeDepth(nodes, nodesByBreadth, edges, height, width, nodeGap, orient);\n    resolveCollisions(nodesByBreadth, nodeGap, height, width, orient);\n\n    for (var alpha = 1; iterations > 0; iterations--) {\n        // 0.99 is a experience parameter, ensure that each iterations of\n        // changes as small as possible.\n        alpha *= 0.99;\n        relaxRightToLeft(nodesByBreadth, alpha, orient);\n        resolveCollisions(nodesByBreadth, nodeGap, height, width, orient);\n        relaxLeftToRight(nodesByBreadth, alpha, orient);\n        resolveCollisions(nodesByBreadth, nodeGap, height, width, orient);\n    }\n}\n\nfunction prepareNodesByBreadth(nodes, orient) {\n    var nodesByBreadth = [];\n    var keyAttr = orient === 'vertical' ? 'y' : 'x';\n\n    var groupResult = groupData(nodes, function (node) {\n        return node.getLayout()[keyAttr];\n    });\n    groupResult.keys.sort(function (a, b) {\n        return a - b;\n    });\n    each$1(groupResult.keys, function (key) {\n        nodesByBreadth.push(groupResult.buckets.get(key));\n    });\n\n    return nodesByBreadth;\n}\n\n/**\n * Compute the original y-position for each node\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth\n *     group by the array of all sankey nodes based on the nodes x-position.\n * @param {module:echarts/data/Graph~Edge} edges  edge of sankey view\n * @param {number} height  the whole height of the area to draw the view\n * @param {number} nodeGap  the vertical distance between two nodes\n */\nfunction initializeNodeDepth(nodes, nodesByBreadth, edges, height, width, nodeGap, orient) {\n    var kyArray = [];\n    each$1(nodesByBreadth, function (nodes) {\n        var n = nodes.length;\n        var sum = 0;\n        var ky = 0;\n        each$1(nodes, function (node) {\n            sum += node.getLayout().value;\n        });\n        if (orient === 'vertical') {\n            ky = (width - (n - 1) * nodeGap) / sum;\n        }\n        else {\n            ky = (height - (n - 1) * nodeGap) / sum;\n        }\n        kyArray.push(ky);\n    });\n\n    kyArray.sort(function (a, b) {\n        return a - b;\n    });\n    var ky0 = kyArray[0];\n\n    each$1(nodesByBreadth, function (nodes) {\n        each$1(nodes, function (node, i) {\n            var nodeDy = node.getLayout().value * ky0;\n            if (orient === 'vertical') {\n                node.setLayout({x: i}, true);\n                node.setLayout({dx: nodeDy}, true);\n            }\n            else {\n                node.setLayout({y: i}, true);\n                node.setLayout({dy: nodeDy}, true);\n            }\n\n        });\n    });\n\n    each$1(edges, function (edge) {\n        var edgeDy = +edge.getValue() * ky0;\n        edge.setLayout({dy: edgeDy}, true);\n    });\n}\n\n/**\n * Resolve the collision of initialized depth (y-position)\n *\n * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth\n *     group by the array of all sankey nodes based on the nodes x-position.\n * @param {number} nodeGap  the vertical distance between two nodes\n * @param {number} height  the whole height of the area to draw the view\n */\nfunction resolveCollisions(nodesByBreadth, nodeGap, height, width, orient) {\n    each$1(nodesByBreadth, function (nodes) {\n        var node;\n        var dy;\n        var y0 = 0;\n        var n = nodes.length;\n        var i;\n\n        if (orient === 'vertical') {\n            var nodeX;\n            nodes.sort(function (a, b) {\n                return a.getLayout().x - b.getLayout().x;\n            });\n            for (i = 0; i < n; i++) {\n                node = nodes[i];\n                dy = y0 - node.getLayout().x;\n                if (dy > 0) {\n                    nodeX = node.getLayout().x + dy;\n                    node.setLayout({x: nodeX}, true);\n                }\n                y0 = node.getLayout().x + node.getLayout().dx + nodeGap;\n            }\n            // If the bottommost node goes outside the bounds, push it back up\n            dy = y0 - nodeGap - width;\n            if (dy > 0) {\n                nodeX = node.getLayout().x - dy;\n                node.setLayout({x: nodeX}, true);\n                y0 = nodeX;\n                for (i = n - 2; i >= 0; --i) {\n                    node = nodes[i];\n                    dy = node.getLayout().x + node.getLayout().dx + nodeGap - y0;\n                    if (dy > 0) {\n                        nodeX = node.getLayout().x - dy;\n                        node.setLayout({x: nodeX}, true);\n                    }\n                    y0 = node.getLayout().x;\n                }\n            }\n        }\n        else {\n            var nodeY;\n            nodes.sort(function (a, b) {\n                return a.getLayout().y - b.getLayout().y;\n            });\n            for (i = 0; i < n; i++) {\n                node = nodes[i];\n                dy = y0 - node.getLayout().y;\n                if (dy > 0) {\n                    nodeY = node.getLayout().y + dy;\n                    node.setLayout({y: nodeY}, true);\n                }\n                y0 = node.getLayout().y + node.getLayout().dy + nodeGap;\n            }\n            // If the bottommost node goes outside the bounds, push it back up\n            dy = y0 - nodeGap - height;\n            if (dy > 0) {\n                nodeY = node.getLayout().y - dy;\n                node.setLayout({y: nodeY}, true);\n                y0 = nodeY;\n                for (i = n - 2; i >= 0; --i) {\n                    node = nodes[i];\n                    dy = node.getLayout().y + node.getLayout().dy + nodeGap - y0;\n                    if (dy > 0) {\n                        nodeY = node.getLayout().y - dy;\n                        node.setLayout({y: nodeY}, true);\n                    }\n                    y0 = node.getLayout().y;\n                }\n            }\n        }\n    });\n}\n\n/**\n * Change the y-position of the nodes, except most the right side nodes\n *\n * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth\n *     group by the array of all sankey nodes based on the node x-position.\n * @param {number} alpha  parameter used to adjust the nodes y-position\n */\nfunction relaxRightToLeft(nodesByBreadth, alpha, orient) {\n    each$1(nodesByBreadth.slice().reverse(), function (nodes) {\n        each$1(nodes, function (node) {\n            if (node.outEdges.length) {\n                var y = sum(node.outEdges, weightedTarget, orient) / sum(node.outEdges, getEdgeValue, orient);\n                if (orient === 'vertical') {\n                    var nodeX = node.getLayout().x + (y - center$1(node, orient)) * alpha;\n                    node.setLayout({x: nodeX}, true);\n                }\n                else {\n                    var nodeY = node.getLayout().y + (y - center$1(node, orient)) * alpha;\n                    node.setLayout({y: nodeY}, true);\n                }\n            }\n        });\n    });\n}\n\nfunction weightedTarget(edge, orient) {\n    return center$1(edge.node2, orient) * edge.getValue();\n}\n\nfunction weightedSource(edge, orient) {\n    return center$1(edge.node1, orient) * edge.getValue();\n}\n\nfunction center$1(node, orient) {\n    if (orient === 'vertical') {\n        return node.getLayout().x + node.getLayout().dx / 2;\n    }\n    return node.getLayout().y + node.getLayout().dy / 2;\n}\n\nfunction getEdgeValue(edge) {\n    return edge.getValue();\n}\n\nfunction sum(array, f, orient) {\n    var sum = 0;\n    var len = array.length;\n    var i = -1;\n    while (++i < len) {\n        var value = +f.call(array, array[i], orient);\n        if (!isNaN(value)) {\n            sum += value;\n        }\n    }\n    return sum;\n}\n\n/**\n * Change the y-position of the nodes, except most the left side nodes\n *\n * @param {Array.<Array.<module:echarts/data/Graph~Node>>} nodesByBreadth\n *     group by the array of all sankey nodes based on the node x-position.\n * @param {number} alpha  parameter used to adjust the nodes y-position\n */\nfunction relaxLeftToRight(nodesByBreadth, alpha, orient) {\n    each$1(nodesByBreadth, function (nodes) {\n        each$1(nodes, function (node) {\n            if (node.inEdges.length) {\n                var y = sum(node.inEdges, weightedSource, orient) / sum(node.inEdges, getEdgeValue, orient);\n                if (orient === 'vertical') {\n                    var nodeX = node.getLayout().x + (y - center$1(node, orient)) * alpha;\n                    node.setLayout({x: nodeX}, true);\n                }\n                else {\n                    var nodeY = node.getLayout().y + (y - center$1(node, orient)) * alpha;\n                    node.setLayout({y: nodeY}, true);\n                }\n            }\n        });\n    });\n}\n\n/**\n * Compute the depth(y-position) of each edge\n *\n * @param {module:echarts/data/Graph~Node} nodes  node of sankey view\n */\nfunction computeEdgeDepths(nodes, orient) {\n    each$1(nodes, function (node) {\n        if (orient === 'vertical') {\n            node.outEdges.sort(function (a, b) {\n                return a.node2.getLayout().x - b.node2.getLayout().x;\n            });\n            node.inEdges.sort(function (a, b) {\n                return a.node1.getLayout().x - b.node1.getLayout().x;\n            });\n        }\n        else {\n            node.outEdges.sort(function (a, b) {\n                return a.node2.getLayout().y - b.node2.getLayout().y;\n            });\n            node.inEdges.sort(function (a, b) {\n                return a.node1.getLayout().y - b.node1.getLayout().y;\n            });\n        }\n    });\n    each$1(nodes, function (node) {\n        var sy = 0;\n        var ty = 0;\n        each$1(node.outEdges, function (edge) {\n            edge.setLayout({sy: sy}, true);\n            sy += edge.getLayout().dy;\n        });\n        each$1(node.inEdges, function (edge) {\n            edge.setLayout({ty: ty}, true);\n            ty += edge.getLayout().dy;\n        });\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Visual encoding for sankey view\n * @author  Deqing Li(annong035@gmail.com)\n */\n\nvar sankeyVisual = function (ecModel, payload) {\n    ecModel.eachSeriesByType('sankey', function (seriesModel) {\n        var graph = seriesModel.getGraph();\n        var nodes = graph.nodes;\n        if (nodes.length) {\n            var minValue = Infinity;\n            var maxValue = -Infinity;\n            each$1(nodes, function (node) {\n                var nodeValue = node.getLayout().value;\n                if (nodeValue < minValue) {\n                    minValue = nodeValue;\n                }\n                if (nodeValue > maxValue) {\n                    maxValue = nodeValue;\n                }\n            });\n\n            each$1(nodes, function (node) {\n                var mapping = new VisualMapping({\n                    type: 'color',\n                    mappingMethod: 'linear',\n                    dataExtent: [minValue, maxValue],\n                    visual: seriesModel.get('color')\n                });\n\n                var mapValueToColor = mapping.mapValueToVisual(node.getLayout().value);\n                node.setVisual('color', mapValueToColor);\n                // If set itemStyle.normal.color\n                var itemModel = node.getModel();\n                var customColor = itemModel.get('itemStyle.color');\n                if (customColor != null) {\n                    node.setVisual('color', customColor);\n                }\n            });\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterLayout(sankeyLayout);\nregisterVisual(sankeyVisual);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar seriesModelMixin = {\n\n    /**\n     * @private\n     * @type {string}\n     */\n    _baseAxisDim: null,\n\n    /**\n     * @override\n     */\n    getInitialData: function (option, ecModel) {\n        // When both types of xAxis and yAxis are 'value', layout is\n        // needed to be specified by user. Otherwise, layout can be\n        // judged by which axis is category.\n\n        var ordinalMeta;\n\n        var xAxisModel = ecModel.getComponent('xAxis', this.get('xAxisIndex'));\n        var yAxisModel = ecModel.getComponent('yAxis', this.get('yAxisIndex'));\n        var xAxisType = xAxisModel.get('type');\n        var yAxisType = yAxisModel.get('type');\n        var addOrdinal;\n\n        // FIXME\n        // 考虑时间轴\n\n        if (xAxisType === 'category') {\n            option.layout = 'horizontal';\n            ordinalMeta = xAxisModel.getOrdinalMeta();\n            addOrdinal = true;\n        }\n        else if (yAxisType === 'category') {\n            option.layout = 'vertical';\n            ordinalMeta = yAxisModel.getOrdinalMeta();\n            addOrdinal = true;\n        }\n        else {\n            option.layout = option.layout || 'horizontal';\n        }\n\n        var coordDims = ['x', 'y'];\n        var baseAxisDimIndex = option.layout === 'horizontal' ? 0 : 1;\n        var baseAxisDim = this._baseAxisDim = coordDims[baseAxisDimIndex];\n        var otherAxisDim = coordDims[1 - baseAxisDimIndex];\n        var axisModels = [xAxisModel, yAxisModel];\n        var baseAxisType = axisModels[baseAxisDimIndex].get('type');\n        var otherAxisType = axisModels[1 - baseAxisDimIndex].get('type');\n        var data = option.data;\n\n        // ??? FIXME make a stage to perform data transfrom.\n        // MUST create a new data, consider setOption({}) again.\n        if (data && addOrdinal) {\n            var newOptionData = [];\n            each$1(data, function (item, index) {\n                var newItem;\n                if (item.value && isArray(item.value)) {\n                    newItem = item.value.slice();\n                    item.value.unshift(index);\n                }\n                else if (isArray(item)) {\n                    newItem = item.slice();\n                    item.unshift(index);\n                }\n                else {\n                    newItem = item;\n                }\n                newOptionData.push(newItem);\n            });\n            option.data = newOptionData;\n        }\n\n        var defaultValueDimensions = this.defaultValueDimensions;\n\n        return createListSimply(\n            this,\n            {\n                coordDimensions: [{\n                    name: baseAxisDim,\n                    type: getDimensionTypeByAxis(baseAxisType),\n                    ordinalMeta: ordinalMeta,\n                    otherDims: {\n                        tooltip: false,\n                        itemName: 0\n                    },\n                    dimsDef: ['base']\n                }, {\n                    name: otherAxisDim,\n                    type: getDimensionTypeByAxis(otherAxisType),\n                    dimsDef: defaultValueDimensions.slice()\n                }],\n                dimensionsCount: defaultValueDimensions.length + 1\n            }\n        );\n    },\n\n    /**\n     * If horizontal, base axis is x, otherwise y.\n     * @override\n     */\n    getBaseAxis: function () {\n        var dim = this._baseAxisDim;\n        return this.ecModel.getComponent(dim + 'Axis', this.get(dim + 'AxisIndex')).axis;\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BoxplotSeries = SeriesModel.extend({\n\n    type: 'series.boxplot',\n\n    dependencies: ['xAxis', 'yAxis', 'grid'],\n\n    // TODO\n    // box width represents group size, so dimension should have 'size'.\n\n    /**\n     * @see <https://en.wikipedia.org/wiki/Box_plot>\n     * The meanings of 'min' and 'max' depend on user,\n     * and echarts do not need to know it.\n     * @readOnly\n     */\n    defaultValueDimensions: [\n        {name: 'min', defaultTooltip: true},\n        {name: 'Q1', defaultTooltip: true},\n        {name: 'median', defaultTooltip: true},\n        {name: 'Q3', defaultTooltip: true},\n        {name: 'max', defaultTooltip: true}\n    ],\n\n    /**\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: null,\n\n    /**\n     * @override\n     */\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        layout: null,               // 'horizontal' or 'vertical'\n        boxWidth: [7, 50],       // [min, max] can be percent of band width.\n\n        itemStyle: {\n            color: '#fff',\n            borderWidth: 1\n        },\n\n        emphasis: {\n            itemStyle: {\n                borderWidth: 2,\n                shadowBlur: 5,\n                shadowOffsetX: 2,\n                shadowOffsetY: 2,\n                shadowColor: 'rgba(0,0,0,0.4)'\n            }\n        },\n\n        animationEasing: 'elasticOut',\n        animationDuration: 800\n    }\n});\n\nmixin(BoxplotSeries, seriesModelMixin, true);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Update common properties\nvar NORMAL_ITEM_STYLE_PATH = ['itemStyle'];\nvar EMPHASIS_ITEM_STYLE_PATH = ['emphasis', 'itemStyle'];\n\nvar BoxplotView = Chart.extend({\n\n    type: 'boxplot',\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var group = this.group;\n        var oldData = this._data;\n\n        // There is no old data only when first rendering or switching from\n        // stream mode to normal mode, where previous elements should be removed.\n        if (!this._data) {\n            group.removeAll();\n        }\n\n        var constDim = seriesModel.get('layout') === 'horizontal' ? 1 : 0;\n\n        data.diff(oldData)\n            .add(function (newIdx) {\n                if (data.hasValue(newIdx)) {\n                    var itemLayout = data.getItemLayout(newIdx);\n                    var symbolEl = createNormalBox(itemLayout, data, newIdx, constDim, true);\n                    data.setItemGraphicEl(newIdx, symbolEl);\n                    group.add(symbolEl);\n                }\n            })\n            .update(function (newIdx, oldIdx) {\n                var symbolEl = oldData.getItemGraphicEl(oldIdx);\n\n                // Empty data\n                if (!data.hasValue(newIdx)) {\n                    group.remove(symbolEl);\n                    return;\n                }\n\n                var itemLayout = data.getItemLayout(newIdx);\n                if (!symbolEl) {\n                    symbolEl = createNormalBox(itemLayout, data, newIdx, constDim);\n                }\n                else {\n                    updateNormalBoxData(itemLayout, symbolEl, data, newIdx);\n                }\n\n                group.add(symbolEl);\n\n                data.setItemGraphicEl(newIdx, symbolEl);\n            })\n            .remove(function (oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n                el && group.remove(el);\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    remove: function (ecModel) {\n        var group = this.group;\n        var data = this._data;\n        this._data = null;\n        data && data.eachItemGraphicEl(function (el) {\n            el && group.remove(el);\n        });\n    },\n\n    dispose: noop\n\n});\n\n\nvar BoxPath = Path.extend({\n\n    type: 'boxplotBoxPath',\n\n    shape: {},\n\n    buildPath: function (ctx, shape) {\n        var ends = shape.points;\n\n        var i = 0;\n        ctx.moveTo(ends[i][0], ends[i][1]);\n        i++;\n        for (; i < 4; i++) {\n            ctx.lineTo(ends[i][0], ends[i][1]);\n        }\n        ctx.closePath();\n\n        for (; i < ends.length; i++) {\n            ctx.moveTo(ends[i][0], ends[i][1]);\n            i++;\n            ctx.lineTo(ends[i][0], ends[i][1]);\n        }\n    }\n});\n\n\nfunction createNormalBox(itemLayout, data, dataIndex, constDim, isInit) {\n    var ends = itemLayout.ends;\n\n    var el = new BoxPath({\n        shape: {\n            points: isInit\n                ? transInit(ends, constDim, itemLayout)\n                : ends\n        }\n    });\n\n    updateNormalBoxData(itemLayout, el, data, dataIndex, isInit);\n\n    return el;\n}\n\nfunction updateNormalBoxData(itemLayout, el, data, dataIndex, isInit) {\n    var seriesModel = data.hostModel;\n    var updateMethod = graphic[isInit ? 'initProps' : 'updateProps'];\n\n    updateMethod(\n        el,\n        {shape: {points: itemLayout.ends}},\n        seriesModel,\n        dataIndex\n    );\n\n    var itemModel = data.getItemModel(dataIndex);\n    var normalItemStyleModel = itemModel.getModel(NORMAL_ITEM_STYLE_PATH);\n    var borderColor = data.getItemVisual(dataIndex, 'color');\n\n    // Exclude borderColor.\n    var itemStyle = normalItemStyleModel.getItemStyle(['borderColor']);\n    itemStyle.stroke = borderColor;\n    itemStyle.strokeNoScale = true;\n    el.useStyle(itemStyle);\n\n    el.z2 = 100;\n\n    var hoverStyle = itemModel.getModel(EMPHASIS_ITEM_STYLE_PATH).getItemStyle();\n    setHoverStyle(el, hoverStyle);\n}\n\nfunction transInit(points, dim, itemLayout) {\n    return map(points, function (point) {\n        point = point.slice();\n        point[dim] = itemLayout.initBaseline;\n        return point;\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar borderColorQuery = ['itemStyle', 'borderColor'];\n\nvar boxplotVisual = function (ecModel, api) {\n\n    var globalColors = ecModel.get('color');\n\n    ecModel.eachRawSeriesByType('boxplot', function (seriesModel) {\n\n        var defaulColor = globalColors[seriesModel.seriesIndex % globalColors.length];\n        var data = seriesModel.getData();\n\n        data.setVisual({\n            legendSymbol: 'roundRect',\n            // Use name 'color' but not 'borderColor' for legend usage and\n            // visual coding from other component like dataRange.\n            color: seriesModel.get(borderColorQuery) || defaulColor\n        });\n\n        // Only visible series has each data be visual encoded\n        if (!ecModel.isSeriesFiltered(seriesModel)) {\n            data.each(function (idx) {\n                var itemModel = data.getItemModel(idx);\n                data.setItemVisual(\n                    idx,\n                    {color: itemModel.get(borderColorQuery, true)}\n                );\n            });\n        }\n    });\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$13 = each$1;\n\nvar boxplotLayout = function (ecModel) {\n\n    var groupResult = groupSeriesByAxis(ecModel);\n\n    each$13(groupResult, function (groupItem) {\n        var seriesModels = groupItem.seriesModels;\n\n        if (!seriesModels.length) {\n            return;\n        }\n\n        calculateBase(groupItem);\n\n        each$13(seriesModels, function (seriesModel, idx) {\n            layoutSingleSeries(\n                seriesModel,\n                groupItem.boxOffsetList[idx],\n                groupItem.boxWidthList[idx]\n            );\n        });\n    });\n};\n\n/**\n * Group series by axis.\n */\nfunction groupSeriesByAxis(ecModel) {\n    var result = [];\n    var axisList = [];\n\n    ecModel.eachSeriesByType('boxplot', function (seriesModel) {\n        var baseAxis = seriesModel.getBaseAxis();\n        var idx = indexOf(axisList, baseAxis);\n\n        if (idx < 0) {\n            idx = axisList.length;\n            axisList[idx] = baseAxis;\n            result[idx] = {axis: baseAxis, seriesModels: []};\n        }\n\n        result[idx].seriesModels.push(seriesModel);\n    });\n\n    return result;\n}\n\n/**\n * Calculate offset and box width for each series.\n */\nfunction calculateBase(groupItem) {\n    var extent;\n    var baseAxis = groupItem.axis;\n    var seriesModels = groupItem.seriesModels;\n    var seriesCount = seriesModels.length;\n\n    var boxWidthList = groupItem.boxWidthList = [];\n    var boxOffsetList = groupItem.boxOffsetList = [];\n    var boundList = [];\n\n    var bandWidth;\n    if (baseAxis.type === 'category') {\n        bandWidth = baseAxis.getBandWidth();\n    }\n    else {\n        var maxDataCount = 0;\n        each$13(seriesModels, function (seriesModel) {\n            maxDataCount = Math.max(maxDataCount, seriesModel.getData().count());\n        });\n        extent = baseAxis.getExtent(),\n        Math.abs(extent[1] - extent[0]) / maxDataCount;\n    }\n\n    each$13(seriesModels, function (seriesModel) {\n        var boxWidthBound = seriesModel.get('boxWidth');\n        if (!isArray(boxWidthBound)) {\n            boxWidthBound = [boxWidthBound, boxWidthBound];\n        }\n        boundList.push([\n            parsePercent$1(boxWidthBound[0], bandWidth) || 0,\n            parsePercent$1(boxWidthBound[1], bandWidth) || 0\n        ]);\n    });\n\n    var availableWidth = bandWidth * 0.8 - 2;\n    var boxGap = availableWidth / seriesCount * 0.3;\n    var boxWidth = (availableWidth - boxGap * (seriesCount - 1)) / seriesCount;\n    var base = boxWidth / 2 - availableWidth / 2;\n\n    each$13(seriesModels, function (seriesModel, idx) {\n        boxOffsetList.push(base);\n        base += boxGap + boxWidth;\n\n        boxWidthList.push(\n            Math.min(Math.max(boxWidth, boundList[idx][0]), boundList[idx][1])\n        );\n    });\n}\n\n/**\n * Calculate points location for each series.\n */\nfunction layoutSingleSeries(seriesModel, offset, boxWidth) {\n    var coordSys = seriesModel.coordinateSystem;\n    var data = seriesModel.getData();\n    var halfWidth = boxWidth / 2;\n    var cDimIdx = seriesModel.get('layout') === 'horizontal' ? 0 : 1;\n    var vDimIdx = 1 - cDimIdx;\n    var coordDims = ['x', 'y'];\n    var cDim = data.mapDimension(coordDims[cDimIdx]);\n    var vDims = data.mapDimension(coordDims[vDimIdx], true);\n\n    if (cDim == null || vDims.length < 5) {\n        return;\n    }\n\n    for (var dataIndex = 0; dataIndex < data.count(); dataIndex++) {\n        var axisDimVal = data.get(cDim, dataIndex);\n\n        var median = getPoint(axisDimVal, vDims[2], dataIndex);\n        var end1 = getPoint(axisDimVal, vDims[0], dataIndex);\n        var end2 = getPoint(axisDimVal, vDims[1], dataIndex);\n        var end4 = getPoint(axisDimVal, vDims[3], dataIndex);\n        var end5 = getPoint(axisDimVal, vDims[4], dataIndex);\n\n        var ends = [];\n        addBodyEnd(ends, end2, 0);\n        addBodyEnd(ends, end4, 1);\n\n        ends.push(end1, end2, end5, end4);\n        layEndLine(ends, end1);\n        layEndLine(ends, end5);\n        layEndLine(ends, median);\n\n        data.setItemLayout(dataIndex, {\n            initBaseline: median[vDimIdx],\n            ends: ends\n        });\n    }\n\n    function getPoint(axisDimVal, dimIdx, dataIndex) {\n        var val = data.get(dimIdx, dataIndex);\n        var p = [];\n        p[cDimIdx] = axisDimVal;\n        p[vDimIdx] = val;\n        var point;\n        if (isNaN(axisDimVal) || isNaN(val)) {\n            point = [NaN, NaN];\n        }\n        else {\n            point = coordSys.dataToPoint(p);\n            point[cDimIdx] += offset;\n        }\n        return point;\n    }\n\n    function addBodyEnd(ends, point, start) {\n        var point1 = point.slice();\n        var point2 = point.slice();\n        point1[cDimIdx] += halfWidth;\n        point2[cDimIdx] -= halfWidth;\n        start\n            ? ends.push(point1, point2)\n            : ends.push(point2, point1);\n    }\n\n    function layEndLine(ends, endCenter) {\n        var from = endCenter.slice();\n        var to = endCenter.slice();\n        from[cDimIdx] -= halfWidth;\n        to[cDimIdx] += halfWidth;\n        ends.push(from, to);\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(boxplotVisual);\nregisterLayout(boxplotLayout);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar CandlestickSeries = SeriesModel.extend({\n\n    type: 'series.candlestick',\n\n    dependencies: ['xAxis', 'yAxis', 'grid'],\n\n    /**\n     * @readOnly\n     */\n    defaultValueDimensions: [\n        {name: 'open', defaultTooltip: true},\n        {name: 'close', defaultTooltip: true},\n        {name: 'lowest', defaultTooltip: true},\n        {name: 'highest', defaultTooltip: true}\n    ],\n\n    /**\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: null,\n\n    /**\n     * @override\n     */\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        layout: null, // 'horizontal' or 'vertical'\n\n        itemStyle: {\n            color: '#c23531', // 阳线 positive\n            color0: '#314656', // 阴线 negative     '#c23531', '#314656'\n            borderWidth: 1,\n            // FIXME\n            // ec2中使用的是lineStyle.color 和 lineStyle.color0\n            borderColor: '#c23531',\n            borderColor0: '#314656'\n        },\n\n        emphasis: {\n            itemStyle: {\n                borderWidth: 2\n            }\n        },\n\n        barMaxWidth: null,\n        barMinWidth: null,\n        barWidth: null,\n\n        large: true,\n        largeThreshold: 600,\n\n        progressive: 3e3,\n        progressiveThreshold: 1e4,\n        progressiveChunkMode: 'mod',\n\n        animationUpdate: false,\n        animationEasing: 'linear',\n        animationDuration: 300\n    },\n\n    /**\n     * Get dimension for shadow in dataZoom\n     * @return {string} dimension name\n     */\n    getShadowDim: function () {\n        return 'open';\n    },\n\n    brushSelector: function (dataIndex, data, selectors) {\n        var itemLayout = data.getItemLayout(dataIndex);\n        return itemLayout && selectors.rect(itemLayout.brushRect);\n    }\n\n});\n\nmixin(CandlestickSeries, seriesModelMixin, true);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar NORMAL_ITEM_STYLE_PATH$1 = ['itemStyle'];\nvar EMPHASIS_ITEM_STYLE_PATH$1 = ['emphasis', 'itemStyle'];\nvar SKIP_PROPS = ['color', 'color0', 'borderColor', 'borderColor0'];\n\n\nvar CandlestickView = Chart.extend({\n\n    type: 'candlestick',\n\n    render: function (seriesModel, ecModel, api) {\n        this._updateDrawMode(seriesModel);\n\n        this._isLargeDraw\n            ? this._renderLarge(seriesModel)\n            : this._renderNormal(seriesModel);\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this._clear();\n        this._updateDrawMode(seriesModel);\n    },\n\n    incrementalRender: function (params, seriesModel, ecModel, api) {\n        this._isLargeDraw\n             ? this._incrementalRenderLarge(params, seriesModel)\n             : this._incrementalRenderNormal(params, seriesModel);\n    },\n\n    _updateDrawMode: function (seriesModel) {\n        var isLargeDraw = seriesModel.pipelineContext.large;\n        if (this._isLargeDraw == null || isLargeDraw ^ this._isLargeDraw) {\n            this._isLargeDraw = isLargeDraw;\n            this._clear();\n        }\n    },\n\n    _renderNormal: function (seriesModel) {\n        var data = seriesModel.getData();\n        var oldData = this._data;\n        var group = this.group;\n        var isSimpleBox = data.getLayout('isSimpleBox');\n\n        // There is no old data only when first rendering or switching from\n        // stream mode to normal mode, where previous elements should be removed.\n        if (!this._data) {\n            group.removeAll();\n        }\n\n        data.diff(oldData)\n            .add(function (newIdx) {\n                if (data.hasValue(newIdx)) {\n                    var el;\n\n                    var itemLayout = data.getItemLayout(newIdx);\n                    el = createNormalBox$1(itemLayout, newIdx, true);\n                    initProps(el, {shape: {points: itemLayout.ends}}, seriesModel, newIdx);\n\n                    setBoxCommon(el, data, newIdx, isSimpleBox);\n\n                    group.add(el);\n                    data.setItemGraphicEl(newIdx, el);\n                }\n            })\n            .update(function (newIdx, oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n\n                // Empty data\n                if (!data.hasValue(newIdx)) {\n                    group.remove(el);\n                    return;\n                }\n\n                var itemLayout = data.getItemLayout(newIdx);\n                if (!el) {\n                    el = createNormalBox$1(itemLayout, newIdx);\n                }\n                else {\n                    updateProps(el, {shape: {points: itemLayout.ends}}, seriesModel, newIdx);\n                }\n\n                setBoxCommon(el, data, newIdx, isSimpleBox);\n\n                group.add(el);\n                data.setItemGraphicEl(newIdx, el);\n            })\n            .remove(function (oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n                el && group.remove(el);\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    _renderLarge: function (seriesModel) {\n        this._clear();\n        createLarge$1(seriesModel, this.group);\n    },\n\n    _incrementalRenderNormal: function (params, seriesModel) {\n        var data = seriesModel.getData();\n        var isSimpleBox = data.getLayout('isSimpleBox');\n\n        var dataIndex;\n        while ((dataIndex = params.next()) != null) {\n            var el;\n\n            var itemLayout = data.getItemLayout(dataIndex);\n            el = createNormalBox$1(itemLayout, dataIndex);\n            setBoxCommon(el, data, dataIndex, isSimpleBox);\n\n            el.incremental = true;\n            this.group.add(el);\n        }\n    },\n\n    _incrementalRenderLarge: function (params, seriesModel) {\n        createLarge$1(seriesModel, this.group, true);\n    },\n\n    remove: function (ecModel) {\n        this._clear();\n    },\n\n    _clear: function () {\n        this.group.removeAll();\n        this._data = null;\n    },\n\n    dispose: noop\n\n});\n\n\nvar NormalBoxPath = Path.extend({\n\n    type: 'normalCandlestickBox',\n\n    shape: {},\n\n    buildPath: function (ctx, shape) {\n        var ends = shape.points;\n\n        if (this.__simpleBox) {\n            ctx.moveTo(ends[4][0], ends[4][1]);\n            ctx.lineTo(ends[6][0], ends[6][1]);\n        }\n        else {\n            ctx.moveTo(ends[0][0], ends[0][1]);\n            ctx.lineTo(ends[1][0], ends[1][1]);\n            ctx.lineTo(ends[2][0], ends[2][1]);\n            ctx.lineTo(ends[3][0], ends[3][1]);\n            ctx.closePath();\n\n            ctx.moveTo(ends[4][0], ends[4][1]);\n            ctx.lineTo(ends[5][0], ends[5][1]);\n            ctx.moveTo(ends[6][0], ends[6][1]);\n            ctx.lineTo(ends[7][0], ends[7][1]);\n        }\n    }\n});\n\nfunction createNormalBox$1(itemLayout, dataIndex, isInit) {\n    var ends = itemLayout.ends;\n    return new NormalBoxPath({\n        shape: {\n            points: isInit\n                ? transInit$1(ends, itemLayout)\n                : ends\n        },\n        z2: 100\n    });\n}\n\nfunction setBoxCommon(el, data, dataIndex, isSimpleBox) {\n    var itemModel = data.getItemModel(dataIndex);\n    var normalItemStyleModel = itemModel.getModel(NORMAL_ITEM_STYLE_PATH$1);\n    var color = data.getItemVisual(dataIndex, 'color');\n    var borderColor = data.getItemVisual(dataIndex, 'borderColor') || color;\n\n    // Color must be excluded.\n    // Because symbol provide setColor individually to set fill and stroke\n    var itemStyle = normalItemStyleModel.getItemStyle(SKIP_PROPS);\n\n    el.useStyle(itemStyle);\n    el.style.strokeNoScale = true;\n    el.style.fill = color;\n    el.style.stroke = borderColor;\n\n    el.__simpleBox = isSimpleBox;\n\n    var hoverStyle = itemModel.getModel(EMPHASIS_ITEM_STYLE_PATH$1).getItemStyle();\n    setHoverStyle(el, hoverStyle);\n}\n\nfunction transInit$1(points, itemLayout) {\n    return map(points, function (point) {\n        point = point.slice();\n        point[1] = itemLayout.initBaseline;\n        return point;\n    });\n}\n\n\n\nvar LargeBoxPath = Path.extend({\n\n    type: 'largeCandlestickBox',\n\n    shape: {},\n\n    buildPath: function (ctx, shape) {\n        // Drawing lines is more efficient than drawing\n        // a whole line or drawing rects.\n        var points = shape.points;\n        for (var i = 0; i < points.length;) {\n            if (this.__sign === points[i++]) {\n                var x = points[i++];\n                ctx.moveTo(x, points[i++]);\n                ctx.lineTo(x, points[i++]);\n            }\n            else {\n                i += 3;\n            }\n        }\n    }\n});\n\nfunction createLarge$1(seriesModel, group, incremental) {\n    var data = seriesModel.getData();\n    var largePoints = data.getLayout('largePoints');\n\n    var elP = new LargeBoxPath({\n        shape: {points: largePoints},\n        __sign: 1\n    });\n    group.add(elP);\n    var elN = new LargeBoxPath({\n        shape: {points: largePoints},\n        __sign: -1\n    });\n    group.add(elN);\n\n    setLargeStyle$1(1, elP, seriesModel, data);\n    setLargeStyle$1(-1, elN, seriesModel, data);\n\n    if (incremental) {\n        elP.incremental = true;\n        elN.incremental = true;\n    }\n}\n\nfunction setLargeStyle$1(sign, el, seriesModel, data) {\n    var suffix = sign > 0 ? 'P' : 'N';\n    var borderColor = data.getVisual('borderColor' + suffix)\n        || data.getVisual('color' + suffix);\n\n    // Color must be excluded.\n    // Because symbol provide setColor individually to set fill and stroke\n    var itemStyle = seriesModel.getModel(NORMAL_ITEM_STYLE_PATH$1).getItemStyle(SKIP_PROPS);\n\n    el.useStyle(itemStyle);\n    el.style.fill = null;\n    el.style.stroke = borderColor;\n    // No different\n    // el.style.lineWidth = .5;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar preprocessor = function (option) {\n    if (!option || !isArray(option.series)) {\n        return;\n    }\n\n    // Translate 'k' to 'candlestick'.\n    each$1(option.series, function (seriesItem) {\n        if (isObject$1(seriesItem) && seriesItem.type === 'k') {\n            seriesItem.type = 'candlestick';\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar positiveBorderColorQuery = ['itemStyle', 'borderColor'];\nvar negativeBorderColorQuery = ['itemStyle', 'borderColor0'];\nvar positiveColorQuery = ['itemStyle', 'color'];\nvar negativeColorQuery = ['itemStyle', 'color0'];\n\nvar candlestickVisual = {\n\n    seriesType: 'candlestick',\n\n    plan: createRenderPlanner(),\n\n    // For legend.\n    performRawSeries: true,\n\n    reset: function (seriesModel, ecModel) {\n\n        var data = seriesModel.getData();\n        var isLargeRender = seriesModel.pipelineContext.large;\n\n        data.setVisual({\n            legendSymbol: 'roundRect',\n            colorP: getColor(1, seriesModel),\n            colorN: getColor(-1, seriesModel),\n            borderColorP: getBorderColor(1, seriesModel),\n            borderColorN: getBorderColor(-1, seriesModel)\n        });\n\n        // Only visible series has each data be visual encoded\n        if (ecModel.isSeriesFiltered(seriesModel)) {\n            return;\n        }\n\n        return !isLargeRender && {progress: progress};\n\n\n        function progress(params, data) {\n            var dataIndex;\n            while ((dataIndex = params.next()) != null) {\n                var itemModel = data.getItemModel(dataIndex);\n                var sign = data.getItemLayout(dataIndex).sign;\n\n                data.setItemVisual(\n                    dataIndex,\n                    {\n                        color: getColor(sign, itemModel),\n                        borderColor: getBorderColor(sign, itemModel)\n                    }\n                );\n            }\n        }\n\n        function getColor(sign, model) {\n            return model.get(\n                sign > 0 ? positiveColorQuery : negativeColorQuery\n            );\n        }\n\n        function getBorderColor(sign, model) {\n            return model.get(\n                sign > 0 ? positiveBorderColorQuery : negativeBorderColorQuery\n            );\n        }\n\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar LargeArr$1 = typeof Float32Array !== 'undefined' ? Float32Array : Array;\n\nvar candlestickLayout = {\n\n    seriesType: 'candlestick',\n\n    plan: createRenderPlanner(),\n\n    reset: function (seriesModel) {\n\n        var coordSys = seriesModel.coordinateSystem;\n        var data = seriesModel.getData();\n        var candleWidth = calculateCandleWidth(seriesModel, data);\n        var cDimIdx = 0;\n        var vDimIdx = 1;\n        var coordDims = ['x', 'y'];\n        var cDim = data.mapDimension(coordDims[cDimIdx]);\n        var vDims = data.mapDimension(coordDims[vDimIdx], true);\n        var openDim = vDims[0];\n        var closeDim = vDims[1];\n        var lowestDim = vDims[2];\n        var highestDim = vDims[3];\n\n        data.setLayout({\n            candleWidth: candleWidth,\n            // The value is experimented visually.\n            isSimpleBox: candleWidth <= 1.3\n        });\n\n        if (cDim == null || vDims.length < 4) {\n            return;\n        }\n\n        return {\n            progress: seriesModel.pipelineContext.large\n                ? largeProgress : normalProgress\n        };\n\n        function normalProgress(params, data) {\n            var dataIndex;\n            while ((dataIndex = params.next()) != null) {\n\n                var axisDimVal = data.get(cDim, dataIndex);\n                var openVal = data.get(openDim, dataIndex);\n                var closeVal = data.get(closeDim, dataIndex);\n                var lowestVal = data.get(lowestDim, dataIndex);\n                var highestVal = data.get(highestDim, dataIndex);\n\n                var ocLow = Math.min(openVal, closeVal);\n                var ocHigh = Math.max(openVal, closeVal);\n\n                var ocLowPoint = getPoint(ocLow, axisDimVal);\n                var ocHighPoint = getPoint(ocHigh, axisDimVal);\n                var lowestPoint = getPoint(lowestVal, axisDimVal);\n                var highestPoint = getPoint(highestVal, axisDimVal);\n\n                var ends = [];\n                addBodyEnd(ends, ocHighPoint, 0);\n                addBodyEnd(ends, ocLowPoint, 1);\n\n                ends.push(\n                    subPixelOptimizePoint(highestPoint),\n                    subPixelOptimizePoint(ocHighPoint),\n                    subPixelOptimizePoint(lowestPoint),\n                    subPixelOptimizePoint(ocLowPoint)\n                );\n\n                data.setItemLayout(dataIndex, {\n                    sign: getSign(data, dataIndex, openVal, closeVal, closeDim),\n                    initBaseline: openVal > closeVal\n                        ? ocHighPoint[vDimIdx] : ocLowPoint[vDimIdx], // open point.\n                    ends: ends,\n                    brushRect: makeBrushRect(lowestVal, highestVal, axisDimVal)\n                });\n            }\n\n            function getPoint(val, axisDimVal) {\n                var p = [];\n                p[cDimIdx] = axisDimVal;\n                p[vDimIdx] = val;\n                return (isNaN(axisDimVal) || isNaN(val))\n                    ? [NaN, NaN]\n                    : coordSys.dataToPoint(p);\n            }\n\n            function addBodyEnd(ends, point, start) {\n                var point1 = point.slice();\n                var point2 = point.slice();\n\n                point1[cDimIdx] = subPixelOptimize(\n                    point1[cDimIdx] + candleWidth / 2, 1, false\n                );\n                point2[cDimIdx] = subPixelOptimize(\n                    point2[cDimIdx] - candleWidth / 2, 1, true\n                );\n\n                start\n                    ? ends.push(point1, point2)\n                    : ends.push(point2, point1);\n            }\n\n            function makeBrushRect(lowestVal, highestVal, axisDimVal) {\n                var pmin = getPoint(lowestVal, axisDimVal);\n                var pmax = getPoint(highestVal, axisDimVal);\n\n                pmin[cDimIdx] -= candleWidth / 2;\n                pmax[cDimIdx] -= candleWidth / 2;\n\n                return {\n                    x: pmin[0],\n                    y: pmin[1],\n                    width: vDimIdx ? candleWidth : pmax[0] - pmin[0],\n                    height: vDimIdx ? pmax[1] - pmin[1] : candleWidth\n                };\n            }\n\n            function subPixelOptimizePoint(point) {\n                point[cDimIdx] = subPixelOptimize(point[cDimIdx], 1);\n                return point;\n            }\n        }\n\n        function largeProgress(params, data) {\n            // Structure: [sign, x, yhigh, ylow, sign, x, yhigh, ylow, ...]\n            var points = new LargeArr$1(params.count * 5);\n            var offset = 0;\n            var point;\n            var tmpIn = [];\n            var tmpOut = [];\n            var dataIndex;\n\n            while ((dataIndex = params.next()) != null) {\n                var axisDimVal = data.get(cDim, dataIndex);\n                var openVal = data.get(openDim, dataIndex);\n                var closeVal = data.get(closeDim, dataIndex);\n                var lowestVal = data.get(lowestDim, dataIndex);\n                var highestVal = data.get(highestDim, dataIndex);\n\n                if (isNaN(axisDimVal) || isNaN(lowestVal) || isNaN(highestVal)) {\n                    points[offset++] = NaN;\n                    offset += 4;\n                    continue;\n                }\n\n                points[offset++] = getSign(data, dataIndex, openVal, closeVal, closeDim);\n\n                tmpIn[cDimIdx] = axisDimVal;\n\n                tmpIn[vDimIdx] = lowestVal;\n                point = coordSys.dataToPoint(tmpIn, null, tmpOut);\n                points[offset++] = point ? point[0] : NaN;\n                points[offset++] = point ? point[1] : NaN;\n                tmpIn[vDimIdx] = highestVal;\n                point = coordSys.dataToPoint(tmpIn, null, tmpOut);\n                points[offset++] = point ? point[1] : NaN;\n            }\n\n            data.setLayout('largePoints', points);\n        }\n    }\n};\n\nfunction getSign(data, dataIndex, openVal, closeVal, closeDim) {\n    var sign;\n    if (openVal > closeVal) {\n        sign = -1;\n    }\n    else if (openVal < closeVal) {\n        sign = 1;\n    }\n    else {\n        sign = dataIndex > 0\n            // If close === open, compare with close of last record\n            ? (data.get(closeDim, dataIndex - 1) <= closeVal ? 1 : -1)\n            // No record of previous, set to be positive\n            : 1;\n    }\n\n    return sign;\n}\n\nfunction calculateCandleWidth(seriesModel, data) {\n    var baseAxis = seriesModel.getBaseAxis();\n    var extent;\n\n    var bandWidth = baseAxis.type === 'category'\n        ? baseAxis.getBandWidth()\n        : (\n            extent = baseAxis.getExtent(),\n            Math.abs(extent[1] - extent[0]) / data.count()\n        );\n\n    var barMaxWidth = parsePercent$1(\n        retrieve2(seriesModel.get('barMaxWidth'), bandWidth),\n        bandWidth\n    );\n    var barMinWidth = parsePercent$1(\n        retrieve2(seriesModel.get('barMinWidth'), 1),\n        bandWidth\n    );\n    var barWidth = seriesModel.get('barWidth');\n\n    return barWidth != null\n        ? parsePercent$1(barWidth, bandWidth)\n        // Put max outer to ensure bar visible in spite of overlap.\n        : Math.max(Math.min(bandWidth / 2, barMaxWidth), barMinWidth);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterPreprocessor(preprocessor);\nregisterVisual(candlestickVisual);\nregisterLayout(candlestickLayout);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.effectScatter',\n\n    dependencies: ['grid', 'polar'],\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    brushSelector: 'point',\n\n    defaultOption: {\n        coordinateSystem: 'cartesian2d',\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        effectType: 'ripple',\n\n        progressive: 0,\n\n        // When to show the effect, option: 'render'|'emphasis'\n        showEffectOn: 'render',\n\n        // Ripple effect config\n        rippleEffect: {\n            period: 4,\n            // Scale of ripple\n            scale: 2.5,\n            // Brush type can be fill or stroke\n            brushType: 'fill'\n        },\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // Polar coordinate system\n        // polarIndex: 0,\n\n        // Geo coordinate system\n        // geoIndex: 0,\n\n        // symbol: null,        // 图形类型\n        symbolSize: 10          // 图形大小，半宽（半径）参数，当图形为方向或菱形则总宽度为symbolSize * 2\n        // symbolRotate: null,  // 图形旋转控制\n\n        // large: false,\n        // Available when large is true\n        // largeThreshold: 2000,\n\n        // itemStyle: {\n        //     opacity: 1\n        // }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Symbol with ripple effect\n * @module echarts/chart/helper/EffectSymbol\n */\n\nvar EFFECT_RIPPLE_NUMBER = 3;\n\nfunction normalizeSymbolSize$1(symbolSize) {\n    if (!isArray(symbolSize)) {\n        symbolSize = [+symbolSize, +symbolSize];\n    }\n    return symbolSize;\n}\n\nfunction updateRipplePath(rippleGroup, effectCfg) {\n    rippleGroup.eachChild(function (ripplePath) {\n        ripplePath.attr({\n            z: effectCfg.z,\n            zlevel: effectCfg.zlevel,\n            style: {\n                stroke: effectCfg.brushType === 'stroke' ? effectCfg.color : null,\n                fill: effectCfg.brushType === 'fill' ? effectCfg.color : null\n            }\n        });\n    });\n}\n/**\n * @constructor\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @extends {module:zrender/graphic/Group}\n */\nfunction EffectSymbol(data, idx) {\n    Group.call(this);\n\n    var symbol = new SymbolClz$1(data, idx);\n    var rippleGroup = new Group();\n    this.add(symbol);\n    this.add(rippleGroup);\n\n    rippleGroup.beforeUpdate = function () {\n        this.attr(symbol.getScale());\n    };\n    this.updateData(data, idx);\n}\n\nvar effectSymbolProto = EffectSymbol.prototype;\n\neffectSymbolProto.stopEffectAnimation = function () {\n    this.childAt(1).removeAll();\n};\n\neffectSymbolProto.startEffectAnimation = function (effectCfg) {\n    var symbolType = effectCfg.symbolType;\n    var color = effectCfg.color;\n    var rippleGroup = this.childAt(1);\n\n    for (var i = 0; i < EFFECT_RIPPLE_NUMBER; i++) {\n        // var ripplePath = createSymbol(\n        //     symbolType, -0.5, -0.5, 1, 1, color\n        // );\n        // If width/height are set too small (e.g., set to 1) on ios10\n        // and macOS Sierra, a circle stroke become a rect, no matter what\n        // the scale is set. So we set width/height as 2. See #4136.\n        var ripplePath = createSymbol(\n            symbolType, -1, -1, 2, 2, color\n        );\n        ripplePath.attr({\n            style: {\n                strokeNoScale: true\n            },\n            z2: 99,\n            silent: true,\n            scale: [0.5, 0.5]\n        });\n\n        var delay = -i / EFFECT_RIPPLE_NUMBER * effectCfg.period + effectCfg.effectOffset;\n        // TODO Configurable effectCfg.period\n        ripplePath.animate('', true)\n            .when(effectCfg.period, {\n                scale: [effectCfg.rippleScale / 2, effectCfg.rippleScale / 2]\n            })\n            .delay(delay)\n            .start();\n        ripplePath.animateStyle(true)\n            .when(effectCfg.period, {\n                opacity: 0\n            })\n            .delay(delay)\n            .start();\n\n        rippleGroup.add(ripplePath);\n    }\n\n    updateRipplePath(rippleGroup, effectCfg);\n};\n\n/**\n * Update effect symbol\n */\neffectSymbolProto.updateEffectAnimation = function (effectCfg) {\n    var oldEffectCfg = this._effectCfg;\n    var rippleGroup = this.childAt(1);\n\n    // Must reinitialize effect if following configuration changed\n    var DIFFICULT_PROPS = ['symbolType', 'period', 'rippleScale'];\n    for (var i = 0; i < DIFFICULT_PROPS.length; i++) {\n        var propName = DIFFICULT_PROPS[i];\n        if (oldEffectCfg[propName] !== effectCfg[propName]) {\n            this.stopEffectAnimation();\n            this.startEffectAnimation(effectCfg);\n            return;\n        }\n    }\n\n    updateRipplePath(rippleGroup, effectCfg);\n};\n\n/**\n * Highlight symbol\n */\neffectSymbolProto.highlight = function () {\n    this.trigger('emphasis');\n};\n\n/**\n * Downplay symbol\n */\neffectSymbolProto.downplay = function () {\n    this.trigger('normal');\n};\n\n/**\n * Update symbol properties\n * @param  {module:echarts/data/List} data\n * @param  {number} idx\n */\neffectSymbolProto.updateData = function (data, idx) {\n    var seriesModel = data.hostModel;\n\n    this.childAt(0).updateData(data, idx);\n\n    var rippleGroup = this.childAt(1);\n    var itemModel = data.getItemModel(idx);\n    var symbolType = data.getItemVisual(idx, 'symbol');\n    var symbolSize = normalizeSymbolSize$1(data.getItemVisual(idx, 'symbolSize'));\n    var color = data.getItemVisual(idx, 'color');\n\n    rippleGroup.attr('scale', symbolSize);\n\n    rippleGroup.traverse(function (ripplePath) {\n        ripplePath.attr({\n            fill: color\n        });\n    });\n\n    var symbolOffset = itemModel.getShallow('symbolOffset');\n    if (symbolOffset) {\n        var pos = rippleGroup.position;\n        pos[0] = parsePercent$1(symbolOffset[0], symbolSize[0]);\n        pos[1] = parsePercent$1(symbolOffset[1], symbolSize[1]);\n    }\n    rippleGroup.rotation = (itemModel.getShallow('symbolRotate') || 0) * Math.PI / 180 || 0;\n\n    var effectCfg = {};\n\n    effectCfg.showEffectOn = seriesModel.get('showEffectOn');\n    effectCfg.rippleScale = itemModel.get('rippleEffect.scale');\n    effectCfg.brushType = itemModel.get('rippleEffect.brushType');\n    effectCfg.period = itemModel.get('rippleEffect.period') * 1000;\n    effectCfg.effectOffset = idx / data.count();\n    effectCfg.z = itemModel.getShallow('z') || 0;\n    effectCfg.zlevel = itemModel.getShallow('zlevel') || 0;\n    effectCfg.symbolType = symbolType;\n    effectCfg.color = color;\n\n    this.off('mouseover').off('mouseout').off('emphasis').off('normal');\n\n    if (effectCfg.showEffectOn === 'render') {\n        this._effectCfg\n            ? this.updateEffectAnimation(effectCfg)\n            : this.startEffectAnimation(effectCfg);\n\n        this._effectCfg = effectCfg;\n    }\n    else {\n        // Not keep old effect config\n        this._effectCfg = null;\n\n        this.stopEffectAnimation();\n        var symbol = this.childAt(0);\n        var onEmphasis = function () {\n            symbol.highlight();\n            if (effectCfg.showEffectOn !== 'render') {\n                this.startEffectAnimation(effectCfg);\n            }\n        };\n        var onNormal = function () {\n            symbol.downplay();\n            if (effectCfg.showEffectOn !== 'render') {\n                this.stopEffectAnimation();\n            }\n        };\n        this.on('mouseover', onEmphasis, this)\n            .on('mouseout', onNormal, this)\n            .on('emphasis', onEmphasis, this)\n            .on('normal', onNormal, this);\n    }\n\n    this._effectCfg = effectCfg;\n};\n\neffectSymbolProto.fadeOut = function (cb) {\n    this.off('mouseover').off('mouseout').off('emphasis').off('normal');\n    cb && cb();\n};\n\ninherits(EffectSymbol, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendChartView({\n\n    type: 'effectScatter',\n\n    init: function () {\n        this._symbolDraw = new SymbolDraw(EffectSymbol);\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var effectSymbolDraw = this._symbolDraw;\n        effectSymbolDraw.updateData(data);\n        this.group.add(effectSymbolDraw.group);\n    },\n\n    updateTransform: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        this.group.dirty();\n\n        var res = pointsLayout().reset(seriesModel);\n        if (res.progress) {\n            res.progress({ start: 0, end: data.count() }, data);\n        }\n\n        this._symbolDraw.updateLayout(data);\n    },\n\n    _updateGroupTransform: function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys && coordSys.getRoamTransform) {\n            this.group.transform = clone$2(coordSys.getRoamTransform());\n            this.group.decomposeTransform();\n        }\n    },\n\n    remove: function (ecModel, api) {\n        this._symbolDraw && this._symbolDraw.remove(api);\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(visualSymbol('effectScatter', 'circle'));\nregisterLayout(pointsLayout('effectScatter'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Uint32Array, Float64Array, Float32Array */\n\nvar Uint32Arr = typeof Uint32Array === 'undefined' ? Array : Uint32Array;\nvar Float64Arr = typeof Float64Array === 'undefined' ? Array : Float64Array;\n\nfunction compatEc2(seriesOpt) {\n    var data = seriesOpt.data;\n    if (data && data[0] && data[0][0] && data[0][0].coord) {\n        if (__DEV__) {\n            console.warn('Lines data configuration has been changed to'\n                + ' { coords:[[1,2],[2,3]] }');\n        }\n        seriesOpt.data = map(data, function (itemOpt) {\n            var coords = [\n                itemOpt[0].coord, itemOpt[1].coord\n            ];\n            var target = {\n                coords: coords\n            };\n            if (itemOpt[0].name) {\n                target.fromName = itemOpt[0].name;\n            }\n            if (itemOpt[1].name) {\n                target.toName = itemOpt[1].name;\n            }\n            return mergeAll([target, itemOpt[0], itemOpt[1]]);\n        });\n    }\n}\n\nvar LinesSeries = SeriesModel.extend({\n\n    type: 'series.lines',\n\n    dependencies: ['grid', 'polar'],\n\n    visualColorAccessPath: 'lineStyle.color',\n\n    init: function (option) {\n        // The input data may be null/undefined.\n        option.data = option.data || [];\n\n        // Not using preprocessor because mergeOption may not have series.type\n        compatEc2(option);\n\n        var result = this._processFlatCoordsArray(option.data);\n        this._flatCoords = result.flatCoords;\n        this._flatCoordsOffset = result.flatCoordsOffset;\n        if (result.flatCoords) {\n            option.data = new Float32Array(result.count);\n        }\n\n        LinesSeries.superApply(this, 'init', arguments);\n    },\n\n    mergeOption: function (option) {\n        // The input data may be null/undefined.\n        option.data = option.data || [];\n\n        compatEc2(option);\n\n        if (option.data) {\n            // Only update when have option data to merge.\n            var result = this._processFlatCoordsArray(option.data);\n            this._flatCoords = result.flatCoords;\n            this._flatCoordsOffset = result.flatCoordsOffset;\n            if (result.flatCoords) {\n                option.data = new Float32Array(result.count);\n            }\n        }\n\n        LinesSeries.superApply(this, 'mergeOption', arguments);\n    },\n\n    appendData: function (params) {\n        var result = this._processFlatCoordsArray(params.data);\n        if (result.flatCoords) {\n            if (!this._flatCoords) {\n                this._flatCoords = result.flatCoords;\n                this._flatCoordsOffset = result.flatCoordsOffset;\n            }\n            else {\n                this._flatCoords = concatArray(this._flatCoords, result.flatCoords);\n                this._flatCoordsOffset = concatArray(this._flatCoordsOffset, result.flatCoordsOffset);\n            }\n            params.data = new Float32Array(result.count);\n        }\n\n        this.getRawData().appendData(params.data);\n    },\n\n    _getCoordsFromItemModel: function (idx) {\n        var itemModel = this.getData().getItemModel(idx);\n        var coords = (itemModel.option instanceof Array)\n            ? itemModel.option : itemModel.getShallow('coords');\n\n        if (__DEV__) {\n            if (!(coords instanceof Array && coords.length > 0 && coords[0] instanceof Array)) {\n                throw new Error(\n                    'Invalid coords ' + JSON.stringify(coords) + '. Lines must have 2d coords array in data item.'\n                );\n            }\n        }\n        return coords;\n    },\n\n    getLineCoordsCount: function (idx) {\n        if (this._flatCoordsOffset) {\n            return this._flatCoordsOffset[idx * 2 + 1];\n        }\n        else {\n            return this._getCoordsFromItemModel(idx).length;\n        }\n    },\n\n    getLineCoords: function (idx, out) {\n        if (this._flatCoordsOffset) {\n            var offset = this._flatCoordsOffset[idx * 2];\n            var len = this._flatCoordsOffset[idx * 2 + 1];\n            for (var i = 0; i < len; i++) {\n                out[i] = out[i] || [];\n                out[i][0] = this._flatCoords[offset + i * 2];\n                out[i][1] = this._flatCoords[offset + i * 2 + 1];\n            }\n            return len;\n        }\n        else {\n            var coords = this._getCoordsFromItemModel(idx);\n            for (var i = 0; i < coords.length; i++) {\n                out[i] = out[i] || [];\n                out[i][0] = coords[i][0];\n                out[i][1] = coords[i][1];\n            }\n            return coords.length;\n        }\n    },\n\n    _processFlatCoordsArray: function (data) {\n        var startOffset = 0;\n        if (this._flatCoords) {\n            startOffset = this._flatCoords.length;\n        }\n        // Stored as a typed array. In format\n        // Points Count(2) | x | y | x | y | Points Count(3) | x |  y | x | y | x | y |\n        if (typeof data[0] === 'number') {\n            var len = data.length;\n            // Store offset and len of each segment\n            var coordsOffsetAndLenStorage = new Uint32Arr(len);\n            var coordsStorage = new Float64Arr(len);\n            var coordsCursor = 0;\n            var offsetCursor = 0;\n            var dataCount = 0;\n            for (var i = 0; i < len;) {\n                dataCount++;\n                var count = data[i++];\n                // Offset\n                coordsOffsetAndLenStorage[offsetCursor++] = coordsCursor + startOffset;\n                // Len\n                coordsOffsetAndLenStorage[offsetCursor++] = count;\n                for (var k = 0; k < count; k++) {\n                    var x = data[i++];\n                    var y = data[i++];\n                    coordsStorage[coordsCursor++] = x;\n                    coordsStorage[coordsCursor++] = y;\n\n                    if (i > len) {\n                        if (__DEV__) {\n                            throw new Error('Invalid data format.');\n                        }\n                    }\n                }\n            }\n\n            return {\n                flatCoordsOffset: new Uint32Array(coordsOffsetAndLenStorage.buffer, 0, offsetCursor),\n                flatCoords: coordsStorage,\n                count: dataCount\n            };\n        }\n\n        return {\n            flatCoordsOffset: null,\n            flatCoords: null,\n            count: data.length\n        };\n    },\n\n    getInitialData: function (option, ecModel) {\n        if (__DEV__) {\n            var CoordSys = CoordinateSystemManager.get(option.coordinateSystem);\n            if (!CoordSys) {\n                throw new Error('Unkown coordinate system ' + option.coordinateSystem);\n            }\n        }\n\n        var lineData = new List(['value'], this);\n        lineData.hasItemOption = false;\n\n        lineData.initData(option.data, [], function (dataItem, dimName, dataIndex, dimIndex) {\n            // dataItem is simply coords\n            if (dataItem instanceof Array) {\n                return NaN;\n            }\n            else {\n                lineData.hasItemOption = true;\n                var value = dataItem.value;\n                if (value != null) {\n                    return value instanceof Array ? value[dimIndex] : value;\n                }\n            }\n        });\n\n        return lineData;\n    },\n\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var itemModel = data.getItemModel(dataIndex);\n        var name = itemModel.get('name');\n        if (name) {\n            return name;\n        }\n        var fromName = itemModel.get('fromName');\n        var toName = itemModel.get('toName');\n        var html = [];\n        fromName != null && html.push(fromName);\n        toName != null && html.push(toName);\n\n        return encodeHTML(html.join(' > '));\n    },\n\n    preventIncremental: function () {\n        return !!this.get('effect.show');\n    },\n\n    getProgressive: function () {\n        var progressive = this.option.progressive;\n        if (progressive == null) {\n            return this.option.large ? 1e4 : this.get('progressive');\n        }\n        return progressive;\n    },\n\n    getProgressiveThreshold: function () {\n        var progressiveThreshold = this.option.progressiveThreshold;\n        if (progressiveThreshold == null) {\n            return this.option.large ? 2e4 : this.get('progressiveThreshold');\n        }\n        return progressiveThreshold;\n    },\n\n    defaultOption: {\n        coordinateSystem: 'geo',\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // Cartesian coordinate system\n        xAxisIndex: 0,\n        yAxisIndex: 0,\n\n        symbol: ['none', 'none'],\n        symbolSize: [10, 10],\n        // Geo coordinate system\n        geoIndex: 0,\n\n        effect: {\n            show: false,\n            period: 4,\n            // Animation delay. support callback\n            // delay: 0,\n            // If move with constant speed px/sec\n            // period will be ignored if this property is > 0,\n            constantSpeed: 0,\n            symbol: 'circle',\n            symbolSize: 3,\n            loop: true,\n            // Length of trail, 0 - 1\n            trailLength: 0.2\n            // Same with lineStyle.color\n            // color\n        },\n\n        large: false,\n        // Available when large is true\n        largeThreshold: 2000,\n\n        // If lines are polyline\n        // polyline not support curveness, label, animation\n        polyline: false,\n\n        label: {\n            show: false,\n            position: 'end'\n            // distance: 5,\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n        },\n\n        lineStyle: {\n            opacity: 0.5\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Provide effect for line\n * @module echarts/chart/helper/EffectLine\n */\n\n/**\n * @constructor\n * @extends {module:zrender/graphic/Group}\n * @alias {module:echarts/chart/helper/Line}\n */\nfunction EffectLine(lineData, idx, seriesScope) {\n    Group.call(this);\n\n    this.add(this.createLine(lineData, idx, seriesScope));\n\n    this._updateEffectSymbol(lineData, idx);\n}\n\nvar effectLineProto = EffectLine.prototype;\n\neffectLineProto.createLine = function (lineData, idx, seriesScope) {\n    return new Line$1(lineData, idx, seriesScope);\n};\n\neffectLineProto._updateEffectSymbol = function (lineData, idx) {\n    var itemModel = lineData.getItemModel(idx);\n    var effectModel = itemModel.getModel('effect');\n    var size = effectModel.get('symbolSize');\n    var symbolType = effectModel.get('symbol');\n    if (!isArray(size)) {\n        size = [size, size];\n    }\n    var color = effectModel.get('color') || lineData.getItemVisual(idx, 'color');\n    var symbol = this.childAt(1);\n\n    if (this._symbolType !== symbolType) {\n        // Remove previous\n        this.remove(symbol);\n\n        symbol = createSymbol(\n            symbolType, -0.5, -0.5, 1, 1, color\n        );\n        symbol.z2 = 100;\n        symbol.culling = true;\n\n        this.add(symbol);\n    }\n\n    // Symbol may be removed if loop is false\n    if (!symbol) {\n        return;\n    }\n\n    // Shadow color is same with color in default\n    symbol.setStyle('shadowColor', color);\n    symbol.setStyle(effectModel.getItemStyle(['color']));\n\n    symbol.attr('scale', size);\n\n    symbol.setColor(color);\n    symbol.attr('scale', size);\n\n    this._symbolType = symbolType;\n\n    this._updateEffectAnimation(lineData, effectModel, idx);\n};\n\neffectLineProto._updateEffectAnimation = function (lineData, effectModel, idx) {\n\n    var symbol = this.childAt(1);\n    if (!symbol) {\n        return;\n    }\n\n    var self = this;\n\n    var points = lineData.getItemLayout(idx);\n\n    var period = effectModel.get('period') * 1000;\n    var loop = effectModel.get('loop');\n    var constantSpeed = effectModel.get('constantSpeed');\n    var delayExpr = retrieve(effectModel.get('delay'), function (idx) {\n        return idx / lineData.count() * period / 3;\n    });\n    var isDelayFunc = typeof delayExpr === 'function';\n\n    // Ignore when updating\n    symbol.ignore = true;\n\n    this.updateAnimationPoints(symbol, points);\n\n    if (constantSpeed > 0) {\n        period = this.getLineLength(symbol) / constantSpeed * 1000;\n    }\n\n    if (period !== this._period || loop !== this._loop) {\n\n        symbol.stopAnimation();\n\n        var delay = delayExpr;\n        if (isDelayFunc) {\n            delay = delayExpr(idx);\n        }\n        if (symbol.__t > 0) {\n            delay = -period * symbol.__t;\n        }\n        symbol.__t = 0;\n        var animator = symbol.animate('', loop)\n            .when(period, {\n                __t: 1\n            })\n            .delay(delay)\n            .during(function () {\n                self.updateSymbolPosition(symbol);\n            });\n        if (!loop) {\n            animator.done(function () {\n                self.remove(symbol);\n            });\n        }\n        animator.start();\n    }\n\n    this._period = period;\n    this._loop = loop;\n};\n\neffectLineProto.getLineLength = function (symbol) {\n    // Not so accurate\n    return (dist(symbol.__p1, symbol.__cp1)\n        + dist(symbol.__cp1, symbol.__p2));\n};\n\neffectLineProto.updateAnimationPoints = function (symbol, points) {\n    symbol.__p1 = points[0];\n    symbol.__p2 = points[1];\n    symbol.__cp1 = points[2] || [\n        (points[0][0] + points[1][0]) / 2,\n        (points[0][1] + points[1][1]) / 2\n    ];\n};\n\neffectLineProto.updateData = function (lineData, idx, seriesScope) {\n    this.childAt(0).updateData(lineData, idx, seriesScope);\n    this._updateEffectSymbol(lineData, idx);\n};\n\neffectLineProto.updateSymbolPosition = function (symbol) {\n    var p1 = symbol.__p1;\n    var p2 = symbol.__p2;\n    var cp1 = symbol.__cp1;\n    var t = symbol.__t;\n    var pos = symbol.position;\n    var quadraticAt$$1 = quadraticAt;\n    var quadraticDerivativeAt$$1 = quadraticDerivativeAt;\n    pos[0] = quadraticAt$$1(p1[0], cp1[0], p2[0], t);\n    pos[1] = quadraticAt$$1(p1[1], cp1[1], p2[1], t);\n\n    // Tangent\n    var tx = quadraticDerivativeAt$$1(p1[0], cp1[0], p2[0], t);\n    var ty = quadraticDerivativeAt$$1(p1[1], cp1[1], p2[1], t);\n\n    symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2;\n\n    symbol.ignore = false;\n};\n\n\neffectLineProto.updateLayout = function (lineData, idx) {\n    this.childAt(0).updateLayout(lineData, idx);\n\n    var effectModel = lineData.getItemModel(idx).getModel('effect');\n    this._updateEffectAnimation(lineData, effectModel, idx);\n};\n\ninherits(EffectLine, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Line\n */\n\n/**\n * @constructor\n * @extends {module:zrender/graphic/Group}\n * @alias {module:echarts/chart/helper/Polyline}\n */\nfunction Polyline$2(lineData, idx, seriesScope) {\n    Group.call(this);\n\n    this._createPolyline(lineData, idx, seriesScope);\n}\n\nvar polylineProto = Polyline$2.prototype;\n\npolylineProto._createPolyline = function (lineData, idx, seriesScope) {\n    // var seriesModel = lineData.hostModel;\n    var points = lineData.getItemLayout(idx);\n\n    var line = new Polyline({\n        shape: {\n            points: points\n        }\n    });\n\n    this.add(line);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\npolylineProto.updateData = function (lineData, idx, seriesScope) {\n    var seriesModel = lineData.hostModel;\n\n    var line = this.childAt(0);\n    var target = {\n        shape: {\n            points: lineData.getItemLayout(idx)\n        }\n    };\n    updateProps(line, target, seriesModel, idx);\n\n    this._updateCommonStl(lineData, idx, seriesScope);\n};\n\npolylineProto._updateCommonStl = function (lineData, idx, seriesScope) {\n    var line = this.childAt(0);\n    var itemModel = lineData.getItemModel(idx);\n\n    var visualColor = lineData.getItemVisual(idx, 'color');\n\n    var lineStyle = seriesScope && seriesScope.lineStyle;\n    var hoverLineStyle = seriesScope && seriesScope.hoverLineStyle;\n\n    if (!seriesScope || lineData.hasItemOption) {\n        lineStyle = itemModel.getModel('lineStyle').getLineStyle();\n        hoverLineStyle = itemModel.getModel('emphasis.lineStyle').getLineStyle();\n    }\n    line.useStyle(defaults(\n        {\n            strokeNoScale: true,\n            fill: 'none',\n            stroke: visualColor\n        },\n        lineStyle\n    ));\n    line.hoverStyle = hoverLineStyle;\n\n    setHoverStyle(this);\n};\n\npolylineProto.updateLayout = function (lineData, idx) {\n    var polyline = this.childAt(0);\n    polyline.setShape('points', lineData.getItemLayout(idx));\n};\n\ninherits(Polyline$2, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Provide effect for line\n * @module echarts/chart/helper/EffectLine\n */\n\n/**\n * @constructor\n * @extends {module:echarts/chart/helper/EffectLine}\n * @alias {module:echarts/chart/helper/Polyline}\n */\nfunction EffectPolyline(lineData, idx, seriesScope) {\n    EffectLine.call(this, lineData, idx, seriesScope);\n    this._lastFrame = 0;\n    this._lastFramePercent = 0;\n}\n\nvar effectPolylineProto = EffectPolyline.prototype;\n\n// Overwrite\neffectPolylineProto.createLine = function (lineData, idx, seriesScope) {\n    return new Polyline$2(lineData, idx, seriesScope);\n};\n\n// Overwrite\neffectPolylineProto.updateAnimationPoints = function (symbol, points) {\n    this._points = points;\n    var accLenArr = [0];\n    var len$$1 = 0;\n    for (var i = 1; i < points.length; i++) {\n        var p1 = points[i - 1];\n        var p2 = points[i];\n        len$$1 += dist(p1, p2);\n        accLenArr.push(len$$1);\n    }\n    if (len$$1 === 0) {\n        return;\n    }\n\n    for (var i = 0; i < accLenArr.length; i++) {\n        accLenArr[i] /= len$$1;\n    }\n    this._offsets = accLenArr;\n    this._length = len$$1;\n};\n\n// Overwrite\neffectPolylineProto.getLineLength = function (symbol) {\n    return this._length;\n};\n\n// Overwrite\neffectPolylineProto.updateSymbolPosition = function (symbol) {\n    var t = symbol.__t;\n    var points = this._points;\n    var offsets = this._offsets;\n    var len$$1 = points.length;\n\n    if (!offsets) {\n        // Has length 0\n        return;\n    }\n\n    var lastFrame = this._lastFrame;\n    var frame;\n\n    if (t < this._lastFramePercent) {\n        // Start from the next frame\n        // PENDING start from lastFrame ?\n        var start = Math.min(lastFrame + 1, len$$1 - 1);\n        for (frame = start; frame >= 0; frame--) {\n            if (offsets[frame] <= t) {\n                break;\n            }\n        }\n        // PENDING really need to do this ?\n        frame = Math.min(frame, len$$1 - 2);\n    }\n    else {\n        for (var frame = lastFrame; frame < len$$1; frame++) {\n            if (offsets[frame] > t) {\n                break;\n            }\n        }\n        frame = Math.min(frame - 1, len$$1 - 2);\n    }\n\n    lerp(\n        symbol.position, points[frame], points[frame + 1],\n        (t - offsets[frame]) / (offsets[frame + 1] - offsets[frame])\n    );\n\n    var tx = points[frame + 1][0] - points[frame][0];\n    var ty = points[frame + 1][1] - points[frame][1];\n    symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2;\n\n    this._lastFrame = frame;\n    this._lastFramePercent = t;\n\n    symbol.ignore = false;\n};\n\ninherits(EffectPolyline, EffectLine);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Batch by color\n\nvar LargeLineShape = extendShape({\n\n    shape: {\n        polyline: false,\n        curveness: 0,\n        segs: []\n    },\n\n    buildPath: function (path, shape) {\n        var segs = shape.segs;\n        var curveness = shape.curveness;\n\n        if (shape.polyline) {\n            for (var i = 0; i < segs.length;) {\n                var count = segs[i++];\n                if (count > 0) {\n                    path.moveTo(segs[i++], segs[i++]);\n                    for (var k = 1; k < count; k++) {\n                        path.lineTo(segs[i++], segs[i++]);\n                    }\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < segs.length;) {\n                var x0 = segs[i++];\n                var y0 = segs[i++];\n                var x1 = segs[i++];\n                var y1 = segs[i++];\n                path.moveTo(x0, y0);\n                if (curveness > 0) {\n                    var x2 = (x0 + x1) / 2 - (y0 - y1) * curveness;\n                    var y2 = (y0 + y1) / 2 - (x1 - x0) * curveness;\n                    path.quadraticCurveTo(x2, y2, x1, y1);\n                }\n                else {\n                    path.lineTo(x1, y1);\n                }\n            }\n        }\n    },\n\n    findDataIndex: function (x, y) {\n\n        var shape = this.shape;\n        var segs = shape.segs;\n        var curveness = shape.curveness;\n\n        if (shape.polyline) {\n            var dataIndex = 0;\n            for (var i = 0; i < segs.length;) {\n                var count = segs[i++];\n                if (count > 0) {\n                    var x0 = segs[i++];\n                    var y0 = segs[i++];\n                    for (var k = 1; k < count; k++) {\n                        var x1 = segs[i++];\n                        var y1 = segs[i++];\n                        if (containStroke$1(x0, y0, x1, y1)) {\n                            return dataIndex;\n                        }\n                    }\n                }\n\n                dataIndex++;\n            }\n        }\n        else {\n            var dataIndex = 0;\n            for (var i = 0; i < segs.length;) {\n                var x0 = segs[i++];\n                var y0 = segs[i++];\n                var x1 = segs[i++];\n                var y1 = segs[i++];\n                if (curveness > 0) {\n                    var x2 = (x0 + x1) / 2 - (y0 - y1) * curveness;\n                    var y2 = (y0 + y1) / 2 - (x1 - x0) * curveness;\n\n                    if (containStroke$3(x0, y0, x2, y2, x1, y1)) {\n                        return dataIndex;\n                    }\n                }\n                else {\n                    if (containStroke$1(x0, y0, x1, y1)) {\n                        return dataIndex;\n                    }\n                }\n\n                dataIndex++;\n            }\n        }\n\n        return -1;\n    }\n});\n\nfunction LargeLineDraw() {\n    this.group = new Group();\n}\n\nvar largeLineProto = LargeLineDraw.prototype;\n\nlargeLineProto.isPersistent = function () {\n    return !this._incremental;\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n */\nlargeLineProto.updateData = function (data) {\n    this.group.removeAll();\n\n    var lineEl = new LargeLineShape({\n        rectHover: true,\n        cursor: 'default'\n    });\n    lineEl.setShape({\n        segs: data.getLayout('linesPoints')\n    });\n\n    this._setCommon(lineEl, data);\n\n    // Add back\n    this.group.add(lineEl);\n\n    this._incremental = null;\n};\n\n/**\n * @override\n */\nlargeLineProto.incrementalPrepareUpdate = function (data) {\n    this.group.removeAll();\n\n    this._clearIncremental();\n\n    if (data.count() > 5e5) {\n        if (!this._incremental) {\n            this._incremental = new IncrementalDisplayble({\n                silent: true\n            });\n        }\n        this.group.add(this._incremental);\n    }\n    else {\n        this._incremental = null;\n    }\n};\n\n/**\n * @override\n */\nlargeLineProto.incrementalUpdate = function (taskParams, data) {\n    var lineEl = new LargeLineShape();\n    lineEl.setShape({\n        segs: data.getLayout('linesPoints')\n    });\n\n    this._setCommon(lineEl, data, !!this._incremental);\n\n    if (!this._incremental) {\n        lineEl.rectHover = true;\n        lineEl.cursor = 'default';\n        lineEl.__startIndex = taskParams.start;\n        this.group.add(lineEl);\n    }\n    else {\n        this._incremental.addDisplayable(lineEl, true);\n    }\n};\n\n/**\n * @override\n */\nlargeLineProto.remove = function () {\n    this._clearIncremental();\n    this._incremental = null;\n    this.group.removeAll();\n};\n\nlargeLineProto._setCommon = function (lineEl, data, isIncremental) {\n    var hostModel = data.hostModel;\n\n    lineEl.setShape({\n        polyline: hostModel.get('polyline'),\n        curveness: hostModel.get('lineStyle.curveness')\n    });\n\n    lineEl.useStyle(\n        hostModel.getModel('lineStyle').getLineStyle()\n    );\n    lineEl.style.strokeNoScale = true;\n\n    var visualColor = data.getVisual('color');\n    if (visualColor) {\n        lineEl.setStyle('stroke', visualColor);\n    }\n    lineEl.setStyle('fill');\n\n    if (!isIncremental) {\n        // Enable tooltip\n        // PENDING May have performance issue when path is extremely large\n        lineEl.seriesIndex = hostModel.seriesIndex;\n        lineEl.on('mousemove', function (e) {\n            lineEl.dataIndex = null;\n            var dataIndex = lineEl.findDataIndex(e.offsetX, e.offsetY);\n            if (dataIndex > 0) {\n                // Provide dataIndex for tooltip\n                lineEl.dataIndex = dataIndex + lineEl.__startIndex;\n            }\n        });\n    }\n};\n\nlargeLineProto._clearIncremental = function () {\n    var incremental = this._incremental;\n    if (incremental) {\n        incremental.clearDisplaybles();\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar linesLayout = {\n    seriesType: 'lines',\n\n    plan: createRenderPlanner(),\n\n    reset: function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n        var isPolyline = seriesModel.get('polyline');\n        var isLarge = seriesModel.pipelineContext.large;\n\n        function progress(params, lineData) {\n            var lineCoords = [];\n            if (isLarge) {\n                var points;\n                var segCount = params.end - params.start;\n                if (isPolyline) {\n                    var totalCoordsCount = 0;\n                    for (var i = params.start; i < params.end; i++) {\n                        totalCoordsCount += seriesModel.getLineCoordsCount(i);\n                    }\n                    points = new Float32Array(segCount + totalCoordsCount * 2);\n                }\n                else {\n                    points = new Float32Array(segCount * 4);\n                }\n\n                var offset = 0;\n                var pt = [];\n                for (var i = params.start; i < params.end; i++) {\n                    var len = seriesModel.getLineCoords(i, lineCoords);\n                    if (isPolyline) {\n                        points[offset++] = len;\n                    }\n                    for (var k = 0; k < len; k++) {\n                        pt = coordSys.dataToPoint(lineCoords[k], false, pt);\n                        points[offset++] = pt[0];\n                        points[offset++] = pt[1];\n                    }\n                }\n\n                lineData.setLayout('linesPoints', points);\n            }\n            else {\n                for (var i = params.start; i < params.end; i++) {\n                    var itemModel = lineData.getItemModel(i);\n                    var len = seriesModel.getLineCoords(i, lineCoords);\n\n                    var pts = [];\n                    if (isPolyline) {\n                        for (var j = 0; j < len; j++) {\n                            pts.push(coordSys.dataToPoint(lineCoords[j]));\n                        }\n                    }\n                    else {\n                        pts[0] = coordSys.dataToPoint(lineCoords[0]);\n                        pts[1] = coordSys.dataToPoint(lineCoords[1]);\n\n                        var curveness = itemModel.get('lineStyle.curveness');\n                        if (+curveness) {\n                            pts[2] = [\n                                (pts[0][0] + pts[1][0]) / 2 - (pts[0][1] - pts[1][1]) * curveness,\n                                (pts[0][1] + pts[1][1]) / 2 - (pts[1][0] - pts[0][0]) * curveness\n                            ];\n                        }\n                    }\n                    lineData.setItemLayout(i, pts);\n                }\n            }\n        }\n\n        return { progress: progress };\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendChartView({\n\n    type: 'lines',\n\n    init: function () {},\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        var lineDraw = this._updateLineDraw(data, seriesModel);\n\n        var zlevel = seriesModel.get('zlevel');\n        var trailLength = seriesModel.get('effect.trailLength');\n\n        var zr = api.getZr();\n        // Avoid the drag cause ghost shadow\n        // FIXME Better way ?\n        // SVG doesn't support\n        var isSvg = zr.painter.getType() === 'svg';\n        if (!isSvg) {\n            zr.painter.getLayer(zlevel).clear(true);\n        }\n        // Config layer with motion blur\n        if (this._lastZlevel != null && !isSvg) {\n            zr.configLayer(this._lastZlevel, {\n                motionBlur: false\n            });\n        }\n        if (this._showEffect(seriesModel) && trailLength) {\n            if (__DEV__) {\n                var notInIndividual = false;\n                ecModel.eachSeries(function (otherSeriesModel) {\n                    if (otherSeriesModel !== seriesModel && otherSeriesModel.get('zlevel') === zlevel) {\n                        notInIndividual = true;\n                    }\n                });\n                notInIndividual && console.warn('Lines with trail effect should have an individual zlevel');\n            }\n\n            if (!isSvg) {\n                zr.configLayer(zlevel, {\n                    motionBlur: true,\n                    lastFrameAlpha: Math.max(Math.min(trailLength / 10 + 0.9, 1), 0)\n                });\n            }\n        }\n\n        lineDraw.updateData(data);\n\n        this._lastZlevel = zlevel;\n\n        this._finished = true;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        var lineDraw = this._updateLineDraw(data, seriesModel);\n\n        lineDraw.incrementalPrepareUpdate(data);\n\n        this._clearLayer(api);\n\n        this._finished = false;\n    },\n\n    incrementalRender: function (taskParams, seriesModel, ecModel) {\n        this._lineDraw.incrementalUpdate(taskParams, seriesModel.getData());\n\n        this._finished = taskParams.end === seriesModel.getData().count();\n    },\n\n    updateTransform: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n        var pipelineContext = seriesModel.pipelineContext;\n\n        if (!this._finished || pipelineContext.large || pipelineContext.progressiveRender) {\n            // TODO Don't have to do update in large mode. Only do it when there are millions of data.\n            return {\n                update: true\n            };\n        }\n        else {\n            // TODO Use same logic with ScatterView.\n            // Manually update layout\n            var res = linesLayout.reset(seriesModel);\n            if (res.progress) {\n                res.progress({ start: 0, end: data.count() }, data);\n            }\n            this._lineDraw.updateLayout();\n            this._clearLayer(api);\n        }\n    },\n\n    _updateLineDraw: function (data, seriesModel) {\n        var lineDraw = this._lineDraw;\n        var hasEffect = this._showEffect(seriesModel);\n        var isPolyline = !!seriesModel.get('polyline');\n        var pipelineContext = seriesModel.pipelineContext;\n        var isLargeDraw = pipelineContext.large;\n\n        if (__DEV__) {\n            if (hasEffect && isLargeDraw) {\n                console.warn('Large lines not support effect');\n            }\n        }\n        if (!lineDraw\n            || hasEffect !== this._hasEffet\n            || isPolyline !== this._isPolyline\n            || isLargeDraw !== this._isLargeDraw\n        ) {\n            if (lineDraw) {\n                lineDraw.remove();\n            }\n            lineDraw = this._lineDraw = isLargeDraw\n                ? new LargeLineDraw()\n                : new LineDraw(\n                    isPolyline\n                        ? (hasEffect ? EffectPolyline : Polyline$2)\n                        : (hasEffect ? EffectLine : Line$1)\n                );\n            this._hasEffet = hasEffect;\n            this._isPolyline = isPolyline;\n            this._isLargeDraw = isLargeDraw;\n            this.group.removeAll();\n        }\n\n        this.group.add(lineDraw.group);\n\n        return lineDraw;\n    },\n\n    _showEffect: function (seriesModel) {\n        return !!seriesModel.get('effect.show');\n    },\n\n    _clearLayer: function (api) {\n        // Not use motion when dragging or zooming\n        var zr = api.getZr();\n        var isSvg = zr.painter.getType() === 'svg';\n        if (!isSvg && this._lastZlevel != null) {\n            zr.painter.getLayer(this._lastZlevel).clear(true);\n        }\n    },\n\n    remove: function (ecModel, api) {\n        this._lineDraw && this._lineDraw.remove();\n        this._lineDraw = null;\n        // Clear motion when lineDraw is removed\n        this._clearLayer(api);\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction normalize$2(a) {\n    if (!(a instanceof Array)) {\n        a = [a, a];\n    }\n    return a;\n}\n\nvar opacityQuery = 'lineStyle.opacity'.split('.');\n\nvar linesVisual = {\n    seriesType: 'lines',\n    reset: function (seriesModel, ecModel, api) {\n        var symbolType = normalize$2(seriesModel.get('symbol'));\n        var symbolSize = normalize$2(seriesModel.get('symbolSize'));\n        var data = seriesModel.getData();\n\n        data.setVisual('fromSymbol', symbolType && symbolType[0]);\n        data.setVisual('toSymbol', symbolType && symbolType[1]);\n        data.setVisual('fromSymbolSize', symbolSize && symbolSize[0]);\n        data.setVisual('toSymbolSize', symbolSize && symbolSize[1]);\n        data.setVisual('opacity', seriesModel.get(opacityQuery));\n\n        function dataEach(data, idx) {\n            var itemModel = data.getItemModel(idx);\n            var symbolType = normalize$2(itemModel.getShallow('symbol', true));\n            var symbolSize = normalize$2(itemModel.getShallow('symbolSize', true));\n            var opacity = itemModel.get(opacityQuery);\n\n            symbolType[0] && data.setItemVisual(idx, 'fromSymbol', symbolType[0]);\n            symbolType[1] && data.setItemVisual(idx, 'toSymbol', symbolType[1]);\n            symbolSize[0] && data.setItemVisual(idx, 'fromSymbolSize', symbolSize[0]);\n            symbolSize[1] && data.setItemVisual(idx, 'toSymbolSize', symbolSize[1]);\n\n            data.setItemVisual(idx, 'opacity', opacity);\n        }\n\n        return {dataEach: data.hasItemOption ? dataEach : null};\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterLayout(linesLayout);\nregisterVisual(linesVisual);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n    type: 'series.heatmap',\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this, {\n            generateCoord: 'value'\n        });\n    },\n\n    preventIncremental: function () {\n        var coordSysCreator = CoordinateSystemManager.get(this.get('coordinateSystem'));\n        if (coordSysCreator && coordSysCreator.dimensions) {\n            return coordSysCreator.dimensions[0] === 'lng' && coordSysCreator.dimensions[1] === 'lat';\n        }\n    },\n\n    defaultOption: {\n\n        // Cartesian2D or geo\n        coordinateSystem: 'cartesian2d',\n\n        zlevel: 0,\n\n        z: 2,\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // Geo coordinate system\n        geoIndex: 0,\n\n        blurSize: 30,\n\n        pointSize: 20,\n\n        maxOpacity: 1,\n\n        minOpacity: 0\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Uint8ClampedArray */\n\n/**\n * @file defines echarts Heatmap Chart\n * @author Ovilia (me@zhangwenli.com)\n * Inspired by https://github.com/mourner/simpleheat\n *\n * @module\n */\n\nvar GRADIENT_LEVELS = 256;\n\n/**\n * Heatmap Chart\n *\n * @class\n */\nfunction Heatmap() {\n    var canvas = createCanvas();\n    this.canvas = canvas;\n\n    this.blurSize = 30;\n    this.pointSize = 20;\n\n    this.maxOpacity = 1;\n    this.minOpacity = 0;\n\n    this._gradientPixels = {};\n}\n\nHeatmap.prototype = {\n    /**\n     * Renders Heatmap and returns the rendered canvas\n     * @param {Array} data array of data, each has x, y, value\n     * @param {number} width canvas width\n     * @param {number} height canvas height\n     */\n    update: function (data, width, height, normalize, colorFunc, isInRange) {\n        var brush = this._getBrush();\n        var gradientInRange = this._getGradient(data, colorFunc, 'inRange');\n        var gradientOutOfRange = this._getGradient(data, colorFunc, 'outOfRange');\n        var r = this.pointSize + this.blurSize;\n\n        var canvas = this.canvas;\n        var ctx = canvas.getContext('2d');\n        var len = data.length;\n        canvas.width = width;\n        canvas.height = height;\n        for (var i = 0; i < len; ++i) {\n            var p = data[i];\n            var x = p[0];\n            var y = p[1];\n            var value = p[2];\n\n            // calculate alpha using value\n            var alpha = normalize(value);\n\n            // draw with the circle brush with alpha\n            ctx.globalAlpha = alpha;\n            ctx.drawImage(brush, x - r, y - r);\n        }\n\n        if (!canvas.width || !canvas.height) {\n            // Avoid \"Uncaught DOMException: Failed to execute 'getImageData' on\n            // 'CanvasRenderingContext2D': The source height is 0.\"\n            return canvas;\n        }\n\n        // colorize the canvas using alpha value and set with gradient\n        var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n\n        var pixels = imageData.data;\n        var offset = 0;\n        var pixelLen = pixels.length;\n        var minOpacity = this.minOpacity;\n        var maxOpacity = this.maxOpacity;\n        var diffOpacity = maxOpacity - minOpacity;\n\n        while (offset < pixelLen) {\n            var alpha = pixels[offset + 3] / 256;\n            var gradientOffset = Math.floor(alpha * (GRADIENT_LEVELS - 1)) * 4;\n            // Simple optimize to ignore the empty data\n            if (alpha > 0) {\n                var gradient = isInRange(alpha) ? gradientInRange : gradientOutOfRange;\n                // Any alpha > 0 will be mapped to [minOpacity, maxOpacity]\n                alpha > 0 && (alpha = alpha * diffOpacity + minOpacity);\n                pixels[offset++] = gradient[gradientOffset];\n                pixels[offset++] = gradient[gradientOffset + 1];\n                pixels[offset++] = gradient[gradientOffset + 2];\n                pixels[offset++] = gradient[gradientOffset + 3] * alpha * 256;\n            }\n            else {\n                offset += 4;\n            }\n        }\n        ctx.putImageData(imageData, 0, 0);\n\n        return canvas;\n    },\n\n    /**\n     * get canvas of a black circle brush used for canvas to draw later\n     * @private\n     * @returns {Object} circle brush canvas\n     */\n    _getBrush: function () {\n        var brushCanvas = this._brushCanvas || (this._brushCanvas = createCanvas());\n        // set brush size\n        var r = this.pointSize + this.blurSize;\n        var d = r * 2;\n        brushCanvas.width = d;\n        brushCanvas.height = d;\n\n        var ctx = brushCanvas.getContext('2d');\n        ctx.clearRect(0, 0, d, d);\n\n        // in order to render shadow without the distinct circle,\n        // draw the distinct circle in an invisible place,\n        // and use shadowOffset to draw shadow in the center of the canvas\n        ctx.shadowOffsetX = d;\n        ctx.shadowBlur = this.blurSize;\n        // draw the shadow in black, and use alpha and shadow blur to generate\n        // color in color map\n        ctx.shadowColor = '#000';\n\n        // draw circle in the left to the canvas\n        ctx.beginPath();\n        ctx.arc(-r, r, this.pointSize, 0, Math.PI * 2, true);\n        ctx.closePath();\n        ctx.fill();\n        return brushCanvas;\n    },\n\n    /**\n     * get gradient color map\n     * @private\n     */\n    _getGradient: function (data, colorFunc, state) {\n        var gradientPixels = this._gradientPixels;\n        var pixelsSingleState = gradientPixels[state] || (gradientPixels[state] = new Uint8ClampedArray(256 * 4));\n        var color = [0, 0, 0, 0];\n        var off = 0;\n        for (var i = 0; i < 256; i++) {\n            colorFunc[state](i / 255, true, color);\n            pixelsSingleState[off++] = color[0];\n            pixelsSingleState[off++] = color[1];\n            pixelsSingleState[off++] = color[2];\n            pixelsSingleState[off++] = color[3];\n        }\n        return pixelsSingleState;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction getIsInPiecewiseRange(dataExtent, pieceList, selected) {\n    var dataSpan = dataExtent[1] - dataExtent[0];\n    pieceList = map(pieceList, function (piece) {\n        return {\n            interval: [\n                (piece.interval[0] - dataExtent[0]) / dataSpan,\n                (piece.interval[1] - dataExtent[0]) / dataSpan\n            ]\n        };\n    });\n    var len = pieceList.length;\n    var lastIndex = 0;\n\n    return function (val) {\n        // Try to find in the location of the last found\n        for (var i = lastIndex; i < len; i++) {\n            var interval = pieceList[i].interval;\n            if (interval[0] <= val && val <= interval[1]) {\n                lastIndex = i;\n                break;\n            }\n        }\n        if (i === len) { // Not found, back interation\n            for (var i = lastIndex - 1; i >= 0; i--) {\n                var interval = pieceList[i].interval;\n                if (interval[0] <= val && val <= interval[1]) {\n                    lastIndex = i;\n                    break;\n                }\n            }\n        }\n        return i >= 0 && i < len && selected[i];\n    };\n}\n\nfunction getIsInContinuousRange(dataExtent, range) {\n    var dataSpan = dataExtent[1] - dataExtent[0];\n    range = [\n        (range[0] - dataExtent[0]) / dataSpan,\n        (range[1] - dataExtent[0]) / dataSpan\n    ];\n    return function (val) {\n        return val >= range[0] && val <= range[1];\n    };\n}\n\nfunction isGeoCoordSys(coordSys) {\n    var dimensions = coordSys.dimensions;\n    // Not use coorSys.type === 'geo' because coordSys maybe extended\n    return dimensions[0] === 'lng' && dimensions[1] === 'lat';\n}\n\nextendChartView({\n\n    type: 'heatmap',\n\n    render: function (seriesModel, ecModel, api) {\n        var visualMapOfThisSeries;\n        ecModel.eachComponent('visualMap', function (visualMap) {\n            visualMap.eachTargetSeries(function (targetSeries) {\n                if (targetSeries === seriesModel) {\n                    visualMapOfThisSeries = visualMap;\n                }\n            });\n        });\n\n        if (__DEV__) {\n            if (!visualMapOfThisSeries) {\n                throw new Error('Heatmap must use with visualMap');\n            }\n        }\n\n        this.group.removeAll();\n\n        this._incrementalDisplayable = null;\n\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys.type === 'cartesian2d' || coordSys.type === 'calendar') {\n            this._renderOnCartesianAndCalendar(seriesModel, api, 0, seriesModel.getData().count());\n        }\n        else if (isGeoCoordSys(coordSys)) {\n            this._renderOnGeo(\n                coordSys, seriesModel, visualMapOfThisSeries, api\n            );\n        }\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this.group.removeAll();\n    },\n\n    incrementalRender: function (params, seriesModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys) {\n            this._renderOnCartesianAndCalendar(seriesModel, api, params.start, params.end, true);\n        }\n    },\n\n    _renderOnCartesianAndCalendar: function (seriesModel, api, start, end, incremental) {\n\n        var coordSys = seriesModel.coordinateSystem;\n        var width;\n        var height;\n\n        if (coordSys.type === 'cartesian2d') {\n            var xAxis = coordSys.getAxis('x');\n            var yAxis = coordSys.getAxis('y');\n\n            if (__DEV__) {\n                if (!(xAxis.type === 'category' && yAxis.type === 'category')) {\n                    throw new Error('Heatmap on cartesian must have two category axes');\n                }\n                if (!(xAxis.onBand && yAxis.onBand)) {\n                    throw new Error('Heatmap on cartesian must have two axes with boundaryGap true');\n                }\n            }\n\n            width = xAxis.getBandWidth();\n            height = yAxis.getBandWidth();\n        }\n\n        var group = this.group;\n        var data = seriesModel.getData();\n\n        var itemStyleQuery = 'itemStyle';\n        var hoverItemStyleQuery = 'emphasis.itemStyle';\n        var labelQuery = 'label';\n        var hoverLabelQuery = 'emphasis.label';\n        var style = seriesModel.getModel(itemStyleQuery).getItemStyle(['color']);\n        var hoverStl = seriesModel.getModel(hoverItemStyleQuery).getItemStyle();\n        var labelModel = seriesModel.getModel(labelQuery);\n        var hoverLabelModel = seriesModel.getModel(hoverLabelQuery);\n        var coordSysType = coordSys.type;\n\n\n        var dataDims = coordSysType === 'cartesian2d'\n            ? [\n                data.mapDimension('x'),\n                data.mapDimension('y'),\n                data.mapDimension('value')\n            ]\n            : [\n                data.mapDimension('time'),\n                data.mapDimension('value')\n            ];\n\n        for (var idx = start; idx < end; idx++) {\n            var rect;\n\n            if (coordSysType === 'cartesian2d') {\n                // Ignore empty data\n                if (isNaN(data.get(dataDims[2], idx))) {\n                    continue;\n                }\n\n                var point = coordSys.dataToPoint([\n                    data.get(dataDims[0], idx),\n                    data.get(dataDims[1], idx)\n                ]);\n\n                rect = new Rect({\n                    shape: {\n                        x: point[0] - width / 2,\n                        y: point[1] - height / 2,\n                        width: width,\n                        height: height\n                    },\n                    style: {\n                        fill: data.getItemVisual(idx, 'color'),\n                        opacity: data.getItemVisual(idx, 'opacity')\n                    }\n                });\n            }\n            else {\n                // Ignore empty data\n                if (isNaN(data.get(dataDims[1], idx))) {\n                    continue;\n                }\n\n                rect = new Rect({\n                    z2: 1,\n                    shape: coordSys.dataToRect([data.get(dataDims[0], idx)]).contentShape,\n                    style: {\n                        fill: data.getItemVisual(idx, 'color'),\n                        opacity: data.getItemVisual(idx, 'opacity')\n                    }\n                });\n            }\n\n            var itemModel = data.getItemModel(idx);\n\n            // Optimization for large datset\n            if (data.hasItemOption) {\n                style = itemModel.getModel(itemStyleQuery).getItemStyle(['color']);\n                hoverStl = itemModel.getModel(hoverItemStyleQuery).getItemStyle();\n                labelModel = itemModel.getModel(labelQuery);\n                hoverLabelModel = itemModel.getModel(hoverLabelQuery);\n            }\n\n            var rawValue = seriesModel.getRawValue(idx);\n            var defaultText = '-';\n            if (rawValue && rawValue[2] != null) {\n                defaultText = rawValue[2];\n            }\n\n            setLabelStyle(\n                style, hoverStl, labelModel, hoverLabelModel,\n                {\n                    labelFetcher: seriesModel,\n                    labelDataIndex: idx,\n                    defaultText: defaultText,\n                    isRectText: true\n                }\n            );\n\n            rect.setStyle(style);\n            setHoverStyle(rect, data.hasItemOption ? hoverStl : extend({}, hoverStl));\n\n            rect.incremental = incremental;\n            // PENDING\n            if (incremental) {\n                // Rect must use hover layer if it's incremental.\n                rect.useHoverLayer = true;\n            }\n\n            group.add(rect);\n            data.setItemGraphicEl(idx, rect);\n        }\n    },\n\n    _renderOnGeo: function (geo, seriesModel, visualMapModel, api) {\n        var inRangeVisuals = visualMapModel.targetVisuals.inRange;\n        var outOfRangeVisuals = visualMapModel.targetVisuals.outOfRange;\n        // if (!visualMapping) {\n        //     throw new Error('Data range must have color visuals');\n        // }\n\n        var data = seriesModel.getData();\n        var hmLayer = this._hmLayer || (this._hmLayer || new Heatmap());\n        hmLayer.blurSize = seriesModel.get('blurSize');\n        hmLayer.pointSize = seriesModel.get('pointSize');\n        hmLayer.minOpacity = seriesModel.get('minOpacity');\n        hmLayer.maxOpacity = seriesModel.get('maxOpacity');\n\n        var rect = geo.getViewRect().clone();\n        var roamTransform = geo.getRoamTransform();\n        rect.applyTransform(roamTransform);\n\n        // Clamp on viewport\n        var x = Math.max(rect.x, 0);\n        var y = Math.max(rect.y, 0);\n        var x2 = Math.min(rect.width + rect.x, api.getWidth());\n        var y2 = Math.min(rect.height + rect.y, api.getHeight());\n        var width = x2 - x;\n        var height = y2 - y;\n\n        var dims = [\n            data.mapDimension('lng'),\n            data.mapDimension('lat'),\n            data.mapDimension('value')\n        ];\n\n        var points = data.mapArray(dims, function (lng, lat, value) {\n            var pt = geo.dataToPoint([lng, lat]);\n            pt[0] -= x;\n            pt[1] -= y;\n            pt.push(value);\n            return pt;\n        });\n\n        var dataExtent = visualMapModel.getExtent();\n        var isInRange = visualMapModel.type === 'visualMap.continuous'\n            ? getIsInContinuousRange(dataExtent, visualMapModel.option.range)\n            : getIsInPiecewiseRange(\n                dataExtent, visualMapModel.getPieceList(), visualMapModel.option.selected\n            );\n\n        hmLayer.update(\n            points, width, height,\n            inRangeVisuals.color.getNormalizer(),\n            {\n                inRange: inRangeVisuals.color.getColorMapper(),\n                outOfRange: outOfRangeVisuals.color.getColorMapper()\n            },\n            isInRange\n        );\n        var img = new ZImage({\n            style: {\n                width: width,\n                height: height,\n                x: x,\n                y: y,\n                image: hmLayer.canvas\n            },\n            silent: true\n        });\n        this.group.add(img);\n    },\n\n    dispose: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PictorialBarSeries = BaseBarSeries.extend({\n\n    type: 'series.pictorialBar',\n\n    dependencies: ['grid'],\n\n    defaultOption: {\n        symbol: 'circle',     // Customized bar shape\n        symbolSize: null,     // Can be ['100%', '100%'], null means auto.\n        symbolRotate: null,\n\n        symbolPosition: null, // 'start' or 'end' or 'center', null means auto.\n        symbolOffset: null,\n        symbolMargin: null,   // start margin and end margin. Can be a number or a percent string.\n                                // Auto margin by defualt.\n        symbolRepeat: false,  // false/null/undefined, means no repeat.\n                                // Can be true, means auto calculate repeat times and cut by data.\n                                // Can be a number, specifies repeat times, and do not cut by data.\n                                // Can be 'fixed', means auto calculate repeat times but do not cut by data.\n        symbolRepeatDirection: 'end', // 'end' means from 'start' to 'end'.\n\n        symbolClip: false,\n        symbolBoundingData: null, // Can be 60 or -40 or [-40, 60]\n        symbolPatternSize: 400, // 400 * 400 px\n\n        barGap: '-100%',      // In most case, overlap is needed.\n\n        // z can be set in data item, which is z2 actually.\n\n        // Disable progressive\n        progressive: 0,\n        hoverAnimation: false // Open only when needed.\n    },\n\n    getInitialData: function (option) {\n        // Disable stack.\n        option.stack = null;\n        return PictorialBarSeries.superApply(this, 'getInitialData', arguments);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BAR_BORDER_WIDTH_QUERY$1 = ['itemStyle', 'borderWidth'];\n\n// index: +isHorizontal\nvar LAYOUT_ATTRS = [\n    {xy: 'x', wh: 'width', index: 0, posDesc: ['left', 'right']},\n    {xy: 'y', wh: 'height', index: 1, posDesc: ['top', 'bottom']}\n];\n\nvar pathForLineWidth = new Circle();\n\nvar BarView$1 = extendChartView({\n\n    type: 'pictorialBar',\n\n    render: function (seriesModel, ecModel, api) {\n        var group = this.group;\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var isHorizontal = !!baseAxis.isHorizontal();\n        var coordSysRect = cartesian.grid.getRect();\n\n        var opt = {\n            ecSize: {width: api.getWidth(), height: api.getHeight()},\n            seriesModel: seriesModel,\n            coordSys: cartesian,\n            coordSysExtent: [\n                [coordSysRect.x, coordSysRect.x + coordSysRect.width],\n                [coordSysRect.y, coordSysRect.y + coordSysRect.height]\n            ],\n            isHorizontal: isHorizontal,\n            valueDim: LAYOUT_ATTRS[+isHorizontal],\n            categoryDim: LAYOUT_ATTRS[1 - isHorizontal]\n        };\n\n        data.diff(oldData)\n            .add(function (dataIndex) {\n                if (!data.hasValue(dataIndex)) {\n                    return;\n                }\n\n                var itemModel = getItemModel(data, dataIndex);\n                var symbolMeta = getSymbolMeta(data, dataIndex, itemModel, opt);\n\n                var bar = createBar(data, opt, symbolMeta);\n\n                data.setItemGraphicEl(dataIndex, bar);\n                group.add(bar);\n\n                updateCommon$1(bar, opt, symbolMeta);\n            })\n            .update(function (newIndex, oldIndex) {\n                var bar = oldData.getItemGraphicEl(oldIndex);\n\n                if (!data.hasValue(newIndex)) {\n                    group.remove(bar);\n                    return;\n                }\n\n                var itemModel = getItemModel(data, newIndex);\n                var symbolMeta = getSymbolMeta(data, newIndex, itemModel, opt);\n\n                var pictorialShapeStr = getShapeStr(data, symbolMeta);\n                if (bar && pictorialShapeStr !== bar.__pictorialShapeStr) {\n                    group.remove(bar);\n                    data.setItemGraphicEl(newIndex, null);\n                    bar = null;\n                }\n\n                if (bar) {\n                    updateBar(bar, opt, symbolMeta);\n                }\n                else {\n                    bar = createBar(data, opt, symbolMeta, true);\n                }\n\n                data.setItemGraphicEl(newIndex, bar);\n                bar.__pictorialSymbolMeta = symbolMeta;\n                // Add back\n                group.add(bar);\n\n                updateCommon$1(bar, opt, symbolMeta);\n            })\n            .remove(function (dataIndex) {\n                var bar = oldData.getItemGraphicEl(dataIndex);\n                bar && removeBar(oldData, dataIndex, bar.__pictorialSymbolMeta.animationModel, bar);\n            })\n            .execute();\n\n        this._data = data;\n\n        return this.group;\n    },\n\n    dispose: noop,\n\n    remove: function (ecModel, api) {\n        var group = this.group;\n        var data = this._data;\n        if (ecModel.get('animation')) {\n            if (data) {\n                data.eachItemGraphicEl(function (bar) {\n                    removeBar(data, bar.dataIndex, ecModel, bar);\n                });\n            }\n        }\n        else {\n            group.removeAll();\n        }\n    }\n});\n\n\n// Set or calculate default value about symbol, and calculate layout info.\nfunction getSymbolMeta(data, dataIndex, itemModel, opt) {\n    var layout = data.getItemLayout(dataIndex);\n    var symbolRepeat = itemModel.get('symbolRepeat');\n    var symbolClip = itemModel.get('symbolClip');\n    var symbolPosition = itemModel.get('symbolPosition') || 'start';\n    var symbolRotate = itemModel.get('symbolRotate');\n    var rotation = (symbolRotate || 0) * Math.PI / 180 || 0;\n    var symbolPatternSize = itemModel.get('symbolPatternSize') || 2;\n    var isAnimationEnabled = itemModel.isAnimationEnabled();\n\n    var symbolMeta = {\n        dataIndex: dataIndex,\n        layout: layout,\n        itemModel: itemModel,\n        symbolType: data.getItemVisual(dataIndex, 'symbol') || 'circle',\n        color: data.getItemVisual(dataIndex, 'color'),\n        symbolClip: symbolClip,\n        symbolRepeat: symbolRepeat,\n        symbolRepeatDirection: itemModel.get('symbolRepeatDirection'),\n        symbolPatternSize: symbolPatternSize,\n        rotation: rotation,\n        animationModel: isAnimationEnabled ? itemModel : null,\n        hoverAnimation: isAnimationEnabled && itemModel.get('hoverAnimation'),\n        z2: itemModel.getShallow('z', true) || 0\n    };\n\n    prepareBarLength(itemModel, symbolRepeat, layout, opt, symbolMeta);\n\n    prepareSymbolSize(\n        data, dataIndex, layout, symbolRepeat, symbolClip, symbolMeta.boundingLength,\n        symbolMeta.pxSign, symbolPatternSize, opt, symbolMeta\n    );\n\n    prepareLineWidth(itemModel, symbolMeta.symbolScale, rotation, opt, symbolMeta);\n\n    var symbolSize = symbolMeta.symbolSize;\n    var symbolOffset = itemModel.get('symbolOffset');\n    if (isArray(symbolOffset)) {\n        symbolOffset = [\n            parsePercent$1(symbolOffset[0], symbolSize[0]),\n            parsePercent$1(symbolOffset[1], symbolSize[1])\n        ];\n    }\n\n    prepareLayoutInfo(\n        itemModel, symbolSize, layout, symbolRepeat, symbolClip, symbolOffset,\n        symbolPosition, symbolMeta.valueLineWidth, symbolMeta.boundingLength, symbolMeta.repeatCutLength,\n        opt, symbolMeta\n    );\n\n    return symbolMeta;\n}\n\n// bar length can be negative.\nfunction prepareBarLength(itemModel, symbolRepeat, layout, opt, output) {\n    var valueDim = opt.valueDim;\n    var symbolBoundingData = itemModel.get('symbolBoundingData');\n    var valueAxis = opt.coordSys.getOtherAxis(opt.coordSys.getBaseAxis());\n    var zeroPx = valueAxis.toGlobalCoord(valueAxis.dataToCoord(0));\n    var pxSignIdx = 1 - +(layout[valueDim.wh] <= 0);\n    var boundingLength;\n\n    if (isArray(symbolBoundingData)) {\n        var symbolBoundingExtent = [\n            convertToCoordOnAxis(valueAxis, symbolBoundingData[0]) - zeroPx,\n            convertToCoordOnAxis(valueAxis, symbolBoundingData[1]) - zeroPx\n        ];\n        symbolBoundingExtent[1] < symbolBoundingExtent[0] && (symbolBoundingExtent.reverse());\n        boundingLength = symbolBoundingExtent[pxSignIdx];\n    }\n    else if (symbolBoundingData != null) {\n        boundingLength = convertToCoordOnAxis(valueAxis, symbolBoundingData) - zeroPx;\n    }\n    else if (symbolRepeat) {\n        boundingLength = opt.coordSysExtent[valueDim.index][pxSignIdx] - zeroPx;\n    }\n    else {\n        boundingLength = layout[valueDim.wh];\n    }\n\n    output.boundingLength = boundingLength;\n\n    if (symbolRepeat) {\n        output.repeatCutLength = layout[valueDim.wh];\n    }\n\n    output.pxSign = boundingLength > 0 ? 1 : boundingLength < 0 ? -1 : 0;\n}\n\nfunction convertToCoordOnAxis(axis, value) {\n    return axis.toGlobalCoord(axis.dataToCoord(axis.scale.parse(value)));\n}\n\n// Support ['100%', '100%']\nfunction prepareSymbolSize(\n    data, dataIndex, layout, symbolRepeat, symbolClip, boundingLength,\n    pxSign, symbolPatternSize, opt, output\n) {\n    var valueDim = opt.valueDim;\n    var categoryDim = opt.categoryDim;\n    var categorySize = Math.abs(layout[categoryDim.wh]);\n\n    var symbolSize = data.getItemVisual(dataIndex, 'symbolSize');\n    if (isArray(symbolSize)) {\n        symbolSize = symbolSize.slice();\n    }\n    else {\n        if (symbolSize == null) {\n            symbolSize = '100%';\n        }\n        symbolSize = [symbolSize, symbolSize];\n    }\n\n    // Note: percentage symbolSize (like '100%') do not consider lineWidth, because it is\n    // to complicated to calculate real percent value if considering scaled lineWidth.\n    // So the actual size will bigger than layout size if lineWidth is bigger than zero,\n    // which can be tolerated in pictorial chart.\n\n    symbolSize[categoryDim.index] = parsePercent$1(\n        symbolSize[categoryDim.index],\n        categorySize\n    );\n    symbolSize[valueDim.index] = parsePercent$1(\n        symbolSize[valueDim.index],\n        symbolRepeat ? categorySize : Math.abs(boundingLength)\n    );\n\n    output.symbolSize = symbolSize;\n\n    // If x or y is less than zero, show reversed shape.\n    var symbolScale = output.symbolScale = [\n        symbolSize[0] / symbolPatternSize,\n        symbolSize[1] / symbolPatternSize\n    ];\n    // Follow convention, 'right' and 'top' is the normal scale.\n    symbolScale[valueDim.index] *= (opt.isHorizontal ? -1 : 1) * pxSign;\n}\n\nfunction prepareLineWidth(itemModel, symbolScale, rotation, opt, output) {\n    // In symbols are drawn with scale, so do not need to care about the case that width\n    // or height are too small. But symbol use strokeNoScale, where acture lineWidth should\n    // be calculated.\n    var valueLineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY$1) || 0;\n\n    if (valueLineWidth) {\n        pathForLineWidth.attr({\n            scale: symbolScale.slice(),\n            rotation: rotation\n        });\n        pathForLineWidth.updateTransform();\n        valueLineWidth /= pathForLineWidth.getLineScale();\n        valueLineWidth *= symbolScale[opt.valueDim.index];\n    }\n\n    output.valueLineWidth = valueLineWidth;\n}\n\nfunction prepareLayoutInfo(\n    itemModel, symbolSize, layout, symbolRepeat, symbolClip, symbolOffset,\n    symbolPosition, valueLineWidth, boundingLength, repeatCutLength, opt, output\n) {\n    var categoryDim = opt.categoryDim;\n    var valueDim = opt.valueDim;\n    var pxSign = output.pxSign;\n\n    var unitLength = Math.max(symbolSize[valueDim.index] + valueLineWidth, 0);\n    var pathLen = unitLength;\n\n    // Note: rotation will not effect the layout of symbols, because user may\n    // want symbols to rotate on its center, which should not be translated\n    // when rotating.\n\n    if (symbolRepeat) {\n        var absBoundingLength = Math.abs(boundingLength);\n\n        var symbolMargin = retrieve(itemModel.get('symbolMargin'), '15%') + '';\n        var hasEndGap = false;\n        if (symbolMargin.lastIndexOf('!') === symbolMargin.length - 1) {\n            hasEndGap = true;\n            symbolMargin = symbolMargin.slice(0, symbolMargin.length - 1);\n        }\n        symbolMargin = parsePercent$1(symbolMargin, symbolSize[valueDim.index]);\n\n        var uLenWithMargin = Math.max(unitLength + symbolMargin * 2, 0);\n\n        // When symbol margin is less than 0, margin at both ends will be subtracted\n        // to ensure that all of the symbols will not be overflow the given area.\n        var endFix = hasEndGap ? 0 : symbolMargin * 2;\n\n        // Both final repeatTimes and final symbolMargin area calculated based on\n        // boundingLength.\n        var repeatSpecified = isNumeric(symbolRepeat);\n        var repeatTimes = repeatSpecified\n            ? symbolRepeat\n            : toIntTimes((absBoundingLength + endFix) / uLenWithMargin);\n\n        // Adjust calculate margin, to ensure each symbol is displayed\n        // entirely in the given layout area.\n        var mDiff = absBoundingLength - repeatTimes * unitLength;\n        symbolMargin = mDiff / 2 / (hasEndGap ? repeatTimes : repeatTimes - 1);\n        uLenWithMargin = unitLength + symbolMargin * 2;\n        endFix = hasEndGap ? 0 : symbolMargin * 2;\n\n        // Update repeatTimes when not all symbol will be shown.\n        if (!repeatSpecified && symbolRepeat !== 'fixed') {\n            repeatTimes = repeatCutLength\n                ? toIntTimes((Math.abs(repeatCutLength) + endFix) / uLenWithMargin)\n                : 0;\n        }\n\n        pathLen = repeatTimes * uLenWithMargin - endFix;\n        output.repeatTimes = repeatTimes;\n        output.symbolMargin = symbolMargin;\n    }\n\n    var sizeFix = pxSign * (pathLen / 2);\n    var pathPosition = output.pathPosition = [];\n    pathPosition[categoryDim.index] = layout[categoryDim.wh] / 2;\n    pathPosition[valueDim.index] = symbolPosition === 'start'\n        ? sizeFix\n        : symbolPosition === 'end'\n        ? boundingLength - sizeFix\n        : boundingLength / 2; // 'center'\n    if (symbolOffset) {\n        pathPosition[0] += symbolOffset[0];\n        pathPosition[1] += symbolOffset[1];\n    }\n\n    var bundlePosition = output.bundlePosition = [];\n    bundlePosition[categoryDim.index] = layout[categoryDim.xy];\n    bundlePosition[valueDim.index] = layout[valueDim.xy];\n\n    var barRectShape = output.barRectShape = extend({}, layout);\n    barRectShape[valueDim.wh] = pxSign * Math.max(\n        Math.abs(layout[valueDim.wh]), Math.abs(pathPosition[valueDim.index] + sizeFix)\n    );\n    barRectShape[categoryDim.wh] = layout[categoryDim.wh];\n\n    var clipShape = output.clipShape = {};\n    // Consider that symbol may be overflow layout rect.\n    clipShape[categoryDim.xy] = -layout[categoryDim.xy];\n    clipShape[categoryDim.wh] = opt.ecSize[categoryDim.wh];\n    clipShape[valueDim.xy] = 0;\n    clipShape[valueDim.wh] = layout[valueDim.wh];\n}\n\nfunction createPath(symbolMeta) {\n    var symbolPatternSize = symbolMeta.symbolPatternSize;\n    var path = createSymbol(\n        // Consider texture img, make a big size.\n        symbolMeta.symbolType,\n        -symbolPatternSize / 2,\n        -symbolPatternSize / 2,\n        symbolPatternSize,\n        symbolPatternSize,\n        symbolMeta.color\n    );\n    path.attr({\n        culling: true\n    });\n    path.type !== 'image' && path.setStyle({\n        strokeNoScale: true\n    });\n\n    return path;\n}\n\nfunction createOrUpdateRepeatSymbols(bar, opt, symbolMeta, isUpdate) {\n    var bundle = bar.__pictorialBundle;\n    var symbolSize = symbolMeta.symbolSize;\n    var valueLineWidth = symbolMeta.valueLineWidth;\n    var pathPosition = symbolMeta.pathPosition;\n    var valueDim = opt.valueDim;\n    var repeatTimes = symbolMeta.repeatTimes || 0;\n\n    var index = 0;\n    var unit = symbolSize[opt.valueDim.index] + valueLineWidth + symbolMeta.symbolMargin * 2;\n\n    eachPath(bar, function (path) {\n        path.__pictorialAnimationIndex = index;\n        path.__pictorialRepeatTimes = repeatTimes;\n        if (index < repeatTimes) {\n            updateAttr(path, null, makeTarget(index), symbolMeta, isUpdate);\n        }\n        else {\n            updateAttr(path, null, {scale: [0, 0]}, symbolMeta, isUpdate, function () {\n                bundle.remove(path);\n            });\n        }\n\n        updateHoverAnimation(path, symbolMeta);\n\n        index++;\n    });\n\n    for (; index < repeatTimes; index++) {\n        var path = createPath(symbolMeta);\n        path.__pictorialAnimationIndex = index;\n        path.__pictorialRepeatTimes = repeatTimes;\n        bundle.add(path);\n\n        var target = makeTarget(index);\n\n        updateAttr(\n            path,\n            {\n                position: target.position,\n                scale: [0, 0]\n            },\n            {\n                scale: target.scale,\n                rotation: target.rotation\n            },\n            symbolMeta,\n            isUpdate\n        );\n\n        // FIXME\n        // If all emphasis/normal through action.\n        path\n            .on('mouseover', onMouseOver)\n            .on('mouseout', onMouseOut);\n\n        updateHoverAnimation(path, symbolMeta);\n    }\n\n    function makeTarget(index) {\n        var position = pathPosition.slice();\n        // (start && pxSign > 0) || (end && pxSign < 0): i = repeatTimes - index\n        // Otherwise: i = index;\n        var pxSign = symbolMeta.pxSign;\n        var i = index;\n        if (symbolMeta.symbolRepeatDirection === 'start' ? pxSign > 0 : pxSign < 0) {\n            i = repeatTimes - 1 - index;\n        }\n        position[valueDim.index] = unit * (i - repeatTimes / 2 + 0.5) + pathPosition[valueDim.index];\n\n        return {\n            position: position,\n            scale: symbolMeta.symbolScale.slice(),\n            rotation: symbolMeta.rotation\n        };\n    }\n\n    function onMouseOver() {\n        eachPath(bar, function (path) {\n            path.trigger('emphasis');\n        });\n    }\n\n    function onMouseOut() {\n        eachPath(bar, function (path) {\n            path.trigger('normal');\n        });\n    }\n}\n\nfunction createOrUpdateSingleSymbol(bar, opt, symbolMeta, isUpdate) {\n    var bundle = bar.__pictorialBundle;\n    var mainPath = bar.__pictorialMainPath;\n\n    if (!mainPath) {\n        mainPath = bar.__pictorialMainPath = createPath(symbolMeta);\n        bundle.add(mainPath);\n\n        updateAttr(\n            mainPath,\n            {\n                position: symbolMeta.pathPosition.slice(),\n                scale: [0, 0],\n                rotation: symbolMeta.rotation\n            },\n            {\n                scale: symbolMeta.symbolScale.slice()\n            },\n            symbolMeta,\n            isUpdate\n        );\n\n        mainPath\n            .on('mouseover', onMouseOver)\n            .on('mouseout', onMouseOut);\n    }\n    else {\n        updateAttr(\n            mainPath,\n            null,\n            {\n                position: symbolMeta.pathPosition.slice(),\n                scale: symbolMeta.symbolScale.slice(),\n                rotation: symbolMeta.rotation\n            },\n            symbolMeta,\n            isUpdate\n        );\n    }\n\n    updateHoverAnimation(mainPath, symbolMeta);\n\n    function onMouseOver() {\n        this.trigger('emphasis');\n    }\n\n    function onMouseOut() {\n        this.trigger('normal');\n    }\n}\n\n// bar rect is used for label.\nfunction createOrUpdateBarRect(bar, symbolMeta, isUpdate) {\n    var rectShape = extend({}, symbolMeta.barRectShape);\n\n    var barRect = bar.__pictorialBarRect;\n    if (!barRect) {\n        barRect = bar.__pictorialBarRect = new Rect({\n            z2: 2,\n            shape: rectShape,\n            silent: true,\n            style: {\n                stroke: 'transparent',\n                fill: 'transparent',\n                lineWidth: 0\n            }\n        });\n\n        bar.add(barRect);\n    }\n    else {\n        updateAttr(barRect, null, {shape: rectShape}, symbolMeta, isUpdate);\n    }\n}\n\nfunction createOrUpdateClip(bar, opt, symbolMeta, isUpdate) {\n    // If not clip, symbol will be remove and rebuilt.\n    if (symbolMeta.symbolClip) {\n        var clipPath = bar.__pictorialClipPath;\n        var clipShape = extend({}, symbolMeta.clipShape);\n        var valueDim = opt.valueDim;\n        var animationModel = symbolMeta.animationModel;\n        var dataIndex = symbolMeta.dataIndex;\n\n        if (clipPath) {\n            updateProps(\n                clipPath, {shape: clipShape}, animationModel, dataIndex\n            );\n        }\n        else {\n            clipShape[valueDim.wh] = 0;\n            clipPath = new Rect({shape: clipShape});\n            bar.__pictorialBundle.setClipPath(clipPath);\n            bar.__pictorialClipPath = clipPath;\n\n            var target = {};\n            target[valueDim.wh] = symbolMeta.clipShape[valueDim.wh];\n\n            graphic[isUpdate ? 'updateProps' : 'initProps'](\n                clipPath, {shape: target}, animationModel, dataIndex\n            );\n        }\n    }\n}\n\nfunction getItemModel(data, dataIndex) {\n    var itemModel = data.getItemModel(dataIndex);\n    itemModel.getAnimationDelayParams = getAnimationDelayParams;\n    itemModel.isAnimationEnabled = isAnimationEnabled;\n    return itemModel;\n}\n\nfunction getAnimationDelayParams(path) {\n    // The order is the same as the z-order, see `symbolRepeatDiretion`.\n    return {\n        index: path.__pictorialAnimationIndex,\n        count: path.__pictorialRepeatTimes\n    };\n}\n\nfunction isAnimationEnabled() {\n    // `animation` prop can be set on itemModel in pictorial bar chart.\n    return this.parentModel.isAnimationEnabled() && !!this.getShallow('animation');\n}\n\nfunction updateHoverAnimation(path, symbolMeta) {\n    path.off('emphasis').off('normal');\n\n    var scale = symbolMeta.symbolScale.slice();\n\n    symbolMeta.hoverAnimation && path\n        .on('emphasis', function () {\n            this.animateTo({\n                scale: [scale[0] * 1.1, scale[1] * 1.1]\n            }, 400, 'elasticOut');\n        })\n        .on('normal', function () {\n            this.animateTo({\n                scale: scale.slice()\n            }, 400, 'elasticOut');\n        });\n}\n\nfunction createBar(data, opt, symbolMeta, isUpdate) {\n    // bar is the main element for each data.\n    var bar = new Group();\n    // bundle is used for location and clip.\n    var bundle = new Group();\n    bar.add(bundle);\n    bar.__pictorialBundle = bundle;\n    bundle.attr('position', symbolMeta.bundlePosition.slice());\n\n    if (symbolMeta.symbolRepeat) {\n        createOrUpdateRepeatSymbols(bar, opt, symbolMeta);\n    }\n    else {\n        createOrUpdateSingleSymbol(bar, opt, symbolMeta);\n    }\n\n    createOrUpdateBarRect(bar, symbolMeta, isUpdate);\n\n    createOrUpdateClip(bar, opt, symbolMeta, isUpdate);\n\n    bar.__pictorialShapeStr = getShapeStr(data, symbolMeta);\n    bar.__pictorialSymbolMeta = symbolMeta;\n\n    return bar;\n}\n\nfunction updateBar(bar, opt, symbolMeta) {\n    var animationModel = symbolMeta.animationModel;\n    var dataIndex = symbolMeta.dataIndex;\n    var bundle = bar.__pictorialBundle;\n\n    updateProps(\n        bundle, {position: symbolMeta.bundlePosition.slice()}, animationModel, dataIndex\n    );\n\n    if (symbolMeta.symbolRepeat) {\n        createOrUpdateRepeatSymbols(bar, opt, symbolMeta, true);\n    }\n    else {\n        createOrUpdateSingleSymbol(bar, opt, symbolMeta, true);\n    }\n\n    createOrUpdateBarRect(bar, symbolMeta, true);\n\n    createOrUpdateClip(bar, opt, symbolMeta, true);\n}\n\nfunction removeBar(data, dataIndex, animationModel, bar) {\n    // Not show text when animating\n    var labelRect = bar.__pictorialBarRect;\n    labelRect && (labelRect.style.text = null);\n\n    var pathes = [];\n    eachPath(bar, function (path) {\n        pathes.push(path);\n    });\n    bar.__pictorialMainPath && pathes.push(bar.__pictorialMainPath);\n\n    // I do not find proper remove animation for clip yet.\n    bar.__pictorialClipPath && (animationModel = null);\n\n    each$1(pathes, function (path) {\n        updateProps(\n            path, {scale: [0, 0]}, animationModel, dataIndex,\n            function () {\n                bar.parent && bar.parent.remove(bar);\n            }\n        );\n    });\n\n    data.setItemGraphicEl(dataIndex, null);\n}\n\nfunction getShapeStr(data, symbolMeta) {\n    return [\n        data.getItemVisual(symbolMeta.dataIndex, 'symbol') || 'none',\n        !!symbolMeta.symbolRepeat,\n        !!symbolMeta.symbolClip\n    ].join(':');\n}\n\nfunction eachPath(bar, cb, context) {\n    // Do not use Group#eachChild, because it do not support remove.\n    each$1(bar.__pictorialBundle.children(), function (el) {\n        el !== bar.__pictorialBarRect && cb.call(context, el);\n    });\n}\n\nfunction updateAttr(el, immediateAttrs, animationAttrs, symbolMeta, isUpdate, cb) {\n    immediateAttrs && el.attr(immediateAttrs);\n    // when symbolCip used, only clip path has init animation, otherwise it would be weird effect.\n    if (symbolMeta.symbolClip && !isUpdate) {\n        animationAttrs && el.attr(animationAttrs);\n    }\n    else {\n        animationAttrs && graphic[isUpdate ? 'updateProps' : 'initProps'](\n            el, animationAttrs, symbolMeta.animationModel, symbolMeta.dataIndex, cb\n        );\n    }\n}\n\nfunction updateCommon$1(bar, opt, symbolMeta) {\n    var color = symbolMeta.color;\n    var dataIndex = symbolMeta.dataIndex;\n    var itemModel = symbolMeta.itemModel;\n    // Color must be excluded.\n    // Because symbol provide setColor individually to set fill and stroke\n    var normalStyle = itemModel.getModel('itemStyle').getItemStyle(['color']);\n    var hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n    var cursorStyle = itemModel.getShallow('cursor');\n\n    eachPath(bar, function (path) {\n        // PENDING setColor should be before setStyle!!!\n        path.setColor(color);\n        path.setStyle(defaults(\n            {\n                fill: color,\n                opacity: symbolMeta.opacity\n            },\n            normalStyle\n        ));\n        setHoverStyle(path, hoverStyle);\n\n        cursorStyle && (path.cursor = cursorStyle);\n        path.z2 = symbolMeta.z2;\n    });\n\n    var barRectHoverStyle = {};\n    var barPositionOutside = opt.valueDim.posDesc[+(symbolMeta.boundingLength > 0)];\n    var barRect = bar.__pictorialBarRect;\n\n    setLabel(\n        barRect.style, barRectHoverStyle, itemModel,\n        color, opt.seriesModel, dataIndex, barPositionOutside\n    );\n\n    setHoverStyle(barRect, barRectHoverStyle);\n}\n\nfunction toIntTimes(times) {\n    var roundedTimes = Math.round(times);\n    // Escapse accurate error\n    return Math.abs(times - roundedTimes) < 1e-4\n        ? roundedTimes\n        : Math.ceil(times);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterLayout(curry(\n    layout, 'pictorialBar'\n));\nregisterVisual(visualSymbol('pictorialBar', 'roundRect'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @constructor  module:echarts/coord/single/SingleAxis\n * @extends {module:echarts/coord/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n * @param {string} position\n */\nvar SingleAxis = function (dim, scale, coordExtent, axisType, position) {\n\n    Axis.call(this, dim, scale, coordExtent);\n\n    /**\n     * Axis type\n     * - 'category'\n     * - 'value'\n     * - 'time'\n     * - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * Axis position\n     *  - 'top'\n     *  - 'bottom'\n     *  - 'left'\n     *  - 'right'\n     *  @type {string}\n     */\n    this.position = position || 'bottom';\n\n    /**\n     * Axis orient\n     *  - 'horizontal'\n     *  - 'vertical'\n     * @type {[type]}\n     */\n    this.orient = null;\n\n};\n\nSingleAxis.prototype = {\n\n    constructor: SingleAxis,\n\n    /**\n     * Axis model\n     * @type {module:echarts/coord/single/AxisModel}\n     */\n    model: null,\n\n    /**\n     * Judge the orient of the axis.\n     * @return {boolean}\n     */\n    isHorizontal: function () {\n        var position = this.position;\n        return position === 'top' || position === 'bottom';\n\n    },\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.coordinateSystem.pointToData(point, clamp)[0];\n    },\n\n    /**\n     * Convert the local coord(processed by dataToCoord())\n     * to global coord(concrete pixel coord).\n     * designated by module:echarts/coord/single/Single.\n     * @type {Function}\n     */\n    toGlobalCoord: null,\n\n    /**\n     * Convert the global coord to local coord.\n     * designated by module:echarts/coord/single/Single.\n     * @type {Function}\n     */\n    toLocalCoord: null\n\n};\n\ninherits(SingleAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Single coordinates system.\n */\n\n/**\n * Create a single coordinates system.\n *\n * @param {module:echarts/coord/single/AxisModel} axisModel\n * @param {module:echarts/model/Global} ecModel\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction Single(axisModel, ecModel, api) {\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.dimension = 'single';\n\n    /**\n     * Add it just for draw tooltip.\n     *\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    this.dimensions = ['single'];\n\n    /**\n     * @private\n     * @type {module:echarts/coord/single/SingleAxis}.\n     */\n    this._axis = null;\n\n    /**\n     * @private\n     * @type {module:zrender/core/BoundingRect}\n     */\n    this._rect;\n\n    this._init(axisModel, ecModel, api);\n\n    /**\n     * @type {module:echarts/coord/single/AxisModel}\n     */\n    this.model = axisModel;\n}\n\nSingle.prototype = {\n\n    type: 'singleAxis',\n\n    axisPointerEnabled: true,\n\n    constructor: Single,\n\n    /**\n     * Initialize single coordinate system.\n     *\n     * @param  {module:echarts/coord/single/AxisModel} axisModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @private\n     */\n    _init: function (axisModel, ecModel, api) {\n\n        var dim = this.dimension;\n\n        var axis = new SingleAxis(\n            dim,\n            createScaleByModel(axisModel),\n            [0, 0],\n            axisModel.get('type'),\n            axisModel.get('position')\n        );\n\n        var isCategory = axis.type === 'category';\n        axis.onBand = isCategory && axisModel.get('boundaryGap');\n        axis.inverse = axisModel.get('inverse');\n        axis.orient = axisModel.get('orient');\n\n        axisModel.axis = axis;\n        axis.model = axisModel;\n        axis.coordinateSystem = this;\n        this._axis = axis;\n    },\n\n    /**\n     * Update axis scale after data processed\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    update: function (ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            if (seriesModel.coordinateSystem === this) {\n                var data = seriesModel.getData();\n                each$1(data.mapDimension(this.dimension, true), function (dim) {\n                    this._axis.scale.unionExtentFromData(data, dim);\n                }, this);\n                niceScaleExtent(this._axis.scale, this._axis.model);\n            }\n        }, this);\n    },\n\n    /**\n     * Resize the single coordinate system.\n     *\n     * @param  {module:echarts/coord/single/AxisModel} axisModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    resize: function (axisModel, api) {\n        this._rect = getLayoutRect(\n            {\n                left: axisModel.get('left'),\n                top: axisModel.get('top'),\n                right: axisModel.get('right'),\n                bottom: axisModel.get('bottom'),\n                width: axisModel.get('width'),\n                height: axisModel.get('height')\n            },\n            {\n                width: api.getWidth(),\n                height: api.getHeight()\n            }\n        );\n\n        this._adjustAxis();\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getRect: function () {\n        return this._rect;\n    },\n\n    /**\n     * @private\n     */\n    _adjustAxis: function () {\n\n        var rect = this._rect;\n        var axis = this._axis;\n\n        var isHorizontal = axis.isHorizontal();\n        var extent = isHorizontal ? [0, rect.width] : [0, rect.height];\n        var idx = axis.reverse ? 1 : 0;\n\n        axis.setExtent(extent[idx], extent[1 - idx]);\n\n        this._updateAxisTransform(axis, isHorizontal ? rect.x : rect.y);\n\n    },\n\n    /**\n     * @param  {module:echarts/coord/single/SingleAxis} axis\n     * @param  {number} coordBase\n     */\n    _updateAxisTransform: function (axis, coordBase) {\n\n        var axisExtent = axis.getExtent();\n        var extentSum = axisExtent[0] + axisExtent[1];\n        var isHorizontal = axis.isHorizontal();\n\n        axis.toGlobalCoord = isHorizontal\n            ? function (coord) {\n                return coord + coordBase;\n            }\n            : function (coord) {\n                return extentSum - coord + coordBase;\n            };\n\n        axis.toLocalCoord = isHorizontal\n            ? function (coord) {\n                return coord - coordBase;\n            }\n            : function (coord) {\n                return extentSum - coord + coordBase;\n            };\n    },\n\n    /**\n     * Get axis.\n     *\n     * @return {module:echarts/coord/single/SingleAxis}\n     */\n    getAxis: function () {\n        return this._axis;\n    },\n\n    /**\n     * Get axis, add it just for draw tooltip.\n     *\n     * @return {[type]} [description]\n     */\n    getBaseAxis: function () {\n        return this._axis;\n    },\n\n    /**\n     * @return {Array.<module:echarts/coord/Axis>}\n     */\n    getAxes: function () {\n        return [this._axis];\n    },\n\n    /**\n     * @return {Object} {baseAxes: [], otherAxes: []}\n     */\n    getTooltipAxes: function () {\n        return {baseAxes: [this.getAxis()]};\n    },\n\n    /**\n     * If contain point.\n     *\n     * @param  {Array.<number>} point\n     * @return {boolean}\n     */\n    containPoint: function (point) {\n        var rect = this.getRect();\n        var axis = this.getAxis();\n        var orient = axis.orient;\n        if (orient === 'horizontal') {\n            return axis.contain(axis.toLocalCoord(point[0]))\n            && (point[1] >= rect.y && point[1] <= (rect.y + rect.height));\n        }\n        else {\n            return axis.contain(axis.toLocalCoord(point[1]))\n            && (point[0] >= rect.y && point[0] <= (rect.y + rect.height));\n        }\n    },\n\n    /**\n     * @param {Array.<number>} point\n     * @return {Array.<number>}\n     */\n    pointToData: function (point) {\n        var axis = this.getAxis();\n        return [axis.coordToData(axis.toLocalCoord(\n            point[axis.orient === 'horizontal' ? 0 : 1]\n        ))];\n    },\n\n    /**\n     * Convert the series data to concrete point.\n     *\n     * @param  {number|Array.<number>} val\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (val) {\n        var axis = this.getAxis();\n        var rect = this.getRect();\n        var pt = [];\n        var idx = axis.orient === 'horizontal' ? 0 : 1;\n\n        if (val instanceof Array) {\n            val = val[0];\n        }\n\n        pt[idx] = axis.toGlobalCoord(axis.dataToCoord(+val));\n        pt[1 - idx] = idx === 0 ? (rect.y + rect.height / 2) : (rect.x + rect.width / 2);\n        return pt;\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Single coordinate system creator.\n */\n\n/**\n * Create single coordinate system and inject it into seriesModel.\n *\n * @param {module:echarts/model/Global} ecModel\n * @param {module:echarts/ExtensionAPI} api\n * @return {Array.<module:echarts/coord/single/Single>}\n */\nfunction create$3(ecModel, api) {\n    var singles = [];\n\n    ecModel.eachComponent('singleAxis', function (axisModel, idx) {\n\n        var single = new Single(axisModel, ecModel, api);\n        single.name = 'single_' + idx;\n        single.resize(axisModel, api);\n        axisModel.coordinateSystem = single;\n        singles.push(single);\n\n    });\n\n    ecModel.eachSeries(function (seriesModel) {\n        if (seriesModel.get('coordinateSystem') === 'singleAxis') {\n            var singleAxisModel = ecModel.queryComponents({\n                mainType: 'singleAxis',\n                index: seriesModel.get('singleAxisIndex'),\n                id: seriesModel.get('singleAxisId')\n            })[0];\n            seriesModel.coordinateSystem = singleAxisModel && singleAxisModel.coordinateSystem;\n        }\n    });\n\n    return singles;\n}\n\nCoordinateSystemManager.register('single', {\n    create: create$3,\n    dimensions: Single.prototype.dimensions\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} opt {labelInside}\n * @return {Object} {\n *  position, rotation, labelDirection, labelOffset,\n *  tickDirection, labelRotate, z2\n * }\n */\nfunction layout$2(axisModel, opt) {\n    opt = opt || {};\n    var single = axisModel.coordinateSystem;\n    var axis = axisModel.axis;\n    var layout = {};\n\n    var axisPosition = axis.position;\n    var orient = axis.orient;\n\n    var rect = single.getRect();\n    var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];\n\n    var positionMap = {\n        horizontal: {top: rectBound[2], bottom: rectBound[3]},\n        vertical: {left: rectBound[0], right: rectBound[1]}\n    };\n\n    layout.position = [\n        orient === 'vertical'\n            ? positionMap.vertical[axisPosition]\n            : rectBound[0],\n        orient === 'horizontal'\n            ? positionMap.horizontal[axisPosition]\n            : rectBound[3]\n    ];\n\n    var r = {horizontal: 0, vertical: 1};\n    layout.rotation = Math.PI / 2 * r[orient];\n\n    var directionMap = {top: -1, bottom: 1, right: 1, left: -1};\n\n    layout.labelDirection = layout.tickDirection\n        = layout.nameDirection\n        = directionMap[axisPosition];\n\n    if (axisModel.get('axisTick.inside')) {\n        layout.tickDirection = -layout.tickDirection;\n    }\n\n    if (retrieve(opt.labelInside, axisModel.get('axisLabel.inside'))) {\n        layout.labelDirection = -layout.labelDirection;\n    }\n\n    var labelRotation = opt.rotate;\n    labelRotation == null && (labelRotation = axisModel.get('axisLabel.rotate'));\n    layout.labelRotation = axisPosition === 'top' ? -labelRotation : labelRotation;\n\n    layout.z2 = 1;\n\n    return layout;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar axisBuilderAttrs$2 = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\n\nvar selfBuilderAttr = 'splitLine';\n\nvar SingleAxisView = AxisView.extend({\n\n    type: 'singleAxis',\n\n    axisPointerClass: 'SingleAxisPointer',\n\n    render: function (axisModel, ecModel, api, payload) {\n\n        var group = this.group;\n\n        group.removeAll();\n\n        var layout = layout$2(axisModel);\n\n        var axisBuilder = new AxisBuilder(axisModel, layout);\n\n        each$1(axisBuilderAttrs$2, axisBuilder.add, axisBuilder);\n\n        group.add(axisBuilder.getGroup());\n\n        if (axisModel.get(selfBuilderAttr + '.show')) {\n            this['_' + selfBuilderAttr](axisModel);\n        }\n\n        SingleAxisView.superCall(this, 'render', axisModel, ecModel, api, payload);\n    },\n\n    _splitLine: function (axisModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitLineModel = axisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineWidth = lineStyleModel.get('width');\n        var lineColors = lineStyleModel.get('color');\n\n        lineColors = lineColors instanceof Array ? lineColors : [lineColors];\n\n        var gridRect = axisModel.coordinateSystem.getRect();\n        var isHorizontal = axis.isHorizontal();\n\n        var splitLines = [];\n        var lineCount = 0;\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitLineModel\n        });\n\n        var p1 = [];\n        var p2 = [];\n\n        for (var i = 0; i < ticksCoords.length; ++i) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n            if (isHorizontal) {\n                p1[0] = tickCoord;\n                p1[1] = gridRect.y;\n                p2[0] = tickCoord;\n                p2[1] = gridRect.y + gridRect.height;\n            }\n            else {\n                p1[0] = gridRect.x;\n                p1[1] = tickCoord;\n                p2[0] = gridRect.x + gridRect.width;\n                p2[1] = tickCoord;\n            }\n            var colorIndex = (lineCount++) % lineColors.length;\n            splitLines[colorIndex] = splitLines[colorIndex] || [];\n            splitLines[colorIndex].push(new Line(\n                subPixelOptimizeLine({\n                    shape: {\n                        x1: p1[0],\n                        y1: p1[1],\n                        x2: p2[0],\n                        y2: p2[1]\n                    },\n                    style: {\n                        lineWidth: lineWidth\n                    },\n                    silent: true\n                })));\n        }\n\n        for (var i = 0; i < splitLines.length; ++i) {\n            this.group.add(mergePath(splitLines[i], {\n                style: {\n                    stroke: lineColors[i % lineColors.length],\n                    lineDash: lineStyleModel.getLineDash(lineWidth),\n                    lineWidth: lineWidth\n                },\n                silent: true\n            }));\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisModel$4 = ComponentModel.extend({\n\n    type: 'singleAxis',\n\n    layoutMode: 'box',\n\n    /**\n     * @type {module:echarts/coord/single/SingleAxis}\n     */\n    axis: null,\n\n    /**\n     * @type {module:echarts/coord/single/Single}\n     */\n    coordinateSystem: null,\n\n    /**\n     * @override\n     */\n    getCoordSysModel: function () {\n        return this;\n    }\n\n});\n\nvar defaultOption$2 = {\n\n    left: '5%',\n    top: '5%',\n    right: '5%',\n    bottom: '5%',\n\n    type: 'value',\n\n    position: 'bottom',\n\n    orient: 'horizontal',\n\n    axisLine: {\n        show: true,\n        lineStyle: {\n            width: 2,\n            type: 'solid'\n        }\n    },\n\n    // Single coordinate system and single axis is the,\n    // which is used as the parent tooltip model.\n    // same model, so we set default tooltip show as true.\n    tooltip: {\n        show: true\n    },\n\n    axisTick: {\n        show: true,\n        length: 6,\n        lineStyle: {\n            width: 2\n        }\n    },\n\n    axisLabel: {\n        show: true,\n        interval: 'auto'\n    },\n\n    splitLine: {\n        show: true,\n        lineStyle: {\n            type: 'dashed',\n            opacity: 0.2\n        }\n    }\n};\n\nfunction getAxisType$2(axisName, option) {\n    return option.type || (option.data ? 'category' : 'value');\n}\n\nmerge(AxisModel$4.prototype, axisModelCommonMixin);\n\naxisModelCreator('single', AxisModel$4, getAxisType$2, defaultOption$2);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} finder contains {seriesIndex, dataIndex, dataIndexInside}\n * @param {module:echarts/model/Global} ecModel\n * @return {Object} {point: [x, y], el: ...} point Will not be null.\n */\nvar findPointFromSeries = function (finder, ecModel) {\n    var point = [];\n    var seriesIndex = finder.seriesIndex;\n    var seriesModel;\n    if (seriesIndex == null || !(\n        seriesModel = ecModel.getSeriesByIndex(seriesIndex)\n    )) {\n        return {point: []};\n    }\n\n    var data = seriesModel.getData();\n    var dataIndex = queryDataIndex(data, finder);\n    if (dataIndex == null || dataIndex < 0 || isArray(dataIndex)) {\n        return {point: []};\n    }\n\n    var el = data.getItemGraphicEl(dataIndex);\n    var coordSys = seriesModel.coordinateSystem;\n\n    if (seriesModel.getTooltipPosition) {\n        point = seriesModel.getTooltipPosition(dataIndex) || [];\n    }\n    else if (coordSys && coordSys.dataToPoint) {\n        point = coordSys.dataToPoint(\n            data.getValues(\n                map(coordSys.dimensions, function (dim) {\n                    return data.mapDimension(dim);\n                }), dataIndex, true\n            )\n        ) || [];\n    }\n    else if (el) {\n        // Use graphic bounding rect\n        var rect = el.getBoundingRect().clone();\n        rect.applyTransform(el.transform);\n        point = [\n            rect.x + rect.width / 2,\n            rect.y + rect.height / 2\n        ];\n    }\n\n    return {point: point, el: el};\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$14 = each$1;\nvar curry$3 = curry;\nvar inner$9 = makeInner();\n\n/**\n * Basic logic: check all axis, if they do not demand show/highlight,\n * then hide/downplay them.\n *\n * @param {Object} coordSysAxesInfo\n * @param {Object} payload\n * @param {string} [payload.currTrigger] 'click' | 'mousemove' | 'leave'\n * @param {Array.<number>} [payload.x] x and y, which are mandatory, specify a point to\n *              trigger axisPointer and tooltip.\n * @param {Array.<number>} [payload.y] x and y, which are mandatory, specify a point to\n *              trigger axisPointer and tooltip.\n * @param {Object} [payload.seriesIndex] finder, optional, restrict target axes.\n * @param {Object} [payload.dataIndex] finder, restrict target axes.\n * @param {Object} [payload.axesInfo] finder, restrict target axes.\n *        [{\n *          axisDim: 'x'|'y'|'angle'|...,\n *          axisIndex: ...,\n *          value: ...\n *        }, ...]\n * @param {Function} [payload.dispatchAction]\n * @param {Object} [payload.tooltipOption]\n * @param {Object|Array.<number>|Function} [payload.position] Tooltip position,\n *        which can be specified in dispatchAction\n * @param {module:echarts/model/Global} ecModel\n * @param {module:echarts/ExtensionAPI} api\n * @return {Object} content of event obj for echarts.connect.\n */\nvar axisTrigger = function (payload, ecModel, api) {\n    var currTrigger = payload.currTrigger;\n    var point = [payload.x, payload.y];\n    var finder = payload;\n    var dispatchAction = payload.dispatchAction || bind(api.dispatchAction, api);\n    var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo;\n\n    // Pending\n    // See #6121. But we are not able to reproduce it yet.\n    if (!coordSysAxesInfo) {\n        return;\n    }\n\n    if (illegalPoint(point)) {\n        // Used in the default behavior of `connection`: use the sample seriesIndex\n        // and dataIndex. And also used in the tooltipView trigger.\n        point = findPointFromSeries({\n            seriesIndex: finder.seriesIndex,\n            // Do not use dataIndexInside from other ec instance.\n            // FIXME: auto detect it?\n            dataIndex: finder.dataIndex\n        }, ecModel).point;\n    }\n    var isIllegalPoint = illegalPoint(point);\n\n    // Axis and value can be specified when calling dispatchAction({type: 'updateAxisPointer'}).\n    // Notice: In this case, it is difficult to get the `point` (which is necessary to show\n    // tooltip, so if point is not given, we just use the point found by sample seriesIndex\n    // and dataIndex.\n    var inputAxesInfo = finder.axesInfo;\n\n    var axesInfo = coordSysAxesInfo.axesInfo;\n    var shouldHide = currTrigger === 'leave' || illegalPoint(point);\n    var outputFinder = {};\n\n    var showValueMap = {};\n    var dataByCoordSys = {list: [], map: {}};\n    var updaters = {\n        showPointer: curry$3(showPointer, showValueMap),\n        showTooltip: curry$3(showTooltip, dataByCoordSys)\n    };\n\n    // Process for triggered axes.\n    each$14(coordSysAxesInfo.coordSysMap, function (coordSys, coordSysKey) {\n        // If a point given, it must be contained by the coordinate system.\n        var coordSysContainsPoint = isIllegalPoint || coordSys.containPoint(point);\n\n        each$14(coordSysAxesInfo.coordSysAxesInfo[coordSysKey], function (axisInfo, key) {\n            var axis = axisInfo.axis;\n            var inputAxisInfo = findInputAxisInfo(inputAxesInfo, axisInfo);\n            // If no inputAxesInfo, no axis is restricted.\n            if (!shouldHide && coordSysContainsPoint && (!inputAxesInfo || inputAxisInfo)) {\n                var val = inputAxisInfo && inputAxisInfo.value;\n                if (val == null && !isIllegalPoint) {\n                    val = axis.pointToData(point);\n                }\n                val != null && processOnAxis(axisInfo, val, updaters, false, outputFinder);\n            }\n        });\n    });\n\n    // Process for linked axes.\n    var linkTriggers = {};\n    each$14(axesInfo, function (tarAxisInfo, tarKey) {\n        var linkGroup = tarAxisInfo.linkGroup;\n\n        // If axis has been triggered in the previous stage, it should not be triggered by link.\n        if (linkGroup && !showValueMap[tarKey]) {\n            each$14(linkGroup.axesInfo, function (srcAxisInfo, srcKey) {\n                var srcValItem = showValueMap[srcKey];\n                // If srcValItem exist, source axis is triggered, so link to target axis.\n                if (srcAxisInfo !== tarAxisInfo && srcValItem) {\n                    var val = srcValItem.value;\n                    linkGroup.mapper && (val = tarAxisInfo.axis.scale.parse(linkGroup.mapper(\n                        val, makeMapperParam(srcAxisInfo), makeMapperParam(tarAxisInfo)\n                    )));\n                    linkTriggers[tarAxisInfo.key] = val;\n                }\n            });\n        }\n    });\n    each$14(linkTriggers, function (val, tarKey) {\n        processOnAxis(axesInfo[tarKey], val, updaters, true, outputFinder);\n    });\n\n    updateModelActually(showValueMap, axesInfo, outputFinder);\n    dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction);\n    dispatchHighDownActually(axesInfo, dispatchAction, api);\n\n    return outputFinder;\n};\n\nfunction processOnAxis(axisInfo, newValue, updaters, dontSnap, outputFinder) {\n    var axis = axisInfo.axis;\n\n    if (axis.scale.isBlank() || !axis.containData(newValue)) {\n        return;\n    }\n\n    if (!axisInfo.involveSeries) {\n        updaters.showPointer(axisInfo, newValue);\n        return;\n    }\n\n    // Heavy calculation. So put it after axis.containData checking.\n    var payloadInfo = buildPayloadsBySeries(newValue, axisInfo);\n    var payloadBatch = payloadInfo.payloadBatch;\n    var snapToValue = payloadInfo.snapToValue;\n\n    // Fill content of event obj for echarts.connect.\n    // By defualt use the first involved series data as a sample to connect.\n    if (payloadBatch[0] && outputFinder.seriesIndex == null) {\n        extend(outputFinder, payloadBatch[0]);\n    }\n\n    // If no linkSource input, this process is for collecting link\n    // target, where snap should not be accepted.\n    if (!dontSnap && axisInfo.snap) {\n        if (axis.containData(snapToValue) && snapToValue != null) {\n            newValue = snapToValue;\n        }\n    }\n\n    updaters.showPointer(axisInfo, newValue, payloadBatch, outputFinder);\n    // Tooltip should always be snapToValue, otherwise there will be\n    // incorrect \"axis value ~ series value\" mapping displayed in tooltip.\n    updaters.showTooltip(axisInfo, payloadInfo, snapToValue);\n}\n\nfunction buildPayloadsBySeries(value, axisInfo) {\n    var axis = axisInfo.axis;\n    var dim = axis.dim;\n    var snapToValue = value;\n    var payloadBatch = [];\n    var minDist = Number.MAX_VALUE;\n    var minDiff = -1;\n\n    each$14(axisInfo.seriesModels, function (series, idx) {\n        var dataDim = series.getData().mapDimension(dim, true);\n        var seriesNestestValue;\n        var dataIndices;\n\n        if (series.getAxisTooltipData) {\n            var result = series.getAxisTooltipData(dataDim, value, axis);\n            dataIndices = result.dataIndices;\n            seriesNestestValue = result.nestestValue;\n        }\n        else {\n            dataIndices = series.getData().indicesOfNearest(\n                dataDim[0],\n                value,\n                // Add a threshold to avoid find the wrong dataIndex\n                // when data length is not same.\n                // false,\n                axis.type === 'category' ? 0.5 : null\n            );\n            if (!dataIndices.length) {\n                return;\n            }\n            seriesNestestValue = series.getData().get(dataDim[0], dataIndices[0]);\n        }\n\n        if (seriesNestestValue == null || !isFinite(seriesNestestValue)) {\n            return;\n        }\n\n        var diff = value - seriesNestestValue;\n        var dist = Math.abs(diff);\n        // Consider category case\n        if (dist <= minDist) {\n            if (dist < minDist || (diff >= 0 && minDiff < 0)) {\n                minDist = dist;\n                minDiff = diff;\n                snapToValue = seriesNestestValue;\n                payloadBatch.length = 0;\n            }\n            each$14(dataIndices, function (dataIndex) {\n                payloadBatch.push({\n                    seriesIndex: series.seriesIndex,\n                    dataIndexInside: dataIndex,\n                    dataIndex: series.getData().getRawIndex(dataIndex)\n                });\n            });\n        }\n    });\n\n    return {\n        payloadBatch: payloadBatch,\n        snapToValue: snapToValue\n    };\n}\n\nfunction showPointer(showValueMap, axisInfo, value, payloadBatch) {\n    showValueMap[axisInfo.key] = {value: value, payloadBatch: payloadBatch};\n}\n\nfunction showTooltip(dataByCoordSys, axisInfo, payloadInfo, value) {\n    var payloadBatch = payloadInfo.payloadBatch;\n    var axis = axisInfo.axis;\n    var axisModel = axis.model;\n    var axisPointerModel = axisInfo.axisPointerModel;\n\n    // If no data, do not create anything in dataByCoordSys,\n    // whose length will be used to judge whether dispatch action.\n    if (!axisInfo.triggerTooltip || !payloadBatch.length) {\n        return;\n    }\n\n    var coordSysModel = axisInfo.coordSys.model;\n    var coordSysKey = makeKey(coordSysModel);\n    var coordSysItem = dataByCoordSys.map[coordSysKey];\n    if (!coordSysItem) {\n        coordSysItem = dataByCoordSys.map[coordSysKey] = {\n            coordSysId: coordSysModel.id,\n            coordSysIndex: coordSysModel.componentIndex,\n            coordSysType: coordSysModel.type,\n            coordSysMainType: coordSysModel.mainType,\n            dataByAxis: []\n        };\n        dataByCoordSys.list.push(coordSysItem);\n    }\n\n    coordSysItem.dataByAxis.push({\n        axisDim: axis.dim,\n        axisIndex: axisModel.componentIndex,\n        axisType: axisModel.type,\n        axisId: axisModel.id,\n        value: value,\n        // Caustion: viewHelper.getValueLabel is actually on \"view stage\", which\n        // depends that all models have been updated. So it should not be performed\n        // here. Considering axisPointerModel used here is volatile, which is hard\n        // to be retrieve in TooltipView, we prepare parameters here.\n        valueLabelOpt: {\n            precision: axisPointerModel.get('label.precision'),\n            formatter: axisPointerModel.get('label.formatter')\n        },\n        seriesDataIndices: payloadBatch.slice()\n    });\n}\n\nfunction updateModelActually(showValueMap, axesInfo, outputFinder) {\n    var outputAxesInfo = outputFinder.axesInfo = [];\n    // Basic logic: If no 'show' required, 'hide' this axisPointer.\n    each$14(axesInfo, function (axisInfo, key) {\n        var option = axisInfo.axisPointerModel.option;\n        var valItem = showValueMap[key];\n\n        if (valItem) {\n            !axisInfo.useHandle && (option.status = 'show');\n            option.value = valItem.value;\n            // For label formatter param and highlight.\n            option.seriesDataIndices = (valItem.payloadBatch || []).slice();\n        }\n        // When always show (e.g., handle used), remain\n        // original value and status.\n        else {\n            // If hide, value still need to be set, consider\n            // click legend to toggle axis blank.\n            !axisInfo.useHandle && (option.status = 'hide');\n        }\n\n        // If status is 'hide', should be no info in payload.\n        option.status === 'show' && outputAxesInfo.push({\n            axisDim: axisInfo.axis.dim,\n            axisIndex: axisInfo.axis.model.componentIndex,\n            value: option.value\n        });\n    });\n}\n\nfunction dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction) {\n    // Basic logic: If no showTip required, hideTip will be dispatched.\n    if (illegalPoint(point) || !dataByCoordSys.list.length) {\n        dispatchAction({type: 'hideTip'});\n        return;\n    }\n\n    // In most case only one axis (or event one series is used). It is\n    // convinient to fetch payload.seriesIndex and payload.dataIndex\n    // dirtectly. So put the first seriesIndex and dataIndex of the first\n    // axis on the payload.\n    var sampleItem = ((dataByCoordSys.list[0].dataByAxis[0] || {}).seriesDataIndices || [])[0] || {};\n\n    dispatchAction({\n        type: 'showTip',\n        escapeConnect: true,\n        x: point[0],\n        y: point[1],\n        tooltipOption: payload.tooltipOption,\n        position: payload.position,\n        dataIndexInside: sampleItem.dataIndexInside,\n        dataIndex: sampleItem.dataIndex,\n        seriesIndex: sampleItem.seriesIndex,\n        dataByCoordSys: dataByCoordSys.list\n    });\n}\n\nfunction dispatchHighDownActually(axesInfo, dispatchAction, api) {\n    // FIXME\n    // highlight status modification shoule be a stage of main process?\n    // (Consider confilct (e.g., legend and axisPointer) and setOption)\n\n    var zr = api.getZr();\n    var highDownKey = 'axisPointerLastHighlights';\n    var lastHighlights = inner$9(zr)[highDownKey] || {};\n    var newHighlights = inner$9(zr)[highDownKey] = {};\n\n    // Update highlight/downplay status according to axisPointer model.\n    // Build hash map and remove duplicate incidentally.\n    each$14(axesInfo, function (axisInfo, key) {\n        var option = axisInfo.axisPointerModel.option;\n        option.status === 'show' && each$14(option.seriesDataIndices, function (batchItem) {\n            var key = batchItem.seriesIndex + ' | ' + batchItem.dataIndex;\n            newHighlights[key] = batchItem;\n        });\n    });\n\n    // Diff.\n    var toHighlight = [];\n    var toDownplay = [];\n    each$1(lastHighlights, function (batchItem, key) {\n        !newHighlights[key] && toDownplay.push(batchItem);\n    });\n    each$1(newHighlights, function (batchItem, key) {\n        !lastHighlights[key] && toHighlight.push(batchItem);\n    });\n\n    toDownplay.length && api.dispatchAction({\n        type: 'downplay', escapeConnect: true, batch: toDownplay\n    });\n    toHighlight.length && api.dispatchAction({\n        type: 'highlight', escapeConnect: true, batch: toHighlight\n    });\n}\n\nfunction findInputAxisInfo(inputAxesInfo, axisInfo) {\n    for (var i = 0; i < (inputAxesInfo || []).length; i++) {\n        var inputAxisInfo = inputAxesInfo[i];\n        if (axisInfo.axis.dim === inputAxisInfo.axisDim\n            && axisInfo.axis.model.componentIndex === inputAxisInfo.axisIndex\n        ) {\n            return inputAxisInfo;\n        }\n    }\n}\n\nfunction makeMapperParam(axisInfo) {\n    var axisModel = axisInfo.axis.model;\n    var item = {};\n    var dim = item.axisDim = axisInfo.axis.dim;\n    item.axisIndex = item[dim + 'AxisIndex'] = axisModel.componentIndex;\n    item.axisName = item[dim + 'AxisName'] = axisModel.name;\n    item.axisId = item[dim + 'AxisId'] = axisModel.id;\n    return item;\n}\n\nfunction illegalPoint(point) {\n    return !point || point[0] == null || isNaN(point[0]) || point[1] == null || isNaN(point[1]);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisPointerModel = extendComponentModel({\n\n    type: 'axisPointer',\n\n    coordSysAxesInfo: null,\n\n    defaultOption: {\n        // 'auto' means that show when triggered by tooltip or handle.\n        show: 'auto',\n        // 'click' | 'mousemove' | 'none'\n        triggerOn: null, // set default in AxisPonterView.js\n\n        zlevel: 0,\n        z: 50,\n\n        type: 'line', // 'line' 'shadow' 'cross' 'none'.\n        // axispointer triggered by tootip determine snap automatically,\n        // see `modelHelper`.\n        snap: false,\n        triggerTooltip: true,\n\n        value: null,\n        status: null, // Init value depends on whether handle is used.\n\n        // [group0, group1, ...]\n        // Each group can be: {\n        //      mapper: function () {},\n        //      singleTooltip: 'multiple',  // 'multiple' or 'single'\n        //      xAxisId: ...,\n        //      yAxisName: ...,\n        //      angleAxisIndex: ...\n        // }\n        // mapper: can be ignored.\n        //      input: {axisInfo, value}\n        //      output: {axisInfo, value}\n        link: [],\n\n        // Do not set 'auto' here, otherwise global animation: false\n        // will not effect at this axispointer.\n        animation: null,\n        animationDurationUpdate: 200,\n\n        lineStyle: {\n            color: '#aaa',\n            width: 1,\n            type: 'solid'\n        },\n\n        shadowStyle: {\n            color: 'rgba(150,150,150,0.3)'\n        },\n\n        label: {\n            show: true,\n            formatter: null, // string | Function\n            precision: 'auto', // Or a number like 0, 1, 2 ...\n            margin: 3,\n            color: '#fff',\n            padding: [5, 7, 5, 7],\n            backgroundColor: 'auto', // default: axis line color\n            borderColor: null,\n            borderWidth: 0,\n            shadowBlur: 3,\n            shadowColor: '#aaa'\n            // Considering applicability, common style should\n            // better not have shadowOffset.\n            // shadowOffsetX: 0,\n            // shadowOffsetY: 2\n        },\n\n        handle: {\n            show: false,\n            /* eslint-disable */\n            icon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z', // jshint ignore:line\n            /* eslint-enable */\n            size: 45,\n            // handle margin is from symbol center to axis, which is stable when circular move.\n            margin: 50,\n            // color: '#1b8bbd'\n            // color: '#2f4554'\n            color: '#333',\n            shadowBlur: 3,\n            shadowColor: '#aaa',\n            shadowOffsetX: 0,\n            shadowOffsetY: 2,\n\n            // For mobile performance\n            throttle: 40\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$10 = makeInner();\nvar each$15 = each$1;\n\n/**\n * @param {string} key\n * @param {module:echarts/ExtensionAPI} api\n * @param {Function} handler\n *      param: {string} currTrigger\n *      param: {Array.<number>} point\n */\nfunction register(key, api, handler) {\n    if (env$1.node) {\n        return;\n    }\n\n    var zr = api.getZr();\n    inner$10(zr).records || (inner$10(zr).records = {});\n\n    initGlobalListeners(zr, api);\n\n    var record = inner$10(zr).records[key] || (inner$10(zr).records[key] = {});\n    record.handler = handler;\n}\n\nfunction initGlobalListeners(zr, api) {\n    if (inner$10(zr).initialized) {\n        return;\n    }\n\n    inner$10(zr).initialized = true;\n\n    useHandler('click', curry(doEnter, 'click'));\n    useHandler('mousemove', curry(doEnter, 'mousemove'));\n    // useHandler('mouseout', onLeave);\n    useHandler('globalout', onLeave);\n\n    function useHandler(eventType, cb) {\n        zr.on(eventType, function (e) {\n            var dis = makeDispatchAction(api);\n\n            each$15(inner$10(zr).records, function (record) {\n                record && cb(record, e, dis.dispatchAction);\n            });\n\n            dispatchTooltipFinally(dis.pendings, api);\n        });\n    }\n}\n\nfunction dispatchTooltipFinally(pendings, api) {\n    var showLen = pendings.showTip.length;\n    var hideLen = pendings.hideTip.length;\n\n    var actuallyPayload;\n    if (showLen) {\n        actuallyPayload = pendings.showTip[showLen - 1];\n    }\n    else if (hideLen) {\n        actuallyPayload = pendings.hideTip[hideLen - 1];\n    }\n    if (actuallyPayload) {\n        actuallyPayload.dispatchAction = null;\n        api.dispatchAction(actuallyPayload);\n    }\n}\n\nfunction onLeave(record, e, dispatchAction) {\n    record.handler('leave', null, dispatchAction);\n}\n\nfunction doEnter(currTrigger, record, e, dispatchAction) {\n    record.handler(currTrigger, e, dispatchAction);\n}\n\nfunction makeDispatchAction(api) {\n    var pendings = {\n        showTip: [],\n        hideTip: []\n    };\n    // FIXME\n    // better approach?\n    // 'showTip' and 'hideTip' can be triggered by axisPointer and tooltip,\n    // which may be conflict, (axisPointer call showTip but tooltip call hideTip);\n    // So we have to add \"final stage\" to merge those dispatched actions.\n    var dispatchAction = function (payload) {\n        var pendingList = pendings[payload.type];\n        if (pendingList) {\n            pendingList.push(payload);\n        }\n        else {\n            payload.dispatchAction = dispatchAction;\n            api.dispatchAction(payload);\n        }\n    };\n\n    return {\n        dispatchAction: dispatchAction,\n        pendings: pendings\n    };\n}\n\n/**\n * @param {string} key\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction unregister(key, api) {\n    if (env$1.node) {\n        return;\n    }\n    var zr = api.getZr();\n    var record = (inner$10(zr).records || {})[key];\n    if (record) {\n        inner$10(zr).records[key] = null;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisPointerView = extendComponentView({\n\n    type: 'axisPointer',\n\n    render: function (globalAxisPointerModel, ecModel, api) {\n        var globalTooltipModel = ecModel.getComponent('tooltip');\n        var triggerOn = globalAxisPointerModel.get('triggerOn')\n            || (globalTooltipModel && globalTooltipModel.get('triggerOn') || 'mousemove|click');\n\n        // Register global listener in AxisPointerView to enable\n        // AxisPointerView to be independent to Tooltip.\n        register(\n            'axisPointer',\n            api,\n            function (currTrigger, e, dispatchAction) {\n                // If 'none', it is not controlled by mouse totally.\n                if (triggerOn !== 'none'\n                    && (currTrigger === 'leave' || triggerOn.indexOf(currTrigger) >= 0)\n                ) {\n                    dispatchAction({\n                        type: 'updateAxisPointer',\n                        currTrigger: currTrigger,\n                        x: e && e.offsetX,\n                        y: e && e.offsetY\n                    });\n                }\n            }\n        );\n    },\n\n    /**\n     * @override\n     */\n    remove: function (ecModel, api) {\n        unregister(api.getZr(), 'axisPointer');\n        AxisPointerView.superApply(this._model, 'remove', arguments);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function (ecModel, api) {\n        unregister('axisPointer', api);\n        AxisPointerView.superApply(this._model, 'dispose', arguments);\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$11 = makeInner();\nvar clone$4 = clone;\nvar bind$2 = bind;\n\n/**\n * Base axis pointer class in 2D.\n * Implemenents {module:echarts/component/axis/IAxisPointer}.\n */\nfunction BaseAxisPointer() {\n}\n\nBaseAxisPointer.prototype = {\n\n    /**\n     * @private\n     */\n    _group: null,\n\n    /**\n     * @private\n     */\n    _lastGraphicKey: null,\n\n    /**\n     * @private\n     */\n    _handle: null,\n\n    /**\n     * @private\n     */\n    _dragging: false,\n\n    /**\n     * @private\n     */\n    _lastValue: null,\n\n    /**\n     * @private\n     */\n    _lastStatus: null,\n\n    /**\n     * @private\n     */\n    _payloadInfo: null,\n\n    /**\n     * In px, arbitrary value. Do not set too small,\n     * no animation is ok for most cases.\n     * @protected\n     */\n    animationThreshold: 15,\n\n    /**\n     * @implement\n     */\n    render: function (axisModel, axisPointerModel, api, forceRender) {\n        var value = axisPointerModel.get('value');\n        var status = axisPointerModel.get('status');\n\n        // Bind them to `this`, not in closure, otherwise they will not\n        // be replaced when user calling setOption in not merge mode.\n        this._axisModel = axisModel;\n        this._axisPointerModel = axisPointerModel;\n        this._api = api;\n\n        // Optimize: `render` will be called repeatly during mouse move.\n        // So it is power consuming if performing `render` each time,\n        // especially on mobile device.\n        if (!forceRender\n            && this._lastValue === value\n            && this._lastStatus === status\n        ) {\n            return;\n        }\n        this._lastValue = value;\n        this._lastStatus = status;\n\n        var group = this._group;\n        var handle = this._handle;\n\n        if (!status || status === 'hide') {\n            // Do not clear here, for animation better.\n            group && group.hide();\n            handle && handle.hide();\n            return;\n        }\n        group && group.show();\n        handle && handle.show();\n\n        // Otherwise status is 'show'\n        var elOption = {};\n        this.makeElOption(elOption, value, axisModel, axisPointerModel, api);\n\n        // Enable change axis pointer type.\n        var graphicKey = elOption.graphicKey;\n        if (graphicKey !== this._lastGraphicKey) {\n            this.clear(api);\n        }\n        this._lastGraphicKey = graphicKey;\n\n        var moveAnimation = this._moveAnimation\n            = this.determineAnimation(axisModel, axisPointerModel);\n\n        if (!group) {\n            group = this._group = new Group();\n            this.createPointerEl(group, elOption, axisModel, axisPointerModel);\n            this.createLabelEl(group, elOption, axisModel, axisPointerModel);\n            api.getZr().add(group);\n        }\n        else {\n            var doUpdateProps = curry(updateProps$1, axisPointerModel, moveAnimation);\n            this.updatePointerEl(group, elOption, doUpdateProps, axisPointerModel);\n            this.updateLabelEl(group, elOption, doUpdateProps, axisPointerModel);\n        }\n\n        updateMandatoryProps(group, axisPointerModel, true);\n\n        this._renderHandle(value);\n    },\n\n    /**\n     * @implement\n     */\n    remove: function (api) {\n        this.clear(api);\n    },\n\n    /**\n     * @implement\n     */\n    dispose: function (api) {\n        this.clear(api);\n    },\n\n    /**\n     * @protected\n     */\n    determineAnimation: function (axisModel, axisPointerModel) {\n        var animation = axisPointerModel.get('animation');\n        var axis = axisModel.axis;\n        var isCategoryAxis = axis.type === 'category';\n        var useSnap = axisPointerModel.get('snap');\n\n        // Value axis without snap always do not snap.\n        if (!useSnap && !isCategoryAxis) {\n            return false;\n        }\n\n        if (animation === 'auto' || animation == null) {\n            var animationThreshold = this.animationThreshold;\n            if (isCategoryAxis && axis.getBandWidth() > animationThreshold) {\n                return true;\n            }\n\n            // It is important to auto animation when snap used. Consider if there is\n            // a dataZoom, animation will be disabled when too many points exist, while\n            // it will be enabled for better visual effect when little points exist.\n            if (useSnap) {\n                var seriesDataCount = getAxisInfo(axisModel).seriesDataCount;\n                var axisExtent = axis.getExtent();\n                // Approximate band width\n                return Math.abs(axisExtent[0] - axisExtent[1]) / seriesDataCount > animationThreshold;\n            }\n\n            return false;\n        }\n\n        return animation === true;\n    },\n\n    /**\n     * add {pointer, label, graphicKey} to elOption\n     * @protected\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        // Shoule be implemenented by sub-class.\n    },\n\n    /**\n     * @protected\n     */\n    createPointerEl: function (group, elOption, axisModel, axisPointerModel) {\n        var pointerOption = elOption.pointer;\n        if (pointerOption) {\n            var pointerEl = inner$11(group).pointerEl = new graphic[pointerOption.type](\n                clone$4(elOption.pointer)\n            );\n            group.add(pointerEl);\n        }\n    },\n\n    /**\n     * @protected\n     */\n    createLabelEl: function (group, elOption, axisModel, axisPointerModel) {\n        if (elOption.label) {\n            var labelEl = inner$11(group).labelEl = new Rect(\n                clone$4(elOption.label)\n            );\n\n            group.add(labelEl);\n            updateLabelShowHide(labelEl, axisPointerModel);\n        }\n    },\n\n    /**\n     * @protected\n     */\n    updatePointerEl: function (group, elOption, updateProps$$1) {\n        var pointerEl = inner$11(group).pointerEl;\n        if (pointerEl) {\n            pointerEl.setStyle(elOption.pointer.style);\n            updateProps$$1(pointerEl, {shape: elOption.pointer.shape});\n        }\n    },\n\n    /**\n     * @protected\n     */\n    updateLabelEl: function (group, elOption, updateProps$$1, axisPointerModel) {\n        var labelEl = inner$11(group).labelEl;\n        if (labelEl) {\n            labelEl.setStyle(elOption.label.style);\n            updateProps$$1(labelEl, {\n                // Consider text length change in vertical axis, animation should\n                // be used on shape, otherwise the effect will be weird.\n                shape: elOption.label.shape,\n                position: elOption.label.position\n            });\n\n            updateLabelShowHide(labelEl, axisPointerModel);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _renderHandle: function (value) {\n        if (this._dragging || !this.updateHandleTransform) {\n            return;\n        }\n\n        var axisPointerModel = this._axisPointerModel;\n        var zr = this._api.getZr();\n        var handle = this._handle;\n        var handleModel = axisPointerModel.getModel('handle');\n\n        var status = axisPointerModel.get('status');\n        if (!handleModel.get('show') || !status || status === 'hide') {\n            handle && zr.remove(handle);\n            this._handle = null;\n            return;\n        }\n\n        var isInit;\n        if (!this._handle) {\n            isInit = true;\n            handle = this._handle = createIcon(\n                handleModel.get('icon'),\n                {\n                    cursor: 'move',\n                    draggable: true,\n                    onmousemove: function (e) {\n                        // Fot mobile devicem, prevent screen slider on the button.\n                        stop(e.event);\n                    },\n                    onmousedown: bind$2(this._onHandleDragMove, this, 0, 0),\n                    drift: bind$2(this._onHandleDragMove, this),\n                    ondragend: bind$2(this._onHandleDragEnd, this)\n                }\n            );\n            zr.add(handle);\n        }\n\n        updateMandatoryProps(handle, axisPointerModel, false);\n\n        // update style\n        var includeStyles = [\n            'color', 'borderColor', 'borderWidth', 'opacity',\n            'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'\n        ];\n        handle.setStyle(handleModel.getItemStyle(null, includeStyles));\n\n        // update position\n        var handleSize = handleModel.get('size');\n        if (!isArray(handleSize)) {\n            handleSize = [handleSize, handleSize];\n        }\n        handle.attr('scale', [handleSize[0] / 2, handleSize[1] / 2]);\n\n        createOrUpdate(\n            this,\n            '_doDispatchAxisPointer',\n            handleModel.get('throttle') || 0,\n            'fixRate'\n        );\n\n        this._moveHandleToValue(value, isInit);\n    },\n\n    /**\n     * @private\n     */\n    _moveHandleToValue: function (value, isInit) {\n        updateProps$1(\n            this._axisPointerModel,\n            !isInit && this._moveAnimation,\n            this._handle,\n            getHandleTransProps(this.getHandleTransform(\n                value, this._axisModel, this._axisPointerModel\n            ))\n        );\n    },\n\n    /**\n     * @private\n     */\n    _onHandleDragMove: function (dx, dy) {\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        this._dragging = true;\n\n        // Persistent for throttle.\n        var trans = this.updateHandleTransform(\n            getHandleTransProps(handle),\n            [dx, dy],\n            this._axisModel,\n            this._axisPointerModel\n        );\n        this._payloadInfo = trans;\n\n        handle.stopAnimation();\n        handle.attr(getHandleTransProps(trans));\n        inner$11(handle).lastProp = null;\n\n        this._doDispatchAxisPointer();\n    },\n\n    /**\n     * Throttled method.\n     * @private\n     */\n    _doDispatchAxisPointer: function () {\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        var payloadInfo = this._payloadInfo;\n        var axisModel = this._axisModel;\n        this._api.dispatchAction({\n            type: 'updateAxisPointer',\n            x: payloadInfo.cursorPoint[0],\n            y: payloadInfo.cursorPoint[1],\n            tooltipOption: payloadInfo.tooltipOption,\n            axesInfo: [{\n                axisDim: axisModel.axis.dim,\n                axisIndex: axisModel.componentIndex\n            }]\n        });\n    },\n\n    /**\n     * @private\n     */\n    _onHandleDragEnd: function (moveAnimation) {\n        this._dragging = false;\n        var handle = this._handle;\n        if (!handle) {\n            return;\n        }\n\n        var value = this._axisPointerModel.get('value');\n        // Consider snap or categroy axis, handle may be not consistent with\n        // axisPointer. So move handle to align the exact value position when\n        // drag ended.\n        this._moveHandleToValue(value);\n\n        // For the effect: tooltip will be shown when finger holding on handle\n        // button, and will be hidden after finger left handle button.\n        this._api.dispatchAction({\n            type: 'hideTip'\n        });\n    },\n\n    /**\n     * Should be implemenented by sub-class if support `handle`.\n     * @protected\n     * @param {number} value\n     * @param {module:echarts/model/Model} axisModel\n     * @param {module:echarts/model/Model} axisPointerModel\n     * @return {Object} {position: [x, y], rotation: 0}\n     */\n    getHandleTransform: null,\n\n    /**\n     * * Should be implemenented by sub-class if support `handle`.\n     * @protected\n     * @param {Object} transform {position, rotation}\n     * @param {Array.<number>} delta [dx, dy]\n     * @param {module:echarts/model/Model} axisModel\n     * @param {module:echarts/model/Model} axisPointerModel\n     * @return {Object} {position: [x, y], rotation: 0, cursorPoint: [x, y]}\n     */\n    updateHandleTransform: null,\n\n    /**\n     * @private\n     */\n    clear: function (api) {\n        this._lastValue = null;\n        this._lastStatus = null;\n\n        var zr = api.getZr();\n        var group = this._group;\n        var handle = this._handle;\n        if (zr && group) {\n            this._lastGraphicKey = null;\n            group && zr.remove(group);\n            handle && zr.remove(handle);\n            this._group = null;\n            this._handle = null;\n            this._payloadInfo = null;\n        }\n    },\n\n    /**\n     * @protected\n     */\n    doClear: function () {\n        // Implemented by sub-class if necessary.\n    },\n\n    /**\n     * @protected\n     * @param {Array.<number>} xy\n     * @param {Array.<number>} wh\n     * @param {number} [xDimIndex=0] or 1\n     */\n    buildLabel: function (xy, wh, xDimIndex) {\n        xDimIndex = xDimIndex || 0;\n        return {\n            x: xy[xDimIndex],\n            y: xy[1 - xDimIndex],\n            width: wh[xDimIndex],\n            height: wh[1 - xDimIndex]\n        };\n    }\n};\n\nBaseAxisPointer.prototype.constructor = BaseAxisPointer;\n\n\nfunction updateProps$1(animationModel, moveAnimation, el, props) {\n    // Animation optimize.\n    if (!propsEqual(inner$11(el).lastProp, props)) {\n        inner$11(el).lastProp = props;\n        moveAnimation\n            ? updateProps(el, props, animationModel)\n            : (el.stopAnimation(), el.attr(props));\n    }\n}\n\nfunction propsEqual(lastProps, newProps) {\n    if (isObject$1(lastProps) && isObject$1(newProps)) {\n        var equals = true;\n        each$1(newProps, function (item, key) {\n            equals = equals && propsEqual(lastProps[key], item);\n        });\n        return !!equals;\n    }\n    else {\n        return lastProps === newProps;\n    }\n}\n\nfunction updateLabelShowHide(labelEl, axisPointerModel) {\n    labelEl[axisPointerModel.get('label.show') ? 'show' : 'hide']();\n}\n\nfunction getHandleTransProps(trans) {\n    return {\n        position: trans.position.slice(),\n        rotation: trans.rotation || 0\n    };\n}\n\nfunction updateMandatoryProps(group, axisPointerModel, silent) {\n    var z = axisPointerModel.get('z');\n    var zlevel = axisPointerModel.get('zlevel');\n\n    group && group.traverse(function (el) {\n        if (el.type !== 'group') {\n            z != null && (el.z = z);\n            zlevel != null && (el.zlevel = zlevel);\n            el.silent = silent;\n        }\n    });\n}\n\nenableClassExtend(BaseAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/model/Model} axisPointerModel\n */\nfunction buildElStyle(axisPointerModel) {\n    var axisPointerType = axisPointerModel.get('type');\n    var styleModel = axisPointerModel.getModel(axisPointerType + 'Style');\n    var style;\n    if (axisPointerType === 'line') {\n        style = styleModel.getLineStyle();\n        style.fill = null;\n    }\n    else if (axisPointerType === 'shadow') {\n        style = styleModel.getAreaStyle();\n        style.stroke = null;\n    }\n    return style;\n}\n\n/**\n * @param {Function} labelPos {align, verticalAlign, position}\n */\nfunction buildLabelElOption(\n    elOption, axisModel, axisPointerModel, api, labelPos\n) {\n    var value = axisPointerModel.get('value');\n    var text = getValueLabel(\n        value, axisModel.axis, axisModel.ecModel,\n        axisPointerModel.get('seriesDataIndices'),\n        {\n            precision: axisPointerModel.get('label.precision'),\n            formatter: axisPointerModel.get('label.formatter')\n        }\n    );\n    var labelModel = axisPointerModel.getModel('label');\n    var paddings = normalizeCssArray$1(labelModel.get('padding') || 0);\n\n    var font = labelModel.getFont();\n    var textRect = getBoundingRect(text, font);\n\n    var position = labelPos.position;\n    var width = textRect.width + paddings[1] + paddings[3];\n    var height = textRect.height + paddings[0] + paddings[2];\n\n    // Adjust by align.\n    var align = labelPos.align;\n    align === 'right' && (position[0] -= width);\n    align === 'center' && (position[0] -= width / 2);\n    var verticalAlign = labelPos.verticalAlign;\n    verticalAlign === 'bottom' && (position[1] -= height);\n    verticalAlign === 'middle' && (position[1] -= height / 2);\n\n    // Not overflow ec container\n    confineInContainer(position, width, height, api);\n\n    var bgColor = labelModel.get('backgroundColor');\n    if (!bgColor || bgColor === 'auto') {\n        bgColor = axisModel.get('axisLine.lineStyle.color');\n    }\n\n    elOption.label = {\n        shape: {x: 0, y: 0, width: width, height: height, r: labelModel.get('borderRadius')},\n        position: position.slice(),\n        // TODO: rich\n        style: {\n            text: text,\n            textFont: font,\n            textFill: labelModel.getTextColor(),\n            textPosition: 'inside',\n            fill: bgColor,\n            stroke: labelModel.get('borderColor') || 'transparent',\n            lineWidth: labelModel.get('borderWidth') || 0,\n            shadowBlur: labelModel.get('shadowBlur'),\n            shadowColor: labelModel.get('shadowColor'),\n            shadowOffsetX: labelModel.get('shadowOffsetX'),\n            shadowOffsetY: labelModel.get('shadowOffsetY')\n        },\n        // Lable should be over axisPointer.\n        z2: 10\n    };\n}\n\n// Do not overflow ec container\nfunction confineInContainer(position, width, height, api) {\n    var viewWidth = api.getWidth();\n    var viewHeight = api.getHeight();\n    position[0] = Math.min(position[0] + width, viewWidth) - width;\n    position[1] = Math.min(position[1] + height, viewHeight) - height;\n    position[0] = Math.max(position[0], 0);\n    position[1] = Math.max(position[1], 0);\n}\n\n/**\n * @param {number} value\n * @param {module:echarts/coord/Axis} axis\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} opt\n * @param {Array.<Object>} seriesDataIndices\n * @param {number|string} opt.precision 'auto' or a number\n * @param {string|Function} opt.formatter label formatter\n */\nfunction getValueLabel(value, axis, ecModel, seriesDataIndices, opt) {\n    value = axis.scale.parse(value);\n    var text = axis.scale.getLabel(\n        // If `precision` is set, width can be fixed (like '12.00500'), which\n        // helps to debounce when when moving label.\n        value, {precision: opt.precision}\n    );\n    var formatter = opt.formatter;\n\n    if (formatter) {\n        var params = {\n            value: getAxisRawValue(axis, value),\n            seriesData: []\n        };\n        each$1(seriesDataIndices, function (idxItem) {\n            var series = ecModel.getSeriesByIndex(idxItem.seriesIndex);\n            var dataIndex = idxItem.dataIndexInside;\n            var dataParams = series && series.getDataParams(dataIndex);\n            dataParams && params.seriesData.push(dataParams);\n        });\n\n        if (isString(formatter)) {\n            text = formatter.replace('{value}', text);\n        }\n        else if (isFunction$1(formatter)) {\n            text = formatter(params);\n        }\n    }\n\n    return text;\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @param {number} value\n * @param {Object} layoutInfo {\n *  rotation, position, labelOffset, labelDirection, labelMargin\n * }\n */\nfunction getTransformedPosition(axis, value, layoutInfo) {\n    var transform = create$1();\n    rotate(transform, transform, layoutInfo.rotation);\n    translate(transform, transform, layoutInfo.position);\n\n    return applyTransform$1([\n        axis.dataToCoord(value),\n        (layoutInfo.labelOffset || 0)\n            + (layoutInfo.labelDirection || 1) * (layoutInfo.labelMargin || 0)\n    ], transform);\n}\n\nfunction buildCartesianSingleLabelElOption(\n    value, elOption, layoutInfo, axisModel, axisPointerModel, api\n) {\n    var textLayout = AxisBuilder.innerTextLayout(\n        layoutInfo.rotation, 0, layoutInfo.labelDirection\n    );\n    layoutInfo.labelMargin = axisPointerModel.get('label.margin');\n    buildLabelElOption(elOption, axisModel, axisPointerModel, api, {\n        position: getTransformedPosition(axisModel.axis, value, layoutInfo),\n        align: textLayout.textAlign,\n        verticalAlign: textLayout.textVerticalAlign\n    });\n}\n\n/**\n * @param {Array.<number>} p1\n * @param {Array.<number>} p2\n * @param {number} [xDimIndex=0] or 1\n */\nfunction makeLineShape(p1, p2, xDimIndex) {\n    xDimIndex = xDimIndex || 0;\n    return {\n        x1: p1[xDimIndex],\n        y1: p1[1 - xDimIndex],\n        x2: p2[xDimIndex],\n        y2: p2[1 - xDimIndex]\n    };\n}\n\n/**\n * @param {Array.<number>} xy\n * @param {Array.<number>} wh\n * @param {number} [xDimIndex=0] or 1\n */\nfunction makeRectShape(xy, wh, xDimIndex) {\n    xDimIndex = xDimIndex || 0;\n    return {\n        x: xy[xDimIndex],\n        y: xy[1 - xDimIndex],\n        width: wh[xDimIndex],\n        height: wh[1 - xDimIndex]\n    };\n}\n\nfunction makeSectorShape(cx, cy, r0, r, startAngle, endAngle) {\n    return {\n        cx: cx,\n        cy: cy,\n        r0: r0,\n        r: r,\n        startAngle: startAngle,\n        endAngle: endAngle,\n        clockwise: true\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar CartesianAxisPointer = BaseAxisPointer.extend({\n\n    /**\n     * @override\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        var axis = axisModel.axis;\n        var grid = axis.grid;\n        var axisPointerType = axisPointerModel.get('type');\n        var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent();\n        var pixelValue = axis.toGlobalCoord(axis.dataToCoord(value, true));\n\n        if (axisPointerType && axisPointerType !== 'none') {\n            var elStyle = buildElStyle(axisPointerModel);\n            var pointerOption = pointerShapeBuilder[axisPointerType](\n                axis, pixelValue, otherExtent, elStyle\n            );\n            pointerOption.style = elStyle;\n            elOption.graphicKey = pointerOption.type;\n            elOption.pointer = pointerOption;\n        }\n\n        var layoutInfo = layout$1(grid.model, axisModel);\n        buildCartesianSingleLabelElOption(\n            value, elOption, layoutInfo, axisModel, axisPointerModel, api\n        );\n    },\n\n    /**\n     * @override\n     */\n    getHandleTransform: function (value, axisModel, axisPointerModel) {\n        var layoutInfo = layout$1(axisModel.axis.grid.model, axisModel, {\n            labelInside: false\n        });\n        layoutInfo.labelMargin = axisPointerModel.get('handle.margin');\n        return {\n            position: getTransformedPosition(axisModel.axis, value, layoutInfo),\n            rotation: layoutInfo.rotation + (layoutInfo.labelDirection < 0 ? Math.PI : 0)\n        };\n    },\n\n    /**\n     * @override\n     */\n    updateHandleTransform: function (transform, delta, axisModel, axisPointerModel) {\n        var axis = axisModel.axis;\n        var grid = axis.grid;\n        var axisExtent = axis.getGlobalExtent(true);\n        var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent();\n        var dimIndex = axis.dim === 'x' ? 0 : 1;\n\n        var currPosition = transform.position;\n        currPosition[dimIndex] += delta[dimIndex];\n        currPosition[dimIndex] = Math.min(axisExtent[1], currPosition[dimIndex]);\n        currPosition[dimIndex] = Math.max(axisExtent[0], currPosition[dimIndex]);\n\n        var cursorOtherValue = (otherExtent[1] + otherExtent[0]) / 2;\n        var cursorPoint = [cursorOtherValue, cursorOtherValue];\n        cursorPoint[dimIndex] = currPosition[dimIndex];\n\n        // Make tooltip do not overlap axisPointer and in the middle of the grid.\n        var tooltipOptions = [{verticalAlign: 'middle'}, {align: 'center'}];\n\n        return {\n            position: currPosition,\n            rotation: transform.rotation,\n            cursorPoint: cursorPoint,\n            tooltipOption: tooltipOptions[dimIndex]\n        };\n    }\n\n});\n\nfunction getCartesian(grid, axis) {\n    var opt = {};\n    opt[axis.dim + 'AxisIndex'] = axis.index;\n    return grid.getCartesian(opt);\n}\n\nvar pointerShapeBuilder = {\n\n    line: function (axis, pixelValue, otherExtent, elStyle) {\n        var targetShape = makeLineShape(\n            [pixelValue, otherExtent[0]],\n            [pixelValue, otherExtent[1]],\n            getAxisDimIndex(axis)\n        );\n        subPixelOptimizeLine({\n            shape: targetShape,\n            style: elStyle\n        });\n        return {\n            type: 'Line',\n            shape: targetShape\n        };\n    },\n\n    shadow: function (axis, pixelValue, otherExtent, elStyle) {\n        var bandWidth = Math.max(1, axis.getBandWidth());\n        var span = otherExtent[1] - otherExtent[0];\n        return {\n            type: 'Rect',\n            shape: makeRectShape(\n                [pixelValue - bandWidth / 2, otherExtent[0]],\n                [bandWidth, span],\n                getAxisDimIndex(axis)\n            )\n        };\n    }\n};\n\nfunction getAxisDimIndex(axis) {\n    return axis.dim === 'x' ? 0 : 1;\n}\n\nAxisView.registerAxisPointerClass('CartesianAxisPointer', CartesianAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// CartesianAxisPointer is not supposed to be required here. But consider\n// echarts.simple.js and online build tooltip, which only require gridSimple,\n// CartesianAxisPointer should be able to required somewhere.\nregisterPreprocessor(function (option) {\n    // Always has a global axisPointerModel for default setting.\n    if (option) {\n        (!option.axisPointer || option.axisPointer.length === 0)\n            && (option.axisPointer = {});\n\n        var link = option.axisPointer.link;\n        // Normalize to array to avoid object mergin. But if link\n        // is not set, remain null/undefined, otherwise it will\n        // override existent link setting.\n        if (link && !isArray(link)) {\n            option.axisPointer.link = [link];\n        }\n    }\n});\n\n// This process should proformed after coordinate systems created\n// and series data processed. So put it on statistic processing stage.\nregisterProcessor(PRIORITY.PROCESSOR.STATISTIC, function (ecModel, api) {\n    // Build axisPointerModel, mergin tooltip.axisPointer model for each axis.\n    // allAxesInfo should be updated when setOption performed.\n    ecModel.getComponent('axisPointer').coordSysAxesInfo\n        = collect(ecModel, api);\n});\n\n// Broadcast to all views.\nregisterAction({\n    type: 'updateAxisPointer',\n    event: 'updateAxisPointer',\n    update: ':updateAxisPointer'\n}, axisTrigger);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar XY = ['x', 'y'];\nvar WH = ['width', 'height'];\n\nvar SingleAxisPointer = BaseAxisPointer.extend({\n\n    /**\n     * @override\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        var axis = axisModel.axis;\n        var coordSys = axis.coordinateSystem;\n        var otherExtent = getGlobalExtent(coordSys, 1 - getPointDimIndex(axis));\n        var pixelValue = coordSys.dataToPoint(value)[0];\n\n        var axisPointerType = axisPointerModel.get('type');\n        if (axisPointerType && axisPointerType !== 'none') {\n            var elStyle = buildElStyle(axisPointerModel);\n            var pointerOption = pointerShapeBuilder$1[axisPointerType](\n                axis, pixelValue, otherExtent, elStyle\n            );\n            pointerOption.style = elStyle;\n\n            elOption.graphicKey = pointerOption.type;\n            elOption.pointer = pointerOption;\n        }\n\n        var layoutInfo = layout$2(axisModel);\n        buildCartesianSingleLabelElOption(\n            value, elOption, layoutInfo, axisModel, axisPointerModel, api\n        );\n    },\n\n    /**\n     * @override\n     */\n    getHandleTransform: function (value, axisModel, axisPointerModel) {\n        var layoutInfo = layout$2(axisModel, {labelInside: false});\n        layoutInfo.labelMargin = axisPointerModel.get('handle.margin');\n        return {\n            position: getTransformedPosition(axisModel.axis, value, layoutInfo),\n            rotation: layoutInfo.rotation + (layoutInfo.labelDirection < 0 ? Math.PI : 0)\n        };\n    },\n\n    /**\n     * @override\n     */\n    updateHandleTransform: function (transform, delta, axisModel, axisPointerModel) {\n        var axis = axisModel.axis;\n        var coordSys = axis.coordinateSystem;\n        var dimIndex = getPointDimIndex(axis);\n        var axisExtent = getGlobalExtent(coordSys, dimIndex);\n        var currPosition = transform.position;\n        currPosition[dimIndex] += delta[dimIndex];\n        currPosition[dimIndex] = Math.min(axisExtent[1], currPosition[dimIndex]);\n        currPosition[dimIndex] = Math.max(axisExtent[0], currPosition[dimIndex]);\n        var otherExtent = getGlobalExtent(coordSys, 1 - dimIndex);\n        var cursorOtherValue = (otherExtent[1] + otherExtent[0]) / 2;\n        var cursorPoint = [cursorOtherValue, cursorOtherValue];\n        cursorPoint[dimIndex] = currPosition[dimIndex];\n\n        return {\n            position: currPosition,\n            rotation: transform.rotation,\n            cursorPoint: cursorPoint,\n            tooltipOption: {\n                verticalAlign: 'middle'\n            }\n        };\n    }\n});\n\nvar pointerShapeBuilder$1 = {\n\n    line: function (axis, pixelValue, otherExtent, elStyle) {\n        var targetShape = makeLineShape(\n            [pixelValue, otherExtent[0]],\n            [pixelValue, otherExtent[1]],\n            getPointDimIndex(axis)\n        );\n        subPixelOptimizeLine({\n            shape: targetShape,\n            style: elStyle\n        });\n        return {\n            type: 'Line',\n            shape: targetShape\n        };\n    },\n\n    shadow: function (axis, pixelValue, otherExtent, elStyle) {\n        var bandWidth = axis.getBandWidth();\n        var span = otherExtent[1] - otherExtent[0];\n        return {\n            type: 'Rect',\n            shape: makeRectShape(\n                [pixelValue - bandWidth / 2, otherExtent[0]],\n                [bandWidth, span],\n                getPointDimIndex(axis)\n            )\n        };\n    }\n};\n\nfunction getPointDimIndex(axis) {\n    return axis.isHorizontal() ? 0 : 1;\n}\n\nfunction getGlobalExtent(coordSys, dimIndex) {\n    var rect = coordSys.getRect();\n    return [rect[XY[dimIndex]], rect[XY[dimIndex]] + rect[WH[dimIndex]]];\n}\n\nAxisView.registerAxisPointerClass('SingleAxisPointer', SingleAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentView({\n    type: 'single'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file  Define the themeRiver view's series model\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar DATA_NAME_INDEX = 2;\n\nvar ThemeRiverSeries = SeriesModel.extend({\n\n    type: 'series.themeRiver',\n\n    dependencies: ['singleAxis'],\n\n    /**\n     * @readOnly\n     * @type {module:zrender/core/util#HashMap}\n     */\n    nameMap: null,\n\n    /**\n     * @override\n     */\n    init: function (option) {\n        // eslint-disable-next-line\n        ThemeRiverSeries.superApply(this, 'init', arguments);\n\n        // Put this function here is for the sake of consistency of code style.\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n    },\n\n    /**\n     * If there is no value of a certain point in the time for some event,set it value to 0.\n     *\n     * @param {Array} data  initial data in the option\n     * @return {Array}\n     */\n    fixData: function (data) {\n        var rawDataLength = data.length;\n\n        // grouped data by name\n        var groupResult = groupData(data, function (item) {\n            return item[2];\n        });\n        var layData = [];\n        groupResult.buckets.each(function (items, key) {\n            layData.push({name: key, dataList: items});\n        });\n\n        var layerNum = layData.length;\n        var largestLayer = -1;\n        var index = -1;\n        for (var i = 0; i < layerNum; ++i) {\n            var len = layData[i].dataList.length;\n            if (len > largestLayer) {\n                largestLayer = len;\n                index = i;\n            }\n        }\n\n        for (var k = 0; k < layerNum; ++k) {\n            if (k === index) {\n                continue;\n            }\n            var name = layData[k].name;\n            for (var j = 0; j < largestLayer; ++j) {\n                var timeValue = layData[index].dataList[j][0];\n                var length = layData[k].dataList.length;\n                var keyIndex = -1;\n                for (var l = 0; l < length; ++l) {\n                    var value = layData[k].dataList[l][0];\n                    if (value === timeValue) {\n                        keyIndex = l;\n                        break;\n                    }\n                }\n                if (keyIndex === -1) {\n                    data[rawDataLength] = [];\n                    data[rawDataLength][0] = timeValue;\n                    data[rawDataLength][1] = 0;\n                    data[rawDataLength][2] = name;\n                    rawDataLength++;\n\n                }\n            }\n        }\n        return data;\n    },\n\n    /**\n     * @override\n     * @param  {Object} option  the initial option that user gived\n     * @param  {module:echarts/model/Model} ecModel  the model object for themeRiver option\n     * @return {module:echarts/data/List}\n     */\n    getInitialData: function (option, ecModel) {\n\n        var singleAxisModel = ecModel.queryComponents({\n            mainType: 'singleAxis',\n            index: this.get('singleAxisIndex'),\n            id: this.get('singleAxisId')\n        })[0];\n\n        var axisType = singleAxisModel.get('type');\n\n        // filter the data item with the value of label is undefined\n        var filterData = filter(option.data, function (dataItem) {\n            return dataItem[2] !== undefined;\n        });\n\n        // ??? TODO design a stage to transfer data for themeRiver and lines?\n        var data = this.fixData(filterData || []);\n        var nameList = [];\n        var nameMap = this.nameMap = createHashMap();\n        var count = 0;\n\n        for (var i = 0; i < data.length; ++i) {\n            nameList.push(data[i][DATA_NAME_INDEX]);\n            if (!nameMap.get(data[i][DATA_NAME_INDEX])) {\n                nameMap.set(data[i][DATA_NAME_INDEX], count);\n                count++;\n            }\n        }\n\n        var dimensionsInfo = createDimensions(data, {\n            coordDimensions: ['single'],\n            dimensionsDefine: [\n                {\n                    name: 'time',\n                    type: getDimensionTypeByAxis(axisType)\n                },\n                {\n                    name: 'value',\n                    type: 'float'\n                },\n                {\n                    name: 'name',\n                    type: 'ordinal'\n                }\n            ],\n            encodeDefine: {\n                single: 0,\n                value: 1,\n                itemName: 2\n            }\n        });\n\n        var list = new List(dimensionsInfo, this);\n        list.initData(data);\n\n        return list;\n    },\n\n    /**\n     * The raw data is divided into multiple layers and each layer\n     *     has same name.\n     *\n     * @return {Array.<Array.<number>>}\n     */\n    getLayerSeries: function () {\n        var data = this.getData();\n        var lenCount = data.count();\n        var indexArr = [];\n\n        for (var i = 0; i < lenCount; ++i) {\n            indexArr[i] = i;\n        }\n\n        var timeDim = data.mapDimension('single');\n\n        // data group by name\n        var groupResult = groupData(indexArr, function (index) {\n            return data.get('name', index);\n        });\n        var layerSeries = [];\n        groupResult.buckets.each(function (items, key) {\n            items.sort(function (index1, index2) {\n                return data.get(timeDim, index1) - data.get(timeDim, index2);\n            });\n            layerSeries.push({name: key, indices: items});\n        });\n\n        return layerSeries;\n    },\n\n    /**\n     * Get data indices for show tooltip content\n     *\n     * @param {Array.<string>|string} dim  single coordinate dimension\n     * @param {number} value axis value\n     * @param {module:echarts/coord/single/SingleAxis} baseAxis  single Axis used\n     *     the themeRiver.\n     * @return {Object} {dataIndices, nestestValue}\n     */\n    getAxisTooltipData: function (dim, value, baseAxis) {\n        if (!isArray(dim)) {\n            dim = dim ? [dim] : [];\n        }\n\n        var data = this.getData();\n        var layerSeries = this.getLayerSeries();\n        var indices = [];\n        var layerNum = layerSeries.length;\n        var nestestValue;\n\n        for (var i = 0; i < layerNum; ++i) {\n            var minDist = Number.MAX_VALUE;\n            var nearestIdx = -1;\n            var pointNum = layerSeries[i].indices.length;\n            for (var j = 0; j < pointNum; ++j) {\n                var theValue = data.get(dim[0], layerSeries[i].indices[j]);\n                var dist = Math.abs(theValue - value);\n                if (dist <= minDist) {\n                    nestestValue = theValue;\n                    minDist = dist;\n                    nearestIdx = layerSeries[i].indices[j];\n                }\n            }\n            indices.push(nearestIdx);\n        }\n\n        return {dataIndices: indices, nestestValue: nestestValue};\n    },\n\n    /**\n     * @override\n     * @param {number} dataIndex  index of data\n     */\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var htmlName = data.getName(dataIndex);\n        var htmlValue = data.get(data.mapDimension('value'), dataIndex);\n        if (isNaN(htmlValue) || htmlValue == null) {\n            htmlValue = '-';\n        }\n        return encodeHTML(htmlName + ' : ' + htmlValue);\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n\n        coordinateSystem: 'singleAxis',\n\n        // gap in axis's orthogonal orientation\n        boundaryGap: ['10%', '10%'],\n\n        // legendHoverLink: true,\n\n        singleAxisIndex: 0,\n\n        animationEasing: 'linear',\n\n        label: {\n            margin: 4,\n            show: true,\n            position: 'left',\n            color: '#000',\n            fontSize: 11\n        },\n\n        emphasis: {\n            label: {\n                show: true\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file  The file used to draw themeRiver view\n * @author  Deqing Li(annong035@gmail.com)\n */\n\nextendChartView({\n\n    type: 'themeRiver',\n\n    init: function () {\n        this._layers = [];\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var data = seriesModel.getData();\n\n        var group = this.group;\n\n        var layerSeries = seriesModel.getLayerSeries();\n\n        var layoutInfo = data.getLayout('layoutInfo');\n        var rect = layoutInfo.rect;\n        var boundaryGap = layoutInfo.boundaryGap;\n\n        group.attr('position', [0, rect.y + boundaryGap[0]]);\n\n        function keyGetter(item) {\n            return item.name;\n        }\n        var dataDiffer = new DataDiffer(\n            this._layersSeries || [], layerSeries,\n            keyGetter, keyGetter\n        );\n\n        var newLayersGroups = {};\n\n        dataDiffer\n            .add(bind(process, this, 'add'))\n            .update(bind(process, this, 'update'))\n            .remove(bind(process, this, 'remove'))\n            .execute();\n\n        function process(status, idx, oldIdx) {\n            var oldLayersGroups = this._layers;\n            if (status === 'remove') {\n                group.remove(oldLayersGroups[idx]);\n                return;\n            }\n            var points0 = [];\n            var points1 = [];\n            var color;\n            var indices = layerSeries[idx].indices;\n            for (var j = 0; j < indices.length; j++) {\n                var layout = data.getItemLayout(indices[j]);\n                var x = layout.x;\n                var y0 = layout.y0;\n                var y = layout.y;\n\n                points0.push([x, y0]);\n                points1.push([x, y0 + y]);\n\n                color = data.getItemVisual(indices[j], 'color');\n            }\n\n            var polygon;\n            var text;\n            var textLayout = data.getItemLayout(indices[0]);\n            var itemModel = data.getItemModel(indices[j - 1]);\n            var labelModel = itemModel.getModel('label');\n            var margin = labelModel.get('margin');\n            if (status === 'add') {\n                var layerGroup = newLayersGroups[idx] = new Group();\n                polygon = new Polygon$1({\n                    shape: {\n                        points: points0,\n                        stackedOnPoints: points1,\n                        smooth: 0.4,\n                        stackedOnSmooth: 0.4,\n                        smoothConstraint: false\n                    },\n                    z2: 0\n                });\n                text = new Text({\n                    style: {\n                        x: textLayout.x - margin,\n                        y: textLayout.y0 + textLayout.y / 2\n                    }\n                });\n                layerGroup.add(polygon);\n                layerGroup.add(text);\n                group.add(layerGroup);\n\n                polygon.setClipPath(createGridClipShape$3(polygon.getBoundingRect(), seriesModel, function () {\n                    polygon.removeClipPath();\n                }));\n            }\n            else {\n                var layerGroup = oldLayersGroups[oldIdx];\n                polygon = layerGroup.childAt(0);\n                text = layerGroup.childAt(1);\n                group.add(layerGroup);\n\n                newLayersGroups[idx] = layerGroup;\n\n                updateProps(polygon, {\n                    shape: {\n                        points: points0,\n                        stackedOnPoints: points1\n                    }\n                }, seriesModel);\n\n                updateProps(text, {\n                    style: {\n                        x: textLayout.x - margin,\n                        y: textLayout.y0 + textLayout.y / 2\n                    }\n                }, seriesModel);\n            }\n\n            var hoverItemStyleModel = itemModel.getModel('emphasis.itemStyle');\n            var itemStyleModel = itemModel.getModel('itemStyle');\n\n            setTextStyle(text.style, labelModel, {\n                text: labelModel.get('show')\n                    ? seriesModel.getFormattedLabel(indices[j - 1], 'normal')\n                        || data.getName(indices[j - 1])\n                    : null,\n                textVerticalAlign: 'middle'\n            });\n\n            polygon.setStyle(extend({\n                fill: color\n            }, itemStyleModel.getItemStyle(['color'])));\n\n            setHoverStyle(polygon, hoverItemStyleModel.getItemStyle());\n        }\n\n        this._layersSeries = layerSeries;\n        this._layers = newLayersGroups;\n    },\n\n    dispose: function () {}\n});\n\n// add animation to the view\nfunction createGridClipShape$3(rect, seriesModel, cb) {\n    var rectEl = new Rect({\n        shape: {\n            x: rect.x - 10,\n            y: rect.y - 10,\n            width: 0,\n            height: rect.height + 20\n        }\n    });\n    initProps(rectEl, {\n        shape: {\n            width: rect.width + 20,\n            height: rect.height + 20\n        }\n    }, seriesModel, cb);\n\n    return rectEl;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file  Using layout algorithm transform the raw data to layout information.\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar themeRiverLayout = function (ecModel, api) {\n\n    ecModel.eachSeriesByType('themeRiver', function (seriesModel) {\n\n        var data = seriesModel.getData();\n\n        var single = seriesModel.coordinateSystem;\n\n        var layoutInfo = {};\n\n        // use the axis boundingRect for view\n        var rect = single.getRect();\n\n        layoutInfo.rect = rect;\n\n        var boundaryGap = seriesModel.get('boundaryGap');\n\n        var axis = single.getAxis();\n\n        layoutInfo.boundaryGap = boundaryGap;\n\n        if (axis.orient === 'horizontal') {\n            boundaryGap[0] = parsePercent$1(boundaryGap[0], rect.height);\n            boundaryGap[1] = parsePercent$1(boundaryGap[1], rect.height);\n            var height = rect.height - boundaryGap[0] - boundaryGap[1];\n            themeRiverLayout$1(data, seriesModel, height);\n        }\n        else {\n            boundaryGap[0] = parsePercent$1(boundaryGap[0], rect.width);\n            boundaryGap[1] = parsePercent$1(boundaryGap[1], rect.width);\n            var width = rect.width - boundaryGap[0] - boundaryGap[1];\n            themeRiverLayout$1(data, seriesModel, width);\n        }\n\n        data.setLayout('layoutInfo', layoutInfo);\n    });\n};\n\n/**\n * The layout information about themeriver\n *\n * @param {module:echarts/data/List} data  data in the series\n * @param {module:echarts/model/Series} seriesModel  the model object of themeRiver series\n * @param {number} height  value used to compute every series height\n */\nfunction themeRiverLayout$1(data, seriesModel, height) {\n    if (!data.count()) {\n        return;\n    }\n    var coordSys = seriesModel.coordinateSystem;\n    // the data in each layer are organized into a series.\n    var layerSeries = seriesModel.getLayerSeries();\n\n    // the points in each layer.\n    var timeDim = data.mapDimension('single');\n    var valueDim = data.mapDimension('value');\n    var layerPoints = map(layerSeries, function (singleLayer) {\n        return map(singleLayer.indices, function (idx) {\n            var pt = coordSys.dataToPoint(data.get(timeDim, idx));\n            pt[1] = data.get(valueDim, idx);\n            return pt;\n        });\n    });\n\n    var base = computeBaseline(layerPoints);\n    var baseLine = base.y0;\n    var ky = height / base.max;\n\n    // set layout information for each item.\n    var n = layerSeries.length;\n    var m = layerSeries[0].indices.length;\n    var baseY0;\n    for (var j = 0; j < m; ++j) {\n        baseY0 = baseLine[j] * ky;\n        data.setItemLayout(layerSeries[0].indices[j], {\n            layerIndex: 0,\n            x: layerPoints[0][j][0],\n            y0: baseY0,\n            y: layerPoints[0][j][1] * ky\n        });\n        for (var i = 1; i < n; ++i) {\n            baseY0 += layerPoints[i - 1][j][1] * ky;\n            data.setItemLayout(layerSeries[i].indices[j], {\n                layerIndex: i,\n                x: layerPoints[i][j][0],\n                y0: baseY0,\n                y: layerPoints[i][j][1] * ky\n            });\n        }\n    }\n}\n\n/**\n * Compute the baseLine of the rawdata\n * Inspired by Lee Byron's paper Stacked Graphs - Geometry & Aesthetics\n *\n * @param  {Array.<Array>} data  the points in each layer\n * @return {Object}\n */\nfunction computeBaseline(data) {\n    var layerNum = data.length;\n    var pointNum = data[0].length;\n    var sums = [];\n    var y0 = [];\n    var max = 0;\n    var temp;\n    var base = {};\n\n    for (var i = 0; i < pointNum; ++i) {\n        for (var j = 0, temp = 0; j < layerNum; ++j) {\n            temp += data[j][i][1];\n        }\n        if (temp > max) {\n            max = temp;\n        }\n        sums.push(temp);\n    }\n\n    for (var k = 0; k < pointNum; ++k) {\n        y0[k] = (max - sums[k]) / 2;\n    }\n    max = 0;\n\n    for (var l = 0; l < pointNum; ++l) {\n        var sum = sums[l] + y0[l];\n        if (sum > max) {\n            max = sum;\n        }\n    }\n    base.y0 = y0;\n    base.max = max;\n\n    return base;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Visual encoding for themeRiver view\n * @author Deqing Li(annong035@gmail.com)\n */\n\nvar themeRiverVisual = function (ecModel) {\n    ecModel.eachSeriesByType('themeRiver', function (seriesModel) {\n        var data = seriesModel.getData();\n        var rawData = seriesModel.getRawData();\n        var colorList = seriesModel.get('color');\n        var idxMap = createHashMap();\n\n        data.each(function (idx) {\n            idxMap.set(data.getRawIndex(idx), idx);\n        });\n\n        rawData.each(function (rawIndex) {\n            var name = rawData.getName(rawIndex);\n            var color = colorList[(seriesModel.nameMap.get(name) - 1) % colorList.length];\n\n            rawData.setItemVisual(rawIndex, 'color', color);\n\n            var idx = idxMap.get(rawIndex);\n\n            if (idx != null) {\n                data.setItemVisual(idx, 'color', color);\n            }\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterLayout(themeRiverLayout);\nregisterVisual(themeRiverVisual);\nregisterProcessor(dataFilter('themeRiver'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.sunburst',\n\n    /**\n     * @type {module:echarts/data/Tree~Node}\n     */\n    _viewRoot: null,\n\n    getInitialData: function (option, ecModel) {\n        // Create a virtual root.\n        var root = { name: option.name, children: option.data };\n\n        completeTreeValue$1(root);\n\n        var levels = option.levels || [];\n\n        // levels = option.levels = setDefault(levels, ecModel);\n\n        var treeOption = {};\n\n        treeOption.levels = levels;\n\n        // Make sure always a new tree is created when setOption,\n        // in TreemapView, we check whether oldTree === newTree\n        // to choose mappings approach among old shapes and new shapes.\n        return Tree.createTree(root, this, treeOption).data;\n    },\n\n    optionUpdated: function () {\n        this.resetViewRoot();\n    },\n\n    /*\n     * @override\n     */\n    getDataParams: function (dataIndex) {\n        var params = SeriesModel.prototype.getDataParams.apply(this, arguments);\n\n        var node = this.getData().tree.getNodeByDataIndex(dataIndex);\n        params.treePathInfo = wrapTreePathInfo(node, this);\n\n        return params;\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n\n        // 默认全局居中\n        center: ['50%', '50%'],\n        radius: [0, '75%'],\n        // 默认顺时针\n        clockwise: true,\n        startAngle: 90,\n        // 最小角度改为0\n        minAngle: 0,\n\n        percentPrecision: 2,\n\n        // If still show when all data zero.\n        stillShowZeroSum: true,\n\n        // Policy of highlighting pieces when hover on one\n        // Valid values: 'none' (for not downplay others), 'descendant',\n        // 'ancestor', 'self'\n        highlightPolicy: 'descendant',\n\n        // 'rootToNode', 'link', or false\n        nodeClick: 'rootToNode',\n\n        renderLabelForZeroData: false,\n\n        label: {\n            // could be: 'radial', 'tangential', or 'none'\n            rotate: 'radial',\n            show: true,\n            opacity: 1,\n            // 'left' is for inner side of inside, and 'right' is for outter\n            // side for inside\n            align: 'center',\n            position: 'inside',\n            distance: 5,\n            silent: true,\n            emphasis: {}\n        },\n        itemStyle: {\n            borderWidth: 1,\n            borderColor: 'white',\n            borderType: 'solid',\n            shadowBlur: 0,\n            shadowColor: 'rgba(0, 0, 0, 0.2)',\n            shadowOffsetX: 0,\n            shadowOffsetY: 0,\n            opacity: 1,\n            emphasis: {},\n            highlight: {\n                opacity: 1\n            },\n            downplay: {\n                opacity: 0.9\n            }\n        },\n\n        // Animation type canbe expansion, scale\n        animationType: 'expansion',\n        animationDuration: 1000,\n        animationDurationUpdate: 500,\n        animationEasing: 'cubicOut',\n\n        data: [],\n\n        levels: [],\n\n        /**\n         * Sort order.\n         *\n         * Valid values: 'desc', 'asc', null, or callback function.\n         * 'desc' and 'asc' for descend and ascendant order;\n         * null for not sorting;\n         * example of callback function:\n         * function(nodeA, nodeB) {\n         *     return nodeA.getValue() - nodeB.getValue();\n         * }\n         */\n        sort: 'desc'\n    },\n\n    getViewRoot: function () {\n        return this._viewRoot;\n    },\n\n    /**\n     * @param {module:echarts/data/Tree~Node} [viewRoot]\n     */\n    resetViewRoot: function (viewRoot) {\n        viewRoot\n            ? (this._viewRoot = viewRoot)\n            : (viewRoot = this._viewRoot);\n\n        var root = this.getRawData().tree.root;\n\n        if (!viewRoot\n            || (viewRoot !== root && !root.contains(viewRoot))\n        ) {\n            this._viewRoot = root;\n        }\n    }\n});\n\n\n\n/**\n * @param {Object} dataNode\n */\nfunction completeTreeValue$1(dataNode) {\n    // Postorder travel tree.\n    // If value of none-leaf node is not set,\n    // calculate it by suming up the value of all children.\n    var sum = 0;\n\n    each$1(dataNode.children, function (child) {\n\n        completeTreeValue$1(child);\n\n        var childValue = child.value;\n        isArray(childValue) && (childValue = childValue[0]);\n\n        sum += childValue;\n    });\n\n    var thisValue = dataNode.value;\n    if (isArray(thisValue)) {\n        thisValue = thisValue[0];\n    }\n\n    if (thisValue == null || isNaN(thisValue)) {\n        thisValue = sum;\n    }\n    // Value should not less than 0.\n    if (thisValue < 0) {\n        thisValue = 0;\n    }\n\n    isArray(dataNode.value)\n        ? (dataNode.value[0] = thisValue)\n        : (dataNode.value = thisValue);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar NodeHighlightPolicy = {\n    NONE: 'none', // not downplay others\n    DESCENDANT: 'descendant',\n    ANCESTOR: 'ancestor',\n    SELF: 'self'\n};\n\nvar DEFAULT_SECTOR_Z = 2;\nvar DEFAULT_TEXT_Z = 4;\n\n/**\n * Sunburstce of Sunburst including Sector, Label, LabelLine\n * @constructor\n * @extends {module:zrender/graphic/Group}\n */\nfunction SunburstPiece(node, seriesModel, ecModel) {\n\n    Group.call(this);\n\n    var sector = new Sector({\n        z2: DEFAULT_SECTOR_Z\n    });\n    sector.seriesIndex = seriesModel.seriesIndex;\n\n    var text = new Text({\n        z2: DEFAULT_TEXT_Z,\n        silent: node.getModel('label').get('silent')\n    });\n    this.add(sector);\n    this.add(text);\n\n    this.updateData(true, node, 'normal', seriesModel, ecModel);\n\n    // Hover to change label and labelLine\n    function onEmphasis() {\n        text.ignore = text.hoverIgnore;\n    }\n    function onNormal() {\n        text.ignore = text.normalIgnore;\n    }\n    this.on('emphasis', onEmphasis)\n        .on('normal', onNormal)\n        .on('mouseover', onEmphasis)\n        .on('mouseout', onNormal);\n}\n\nvar SunburstPieceProto = SunburstPiece.prototype;\n\nSunburstPieceProto.updateData = function (\n    firstCreate,\n    node,\n    state,\n    seriesModel,\n    ecModel\n) {\n    this.node = node;\n    node.piece = this;\n\n    seriesModel = seriesModel || this._seriesModel;\n    ecModel = ecModel || this._ecModel;\n\n    var sector = this.childAt(0);\n    sector.dataIndex = node.dataIndex;\n\n    var itemModel = node.getModel();\n    var layout = node.getLayout();\n    // if (!layout) {\n    //     console.log(node.getLayout());\n    // }\n    var sectorShape = extend({}, layout);\n    sectorShape.label = null;\n\n    var visualColor = getNodeColor(node, seriesModel, ecModel);\n\n    fillDefaultColor(node, seriesModel, visualColor);\n\n    var normalStyle = itemModel.getModel('itemStyle').getItemStyle();\n    var style;\n    if (state === 'normal') {\n        style = normalStyle;\n    }\n    else {\n        var stateStyle = itemModel.getModel(state + '.itemStyle')\n            .getItemStyle();\n        style = merge(stateStyle, normalStyle);\n    }\n    style = defaults(\n        {\n            lineJoin: 'bevel',\n            fill: style.fill || visualColor\n        },\n        style\n    );\n\n    if (firstCreate) {\n        sector.setShape(sectorShape);\n        sector.shape.r = layout.r0;\n        updateProps(\n            sector,\n            {\n                shape: {\n                    r: layout.r\n                }\n            },\n            seriesModel,\n            node.dataIndex\n        );\n        sector.useStyle(style);\n    }\n    else if (typeof style.fill === 'object' && style.fill.type\n        || typeof sector.style.fill === 'object' && sector.style.fill.type\n    ) {\n        // Disable animation for gradient since no interpolation method\n        // is supported for gradient\n        updateProps(sector, {\n            shape: sectorShape\n        }, seriesModel);\n        sector.useStyle(style);\n    }\n    else {\n        updateProps(sector, {\n            shape: sectorShape,\n            style: style\n        }, seriesModel);\n    }\n\n    this._updateLabel(seriesModel, visualColor, state);\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && sector.attr('cursor', cursorStyle);\n\n    if (firstCreate) {\n        var highlightPolicy = seriesModel.getShallow('highlightPolicy');\n        this._initEvents(sector, node, seriesModel, highlightPolicy);\n    }\n\n    this._seriesModel = seriesModel || this._seriesModel;\n    this._ecModel = ecModel || this._ecModel;\n};\n\nSunburstPieceProto.onEmphasis = function (highlightPolicy) {\n    var that = this;\n    this.node.hostTree.root.eachNode(function (n) {\n        if (n.piece) {\n            if (that.node === n) {\n                n.piece.updateData(false, n, 'emphasis');\n            }\n            else if (isNodeHighlighted(n, that.node, highlightPolicy)) {\n                n.piece.childAt(0).trigger('highlight');\n            }\n            else if (highlightPolicy !== NodeHighlightPolicy.NONE) {\n                n.piece.childAt(0).trigger('downplay');\n            }\n        }\n    });\n};\n\nSunburstPieceProto.onNormal = function () {\n    this.node.hostTree.root.eachNode(function (n) {\n        if (n.piece) {\n            n.piece.updateData(false, n, 'normal');\n        }\n    });\n};\n\nSunburstPieceProto.onHighlight = function () {\n    this.updateData(false, this.node, 'highlight');\n};\n\nSunburstPieceProto.onDownplay = function () {\n    this.updateData(false, this.node, 'downplay');\n};\n\nSunburstPieceProto._updateLabel = function (seriesModel, visualColor, state) {\n    var itemModel = this.node.getModel();\n    var normalModel = itemModel.getModel('label');\n    var labelModel = state === 'normal' || state === 'emphasis'\n        ? normalModel\n        : itemModel.getModel(state + '.label');\n    var labelHoverModel = itemModel.getModel('emphasis.label');\n\n    var text = retrieve(\n        seriesModel.getFormattedLabel(\n            this.node.dataIndex, 'normal', null, null, 'label'\n        ),\n        this.node.name\n    );\n    if (getLabelAttr('show') === false) {\n        text = '';\n    }\n\n    var layout = this.node.getLayout();\n    var labelMinAngle = labelModel.get('minAngle');\n    if (labelMinAngle == null) {\n        labelMinAngle = normalModel.get('minAngle');\n    }\n    labelMinAngle = labelMinAngle / 180 * Math.PI;\n    var angle = layout.endAngle - layout.startAngle;\n    if (labelMinAngle != null && Math.abs(angle) < labelMinAngle) {\n        // Not displaying text when angle is too small\n        text = '';\n    }\n\n    var label = this.childAt(1);\n\n    setLabelStyle(\n        label.style, label.hoverStyle || {}, normalModel, labelHoverModel,\n        {\n            defaultText: labelModel.getShallow('show') ? text : null,\n            autoColor: visualColor,\n            useInsideStyle: true\n        }\n    );\n\n    var midAngle = (layout.startAngle + layout.endAngle) / 2;\n    var dx = Math.cos(midAngle);\n    var dy = Math.sin(midAngle);\n\n    var r;\n    var labelPosition = getLabelAttr('position');\n    var labelPadding = getLabelAttr('distance') || 0;\n    var textAlign = getLabelAttr('align');\n    if (labelPosition === 'outside') {\n        r = layout.r + labelPadding;\n        textAlign = midAngle > Math.PI / 2 ? 'right' : 'left';\n    }\n    else {\n        if (!textAlign || textAlign === 'center') {\n            r = (layout.r + layout.r0) / 2;\n            textAlign = 'center';\n        }\n        else if (textAlign === 'left') {\n            r = layout.r0 + labelPadding;\n            if (midAngle > Math.PI / 2) {\n                textAlign = 'right';\n            }\n        }\n        else if (textAlign === 'right') {\n            r = layout.r - labelPadding;\n            if (midAngle > Math.PI / 2) {\n                textAlign = 'left';\n            }\n        }\n    }\n\n    label.attr('style', {\n        text: text,\n        textAlign: textAlign,\n        textVerticalAlign: getLabelAttr('verticalAlign') || 'middle',\n        opacity: getLabelAttr('opacity')\n    });\n\n    var textX = r * dx + layout.cx;\n    var textY = r * dy + layout.cy;\n    label.attr('position', [textX, textY]);\n\n    var rotateType = getLabelAttr('rotate');\n    var rotate = 0;\n    if (rotateType === 'radial') {\n        rotate = -midAngle;\n        if (rotate < -Math.PI / 2) {\n            rotate += Math.PI;\n        }\n    }\n    else if (rotateType === 'tangential') {\n        rotate = Math.PI / 2 - midAngle;\n        if (rotate > Math.PI / 2) {\n            rotate -= Math.PI;\n        }\n        else if (rotate < -Math.PI / 2) {\n            rotate += Math.PI;\n        }\n    } else if (typeof rotateType === 'number') {\n        rotate = rotateType * Math.PI / 180;\n    }\n    label.attr('rotation', rotate);\n\n    function getLabelAttr(name) {\n        var stateAttr = labelModel.get(name);\n        if (stateAttr == null) {\n            return normalModel.get(name);\n        }\n        else {\n            return stateAttr;\n        }\n    }\n};\n\nSunburstPieceProto._initEvents = function (\n    sector,\n    node,\n    seriesModel,\n    highlightPolicy\n) {\n    sector.off('mouseover').off('mouseout').off('emphasis').off('normal');\n\n    var that = this;\n    var onEmphasis = function () {\n        that.onEmphasis(highlightPolicy);\n    };\n    var onNormal = function () {\n        that.onNormal();\n    };\n    var onDownplay = function () {\n        that.onDownplay();\n    };\n    var onHighlight = function () {\n        that.onHighlight();\n    };\n\n    if (seriesModel.isAnimationEnabled()) {\n        sector\n            .on('mouseover', onEmphasis)\n            .on('mouseout', onNormal)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal)\n            .on('downplay', onDownplay)\n            .on('highlight', onHighlight);\n    }\n};\n\ninherits(SunburstPiece, Group);\n\n/**\n * Get node color\n *\n * @param {TreeNode} node the node to get color\n * @param {module:echarts/model/Series} seriesModel series\n * @param {module:echarts/model/Global} ecModel echarts defaults\n */\nfunction getNodeColor(node, seriesModel, ecModel) {\n    // Color from visualMap\n    var visualColor = node.getVisual('color');\n    var visualMetaList = node.getVisual('visualMeta');\n    if (!visualMetaList || visualMetaList.length === 0) {\n        // Use first-generation color if has no visualMap\n        visualColor = null;\n    }\n\n    // Self color or level color\n    var color = node.getModel('itemStyle').get('color');\n    if (color) {\n        return color;\n    }\n    else if (visualColor) {\n        // Color mapping\n        return visualColor;\n    }\n    else if (node.depth === 0) {\n        // Virtual root node\n        return ecModel.option.color[0];\n    }\n    else {\n        // First-generation color\n        var length = ecModel.option.color.length;\n        color = ecModel.option.color[getRootId(node) % length];\n    }\n    return color;\n}\n\n/**\n * Get index of root in sorted order\n *\n * @param {TreeNode} node current node\n * @return {number} index in root\n */\nfunction getRootId(node) {\n    var ancestor = node;\n    while (ancestor.depth > 1) {\n        ancestor = ancestor.parentNode;\n    }\n\n    var virtualRoot = node.getAncestors()[0];\n    return indexOf(virtualRoot.children, ancestor);\n}\n\nfunction isNodeHighlighted(node, activeNode, policy) {\n    if (policy === NodeHighlightPolicy.NONE) {\n        return false;\n    }\n    else if (policy === NodeHighlightPolicy.SELF) {\n        return node === activeNode;\n    }\n    else if (policy === NodeHighlightPolicy.ANCESTOR) {\n        return node === activeNode || node.isAncestorOf(activeNode);\n    }\n    else {\n        return node === activeNode || node.isDescendantOf(activeNode);\n    }\n}\n\n// Fix tooltip callback function params.color incorrect when pick a default color\nfunction fillDefaultColor(node, seriesModel, color) {\n    var data = seriesModel.getData();\n    data.setItemVisual(node.dataIndex, 'color', color);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ROOT_TO_NODE_ACTION = 'sunburstRootToNode';\n\nvar SunburstView = Chart.extend({\n\n    type: 'sunburst',\n\n    init: function () {\n    },\n\n    render: function (seriesModel, ecModel, api, payload) {\n        var that = this;\n\n        this.seriesModel = seriesModel;\n        this.api = api;\n        this.ecModel = ecModel;\n\n        var data = seriesModel.getData();\n        var virtualRoot = data.tree.root;\n\n        var newRoot = seriesModel.getViewRoot();\n\n        var group = this.group;\n\n        var renderLabelForZeroData = seriesModel.get('renderLabelForZeroData');\n\n        var newChildren = [];\n        newRoot.eachNode(function (node) {\n            newChildren.push(node);\n        });\n        var oldChildren = this._oldChildren || [];\n\n        dualTravel(newChildren, oldChildren);\n\n        renderRollUp(virtualRoot, newRoot);\n\n        if (payload && payload.highlight && payload.highlight.piece) {\n            var highlightPolicy = seriesModel.getShallow('highlightPolicy');\n            payload.highlight.piece.onEmphasis(highlightPolicy);\n        }\n        else if (payload && payload.unhighlight) {\n            var piece = this.virtualPiece;\n            if (!piece && virtualRoot.children.length) {\n                piece = virtualRoot.children[0].piece;\n            }\n            if (piece) {\n                piece.onNormal();\n            }\n        }\n\n        this._initEvents();\n\n        this._oldChildren = newChildren;\n\n        function dualTravel(newChildren, oldChildren) {\n            if (newChildren.length === 0 && oldChildren.length === 0) {\n                return;\n            }\n\n            new DataDiffer(oldChildren, newChildren, getKey, getKey)\n                .add(processNode)\n                .update(processNode)\n                .remove(curry(processNode, null))\n                .execute();\n\n            function getKey(node) {\n                return node.getId();\n            }\n\n            function processNode(newId, oldId) {\n                var newNode = newId == null ? null : newChildren[newId];\n                var oldNode = oldId == null ? null : oldChildren[oldId];\n\n                doRenderNode(newNode, oldNode);\n            }\n        }\n\n        function doRenderNode(newNode, oldNode) {\n            if (!renderLabelForZeroData && newNode && !newNode.getValue()) {\n                // Not render data with value 0\n                newNode = null;\n            }\n\n            if (newNode !== virtualRoot && oldNode !== virtualRoot) {\n                if (oldNode && oldNode.piece) {\n                    if (newNode) {\n                        // Update\n                        oldNode.piece.updateData(\n                            false, newNode, 'normal', seriesModel, ecModel);\n\n                        // For tooltip\n                        data.setItemGraphicEl(newNode.dataIndex, oldNode.piece);\n                    }\n                    else {\n                        // Remove\n                        removeNode(oldNode);\n                    }\n                }\n                else if (newNode) {\n                    // Add\n                    var piece = new SunburstPiece(\n                        newNode,\n                        seriesModel,\n                        ecModel\n                    );\n                    group.add(piece);\n\n                    // For tooltip\n                    data.setItemGraphicEl(newNode.dataIndex, piece);\n                }\n            }\n        }\n\n        function removeNode(node) {\n            if (!node) {\n                return;\n            }\n\n            if (node.piece) {\n                group.remove(node.piece);\n                node.piece = null;\n            }\n        }\n\n        function renderRollUp(virtualRoot, viewRoot) {\n            if (viewRoot.depth > 0) {\n                // Render\n                if (that.virtualPiece) {\n                    // Update\n                    that.virtualPiece.updateData(\n                        false, virtualRoot, 'normal', seriesModel, ecModel);\n                }\n                else {\n                    // Add\n                    that.virtualPiece = new SunburstPiece(\n                        virtualRoot,\n                        seriesModel,\n                        ecModel\n                    );\n                    group.add(that.virtualPiece);\n                }\n\n                if (viewRoot.piece._onclickEvent) {\n                    viewRoot.piece.off('click', viewRoot.piece._onclickEvent);\n                }\n                var event = function (e) {\n                    that._rootToNode(viewRoot.parentNode);\n                };\n                viewRoot.piece._onclickEvent = event;\n                that.virtualPiece.on('click', event);\n            }\n            else if (that.virtualPiece) {\n                // Remove\n                group.remove(that.virtualPiece);\n                that.virtualPiece = null;\n            }\n        }\n    },\n\n    dispose: function () {\n    },\n\n    /**\n     * @private\n     */\n    _initEvents: function () {\n        var that = this;\n\n        var event = function (e) {\n            var targetFound = false;\n            var viewRoot = that.seriesModel.getViewRoot();\n            viewRoot.eachNode(function (node) {\n                if (!targetFound\n                    && node.piece && node.piece.childAt(0) === e.target\n                ) {\n                    var nodeClick = node.getModel().get('nodeClick');\n                    if (nodeClick === 'rootToNode') {\n                        that._rootToNode(node);\n                    }\n                    else if (nodeClick === 'link') {\n                        var itemModel = node.getModel();\n                        var link = itemModel.get('link');\n                        if (link) {\n                            var linkTarget = itemModel.get('target', true)\n                                || '_blank';\n                            window.open(link, linkTarget);\n                        }\n                    }\n                    targetFound = true;\n                }\n            });\n        };\n\n        if (this.group._onclickEvent) {\n            this.group.off('click', this.group._onclickEvent);\n        }\n        this.group.on('click', event);\n        this.group._onclickEvent = event;\n    },\n\n    /**\n     * @private\n     */\n    _rootToNode: function (node) {\n        if (node !== this.seriesModel.getViewRoot()) {\n            this.api.dispatchAction({\n                type: ROOT_TO_NODE_ACTION,\n                from: this.uid,\n                seriesId: this.seriesModel.id,\n                targetNode: node\n            });\n        }\n    },\n\n    /**\n     * @implement\n     */\n    containPoint: function (point, seriesModel) {\n        var treeRoot = seriesModel.getData();\n        var itemLayout = treeRoot.getItemLayout(0);\n        if (itemLayout) {\n            var dx = point[0] - itemLayout.cx;\n            var dy = point[1] - itemLayout.cy;\n            var radius = Math.sqrt(dx * dx + dy * dy);\n            return radius <= itemLayout.r && radius >= itemLayout.r0;\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Sunburst action\n */\n\nvar ROOT_TO_NODE_ACTION$1 = 'sunburstRootToNode';\n\nregisterAction(\n    {type: ROOT_TO_NODE_ACTION$1, update: 'updateView'},\n    function (payload, ecModel) {\n\n        ecModel.eachComponent(\n            {mainType: 'series', subType: 'sunburst', query: payload},\n            handleRootToNode\n        );\n\n        function handleRootToNode(model, index) {\n            var targetInfo = retrieveTargetInfo(payload, [ROOT_TO_NODE_ACTION$1], model);\n\n            if (targetInfo) {\n                var originViewRoot = model.getViewRoot();\n                if (originViewRoot) {\n                    payload.direction = aboveViewRoot(originViewRoot, targetInfo.node)\n                        ? 'rollUp' : 'drillDown';\n                }\n                model.resetViewRoot(targetInfo.node);\n            }\n        }\n    }\n);\n\n\nvar HIGHLIGHT_ACTION = 'sunburstHighlight';\n\nregisterAction(\n    {type: HIGHLIGHT_ACTION, update: 'updateView'},\n    function (payload, ecModel) {\n\n        ecModel.eachComponent(\n            {mainType: 'series', subType: 'sunburst', query: payload},\n            handleHighlight\n        );\n\n        function handleHighlight(model, index) {\n            var targetInfo = retrieveTargetInfo(payload, [HIGHLIGHT_ACTION], model);\n\n            if (targetInfo) {\n                payload.highlight = targetInfo.node;\n            }\n        }\n    }\n);\n\n\nvar UNHIGHLIGHT_ACTION = 'sunburstUnhighlight';\n\nregisterAction(\n    {type: UNHIGHLIGHT_ACTION, update: 'updateView'},\n    function (payload, ecModel) {\n\n        ecModel.eachComponent(\n            {mainType: 'series', subType: 'sunburst', query: payload},\n            handleUnhighlight\n        );\n\n        function handleUnhighlight(model, index) {\n            payload.unhighlight = true;\n        }\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar RADIAN$1 = Math.PI / 180;\n\nvar sunburstLayout = function (seriesType, ecModel, api, payload) {\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        var center = seriesModel.get('center');\n        var radius = seriesModel.get('radius');\n\n        if (!isArray(radius)) {\n            radius = [0, radius];\n        }\n        if (!isArray(center)) {\n            center = [center, center];\n        }\n\n        var width = api.getWidth();\n        var height = api.getHeight();\n        var size = Math.min(width, height);\n        var cx = parsePercent$1(center[0], width);\n        var cy = parsePercent$1(center[1], height);\n        var r0 = parsePercent$1(radius[0], size / 2);\n        var r = parsePercent$1(radius[1], size / 2);\n\n        var startAngle = -seriesModel.get('startAngle') * RADIAN$1;\n        var minAngle = seriesModel.get('minAngle') * RADIAN$1;\n\n        var virtualRoot = seriesModel.getData().tree.root;\n        var treeRoot = seriesModel.getViewRoot();\n        var rootDepth = treeRoot.depth;\n\n        var sort = seriesModel.get('sort');\n        if (sort != null) {\n            initChildren$1(treeRoot, sort);\n        }\n\n        var validDataCount = 0;\n        each$1(treeRoot.children, function (child) {\n            !isNaN(child.getValue()) && validDataCount++;\n        });\n\n        var sum = treeRoot.getValue();\n        // Sum may be 0\n        var unitRadian = Math.PI / (sum || validDataCount) * 2;\n\n        var renderRollupNode = treeRoot.depth > 0;\n        var levels = treeRoot.height - (renderRollupNode ? -1 : 1);\n        var rPerLevel = (r - r0) / (levels || 1);\n\n        var clockwise = seriesModel.get('clockwise');\n\n        var stillShowZeroSum = seriesModel.get('stillShowZeroSum');\n\n        // In the case some sector angle is smaller than minAngle\n        var dir = clockwise ? 1 : -1;\n\n        /**\n         * Render a tree\n         * @return increased angle\n         */\n        var renderNode = function (node, startAngle) {\n            if (!node) {\n                return;\n            }\n\n            var endAngle = startAngle;\n\n            // Render self\n            if (node !== virtualRoot) {\n                // Tree node is virtual, so it doesn't need to be drawn\n                var value = node.getValue();\n\n                var angle = (sum === 0 && stillShowZeroSum)\n                    ? unitRadian : (value * unitRadian);\n                if (angle < minAngle) {\n                    angle = minAngle;\n                    \n                }\n                else {\n                    \n                }\n\n                endAngle = startAngle + dir * angle;\n\n                var depth = node.depth - rootDepth\n                    - (renderRollupNode ? -1 : 1);\n                var rStart = r0 + rPerLevel * depth;\n                var rEnd = r0 + rPerLevel * (depth + 1);\n\n                var itemModel = node.getModel();\n                if (itemModel.get('r0') != null) {\n                    rStart = parsePercent$1(itemModel.get('r0'), size / 2);\n                }\n                if (itemModel.get('r') != null) {\n                    rEnd = parsePercent$1(itemModel.get('r'), size / 2);\n                }\n\n                node.setLayout({\n                    angle: angle,\n                    startAngle: startAngle,\n                    endAngle: endAngle,\n                    clockwise: clockwise,\n                    cx: cx,\n                    cy: cy,\n                    r0: rStart,\n                    r: rEnd\n                });\n            }\n\n            // Render children\n            if (node.children && node.children.length) {\n                // currentAngle = startAngle;\n                var siblingAngle = 0;\n                each$1(node.children, function (node) {\n                    siblingAngle += renderNode(node, startAngle + siblingAngle);\n                });\n            }\n\n            return endAngle - startAngle;\n        };\n\n        // Virtual root node for roll up\n        if (renderRollupNode) {\n            var rStart = r0;\n            var rEnd = r0 + rPerLevel;\n\n            var angle = Math.PI * 2;\n            virtualRoot.setLayout({\n                angle: angle,\n                startAngle: startAngle,\n                endAngle: startAngle + angle,\n                clockwise: clockwise,\n                cx: cx,\n                cy: cy,\n                r0: rStart,\n                r: rEnd\n            });\n        }\n\n        renderNode(treeRoot, startAngle);\n    });\n};\n\n/**\n * Init node children by order and update visual\n *\n * @param {TreeNode} node  root node\n * @param {boolean}  isAsc if is in ascendant order\n */\nfunction initChildren$1(node, isAsc) {\n    var children = node.children || [];\n\n    node.children = sort$2(children, isAsc);\n\n    // Init children recursively\n    if (children.length) {\n        each$1(node.children, function (child) {\n            initChildren$1(child, isAsc);\n        });\n    }\n}\n\n/**\n * Sort children nodes\n *\n * @param {TreeNode[]}               children children of node to be sorted\n * @param {string | function | null} sort sort method\n *                                   See SunburstSeries.js for details.\n */\nfunction sort$2(children, sortOrder) {\n    if (typeof sortOrder === 'function') {\n        return children.sort(sortOrder);\n    }\n    else {\n        var isAsc = sortOrder === 'asc';\n        return children.sort(function (a, b) {\n            var diff = (a.getValue() - b.getValue()) * (isAsc ? 1 : -1);\n            return diff === 0\n                ? (a.dataIndex - b.dataIndex) * (isAsc ? -1 : 1)\n                : diff;\n        });\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterVisual(curry(dataColor, 'sunburst'));\nregisterLayout(curry(sunburstLayout, 'sunburst'));\nregisterProcessor(curry(dataFilter, 'sunburst'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction dataToCoordSize(dataSize, dataItem) {\n    // dataItem is necessary in log axis.\n    dataItem = dataItem || [0, 0];\n    return map(['x', 'y'], function (dim, dimIdx) {\n        var axis = this.getAxis(dim);\n        var val = dataItem[dimIdx];\n        var halfSize = dataSize[dimIdx] / 2;\n        return axis.type === 'category'\n            ? axis.getBandWidth()\n            : Math.abs(axis.dataToCoord(val - halfSize) - axis.dataToCoord(val + halfSize));\n    }, this);\n}\n\nvar prepareCartesian2d = function (coordSys) {\n    var rect = coordSys.grid.getRect();\n    return {\n        coordSys: {\n            // The name exposed to user is always 'cartesian2d' but not 'grid'.\n            type: 'cartesian2d',\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        },\n        api: {\n            coord: function (data) {\n                // do not provide \"out\" param\n                return coordSys.dataToPoint(data);\n            },\n            size: bind(dataToCoordSize, coordSys)\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction dataToCoordSize$1(dataSize, dataItem) {\n    dataItem = dataItem || [0, 0];\n    return map([0, 1], function (dimIdx) {\n        var val = dataItem[dimIdx];\n        var halfSize = dataSize[dimIdx] / 2;\n        var p1 = [];\n        var p2 = [];\n        p1[dimIdx] = val - halfSize;\n        p2[dimIdx] = val + halfSize;\n        p1[1 - dimIdx] = p2[1 - dimIdx] = dataItem[1 - dimIdx];\n        return Math.abs(this.dataToPoint(p1)[dimIdx] - this.dataToPoint(p2)[dimIdx]);\n    }, this);\n}\n\nvar prepareGeo = function (coordSys) {\n    var rect = coordSys.getBoundingRect();\n    return {\n        coordSys: {\n            type: 'geo',\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height,\n            zoom: coordSys.getZoom()\n        },\n        api: {\n            coord: function (data) {\n                // do not provide \"out\" and noRoam param,\n                // Compatible with this usage:\n                // echarts.util.map(item.points, api.coord)\n                return coordSys.dataToPoint(data);\n            },\n            size: bind(dataToCoordSize$1, coordSys)\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction dataToCoordSize$2(dataSize, dataItem) {\n    // dataItem is necessary in log axis.\n    var axis = this.getAxis();\n    var val = dataItem instanceof Array ? dataItem[0] : dataItem;\n    var halfSize = (dataSize instanceof Array ? dataSize[0] : dataSize) / 2;\n    return axis.type === 'category'\n        ? axis.getBandWidth()\n        : Math.abs(axis.dataToCoord(val - halfSize) - axis.dataToCoord(val + halfSize));\n}\n\nvar prepareSingleAxis = function (coordSys) {\n    var rect = coordSys.getRect();\n\n    return {\n        coordSys: {\n            type: 'singleAxis',\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        },\n        api: {\n            coord: function (val) {\n                // do not provide \"out\" param\n                return coordSys.dataToPoint(val);\n            },\n            size: bind(dataToCoordSize$2, coordSys)\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction dataToCoordSize$3(dataSize, dataItem) {\n    // dataItem is necessary in log axis.\n    return map(['Radius', 'Angle'], function (dim, dimIdx) {\n        var axis = this['get' + dim + 'Axis']();\n        var val = dataItem[dimIdx];\n        var halfSize = dataSize[dimIdx] / 2;\n        var method = 'dataTo' + dim;\n\n        var result = axis.type === 'category'\n            ? axis.getBandWidth()\n            : Math.abs(axis[method](val - halfSize) - axis[method](val + halfSize));\n\n        if (dim === 'Angle') {\n            result = result * Math.PI / 180;\n        }\n\n        return result;\n\n    }, this);\n}\n\nvar preparePolar = function (coordSys) {\n    var radiusAxis = coordSys.getRadiusAxis();\n    var angleAxis = coordSys.getAngleAxis();\n    var radius = radiusAxis.getExtent();\n    radius[0] > radius[1] && radius.reverse();\n\n    return {\n        coordSys: {\n            type: 'polar',\n            cx: coordSys.cx,\n            cy: coordSys.cy,\n            r: radius[1],\n            r0: radius[0]\n        },\n        api: {\n            coord: bind(function (data) {\n                var radius = radiusAxis.dataToRadius(data[0]);\n                var angle = angleAxis.dataToAngle(data[1]);\n                var coord = coordSys.coordToPoint([radius, angle]);\n                coord.push(radius, angle * Math.PI / 180);\n                return coord;\n            }),\n            size: bind(dataToCoordSize$3, coordSys)\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar prepareCalendar = function (coordSys) {\n    var rect = coordSys.getRect();\n    var rangeInfo = coordSys.getRangeInfo();\n\n    return {\n        coordSys: {\n            type: 'calendar',\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height,\n            cellWidth: coordSys.getCellWidth(),\n            cellHeight: coordSys.getCellHeight(),\n            rangeInfo: {\n                start: rangeInfo.start,\n                end: rangeInfo.end,\n                weeks: rangeInfo.weeks,\n                dayCount: rangeInfo.allDay\n            }\n        },\n        api: {\n            coord: function (data, clamp) {\n                return coordSys.dataToPoint(data, clamp);\n            }\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ITEM_STYLE_NORMAL_PATH = ['itemStyle'];\nvar ITEM_STYLE_EMPHASIS_PATH = ['emphasis', 'itemStyle'];\nvar LABEL_NORMAL = ['label'];\nvar LABEL_EMPHASIS = ['emphasis', 'label'];\n// Use prefix to avoid index to be the same as el.name,\n// which will cause weird udpate animation.\nvar GROUP_DIFF_PREFIX = 'e\\0\\0';\n\n/**\n * To reduce total package size of each coordinate systems, the modules `prepareCustom`\n * of each coordinate systems are not required by each coordinate systems directly, but\n * required by the module `custom`.\n *\n * prepareInfoForCustomSeries {Function}: optional\n *     @return {Object} {coordSys: {...}, api: {\n *         coord: function (data, clamp) {}, // return point in global.\n *         size: function (dataSize, dataItem) {} // return size of each axis in coordSys.\n *     }}\n */\nvar prepareCustoms = {\n    cartesian2d: prepareCartesian2d,\n    geo: prepareGeo,\n    singleAxis: prepareSingleAxis,\n    polar: preparePolar,\n    calendar: prepareCalendar\n};\n\n\n// ------\n// Model\n// ------\n\nSeriesModel.extend({\n\n    type: 'series.custom',\n\n    dependencies: ['grid', 'polar', 'geo', 'singleAxis', 'calendar'],\n\n    defaultOption: {\n        coordinateSystem: 'cartesian2d', // Can be set as 'none'\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        useTransform: true\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // Polar coordinate system\n        // polarIndex: 0,\n\n        // Geo coordinate system\n        // geoIndex: 0,\n\n        // label: {}\n        // itemStyle: {}\n    },\n\n    /**\n     * @override\n     */\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    /**\n     * @override\n     */\n    getDataParams: function (dataIndex, dataType, el) {\n        var params = SeriesModel.prototype.getDataParams.apply(this, arguments);\n        el && (params.info = el.info);\n        return params;\n    }\n});\n\n// -----\n// View\n// -----\n\nChart.extend({\n\n    type: 'custom',\n\n    /**\n     * @private\n     * @type {module:echarts/data/List}\n     */\n    _data: null,\n\n    /**\n     * @override\n     */\n    render: function (customSeries, ecModel, api, payload) {\n        var oldData = this._data;\n        var data = customSeries.getData();\n        var group = this.group;\n        var renderItem = makeRenderItem(customSeries, data, ecModel, api);\n\n        // By default, merge mode is applied. In most cases, custom series is\n        // used in the scenario that data amount is not large but graphic elements\n        // is complicated, where merge mode is probably necessary for optimization.\n        // For example, reuse graphic elements and only update the transform when\n        // roam or data zoom according to `actionType`.\n        data.diff(oldData)\n            .add(function (newIdx) {\n                createOrUpdate$1(\n                    null, newIdx, renderItem(newIdx, payload), customSeries, group, data\n                );\n            })\n            .update(function (newIdx, oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n                createOrUpdate$1(\n                    el, newIdx, renderItem(newIdx, payload), customSeries, group, data\n                );\n            })\n            .remove(function (oldIdx) {\n                var el = oldData.getItemGraphicEl(oldIdx);\n                el && group.remove(el);\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    incrementalPrepareRender: function (customSeries, ecModel, api) {\n        this.group.removeAll();\n        this._data = null;\n    },\n\n    incrementalRender: function (params, customSeries, ecModel, api, payload) {\n        var data = customSeries.getData();\n        var renderItem = makeRenderItem(customSeries, data, ecModel, api);\n        function setIncrementalAndHoverLayer(el) {\n            if (!el.isGroup) {\n                el.incremental = true;\n                el.useHoverLayer = true;\n            }\n        }\n        for (var idx = params.start; idx < params.end; idx++) {\n            var el = createOrUpdate$1(null, idx, renderItem(idx, payload), customSeries, this.group, data);\n            el.traverse(setIncrementalAndHoverLayer);\n        }\n    },\n\n    /**\n     * @override\n     */\n    dispose: noop,\n\n    /**\n     * @override\n     */\n    filterForExposedEvent: function (eventType, query, targetEl, packedEvent) {\n        var elementName = query.element;\n        if (elementName == null || targetEl.name === elementName) {\n            return true;\n        }\n\n        // Enable to give a name on a group made by `renderItem`, and listen\n        // events that triggerd by its descendents.\n        while ((targetEl = targetEl.parent) && targetEl !== this.group) {\n            if (targetEl.name === elementName) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n});\n\n\nfunction createEl(elOption) {\n    var graphicType = elOption.type;\n    var el;\n\n    if (graphicType === 'path') {\n        var shape = elOption.shape;\n        // Using pathRect brings convenience to users sacle svg path.\n        var pathRect = (shape.width != null && shape.height != null)\n            ? {\n                x: shape.x || 0,\n                y: shape.y || 0,\n                width: shape.width,\n                height: shape.height\n            }\n            : null;\n        var pathData = getPathData(shape);\n        // Path is also used for icon, so layout 'center' by default.\n        el = makePath(pathData, null, pathRect, shape.layout || 'center');\n        el.__customPathData = pathData;\n    }\n    else if (graphicType === 'image') {\n        el = new ZImage({});\n        el.__customImagePath = elOption.style.image;\n    }\n    else if (graphicType === 'text') {\n        el = new Text({});\n        el.__customText = elOption.style.text;\n    }\n    else {\n        var Clz = graphic[graphicType.charAt(0).toUpperCase() + graphicType.slice(1)];\n\n        if (__DEV__) {\n            assert$1(Clz, 'graphic type \"' + graphicType + '\" can not be found.');\n        }\n\n        el = new Clz();\n    }\n\n    el.__customGraphicType = graphicType;\n    el.name = elOption.name;\n\n    return el;\n}\n\nfunction updateEl(el, dataIndex, elOption, animatableModel, data, isInit, isRoot) {\n    var transitionProps = {};\n    var elOptionStyle = elOption.style || {};\n\n    elOption.shape && (transitionProps.shape = clone(elOption.shape));\n    elOption.position && (transitionProps.position = elOption.position.slice());\n    elOption.scale && (transitionProps.scale = elOption.scale.slice());\n    elOption.origin && (transitionProps.origin = elOption.origin.slice());\n    elOption.rotation && (transitionProps.rotation = elOption.rotation);\n\n    if (el.type === 'image' && elOption.style) {\n        var targetStyle = transitionProps.style = {};\n        each$1(['x', 'y', 'width', 'height'], function (prop) {\n            prepareStyleTransition(prop, targetStyle, elOptionStyle, el.style, isInit);\n        });\n    }\n\n    if (el.type === 'text' && elOption.style) {\n        var targetStyle = transitionProps.style = {};\n        each$1(['x', 'y'], function (prop) {\n            prepareStyleTransition(prop, targetStyle, elOptionStyle, el.style, isInit);\n        });\n        // Compatible with previous: both support\n        // textFill and fill, textStroke and stroke in 'text' element.\n        !elOptionStyle.hasOwnProperty('textFill') && elOptionStyle.fill && (\n            elOptionStyle.textFill = elOptionStyle.fill\n        );\n        !elOptionStyle.hasOwnProperty('textStroke') && elOptionStyle.stroke && (\n            elOptionStyle.textStroke = elOptionStyle.stroke\n        );\n    }\n\n    if (el.type !== 'group') {\n        el.useStyle(elOptionStyle);\n\n        // Init animation.\n        if (isInit) {\n            el.style.opacity = 0;\n            var targetOpacity = elOptionStyle.opacity;\n            targetOpacity == null && (targetOpacity = 1);\n            initProps(el, {style: {opacity: targetOpacity}}, animatableModel, dataIndex);\n        }\n    }\n\n    if (isInit) {\n        el.attr(transitionProps);\n    }\n    else {\n        updateProps(el, transitionProps, animatableModel, dataIndex);\n    }\n\n    // Merge by default.\n    // z2 must not be null/undefined, otherwise sort error may occur.\n    elOption.hasOwnProperty('z2') && el.attr('z2', elOption.z2 || 0);\n    elOption.hasOwnProperty('silent') && el.attr('silent', elOption.silent);\n    elOption.hasOwnProperty('invisible') && el.attr('invisible', elOption.invisible);\n    elOption.hasOwnProperty('ignore') && el.attr('ignore', elOption.ignore);\n    // `elOption.info` enables user to mount some info on\n    // elements and use them in event handlers.\n    // Update them only when user specified, otherwise, remain.\n    elOption.hasOwnProperty('info') && el.attr('info', elOption.info);\n\n    // If `elOption.styleEmphasis` is `false`, remove hover style. The\n    // logic is ensured by `graphicUtil.setElementHoverStyle`.\n    var styleEmphasis = elOption.styleEmphasis;\n    var disableStyleEmphasis = styleEmphasis === false;\n    if (!(\n        // Try to escapse setting hover style for performance.\n        (el.__cusHasEmphStl && styleEmphasis == null)\n        || (!el.__cusHasEmphStl && disableStyleEmphasis)\n    )) {\n        // Should not use graphicUtil.setHoverStyle, since the styleEmphasis\n        // should not be share by group and its descendants.\n        setElementHoverStyle(el, styleEmphasis);\n        el.__cusHasEmphStl = !disableStyleEmphasis;\n    }\n    isRoot && setAsHoverStyleTrigger(el, !disableStyleEmphasis);\n}\n\nfunction prepareStyleTransition(prop, targetStyle, elOptionStyle, oldElStyle, isInit) {\n    if (elOptionStyle[prop] != null && !isInit) {\n        targetStyle[prop] = elOptionStyle[prop];\n        elOptionStyle[prop] = oldElStyle[prop];\n    }\n}\n\nfunction makeRenderItem(customSeries, data, ecModel, api) {\n    var renderItem = customSeries.get('renderItem');\n    var coordSys = customSeries.coordinateSystem;\n    var prepareResult = {};\n\n    if (coordSys) {\n        if (__DEV__) {\n            assert$1(renderItem, 'series.render is required.');\n            assert$1(\n                coordSys.prepareCustoms || prepareCustoms[coordSys.type],\n                'This coordSys does not support custom series.'\n            );\n        }\n\n        prepareResult = coordSys.prepareCustoms\n            ? coordSys.prepareCustoms()\n            : prepareCustoms[coordSys.type](coordSys);\n    }\n\n    var userAPI = defaults({\n        getWidth: api.getWidth,\n        getHeight: api.getHeight,\n        getZr: api.getZr,\n        getDevicePixelRatio: api.getDevicePixelRatio,\n        value: value,\n        style: style,\n        styleEmphasis: styleEmphasis,\n        visual: visual,\n        barLayout: barLayout,\n        currentSeriesIndices: currentSeriesIndices,\n        font: font\n    }, prepareResult.api || {});\n\n    var userParams = {\n        // The life cycle of context: current round of rendering.\n        // The global life cycle is probably not necessary, because\n        // user can store global status by themselves.\n        context: {},\n        seriesId: customSeries.id,\n        seriesName: customSeries.name,\n        seriesIndex: customSeries.seriesIndex,\n        coordSys: prepareResult.coordSys,\n        dataInsideLength: data.count(),\n        encode: wrapEncodeDef(customSeries.getData())\n    };\n\n    // Do not support call `api` asynchronously without dataIndexInside input.\n    var currDataIndexInside;\n    var currDirty = true;\n    var currItemModel;\n    var currLabelNormalModel;\n    var currLabelEmphasisModel;\n    var currVisualColor;\n\n    return function (dataIndexInside, payload) {\n        currDataIndexInside = dataIndexInside;\n        currDirty = true;\n\n        return renderItem && renderItem(\n            defaults({\n                dataIndexInside: dataIndexInside,\n                dataIndex: data.getRawIndex(dataIndexInside),\n                // Can be used for optimization when zoom or roam.\n                actionType: payload ? payload.type : null\n            }, userParams),\n            userAPI\n        );\n    };\n\n    // Do not update cache until api called.\n    function updateCache(dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        if (currDirty) {\n            currItemModel = data.getItemModel(dataIndexInside);\n            currLabelNormalModel = currItemModel.getModel(LABEL_NORMAL);\n            currLabelEmphasisModel = currItemModel.getModel(LABEL_EMPHASIS);\n            currVisualColor = data.getItemVisual(dataIndexInside, 'color');\n\n            currDirty = false;\n        }\n    }\n\n    /**\n     * @public\n     * @param {number|string} dim\n     * @param {number} [dataIndexInside=currDataIndexInside]\n     * @return {number|string} value\n     */\n    function value(dim, dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        return data.get(data.getDimension(dim || 0), dataIndexInside);\n    }\n\n    /**\n     * By default, `visual` is applied to style (to support visualMap).\n     * `visual.color` is applied at `fill`. If user want apply visual.color on `stroke`,\n     * it can be implemented as:\n     * `api.style({stroke: api.visual('color'), fill: null})`;\n     * @public\n     * @param {Object} [extra]\n     * @param {number} [dataIndexInside=currDataIndexInside]\n     */\n    function style(extra, dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        updateCache(dataIndexInside);\n\n        var itemStyle = currItemModel.getModel(ITEM_STYLE_NORMAL_PATH).getItemStyle();\n\n        currVisualColor != null && (itemStyle.fill = currVisualColor);\n        var opacity = data.getItemVisual(dataIndexInside, 'opacity');\n        opacity != null && (itemStyle.opacity = opacity);\n\n        setTextStyle(itemStyle, currLabelNormalModel, null, {\n            autoColor: currVisualColor,\n            isRectText: true\n        });\n\n        itemStyle.text = currLabelNormalModel.getShallow('show')\n            ? retrieve2(\n                customSeries.getFormattedLabel(dataIndexInside, 'normal'),\n                getDefaultLabel(data, dataIndexInside)\n            )\n            : null;\n\n        extra && extend(itemStyle, extra);\n        return itemStyle;\n    }\n\n    /**\n     * @public\n     * @param {Object} [extra]\n     * @param {number} [dataIndexInside=currDataIndexInside]\n     */\n    function styleEmphasis(extra, dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        updateCache(dataIndexInside);\n\n        var itemStyle = currItemModel.getModel(ITEM_STYLE_EMPHASIS_PATH).getItemStyle();\n\n        setTextStyle(itemStyle, currLabelEmphasisModel, null, {\n            isRectText: true\n        }, true);\n\n        itemStyle.text = currLabelEmphasisModel.getShallow('show')\n            ? retrieve3(\n                customSeries.getFormattedLabel(dataIndexInside, 'emphasis'),\n                customSeries.getFormattedLabel(dataIndexInside, 'normal'),\n                getDefaultLabel(data, dataIndexInside)\n            )\n            : null;\n\n        extra && extend(itemStyle, extra);\n        return itemStyle;\n    }\n\n    /**\n     * @public\n     * @param {string} visualType\n     * @param {number} [dataIndexInside=currDataIndexInside]\n     */\n    function visual(visualType, dataIndexInside) {\n        dataIndexInside == null && (dataIndexInside = currDataIndexInside);\n        return data.getItemVisual(dataIndexInside, visualType);\n    }\n\n    /**\n     * @public\n     * @param {number} opt.count Positive interger.\n     * @param {number} [opt.barWidth]\n     * @param {number} [opt.barMaxWidth]\n     * @param {number} [opt.barGap]\n     * @param {number} [opt.barCategoryGap]\n     * @return {Object} {width, offset, offsetCenter} is not support, return undefined.\n     */\n    function barLayout(opt) {\n        if (coordSys.getBaseAxis) {\n            var baseAxis = coordSys.getBaseAxis();\n            return getLayoutOnAxis(defaults({axis: baseAxis}, opt), api);\n        }\n    }\n\n    /**\n     * @public\n     * @return {Array.<number>}\n     */\n    function currentSeriesIndices() {\n        return ecModel.getCurrentSeriesIndices();\n    }\n\n    /**\n     * @public\n     * @param {Object} opt\n     * @param {string} [opt.fontStyle]\n     * @param {number} [opt.fontWeight]\n     * @param {number} [opt.fontSize]\n     * @param {string} [opt.fontFamily]\n     * @return {string} font string\n     */\n    function font(opt) {\n        return getFont(opt, ecModel);\n    }\n}\n\nfunction wrapEncodeDef(data) {\n    var encodeDef = {};\n    each$1(data.dimensions, function (dimName, dataDimIndex) {\n        var dimInfo = data.getDimensionInfo(dimName);\n        if (!dimInfo.isExtraCoord) {\n            var coordDim = dimInfo.coordDim;\n            var dataDims = encodeDef[coordDim] = encodeDef[coordDim] || [];\n            dataDims[dimInfo.coordDimIndex] = dataDimIndex;\n        }\n    });\n    return encodeDef;\n}\n\nfunction createOrUpdate$1(el, dataIndex, elOption, animatableModel, group, data) {\n    el = doCreateOrUpdate(el, dataIndex, elOption, animatableModel, group, data, true);\n    el && data.setItemGraphicEl(dataIndex, el);\n\n    return el;\n}\n\nfunction doCreateOrUpdate(el, dataIndex, elOption, animatableModel, group, data, isRoot) {\n\n    // [Rule]\n    // By default, follow merge mode.\n    //     (It probably brings benifit for performance in some cases of large data, where\n    //     user program can be optimized to that only updated props needed to be re-calculated,\n    //     or according to `actionType` some calculation can be skipped.)\n    // If `renderItem` returns `null`/`undefined`/`false`, remove the previous el if existing.\n    //     (It seems that violate the \"merge\" principle, but most of users probably intuitively\n    //     regard \"return;\" as \"show nothing element whatever\", so make a exception to meet the\n    //     most cases.)\n\n    var simplyRemove = !elOption; // `null`/`undefined`/`false`\n    elOption = elOption || {};\n    var elOptionType = elOption.type;\n    var elOptionShape = elOption.shape;\n    var elOptionStyle = elOption.style;\n\n    if (el && (\n        simplyRemove\n        // || elOption.$merge === false\n        // If `elOptionType` is `null`, follow the merge principle.\n        || (elOptionType != null\n            && elOptionType !== el.__customGraphicType\n        )\n        || (elOptionType === 'path'\n            && hasOwnPathData(elOptionShape) && getPathData(elOptionShape) !== el.__customPathData\n        )\n        || (elOptionType === 'image'\n            && hasOwn(elOptionStyle, 'image') && elOptionStyle.image !== el.__customImagePath\n        )\n        // FIXME test and remove this restriction?\n        || (elOptionType === 'text'\n            && hasOwn(elOptionShape, 'text') && elOptionStyle.text !== el.__customText\n        )\n    )) {\n        group.remove(el);\n        el = null;\n    }\n\n    // `elOption.type` is undefined when `renderItem` returns nothing.\n    if (simplyRemove) {\n        return;\n    }\n\n    var isInit = !el;\n    !el && (el = createEl(elOption));\n    updateEl(el, dataIndex, elOption, animatableModel, data, isInit, isRoot);\n\n    if (elOptionType === 'group') {\n        mergeChildren(el, dataIndex, elOption, animatableModel, data);\n    }\n\n    // Always add whatever already added to ensure sequence.\n    group.add(el);\n\n    return el;\n}\n\n// Usage:\n// (1) By default, `elOption.$mergeChildren` is `'byIndex'`, which indicates that\n//     the existing children will not be removed, and enables the feature that\n//     update some of the props of some of the children simply by construct\n//     the returned children of `renderItem` like:\n//     `var children = group.children = []; children[3] = {opacity: 0.5};`\n// (2) If `elOption.$mergeChildren` is `'byName'`, add/update/remove children\n//     by child.name. But that might be lower performance.\n// (3) If `elOption.$mergeChildren` is `false`, the existing children will be\n//     replaced totally.\n// (4) If `!elOption.children`, following the \"merge\" principle, nothing will happen.\n//\n// For implementation simpleness, do not provide a direct way to remove sinlge\n// child (otherwise the total indicies of the children array have to be modified).\n// User can remove a single child by set its `ignore` as `true` or replace\n// it by another element, where its `$merge` can be set as `true` if necessary.\nfunction mergeChildren(el, dataIndex, elOption, animatableModel, data) {\n    var newChildren = elOption.children;\n    var newLen = newChildren ? newChildren.length : 0;\n    var mergeChildren = elOption.$mergeChildren;\n    // `diffChildrenByName` has been deprecated.\n    var byName = mergeChildren === 'byName' || elOption.diffChildrenByName;\n    var notMerge = mergeChildren === false;\n\n    // For better performance on roam update, only enter if necessary.\n    if (!newLen && !byName && !notMerge) {\n        return;\n    }\n\n    if (byName) {\n        diffGroupChildren({\n            oldChildren: el.children() || [],\n            newChildren: newChildren || [],\n            dataIndex: dataIndex,\n            animatableModel: animatableModel,\n            group: el,\n            data: data\n        });\n        return;\n    }\n\n    notMerge && el.removeAll();\n\n    // Mapping children of a group simply by index, which\n    // might be better performance.\n    var index = 0;\n    for (; index < newLen; index++) {\n        newChildren[index] && doCreateOrUpdate(\n            el.childAt(index),\n            dataIndex,\n            newChildren[index],\n            animatableModel,\n            el,\n            data\n        );\n    }\n    if (__DEV__) {\n        assert$1(\n            !notMerge || el.childCount() === index,\n            'MUST NOT contain empty item in children array when `group.$mergeChildren` is `false`.'\n        );\n    }\n}\n\nfunction diffGroupChildren(context) {\n    (new DataDiffer(\n        context.oldChildren,\n        context.newChildren,\n        getKey,\n        getKey,\n        context\n    ))\n        .add(processAddUpdate)\n        .update(processAddUpdate)\n        .remove(processRemove)\n        .execute();\n}\n\nfunction getKey(item, idx) {\n    var name = item && item.name;\n    return name != null ? name : GROUP_DIFF_PREFIX + idx;\n}\n\nfunction processAddUpdate(newIndex, oldIndex) {\n    var context = this.context;\n    var childOption = newIndex != null ? context.newChildren[newIndex] : null;\n    var child = oldIndex != null ? context.oldChildren[oldIndex] : null;\n\n    doCreateOrUpdate(\n        child,\n        context.dataIndex,\n        childOption,\n        context.animatableModel,\n        context.group,\n        context.data\n    );\n}\n\nfunction processRemove(oldIndex) {\n    var context = this.context;\n    var child = context.oldChildren[oldIndex];\n    child && context.group.remove(child);\n}\n\nfunction getPathData(shape) {\n    // \"d\" follows the SVG convention.\n    return shape && (shape.pathData || shape.d);\n}\n\nfunction hasOwnPathData(shape) {\n    return shape && (shape.hasOwnProperty('pathData') || shape.hasOwnProperty('d'));\n}\n\nfunction hasOwn(host, prop) {\n    return host && host.hasOwnProperty(prop);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// -------------\n// Preprocessor\n// -------------\n\nregisterPreprocessor(function (option) {\n    var graphicOption = option.graphic;\n\n    // Convert\n    // {graphic: [{left: 10, type: 'circle'}, ...]}\n    // or\n    // {graphic: {left: 10, type: 'circle'}}\n    // to\n    // {graphic: [{elements: [{left: 10, type: 'circle'}, ...]}]}\n    if (isArray(graphicOption)) {\n        if (!graphicOption[0] || !graphicOption[0].elements) {\n            option.graphic = [{elements: graphicOption}];\n        }\n        else {\n            // Only one graphic instance can be instantiated. (We dont\n            // want that too many views are created in echarts._viewMap)\n            option.graphic = [option.graphic[0]];\n        }\n    }\n    else if (graphicOption && !graphicOption.elements) {\n        option.graphic = [{elements: [graphicOption]}];\n    }\n});\n\n// ------\n// Model\n// ------\n\nvar GraphicModel = extendComponentModel({\n\n    type: 'graphic',\n\n    defaultOption: {\n\n        // Extra properties for each elements:\n        //\n        // left/right/top/bottom: (like 12, '22%', 'center', default undefined)\n        //      If left/rigth is set, shape.x/shape.cx/position will not be used.\n        //      If top/bottom is set, shape.y/shape.cy/position will not be used.\n        //      This mechanism is useful when you want to position a group/element\n        //      against the right side or the center of this container.\n        //\n        // width/height: (can only be pixel value, default 0)\n        //      Only be used to specify contianer(group) size, if needed. And\n        //      can not be percentage value (like '33%'). See the reason in the\n        //      layout algorithm below.\n        //\n        // bounding: (enum: 'all' (default) | 'raw')\n        //      Specify how to calculate boundingRect when locating.\n        //      'all': Get uioned and transformed boundingRect\n        //          from both itself and its descendants.\n        //          This mode simplies confining a group of elements in the bounding\n        //          of their ancester container (e.g., using 'right: 0').\n        //      'raw': Only use the boundingRect of itself and before transformed.\n        //          This mode is similar to css behavior, which is useful when you\n        //          want an element to be able to overflow its container. (Consider\n        //          a rotated circle needs to be located in a corner.)\n        // info: custom info. enables user to mount some info on elements and use them\n        //      in event handlers. Update them only when user specified, otherwise, remain.\n\n        // Note: elements is always behind its ancestors in this elements array.\n        elements: [],\n        parentId: null\n    },\n\n    /**\n     * Save el options for the sake of the performance (only update modified graphics).\n     * The order is the same as those in option. (ancesters -> descendants)\n     *\n     * @private\n     * @type {Array.<Object>}\n     */\n    _elOptionsToUpdate: null,\n\n    /**\n     * @override\n     */\n    mergeOption: function (option) {\n        // Prevent default merge to elements\n        var elements = this.option.elements;\n        this.option.elements = null;\n\n        GraphicModel.superApply(this, 'mergeOption', arguments);\n\n        this.option.elements = elements;\n    },\n\n    /**\n     * @override\n     */\n    optionUpdated: function (newOption, isInit) {\n        var thisOption = this.option;\n        var newList = (isInit ? thisOption : newOption).elements;\n        var existList = thisOption.elements = isInit ? [] : thisOption.elements;\n\n        var flattenedList = [];\n        this._flatten(newList, flattenedList);\n\n        var mappingResult = mappingToExists(existList, flattenedList);\n        makeIdAndName(mappingResult);\n\n        // Clear elOptionsToUpdate\n        var elOptionsToUpdate = this._elOptionsToUpdate = [];\n\n        each$1(mappingResult, function (resultItem, index) {\n            var newElOption = resultItem.option;\n\n            if (__DEV__) {\n                assert$1(\n                    isObject$1(newElOption) || resultItem.exist,\n                    'Empty graphic option definition'\n                );\n            }\n\n            if (!newElOption) {\n                return;\n            }\n\n            elOptionsToUpdate.push(newElOption);\n\n            setKeyInfoToNewElOption(resultItem, newElOption);\n\n            mergeNewElOptionToExist(existList, index, newElOption);\n\n            setLayoutInfoToExist(existList[index], newElOption);\n\n        }, this);\n\n        // Clean\n        for (var i = existList.length - 1; i >= 0; i--) {\n            if (existList[i] == null) {\n                existList.splice(i, 1);\n            }\n            else {\n                // $action should be volatile, otherwise option gotten from\n                // `getOption` will contain unexpected $action.\n                delete existList[i].$action;\n            }\n        }\n    },\n\n    /**\n     * Convert\n     * [{\n     *  type: 'group',\n     *  id: 'xx',\n     *  children: [{type: 'circle'}, {type: 'polygon'}]\n     * }]\n     * to\n     * [\n     *  {type: 'group', id: 'xx'},\n     *  {type: 'circle', parentId: 'xx'},\n     *  {type: 'polygon', parentId: 'xx'}\n     * ]\n     *\n     * @private\n     * @param {Array.<Object>} optionList option list\n     * @param {Array.<Object>} result result of flatten\n     * @param {Object} parentOption parent option\n     */\n    _flatten: function (optionList, result, parentOption) {\n        each$1(optionList, function (option) {\n            if (!option) {\n                return;\n            }\n\n            if (parentOption) {\n                option.parentOption = parentOption;\n            }\n\n            result.push(option);\n\n            var children = option.children;\n            if (option.type === 'group' && children) {\n                this._flatten(children, result, option);\n            }\n            // Deleting for JSON output, and for not affecting group creation.\n            delete option.children;\n        }, this);\n    },\n\n    // FIXME\n    // Pass to view using payload? setOption has a payload?\n    useElOptionsToUpdate: function () {\n        var els = this._elOptionsToUpdate;\n        // Clear to avoid render duplicately when zooming.\n        this._elOptionsToUpdate = null;\n        return els;\n    }\n});\n\n// -----\n// View\n// -----\n\nextendComponentView({\n\n    type: 'graphic',\n\n    /**\n     * @override\n     */\n    init: function (ecModel, api) {\n\n        /**\n         * @private\n         * @type {module:zrender/core/util.HashMap}\n         */\n        this._elMap = createHashMap();\n\n        /**\n         * @private\n         * @type {module:echarts/graphic/GraphicModel}\n         */\n        this._lastGraphicModel;\n    },\n\n    /**\n     * @override\n     */\n    render: function (graphicModel, ecModel, api) {\n\n        // Having leveraged between use cases and algorithm complexity, a very\n        // simple layout mechanism is used:\n        // The size(width/height) can be determined by itself or its parent (not\n        // implemented yet), but can not by its children. (Top-down travel)\n        // The location(x/y) can be determined by the bounding rect of itself\n        // (can including its descendants or not) and the size of its parent.\n        // (Bottom-up travel)\n\n        // When `chart.clear()` or `chart.setOption({...}, true)` with the same id,\n        // view will be reused.\n        if (graphicModel !== this._lastGraphicModel) {\n            this._clear();\n        }\n        this._lastGraphicModel = graphicModel;\n\n        this._updateElements(graphicModel);\n        this._relocate(graphicModel, api);\n    },\n\n    /**\n     * Update graphic elements.\n     *\n     * @private\n     * @param {Object} graphicModel graphic model\n     */\n    _updateElements: function (graphicModel) {\n        var elOptionsToUpdate = graphicModel.useElOptionsToUpdate();\n\n        if (!elOptionsToUpdate) {\n            return;\n        }\n\n        var elMap = this._elMap;\n        var rootGroup = this.group;\n\n        // Top-down tranverse to assign graphic settings to each elements.\n        each$1(elOptionsToUpdate, function (elOption) {\n            var $action = elOption.$action;\n            var id = elOption.id;\n            var existEl = elMap.get(id);\n            var parentId = elOption.parentId;\n            var targetElParent = parentId != null ? elMap.get(parentId) : rootGroup;\n\n            var elOptionStyle = elOption.style;\n            if (elOption.type === 'text' && elOptionStyle) {\n                // In top/bottom mode, textVerticalAlign should not be used, which cause\n                // inaccurately locating.\n                if (elOption.hv && elOption.hv[1]) {\n                    elOptionStyle.textVerticalAlign = elOptionStyle.textBaseline = null;\n                }\n\n                // Compatible with previous setting: both support fill and textFill,\n                // stroke and textStroke.\n                !elOptionStyle.hasOwnProperty('textFill') && elOptionStyle.fill && (\n                    elOptionStyle.textFill = elOptionStyle.fill\n                );\n                !elOptionStyle.hasOwnProperty('textStroke') && elOptionStyle.stroke && (\n                    elOptionStyle.textStroke = elOptionStyle.stroke\n                );\n            }\n\n            // Remove unnecessary props to avoid potential problems.\n            var elOptionCleaned = getCleanedElOption(elOption);\n\n            // For simple, do not support parent change, otherwise reorder is needed.\n            if (__DEV__) {\n                existEl && assert$1(\n                    targetElParent === existEl.parent,\n                    'Changing parent is not supported.'\n                );\n            }\n\n            if (!$action || $action === 'merge') {\n                existEl\n                    ? existEl.attr(elOptionCleaned)\n                    : createEl$1(id, targetElParent, elOptionCleaned, elMap);\n            }\n            else if ($action === 'replace') {\n                removeEl(existEl, elMap);\n                createEl$1(id, targetElParent, elOptionCleaned, elMap);\n            }\n            else if ($action === 'remove') {\n                removeEl(existEl, elMap);\n            }\n\n            var el = elMap.get(id);\n            if (el) {\n                el.__ecGraphicWidth = elOption.width;\n                el.__ecGraphicHeight = elOption.height;\n                setEventData(el, graphicModel, elOption);\n            }\n        });\n    },\n\n    /**\n     * Locate graphic elements.\n     *\n     * @private\n     * @param {Object} graphicModel graphic model\n     * @param {module:echarts/ExtensionAPI} api extension API\n     */\n    _relocate: function (graphicModel, api) {\n        var elOptions = graphicModel.option.elements;\n        var rootGroup = this.group;\n        var elMap = this._elMap;\n\n        // Bottom-up tranvese all elements (consider ec resize) to locate elements.\n        for (var i = elOptions.length - 1; i >= 0; i--) {\n            var elOption = elOptions[i];\n            var el = elMap.get(elOption.id);\n\n            if (!el) {\n                continue;\n            }\n\n            var parentEl = el.parent;\n            var containerInfo = parentEl === rootGroup\n                ? {\n                    width: api.getWidth(),\n                    height: api.getHeight()\n                }\n                : { // Like 'position:absolut' in css, default 0.\n                    width: parentEl.__ecGraphicWidth || 0,\n                    height: parentEl.__ecGraphicHeight || 0\n                };\n\n            positionElement(\n                el, elOption, containerInfo, null,\n                {hv: elOption.hv, boundingMode: elOption.bounding}\n            );\n        }\n    },\n\n    /**\n     * Clear all elements.\n     *\n     * @private\n     */\n    _clear: function () {\n        var elMap = this._elMap;\n        elMap.each(function (el) {\n            removeEl(el, elMap);\n        });\n        this._elMap = createHashMap();\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._clear();\n    }\n});\n\nfunction createEl$1(id, targetElParent, elOption, elMap) {\n    var graphicType = elOption.type;\n\n    if (__DEV__) {\n        assert$1(graphicType, 'graphic type MUST be set');\n    }\n\n    var Clz = graphic[graphicType.charAt(0).toUpperCase() + graphicType.slice(1)];\n\n    if (__DEV__) {\n        assert$1(Clz, 'graphic type can not be found');\n    }\n\n    var el = new Clz(elOption);\n    targetElParent.add(el);\n    elMap.set(id, el);\n    el.__ecGraphicId = id;\n}\n\nfunction removeEl(existEl, elMap) {\n    var existElParent = existEl && existEl.parent;\n    if (existElParent) {\n        existEl.type === 'group' && existEl.traverse(function (el) {\n            removeEl(el, elMap);\n        });\n        elMap.removeKey(existEl.__ecGraphicId);\n        existElParent.remove(existEl);\n    }\n}\n\n// Remove unnecessary props to avoid potential problems.\nfunction getCleanedElOption(elOption) {\n    elOption = extend({}, elOption);\n    each$1(\n        ['id', 'parentId', '$action', 'hv', 'bounding'].concat(LOCATION_PARAMS),\n        function (name) {\n            delete elOption[name];\n        }\n    );\n    return elOption;\n}\n\nfunction isSetLoc(obj, props) {\n    var isSet;\n    each$1(props, function (prop) {\n        obj[prop] != null && obj[prop] !== 'auto' && (isSet = true);\n    });\n    return isSet;\n}\n\nfunction setKeyInfoToNewElOption(resultItem, newElOption) {\n    var existElOption = resultItem.exist;\n\n    // Set id and type after id assigned.\n    newElOption.id = resultItem.keyInfo.id;\n    !newElOption.type && existElOption && (newElOption.type = existElOption.type);\n\n    // Set parent id if not specified\n    if (newElOption.parentId == null) {\n        var newElParentOption = newElOption.parentOption;\n        if (newElParentOption) {\n            newElOption.parentId = newElParentOption.id;\n        }\n        else if (existElOption) {\n            newElOption.parentId = existElOption.parentId;\n        }\n    }\n\n    // Clear\n    newElOption.parentOption = null;\n}\n\nfunction mergeNewElOptionToExist(existList, index, newElOption) {\n    // Update existing options, for `getOption` feature.\n    var newElOptCopy = extend({}, newElOption);\n    var existElOption = existList[index];\n\n    var $action = newElOption.$action || 'merge';\n    if ($action === 'merge') {\n        if (existElOption) {\n\n            if (__DEV__) {\n                var newType = newElOption.type;\n                assert$1(\n                    !newType || existElOption.type === newType,\n                    'Please set $action: \"replace\" to change `type`'\n                );\n            }\n\n            // We can ensure that newElOptCopy and existElOption are not\n            // the same object, so `merge` will not change newElOptCopy.\n            merge(existElOption, newElOptCopy, true);\n            // Rigid body, use ignoreSize.\n            mergeLayoutParam(existElOption, newElOptCopy, {ignoreSize: true});\n            // Will be used in render.\n            copyLayoutParams(newElOption, existElOption);\n        }\n        else {\n            existList[index] = newElOptCopy;\n        }\n    }\n    else if ($action === 'replace') {\n        existList[index] = newElOptCopy;\n    }\n    else if ($action === 'remove') {\n        // null will be cleaned later.\n        existElOption && (existList[index] = null);\n    }\n}\n\nfunction setLayoutInfoToExist(existItem, newElOption) {\n    if (!existItem) {\n        return;\n    }\n    existItem.hv = newElOption.hv = [\n        // Rigid body, dont care `width`.\n        isSetLoc(newElOption, ['left', 'right']),\n        // Rigid body, dont care `height`.\n        isSetLoc(newElOption, ['top', 'bottom'])\n    ];\n    // Give default group size. Otherwise layout error may occur.\n    if (existItem.type === 'group') {\n        existItem.width == null && (existItem.width = newElOption.width = 0);\n        existItem.height == null && (existItem.height = newElOption.height = 0);\n    }\n}\n\nfunction setEventData(el, graphicModel, elOption) {\n    var eventData = el.eventData;\n    // Simple optimize for large amount of elements that no need event.\n    if (!el.silent && !el.ignore && !eventData) {\n        eventData = el.eventData = {\n            componentType: 'graphic',\n            componentIndex: graphicModel.componentIndex,\n            name: el.name\n        };\n    }\n\n    // `elOption.info` enables user to mount some info on\n    // elements and use them in event handlers.\n    if (eventData) {\n        eventData.info = el.info;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar LegendModel = extendComponentModel({\n\n    type: 'legend.plain',\n\n    dependencies: ['series'],\n\n    layoutMode: {\n        type: 'box',\n        // legend.width/height are maxWidth/maxHeight actually,\n        // whereas realy width/height is calculated by its content.\n        // (Setting {left: 10, right: 10} does not make sense).\n        // So consider the case:\n        // `setOption({legend: {left: 10});`\n        // then `setOption({legend: {right: 10});`\n        // The previous `left` should be cleared by setting `ignoreSize`.\n        ignoreSize: true\n    },\n\n    init: function (option, parentModel, ecModel) {\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        option.selected = option.selected || {};\n    },\n\n    mergeOption: function (option) {\n        LegendModel.superCall(this, 'mergeOption', option);\n    },\n\n    optionUpdated: function () {\n        this._updateData(this.ecModel);\n\n        var legendData = this._data;\n\n        // If selectedMode is single, try to select one\n        if (legendData[0] && this.get('selectedMode') === 'single') {\n            var hasSelected = false;\n            // If has any selected in option.selected\n            for (var i = 0; i < legendData.length; i++) {\n                var name = legendData[i].get('name');\n                if (this.isSelected(name)) {\n                    // Force to unselect others\n                    this.select(name);\n                    hasSelected = true;\n                    break;\n                }\n            }\n            // Try select the first if selectedMode is single\n            !hasSelected && this.select(legendData[0].get('name'));\n        }\n    },\n\n    _updateData: function (ecModel) {\n        var potentialData = [];\n        var availableNames = [];\n\n        ecModel.eachRawSeries(function (seriesModel) {\n            var seriesName = seriesModel.name;\n            availableNames.push(seriesName);\n            var isPotential;\n\n            if (seriesModel.legendDataProvider) {\n                var data = seriesModel.legendDataProvider();\n                var names = data.mapArray(data.getName);\n\n                if (!ecModel.isSeriesFiltered(seriesModel)) {\n                    availableNames = availableNames.concat(names);\n                }\n\n                if (names.length) {\n                    potentialData = potentialData.concat(names);\n                }\n                else {\n                    isPotential = true;\n                }\n            }\n            else {\n                isPotential = true;\n            }\n\n            if (isPotential && isNameSpecified(seriesModel)) {\n                potentialData.push(seriesModel.name);\n            }\n        });\n\n        /**\n         * @type {Array.<string>}\n         * @private\n         */\n        this._availableNames = availableNames;\n\n        // If legend.data not specified in option, use availableNames as data,\n        // which is convinient for user preparing option.\n        var rawData = this.get('data') || potentialData;\n\n        var legendData = map(rawData, function (dataItem) {\n            // Can be string or number\n            if (typeof dataItem === 'string' || typeof dataItem === 'number') {\n                dataItem = {\n                    name: dataItem\n                };\n            }\n            return new Model(dataItem, this, this.ecModel);\n        }, this);\n\n        /**\n         * @type {Array.<module:echarts/model/Model>}\n         * @private\n         */\n        this._data = legendData;\n    },\n\n    /**\n     * @return {Array.<module:echarts/model/Model>}\n     */\n    getData: function () {\n        return this._data;\n    },\n\n    /**\n     * @param {string} name\n     */\n    select: function (name) {\n        var selected = this.option.selected;\n        var selectedMode = this.get('selectedMode');\n        if (selectedMode === 'single') {\n            var data = this._data;\n            each$1(data, function (dataItem) {\n                selected[dataItem.get('name')] = false;\n            });\n        }\n        selected[name] = true;\n    },\n\n    /**\n     * @param {string} name\n     */\n    unSelect: function (name) {\n        if (this.get('selectedMode') !== 'single') {\n            this.option.selected[name] = false;\n        }\n    },\n\n    /**\n     * @param {string} name\n     */\n    toggleSelected: function (name) {\n        var selected = this.option.selected;\n        // Default is true\n        if (!selected.hasOwnProperty(name)) {\n            selected[name] = true;\n        }\n        this[selected[name] ? 'unSelect' : 'select'](name);\n    },\n\n    /**\n     * @param {string} name\n     */\n    isSelected: function (name) {\n        var selected = this.option.selected;\n        return !(selected.hasOwnProperty(name) && !selected[name])\n            && indexOf(this._availableNames, name) >= 0;\n    },\n\n    defaultOption: {\n        // 一级层叠\n        zlevel: 0,\n        // 二级层叠\n        z: 4,\n        show: true,\n\n        // 布局方式，默认为水平布局，可选为：\n        // 'horizontal' | 'vertical'\n        orient: 'horizontal',\n\n        left: 'center',\n        // right: 'center',\n\n        top: 0,\n        // bottom: null,\n\n        // 水平对齐\n        // 'auto' | 'left' | 'right'\n        // 默认为 'auto', 根据 x 的位置判断是左对齐还是右对齐\n        align: 'auto',\n\n        backgroundColor: 'rgba(0,0,0,0)',\n        // 图例边框颜色\n        borderColor: '#ccc',\n        borderRadius: 0,\n        // 图例边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n        // 图例内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n        // 各个item之间的间隔，单位px，默认为10，\n        // 横向布局时为水平间隔，纵向布局时为纵向间隔\n        itemGap: 10,\n        // 图例图形宽度\n        itemWidth: 25,\n        // 图例图形高度\n        itemHeight: 14,\n\n        // 图例关闭时候的颜色\n        inactiveColor: '#ccc',\n\n        textStyle: {\n            // 图例文字颜色\n            color: '#333'\n        },\n        // formatter: '',\n        // 选择模式，默认开启图例开关\n        selectedMode: true,\n        // 配置默认选中状态，可配合LEGEND.SELECTED事件做动态数据载入\n        // selected: null,\n        // 图例内容（详见legend.data，数组中每一项代表一个item\n        // data: [],\n\n        // Tooltip 相关配置\n        tooltip: {\n            show: false\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction legendSelectActionHandler(methodName, payload, ecModel) {\n    var selectedMap = {};\n    var isToggleSelect = methodName === 'toggleSelected';\n    var isSelected;\n    // Update all legend components\n    ecModel.eachComponent('legend', function (legendModel) {\n        if (isToggleSelect && isSelected != null) {\n            // Force other legend has same selected status\n            // Or the first is toggled to true and other are toggled to false\n            // In the case one legend has some item unSelected in option. And if other legend\n            // doesn't has the item, they will assume it is selected.\n            legendModel[isSelected ? 'select' : 'unSelect'](payload.name);\n        }\n        else {\n            legendModel[methodName](payload.name);\n            isSelected = legendModel.isSelected(payload.name);\n        }\n        var legendData = legendModel.getData();\n        each$1(legendData, function (model) {\n            var name = model.get('name');\n            // Wrap element\n            if (name === '\\n' || name === '') {\n                return;\n            }\n            var isItemSelected = legendModel.isSelected(name);\n            if (selectedMap.hasOwnProperty(name)) {\n                // Unselected if any legend is unselected\n                selectedMap[name] = selectedMap[name] && isItemSelected;\n            }\n            else {\n                selectedMap[name] = isItemSelected;\n            }\n        });\n    });\n    // Return the event explicitly\n    return {\n        name: payload.name,\n        selected: selectedMap\n    };\n}\n/**\n * @event legendToggleSelect\n * @type {Object}\n * @property {string} type 'legendToggleSelect'\n * @property {string} [from]\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendToggleSelect', 'legendselectchanged',\n    curry(legendSelectActionHandler, 'toggleSelected')\n);\n\n/**\n * @event legendSelect\n * @type {Object}\n * @property {string} type 'legendSelect'\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendSelect', 'legendselected',\n    curry(legendSelectActionHandler, 'select')\n);\n\n/**\n * @event legendUnSelect\n * @type {Object}\n * @property {string} type 'legendUnSelect'\n * @property {string} name Series name or data item name\n */\nregisterAction(\n    'legendUnSelect', 'legendunselected',\n    curry(legendSelectActionHandler, 'unSelect')\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Layout list like component.\n * It will box layout each items in group of component and then position the whole group in the viewport\n * @param {module:zrender/group/Group} group\n * @param {module:echarts/model/Component} componentModel\n * @param {module:echarts/ExtensionAPI}\n */\nfunction layout$3(group, componentModel, api) {\n    var boxLayoutParams = componentModel.getBoxLayoutParams();\n    var padding = componentModel.get('padding');\n    var viewportSize = {width: api.getWidth(), height: api.getHeight()};\n\n    var rect = getLayoutRect(\n        boxLayoutParams,\n        viewportSize,\n        padding\n    );\n\n    box(\n        componentModel.get('orient'),\n        group,\n        componentModel.get('itemGap'),\n        rect.width,\n        rect.height\n    );\n\n    positionElement(\n        group,\n        boxLayoutParams,\n        viewportSize,\n        padding\n    );\n}\n\nfunction makeBackground(rect, componentModel) {\n    var padding = normalizeCssArray$1(\n        componentModel.get('padding')\n    );\n    var style = componentModel.getItemStyle(['color', 'opacity']);\n    style.fill = componentModel.get('backgroundColor');\n    var rect = new Rect({\n        shape: {\n            x: rect.x - padding[3],\n            y: rect.y - padding[0],\n            width: rect.width + padding[1] + padding[3],\n            height: rect.height + padding[0] + padding[2],\n            r: componentModel.get('borderRadius')\n        },\n        style: style,\n        silent: true,\n        z2: -1\n    });\n    // FIXME\n    // `subPixelOptimizeRect` may bring some gap between edge of viewpart\n    // and background rect when setting like `left: 0`, `top: 0`.\n    // graphic.subPixelOptimizeRect(rect);\n\n    return rect;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar curry$4 = curry;\nvar each$16 = each$1;\nvar Group$3 = Group;\n\nvar LegendView = extendComponentView({\n\n    type: 'legend.plain',\n\n    newlineDisabled: false,\n\n    /**\n     * @override\n     */\n    init: function () {\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._contentGroup = new Group$3());\n\n        /**\n         * @private\n         * @type {module:zrender/Element}\n         */\n        this._backgroundEl;\n\n        /**\n         * If first rendering, `contentGroup.position` is [0, 0], which\n         * does not make sense and may cause unexepcted animation if adopted.\n         * @private\n         * @type {boolean}\n         */\n        this._isFirstRender = true;\n    },\n\n    /**\n     * @protected\n     */\n    getContentGroup: function () {\n        return this._contentGroup;\n    },\n\n    /**\n     * @override\n     */\n    render: function (legendModel, ecModel, api) {\n        var isFirstRender = this._isFirstRender;\n        this._isFirstRender = false;\n\n        this.resetInner();\n\n        if (!legendModel.get('show', true)) {\n            return;\n        }\n\n        var itemAlign = legendModel.get('align');\n        if (!itemAlign || itemAlign === 'auto') {\n            itemAlign = (\n                legendModel.get('left') === 'right'\n                && legendModel.get('orient') === 'vertical'\n            ) ? 'right' : 'left';\n        }\n\n        this.renderInner(itemAlign, legendModel, ecModel, api);\n\n        // Perform layout.\n        var positionInfo = legendModel.getBoxLayoutParams();\n        var viewportSize = {width: api.getWidth(), height: api.getHeight()};\n        var padding = legendModel.get('padding');\n\n        var maxSize = getLayoutRect(positionInfo, viewportSize, padding);\n\n        var mainRect = this.layoutInner(legendModel, itemAlign, maxSize, isFirstRender);\n\n        // Place mainGroup, based on the calculated `mainRect`.\n        var layoutRect = getLayoutRect(\n            defaults({width: mainRect.width, height: mainRect.height}, positionInfo),\n            viewportSize,\n            padding\n        );\n        this.group.attr('position', [layoutRect.x - mainRect.x, layoutRect.y - mainRect.y]);\n\n        // Render background after group is layout.\n        this.group.add(\n            this._backgroundEl = makeBackground(mainRect, legendModel)\n        );\n    },\n\n    /**\n     * @protected\n     */\n    resetInner: function () {\n        this.getContentGroup().removeAll();\n        this._backgroundEl && this.group.remove(this._backgroundEl);\n    },\n\n    /**\n     * @protected\n     */\n    renderInner: function (itemAlign, legendModel, ecModel, api) {\n        var contentGroup = this.getContentGroup();\n        var legendDrawnMap = createHashMap();\n        var selectMode = legendModel.get('selectedMode');\n\n        var excludeSeriesId = [];\n        ecModel.eachRawSeries(function (seriesModel) {\n            !seriesModel.get('legendHoverLink') && excludeSeriesId.push(seriesModel.id);\n        });\n\n        each$16(legendModel.getData(), function (itemModel, dataIndex) {\n            var name = itemModel.get('name');\n\n            // Use empty string or \\n as a newline string\n            if (!this.newlineDisabled && (name === '' || name === '\\n')) {\n                contentGroup.add(new Group$3({\n                    newline: true\n                }));\n                return;\n            }\n\n            // Representitive series.\n            var seriesModel = ecModel.getSeriesByName(name)[0];\n\n            if (legendDrawnMap.get(name)) {\n                // Have been drawed\n                return;\n            }\n\n            // Series legend\n            if (seriesModel) {\n                var data = seriesModel.getData();\n                var color = data.getVisual('color');\n\n                // If color is a callback function\n                if (typeof color === 'function') {\n                    // Use the first data\n                    color = color(seriesModel.getDataParams(0));\n                }\n\n                // Using rect symbol defaultly\n                var legendSymbolType = data.getVisual('legendSymbol') || 'roundRect';\n                var symbolType = data.getVisual('symbol');\n\n                var itemGroup = this._createItem(\n                    name, dataIndex, itemModel, legendModel,\n                    legendSymbolType, symbolType,\n                    itemAlign, color,\n                    selectMode\n                );\n\n                itemGroup.on('click', curry$4(dispatchSelectAction, name, api))\n                    .on('mouseover', curry$4(dispatchHighlightAction, seriesModel.name, null, api, excludeSeriesId))\n                    .on('mouseout', curry$4(dispatchDownplayAction, seriesModel.name, null, api, excludeSeriesId));\n\n                legendDrawnMap.set(name, true);\n            }\n            else {\n                // Data legend of pie, funnel\n                ecModel.eachRawSeries(function (seriesModel) {\n                    // In case multiple series has same data name\n                    if (legendDrawnMap.get(name)) {\n                        return;\n                    }\n\n                    if (seriesModel.legendDataProvider) {\n                        var data = seriesModel.legendDataProvider();\n                        var idx = data.indexOfName(name);\n                        if (idx < 0) {\n                            return;\n                        }\n\n                        var color = data.getItemVisual(idx, 'color');\n\n                        var legendSymbolType = 'roundRect';\n\n                        var itemGroup = this._createItem(\n                            name, dataIndex, itemModel, legendModel,\n                            legendSymbolType, null,\n                            itemAlign, color,\n                            selectMode\n                        );\n\n                        // FIXME: consider different series has items with the same name.\n                        itemGroup.on('click', curry$4(dispatchSelectAction, name, api))\n                            // Should not specify the series name, consider legend controls\n                            // more than one pie series.\n                            .on('mouseover', curry$4(dispatchHighlightAction, null, name, api, excludeSeriesId))\n                            .on('mouseout', curry$4(dispatchDownplayAction, null, name, api, excludeSeriesId));\n\n                        legendDrawnMap.set(name, true);\n                    }\n\n                }, this);\n            }\n\n            if (__DEV__) {\n                if (!legendDrawnMap.get(name)) {\n                    console.warn(\n                        name + ' series not exists. Legend data should be same with series name or data name.'\n                    );\n                }\n            }\n        }, this);\n    },\n\n    _createItem: function (\n        name, dataIndex, itemModel, legendModel,\n        legendSymbolType, symbolType,\n        itemAlign, color, selectMode\n    ) {\n        var itemWidth = legendModel.get('itemWidth');\n        var itemHeight = legendModel.get('itemHeight');\n        var inactiveColor = legendModel.get('inactiveColor');\n        var symbolKeepAspect = legendModel.get('symbolKeepAspect');\n\n        var isSelected = legendModel.isSelected(name);\n        var itemGroup = new Group$3();\n\n        var textStyleModel = itemModel.getModel('textStyle');\n\n        var itemIcon = itemModel.get('icon');\n\n        var tooltipModel = itemModel.getModel('tooltip');\n        var legendGlobalTooltipModel = tooltipModel.parentModel;\n\n        // Use user given icon first\n        legendSymbolType = itemIcon || legendSymbolType;\n        itemGroup.add(createSymbol(\n            legendSymbolType,\n            0,\n            0,\n            itemWidth,\n            itemHeight,\n            isSelected ? color : inactiveColor,\n            // symbolKeepAspect default true for legend\n            symbolKeepAspect == null ? true : symbolKeepAspect\n        ));\n\n        // Compose symbols\n        // PENDING\n        if (!itemIcon && symbolType\n            // At least show one symbol, can't be all none\n            && ((symbolType !== legendSymbolType) || symbolType === 'none')\n        ) {\n            var size = itemHeight * 0.8;\n            if (symbolType === 'none') {\n                symbolType = 'circle';\n            }\n            // Put symbol in the center\n            itemGroup.add(createSymbol(\n                symbolType,\n                (itemWidth - size) / 2,\n                (itemHeight - size) / 2,\n                size,\n                size,\n                isSelected ? color : inactiveColor,\n                // symbolKeepAspect default true for legend\n                symbolKeepAspect == null ? true : symbolKeepAspect\n            ));\n        }\n\n        var textX = itemAlign === 'left' ? itemWidth + 5 : -5;\n        var textAlign = itemAlign;\n\n        var formatter = legendModel.get('formatter');\n        var content = name;\n        if (typeof formatter === 'string' && formatter) {\n            content = formatter.replace('{name}', name != null ? name : '');\n        }\n        else if (typeof formatter === 'function') {\n            content = formatter(name);\n        }\n\n        itemGroup.add(new Text({\n            style: setTextStyle({}, textStyleModel, {\n                text: content,\n                x: textX,\n                y: itemHeight / 2,\n                textFill: isSelected ? textStyleModel.getTextColor() : inactiveColor,\n                textAlign: textAlign,\n                textVerticalAlign: 'middle'\n            })\n        }));\n\n        // Add a invisible rect to increase the area of mouse hover\n        var hitRect = new Rect({\n            shape: itemGroup.getBoundingRect(),\n            invisible: true,\n            tooltip: tooltipModel.get('show') ? extend({\n                content: name,\n                // Defaul formatter\n                formatter: legendGlobalTooltipModel.get('formatter', true) || function () {\n                    return name;\n                },\n                formatterParams: {\n                    componentType: 'legend',\n                    legendIndex: legendModel.componentIndex,\n                    name: name,\n                    $vars: ['name']\n                }\n            }, tooltipModel.option) : null\n        });\n        itemGroup.add(hitRect);\n\n        itemGroup.eachChild(function (child) {\n            child.silent = true;\n        });\n\n        hitRect.silent = !selectMode;\n\n        this.getContentGroup().add(itemGroup);\n\n        setHoverStyle(itemGroup);\n\n        itemGroup.__legendDataIndex = dataIndex;\n\n        return itemGroup;\n    },\n\n    /**\n     * @protected\n     */\n    layoutInner: function (legendModel, itemAlign, maxSize) {\n        var contentGroup = this.getContentGroup();\n\n        // Place items in contentGroup.\n        box(\n            legendModel.get('orient'),\n            contentGroup,\n            legendModel.get('itemGap'),\n            maxSize.width,\n            maxSize.height\n        );\n\n        var contentRect = contentGroup.getBoundingRect();\n        contentGroup.attr('position', [-contentRect.x, -contentRect.y]);\n\n        return this.group.getBoundingRect();\n    },\n\n    /**\n     * @protected\n     */\n    remove: function () {\n        this.getContentGroup().removeAll();\n        this._isFirstRender = true;\n    }\n\n});\n\nfunction dispatchSelectAction(name, api) {\n    api.dispatchAction({\n        type: 'legendToggleSelect',\n        name: name\n    });\n}\n\nfunction dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId) {\n    // If element hover will move to a hoverLayer.\n    var el = api.getZr().storage.getDisplayList()[0];\n    if (!(el && el.useHoverLayer)) {\n        api.dispatchAction({\n            type: 'highlight',\n            seriesName: seriesName,\n            name: dataName,\n            excludeSeriesId: excludeSeriesId\n        });\n    }\n}\n\nfunction dispatchDownplayAction(seriesName, dataName, api, excludeSeriesId) {\n    // If element hover will move to a hoverLayer.\n    var el = api.getZr().storage.getDisplayList()[0];\n    if (!(el && el.useHoverLayer)) {\n        api.dispatchAction({\n            type: 'downplay',\n            seriesName: seriesName,\n            name: dataName,\n            excludeSeriesId: excludeSeriesId\n        });\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar legendFilter = function (ecModel) {\n\n    var legendModels = ecModel.findComponents({\n        mainType: 'legend'\n    });\n    if (legendModels && legendModels.length) {\n        ecModel.filterSeries(function (series) {\n            // If in any legend component the status is not selected.\n            // Because in legend series is assumed selected when it is not in the legend data.\n            for (var i = 0; i < legendModels.length; i++) {\n                if (!legendModels[i].isSelected(series.name)) {\n                    return false;\n                }\n            }\n            return true;\n        });\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n// Do not contain scrollable legend, for sake of file size.\n\n// Series Filter\nregisterProcessor(legendFilter);\n\nComponentModel.registerSubTypeDefaulter('legend', function () {\n    // Default 'plain' when no type specified.\n    return 'plain';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ScrollableLegendModel = LegendModel.extend({\n\n    type: 'legend.scroll',\n\n    /**\n     * @param {number} scrollDataIndex\n     */\n    setScrollDataIndex: function (scrollDataIndex) {\n        this.option.scrollDataIndex = scrollDataIndex;\n    },\n\n    defaultOption: {\n        scrollDataIndex: 0,\n        pageButtonItemGap: 5,\n        pageButtonGap: null,\n        pageButtonPosition: 'end', // 'start' or 'end'\n        pageFormatter: '{current}/{total}', // If null/undefined, do not show page.\n        pageIcons: {\n            horizontal: ['M0,0L12,-10L12,10z', 'M0,0L-12,-10L-12,10z'],\n            vertical: ['M0,0L20,0L10,-20z', 'M0,0L20,0L10,20z']\n        },\n        pageIconColor: '#2f4554',\n        pageIconInactiveColor: '#aaa',\n        pageIconSize: 15, // Can be [10, 3], which represents [width, height]\n        pageTextStyle: {\n            color: '#333'\n        },\n\n        animationDurationUpdate: 800\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel, extraOpt) {\n        var inputPositionParams = getLayoutParams(option);\n\n        ScrollableLegendModel.superCall(this, 'init', option, parentModel, ecModel, extraOpt);\n\n        mergeAndNormalizeLayoutParams(this, option, inputPositionParams);\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (option, extraOpt) {\n        ScrollableLegendModel.superCall(this, 'mergeOption', option, extraOpt);\n\n        mergeAndNormalizeLayoutParams(this, this.option, option);\n    },\n\n    getOrient: function () {\n        return this.get('orient') === 'vertical'\n            ? {index: 1, name: 'vertical'}\n            : {index: 0, name: 'horizontal'};\n    }\n\n});\n\n// Do not `ignoreSize` to enable setting {left: 10, right: 10}.\nfunction mergeAndNormalizeLayoutParams(legendModel, target, raw) {\n    var orient = legendModel.getOrient();\n    var ignoreSize = [1, 1];\n    ignoreSize[orient.index] = 0;\n    mergeLayoutParam(target, raw, {\n        type: 'box', ignoreSize: ignoreSize\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Separate legend and scrollable legend to reduce package size.\n */\n\nvar Group$4 = Group;\n\nvar WH$1 = ['width', 'height'];\nvar XY$1 = ['x', 'y'];\n\nvar ScrollableLegendView = LegendView.extend({\n\n    type: 'legend.scroll',\n\n    newlineDisabled: true,\n\n    init: function () {\n\n        ScrollableLegendView.superCall(this, 'init');\n\n        /**\n         * @private\n         * @type {number} For `scroll`.\n         */\n        this._currentIndex = 0;\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._containerGroup = new Group$4());\n        this._containerGroup.add(this.getContentGroup());\n\n        /**\n         * @private\n         * @type {module:zrender/container/Group}\n         */\n        this.group.add(this._controllerGroup = new Group$4());\n\n        /**\n         *\n         * @private\n         */\n        this._showController;\n    },\n\n    /**\n     * @override\n     */\n    resetInner: function () {\n        ScrollableLegendView.superCall(this, 'resetInner');\n\n        this._controllerGroup.removeAll();\n        this._containerGroup.removeClipPath();\n        this._containerGroup.__rectSize = null;\n    },\n\n    /**\n     * @override\n     */\n    renderInner: function (itemAlign, legendModel, ecModel, api) {\n        var me = this;\n\n        // Render content items.\n        ScrollableLegendView.superCall(this, 'renderInner', itemAlign, legendModel, ecModel, api);\n\n        var controllerGroup = this._controllerGroup;\n\n        // FIXME: support be 'auto' adapt to size number text length,\n        // e.g., '3/12345' should not overlap with the control arrow button.\n        var pageIconSize = legendModel.get('pageIconSize', true);\n        if (!isArray(pageIconSize)) {\n            pageIconSize = [pageIconSize, pageIconSize];\n        }\n\n        createPageButton('pagePrev', 0);\n\n        var pageTextStyleModel = legendModel.getModel('pageTextStyle');\n        controllerGroup.add(new Text({\n            name: 'pageText',\n            style: {\n                textFill: pageTextStyleModel.getTextColor(),\n                font: pageTextStyleModel.getFont(),\n                textVerticalAlign: 'middle',\n                textAlign: 'center'\n            },\n            silent: true\n        }));\n\n        createPageButton('pageNext', 1);\n\n        function createPageButton(name, iconIdx) {\n            var pageDataIndexName = name + 'DataIndex';\n            var icon = createIcon(\n                legendModel.get('pageIcons', true)[legendModel.getOrient().name][iconIdx],\n                {\n                    // Buttons will be created in each render, so we do not need\n                    // to worry about avoiding using legendModel kept in scope.\n                    onclick: bind(\n                        me._pageGo, me, pageDataIndexName, legendModel, api\n                    )\n                },\n                {\n                    x: -pageIconSize[0] / 2,\n                    y: -pageIconSize[1] / 2,\n                    width: pageIconSize[0],\n                    height: pageIconSize[1]\n                }\n            );\n            icon.name = name;\n            controllerGroup.add(icon);\n        }\n    },\n\n    /**\n     * @override\n     */\n    layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender) {\n        var contentGroup = this.getContentGroup();\n        var containerGroup = this._containerGroup;\n        var controllerGroup = this._controllerGroup;\n\n        var orientIdx = legendModel.getOrient().index;\n        var wh = WH$1[orientIdx];\n        var hw = WH$1[1 - orientIdx];\n        var yx = XY$1[1 - orientIdx];\n\n        // Place items in contentGroup.\n        box(\n            legendModel.get('orient'),\n            contentGroup,\n            legendModel.get('itemGap'),\n            !orientIdx ? null : maxSize.width,\n            orientIdx ? null : maxSize.height\n        );\n\n        box(\n            // Buttons in controller are layout always horizontally.\n            'horizontal',\n            controllerGroup,\n            legendModel.get('pageButtonItemGap', true)\n        );\n\n        var contentRect = contentGroup.getBoundingRect();\n        var controllerRect = controllerGroup.getBoundingRect();\n        var showController = this._showController = contentRect[wh] > maxSize[wh];\n\n        var contentPos = [-contentRect.x, -contentRect.y];\n        // Remain contentPos when scroll animation perfroming.\n        // If first rendering, `contentGroup.position` is [0, 0], which\n        // does not make sense and may cause unexepcted animation if adopted.\n        if (!isFirstRender) {\n            contentPos[orientIdx] = contentGroup.position[orientIdx];\n        }\n\n        // Layout container group based on 0.\n        var containerPos = [0, 0];\n        var controllerPos = [-controllerRect.x, -controllerRect.y];\n        var pageButtonGap = retrieve2(\n            legendModel.get('pageButtonGap', true), legendModel.get('itemGap', true)\n        );\n\n        // Place containerGroup and controllerGroup and contentGroup.\n        if (showController) {\n            var pageButtonPosition = legendModel.get('pageButtonPosition', true);\n            // controller is on the right / bottom.\n            if (pageButtonPosition === 'end') {\n                controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh];\n            }\n            // controller is on the left / top.\n            else {\n                containerPos[orientIdx] += controllerRect[wh] + pageButtonGap;\n            }\n        }\n\n        // Always align controller to content as 'middle'.\n        controllerPos[1 - orientIdx] += contentRect[hw] / 2 - controllerRect[hw] / 2;\n\n        contentGroup.attr('position', contentPos);\n        containerGroup.attr('position', containerPos);\n        controllerGroup.attr('position', controllerPos);\n\n        // Calculate `mainRect` and set `clipPath`.\n        // mainRect should not be calculated by `this.group.getBoundingRect()`\n        // for sake of the overflow.\n        var mainRect = this.group.getBoundingRect();\n        var mainRect = {x: 0, y: 0};\n        // Consider content may be overflow (should be clipped).\n        mainRect[wh] = showController ? maxSize[wh] : contentRect[wh];\n        mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw]);\n        // `containerRect[yx] + containerPos[1 - orientIdx]` is 0.\n        mainRect[yx] = Math.min(0, controllerRect[yx] + controllerPos[1 - orientIdx]);\n\n        containerGroup.__rectSize = maxSize[wh];\n        if (showController) {\n            var clipShape = {x: 0, y: 0};\n            clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap, 0);\n            clipShape[hw] = mainRect[hw];\n            containerGroup.setClipPath(new Rect({shape: clipShape}));\n            // Consider content may be larger than container, container rect\n            // can not be obtained from `containerGroup.getBoundingRect()`.\n            containerGroup.__rectSize = clipShape[wh];\n        }\n        else {\n            // Do not remove or ignore controller. Keep them set as place holders.\n            controllerGroup.eachChild(function (child) {\n                child.attr({invisible: true, silent: true});\n            });\n        }\n\n        // Content translate animation.\n        var pageInfo = this._getPageInfo(legendModel);\n        pageInfo.pageIndex != null && updateProps(\n            contentGroup,\n            {position: pageInfo.contentPosition},\n            // When switch from \"show controller\" to \"not show controller\", view should be\n            // updated immediately without animation, otherwise causes weird efffect.\n            showController ? legendModel : false\n        );\n\n        this._updatePageInfoView(legendModel, pageInfo);\n\n        return mainRect;\n    },\n\n    _pageGo: function (to, legendModel, api) {\n        var scrollDataIndex = this._getPageInfo(legendModel)[to];\n\n        scrollDataIndex != null && api.dispatchAction({\n            type: 'legendScroll',\n            scrollDataIndex: scrollDataIndex,\n            legendId: legendModel.id\n        });\n    },\n\n    _updatePageInfoView: function (legendModel, pageInfo) {\n        var controllerGroup = this._controllerGroup;\n\n        each$1(['pagePrev', 'pageNext'], function (name) {\n            var canJump = pageInfo[name + 'DataIndex'] != null;\n            var icon = controllerGroup.childOfName(name);\n            if (icon) {\n                icon.setStyle(\n                    'fill',\n                    canJump\n                        ? legendModel.get('pageIconColor', true)\n                        : legendModel.get('pageIconInactiveColor', true)\n                );\n                icon.cursor = canJump ? 'pointer' : 'default';\n            }\n        });\n\n        var pageText = controllerGroup.childOfName('pageText');\n        var pageFormatter = legendModel.get('pageFormatter');\n        var pageIndex = pageInfo.pageIndex;\n        var current = pageIndex != null ? pageIndex + 1 : 0;\n        var total = pageInfo.pageCount;\n\n        pageText && pageFormatter && pageText.setStyle(\n            'text',\n            isString(pageFormatter)\n                ? pageFormatter.replace('{current}', current).replace('{total}', total)\n                : pageFormatter({current: current, total: total})\n        );\n    },\n\n    /**\n     * @param {module:echarts/model/Model} legendModel\n     * @return {Object} {\n     *  contentPosition: Array.<number>, null when data item not found.\n     *  pageIndex: number, null when data item not found.\n     *  pageCount: number, always be a number, can be 0.\n     *  pagePrevDataIndex: number, null when no next page.\n     *  pageNextDataIndex: number, null when no previous page.\n     * }\n     */\n    _getPageInfo: function (legendModel) {\n        var scrollDataIndex = legendModel.get('scrollDataIndex', true);\n        var contentGroup = this.getContentGroup();\n        var containerRectSize = this._containerGroup.__rectSize;\n        var orientIdx = legendModel.getOrient().index;\n        var wh = WH$1[orientIdx];\n        var xy = XY$1[orientIdx];\n        var targetItemIndex = this._findTargetItemIndex(scrollDataIndex);\n        var children = contentGroup.children();\n        var targetItem = children[targetItemIndex];\n        var itemCount = children.length;\n        var pCount = !itemCount ? 0 : 1;\n\n        var result = {\n            contentPosition: contentGroup.position.slice(),\n            pageCount: pCount,\n            pageIndex: pCount - 1,\n            pagePrevDataIndex: null,\n            pageNextDataIndex: null\n        };\n\n        if (!targetItem) {\n            return result;\n        }\n\n        var targetItemInfo = getItemInfo(targetItem);\n        result.contentPosition[orientIdx] = -targetItemInfo.s;\n\n        // Strategy:\n        // (1) Always align based on the left/top most item.\n        // (2) It is user-friendly that the last item shown in the\n        // current window is shown at the begining of next window.\n        // Otherwise if half of the last item is cut by the window,\n        // it will have no chance to display entirely.\n        // (3) Consider that item size probably be different, we\n        // have calculate pageIndex by size rather than item index,\n        // and we can not get page index directly by division.\n        // (4) The window is to narrow to contain more than\n        // one item, we should make sure that the page can be fliped.\n\n        for (var i = targetItemIndex + 1,\n            winStartItemInfo = targetItemInfo,\n            winEndItemInfo = targetItemInfo,\n            currItemInfo = null;\n            i <= itemCount;\n            ++i\n        ) {\n            currItemInfo = getItemInfo(children[i]);\n            if (\n                // Half of the last item is out of the window.\n                (!currItemInfo && winEndItemInfo.e > winStartItemInfo.s + containerRectSize)\n                // If the current item does not intersect with the window, the new page\n                // can be started at the current item or the last item.\n                || (currItemInfo && !intersect(currItemInfo, winStartItemInfo.s))\n            ) {\n                if (winEndItemInfo.i > winStartItemInfo.i) {\n                    winStartItemInfo = winEndItemInfo;\n                }\n                else { // e.g., when page size is smaller than item size.\n                    winStartItemInfo = currItemInfo;\n                }\n                if (winStartItemInfo) {\n                    if (result.pageNextDataIndex == null) {\n                        result.pageNextDataIndex = winStartItemInfo.i;\n                    }\n                    ++result.pageCount;\n                }\n            }\n            winEndItemInfo = currItemInfo;\n        }\n\n        for (var i = targetItemIndex - 1,\n            winStartItemInfo = targetItemInfo,\n            winEndItemInfo = targetItemInfo,\n            currItemInfo = null;\n            i >= -1;\n            --i\n        ) {\n            currItemInfo = getItemInfo(children[i]);\n            if (\n                // If the the end item does not intersect with the window started\n                // from the current item, a page can be settled.\n                (!currItemInfo || !intersect(winEndItemInfo, currItemInfo.s))\n                // e.g., when page size is smaller than item size.\n                && winStartItemInfo.i < winEndItemInfo.i\n            ) {\n                winEndItemInfo = winStartItemInfo;\n                if (result.pagePrevDataIndex == null) {\n                    result.pagePrevDataIndex = winStartItemInfo.i;\n                }\n                ++result.pageCount;\n                ++result.pageIndex;\n            }\n            winStartItemInfo = currItemInfo;\n        }\n\n        return result;\n\n        function getItemInfo(el) {\n            if (el) {\n                var itemRect = el.getBoundingRect();\n                var start = itemRect[xy] + el.position[orientIdx];\n                return {\n                    s: start,\n                    e: start + itemRect[wh],\n                    i: el.__legendDataIndex\n                };\n            }\n        }\n\n        function intersect(itemInfo, winStart) {\n            return itemInfo.e >= winStart && itemInfo.s <= winStart + containerRectSize;\n        }\n    },\n\n    _findTargetItemIndex: function (targetDataIndex) {\n        var index;\n        var contentGroup = this.getContentGroup();\n        if (this._showController) {\n            contentGroup.eachChild(function (child, idx) {\n                if (child.__legendDataIndex === targetDataIndex) {\n                    index = idx;\n                }\n            });\n        }\n        else {\n            index = 0;\n        }\n        return index;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @event legendScroll\n * @type {Object}\n * @property {string} type 'legendScroll'\n * @property {string} scrollDataIndex\n */\nregisterAction(\n    'legendScroll', 'legendscroll',\n    function (payload, ecModel) {\n        var scrollDataIndex = payload.scrollDataIndex;\n\n        scrollDataIndex != null && ecModel.eachComponent(\n            {mainType: 'legend', subType: 'scroll', query: payload},\n            function (legendModel) {\n                legendModel.setScrollDataIndex(scrollDataIndex);\n            }\n        );\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Legend component entry file8\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentModel({\n\n    type: 'tooltip',\n\n    dependencies: ['axisPointer'],\n\n    defaultOption: {\n        zlevel: 0,\n\n        z: 60,\n\n        show: true,\n\n        // tooltip主体内容\n        showContent: true,\n\n        // 'trigger' only works on coordinate system.\n        // 'item' | 'axis' | 'none'\n        trigger: 'item',\n\n        // 'click' | 'mousemove' | 'none'\n        triggerOn: 'mousemove|click',\n\n        alwaysShowContent: false,\n\n        displayMode: 'single', // 'single' | 'multipleByCoordSys'\n\n        renderMode: 'auto', // 'auto' | 'html' | 'richText'\n        // 'auto': use html by default, and use non-html if `document` is not defined\n        // 'html': use html for tooltip\n        // 'richText': use canvas, svg, and etc. for tooltip\n\n        // 位置 {Array} | {Function}\n        // position: null\n        // Consider triggered from axisPointer handle, verticalAlign should be 'middle'\n        // align: null,\n        // verticalAlign: null,\n\n        // 是否约束 content 在 viewRect 中。默认 false 是为了兼容以前版本。\n        confine: false,\n\n        // 内容格式器：{string}（Template） ¦ {Function}\n        // formatter: null\n\n        showDelay: 0,\n\n        // 隐藏延迟，单位ms\n        hideDelay: 100,\n\n        // 动画变换时间，单位s\n        transitionDuration: 0.4,\n\n        enterable: false,\n\n        // 提示背景颜色，默认为透明度为0.7的黑色\n        backgroundColor: 'rgba(50,50,50,0.7)',\n\n        // 提示边框颜色\n        borderColor: '#333',\n\n        // 提示边框圆角，单位px，默认为4\n        borderRadius: 4,\n\n        // 提示边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n\n        // 提示内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n\n        // Extra css text\n        extraCssText: '',\n\n        // 坐标轴指示器，坐标轴触发有效\n        axisPointer: {\n            // 默认为直线\n            // 可选为：'line' | 'shadow' | 'cross'\n            type: 'line',\n\n            // type 为 line 的时候有效，指定 tooltip line 所在的轴，可选\n            // 可选 'x' | 'y' | 'angle' | 'radius' | 'auto'\n            // 默认 'auto'，会选择类型为 category 的轴，对于双数值轴，笛卡尔坐标系会默认选择 x 轴\n            // 极坐标系会默认选择 angle 轴\n            axis: 'auto',\n\n            animation: 'auto',\n            animationDurationUpdate: 200,\n            animationEasingUpdate: 'exponentialOut',\n\n            crossStyle: {\n                color: '#999',\n                width: 1,\n                type: 'dashed',\n\n                // TODO formatter\n                textStyle: {}\n            }\n\n            // lineStyle and shadowStyle should not be specified here,\n            // otherwise it will always override those styles on option.axisPointer.\n        },\n        textStyle: {\n            color: '#fff',\n            fontSize: 14\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$18 = each$1;\nvar toCamelCase$1 = toCamelCase;\n\nvar vendors = ['', '-webkit-', '-moz-', '-o-'];\n\nvar gCssText = 'position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;';\n\n/**\n * @param {number} duration\n * @return {string}\n * @inner\n */\nfunction assembleTransition(duration) {\n    var transitionCurve = 'cubic-bezier(0.23, 1, 0.32, 1)';\n    var transitionText = 'left ' + duration + 's ' + transitionCurve + ','\n                        + 'top ' + duration + 's ' + transitionCurve;\n    return map(vendors, function (vendorPrefix) {\n        return vendorPrefix + 'transition:' + transitionText;\n    }).join(';');\n}\n\n/**\n * @param {Object} textStyle\n * @return {string}\n * @inner\n */\nfunction assembleFont(textStyleModel) {\n    var cssText = [];\n\n    var fontSize = textStyleModel.get('fontSize');\n    var color = textStyleModel.getTextColor();\n\n    color && cssText.push('color:' + color);\n\n    cssText.push('font:' + textStyleModel.getFont());\n\n    fontSize\n        && cssText.push('line-height:' + Math.round(fontSize * 3 / 2) + 'px');\n\n    each$18(['decoration', 'align'], function (name) {\n        var val = textStyleModel.get(name);\n        val && cssText.push('text-' + name + ':' + val);\n    });\n\n    return cssText.join(';');\n}\n\n/**\n * @param {Object} tooltipModel\n * @return {string}\n * @inner\n */\nfunction assembleCssText(tooltipModel) {\n\n    var cssText = [];\n\n    var transitionDuration = tooltipModel.get('transitionDuration');\n    var backgroundColor = tooltipModel.get('backgroundColor');\n    var textStyleModel = tooltipModel.getModel('textStyle');\n    var padding = tooltipModel.get('padding');\n\n    // Animation transition. Do not animate when transitionDuration is 0.\n    transitionDuration\n        && cssText.push(assembleTransition(transitionDuration));\n\n    if (backgroundColor) {\n        if (env$1.canvasSupported) {\n            cssText.push('background-Color:' + backgroundColor);\n        }\n        else {\n            // for ie\n            cssText.push(\n                'background-Color:#' + toHex(backgroundColor)\n            );\n            cssText.push('filter:alpha(opacity=70)');\n        }\n    }\n\n    // Border style\n    each$18(['width', 'color', 'radius'], function (name) {\n        var borderName = 'border-' + name;\n        var camelCase = toCamelCase$1(borderName);\n        var val = tooltipModel.get(camelCase);\n        val != null\n            && cssText.push(borderName + ':' + val + (name === 'color' ? '' : 'px'));\n    });\n\n    // Text style\n    cssText.push(assembleFont(textStyleModel));\n\n    // Padding\n    if (padding != null) {\n        cssText.push('padding:' + normalizeCssArray$1(padding).join('px ') + 'px');\n    }\n\n    return cssText.join(';') + ';';\n}\n\n/**\n * @alias module:echarts/component/tooltip/TooltipContent\n * @constructor\n */\nfunction TooltipContent(container, api) {\n    if (env$1.wxa) {\n        return null;\n    }\n\n    var el = document.createElement('div');\n    var zr = this._zr = api.getZr();\n\n    this.el = el;\n\n    this._x = api.getWidth() / 2;\n    this._y = api.getHeight() / 2;\n\n    container.appendChild(el);\n\n    this._container = container;\n\n    this._show = false;\n\n    /**\n     * @private\n     */\n    this._hideTimeout;\n\n    var self = this;\n    el.onmouseenter = function () {\n        // clear the timeout in hideLater and keep showing tooltip\n        if (self._enterable) {\n            clearTimeout(self._hideTimeout);\n            self._show = true;\n        }\n        self._inContent = true;\n    };\n    el.onmousemove = function (e) {\n        e = e || window.event;\n        if (!self._enterable) {\n            // Try trigger zrender event to avoid mouse\n            // in and out shape too frequently\n            var handler = zr.handler;\n            normalizeEvent(container, e, true);\n            handler.dispatch('mousemove', e);\n        }\n    };\n    el.onmouseleave = function () {\n        if (self._enterable) {\n            if (self._show) {\n                self.hideLater(self._hideDelay);\n            }\n        }\n        self._inContent = false;\n    };\n}\n\nTooltipContent.prototype = {\n\n    constructor: TooltipContent,\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    _enterable: true,\n\n    /**\n     * Update when tooltip is rendered\n     */\n    update: function () {\n        // FIXME\n        // Move this logic to ec main?\n        var container = this._container;\n        var stl = container.currentStyle\n            || document.defaultView.getComputedStyle(container);\n        var domStyle = container.style;\n        if (domStyle.position !== 'absolute' && stl.position !== 'absolute') {\n            domStyle.position = 'relative';\n        }\n        // Hide the tooltip\n        // PENDING\n        // this.hide();\n    },\n\n    show: function (tooltipModel) {\n        clearTimeout(this._hideTimeout);\n        var el = this.el;\n\n        el.style.cssText = gCssText + assembleCssText(tooltipModel)\n            // http://stackoverflow.com/questions/21125587/css3-transition-not-working-in-chrome-anymore\n            + ';left:' + this._x + 'px;top:' + this._y + 'px;'\n            + (tooltipModel.get('extraCssText') || '');\n\n        el.style.display = el.innerHTML ? 'block' : 'none';\n\n        // If mouse occsionally move over the tooltip, a mouseout event will be\n        // triggered by canvas, and cuase some unexpectable result like dragging\n        // stop, \"unfocusAdjacency\". Here `pointer-events: none` is used to solve\n        // it. Although it is not suppored by IE8~IE10, fortunately it is a rare\n        // scenario.\n        el.style.pointerEvents = this._enterable ? 'auto' : 'none';\n\n        this._show = true;\n    },\n\n    setContent: function (content) {\n        this.el.innerHTML = content == null ? '' : content;\n    },\n\n    setEnterable: function (enterable) {\n        this._enterable = enterable;\n    },\n\n    getSize: function () {\n        var el = this.el;\n        return [el.clientWidth, el.clientHeight];\n    },\n\n    moveTo: function (x, y) {\n        // xy should be based on canvas root. But tooltipContent is\n        // the sibling of canvas root. So padding of ec container\n        // should be considered here.\n        var zr = this._zr;\n        var viewportRootOffset;\n        if (zr && zr.painter && (viewportRootOffset = zr.painter.getViewportRootOffset())) {\n            x += viewportRootOffset.offsetLeft;\n            y += viewportRootOffset.offsetTop;\n        }\n\n        var style = this.el.style;\n        style.left = x + 'px';\n        style.top = y + 'px';\n\n        this._x = x;\n        this._y = y;\n    },\n\n    hide: function () {\n        this.el.style.display = 'none';\n        this._show = false;\n    },\n\n    hideLater: function (time) {\n        if (this._show && !(this._inContent && this._enterable)) {\n            if (time) {\n                this._hideDelay = time;\n                // Set show false to avoid invoke hideLater mutiple times\n                this._show = false;\n                this._hideTimeout = setTimeout(bind(this.hide, this), time);\n            }\n            else {\n                this.hide();\n            }\n        }\n    },\n\n    isShow: function () {\n        return this._show;\n    },\n\n    getOuterSize: function () {\n        var width = this.el.clientWidth;\n        var height = this.el.clientHeight;\n\n        // Consider browser compatibility.\n        // IE8 does not support getComputedStyle.\n        if (document.defaultView && document.defaultView.getComputedStyle) {\n            var stl = document.defaultView.getComputedStyle(this.el);\n            if (stl) {\n                width += parseInt(stl.paddingLeft, 10) + parseInt(stl.paddingRight, 10)\n                    + parseInt(stl.borderLeftWidth, 10) + parseInt(stl.borderRightWidth, 10);\n                height += parseInt(stl.paddingTop, 10) + parseInt(stl.paddingBottom, 10)\n                    + parseInt(stl.borderTopWidth, 10) + parseInt(stl.borderBottomWidth, 10);\n            }\n        }\n\n        return {width: width, height: height};\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import Group from 'zrender/src/container/Group';\n/**\n * @alias module:echarts/component/tooltip/TooltipRichContent\n * @constructor\n */\nfunction TooltipRichContent(api) {\n\n    this._zr = api.getZr();\n\n    this._show = false;\n\n    /**\n     * @private\n     */\n    this._hideTimeout;\n}\n\nTooltipRichContent.prototype = {\n\n    constructor: TooltipRichContent,\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    _enterable: true,\n\n    /**\n     * Update when tooltip is rendered\n     */\n    update: function () {\n        // noop\n    },\n\n    show: function (tooltipModel) {\n        if (this._hideTimeout) {\n            clearTimeout(this._hideTimeout);\n        }\n\n        this.el.attr('show', true);\n        this._show = true;\n    },\n\n    /**\n     * Set tooltip content\n     *\n     * @param {string} content rich text string of content\n     * @param {Object} markerRich rich text style\n     * @param {Object} tooltipModel tooltip model\n     */\n    setContent: function (content, markerRich, tooltipModel) {\n        if (this.el) {\n            this._zr.remove(this.el);\n        }\n\n        var markers = {};\n        var text = content;\n        var prefix = '{marker';\n        var suffix = '|}';\n        var startId = text.indexOf(prefix);\n        while (startId >= 0) {\n            var endId = text.indexOf(suffix);\n            var name = text.substr(startId + prefix.length, endId - startId - prefix.length);\n            if (name.indexOf('sub') > -1) {\n                markers['marker' + name] = {\n                    textWidth: 4,\n                    textHeight: 4,\n                    textBorderRadius: 2,\n                    textBackgroundColor: markerRich[name],\n                    // TODO: textOffset is not implemented for rich text\n                    textOffset: [3, 0]\n                };\n            }\n            else {\n                markers['marker' + name] = {\n                    textWidth: 10,\n                    textHeight: 10,\n                    textBorderRadius: 5,\n                    textBackgroundColor: markerRich[name]\n                };\n            }\n\n            text = text.substr(endId + 1);\n            startId = text.indexOf('{marker');\n        }\n\n        this.el = new Text({\n            style: {\n                rich: markers,\n                text: content,\n                textLineHeight: 20,\n                textBackgroundColor: tooltipModel.get('backgroundColor'),\n                textBorderRadius: tooltipModel.get('borderRadius'),\n                textFill: tooltipModel.get('textStyle.color'),\n                textPadding: tooltipModel.get('padding')\n            },\n            z: tooltipModel.get('z')\n        });\n        this._zr.add(this.el);\n\n        var self = this;\n        this.el.on('mouseover', function () {\n            // clear the timeout in hideLater and keep showing tooltip\n            if (self._enterable) {\n                clearTimeout(self._hideTimeout);\n                self._show = true;\n            }\n            self._inContent = true;\n        });\n        this.el.on('mouseout', function () {\n            if (self._enterable) {\n                if (self._show) {\n                    self.hideLater(self._hideDelay);\n                }\n            }\n            self._inContent = false;\n        });\n    },\n\n    setEnterable: function (enterable) {\n        this._enterable = enterable;\n    },\n\n    getSize: function () {\n        var bounding = this.el.getBoundingRect();\n        return [bounding.width, bounding.height];\n    },\n\n    moveTo: function (x, y) {\n        if (this.el) {\n            this.el.attr('position', [x, y]);\n        }\n    },\n\n    hide: function () {\n        this.el.hide();\n        this._show = false;\n    },\n\n    hideLater: function (time) {\n        if (this._show && !(this._inContent && this._enterable)) {\n            if (time) {\n                this._hideDelay = time;\n                // Set show false to avoid invoke hideLater mutiple times\n                this._show = false;\n                this._hideTimeout = setTimeout(bind(this.hide, this), time);\n            }\n            else {\n                this.hide();\n            }\n        }\n    },\n\n    isShow: function () {\n        return this._show;\n    },\n\n    getOuterSize: function () {\n        return this.getSize();\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$3 = bind;\nvar each$17 = each$1;\nvar parsePercent$2 = parsePercent$1;\n\nvar proxyRect = new Rect({\n    shape: {x: -1, y: -1, width: 2, height: 2}\n});\n\nextendComponentView({\n\n    type: 'tooltip',\n\n    init: function (ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n\n        var tooltipModel = ecModel.getComponent('tooltip');\n        var renderMode = tooltipModel.get('renderMode');\n        this._renderMode = getTooltipRenderMode(renderMode);\n\n        var tooltipContent;\n        if (this._renderMode === 'html') {\n            tooltipContent = new TooltipContent(api.getDom(), api);\n            this._newLine = '<br/>';\n        }\n        else {\n            tooltipContent = new TooltipRichContent(api);\n            this._newLine = '\\n';\n        }\n\n        this._tooltipContent = tooltipContent;\n    },\n\n    render: function (tooltipModel, ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n\n        // Reset\n        this.group.removeAll();\n\n        /**\n         * @private\n         * @type {module:echarts/component/tooltip/TooltipModel}\n         */\n        this._tooltipModel = tooltipModel;\n\n        /**\n         * @private\n         * @type {module:echarts/model/Global}\n         */\n        this._ecModel = ecModel;\n\n        /**\n         * @private\n         * @type {module:echarts/ExtensionAPI}\n         */\n        this._api = api;\n\n        /**\n         * Should be cleaned when render.\n         * @private\n         * @type {Array.<Array.<Object>>}\n         */\n        this._lastDataByCoordSys = null;\n\n        /**\n         * @private\n         * @type {boolean}\n         */\n        this._alwaysShowContent = tooltipModel.get('alwaysShowContent');\n\n        var tooltipContent = this._tooltipContent;\n        tooltipContent.update();\n        tooltipContent.setEnterable(tooltipModel.get('enterable'));\n\n        this._initGlobalListener();\n\n        this._keepShow();\n    },\n\n    _initGlobalListener: function () {\n        var tooltipModel = this._tooltipModel;\n        var triggerOn = tooltipModel.get('triggerOn');\n\n        register(\n            'itemTooltip',\n            this._api,\n            bind$3(function (currTrigger, e, dispatchAction) {\n                // If 'none', it is not controlled by mouse totally.\n                if (triggerOn !== 'none') {\n                    if (triggerOn.indexOf(currTrigger) >= 0) {\n                        this._tryShow(e, dispatchAction);\n                    }\n                    else if (currTrigger === 'leave') {\n                        this._hide(dispatchAction);\n                    }\n                }\n            }, this)\n        );\n    },\n\n    _keepShow: function () {\n        var tooltipModel = this._tooltipModel;\n        var ecModel = this._ecModel;\n        var api = this._api;\n\n        // Try to keep the tooltip show when refreshing\n        if (this._lastX != null\n            && this._lastY != null\n            // When user is willing to control tooltip totally using API,\n            // self.manuallyShowTip({x, y}) might cause tooltip hide,\n            // which is not expected.\n            && tooltipModel.get('triggerOn') !== 'none'\n        ) {\n            var self = this;\n            clearTimeout(this._refreshUpdateTimeout);\n            this._refreshUpdateTimeout = setTimeout(function () {\n                // Show tip next tick after other charts are rendered\n                // In case highlight action has wrong result\n                // FIXME\n                self.manuallyShowTip(tooltipModel, ecModel, api, {\n                    x: self._lastX,\n                    y: self._lastY\n                });\n            });\n        }\n    },\n\n    /**\n     * Show tip manually by\n     * dispatchAction({\n     *     type: 'showTip',\n     *     x: 10,\n     *     y: 10\n     * });\n     * Or\n     * dispatchAction({\n     *      type: 'showTip',\n     *      seriesIndex: 0,\n     *      dataIndex or dataIndexInside or name\n     * });\n     *\n     *  TODO Batch\n     */\n    manuallyShowTip: function (tooltipModel, ecModel, api, payload) {\n        if (payload.from === this.uid || env$1.node) {\n            return;\n        }\n\n        var dispatchAction = makeDispatchAction$1(payload, api);\n\n        // Reset ticket\n        this._ticket = '';\n\n        // When triggered from axisPointer.\n        var dataByCoordSys = payload.dataByCoordSys;\n\n        if (payload.tooltip && payload.x != null && payload.y != null) {\n            var el = proxyRect;\n            el.position = [payload.x, payload.y];\n            el.update();\n            el.tooltip = payload.tooltip;\n            // Manually show tooltip while view is not using zrender elements.\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                target: el\n            }, dispatchAction);\n        }\n        else if (dataByCoordSys) {\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                position: payload.position,\n                event: {},\n                dataByCoordSys: payload.dataByCoordSys,\n                tooltipOption: payload.tooltipOption\n            }, dispatchAction);\n        }\n        else if (payload.seriesIndex != null) {\n\n            if (this._manuallyAxisShowTip(tooltipModel, ecModel, api, payload)) {\n                return;\n            }\n\n            var pointInfo = findPointFromSeries(payload, ecModel);\n            var cx = pointInfo.point[0];\n            var cy = pointInfo.point[1];\n            if (cx != null && cy != null) {\n                this._tryShow({\n                    offsetX: cx,\n                    offsetY: cy,\n                    position: payload.position,\n                    target: pointInfo.el,\n                    event: {}\n                }, dispatchAction);\n            }\n        }\n        else if (payload.x != null && payload.y != null) {\n            // FIXME\n            // should wrap dispatchAction like `axisPointer/globalListener` ?\n            api.dispatchAction({\n                type: 'updateAxisPointer',\n                x: payload.x,\n                y: payload.y\n            });\n\n            this._tryShow({\n                offsetX: payload.x,\n                offsetY: payload.y,\n                position: payload.position,\n                target: api.getZr().findHover(payload.x, payload.y).target,\n                event: {}\n            }, dispatchAction);\n        }\n    },\n\n    manuallyHideTip: function (tooltipModel, ecModel, api, payload) {\n        var tooltipContent = this._tooltipContent;\n\n        if (!this._alwaysShowContent && this._tooltipModel) {\n            tooltipContent.hideLater(this._tooltipModel.get('hideDelay'));\n        }\n\n        this._lastX = this._lastY = null;\n\n        if (payload.from !== this.uid) {\n            this._hide(makeDispatchAction$1(payload, api));\n        }\n    },\n\n    // Be compatible with previous design, that is, when tooltip.type is 'axis' and\n    // dispatchAction 'showTip' with seriesIndex and dataIndex will trigger axis pointer\n    // and tooltip.\n    _manuallyAxisShowTip: function (tooltipModel, ecModel, api, payload) {\n        var seriesIndex = payload.seriesIndex;\n        var dataIndex = payload.dataIndex;\n        var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo;\n\n        if (seriesIndex == null || dataIndex == null || coordSysAxesInfo == null) {\n            return;\n        }\n\n        var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n        if (!seriesModel) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var tooltipModel = buildTooltipModel([\n            data.getItemModel(dataIndex),\n            seriesModel,\n            (seriesModel.coordinateSystem || {}).model,\n            tooltipModel\n        ]);\n\n        if (tooltipModel.get('trigger') !== 'axis') {\n            return;\n        }\n\n        api.dispatchAction({\n            type: 'updateAxisPointer',\n            seriesIndex: seriesIndex,\n            dataIndex: dataIndex,\n            position: payload.position\n        });\n\n        return true;\n    },\n\n    _tryShow: function (e, dispatchAction) {\n        var el = e.target;\n        var tooltipModel = this._tooltipModel;\n\n        if (!tooltipModel) {\n            return;\n        }\n\n        // Save mouse x, mouse y. So we can try to keep showing the tip if chart is refreshed\n        this._lastX = e.offsetX;\n        this._lastY = e.offsetY;\n\n        var dataByCoordSys = e.dataByCoordSys;\n        if (dataByCoordSys && dataByCoordSys.length) {\n            this._showAxisTooltip(dataByCoordSys, e);\n        }\n        // Always show item tooltip if mouse is on the element with dataIndex\n        else if (el && el.dataIndex != null) {\n            this._lastDataByCoordSys = null;\n            this._showSeriesItemTooltip(e, el, dispatchAction);\n        }\n        // Tooltip provided directly. Like legend.\n        else if (el && el.tooltip) {\n            this._lastDataByCoordSys = null;\n            this._showComponentItemTooltip(e, el, dispatchAction);\n        }\n        else {\n            this._lastDataByCoordSys = null;\n            this._hide(dispatchAction);\n        }\n    },\n\n    _showOrMove: function (tooltipModel, cb) {\n        // showDelay is used in this case: tooltip.enterable is set\n        // as true. User intent to move mouse into tooltip and click\n        // something. `showDelay` makes it easyer to enter the content\n        // but tooltip do not move immediately.\n        var delay = tooltipModel.get('showDelay');\n        cb = bind(cb, this);\n        clearTimeout(this._showTimout);\n        delay > 0\n            ? (this._showTimout = setTimeout(cb, delay))\n            : cb();\n    },\n\n    _showAxisTooltip: function (dataByCoordSys, e) {\n        var ecModel = this._ecModel;\n        var globalTooltipModel = this._tooltipModel;\n        var point = [e.offsetX, e.offsetY];\n        var singleDefaultHTML = [];\n        var singleParamsList = [];\n        var singleTooltipModel = buildTooltipModel([\n            e.tooltipOption,\n            globalTooltipModel\n        ]);\n\n        var renderMode = this._renderMode;\n        var newLine = this._newLine;\n\n        var markers = {};\n\n        each$17(dataByCoordSys, function (itemCoordSys) {\n            // var coordParamList = [];\n            // var coordDefaultHTML = [];\n            // var coordTooltipModel = buildTooltipModel([\n            //     e.tooltipOption,\n            //     itemCoordSys.tooltipOption,\n            //     ecModel.getComponent(itemCoordSys.coordSysMainType, itemCoordSys.coordSysIndex),\n            //     globalTooltipModel\n            // ]);\n            // var displayMode = coordTooltipModel.get('displayMode');\n            // var paramsList = displayMode === 'single' ? singleParamsList : [];\n\n            each$17(itemCoordSys.dataByAxis, function (item) {\n                var axisModel = ecModel.getComponent(item.axisDim + 'Axis', item.axisIndex);\n                var axisValue = item.value;\n                var seriesDefaultHTML = [];\n\n                if (!axisModel || axisValue == null) {\n                    return;\n                }\n\n                var valueLabel = getValueLabel(\n                    axisValue, axisModel.axis, ecModel,\n                    item.seriesDataIndices,\n                    item.valueLabelOpt\n                );\n\n                each$1(item.seriesDataIndices, function (idxItem) {\n                    var series = ecModel.getSeriesByIndex(idxItem.seriesIndex);\n                    var dataIndex = idxItem.dataIndexInside;\n                    var dataParams = series && series.getDataParams(dataIndex);\n                    dataParams.axisDim = item.axisDim;\n                    dataParams.axisIndex = item.axisIndex;\n                    dataParams.axisType = item.axisType;\n                    dataParams.axisId = item.axisId;\n                    dataParams.axisValue = getAxisRawValue(axisModel.axis, axisValue);\n                    dataParams.axisValueLabel = valueLabel;\n\n                    if (dataParams) {\n                        singleParamsList.push(dataParams);\n                        var seriesTooltip = series.formatTooltip(dataIndex, true, null, renderMode);\n\n                        var html;\n                        if (isObject$1(seriesTooltip)) {\n                            html = seriesTooltip.html;\n                            var newMarkers = seriesTooltip.markers;\n                            merge(markers, newMarkers);\n                        }\n                        else {\n                            html = seriesTooltip;\n                        }\n                        seriesDefaultHTML.push(html);\n                    }\n                });\n\n                // Default tooltip content\n                // FIXME\n                // (1) shold be the first data which has name?\n                // (2) themeRiver, firstDataIndex is array, and first line is unnecessary.\n                var firstLine = valueLabel;\n                if (renderMode !== 'html') {\n                    singleDefaultHTML.push(seriesDefaultHTML.join(newLine));\n                }\n                else {\n                    singleDefaultHTML.push(\n                        (firstLine ? encodeHTML(firstLine) + newLine : '')\n                        + seriesDefaultHTML.join(newLine)\n                    );\n                }\n            });\n        }, this);\n\n        // In most case, the second axis is shown upper than the first one.\n        singleDefaultHTML.reverse();\n        singleDefaultHTML = singleDefaultHTML.join(this._newLine + this._newLine);\n\n        var positionExpr = e.position;\n        this._showOrMove(singleTooltipModel, function () {\n            if (this._updateContentNotChangedOnAxis(dataByCoordSys)) {\n                this._updatePosition(\n                    singleTooltipModel,\n                    positionExpr,\n                    point[0], point[1],\n                    this._tooltipContent,\n                    singleParamsList\n                );\n            }\n            else {\n                this._showTooltipContent(\n                    singleTooltipModel, singleDefaultHTML, singleParamsList, Math.random(),\n                    point[0], point[1], positionExpr, undefined, markers\n                );\n            }\n        });\n\n        // Do not trigger events here, because this branch only be entered\n        // from dispatchAction.\n    },\n\n    _showSeriesItemTooltip: function (e, el, dispatchAction) {\n        var ecModel = this._ecModel;\n        // Use dataModel in element if possible\n        // Used when mouseover on a element like markPoint or edge\n        // In which case, the data is not main data in series.\n        var seriesIndex = el.seriesIndex;\n        var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n\n        // For example, graph link.\n        var dataModel = el.dataModel || seriesModel;\n        var dataIndex = el.dataIndex;\n        var dataType = el.dataType;\n        var data = dataModel.getData();\n\n        var tooltipModel = buildTooltipModel([\n            data.getItemModel(dataIndex),\n            dataModel,\n            seriesModel && (seriesModel.coordinateSystem || {}).model,\n            this._tooltipModel\n        ]);\n\n        var tooltipTrigger = tooltipModel.get('trigger');\n        if (tooltipTrigger != null && tooltipTrigger !== 'item') {\n            return;\n        }\n\n        var params = dataModel.getDataParams(dataIndex, dataType);\n        var seriesTooltip = dataModel.formatTooltip(dataIndex, false, dataType, this._renderMode);\n        var defaultHtml;\n        var markers;\n        if (isObject$1(seriesTooltip)) {\n            defaultHtml = seriesTooltip.html;\n            markers = seriesTooltip.markers;\n        }\n        else {\n            defaultHtml = seriesTooltip;\n            markers = null;\n        }\n\n        var asyncTicket = 'item_' + dataModel.name + '_' + dataIndex;\n\n        this._showOrMove(tooltipModel, function () {\n            this._showTooltipContent(\n                tooltipModel, defaultHtml, params, asyncTicket,\n                e.offsetX, e.offsetY, e.position, e.target, markers\n            );\n        });\n\n        // FIXME\n        // duplicated showtip if manuallyShowTip is called from dispatchAction.\n        dispatchAction({\n            type: 'showTip',\n            dataIndexInside: dataIndex,\n            dataIndex: data.getRawIndex(dataIndex),\n            seriesIndex: seriesIndex,\n            from: this.uid\n        });\n    },\n\n    _showComponentItemTooltip: function (e, el, dispatchAction) {\n        var tooltipOpt = el.tooltip;\n        if (typeof tooltipOpt === 'string') {\n            var content = tooltipOpt;\n            tooltipOpt = {\n                content: content,\n                // Fixed formatter\n                formatter: content\n            };\n        }\n        var subTooltipModel = new Model(tooltipOpt, this._tooltipModel, this._ecModel);\n        var defaultHtml = subTooltipModel.get('content');\n        var asyncTicket = Math.random();\n\n        // Do not check whether `trigger` is 'none' here, because `trigger`\n        // only works on cooridinate system. In fact, we have not found case\n        // that requires setting `trigger` nothing on component yet.\n\n        this._showOrMove(subTooltipModel, function () {\n            this._showTooltipContent(\n                subTooltipModel, defaultHtml, subTooltipModel.get('formatterParams') || {},\n                asyncTicket, e.offsetX, e.offsetY, e.position, el\n            );\n        });\n\n        // If not dispatch showTip, tip may be hide triggered by axis.\n        dispatchAction({\n            type: 'showTip',\n            from: this.uid\n        });\n    },\n\n    _showTooltipContent: function (\n        tooltipModel, defaultHtml, params, asyncTicket, x, y, positionExpr, el, markers\n    ) {\n        // Reset ticket\n        this._ticket = '';\n\n        if (!tooltipModel.get('showContent') || !tooltipModel.get('show')) {\n            return;\n        }\n\n        var tooltipContent = this._tooltipContent;\n\n        var formatter = tooltipModel.get('formatter');\n        positionExpr = positionExpr || tooltipModel.get('position');\n        var html = defaultHtml;\n\n        if (formatter && typeof formatter === 'string') {\n            html = formatTpl(formatter, params, true);\n        }\n        else if (typeof formatter === 'function') {\n            var callback = bind$3(function (cbTicket, html) {\n                if (cbTicket === this._ticket) {\n                    tooltipContent.setContent(html, markers, tooltipModel);\n                    this._updatePosition(\n                        tooltipModel, positionExpr, x, y, tooltipContent, params, el\n                    );\n                }\n            }, this);\n            this._ticket = asyncTicket;\n            html = formatter(params, asyncTicket, callback);\n        }\n\n        tooltipContent.setContent(html, markers, tooltipModel);\n        tooltipContent.show(tooltipModel);\n\n        this._updatePosition(\n            tooltipModel, positionExpr, x, y, tooltipContent, params, el\n        );\n    },\n\n    /**\n     * @param  {string|Function|Array.<number>|Object} positionExpr\n     * @param  {number} x Mouse x\n     * @param  {number} y Mouse y\n     * @param  {boolean} confine Whether confine tooltip content in view rect.\n     * @param  {Object|<Array.<Object>} params\n     * @param  {module:zrender/Element} el target element\n     * @param  {module:echarts/ExtensionAPI} api\n     * @return {Array.<number>}\n     */\n    _updatePosition: function (tooltipModel, positionExpr, x, y, content, params, el) {\n        var viewWidth = this._api.getWidth();\n        var viewHeight = this._api.getHeight();\n        positionExpr = positionExpr || tooltipModel.get('position');\n\n        var contentSize = content.getSize();\n        var align = tooltipModel.get('align');\n        var vAlign = tooltipModel.get('verticalAlign');\n        var rect = el && el.getBoundingRect().clone();\n        el && rect.applyTransform(el.transform);\n\n        if (typeof positionExpr === 'function') {\n            // Callback of position can be an array or a string specify the position\n            positionExpr = positionExpr([x, y], params, content.el, rect, {\n                viewSize: [viewWidth, viewHeight],\n                contentSize: contentSize.slice()\n            });\n        }\n\n        if (isArray(positionExpr)) {\n            x = parsePercent$2(positionExpr[0], viewWidth);\n            y = parsePercent$2(positionExpr[1], viewHeight);\n        }\n        else if (isObject$1(positionExpr)) {\n            positionExpr.width = contentSize[0];\n            positionExpr.height = contentSize[1];\n            var layoutRect = getLayoutRect(\n                positionExpr, {width: viewWidth, height: viewHeight}\n            );\n            x = layoutRect.x;\n            y = layoutRect.y;\n            align = null;\n            // When positionExpr is left/top/right/bottom,\n            // align and verticalAlign will not work.\n            vAlign = null;\n        }\n        // Specify tooltip position by string 'top' 'bottom' 'left' 'right' around graphic element\n        else if (typeof positionExpr === 'string' && el) {\n            var pos = calcTooltipPosition(\n                positionExpr, rect, contentSize\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n        else {\n            var pos = refixTooltipPosition(\n                x, y, content, viewWidth, viewHeight, align ? null : 20, vAlign ? null : 20\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n\n        align && (x -= isCenterAlign(align) ? contentSize[0] / 2 : align === 'right' ? contentSize[0] : 0);\n        vAlign && (y -= isCenterAlign(vAlign) ? contentSize[1] / 2 : vAlign === 'bottom' ? contentSize[1] : 0);\n\n        if (tooltipModel.get('confine')) {\n            var pos = confineTooltipPosition(\n                x, y, content, viewWidth, viewHeight\n            );\n            x = pos[0];\n            y = pos[1];\n        }\n\n        content.moveTo(x, y);\n    },\n\n    // FIXME\n    // Should we remove this but leave this to user?\n    _updateContentNotChangedOnAxis: function (dataByCoordSys) {\n        var lastCoordSys = this._lastDataByCoordSys;\n        var contentNotChanged = !!lastCoordSys\n            && lastCoordSys.length === dataByCoordSys.length;\n\n        contentNotChanged && each$17(lastCoordSys, function (lastItemCoordSys, indexCoordSys) {\n            var lastDataByAxis = lastItemCoordSys.dataByAxis || {};\n            var thisItemCoordSys = dataByCoordSys[indexCoordSys] || {};\n            var thisDataByAxis = thisItemCoordSys.dataByAxis || [];\n            contentNotChanged &= lastDataByAxis.length === thisDataByAxis.length;\n\n            contentNotChanged && each$17(lastDataByAxis, function (lastItem, indexAxis) {\n                var thisItem = thisDataByAxis[indexAxis] || {};\n                var lastIndices = lastItem.seriesDataIndices || [];\n                var newIndices = thisItem.seriesDataIndices || [];\n\n                contentNotChanged\n                    &= lastItem.value === thisItem.value\n                    && lastItem.axisType === thisItem.axisType\n                    && lastItem.axisId === thisItem.axisId\n                    && lastIndices.length === newIndices.length;\n\n                contentNotChanged && each$17(lastIndices, function (lastIdxItem, j) {\n                    var newIdxItem = newIndices[j];\n                    contentNotChanged\n                        &= lastIdxItem.seriesIndex === newIdxItem.seriesIndex\n                        && lastIdxItem.dataIndex === newIdxItem.dataIndex;\n                });\n            });\n        });\n\n        this._lastDataByCoordSys = dataByCoordSys;\n\n        return !!contentNotChanged;\n    },\n\n    _hide: function (dispatchAction) {\n        // Do not directly hideLater here, because this behavior may be prevented\n        // in dispatchAction when showTip is dispatched.\n\n        // FIXME\n        // duplicated hideTip if manuallyHideTip is called from dispatchAction.\n        this._lastDataByCoordSys = null;\n        dispatchAction({\n            type: 'hideTip',\n            from: this.uid\n        });\n    },\n\n    dispose: function (ecModel, api) {\n        if (env$1.node) {\n            return;\n        }\n        this._tooltipContent.hide();\n        unregister('itemTooltip', api);\n    }\n});\n\n\n/**\n * @param {Array.<Object|module:echarts/model/Model>} modelCascade\n * From top to bottom. (the last one should be globalTooltipModel);\n */\nfunction buildTooltipModel(modelCascade) {\n    var resultModel = modelCascade.pop();\n    while (modelCascade.length) {\n        var tooltipOpt = modelCascade.pop();\n        if (tooltipOpt) {\n            if (Model.isInstance(tooltipOpt)) {\n                tooltipOpt = tooltipOpt.get('tooltip', true);\n            }\n            // In each data item tooltip can be simply write:\n            // {\n            //  value: 10,\n            //  tooltip: 'Something you need to know'\n            // }\n            if (typeof tooltipOpt === 'string') {\n                tooltipOpt = {formatter: tooltipOpt};\n            }\n            resultModel = new Model(tooltipOpt, resultModel, resultModel.ecModel);\n        }\n    }\n    return resultModel;\n}\n\nfunction makeDispatchAction$1(payload, api) {\n    return payload.dispatchAction || bind(api.dispatchAction, api);\n}\n\nfunction refixTooltipPosition(x, y, content, viewWidth, viewHeight, gapH, gapV) {\n    var size = content.getOuterSize();\n    var width = size.width;\n    var height = size.height;\n\n    if (gapH != null) {\n        if (x + width + gapH > viewWidth) {\n            x -= width + gapH;\n        }\n        else {\n            x += gapH;\n        }\n    }\n    if (gapV != null) {\n        if (y + height + gapV > viewHeight) {\n            y -= height + gapV;\n        }\n        else {\n            y += gapV;\n        }\n    }\n    return [x, y];\n}\n\nfunction confineTooltipPosition(x, y, content, viewWidth, viewHeight) {\n    var size = content.getOuterSize();\n    var width = size.width;\n    var height = size.height;\n\n    x = Math.min(x + width, viewWidth) - width;\n    y = Math.min(y + height, viewHeight) - height;\n    x = Math.max(x, 0);\n    y = Math.max(y, 0);\n\n    return [x, y];\n}\n\nfunction calcTooltipPosition(position, rect, contentSize) {\n    var domWidth = contentSize[0];\n    var domHeight = contentSize[1];\n    var gap = 5;\n    var x = 0;\n    var y = 0;\n    var rectWidth = rect.width;\n    var rectHeight = rect.height;\n    switch (position) {\n        case 'inside':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n            break;\n        case 'top':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y - domHeight - gap;\n            break;\n        case 'bottom':\n            x = rect.x + rectWidth / 2 - domWidth / 2;\n            y = rect.y + rectHeight + gap;\n            break;\n        case 'left':\n            x = rect.x - domWidth - gap;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n            break;\n        case 'right':\n            x = rect.x + rectWidth + gap;\n            y = rect.y + rectHeight / 2 - domHeight / 2;\n    }\n    return [x, y];\n}\n\nfunction isCenterAlign(align) {\n    return align === 'center' || align === 'middle';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME Better way to pack data in graphic element\n\n/**\n * @action\n * @property {string} type\n * @property {number} seriesIndex\n * @property {number} dataIndex\n * @property {number} [x]\n * @property {number} [y]\n */\nregisterAction(\n    {\n        type: 'showTip',\n        event: 'showTip',\n        update: 'tooltip:manuallyShowTip'\n    },\n    // noop\n    function () {}\n);\n\nregisterAction(\n    {\n        type: 'hideTip',\n        event: 'hideTip',\n        update: 'tooltip:manuallyHideTip'\n    },\n    // noop\n    function () {}\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction getSeriesStackId$1(seriesModel) {\n    return seriesModel.get('stack')\n        || '__ec_stack_' + seriesModel.seriesIndex;\n}\n\nfunction getAxisKey$1(axis) {\n    return axis.dim;\n}\n\n/**\n * @param {string} seriesType\n * @param {module:echarts/model/Global} ecModel\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction barLayoutPolar(seriesType, ecModel, api) {\n\n    // FIXME\n    // Revert becuase it brings bar progressive bug.\n    // The complete fix will be added in the next version.\n    var width = api.getWidth();\n    var height = api.getHeight();\n\n    var lastStackCoords = {};\n\n    var barWidthAndOffset = calRadialBar(\n        filter(\n            ecModel.getSeriesByType(seriesType),\n            function (seriesModel) {\n                return !ecModel.isSeriesFiltered(seriesModel)\n                    && seriesModel.coordinateSystem\n                    && seriesModel.coordinateSystem.type === 'polar';\n            }\n        )\n    );\n\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        // Check series coordinate, do layout for polar only\n        if (seriesModel.coordinateSystem.type !== 'polar') {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var polar = seriesModel.coordinateSystem;\n        var baseAxis = polar.getBaseAxis();\n\n        var stackId = getSeriesStackId$1(seriesModel);\n        var columnLayoutInfo\n            = barWidthAndOffset[getAxisKey$1(baseAxis)][stackId];\n        var columnOffset = columnLayoutInfo.offset;\n        var columnWidth = columnLayoutInfo.width;\n        var valueAxis = polar.getOtherAxis(baseAxis);\n\n        var cx = seriesModel.coordinateSystem.cx;\n        var cy = seriesModel.coordinateSystem.cy;\n\n        var barMinHeight = seriesModel.get('barMinHeight') || 0;\n        var barMinAngle = seriesModel.get('barMinAngle') || 0;\n\n        lastStackCoords[stackId] = lastStackCoords[stackId] || [];\n\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var stacked = isDimensionStacked(data, valueDim /*, baseDim*/);\n\n        var valueAxisStart = valueAxis.getExtent()[0];\n\n        for (var idx = 0, len = data.count(); idx < len; idx++) {\n            var value = data.get(valueDim, idx);\n            var baseValue = data.get(baseDim, idx);\n\n            if (isNaN(value)) {\n                continue;\n            }\n\n            var sign = value >= 0 ? 'p' : 'n';\n            var baseCoord = valueAxisStart;\n\n            // Because of the barMinHeight, we can not use the value in\n            // stackResultDimension directly.\n            // Only ordinal axis can be stacked.\n            if (stacked) {\n                if (!lastStackCoords[stackId][baseValue]) {\n                    lastStackCoords[stackId][baseValue] = {\n                        p: valueAxisStart, // Positive stack\n                        n: valueAxisStart  // Negative stack\n                    };\n                }\n                // Should also consider #4243\n                baseCoord = lastStackCoords[stackId][baseValue][sign];\n            }\n\n            var r0;\n            var r;\n            var startAngle;\n            var endAngle;\n\n            // radial sector\n            if (valueAxis.dim === 'radius') {\n                var radiusSpan = valueAxis.dataToRadius(value) - valueAxisStart;\n                var angle = baseAxis.dataToAngle(baseValue);\n\n                if (Math.abs(radiusSpan) < barMinHeight) {\n                    radiusSpan = (radiusSpan < 0 ? -1 : 1) * barMinHeight;\n                }\n\n                r0 = baseCoord;\n                r = baseCoord + radiusSpan;\n                startAngle = angle - columnOffset;\n                endAngle = startAngle - columnWidth;\n\n                stacked && (lastStackCoords[stackId][baseValue][sign] = r);\n            }\n            // tangential sector\n            else {\n                // angleAxis must be clamped.\n                var angleSpan = valueAxis.dataToAngle(value, true) - valueAxisStart;\n                var radius = baseAxis.dataToRadius(baseValue);\n\n                if (Math.abs(angleSpan) < barMinAngle) {\n                    angleSpan = (angleSpan < 0 ? -1 : 1) * barMinAngle;\n                }\n\n                r0 = radius + columnOffset;\n                r = r0 + columnWidth;\n                startAngle = baseCoord;\n                endAngle = baseCoord + angleSpan;\n\n                // if the previous stack is at the end of the ring,\n                // add a round to differentiate it from origin\n                // var extent = angleAxis.getExtent();\n                // var stackCoord = angle;\n                // if (stackCoord === extent[0] && value > 0) {\n                //     stackCoord = extent[1];\n                // }\n                // else if (stackCoord === extent[1] && value < 0) {\n                //     stackCoord = extent[0];\n                // }\n                stacked && (lastStackCoords[stackId][baseValue][sign] = endAngle);\n            }\n\n            data.setItemLayout(idx, {\n                cx: cx,\n                cy: cy,\n                r0: r0,\n                r: r,\n                // Consider that positive angle is anti-clockwise,\n                // while positive radian of sector is clockwise\n                startAngle: -startAngle * Math.PI / 180,\n                endAngle: -endAngle * Math.PI / 180\n            });\n\n        }\n\n    }, this);\n\n}\n\n/**\n * Calculate bar width and offset for radial bar charts\n */\nfunction calRadialBar(barSeries, api) {\n    // Columns info on each category axis. Key is polar name\n    var columnsMap = {};\n\n    each$1(barSeries, function (seriesModel, idx) {\n        var data = seriesModel.getData();\n        var polar = seriesModel.coordinateSystem;\n\n        var baseAxis = polar.getBaseAxis();\n\n        var axisExtent = baseAxis.getExtent();\n        var bandWidth = baseAxis.type === 'category'\n            ? baseAxis.getBandWidth()\n            : (Math.abs(axisExtent[1] - axisExtent[0]) / data.count());\n\n        var columnsOnAxis = columnsMap[getAxisKey$1(baseAxis)] || {\n            bandWidth: bandWidth,\n            remainedWidth: bandWidth,\n            autoWidthCount: 0,\n            categoryGap: '20%',\n            gap: '30%',\n            stacks: {}\n        };\n        var stacks = columnsOnAxis.stacks;\n        columnsMap[getAxisKey$1(baseAxis)] = columnsOnAxis;\n\n        var stackId = getSeriesStackId$1(seriesModel);\n\n        if (!stacks[stackId]) {\n            columnsOnAxis.autoWidthCount++;\n        }\n        stacks[stackId] = stacks[stackId] || {\n            width: 0,\n            maxWidth: 0\n        };\n\n        var barWidth = parsePercent$1(\n            seriesModel.get('barWidth'),\n            bandWidth\n        );\n        var barMaxWidth = parsePercent$1(\n            seriesModel.get('barMaxWidth'),\n            bandWidth\n        );\n        var barGap = seriesModel.get('barGap');\n        var barCategoryGap = seriesModel.get('barCategoryGap');\n\n        if (barWidth && !stacks[stackId].width) {\n            barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);\n            stacks[stackId].width = barWidth;\n            columnsOnAxis.remainedWidth -= barWidth;\n        }\n\n        barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);\n        (barGap != null) && (columnsOnAxis.gap = barGap);\n        (barCategoryGap != null) && (columnsOnAxis.categoryGap = barCategoryGap);\n    });\n\n\n    var result = {};\n\n    each$1(columnsMap, function (columnsOnAxis, coordSysName) {\n\n        result[coordSysName] = {};\n\n        var stacks = columnsOnAxis.stacks;\n        var bandWidth = columnsOnAxis.bandWidth;\n        var categoryGap = parsePercent$1(columnsOnAxis.categoryGap, bandWidth);\n        var barGapPercent = parsePercent$1(columnsOnAxis.gap, 1);\n\n        var remainedWidth = columnsOnAxis.remainedWidth;\n        var autoWidthCount = columnsOnAxis.autoWidthCount;\n        var autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        // Find if any auto calculated bar exceeded maxBarWidth\n        each$1(stacks, function (column, stack) {\n            var maxWidth = column.maxWidth;\n            if (maxWidth && maxWidth < autoWidth) {\n                maxWidth = Math.min(maxWidth, remainedWidth);\n                if (column.width) {\n                    maxWidth = Math.min(maxWidth, column.width);\n                }\n                remainedWidth -= maxWidth;\n                column.width = maxWidth;\n                autoWidthCount--;\n            }\n        });\n\n        // Recalculate width again\n        autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        var widthSum = 0;\n        var lastColumn;\n        each$1(stacks, function (column, idx) {\n            if (!column.width) {\n                column.width = autoWidth;\n            }\n            lastColumn = column;\n            widthSum += column.width * (1 + barGapPercent);\n        });\n        if (lastColumn) {\n            widthSum -= lastColumn.width * barGapPercent;\n        }\n\n        var offset = -widthSum / 2;\n        each$1(stacks, function (column, stackId) {\n            result[coordSysName][stackId] = result[coordSysName][stackId] || {\n                offset: offset,\n                width: column.width\n            };\n\n            offset += column.width * (1 + barGapPercent);\n        });\n    });\n\n    return result;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction RadiusAxis(scale, radiusExtent) {\n\n    Axis.call(this, 'radius', scale, radiusExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = 'category';\n}\n\nRadiusAxis.prototype = {\n\n    constructor: RadiusAxis,\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.polar.pointToData(point, clamp)[this.dim === 'radius' ? 0 : 1];\n    },\n\n    dataToRadius: Axis.prototype.dataToCoord,\n\n    radiusToData: Axis.prototype.coordToData\n};\n\ninherits(RadiusAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$12 = makeInner();\n\nfunction AngleAxis(scale, angleExtent) {\n\n    angleExtent = angleExtent || [0, 360];\n\n    Axis.call(this, 'angle', scale, angleExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = 'category';\n}\n\nAngleAxis.prototype = {\n\n    constructor: AngleAxis,\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.polar.pointToData(point, clamp)[this.dim === 'radius' ? 0 : 1];\n    },\n\n    dataToAngle: Axis.prototype.dataToCoord,\n\n    angleToData: Axis.prototype.coordToData,\n\n    /**\n     * Only be called in category axis.\n     * Angle axis uses text height to decide interval\n     *\n     * @override\n     * @return {number} Auto interval for cateogry axis tick and label\n     */\n    calculateCategoryInterval: function () {\n        var axis = this;\n        var labelModel = axis.getLabelModel();\n\n        var ordinalScale = axis.scale;\n        var ordinalExtent = ordinalScale.getExtent();\n        // Providing this method is for optimization:\n        // avoid generating a long array by `getTicks`\n        // in large category data case.\n        var tickCount = ordinalScale.count();\n\n        if (ordinalExtent[1] - ordinalExtent[0] < 1) {\n            return 0;\n        }\n\n        var tickValue = ordinalExtent[0];\n        var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue);\n        var unitH = Math.abs(unitSpan);\n\n        // Not precise, just use height as text width\n        // and each distance from axis line yet.\n        var rect = getBoundingRect(\n            tickValue, labelModel.getFont(), 'center', 'top'\n        );\n        var maxH = Math.max(rect.height, 7);\n\n        var dh = maxH / unitH;\n        // 0/0 is NaN, 1/0 is Infinity.\n        isNaN(dh) && (dh = Infinity);\n        var interval = Math.max(0, Math.floor(dh));\n\n        var cache = inner$12(axis.model);\n        var lastAutoInterval = cache.lastAutoInterval;\n        var lastTickCount = cache.lastTickCount;\n\n        // Use cache to keep interval stable while moving zoom window,\n        // otherwise the calculated interval might jitter when the zoom\n        // window size is close to the interval-changing size.\n        if (lastAutoInterval != null\n            && lastTickCount != null\n            && Math.abs(lastAutoInterval - interval) <= 1\n            && Math.abs(lastTickCount - tickCount) <= 1\n            // Always choose the bigger one, otherwise the critical\n            // point is not the same when zooming in or zooming out.\n            && lastAutoInterval > interval\n        ) {\n            interval = lastAutoInterval;\n        }\n        // Only update cache if cache not used, otherwise the\n        // changing of interval is too insensitive.\n        else {\n            cache.lastTickCount = tickCount;\n            cache.lastAutoInterval = interval;\n        }\n\n        return interval;\n    }\n};\n\ninherits(AngleAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/coord/polar/Polar\n */\n\n/**\n * @alias {module:echarts/coord/polar/Polar}\n * @constructor\n * @param {string} name\n */\nvar Polar = function (name) {\n\n    /**\n     * @type {string}\n     */\n    this.name = name || '';\n\n    /**\n     * x of polar center\n     * @type {number}\n     */\n    this.cx = 0;\n\n    /**\n     * y of polar center\n     * @type {number}\n     */\n    this.cy = 0;\n\n    /**\n     * @type {module:echarts/coord/polar/RadiusAxis}\n     * @private\n     */\n    this._radiusAxis = new RadiusAxis();\n\n    /**\n     * @type {module:echarts/coord/polar/AngleAxis}\n     * @private\n     */\n    this._angleAxis = new AngleAxis();\n\n    this._radiusAxis.polar = this._angleAxis.polar = this;\n};\n\nPolar.prototype = {\n\n    type: 'polar',\n\n    axisPointerEnabled: true,\n\n    constructor: Polar,\n\n    /**\n     * @param {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['radius', 'angle'],\n\n    /**\n     * @type {module:echarts/coord/PolarModel}\n     */\n    model: null,\n\n    /**\n     * If contain coord\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    containPoint: function (point) {\n        var coord = this.pointToCoord(point);\n        return this._radiusAxis.contain(coord[0])\n            && this._angleAxis.contain(coord[1]);\n    },\n\n    /**\n     * If contain data\n     * @param {Array.<number>} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this._radiusAxis.containData(data[0])\n            && this._angleAxis.containData(data[1]);\n    },\n\n    /**\n     * @param {string} dim\n     * @return {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}\n     */\n    getAxis: function (dim) {\n        return this['_' + dim + 'Axis'];\n    },\n\n    /**\n     * @return {Array.<module:echarts/coord/Axis>}\n     */\n    getAxes: function () {\n        return [this._radiusAxis, this._angleAxis];\n    },\n\n    /**\n     * Get axes by type of scale\n     * @param {string} scaleType\n     * @return {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}\n     */\n    getAxesByScale: function (scaleType) {\n        var axes = [];\n        var angleAxis = this._angleAxis;\n        var radiusAxis = this._radiusAxis;\n        angleAxis.scale.type === scaleType && axes.push(angleAxis);\n        radiusAxis.scale.type === scaleType && axes.push(radiusAxis);\n\n        return axes;\n    },\n\n    /**\n     * @return {module:echarts/coord/polar/AngleAxis}\n     */\n    getAngleAxis: function () {\n        return this._angleAxis;\n    },\n\n    /**\n     * @return {module:echarts/coord/polar/RadiusAxis}\n     */\n    getRadiusAxis: function () {\n        return this._radiusAxis;\n    },\n\n    /**\n     * @param {module:echarts/coord/polar/Axis}\n     * @return {module:echarts/coord/polar/Axis}\n     */\n    getOtherAxis: function (axis) {\n        var angleAxis = this._angleAxis;\n        return axis === angleAxis ? this._radiusAxis : angleAxis;\n    },\n\n    /**\n     * Base axis will be used on stacking.\n     *\n     * @return {module:echarts/coord/polar/Axis}\n     */\n    getBaseAxis: function () {\n        return this.getAxesByScale('ordinal')[0]\n            || this.getAxesByScale('time')[0]\n            || this.getAngleAxis();\n    },\n\n    /**\n     * @param {string} [dim] 'radius' or 'angle' or 'auto' or null/undefined\n     * @return {Object} {baseAxes: [], otherAxes: []}\n     */\n    getTooltipAxes: function (dim) {\n        var baseAxis = (dim != null && dim !== 'auto')\n            ? this.getAxis(dim) : this.getBaseAxis();\n        return {\n            baseAxes: [baseAxis],\n            otherAxes: [this.getOtherAxis(baseAxis)]\n        };\n    },\n\n    /**\n     * Convert a single data item to (x, y) point.\n     * Parameter data is an array which the first element is radius and the second is angle\n     * @param {Array.<number>} data\n     * @param {boolean} [clamp=false]\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, clamp) {\n        return this.coordToPoint([\n            this._radiusAxis.dataToRadius(data[0], clamp),\n            this._angleAxis.dataToAngle(data[1], clamp)\n        ]);\n    },\n\n    /**\n     * Convert a (x, y) point to data\n     * @param {Array.<number>} point\n     * @param {boolean} [clamp=false]\n     * @return {Array.<number>}\n     */\n    pointToData: function (point, clamp) {\n        var coord = this.pointToCoord(point);\n        return [\n            this._radiusAxis.radiusToData(coord[0], clamp),\n            this._angleAxis.angleToData(coord[1], clamp)\n        ];\n    },\n\n    /**\n     * Convert a (x, y) point to (radius, angle) coord\n     * @param {Array.<number>} point\n     * @return {Array.<number>}\n     */\n    pointToCoord: function (point) {\n        var dx = point[0] - this.cx;\n        var dy = point[1] - this.cy;\n        var angleAxis = this.getAngleAxis();\n        var extent = angleAxis.getExtent();\n        var minAngle = Math.min(extent[0], extent[1]);\n        var maxAngle = Math.max(extent[0], extent[1]);\n        // Fix fixed extent in polarCreator\n        // FIXME\n        angleAxis.inverse\n            ? (minAngle = maxAngle - 360)\n            : (maxAngle = minAngle + 360);\n\n        var radius = Math.sqrt(dx * dx + dy * dy);\n        dx /= radius;\n        dy /= radius;\n\n        var radian = Math.atan2(-dy, dx) / Math.PI * 180;\n\n        // move to angleExtent\n        var dir = radian < minAngle ? 1 : -1;\n        while (radian < minAngle || radian > maxAngle) {\n            radian += dir * 360;\n        }\n\n        return [radius, radian];\n    },\n\n    /**\n     * Convert a (radius, angle) coord to (x, y) point\n     * @param {Array.<number>} coord\n     * @return {Array.<number>}\n     */\n    coordToPoint: function (coord) {\n        var radius = coord[0];\n        var radian = coord[1] / 180 * Math.PI;\n        var x = Math.cos(radian) * radius + this.cx;\n        // Inverse the y\n        var y = -Math.sin(radian) * radius + this.cy;\n\n        return [x, y];\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PolarAxisModel = ComponentModel.extend({\n\n    type: 'polarAxis',\n\n    /**\n     * @type {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}\n     */\n    axis: null,\n\n    /**\n     * @override\n     */\n    getCoordSysModel: function () {\n        return this.ecModel.queryComponents({\n            mainType: 'polar',\n            index: this.option.polarIndex,\n            id: this.option.polarId\n        })[0];\n    }\n\n});\n\nmerge(PolarAxisModel.prototype, axisModelCommonMixin);\n\nvar polarAxisDefaultExtendedOption = {\n    angle: {\n        // polarIndex: 0,\n        // polarId: '',\n\n        startAngle: 90,\n\n        clockwise: true,\n\n        splitNumber: 12,\n\n        axisLabel: {\n            rotate: false\n        }\n    },\n    radius: {\n        // polarIndex: 0,\n        // polarId: '',\n\n        splitNumber: 5\n    }\n};\n\nfunction getAxisType$3(axisDim, option) {\n    // Default axis with data is category axis\n    return option.type || (option.data ? 'category' : 'value');\n}\n\naxisModelCreator('angle', PolarAxisModel, getAxisType$3, polarAxisDefaultExtendedOption.angle);\naxisModelCreator('radius', PolarAxisModel, getAxisType$3, polarAxisDefaultExtendedOption.radius);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentModel({\n\n    type: 'polar',\n\n    dependencies: ['polarAxis', 'angleAxis'],\n\n    /**\n     * @type {module:echarts/coord/polar/Polar}\n     */\n    coordinateSystem: null,\n\n    /**\n     * @param {string} axisType\n     * @return {module:echarts/coord/polar/AxisModel}\n     */\n    findAxisModel: function (axisType) {\n        var foundAxisModel;\n        var ecModel = this.ecModel;\n\n        ecModel.eachComponent(axisType, function (axisModel) {\n            if (axisModel.getCoordSysModel() === this) {\n                foundAxisModel = axisModel;\n            }\n        }, this);\n        return foundAxisModel;\n    },\n\n    defaultOption: {\n\n        zlevel: 0,\n\n        z: 0,\n\n        center: ['50%', '50%'],\n\n        radius: '80%'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Axis scale\n\n/**\n * Resize method bound to the polar\n * @param {module:echarts/coord/polar/PolarModel} polarModel\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction resizePolar(polar, polarModel, api) {\n    var center = polarModel.get('center');\n    var width = api.getWidth();\n    var height = api.getHeight();\n\n    polar.cx = parsePercent$1(center[0], width);\n    polar.cy = parsePercent$1(center[1], height);\n\n    var radiusAxis = polar.getRadiusAxis();\n    var size = Math.min(width, height) / 2;\n    var radius = parsePercent$1(polarModel.get('radius'), size);\n    radiusAxis.inverse\n        ? radiusAxis.setExtent(radius, 0)\n        : radiusAxis.setExtent(0, radius);\n}\n\n/**\n * Update polar\n */\nfunction updatePolarScale(ecModel, api) {\n    var polar = this;\n    var angleAxis = polar.getAngleAxis();\n    var radiusAxis = polar.getRadiusAxis();\n    // Reset scale\n    angleAxis.scale.setExtent(Infinity, -Infinity);\n    radiusAxis.scale.setExtent(Infinity, -Infinity);\n\n    ecModel.eachSeries(function (seriesModel) {\n        if (seriesModel.coordinateSystem === polar) {\n            var data = seriesModel.getData();\n            each$1(data.mapDimension('radius', true), function (dim) {\n                radiusAxis.scale.unionExtentFromData(\n                    data, getStackedDimension(data, dim)\n                );\n            });\n            each$1(data.mapDimension('angle', true), function (dim) {\n                angleAxis.scale.unionExtentFromData(\n                    data, getStackedDimension(data, dim)\n                );\n            });\n        }\n    });\n\n    niceScaleExtent(angleAxis.scale, angleAxis.model);\n    niceScaleExtent(radiusAxis.scale, radiusAxis.model);\n\n    // Fix extent of category angle axis\n    if (angleAxis.type === 'category' && !angleAxis.onBand) {\n        var extent = angleAxis.getExtent();\n        var diff = 360 / angleAxis.scale.count();\n        angleAxis.inverse ? (extent[1] += diff) : (extent[1] -= diff);\n        angleAxis.setExtent(extent[0], extent[1]);\n    }\n}\n\n/**\n * Set common axis properties\n * @param {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}\n * @param {module:echarts/coord/polar/AxisModel}\n * @inner\n */\nfunction setAxis(axis, axisModel) {\n    axis.type = axisModel.get('type');\n    axis.scale = createScaleByModel(axisModel);\n    axis.onBand = axisModel.get('boundaryGap') && axis.type === 'category';\n    axis.inverse = axisModel.get('inverse');\n\n    if (axisModel.mainType === 'angleAxis') {\n        axis.inverse ^= axisModel.get('clockwise');\n        var startAngle = axisModel.get('startAngle');\n        axis.setExtent(startAngle, startAngle + (axis.inverse ? -360 : 360));\n    }\n\n    // Inject axis instance\n    axisModel.axis = axis;\n    axis.model = axisModel;\n}\n\n\nvar polarCreator = {\n\n    dimensions: Polar.prototype.dimensions,\n\n    create: function (ecModel, api) {\n        var polarList = [];\n        ecModel.eachComponent('polar', function (polarModel, idx) {\n            var polar = new Polar(idx);\n            // Inject resize and update method\n            polar.update = updatePolarScale;\n\n            var radiusAxis = polar.getRadiusAxis();\n            var angleAxis = polar.getAngleAxis();\n\n            var radiusAxisModel = polarModel.findAxisModel('radiusAxis');\n            var angleAxisModel = polarModel.findAxisModel('angleAxis');\n\n            setAxis(radiusAxis, radiusAxisModel);\n            setAxis(angleAxis, angleAxisModel);\n\n            resizePolar(polar, polarModel, api);\n\n            polarList.push(polar);\n\n            polarModel.coordinateSystem = polar;\n            polar.model = polarModel;\n        });\n        // Inject coordinateSystem to series\n        ecModel.eachSeries(function (seriesModel) {\n            if (seriesModel.get('coordinateSystem') === 'polar') {\n                var polarModel = ecModel.queryComponents({\n                    mainType: 'polar',\n                    index: seriesModel.get('polarIndex'),\n                    id: seriesModel.get('polarId')\n                })[0];\n\n                if (__DEV__) {\n                    if (!polarModel) {\n                        throw new Error(\n                            'Polar \"' + retrieve(\n                                seriesModel.get('polarIndex'),\n                                seriesModel.get('polarId'),\n                                0\n                            ) + '\" not found'\n                        );\n                    }\n                }\n                seriesModel.coordinateSystem = polarModel.coordinateSystem;\n            }\n        });\n\n        return polarList;\n    }\n};\n\nCoordinateSystemManager.register('polar', polarCreator);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar elementList$1 = ['axisLine', 'axisLabel', 'axisTick', 'splitLine', 'splitArea'];\n\nfunction getAxisLineShape(polar, rExtent, angle) {\n    rExtent[1] > rExtent[0] && (rExtent = rExtent.slice().reverse());\n    var start = polar.coordToPoint([rExtent[0], angle]);\n    var end = polar.coordToPoint([rExtent[1], angle]);\n\n    return {\n        x1: start[0],\n        y1: start[1],\n        x2: end[0],\n        y2: end[1]\n    };\n}\n\nfunction getRadiusIdx(polar) {\n    var radiusAxis = polar.getRadiusAxis();\n    return radiusAxis.inverse ? 0 : 1;\n}\n\n// Remove the last tick which will overlap the first tick\nfunction fixAngleOverlap(list) {\n    var firstItem = list[0];\n    var lastItem = list[list.length - 1];\n    if (firstItem\n        && lastItem\n        && Math.abs(Math.abs(firstItem.coord - lastItem.coord) - 360) < 1e-4\n    ) {\n        list.pop();\n    }\n}\n\nAxisView.extend({\n\n    type: 'angleAxis',\n\n    axisPointerClass: 'PolarAxisPointer',\n\n    render: function (angleAxisModel, ecModel) {\n        this.group.removeAll();\n        if (!angleAxisModel.get('show')) {\n            return;\n        }\n\n        var angleAxis = angleAxisModel.axis;\n        var polar = angleAxis.polar;\n        var radiusExtent = polar.getRadiusAxis().getExtent();\n\n        var ticksAngles = angleAxis.getTicksCoords();\n        var labels = map(angleAxis.getViewLabels(), function (labelItem) {\n            var labelItem = clone(labelItem);\n            labelItem.coord = angleAxis.dataToCoord(labelItem.tickValue);\n            return labelItem;\n        });\n\n        fixAngleOverlap(labels);\n        fixAngleOverlap(ticksAngles);\n\n        each$1(elementList$1, function (name) {\n            if (angleAxisModel.get(name + '.show')\n                && (!angleAxis.scale.isBlank() || name === 'axisLine')\n            ) {\n                this['_' + name](angleAxisModel, polar, ticksAngles, radiusExtent, labels);\n            }\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _axisLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) {\n        var lineStyleModel = angleAxisModel.getModel('axisLine.lineStyle');\n\n        var circle = new Circle({\n            shape: {\n                cx: polar.cx,\n                cy: polar.cy,\n                r: radiusExtent[getRadiusIdx(polar)]\n            },\n            style: lineStyleModel.getLineStyle(),\n            z2: 1,\n            silent: true\n        });\n        circle.style.fill = null;\n\n        this.group.add(circle);\n    },\n\n    /**\n     * @private\n     */\n    _axisTick: function (angleAxisModel, polar, ticksAngles, radiusExtent) {\n        var tickModel = angleAxisModel.getModel('axisTick');\n\n        var tickLen = (tickModel.get('inside') ? -1 : 1) * tickModel.get('length');\n        var radius = radiusExtent[getRadiusIdx(polar)];\n\n        var lines = map(ticksAngles, function (tickAngleItem) {\n            return new Line({\n                shape: getAxisLineShape(polar, [radius, radius + tickLen], tickAngleItem.coord)\n            });\n        });\n        this.group.add(mergePath(\n            lines, {\n                style: defaults(\n                    tickModel.getModel('lineStyle').getLineStyle(),\n                    {\n                        stroke: angleAxisModel.get('axisLine.lineStyle.color')\n                    }\n                )\n            }\n        ));\n    },\n\n    /**\n     * @private\n     */\n    _axisLabel: function (angleAxisModel, polar, ticksAngles, radiusExtent, labels) {\n        var rawCategoryData = angleAxisModel.getCategories(true);\n\n        var commonLabelModel = angleAxisModel.getModel('axisLabel');\n\n        var labelMargin = commonLabelModel.get('margin');\n\n        // Use length of ticksAngles because it may remove the last tick to avoid overlapping\n        each$1(labels, function (labelItem, idx) {\n            var labelModel = commonLabelModel;\n            var tickValue = labelItem.tickValue;\n\n            var r = radiusExtent[getRadiusIdx(polar)];\n            var p = polar.coordToPoint([r + labelMargin, labelItem.coord]);\n            var cx = polar.cx;\n            var cy = polar.cy;\n\n            var labelTextAlign = Math.abs(p[0] - cx) / r < 0.3\n                ? 'center' : (p[0] > cx ? 'left' : 'right');\n            var labelTextVerticalAlign = Math.abs(p[1] - cy) / r < 0.3\n                ? 'middle' : (p[1] > cy ? 'top' : 'bottom');\n\n            if (rawCategoryData && rawCategoryData[tickValue] && rawCategoryData[tickValue].textStyle) {\n                labelModel = new Model(\n                    rawCategoryData[tickValue].textStyle, commonLabelModel, commonLabelModel.ecModel\n                );\n            }\n\n            var textEl = new Text({silent: true});\n            this.group.add(textEl);\n            setTextStyle(textEl.style, labelModel, {\n                x: p[0],\n                y: p[1],\n                textFill: labelModel.getTextColor() || angleAxisModel.get('axisLine.lineStyle.color'),\n                text: labelItem.formattedLabel,\n                textAlign: labelTextAlign,\n                textVerticalAlign: labelTextVerticalAlign\n            });\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _splitLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) {\n        var splitLineModel = angleAxisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineColors = lineStyleModel.get('color');\n        var lineCount = 0;\n\n        lineColors = lineColors instanceof Array ? lineColors : [lineColors];\n\n        var splitLines = [];\n\n        for (var i = 0; i < ticksAngles.length; i++) {\n            var colorIndex = (lineCount++) % lineColors.length;\n            splitLines[colorIndex] = splitLines[colorIndex] || [];\n            splitLines[colorIndex].push(new Line({\n                shape: getAxisLineShape(polar, radiusExtent, ticksAngles[i].coord)\n            }));\n        }\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        for (var i = 0; i < splitLines.length; i++) {\n            this.group.add(mergePath(splitLines[i], {\n                style: defaults({\n                    stroke: lineColors[i % lineColors.length]\n                }, lineStyleModel.getLineStyle()),\n                silent: true,\n                z: angleAxisModel.get('z')\n            }));\n        }\n    },\n\n    /**\n     * @private\n     */\n    _splitArea: function (angleAxisModel, polar, ticksAngles, radiusExtent) {\n        if (!ticksAngles.length) {\n            return;\n        }\n\n        var splitAreaModel = angleAxisModel.getModel('splitArea');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n        var areaColors = areaStyleModel.get('color');\n        var lineCount = 0;\n\n        areaColors = areaColors instanceof Array ? areaColors : [areaColors];\n\n        var splitAreas = [];\n\n        var RADIAN = Math.PI / 180;\n        var prevAngle = -ticksAngles[0].coord * RADIAN;\n        var r0 = Math.min(radiusExtent[0], radiusExtent[1]);\n        var r1 = Math.max(radiusExtent[0], radiusExtent[1]);\n\n        var clockwise = angleAxisModel.get('clockwise');\n\n        for (var i = 1; i < ticksAngles.length; i++) {\n            var colorIndex = (lineCount++) % areaColors.length;\n            splitAreas[colorIndex] = splitAreas[colorIndex] || [];\n            splitAreas[colorIndex].push(new Sector({\n                shape: {\n                    cx: polar.cx,\n                    cy: polar.cy,\n                    r0: r0,\n                    r: r1,\n                    startAngle: prevAngle,\n                    endAngle: -ticksAngles[i].coord * RADIAN,\n                    clockwise: clockwise\n                },\n                silent: true\n            }));\n            prevAngle = -ticksAngles[i].coord * RADIAN;\n        }\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        for (var i = 0; i < splitAreas.length; i++) {\n            this.group.add(mergePath(splitAreas[i], {\n                style: defaults({\n                    fill: areaColors[i % areaColors.length]\n                }, areaStyleModel.getAreaStyle()),\n                silent: true\n            }));\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar axisBuilderAttrs$3 = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\nvar selfBuilderAttrs$1 = [\n    'splitLine', 'splitArea'\n];\n\nAxisView.extend({\n\n    type: 'radiusAxis',\n\n    axisPointerClass: 'PolarAxisPointer',\n\n    render: function (radiusAxisModel, ecModel) {\n        this.group.removeAll();\n        if (!radiusAxisModel.get('show')) {\n            return;\n        }\n        var radiusAxis = radiusAxisModel.axis;\n        var polar = radiusAxis.polar;\n        var angleAxis = polar.getAngleAxis();\n        var ticksCoords = radiusAxis.getTicksCoords();\n        var axisAngle = angleAxis.getExtent()[0];\n        var radiusExtent = radiusAxis.getExtent();\n\n        var layout = layoutAxis(polar, radiusAxisModel, axisAngle);\n        var axisBuilder = new AxisBuilder(radiusAxisModel, layout);\n        each$1(axisBuilderAttrs$3, axisBuilder.add, axisBuilder);\n        this.group.add(axisBuilder.getGroup());\n\n        each$1(selfBuilderAttrs$1, function (name) {\n            if (radiusAxisModel.get(name + '.show') && !radiusAxis.scale.isBlank()) {\n                this['_' + name](radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords);\n            }\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _splitLine: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) {\n        var splitLineModel = radiusAxisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineColors = lineStyleModel.get('color');\n        var lineCount = 0;\n\n        lineColors = lineColors instanceof Array ? lineColors : [lineColors];\n\n        var splitLines = [];\n\n        for (var i = 0; i < ticksCoords.length; i++) {\n            var colorIndex = (lineCount++) % lineColors.length;\n            splitLines[colorIndex] = splitLines[colorIndex] || [];\n            splitLines[colorIndex].push(new Circle({\n                shape: {\n                    cx: polar.cx,\n                    cy: polar.cy,\n                    r: ticksCoords[i].coord\n                },\n                silent: true\n            }));\n        }\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        for (var i = 0; i < splitLines.length; i++) {\n            this.group.add(mergePath(splitLines[i], {\n                style: defaults({\n                    stroke: lineColors[i % lineColors.length],\n                    fill: null\n                }, lineStyleModel.getLineStyle()),\n                silent: true\n            }));\n        }\n    },\n\n    /**\n     * @private\n     */\n    _splitArea: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) {\n        if (!ticksCoords.length) {\n            return;\n        }\n\n        var splitAreaModel = radiusAxisModel.getModel('splitArea');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n        var areaColors = areaStyleModel.get('color');\n        var lineCount = 0;\n\n        areaColors = areaColors instanceof Array ? areaColors : [areaColors];\n\n        var splitAreas = [];\n\n        var prevRadius = ticksCoords[0].coord;\n        for (var i = 1; i < ticksCoords.length; i++) {\n            var colorIndex = (lineCount++) % areaColors.length;\n            splitAreas[colorIndex] = splitAreas[colorIndex] || [];\n            splitAreas[colorIndex].push(new Sector({\n                shape: {\n                    cx: polar.cx,\n                    cy: polar.cy,\n                    r0: prevRadius,\n                    r: ticksCoords[i].coord,\n                    startAngle: 0,\n                    endAngle: Math.PI * 2\n                },\n                silent: true\n            }));\n            prevRadius = ticksCoords[i].coord;\n        }\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        for (var i = 0; i < splitAreas.length; i++) {\n            this.group.add(mergePath(splitAreas[i], {\n                style: defaults({\n                    fill: areaColors[i % areaColors.length]\n                }, areaStyleModel.getAreaStyle()),\n                silent: true\n            }));\n        }\n    }\n});\n\n/**\n * @inner\n */\nfunction layoutAxis(polar, radiusAxisModel, axisAngle) {\n    return {\n        position: [polar.cx, polar.cy],\n        rotation: axisAngle / 180 * Math.PI,\n        labelDirection: -1,\n        tickDirection: -1,\n        nameDirection: 1,\n        labelRotate: radiusAxisModel.getModel('axisLabel').get('rotate'),\n        // Over splitLine and splitArea\n        z2: 1\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PolarAxisPointer = BaseAxisPointer.extend({\n\n    /**\n     * @override\n     */\n    makeElOption: function (elOption, value, axisModel, axisPointerModel, api) {\n        var axis = axisModel.axis;\n\n        if (axis.dim === 'angle') {\n            this.animationThreshold = Math.PI / 18;\n        }\n\n        var polar = axis.polar;\n        var otherAxis = polar.getOtherAxis(axis);\n        var otherExtent = otherAxis.getExtent();\n\n        var coordValue;\n        coordValue = axis['dataTo' + capitalFirst(axis.dim)](value);\n\n        var axisPointerType = axisPointerModel.get('type');\n        if (axisPointerType && axisPointerType !== 'none') {\n            var elStyle = buildElStyle(axisPointerModel);\n            var pointerOption = pointerShapeBuilder$2[axisPointerType](\n                axis, polar, coordValue, otherExtent, elStyle\n            );\n            pointerOption.style = elStyle;\n            elOption.graphicKey = pointerOption.type;\n            elOption.pointer = pointerOption;\n        }\n\n        var labelMargin = axisPointerModel.get('label.margin');\n        var labelPos = getLabelPosition(value, axisModel, axisPointerModel, polar, labelMargin);\n        buildLabelElOption(elOption, axisModel, axisPointerModel, api, labelPos);\n    }\n\n    // Do not support handle, utill any user requires it.\n\n});\n\nfunction getLabelPosition(value, axisModel, axisPointerModel, polar, labelMargin) {\n    var axis = axisModel.axis;\n    var coord = axis.dataToCoord(value);\n    var axisAngle = polar.getAngleAxis().getExtent()[0];\n    axisAngle = axisAngle / 180 * Math.PI;\n    var radiusExtent = polar.getRadiusAxis().getExtent();\n    var position;\n    var align;\n    var verticalAlign;\n\n    if (axis.dim === 'radius') {\n        var transform = create$1();\n        rotate(transform, transform, axisAngle);\n        translate(transform, transform, [polar.cx, polar.cy]);\n        position = applyTransform$1([coord, -labelMargin], transform);\n\n        var labelRotation = axisModel.getModel('axisLabel').get('rotate') || 0;\n        var labelLayout = AxisBuilder.innerTextLayout(\n            axisAngle, labelRotation * Math.PI / 180, -1\n        );\n        align = labelLayout.textAlign;\n        verticalAlign = labelLayout.textVerticalAlign;\n    }\n    else { // angle axis\n        var r = radiusExtent[1];\n        position = polar.coordToPoint([r + labelMargin, coord]);\n        var cx = polar.cx;\n        var cy = polar.cy;\n        align = Math.abs(position[0] - cx) / r < 0.3\n            ? 'center' : (position[0] > cx ? 'left' : 'right');\n        verticalAlign = Math.abs(position[1] - cy) / r < 0.3\n            ? 'middle' : (position[1] > cy ? 'top' : 'bottom');\n    }\n\n    return {\n        position: position,\n        align: align,\n        verticalAlign: verticalAlign\n    };\n}\n\n\nvar pointerShapeBuilder$2 = {\n\n    line: function (axis, polar, coordValue, otherExtent, elStyle) {\n        return axis.dim === 'angle'\n            ? {\n                type: 'Line',\n                shape: makeLineShape(\n                    polar.coordToPoint([otherExtent[0], coordValue]),\n                    polar.coordToPoint([otherExtent[1], coordValue])\n                )\n            }\n            : {\n                type: 'Circle',\n                shape: {\n                    cx: polar.cx,\n                    cy: polar.cy,\n                    r: coordValue\n                }\n            };\n    },\n\n    shadow: function (axis, polar, coordValue, otherExtent, elStyle) {\n        var bandWidth = Math.max(1, axis.getBandWidth());\n        var radian = Math.PI / 180;\n\n        return axis.dim === 'angle'\n            ? {\n                type: 'Sector',\n                shape: makeSectorShape(\n                    polar.cx, polar.cy,\n                    otherExtent[0], otherExtent[1],\n                    // In ECharts y is negative if angle is positive\n                    (-coordValue - bandWidth / 2) * radian,\n                    (-coordValue + bandWidth / 2) * radian\n                )\n            }\n            : {\n                type: 'Sector',\n                shape: makeSectorShape(\n                    polar.cx, polar.cy,\n                    coordValue - bandWidth / 2,\n                    coordValue + bandWidth / 2,\n                    0, Math.PI * 2\n                )\n            };\n    }\n};\n\nAxisView.registerAxisPointerClass('PolarAxisPointer', PolarAxisPointer);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// For reducing size of echarts.min, barLayoutPolar is required by polar.\nregisterLayout(curry(barLayoutPolar, 'bar'));\n\n// Polar view\nextendComponentView({\n    type: 'polar'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar GeoModel = ComponentModel.extend({\n\n    type: 'geo',\n\n    /**\n     * @type {module:echarts/coord/geo/Geo}\n     */\n    coordinateSystem: null,\n\n    layoutMode: 'box',\n\n    init: function (option) {\n        ComponentModel.prototype.init.apply(this, arguments);\n\n        // Default label emphasis `show`\n        defaultEmphasis(option, 'label', ['show']);\n    },\n\n    optionUpdated: function () {\n        var option = this.option;\n        var self = this;\n\n        option.regions = geoCreator.getFilledRegions(option.regions, option.map, option.nameMap);\n\n        this._optionModelMap = reduce(option.regions || [], function (optionModelMap, regionOpt) {\n            if (regionOpt.name) {\n                optionModelMap.set(regionOpt.name, new Model(regionOpt, self));\n            }\n            return optionModelMap;\n        }, createHashMap());\n\n        this.updateSelectedMap(option.regions);\n    },\n\n    defaultOption: {\n\n        zlevel: 0,\n\n        z: 0,\n\n        show: true,\n\n        left: 'center',\n\n        top: 'center',\n\n\n        // width:,\n        // height:,\n        // right\n        // bottom\n\n        // Aspect is width / height. Inited to be geoJson bbox aspect\n        // This parameter is used for scale this aspect\n        // If svg used, aspectScale is 1 by default.\n        // aspectScale: 0.75,\n        aspectScale: null,\n\n        ///// Layout with center and size\n        // If you wan't to put map in a fixed size box with right aspect ratio\n        // This two properties may more conveninet\n        // layoutCenter: [50%, 50%]\n        // layoutSize: 100\n\n        silent: false,\n\n        // Map type\n        map: '',\n\n        // Define left-top, right-bottom coords to control view\n        // For example, [ [180, 90], [-180, -90] ]\n        boundingCoords: null,\n\n        // Default on center of map\n        center: null,\n\n        zoom: 1,\n\n        scaleLimit: null,\n\n        // selectedMode: false\n\n        label: {\n            show: false,\n            color: '#000'\n        },\n\n        itemStyle: {\n            // color: 各异,\n            borderWidth: 0.5,\n            borderColor: '#444',\n            color: '#eee'\n        },\n\n        emphasis: {\n            label: {\n                show: true,\n                color: 'rgb(100,0,0)'\n            },\n            itemStyle: {\n                color: 'rgba(255,215,0,0.8)'\n            }\n        },\n\n        regions: []\n    },\n\n    /**\n     * Get model of region\n     * @param  {string} name\n     * @return {module:echarts/model/Model}\n     */\n    getRegionModel: function (name) {\n        return this._optionModelMap.get(name) || new Model(null, this, this.ecModel);\n    },\n\n    /**\n     * Format label\n     * @param {string} name Region name\n     * @param {string} [status='normal'] 'normal' or 'emphasis'\n     * @return {string}\n     */\n    getFormattedLabel: function (name, status) {\n        var regionModel = this.getRegionModel(name);\n        var formatter = regionModel.get('label.' + status + '.formatter');\n        var params = {\n            name: name\n        };\n        if (typeof formatter === 'function') {\n            params.status = status;\n            return formatter(params);\n        }\n        else if (typeof formatter === 'string') {\n            return formatter.replace('{a}', name != null ? name : '');\n        }\n    },\n\n    setZoom: function (zoom) {\n        this.option.zoom = zoom;\n    },\n\n    setCenter: function (center) {\n        this.option.center = center;\n    }\n});\n\nmixin(GeoModel, selectableMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentView({\n\n    type: 'geo',\n\n    init: function (ecModel, api) {\n        var mapDraw = new MapDraw(api, true);\n        this._mapDraw = mapDraw;\n\n        this.group.add(mapDraw.group);\n    },\n\n    render: function (geoModel, ecModel, api, payload) {\n        // Not render if it is an toggleSelect action from self\n        if (payload && payload.type === 'geoToggleSelect'\n            && payload.from === this.uid\n        ) {\n            return;\n        }\n\n        var mapDraw = this._mapDraw;\n        if (geoModel.get('show')) {\n            mapDraw.draw(geoModel, ecModel, api, this, payload);\n        }\n        else {\n            this._mapDraw.group.removeAll();\n        }\n\n        this.group.silent = geoModel.get('silent');\n    },\n\n    dispose: function () {\n        this._mapDraw && this._mapDraw.remove();\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction makeAction(method, actionInfo) {\n    actionInfo.update = 'updateView';\n    registerAction(actionInfo, function (payload, ecModel) {\n        var selected = {};\n\n        ecModel.eachComponent(\n            { mainType: 'geo', query: payload},\n            function (geoModel) {\n                geoModel[method](payload.name);\n                var geo = geoModel.coordinateSystem;\n                each$1(geo.regions, function (region) {\n                    selected[region.name] = geoModel.isSelected(region.name) || false;\n                });\n            }\n        );\n\n        return {\n            selected: selected,\n            name: payload.name\n        };\n    });\n}\n\nmakeAction('toggleSelected', {\n    type: 'geoToggleSelect',\n    event: 'geoselectchanged'\n});\nmakeAction('select', {\n    type: 'geoSelect',\n    event: 'geoselected'\n});\nmakeAction('unSelect', {\n    type: 'geoUnSelect',\n    event: 'geounselected'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DEFAULT_TOOLBOX_BTNS = ['rect', 'polygon', 'keep', 'clear'];\n\nvar preprocessor$1 = function (option, isNew) {\n    var brushComponents = option && option.brush;\n    if (!isArray(brushComponents)) {\n        brushComponents = brushComponents ? [brushComponents] : [];\n    }\n\n    if (!brushComponents.length) {\n        return;\n    }\n\n    var brushComponentSpecifiedBtns = [];\n\n    each$1(brushComponents, function (brushOpt) {\n        var tbs = brushOpt.hasOwnProperty('toolbox')\n            ? brushOpt.toolbox : [];\n\n        if (tbs instanceof Array) {\n            brushComponentSpecifiedBtns = brushComponentSpecifiedBtns.concat(tbs);\n        }\n    });\n\n    var toolbox = option && option.toolbox;\n\n    if (isArray(toolbox)) {\n        toolbox = toolbox[0];\n    }\n    if (!toolbox) {\n        toolbox = {feature: {}};\n        option.toolbox = [toolbox];\n    }\n\n    var toolboxFeature = (toolbox.feature || (toolbox.feature = {}));\n    var toolboxBrush = toolboxFeature.brush || (toolboxFeature.brush = {});\n    var brushTypes = toolboxBrush.type || (toolboxBrush.type = []);\n\n    brushTypes.push.apply(brushTypes, brushComponentSpecifiedBtns);\n\n    removeDuplicate(brushTypes);\n\n    if (isNew && !brushTypes.length) {\n        brushTypes.push.apply(brushTypes, DEFAULT_TOOLBOX_BTNS);\n    }\n};\n\nfunction removeDuplicate(arr) {\n    var map$$1 = {};\n    each$1(arr, function (val) {\n        map$$1[val] = 1;\n    });\n    arr.length = 0;\n    each$1(map$$1, function (flag, val) {\n        arr.push(val);\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Visual solution, for consistent option specification.\n */\n\nvar each$19 = each$1;\n\nfunction hasKeys(obj) {\n    if (obj) {\n        for (var name in obj) {\n            if (obj.hasOwnProperty(name)) {\n                return true;\n            }\n        }\n    }\n}\n\n/**\n * @param {Object} option\n * @param {Array.<string>} stateList\n * @param {Function} [supplementVisualOption]\n * @return {Object} visualMappings <state, <visualType, module:echarts/visual/VisualMapping>>\n */\nfunction createVisualMappings(option, stateList, supplementVisualOption) {\n    var visualMappings = {};\n\n    each$19(stateList, function (state) {\n        var mappings = visualMappings[state] = createMappings();\n\n        each$19(option[state], function (visualData, visualType) {\n            if (!VisualMapping.isValidType(visualType)) {\n                return;\n            }\n            var mappingOption = {\n                type: visualType,\n                visual: visualData\n            };\n            supplementVisualOption && supplementVisualOption(mappingOption, state);\n            mappings[visualType] = new VisualMapping(mappingOption);\n\n            // Prepare a alpha for opacity, for some case that opacity\n            // is not supported, such as rendering using gradient color.\n            if (visualType === 'opacity') {\n                mappingOption = clone(mappingOption);\n                mappingOption.type = 'colorAlpha';\n                mappings.__hidden.__alphaForOpacity = new VisualMapping(mappingOption);\n            }\n        });\n    });\n\n    return visualMappings;\n\n    function createMappings() {\n        var Creater = function () {};\n        // Make sure hidden fields will not be visited by\n        // object iteration (with hasOwnProperty checking).\n        Creater.prototype.__hidden = Creater.prototype;\n        var obj = new Creater();\n        return obj;\n    }\n}\n\n/**\n * @param {Object} thisOption\n * @param {Object} newOption\n * @param {Array.<string>} keys\n */\nfunction replaceVisualOption(thisOption, newOption, keys) {\n    // Visual attributes merge is not supported, otherwise it\n    // brings overcomplicated merge logic. See #2853. So if\n    // newOption has anyone of these keys, all of these keys\n    // will be reset. Otherwise, all keys remain.\n    var has;\n    each$1(keys, function (key) {\n        if (newOption.hasOwnProperty(key) && hasKeys(newOption[key])) {\n            has = true;\n        }\n    });\n    has && each$1(keys, function (key) {\n        if (newOption.hasOwnProperty(key) && hasKeys(newOption[key])) {\n            thisOption[key] = clone(newOption[key]);\n        }\n        else {\n            delete thisOption[key];\n        }\n    });\n}\n\n/**\n * @param {Array.<string>} stateList\n * @param {Object} visualMappings <state, Object.<visualType, module:echarts/visual/VisualMapping>>\n * @param {module:echarts/data/List} list\n * @param {Function} getValueState param: valueOrIndex, return: state.\n * @param {object} [scope] Scope for getValueState\n * @param {string} [dimension] Concrete dimension, if used.\n */\n// ???! handle brush?\nfunction applyVisual(stateList, visualMappings, data, getValueState, scope, dimension) {\n    var visualTypesMap = {};\n    each$1(stateList, function (state) {\n        var visualTypes = VisualMapping.prepareVisualTypes(visualMappings[state]);\n        visualTypesMap[state] = visualTypes;\n    });\n\n    var dataIndex;\n\n    function getVisual(key) {\n        return data.getItemVisual(dataIndex, key);\n    }\n\n    function setVisual(key, value) {\n        data.setItemVisual(dataIndex, key, value);\n    }\n\n    if (dimension == null) {\n        data.each(eachItem);\n    }\n    else {\n        data.each([dimension], eachItem);\n    }\n\n    function eachItem(valueOrIndex, index) {\n        dataIndex = dimension == null ? valueOrIndex : index;\n\n        var rawDataItem = data.getRawDataItem(dataIndex);\n        // Consider performance\n        if (rawDataItem && rawDataItem.visualMap === false) {\n            return;\n        }\n\n        var valueState = getValueState.call(scope, valueOrIndex);\n        var mappings = visualMappings[valueState];\n        var visualTypes = visualTypesMap[valueState];\n\n        for (var i = 0, len = visualTypes.length; i < len; i++) {\n            var type = visualTypes[i];\n            mappings[type] && mappings[type].applyVisual(\n                valueOrIndex, getVisual, setVisual\n            );\n        }\n    }\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {Array.<string>} stateList\n * @param {Object} visualMappings <state, Object.<visualType, module:echarts/visual/VisualMapping>>\n * @param {Function} getValueState param: valueOrIndex, return: state.\n * @param {number} [dim] dimension or dimension index.\n */\nfunction incrementalApplyVisual(stateList, visualMappings, getValueState, dim) {\n    var visualTypesMap = {};\n    each$1(stateList, function (state) {\n        var visualTypes = VisualMapping.prepareVisualTypes(visualMappings[state]);\n        visualTypesMap[state] = visualTypes;\n    });\n\n    function progress(params, data) {\n        if (dim != null) {\n            dim = data.getDimension(dim);\n        }\n\n        function getVisual(key) {\n            return data.getItemVisual(dataIndex, key);\n        }\n\n        function setVisual(key, value) {\n            data.setItemVisual(dataIndex, key, value);\n        }\n\n        var dataIndex;\n        while ((dataIndex = params.next()) != null) {\n            var rawDataItem = data.getRawDataItem(dataIndex);\n\n            // Consider performance\n            if (rawDataItem && rawDataItem.visualMap === false) {\n                continue;\n            }\n\n            var value = dim != null\n                ? data.get(dim, dataIndex, true)\n                : dataIndex;\n\n            var valueState = getValueState(value);\n            var mappings = visualMappings[valueState];\n            var visualTypes = visualTypesMap[valueState];\n\n            for (var i = 0, len = visualTypes.length; i < len; i++) {\n                var type = visualTypes[i];\n                mappings[type] && mappings[type].applyVisual(value, getVisual, setVisual);\n            }\n        }\n    }\n\n    return {progress: progress};\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Key of the first level is brushType: `line`, `rect`, `polygon`.\n// Key of the second level is chart element type: `point`, `rect`.\n// See moudule:echarts/component/helper/BrushController\n// function param:\n//      {Object} itemLayout fetch from data.getItemLayout(dataIndex)\n//      {Object} selectors {point: selector, rect: selector, ...}\n//      {Object} area {range: [[], [], ..], boudingRect}\n// function return:\n//      {boolean} Whether in the given brush.\nvar selector = {\n    lineX: getLineSelectors(0),\n    lineY: getLineSelectors(1),\n    rect: {\n        point: function (itemLayout, selectors, area) {\n            return itemLayout && area.boundingRect.contain(itemLayout[0], itemLayout[1]);\n        },\n        rect: function (itemLayout, selectors, area) {\n            return itemLayout && area.boundingRect.intersect(itemLayout);\n        }\n    },\n    polygon: {\n        point: function (itemLayout, selectors, area) {\n            return itemLayout\n                && area.boundingRect.contain(itemLayout[0], itemLayout[1])\n                && contain$1(area.range, itemLayout[0], itemLayout[1]);\n        },\n        rect: function (itemLayout, selectors, area) {\n            var points = area.range;\n\n            if (!itemLayout || points.length <= 1) {\n                return false;\n            }\n\n            var x = itemLayout.x;\n            var y = itemLayout.y;\n            var width = itemLayout.width;\n            var height = itemLayout.height;\n            var p = points[0];\n\n            if (contain$1(points, x, y)\n                || contain$1(points, x + width, y)\n                || contain$1(points, x, y + height)\n                || contain$1(points, x + width, y + height)\n                || BoundingRect.create(itemLayout).contain(p[0], p[1])\n                || lineIntersectPolygon(x, y, x + width, y, points)\n                || lineIntersectPolygon(x, y, x, y + height, points)\n                || lineIntersectPolygon(x + width, y, x + width, y + height, points)\n                || lineIntersectPolygon(x, y + height, x + width, y + height, points)\n            ) {\n                return true;\n            }\n        }\n    }\n};\n\nfunction getLineSelectors(xyIndex) {\n    var xy = ['x', 'y'];\n    var wh = ['width', 'height'];\n\n    return {\n        point: function (itemLayout, selectors, area) {\n            if (itemLayout) {\n                var range = area.range;\n                var p = itemLayout[xyIndex];\n                return inLineRange(p, range);\n            }\n        },\n        rect: function (itemLayout, selectors, area) {\n            if (itemLayout) {\n                var range = area.range;\n                var layoutRange = [\n                    itemLayout[xy[xyIndex]],\n                    itemLayout[xy[xyIndex]] + itemLayout[wh[xyIndex]]\n                ];\n                layoutRange[1] < layoutRange[0] && layoutRange.reverse();\n                return inLineRange(layoutRange[0], range)\n                    || inLineRange(layoutRange[1], range)\n                    || inLineRange(range[0], layoutRange)\n                    || inLineRange(range[1], layoutRange);\n            }\n        }\n    };\n}\n\nfunction inLineRange(p, range) {\n    return range[0] <= p && p <= range[1];\n}\n\nfunction lineIntersectPolygon(lx, ly, l2x, l2y, points) {\n    for (var i = 0, p2 = points[points.length - 1]; i < points.length; i++) {\n        var p = points[i];\n        if (lineIntersect(lx, ly, l2x, l2y, p[0], p[1], p2[0], p2[1])) {\n            return true;\n        }\n        p2 = p;\n    }\n}\n\n// Code from <http://blog.csdn.net/rickliuxiao/article/details/6259322> with some fix.\n// See <https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection>\nfunction lineIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y) {\n    var delta = determinant(a2x - a1x, b1x - b2x, a2y - a1y, b1y - b2y);\n    if (nearZero(delta)) { // parallel\n        return false;\n    }\n    var namenda = determinant(b1x - a1x, b1x - b2x, b1y - a1y, b1y - b2y) / delta;\n    if (namenda < 0 || namenda > 1) {\n        return false;\n    }\n    var miu = determinant(a2x - a1x, b1x - a1x, a2y - a1y, b1y - a1y) / delta;\n    if (miu < 0 || miu > 1) {\n        return false;\n    }\n    return true;\n}\n\nfunction nearZero(val) {\n    return val <= (1e-6) && val >= -(1e-6);\n}\n\nfunction determinant(v1, v2, v3, v4) {\n    return v1 * v4 - v2 * v3;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$20 = each$1;\nvar indexOf$1 = indexOf;\nvar curry$5 = curry;\n\nvar COORD_CONVERTS = ['dataToPoint', 'pointToData'];\n\n// FIXME\n// how to genarialize to more coordinate systems.\nvar INCLUDE_FINDER_MAIN_TYPES = [\n    'grid', 'xAxis', 'yAxis', 'geo', 'graph',\n    'polar', 'radiusAxis', 'angleAxis', 'bmap'\n];\n\n/**\n * [option in constructor]:\n * {\n *     Index/Id/Name of geo, xAxis, yAxis, grid: See util/model#parseFinder.\n * }\n *\n *\n * [targetInfo]:\n *\n * There can be multiple axes in a single targetInfo. Consider the case\n * of `grid` component, a targetInfo represents a grid which contains one or more\n * cartesian and one or more axes. And consider the case of parallel system,\n * which has multiple axes in a coordinate system.\n * Can be {\n *     panelId: ...,\n *     coordSys: <a representitive cartesian in grid (first cartesian by default)>,\n *     coordSyses: all cartesians.\n *     gridModel: <grid component>\n *     xAxes: correspond to coordSyses on index\n *     yAxes: correspond to coordSyses on index\n * }\n * or {\n *     panelId: ...,\n *     coordSys: <geo coord sys>\n *     coordSyses: [<geo coord sys>]\n *     geoModel: <geo component>\n * }\n *\n *\n * [panelOpt]:\n *\n * Make from targetInfo. Input to BrushController.\n * {\n *     panelId: ...,\n *     rect: ...\n * }\n *\n *\n * [area]:\n *\n * Generated by BrushController or user input.\n * {\n *     panelId: Used to locate coordInfo directly. If user inpput, no panelId.\n *     brushType: determine how to convert to/from coord('rect' or 'polygon' or 'lineX/Y').\n *     Index/Id/Name of geo, xAxis, yAxis, grid: See util/model#parseFinder.\n *     range: pixel range.\n *     coordRange: representitive coord range (the first one of coordRanges).\n *     coordRanges: <Array> coord ranges, used in multiple cartesian in one grid.\n * }\n */\n\n/**\n * @param {Object} option contains Index/Id/Name of xAxis/yAxis/geo/grid\n *        Each can be {number|Array.<number>}. like: {xAxisIndex: [3, 4]}\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} [opt]\n * @param {Array.<string>} [opt.include] include coordinate system types.\n */\nfunction BrushTargetManager(option, ecModel, opt) {\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    var targetInfoList = this._targetInfoList = [];\n    var info = {};\n    var foundCpts = parseFinder$1(ecModel, option);\n\n    each$20(targetInfoBuilders, function (builder, type) {\n        if (!opt || !opt.include || indexOf$1(opt.include, type) >= 0) {\n            builder(foundCpts, targetInfoList, info);\n        }\n    });\n}\n\nvar proto$2 = BrushTargetManager.prototype;\n\nproto$2.setOutputRanges = function (areas, ecModel) {\n    this.matchOutputRanges(areas, ecModel, function (area, coordRange, coordSys) {\n        (area.coordRanges || (area.coordRanges = [])).push(coordRange);\n        // area.coordRange is the first of area.coordRanges\n        if (!area.coordRange) {\n            area.coordRange = coordRange;\n            // In 'category' axis, coord to pixel is not reversible, so we can not\n            // rebuild range by coordRange accrately, which may bring trouble when\n            // brushing only one item. So we use __rangeOffset to rebuilding range\n            // by coordRange. And this it only used in brush component so it is no\n            // need to be adapted to coordRanges.\n            var result = coordConvert[area.brushType](0, coordSys, coordRange);\n            area.__rangeOffset = {\n                offset: diffProcessor[area.brushType](result.values, area.range, [1, 1]),\n                xyMinMax: result.xyMinMax\n            };\n        }\n    });\n};\n\nproto$2.matchOutputRanges = function (areas, ecModel, cb) {\n    each$20(areas, function (area) {\n        var targetInfo = this.findTargetInfo(area, ecModel);\n\n        if (targetInfo && targetInfo !== true) {\n            each$1(\n                targetInfo.coordSyses,\n                function (coordSys) {\n                    var result = coordConvert[area.brushType](1, coordSys, area.range);\n                    cb(area, result.values, coordSys, ecModel);\n                }\n            );\n        }\n    }, this);\n};\n\nproto$2.setInputRanges = function (areas, ecModel) {\n    each$20(areas, function (area) {\n        var targetInfo = this.findTargetInfo(area, ecModel);\n\n        if (__DEV__) {\n            assert$1(\n                !targetInfo || targetInfo === true || area.coordRange,\n                'coordRange must be specified when coord index specified.'\n            );\n            assert$1(\n                !targetInfo || targetInfo !== true || area.range,\n                'range must be specified in global brush.'\n            );\n        }\n\n        area.range = area.range || [];\n\n        // convert coordRange to global range and set panelId.\n        if (targetInfo && targetInfo !== true) {\n            area.panelId = targetInfo.panelId;\n            // (1) area.range shoule always be calculate from coordRange but does\n            // not keep its original value, for the sake of the dataZoom scenario,\n            // where area.coordRange remains unchanged but area.range may be changed.\n            // (2) Only support converting one coordRange to pixel range in brush\n            // component. So do not consider `coordRanges`.\n            // (3) About __rangeOffset, see comment above.\n            var result = coordConvert[area.brushType](0, targetInfo.coordSys, area.coordRange);\n            var rangeOffset = area.__rangeOffset;\n            area.range = rangeOffset\n                ? diffProcessor[area.brushType](\n                    result.values,\n                    rangeOffset.offset,\n                    getScales(result.xyMinMax, rangeOffset.xyMinMax)\n                )\n                : result.values;\n        }\n    }, this);\n};\n\nproto$2.makePanelOpts = function (api, getDefaultBrushType) {\n    return map(this._targetInfoList, function (targetInfo) {\n        var rect = targetInfo.getPanelRect();\n        return {\n            panelId: targetInfo.panelId,\n            defaultBrushType: getDefaultBrushType && getDefaultBrushType(targetInfo),\n            clipPath: makeRectPanelClipPath(rect),\n            isTargetByCursor: makeRectIsTargetByCursor(\n                rect, api, targetInfo.coordSysModel\n            ),\n            getLinearBrushOtherExtent: makeLinearBrushOtherExtent(rect)\n        };\n    });\n};\n\nproto$2.controlSeries = function (area, seriesModel, ecModel) {\n    // Check whether area is bound in coord, and series do not belong to that coord.\n    // If do not do this check, some brush (like lineX) will controll all axes.\n    var targetInfo = this.findTargetInfo(area, ecModel);\n    return targetInfo === true || (\n        targetInfo && indexOf$1(targetInfo.coordSyses, seriesModel.coordinateSystem) >= 0\n    );\n};\n\n/**\n * If return Object, a coord found.\n * If reutrn true, global found.\n * Otherwise nothing found.\n *\n * @param {Object} area\n * @param {Array} targetInfoList\n * @return {Object|boolean}\n */\nproto$2.findTargetInfo = function (area, ecModel) {\n    var targetInfoList = this._targetInfoList;\n    var foundCpts = parseFinder$1(ecModel, area);\n\n    for (var i = 0; i < targetInfoList.length; i++) {\n        var targetInfo = targetInfoList[i];\n        var areaPanelId = area.panelId;\n        if (areaPanelId) {\n            if (targetInfo.panelId === areaPanelId) {\n                return targetInfo;\n            }\n        }\n        else {\n            for (var i = 0; i < targetInfoMatchers.length; i++) {\n                if (targetInfoMatchers[i](foundCpts, targetInfo)) {\n                    return targetInfo;\n                }\n            }\n        }\n    }\n\n    return true;\n};\n\nfunction formatMinMax(minMax) {\n    minMax[0] > minMax[1] && minMax.reverse();\n    return minMax;\n}\n\nfunction parseFinder$1(ecModel, option) {\n    return parseFinder(\n        ecModel, option, {includeMainTypes: INCLUDE_FINDER_MAIN_TYPES}\n    );\n}\n\nvar targetInfoBuilders = {\n\n    grid: function (foundCpts, targetInfoList) {\n        var xAxisModels = foundCpts.xAxisModels;\n        var yAxisModels = foundCpts.yAxisModels;\n        var gridModels = foundCpts.gridModels;\n        // Remove duplicated.\n        var gridModelMap = createHashMap();\n        var xAxesHas = {};\n        var yAxesHas = {};\n\n        if (!xAxisModels && !yAxisModels && !gridModels) {\n            return;\n        }\n\n        each$20(xAxisModels, function (axisModel) {\n            var gridModel = axisModel.axis.grid.model;\n            gridModelMap.set(gridModel.id, gridModel);\n            xAxesHas[gridModel.id] = true;\n        });\n        each$20(yAxisModels, function (axisModel) {\n            var gridModel = axisModel.axis.grid.model;\n            gridModelMap.set(gridModel.id, gridModel);\n            yAxesHas[gridModel.id] = true;\n        });\n        each$20(gridModels, function (gridModel) {\n            gridModelMap.set(gridModel.id, gridModel);\n            xAxesHas[gridModel.id] = true;\n            yAxesHas[gridModel.id] = true;\n        });\n\n        gridModelMap.each(function (gridModel) {\n            var grid = gridModel.coordinateSystem;\n            var cartesians = [];\n\n            each$20(grid.getCartesians(), function (cartesian, index) {\n                if (indexOf$1(xAxisModels, cartesian.getAxis('x').model) >= 0\n                    || indexOf$1(yAxisModels, cartesian.getAxis('y').model) >= 0\n                ) {\n                    cartesians.push(cartesian);\n                }\n            });\n            targetInfoList.push({\n                panelId: 'grid--' + gridModel.id,\n                gridModel: gridModel,\n                coordSysModel: gridModel,\n                // Use the first one as the representitive coordSys.\n                coordSys: cartesians[0],\n                coordSyses: cartesians,\n                getPanelRect: panelRectBuilder.grid,\n                xAxisDeclared: xAxesHas[gridModel.id],\n                yAxisDeclared: yAxesHas[gridModel.id]\n            });\n        });\n    },\n\n    geo: function (foundCpts, targetInfoList) {\n        each$20(foundCpts.geoModels, function (geoModel) {\n            var coordSys = geoModel.coordinateSystem;\n            targetInfoList.push({\n                panelId: 'geo--' + geoModel.id,\n                geoModel: geoModel,\n                coordSysModel: geoModel,\n                coordSys: coordSys,\n                coordSyses: [coordSys],\n                getPanelRect: panelRectBuilder.geo\n            });\n        });\n    }\n};\n\nvar targetInfoMatchers = [\n\n    // grid\n    function (foundCpts, targetInfo) {\n        var xAxisModel = foundCpts.xAxisModel;\n        var yAxisModel = foundCpts.yAxisModel;\n        var gridModel = foundCpts.gridModel;\n\n        !gridModel && xAxisModel && (gridModel = xAxisModel.axis.grid.model);\n        !gridModel && yAxisModel && (gridModel = yAxisModel.axis.grid.model);\n\n        return gridModel && gridModel === targetInfo.gridModel;\n    },\n\n    // geo\n    function (foundCpts, targetInfo) {\n        var geoModel = foundCpts.geoModel;\n        return geoModel && geoModel === targetInfo.geoModel;\n    }\n];\n\nvar panelRectBuilder = {\n\n    grid: function () {\n        // grid is not Transformable.\n        return this.coordSys.grid.getRect().clone();\n    },\n\n    geo: function () {\n        var coordSys = this.coordSys;\n        var rect = coordSys.getBoundingRect().clone();\n        // geo roam and zoom transform\n        rect.applyTransform(getTransform(coordSys));\n        return rect;\n    }\n};\n\nvar coordConvert = {\n\n    lineX: curry$5(axisConvert, 0),\n\n    lineY: curry$5(axisConvert, 1),\n\n    rect: function (to, coordSys, rangeOrCoordRange) {\n        var xminymin = coordSys[COORD_CONVERTS[to]]([rangeOrCoordRange[0][0], rangeOrCoordRange[1][0]]);\n        var xmaxymax = coordSys[COORD_CONVERTS[to]]([rangeOrCoordRange[0][1], rangeOrCoordRange[1][1]]);\n        var values = [\n            formatMinMax([xminymin[0], xmaxymax[0]]),\n            formatMinMax([xminymin[1], xmaxymax[1]])\n        ];\n        return {values: values, xyMinMax: values};\n    },\n\n    polygon: function (to, coordSys, rangeOrCoordRange) {\n        var xyMinMax = [[Infinity, -Infinity], [Infinity, -Infinity]];\n        var values = map(rangeOrCoordRange, function (item) {\n            var p = coordSys[COORD_CONVERTS[to]](item);\n            xyMinMax[0][0] = Math.min(xyMinMax[0][0], p[0]);\n            xyMinMax[1][0] = Math.min(xyMinMax[1][0], p[1]);\n            xyMinMax[0][1] = Math.max(xyMinMax[0][1], p[0]);\n            xyMinMax[1][1] = Math.max(xyMinMax[1][1], p[1]);\n            return p;\n        });\n        return {values: values, xyMinMax: xyMinMax};\n    }\n};\n\nfunction axisConvert(axisNameIndex, to, coordSys, rangeOrCoordRange) {\n    if (__DEV__) {\n        assert$1(\n            coordSys.type === 'cartesian2d',\n            'lineX/lineY brush is available only in cartesian2d.'\n        );\n    }\n\n    var axis = coordSys.getAxis(['x', 'y'][axisNameIndex]);\n    var values = formatMinMax(map([0, 1], function (i) {\n        return to\n            ? axis.coordToData(axis.toLocalCoord(rangeOrCoordRange[i]))\n            : axis.toGlobalCoord(axis.dataToCoord(rangeOrCoordRange[i]));\n    }));\n    var xyMinMax = [];\n    xyMinMax[axisNameIndex] = values;\n    xyMinMax[1 - axisNameIndex] = [NaN, NaN];\n\n    return {values: values, xyMinMax: xyMinMax};\n}\n\nvar diffProcessor = {\n    lineX: curry$5(axisDiffProcessor, 0),\n\n    lineY: curry$5(axisDiffProcessor, 1),\n\n    rect: function (values, refer, scales) {\n        return [\n            [values[0][0] - scales[0] * refer[0][0], values[0][1] - scales[0] * refer[0][1]],\n            [values[1][0] - scales[1] * refer[1][0], values[1][1] - scales[1] * refer[1][1]]\n        ];\n    },\n\n    polygon: function (values, refer, scales) {\n        return map(values, function (item, idx) {\n            return [item[0] - scales[0] * refer[idx][0], item[1] - scales[1] * refer[idx][1]];\n        });\n    }\n};\n\nfunction axisDiffProcessor(axisNameIndex, values, refer, scales) {\n    return [\n        values[0] - scales[axisNameIndex] * refer[0],\n        values[1] - scales[axisNameIndex] * refer[1]\n    ];\n}\n\n// We have to process scale caused by dataZoom manually,\n// although it might be not accurate.\nfunction getScales(xyMinMaxCurr, xyMinMaxOrigin) {\n    var sizeCurr = getSize(xyMinMaxCurr);\n    var sizeOrigin = getSize(xyMinMaxOrigin);\n    var scales = [sizeCurr[0] / sizeOrigin[0], sizeCurr[1] / sizeOrigin[1]];\n    isNaN(scales[0]) && (scales[0] = 1);\n    isNaN(scales[1]) && (scales[1] = 1);\n    return scales;\n}\n\nfunction getSize(xyMinMax) {\n    return xyMinMax\n        ? [xyMinMax[0][1] - xyMinMax[0][0], xyMinMax[1][1] - xyMinMax[1][0]]\n        : [NaN, NaN];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar STATE_LIST = ['inBrush', 'outOfBrush'];\nvar DISPATCH_METHOD = '__ecBrushSelect';\nvar DISPATCH_FLAG = '__ecInBrushSelectEvent';\nvar PRIORITY_BRUSH = PRIORITY.VISUAL.BRUSH;\n\n/**\n * Layout for visual, the priority higher than other layout, and before brush visual.\n */\nregisterLayout(PRIORITY_BRUSH, function (ecModel, api, payload) {\n    ecModel.eachComponent({mainType: 'brush'}, function (brushModel) {\n\n        payload && payload.type === 'takeGlobalCursor' && brushModel.setBrushOption(\n            payload.key === 'brush' ? payload.brushOption : {brushType: false}\n        );\n\n        var brushTargetManager = brushModel.brushTargetManager = new BrushTargetManager(brushModel.option, ecModel);\n\n        brushTargetManager.setInputRanges(brushModel.areas, ecModel);\n    });\n});\n\n/**\n * Register the visual encoding if this modules required.\n */\nregisterVisual(PRIORITY_BRUSH, function (ecModel, api, payload) {\n\n    var brushSelected = [];\n    var throttleType;\n    var throttleDelay;\n\n    ecModel.eachComponent({mainType: 'brush'}, function (brushModel, brushIndex) {\n\n        var thisBrushSelected = {\n            brushId: brushModel.id,\n            brushIndex: brushIndex,\n            brushName: brushModel.name,\n            areas: clone(brushModel.areas),\n            selected: []\n        };\n        // Every brush component exists in event params, convenient\n        // for user to find by index.\n        brushSelected.push(thisBrushSelected);\n\n        var brushOption = brushModel.option;\n        var brushLink = brushOption.brushLink;\n        var linkedSeriesMap = [];\n        var selectedDataIndexForLink = [];\n        var rangeInfoBySeries = [];\n        var hasBrushExists = 0;\n\n        if (!brushIndex) { // Only the first throttle setting works.\n            throttleType = brushOption.throttleType;\n            throttleDelay = brushOption.throttleDelay;\n        }\n\n        // Add boundingRect and selectors to range.\n        var areas = map(brushModel.areas, function (area) {\n            return bindSelector(\n                defaults(\n                    {boundingRect: boundingRectBuilders[area.brushType](area)},\n                    area\n                )\n            );\n        });\n\n        var visualMappings = createVisualMappings(\n            brushModel.option, STATE_LIST, function (mappingOption) {\n                mappingOption.mappingMethod = 'fixed';\n            }\n        );\n\n        isArray(brushLink) && each$1(brushLink, function (seriesIndex) {\n            linkedSeriesMap[seriesIndex] = 1;\n        });\n\n        function linkOthers(seriesIndex) {\n            return brushLink === 'all' || linkedSeriesMap[seriesIndex];\n        }\n\n        // If no supported brush or no brush on the series,\n        // all visuals should be in original state.\n        function brushed(rangeInfoList) {\n            return !!rangeInfoList.length;\n        }\n\n        /**\n         * Logic for each series: (If the logic has to be modified one day, do it carefully!)\n         *\n         * ( brushed ┬ && ┬hasBrushExist ┬ && linkOthers  ) => StepA: ┬record, ┬ StepB: ┬visualByRecord.\n         *   !brushed┘    ├hasBrushExist ┤                            └nothing,┘        ├visualByRecord.\n         *                └!hasBrushExist┘                                              └nothing.\n         * ( !brushed  && ┬hasBrushExist ┬ && linkOthers  ) => StepA:  nothing,  StepB: ┬visualByRecord.\n         *                └!hasBrushExist┘                                              └nothing.\n         * ( brushed ┬ &&                     !linkOthers ) => StepA:  nothing,  StepB: ┬visualByCheck.\n         *   !brushed┘                                                                  └nothing.\n         * ( !brushed  &&                     !linkOthers ) => StepA:  nothing,  StepB:  nothing.\n         */\n\n        // Step A\n        ecModel.eachSeries(function (seriesModel, seriesIndex) {\n            var rangeInfoList = rangeInfoBySeries[seriesIndex] = [];\n\n            seriesModel.subType === 'parallel'\n                ? stepAParallel(seriesModel, seriesIndex, rangeInfoList)\n                : stepAOthers(seriesModel, seriesIndex, rangeInfoList);\n        });\n\n        function stepAParallel(seriesModel, seriesIndex) {\n            var coordSys = seriesModel.coordinateSystem;\n            hasBrushExists |= coordSys.hasAxisBrushed();\n\n            linkOthers(seriesIndex) && coordSys.eachActiveState(\n                seriesModel.getData(),\n                function (activeState, dataIndex) {\n                    activeState === 'active' && (selectedDataIndexForLink[dataIndex] = 1);\n                }\n            );\n        }\n\n        function stepAOthers(seriesModel, seriesIndex, rangeInfoList) {\n            var selectorsByBrushType = getSelectorsByBrushType(seriesModel);\n            if (!selectorsByBrushType || brushModelNotControll(brushModel, seriesIndex)) {\n                return;\n            }\n\n            each$1(areas, function (area) {\n                selectorsByBrushType[area.brushType]\n                    && brushModel.brushTargetManager.controlSeries(area, seriesModel, ecModel)\n                    && rangeInfoList.push(area);\n                hasBrushExists |= brushed(rangeInfoList);\n            });\n\n            if (linkOthers(seriesIndex) && brushed(rangeInfoList)) {\n                var data = seriesModel.getData();\n                data.each(function (dataIndex) {\n                    if (checkInRange(selectorsByBrushType, rangeInfoList, data, dataIndex)) {\n                        selectedDataIndexForLink[dataIndex] = 1;\n                    }\n                });\n            }\n        }\n\n        // Step B\n        ecModel.eachSeries(function (seriesModel, seriesIndex) {\n            var seriesBrushSelected = {\n                seriesId: seriesModel.id,\n                seriesIndex: seriesIndex,\n                seriesName: seriesModel.name,\n                dataIndex: []\n            };\n            // Every series exists in event params, convenient\n            // for user to find series by seriesIndex.\n            thisBrushSelected.selected.push(seriesBrushSelected);\n\n            var selectorsByBrushType = getSelectorsByBrushType(seriesModel);\n            var rangeInfoList = rangeInfoBySeries[seriesIndex];\n\n            var data = seriesModel.getData();\n            var getValueState = linkOthers(seriesIndex)\n                ? function (dataIndex) {\n                    return selectedDataIndexForLink[dataIndex]\n                        ? (seriesBrushSelected.dataIndex.push(data.getRawIndex(dataIndex)), 'inBrush')\n                        : 'outOfBrush';\n                }\n                : function (dataIndex) {\n                    return checkInRange(selectorsByBrushType, rangeInfoList, data, dataIndex)\n                        ? (seriesBrushSelected.dataIndex.push(data.getRawIndex(dataIndex)), 'inBrush')\n                        : 'outOfBrush';\n                };\n\n            // If no supported brush or no brush, all visuals are in original state.\n            (linkOthers(seriesIndex) ? hasBrushExists : brushed(rangeInfoList))\n                && applyVisual(\n                    STATE_LIST, visualMappings, data, getValueState\n                );\n        });\n\n    });\n\n    dispatchAction(api, throttleType, throttleDelay, brushSelected, payload);\n});\n\nfunction dispatchAction(api, throttleType, throttleDelay, brushSelected, payload) {\n    // This event will not be triggered when `setOpion`, otherwise dead lock may\n    // triggered when do `setOption` in event listener, which we do not find\n    // satisfactory way to solve yet. Some considered resolutions:\n    // (a) Diff with prevoius selected data ant only trigger event when changed.\n    // But store previous data and diff precisely (i.e., not only by dataIndex, but\n    // also detect value changes in selected data) might bring complexity or fragility.\n    // (b) Use spectial param like `silent` to suppress event triggering.\n    // But such kind of volatile param may be weird in `setOption`.\n    if (!payload) {\n        return;\n    }\n\n    var zr = api.getZr();\n    if (zr[DISPATCH_FLAG]) {\n        return;\n    }\n\n    if (!zr[DISPATCH_METHOD]) {\n        zr[DISPATCH_METHOD] = doDispatch;\n    }\n\n    var fn = createOrUpdate(zr, DISPATCH_METHOD, throttleDelay, throttleType);\n\n    fn(api, brushSelected);\n}\n\nfunction doDispatch(api, brushSelected) {\n    if (!api.isDisposed()) {\n        var zr = api.getZr();\n        zr[DISPATCH_FLAG] = true;\n        api.dispatchAction({\n            type: 'brushSelect',\n            batch: brushSelected\n        });\n        zr[DISPATCH_FLAG] = false;\n    }\n}\n\nfunction checkInRange(selectorsByBrushType, rangeInfoList, data, dataIndex) {\n    for (var i = 0, len = rangeInfoList.length; i < len; i++) {\n        var area = rangeInfoList[i];\n        if (selectorsByBrushType[area.brushType](\n            dataIndex, data, area.selectors, area\n        )) {\n            return true;\n        }\n    }\n}\n\nfunction getSelectorsByBrushType(seriesModel) {\n    var brushSelector = seriesModel.brushSelector;\n    if (isString(brushSelector)) {\n        var sels = [];\n        each$1(selector, function (selectorsByElementType, brushType) {\n            sels[brushType] = function (dataIndex, data, selectors, area) {\n                var itemLayout = data.getItemLayout(dataIndex);\n                return selectorsByElementType[brushSelector](itemLayout, selectors, area);\n            };\n        });\n        return sels;\n    }\n    else if (isFunction$1(brushSelector)) {\n        var bSelector = {};\n        each$1(selector, function (sel, brushType) {\n            bSelector[brushType] = brushSelector;\n        });\n        return bSelector;\n    }\n    return brushSelector;\n}\n\nfunction brushModelNotControll(brushModel, seriesIndex) {\n    var seriesIndices = brushModel.option.seriesIndex;\n    return seriesIndices != null\n        && seriesIndices !== 'all'\n        && (\n            isArray(seriesIndices)\n            ? indexOf(seriesIndices, seriesIndex) < 0\n            : seriesIndex !== seriesIndices\n        );\n}\n\nfunction bindSelector(area) {\n    var selectors = area.selectors = {};\n    each$1(selector[area.brushType], function (selFn, elType) {\n        // Do not use function binding or curry for performance.\n        selectors[elType] = function (itemLayout) {\n            return selFn(itemLayout, selectors, area);\n        };\n    });\n    return area;\n}\n\nvar boundingRectBuilders = {\n\n    lineX: noop,\n\n    lineY: noop,\n\n    rect: function (area) {\n        return getBoundingRectFromMinMax(area.range);\n    },\n\n    polygon: function (area) {\n        var minMax;\n        var range = area.range;\n\n        for (var i = 0, len = range.length; i < len; i++) {\n            minMax = minMax || [[Infinity, -Infinity], [Infinity, -Infinity]];\n            var rg = range[i];\n            rg[0] < minMax[0][0] && (minMax[0][0] = rg[0]);\n            rg[0] > minMax[0][1] && (minMax[0][1] = rg[0]);\n            rg[1] < minMax[1][0] && (minMax[1][0] = rg[1]);\n            rg[1] > minMax[1][1] && (minMax[1][1] = rg[1]);\n        }\n\n        return minMax && getBoundingRectFromMinMax(minMax);\n    }\n};\n\nfunction getBoundingRectFromMinMax(minMax) {\n    return new BoundingRect(\n        minMax[0][0],\n        minMax[1][0],\n        minMax[0][1] - minMax[0][0],\n        minMax[1][1] - minMax[1][0]\n    );\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DEFAULT_OUT_OF_BRUSH_COLOR = ['#ddd'];\n\nvar BrushModel = extendComponentModel({\n\n    type: 'brush',\n\n    dependencies: ['geo', 'grid', 'xAxis', 'yAxis', 'parallel', 'series'],\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        // inBrush: null,\n        // outOfBrush: null,\n        toolbox: null,          // Default value see preprocessor.\n        brushLink: null,        // Series indices array, broadcast using dataIndex.\n                                // or 'all', which means all series. 'none' or null means no series.\n        seriesIndex: 'all',     // seriesIndex array, specify series controlled by this brush component.\n        geoIndex: null,         //\n        xAxisIndex: null,\n        yAxisIndex: null,\n\n        brushType: 'rect',      // Default brushType, see BrushController.\n        brushMode: 'single',    // Default brushMode, 'single' or 'multiple'\n        transformable: true,    // Default transformable.\n        brushStyle: {           // Default brushStyle\n            borderWidth: 1,\n            color: 'rgba(120,140,180,0.3)',\n            borderColor: 'rgba(120,140,180,0.8)'\n        },\n\n        throttleType: 'fixRate', // Throttle in brushSelected event. 'fixRate' or 'debounce'.\n                                 // If null, no throttle. Valid only in the first brush component\n        throttleDelay: 0,        // Unit: ms, 0 means every event will be triggered.\n\n        // FIXME\n        // 试验效果\n        removeOnClick: true,\n\n        z: 10000\n    },\n\n    /**\n     * @readOnly\n     * @type {Array.<Object>}\n     */\n    areas: [],\n\n    /**\n     * Current activated brush type.\n     * If null, brush is inactived.\n     * see module:echarts/component/helper/BrushController\n     * @readOnly\n     * @type {string}\n     */\n    brushType: null,\n\n    /**\n     * Current brush opt.\n     * see module:echarts/component/helper/BrushController\n     * @readOnly\n     * @type {Object}\n     */\n    brushOption: {},\n\n    /**\n     * @readOnly\n     * @type {Array.<Object>}\n     */\n    coordInfoList: [],\n\n    optionUpdated: function (newOption, isInit) {\n        var thisOption = this.option;\n\n        !isInit && replaceVisualOption(\n            thisOption, newOption, ['inBrush', 'outOfBrush']\n        );\n\n        var inBrush = thisOption.inBrush = thisOption.inBrush || {};\n        // Always give default visual, consider setOption at the second time.\n        thisOption.outOfBrush = thisOption.outOfBrush || {color: DEFAULT_OUT_OF_BRUSH_COLOR};\n\n        if (!inBrush.hasOwnProperty('liftZ')) {\n            // Bigger than the highlight z lift, otherwise it will\n            // be effected by the highlight z when brush.\n            inBrush.liftZ = 5;\n        }\n    },\n\n    /**\n     * If ranges is null/undefined, range state remain.\n     *\n     * @param {Array.<Object>} [ranges]\n     */\n    setAreas: function (areas) {\n        if (__DEV__) {\n            assert$1(isArray(areas));\n            each$1(areas, function (area) {\n                assert$1(area.brushType, 'Illegal areas');\n            });\n        }\n\n        // If ranges is null/undefined, range state remain.\n        // This helps user to dispatchAction({type: 'brush'}) with no areas\n        // set but just want to get the current brush select info from a `brush` event.\n        if (!areas) {\n            return;\n        }\n\n        this.areas = map(areas, function (area) {\n            return generateBrushOption(this.option, area);\n        }, this);\n    },\n\n    /**\n     * see module:echarts/component/helper/BrushController\n     * @param {Object} brushOption\n     */\n    setBrushOption: function (brushOption) {\n        this.brushOption = generateBrushOption(this.option, brushOption);\n        this.brushType = this.brushOption.brushType;\n    }\n\n});\n\nfunction generateBrushOption(option, brushOption) {\n    return merge(\n        {\n            brushType: option.brushType,\n            brushMode: option.brushMode,\n            transformable: option.transformable,\n            brushStyle: new Model(option.brushStyle).getItemStyle(),\n            removeOnClick: option.removeOnClick,\n            z: option.z\n        },\n        brushOption,\n        true\n    );\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentView({\n\n    type: 'brush',\n\n    init: function (ecModel, api) {\n\n        /**\n         * @readOnly\n         * @type {module:echarts/model/Global}\n         */\n        this.ecModel = ecModel;\n\n        /**\n         * @readOnly\n         * @type {module:echarts/ExtensionAPI}\n         */\n        this.api = api;\n\n        /**\n         * @readOnly\n         * @type {module:echarts/component/brush/BrushModel}\n         */\n        this.model;\n\n        /**\n         * @private\n         * @type {module:echarts/component/helper/BrushController}\n         */\n        (this._brushController = new BrushController(api.getZr()))\n            .on('brush', bind(this._onBrush, this))\n            .mount();\n    },\n\n    /**\n     * @override\n     */\n    render: function (brushModel) {\n        this.model = brushModel;\n        return updateController.apply(this, arguments);\n    },\n\n    /**\n     * @override\n     */\n    updateTransform: updateController,\n\n    /**\n     * @override\n     */\n    updateView: updateController,\n\n    // /**\n    //  * @override\n    //  */\n    // updateLayout: updateController,\n\n    // /**\n    //  * @override\n    //  */\n    // updateVisual: updateController,\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._brushController.dispose();\n    },\n\n    /**\n     * @private\n     */\n    _onBrush: function (areas, opt) {\n        var modelId = this.model.id;\n\n        this.model.brushTargetManager.setOutputRanges(areas, this.ecModel);\n\n        // Action is not dispatched on drag end, because the drag end\n        // emits the same params with the last drag move event, and\n        // may have some delay when using touch pad, which makes\n        // animation not smooth (when using debounce).\n        (!opt.isEnd || opt.removeOnClick) && this.api.dispatchAction({\n            type: 'brush',\n            brushId: modelId,\n            areas: clone(areas),\n            $from: modelId\n        });\n    }\n\n});\n\nfunction updateController(brushModel, ecModel, api, payload) {\n    // Do not update controller when drawing.\n    (!payload || payload.$from !== brushModel.id) && this._brushController\n        .setPanels(brushModel.brushTargetManager.makePanelOpts(api))\n        .enableBrush(brushModel.brushOption)\n        .updateCovers(brushModel.areas.slice());\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * payload: {\n *      brushIndex: number, or,\n *      brushId: string, or,\n *      brushName: string,\n *      globalRanges: Array\n * }\n */\nregisterAction(\n        {type: 'brush', event: 'brush' /*, update: 'updateView' */},\n    function (payload, ecModel) {\n        ecModel.eachComponent({mainType: 'brush', query: payload}, function (brushModel) {\n            brushModel.setAreas(payload.areas);\n        });\n    }\n);\n\n/**\n * payload: {\n *      brushComponents: [\n *          {\n *              brushId,\n *              brushIndex,\n *              brushName,\n *              series: [\n *                  {\n *                      seriesId,\n *                      seriesIndex,\n *                      seriesName,\n *                      rawIndices: [21, 34, ...]\n *                  },\n *                  ...\n *              ]\n *          },\n *          ...\n *      ]\n * }\n */\nregisterAction(\n    {type: 'brushSelect', event: 'brushSelected', update: 'none'},\n    function () {}\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar features = {};\n\nfunction register$1(name, ctor) {\n    features[name] = ctor;\n}\n\nfunction get$1(name) {\n    return features[name];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar brushLang = lang.toolbox.brush;\n\nfunction Brush(model, ecModel, api) {\n    this.model = model;\n    this.ecModel = ecModel;\n    this.api = api;\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._brushType;\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._brushMode;\n}\n\nBrush.defaultOption = {\n    show: true,\n    type: ['rect', 'polygon', 'lineX', 'lineY', 'keep', 'clear'],\n    icon: {\n        /* eslint-disable */\n        rect: 'M7.3,34.7 M0.4,10V-0.2h9.8 M89.6,10V-0.2h-9.8 M0.4,60v10.2h9.8 M89.6,60v10.2h-9.8 M12.3,22.4V10.5h13.1 M33.6,10.5h7.8 M49.1,10.5h7.8 M77.5,22.4V10.5h-13 M12.3,31.1v8.2 M77.7,31.1v8.2 M12.3,47.6v11.9h13.1 M33.6,59.5h7.6 M49.1,59.5 h7.7 M77.5,47.6v11.9h-13', // jshint ignore:line\n        polygon: 'M55.2,34.9c1.7,0,3.1,1.4,3.1,3.1s-1.4,3.1-3.1,3.1 s-3.1-1.4-3.1-3.1S53.5,34.9,55.2,34.9z M50.4,51c1.7,0,3.1,1.4,3.1,3.1c0,1.7-1.4,3.1-3.1,3.1c-1.7,0-3.1-1.4-3.1-3.1 C47.3,52.4,48.7,51,50.4,51z M55.6,37.1l1.5-7.8 M60.1,13.5l1.6-8.7l-7.8,4 M59,19l-1,5.3 M24,16.1l6.4,4.9l6.4-3.3 M48.5,11.6 l-5.9,3.1 M19.1,12.8L9.7,5.1l1.1,7.7 M13.4,29.8l1,7.3l6.6,1.6 M11.6,18.4l1,6.1 M32.8,41.9 M26.6,40.4 M27.3,40.2l6.1,1.6 M49.9,52.1l-5.6-7.6l-4.9-1.2', // jshint ignore:line\n        lineX: 'M15.2,30 M19.7,15.6V1.9H29 M34.8,1.9H40.4 M55.3,15.6V1.9H45.9 M19.7,44.4V58.1H29 M34.8,58.1H40.4 M55.3,44.4 V58.1H45.9 M12.5,20.3l-9.4,9.6l9.6,9.8 M3.1,29.9h16.5 M62.5,20.3l9.4,9.6L62.3,39.7 M71.9,29.9H55.4', // jshint ignore:line\n        lineY: 'M38.8,7.7 M52.7,12h13.2v9 M65.9,26.6V32 M52.7,46.3h13.2v-9 M24.9,12H11.8v9 M11.8,26.6V32 M24.9,46.3H11.8v-9 M48.2,5.1l-9.3-9l-9.4,9.2 M38.9-3.9V12 M48.2,53.3l-9.3,9l-9.4-9.2 M38.9,62.3V46.4', // jshint ignore:line\n        keep: 'M4,10.5V1h10.3 M20.7,1h6.1 M33,1h6.1 M55.4,10.5V1H45.2 M4,17.3v6.6 M55.6,17.3v6.6 M4,30.5V40h10.3 M20.7,40 h6.1 M33,40h6.1 M55.4,30.5V40H45.2 M21,18.9h62.9v48.6H21V18.9z', // jshint ignore:line\n        clear: 'M22,14.7l30.9,31 M52.9,14.7L22,45.7 M4.7,16.8V4.2h13.1 M26,4.2h7.8 M41.6,4.2h7.8 M70.3,16.8V4.2H57.2 M4.7,25.9v8.6 M70.3,25.9v8.6 M4.7,43.2v12.6h13.1 M26,55.8h7.8 M41.6,55.8h7.8 M70.3,43.2v12.6H57.2' // jshint ignore:line\n        /* eslint-enable */\n    },\n    // `rect`, `polygon`, `lineX`, `lineY`, `keep`, `clear`\n    title: clone(brushLang.title)\n};\n\nvar proto$3 = Brush.prototype;\n\n// proto.updateLayout = function (featureModel, ecModel, api) {\n/* eslint-disable */\nproto$3.render =\n/* eslint-enable */\nproto$3.updateView = function (featureModel, ecModel, api) {\n    var brushType;\n    var brushMode;\n    var isBrushed;\n\n    ecModel.eachComponent({mainType: 'brush'}, function (brushModel) {\n        brushType = brushModel.brushType;\n        brushMode = brushModel.brushOption.brushMode || 'single';\n        isBrushed |= brushModel.areas.length;\n    });\n    this._brushType = brushType;\n    this._brushMode = brushMode;\n\n    each$1(featureModel.get('type', true), function (type) {\n        featureModel.setIconStatus(\n            type,\n            (\n                type === 'keep'\n                ? brushMode === 'multiple'\n                : type === 'clear'\n                ? isBrushed\n                : type === brushType\n            ) ? 'emphasis' : 'normal'\n        );\n    });\n};\n\nproto$3.getIcons = function () {\n    var model = this.model;\n    var availableIcons = model.get('icon', true);\n    var icons = {};\n    each$1(model.get('type', true), function (type) {\n        if (availableIcons[type]) {\n            icons[type] = availableIcons[type];\n        }\n    });\n    return icons;\n};\n\nproto$3.onclick = function (ecModel, api, type) {\n    var brushType = this._brushType;\n    var brushMode = this._brushMode;\n\n    if (type === 'clear') {\n        // Trigger parallel action firstly\n        api.dispatchAction({\n            type: 'axisAreaSelect',\n            intervals: []\n        });\n\n        api.dispatchAction({\n            type: 'brush',\n            command: 'clear',\n            // Clear all areas of all brush components.\n            areas: []\n        });\n    }\n    else {\n        api.dispatchAction({\n            type: 'takeGlobalCursor',\n            key: 'brush',\n            brushOption: {\n                brushType: type === 'keep'\n                    ? brushType\n                    : (brushType === type ? false : type),\n                brushMode: type === 'keep'\n                    ? (brushMode === 'multiple' ? 'single' : 'multiple')\n                    : brushMode\n            }\n        });\n    }\n};\n\nregister$1('brush', Brush);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Brush component entry\n */\n\nregisterPreprocessor(preprocessor$1);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (24*60*60*1000)\nvar PROXIMATE_ONE_DAY = 86400000;\n\n/**\n * Calendar\n *\n * @constructor\n *\n * @param {Object} calendarModel calendarModel\n * @param {Object} ecModel       ecModel\n * @param {Object} api           api\n */\nfunction Calendar(calendarModel, ecModel, api) {\n    this._model = calendarModel;\n}\n\nCalendar.prototype = {\n\n    constructor: Calendar,\n\n    type: 'calendar',\n\n    dimensions: ['time', 'value'],\n\n    // Required in createListFromData\n    getDimensionsInfo: function () {\n        return [{name: 'time', type: 'time'}, 'value'];\n    },\n\n    getRangeInfo: function () {\n        return this._rangeInfo;\n    },\n\n    getModel: function () {\n        return this._model;\n    },\n\n    getRect: function () {\n        return this._rect;\n    },\n\n    getCellWidth: function () {\n        return this._sw;\n    },\n\n    getCellHeight: function () {\n        return this._sh;\n    },\n\n    getOrient: function () {\n        return this._orient;\n    },\n\n    /**\n     * getFirstDayOfWeek\n     *\n     * @example\n     *     0 : start at Sunday\n     *     1 : start at Monday\n     *\n     * @return {number}\n     */\n    getFirstDayOfWeek: function () {\n        return this._firstDayOfWeek;\n    },\n\n    /**\n     * get date info\n     *\n     * @param  {string|number} date date\n     * @return {Object}\n     * {\n     *      y: string, local full year, eg., '1940',\n     *      m: string, local month, from '01' ot '12',\n     *      d: string, local date, from '01' to '31' (if exists),\n     *      day: It is not date.getDay(). It is the location of the cell in a week, from 0 to 6,\n     *      time: timestamp,\n     *      formatedDate: string, yyyy-MM-dd,\n     *      date: original date object.\n     * }\n     */\n    getDateInfo: function (date) {\n\n        date = parseDate(date);\n\n        var y = date.getFullYear();\n\n        var m = date.getMonth() + 1;\n        m = m < 10 ? '0' + m : m;\n\n        var d = date.getDate();\n        d = d < 10 ? '0' + d : d;\n\n        var day = date.getDay();\n\n        day = Math.abs((day + 7 - this.getFirstDayOfWeek()) % 7);\n\n        return {\n            y: y,\n            m: m,\n            d: d,\n            day: day,\n            time: date.getTime(),\n            formatedDate: y + '-' + m + '-' + d,\n            date: date\n        };\n    },\n\n    getNextNDay: function (date, n) {\n        n = n || 0;\n        if (n === 0) {\n            return this.getDateInfo(date);\n        }\n\n        date = new Date(this.getDateInfo(date).time);\n        date.setDate(date.getDate() + n);\n\n        return this.getDateInfo(date);\n    },\n\n    update: function (ecModel, api) {\n\n        this._firstDayOfWeek = +this._model.getModel('dayLabel').get('firstDay');\n        this._orient = this._model.get('orient');\n        this._lineWidth = this._model.getModel('itemStyle').getItemStyle().lineWidth || 0;\n\n\n        this._rangeInfo = this._getRangeInfo(this._initRangeOption());\n        var weeks = this._rangeInfo.weeks || 1;\n        var whNames = ['width', 'height'];\n        var cellSize = this._model.get('cellSize').slice();\n        var layoutParams = this._model.getBoxLayoutParams();\n        var cellNumbers = this._orient === 'horizontal' ? [weeks, 7] : [7, weeks];\n\n        each$1([0, 1], function (idx) {\n            if (cellSizeSpecified(cellSize, idx)) {\n                layoutParams[whNames[idx]] = cellSize[idx] * cellNumbers[idx];\n            }\n        });\n\n        var whGlobal = {\n            width: api.getWidth(),\n            height: api.getHeight()\n        };\n        var calendarRect = this._rect = getLayoutRect(layoutParams, whGlobal);\n\n        each$1([0, 1], function (idx) {\n            if (!cellSizeSpecified(cellSize, idx)) {\n                cellSize[idx] = calendarRect[whNames[idx]] / cellNumbers[idx];\n            }\n        });\n\n        function cellSizeSpecified(cellSize, idx) {\n            return cellSize[idx] != null && cellSize[idx] !== 'auto';\n        }\n\n        this._sw = cellSize[0];\n        this._sh = cellSize[1];\n    },\n\n\n    /**\n     * Convert a time data(time, value) item to (x, y) point.\n     *\n     * @override\n     * @param  {Array|number} data data\n     * @param  {boolean} [clamp=true] out of range\n     * @return {Array} point\n     */\n    dataToPoint: function (data, clamp) {\n        isArray(data) && (data = data[0]);\n        clamp == null && (clamp = true);\n\n        var dayInfo = this.getDateInfo(data);\n        var range = this._rangeInfo;\n        var date = dayInfo.formatedDate;\n\n        // if not in range return [NaN, NaN]\n        if (clamp && !(\n            dayInfo.time >= range.start.time\n            && dayInfo.time < range.end.time + PROXIMATE_ONE_DAY\n        )) {\n            return [NaN, NaN];\n        }\n\n        var week = dayInfo.day;\n        var nthWeek = this._getRangeInfo([range.start.time, date]).nthWeek;\n\n        if (this._orient === 'vertical') {\n            return [\n                this._rect.x + week * this._sw + this._sw / 2,\n                this._rect.y + nthWeek * this._sh + this._sh / 2\n            ];\n\n        }\n\n        return [\n            this._rect.x + nthWeek * this._sw + this._sw / 2,\n            this._rect.y + week * this._sh + this._sh / 2\n        ];\n\n    },\n\n    /**\n     * Convert a (x, y) point to time data\n     *\n     * @override\n     * @param  {string} point point\n     * @return {string}       data\n     */\n    pointToData: function (point) {\n\n        var date = this.pointToDate(point);\n\n        return date && date.time;\n    },\n\n    /**\n     * Convert a time date item to (x, y) four point.\n     *\n     * @param  {Array} data  date[0] is date\n     * @param  {boolean} [clamp=true]  out of range\n     * @return {Object}       point\n     */\n    dataToRect: function (data, clamp) {\n        var point = this.dataToPoint(data, clamp);\n\n        return {\n            contentShape: {\n                x: point[0] - (this._sw - this._lineWidth) / 2,\n                y: point[1] - (this._sh - this._lineWidth) / 2,\n                width: this._sw - this._lineWidth,\n                height: this._sh - this._lineWidth\n            },\n\n            center: point,\n\n            tl: [\n                point[0] - this._sw / 2,\n                point[1] - this._sh / 2\n            ],\n\n            tr: [\n                point[0] + this._sw / 2,\n                point[1] - this._sh / 2\n            ],\n\n            br: [\n                point[0] + this._sw / 2,\n                point[1] + this._sh / 2\n            ],\n\n            bl: [\n                point[0] - this._sw / 2,\n                point[1] + this._sh / 2\n            ]\n\n        };\n    },\n\n    /**\n     * Convert a (x, y) point to time date\n     *\n     * @param  {Array} point point\n     * @return {Object}       date\n     */\n    pointToDate: function (point) {\n        var nthX = Math.floor((point[0] - this._rect.x) / this._sw) + 1;\n        var nthY = Math.floor((point[1] - this._rect.y) / this._sh) + 1;\n        var range = this._rangeInfo.range;\n\n        if (this._orient === 'vertical') {\n            return this._getDateByWeeksAndDay(nthY, nthX - 1, range);\n        }\n\n        return this._getDateByWeeksAndDay(nthX, nthY - 1, range);\n    },\n\n    /**\n     * @inheritDoc\n     */\n    convertToPixel: curry(doConvert$2, 'dataToPoint'),\n\n    /**\n     * @inheritDoc\n     */\n    convertFromPixel: curry(doConvert$2, 'pointToData'),\n\n    /**\n     * initRange\n     *\n     * @private\n     * @return {Array} [start, end]\n     */\n    _initRangeOption: function () {\n        var range = this._model.get('range');\n\n        var rg = range;\n\n        if (isArray(rg) && rg.length === 1) {\n            rg = rg[0];\n        }\n\n        if (/^\\d{4}$/.test(rg)) {\n            range = [rg + '-01-01', rg + '-12-31'];\n        }\n\n        if (/^\\d{4}[\\/|-]\\d{1,2}$/.test(rg)) {\n\n            var start = this.getDateInfo(rg);\n            var firstDay = start.date;\n            firstDay.setMonth(firstDay.getMonth() + 1);\n\n            var end = this.getNextNDay(firstDay, -1);\n            range = [start.formatedDate, end.formatedDate];\n        }\n\n        if (/^\\d{4}[\\/|-]\\d{1,2}[\\/|-]\\d{1,2}$/.test(rg)) {\n            range = [rg, rg];\n        }\n\n        var tmp = this._getRangeInfo(range);\n\n        if (tmp.start.time > tmp.end.time) {\n            range.reverse();\n        }\n\n        return range;\n    },\n\n    /**\n     * range info\n     *\n     * @private\n     * @param  {Array} range range ['2017-01-01', '2017-07-08']\n     *  If range[0] > range[1], they will not be reversed.\n     * @return {Object}       obj\n     */\n    _getRangeInfo: function (range) {\n        range = [\n            this.getDateInfo(range[0]),\n            this.getDateInfo(range[1])\n        ];\n\n        var reversed;\n        if (range[0].time > range[1].time) {\n            reversed = true;\n            range.reverse();\n        }\n\n        var allDay = Math.floor(range[1].time / PROXIMATE_ONE_DAY)\n            - Math.floor(range[0].time / PROXIMATE_ONE_DAY) + 1;\n\n        // Consider case:\n        // Firstly set system timezone as \"Time Zone: America/Toronto\",\n        // ```\n        // var first = new Date(1478412000000 - 3600 * 1000 * 2.5);\n        // var second = new Date(1478412000000);\n        // var allDays = Math.floor(second / ONE_DAY) - Math.floor(first / ONE_DAY) + 1;\n        // ```\n        // will get wrong result because of DST. So we should fix it.\n        var date = new Date(range[0].time);\n        var startDateNum = date.getDate();\n        var endDateNum = range[1].date.getDate();\n        date.setDate(startDateNum + allDay - 1);\n        // The bias can not over a month, so just compare date.\n        if (date.getDate() !== endDateNum) {\n            var sign = date.getTime() - range[1].time > 0 ? 1 : -1;\n            while (date.getDate() !== endDateNum && (date.getTime() - range[1].time) * sign > 0) {\n                allDay -= sign;\n                date.setDate(startDateNum + allDay - 1);\n            }\n        }\n\n        var weeks = Math.floor((allDay + range[0].day + 6) / 7);\n        var nthWeek = reversed ? -weeks + 1 : weeks - 1;\n\n        reversed && range.reverse();\n\n        return {\n            range: [range[0].formatedDate, range[1].formatedDate],\n            start: range[0],\n            end: range[1],\n            allDay: allDay,\n            weeks: weeks,\n            // From 0.\n            nthWeek: nthWeek,\n            fweek: range[0].day,\n            lweek: range[1].day\n        };\n    },\n\n    /**\n     * get date by nthWeeks and week day in range\n     *\n     * @private\n     * @param  {number} nthWeek the week\n     * @param  {number} day   the week day\n     * @param  {Array} range [d1, d2]\n     * @return {Object}\n     */\n    _getDateByWeeksAndDay: function (nthWeek, day, range) {\n        var rangeInfo = this._getRangeInfo(range);\n\n        if (nthWeek > rangeInfo.weeks\n            || (nthWeek === 0 && day < rangeInfo.fweek)\n            || (nthWeek === rangeInfo.weeks && day > rangeInfo.lweek)\n        ) {\n            return false;\n        }\n\n        var nthDay = (nthWeek - 1) * 7 - rangeInfo.fweek + day;\n        var date = new Date(rangeInfo.start.time);\n        date.setDate(rangeInfo.start.d + nthDay);\n\n        return this.getDateInfo(date);\n    }\n};\n\nCalendar.dimensions = Calendar.prototype.dimensions;\n\nCalendar.getDimensionsInfo = Calendar.prototype.getDimensionsInfo;\n\nCalendar.create = function (ecModel, api) {\n    var calendarList = [];\n\n    ecModel.eachComponent('calendar', function (calendarModel) {\n        var calendar = new Calendar(calendarModel, ecModel, api);\n        calendarList.push(calendar);\n        calendarModel.coordinateSystem = calendar;\n    });\n\n    ecModel.eachSeries(function (calendarSeries) {\n        if (calendarSeries.get('coordinateSystem') === 'calendar') {\n            // Inject coordinate system\n            calendarSeries.coordinateSystem = calendarList[calendarSeries.get('calendarIndex') || 0];\n        }\n    });\n    return calendarList;\n};\n\nfunction doConvert$2(methodName, ecModel, finder, value) {\n    var calendarModel = finder.calendarModel;\n    var seriesModel = finder.seriesModel;\n\n    var coordSys = calendarModel\n        ? calendarModel.coordinateSystem\n        : seriesModel\n        ? seriesModel.coordinateSystem\n        : null;\n\n    return coordSys === this ? coordSys[methodName](value) : null;\n}\n\nCoordinateSystemManager.register('calendar', Calendar);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar CalendarModel = ComponentModel.extend({\n\n    type: 'calendar',\n\n    /**\n     * @type {module:echarts/coord/calendar/Calendar}\n     */\n    coordinateSystem: null,\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        left: 80,\n        top: 60,\n\n        cellSize: 20,\n\n        // horizontal vertical\n        orient: 'horizontal',\n\n        // month separate line style\n        splitLine: {\n            show: true,\n            lineStyle: {\n                color: '#000',\n                width: 1,\n                type: 'solid'\n            }\n        },\n\n        // rect style  temporarily unused emphasis\n        itemStyle: {\n            color: '#fff',\n            borderWidth: 1,\n            borderColor: '#ccc'\n        },\n\n        // week text style\n        dayLabel: {\n            show: true,\n\n            // a week first day\n            firstDay: 0,\n\n            // start end\n            position: 'start',\n            margin: '50%', // 50% of cellSize\n            nameMap: 'en',\n            color: '#000'\n        },\n\n        // month text style\n        monthLabel: {\n            show: true,\n\n            // start end\n            position: 'start',\n            margin: 5,\n\n            // center or left\n            align: 'center',\n\n            // cn en []\n            nameMap: 'en',\n            formatter: null,\n            color: '#000'\n        },\n\n        // year text style\n        yearLabel: {\n            show: true,\n\n            // top bottom left right\n            position: null,\n            margin: 30,\n            formatter: null,\n            color: '#ccc',\n            fontFamily: 'sans-serif',\n            fontWeight: 'bolder',\n            fontSize: 20\n        }\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel, extraOpt) {\n        var inputPositionParams = getLayoutParams(option);\n\n        CalendarModel.superApply(this, 'init', arguments);\n\n        mergeAndNormalizeLayoutParams$1(option, inputPositionParams);\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (option, extraOpt) {\n        CalendarModel.superApply(this, 'mergeOption', arguments);\n\n        mergeAndNormalizeLayoutParams$1(this.option, option);\n    }\n});\n\nfunction mergeAndNormalizeLayoutParams$1(target, raw) {\n    // Normalize cellSize\n    var cellSize = target.cellSize;\n\n    if (!isArray(cellSize)) {\n        cellSize = target.cellSize = [cellSize, cellSize];\n    }\n    else if (cellSize.length === 1) {\n        cellSize[1] = cellSize[0];\n    }\n\n    var ignoreSize = map([0, 1], function (hvIdx) {\n        // If user have set `width` or both `left` and `right`, cellSize\n        // will be automatically set to 'auto', otherwise the default\n        // setting of cellSize will make `width` setting not work.\n        if (sizeCalculable(raw, hvIdx)) {\n            cellSize[hvIdx] = 'auto';\n        }\n        return cellSize[hvIdx] != null && cellSize[hvIdx] !== 'auto';\n    });\n\n    mergeLayoutParam(target, raw, {\n        type: 'box', ignoreSize: ignoreSize\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar MONTH_TEXT = {\n    EN: [\n        'Jan', 'Feb', 'Mar',\n        'Apr', 'May', 'Jun',\n        'Jul', 'Aug', 'Sep',\n        'Oct', 'Nov', 'Dec'\n    ],\n    CN: [\n        '一月', '二月', '三月',\n        '四月', '五月', '六月',\n        '七月', '八月', '九月',\n        '十月', '十一月', '十二月'\n    ]\n};\n\nvar WEEK_TEXT = {\n    EN: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],\n    CN: ['日', '一', '二', '三', '四', '五', '六']\n};\n\nextendComponentView({\n\n    type: 'calendar',\n\n    /**\n     * top/left line points\n     *  @private\n     */\n    _tlpoints: null,\n\n    /**\n     * bottom/right line points\n     *  @private\n     */\n    _blpoints: null,\n\n    /**\n     * first day of month\n     *  @private\n     */\n    _firstDayOfMonth: null,\n\n    /**\n     * first day point of month\n     *  @private\n     */\n    _firstDayPoints: null,\n\n    render: function (calendarModel, ecModel, api) {\n\n        var group = this.group;\n\n        group.removeAll();\n\n        var coordSys = calendarModel.coordinateSystem;\n\n        // range info\n        var rangeData = coordSys.getRangeInfo();\n        var orient = coordSys.getOrient();\n\n        this._renderDayRect(calendarModel, rangeData, group);\n\n        // _renderLines must be called prior to following function\n        this._renderLines(calendarModel, rangeData, orient, group);\n\n        this._renderYearText(calendarModel, rangeData, orient, group);\n\n        this._renderMonthText(calendarModel, orient, group);\n\n        this._renderWeekText(calendarModel, rangeData, orient, group);\n    },\n\n    // render day rect\n    _renderDayRect: function (calendarModel, rangeData, group) {\n        var coordSys = calendarModel.coordinateSystem;\n        var itemRectStyleModel = calendarModel.getModel('itemStyle').getItemStyle();\n        var sw = coordSys.getCellWidth();\n        var sh = coordSys.getCellHeight();\n\n        for (var i = rangeData.start.time;\n            i <= rangeData.end.time;\n            i = coordSys.getNextNDay(i, 1).time\n        ) {\n\n            var point = coordSys.dataToRect([i], false).tl;\n\n            // every rect\n            var rect = new Rect({\n                shape: {\n                    x: point[0],\n                    y: point[1],\n                    width: sw,\n                    height: sh\n                },\n                cursor: 'default',\n                style: itemRectStyleModel\n            });\n\n            group.add(rect);\n        }\n\n    },\n\n    // render separate line\n    _renderLines: function (calendarModel, rangeData, orient, group) {\n\n        var self = this;\n\n        var coordSys = calendarModel.coordinateSystem;\n\n        var lineStyleModel = calendarModel.getModel('splitLine.lineStyle').getLineStyle();\n        var show = calendarModel.get('splitLine.show');\n\n        var lineWidth = lineStyleModel.lineWidth;\n\n        this._tlpoints = [];\n        this._blpoints = [];\n        this._firstDayOfMonth = [];\n        this._firstDayPoints = [];\n\n\n        var firstDay = rangeData.start;\n\n        for (var i = 0; firstDay.time <= rangeData.end.time; i++) {\n            addPoints(firstDay.formatedDate);\n\n            if (i === 0) {\n                firstDay = coordSys.getDateInfo(rangeData.start.y + '-' + rangeData.start.m);\n            }\n\n            var date = firstDay.date;\n            date.setMonth(date.getMonth() + 1);\n            firstDay = coordSys.getDateInfo(date);\n        }\n\n        addPoints(coordSys.getNextNDay(rangeData.end.time, 1).formatedDate);\n\n        function addPoints(date) {\n\n            self._firstDayOfMonth.push(coordSys.getDateInfo(date));\n            self._firstDayPoints.push(coordSys.dataToRect([date], false).tl);\n\n            var points = self._getLinePointsOfOneWeek(calendarModel, date, orient);\n\n            self._tlpoints.push(points[0]);\n            self._blpoints.push(points[points.length - 1]);\n\n            show && self._drawSplitline(points, lineStyleModel, group);\n        }\n\n\n        // render top/left line\n        show && this._drawSplitline(self._getEdgesPoints(self._tlpoints, lineWidth, orient), lineStyleModel, group);\n\n        // render bottom/right line\n        show && this._drawSplitline(self._getEdgesPoints(self._blpoints, lineWidth, orient), lineStyleModel, group);\n\n    },\n\n    // get points at both ends\n    _getEdgesPoints: function (points, lineWidth, orient) {\n        var rs = [points[0].slice(), points[points.length - 1].slice()];\n        var idx = orient === 'horizontal' ? 0 : 1;\n\n        // both ends of the line are extend half lineWidth\n        rs[0][idx] = rs[0][idx] - lineWidth / 2;\n        rs[1][idx] = rs[1][idx] + lineWidth / 2;\n\n        return rs;\n    },\n\n    // render split line\n    _drawSplitline: function (points, lineStyleModel, group) {\n\n        var poyline = new Polyline({\n            z2: 20,\n            shape: {\n                points: points\n            },\n            style: lineStyleModel\n        });\n\n        group.add(poyline);\n    },\n\n    // render month line of one week points\n    _getLinePointsOfOneWeek: function (calendarModel, date, orient) {\n\n        var coordSys = calendarModel.coordinateSystem;\n        date = coordSys.getDateInfo(date);\n\n        var points = [];\n\n        for (var i = 0; i < 7; i++) {\n\n            var tmpD = coordSys.getNextNDay(date.time, i);\n            var point = coordSys.dataToRect([tmpD.time], false);\n\n            points[2 * tmpD.day] = point.tl;\n            points[2 * tmpD.day + 1] = point[orient === 'horizontal' ? 'bl' : 'tr'];\n        }\n\n        return points;\n\n    },\n\n    _formatterLabel: function (formatter, params) {\n\n        if (typeof formatter === 'string' && formatter) {\n            return formatTplSimple(formatter, params);\n        }\n\n        if (typeof formatter === 'function') {\n            return formatter(params);\n        }\n\n        return params.nameMap;\n\n    },\n\n    _yearTextPositionControl: function (textEl, point, orient, position, margin) {\n\n        point = point.slice();\n        var aligns = ['center', 'bottom'];\n\n        if (position === 'bottom') {\n            point[1] += margin;\n            aligns = ['center', 'top'];\n        }\n        else if (position === 'left') {\n            point[0] -= margin;\n        }\n        else if (position === 'right') {\n            point[0] += margin;\n            aligns = ['center', 'top'];\n        }\n        else { // top\n            point[1] -= margin;\n        }\n\n        var rotate = 0;\n        if (position === 'left' || position === 'right') {\n            rotate = Math.PI / 2;\n        }\n\n        return {\n            rotation: rotate,\n            position: point,\n            style: {\n                textAlign: aligns[0],\n                textVerticalAlign: aligns[1]\n            }\n        };\n    },\n\n    // render year\n    _renderYearText: function (calendarModel, rangeData, orient, group) {\n        var yearLabel = calendarModel.getModel('yearLabel');\n\n        if (!yearLabel.get('show')) {\n            return;\n        }\n\n        var margin = yearLabel.get('margin');\n        var pos = yearLabel.get('position');\n\n        if (!pos) {\n            pos = orient !== 'horizontal' ? 'top' : 'left';\n        }\n\n        var points = [this._tlpoints[this._tlpoints.length - 1], this._blpoints[0]];\n        var xc = (points[0][0] + points[1][0]) / 2;\n        var yc = (points[0][1] + points[1][1]) / 2;\n\n        var idx = orient === 'horizontal' ? 0 : 1;\n\n        var posPoints = {\n            top: [xc, points[idx][1]],\n            bottom: [xc, points[1 - idx][1]],\n            left: [points[1 - idx][0], yc],\n            right: [points[idx][0], yc]\n        };\n\n        var name = rangeData.start.y;\n\n        if (+rangeData.end.y > +rangeData.start.y) {\n            name = name + '-' + rangeData.end.y;\n        }\n\n        var formatter = yearLabel.get('formatter');\n\n        var params = {\n            start: rangeData.start.y,\n            end: rangeData.end.y,\n            nameMap: name\n        };\n\n        var content = this._formatterLabel(formatter, params);\n\n        var yearText = new Text({z2: 30});\n        setTextStyle(yearText.style, yearLabel, {text: content}),\n        yearText.attr(this._yearTextPositionControl(yearText, posPoints[pos], orient, pos, margin));\n\n        group.add(yearText);\n    },\n\n    _monthTextPositionControl: function (point, isCenter, orient, position, margin) {\n        var align = 'left';\n        var vAlign = 'top';\n        var x = point[0];\n        var y = point[1];\n\n        if (orient === 'horizontal') {\n            y = y + margin;\n\n            if (isCenter) {\n                align = 'center';\n            }\n\n            if (position === 'start') {\n                vAlign = 'bottom';\n            }\n        }\n        else {\n            x = x + margin;\n\n            if (isCenter) {\n                vAlign = 'middle';\n            }\n\n            if (position === 'start') {\n                align = 'right';\n            }\n        }\n\n        return {\n            x: x,\n            y: y,\n            textAlign: align,\n            textVerticalAlign: vAlign\n        };\n    },\n\n    // render month and year text\n    _renderMonthText: function (calendarModel, orient, group) {\n        var monthLabel = calendarModel.getModel('monthLabel');\n\n        if (!monthLabel.get('show')) {\n            return;\n        }\n\n        var nameMap = monthLabel.get('nameMap');\n        var margin = monthLabel.get('margin');\n        var pos = monthLabel.get('position');\n        var align = monthLabel.get('align');\n\n        var termPoints = [this._tlpoints, this._blpoints];\n\n        if (isString(nameMap)) {\n            nameMap = MONTH_TEXT[nameMap.toUpperCase()] || [];\n        }\n\n        var idx = pos === 'start' ? 0 : 1;\n        var axis = orient === 'horizontal' ? 0 : 1;\n        margin = pos === 'start' ? -margin : margin;\n        var isCenter = (align === 'center');\n\n        for (var i = 0; i < termPoints[idx].length - 1; i++) {\n\n            var tmp = termPoints[idx][i].slice();\n            var firstDay = this._firstDayOfMonth[i];\n\n            if (isCenter) {\n                var firstDayPoints = this._firstDayPoints[i];\n                tmp[axis] = (firstDayPoints[axis] + termPoints[0][i + 1][axis]) / 2;\n            }\n\n            var formatter = monthLabel.get('formatter');\n            var name = nameMap[+firstDay.m - 1];\n            var params = {\n                yyyy: firstDay.y,\n                yy: (firstDay.y + '').slice(2),\n                MM: firstDay.m,\n                M: +firstDay.m,\n                nameMap: name\n            };\n\n            var content = this._formatterLabel(formatter, params);\n\n            var monthText = new Text({z2: 30});\n            extend(\n                setTextStyle(monthText.style, monthLabel, {text: content}),\n                this._monthTextPositionControl(tmp, isCenter, orient, pos, margin)\n            );\n\n            group.add(monthText);\n        }\n    },\n\n    _weekTextPositionControl: function (point, orient, position, margin, cellSize) {\n        var align = 'center';\n        var vAlign = 'middle';\n        var x = point[0];\n        var y = point[1];\n        var isStart = position === 'start';\n\n        if (orient === 'horizontal') {\n            x = x + margin + (isStart ? 1 : -1) * cellSize[0] / 2;\n            align = isStart ? 'right' : 'left';\n        }\n        else {\n            y = y + margin + (isStart ? 1 : -1) * cellSize[1] / 2;\n            vAlign = isStart ? 'bottom' : 'top';\n        }\n\n        return {\n            x: x,\n            y: y,\n            textAlign: align,\n            textVerticalAlign: vAlign\n        };\n    },\n\n    // render weeks\n    _renderWeekText: function (calendarModel, rangeData, orient, group) {\n        var dayLabel = calendarModel.getModel('dayLabel');\n\n        if (!dayLabel.get('show')) {\n            return;\n        }\n\n        var coordSys = calendarModel.coordinateSystem;\n        var pos = dayLabel.get('position');\n        var nameMap = dayLabel.get('nameMap');\n        var margin = dayLabel.get('margin');\n        var firstDayOfWeek = coordSys.getFirstDayOfWeek();\n\n        if (isString(nameMap)) {\n            nameMap = WEEK_TEXT[nameMap.toUpperCase()] || [];\n        }\n\n        var start = coordSys.getNextNDay(\n            rangeData.end.time, (7 - rangeData.lweek)\n        ).time;\n\n        var cellSize = [coordSys.getCellWidth(), coordSys.getCellHeight()];\n        margin = parsePercent$1(margin, cellSize[orient === 'horizontal' ? 0 : 1]);\n\n        if (pos === 'start') {\n            start = coordSys.getNextNDay(\n                rangeData.start.time, -(7 + rangeData.fweek)\n            ).time;\n            margin = -margin;\n        }\n\n        for (var i = 0; i < 7; i++) {\n\n            var tmpD = coordSys.getNextNDay(start, i);\n            var point = coordSys.dataToRect([tmpD.time], false).center;\n            var day = i;\n            day = Math.abs((i + firstDayOfWeek) % 7);\n            var weekText = new Text({z2: 30});\n\n            extend(\n                setTextStyle(weekText.style, dayLabel, {text: nameMap[day]}),\n                this._weekTextPositionControl(point, orient, pos, margin, cellSize)\n            );\n            group.add(weekText);\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file calendar.js\n * @author dxh\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Model\nextendComponentModel({\n\n    type: 'title',\n\n    layoutMode: {type: 'box', ignoreSize: true},\n\n    defaultOption: {\n        // 一级层叠\n        zlevel: 0,\n        // 二级层叠\n        z: 6,\n        show: true,\n\n        text: '',\n        // 超链接跳转\n        // link: null,\n        // 仅支持self | blank\n        target: 'blank',\n        subtext: '',\n\n        // 超链接跳转\n        // sublink: null,\n        // 仅支持self | blank\n        subtarget: 'blank',\n\n        // 'center' ¦ 'left' ¦ 'right'\n        // ¦ {number}（x坐标，单位px）\n        left: 0,\n        // 'top' ¦ 'bottom' ¦ 'center'\n        // ¦ {number}（y坐标，单位px）\n        top: 0,\n\n        // 水平对齐\n        // 'auto' | 'left' | 'right' | 'center'\n        // 默认根据 left 的位置判断是左对齐还是右对齐\n        // textAlign: null\n        //\n        // 垂直对齐\n        // 'auto' | 'top' | 'bottom' | 'middle'\n        // 默认根据 top 位置判断是上对齐还是下对齐\n        // textBaseline: null\n\n        backgroundColor: 'rgba(0,0,0,0)',\n\n        // 标题边框颜色\n        borderColor: '#ccc',\n\n        // 标题边框线宽，单位px，默认为0（无边框）\n        borderWidth: 0,\n\n        // 标题内边距，单位px，默认各方向内边距为5，\n        // 接受数组分别设定上右下左边距，同css\n        padding: 5,\n\n        // 主副标题纵向间隔，单位px，默认为10，\n        itemGap: 10,\n        textStyle: {\n            fontSize: 18,\n            fontWeight: 'bolder',\n            color: '#333'\n        },\n        subtextStyle: {\n            color: '#aaa'\n        }\n    }\n});\n\n// View\nextendComponentView({\n\n    type: 'title',\n\n    render: function (titleModel, ecModel, api) {\n        this.group.removeAll();\n\n        if (!titleModel.get('show')) {\n            return;\n        }\n\n        var group = this.group;\n\n        var textStyleModel = titleModel.getModel('textStyle');\n        var subtextStyleModel = titleModel.getModel('subtextStyle');\n\n        var textAlign = titleModel.get('textAlign');\n        var textBaseline = titleModel.get('textBaseline');\n\n        var textEl = new Text({\n            style: setTextStyle({}, textStyleModel, {\n                text: titleModel.get('text'),\n                textFill: textStyleModel.getTextColor()\n            }, {disableBox: true}),\n            z2: 10\n        });\n\n        var textRect = textEl.getBoundingRect();\n\n        var subText = titleModel.get('subtext');\n        var subTextEl = new Text({\n            style: setTextStyle({}, subtextStyleModel, {\n                text: subText,\n                textFill: subtextStyleModel.getTextColor(),\n                y: textRect.height + titleModel.get('itemGap'),\n                textVerticalAlign: 'top'\n            }, {disableBox: true}),\n            z2: 10\n        });\n\n        var link = titleModel.get('link');\n        var sublink = titleModel.get('sublink');\n        var triggerEvent = titleModel.get('triggerEvent', true);\n\n        textEl.silent = !link && !triggerEvent;\n        subTextEl.silent = !sublink && !triggerEvent;\n\n        if (link) {\n            textEl.on('click', function () {\n                window.open(link, '_' + titleModel.get('target'));\n            });\n        }\n        if (sublink) {\n            subTextEl.on('click', function () {\n                window.open(sublink, '_' + titleModel.get('subtarget'));\n            });\n        }\n\n        textEl.eventData = subTextEl.eventData = triggerEvent\n            ? {\n                componentType: 'title',\n                componentIndex: titleModel.componentIndex\n            }\n            : null;\n\n        group.add(textEl);\n        subText && group.add(subTextEl);\n        // If no subText, but add subTextEl, there will be an empty line.\n\n        var groupRect = group.getBoundingRect();\n        var layoutOption = titleModel.getBoxLayoutParams();\n        layoutOption.width = groupRect.width;\n        layoutOption.height = groupRect.height;\n        var layoutRect = getLayoutRect(\n            layoutOption, {\n                width: api.getWidth(),\n                height: api.getHeight()\n            }, titleModel.get('padding')\n        );\n        // Adjust text align based on position\n        if (!textAlign) {\n            // Align left if title is on the left. center and right is same\n            textAlign = titleModel.get('left') || titleModel.get('right');\n            if (textAlign === 'middle') {\n                textAlign = 'center';\n            }\n            // Adjust layout by text align\n            if (textAlign === 'right') {\n                layoutRect.x += layoutRect.width;\n            }\n            else if (textAlign === 'center') {\n                layoutRect.x += layoutRect.width / 2;\n            }\n        }\n        if (!textBaseline) {\n            textBaseline = titleModel.get('top') || titleModel.get('bottom');\n            if (textBaseline === 'center') {\n                textBaseline = 'middle';\n            }\n            if (textBaseline === 'bottom') {\n                layoutRect.y += layoutRect.height;\n            }\n            else if (textBaseline === 'middle') {\n                layoutRect.y += layoutRect.height / 2;\n            }\n\n            textBaseline = textBaseline || 'top';\n        }\n\n        group.attr('position', [layoutRect.x, layoutRect.y]);\n        var alignStyle = {\n            textAlign: textAlign,\n            textVerticalAlign: textBaseline\n        };\n        textEl.setStyle(alignStyle);\n        subTextEl.setStyle(alignStyle);\n\n        // Render background\n        // Get groupRect again because textAlign has been changed\n        groupRect = group.getBoundingRect();\n        var padding = layoutRect.margin;\n        var style = titleModel.getItemStyle(['color', 'opacity']);\n        style.fill = titleModel.get('backgroundColor');\n        var rect = new Rect({\n            shape: {\n                x: groupRect.x - padding[3],\n                y: groupRect.y - padding[0],\n                width: groupRect.width + padding[1] + padding[3],\n                height: groupRect.height + padding[0] + padding[2],\n                r: titleModel.get('borderRadius')\n            },\n            style: style,\n            silent: true\n        });\n        subPixelOptimizeRect(rect);\n\n        group.add(rect);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nComponentModel.registerSubTypeDefaulter('dataZoom', function () {\n    // Default 'slider' when no type specified.\n    return 'slider';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AXIS_DIMS = ['x', 'y', 'z', 'radius', 'angle', 'single'];\n// Supported coords.\nvar COORDS = ['cartesian2d', 'polar', 'singleAxis'];\n\n/**\n * @param {string} coordType\n * @return {boolean}\n */\nfunction isCoordSupported(coordType) {\n    return indexOf(COORDS, coordType) >= 0;\n}\n\n/**\n * Create \"each\" method to iterate names.\n *\n * @pubilc\n * @param  {Array.<string>} names\n * @param  {Array.<string>=} attrs\n * @return {Function}\n */\nfunction createNameEach(names, attrs) {\n    names = names.slice();\n    var capitalNames = map(names, capitalFirst);\n    attrs = (attrs || []).slice();\n    var capitalAttrs = map(attrs, capitalFirst);\n\n    return function (callback, context) {\n        each$1(names, function (name, index) {\n            var nameObj = {name: name, capital: capitalNames[index]};\n\n            for (var j = 0; j < attrs.length; j++) {\n                nameObj[attrs[j]] = name + capitalAttrs[j];\n            }\n\n            callback.call(context, nameObj);\n        });\n    };\n}\n\n/**\n * Iterate each dimension name.\n *\n * @public\n * @param {Function} callback The parameter is like:\n *                            {\n *                                name: 'angle',\n *                                capital: 'Angle',\n *                                axis: 'angleAxis',\n *                                axisIndex: 'angleAixs',\n *                                index: 'angleIndex'\n *                            }\n * @param {Object} context\n */\nvar eachAxisDim$1 = createNameEach(AXIS_DIMS, ['axisIndex', 'axis', 'index', 'id']);\n\n/**\n * If tow dataZoomModels has the same axis controlled, we say that they are 'linked'.\n * dataZoomModels and 'links' make up one or more graphics.\n * This function finds the graphic where the source dataZoomModel is in.\n *\n * @public\n * @param {Function} forEachNode Node iterator.\n * @param {Function} forEachEdgeType edgeType iterator\n * @param {Function} edgeIdGetter Giving node and edgeType, return an array of edge id.\n * @return {Function} Input: sourceNode, Output: Like {nodes: [], dims: {}}\n */\nfunction createLinkedNodesFinder(forEachNode, forEachEdgeType, edgeIdGetter) {\n\n    return function (sourceNode) {\n        var result = {\n            nodes: [],\n            records: {} // key: edgeType.name, value: Object (key: edge id, value: boolean).\n        };\n\n        forEachEdgeType(function (edgeType) {\n            result.records[edgeType.name] = {};\n        });\n\n        if (!sourceNode) {\n            return result;\n        }\n\n        absorb(sourceNode, result);\n\n        var existsLink;\n        do {\n            existsLink = false;\n            forEachNode(processSingleNode);\n        }\n        while (existsLink);\n\n        function processSingleNode(node) {\n            if (!isNodeAbsorded(node, result) && isLinked(node, result)) {\n                absorb(node, result);\n                existsLink = true;\n            }\n        }\n\n        return result;\n    };\n\n    function isNodeAbsorded(node, result) {\n        return indexOf(result.nodes, node) >= 0;\n    }\n\n    function isLinked(node, result) {\n        var hasLink = false;\n        forEachEdgeType(function (edgeType) {\n            each$1(edgeIdGetter(node, edgeType) || [], function (edgeId) {\n                result.records[edgeType.name][edgeId] && (hasLink = true);\n            });\n        });\n        return hasLink;\n    }\n\n    function absorb(node, result) {\n        result.nodes.push(node);\n        forEachEdgeType(function (edgeType) {\n            each$1(edgeIdGetter(node, edgeType) || [], function (edgeId) {\n                result.records[edgeType.name][edgeId] = true;\n            });\n        });\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$22 = each$1;\nvar asc$1 = asc;\n\n/**\n * Operate single axis.\n * One axis can only operated by one axis operator.\n * Different dataZoomModels may be defined to operate the same axis.\n * (i.e. 'inside' data zoom and 'slider' data zoom components)\n * So dataZoomModels share one axisProxy in that case.\n *\n * @class\n */\nvar AxisProxy = function (dimName, axisIndex, dataZoomModel, ecModel) {\n\n    /**\n     * @private\n     * @type {string}\n     */\n    this._dimName = dimName;\n\n    /**\n     * @private\n     */\n    this._axisIndex = axisIndex;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._valueWindow;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._percentWindow;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._dataExtent;\n\n    /**\n     * {minSpan, maxSpan, minValueSpan, maxValueSpan}\n     * @private\n     * @type {Object}\n     */\n    this._minMaxSpan;\n\n    /**\n     * @readOnly\n     * @type {module: echarts/model/Global}\n     */\n    this.ecModel = ecModel;\n\n    /**\n     * @private\n     * @type {module: echarts/component/dataZoom/DataZoomModel}\n     */\n    this._dataZoomModel = dataZoomModel;\n\n    // /**\n    //  * @readOnly\n    //  * @private\n    //  */\n    // this.hasSeriesStacked;\n};\n\nAxisProxy.prototype = {\n\n    constructor: AxisProxy,\n\n    /**\n     * Whether the axisProxy is hosted by dataZoomModel.\n     *\n     * @public\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     * @return {boolean}\n     */\n    hostedBy: function (dataZoomModel) {\n        return this._dataZoomModel === dataZoomModel;\n    },\n\n    /**\n     * @return {Array.<number>} Value can only be NaN or finite value.\n     */\n    getDataValueWindow: function () {\n        return this._valueWindow.slice();\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getDataPercentWindow: function () {\n        return this._percentWindow.slice();\n    },\n\n    /**\n     * @public\n     * @param {number} axisIndex\n     * @return {Array} seriesModels\n     */\n    getTargetSeriesModels: function () {\n        var seriesModels = [];\n        var ecModel = this.ecModel;\n\n        ecModel.eachSeries(function (seriesModel) {\n            if (isCoordSupported(seriesModel.get('coordinateSystem'))) {\n                var dimName = this._dimName;\n                var axisModel = ecModel.queryComponents({\n                    mainType: dimName + 'Axis',\n                    index: seriesModel.get(dimName + 'AxisIndex'),\n                    id: seriesModel.get(dimName + 'AxisId')\n                })[0];\n                if (this._axisIndex === (axisModel && axisModel.componentIndex)) {\n                    seriesModels.push(seriesModel);\n                }\n            }\n        }, this);\n\n        return seriesModels;\n    },\n\n    getAxisModel: function () {\n        return this.ecModel.getComponent(this._dimName + 'Axis', this._axisIndex);\n    },\n\n    getOtherAxisModel: function () {\n        var axisDim = this._dimName;\n        var ecModel = this.ecModel;\n        var axisModel = this.getAxisModel();\n        var isCartesian = axisDim === 'x' || axisDim === 'y';\n        var otherAxisDim;\n        var coordSysIndexName;\n        if (isCartesian) {\n            coordSysIndexName = 'gridIndex';\n            otherAxisDim = axisDim === 'x' ? 'y' : 'x';\n        }\n        else {\n            coordSysIndexName = 'polarIndex';\n            otherAxisDim = axisDim === 'angle' ? 'radius' : 'angle';\n        }\n        var foundOtherAxisModel;\n        ecModel.eachComponent(otherAxisDim + 'Axis', function (otherAxisModel) {\n            if ((otherAxisModel.get(coordSysIndexName) || 0)\n                === (axisModel.get(coordSysIndexName) || 0)\n            ) {\n                foundOtherAxisModel = otherAxisModel;\n            }\n        });\n        return foundOtherAxisModel;\n    },\n\n    getMinMaxSpan: function () {\n        return clone(this._minMaxSpan);\n    },\n\n    /**\n     * Only calculate by given range and this._dataExtent, do not change anything.\n     *\n     * @param {Object} opt\n     * @param {number} [opt.start]\n     * @param {number} [opt.end]\n     * @param {number} [opt.startValue]\n     * @param {number} [opt.endValue]\n     */\n    calculateDataWindow: function (opt) {\n        var dataExtent = this._dataExtent;\n        var axisModel = this.getAxisModel();\n        var scale = axisModel.axis.scale;\n        var rangePropMode = this._dataZoomModel.getRangePropMode();\n        var percentExtent = [0, 100];\n        var percentWindow = [\n            opt.start,\n            opt.end\n        ];\n        var valueWindow = [];\n\n        each$22(['startValue', 'endValue'], function (prop) {\n            valueWindow.push(opt[prop] != null ? scale.parse(opt[prop]) : null);\n        });\n\n        // Normalize bound.\n        each$22([0, 1], function (idx) {\n            var boundValue = valueWindow[idx];\n            var boundPercent = percentWindow[idx];\n\n            // Notice: dataZoom is based either on `percentProp` ('start', 'end') or\n            // on `valueProp` ('startValue', 'endValue'). The former one is suitable\n            // for cases that a dataZoom component controls multiple axes with different\n            // unit or extent, and the latter one is suitable for accurate zoom by pixel\n            // (e.g., in dataZoomSelect). `valueProp` can be calculated from `percentProp`,\n            // but it is awkward that `percentProp` can not be obtained from `valueProp`\n            // accurately (because all of values that are overflow the `dataExtent` will\n            // be calculated to percent '100%'). So we have to use\n            // `dataZoom.getRangePropMode()` to mark which prop is used.\n            // `rangePropMode` is updated only when setOption or dispatchAction, otherwise\n            // it remains its original value.\n\n            if (rangePropMode[idx] === 'percent') {\n                if (boundPercent == null) {\n                    boundPercent = percentExtent[idx];\n                }\n                // Use scale.parse to math round for category or time axis.\n                boundValue = scale.parse(linearMap(\n                    boundPercent, percentExtent, dataExtent, true\n                ));\n            }\n            else {\n                // Calculating `percent` from `value` may be not accurate, because\n                // This calculation can not be inversed, because all of values that\n                // are overflow the `dataExtent` will be calculated to percent '100%'\n                boundPercent = linearMap(\n                    boundValue, dataExtent, percentExtent, true\n                );\n            }\n\n            // valueWindow[idx] = round(boundValue);\n            // percentWindow[idx] = round(boundPercent);\n            valueWindow[idx] = boundValue;\n            percentWindow[idx] = boundPercent;\n        });\n\n        return {\n            valueWindow: asc$1(valueWindow),\n            percentWindow: asc$1(percentWindow)\n        };\n    },\n\n    /**\n     * Notice: reset should not be called before series.restoreData() called,\n     * so it is recommanded to be called in \"process stage\" but not \"model init\n     * stage\".\n     *\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    reset: function (dataZoomModel) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        var targetSeries = this.getTargetSeriesModels();\n        // Culculate data window and data extent, and record them.\n        this._dataExtent = calculateDataExtent(this, this._dimName, targetSeries);\n\n        // this.hasSeriesStacked = false;\n        // each(targetSeries, function (series) {\n            // var data = series.getData();\n            // var dataDim = data.mapDimension(this._dimName);\n            // var stackedDimension = data.getCalculationInfo('stackedDimension');\n            // if (stackedDimension && stackedDimension === dataDim) {\n                // this.hasSeriesStacked = true;\n            // }\n        // }, this);\n\n        var dataWindow = this.calculateDataWindow(dataZoomModel.option);\n\n        this._valueWindow = dataWindow.valueWindow;\n        this._percentWindow = dataWindow.percentWindow;\n\n        setMinMaxSpan(this);\n\n        // Update axis setting then.\n        setAxisModel(this);\n    },\n\n    /**\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    restore: function (dataZoomModel) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        this._valueWindow = this._percentWindow = null;\n        setAxisModel(this, true);\n    },\n\n    /**\n     * @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel\n     */\n    filterData: function (dataZoomModel, api) {\n        if (dataZoomModel !== this._dataZoomModel) {\n            return;\n        }\n\n        var axisDim = this._dimName;\n        var seriesModels = this.getTargetSeriesModels();\n        var filterMode = dataZoomModel.get('filterMode');\n        var valueWindow = this._valueWindow;\n\n        if (filterMode === 'none') {\n            return;\n        }\n\n        // FIXME\n        // Toolbox may has dataZoom injected. And if there are stacked bar chart\n        // with NaN data, NaN will be filtered and stack will be wrong.\n        // So we need to force the mode to be set empty.\n        // In fect, it is not a big deal that do not support filterMode-'filter'\n        // when using toolbox#dataZoom, utill tooltip#dataZoom support \"single axis\n        // selection\" some day, which might need \"adapt to data extent on the\n        // otherAxis\", which is disabled by filterMode-'empty'.\n        // But currently, stack has been fixed to based on value but not index,\n        // so this is not an issue any more.\n        // var otherAxisModel = this.getOtherAxisModel();\n        // if (dataZoomModel.get('$fromToolbox')\n        //     && otherAxisModel\n        //     && otherAxisModel.hasSeriesStacked\n        // ) {\n        //     filterMode = 'empty';\n        // }\n\n        // TODO\n        // filterMode 'weakFilter' and 'empty' is not optimized for huge data yet.\n\n        each$22(seriesModels, function (seriesModel) {\n            var seriesData = seriesModel.getData();\n            var dataDims = seriesData.mapDimension(axisDim, true);\n\n            if (!dataDims.length) {\n                return;\n            }\n\n            if (filterMode === 'weakFilter') {\n                seriesData.filterSelf(function (dataIndex) {\n                    var leftOut;\n                    var rightOut;\n                    var hasValue;\n                    for (var i = 0; i < dataDims.length; i++) {\n                        var value = seriesData.get(dataDims[i], dataIndex);\n                        var thisHasValue = !isNaN(value);\n                        var thisLeftOut = value < valueWindow[0];\n                        var thisRightOut = value > valueWindow[1];\n                        if (thisHasValue && !thisLeftOut && !thisRightOut) {\n                            return true;\n                        }\n                        thisHasValue && (hasValue = true);\n                        thisLeftOut && (leftOut = true);\n                        thisRightOut && (rightOut = true);\n                    }\n                    // If both left out and right out, do not filter.\n                    return hasValue && leftOut && rightOut;\n                });\n            }\n            else {\n                each$22(dataDims, function (dim) {\n                    if (filterMode === 'empty') {\n                        seriesModel.setData(\n                            seriesData.map(dim, function (value) {\n                                return !isInWindow(value) ? NaN : value;\n                            })\n                        );\n                    }\n                    else {\n                        var range = {};\n                        range[dim] = valueWindow;\n\n                        // console.time('select');\n                        seriesData.selectRange(range);\n                        // console.timeEnd('select');\n                    }\n                });\n            }\n\n            each$22(dataDims, function (dim) {\n                seriesData.setApproximateExtent(valueWindow, dim);\n            });\n        });\n\n        function isInWindow(value) {\n            return value >= valueWindow[0] && value <= valueWindow[1];\n        }\n    }\n};\n\nfunction calculateDataExtent(axisProxy, axisDim, seriesModels) {\n    var dataExtent = [Infinity, -Infinity];\n\n    each$22(seriesModels, function (seriesModel) {\n        var seriesData = seriesModel.getData();\n        if (seriesData) {\n            each$22(seriesData.mapDimension(axisDim, true), function (dim) {\n                var seriesExtent = seriesData.getApproximateExtent(dim);\n                seriesExtent[0] < dataExtent[0] && (dataExtent[0] = seriesExtent[0]);\n                seriesExtent[1] > dataExtent[1] && (dataExtent[1] = seriesExtent[1]);\n            });\n        }\n    });\n\n    if (dataExtent[1] < dataExtent[0]) {\n        dataExtent = [NaN, NaN];\n    }\n\n    // It is important to get \"consistent\" extent when more then one axes is\n    // controlled by a `dataZoom`, otherwise those axes will not be synchronized\n    // when zooming. But it is difficult to know what is \"consistent\", considering\n    // axes have different type or even different meanings (For example, two\n    // time axes are used to compare data of the same date in different years).\n    // So basically dataZoom just obtains extent by series.data (in category axis\n    // extent can be obtained from axis.data).\n    // Nevertheless, user can set min/max/scale on axes to make extent of axes\n    // consistent.\n    fixExtentByAxis(axisProxy, dataExtent);\n\n    return dataExtent;\n}\n\nfunction fixExtentByAxis(axisProxy, dataExtent) {\n    var axisModel = axisProxy.getAxisModel();\n    var min = axisModel.getMin(true);\n\n    // For category axis, if min/max/scale are not set, extent is determined\n    // by axis.data by default.\n    var isCategoryAxis = axisModel.get('type') === 'category';\n    var axisDataLen = isCategoryAxis && axisModel.getCategories().length;\n\n    if (min != null && min !== 'dataMin' && typeof min !== 'function') {\n        dataExtent[0] = min;\n    }\n    else if (isCategoryAxis) {\n        dataExtent[0] = axisDataLen > 0 ? 0 : NaN;\n    }\n\n    var max = axisModel.getMax(true);\n    if (max != null && max !== 'dataMax' && typeof max !== 'function') {\n        dataExtent[1] = max;\n    }\n    else if (isCategoryAxis) {\n        dataExtent[1] = axisDataLen > 0 ? axisDataLen - 1 : NaN;\n    }\n\n    if (!axisModel.get('scale', true)) {\n        dataExtent[0] > 0 && (dataExtent[0] = 0);\n        dataExtent[1] < 0 && (dataExtent[1] = 0);\n    }\n\n    // For value axis, if min/max/scale are not set, we just use the extent obtained\n    // by series data, which may be a little different from the extent calculated by\n    // `axisHelper.getScaleExtent`. But the different just affects the experience a\n    // little when zooming. So it will not be fixed until some users require it strongly.\n\n    return dataExtent;\n}\n\nfunction setAxisModel(axisProxy, isRestore) {\n    var axisModel = axisProxy.getAxisModel();\n\n    var percentWindow = axisProxy._percentWindow;\n    var valueWindow = axisProxy._valueWindow;\n\n    if (!percentWindow) {\n        return;\n    }\n\n    // [0, 500]: arbitrary value, guess axis extent.\n    var precision = getPixelPrecision(valueWindow, [0, 500]);\n    precision = Math.min(precision, 20);\n    // isRestore or isFull\n    var useOrigin = isRestore || (percentWindow[0] === 0 && percentWindow[1] === 100);\n\n    axisModel.setRange(\n        useOrigin ? null : +valueWindow[0].toFixed(precision),\n        useOrigin ? null : +valueWindow[1].toFixed(precision)\n    );\n}\n\nfunction setMinMaxSpan(axisProxy) {\n    var minMaxSpan = axisProxy._minMaxSpan = {};\n    var dataZoomModel = axisProxy._dataZoomModel;\n\n    each$22(['min', 'max'], function (minMax) {\n        minMaxSpan[minMax + 'Span'] = dataZoomModel.get(minMax + 'Span');\n\n        // minValueSpan and maxValueSpan has higher priority than minSpan and maxSpan\n        var valueSpan = dataZoomModel.get(minMax + 'ValueSpan');\n\n        if (valueSpan != null) {\n            minMaxSpan[minMax + 'ValueSpan'] = valueSpan;\n            valueSpan = axisProxy.getAxisModel().axis.scale.parse(valueSpan);\n\n            if (valueSpan != null) {\n                var dataExtent = axisProxy._dataExtent;\n                minMaxSpan[minMax + 'Span'] = linearMap(\n                    dataExtent[0] + valueSpan, dataExtent, [0, 100], true\n                );\n            }\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$21 = each$1;\nvar eachAxisDim = eachAxisDim$1;\n\nvar DataZoomModel = extendComponentModel({\n\n    type: 'dataZoom',\n\n    dependencies: [\n        'xAxis', 'yAxis', 'zAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'series'\n    ],\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        zlevel: 0,\n        z: 4,                   // Higher than normal component (z: 2).\n        orient: null,           // Default auto by axisIndex. Possible value: 'horizontal', 'vertical'.\n        xAxisIndex: null,       // Default the first horizontal category axis.\n        yAxisIndex: null,       // Default the first vertical category axis.\n\n        filterMode: 'filter',   // Possible values: 'filter' or 'empty' or 'weakFilter'.\n                                // 'filter': data items which are out of window will be removed. This option is\n                                //          applicable when filtering outliers. For each data item, it will be\n                                //          filtered if one of the relevant dimensions is out of the window.\n                                // 'weakFilter': data items which are out of window will be removed. This option\n                                //          is applicable when filtering outliers. For each data item, it will be\n                                //          filtered only if all  of the relevant dimensions are out of the same\n                                //          side of the window.\n                                // 'empty': data items which are out of window will be set to empty.\n                                //          This option is applicable when user should not neglect\n                                //          that there are some data items out of window.\n                                // 'none': Do not filter.\n                                // Taking line chart as an example, line will be broken in\n                                // the filtered points when filterModel is set to 'empty', but\n                                // be connected when set to 'filter'.\n\n        throttle: null,         // Dispatch action by the fixed rate, avoid frequency.\n                                // default 100. Do not throttle when use null/undefined.\n                                // If animation === true and animationDurationUpdate > 0,\n                                // default value is 100, otherwise 20.\n        start: 0,               // Start percent. 0 ~ 100\n        end: 100,               // End percent. 0 ~ 100\n        startValue: null,       // Start value. If startValue specified, start is ignored.\n        endValue: null,         // End value. If endValue specified, end is ignored.\n        minSpan: null,          // 0 ~ 100\n        maxSpan: null,          // 0 ~ 100\n        minValueSpan: null,     // The range of dataZoom can not be smaller than that.\n        maxValueSpan: null,     // The range of dataZoom can not be larger than that.\n        rangeMode: null         // Array, can be 'value' or 'percent'.\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel) {\n\n        /**\n         * key like x_0, y_1\n         * @private\n         * @type {Object}\n         */\n        this._dataIntervalByAxis = {};\n\n        /**\n         * @private\n         */\n        this._dataInfo = {};\n\n        /**\n         * key like x_0, y_1\n         * @private\n         */\n        this._axisProxies = {};\n\n        /**\n         * @readOnly\n         */\n        this.textStyleModel;\n\n        /**\n         * @private\n         */\n        this._autoThrottle = true;\n\n        /**\n         * 'percent' or 'value'\n         * @private\n         */\n        this._rangePropMode = ['percent', 'percent'];\n\n        var rawOption = retrieveRaw(option);\n\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        this.doInit(rawOption);\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (newOption) {\n        var rawOption = retrieveRaw(newOption);\n\n        //FIX #2591\n        merge(this.option, newOption, true);\n\n        this.doInit(rawOption);\n    },\n\n    /**\n     * @protected\n     */\n    doInit: function (rawOption) {\n        var thisOption = this.option;\n\n        // Disable realtime view update if canvas is not supported.\n        if (!env$1.canvasSupported) {\n            thisOption.realtime = false;\n        }\n\n        this._setDefaultThrottle(rawOption);\n\n        updateRangeUse(this, rawOption);\n\n        each$21([['start', 'startValue'], ['end', 'endValue']], function (names, index) {\n            // start/end has higher priority over startValue/endValue if they\n            // both set, but we should make chart.setOption({endValue: 1000})\n            // effective, rather than chart.setOption({endValue: 1000, end: null}).\n            if (this._rangePropMode[index] === 'value') {\n                thisOption[names[0]] = null;\n            }\n            // Otherwise do nothing and use the merge result.\n        }, this);\n\n        this.textStyleModel = this.getModel('textStyle');\n\n        this._resetTarget();\n\n        this._giveAxisProxies();\n    },\n\n    /**\n     * @private\n     */\n    _giveAxisProxies: function () {\n        var axisProxies = this._axisProxies;\n\n        this.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel, ecModel) {\n            var axisModel = this.dependentModels[dimNames.axis][axisIndex];\n\n            // If exists, share axisProxy with other dataZoomModels.\n            var axisProxy = axisModel.__dzAxisProxy || (\n                // Use the first dataZoomModel as the main model of axisProxy.\n                axisModel.__dzAxisProxy = new AxisProxy(\n                    dimNames.name, axisIndex, this, ecModel\n                )\n            );\n            // FIXME\n            // dispose __dzAxisProxy\n\n            axisProxies[dimNames.name + '_' + axisIndex] = axisProxy;\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _resetTarget: function () {\n        var thisOption = this.option;\n\n        var autoMode = this._judgeAutoMode();\n\n        eachAxisDim(function (dimNames) {\n            var axisIndexName = dimNames.axisIndex;\n            thisOption[axisIndexName] = normalizeToArray(\n                thisOption[axisIndexName]\n            );\n        }, this);\n\n        if (autoMode === 'axisIndex') {\n            this._autoSetAxisIndex();\n        }\n        else if (autoMode === 'orient') {\n            this._autoSetOrient();\n        }\n    },\n\n    /**\n     * @private\n     */\n    _judgeAutoMode: function () {\n        // Auto set only works for setOption at the first time.\n        // The following is user's reponsibility. So using merged\n        // option is OK.\n        var thisOption = this.option;\n\n        var hasIndexSpecified = false;\n        eachAxisDim(function (dimNames) {\n            // When user set axisIndex as a empty array, we think that user specify axisIndex\n            // but do not want use auto mode. Because empty array may be encountered when\n            // some error occured.\n            if (thisOption[dimNames.axisIndex] != null) {\n                hasIndexSpecified = true;\n            }\n        }, this);\n\n        var orient = thisOption.orient;\n\n        if (orient == null && hasIndexSpecified) {\n            return 'orient';\n        }\n        else if (!hasIndexSpecified) {\n            if (orient == null) {\n                thisOption.orient = 'horizontal';\n            }\n            return 'axisIndex';\n        }\n    },\n\n    /**\n     * @private\n     */\n    _autoSetAxisIndex: function () {\n        var autoAxisIndex = true;\n        var orient = this.get('orient', true);\n        var thisOption = this.option;\n        var dependentModels = this.dependentModels;\n\n        if (autoAxisIndex) {\n            // Find axis that parallel to dataZoom as default.\n            var dimName = orient === 'vertical' ? 'y' : 'x';\n\n            if (dependentModels[dimName + 'Axis'].length) {\n                thisOption[dimName + 'AxisIndex'] = [0];\n                autoAxisIndex = false;\n            }\n            else {\n                each$21(dependentModels.singleAxis, function (singleAxisModel) {\n                    if (autoAxisIndex && singleAxisModel.get('orient', true) === orient) {\n                        thisOption.singleAxisIndex = [singleAxisModel.componentIndex];\n                        autoAxisIndex = false;\n                    }\n                });\n            }\n        }\n\n        if (autoAxisIndex) {\n            // Find the first category axis as default. (consider polar)\n            eachAxisDim(function (dimNames) {\n                if (!autoAxisIndex) {\n                    return;\n                }\n                var axisIndices = [];\n                var axisModels = this.dependentModels[dimNames.axis];\n                if (axisModels.length && !axisIndices.length) {\n                    for (var i = 0, len = axisModels.length; i < len; i++) {\n                        if (axisModels[i].get('type') === 'category') {\n                            axisIndices.push(i);\n                        }\n                    }\n                }\n                thisOption[dimNames.axisIndex] = axisIndices;\n                if (axisIndices.length) {\n                    autoAxisIndex = false;\n                }\n            }, this);\n        }\n\n        if (autoAxisIndex) {\n            // FIXME\n            // 这里是兼容ec2的写法（没指定xAxisIndex和yAxisIndex时把scatter和双数值轴折柱纳入dataZoom控制），\n            // 但是实际是否需要Grid.js#getScaleByOption来判断（考虑time，log等axis type）？\n\n            // If both dataZoom.xAxisIndex and dataZoom.yAxisIndex is not specified,\n            // dataZoom component auto adopts series that reference to\n            // both xAxis and yAxis which type is 'value'.\n            this.ecModel.eachSeries(function (seriesModel) {\n                if (this._isSeriesHasAllAxesTypeOf(seriesModel, 'value')) {\n                    eachAxisDim(function (dimNames) {\n                        var axisIndices = thisOption[dimNames.axisIndex];\n\n                        var axisIndex = seriesModel.get(dimNames.axisIndex);\n                        var axisId = seriesModel.get(dimNames.axisId);\n\n                        var axisModel = seriesModel.ecModel.queryComponents({\n                            mainType: dimNames.axis,\n                            index: axisIndex,\n                            id: axisId\n                        })[0];\n\n                        if (__DEV__) {\n                            if (!axisModel) {\n                                throw new Error(\n                                    dimNames.axis + ' \"' + retrieve(\n                                        axisIndex,\n                                        axisId,\n                                        0\n                                    ) + '\" not found'\n                                );\n                            }\n                        }\n                        axisIndex = axisModel.componentIndex;\n\n                        if (indexOf(axisIndices, axisIndex) < 0) {\n                            axisIndices.push(axisIndex);\n                        }\n                    });\n                }\n            }, this);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _autoSetOrient: function () {\n        var dim;\n\n        // Find the first axis\n        this.eachTargetAxis(function (dimNames) {\n            !dim && (dim = dimNames.name);\n        }, this);\n\n        this.option.orient = dim === 'y' ? 'vertical' : 'horizontal';\n    },\n\n    /**\n     * @private\n     */\n    _isSeriesHasAllAxesTypeOf: function (seriesModel, axisType) {\n        // FIXME\n        // 需要series的xAxisIndex和yAxisIndex都首先自动设置上。\n        // 例如series.type === scatter时。\n\n        var is = true;\n        eachAxisDim(function (dimNames) {\n            var seriesAxisIndex = seriesModel.get(dimNames.axisIndex);\n            var axisModel = this.dependentModels[dimNames.axis][seriesAxisIndex];\n\n            if (!axisModel || axisModel.get('type') !== axisType) {\n                is = false;\n            }\n        }, this);\n        return is;\n    },\n\n    /**\n     * @private\n     */\n    _setDefaultThrottle: function (rawOption) {\n        // When first time user set throttle, auto throttle ends.\n        if (rawOption.hasOwnProperty('throttle')) {\n            this._autoThrottle = false;\n        }\n        if (this._autoThrottle) {\n            var globalOption = this.ecModel.option;\n            this.option.throttle\n                = (globalOption.animation && globalOption.animationDurationUpdate > 0)\n                ? 100 : 20;\n        }\n    },\n\n    /**\n     * @public\n     */\n    getFirstTargetAxisModel: function () {\n        var firstAxisModel;\n        eachAxisDim(function (dimNames) {\n            if (firstAxisModel == null) {\n                var indices = this.get(dimNames.axisIndex);\n                if (indices.length) {\n                    firstAxisModel = this.dependentModels[dimNames.axis][indices[0]];\n                }\n            }\n        }, this);\n\n        return firstAxisModel;\n    },\n\n    /**\n     * @public\n     * @param {Function} callback param: axisModel, dimNames, axisIndex, dataZoomModel, ecModel\n     */\n    eachTargetAxis: function (callback, context) {\n        var ecModel = this.ecModel;\n        eachAxisDim(function (dimNames) {\n            each$21(\n                this.get(dimNames.axisIndex),\n                function (axisIndex) {\n                    callback.call(context, dimNames, axisIndex, this, ecModel);\n                },\n                this\n            );\n        }, this);\n    },\n\n    /**\n     * @param {string} dimName\n     * @param {number} axisIndex\n     * @return {module:echarts/component/dataZoom/AxisProxy} If not found, return null/undefined.\n     */\n    getAxisProxy: function (dimName, axisIndex) {\n        return this._axisProxies[dimName + '_' + axisIndex];\n    },\n\n    /**\n     * @param {string} dimName\n     * @param {number} axisIndex\n     * @return {module:echarts/model/Model} If not found, return null/undefined.\n     */\n    getAxisModel: function (dimName, axisIndex) {\n        var axisProxy = this.getAxisProxy(dimName, axisIndex);\n        return axisProxy && axisProxy.getAxisModel();\n    },\n\n    /**\n     * If not specified, set to undefined.\n     *\n     * @public\n     * @param {Object} opt\n     * @param {number} [opt.start]\n     * @param {number} [opt.end]\n     * @param {number} [opt.startValue]\n     * @param {number} [opt.endValue]\n     * @param {boolean} [ignoreUpdateRangeUsg=false]\n     */\n    setRawRange: function (opt, ignoreUpdateRangeUsg) {\n        var option = this.option;\n        each$21([['start', 'startValue'], ['end', 'endValue']], function (names) {\n            // If only one of 'start' and 'startValue' is not null/undefined, the other\n            // should be cleared, which enable clear the option.\n            // If both of them are not set, keep option with the original value, which\n            // enable use only set start but not set end when calling `dispatchAction`.\n            // The same as 'end' and 'endValue'.\n            if (opt[names[0]] != null || opt[names[1]] != null) {\n                option[names[0]] = opt[names[0]];\n                option[names[1]] = opt[names[1]];\n            }\n        }, this);\n\n        !ignoreUpdateRangeUsg && updateRangeUse(this, opt);\n    },\n\n    /**\n     * @public\n     * @return {Array.<number>} [startPercent, endPercent]\n     */\n    getPercentRange: function () {\n        var axisProxy = this.findRepresentativeAxisProxy();\n        if (axisProxy) {\n            return axisProxy.getDataPercentWindow();\n        }\n    },\n\n    /**\n     * @public\n     * For example, chart.getModel().getComponent('dataZoom').getValueRange('y', 0);\n     *\n     * @param {string} [axisDimName]\n     * @param {number} [axisIndex]\n     * @return {Array.<number>} [startValue, endValue] value can only be '-' or finite number.\n     */\n    getValueRange: function (axisDimName, axisIndex) {\n        if (axisDimName == null && axisIndex == null) {\n            var axisProxy = this.findRepresentativeAxisProxy();\n            if (axisProxy) {\n                return axisProxy.getDataValueWindow();\n            }\n        }\n        else {\n            return this.getAxisProxy(axisDimName, axisIndex).getDataValueWindow();\n        }\n    },\n\n    /**\n     * @public\n     * @param {module:echarts/model/Model} [axisModel] If axisModel given, find axisProxy\n     *      corresponding to the axisModel\n     * @return {module:echarts/component/dataZoom/AxisProxy}\n     */\n    findRepresentativeAxisProxy: function (axisModel) {\n        if (axisModel) {\n            return axisModel.__dzAxisProxy;\n        }\n\n        // Find the first hosted axisProxy\n        var axisProxies = this._axisProxies;\n        for (var key in axisProxies) {\n            if (axisProxies.hasOwnProperty(key) && axisProxies[key].hostedBy(this)) {\n                return axisProxies[key];\n            }\n        }\n\n        // If no hosted axis find not hosted axisProxy.\n        // Consider this case: dataZoomModel1 and dataZoomModel2 control the same axis,\n        // and the option.start or option.end settings are different. The percentRange\n        // should follow axisProxy.\n        // (We encounter this problem in toolbox data zoom.)\n        for (var key in axisProxies) {\n            if (axisProxies.hasOwnProperty(key) && !axisProxies[key].hostedBy(this)) {\n                return axisProxies[key];\n            }\n        }\n    },\n\n    /**\n     * @return {Array.<string>}\n     */\n    getRangePropMode: function () {\n        return this._rangePropMode.slice();\n    }\n\n});\n\nfunction retrieveRaw(option) {\n    var ret = {};\n    each$21(\n        ['start', 'end', 'startValue', 'endValue', 'throttle'],\n        function (name) {\n            option.hasOwnProperty(name) && (ret[name] = option[name]);\n        }\n    );\n    return ret;\n}\n\nfunction updateRangeUse(dataZoomModel, rawOption) {\n    var rangePropMode = dataZoomModel._rangePropMode;\n    var rangeModeInOption = dataZoomModel.get('rangeMode');\n\n    each$21([['start', 'startValue'], ['end', 'endValue']], function (names, index) {\n        var percentSpecified = rawOption[names[0]] != null;\n        var valueSpecified = rawOption[names[1]] != null;\n        if (percentSpecified && !valueSpecified) {\n            rangePropMode[index] = 'percent';\n        }\n        else if (!percentSpecified && valueSpecified) {\n            rangePropMode[index] = 'value';\n        }\n        else if (rangeModeInOption) {\n            rangePropMode[index] = rangeModeInOption[index];\n        }\n        else if (percentSpecified) { // percentSpecified && valueSpecified\n            rangePropMode[index] = 'percent';\n        }\n        // else remain its original setting.\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DataZoomView = Component.extend({\n\n    type: 'dataZoom',\n\n    render: function (dataZoomModel, ecModel, api, payload) {\n        this.dataZoomModel = dataZoomModel;\n        this.ecModel = ecModel;\n        this.api = api;\n    },\n\n    /**\n     * Find the first target coordinate system.\n     *\n     * @protected\n     * @return {Object} {\n     *                   grid: [\n     *                       {model: coord0, axisModels: [axis1, axis3], coordIndex: 1},\n     *                       {model: coord1, axisModels: [axis0, axis2], coordIndex: 0},\n     *                       ...\n     *                   ],  // cartesians must not be null/undefined.\n     *                   polar: [\n     *                       {model: coord0, axisModels: [axis4], coordIndex: 0},\n     *                       ...\n     *                   ],  // polars must not be null/undefined.\n     *                   singleAxis: [\n     *                       {model: coord0, axisModels: [], coordIndex: 0}\n     *                   ]\n     */\n    getTargetCoordInfo: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var ecModel = this.ecModel;\n        var coordSysLists = {};\n\n        dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {\n            var axisModel = ecModel.getComponent(dimNames.axis, axisIndex);\n            if (axisModel) {\n                var coordModel = axisModel.getCoordSysModel();\n                coordModel && save(\n                    coordModel,\n                    axisModel,\n                    coordSysLists[coordModel.mainType] || (coordSysLists[coordModel.mainType] = []),\n                    coordModel.componentIndex\n                );\n            }\n        }, this);\n\n        function save(coordModel, axisModel, store, coordIndex) {\n            var item;\n            for (var i = 0; i < store.length; i++) {\n                if (store[i].model === coordModel) {\n                    item = store[i];\n                    break;\n                }\n            }\n            if (!item) {\n                store.push(item = {\n                    model: coordModel, axisModels: [], coordIndex: coordIndex\n                });\n            }\n            item.axisModels.push(axisModel);\n        }\n\n        return coordSysLists;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar SliderZoomModel = DataZoomModel.extend({\n\n    type: 'dataZoom.slider',\n\n    layoutMode: 'box',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        show: true,\n\n        // ph => placeholder. Using placehoder here because\n        // deault value can only be drived in view stage.\n        right: 'ph',  // Default align to grid rect.\n        top: 'ph',    // Default align to grid rect.\n        width: 'ph',  // Default align to grid rect.\n        height: 'ph', // Default align to grid rect.\n        left: null,   // Default align to grid rect.\n        bottom: null, // Default align to grid rect.\n\n        backgroundColor: 'rgba(47,69,84,0)',    // Background of slider zoom component.\n        // dataBackgroundColor: '#ddd',         // Background coor of data shadow and border of box,\n                                                // highest priority, remain for compatibility of\n                                                // previous version, but not recommended any more.\n        dataBackground: {\n            lineStyle: {\n                color: '#2f4554',\n                width: 0.5,\n                opacity: 0.3\n            },\n            areaStyle: {\n                color: 'rgba(47,69,84,0.3)',\n                opacity: 0.3\n            }\n        },\n        borderColor: '#ddd',                    // border color of the box. For compatibility,\n                                                // if dataBackgroundColor is set, borderColor\n                                                // is ignored.\n\n        fillerColor: 'rgba(167,183,204,0.4)',     // Color of selected area.\n        // handleColor: 'rgba(89,170,216,0.95)',     // Color of handle.\n        // handleIcon: 'path://M4.9,17.8c0-1.4,4.5-10.5,5.5-12.4c0-0.1,0.6-1.1,0.9-1.1c0.4,0,0.9,1,0.9,1.1c1.1,2.2,5.4,11,5.4,12.4v17.8c0,1.5-0.6,2.1-1.3,2.1H6.1c-0.7,0-1.3-0.6-1.3-2.1V17.8z',\n        /* eslint-disable */\n        handleIcon: 'M8.2,13.6V3.9H6.3v9.7H3.1v14.9h3.3v9.7h1.8v-9.7h3.3V13.6H8.2z M9.7,24.4H4.8v-1.4h4.9V24.4z M9.7,19.1H4.8v-1.4h4.9V19.1z',\n        /* eslint-enable */\n        // Percent of the slider height\n        handleSize: '100%',\n\n        handleStyle: {\n            color: '#a7b7cc'\n        },\n\n        labelPrecision: null,\n        labelFormatter: null,\n        showDetail: true,\n        showDataShadow: 'auto',                 // Default auto decision.\n        realtime: true,\n        zoomLock: false,                        // Whether disable zoom.\n        textStyle: {\n            color: '#333'\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar Rect$2 = Rect;\nvar linearMap$1 = linearMap;\nvar asc$2 = asc;\nvar bind$4 = bind;\nvar each$23 = each$1;\n\n// Constants\nvar DEFAULT_LOCATION_EDGE_GAP = 7;\nvar DEFAULT_FRAME_BORDER_WIDTH = 1;\nvar DEFAULT_FILLER_SIZE = 30;\nvar HORIZONTAL = 'horizontal';\nvar VERTICAL = 'vertical';\nvar LABEL_GAP = 5;\nvar SHOW_DATA_SHADOW_SERIES_TYPE = ['line', 'bar', 'candlestick', 'scatter'];\n\nvar SliderZoomView = DataZoomView.extend({\n\n    type: 'dataZoom.slider',\n\n    init: function (ecModel, api) {\n\n        /**\n         * @private\n         * @type {Object}\n         */\n        this._displayables = {};\n\n        /**\n         * @private\n         * @type {string}\n         */\n        this._orient;\n\n        /**\n         * [0, 100]\n         * @private\n         */\n        this._range;\n\n        /**\n         * [coord of the first handle, coord of the second handle]\n         * @private\n         */\n        this._handleEnds;\n\n        /**\n         * [length, thick]\n         * @private\n         * @type {Array.<number>}\n         */\n        this._size;\n\n        /**\n         * @private\n         * @type {number}\n         */\n        this._handleWidth;\n\n        /**\n         * @private\n         * @type {number}\n         */\n        this._handleHeight;\n\n        /**\n         * @private\n         */\n        this._location;\n\n        /**\n         * @private\n         */\n        this._dragging;\n\n        /**\n         * @private\n         */\n        this._dataShadowInfo;\n\n        this.api = api;\n    },\n\n    /**\n     * @override\n     */\n    render: function (dataZoomModel, ecModel, api, payload) {\n        SliderZoomView.superApply(this, 'render', arguments);\n\n        createOrUpdate(\n            this,\n            '_dispatchZoomAction',\n            this.dataZoomModel.get('throttle'),\n            'fixRate'\n        );\n\n        this._orient = dataZoomModel.get('orient');\n\n        if (this.dataZoomModel.get('show') === false) {\n            this.group.removeAll();\n            return;\n        }\n\n        // Notice: this._resetInterval() should not be executed when payload.type\n        // is 'dataZoom', origin this._range should be maintained, otherwise 'pan'\n        // or 'zoom' info will be missed because of 'throttle' of this.dispatchAction,\n        if (!payload || payload.type !== 'dataZoom' || payload.from !== this.uid) {\n            this._buildView();\n        }\n\n        this._updateView();\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        SliderZoomView.superApply(this, 'remove', arguments);\n        clear(this, '_dispatchZoomAction');\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        SliderZoomView.superApply(this, 'dispose', arguments);\n        clear(this, '_dispatchZoomAction');\n    },\n\n    _buildView: function () {\n        var thisGroup = this.group;\n\n        thisGroup.removeAll();\n\n        this._resetLocation();\n        this._resetInterval();\n\n        var barGroup = this._displayables.barGroup = new Group();\n\n        this._renderBackground();\n\n        this._renderHandle();\n\n        this._renderDataShadow();\n\n        thisGroup.add(barGroup);\n\n        this._positionGroup();\n    },\n\n    /**\n     * @private\n     */\n    _resetLocation: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var api = this.api;\n\n        // If some of x/y/width/height are not specified,\n        // auto-adapt according to target grid.\n        var coordRect = this._findCoordRect();\n        var ecSize = {width: api.getWidth(), height: api.getHeight()};\n        // Default align by coordinate system rect.\n        var positionInfo = this._orient === HORIZONTAL\n            ? {\n                // Why using 'right', because right should be used in vertical,\n                // and it is better to be consistent for dealing with position param merge.\n                right: ecSize.width - coordRect.x - coordRect.width,\n                top: (ecSize.height - DEFAULT_FILLER_SIZE - DEFAULT_LOCATION_EDGE_GAP),\n                width: coordRect.width,\n                height: DEFAULT_FILLER_SIZE\n            }\n            : { // vertical\n                right: DEFAULT_LOCATION_EDGE_GAP,\n                top: coordRect.y,\n                width: DEFAULT_FILLER_SIZE,\n                height: coordRect.height\n            };\n\n        // Do not write back to option and replace value 'ph', because\n        // the 'ph' value should be recalculated when resize.\n        var layoutParams = getLayoutParams(dataZoomModel.option);\n\n        // Replace the placeholder value.\n        each$1(['right', 'top', 'width', 'height'], function (name) {\n            if (layoutParams[name] === 'ph') {\n                layoutParams[name] = positionInfo[name];\n            }\n        });\n\n        var layoutRect = getLayoutRect(\n            layoutParams,\n            ecSize,\n            dataZoomModel.padding\n        );\n\n        this._location = {x: layoutRect.x, y: layoutRect.y};\n        this._size = [layoutRect.width, layoutRect.height];\n        this._orient === VERTICAL && this._size.reverse();\n    },\n\n    /**\n     * @private\n     */\n    _positionGroup: function () {\n        var thisGroup = this.group;\n        var location = this._location;\n        var orient = this._orient;\n\n        // Just use the first axis to determine mapping.\n        var targetAxisModel = this.dataZoomModel.getFirstTargetAxisModel();\n        var inverse = targetAxisModel && targetAxisModel.get('inverse');\n\n        var barGroup = this._displayables.barGroup;\n        var otherAxisInverse = (this._dataShadowInfo || {}).otherAxisInverse;\n\n        // Transform barGroup.\n        barGroup.attr(\n            (orient === HORIZONTAL && !inverse)\n            ? {scale: otherAxisInverse ? [1, 1] : [1, -1]}\n            : (orient === HORIZONTAL && inverse)\n            ? {scale: otherAxisInverse ? [-1, 1] : [-1, -1]}\n            : (orient === VERTICAL && !inverse)\n            ? {scale: otherAxisInverse ? [1, -1] : [1, 1], rotation: Math.PI / 2}\n            // Dont use Math.PI, considering shadow direction.\n            : {scale: otherAxisInverse ? [-1, -1] : [-1, 1], rotation: Math.PI / 2}\n        );\n\n        // Position barGroup\n        var rect = thisGroup.getBoundingRect([barGroup]);\n        thisGroup.attr('position', [location.x - rect.x, location.y - rect.y]);\n    },\n\n    /**\n     * @private\n     */\n    _getViewExtent: function () {\n        return [0, this._size[0]];\n    },\n\n    _renderBackground: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var size = this._size;\n        var barGroup = this._displayables.barGroup;\n\n        barGroup.add(new Rect$2({\n            silent: true,\n            shape: {\n                x: 0, y: 0, width: size[0], height: size[1]\n            },\n            style: {\n                fill: dataZoomModel.get('backgroundColor')\n            },\n            z2: -40\n        }));\n\n        // Click panel, over shadow, below handles.\n        barGroup.add(new Rect$2({\n            shape: {\n                x: 0, y: 0, width: size[0], height: size[1]\n            },\n            style: {\n                fill: 'transparent'\n            },\n            z2: 0,\n            onclick: bind(this._onClickPanelClick, this)\n        }));\n    },\n\n    _renderDataShadow: function () {\n        var info = this._dataShadowInfo = this._prepareDataShadowInfo();\n\n        if (!info) {\n            return;\n        }\n\n        var size = this._size;\n        var seriesModel = info.series;\n        var data = seriesModel.getRawData();\n\n        var otherDim = seriesModel.getShadowDim\n            ? seriesModel.getShadowDim() // @see candlestick\n            : info.otherDim;\n\n        if (otherDim == null) {\n            return;\n        }\n\n        var otherDataExtent = data.getDataExtent(otherDim);\n        // Nice extent.\n        var otherOffset = (otherDataExtent[1] - otherDataExtent[0]) * 0.3;\n        otherDataExtent = [\n            otherDataExtent[0] - otherOffset,\n            otherDataExtent[1] + otherOffset\n        ];\n        var otherShadowExtent = [0, size[1]];\n\n        var thisShadowExtent = [0, size[0]];\n\n        var areaPoints = [[size[0], 0], [0, 0]];\n        var linePoints = [];\n        var step = thisShadowExtent[1] / (data.count() - 1);\n        var thisCoord = 0;\n\n        // Optimize for large data shadow\n        var stride = Math.round(data.count() / size[0]);\n        var lastIsEmpty;\n        data.each([otherDim], function (value, index) {\n            if (stride > 0 && (index % stride)) {\n                thisCoord += step;\n                return;\n            }\n\n            // FIXME\n            // Should consider axis.min/axis.max when drawing dataShadow.\n\n            // FIXME\n            // 应该使用统一的空判断？还是在list里进行空判断？\n            var isEmpty = value == null || isNaN(value) || value === '';\n            // See #4235.\n            var otherCoord = isEmpty\n                ? 0 : linearMap$1(value, otherDataExtent, otherShadowExtent, true);\n\n            // Attempt to draw data shadow precisely when there are empty value.\n            if (isEmpty && !lastIsEmpty && index) {\n                areaPoints.push([areaPoints[areaPoints.length - 1][0], 0]);\n                linePoints.push([linePoints[linePoints.length - 1][0], 0]);\n            }\n            else if (!isEmpty && lastIsEmpty) {\n                areaPoints.push([thisCoord, 0]);\n                linePoints.push([thisCoord, 0]);\n            }\n\n            areaPoints.push([thisCoord, otherCoord]);\n            linePoints.push([thisCoord, otherCoord]);\n\n            thisCoord += step;\n            lastIsEmpty = isEmpty;\n        });\n\n        var dataZoomModel = this.dataZoomModel;\n        // var dataBackgroundModel = dataZoomModel.getModel('dataBackground');\n        this._displayables.barGroup.add(new Polygon({\n            shape: {points: areaPoints},\n            style: defaults(\n                {fill: dataZoomModel.get('dataBackgroundColor')},\n                dataZoomModel.getModel('dataBackground.areaStyle').getAreaStyle()\n            ),\n            silent: true,\n            z2: -20\n        }));\n        this._displayables.barGroup.add(new Polyline({\n            shape: {points: linePoints},\n            style: dataZoomModel.getModel('dataBackground.lineStyle').getLineStyle(),\n            silent: true,\n            z2: -19\n        }));\n    },\n\n    _prepareDataShadowInfo: function () {\n        var dataZoomModel = this.dataZoomModel;\n        var showDataShadow = dataZoomModel.get('showDataShadow');\n\n        if (showDataShadow === false) {\n            return;\n        }\n\n        // Find a representative series.\n        var result;\n        var ecModel = this.ecModel;\n\n        dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {\n            var seriesModels = dataZoomModel\n                .getAxisProxy(dimNames.name, axisIndex)\n                .getTargetSeriesModels();\n\n            each$1(seriesModels, function (seriesModel) {\n                if (result) {\n                    return;\n                }\n\n                if (showDataShadow !== true && indexOf(\n                        SHOW_DATA_SHADOW_SERIES_TYPE, seriesModel.get('type')\n                    ) < 0\n                ) {\n                    return;\n                }\n\n                var thisAxis = ecModel.getComponent(dimNames.axis, axisIndex).axis;\n                var otherDim = getOtherDim(dimNames.name);\n                var otherAxisInverse;\n                var coordSys = seriesModel.coordinateSystem;\n\n                if (otherDim != null && coordSys.getOtherAxis) {\n                    otherAxisInverse = coordSys.getOtherAxis(thisAxis).inverse;\n                }\n\n                otherDim = seriesModel.getData().mapDimension(otherDim);\n\n                result = {\n                    thisAxis: thisAxis,\n                    series: seriesModel,\n                    thisDim: dimNames.name,\n                    otherDim: otherDim,\n                    otherAxisInverse: otherAxisInverse\n                };\n\n            }, this);\n\n        }, this);\n\n        return result;\n    },\n\n    _renderHandle: function () {\n        var displaybles = this._displayables;\n        var handles = displaybles.handles = [];\n        var handleLabels = displaybles.handleLabels = [];\n        var barGroup = this._displayables.barGroup;\n        var size = this._size;\n        var dataZoomModel = this.dataZoomModel;\n\n        barGroup.add(displaybles.filler = new Rect$2({\n            draggable: true,\n            cursor: getCursor(this._orient),\n            drift: bind$4(this._onDragMove, this, 'all'),\n            onmousemove: function (e) {\n                // Fot mobile devicem, prevent screen slider on the button.\n                stop(e.event);\n            },\n            ondragstart: bind$4(this._showDataInfo, this, true),\n            ondragend: bind$4(this._onDragEnd, this),\n            onmouseover: bind$4(this._showDataInfo, this, true),\n            onmouseout: bind$4(this._showDataInfo, this, false),\n            style: {\n                fill: dataZoomModel.get('fillerColor'),\n                textPosition: 'inside'\n            }\n        }));\n\n        // Frame border.\n        barGroup.add(new Rect$2(subPixelOptimizeRect({\n            silent: true,\n            shape: {\n                x: 0,\n                y: 0,\n                width: size[0],\n                height: size[1]\n            },\n            style: {\n                stroke: dataZoomModel.get('dataBackgroundColor')\n                    || dataZoomModel.get('borderColor'),\n                lineWidth: DEFAULT_FRAME_BORDER_WIDTH,\n                fill: 'rgba(0,0,0,0)'\n            }\n        })));\n\n        each$23([0, 1], function (handleIndex) {\n            var path = createIcon(\n                dataZoomModel.get('handleIcon'),\n                {\n                    cursor: getCursor(this._orient),\n                    draggable: true,\n                    drift: bind$4(this._onDragMove, this, handleIndex),\n                    onmousemove: function (e) {\n                        // Fot mobile devicem, prevent screen slider on the button.\n                        stop(e.event);\n                    },\n                    ondragend: bind$4(this._onDragEnd, this),\n                    onmouseover: bind$4(this._showDataInfo, this, true),\n                    onmouseout: bind$4(this._showDataInfo, this, false)\n                },\n                {x: -1, y: 0, width: 2, height: 2}\n            );\n\n            var bRect = path.getBoundingRect();\n            this._handleHeight = parsePercent$1(dataZoomModel.get('handleSize'), this._size[1]);\n            this._handleWidth = bRect.width / bRect.height * this._handleHeight;\n\n            path.setStyle(dataZoomModel.getModel('handleStyle').getItemStyle());\n            var handleColor = dataZoomModel.get('handleColor');\n            // Compatitable with previous version\n            if (handleColor != null) {\n                path.style.fill = handleColor;\n            }\n\n            barGroup.add(handles[handleIndex] = path);\n\n            var textStyleModel = dataZoomModel.textStyleModel;\n\n            this.group.add(\n                handleLabels[handleIndex] = new Text({\n                silent: true,\n                invisible: true,\n                style: {\n                    x: 0, y: 0, text: '',\n                    textVerticalAlign: 'middle',\n                    textAlign: 'center',\n                    textFill: textStyleModel.getTextColor(),\n                    textFont: textStyleModel.getFont()\n                },\n                z2: 10\n            }));\n\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _resetInterval: function () {\n        var range = this._range = this.dataZoomModel.getPercentRange();\n        var viewExtent = this._getViewExtent();\n\n        this._handleEnds = [\n            linearMap$1(range[0], [0, 100], viewExtent, true),\n            linearMap$1(range[1], [0, 100], viewExtent, true)\n        ];\n    },\n\n    /**\n     * @private\n     * @param {(number|string)} handleIndex 0 or 1 or 'all'\n     * @param {number} delta\n     * @return {boolean} changed\n     */\n    _updateInterval: function (handleIndex, delta) {\n        var dataZoomModel = this.dataZoomModel;\n        var handleEnds = this._handleEnds;\n        var viewExtend = this._getViewExtent();\n        var minMaxSpan = dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan();\n        var percentExtent = [0, 100];\n\n        sliderMove(\n            delta,\n            handleEnds,\n            viewExtend,\n            dataZoomModel.get('zoomLock') ? 'all' : handleIndex,\n            minMaxSpan.minSpan != null\n                ? linearMap$1(minMaxSpan.minSpan, percentExtent, viewExtend, true) : null,\n            minMaxSpan.maxSpan != null\n                ? linearMap$1(minMaxSpan.maxSpan, percentExtent, viewExtend, true) : null\n        );\n\n        var lastRange = this._range;\n        var range = this._range = asc$2([\n            linearMap$1(handleEnds[0], viewExtend, percentExtent, true),\n            linearMap$1(handleEnds[1], viewExtend, percentExtent, true)\n        ]);\n\n        return !lastRange || lastRange[0] !== range[0] || lastRange[1] !== range[1];\n    },\n\n    /**\n     * @private\n     */\n    _updateView: function (nonRealtime) {\n        var displaybles = this._displayables;\n        var handleEnds = this._handleEnds;\n        var handleInterval = asc$2(handleEnds.slice());\n        var size = this._size;\n\n        each$23([0, 1], function (handleIndex) {\n            // Handles\n            var handle = displaybles.handles[handleIndex];\n            var handleHeight = this._handleHeight;\n            handle.attr({\n                scale: [handleHeight / 2, handleHeight / 2],\n                position: [handleEnds[handleIndex], size[1] / 2 - handleHeight / 2]\n            });\n        }, this);\n\n        // Filler\n        displaybles.filler.setShape({\n            x: handleInterval[0],\n            y: 0,\n            width: handleInterval[1] - handleInterval[0],\n            height: size[1]\n        });\n\n        this._updateDataInfo(nonRealtime);\n    },\n\n    /**\n     * @private\n     */\n    _updateDataInfo: function (nonRealtime) {\n        var dataZoomModel = this.dataZoomModel;\n        var displaybles = this._displayables;\n        var handleLabels = displaybles.handleLabels;\n        var orient = this._orient;\n        var labelTexts = ['', ''];\n\n        // FIXME\n        // date型，支持formatter，autoformatter（ec2 date.getAutoFormatter）\n        if (dataZoomModel.get('showDetail')) {\n            var axisProxy = dataZoomModel.findRepresentativeAxisProxy();\n\n            if (axisProxy) {\n                var axis = axisProxy.getAxisModel().axis;\n                var range = this._range;\n\n                var dataInterval = nonRealtime\n                    // See #4434, data and axis are not processed and reset yet in non-realtime mode.\n                    ? axisProxy.calculateDataWindow({\n                        start: range[0], end: range[1]\n                    }).valueWindow\n                    : axisProxy.getDataValueWindow();\n\n                labelTexts = [\n                    this._formatLabel(dataInterval[0], axis),\n                    this._formatLabel(dataInterval[1], axis)\n                ];\n            }\n        }\n\n        var orderedHandleEnds = asc$2(this._handleEnds.slice());\n\n        setLabel.call(this, 0);\n        setLabel.call(this, 1);\n\n        function setLabel(handleIndex) {\n            // Label\n            // Text should not transform by barGroup.\n            // Ignore handlers transform\n            var barTransform = getTransform(\n                displaybles.handles[handleIndex].parent, this.group\n            );\n            var direction = transformDirection(\n                handleIndex === 0 ? 'right' : 'left', barTransform\n            );\n            var offset = this._handleWidth / 2 + LABEL_GAP;\n            var textPoint = applyTransform$1(\n                [\n                    orderedHandleEnds[handleIndex] + (handleIndex === 0 ? -offset : offset),\n                    this._size[1] / 2\n                ],\n                barTransform\n            );\n            handleLabels[handleIndex].setStyle({\n                x: textPoint[0],\n                y: textPoint[1],\n                textVerticalAlign: orient === HORIZONTAL ? 'middle' : direction,\n                textAlign: orient === HORIZONTAL ? direction : 'center',\n                text: labelTexts[handleIndex]\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _formatLabel: function (value, axis) {\n        var dataZoomModel = this.dataZoomModel;\n        var labelFormatter = dataZoomModel.get('labelFormatter');\n\n        var labelPrecision = dataZoomModel.get('labelPrecision');\n        if (labelPrecision == null || labelPrecision === 'auto') {\n            labelPrecision = axis.getPixelPrecision();\n        }\n\n        var valueStr = (value == null || isNaN(value))\n            ? ''\n            // FIXME Glue code\n            : (axis.type === 'category' || axis.type === 'time')\n                ? axis.scale.getLabel(Math.round(value))\n                // param of toFixed should less then 20.\n                : value.toFixed(Math.min(labelPrecision, 20));\n\n        return isFunction$1(labelFormatter)\n            ? labelFormatter(value, valueStr)\n            : isString(labelFormatter)\n            ? labelFormatter.replace('{value}', valueStr)\n            : valueStr;\n    },\n\n    /**\n     * @private\n     * @param {boolean} showOrHide true: show, false: hide\n     */\n    _showDataInfo: function (showOrHide) {\n        // Always show when drgging.\n        showOrHide = this._dragging || showOrHide;\n\n        var handleLabels = this._displayables.handleLabels;\n        handleLabels[0].attr('invisible', !showOrHide);\n        handleLabels[1].attr('invisible', !showOrHide);\n    },\n\n    _onDragMove: function (handleIndex, dx, dy) {\n        this._dragging = true;\n\n        // Transform dx, dy to bar coordination.\n        var barTransform = this._displayables.barGroup.getLocalTransform();\n        var vertex = applyTransform$1([dx, dy], barTransform, true);\n\n        var changed = this._updateInterval(handleIndex, vertex[0]);\n\n        var realtime = this.dataZoomModel.get('realtime');\n\n        this._updateView(!realtime);\n\n        // Avoid dispatch dataZoom repeatly but range not changed,\n        // which cause bad visual effect when progressive enabled.\n        changed && realtime && this._dispatchZoomAction();\n    },\n\n    _onDragEnd: function () {\n        this._dragging = false;\n        this._showDataInfo(false);\n\n        // While in realtime mode and stream mode, dispatch action when\n        // drag end will cause the whole view rerender, which is unnecessary.\n        var realtime = this.dataZoomModel.get('realtime');\n        !realtime && this._dispatchZoomAction();\n    },\n\n    _onClickPanelClick: function (e) {\n        var size = this._size;\n        var localPoint = this._displayables.barGroup.transformCoordToLocal(e.offsetX, e.offsetY);\n\n        if (localPoint[0] < 0 || localPoint[0] > size[0]\n            || localPoint[1] < 0 || localPoint[1] > size[1]\n        ) {\n            return;\n        }\n\n        var handleEnds = this._handleEnds;\n        var center = (handleEnds[0] + handleEnds[1]) / 2;\n\n        var changed = this._updateInterval('all', localPoint[0] - center);\n        this._updateView();\n        changed && this._dispatchZoomAction();\n    },\n\n    /**\n     * This action will be throttled.\n     * @private\n     */\n    _dispatchZoomAction: function () {\n        var range = this._range;\n\n        this.api.dispatchAction({\n            type: 'dataZoom',\n            from: this.uid,\n            dataZoomId: this.dataZoomModel.id,\n            start: range[0],\n            end: range[1]\n        });\n    },\n\n    /**\n     * @private\n     */\n    _findCoordRect: function () {\n        // Find the grid coresponding to the first axis referred by dataZoom.\n        var rect;\n        each$23(this.getTargetCoordInfo(), function (coordInfoList) {\n            if (!rect && coordInfoList.length) {\n                var coordSys = coordInfoList[0].model.coordinateSystem;\n                rect = coordSys.getRect && coordSys.getRect();\n            }\n        });\n        if (!rect) {\n            var width = this.api.getWidth();\n            var height = this.api.getHeight();\n            rect = {\n                x: width * 0.2,\n                y: height * 0.2,\n                width: width * 0.6,\n                height: height * 0.6\n            };\n        }\n\n        return rect;\n    }\n\n});\n\nfunction getOtherDim(thisDim) {\n    // FIXME\n    // 这个逻辑和getOtherAxis里一致，但是写在这里是否不好\n    var map$$1 = {x: 'y', y: 'x', radius: 'angle', angle: 'radius'};\n    return map$$1[thisDim];\n}\n\nfunction getCursor(orient) {\n    return orient === 'vertical' ? 'ns-resize' : 'ew-resize';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomModel.extend({\n\n    type: 'dataZoom.inside',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        disabled: false,   // Whether disable this inside zoom.\n        zoomLock: false,   // Whether disable zoom but only pan.\n        zoomOnMouseWheel: true, // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        moveOnMouseMove: true,   // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        moveOnMouseWheel: false, // Can be: true / false / 'shift' / 'ctrl' / 'alt'.\n        preventDefaultMouseMove: true\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Only create one roam controller for each coordinate system.\n// one roam controller might be refered by two inside data zoom\n// components (for example, one for x and one for y). When user\n// pan or zoom, only dispatch one action for those data zoom\n// components.\n\nvar ATTR$1 = '\\0_ec_dataZoom_roams';\n\n\n/**\n * @public\n * @param {module:echarts/ExtensionAPI} api\n * @param {Object} dataZoomInfo\n * @param {string} dataZoomInfo.coordId\n * @param {Function} dataZoomInfo.containsPoint\n * @param {Array.<string>} dataZoomInfo.allCoordIds\n * @param {string} dataZoomInfo.dataZoomId\n * @param {Object} dataZoomInfo.getRange\n * @param {Function} dataZoomInfo.getRange.pan\n * @param {Function} dataZoomInfo.getRange.zoom\n * @param {Function} dataZoomInfo.getRange.scrollMove\n * @param {boolean} dataZoomInfo.dataZoomModel\n */\nfunction register$2(api, dataZoomInfo) {\n    var store = giveStore(api);\n    var theDataZoomId = dataZoomInfo.dataZoomId;\n    var theCoordId = dataZoomInfo.coordId;\n\n    // Do clean when a dataZoom changes its target coordnate system.\n    // Avoid memory leak, dispose all not-used-registered.\n    each$1(store, function (record, coordId) {\n        var dataZoomInfos = record.dataZoomInfos;\n        if (dataZoomInfos[theDataZoomId]\n            && indexOf(dataZoomInfo.allCoordIds, theCoordId) < 0\n        ) {\n            delete dataZoomInfos[theDataZoomId];\n            record.count--;\n        }\n    });\n\n    cleanStore(store);\n\n    var record = store[theCoordId];\n    // Create if needed.\n    if (!record) {\n        record = store[theCoordId] = {\n            coordId: theCoordId,\n            dataZoomInfos: {},\n            count: 0\n        };\n        record.controller = createController(api, record);\n        record.dispatchAction = curry(dispatchAction$1, api);\n    }\n\n    // Update reference of dataZoom.\n    !(record.dataZoomInfos[theDataZoomId]) && record.count++;\n    record.dataZoomInfos[theDataZoomId] = dataZoomInfo;\n\n    var controllerParams = mergeControllerParams(record.dataZoomInfos);\n    record.controller.enable(controllerParams.controlType, controllerParams.opt);\n\n    // Consider resize, area should be always updated.\n    record.controller.setPointerChecker(dataZoomInfo.containsPoint);\n\n    // Update throttle.\n    createOrUpdate(\n        record,\n        'dispatchAction',\n        dataZoomInfo.dataZoomModel.get('throttle', true),\n        'fixRate'\n    );\n}\n\n/**\n * @public\n * @param {module:echarts/ExtensionAPI} api\n * @param {string} dataZoomId\n */\nfunction unregister$1(api, dataZoomId) {\n    var store = giveStore(api);\n\n    each$1(store, function (record) {\n        record.controller.dispose();\n        var dataZoomInfos = record.dataZoomInfos;\n        if (dataZoomInfos[dataZoomId]) {\n            delete dataZoomInfos[dataZoomId];\n            record.count--;\n        }\n    });\n\n    cleanStore(store);\n}\n\n/**\n * @public\n */\nfunction generateCoordId(coordModel) {\n    return coordModel.type + '\\0_' + coordModel.id;\n}\n\n/**\n * Key: coordId, value: {dataZoomInfos: [], count, controller}\n * @type {Array.<Object>}\n */\nfunction giveStore(api) {\n    // Mount store on zrender instance, so that we do not\n    // need to worry about dispose.\n    var zr = api.getZr();\n    return zr[ATTR$1] || (zr[ATTR$1] = {});\n}\n\nfunction createController(api, newRecord) {\n    var controller = new RoamController(api.getZr());\n\n    each$1(['pan', 'zoom', 'scrollMove'], function (eventName) {\n        controller.on(eventName, function (event) {\n            var batch = [];\n\n            each$1(newRecord.dataZoomInfos, function (info) {\n                // Check whether the behaviors (zoomOnMouseWheel, moveOnMouseMove,\n                // moveOnMouseWheel, ...) enabled.\n                if (!event.isAvailableBehavior(info.dataZoomModel.option)) {\n                    return;\n                }\n\n                var method = (info.getRange || {})[eventName];\n                var range = method && method(newRecord.controller, event);\n\n                !info.dataZoomModel.get('disabled', true) && range && batch.push({\n                    dataZoomId: info.dataZoomId,\n                    start: range[0],\n                    end: range[1]\n                });\n            });\n\n            batch.length && newRecord.dispatchAction(batch);\n        });\n    });\n\n    return controller;\n}\n\nfunction cleanStore(store) {\n    each$1(store, function (record, coordId) {\n        if (!record.count) {\n            record.controller.dispose();\n            delete store[coordId];\n        }\n    });\n}\n\n/**\n * This action will be throttled.\n */\nfunction dispatchAction$1(api, batch) {\n    api.dispatchAction({\n        type: 'dataZoom',\n        batch: batch\n    });\n}\n\n/**\n * Merge roamController settings when multiple dataZooms share one roamController.\n */\nfunction mergeControllerParams(dataZoomInfos) {\n    var controlType;\n    // DO NOT use reserved word (true, false, undefined) as key literally. Even if encapsulated\n    // as string, it is probably revert to reserved word by compress tool. See #7411.\n    var prefix = 'type_';\n    var typePriority = {\n        'type_true': 2,\n        'type_move': 1,\n        'type_false': 0,\n        'type_undefined': -1\n    };\n    var preventDefaultMouseMove = true;\n\n    each$1(dataZoomInfos, function (dataZoomInfo) {\n        var dataZoomModel = dataZoomInfo.dataZoomModel;\n        var oneType = dataZoomModel.get('disabled', true)\n            ? false\n            : dataZoomModel.get('zoomLock', true)\n            ? 'move'\n            : true;\n        if (typePriority[prefix + oneType] > typePriority[prefix + controlType]) {\n            controlType = oneType;\n        }\n\n        // Prevent default move event by default. If one false, do not prevent. Otherwise\n        // users may be confused why it does not work when multiple insideZooms exist.\n        preventDefaultMouseMove &= dataZoomModel.get('preventDefaultMouseMove', true);\n    });\n\n    return {\n        controlType: controlType,\n        opt: {\n            // RoamController will enable all of these functionalities,\n            // and the final behavior is determined by its event listener\n            // provided by each inside zoom.\n            zoomOnMouseWheel: true,\n            moveOnMouseMove: true,\n            moveOnMouseWheel: true,\n            preventDefaultMouseMove: !!preventDefaultMouseMove\n        }\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$5 = bind;\n\nvar InsideZoomView = DataZoomView.extend({\n\n    type: 'dataZoom.inside',\n\n    /**\n     * @override\n     */\n    init: function (ecModel, api) {\n        /**\n         * 'throttle' is used in this.dispatchAction, so we save range\n         * to avoid missing some 'pan' info.\n         * @private\n         * @type {Array.<number>}\n         */\n        this._range;\n    },\n\n    /**\n     * @override\n     */\n    render: function (dataZoomModel, ecModel, api, payload) {\n        InsideZoomView.superApply(this, 'render', arguments);\n\n        // Hance the `throttle` util ensures to preserve command order,\n        // here simply updating range all the time will not cause missing\n        // any of the the roam change.\n        this._range = dataZoomModel.getPercentRange();\n\n        // Reset controllers.\n        each$1(this.getTargetCoordInfo(), function (coordInfoList, coordSysName) {\n\n            var allCoordIds = map(coordInfoList, function (coordInfo) {\n                return generateCoordId(coordInfo.model);\n            });\n\n            each$1(coordInfoList, function (coordInfo) {\n                var coordModel = coordInfo.model;\n\n                var getRange = {};\n                each$1(['pan', 'zoom', 'scrollMove'], function (eventName) {\n                    getRange[eventName] = bind$5(roamHandlers[eventName], this, coordInfo, coordSysName);\n                }, this);\n\n                register$2(\n                    api,\n                    {\n                        coordId: generateCoordId(coordModel),\n                        allCoordIds: allCoordIds,\n                        containsPoint: function (e, x, y) {\n                            return coordModel.coordinateSystem.containPoint([x, y]);\n                        },\n                        dataZoomId: dataZoomModel.id,\n                        dataZoomModel: dataZoomModel,\n                        getRange: getRange\n                    }\n                );\n            }, this);\n\n        }, this);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        unregister$1(this.api, this.dataZoomModel.id);\n        InsideZoomView.superApply(this, 'dispose', arguments);\n        this._range = null;\n    }\n\n});\n\nvar roamHandlers = {\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    zoom: function (coordInfo, coordSysName, controller, e) {\n        var lastRange = this._range;\n        var range = lastRange.slice();\n\n        // Calculate transform by the first axis.\n        var axisModel = coordInfo.axisModels[0];\n        if (!axisModel) {\n            return;\n        }\n\n        var directionInfo = getDirectionInfo[coordSysName](\n            null, [e.originX, e.originY], axisModel, controller, coordInfo\n        );\n        var percentPoint = (\n            directionInfo.signal > 0\n                ? (directionInfo.pixelStart + directionInfo.pixelLength - directionInfo.pixel)\n                : (directionInfo.pixel - directionInfo.pixelStart)\n            ) / directionInfo.pixelLength * (range[1] - range[0]) + range[0];\n\n        var scale = Math.max(1 / e.scale, 0);\n        range[0] = (range[0] - percentPoint) * scale + percentPoint;\n        range[1] = (range[1] - percentPoint) * scale + percentPoint;\n\n        // Restrict range.\n        var minMaxSpan = this.dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan();\n\n        sliderMove(0, range, [0, 100], 0, minMaxSpan.minSpan, minMaxSpan.maxSpan);\n\n        this._range = range;\n\n        if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) {\n            return range;\n        }\n    },\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    pan: makeMover(function (range, axisModel, coordInfo, coordSysName, controller, e) {\n        var directionInfo = getDirectionInfo[coordSysName](\n            [e.oldX, e.oldY], [e.newX, e.newY], axisModel, controller, coordInfo\n        );\n\n        return directionInfo.signal\n            * (range[1] - range[0])\n            * directionInfo.pixel / directionInfo.pixelLength;\n    }),\n\n    /**\n     * @this {module:echarts/component/dataZoom/InsideZoomView}\n     */\n    scrollMove: makeMover(function (range, axisModel, coordInfo, coordSysName, controller, e) {\n        var directionInfo = getDirectionInfo[coordSysName](\n            [0, 0], [e.scrollDelta, e.scrollDelta], axisModel, controller, coordInfo\n        );\n        return directionInfo.signal * (range[1] - range[0]) * e.scrollDelta;\n    })\n};\n\nfunction makeMover(getPercentDelta) {\n    return function (coordInfo, coordSysName, controller, e) {\n        var lastRange = this._range;\n        var range = lastRange.slice();\n\n        // Calculate transform by the first axis.\n        var axisModel = coordInfo.axisModels[0];\n        if (!axisModel) {\n            return;\n        }\n\n        var percentDelta = getPercentDelta(\n            range, axisModel, coordInfo, coordSysName, controller, e\n        );\n\n        sliderMove(percentDelta, range, [0, 100], 'all');\n\n        this._range = range;\n\n        if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) {\n            return range;\n        }\n    };\n}\n\nvar getDirectionInfo = {\n\n    grid: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var ret = {};\n        var rect = coordInfo.model.coordinateSystem.getRect();\n        oldPoint = oldPoint || [0, 0];\n\n        if (axis.dim === 'x') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            ret.pixelLength = rect.width;\n            ret.pixelStart = rect.x;\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // axis.dim === 'y'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            ret.pixelLength = rect.height;\n            ret.pixelStart = rect.y;\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    },\n\n    polar: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var ret = {};\n        var polar = coordInfo.model.coordinateSystem;\n        var radiusExtent = polar.getRadiusAxis().getExtent();\n        var angleExtent = polar.getAngleAxis().getExtent();\n\n        oldPoint = oldPoint ? polar.pointToCoord(oldPoint) : [0, 0];\n        newPoint = polar.pointToCoord(newPoint);\n\n        if (axisModel.mainType === 'radiusAxis') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            // ret.pixelLength = Math.abs(radiusExtent[1] - radiusExtent[0]);\n            // ret.pixelStart = Math.min(radiusExtent[0], radiusExtent[1]);\n            ret.pixelLength = radiusExtent[1] - radiusExtent[0];\n            ret.pixelStart = radiusExtent[0];\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // 'angleAxis'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            // ret.pixelLength = Math.abs(angleExtent[1] - angleExtent[0]);\n            // ret.pixelStart = Math.min(angleExtent[0], angleExtent[1]);\n            ret.pixelLength = angleExtent[1] - angleExtent[0];\n            ret.pixelStart = angleExtent[0];\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    },\n\n    singleAxis: function (oldPoint, newPoint, axisModel, controller, coordInfo) {\n        var axis = axisModel.axis;\n        var rect = coordInfo.model.coordinateSystem.getRect();\n        var ret = {};\n\n        oldPoint = oldPoint || [0, 0];\n\n        if (axis.orient === 'horizontal') {\n            ret.pixel = newPoint[0] - oldPoint[0];\n            ret.pixelLength = rect.width;\n            ret.pixelStart = rect.x;\n            ret.signal = axis.inverse ? 1 : -1;\n        }\n        else { // 'vertical'\n            ret.pixel = newPoint[1] - oldPoint[1];\n            ret.pixelLength = rect.height;\n            ret.pixelStart = rect.y;\n            ret.signal = axis.inverse ? -1 : 1;\n        }\n\n        return ret;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterProcessor({\n\n    // `dataZoomProcessor` will only be performed in needed series. Consider if\n    // there is a line series and a pie series, it is better not to update the\n    // line series if only pie series is needed to be updated.\n    getTargetSeries: function (ecModel) {\n        var seriesModelMap = createHashMap();\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                var axisProxy = dataZoomModel.getAxisProxy(dimNames.name, axisIndex);\n                each$1(axisProxy.getTargetSeriesModels(), function (seriesModel) {\n                    seriesModelMap.set(seriesModel.uid, seriesModel);\n                });\n            });\n        });\n\n        return seriesModelMap;\n    },\n\n    modifyOutputEnd: true,\n\n    // Consider appendData, where filter should be performed. Because data process is\n    // in block mode currently, it is not need to worry about that the overallProgress\n    // execute every frame.\n    overallReset: function (ecModel, api) {\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            // We calculate window and reset axis here but not in model\n            // init stage and not after action dispatch handler, because\n            // reset should be called after seriesData.restoreData.\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                dataZoomModel.getAxisProxy(dimNames.name, axisIndex).reset(dataZoomModel, api);\n            });\n\n            // Caution: data zoom filtering is order sensitive when using\n            // percent range and no min/max/scale set on axis.\n            // For example, we have dataZoom definition:\n            // [\n            //      {xAxisIndex: 0, start: 30, end: 70},\n            //      {yAxisIndex: 0, start: 20, end: 80}\n            // ]\n            // In this case, [20, 80] of y-dataZoom should be based on data\n            // that have filtered by x-dataZoom using range of [30, 70],\n            // but should not be based on full raw data. Thus sliding\n            // x-dataZoom will change both ranges of xAxis and yAxis,\n            // while sliding y-dataZoom will only change the range of yAxis.\n            // So we should filter x-axis after reset x-axis immediately,\n            // and then reset y-axis and filter y-axis.\n            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel) {\n                dataZoomModel.getAxisProxy(dimNames.name, axisIndex).filterData(dataZoomModel, api);\n            });\n        });\n\n        ecModel.eachComponent('dataZoom', function (dataZoomModel) {\n            // Fullfill all of the range props so that user\n            // is able to get them from chart.getOption().\n            var axisProxy = dataZoomModel.findRepresentativeAxisProxy();\n            var percentRange = axisProxy.getDataPercentWindow();\n            var valueRange = axisProxy.getDataValueWindow();\n\n            dataZoomModel.setRawRange({\n                start: percentRange[0],\n                end: percentRange[1],\n                startValue: valueRange[0],\n                endValue: valueRange[1]\n            }, true);\n        });\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterAction('dataZoom', function (payload, ecModel) {\n\n    var linkedNodesFinder = createLinkedNodesFinder(\n        bind(ecModel.eachComponent, ecModel, 'dataZoom'),\n        eachAxisDim$1,\n        function (model, dimNames) {\n            return model.get(dimNames.axisIndex);\n        }\n    );\n\n    var effectedModels = [];\n\n    ecModel.eachComponent(\n        {mainType: 'dataZoom', query: payload},\n        function (model, index) {\n            effectedModels.push.apply(\n                effectedModels, linkedNodesFinder(model).nodes\n            );\n        }\n    );\n\n    each$1(effectedModels, function (dataZoomModel, index) {\n        dataZoomModel.setRawRange({\n            start: payload.start,\n            end: payload.end,\n            startValue: payload.startValue,\n            endValue: payload.endValue\n        });\n    });\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$24 = each$1;\n\nvar preprocessor$2 = function (option) {\n    var visualMap = option && option.visualMap;\n\n    if (!isArray(visualMap)) {\n        visualMap = visualMap ? [visualMap] : [];\n    }\n\n    each$24(visualMap, function (opt) {\n        if (!opt) {\n            return;\n        }\n\n        // rename splitList to pieces\n        if (has$1(opt, 'splitList') && !has$1(opt, 'pieces')) {\n            opt.pieces = opt.splitList;\n            delete opt.splitList;\n        }\n\n        var pieces = opt.pieces;\n        if (pieces && isArray(pieces)) {\n            each$24(pieces, function (piece) {\n                if (isObject$1(piece)) {\n                    if (has$1(piece, 'start') && !has$1(piece, 'min')) {\n                        piece.min = piece.start;\n                    }\n                    if (has$1(piece, 'end') && !has$1(piece, 'max')) {\n                        piece.max = piece.end;\n                    }\n                }\n            });\n        }\n    });\n};\n\nfunction has$1(obj, name) {\n    return obj && obj.hasOwnProperty && obj.hasOwnProperty(name);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nComponentModel.registerSubTypeDefaulter('visualMap', function (option) {\n    // Compatible with ec2, when splitNumber === 0, continuous visualMap will be used.\n    return (\n            !option.categories\n            && (\n                !(\n                    option.pieces\n                        ? option.pieces.length > 0\n                        : option.splitNumber > 0\n                )\n                || option.calculable\n            )\n        )\n        ? 'continuous' : 'piecewise';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar VISUAL_PRIORITY = PRIORITY.VISUAL.COMPONENT;\n\nregisterVisual(VISUAL_PRIORITY, {\n    createOnAllSeries: true,\n    reset: function (seriesModel, ecModel) {\n        var resetDefines = [];\n        ecModel.eachComponent('visualMap', function (visualMapModel) {\n            var pipelineContext = seriesModel.pipelineContext;\n            if (!visualMapModel.isTargetSeries(seriesModel)\n                || (pipelineContext && pipelineContext.large)\n            ) {\n                return;\n            }\n\n            resetDefines.push(incrementalApplyVisual(\n                visualMapModel.stateList,\n                visualMapModel.targetVisuals,\n                bind(visualMapModel.getValueState, visualMapModel),\n                visualMapModel.getDataDimension(seriesModel.getData())\n            ));\n        });\n\n        return resetDefines;\n    }\n});\n\n// Only support color.\nregisterVisual(VISUAL_PRIORITY, {\n    createOnAllSeries: true,\n    reset: function (seriesModel, ecModel) {\n        var data = seriesModel.getData();\n        var visualMetaList = [];\n\n        ecModel.eachComponent('visualMap', function (visualMapModel) {\n            if (visualMapModel.isTargetSeries(seriesModel)) {\n                var visualMeta = visualMapModel.getVisualMeta(\n                    bind(getColorVisual, null, seriesModel, visualMapModel)\n                ) || {stops: [], outerColors: []};\n\n                var concreteDim = visualMapModel.getDataDimension(data);\n                var dimInfo = data.getDimensionInfo(concreteDim);\n                if (dimInfo != null) {\n                    // visualMeta.dimension should be dimension index, but not concrete dimension.\n                    visualMeta.dimension = dimInfo.index;\n                    visualMetaList.push(visualMeta);\n                }\n            }\n        });\n\n        // console.log(JSON.stringify(visualMetaList.map(a => a.stops)));\n        seriesModel.getData().setVisual('visualMeta', visualMetaList);\n    }\n});\n\n// FIXME\n// performance and export for heatmap?\n// value can be Infinity or -Infinity\nfunction getColorVisual(seriesModel, visualMapModel, value, valueState) {\n    var mappings = visualMapModel.targetVisuals[valueState];\n    var visualTypes = VisualMapping.prepareVisualTypes(mappings);\n    var resultVisual = {\n        color: seriesModel.getData().getVisual('color') // default color.\n    };\n\n    for (var i = 0, len = visualTypes.length; i < len; i++) {\n        var type = visualTypes[i];\n        var mapping = mappings[\n            type === 'opacity' ? '__alphaForOpacity' : type\n        ];\n        mapping && mapping.applyVisual(value, getVisual, setVisual);\n    }\n\n    return resultVisual.color;\n\n    function getVisual(key) {\n        return resultVisual[key];\n    }\n\n    function setVisual(key, value) {\n        resultVisual[key] = value;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @file Visual mapping.\n */\n\nvar visualDefault = {\n\n    /**\n     * @public\n     */\n    get: function (visualType, key, isCategory) {\n        var value = clone(\n            (defaultOption$3[visualType] || {})[key]\n        );\n\n        return isCategory\n            ? (isArray(value) ? value[value.length - 1] : value)\n            : value;\n    }\n\n};\n\nvar defaultOption$3 = {\n\n    color: {\n        active: ['#006edd', '#e0ffff'],\n        inactive: ['rgba(0,0,0,0)']\n    },\n\n    colorHue: {\n        active: [0, 360],\n        inactive: [0, 0]\n    },\n\n    colorSaturation: {\n        active: [0.3, 1],\n        inactive: [0, 0]\n    },\n\n    colorLightness: {\n        active: [0.9, 0.5],\n        inactive: [0, 0]\n    },\n\n    colorAlpha: {\n        active: [0.3, 1],\n        inactive: [0, 0]\n    },\n\n    opacity: {\n        active: [0.3, 1],\n        inactive: [0, 0]\n    },\n\n    symbol: {\n        active: ['circle', 'roundRect', 'diamond'],\n        inactive: ['none']\n    },\n\n    symbolSize: {\n        active: [10, 50],\n        inactive: [0, 0]\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar mapVisual$2 = VisualMapping.mapVisual;\nvar eachVisual = VisualMapping.eachVisual;\nvar isArray$3 = isArray;\nvar each$25 = each$1;\nvar asc$3 = asc;\nvar linearMap$2 = linearMap;\nvar noop$2 = noop;\n\nvar VisualMapModel = extendComponentModel({\n\n    type: 'visualMap',\n\n    dependencies: ['series'],\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    stateList: ['inRange', 'outOfRange'],\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    replacableOptionKeys: [\n        'inRange', 'outOfRange', 'target', 'controller', 'color'\n    ],\n\n    /**\n     * [lowerBound, upperBound]\n     *\n     * @readOnly\n     * @type {Array.<number>}\n     */\n    dataBound: [-Infinity, Infinity],\n\n    /**\n     * @readOnly\n     * @type {string|Object}\n     */\n    layoutMode: {type: 'box', ignoreSize: true},\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        show: true,\n\n        zlevel: 0,\n        z: 4,\n\n        seriesIndex: 'all',     // 'all' or null/undefined: all series.\n                                // A number or an array of number: the specified series.\n\n                                // set min: 0, max: 200, only for campatible with ec2.\n                                // In fact min max should not have default value.\n        min: 0,                 // min value, must specified if pieces is not specified.\n        max: 200,               // max value, must specified if pieces is not specified.\n\n        dimension: null,\n        inRange: null,          // 'color', 'colorHue', 'colorSaturation', 'colorLightness', 'colorAlpha',\n                                // 'symbol', 'symbolSize'\n        outOfRange: null,       // 'color', 'colorHue', 'colorSaturation',\n                                // 'colorLightness', 'colorAlpha',\n                                // 'symbol', 'symbolSize'\n\n        left: 0,                // 'center' ¦ 'left' ¦ 'right' ¦ {number} (px)\n        right: null,            // The same as left.\n        top: null,              // 'top' ¦ 'bottom' ¦ 'center' ¦ {number} (px)\n        bottom: 0,              // The same as top.\n\n        itemWidth: null,\n        itemHeight: null,\n        inverse: false,\n        orient: 'vertical',        // 'horizontal' ¦ 'vertical'\n\n        backgroundColor: 'rgba(0,0,0,0)',\n        borderColor: '#ccc',       // 值域边框颜色\n        contentColor: '#5793f3',\n        inactiveColor: '#aaa',\n        borderWidth: 0,            // 值域边框线宽，单位px，默认为0（无边框）\n        padding: 5,                // 值域内边距，单位px，默认各方向内边距为5，\n                                    // 接受数组分别设定上右下左边距，同css\n        textGap: 10,               //\n        precision: 0,              // 小数精度，默认为0，无小数点\n        color: null,               //颜色（deprecated，兼容ec2，顺序同pieces，不同于inRange/outOfRange）\n\n        formatter: null,\n        text: null,                // 文本，如['高', '低']，兼容ec2，text[0]对应高值，text[1]对应低值\n        textStyle: {\n            color: '#333'          // 值域文字颜色\n        }\n    },\n\n    /**\n     * @protected\n     */\n    init: function (option, parentModel, ecModel) {\n\n        /**\n         * @private\n         * @type {Array.<number>}\n         */\n        this._dataExtent;\n\n        /**\n         * @readOnly\n         */\n        this.targetVisuals = {};\n\n        /**\n         * @readOnly\n         */\n        this.controllerVisuals = {};\n\n        /**\n         * @readOnly\n         */\n        this.textStyleModel;\n\n        /**\n         * [width, height]\n         * @readOnly\n         * @type {Array.<number>}\n         */\n        this.itemSize;\n\n        this.mergeDefaultAndTheme(option, ecModel);\n    },\n\n    /**\n     * @protected\n     */\n    optionUpdated: function (newOption, isInit) {\n        var thisOption = this.option;\n\n        // FIXME\n        // necessary?\n        // Disable realtime view update if canvas is not supported.\n        if (!env$1.canvasSupported) {\n            thisOption.realtime = false;\n        }\n\n        !isInit && replaceVisualOption(\n            thisOption, newOption, this.replacableOptionKeys\n        );\n\n        this.textStyleModel = this.getModel('textStyle');\n\n        this.resetItemSize();\n\n        this.completeVisualOption();\n    },\n\n    /**\n     * @protected\n     */\n    resetVisual: function (supplementVisualOption) {\n        var stateList = this.stateList;\n        supplementVisualOption = bind(supplementVisualOption, this);\n\n        this.controllerVisuals = createVisualMappings(\n            this.option.controller, stateList, supplementVisualOption\n        );\n        this.targetVisuals = createVisualMappings(\n            this.option.target, stateList, supplementVisualOption\n        );\n    },\n\n    /**\n     * @protected\n     * @return {Array.<number>} An array of series indices.\n     */\n    getTargetSeriesIndices: function () {\n        var optionSeriesIndex = this.option.seriesIndex;\n        var seriesIndices = [];\n\n        if (optionSeriesIndex == null || optionSeriesIndex === 'all') {\n            this.ecModel.eachSeries(function (seriesModel, index) {\n                seriesIndices.push(index);\n            });\n        }\n        else {\n            seriesIndices = normalizeToArray(optionSeriesIndex);\n        }\n\n        return seriesIndices;\n    },\n\n    /**\n     * @public\n     */\n    eachTargetSeries: function (callback, context) {\n        each$1(this.getTargetSeriesIndices(), function (seriesIndex) {\n            callback.call(context, this.ecModel.getSeriesByIndex(seriesIndex));\n        }, this);\n    },\n\n    /**\n     * @pubilc\n     */\n    isTargetSeries: function (seriesModel) {\n        var is = false;\n        this.eachTargetSeries(function (model) {\n            model === seriesModel && (is = true);\n        });\n        return is;\n    },\n\n    /**\n     * @example\n     * this.formatValueText(someVal); // format single numeric value to text.\n     * this.formatValueText(someVal, true); // format single category value to text.\n     * this.formatValueText([min, max]); // format numeric min-max to text.\n     * this.formatValueText([this.dataBound[0], max]); // using data lower bound.\n     * this.formatValueText([min, this.dataBound[1]]); // using data upper bound.\n     *\n     * @param {number|Array.<number>} value Real value, or this.dataBound[0 or 1].\n     * @param {boolean} [isCategory=false] Only available when value is number.\n     * @param {Array.<string>} edgeSymbols Open-close symbol when value is interval.\n     * @return {string}\n     * @protected\n     */\n    formatValueText: function (value, isCategory, edgeSymbols) {\n        var option = this.option;\n        var precision = option.precision;\n        var dataBound = this.dataBound;\n        var formatter = option.formatter;\n        var isMinMax;\n        var textValue;\n        edgeSymbols = edgeSymbols || ['<', '>'];\n\n        if (isArray(value)) {\n            value = value.slice();\n            isMinMax = true;\n        }\n\n        textValue = isCategory\n            ? value\n            : (isMinMax\n                ? [toFixed(value[0]), toFixed(value[1])]\n                : toFixed(value)\n            );\n\n        if (isString(formatter)) {\n            return formatter\n                .replace('{value}', isMinMax ? textValue[0] : textValue)\n                .replace('{value2}', isMinMax ? textValue[1] : textValue);\n        }\n        else if (isFunction$1(formatter)) {\n            return isMinMax\n                ? formatter(value[0], value[1])\n                : formatter(value);\n        }\n\n        if (isMinMax) {\n            if (value[0] === dataBound[0]) {\n                return edgeSymbols[0] + ' ' + textValue[1];\n            }\n            else if (value[1] === dataBound[1]) {\n                return edgeSymbols[1] + ' ' + textValue[0];\n            }\n            else {\n                return textValue[0] + ' - ' + textValue[1];\n            }\n        }\n        else { // Format single value (includes category case).\n            return textValue;\n        }\n\n        function toFixed(val) {\n            return val === dataBound[0]\n                ? 'min'\n                : val === dataBound[1]\n                ? 'max'\n                : (+val).toFixed(Math.min(precision, 20));\n        }\n    },\n\n    /**\n     * @protected\n     */\n    resetExtent: function () {\n        var thisOption = this.option;\n\n        // Can not calculate data extent by data here.\n        // Because series and data may be modified in processing stage.\n        // So we do not support the feature \"auto min/max\".\n\n        var extent = asc$3([thisOption.min, thisOption.max]);\n\n        this._dataExtent = extent;\n    },\n\n    /**\n     * @public\n     * @param {module:echarts/data/List} list\n     * @return {string} Concrete dimention. If return null/undefined,\n     *                  no dimension used.\n     */\n    getDataDimension: function (list) {\n        var optDim = this.option.dimension;\n        var listDimensions = list.dimensions;\n        if (optDim == null && !listDimensions.length) {\n            return;\n        }\n\n        if (optDim != null) {\n            return list.getDimension(optDim);\n        }\n\n        var dimNames = list.dimensions;\n        for (var i = dimNames.length - 1; i >= 0; i--) {\n            var dimName = dimNames[i];\n            var dimInfo = list.getDimensionInfo(dimName);\n            if (!dimInfo.isCalculationCoord) {\n                return dimName;\n            }\n        }\n    },\n\n    /**\n     * @public\n     * @override\n     */\n    getExtent: function () {\n        return this._dataExtent.slice();\n    },\n\n    /**\n     * @protected\n     */\n    completeVisualOption: function () {\n        var ecModel = this.ecModel;\n        var thisOption = this.option;\n        var base = {inRange: thisOption.inRange, outOfRange: thisOption.outOfRange};\n\n        var target = thisOption.target || (thisOption.target = {});\n        var controller = thisOption.controller || (thisOption.controller = {});\n\n        merge(target, base); // Do not override\n        merge(controller, base); // Do not override\n\n        var isCategory = this.isCategory();\n\n        completeSingle.call(this, target);\n        completeSingle.call(this, controller);\n        completeInactive.call(this, target, 'inRange', 'outOfRange');\n        // completeInactive.call(this, target, 'outOfRange', 'inRange');\n        completeController.call(this, controller);\n\n        function completeSingle(base) {\n            // Compatible with ec2 dataRange.color.\n            // The mapping order of dataRange.color is: [high value, ..., low value]\n            // whereas inRange.color and outOfRange.color is [low value, ..., high value]\n            // Notice: ec2 has no inverse.\n            if (isArray$3(thisOption.color)\n                // If there has been inRange: {symbol: ...}, adding color is a mistake.\n                // So adding color only when no inRange defined.\n                && !base.inRange\n            ) {\n                base.inRange = {color: thisOption.color.slice().reverse()};\n            }\n\n            // Compatible with previous logic, always give a defautl color, otherwise\n            // simple config with no inRange and outOfRange will not work.\n            // Originally we use visualMap.color as the default color, but setOption at\n            // the second time the default color will be erased. So we change to use\n            // constant DEFAULT_COLOR.\n            // If user do not want the defualt color, set inRange: {color: null}.\n            base.inRange = base.inRange || {color: ecModel.get('gradientColor')};\n\n            // If using shortcut like: {inRange: 'symbol'}, complete default value.\n            each$25(this.stateList, function (state) {\n                var visualType = base[state];\n\n                if (isString(visualType)) {\n                    var defa = visualDefault.get(visualType, 'active', isCategory);\n                    if (defa) {\n                        base[state] = {};\n                        base[state][visualType] = defa;\n                    }\n                    else {\n                        // Mark as not specified.\n                        delete base[state];\n                    }\n                }\n            }, this);\n        }\n\n        function completeInactive(base, stateExist, stateAbsent) {\n            var optExist = base[stateExist];\n            var optAbsent = base[stateAbsent];\n\n            if (optExist && !optAbsent) {\n                optAbsent = base[stateAbsent] = {};\n                each$25(optExist, function (visualData, visualType) {\n                    if (!VisualMapping.isValidType(visualType)) {\n                        return;\n                    }\n\n                    var defa = visualDefault.get(visualType, 'inactive', isCategory);\n\n                    if (defa != null) {\n                        optAbsent[visualType] = defa;\n\n                        // Compatibable with ec2:\n                        // Only inactive color to rgba(0,0,0,0) can not\n                        // make label transparent, so use opacity also.\n                        if (visualType === 'color'\n                            && !optAbsent.hasOwnProperty('opacity')\n                            && !optAbsent.hasOwnProperty('colorAlpha')\n                        ) {\n                            optAbsent.opacity = [0, 0];\n                        }\n                    }\n                });\n            }\n        }\n\n        function completeController(controller) {\n            var symbolExists = (controller.inRange || {}).symbol\n                || (controller.outOfRange || {}).symbol;\n            var symbolSizeExists = (controller.inRange || {}).symbolSize\n                || (controller.outOfRange || {}).symbolSize;\n            var inactiveColor = this.get('inactiveColor');\n\n            each$25(this.stateList, function (state) {\n\n                var itemSize = this.itemSize;\n                var visuals = controller[state];\n\n                // Set inactive color for controller if no other color\n                // attr (like colorAlpha) specified.\n                if (!visuals) {\n                    visuals = controller[state] = {\n                        color: isCategory ? inactiveColor : [inactiveColor]\n                    };\n                }\n\n                // Consistent symbol and symbolSize if not specified.\n                if (visuals.symbol == null) {\n                    visuals.symbol = symbolExists\n                        && clone(symbolExists)\n                        || (isCategory ? 'roundRect' : ['roundRect']);\n                }\n                if (visuals.symbolSize == null) {\n                    visuals.symbolSize = symbolSizeExists\n                        && clone(symbolSizeExists)\n                        || (isCategory ? itemSize[0] : [itemSize[0], itemSize[0]]);\n                }\n\n                // Filter square and none.\n                visuals.symbol = mapVisual$2(visuals.symbol, function (symbol) {\n                    return (symbol === 'none' || symbol === 'square') ? 'roundRect' : symbol;\n                });\n\n                // Normalize symbolSize\n                var symbolSize = visuals.symbolSize;\n\n                if (symbolSize != null) {\n                    var max = -Infinity;\n                    // symbolSize can be object when categories defined.\n                    eachVisual(symbolSize, function (value) {\n                        value > max && (max = value);\n                    });\n                    visuals.symbolSize = mapVisual$2(symbolSize, function (value) {\n                        return linearMap$2(value, [0, max], [0, itemSize[0]], true);\n                    });\n                }\n\n            }, this);\n        }\n    },\n\n    /**\n     * @protected\n     */\n    resetItemSize: function () {\n        this.itemSize = [\n            parseFloat(this.get('itemWidth')),\n            parseFloat(this.get('itemHeight'))\n        ];\n    },\n\n    /**\n     * @public\n     */\n    isCategory: function () {\n        return !!this.option.categories;\n    },\n\n    /**\n     * @public\n     * @abstract\n     */\n    setSelected: noop$2,\n\n    /**\n     * @public\n     * @abstract\n     * @param {*|module:echarts/data/List} valueOrData\n     * @param {number} dataIndex\n     * @return {string} state See this.stateList\n     */\n    getValueState: noop$2,\n\n    /**\n     * FIXME\n     * Do not publish to thirt-part-dev temporarily\n     * util the interface is stable. (Should it return\n     * a function but not visual meta?)\n     *\n     * @pubilc\n     * @abstract\n     * @param {Function} getColorVisual\n     *        params: value, valueState\n     *        return: color\n     * @return {Object} visualMeta\n     *        should includes {stops, outerColors}\n     *        outerColor means [colorBeyondMinValue, colorBeyondMaxValue]\n     */\n    getVisualMeta: noop$2\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Constant\nvar DEFAULT_BAR_BOUND = [20, 140];\n\nvar ContinuousModel = VisualMapModel.extend({\n\n    type: 'visualMap.continuous',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        align: 'auto',           // 'auto', 'left', 'right', 'top', 'bottom'\n        calculable: false,       // This prop effect default component type determine,\n                                 // See echarts/component/visualMap/typeDefaulter.\n        range: null,             // selected range. In default case `range` is [min, max]\n                                 // and can auto change along with modification of min max,\n                                 // util use specifid a range.\n        realtime: true,          // Whether realtime update.\n        itemHeight: null,        // The length of the range control edge.\n        itemWidth: null,         // The length of the other side.\n        hoverLink: true,         // Enable hover highlight.\n        hoverLinkDataSize: null, // The size of hovered data.\n        hoverLinkOnHandle: null  // Whether trigger hoverLink when hover handle.\n                                 // If not specified, follow the value of `realtime`.\n    },\n\n    /**\n     * @override\n     */\n    optionUpdated: function (newOption, isInit) {\n        ContinuousModel.superApply(this, 'optionUpdated', arguments);\n\n        this.resetExtent();\n\n        this.resetVisual(function (mappingOption) {\n            mappingOption.mappingMethod = 'linear';\n            mappingOption.dataExtent = this.getExtent();\n        });\n\n        this._resetRange();\n    },\n\n    /**\n     * @protected\n     * @override\n     */\n    resetItemSize: function () {\n        ContinuousModel.superApply(this, 'resetItemSize', arguments);\n\n        var itemSize = this.itemSize;\n\n        this._orient === 'horizontal' && itemSize.reverse();\n\n        (itemSize[0] == null || isNaN(itemSize[0])) && (itemSize[0] = DEFAULT_BAR_BOUND[0]);\n        (itemSize[1] == null || isNaN(itemSize[1])) && (itemSize[1] = DEFAULT_BAR_BOUND[1]);\n    },\n\n    /**\n     * @private\n     */\n    _resetRange: function () {\n        var dataExtent = this.getExtent();\n        var range = this.option.range;\n\n        if (!range || range.auto) {\n            // `range` should always be array (so we dont use other\n            // value like 'auto') for user-friend. (consider getOption).\n            dataExtent.auto = 1;\n            this.option.range = dataExtent;\n        }\n        else if (isArray(range)) {\n            if (range[0] > range[1]) {\n                range.reverse();\n            }\n            range[0] = Math.max(range[0], dataExtent[0]);\n            range[1] = Math.min(range[1], dataExtent[1]);\n        }\n    },\n\n    /**\n     * @protected\n     * @override\n     */\n    completeVisualOption: function () {\n        VisualMapModel.prototype.completeVisualOption.apply(this, arguments);\n\n        each$1(this.stateList, function (state) {\n            var symbolSize = this.option.controller[state].symbolSize;\n            if (symbolSize && symbolSize[0] !== symbolSize[1]) {\n                symbolSize[0] = 0; // For good looking.\n            }\n        }, this);\n    },\n\n    /**\n     * @override\n     */\n    setSelected: function (selected) {\n        this.option.range = selected.slice();\n        this._resetRange();\n    },\n\n    /**\n     * @public\n     */\n    getSelected: function () {\n        var dataExtent = this.getExtent();\n\n        var dataInterval = asc(\n            (this.get('range') || []).slice()\n        );\n\n        // Clamp\n        dataInterval[0] > dataExtent[1] && (dataInterval[0] = dataExtent[1]);\n        dataInterval[1] > dataExtent[1] && (dataInterval[1] = dataExtent[1]);\n        dataInterval[0] < dataExtent[0] && (dataInterval[0] = dataExtent[0]);\n        dataInterval[1] < dataExtent[0] && (dataInterval[1] = dataExtent[0]);\n\n        return dataInterval;\n    },\n\n    /**\n     * @override\n     */\n    getValueState: function (value) {\n        var range = this.option.range;\n        var dataExtent = this.getExtent();\n\n        // When range[0] === dataExtent[0], any value larger than dataExtent[0] maps to 'inRange'.\n        // range[1] is processed likewise.\n        return (\n            (range[0] <= dataExtent[0] || range[0] <= value)\n            && (range[1] >= dataExtent[1] || value <= range[1])\n        ) ? 'inRange' : 'outOfRange';\n    },\n\n    /**\n     * @params {Array.<number>} range target value: range[0] <= value && value <= range[1]\n     * @return {Array.<Object>} [{seriesId, dataIndices: <Array.<number>>}, ...]\n     */\n    findTargetDataIndices: function (range) {\n        var result = [];\n\n        this.eachTargetSeries(function (seriesModel) {\n            var dataIndices = [];\n            var data = seriesModel.getData();\n\n            data.each(this.getDataDimension(data), function (value, dataIndex) {\n                range[0] <= value && value <= range[1] && dataIndices.push(dataIndex);\n            }, this);\n\n            result.push({seriesId: seriesModel.id, dataIndex: dataIndices});\n        }, this);\n\n        return result;\n    },\n\n    /**\n     * @implement\n     */\n    getVisualMeta: function (getColorVisual) {\n        var oVals = getColorStopValues(this, 'outOfRange', this.getExtent());\n        var iVals = getColorStopValues(this, 'inRange', this.option.range.slice());\n        var stops = [];\n\n        function setStop(value, valueState) {\n            stops.push({\n                value: value,\n                color: getColorVisual(value, valueState)\n            });\n        }\n\n        // Format to: outOfRange -- inRange -- outOfRange.\n        var iIdx = 0;\n        var oIdx = 0;\n        var iLen = iVals.length;\n        var oLen = oVals.length;\n\n        for (; oIdx < oLen && (!iVals.length || oVals[oIdx] <= iVals[0]); oIdx++) {\n            // If oVal[oIdx] === iVals[iIdx], oVal[oIdx] should be ignored.\n            if (oVals[oIdx] < iVals[iIdx]) {\n                setStop(oVals[oIdx], 'outOfRange');\n            }\n        }\n        for (var first = 1; iIdx < iLen; iIdx++, first = 0) {\n            // If range is full, value beyond min, max will be clamped.\n            // make a singularity\n            first && stops.length && setStop(iVals[iIdx], 'outOfRange');\n            setStop(iVals[iIdx], 'inRange');\n        }\n        for (var first = 1; oIdx < oLen; oIdx++) {\n            if (!iVals.length || iVals[iVals.length - 1] < oVals[oIdx]) {\n                // make a singularity\n                if (first) {\n                    stops.length && setStop(stops[stops.length - 1].value, 'outOfRange');\n                    first = 0;\n                }\n                setStop(oVals[oIdx], 'outOfRange');\n            }\n        }\n\n        var stopsLen = stops.length;\n\n        return {\n            stops: stops,\n            outerColors: [\n                stopsLen ? stops[0].color : 'transparent',\n                stopsLen ? stops[stopsLen - 1].color : 'transparent'\n            ]\n        };\n    }\n\n});\n\nfunction getColorStopValues(visualMapModel, valueState, dataExtent) {\n    if (dataExtent[0] === dataExtent[1]) {\n        return dataExtent.slice();\n    }\n\n    // When using colorHue mapping, it is not linear color any more.\n    // Moreover, canvas gradient seems not to be accurate linear.\n    // FIXME\n    // Should be arbitrary value 100? or based on pixel size?\n    var count = 200;\n    var step = (dataExtent[1] - dataExtent[0]) / count;\n\n    var value = dataExtent[0];\n    var stopValues = [];\n    for (var i = 0; i <= count && value < dataExtent[1]; i++) {\n        stopValues.push(value);\n        value += step;\n    }\n    stopValues.push(dataExtent[1]);\n\n    return stopValues;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar VisualMapView = extendComponentView({\n\n    type: 'visualMap',\n\n    /**\n     * @readOnly\n     * @type {Object}\n     */\n    autoPositionValues: {left: 1, right: 1, top: 1, bottom: 1},\n\n    init: function (ecModel, api) {\n        /**\n         * @readOnly\n         * @type {module:echarts/model/Global}\n         */\n        this.ecModel = ecModel;\n\n        /**\n         * @readOnly\n         * @type {module:echarts/ExtensionAPI}\n         */\n        this.api = api;\n\n        /**\n         * @readOnly\n         * @type {module:echarts/component/visualMap/visualMapModel}\n         */\n        this.visualMapModel;\n    },\n\n    /**\n     * @protected\n     */\n    render: function (visualMapModel, ecModel, api, payload) {\n        this.visualMapModel = visualMapModel;\n\n        if (visualMapModel.get('show') === false) {\n            this.group.removeAll();\n            return;\n        }\n\n        this.doRender.apply(this, arguments);\n    },\n\n    /**\n     * @protected\n     */\n    renderBackground: function (group) {\n        var visualMapModel = this.visualMapModel;\n        var padding = normalizeCssArray$1(visualMapModel.get('padding') || 0);\n        var rect = group.getBoundingRect();\n\n        group.add(new Rect({\n            z2: -1, // Lay background rect on the lowest layer.\n            silent: true,\n            shape: {\n                x: rect.x - padding[3],\n                y: rect.y - padding[0],\n                width: rect.width + padding[3] + padding[1],\n                height: rect.height + padding[0] + padding[2]\n            },\n            style: {\n                fill: visualMapModel.get('backgroundColor'),\n                stroke: visualMapModel.get('borderColor'),\n                lineWidth: visualMapModel.get('borderWidth')\n            }\n        }));\n    },\n\n    /**\n     * @protected\n     * @param {number} targetValue can be Infinity or -Infinity\n     * @param {string=} visualCluster Only can be 'color' 'opacity' 'symbol' 'symbolSize'\n     * @param {Object} [opts]\n     * @param {string=} [opts.forceState] Specify state, instead of using getValueState method.\n     * @param {string=} [opts.convertOpacityToAlpha=false] For color gradient in controller widget.\n     * @return {*} Visual value.\n     */\n    getControllerVisual: function (targetValue, visualCluster, opts) {\n        opts = opts || {};\n\n        var forceState = opts.forceState;\n        var visualMapModel = this.visualMapModel;\n        var visualObj = {};\n\n        // Default values.\n        if (visualCluster === 'symbol') {\n            visualObj.symbol = visualMapModel.get('itemSymbol');\n        }\n        if (visualCluster === 'color') {\n            var defaultColor = visualMapModel.get('contentColor');\n            visualObj.color = defaultColor;\n        }\n\n        function getter(key) {\n            return visualObj[key];\n        }\n\n        function setter(key, value) {\n            visualObj[key] = value;\n        }\n\n        var mappings = visualMapModel.controllerVisuals[\n            forceState || visualMapModel.getValueState(targetValue)\n        ];\n        var visualTypes = VisualMapping.prepareVisualTypes(mappings);\n\n        each$1(visualTypes, function (type) {\n            var visualMapping = mappings[type];\n            if (opts.convertOpacityToAlpha && type === 'opacity') {\n                type = 'colorAlpha';\n                visualMapping = mappings.__alphaForOpacity;\n            }\n            if (VisualMapping.dependsOn(type, visualCluster)) {\n                visualMapping && visualMapping.applyVisual(\n                    targetValue, getter, setter\n                );\n            }\n        });\n\n        return visualObj[visualCluster];\n    },\n\n    /**\n     * @protected\n     */\n    positionGroup: function (group) {\n        var model = this.visualMapModel;\n        var api = this.api;\n\n        positionElement(\n            group,\n            model.getBoxLayoutParams(),\n            {width: api.getWidth(), height: api.getHeight()}\n        );\n    },\n\n    /**\n     * @protected\n     * @abstract\n     */\n    doRender: noop\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/component/visualMap/VisualMapModel} visualMapModel\\\n * @param {module:echarts/ExtensionAPI} api\n * @param {Array.<number>} itemSize always [short, long]\n * @return {string} 'left' or 'right' or 'top' or 'bottom'\n */\nfunction getItemAlign(visualMapModel, api, itemSize) {\n    var modelOption = visualMapModel.option;\n    var itemAlign = modelOption.align;\n\n    if (itemAlign != null && itemAlign !== 'auto') {\n        return itemAlign;\n    }\n\n    // Auto decision align.\n    var ecSize = {width: api.getWidth(), height: api.getHeight()};\n    var realIndex = modelOption.orient === 'horizontal' ? 1 : 0;\n\n    var paramsSet = [\n        ['left', 'right', 'width'],\n        ['top', 'bottom', 'height']\n    ];\n    var reals = paramsSet[realIndex];\n    var fakeValue = [0, null, 10];\n\n    var layoutInput = {};\n    for (var i = 0; i < 3; i++) {\n        layoutInput[paramsSet[1 - realIndex][i]] = fakeValue[i];\n        layoutInput[reals[i]] = i === 2 ? itemSize[0] : modelOption[reals[i]];\n    }\n\n    var rParam = [['x', 'width', 3], ['y', 'height', 0]][realIndex];\n    var rect = getLayoutRect(layoutInput, ecSize, modelOption.padding);\n\n    return reals[\n        (rect.margin[rParam[2]] || 0) + rect[rParam[0]] + rect[rParam[1]] * 0.5\n            < ecSize[rParam[1]] * 0.5 ? 0 : 1\n    ];\n}\n\n/**\n * Prepare dataIndex for outside usage, where dataIndex means rawIndex, and\n * dataIndexInside means filtered index.\n */\nfunction convertDataIndex(batch) {\n    each$1(batch || [], function (batchItem) {\n        if (batch.dataIndex != null) {\n            batch.dataIndexInside = batch.dataIndex;\n            batch.dataIndex = null;\n        }\n    });\n    return batch;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar linearMap$3 = linearMap;\nvar each$26 = each$1;\nvar mathMin$7 = Math.min;\nvar mathMax$7 = Math.max;\n\n// Arbitrary value\nvar HOVER_LINK_SIZE = 12;\nvar HOVER_LINK_OUT = 6;\n\n// Notice:\n// Any \"interval\" should be by the order of [low, high].\n// \"handle0\" (handleIndex === 0) maps to\n// low data value: this._dataInterval[0] and has low coord.\n// \"handle1\" (handleIndex === 1) maps to\n// high data value: this._dataInterval[1] and has high coord.\n// The logic of transform is implemented in this._createBarGroup.\n\nvar ContinuousView = VisualMapView.extend({\n\n    type: 'visualMap.continuous',\n\n    /**\n     * @override\n     */\n    init: function () {\n\n        ContinuousView.superApply(this, 'init', arguments);\n\n        /**\n         * @private\n         */\n        this._shapes = {};\n\n        /**\n         * @private\n         */\n        this._dataInterval = [];\n\n        /**\n         * @private\n         */\n        this._handleEnds = [];\n\n        /**\n         * @private\n         */\n        this._orient;\n\n        /**\n         * @private\n         */\n        this._useHandle;\n\n        /**\n         * @private\n         */\n        this._hoverLinkDataIndices = [];\n\n        /**\n         * @private\n         */\n        this._dragging;\n\n        /**\n         * @private\n         */\n        this._hovering;\n    },\n\n    /**\n     * @protected\n     * @override\n     */\n    doRender: function (visualMapModel, ecModel, api, payload) {\n        if (!payload || payload.type !== 'selectDataRange' || payload.from !== this.uid) {\n            this._buildView();\n        }\n    },\n\n    /**\n     * @private\n     */\n    _buildView: function () {\n        this.group.removeAll();\n\n        var visualMapModel = this.visualMapModel;\n        var thisGroup = this.group;\n\n        this._orient = visualMapModel.get('orient');\n        this._useHandle = visualMapModel.get('calculable');\n\n        this._resetInterval();\n\n        this._renderBar(thisGroup);\n\n        var dataRangeText = visualMapModel.get('text');\n        this._renderEndsText(thisGroup, dataRangeText, 0);\n        this._renderEndsText(thisGroup, dataRangeText, 1);\n\n        // Do this for background size calculation.\n        this._updateView(true);\n\n        // After updating view, inner shapes is built completely,\n        // and then background can be rendered.\n        this.renderBackground(thisGroup);\n\n        // Real update view\n        this._updateView();\n\n        this._enableHoverLinkToSeries();\n        this._enableHoverLinkFromSeries();\n\n        this.positionGroup(thisGroup);\n    },\n\n    /**\n     * @private\n     */\n    _renderEndsText: function (group, dataRangeText, endsIndex) {\n        if (!dataRangeText) {\n            return;\n        }\n\n        // Compatible with ec2, text[0] map to high value, text[1] map low value.\n        var text = dataRangeText[1 - endsIndex];\n        text = text != null ? text + '' : '';\n\n        var visualMapModel = this.visualMapModel;\n        var textGap = visualMapModel.get('textGap');\n        var itemSize = visualMapModel.itemSize;\n\n        var barGroup = this._shapes.barGroup;\n        var position = this._applyTransform(\n            [\n                itemSize[0] / 2,\n                endsIndex === 0 ? -textGap : itemSize[1] + textGap\n            ],\n            barGroup\n        );\n        var align = this._applyTransform(\n            endsIndex === 0 ? 'bottom' : 'top',\n            barGroup\n        );\n        var orient = this._orient;\n        var textStyleModel = this.visualMapModel.textStyleModel;\n\n        this.group.add(new Text({\n            style: {\n                x: position[0],\n                y: position[1],\n                textVerticalAlign: orient === 'horizontal' ? 'middle' : align,\n                textAlign: orient === 'horizontal' ? align : 'center',\n                text: text,\n                textFont: textStyleModel.getFont(),\n                textFill: textStyleModel.getTextColor()\n            }\n        }));\n    },\n\n    /**\n     * @private\n     */\n    _renderBar: function (targetGroup) {\n        var visualMapModel = this.visualMapModel;\n        var shapes = this._shapes;\n        var itemSize = visualMapModel.itemSize;\n        var orient = this._orient;\n        var useHandle = this._useHandle;\n        var itemAlign = getItemAlign(visualMapModel, this.api, itemSize);\n        var barGroup = shapes.barGroup = this._createBarGroup(itemAlign);\n\n        // Bar\n        barGroup.add(shapes.outOfRange = createPolygon());\n        barGroup.add(shapes.inRange = createPolygon(\n            null,\n            useHandle ? getCursor$1(this._orient) : null,\n            bind(this._dragHandle, this, 'all', false),\n            bind(this._dragHandle, this, 'all', true)\n        ));\n\n        var textRect = visualMapModel.textStyleModel.getTextRect('国');\n        var textSize = mathMax$7(textRect.width, textRect.height);\n\n        // Handle\n        if (useHandle) {\n            shapes.handleThumbs = [];\n            shapes.handleLabels = [];\n            shapes.handleLabelPoints = [];\n\n            this._createHandle(barGroup, 0, itemSize, textSize, orient, itemAlign);\n            this._createHandle(barGroup, 1, itemSize, textSize, orient, itemAlign);\n        }\n\n        this._createIndicator(barGroup, itemSize, textSize, orient);\n\n        targetGroup.add(barGroup);\n    },\n\n    /**\n     * @private\n     */\n    _createHandle: function (barGroup, handleIndex, itemSize, textSize, orient) {\n        var onDrift = bind(this._dragHandle, this, handleIndex, false);\n        var onDragEnd = bind(this._dragHandle, this, handleIndex, true);\n        var handleThumb = createPolygon(\n            createHandlePoints(handleIndex, textSize),\n            getCursor$1(this._orient),\n            onDrift,\n            onDragEnd\n        );\n        handleThumb.position[0] = itemSize[0];\n        barGroup.add(handleThumb);\n\n        // Text is always horizontal layout but should not be effected by\n        // transform (orient/inverse). So label is built separately but not\n        // use zrender/graphic/helper/RectText, and is located based on view\n        // group (according to handleLabelPoint) but not barGroup.\n        var textStyleModel = this.visualMapModel.textStyleModel;\n        var handleLabel = new Text({\n            draggable: true,\n            drift: onDrift,\n            onmousemove: function (e) {\n                // Fot mobile devicem, prevent screen slider on the button.\n                stop(e.event);\n            },\n            ondragend: onDragEnd,\n            style: {\n                x: 0, y: 0, text: '',\n                textFont: textStyleModel.getFont(),\n                textFill: textStyleModel.getTextColor()\n            }\n        });\n        this.group.add(handleLabel);\n\n        var handleLabelPoint = [\n            orient === 'horizontal'\n                ? textSize / 2\n                : textSize * 1.5,\n            orient === 'horizontal'\n                ? (handleIndex === 0 ? -(textSize * 1.5) : (textSize * 1.5))\n                : (handleIndex === 0 ? -textSize / 2 : textSize / 2)\n        ];\n\n        var shapes = this._shapes;\n        shapes.handleThumbs[handleIndex] = handleThumb;\n        shapes.handleLabelPoints[handleIndex] = handleLabelPoint;\n        shapes.handleLabels[handleIndex] = handleLabel;\n    },\n\n    /**\n     * @private\n     */\n    _createIndicator: function (barGroup, itemSize, textSize, orient) {\n        var indicator = createPolygon([[0, 0]], 'move');\n        indicator.position[0] = itemSize[0];\n        indicator.attr({invisible: true, silent: true});\n        barGroup.add(indicator);\n\n        var textStyleModel = this.visualMapModel.textStyleModel;\n        var indicatorLabel = new Text({\n            silent: true,\n            invisible: true,\n            style: {\n                x: 0, y: 0, text: '',\n                textFont: textStyleModel.getFont(),\n                textFill: textStyleModel.getTextColor()\n            }\n        });\n        this.group.add(indicatorLabel);\n\n        var indicatorLabelPoint = [\n            orient === 'horizontal' ? textSize / 2 : HOVER_LINK_OUT + 3,\n            0\n        ];\n\n        var shapes = this._shapes;\n        shapes.indicator = indicator;\n        shapes.indicatorLabel = indicatorLabel;\n        shapes.indicatorLabelPoint = indicatorLabelPoint;\n    },\n\n    /**\n     * @private\n     */\n    _dragHandle: function (handleIndex, isEnd, dx, dy) {\n        if (!this._useHandle) {\n            return;\n        }\n\n        this._dragging = !isEnd;\n\n        if (!isEnd) {\n            // Transform dx, dy to bar coordination.\n            var vertex = this._applyTransform([dx, dy], this._shapes.barGroup, true);\n            this._updateInterval(handleIndex, vertex[1]);\n\n            // Considering realtime, update view should be executed\n            // before dispatch action.\n            this._updateView();\n        }\n\n        // dragEnd do not dispatch action when realtime.\n        if (isEnd === !this.visualMapModel.get('realtime')) { // jshint ignore:line\n            this.api.dispatchAction({\n                type: 'selectDataRange',\n                from: this.uid,\n                visualMapId: this.visualMapModel.id,\n                selected: this._dataInterval.slice()\n            });\n        }\n\n        if (isEnd) {\n            !this._hovering && this._clearHoverLinkToSeries();\n        }\n        else if (useHoverLinkOnHandle(this.visualMapModel)) {\n            this._doHoverLinkToSeries(this._handleEnds[handleIndex], false);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _resetInterval: function () {\n        var visualMapModel = this.visualMapModel;\n\n        var dataInterval = this._dataInterval = visualMapModel.getSelected();\n        var dataExtent = visualMapModel.getExtent();\n        var sizeExtent = [0, visualMapModel.itemSize[1]];\n\n        this._handleEnds = [\n            linearMap$3(dataInterval[0], dataExtent, sizeExtent, true),\n            linearMap$3(dataInterval[1], dataExtent, sizeExtent, true)\n        ];\n    },\n\n    /**\n     * @private\n     * @param {(number|string)} handleIndex 0 or 1 or 'all'\n     * @param {number} dx\n     * @param {number} dy\n     */\n    _updateInterval: function (handleIndex, delta) {\n        delta = delta || 0;\n        var visualMapModel = this.visualMapModel;\n        var handleEnds = this._handleEnds;\n        var sizeExtent = [0, visualMapModel.itemSize[1]];\n\n        sliderMove(\n            delta,\n            handleEnds,\n            sizeExtent,\n            handleIndex,\n            // cross is forbiden\n            0\n        );\n\n        var dataExtent = visualMapModel.getExtent();\n        // Update data interval.\n        this._dataInterval = [\n            linearMap$3(handleEnds[0], sizeExtent, dataExtent, true),\n            linearMap$3(handleEnds[1], sizeExtent, dataExtent, true)\n        ];\n    },\n\n    /**\n     * @private\n     */\n    _updateView: function (forSketch) {\n        var visualMapModel = this.visualMapModel;\n        var dataExtent = visualMapModel.getExtent();\n        var shapes = this._shapes;\n\n        var outOfRangeHandleEnds = [0, visualMapModel.itemSize[1]];\n        var inRangeHandleEnds = forSketch ? outOfRangeHandleEnds : this._handleEnds;\n\n        var visualInRange = this._createBarVisual(\n            this._dataInterval, dataExtent, inRangeHandleEnds, 'inRange'\n        );\n        var visualOutOfRange = this._createBarVisual(\n            dataExtent, dataExtent, outOfRangeHandleEnds, 'outOfRange'\n        );\n\n        shapes.inRange\n            .setStyle({\n                fill: visualInRange.barColor,\n                opacity: visualInRange.opacity\n            })\n            .setShape('points', visualInRange.barPoints);\n        shapes.outOfRange\n            .setStyle({\n                fill: visualOutOfRange.barColor,\n                opacity: visualOutOfRange.opacity\n            })\n            .setShape('points', visualOutOfRange.barPoints);\n\n        this._updateHandle(inRangeHandleEnds, visualInRange);\n    },\n\n    /**\n     * @private\n     */\n    _createBarVisual: function (dataInterval, dataExtent, handleEnds, forceState) {\n        var opts = {\n            forceState: forceState,\n            convertOpacityToAlpha: true\n        };\n        var colorStops = this._makeColorGradient(dataInterval, opts);\n\n        var symbolSizes = [\n            this.getControllerVisual(dataInterval[0], 'symbolSize', opts),\n            this.getControllerVisual(dataInterval[1], 'symbolSize', opts)\n        ];\n        var barPoints = this._createBarPoints(handleEnds, symbolSizes);\n\n        return {\n            barColor: new LinearGradient(0, 0, 0, 1, colorStops),\n            barPoints: barPoints,\n            handlesColor: [\n                colorStops[0].color,\n                colorStops[colorStops.length - 1].color\n            ]\n        };\n    },\n\n    /**\n     * @private\n     */\n    _makeColorGradient: function (dataInterval, opts) {\n        // Considering colorHue, which is not linear, so we have to sample\n        // to calculate gradient color stops, but not only caculate head\n        // and tail.\n        var sampleNumber = 100; // Arbitrary value.\n        var colorStops = [];\n        var step = (dataInterval[1] - dataInterval[0]) / sampleNumber;\n\n        colorStops.push({\n            color: this.getControllerVisual(dataInterval[0], 'color', opts),\n            offset: 0\n        });\n\n        for (var i = 1; i < sampleNumber; i++) {\n            var currValue = dataInterval[0] + step * i;\n            if (currValue > dataInterval[1]) {\n                break;\n            }\n            colorStops.push({\n                color: this.getControllerVisual(currValue, 'color', opts),\n                offset: i / sampleNumber\n            });\n        }\n\n        colorStops.push({\n            color: this.getControllerVisual(dataInterval[1], 'color', opts),\n            offset: 1\n        });\n\n        return colorStops;\n    },\n\n    /**\n     * @private\n     */\n    _createBarPoints: function (handleEnds, symbolSizes) {\n        var itemSize = this.visualMapModel.itemSize;\n\n        return [\n            [itemSize[0] - symbolSizes[0], handleEnds[0]],\n            [itemSize[0], handleEnds[0]],\n            [itemSize[0], handleEnds[1]],\n            [itemSize[0] - symbolSizes[1], handleEnds[1]]\n        ];\n    },\n\n    /**\n     * @private\n     */\n    _createBarGroup: function (itemAlign) {\n        var orient = this._orient;\n        var inverse = this.visualMapModel.get('inverse');\n\n        return new Group(\n            (orient === 'horizontal' && !inverse)\n            ? {scale: itemAlign === 'bottom' ? [1, 1] : [-1, 1], rotation: Math.PI / 2}\n            : (orient === 'horizontal' && inverse)\n            ? {scale: itemAlign === 'bottom' ? [-1, 1] : [1, 1], rotation: -Math.PI / 2}\n            : (orient === 'vertical' && !inverse)\n            ? {scale: itemAlign === 'left' ? [1, -1] : [-1, -1]}\n            : {scale: itemAlign === 'left' ? [1, 1] : [-1, 1]}\n        );\n    },\n\n    /**\n     * @private\n     */\n    _updateHandle: function (handleEnds, visualInRange) {\n        if (!this._useHandle) {\n            return;\n        }\n\n        var shapes = this._shapes;\n        var visualMapModel = this.visualMapModel;\n        var handleThumbs = shapes.handleThumbs;\n        var handleLabels = shapes.handleLabels;\n\n        each$26([0, 1], function (handleIndex) {\n            var handleThumb = handleThumbs[handleIndex];\n            handleThumb.setStyle('fill', visualInRange.handlesColor[handleIndex]);\n            handleThumb.position[1] = handleEnds[handleIndex];\n\n            // Update handle label position.\n            var textPoint = applyTransform$1(\n                shapes.handleLabelPoints[handleIndex],\n                getTransform(handleThumb, this.group)\n            );\n            handleLabels[handleIndex].setStyle({\n                x: textPoint[0],\n                y: textPoint[1],\n                text: visualMapModel.formatValueText(this._dataInterval[handleIndex]),\n                textVerticalAlign: 'middle',\n                textAlign: this._applyTransform(\n                    this._orient === 'horizontal'\n                        ? (handleIndex === 0 ? 'bottom' : 'top')\n                        : 'left',\n                    shapes.barGroup\n                )\n            });\n        }, this);\n    },\n\n    /**\n     * @private\n     * @param {number} cursorValue\n     * @param {number} textValue\n     * @param {string} [rangeSymbol]\n     * @param {number} [halfHoverLinkSize]\n     */\n    _showIndicator: function (cursorValue, textValue, rangeSymbol, halfHoverLinkSize) {\n        var visualMapModel = this.visualMapModel;\n        var dataExtent = visualMapModel.getExtent();\n        var itemSize = visualMapModel.itemSize;\n        var sizeExtent = [0, itemSize[1]];\n        var pos = linearMap$3(cursorValue, dataExtent, sizeExtent, true);\n\n        var shapes = this._shapes;\n        var indicator = shapes.indicator;\n        if (!indicator) {\n            return;\n        }\n\n        indicator.position[1] = pos;\n        indicator.attr('invisible', false);\n        indicator.setShape('points', createIndicatorPoints(\n            !!rangeSymbol, halfHoverLinkSize, pos, itemSize[1]\n        ));\n\n        var opts = {convertOpacityToAlpha: true};\n        var color = this.getControllerVisual(cursorValue, 'color', opts);\n        indicator.setStyle('fill', color);\n\n        // Update handle label position.\n        var textPoint = applyTransform$1(\n            shapes.indicatorLabelPoint,\n            getTransform(indicator, this.group)\n        );\n\n        var indicatorLabel = shapes.indicatorLabel;\n        indicatorLabel.attr('invisible', false);\n        var align = this._applyTransform('left', shapes.barGroup);\n        var orient = this._orient;\n        indicatorLabel.setStyle({\n            text: (rangeSymbol ? rangeSymbol : '') + visualMapModel.formatValueText(textValue),\n            textVerticalAlign: orient === 'horizontal' ? align : 'middle',\n            textAlign: orient === 'horizontal' ? 'center' : align,\n            x: textPoint[0],\n            y: textPoint[1]\n        });\n    },\n\n    /**\n     * @private\n     */\n    _enableHoverLinkToSeries: function () {\n        var self = this;\n        this._shapes.barGroup\n\n            .on('mousemove', function (e) {\n                self._hovering = true;\n\n                if (!self._dragging) {\n                    var itemSize = self.visualMapModel.itemSize;\n                    var pos = self._applyTransform(\n                        [e.offsetX, e.offsetY], self._shapes.barGroup, true, true\n                    );\n                    // For hover link show when hover handle, which might be\n                    // below or upper than sizeExtent.\n                    pos[1] = mathMin$7(mathMax$7(0, pos[1]), itemSize[1]);\n                    self._doHoverLinkToSeries(\n                        pos[1],\n                        0 <= pos[0] && pos[0] <= itemSize[0]\n                    );\n                }\n            })\n\n            .on('mouseout', function () {\n                // When mouse is out of handle, hoverLink still need\n                // to be displayed when realtime is set as false.\n                self._hovering = false;\n                !self._dragging && self._clearHoverLinkToSeries();\n            });\n    },\n\n    /**\n     * @private\n     */\n    _enableHoverLinkFromSeries: function () {\n        var zr = this.api.getZr();\n\n        if (this.visualMapModel.option.hoverLink) {\n            zr.on('mouseover', this._hoverLinkFromSeriesMouseOver, this);\n            zr.on('mouseout', this._hideIndicator, this);\n        }\n        else {\n            this._clearHoverLinkFromSeries();\n        }\n    },\n\n    /**\n     * @private\n     */\n    _doHoverLinkToSeries: function (cursorPos, hoverOnBar) {\n        var visualMapModel = this.visualMapModel;\n        var itemSize = visualMapModel.itemSize;\n\n        if (!visualMapModel.option.hoverLink) {\n            return;\n        }\n\n        var sizeExtent = [0, itemSize[1]];\n        var dataExtent = visualMapModel.getExtent();\n\n        // For hover link show when hover handle, which might be below or upper than sizeExtent.\n        cursorPos = mathMin$7(mathMax$7(sizeExtent[0], cursorPos), sizeExtent[1]);\n\n        var halfHoverLinkSize = getHalfHoverLinkSize(visualMapModel, dataExtent, sizeExtent);\n        var hoverRange = [cursorPos - halfHoverLinkSize, cursorPos + halfHoverLinkSize];\n        var cursorValue = linearMap$3(cursorPos, sizeExtent, dataExtent, true);\n        var valueRange = [\n            linearMap$3(hoverRange[0], sizeExtent, dataExtent, true),\n            linearMap$3(hoverRange[1], sizeExtent, dataExtent, true)\n        ];\n        // Consider data range is out of visualMap range, see test/visualMap-continuous.html,\n        // where china and india has very large population.\n        hoverRange[0] < sizeExtent[0] && (valueRange[0] = -Infinity);\n        hoverRange[1] > sizeExtent[1] && (valueRange[1] = Infinity);\n\n        // Do not show indicator when mouse is over handle,\n        // otherwise labels overlap, especially when dragging.\n        if (hoverOnBar) {\n            if (valueRange[0] === -Infinity) {\n                this._showIndicator(cursorValue, valueRange[1], '< ', halfHoverLinkSize);\n            }\n            else if (valueRange[1] === Infinity) {\n                this._showIndicator(cursorValue, valueRange[0], '> ', halfHoverLinkSize);\n            }\n            else {\n                this._showIndicator(cursorValue, cursorValue, '≈ ', halfHoverLinkSize);\n            }\n        }\n\n        // When realtime is set as false, handles, which are in barGroup,\n        // also trigger hoverLink, which help user to realize where they\n        // focus on when dragging. (see test/heatmap-large.html)\n        // When realtime is set as true, highlight will not show when hover\n        // handle, because the label on handle, which displays a exact value\n        // but not range, might mislead users.\n        var oldBatch = this._hoverLinkDataIndices;\n        var newBatch = [];\n        if (hoverOnBar || useHoverLinkOnHandle(visualMapModel)) {\n            newBatch = this._hoverLinkDataIndices = visualMapModel.findTargetDataIndices(valueRange);\n        }\n\n        var resultBatches = compressBatches(oldBatch, newBatch);\n\n        this._dispatchHighDown('downplay', convertDataIndex(resultBatches[0]));\n        this._dispatchHighDown('highlight', convertDataIndex(resultBatches[1]));\n    },\n\n    /**\n     * @private\n     */\n    _hoverLinkFromSeriesMouseOver: function (e) {\n        var el = e.target;\n        var visualMapModel = this.visualMapModel;\n\n        if (!el || el.dataIndex == null) {\n            return;\n        }\n\n        var dataModel = this.ecModel.getSeriesByIndex(el.seriesIndex);\n\n        if (!visualMapModel.isTargetSeries(dataModel)) {\n            return;\n        }\n\n        var data = dataModel.getData(el.dataType);\n        var value = data.get(visualMapModel.getDataDimension(data), el.dataIndex, true);\n\n        if (!isNaN(value)) {\n            this._showIndicator(value, value);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _hideIndicator: function () {\n        var shapes = this._shapes;\n        shapes.indicator && shapes.indicator.attr('invisible', true);\n        shapes.indicatorLabel && shapes.indicatorLabel.attr('invisible', true);\n    },\n\n    /**\n     * @private\n     */\n    _clearHoverLinkToSeries: function () {\n        this._hideIndicator();\n\n        var indices = this._hoverLinkDataIndices;\n        this._dispatchHighDown('downplay', convertDataIndex(indices));\n\n        indices.length = 0;\n    },\n\n    /**\n     * @private\n     */\n    _clearHoverLinkFromSeries: function () {\n        this._hideIndicator();\n\n        var zr = this.api.getZr();\n        zr.off('mouseover', this._hoverLinkFromSeriesMouseOver);\n        zr.off('mouseout', this._hideIndicator);\n    },\n\n    /**\n     * @private\n     */\n    _applyTransform: function (vertex, element, inverse, global) {\n        var transform = getTransform(element, global ? null : this.group);\n\n        return graphic[\n            isArray(vertex) ? 'applyTransform' : 'transformDirection'\n        ](vertex, transform, inverse);\n    },\n\n    /**\n     * @private\n     */\n    _dispatchHighDown: function (type, batch) {\n        batch && batch.length && this.api.dispatchAction({\n            type: type,\n            batch: batch\n        });\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._clearHoverLinkFromSeries();\n        this._clearHoverLinkToSeries();\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this._clearHoverLinkFromSeries();\n        this._clearHoverLinkToSeries();\n    }\n\n});\n\nfunction createPolygon(points, cursor, onDrift, onDragEnd) {\n    return new Polygon({\n        shape: {points: points},\n        draggable: !!onDrift,\n        cursor: cursor,\n        drift: onDrift,\n        onmousemove: function (e) {\n            // Fot mobile devicem, prevent screen slider on the button.\n            stop(e.event);\n        },\n        ondragend: onDragEnd\n    });\n}\n\nfunction createHandlePoints(handleIndex, textSize) {\n    return handleIndex === 0\n        ? [[0, 0], [textSize, 0], [textSize, -textSize]]\n        : [[0, 0], [textSize, 0], [textSize, textSize]];\n}\n\nfunction createIndicatorPoints(isRange, halfHoverLinkSize, pos, extentMax) {\n    return isRange\n        ? [ // indicate range\n            [0, -mathMin$7(halfHoverLinkSize, mathMax$7(pos, 0))],\n            [HOVER_LINK_OUT, 0],\n            [0, mathMin$7(halfHoverLinkSize, mathMax$7(extentMax - pos, 0))]\n        ]\n        : [ // indicate single value\n            [0, 0], [5, -5], [5, 5]\n        ];\n}\n\nfunction getHalfHoverLinkSize(visualMapModel, dataExtent, sizeExtent) {\n    var halfHoverLinkSize = HOVER_LINK_SIZE / 2;\n    var hoverLinkDataSize = visualMapModel.get('hoverLinkDataSize');\n    if (hoverLinkDataSize) {\n        halfHoverLinkSize = linearMap$3(hoverLinkDataSize, dataExtent, sizeExtent, true) / 2;\n    }\n    return halfHoverLinkSize;\n}\n\nfunction useHoverLinkOnHandle(visualMapModel) {\n    var hoverLinkOnHandle = visualMapModel.get('hoverLinkOnHandle');\n    return !!(hoverLinkOnHandle == null ? visualMapModel.get('realtime') : hoverLinkOnHandle);\n}\n\nfunction getCursor$1(orient) {\n    return orient === 'vertical' ? 'ns-resize' : 'ew-resize';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar actionInfo$2 = {\n    type: 'selectDataRange',\n    event: 'dataRangeSelected',\n    // FIXME use updateView appears wrong\n    update: 'update'\n};\n\nregisterAction(actionInfo$2, function (payload, ecModel) {\n\n    ecModel.eachComponent({mainType: 'visualMap', query: payload}, function (model) {\n        model.setSelected(payload.selected);\n    });\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\nregisterPreprocessor(preprocessor$2);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PiecewiseModel = VisualMapModel.extend({\n\n    type: 'visualMap.piecewise',\n\n    /**\n     * Order Rule:\n     *\n     * option.categories / option.pieces / option.text / option.selected:\n     *     If !option.inverse,\n     *     Order when vertical: ['top', ..., 'bottom'].\n     *     Order when horizontal: ['left', ..., 'right'].\n     *     If option.inverse, the meaning of\n     *     the order should be reversed.\n     *\n     * this._pieceList:\n     *     The order is always [low, ..., high].\n     *\n     * Mapping from location to low-high:\n     *     If !option.inverse\n     *     When vertical, top is high.\n     *     When horizontal, right is high.\n     *     If option.inverse, reverse.\n     */\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n        selected: null,             // Object. If not specified, means selected.\n                                    // When pieces and splitNumber: {'0': true, '5': true}\n                                    // When categories: {'cate1': false, 'cate3': true}\n                                    // When selected === false, means all unselected.\n\n        minOpen: false,             // Whether include values that smaller than `min`.\n        maxOpen: false,             // Whether include values that bigger than `max`.\n\n        align: 'auto',              // 'auto', 'left', 'right'\n        itemWidth: 20,              // When put the controller vertically, it is the length of\n                                    // horizontal side of each item. Otherwise, vertical side.\n        itemHeight: 14,             // When put the controller vertically, it is the length of\n                                    // vertical side of each item. Otherwise, horizontal side.\n        itemSymbol: 'roundRect',\n        pieceList: null,            // Each item is Object, with some of those attrs:\n                                    // {min, max, lt, gt, lte, gte, value,\n                                    // color, colorSaturation, colorAlpha, opacity,\n                                    // symbol, symbolSize}, which customize the range or visual\n                                    // coding of the certain piece. Besides, see \"Order Rule\".\n        categories: null,           // category names, like: ['some1', 'some2', 'some3'].\n                                    // Attr min/max are ignored when categories set. See \"Order Rule\"\n        splitNumber: 5,             // If set to 5, auto split five pieces equally.\n                                    // If set to 0 and component type not set, component type will be\n                                    // determined as \"continuous\". (It is less reasonable but for ec2\n                                    // compatibility, see echarts/component/visualMap/typeDefaulter)\n        selectedMode: 'multiple',   // Can be 'multiple' or 'single'.\n        itemGap: 10,                // The gap between two items, in px.\n        hoverLink: true,            // Enable hover highlight.\n\n        showLabel: null             // By default, when text is used, label will hide (the logic\n                                    // is remained for compatibility reason)\n    },\n\n    /**\n     * @override\n     */\n    optionUpdated: function (newOption, isInit) {\n        PiecewiseModel.superApply(this, 'optionUpdated', arguments);\n\n        /**\n         * The order is always [low, ..., high].\n         * [{text: string, interval: Array.<number>}, ...]\n         * @private\n         * @type {Array.<Object>}\n         */\n        this._pieceList = [];\n\n        this.resetExtent();\n\n        /**\n         * 'pieces', 'categories', 'splitNumber'\n         * @type {string}\n         */\n        var mode = this._mode = this._determineMode();\n\n        resetMethods[this._mode].call(this);\n\n        this._resetSelected(newOption, isInit);\n\n        var categories = this.option.categories;\n\n        this.resetVisual(function (mappingOption, state) {\n            if (mode === 'categories') {\n                mappingOption.mappingMethod = 'category';\n                mappingOption.categories = clone(categories);\n            }\n            else {\n                mappingOption.dataExtent = this.getExtent();\n                mappingOption.mappingMethod = 'piecewise';\n                mappingOption.pieceList = map(this._pieceList, function (piece) {\n                    var piece = clone(piece);\n                    if (state !== 'inRange') {\n                        // FIXME\n                        // outOfRange do not support special visual in pieces.\n                        piece.visual = null;\n                    }\n                    return piece;\n                });\n            }\n        });\n    },\n\n    /**\n     * @protected\n     * @override\n     */\n    completeVisualOption: function () {\n        // Consider this case:\n        // visualMap: {\n        //      pieces: [{symbol: 'circle', lt: 0}, {symbol: 'rect', gte: 0}]\n        // }\n        // where no inRange/outOfRange set but only pieces. So we should make\n        // default inRange/outOfRange for this case, otherwise visuals that only\n        // appear in `pieces` will not be taken into account in visual encoding.\n\n        var option = this.option;\n        var visualTypesInPieces = {};\n        var visualTypes = VisualMapping.listVisualTypes();\n        var isCategory = this.isCategory();\n\n        each$1(option.pieces, function (piece) {\n            each$1(visualTypes, function (visualType) {\n                if (piece.hasOwnProperty(visualType)) {\n                    visualTypesInPieces[visualType] = 1;\n                }\n            });\n        });\n\n        each$1(visualTypesInPieces, function (v, visualType) {\n            var exists = 0;\n            each$1(this.stateList, function (state) {\n                exists |= has(option, state, visualType)\n                    || has(option.target, state, visualType);\n            }, this);\n\n            !exists && each$1(this.stateList, function (state) {\n                (option[state] || (option[state] = {}))[visualType] = visualDefault.get(\n                    visualType, state === 'inRange' ? 'active' : 'inactive', isCategory\n                );\n            });\n        }, this);\n\n        function has(obj, state, visualType) {\n            return obj && obj[state] && (\n                isObject$1(obj[state])\n                    ? obj[state].hasOwnProperty(visualType)\n                    : obj[state] === visualType // e.g., inRange: 'symbol'\n            );\n        }\n\n        VisualMapModel.prototype.completeVisualOption.apply(this, arguments);\n    },\n\n    _resetSelected: function (newOption, isInit) {\n        var thisOption = this.option;\n        var pieceList = this._pieceList;\n\n        // Selected do not merge but all override.\n        var selected = (isInit ? thisOption : newOption).selected || {};\n        thisOption.selected = selected;\n\n        // Consider 'not specified' means true.\n        each$1(pieceList, function (piece, index) {\n            var key = this.getSelectedMapKey(piece);\n            if (!selected.hasOwnProperty(key)) {\n                selected[key] = true;\n            }\n        }, this);\n\n        if (thisOption.selectedMode === 'single') {\n            // Ensure there is only one selected.\n            var hasSel = false;\n\n            each$1(pieceList, function (piece, index) {\n                var key = this.getSelectedMapKey(piece);\n                if (selected[key]) {\n                    hasSel\n                        ? (selected[key] = false)\n                        : (hasSel = true);\n                }\n            }, this);\n        }\n        // thisOption.selectedMode === 'multiple', default: all selected.\n    },\n\n    /**\n     * @public\n     */\n    getSelectedMapKey: function (piece) {\n        return this._mode === 'categories'\n            ? piece.value + '' : piece.index + '';\n    },\n\n    /**\n     * @public\n     */\n    getPieceList: function () {\n        return this._pieceList;\n    },\n\n    /**\n     * @private\n     * @return {string}\n     */\n    _determineMode: function () {\n        var option = this.option;\n\n        return option.pieces && option.pieces.length > 0\n            ? 'pieces'\n            : this.option.categories\n            ? 'categories'\n            : 'splitNumber';\n    },\n\n    /**\n     * @public\n     * @override\n     */\n    setSelected: function (selected) {\n        this.option.selected = clone(selected);\n    },\n\n    /**\n     * @public\n     * @override\n     */\n    getValueState: function (value) {\n        var index = VisualMapping.findPieceIndex(value, this._pieceList);\n\n        return index != null\n            ? (this.option.selected[this.getSelectedMapKey(this._pieceList[index])]\n                ? 'inRange' : 'outOfRange'\n            )\n            : 'outOfRange';\n    },\n\n    /**\n     * @public\n     * @params {number} pieceIndex piece index in visualMapModel.getPieceList()\n     * @return {Array.<Object>} [{seriesId, dataIndices: <Array.<number>>}, ...]\n     */\n    findTargetDataIndices: function (pieceIndex) {\n        var result = [];\n\n        this.eachTargetSeries(function (seriesModel) {\n            var dataIndices = [];\n            var data = seriesModel.getData();\n\n            data.each(this.getDataDimension(data), function (value, dataIndex) {\n                // Should always base on model pieceList, because it is order sensitive.\n                var pIdx = VisualMapping.findPieceIndex(value, this._pieceList);\n                pIdx === pieceIndex && dataIndices.push(dataIndex);\n            }, this);\n\n            result.push({seriesId: seriesModel.id, dataIndex: dataIndices});\n        }, this);\n\n        return result;\n    },\n\n    /**\n     * @private\n     * @param {Object} piece piece.value or piece.interval is required.\n     * @return {number} Can be Infinity or -Infinity\n     */\n    getRepresentValue: function (piece) {\n        var representValue;\n        if (this.isCategory()) {\n            representValue = piece.value;\n        }\n        else {\n            if (piece.value != null) {\n                representValue = piece.value;\n            }\n            else {\n                var pieceInterval = piece.interval || [];\n                representValue = (pieceInterval[0] === -Infinity && pieceInterval[1] === Infinity)\n                    ? 0\n                    : (pieceInterval[0] + pieceInterval[1]) / 2;\n            }\n        }\n        return representValue;\n    },\n\n    getVisualMeta: function (getColorVisual) {\n        // Do not support category. (category axis is ordinal, numerical)\n        if (this.isCategory()) {\n            return;\n        }\n\n        var stops = [];\n        var outerColors = [];\n        var visualMapModel = this;\n\n        function setStop(interval, valueState) {\n            var representValue = visualMapModel.getRepresentValue({interval: interval});\n            if (!valueState) {\n                valueState = visualMapModel.getValueState(representValue);\n            }\n            var color = getColorVisual(representValue, valueState);\n            if (interval[0] === -Infinity) {\n                outerColors[0] = color;\n            }\n            else if (interval[1] === Infinity) {\n                outerColors[1] = color;\n            }\n            else {\n                stops.push(\n                    {value: interval[0], color: color},\n                    {value: interval[1], color: color}\n                );\n            }\n        }\n\n        // Suplement\n        var pieceList = this._pieceList.slice();\n        if (!pieceList.length) {\n            pieceList.push({interval: [-Infinity, Infinity]});\n        }\n        else {\n            var edge = pieceList[0].interval[0];\n            edge !== -Infinity && pieceList.unshift({interval: [-Infinity, edge]});\n            edge = pieceList[pieceList.length - 1].interval[1];\n            edge !== Infinity && pieceList.push({interval: [edge, Infinity]});\n        }\n\n        var curr = -Infinity;\n        each$1(pieceList, function (piece) {\n            var interval = piece.interval;\n            if (interval) {\n                // Fulfill gap.\n                interval[0] > curr && setStop([curr, interval[0]], 'outOfRange');\n                setStop(interval.slice());\n                curr = interval[1];\n            }\n        }, this);\n\n        return {stops: stops, outerColors: outerColors};\n    }\n\n});\n\n/**\n * Key is this._mode\n * @type {Object}\n * @this {module:echarts/component/viusalMap/PiecewiseMode}\n */\nvar resetMethods = {\n\n    splitNumber: function () {\n        var thisOption = this.option;\n        var pieceList = this._pieceList;\n        var precision = Math.min(thisOption.precision, 20);\n        var dataExtent = this.getExtent();\n        var splitNumber = thisOption.splitNumber;\n        splitNumber = Math.max(parseInt(splitNumber, 10), 1);\n        thisOption.splitNumber = splitNumber;\n\n        var splitStep = (dataExtent[1] - dataExtent[0]) / splitNumber;\n        // Precision auto-adaption\n        while (+splitStep.toFixed(precision) !== splitStep && precision < 5) {\n            precision++;\n        }\n        thisOption.precision = precision;\n        splitStep = +splitStep.toFixed(precision);\n\n        var index = 0;\n\n        if (thisOption.minOpen) {\n            pieceList.push({\n                index: index++,\n                interval: [-Infinity, dataExtent[0]],\n                close: [0, 0]\n            });\n        }\n\n        for (\n            var curr = dataExtent[0], len = index + splitNumber;\n            index < len;\n            curr += splitStep\n        ) {\n            var max = index === splitNumber - 1 ? dataExtent[1] : (curr + splitStep);\n\n            pieceList.push({\n                index: index++,\n                interval: [curr, max],\n                close: [1, 1]\n            });\n        }\n\n        if (thisOption.maxOpen) {\n            pieceList.push({\n                index: index++,\n                interval: [dataExtent[1], Infinity],\n                close: [0, 0]\n            });\n        }\n\n        reformIntervals(pieceList);\n\n        each$1(pieceList, function (piece) {\n            piece.text = this.formatValueText(piece.interval);\n        }, this);\n    },\n\n    categories: function () {\n        var thisOption = this.option;\n        each$1(thisOption.categories, function (cate) {\n            // FIXME category模式也使用pieceList，但在visualMapping中不是使用pieceList。\n            // 是否改一致。\n            this._pieceList.push({\n                text: this.formatValueText(cate, true),\n                value: cate\n            });\n        }, this);\n\n        // See \"Order Rule\".\n        normalizeReverse(thisOption, this._pieceList);\n    },\n\n    pieces: function () {\n        var thisOption = this.option;\n        var pieceList = this._pieceList;\n\n        each$1(thisOption.pieces, function (pieceListItem, index) {\n\n            if (!isObject$1(pieceListItem)) {\n                pieceListItem = {value: pieceListItem};\n            }\n\n            var item = {text: '', index: index};\n\n            if (pieceListItem.label != null) {\n                item.text = pieceListItem.label;\n            }\n\n            if (pieceListItem.hasOwnProperty('value')) {\n                var value = item.value = pieceListItem.value;\n                item.interval = [value, value];\n                item.close = [1, 1];\n            }\n            else {\n                // `min` `max` is legacy option.\n                // `lt` `gt` `lte` `gte` is recommanded.\n                var interval = item.interval = [];\n                var close = item.close = [0, 0];\n\n                var closeList = [1, 0, 1];\n                var infinityList = [-Infinity, Infinity];\n\n                var useMinMax = [];\n                for (var lg = 0; lg < 2; lg++) {\n                    var names = [['gte', 'gt', 'min'], ['lte', 'lt', 'max']][lg];\n                    for (var i = 0; i < 3 && interval[lg] == null; i++) {\n                        interval[lg] = pieceListItem[names[i]];\n                        close[lg] = closeList[i];\n                        useMinMax[lg] = i === 2;\n                    }\n                    interval[lg] == null && (interval[lg] = infinityList[lg]);\n                }\n                useMinMax[0] && interval[1] === Infinity && (close[0] = 0);\n                useMinMax[1] && interval[0] === -Infinity && (close[1] = 0);\n\n                if (__DEV__) {\n                    if (interval[0] > interval[1]) {\n                        console.warn(\n                            'Piece ' + index + 'is illegal: ' + interval\n                            + ' lower bound should not greater then uppper bound.'\n                        );\n                    }\n                }\n\n                if (interval[0] === interval[1] && close[0] && close[1]) {\n                    // Consider: [{min: 5, max: 5, visual: {...}}, {min: 0, max: 5}],\n                    // we use value to lift the priority when min === max\n                    item.value = interval[0];\n                }\n            }\n\n            item.visual = VisualMapping.retrieveVisuals(pieceListItem);\n\n            pieceList.push(item);\n\n        }, this);\n\n        // See \"Order Rule\".\n        normalizeReverse(thisOption, pieceList);\n        // Only pieces\n        reformIntervals(pieceList);\n\n        each$1(pieceList, function (piece) {\n            var close = piece.close;\n            var edgeSymbols = [['<', '≤'][close[1]], ['>', '≥'][close[0]]];\n            piece.text = piece.text || this.formatValueText(\n                piece.value != null ? piece.value : piece.interval,\n                false,\n                edgeSymbols\n            );\n        }, this);\n    }\n};\n\nfunction normalizeReverse(thisOption, pieceList) {\n    var inverse = thisOption.inverse;\n    if (thisOption.orient === 'vertical' ? !inverse : inverse) {\n            pieceList.reverse();\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PiecewiseVisualMapView = VisualMapView.extend({\n\n    type: 'visualMap.piecewise',\n\n    /**\n     * @protected\n     * @override\n     */\n    doRender: function () {\n        var thisGroup = this.group;\n\n        thisGroup.removeAll();\n\n        var visualMapModel = this.visualMapModel;\n        var textGap = visualMapModel.get('textGap');\n        var textStyleModel = visualMapModel.textStyleModel;\n        var textFont = textStyleModel.getFont();\n        var textFill = textStyleModel.getTextColor();\n        var itemAlign = this._getItemAlign();\n        var itemSize = visualMapModel.itemSize;\n        var viewData = this._getViewData();\n        var endsText = viewData.endsText;\n        var showLabel = retrieve(visualMapModel.get('showLabel', true), !endsText);\n\n        endsText && this._renderEndsText(\n            thisGroup, endsText[0], itemSize, showLabel, itemAlign\n        );\n\n        each$1(viewData.viewPieceList, renderItem, this);\n\n        endsText && this._renderEndsText(\n            thisGroup, endsText[1], itemSize, showLabel, itemAlign\n        );\n\n        box(\n            visualMapModel.get('orient'), thisGroup, visualMapModel.get('itemGap')\n        );\n\n        this.renderBackground(thisGroup);\n\n        this.positionGroup(thisGroup);\n\n        function renderItem(item) {\n            var piece = item.piece;\n\n            var itemGroup = new Group();\n            itemGroup.onclick = bind(this._onItemClick, this, piece);\n\n            this._enableHoverLink(itemGroup, item.indexInModelPieceList);\n\n            var representValue = visualMapModel.getRepresentValue(piece);\n\n            this._createItemSymbol(\n                itemGroup, representValue, [0, 0, itemSize[0], itemSize[1]]\n            );\n\n            if (showLabel) {\n                var visualState = this.visualMapModel.getValueState(representValue);\n\n                itemGroup.add(new Text({\n                    style: {\n                        x: itemAlign === 'right' ? -textGap : itemSize[0] + textGap,\n                        y: itemSize[1] / 2,\n                        text: piece.text,\n                        textVerticalAlign: 'middle',\n                        textAlign: itemAlign,\n                        textFont: textFont,\n                        textFill: textFill,\n                        opacity: visualState === 'outOfRange' ? 0.5 : 1\n                    }\n                }));\n            }\n\n            thisGroup.add(itemGroup);\n        }\n    },\n\n    /**\n     * @private\n     */\n    _enableHoverLink: function (itemGroup, pieceIndex) {\n        itemGroup\n            .on('mouseover', bind(onHoverLink, this, 'highlight'))\n            .on('mouseout', bind(onHoverLink, this, 'downplay'));\n\n        function onHoverLink(method) {\n            var visualMapModel = this.visualMapModel;\n\n            visualMapModel.option.hoverLink && this.api.dispatchAction({\n                type: method,\n                batch: convertDataIndex(\n                    visualMapModel.findTargetDataIndices(pieceIndex)\n                )\n            });\n        }\n    },\n\n    /**\n     * @private\n     */\n    _getItemAlign: function () {\n        var visualMapModel = this.visualMapModel;\n        var modelOption = visualMapModel.option;\n\n        if (modelOption.orient === 'vertical') {\n            return getItemAlign(\n                visualMapModel, this.api, visualMapModel.itemSize\n            );\n        }\n        else { // horizontal, most case left unless specifying right.\n            var align = modelOption.align;\n            if (!align || align === 'auto') {\n                align = 'left';\n            }\n            return align;\n        }\n    },\n\n    /**\n     * @private\n     */\n    _renderEndsText: function (group, text, itemSize, showLabel, itemAlign) {\n        if (!text) {\n            return;\n        }\n\n        var itemGroup = new Group();\n        var textStyleModel = this.visualMapModel.textStyleModel;\n\n        itemGroup.add(new Text({\n            style: {\n                x: showLabel ? (itemAlign === 'right' ? itemSize[0] : 0) : itemSize[0] / 2,\n                y: itemSize[1] / 2,\n                textVerticalAlign: 'middle',\n                textAlign: showLabel ? itemAlign : 'center',\n                text: text,\n                textFont: textStyleModel.getFont(),\n                textFill: textStyleModel.getTextColor()\n            }\n        }));\n\n        group.add(itemGroup);\n    },\n\n    /**\n     * @private\n     * @return {Object} {peiceList, endsText} The order is the same as screen pixel order.\n     */\n    _getViewData: function () {\n        var visualMapModel = this.visualMapModel;\n\n        var viewPieceList = map(visualMapModel.getPieceList(), function (piece, index) {\n            return {piece: piece, indexInModelPieceList: index};\n        });\n        var endsText = visualMapModel.get('text');\n\n        // Consider orient and inverse.\n        var orient = visualMapModel.get('orient');\n        var inverse = visualMapModel.get('inverse');\n\n        // Order of model pieceList is always [low, ..., high]\n        if (orient === 'horizontal' ? inverse : !inverse) {\n            viewPieceList.reverse();\n        }\n        // Origin order of endsText is [high, low]\n        else if (endsText) {\n            endsText = endsText.slice().reverse();\n        }\n\n        return {viewPieceList: viewPieceList, endsText: endsText};\n    },\n\n    /**\n     * @private\n     */\n    _createItemSymbol: function (group, representValue, shapeParam) {\n        group.add(createSymbol(\n            this.getControllerVisual(representValue, 'symbol'),\n            shapeParam[0], shapeParam[1], shapeParam[2], shapeParam[3],\n            this.getControllerVisual(representValue, 'color')\n        ));\n    },\n\n    /**\n     * @private\n     */\n    _onItemClick: function (piece) {\n        var visualMapModel = this.visualMapModel;\n        var option = visualMapModel.option;\n        var selected = clone(option.selected);\n        var newKey = visualMapModel.getSelectedMapKey(piece);\n\n        if (option.selectedMode === 'single') {\n            selected[newKey] = true;\n            each$1(selected, function (o, key) {\n                selected[key] = key === newKey;\n            });\n        }\n        else {\n            selected[newKey] = !selected[newKey];\n        }\n\n        this.api.dispatchAction({\n            type: 'selectDataRange',\n            from: this.uid,\n            visualMapId: this.visualMapModel.id,\n            selected: selected\n        });\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\nregisterPreprocessor(preprocessor$2);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * visualMap component entry\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar addCommas$1 = addCommas;\nvar encodeHTML$1 = encodeHTML;\n\nfunction fillLabel(opt) {\n    defaultEmphasis(opt, 'label', ['show']);\n}\nvar MarkerModel = extendComponentModel({\n\n    type: 'marker',\n\n    dependencies: ['series', 'grid', 'polar', 'geo'],\n\n    /**\n     * @overrite\n     */\n    init: function (option, parentModel, ecModel, extraOpt) {\n\n        if (__DEV__) {\n            if (this.type === 'marker') {\n                throw new Error('Marker component is abstract component. Use markLine, markPoint, markArea instead.');\n            }\n        }\n        this.mergeDefaultAndTheme(option, ecModel);\n        this.mergeOption(option, ecModel, extraOpt.createdBySelf, true);\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isAnimationEnabled: function () {\n        if (env$1.node) {\n            return false;\n        }\n\n        var hostSeries = this.__hostSeries;\n        return this.getShallow('animation') && hostSeries && hostSeries.isAnimationEnabled();\n    },\n\n    mergeOption: function (newOpt, ecModel, createdBySelf, isInit) {\n        var MarkerModel = this.constructor;\n        var modelPropName = this.mainType + 'Model';\n        if (!createdBySelf) {\n            ecModel.eachSeries(function (seriesModel) {\n\n                var markerOpt = seriesModel.get(this.mainType, true);\n\n                var markerModel = seriesModel[modelPropName];\n                if (!markerOpt || !markerOpt.data) {\n                    seriesModel[modelPropName] = null;\n                    return;\n                }\n                if (!markerModel) {\n                    if (isInit) {\n                        // Default label emphasis `position` and `show`\n                        fillLabel(markerOpt);\n                    }\n                    each$1(markerOpt.data, function (item) {\n                        // FIXME Overwrite fillLabel method ?\n                        if (item instanceof Array) {\n                            fillLabel(item[0]);\n                            fillLabel(item[1]);\n                        }\n                        else {\n                            fillLabel(item);\n                        }\n                    });\n\n                    markerModel = new MarkerModel(\n                        markerOpt, this, ecModel\n                    );\n\n                    extend(markerModel, {\n                        mainType: this.mainType,\n                        // Use the same series index and name\n                        seriesIndex: seriesModel.seriesIndex,\n                        name: seriesModel.name,\n                        createdBySelf: true\n                    });\n\n                    markerModel.__hostSeries = seriesModel;\n                }\n                else {\n                    markerModel.mergeOption(markerOpt, ecModel, true);\n                }\n                seriesModel[modelPropName] = markerModel;\n            }, this);\n        }\n    },\n\n    formatTooltip: function (dataIndex) {\n        var data = this.getData();\n        var value = this.getRawValue(dataIndex);\n        var formattedValue = isArray(value)\n            ? map(value, addCommas$1).join(', ') : addCommas$1(value);\n        var name = data.getName(dataIndex);\n        var html = encodeHTML$1(this.name);\n        if (value != null || name) {\n            html += '<br />';\n        }\n        if (name) {\n            html += encodeHTML$1(name);\n            if (value != null) {\n                html += ' : ';\n            }\n        }\n        if (value != null) {\n            html += encodeHTML$1(formattedValue);\n        }\n        return html;\n    },\n\n    getData: function () {\n        return this._data;\n    },\n\n    setData: function (data) {\n        this._data = data;\n    }\n});\n\nmixin(MarkerModel, dataFormatMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markPoint',\n\n    defaultOption: {\n        zlevel: 0,\n        z: 5,\n        symbol: 'pin',\n        symbolSize: 50,\n        //symbolRotate: 0,\n        //symbolOffset: [0, 0]\n        tooltip: {\n            trigger: 'item'\n        },\n        label: {\n            show: true,\n            position: 'inside'\n        },\n        itemStyle: {\n            borderWidth: 2\n        },\n        emphasis: {\n            label: {\n                show: true\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar indexOf$2 = indexOf;\n\nfunction hasXOrY(item) {\n    return !(isNaN(parseFloat(item.x)) && isNaN(parseFloat(item.y)));\n}\n\nfunction hasXAndY(item) {\n    return !isNaN(parseFloat(item.x)) && !isNaN(parseFloat(item.y));\n}\n\n// Make it simple, do not visit all stacked value to count precision.\n// function getPrecision(data, valueAxisDim, dataIndex) {\n//     var precision = -1;\n//     var stackedDim = data.mapDimension(valueAxisDim);\n//     do {\n//         precision = Math.max(\n//             numberUtil.getPrecision(data.get(stackedDim, dataIndex)),\n//             precision\n//         );\n//         var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');\n//         if (stackedOnSeries) {\n//             var byValue = data.get(data.getCalculationInfo('stackedByDimension'), dataIndex);\n//             data = stackedOnSeries.getData();\n//             dataIndex = data.indexOf(data.getCalculationInfo('stackedByDimension'), byValue);\n//             stackedDim = data.getCalculationInfo('stackedDimension');\n//         }\n//         else {\n//             data = null;\n//         }\n//     } while (data);\n\n//     return precision;\n// }\n\nfunction markerTypeCalculatorWithExtent(\n    mlType, data, otherDataDim, targetDataDim, otherCoordIndex, targetCoordIndex\n) {\n    var coordArr = [];\n\n    var stacked = isDimensionStacked(data, targetDataDim /*, otherDataDim*/);\n    var calcDataDim = stacked\n        ? data.getCalculationInfo('stackResultDimension')\n        : targetDataDim;\n\n    var value = numCalculate(data, calcDataDim, mlType);\n\n    var dataIndex = data.indicesOfNearest(calcDataDim, value)[0];\n    coordArr[otherCoordIndex] = data.get(otherDataDim, dataIndex);\n    coordArr[targetCoordIndex] = data.get(targetDataDim, dataIndex);\n\n    // Make it simple, do not visit all stacked value to count precision.\n    var precision = getPrecision(data.get(targetDataDim, dataIndex));\n    precision = Math.min(precision, 20);\n    if (precision >= 0) {\n        coordArr[targetCoordIndex] = +coordArr[targetCoordIndex].toFixed(precision);\n    }\n\n    return coordArr;\n}\n\nvar curry$6 = curry;\n// TODO Specified percent\nvar markerTypeCalculator = {\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    min: curry$6(markerTypeCalculatorWithExtent, 'min'),\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    max: curry$6(markerTypeCalculatorWithExtent, 'max'),\n\n    /**\n     * @method\n     * @param {module:echarts/data/List} data\n     * @param {string} baseAxisDim\n     * @param {string} valueAxisDim\n     */\n    average: curry$6(markerTypeCalculatorWithExtent, 'average')\n};\n\n/**\n * Transform markPoint data item to format used in List by do the following\n * 1. Calculate statistic like `max`, `min`, `average`\n * 2. Convert `item.xAxis`, `item.yAxis` to `item.coord` array\n * @param  {module:echarts/model/Series} seriesModel\n * @param  {module:echarts/coord/*} [coordSys]\n * @param  {Object} item\n * @return {Object}\n */\nfunction dataTransform(seriesModel, item) {\n    var data = seriesModel.getData();\n    var coordSys = seriesModel.coordinateSystem;\n\n    // 1. If not specify the position with pixel directly\n    // 2. If `coord` is not a data array. Which uses `xAxis`,\n    // `yAxis` to specify the coord on each dimension\n\n    // parseFloat first because item.x and item.y can be percent string like '20%'\n    if (item && !hasXAndY(item) && !isArray(item.coord) && coordSys) {\n        var dims = coordSys.dimensions;\n        var axisInfo = getAxisInfo$1(item, data, coordSys, seriesModel);\n\n        // Clone the option\n        // Transform the properties xAxis, yAxis, radiusAxis, angleAxis, geoCoord to value\n        item = clone(item);\n\n        if (item.type\n            && markerTypeCalculator[item.type]\n            && axisInfo.baseAxis && axisInfo.valueAxis\n        ) {\n            var otherCoordIndex = indexOf$2(dims, axisInfo.baseAxis.dim);\n            var targetCoordIndex = indexOf$2(dims, axisInfo.valueAxis.dim);\n\n            item.coord = markerTypeCalculator[item.type](\n                data, axisInfo.baseDataDim, axisInfo.valueDataDim,\n                otherCoordIndex, targetCoordIndex\n            );\n            // Force to use the value of calculated value.\n            item.value = item.coord[targetCoordIndex];\n        }\n        else {\n            // FIXME Only has one of xAxis and yAxis.\n            var coord = [\n                item.xAxis != null ? item.xAxis : item.radiusAxis,\n                item.yAxis != null ? item.yAxis : item.angleAxis\n            ];\n            // Each coord support max, min, average\n            for (var i = 0; i < 2; i++) {\n                if (markerTypeCalculator[coord[i]]) {\n                    coord[i] = numCalculate(data, data.mapDimension(dims[i]), coord[i]);\n                }\n            }\n            item.coord = coord;\n        }\n    }\n    return item;\n}\n\nfunction getAxisInfo$1(item, data, coordSys, seriesModel) {\n    var ret = {};\n\n    if (item.valueIndex != null || item.valueDim != null) {\n        ret.valueDataDim = item.valueIndex != null\n            ? data.getDimension(item.valueIndex) : item.valueDim;\n        ret.valueAxis = coordSys.getAxis(dataDimToCoordDim(seriesModel, ret.valueDataDim));\n        ret.baseAxis = coordSys.getOtherAxis(ret.valueAxis);\n        ret.baseDataDim = data.mapDimension(ret.baseAxis.dim);\n    }\n    else {\n        ret.baseAxis = seriesModel.getBaseAxis();\n        ret.valueAxis = coordSys.getOtherAxis(ret.baseAxis);\n        ret.baseDataDim = data.mapDimension(ret.baseAxis.dim);\n        ret.valueDataDim = data.mapDimension(ret.valueAxis.dim);\n    }\n\n    return ret;\n}\n\nfunction dataDimToCoordDim(seriesModel, dataDim) {\n    var data = seriesModel.getData();\n    var dimensions = data.dimensions;\n    dataDim = data.getDimension(dataDim);\n    for (var i = 0; i < dimensions.length; i++) {\n        var dimItem = data.getDimensionInfo(dimensions[i]);\n        if (dimItem.name === dataDim) {\n            return dimItem.coordDim;\n        }\n    }\n}\n\n/**\n * Filter data which is out of coordinateSystem range\n * [dataFilter description]\n * @param  {module:echarts/coord/*} [coordSys]\n * @param  {Object} item\n * @return {boolean}\n */\nfunction dataFilter$1(coordSys, item) {\n    // Alwalys return true if there is no coordSys\n    return (coordSys && coordSys.containData && item.coord && !hasXOrY(item))\n        ? coordSys.containData(item.coord) : true;\n}\n\nfunction dimValueGetter(item, dimName, dataIndex, dimIndex) {\n    // x, y, radius, angle\n    if (dimIndex < 2) {\n        return item.coord && item.coord[dimIndex];\n    }\n    return item.value;\n}\n\nfunction numCalculate(data, valueDataDim, type) {\n    if (type === 'average') {\n        var sum = 0;\n        var count = 0;\n        data.each(valueDataDim, function (val, idx) {\n            if (!isNaN(val)) {\n                sum += val;\n                count++;\n            }\n        });\n        return sum / count;\n    }\n    else if (type === 'median') {\n        return data.getMedian(valueDataDim);\n    }\n    else {\n        // max & min\n        return data.getDataExtent(valueDataDim, true)[type === 'max' ? 1 : 0];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar MarkerView = extendComponentView({\n\n    type: 'marker',\n\n    init: function () {\n        /**\n         * Markline grouped by series\n         * @private\n         * @type {module:zrender/core/util.HashMap}\n         */\n        this.markerGroupMap = createHashMap();\n    },\n\n    render: function (markerModel, ecModel, api) {\n        var markerGroupMap = this.markerGroupMap;\n        markerGroupMap.each(function (item) {\n            item.__keep = false;\n        });\n\n        var markerModelKey = this.type + 'Model';\n        ecModel.eachSeries(function (seriesModel) {\n            var markerModel = seriesModel[markerModelKey];\n            markerModel && this.renderSeries(seriesModel, markerModel, ecModel, api);\n        }, this);\n\n        markerGroupMap.each(function (item) {\n            !item.__keep && this.group.remove(item.group);\n        }, this);\n    },\n\n    renderSeries: function () {}\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction updateMarkerLayout(mpData, seriesModel, api) {\n    var coordSys = seriesModel.coordinateSystem;\n    mpData.each(function (idx) {\n        var itemModel = mpData.getItemModel(idx);\n        var point;\n        var xPx = parsePercent$1(itemModel.get('x'), api.getWidth());\n        var yPx = parsePercent$1(itemModel.get('y'), api.getHeight());\n        if (!isNaN(xPx) && !isNaN(yPx)) {\n            point = [xPx, yPx];\n        }\n        // Chart like bar may have there own marker positioning logic\n        else if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                mpData.getValues(mpData.dimensions, idx)\n            );\n        }\n        else if (coordSys) {\n            var x = mpData.get(coordSys.dimensions[0], idx);\n            var y = mpData.get(coordSys.dimensions[1], idx);\n            point = coordSys.dataToPoint([x, y]);\n\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n\n        mpData.setItemLayout(idx, point);\n    });\n}\n\nMarkerView.extend({\n\n    type: 'markPoint',\n\n    // updateLayout: function (markPointModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var mpModel = seriesModel.markPointModel;\n    //         if (mpModel) {\n    //             updateMarkerLayout(mpModel.getData(), seriesModel, api);\n    //             this.markerGroupMap.get(seriesModel.id).updateLayout(mpModel);\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markPointModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var mpModel = seriesModel.markPointModel;\n            if (mpModel) {\n                updateMarkerLayout(mpModel.getData(), seriesModel, api);\n                this.markerGroupMap.get(seriesModel.id).updateLayout(mpModel);\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, mpModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var symbolDrawMap = this.markerGroupMap;\n        var symbolDraw = symbolDrawMap.get(seriesId)\n            || symbolDrawMap.set(seriesId, new SymbolDraw());\n\n        var mpData = createList$1(coordSys, seriesModel, mpModel);\n\n        // FIXME\n        mpModel.setData(mpData);\n\n        updateMarkerLayout(mpModel.getData(), seriesModel, api);\n\n        mpData.each(function (idx) {\n            var itemModel = mpData.getItemModel(idx);\n            var symbolSize = itemModel.getShallow('symbolSize');\n            if (typeof symbolSize === 'function') {\n                // FIXME 这里不兼容 ECharts 2.x，2.x 貌似参数是整个数据？\n                symbolSize = symbolSize(\n                    mpModel.getRawValue(idx), mpModel.getDataParams(idx)\n                );\n            }\n            mpData.setItemVisual(idx, {\n                symbolSize: symbolSize,\n                color: itemModel.get('itemStyle.color')\n                    || seriesData.getVisual('color'),\n                symbol: itemModel.getShallow('symbol')\n            });\n        });\n\n        // TODO Text are wrong\n        symbolDraw.updateData(mpData);\n        this.group.add(symbolDraw.group);\n\n        // Set host model for tooltip\n        // FIXME\n        mpData.eachItemGraphicEl(function (el) {\n            el.traverse(function (child) {\n                child.dataModel = mpModel;\n            });\n        });\n\n        symbolDraw.__keep = true;\n\n        symbolDraw.group.silent = mpModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} [coordSys]\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$1(coordSys, seriesModel, mpModel) {\n    var coordDimsInfos;\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var info = seriesModel.getData().getDimensionInfo(\n                seriesModel.getData().mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n    }\n\n    var mpData = new List(coordDimsInfos, mpModel);\n    var dataOpt = map(mpModel.get('data'), curry(\n            dataTransform, seriesModel\n        ));\n    if (coordSys) {\n        dataOpt = filter(\n            dataOpt, curry(dataFilter$1, coordSys)\n        );\n    }\n\n    mpData.initData(dataOpt, null,\n        coordSys ? dimValueGetter : function (item) {\n            return item.value;\n        }\n    );\n\n    return mpData;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// HINT Markpoint can't be used too much\nregisterPreprocessor(function (opt) {\n    // Make sure markPoint component is enabled\n    opt.markPoint = opt.markPoint || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markLine',\n\n    defaultOption: {\n        zlevel: 0,\n        z: 5,\n\n        symbol: ['circle', 'arrow'],\n        symbolSize: [8, 16],\n\n        //symbolRotate: 0,\n\n        precision: 2,\n        tooltip: {\n            trigger: 'item'\n        },\n        label: {\n            show: true,\n            position: 'end'\n        },\n        lineStyle: {\n            type: 'dashed'\n        },\n        emphasis: {\n            label: {\n                show: true\n            },\n            lineStyle: {\n                width: 3\n            }\n        },\n        animationEasing: 'linear'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar markLineTransform = function (seriesModel, coordSys, mlModel, item) {\n    var data = seriesModel.getData();\n    // Special type markLine like 'min', 'max', 'average', 'median'\n    var mlType = item.type;\n\n    if (!isArray(item)\n        && (\n            mlType === 'min' || mlType === 'max' || mlType === 'average' || mlType === 'median'\n            // In case\n            // data: [{\n            //   yAxis: 10\n            // }]\n            || (item.xAxis != null || item.yAxis != null)\n        )\n    ) {\n        var valueAxis;\n        var valueDataDim;\n        var value;\n\n        if (item.yAxis != null || item.xAxis != null) {\n            valueDataDim = item.yAxis != null ? 'y' : 'x';\n            valueAxis = coordSys.getAxis(valueDataDim);\n\n            value = retrieve(item.yAxis, item.xAxis);\n        }\n        else {\n            var axisInfo = getAxisInfo$1(item, data, coordSys, seriesModel);\n            valueDataDim = axisInfo.valueDataDim;\n            valueAxis = axisInfo.valueAxis;\n            value = numCalculate(data, valueDataDim, mlType);\n        }\n        var valueIndex = valueDataDim === 'x' ? 0 : 1;\n        var baseIndex = 1 - valueIndex;\n\n        var mlFrom = clone(item);\n        var mlTo = {};\n\n        mlFrom.type = null;\n\n        mlFrom.coord = [];\n        mlTo.coord = [];\n        mlFrom.coord[baseIndex] = -Infinity;\n        mlTo.coord[baseIndex] = Infinity;\n\n        var precision = mlModel.get('precision');\n        if (precision >= 0 && typeof value === 'number') {\n            value = +value.toFixed(Math.min(precision, 20));\n        }\n\n        mlFrom.coord[valueIndex] = mlTo.coord[valueIndex] = value;\n\n        item = [mlFrom, mlTo, { // Extra option for tooltip and label\n            type: mlType,\n            valueIndex: item.valueIndex,\n            // Force to use the value of calculated value.\n            value: value\n        }];\n    }\n\n    item = [\n        dataTransform(seriesModel, item[0]),\n        dataTransform(seriesModel, item[1]),\n        extend({}, item[2])\n    ];\n\n    // Avoid line data type is extended by from(to) data type\n    item[2].type = item[2].type || '';\n\n    // Merge from option and to option into line option\n    merge(item[2], item[0]);\n    merge(item[2], item[1]);\n\n    return item;\n};\n\nfunction isInifinity(val) {\n    return !isNaN(val) && !isFinite(val);\n}\n\n// If a markLine has one dim\nfunction ifMarkLineHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) {\n    var otherDimIndex = 1 - dimIndex;\n    var dimName = coordSys.dimensions[dimIndex];\n    return isInifinity(fromCoord[otherDimIndex]) && isInifinity(toCoord[otherDimIndex])\n        && fromCoord[dimIndex] === toCoord[dimIndex] && coordSys.getAxis(dimName).containData(fromCoord[dimIndex]);\n}\n\nfunction markLineFilter(coordSys, item) {\n    if (coordSys.type === 'cartesian2d') {\n        var fromCoord = item[0].coord;\n        var toCoord = item[1].coord;\n        // In case\n        // {\n        //  markLine: {\n        //    data: [{ yAxis: 2 }]\n        //  }\n        // }\n        if (\n            fromCoord && toCoord\n            && (ifMarkLineHasOnlyDim(1, fromCoord, toCoord, coordSys)\n            || ifMarkLineHasOnlyDim(0, fromCoord, toCoord, coordSys))\n        ) {\n            return true;\n        }\n    }\n    return dataFilter$1(coordSys, item[0])\n        && dataFilter$1(coordSys, item[1]);\n}\n\nfunction updateSingleMarkerEndLayout(\n    data, idx, isFrom, seriesModel, api\n) {\n    var coordSys = seriesModel.coordinateSystem;\n    var itemModel = data.getItemModel(idx);\n\n    var point;\n    var xPx = parsePercent$1(itemModel.get('x'), api.getWidth());\n    var yPx = parsePercent$1(itemModel.get('y'), api.getHeight());\n    if (!isNaN(xPx) && !isNaN(yPx)) {\n        point = [xPx, yPx];\n    }\n    else {\n        // Chart like bar may have there own marker positioning logic\n        if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                data.getValues(data.dimensions, idx)\n            );\n        }\n        else {\n            var dims = coordSys.dimensions;\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            point = coordSys.dataToPoint([x, y]);\n        }\n        // Expand line to the edge of grid if value on one axis is Inifnity\n        // In case\n        //  markLine: {\n        //    data: [{\n        //      yAxis: 2\n        //      // or\n        //      type: 'average'\n        //    }]\n        //  }\n        if (coordSys.type === 'cartesian2d') {\n            var xAxis = coordSys.getAxis('x');\n            var yAxis = coordSys.getAxis('y');\n            var dims = coordSys.dimensions;\n            if (isInifinity(data.get(dims[0], idx))) {\n                point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[isFrom ? 0 : 1]);\n            }\n            else if (isInifinity(data.get(dims[1], idx))) {\n                point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[isFrom ? 0 : 1]);\n            }\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n    }\n\n    data.setItemLayout(idx, point);\n}\n\nMarkerView.extend({\n\n    type: 'markLine',\n\n    // updateLayout: function (markLineModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var mlModel = seriesModel.markLineModel;\n    //         if (mlModel) {\n    //             var mlData = mlModel.getData();\n    //             var fromData = mlModel.__from;\n    //             var toData = mlModel.__to;\n    //             // Update visual and layout of from symbol and to symbol\n    //             fromData.each(function (idx) {\n    //                 updateSingleMarkerEndLayout(fromData, idx, true, seriesModel, api);\n    //                 updateSingleMarkerEndLayout(toData, idx, false, seriesModel, api);\n    //             });\n    //             // Update layout of line\n    //             mlData.each(function (idx) {\n    //                 mlData.setItemLayout(idx, [\n    //                     fromData.getItemLayout(idx),\n    //                     toData.getItemLayout(idx)\n    //                 ]);\n    //             });\n\n    //             this.markerGroupMap.get(seriesModel.id).updateLayout();\n\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markLineModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var mlModel = seriesModel.markLineModel;\n            if (mlModel) {\n                var mlData = mlModel.getData();\n                var fromData = mlModel.__from;\n                var toData = mlModel.__to;\n                // Update visual and layout of from symbol and to symbol\n                fromData.each(function (idx) {\n                    updateSingleMarkerEndLayout(fromData, idx, true, seriesModel, api);\n                    updateSingleMarkerEndLayout(toData, idx, false, seriesModel, api);\n                });\n                // Update layout of line\n                mlData.each(function (idx) {\n                    mlData.setItemLayout(idx, [\n                        fromData.getItemLayout(idx),\n                        toData.getItemLayout(idx)\n                    ]);\n                });\n\n                this.markerGroupMap.get(seriesModel.id).updateLayout();\n\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, mlModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var lineDrawMap = this.markerGroupMap;\n        var lineDraw = lineDrawMap.get(seriesId)\n            || lineDrawMap.set(seriesId, new LineDraw());\n        this.group.add(lineDraw.group);\n\n        var mlData = createList$2(coordSys, seriesModel, mlModel);\n\n        var fromData = mlData.from;\n        var toData = mlData.to;\n        var lineData = mlData.line;\n\n        mlModel.__from = fromData;\n        mlModel.__to = toData;\n        // Line data for tooltip and formatter\n        mlModel.setData(lineData);\n\n        var symbolType = mlModel.get('symbol');\n        var symbolSize = mlModel.get('symbolSize');\n        if (!isArray(symbolType)) {\n            symbolType = [symbolType, symbolType];\n        }\n        if (typeof symbolSize === 'number') {\n            symbolSize = [symbolSize, symbolSize];\n        }\n\n        // Update visual and layout of from symbol and to symbol\n        mlData.from.each(function (idx) {\n            updateDataVisualAndLayout(fromData, idx, true);\n            updateDataVisualAndLayout(toData, idx, false);\n        });\n\n        // Update visual and layout of line\n        lineData.each(function (idx) {\n            var lineColor = lineData.getItemModel(idx).get('lineStyle.color');\n            lineData.setItemVisual(idx, {\n                color: lineColor || fromData.getItemVisual(idx, 'color')\n            });\n            lineData.setItemLayout(idx, [\n                fromData.getItemLayout(idx),\n                toData.getItemLayout(idx)\n            ]);\n\n            lineData.setItemVisual(idx, {\n                'fromSymbolSize': fromData.getItemVisual(idx, 'symbolSize'),\n                'fromSymbol': fromData.getItemVisual(idx, 'symbol'),\n                'toSymbolSize': toData.getItemVisual(idx, 'symbolSize'),\n                'toSymbol': toData.getItemVisual(idx, 'symbol')\n            });\n        });\n\n        lineDraw.updateData(lineData);\n\n        // Set host model for tooltip\n        // FIXME\n        mlData.line.eachItemGraphicEl(function (el, idx) {\n            el.traverse(function (child) {\n                child.dataModel = mlModel;\n            });\n        });\n\n        function updateDataVisualAndLayout(data, idx, isFrom) {\n            var itemModel = data.getItemModel(idx);\n\n            updateSingleMarkerEndLayout(\n                data, idx, isFrom, seriesModel, api\n            );\n\n            data.setItemVisual(idx, {\n                symbolSize: itemModel.get('symbolSize') || symbolSize[isFrom ? 0 : 1],\n                symbol: itemModel.get('symbol', true) || symbolType[isFrom ? 0 : 1],\n                color: itemModel.get('itemStyle.color') || seriesData.getVisual('color')\n            });\n        }\n\n        lineDraw.__keep = true;\n\n        lineDraw.group.silent = mlModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} coordSys\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$2(coordSys, seriesModel, mlModel) {\n\n    var coordDimsInfos;\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var info = seriesModel.getData().getDimensionInfo(\n                seriesModel.getData().mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n    }\n\n    var fromData = new List(coordDimsInfos, mlModel);\n    var toData = new List(coordDimsInfos, mlModel);\n    // No dimensions\n    var lineData = new List([], mlModel);\n\n    var optData = map(mlModel.get('data'), curry(\n        markLineTransform, seriesModel, coordSys, mlModel\n    ));\n    if (coordSys) {\n        optData = filter(\n            optData, curry(markLineFilter, coordSys)\n        );\n    }\n    var dimValueGetter$$1 = coordSys ? dimValueGetter : function (item) {\n        return item.value;\n    };\n    fromData.initData(\n        map(optData, function (item) {\n            return item[0];\n        }),\n        null,\n        dimValueGetter$$1\n    );\n    toData.initData(\n        map(optData, function (item) {\n            return item[1];\n        }),\n        null,\n        dimValueGetter$$1\n    );\n    lineData.initData(\n        map(optData, function (item) {\n            return item[2];\n        })\n    );\n    lineData.hasItemOption = true;\n\n    return {\n        from: fromData,\n        to: toData,\n        line: lineData\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterPreprocessor(function (opt) {\n    // Make sure markLine component is enabled\n    opt.markLine = opt.markLine || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nMarkerModel.extend({\n\n    type: 'markArea',\n\n    defaultOption: {\n        zlevel: 0,\n        // PENDING\n        z: 1,\n        tooltip: {\n            trigger: 'item'\n        },\n        // markArea should fixed on the coordinate system\n        animation: false,\n        label: {\n            show: true,\n            position: 'top'\n        },\n        itemStyle: {\n            // color and borderColor default to use color from series\n            // color: 'auto'\n            // borderColor: 'auto'\n            borderWidth: 0\n        },\n\n        emphasis: {\n            label: {\n                show: true,\n                position: 'top'\n            }\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Better on polar\n\nvar markAreaTransform = function (seriesModel, coordSys, maModel, item) {\n    var lt = dataTransform(seriesModel, item[0]);\n    var rb = dataTransform(seriesModel, item[1]);\n    var retrieve$$1 = retrieve;\n\n    // FIXME make sure lt is less than rb\n    var ltCoord = lt.coord;\n    var rbCoord = rb.coord;\n    ltCoord[0] = retrieve$$1(ltCoord[0], -Infinity);\n    ltCoord[1] = retrieve$$1(ltCoord[1], -Infinity);\n\n    rbCoord[0] = retrieve$$1(rbCoord[0], Infinity);\n    rbCoord[1] = retrieve$$1(rbCoord[1], Infinity);\n\n    // Merge option into one\n    var result = mergeAll([{}, lt, rb]);\n\n    result.coord = [\n        lt.coord, rb.coord\n    ];\n    result.x0 = lt.x;\n    result.y0 = lt.y;\n    result.x1 = rb.x;\n    result.y1 = rb.y;\n    return result;\n};\n\nfunction isInifinity$1(val) {\n    return !isNaN(val) && !isFinite(val);\n}\n\n// If a markArea has one dim\nfunction ifMarkLineHasOnlyDim$1(dimIndex, fromCoord, toCoord, coordSys) {\n    var otherDimIndex = 1 - dimIndex;\n    return isInifinity$1(fromCoord[otherDimIndex]) && isInifinity$1(toCoord[otherDimIndex]);\n}\n\nfunction markAreaFilter(coordSys, item) {\n    var fromCoord = item.coord[0];\n    var toCoord = item.coord[1];\n    if (coordSys.type === 'cartesian2d') {\n        // In case\n        // {\n        //  markArea: {\n        //    data: [{ yAxis: 2 }]\n        //  }\n        // }\n        if (\n            fromCoord && toCoord\n            && (ifMarkLineHasOnlyDim$1(1, fromCoord, toCoord, coordSys)\n            || ifMarkLineHasOnlyDim$1(0, fromCoord, toCoord, coordSys))\n        ) {\n            return true;\n        }\n    }\n    return dataFilter$1(coordSys, {\n            coord: fromCoord,\n            x: item.x0,\n            y: item.y0\n        })\n        || dataFilter$1(coordSys, {\n            coord: toCoord,\n            x: item.x1,\n            y: item.y1\n        });\n}\n\n// dims can be ['x0', 'y0'], ['x1', 'y1'], ['x0', 'y1'], ['x1', 'y0']\nfunction getSingleMarkerEndPoint(data, idx, dims, seriesModel, api) {\n    var coordSys = seriesModel.coordinateSystem;\n    var itemModel = data.getItemModel(idx);\n\n    var point;\n    var xPx = parsePercent$1(itemModel.get(dims[0]), api.getWidth());\n    var yPx = parsePercent$1(itemModel.get(dims[1]), api.getHeight());\n    if (!isNaN(xPx) && !isNaN(yPx)) {\n        point = [xPx, yPx];\n    }\n    else {\n        // Chart like bar may have there own marker positioning logic\n        if (seriesModel.getMarkerPosition) {\n            // Use the getMarkerPoisition\n            point = seriesModel.getMarkerPosition(\n                data.getValues(dims, idx)\n            );\n        }\n        else {\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            var pt = [x, y];\n            coordSys.clampData && coordSys.clampData(pt, pt);\n            point = coordSys.dataToPoint(pt, true);\n        }\n        if (coordSys.type === 'cartesian2d') {\n            var xAxis = coordSys.getAxis('x');\n            var yAxis = coordSys.getAxis('y');\n            var x = data.get(dims[0], idx);\n            var y = data.get(dims[1], idx);\n            if (isInifinity$1(x)) {\n                point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[dims[0] === 'x0' ? 0 : 1]);\n            }\n            else if (isInifinity$1(y)) {\n                point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[dims[1] === 'y0' ? 0 : 1]);\n            }\n        }\n\n        // Use x, y if has any\n        if (!isNaN(xPx)) {\n            point[0] = xPx;\n        }\n        if (!isNaN(yPx)) {\n            point[1] = yPx;\n        }\n    }\n\n    return point;\n}\n\nvar dimPermutations = [['x0', 'y0'], ['x1', 'y0'], ['x1', 'y1'], ['x0', 'y1']];\n\nMarkerView.extend({\n\n    type: 'markArea',\n\n    // updateLayout: function (markAreaModel, ecModel, api) {\n    //     ecModel.eachSeries(function (seriesModel) {\n    //         var maModel = seriesModel.markAreaModel;\n    //         if (maModel) {\n    //             var areaData = maModel.getData();\n    //             areaData.each(function (idx) {\n    //                 var points = zrUtil.map(dimPermutations, function (dim) {\n    //                     return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n    //                 });\n    //                 // Layout\n    //                 areaData.setItemLayout(idx, points);\n    //                 var el = areaData.getItemGraphicEl(idx);\n    //                 el.setShape('points', points);\n    //             });\n    //         }\n    //     }, this);\n    // },\n\n    updateTransform: function (markAreaModel, ecModel, api) {\n        ecModel.eachSeries(function (seriesModel) {\n            var maModel = seriesModel.markAreaModel;\n            if (maModel) {\n                var areaData = maModel.getData();\n                areaData.each(function (idx) {\n                    var points = map(dimPermutations, function (dim) {\n                        return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n                    });\n                    // Layout\n                    areaData.setItemLayout(idx, points);\n                    var el = areaData.getItemGraphicEl(idx);\n                    el.setShape('points', points);\n                });\n            }\n        }, this);\n    },\n\n    renderSeries: function (seriesModel, maModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var seriesId = seriesModel.id;\n        var seriesData = seriesModel.getData();\n\n        var areaGroupMap = this.markerGroupMap;\n        var polygonGroup = areaGroupMap.get(seriesId)\n            || areaGroupMap.set(seriesId, {group: new Group()});\n\n        this.group.add(polygonGroup.group);\n        polygonGroup.__keep = true;\n\n        var areaData = createList$3(coordSys, seriesModel, maModel);\n\n        // Line data for tooltip and formatter\n        maModel.setData(areaData);\n\n        // Update visual and layout of line\n        areaData.each(function (idx) {\n            // Layout\n            areaData.setItemLayout(idx, map(dimPermutations, function (dim) {\n                return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);\n            }));\n\n            // Visual\n            areaData.setItemVisual(idx, {\n                color: seriesData.getVisual('color')\n            });\n        });\n\n\n        areaData.diff(polygonGroup.__data)\n            .add(function (idx) {\n                var polygon = new Polygon({\n                    shape: {\n                        points: areaData.getItemLayout(idx)\n                    }\n                });\n                areaData.setItemGraphicEl(idx, polygon);\n                polygonGroup.group.add(polygon);\n            })\n            .update(function (newIdx, oldIdx) {\n                var polygon = polygonGroup.__data.getItemGraphicEl(oldIdx);\n                updateProps(polygon, {\n                    shape: {\n                        points: areaData.getItemLayout(newIdx)\n                    }\n                }, maModel, newIdx);\n                polygonGroup.group.add(polygon);\n                areaData.setItemGraphicEl(newIdx, polygon);\n            })\n            .remove(function (idx) {\n                var polygon = polygonGroup.__data.getItemGraphicEl(idx);\n                polygonGroup.group.remove(polygon);\n            })\n            .execute();\n\n        areaData.eachItemGraphicEl(function (polygon, idx) {\n            var itemModel = areaData.getItemModel(idx);\n            var labelModel = itemModel.getModel('label');\n            var labelHoverModel = itemModel.getModel('emphasis.label');\n            var color = areaData.getItemVisual(idx, 'color');\n            polygon.useStyle(\n                defaults(\n                    itemModel.getModel('itemStyle').getItemStyle(),\n                    {\n                        fill: modifyAlpha(color, 0.4),\n                        stroke: color\n                    }\n                )\n            );\n\n            polygon.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n\n            setLabelStyle(\n                polygon.style, polygon.hoverStyle, labelModel, labelHoverModel,\n                {\n                    labelFetcher: maModel,\n                    labelDataIndex: idx,\n                    defaultText: areaData.getName(idx) || '',\n                    isRectText: true,\n                    autoColor: color\n                }\n            );\n\n            setHoverStyle(polygon, {});\n\n            polygon.dataModel = maModel;\n        });\n\n        polygonGroup.__data = areaData;\n\n        polygonGroup.group.silent = maModel.get('silent') || seriesModel.get('silent');\n    }\n});\n\n/**\n * @inner\n * @param {module:echarts/coord/*} coordSys\n * @param {module:echarts/model/Series} seriesModel\n * @param {module:echarts/model/Model} mpModel\n */\nfunction createList$3(coordSys, seriesModel, maModel) {\n\n    var coordDimsInfos;\n    var areaData;\n    var dims = ['x0', 'y0', 'x1', 'y1'];\n    if (coordSys) {\n        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {\n            var data = seriesModel.getData();\n            var info = data.getDimensionInfo(\n                data.mapDimension(coordDim)\n            ) || {};\n            // In map series data don't have lng and lat dimension. Fallback to same with coordSys\n            return defaults({name: coordDim}, info);\n        });\n        areaData = new List(map(dims, function (dim, idx) {\n            return {\n                name: dim,\n                type: coordDimsInfos[idx % 2].type\n            };\n        }), maModel);\n    }\n    else {\n        coordDimsInfos = [{\n            name: 'value',\n            type: 'float'\n        }];\n        areaData = new List(coordDimsInfos, maModel);\n    }\n\n    var optData = map(maModel.get('data'), curry(\n        markAreaTransform, seriesModel, coordSys, maModel\n    ));\n    if (coordSys) {\n        optData = filter(\n            optData, curry(markAreaFilter, coordSys)\n        );\n    }\n\n    var dimValueGetter$$1 = coordSys ? function (item, dimName, dataIndex, dimIndex) {\n        return item.coord[Math.floor(dimIndex / 2)][dimIndex % 2];\n    } : function (item) {\n        return item.value;\n    };\n    areaData.initData(optData, null, dimValueGetter$$1);\n    areaData.hasItemOption = true;\n    return areaData;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterPreprocessor(function (opt) {\n    // Make sure markArea component is enabled\n    opt.markArea = opt.markArea || {};\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar preprocessor$3 = function (option) {\n    var timelineOpt = option && option.timeline;\n\n    if (!isArray(timelineOpt)) {\n        timelineOpt = timelineOpt ? [timelineOpt] : [];\n    }\n\n    each$1(timelineOpt, function (opt) {\n        if (!opt) {\n            return;\n        }\n\n        compatibleEC2(opt);\n    });\n};\n\nfunction compatibleEC2(opt) {\n    var type = opt.type;\n\n    var ec2Types = {'number': 'value', 'time': 'time'};\n\n    // Compatible with ec2\n    if (ec2Types[type]) {\n        opt.axisType = ec2Types[type];\n        delete opt.type;\n    }\n\n    transferItem(opt);\n\n    if (has$2(opt, 'controlPosition')) {\n        var controlStyle = opt.controlStyle || (opt.controlStyle = {});\n        if (!has$2(controlStyle, 'position')) {\n            controlStyle.position = opt.controlPosition;\n        }\n        if (controlStyle.position === 'none' && !has$2(controlStyle, 'show')) {\n            controlStyle.show = false;\n            delete controlStyle.position;\n        }\n        delete opt.controlPosition;\n    }\n\n    each$1(opt.data || [], function (dataItem) {\n        if (isObject$1(dataItem) && !isArray(dataItem)) {\n            if (!has$2(dataItem, 'value') && has$2(dataItem, 'name')) {\n                // In ec2, using name as value.\n                dataItem.value = dataItem.name;\n            }\n            transferItem(dataItem);\n        }\n    });\n}\n\nfunction transferItem(opt) {\n    var itemStyle = opt.itemStyle || (opt.itemStyle = {});\n\n    var itemStyleEmphasis = itemStyle.emphasis || (itemStyle.emphasis = {});\n\n    // Transfer label out\n    var label = opt.label || (opt.label || {});\n    var labelNormal = label.normal || (label.normal = {});\n    var excludeLabelAttr = {normal: 1, emphasis: 1};\n\n    each$1(label, function (value, name) {\n        if (!excludeLabelAttr[name] && !has$2(labelNormal, name)) {\n            labelNormal[name] = value;\n        }\n    });\n\n    if (itemStyleEmphasis.label && !has$2(label, 'emphasis')) {\n        label.emphasis = itemStyleEmphasis.label;\n        delete itemStyleEmphasis.label;\n    }\n}\n\nfunction has$2(obj, attr) {\n    return obj.hasOwnProperty(attr);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nComponentModel.registerSubTypeDefaulter('timeline', function () {\n    // Only slider now.\n    return 'slider';\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nregisterAction(\n\n    {type: 'timelineChange', event: 'timelineChanged', update: 'prepareAndUpdate'},\n\n    function (payload, ecModel) {\n\n        var timelineModel = ecModel.getComponent('timeline');\n        if (timelineModel && payload.currentIndex != null) {\n            timelineModel.setCurrentIndex(payload.currentIndex);\n\n            if (!timelineModel.get('loop', true) && timelineModel.isIndexMax()) {\n                timelineModel.setPlayState(false);\n            }\n        }\n\n        // Set normalized currentIndex to payload.\n        ecModel.resetOption('timeline');\n\n        return defaults({\n            currentIndex: timelineModel.option.currentIndex\n        }, payload);\n    }\n);\n\nregisterAction(\n\n    {type: 'timelinePlayChange', event: 'timelinePlayChanged', update: 'update'},\n\n    function (payload, ecModel) {\n        var timelineModel = ecModel.getComponent('timeline');\n        if (timelineModel && payload.playState != null) {\n            timelineModel.setPlayState(payload.playState);\n        }\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TimelineModel = ComponentModel.extend({\n\n    type: 'timeline',\n\n    layoutMode: 'box',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n\n        zlevel: 0,                  // 一级层叠\n        z: 4,                       // 二级层叠\n        show: true,\n\n        axisType: 'time',  // 模式是时间类型，支持 value, category\n\n        realtime: true,\n\n        left: '20%',\n        top: null,\n        right: '20%',\n        bottom: 0,\n        width: null,\n        height: 40,\n        padding: 5,\n\n        controlPosition: 'left',           // 'left' 'right' 'top' 'bottom' 'none'\n        autoPlay: false,\n        rewind: false,                     // 反向播放\n        loop: true,\n        playInterval: 2000,                // 播放时间间隔，单位ms\n\n        currentIndex: 0,\n\n        itemStyle: {},\n        label: {\n            color: '#000'\n        },\n\n        data: []\n    },\n\n    /**\n     * @override\n     */\n    init: function (option, parentModel, ecModel) {\n\n        /**\n         * @private\n         * @type {module:echarts/data/List}\n         */\n        this._data;\n\n        /**\n         * @private\n         * @type {Array.<string>}\n         */\n        this._names;\n\n        this.mergeDefaultAndTheme(option, ecModel);\n        this._initData();\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function (option) {\n        TimelineModel.superApply(this, 'mergeOption', arguments);\n        this._initData();\n    },\n\n    /**\n     * @param {number} [currentIndex]\n     */\n    setCurrentIndex: function (currentIndex) {\n        if (currentIndex == null) {\n            currentIndex = this.option.currentIndex;\n        }\n        var count = this._data.count();\n\n        if (this.option.loop) {\n            currentIndex = (currentIndex % count + count) % count;\n        }\n        else {\n            currentIndex >= count && (currentIndex = count - 1);\n            currentIndex < 0 && (currentIndex = 0);\n        }\n\n        this.option.currentIndex = currentIndex;\n    },\n\n    /**\n     * @return {number} currentIndex\n     */\n    getCurrentIndex: function () {\n        return this.option.currentIndex;\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isIndexMax: function () {\n        return this.getCurrentIndex() >= this._data.count() - 1;\n    },\n\n    /**\n     * @param {boolean} state true: play, false: stop\n     */\n    setPlayState: function (state) {\n        this.option.autoPlay = !!state;\n    },\n\n    /**\n     * @return {boolean} true: play, false: stop\n     */\n    getPlayState: function () {\n        return !!this.option.autoPlay;\n    },\n\n    /**\n     * @private\n     */\n    _initData: function () {\n        var thisOption = this.option;\n        var dataArr = thisOption.data || [];\n        var axisType = thisOption.axisType;\n        var names = this._names = [];\n\n        if (axisType === 'category') {\n            var idxArr = [];\n            each$1(dataArr, function (item, index) {\n                var value = getDataItemValue(item);\n                var newItem;\n\n                if (isObject$1(item)) {\n                    newItem = clone(item);\n                    newItem.value = index;\n                }\n                else {\n                    newItem = index;\n                }\n\n                idxArr.push(newItem);\n\n                if (!isString(value) && (value == null || isNaN(value))) {\n                    value = '';\n                }\n\n                names.push(value + '');\n            });\n            dataArr = idxArr;\n        }\n\n        var dimType = ({category: 'ordinal', time: 'time'})[axisType] || 'number';\n\n        var data = this._data = new List([{name: 'value', type: dimType}], this);\n\n        data.initData(dataArr, names);\n    },\n\n    getData: function () {\n        return this._data;\n    },\n\n    /**\n     * @public\n     * @return {Array.<string>} categoreis\n     */\n    getCategories: function () {\n        if (this.get('axisType') === 'category') {\n            return this._names.slice();\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar SliderTimelineModel = TimelineModel.extend({\n\n    type: 'timeline.slider',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n\n        backgroundColor: 'rgba(0,0,0,0)',   // 时间轴背景颜色\n        borderColor: '#ccc',               // 时间轴边框颜色\n        borderWidth: 0,                    // 时间轴边框线宽，单位px，默认为0（无边框）\n\n        orient: 'horizontal',              // 'vertical'\n        inverse: false,\n\n        tooltip: {                          // boolean or Object\n            trigger: 'item'                 // data item may also have tootip attr.\n        },\n\n        symbol: 'emptyCircle',\n        symbolSize: 10,\n\n        lineStyle: {\n            show: true,\n            width: 2,\n            color: '#304654'\n        },\n        label: {                            // 文本标签\n            position: 'auto',           // auto left right top bottom\n                                        // When using number, label position is not\n                                        // restricted by viewRect.\n                                        // positive: right/bottom, negative: left/top\n            show: true,\n            interval: 'auto',\n            rotate: 0,\n            // formatter: null,\n            // 其余属性默认使用全局文本样式，详见TEXTSTYLE\n            color: '#304654'\n        },\n        itemStyle: {\n            color: '#304654',\n            borderWidth: 1\n        },\n\n        checkpointStyle: {\n            symbol: 'circle',\n            symbolSize: 13,\n            color: '#c23531',\n            borderWidth: 5,\n            borderColor: 'rgba(194,53,49, 0.5)',\n            animation: true,\n            animationDuration: 300,\n            animationEasing: 'quinticInOut'\n        },\n\n        controlStyle: {\n            show: true,\n            showPlayBtn: true,\n            showPrevBtn: true,\n            showNextBtn: true,\n            itemSize: 22,\n            itemGap: 12,\n            position: 'left',  // 'left' 'right' 'top' 'bottom'\n            playIcon: 'path://M31.6,53C17.5,53,6,41.5,6,27.4S17.5,1.8,31.6,1.8C45.7,1.8,57.2,13.3,57.2,27.4S45.7,53,31.6,53z M31.6,3.3 C18.4,3.3,7.5,14.1,7.5,27.4c0,13.3,10.8,24.1,24.1,24.1C44.9,51.5,55.7,40.7,55.7,27.4C55.7,14.1,44.9,3.3,31.6,3.3z M24.9,21.3 c0-2.2,1.6-3.1,3.5-2l10.5,6.1c1.899,1.1,1.899,2.9,0,4l-10.5,6.1c-1.9,1.1-3.5,0.2-3.5-2V21.3z', // jshint ignore:line\n            stopIcon: 'path://M30.9,53.2C16.8,53.2,5.3,41.7,5.3,27.6S16.8,2,30.9,2C45,2,56.4,13.5,56.4,27.6S45,53.2,30.9,53.2z M30.9,3.5C17.6,3.5,6.8,14.4,6.8,27.6c0,13.3,10.8,24.1,24.101,24.1C44.2,51.7,55,40.9,55,27.6C54.9,14.4,44.1,3.5,30.9,3.5z M36.9,35.8c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H36c0.5,0,0.9,0.4,0.9,1V35.8z M27.8,35.8 c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H27c0.5,0,0.9,0.4,0.9,1L27.8,35.8L27.8,35.8z', // jshint ignore:line\n            nextIcon: 'path://M18.6,50.8l22.5-22.5c0.2-0.2,0.3-0.4,0.3-0.7c0-0.3-0.1-0.5-0.3-0.7L18.7,4.4c-0.1-0.1-0.2-0.3-0.2-0.5 c0-0.4,0.3-0.8,0.8-0.8c0.2,0,0.5,0.1,0.6,0.3l23.5,23.5l0,0c0.2,0.2,0.3,0.4,0.3,0.7c0,0.3-0.1,0.5-0.3,0.7l-0.1,0.1L19.7,52 c-0.1,0.1-0.3,0.2-0.5,0.2c-0.4,0-0.8-0.3-0.8-0.8C18.4,51.2,18.5,51,18.6,50.8z', // jshint ignore:line\n            prevIcon: 'path://M43,52.8L20.4,30.3c-0.2-0.2-0.3-0.4-0.3-0.7c0-0.3,0.1-0.5,0.3-0.7L42.9,6.4c0.1-0.1,0.2-0.3,0.2-0.5 c0-0.4-0.3-0.8-0.8-0.8c-0.2,0-0.5,0.1-0.6,0.3L18.3,28.8l0,0c-0.2,0.2-0.3,0.4-0.3,0.7c0,0.3,0.1,0.5,0.3,0.7l0.1,0.1L41.9,54 c0.1,0.1,0.3,0.2,0.5,0.2c0.4,0,0.8-0.3,0.8-0.8C43.2,53.2,43.1,53,43,52.8z', // jshint ignore:line\n\n            color: '#304654',\n            borderColor: '#304654',\n            borderWidth: 1\n        },\n\n        emphasis: {\n            label: {\n                show: true,\n                // 其余属性默认使用全局文本样式，详见TEXTSTYLE\n                color: '#c23531'\n            },\n\n            itemStyle: {\n                color: '#c23531'\n            },\n\n            controlStyle: {\n                color: '#c23531',\n                borderColor: '#c23531',\n                borderWidth: 2\n            }\n        },\n        data: []\n    }\n\n});\n\nmixin(SliderTimelineModel, dataFormatMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TimelineView = Component.extend({\n    type: 'timeline'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Extend axis 2d\n * @constructor module:echarts/coord/cartesian/Axis2D\n * @extends {module:echarts/coord/cartesian/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n * @param {string} position\n */\nvar TimelineAxis = function (dim, scale, coordExtent, axisType) {\n\n    Axis.call(this, dim, scale, coordExtent);\n\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * Axis model\n     * @param {module:echarts/component/TimelineModel}\n     */\n    this.model = null;\n};\n\nTimelineAxis.prototype = {\n\n    constructor: TimelineAxis,\n\n    /**\n     * @override\n     */\n    getLabelModel: function () {\n        return this.model.getModel('label');\n    },\n\n    /**\n     * @override\n     */\n    isHorizontal: function () {\n        return this.model.get('orient') === 'horizontal';\n    }\n\n};\n\ninherits(TimelineAxis, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar bind$6 = bind;\nvar each$27 = each$1;\n\nvar PI$4 = Math.PI;\n\nTimelineView.extend({\n\n    type: 'timeline.slider',\n\n    init: function (ecModel, api) {\n\n        this.api = api;\n\n        /**\n         * @private\n         * @type {module:echarts/component/timeline/TimelineAxis}\n         */\n        this._axis;\n\n        /**\n         * @private\n         * @type {module:zrender/core/BoundingRect}\n         */\n        this._viewRect;\n\n        /**\n         * @type {number}\n         */\n        this._timer;\n\n        /**\n         * @type {module:zrender/Element}\n         */\n        this._currentPointer;\n\n        /**\n         * @type {module:zrender/container/Group}\n         */\n        this._mainGroup;\n\n        /**\n         * @type {module:zrender/container/Group}\n         */\n        this._labelGroup;\n    },\n\n    /**\n     * @override\n     */\n    render: function (timelineModel, ecModel, api, payload) {\n        this.model = timelineModel;\n        this.api = api;\n        this.ecModel = ecModel;\n\n        this.group.removeAll();\n\n        if (timelineModel.get('show', true)) {\n\n            var layoutInfo = this._layout(timelineModel, api);\n            var mainGroup = this._createGroup('mainGroup');\n            var labelGroup = this._createGroup('labelGroup');\n\n            /**\n             * @private\n             * @type {module:echarts/component/timeline/TimelineAxis}\n             */\n            var axis = this._axis = this._createAxis(layoutInfo, timelineModel);\n\n            timelineModel.formatTooltip = function (dataIndex) {\n                return encodeHTML(axis.scale.getLabel(dataIndex));\n            };\n\n            each$27(\n                ['AxisLine', 'AxisTick', 'Control', 'CurrentPointer'],\n                function (name) {\n                    this['_render' + name](layoutInfo, mainGroup, axis, timelineModel);\n                },\n                this\n            );\n\n            this._renderAxisLabel(layoutInfo, labelGroup, axis, timelineModel);\n            this._position(layoutInfo, timelineModel);\n        }\n\n        this._doPlayStop();\n    },\n\n    /**\n     * @override\n     */\n    remove: function () {\n        this._clearTimer();\n        this.group.removeAll();\n    },\n\n    /**\n     * @override\n     */\n    dispose: function () {\n        this._clearTimer();\n    },\n\n    _layout: function (timelineModel, api) {\n        var labelPosOpt = timelineModel.get('label.position');\n        var orient = timelineModel.get('orient');\n        var viewRect = getViewRect$4(timelineModel, api);\n        // Auto label offset.\n        if (labelPosOpt == null || labelPosOpt === 'auto') {\n            labelPosOpt = orient === 'horizontal'\n                ? ((viewRect.y + viewRect.height / 2) < api.getHeight() / 2 ? '-' : '+')\n                : ((viewRect.x + viewRect.width / 2) < api.getWidth() / 2 ? '+' : '-');\n        }\n        else if (isNaN(labelPosOpt)) {\n            labelPosOpt = ({\n                horizontal: {top: '-', bottom: '+'},\n                vertical: {left: '-', right: '+'}\n            })[orient][labelPosOpt];\n        }\n\n        var labelAlignMap = {\n            horizontal: 'center',\n            vertical: (labelPosOpt >= 0 || labelPosOpt === '+') ? 'left' : 'right'\n        };\n\n        var labelBaselineMap = {\n            horizontal: (labelPosOpt >= 0 || labelPosOpt === '+') ? 'top' : 'bottom',\n            vertical: 'middle'\n        };\n        var rotationMap = {\n            horizontal: 0,\n            vertical: PI$4 / 2\n        };\n\n        // Position\n        var mainLength = orient === 'vertical' ? viewRect.height : viewRect.width;\n\n        var controlModel = timelineModel.getModel('controlStyle');\n        var showControl = controlModel.get('show', true);\n        var controlSize = showControl ? controlModel.get('itemSize') : 0;\n        var controlGap = showControl ? controlModel.get('itemGap') : 0;\n        var sizePlusGap = controlSize + controlGap;\n\n        // Special label rotate.\n        var labelRotation = timelineModel.get('label.rotate') || 0;\n        labelRotation = labelRotation * PI$4 / 180; // To radian.\n\n        var playPosition;\n        var prevBtnPosition;\n        var nextBtnPosition;\n        var axisExtent;\n        var controlPosition = controlModel.get('position', true);\n        var showPlayBtn = showControl && controlModel.get('showPlayBtn', true);\n        var showPrevBtn = showControl && controlModel.get('showPrevBtn', true);\n        var showNextBtn = showControl && controlModel.get('showNextBtn', true);\n        var xLeft = 0;\n        var xRight = mainLength;\n\n        // position[0] means left, position[1] means middle.\n        if (controlPosition === 'left' || controlPosition === 'bottom') {\n            showPlayBtn && (playPosition = [0, 0], xLeft += sizePlusGap);\n            showPrevBtn && (prevBtnPosition = [xLeft, 0], xLeft += sizePlusGap);\n            showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);\n        }\n        else { // 'top' 'right'\n            showPlayBtn && (playPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);\n            showPrevBtn && (prevBtnPosition = [0, 0], xLeft += sizePlusGap);\n            showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);\n        }\n        axisExtent = [xLeft, xRight];\n\n        if (timelineModel.get('inverse')) {\n            axisExtent.reverse();\n        }\n\n        return {\n            viewRect: viewRect,\n            mainLength: mainLength,\n            orient: orient,\n\n            rotation: rotationMap[orient],\n            labelRotation: labelRotation,\n            labelPosOpt: labelPosOpt,\n            labelAlign: timelineModel.get('label.align') || labelAlignMap[orient],\n            labelBaseline: timelineModel.get('label.verticalAlign')\n                || timelineModel.get('label.baseline')\n                || labelBaselineMap[orient],\n\n            // Based on mainGroup.\n            playPosition: playPosition,\n            prevBtnPosition: prevBtnPosition,\n            nextBtnPosition: nextBtnPosition,\n            axisExtent: axisExtent,\n\n            controlSize: controlSize,\n            controlGap: controlGap\n        };\n    },\n\n    _position: function (layoutInfo, timelineModel) {\n        // Position is be called finally, because bounding rect is needed for\n        // adapt content to fill viewRect (auto adapt offset).\n\n        // Timeline may be not all in the viewRect when 'offset' is specified\n        // as a number, because it is more appropriate that label aligns at\n        // 'offset' but not the other edge defined by viewRect.\n\n        var mainGroup = this._mainGroup;\n        var labelGroup = this._labelGroup;\n\n        var viewRect = layoutInfo.viewRect;\n        if (layoutInfo.orient === 'vertical') {\n            // transform to horizontal, inverse rotate by left-top point.\n            var m = create$1();\n            var rotateOriginX = viewRect.x;\n            var rotateOriginY = viewRect.y + viewRect.height;\n            translate(m, m, [-rotateOriginX, -rotateOriginY]);\n            rotate(m, m, -PI$4 / 2);\n            translate(m, m, [rotateOriginX, rotateOriginY]);\n            viewRect = viewRect.clone();\n            viewRect.applyTransform(m);\n        }\n\n        var viewBound = getBound(viewRect);\n        var mainBound = getBound(mainGroup.getBoundingRect());\n        var labelBound = getBound(labelGroup.getBoundingRect());\n\n        var mainPosition = mainGroup.position;\n        var labelsPosition = labelGroup.position;\n\n        labelsPosition[0] = mainPosition[0] = viewBound[0][0];\n\n        var labelPosOpt = layoutInfo.labelPosOpt;\n\n        if (isNaN(labelPosOpt)) { // '+' or '-'\n            var mainBoundIdx = labelPosOpt === '+' ? 0 : 1;\n            toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx);\n            toBound(labelsPosition, labelBound, viewBound, 1, 1 - mainBoundIdx);\n        }\n        else {\n            var mainBoundIdx = labelPosOpt >= 0 ? 0 : 1;\n            toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx);\n            labelsPosition[1] = mainPosition[1] + labelPosOpt;\n        }\n\n        mainGroup.attr('position', mainPosition);\n        labelGroup.attr('position', labelsPosition);\n        mainGroup.rotation = labelGroup.rotation = layoutInfo.rotation;\n\n        setOrigin(mainGroup);\n        setOrigin(labelGroup);\n\n        function setOrigin(targetGroup) {\n            var pos = targetGroup.position;\n            targetGroup.origin = [\n                viewBound[0][0] - pos[0],\n                viewBound[1][0] - pos[1]\n            ];\n        }\n\n        function getBound(rect) {\n            // [[xmin, xmax], [ymin, ymax]]\n            return [\n                [rect.x, rect.x + rect.width],\n                [rect.y, rect.y + rect.height]\n            ];\n        }\n\n        function toBound(fromPos, from, to, dimIdx, boundIdx) {\n            fromPos[dimIdx] += to[dimIdx][boundIdx] - from[dimIdx][boundIdx];\n        }\n    },\n\n    _createAxis: function (layoutInfo, timelineModel) {\n        var data = timelineModel.getData();\n        var axisType = timelineModel.get('axisType');\n\n        var scale = createScaleByModel(timelineModel, axisType);\n\n        // Customize scale. The `tickValue` is `dataIndex`.\n        scale.getTicks = function () {\n            return data.mapArray(['value'], function (value) {\n                return value;\n            });\n        };\n\n        var dataExtent = data.getDataExtent('value');\n        scale.setExtent(dataExtent[0], dataExtent[1]);\n        scale.niceTicks();\n\n        var axis = new TimelineAxis('value', scale, layoutInfo.axisExtent, axisType);\n        axis.model = timelineModel;\n\n        return axis;\n    },\n\n    _createGroup: function (name) {\n        var newGroup = this['_' + name] = new Group();\n        this.group.add(newGroup);\n        return newGroup;\n    },\n\n    _renderAxisLine: function (layoutInfo, group, axis, timelineModel) {\n        var axisExtent = axis.getExtent();\n\n        if (!timelineModel.get('lineStyle.show')) {\n            return;\n        }\n\n        group.add(new Line({\n            shape: {\n                x1: axisExtent[0], y1: 0,\n                x2: axisExtent[1], y2: 0\n            },\n            style: extend(\n                {lineCap: 'round'},\n                timelineModel.getModel('lineStyle').getLineStyle()\n            ),\n            silent: true,\n            z2: 1\n        }));\n    },\n\n    /**\n     * @private\n     */\n    _renderAxisTick: function (layoutInfo, group, axis, timelineModel) {\n        var data = timelineModel.getData();\n        // Show all ticks, despite ignoring strategy.\n        var ticks = axis.scale.getTicks();\n\n        // The value is dataIndex, see the costomized scale.\n        each$27(ticks, function (value) {\n            var tickCoord = axis.dataToCoord(value);\n            var itemModel = data.getItemModel(value);\n            var itemStyleModel = itemModel.getModel('itemStyle');\n            var hoverStyleModel = itemModel.getModel('emphasis.itemStyle');\n            var symbolOpt = {\n                position: [tickCoord, 0],\n                onclick: bind$6(this._changeTimeline, this, value)\n            };\n            var el = giveSymbol(itemModel, itemStyleModel, group, symbolOpt);\n            setHoverStyle(el, hoverStyleModel.getItemStyle());\n\n            if (itemModel.get('tooltip')) {\n                el.dataIndex = value;\n                el.dataModel = timelineModel;\n            }\n            else {\n                el.dataIndex = el.dataModel = null;\n            }\n\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _renderAxisLabel: function (layoutInfo, group, axis, timelineModel) {\n        var labelModel = axis.getLabelModel();\n\n        if (!labelModel.get('show')) {\n            return;\n        }\n\n        var data = timelineModel.getData();\n        var labels = axis.getViewLabels();\n\n        each$27(labels, function (labelItem) {\n            // The tickValue is dataIndex, see the costomized scale.\n            var dataIndex = labelItem.tickValue;\n\n            var itemModel = data.getItemModel(dataIndex);\n            var normalLabelModel = itemModel.getModel('label');\n            var hoverLabelModel = itemModel.getModel('emphasis.label');\n            var tickCoord = axis.dataToCoord(labelItem.tickValue);\n            var textEl = new Text({\n                position: [tickCoord, 0],\n                rotation: layoutInfo.labelRotation - layoutInfo.rotation,\n                onclick: bind$6(this._changeTimeline, this, dataIndex),\n                silent: false\n            });\n            setTextStyle(textEl.style, normalLabelModel, {\n                text: labelItem.formattedLabel,\n                textAlign: layoutInfo.labelAlign,\n                textVerticalAlign: layoutInfo.labelBaseline\n            });\n\n            group.add(textEl);\n            setHoverStyle(\n                textEl, setTextStyle({}, hoverLabelModel)\n            );\n\n        }, this);\n    },\n\n    /**\n     * @private\n     */\n    _renderControl: function (layoutInfo, group, axis, timelineModel) {\n        var controlSize = layoutInfo.controlSize;\n        var rotation = layoutInfo.rotation;\n\n        var itemStyle = timelineModel.getModel('controlStyle').getItemStyle();\n        var hoverStyle = timelineModel.getModel('emphasis.controlStyle').getItemStyle();\n        var rect = [0, -controlSize / 2, controlSize, controlSize];\n        var playState = timelineModel.getPlayState();\n        var inverse = timelineModel.get('inverse', true);\n\n        makeBtn(\n            layoutInfo.nextBtnPosition,\n            'controlStyle.nextIcon',\n            bind$6(this._changeTimeline, this, inverse ? '-' : '+')\n        );\n        makeBtn(\n            layoutInfo.prevBtnPosition,\n            'controlStyle.prevIcon',\n            bind$6(this._changeTimeline, this, inverse ? '+' : '-')\n        );\n        makeBtn(\n            layoutInfo.playPosition,\n            'controlStyle.' + (playState ? 'stopIcon' : 'playIcon'),\n            bind$6(this._handlePlayClick, this, !playState),\n            true\n        );\n\n        function makeBtn(position, iconPath, onclick, willRotate) {\n            if (!position) {\n                return;\n            }\n            var opt = {\n                position: position,\n                origin: [controlSize / 2, 0],\n                rotation: willRotate ? -rotation : 0,\n                rectHover: true,\n                style: itemStyle,\n                onclick: onclick\n            };\n            var btn = makeIcon(timelineModel, iconPath, rect, opt);\n            group.add(btn);\n            setHoverStyle(btn, hoverStyle);\n        }\n    },\n\n    _renderCurrentPointer: function (layoutInfo, group, axis, timelineModel) {\n        var data = timelineModel.getData();\n        var currentIndex = timelineModel.getCurrentIndex();\n        var pointerModel = data.getItemModel(currentIndex).getModel('checkpointStyle');\n        var me = this;\n\n        var callback = {\n            onCreate: function (pointer) {\n                pointer.draggable = true;\n                pointer.drift = bind$6(me._handlePointerDrag, me);\n                pointer.ondragend = bind$6(me._handlePointerDragend, me);\n                pointerMoveTo(pointer, currentIndex, axis, timelineModel, true);\n            },\n            onUpdate: function (pointer) {\n                pointerMoveTo(pointer, currentIndex, axis, timelineModel);\n            }\n        };\n\n        // Reuse when exists, for animation and drag.\n        this._currentPointer = giveSymbol(\n            pointerModel, pointerModel, this._mainGroup, {}, this._currentPointer, callback\n        );\n    },\n\n    _handlePlayClick: function (nextState) {\n        this._clearTimer();\n        this.api.dispatchAction({\n            type: 'timelinePlayChange',\n            playState: nextState,\n            from: this.uid\n        });\n    },\n\n    _handlePointerDrag: function (dx, dy, e) {\n        this._clearTimer();\n        this._pointerChangeTimeline([e.offsetX, e.offsetY]);\n    },\n\n    _handlePointerDragend: function (e) {\n        this._pointerChangeTimeline([e.offsetX, e.offsetY], true);\n    },\n\n    _pointerChangeTimeline: function (mousePos, trigger) {\n        var toCoord = this._toAxisCoord(mousePos)[0];\n\n        var axis = this._axis;\n        var axisExtent = asc(axis.getExtent().slice());\n\n        toCoord > axisExtent[1] && (toCoord = axisExtent[1]);\n        toCoord < axisExtent[0] && (toCoord = axisExtent[0]);\n\n        this._currentPointer.position[0] = toCoord;\n        this._currentPointer.dirty();\n\n        var targetDataIndex = this._findNearestTick(toCoord);\n        var timelineModel = this.model;\n\n        if (trigger || (\n            targetDataIndex !== timelineModel.getCurrentIndex()\n            && timelineModel.get('realtime')\n        )) {\n            this._changeTimeline(targetDataIndex);\n        }\n    },\n\n    _doPlayStop: function () {\n        this._clearTimer();\n\n        if (this.model.getPlayState()) {\n            this._timer = setTimeout(\n                bind$6(handleFrame, this),\n                this.model.get('playInterval')\n            );\n        }\n\n        function handleFrame() {\n            // Do not cache\n            var timelineModel = this.model;\n            this._changeTimeline(\n                timelineModel.getCurrentIndex()\n                + (timelineModel.get('rewind', true) ? -1 : 1)\n            );\n        }\n    },\n\n    _toAxisCoord: function (vertex) {\n        var trans = this._mainGroup.getLocalTransform();\n        return applyTransform$1(vertex, trans, true);\n    },\n\n    _findNearestTick: function (axisCoord) {\n        var data = this.model.getData();\n        var dist = Infinity;\n        var targetDataIndex;\n        var axis = this._axis;\n\n        data.each(['value'], function (value, dataIndex) {\n            var coord = axis.dataToCoord(value);\n            var d = Math.abs(coord - axisCoord);\n            if (d < dist) {\n                dist = d;\n                targetDataIndex = dataIndex;\n            }\n        });\n\n        return targetDataIndex;\n    },\n\n    _clearTimer: function () {\n        if (this._timer) {\n            clearTimeout(this._timer);\n            this._timer = null;\n        }\n    },\n\n    _changeTimeline: function (nextIndex) {\n        var currentIndex = this.model.getCurrentIndex();\n\n        if (nextIndex === '+') {\n            nextIndex = currentIndex + 1;\n        }\n        else if (nextIndex === '-') {\n            nextIndex = currentIndex - 1;\n        }\n\n        this.api.dispatchAction({\n            type: 'timelineChange',\n            currentIndex: nextIndex,\n            from: this.uid\n        });\n    }\n\n});\n\nfunction getViewRect$4(model, api) {\n    return getLayoutRect(\n        model.getBoxLayoutParams(),\n        {\n            width: api.getWidth(),\n            height: api.getHeight()\n        },\n        model.get('padding')\n    );\n}\n\nfunction makeIcon(timelineModel, objPath, rect, opts) {\n    var icon = makePath(\n        timelineModel.get(objPath).replace(/^path:\\/\\//, ''),\n        clone(opts || {}),\n        new BoundingRect(rect[0], rect[1], rect[2], rect[3]),\n        'center'\n    );\n\n    return icon;\n}\n\n/**\n * Create symbol or update symbol\n * opt: basic position and event handlers\n */\nfunction giveSymbol(hostModel, itemStyleModel, group, opt, symbol, callback) {\n    var color = itemStyleModel.get('color');\n\n    if (!symbol) {\n        var symbolType = hostModel.get('symbol');\n        symbol = createSymbol(symbolType, -1, -1, 2, 2, color);\n        symbol.setStyle('strokeNoScale', true);\n        group.add(symbol);\n        callback && callback.onCreate(symbol);\n    }\n    else {\n        symbol.setColor(color);\n        group.add(symbol); // Group may be new, also need to add.\n        callback && callback.onUpdate(symbol);\n    }\n\n    // Style\n    var itemStyle = itemStyleModel.getItemStyle(['color', 'symbol', 'symbolSize']);\n    symbol.setStyle(itemStyle);\n\n    // Transform and events.\n    opt = merge({\n        rectHover: true,\n        z2: 100\n    }, opt, true);\n\n    var symbolSize = hostModel.get('symbolSize');\n    symbolSize = symbolSize instanceof Array\n        ? symbolSize.slice()\n        : [+symbolSize, +symbolSize];\n    symbolSize[0] /= 2;\n    symbolSize[1] /= 2;\n    opt.scale = symbolSize;\n\n    var symbolOffset = hostModel.get('symbolOffset');\n    if (symbolOffset) {\n        var pos = opt.position = opt.position || [0, 0];\n        pos[0] += parsePercent$1(symbolOffset[0], symbolSize[0]);\n        pos[1] += parsePercent$1(symbolOffset[1], symbolSize[1]);\n    }\n\n    var symbolRotate = hostModel.get('symbolRotate');\n    opt.rotation = (symbolRotate || 0) * Math.PI / 180 || 0;\n\n    symbol.attr(opt);\n\n    // FIXME\n    // (1) When symbol.style.strokeNoScale is true and updateTransform is not performed,\n    // getBoundingRect will return wrong result.\n    // (This is supposed to be resolved in zrender, but it is a little difficult to\n    // leverage performance and auto updateTransform)\n    // (2) All of ancesters of symbol do not scale, so we can just updateTransform symbol.\n    symbol.updateTransform();\n\n    return symbol;\n}\n\nfunction pointerMoveTo(pointer, dataIndex, axis, timelineModel, noAnimation) {\n    if (pointer.dragging) {\n        return;\n    }\n\n    var pointerModel = timelineModel.getModel('checkpointStyle');\n    var toCoord = axis.dataToCoord(timelineModel.getData().get(['value'], dataIndex));\n\n    if (noAnimation || !pointerModel.get('animation', true)) {\n        pointer.attr({position: [toCoord, 0]});\n    }\n    else {\n        pointer.stopAnimation(true);\n        pointer.animateTo(\n            {position: [toCoord, 0]},\n            pointerModel.get('animationDuration', true),\n            pointerModel.get('animationEasing', true)\n        );\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\nregisterPreprocessor(preprocessor$3);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar ToolboxModel = extendComponentModel({\n\n    type: 'toolbox',\n\n    layoutMode: {\n        type: 'box',\n        ignoreSize: true\n    },\n\n    optionUpdated: function () {\n        ToolboxModel.superApply(this, 'optionUpdated', arguments);\n\n        each$1(this.option.feature, function (featureOpt, featureName) {\n            var Feature = get$1(featureName);\n            Feature && merge(featureOpt, Feature.defaultOption);\n        });\n    },\n\n    defaultOption: {\n\n        show: true,\n\n        z: 6,\n\n        zlevel: 0,\n\n        orient: 'horizontal',\n\n        left: 'right',\n\n        top: 'top',\n\n        // right\n        // bottom\n\n        backgroundColor: 'transparent',\n\n        borderColor: '#ccc',\n\n        borderRadius: 0,\n\n        borderWidth: 0,\n\n        padding: 5,\n\n        itemSize: 15,\n\n        itemGap: 8,\n\n        showTitle: true,\n\n        iconStyle: {\n            borderColor: '#666',\n            color: 'none'\n        },\n        emphasis: {\n            iconStyle: {\n                borderColor: '#3E98C5'\n            }\n        }\n        // textStyle: {},\n\n        // feature\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nextendComponentView({\n\n    type: 'toolbox',\n\n    render: function (toolboxModel, ecModel, api, payload) {\n        var group = this.group;\n        group.removeAll();\n\n        if (!toolboxModel.get('show')) {\n            return;\n        }\n\n        var itemSize = +toolboxModel.get('itemSize');\n        var featureOpts = toolboxModel.get('feature') || {};\n        var features = this._features || (this._features = {});\n\n        var featureNames = [];\n        each$1(featureOpts, function (opt, name) {\n            featureNames.push(name);\n        });\n\n        (new DataDiffer(this._featureNames || [], featureNames))\n            .add(processFeature)\n            .update(processFeature)\n            .remove(curry(processFeature, null))\n            .execute();\n\n        // Keep for diff.\n        this._featureNames = featureNames;\n\n        function processFeature(newIndex, oldIndex) {\n            var featureName = featureNames[newIndex];\n            var oldName = featureNames[oldIndex];\n            var featureOpt = featureOpts[featureName];\n            var featureModel = new Model(featureOpt, toolboxModel, toolboxModel.ecModel);\n            var feature;\n\n            if (featureName && !oldName) { // Create\n                if (isUserFeatureName(featureName)) {\n                    feature = {\n                        model: featureModel,\n                        onclick: featureModel.option.onclick,\n                        featureName: featureName\n                    };\n                }\n                else {\n                    var Feature = get$1(featureName);\n                    if (!Feature) {\n                        return;\n                    }\n                    feature = new Feature(featureModel, ecModel, api);\n                }\n                features[featureName] = feature;\n            }\n            else {\n                feature = features[oldName];\n                // If feature does not exsit.\n                if (!feature) {\n                    return;\n                }\n                feature.model = featureModel;\n                feature.ecModel = ecModel;\n                feature.api = api;\n            }\n\n            if (!featureName && oldName) {\n                feature.dispose && feature.dispose(ecModel, api);\n                return;\n            }\n\n            if (!featureModel.get('show') || feature.unusable) {\n                feature.remove && feature.remove(ecModel, api);\n                return;\n            }\n\n            createIconPaths(featureModel, feature, featureName);\n\n            featureModel.setIconStatus = function (iconName, status) {\n                var option = this.option;\n                var iconPaths = this.iconPaths;\n                option.iconStatus = option.iconStatus || {};\n                option.iconStatus[iconName] = status;\n                // FIXME\n                iconPaths[iconName] && iconPaths[iconName].trigger(status);\n            };\n\n            if (feature.render) {\n                feature.render(featureModel, ecModel, api, payload);\n            }\n        }\n\n        function createIconPaths(featureModel, feature, featureName) {\n            var iconStyleModel = featureModel.getModel('iconStyle');\n            var iconStyleEmphasisModel = featureModel.getModel('emphasis.iconStyle');\n\n            // If one feature has mutiple icon. they are orginaized as\n            // {\n            //     icon: {\n            //         foo: '',\n            //         bar: ''\n            //     },\n            //     title: {\n            //         foo: '',\n            //         bar: ''\n            //     }\n            // }\n            var icons = feature.getIcons ? feature.getIcons() : featureModel.get('icon');\n            var titles = featureModel.get('title') || {};\n            if (typeof icons === 'string') {\n                var icon = icons;\n                var title = titles;\n                icons = {};\n                titles = {};\n                icons[featureName] = icon;\n                titles[featureName] = title;\n            }\n            var iconPaths = featureModel.iconPaths = {};\n            each$1(icons, function (iconStr, iconName) {\n                var path = createIcon(\n                    iconStr,\n                    {},\n                    {\n                        x: -itemSize / 2,\n                        y: -itemSize / 2,\n                        width: itemSize,\n                        height: itemSize\n                    }\n                );\n                path.setStyle(iconStyleModel.getItemStyle());\n                path.hoverStyle = iconStyleEmphasisModel.getItemStyle();\n\n                setHoverStyle(path);\n\n                if (toolboxModel.get('showTitle')) {\n                    path.__title = titles[iconName];\n                    path.on('mouseover', function () {\n                            // Should not reuse above hoverStyle, which might be modified.\n                            var hoverStyle = iconStyleEmphasisModel.getItemStyle();\n                            path.setStyle({\n                                text: titles[iconName],\n                                textPosition: hoverStyle.textPosition || 'bottom',\n                                textFill: hoverStyle.fill || hoverStyle.stroke || '#000',\n                                textAlign: hoverStyle.textAlign || 'center'\n                            });\n                        })\n                        .on('mouseout', function () {\n                            path.setStyle({\n                                textFill: null\n                            });\n                        });\n                }\n                path.trigger(featureModel.get('iconStatus.' + iconName) || 'normal');\n\n                group.add(path);\n                path.on('click', bind(\n                    feature.onclick, feature, ecModel, api, iconName\n                ));\n\n                iconPaths[iconName] = path;\n            });\n        }\n\n        layout$3(group, toolboxModel, api);\n        // Render background after group is layout\n        // FIXME\n        group.add(makeBackground(group.getBoundingRect(), toolboxModel));\n\n        // Adjust icon title positions to avoid them out of screen\n        group.eachChild(function (icon) {\n            var titleText = icon.__title;\n            var hoverStyle = icon.hoverStyle;\n            // May be background element\n            if (hoverStyle && titleText) {\n                var rect = getBoundingRect(\n                    titleText, makeFont(hoverStyle)\n                );\n                var offsetX = icon.position[0] + group.position[0];\n                var offsetY = icon.position[1] + group.position[1] + itemSize;\n\n                var needPutOnTop = false;\n                if (offsetY + rect.height > api.getHeight()) {\n                    hoverStyle.textPosition = 'top';\n                    needPutOnTop = true;\n                }\n                var topOffset = needPutOnTop ? (-5 - rect.height) : (itemSize + 8);\n                if (offsetX + rect.width / 2 > api.getWidth()) {\n                    hoverStyle.textPosition = ['100%', topOffset];\n                    hoverStyle.textAlign = 'right';\n                }\n                else if (offsetX - rect.width / 2 < 0) {\n                    hoverStyle.textPosition = [0, topOffset];\n                    hoverStyle.textAlign = 'left';\n                }\n            }\n        });\n    },\n\n    updateView: function (toolboxModel, ecModel, api, payload) {\n        each$1(this._features, function (feature) {\n            feature.updateView && feature.updateView(feature.model, ecModel, api, payload);\n        });\n    },\n\n    // updateLayout: function (toolboxModel, ecModel, api, payload) {\n    //     zrUtil.each(this._features, function (feature) {\n    //         feature.updateLayout && feature.updateLayout(feature.model, ecModel, api, payload);\n    //     });\n    // },\n\n    remove: function (ecModel, api) {\n        each$1(this._features, function (feature) {\n            feature.remove && feature.remove(ecModel, api);\n        });\n        this.group.removeAll();\n    },\n\n    dispose: function (ecModel, api) {\n        each$1(this._features, function (feature) {\n            feature.dispose && feature.dispose(ecModel, api);\n        });\n    }\n});\n\nfunction isUserFeatureName(featureName) {\n    return featureName.indexOf('my') === 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Uint8Array */\n\nvar saveAsImageLang = lang.toolbox.saveAsImage;\n\nfunction SaveAsImage(model) {\n    this.model = model;\n}\n\nSaveAsImage.defaultOption = {\n    show: true,\n    icon: 'M4.7,22.9L29.3,45.5L54.7,23.4M4.6,43.6L4.6,58L53.8,58L53.8,43.6M29.2,45.1L29.2,0',\n    title: saveAsImageLang.title,\n    type: 'png',\n    // Default use option.backgroundColor\n    // backgroundColor: '#fff',\n    name: '',\n    excludeComponents: ['toolbox'],\n    pixelRatio: 1,\n    lang: saveAsImageLang.lang.slice()\n};\n\nSaveAsImage.prototype.unusable = !env$1.canvasSupported;\n\nvar proto$4 = SaveAsImage.prototype;\n\nproto$4.onclick = function (ecModel, api) {\n    var model = this.model;\n    var title = model.get('name') || ecModel.get('title.0.text') || 'echarts';\n    var $a = document.createElement('a');\n    var type = model.get('type', true) || 'png';\n    $a.download = title + '.' + type;\n    $a.target = '_blank';\n    var url = api.getConnectedDataURL({\n        type: type,\n        backgroundColor: model.get('backgroundColor', true)\n            || ecModel.get('backgroundColor') || '#fff',\n        excludeComponents: model.get('excludeComponents'),\n        pixelRatio: model.get('pixelRatio')\n    });\n    $a.href = url;\n    // Chrome and Firefox\n    if (typeof MouseEvent === 'function' && !env$1.browser.ie && !env$1.browser.edge) {\n        var evt = new MouseEvent('click', {\n            view: window,\n            bubbles: true,\n            cancelable: false\n        });\n        $a.dispatchEvent(evt);\n    }\n    // IE\n    else {\n        if (window.navigator.msSaveOrOpenBlob) {\n            var bstr = atob(url.split(',')[1]);\n            var n = bstr.length;\n            var u8arr = new Uint8Array(n);\n            while (n--) {\n                u8arr[n] = bstr.charCodeAt(n);\n            }\n            var blob = new Blob([u8arr]);\n            window.navigator.msSaveOrOpenBlob(blob, title + '.' + type);\n        }\n        else {\n            var lang$$1 = model.get('lang');\n            var html = ''\n                + '<body style=\"margin:0;\">'\n                + '<img src=\"' + url + '\" style=\"max-width:100%;\" title=\"' + ((lang$$1 && lang$$1[0]) || '') + '\" />'\n                + '</body>';\n            var tab = window.open();\n            tab.document.write(html);\n        }\n    }\n};\n\nregister$1(\n    'saveAsImage', SaveAsImage\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar magicTypeLang = lang.toolbox.magicType;\n\nfunction MagicType(model) {\n    this.model = model;\n}\n\nMagicType.defaultOption = {\n    show: true,\n    type: [],\n    // Icon group\n    icon: {\n        /* eslint-disable */\n        line: 'M4.1,28.9h7.1l9.3-22l7.4,38l9.7-19.7l3,12.8h14.9M4.1,58h51.4',\n        bar: 'M6.7,22.9h10V48h-10V22.9zM24.9,13h10v35h-10V13zM43.2,2h10v46h-10V2zM3.1,58h53.7',\n        stack: 'M8.2,38.4l-8.4,4.1l30.6,15.3L60,42.5l-8.1-4.1l-21.5,11L8.2,38.4z M51.9,30l-8.1,4.2l-13.4,6.9l-13.9-6.9L8.2,30l-8.4,4.2l8.4,4.2l22.2,11l21.5-11l8.1-4.2L51.9,30z M51.9,21.7l-8.1,4.2L35.7,30l-5.3,2.8L24.9,30l-8.4-4.1l-8.3-4.2l-8.4,4.2L8.2,30l8.3,4.2l13.9,6.9l13.4-6.9l8.1-4.2l8.1-4.1L51.9,21.7zM30.4,2.2L-0.2,17.5l8.4,4.1l8.3,4.2l8.4,4.2l5.5,2.7l5.3-2.7l8.1-4.2l8.1-4.2l8.1-4.1L30.4,2.2z', // jshint ignore:line\n        tiled: 'M2.3,2.2h22.8V25H2.3V2.2z M35,2.2h22.8V25H35V2.2zM2.3,35h22.8v22.8H2.3V35z M35,35h22.8v22.8H35V35z'\n        /* eslint-enable */\n    },\n    // `line`, `bar`, `stack`, `tiled`\n    title: clone(magicTypeLang.title),\n    option: {},\n    seriesIndex: {}\n};\n\nvar proto$5 = MagicType.prototype;\n\nproto$5.getIcons = function () {\n    var model = this.model;\n    var availableIcons = model.get('icon');\n    var icons = {};\n    each$1(model.get('type'), function (type) {\n        if (availableIcons[type]) {\n            icons[type] = availableIcons[type];\n        }\n    });\n    return icons;\n};\n\nvar seriesOptGenreator = {\n    'line': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                type: 'line',\n                // Preserve data related option\n                data: seriesModel.get('data'),\n                stack: seriesModel.get('stack'),\n                markPoint: seriesModel.get('markPoint'),\n                markLine: seriesModel.get('markLine')\n            }, model.get('option.line') || {}, true);\n        }\n    },\n    'bar': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line') {\n            return merge({\n                id: seriesId,\n                type: 'bar',\n                // Preserve data related option\n                data: seriesModel.get('data'),\n                stack: seriesModel.get('stack'),\n                markPoint: seriesModel.get('markPoint'),\n                markLine: seriesModel.get('markLine')\n            }, model.get('option.bar') || {}, true);\n        }\n    },\n    'stack': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line' || seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                stack: '__ec_magicType_stack__'\n            }, model.get('option.stack') || {}, true);\n        }\n    },\n    'tiled': function (seriesType, seriesId, seriesModel, model) {\n        if (seriesType === 'line' || seriesType === 'bar') {\n            return merge({\n                id: seriesId,\n                stack: ''\n            }, model.get('option.tiled') || {}, true);\n        }\n    }\n};\n\nvar radioTypes = [\n    ['line', 'bar'],\n    ['stack', 'tiled']\n];\n\nproto$5.onclick = function (ecModel, api, type) {\n    var model = this.model;\n    var seriesIndex = model.get('seriesIndex.' + type);\n    // Not supported magicType\n    if (!seriesOptGenreator[type]) {\n        return;\n    }\n    var newOption = {\n        series: []\n    };\n    var generateNewSeriesTypes = function (seriesModel) {\n        var seriesType = seriesModel.subType;\n        var seriesId = seriesModel.id;\n        var newSeriesOpt = seriesOptGenreator[type](\n            seriesType, seriesId, seriesModel, model\n        );\n        if (newSeriesOpt) {\n            // PENDING If merge original option?\n            defaults(newSeriesOpt, seriesModel.option);\n            newOption.series.push(newSeriesOpt);\n        }\n        // Modify boundaryGap\n        var coordSys = seriesModel.coordinateSystem;\n        if (coordSys && coordSys.type === 'cartesian2d' && (type === 'line' || type === 'bar')) {\n            var categoryAxis = coordSys.getAxesByScale('ordinal')[0];\n            if (categoryAxis) {\n                var axisDim = categoryAxis.dim;\n                var axisType = axisDim + 'Axis';\n                var axisModel = ecModel.queryComponents({\n                    mainType: axisType,\n                    index: seriesModel.get(name + 'Index'),\n                    id: seriesModel.get(name + 'Id')\n                })[0];\n                var axisIndex = axisModel.componentIndex;\n\n                newOption[axisType] = newOption[axisType] || [];\n                for (var i = 0; i <= axisIndex; i++) {\n                    newOption[axisType][axisIndex] = newOption[axisType][axisIndex] || {};\n                }\n                newOption[axisType][axisIndex].boundaryGap = type === 'bar';\n            }\n        }\n    };\n\n    each$1(radioTypes, function (radio) {\n        if (indexOf(radio, type) >= 0) {\n            each$1(radio, function (item) {\n                model.setIconStatus(item, 'normal');\n            });\n        }\n    });\n\n    model.setIconStatus(type, 'emphasis');\n\n    ecModel.eachComponent(\n        {\n            mainType: 'series',\n            query: seriesIndex == null ? null : {\n                seriesIndex: seriesIndex\n            }\n        }, generateNewSeriesTypes\n    );\n    api.dispatchAction({\n        type: 'changeMagicType',\n        currentType: type,\n        newOption: newOption\n    });\n};\n\nregisterAction({\n    type: 'changeMagicType',\n    event: 'magicTypeChanged',\n    update: 'prepareAndUpdate'\n}, function (payload, ecModel) {\n    ecModel.mergeOption(payload.newOption);\n});\n\nregister$1('magicType', MagicType);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar dataViewLang = lang.toolbox.dataView;\n\nvar BLOCK_SPLITER = new Array(60).join('-');\nvar ITEM_SPLITER = '\\t';\n/**\n * Group series into two types\n *  1. on category axis, like line, bar\n *  2. others, like scatter, pie\n * @param {module:echarts/model/Global} ecModel\n * @return {Object}\n * @inner\n */\nfunction groupSeries(ecModel) {\n    var seriesGroupByCategoryAxis = {};\n    var otherSeries = [];\n    var meta = [];\n    ecModel.eachRawSeries(function (seriesModel) {\n        var coordSys = seriesModel.coordinateSystem;\n\n        if (coordSys && (coordSys.type === 'cartesian2d' || coordSys.type === 'polar')) {\n            var baseAxis = coordSys.getBaseAxis();\n            if (baseAxis.type === 'category') {\n                var key = baseAxis.dim + '_' + baseAxis.index;\n                if (!seriesGroupByCategoryAxis[key]) {\n                    seriesGroupByCategoryAxis[key] = {\n                        categoryAxis: baseAxis,\n                        valueAxis: coordSys.getOtherAxis(baseAxis),\n                        series: []\n                    };\n                    meta.push({\n                        axisDim: baseAxis.dim,\n                        axisIndex: baseAxis.index\n                    });\n                }\n                seriesGroupByCategoryAxis[key].series.push(seriesModel);\n            }\n            else {\n                otherSeries.push(seriesModel);\n            }\n        }\n        else {\n            otherSeries.push(seriesModel);\n        }\n    });\n\n    return {\n        seriesGroupByCategoryAxis: seriesGroupByCategoryAxis,\n        other: otherSeries,\n        meta: meta\n    };\n}\n\n/**\n * Assemble content of series on cateogory axis\n * @param {Array.<module:echarts/model/Series>} series\n * @return {string}\n * @inner\n */\nfunction assembleSeriesWithCategoryAxis(series) {\n    var tables = [];\n    each$1(series, function (group, key) {\n        var categoryAxis = group.categoryAxis;\n        var valueAxis = group.valueAxis;\n        var valueAxisDim = valueAxis.dim;\n\n        var headers = [' '].concat(map(group.series, function (series) {\n            return series.name;\n        }));\n        var columns = [categoryAxis.model.getCategories()];\n        each$1(group.series, function (series) {\n            columns.push(series.getRawData().mapArray(valueAxisDim, function (val) {\n                return val;\n            }));\n        });\n        // Assemble table content\n        var lines = [headers.join(ITEM_SPLITER)];\n        for (var i = 0; i < columns[0].length; i++) {\n            var items = [];\n            for (var j = 0; j < columns.length; j++) {\n                items.push(columns[j][i]);\n            }\n            lines.push(items.join(ITEM_SPLITER));\n        }\n        tables.push(lines.join('\\n'));\n    });\n    return tables.join('\\n\\n' + BLOCK_SPLITER + '\\n\\n');\n}\n\n/**\n * Assemble content of other series\n * @param {Array.<module:echarts/model/Series>} series\n * @return {string}\n * @inner\n */\nfunction assembleOtherSeries(series) {\n    return map(series, function (series) {\n        var data = series.getRawData();\n        var lines = [series.name];\n        var vals = [];\n        data.each(data.dimensions, function () {\n            var argLen = arguments.length;\n            var dataIndex = arguments[argLen - 1];\n            var name = data.getName(dataIndex);\n            for (var i = 0; i < argLen - 1; i++) {\n                vals[i] = arguments[i];\n            }\n            lines.push((name ? (name + ITEM_SPLITER) : '') + vals.join(ITEM_SPLITER));\n        });\n        return lines.join('\\n');\n    }).join('\\n\\n' + BLOCK_SPLITER + '\\n\\n');\n}\n\n/**\n * @param {module:echarts/model/Global}\n * @return {Object}\n * @inner\n */\nfunction getContentFromModel(ecModel) {\n\n    var result = groupSeries(ecModel);\n\n    return {\n        value: filter([\n                assembleSeriesWithCategoryAxis(result.seriesGroupByCategoryAxis),\n                assembleOtherSeries(result.other)\n            ], function (str) {\n                return str.replace(/[\\n\\t\\s]/g, '');\n            }).join('\\n\\n' + BLOCK_SPLITER + '\\n\\n'),\n\n        meta: result.meta\n    };\n}\n\n\nfunction trim$1(str) {\n    return str.replace(/^\\s\\s*/, '').replace(/\\s\\s*$/, '');\n}\n/**\n * If a block is tsv format\n */\nfunction isTSVFormat(block) {\n    // Simple method to find out if a block is tsv format\n    var firstLine = block.slice(0, block.indexOf('\\n'));\n    if (firstLine.indexOf(ITEM_SPLITER) >= 0) {\n        return true;\n    }\n}\n\nvar itemSplitRegex = new RegExp('[' + ITEM_SPLITER + ']+', 'g');\n/**\n * @param {string} tsv\n * @return {Object}\n */\nfunction parseTSVContents(tsv) {\n    var tsvLines = tsv.split(/\\n+/g);\n    var headers = trim$1(tsvLines.shift()).split(itemSplitRegex);\n\n    var categories = [];\n    var series = map(headers, function (header) {\n        return {\n            name: header,\n            data: []\n        };\n    });\n    for (var i = 0; i < tsvLines.length; i++) {\n        var items = trim$1(tsvLines[i]).split(itemSplitRegex);\n        categories.push(items.shift());\n        for (var j = 0; j < items.length; j++) {\n            series[j] && (series[j].data[i] = items[j]);\n        }\n    }\n    return {\n        series: series,\n        categories: categories\n    };\n}\n\n/**\n * @param {string} str\n * @return {Array.<Object>}\n * @inner\n */\nfunction parseListContents(str) {\n    var lines = str.split(/\\n+/g);\n    var seriesName = trim$1(lines.shift());\n\n    var data = [];\n    for (var i = 0; i < lines.length; i++) {\n        var items = trim$1(lines[i]).split(itemSplitRegex);\n        var name = '';\n        var value;\n        var hasName = false;\n        if (isNaN(items[0])) { // First item is name\n            hasName = true;\n            name = items[0];\n            items = items.slice(1);\n            data[i] = {\n                name: name,\n                value: []\n            };\n            value = data[i].value;\n        }\n        else {\n            value = data[i] = [];\n        }\n        for (var j = 0; j < items.length; j++) {\n            value.push(+items[j]);\n        }\n        if (value.length === 1) {\n            hasName ? (data[i].value = value[0]) : (data[i] = value[0]);\n        }\n    }\n\n    return {\n        name: seriesName,\n        data: data\n    };\n}\n\n/**\n * @param {string} str\n * @param {Array.<Object>} blockMetaList\n * @return {Object}\n * @inner\n */\nfunction parseContents(str, blockMetaList) {\n    var blocks = str.split(new RegExp('\\n*' + BLOCK_SPLITER + '\\n*', 'g'));\n    var newOption = {\n        series: []\n    };\n    each$1(blocks, function (block, idx) {\n        if (isTSVFormat(block)) {\n            var result = parseTSVContents(block);\n            var blockMeta = blockMetaList[idx];\n            var axisKey = blockMeta.axisDim + 'Axis';\n\n            if (blockMeta) {\n                newOption[axisKey] = newOption[axisKey] || [];\n                newOption[axisKey][blockMeta.axisIndex] = {\n                    data: result.categories\n                };\n                newOption.series = newOption.series.concat(result.series);\n            }\n        }\n        else {\n            var result = parseListContents(block);\n            newOption.series.push(result);\n        }\n    });\n    return newOption;\n}\n\n/**\n * @alias {module:echarts/component/toolbox/feature/DataView}\n * @constructor\n * @param {module:echarts/model/Model} model\n */\nfunction DataView(model) {\n\n    this._dom = null;\n\n    this.model = model;\n}\n\nDataView.defaultOption = {\n    show: true,\n    readOnly: false,\n    optionToContent: null,\n    contentToOption: null,\n\n    icon: 'M17.5,17.3H33 M17.5,17.3H33 M45.4,29.5h-28 M11.5,2v56H51V14.8L38.4,2H11.5z M38.4,2.2v12.7H51 M45.4,41.7h-28',\n    title: clone(dataViewLang.title),\n    lang: clone(dataViewLang.lang),\n    backgroundColor: '#fff',\n    textColor: '#000',\n    textareaColor: '#fff',\n    textareaBorderColor: '#333',\n    buttonColor: '#c23531',\n    buttonTextColor: '#fff'\n};\n\nDataView.prototype.onclick = function (ecModel, api) {\n    var container = api.getDom();\n    var model = this.model;\n    if (this._dom) {\n        container.removeChild(this._dom);\n    }\n    var root = document.createElement('div');\n    root.style.cssText = 'position:absolute;left:5px;top:5px;bottom:5px;right:5px;';\n    root.style.backgroundColor = model.get('backgroundColor') || '#fff';\n\n    // Create elements\n    var header = document.createElement('h4');\n    var lang$$1 = model.get('lang') || [];\n    header.innerHTML = lang$$1[0] || model.get('title');\n    header.style.cssText = 'margin: 10px 20px;';\n    header.style.color = model.get('textColor');\n\n    var viewMain = document.createElement('div');\n    var textarea = document.createElement('textarea');\n    viewMain.style.cssText = 'display:block;width:100%;overflow:auto;';\n\n    var optionToContent = model.get('optionToContent');\n    var contentToOption = model.get('contentToOption');\n    var result = getContentFromModel(ecModel);\n    if (typeof optionToContent === 'function') {\n        var htmlOrDom = optionToContent(api.getOption());\n        if (typeof htmlOrDom === 'string') {\n            viewMain.innerHTML = htmlOrDom;\n        }\n        else if (isDom(htmlOrDom)) {\n            viewMain.appendChild(htmlOrDom);\n        }\n    }\n    else {\n        // Use default textarea\n        viewMain.appendChild(textarea);\n        textarea.readOnly = model.get('readOnly');\n        textarea.style.cssText = 'width:100%;height:100%;font-family:monospace;font-size:14px;line-height:1.6rem;';\n        textarea.style.color = model.get('textColor');\n        textarea.style.borderColor = model.get('textareaBorderColor');\n        textarea.style.backgroundColor = model.get('textareaColor');\n        textarea.value = result.value;\n    }\n\n    var blockMetaList = result.meta;\n\n    var buttonContainer = document.createElement('div');\n    buttonContainer.style.cssText = 'position:absolute;bottom:0;left:0;right:0;';\n\n    var buttonStyle = 'float:right;margin-right:20px;border:none;'\n        + 'cursor:pointer;padding:2px 5px;font-size:12px;border-radius:3px';\n    var closeButton = document.createElement('div');\n    var refreshButton = document.createElement('div');\n\n    buttonStyle += ';background-color:' + model.get('buttonColor');\n    buttonStyle += ';color:' + model.get('buttonTextColor');\n\n    var self = this;\n\n    function close() {\n        container.removeChild(root);\n        self._dom = null;\n    }\n    addEventListener(closeButton, 'click', close);\n\n    addEventListener(refreshButton, 'click', function () {\n        var newOption;\n        try {\n            if (typeof contentToOption === 'function') {\n                newOption = contentToOption(viewMain, api.getOption());\n            }\n            else {\n                newOption = parseContents(textarea.value, blockMetaList);\n            }\n        }\n        catch (e) {\n            close();\n            throw new Error('Data view format error ' + e);\n        }\n        if (newOption) {\n            api.dispatchAction({\n                type: 'changeDataView',\n                newOption: newOption\n            });\n        }\n\n        close();\n    });\n\n    closeButton.innerHTML = lang$$1[1];\n    refreshButton.innerHTML = lang$$1[2];\n    refreshButton.style.cssText = buttonStyle;\n    closeButton.style.cssText = buttonStyle;\n\n    !model.get('readOnly') && buttonContainer.appendChild(refreshButton);\n    buttonContainer.appendChild(closeButton);\n\n    // http://stackoverflow.com/questions/6637341/use-tab-to-indent-in-textarea\n    addEventListener(textarea, 'keydown', function (e) {\n        if ((e.keyCode || e.which) === 9) {\n            // get caret position/selection\n            var val = this.value;\n            var start = this.selectionStart;\n            var end = this.selectionEnd;\n\n            // set textarea value to: text before caret + tab + text after caret\n            this.value = val.substring(0, start) + ITEM_SPLITER + val.substring(end);\n\n            // put caret at right position again\n            this.selectionStart = this.selectionEnd = start + 1;\n\n            // prevent the focus lose\n            stop(e);\n        }\n    });\n\n    root.appendChild(header);\n    root.appendChild(viewMain);\n    root.appendChild(buttonContainer);\n\n    viewMain.style.height = (container.clientHeight - 80) + 'px';\n\n    container.appendChild(root);\n    this._dom = root;\n};\n\nDataView.prototype.remove = function (ecModel, api) {\n    this._dom && api.getDom().removeChild(this._dom);\n};\n\nDataView.prototype.dispose = function (ecModel, api) {\n    this.remove(ecModel, api);\n};\n\n/**\n * @inner\n */\nfunction tryMergeDataOption(newData, originalData) {\n    return map(newData, function (newVal, idx) {\n        var original = originalData && originalData[idx];\n        if (isObject$1(original) && !isArray(original)) {\n            if (isObject$1(newVal) && !isArray(newVal)) {\n                newVal = newVal.value;\n            }\n            // Original data has option\n            return defaults({\n                value: newVal\n            }, original);\n        }\n        else {\n            return newVal;\n        }\n    });\n}\n\nregister$1('dataView', DataView);\n\nregisterAction({\n    type: 'changeDataView',\n    event: 'dataViewChanged',\n    update: 'prepareAndUpdate'\n}, function (payload, ecModel) {\n    var newSeriesOptList = [];\n    each$1(payload.newOption.series, function (seriesOpt) {\n        var seriesModel = ecModel.getSeriesByName(seriesOpt.name)[0];\n        if (!seriesModel) {\n            // New created series\n            // Geuss the series type\n            newSeriesOptList.push(extend({\n                // Default is scatter\n                type: 'scatter'\n            }, seriesOpt));\n        }\n        else {\n            var originalData = seriesModel.get('data');\n            newSeriesOptList.push({\n                name: seriesOpt.name,\n                data: tryMergeDataOption(seriesOpt.data, originalData)\n            });\n        }\n    });\n\n    ecModel.mergeOption(defaults({\n        series: newSeriesOptList\n    }, payload.newOption));\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$29 = each$1;\n\nvar ATTR$2 = '\\0_ec_hist_store';\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} newSnapshot {dataZoomId, batch: [payloadInfo, ...]}\n */\nfunction push(ecModel, newSnapshot) {\n    var store = giveStore$1(ecModel);\n\n    // If previous dataZoom can not be found,\n    // complete an range with current range.\n    each$29(newSnapshot, function (batchItem, dataZoomId) {\n        var i = store.length - 1;\n        for (; i >= 0; i--) {\n            var snapshot = store[i];\n            if (snapshot[dataZoomId]) {\n                break;\n            }\n        }\n        if (i < 0) {\n            // No origin range set, create one by current range.\n            var dataZoomModel = ecModel.queryComponents(\n                {mainType: 'dataZoom', subType: 'select', id: dataZoomId}\n            )[0];\n            if (dataZoomModel) {\n                var percentRange = dataZoomModel.getPercentRange();\n                store[0][dataZoomId] = {\n                    dataZoomId: dataZoomId,\n                    start: percentRange[0],\n                    end: percentRange[1]\n                };\n            }\n        }\n    });\n\n    store.push(newSnapshot);\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @return {Object} snapshot\n */\nfunction pop(ecModel) {\n    var store = giveStore$1(ecModel);\n    var head = store[store.length - 1];\n    store.length > 1 && store.pop();\n\n    // Find top for all dataZoom.\n    var snapshot = {};\n    each$29(head, function (batchItem, dataZoomId) {\n        for (var i = store.length - 1; i >= 0; i--) {\n            var batchItem = store[i][dataZoomId];\n            if (batchItem) {\n                snapshot[dataZoomId] = batchItem;\n                break;\n            }\n        }\n    });\n\n    return snapshot;\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n */\nfunction clear$1(ecModel) {\n    ecModel[ATTR$2] = null;\n}\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @return {number} records. always >= 1.\n */\nfunction count(ecModel) {\n    return giveStore$1(ecModel).length;\n}\n\n/**\n * [{key: dataZoomId, value: {dataZoomId, range}}, ...]\n * History length of each dataZoom may be different.\n * this._history[0] is used to store origin range.\n * @type {Array.<Object>}\n */\nfunction giveStore$1(ecModel) {\n    var store = ecModel[ATTR$2];\n    if (!store) {\n        store = ecModel[ATTR$2] = [{}];\n    }\n    return store;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomModel.extend({\n    type: 'dataZoom.select'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nDataZoomView.extend({\n    type: 'dataZoom.select'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * DataZoom component entry\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Use dataZoomSelect\nvar dataZoomLang = lang.toolbox.dataZoom;\nvar each$28 = each$1;\n\n// Spectial component id start with \\0ec\\0, see echarts/model/Global.js~hasInnerId\nvar DATA_ZOOM_ID_BASE = '\\0_ec_\\0toolbox-dataZoom_';\n\nfunction DataZoom(model, ecModel, api) {\n\n    /**\n     * @private\n     * @type {module:echarts/component/helper/BrushController}\n     */\n    (this._brushController = new BrushController(api.getZr()))\n        .on('brush', bind(this._onBrush, this))\n        .mount();\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._isZoomActive;\n}\n\nDataZoom.defaultOption = {\n    show: true,\n    // Icon group\n    icon: {\n        zoom: 'M0,13.5h26.9 M13.5,26.9V0 M32.1,13.5H58V58H13.5 V32.1',\n        back: 'M22,1.4L9.9,13.5l12.3,12.3 M10.3,13.5H54.9v44.6 H10.3v-26'\n    },\n    // `zoom`, `back`\n    title: clone(dataZoomLang.title)\n};\n\nvar proto$6 = DataZoom.prototype;\n\nproto$6.render = function (featureModel, ecModel, api, payload) {\n    this.model = featureModel;\n    this.ecModel = ecModel;\n    this.api = api;\n\n    updateZoomBtnStatus(featureModel, ecModel, this, payload, api);\n    updateBackBtnStatus(featureModel, ecModel);\n};\n\nproto$6.onclick = function (ecModel, api, type) {\n    handlers$1[type].call(this);\n};\n\nproto$6.remove = function (ecModel, api) {\n    this._brushController.unmount();\n};\n\nproto$6.dispose = function (ecModel, api) {\n    this._brushController.dispose();\n};\n\n/**\n * @private\n */\nvar handlers$1 = {\n\n    zoom: function () {\n        var nextActive = !this._isZoomActive;\n\n        this.api.dispatchAction({\n            type: 'takeGlobalCursor',\n            key: 'dataZoomSelect',\n            dataZoomSelectActive: nextActive\n        });\n    },\n\n    back: function () {\n        this._dispatchZoomAction(pop(this.ecModel));\n    }\n};\n\n/**\n * @private\n */\nproto$6._onBrush = function (areas, opt) {\n    if (!opt.isEnd || !areas.length) {\n        return;\n    }\n    var snapshot = {};\n    var ecModel = this.ecModel;\n\n    this._brushController.updateCovers([]); // remove cover\n\n    var brushTargetManager = new BrushTargetManager(\n        retrieveAxisSetting(this.model.option), ecModel, {include: ['grid']}\n    );\n    brushTargetManager.matchOutputRanges(areas, ecModel, function (area, coordRange, coordSys) {\n        if (coordSys.type !== 'cartesian2d') {\n            return;\n        }\n\n        var brushType = area.brushType;\n        if (brushType === 'rect') {\n            setBatch('x', coordSys, coordRange[0]);\n            setBatch('y', coordSys, coordRange[1]);\n        }\n        else {\n            setBatch(({lineX: 'x', lineY: 'y'})[brushType], coordSys, coordRange);\n        }\n    });\n\n    push(ecModel, snapshot);\n\n    this._dispatchZoomAction(snapshot);\n\n    function setBatch(dimName, coordSys, minMax) {\n        var axis = coordSys.getAxis(dimName);\n        var axisModel = axis.model;\n        var dataZoomModel = findDataZoom(dimName, axisModel, ecModel);\n\n        // Restrict range.\n        var minMaxSpan = dataZoomModel.findRepresentativeAxisProxy(axisModel).getMinMaxSpan();\n        if (minMaxSpan.minValueSpan != null || minMaxSpan.maxValueSpan != null) {\n            minMax = sliderMove(\n                0, minMax.slice(), axis.scale.getExtent(), 0,\n                minMaxSpan.minValueSpan, minMaxSpan.maxValueSpan\n            );\n        }\n\n        dataZoomModel && (snapshot[dataZoomModel.id] = {\n            dataZoomId: dataZoomModel.id,\n            startValue: minMax[0],\n            endValue: minMax[1]\n        });\n    }\n\n    function findDataZoom(dimName, axisModel, ecModel) {\n        var found;\n        ecModel.eachComponent({mainType: 'dataZoom', subType: 'select'}, function (dzModel) {\n            var has = dzModel.getAxisModel(dimName, axisModel.componentIndex);\n            has && (found = dzModel);\n        });\n        return found;\n    }\n};\n\n/**\n * @private\n */\nproto$6._dispatchZoomAction = function (snapshot) {\n    var batch = [];\n\n    // Convert from hash map to array.\n    each$28(snapshot, function (batchItem, dataZoomId) {\n        batch.push(clone(batchItem));\n    });\n\n    batch.length && this.api.dispatchAction({\n        type: 'dataZoom',\n        from: this.uid,\n        batch: batch\n    });\n};\n\nfunction retrieveAxisSetting(option) {\n    var setting = {};\n    // Compatible with previous setting: null => all axis, false => no axis.\n    each$1(['xAxisIndex', 'yAxisIndex'], function (name) {\n        setting[name] = option[name];\n        setting[name] == null && (setting[name] = 'all');\n        (setting[name] === false || setting[name] === 'none') && (setting[name] = []);\n    });\n    return setting;\n}\n\nfunction updateBackBtnStatus(featureModel, ecModel) {\n    featureModel.setIconStatus(\n        'back',\n        count(ecModel) > 1 ? 'emphasis' : 'normal'\n    );\n}\n\nfunction updateZoomBtnStatus(featureModel, ecModel, view, payload, api) {\n    var zoomActive = view._isZoomActive;\n\n    if (payload && payload.type === 'takeGlobalCursor') {\n        zoomActive = payload.key === 'dataZoomSelect'\n            ? payload.dataZoomSelectActive : false;\n    }\n\n    view._isZoomActive = zoomActive;\n\n    featureModel.setIconStatus('zoom', zoomActive ? 'emphasis' : 'normal');\n\n    var brushTargetManager = new BrushTargetManager(\n        retrieveAxisSetting(featureModel.option), ecModel, {include: ['grid']}\n    );\n\n    view._brushController\n        .setPanels(brushTargetManager.makePanelOpts(api, function (targetInfo) {\n            return (targetInfo.xAxisDeclared && !targetInfo.yAxisDeclared)\n                ? 'lineX'\n                : (!targetInfo.xAxisDeclared && targetInfo.yAxisDeclared)\n                ? 'lineY'\n                : 'rect';\n        }))\n        .enableBrush(\n            zoomActive\n            ? {\n                brushType: 'auto',\n                brushStyle: {\n                    // FIXME user customized?\n                    lineWidth: 0,\n                    fill: 'rgba(0,0,0,0.2)'\n                }\n            }\n            : false\n        );\n}\n\n\nregister$1('dataZoom', DataZoom);\n\n\n// Create special dataZoom option for select\n// FIXME consider the case of merge option, where axes options are not exists.\nregisterPreprocessor(function (option) {\n    if (!option) {\n        return;\n    }\n\n    var dataZoomOpts = option.dataZoom || (option.dataZoom = []);\n    if (!isArray(dataZoomOpts)) {\n        option.dataZoom = dataZoomOpts = [dataZoomOpts];\n    }\n\n    var toolboxOpt = option.toolbox;\n    if (toolboxOpt) {\n        // Assume there is only one toolbox\n        if (isArray(toolboxOpt)) {\n            toolboxOpt = toolboxOpt[0];\n        }\n\n        if (toolboxOpt && toolboxOpt.feature) {\n            var dataZoomOpt = toolboxOpt.feature.dataZoom;\n            // FIXME: If add dataZoom when setOption in merge mode,\n            // no axis info to be added. See `test/dataZoom-extreme.html`\n            addForAxis('xAxis', dataZoomOpt);\n            addForAxis('yAxis', dataZoomOpt);\n        }\n    }\n\n    function addForAxis(axisName, dataZoomOpt) {\n        if (!dataZoomOpt) {\n            return;\n        }\n\n        // Try not to modify model, because it is not merged yet.\n        var axisIndicesName = axisName + 'Index';\n        var givenAxisIndices = dataZoomOpt[axisIndicesName];\n        if (givenAxisIndices != null\n            && givenAxisIndices !== 'all'\n            && !isArray(givenAxisIndices)\n        ) {\n            givenAxisIndices = (givenAxisIndices === false || givenAxisIndices === 'none') ? [] : [givenAxisIndices];\n        }\n\n        forEachComponent(axisName, function (axisOpt, axisIndex) {\n            if (givenAxisIndices != null\n                && givenAxisIndices !== 'all'\n                && indexOf(givenAxisIndices, axisIndex) === -1\n            ) {\n                return;\n            }\n            var newOpt = {\n                type: 'select',\n                $fromToolbox: true,\n                // Id for merge mapping.\n                id: DATA_ZOOM_ID_BASE + axisName + axisIndex\n            };\n            // FIXME\n            // Only support one axis now.\n            newOpt[axisIndicesName] = axisIndex;\n            dataZoomOpts.push(newOpt);\n        });\n    }\n\n    function forEachComponent(mainType, cb) {\n        var opts = option[mainType];\n        if (!isArray(opts)) {\n            opts = opts ? [opts] : [];\n        }\n        each$28(opts, cb);\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar restoreLang = lang.toolbox.restore;\n\nfunction Restore(model) {\n    this.model = model;\n}\n\nRestore.defaultOption = {\n    show: true,\n    /* eslint-disable */\n    icon: 'M3.8,33.4 M47,18.9h9.8V8.7 M56.3,20.1 C52.1,9,40.5,0.6,26.8,2.1C12.6,3.7,1.6,16.2,2.1,30.6 M13,41.1H3.1v10.2 M3.7,39.9c4.2,11.1,15.8,19.5,29.5,18 c14.2-1.6,25.2-14.1,24.7-28.5',\n    /* eslint-enable */\n    title: restoreLang.title\n};\n\nvar proto$7 = Restore.prototype;\n\nproto$7.onclick = function (ecModel, api, type) {\n    clear$1(ecModel);\n\n    api.dispatchAction({\n        type: 'restore',\n        from: this.uid\n    });\n};\n\nregister$1('restore', Restore);\n\nregisterAction(\n    {type: 'restore', event: 'restore', update: 'prepareAndUpdate'},\n    function (payload, ecModel) {\n        ecModel.resetOption('recreate');\n    }\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar urn = 'urn:schemas-microsoft-com:vml';\nvar win = typeof window === 'undefined' ? null : window;\n\nvar vmlInited = false;\n\nvar doc = win && win.document;\n\nfunction createNode(tagName) {\n    return doCreateNode(tagName);\n}\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar doCreateNode;\n\nif (doc && !env$1.canvasSupported) {\n    try {\n        !doc.namespaces.zrvml && doc.namespaces.add('zrvml', urn);\n        doCreateNode = function (tagName) {\n            return doc.createElement('<zrvml:' + tagName + ' class=\"zrvml\">');\n        };\n    }\n    catch (e) {\n        doCreateNode = function (tagName) {\n            return doc.createElement('<' + tagName + ' xmlns=\"' + urn + '\" class=\"zrvml\">');\n        };\n    }\n}\n\n// From raphael\nfunction initVML() {\n    if (vmlInited || !doc) {\n        return;\n    }\n    vmlInited = true;\n\n    var styleSheets = doc.styleSheets;\n    if (styleSheets.length < 31) {\n        doc.createStyleSheet().addRule('.zrvml', 'behavior:url(#default#VML)');\n    }\n    else {\n        // http://msdn.microsoft.com/en-us/library/ms531194%28VS.85%29.aspx\n        styleSheets[0].addRule('.zrvml', 'behavior:url(#default#VML)');\n    }\n}\n\n// http://www.w3.org/TR/NOTE-VML\n// TODO Use proxy like svg instead of overwrite brush methods\n\nvar CMD$3 = PathProxy.CMD;\nvar round$4 = Math.round;\nvar sqrt = Math.sqrt;\nvar abs$1 = Math.abs;\nvar cos = Math.cos;\nvar sin = Math.sin;\nvar mathMax$8 = Math.max;\n\nif (!env$1.canvasSupported) {\n\n    var comma = ',';\n    var imageTransformPrefix = 'progid:DXImageTransform.Microsoft';\n\n    var Z = 21600;\n    var Z2 = Z / 2;\n\n    var ZLEVEL_BASE = 100000;\n    var Z_BASE$1 = 1000;\n\n    var initRootElStyle = function (el) {\n        el.style.cssText = 'position:absolute;left:0;top:0;width:1px;height:1px;';\n        el.coordsize = Z + ',' + Z;\n        el.coordorigin = '0,0';\n    };\n\n    var encodeHtmlAttribute = function (s) {\n        return String(s).replace(/&/g, '&amp;').replace(/\"/g, '&quot;');\n    };\n\n    var rgb2Str = function (r, g, b) {\n        return 'rgb(' + [r, g, b].join(',') + ')';\n    };\n\n    var append = function (parent, child) {\n        if (child && parent && child.parentNode !== parent) {\n            parent.appendChild(child);\n        }\n    };\n\n    var remove = function (parent, child) {\n        if (child && parent && child.parentNode === parent) {\n            parent.removeChild(child);\n        }\n    };\n\n    var getZIndex = function (zlevel, z, z2) {\n        // z 的取值范围为 [0, 1000]\n        return (parseFloat(zlevel) || 0) * ZLEVEL_BASE + (parseFloat(z) || 0) * Z_BASE$1 + z2;\n    };\n\n    var parsePercent$3 = function (value, maxValue) {\n        if (typeof value === 'string') {\n            if (value.lastIndexOf('%') >= 0) {\n                return parseFloat(value) / 100 * maxValue;\n            }\n            return parseFloat(value);\n        }\n        return value;\n    };\n\n    /***************************************************\n     * PATH\n     **************************************************/\n\n    var setColorAndOpacity = function (el, color, opacity) {\n        var colorArr = parse(color);\n        opacity = +opacity;\n        if (isNaN(opacity)) {\n            opacity = 1;\n        }\n        if (colorArr) {\n            el.color = rgb2Str(colorArr[0], colorArr[1], colorArr[2]);\n            el.opacity = opacity * colorArr[3];\n        }\n    };\n\n    var getColorAndAlpha = function (color) {\n        var colorArr = parse(color);\n        return [\n            rgb2Str(colorArr[0], colorArr[1], colorArr[2]),\n            colorArr[3]\n        ];\n    };\n\n    var updateFillNode = function (el, style, zrEl) {\n        // TODO pattern\n        var fill = style.fill;\n        if (fill != null) {\n            // Modified from excanvas\n            if (fill instanceof Gradient) {\n                var gradientType;\n                var angle = 0;\n                var focus = [0, 0];\n                // additional offset\n                var shift = 0;\n                // scale factor for offset\n                var expansion = 1;\n                var rect = zrEl.getBoundingRect();\n                var rectWidth = rect.width;\n                var rectHeight = rect.height;\n                if (fill.type === 'linear') {\n                    gradientType = 'gradient';\n                    var transform = zrEl.transform;\n                    var p0 = [fill.x * rectWidth, fill.y * rectHeight];\n                    var p1 = [fill.x2 * rectWidth, fill.y2 * rectHeight];\n                    if (transform) {\n                        applyTransform(p0, p0, transform);\n                        applyTransform(p1, p1, transform);\n                    }\n                    var dx = p1[0] - p0[0];\n                    var dy = p1[1] - p0[1];\n                    angle = Math.atan2(dx, dy) * 180 / Math.PI;\n                    // The angle should be a non-negative number.\n                    if (angle < 0) {\n                        angle += 360;\n                    }\n\n                    // Very small angles produce an unexpected result because they are\n                    // converted to a scientific notation string.\n                    if (angle < 1e-6) {\n                        angle = 0;\n                    }\n                }\n                else {\n                    gradientType = 'gradientradial';\n                    var p0 = [fill.x * rectWidth, fill.y * rectHeight];\n                    var transform = zrEl.transform;\n                    var scale$$1 = zrEl.scale;\n                    var width = rectWidth;\n                    var height = rectHeight;\n                    focus = [\n                        // Percent in bounding rect\n                        (p0[0] - rect.x) / width,\n                        (p0[1] - rect.y) / height\n                    ];\n                    if (transform) {\n                        applyTransform(p0, p0, transform);\n                    }\n\n                    width /= scale$$1[0] * Z;\n                    height /= scale$$1[1] * Z;\n                    var dimension = mathMax$8(width, height);\n                    shift = 2 * 0 / dimension;\n                    expansion = 2 * fill.r / dimension - shift;\n                }\n\n                // We need to sort the color stops in ascending order by offset,\n                // otherwise IE won't interpret it correctly.\n                var stops = fill.colorStops.slice();\n                stops.sort(function (cs1, cs2) {\n                    return cs1.offset - cs2.offset;\n                });\n\n                var length$$1 = stops.length;\n                // Color and alpha list of first and last stop\n                var colorAndAlphaList = [];\n                var colors = [];\n                for (var i = 0; i < length$$1; i++) {\n                    var stop = stops[i];\n                    var colorAndAlpha = getColorAndAlpha(stop.color);\n                    colors.push(stop.offset * expansion + shift + ' ' + colorAndAlpha[0]);\n                    if (i === 0 || i === length$$1 - 1) {\n                        colorAndAlphaList.push(colorAndAlpha);\n                    }\n                }\n\n                if (length$$1 >= 2) {\n                    var color1 = colorAndAlphaList[0][0];\n                    var color2 = colorAndAlphaList[1][0];\n                    var opacity1 = colorAndAlphaList[0][1] * style.opacity;\n                    var opacity2 = colorAndAlphaList[1][1] * style.opacity;\n\n                    el.type = gradientType;\n                    el.method = 'none';\n                    el.focus = '100%';\n                    el.angle = angle;\n                    el.color = color1;\n                    el.color2 = color2;\n                    el.colors = colors.join(',');\n                    // When colors attribute is used, the meanings of opacity and o:opacity2\n                    // are reversed.\n                    el.opacity = opacity2;\n                    // FIXME g_o_:opacity ?\n                    el.opacity2 = opacity1;\n                }\n                if (gradientType === 'radial') {\n                    el.focusposition = focus.join(',');\n                }\n            }\n            else {\n                // FIXME Change from Gradient fill to color fill\n                setColorAndOpacity(el, fill, style.opacity);\n            }\n        }\n    };\n\n    var updateStrokeNode = function (el, style) {\n        // if (style.lineJoin != null) {\n        //     el.joinstyle = style.lineJoin;\n        // }\n        // if (style.miterLimit != null) {\n        //     el.miterlimit = style.miterLimit * Z;\n        // }\n        // if (style.lineCap != null) {\n        //     el.endcap = style.lineCap;\n        // }\n        if (style.lineDash != null) {\n            el.dashstyle = style.lineDash.join(' ');\n        }\n        if (style.stroke != null && !(style.stroke instanceof Gradient)) {\n            setColorAndOpacity(el, style.stroke, style.opacity);\n        }\n    };\n\n    var updateFillAndStroke = function (vmlEl, type, style, zrEl) {\n        var isFill = type === 'fill';\n        var el = vmlEl.getElementsByTagName(type)[0];\n        // Stroke must have lineWidth\n        if (style[type] != null && style[type] !== 'none' && (isFill || (!isFill && style.lineWidth))) {\n            vmlEl[isFill ? 'filled' : 'stroked'] = 'true';\n            // FIXME Remove before updating, or set `colors` will throw error\n            if (style[type] instanceof Gradient) {\n                remove(vmlEl, el);\n            }\n            if (!el) {\n                el = createNode(type);\n            }\n\n            isFill ? updateFillNode(el, style, zrEl) : updateStrokeNode(el, style);\n            append(vmlEl, el);\n        }\n        else {\n            vmlEl[isFill ? 'filled' : 'stroked'] = 'false';\n            remove(vmlEl, el);\n        }\n    };\n\n    var points$3 = [[], [], []];\n    var pathDataToString = function (path, m) {\n        var M = CMD$3.M;\n        var C = CMD$3.C;\n        var L = CMD$3.L;\n        var A = CMD$3.A;\n        var Q = CMD$3.Q;\n\n        var str = [];\n        var nPoint;\n        var cmdStr;\n        var cmd;\n        var i;\n        var xi;\n        var yi;\n        var data = path.data;\n        var dataLength = path.len();\n        for (i = 0; i < dataLength;) {\n            cmd = data[i++];\n            cmdStr = '';\n            nPoint = 0;\n            switch (cmd) {\n                case M:\n                    cmdStr = ' m ';\n                    nPoint = 1;\n                    xi = data[i++];\n                    yi = data[i++];\n                    points$3[0][0] = xi;\n                    points$3[0][1] = yi;\n                    break;\n                case L:\n                    cmdStr = ' l ';\n                    nPoint = 1;\n                    xi = data[i++];\n                    yi = data[i++];\n                    points$3[0][0] = xi;\n                    points$3[0][1] = yi;\n                    break;\n                case Q:\n                case C:\n                    cmdStr = ' c ';\n                    nPoint = 3;\n                    var x1 = data[i++];\n                    var y1 = data[i++];\n                    var x2 = data[i++];\n                    var y2 = data[i++];\n                    var x3;\n                    var y3;\n                    if (cmd === Q) {\n                        // Convert quadratic to cubic using degree elevation\n                        x3 = x2;\n                        y3 = y2;\n                        x2 = (x2 + 2 * x1) / 3;\n                        y2 = (y2 + 2 * y1) / 3;\n                        x1 = (xi + 2 * x1) / 3;\n                        y1 = (yi + 2 * y1) / 3;\n                    }\n                    else {\n                        x3 = data[i++];\n                        y3 = data[i++];\n                    }\n                    points$3[0][0] = x1;\n                    points$3[0][1] = y1;\n                    points$3[1][0] = x2;\n                    points$3[1][1] = y2;\n                    points$3[2][0] = x3;\n                    points$3[2][1] = y3;\n\n                    xi = x3;\n                    yi = y3;\n                    break;\n                case A:\n                    var x = 0;\n                    var y = 0;\n                    var sx = 1;\n                    var sy = 1;\n                    var angle = 0;\n                    if (m) {\n                        // Extract SRT from matrix\n                        x = m[4];\n                        y = m[5];\n                        sx = sqrt(m[0] * m[0] + m[1] * m[1]);\n                        sy = sqrt(m[2] * m[2] + m[3] * m[3]);\n                        angle = Math.atan2(-m[1] / sy, m[0] / sx);\n                    }\n\n                    var cx = data[i++];\n                    var cy = data[i++];\n                    var rx = data[i++];\n                    var ry = data[i++];\n                    var startAngle = data[i++] + angle;\n                    var endAngle = data[i++] + startAngle + angle;\n                    // FIXME\n                    // var psi = data[i++];\n                    i++;\n                    var clockwise = data[i++];\n\n                    var x0 = cx + cos(startAngle) * rx;\n                    var y0 = cy + sin(startAngle) * ry;\n\n                    var x1 = cx + cos(endAngle) * rx;\n                    var y1 = cy + sin(endAngle) * ry;\n\n                    var type = clockwise ? ' wa ' : ' at ';\n                    if (Math.abs(x0 - x1) < 1e-4) {\n                        // IE won't render arches drawn counter clockwise if x0 == x1.\n                        if (Math.abs(endAngle - startAngle) > 1e-2) {\n                            // Offset x0 by 1/80 of a pixel. Use something\n                            // that can be represented in binary\n                            if (clockwise) {\n                                x0 += 270 / Z;\n                            }\n                        }\n                        else {\n                            // Avoid case draw full circle\n                            if (Math.abs(y0 - cy) < 1e-4) {\n                                if ((clockwise && x0 < cx) || (!clockwise && x0 > cx)) {\n                                    y1 -= 270 / Z;\n                                }\n                                else {\n                                    y1 += 270 / Z;\n                                }\n                            }\n                            else if ((clockwise && y0 < cy) || (!clockwise && y0 > cy)) {\n                                x1 += 270 / Z;\n                            }\n                            else {\n                                x1 -= 270 / Z;\n                            }\n                        }\n                    }\n                    str.push(\n                        type,\n                        round$4(((cx - rx) * sx + x) * Z - Z2), comma,\n                        round$4(((cy - ry) * sy + y) * Z - Z2), comma,\n                        round$4(((cx + rx) * sx + x) * Z - Z2), comma,\n                        round$4(((cy + ry) * sy + y) * Z - Z2), comma,\n                        round$4((x0 * sx + x) * Z - Z2), comma,\n                        round$4((y0 * sy + y) * Z - Z2), comma,\n                        round$4((x1 * sx + x) * Z - Z2), comma,\n                        round$4((y1 * sy + y) * Z - Z2)\n                    );\n\n                    xi = x1;\n                    yi = y1;\n                    break;\n                case CMD$3.R:\n                    var p0 = points$3[0];\n                    var p1 = points$3[1];\n                    // x0, y0\n                    p0[0] = data[i++];\n                    p0[1] = data[i++];\n                    // x1, y1\n                    p1[0] = p0[0] + data[i++];\n                    p1[1] = p0[1] + data[i++];\n\n                    if (m) {\n                        applyTransform(p0, p0, m);\n                        applyTransform(p1, p1, m);\n                    }\n\n                    p0[0] = round$4(p0[0] * Z - Z2);\n                    p1[0] = round$4(p1[0] * Z - Z2);\n                    p0[1] = round$4(p0[1] * Z - Z2);\n                    p1[1] = round$4(p1[1] * Z - Z2);\n                    str.push(\n                        // x0, y0\n                        ' m ', p0[0], comma, p0[1],\n                        // x1, y0\n                        ' l ', p1[0], comma, p0[1],\n                        // x1, y1\n                        ' l ', p1[0], comma, p1[1],\n                        // x0, y1\n                        ' l ', p0[0], comma, p1[1]\n                    );\n                    break;\n                case CMD$3.Z:\n                    // FIXME Update xi, yi\n                    str.push(' x ');\n            }\n\n            if (nPoint > 0) {\n                str.push(cmdStr);\n                for (var k = 0; k < nPoint; k++) {\n                    var p = points$3[k];\n\n                    m && applyTransform(p, p, m);\n                    // 不 round 会非常慢\n                    str.push(\n                        round$4(p[0] * Z - Z2), comma, round$4(p[1] * Z - Z2),\n                        k < nPoint - 1 ? comma : ''\n                    );\n                }\n            }\n        }\n\n        return str.join('');\n    };\n\n    // Rewrite the original path method\n    Path.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n\n        var vmlEl = this._vmlEl;\n        if (!vmlEl) {\n            vmlEl = createNode('shape');\n            initRootElStyle(vmlEl);\n\n            this._vmlEl = vmlEl;\n        }\n\n        updateFillAndStroke(vmlEl, 'fill', style, this);\n        updateFillAndStroke(vmlEl, 'stroke', style, this);\n\n        var m = this.transform;\n        var needTransform = m != null;\n        var strokeEl = vmlEl.getElementsByTagName('stroke')[0];\n        if (strokeEl) {\n            var lineWidth = style.lineWidth;\n            // Get the line scale.\n            // Determinant of this.m_ means how much the area is enlarged by the\n            // transformation. So its square root can be used as a scale factor\n            // for width.\n            if (needTransform && !style.strokeNoScale) {\n                var det = m[0] * m[3] - m[1] * m[2];\n                lineWidth *= sqrt(abs$1(det));\n            }\n            strokeEl.weight = lineWidth + 'px';\n        }\n\n        var path = this.path || (this.path = new PathProxy());\n        if (this.__dirtyPath) {\n            path.beginPath();\n            path.subPixelOptimize = false;\n            this.buildPath(path, this.shape);\n            path.toStatic();\n            this.__dirtyPath = false;\n        }\n\n        vmlEl.path = pathDataToString(path, this.transform);\n\n        vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Append to root\n        append(vmlRoot, vmlEl);\n\n        // Text\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, this.getBoundingRect());\n        }\n        else {\n            this.removeRectText(vmlRoot);\n        }\n    };\n\n    Path.prototype.onRemove = function (vmlRoot) {\n        remove(vmlRoot, this._vmlEl);\n        this.removeRectText(vmlRoot);\n    };\n\n    Path.prototype.onAdd = function (vmlRoot) {\n        append(vmlRoot, this._vmlEl);\n        this.appendRectText(vmlRoot);\n    };\n\n    /***************************************************\n     * IMAGE\n     **************************************************/\n    var isImage = function (img) {\n        // FIXME img instanceof Image 如果 img 是一个字符串的时候，IE8 下会报错\n        return (typeof img === 'object') && img.tagName && img.tagName.toUpperCase() === 'IMG';\n        // return img instanceof Image;\n    };\n\n    // Rewrite the original path method\n    ZImage.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n        var image = style.image;\n\n        // Image original width, height\n        var ow;\n        var oh;\n\n        if (isImage(image)) {\n            var src = image.src;\n            if (src === this._imageSrc) {\n                ow = this._imageWidth;\n                oh = this._imageHeight;\n            }\n            else {\n                var imageRuntimeStyle = image.runtimeStyle;\n                var oldRuntimeWidth = imageRuntimeStyle.width;\n                var oldRuntimeHeight = imageRuntimeStyle.height;\n                imageRuntimeStyle.width = 'auto';\n                imageRuntimeStyle.height = 'auto';\n\n                // get the original size\n                ow = image.width;\n                oh = image.height;\n\n                // and remove overides\n                imageRuntimeStyle.width = oldRuntimeWidth;\n                imageRuntimeStyle.height = oldRuntimeHeight;\n\n                // Caching image original width, height and src\n                this._imageSrc = src;\n                this._imageWidth = ow;\n                this._imageHeight = oh;\n            }\n            image = src;\n        }\n        else {\n            if (image === this._imageSrc) {\n                ow = this._imageWidth;\n                oh = this._imageHeight;\n            }\n        }\n        if (!image) {\n            return;\n        }\n\n        var x = style.x || 0;\n        var y = style.y || 0;\n\n        var dw = style.width;\n        var dh = style.height;\n\n        var sw = style.sWidth;\n        var sh = style.sHeight;\n        var sx = style.sx || 0;\n        var sy = style.sy || 0;\n\n        var hasCrop = sw && sh;\n\n        var vmlEl = this._vmlEl;\n        if (!vmlEl) {\n            // FIXME 使用 group 在 left, top 都不是 0 的时候就无法显示了。\n            // vmlEl = vmlCore.createNode('group');\n            vmlEl = doc.createElement('div');\n            initRootElStyle(vmlEl);\n\n            this._vmlEl = vmlEl;\n        }\n\n        var vmlElStyle = vmlEl.style;\n        var hasRotation = false;\n        var m;\n        var scaleX = 1;\n        var scaleY = 1;\n        if (this.transform) {\n            m = this.transform;\n            scaleX = sqrt(m[0] * m[0] + m[1] * m[1]);\n            scaleY = sqrt(m[2] * m[2] + m[3] * m[3]);\n\n            hasRotation = m[1] || m[2];\n        }\n        if (hasRotation) {\n            // If filters are necessary (rotation exists), create them\n            // filters are bog-slow, so only create them if abbsolutely necessary\n            // The following check doesn't account for skews (which don't exist\n            // in the canvas spec (yet) anyway.\n            // From excanvas\n            var p0 = [x, y];\n            var p1 = [x + dw, y];\n            var p2 = [x, y + dh];\n            var p3 = [x + dw, y + dh];\n            applyTransform(p0, p0, m);\n            applyTransform(p1, p1, m);\n            applyTransform(p2, p2, m);\n            applyTransform(p3, p3, m);\n\n            var maxX = mathMax$8(p0[0], p1[0], p2[0], p3[0]);\n            var maxY = mathMax$8(p0[1], p1[1], p2[1], p3[1]);\n\n            var transformFilter = [];\n            transformFilter.push('M11=', m[0] / scaleX, comma,\n                        'M12=', m[2] / scaleY, comma,\n                        'M21=', m[1] / scaleX, comma,\n                        'M22=', m[3] / scaleY, comma,\n                        'Dx=', round$4(x * scaleX + m[4]), comma,\n                        'Dy=', round$4(y * scaleY + m[5]));\n\n            vmlElStyle.padding = '0 ' + round$4(maxX) + 'px ' + round$4(maxY) + 'px 0';\n            // FIXME DXImageTransform 在 IE11 的兼容模式下不起作用\n            vmlElStyle.filter = imageTransformPrefix + '.Matrix('\n                + transformFilter.join('') + ', SizingMethod=clip)';\n\n        }\n        else {\n            if (m) {\n                x = x * scaleX + m[4];\n                y = y * scaleY + m[5];\n            }\n            vmlElStyle.filter = '';\n            vmlElStyle.left = round$4(x) + 'px';\n            vmlElStyle.top = round$4(y) + 'px';\n        }\n\n        var imageEl = this._imageEl;\n        var cropEl = this._cropEl;\n\n        if (!imageEl) {\n            imageEl = doc.createElement('div');\n            this._imageEl = imageEl;\n        }\n        var imageELStyle = imageEl.style;\n        if (hasCrop) {\n            // Needs know image original width and height\n            if (!(ow && oh)) {\n                var tmpImage = new Image();\n                var self = this;\n                tmpImage.onload = function () {\n                    tmpImage.onload = null;\n                    ow = tmpImage.width;\n                    oh = tmpImage.height;\n                    // Adjust image width and height to fit the ratio destinationSize / sourceSize\n                    imageELStyle.width = round$4(scaleX * ow * dw / sw) + 'px';\n                    imageELStyle.height = round$4(scaleY * oh * dh / sh) + 'px';\n\n                    // Caching image original width, height and src\n                    self._imageWidth = ow;\n                    self._imageHeight = oh;\n                    self._imageSrc = image;\n                };\n                tmpImage.src = image;\n            }\n            else {\n                imageELStyle.width = round$4(scaleX * ow * dw / sw) + 'px';\n                imageELStyle.height = round$4(scaleY * oh * dh / sh) + 'px';\n            }\n\n            if (!cropEl) {\n                cropEl = doc.createElement('div');\n                cropEl.style.overflow = 'hidden';\n                this._cropEl = cropEl;\n            }\n            var cropElStyle = cropEl.style;\n            cropElStyle.width = round$4((dw + sx * dw / sw) * scaleX);\n            cropElStyle.height = round$4((dh + sy * dh / sh) * scaleY);\n            cropElStyle.filter = imageTransformPrefix + '.Matrix(Dx='\n                    + (-sx * dw / sw * scaleX) + ',Dy=' + (-sy * dh / sh * scaleY) + ')';\n\n            if (!cropEl.parentNode) {\n                vmlEl.appendChild(cropEl);\n            }\n            if (imageEl.parentNode !== cropEl) {\n                cropEl.appendChild(imageEl);\n            }\n        }\n        else {\n            imageELStyle.width = round$4(scaleX * dw) + 'px';\n            imageELStyle.height = round$4(scaleY * dh) + 'px';\n\n            vmlEl.appendChild(imageEl);\n\n            if (cropEl && cropEl.parentNode) {\n                vmlEl.removeChild(cropEl);\n                this._cropEl = null;\n            }\n        }\n\n        var filterStr = '';\n        var alpha = style.opacity;\n        if (alpha < 1) {\n            filterStr += '.Alpha(opacity=' + round$4(alpha * 100) + ') ';\n        }\n        filterStr += imageTransformPrefix + '.AlphaImageLoader(src=' + image + ', SizingMethod=scale)';\n\n        imageELStyle.filter = filterStr;\n\n        vmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Append to root\n        append(vmlRoot, vmlEl);\n\n        // Text\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, this.getBoundingRect());\n        }\n    };\n\n    ZImage.prototype.onRemove = function (vmlRoot) {\n        remove(vmlRoot, this._vmlEl);\n\n        this._vmlEl = null;\n        this._cropEl = null;\n        this._imageEl = null;\n\n        this.removeRectText(vmlRoot);\n    };\n\n    ZImage.prototype.onAdd = function (vmlRoot) {\n        append(vmlRoot, this._vmlEl);\n        this.appendRectText(vmlRoot);\n    };\n\n\n    /***************************************************\n     * TEXT\n     **************************************************/\n\n    var DEFAULT_STYLE_NORMAL = 'normal';\n\n    var fontStyleCache = {};\n    var fontStyleCacheCount = 0;\n    var MAX_FONT_CACHE_SIZE = 100;\n    var fontEl = document.createElement('div');\n\n    var getFontStyle = function (fontString) {\n        var fontStyle = fontStyleCache[fontString];\n        if (!fontStyle) {\n            // Clear cache\n            if (fontStyleCacheCount > MAX_FONT_CACHE_SIZE) {\n                fontStyleCacheCount = 0;\n                fontStyleCache = {};\n            }\n\n            var style = fontEl.style;\n            var fontFamily;\n            try {\n                style.font = fontString;\n                fontFamily = style.fontFamily.split(',')[0];\n            }\n            catch (e) {\n            }\n\n            fontStyle = {\n                style: style.fontStyle || DEFAULT_STYLE_NORMAL,\n                variant: style.fontVariant || DEFAULT_STYLE_NORMAL,\n                weight: style.fontWeight || DEFAULT_STYLE_NORMAL,\n                size: parseFloat(style.fontSize || 12) | 0,\n                family: fontFamily || 'Microsoft YaHei'\n            };\n\n            fontStyleCache[fontString] = fontStyle;\n            fontStyleCacheCount++;\n        }\n        return fontStyle;\n    };\n\n    var textMeasureEl;\n    // Overwrite measure text method\n    $override$1('measureText', function (text, textFont) {\n        var doc$$1 = doc;\n        if (!textMeasureEl) {\n            textMeasureEl = doc$$1.createElement('div');\n            textMeasureEl.style.cssText = 'position:absolute;top:-20000px;left:0;'\n                + 'padding:0;margin:0;border:none;white-space:pre;';\n            doc.body.appendChild(textMeasureEl);\n        }\n\n        try {\n            textMeasureEl.style.font = textFont;\n        }\n        catch (ex) {\n            // Ignore failures to set to invalid font.\n        }\n        textMeasureEl.innerHTML = '';\n        // Don't use innerHTML or innerText because they allow markup/whitespace.\n        textMeasureEl.appendChild(doc$$1.createTextNode(text));\n        return {\n            width: textMeasureEl.offsetWidth\n        };\n    });\n\n    var tmpRect$2 = new BoundingRect();\n\n    var drawRectText = function (vmlRoot, rect, textRect, fromTextEl) {\n\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        var text = style.text;\n        // Convert to string\n        text != null && (text += '');\n        if (!text) {\n            return;\n        }\n\n        // Convert rich text to plain text. Rich text is not supported in\n        // IE8-, but tags in rich text template will be removed.\n        if (style.rich) {\n            var contentBlock = parseRichText(text, style);\n            text = [];\n            for (var i = 0; i < contentBlock.lines.length; i++) {\n                var tokens = contentBlock.lines[i].tokens;\n                var textLine = [];\n                for (var j = 0; j < tokens.length; j++) {\n                    textLine.push(tokens[j].text);\n                }\n                text.push(textLine.join(''));\n            }\n            text = text.join('\\n');\n        }\n\n        var x;\n        var y;\n        var align = style.textAlign;\n        var verticalAlign = style.textVerticalAlign;\n\n        var fontStyle = getFontStyle(style.font);\n        // FIXME encodeHtmlAttribute ?\n        var font = fontStyle.style + ' ' + fontStyle.variant + ' ' + fontStyle.weight + ' '\n            + fontStyle.size + 'px \"' + fontStyle.family + '\"';\n\n        textRect = textRect || getBoundingRect(\n            text, font, align, verticalAlign, style.textPadding, style.textLineHeight\n        );\n\n        // Transform rect to view space\n        var m = this.transform;\n        // Ignore transform for text in other element\n        if (m && !fromTextEl) {\n            tmpRect$2.copy(rect);\n            tmpRect$2.applyTransform(m);\n            rect = tmpRect$2;\n        }\n\n        if (!fromTextEl) {\n            var textPosition = style.textPosition;\n            var distance$$1 = style.textDistance;\n            // Text position represented by coord\n            if (textPosition instanceof Array) {\n                x = rect.x + parsePercent$3(textPosition[0], rect.width);\n                y = rect.y + parsePercent$3(textPosition[1], rect.height);\n\n                align = align || 'left';\n            }\n            else {\n                var res = adjustTextPositionOnRect(\n                    textPosition, rect, distance$$1\n                );\n                x = res.x;\n                y = res.y;\n\n                // Default align and baseline when has textPosition\n                align = align || res.textAlign;\n                verticalAlign = verticalAlign || res.textVerticalAlign;\n            }\n        }\n        else {\n            x = rect.x;\n            y = rect.y;\n        }\n\n        x = adjustTextX(x, textRect.width, align);\n        y = adjustTextY(y, textRect.height, verticalAlign);\n\n        // Force baseline 'middle'\n        y += textRect.height / 2;\n\n        // var fontSize = fontStyle.size;\n        // 1.75 is an arbitrary number, as there is no info about the text baseline\n        // switch (baseline) {\n            // case 'hanging':\n            // case 'top':\n            //     y += fontSize / 1.75;\n            //     break;\n        //     case 'middle':\n        //         break;\n        //     default:\n        //     // case null:\n        //     // case 'alphabetic':\n        //     // case 'ideographic':\n        //     // case 'bottom':\n        //         y -= fontSize / 2.25;\n        //         break;\n        // }\n\n        // switch (align) {\n        //     case 'left':\n        //         break;\n        //     case 'center':\n        //         x -= textRect.width / 2;\n        //         break;\n        //     case 'right':\n        //         x -= textRect.width;\n        //         break;\n            // case 'end':\n                // align = elementStyle.direction == 'ltr' ? 'right' : 'left';\n                // break;\n            // case 'start':\n                // align = elementStyle.direction == 'rtl' ? 'right' : 'left';\n                // break;\n            // default:\n            //     align = 'left';\n        // }\n\n        var createNode$$1 = createNode;\n\n        var textVmlEl = this._textVmlEl;\n        var pathEl;\n        var textPathEl;\n        var skewEl;\n        if (!textVmlEl) {\n            textVmlEl = createNode$$1('line');\n            pathEl = createNode$$1('path');\n            textPathEl = createNode$$1('textpath');\n            skewEl = createNode$$1('skew');\n\n            // FIXME Why here is not cammel case\n            // Align 'center' seems wrong\n            textPathEl.style['v-text-align'] = 'left';\n\n            initRootElStyle(textVmlEl);\n\n            pathEl.textpathok = true;\n            textPathEl.on = true;\n\n            textVmlEl.from = '0 0';\n            textVmlEl.to = '1000 0.05';\n\n            append(textVmlEl, skewEl);\n            append(textVmlEl, pathEl);\n            append(textVmlEl, textPathEl);\n\n            this._textVmlEl = textVmlEl;\n        }\n        else {\n            // 这里是在前面 appendChild 保证顺序的前提下\n            skewEl = textVmlEl.firstChild;\n            pathEl = skewEl.nextSibling;\n            textPathEl = pathEl.nextSibling;\n        }\n\n        var coords = [x, y];\n        var textVmlElStyle = textVmlEl.style;\n        // Ignore transform for text in other element\n        if (m && fromTextEl) {\n            applyTransform(coords, coords, m);\n\n            skewEl.on = true;\n\n            skewEl.matrix = m[0].toFixed(3) + comma + m[2].toFixed(3) + comma\n                            + m[1].toFixed(3) + comma + m[3].toFixed(3) + ',0,0';\n\n            // Text position\n            skewEl.offset = (round$4(coords[0]) || 0) + ',' + (round$4(coords[1]) || 0);\n            // Left top point as origin\n            skewEl.origin = '0 0';\n\n            textVmlElStyle.left = '0px';\n            textVmlElStyle.top = '0px';\n        }\n        else {\n            skewEl.on = false;\n            textVmlElStyle.left = round$4(x) + 'px';\n            textVmlElStyle.top = round$4(y) + 'px';\n        }\n\n        textPathEl.string = encodeHtmlAttribute(text);\n        // TODO\n        try {\n            textPathEl.style.font = font;\n        }\n        // Error font format\n        catch (e) {}\n\n        updateFillAndStroke(textVmlEl, 'fill', {\n            fill: style.textFill,\n            opacity: style.opacity\n        }, this);\n        updateFillAndStroke(textVmlEl, 'stroke', {\n            stroke: style.textStroke,\n            opacity: style.opacity,\n            lineDash: style.lineDash\n        }, this);\n\n        textVmlEl.style.zIndex = getZIndex(this.zlevel, this.z, this.z2);\n\n        // Attached to root\n        append(vmlRoot, textVmlEl);\n    };\n\n    var removeRectText = function (vmlRoot) {\n        remove(vmlRoot, this._textVmlEl);\n        this._textVmlEl = null;\n    };\n\n    var appendRectText = function (vmlRoot) {\n        append(vmlRoot, this._textVmlEl);\n    };\n\n    var list = [RectText, Displayable, ZImage, Path, Text];\n\n    // In case Displayable has been mixed in RectText\n    for (var i$3 = 0; i$3 < list.length; i$3++) {\n        var proto$8 = list[i$3].prototype;\n        proto$8.drawRectText = drawRectText;\n        proto$8.removeRectText = removeRectText;\n        proto$8.appendRectText = appendRectText;\n    }\n\n    Text.prototype.brushVML = function (vmlRoot) {\n        var style = this.style;\n        if (style.text != null) {\n            this.drawRectText(vmlRoot, {\n                x: style.x || 0, y: style.y || 0,\n                width: 0, height: 0\n            }, this.getBoundingRect(), true);\n        }\n        else {\n            this.removeRectText(vmlRoot);\n        }\n    };\n\n    Text.prototype.onRemove = function (vmlRoot) {\n        this.removeRectText(vmlRoot);\n    };\n\n    Text.prototype.onAdd = function (vmlRoot) {\n        this.appendRectText(vmlRoot);\n    };\n}\n\n/**\n * VML Painter.\n *\n * @module zrender/vml/Painter\n */\n\nfunction parseInt10$1(val) {\n    return parseInt(val, 10);\n}\n\n/**\n * @alias module:zrender/vml/Painter\n */\nfunction VMLPainter(root, storage) {\n\n    initVML();\n\n    this.root = root;\n\n    this.storage = storage;\n\n    var vmlViewport = document.createElement('div');\n\n    var vmlRoot = document.createElement('div');\n\n    vmlViewport.style.cssText = 'display:inline-block;overflow:hidden;position:relative;width:300px;height:150px;';\n\n    vmlRoot.style.cssText = 'position:absolute;left:0;top:0;';\n\n    root.appendChild(vmlViewport);\n\n    this._vmlRoot = vmlRoot;\n    this._vmlViewport = vmlViewport;\n\n    this.resize();\n\n    // Modify storage\n    var oldDelFromStorage = storage.delFromStorage;\n    var oldAddToStorage = storage.addToStorage;\n    storage.delFromStorage = function (el) {\n        oldDelFromStorage.call(storage, el);\n\n        if (el) {\n            el.onRemove && el.onRemove(vmlRoot);\n        }\n    };\n\n    storage.addToStorage = function (el) {\n        // Displayable already has a vml node\n        el.onAdd && el.onAdd(vmlRoot);\n\n        oldAddToStorage.call(storage, el);\n    };\n\n    this._firstPaint = true;\n}\n\nVMLPainter.prototype = {\n\n    constructor: VMLPainter,\n\n    getType: function () {\n        return 'vml';\n    },\n\n    /**\n     * @return {HTMLDivElement}\n     */\n    getViewportRoot: function () {\n        return this._vmlViewport;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    /**\n     * 刷新\n     */\n    refresh: function () {\n\n        var list = this.storage.getDisplayList(true, true);\n\n        this._paintList(list);\n    },\n\n    _paintList: function (list) {\n        var vmlRoot = this._vmlRoot;\n        for (var i = 0; i < list.length; i++) {\n            var el = list[i];\n            if (el.invisible || el.ignore) {\n                if (!el.__alreadyNotVisible) {\n                    el.onRemove(vmlRoot);\n                }\n                // Set as already invisible\n                el.__alreadyNotVisible = true;\n            }\n            else {\n                if (el.__alreadyNotVisible) {\n                    el.onAdd(vmlRoot);\n                }\n                el.__alreadyNotVisible = false;\n                if (el.__dirty) {\n                    el.beforeBrush && el.beforeBrush();\n                    (el.brushVML || el.brush).call(el, vmlRoot);\n                    el.afterBrush && el.afterBrush();\n                }\n            }\n            el.__dirty = false;\n        }\n\n        if (this._firstPaint) {\n            // Detached from document at first time\n            // to avoid page refreshing too many times\n\n            // FIXME 如果每次都先 removeChild 可能会导致一些填充和描边的效果改变\n            this._vmlViewport.appendChild(vmlRoot);\n            this._firstPaint = false;\n        }\n    },\n\n    resize: function (width, height) {\n        var width = width == null ? this._getWidth() : width;\n        var height = height == null ? this._getHeight() : height;\n\n        if (this._width !== width || this._height !== height) {\n            this._width = width;\n            this._height = height;\n\n            var vmlViewportStyle = this._vmlViewport.style;\n            vmlViewportStyle.width = width + 'px';\n            vmlViewportStyle.height = height + 'px';\n        }\n    },\n\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this._vmlRoot =\n        this._vmlViewport =\n        this.storage = null;\n    },\n\n    getWidth: function () {\n        return this._width;\n    },\n\n    getHeight: function () {\n        return this._height;\n    },\n\n    clear: function () {\n        if (this._vmlViewport) {\n            this.root.removeChild(this._vmlViewport);\n        }\n    },\n\n    _getWidth: function () {\n        var root = this.root;\n        var stl = root.currentStyle;\n\n        return ((root.clientWidth || parseInt10$1(stl.width))\n                - parseInt10$1(stl.paddingLeft)\n                - parseInt10$1(stl.paddingRight)) | 0;\n    },\n\n    _getHeight: function () {\n        var root = this.root;\n        var stl = root.currentStyle;\n\n        return ((root.clientHeight || parseInt10$1(stl.height))\n                - parseInt10$1(stl.paddingTop)\n                - parseInt10$1(stl.paddingBottom)) | 0;\n    }\n};\n\n// Not supported methods\nfunction createMethodNotSupport(method) {\n    return function () {\n        zrLog('In IE8.0 VML mode painter not support method \"' + method + '\"');\n    };\n}\n\n// Unsupported methods\neach$1([\n    'getLayer', 'insertLayer', 'eachLayer', 'eachBuiltinLayer', 'eachOtherLayer', 'getLayers',\n    'modLayer', 'delLayer', 'clearLayer', 'toDataURL', 'pathToImage'\n], function (name) {\n    VMLPainter.prototype[name] = createMethodNotSupport(name);\n});\n\nregisterPainter('vml', VMLPainter);\n\nvar svgURI = 'http://www.w3.org/2000/svg';\n\nfunction createElement(name) {\n    return document.createElementNS(svgURI, name);\n}\n\n// TODO\n// 1. shadow\n// 2. Image: sx, sy, sw, sh\n\nvar CMD$4 = PathProxy.CMD;\nvar arrayJoin = Array.prototype.join;\n\nvar NONE = 'none';\nvar mathRound = Math.round;\nvar mathSin$3 = Math.sin;\nvar mathCos$3 = Math.cos;\nvar PI$5 = Math.PI;\nvar PI2$7 = Math.PI * 2;\nvar degree = 180 / PI$5;\n\nvar EPSILON$4 = 1e-4;\n\nfunction round4(val) {\n    return mathRound(val * 1e4) / 1e4;\n}\n\nfunction isAroundZero$1(val) {\n    return val < EPSILON$4 && val > -EPSILON$4;\n}\n\nfunction pathHasFill(style, isText) {\n    var fill = isText ? style.textFill : style.fill;\n    return fill != null && fill !== NONE;\n}\n\nfunction pathHasStroke(style, isText) {\n    var stroke = isText ? style.textStroke : style.stroke;\n    return stroke != null && stroke !== NONE;\n}\n\nfunction setTransform(svgEl, m) {\n    if (m) {\n        attr(svgEl, 'transform', 'matrix(' + arrayJoin.call(m, ',') + ')');\n    }\n}\n\nfunction attr(el, key, val) {\n    if (!val || val.type !== 'linear' && val.type !== 'radial') {\n        // Don't set attribute for gradient, since it need new dom nodes\n        el.setAttribute(key, val);\n    }\n}\n\nfunction attrXLink(el, key, val) {\n    el.setAttributeNS('http://www.w3.org/1999/xlink', key, val);\n}\n\nfunction bindStyle(svgEl, style, isText, el) {\n    if (pathHasFill(style, isText)) {\n        var fill = isText ? style.textFill : style.fill;\n        fill = fill === 'transparent' ? NONE : fill;\n\n        /**\n         * FIXME:\n         * This is a temporary fix for Chrome's clipping bug\n         * that happens when a clip-path is referring another one.\n         * This fix should be used before Chrome's bug is fixed.\n         * For an element that has clip-path, and fill is none,\n         * set it to be \"rgba(0, 0, 0, 0.002)\" will hide the element.\n         * Otherwise, it will show black fill color.\n         * 0.002 is used because this won't work for alpha values smaller\n         * than 0.002.\n         *\n         * See\n         * https://bugs.chromium.org/p/chromium/issues/detail?id=659790\n         * for more information.\n         */\n        if (svgEl.getAttribute('clip-path') !== 'none' && fill === NONE) {\n            fill = 'rgba(0, 0, 0, 0.002)';\n        }\n\n        attr(svgEl, 'fill', fill);\n        attr(svgEl, 'fill-opacity', style.fillOpacity != null ? style.fillOpacity * style.opacity : style.opacity);\n    }\n    else {\n        attr(svgEl, 'fill', NONE);\n    }\n\n    if (pathHasStroke(style, isText)) {\n        var stroke = isText ? style.textStroke : style.stroke;\n        stroke = stroke === 'transparent' ? NONE : stroke;\n        attr(svgEl, 'stroke', stroke);\n        var strokeWidth = isText\n            ? style.textStrokeWidth\n            : style.lineWidth;\n        var strokeScale = !isText && style.strokeNoScale\n            ? el.getLineScale()\n            : 1;\n        attr(svgEl, 'stroke-width', strokeWidth / strokeScale);\n        // stroke then fill for text; fill then stroke for others\n        attr(svgEl, 'paint-order', isText ? 'stroke' : 'fill');\n        attr(svgEl, 'stroke-opacity', style.strokeOpacity != null ? style.strokeOpacity : style.opacity);\n        var lineDash = style.lineDash;\n        if (lineDash) {\n            attr(svgEl, 'stroke-dasharray', style.lineDash.join(','));\n            attr(svgEl, 'stroke-dashoffset', mathRound(style.lineDashOffset || 0));\n        }\n        else {\n            attr(svgEl, 'stroke-dasharray', '');\n        }\n\n        // PENDING\n        style.lineCap && attr(svgEl, 'stroke-linecap', style.lineCap);\n        style.lineJoin && attr(svgEl, 'stroke-linejoin', style.lineJoin);\n        style.miterLimit && attr(svgEl, 'stroke-miterlimit', style.miterLimit);\n    }\n    else {\n        attr(svgEl, 'stroke', NONE);\n    }\n}\n\n/***************************************************\n * PATH\n **************************************************/\nfunction pathDataToString$1(path) {\n    var str = [];\n    var data = path.data;\n    var dataLength = path.len();\n    for (var i = 0; i < dataLength;) {\n        var cmd = data[i++];\n        var cmdStr = '';\n        var nData = 0;\n        switch (cmd) {\n            case CMD$4.M:\n                cmdStr = 'M';\n                nData = 2;\n                break;\n            case CMD$4.L:\n                cmdStr = 'L';\n                nData = 2;\n                break;\n            case CMD$4.Q:\n                cmdStr = 'Q';\n                nData = 4;\n                break;\n            case CMD$4.C:\n                cmdStr = 'C';\n                nData = 6;\n                break;\n            case CMD$4.A:\n                var cx = data[i++];\n                var cy = data[i++];\n                var rx = data[i++];\n                var ry = data[i++];\n                var theta = data[i++];\n                var dTheta = data[i++];\n                var psi = data[i++];\n                var clockwise = data[i++];\n\n                var dThetaPositive = Math.abs(dTheta);\n                var isCircle = isAroundZero$1(dThetaPositive - PI2$7)\n                    && !isAroundZero$1(dThetaPositive);\n\n                var large = false;\n                if (dThetaPositive >= PI2$7) {\n                    large = true;\n                }\n                else if (isAroundZero$1(dThetaPositive)) {\n                    large = false;\n                }\n                else {\n                    large = (dTheta > -PI$5 && dTheta < 0 || dTheta > PI$5)\n                        === !!clockwise;\n                }\n\n                var x0 = round4(cx + rx * mathCos$3(theta));\n                var y0 = round4(cy + ry * mathSin$3(theta));\n\n                // It will not draw if start point and end point are exactly the same\n                // We need to shift the end point with a small value\n                // FIXME A better way to draw circle ?\n                if (isCircle) {\n                    if (clockwise) {\n                        dTheta = PI2$7 - 1e-4;\n                    }\n                    else {\n                        dTheta = -PI2$7 + 1e-4;\n                    }\n\n                    large = true;\n\n                    if (i === 9) {\n                        // Move to (x0, y0) only when CMD.A comes at the\n                        // first position of a shape.\n                        // For instance, when drawing a ring, CMD.A comes\n                        // after CMD.M, so it's unnecessary to move to\n                        // (x0, y0).\n                        str.push('M', x0, y0);\n                    }\n                }\n\n                var x = round4(cx + rx * mathCos$3(theta + dTheta));\n                var y = round4(cy + ry * mathSin$3(theta + dTheta));\n\n                // FIXME Ellipse\n                str.push('A', round4(rx), round4(ry),\n                    mathRound(psi * degree), +large, +clockwise, x, y);\n                break;\n            case CMD$4.Z:\n                cmdStr = 'Z';\n                break;\n            case CMD$4.R:\n                var x = round4(data[i++]);\n                var y = round4(data[i++]);\n                var w = round4(data[i++]);\n                var h = round4(data[i++]);\n                str.push(\n                    'M', x, y,\n                    'L', x + w, y,\n                    'L', x + w, y + h,\n                    'L', x, y + h,\n                    'L', x, y\n                );\n                break;\n        }\n        cmdStr && str.push(cmdStr);\n        for (var j = 0; j < nData; j++) {\n            // PENDING With scale\n            str.push(round4(data[i++]));\n        }\n    }\n    return str.join(' ');\n}\n\nvar svgPath = {};\nsvgPath.brush = function (el) {\n    var style = el.style;\n\n    var svgEl = el.__svgEl;\n    if (!svgEl) {\n        svgEl = createElement('path');\n        el.__svgEl = svgEl;\n    }\n\n    if (!el.path) {\n        el.createPathProxy();\n    }\n    var path = el.path;\n\n    if (el.__dirtyPath) {\n        path.beginPath();\n        path.subPixelOptimize = false;\n        el.buildPath(path, el.shape);\n        el.__dirtyPath = false;\n\n        var pathStr = pathDataToString$1(path);\n        if (pathStr.indexOf('NaN') < 0) {\n            // Ignore illegal path, which may happen such in out-of-range\n            // data in Calendar series.\n            attr(svgEl, 'd', pathStr);\n        }\n    }\n\n    bindStyle(svgEl, style, false, el);\n    setTransform(svgEl, el.transform);\n\n    if (style.text != null) {\n        svgTextDrawRectText(el, el.getBoundingRect());\n    }\n};\n\n/***************************************************\n * IMAGE\n **************************************************/\nvar svgImage = {};\nsvgImage.brush = function (el) {\n    var style = el.style;\n    var image = style.image;\n\n    if (image instanceof HTMLImageElement) {\n        var src = image.src;\n        image = src;\n    }\n    if (!image) {\n        return;\n    }\n\n    var x = style.x || 0;\n    var y = style.y || 0;\n\n    var dw = style.width;\n    var dh = style.height;\n\n    var svgEl = el.__svgEl;\n    if (!svgEl) {\n        svgEl = createElement('image');\n        el.__svgEl = svgEl;\n    }\n\n    if (image !== el.__imageSrc) {\n        attrXLink(svgEl, 'href', image);\n        // Caching image src\n        el.__imageSrc = image;\n    }\n\n    attr(svgEl, 'width', dw);\n    attr(svgEl, 'height', dh);\n\n    attr(svgEl, 'x', x);\n    attr(svgEl, 'y', y);\n\n    setTransform(svgEl, el.transform);\n\n    if (style.text != null) {\n        svgTextDrawRectText(el, el.getBoundingRect());\n    }\n};\n\n/***************************************************\n * TEXT\n **************************************************/\nvar svgText = {};\nvar tmpRect$3 = new BoundingRect();\n\nvar svgTextDrawRectText = function (el, rect, textRect) {\n    var style = el.style;\n\n    el.__dirty && normalizeTextStyle(style, true);\n\n    var text = style.text;\n    // Convert to string\n    if (text == null) {\n        // Draw no text only when text is set to null, but not ''\n        return;\n    }\n    else {\n        text += '';\n    }\n\n    var textSvgEl = el.__textSvgEl;\n    if (!textSvgEl) {\n        textSvgEl = createElement('text');\n        el.__textSvgEl = textSvgEl;\n    }\n\n    var x;\n    var y;\n    var textPosition = style.textPosition;\n    var distance = style.textDistance;\n    var align = style.textAlign || 'left';\n\n    if (typeof style.fontSize === 'number') {\n        style.fontSize += 'px';\n    }\n    var font = style.font\n        || [\n            style.fontStyle || '',\n            style.fontWeight || '',\n            style.fontSize || '',\n            style.fontFamily || ''\n        ].join(' ')\n        || DEFAULT_FONT$1;\n\n    var verticalAlign = getVerticalAlignForSvg(style.textVerticalAlign);\n\n    textRect = getBoundingRect(\n        text, font, align,\n        verticalAlign, style.textPadding, style.textLineHeight\n    );\n\n    var lineHeight = textRect.lineHeight;\n    // Text position represented by coord\n    if (textPosition instanceof Array) {\n        x = rect.x + textPosition[0];\n        y = rect.y + textPosition[1];\n    }\n    else {\n        var newPos = adjustTextPositionOnRect(\n            textPosition, rect, distance\n        );\n        x = newPos.x;\n        y = newPos.y;\n        verticalAlign = getVerticalAlignForSvg(newPos.textVerticalAlign);\n        align = newPos.textAlign;\n    }\n\n    attr(textSvgEl, 'alignment-baseline', verticalAlign);\n\n    if (font) {\n        textSvgEl.style.font = font;\n    }\n\n    var textPadding = style.textPadding;\n\n    // Make baseline top\n    attr(textSvgEl, 'x', x);\n    attr(textSvgEl, 'y', y);\n\n    bindStyle(textSvgEl, style, true, el);\n    if (el instanceof Text || el.style.transformText) {\n        // Transform text with element\n        setTransform(textSvgEl, el.transform);\n    }\n    else {\n        if (el.transform) {\n            tmpRect$3.copy(rect);\n            tmpRect$3.applyTransform(el.transform);\n            rect = tmpRect$3;\n        }\n        else {\n            var pos = el.transformCoordToGlobal(rect.x, rect.y);\n            rect.x = pos[0];\n            rect.y = pos[1];\n            el.transform = identity(create$1());\n        }\n\n        // Text rotation, but no element transform\n        var origin = style.textOrigin;\n        if (origin === 'center') {\n            x = textRect.width / 2 + x;\n            y = textRect.height / 2 + y;\n        }\n        else if (origin) {\n            x = origin[0] + x;\n            y = origin[1] + y;\n        }\n        var rotate$$1 = -style.textRotation || 0;\n        var transform = create$1();\n        // Apply textRotate to element matrix\n        rotate(transform, transform, rotate$$1);\n\n        var pos = [el.transform[4], el.transform[5]];\n        translate(transform, transform, pos);\n        setTransform(textSvgEl, transform);\n    }\n\n    var textLines = text.split('\\n');\n    var nTextLines = textLines.length;\n    var textAnchor = align;\n    // PENDING\n    if (textAnchor === 'left') {\n        textAnchor = 'start';\n        textPadding && (x += textPadding[3]);\n    }\n    else if (textAnchor === 'right') {\n        textAnchor = 'end';\n        textPadding && (x -= textPadding[1]);\n    }\n    else if (textAnchor === 'center') {\n        textAnchor = 'middle';\n        textPadding && (x += (textPadding[3] - textPadding[1]) / 2);\n    }\n\n    var dy = 0;\n    if (verticalAlign === 'after-edge') {\n        dy = -textRect.height + lineHeight;\n        textPadding && (dy -= textPadding[2]);\n    }\n    else if (verticalAlign === 'middle') {\n        dy = (-textRect.height + lineHeight) / 2;\n        textPadding && (y += (textPadding[0] - textPadding[2]) / 2);\n    }\n    else {\n        textPadding && (dy += textPadding[0]);\n    }\n\n    // Font may affect position of each tspan elements\n    if (el.__text !== text || el.__textFont !== font) {\n        var tspanList = el.__tspanList || [];\n        el.__tspanList = tspanList;\n        for (var i = 0; i < nTextLines; i++) {\n            // Using cached tspan elements\n            var tspan = tspanList[i];\n            if (!tspan) {\n                tspan = tspanList[i] = createElement('tspan');\n                textSvgEl.appendChild(tspan);\n                attr(tspan, 'alignment-baseline', verticalAlign);\n                attr(tspan, 'text-anchor', textAnchor);\n            }\n            else {\n                tspan.innerHTML = '';\n            }\n            attr(tspan, 'x', x);\n            attr(tspan, 'y', y + i * lineHeight + dy);\n            tspan.appendChild(document.createTextNode(textLines[i]));\n        }\n        // Remove unsed tspan elements\n        for (; i < tspanList.length; i++) {\n            textSvgEl.removeChild(tspanList[i]);\n        }\n        tspanList.length = nTextLines;\n\n        el.__text = text;\n        el.__textFont = font;\n    }\n    else if (el.__tspanList.length) {\n        // Update span x and y\n        var len = el.__tspanList.length;\n        for (var i = 0; i < len; ++i) {\n            var tspan = el.__tspanList[i];\n            if (tspan) {\n                attr(tspan, 'x', x);\n                attr(tspan, 'y', y + i * lineHeight + dy);\n            }\n        }\n    }\n};\n\nfunction getVerticalAlignForSvg(verticalAlign) {\n    if (verticalAlign === 'middle') {\n        return 'middle';\n    }\n    else if (verticalAlign === 'bottom') {\n        return 'after-edge';\n    }\n    else {\n        return 'hanging';\n    }\n}\n\nsvgText.drawRectText = svgTextDrawRectText;\n\nsvgText.brush = function (el) {\n    var style = el.style;\n    if (style.text != null) {\n        // 强制设置 textPosition\n        style.textPosition = [0, 0];\n        svgTextDrawRectText(el, {\n            x: style.x || 0, y: style.y || 0,\n            width: 0, height: 0\n        }, el.getBoundingRect());\n    }\n};\n\n// Myers' Diff Algorithm\n// Modified from https://github.com/kpdecker/jsdiff/blob/master/src/diff/base.js\n\nfunction Diff() {}\n\nDiff.prototype = {\n    diff: function (oldArr, newArr, equals) {\n        if (!equals) {\n            equals = function (a, b) {\n                return a === b;\n            };\n        }\n        this.equals = equals;\n\n        var self = this;\n\n        oldArr = oldArr.slice();\n        newArr = newArr.slice();\n        // Allow subclasses to massage the input prior to running\n        var newLen = newArr.length;\n        var oldLen = oldArr.length;\n        var editLength = 1;\n        var maxEditLength = newLen + oldLen;\n        var bestPath = [{ newPos: -1, components: [] }];\n\n        // Seed editLength = 0, i.e. the content starts with the same values\n        var oldPos = this.extractCommon(bestPath[0], newArr, oldArr, 0);\n        if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) {\n            var indices = [];\n            for (var i = 0; i < newArr.length; i++) {\n                indices.push(i);\n            }\n            // Identity per the equality and tokenizer\n            return [{\n                indices: indices, count: newArr.length\n            }];\n        }\n\n        // Main worker method. checks all permutations of a given edit length for acceptance.\n        function execEditLength() {\n            for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) {\n                var basePath;\n                var addPath = bestPath[diagonalPath - 1];\n                var removePath = bestPath[diagonalPath + 1];\n                var oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;\n                if (addPath) {\n                    // No one else is going to attempt to use this value, clear it\n                    bestPath[diagonalPath - 1] = undefined;\n                }\n\n                var canAdd = addPath && addPath.newPos + 1 < newLen;\n                var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;\n                if (!canAdd && !canRemove) {\n                    // If this path is a terminal then prune\n                    bestPath[diagonalPath] = undefined;\n                    continue;\n                }\n\n                // Select the diagonal that we want to branch from. We select the prior\n                // path whose position in the new string is the farthest from the origin\n                // and does not pass the bounds of the diff graph\n                if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {\n                    basePath = clonePath(removePath);\n                    self.pushComponent(basePath.components, undefined, true);\n                }\n                else {\n                    basePath = addPath;   // No need to clone, we've pulled it from the list\n                    basePath.newPos++;\n                    self.pushComponent(basePath.components, true, undefined);\n                }\n\n                oldPos = self.extractCommon(basePath, newArr, oldArr, diagonalPath);\n\n                // If we have hit the end of both strings, then we are done\n                if (basePath.newPos + 1 >= newLen && oldPos + 1 >= oldLen) {\n                    return buildValues(self, basePath.components, newArr, oldArr);\n                }\n                else {\n                    // Otherwise track this path as a potential candidate and continue.\n                    bestPath[diagonalPath] = basePath;\n                }\n            }\n\n            editLength++;\n        }\n\n        while (editLength <= maxEditLength) {\n            var ret = execEditLength();\n            if (ret) {\n                return ret;\n            }\n        }\n    },\n\n    pushComponent: function (components, added, removed) {\n        var last = components[components.length - 1];\n        if (last && last.added === added && last.removed === removed) {\n            // We need to clone here as the component clone operation is just\n            // as shallow array clone\n            components[components.length - 1] = {count: last.count + 1, added: added, removed: removed };\n        }\n        else {\n            components.push({count: 1, added: added, removed: removed });\n        }\n    },\n    extractCommon: function (basePath, newArr, oldArr, diagonalPath) {\n        var newLen = newArr.length;\n        var oldLen = oldArr.length;\n        var newPos = basePath.newPos;\n        var oldPos = newPos - diagonalPath;\n        var commonCount = 0;\n\n        while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newArr[newPos + 1], oldArr[oldPos + 1])) {\n            newPos++;\n            oldPos++;\n            commonCount++;\n        }\n\n        if (commonCount) {\n            basePath.components.push({count: commonCount});\n        }\n\n        basePath.newPos = newPos;\n        return oldPos;\n    },\n    tokenize: function (value) {\n        return value.slice();\n    },\n    join: function (value) {\n        return value.slice();\n    }\n};\n\nfunction buildValues(diff, components, newArr, oldArr) {\n    var componentPos = 0;\n    var componentLen = components.length;\n    var newPos = 0;\n    var oldPos = 0;\n\n    for (; componentPos < componentLen; componentPos++) {\n        var component = components[componentPos];\n        if (!component.removed) {\n            var indices = [];\n            for (var i = newPos; i < newPos + component.count; i++) {\n                indices.push(i);\n            }\n            component.indices = indices;\n            newPos += component.count;\n            // Common case\n            if (!component.added) {\n                oldPos += component.count;\n            }\n        }\n        else {\n            var indices = [];\n            for (var i = oldPos; i < oldPos + component.count; i++) {\n                indices.push(i);\n            }\n            component.indices = indices;\n            oldPos += component.count;\n        }\n    }\n\n    return components;\n}\n\nfunction clonePath(path) {\n    return { newPos: path.newPos, components: path.components.slice(0) };\n}\n\nvar arrayDiff = new Diff();\n\nvar arrayDiff$1 = function (oldArr, newArr, callback) {\n    return arrayDiff.diff(oldArr, newArr, callback);\n};\n\n/**\n * @file Manages elements that can be defined in <defs> in SVG,\n *       e.g., gradients, clip path, etc.\n * @author Zhang Wenli\n */\n\nvar MARK_UNUSED = '0';\nvar MARK_USED = '1';\n\n/**\n * Manages elements that can be defined in <defs> in SVG,\n * e.g., gradients, clip path, etc.\n *\n * @class\n * @param {number}          zrId      zrender instance id\n * @param {SVGElement}      svgRoot   root of SVG document\n * @param {string|string[]} tagNames  possible tag names\n * @param {string}          markLabel label name to make if the element\n *                                    is used\n */\nfunction Definable(\n    zrId,\n    svgRoot,\n    tagNames,\n    markLabel,\n    domName\n) {\n    this._zrId = zrId;\n    this._svgRoot = svgRoot;\n    this._tagNames = typeof tagNames === 'string' ? [tagNames] : tagNames;\n    this._markLabel = markLabel;\n    this._domName = domName || '_dom';\n\n    this.nextId = 0;\n}\n\n\nDefinable.prototype.createElement = createElement;\n\n\n/**\n * Get the <defs> tag for svgRoot; optionally creates one if not exists.\n *\n * @param {boolean} isForceCreating if need to create when not exists\n * @return {SVGDefsElement} SVG <defs> element, null if it doesn't\n * exist and isForceCreating is false\n */\nDefinable.prototype.getDefs = function (isForceCreating) {\n    var svgRoot = this._svgRoot;\n    var defs = this._svgRoot.getElementsByTagName('defs');\n    if (defs.length === 0) {\n        // Not exist\n        if (isForceCreating) {\n            defs = svgRoot.insertBefore(\n                this.createElement('defs'), // Create new tag\n                svgRoot.firstChild // Insert in the front of svg\n            );\n            if (!defs.contains) {\n                // IE doesn't support contains method\n                defs.contains = function (el) {\n                    var children = defs.children;\n                    if (!children) {\n                        return false;\n                    }\n                    for (var i = children.length - 1; i >= 0; --i) {\n                        if (children[i] === el) {\n                            return true;\n                        }\n                    }\n                    return false;\n                };\n            }\n            return defs;\n        }\n        else {\n            return null;\n        }\n    }\n    else {\n        return defs[0];\n    }\n};\n\n\n/**\n * Update DOM element if necessary.\n *\n * @param {Object|string} element style element. e.g., for gradient,\n *                                it may be '#ccc' or {type: 'linear', ...}\n * @param {Function|undefined} onUpdate update callback\n */\nDefinable.prototype.update = function (element, onUpdate) {\n    if (!element) {\n        return;\n    }\n\n    var defs = this.getDefs(false);\n    if (element[this._domName] && defs.contains(element[this._domName])) {\n        // Update DOM\n        if (typeof onUpdate === 'function') {\n            onUpdate(element);\n        }\n    }\n    else {\n        // No previous dom, create new\n        var dom = this.add(element);\n        if (dom) {\n            element[this._domName] = dom;\n        }\n    }\n};\n\n\n/**\n * Add gradient dom to defs\n *\n * @param {SVGElement} dom DOM to be added to <defs>\n */\nDefinable.prototype.addDom = function (dom) {\n    var defs = this.getDefs(true);\n    defs.appendChild(dom);\n};\n\n\n/**\n * Remove DOM of a given element.\n *\n * @param {SVGElement} element element to remove dom\n */\nDefinable.prototype.removeDom = function (element) {\n    var defs = this.getDefs(false);\n    if (defs && element[this._domName]) {\n        defs.removeChild(element[this._domName]);\n        element[this._domName] = null;\n    }\n};\n\n\n/**\n * Get DOMs of this element.\n *\n * @return {HTMLDomElement} doms of this defineable elements in <defs>\n */\nDefinable.prototype.getDoms = function () {\n    var defs = this.getDefs(false);\n    if (!defs) {\n        // No dom when defs is not defined\n        return [];\n    }\n\n    var doms = [];\n    each$1(this._tagNames, function (tagName) {\n        var tags = defs.getElementsByTagName(tagName);\n        // Note that tags is HTMLCollection, which is array-like\n        // rather than real array.\n        // So `doms.concat(tags)` add tags as one object.\n        doms = doms.concat([].slice.call(tags));\n    });\n\n    return doms;\n};\n\n\n/**\n * Mark DOMs to be unused before painting, and clear unused ones at the end\n * of the painting.\n */\nDefinable.prototype.markAllUnused = function () {\n    var doms = this.getDoms();\n    var that = this;\n    each$1(doms, function (dom) {\n        dom[that._markLabel] = MARK_UNUSED;\n    });\n};\n\n\n/**\n * Mark a single DOM to be used.\n *\n * @param {SVGElement} dom DOM to mark\n */\nDefinable.prototype.markUsed = function (dom) {\n    if (dom) {\n        dom[this._markLabel] = MARK_USED;\n    }\n};\n\n\n/**\n * Remove unused DOMs defined in <defs>\n */\nDefinable.prototype.removeUnused = function () {\n    var defs = this.getDefs(false);\n    if (!defs) {\n        // Nothing to remove\n        return;\n    }\n\n    var doms = this.getDoms();\n    var that = this;\n    each$1(doms, function (dom) {\n        if (dom[that._markLabel] !== MARK_USED) {\n            // Remove gradient\n            defs.removeChild(dom);\n        }\n    });\n};\n\n\n/**\n * Get SVG proxy.\n *\n * @param {Displayable} displayable displayable element\n * @return {Path|Image|Text} svg proxy of given element\n */\nDefinable.prototype.getSvgProxy = function (displayable) {\n    if (displayable instanceof Path) {\n        return svgPath;\n    }\n    else if (displayable instanceof ZImage) {\n        return svgImage;\n    }\n    else if (displayable instanceof Text) {\n        return svgText;\n    }\n    else {\n        return svgPath;\n    }\n};\n\n\n/**\n * Get text SVG element.\n *\n * @param {Displayable} displayable displayable element\n * @return {SVGElement} SVG element of text\n */\nDefinable.prototype.getTextSvgElement = function (displayable) {\n    return displayable.__textSvgEl;\n};\n\n\n/**\n * Get SVG element.\n *\n * @param {Displayable} displayable displayable element\n * @return {SVGElement} SVG element\n */\nDefinable.prototype.getSvgElement = function (displayable) {\n    return displayable.__svgEl;\n};\n\n/**\n * @file Manages SVG gradient elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG gradient elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction GradientManager(zrId, svgRoot) {\n    Definable.call(\n        this,\n        zrId,\n        svgRoot,\n        ['linearGradient', 'radialGradient'],\n        '__gradient_in_use__'\n    );\n}\n\n\ninherits(GradientManager, Definable);\n\n\n/**\n * Create new gradient DOM for fill or stroke if not exist,\n * but will not update gradient if exists.\n *\n * @param {SvgElement}  svgElement   SVG element to paint\n * @param {Displayable} displayable  zrender displayable element\n */\nGradientManager.prototype.addWithoutUpdate = function (\n    svgElement,\n    displayable\n) {\n    if (displayable && displayable.style) {\n        var that = this;\n        each$1(['fill', 'stroke'], function (fillOrStroke) {\n            if (displayable.style[fillOrStroke]\n                && (displayable.style[fillOrStroke].type === 'linear'\n                || displayable.style[fillOrStroke].type === 'radial')\n            ) {\n                var gradient = displayable.style[fillOrStroke];\n                var defs = that.getDefs(true);\n\n                // Create dom in <defs> if not exists\n                var dom;\n                if (gradient._dom) {\n                    // Gradient exists\n                    dom = gradient._dom;\n                    if (!defs.contains(gradient._dom)) {\n                        // _dom is no longer in defs, recreate\n                        that.addDom(dom);\n                    }\n                }\n                else {\n                    // New dom\n                    dom = that.add(gradient);\n                }\n\n                that.markUsed(displayable);\n\n                var id = dom.getAttribute('id');\n                svgElement.setAttribute(fillOrStroke, 'url(#' + id + ')');\n            }\n        });\n    }\n};\n\n\n/**\n * Add a new gradient tag in <defs>\n *\n * @param   {Gradient} gradient zr gradient instance\n * @return {SVGLinearGradientElement | SVGRadialGradientElement}\n *                            created DOM\n */\nGradientManager.prototype.add = function (gradient) {\n    var dom;\n    if (gradient.type === 'linear') {\n        dom = this.createElement('linearGradient');\n    }\n    else if (gradient.type === 'radial') {\n        dom = this.createElement('radialGradient');\n    }\n    else {\n        zrLog('Illegal gradient type.');\n        return null;\n    }\n\n    // Set dom id with gradient id, since each gradient instance\n    // will have no more than one dom element.\n    // id may exists before for those dirty elements, in which case\n    // id should remain the same, and other attributes should be\n    // updated.\n    gradient.id = gradient.id || this.nextId++;\n    dom.setAttribute('id', 'zr' + this._zrId\n        + '-gradient-' + gradient.id);\n\n    this.updateDom(gradient, dom);\n    this.addDom(dom);\n\n    return dom;\n};\n\n\n/**\n * Update gradient.\n *\n * @param {Gradient} gradient zr gradient instance\n */\nGradientManager.prototype.update = function (gradient) {\n    var that = this;\n    Definable.prototype.update.call(this, gradient, function () {\n        var type = gradient.type;\n        var tagName = gradient._dom.tagName;\n        if (type === 'linear' && tagName === 'linearGradient'\n            || type === 'radial' && tagName === 'radialGradient'\n        ) {\n            // Gradient type is not changed, update gradient\n            that.updateDom(gradient, gradient._dom);\n        }\n        else {\n            // Remove and re-create if type is changed\n            that.removeDom(gradient);\n            that.add(gradient);\n        }\n    });\n};\n\n\n/**\n * Update gradient dom\n *\n * @param {Gradient} gradient zr gradient instance\n * @param {SVGLinearGradientElement | SVGRadialGradientElement} dom\n *                            DOM to update\n */\nGradientManager.prototype.updateDom = function (gradient, dom) {\n    if (gradient.type === 'linear') {\n        dom.setAttribute('x1', gradient.x);\n        dom.setAttribute('y1', gradient.y);\n        dom.setAttribute('x2', gradient.x2);\n        dom.setAttribute('y2', gradient.y2);\n    }\n    else if (gradient.type === 'radial') {\n        dom.setAttribute('cx', gradient.x);\n        dom.setAttribute('cy', gradient.y);\n        dom.setAttribute('r', gradient.r);\n    }\n    else {\n        zrLog('Illegal gradient type.');\n        return;\n    }\n\n    if (gradient.global) {\n        // x1, x2, y1, y2 in range of 0 to canvas width or height\n        dom.setAttribute('gradientUnits', 'userSpaceOnUse');\n    }\n    else {\n        // x1, x2, y1, y2 in range of 0 to 1\n        dom.setAttribute('gradientUnits', 'objectBoundingBox');\n    }\n\n    // Remove color stops if exists\n    dom.innerHTML = '';\n\n    // Add color stops\n    var colors = gradient.colorStops;\n    for (var i = 0, len = colors.length; i < len; ++i) {\n        var stop = this.createElement('stop');\n        stop.setAttribute('offset', colors[i].offset * 100 + '%');\n\n        var color = colors[i].color;\n        if (color.indexOf('rgba' > -1)) {\n            // Fix Safari bug that stop-color not recognizing alpha #9014\n            var opacity = parse(color)[3];\n            var hex = toHex(color);\n\n            // stop-color cannot be color, since:\n            // The opacity value used for the gradient calculation is the\n            // *product* of the value of stop-opacity and the opacity of the\n            // value of stop-color.\n            // See https://www.w3.org/TR/SVG2/pservers.html#StopOpacityProperty\n            stop.setAttribute('stop-color', '#' + hex);\n            stop.setAttribute('stop-opacity', opacity);\n        }\n        else {\n            stop.setAttribute('stop-color', colors[i].color);\n        }\n\n        dom.appendChild(stop);\n    }\n\n    // Store dom element in gradient, to avoid creating multiple\n    // dom instances for the same gradient element\n    gradient._dom = dom;\n};\n\n/**\n * Mark a single gradient to be used\n *\n * @param {Displayable} displayable displayable element\n */\nGradientManager.prototype.markUsed = function (displayable) {\n    if (displayable.style) {\n        var gradient = displayable.style.fill;\n        if (gradient && gradient._dom) {\n            Definable.prototype.markUsed.call(this, gradient._dom);\n        }\n\n        gradient = displayable.style.stroke;\n        if (gradient && gradient._dom) {\n            Definable.prototype.markUsed.call(this, gradient._dom);\n        }\n    }\n};\n\n/**\n * @file Manages SVG clipPath elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG clipPath elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction ClippathManager(zrId, svgRoot) {\n    Definable.call(this, zrId, svgRoot, 'clipPath', '__clippath_in_use__');\n}\n\n\ninherits(ClippathManager, Definable);\n\n\n/**\n * Update clipPath.\n *\n * @param {Displayable} displayable displayable element\n */\nClippathManager.prototype.update = function (displayable) {\n    var svgEl = this.getSvgElement(displayable);\n    if (svgEl) {\n        this.updateDom(svgEl, displayable.__clipPaths, false);\n    }\n\n    var textEl = this.getTextSvgElement(displayable);\n    if (textEl) {\n        // Make another clipPath for text, since it's transform\n        // matrix is not the same with svgElement\n        this.updateDom(textEl, displayable.__clipPaths, true);\n    }\n\n    this.markUsed(displayable);\n};\n\n\n/**\n * Create an SVGElement of displayable and create a <clipPath> of its\n * clipPath\n *\n * @param {Displayable} parentEl  parent element\n * @param {ClipPath[]}  clipPaths clipPaths of parent element\n * @param {boolean}     isText    if parent element is Text\n */\nClippathManager.prototype.updateDom = function (\n    parentEl,\n    clipPaths,\n    isText\n) {\n    if (clipPaths && clipPaths.length > 0) {\n        // Has clipPath, create <clipPath> with the first clipPath\n        var defs = this.getDefs(true);\n        var clipPath = clipPaths[0];\n        var clipPathEl;\n        var id;\n\n        var dom = isText ? '_textDom' : '_dom';\n\n        if (clipPath[dom]) {\n            // Use a dom that is already in <defs>\n            id = clipPath[dom].getAttribute('id');\n            clipPathEl = clipPath[dom];\n\n            // Use a dom that is already in <defs>\n            if (!defs.contains(clipPathEl)) {\n                // This happens when set old clipPath that has\n                // been previously removed\n                defs.appendChild(clipPathEl);\n            }\n        }\n        else {\n            // New <clipPath>\n            id = 'zr' + this._zrId + '-clip-' + this.nextId;\n            ++this.nextId;\n            clipPathEl = this.createElement('clipPath');\n            clipPathEl.setAttribute('id', id);\n            defs.appendChild(clipPathEl);\n\n            clipPath[dom] = clipPathEl;\n        }\n\n        // Build path and add to <clipPath>\n        var svgProxy = this.getSvgProxy(clipPath);\n        if (clipPath.transform\n            && clipPath.parent.invTransform\n            && !isText\n        ) {\n            /**\n             * If a clipPath has a parent with transform, the transform\n             * of parent should not be considered when setting transform\n             * of clipPath. So we need to transform back from parent's\n             * transform, which is done by multiplying parent's inverse\n             * transform.\n             */\n            // Store old transform\n            var transform = Array.prototype.slice.call(\n                clipPath.transform\n            );\n\n            // Transform back from parent, and brush path\n            mul$1(\n                clipPath.transform,\n                clipPath.parent.invTransform,\n                clipPath.transform\n            );\n            svgProxy.brush(clipPath);\n\n            // Set back transform of clipPath\n            clipPath.transform = transform;\n        }\n        else {\n            svgProxy.brush(clipPath);\n        }\n\n        var pathEl = this.getSvgElement(clipPath);\n\n        clipPathEl.innerHTML = '';\n        /**\n         * Use `cloneNode()` here to appendChild to multiple parents,\n         * which may happend when Text and other shapes are using the same\n         * clipPath. Since Text will create an extra clipPath DOM due to\n         * different transform rules.\n         */\n        clipPathEl.appendChild(pathEl.cloneNode());\n\n        parentEl.setAttribute('clip-path', 'url(#' + id + ')');\n\n        if (clipPaths.length > 1) {\n            // Make the other clipPaths recursively\n            this.updateDom(clipPathEl, clipPaths.slice(1), isText);\n        }\n    }\n    else {\n        // No clipPath\n        if (parentEl) {\n            parentEl.setAttribute('clip-path', 'none');\n        }\n    }\n};\n\n/**\n * Mark a single clipPath to be used\n *\n * @param {Displayable} displayable displayable element\n */\nClippathManager.prototype.markUsed = function (displayable) {\n    var that = this;\n    if (displayable.__clipPaths && displayable.__clipPaths.length > 0) {\n        each$1(displayable.__clipPaths, function (clipPath) {\n            if (clipPath._dom) {\n                Definable.prototype.markUsed.call(that, clipPath._dom);\n            }\n            if (clipPath._textDom) {\n                Definable.prototype.markUsed.call(that, clipPath._textDom);\n            }\n        });\n    }\n};\n\n/**\n * @file Manages SVG shadow elements.\n * @author Zhang Wenli\n */\n\n/**\n * Manages SVG shadow elements.\n *\n * @class\n * @extends Definable\n * @param   {number}     zrId    zrender instance id\n * @param   {SVGElement} svgRoot root of SVG document\n */\nfunction ShadowManager(zrId, svgRoot) {\n    Definable.call(\n        this,\n        zrId,\n        svgRoot,\n        ['filter'],\n        '__filter_in_use__',\n        '_shadowDom'\n    );\n}\n\n\ninherits(ShadowManager, Definable);\n\n\n/**\n * Create new shadow DOM for fill or stroke if not exist,\n * but will not update shadow if exists.\n *\n * @param {SvgElement}  svgElement   SVG element to paint\n * @param {Displayable} displayable  zrender displayable element\n */\nShadowManager.prototype.addWithoutUpdate = function (\n    svgElement,\n    displayable\n) {\n    if (displayable && hasShadow(displayable.style)) {\n        var style = displayable.style;\n\n        // Create dom in <defs> if not exists\n        var dom;\n        if (style._shadowDom) {\n            // Gradient exists\n            dom = style._shadowDom;\n\n            var defs = this.getDefs(true);\n            if (!defs.contains(style._shadowDom)) {\n                // _shadowDom is no longer in defs, recreate\n                this.addDom(dom);\n            }\n        }\n        else {\n            // New dom\n            dom = this.add(displayable);\n        }\n\n        this.markUsed(displayable);\n\n        var id = dom.getAttribute('id');\n        svgElement.style.filter = 'url(#' + id + ')';\n    }\n};\n\n\n/**\n * Add a new shadow tag in <defs>\n *\n * @param {Displayable} displayable  zrender displayable element\n * @return {SVGFilterElement} created DOM\n */\nShadowManager.prototype.add = function (displayable) {\n    var dom = this.createElement('filter');\n    var style = displayable.style;\n\n    // Set dom id with shadow id, since each shadow instance\n    // will have no more than one dom element.\n    // id may exists before for those dirty elements, in which case\n    // id should remain the same, and other attributes should be\n    // updated.\n    style._shadowDomId = style._shadowDomId || this.nextId++;\n    dom.setAttribute('id', 'zr' + this._zrId\n        + '-shadow-' + style._shadowDomId);\n\n    this.updateDom(displayable, dom);\n    this.addDom(dom);\n\n    return dom;\n};\n\n\n/**\n * Update shadow.\n *\n * @param {Displayable} displayable  zrender displayable element\n */\nShadowManager.prototype.update = function (svgElement, displayable) {\n    var style = displayable.style;\n    if (hasShadow(style)) {\n        var that = this;\n        Definable.prototype.update.call(this, displayable, function (style) {\n            that.updateDom(displayable, style._shadowDom);\n        });\n    }\n    else {\n        // Remove shadow\n        this.remove(svgElement, style);\n    }\n};\n\n\n/**\n * Remove DOM and clear parent filter\n */\nShadowManager.prototype.remove = function (svgElement, style) {\n    if (style._shadowDomId != null) {\n        this.removeDom(style);\n        svgElement.style.filter = '';\n    }\n};\n\n\n/**\n * Update shadow dom\n *\n * @param {Displayable} displayable  zrender displayable element\n * @param {SVGFilterElement} dom DOM to update\n */\nShadowManager.prototype.updateDom = function (displayable, dom) {\n    var domChild = dom.getElementsByTagName('feDropShadow');\n    if (domChild.length === 0) {\n        domChild = this.createElement('feDropShadow');\n    }\n    else {\n        domChild = domChild[0];\n    }\n\n    var style = displayable.style;\n    var scaleX = displayable.scale ? (displayable.scale[0] || 1) : 1;\n    var scaleY = displayable.scale ? (displayable.scale[1] || 1) : 1;\n\n    // TODO: textBoxShadowBlur is not supported yet\n    var offsetX, offsetY, blur, color;\n    if (style.shadowBlur || style.shadowOffsetX || style.shadowOffsetY) {\n        offsetX = style.shadowOffsetX || 0;\n        offsetY = style.shadowOffsetY || 0;\n        blur = style.shadowBlur;\n        color = style.shadowColor;\n    }\n    else if (style.textShadowBlur) {\n        offsetX = style.textShadowOffsetX || 0;\n        offsetY = style.textShadowOffsetY || 0;\n        blur = style.textShadowBlur;\n        color = style.textShadowColor;\n    }\n    else {\n        // Remove shadow\n        this.removeDom(dom, style);\n        return;\n    }\n\n    domChild.setAttribute('dx', offsetX / scaleX);\n    domChild.setAttribute('dy', offsetY / scaleY);\n    domChild.setAttribute('flood-color', color);\n\n    // Divide by two here so that it looks the same as in canvas\n    // See: https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-shadowblur\n    var stdDx = blur / 2 / scaleX;\n    var stdDy = blur / 2 / scaleY;\n    var stdDeviation = stdDx + ' ' + stdDy;\n    domChild.setAttribute('stdDeviation', stdDeviation);\n\n    // Fix filter clipping problem\n    dom.setAttribute('x', '-100%');\n    dom.setAttribute('y', '-100%');\n    dom.setAttribute('width', Math.ceil(blur / 2 * 200) + '%');\n    dom.setAttribute('height', Math.ceil(blur / 2 * 200) + '%');\n\n    dom.appendChild(domChild);\n\n    // Store dom element in shadow, to avoid creating multiple\n    // dom instances for the same shadow element\n    style._shadowDom = dom;\n};\n\n/**\n * Mark a single shadow to be used\n *\n * @param {Displayable} displayable displayable element\n */\nShadowManager.prototype.markUsed = function (displayable) {\n    var style = displayable.style;\n    if (style && style._shadowDom) {\n        Definable.prototype.markUsed.call(this, style._shadowDom);\n    }\n};\n\nfunction hasShadow(style) {\n    // TODO: textBoxShadowBlur is not supported yet\n    return style\n        && (style.shadowBlur || style.shadowOffsetX || style.shadowOffsetY\n            || style.textShadowBlur || style.textShadowOffsetX\n            || style.textShadowOffsetY);\n}\n\n/**\n * SVG Painter\n * @module zrender/svg/Painter\n */\n\nfunction parseInt10$2(val) {\n    return parseInt(val, 10);\n}\n\nfunction getSvgProxy(el) {\n    if (el instanceof Path) {\n        return svgPath;\n    }\n    else if (el instanceof ZImage) {\n        return svgImage;\n    }\n    else if (el instanceof Text) {\n        return svgText;\n    }\n    else {\n        return svgPath;\n    }\n}\n\nfunction checkParentAvailable(parent, child) {\n    return child && parent && child.parentNode !== parent;\n}\n\nfunction insertAfter(parent, child, prevSibling) {\n    if (checkParentAvailable(parent, child) && prevSibling) {\n        var nextSibling = prevSibling.nextSibling;\n        nextSibling ? parent.insertBefore(child, nextSibling)\n            : parent.appendChild(child);\n    }\n}\n\nfunction prepend(parent, child) {\n    if (checkParentAvailable(parent, child)) {\n        var firstChild = parent.firstChild;\n        firstChild ? parent.insertBefore(child, firstChild)\n            : parent.appendChild(child);\n    }\n}\n\nfunction remove$1(parent, child) {\n    if (child && parent && child.parentNode === parent) {\n        parent.removeChild(child);\n    }\n}\n\nfunction getTextSvgElement(displayable) {\n    return displayable.__textSvgEl;\n}\n\nfunction getSvgElement(displayable) {\n    return displayable.__svgEl;\n}\n\n/**\n * @alias module:zrender/svg/Painter\n * @constructor\n * @param {HTMLElement} root 绘图容器\n * @param {module:zrender/Storage} storage\n * @param {Object} opts\n */\nvar SVGPainter = function (root, storage, opts, zrId) {\n\n    this.root = root;\n    this.storage = storage;\n    this._opts = opts = extend({}, opts || {});\n\n    var svgRoot = createElement('svg');\n    svgRoot.setAttribute('xmlns', 'http://www.w3.org/2000/svg');\n    svgRoot.setAttribute('version', '1.1');\n    svgRoot.setAttribute('baseProfile', 'full');\n    svgRoot.style.cssText = 'user-select:none;position:absolute;left:0;top:0;';\n\n    this.gradientManager = new GradientManager(zrId, svgRoot);\n    this.clipPathManager = new ClippathManager(zrId, svgRoot);\n    this.shadowManager = new ShadowManager(zrId, svgRoot);\n\n    var viewport = document.createElement('div');\n    viewport.style.cssText = 'overflow:hidden;position:relative';\n\n    this._svgRoot = svgRoot;\n    this._viewport = viewport;\n\n    root.appendChild(viewport);\n    viewport.appendChild(svgRoot);\n\n    this.resize(opts.width, opts.height);\n\n    this._visibleList = [];\n};\n\nSVGPainter.prototype = {\n\n    constructor: SVGPainter,\n\n    getType: function () {\n        return 'svg';\n    },\n\n    getViewportRoot: function () {\n        return this._viewport;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    refresh: function () {\n\n        var list = this.storage.getDisplayList(true);\n\n        this._paintList(list);\n    },\n\n    setBackgroundColor: function (backgroundColor) {\n        // TODO gradient\n        this._viewport.style.background = backgroundColor;\n    },\n\n    _paintList: function (list) {\n        this.gradientManager.markAllUnused();\n        this.clipPathManager.markAllUnused();\n        this.shadowManager.markAllUnused();\n\n        var svgRoot = this._svgRoot;\n        var visibleList = this._visibleList;\n        var listLen = list.length;\n\n        var newVisibleList = [];\n        var i;\n        for (i = 0; i < listLen; i++) {\n            var displayable = list[i];\n            var svgProxy = getSvgProxy(displayable);\n            var svgElement = getSvgElement(displayable)\n                || getTextSvgElement(displayable);\n            if (!displayable.invisible) {\n                if (displayable.__dirty) {\n                    svgProxy && svgProxy.brush(displayable);\n\n                    // Update clipPath\n                    this.clipPathManager.update(displayable);\n\n                    // Update gradient and shadow\n                    if (displayable.style) {\n                        this.gradientManager\n                            .update(displayable.style.fill);\n                        this.gradientManager\n                            .update(displayable.style.stroke);\n\n                        this.shadowManager\n                            .update(svgElement, displayable);\n                    }\n\n                    displayable.__dirty = false;\n                }\n                newVisibleList.push(displayable);\n            }\n        }\n\n        var diff = arrayDiff$1(visibleList, newVisibleList);\n        var prevSvgElement;\n\n        // First do remove, in case element moved to the head and do remove\n        // after add\n        for (i = 0; i < diff.length; i++) {\n            var item = diff[i];\n            if (item.removed) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = visibleList[item.indices[k]];\n                    var svgElement = getSvgElement(displayable);\n                    var textSvgElement = getTextSvgElement(displayable);\n                    remove$1(svgRoot, svgElement);\n                    remove$1(svgRoot, textSvgElement);\n                }\n            }\n        }\n        for (i = 0; i < diff.length; i++) {\n            var item = diff[i];\n            if (item.added) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = newVisibleList[item.indices[k]];\n                    var svgElement = getSvgElement(displayable);\n                    var textSvgElement = getTextSvgElement(displayable);\n                    prevSvgElement\n                        ? insertAfter(svgRoot, svgElement, prevSvgElement)\n                        : prepend(svgRoot, svgElement);\n                    if (svgElement) {\n                        insertAfter(svgRoot, textSvgElement, svgElement);\n                    }\n                    else if (prevSvgElement) {\n                        insertAfter(\n                            svgRoot, textSvgElement, prevSvgElement\n                        );\n                    }\n                    else {\n                        prepend(svgRoot, textSvgElement);\n                    }\n                    // Insert text\n                    insertAfter(svgRoot, textSvgElement, svgElement);\n                    prevSvgElement = textSvgElement || svgElement\n                        || prevSvgElement;\n\n                    this.gradientManager\n                        .addWithoutUpdate(svgElement, displayable);\n                    this.shadowManager\n                        .addWithoutUpdate(prevSvgElement, displayable);\n                    this.clipPathManager.markUsed(displayable);\n                }\n            }\n            else if (!item.removed) {\n                for (var k = 0; k < item.count; k++) {\n                    var displayable = newVisibleList[item.indices[k]];\n                    prevSvgElement =\n                        svgElement =\n                        getTextSvgElement(displayable)\n                        || getSvgElement(displayable)\n                        || prevSvgElement;\n\n                    this.gradientManager.markUsed(displayable);\n                    this.gradientManager\n                        .addWithoutUpdate(svgElement, displayable);\n\n                    this.shadowManager.markUsed(displayable);\n                    this.shadowManager\n                        .addWithoutUpdate(svgElement, displayable);\n\n                    this.clipPathManager.markUsed(displayable);\n                }\n            }\n        }\n\n        this.gradientManager.removeUnused();\n        this.clipPathManager.removeUnused();\n        this.shadowManager.removeUnused();\n\n        this._visibleList = newVisibleList;\n    },\n\n    _getDefs: function (isForceCreating) {\n        var svgRoot = this._svgRoot;\n        var defs = this._svgRoot.getElementsByTagName('defs');\n        if (defs.length === 0) {\n            // Not exist\n            if (isForceCreating) {\n                var defs = svgRoot.insertBefore(\n                    createElement('defs'), // Create new tag\n                    svgRoot.firstChild // Insert in the front of svg\n                );\n                if (!defs.contains) {\n                    // IE doesn't support contains method\n                    defs.contains = function (el) {\n                        var children = defs.children;\n                        if (!children) {\n                            return false;\n                        }\n                        for (var i = children.length - 1; i >= 0; --i) {\n                            if (children[i] === el) {\n                                return true;\n                            }\n                        }\n                        return false;\n                    };\n                }\n                return defs;\n            }\n            else {\n                return null;\n            }\n        }\n        else {\n            return defs[0];\n        }\n    },\n\n    resize: function (width, height) {\n        var viewport = this._viewport;\n        // FIXME Why ?\n        viewport.style.display = 'none';\n\n        // Save input w/h\n        var opts = this._opts;\n        width != null && (opts.width = width);\n        height != null && (opts.height = height);\n\n        width = this._getSize(0);\n        height = this._getSize(1);\n\n        viewport.style.display = '';\n\n        if (this._width !== width || this._height !== height) {\n            this._width = width;\n            this._height = height;\n\n            var viewportStyle = viewport.style;\n            viewportStyle.width = width + 'px';\n            viewportStyle.height = height + 'px';\n\n            var svgRoot = this._svgRoot;\n            // Set width by 'svgRoot.width = width' is invalid\n            svgRoot.setAttribute('width', width);\n            svgRoot.setAttribute('height', height);\n        }\n    },\n\n    /**\n     * 获取绘图区域宽度\n     */\n    getWidth: function () {\n        return this._width;\n    },\n\n    /**\n     * 获取绘图区域高度\n     */\n    getHeight: function () {\n        return this._height;\n    },\n\n    _getSize: function (whIdx) {\n        var opts = this._opts;\n        var wh = ['width', 'height'][whIdx];\n        var cwh = ['clientWidth', 'clientHeight'][whIdx];\n        var plt = ['paddingLeft', 'paddingTop'][whIdx];\n        var prb = ['paddingRight', 'paddingBottom'][whIdx];\n\n        if (opts[wh] != null && opts[wh] !== 'auto') {\n            return parseFloat(opts[wh]);\n        }\n\n        var root = this.root;\n        // IE8 does not support getComputedStyle, but it use VML.\n        var stl = document.defaultView.getComputedStyle(root);\n\n        return (\n            (root[cwh] || parseInt10$2(stl[wh]) || parseInt10$2(root.style[wh]))\n            - (parseInt10$2(stl[plt]) || 0)\n            - (parseInt10$2(stl[prb]) || 0)\n        ) | 0;\n    },\n\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this._svgRoot =\n            this._viewport =\n            this.storage =\n            null;\n    },\n\n    clear: function () {\n        if (this._viewport) {\n            this.root.removeChild(this._viewport);\n        }\n    },\n\n    pathToDataUrl: function () {\n        this.refresh();\n        var html = this._svgRoot.outerHTML;\n        return 'data:image/svg+xml;charset=UTF-8,' + html;\n    }\n};\n\n// Not supported methods\nfunction createMethodNotSupport$1(method) {\n    return function () {\n        zrLog('In SVG mode painter not support method \"' + method + '\"');\n    };\n}\n\n// Unsuppoted methods\neach$1([\n    'getLayer', 'insertLayer', 'eachLayer', 'eachBuiltinLayer',\n    'eachOtherLayer', 'getLayers', 'modLayer', 'delLayer', 'clearLayer',\n    'toDataURL', 'pathToImage'\n], function (name) {\n    SVGPainter.prototype[name] = createMethodNotSupport$1(name);\n});\n\nregisterPainter('svg', SVGPainter);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Import all charts and components\n\nexports.version = version;\nexports.dependencies = dependencies;\nexports.PRIORITY = PRIORITY;\nexports.init = init;\nexports.connect = connect;\nexports.disConnect = disConnect;\nexports.disconnect = disconnect;\nexports.dispose = dispose;\nexports.getInstanceByDom = getInstanceByDom;\nexports.getInstanceById = getInstanceById;\nexports.registerTheme = registerTheme;\nexports.registerPreprocessor = registerPreprocessor;\nexports.registerProcessor = registerProcessor;\nexports.registerPostUpdate = registerPostUpdate;\nexports.registerAction = registerAction;\nexports.registerCoordinateSystem = registerCoordinateSystem;\nexports.getCoordinateSystemDimensions = getCoordinateSystemDimensions;\nexports.registerLayout = registerLayout;\nexports.registerVisual = registerVisual;\nexports.registerLoading = registerLoading;\nexports.extendComponentModel = extendComponentModel;\nexports.extendComponentView = extendComponentView;\nexports.extendSeriesModel = extendSeriesModel;\nexports.extendChartView = extendChartView;\nexports.setCanvasCreator = setCanvasCreator;\nexports.registerMap = registerMap;\nexports.getMap = getMap;\nexports.dataTool = dataTool;\nexports.zrender = zrender;\nexports.number = number;\nexports.format = format;\nexports.throttle = throttle;\nexports.helper = helper;\nexports.matrix = matrix;\nexports.vector = vector;\nexports.color = color;\nexports.parseGeoJSON = parseGeoJson$1;\nexports.parseGeoJson = parseGeoJson;\nexports.util = ecUtil;\nexports.graphic = graphic$1;\nexports.List = List;\nexports.Model = Model;\nexports.Axis = Axis;\nexports.env = env$1;\n\n})));\n//# sourceMappingURL=echarts.js.map\n"
  },
  {
    "path": "static/js/Echarts/echarts.simple.js",
    "content": "(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n\ttypeof define === 'function' && define.amd ? define(['exports'], factory) :\n\t(factory((global.echarts = {})));\n}(this, (function (exports) { 'use strict';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (1) The code `if (__DEV__) ...` can be removed by build tool.\n// (2) If intend to use `__DEV__`, this module should be imported. Use a global\n// variable `__DEV__` may cause that miss the declaration (see #6535), or the\n// declaration is behind of the using position (for example in `Model.extent`,\n// And tools like rollup can not analysis the dependency if not import).\n\nvar dev;\n\n// In browser\nif (typeof window !== 'undefined') {\n    dev = window.__DEV__;\n}\n// In node\nelse if (typeof global !== 'undefined') {\n    dev = global.__DEV__;\n}\n\nif (typeof dev === 'undefined') {\n    dev = true;\n}\n\nvar __DEV__ = dev;\n\n/**\n * zrender: 生成唯一id\n *\n * @author errorrik (errorrik@gmail.com)\n */\n\nvar idStart = 0x0907;\n\nvar guid = function () {\n    return idStart++;\n};\n\n/**\n * echarts设备环境识别\n *\n * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。\n * @author firede[firede@firede.us]\n * @desc thanks zepto.\n */\n\nvar env = {};\n\nif (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') {\n    // In Weixin Application\n    env = {\n        browser: {},\n        os: {},\n        node: false,\n        wxa: true, // Weixin Application\n        canvasSupported: true,\n        svgSupported: false,\n        touchEventsSupported: true,\n        domSupported: false\n    };\n}\nelse if (typeof document === 'undefined' && typeof self !== 'undefined') {\n    // In worker\n    env = {\n        browser: {},\n        os: {},\n        node: false,\n        worker: true,\n        canvasSupported: true,\n        domSupported: false\n    };\n}\nelse if (typeof navigator === 'undefined') {\n    // In node\n    env = {\n        browser: {},\n        os: {},\n        node: true,\n        worker: false,\n        // Assume canvas is supported\n        canvasSupported: true,\n        svgSupported: true,\n        domSupported: false\n    };\n}\nelse {\n    env = detect(navigator.userAgent);\n}\n\nvar env$1 = env;\n\n// Zepto.js\n// (c) 2010-2013 Thomas Fuchs\n// Zepto.js may be freely distributed under the MIT license.\n\nfunction detect(ua) {\n    var os = {};\n    var browser = {};\n    // var webkit = ua.match(/Web[kK]it[\\/]{0,1}([\\d.]+)/);\n    // var android = ua.match(/(Android);?[\\s\\/]+([\\d.]+)?/);\n    // var ipad = ua.match(/(iPad).*OS\\s([\\d_]+)/);\n    // var ipod = ua.match(/(iPod)(.*OS\\s([\\d_]+))?/);\n    // var iphone = !ipad && ua.match(/(iPhone\\sOS)\\s([\\d_]+)/);\n    // var webos = ua.match(/(webOS|hpwOS)[\\s\\/]([\\d.]+)/);\n    // var touchpad = webos && ua.match(/TouchPad/);\n    // var kindle = ua.match(/Kindle\\/([\\d.]+)/);\n    // var silk = ua.match(/Silk\\/([\\d._]+)/);\n    // var blackberry = ua.match(/(BlackBerry).*Version\\/([\\d.]+)/);\n    // var bb10 = ua.match(/(BB10).*Version\\/([\\d.]+)/);\n    // var rimtabletos = ua.match(/(RIM\\sTablet\\sOS)\\s([\\d.]+)/);\n    // var playbook = ua.match(/PlayBook/);\n    // var chrome = ua.match(/Chrome\\/([\\d.]+)/) || ua.match(/CriOS\\/([\\d.]+)/);\n    var firefox = ua.match(/Firefox\\/([\\d.]+)/);\n    // var safari = webkit && ua.match(/Mobile\\//) && !chrome;\n    // var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome;\n    var ie = ua.match(/MSIE\\s([\\d.]+)/)\n        // IE 11 Trident/7.0; rv:11.0\n        || ua.match(/Trident\\/.+?rv:(([\\d.]+))/);\n    var edge = ua.match(/Edge\\/([\\d.]+)/); // IE 12 and 12+\n\n    var weChat = (/micromessenger/i).test(ua);\n\n    // Todo: clean this up with a better OS/browser seperation:\n    // - discern (more) between multiple browsers on android\n    // - decide if kindle fire in silk mode is android or not\n    // - Firefox on Android doesn't specify the Android version\n    // - possibly devide in os, device and browser hashes\n\n    // if (browser.webkit = !!webkit) browser.version = webkit[1];\n\n    // if (android) os.android = true, os.version = android[2];\n    // if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.');\n    // if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.');\n    // if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null;\n    // if (webos) os.webos = true, os.version = webos[2];\n    // if (touchpad) os.touchpad = true;\n    // if (blackberry) os.blackberry = true, os.version = blackberry[2];\n    // if (bb10) os.bb10 = true, os.version = bb10[2];\n    // if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2];\n    // if (playbook) browser.playbook = true;\n    // if (kindle) os.kindle = true, os.version = kindle[1];\n    // if (silk) browser.silk = true, browser.version = silk[1];\n    // if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true;\n    // if (chrome) browser.chrome = true, browser.version = chrome[1];\n    if (firefox) {\n        browser.firefox = true;\n        browser.version = firefox[1];\n    }\n    // if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true;\n    // if (webview) browser.webview = true;\n\n    if (ie) {\n        browser.ie = true;\n        browser.version = ie[1];\n    }\n\n    if (edge) {\n        browser.edge = true;\n        browser.version = edge[1];\n    }\n\n    // It is difficult to detect WeChat in Win Phone precisely, because ua can\n    // not be set on win phone. So we do not consider Win Phone.\n    if (weChat) {\n        browser.weChat = true;\n    }\n\n    // os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) ||\n    //     (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/)));\n    // os.phone  = !!(!os.tablet && !os.ipod && (android || iphone || webos ||\n    //     (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\\/([\\d.]+)/)) ||\n    //     (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/))));\n\n    return {\n        browser: browser,\n        os: os,\n        node: false,\n        // 原生canvas支持，改极端点了\n        // canvasSupported : !(browser.ie && parseFloat(browser.version) < 9)\n        canvasSupported: !!document.createElement('canvas').getContext,\n        svgSupported: typeof SVGRect !== 'undefined',\n        // works on most browsers\n        // IE10/11 does not support touch event, and MS Edge supports them but not by\n        // default, so we dont check navigator.maxTouchPoints for them here.\n        touchEventsSupported: 'ontouchstart' in window && !browser.ie && !browser.edge,\n        // <http://caniuse.com/#search=pointer%20event>.\n        pointerEventsSupported: 'onpointerdown' in window\n            // Firefox supports pointer but not by default, only MS browsers are reliable on pointer\n            // events currently. So we dont use that on other browsers unless tested sufficiently.\n            // Although IE 10 supports pointer event, it use old style and is different from the\n            // standard. So we exclude that. (IE 10 is hardly used on touch device)\n            && (browser.edge || (browser.ie && browser.version >= 11)),\n        // passiveSupported: detectPassiveSupport()\n        domSupported: typeof document !== 'undefined'\n    };\n}\n\n// See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection\n// function detectPassiveSupport() {\n//     // Test via a getter in the options object to see if the passive property is accessed\n//     var supportsPassive = false;\n//     try {\n//         var opts = Object.defineProperty({}, 'passive', {\n//             get: function() {\n//                 supportsPassive = true;\n//             }\n//         });\n//         window.addEventListener('testPassive', function() {}, opts);\n//     } catch (e) {\n//     }\n//     return supportsPassive;\n// }\n\n/**\n * @module zrender/core/util\n */\n\n// 用于处理merge时无法遍历Date等对象的问题\nvar BUILTIN_OBJECT = {\n    '[object Function]': 1,\n    '[object RegExp]': 1,\n    '[object Date]': 1,\n    '[object Error]': 1,\n    '[object CanvasGradient]': 1,\n    '[object CanvasPattern]': 1,\n    // For node-canvas\n    '[object Image]': 1,\n    '[object Canvas]': 1\n};\n\nvar TYPED_ARRAY = {\n    '[object Int8Array]': 1,\n    '[object Uint8Array]': 1,\n    '[object Uint8ClampedArray]': 1,\n    '[object Int16Array]': 1,\n    '[object Uint16Array]': 1,\n    '[object Int32Array]': 1,\n    '[object Uint32Array]': 1,\n    '[object Float32Array]': 1,\n    '[object Float64Array]': 1\n};\n\nvar objToString = Object.prototype.toString;\n\nvar arrayProto = Array.prototype;\nvar nativeForEach = arrayProto.forEach;\nvar nativeFilter = arrayProto.filter;\nvar nativeSlice = arrayProto.slice;\nvar nativeMap = arrayProto.map;\nvar nativeReduce = arrayProto.reduce;\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar methods = {};\n\nfunction $override(name, fn) {\n    // Clear ctx instance for different environment\n    if (name === 'createCanvas') {\n        _ctx = null;\n    }\n\n    methods[name] = fn;\n}\n\n/**\n * Those data types can be cloned:\n *     Plain object, Array, TypedArray, number, string, null, undefined.\n * Those data types will be assgined using the orginal data:\n *     BUILTIN_OBJECT\n * Instance of user defined class will be cloned to a plain object, without\n * properties in prototype.\n * Other data types is not supported (not sure what will happen).\n *\n * Caution: do not support clone Date, for performance consideration.\n * (There might be a large number of date in `series.data`).\n * So date should not be modified in and out of echarts.\n *\n * @param {*} source\n * @return {*} new\n */\nfunction clone(source) {\n    if (source == null || typeof source !== 'object') {\n        return source;\n    }\n\n    var result = source;\n    var typeStr = objToString.call(source);\n\n    if (typeStr === '[object Array]') {\n        if (!isPrimitive(source)) {\n            result = [];\n            for (var i = 0, len = source.length; i < len; i++) {\n                result[i] = clone(source[i]);\n            }\n        }\n    }\n    else if (TYPED_ARRAY[typeStr]) {\n        if (!isPrimitive(source)) {\n            var Ctor = source.constructor;\n            if (source.constructor.from) {\n                result = Ctor.from(source);\n            }\n            else {\n                result = new Ctor(source.length);\n                for (var i = 0, len = source.length; i < len; i++) {\n                    result[i] = clone(source[i]);\n                }\n            }\n        }\n    }\n    else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) {\n        result = {};\n        for (var key in source) {\n            if (source.hasOwnProperty(key)) {\n                result[key] = clone(source[key]);\n            }\n        }\n    }\n\n    return result;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overwrite=false]\n */\nfunction merge(target, source, overwrite) {\n    // We should escapse that source is string\n    // and enter for ... in ...\n    if (!isObject$1(source) || !isObject$1(target)) {\n        return overwrite ? clone(source) : target;\n    }\n\n    for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n            var targetProp = target[key];\n            var sourceProp = source[key];\n\n            if (isObject$1(sourceProp)\n                && isObject$1(targetProp)\n                && !isArray(sourceProp)\n                && !isArray(targetProp)\n                && !isDom(sourceProp)\n                && !isDom(targetProp)\n                && !isBuiltInObject(sourceProp)\n                && !isBuiltInObject(targetProp)\n                && !isPrimitive(sourceProp)\n                && !isPrimitive(targetProp)\n            ) {\n                // 如果需要递归覆盖，就递归调用merge\n                merge(targetProp, sourceProp, overwrite);\n            }\n            else if (overwrite || !(key in target)) {\n                // 否则只处理overwrite为true，或者在目标对象中没有此属性的情况\n                // NOTE，在 target[key] 不存在的时候也是直接覆盖\n                target[key] = clone(source[key], true);\n            }\n        }\n    }\n\n    return target;\n}\n\n/**\n * @param {Array} targetAndSources The first item is target, and the rests are source.\n * @param {boolean} [overwrite=false]\n * @return {*} target\n */\nfunction mergeAll(targetAndSources, overwrite) {\n    var result = targetAndSources[0];\n    for (var i = 1, len = targetAndSources.length; i < len; i++) {\n        result = merge(result, targetAndSources[i], overwrite);\n    }\n    return result;\n}\n\n/**\n * @param {*} target\n * @param {*} source\n * @memberOf module:zrender/core/util\n */\nfunction extend(target, source) {\n    for (var key in source) {\n        if (source.hasOwnProperty(key)) {\n            target[key] = source[key];\n        }\n    }\n    return target;\n}\n\n/**\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overlay=false]\n * @memberOf module:zrender/core/util\n */\nfunction defaults(target, source, overlay) {\n    for (var key in source) {\n        if (source.hasOwnProperty(key)\n            && (overlay ? source[key] != null : target[key] == null)\n        ) {\n            target[key] = source[key];\n        }\n    }\n    return target;\n}\n\nvar createCanvas = function () {\n    return methods.createCanvas();\n};\n\nmethods.createCanvas = function () {\n    return document.createElement('canvas');\n};\n\n// FIXME\nvar _ctx;\n\nfunction getContext() {\n    if (!_ctx) {\n        // Use util.createCanvas instead of createCanvas\n        // because createCanvas may be overwritten in different environment\n        _ctx = createCanvas().getContext('2d');\n    }\n    return _ctx;\n}\n\n/**\n * 查询数组中元素的index\n * @memberOf module:zrender/core/util\n */\nfunction indexOf(array, value) {\n    if (array) {\n        if (array.indexOf) {\n            return array.indexOf(value);\n        }\n        for (var i = 0, len = array.length; i < len; i++) {\n            if (array[i] === value) {\n                return i;\n            }\n        }\n    }\n    return -1;\n}\n\n/**\n * 构造类继承关系\n *\n * @memberOf module:zrender/core/util\n * @param {Function} clazz 源类\n * @param {Function} baseClazz 基类\n */\nfunction inherits(clazz, baseClazz) {\n    var clazzPrototype = clazz.prototype;\n    function F() {}\n    F.prototype = baseClazz.prototype;\n    clazz.prototype = new F();\n\n    for (var prop in clazzPrototype) {\n        clazz.prototype[prop] = clazzPrototype[prop];\n    }\n    clazz.prototype.constructor = clazz;\n    clazz.superClass = baseClazz;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Object|Function} target\n * @param {Object|Function} sorce\n * @param {boolean} overlay\n */\nfunction mixin(target, source, overlay) {\n    target = 'prototype' in target ? target.prototype : target;\n    source = 'prototype' in source ? source.prototype : source;\n\n    defaults(target, source, overlay);\n}\n\n/**\n * Consider typed array.\n * @param {Array|TypedArray} data\n */\nfunction isArrayLike(data) {\n    if (!data) {\n        return;\n    }\n    if (typeof data === 'string') {\n        return false;\n    }\n    return typeof data.length === 'number';\n}\n\n/**\n * 数组或对象遍历\n * @memberOf module:zrender/core/util\n * @param {Object|Array} obj\n * @param {Function} cb\n * @param {*} [context]\n */\nfunction each$1(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.forEach && obj.forEach === nativeForEach) {\n        obj.forEach(cb, context);\n    }\n    else if (obj.length === +obj.length) {\n        for (var i = 0, len = obj.length; i < len; i++) {\n            cb.call(context, obj[i], i, obj);\n        }\n    }\n    else {\n        for (var key in obj) {\n            if (obj.hasOwnProperty(key)) {\n                cb.call(context, obj[key], key, obj);\n            }\n        }\n    }\n}\n\n/**\n * 数组映射\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction map(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.map && obj.map === nativeMap) {\n        return obj.map(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            result.push(cb.call(context, obj[i], i, obj));\n        }\n        return result;\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {Object} [memo]\n * @param {*} [context]\n * @return {Array}\n */\nfunction reduce(obj, cb, memo, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.reduce && obj.reduce === nativeReduce) {\n        return obj.reduce(cb, memo, context);\n    }\n    else {\n        for (var i = 0, len = obj.length; i < len; i++) {\n            memo = cb.call(context, memo, obj[i], i, obj);\n        }\n        return memo;\n    }\n}\n\n/**\n * 数组过滤\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction filter(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.filter && obj.filter === nativeFilter) {\n        return obj.filter(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            if (cb.call(context, obj[i], i, obj)) {\n                result.push(obj[i]);\n            }\n        }\n        return result;\n    }\n}\n\n/**\n * 数组项查找\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {*}\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @param {*} context\n * @return {Function}\n */\nfunction bind(func, context) {\n    var args = nativeSlice.call(arguments, 2);\n    return function () {\n        return func.apply(context, args.concat(nativeSlice.call(arguments)));\n    };\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @return {Function}\n */\nfunction curry(func) {\n    var args = nativeSlice.call(arguments, 1);\n    return function () {\n        return func.apply(this, args.concat(nativeSlice.call(arguments)));\n    };\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isArray(value) {\n    return objToString.call(value) === '[object Array]';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isFunction$1(value) {\n    return typeof value === 'function';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isString(value) {\n    return objToString.call(value) === '[object String]';\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isObject$1(value) {\n    // Avoid a V8 JIT bug in Chrome 19-20.\n    // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.\n    var type = typeof value;\n    return type === 'function' || (!!value && type === 'object');\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isBuiltInObject(value) {\n    return !!BUILTIN_OBJECT[objToString.call(value)];\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isTypedArray(value) {\n    return !!TYPED_ARRAY[objToString.call(value)];\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\nfunction isDom(value) {\n    return typeof value === 'object'\n        && typeof value.nodeType === 'number'\n        && typeof value.ownerDocument === 'object';\n}\n\n/**\n * Whether is exactly NaN. Notice isNaN('a') returns true.\n * @param {*} value\n * @return {boolean}\n */\nfunction eqNaN(value) {\n    return value !== value;\n}\n\n/**\n * If value1 is not null, then return value1, otherwise judget rest of values.\n * Low performance.\n * @memberOf module:zrender/core/util\n * @return {*} Final value\n */\nfunction retrieve(values) {\n    for (var i = 0, len = arguments.length; i < len; i++) {\n        if (arguments[i] != null) {\n            return arguments[i];\n        }\n    }\n}\n\nfunction retrieve2(value0, value1) {\n    return value0 != null\n        ? value0\n        : value1;\n}\n\nfunction retrieve3(value0, value1, value2) {\n    return value0 != null\n        ? value0\n        : value1 != null\n        ? value1\n        : value2;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} arr\n * @param {number} startIndex\n * @param {number} endIndex\n * @return {Array}\n */\nfunction slice() {\n    return Function.call.apply(nativeSlice, arguments);\n}\n\n/**\n * Normalize css liked array configuration\n * e.g.\n *  3 => [3, 3, 3, 3]\n *  [4, 2] => [4, 2, 4, 2]\n *  [4, 3, 2] => [4, 3, 2, 3]\n * @param {number|Array.<number>} val\n * @return {Array.<number>}\n */\nfunction normalizeCssArray(val) {\n    if (typeof (val) === 'number') {\n        return [val, val, val, val];\n    }\n    var len = val.length;\n    if (len === 2) {\n        // vertical | horizontal\n        return [val[0], val[1], val[0], val[1]];\n    }\n    else if (len === 3) {\n        // top | horizontal | bottom\n        return [val[0], val[1], val[2], val[1]];\n    }\n    return val;\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {boolean} condition\n * @param {string} message\n */\nfunction assert$1(condition, message) {\n    if (!condition) {\n        throw new Error(message);\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {string} str string to be trimed\n * @return {string} trimed string\n */\nfunction trim(str) {\n    if (str == null) {\n        return null;\n    }\n    else if (typeof str.trim === 'function') {\n        return str.trim();\n    }\n    else {\n        return str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n    }\n}\n\nvar primitiveKey = '__ec_primitive__';\n/**\n * Set an object as primitive to be ignored traversing children in clone or merge\n */\nfunction setAsPrimitive(obj) {\n    obj[primitiveKey] = true;\n}\n\nfunction isPrimitive(obj) {\n    return obj[primitiveKey];\n}\n\n/**\n * @constructor\n * @param {Object} obj Only apply `ownProperty`.\n */\nfunction HashMap(obj) {\n    var isArr = isArray(obj);\n    // Key should not be set on this, otherwise\n    // methods get/set/... may be overrided.\n    this.data = {};\n    var thisMap = this;\n\n    (obj instanceof HashMap)\n        ? obj.each(visit)\n        : (obj && each$1(obj, visit));\n\n    function visit(value, key) {\n        isArr ? thisMap.set(value, key) : thisMap.set(key, value);\n    }\n}\n\nHashMap.prototype = {\n    constructor: HashMap,\n    // Do not provide `has` method to avoid defining what is `has`.\n    // (We usually treat `null` and `undefined` as the same, different\n    // from ES6 Map).\n    get: function (key) {\n        return this.data.hasOwnProperty(key) ? this.data[key] : null;\n    },\n    set: function (key, value) {\n        // Comparing with invocation chaining, `return value` is more commonly\n        // used in this case: `var someVal = map.set('a', genVal());`\n        return (this.data[key] = value);\n    },\n    // Although util.each can be performed on this hashMap directly, user\n    // should not use the exposed keys, who are prefixed.\n    each: function (cb, context) {\n        context !== void 0 && (cb = bind(cb, context));\n        for (var key in this.data) {\n            this.data.hasOwnProperty(key) && cb(this.data[key], key);\n        }\n    },\n    // Do not use this method if performance sensitive.\n    removeKey: function (key) {\n        delete this.data[key];\n    }\n};\n\nfunction createHashMap(obj) {\n    return new HashMap(obj);\n}\n\n\n\n\nfunction noop() {}\n\nvar ArrayCtor = typeof Float32Array === 'undefined'\n    ? Array\n    : Float32Array;\n\n/**\n * 创建一个向量\n * @param {number} [x=0]\n * @param {number} [y=0]\n * @return {Vector2}\n */\nfunction create(x, y) {\n    var out = new ArrayCtor(2);\n    if (x == null) {\n        x = 0;\n    }\n    if (y == null) {\n        y = 0;\n    }\n    out[0] = x;\n    out[1] = y;\n    return out;\n}\n\n/**\n * 复制向量数据\n * @param {Vector2} out\n * @param {Vector2} v\n * @return {Vector2}\n */\nfunction copy(out, v) {\n    out[0] = v[0];\n    out[1] = v[1];\n    return out;\n}\n\n/**\n * 克隆一个向量\n * @param {Vector2} v\n * @return {Vector2}\n */\nfunction clone$1(v) {\n    var out = new ArrayCtor(2);\n    out[0] = v[0];\n    out[1] = v[1];\n    return out;\n}\n\n/**\n * 设置向量的两个项\n * @param {Vector2} out\n * @param {number} a\n * @param {number} b\n * @return {Vector2} 结果\n */\n\n\n/**\n * 向量相加\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction add(out, v1, v2) {\n    out[0] = v1[0] + v2[0];\n    out[1] = v1[1] + v2[1];\n    return out;\n}\n\n/**\n * 向量缩放后相加\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @param {number} a\n */\nfunction scaleAndAdd(out, v1, v2, a) {\n    out[0] = v1[0] + v2[0] * a;\n    out[1] = v1[1] + v2[1] * a;\n    return out;\n}\n\n/**\n * 向量相减\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\nfunction sub(out, v1, v2) {\n    out[0] = v1[0] - v2[0];\n    out[1] = v1[1] - v2[1];\n    return out;\n}\n\n/**\n * 向量长度\n * @param {Vector2} v\n * @return {number}\n */\nfunction len(v) {\n    return Math.sqrt(lenSquare(v));\n}\n // jshint ignore:line\n\n/**\n * 向量长度平方\n * @param {Vector2} v\n * @return {number}\n */\nfunction lenSquare(v) {\n    return v[0] * v[0] + v[1] * v[1];\n}\n\n\n/**\n * 向量乘法\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\n\n\n/**\n * 向量除法\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n */\n\n\n/**\n * 向量点乘\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\n\n\n/**\n * 向量缩放\n * @param {Vector2} out\n * @param {Vector2} v\n * @param {number} s\n */\nfunction scale(out, v, s) {\n    out[0] = v[0] * s;\n    out[1] = v[1] * s;\n    return out;\n}\n\n/**\n * 向量归一化\n * @param {Vector2} out\n * @param {Vector2} v\n */\nfunction normalize(out, v) {\n    var d = len(v);\n    if (d === 0) {\n        out[0] = 0;\n        out[1] = 0;\n    }\n    else {\n        out[0] = v[0] / d;\n        out[1] = v[1] / d;\n    }\n    return out;\n}\n\n/**\n * 计算向量间距离\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction distance(v1, v2) {\n    return Math.sqrt(\n        (v1[0] - v2[0]) * (v1[0] - v2[0])\n        + (v1[1] - v2[1]) * (v1[1] - v2[1])\n    );\n}\nvar dist = distance;\n\n/**\n * 向量距离平方\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @return {number}\n */\nfunction distanceSquare(v1, v2) {\n    return (v1[0] - v2[0]) * (v1[0] - v2[0])\n        + (v1[1] - v2[1]) * (v1[1] - v2[1]);\n}\nvar distSquare = distanceSquare;\n\n/**\n * 求负向量\n * @param {Vector2} out\n * @param {Vector2} v\n */\n\n\n/**\n * 插值两个点\n * @param {Vector2} out\n * @param {Vector2} v1\n * @param {Vector2} v2\n * @param {number} t\n */\n\n\n/**\n * 矩阵左乘向量\n * @param {Vector2} out\n * @param {Vector2} v\n * @param {Vector2} m\n */\nfunction applyTransform(out, v, m) {\n    var x = v[0];\n    var y = v[1];\n    out[0] = m[0] * x + m[2] * y + m[4];\n    out[1] = m[1] * x + m[3] * y + m[5];\n    return out;\n}\n\n/**\n * 求两个向量最小值\n * @param  {Vector2} out\n * @param  {Vector2} v1\n * @param  {Vector2} v2\n */\nfunction min(out, v1, v2) {\n    out[0] = Math.min(v1[0], v2[0]);\n    out[1] = Math.min(v1[1], v2[1]);\n    return out;\n}\n\n/**\n * 求两个向量最大值\n * @param  {Vector2} out\n * @param  {Vector2} v1\n * @param  {Vector2} v2\n */\nfunction max(out, v1, v2) {\n    out[0] = Math.max(v1[0], v2[0]);\n    out[1] = Math.max(v1[1], v2[1]);\n    return out;\n}\n\n// TODO Draggable for group\n// FIXME Draggable on element which has parent rotation or scale\nfunction Draggable() {\n\n    this.on('mousedown', this._dragStart, this);\n    this.on('mousemove', this._drag, this);\n    this.on('mouseup', this._dragEnd, this);\n    this.on('globalout', this._dragEnd, this);\n    // this._dropTarget = null;\n    // this._draggingTarget = null;\n\n    // this._x = 0;\n    // this._y = 0;\n}\n\nDraggable.prototype = {\n\n    constructor: Draggable,\n\n    _dragStart: function (e) {\n        var draggingTarget = e.target;\n        if (draggingTarget && draggingTarget.draggable) {\n            this._draggingTarget = draggingTarget;\n            draggingTarget.dragging = true;\n            this._x = e.offsetX;\n            this._y = e.offsetY;\n\n            this.dispatchToElement(param(draggingTarget, e), 'dragstart', e.event);\n        }\n    },\n\n    _drag: function (e) {\n        var draggingTarget = this._draggingTarget;\n        if (draggingTarget) {\n\n            var x = e.offsetX;\n            var y = e.offsetY;\n\n            var dx = x - this._x;\n            var dy = y - this._y;\n            this._x = x;\n            this._y = y;\n\n            draggingTarget.drift(dx, dy, e);\n            this.dispatchToElement(param(draggingTarget, e), 'drag', e.event);\n\n            var dropTarget = this.findHover(x, y, draggingTarget).target;\n            var lastDropTarget = this._dropTarget;\n            this._dropTarget = dropTarget;\n\n            if (draggingTarget !== dropTarget) {\n                if (lastDropTarget && dropTarget !== lastDropTarget) {\n                    this.dispatchToElement(param(lastDropTarget, e), 'dragleave', e.event);\n                }\n                if (dropTarget && dropTarget !== lastDropTarget) {\n                    this.dispatchToElement(param(dropTarget, e), 'dragenter', e.event);\n                }\n            }\n        }\n    },\n\n    _dragEnd: function (e) {\n        var draggingTarget = this._draggingTarget;\n\n        if (draggingTarget) {\n            draggingTarget.dragging = false;\n        }\n\n        this.dispatchToElement(param(draggingTarget, e), 'dragend', e.event);\n\n        if (this._dropTarget) {\n            this.dispatchToElement(param(this._dropTarget, e), 'drop', e.event);\n        }\n\n        this._draggingTarget = null;\n        this._dropTarget = null;\n    }\n\n};\n\nfunction param(target, e) {\n    return {target: target, topTarget: e && e.topTarget};\n}\n\n/**\n * Event Mixin\n * @module zrender/mixin/Eventful\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         pissang (https://www.github.com/pissang)\n */\n\nvar arrySlice = Array.prototype.slice;\n\n/**\n * Event dispatcher.\n *\n * @alias module:zrender/mixin/Eventful\n * @constructor\n * @param {Object} [eventProcessor] The object eventProcessor is the scope when\n *        `eventProcessor.xxx` called.\n * @param {Function} [eventProcessor.normalizeQuery]\n *        param: {string|Object} Raw query.\n *        return: {string|Object} Normalized query.\n * @param {Function} [eventProcessor.filter] Event will be dispatched only\n *        if it returns `true`.\n *        param: {string} eventType\n *        param: {string|Object} query\n *        return: {boolean}\n * @param {Function} [eventProcessor.afterTrigger] Call after all handlers called.\n *        param: {string} eventType\n */\nvar Eventful = function (eventProcessor) {\n    this._$handlers = {};\n    this._$eventProcessor = eventProcessor;\n};\n\nEventful.prototype = {\n\n    constructor: Eventful,\n\n    /**\n     * The handler can only be triggered once, then removed.\n     *\n     * @param {string} event The event name.\n     * @param {string|Object} [query] Condition used on event filter.\n     * @param {Function} handler The event handler.\n     * @param {Object} context\n     */\n    one: function (event, query, handler, context) {\n        return on(this, event, query, handler, context, true);\n    },\n\n    /**\n     * Bind a handler.\n     *\n     * @param {string} event The event name.\n     * @param {string|Object} [query] Condition used on event filter.\n     * @param {Function} handler The event handler.\n     * @param {Object} [context]\n     */\n    on: function (event, query, handler, context) {\n        return on(this, event, query, handler, context, false);\n    },\n\n    /**\n     * Whether any handler has bound.\n     *\n     * @param  {string}  event\n     * @return {boolean}\n     */\n    isSilent: function (event) {\n        var _h = this._$handlers;\n        return !_h[event] || !_h[event].length;\n    },\n\n    /**\n     * Unbind a event.\n     *\n     * @param {string} event The event name.\n     * @param {Function} [handler] The event handler.\n     */\n    off: function (event, handler) {\n        var _h = this._$handlers;\n\n        if (!event) {\n            this._$handlers = {};\n            return this;\n        }\n\n        if (handler) {\n            if (_h[event]) {\n                var newList = [];\n                for (var i = 0, l = _h[event].length; i < l; i++) {\n                    if (_h[event][i].h !== handler) {\n                        newList.push(_h[event][i]);\n                    }\n                }\n                _h[event] = newList;\n            }\n\n            if (_h[event] && _h[event].length === 0) {\n                delete _h[event];\n            }\n        }\n        else {\n            delete _h[event];\n        }\n\n        return this;\n    },\n\n    /**\n     * Dispatch a event.\n     *\n     * @param {string} type The event name.\n     */\n    trigger: function (type) {\n        var _h = this._$handlers[type];\n        var eventProcessor = this._$eventProcessor;\n\n        if (_h) {\n            var args = arguments;\n            var argLen = args.length;\n\n            if (argLen > 3) {\n                args = arrySlice.call(args, 1);\n            }\n\n            var len = _h.length;\n            for (var i = 0; i < len;) {\n                var hItem = _h[i];\n                if (eventProcessor\n                    && eventProcessor.filter\n                    && hItem.query != null\n                    && !eventProcessor.filter(type, hItem.query)\n                ) {\n                    i++;\n                    continue;\n                }\n\n                // Optimize advise from backbone\n                switch (argLen) {\n                    case 1:\n                        hItem.h.call(hItem.ctx);\n                        break;\n                    case 2:\n                        hItem.h.call(hItem.ctx, args[1]);\n                        break;\n                    case 3:\n                        hItem.h.call(hItem.ctx, args[1], args[2]);\n                        break;\n                    default:\n                        // have more than 2 given arguments\n                        hItem.h.apply(hItem.ctx, args);\n                        break;\n                }\n\n                if (hItem.one) {\n                    _h.splice(i, 1);\n                    len--;\n                }\n                else {\n                    i++;\n                }\n            }\n        }\n\n        eventProcessor && eventProcessor.afterTrigger\n            && eventProcessor.afterTrigger(type);\n\n        return this;\n    },\n\n    /**\n     * Dispatch a event with context, which is specified at the last parameter.\n     *\n     * @param {string} type The event name.\n     */\n    triggerWithContext: function (type) {\n        var _h = this._$handlers[type];\n        var eventProcessor = this._$eventProcessor;\n\n        if (_h) {\n            var args = arguments;\n            var argLen = args.length;\n\n            if (argLen > 4) {\n                args = arrySlice.call(args, 1, args.length - 1);\n            }\n            var ctx = args[args.length - 1];\n\n            var len = _h.length;\n            for (var i = 0; i < len;) {\n                var hItem = _h[i];\n                if (eventProcessor\n                    && eventProcessor.filter\n                    && hItem.query != null\n                    && !eventProcessor.filter(type, hItem.query)\n                ) {\n                    i++;\n                    continue;\n                }\n\n                // Optimize advise from backbone\n                switch (argLen) {\n                    case 1:\n                        hItem.h.call(ctx);\n                        break;\n                    case 2:\n                        hItem.h.call(ctx, args[1]);\n                        break;\n                    case 3:\n                        hItem.h.call(ctx, args[1], args[2]);\n                        break;\n                    default:\n                        // have more than 2 given arguments\n                        hItem.h.apply(ctx, args);\n                        break;\n                }\n\n                if (hItem.one) {\n                    _h.splice(i, 1);\n                    len--;\n                }\n                else {\n                    i++;\n                }\n            }\n        }\n\n        eventProcessor && eventProcessor.afterTrigger\n            && eventProcessor.afterTrigger(type);\n\n        return this;\n    }\n};\n\nfunction normalizeQuery(host, query) {\n    var eventProcessor = host._$eventProcessor;\n    if (query != null && eventProcessor && eventProcessor.normalizeQuery) {\n        query = eventProcessor.normalizeQuery(query);\n    }\n    return query;\n}\n\nfunction on(eventful, event, query, handler, context, isOnce) {\n    var _h = eventful._$handlers;\n\n    if (typeof query === 'function') {\n        context = handler;\n        handler = query;\n        query = null;\n    }\n\n    if (!handler || !event) {\n        return eventful;\n    }\n\n    query = normalizeQuery(eventful, query);\n\n    if (!_h[event]) {\n        _h[event] = [];\n    }\n\n    for (var i = 0; i < _h[event].length; i++) {\n        if (_h[event][i].h === handler) {\n            return eventful;\n        }\n    }\n\n    var wrap = {\n        h: handler,\n        one: isOnce,\n        query: query,\n        ctx: context || eventful,\n        // FIXME\n        // Do not publish this feature util it is proved that it makes sense.\n        callAtLast: handler.zrEventfulCallAtLast\n    };\n\n    var lastIndex = _h[event].length - 1;\n    var lastWrap = _h[event][lastIndex];\n    (lastWrap && lastWrap.callAtLast)\n        ? _h[event].splice(lastIndex, 0, wrap)\n        : _h[event].push(wrap);\n\n    return eventful;\n}\n\n/**\n * 事件辅助类\n * @module zrender/core/event\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n */\n\nvar isDomLevel2 = (typeof window !== 'undefined') && !!window.addEventListener;\n\nvar MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;\n\nfunction getBoundingClientRect(el) {\n    // BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect\n    return el.getBoundingClientRect ? el.getBoundingClientRect() : {left: 0, top: 0};\n}\n\n// `calculate` is optional, default false\nfunction clientToLocal(el, e, out, calculate) {\n    out = out || {};\n\n    // According to the W3C Working Draft, offsetX and offsetY should be relative\n    // to the padding edge of the target element. The only browser using this convention\n    // is IE. Webkit uses the border edge, Opera uses the content edge, and FireFox does\n    // not support the properties.\n    // (see http://www.jacklmoore.com/notes/mouse-position/)\n    // In zr painter.dom, padding edge equals to border edge.\n\n    // FIXME\n    // When mousemove event triggered on ec tooltip, target is not zr painter.dom, and\n    // offsetX/Y is relative to e.target, where the calculation of zrX/Y via offsetX/Y\n    // is too complex. So css-transfrom dont support in this case temporarily.\n    if (calculate || !env$1.canvasSupported) {\n        defaultGetZrXY(el, e, out);\n    }\n    // Caution: In FireFox, layerX/layerY Mouse position relative to the closest positioned\n    // ancestor element, so we should make sure el is positioned (e.g., not position:static).\n    // BTW1, Webkit don't return the same results as FF in non-simple cases (like add\n    // zoom-factor, overflow / opacity layers, transforms ...)\n    // BTW2, (ev.offsetY || ev.pageY - $(ev.target).offset().top) is not correct in preserve-3d.\n    // <https://bugs.jquery.com/ticket/8523#comment:14>\n    // BTW3, In ff, offsetX/offsetY is always 0.\n    else if (env$1.browser.firefox && e.layerX != null && e.layerX !== e.offsetX) {\n        out.zrX = e.layerX;\n        out.zrY = e.layerY;\n    }\n    // For IE6+, chrome, safari, opera. (When will ff support offsetX?)\n    else if (e.offsetX != null) {\n        out.zrX = e.offsetX;\n        out.zrY = e.offsetY;\n    }\n    // For some other device, e.g., IOS safari.\n    else {\n        defaultGetZrXY(el, e, out);\n    }\n\n    return out;\n}\n\nfunction defaultGetZrXY(el, e, out) {\n    // This well-known method below does not support css transform.\n    var box = getBoundingClientRect(el);\n    out.zrX = e.clientX - box.left;\n    out.zrY = e.clientY - box.top;\n}\n\n/**\n * 如果存在第三方嵌入的一些dom触发的事件，或touch事件，需要转换一下事件坐标.\n * `calculate` is optional, default false.\n */\nfunction normalizeEvent(el, e, calculate) {\n\n    e = e || window.event;\n\n    if (e.zrX != null) {\n        return e;\n    }\n\n    var eventType = e.type;\n    var isTouch = eventType && eventType.indexOf('touch') >= 0;\n\n    if (!isTouch) {\n        clientToLocal(el, e, e, calculate);\n        e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3;\n    }\n    else {\n        var touch = eventType !== 'touchend'\n            ? e.targetTouches[0]\n            : e.changedTouches[0];\n        touch && clientToLocal(el, touch, e, calculate);\n    }\n\n    // Add which for click: 1 === left; 2 === middle; 3 === right; otherwise: 0;\n    // See jQuery: https://github.com/jquery/jquery/blob/master/src/event.js\n    // If e.which has been defined, if may be readonly,\n    // see: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/which\n    var button = e.button;\n    if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) {\n        e.which = (button & 1 ? 1 : (button & 2 ? 3 : (button & 4 ? 2 : 0)));\n    }\n    // [Caution]: `e.which` from browser is not always reliable. For example,\n    // when press left button and `mousemove (pointermove)` in Edge, the `e.which`\n    // is 65536 and the `e.button` is -1. But the `mouseup (pointerup)` and\n    // `mousedown (pointerdown)` is the same as Chrome does.\n\n    return e;\n}\n\n/**\n * @param {HTMLElement} el\n * @param {string} name\n * @param {Function} handler\n */\nfunction addEventListener(el, name, handler) {\n    if (isDomLevel2) {\n        // Reproduct the console warning:\n        // [Violation] Added non-passive event listener to a scroll-blocking <some> event.\n        // Consider marking event handler as 'passive' to make the page more responsive.\n        // Just set console log level: verbose in chrome dev tool.\n        // then the warning log will be printed when addEventListener called.\n        // See https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md\n        // We have not yet found a neat way to using passive. Because in zrender the dom event\n        // listener delegate all of the upper events of element. Some of those events need\n        // to prevent default. For example, the feature `preventDefaultMouseMove` of echarts.\n        // Before passive can be adopted, these issues should be considered:\n        // (1) Whether and how a zrender user specifies an event listener passive. And by default,\n        // passive or not.\n        // (2) How to tread that some zrender event listener is passive, and some is not. If\n        // we use other way but not preventDefault of mousewheel and touchmove, browser\n        // compatibility should be handled.\n\n        // var opts = (env.passiveSupported && name === 'mousewheel')\n        //     ? {passive: true}\n        //     // By default, the third param of el.addEventListener is `capture: false`.\n        //     : void 0;\n        // el.addEventListener(name, handler /* , opts */);\n        el.addEventListener(name, handler);\n    }\n    else {\n        el.attachEvent('on' + name, handler);\n    }\n}\n\nfunction removeEventListener(el, name, handler) {\n    if (isDomLevel2) {\n        el.removeEventListener(name, handler);\n    }\n    else {\n        el.detachEvent('on' + name, handler);\n    }\n}\n\n/**\n * preventDefault and stopPropagation.\n * Notice: do not do that in zrender. Upper application\n * do that if necessary.\n *\n * @memberOf module:zrender/core/event\n * @method\n * @param {Event} e : event对象\n */\nvar stop = isDomLevel2\n    ? function (e) {\n        e.preventDefault();\n        e.stopPropagation();\n        e.cancelBubble = true;\n    }\n    : function (e) {\n        e.returnValue = false;\n        e.cancelBubble = true;\n    };\n\n/**\n * This method only works for mouseup and mousedown. The functionality is restricted\n * for fault tolerance, See the `e.which` compatibility above.\n *\n * @param {MouseEvent} e\n * @return {boolean}\n */\n\n\n/**\n * To be removed.\n * @deprecated\n */\n\n/**\n * Only implements needed gestures for mobile.\n */\n\nvar GestureMgr = function () {\n\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    this._track = [];\n};\n\nGestureMgr.prototype = {\n\n    constructor: GestureMgr,\n\n    recognize: function (event, target, root) {\n        this._doTrack(event, target, root);\n        return this._recognize(event);\n    },\n\n    clear: function () {\n        this._track.length = 0;\n        return this;\n    },\n\n    _doTrack: function (event, target, root) {\n        var touches = event.touches;\n\n        if (!touches) {\n            return;\n        }\n\n        var trackItem = {\n            points: [],\n            touches: [],\n            target: target,\n            event: event\n        };\n\n        for (var i = 0, len = touches.length; i < len; i++) {\n            var touch = touches[i];\n            var pos = clientToLocal(root, touch, {});\n            trackItem.points.push([pos.zrX, pos.zrY]);\n            trackItem.touches.push(touch);\n        }\n\n        this._track.push(trackItem);\n    },\n\n    _recognize: function (event) {\n        for (var eventName in recognizers) {\n            if (recognizers.hasOwnProperty(eventName)) {\n                var gestureInfo = recognizers[eventName](this._track, event);\n                if (gestureInfo) {\n                    return gestureInfo;\n                }\n            }\n        }\n    }\n};\n\nfunction dist$1(pointPair) {\n    var dx = pointPair[1][0] - pointPair[0][0];\n    var dy = pointPair[1][1] - pointPair[0][1];\n\n    return Math.sqrt(dx * dx + dy * dy);\n}\n\nfunction center(pointPair) {\n    return [\n        (pointPair[0][0] + pointPair[1][0]) / 2,\n        (pointPair[0][1] + pointPair[1][1]) / 2\n    ];\n}\n\nvar recognizers = {\n\n    pinch: function (track, event) {\n        var trackLen = track.length;\n\n        if (!trackLen) {\n            return;\n        }\n\n        var pinchEnd = (track[trackLen - 1] || {}).points;\n        var pinchPre = (track[trackLen - 2] || {}).points || pinchEnd;\n\n        if (pinchPre\n            && pinchPre.length > 1\n            && pinchEnd\n            && pinchEnd.length > 1\n        ) {\n            var pinchScale = dist$1(pinchEnd) / dist$1(pinchPre);\n            !isFinite(pinchScale) && (pinchScale = 1);\n\n            event.pinchScale = pinchScale;\n\n            var pinchCenter = center(pinchEnd);\n            event.pinchX = pinchCenter[0];\n            event.pinchY = pinchCenter[1];\n\n            return {\n                type: 'pinch',\n                target: track[0].target,\n                event: event\n            };\n        }\n    }\n\n    // Only pinch currently.\n};\n\nvar SILENT = 'silent';\n\nfunction makeEventPacket(eveType, targetInfo, event) {\n    return {\n        type: eveType,\n        event: event,\n        // target can only be an element that is not silent.\n        target: targetInfo.target,\n        // topTarget can be a silent element.\n        topTarget: targetInfo.topTarget,\n        cancelBubble: false,\n        offsetX: event.zrX,\n        offsetY: event.zrY,\n        gestureEvent: event.gestureEvent,\n        pinchX: event.pinchX,\n        pinchY: event.pinchY,\n        pinchScale: event.pinchScale,\n        wheelDelta: event.zrDelta,\n        zrByTouch: event.zrByTouch,\n        which: event.which,\n        stop: stopEvent\n    };\n}\n\nfunction stopEvent(event) {\n    stop(this.event);\n}\n\nfunction EmptyProxy() {}\nEmptyProxy.prototype.dispose = function () {};\n\nvar handlerNames = [\n    'click', 'dblclick', 'mousewheel', 'mouseout',\n    'mouseup', 'mousedown', 'mousemove', 'contextmenu'\n];\n/**\n * @alias module:zrender/Handler\n * @constructor\n * @extends module:zrender/mixin/Eventful\n * @param {module:zrender/Storage} storage Storage instance.\n * @param {module:zrender/Painter} painter Painter instance.\n * @param {module:zrender/dom/HandlerProxy} proxy HandlerProxy instance.\n * @param {HTMLElement} painterRoot painter.root (not painter.getViewportRoot()).\n */\nvar Handler = function (storage, painter, proxy, painterRoot) {\n    Eventful.call(this);\n\n    this.storage = storage;\n\n    this.painter = painter;\n\n    this.painterRoot = painterRoot;\n\n    proxy = proxy || new EmptyProxy();\n\n    /**\n     * Proxy of event. can be Dom, WebGLSurface, etc.\n     */\n    this.proxy = null;\n\n    /**\n     * {target, topTarget, x, y}\n     * @private\n     * @type {Object}\n     */\n    this._hovered = {};\n\n    /**\n     * @private\n     * @type {Date}\n     */\n    this._lastTouchMoment;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._lastX;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._lastY;\n\n    /**\n     * @private\n     * @type {module:zrender/core/GestureMgr}\n     */\n    this._gestureMgr;\n\n\n    Draggable.call(this);\n\n    this.setHandlerProxy(proxy);\n};\n\nHandler.prototype = {\n\n    constructor: Handler,\n\n    setHandlerProxy: function (proxy) {\n        if (this.proxy) {\n            this.proxy.dispose();\n        }\n\n        if (proxy) {\n            each$1(handlerNames, function (name) {\n                proxy.on && proxy.on(name, this[name], this);\n            }, this);\n            // Attach handler\n            proxy.handler = this;\n        }\n        this.proxy = proxy;\n    },\n\n    mousemove: function (event) {\n        var x = event.zrX;\n        var y = event.zrY;\n\n        var lastHovered = this._hovered;\n        var lastHoveredTarget = lastHovered.target;\n\n        // If lastHoveredTarget is removed from zr (detected by '__zr') by some API call\n        // (like 'setOption' or 'dispatchAction') in event handlers, we should find\n        // lastHovered again here. Otherwise 'mouseout' can not be triggered normally.\n        // See #6198.\n        if (lastHoveredTarget && !lastHoveredTarget.__zr) {\n            lastHovered = this.findHover(lastHovered.x, lastHovered.y);\n            lastHoveredTarget = lastHovered.target;\n        }\n\n        var hovered = this._hovered = this.findHover(x, y);\n        var hoveredTarget = hovered.target;\n\n        var proxy = this.proxy;\n        proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default');\n\n        // Mouse out on previous hovered element\n        if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget) {\n            this.dispatchToElement(lastHovered, 'mouseout', event);\n        }\n\n        // Mouse moving on one element\n        this.dispatchToElement(hovered, 'mousemove', event);\n\n        // Mouse over on a new element\n        if (hoveredTarget && hoveredTarget !== lastHoveredTarget) {\n            this.dispatchToElement(hovered, 'mouseover', event);\n        }\n    },\n\n    mouseout: function (event) {\n        this.dispatchToElement(this._hovered, 'mouseout', event);\n\n        // There might be some doms created by upper layer application\n        // at the same level of painter.getViewportRoot() (e.g., tooltip\n        // dom created by echarts), where 'globalout' event should not\n        // be triggered when mouse enters these doms. (But 'mouseout'\n        // should be triggered at the original hovered element as usual).\n        var element = event.toElement || event.relatedTarget;\n        var innerDom;\n        do {\n            element = element && element.parentNode;\n        }\n        while (element && element.nodeType !== 9 && !(\n            innerDom = element === this.painterRoot\n        ));\n\n        !innerDom && this.trigger('globalout', {event: event});\n    },\n\n    /**\n     * Resize\n     */\n    resize: function (event) {\n        this._hovered = {};\n    },\n\n    /**\n     * Dispatch event\n     * @param {string} eventName\n     * @param {event=} eventArgs\n     */\n    dispatch: function (eventName, eventArgs) {\n        var handler = this[eventName];\n        handler && handler.call(this, eventArgs);\n    },\n\n    /**\n     * Dispose\n     */\n    dispose: function () {\n\n        this.proxy.dispose();\n\n        this.storage =\n        this.proxy =\n        this.painter = null;\n    },\n\n    /**\n     * 设置默认的cursor style\n     * @param {string} [cursorStyle='default'] 例如 crosshair\n     */\n    setCursorStyle: function (cursorStyle) {\n        var proxy = this.proxy;\n        proxy.setCursor && proxy.setCursor(cursorStyle);\n    },\n\n    /**\n     * 事件分发代理\n     *\n     * @private\n     * @param {Object} targetInfo {target, topTarget} 目标图形元素\n     * @param {string} eventName 事件名称\n     * @param {Object} event 事件对象\n     */\n    dispatchToElement: function (targetInfo, eventName, event) {\n        targetInfo = targetInfo || {};\n        var el = targetInfo.target;\n        if (el && el.silent) {\n            return;\n        }\n        var eventHandler = 'on' + eventName;\n        var eventPacket = makeEventPacket(eventName, targetInfo, event);\n\n        while (el) {\n            el[eventHandler]\n                && (eventPacket.cancelBubble = el[eventHandler].call(el, eventPacket));\n\n            el.trigger(eventName, eventPacket);\n\n            el = el.parent;\n\n            if (eventPacket.cancelBubble) {\n                break;\n            }\n        }\n\n        if (!eventPacket.cancelBubble) {\n            // 冒泡到顶级 zrender 对象\n            this.trigger(eventName, eventPacket);\n            // 分发事件到用户自定义层\n            // 用户有可能在全局 click 事件中 dispose，所以需要判断下 painter 是否存在\n            this.painter && this.painter.eachOtherLayer(function (layer) {\n                if (typeof (layer[eventHandler]) === 'function') {\n                    layer[eventHandler].call(layer, eventPacket);\n                }\n                if (layer.trigger) {\n                    layer.trigger(eventName, eventPacket);\n                }\n            });\n        }\n    },\n\n    /**\n     * @private\n     * @param {number} x\n     * @param {number} y\n     * @param {module:zrender/graphic/Displayable} exclude\n     * @return {model:zrender/Element}\n     * @method\n     */\n    findHover: function (x, y, exclude) {\n        var list = this.storage.getDisplayList();\n        var out = {x: x, y: y};\n\n        for (var i = list.length - 1; i >= 0; i--) {\n            var hoverCheckResult;\n            if (list[i] !== exclude\n                // getDisplayList may include ignored item in VML mode\n                && !list[i].ignore\n                && (hoverCheckResult = isHover(list[i], x, y))\n            ) {\n                !out.topTarget && (out.topTarget = list[i]);\n                if (hoverCheckResult !== SILENT) {\n                    out.target = list[i];\n                    break;\n                }\n            }\n        }\n\n        return out;\n    },\n\n    processGesture: function (event, stage) {\n        if (!this._gestureMgr) {\n            this._gestureMgr = new GestureMgr();\n        }\n        var gestureMgr = this._gestureMgr;\n\n        stage === 'start' && gestureMgr.clear();\n\n        var gestureInfo = gestureMgr.recognize(\n            event,\n            this.findHover(event.zrX, event.zrY, null).target,\n            this.proxy.dom\n        );\n\n        stage === 'end' && gestureMgr.clear();\n\n        // Do not do any preventDefault here. Upper application do that if necessary.\n        if (gestureInfo) {\n            var type = gestureInfo.type;\n            event.gestureEvent = type;\n\n            this.dispatchToElement({target: gestureInfo.target}, type, gestureInfo.event);\n        }\n    }\n};\n\n// Common handlers\neach$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {\n    Handler.prototype[name] = function (event) {\n        // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover\n        var hovered = this.findHover(event.zrX, event.zrY);\n        var hoveredTarget = hovered.target;\n\n        if (name === 'mousedown') {\n            this._downEl = hoveredTarget;\n            this._downPoint = [event.zrX, event.zrY];\n            // In case click triggered before mouseup\n            this._upEl = hoveredTarget;\n        }\n        else if (name === 'mouseup') {\n            this._upEl = hoveredTarget;\n        }\n        else if (name === 'click') {\n            if (this._downEl !== this._upEl\n                // Original click event is triggered on the whole canvas element,\n                // including the case that `mousedown` - `mousemove` - `mouseup`,\n                // which should be filtered, otherwise it will bring trouble to\n                // pan and zoom.\n                || !this._downPoint\n                // Arbitrary value\n                || dist(this._downPoint, [event.zrX, event.zrY]) > 4\n            ) {\n                return;\n            }\n            this._downPoint = null;\n        }\n\n        this.dispatchToElement(hovered, name, event);\n    };\n});\n\nfunction isHover(displayable, x, y) {\n    if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) {\n        var el = displayable;\n        var isSilent;\n        while (el) {\n            // If clipped by ancestor.\n            // FIXME: If clipPath has neither stroke nor fill,\n            // el.clipPath.contain(x, y) will always return false.\n            if (el.clipPath && !el.clipPath.contain(x, y)) {\n                return false;\n            }\n            if (el.silent) {\n                isSilent = true;\n            }\n            el = el.parent;\n        }\n        return isSilent ? SILENT : true;\n    }\n\n    return false;\n}\n\nmixin(Handler, Eventful);\nmixin(Handler, Draggable);\n\n/**\n * 3x2矩阵操作类\n * @exports zrender/tool/matrix\n */\n\nvar ArrayCtor$1 = typeof Float32Array === 'undefined'\n    ? Array\n    : Float32Array;\n\n/**\n * Create a identity matrix.\n * @return {Float32Array|Array.<number>}\n */\nfunction create$1() {\n    var out = new ArrayCtor$1(6);\n    identity(out);\n\n    return out;\n}\n\n/**\n * 设置矩阵为单位矩阵\n * @param {Float32Array|Array.<number>} out\n */\nfunction identity(out) {\n    out[0] = 1;\n    out[1] = 0;\n    out[2] = 0;\n    out[3] = 1;\n    out[4] = 0;\n    out[5] = 0;\n    return out;\n}\n\n/**\n * 复制矩阵\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} m\n */\nfunction copy$1(out, m) {\n    out[0] = m[0];\n    out[1] = m[1];\n    out[2] = m[2];\n    out[3] = m[3];\n    out[4] = m[4];\n    out[5] = m[5];\n    return out;\n}\n\n/**\n * 矩阵相乘\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} m1\n * @param {Float32Array|Array.<number>} m2\n */\nfunction mul$1(out, m1, m2) {\n    // Consider matrix.mul(m, m2, m);\n    // where out is the same as m2.\n    // So use temp variable to escape error.\n    var out0 = m1[0] * m2[0] + m1[2] * m2[1];\n    var out1 = m1[1] * m2[0] + m1[3] * m2[1];\n    var out2 = m1[0] * m2[2] + m1[2] * m2[3];\n    var out3 = m1[1] * m2[2] + m1[3] * m2[3];\n    var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];\n    var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];\n    out[0] = out0;\n    out[1] = out1;\n    out[2] = out2;\n    out[3] = out3;\n    out[4] = out4;\n    out[5] = out5;\n    return out;\n}\n\n/**\n * 平移变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {Float32Array|Array.<number>} v\n */\nfunction translate(out, a, v) {\n    out[0] = a[0];\n    out[1] = a[1];\n    out[2] = a[2];\n    out[3] = a[3];\n    out[4] = a[4] + v[0];\n    out[5] = a[5] + v[1];\n    return out;\n}\n\n/**\n * 旋转变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {number} rad\n */\nfunction rotate(out, a, rad) {\n    var aa = a[0];\n    var ac = a[2];\n    var atx = a[4];\n    var ab = a[1];\n    var ad = a[3];\n    var aty = a[5];\n    var st = Math.sin(rad);\n    var ct = Math.cos(rad);\n\n    out[0] = aa * ct + ab * st;\n    out[1] = -aa * st + ab * ct;\n    out[2] = ac * ct + ad * st;\n    out[3] = -ac * st + ct * ad;\n    out[4] = ct * atx + st * aty;\n    out[5] = ct * aty - st * atx;\n    return out;\n}\n\n/**\n * 缩放变换\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n * @param {Float32Array|Array.<number>} v\n */\nfunction scale$1(out, a, v) {\n    var vx = v[0];\n    var vy = v[1];\n    out[0] = a[0] * vx;\n    out[1] = a[1] * vy;\n    out[2] = a[2] * vx;\n    out[3] = a[3] * vy;\n    out[4] = a[4] * vx;\n    out[5] = a[5] * vy;\n    return out;\n}\n\n/**\n * 求逆矩阵\n * @param {Float32Array|Array.<number>} out\n * @param {Float32Array|Array.<number>} a\n */\nfunction invert(out, a) {\n\n    var aa = a[0];\n    var ac = a[2];\n    var atx = a[4];\n    var ab = a[1];\n    var ad = a[3];\n    var aty = a[5];\n\n    var det = aa * ad - ab * ac;\n    if (!det) {\n        return null;\n    }\n    det = 1.0 / det;\n\n    out[0] = ad * det;\n    out[1] = -ab * det;\n    out[2] = -ac * det;\n    out[3] = aa * det;\n    out[4] = (ac * aty - ad * atx) * det;\n    out[5] = (ab * atx - aa * aty) * det;\n    return out;\n}\n\n/**\n * Clone a new matrix.\n * @param {Float32Array|Array.<number>} a\n */\n\n/**\n * 提供变换扩展\n * @module zrender/mixin/Transformable\n * @author pissang (https://www.github.com/pissang)\n */\n\nvar mIdentity = identity;\n\nvar EPSILON = 5e-5;\n\nfunction isNotAroundZero(val) {\n    return val > EPSILON || val < -EPSILON;\n}\n\n/**\n * @alias module:zrender/mixin/Transformable\n * @constructor\n */\nvar Transformable = function (opts) {\n    opts = opts || {};\n    // If there are no given position, rotation, scale\n    if (!opts.position) {\n        /**\n         * 平移\n         * @type {Array.<number>}\n         * @default [0, 0]\n         */\n        this.position = [0, 0];\n    }\n    if (opts.rotation == null) {\n        /**\n         * 旋转\n         * @type {Array.<number>}\n         * @default 0\n         */\n        this.rotation = 0;\n    }\n    if (!opts.scale) {\n        /**\n         * 缩放\n         * @type {Array.<number>}\n         * @default [1, 1]\n         */\n        this.scale = [1, 1];\n    }\n    /**\n     * 旋转和缩放的原点\n     * @type {Array.<number>}\n     * @default null\n     */\n    this.origin = this.origin || null;\n};\n\nvar transformableProto = Transformable.prototype;\ntransformableProto.transform = null;\n\n/**\n * 判断是否需要有坐标变换\n * 如果有坐标变换, 则从position, rotation, scale以及父节点的transform计算出自身的transform矩阵\n */\ntransformableProto.needLocalTransform = function () {\n    return isNotAroundZero(this.rotation)\n        || isNotAroundZero(this.position[0])\n        || isNotAroundZero(this.position[1])\n        || isNotAroundZero(this.scale[0] - 1)\n        || isNotAroundZero(this.scale[1] - 1);\n};\n\nvar scaleTmp = [];\ntransformableProto.updateTransform = function () {\n    var parent = this.parent;\n    var parentHasTransform = parent && parent.transform;\n    var needLocalTransform = this.needLocalTransform();\n\n    var m = this.transform;\n    if (!(needLocalTransform || parentHasTransform)) {\n        m && mIdentity(m);\n        return;\n    }\n\n    m = m || create$1();\n\n    if (needLocalTransform) {\n        this.getLocalTransform(m);\n    }\n    else {\n        mIdentity(m);\n    }\n\n    // 应用父节点变换\n    if (parentHasTransform) {\n        if (needLocalTransform) {\n            mul$1(m, parent.transform, m);\n        }\n        else {\n            copy$1(m, parent.transform);\n        }\n    }\n    // 保存这个变换矩阵\n    this.transform = m;\n\n    var globalScaleRatio = this.globalScaleRatio;\n    if (globalScaleRatio != null && globalScaleRatio !== 1) {\n        this.getGlobalScale(scaleTmp);\n        var relX = scaleTmp[0] < 0 ? -1 : 1;\n        var relY = scaleTmp[1] < 0 ? -1 : 1;\n        var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0;\n        var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0;\n\n        m[0] *= sx;\n        m[1] *= sx;\n        m[2] *= sy;\n        m[3] *= sy;\n    }\n\n    this.invTransform = this.invTransform || create$1();\n    invert(this.invTransform, m);\n};\n\ntransformableProto.getLocalTransform = function (m) {\n    return Transformable.getLocalTransform(this, m);\n};\n\n/**\n * 将自己的transform应用到context上\n * @param {CanvasRenderingContext2D} ctx\n */\ntransformableProto.setTransform = function (ctx) {\n    var m = this.transform;\n    var dpr = ctx.dpr || 1;\n    if (m) {\n        ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]);\n    }\n    else {\n        ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    }\n};\n\ntransformableProto.restoreTransform = function (ctx) {\n    var dpr = ctx.dpr || 1;\n    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n};\n\nvar tmpTransform = [];\nvar originTransform = create$1();\n\ntransformableProto.setLocalTransform = function (m) {\n    if (!m) {\n        // TODO return or set identity?\n        return;\n    }\n    var sx = m[0] * m[0] + m[1] * m[1];\n    var sy = m[2] * m[2] + m[3] * m[3];\n    var position = this.position;\n    var scale$$1 = this.scale;\n    if (isNotAroundZero(sx - 1)) {\n        sx = Math.sqrt(sx);\n    }\n    if (isNotAroundZero(sy - 1)) {\n        sy = Math.sqrt(sy);\n    }\n    if (m[0] < 0) {\n        sx = -sx;\n    }\n    if (m[3] < 0) {\n        sy = -sy;\n    }\n\n    position[0] = m[4];\n    position[1] = m[5];\n    scale$$1[0] = sx;\n    scale$$1[1] = sy;\n    this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);\n};\n/**\n * 分解`transform`矩阵到`position`, `rotation`, `scale`\n */\ntransformableProto.decomposeTransform = function () {\n    if (!this.transform) {\n        return;\n    }\n    var parent = this.parent;\n    var m = this.transform;\n    if (parent && parent.transform) {\n        // Get local transform and decompose them to position, scale, rotation\n        mul$1(tmpTransform, parent.invTransform, m);\n        m = tmpTransform;\n    }\n    var origin = this.origin;\n    if (origin && (origin[0] || origin[1])) {\n        originTransform[4] = origin[0];\n        originTransform[5] = origin[1];\n        mul$1(tmpTransform, m, originTransform);\n        tmpTransform[4] -= origin[0];\n        tmpTransform[5] -= origin[1];\n        m = tmpTransform;\n    }\n\n    this.setLocalTransform(m);\n};\n\n/**\n * Get global scale\n * @return {Array.<number>}\n */\ntransformableProto.getGlobalScale = function (out) {\n    var m = this.transform;\n    out = out || [];\n    if (!m) {\n        out[0] = 1;\n        out[1] = 1;\n        return out;\n    }\n    out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]);\n    out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]);\n    if (m[0] < 0) {\n        out[0] = -out[0];\n    }\n    if (m[3] < 0) {\n        out[1] = -out[1];\n    }\n    return out;\n};\n/**\n * 变换坐标位置到 shape 的局部坐标空间\n * @method\n * @param {number} x\n * @param {number} y\n * @return {Array.<number>}\n */\ntransformableProto.transformCoordToLocal = function (x, y) {\n    var v2 = [x, y];\n    var invTransform = this.invTransform;\n    if (invTransform) {\n        applyTransform(v2, v2, invTransform);\n    }\n    return v2;\n};\n\n/**\n * 变换局部坐标位置到全局坐标空间\n * @method\n * @param {number} x\n * @param {number} y\n * @return {Array.<number>}\n */\ntransformableProto.transformCoordToGlobal = function (x, y) {\n    var v2 = [x, y];\n    var transform = this.transform;\n    if (transform) {\n        applyTransform(v2, v2, transform);\n    }\n    return v2;\n};\n\n/**\n * @static\n * @param {Object} target\n * @param {Array.<number>} target.origin\n * @param {number} target.rotation\n * @param {Array.<number>} target.position\n * @param {Array.<number>} [m]\n */\nTransformable.getLocalTransform = function (target, m) {\n    m = m || [];\n    mIdentity(m);\n\n    var origin = target.origin;\n    var scale$$1 = target.scale || [1, 1];\n    var rotation = target.rotation || 0;\n    var position = target.position || [0, 0];\n\n    if (origin) {\n        // Translate to origin\n        m[4] -= origin[0];\n        m[5] -= origin[1];\n    }\n    scale$1(m, m, scale$$1);\n    if (rotation) {\n        rotate(m, m, rotation);\n    }\n    if (origin) {\n        // Translate back from origin\n        m[4] += origin[0];\n        m[5] += origin[1];\n    }\n\n    m[4] += position[0];\n    m[5] += position[1];\n\n    return m;\n};\n\n/**\n * 缓动代码来自 https://github.com/sole/tween.js/blob/master/src/Tween.js\n * @see http://sole.github.io/tween.js/examples/03_graphs.html\n * @exports zrender/animation/easing\n */\nvar easing = {\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    linear: function (k) {\n        return k;\n    },\n\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticIn: function (k) {\n        return k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticOut: function (k) {\n        return k * (2 - k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quadraticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k;\n        }\n        return -0.5 * (--k * (k - 2) - 1);\n    },\n\n    // 三次方的缓动（t^3）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicIn: function (k) {\n        return k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicOut: function (k) {\n        return --k * k * k + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    cubicInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k;\n        }\n        return 0.5 * ((k -= 2) * k * k + 2);\n    },\n\n    // 四次方的缓动（t^4）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticIn: function (k) {\n        return k * k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticOut: function (k) {\n        return 1 - (--k * k * k * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quarticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k * k;\n        }\n        return -0.5 * ((k -= 2) * k * k * k - 2);\n    },\n\n    // 五次方的缓动（t^5）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticIn: function (k) {\n        return k * k * k * k * k;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticOut: function (k) {\n        return --k * k * k * k * k + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    quinticInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return 0.5 * k * k * k * k * k;\n        }\n        return 0.5 * ((k -= 2) * k * k * k * k + 2);\n    },\n\n    // 正弦曲线的缓动（sin(t)）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalIn: function (k) {\n        return 1 - Math.cos(k * Math.PI / 2);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalOut: function (k) {\n        return Math.sin(k * Math.PI / 2);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    sinusoidalInOut: function (k) {\n        return 0.5 * (1 - Math.cos(Math.PI * k));\n    },\n\n    // 指数曲线的缓动（2^t）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialIn: function (k) {\n        return k === 0 ? 0 : Math.pow(1024, k - 1);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialOut: function (k) {\n        return k === 1 ? 1 : 1 - Math.pow(2, -10 * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    exponentialInOut: function (k) {\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if ((k *= 2) < 1) {\n            return 0.5 * Math.pow(1024, k - 1);\n        }\n        return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);\n    },\n\n    // 圆形曲线的缓动（sqrt(1-t^2)）\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularIn: function (k) {\n        return 1 - Math.sqrt(1 - k * k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularOut: function (k) {\n        return Math.sqrt(1 - (--k * k));\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    circularInOut: function (k) {\n        if ((k *= 2) < 1) {\n            return -0.5 * (Math.sqrt(1 - k * k) - 1);\n        }\n        return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);\n    },\n\n    // 创建类似于弹簧在停止前来回振荡的动画\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticIn: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        return -(a * Math.pow(2, 10 * (k -= 1))\n                    * Math.sin((k - s) * (2 * Math.PI) / p));\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticOut: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        return (a * Math.pow(2, -10 * k)\n                    * Math.sin((k - s) * (2 * Math.PI) / p) + 1);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    elasticInOut: function (k) {\n        var s;\n        var a = 0.1;\n        var p = 0.4;\n        if (k === 0) {\n            return 0;\n        }\n        if (k === 1) {\n            return 1;\n        }\n        if (!a || a < 1) {\n            a = 1;\n            s = p / 4;\n        }\n        else {\n            s = p * Math.asin(1 / a) / (2 * Math.PI);\n        }\n        if ((k *= 2) < 1) {\n            return -0.5 * (a * Math.pow(2, 10 * (k -= 1))\n                * Math.sin((k - s) * (2 * Math.PI) / p));\n        }\n        return a * Math.pow(2, -10 * (k -= 1))\n                * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;\n\n    },\n\n    // 在某一动画开始沿指示的路径进行动画处理前稍稍收回该动画的移动\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backIn: function (k) {\n        var s = 1.70158;\n        return k * k * ((s + 1) * k - s);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backOut: function (k) {\n        var s = 1.70158;\n        return --k * k * ((s + 1) * k + s) + 1;\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    backInOut: function (k) {\n        var s = 1.70158 * 1.525;\n        if ((k *= 2) < 1) {\n            return 0.5 * (k * k * ((s + 1) * k - s));\n        }\n        return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);\n    },\n\n    // 创建弹跳效果\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceIn: function (k) {\n        return 1 - easing.bounceOut(1 - k);\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceOut: function (k) {\n        if (k < (1 / 2.75)) {\n            return 7.5625 * k * k;\n        }\n        else if (k < (2 / 2.75)) {\n            return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;\n        }\n        else if (k < (2.5 / 2.75)) {\n            return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;\n        }\n        else {\n            return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;\n        }\n    },\n    /**\n    * @param {number} k\n    * @return {number}\n    */\n    bounceInOut: function (k) {\n        if (k < 0.5) {\n            return easing.bounceIn(k * 2) * 0.5;\n        }\n        return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;\n    }\n};\n\n/**\n * 动画主控制器\n * @config target 动画对象，可以是数组，如果是数组的话会批量分发onframe等事件\n * @config life(1000) 动画时长\n * @config delay(0) 动画延迟时间\n * @config loop(true)\n * @config gap(0) 循环的间隔时间\n * @config onframe\n * @config easing(optional)\n * @config ondestroy(optional)\n * @config onrestart(optional)\n *\n * TODO pause\n */\n\nfunction Clip(options) {\n\n    this._target = options.target;\n\n    // 生命周期\n    this._life = options.life || 1000;\n    // 延时\n    this._delay = options.delay || 0;\n    // 开始时间\n    // this._startTime = new Date().getTime() + this._delay;// 单位毫秒\n    this._initialized = false;\n\n    // 是否循环\n    this.loop = options.loop == null ? false : options.loop;\n\n    this.gap = options.gap || 0;\n\n    this.easing = options.easing || 'Linear';\n\n    this.onframe = options.onframe;\n    this.ondestroy = options.ondestroy;\n    this.onrestart = options.onrestart;\n\n    this._pausedTime = 0;\n    this._paused = false;\n}\n\nClip.prototype = {\n\n    constructor: Clip,\n\n    step: function (globalTime, deltaTime) {\n        // Set startTime on first step, or _startTime may has milleseconds different between clips\n        // PENDING\n        if (!this._initialized) {\n            this._startTime = globalTime + this._delay;\n            this._initialized = true;\n        }\n\n        if (this._paused) {\n            this._pausedTime += deltaTime;\n            return;\n        }\n\n        var percent = (globalTime - this._startTime - this._pausedTime) / this._life;\n\n        // 还没开始\n        if (percent < 0) {\n            return;\n        }\n\n        percent = Math.min(percent, 1);\n\n        var easing$$1 = this.easing;\n        var easingFunc = typeof easing$$1 === 'string' ? easing[easing$$1] : easing$$1;\n        var schedule = typeof easingFunc === 'function'\n            ? easingFunc(percent)\n            : percent;\n\n        this.fire('frame', schedule);\n\n        // 结束\n        if (percent === 1) {\n            if (this.loop) {\n                this.restart(globalTime);\n                // 重新开始周期\n                // 抛出而不是直接调用事件直到 stage.update 后再统一调用这些事件\n                return 'restart';\n            }\n\n            // 动画完成将这个控制器标识为待删除\n            // 在Animation.update中进行批量删除\n            this._needsRemove = true;\n            return 'destroy';\n        }\n\n        return null;\n    },\n\n    restart: function (globalTime) {\n        var remainder = (globalTime - this._startTime - this._pausedTime) % this._life;\n        this._startTime = globalTime - remainder + this.gap;\n        this._pausedTime = 0;\n\n        this._needsRemove = false;\n    },\n\n    fire: function (eventType, arg) {\n        eventType = 'on' + eventType;\n        if (this[eventType]) {\n            this[eventType](this._target, arg);\n        }\n    },\n\n    pause: function () {\n        this._paused = true;\n    },\n\n    resume: function () {\n        this._paused = false;\n    }\n};\n\n// Simple LRU cache use doubly linked list\n// @module zrender/core/LRU\n\n/**\n * Simple double linked list. Compared with array, it has O(1) remove operation.\n * @constructor\n */\nvar LinkedList = function () {\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.head = null;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.tail = null;\n\n    this._len = 0;\n};\n\nvar linkedListProto = LinkedList.prototype;\n/**\n * Insert a new value at the tail\n * @param  {} val\n * @return {module:zrender/core/LRU~Entry}\n */\nlinkedListProto.insert = function (val) {\n    var entry = new Entry(val);\n    this.insertEntry(entry);\n    return entry;\n};\n\n/**\n * Insert an entry at the tail\n * @param  {module:zrender/core/LRU~Entry} entry\n */\nlinkedListProto.insertEntry = function (entry) {\n    if (!this.head) {\n        this.head = this.tail = entry;\n    }\n    else {\n        this.tail.next = entry;\n        entry.prev = this.tail;\n        entry.next = null;\n        this.tail = entry;\n    }\n    this._len++;\n};\n\n/**\n * Remove entry.\n * @param  {module:zrender/core/LRU~Entry} entry\n */\nlinkedListProto.remove = function (entry) {\n    var prev = entry.prev;\n    var next = entry.next;\n    if (prev) {\n        prev.next = next;\n    }\n    else {\n        // Is head\n        this.head = next;\n    }\n    if (next) {\n        next.prev = prev;\n    }\n    else {\n        // Is tail\n        this.tail = prev;\n    }\n    entry.next = entry.prev = null;\n    this._len--;\n};\n\n/**\n * @return {number}\n */\nlinkedListProto.len = function () {\n    return this._len;\n};\n\n/**\n * Clear list\n */\nlinkedListProto.clear = function () {\n    this.head = this.tail = null;\n    this._len = 0;\n};\n\n/**\n * @constructor\n * @param {} val\n */\nvar Entry = function (val) {\n    /**\n     * @type {}\n     */\n    this.value = val;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.next;\n\n    /**\n     * @type {module:zrender/core/LRU~Entry}\n     */\n    this.prev;\n};\n\n/**\n * LRU Cache\n * @constructor\n * @alias module:zrender/core/LRU\n */\nvar LRU = function (maxSize) {\n\n    this._list = new LinkedList();\n\n    this._map = {};\n\n    this._maxSize = maxSize || 10;\n\n    this._lastRemovedEntry = null;\n};\n\nvar LRUProto = LRU.prototype;\n\n/**\n * @param  {string} key\n * @param  {} value\n * @return {} Removed value\n */\nLRUProto.put = function (key, value) {\n    var list = this._list;\n    var map = this._map;\n    var removed = null;\n    if (map[key] == null) {\n        var len = list.len();\n        // Reuse last removed entry\n        var entry = this._lastRemovedEntry;\n\n        if (len >= this._maxSize && len > 0) {\n            // Remove the least recently used\n            var leastUsedEntry = list.head;\n            list.remove(leastUsedEntry);\n            delete map[leastUsedEntry.key];\n\n            removed = leastUsedEntry.value;\n            this._lastRemovedEntry = leastUsedEntry;\n        }\n\n        if (entry) {\n            entry.value = value;\n        }\n        else {\n            entry = new Entry(value);\n        }\n        entry.key = key;\n        list.insertEntry(entry);\n        map[key] = entry;\n    }\n\n    return removed;\n};\n\n/**\n * @param  {string} key\n * @return {}\n */\nLRUProto.get = function (key) {\n    var entry = this._map[key];\n    var list = this._list;\n    if (entry != null) {\n        // Put the latest used entry in the tail\n        if (entry !== list.tail) {\n            list.remove(entry);\n            list.insertEntry(entry);\n        }\n\n        return entry.value;\n    }\n};\n\n/**\n * Clear the cache\n */\nLRUProto.clear = function () {\n    this._list.clear();\n    this._map = {};\n};\n\nvar kCSSColorTable = {\n    'transparent': [0, 0, 0, 0], 'aliceblue': [240, 248, 255, 1],\n    'antiquewhite': [250, 235, 215, 1], 'aqua': [0, 255, 255, 1],\n    'aquamarine': [127, 255, 212, 1], 'azure': [240, 255, 255, 1],\n    'beige': [245, 245, 220, 1], 'bisque': [255, 228, 196, 1],\n    'black': [0, 0, 0, 1], 'blanchedalmond': [255, 235, 205, 1],\n    'blue': [0, 0, 255, 1], 'blueviolet': [138, 43, 226, 1],\n    'brown': [165, 42, 42, 1], 'burlywood': [222, 184, 135, 1],\n    'cadetblue': [95, 158, 160, 1], 'chartreuse': [127, 255, 0, 1],\n    'chocolate': [210, 105, 30, 1], 'coral': [255, 127, 80, 1],\n    'cornflowerblue': [100, 149, 237, 1], 'cornsilk': [255, 248, 220, 1],\n    'crimson': [220, 20, 60, 1], 'cyan': [0, 255, 255, 1],\n    'darkblue': [0, 0, 139, 1], 'darkcyan': [0, 139, 139, 1],\n    'darkgoldenrod': [184, 134, 11, 1], 'darkgray': [169, 169, 169, 1],\n    'darkgreen': [0, 100, 0, 1], 'darkgrey': [169, 169, 169, 1],\n    'darkkhaki': [189, 183, 107, 1], 'darkmagenta': [139, 0, 139, 1],\n    'darkolivegreen': [85, 107, 47, 1], 'darkorange': [255, 140, 0, 1],\n    'darkorchid': [153, 50, 204, 1], 'darkred': [139, 0, 0, 1],\n    'darksalmon': [233, 150, 122, 1], 'darkseagreen': [143, 188, 143, 1],\n    'darkslateblue': [72, 61, 139, 1], 'darkslategray': [47, 79, 79, 1],\n    'darkslategrey': [47, 79, 79, 1], 'darkturquoise': [0, 206, 209, 1],\n    'darkviolet': [148, 0, 211, 1], 'deeppink': [255, 20, 147, 1],\n    'deepskyblue': [0, 191, 255, 1], 'dimgray': [105, 105, 105, 1],\n    'dimgrey': [105, 105, 105, 1], 'dodgerblue': [30, 144, 255, 1],\n    'firebrick': [178, 34, 34, 1], 'floralwhite': [255, 250, 240, 1],\n    'forestgreen': [34, 139, 34, 1], 'fuchsia': [255, 0, 255, 1],\n    'gainsboro': [220, 220, 220, 1], 'ghostwhite': [248, 248, 255, 1],\n    'gold': [255, 215, 0, 1], 'goldenrod': [218, 165, 32, 1],\n    'gray': [128, 128, 128, 1], 'green': [0, 128, 0, 1],\n    'greenyellow': [173, 255, 47, 1], 'grey': [128, 128, 128, 1],\n    'honeydew': [240, 255, 240, 1], 'hotpink': [255, 105, 180, 1],\n    'indianred': [205, 92, 92, 1], 'indigo': [75, 0, 130, 1],\n    'ivory': [255, 255, 240, 1], 'khaki': [240, 230, 140, 1],\n    'lavender': [230, 230, 250, 1], 'lavenderblush': [255, 240, 245, 1],\n    'lawngreen': [124, 252, 0, 1], 'lemonchiffon': [255, 250, 205, 1],\n    'lightblue': [173, 216, 230, 1], 'lightcoral': [240, 128, 128, 1],\n    'lightcyan': [224, 255, 255, 1], 'lightgoldenrodyellow': [250, 250, 210, 1],\n    'lightgray': [211, 211, 211, 1], 'lightgreen': [144, 238, 144, 1],\n    'lightgrey': [211, 211, 211, 1], 'lightpink': [255, 182, 193, 1],\n    'lightsalmon': [255, 160, 122, 1], 'lightseagreen': [32, 178, 170, 1],\n    'lightskyblue': [135, 206, 250, 1], 'lightslategray': [119, 136, 153, 1],\n    'lightslategrey': [119, 136, 153, 1], 'lightsteelblue': [176, 196, 222, 1],\n    'lightyellow': [255, 255, 224, 1], 'lime': [0, 255, 0, 1],\n    'limegreen': [50, 205, 50, 1], 'linen': [250, 240, 230, 1],\n    'magenta': [255, 0, 255, 1], 'maroon': [128, 0, 0, 1],\n    'mediumaquamarine': [102, 205, 170, 1], 'mediumblue': [0, 0, 205, 1],\n    'mediumorchid': [186, 85, 211, 1], 'mediumpurple': [147, 112, 219, 1],\n    'mediumseagreen': [60, 179, 113, 1], 'mediumslateblue': [123, 104, 238, 1],\n    'mediumspringgreen': [0, 250, 154, 1], 'mediumturquoise': [72, 209, 204, 1],\n    'mediumvioletred': [199, 21, 133, 1], 'midnightblue': [25, 25, 112, 1],\n    'mintcream': [245, 255, 250, 1], 'mistyrose': [255, 228, 225, 1],\n    'moccasin': [255, 228, 181, 1], 'navajowhite': [255, 222, 173, 1],\n    'navy': [0, 0, 128, 1], 'oldlace': [253, 245, 230, 1],\n    'olive': [128, 128, 0, 1], 'olivedrab': [107, 142, 35, 1],\n    'orange': [255, 165, 0, 1], 'orangered': [255, 69, 0, 1],\n    'orchid': [218, 112, 214, 1], 'palegoldenrod': [238, 232, 170, 1],\n    'palegreen': [152, 251, 152, 1], 'paleturquoise': [175, 238, 238, 1],\n    'palevioletred': [219, 112, 147, 1], 'papayawhip': [255, 239, 213, 1],\n    'peachpuff': [255, 218, 185, 1], 'peru': [205, 133, 63, 1],\n    'pink': [255, 192, 203, 1], 'plum': [221, 160, 221, 1],\n    'powderblue': [176, 224, 230, 1], 'purple': [128, 0, 128, 1],\n    'red': [255, 0, 0, 1], 'rosybrown': [188, 143, 143, 1],\n    'royalblue': [65, 105, 225, 1], 'saddlebrown': [139, 69, 19, 1],\n    'salmon': [250, 128, 114, 1], 'sandybrown': [244, 164, 96, 1],\n    'seagreen': [46, 139, 87, 1], 'seashell': [255, 245, 238, 1],\n    'sienna': [160, 82, 45, 1], 'silver': [192, 192, 192, 1],\n    'skyblue': [135, 206, 235, 1], 'slateblue': [106, 90, 205, 1],\n    'slategray': [112, 128, 144, 1], 'slategrey': [112, 128, 144, 1],\n    'snow': [255, 250, 250, 1], 'springgreen': [0, 255, 127, 1],\n    'steelblue': [70, 130, 180, 1], 'tan': [210, 180, 140, 1],\n    'teal': [0, 128, 128, 1], 'thistle': [216, 191, 216, 1],\n    'tomato': [255, 99, 71, 1], 'turquoise': [64, 224, 208, 1],\n    'violet': [238, 130, 238, 1], 'wheat': [245, 222, 179, 1],\n    'white': [255, 255, 255, 1], 'whitesmoke': [245, 245, 245, 1],\n    'yellow': [255, 255, 0, 1], 'yellowgreen': [154, 205, 50, 1]\n};\n\nfunction clampCssByte(i) {  // Clamp to integer 0 .. 255.\n    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).\n    return i < 0 ? 0 : i > 255 ? 255 : i;\n}\n\nfunction clampCssFloat(f) {  // Clamp to float 0.0 .. 1.0.\n    return f < 0 ? 0 : f > 1 ? 1 : f;\n}\n\nfunction parseCssInt(str) {  // int or percentage.\n    if (str.length && str.charAt(str.length - 1) === '%') {\n        return clampCssByte(parseFloat(str) / 100 * 255);\n    }\n    return clampCssByte(parseInt(str, 10));\n}\n\nfunction parseCssFloat(str) {  // float or percentage.\n    if (str.length && str.charAt(str.length - 1) === '%') {\n        return clampCssFloat(parseFloat(str) / 100);\n    }\n    return clampCssFloat(parseFloat(str));\n}\n\nfunction cssHueToRgb(m1, m2, h) {\n    if (h < 0) {\n        h += 1;\n    }\n    else if (h > 1) {\n        h -= 1;\n    }\n\n    if (h * 6 < 1) {\n        return m1 + (m2 - m1) * h * 6;\n    }\n    if (h * 2 < 1) {\n        return m2;\n    }\n    if (h * 3 < 2) {\n        return m1 + (m2 - m1) * (2 / 3 - h) * 6;\n    }\n    return m1;\n}\n\nfunction setRgba(out, r, g, b, a) {\n    out[0] = r; out[1] = g; out[2] = b; out[3] = a;\n    return out;\n}\nfunction copyRgba(out, a) {\n    out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3];\n    return out;\n}\n\nvar colorCache = new LRU(20);\nvar lastRemovedArr = null;\n\nfunction putToCache(colorStr, rgbaArr) {\n    // Reuse removed array\n    if (lastRemovedArr) {\n        copyRgba(lastRemovedArr, rgbaArr);\n    }\n    lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice()));\n}\n\n/**\n * @param {string} colorStr\n * @param {Array.<number>} out\n * @return {Array.<number>}\n * @memberOf module:zrender/util/color\n */\nfunction parse(colorStr, rgbaArr) {\n    if (!colorStr) {\n        return;\n    }\n    rgbaArr = rgbaArr || [];\n\n    var cached = colorCache.get(colorStr);\n    if (cached) {\n        return copyRgba(rgbaArr, cached);\n    }\n\n    // colorStr may be not string\n    colorStr = colorStr + '';\n    // Remove all whitespace, not compliant, but should just be more accepting.\n    var str = colorStr.replace(/ /g, '').toLowerCase();\n\n    // Color keywords (and transparent) lookup.\n    if (str in kCSSColorTable) {\n        copyRgba(rgbaArr, kCSSColorTable[str]);\n        putToCache(colorStr, rgbaArr);\n        return rgbaArr;\n    }\n\n    // #abc and #abc123 syntax.\n    if (str.charAt(0) === '#') {\n        if (str.length === 4) {\n            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n            if (!(iv >= 0 && iv <= 0xfff)) {\n                setRgba(rgbaArr, 0, 0, 0, 1);\n                return;  // Covers NaN.\n            }\n            setRgba(rgbaArr,\n                ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8),\n                (iv & 0xf0) | ((iv & 0xf0) >> 4),\n                (iv & 0xf) | ((iv & 0xf) << 4),\n                1\n            );\n            putToCache(colorStr, rgbaArr);\n            return rgbaArr;\n        }\n        else if (str.length === 7) {\n            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.\n            if (!(iv >= 0 && iv <= 0xffffff)) {\n                setRgba(rgbaArr, 0, 0, 0, 1);\n                return;  // Covers NaN.\n            }\n            setRgba(rgbaArr,\n                (iv & 0xff0000) >> 16,\n                (iv & 0xff00) >> 8,\n                iv & 0xff,\n                1\n            );\n            putToCache(colorStr, rgbaArr);\n            return rgbaArr;\n        }\n\n        return;\n    }\n    var op = str.indexOf('(');\n    var ep = str.indexOf(')');\n    if (op !== -1 && ep + 1 === str.length) {\n        var fname = str.substr(0, op);\n        var params = str.substr(op + 1, ep - (op + 1)).split(',');\n        var alpha = 1;  // To allow case fallthrough.\n        switch (fname) {\n            case 'rgba':\n                if (params.length !== 4) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                alpha = parseCssFloat(params.pop()); // jshint ignore:line\n            // Fall through.\n            case 'rgb':\n                if (params.length !== 3) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                setRgba(rgbaArr,\n                    parseCssInt(params[0]),\n                    parseCssInt(params[1]),\n                    parseCssInt(params[2]),\n                    alpha\n                );\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            case 'hsla':\n                if (params.length !== 4) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                params[3] = parseCssFloat(params[3]);\n                hsla2rgba(params, rgbaArr);\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            case 'hsl':\n                if (params.length !== 3) {\n                    setRgba(rgbaArr, 0, 0, 0, 1);\n                    return;\n                }\n                hsla2rgba(params, rgbaArr);\n                putToCache(colorStr, rgbaArr);\n                return rgbaArr;\n            default:\n                return;\n        }\n    }\n\n    setRgba(rgbaArr, 0, 0, 0, 1);\n    return;\n}\n\n/**\n * @param {Array.<number>} hsla\n * @param {Array.<number>} rgba\n * @return {Array.<number>} rgba\n */\nfunction hsla2rgba(hsla, rgba) {\n    var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360;  // 0 .. 1\n    // NOTE(deanm): According to the CSS spec s/l should only be\n    // percentages, but we don't bother and let float or percentage.\n    var s = parseCssFloat(hsla[1]);\n    var l = parseCssFloat(hsla[2]);\n    var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;\n    var m1 = l * 2 - m2;\n\n    rgba = rgba || [];\n    setRgba(rgba,\n        clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255),\n        clampCssByte(cssHueToRgb(m1, m2, h) * 255),\n        clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255),\n        1\n    );\n\n    if (hsla.length === 4) {\n        rgba[3] = hsla[3];\n    }\n\n    return rgba;\n}\n\n/**\n * @param {string} color\n * @param {number} level\n * @return {string}\n * @memberOf module:zrender/util/color\n */\nfunction lift(color, level) {\n    var colorArr = parse(color);\n    if (colorArr) {\n        for (var i = 0; i < 3; i++) {\n            if (level < 0) {\n                colorArr[i] = colorArr[i] * (1 - level) | 0;\n            }\n            else {\n                colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0;\n            }\n            if (colorArr[i] > 255) {\n                colorArr[i] = 255;\n            }\n            else if (color[i] < 0) {\n                colorArr[i] = 0;\n            }\n        }\n        return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');\n    }\n}\n\n/**\n * @param {string} color\n * @return {string}\n * @memberOf module:zrender/util/color\n */\n\n\n/**\n * Map value to color. Faster than lerp methods because color is represented by rgba array.\n * @param {number} normalizedValue A float between 0 and 1.\n * @param {Array.<Array.<number>>} colors List of rgba color array\n * @param {Array.<number>} [out] Mapped gba color array\n * @return {Array.<number>} will be null/undefined if input illegal.\n */\n\n\n/**\n * @deprecated\n */\n\n\n/**\n * @param {number} normalizedValue A float between 0 and 1.\n * @param {Array.<string>} colors Color list.\n * @param {boolean=} fullOutput Default false.\n * @return {(string|Object)} Result color. If fullOutput,\n *                           return {color: ..., leftIndex: ..., rightIndex: ..., value: ...},\n * @memberOf module:zrender/util/color\n */\n\n\n/**\n * @deprecated\n */\n\n\n/**\n * @param {string} color\n * @param {number=} h 0 ~ 360, ignore when null.\n * @param {number=} s 0 ~ 1, ignore when null.\n * @param {number=} l 0 ~ 1, ignore when null.\n * @return {string} Color string in rgba format.\n * @memberOf module:zrender/util/color\n */\n\n\n/**\n * @param {string} color\n * @param {number=} alpha 0 ~ 1\n * @return {string} Color string in rgba format.\n * @memberOf module:zrender/util/color\n */\n\n\n/**\n * @param {Array.<number>} arrColor like [12,33,44,0.4]\n * @param {string} type 'rgba', 'hsva', ...\n * @return {string} Result color. (If input illegal, return undefined).\n */\nfunction stringify(arrColor, type) {\n    if (!arrColor || !arrColor.length) {\n        return;\n    }\n    var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];\n    if (type === 'rgba' || type === 'hsva' || type === 'hsla') {\n        colorStr += ',' + arrColor[3];\n    }\n    return type + '(' + colorStr + ')';\n}\n\n/**\n * @module echarts/animation/Animator\n */\n\nvar arraySlice = Array.prototype.slice;\n\nfunction defaultGetter(target, key) {\n    return target[key];\n}\n\nfunction defaultSetter(target, key, value) {\n    target[key] = value;\n}\n\n/**\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} percent\n * @return {number}\n */\nfunction interpolateNumber(p0, p1, percent) {\n    return (p1 - p0) * percent + p0;\n}\n\n/**\n * @param  {string} p0\n * @param  {string} p1\n * @param  {number} percent\n * @return {string}\n */\nfunction interpolateString(p0, p1, percent) {\n    return percent > 0.5 ? p1 : p0;\n}\n\n/**\n * @param  {Array} p0\n * @param  {Array} p1\n * @param  {number} percent\n * @param  {Array} out\n * @param  {number} arrDim\n */\nfunction interpolateArray(p0, p1, percent, out, arrDim) {\n    var len = p0.length;\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            out[i] = interpolateNumber(p0[i], p1[i], percent);\n        }\n    }\n    else {\n        var len2 = len && p0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                out[i][j] = interpolateNumber(\n                    p0[i][j], p1[i][j], percent\n                );\n            }\n        }\n    }\n}\n\n// arr0 is source array, arr1 is target array.\n// Do some preprocess to avoid error happened when interpolating from arr0 to arr1\nfunction fillArr(arr0, arr1, arrDim) {\n    var arr0Len = arr0.length;\n    var arr1Len = arr1.length;\n    if (arr0Len !== arr1Len) {\n        // FIXME Not work for TypedArray\n        var isPreviousLarger = arr0Len > arr1Len;\n        if (isPreviousLarger) {\n            // Cut the previous\n            arr0.length = arr1Len;\n        }\n        else {\n            // Fill the previous\n            for (var i = arr0Len; i < arr1Len; i++) {\n                arr0.push(\n                    arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i])\n                );\n            }\n        }\n    }\n    // Handling NaN value\n    var len2 = arr0[0] && arr0[0].length;\n    for (var i = 0; i < arr0.length; i++) {\n        if (arrDim === 1) {\n            if (isNaN(arr0[i])) {\n                arr0[i] = arr1[i];\n            }\n        }\n        else {\n            for (var j = 0; j < len2; j++) {\n                if (isNaN(arr0[i][j])) {\n                    arr0[i][j] = arr1[i][j];\n                }\n            }\n        }\n    }\n}\n\n/**\n * @param  {Array} arr0\n * @param  {Array} arr1\n * @param  {number} arrDim\n * @return {boolean}\n */\nfunction isArraySame(arr0, arr1, arrDim) {\n    if (arr0 === arr1) {\n        return true;\n    }\n    var len = arr0.length;\n    if (len !== arr1.length) {\n        return false;\n    }\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            if (arr0[i] !== arr1[i]) {\n                return false;\n            }\n        }\n    }\n    else {\n        var len2 = arr0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                if (arr0[i][j] !== arr1[i][j]) {\n                    return false;\n                }\n            }\n        }\n    }\n    return true;\n}\n\n/**\n * Catmull Rom interpolate array\n * @param  {Array} p0\n * @param  {Array} p1\n * @param  {Array} p2\n * @param  {Array} p3\n * @param  {number} t\n * @param  {number} t2\n * @param  {number} t3\n * @param  {Array} out\n * @param  {number} arrDim\n */\nfunction catmullRomInterpolateArray(\n    p0, p1, p2, p3, t, t2, t3, out, arrDim\n) {\n    var len = p0.length;\n    if (arrDim === 1) {\n        for (var i = 0; i < len; i++) {\n            out[i] = catmullRomInterpolate(\n                p0[i], p1[i], p2[i], p3[i], t, t2, t3\n            );\n        }\n    }\n    else {\n        var len2 = p0[0].length;\n        for (var i = 0; i < len; i++) {\n            for (var j = 0; j < len2; j++) {\n                out[i][j] = catmullRomInterpolate(\n                    p0[i][j], p1[i][j], p2[i][j], p3[i][j],\n                    t, t2, t3\n                );\n            }\n        }\n    }\n}\n\n/**\n * Catmull Rom interpolate number\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @param  {number} t2\n * @param  {number} t3\n * @return {number}\n */\nfunction catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {\n    var v0 = (p2 - p0) * 0.5;\n    var v1 = (p3 - p1) * 0.5;\n    return (2 * (p1 - p2) + v0 + v1) * t3\n            + (-3 * (p1 - p2) - 2 * v0 - v1) * t2\n            + v0 * t + p1;\n}\n\nfunction cloneValue(value) {\n    if (isArrayLike(value)) {\n        var len = value.length;\n        if (isArrayLike(value[0])) {\n            var ret = [];\n            for (var i = 0; i < len; i++) {\n                ret.push(arraySlice.call(value[i]));\n            }\n            return ret;\n        }\n\n        return arraySlice.call(value);\n    }\n\n    return value;\n}\n\nfunction rgba2String(rgba) {\n    rgba[0] = Math.floor(rgba[0]);\n    rgba[1] = Math.floor(rgba[1]);\n    rgba[2] = Math.floor(rgba[2]);\n\n    return 'rgba(' + rgba.join(',') + ')';\n}\n\nfunction getArrayDim(keyframes) {\n    var lastValue = keyframes[keyframes.length - 1].value;\n    return isArrayLike(lastValue && lastValue[0]) ? 2 : 1;\n}\n\nfunction createTrackClip(animator, easing, oneTrackDone, keyframes, propName, forceAnimate) {\n    var getter = animator._getter;\n    var setter = animator._setter;\n    var useSpline = easing === 'spline';\n\n    var trackLen = keyframes.length;\n    if (!trackLen) {\n        return;\n    }\n    // Guess data type\n    var firstVal = keyframes[0].value;\n    var isValueArray = isArrayLike(firstVal);\n    var isValueColor = false;\n    var isValueString = false;\n\n    // For vertices morphing\n    var arrDim = isValueArray ? getArrayDim(keyframes) : 0;\n\n    var trackMaxTime;\n    // Sort keyframe as ascending\n    keyframes.sort(function (a, b) {\n        return a.time - b.time;\n    });\n\n    trackMaxTime = keyframes[trackLen - 1].time;\n    // Percents of each keyframe\n    var kfPercents = [];\n    // Value of each keyframe\n    var kfValues = [];\n    var prevValue = keyframes[0].value;\n    var isAllValueEqual = true;\n    for (var i = 0; i < trackLen; i++) {\n        kfPercents.push(keyframes[i].time / trackMaxTime);\n        // Assume value is a color when it is a string\n        var value = keyframes[i].value;\n\n        // Check if value is equal, deep check if value is array\n        if (!((isValueArray && isArraySame(value, prevValue, arrDim))\n            || (!isValueArray && value === prevValue))) {\n            isAllValueEqual = false;\n        }\n        prevValue = value;\n\n        // Try converting a string to a color array\n        if (typeof value === 'string') {\n            var colorArray = parse(value);\n            if (colorArray) {\n                value = colorArray;\n                isValueColor = true;\n            }\n            else {\n                isValueString = true;\n            }\n        }\n        kfValues.push(value);\n    }\n    if (!forceAnimate && isAllValueEqual) {\n        return;\n    }\n\n    var lastValue = kfValues[trackLen - 1];\n    // Polyfill array and NaN value\n    for (var i = 0; i < trackLen - 1; i++) {\n        if (isValueArray) {\n            fillArr(kfValues[i], lastValue, arrDim);\n        }\n        else {\n            if (isNaN(kfValues[i]) && !isNaN(lastValue) && !isValueString && !isValueColor) {\n                kfValues[i] = lastValue;\n            }\n        }\n    }\n    isValueArray && fillArr(getter(animator._target, propName), lastValue, arrDim);\n\n    // Cache the key of last frame to speed up when\n    // animation playback is sequency\n    var lastFrame = 0;\n    var lastFramePercent = 0;\n    var start;\n    var w;\n    var p0;\n    var p1;\n    var p2;\n    var p3;\n\n    if (isValueColor) {\n        var rgba = [0, 0, 0, 0];\n    }\n\n    var onframe = function (target, percent) {\n        // Find the range keyframes\n        // kf1-----kf2---------current--------kf3\n        // find kf2 and kf3 and do interpolation\n        var frame;\n        // In the easing function like elasticOut, percent may less than 0\n        if (percent < 0) {\n            frame = 0;\n        }\n        else if (percent < lastFramePercent) {\n            // Start from next key\n            // PENDING start from lastFrame ?\n            start = Math.min(lastFrame + 1, trackLen - 1);\n            for (frame = start; frame >= 0; frame--) {\n                if (kfPercents[frame] <= percent) {\n                    break;\n                }\n            }\n            // PENDING really need to do this ?\n            frame = Math.min(frame, trackLen - 2);\n        }\n        else {\n            for (frame = lastFrame; frame < trackLen; frame++) {\n                if (kfPercents[frame] > percent) {\n                    break;\n                }\n            }\n            frame = Math.min(frame - 1, trackLen - 2);\n        }\n        lastFrame = frame;\n        lastFramePercent = percent;\n\n        var range = (kfPercents[frame + 1] - kfPercents[frame]);\n        if (range === 0) {\n            return;\n        }\n        else {\n            w = (percent - kfPercents[frame]) / range;\n        }\n        if (useSpline) {\n            p1 = kfValues[frame];\n            p0 = kfValues[frame === 0 ? frame : frame - 1];\n            p2 = kfValues[frame > trackLen - 2 ? trackLen - 1 : frame + 1];\n            p3 = kfValues[frame > trackLen - 3 ? trackLen - 1 : frame + 2];\n            if (isValueArray) {\n                catmullRomInterpolateArray(\n                    p0, p1, p2, p3, w, w * w, w * w * w,\n                    getter(target, propName),\n                    arrDim\n                );\n            }\n            else {\n                var value;\n                if (isValueColor) {\n                    value = catmullRomInterpolateArray(\n                        p0, p1, p2, p3, w, w * w, w * w * w,\n                        rgba, 1\n                    );\n                    value = rgba2String(rgba);\n                }\n                else if (isValueString) {\n                    // String is step(0.5)\n                    return interpolateString(p1, p2, w);\n                }\n                else {\n                    value = catmullRomInterpolate(\n                        p0, p1, p2, p3, w, w * w, w * w * w\n                    );\n                }\n                setter(\n                    target,\n                    propName,\n                    value\n                );\n            }\n        }\n        else {\n            if (isValueArray) {\n                interpolateArray(\n                    kfValues[frame], kfValues[frame + 1], w,\n                    getter(target, propName),\n                    arrDim\n                );\n            }\n            else {\n                var value;\n                if (isValueColor) {\n                    interpolateArray(\n                        kfValues[frame], kfValues[frame + 1], w,\n                        rgba, 1\n                    );\n                    value = rgba2String(rgba);\n                }\n                else if (isValueString) {\n                    // String is step(0.5)\n                    return interpolateString(kfValues[frame], kfValues[frame + 1], w);\n                }\n                else {\n                    value = interpolateNumber(kfValues[frame], kfValues[frame + 1], w);\n                }\n                setter(\n                    target,\n                    propName,\n                    value\n                );\n            }\n        }\n    };\n\n    var clip = new Clip({\n        target: animator._target,\n        life: trackMaxTime,\n        loop: animator._loop,\n        delay: animator._delay,\n        onframe: onframe,\n        ondestroy: oneTrackDone\n    });\n\n    if (easing && easing !== 'spline') {\n        clip.easing = easing;\n    }\n\n    return clip;\n}\n\n/**\n * @alias module:zrender/animation/Animator\n * @constructor\n * @param {Object} target\n * @param {boolean} loop\n * @param {Function} getter\n * @param {Function} setter\n */\nvar Animator = function (target, loop, getter, setter) {\n    this._tracks = {};\n    this._target = target;\n\n    this._loop = loop || false;\n\n    this._getter = getter || defaultGetter;\n    this._setter = setter || defaultSetter;\n\n    this._clipCount = 0;\n\n    this._delay = 0;\n\n    this._doneList = [];\n\n    this._onframeList = [];\n\n    this._clipList = [];\n};\n\nAnimator.prototype = {\n    /**\n     * 设置动画关键帧\n     * @param  {number} time 关键帧时间，单位是ms\n     * @param  {Object} props 关键帧的属性值，key-value表示\n     * @return {module:zrender/animation/Animator}\n     */\n    when: function (time /* ms */, props) {\n        var tracks = this._tracks;\n        for (var propName in props) {\n            if (!props.hasOwnProperty(propName)) {\n                continue;\n            }\n\n            if (!tracks[propName]) {\n                tracks[propName] = [];\n                // Invalid value\n                var value = this._getter(this._target, propName);\n                if (value == null) {\n                    // zrLog('Invalid property ' + propName);\n                    continue;\n                }\n                // If time is 0\n                //  Then props is given initialize value\n                // Else\n                //  Initialize value from current prop value\n                if (time !== 0) {\n                    tracks[propName].push({\n                        time: 0,\n                        value: cloneValue(value)\n                    });\n                }\n            }\n            tracks[propName].push({\n                time: time,\n                value: props[propName]\n            });\n        }\n        return this;\n    },\n    /**\n     * 添加动画每一帧的回调函数\n     * @param  {Function} callback\n     * @return {module:zrender/animation/Animator}\n     */\n    during: function (callback) {\n        this._onframeList.push(callback);\n        return this;\n    },\n\n    pause: function () {\n        for (var i = 0; i < this._clipList.length; i++) {\n            this._clipList[i].pause();\n        }\n        this._paused = true;\n    },\n\n    resume: function () {\n        for (var i = 0; i < this._clipList.length; i++) {\n            this._clipList[i].resume();\n        }\n        this._paused = false;\n    },\n\n    isPaused: function () {\n        return !!this._paused;\n    },\n\n    _doneCallback: function () {\n        // Clear all tracks\n        this._tracks = {};\n        // Clear all clips\n        this._clipList.length = 0;\n\n        var doneList = this._doneList;\n        var len = doneList.length;\n        for (var i = 0; i < len; i++) {\n            doneList[i].call(this);\n        }\n    },\n    /**\n     * 开始执行动画\n     * @param  {string|Function} [easing]\n     *         动画缓动函数，详见{@link module:zrender/animation/easing}\n     * @param  {boolean} forceAnimate\n     * @return {module:zrender/animation/Animator}\n     */\n    start: function (easing, forceAnimate) {\n\n        var self = this;\n        var clipCount = 0;\n\n        var oneTrackDone = function () {\n            clipCount--;\n            if (!clipCount) {\n                self._doneCallback();\n            }\n        };\n\n        var lastClip;\n        for (var propName in this._tracks) {\n            if (!this._tracks.hasOwnProperty(propName)) {\n                continue;\n            }\n            var clip = createTrackClip(\n                this, easing, oneTrackDone,\n                this._tracks[propName], propName, forceAnimate\n            );\n            if (clip) {\n                this._clipList.push(clip);\n                clipCount++;\n\n                // If start after added to animation\n                if (this.animation) {\n                    this.animation.addClip(clip);\n                }\n\n                lastClip = clip;\n            }\n        }\n\n        // Add during callback on the last clip\n        if (lastClip) {\n            var oldOnFrame = lastClip.onframe;\n            lastClip.onframe = function (target, percent) {\n                oldOnFrame(target, percent);\n\n                for (var i = 0; i < self._onframeList.length; i++) {\n                    self._onframeList[i](target, percent);\n                }\n            };\n        }\n\n        // This optimization will help the case that in the upper application\n        // the view may be refreshed frequently, where animation will be\n        // called repeatly but nothing changed.\n        if (!clipCount) {\n            this._doneCallback();\n        }\n        return this;\n    },\n    /**\n     * 停止动画\n     * @param {boolean} forwardToLast If move to last frame before stop\n     */\n    stop: function (forwardToLast) {\n        var clipList = this._clipList;\n        var animation = this.animation;\n        for (var i = 0; i < clipList.length; i++) {\n            var clip = clipList[i];\n            if (forwardToLast) {\n                // Move to last frame before stop\n                clip.onframe(this._target, 1);\n            }\n            animation && animation.removeClip(clip);\n        }\n        clipList.length = 0;\n    },\n    /**\n     * 设置动画延迟开始的时间\n     * @param  {number} time 单位ms\n     * @return {module:zrender/animation/Animator}\n     */\n    delay: function (time) {\n        this._delay = time;\n        return this;\n    },\n    /**\n     * 添加动画结束的回调\n     * @param  {Function} cb\n     * @return {module:zrender/animation/Animator}\n     */\n    done: function (cb) {\n        if (cb) {\n            this._doneList.push(cb);\n        }\n        return this;\n    },\n\n    /**\n     * @return {Array.<module:zrender/animation/Clip>}\n     */\n    getClips: function () {\n        return this._clipList;\n    }\n};\n\nvar dpr = 1;\n\n// If in browser environment\nif (typeof window !== 'undefined') {\n    dpr = Math.max(window.devicePixelRatio || 1, 1);\n}\n\n/**\n * config默认配置项\n * @exports zrender/config\n * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)\n */\n\n/**\n * debug日志选项：catchBrushException为true下有效\n * 0 : 不生成debug数据，发布用\n * 1 : 异常抛出，调试用\n * 2 : 控制台输出，调试用\n */\nvar debugMode = 0;\n\n// retina 屏幕优化\nvar devicePixelRatio = dpr;\n\nvar log = function () {\n};\n\nif (debugMode === 1) {\n    log = function () {\n        for (var k in arguments) {\n            throw new Error(arguments[k]);\n        }\n    };\n}\nelse if (debugMode > 1) {\n    log = function () {\n        for (var k in arguments) {\n            console.log(arguments[k]);\n        }\n    };\n}\n\nvar log$1 = log;\n\n/**\n * @alias modue:zrender/mixin/Animatable\n * @constructor\n */\nvar Animatable = function () {\n\n    /**\n     * @type {Array.<module:zrender/animation/Animator>}\n     * @readOnly\n     */\n    this.animators = [];\n};\n\nAnimatable.prototype = {\n\n    constructor: Animatable,\n\n    /**\n     * 动画\n     *\n     * @param {string} path The path to fetch value from object, like 'a.b.c'.\n     * @param {boolean} [loop] Whether to loop animation.\n     * @return {module:zrender/animation/Animator}\n     * @example:\n     *     el.animate('style', false)\n     *         .when(1000, {x: 10} )\n     *         .done(function(){ // Animation done })\n     *         .start()\n     */\n    animate: function (path, loop) {\n        var target;\n        var animatingShape = false;\n        var el = this;\n        var zr = this.__zr;\n        if (path) {\n            var pathSplitted = path.split('.');\n            var prop = el;\n            // If animating shape\n            animatingShape = pathSplitted[0] === 'shape';\n            for (var i = 0, l = pathSplitted.length; i < l; i++) {\n                if (!prop) {\n                    continue;\n                }\n                prop = prop[pathSplitted[i]];\n            }\n            if (prop) {\n                target = prop;\n            }\n        }\n        else {\n            target = el;\n        }\n\n        if (!target) {\n            log$1(\n                'Property \"'\n                + path\n                + '\" is not existed in element '\n                + el.id\n            );\n            return;\n        }\n\n        var animators = el.animators;\n\n        var animator = new Animator(target, loop);\n\n        animator.during(function (target) {\n            el.dirty(animatingShape);\n        })\n        .done(function () {\n            // FIXME Animator will not be removed if use `Animator#stop` to stop animation\n            animators.splice(indexOf(animators, animator), 1);\n        });\n\n        animators.push(animator);\n\n        // If animate after added to the zrender\n        if (zr) {\n            zr.animation.addAnimator(animator);\n        }\n\n        return animator;\n    },\n\n    /**\n     * 停止动画\n     * @param {boolean} forwardToLast If move to last frame before stop\n     */\n    stopAnimation: function (forwardToLast) {\n        var animators = this.animators;\n        var len = animators.length;\n        for (var i = 0; i < len; i++) {\n            animators[i].stop(forwardToLast);\n        }\n        animators.length = 0;\n\n        return this;\n    },\n\n    /**\n     * Caution: this method will stop previous animation.\n     * So do not use this method to one element twice before\n     * animation starts, unless you know what you are doing.\n     * @param {Object} target\n     * @param {number} [time=500] Time in ms\n     * @param {string} [easing='linear']\n     * @param {number} [delay=0]\n     * @param {Function} [callback]\n     * @param {Function} [forceAnimate] Prevent stop animation and callback\n     *        immediently when target values are the same as current values.\n     *\n     * @example\n     *  // Animate position\n     *  el.animateTo({\n     *      position: [10, 10]\n     *  }, function () { // done })\n     *\n     *  // Animate shape, style and position in 100ms, delayed 100ms, with cubicOut easing\n     *  el.animateTo({\n     *      shape: {\n     *          width: 500\n     *      },\n     *      style: {\n     *          fill: 'red'\n     *      }\n     *      position: [10, 10]\n     *  }, 100, 100, 'cubicOut', function () { // done })\n     */\n    // TODO Return animation key\n    animateTo: function (target, time, delay, easing, callback, forceAnimate) {\n        animateTo(this, target, time, delay, easing, callback, forceAnimate);\n    },\n\n    /**\n     * Animate from the target state to current state.\n     * The params and the return value are the same as `this.animateTo`.\n     */\n    animateFrom: function (target, time, delay, easing, callback, forceAnimate) {\n        animateTo(this, target, time, delay, easing, callback, forceAnimate, true);\n    }\n};\n\nfunction animateTo(animatable, target, time, delay, easing, callback, forceAnimate, reverse) {\n    // animateTo(target, time, easing, callback);\n    if (isString(delay)) {\n        callback = easing;\n        easing = delay;\n        delay = 0;\n    }\n    // animateTo(target, time, delay, callback);\n    else if (isFunction$1(easing)) {\n        callback = easing;\n        easing = 'linear';\n        delay = 0;\n    }\n    // animateTo(target, time, callback);\n    else if (isFunction$1(delay)) {\n        callback = delay;\n        delay = 0;\n    }\n    // animateTo(target, callback)\n    else if (isFunction$1(time)) {\n        callback = time;\n        time = 500;\n    }\n    // animateTo(target)\n    else if (!time) {\n        time = 500;\n    }\n    // Stop all previous animations\n    animatable.stopAnimation();\n    animateToShallow(animatable, '', animatable, target, time, delay, reverse);\n\n    // Animators may be removed immediately after start\n    // if there is nothing to animate\n    var animators = animatable.animators.slice();\n    var count = animators.length;\n    function done() {\n        count--;\n        if (!count) {\n            callback && callback();\n        }\n    }\n\n    // No animators. This should be checked before animators[i].start(),\n    // because 'done' may be executed immediately if no need to animate.\n    if (!count) {\n        callback && callback();\n    }\n    // Start after all animators created\n    // Incase any animator is done immediately when all animation properties are not changed\n    for (var i = 0; i < animators.length; i++) {\n        animators[i]\n            .done(done)\n            .start(easing, forceAnimate);\n    }\n}\n\n/**\n * @param {string} path=''\n * @param {Object} source=animatable\n * @param {Object} target\n * @param {number} [time=500]\n * @param {number} [delay=0]\n * @param {boolean} [reverse] If `true`, animate\n *        from the `target` to current state.\n *\n * @example\n *  // Animate position\n *  el._animateToShallow({\n *      position: [10, 10]\n *  })\n *\n *  // Animate shape, style and position in 100ms, delayed 100ms\n *  el._animateToShallow({\n *      shape: {\n *          width: 500\n *      },\n *      style: {\n *          fill: 'red'\n *      }\n *      position: [10, 10]\n *  }, 100, 100)\n */\nfunction animateToShallow(animatable, path, source, target, time, delay, reverse) {\n    var objShallow = {};\n    var propertyCount = 0;\n    for (var name in target) {\n        if (!target.hasOwnProperty(name)) {\n            continue;\n        }\n\n        if (source[name] != null) {\n            if (isObject$1(target[name]) && !isArrayLike(target[name])) {\n                animateToShallow(\n                    animatable,\n                    path ? path + '.' + name : name,\n                    source[name],\n                    target[name],\n                    time,\n                    delay,\n                    reverse\n                );\n            }\n            else {\n                if (reverse) {\n                    objShallow[name] = source[name];\n                    setAttrByPath(animatable, path, name, target[name]);\n                }\n                else {\n                    objShallow[name] = target[name];\n                }\n                propertyCount++;\n            }\n        }\n        else if (target[name] != null && !reverse) {\n            setAttrByPath(animatable, path, name, target[name]);\n        }\n    }\n\n    if (propertyCount > 0) {\n        animatable.animate(path, false)\n            .when(time == null ? 500 : time, objShallow)\n            .delay(delay || 0);\n    }\n}\n\nfunction setAttrByPath(el, path, name, value) {\n    // Attr directly if not has property\n    // FIXME, if some property not needed for element ?\n    if (!path) {\n        el.attr(name, value);\n    }\n    else {\n        // Only support set shape or style\n        var props = {};\n        props[path] = {};\n        props[path][name] = value;\n        el.attr(props);\n    }\n}\n\n/**\n * @alias module:zrender/Element\n * @constructor\n * @extends {module:zrender/mixin/Animatable}\n * @extends {module:zrender/mixin/Transformable}\n * @extends {module:zrender/mixin/Eventful}\n */\nvar Element = function (opts) { // jshint ignore:line\n\n    Transformable.call(this, opts);\n    Eventful.call(this, opts);\n    Animatable.call(this, opts);\n\n    /**\n     * 画布元素ID\n     * @type {string}\n     */\n    this.id = opts.id || guid();\n};\n\nElement.prototype = {\n\n    /**\n     * 元素类型\n     * Element type\n     * @type {string}\n     */\n    type: 'element',\n\n    /**\n     * 元素名字\n     * Element name\n     * @type {string}\n     */\n    name: '',\n\n    /**\n     * ZRender 实例对象，会在 element 添加到 zrender 实例中后自动赋值\n     * ZRender instance will be assigned when element is associated with zrender\n     * @name module:/zrender/Element#__zr\n     * @type {module:zrender/ZRender}\n     */\n    __zr: null,\n\n    /**\n     * 图形是否忽略，为true时忽略图形的绘制以及事件触发\n     * If ignore drawing and events of the element object\n     * @name module:/zrender/Element#ignore\n     * @type {boolean}\n     * @default false\n     */\n    ignore: false,\n\n    /**\n     * 用于裁剪的路径(shape)，所有 Group 内的路径在绘制时都会被这个路径裁剪\n     * 该路径会继承被裁减对象的变换\n     * @type {module:zrender/graphic/Path}\n     * @see http://www.w3.org/TR/2dcontext/#clipping-region\n     * @readOnly\n     */\n    clipPath: null,\n\n    /**\n     * 是否是 Group\n     * @type {boolean}\n     */\n    isGroup: false,\n\n    /**\n     * Drift element\n     * @param  {number} dx dx on the global space\n     * @param  {number} dy dy on the global space\n     */\n    drift: function (dx, dy) {\n        switch (this.draggable) {\n            case 'horizontal':\n                dy = 0;\n                break;\n            case 'vertical':\n                dx = 0;\n                break;\n        }\n\n        var m = this.transform;\n        if (!m) {\n            m = this.transform = [1, 0, 0, 1, 0, 0];\n        }\n        m[4] += dx;\n        m[5] += dy;\n\n        this.decomposeTransform();\n        this.dirty(false);\n    },\n\n    /**\n     * Hook before update\n     */\n    beforeUpdate: function () {},\n    /**\n     * Hook after update\n     */\n    afterUpdate: function () {},\n    /**\n     * Update each frame\n     */\n    update: function () {\n        this.updateTransform();\n    },\n\n    /**\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {},\n\n    /**\n     * @protected\n     */\n    attrKV: function (key, value) {\n        if (key === 'position' || key === 'scale' || key === 'origin') {\n            // Copy the array\n            if (value) {\n                var target = this[key];\n                if (!target) {\n                    target = this[key] = [];\n                }\n                target[0] = value[0];\n                target[1] = value[1];\n            }\n        }\n        else {\n            this[key] = value;\n        }\n    },\n\n    /**\n     * Hide the element\n     */\n    hide: function () {\n        this.ignore = true;\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * Show the element\n     */\n    show: function () {\n        this.ignore = false;\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * @param {string|Object} key\n     * @param {*} value\n     */\n    attr: function (key, value) {\n        if (typeof key === 'string') {\n            this.attrKV(key, value);\n        }\n        else if (isObject$1(key)) {\n            for (var name in key) {\n                if (key.hasOwnProperty(name)) {\n                    this.attrKV(name, key[name]);\n                }\n            }\n        }\n\n        this.dirty(false);\n\n        return this;\n    },\n\n    /**\n     * @param {module:zrender/graphic/Path} clipPath\n     */\n    setClipPath: function (clipPath) {\n        var zr = this.__zr;\n        if (zr) {\n            clipPath.addSelfToZr(zr);\n        }\n\n        // Remove previous clip path\n        if (this.clipPath && this.clipPath !== clipPath) {\n            this.removeClipPath();\n        }\n\n        this.clipPath = clipPath;\n        clipPath.__zr = zr;\n        clipPath.__clipTarget = this;\n\n        this.dirty(false);\n    },\n\n    /**\n     */\n    removeClipPath: function () {\n        var clipPath = this.clipPath;\n        if (clipPath) {\n            if (clipPath.__zr) {\n                clipPath.removeSelfFromZr(clipPath.__zr);\n            }\n\n            clipPath.__zr = null;\n            clipPath.__clipTarget = null;\n            this.clipPath = null;\n\n            this.dirty(false);\n        }\n    },\n\n    /**\n     * Add self from zrender instance.\n     * Not recursively because it will be invoked when element added to storage.\n     * @param {module:zrender/ZRender} zr\n     */\n    addSelfToZr: function (zr) {\n        this.__zr = zr;\n        // 添加动画\n        var animators = this.animators;\n        if (animators) {\n            for (var i = 0; i < animators.length; i++) {\n                zr.animation.addAnimator(animators[i]);\n            }\n        }\n\n        if (this.clipPath) {\n            this.clipPath.addSelfToZr(zr);\n        }\n    },\n\n    /**\n     * Remove self from zrender instance.\n     * Not recursively because it will be invoked when element added to storage.\n     * @param {module:zrender/ZRender} zr\n     */\n    removeSelfFromZr: function (zr) {\n        this.__zr = null;\n        // 移除动画\n        var animators = this.animators;\n        if (animators) {\n            for (var i = 0; i < animators.length; i++) {\n                zr.animation.removeAnimator(animators[i]);\n            }\n        }\n\n        if (this.clipPath) {\n            this.clipPath.removeSelfFromZr(zr);\n        }\n    }\n};\n\nmixin(Element, Animatable);\nmixin(Element, Transformable);\nmixin(Element, Eventful);\n\n/**\n * @module echarts/core/BoundingRect\n */\n\nvar v2ApplyTransform = applyTransform;\nvar mathMin = Math.min;\nvar mathMax = Math.max;\n\n/**\n * @alias module:echarts/core/BoundingRect\n */\nfunction BoundingRect(x, y, width, height) {\n\n    if (width < 0) {\n        x = x + width;\n        width = -width;\n    }\n    if (height < 0) {\n        y = y + height;\n        height = -height;\n    }\n\n    /**\n     * @type {number}\n     */\n    this.x = x;\n    /**\n     * @type {number}\n     */\n    this.y = y;\n    /**\n     * @type {number}\n     */\n    this.width = width;\n    /**\n     * @type {number}\n     */\n    this.height = height;\n}\n\nBoundingRect.prototype = {\n\n    constructor: BoundingRect,\n\n    /**\n     * @param {module:echarts/core/BoundingRect} other\n     */\n    union: function (other) {\n        var x = mathMin(other.x, this.x);\n        var y = mathMin(other.y, this.y);\n\n        this.width = mathMax(\n                other.x + other.width,\n                this.x + this.width\n            ) - x;\n        this.height = mathMax(\n                other.y + other.height,\n                this.y + this.height\n            ) - y;\n        this.x = x;\n        this.y = y;\n    },\n\n    /**\n     * @param {Array.<number>} m\n     * @methods\n     */\n    applyTransform: (function () {\n        var lt = [];\n        var rb = [];\n        var lb = [];\n        var rt = [];\n        return function (m) {\n            // In case usage like this\n            // el.getBoundingRect().applyTransform(el.transform)\n            // And element has no transform\n            if (!m) {\n                return;\n            }\n            lt[0] = lb[0] = this.x;\n            lt[1] = rt[1] = this.y;\n            rb[0] = rt[0] = this.x + this.width;\n            rb[1] = lb[1] = this.y + this.height;\n\n            v2ApplyTransform(lt, lt, m);\n            v2ApplyTransform(rb, rb, m);\n            v2ApplyTransform(lb, lb, m);\n            v2ApplyTransform(rt, rt, m);\n\n            this.x = mathMin(lt[0], rb[0], lb[0], rt[0]);\n            this.y = mathMin(lt[1], rb[1], lb[1], rt[1]);\n            var maxX = mathMax(lt[0], rb[0], lb[0], rt[0]);\n            var maxY = mathMax(lt[1], rb[1], lb[1], rt[1]);\n            this.width = maxX - this.x;\n            this.height = maxY - this.y;\n        };\n    })(),\n\n    /**\n     * Calculate matrix of transforming from self to target rect\n     * @param  {module:zrender/core/BoundingRect} b\n     * @return {Array.<number>}\n     */\n    calculateTransform: function (b) {\n        var a = this;\n        var sx = b.width / a.width;\n        var sy = b.height / a.height;\n\n        var m = create$1();\n\n        // 矩阵右乘\n        translate(m, m, [-a.x, -a.y]);\n        scale$1(m, m, [sx, sy]);\n        translate(m, m, [b.x, b.y]);\n\n        return m;\n    },\n\n    /**\n     * @param {(module:echarts/core/BoundingRect|Object)} b\n     * @return {boolean}\n     */\n    intersect: function (b) {\n        if (!b) {\n            return false;\n        }\n\n        if (!(b instanceof BoundingRect)) {\n            // Normalize negative width/height.\n            b = BoundingRect.create(b);\n        }\n\n        var a = this;\n        var ax0 = a.x;\n        var ax1 = a.x + a.width;\n        var ay0 = a.y;\n        var ay1 = a.y + a.height;\n\n        var bx0 = b.x;\n        var bx1 = b.x + b.width;\n        var by0 = b.y;\n        var by1 = b.y + b.height;\n\n        return !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);\n    },\n\n    contain: function (x, y) {\n        var rect = this;\n        return x >= rect.x\n            && x <= (rect.x + rect.width)\n            && y >= rect.y\n            && y <= (rect.y + rect.height);\n    },\n\n    /**\n     * @return {module:echarts/core/BoundingRect}\n     */\n    clone: function () {\n        return new BoundingRect(this.x, this.y, this.width, this.height);\n    },\n\n    /**\n     * Copy from another rect\n     */\n    copy: function (other) {\n        this.x = other.x;\n        this.y = other.y;\n        this.width = other.width;\n        this.height = other.height;\n    },\n\n    plain: function () {\n        return {\n            x: this.x,\n            y: this.y,\n            width: this.width,\n            height: this.height\n        };\n    }\n};\n\n/**\n * @param {Object|module:zrender/core/BoundingRect} rect\n * @param {number} rect.x\n * @param {number} rect.y\n * @param {number} rect.width\n * @param {number} rect.height\n * @return {module:zrender/core/BoundingRect}\n */\nBoundingRect.create = function (rect) {\n    return new BoundingRect(rect.x, rect.y, rect.width, rect.height);\n};\n\n/**\n * Group是一个容器，可以插入子节点，Group的变换也会被应用到子节点上\n * @module zrender/graphic/Group\n * @example\n *     var Group = require('zrender/container/Group');\n *     var Circle = require('zrender/graphic/shape/Circle');\n *     var g = new Group();\n *     g.position[0] = 100;\n *     g.position[1] = 100;\n *     g.add(new Circle({\n *         style: {\n *             x: 100,\n *             y: 100,\n *             r: 20,\n *         }\n *     }));\n *     zr.add(g);\n */\n\n/**\n * @alias module:zrender/graphic/Group\n * @constructor\n * @extends module:zrender/mixin/Transformable\n * @extends module:zrender/mixin/Eventful\n */\nvar Group = function (opts) {\n\n    opts = opts || {};\n\n    Element.call(this, opts);\n\n    for (var key in opts) {\n        if (opts.hasOwnProperty(key)) {\n            this[key] = opts[key];\n        }\n    }\n\n    this._children = [];\n\n    this.__storage = null;\n\n    this.__dirty = true;\n};\n\nGroup.prototype = {\n\n    constructor: Group,\n\n    isGroup: true,\n\n    /**\n     * @type {string}\n     */\n    type: 'group',\n\n    /**\n     * 所有子孙元素是否响应鼠标事件\n     * @name module:/zrender/container/Group#silent\n     * @type {boolean}\n     * @default false\n     */\n    silent: false,\n\n    /**\n     * @return {Array.<module:zrender/Element>}\n     */\n    children: function () {\n        return this._children.slice();\n    },\n\n    /**\n     * 获取指定 index 的儿子节点\n     * @param  {number} idx\n     * @return {module:zrender/Element}\n     */\n    childAt: function (idx) {\n        return this._children[idx];\n    },\n\n    /**\n     * 获取指定名字的儿子节点\n     * @param  {string} name\n     * @return {module:zrender/Element}\n     */\n    childOfName: function (name) {\n        var children = this._children;\n        for (var i = 0; i < children.length; i++) {\n            if (children[i].name === name) {\n                return children[i];\n            }\n            }\n    },\n\n    /**\n     * @return {number}\n     */\n    childCount: function () {\n        return this._children.length;\n    },\n\n    /**\n     * 添加子节点到最后\n     * @param {module:zrender/Element} child\n     */\n    add: function (child) {\n        if (child && child !== this && child.parent !== this) {\n\n            this._children.push(child);\n\n            this._doAdd(child);\n        }\n\n        return this;\n    },\n\n    /**\n     * 添加子节点在 nextSibling 之前\n     * @param {module:zrender/Element} child\n     * @param {module:zrender/Element} nextSibling\n     */\n    addBefore: function (child, nextSibling) {\n        if (child && child !== this && child.parent !== this\n            && nextSibling && nextSibling.parent === this) {\n\n            var children = this._children;\n            var idx = children.indexOf(nextSibling);\n\n            if (idx >= 0) {\n                children.splice(idx, 0, child);\n                this._doAdd(child);\n            }\n        }\n\n        return this;\n    },\n\n    _doAdd: function (child) {\n        if (child.parent) {\n            child.parent.remove(child);\n        }\n\n        child.parent = this;\n\n        var storage = this.__storage;\n        var zr = this.__zr;\n        if (storage && storage !== child.__storage) {\n\n            storage.addToStorage(child);\n\n            if (child instanceof Group) {\n                child.addChildrenToStorage(storage);\n            }\n        }\n\n        zr && zr.refresh();\n    },\n\n    /**\n     * 移除子节点\n     * @param {module:zrender/Element} child\n     */\n    remove: function (child) {\n        var zr = this.__zr;\n        var storage = this.__storage;\n        var children = this._children;\n\n        var idx = indexOf(children, child);\n        if (idx < 0) {\n            return this;\n        }\n        children.splice(idx, 1);\n\n        child.parent = null;\n\n        if (storage) {\n\n            storage.delFromStorage(child);\n\n            if (child instanceof Group) {\n                child.delChildrenFromStorage(storage);\n            }\n        }\n\n        zr && zr.refresh();\n\n        return this;\n    },\n\n    /**\n     * 移除所有子节点\n     */\n    removeAll: function () {\n        var children = this._children;\n        var storage = this.__storage;\n        var child;\n        var i;\n        for (i = 0; i < children.length; i++) {\n            child = children[i];\n            if (storage) {\n                storage.delFromStorage(child);\n                if (child instanceof Group) {\n                    child.delChildrenFromStorage(storage);\n                }\n            }\n            child.parent = null;\n        }\n        children.length = 0;\n\n        return this;\n    },\n\n    /**\n     * 遍历所有子节点\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    eachChild: function (cb, context) {\n        var children = this._children;\n        for (var i = 0; i < children.length; i++) {\n            var child = children[i];\n            cb.call(context, child, i);\n        }\n        return this;\n    },\n\n    /**\n     * 深度优先遍历所有子孙节点\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            cb.call(context, child);\n\n            if (child.type === 'group') {\n                child.traverse(cb, context);\n            }\n        }\n        return this;\n    },\n\n    addChildrenToStorage: function (storage) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            storage.addToStorage(child);\n            if (child instanceof Group) {\n                child.addChildrenToStorage(storage);\n            }\n        }\n    },\n\n    delChildrenFromStorage: function (storage) {\n        for (var i = 0; i < this._children.length; i++) {\n            var child = this._children[i];\n            storage.delFromStorage(child);\n            if (child instanceof Group) {\n                child.delChildrenFromStorage(storage);\n            }\n        }\n    },\n\n    dirty: function () {\n        this.__dirty = true;\n        this.__zr && this.__zr.refresh();\n        return this;\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function (includeChildren) {\n        // TODO Caching\n        var rect = null;\n        var tmpRect = new BoundingRect(0, 0, 0, 0);\n        var children = includeChildren || this._children;\n        var tmpMat = [];\n\n        for (var i = 0; i < children.length; i++) {\n            var child = children[i];\n            if (child.ignore || child.invisible) {\n                continue;\n            }\n\n            var childRect = child.getBoundingRect();\n            var transform = child.getLocalTransform(tmpMat);\n            // TODO\n            // The boundingRect cacluated by transforming original\n            // rect may be bigger than the actual bundingRect when rotation\n            // is used. (Consider a circle rotated aginst its center, where\n            // the actual boundingRect should be the same as that not be\n            // rotated.) But we can not find better approach to calculate\n            // actual boundingRect yet, considering performance.\n            if (transform) {\n                tmpRect.copy(childRect);\n                tmpRect.applyTransform(transform);\n                rect = rect || tmpRect.clone();\n                rect.union(tmpRect);\n            }\n            else {\n                rect = rect || childRect.clone();\n                rect.union(childRect);\n            }\n        }\n        return rect || tmpRect;\n    }\n};\n\ninherits(Group, Element);\n\n// https://github.com/mziccard/node-timsort\nvar DEFAULT_MIN_MERGE = 32;\n\nvar DEFAULT_MIN_GALLOPING = 7;\n\nfunction minRunLength(n) {\n    var r = 0;\n\n    while (n >= DEFAULT_MIN_MERGE) {\n        r |= n & 1;\n        n >>= 1;\n    }\n\n    return n + r;\n}\n\nfunction makeAscendingRun(array, lo, hi, compare) {\n    var runHi = lo + 1;\n\n    if (runHi === hi) {\n        return 1;\n    }\n\n    if (compare(array[runHi++], array[lo]) < 0) {\n        while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {\n            runHi++;\n        }\n\n        reverseRun(array, lo, runHi);\n    }\n    else {\n        while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {\n            runHi++;\n        }\n    }\n\n    return runHi - lo;\n}\n\nfunction reverseRun(array, lo, hi) {\n    hi--;\n\n    while (lo < hi) {\n        var t = array[lo];\n        array[lo++] = array[hi];\n        array[hi--] = t;\n    }\n}\n\nfunction binaryInsertionSort(array, lo, hi, start, compare) {\n    if (start === lo) {\n        start++;\n    }\n\n    for (; start < hi; start++) {\n        var pivot = array[start];\n\n        var left = lo;\n        var right = start;\n        var mid;\n\n        while (left < right) {\n            mid = left + right >>> 1;\n\n            if (compare(pivot, array[mid]) < 0) {\n                right = mid;\n            }\n            else {\n                left = mid + 1;\n            }\n        }\n\n        var n = start - left;\n\n        switch (n) {\n            case 3:\n                array[left + 3] = array[left + 2];\n\n            case 2:\n                array[left + 2] = array[left + 1];\n\n            case 1:\n                array[left + 1] = array[left];\n                break;\n            default:\n                while (n > 0) {\n                    array[left + n] = array[left + n - 1];\n                    n--;\n                }\n        }\n\n        array[left] = pivot;\n    }\n}\n\nfunction gallopLeft(value, array, start, length, hint, compare) {\n    var lastOffset = 0;\n    var maxOffset = 0;\n    var offset = 1;\n\n    if (compare(value, array[start + hint]) > 0) {\n        maxOffset = length - hint;\n\n        while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        lastOffset += hint;\n        offset += hint;\n    }\n    else {\n        maxOffset = hint + 1;\n        while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        var tmp = lastOffset;\n        lastOffset = hint - offset;\n        offset = hint - tmp;\n    }\n\n    lastOffset++;\n    while (lastOffset < offset) {\n        var m = lastOffset + (offset - lastOffset >>> 1);\n\n        if (compare(value, array[start + m]) > 0) {\n            lastOffset = m + 1;\n        }\n        else {\n            offset = m;\n        }\n    }\n    return offset;\n}\n\nfunction gallopRight(value, array, start, length, hint, compare) {\n    var lastOffset = 0;\n    var maxOffset = 0;\n    var offset = 1;\n\n    if (compare(value, array[start + hint]) < 0) {\n        maxOffset = hint + 1;\n\n        while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        var tmp = lastOffset;\n        lastOffset = hint - offset;\n        offset = hint - tmp;\n    }\n    else {\n        maxOffset = length - hint;\n\n        while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {\n            lastOffset = offset;\n            offset = (offset << 1) + 1;\n\n            if (offset <= 0) {\n                offset = maxOffset;\n            }\n        }\n\n        if (offset > maxOffset) {\n            offset = maxOffset;\n        }\n\n        lastOffset += hint;\n        offset += hint;\n    }\n\n    lastOffset++;\n\n    while (lastOffset < offset) {\n        var m = lastOffset + (offset - lastOffset >>> 1);\n\n        if (compare(value, array[start + m]) < 0) {\n            offset = m;\n        }\n        else {\n            lastOffset = m + 1;\n        }\n    }\n\n    return offset;\n}\n\nfunction TimSort(array, compare) {\n    var minGallop = DEFAULT_MIN_GALLOPING;\n    var runStart;\n    var runLength;\n    var stackSize = 0;\n\n    var tmp = [];\n\n    runStart = [];\n    runLength = [];\n\n    function pushRun(_runStart, _runLength) {\n        runStart[stackSize] = _runStart;\n        runLength[stackSize] = _runLength;\n        stackSize += 1;\n    }\n\n    function mergeRuns() {\n        while (stackSize > 1) {\n            var n = stackSize - 2;\n\n            if (n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1] || n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1]) {\n                if (runLength[n - 1] < runLength[n + 1]) {\n                    n--;\n                }\n            }\n            else if (runLength[n] > runLength[n + 1]) {\n                break;\n            }\n            mergeAt(n);\n        }\n    }\n\n    function forceMergeRuns() {\n        while (stackSize > 1) {\n            var n = stackSize - 2;\n\n            if (n > 0 && runLength[n - 1] < runLength[n + 1]) {\n                n--;\n            }\n\n            mergeAt(n);\n        }\n    }\n\n    function mergeAt(i) {\n        var start1 = runStart[i];\n        var length1 = runLength[i];\n        var start2 = runStart[i + 1];\n        var length2 = runLength[i + 1];\n\n        runLength[i] = length1 + length2;\n\n        if (i === stackSize - 3) {\n            runStart[i + 1] = runStart[i + 2];\n            runLength[i + 1] = runLength[i + 2];\n        }\n\n        stackSize--;\n\n        var k = gallopRight(array[start2], array, start1, length1, 0, compare);\n        start1 += k;\n        length1 -= k;\n\n        if (length1 === 0) {\n            return;\n        }\n\n        length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);\n\n        if (length2 === 0) {\n            return;\n        }\n\n        if (length1 <= length2) {\n            mergeLow(start1, length1, start2, length2);\n        }\n        else {\n            mergeHigh(start1, length1, start2, length2);\n        }\n    }\n\n    function mergeLow(start1, length1, start2, length2) {\n        var i = 0;\n\n        for (i = 0; i < length1; i++) {\n            tmp[i] = array[start1 + i];\n        }\n\n        var cursor1 = 0;\n        var cursor2 = start2;\n        var dest = start1;\n\n        array[dest++] = array[cursor2++];\n\n        if (--length2 === 0) {\n            for (i = 0; i < length1; i++) {\n                array[dest + i] = tmp[cursor1 + i];\n            }\n            return;\n        }\n\n        if (length1 === 1) {\n            for (i = 0; i < length2; i++) {\n                array[dest + i] = array[cursor2 + i];\n            }\n            array[dest + length2] = tmp[cursor1];\n            return;\n        }\n\n        var _minGallop = minGallop;\n        var count1, count2, exit;\n\n        while (1) {\n            count1 = 0;\n            count2 = 0;\n            exit = false;\n\n            do {\n                if (compare(array[cursor2], tmp[cursor1]) < 0) {\n                    array[dest++] = array[cursor2++];\n                    count2++;\n                    count1 = 0;\n\n                    if (--length2 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                else {\n                    array[dest++] = tmp[cursor1++];\n                    count1++;\n                    count2 = 0;\n                    if (--length1 === 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n            } while ((count1 | count2) < _minGallop);\n\n            if (exit) {\n                break;\n            }\n\n            do {\n                count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);\n\n                if (count1 !== 0) {\n                    for (i = 0; i < count1; i++) {\n                        array[dest + i] = tmp[cursor1 + i];\n                    }\n\n                    dest += count1;\n                    cursor1 += count1;\n                    length1 -= count1;\n                    if (length1 <= 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest++] = array[cursor2++];\n\n                if (--length2 === 0) {\n                    exit = true;\n                    break;\n                }\n\n                count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);\n\n                if (count2 !== 0) {\n                    for (i = 0; i < count2; i++) {\n                        array[dest + i] = array[cursor2 + i];\n                    }\n\n                    dest += count2;\n                    cursor2 += count2;\n                    length2 -= count2;\n\n                    if (length2 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                array[dest++] = tmp[cursor1++];\n\n                if (--length1 === 1) {\n                    exit = true;\n                    break;\n                }\n\n                _minGallop--;\n            } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);\n\n            if (exit) {\n                break;\n            }\n\n            if (_minGallop < 0) {\n                _minGallop = 0;\n            }\n\n            _minGallop += 2;\n        }\n\n        minGallop = _minGallop;\n\n        minGallop < 1 && (minGallop = 1);\n\n        if (length1 === 1) {\n            for (i = 0; i < length2; i++) {\n                array[dest + i] = array[cursor2 + i];\n            }\n            array[dest + length2] = tmp[cursor1];\n        }\n        else if (length1 === 0) {\n            throw new Error();\n            // throw new Error('mergeLow preconditions were not respected');\n        }\n        else {\n            for (i = 0; i < length1; i++) {\n                array[dest + i] = tmp[cursor1 + i];\n            }\n        }\n    }\n\n    function mergeHigh(start1, length1, start2, length2) {\n        var i = 0;\n\n        for (i = 0; i < length2; i++) {\n            tmp[i] = array[start2 + i];\n        }\n\n        var cursor1 = start1 + length1 - 1;\n        var cursor2 = length2 - 1;\n        var dest = start2 + length2 - 1;\n        var customCursor = 0;\n        var customDest = 0;\n\n        array[dest--] = array[cursor1--];\n\n        if (--length1 === 0) {\n            customCursor = dest - (length2 - 1);\n\n            for (i = 0; i < length2; i++) {\n                array[customCursor + i] = tmp[i];\n            }\n\n            return;\n        }\n\n        if (length2 === 1) {\n            dest -= length1;\n            cursor1 -= length1;\n            customDest = dest + 1;\n            customCursor = cursor1 + 1;\n\n            for (i = length1 - 1; i >= 0; i--) {\n                array[customDest + i] = array[customCursor + i];\n            }\n\n            array[dest] = tmp[cursor2];\n            return;\n        }\n\n        var _minGallop = minGallop;\n\n        while (true) {\n            var count1 = 0;\n            var count2 = 0;\n            var exit = false;\n\n            do {\n                if (compare(tmp[cursor2], array[cursor1]) < 0) {\n                    array[dest--] = array[cursor1--];\n                    count1++;\n                    count2 = 0;\n                    if (--length1 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n                else {\n                    array[dest--] = tmp[cursor2--];\n                    count2++;\n                    count1 = 0;\n                    if (--length2 === 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n            } while ((count1 | count2) < _minGallop);\n\n            if (exit) {\n                break;\n            }\n\n            do {\n                count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);\n\n                if (count1 !== 0) {\n                    dest -= count1;\n                    cursor1 -= count1;\n                    length1 -= count1;\n                    customDest = dest + 1;\n                    customCursor = cursor1 + 1;\n\n                    for (i = count1 - 1; i >= 0; i--) {\n                        array[customDest + i] = array[customCursor + i];\n                    }\n\n                    if (length1 === 0) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest--] = tmp[cursor2--];\n\n                if (--length2 === 1) {\n                    exit = true;\n                    break;\n                }\n\n                count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);\n\n                if (count2 !== 0) {\n                    dest -= count2;\n                    cursor2 -= count2;\n                    length2 -= count2;\n                    customDest = dest + 1;\n                    customCursor = cursor2 + 1;\n\n                    for (i = 0; i < count2; i++) {\n                        array[customDest + i] = tmp[customCursor + i];\n                    }\n\n                    if (length2 <= 1) {\n                        exit = true;\n                        break;\n                    }\n                }\n\n                array[dest--] = array[cursor1--];\n\n                if (--length1 === 0) {\n                    exit = true;\n                    break;\n                }\n\n                _minGallop--;\n            } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);\n\n            if (exit) {\n                break;\n            }\n\n            if (_minGallop < 0) {\n                _minGallop = 0;\n            }\n\n            _minGallop += 2;\n        }\n\n        minGallop = _minGallop;\n\n        if (minGallop < 1) {\n            minGallop = 1;\n        }\n\n        if (length2 === 1) {\n            dest -= length1;\n            cursor1 -= length1;\n            customDest = dest + 1;\n            customCursor = cursor1 + 1;\n\n            for (i = length1 - 1; i >= 0; i--) {\n                array[customDest + i] = array[customCursor + i];\n            }\n\n            array[dest] = tmp[cursor2];\n        }\n        else if (length2 === 0) {\n            throw new Error();\n            // throw new Error('mergeHigh preconditions were not respected');\n        }\n        else {\n            customCursor = dest - (length2 - 1);\n            for (i = 0; i < length2; i++) {\n                array[customCursor + i] = tmp[i];\n            }\n        }\n    }\n\n    this.mergeRuns = mergeRuns;\n    this.forceMergeRuns = forceMergeRuns;\n    this.pushRun = pushRun;\n}\n\nfunction sort(array, compare, lo, hi) {\n    if (!lo) {\n        lo = 0;\n    }\n    if (!hi) {\n        hi = array.length;\n    }\n\n    var remaining = hi - lo;\n\n    if (remaining < 2) {\n        return;\n    }\n\n    var runLength = 0;\n\n    if (remaining < DEFAULT_MIN_MERGE) {\n        runLength = makeAscendingRun(array, lo, hi, compare);\n        binaryInsertionSort(array, lo, hi, lo + runLength, compare);\n        return;\n    }\n\n    var ts = new TimSort(array, compare);\n\n    var minRun = minRunLength(remaining);\n\n    do {\n        runLength = makeAscendingRun(array, lo, hi, compare);\n        if (runLength < minRun) {\n            var force = remaining;\n            if (force > minRun) {\n                force = minRun;\n            }\n\n            binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);\n            runLength = force;\n        }\n\n        ts.pushRun(lo, runLength);\n        ts.mergeRuns();\n\n        remaining -= runLength;\n        lo += runLength;\n    } while (remaining !== 0);\n\n    ts.forceMergeRuns();\n}\n\n// Use timsort because in most case elements are partially sorted\n// https://jsfiddle.net/pissang/jr4x7mdm/8/\nfunction shapeCompareFunc(a, b) {\n    if (a.zlevel === b.zlevel) {\n        if (a.z === b.z) {\n            // if (a.z2 === b.z2) {\n            //     // FIXME Slow has renderidx compare\n            //     // http://stackoverflow.com/questions/20883421/sorting-in-javascript-should-every-compare-function-have-a-return-0-statement\n            //     // https://github.com/v8/v8/blob/47cce544a31ed5577ffe2963f67acb4144ee0232/src/js/array.js#L1012\n            //     return a.__renderidx - b.__renderidx;\n            // }\n            return a.z2 - b.z2;\n        }\n        return a.z - b.z;\n    }\n    return a.zlevel - b.zlevel;\n}\n/**\n * 内容仓库 (M)\n * @alias module:zrender/Storage\n * @constructor\n */\nvar Storage = function () { // jshint ignore:line\n    this._roots = [];\n\n    this._displayList = [];\n\n    this._displayListLen = 0;\n};\n\nStorage.prototype = {\n\n    constructor: Storage,\n\n    /**\n     * @param  {Function} cb\n     *\n     */\n    traverse: function (cb, context) {\n        for (var i = 0; i < this._roots.length; i++) {\n            this._roots[i].traverse(cb, context);\n        }\n    },\n\n    /**\n     * 返回所有图形的绘制队列\n     * @param {boolean} [update=false] 是否在返回前更新该数组\n     * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组, 在 update 为 true 的时候有效\n     *\n     * 详见{@link module:zrender/graphic/Displayable.prototype.updateDisplayList}\n     * @return {Array.<module:zrender/graphic/Displayable>}\n     */\n    getDisplayList: function (update, includeIgnore) {\n        includeIgnore = includeIgnore || false;\n        if (update) {\n            this.updateDisplayList(includeIgnore);\n        }\n        return this._displayList;\n    },\n\n    /**\n     * 更新图形的绘制队列。\n     * 每次绘制前都会调用，该方法会先深度优先遍历整个树，更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中，\n     * 最后根据绘制的优先级（zlevel > z > 插入顺序）排序得到绘制队列\n     * @param {boolean} [includeIgnore=false] 是否包含 ignore 的数组\n     */\n    updateDisplayList: function (includeIgnore) {\n        this._displayListLen = 0;\n\n        var roots = this._roots;\n        var displayList = this._displayList;\n        for (var i = 0, len = roots.length; i < len; i++) {\n            this._updateAndAddDisplayable(roots[i], null, includeIgnore);\n        }\n\n        displayList.length = this._displayListLen;\n\n        env$1.canvasSupported && sort(displayList, shapeCompareFunc);\n    },\n\n    _updateAndAddDisplayable: function (el, clipPaths, includeIgnore) {\n\n        if (el.ignore && !includeIgnore) {\n            return;\n        }\n\n        el.beforeUpdate();\n\n        if (el.__dirty) {\n\n            el.update();\n\n        }\n\n        el.afterUpdate();\n\n        var userSetClipPath = el.clipPath;\n        if (userSetClipPath) {\n\n            // FIXME 效率影响\n            if (clipPaths) {\n                clipPaths = clipPaths.slice();\n            }\n            else {\n                clipPaths = [];\n            }\n\n            var currentClipPath = userSetClipPath;\n            var parentClipPath = el;\n            // Recursively add clip path\n            while (currentClipPath) {\n                // clipPath 的变换是基于使用这个 clipPath 的元素\n                currentClipPath.parent = parentClipPath;\n                currentClipPath.updateTransform();\n\n                clipPaths.push(currentClipPath);\n\n                parentClipPath = currentClipPath;\n                currentClipPath = currentClipPath.clipPath;\n            }\n        }\n\n        if (el.isGroup) {\n            var children = el._children;\n\n            for (var i = 0; i < children.length; i++) {\n                var child = children[i];\n\n                // Force to mark as dirty if group is dirty\n                // FIXME __dirtyPath ?\n                if (el.__dirty) {\n                    child.__dirty = true;\n                }\n\n                this._updateAndAddDisplayable(child, clipPaths, includeIgnore);\n            }\n\n            // Mark group clean here\n            el.__dirty = false;\n\n        }\n        else {\n            el.__clipPaths = clipPaths;\n\n            this._displayList[this._displayListLen++] = el;\n        }\n    },\n\n    /**\n     * 添加图形(Shape)或者组(Group)到根节点\n     * @param {module:zrender/Element} el\n     */\n    addRoot: function (el) {\n        if (el.__storage === this) {\n            return;\n        }\n\n        if (el instanceof Group) {\n            el.addChildrenToStorage(this);\n        }\n\n        this.addToStorage(el);\n        this._roots.push(el);\n    },\n\n    /**\n     * 删除指定的图形(Shape)或者组(Group)\n     * @param {string|Array.<string>} [el] 如果为空清空整个Storage\n     */\n    delRoot: function (el) {\n        if (el == null) {\n            // 不指定el清空\n            for (var i = 0; i < this._roots.length; i++) {\n                var root = this._roots[i];\n                if (root instanceof Group) {\n                    root.delChildrenFromStorage(this);\n                }\n            }\n\n            this._roots = [];\n            this._displayList = [];\n            this._displayListLen = 0;\n\n            return;\n        }\n\n        if (el instanceof Array) {\n            for (var i = 0, l = el.length; i < l; i++) {\n                this.delRoot(el[i]);\n            }\n            return;\n        }\n\n\n        var idx = indexOf(this._roots, el);\n        if (idx >= 0) {\n            this.delFromStorage(el);\n            this._roots.splice(idx, 1);\n            if (el instanceof Group) {\n                el.delChildrenFromStorage(this);\n            }\n        }\n    },\n\n    addToStorage: function (el) {\n        if (el) {\n            el.__storage = this;\n            el.dirty(false);\n        }\n        return this;\n    },\n\n    delFromStorage: function (el) {\n        if (el) {\n            el.__storage = null;\n        }\n\n        return this;\n    },\n\n    /**\n     * 清空并且释放Storage\n     */\n    dispose: function () {\n        this._renderList =\n        this._roots = null;\n    },\n\n    displayableSortFunc: shapeCompareFunc\n};\n\nvar SHADOW_PROPS = {\n    'shadowBlur': 1,\n    'shadowOffsetX': 1,\n    'shadowOffsetY': 1,\n    'textShadowBlur': 1,\n    'textShadowOffsetX': 1,\n    'textShadowOffsetY': 1,\n    'textBoxShadowBlur': 1,\n    'textBoxShadowOffsetX': 1,\n    'textBoxShadowOffsetY': 1\n};\n\nvar fixShadow = function (ctx, propName, value) {\n    if (SHADOW_PROPS.hasOwnProperty(propName)) {\n        return value *= ctx.dpr;\n    }\n    return value;\n};\n\nvar ContextCachedBy = {\n    NONE: 0,\n    STYLE_BIND: 1,\n    PLAIN_TEXT: 2\n};\n\n// Avoid confused with 0/false.\nvar WILL_BE_RESTORED = 9;\n\nvar STYLE_COMMON_PROPS = [\n    ['shadowBlur', 0], ['shadowOffsetX', 0], ['shadowOffsetY', 0], ['shadowColor', '#000'],\n    ['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]\n];\n\n// var SHADOW_PROPS = STYLE_COMMON_PROPS.slice(0, 4);\n// var LINE_PROPS = STYLE_COMMON_PROPS.slice(4);\n\nvar Style = function (opts) {\n    this.extendFrom(opts, false);\n};\n\nfunction createLinearGradient(ctx, obj, rect) {\n    var x = obj.x == null ? 0 : obj.x;\n    var x2 = obj.x2 == null ? 1 : obj.x2;\n    var y = obj.y == null ? 0 : obj.y;\n    var y2 = obj.y2 == null ? 0 : obj.y2;\n\n    if (!obj.global) {\n        x = x * rect.width + rect.x;\n        x2 = x2 * rect.width + rect.x;\n        y = y * rect.height + rect.y;\n        y2 = y2 * rect.height + rect.y;\n    }\n\n    // Fix NaN when rect is Infinity\n    x = isNaN(x) ? 0 : x;\n    x2 = isNaN(x2) ? 1 : x2;\n    y = isNaN(y) ? 0 : y;\n    y2 = isNaN(y2) ? 0 : y2;\n\n    var canvasGradient = ctx.createLinearGradient(x, y, x2, y2);\n\n    return canvasGradient;\n}\n\nfunction createRadialGradient(ctx, obj, rect) {\n    var width = rect.width;\n    var height = rect.height;\n    var min = Math.min(width, height);\n\n    var x = obj.x == null ? 0.5 : obj.x;\n    var y = obj.y == null ? 0.5 : obj.y;\n    var r = obj.r == null ? 0.5 : obj.r;\n    if (!obj.global) {\n        x = x * width + rect.x;\n        y = y * height + rect.y;\n        r = r * min;\n    }\n\n    var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r);\n\n    return canvasGradient;\n}\n\n\nStyle.prototype = {\n\n    constructor: Style,\n\n    /**\n     * @type {string}\n     */\n    fill: '#000',\n\n    /**\n     * @type {string}\n     */\n    stroke: null,\n\n    /**\n     * @type {number}\n     */\n    opacity: 1,\n\n    /**\n     * @type {number}\n     */\n    fillOpacity: null,\n\n    /**\n     * @type {number}\n     */\n    strokeOpacity: null,\n\n    /**\n     * @type {Array.<number>}\n     */\n    lineDash: null,\n\n    /**\n     * @type {number}\n     */\n    lineDashOffset: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    shadowOffsetY: 0,\n\n    /**\n     * @type {number}\n     */\n    lineWidth: 1,\n\n    /**\n     * If stroke ignore scale\n     * @type {Boolean}\n     */\n    strokeNoScale: false,\n\n    // Bounding rect text configuration\n    // Not affected by element transform\n    /**\n     * @type {string}\n     */\n    text: null,\n\n    /**\n     * If `fontSize` or `fontFamily` exists, `font` will be reset by\n     * `fontSize`, `fontStyle`, `fontWeight`, `fontFamily`.\n     * So do not visit it directly in upper application (like echarts),\n     * but use `contain/text#makeFont` instead.\n     * @type {string}\n     */\n    font: null,\n\n    /**\n     * The same as font. Use font please.\n     * @deprecated\n     * @type {string}\n     */\n    textFont: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontStyle: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontWeight: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * Should be 12 but not '12px'.\n     * @type {number}\n     */\n    fontSize: null,\n\n    /**\n     * It helps merging respectively, rather than parsing an entire font string.\n     * @type {string}\n     */\n    fontFamily: null,\n\n    /**\n     * Reserved for special functinality, like 'hr'.\n     * @type {string}\n     */\n    textTag: null,\n\n    /**\n     * @type {string}\n     */\n    textFill: '#000',\n\n    /**\n     * @type {string}\n     */\n    textStroke: null,\n\n    /**\n     * @type {number}\n     */\n    textWidth: null,\n\n    /**\n     * Only for textBackground.\n     * @type {number}\n     */\n    textHeight: null,\n\n    /**\n     * textStroke may be set as some color as a default\n     * value in upper applicaion, where the default value\n     * of textStrokeWidth should be 0 to make sure that\n     * user can choose to do not use text stroke.\n     * @type {number}\n     */\n    textStrokeWidth: 0,\n\n    /**\n     * @type {number}\n     */\n    textLineHeight: null,\n\n    /**\n     * 'inside', 'left', 'right', 'top', 'bottom'\n     * [x, y]\n     * Based on x, y of rect.\n     * @type {string|Array.<number>}\n     * @default 'inside'\n     */\n    textPosition: 'inside',\n\n    /**\n     * If not specified, use the boundingRect of a `displayable`.\n     * @type {Object}\n     */\n    textRect: null,\n\n    /**\n     * [x, y]\n     * @type {Array.<number>}\n     */\n    textOffset: null,\n\n    /**\n     * @type {string}\n     */\n    textAlign: null,\n\n    /**\n     * @type {string}\n     */\n    textVerticalAlign: null,\n\n    /**\n     * @type {number}\n     */\n    textDistance: 5,\n\n    /**\n     * @type {string}\n     */\n    textShadowColor: 'transparent',\n\n    /**\n     * @type {number}\n     */\n    textShadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    textShadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    textShadowOffsetY: 0,\n\n    /**\n     * @type {string}\n     */\n    textBoxShadowColor: 'transparent',\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowBlur: 0,\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowOffsetX: 0,\n\n    /**\n     * @type {number}\n     */\n    textBoxShadowOffsetY: 0,\n\n    /**\n     * Whether transform text.\n     * Only useful in Path and Image element\n     * @type {boolean}\n     */\n    transformText: false,\n\n    /**\n     * Text rotate around position of Path or Image\n     * Only useful in Path and Image element and transformText is false.\n     */\n    textRotation: 0,\n\n    /**\n     * Text origin of text rotation, like [10, 40].\n     * Based on x, y of rect.\n     * Useful in label rotation of circular symbol.\n     * By default, this origin is textPosition.\n     * Can be 'center'.\n     * @type {string|Array.<number>}\n     */\n    textOrigin: null,\n\n    /**\n     * @type {string}\n     */\n    textBackgroundColor: null,\n\n    /**\n     * @type {string}\n     */\n    textBorderColor: null,\n\n    /**\n     * @type {number}\n     */\n    textBorderWidth: 0,\n\n    /**\n     * @type {number}\n     */\n    textBorderRadius: 0,\n\n    /**\n     * Can be `2` or `[2, 4]` or `[2, 3, 4, 5]`\n     * @type {number|Array.<number>}\n     */\n    textPadding: null,\n\n    /**\n     * Text styles for rich text.\n     * @type {Object}\n     */\n    rich: null,\n\n    /**\n     * {outerWidth, outerHeight, ellipsis, placeholder}\n     * @type {Object}\n     */\n    truncate: null,\n\n    /**\n     * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation\n     * @type {string}\n     */\n    blend: null,\n\n    /**\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    bind: function (ctx, el, prevEl) {\n        var style = this;\n        var prevStyle = prevEl && prevEl.style;\n        // If no prevStyle, it means first draw.\n        // Only apply cache if the last time cachced by this function.\n        var notCheckCache = !prevStyle || ctx.__attrCachedBy !== ContextCachedBy.STYLE_BIND;\n\n        ctx.__attrCachedBy = ContextCachedBy.STYLE_BIND;\n\n        for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {\n            var prop = STYLE_COMMON_PROPS[i];\n            var styleName = prop[0];\n\n            if (notCheckCache || style[styleName] !== prevStyle[styleName]) {\n                // FIXME Invalid property value will cause style leak from previous element.\n                ctx[styleName] =\n                    fixShadow(ctx, styleName, style[styleName] || prop[1]);\n            }\n        }\n\n        if ((notCheckCache || style.fill !== prevStyle.fill)) {\n            ctx.fillStyle = style.fill;\n        }\n        if ((notCheckCache || style.stroke !== prevStyle.stroke)) {\n            ctx.strokeStyle = style.stroke;\n        }\n        if ((notCheckCache || style.opacity !== prevStyle.opacity)) {\n            ctx.globalAlpha = style.opacity == null ? 1 : style.opacity;\n        }\n\n        if ((notCheckCache || style.blend !== prevStyle.blend)) {\n            ctx.globalCompositeOperation = style.blend || 'source-over';\n        }\n        if (this.hasStroke()) {\n            var lineWidth = style.lineWidth;\n            ctx.lineWidth = lineWidth / (\n                (this.strokeNoScale && el && el.getLineScale) ? el.getLineScale() : 1\n            );\n        }\n    },\n\n    hasFill: function () {\n        var fill = this.fill;\n        return fill != null && fill !== 'none';\n    },\n\n    hasStroke: function () {\n        var stroke = this.stroke;\n        return stroke != null && stroke !== 'none' && this.lineWidth > 0;\n    },\n\n    /**\n     * Extend from other style\n     * @param {zrender/graphic/Style} otherStyle\n     * @param {boolean} overwrite true: overwrirte any way.\n     *                            false: overwrite only when !target.hasOwnProperty\n     *                            others: overwrite when property is not null/undefined.\n     */\n    extendFrom: function (otherStyle, overwrite) {\n        if (otherStyle) {\n            for (var name in otherStyle) {\n                if (otherStyle.hasOwnProperty(name)\n                    && (overwrite === true\n                        || (\n                            overwrite === false\n                                ? !this.hasOwnProperty(name)\n                                : otherStyle[name] != null\n                        )\n                    )\n                ) {\n                    this[name] = otherStyle[name];\n                }\n            }\n        }\n    },\n\n    /**\n     * Batch setting style with a given object\n     * @param {Object|string} obj\n     * @param {*} [obj]\n     */\n    set: function (obj, value) {\n        if (typeof obj === 'string') {\n            this[obj] = value;\n        }\n        else {\n            this.extendFrom(obj, true);\n        }\n    },\n\n    /**\n     * Clone\n     * @return {zrender/graphic/Style} [description]\n     */\n    clone: function () {\n        var newStyle = new this.constructor();\n        newStyle.extendFrom(this, true);\n        return newStyle;\n    },\n\n    getGradient: function (ctx, obj, rect) {\n        var method = obj.type === 'radial' ? createRadialGradient : createLinearGradient;\n        var canvasGradient = method(ctx, obj, rect);\n        var colorStops = obj.colorStops;\n        for (var i = 0; i < colorStops.length; i++) {\n            canvasGradient.addColorStop(\n                colorStops[i].offset, colorStops[i].color\n            );\n        }\n        return canvasGradient;\n    }\n\n};\n\nvar styleProto = Style.prototype;\nfor (var i = 0; i < STYLE_COMMON_PROPS.length; i++) {\n    var prop = STYLE_COMMON_PROPS[i];\n    if (!(prop[0] in styleProto)) {\n        styleProto[prop[0]] = prop[1];\n    }\n}\n\n// Provide for others\nStyle.getGradient = styleProto.getGradient;\n\nvar Pattern = function (image, repeat) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {image: ...}`, where this constructor will not be called.\n\n    this.image = image;\n    this.repeat = repeat;\n\n    // Can be cloned\n    this.type = 'pattern';\n};\n\nPattern.prototype.getCanvasPattern = function (ctx) {\n    return ctx.createPattern(this.image, this.repeat || 'repeat');\n};\n\n/**\n * @module zrender/Layer\n * @author pissang(https://www.github.com/pissang)\n */\n\nfunction returnFalse() {\n    return false;\n}\n\n/**\n * 创建dom\n *\n * @inner\n * @param {string} id dom id 待用\n * @param {Painter} painter painter instance\n * @param {number} number\n */\nfunction createDom(id, painter, dpr) {\n    var newDom = createCanvas();\n    var width = painter.getWidth();\n    var height = painter.getHeight();\n\n    var newDomStyle = newDom.style;\n    if (newDomStyle) {  // In node or some other non-browser environment\n        newDomStyle.position = 'absolute';\n        newDomStyle.left = 0;\n        newDomStyle.top = 0;\n        newDomStyle.width = width + 'px';\n        newDomStyle.height = height + 'px';\n\n        newDom.setAttribute('data-zr-dom-id', id);\n    }\n\n    newDom.width = width * dpr;\n    newDom.height = height * dpr;\n\n    return newDom;\n}\n\n/**\n * @alias module:zrender/Layer\n * @constructor\n * @extends module:zrender/mixin/Transformable\n * @param {string} id\n * @param {module:zrender/Painter} painter\n * @param {number} [dpr]\n */\nvar Layer = function (id, painter, dpr) {\n    var dom;\n    dpr = dpr || devicePixelRatio;\n    if (typeof id === 'string') {\n        dom = createDom(id, painter, dpr);\n    }\n    // Not using isDom because in node it will return false\n    else if (isObject$1(id)) {\n        dom = id;\n        id = dom.id;\n    }\n    this.id = id;\n    this.dom = dom;\n\n    var domStyle = dom.style;\n    if (domStyle) { // Not in node\n        dom.onselectstart = returnFalse; // 避免页面选中的尴尬\n        domStyle['-webkit-user-select'] = 'none';\n        domStyle['user-select'] = 'none';\n        domStyle['-webkit-touch-callout'] = 'none';\n        domStyle['-webkit-tap-highlight-color'] = 'rgba(0,0,0,0)';\n        domStyle['padding'] = 0;\n        domStyle['margin'] = 0;\n        domStyle['border-width'] = 0;\n    }\n\n    this.domBack = null;\n    this.ctxBack = null;\n\n    this.painter = painter;\n\n    this.config = null;\n\n    // Configs\n    /**\n     * 每次清空画布的颜色\n     * @type {string}\n     * @default 0\n     */\n    this.clearColor = 0;\n    /**\n     * 是否开启动态模糊\n     * @type {boolean}\n     * @default false\n     */\n    this.motionBlur = false;\n    /**\n     * 在开启动态模糊的时候使用，与上一帧混合的alpha值，值越大尾迹越明显\n     * @type {number}\n     * @default 0.7\n     */\n    this.lastFrameAlpha = 0.7;\n\n    /**\n     * Layer dpr\n     * @type {number}\n     */\n    this.dpr = dpr;\n};\n\nLayer.prototype = {\n\n    constructor: Layer,\n\n    __dirty: true,\n\n    __used: false,\n\n    __drawIndex: 0,\n    __startIndex: 0,\n    __endIndex: 0,\n\n    incremental: false,\n\n    getElementCount: function () {\n        return this.__endIndex - this.__startIndex;\n    },\n\n    initContext: function () {\n        this.ctx = this.dom.getContext('2d');\n        this.ctx.dpr = this.dpr;\n    },\n\n    createBackBuffer: function () {\n        var dpr = this.dpr;\n\n        this.domBack = createDom('back-' + this.id, this.painter, dpr);\n        this.ctxBack = this.domBack.getContext('2d');\n\n        if (dpr !== 1) {\n            this.ctxBack.scale(dpr, dpr);\n        }\n    },\n\n    /**\n     * @param  {number} width\n     * @param  {number} height\n     */\n    resize: function (width, height) {\n        var dpr = this.dpr;\n\n        var dom = this.dom;\n        var domStyle = dom.style;\n        var domBack = this.domBack;\n\n        if (domStyle) {\n            domStyle.width = width + 'px';\n            domStyle.height = height + 'px';\n        }\n\n        dom.width = width * dpr;\n        dom.height = height * dpr;\n\n        if (domBack) {\n            domBack.width = width * dpr;\n            domBack.height = height * dpr;\n\n            if (dpr !== 1) {\n                this.ctxBack.scale(dpr, dpr);\n            }\n        }\n    },\n\n    /**\n     * 清空该层画布\n     * @param {boolean} [clearAll]=false Clear all with out motion blur\n     * @param {Color} [clearColor]\n     */\n    clear: function (clearAll, clearColor) {\n        var dom = this.dom;\n        var ctx = this.ctx;\n        var width = dom.width;\n        var height = dom.height;\n\n        var clearColor = clearColor || this.clearColor;\n        var haveMotionBLur = this.motionBlur && !clearAll;\n        var lastFrameAlpha = this.lastFrameAlpha;\n\n        var dpr = this.dpr;\n\n        if (haveMotionBLur) {\n            if (!this.domBack) {\n                this.createBackBuffer();\n            }\n\n            this.ctxBack.globalCompositeOperation = 'copy';\n            this.ctxBack.drawImage(\n                dom, 0, 0,\n                width / dpr,\n                height / dpr\n            );\n        }\n\n        ctx.clearRect(0, 0, width, height);\n        if (clearColor && clearColor !== 'transparent') {\n            var clearColorGradientOrPattern;\n            // Gradient\n            if (clearColor.colorStops) {\n                // Cache canvas gradient\n                clearColorGradientOrPattern = clearColor.__canvasGradient || Style.getGradient(ctx, clearColor, {\n                    x: 0,\n                    y: 0,\n                    width: width,\n                    height: height\n                });\n\n                clearColor.__canvasGradient = clearColorGradientOrPattern;\n            }\n            // Pattern\n            else if (clearColor.image) {\n                clearColorGradientOrPattern = Pattern.prototype.getCanvasPattern.call(clearColor, ctx);\n            }\n            ctx.save();\n            ctx.fillStyle = clearColorGradientOrPattern || clearColor;\n            ctx.fillRect(0, 0, width, height);\n            ctx.restore();\n        }\n\n        if (haveMotionBLur) {\n            var domBack = this.domBack;\n            ctx.save();\n            ctx.globalAlpha = lastFrameAlpha;\n            ctx.drawImage(domBack, 0, 0, width, height);\n            ctx.restore();\n        }\n    }\n};\n\nvar requestAnimationFrame = (\n    typeof window !== 'undefined'\n    && (\n        (window.requestAnimationFrame && window.requestAnimationFrame.bind(window))\n        // https://github.com/ecomfe/zrender/issues/189#issuecomment-224919809\n        || (window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window))\n        || window.mozRequestAnimationFrame\n        || window.webkitRequestAnimationFrame\n    )\n) || function (func) {\n    setTimeout(func, 16);\n};\n\nvar globalImageCache = new LRU(50);\n\n/**\n * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc\n * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image\n */\nfunction findExistImage(newImageOrSrc) {\n    if (typeof newImageOrSrc === 'string') {\n        var cachedImgObj = globalImageCache.get(newImageOrSrc);\n        return cachedImgObj && cachedImgObj.image;\n    }\n    else {\n        return newImageOrSrc;\n    }\n}\n\n/**\n * Caution: User should cache loaded images, but not just count on LRU.\n * Consider if required images more than LRU size, will dead loop occur?\n *\n * @param {string|HTMLImageElement|HTMLCanvasElement|Canvas} newImageOrSrc\n * @param {HTMLImageElement|HTMLCanvasElement|Canvas} image Existent image.\n * @param {module:zrender/Element} [hostEl] For calling `dirty`.\n * @param {Function} [cb] params: (image, cbPayload)\n * @param {Object} [cbPayload] Payload on cb calling.\n * @return {HTMLImageElement|HTMLCanvasElement|Canvas} image\n */\nfunction createOrUpdateImage(newImageOrSrc, image, hostEl, cb, cbPayload) {\n    if (!newImageOrSrc) {\n        return image;\n    }\n    else if (typeof newImageOrSrc === 'string') {\n\n        // Image should not be loaded repeatly.\n        if ((image && image.__zrImageSrc === newImageOrSrc) || !hostEl) {\n            return image;\n        }\n\n        // Only when there is no existent image or existent image src\n        // is different, this method is responsible for load.\n        var cachedImgObj = globalImageCache.get(newImageOrSrc);\n\n        var pendingWrap = {hostEl: hostEl, cb: cb, cbPayload: cbPayload};\n\n        if (cachedImgObj) {\n            image = cachedImgObj.image;\n            !isImageReady(image) && cachedImgObj.pending.push(pendingWrap);\n        }\n        else {\n            image = new Image();\n            image.onload = image.onerror = imageOnLoad;\n\n            globalImageCache.put(\n                newImageOrSrc,\n                image.__cachedImgObj = {\n                    image: image,\n                    pending: [pendingWrap]\n                }\n            );\n\n            image.src = image.__zrImageSrc = newImageOrSrc;\n        }\n\n        return image;\n    }\n    // newImageOrSrc is an HTMLImageElement or HTMLCanvasElement or Canvas\n    else {\n        return newImageOrSrc;\n    }\n}\n\nfunction imageOnLoad() {\n    var cachedImgObj = this.__cachedImgObj;\n    this.onload = this.onerror = this.__cachedImgObj = null;\n\n    for (var i = 0; i < cachedImgObj.pending.length; i++) {\n        var pendingWrap = cachedImgObj.pending[i];\n        var cb = pendingWrap.cb;\n        cb && cb(this, pendingWrap.cbPayload);\n        pendingWrap.hostEl.dirty();\n    }\n    cachedImgObj.pending.length = 0;\n}\n\nfunction isImageReady(image) {\n    return image && image.width && image.height;\n}\n\nvar textWidthCache = {};\nvar textWidthCacheCounter = 0;\n\nvar TEXT_CACHE_MAX = 5000;\nvar STYLE_REG = /\\{([a-zA-Z0-9_]+)\\|([^}]*)\\}/g;\n\nvar DEFAULT_FONT$1 = '12px sans-serif';\n\n// Avoid assign to an exported variable, for transforming to cjs.\nvar methods$1 = {};\n\n\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @return {number} width\n */\nfunction getWidth(text, font) {\n    font = font || DEFAULT_FONT$1;\n    var key = text + ':' + font;\n    if (textWidthCache[key]) {\n        return textWidthCache[key];\n    }\n\n    var textLines = (text + '').split('\\n');\n    var width = 0;\n\n    for (var i = 0, l = textLines.length; i < l; i++) {\n        // textContain.measureText may be overrided in SVG or VML\n        width = Math.max(measureText(textLines[i], font).width, width);\n    }\n\n    if (textWidthCacheCounter > TEXT_CACHE_MAX) {\n        textWidthCacheCounter = 0;\n        textWidthCache = {};\n    }\n    textWidthCacheCounter++;\n    textWidthCache[key] = width;\n\n    return width;\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @param {string} [textAlign='left']\n * @param {string} [textVerticalAlign='top']\n * @param {Array.<number>} [textPadding]\n * @param {Object} [rich]\n * @param {Object} [truncate]\n * @return {Object} {x, y, width, height, lineHeight}\n */\nfunction getBoundingRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) {\n    return rich\n        ? getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate)\n        : getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate);\n}\n\nfunction getPlainTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, truncate) {\n    var contentBlock = parsePlainText(text, font, textPadding, textLineHeight, truncate);\n    var outerWidth = getWidth(text, font);\n    if (textPadding) {\n        outerWidth += textPadding[1] + textPadding[3];\n    }\n    var outerHeight = contentBlock.outerHeight;\n\n    var x = adjustTextX(0, outerWidth, textAlign);\n    var y = adjustTextY(0, outerHeight, textVerticalAlign);\n\n    var rect = new BoundingRect(x, y, outerWidth, outerHeight);\n    rect.lineHeight = contentBlock.lineHeight;\n\n    return rect;\n}\n\nfunction getRichTextRect(text, font, textAlign, textVerticalAlign, textPadding, textLineHeight, rich, truncate) {\n    var contentBlock = parseRichText(text, {\n        rich: rich,\n        truncate: truncate,\n        font: font,\n        textAlign: textAlign,\n        textPadding: textPadding,\n        textLineHeight: textLineHeight\n    });\n    var outerWidth = contentBlock.outerWidth;\n    var outerHeight = contentBlock.outerHeight;\n\n    var x = adjustTextX(0, outerWidth, textAlign);\n    var y = adjustTextY(0, outerHeight, textVerticalAlign);\n\n    return new BoundingRect(x, y, outerWidth, outerHeight);\n}\n\n/**\n * @public\n * @param {number} x\n * @param {number} width\n * @param {string} [textAlign='left']\n * @return {number} Adjusted x.\n */\nfunction adjustTextX(x, width, textAlign) {\n    // FIXME Right to left language\n    if (textAlign === 'right') {\n        x -= width;\n    }\n    else if (textAlign === 'center') {\n        x -= width / 2;\n    }\n    return x;\n}\n\n/**\n * @public\n * @param {number} y\n * @param {number} height\n * @param {string} [textVerticalAlign='top']\n * @return {number} Adjusted y.\n */\nfunction adjustTextY(y, height, textVerticalAlign) {\n    if (textVerticalAlign === 'middle') {\n        y -= height / 2;\n    }\n    else if (textVerticalAlign === 'bottom') {\n        y -= height;\n    }\n    return y;\n}\n\n/**\n * @public\n * @param {stirng} textPosition\n * @param {Object} rect {x, y, width, height}\n * @param {number} distance\n * @return {Object} {x, y, textAlign, textVerticalAlign}\n */\nfunction adjustTextPositionOnRect(textPosition, rect, distance) {\n\n    var x = rect.x;\n    var y = rect.y;\n\n    var height = rect.height;\n    var width = rect.width;\n    var halfHeight = height / 2;\n\n    var textAlign = 'left';\n    var textVerticalAlign = 'top';\n\n    switch (textPosition) {\n        case 'left':\n            x -= distance;\n            y += halfHeight;\n            textAlign = 'right';\n            textVerticalAlign = 'middle';\n            break;\n        case 'right':\n            x += distance + width;\n            y += halfHeight;\n            textVerticalAlign = 'middle';\n            break;\n        case 'top':\n            x += width / 2;\n            y -= distance;\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            break;\n        case 'bottom':\n            x += width / 2;\n            y += height + distance;\n            textAlign = 'center';\n            break;\n        case 'inside':\n            x += width / 2;\n            y += halfHeight;\n            textAlign = 'center';\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideLeft':\n            x += distance;\n            y += halfHeight;\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideRight':\n            x += width - distance;\n            y += halfHeight;\n            textAlign = 'right';\n            textVerticalAlign = 'middle';\n            break;\n        case 'insideTop':\n            x += width / 2;\n            y += distance;\n            textAlign = 'center';\n            break;\n        case 'insideBottom':\n            x += width / 2;\n            y += height - distance;\n            textAlign = 'center';\n            textVerticalAlign = 'bottom';\n            break;\n        case 'insideTopLeft':\n            x += distance;\n            y += distance;\n            break;\n        case 'insideTopRight':\n            x += width - distance;\n            y += distance;\n            textAlign = 'right';\n            break;\n        case 'insideBottomLeft':\n            x += distance;\n            y += height - distance;\n            textVerticalAlign = 'bottom';\n            break;\n        case 'insideBottomRight':\n            x += width - distance;\n            y += height - distance;\n            textAlign = 'right';\n            textVerticalAlign = 'bottom';\n            break;\n    }\n\n    return {\n        x: x,\n        y: y,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\n/**\n * Show ellipsis if overflow.\n *\n * @public\n * @param  {string} text\n * @param  {string} containerWidth\n * @param  {string} font\n * @param  {number} [ellipsis='...']\n * @param  {Object} [options]\n * @param  {number} [options.maxIterations=3]\n * @param  {number} [options.minChar=0] If truncate result are less\n *                  then minChar, ellipsis will not show, which is\n *                  better for user hint in some cases.\n * @param  {number} [options.placeholder=''] When all truncated, use the placeholder.\n * @return {string}\n */\nfunction truncateText(text, containerWidth, font, ellipsis, options) {\n    if (!containerWidth) {\n        return '';\n    }\n\n    var textLines = (text + '').split('\\n');\n    options = prepareTruncateOptions(containerWidth, font, ellipsis, options);\n\n    // FIXME\n    // It is not appropriate that every line has '...' when truncate multiple lines.\n    for (var i = 0, len = textLines.length; i < len; i++) {\n        textLines[i] = truncateSingleLine(textLines[i], options);\n    }\n\n    return textLines.join('\\n');\n}\n\nfunction prepareTruncateOptions(containerWidth, font, ellipsis, options) {\n    options = extend({}, options);\n\n    options.font = font;\n    var ellipsis = retrieve2(ellipsis, '...');\n    options.maxIterations = retrieve2(options.maxIterations, 2);\n    var minChar = options.minChar = retrieve2(options.minChar, 0);\n    // FIXME\n    // Other languages?\n    options.cnCharWidth = getWidth('国', font);\n    // FIXME\n    // Consider proportional font?\n    var ascCharWidth = options.ascCharWidth = getWidth('a', font);\n    options.placeholder = retrieve2(options.placeholder, '');\n\n    // Example 1: minChar: 3, text: 'asdfzxcv', truncate result: 'asdf', but not: 'a...'.\n    // Example 2: minChar: 3, text: '维度', truncate result: '维', but not: '...'.\n    var contentWidth = containerWidth = Math.max(0, containerWidth - 1); // Reserve some gap.\n    for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) {\n        contentWidth -= ascCharWidth;\n    }\n\n    var ellipsisWidth = getWidth(ellipsis, font);\n    if (ellipsisWidth > contentWidth) {\n        ellipsis = '';\n        ellipsisWidth = 0;\n    }\n\n    contentWidth = containerWidth - ellipsisWidth;\n\n    options.ellipsis = ellipsis;\n    options.ellipsisWidth = ellipsisWidth;\n    options.contentWidth = contentWidth;\n    options.containerWidth = containerWidth;\n\n    return options;\n}\n\nfunction truncateSingleLine(textLine, options) {\n    var containerWidth = options.containerWidth;\n    var font = options.font;\n    var contentWidth = options.contentWidth;\n\n    if (!containerWidth) {\n        return '';\n    }\n\n    var lineWidth = getWidth(textLine, font);\n\n    if (lineWidth <= containerWidth) {\n        return textLine;\n    }\n\n    for (var j = 0; ; j++) {\n        if (lineWidth <= contentWidth || j >= options.maxIterations) {\n            textLine += options.ellipsis;\n            break;\n        }\n\n        var subLength = j === 0\n            ? estimateLength(textLine, contentWidth, options.ascCharWidth, options.cnCharWidth)\n            : lineWidth > 0\n            ? Math.floor(textLine.length * contentWidth / lineWidth)\n            : 0;\n\n        textLine = textLine.substr(0, subLength);\n        lineWidth = getWidth(textLine, font);\n    }\n\n    if (textLine === '') {\n        textLine = options.placeholder;\n    }\n\n    return textLine;\n}\n\nfunction estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) {\n    var width = 0;\n    var i = 0;\n    for (var len = text.length; i < len && width < contentWidth; i++) {\n        var charCode = text.charCodeAt(i);\n        width += (0 <= charCode && charCode <= 127) ? ascCharWidth : cnCharWidth;\n    }\n    return i;\n}\n\n/**\n * @public\n * @param {string} font\n * @return {number} line height\n */\nfunction getLineHeight(font) {\n    // FIXME A rough approach.\n    return getWidth('国', font);\n}\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @return {Object} width\n */\nfunction measureText(text, font) {\n    return methods$1.measureText(text, font);\n}\n\n// Avoid assign to an exported variable, for transforming to cjs.\nmethods$1.measureText = function (text, font) {\n    var ctx = getContext();\n    ctx.font = font || DEFAULT_FONT$1;\n    return ctx.measureText(text);\n};\n\n/**\n * @public\n * @param {string} text\n * @param {string} font\n * @param {Object} [truncate]\n * @return {Object} block: {lineHeight, lines, height, outerHeight}\n *  Notice: for performance, do not calculate outerWidth util needed.\n */\nfunction parsePlainText(text, font, padding, textLineHeight, truncate) {\n    text != null && (text += '');\n\n    var lineHeight = retrieve2(textLineHeight, getLineHeight(font));\n    var lines = text ? text.split('\\n') : [];\n    var height = lines.length * lineHeight;\n    var outerHeight = height;\n\n    if (padding) {\n        outerHeight += padding[0] + padding[2];\n    }\n\n    if (text && truncate) {\n        var truncOuterHeight = truncate.outerHeight;\n        var truncOuterWidth = truncate.outerWidth;\n        if (truncOuterHeight != null && outerHeight > truncOuterHeight) {\n            text = '';\n            lines = [];\n        }\n        else if (truncOuterWidth != null) {\n            var options = prepareTruncateOptions(\n                truncOuterWidth - (padding ? padding[1] + padding[3] : 0),\n                font,\n                truncate.ellipsis,\n                {minChar: truncate.minChar, placeholder: truncate.placeholder}\n            );\n\n            // FIXME\n            // It is not appropriate that every line has '...' when truncate multiple lines.\n            for (var i = 0, len = lines.length; i < len; i++) {\n                lines[i] = truncateSingleLine(lines[i], options);\n            }\n        }\n    }\n\n    return {\n        lines: lines,\n        height: height,\n        outerHeight: outerHeight,\n        lineHeight: lineHeight\n    };\n}\n\n/**\n * For example: 'some text {a|some text}other text{b|some text}xxx{c|}xxx'\n * Also consider 'bbbb{a|xxx\\nzzz}xxxx\\naaaa'.\n *\n * @public\n * @param {string} text\n * @param {Object} style\n * @return {Object} block\n * {\n *      width,\n *      height,\n *      lines: [{\n *          lineHeight,\n *          width,\n *          tokens: [[{\n *              styleName,\n *              text,\n *              width,      // include textPadding\n *              height,     // include textPadding\n *              textWidth, // pure text width\n *              textHeight, // pure text height\n *              lineHeihgt,\n *              font,\n *              textAlign,\n *              textVerticalAlign\n *          }], [...], ...]\n *      }, ...]\n * }\n * If styleName is undefined, it is plain text.\n */\nfunction parseRichText(text, style) {\n    var contentBlock = {lines: [], width: 0, height: 0};\n\n    text != null && (text += '');\n    if (!text) {\n        return contentBlock;\n    }\n\n    var lastIndex = STYLE_REG.lastIndex = 0;\n    var result;\n    while ((result = STYLE_REG.exec(text)) != null) {\n        var matchedIndex = result.index;\n        if (matchedIndex > lastIndex) {\n            pushTokens(contentBlock, text.substring(lastIndex, matchedIndex));\n        }\n        pushTokens(contentBlock, result[2], result[1]);\n        lastIndex = STYLE_REG.lastIndex;\n    }\n\n    if (lastIndex < text.length) {\n        pushTokens(contentBlock, text.substring(lastIndex, text.length));\n    }\n\n    var lines = contentBlock.lines;\n    var contentHeight = 0;\n    var contentWidth = 0;\n    // For `textWidth: 100%`\n    var pendingList = [];\n\n    var stlPadding = style.textPadding;\n\n    var truncate = style.truncate;\n    var truncateWidth = truncate && truncate.outerWidth;\n    var truncateHeight = truncate && truncate.outerHeight;\n    if (stlPadding) {\n        truncateWidth != null && (truncateWidth -= stlPadding[1] + stlPadding[3]);\n        truncateHeight != null && (truncateHeight -= stlPadding[0] + stlPadding[2]);\n    }\n\n    // Calculate layout info of tokens.\n    for (var i = 0; i < lines.length; i++) {\n        var line = lines[i];\n        var lineHeight = 0;\n        var lineWidth = 0;\n\n        for (var j = 0; j < line.tokens.length; j++) {\n            var token = line.tokens[j];\n            var tokenStyle = token.styleName && style.rich[token.styleName] || {};\n            // textPadding should not inherit from style.\n            var textPadding = token.textPadding = tokenStyle.textPadding;\n\n            // textFont has been asigned to font by `normalizeStyle`.\n            var font = token.font = tokenStyle.font || style.font;\n\n            // textHeight can be used when textVerticalAlign is specified in token.\n            var tokenHeight = token.textHeight = retrieve2(\n                // textHeight should not be inherited, consider it can be specified\n                // as box height of the block.\n                tokenStyle.textHeight, getLineHeight(font)\n            );\n            textPadding && (tokenHeight += textPadding[0] + textPadding[2]);\n            token.height = tokenHeight;\n            token.lineHeight = retrieve3(\n                tokenStyle.textLineHeight, style.textLineHeight, tokenHeight\n            );\n\n            token.textAlign = tokenStyle && tokenStyle.textAlign || style.textAlign;\n            token.textVerticalAlign = tokenStyle && tokenStyle.textVerticalAlign || 'middle';\n\n            if (truncateHeight != null && contentHeight + token.lineHeight > truncateHeight) {\n                return {lines: [], width: 0, height: 0};\n            }\n\n            token.textWidth = getWidth(token.text, font);\n            var tokenWidth = tokenStyle.textWidth;\n            var tokenWidthNotSpecified = tokenWidth == null || tokenWidth === 'auto';\n\n            // Percent width, can be `100%`, can be used in drawing separate\n            // line when box width is needed to be auto.\n            if (typeof tokenWidth === 'string' && tokenWidth.charAt(tokenWidth.length - 1) === '%') {\n                token.percentWidth = tokenWidth;\n                pendingList.push(token);\n                tokenWidth = 0;\n                // Do not truncate in this case, because there is no user case\n                // and it is too complicated.\n            }\n            else {\n                if (tokenWidthNotSpecified) {\n                    tokenWidth = token.textWidth;\n\n                    // FIXME: If image is not loaded and textWidth is not specified, calling\n                    // `getBoundingRect()` will not get correct result.\n                    var textBackgroundColor = tokenStyle.textBackgroundColor;\n                    var bgImg = textBackgroundColor && textBackgroundColor.image;\n\n                    // Use cases:\n                    // (1) If image is not loaded, it will be loaded at render phase and call\n                    // `dirty()` and `textBackgroundColor.image` will be replaced with the loaded\n                    // image, and then the right size will be calculated here at the next tick.\n                    // See `graphic/helper/text.js`.\n                    // (2) If image loaded, and `textBackgroundColor.image` is image src string,\n                    // use `imageHelper.findExistImage` to find cached image.\n                    // `imageHelper.findExistImage` will always be called here before\n                    // `imageHelper.createOrUpdateImage` in `graphic/helper/text.js#renderRichText`\n                    // which ensures that image will not be rendered before correct size calcualted.\n                    if (bgImg) {\n                        bgImg = findExistImage(bgImg);\n                        if (isImageReady(bgImg)) {\n                            tokenWidth = Math.max(tokenWidth, bgImg.width * tokenHeight / bgImg.height);\n                        }\n                    }\n                }\n\n                var paddingW = textPadding ? textPadding[1] + textPadding[3] : 0;\n                tokenWidth += paddingW;\n\n                var remianTruncWidth = truncateWidth != null ? truncateWidth - lineWidth : null;\n\n                if (remianTruncWidth != null && remianTruncWidth < tokenWidth) {\n                    if (!tokenWidthNotSpecified || remianTruncWidth < paddingW) {\n                        token.text = '';\n                        token.textWidth = tokenWidth = 0;\n                    }\n                    else {\n                        token.text = truncateText(\n                            token.text, remianTruncWidth - paddingW, font, truncate.ellipsis,\n                            {minChar: truncate.minChar}\n                        );\n                        token.textWidth = getWidth(token.text, font);\n                        tokenWidth = token.textWidth + paddingW;\n                    }\n                }\n            }\n\n            lineWidth += (token.width = tokenWidth);\n            tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight));\n        }\n\n        line.width = lineWidth;\n        line.lineHeight = lineHeight;\n        contentHeight += lineHeight;\n        contentWidth = Math.max(contentWidth, lineWidth);\n    }\n\n    contentBlock.outerWidth = contentBlock.width = retrieve2(style.textWidth, contentWidth);\n    contentBlock.outerHeight = contentBlock.height = retrieve2(style.textHeight, contentHeight);\n\n    if (stlPadding) {\n        contentBlock.outerWidth += stlPadding[1] + stlPadding[3];\n        contentBlock.outerHeight += stlPadding[0] + stlPadding[2];\n    }\n\n    for (var i = 0; i < pendingList.length; i++) {\n        var token = pendingList[i];\n        var percentWidth = token.percentWidth;\n        // Should not base on outerWidth, because token can not be placed out of padding.\n        token.width = parseInt(percentWidth, 10) / 100 * contentWidth;\n    }\n\n    return contentBlock;\n}\n\nfunction pushTokens(block, str, styleName) {\n    var isEmptyStr = str === '';\n    var strs = str.split('\\n');\n    var lines = block.lines;\n\n    for (var i = 0; i < strs.length; i++) {\n        var text = strs[i];\n        var token = {\n            styleName: styleName,\n            text: text,\n            isLineHolder: !text && !isEmptyStr\n        };\n\n        // The first token should be appended to the last line.\n        if (!i) {\n            var tokens = (lines[lines.length - 1] || (lines[0] = {tokens: []})).tokens;\n\n            // Consider cases:\n            // (1) ''.split('\\n') => ['', '\\n', ''], the '' at the first item\n            // (which is a placeholder) should be replaced by new token.\n            // (2) A image backage, where token likes {a|}.\n            // (3) A redundant '' will affect textAlign in line.\n            // (4) tokens with the same tplName should not be merged, because\n            // they should be displayed in different box (with border and padding).\n            var tokensLen = tokens.length;\n            (tokensLen === 1 && tokens[0].isLineHolder)\n                ? (tokens[0] = token)\n                // Consider text is '', only insert when it is the \"lineHolder\" or\n                // \"emptyStr\". Otherwise a redundant '' will affect textAlign in line.\n                : ((text || !tokensLen || isEmptyStr) && tokens.push(token));\n        }\n        // Other tokens always start a new line.\n        else {\n            // If there is '', insert it as a placeholder.\n            lines.push({tokens: [token]});\n        }\n    }\n}\n\nfunction makeFont(style) {\n    // FIXME in node-canvas fontWeight is before fontStyle\n    // Use `fontSize` `fontFamily` to check whether font properties are defined.\n    var font = (style.fontSize || style.fontFamily) && [\n        style.fontStyle,\n        style.fontWeight,\n        (style.fontSize || 12) + 'px',\n        // If font properties are defined, `fontFamily` should not be ignored.\n        style.fontFamily || 'sans-serif'\n    ].join(' ');\n    return font && trim(font) || style.textFont || style.font;\n}\n\n/**\n * @param {Object} ctx\n * @param {Object} shape\n * @param {number} shape.x\n * @param {number} shape.y\n * @param {number} shape.width\n * @param {number} shape.height\n * @param {number} shape.r\n */\nfunction buildPath(ctx, shape) {\n    var x = shape.x;\n    var y = shape.y;\n    var width = shape.width;\n    var height = shape.height;\n    var r = shape.r;\n    var r1;\n    var r2;\n    var r3;\n    var r4;\n\n    // Convert width and height to positive for better borderRadius\n    if (width < 0) {\n        x = x + width;\n        width = -width;\n    }\n    if (height < 0) {\n        y = y + height;\n        height = -height;\n    }\n\n    if (typeof r === 'number') {\n        r1 = r2 = r3 = r4 = r;\n    }\n    else if (r instanceof Array) {\n        if (r.length === 1) {\n            r1 = r2 = r3 = r4 = r[0];\n        }\n        else if (r.length === 2) {\n            r1 = r3 = r[0];\n            r2 = r4 = r[1];\n        }\n        else if (r.length === 3) {\n            r1 = r[0];\n            r2 = r4 = r[1];\n            r3 = r[2];\n        }\n        else {\n            r1 = r[0];\n            r2 = r[1];\n            r3 = r[2];\n            r4 = r[3];\n        }\n    }\n    else {\n        r1 = r2 = r3 = r4 = 0;\n    }\n\n    var total;\n    if (r1 + r2 > width) {\n        total = r1 + r2;\n        r1 *= width / total;\n        r2 *= width / total;\n    }\n    if (r3 + r4 > width) {\n        total = r3 + r4;\n        r3 *= width / total;\n        r4 *= width / total;\n    }\n    if (r2 + r3 > height) {\n        total = r2 + r3;\n        r2 *= height / total;\n        r3 *= height / total;\n    }\n    if (r1 + r4 > height) {\n        total = r1 + r4;\n        r1 *= height / total;\n        r4 *= height / total;\n    }\n    ctx.moveTo(x + r1, y);\n    ctx.lineTo(x + width - r2, y);\n    r2 !== 0 && ctx.arc(x + width - r2, y + r2, r2, -Math.PI / 2, 0);\n    ctx.lineTo(x + width, y + height - r3);\n    r3 !== 0 && ctx.arc(x + width - r3, y + height - r3, r3, 0, Math.PI / 2);\n    ctx.lineTo(x + r4, y + height);\n    r4 !== 0 && ctx.arc(x + r4, y + height - r4, r4, Math.PI / 2, Math.PI);\n    ctx.lineTo(x, y + r1);\n    r1 !== 0 && ctx.arc(x + r1, y + r1, r1, Math.PI, Math.PI * 1.5);\n}\n\nvar DEFAULT_FONT = DEFAULT_FONT$1;\n\n// TODO: Have not support 'start', 'end' yet.\nvar VALID_TEXT_ALIGN = {left: 1, right: 1, center: 1};\nvar VALID_TEXT_VERTICAL_ALIGN = {top: 1, bottom: 1, middle: 1};\n// Different from `STYLE_COMMON_PROPS` of `graphic/Style`,\n// the default value of shadowColor is `'transparent'`.\nvar SHADOW_STYLE_COMMON_PROPS = [\n    ['textShadowBlur', 'shadowBlur', 0],\n    ['textShadowOffsetX', 'shadowOffsetX', 0],\n    ['textShadowOffsetY', 'shadowOffsetY', 0],\n    ['textShadowColor', 'shadowColor', 'transparent']\n];\n\n/**\n * @param {module:zrender/graphic/Style} style\n * @return {module:zrender/graphic/Style} The input style.\n */\nfunction normalizeTextStyle(style) {\n    normalizeStyle(style);\n    each$1(style.rich, normalizeStyle);\n    return style;\n}\n\nfunction normalizeStyle(style) {\n    if (style) {\n\n        style.font = makeFont(style);\n\n        var textAlign = style.textAlign;\n        textAlign === 'middle' && (textAlign = 'center');\n        style.textAlign = (\n            textAlign == null || VALID_TEXT_ALIGN[textAlign]\n        ) ? textAlign : 'left';\n\n        // Compatible with textBaseline.\n        var textVerticalAlign = style.textVerticalAlign || style.textBaseline;\n        textVerticalAlign === 'center' && (textVerticalAlign = 'middle');\n        style.textVerticalAlign = (\n            textVerticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[textVerticalAlign]\n        ) ? textVerticalAlign : 'top';\n\n        var textPadding = style.textPadding;\n        if (textPadding) {\n            style.textPadding = normalizeCssArray(style.textPadding);\n        }\n    }\n}\n\n/**\n * @param {CanvasRenderingContext2D} ctx\n * @param {string} text\n * @param {module:zrender/graphic/Style} style\n * @param {Object|boolean} [rect] {x, y, width, height}\n *                  If set false, rect text is not used.\n * @param {Element|module:zrender/graphic/helper/constant.WILL_BE_RESTORED} [prevEl] For ctx prop cache.\n */\nfunction renderText(hostEl, ctx, text, style, rect, prevEl) {\n    style.rich\n        ? renderRichText(hostEl, ctx, text, style, rect, prevEl)\n        : renderPlainText(hostEl, ctx, text, style, rect, prevEl);\n}\n\n// Avoid setting to ctx according to prevEl if possible for\n// performance in scenarios of large amount text.\nfunction renderPlainText(hostEl, ctx, text, style, rect, prevEl) {\n    'use strict';\n\n    var needDrawBg = needDrawBackground(style);\n\n    var prevStyle;\n    var checkCache = false;\n    var cachedByMe = ctx.__attrCachedBy === ContextCachedBy.PLAIN_TEXT;\n\n    // Only take and check cache for `Text` el, but not RectText.\n    if (prevEl !== WILL_BE_RESTORED) {\n        if (prevEl) {\n            prevStyle = prevEl.style;\n            checkCache = !needDrawBg && cachedByMe && prevStyle;\n        }\n\n        // Prevent from using cache in `Style::bind`, because of the case:\n        // ctx property is modified by other properties than `Style::bind`\n        // used, and Style::bind is called next.\n        ctx.__attrCachedBy = needDrawBg ? ContextCachedBy.NONE : ContextCachedBy.PLAIN_TEXT;\n    }\n    // Since this will be restored, prevent from using these props to check cache in the next\n    // entering of this method. But do not need to clear other cache like `Style::bind`.\n    else if (cachedByMe) {\n        ctx.__attrCachedBy = ContextCachedBy.NONE;\n    }\n\n    var styleFont = style.font || DEFAULT_FONT;\n    // PENDING\n    // Only `Text` el set `font` and keep it (`RectText` will restore). So theoretically\n    // we can make font cache on ctx, which can cache for text el that are discontinuous.\n    // But layer save/restore needed to be considered.\n    // if (styleFont !== ctx.__fontCache) {\n    //     ctx.font = styleFont;\n    //     if (prevEl !== WILL_BE_RESTORED) {\n    //         ctx.__fontCache = styleFont;\n    //     }\n    // }\n    if (!checkCache || styleFont !== (prevStyle.font || DEFAULT_FONT)) {\n        ctx.font = styleFont;\n    }\n\n    // Use the final font from context-2d, because the final\n    // font might not be the style.font when it is illegal.\n    // But get `ctx.font` might be time consuming.\n    var computedFont = hostEl.__computedFont;\n    if (hostEl.__styleFont !== styleFont) {\n        hostEl.__styleFont = styleFont;\n        computedFont = hostEl.__computedFont = ctx.font;\n    }\n\n    var textPadding = style.textPadding;\n    var textLineHeight = style.textLineHeight;\n\n    var contentBlock = hostEl.__textCotentBlock;\n    if (!contentBlock || hostEl.__dirtyText) {\n        contentBlock = hostEl.__textCotentBlock = parsePlainText(\n            text, computedFont, textPadding, textLineHeight, style.truncate\n        );\n    }\n\n    var outerHeight = contentBlock.outerHeight;\n\n    var textLines = contentBlock.lines;\n    var lineHeight = contentBlock.lineHeight;\n\n    var boxPos = getBoxPosition(outerHeight, style, rect);\n    var baseX = boxPos.baseX;\n    var baseY = boxPos.baseY;\n    var textAlign = boxPos.textAlign || 'left';\n    var textVerticalAlign = boxPos.textVerticalAlign;\n\n    // Origin of textRotation should be the base point of text drawing.\n    applyTextRotation(ctx, style, rect, baseX, baseY);\n\n    var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);\n    var textX = baseX;\n    var textY = boxY;\n\n    if (needDrawBg || textPadding) {\n        // Consider performance, do not call getTextWidth util necessary.\n        var textWidth = getWidth(text, computedFont);\n        var outerWidth = textWidth;\n        textPadding && (outerWidth += textPadding[1] + textPadding[3]);\n        var boxX = adjustTextX(baseX, outerWidth, textAlign);\n\n        needDrawBg && drawBackground(hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight);\n\n        if (textPadding) {\n            textX = getTextXForPadding(baseX, textAlign, textPadding);\n            textY += textPadding[0];\n        }\n    }\n\n    // Always set textAlign and textBase line, because it is difficute to calculate\n    // textAlign from prevEl, and we dont sure whether textAlign will be reset if\n    // font set happened.\n    ctx.textAlign = textAlign;\n    // Force baseline to be \"middle\". Otherwise, if using \"top\", the\n    // text will offset downward a little bit in font \"Microsoft YaHei\".\n    ctx.textBaseline = 'middle';\n    // Set text opacity\n    ctx.globalAlpha = style.opacity || 1;\n\n    // Always set shadowBlur and shadowOffset to avoid leak from displayable.\n    for (var i = 0; i < SHADOW_STYLE_COMMON_PROPS.length; i++) {\n        var propItem = SHADOW_STYLE_COMMON_PROPS[i];\n        var styleProp = propItem[0];\n        var ctxProp = propItem[1];\n        var val = style[styleProp];\n        if (!checkCache || val !== prevStyle[styleProp]) {\n            ctx[ctxProp] = fixShadow(ctx, ctxProp, val || propItem[2]);\n        }\n    }\n\n    // `textBaseline` is set as 'middle'.\n    textY += lineHeight / 2;\n\n    var textStrokeWidth = style.textStrokeWidth;\n    var textStrokeWidthPrev = checkCache ? prevStyle.textStrokeWidth : null;\n    var strokeWidthChanged = !checkCache || textStrokeWidth !== textStrokeWidthPrev;\n    var strokeChanged = !checkCache || strokeWidthChanged || style.textStroke !== prevStyle.textStroke;\n    var textStroke = getStroke(style.textStroke, textStrokeWidth);\n    var textFill = getFill(style.textFill);\n\n    if (textStroke) {\n        if (strokeWidthChanged) {\n            ctx.lineWidth = textStrokeWidth;\n        }\n        if (strokeChanged) {\n            ctx.strokeStyle = textStroke;\n        }\n    }\n    if (textFill) {\n        if (!checkCache || style.textFill !== prevStyle.textFill) {\n            ctx.fillStyle = textFill;\n        }\n    }\n\n    // Optimize simply, in most cases only one line exists.\n    if (textLines.length === 1) {\n        // Fill after stroke so the outline will not cover the main part.\n        textStroke && ctx.strokeText(textLines[0], textX, textY);\n        textFill && ctx.fillText(textLines[0], textX, textY);\n    }\n    else {\n        for (var i = 0; i < textLines.length; i++) {\n            // Fill after stroke so the outline will not cover the main part.\n            textStroke && ctx.strokeText(textLines[i], textX, textY);\n            textFill && ctx.fillText(textLines[i], textX, textY);\n            textY += lineHeight;\n        }\n    }\n}\n\nfunction renderRichText(hostEl, ctx, text, style, rect, prevEl) {\n    // Do not do cache for rich text because of the complexity.\n    // But `RectText` this will be restored, do not need to clear other cache like `Style::bind`.\n    if (prevEl !== WILL_BE_RESTORED) {\n        ctx.__attrCachedBy = ContextCachedBy.NONE;\n    }\n\n    var contentBlock = hostEl.__textCotentBlock;\n\n    if (!contentBlock || hostEl.__dirtyText) {\n        contentBlock = hostEl.__textCotentBlock = parseRichText(text, style);\n    }\n\n    drawRichText(hostEl, ctx, contentBlock, style, rect);\n}\n\nfunction drawRichText(hostEl, ctx, contentBlock, style, rect) {\n    var contentWidth = contentBlock.width;\n    var outerWidth = contentBlock.outerWidth;\n    var outerHeight = contentBlock.outerHeight;\n    var textPadding = style.textPadding;\n\n    var boxPos = getBoxPosition(outerHeight, style, rect);\n    var baseX = boxPos.baseX;\n    var baseY = boxPos.baseY;\n    var textAlign = boxPos.textAlign;\n    var textVerticalAlign = boxPos.textVerticalAlign;\n\n    // Origin of textRotation should be the base point of text drawing.\n    applyTextRotation(ctx, style, rect, baseX, baseY);\n\n    var boxX = adjustTextX(baseX, outerWidth, textAlign);\n    var boxY = adjustTextY(baseY, outerHeight, textVerticalAlign);\n    var xLeft = boxX;\n    var lineTop = boxY;\n    if (textPadding) {\n        xLeft += textPadding[3];\n        lineTop += textPadding[0];\n    }\n    var xRight = xLeft + contentWidth;\n\n    needDrawBackground(style) && drawBackground(\n        hostEl, ctx, style, boxX, boxY, outerWidth, outerHeight\n    );\n\n    for (var i = 0; i < contentBlock.lines.length; i++) {\n        var line = contentBlock.lines[i];\n        var tokens = line.tokens;\n        var tokenCount = tokens.length;\n        var lineHeight = line.lineHeight;\n        var usedWidth = line.width;\n\n        var leftIndex = 0;\n        var lineXLeft = xLeft;\n        var lineXRight = xRight;\n        var rightIndex = tokenCount - 1;\n        var token;\n\n        while (\n            leftIndex < tokenCount\n            && (token = tokens[leftIndex], !token.textAlign || token.textAlign === 'left')\n        ) {\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft, 'left');\n            usedWidth -= token.width;\n            lineXLeft += token.width;\n            leftIndex++;\n        }\n\n        while (\n            rightIndex >= 0\n            && (token = tokens[rightIndex], token.textAlign === 'right')\n        ) {\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXRight, 'right');\n            usedWidth -= token.width;\n            lineXRight -= token.width;\n            rightIndex--;\n        }\n\n        // The other tokens are placed as textAlign 'center' if there is enough space.\n        lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - usedWidth) / 2;\n        while (leftIndex <= rightIndex) {\n            token = tokens[leftIndex];\n            // Consider width specified by user, use 'center' rather than 'left'.\n            placeToken(hostEl, ctx, token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center');\n            lineXLeft += token.width;\n            leftIndex++;\n        }\n\n        lineTop += lineHeight;\n    }\n}\n\nfunction applyTextRotation(ctx, style, rect, x, y) {\n    // textRotation only apply in RectText.\n    if (rect && style.textRotation) {\n        var origin = style.textOrigin;\n        if (origin === 'center') {\n            x = rect.width / 2 + rect.x;\n            y = rect.height / 2 + rect.y;\n        }\n        else if (origin) {\n            x = origin[0] + rect.x;\n            y = origin[1] + rect.y;\n        }\n\n        ctx.translate(x, y);\n        // Positive: anticlockwise\n        ctx.rotate(-style.textRotation);\n        ctx.translate(-x, -y);\n    }\n}\n\nfunction placeToken(hostEl, ctx, token, style, lineHeight, lineTop, x, textAlign) {\n    var tokenStyle = style.rich[token.styleName] || {};\n    tokenStyle.text = token.text;\n\n    // 'ctx.textBaseline' is always set as 'middle', for sake of\n    // the bias of \"Microsoft YaHei\".\n    var textVerticalAlign = token.textVerticalAlign;\n    var y = lineTop + lineHeight / 2;\n    if (textVerticalAlign === 'top') {\n        y = lineTop + token.height / 2;\n    }\n    else if (textVerticalAlign === 'bottom') {\n        y = lineTop + lineHeight - token.height / 2;\n    }\n\n    !token.isLineHolder && needDrawBackground(tokenStyle) && drawBackground(\n        hostEl,\n        ctx,\n        tokenStyle,\n        textAlign === 'right'\n            ? x - token.width\n            : textAlign === 'center'\n            ? x - token.width / 2\n            : x,\n        y - token.height / 2,\n        token.width,\n        token.height\n    );\n\n    var textPadding = token.textPadding;\n    if (textPadding) {\n        x = getTextXForPadding(x, textAlign, textPadding);\n        y -= token.height / 2 - textPadding[2] - token.textHeight / 2;\n    }\n\n    setCtx(ctx, 'shadowBlur', retrieve3(tokenStyle.textShadowBlur, style.textShadowBlur, 0));\n    setCtx(ctx, 'shadowColor', tokenStyle.textShadowColor || style.textShadowColor || 'transparent');\n    setCtx(ctx, 'shadowOffsetX', retrieve3(tokenStyle.textShadowOffsetX, style.textShadowOffsetX, 0));\n    setCtx(ctx, 'shadowOffsetY', retrieve3(tokenStyle.textShadowOffsetY, style.textShadowOffsetY, 0));\n\n    setCtx(ctx, 'textAlign', textAlign);\n    // Force baseline to be \"middle\". Otherwise, if using \"top\", the\n    // text will offset downward a little bit in font \"Microsoft YaHei\".\n    setCtx(ctx, 'textBaseline', 'middle');\n\n    setCtx(ctx, 'font', token.font || DEFAULT_FONT);\n\n    var textStroke = getStroke(tokenStyle.textStroke || style.textStroke, textStrokeWidth);\n    var textFill = getFill(tokenStyle.textFill || style.textFill);\n    var textStrokeWidth = retrieve2(tokenStyle.textStrokeWidth, style.textStrokeWidth);\n\n    // Fill after stroke so the outline will not cover the main part.\n    if (textStroke) {\n        setCtx(ctx, 'lineWidth', textStrokeWidth);\n        setCtx(ctx, 'strokeStyle', textStroke);\n        ctx.strokeText(token.text, x, y);\n    }\n    if (textFill) {\n        setCtx(ctx, 'fillStyle', textFill);\n        ctx.fillText(token.text, x, y);\n    }\n}\n\nfunction needDrawBackground(style) {\n    return !!(\n        style.textBackgroundColor\n        || (style.textBorderWidth && style.textBorderColor)\n    );\n}\n\n// style: {textBackgroundColor, textBorderWidth, textBorderColor, textBorderRadius, text}\n// shape: {x, y, width, height}\nfunction drawBackground(hostEl, ctx, style, x, y, width, height) {\n    var textBackgroundColor = style.textBackgroundColor;\n    var textBorderWidth = style.textBorderWidth;\n    var textBorderColor = style.textBorderColor;\n    var isPlainBg = isString(textBackgroundColor);\n\n    setCtx(ctx, 'shadowBlur', style.textBoxShadowBlur || 0);\n    setCtx(ctx, 'shadowColor', style.textBoxShadowColor || 'transparent');\n    setCtx(ctx, 'shadowOffsetX', style.textBoxShadowOffsetX || 0);\n    setCtx(ctx, 'shadowOffsetY', style.textBoxShadowOffsetY || 0);\n\n    if (isPlainBg || (textBorderWidth && textBorderColor)) {\n        ctx.beginPath();\n        var textBorderRadius = style.textBorderRadius;\n        if (!textBorderRadius) {\n            ctx.rect(x, y, width, height);\n        }\n        else {\n            buildPath(ctx, {\n                x: x, y: y, width: width, height: height, r: textBorderRadius\n            });\n        }\n        ctx.closePath();\n    }\n\n    if (isPlainBg) {\n        setCtx(ctx, 'fillStyle', textBackgroundColor);\n\n        if (style.fillOpacity != null) {\n            var originalGlobalAlpha = ctx.globalAlpha;\n            ctx.globalAlpha = style.fillOpacity * style.opacity;\n            ctx.fill();\n            ctx.globalAlpha = originalGlobalAlpha;\n        }\n        else {\n            ctx.fill();\n        }\n    }\n    else if (isObject$1(textBackgroundColor)) {\n        var image = textBackgroundColor.image;\n\n        image = createOrUpdateImage(\n            image, null, hostEl, onBgImageLoaded, textBackgroundColor\n        );\n        if (image && isImageReady(image)) {\n            ctx.drawImage(image, x, y, width, height);\n        }\n    }\n\n    if (textBorderWidth && textBorderColor) {\n        setCtx(ctx, 'lineWidth', textBorderWidth);\n        setCtx(ctx, 'strokeStyle', textBorderColor);\n\n        if (style.strokeOpacity != null) {\n            var originalGlobalAlpha = ctx.globalAlpha;\n            ctx.globalAlpha = style.strokeOpacity * style.opacity;\n            ctx.stroke();\n            ctx.globalAlpha = originalGlobalAlpha;\n        }\n        else {\n            ctx.stroke();\n        }\n    }\n}\n\nfunction onBgImageLoaded(image, textBackgroundColor) {\n    // Replace image, so that `contain/text.js#parseRichText`\n    // will get correct result in next tick.\n    textBackgroundColor.image = image;\n}\n\nfunction getBoxPosition(blockHeiht, style, rect) {\n    var baseX = style.x || 0;\n    var baseY = style.y || 0;\n    var textAlign = style.textAlign;\n    var textVerticalAlign = style.textVerticalAlign;\n\n    // Text position represented by coord\n    if (rect) {\n        var textPosition = style.textPosition;\n        if (textPosition instanceof Array) {\n            // Percent\n            baseX = rect.x + parsePercent(textPosition[0], rect.width);\n            baseY = rect.y + parsePercent(textPosition[1], rect.height);\n        }\n        else {\n            var res = adjustTextPositionOnRect(\n                textPosition, rect, style.textDistance\n            );\n            baseX = res.x;\n            baseY = res.y;\n            // Default align and baseline when has textPosition\n            textAlign = textAlign || res.textAlign;\n            textVerticalAlign = textVerticalAlign || res.textVerticalAlign;\n        }\n\n        // textOffset is only support in RectText, otherwise\n        // we have to adjust boundingRect for textOffset.\n        var textOffset = style.textOffset;\n        if (textOffset) {\n            baseX += textOffset[0];\n            baseY += textOffset[1];\n        }\n    }\n\n    return {\n        baseX: baseX,\n        baseY: baseY,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\nfunction setCtx(ctx, prop, value) {\n    ctx[prop] = fixShadow(ctx, prop, value);\n    return ctx[prop];\n}\n\n/**\n * @param {string} [stroke] If specified, do not check style.textStroke.\n * @param {string} [lineWidth] If specified, do not check style.textStroke.\n * @param {number} style\n */\nfunction getStroke(stroke, lineWidth) {\n    return (stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none')\n        ? null\n        // TODO pattern and gradient?\n        : (stroke.image || stroke.colorStops)\n        ? '#000'\n        : stroke;\n}\n\nfunction getFill(fill) {\n    return (fill == null || fill === 'none')\n        ? null\n        // TODO pattern and gradient?\n        : (fill.image || fill.colorStops)\n        ? '#000'\n        : fill;\n}\n\nfunction parsePercent(value, maxValue) {\n    if (typeof value === 'string') {\n        if (value.lastIndexOf('%') >= 0) {\n            return parseFloat(value) / 100 * maxValue;\n        }\n        return parseFloat(value);\n    }\n    return value;\n}\n\nfunction getTextXForPadding(x, textAlign, textPadding) {\n    return textAlign === 'right'\n        ? (x - textPadding[1])\n        : textAlign === 'center'\n        ? (x + textPadding[3] / 2 - textPadding[1] / 2)\n        : (x + textPadding[3]);\n}\n\n/**\n * @param {string} text\n * @param {module:zrender/Style} style\n * @return {boolean}\n */\nfunction needDrawText(text, style) {\n    return text != null\n        && (text\n            || style.textBackgroundColor\n            || (style.textBorderWidth && style.textBorderColor)\n            || style.textPadding\n        );\n}\n\n/**\n * Mixin for drawing text in a element bounding rect\n * @module zrender/mixin/RectText\n */\n\nvar tmpRect$1 = new BoundingRect();\n\nvar RectText = function () {};\n\nRectText.prototype = {\n\n    constructor: RectText,\n\n    /**\n     * Draw text in a rect with specified position.\n     * @param  {CanvasRenderingContext2D} ctx\n     * @param  {Object} rect Displayable rect\n     */\n    drawRectText: function (ctx, rect) {\n        var style = this.style;\n\n        rect = style.textRect || rect;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        var text = style.text;\n\n        // Convert to string\n        text != null && (text += '');\n\n        if (!needDrawText(text, style)) {\n            return;\n        }\n\n        // FIXME\n        // Do not provide prevEl to `textHelper.renderText` for ctx prop cache,\n        // but use `ctx.save()` and `ctx.restore()`. Because the cache for rect\n        // text propably break the cache for its host elements.\n        ctx.save();\n\n        // Transform rect to view space\n        var transform = this.transform;\n        if (!style.transformText) {\n            if (transform) {\n                tmpRect$1.copy(rect);\n                tmpRect$1.applyTransform(transform);\n                rect = tmpRect$1;\n            }\n        }\n        else {\n            this.setTransform(ctx);\n        }\n\n        // transformText and textRotation can not be used at the same time.\n        renderText(this, ctx, text, style, rect, WILL_BE_RESTORED);\n\n        ctx.restore();\n    }\n};\n\n/**\n * 可绘制的图形基类\n * Base class of all displayable graphic objects\n * @module zrender/graphic/Displayable\n */\n\n\n/**\n * @alias module:zrender/graphic/Displayable\n * @extends module:zrender/Element\n * @extends module:zrender/graphic/mixin/RectText\n */\nfunction Displayable(opts) {\n\n    opts = opts || {};\n\n    Element.call(this, opts);\n\n    // Extend properties\n    for (var name in opts) {\n        if (\n            opts.hasOwnProperty(name)\n                && name !== 'style'\n        ) {\n            this[name] = opts[name];\n        }\n    }\n\n    /**\n     * @type {module:zrender/graphic/Style}\n     */\n    this.style = new Style(opts.style, this);\n\n    this._rect = null;\n    // Shapes for cascade clipping.\n    this.__clipPaths = [];\n\n    // FIXME Stateful must be mixined after style is setted\n    // Stateful.call(this, opts);\n}\n\nDisplayable.prototype = {\n\n    constructor: Displayable,\n\n    type: 'displayable',\n\n    /**\n     * Displayable 是否为脏，Painter 中会根据该标记判断是否需要是否需要重新绘制\n     * Dirty flag. From which painter will determine if this displayable object needs brush\n     * @name module:zrender/graphic/Displayable#__dirty\n     * @type {boolean}\n     */\n    __dirty: true,\n\n    /**\n     * 图形是否可见，为true时不绘制图形，但是仍能触发鼠标事件\n     * If ignore drawing of the displayable object. Mouse event will still be triggered\n     * @name module:/zrender/graphic/Displayable#invisible\n     * @type {boolean}\n     * @default false\n     */\n    invisible: false,\n\n    /**\n     * @name module:/zrender/graphic/Displayable#z\n     * @type {number}\n     * @default 0\n     */\n    z: 0,\n\n    /**\n     * @name module:/zrender/graphic/Displayable#z\n     * @type {number}\n     * @default 0\n     */\n    z2: 0,\n\n    /**\n     * z层level，决定绘画在哪层canvas中\n     * @name module:/zrender/graphic/Displayable#zlevel\n     * @type {number}\n     * @default 0\n     */\n    zlevel: 0,\n\n    /**\n     * 是否可拖拽\n     * @name module:/zrender/graphic/Displayable#draggable\n     * @type {boolean}\n     * @default false\n     */\n    draggable: false,\n\n    /**\n     * 是否正在拖拽\n     * @name module:/zrender/graphic/Displayable#draggable\n     * @type {boolean}\n     * @default false\n     */\n    dragging: false,\n\n    /**\n     * 是否相应鼠标事件\n     * @name module:/zrender/graphic/Displayable#silent\n     * @type {boolean}\n     * @default false\n     */\n    silent: false,\n\n    /**\n     * If enable culling\n     * @type {boolean}\n     * @default false\n     */\n    culling: false,\n\n    /**\n     * Mouse cursor when hovered\n     * @name module:/zrender/graphic/Displayable#cursor\n     * @type {string}\n     */\n    cursor: 'pointer',\n\n    /**\n     * If hover area is bounding rect\n     * @name module:/zrender/graphic/Displayable#rectHover\n     * @type {string}\n     */\n    rectHover: false,\n\n    /**\n     * Render the element progressively when the value >= 0,\n     * usefull for large data.\n     * @type {boolean}\n     */\n    progressive: false,\n\n    /**\n     * @type {boolean}\n     */\n    incremental: false,\n    /**\n     * Scale ratio for global scale.\n     * @type {boolean}\n     */\n    globalScaleRatio: 1,\n\n    beforeBrush: function (ctx) {},\n\n    afterBrush: function (ctx) {},\n\n    /**\n     * 图形绘制方法\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    // Interface\n    brush: function (ctx, prevEl) {},\n\n    /**\n     * 获取最小包围盒\n     * @return {module:zrender/core/BoundingRect}\n     */\n    // Interface\n    getBoundingRect: function () {},\n\n    /**\n     * 判断坐标 x, y 是否在图形上\n     * If displayable element contain coord x, y\n     * @param  {number} x\n     * @param  {number} y\n     * @return {boolean}\n     */\n    contain: function (x, y) {\n        return this.rectContain(x, y);\n    },\n\n    /**\n     * @param  {Function} cb\n     * @param  {}   context\n     */\n    traverse: function (cb, context) {\n        cb.call(context, this);\n    },\n\n    /**\n     * 判断坐标 x, y 是否在图形的包围盒上\n     * If bounding rect of element contain coord x, y\n     * @param  {number} x\n     * @param  {number} y\n     * @return {boolean}\n     */\n    rectContain: function (x, y) {\n        var coord = this.transformCoordToLocal(x, y);\n        var rect = this.getBoundingRect();\n        return rect.contain(coord[0], coord[1]);\n    },\n\n    /**\n     * 标记图形元素为脏，并且在下一帧重绘\n     * Mark displayable element dirty and refresh next frame\n     */\n    dirty: function () {\n        this.__dirty = this.__dirtyText = true;\n\n        this._rect = null;\n\n        this.__zr && this.__zr.refresh();\n    },\n\n    /**\n     * 图形是否会触发事件\n     * If displayable object binded any event\n     * @return {boolean}\n     */\n    // TODO, 通过 bind 绑定的事件\n    // isSilent: function () {\n    //     return !(\n    //         this.hoverable || this.draggable\n    //         || this.onmousemove || this.onmouseover || this.onmouseout\n    //         || this.onmousedown || this.onmouseup || this.onclick\n    //         || this.ondragenter || this.ondragover || this.ondragleave\n    //         || this.ondrop\n    //     );\n    // },\n    /**\n     * Alias for animate('style')\n     * @param {boolean} loop\n     */\n    animateStyle: function (loop) {\n        return this.animate('style', loop);\n    },\n\n    attrKV: function (key, value) {\n        if (key !== 'style') {\n            Element.prototype.attrKV.call(this, key, value);\n        }\n        else {\n            this.style.set(value);\n        }\n    },\n\n    /**\n     * @param {Object|string} key\n     * @param {*} value\n     */\n    setStyle: function (key, value) {\n        this.style.set(key, value);\n        this.dirty(false);\n        return this;\n    },\n\n    /**\n     * Use given style object\n     * @param  {Object} obj\n     */\n    useStyle: function (obj) {\n        this.style = new Style(obj, this);\n        this.dirty(false);\n        return this;\n    }\n};\n\ninherits(Displayable, Element);\n\nmixin(Displayable, RectText);\n\n/**\n * @alias zrender/graphic/Image\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nfunction ZImage(opts) {\n    Displayable.call(this, opts);\n}\n\nZImage.prototype = {\n\n    constructor: ZImage,\n\n    type: 'image',\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n        var src = style.image;\n\n        // Must bind each time\n        style.bind(ctx, this, prevEl);\n\n        var image = this._image = createOrUpdateImage(\n            src,\n            this._image,\n            this,\n            this.onload\n        );\n\n        if (!image || !isImageReady(image)) {\n            return;\n        }\n\n        // 图片已经加载完成\n        // if (image.nodeName.toUpperCase() == 'IMG') {\n        //     if (!image.complete) {\n        //         return;\n        //     }\n        // }\n        // Else is canvas\n\n        var x = style.x || 0;\n        var y = style.y || 0;\n        var width = style.width;\n        var height = style.height;\n        var aspect = image.width / image.height;\n        if (width == null && height != null) {\n            // Keep image/height ratio\n            width = height * aspect;\n        }\n        else if (height == null && width != null) {\n            height = width / aspect;\n        }\n        else if (width == null && height == null) {\n            width = image.width;\n            height = image.height;\n        }\n\n        // 设置transform\n        this.setTransform(ctx);\n\n        if (style.sWidth && style.sHeight) {\n            var sx = style.sx || 0;\n            var sy = style.sy || 0;\n            ctx.drawImage(\n                image,\n                sx, sy, style.sWidth, style.sHeight,\n                x, y, width, height\n            );\n        }\n        else if (style.sx && style.sy) {\n            var sx = style.sx;\n            var sy = style.sy;\n            var sWidth = width - sx;\n            var sHeight = height - sy;\n            ctx.drawImage(\n                image,\n                sx, sy, sWidth, sHeight,\n                x, y, width, height\n            );\n        }\n        else {\n            ctx.drawImage(image, x, y, width, height);\n        }\n\n        // Draw rect text\n        if (style.text != null) {\n            // Only restore transform when needs draw text.\n            this.restoreTransform(ctx);\n            this.drawRectText(ctx, this.getBoundingRect());\n        }\n    },\n\n    getBoundingRect: function () {\n        var style = this.style;\n        if (!this._rect) {\n            this._rect = new BoundingRect(\n                style.x || 0, style.y || 0, style.width || 0, style.height || 0\n            );\n        }\n        return this._rect;\n    }\n};\n\ninherits(ZImage, Displayable);\n\nvar HOVER_LAYER_ZLEVEL = 1e5;\nvar CANVAS_ZLEVEL = 314159;\n\nvar EL_AFTER_INCREMENTAL_INC = 0.01;\nvar INCREMENTAL_INC = 0.001;\n\nfunction parseInt10(val) {\n    return parseInt(val, 10);\n}\n\nfunction isLayerValid(layer) {\n    if (!layer) {\n        return false;\n    }\n\n    if (layer.__builtin__) {\n        return true;\n    }\n\n    if (typeof (layer.resize) !== 'function'\n        || typeof (layer.refresh) !== 'function'\n    ) {\n        return false;\n    }\n\n    return true;\n}\n\nvar tmpRect = new BoundingRect(0, 0, 0, 0);\nvar viewRect = new BoundingRect(0, 0, 0, 0);\nfunction isDisplayableCulled(el, width, height) {\n    tmpRect.copy(el.getBoundingRect());\n    if (el.transform) {\n        tmpRect.applyTransform(el.transform);\n    }\n    viewRect.width = width;\n    viewRect.height = height;\n    return !tmpRect.intersect(viewRect);\n}\n\nfunction isClipPathChanged(clipPaths, prevClipPaths) {\n    if (clipPaths === prevClipPaths) { // Can both be null or undefined\n        return false;\n    }\n\n    if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) {\n        return true;\n    }\n    for (var i = 0; i < clipPaths.length; i++) {\n        if (clipPaths[i] !== prevClipPaths[i]) {\n            return true;\n        }\n    }\n}\n\nfunction doClip(clipPaths, ctx) {\n    for (var i = 0; i < clipPaths.length; i++) {\n        var clipPath = clipPaths[i];\n\n        clipPath.setTransform(ctx);\n        ctx.beginPath();\n        clipPath.buildPath(ctx, clipPath.shape);\n        ctx.clip();\n        // Transform back\n        clipPath.restoreTransform(ctx);\n    }\n}\n\nfunction createRoot(width, height) {\n    var domRoot = document.createElement('div');\n\n    // domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬\n    domRoot.style.cssText = [\n        'position:relative',\n        'overflow:hidden',\n        'width:' + width + 'px',\n        'height:' + height + 'px',\n        'padding:0',\n        'margin:0',\n        'border-width:0'\n    ].join(';') + ';';\n\n    return domRoot;\n}\n\n\n/**\n * @alias module:zrender/Painter\n * @constructor\n * @param {HTMLElement} root 绘图容器\n * @param {module:zrender/Storage} storage\n * @param {Object} opts\n */\nvar Painter = function (root, storage, opts) {\n\n    this.type = 'canvas';\n\n    // In node environment using node-canvas\n    var singleCanvas = !root.nodeName // In node ?\n        || root.nodeName.toUpperCase() === 'CANVAS';\n\n    this._opts = opts = extend({}, opts || {});\n\n    /**\n     * @type {number}\n     */\n    this.dpr = opts.devicePixelRatio || devicePixelRatio;\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._singleCanvas = singleCanvas;\n    /**\n     * 绘图容器\n     * @type {HTMLElement}\n     */\n    this.root = root;\n\n    var rootStyle = root.style;\n\n    if (rootStyle) {\n        rootStyle['-webkit-tap-highlight-color'] = 'transparent';\n        rootStyle['-webkit-user-select'] =\n        rootStyle['user-select'] =\n        rootStyle['-webkit-touch-callout'] = 'none';\n\n        root.innerHTML = '';\n    }\n\n    /**\n     * @type {module:zrender/Storage}\n     */\n    this.storage = storage;\n\n    /**\n     * @type {Array.<number>}\n     * @private\n     */\n    var zlevelList = this._zlevelList = [];\n\n    /**\n     * @type {Object.<string, module:zrender/Layer>}\n     * @private\n     */\n    var layers = this._layers = {};\n\n    /**\n     * @type {Object.<string, Object>}\n     * @private\n     */\n    this._layerConfig = {};\n\n    /**\n     * zrender will do compositing when root is a canvas and have multiple zlevels.\n     */\n    this._needsManuallyCompositing = false;\n\n    if (!singleCanvas) {\n        this._width = this._getSize(0);\n        this._height = this._getSize(1);\n\n        var domRoot = this._domRoot = createRoot(\n            this._width, this._height\n        );\n        root.appendChild(domRoot);\n    }\n    else {\n        var width = root.width;\n        var height = root.height;\n\n        if (opts.width != null) {\n            width = opts.width;\n        }\n        if (opts.height != null) {\n            height = opts.height;\n        }\n        this.dpr = opts.devicePixelRatio || 1;\n\n        // Use canvas width and height directly\n        root.width = width * this.dpr;\n        root.height = height * this.dpr;\n\n        this._width = width;\n        this._height = height;\n\n        // Create layer if only one given canvas\n        // Device can be specified to create a high dpi image.\n        var mainLayer = new Layer(root, this, this.dpr);\n        mainLayer.__builtin__ = true;\n        mainLayer.initContext();\n        // FIXME Use canvas width and height\n        // mainLayer.resize(width, height);\n        layers[CANVAS_ZLEVEL] = mainLayer;\n        mainLayer.zlevel = CANVAS_ZLEVEL;\n        // Not use common zlevel.\n        zlevelList.push(CANVAS_ZLEVEL);\n\n        this._domRoot = root;\n    }\n\n    /**\n     * @type {module:zrender/Layer}\n     * @private\n     */\n    this._hoverlayer = null;\n\n    this._hoverElements = [];\n};\n\nPainter.prototype = {\n\n    constructor: Painter,\n\n    getType: function () {\n        return 'canvas';\n    },\n\n    /**\n     * If painter use a single canvas\n     * @return {boolean}\n     */\n    isSingleCanvas: function () {\n        return this._singleCanvas;\n    },\n    /**\n     * @return {HTMLDivElement}\n     */\n    getViewportRoot: function () {\n        return this._domRoot;\n    },\n\n    getViewportRootOffset: function () {\n        var viewportRoot = this.getViewportRoot();\n        if (viewportRoot) {\n            return {\n                offsetLeft: viewportRoot.offsetLeft || 0,\n                offsetTop: viewportRoot.offsetTop || 0\n            };\n        }\n    },\n\n    /**\n     * 刷新\n     * @param {boolean} [paintAll=false] 强制绘制所有displayable\n     */\n    refresh: function (paintAll) {\n\n        var list = this.storage.getDisplayList(true);\n\n        var zlevelList = this._zlevelList;\n\n        this._redrawId = Math.random();\n\n        this._paintList(list, paintAll, this._redrawId);\n\n        // Paint custum layers\n        for (var i = 0; i < zlevelList.length; i++) {\n            var z = zlevelList[i];\n            var layer = this._layers[z];\n            if (!layer.__builtin__ && layer.refresh) {\n                var clearColor = i === 0 ? this._backgroundColor : null;\n                layer.refresh(clearColor);\n            }\n        }\n\n        this.refreshHover();\n\n        return this;\n    },\n\n    addHover: function (el, hoverStyle) {\n        if (el.__hoverMir) {\n            return;\n        }\n        var elMirror = new el.constructor({\n            style: el.style,\n            shape: el.shape,\n            z: el.z,\n            z2: el.z2,\n            silent: el.silent\n        });\n        elMirror.__from = el;\n        el.__hoverMir = elMirror;\n        hoverStyle && elMirror.setStyle(hoverStyle);\n        this._hoverElements.push(elMirror);\n\n        return elMirror;\n    },\n\n    removeHover: function (el) {\n        var elMirror = el.__hoverMir;\n        var hoverElements = this._hoverElements;\n        var idx = indexOf(hoverElements, elMirror);\n        if (idx >= 0) {\n            hoverElements.splice(idx, 1);\n        }\n        el.__hoverMir = null;\n    },\n\n    clearHover: function (el) {\n        var hoverElements = this._hoverElements;\n        for (var i = 0; i < hoverElements.length; i++) {\n            var from = hoverElements[i].__from;\n            if (from) {\n                from.__hoverMir = null;\n            }\n        }\n        hoverElements.length = 0;\n    },\n\n    refreshHover: function () {\n        var hoverElements = this._hoverElements;\n        var len = hoverElements.length;\n        var hoverLayer = this._hoverlayer;\n        hoverLayer && hoverLayer.clear();\n\n        if (!len) {\n            return;\n        }\n        sort(hoverElements, this.storage.displayableSortFunc);\n\n        // Use a extream large zlevel\n        // FIXME?\n        if (!hoverLayer) {\n            hoverLayer = this._hoverlayer = this.getLayer(HOVER_LAYER_ZLEVEL);\n        }\n\n        var scope = {};\n        hoverLayer.ctx.save();\n        for (var i = 0; i < len;) {\n            var el = hoverElements[i];\n            var originalEl = el.__from;\n            // Original el is removed\n            // PENDING\n            if (!(originalEl && originalEl.__zr)) {\n                hoverElements.splice(i, 1);\n                originalEl.__hoverMir = null;\n                len--;\n                continue;\n            }\n            i++;\n\n            // Use transform\n            // FIXME style and shape ?\n            if (!originalEl.invisible) {\n                el.transform = originalEl.transform;\n                el.invTransform = originalEl.invTransform;\n                el.__clipPaths = originalEl.__clipPaths;\n                // el.\n                this._doPaintEl(el, hoverLayer, true, scope);\n            }\n        }\n\n        hoverLayer.ctx.restore();\n    },\n\n    getHoverLayer: function () {\n        return this.getLayer(HOVER_LAYER_ZLEVEL);\n    },\n\n    _paintList: function (list, paintAll, redrawId) {\n        if (this._redrawId !== redrawId) {\n            return;\n        }\n\n        paintAll = paintAll || false;\n\n        this._updateLayerStatus(list);\n\n        var finished = this._doPaintList(list, paintAll);\n\n        if (this._needsManuallyCompositing) {\n            this._compositeManually();\n        }\n\n        if (!finished) {\n            var self = this;\n            requestAnimationFrame(function () {\n                self._paintList(list, paintAll, redrawId);\n            });\n        }\n    },\n\n    _compositeManually: function () {\n        var ctx = this.getLayer(CANVAS_ZLEVEL).ctx;\n        var width = this._domRoot.width;\n        var height = this._domRoot.height;\n        ctx.clearRect(0, 0, width, height);\n        // PENDING, If only builtin layer?\n        this.eachBuiltinLayer(function (layer) {\n            if (layer.virtual) {\n                ctx.drawImage(layer.dom, 0, 0, width, height);\n            }\n        });\n    },\n\n    _doPaintList: function (list, paintAll) {\n        var layerList = [];\n        for (var zi = 0; zi < this._zlevelList.length; zi++) {\n            var zlevel = this._zlevelList[zi];\n            var layer = this._layers[zlevel];\n            if (layer.__builtin__\n                && layer !== this._hoverlayer\n                && (layer.__dirty || paintAll)\n            ) {\n                layerList.push(layer);\n            }\n        }\n\n        var finished = true;\n\n        for (var k = 0; k < layerList.length; k++) {\n            var layer = layerList[k];\n            var ctx = layer.ctx;\n            var scope = {};\n            ctx.save();\n\n            var start = paintAll ? layer.__startIndex : layer.__drawIndex;\n\n            var useTimer = !paintAll && layer.incremental && Date.now;\n            var startTime = useTimer && Date.now();\n\n            var clearColor = layer.zlevel === this._zlevelList[0]\n                ? this._backgroundColor : null;\n            // All elements in this layer are cleared.\n            if (layer.__startIndex === layer.__endIndex) {\n                layer.clear(false, clearColor);\n            }\n            else if (start === layer.__startIndex) {\n                var firstEl = list[start];\n                if (!firstEl.incremental || !firstEl.notClear || paintAll) {\n                    layer.clear(false, clearColor);\n                }\n            }\n            if (start === -1) {\n                console.error('For some unknown reason. drawIndex is -1');\n                start = layer.__startIndex;\n            }\n            for (var i = start; i < layer.__endIndex; i++) {\n                var el = list[i];\n                this._doPaintEl(el, layer, paintAll, scope);\n                el.__dirty = el.__dirtyText = false;\n\n                if (useTimer) {\n                    // Date.now can be executed in 13,025,305 ops/second.\n                    var dTime = Date.now() - startTime;\n                    // Give 15 millisecond to draw.\n                    // The rest elements will be drawn in the next frame.\n                    if (dTime > 15) {\n                        break;\n                    }\n                }\n            }\n\n            layer.__drawIndex = i;\n\n            if (layer.__drawIndex < layer.__endIndex) {\n                finished = false;\n            }\n\n            if (scope.prevElClipPaths) {\n                // Needs restore the state. If last drawn element is in the clipping area.\n                ctx.restore();\n            }\n\n            ctx.restore();\n        }\n\n        if (env$1.wxa) {\n            // Flush for weixin application\n            each$1(this._layers, function (layer) {\n                if (layer && layer.ctx && layer.ctx.draw) {\n                    layer.ctx.draw();\n                }\n            });\n        }\n\n        return finished;\n    },\n\n    _doPaintEl: function (el, currentLayer, forcePaint, scope) {\n        var ctx = currentLayer.ctx;\n        var m = el.transform;\n        if (\n            (currentLayer.__dirty || forcePaint)\n            // Ignore invisible element\n            && !el.invisible\n            // Ignore transparent element\n            && el.style.opacity !== 0\n            // Ignore scale 0 element, in some environment like node-canvas\n            // Draw a scale 0 element can cause all following draw wrong\n            // And setTransform with scale 0 will cause set back transform failed.\n            && !(m && !m[0] && !m[3])\n            // Ignore culled element\n            && !(el.culling && isDisplayableCulled(el, this._width, this._height))\n        ) {\n\n            var clipPaths = el.__clipPaths;\n\n            // Optimize when clipping on group with several elements\n            if (!scope.prevElClipPaths\n                || isClipPathChanged(clipPaths, scope.prevElClipPaths)\n            ) {\n                // If has previous clipping state, restore from it\n                if (scope.prevElClipPaths) {\n                    currentLayer.ctx.restore();\n                    scope.prevElClipPaths = null;\n\n                    // Reset prevEl since context has been restored\n                    scope.prevEl = null;\n                }\n                // New clipping state\n                if (clipPaths) {\n                    ctx.save();\n                    doClip(clipPaths, ctx);\n                    scope.prevElClipPaths = clipPaths;\n                }\n            }\n            el.beforeBrush && el.beforeBrush(ctx);\n\n            el.brush(ctx, scope.prevEl || null);\n            scope.prevEl = el;\n\n            el.afterBrush && el.afterBrush(ctx);\n        }\n    },\n\n    /**\n     * 获取 zlevel 所在层，如果不存在则会创建一个新的层\n     * @param {number} zlevel\n     * @param {boolean} virtual Virtual layer will not be inserted into dom.\n     * @return {module:zrender/Layer}\n     */\n    getLayer: function (zlevel, virtual) {\n        if (this._singleCanvas && !this._needsManuallyCompositing) {\n            zlevel = CANVAS_ZLEVEL;\n        }\n        var layer = this._layers[zlevel];\n        if (!layer) {\n            // Create a new layer\n            layer = new Layer('zr_' + zlevel, this, this.dpr);\n            layer.zlevel = zlevel;\n            layer.__builtin__ = true;\n\n            if (this._layerConfig[zlevel]) {\n                merge(layer, this._layerConfig[zlevel], true);\n            }\n\n            if (virtual) {\n                layer.virtual = virtual;\n            }\n\n            this.insertLayer(zlevel, layer);\n\n            // Context is created after dom inserted to document\n            // Or excanvas will get 0px clientWidth and clientHeight\n            layer.initContext();\n        }\n\n        return layer;\n    },\n\n    insertLayer: function (zlevel, layer) {\n\n        var layersMap = this._layers;\n        var zlevelList = this._zlevelList;\n        var len = zlevelList.length;\n        var prevLayer = null;\n        var i = -1;\n        var domRoot = this._domRoot;\n\n        if (layersMap[zlevel]) {\n            log$1('ZLevel ' + zlevel + ' has been used already');\n            return;\n        }\n        // Check if is a valid layer\n        if (!isLayerValid(layer)) {\n            log$1('Layer of zlevel ' + zlevel + ' is not valid');\n            return;\n        }\n\n        if (len > 0 && zlevel > zlevelList[0]) {\n            for (i = 0; i < len - 1; i++) {\n                if (\n                    zlevelList[i] < zlevel\n                    && zlevelList[i + 1] > zlevel\n                ) {\n                    break;\n                }\n            }\n            prevLayer = layersMap[zlevelList[i]];\n        }\n        zlevelList.splice(i + 1, 0, zlevel);\n\n        layersMap[zlevel] = layer;\n\n        // Vitual layer will not directly show on the screen.\n        // (It can be a WebGL layer and assigned to a ZImage element)\n        // But it still under management of zrender.\n        if (!layer.virtual) {\n            if (prevLayer) {\n                var prevDom = prevLayer.dom;\n                if (prevDom.nextSibling) {\n                    domRoot.insertBefore(\n                        layer.dom,\n                        prevDom.nextSibling\n                    );\n                }\n                else {\n                    domRoot.appendChild(layer.dom);\n                }\n            }\n            else {\n                if (domRoot.firstChild) {\n                    domRoot.insertBefore(layer.dom, domRoot.firstChild);\n                }\n                else {\n                    domRoot.appendChild(layer.dom);\n                }\n            }\n        }\n    },\n\n    // Iterate each layer\n    eachLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            cb.call(context, this._layers[z], z);\n        }\n    },\n\n    // Iterate each buildin layer\n    eachBuiltinLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var layer;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            layer = this._layers[z];\n            if (layer.__builtin__) {\n                cb.call(context, layer, z);\n            }\n        }\n    },\n\n    // Iterate each other layer except buildin layer\n    eachOtherLayer: function (cb, context) {\n        var zlevelList = this._zlevelList;\n        var layer;\n        var z;\n        var i;\n        for (i = 0; i < zlevelList.length; i++) {\n            z = zlevelList[i];\n            layer = this._layers[z];\n            if (!layer.__builtin__) {\n                cb.call(context, layer, z);\n            }\n        }\n    },\n\n    /**\n     * 获取所有已创建的层\n     * @param {Array.<module:zrender/Layer>} [prevLayer]\n     */\n    getLayers: function () {\n        return this._layers;\n    },\n\n    _updateLayerStatus: function (list) {\n\n        this.eachBuiltinLayer(function (layer, z) {\n            layer.__dirty = layer.__used = false;\n        });\n\n        function updatePrevLayer(idx) {\n            if (prevLayer) {\n                if (prevLayer.__endIndex !== idx) {\n                    prevLayer.__dirty = true;\n                }\n                prevLayer.__endIndex = idx;\n            }\n        }\n\n        if (this._singleCanvas) {\n            for (var i = 1; i < list.length; i++) {\n                var el = list[i];\n                if (el.zlevel !== list[i - 1].zlevel || el.incremental) {\n                    this._needsManuallyCompositing = true;\n                    break;\n                }\n            }\n        }\n\n        var prevLayer = null;\n        var incrementalLayerCount = 0;\n        for (var i = 0; i < list.length; i++) {\n            var el = list[i];\n            var zlevel = el.zlevel;\n            var layer;\n            // PENDING If change one incremental element style ?\n            // TODO Where there are non-incremental elements between incremental elements.\n            if (el.incremental) {\n                layer = this.getLayer(zlevel + INCREMENTAL_INC, this._needsManuallyCompositing);\n                layer.incremental = true;\n                incrementalLayerCount = 1;\n            }\n            else {\n                layer = this.getLayer(zlevel + (incrementalLayerCount > 0 ? EL_AFTER_INCREMENTAL_INC : 0), this._needsManuallyCompositing);\n            }\n\n            if (!layer.__builtin__) {\n                log$1('ZLevel ' + zlevel + ' has been used by unkown layer ' + layer.id);\n            }\n\n            if (layer !== prevLayer) {\n                layer.__used = true;\n                if (layer.__startIndex !== i) {\n                    layer.__dirty = true;\n                }\n                layer.__startIndex = i;\n                if (!layer.incremental) {\n                    layer.__drawIndex = i;\n                }\n                else {\n                    // Mark layer draw index needs to update.\n                    layer.__drawIndex = -1;\n                }\n                updatePrevLayer(i);\n                prevLayer = layer;\n            }\n            if (el.__dirty) {\n                layer.__dirty = true;\n                if (layer.incremental && layer.__drawIndex < 0) {\n                    // Start draw from the first dirty element.\n                    layer.__drawIndex = i;\n                }\n            }\n        }\n\n        updatePrevLayer(i);\n\n        this.eachBuiltinLayer(function (layer, z) {\n            // Used in last frame but not in this frame. Needs clear\n            if (!layer.__used && layer.getElementCount() > 0) {\n                layer.__dirty = true;\n                layer.__startIndex = layer.__endIndex = layer.__drawIndex = 0;\n            }\n            // For incremental layer. In case start index changed and no elements are dirty.\n            if (layer.__dirty && layer.__drawIndex < 0) {\n                layer.__drawIndex = layer.__startIndex;\n            }\n        });\n    },\n\n    /**\n     * 清除hover层外所有内容\n     */\n    clear: function () {\n        this.eachBuiltinLayer(this._clearLayer);\n        return this;\n    },\n\n    _clearLayer: function (layer) {\n        layer.clear();\n    },\n\n    setBackgroundColor: function (backgroundColor) {\n        this._backgroundColor = backgroundColor;\n    },\n\n    /**\n     * 修改指定zlevel的绘制参数\n     *\n     * @param {string} zlevel\n     * @param {Object} config 配置对象\n     * @param {string} [config.clearColor=0] 每次清空画布的颜色\n     * @param {string} [config.motionBlur=false] 是否开启动态模糊\n     * @param {number} [config.lastFrameAlpha=0.7]\n     *                 在开启动态模糊的时候使用，与上一帧混合的alpha值，值越大尾迹越明显\n     */\n    configLayer: function (zlevel, config) {\n        if (config) {\n            var layerConfig = this._layerConfig;\n            if (!layerConfig[zlevel]) {\n                layerConfig[zlevel] = config;\n            }\n            else {\n                merge(layerConfig[zlevel], config, true);\n            }\n\n            for (var i = 0; i < this._zlevelList.length; i++) {\n                var _zlevel = this._zlevelList[i];\n                if (_zlevel === zlevel || _zlevel === zlevel + EL_AFTER_INCREMENTAL_INC) {\n                    var layer = this._layers[_zlevel];\n                    merge(layer, layerConfig[zlevel], true);\n                }\n            }\n        }\n    },\n\n    /**\n     * 删除指定层\n     * @param {number} zlevel 层所在的zlevel\n     */\n    delLayer: function (zlevel) {\n        var layers = this._layers;\n        var zlevelList = this._zlevelList;\n        var layer = layers[zlevel];\n        if (!layer) {\n            return;\n        }\n        layer.dom.parentNode.removeChild(layer.dom);\n        delete layers[zlevel];\n\n        zlevelList.splice(indexOf(zlevelList, zlevel), 1);\n    },\n\n    /**\n     * 区域大小变化后重绘\n     */\n    resize: function (width, height) {\n        if (!this._domRoot.style) { // Maybe in node or worker\n            if (width == null || height == null) {\n                return;\n            }\n            this._width = width;\n            this._height = height;\n\n            this.getLayer(CANVAS_ZLEVEL).resize(width, height);\n        }\n        else {\n            var domRoot = this._domRoot;\n            // FIXME Why ?\n            domRoot.style.display = 'none';\n\n            // Save input w/h\n            var opts = this._opts;\n            width != null && (opts.width = width);\n            height != null && (opts.height = height);\n\n            width = this._getSize(0);\n            height = this._getSize(1);\n\n            domRoot.style.display = '';\n\n            // 优化没有实际改变的resize\n            if (this._width !== width || height !== this._height) {\n                domRoot.style.width = width + 'px';\n                domRoot.style.height = height + 'px';\n\n                for (var id in this._layers) {\n                    if (this._layers.hasOwnProperty(id)) {\n                        this._layers[id].resize(width, height);\n                    }\n                }\n                each$1(this._progressiveLayers, function (layer) {\n                    layer.resize(width, height);\n                });\n\n                this.refresh(true);\n            }\n\n            this._width = width;\n            this._height = height;\n\n        }\n        return this;\n    },\n\n    /**\n     * 清除单独的一个层\n     * @param {number} zlevel\n     */\n    clearLayer: function (zlevel) {\n        var layer = this._layers[zlevel];\n        if (layer) {\n            layer.clear();\n        }\n    },\n\n    /**\n     * 释放\n     */\n    dispose: function () {\n        this.root.innerHTML = '';\n\n        this.root =\n        this.storage =\n\n        this._domRoot =\n        this._layers = null;\n    },\n\n    /**\n     * Get canvas which has all thing rendered\n     * @param {Object} opts\n     * @param {string} [opts.backgroundColor]\n     * @param {number} [opts.pixelRatio]\n     */\n    getRenderedCanvas: function (opts) {\n        opts = opts || {};\n        if (this._singleCanvas && !this._compositeManually) {\n            return this._layers[CANVAS_ZLEVEL].dom;\n        }\n\n        var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr);\n        imageLayer.initContext();\n        imageLayer.clear(false, opts.backgroundColor || this._backgroundColor);\n\n        if (opts.pixelRatio <= this.dpr) {\n            this.refresh();\n\n            var width = imageLayer.dom.width;\n            var height = imageLayer.dom.height;\n            var ctx = imageLayer.ctx;\n            this.eachLayer(function (layer) {\n                if (layer.__builtin__) {\n                    ctx.drawImage(layer.dom, 0, 0, width, height);\n                }\n                else if (layer.renderToCanvas) {\n                    imageLayer.ctx.save();\n                    layer.renderToCanvas(imageLayer.ctx);\n                    imageLayer.ctx.restore();\n                }\n            });\n        }\n        else {\n            // PENDING, echarts-gl and incremental rendering.\n            var scope = {};\n            var displayList = this.storage.getDisplayList(true);\n            for (var i = 0; i < displayList.length; i++) {\n                var el = displayList[i];\n                this._doPaintEl(el, imageLayer, true, scope);\n            }\n        }\n\n        return imageLayer.dom;\n    },\n    /**\n     * 获取绘图区域宽度\n     */\n    getWidth: function () {\n        return this._width;\n    },\n\n    /**\n     * 获取绘图区域高度\n     */\n    getHeight: function () {\n        return this._height;\n    },\n\n    _getSize: function (whIdx) {\n        var opts = this._opts;\n        var wh = ['width', 'height'][whIdx];\n        var cwh = ['clientWidth', 'clientHeight'][whIdx];\n        var plt = ['paddingLeft', 'paddingTop'][whIdx];\n        var prb = ['paddingRight', 'paddingBottom'][whIdx];\n\n        if (opts[wh] != null && opts[wh] !== 'auto') {\n            return parseFloat(opts[wh]);\n        }\n\n        var root = this.root;\n        // IE8 does not support getComputedStyle, but it use VML.\n        var stl = document.defaultView.getComputedStyle(root);\n\n        return (\n            (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh]))\n            - (parseInt10(stl[plt]) || 0)\n            - (parseInt10(stl[prb]) || 0)\n        ) | 0;\n    },\n\n    pathToImage: function (path, dpr) {\n        dpr = dpr || this.dpr;\n\n        var canvas = document.createElement('canvas');\n        var ctx = canvas.getContext('2d');\n        var rect = path.getBoundingRect();\n        var style = path.style;\n        var shadowBlurSize = style.shadowBlur * dpr;\n        var shadowOffsetX = style.shadowOffsetX * dpr;\n        var shadowOffsetY = style.shadowOffsetY * dpr;\n        var lineWidth = style.hasStroke() ? style.lineWidth : 0;\n\n        var leftMargin = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize);\n        var rightMargin = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize);\n        var topMargin = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize);\n        var bottomMargin = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize);\n        var width = rect.width + leftMargin + rightMargin;\n        var height = rect.height + topMargin + bottomMargin;\n\n        canvas.width = width * dpr;\n        canvas.height = height * dpr;\n\n        ctx.scale(dpr, dpr);\n        ctx.clearRect(0, 0, width, height);\n        ctx.dpr = dpr;\n\n        var pathTransform = {\n            position: path.position,\n            rotation: path.rotation,\n            scale: path.scale\n        };\n        path.position = [leftMargin - rect.x, topMargin - rect.y];\n        path.rotation = 0;\n        path.scale = [1, 1];\n        path.updateTransform();\n        if (path) {\n            path.brush(ctx);\n        }\n\n        var ImageShape = ZImage;\n        var imgShape = new ImageShape({\n            style: {\n                x: 0,\n                y: 0,\n                image: canvas\n            }\n        });\n\n        if (pathTransform.position != null) {\n            imgShape.position = path.position = pathTransform.position;\n        }\n\n        if (pathTransform.rotation != null) {\n            imgShape.rotation = path.rotation = pathTransform.rotation;\n        }\n\n        if (pathTransform.scale != null) {\n            imgShape.scale = path.scale = pathTransform.scale;\n        }\n\n        return imgShape;\n    }\n};\n\n/**\n * 动画主类, 调度和管理所有动画控制器\n *\n * @module zrender/animation/Animation\n * @author pissang(https://github.com/pissang)\n */\n// TODO Additive animation\n// http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/\n// https://developer.apple.com/videos/wwdc2014/#236\n\n/**\n * @typedef {Object} IZRenderStage\n * @property {Function} update\n */\n\n/**\n * @alias module:zrender/animation/Animation\n * @constructor\n * @param {Object} [options]\n * @param {Function} [options.onframe]\n * @param {IZRenderStage} [options.stage]\n * @example\n *     var animation = new Animation();\n *     var obj = {\n *         x: 100,\n *         y: 100\n *     };\n *     animation.animate(node.position)\n *         .when(1000, {\n *             x: 500,\n *             y: 500\n *         })\n *         .when(2000, {\n *             x: 100,\n *             y: 100\n *         })\n *         .start('spline');\n */\nvar Animation = function (options) {\n\n    options = options || {};\n\n    this.stage = options.stage || {};\n\n    this.onframe = options.onframe || function () {};\n\n    // private properties\n    this._clips = [];\n\n    this._running = false;\n\n    this._time;\n\n    this._pausedTime;\n\n    this._pauseStart;\n\n    this._paused = false;\n\n    Eventful.call(this);\n};\n\nAnimation.prototype = {\n\n    constructor: Animation,\n    /**\n     * 添加 clip\n     * @param {module:zrender/animation/Clip} clip\n     */\n    addClip: function (clip) {\n        this._clips.push(clip);\n    },\n    /**\n     * 添加 animator\n     * @param {module:zrender/animation/Animator} animator\n     */\n    addAnimator: function (animator) {\n        animator.animation = this;\n        var clips = animator.getClips();\n        for (var i = 0; i < clips.length; i++) {\n            this.addClip(clips[i]);\n        }\n    },\n    /**\n     * 删除动画片段\n     * @param {module:zrender/animation/Clip} clip\n     */\n    removeClip: function (clip) {\n        var idx = indexOf(this._clips, clip);\n        if (idx >= 0) {\n            this._clips.splice(idx, 1);\n        }\n    },\n\n    /**\n     * 删除动画片段\n     * @param {module:zrender/animation/Animator} animator\n     */\n    removeAnimator: function (animator) {\n        var clips = animator.getClips();\n        for (var i = 0; i < clips.length; i++) {\n            this.removeClip(clips[i]);\n        }\n        animator.animation = null;\n    },\n\n    _update: function () {\n        var time = new Date().getTime() - this._pausedTime;\n        var delta = time - this._time;\n        var clips = this._clips;\n        var len = clips.length;\n\n        var deferredEvents = [];\n        var deferredClips = [];\n        for (var i = 0; i < len; i++) {\n            var clip = clips[i];\n            var e = clip.step(time, delta);\n            // Throw out the events need to be called after\n            // stage.update, like destroy\n            if (e) {\n                deferredEvents.push(e);\n                deferredClips.push(clip);\n            }\n        }\n\n        // Remove the finished clip\n        for (var i = 0; i < len;) {\n            if (clips[i]._needsRemove) {\n                clips[i] = clips[len - 1];\n                clips.pop();\n                len--;\n            }\n            else {\n                i++;\n            }\n        }\n\n        len = deferredEvents.length;\n        for (var i = 0; i < len; i++) {\n            deferredClips[i].fire(deferredEvents[i]);\n        }\n\n        this._time = time;\n\n        this.onframe(delta);\n\n        // 'frame' should be triggered before stage, because upper application\n        // depends on the sequence (e.g., echarts-stream and finish\n        // event judge)\n        this.trigger('frame', delta);\n\n        if (this.stage.update) {\n            this.stage.update();\n        }\n    },\n\n    _startLoop: function () {\n        var self = this;\n\n        this._running = true;\n\n        function step() {\n            if (self._running) {\n\n                requestAnimationFrame(step);\n\n                !self._paused && self._update();\n            }\n        }\n\n        requestAnimationFrame(step);\n    },\n\n    /**\n     * Start animation.\n     */\n    start: function () {\n\n        this._time = new Date().getTime();\n        this._pausedTime = 0;\n\n        this._startLoop();\n    },\n\n    /**\n     * Stop animation.\n     */\n    stop: function () {\n        this._running = false;\n    },\n\n    /**\n     * Pause animation.\n     */\n    pause: function () {\n        if (!this._paused) {\n            this._pauseStart = new Date().getTime();\n            this._paused = true;\n        }\n    },\n\n    /**\n     * Resume animation.\n     */\n    resume: function () {\n        if (this._paused) {\n            this._pausedTime += (new Date().getTime()) - this._pauseStart;\n            this._paused = false;\n        }\n    },\n\n    /**\n     * Clear animation.\n     */\n    clear: function () {\n        this._clips = [];\n    },\n\n    /**\n     * Whether animation finished.\n     */\n    isFinished: function () {\n        return !this._clips.length;\n    },\n\n    /**\n     * Creat animator for a target, whose props can be animated.\n     *\n     * @param  {Object} target\n     * @param  {Object} options\n     * @param  {boolean} [options.loop=false] Whether loop animation.\n     * @param  {Function} [options.getter=null] Get value from target.\n     * @param  {Function} [options.setter=null] Set value to target.\n     * @return {module:zrender/animation/Animation~Animator}\n     */\n    // TODO Gap\n    animate: function (target, options) {\n        options = options || {};\n\n        var animator = new Animator(\n            target,\n            options.loop,\n            options.getter,\n            options.setter\n        );\n\n        this.addAnimator(animator);\n\n        return animator;\n    }\n};\n\nmixin(Animation, Eventful);\n\nvar TOUCH_CLICK_DELAY = 300;\n\nvar mouseHandlerNames = [\n    'click', 'dblclick', 'mousewheel', 'mouseout',\n    'mouseup', 'mousedown', 'mousemove', 'contextmenu'\n];\n\nvar touchHandlerNames = [\n    'touchstart', 'touchend', 'touchmove'\n];\n\nvar pointerEventNames = {\n    pointerdown: 1, pointerup: 1, pointermove: 1, pointerout: 1\n};\n\nvar pointerHandlerNames = map(mouseHandlerNames, function (name) {\n    var nm = name.replace('mouse', 'pointer');\n    return pointerEventNames[nm] ? nm : name;\n});\n\nfunction eventNameFix(name) {\n    return (name === 'mousewheel' && env$1.browser.firefox) ? 'DOMMouseScroll' : name;\n}\n\n// function onMSGestureChange(proxy, event) {\n//     if (event.translationX || event.translationY) {\n//         // mousemove is carried by MSGesture to reduce the sensitivity.\n//         proxy.handler.dispatchToElement(event.target, 'mousemove', event);\n//     }\n//     if (event.scale !== 1) {\n//         event.pinchX = event.offsetX;\n//         event.pinchY = event.offsetY;\n//         event.pinchScale = event.scale;\n//         proxy.handler.dispatchToElement(event.target, 'pinch', event);\n//     }\n// }\n\n/**\n * Prevent mouse event from being dispatched after Touch Events action\n * @see <https://github.com/deltakosh/handjs/blob/master/src/hand.base.js>\n * 1. Mobile browsers dispatch mouse events 300ms after touchend.\n * 2. Chrome for Android dispatch mousedown for long-touch about 650ms\n * Result: Blocking Mouse Events for 700ms.\n */\nfunction setTouchTimer(instance) {\n    instance._touching = true;\n    clearTimeout(instance._touchTimer);\n    instance._touchTimer = setTimeout(function () {\n        instance._touching = false;\n    }, 700);\n}\n\n\nvar domHandlers = {\n    /**\n     * Mouse move handler\n     * @inner\n     * @param {Event} event\n     */\n    mousemove: function (event) {\n        event = normalizeEvent(this.dom, event);\n\n        this.trigger('mousemove', event);\n    },\n\n    /**\n     * Mouse out handler\n     * @inner\n     * @param {Event} event\n     */\n    mouseout: function (event) {\n        event = normalizeEvent(this.dom, event);\n\n        var element = event.toElement || event.relatedTarget;\n        if (element !== this.dom) {\n            while (element && element.nodeType !== 9) {\n                // 忽略包含在root中的dom引起的mouseOut\n                if (element === this.dom) {\n                    return;\n                }\n\n                element = element.parentNode;\n            }\n        }\n\n        this.trigger('mouseout', event);\n    },\n\n    /**\n     * Touch开始响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchstart: function (event) {\n        // Default mouse behaviour should not be disabled here.\n        // For example, page may needs to be slided.\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this._lastTouchMoment = new Date();\n\n        this.handler.processGesture(this, event, 'start');\n\n        // In touch device, trigger `mousemove`(`mouseover`) should\n        // be triggered, and must before `mousedown` triggered.\n        domHandlers.mousemove.call(this, event);\n\n        domHandlers.mousedown.call(this, event);\n\n        setTouchTimer(this);\n    },\n\n    /**\n     * Touch移动响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchmove: function (event) {\n\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this.handler.processGesture(this, event, 'change');\n\n        // Mouse move should always be triggered no matter whether\n        // there is gestrue event, because mouse move and pinch may\n        // be used at the same time.\n        domHandlers.mousemove.call(this, event);\n\n        setTouchTimer(this);\n    },\n\n    /**\n     * Touch结束响应函数\n     * @inner\n     * @param {Event} event\n     */\n    touchend: function (event) {\n\n        event = normalizeEvent(this.dom, event);\n\n        // Mark touch, which is useful in distinguish touch and\n        // mouse event in upper applicatoin.\n        event.zrByTouch = true;\n\n        this.handler.processGesture(this, event, 'end');\n\n        domHandlers.mouseup.call(this, event);\n\n        // Do not trigger `mouseout` here, in spite of `mousemove`(`mouseover`) is\n        // triggered in `touchstart`. This seems to be illogical, but by this mechanism,\n        // we can conveniently implement \"hover style\" in both PC and touch device just\n        // by listening to `mouseover` to add \"hover style\" and listening to `mouseout`\n        // to remove \"hover style\" on an element, without any additional code for\n        // compatibility. (`mouseout` will not be triggered in `touchend`, so \"hover\n        // style\" will remain for user view)\n\n        // click event should always be triggered no matter whether\n        // there is gestrue event. System click can not be prevented.\n        if (+new Date() - this._lastTouchMoment < TOUCH_CLICK_DELAY) {\n            domHandlers.click.call(this, event);\n        }\n\n        setTouchTimer(this);\n    },\n\n    pointerdown: function (event) {\n        domHandlers.mousedown.call(this, event);\n\n        // if (useMSGuesture(this, event)) {\n        //     this._msGesture.addPointer(event.pointerId);\n        // }\n    },\n\n    pointermove: function (event) {\n        // FIXME\n        // pointermove is so sensitive that it always triggered when\n        // tap(click) on touch screen, which affect some judgement in\n        // upper application. So, we dont support mousemove on MS touch\n        // device yet.\n        if (!isPointerFromTouch(event)) {\n            domHandlers.mousemove.call(this, event);\n        }\n    },\n\n    pointerup: function (event) {\n        domHandlers.mouseup.call(this, event);\n    },\n\n    pointerout: function (event) {\n        // pointerout will be triggered when tap on touch screen\n        // (IE11+/Edge on MS Surface) after click event triggered,\n        // which is inconsistent with the mousout behavior we defined\n        // in touchend. So we unify them.\n        // (check domHandlers.touchend for detailed explanation)\n        if (!isPointerFromTouch(event)) {\n            domHandlers.mouseout.call(this, event);\n        }\n    }\n};\n\nfunction isPointerFromTouch(event) {\n    var pointerType = event.pointerType;\n    return pointerType === 'pen' || pointerType === 'touch';\n}\n\n// function useMSGuesture(handlerProxy, event) {\n//     return isPointerFromTouch(event) && !!handlerProxy._msGesture;\n// }\n\n// Common handlers\neach$1(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {\n    domHandlers[name] = function (event) {\n        event = normalizeEvent(this.dom, event);\n        this.trigger(name, event);\n    };\n});\n\n/**\n * 为控制类实例初始化dom 事件处理函数\n *\n * @inner\n * @param {module:zrender/Handler} instance 控制类实例\n */\nfunction initDomHandler(instance) {\n    each$1(touchHandlerNames, function (name) {\n        instance._handlers[name] = bind(domHandlers[name], instance);\n    });\n\n    each$1(pointerHandlerNames, function (name) {\n        instance._handlers[name] = bind(domHandlers[name], instance);\n    });\n\n    each$1(mouseHandlerNames, function (name) {\n        instance._handlers[name] = makeMouseHandler(domHandlers[name], instance);\n    });\n\n    function makeMouseHandler(fn, instance) {\n        return function () {\n            if (instance._touching) {\n                return;\n            }\n            return fn.apply(instance, arguments);\n        };\n    }\n}\n\n\nfunction HandlerDomProxy(dom) {\n    Eventful.call(this);\n\n    this.dom = dom;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._touching = false;\n\n    /**\n     * @private\n     * @type {number}\n     */\n    this._touchTimer;\n\n    this._handlers = {};\n\n    initDomHandler(this);\n\n    if (env$1.pointerEventsSupported) { // Only IE11+/Edge\n        // 1. On devices that both enable touch and mouse (e.g., MS Surface and lenovo X240),\n        // IE11+/Edge do not trigger touch event, but trigger pointer event and mouse event\n        // at the same time.\n        // 2. On MS Surface, it probablely only trigger mousedown but no mouseup when tap on\n        // screen, which do not occurs in pointer event.\n        // So we use pointer event to both detect touch gesture and mouse behavior.\n        mountHandlers(pointerHandlerNames, this);\n\n        // FIXME\n        // Note: MS Gesture require CSS touch-action set. But touch-action is not reliable,\n        // which does not prevent defuault behavior occasionally (which may cause view port\n        // zoomed in but use can not zoom it back). And event.preventDefault() does not work.\n        // So we have to not to use MSGesture and not to support touchmove and pinch on MS\n        // touch screen. And we only support click behavior on MS touch screen now.\n\n        // MS Gesture Event is only supported on IE11+/Edge and on Windows 8+.\n        // We dont support touch on IE on win7.\n        // See <https://msdn.microsoft.com/en-us/library/dn433243(v=vs.85).aspx>\n        // if (typeof MSGesture === 'function') {\n        //     (this._msGesture = new MSGesture()).target = dom; // jshint ignore:line\n        //     dom.addEventListener('MSGestureChange', onMSGestureChange);\n        // }\n    }\n    else {\n        if (env$1.touchEventsSupported) {\n            mountHandlers(touchHandlerNames, this);\n            // Handler of 'mouseout' event is needed in touch mode, which will be mounted below.\n            // addEventListener(root, 'mouseout', this._mouseoutHandler);\n        }\n\n        // 1. Considering some devices that both enable touch and mouse event (like on MS Surface\n        // and lenovo X240, @see #2350), we make mouse event be always listened, otherwise\n        // mouse event can not be handle in those devices.\n        // 2. On MS Surface, Chrome will trigger both touch event and mouse event. How to prevent\n        // mouseevent after touch event triggered, see `setTouchTimer`.\n        mountHandlers(mouseHandlerNames, this);\n    }\n\n    function mountHandlers(handlerNames, instance) {\n        each$1(handlerNames, function (name) {\n            addEventListener(dom, eventNameFix(name), instance._handlers[name]);\n        }, instance);\n    }\n}\n\nvar handlerDomProxyProto = HandlerDomProxy.prototype;\nhandlerDomProxyProto.dispose = function () {\n    var handlerNames = mouseHandlerNames.concat(touchHandlerNames);\n\n    for (var i = 0; i < handlerNames.length; i++) {\n        var name = handlerNames[i];\n        removeEventListener(this.dom, eventNameFix(name), this._handlers[name]);\n    }\n};\n\nhandlerDomProxyProto.setCursor = function (cursorStyle) {\n    this.dom.style && (this.dom.style.cursor = cursorStyle || 'default');\n};\n\nmixin(HandlerDomProxy, Eventful);\n\n/*!\n* ZRender, a high performance 2d drawing library.\n*\n* Copyright (c) 2013, Baidu Inc.\n* All rights reserved.\n*\n* LICENSE\n* https://github.com/ecomfe/zrender/blob/master/LICENSE.txt\n*/\n\nvar useVML = !env$1.canvasSupported;\n\nvar painterCtors = {\n    canvas: Painter\n};\n\n/**\n * @type {string}\n */\nvar version$1 = '4.0.7';\n\n/**\n * Initializing a zrender instance\n * @param {HTMLElement} dom\n * @param {Object} [opts]\n * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'\n * @param {number} [opts.devicePixelRatio]\n * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)\n * @return {module:zrender/ZRender}\n */\nfunction init$1(dom, opts) {\n    var zr = new ZRender(guid(), dom, opts);\n    return zr;\n}\n\n/**\n * Dispose zrender instance\n * @param {module:zrender/ZRender} zr\n */\n\n\n/**\n * Get zrender instance by id\n * @param {string} id zrender instance id\n * @return {module:zrender/ZRender}\n */\n\n\n\n\n/**\n * @module zrender/ZRender\n */\n/**\n * @constructor\n * @alias module:zrender/ZRender\n * @param {string} id\n * @param {HTMLElement} dom\n * @param {Object} opts\n * @param {string} [opts.renderer='canvas'] 'canvas' or 'svg'\n * @param {number} [opts.devicePixelRatio]\n * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)\n */\nvar ZRender = function (id, dom, opts) {\n\n    opts = opts || {};\n\n    /**\n     * @type {HTMLDomElement}\n     */\n    this.dom = dom;\n\n    /**\n     * @type {string}\n     */\n    this.id = id;\n\n    var self = this;\n    var storage = new Storage();\n\n    var rendererType = opts.renderer;\n    // TODO WebGL\n    if (useVML) {\n        if (!painterCtors.vml) {\n            throw new Error('You need to require \\'zrender/vml/vml\\' to support IE8');\n        }\n        rendererType = 'vml';\n    }\n    else if (!rendererType || !painterCtors[rendererType]) {\n        rendererType = 'canvas';\n    }\n    var painter = new painterCtors[rendererType](dom, storage, opts, id);\n\n    this.storage = storage;\n    this.painter = painter;\n\n    var handerProxy = (!env$1.node && !env$1.worker) ? new HandlerDomProxy(painter.getViewportRoot()) : null;\n    this.handler = new Handler(storage, painter, handerProxy, painter.root);\n\n    /**\n     * @type {module:zrender/animation/Animation}\n     */\n    this.animation = new Animation({\n        stage: {\n            update: bind(this.flush, this)\n        }\n    });\n    this.animation.start();\n\n    /**\n     * @type {boolean}\n     * @private\n     */\n    this._needsRefresh;\n\n    // 修改 storage.delFromStorage, 每次删除元素之前删除动画\n    // FIXME 有点ugly\n    var oldDelFromStorage = storage.delFromStorage;\n    var oldAddToStorage = storage.addToStorage;\n\n    storage.delFromStorage = function (el) {\n        oldDelFromStorage.call(storage, el);\n\n        el && el.removeSelfFromZr(self);\n    };\n\n    storage.addToStorage = function (el) {\n        oldAddToStorage.call(storage, el);\n\n        el.addSelfToZr(self);\n    };\n};\n\nZRender.prototype = {\n\n    constructor: ZRender,\n    /**\n     * 获取实例唯一标识\n     * @return {string}\n     */\n    getId: function () {\n        return this.id;\n    },\n\n    /**\n     * 添加元素\n     * @param  {module:zrender/Element} el\n     */\n    add: function (el) {\n        this.storage.addRoot(el);\n        this._needsRefresh = true;\n    },\n\n    /**\n     * 删除元素\n     * @param  {module:zrender/Element} el\n     */\n    remove: function (el) {\n        this.storage.delRoot(el);\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Change configuration of layer\n     * @param {string} zLevel\n     * @param {Object} config\n     * @param {string} [config.clearColor=0] Clear color\n     * @param {string} [config.motionBlur=false] If enable motion blur\n     * @param {number} [config.lastFrameAlpha=0.7] Motion blur factor. Larger value cause longer trailer\n    */\n    configLayer: function (zLevel, config) {\n        if (this.painter.configLayer) {\n            this.painter.configLayer(zLevel, config);\n        }\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Set background color\n     * @param {string} backgroundColor\n     */\n    setBackgroundColor: function (backgroundColor) {\n        if (this.painter.setBackgroundColor) {\n            this.painter.setBackgroundColor(backgroundColor);\n        }\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Repaint the canvas immediately\n     */\n    refreshImmediately: function () {\n        // var start = new Date();\n        // Clear needsRefresh ahead to avoid something wrong happens in refresh\n        // Or it will cause zrender refreshes again and again.\n        this._needsRefresh = false;\n        this.painter.refresh();\n        /**\n         * Avoid trigger zr.refresh in Element#beforeUpdate hook\n         */\n        this._needsRefresh = false;\n        // var end = new Date();\n        // var log = document.getElementById('log');\n        // if (log) {\n        //     log.innerHTML = log.innerHTML + '<br>' + (end - start);\n        // }\n    },\n\n    /**\n     * Mark and repaint the canvas in the next frame of browser\n     */\n    refresh: function () {\n        this._needsRefresh = true;\n    },\n\n    /**\n     * Perform all refresh\n     */\n    flush: function () {\n        var triggerRendered;\n\n        if (this._needsRefresh) {\n            triggerRendered = true;\n            this.refreshImmediately();\n        }\n        if (this._needsRefreshHover) {\n            triggerRendered = true;\n            this.refreshHoverImmediately();\n        }\n\n        triggerRendered && this.trigger('rendered');\n    },\n\n    /**\n     * Add element to hover layer\n     * @param  {module:zrender/Element} el\n     * @param {Object} style\n     */\n    addHover: function (el, style) {\n        if (this.painter.addHover) {\n            var elMirror = this.painter.addHover(el, style);\n            this.refreshHover();\n            return elMirror;\n        }\n    },\n\n    /**\n     * Add element from hover layer\n     * @param  {module:zrender/Element} el\n     */\n    removeHover: function (el) {\n        if (this.painter.removeHover) {\n            this.painter.removeHover(el);\n            this.refreshHover();\n        }\n    },\n\n    /**\n     * Clear all hover elements in hover layer\n     * @param  {module:zrender/Element} el\n     */\n    clearHover: function () {\n        if (this.painter.clearHover) {\n            this.painter.clearHover();\n            this.refreshHover();\n        }\n    },\n\n    /**\n     * Refresh hover in next frame\n     */\n    refreshHover: function () {\n        this._needsRefreshHover = true;\n    },\n\n    /**\n     * Refresh hover immediately\n     */\n    refreshHoverImmediately: function () {\n        this._needsRefreshHover = false;\n        this.painter.refreshHover && this.painter.refreshHover();\n    },\n\n    /**\n     * Resize the canvas.\n     * Should be invoked when container size is changed\n     * @param {Object} [opts]\n     * @param {number|string} [opts.width] Can be 'auto' (the same as null/undefined)\n     * @param {number|string} [opts.height] Can be 'auto' (the same as null/undefined)\n     */\n    resize: function (opts) {\n        opts = opts || {};\n        this.painter.resize(opts.width, opts.height);\n        this.handler.resize();\n    },\n\n    /**\n     * Stop and clear all animation immediately\n     */\n    clearAnimation: function () {\n        this.animation.clear();\n    },\n\n    /**\n     * Get container width\n     */\n    getWidth: function () {\n        return this.painter.getWidth();\n    },\n\n    /**\n     * Get container height\n     */\n    getHeight: function () {\n        return this.painter.getHeight();\n    },\n\n    /**\n     * Export the canvas as Base64 URL\n     * @param {string} type\n     * @param {string} [backgroundColor='#fff']\n     * @return {string} Base64 URL\n     */\n    // toDataURL: function(type, backgroundColor) {\n    //     return this.painter.getRenderedCanvas({\n    //         backgroundColor: backgroundColor\n    //     }).toDataURL(type);\n    // },\n\n    /**\n     * Converting a path to image.\n     * It has much better performance of drawing image rather than drawing a vector path.\n     * @param {module:zrender/graphic/Path} e\n     * @param {number} width\n     * @param {number} height\n     */\n    pathToImage: function (e, dpr) {\n        return this.painter.pathToImage(e, dpr);\n    },\n\n    /**\n     * Set default cursor\n     * @param {string} [cursorStyle='default'] 例如 crosshair\n     */\n    setCursorStyle: function (cursorStyle) {\n        this.handler.setCursorStyle(cursorStyle);\n    },\n\n    /**\n     * Find hovered element\n     * @param {number} x\n     * @param {number} y\n     * @return {Object} {target, topTarget}\n     */\n    findHover: function (x, y) {\n        return this.handler.findHover(x, y);\n    },\n\n    /**\n     * Bind event\n     *\n     * @param {string} eventName Event name\n     * @param {Function} eventHandler Handler function\n     * @param {Object} [context] Context object\n     */\n    on: function (eventName, eventHandler, context) {\n        this.handler.on(eventName, eventHandler, context);\n    },\n\n    /**\n     * Unbind event\n     * @param {string} eventName Event name\n     * @param {Function} [eventHandler] Handler function\n     */\n    off: function (eventName, eventHandler) {\n        this.handler.off(eventName, eventHandler);\n    },\n\n    /**\n     * Trigger event manually\n     *\n     * @param {string} eventName Event name\n     * @param {event=} event Event object\n     */\n    trigger: function (eventName, event) {\n        this.handler.trigger(eventName, event);\n    },\n\n\n    /**\n     * Clear all objects and the canvas.\n     */\n    clear: function () {\n        this.storage.delRoot();\n        this.painter.clear();\n    },\n\n    /**\n     * Dispose self.\n     */\n    dispose: function () {\n        this.animation.stop();\n\n        this.clear();\n        this.storage.dispose();\n        this.painter.dispose();\n        this.handler.dispose();\n\n        this.animation =\n        this.storage =\n        this.painter =\n        this.handler = null;\n\n        \n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$2 = each$1;\nvar isObject$2 = isObject$1;\nvar isArray$1 = isArray;\n\n/**\n * Make the name displayable. But we should\n * make sure it is not duplicated with user\n * specified name, so use '\\0';\n */\nvar DUMMY_COMPONENT_NAME_PREFIX = 'series\\0';\n\n/**\n * If value is not array, then translate it to array.\n * @param  {*} value\n * @return {Array} [value] or value\n */\nfunction normalizeToArray(value) {\n    return value instanceof Array\n        ? value\n        : value == null\n        ? []\n        : [value];\n}\n\n/**\n * Sync default option between normal and emphasis like `position` and `show`\n * In case some one will write code like\n *     label: {\n *          show: false,\n *          position: 'outside',\n *          fontSize: 18\n *     },\n *     emphasis: {\n *          label: { show: true }\n *     }\n * @param {Object} opt\n * @param {string} key\n * @param {Array.<string>} subOpts\n */\nfunction defaultEmphasis(opt, key, subOpts) {\n    // Caution: performance sensitive.\n    if (opt) {\n        opt[key] = opt[key] || {};\n        opt.emphasis = opt.emphasis || {};\n        opt.emphasis[key] = opt.emphasis[key] || {};\n\n        // Default emphasis option from normal\n        for (var i = 0, len = subOpts.length; i < len; i++) {\n            var subOptName = subOpts[i];\n            if (!opt.emphasis[key].hasOwnProperty(subOptName)\n                && opt[key].hasOwnProperty(subOptName)\n            ) {\n                opt.emphasis[key][subOptName] = opt[key][subOptName];\n            }\n        }\n    }\n}\n\nvar TEXT_STYLE_OPTIONS = [\n    'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',\n    'rich', 'tag', 'color', 'textBorderColor', 'textBorderWidth',\n    'width', 'height', 'lineHeight', 'align', 'verticalAlign', 'baseline',\n    'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY',\n    'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY',\n    'backgroundColor', 'borderColor', 'borderWidth', 'borderRadius', 'padding'\n];\n\n// modelUtil.LABEL_OPTIONS = modelUtil.TEXT_STYLE_OPTIONS.concat([\n//     'position', 'offset', 'rotate', 'origin', 'show', 'distance', 'formatter',\n//     'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',\n//     // FIXME: deprecated, check and remove it.\n//     'textStyle'\n// ]);\n\n/**\n * The method do not ensure performance.\n * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]\n * This helper method retieves value from data.\n * @param {string|number|Date|Array|Object} dataItem\n * @return {number|string|Date|Array.<number|string|Date>}\n */\nfunction getDataItemValue(dataItem) {\n    return (isObject$2(dataItem) && !isArray$1(dataItem) && !(dataItem instanceof Date))\n        ? dataItem.value : dataItem;\n}\n\n/**\n * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]\n * This helper method determine if dataItem has extra option besides value\n * @param {string|number|Date|Array|Object} dataItem\n */\nfunction isDataItemOption(dataItem) {\n    return isObject$2(dataItem)\n        && !(dataItem instanceof Array);\n        // // markLine data can be array\n        // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array));\n}\n\n/**\n * Mapping to exists for merge.\n *\n * @public\n * @param {Array.<Object>|Array.<module:echarts/model/Component>} exists\n * @param {Object|Array.<Object>} newCptOptions\n * @return {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],\n *                          index of which is the same as exists.\n */\nfunction mappingToExists(exists, newCptOptions) {\n    // Mapping by the order by original option (but not order of\n    // new option) in merge mode. Because we should ensure\n    // some specified index (like xAxisIndex) is consistent with\n    // original option, which is easy to understand, espatially in\n    // media query. And in most case, merge option is used to\n    // update partial option but not be expected to change order.\n    newCptOptions = (newCptOptions || []).slice();\n\n    var result = map(exists || [], function (obj, index) {\n        return {exist: obj};\n    });\n\n    // Mapping by id or name if specified.\n    each$2(newCptOptions, function (cptOption, index) {\n        if (!isObject$2(cptOption)) {\n            return;\n        }\n\n        // id has highest priority.\n        for (var i = 0; i < result.length; i++) {\n            if (!result[i].option // Consider name: two map to one.\n                && cptOption.id != null\n                && result[i].exist.id === cptOption.id + ''\n            ) {\n                result[i].option = cptOption;\n                newCptOptions[index] = null;\n                return;\n            }\n        }\n\n        for (var i = 0; i < result.length; i++) {\n            var exist = result[i].exist;\n            if (!result[i].option // Consider name: two map to one.\n                // Can not match when both ids exist but different.\n                && (exist.id == null || cptOption.id == null)\n                && cptOption.name != null\n                && !isIdInner(cptOption)\n                && !isIdInner(exist)\n                && exist.name === cptOption.name + ''\n            ) {\n                result[i].option = cptOption;\n                newCptOptions[index] = null;\n                return;\n            }\n        }\n    });\n\n    // Otherwise mapping by index.\n    each$2(newCptOptions, function (cptOption, index) {\n        if (!isObject$2(cptOption)) {\n            return;\n        }\n\n        var i = 0;\n        for (; i < result.length; i++) {\n            var exist = result[i].exist;\n            if (!result[i].option\n                // Existing model that already has id should be able to\n                // mapped to (because after mapping performed model may\n                // be assigned with a id, whish should not affect next\n                // mapping), except those has inner id.\n                && !isIdInner(exist)\n                // Caution:\n                // Do not overwrite id. But name can be overwritten,\n                // because axis use name as 'show label text'.\n                // 'exist' always has id and name and we dont\n                // need to check it.\n                && cptOption.id == null\n            ) {\n                result[i].option = cptOption;\n                break;\n            }\n        }\n\n        if (i >= result.length) {\n            result.push({option: cptOption});\n        }\n    });\n\n    return result;\n}\n\n/**\n * Make id and name for mapping result (result of mappingToExists)\n * into `keyInfo` field.\n *\n * @public\n * @param {Array.<Object>} Result, like [{exist: ..., option: ...}, {}],\n *                          which order is the same as exists.\n * @return {Array.<Object>} The input.\n */\nfunction makeIdAndName(mapResult) {\n    // We use this id to hash component models and view instances\n    // in echarts. id can be specified by user, or auto generated.\n\n    // The id generation rule ensures new view instance are able\n    // to mapped to old instance when setOption are called in\n    // no-merge mode. So we generate model id by name and plus\n    // type in view id.\n\n    // name can be duplicated among components, which is convenient\n    // to specify multi components (like series) by one name.\n\n    // Ensure that each id is distinct.\n    var idMap = createHashMap();\n\n    each$2(mapResult, function (item, index) {\n        var existCpt = item.exist;\n        existCpt && idMap.set(existCpt.id, item);\n    });\n\n    each$2(mapResult, function (item, index) {\n        var opt = item.option;\n\n        assert$1(\n            !opt || opt.id == null || !idMap.get(opt.id) || idMap.get(opt.id) === item,\n            'id duplicates: ' + (opt && opt.id)\n        );\n\n        opt && opt.id != null && idMap.set(opt.id, item);\n        !item.keyInfo && (item.keyInfo = {});\n    });\n\n    // Make name and id.\n    each$2(mapResult, function (item, index) {\n        var existCpt = item.exist;\n        var opt = item.option;\n        var keyInfo = item.keyInfo;\n\n        if (!isObject$2(opt)) {\n            return;\n        }\n\n        // name can be overwitten. Consider case: axis.name = '20km'.\n        // But id generated by name will not be changed, which affect\n        // only in that case: setOption with 'not merge mode' and view\n        // instance will be recreated, which can be accepted.\n        keyInfo.name = opt.name != null\n            ? opt.name + ''\n            : existCpt\n            ? existCpt.name\n            // Avoid diffferent series has the same name,\n            // because name may be used like in color pallet.\n            : DUMMY_COMPONENT_NAME_PREFIX + index;\n\n        if (existCpt) {\n            keyInfo.id = existCpt.id;\n        }\n        else if (opt.id != null) {\n            keyInfo.id = opt.id + '';\n        }\n        else {\n            // Consider this situatoin:\n            //  optionA: [{name: 'a'}, {name: 'a'}, {..}]\n            //  optionB [{..}, {name: 'a'}, {name: 'a'}]\n            // Series with the same name between optionA and optionB\n            // should be mapped.\n            var idNum = 0;\n            do {\n                keyInfo.id = '\\0' + keyInfo.name + '\\0' + idNum++;\n            }\n            while (idMap.get(keyInfo.id));\n        }\n\n        idMap.set(keyInfo.id, item);\n    });\n}\n\nfunction isNameSpecified(componentModel) {\n    var name = componentModel.name;\n    // Is specified when `indexOf` get -1 or > 0.\n    return !!(name && name.indexOf(DUMMY_COMPONENT_NAME_PREFIX));\n}\n\n/**\n * @public\n * @param {Object} cptOption\n * @return {boolean}\n */\nfunction isIdInner(cptOption) {\n    return isObject$2(cptOption)\n        && cptOption.id\n        && (cptOption.id + '').indexOf('\\0_ec_\\0') === 0;\n}\n\n/**\n * A helper for removing duplicate items between batchA and batchB,\n * and in themselves, and categorize by series.\n *\n * @param {Array.<Object>} batchA Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]\n * @param {Array.<Object>} batchB Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]\n * @return {Array.<Array.<Object>, Array.<Object>>} result: [resultBatchA, resultBatchB]\n */\n\n\n/**\n * @param {module:echarts/data/List} data\n * @param {Object} payload Contains dataIndex (means rawIndex) / dataIndexInside / name\n *                         each of which can be Array or primary type.\n * @return {number|Array.<number>} dataIndex If not found, return undefined/null.\n */\nfunction queryDataIndex(data, payload) {\n    if (payload.dataIndexInside != null) {\n        return payload.dataIndexInside;\n    }\n    else if (payload.dataIndex != null) {\n        return isArray(payload.dataIndex)\n            ? map(payload.dataIndex, function (value) {\n                return data.indexOfRawIndex(value);\n            })\n            : data.indexOfRawIndex(payload.dataIndex);\n    }\n    else if (payload.name != null) {\n        return isArray(payload.name)\n            ? map(payload.name, function (value) {\n                return data.indexOfName(value);\n            })\n            : data.indexOfName(payload.name);\n    }\n}\n\n/**\n * Enable property storage to any host object.\n * Notice: Serialization is not supported.\n *\n * For example:\n * var inner = zrUitl.makeInner();\n *\n * function some1(hostObj) {\n *      inner(hostObj).someProperty = 1212;\n *      ...\n * }\n * function some2() {\n *      var fields = inner(this);\n *      fields.someProperty1 = 1212;\n *      fields.someProperty2 = 'xx';\n *      ...\n * }\n *\n * @return {Function}\n */\nfunction makeInner() {\n    // Consider different scope by es module import.\n    var key = '__\\0ec_inner_' + innerUniqueIndex++ + '_' + Math.random().toFixed(5);\n    return function (hostObj) {\n        return hostObj[key] || (hostObj[key] = {});\n    };\n}\nvar innerUniqueIndex = 0;\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex, seriesId, seriesName,\n *            geoIndex, geoId, geoName,\n *            bmapIndex, bmapId, bmapName,\n *            xAxisIndex, xAxisId, xAxisName,\n *            yAxisIndex, yAxisId, yAxisName,\n *            gridIndex, gridId, gridName,\n *            ... (can be extended)\n *        }\n *        Each properties can be number|string|Array.<number>|Array.<string>\n *        For example, a finder could be\n *        {\n *            seriesIndex: 3,\n *            geoId: ['aa', 'cc'],\n *            gridName: ['xx', 'rr']\n *        }\n *        xxxIndex can be set as 'all' (means all xxx) or 'none' (means not specify)\n *        If nothing or null/undefined specified, return nothing.\n * @param {Object} [opt]\n * @param {string} [opt.defaultMainType]\n * @param {Array.<string>} [opt.includeMainTypes]\n * @return {Object} result like:\n *        {\n *            seriesModels: [seriesModel1, seriesModel2],\n *            seriesModel: seriesModel1, // The first model\n *            geoModels: [geoModel1, geoModel2],\n *            geoModel: geoModel1, // The first model\n *            ...\n *        }\n */\nfunction parseFinder(ecModel, finder, opt) {\n    if (isString(finder)) {\n        var obj = {};\n        obj[finder + 'Index'] = 0;\n        finder = obj;\n    }\n\n    var defaultMainType = opt && opt.defaultMainType;\n    if (defaultMainType\n        && !has(finder, defaultMainType + 'Index')\n        && !has(finder, defaultMainType + 'Id')\n        && !has(finder, defaultMainType + 'Name')\n    ) {\n        finder[defaultMainType + 'Index'] = 0;\n    }\n\n    var result = {};\n\n    each$2(finder, function (value, key) {\n        var value = finder[key];\n\n        // Exclude 'dataIndex' and other illgal keys.\n        if (key === 'dataIndex' || key === 'dataIndexInside') {\n            result[key] = value;\n            return;\n        }\n\n        var parsedKey = key.match(/^(\\w+)(Index|Id|Name)$/) || [];\n        var mainType = parsedKey[1];\n        var queryType = (parsedKey[2] || '').toLowerCase();\n\n        if (!mainType\n            || !queryType\n            || value == null\n            || (queryType === 'index' && value === 'none')\n            || (opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0)\n        ) {\n            return;\n        }\n\n        var queryParam = {mainType: mainType};\n        if (queryType !== 'index' || value !== 'all') {\n            queryParam[queryType] = value;\n        }\n\n        var models = ecModel.queryComponents(queryParam);\n        result[mainType + 'Models'] = models;\n        result[mainType + 'Model'] = models[0];\n    });\n\n    return result;\n}\n\nfunction has(obj, prop) {\n    return obj && obj.hasOwnProperty(prop);\n}\n\nfunction setAttribute(dom, key, value) {\n    dom.setAttribute\n        ? dom.setAttribute(key, value)\n        : (dom[key] = value);\n}\n\nfunction getAttribute(dom, key) {\n    return dom.getAttribute\n        ? dom.getAttribute(key)\n        : dom[key];\n}\n\nfunction getTooltipRenderMode(renderModeOption) {\n    if (renderModeOption === 'auto') {\n        // Using html when `document` exists, use richText otherwise\n        return env$1.domSupported ? 'html' : 'richText';\n    }\n    else {\n        return renderModeOption || 'html';\n    }\n}\n\n/**\n * Group a list by key.\n *\n * @param {Array} array\n * @param {Function} getKey\n *        param {*} Array item\n *        return {string} key\n * @return {Object} Result\n *        {Array}: keys,\n *        {module:zrender/core/util/HashMap} buckets: {key -> Array}\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar TYPE_DELIMITER = '.';\nvar IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';\n\n/**\n * Notice, parseClassType('') should returns {main: '', sub: ''}\n * @public\n */\nfunction parseClassType$1(componentType) {\n    var ret = {main: '', sub: ''};\n    if (componentType) {\n        componentType = componentType.split(TYPE_DELIMITER);\n        ret.main = componentType[0] || '';\n        ret.sub = componentType[1] || '';\n    }\n    return ret;\n}\n\n/**\n * @public\n */\nfunction checkClassType(componentType) {\n    assert$1(\n        /^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType),\n        'componentType \"' + componentType + '\" illegal'\n    );\n}\n\n/**\n * @public\n */\nfunction enableClassExtend(RootClass, mandatoryMethods) {\n\n    RootClass.$constructor = RootClass;\n    RootClass.extend = function (proto) {\n\n        if (__DEV__) {\n            each$1(mandatoryMethods, function (method) {\n                if (!proto[method]) {\n                    console.warn(\n                        'Method `' + method + '` should be implemented'\n                        + (proto.type ? ' in ' + proto.type : '') + '.'\n                    );\n                }\n            });\n        }\n\n        var superClass = this;\n        var ExtendedClass = function () {\n            if (!proto.$constructor) {\n                superClass.apply(this, arguments);\n            }\n            else {\n                proto.$constructor.apply(this, arguments);\n            }\n        };\n\n        extend(ExtendedClass.prototype, proto);\n\n        ExtendedClass.extend = this.extend;\n        ExtendedClass.superCall = superCall;\n        ExtendedClass.superApply = superApply;\n        inherits(ExtendedClass, this);\n        ExtendedClass.superClass = superClass;\n\n        return ExtendedClass;\n    };\n}\n\nvar classBase = 0;\n\n/**\n * Can not use instanceof, consider different scope by\n * cross domain or es module import in ec extensions.\n * Mount a method \"isInstance()\" to Clz.\n */\nfunction enableClassCheck(Clz) {\n    var classAttr = ['__\\0is_clz', classBase++, Math.random().toFixed(3)].join('_');\n    Clz.prototype[classAttr] = true;\n\n    if (__DEV__) {\n        assert$1(!Clz.isInstance, 'The method \"is\" can not be defined.');\n    }\n\n    Clz.isInstance = function (obj) {\n        return !!(obj && obj[classAttr]);\n    };\n}\n\n// superCall should have class info, which can not be fetch from 'this'.\n// Consider this case:\n// class A has method f,\n// class B inherits class A, overrides method f, f call superApply('f'),\n// class C inherits class B, do not overrides method f,\n// then when method of class C is called, dead loop occured.\nfunction superCall(context, methodName) {\n    var args = slice(arguments, 2);\n    return this.superClass.prototype[methodName].apply(context, args);\n}\n\nfunction superApply(context, methodName, args) {\n    return this.superClass.prototype[methodName].apply(context, args);\n}\n\n/**\n * @param {Object} entity\n * @param {Object} options\n * @param {boolean} [options.registerWhenExtend]\n * @public\n */\nfunction enableClassManagement(entity, options) {\n    options = options || {};\n\n    /**\n     * Component model classes\n     * key: componentType,\n     * value:\n     *     componentClass, when componentType is 'xxx'\n     *     or Object.<subKey, componentClass>, when componentType is 'xxx.yy'\n     * @type {Object}\n     */\n    var storage = {};\n\n    entity.registerClass = function (Clazz, componentType) {\n        if (componentType) {\n            checkClassType(componentType);\n            componentType = parseClassType$1(componentType);\n\n            if (!componentType.sub) {\n                if (__DEV__) {\n                    if (storage[componentType.main]) {\n                        console.warn(componentType.main + ' exists.');\n                    }\n                }\n                storage[componentType.main] = Clazz;\n            }\n            else if (componentType.sub !== IS_CONTAINER) {\n                var container = makeContainer(componentType);\n                container[componentType.sub] = Clazz;\n            }\n        }\n        return Clazz;\n    };\n\n    entity.getClass = function (componentMainType, subType, throwWhenNotFound) {\n        var Clazz = storage[componentMainType];\n\n        if (Clazz && Clazz[IS_CONTAINER]) {\n            Clazz = subType ? Clazz[subType] : null;\n        }\n\n        if (throwWhenNotFound && !Clazz) {\n            throw new Error(\n                !subType\n                    ? componentMainType + '.' + 'type should be specified.'\n                    : 'Component ' + componentMainType + '.' + (subType || '') + ' not exists. Load it first.'\n            );\n        }\n\n        return Clazz;\n    };\n\n    entity.getClassesByMainType = function (componentType) {\n        componentType = parseClassType$1(componentType);\n\n        var result = [];\n        var obj = storage[componentType.main];\n\n        if (obj && obj[IS_CONTAINER]) {\n            each$1(obj, function (o, type) {\n                type !== IS_CONTAINER && result.push(o);\n            });\n        }\n        else {\n            result.push(obj);\n        }\n\n        return result;\n    };\n\n    entity.hasClass = function (componentType) {\n        // Just consider componentType.main.\n        componentType = parseClassType$1(componentType);\n        return !!storage[componentType.main];\n    };\n\n    /**\n     * @return {Array.<string>} Like ['aa', 'bb'], but can not be ['aa.xx']\n     */\n    entity.getAllClassMainTypes = function () {\n        var types = [];\n        each$1(storage, function (obj, type) {\n            types.push(type);\n        });\n        return types;\n    };\n\n    /**\n     * If a main type is container and has sub types\n     * @param  {string}  mainType\n     * @return {boolean}\n     */\n    entity.hasSubTypes = function (componentType) {\n        componentType = parseClassType$1(componentType);\n        var obj = storage[componentType.main];\n        return obj && obj[IS_CONTAINER];\n    };\n\n    entity.parseClassType = parseClassType$1;\n\n    function makeContainer(componentType) {\n        var container = storage[componentType.main];\n        if (!container || !container[IS_CONTAINER]) {\n            container = storage[componentType.main] = {};\n            container[IS_CONTAINER] = true;\n        }\n        return container;\n    }\n\n    if (options.registerWhenExtend) {\n        var originalExtend = entity.extend;\n        if (originalExtend) {\n            entity.extend = function (proto) {\n                var ExtendedClass = originalExtend.call(this, proto);\n                return entity.registerClass(ExtendedClass, proto.type);\n            };\n        }\n    }\n\n    return entity;\n}\n\n/**\n * @param {string|Array.<string>} properties\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO Parse shadow style\n// TODO Only shallow path support\nvar makeStyleMapper = function (properties) {\n    // Normalize\n    for (var i = 0; i < properties.length; i++) {\n        if (!properties[i][1]) {\n            properties[i][1] = properties[i][0];\n        }\n    }\n    return function (model, excludes, includes) {\n        var style = {};\n        for (var i = 0; i < properties.length; i++) {\n            var propName = properties[i][1];\n            if ((excludes && indexOf(excludes, propName) >= 0)\n                || (includes && indexOf(includes, propName) < 0)\n            ) {\n                continue;\n            }\n            var val = model.getShallow(propName);\n            if (val != null) {\n                style[properties[i][0]] = val;\n            }\n        }\n        return style;\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getLineStyle = makeStyleMapper(\n    [\n        ['lineWidth', 'width'],\n        ['stroke', 'color'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor']\n    ]\n);\n\nvar lineStyleMixin = {\n    getLineStyle: function (excludes) {\n        var style = getLineStyle(this, excludes);\n        var lineDash = this.getLineDash(style.lineWidth);\n        lineDash && (style.lineDash = lineDash);\n        return style;\n    },\n\n    getLineDash: function (lineWidth) {\n        if (lineWidth == null) {\n            lineWidth = 1;\n        }\n        var lineType = this.get('type');\n        var dotSize = Math.max(lineWidth, 2);\n        var dashSize = lineWidth * 4;\n        return (lineType === 'solid' || lineType == null) ? null\n            : (lineType === 'dashed' ? [dashSize, dashSize] : [dotSize, dotSize]);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getAreaStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['opacity'],\n        ['shadowColor']\n    ]\n);\n\nvar areaStyleMixin = {\n    getAreaStyle: function (excludes, includes) {\n        return getAreaStyle(this, excludes, includes);\n    }\n};\n\n/**\n * 曲线辅助模块\n * @module zrender/core/curve\n * @author pissang(https://www.github.com/pissang)\n */\n\nvar mathPow = Math.pow;\nvar mathSqrt$2 = Math.sqrt;\n\nvar EPSILON$1 = 1e-8;\nvar EPSILON_NUMERIC = 1e-4;\n\nvar THREE_SQRT = mathSqrt$2(3);\nvar ONE_THIRD = 1 / 3;\n\n// 临时变量\nvar _v0 = create();\nvar _v1 = create();\nvar _v2 = create();\n\nfunction isAroundZero(val) {\n    return val > -EPSILON$1 && val < EPSILON$1;\n}\nfunction isNotAroundZero$1(val) {\n    return val > EPSILON$1 || val < -EPSILON$1;\n}\n/**\n * 计算三次贝塞尔值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @return {number}\n */\nfunction cubicAt(p0, p1, p2, p3, t) {\n    var onet = 1 - t;\n    return onet * onet * (onet * p0 + 3 * t * p1)\n            + t * t * (t * p3 + 3 * onet * p2);\n}\n\n/**\n * 计算三次贝塞尔导数值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @return {number}\n */\nfunction cubicDerivativeAt(p0, p1, p2, p3, t) {\n    var onet = 1 - t;\n    return 3 * (\n        ((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet\n        + (p3 - p2) * t * t\n    );\n}\n\n/**\n * 计算三次贝塞尔方程根，使用盛金公式\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} val\n * @param  {Array.<number>} roots\n * @return {number} 有效根数目\n */\nfunction cubicRootAt(p0, p1, p2, p3, val, roots) {\n    // Evaluate roots of cubic functions\n    var a = p3 + 3 * (p1 - p2) - p0;\n    var b = 3 * (p2 - p1 * 2 + p0);\n    var c = 3 * (p1 - p0);\n    var d = p0 - val;\n\n    var A = b * b - 3 * a * c;\n    var B = b * c - 9 * a * d;\n    var C = c * c - 3 * b * d;\n\n    var n = 0;\n\n    if (isAroundZero(A) && isAroundZero(B)) {\n        if (isAroundZero(b)) {\n            roots[0] = 0;\n        }\n        else {\n            var t1 = -c / b;  //t1, t2, t3, b is not zero\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = B * B - 4 * A * C;\n\n        if (isAroundZero(disc)) {\n            var K = B / A;\n            var t1 = -b / a + K;  // t1, a is not zero\n            var t2 = -K / 2;  // t2, t3\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var Y1 = A * b + 1.5 * a * (-B + discSqrt);\n            var Y2 = A * b + 1.5 * a * (-B - discSqrt);\n            if (Y1 < 0) {\n                Y1 = -mathPow(-Y1, ONE_THIRD);\n            }\n            else {\n                Y1 = mathPow(Y1, ONE_THIRD);\n            }\n            if (Y2 < 0) {\n                Y2 = -mathPow(-Y2, ONE_THIRD);\n            }\n            else {\n                Y2 = mathPow(Y2, ONE_THIRD);\n            }\n            var t1 = (-b - (Y1 + Y2)) / (3 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n        else {\n            var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt$2(A * A * A));\n            var theta = Math.acos(T) / 3;\n            var ASqrt = mathSqrt$2(A);\n            var tmp = Math.cos(theta);\n\n            var t1 = (-b - 2 * ASqrt * tmp) / (3 * a);\n            var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a);\n            var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n            if (t3 >= 0 && t3 <= 1) {\n                roots[n++] = t3;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 计算三次贝塞尔方程极限值的位置\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {Array.<number>} extrema\n * @return {number} 有效数目\n */\nfunction cubicExtrema(p0, p1, p2, p3, extrema) {\n    var b = 6 * p2 - 12 * p1 + 6 * p0;\n    var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2;\n    var c = 3 * p1 - 3 * p0;\n\n    var n = 0;\n    if (isAroundZero(a)) {\n        if (isNotAroundZero$1(b)) {\n            var t1 = -c / b;\n            if (t1 >= 0 && t1 <= 1) {\n                extrema[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = b * b - 4 * a * c;\n        if (isAroundZero(disc)) {\n            extrema[0] = -b / (2 * a);\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var t1 = (-b + discSqrt) / (2 * a);\n            var t2 = (-b - discSqrt) / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                extrema[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                extrema[n++] = t2;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 细分三次贝塞尔曲线\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} p3\n * @param  {number} t\n * @param  {Array.<number>} out\n */\nfunction cubicSubdivide(p0, p1, p2, p3, t, out) {\n    var p01 = (p1 - p0) * t + p0;\n    var p12 = (p2 - p1) * t + p1;\n    var p23 = (p3 - p2) * t + p2;\n\n    var p012 = (p12 - p01) * t + p01;\n    var p123 = (p23 - p12) * t + p12;\n\n    var p0123 = (p123 - p012) * t + p012;\n    // Seg0\n    out[0] = p0;\n    out[1] = p01;\n    out[2] = p012;\n    out[3] = p0123;\n    // Seg1\n    out[4] = p0123;\n    out[5] = p123;\n    out[6] = p23;\n    out[7] = p3;\n}\n\n/**\n * 投射点到三次贝塞尔曲线上，返回投射距离。\n * 投射点有可能会有一个或者多个，这里只返回其中距离最短的一个。\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x3\n * @param {number} y3\n * @param {number} x\n * @param {number} y\n * @param {Array.<number>} [out] 投射点\n * @return {number}\n */\nfunction cubicProjectPoint(\n    x0, y0, x1, y1, x2, y2, x3, y3,\n    x, y, out\n) {\n    // http://pomax.github.io/bezierinfo/#projections\n    var t;\n    var interval = 0.005;\n    var d = Infinity;\n    var prev;\n    var next;\n    var d1;\n    var d2;\n\n    _v0[0] = x;\n    _v0[1] = y;\n\n    // 先粗略估计一下可能的最小距离的 t 值\n    // PENDING\n    for (var _t = 0; _t < 1; _t += 0.05) {\n        _v1[0] = cubicAt(x0, x1, x2, x3, _t);\n        _v1[1] = cubicAt(y0, y1, y2, y3, _t);\n        d1 = distSquare(_v0, _v1);\n        if (d1 < d) {\n            t = _t;\n            d = d1;\n        }\n    }\n    d = Infinity;\n\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        if (interval < EPSILON_NUMERIC) {\n            break;\n        }\n        prev = t - interval;\n        next = t + interval;\n        // t - interval\n        _v1[0] = cubicAt(x0, x1, x2, x3, prev);\n        _v1[1] = cubicAt(y0, y1, y2, y3, prev);\n\n        d1 = distSquare(_v1, _v0);\n\n        if (prev >= 0 && d1 < d) {\n            t = prev;\n            d = d1;\n        }\n        else {\n            // t + interval\n            _v2[0] = cubicAt(x0, x1, x2, x3, next);\n            _v2[1] = cubicAt(y0, y1, y2, y3, next);\n            d2 = distSquare(_v2, _v0);\n\n            if (next <= 1 && d2 < d) {\n                t = next;\n                d = d2;\n            }\n            else {\n                interval *= 0.5;\n            }\n        }\n    }\n    // t\n    if (out) {\n        out[0] = cubicAt(x0, x1, x2, x3, t);\n        out[1] = cubicAt(y0, y1, y2, y3, t);\n    }\n    // console.log(interval, i);\n    return mathSqrt$2(d);\n}\n\n/**\n * 计算二次方贝塞尔值\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @return {number}\n */\nfunction quadraticAt(p0, p1, p2, t) {\n    var onet = 1 - t;\n    return onet * (onet * p0 + 2 * t * p1) + t * t * p2;\n}\n\n/**\n * 计算二次方贝塞尔导数值\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @return {number}\n */\nfunction quadraticDerivativeAt(p0, p1, p2, t) {\n    return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1));\n}\n\n/**\n * 计算二次方贝塞尔方程根\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @param  {Array.<number>} roots\n * @return {number} 有效根数目\n */\nfunction quadraticRootAt(p0, p1, p2, val, roots) {\n    var a = p0 - 2 * p1 + p2;\n    var b = 2 * (p1 - p0);\n    var c = p0 - val;\n\n    var n = 0;\n    if (isAroundZero(a)) {\n        if (isNotAroundZero$1(b)) {\n            var t1 = -c / b;\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n    }\n    else {\n        var disc = b * b - 4 * a * c;\n        if (isAroundZero(disc)) {\n            var t1 = -b / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n        }\n        else if (disc > 0) {\n            var discSqrt = mathSqrt$2(disc);\n            var t1 = (-b + discSqrt) / (2 * a);\n            var t2 = (-b - discSqrt) / (2 * a);\n            if (t1 >= 0 && t1 <= 1) {\n                roots[n++] = t1;\n            }\n            if (t2 >= 0 && t2 <= 1) {\n                roots[n++] = t2;\n            }\n        }\n    }\n    return n;\n}\n\n/**\n * 计算二次贝塞尔方程极限值\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @return {number}\n */\nfunction quadraticExtremum(p0, p1, p2) {\n    var divider = p0 + p2 - 2 * p1;\n    if (divider === 0) {\n        // p1 is center of p0 and p2\n        return 0.5;\n    }\n    else {\n        return (p0 - p1) / divider;\n    }\n}\n\n/**\n * 细分二次贝塞尔曲线\n * @memberOf module:zrender/core/curve\n * @param  {number} p0\n * @param  {number} p1\n * @param  {number} p2\n * @param  {number} t\n * @param  {Array.<number>} out\n */\nfunction quadraticSubdivide(p0, p1, p2, t, out) {\n    var p01 = (p1 - p0) * t + p0;\n    var p12 = (p2 - p1) * t + p1;\n    var p012 = (p12 - p01) * t + p01;\n\n    // Seg0\n    out[0] = p0;\n    out[1] = p01;\n    out[2] = p012;\n\n    // Seg1\n    out[3] = p012;\n    out[4] = p12;\n    out[5] = p2;\n}\n\n/**\n * 投射点到二次贝塞尔曲线上，返回投射距离。\n * 投射点有可能会有一个或者多个，这里只返回其中距离最短的一个。\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x\n * @param {number} y\n * @param {Array.<number>} out 投射点\n * @return {number}\n */\nfunction quadraticProjectPoint(\n    x0, y0, x1, y1, x2, y2,\n    x, y, out\n) {\n    // http://pomax.github.io/bezierinfo/#projections\n    var t;\n    var interval = 0.005;\n    var d = Infinity;\n\n    _v0[0] = x;\n    _v0[1] = y;\n\n    // 先粗略估计一下可能的最小距离的 t 值\n    // PENDING\n    for (var _t = 0; _t < 1; _t += 0.05) {\n        _v1[0] = quadraticAt(x0, x1, x2, _t);\n        _v1[1] = quadraticAt(y0, y1, y2, _t);\n        var d1 = distSquare(_v0, _v1);\n        if (d1 < d) {\n            t = _t;\n            d = d1;\n        }\n    }\n    d = Infinity;\n\n    // At most 32 iteration\n    for (var i = 0; i < 32; i++) {\n        if (interval < EPSILON_NUMERIC) {\n            break;\n        }\n        var prev = t - interval;\n        var next = t + interval;\n        // t - interval\n        _v1[0] = quadraticAt(x0, x1, x2, prev);\n        _v1[1] = quadraticAt(y0, y1, y2, prev);\n\n        var d1 = distSquare(_v1, _v0);\n\n        if (prev >= 0 && d1 < d) {\n            t = prev;\n            d = d1;\n        }\n        else {\n            // t + interval\n            _v2[0] = quadraticAt(x0, x1, x2, next);\n            _v2[1] = quadraticAt(y0, y1, y2, next);\n            var d2 = distSquare(_v2, _v0);\n            if (next <= 1 && d2 < d) {\n                t = next;\n                d = d2;\n            }\n            else {\n                interval *= 0.5;\n            }\n        }\n    }\n    // t\n    if (out) {\n        out[0] = quadraticAt(x0, x1, x2, t);\n        out[1] = quadraticAt(y0, y1, y2, t);\n    }\n    // console.log(interval, i);\n    return mathSqrt$2(d);\n}\n\n/**\n * @author Yi Shen(https://github.com/pissang)\n */\n\nvar mathMin$3 = Math.min;\nvar mathMax$3 = Math.max;\nvar mathSin$2 = Math.sin;\nvar mathCos$2 = Math.cos;\nvar PI2 = Math.PI * 2;\n\nvar start = create();\nvar end = create();\nvar extremity = create();\n\n/**\n * 从顶点数组中计算出最小包围盒，写入`min`和`max`中\n * @module zrender/core/bbox\n * @param {Array<Object>} points 顶点数组\n * @param {number} min\n * @param {number} max\n */\n\n\n/**\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromLine(x0, y0, x1, y1, min$$1, max$$1) {\n    min$$1[0] = mathMin$3(x0, x1);\n    min$$1[1] = mathMin$3(y0, y1);\n    max$$1[0] = mathMax$3(x0, x1);\n    max$$1[1] = mathMax$3(y0, y1);\n}\n\nvar xDim = [];\nvar yDim = [];\n/**\n * 从三阶贝塞尔曲线(p0, p1, p2, p3)中计算出最小包围盒，写入`min`和`max`中\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {number} x3\n * @param {number} y3\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromCubic(\n    x0, y0, x1, y1, x2, y2, x3, y3, min$$1, max$$1\n) {\n    var cubicExtrema$$1 = cubicExtrema;\n    var cubicAt$$1 = cubicAt;\n    var i;\n    var n = cubicExtrema$$1(x0, x1, x2, x3, xDim);\n    min$$1[0] = Infinity;\n    min$$1[1] = Infinity;\n    max$$1[0] = -Infinity;\n    max$$1[1] = -Infinity;\n\n    for (i = 0; i < n; i++) {\n        var x = cubicAt$$1(x0, x1, x2, x3, xDim[i]);\n        min$$1[0] = mathMin$3(x, min$$1[0]);\n        max$$1[0] = mathMax$3(x, max$$1[0]);\n    }\n    n = cubicExtrema$$1(y0, y1, y2, y3, yDim);\n    for (i = 0; i < n; i++) {\n        var y = cubicAt$$1(y0, y1, y2, y3, yDim[i]);\n        min$$1[1] = mathMin$3(y, min$$1[1]);\n        max$$1[1] = mathMax$3(y, max$$1[1]);\n    }\n\n    min$$1[0] = mathMin$3(x0, min$$1[0]);\n    max$$1[0] = mathMax$3(x0, max$$1[0]);\n    min$$1[0] = mathMin$3(x3, min$$1[0]);\n    max$$1[0] = mathMax$3(x3, max$$1[0]);\n\n    min$$1[1] = mathMin$3(y0, min$$1[1]);\n    max$$1[1] = mathMax$3(y0, max$$1[1]);\n    min$$1[1] = mathMin$3(y3, min$$1[1]);\n    max$$1[1] = mathMax$3(y3, max$$1[1]);\n}\n\n/**\n * 从二阶贝塞尔曲线(p0, p1, p2)中计算出最小包围盒，写入`min`和`max`中\n * @memberOf module:zrender/core/bbox\n * @param {number} x0\n * @param {number} y0\n * @param {number} x1\n * @param {number} y1\n * @param {number} x2\n * @param {number} y2\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromQuadratic(x0, y0, x1, y1, x2, y2, min$$1, max$$1) {\n    var quadraticExtremum$$1 = quadraticExtremum;\n    var quadraticAt$$1 = quadraticAt;\n    // Find extremities, where derivative in x dim or y dim is zero\n    var tx =\n        mathMax$3(\n            mathMin$3(quadraticExtremum$$1(x0, x1, x2), 1), 0\n        );\n    var ty =\n        mathMax$3(\n            mathMin$3(quadraticExtremum$$1(y0, y1, y2), 1), 0\n        );\n\n    var x = quadraticAt$$1(x0, x1, x2, tx);\n    var y = quadraticAt$$1(y0, y1, y2, ty);\n\n    min$$1[0] = mathMin$3(x0, x2, x);\n    min$$1[1] = mathMin$3(y0, y2, y);\n    max$$1[0] = mathMax$3(x0, x2, x);\n    max$$1[1] = mathMax$3(y0, y2, y);\n}\n\n/**\n * 从圆弧中计算出最小包围盒，写入`min`和`max`中\n * @method\n * @memberOf module:zrender/core/bbox\n * @param {number} x\n * @param {number} y\n * @param {number} rx\n * @param {number} ry\n * @param {number} startAngle\n * @param {number} endAngle\n * @param {number} anticlockwise\n * @param {Array.<number>} min\n * @param {Array.<number>} max\n */\nfunction fromArc(\n    x, y, rx, ry, startAngle, endAngle, anticlockwise, min$$1, max$$1\n) {\n    var vec2Min = min;\n    var vec2Max = max;\n\n    var diff = Math.abs(startAngle - endAngle);\n\n\n    if (diff % PI2 < 1e-4 && diff > 1e-4) {\n        // Is a circle\n        min$$1[0] = x - rx;\n        min$$1[1] = y - ry;\n        max$$1[0] = x + rx;\n        max$$1[1] = y + ry;\n        return;\n    }\n\n    start[0] = mathCos$2(startAngle) * rx + x;\n    start[1] = mathSin$2(startAngle) * ry + y;\n\n    end[0] = mathCos$2(endAngle) * rx + x;\n    end[1] = mathSin$2(endAngle) * ry + y;\n\n    vec2Min(min$$1, start, end);\n    vec2Max(max$$1, start, end);\n\n    // Thresh to [0, Math.PI * 2]\n    startAngle = startAngle % (PI2);\n    if (startAngle < 0) {\n        startAngle = startAngle + PI2;\n    }\n    endAngle = endAngle % (PI2);\n    if (endAngle < 0) {\n        endAngle = endAngle + PI2;\n    }\n\n    if (startAngle > endAngle && !anticlockwise) {\n        endAngle += PI2;\n    }\n    else if (startAngle < endAngle && anticlockwise) {\n        startAngle += PI2;\n    }\n    if (anticlockwise) {\n        var tmp = endAngle;\n        endAngle = startAngle;\n        startAngle = tmp;\n    }\n\n    // var number = 0;\n    // var step = (anticlockwise ? -Math.PI : Math.PI) / 2;\n    for (var angle = 0; angle < endAngle; angle += Math.PI / 2) {\n        if (angle > startAngle) {\n            extremity[0] = mathCos$2(angle) * rx + x;\n            extremity[1] = mathSin$2(angle) * ry + y;\n\n            vec2Min(min$$1, extremity, min$$1);\n            vec2Max(max$$1, extremity, max$$1);\n        }\n    }\n}\n\n/**\n * Path 代理，可以在`buildPath`中用于替代`ctx`, 会保存每个path操作的命令到pathCommands属性中\n * 可以用于 isInsidePath 判断以及获取boundingRect\n *\n * @module zrender/core/PathProxy\n * @author Yi Shen (http://www.github.com/pissang)\n */\n\n// TODO getTotalLength, getPointAtLength\n\nvar CMD = {\n    M: 1,\n    L: 2,\n    C: 3,\n    Q: 4,\n    A: 5,\n    Z: 6,\n    // Rect\n    R: 7\n};\n\n// var CMD_MEM_SIZE = {\n//     M: 3,\n//     L: 3,\n//     C: 7,\n//     Q: 5,\n//     A: 9,\n//     R: 5,\n//     Z: 1\n// };\n\nvar min$1 = [];\nvar max$1 = [];\nvar min2 = [];\nvar max2 = [];\nvar mathMin$2 = Math.min;\nvar mathMax$2 = Math.max;\nvar mathCos$1 = Math.cos;\nvar mathSin$1 = Math.sin;\nvar mathSqrt$1 = Math.sqrt;\nvar mathAbs = Math.abs;\n\nvar hasTypedArray = typeof Float32Array !== 'undefined';\n\n/**\n * @alias module:zrender/core/PathProxy\n * @constructor\n */\nvar PathProxy = function (notSaveData) {\n\n    this._saveData = !(notSaveData || false);\n\n    if (this._saveData) {\n        /**\n         * Path data. Stored as flat array\n         * @type {Array.<Object>}\n         */\n        this.data = [];\n    }\n\n    this._ctx = null;\n};\n\n/**\n * 快速计算Path包围盒（并不是最小包围盒）\n * @return {Object}\n */\nPathProxy.prototype = {\n\n    constructor: PathProxy,\n\n    _xi: 0,\n    _yi: 0,\n\n    _x0: 0,\n    _y0: 0,\n    // Unit x, Unit y. Provide for avoiding drawing that too short line segment\n    _ux: 0,\n    _uy: 0,\n\n    _len: 0,\n\n    _lineDash: null,\n\n    _dashOffset: 0,\n\n    _dashIdx: 0,\n\n    _dashSum: 0,\n\n    /**\n     * @readOnly\n     */\n    setScale: function (sx, sy) {\n        this._ux = mathAbs(1 / devicePixelRatio / sx) || 0;\n        this._uy = mathAbs(1 / devicePixelRatio / sy) || 0;\n    },\n\n    getContext: function () {\n        return this._ctx;\n    },\n\n    /**\n     * @param  {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    beginPath: function (ctx) {\n\n        this._ctx = ctx;\n\n        ctx && ctx.beginPath();\n\n        ctx && (this.dpr = ctx.dpr);\n\n        // Reset\n        if (this._saveData) {\n            this._len = 0;\n        }\n\n        if (this._lineDash) {\n            this._lineDash = null;\n\n            this._dashOffset = 0;\n        }\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x\n     * @param  {number} y\n     * @return {module:zrender/core/PathProxy}\n     */\n    moveTo: function (x, y) {\n        this.addData(CMD.M, x, y);\n        this._ctx && this._ctx.moveTo(x, y);\n\n        // x0, y0, xi, yi 是记录在 _dashedXXXXTo 方法中使用\n        // xi, yi 记录当前点, x0, y0 在 closePath 的时候回到起始点。\n        // 有可能在 beginPath 之后直接调用 lineTo，这时候 x0, y0 需要\n        // 在 lineTo 方法中记录，这里先不考虑这种情况，dashed line 也只在 IE10- 中不支持\n        this._x0 = x;\n        this._y0 = y;\n\n        this._xi = x;\n        this._yi = y;\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x\n     * @param  {number} y\n     * @return {module:zrender/core/PathProxy}\n     */\n    lineTo: function (x, y) {\n        var exceedUnit = mathAbs(x - this._xi) > this._ux\n            || mathAbs(y - this._yi) > this._uy\n            // Force draw the first segment\n            || this._len < 5;\n\n        this.addData(CMD.L, x, y);\n\n        if (this._ctx && exceedUnit) {\n            this._needsDash() ? this._dashedLineTo(x, y)\n                : this._ctx.lineTo(x, y);\n        }\n        if (exceedUnit) {\n            this._xi = x;\n            this._yi = y;\n        }\n\n        return this;\n    },\n\n    /**\n     * @param  {number} x1\n     * @param  {number} y1\n     * @param  {number} x2\n     * @param  {number} y2\n     * @param  {number} x3\n     * @param  {number} y3\n     * @return {module:zrender/core/PathProxy}\n     */\n    bezierCurveTo: function (x1, y1, x2, y2, x3, y3) {\n        this.addData(CMD.C, x1, y1, x2, y2, x3, y3);\n        if (this._ctx) {\n            this._needsDash() ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3)\n                : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);\n        }\n        this._xi = x3;\n        this._yi = y3;\n        return this;\n    },\n\n    /**\n     * @param  {number} x1\n     * @param  {number} y1\n     * @param  {number} x2\n     * @param  {number} y2\n     * @return {module:zrender/core/PathProxy}\n     */\n    quadraticCurveTo: function (x1, y1, x2, y2) {\n        this.addData(CMD.Q, x1, y1, x2, y2);\n        if (this._ctx) {\n            this._needsDash() ? this._dashedQuadraticTo(x1, y1, x2, y2)\n                : this._ctx.quadraticCurveTo(x1, y1, x2, y2);\n        }\n        this._xi = x2;\n        this._yi = y2;\n        return this;\n    },\n\n    /**\n     * @param  {number} cx\n     * @param  {number} cy\n     * @param  {number} r\n     * @param  {number} startAngle\n     * @param  {number} endAngle\n     * @param  {boolean} anticlockwise\n     * @return {module:zrender/core/PathProxy}\n     */\n    arc: function (cx, cy, r, startAngle, endAngle, anticlockwise) {\n        this.addData(\n            CMD.A, cx, cy, r, r, startAngle, endAngle - startAngle, 0, anticlockwise ? 0 : 1\n        );\n        this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);\n\n        this._xi = mathCos$1(endAngle) * r + cx;\n        this._yi = mathSin$1(endAngle) * r + cy;\n        return this;\n    },\n\n    // TODO\n    arcTo: function (x1, y1, x2, y2, radius) {\n        if (this._ctx) {\n            this._ctx.arcTo(x1, y1, x2, y2, radius);\n        }\n        return this;\n    },\n\n    // TODO\n    rect: function (x, y, w, h) {\n        this._ctx && this._ctx.rect(x, y, w, h);\n        this.addData(CMD.R, x, y, w, h);\n        return this;\n    },\n\n    /**\n     * @return {module:zrender/core/PathProxy}\n     */\n    closePath: function () {\n        this.addData(CMD.Z);\n\n        var ctx = this._ctx;\n        var x0 = this._x0;\n        var y0 = this._y0;\n        if (ctx) {\n            this._needsDash() && this._dashedLineTo(x0, y0);\n            ctx.closePath();\n        }\n\n        this._xi = x0;\n        this._yi = y0;\n        return this;\n    },\n\n    /**\n     * Context 从外部传入，因为有可能是 rebuildPath 完之后再 fill。\n     * stroke 同样\n     * @param {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    fill: function (ctx) {\n        ctx && ctx.fill();\n        this.toStatic();\n    },\n\n    /**\n     * @param {CanvasRenderingContext2D} ctx\n     * @return {module:zrender/core/PathProxy}\n     */\n    stroke: function (ctx) {\n        ctx && ctx.stroke();\n        this.toStatic();\n    },\n\n    /**\n     * 必须在其它绘制命令前调用\n     * Must be invoked before all other path drawing methods\n     * @return {module:zrender/core/PathProxy}\n     */\n    setLineDash: function (lineDash) {\n        if (lineDash instanceof Array) {\n            this._lineDash = lineDash;\n\n            this._dashIdx = 0;\n\n            var lineDashSum = 0;\n            for (var i = 0; i < lineDash.length; i++) {\n                lineDashSum += lineDash[i];\n            }\n            this._dashSum = lineDashSum;\n        }\n        return this;\n    },\n\n    /**\n     * 必须在其它绘制命令前调用\n     * Must be invoked before all other path drawing methods\n     * @return {module:zrender/core/PathProxy}\n     */\n    setLineDashOffset: function (offset) {\n        this._dashOffset = offset;\n        return this;\n    },\n\n    /**\n     *\n     * @return {boolean}\n     */\n    len: function () {\n        return this._len;\n    },\n\n    /**\n     * 直接设置 Path 数据\n     */\n    setData: function (data) {\n\n        var len$$1 = data.length;\n\n        if (!(this.data && this.data.length === len$$1) && hasTypedArray) {\n            this.data = new Float32Array(len$$1);\n        }\n\n        for (var i = 0; i < len$$1; i++) {\n            this.data[i] = data[i];\n        }\n\n        this._len = len$$1;\n    },\n\n    /**\n     * 添加子路径\n     * @param {module:zrender/core/PathProxy|Array.<module:zrender/core/PathProxy>} path\n     */\n    appendPath: function (path) {\n        if (!(path instanceof Array)) {\n            path = [path];\n        }\n        var len$$1 = path.length;\n        var appendSize = 0;\n        var offset = this._len;\n        for (var i = 0; i < len$$1; i++) {\n            appendSize += path[i].len();\n        }\n        if (hasTypedArray && (this.data instanceof Float32Array)) {\n            this.data = new Float32Array(offset + appendSize);\n        }\n        for (var i = 0; i < len$$1; i++) {\n            var appendPathData = path[i].data;\n            for (var k = 0; k < appendPathData.length; k++) {\n                this.data[offset++] = appendPathData[k];\n            }\n        }\n        this._len = offset;\n    },\n\n    /**\n     * 填充 Path 数据。\n     * 尽量复用而不申明新的数组。大部分图形重绘的指令数据长度都是不变的。\n     */\n    addData: function (cmd) {\n        if (!this._saveData) {\n            return;\n        }\n\n        var data = this.data;\n        if (this._len + arguments.length > data.length) {\n            // 因为之前的数组已经转换成静态的 Float32Array\n            // 所以不够用时需要扩展一个新的动态数组\n            this._expandData();\n            data = this.data;\n        }\n        for (var i = 0; i < arguments.length; i++) {\n            data[this._len++] = arguments[i];\n        }\n\n        this._prevCmd = cmd;\n    },\n\n    _expandData: function () {\n        // Only if data is Float32Array\n        if (!(this.data instanceof Array)) {\n            var newData = [];\n            for (var i = 0; i < this._len; i++) {\n                newData[i] = this.data[i];\n            }\n            this.data = newData;\n        }\n    },\n\n    /**\n     * If needs js implemented dashed line\n     * @return {boolean}\n     * @private\n     */\n    _needsDash: function () {\n        return this._lineDash;\n    },\n\n    _dashedLineTo: function (x1, y1) {\n        var dashSum = this._dashSum;\n        var offset = this._dashOffset;\n        var lineDash = this._lineDash;\n        var ctx = this._ctx;\n\n        var x0 = this._xi;\n        var y0 = this._yi;\n        var dx = x1 - x0;\n        var dy = y1 - y0;\n        var dist$$1 = mathSqrt$1(dx * dx + dy * dy);\n        var x = x0;\n        var y = y0;\n        var dash;\n        var nDash = lineDash.length;\n        var idx;\n        dx /= dist$$1;\n        dy /= dist$$1;\n\n        if (offset < 0) {\n            // Convert to positive offset\n            offset = dashSum + offset;\n        }\n        offset %= dashSum;\n        x -= offset * dx;\n        y -= offset * dy;\n\n        while ((dx > 0 && x <= x1) || (dx < 0 && x >= x1)\n        || (dx === 0 && ((dy > 0 && y <= y1) || (dy < 0 && y >= y1)))) {\n            idx = this._dashIdx;\n            dash = lineDash[idx];\n            x += dx * dash;\n            y += dy * dash;\n            this._dashIdx = (idx + 1) % nDash;\n            // Skip positive offset\n            if ((dx > 0 && x < x0) || (dx < 0 && x > x0) || (dy > 0 && y < y0) || (dy < 0 && y > y0)) {\n                continue;\n            }\n            ctx[idx % 2 ? 'moveTo' : 'lineTo'](\n                dx >= 0 ? mathMin$2(x, x1) : mathMax$2(x, x1),\n                dy >= 0 ? mathMin$2(y, y1) : mathMax$2(y, y1)\n            );\n        }\n        // Offset for next lineTo\n        dx = x - x1;\n        dy = y - y1;\n        this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);\n    },\n\n    // Not accurate dashed line to\n    _dashedBezierTo: function (x1, y1, x2, y2, x3, y3) {\n        var dashSum = this._dashSum;\n        var offset = this._dashOffset;\n        var lineDash = this._lineDash;\n        var ctx = this._ctx;\n\n        var x0 = this._xi;\n        var y0 = this._yi;\n        var t;\n        var dx;\n        var dy;\n        var cubicAt$$1 = cubicAt;\n        var bezierLen = 0;\n        var idx = this._dashIdx;\n        var nDash = lineDash.length;\n\n        var x;\n        var y;\n\n        var tmpLen = 0;\n\n        if (offset < 0) {\n            // Convert to positive offset\n            offset = dashSum + offset;\n        }\n        offset %= dashSum;\n        // Bezier approx length\n        for (t = 0; t < 1; t += 0.1) {\n            dx = cubicAt$$1(x0, x1, x2, x3, t + 0.1)\n                - cubicAt$$1(x0, x1, x2, x3, t);\n            dy = cubicAt$$1(y0, y1, y2, y3, t + 0.1)\n                - cubicAt$$1(y0, y1, y2, y3, t);\n            bezierLen += mathSqrt$1(dx * dx + dy * dy);\n        }\n\n        // Find idx after add offset\n        for (; idx < nDash; idx++) {\n            tmpLen += lineDash[idx];\n            if (tmpLen > offset) {\n                break;\n            }\n        }\n        t = (tmpLen - offset) / bezierLen;\n\n        while (t <= 1) {\n\n            x = cubicAt$$1(x0, x1, x2, x3, t);\n            y = cubicAt$$1(y0, y1, y2, y3, t);\n\n            // Use line to approximate dashed bezier\n            // Bad result if dash is long\n            idx % 2 ? ctx.moveTo(x, y)\n                : ctx.lineTo(x, y);\n\n            t += lineDash[idx] / bezierLen;\n\n            idx = (idx + 1) % nDash;\n        }\n\n        // Finish the last segment and calculate the new offset\n        (idx % 2 !== 0) && ctx.lineTo(x3, y3);\n        dx = x3 - x;\n        dy = y3 - y;\n        this._dashOffset = -mathSqrt$1(dx * dx + dy * dy);\n    },\n\n    _dashedQuadraticTo: function (x1, y1, x2, y2) {\n        // Convert quadratic to cubic using degree elevation\n        var x3 = x2;\n        var y3 = y2;\n        x2 = (x2 + 2 * x1) / 3;\n        y2 = (y2 + 2 * y1) / 3;\n        x1 = (this._xi + 2 * x1) / 3;\n        y1 = (this._yi + 2 * y1) / 3;\n\n        this._dashedBezierTo(x1, y1, x2, y2, x3, y3);\n    },\n\n    /**\n     * 转成静态的 Float32Array 减少堆内存占用\n     * Convert dynamic array to static Float32Array\n     */\n    toStatic: function () {\n        var data = this.data;\n        if (data instanceof Array) {\n            data.length = this._len;\n            if (hasTypedArray) {\n                this.data = new Float32Array(data);\n            }\n        }\n    },\n\n    /**\n     * @return {module:zrender/core/BoundingRect}\n     */\n    getBoundingRect: function () {\n        min$1[0] = min$1[1] = min2[0] = min2[1] = Number.MAX_VALUE;\n        max$1[0] = max$1[1] = max2[0] = max2[1] = -Number.MAX_VALUE;\n\n        var data = this.data;\n        var xi = 0;\n        var yi = 0;\n        var x0 = 0;\n        var y0 = 0;\n\n        for (var i = 0; i < data.length;) {\n            var cmd = data[i++];\n\n            if (i === 1) {\n                // 如果第一个命令是 L, C, Q\n                // 则 previous point 同绘制命令的第一个 point\n                //\n                // 第一个命令为 Arc 的情况下会在后面特殊处理\n                xi = data[i];\n                yi = data[i + 1];\n\n                x0 = xi;\n                y0 = yi;\n            }\n\n            switch (cmd) {\n                case CMD.M:\n                    // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点\n                    // 在 closePath 的时候使用\n                    x0 = data[i++];\n                    y0 = data[i++];\n                    xi = x0;\n                    yi = y0;\n                    min2[0] = x0;\n                    min2[1] = y0;\n                    max2[0] = x0;\n                    max2[1] = y0;\n                    break;\n                case CMD.L:\n                    fromLine(xi, yi, data[i], data[i + 1], min2, max2);\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.C:\n                    fromCubic(\n                        xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        min2, max2\n                    );\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.Q:\n                    fromQuadratic(\n                        xi, yi, data[i++], data[i++], data[i], data[i + 1],\n                        min2, max2\n                    );\n                    xi = data[i++];\n                    yi = data[i++];\n                    break;\n                case CMD.A:\n                    // TODO Arc 判断的开销比较大\n                    var cx = data[i++];\n                    var cy = data[i++];\n                    var rx = data[i++];\n                    var ry = data[i++];\n                    var startAngle = data[i++];\n                    var endAngle = data[i++] + startAngle;\n                    // TODO Arc 旋转\n                    i += 1;\n                    var anticlockwise = 1 - data[i++];\n\n                    if (i === 1) {\n                        // 直接使用 arc 命令\n                        // 第一个命令起点还未定义\n                        x0 = mathCos$1(startAngle) * rx + cx;\n                        y0 = mathSin$1(startAngle) * ry + cy;\n                    }\n\n                    fromArc(\n                        cx, cy, rx, ry, startAngle, endAngle,\n                        anticlockwise, min2, max2\n                    );\n\n                    xi = mathCos$1(endAngle) * rx + cx;\n                    yi = mathSin$1(endAngle) * ry + cy;\n                    break;\n                case CMD.R:\n                    x0 = xi = data[i++];\n                    y0 = yi = data[i++];\n                    var width = data[i++];\n                    var height = data[i++];\n                    // Use fromLine\n                    fromLine(x0, y0, x0 + width, y0 + height, min2, max2);\n                    break;\n                case CMD.Z:\n                    xi = x0;\n                    yi = y0;\n                    break;\n            }\n\n            // Union\n            min(min$1, min$1, min2);\n            max(max$1, max$1, max2);\n        }\n\n        // No data\n        if (i === 0) {\n            min$1[0] = min$1[1] = max$1[0] = max$1[1] = 0;\n        }\n\n        return new BoundingRect(\n            min$1[0], min$1[1], max$1[0] - min$1[0], max$1[1] - min$1[1]\n        );\n    },\n\n    /**\n     * Rebuild path from current data\n     * Rebuild path will not consider javascript implemented line dash.\n     * @param {CanvasRenderingContext2D} ctx\n     */\n    rebuildPath: function (ctx) {\n        var d = this.data;\n        var x0, y0;\n        var xi, yi;\n        var x, y;\n        var ux = this._ux;\n        var uy = this._uy;\n        var len$$1 = this._len;\n        for (var i = 0; i < len$$1;) {\n            var cmd = d[i++];\n\n            if (i === 1) {\n                // 如果第一个命令是 L, C, Q\n                // 则 previous point 同绘制命令的第一个 point\n                //\n                // 第一个命令为 Arc 的情况下会在后面特殊处理\n                xi = d[i];\n                yi = d[i + 1];\n\n                x0 = xi;\n                y0 = yi;\n            }\n            switch (cmd) {\n                case CMD.M:\n                    x0 = xi = d[i++];\n                    y0 = yi = d[i++];\n                    ctx.moveTo(xi, yi);\n                    break;\n                case CMD.L:\n                    x = d[i++];\n                    y = d[i++];\n                    // Not draw too small seg between\n                    if (mathAbs(x - xi) > ux || mathAbs(y - yi) > uy || i === len$$1 - 1) {\n                        ctx.lineTo(x, y);\n                        xi = x;\n                        yi = y;\n                    }\n                    break;\n                case CMD.C:\n                    ctx.bezierCurveTo(\n                        d[i++], d[i++], d[i++], d[i++], d[i++], d[i++]\n                    );\n                    xi = d[i - 2];\n                    yi = d[i - 1];\n                    break;\n                case CMD.Q:\n                    ctx.quadraticCurveTo(d[i++], d[i++], d[i++], d[i++]);\n                    xi = d[i - 2];\n                    yi = d[i - 1];\n                    break;\n                case CMD.A:\n                    var cx = d[i++];\n                    var cy = d[i++];\n                    var rx = d[i++];\n                    var ry = d[i++];\n                    var theta = d[i++];\n                    var dTheta = d[i++];\n                    var psi = d[i++];\n                    var fs = d[i++];\n                    var r = (rx > ry) ? rx : ry;\n                    var scaleX = (rx > ry) ? 1 : rx / ry;\n                    var scaleY = (rx > ry) ? ry / rx : 1;\n                    var isEllipse = Math.abs(rx - ry) > 1e-3;\n                    var endAngle = theta + dTheta;\n                    if (isEllipse) {\n                        ctx.translate(cx, cy);\n                        ctx.rotate(psi);\n                        ctx.scale(scaleX, scaleY);\n                        ctx.arc(0, 0, r, theta, endAngle, 1 - fs);\n                        ctx.scale(1 / scaleX, 1 / scaleY);\n                        ctx.rotate(-psi);\n                        ctx.translate(-cx, -cy);\n                    }\n                    else {\n                        ctx.arc(cx, cy, r, theta, endAngle, 1 - fs);\n                    }\n\n                    if (i === 1) {\n                        // 直接使用 arc 命令\n                        // 第一个命令起点还未定义\n                        x0 = mathCos$1(theta) * rx + cx;\n                        y0 = mathSin$1(theta) * ry + cy;\n                    }\n                    xi = mathCos$1(endAngle) * rx + cx;\n                    yi = mathSin$1(endAngle) * ry + cy;\n                    break;\n                case CMD.R:\n                    x0 = xi = d[i];\n                    y0 = yi = d[i + 1];\n                    ctx.rect(d[i++], d[i++], d[i++], d[i++]);\n                    break;\n                case CMD.Z:\n                    ctx.closePath();\n                    xi = x0;\n                    yi = y0;\n            }\n        }\n    }\n};\n\nPathProxy.CMD = CMD;\n\n/**\n * 线段包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$1(x0, y0, x1, y1, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    var _a = 0;\n    var _b = x0;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l)\n        || (y < y0 - _l && y < y1 - _l)\n        || (x > x0 + _l && x > x1 + _l)\n        || (x < x0 - _l && x < x1 - _l)\n    ) {\n        return false;\n    }\n\n    if (x0 !== x1) {\n        _a = (y0 - y1) / (x0 - x1);\n        _b = (x0 * y1 - x1 * y0) / (x0 - x1);\n    }\n    else {\n        return Math.abs(x - x0) <= _l / 2;\n    }\n    var tmp = _a * x - y + _b;\n    var _s = tmp * tmp / (_a * _a + 1);\n    return _s <= _l / 2 * _l / 2;\n}\n\n/**\n * 三次贝塞尔曲线描边包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  x2\n * @param  {number}  y2\n * @param  {number}  x3\n * @param  {number}  y3\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$2(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l)\n        || (y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l)\n        || (x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l)\n        || (x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l)\n    ) {\n        return false;\n    }\n    var d = cubicProjectPoint(\n        x0, y0, x1, y1, x2, y2, x3, y3,\n        x, y, null\n    );\n    return d <= _l / 2;\n}\n\n/**\n * 二次贝塞尔曲线描边包含判断\n * @param  {number}  x0\n * @param  {number}  y0\n * @param  {number}  x1\n * @param  {number}  y1\n * @param  {number}  x2\n * @param  {number}  y2\n * @param  {number}  lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {boolean}\n */\nfunction containStroke$3(x0, y0, x1, y1, x2, y2, lineWidth, x, y) {\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n    // Quick reject\n    if (\n        (y > y0 + _l && y > y1 + _l && y > y2 + _l)\n        || (y < y0 - _l && y < y1 - _l && y < y2 - _l)\n        || (x > x0 + _l && x > x1 + _l && x > x2 + _l)\n        || (x < x0 - _l && x < x1 - _l && x < x2 - _l)\n    ) {\n        return false;\n    }\n    var d = quadraticProjectPoint(\n        x0, y0, x1, y1, x2, y2,\n        x, y, null\n    );\n    return d <= _l / 2;\n}\n\nvar PI2$3 = Math.PI * 2;\n\nfunction normalizeRadian(angle) {\n    angle %= PI2$3;\n    if (angle < 0) {\n        angle += PI2$3;\n    }\n    return angle;\n}\n\nvar PI2$2 = Math.PI * 2;\n\n/**\n * 圆弧描边包含判断\n * @param  {number}  cx\n * @param  {number}  cy\n * @param  {number}  r\n * @param  {number}  startAngle\n * @param  {number}  endAngle\n * @param  {boolean}  anticlockwise\n * @param  {number} lineWidth\n * @param  {number}  x\n * @param  {number}  y\n * @return {Boolean}\n */\nfunction containStroke$4(\n    cx, cy, r, startAngle, endAngle, anticlockwise,\n    lineWidth, x, y\n) {\n\n    if (lineWidth === 0) {\n        return false;\n    }\n    var _l = lineWidth;\n\n    x -= cx;\n    y -= cy;\n    var d = Math.sqrt(x * x + y * y);\n\n    if ((d - _l > r) || (d + _l < r)) {\n        return false;\n    }\n    if (Math.abs(startAngle - endAngle) % PI2$2 < 1e-4) {\n        // Is a circle\n        return true;\n    }\n    if (anticlockwise) {\n        var tmp = startAngle;\n        startAngle = normalizeRadian(endAngle);\n        endAngle = normalizeRadian(tmp);\n    }\n    else {\n        startAngle = normalizeRadian(startAngle);\n        endAngle = normalizeRadian(endAngle);\n    }\n    if (startAngle > endAngle) {\n        endAngle += PI2$2;\n    }\n\n    var angle = Math.atan2(y, x);\n    if (angle < 0) {\n        angle += PI2$2;\n    }\n    return (angle >= startAngle && angle <= endAngle)\n        || (angle + PI2$2 >= startAngle && angle + PI2$2 <= endAngle);\n}\n\nfunction windingLine(x0, y0, x1, y1, x, y) {\n    if ((y > y0 && y > y1) || (y < y0 && y < y1)) {\n        return 0;\n    }\n    // Ignore horizontal line\n    if (y1 === y0) {\n        return 0;\n    }\n    var dir = y1 < y0 ? 1 : -1;\n    var t = (y - y0) / (y1 - y0);\n\n    // Avoid winding error when intersection point is the connect point of two line of polygon\n    if (t === 1 || t === 0) {\n        dir = y1 < y0 ? 0.5 : -0.5;\n    }\n\n    var x_ = t * (x1 - x0) + x0;\n\n    // If (x, y) on the line, considered as \"contain\".\n    return x_ === x ? Infinity : x_ > x ? dir : 0;\n}\n\nvar CMD$1 = PathProxy.CMD;\nvar PI2$1 = Math.PI * 2;\n\nvar EPSILON$2 = 1e-4;\n\nfunction isAroundEqual(a, b) {\n    return Math.abs(a - b) < EPSILON$2;\n}\n\n// 临时数组\nvar roots = [-1, -1, -1];\nvar extrema = [-1, -1];\n\nfunction swapExtrema() {\n    var tmp = extrema[0];\n    extrema[0] = extrema[1];\n    extrema[1] = tmp;\n}\n\nfunction windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {\n    // Quick reject\n    if (\n        (y > y0 && y > y1 && y > y2 && y > y3)\n        || (y < y0 && y < y1 && y < y2 && y < y3)\n    ) {\n        return 0;\n    }\n    var nRoots = cubicRootAt(y0, y1, y2, y3, y, roots);\n    if (nRoots === 0) {\n        return 0;\n    }\n    else {\n        var w = 0;\n        var nExtrema = -1;\n        var y0_;\n        var y1_;\n        for (var i = 0; i < nRoots; i++) {\n            var t = roots[i];\n\n            // Avoid winding error when intersection point is the connect point of two line of polygon\n            var unit = (t === 0 || t === 1) ? 0.5 : 1;\n\n            var x_ = cubicAt(x0, x1, x2, x3, t);\n            if (x_ < x) { // Quick reject\n                continue;\n            }\n            if (nExtrema < 0) {\n                nExtrema = cubicExtrema(y0, y1, y2, y3, extrema);\n                if (extrema[1] < extrema[0] && nExtrema > 1) {\n                    swapExtrema();\n                }\n                y0_ = cubicAt(y0, y1, y2, y3, extrema[0]);\n                if (nExtrema > 1) {\n                    y1_ = cubicAt(y0, y1, y2, y3, extrema[1]);\n                }\n            }\n            if (nExtrema === 2) {\n                // 分成三段单调函数\n                if (t < extrema[0]) {\n                    w += y0_ < y0 ? unit : -unit;\n                }\n                else if (t < extrema[1]) {\n                    w += y1_ < y0_ ? unit : -unit;\n                }\n                else {\n                    w += y3 < y1_ ? unit : -unit;\n                }\n            }\n            else {\n                // 分成两段单调函数\n                if (t < extrema[0]) {\n                    w += y0_ < y0 ? unit : -unit;\n                }\n                else {\n                    w += y3 < y0_ ? unit : -unit;\n                }\n            }\n        }\n        return w;\n    }\n}\n\nfunction windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {\n    // Quick reject\n    if (\n        (y > y0 && y > y1 && y > y2)\n        || (y < y0 && y < y1 && y < y2)\n    ) {\n        return 0;\n    }\n    var nRoots = quadraticRootAt(y0, y1, y2, y, roots);\n    if (nRoots === 0) {\n        return 0;\n    }\n    else {\n        var t = quadraticExtremum(y0, y1, y2);\n        if (t >= 0 && t <= 1) {\n            var w = 0;\n            var y_ = quadraticAt(y0, y1, y2, t);\n            for (var i = 0; i < nRoots; i++) {\n                // Remove one endpoint.\n                var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1;\n\n                var x_ = quadraticAt(x0, x1, x2, roots[i]);\n                if (x_ < x) {   // Quick reject\n                    continue;\n                }\n                if (roots[i] < t) {\n                    w += y_ < y0 ? unit : -unit;\n                }\n                else {\n                    w += y2 < y_ ? unit : -unit;\n                }\n            }\n            return w;\n        }\n        else {\n            // Remove one endpoint.\n            var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1;\n\n            var x_ = quadraticAt(x0, x1, x2, roots[0]);\n            if (x_ < x) {   // Quick reject\n                return 0;\n            }\n            return y2 < y0 ? unit : -unit;\n        }\n    }\n}\n\n// TODO\n// Arc 旋转\nfunction windingArc(\n    cx, cy, r, startAngle, endAngle, anticlockwise, x, y\n) {\n    y -= cy;\n    if (y > r || y < -r) {\n        return 0;\n    }\n    var tmp = Math.sqrt(r * r - y * y);\n    roots[0] = -tmp;\n    roots[1] = tmp;\n\n    var diff = Math.abs(startAngle - endAngle);\n    if (diff < 1e-4) {\n        return 0;\n    }\n    if (diff % PI2$1 < 1e-4) {\n        // Is a circle\n        startAngle = 0;\n        endAngle = PI2$1;\n        var dir = anticlockwise ? 1 : -1;\n        if (x >= roots[0] + cx && x <= roots[1] + cx) {\n            return dir;\n        }\n        else {\n            return 0;\n        }\n    }\n\n    if (anticlockwise) {\n        var tmp = startAngle;\n        startAngle = normalizeRadian(endAngle);\n        endAngle = normalizeRadian(tmp);\n    }\n    else {\n        startAngle = normalizeRadian(startAngle);\n        endAngle = normalizeRadian(endAngle);\n    }\n    if (startAngle > endAngle) {\n        endAngle += PI2$1;\n    }\n\n    var w = 0;\n    for (var i = 0; i < 2; i++) {\n        var x_ = roots[i];\n        if (x_ + cx > x) {\n            var angle = Math.atan2(y, x_);\n            var dir = anticlockwise ? 1 : -1;\n            if (angle < 0) {\n                angle = PI2$1 + angle;\n            }\n            if (\n                (angle >= startAngle && angle <= endAngle)\n                || (angle + PI2$1 >= startAngle && angle + PI2$1 <= endAngle)\n            ) {\n                if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {\n                    dir = -dir;\n                }\n                w += dir;\n            }\n        }\n    }\n    return w;\n}\n\nfunction containPath(data, lineWidth, isStroke, x, y) {\n    var w = 0;\n    var xi = 0;\n    var yi = 0;\n    var x0 = 0;\n    var y0 = 0;\n\n    for (var i = 0; i < data.length;) {\n        var cmd = data[i++];\n        // Begin a new subpath\n        if (cmd === CMD$1.M && i > 1) {\n            // Close previous subpath\n            if (!isStroke) {\n                w += windingLine(xi, yi, x0, y0, x, y);\n            }\n            // 如果被任何一个 subpath 包含\n            // if (w !== 0) {\n            //     return true;\n            // }\n        }\n\n        if (i === 1) {\n            // 如果第一个命令是 L, C, Q\n            // 则 previous point 同绘制命令的第一个 point\n            //\n            // 第一个命令为 Arc 的情况下会在后面特殊处理\n            xi = data[i];\n            yi = data[i + 1];\n\n            x0 = xi;\n            y0 = yi;\n        }\n\n        switch (cmd) {\n            case CMD$1.M:\n                // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点\n                // 在 closePath 的时候使用\n                x0 = data[i++];\n                y0 = data[i++];\n                xi = x0;\n                yi = y0;\n                break;\n            case CMD$1.L:\n                if (isStroke) {\n                    if (containStroke$1(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {\n                        return true;\n                    }\n                }\n                else {\n                    // NOTE 在第一个命令为 L, C, Q 的时候会计算出 NaN\n                    w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.C:\n                if (isStroke) {\n                    if (containStroke$2(xi, yi,\n                        data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingCubic(\n                        xi, yi,\n                        data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1],\n                        x, y\n                    ) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.Q:\n                if (isStroke) {\n                    if (containStroke$3(xi, yi,\n                        data[i++], data[i++], data[i], data[i + 1],\n                        lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingQuadratic(\n                        xi, yi,\n                        data[i++], data[i++], data[i], data[i + 1],\n                        x, y\n                    ) || 0;\n                }\n                xi = data[i++];\n                yi = data[i++];\n                break;\n            case CMD$1.A:\n                // TODO Arc 判断的开销比较大\n                var cx = data[i++];\n                var cy = data[i++];\n                var rx = data[i++];\n                var ry = data[i++];\n                var theta = data[i++];\n                var dTheta = data[i++];\n                // TODO Arc 旋转\n                i += 1;\n                var anticlockwise = 1 - data[i++];\n                var x1 = Math.cos(theta) * rx + cx;\n                var y1 = Math.sin(theta) * ry + cy;\n                // 不是直接使用 arc 命令\n                if (i > 1) {\n                    w += windingLine(xi, yi, x1, y1, x, y);\n                }\n                else {\n                    // 第一个命令起点还未定义\n                    x0 = x1;\n                    y0 = y1;\n                }\n                // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放\n                var _x = (x - cx) * ry / rx + cx;\n                if (isStroke) {\n                    if (containStroke$4(\n                        cx, cy, ry, theta, theta + dTheta, anticlockwise,\n                        lineWidth, _x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    w += windingArc(\n                        cx, cy, ry, theta, theta + dTheta, anticlockwise,\n                        _x, y\n                    );\n                }\n                xi = Math.cos(theta + dTheta) * rx + cx;\n                yi = Math.sin(theta + dTheta) * ry + cy;\n                break;\n            case CMD$1.R:\n                x0 = xi = data[i++];\n                y0 = yi = data[i++];\n                var width = data[i++];\n                var height = data[i++];\n                var x1 = x0 + width;\n                var y1 = y0 + height;\n                if (isStroke) {\n                    if (containStroke$1(x0, y0, x1, y0, lineWidth, x, y)\n                        || containStroke$1(x1, y0, x1, y1, lineWidth, x, y)\n                        || containStroke$1(x1, y1, x0, y1, lineWidth, x, y)\n                        || containStroke$1(x0, y1, x0, y0, lineWidth, x, y)\n                    ) {\n                        return true;\n                    }\n                }\n                else {\n                    // FIXME Clockwise ?\n                    w += windingLine(x1, y0, x1, y1, x, y);\n                    w += windingLine(x0, y1, x0, y0, x, y);\n                }\n                break;\n            case CMD$1.Z:\n                if (isStroke) {\n                    if (containStroke$1(\n                        xi, yi, x0, y0, lineWidth, x, y\n                    )) {\n                        return true;\n                    }\n                }\n                else {\n                    // Close a subpath\n                    w += windingLine(xi, yi, x0, y0, x, y);\n                    // 如果被任何一个 subpath 包含\n                    // FIXME subpaths may overlap\n                    // if (w !== 0) {\n                    //     return true;\n                    // }\n                }\n                xi = x0;\n                yi = y0;\n                break;\n        }\n    }\n    if (!isStroke && !isAroundEqual(yi, y0)) {\n        w += windingLine(xi, yi, x0, y0, x, y) || 0;\n    }\n    return w !== 0;\n}\n\nfunction contain(pathData, x, y) {\n    return containPath(pathData, 0, false, x, y);\n}\n\nfunction containStroke(pathData, lineWidth, x, y) {\n    return containPath(pathData, lineWidth, true, x, y);\n}\n\nvar getCanvasPattern = Pattern.prototype.getCanvasPattern;\n\nvar abs = Math.abs;\n\nvar pathProxyForDraw = new PathProxy(true);\n/**\n * @alias module:zrender/graphic/Path\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nfunction Path(opts) {\n    Displayable.call(this, opts);\n\n    /**\n     * @type {module:zrender/core/PathProxy}\n     * @readOnly\n     */\n    this.path = null;\n}\n\nPath.prototype = {\n\n    constructor: Path,\n\n    type: 'path',\n\n    __dirtyPath: true,\n\n    strokeContainThreshold: 5,\n\n    /**\n     * See `module:zrender/src/graphic/helper/subPixelOptimize`.\n     * @type {boolean}\n     */\n    subPixelOptimize: false,\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n        var path = this.path || pathProxyForDraw;\n        var hasStroke = style.hasStroke();\n        var hasFill = style.hasFill();\n        var fill = style.fill;\n        var stroke = style.stroke;\n        var hasFillGradient = hasFill && !!(fill.colorStops);\n        var hasStrokeGradient = hasStroke && !!(stroke.colorStops);\n        var hasFillPattern = hasFill && !!(fill.image);\n        var hasStrokePattern = hasStroke && !!(stroke.image);\n\n        style.bind(ctx, this, prevEl);\n        this.setTransform(ctx);\n\n        if (this.__dirty) {\n            var rect;\n            // Update gradient because bounding rect may changed\n            if (hasFillGradient) {\n                rect = rect || this.getBoundingRect();\n                this._fillGradient = style.getGradient(ctx, fill, rect);\n            }\n            if (hasStrokeGradient) {\n                rect = rect || this.getBoundingRect();\n                this._strokeGradient = style.getGradient(ctx, stroke, rect);\n            }\n        }\n        // Use the gradient or pattern\n        if (hasFillGradient) {\n            // PENDING If may have affect the state\n            ctx.fillStyle = this._fillGradient;\n        }\n        else if (hasFillPattern) {\n            ctx.fillStyle = getCanvasPattern.call(fill, ctx);\n        }\n        if (hasStrokeGradient) {\n            ctx.strokeStyle = this._strokeGradient;\n        }\n        else if (hasStrokePattern) {\n            ctx.strokeStyle = getCanvasPattern.call(stroke, ctx);\n        }\n\n        var lineDash = style.lineDash;\n        var lineDashOffset = style.lineDashOffset;\n\n        var ctxLineDash = !!ctx.setLineDash;\n\n        // Update path sx, sy\n        var scale = this.getGlobalScale();\n        path.setScale(scale[0], scale[1]);\n\n        // Proxy context\n        // Rebuild path in following 2 cases\n        // 1. Path is dirty\n        // 2. Path needs javascript implemented lineDash stroking.\n        //    In this case, lineDash information will not be saved in PathProxy\n        if (this.__dirtyPath\n            || (lineDash && !ctxLineDash && hasStroke)\n        ) {\n            path.beginPath(ctx);\n\n            // Setting line dash before build path\n            if (lineDash && !ctxLineDash) {\n                path.setLineDash(lineDash);\n                path.setLineDashOffset(lineDashOffset);\n            }\n\n            this.buildPath(path, this.shape, false);\n\n            // Clear path dirty flag\n            if (this.path) {\n                this.__dirtyPath = false;\n            }\n        }\n        else {\n            // Replay path building\n            ctx.beginPath();\n            this.path.rebuildPath(ctx);\n        }\n\n        if (hasFill) {\n            if (style.fillOpacity != null) {\n                var originalGlobalAlpha = ctx.globalAlpha;\n                ctx.globalAlpha = style.fillOpacity * style.opacity;\n                path.fill(ctx);\n                ctx.globalAlpha = originalGlobalAlpha;\n            }\n            else {\n                path.fill(ctx);\n            }\n        }\n\n        if (lineDash && ctxLineDash) {\n            ctx.setLineDash(lineDash);\n            ctx.lineDashOffset = lineDashOffset;\n        }\n\n        if (hasStroke) {\n            if (style.strokeOpacity != null) {\n                var originalGlobalAlpha = ctx.globalAlpha;\n                ctx.globalAlpha = style.strokeOpacity * style.opacity;\n                path.stroke(ctx);\n                ctx.globalAlpha = originalGlobalAlpha;\n            }\n            else {\n                path.stroke(ctx);\n            }\n        }\n\n        if (lineDash && ctxLineDash) {\n            // PENDING\n            // Remove lineDash\n            ctx.setLineDash([]);\n        }\n\n        // Draw rect text\n        if (style.text != null) {\n            // Only restore transform when needs draw text.\n            this.restoreTransform(ctx);\n            this.drawRectText(ctx, this.getBoundingRect());\n        }\n    },\n\n    // When bundling path, some shape may decide if use moveTo to begin a new subpath or closePath\n    // Like in circle\n    buildPath: function (ctx, shapeCfg, inBundle) {},\n\n    createPathProxy: function () {\n        this.path = new PathProxy();\n    },\n\n    getBoundingRect: function () {\n        var rect = this._rect;\n        var style = this.style;\n        var needsUpdateRect = !rect;\n        if (needsUpdateRect) {\n            var path = this.path;\n            if (!path) {\n                // Create path on demand.\n                path = this.path = new PathProxy();\n            }\n            if (this.__dirtyPath) {\n                path.beginPath();\n                this.buildPath(path, this.shape, false);\n            }\n            rect = path.getBoundingRect();\n        }\n        this._rect = rect;\n\n        if (style.hasStroke()) {\n            // Needs update rect with stroke lineWidth when\n            // 1. Element changes scale or lineWidth\n            // 2. Shape is changed\n            var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone());\n            if (this.__dirty || needsUpdateRect) {\n                rectWithStroke.copy(rect);\n                // FIXME Must after updateTransform\n                var w = style.lineWidth;\n                // PENDING, Min line width is needed when line is horizontal or vertical\n                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;\n\n                // Only add extra hover lineWidth when there are no fill\n                if (!style.hasFill()) {\n                    w = Math.max(w, this.strokeContainThreshold || 4);\n                }\n                // Consider line width\n                // Line scale can't be 0;\n                if (lineScale > 1e-10) {\n                    rectWithStroke.width += w / lineScale;\n                    rectWithStroke.height += w / lineScale;\n                    rectWithStroke.x -= w / lineScale / 2;\n                    rectWithStroke.y -= w / lineScale / 2;\n                }\n            }\n\n            // Return rect with stroke\n            return rectWithStroke;\n        }\n\n        return rect;\n    },\n\n    contain: function (x, y) {\n        var localPos = this.transformCoordToLocal(x, y);\n        var rect = this.getBoundingRect();\n        var style = this.style;\n        x = localPos[0];\n        y = localPos[1];\n\n        if (rect.contain(x, y)) {\n            var pathData = this.path.data;\n            if (style.hasStroke()) {\n                var lineWidth = style.lineWidth;\n                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;\n                // Line scale can't be 0;\n                if (lineScale > 1e-10) {\n                    // Only add extra hover lineWidth when there are no fill\n                    if (!style.hasFill()) {\n                        lineWidth = Math.max(lineWidth, this.strokeContainThreshold);\n                    }\n                    if (containStroke(\n                        pathData, lineWidth / lineScale, x, y\n                    )) {\n                        return true;\n                    }\n                }\n            }\n            if (style.hasFill()) {\n                return contain(pathData, x, y);\n            }\n        }\n        return false;\n    },\n\n    /**\n     * @param  {boolean} dirtyPath\n     */\n    dirty: function (dirtyPath) {\n        if (dirtyPath == null) {\n            dirtyPath = true;\n        }\n        // Only mark dirty, not mark clean\n        if (dirtyPath) {\n            this.__dirtyPath = dirtyPath;\n            this._rect = null;\n        }\n\n        this.__dirty = this.__dirtyText = true;\n\n        this.__zr && this.__zr.refresh();\n\n        // Used as a clipping path\n        if (this.__clipTarget) {\n            this.__clipTarget.dirty();\n        }\n    },\n\n    /**\n     * Alias for animate('shape')\n     * @param {boolean} loop\n     */\n    animateShape: function (loop) {\n        return this.animate('shape', loop);\n    },\n\n    // Overwrite attrKV\n    attrKV: function (key, value) {\n        // FIXME\n        if (key === 'shape') {\n            this.setShape(value);\n            this.__dirtyPath = true;\n            this._rect = null;\n        }\n        else {\n            Displayable.prototype.attrKV.call(this, key, value);\n        }\n    },\n\n    /**\n     * @param {Object|string} key\n     * @param {*} value\n     */\n    setShape: function (key, value) {\n        var shape = this.shape;\n        // Path from string may not have shape\n        if (shape) {\n            if (isObject$1(key)) {\n                for (var name in key) {\n                    if (key.hasOwnProperty(name)) {\n                        shape[name] = key[name];\n                    }\n                }\n            }\n            else {\n                shape[key] = value;\n            }\n            this.dirty(true);\n        }\n        return this;\n    },\n\n    getLineScale: function () {\n        var m = this.transform;\n        // Get the line scale.\n        // Determinant of `m` means how much the area is enlarged by the\n        // transformation. So its square root can be used as a scale factor\n        // for width.\n        return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10\n            ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1]))\n            : 1;\n    }\n};\n\n/**\n * 扩展一个 Path element, 比如星形，圆等。\n * Extend a path element\n * @param {Object} props\n * @param {string} props.type Path type\n * @param {Function} props.init Initialize\n * @param {Function} props.buildPath Overwrite buildPath method\n * @param {Object} [props.style] Extended default style config\n * @param {Object} [props.shape] Extended default shape config\n */\nPath.extend = function (defaults$$1) {\n    var Sub = function (opts) {\n        Path.call(this, opts);\n\n        if (defaults$$1.style) {\n            // Extend default style\n            this.style.extendFrom(defaults$$1.style, false);\n        }\n\n        // Extend default shape\n        var defaultShape = defaults$$1.shape;\n        if (defaultShape) {\n            this.shape = this.shape || {};\n            var thisShape = this.shape;\n            for (var name in defaultShape) {\n                if (\n                    !thisShape.hasOwnProperty(name)\n                    && defaultShape.hasOwnProperty(name)\n                ) {\n                    thisShape[name] = defaultShape[name];\n                }\n            }\n        }\n\n        defaults$$1.init && defaults$$1.init.call(this, opts);\n    };\n\n    inherits(Sub, Path);\n\n    // FIXME 不能 extend position, rotation 等引用对象\n    for (var name in defaults$$1) {\n        // Extending prototype values and methods\n        if (name !== 'style' && name !== 'shape') {\n            Sub.prototype[name] = defaults$$1[name];\n        }\n    }\n\n    return Sub;\n};\n\ninherits(Path, Displayable);\n\nvar CMD$2 = PathProxy.CMD;\n\nvar points = [[], [], []];\nvar mathSqrt$3 = Math.sqrt;\nvar mathAtan2 = Math.atan2;\n\nvar transformPath = function (path, m) {\n    var data = path.data;\n    var cmd;\n    var nPoint;\n    var i;\n    var j;\n    var k;\n    var p;\n\n    var M = CMD$2.M;\n    var C = CMD$2.C;\n    var L = CMD$2.L;\n    var R = CMD$2.R;\n    var A = CMD$2.A;\n    var Q = CMD$2.Q;\n\n    for (i = 0, j = 0; i < data.length;) {\n        cmd = data[i++];\n        j = i;\n        nPoint = 0;\n\n        switch (cmd) {\n            case M:\n                nPoint = 1;\n                break;\n            case L:\n                nPoint = 1;\n                break;\n            case C:\n                nPoint = 3;\n                break;\n            case Q:\n                nPoint = 2;\n                break;\n            case A:\n                var x = m[4];\n                var y = m[5];\n                var sx = mathSqrt$3(m[0] * m[0] + m[1] * m[1]);\n                var sy = mathSqrt$3(m[2] * m[2] + m[3] * m[3]);\n                var angle = mathAtan2(-m[1] / sy, m[0] / sx);\n                // cx\n                data[i] *= sx;\n                data[i++] += x;\n                // cy\n                data[i] *= sy;\n                data[i++] += y;\n                // Scale rx and ry\n                // FIXME Assume psi is 0 here\n                data[i++] *= sx;\n                data[i++] *= sy;\n\n                // Start angle\n                data[i++] += angle;\n                // end angle\n                data[i++] += angle;\n                // FIXME psi\n                i += 2;\n                j = i;\n                break;\n            case R:\n                // x0, y0\n                p[0] = data[i++];\n                p[1] = data[i++];\n                applyTransform(p, p, m);\n                data[j++] = p[0];\n                data[j++] = p[1];\n                // x1, y1\n                p[0] += data[i++];\n                p[1] += data[i++];\n                applyTransform(p, p, m);\n                data[j++] = p[0];\n                data[j++] = p[1];\n        }\n\n        for (k = 0; k < nPoint; k++) {\n            var p = points[k];\n            p[0] = data[i++];\n            p[1] = data[i++];\n\n            applyTransform(p, p, m);\n            // Write back\n            data[j++] = p[0];\n            data[j++] = p[1];\n        }\n    }\n};\n\n// command chars\n// var cc = [\n//     'm', 'M', 'l', 'L', 'v', 'V', 'h', 'H', 'z', 'Z',\n//     'c', 'C', 'q', 'Q', 't', 'T', 's', 'S', 'a', 'A'\n// ];\n\nvar mathSqrt = Math.sqrt;\nvar mathSin = Math.sin;\nvar mathCos = Math.cos;\nvar PI = Math.PI;\n\nvar vMag = function (v) {\n    return Math.sqrt(v[0] * v[0] + v[1] * v[1]);\n};\nvar vRatio = function (u, v) {\n    return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));\n};\nvar vAngle = function (u, v) {\n    return (u[0] * v[1] < u[1] * v[0] ? -1 : 1)\n            * Math.acos(vRatio(u, v));\n};\n\nfunction processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) {\n    var psi = psiDeg * (PI / 180.0);\n    var xp = mathCos(psi) * (x1 - x2) / 2.0\n                + mathSin(psi) * (y1 - y2) / 2.0;\n    var yp = -1 * mathSin(psi) * (x1 - x2) / 2.0\n                + mathCos(psi) * (y1 - y2) / 2.0;\n\n    var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);\n\n    if (lambda > 1) {\n        rx *= mathSqrt(lambda);\n        ry *= mathSqrt(lambda);\n    }\n\n    var f = (fa === fs ? -1 : 1)\n        * mathSqrt((((rx * rx) * (ry * ry))\n                - ((rx * rx) * (yp * yp))\n                - ((ry * ry) * (xp * xp))) / ((rx * rx) * (yp * yp)\n                + (ry * ry) * (xp * xp))\n            ) || 0;\n\n    var cxp = f * rx * yp / ry;\n    var cyp = f * -ry * xp / rx;\n\n    var cx = (x1 + x2) / 2.0\n                + mathCos(psi) * cxp\n                - mathSin(psi) * cyp;\n    var cy = (y1 + y2) / 2.0\n            + mathSin(psi) * cxp\n            + mathCos(psi) * cyp;\n\n    var theta = vAngle([ 1, 0 ], [ (xp - cxp) / rx, (yp - cyp) / ry ]);\n    var u = [ (xp - cxp) / rx, (yp - cyp) / ry ];\n    var v = [ (-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry ];\n    var dTheta = vAngle(u, v);\n\n    if (vRatio(u, v) <= -1) {\n        dTheta = PI;\n    }\n    if (vRatio(u, v) >= 1) {\n        dTheta = 0;\n    }\n    if (fs === 0 && dTheta > 0) {\n        dTheta = dTheta - 2 * PI;\n    }\n    if (fs === 1 && dTheta < 0) {\n        dTheta = dTheta + 2 * PI;\n    }\n\n    path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs);\n}\n\n\nvar commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig;\n// Consider case:\n// (1) delimiter can be comma or space, where continuous commas\n// or spaces should be seen as one comma.\n// (2) value can be like:\n// '2e-4', 'l.5.9' (ignore 0), 'M-10-10', 'l-2.43e-1,34.9983',\n// 'l-.5E1,54', '121-23-44-11' (no delimiter)\nvar numberReg = /-?([0-9]*\\.)?[0-9]+([eE]-?[0-9]+)?/g;\n// var valueSplitReg = /[\\s,]+/;\n\nfunction createPathProxyFromString(data) {\n    if (!data) {\n        return new PathProxy();\n    }\n\n    // var data = data.replace(/-/g, ' -')\n    //     .replace(/  /g, ' ')\n    //     .replace(/ /g, ',')\n    //     .replace(/,,/g, ',');\n\n    // var n;\n    // create pipes so that we can split the data\n    // for (n = 0; n < cc.length; n++) {\n    //     cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]);\n    // }\n\n    // data = data.replace(/-/g, ',-');\n\n    // create array\n    // var arr = cs.split('|');\n    // init context point\n    var cpx = 0;\n    var cpy = 0;\n    var subpathX = cpx;\n    var subpathY = cpy;\n    var prevCmd;\n\n    var path = new PathProxy();\n    var CMD = PathProxy.CMD;\n\n    // commandReg.lastIndex = 0;\n    // var cmdResult;\n    // while ((cmdResult = commandReg.exec(data)) != null) {\n    //     var cmdStr = cmdResult[1];\n    //     var cmdContent = cmdResult[2];\n\n    var cmdList = data.match(commandReg);\n    for (var l = 0; l < cmdList.length; l++) {\n        var cmdText = cmdList[l];\n        var cmdStr = cmdText.charAt(0);\n\n        var cmd;\n\n        // String#split is faster a little bit than String#replace or RegExp#exec.\n        // var p = cmdContent.split(valueSplitReg);\n        // var pLen = 0;\n        // for (var i = 0; i < p.length; i++) {\n        //     // '' and other invalid str => NaN\n        //     var val = parseFloat(p[i]);\n        //     !isNaN(val) && (p[pLen++] = val);\n        // }\n\n        var p = cmdText.match(numberReg) || [];\n        var pLen = p.length;\n        for (var i = 0; i < pLen; i++) {\n            p[i] = parseFloat(p[i]);\n        }\n\n        var off = 0;\n        while (off < pLen) {\n            var ctlPtx;\n            var ctlPty;\n\n            var rx;\n            var ry;\n            var psi;\n            var fa;\n            var fs;\n\n            var x1 = cpx;\n            var y1 = cpy;\n\n            // convert l, H, h, V, and v to L\n            switch (cmdStr) {\n                case 'l':\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'L':\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'm':\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.M;\n                    path.addData(cmd, cpx, cpy);\n                    subpathX = cpx;\n                    subpathY = cpy;\n                    cmdStr = 'l';\n                    break;\n                case 'M':\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.M;\n                    path.addData(cmd, cpx, cpy);\n                    subpathX = cpx;\n                    subpathY = cpy;\n                    cmdStr = 'L';\n                    break;\n                case 'h':\n                    cpx += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'H':\n                    cpx = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'v':\n                    cpy += p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'V':\n                    cpy = p[off++];\n                    cmd = CMD.L;\n                    path.addData(cmd, cpx, cpy);\n                    break;\n                case 'C':\n                    cmd = CMD.C;\n                    path.addData(\n                        cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]\n                    );\n                    cpx = p[off - 2];\n                    cpy = p[off - 1];\n                    break;\n                case 'c':\n                    cmd = CMD.C;\n                    path.addData(\n                        cmd,\n                        p[off++] + cpx, p[off++] + cpy,\n                        p[off++] + cpx, p[off++] + cpy,\n                        p[off++] + cpx, p[off++] + cpy\n                    );\n                    cpx += p[off - 2];\n                    cpy += p[off - 1];\n                    break;\n                case 'S':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.C) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cmd = CMD.C;\n                    x1 = p[off++];\n                    y1 = p[off++];\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);\n                    break;\n                case 's':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.C) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cmd = CMD.C;\n                    x1 = cpx + p[off++];\n                    y1 = cpy + p[off++];\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);\n                    break;\n                case 'Q':\n                    x1 = p[off++];\n                    y1 = p[off++];\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, x1, y1, cpx, cpy);\n                    break;\n                case 'q':\n                    x1 = p[off++] + cpx;\n                    y1 = p[off++] + cpy;\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, x1, y1, cpx, cpy);\n                    break;\n                case 'T':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.Q) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);\n                    break;\n                case 't':\n                    ctlPtx = cpx;\n                    ctlPty = cpy;\n                    var len = path.len();\n                    var pathData = path.data;\n                    if (prevCmd === CMD.Q) {\n                        ctlPtx += cpx - pathData[len - 4];\n                        ctlPty += cpy - pathData[len - 3];\n                    }\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.Q;\n                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);\n                    break;\n                case 'A':\n                    rx = p[off++];\n                    ry = p[off++];\n                    psi = p[off++];\n                    fa = p[off++];\n                    fs = p[off++];\n\n                    x1 = cpx, y1 = cpy;\n                    cpx = p[off++];\n                    cpy = p[off++];\n                    cmd = CMD.A;\n                    processArc(\n                        x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path\n                    );\n                    break;\n                case 'a':\n                    rx = p[off++];\n                    ry = p[off++];\n                    psi = p[off++];\n                    fa = p[off++];\n                    fs = p[off++];\n\n                    x1 = cpx, y1 = cpy;\n                    cpx += p[off++];\n                    cpy += p[off++];\n                    cmd = CMD.A;\n                    processArc(\n                        x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path\n                    );\n                    break;\n            }\n        }\n\n        if (cmdStr === 'z' || cmdStr === 'Z') {\n            cmd = CMD.Z;\n            path.addData(cmd);\n            // z may be in the middle of the path.\n            cpx = subpathX;\n            cpy = subpathY;\n        }\n\n        prevCmd = cmd;\n    }\n\n    path.toStatic();\n\n    return path;\n}\n\n// TODO Optimize double memory cost problem\nfunction createPathOptions(str, opts) {\n    var pathProxy = createPathProxyFromString(str);\n    opts = opts || {};\n    opts.buildPath = function (path) {\n        if (path.setData) {\n            path.setData(pathProxy.data);\n            // Svg and vml renderer don't have context\n            var ctx = path.getContext();\n            if (ctx) {\n                path.rebuildPath(ctx);\n            }\n        }\n        else {\n            var ctx = path;\n            pathProxy.rebuildPath(ctx);\n        }\n    };\n\n    opts.applyTransform = function (m) {\n        transformPath(pathProxy, m);\n        this.dirty(true);\n    };\n\n    return opts;\n}\n\n/**\n * Create a Path object from path string data\n * http://www.w3.org/TR/SVG/paths.html#PathData\n * @param  {Object} opts Other options\n */\nfunction createFromString(str, opts) {\n    return new Path(createPathOptions(str, opts));\n}\n\n/**\n * Create a Path class from path string data\n * @param  {string} str\n * @param  {Object} opts Other options\n */\nfunction extendFromString(str, opts) {\n    return Path.extend(createPathOptions(str, opts));\n}\n\n/**\n * Merge multiple paths\n */\n// TODO Apply transform\n// TODO stroke dash\n// TODO Optimize double memory cost problem\nfunction mergePath$1(pathEls, opts) {\n    var pathList = [];\n    var len = pathEls.length;\n    for (var i = 0; i < len; i++) {\n        var pathEl = pathEls[i];\n        if (!pathEl.path) {\n            pathEl.createPathProxy();\n        }\n        if (pathEl.__dirtyPath) {\n            pathEl.buildPath(pathEl.path, pathEl.shape, true);\n        }\n        pathList.push(pathEl.path);\n    }\n\n    var pathBundle = new Path(opts);\n    // Need path proxy.\n    pathBundle.createPathProxy();\n    pathBundle.buildPath = function (path) {\n        path.appendPath(pathList);\n        // Svg and vml renderer don't have context\n        var ctx = path.getContext();\n        if (ctx) {\n            path.rebuildPath(ctx);\n        }\n    };\n\n    return pathBundle;\n}\n\n/**\n * @alias zrender/graphic/Text\n * @extends module:zrender/graphic/Displayable\n * @constructor\n * @param {Object} opts\n */\nvar Text = function (opts) { // jshint ignore:line\n    Displayable.call(this, opts);\n};\n\nText.prototype = {\n\n    constructor: Text,\n\n    type: 'text',\n\n    brush: function (ctx, prevEl) {\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        // Use props with prefix 'text'.\n        style.fill = style.stroke = style.shadowBlur = style.shadowColor =\n            style.shadowOffsetX = style.shadowOffsetY = null;\n\n        var text = style.text;\n        // Convert to string\n        text != null && (text += '');\n\n        // Do not apply style.bind in Text node. Because the real bind job\n        // is in textHelper.renderText, and performance of text render should\n        // be considered.\n        // style.bind(ctx, this, prevEl);\n\n        if (!needDrawText(text, style)) {\n            // The current el.style is not applied\n            // and should not be used as cache.\n            ctx.__attrCachedBy = ContextCachedBy.NONE;\n            return;\n        }\n\n        this.setTransform(ctx);\n\n        renderText(this, ctx, text, style, null, prevEl);\n\n        this.restoreTransform(ctx);\n    },\n\n    getBoundingRect: function () {\n        var style = this.style;\n\n        // Optimize, avoid normalize every time.\n        this.__dirty && normalizeTextStyle(style, true);\n\n        if (!this._rect) {\n            var text = style.text;\n            text != null ? (text += '') : (text = '');\n\n            var rect = getBoundingRect(\n                style.text + '',\n                style.font,\n                style.textAlign,\n                style.textVerticalAlign,\n                style.textPadding,\n                style.textLineHeight,\n                style.rich\n            );\n\n            rect.x += style.x || 0;\n            rect.y += style.y || 0;\n\n            if (getStroke(style.textStroke, style.textStrokeWidth)) {\n                var w = style.textStrokeWidth;\n                rect.x -= w / 2;\n                rect.y -= w / 2;\n                rect.width += w;\n                rect.height += w;\n            }\n\n            this._rect = rect;\n        }\n\n        return this._rect;\n    }\n};\n\ninherits(Text, Displayable);\n\n/**\n * 圆形\n * @module zrender/shape/Circle\n */\n\nvar Circle = Path.extend({\n\n    type: 'circle',\n\n    shape: {\n        cx: 0,\n        cy: 0,\n        r: 0\n    },\n\n\n    buildPath: function (ctx, shape, inBundle) {\n        // Better stroking in ShapeBundle\n        // Always do it may have performence issue ( fill may be 2x more cost)\n        if (inBundle) {\n            ctx.moveTo(shape.cx + shape.r, shape.cy);\n        }\n        // else {\n        //     if (ctx.allocate && !ctx.data.length) {\n        //         ctx.allocate(ctx.CMD_MEM_SIZE.A);\n        //     }\n        // }\n        // Better stroking in ShapeBundle\n        // ctx.moveTo(shape.cx + shape.r, shape.cy);\n        ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true);\n    }\n});\n\n// Fix weird bug in some version of IE11 (like 11.0.9600.178**),\n// where exception \"unexpected call to method or property access\"\n// might be thrown when calling ctx.fill or ctx.stroke after a path\n// whose area size is zero is drawn and ctx.clip() is called and\n// shadowBlur is set. See #4572, #3112, #5777.\n// (e.g.,\n//  ctx.moveTo(10, 10);\n//  ctx.lineTo(20, 10);\n//  ctx.closePath();\n//  ctx.clip();\n//  ctx.shadowBlur = 10;\n//  ...\n//  ctx.fill();\n// )\n\nvar shadowTemp = [\n    ['shadowBlur', 0],\n    ['shadowColor', '#000'],\n    ['shadowOffsetX', 0],\n    ['shadowOffsetY', 0]\n];\n\nvar fixClipWithShadow = function (orignalBrush) {\n\n    // version string can be: '11.0'\n    return (env$1.browser.ie && env$1.browser.version >= 11)\n\n        ? function () {\n            var clipPaths = this.__clipPaths;\n            var style = this.style;\n            var modified;\n\n            if (clipPaths) {\n                for (var i = 0; i < clipPaths.length; i++) {\n                    var clipPath = clipPaths[i];\n                    var shape = clipPath && clipPath.shape;\n                    var type = clipPath && clipPath.type;\n\n                    if (shape && (\n                        (type === 'sector' && shape.startAngle === shape.endAngle)\n                        || (type === 'rect' && (!shape.width || !shape.height))\n                    )) {\n                        for (var j = 0; j < shadowTemp.length; j++) {\n                            // It is save to put shadowTemp static, because shadowTemp\n                            // will be all modified each item brush called.\n                            shadowTemp[j][2] = style[shadowTemp[j][0]];\n                            style[shadowTemp[j][0]] = shadowTemp[j][1];\n                        }\n                        modified = true;\n                        break;\n                    }\n                }\n            }\n\n            orignalBrush.apply(this, arguments);\n\n            if (modified) {\n                for (var j = 0; j < shadowTemp.length; j++) {\n                    style[shadowTemp[j][0]] = shadowTemp[j][2];\n                }\n            }\n        }\n\n        : orignalBrush;\n};\n\n/**\n * 扇形\n * @module zrender/graphic/shape/Sector\n */\n\nvar Sector = Path.extend({\n\n    type: 'sector',\n\n    shape: {\n\n        cx: 0,\n\n        cy: 0,\n\n        r0: 0,\n\n        r: 0,\n\n        startAngle: 0,\n\n        endAngle: Math.PI * 2,\n\n        clockwise: true\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n\n        var x = shape.cx;\n        var y = shape.cy;\n        var r0 = Math.max(shape.r0 || 0, 0);\n        var r = Math.max(shape.r, 0);\n        var startAngle = shape.startAngle;\n        var endAngle = shape.endAngle;\n        var clockwise = shape.clockwise;\n\n        var unitX = Math.cos(startAngle);\n        var unitY = Math.sin(startAngle);\n\n        ctx.moveTo(unitX * r0 + x, unitY * r0 + y);\n\n        ctx.lineTo(unitX * r + x, unitY * r + y);\n\n        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);\n\n        ctx.lineTo(\n            Math.cos(endAngle) * r0 + x,\n            Math.sin(endAngle) * r0 + y\n        );\n\n        if (r0 !== 0) {\n            ctx.arc(x, y, r0, endAngle, startAngle, clockwise);\n        }\n\n        ctx.closePath();\n    }\n});\n\n/**\n * 圆环\n * @module zrender/graphic/shape/Ring\n */\n\nvar Ring = Path.extend({\n\n    type: 'ring',\n\n    shape: {\n        cx: 0,\n        cy: 0,\n        r: 0,\n        r0: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var x = shape.cx;\n        var y = shape.cy;\n        var PI2 = Math.PI * 2;\n        ctx.moveTo(x + shape.r, y);\n        ctx.arc(x, y, shape.r, 0, PI2, false);\n        ctx.moveTo(x + shape.r0, y);\n        ctx.arc(x, y, shape.r0, 0, PI2, true);\n    }\n});\n\n/**\n * Catmull-Rom spline 插值折线\n * @module zrender/shape/util/smoothSpline\n * @author pissang (https://www.github.com/pissang)\n *         Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         errorrik (errorrik@gmail.com)\n */\n\n/**\n * @inner\n */\nfunction interpolate(p0, p1, p2, p3, t, t2, t3) {\n    var v0 = (p2 - p0) * 0.5;\n    var v1 = (p3 - p1) * 0.5;\n    return (2 * (p1 - p2) + v0 + v1) * t3\n            + (-3 * (p1 - p2) - 2 * v0 - v1) * t2\n            + v0 * t + p1;\n}\n\n/**\n * @alias module:zrender/shape/util/smoothSpline\n * @param {Array} points 线段顶点数组\n * @param {boolean} isLoop\n * @return {Array}\n */\nvar smoothSpline = function (points, isLoop) {\n    var len$$1 = points.length;\n    var ret = [];\n\n    var distance$$1 = 0;\n    for (var i = 1; i < len$$1; i++) {\n        distance$$1 += distance(points[i - 1], points[i]);\n    }\n\n    var segs = distance$$1 / 2;\n    segs = segs < len$$1 ? len$$1 : segs;\n    for (var i = 0; i < segs; i++) {\n        var pos = i / (segs - 1) * (isLoop ? len$$1 : len$$1 - 1);\n        var idx = Math.floor(pos);\n\n        var w = pos - idx;\n\n        var p0;\n        var p1 = points[idx % len$$1];\n        var p2;\n        var p3;\n        if (!isLoop) {\n            p0 = points[idx === 0 ? idx : idx - 1];\n            p2 = points[idx > len$$1 - 2 ? len$$1 - 1 : idx + 1];\n            p3 = points[idx > len$$1 - 3 ? len$$1 - 1 : idx + 2];\n        }\n        else {\n            p0 = points[(idx - 1 + len$$1) % len$$1];\n            p2 = points[(idx + 1) % len$$1];\n            p3 = points[(idx + 2) % len$$1];\n        }\n\n        var w2 = w * w;\n        var w3 = w * w2;\n\n        ret.push([\n            interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3),\n            interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3)\n        ]);\n    }\n    return ret;\n};\n\n/**\n * 贝塞尔平滑曲线\n * @module zrender/shape/util/smoothBezier\n * @author pissang (https://www.github.com/pissang)\n *         Kener (@Kener-林峰, kener.linfeng@gmail.com)\n *         errorrik (errorrik@gmail.com)\n */\n\n/**\n * 贝塞尔平滑曲线\n * @alias module:zrender/shape/util/smoothBezier\n * @param {Array} points 线段顶点数组\n * @param {number} smooth 平滑等级, 0-1\n * @param {boolean} isLoop\n * @param {Array} constraint 将计算出来的控制点约束在一个包围盒内\n *                           比如 [[0, 0], [100, 100]], 这个包围盒会与\n *                           整个折线的包围盒做一个并集用来约束控制点。\n * @param {Array} 计算出来的控制点数组\n */\nvar smoothBezier = function (points, smooth, isLoop, constraint) {\n    var cps = [];\n\n    var v = [];\n    var v1 = [];\n    var v2 = [];\n    var prevPoint;\n    var nextPoint;\n\n    var min$$1;\n    var max$$1;\n    if (constraint) {\n        min$$1 = [Infinity, Infinity];\n        max$$1 = [-Infinity, -Infinity];\n        for (var i = 0, len$$1 = points.length; i < len$$1; i++) {\n            min(min$$1, min$$1, points[i]);\n            max(max$$1, max$$1, points[i]);\n        }\n        // 与指定的包围盒做并集\n        min(min$$1, min$$1, constraint[0]);\n        max(max$$1, max$$1, constraint[1]);\n    }\n\n    for (var i = 0, len$$1 = points.length; i < len$$1; i++) {\n        var point = points[i];\n\n        if (isLoop) {\n            prevPoint = points[i ? i - 1 : len$$1 - 1];\n            nextPoint = points[(i + 1) % len$$1];\n        }\n        else {\n            if (i === 0 || i === len$$1 - 1) {\n                cps.push(clone$1(points[i]));\n                continue;\n            }\n            else {\n                prevPoint = points[i - 1];\n                nextPoint = points[i + 1];\n            }\n        }\n\n        sub(v, nextPoint, prevPoint);\n\n        // use degree to scale the handle length\n        scale(v, v, smooth);\n\n        var d0 = distance(point, prevPoint);\n        var d1 = distance(point, nextPoint);\n        var sum = d0 + d1;\n        if (sum !== 0) {\n            d0 /= sum;\n            d1 /= sum;\n        }\n\n        scale(v1, v, -d0);\n        scale(v2, v, d1);\n        var cp0 = add([], point, v1);\n        var cp1 = add([], point, v2);\n        if (constraint) {\n            max(cp0, cp0, min$$1);\n            min(cp0, cp0, max$$1);\n            max(cp1, cp1, min$$1);\n            min(cp1, cp1, max$$1);\n        }\n        cps.push(cp0);\n        cps.push(cp1);\n    }\n\n    if (isLoop) {\n        cps.push(cps.shift());\n    }\n\n    return cps;\n};\n\nfunction buildPath$1(ctx, shape, closePath) {\n    var points = shape.points;\n    var smooth = shape.smooth;\n    if (points && points.length >= 2) {\n        if (smooth && smooth !== 'spline') {\n            var controlPoints = smoothBezier(\n                points, smooth, closePath, shape.smoothConstraint\n            );\n\n            ctx.moveTo(points[0][0], points[0][1]);\n            var len = points.length;\n            for (var i = 0; i < (closePath ? len : len - 1); i++) {\n                var cp1 = controlPoints[i * 2];\n                var cp2 = controlPoints[i * 2 + 1];\n                var p = points[(i + 1) % len];\n                ctx.bezierCurveTo(\n                    cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]\n                );\n            }\n        }\n        else {\n            if (smooth === 'spline') {\n                points = smoothSpline(points, closePath);\n            }\n\n            ctx.moveTo(points[0][0], points[0][1]);\n            for (var i = 1, l = points.length; i < l; i++) {\n                ctx.lineTo(points[i][0], points[i][1]);\n            }\n        }\n\n        closePath && ctx.closePath();\n    }\n}\n\n/**\n * 多边形\n * @module zrender/shape/Polygon\n */\n\nvar Polygon = Path.extend({\n\n    type: 'polygon',\n\n    shape: {\n        points: null,\n\n        smooth: false,\n\n        smoothConstraint: null\n    },\n\n    buildPath: function (ctx, shape) {\n        buildPath$1(ctx, shape, true);\n    }\n});\n\n/**\n * @module zrender/graphic/shape/Polyline\n */\n\nvar Polyline = Path.extend({\n\n    type: 'polyline',\n\n    shape: {\n        points: null,\n\n        smooth: false,\n\n        smoothConstraint: null\n    },\n\n    style: {\n        stroke: '#000',\n\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        buildPath$1(ctx, shape, false);\n    }\n});\n\n/**\n * Sub-pixel optimize for canvas rendering, prevent from blur\n * when rendering a thin vertical/horizontal line.\n */\n\nvar round$1 = Math.round;\n\n/**\n * Sub pixel optimize line for canvas\n *\n * @param {Object} outputShape The modification will be performed on `outputShape`.\n *                 `outputShape` and `inputShape` can be the same object.\n *                 `outputShape` object can be used repeatly, because all of\n *                 the `x1`, `x2`, `y1`, `y2` will be assigned in this method.\n * @param {Object} [inputShape]\n * @param {number} [inputShape.x1]\n * @param {number} [inputShape.y1]\n * @param {number} [inputShape.x2]\n * @param {number} [inputShape.y2]\n * @param {Object} [style]\n * @param {number} [style.lineWidth]\n */\nfunction subPixelOptimizeLine$1(outputShape, inputShape, style) {\n    var lineWidth = style && style.lineWidth;\n\n    if (!inputShape || !lineWidth) {\n        return;\n    }\n\n    var x1 = inputShape.x1;\n    var x2 = inputShape.x2;\n    var y1 = inputShape.y1;\n    var y2 = inputShape.y2;\n\n    if (round$1(x1 * 2) === round$1(x2 * 2)) {\n        outputShape.x1 = outputShape.x2 = subPixelOptimize$1(x1, lineWidth, true);\n    }\n    else {\n        outputShape.x1 = x1;\n        outputShape.x2 = x2;\n    }\n    if (round$1(y1 * 2) === round$1(y2 * 2)) {\n        outputShape.y1 = outputShape.y2 = subPixelOptimize$1(y1, lineWidth, true);\n    }\n    else {\n        outputShape.y1 = y1;\n        outputShape.y2 = y2;\n    }\n}\n\n/**\n * Sub pixel optimize rect for canvas\n *\n * @param {Object} outputShape The modification will be performed on `outputShape`.\n *                 `outputShape` and `inputShape` can be the same object.\n *                 `outputShape` object can be used repeatly, because all of\n *                 the `x`, `y`, `width`, `height` will be assigned in this method.\n * @param {Object} [inputShape]\n * @param {number} [inputShape.x]\n * @param {number} [inputShape.y]\n * @param {number} [inputShape.width]\n * @param {number} [inputShape.height]\n * @param {Object} [style]\n * @param {number} [style.lineWidth]\n */\nfunction subPixelOptimizeRect$1(outputShape, inputShape, style) {\n    var lineWidth = style && style.lineWidth;\n\n    if (!inputShape || !lineWidth) {\n        return;\n    }\n\n    var originX = inputShape.x;\n    var originY = inputShape.y;\n    var originWidth = inputShape.width;\n    var originHeight = inputShape.height;\n\n    outputShape.x = subPixelOptimize$1(originX, lineWidth, true);\n    outputShape.y = subPixelOptimize$1(originY, lineWidth, true);\n    outputShape.width = Math.max(\n        subPixelOptimize$1(originX + originWidth, lineWidth, false) - outputShape.x,\n        originWidth === 0 ? 0 : 1\n    );\n    outputShape.height = Math.max(\n        subPixelOptimize$1(originY + originHeight, lineWidth, false) - outputShape.y,\n        originHeight === 0 ? 0 : 1\n    );\n}\n\n/**\n * Sub pixel optimize for canvas\n *\n * @param {number} position Coordinate, such as x, y\n * @param {number} lineWidth Should be nonnegative integer.\n * @param {boolean=} positiveOrNegative Default false (negative).\n * @return {number} Optimized position.\n */\nfunction subPixelOptimize$1(position, lineWidth, positiveOrNegative) {\n    // Assure that (position + lineWidth / 2) is near integer edge,\n    // otherwise line will be fuzzy in canvas.\n    var doubledPosition = round$1(position * 2);\n    return (doubledPosition + round$1(lineWidth)) % 2 === 0\n        ? doubledPosition / 2\n        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;\n}\n\n/**\n * 矩形\n * @module zrender/graphic/shape/Rect\n */\n\n// Avoid create repeatly.\nvar subPixelOptimizeOutputShape = {};\n\nvar Rect = Path.extend({\n\n    type: 'rect',\n\n    shape: {\n        // 左上、右上、右下、左下角的半径依次为r1、r2、r3、r4\n        // r缩写为1         相当于 [1, 1, 1, 1]\n        // r缩写为[1]       相当于 [1, 1, 1, 1]\n        // r缩写为[1, 2]    相当于 [1, 2, 1, 2]\n        // r缩写为[1, 2, 3] 相当于 [1, 2, 3, 2]\n        r: 0,\n\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var x;\n        var y;\n        var width;\n        var height;\n\n        if (this.subPixelOptimize) {\n            subPixelOptimizeRect$1(subPixelOptimizeOutputShape, shape, this.style);\n            x = subPixelOptimizeOutputShape.x;\n            y = subPixelOptimizeOutputShape.y;\n            width = subPixelOptimizeOutputShape.width;\n            height = subPixelOptimizeOutputShape.height;\n            subPixelOptimizeOutputShape.r = shape.r;\n            shape = subPixelOptimizeOutputShape;\n        }\n        else {\n            x = shape.x;\n            y = shape.y;\n            width = shape.width;\n            height = shape.height;\n        }\n\n        if (!shape.r) {\n            ctx.rect(x, y, width, height);\n        }\n        else {\n            buildPath(ctx, shape);\n        }\n        ctx.closePath();\n        return;\n    }\n});\n\n/**\n * 直线\n * @module zrender/graphic/shape/Line\n */\n\n// Avoid create repeatly.\nvar subPixelOptimizeOutputShape$1 = {};\n\nvar Line = Path.extend({\n\n    type: 'line',\n\n    shape: {\n        // Start point\n        x1: 0,\n        y1: 0,\n        // End point\n        x2: 0,\n        y2: 0,\n\n        percent: 1\n    },\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        var x1;\n        var y1;\n        var x2;\n        var y2;\n\n        if (this.subPixelOptimize) {\n            subPixelOptimizeLine$1(subPixelOptimizeOutputShape$1, shape, this.style);\n            x1 = subPixelOptimizeOutputShape$1.x1;\n            y1 = subPixelOptimizeOutputShape$1.y1;\n            x2 = subPixelOptimizeOutputShape$1.x2;\n            y2 = subPixelOptimizeOutputShape$1.y2;\n        }\n        else {\n            x1 = shape.x1;\n            y1 = shape.y1;\n            x2 = shape.x2;\n            y2 = shape.y2;\n        }\n\n        var percent = shape.percent;\n\n        if (percent === 0) {\n            return;\n        }\n\n        ctx.moveTo(x1, y1);\n\n        if (percent < 1) {\n            x2 = x1 * (1 - percent) + x2 * percent;\n            y2 = y1 * (1 - percent) + y2 * percent;\n        }\n        ctx.lineTo(x2, y2);\n    },\n\n    /**\n     * Get point at percent\n     * @param  {number} percent\n     * @return {Array.<number>}\n     */\n    pointAt: function (p) {\n        var shape = this.shape;\n        return [\n            shape.x1 * (1 - p) + shape.x2 * p,\n            shape.y1 * (1 - p) + shape.y2 * p\n        ];\n    }\n});\n\n/**\n * 贝塞尔曲线\n * @module zrender/shape/BezierCurve\n */\n\nvar out = [];\n\nfunction someVectorAt(shape, t, isTangent) {\n    var cpx2 = shape.cpx2;\n    var cpy2 = shape.cpy2;\n    if (cpx2 === null || cpy2 === null) {\n        return [\n            (isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t),\n            (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t)\n        ];\n    }\n    else {\n        return [\n            (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t),\n            (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t)\n        ];\n    }\n}\n\nvar BezierCurve = Path.extend({\n\n    type: 'bezier-curve',\n\n    shape: {\n        x1: 0,\n        y1: 0,\n        x2: 0,\n        y2: 0,\n        cpx1: 0,\n        cpy1: 0,\n        // cpx2: 0,\n        // cpy2: 0\n\n        // Curve show percent, for animating\n        percent: 1\n    },\n\n    style: {\n        stroke: '#000',\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n        var x1 = shape.x1;\n        var y1 = shape.y1;\n        var x2 = shape.x2;\n        var y2 = shape.y2;\n        var cpx1 = shape.cpx1;\n        var cpy1 = shape.cpy1;\n        var cpx2 = shape.cpx2;\n        var cpy2 = shape.cpy2;\n        var percent = shape.percent;\n        if (percent === 0) {\n            return;\n        }\n\n        ctx.moveTo(x1, y1);\n\n        if (cpx2 == null || cpy2 == null) {\n            if (percent < 1) {\n                quadraticSubdivide(\n                    x1, cpx1, x2, percent, out\n                );\n                cpx1 = out[1];\n                x2 = out[2];\n                quadraticSubdivide(\n                    y1, cpy1, y2, percent, out\n                );\n                cpy1 = out[1];\n                y2 = out[2];\n            }\n\n            ctx.quadraticCurveTo(\n                cpx1, cpy1,\n                x2, y2\n            );\n        }\n        else {\n            if (percent < 1) {\n                cubicSubdivide(\n                    x1, cpx1, cpx2, x2, percent, out\n                );\n                cpx1 = out[1];\n                cpx2 = out[2];\n                x2 = out[3];\n                cubicSubdivide(\n                    y1, cpy1, cpy2, y2, percent, out\n                );\n                cpy1 = out[1];\n                cpy2 = out[2];\n                y2 = out[3];\n            }\n            ctx.bezierCurveTo(\n                cpx1, cpy1,\n                cpx2, cpy2,\n                x2, y2\n            );\n        }\n    },\n\n    /**\n     * Get point at percent\n     * @param  {number} t\n     * @return {Array.<number>}\n     */\n    pointAt: function (t) {\n        return someVectorAt(this.shape, t, false);\n    },\n\n    /**\n     * Get tangent at percent\n     * @param  {number} t\n     * @return {Array.<number>}\n     */\n    tangentAt: function (t) {\n        var p = someVectorAt(this.shape, t, true);\n        return normalize(p, p);\n    }\n});\n\n/**\n * 圆弧\n * @module zrender/graphic/shape/Arc\n */\n\nvar Arc = Path.extend({\n\n    type: 'arc',\n\n    shape: {\n\n        cx: 0,\n\n        cy: 0,\n\n        r: 0,\n\n        startAngle: 0,\n\n        endAngle: Math.PI * 2,\n\n        clockwise: true\n    },\n\n    style: {\n\n        stroke: '#000',\n\n        fill: null\n    },\n\n    buildPath: function (ctx, shape) {\n\n        var x = shape.cx;\n        var y = shape.cy;\n        var r = Math.max(shape.r, 0);\n        var startAngle = shape.startAngle;\n        var endAngle = shape.endAngle;\n        var clockwise = shape.clockwise;\n\n        var unitX = Math.cos(startAngle);\n        var unitY = Math.sin(startAngle);\n\n        ctx.moveTo(unitX * r + x, unitY * r + y);\n        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);\n    }\n});\n\n// CompoundPath to improve performance\n\nvar CompoundPath = Path.extend({\n\n    type: 'compound',\n\n    shape: {\n\n        paths: null\n    },\n\n    _updatePathDirty: function () {\n        var dirtyPath = this.__dirtyPath;\n        var paths = this.shape.paths;\n        for (var i = 0; i < paths.length; i++) {\n            // Mark as dirty if any subpath is dirty\n            dirtyPath = dirtyPath || paths[i].__dirtyPath;\n        }\n        this.__dirtyPath = dirtyPath;\n        this.__dirty = this.__dirty || dirtyPath;\n    },\n\n    beforeBrush: function () {\n        this._updatePathDirty();\n        var paths = this.shape.paths || [];\n        var scale = this.getGlobalScale();\n        // Update path scale\n        for (var i = 0; i < paths.length; i++) {\n            if (!paths[i].path) {\n                paths[i].createPathProxy();\n            }\n            paths[i].path.setScale(scale[0], scale[1]);\n        }\n    },\n\n    buildPath: function (ctx, shape) {\n        var paths = shape.paths || [];\n        for (var i = 0; i < paths.length; i++) {\n            paths[i].buildPath(ctx, paths[i].shape, true);\n        }\n    },\n\n    afterBrush: function () {\n        var paths = this.shape.paths || [];\n        for (var i = 0; i < paths.length; i++) {\n            paths[i].__dirtyPath = false;\n        }\n    },\n\n    getBoundingRect: function () {\n        this._updatePathDirty();\n        return Path.prototype.getBoundingRect.call(this);\n    }\n});\n\n/**\n * @param {Array.<Object>} colorStops\n */\nvar Gradient = function (colorStops) {\n\n    this.colorStops = colorStops || [];\n\n};\n\nGradient.prototype = {\n\n    constructor: Gradient,\n\n    addColorStop: function (offset, color) {\n        this.colorStops.push({\n\n            offset: offset,\n\n            color: color\n        });\n    }\n\n};\n\n/**\n * x, y, x2, y2 are all percent from 0 to 1\n * @param {number} [x=0]\n * @param {number} [y=0]\n * @param {number} [x2=1]\n * @param {number} [y2=0]\n * @param {Array.<Object>} colorStops\n * @param {boolean} [globalCoord=false]\n */\nvar LinearGradient = function (x, y, x2, y2, colorStops, globalCoord) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {type: 'linear', colorStops: ...}`, where\n    // this constructor will not be called.\n\n    this.x = x == null ? 0 : x;\n\n    this.y = y == null ? 0 : y;\n\n    this.x2 = x2 == null ? 1 : x2;\n\n    this.y2 = y2 == null ? 0 : y2;\n\n    // Can be cloned\n    this.type = 'linear';\n\n    // If use global coord\n    this.global = globalCoord || false;\n\n    Gradient.call(this, colorStops);\n};\n\nLinearGradient.prototype = {\n\n    constructor: LinearGradient\n};\n\ninherits(LinearGradient, Gradient);\n\n/**\n * x, y, r are all percent from 0 to 1\n * @param {number} [x=0.5]\n * @param {number} [y=0.5]\n * @param {number} [r=0.5]\n * @param {Array.<Object>} [colorStops]\n * @param {boolean} [globalCoord=false]\n */\nvar RadialGradient = function (x, y, r, colorStops, globalCoord) {\n    // Should do nothing more in this constructor. Because gradient can be\n    // declard by `color: {type: 'radial', colorStops: ...}`, where\n    // this constructor will not be called.\n\n    this.x = x == null ? 0.5 : x;\n\n    this.y = y == null ? 0.5 : y;\n\n    this.r = r == null ? 0.5 : r;\n\n    // Can be cloned\n    this.type = 'radial';\n\n    // If use global coord\n    this.global = globalCoord || false;\n\n    Gradient.call(this, colorStops);\n};\n\nRadialGradient.prototype = {\n\n    constructor: RadialGradient\n};\n\ninherits(RadialGradient, Gradient);\n\n/**\n * Displayable for incremental rendering. It will be rendered in a separate layer\n * IncrementalDisplay have two main methods. `clearDisplayables` and `addDisplayables`\n * addDisplayables will render the added displayables incremetally.\n *\n * It use a not clearFlag to tell the painter don't clear the layer if it's the first element.\n */\n// TODO Style override ?\nfunction IncrementalDisplayble(opts) {\n\n    Displayable.call(this, opts);\n\n    this._displayables = [];\n\n    this._temporaryDisplayables = [];\n\n    this._cursor = 0;\n\n    this.notClear = true;\n}\n\nIncrementalDisplayble.prototype.incremental = true;\n\nIncrementalDisplayble.prototype.clearDisplaybles = function () {\n    this._displayables = [];\n    this._temporaryDisplayables = [];\n    this._cursor = 0;\n    this.dirty();\n\n    this.notClear = false;\n};\n\nIncrementalDisplayble.prototype.addDisplayable = function (displayable, notPersistent) {\n    if (notPersistent) {\n        this._temporaryDisplayables.push(displayable);\n    }\n    else {\n        this._displayables.push(displayable);\n    }\n    this.dirty();\n};\n\nIncrementalDisplayble.prototype.addDisplayables = function (displayables, notPersistent) {\n    notPersistent = notPersistent || false;\n    for (var i = 0; i < displayables.length; i++) {\n        this.addDisplayable(displayables[i], notPersistent);\n    }\n};\n\nIncrementalDisplayble.prototype.eachPendingDisplayable = function (cb) {\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        cb && cb(this._displayables[i]);\n    }\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        cb && cb(this._temporaryDisplayables[i]);\n    }\n};\n\nIncrementalDisplayble.prototype.update = function () {\n    this.updateTransform();\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        var displayable = this._displayables[i];\n        // PENDING\n        displayable.parent = this;\n        displayable.update();\n        displayable.parent = null;\n    }\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        var displayable = this._temporaryDisplayables[i];\n        // PENDING\n        displayable.parent = this;\n        displayable.update();\n        displayable.parent = null;\n    }\n};\n\nIncrementalDisplayble.prototype.brush = function (ctx, prevEl) {\n    // Render persistant displayables.\n    for (var i = this._cursor; i < this._displayables.length; i++) {\n        var displayable = this._displayables[i];\n        displayable.beforeBrush && displayable.beforeBrush(ctx);\n        displayable.brush(ctx, i === this._cursor ? null : this._displayables[i - 1]);\n        displayable.afterBrush && displayable.afterBrush(ctx);\n    }\n    this._cursor = i;\n    // Render temporary displayables.\n    for (var i = 0; i < this._temporaryDisplayables.length; i++) {\n        var displayable = this._temporaryDisplayables[i];\n        displayable.beforeBrush && displayable.beforeBrush(ctx);\n        displayable.brush(ctx, i === 0 ? null : this._temporaryDisplayables[i - 1]);\n        displayable.afterBrush && displayable.afterBrush(ctx);\n    }\n\n    this._temporaryDisplayables = [];\n\n    this.notClear = true;\n};\n\nvar m = [];\nIncrementalDisplayble.prototype.getBoundingRect = function () {\n    if (!this._rect) {\n        var rect = new BoundingRect(Infinity, Infinity, -Infinity, -Infinity);\n        for (var i = 0; i < this._displayables.length; i++) {\n            var displayable = this._displayables[i];\n            var childRect = displayable.getBoundingRect().clone();\n            if (displayable.needLocalTransform()) {\n                childRect.applyTransform(displayable.getLocalTransform(m));\n            }\n            rect.union(childRect);\n        }\n        this._rect = rect;\n    }\n    return this._rect;\n};\n\nIncrementalDisplayble.prototype.contain = function (x, y) {\n    var localPos = this.transformCoordToLocal(x, y);\n    var rect = this.getBoundingRect();\n\n    if (rect.contain(localPos[0], localPos[1])) {\n        for (var i = 0; i < this._displayables.length; i++) {\n            var displayable = this._displayables[i];\n            if (displayable.contain(x, y)) {\n                return true;\n            }\n        }\n    }\n    return false;\n};\n\ninherits(IncrementalDisplayble, Displayable);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar round = Math.round;\nvar mathMax$1 = Math.max;\nvar mathMin$1 = Math.min;\n\nvar EMPTY_OBJ = {};\n\nvar Z2_EMPHASIS_LIFT = 1;\n\n/**\n * Extend shape with parameters\n */\nfunction extendShape(opts) {\n    return Path.extend(opts);\n}\n\n/**\n * Extend path\n */\nfunction extendPath(pathData, opts) {\n    return extendFromString(pathData, opts);\n}\n\n/**\n * Create a path element from path data string\n * @param {string} pathData\n * @param {Object} opts\n * @param {module:zrender/core/BoundingRect} rect\n * @param {string} [layout=cover] 'center' or 'cover'\n */\nfunction makePath(pathData, opts, rect, layout) {\n    var path = createFromString(pathData, opts);\n    if (rect) {\n        if (layout === 'center') {\n            rect = centerGraphic(rect, path.getBoundingRect());\n        }\n        resizePath(path, rect);\n    }\n    return path;\n}\n\n/**\n * Create a image element from image url\n * @param {string} imageUrl image url\n * @param {Object} opts options\n * @param {module:zrender/core/BoundingRect} rect constrain rect\n * @param {string} [layout=cover] 'center' or 'cover'\n */\nfunction makeImage(imageUrl, rect, layout) {\n    var path = new ZImage({\n        style: {\n            image: imageUrl,\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        },\n        onload: function (img) {\n            if (layout === 'center') {\n                var boundingRect = {\n                    width: img.width,\n                    height: img.height\n                };\n                path.setStyle(centerGraphic(rect, boundingRect));\n            }\n        }\n    });\n    return path;\n}\n\n/**\n * Get position of centered element in bounding box.\n *\n * @param  {Object} rect         element local bounding box\n * @param  {Object} boundingRect constraint bounding box\n * @return {Object} element position containing x, y, width, and height\n */\nfunction centerGraphic(rect, boundingRect) {\n    // Set rect to center, keep width / height ratio.\n    var aspect = boundingRect.width / boundingRect.height;\n    var width = rect.height * aspect;\n    var height;\n    if (width <= rect.width) {\n        height = rect.height;\n    }\n    else {\n        width = rect.width;\n        height = width / aspect;\n    }\n    var cx = rect.x + rect.width / 2;\n    var cy = rect.y + rect.height / 2;\n\n    return {\n        x: cx - width / 2,\n        y: cy - height / 2,\n        width: width,\n        height: height\n    };\n}\n\nvar mergePath = mergePath$1;\n\n/**\n * Resize a path to fit the rect\n * @param {module:zrender/graphic/Path} path\n * @param {Object} rect\n */\nfunction resizePath(path, rect) {\n    if (!path.applyTransform) {\n        return;\n    }\n\n    var pathRect = path.getBoundingRect();\n\n    var m = pathRect.calculateTransform(rect);\n\n    path.applyTransform(m);\n}\n\n/**\n * Sub pixel optimize line for canvas\n *\n * @param {Object} param\n * @param {Object} [param.shape]\n * @param {number} [param.shape.x1]\n * @param {number} [param.shape.y1]\n * @param {number} [param.shape.x2]\n * @param {number} [param.shape.y2]\n * @param {Object} [param.style]\n * @param {number} [param.style.lineWidth]\n * @return {Object} Modified param\n */\nfunction subPixelOptimizeLine(param) {\n    var shape = param.shape;\n    var lineWidth = param.style.lineWidth;\n\n    if (round(shape.x1 * 2) === round(shape.x2 * 2)) {\n        shape.x1 = shape.x2 = subPixelOptimize(shape.x1, lineWidth, true);\n    }\n    if (round(shape.y1 * 2) === round(shape.y2 * 2)) {\n        shape.y1 = shape.y2 = subPixelOptimize(shape.y1, lineWidth, true);\n    }\n    return param;\n}\n\n/**\n * Sub pixel optimize rect for canvas\n *\n * @param {Object} param\n * @param {Object} [param.shape]\n * @param {number} [param.shape.x]\n * @param {number} [param.shape.y]\n * @param {number} [param.shape.width]\n * @param {number} [param.shape.height]\n * @param {Object} [param.style]\n * @param {number} [param.style.lineWidth]\n * @return {Object} Modified param\n */\nfunction subPixelOptimizeRect(param) {\n    var shape = param.shape;\n    var lineWidth = param.style.lineWidth;\n    var originX = shape.x;\n    var originY = shape.y;\n    var originWidth = shape.width;\n    var originHeight = shape.height;\n    shape.x = subPixelOptimize(shape.x, lineWidth, true);\n    shape.y = subPixelOptimize(shape.y, lineWidth, true);\n    shape.width = Math.max(\n        subPixelOptimize(originX + originWidth, lineWidth, false) - shape.x,\n        originWidth === 0 ? 0 : 1\n    );\n    shape.height = Math.max(\n        subPixelOptimize(originY + originHeight, lineWidth, false) - shape.y,\n        originHeight === 0 ? 0 : 1\n    );\n    return param;\n}\n\n/**\n * Sub pixel optimize for canvas\n *\n * @param {number} position Coordinate, such as x, y\n * @param {number} lineWidth Should be nonnegative integer.\n * @param {boolean=} positiveOrNegative Default false (negative).\n * @return {number} Optimized position.\n */\nfunction subPixelOptimize(position, lineWidth, positiveOrNegative) {\n    // Assure that (position + lineWidth / 2) is near integer edge,\n    // otherwise line will be fuzzy in canvas.\n    var doubledPosition = round(position * 2);\n    return (doubledPosition + round(lineWidth)) % 2 === 0\n        ? doubledPosition / 2\n        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;\n}\n\nfunction hasFillOrStroke(fillOrStroke) {\n    return fillOrStroke != null && fillOrStroke !== 'none';\n}\n\n// Most lifted color are duplicated.\nvar liftedColorMap = createHashMap();\nvar liftedColorCount = 0;\n\nfunction liftColor(color) {\n    if (typeof color !== 'string') {\n        return color;\n    }\n    var liftedColor = liftedColorMap.get(color);\n    if (!liftedColor) {\n        liftedColor = lift(color, -0.1);\n        if (liftedColorCount < 10000) {\n            liftedColorMap.set(color, liftedColor);\n            liftedColorCount++;\n        }\n    }\n    return liftedColor;\n}\n\nfunction cacheElementStl(el) {\n    if (!el.__hoverStlDirty) {\n        return;\n    }\n    el.__hoverStlDirty = false;\n\n    var hoverStyle = el.__hoverStl;\n    if (!hoverStyle) {\n        el.__cachedNormalStl = el.__cachedNormalZ2 = null;\n        return;\n    }\n\n    var normalStyle = el.__cachedNormalStl = {};\n    el.__cachedNormalZ2 = el.z2;\n    var elStyle = el.style;\n\n    for (var name in hoverStyle) {\n        // See comment in `doSingleEnterHover`.\n        if (hoverStyle[name] != null) {\n            normalStyle[name] = elStyle[name];\n        }\n    }\n\n    // Always cache fill and stroke to normalStyle for lifting color.\n    normalStyle.fill = elStyle.fill;\n    normalStyle.stroke = elStyle.stroke;\n}\n\nfunction doSingleEnterHover(el) {\n    var hoverStl = el.__hoverStl;\n\n    if (!hoverStl || el.__highlighted) {\n        return;\n    }\n\n    var useHoverLayer = el.useHoverLayer;\n    el.__highlighted = useHoverLayer ? 'layer' : 'plain';\n\n    var zr = el.__zr;\n    if (!zr && useHoverLayer) {\n        return;\n    }\n\n    var elTarget = el;\n    var targetStyle = el.style;\n\n    if (useHoverLayer) {\n        elTarget = zr.addHover(el);\n        targetStyle = elTarget.style;\n    }\n\n    rollbackDefaultTextStyle(targetStyle);\n\n    if (!useHoverLayer) {\n        cacheElementStl(elTarget);\n    }\n\n    // styles can be:\n    // {\n    //    label: {\n    //        show: false,\n    //        position: 'outside',\n    //        fontSize: 18\n    //    },\n    //    emphasis: {\n    //        label: {\n    //            show: true\n    //        }\n    //    }\n    // },\n    // where properties of `emphasis` may not appear in `normal`. We previously use\n    // module:echarts/util/model#defaultEmphasis to merge `normal` to `emphasis`.\n    // But consider rich text and setOption in merge mode, it is impossible to cover\n    // all properties in merge. So we use merge mode when setting style here, where\n    // only properties that is not `null/undefined` can be set. The disadventage:\n    // null/undefined can not be used to remove style any more in `emphasis`.\n    targetStyle.extendFrom(hoverStl);\n\n    setDefaultHoverFillStroke(targetStyle, hoverStl, 'fill');\n    setDefaultHoverFillStroke(targetStyle, hoverStl, 'stroke');\n\n    applyDefaultTextStyle(targetStyle);\n\n    if (!useHoverLayer) {\n        el.dirty(false);\n        el.z2 += Z2_EMPHASIS_LIFT;\n    }\n}\n\nfunction setDefaultHoverFillStroke(targetStyle, hoverStyle, prop) {\n    if (!hasFillOrStroke(hoverStyle[prop]) && hasFillOrStroke(targetStyle[prop])) {\n        targetStyle[prop] = liftColor(targetStyle[prop]);\n    }\n}\n\nfunction doSingleLeaveHover(el) {\n    var highlighted = el.__highlighted;\n\n    if (!highlighted) {\n        return;\n    }\n\n    el.__highlighted = false;\n\n    if (highlighted === 'layer') {\n        el.__zr && el.__zr.removeHover(el);\n    }\n    else if (highlighted) {\n        var style = el.style;\n\n        var normalStl = el.__cachedNormalStl;\n        if (normalStl) {\n            rollbackDefaultTextStyle(style);\n            // Consider null/undefined value, should use\n            // `setStyle` but not `extendFrom(stl, true)`.\n            el.setStyle(normalStl);\n            applyDefaultTextStyle(style);\n        }\n        // `__cachedNormalZ2` will not be reset if calling `setElementHoverStyle`\n        // when `el` is on emphasis state. So here by comparing with 1, we try\n        // hard to make the bug case rare.\n        var normalZ2 = el.__cachedNormalZ2;\n        if (normalZ2 != null && el.z2 - normalZ2 === Z2_EMPHASIS_LIFT) {\n            el.z2 = normalZ2;\n        }\n    }\n}\n\nfunction traverseCall(el, method) {\n    el.isGroup\n        ? el.traverse(function (child) {\n            !child.isGroup && method(child);\n        })\n        : method(el);\n}\n\n/**\n * Set hover style (namely \"emphasis style\") of element, based on the current\n * style of the given `el`.\n * This method should be called after all of the normal styles have been adopted\n * to the `el`. See the reason on `setHoverStyle`.\n *\n * @param {module:zrender/Element} el Should not be `zrender/container/Group`.\n * @param {Object|boolean} [hoverStl] The specified hover style.\n *        If set as `false`, disable the hover style.\n *        Similarly, The `el.hoverStyle` can alse be set\n *        as `false` to disable the hover style.\n *        Otherwise, use the default hover style if not provided.\n * @param {Object} [opt]\n * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`\n */\nfunction setElementHoverStyle(el, hoverStl) {\n    // For performance consideration, it might be better to make the \"hover style\" only the\n    // difference properties from the \"normal style\", but not a entire copy of all styles.\n    hoverStl = el.__hoverStl = hoverStl !== false && (hoverStl || {});\n    el.__hoverStlDirty = true;\n\n    // FIXME\n    // It is not completely right to save \"normal\"/\"emphasis\" flag on elements.\n    // It probably should be saved on `data` of series. Consider the cases:\n    // (1) A highlighted elements are moved out of the view port and re-enter\n    // again by dataZoom.\n    // (2) call `setOption` and replace elements totally when they are highlighted.\n    if (el.__highlighted) {\n        // Consider the case:\n        // The styles of a highlighted `el` is being updated. The new \"emphasis style\"\n        // should be adapted to the `el`. Notice here new \"normal styles\" should have\n        // been set outside and the cached \"normal style\" is out of date.\n        el.__cachedNormalStl = null;\n        // Do not clear `__cachedNormalZ2` here, because setting `z2` is not a constraint\n        // of this method. In most cases, `z2` is not set and hover style should be able\n        // to rollback. Of course, that would bring bug, but only in a rare case, see\n        // `doSingleLeaveHover` for details.\n        doSingleLeaveHover(el);\n\n        doSingleEnterHover(el);\n    }\n}\n\n/**\n * Emphasis (called by API) has higher priority than `mouseover`.\n * When element has been called to be entered emphasis, mouse over\n * should not trigger the highlight effect (for example, animation\n * scale) again, and `mouseout` should not downplay the highlight\n * effect. So the listener of `mouseover` and `mouseout` should\n * check `isInEmphasis`.\n *\n * @param {module:zrender/Element} el\n * @return {boolean}\n */\nfunction isInEmphasis(el) {\n    return el && el.__isEmphasisEntered;\n}\n\nfunction onElementMouseOver(e) {\n    if (this.__hoverSilentOnTouch && e.zrByTouch) {\n        return;\n    }\n\n    // Only if element is not in emphasis status\n    !this.__isEmphasisEntered && traverseCall(this, doSingleEnterHover);\n}\n\nfunction onElementMouseOut(e) {\n    if (this.__hoverSilentOnTouch && e.zrByTouch) {\n        return;\n    }\n\n    // Only if element is not in emphasis status\n    !this.__isEmphasisEntered && traverseCall(this, doSingleLeaveHover);\n}\n\nfunction enterEmphasis() {\n    this.__isEmphasisEntered = true;\n    traverseCall(this, doSingleEnterHover);\n}\n\nfunction leaveEmphasis() {\n    this.__isEmphasisEntered = false;\n    traverseCall(this, doSingleLeaveHover);\n}\n\n/**\n * Set hover style (namely \"emphasis style\") of element,\n * based on the current style of the given `el`.\n *\n * (1)\n * **CONSTRAINTS** for this method:\n * <A> This method MUST be called after all of the normal styles having been adopted\n * to the `el`.\n * <B> The input `hoverStyle` (that is, \"emphasis style\") MUST be the subset of the\n * \"normal style\" having been set to the el.\n * <C> `color` MUST be one of the \"normal styles\" (because color might be lifted as\n * a default hover style).\n *\n * The reason: this method treat the current style of the `el` as the \"normal style\"\n * and cache them when enter/update the \"emphasis style\". Consider the case: the `el`\n * is in \"emphasis\" state and `setOption`/`dispatchAction` trigger the style updating\n * logic, where the el should shift from the original emphasis style to the new\n * \"emphasis style\" and should be able to \"downplay\" back to the new \"normal style\".\n *\n * Indeed, it is error-prone to make a interface has so many constraints, but I have\n * not found a better solution yet to fit the backward compatibility, performance and\n * the current programming style.\n *\n * (2)\n * Call the method for a \"root\" element once. Do not call it for each descendants.\n * If the descendants elemenets of a group has itself hover style different from the\n * root group, we can simply mount the style on `el.hoverStyle` for them, but should\n * not call this method for them.\n *\n * @param {module:zrender/Element} el\n * @param {Object|boolean} [hoverStyle] See `graphic.setElementHoverStyle`.\n * @param {Object} [opt]\n * @param {boolean} [opt.hoverSilentOnTouch=false] See `graphic.setAsHoverStyleTrigger`.\n */\nfunction setHoverStyle(el, hoverStyle, opt) {\n    el.isGroup\n        ? el.traverse(function (child) {\n            // If element has sepcified hoverStyle, then use it instead of given hoverStyle\n            // Often used when item group has a label element and it's hoverStyle is different\n            !child.isGroup && setElementHoverStyle(child, child.hoverStyle || hoverStyle);\n        })\n        : setElementHoverStyle(el, el.hoverStyle || hoverStyle);\n\n    setAsHoverStyleTrigger(el, opt);\n}\n\n/**\n * @param {Object|boolean} [opt] If `false`, means disable trigger.\n * @param {boolean} [opt.hoverSilentOnTouch=false]\n *        In touch device, mouseover event will be trigger on touchstart event\n *        (see module:zrender/dom/HandlerProxy). By this mechanism, we can\n *        conveniently use hoverStyle when tap on touch screen without additional\n *        code for compatibility.\n *        But if the chart/component has select feature, which usually also use\n *        hoverStyle, there might be conflict between 'select-highlight' and\n *        'hover-highlight' especially when roam is enabled (see geo for example).\n *        In this case, hoverSilentOnTouch should be used to disable hover-highlight\n *        on touch device.\n */\nfunction setAsHoverStyleTrigger(el, opt) {\n    var disable = opt === false;\n    el.__hoverSilentOnTouch = opt != null && opt.hoverSilentOnTouch;\n\n    // Simple optimize, since this method might be\n    // called for each elements of a group in some cases.\n    if (!disable || el.__hoverStyleTrigger) {\n        var method = disable ? 'off' : 'on';\n\n        // Duplicated function will be auto-ignored, see Eventful.js.\n        el[method]('mouseover', onElementMouseOver)[method]('mouseout', onElementMouseOut);\n        // Emphasis, normal can be triggered manually\n        el[method]('emphasis', enterEmphasis)[method]('normal', leaveEmphasis);\n\n        el.__hoverStyleTrigger = !disable;\n    }\n}\n\n/**\n * See more info in `setTextStyleCommon`.\n * @param {Object|module:zrender/graphic/Style} normalStyle\n * @param {Object} emphasisStyle\n * @param {module:echarts/model/Model} normalModel\n * @param {module:echarts/model/Model} emphasisModel\n * @param {Object} opt Check `opt` of `setTextStyleCommon` to find other props.\n * @param {string|Function} [opt.defaultText]\n * @param {module:echarts/model/Model} [opt.labelFetcher] Fetch text by\n *      `opt.labelFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {module:echarts/model/Model} [opt.labelDataIndex] Fetch text by\n *      `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {module:echarts/model/Model} [opt.labelDimIndex] Fetch text by\n *      `opt.textFetcher.getFormattedLabel(opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex)`\n * @param {Object} [normalSpecified]\n * @param {Object} [emphasisSpecified]\n */\nfunction setLabelStyle(\n    normalStyle, emphasisStyle,\n    normalModel, emphasisModel,\n    opt,\n    normalSpecified, emphasisSpecified\n) {\n    opt = opt || EMPTY_OBJ;\n    var labelFetcher = opt.labelFetcher;\n    var labelDataIndex = opt.labelDataIndex;\n    var labelDimIndex = opt.labelDimIndex;\n\n    // This scenario, `label.normal.show = true; label.emphasis.show = false`,\n    // is not supported util someone requests.\n\n    var showNormal = normalModel.getShallow('show');\n    var showEmphasis = emphasisModel.getShallow('show');\n\n    // Consider performance, only fetch label when necessary.\n    // If `normal.show` is `false` and `emphasis.show` is `true` and `emphasis.formatter` is not set,\n    // label should be displayed, where text is fetched by `normal.formatter` or `opt.defaultText`.\n    var baseText;\n    if (showNormal || showEmphasis) {\n        if (labelFetcher) {\n            baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex);\n        }\n        if (baseText == null) {\n            baseText = isFunction$1(opt.defaultText) ? opt.defaultText(labelDataIndex, opt) : opt.defaultText;\n        }\n    }\n    var normalStyleText = showNormal ? baseText : null;\n    var emphasisStyleText = showEmphasis\n        ? retrieve2(\n            labelFetcher\n                ? labelFetcher.getFormattedLabel(labelDataIndex, 'emphasis', null, labelDimIndex)\n                : null,\n            baseText\n        )\n        : null;\n\n    // Optimize: If style.text is null, text will not be drawn.\n    if (normalStyleText != null || emphasisStyleText != null) {\n        // Always set `textStyle` even if `normalStyle.text` is null, because default\n        // values have to be set on `normalStyle`.\n        // If we set default values on `emphasisStyle`, consider case:\n        // Firstly, `setOption(... label: {normal: {text: null}, emphasis: {show: true}} ...);`\n        // Secondly, `setOption(... label: {noraml: {show: true, text: 'abc', color: 'red'} ...);`\n        // Then the 'red' will not work on emphasis.\n        setTextStyle(normalStyle, normalModel, normalSpecified, opt);\n        setTextStyle(emphasisStyle, emphasisModel, emphasisSpecified, opt, true);\n    }\n\n    normalStyle.text = normalStyleText;\n    emphasisStyle.text = emphasisStyleText;\n}\n\n/**\n * Set basic textStyle properties.\n * See more info in `setTextStyleCommon`.\n * @param {Object|module:zrender/graphic/Style} textStyle\n * @param {module:echarts/model/Model} model\n * @param {Object} [specifiedTextStyle] Can be overrided by settings in model.\n * @param {Object} [opt] See `opt` of `setTextStyleCommon`.\n * @param {boolean} [isEmphasis]\n */\nfunction setTextStyle(\n    textStyle, textStyleModel, specifiedTextStyle, opt, isEmphasis\n) {\n    setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis);\n    specifiedTextStyle && extend(textStyle, specifiedTextStyle);\n    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);\n\n    return textStyle;\n}\n\n/**\n * Set text option in the style.\n * See more info in `setTextStyleCommon`.\n * @deprecated\n * @param {Object} textStyle\n * @param {module:echarts/model/Model} labelModel\n * @param {string|boolean} defaultColor Default text color.\n *        If set as false, it will be processed as a emphasis style.\n */\nfunction setText(textStyle, labelModel, defaultColor) {\n    var opt = {isRectText: true};\n    var isEmphasis;\n\n    if (defaultColor === false) {\n        isEmphasis = true;\n    }\n    else {\n        // Support setting color as 'auto' to get visual color.\n        opt.autoColor = defaultColor;\n    }\n    setTextStyleCommon(textStyle, labelModel, opt, isEmphasis);\n    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);\n}\n\n/**\n * The uniform entry of set text style, that is, retrieve style definitions\n * from `model` and set to `textStyle` object.\n *\n * Never in merge mode, but in overwrite mode, that is, all of the text style\n * properties will be set. (Consider the states of normal and emphasis and\n * default value can be adopted, merge would make the logic too complicated\n * to manage.)\n *\n * The `textStyle` object can either be a plain object or an instance of\n * `zrender/src/graphic/Style`, and either be the style of normal or emphasis.\n * After this mothod called, the `textStyle` object can then be used in\n * `el.setStyle(textStyle)` or `el.hoverStyle = textStyle`.\n *\n * Default value will be adopted and `insideRollbackOpt` will be created.\n * See `applyDefaultTextStyle` `rollbackDefaultTextStyle` for more details.\n *\n * opt: {\n *      disableBox: boolean, Whether diable drawing box of block (outer most).\n *      isRectText: boolean,\n *      autoColor: string, specify a color when color is 'auto',\n *              for textFill, textStroke, textBackgroundColor, and textBorderColor.\n *              If autoColor specified, it is used as default textFill.\n *      useInsideStyle:\n *              `true`: Use inside style (textFill, textStroke, textStrokeWidth)\n *                  if `textFill` is not specified.\n *              `false`: Do not use inside style.\n *              `null/undefined`: use inside style if `isRectText` is true and\n *                  `textFill` is not specified and textPosition contains `'inside'`.\n *      forceRich: boolean\n * }\n */\nfunction setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis) {\n    // Consider there will be abnormal when merge hover style to normal style if given default value.\n    opt = opt || EMPTY_OBJ;\n\n    if (opt.isRectText) {\n        var textPosition = textStyleModel.getShallow('position')\n            || (isEmphasis ? null : 'inside');\n        // 'outside' is not a valid zr textPostion value, but used\n        // in bar series, and magric type should be considered.\n        textPosition === 'outside' && (textPosition = 'top');\n        textStyle.textPosition = textPosition;\n        textStyle.textOffset = textStyleModel.getShallow('offset');\n        var labelRotate = textStyleModel.getShallow('rotate');\n        labelRotate != null && (labelRotate *= Math.PI / 180);\n        textStyle.textRotation = labelRotate;\n        textStyle.textDistance = retrieve2(\n            textStyleModel.getShallow('distance'), isEmphasis ? null : 5\n        );\n    }\n\n    var ecModel = textStyleModel.ecModel;\n    var globalTextStyle = ecModel && ecModel.option.textStyle;\n\n    // Consider case:\n    // {\n    //     data: [{\n    //         value: 12,\n    //         label: {\n    //             rich: {\n    //                 // no 'a' here but using parent 'a'.\n    //             }\n    //         }\n    //     }],\n    //     rich: {\n    //         a: { ... }\n    //     }\n    // }\n    var richItemNames = getRichItemNames(textStyleModel);\n    var richResult;\n    if (richItemNames) {\n        richResult = {};\n        for (var name in richItemNames) {\n            if (richItemNames.hasOwnProperty(name)) {\n                // Cascade is supported in rich.\n                var richTextStyle = textStyleModel.getModel(['rich', name]);\n                // In rich, never `disableBox`.\n                setTokenTextStyle(richResult[name] = {}, richTextStyle, globalTextStyle, opt, isEmphasis);\n            }\n        }\n    }\n    textStyle.rich = richResult;\n\n    setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, true);\n\n    if (opt.forceRich && !opt.textStyle) {\n        opt.textStyle = {};\n    }\n\n    return textStyle;\n}\n\n// Consider case:\n// {\n//     data: [{\n//         value: 12,\n//         label: {\n//             rich: {\n//                 // no 'a' here but using parent 'a'.\n//             }\n//         }\n//     }],\n//     rich: {\n//         a: { ... }\n//     }\n// }\nfunction getRichItemNames(textStyleModel) {\n    // Use object to remove duplicated names.\n    var richItemNameMap;\n    while (textStyleModel && textStyleModel !== textStyleModel.ecModel) {\n        var rich = (textStyleModel.option || EMPTY_OBJ).rich;\n        if (rich) {\n            richItemNameMap = richItemNameMap || {};\n            for (var name in rich) {\n                if (rich.hasOwnProperty(name)) {\n                    richItemNameMap[name] = 1;\n                }\n            }\n        }\n        textStyleModel = textStyleModel.parentModel;\n    }\n    return richItemNameMap;\n}\n\nfunction setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isEmphasis, isBlock) {\n    // In merge mode, default value should not be given.\n    globalTextStyle = !isEmphasis && globalTextStyle || EMPTY_OBJ;\n\n    textStyle.textFill = getAutoColor(textStyleModel.getShallow('color'), opt)\n        || globalTextStyle.color;\n    textStyle.textStroke = getAutoColor(textStyleModel.getShallow('textBorderColor'), opt)\n        || globalTextStyle.textBorderColor;\n    textStyle.textStrokeWidth = retrieve2(\n        textStyleModel.getShallow('textBorderWidth'),\n        globalTextStyle.textBorderWidth\n    );\n\n    // Save original textPosition, because style.textPosition will be repalced by\n    // real location (like [10, 30]) in zrender.\n    textStyle.insideRawTextPosition = textStyle.textPosition;\n\n    if (!isEmphasis) {\n        if (isBlock) {\n            textStyle.insideRollbackOpt = opt;\n            applyDefaultTextStyle(textStyle);\n        }\n\n        // Set default finally.\n        if (textStyle.textFill == null) {\n            textStyle.textFill = opt.autoColor;\n        }\n    }\n\n    // Do not use `getFont` here, because merge should be supported, where\n    // part of these properties may be changed in emphasis style, and the\n    // others should remain their original value got from normal style.\n    textStyle.fontStyle = textStyleModel.getShallow('fontStyle') || globalTextStyle.fontStyle;\n    textStyle.fontWeight = textStyleModel.getShallow('fontWeight') || globalTextStyle.fontWeight;\n    textStyle.fontSize = textStyleModel.getShallow('fontSize') || globalTextStyle.fontSize;\n    textStyle.fontFamily = textStyleModel.getShallow('fontFamily') || globalTextStyle.fontFamily;\n\n    textStyle.textAlign = textStyleModel.getShallow('align');\n    textStyle.textVerticalAlign = textStyleModel.getShallow('verticalAlign')\n        || textStyleModel.getShallow('baseline');\n\n    textStyle.textLineHeight = textStyleModel.getShallow('lineHeight');\n    textStyle.textWidth = textStyleModel.getShallow('width');\n    textStyle.textHeight = textStyleModel.getShallow('height');\n    textStyle.textTag = textStyleModel.getShallow('tag');\n\n    if (!isBlock || !opt.disableBox) {\n        textStyle.textBackgroundColor = getAutoColor(textStyleModel.getShallow('backgroundColor'), opt);\n        textStyle.textPadding = textStyleModel.getShallow('padding');\n        textStyle.textBorderColor = getAutoColor(textStyleModel.getShallow('borderColor'), opt);\n        textStyle.textBorderWidth = textStyleModel.getShallow('borderWidth');\n        textStyle.textBorderRadius = textStyleModel.getShallow('borderRadius');\n\n        textStyle.textBoxShadowColor = textStyleModel.getShallow('shadowColor');\n        textStyle.textBoxShadowBlur = textStyleModel.getShallow('shadowBlur');\n        textStyle.textBoxShadowOffsetX = textStyleModel.getShallow('shadowOffsetX');\n        textStyle.textBoxShadowOffsetY = textStyleModel.getShallow('shadowOffsetY');\n    }\n\n    textStyle.textShadowColor = textStyleModel.getShallow('textShadowColor')\n        || globalTextStyle.textShadowColor;\n    textStyle.textShadowBlur = textStyleModel.getShallow('textShadowBlur')\n        || globalTextStyle.textShadowBlur;\n    textStyle.textShadowOffsetX = textStyleModel.getShallow('textShadowOffsetX')\n        || globalTextStyle.textShadowOffsetX;\n    textStyle.textShadowOffsetY = textStyleModel.getShallow('textShadowOffsetY')\n        || globalTextStyle.textShadowOffsetY;\n}\n\nfunction getAutoColor(color, opt) {\n    return color !== 'auto' ? color : (opt && opt.autoColor) ? opt.autoColor : null;\n}\n\n/**\n * Give some default value to the input `textStyle` object, based on the current settings\n * in this `textStyle` object.\n *\n * The Scenario:\n * when text position is `inside` and `textFill` is not specified, we show\n * text border by default for better view. But it should be considered that text position\n * might be changed when hovering or being emphasis, where the `insideRollback` is used to\n * restore the style.\n *\n * Usage (& NOTICE):\n * When a style object (eithor plain object or instance of `zrender/src/graphic/Style`) is\n * about to be modified on its text related properties, `rollbackDefaultTextStyle` should\n * be called before the modification and `applyDefaultTextStyle` should be called after that.\n * (For the case that all of the text related properties is reset, like `setTextStyleCommon`\n * does, `rollbackDefaultTextStyle` is not needed to be called).\n */\nfunction applyDefaultTextStyle(textStyle) {\n    var opt = textStyle.insideRollbackOpt;\n\n    // Only `insideRollbackOpt` created (in `setTextStyleCommon`),\n    // applyDefaultTextStyle works.\n    if (!opt || textStyle.textFill != null) {\n        return;\n    }\n\n    var useInsideStyle = opt.useInsideStyle;\n    var textPosition = textStyle.insideRawTextPosition;\n    var insideRollback;\n    var autoColor = opt.autoColor;\n\n    if (useInsideStyle !== false\n        && (useInsideStyle === true\n            || (opt.isRectText\n                && textPosition\n                // textPosition can be [10, 30]\n                && typeof textPosition === 'string'\n                && textPosition.indexOf('inside') >= 0\n            )\n        )\n    ) {\n        insideRollback = {\n            textFill: null,\n            textStroke: textStyle.textStroke,\n            textStrokeWidth: textStyle.textStrokeWidth\n        };\n        textStyle.textFill = '#fff';\n        // Consider text with #fff overflow its container.\n        if (textStyle.textStroke == null) {\n            textStyle.textStroke = autoColor;\n            textStyle.textStrokeWidth == null && (textStyle.textStrokeWidth = 2);\n        }\n    }\n    else if (autoColor != null) {\n        insideRollback = {textFill: null};\n        textStyle.textFill = autoColor;\n    }\n\n    // Always set `insideRollback`, for clearing previous.\n    if (insideRollback) {\n        textStyle.insideRollback = insideRollback;\n    }\n}\n\n/**\n * Consider the case: in a scatter,\n * label: {\n *     normal: {position: 'inside'},\n *     emphasis: {position: 'top'}\n * }\n * In the normal state, the `textFill` will be set as '#fff' for pretty view (see\n * `applyDefaultTextStyle`), but when switching to emphasis state, the `textFill`\n * should be retured to 'autoColor', but not keep '#fff'.\n */\nfunction rollbackDefaultTextStyle(style) {\n    var insideRollback = style.insideRollback;\n    if (insideRollback) {\n        style.textFill = insideRollback.textFill;\n        style.textStroke = insideRollback.textStroke;\n        style.textStrokeWidth = insideRollback.textStrokeWidth;\n        style.insideRollback = null;\n    }\n}\n\nfunction getFont(opt, ecModel) {\n    // ecModel or default text style model.\n    var gTextStyleModel = ecModel || ecModel.getModel('textStyle');\n    return trim([\n        // FIXME in node-canvas fontWeight is before fontStyle\n        opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '',\n        opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '',\n        (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px',\n        opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'\n    ].join(' '));\n}\n\nfunction animateOrSetProps(isUpdate, el, props, animatableModel, dataIndex, cb) {\n    if (typeof dataIndex === 'function') {\n        cb = dataIndex;\n        dataIndex = null;\n    }\n    // Do not check 'animation' property directly here. Consider this case:\n    // animation model is an `itemModel`, whose does not have `isAnimationEnabled`\n    // but its parent model (`seriesModel`) does.\n    var animationEnabled = animatableModel && animatableModel.isAnimationEnabled();\n\n    if (animationEnabled) {\n        var postfix = isUpdate ? 'Update' : '';\n        var duration = animatableModel.getShallow('animationDuration' + postfix);\n        var animationEasing = animatableModel.getShallow('animationEasing' + postfix);\n        var animationDelay = animatableModel.getShallow('animationDelay' + postfix);\n        if (typeof animationDelay === 'function') {\n            animationDelay = animationDelay(\n                dataIndex,\n                animatableModel.getAnimationDelayParams\n                    ? animatableModel.getAnimationDelayParams(el, dataIndex)\n                    : null\n            );\n        }\n        if (typeof duration === 'function') {\n            duration = duration(dataIndex);\n        }\n\n        duration > 0\n            ? el.animateTo(props, duration, animationDelay || 0, animationEasing, cb, !!cb)\n            : (el.stopAnimation(), el.attr(props), cb && cb());\n    }\n    else {\n        el.stopAnimation();\n        el.attr(props);\n        cb && cb();\n    }\n}\n\n/**\n * Update graphic element properties with or without animation according to the\n * configuration in series.\n *\n * Caution: this method will stop previous animation.\n * So if do not use this method to one element twice before\n * animation starts, unless you know what you are doing.\n *\n * @param {module:zrender/Element} el\n * @param {Object} props\n * @param {module:echarts/model/Model} [animatableModel]\n * @param {number} [dataIndex]\n * @param {Function} [cb]\n * @example\n *     graphic.updateProps(el, {\n *         position: [100, 100]\n *     }, seriesModel, dataIndex, function () { console.log('Animation done!'); });\n *     // Or\n *     graphic.updateProps(el, {\n *         position: [100, 100]\n *     }, seriesModel, function () { console.log('Animation done!'); });\n */\nfunction updateProps(el, props, animatableModel, dataIndex, cb) {\n    animateOrSetProps(true, el, props, animatableModel, dataIndex, cb);\n}\n\n/**\n * Init graphic element properties with or without animation according to the\n * configuration in series.\n *\n * Caution: this method will stop previous animation.\n * So if do not use this method to one element twice before\n * animation starts, unless you know what you are doing.\n *\n * @param {module:zrender/Element} el\n * @param {Object} props\n * @param {module:echarts/model/Model} [animatableModel]\n * @param {number} [dataIndex]\n * @param {Function} cb\n */\nfunction initProps(el, props, animatableModel, dataIndex, cb) {\n    animateOrSetProps(false, el, props, animatableModel, dataIndex, cb);\n}\n\n/**\n * Get transform matrix of target (param target),\n * in coordinate of its ancestor (param ancestor)\n *\n * @param {module:zrender/mixin/Transformable} target\n * @param {module:zrender/mixin/Transformable} [ancestor]\n */\nfunction getTransform(target, ancestor) {\n    var mat = identity([]);\n\n    while (target && target !== ancestor) {\n        mul$1(mat, target.getLocalTransform(), mat);\n        target = target.parent;\n    }\n\n    return mat;\n}\n\n/**\n * Apply transform to an vertex.\n * @param {Array.<number>} target [x, y]\n * @param {Array.<number>|TypedArray.<number>|Object} transform Can be:\n *      + Transform matrix: like [1, 0, 0, 1, 0, 0]\n *      + {position, rotation, scale}, the same as `zrender/Transformable`.\n * @param {boolean=} invert Whether use invert matrix.\n * @return {Array.<number>} [x, y]\n */\nfunction applyTransform$1(target, transform, invert$$1) {\n    if (transform && !isArrayLike(transform)) {\n        transform = Transformable.getLocalTransform(transform);\n    }\n\n    if (invert$$1) {\n        transform = invert([], transform);\n    }\n    return applyTransform([], target, transform);\n}\n\n/**\n * @param {string} direction 'left' 'right' 'top' 'bottom'\n * @param {Array.<number>} transform Transform matrix: like [1, 0, 0, 1, 0, 0]\n * @param {boolean=} invert Whether use invert matrix.\n * @return {string} Transformed direction. 'left' 'right' 'top' 'bottom'\n */\nfunction transformDirection(direction, transform, invert$$1) {\n\n    // Pick a base, ensure that transform result will not be (0, 0).\n    var hBase = (transform[4] === 0 || transform[5] === 0 || transform[0] === 0)\n        ? 1 : Math.abs(2 * transform[4] / transform[0]);\n    var vBase = (transform[4] === 0 || transform[5] === 0 || transform[2] === 0)\n        ? 1 : Math.abs(2 * transform[4] / transform[2]);\n\n    var vertex = [\n        direction === 'left' ? -hBase : direction === 'right' ? hBase : 0,\n        direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0\n    ];\n\n    vertex = applyTransform$1(vertex, transform, invert$$1);\n\n    return Math.abs(vertex[0]) > Math.abs(vertex[1])\n        ? (vertex[0] > 0 ? 'right' : 'left')\n        : (vertex[1] > 0 ? 'bottom' : 'top');\n}\n\n/**\n * Apply group transition animation from g1 to g2.\n * If no animatableModel, no animation.\n */\nfunction groupTransition(g1, g2, animatableModel, cb) {\n    if (!g1 || !g2) {\n        return;\n    }\n\n    function getElMap(g) {\n        var elMap = {};\n        g.traverse(function (el) {\n            if (!el.isGroup && el.anid) {\n                elMap[el.anid] = el;\n            }\n        });\n        return elMap;\n    }\n    function getAnimatableProps(el) {\n        var obj = {\n            position: clone$1(el.position),\n            rotation: el.rotation\n        };\n        if (el.shape) {\n            obj.shape = extend({}, el.shape);\n        }\n        return obj;\n    }\n    var elMap1 = getElMap(g1);\n\n    g2.traverse(function (el) {\n        if (!el.isGroup && el.anid) {\n            var oldEl = elMap1[el.anid];\n            if (oldEl) {\n                var newProp = getAnimatableProps(el);\n                el.attr(getAnimatableProps(oldEl));\n                updateProps(el, newProp, animatableModel, el.dataIndex);\n            }\n            // else {\n            //     if (el.previousProps) {\n            //         graphic.updateProps\n            //     }\n            // }\n        }\n    });\n}\n\n/**\n * @param {Array.<Array.<number>>} points Like: [[23, 44], [53, 66], ...]\n * @param {Object} rect {x, y, width, height}\n * @return {Array.<Array.<number>>} A new clipped points.\n */\nfunction clipPointsByRect(points, rect) {\n    // FIXME: this way migth be incorrect when grpahic clipped by a corner.\n    // and when element have border.\n    return map(points, function (point) {\n        var x = point[0];\n        x = mathMax$1(x, rect.x);\n        x = mathMin$1(x, rect.x + rect.width);\n        var y = point[1];\n        y = mathMax$1(y, rect.y);\n        y = mathMin$1(y, rect.y + rect.height);\n        return [x, y];\n    });\n}\n\n/**\n * @param {Object} targetRect {x, y, width, height}\n * @param {Object} rect {x, y, width, height}\n * @return {Object} A new clipped rect. If rect size are negative, return undefined.\n */\nfunction clipRectByRect(targetRect, rect) {\n    var x = mathMax$1(targetRect.x, rect.x);\n    var x2 = mathMin$1(targetRect.x + targetRect.width, rect.x + rect.width);\n    var y = mathMax$1(targetRect.y, rect.y);\n    var y2 = mathMin$1(targetRect.y + targetRect.height, rect.y + rect.height);\n\n    // If the total rect is cliped, nothing, including the border,\n    // should be painted. So return undefined.\n    if (x2 >= x && y2 >= y) {\n        return {\n            x: x,\n            y: y,\n            width: x2 - x,\n            height: y2 - y\n        };\n    }\n}\n\n/**\n * @param {string} iconStr Support 'image://' or 'path://' or direct svg path.\n * @param {Object} [opt] Properties of `module:zrender/Element`, except `style`.\n * @param {Object} [rect] {x, y, width, height}\n * @return {module:zrender/Element} Icon path or image element.\n */\nfunction createIcon(iconStr, opt, rect) {\n    opt = extend({rectHover: true}, opt);\n    var style = opt.style = {strokeNoScale: true};\n    rect = rect || {x: -1, y: -1, width: 2, height: 2};\n\n    if (iconStr) {\n        return iconStr.indexOf('image://') === 0\n            ? (\n                style.image = iconStr.slice(8),\n                defaults(style, rect),\n                new ZImage(opt)\n            )\n            : (\n                makePath(\n                    iconStr.replace('path://', ''),\n                    opt,\n                    rect,\n                    'center'\n                )\n            );\n    }\n}\n\n\n\n\nvar graphic = (Object.freeze || Object)({\n\tZ2_EMPHASIS_LIFT: Z2_EMPHASIS_LIFT,\n\textendShape: extendShape,\n\textendPath: extendPath,\n\tmakePath: makePath,\n\tmakeImage: makeImage,\n\tmergePath: mergePath,\n\tresizePath: resizePath,\n\tsubPixelOptimizeLine: subPixelOptimizeLine,\n\tsubPixelOptimizeRect: subPixelOptimizeRect,\n\tsubPixelOptimize: subPixelOptimize,\n\tsetElementHoverStyle: setElementHoverStyle,\n\tisInEmphasis: isInEmphasis,\n\tsetHoverStyle: setHoverStyle,\n\tsetAsHoverStyleTrigger: setAsHoverStyleTrigger,\n\tsetLabelStyle: setLabelStyle,\n\tsetTextStyle: setTextStyle,\n\tsetText: setText,\n\tgetFont: getFont,\n\tupdateProps: updateProps,\n\tinitProps: initProps,\n\tgetTransform: getTransform,\n\tapplyTransform: applyTransform$1,\n\ttransformDirection: transformDirection,\n\tgroupTransition: groupTransition,\n\tclipPointsByRect: clipPointsByRect,\n\tclipRectByRect: clipRectByRect,\n\tcreateIcon: createIcon,\n\tGroup: Group,\n\tImage: ZImage,\n\tText: Text,\n\tCircle: Circle,\n\tSector: Sector,\n\tRing: Ring,\n\tPolygon: Polygon,\n\tPolyline: Polyline,\n\tRect: Rect,\n\tLine: Line,\n\tBezierCurve: BezierCurve,\n\tArc: Arc,\n\tIncrementalDisplayable: IncrementalDisplayble,\n\tCompoundPath: CompoundPath,\n\tLinearGradient: LinearGradient,\n\tRadialGradient: RadialGradient,\n\tBoundingRect: BoundingRect\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PATH_COLOR = ['textStyle', 'color'];\n\nvar textStyleMixin = {\n    /**\n     * Get color property or get color from option.textStyle.color\n     * @param {boolean} [isEmphasis]\n     * @return {string}\n     */\n    getTextColor: function (isEmphasis) {\n        var ecModel = this.ecModel;\n        return this.getShallow('color')\n            || (\n                (!isEmphasis && ecModel) ? ecModel.get(PATH_COLOR) : null\n            );\n    },\n\n    /**\n     * Create font string from fontStyle, fontWeight, fontSize, fontFamily\n     * @return {string}\n     */\n    getFont: function () {\n        return getFont({\n            fontStyle: this.getShallow('fontStyle'),\n            fontWeight: this.getShallow('fontWeight'),\n            fontSize: this.getShallow('fontSize'),\n            fontFamily: this.getShallow('fontFamily')\n        }, this.ecModel);\n    },\n\n    getTextRect: function (text) {\n        return getBoundingRect(\n            text,\n            this.getFont(),\n            this.getShallow('align'),\n            this.getShallow('verticalAlign') || this.getShallow('baseline'),\n            this.getShallow('padding'),\n            this.getShallow('lineHeight'),\n            this.getShallow('rich'),\n            this.getShallow('truncateText')\n        );\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getItemStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['stroke', 'borderColor'],\n        ['lineWidth', 'borderWidth'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor'],\n        ['textPosition'],\n        ['textAlign']\n    ]\n);\n\nvar itemStyleMixin = {\n    getItemStyle: function (excludes, includes) {\n        var style = getItemStyle(this, excludes, includes);\n        var lineDash = this.getBorderLineDash();\n        lineDash && (style.lineDash = lineDash);\n        return style;\n    },\n\n    getBorderLineDash: function () {\n        var lineType = this.get('borderType');\n        return (lineType === 'solid' || lineType == null) ? null\n            : (lineType === 'dashed' ? [5, 5] : [1, 1]);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/model/Model\n */\n\nvar mixin$1 = mixin;\nvar inner = makeInner();\n\n/**\n * @alias module:echarts/model/Model\n * @constructor\n * @param {Object} [option]\n * @param {module:echarts/model/Model} [parentModel]\n * @param {module:echarts/model/Global} [ecModel]\n */\nfunction Model(option, parentModel, ecModel) {\n    /**\n     * @type {module:echarts/model/Model}\n     * @readOnly\n     */\n    this.parentModel = parentModel;\n\n    /**\n     * @type {module:echarts/model/Global}\n     * @readOnly\n     */\n    this.ecModel = ecModel;\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    this.option = option;\n\n    // Simple optimization\n    // if (this.init) {\n    //     if (arguments.length <= 4) {\n    //         this.init(option, parentModel, ecModel, extraOpt);\n    //     }\n    //     else {\n    //         this.init.apply(this, arguments);\n    //     }\n    // }\n}\n\nModel.prototype = {\n\n    constructor: Model,\n\n    /**\n     * Model 的初始化函数\n     * @param {Object} option\n     */\n    init: null,\n\n    /**\n     * 从新的 Option merge\n     */\n    mergeOption: function (option) {\n        merge(this.option, option, true);\n    },\n\n    /**\n     * @param {string|Array.<string>} path\n     * @param {boolean} [ignoreParent=false]\n     * @return {*}\n     */\n    get: function (path, ignoreParent) {\n        if (path == null) {\n            return this.option;\n        }\n\n        return doGet(\n            this.option,\n            this.parsePath(path),\n            !ignoreParent && getParent(this, path)\n        );\n    },\n\n    /**\n     * @param {string} key\n     * @param {boolean} [ignoreParent=false]\n     * @return {*}\n     */\n    getShallow: function (key, ignoreParent) {\n        var option = this.option;\n\n        var val = option == null ? option : option[key];\n        var parentModel = !ignoreParent && getParent(this, key);\n        if (val == null && parentModel) {\n            val = parentModel.getShallow(key);\n        }\n        return val;\n    },\n\n    /**\n     * @param {string|Array.<string>} [path]\n     * @param {module:echarts/model/Model} [parentModel]\n     * @return {module:echarts/model/Model}\n     */\n    getModel: function (path, parentModel) {\n        var obj = path == null\n            ? this.option\n            : doGet(this.option, path = this.parsePath(path));\n\n        var thisParentModel;\n        parentModel = parentModel || (\n            (thisParentModel = getParent(this, path))\n                && thisParentModel.getModel(path)\n        );\n\n        return new Model(obj, parentModel, this.ecModel);\n    },\n\n    /**\n     * If model has option\n     */\n    isEmpty: function () {\n        return this.option == null;\n    },\n\n    restoreData: function () {},\n\n    // Pending\n    clone: function () {\n        var Ctor = this.constructor;\n        return new Ctor(clone(this.option));\n    },\n\n    setReadOnly: function (properties) {\n        // clazzUtil.setReadOnly(this, properties);\n    },\n\n    // If path is null/undefined, return null/undefined.\n    parsePath: function (path) {\n        if (typeof path === 'string') {\n            path = path.split('.');\n        }\n        return path;\n    },\n\n    /**\n     * @param {Function} getParentMethod\n     *        param {Array.<string>|string} path\n     *        return {module:echarts/model/Model}\n     */\n    customizeGetParent: function (getParentMethod) {\n        inner(this).getParent = getParentMethod;\n    },\n\n    isAnimationEnabled: function () {\n        if (!env$1.node) {\n            if (this.option.animation != null) {\n                return !!this.option.animation;\n            }\n            else if (this.parentModel) {\n                return this.parentModel.isAnimationEnabled();\n            }\n        }\n    }\n\n};\n\nfunction doGet(obj, pathArr, parentModel) {\n    for (var i = 0; i < pathArr.length; i++) {\n        // Ignore empty\n        if (!pathArr[i]) {\n            continue;\n        }\n        // obj could be number/string/... (like 0)\n        obj = (obj && typeof obj === 'object') ? obj[pathArr[i]] : null;\n        if (obj == null) {\n            break;\n        }\n    }\n    if (obj == null && parentModel) {\n        obj = parentModel.get(pathArr);\n    }\n    return obj;\n}\n\n// `path` can be null/undefined\nfunction getParent(model, path) {\n    var getParentMethod = inner(model).getParent;\n    return getParentMethod ? getParentMethod.call(model, path) : model.parentModel;\n}\n\n// Enable Model.extend.\nenableClassExtend(Model);\nenableClassCheck(Model);\n\nmixin$1(Model, lineStyleMixin);\nmixin$1(Model, areaStyleMixin);\nmixin$1(Model, textStyleMixin);\nmixin$1(Model, itemStyleMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar base = 0;\n\n/**\n * @public\n * @param {string} type\n * @return {string}\n */\nfunction getUID(type) {\n    // Considering the case of crossing js context,\n    // use Math.random to make id as unique as possible.\n    return [(type || ''), base++, Math.random().toFixed(5)].join('_');\n}\n\n/**\n * @inner\n */\nfunction enableSubTypeDefaulter(entity) {\n\n    var subTypeDefaulters = {};\n\n    entity.registerSubTypeDefaulter = function (componentType, defaulter) {\n        componentType = parseClassType$1(componentType);\n        subTypeDefaulters[componentType.main] = defaulter;\n    };\n\n    entity.determineSubType = function (componentType, option) {\n        var type = option.type;\n        if (!type) {\n            var componentTypeMain = parseClassType$1(componentType).main;\n            if (entity.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) {\n                type = subTypeDefaulters[componentTypeMain](option);\n            }\n        }\n        return type;\n    };\n\n    return entity;\n}\n\n/**\n * Topological travel on Activity Network (Activity On Vertices).\n * Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis'].\n *\n * If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology.\n *\n * If there is circle dependencey, Error will be thrown.\n *\n */\nfunction enableTopologicalTravel(entity, dependencyGetter) {\n\n    /**\n     * @public\n     * @param {Array.<string>} targetNameList Target Component type list.\n     *                                           Can be ['aa', 'bb', 'aa.xx']\n     * @param {Array.<string>} fullNameList By which we can build dependency graph.\n     * @param {Function} callback Params: componentType, dependencies.\n     * @param {Object} context Scope of callback.\n     */\n    entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) {\n        if (!targetNameList.length) {\n            return;\n        }\n\n        var result = makeDepndencyGraph(fullNameList);\n        var graph = result.graph;\n        var stack = result.noEntryList;\n\n        var targetNameSet = {};\n        each$1(targetNameList, function (name) {\n            targetNameSet[name] = true;\n        });\n\n        while (stack.length) {\n            var currComponentType = stack.pop();\n            var currVertex = graph[currComponentType];\n            var isInTargetNameSet = !!targetNameSet[currComponentType];\n            if (isInTargetNameSet) {\n                callback.call(context, currComponentType, currVertex.originalDeps.slice());\n                delete targetNameSet[currComponentType];\n            }\n            each$1(\n                currVertex.successor,\n                isInTargetNameSet ? removeEdgeAndAdd : removeEdge\n            );\n        }\n\n        each$1(targetNameSet, function () {\n            throw new Error('Circle dependency may exists');\n        });\n\n        function removeEdge(succComponentType) {\n            graph[succComponentType].entryCount--;\n            if (graph[succComponentType].entryCount === 0) {\n                stack.push(succComponentType);\n            }\n        }\n\n        // Consider this case: legend depends on series, and we call\n        // chart.setOption({series: [...]}), where only series is in option.\n        // If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will\n        // not be called, but only sereis.mergeOption is called. Thus legend\n        // have no chance to update its local record about series (like which\n        // name of series is available in legend).\n        function removeEdgeAndAdd(succComponentType) {\n            targetNameSet[succComponentType] = true;\n            removeEdge(succComponentType);\n        }\n    };\n\n    /**\n     * DepndencyGraph: {Object}\n     * key: conponentType,\n     * value: {\n     *     successor: [conponentTypes...],\n     *     originalDeps: [conponentTypes...],\n     *     entryCount: {number}\n     * }\n     */\n    function makeDepndencyGraph(fullNameList) {\n        var graph = {};\n        var noEntryList = [];\n\n        each$1(fullNameList, function (name) {\n\n            var thisItem = createDependencyGraphItem(graph, name);\n            var originalDeps = thisItem.originalDeps = dependencyGetter(name);\n\n            var availableDeps = getAvailableDependencies(originalDeps, fullNameList);\n            thisItem.entryCount = availableDeps.length;\n            if (thisItem.entryCount === 0) {\n                noEntryList.push(name);\n            }\n\n            each$1(availableDeps, function (dependentName) {\n                if (indexOf(thisItem.predecessor, dependentName) < 0) {\n                    thisItem.predecessor.push(dependentName);\n                }\n                var thatItem = createDependencyGraphItem(graph, dependentName);\n                if (indexOf(thatItem.successor, dependentName) < 0) {\n                    thatItem.successor.push(name);\n                }\n            });\n        });\n\n        return {graph: graph, noEntryList: noEntryList};\n    }\n\n    function createDependencyGraphItem(graph, name) {\n        if (!graph[name]) {\n            graph[name] = {predecessor: [], successor: []};\n        }\n        return graph[name];\n    }\n\n    function getAvailableDependencies(originalDeps, fullNameList) {\n        var availableDeps = [];\n        each$1(originalDeps, function (dep) {\n            indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep);\n        });\n        return availableDeps;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The method \"quantile\" was copied from \"d3.js\".\n* (See more details in the comment of the method below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\nvar RADIAN_EPSILON = 1e-4;\n\nfunction _trim(str) {\n    return str.replace(/^\\s+/, '').replace(/\\s+$/, '');\n}\n\n/**\n * Linear mapping a value from domain to range\n * @memberOf module:echarts/util/number\n * @param  {(number|Array.<number>)} val\n * @param  {Array.<number>} domain Domain extent domain[0] can be bigger than domain[1]\n * @param  {Array.<number>} range  Range extent range[0] can be bigger than range[1]\n * @param  {boolean} clamp\n * @return {(number|Array.<number>}\n */\nfunction linearMap(val, domain, range, clamp) {\n    var subDomain = domain[1] - domain[0];\n    var subRange = range[1] - range[0];\n\n    if (subDomain === 0) {\n        return subRange === 0\n            ? range[0]\n            : (range[0] + range[1]) / 2;\n    }\n\n    // Avoid accuracy problem in edge, such as\n    // 146.39 - 62.83 === 83.55999999999999.\n    // See echarts/test/ut/spec/util/number.js#linearMap#accuracyError\n    // It is a little verbose for efficiency considering this method\n    // is a hotspot.\n    if (clamp) {\n        if (subDomain > 0) {\n            if (val <= domain[0]) {\n                return range[0];\n            }\n            else if (val >= domain[1]) {\n                return range[1];\n            }\n        }\n        else {\n            if (val >= domain[0]) {\n                return range[0];\n            }\n            else if (val <= domain[1]) {\n                return range[1];\n            }\n        }\n    }\n    else {\n        if (val === domain[0]) {\n            return range[0];\n        }\n        if (val === domain[1]) {\n            return range[1];\n        }\n    }\n\n    return (val - domain[0]) / subDomain * subRange + range[0];\n}\n\n/**\n * Convert a percent string to absolute number.\n * Returns NaN if percent is not a valid string or number\n * @memberOf module:echarts/util/number\n * @param {string|number} percent\n * @param {number} all\n * @return {number}\n */\nfunction parsePercent$1(percent, all) {\n    switch (percent) {\n        case 'center':\n        case 'middle':\n            percent = '50%';\n            break;\n        case 'left':\n        case 'top':\n            percent = '0%';\n            break;\n        case 'right':\n        case 'bottom':\n            percent = '100%';\n            break;\n    }\n    if (typeof percent === 'string') {\n        if (_trim(percent).match(/%$/)) {\n            return parseFloat(percent) / 100 * all;\n        }\n\n        return parseFloat(percent);\n    }\n\n    return percent == null ? NaN : +percent;\n}\n\n/**\n * (1) Fix rounding error of float numbers.\n * (2) Support return string to avoid scientific notation like '3.5e-7'.\n *\n * @param {number} x\n * @param {number} [precision]\n * @param {boolean} [returnStr]\n * @return {number|string}\n */\nfunction round$2(x, precision, returnStr) {\n    if (precision == null) {\n        precision = 10;\n    }\n    // Avoid range error\n    precision = Math.min(Math.max(0, precision), 20);\n    x = (+x).toFixed(precision);\n    return returnStr ? x : +x;\n}\n\n\n\n/**\n * Get precision\n * @param {number} val\n */\n\n\n/**\n * @param {string|number} val\n * @return {number}\n */\nfunction getPrecisionSafe(val) {\n    var str = val.toString();\n\n    // Consider scientific notation: '3.4e-12' '3.4e+12'\n    var eIndex = str.indexOf('e');\n    if (eIndex > 0) {\n        var precision = +str.slice(eIndex + 1);\n        return precision < 0 ? -precision : 0;\n    }\n    else {\n        var dotIndex = str.indexOf('.');\n        return dotIndex < 0 ? 0 : str.length - 1 - dotIndex;\n    }\n}\n\n/**\n * Minimal dicernible data precisioin according to a single pixel.\n *\n * @param {Array.<number>} dataExtent\n * @param {Array.<number>} pixelExtent\n * @return {number} precision\n */\nfunction getPixelPrecision(dataExtent, pixelExtent) {\n    var log = Math.log;\n    var LN10 = Math.LN10;\n    var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10);\n    var sizeQuantity = Math.round(log(Math.abs(pixelExtent[1] - pixelExtent[0])) / LN10);\n    // toFixed() digits argument must be between 0 and 20.\n    var precision = Math.min(Math.max(-dataQuantity + sizeQuantity, 0), 20);\n    return !isFinite(precision) ? 20 : precision;\n}\n\n/**\n * Get a data of given precision, assuring the sum of percentages\n * in valueList is 1.\n * The largest remainer method is used.\n * https://en.wikipedia.org/wiki/Largest_remainder_method\n *\n * @param {Array.<number>} valueList a list of all data\n * @param {number} idx index of the data to be processed in valueList\n * @param {number} precision integer number showing digits of precision\n * @return {number} percent ranging from 0 to 100\n */\nfunction getPercentWithPrecision(valueList, idx, precision) {\n    if (!valueList[idx]) {\n        return 0;\n    }\n\n    var sum = reduce(valueList, function (acc, val) {\n        return acc + (isNaN(val) ? 0 : val);\n    }, 0);\n    if (sum === 0) {\n        return 0;\n    }\n\n    var digits = Math.pow(10, precision);\n    var votesPerQuota = map(valueList, function (val) {\n        return (isNaN(val) ? 0 : val) / sum * digits * 100;\n    });\n    var targetSeats = digits * 100;\n\n    var seats = map(votesPerQuota, function (votes) {\n        // Assign automatic seats.\n        return Math.floor(votes);\n    });\n    var currentSum = reduce(seats, function (acc, val) {\n        return acc + val;\n    }, 0);\n\n    var remainder = map(votesPerQuota, function (votes, idx) {\n        return votes - seats[idx];\n    });\n\n    // Has remainding votes.\n    while (currentSum < targetSeats) {\n        // Find next largest remainder.\n        var max = Number.NEGATIVE_INFINITY;\n        var maxId = null;\n        for (var i = 0, len = remainder.length; i < len; ++i) {\n            if (remainder[i] > max) {\n                max = remainder[i];\n                maxId = i;\n            }\n        }\n\n        // Add a vote to max remainder.\n        ++seats[maxId];\n        remainder[maxId] = 0;\n        ++currentSum;\n    }\n\n    return seats[idx] / digits;\n}\n\n// Number.MAX_SAFE_INTEGER, ie do not support.\n\n\n/**\n * To 0 - 2 * PI, considering negative radian.\n * @param {number} radian\n * @return {number}\n */\nfunction remRadian(radian) {\n    var pi2 = Math.PI * 2;\n    return (radian % pi2 + pi2) % pi2;\n}\n\n/**\n * @param {type} radian\n * @return {boolean}\n */\nfunction isRadianAroundZero(val) {\n    return val > -RADIAN_EPSILON && val < RADIAN_EPSILON;\n}\n\n/* eslint-disable */\nvar TIME_REG = /^(?:(\\d{4})(?:[-\\/](\\d{1,2})(?:[-\\/](\\d{1,2})(?:[T ](\\d{1,2})(?::(\\d\\d)(?::(\\d\\d)(?:[.,](\\d+))?)?)?(Z|[\\+\\-]\\d\\d:?\\d\\d)?)?)?)?)?$/; // jshint ignore:line\n/* eslint-enable */\n\n/**\n * @param {string|Date|number} value These values can be accepted:\n *   + An instance of Date, represent a time in its own time zone.\n *   + Or string in a subset of ISO 8601, only including:\n *     + only year, month, date: '2012-03', '2012-03-01', '2012-03-01 05', '2012-03-01 05:06',\n *     + separated with T or space: '2012-03-01T12:22:33.123', '2012-03-01 12:22:33.123',\n *     + time zone: '2012-03-01T12:22:33Z', '2012-03-01T12:22:33+8000', '2012-03-01T12:22:33-05:00',\n *     all of which will be treated as local time if time zone is not specified\n *     (see <https://momentjs.com/>).\n *   + Or other string format, including (all of which will be treated as loacal time):\n *     '2012', '2012-3-1', '2012/3/1', '2012/03/01',\n *     '2009/6/12 2:00', '2009/6/12 2:05:08', '2009/6/12 2:05:08.123'\n *   + a timestamp, which represent a time in UTC.\n * @return {Date} date\n */\nfunction parseDate(value) {\n    if (value instanceof Date) {\n        return value;\n    }\n    else if (typeof value === 'string') {\n        // Different browsers parse date in different way, so we parse it manually.\n        // Some other issues:\n        // new Date('1970-01-01') is UTC,\n        // new Date('1970/01/01') and new Date('1970-1-01') is local.\n        // See issue #3623\n        var match = TIME_REG.exec(value);\n\n        if (!match) {\n            // return Invalid Date.\n            return new Date(NaN);\n        }\n\n        // Use local time when no timezone offset specifed.\n        if (!match[8]) {\n            // match[n] can only be string or undefined.\n            // But take care of '12' + 1 => '121'.\n            return new Date(\n                +match[1],\n                +(match[2] || 1) - 1,\n                +match[3] || 1,\n                +match[4] || 0,\n                +(match[5] || 0),\n                +match[6] || 0,\n                +match[7] || 0\n            );\n        }\n        // Timezoneoffset of Javascript Date has considered DST (Daylight Saving Time,\n        // https://tc39.github.io/ecma262/#sec-daylight-saving-time-adjustment).\n        // For example, system timezone is set as \"Time Zone: America/Toronto\",\n        // then these code will get different result:\n        // `new Date(1478411999999).getTimezoneOffset();  // get 240`\n        // `new Date(1478412000000).getTimezoneOffset();  // get 300`\n        // So we should not use `new Date`, but use `Date.UTC`.\n        else {\n            var hour = +match[4] || 0;\n            if (match[8].toUpperCase() !== 'Z') {\n                hour -= match[8].slice(0, 3);\n            }\n            return new Date(Date.UTC(\n                +match[1],\n                +(match[2] || 1) - 1,\n                +match[3] || 1,\n                hour,\n                +(match[5] || 0),\n                +match[6] || 0,\n                +match[7] || 0\n            ));\n        }\n    }\n    else if (value == null) {\n        return new Date(NaN);\n    }\n\n    return new Date(Math.round(value));\n}\n\n/**\n * Quantity of a number. e.g. 0.1, 1, 10, 100\n *\n * @param  {number} val\n * @return {number}\n */\nfunction quantity(val) {\n    return Math.pow(10, quantityExponent(val));\n}\n\nfunction quantityExponent(val) {\n    return Math.floor(Math.log(val) / Math.LN10);\n}\n\n/**\n * find a “nice” number approximately equal to x. Round the number if round = true,\n * take ceiling if round = false. The primary observation is that the “nicest”\n * numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers.\n *\n * See \"Nice Numbers for Graph Labels\" of Graphic Gems.\n *\n * @param  {number} val Non-negative value.\n * @param  {boolean} round\n * @return {number}\n */\nfunction nice(val, round) {\n    var exponent = quantityExponent(val);\n    var exp10 = Math.pow(10, exponent);\n    var f = val / exp10; // 1 <= f < 10\n    var nf;\n    if (round) {\n        if (f < 1.5) {\n            nf = 1;\n        }\n        else if (f < 2.5) {\n            nf = 2;\n        }\n        else if (f < 4) {\n            nf = 3;\n        }\n        else if (f < 7) {\n            nf = 5;\n        }\n        else {\n            nf = 10;\n        }\n    }\n    else {\n        if (f < 1) {\n            nf = 1;\n        }\n        else if (f < 2) {\n            nf = 2;\n        }\n        else if (f < 3) {\n            nf = 3;\n        }\n        else if (f < 5) {\n            nf = 5;\n        }\n        else {\n            nf = 10;\n        }\n    }\n    val = nf * exp10;\n\n    // Fix 3 * 0.1 === 0.30000000000000004 issue (see IEEE 754).\n    // 20 is the uppper bound of toFixed.\n    return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val;\n}\n\n/**\n * This code was copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/9cc9a875e636a1dcf36cc1e07bdf77e1ad6e2c74/src/arrays/quantile.js>.\n * See the license statement at the head of this file.\n * @param {Array.<number>} ascArr\n */\n\n\n/**\n * Order intervals asc, and split them when overlap.\n * expect(numberUtil.reformIntervals([\n *     {interval: [18, 62], close: [1, 1]},\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [1, 1]},\n *     {interval: [62, 150], close: [1, 1]},\n *     {interval: [106, 150], close: [1, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ])).toEqual([\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [0, 1]},\n *     {interval: [18, 62], close: [0, 1]},\n *     {interval: [62, 150], close: [0, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ]);\n * @param {Array.<Object>} list, where `close` mean open or close\n *        of the interval, and Infinity can be used.\n * @return {Array.<Object>} The origin list, which has been reformed.\n */\n\n\n/**\n * parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n * ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n * subtraction forces infinities to NaN\n *\n * @param {*} v\n * @return {boolean}\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import Text from 'zrender/src/graphic/Text';\n\n/**\n * 每三位默认加,格式化\n * @param {string|number} x\n * @return {string}\n */\nfunction addCommas(x) {\n    if (isNaN(x)) {\n        return '-';\n    }\n    x = (x + '').split('.');\n    return x[0].replace(/(\\d{1,3})(?=(?:\\d{3})+(?!\\d))/g, '$1,')\n            + (x.length > 1 ? ('.' + x[1]) : '');\n}\n\n/**\n * @param {string} str\n * @param {boolean} [upperCaseFirst=false]\n * @return {string} str\n */\n\n\nvar normalizeCssArray$1 = normalizeCssArray;\n\n\nvar replaceReg = /([&<>\"'])/g;\nvar replaceMap = {\n    '&': '&amp;',\n    '<': '&lt;',\n    '>': '&gt;',\n    '\"': '&quot;',\n    '\\'': '&#39;'\n};\n\nfunction encodeHTML(source) {\n    return source == null\n        ? ''\n        : (source + '').replace(replaceReg, function (str, c) {\n            return replaceMap[c];\n        });\n}\n\nvar TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];\n\nvar wrapVar = function (varName, seriesIdx) {\n    return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}';\n};\n\n/**\n * Template formatter\n * @param {string} tpl\n * @param {Array.<Object>|Object} paramsList\n * @param {boolean} [encode=false]\n * @return {string}\n */\nfunction formatTpl(tpl, paramsList, encode) {\n    if (!isArray(paramsList)) {\n        paramsList = [paramsList];\n    }\n    var seriesLen = paramsList.length;\n    if (!seriesLen) {\n        return '';\n    }\n\n    var $vars = paramsList[0].$vars || [];\n    for (var i = 0; i < $vars.length; i++) {\n        var alias = TPL_VAR_ALIAS[i];\n        tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0));\n    }\n    for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) {\n        for (var k = 0; k < $vars.length; k++) {\n            var val = paramsList[seriesIdx][$vars[k]];\n            tpl = tpl.replace(\n                wrapVar(TPL_VAR_ALIAS[k], seriesIdx),\n                encode ? encodeHTML(val) : val\n            );\n        }\n    }\n\n    return tpl;\n}\n\n/**\n * simple Template formatter\n *\n * @param {string} tpl\n * @param {Object} param\n * @param {boolean} [encode=false]\n * @return {string}\n */\n\n\n/**\n * @param {Object|string} [opt] If string, means color.\n * @param {string} [opt.color]\n * @param {string} [opt.extraCssText]\n * @param {string} [opt.type='item'] 'item' or 'subItem'\n * @param {string} [opt.renderMode='html'] render mode of tooltip, 'html' or 'richText'\n * @param {string} [opt.markerId='X'] id name for marker. If only one marker is in a rich text, this can be omitted.\n * @return {string}\n */\nfunction getTooltipMarker(opt, extraCssText) {\n    opt = isString(opt) ? {color: opt, extraCssText: extraCssText} : (opt || {});\n    var color = opt.color;\n    var type = opt.type;\n    var extraCssText = opt.extraCssText;\n    var renderMode = opt.renderMode || 'html';\n    var markerId = opt.markerId || 'X';\n\n    if (!color) {\n        return '';\n    }\n\n    if (renderMode === 'html') {\n        return type === 'subItem'\n        ? '<span style=\"display:inline-block;vertical-align:middle;margin-right:8px;margin-left:3px;'\n            + 'border-radius:4px;width:4px;height:4px;background-color:'\n            + encodeHTML(color) + ';' + (extraCssText || '') + '\"></span>'\n        : '<span style=\"display:inline-block;margin-right:5px;'\n            + 'border-radius:10px;width:10px;height:10px;background-color:'\n            + encodeHTML(color) + ';' + (extraCssText || '') + '\"></span>';\n    }\n    else {\n        // Space for rich element marker\n        return {\n            renderMode: renderMode,\n            content: '{marker' + markerId + '|}  ',\n            style: {\n                color: color\n            }\n        };\n    }\n}\n\nfunction pad(str, len) {\n    str += '';\n    return '0000'.substr(0, len - str.length) + str;\n}\n\n\n/**\n * ISO Date format\n * @param {string} tpl\n * @param {number} value\n * @param {boolean} [isUTC=false] Default in local time.\n *           see `module:echarts/scale/Time`\n *           and `module:echarts/util/number#parseDate`.\n * @inner\n */\nfunction formatTime(tpl, value, isUTC) {\n    if (tpl === 'week'\n        || tpl === 'month'\n        || tpl === 'quarter'\n        || tpl === 'half-year'\n        || tpl === 'year'\n    ) {\n        tpl = 'MM-dd\\nyyyy';\n    }\n\n    var date = parseDate(value);\n    var utc = isUTC ? 'UTC' : '';\n    var y = date['get' + utc + 'FullYear']();\n    var M = date['get' + utc + 'Month']() + 1;\n    var d = date['get' + utc + 'Date']();\n    var h = date['get' + utc + 'Hours']();\n    var m = date['get' + utc + 'Minutes']();\n    var s = date['get' + utc + 'Seconds']();\n    var S = date['get' + utc + 'Milliseconds']();\n\n    tpl = tpl.replace('MM', pad(M, 2))\n        .replace('M', M)\n        .replace('yyyy', y)\n        .replace('yy', y % 100)\n        .replace('dd', pad(d, 2))\n        .replace('d', d)\n        .replace('hh', pad(h, 2))\n        .replace('h', h)\n        .replace('mm', pad(m, 2))\n        .replace('m', m)\n        .replace('ss', pad(s, 2))\n        .replace('s', s)\n        .replace('SSS', pad(S, 3));\n\n    return tpl;\n}\n\n/**\n * Capital first\n * @param {string} str\n * @return {string}\n */\n\n\nvar truncateText$1 = truncateText;\n\n/**\n * @public\n * @param {Object} opt\n * @param {string} opt.text\n * @param {string} opt.font\n * @param {string} [opt.textAlign='left']\n * @param {string} [opt.textVerticalAlign='top']\n * @param {Array.<number>} [opt.textPadding]\n * @param {number} [opt.textLineHeight]\n * @param {Object} [opt.rich]\n * @param {Object} [opt.truncate]\n * @return {Object} {x, y, width, height, lineHeight}\n */\n\n\n/**\n * @deprecated\n * the `textLineHeight` was added later.\n * For backward compatiblility, put it as the last parameter.\n * But deprecated this interface. Please use `getTextBoundingRect` instead.\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Layout helpers for each component positioning\n\nvar each$3 = each$1;\n\n/**\n * @public\n */\nvar LOCATION_PARAMS = [\n    'left', 'right', 'top', 'bottom', 'width', 'height'\n];\n\n/**\n * @public\n */\nvar HV_NAMES = [\n    ['width', 'left', 'right'],\n    ['height', 'top', 'bottom']\n];\n\nfunction boxLayout(orient, group, gap, maxWidth, maxHeight) {\n    var x = 0;\n    var y = 0;\n\n    if (maxWidth == null) {\n        maxWidth = Infinity;\n    }\n    if (maxHeight == null) {\n        maxHeight = Infinity;\n    }\n    var currentLineMaxSize = 0;\n\n    group.eachChild(function (child, idx) {\n        var position = child.position;\n        var rect = child.getBoundingRect();\n        var nextChild = group.childAt(idx + 1);\n        var nextChildRect = nextChild && nextChild.getBoundingRect();\n        var nextX;\n        var nextY;\n\n        if (orient === 'horizontal') {\n            var moveX = rect.width + (nextChildRect ? (-nextChildRect.x + rect.x) : 0);\n            nextX = x + moveX;\n            // Wrap when width exceeds maxWidth or meet a `newline` group\n            // FIXME compare before adding gap?\n            if (nextX > maxWidth || child.newline) {\n                x = 0;\n                nextX = moveX;\n                y += currentLineMaxSize + gap;\n                currentLineMaxSize = rect.height;\n            }\n            else {\n                // FIXME: consider rect.y is not `0`?\n                currentLineMaxSize = Math.max(currentLineMaxSize, rect.height);\n            }\n        }\n        else {\n            var moveY = rect.height + (nextChildRect ? (-nextChildRect.y + rect.y) : 0);\n            nextY = y + moveY;\n            // Wrap when width exceeds maxHeight or meet a `newline` group\n            if (nextY > maxHeight || child.newline) {\n                x += currentLineMaxSize + gap;\n                y = 0;\n                nextY = moveY;\n                currentLineMaxSize = rect.width;\n            }\n            else {\n                currentLineMaxSize = Math.max(currentLineMaxSize, rect.width);\n            }\n        }\n\n        if (child.newline) {\n            return;\n        }\n\n        position[0] = x;\n        position[1] = y;\n\n        orient === 'horizontal'\n            ? (x = nextX + gap)\n            : (y = nextY + gap);\n    });\n}\n\n/**\n * VBox or HBox layouting\n * @param {string} orient\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\n\n\n/**\n * VBox layouting\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar vbox = curry(boxLayout, 'vertical');\n\n/**\n * HBox layouting\n * @param {module:zrender/container/Group} group\n * @param {number} gap\n * @param {number} [width=Infinity]\n * @param {number} [height=Infinity]\n */\nvar hbox = curry(boxLayout, 'horizontal');\n\n/**\n * If x or x2 is not specified or 'center' 'left' 'right',\n * the width would be as long as possible.\n * If y or y2 is not specified or 'middle' 'top' 'bottom',\n * the height would be as long as possible.\n *\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.x]\n * @param {number|string} [positionInfo.y]\n * @param {number|string} [positionInfo.x2]\n * @param {number|string} [positionInfo.y2]\n * @param {Object} containerRect {width, height}\n * @param {string|number} margin\n * @return {Object} {width, height}\n */\n\n\n/**\n * Parse position info.\n *\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.left]\n * @param {number|string} [positionInfo.top]\n * @param {number|string} [positionInfo.right]\n * @param {number|string} [positionInfo.bottom]\n * @param {number|string} [positionInfo.width]\n * @param {number|string} [positionInfo.height]\n * @param {number|string} [positionInfo.aspect] Aspect is width / height\n * @param {Object} containerRect\n * @param {string|number} [margin]\n *\n * @return {module:zrender/core/BoundingRect}\n */\nfunction getLayoutRect(\n    positionInfo, containerRect, margin\n) {\n    margin = normalizeCssArray$1(margin || 0);\n\n    var containerWidth = containerRect.width;\n    var containerHeight = containerRect.height;\n\n    var left = parsePercent$1(positionInfo.left, containerWidth);\n    var top = parsePercent$1(positionInfo.top, containerHeight);\n    var right = parsePercent$1(positionInfo.right, containerWidth);\n    var bottom = parsePercent$1(positionInfo.bottom, containerHeight);\n    var width = parsePercent$1(positionInfo.width, containerWidth);\n    var height = parsePercent$1(positionInfo.height, containerHeight);\n\n    var verticalMargin = margin[2] + margin[0];\n    var horizontalMargin = margin[1] + margin[3];\n    var aspect = positionInfo.aspect;\n\n    // If width is not specified, calculate width from left and right\n    if (isNaN(width)) {\n        width = containerWidth - right - horizontalMargin - left;\n    }\n    if (isNaN(height)) {\n        height = containerHeight - bottom - verticalMargin - top;\n    }\n\n    if (aspect != null) {\n        // If width and height are not given\n        // 1. Graph should not exceeds the container\n        // 2. Aspect must be keeped\n        // 3. Graph should take the space as more as possible\n        // FIXME\n        // Margin is not considered, because there is no case that both\n        // using margin and aspect so far.\n        if (isNaN(width) && isNaN(height)) {\n            if (aspect > containerWidth / containerHeight) {\n                width = containerWidth * 0.8;\n            }\n            else {\n                height = containerHeight * 0.8;\n            }\n        }\n\n        // Calculate width or height with given aspect\n        if (isNaN(width)) {\n            width = aspect * height;\n        }\n        if (isNaN(height)) {\n            height = width / aspect;\n        }\n    }\n\n    // If left is not specified, calculate left from right and width\n    if (isNaN(left)) {\n        left = containerWidth - right - width - horizontalMargin;\n    }\n    if (isNaN(top)) {\n        top = containerHeight - bottom - height - verticalMargin;\n    }\n\n    // Align left and top\n    switch (positionInfo.left || positionInfo.right) {\n        case 'center':\n            left = containerWidth / 2 - width / 2 - margin[3];\n            break;\n        case 'right':\n            left = containerWidth - width - horizontalMargin;\n            break;\n    }\n    switch (positionInfo.top || positionInfo.bottom) {\n        case 'middle':\n        case 'center':\n            top = containerHeight / 2 - height / 2 - margin[0];\n            break;\n        case 'bottom':\n            top = containerHeight - height - verticalMargin;\n            break;\n    }\n    // If something is wrong and left, top, width, height are calculated as NaN\n    left = left || 0;\n    top = top || 0;\n    if (isNaN(width)) {\n        // Width may be NaN if only one value is given except width\n        width = containerWidth - horizontalMargin - left - (right || 0);\n    }\n    if (isNaN(height)) {\n        // Height may be NaN if only one value is given except height\n        height = containerHeight - verticalMargin - top - (bottom || 0);\n    }\n\n    var rect = new BoundingRect(left + margin[3], top + margin[0], width, height);\n    rect.margin = margin;\n    return rect;\n}\n\n\n/**\n * Position a zr element in viewport\n *  Group position is specified by either\n *  {left, top}, {right, bottom}\n *  If all properties exists, right and bottom will be igonred.\n *\n * Logic:\n *     1. Scale (against origin point in parent coord)\n *     2. Rotate (against origin point in parent coord)\n *     3. Traslate (with el.position by this method)\n * So this method only fixes the last step 'Traslate', which does not affect\n * scaling and rotating.\n *\n * If be called repeatly with the same input el, the same result will be gotten.\n *\n * @param {module:zrender/Element} el Should have `getBoundingRect` method.\n * @param {Object} positionInfo\n * @param {number|string} [positionInfo.left]\n * @param {number|string} [positionInfo.top]\n * @param {number|string} [positionInfo.right]\n * @param {number|string} [positionInfo.bottom]\n * @param {number|string} [positionInfo.width] Only for opt.boundingModel: 'raw'\n * @param {number|string} [positionInfo.height] Only for opt.boundingModel: 'raw'\n * @param {Object} containerRect\n * @param {string|number} margin\n * @param {Object} [opt]\n * @param {Array.<number>} [opt.hv=[1,1]] Only horizontal or only vertical.\n * @param {Array.<number>} [opt.boundingMode='all']\n *        Specify how to calculate boundingRect when locating.\n *        'all': Position the boundingRect that is transformed and uioned\n *               both itself and its descendants.\n *               This mode simplies confine the elements in the bounding\n *               of their container (e.g., using 'right: 0').\n *        'raw': Position the boundingRect that is not transformed and only itself.\n *               This mode is useful when you want a element can overflow its\n *               container. (Consider a rotated circle needs to be located in a corner.)\n *               In this mode positionInfo.width/height can only be number.\n */\n\n\n/**\n * @param {Object} option Contains some of the properties in HV_NAMES.\n * @param {number} hvIdx 0: horizontal; 1: vertical.\n */\n\n\n/**\n * Consider Case:\n * When defulat option has {left: 0, width: 100}, and we set {right: 0}\n * through setOption or media query, using normal zrUtil.merge will cause\n * {right: 0} does not take effect.\n *\n * @example\n * ComponentModel.extend({\n *     init: function () {\n *         ...\n *         var inputPositionParams = layout.getLayoutParams(option);\n *         this.mergeOption(inputPositionParams);\n *     },\n *     mergeOption: function (newOption) {\n *         newOption && zrUtil.merge(thisOption, newOption, true);\n *         layout.mergeLayoutParam(thisOption, newOption);\n *     }\n * });\n *\n * @param {Object} targetOption\n * @param {Object} newOption\n * @param {Object|string} [opt]\n * @param {boolean|Array.<boolean>} [opt.ignoreSize=false] Used for the components\n *  that width (or height) should not be calculated by left and right (or top and bottom).\n */\nfunction mergeLayoutParam(targetOption, newOption, opt) {\n    !isObject$1(opt) && (opt = {});\n\n    var ignoreSize = opt.ignoreSize;\n    !isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]);\n\n    var hResult = merge$$1(HV_NAMES[0], 0);\n    var vResult = merge$$1(HV_NAMES[1], 1);\n\n    copy(HV_NAMES[0], targetOption, hResult);\n    copy(HV_NAMES[1], targetOption, vResult);\n\n    function merge$$1(names, hvIdx) {\n        var newParams = {};\n        var newValueCount = 0;\n        var merged = {};\n        var mergedValueCount = 0;\n        var enoughParamNumber = 2;\n\n        each$3(names, function (name) {\n            merged[name] = targetOption[name];\n        });\n        each$3(names, function (name) {\n            // Consider case: newOption.width is null, which is\n            // set by user for removing width setting.\n            hasProp(newOption, name) && (newParams[name] = merged[name] = newOption[name]);\n            hasValue(newParams, name) && newValueCount++;\n            hasValue(merged, name) && mergedValueCount++;\n        });\n\n        if (ignoreSize[hvIdx]) {\n            // Only one of left/right is premitted to exist.\n            if (hasValue(newOption, names[1])) {\n                merged[names[2]] = null;\n            }\n            else if (hasValue(newOption, names[2])) {\n                merged[names[1]] = null;\n            }\n            return merged;\n        }\n\n        // Case: newOption: {width: ..., right: ...},\n        // or targetOption: {right: ...} and newOption: {width: ...},\n        // There is no conflict when merged only has params count\n        // little than enoughParamNumber.\n        if (mergedValueCount === enoughParamNumber || !newValueCount) {\n            return merged;\n        }\n        // Case: newOption: {width: ..., right: ...},\n        // Than we can make sure user only want those two, and ignore\n        // all origin params in targetOption.\n        else if (newValueCount >= enoughParamNumber) {\n            return newParams;\n        }\n        else {\n            // Chose another param from targetOption by priority.\n            for (var i = 0; i < names.length; i++) {\n                var name = names[i];\n                if (!hasProp(newParams, name) && hasProp(targetOption, name)) {\n                    newParams[name] = targetOption[name];\n                    break;\n                }\n            }\n            return newParams;\n        }\n    }\n\n    function hasProp(obj, name) {\n        return obj.hasOwnProperty(name);\n    }\n\n    function hasValue(obj, name) {\n        return obj[name] != null && obj[name] !== 'auto';\n    }\n\n    function copy(names, target, source) {\n        each$3(names, function (name) {\n            target[name] = source[name];\n        });\n    }\n}\n\n/**\n * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.\n * @param {Object} source\n * @return {Object} Result contains those props.\n */\nfunction getLayoutParams(source) {\n    return copyLayoutParams({}, source);\n}\n\n/**\n * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.\n * @param {Object} source\n * @return {Object} Result contains those props.\n */\nfunction copyLayoutParams(target, source) {\n    source && target && each$3(LOCATION_PARAMS, function (name) {\n        source.hasOwnProperty(name) && (target[name] = source[name]);\n    });\n    return target;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar boxLayoutMixin = {\n    getBoxLayoutParams: function () {\n        return {\n            left: this.get('left'),\n            top: this.get('top'),\n            right: this.get('right'),\n            bottom: this.get('bottom'),\n            width: this.get('width'),\n            height: this.get('height')\n        };\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Component model\n *\n * @module echarts/model/Component\n */\n\nvar inner$1 = makeInner();\n\n/**\n * @alias module:echarts/model/Component\n * @constructor\n * @param {Object} option\n * @param {module:echarts/model/Model} parentModel\n * @param {module:echarts/model/Model} ecModel\n */\nvar ComponentModel = Model.extend({\n\n    type: 'component',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    id: '',\n\n    /**\n     * Because simplified concept is probably better, series.name (or component.name)\n     * has been having too many resposibilities:\n     * (1) Generating id (which requires name in option should not be modified).\n     * (2) As an index to mapping series when merging option or calling API (a name\n     * can refer to more then one components, which is convinient is some case).\n     * (3) Display.\n     * @readOnly\n     */\n    name: '',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    mainType: '',\n\n    /**\n     * @readOnly\n     * @type {string}\n     */\n    subType: '',\n\n    /**\n     * @readOnly\n     * @type {number}\n     */\n    componentIndex: 0,\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    defaultOption: null,\n\n    /**\n     * @type {module:echarts/model/Global}\n     * @readOnly\n     */\n    ecModel: null,\n\n    /**\n     * key: componentType\n     * value:  Component model list, can not be null.\n     * @type {Object.<string, Array.<module:echarts/model/Model>>}\n     * @readOnly\n     */\n    dependentModels: [],\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    uid: null,\n\n    /**\n     * Support merge layout params.\n     * Only support 'box' now (left/right/top/bottom/width/height).\n     * @type {string|Object} Object can be {ignoreSize: true}\n     * @readOnly\n     */\n    layoutMode: null,\n\n    $constructor: function (option, parentModel, ecModel, extraOpt) {\n        Model.call(this, option, parentModel, ecModel, extraOpt);\n\n        this.uid = getUID('ec_cpt_model');\n    },\n\n    init: function (option, parentModel, ecModel, extraOpt) {\n        this.mergeDefaultAndTheme(option, ecModel);\n    },\n\n    mergeDefaultAndTheme: function (option, ecModel) {\n        var layoutMode = this.layoutMode;\n        var inputPositionParams = layoutMode\n            ? getLayoutParams(option) : {};\n\n        var themeModel = ecModel.getTheme();\n        merge(option, themeModel.get(this.mainType));\n        merge(option, this.getDefaultOption());\n\n        if (layoutMode) {\n            mergeLayoutParam(option, inputPositionParams, layoutMode);\n        }\n    },\n\n    mergeOption: function (option, extraOpt) {\n        merge(this.option, option, true);\n\n        var layoutMode = this.layoutMode;\n        if (layoutMode) {\n            mergeLayoutParam(this.option, option, layoutMode);\n        }\n    },\n\n    // Hooker after init or mergeOption\n    optionUpdated: function (newCptOption, isInit) {},\n\n    getDefaultOption: function () {\n        var fields = inner$1(this);\n        if (!fields.defaultOption) {\n            var optList = [];\n            var Class = this.constructor;\n            while (Class) {\n                var opt = Class.prototype.defaultOption;\n                opt && optList.push(opt);\n                Class = Class.superClass;\n            }\n\n            var defaultOption = {};\n            for (var i = optList.length - 1; i >= 0; i--) {\n                defaultOption = merge(defaultOption, optList[i], true);\n            }\n            fields.defaultOption = defaultOption;\n        }\n        return fields.defaultOption;\n    },\n\n    getReferringComponents: function (mainType) {\n        return this.ecModel.queryComponents({\n            mainType: mainType,\n            index: this.get(mainType + 'Index', true),\n            id: this.get(mainType + 'Id', true)\n        });\n    }\n\n});\n\n// Reset ComponentModel.extend, add preConstruct.\n// clazzUtil.enableClassExtend(\n//     ComponentModel,\n//     function (option, parentModel, ecModel, extraOpt) {\n//         // Set dependentModels, componentIndex, name, id, mainType, subType.\n//         zrUtil.extend(this, extraOpt);\n\n//         this.uid = componentUtil.getUID('componentModel');\n\n//         // this.setReadOnly([\n//         //     'type', 'id', 'uid', 'name', 'mainType', 'subType',\n//         //     'dependentModels', 'componentIndex'\n//         // ]);\n//     }\n// );\n\n// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(\n    ComponentModel, {registerWhenExtend: true}\n);\nenableSubTypeDefaulter(ComponentModel);\n\n// Add capability of ComponentModel.topologicalTravel.\nenableTopologicalTravel(ComponentModel, getDependencies);\n\nfunction getDependencies(componentType) {\n    var deps = [];\n    each$1(ComponentModel.getClassesByMainType(componentType), function (Clazz) {\n        deps = deps.concat(Clazz.prototype.dependencies || []);\n    });\n\n    // Ensure main type.\n    deps = map(deps, function (type) {\n        return parseClassType$1(type).main;\n    });\n\n    // Hack dataset for convenience.\n    if (componentType !== 'dataset' && indexOf(deps, 'dataset') <= 0) {\n        deps.unshift('dataset');\n    }\n\n    return deps;\n}\n\nmixin(ComponentModel, boxLayoutMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar platform = '';\n// Navigator not exists in node\nif (typeof navigator !== 'undefined') {\n    platform = navigator.platform || '';\n}\n\nvar globalDefault = {\n    // backgroundColor: 'rgba(0,0,0,0)',\n\n    // https://dribbble.com/shots/1065960-Infographic-Pie-chart-visualization\n    // color: ['#5793f3', '#d14a61', '#fd9c35', '#675bba', '#fec42c', '#dd4444', '#d4df5a', '#cd4870'],\n    // Light colors:\n    // color: ['#bcd3bb', '#e88f70', '#edc1a5', '#9dc5c8', '#e1e8c8', '#7b7c68', '#e5b5b5', '#f0b489', '#928ea8', '#bda29a'],\n    // color: ['#cc5664', '#9bd6ec', '#ea946e', '#8acaaa', '#f1ec64', '#ee8686', '#a48dc1', '#5da6bc', '#b9dcae'],\n    // Dark colors:\n    color: [\n        '#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83',\n        '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'\n    ],\n\n    gradientColor: ['#f6efa6', '#d88273', '#bf444c'],\n\n    // If xAxis and yAxis declared, grid is created by default.\n    // grid: {},\n\n    textStyle: {\n        // color: '#000',\n        // decoration: 'none',\n        // PENDING\n        fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif',\n        // fontFamily: 'Arial, Verdana, sans-serif',\n        fontSize: 12,\n        fontStyle: 'normal',\n        fontWeight: 'normal'\n    },\n\n    // http://blogs.adobe.com/webplatform/2014/02/24/using-blend-modes-in-html-canvas/\n    // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation\n    // Default is source-over\n    blendMode: null,\n\n    animation: 'auto',\n    animationDuration: 1000,\n    animationDurationUpdate: 300,\n    animationEasing: 'exponentialOut',\n    animationEasingUpdate: 'cubicOut',\n\n    animationThreshold: 2000,\n    // Configuration for progressive/incremental rendering\n    progressiveThreshold: 3000,\n    progressive: 400,\n\n    // Threshold of if use single hover layer to optimize.\n    // It is recommended that `hoverLayerThreshold` is equivalent to or less than\n    // `progressiveThreshold`, otherwise hover will cause restart of progressive,\n    // which is unexpected.\n    // see example <echarts/test/heatmap-large.html>.\n    hoverLayerThreshold: 3000,\n\n    // See: module:echarts/scale/Time\n    useUTC: false\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$2 = makeInner();\n\nfunction getNearestColorPalette(colors, requestColorNum) {\n    var paletteNum = colors.length;\n    // TODO colors must be in order\n    for (var i = 0; i < paletteNum; i++) {\n        if (colors[i].length > requestColorNum) {\n            return colors[i];\n        }\n    }\n    return colors[paletteNum - 1];\n}\n\nvar colorPaletteMixin = {\n    clearColorPalette: function () {\n        inner$2(this).colorIdx = 0;\n        inner$2(this).colorNameMap = {};\n    },\n\n    /**\n     * @param {string} name MUST NOT be null/undefined. Otherwise call this function\n     *                 twise with the same parameters will get different result.\n     * @param {Object} [scope=this]\n     * @param {Object} [requestColorNum]\n     * @return {string} color string.\n     */\n    getColorFromPalette: function (name, scope, requestColorNum) {\n        scope = scope || this;\n        var scopeFields = inner$2(scope);\n        var colorIdx = scopeFields.colorIdx || 0;\n        var colorNameMap = scopeFields.colorNameMap = scopeFields.colorNameMap || {};\n        // Use `hasOwnProperty` to avoid conflict with Object.prototype.\n        if (colorNameMap.hasOwnProperty(name)) {\n            return colorNameMap[name];\n        }\n        var defaultColorPalette = normalizeToArray(this.get('color', true));\n        var layeredColorPalette = this.get('colorLayer', true);\n        var colorPalette = ((requestColorNum == null || !layeredColorPalette)\n            ? defaultColorPalette : getNearestColorPalette(layeredColorPalette, requestColorNum));\n\n        // In case can't find in layered color palette.\n        colorPalette = colorPalette || defaultColorPalette;\n\n        if (!colorPalette || !colorPalette.length) {\n            return;\n        }\n\n        var color = colorPalette[colorIdx];\n        if (name) {\n            colorNameMap[name] = color;\n        }\n        scopeFields.colorIdx = (colorIdx + 1) % colorPalette.length;\n\n        return color;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Helper for model references.\n * There are many manners to refer axis/coordSys.\n */\n\n// TODO\n// merge relevant logic to this file?\n// check: \"modelHelper\" of tooltip and \"BrushTargetManager\".\n\n/**\n * @return {Object} For example:\n * {\n *     coordSysName: 'cartesian2d',\n *     coordSysDims: ['x', 'y', ...],\n *     axisMap: HashMap({\n *         x: xAxisModel,\n *         y: yAxisModel\n *     }),\n *     categoryAxisMap: HashMap({\n *         x: xAxisModel,\n *         y: undefined\n *     }),\n *     // It also indicate that whether there is category axis.\n *     firstCategoryDimIndex: 1,\n *     // To replace user specified encode.\n * }\n */\nfunction getCoordSysDefineBySeries(seriesModel) {\n    var coordSysName = seriesModel.get('coordinateSystem');\n    var result = {\n        coordSysName: coordSysName,\n        coordSysDims: [],\n        axisMap: createHashMap(),\n        categoryAxisMap: createHashMap()\n    };\n    var fetch = fetchers[coordSysName];\n    if (fetch) {\n        fetch(seriesModel, result, result.axisMap, result.categoryAxisMap);\n        return result;\n    }\n}\n\nvar fetchers = {\n\n    cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var xAxisModel = seriesModel.getReferringComponents('xAxis')[0];\n        var yAxisModel = seriesModel.getReferringComponents('yAxis')[0];\n\n        if (__DEV__) {\n            if (!xAxisModel) {\n                throw new Error('xAxis \"' + retrieve(\n                    seriesModel.get('xAxisIndex'),\n                    seriesModel.get('xAxisId'),\n                    0\n                ) + '\" not found');\n            }\n            if (!yAxisModel) {\n                throw new Error('yAxis \"' + retrieve(\n                    seriesModel.get('xAxisIndex'),\n                    seriesModel.get('yAxisId'),\n                    0\n                ) + '\" not found');\n            }\n        }\n\n        result.coordSysDims = ['x', 'y'];\n        axisMap.set('x', xAxisModel);\n        axisMap.set('y', yAxisModel);\n\n        if (isCategory(xAxisModel)) {\n            categoryAxisMap.set('x', xAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n        if (isCategory(yAxisModel)) {\n            categoryAxisMap.set('y', yAxisModel);\n            result.firstCategoryDimIndex = 1;\n        }\n    },\n\n    singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var singleAxisModel = seriesModel.getReferringComponents('singleAxis')[0];\n\n        if (__DEV__) {\n            if (!singleAxisModel) {\n                throw new Error('singleAxis should be specified.');\n            }\n        }\n\n        result.coordSysDims = ['single'];\n        axisMap.set('single', singleAxisModel);\n\n        if (isCategory(singleAxisModel)) {\n            categoryAxisMap.set('single', singleAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n    },\n\n    polar: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var polarModel = seriesModel.getReferringComponents('polar')[0];\n        var radiusAxisModel = polarModel.findAxisModel('radiusAxis');\n        var angleAxisModel = polarModel.findAxisModel('angleAxis');\n\n        if (__DEV__) {\n            if (!angleAxisModel) {\n                throw new Error('angleAxis option not found');\n            }\n            if (!radiusAxisModel) {\n                throw new Error('radiusAxis option not found');\n            }\n        }\n\n        result.coordSysDims = ['radius', 'angle'];\n        axisMap.set('radius', radiusAxisModel);\n        axisMap.set('angle', angleAxisModel);\n\n        if (isCategory(radiusAxisModel)) {\n            categoryAxisMap.set('radius', radiusAxisModel);\n            result.firstCategoryDimIndex = 0;\n        }\n        if (isCategory(angleAxisModel)) {\n            categoryAxisMap.set('angle', angleAxisModel);\n            result.firstCategoryDimIndex = 1;\n        }\n    },\n\n    geo: function (seriesModel, result, axisMap, categoryAxisMap) {\n        result.coordSysDims = ['lng', 'lat'];\n    },\n\n    parallel: function (seriesModel, result, axisMap, categoryAxisMap) {\n        var ecModel = seriesModel.ecModel;\n        var parallelModel = ecModel.getComponent(\n            'parallel', seriesModel.get('parallelIndex')\n        );\n        var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice();\n\n        each$1(parallelModel.parallelAxisIndex, function (axisIndex, index) {\n            var axisModel = ecModel.getComponent('parallelAxis', axisIndex);\n            var axisDim = coordSysDims[index];\n            axisMap.set(axisDim, axisModel);\n\n            if (isCategory(axisModel) && result.firstCategoryDimIndex == null) {\n                categoryAxisMap.set(axisDim, axisModel);\n                result.firstCategoryDimIndex = index;\n            }\n        });\n    }\n};\n\nfunction isCategory(axisModel) {\n    return axisModel.get('type') === 'category';\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Avoid typo.\nvar SOURCE_FORMAT_ORIGINAL = 'original';\nvar SOURCE_FORMAT_ARRAY_ROWS = 'arrayRows';\nvar SOURCE_FORMAT_OBJECT_ROWS = 'objectRows';\nvar SOURCE_FORMAT_KEYED_COLUMNS = 'keyedColumns';\nvar SOURCE_FORMAT_UNKNOWN = 'unknown';\n// ??? CHANGE A NAME\nvar SOURCE_FORMAT_TYPED_ARRAY = 'typedArray';\n\nvar SERIES_LAYOUT_BY_COLUMN = 'column';\nvar SERIES_LAYOUT_BY_ROW = 'row';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * [sourceFormat]\n *\n * + \"original\":\n * This format is only used in series.data, where\n * itemStyle can be specified in data item.\n *\n * + \"arrayRows\":\n * [\n *     ['product', 'score', 'amount'],\n *     ['Matcha Latte', 89.3, 95.8],\n *     ['Milk Tea', 92.1, 89.4],\n *     ['Cheese Cocoa', 94.4, 91.2],\n *     ['Walnut Brownie', 85.4, 76.9]\n * ]\n *\n * + \"objectRows\":\n * [\n *     {product: 'Matcha Latte', score: 89.3, amount: 95.8},\n *     {product: 'Milk Tea', score: 92.1, amount: 89.4},\n *     {product: 'Cheese Cocoa', score: 94.4, amount: 91.2},\n *     {product: 'Walnut Brownie', score: 85.4, amount: 76.9}\n * ]\n *\n * + \"keyedColumns\":\n * {\n *     'product': ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie'],\n *     'count': [823, 235, 1042, 988],\n *     'score': [95.8, 81.4, 91.2, 76.9]\n * }\n *\n * + \"typedArray\"\n *\n * + \"unknown\"\n */\n\n/**\n * @constructor\n * @param {Object} fields\n * @param {string} fields.sourceFormat\n * @param {Array|Object} fields.fromDataset\n * @param {Array|Object} [fields.data]\n * @param {string} [seriesLayoutBy='column']\n * @param {Array.<Object|string>} [dimensionsDefine]\n * @param {Objet|HashMap} [encodeDefine]\n * @param {number} [startIndex=0]\n * @param {number} [dimensionsDetectCount]\n */\nfunction Source(fields) {\n\n    /**\n     * @type {boolean}\n     */\n    this.fromDataset = fields.fromDataset;\n\n    /**\n     * Not null/undefined.\n     * @type {Array|Object}\n     */\n    this.data = fields.data || (\n        fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []\n    );\n\n    /**\n     * See also \"detectSourceFormat\".\n     * Not null/undefined.\n     * @type {string}\n     */\n    this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN;\n\n    /**\n     * 'row' or 'column'\n     * Not null/undefined.\n     * @type {string} seriesLayoutBy\n     */\n    this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN;\n\n    /**\n     * dimensions definition in option.\n     * can be null/undefined.\n     * @type {Array.<Object|string>}\n     */\n    this.dimensionsDefine = fields.dimensionsDefine;\n\n    /**\n     * encode definition in option.\n     * can be null/undefined.\n     * @type {Objet|HashMap}\n     */\n    this.encodeDefine = fields.encodeDefine && createHashMap(fields.encodeDefine);\n\n    /**\n     * Not null/undefined, uint.\n     * @type {number}\n     */\n    this.startIndex = fields.startIndex || 0;\n\n    /**\n     * Can be null/undefined (when unknown), uint.\n     * @type {number}\n     */\n    this.dimensionsDetectCount = fields.dimensionsDetectCount;\n}\n\n/**\n * Wrap original series data for some compatibility cases.\n */\nSource.seriesDataToSource = function (data) {\n    return new Source({\n        data: data,\n        sourceFormat: isTypedArray(data)\n            ? SOURCE_FORMAT_TYPED_ARRAY\n            : SOURCE_FORMAT_ORIGINAL,\n        fromDataset: false\n    });\n};\n\nenableClassCheck(Source);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$3 = makeInner();\n\n/**\n * @see {module:echarts/data/Source}\n * @param {module:echarts/component/dataset/DatasetModel} datasetModel\n * @return {string} sourceFormat\n */\nfunction detectSourceFormat(datasetModel) {\n    var data = datasetModel.option.source;\n    var sourceFormat = SOURCE_FORMAT_UNKNOWN;\n\n    if (isTypedArray(data)) {\n        sourceFormat = SOURCE_FORMAT_TYPED_ARRAY;\n    }\n    else if (isArray(data)) {\n        // FIXME Whether tolerate null in top level array?\n        if (data.length === 0) {\n            sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;\n        }\n\n        for (var i = 0, len = data.length; i < len; i++) {\n            var item = data[i];\n\n            if (item == null) {\n                continue;\n            }\n            else if (isArray(item)) {\n                sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;\n                break;\n            }\n            else if (isObject$1(item)) {\n                sourceFormat = SOURCE_FORMAT_OBJECT_ROWS;\n                break;\n            }\n        }\n    }\n    else if (isObject$1(data)) {\n        for (var key in data) {\n            if (data.hasOwnProperty(key) && isArrayLike(data[key])) {\n                sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS;\n                break;\n            }\n        }\n    }\n    else if (data != null) {\n        throw new Error('Invalid data');\n    }\n\n    inner$3(datasetModel).sourceFormat = sourceFormat;\n}\n\n/**\n * [Scenarios]:\n * (1) Provide source data directly:\n *     series: {\n *         encode: {...},\n *         dimensions: [...]\n *         seriesLayoutBy: 'row',\n *         data: [[...]]\n *     }\n * (2) Refer to datasetModel.\n *     series: [{\n *         encode: {...}\n *         // Ignore datasetIndex means `datasetIndex: 0`\n *         // and the dimensions defination in dataset is used\n *     }, {\n *         encode: {...},\n *         seriesLayoutBy: 'column',\n *         datasetIndex: 1\n *     }]\n *\n * Get data from series itself or datset.\n * @return {module:echarts/data/Source} source\n */\nfunction getSource(seriesModel) {\n    return inner$3(seriesModel).source;\n}\n\n/**\n * MUST be called before mergeOption of all series.\n * @param {module:echarts/model/Global} ecModel\n */\nfunction resetSourceDefaulter(ecModel) {\n    // `datasetMap` is used to make default encode.\n    inner$3(ecModel).datasetMap = createHashMap();\n}\n\n/**\n * [Caution]:\n * MUST be called after series option merged and\n * before \"series.getInitailData()\" called.\n *\n * [The rule of making default encode]:\n * Category axis (if exists) alway map to the first dimension.\n * Each other axis occupies a subsequent dimension.\n *\n * [Why make default encode]:\n * Simplify the typing of encode in option, avoiding the case like that:\n * series: [{encode: {x: 0, y: 1}}, {encode: {x: 0, y: 2}}, {encode: {x: 0, y: 3}}],\n * where the \"y\" have to be manually typed as \"1, 2, 3, ...\".\n *\n * @param {module:echarts/model/Series} seriesModel\n */\nfunction prepareSource(seriesModel) {\n    var seriesOption = seriesModel.option;\n\n    var data = seriesOption.data;\n    var sourceFormat = isTypedArray(data)\n        ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL;\n    var fromDataset = false;\n\n    var seriesLayoutBy = seriesOption.seriesLayoutBy;\n    var sourceHeader = seriesOption.sourceHeader;\n    var dimensionsDefine = seriesOption.dimensions;\n\n    var datasetModel = getDatasetModel(seriesModel);\n    if (datasetModel) {\n        var datasetOption = datasetModel.option;\n\n        data = datasetOption.source;\n        sourceFormat = inner$3(datasetModel).sourceFormat;\n        fromDataset = true;\n\n        // These settings from series has higher priority.\n        seriesLayoutBy = seriesLayoutBy || datasetOption.seriesLayoutBy;\n        sourceHeader == null && (sourceHeader = datasetOption.sourceHeader);\n        dimensionsDefine = dimensionsDefine || datasetOption.dimensions;\n    }\n\n    var completeResult = completeBySourceData(\n        data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine\n    );\n\n    // Note: dataset option does not have `encode`.\n    var encodeDefine = seriesOption.encode;\n    if (!encodeDefine && datasetModel) {\n        encodeDefine = makeDefaultEncode(\n            seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult\n        );\n    }\n\n    inner$3(seriesModel).source = new Source({\n        data: data,\n        fromDataset: fromDataset,\n        seriesLayoutBy: seriesLayoutBy,\n        sourceFormat: sourceFormat,\n        dimensionsDefine: completeResult.dimensionsDefine,\n        startIndex: completeResult.startIndex,\n        dimensionsDetectCount: completeResult.dimensionsDetectCount,\n        encodeDefine: encodeDefine\n    });\n}\n\n// return {startIndex, dimensionsDefine, dimensionsCount}\nfunction completeBySourceData(data, sourceFormat, seriesLayoutBy, sourceHeader, dimensionsDefine) {\n    if (!data) {\n        return {dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine)};\n    }\n\n    var dimensionsDetectCount;\n    var startIndex;\n    var findPotentialName;\n\n    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {\n        // Rule: Most of the first line are string: it is header.\n        // Caution: consider a line with 5 string and 1 number,\n        // it still can not be sure it is a head, because the\n        // 5 string may be 5 values of category columns.\n        if (sourceHeader === 'auto' || sourceHeader == null) {\n            arrayRowsTravelFirst(function (val) {\n                // '-' is regarded as null/undefined.\n                if (val != null && val !== '-') {\n                    if (isString(val)) {\n                        startIndex == null && (startIndex = 1);\n                    }\n                    else {\n                        startIndex = 0;\n                    }\n                }\n            // 10 is an experience number, avoid long loop.\n            }, seriesLayoutBy, data, 10);\n        }\n        else {\n            startIndex = sourceHeader ? 1 : 0;\n        }\n\n        if (!dimensionsDefine && startIndex === 1) {\n            dimensionsDefine = [];\n            arrayRowsTravelFirst(function (val, index) {\n                dimensionsDefine[index] = val != null ? val : '';\n            }, seriesLayoutBy, data);\n        }\n\n        dimensionsDetectCount = dimensionsDefine\n            ? dimensionsDefine.length\n            : seriesLayoutBy === SERIES_LAYOUT_BY_ROW\n            ? data.length\n            : data[0]\n            ? data[0].length\n            : null;\n    }\n    else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {\n        if (!dimensionsDefine) {\n            dimensionsDefine = objectRowsCollectDimensions(data);\n            findPotentialName = true;\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {\n        if (!dimensionsDefine) {\n            dimensionsDefine = [];\n            findPotentialName = true;\n            each$1(data, function (colArr, key) {\n                dimensionsDefine.push(key);\n            });\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        var value0 = getDataItemValue(data[0]);\n        dimensionsDetectCount = isArray(value0) && value0.length || 1;\n    }\n    else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {\n        if (__DEV__) {\n            assert$1(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.');\n        }\n    }\n\n    var potentialNameDimIndex;\n    if (findPotentialName) {\n        each$1(dimensionsDefine, function (dim, idx) {\n            if ((isObject$1(dim) ? dim.name : dim) === 'name') {\n                potentialNameDimIndex = idx;\n            }\n        });\n    }\n\n    return {\n        startIndex: startIndex,\n        dimensionsDefine: normalizeDimensionsDefine(dimensionsDefine),\n        dimensionsDetectCount: dimensionsDetectCount,\n        potentialNameDimIndex: potentialNameDimIndex\n        // TODO: potentialIdDimIdx\n    };\n}\n\n// Consider dimensions defined like ['A', 'price', 'B', 'price', 'C', 'price'],\n// which is reasonable. But dimension name is duplicated.\n// Returns undefined or an array contains only object without null/undefiend or string.\nfunction normalizeDimensionsDefine(dimensionsDefine) {\n    if (!dimensionsDefine) {\n        // The meaning of null/undefined is different from empty array.\n        return;\n    }\n    var nameMap = createHashMap();\n    return map(dimensionsDefine, function (item, index) {\n        item = extend({}, isObject$1(item) ? item : {name: item});\n\n        // User can set null in dimensions.\n        // We dont auto specify name, othewise a given name may\n        // cause it be refered unexpectedly.\n        if (item.name == null) {\n            return item;\n        }\n\n        // Also consider number form like 2012.\n        item.name += '';\n        // User may also specify displayName.\n        // displayName will always exists except user not\n        // specified or dim name is not specified or detected.\n        // (A auto generated dim name will not be used as\n        // displayName).\n        if (item.displayName == null) {\n            item.displayName = item.name;\n        }\n\n        var exist = nameMap.get(item.name);\n        if (!exist) {\n            nameMap.set(item.name, {count: 1});\n        }\n        else {\n            item.name += '-' + exist.count++;\n        }\n\n        return item;\n    });\n}\n\nfunction arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) {\n    maxLoop == null && (maxLoop = Infinity);\n    if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            cb(data[i] ? data[i][0] : null, i);\n        }\n    }\n    else {\n        var value0 = data[0] || [];\n        for (var i = 0; i < value0.length && i < maxLoop; i++) {\n            cb(value0[i], i);\n        }\n    }\n}\n\nfunction objectRowsCollectDimensions(data) {\n    var firstIndex = 0;\n    var obj;\n    while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line\n    if (obj) {\n        var dimensions = [];\n        each$1(obj, function (value, key) {\n            dimensions.push(key);\n        });\n        return dimensions;\n    }\n}\n\n// ??? TODO merge to completedimensions, where also has\n// default encode making logic. And the default rule\n// should depends on series? consider 'map'.\nfunction makeDefaultEncode(\n    seriesModel, datasetModel, data, sourceFormat, seriesLayoutBy, completeResult\n) {\n    var coordSysDefine = getCoordSysDefineBySeries(seriesModel);\n    var encode = {};\n    // var encodeTooltip = [];\n    // var encodeLabel = [];\n    var encodeItemName = [];\n    var encodeSeriesName = [];\n    var seriesType = seriesModel.subType;\n\n    // ??? TODO refactor: provide by series itself.\n    // Consider the case: 'map' series is based on geo coordSys,\n    // 'graph', 'heatmap' can be based on cartesian. But can not\n    // give default rule simply here.\n    var nSeriesMap = createHashMap(['pie', 'map', 'funnel']);\n    var cSeriesMap = createHashMap([\n        'line', 'bar', 'pictorialBar', 'scatter', 'effectScatter', 'candlestick', 'boxplot'\n    ]);\n\n    // Usually in this case series will use the first data\n    // dimension as the \"value\" dimension, or other default\n    // processes respectively.\n    if (coordSysDefine && cSeriesMap.get(seriesType) != null) {\n        var ecModel = seriesModel.ecModel;\n        var datasetMap = inner$3(ecModel).datasetMap;\n        var key = datasetModel.uid + '_' + seriesLayoutBy;\n        var datasetRecord = datasetMap.get(key)\n            || datasetMap.set(key, {categoryWayDim: 1, valueWayDim: 0});\n\n        // TODO\n        // Auto detect first time axis and do arrangement.\n        each$1(coordSysDefine.coordSysDims, function (coordDim) {\n            // In value way.\n            if (coordSysDefine.firstCategoryDimIndex == null) {\n                var dataDim = datasetRecord.valueWayDim++;\n                encode[coordDim] = dataDim;\n\n                // ??? TODO give a better default series name rule?\n                // especially when encode x y specified.\n                // consider: when mutiple series share one dimension\n                // category axis, series name should better use\n                // the other dimsion name. On the other hand, use\n                // both dimensions name.\n\n                encodeSeriesName.push(dataDim);\n                // encodeTooltip.push(dataDim);\n                // encodeLabel.push(dataDim);\n            }\n            // In category way, category axis.\n            else if (coordSysDefine.categoryAxisMap.get(coordDim)) {\n                encode[coordDim] = 0;\n                encodeItemName.push(0);\n            }\n            // In category way, non-category axis.\n            else {\n                var dataDim = datasetRecord.categoryWayDim++;\n                encode[coordDim] = dataDim;\n                // encodeTooltip.push(dataDim);\n                // encodeLabel.push(dataDim);\n                encodeSeriesName.push(dataDim);\n            }\n        });\n    }\n    // Do not make a complex rule! Hard to code maintain and not necessary.\n    // ??? TODO refactor: provide by series itself.\n    // [{name: ..., value: ...}, ...] like:\n    else if (nSeriesMap.get(seriesType) != null) {\n        // Find the first not ordinal. (5 is an experience value)\n        var firstNotOrdinal;\n        for (var i = 0; i < 5 && firstNotOrdinal == null; i++) {\n            if (!doGuessOrdinal(\n                data, sourceFormat, seriesLayoutBy,\n                completeResult.dimensionsDefine, completeResult.startIndex, i\n            )) {\n                firstNotOrdinal = i;\n            }\n        }\n        if (firstNotOrdinal != null) {\n            encode.value = firstNotOrdinal;\n            var nameDimIndex = completeResult.potentialNameDimIndex\n                || Math.max(firstNotOrdinal - 1, 0);\n            // By default, label use itemName in charts.\n            // So we dont set encodeLabel here.\n            encodeSeriesName.push(nameDimIndex);\n            encodeItemName.push(nameDimIndex);\n            // encodeTooltip.push(firstNotOrdinal);\n        }\n    }\n\n    // encodeTooltip.length && (encode.tooltip = encodeTooltip);\n    // encodeLabel.length && (encode.label = encodeLabel);\n    encodeItemName.length && (encode.itemName = encodeItemName);\n    encodeSeriesName.length && (encode.seriesName = encodeSeriesName);\n\n    return encode;\n}\n\n/**\n * If return null/undefined, indicate that should not use datasetModel.\n */\nfunction getDatasetModel(seriesModel) {\n    var option = seriesModel.option;\n    // Caution: consider the scenario:\n    // A dataset is declared and a series is not expected to use the dataset,\n    // and at the beginning `setOption({series: { noData })` (just prepare other\n    // option but no data), then `setOption({series: {data: [...]}); In this case,\n    // the user should set an empty array to avoid that dataset is used by default.\n    var thisData = option.data;\n    if (!thisData) {\n        return seriesModel.ecModel.getComponent('dataset', option.datasetIndex || 0);\n    }\n}\n\n/**\n * The rule should not be complex, otherwise user might not\n * be able to known where the data is wrong.\n * The code is ugly, but how to make it neat?\n *\n * @param {module:echars/data/Source} source\n * @param {number} dimIndex\n * @return {boolean} Whether ordinal.\n */\nfunction guessOrdinal(source, dimIndex) {\n    return doGuessOrdinal(\n        source.data,\n        source.sourceFormat,\n        source.seriesLayoutBy,\n        source.dimensionsDefine,\n        source.startIndex,\n        dimIndex\n    );\n}\n\n// dimIndex may be overflow source data.\nfunction doGuessOrdinal(\n    data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex\n) {\n    var result;\n    // Experience value.\n    var maxLoop = 5;\n\n    if (isTypedArray(data)) {\n        return false;\n    }\n\n    // When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine\n    // always exists in source.\n    var dimName;\n    if (dimensionsDefine) {\n        dimName = dimensionsDefine[dimIndex];\n        dimName = isObject$1(dimName) ? dimName.name : dimName;\n    }\n\n    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {\n        if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {\n            var sample = data[dimIndex];\n            for (var i = 0; i < (sample || []).length && i < maxLoop; i++) {\n                if ((result = detectValue(sample[startIndex + i])) != null) {\n                    return result;\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < data.length && i < maxLoop; i++) {\n                var row = data[startIndex + i];\n                if (row && (result = detectValue(row[dimIndex])) != null) {\n                    return result;\n                }\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {\n        if (!dimName) {\n            return;\n        }\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            var item = data[i];\n            if (item && (result = detectValue(item[dimName])) != null) {\n                return result;\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {\n        if (!dimName) {\n            return;\n        }\n        var sample = data[dimName];\n        if (!sample || isTypedArray(sample)) {\n            return false;\n        }\n        for (var i = 0; i < sample.length && i < maxLoop; i++) {\n            if ((result = detectValue(sample[i])) != null) {\n                return result;\n            }\n        }\n    }\n    else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        for (var i = 0; i < data.length && i < maxLoop; i++) {\n            var item = data[i];\n            var val = getDataItemValue(item);\n            if (!isArray(val)) {\n                return false;\n            }\n            if ((result = detectValue(val[dimIndex])) != null) {\n                return result;\n            }\n        }\n    }\n\n    function detectValue(val) {\n        // Consider usage convenience, '1', '2' will be treated as \"number\".\n        // `isFinit('')` get `true`.\n        if (val != null && isFinite(val) && val !== '') {\n            return false;\n        }\n        else if (isString(val) && val !== '-') {\n            return true;\n        }\n    }\n\n    return false;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * ECharts global model\n *\n * @module {echarts/model/Global}\n */\n\n\n/**\n * Caution: If the mechanism should be changed some day, these cases\n * should be considered:\n *\n * (1) In `merge option` mode, if using the same option to call `setOption`\n * many times, the result should be the same (try our best to ensure that).\n * (2) In `merge option` mode, if a component has no id/name specified, it\n * will be merged by index, and the result sequence of the components is\n * consistent to the original sequence.\n * (3) `reset` feature (in toolbox). Find detailed info in comments about\n * `mergeOption` in module:echarts/model/OptionManager.\n */\n\nvar OPTION_INNER_KEY = '\\0_ec_inner';\n\n/**\n * @alias module:echarts/model/Global\n *\n * @param {Object} option\n * @param {module:echarts/model/Model} parentModel\n * @param {Object} theme\n */\nvar GlobalModel = Model.extend({\n\n    init: function (option, parentModel, theme, optionManager) {\n        theme = theme || {};\n\n        this.option = null; // Mark as not initialized.\n\n        /**\n         * @type {module:echarts/model/Model}\n         * @private\n         */\n        this._theme = new Model(theme);\n\n        /**\n         * @type {module:echarts/model/OptionManager}\n         */\n        this._optionManager = optionManager;\n    },\n\n    setOption: function (option, optionPreprocessorFuncs) {\n        assert$1(\n            !(OPTION_INNER_KEY in option),\n            'please use chart.getOption()'\n        );\n\n        this._optionManager.setOption(option, optionPreprocessorFuncs);\n\n        this.resetOption(null);\n    },\n\n    /**\n     * @param {string} type null/undefined: reset all.\n     *                      'recreate': force recreate all.\n     *                      'timeline': only reset timeline option\n     *                      'media': only reset media query option\n     * @return {boolean} Whether option changed.\n     */\n    resetOption: function (type) {\n        var optionChanged = false;\n        var optionManager = this._optionManager;\n\n        if (!type || type === 'recreate') {\n            var baseOption = optionManager.mountOption(type === 'recreate');\n\n            if (!this.option || type === 'recreate') {\n                initBase.call(this, baseOption);\n            }\n            else {\n                this.restoreData();\n                this.mergeOption(baseOption);\n            }\n            optionChanged = true;\n        }\n\n        if (type === 'timeline' || type === 'media') {\n            this.restoreData();\n        }\n\n        if (!type || type === 'recreate' || type === 'timeline') {\n            var timelineOption = optionManager.getTimelineOption(this);\n            timelineOption && (this.mergeOption(timelineOption), optionChanged = true);\n        }\n\n        if (!type || type === 'recreate' || type === 'media') {\n            var mediaOptions = optionManager.getMediaOption(this, this._api);\n            if (mediaOptions.length) {\n                each$1(mediaOptions, function (mediaOption) {\n                    this.mergeOption(mediaOption, optionChanged = true);\n                }, this);\n            }\n        }\n\n        return optionChanged;\n    },\n\n    /**\n     * @protected\n     */\n    mergeOption: function (newOption) {\n        var option = this.option;\n        var componentsMap = this._componentsMap;\n        var newCptTypes = [];\n\n        resetSourceDefaulter(this);\n\n        // If no component class, merge directly.\n        // For example: color, animaiton options, etc.\n        each$1(newOption, function (componentOption, mainType) {\n            if (componentOption == null) {\n                return;\n            }\n\n            if (!ComponentModel.hasClass(mainType)) {\n                // globalSettingTask.dirty();\n                option[mainType] = option[mainType] == null\n                    ? clone(componentOption)\n                    : merge(option[mainType], componentOption, true);\n            }\n            else if (mainType) {\n                newCptTypes.push(mainType);\n            }\n        });\n\n        ComponentModel.topologicalTravel(\n            newCptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this\n        );\n\n        function visitComponent(mainType, dependencies) {\n\n            var newCptOptionList = normalizeToArray(newOption[mainType]);\n\n            var mapResult = mappingToExists(\n                componentsMap.get(mainType), newCptOptionList\n            );\n\n            makeIdAndName(mapResult);\n\n            // Set mainType and complete subType.\n            each$1(mapResult, function (item, index) {\n                var opt = item.option;\n                if (isObject$1(opt)) {\n                    item.keyInfo.mainType = mainType;\n                    item.keyInfo.subType = determineSubType(mainType, opt, item.exist);\n                }\n            });\n\n            var dependentModels = getComponentsByTypes(\n                componentsMap, dependencies\n            );\n\n            option[mainType] = [];\n            componentsMap.set(mainType, []);\n\n            each$1(mapResult, function (resultItem, index) {\n                var componentModel = resultItem.exist;\n                var newCptOption = resultItem.option;\n\n                assert$1(\n                    isObject$1(newCptOption) || componentModel,\n                    'Empty component definition'\n                );\n\n                // Consider where is no new option and should be merged using {},\n                // see removeEdgeAndAdd in topologicalTravel and\n                // ComponentModel.getAllClassMainTypes.\n                if (!newCptOption) {\n                    componentModel.mergeOption({}, this);\n                    componentModel.optionUpdated({}, false);\n                }\n                else {\n                    var ComponentModelClass = ComponentModel.getClass(\n                        mainType, resultItem.keyInfo.subType, true\n                    );\n\n                    if (componentModel && componentModel instanceof ComponentModelClass) {\n                        componentModel.name = resultItem.keyInfo.name;\n                        // componentModel.settingTask && componentModel.settingTask.dirty();\n                        componentModel.mergeOption(newCptOption, this);\n                        componentModel.optionUpdated(newCptOption, false);\n                    }\n                    else {\n                        // PENDING Global as parent ?\n                        var extraOpt = extend(\n                            {\n                                dependentModels: dependentModels,\n                                componentIndex: index\n                            },\n                            resultItem.keyInfo\n                        );\n                        componentModel = new ComponentModelClass(\n                            newCptOption, this, this, extraOpt\n                        );\n                        extend(componentModel, extraOpt);\n                        componentModel.init(newCptOption, this, this, extraOpt);\n\n                        // Call optionUpdated after init.\n                        // newCptOption has been used as componentModel.option\n                        // and may be merged with theme and default, so pass null\n                        // to avoid confusion.\n                        componentModel.optionUpdated(null, true);\n                    }\n                }\n\n                componentsMap.get(mainType)[index] = componentModel;\n                option[mainType][index] = componentModel.option;\n            }, this);\n\n            // Backup series for filtering.\n            if (mainType === 'series') {\n                createSeriesIndices(this, componentsMap.get('series'));\n            }\n        }\n\n        this._seriesIndicesMap = createHashMap(\n            this._seriesIndices = this._seriesIndices || []\n        );\n    },\n\n    /**\n     * Get option for output (cloned option and inner info removed)\n     * @public\n     * @return {Object}\n     */\n    getOption: function () {\n        var option = clone(this.option);\n\n        each$1(option, function (opts, mainType) {\n            if (ComponentModel.hasClass(mainType)) {\n                var opts = normalizeToArray(opts);\n                for (var i = opts.length - 1; i >= 0; i--) {\n                    // Remove options with inner id.\n                    if (isIdInner(opts[i])) {\n                        opts.splice(i, 1);\n                    }\n                }\n                option[mainType] = opts;\n            }\n        });\n\n        delete option[OPTION_INNER_KEY];\n\n        return option;\n    },\n\n    /**\n     * @return {module:echarts/model/Model}\n     */\n    getTheme: function () {\n        return this._theme;\n    },\n\n    /**\n     * @param {string} mainType\n     * @param {number} [idx=0]\n     * @return {module:echarts/model/Component}\n     */\n    getComponent: function (mainType, idx) {\n        var list = this._componentsMap.get(mainType);\n        if (list) {\n            return list[idx || 0];\n        }\n    },\n\n    /**\n     * If none of index and id and name used, return all components with mainType.\n     * @param {Object} condition\n     * @param {string} condition.mainType\n     * @param {string} [condition.subType] If ignore, only query by mainType\n     * @param {number|Array.<number>} [condition.index] Either input index or id or name.\n     * @param {string|Array.<string>} [condition.id] Either input index or id or name.\n     * @param {string|Array.<string>} [condition.name] Either input index or id or name.\n     * @return {Array.<module:echarts/model/Component>}\n     */\n    queryComponents: function (condition) {\n        var mainType = condition.mainType;\n        if (!mainType) {\n            return [];\n        }\n\n        var index = condition.index;\n        var id = condition.id;\n        var name = condition.name;\n\n        var cpts = this._componentsMap.get(mainType);\n\n        if (!cpts || !cpts.length) {\n            return [];\n        }\n\n        var result;\n\n        if (index != null) {\n            if (!isArray(index)) {\n                index = [index];\n            }\n            result = filter(map(index, function (idx) {\n                return cpts[idx];\n            }), function (val) {\n                return !!val;\n            });\n        }\n        else if (id != null) {\n            var isIdArray = isArray(id);\n            result = filter(cpts, function (cpt) {\n                return (isIdArray && indexOf(id, cpt.id) >= 0)\n                    || (!isIdArray && cpt.id === id);\n            });\n        }\n        else if (name != null) {\n            var isNameArray = isArray(name);\n            result = filter(cpts, function (cpt) {\n                return (isNameArray && indexOf(name, cpt.name) >= 0)\n                    || (!isNameArray && cpt.name === name);\n            });\n        }\n        else {\n            // Return all components with mainType\n            result = cpts.slice();\n        }\n\n        return filterBySubType(result, condition);\n    },\n\n    /**\n     * The interface is different from queryComponents,\n     * which is convenient for inner usage.\n     *\n     * @usage\n     * var result = findComponents(\n     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}}\n     * );\n     * var result = findComponents(\n     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}}\n     * );\n     * var result = findComponents(\n     *     {mainType: 'series'},\n     *     function (model, index) {...}\n     * );\n     * // result like [component0, componnet1, ...]\n     *\n     * @param {Object} condition\n     * @param {string} condition.mainType Mandatory.\n     * @param {string} [condition.subType] Optional.\n     * @param {Object} [condition.query] like {xxxIndex, xxxId, xxxName},\n     *        where xxx is mainType.\n     *        If query attribute is null/undefined or has no index/id/name,\n     *        do not filtering by query conditions, which is convenient for\n     *        no-payload situations or when target of action is global.\n     * @param {Function} [condition.filter] parameter: component, return boolean.\n     * @return {Array.<module:echarts/model/Component>}\n     */\n    findComponents: function (condition) {\n        var query = condition.query;\n        var mainType = condition.mainType;\n\n        var queryCond = getQueryCond(query);\n        var result = queryCond\n            ? this.queryComponents(queryCond)\n            : this._componentsMap.get(mainType);\n\n        return doFilter(filterBySubType(result, condition));\n\n        function getQueryCond(q) {\n            var indexAttr = mainType + 'Index';\n            var idAttr = mainType + 'Id';\n            var nameAttr = mainType + 'Name';\n            return q && (\n                    q[indexAttr] != null\n                    || q[idAttr] != null\n                    || q[nameAttr] != null\n                )\n                ? {\n                    mainType: mainType,\n                    // subType will be filtered finally.\n                    index: q[indexAttr],\n                    id: q[idAttr],\n                    name: q[nameAttr]\n                }\n                : null;\n        }\n\n        function doFilter(res) {\n            return condition.filter\n                    ? filter(res, condition.filter)\n                    : res;\n        }\n    },\n\n    /**\n     * @usage\n     * eachComponent('legend', function (legendModel, index) {\n     *     ...\n     * });\n     * eachComponent(function (componentType, model, index) {\n     *     // componentType does not include subType\n     *     // (componentType is 'xxx' but not 'xxx.aa')\n     * });\n     * eachComponent(\n     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}},\n     *     function (model, index) {...}\n     * );\n     * eachComponent(\n     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}},\n     *     function (model, index) {...}\n     * );\n     *\n     * @param {string|Object=} mainType When mainType is object, the definition\n     *                                  is the same as the method 'findComponents'.\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachComponent: function (mainType, cb, context) {\n        var componentsMap = this._componentsMap;\n\n        if (typeof mainType === 'function') {\n            context = cb;\n            cb = mainType;\n            componentsMap.each(function (components, componentType) {\n                each$1(components, function (component, index) {\n                    cb.call(context, componentType, component, index);\n                });\n            });\n        }\n        else if (isString(mainType)) {\n            each$1(componentsMap.get(mainType), cb, context);\n        }\n        else if (isObject$1(mainType)) {\n            var queryResult = this.findComponents(mainType);\n            each$1(queryResult, cb, context);\n        }\n    },\n\n    /**\n     * @param {string} name\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeriesByName: function (name) {\n        var series = this._componentsMap.get('series');\n        return filter(series, function (oneSeries) {\n            return oneSeries.name === name;\n        });\n    },\n\n    /**\n     * @param {number} seriesIndex\n     * @return {module:echarts/model/Series}\n     */\n    getSeriesByIndex: function (seriesIndex) {\n        return this._componentsMap.get('series')[seriesIndex];\n    },\n\n    /**\n     * Get series list before filtered by type.\n     * FIXME: rename to getRawSeriesByType?\n     *\n     * @param {string} subType\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeriesByType: function (subType) {\n        var series = this._componentsMap.get('series');\n        return filter(series, function (oneSeries) {\n            return oneSeries.subType === subType;\n        });\n    },\n\n    /**\n     * @return {Array.<module:echarts/model/Series>}\n     */\n    getSeries: function () {\n        return this._componentsMap.get('series').slice();\n    },\n\n    /**\n     * @return {number}\n     */\n    getSeriesCount: function () {\n        return this._componentsMap.get('series').length;\n    },\n\n    /**\n     * After filtering, series may be different\n     * frome raw series.\n     *\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachSeries: function (cb, context) {\n        assertSeriesInitialized(this);\n        each$1(this._seriesIndices, function (rawSeriesIndex) {\n            var series = this._componentsMap.get('series')[rawSeriesIndex];\n            cb.call(context, series, rawSeriesIndex);\n        }, this);\n    },\n\n    /**\n     * Iterate raw series before filtered.\n     *\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachRawSeries: function (cb, context) {\n        each$1(this._componentsMap.get('series'), cb, context);\n    },\n\n    /**\n     * After filtering, series may be different.\n     * frome raw series.\n     *\n     * @parma {string} subType\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachSeriesByType: function (subType, cb, context) {\n        assertSeriesInitialized(this);\n        each$1(this._seriesIndices, function (rawSeriesIndex) {\n            var series = this._componentsMap.get('series')[rawSeriesIndex];\n            if (series.subType === subType) {\n                cb.call(context, series, rawSeriesIndex);\n            }\n        }, this);\n    },\n\n    /**\n     * Iterate raw series before filtered of given type.\n     *\n     * @parma {string} subType\n     * @param {Function} cb\n     * @param {*} context\n     */\n    eachRawSeriesByType: function (subType, cb, context) {\n        return each$1(this.getSeriesByType(subType), cb, context);\n    },\n\n    /**\n     * @param {module:echarts/model/Series} seriesModel\n     */\n    isSeriesFiltered: function (seriesModel) {\n        assertSeriesInitialized(this);\n        return this._seriesIndicesMap.get(seriesModel.componentIndex) == null;\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getCurrentSeriesIndices: function () {\n        return (this._seriesIndices || []).slice();\n    },\n\n    /**\n     * @param {Function} cb\n     * @param {*} context\n     */\n    filterSeries: function (cb, context) {\n        assertSeriesInitialized(this);\n        var filteredSeries = filter(\n            this._componentsMap.get('series'), cb, context\n        );\n        createSeriesIndices(this, filteredSeries);\n    },\n\n    restoreData: function (payload) {\n        var componentsMap = this._componentsMap;\n\n        createSeriesIndices(this, componentsMap.get('series'));\n\n        var componentTypes = [];\n        componentsMap.each(function (components, componentType) {\n            componentTypes.push(componentType);\n        });\n\n        ComponentModel.topologicalTravel(\n            componentTypes,\n            ComponentModel.getAllClassMainTypes(),\n            function (componentType, dependencies) {\n                each$1(componentsMap.get(componentType), function (component) {\n                    (componentType !== 'series' || !isNotTargetSeries(component, payload))\n                        && component.restoreData();\n                });\n            }\n        );\n    }\n\n});\n\nfunction isNotTargetSeries(seriesModel, payload) {\n    if (payload) {\n        var index = payload.seiresIndex;\n        var id = payload.seriesId;\n        var name = payload.seriesName;\n        return (index != null && seriesModel.componentIndex !== index)\n            || (id != null && seriesModel.id !== id)\n            || (name != null && seriesModel.name !== name);\n    }\n}\n\n/**\n * @inner\n */\nfunction mergeTheme(option, theme) {\n    // PENDING\n    // NOT use `colorLayer` in theme if option has `color`\n    var notMergeColorLayer = option.color && !option.colorLayer;\n\n    each$1(theme, function (themeItem, name) {\n        if (name === 'colorLayer' && notMergeColorLayer) {\n            return;\n        }\n        // 如果有 component model 则把具体的 merge 逻辑交给该 model 处理\n        if (!ComponentModel.hasClass(name)) {\n            if (typeof themeItem === 'object') {\n                option[name] = !option[name]\n                    ? clone(themeItem)\n                    : merge(option[name], themeItem, false);\n            }\n            else {\n                if (option[name] == null) {\n                    option[name] = themeItem;\n                }\n            }\n        }\n    });\n}\n\nfunction initBase(baseOption) {\n    baseOption = baseOption;\n\n    // Using OPTION_INNER_KEY to mark that this option can not be used outside,\n    // i.e. `chart.setOption(chart.getModel().option);` is forbiden.\n    this.option = {};\n    this.option[OPTION_INNER_KEY] = 1;\n\n    /**\n     * Init with series: [], in case of calling findSeries method\n     * before series initialized.\n     * @type {Object.<string, Array.<module:echarts/model/Model>>}\n     * @private\n     */\n    this._componentsMap = createHashMap({series: []});\n\n    /**\n     * Mapping between filtered series list and raw series list.\n     * key: filtered series indices, value: raw series indices.\n     * @type {Array.<nubmer>}\n     * @private\n     */\n    this._seriesIndices;\n\n    this._seriesIndicesMap;\n\n    mergeTheme(baseOption, this._theme.option);\n\n    // TODO Needs clone when merging to the unexisted property\n    merge(baseOption, globalDefault, false);\n\n    this.mergeOption(baseOption);\n}\n\n/**\n * @inner\n * @param {Array.<string>|string} types model types\n * @return {Object} key: {string} type, value: {Array.<Object>} models\n */\nfunction getComponentsByTypes(componentsMap, types) {\n    if (!isArray(types)) {\n        types = types ? [types] : [];\n    }\n\n    var ret = {};\n    each$1(types, function (type) {\n        ret[type] = (componentsMap.get(type) || []).slice();\n    });\n\n    return ret;\n}\n\n/**\n * @inner\n */\nfunction determineSubType(mainType, newCptOption, existComponent) {\n    var subType = newCptOption.type\n        ? newCptOption.type\n        : existComponent\n        ? existComponent.subType\n        // Use determineSubType only when there is no existComponent.\n        : ComponentModel.determineSubType(mainType, newCptOption);\n\n    // tooltip, markline, markpoint may always has no subType\n    return subType;\n}\n\n/**\n * @inner\n */\nfunction createSeriesIndices(ecModel, seriesModels) {\n    ecModel._seriesIndicesMap = createHashMap(\n        ecModel._seriesIndices = map(seriesModels, function (series) {\n            return series.componentIndex;\n        }) || []\n    );\n}\n\n/**\n * @inner\n */\nfunction filterBySubType(components, condition) {\n    // Using hasOwnProperty for restrict. Consider\n    // subType is undefined in user payload.\n    return condition.hasOwnProperty('subType')\n        ? filter(components, function (cpt) {\n            return cpt.subType === condition.subType;\n        })\n        : components;\n}\n\n/**\n * @inner\n */\nfunction assertSeriesInitialized(ecModel) {\n    // Components that use _seriesIndices should depends on series component,\n    // which make sure that their initialization is after series.\n    if (__DEV__) {\n        if (!ecModel._seriesIndices) {\n            throw new Error('Option should contains series.');\n        }\n    }\n}\n\nmixin(GlobalModel, colorPaletteMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar echartsAPIList = [\n    'getDom', 'getZr', 'getWidth', 'getHeight', 'getDevicePixelRatio', 'dispatchAction', 'isDisposed',\n    'on', 'off', 'getDataURL', 'getConnectedDataURL', 'getModel', 'getOption',\n    'getViewOfComponentModel', 'getViewOfSeriesModel'\n];\n// And `getCoordinateSystems` and `getComponentByElement` will be injected in echarts.js\n\nfunction ExtensionAPI(chartInstance) {\n    each$1(echartsAPIList, function (name) {\n        this[name] = bind(chartInstance[name], chartInstance);\n    }, this);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar coordinateSystemCreators = {};\n\nfunction CoordinateSystemManager() {\n\n    this._coordinateSystems = [];\n}\n\nCoordinateSystemManager.prototype = {\n\n    constructor: CoordinateSystemManager,\n\n    create: function (ecModel, api) {\n        var coordinateSystems = [];\n        each$1(coordinateSystemCreators, function (creater, type) {\n            var list = creater.create(ecModel, api);\n            coordinateSystems = coordinateSystems.concat(list || []);\n        });\n\n        this._coordinateSystems = coordinateSystems;\n    },\n\n    update: function (ecModel, api) {\n        each$1(this._coordinateSystems, function (coordSys) {\n            coordSys.update && coordSys.update(ecModel, api);\n        });\n    },\n\n    getCoordinateSystems: function () {\n        return this._coordinateSystems.slice();\n    }\n};\n\nCoordinateSystemManager.register = function (type, coordinateSystemCreator) {\n    coordinateSystemCreators[type] = coordinateSystemCreator;\n};\n\nCoordinateSystemManager.get = function (type) {\n    return coordinateSystemCreators[type];\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * ECharts option manager\n *\n * @module {echarts/model/OptionManager}\n */\n\n\nvar each$4 = each$1;\nvar clone$3 = clone;\nvar map$1 = map;\nvar merge$1 = merge;\n\nvar QUERY_REG = /^(min|max)?(.+)$/;\n\n/**\n * TERM EXPLANATIONS:\n *\n * [option]:\n *\n *     An object that contains definitions of components. For example:\n *     var option = {\n *         title: {...},\n *         legend: {...},\n *         visualMap: {...},\n *         series: [\n *             {data: [...]},\n *             {data: [...]},\n *             ...\n *         ]\n *     };\n *\n * [rawOption]:\n *\n *     An object input to echarts.setOption. 'rawOption' may be an\n *     'option', or may be an object contains multi-options. For example:\n *     var option = {\n *         baseOption: {\n *             title: {...},\n *             legend: {...},\n *             series: [\n *                 {data: [...]},\n *                 {data: [...]},\n *                 ...\n *             ]\n *         },\n *         timeline: {...},\n *         options: [\n *             {title: {...}, series: {data: [...]}},\n *             {title: {...}, series: {data: [...]}},\n *             ...\n *         ],\n *         media: [\n *             {\n *                 query: {maxWidth: 320},\n *                 option: {series: {x: 20}, visualMap: {show: false}}\n *             },\n *             {\n *                 query: {minWidth: 320, maxWidth: 720},\n *                 option: {series: {x: 500}, visualMap: {show: true}}\n *             },\n *             {\n *                 option: {series: {x: 1200}, visualMap: {show: true}}\n *             }\n *         ]\n *     };\n *\n * @alias module:echarts/model/OptionManager\n * @param {module:echarts/ExtensionAPI} api\n */\nfunction OptionManager(api) {\n\n    /**\n     * @private\n     * @type {module:echarts/ExtensionAPI}\n     */\n    this._api = api;\n\n    /**\n     * @private\n     * @type {Array.<number>}\n     */\n    this._timelineOptions = [];\n\n    /**\n     * @private\n     * @type {Array.<Object>}\n     */\n    this._mediaList = [];\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._mediaDefault;\n\n    /**\n     * -1, means default.\n     * empty means no media.\n     * @private\n     * @type {Array.<number>}\n     */\n    this._currentMediaIndices = [];\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._optionBackup;\n\n    /**\n     * @private\n     * @type {Object}\n     */\n    this._newBaseOption;\n}\n\n// timeline.notMerge is not supported in ec3. Firstly there is rearly\n// case that notMerge is needed. Secondly supporting 'notMerge' requires\n// rawOption cloned and backuped when timeline changed, which does no\n// good to performance. What's more, that both timeline and setOption\n// method supply 'notMerge' brings complex and some problems.\n// Consider this case:\n// (step1) chart.setOption({timeline: {notMerge: false}, ...}, false);\n// (step2) chart.setOption({timeline: {notMerge: true}, ...}, false);\n\nOptionManager.prototype = {\n\n    constructor: OptionManager,\n\n    /**\n     * @public\n     * @param {Object} rawOption Raw option.\n     * @param {module:echarts/model/Global} ecModel\n     * @param {Array.<Function>} optionPreprocessorFuncs\n     * @return {Object} Init option\n     */\n    setOption: function (rawOption, optionPreprocessorFuncs) {\n        if (rawOption) {\n            // That set dat primitive is dangerous if user reuse the data when setOption again.\n            each$1(normalizeToArray(rawOption.series), function (series) {\n                series && series.data && isTypedArray(series.data) && setAsPrimitive(series.data);\n            });\n        }\n\n        // Caution: some series modify option data, if do not clone,\n        // it should ensure that the repeat modify correctly\n        // (create a new object when modify itself).\n        rawOption = clone$3(rawOption, true);\n\n        // FIXME\n        // 如果 timeline options 或者 media 中设置了某个属性，而baseOption中没有设置，则进行警告。\n\n        var oldOptionBackup = this._optionBackup;\n        var newParsedOption = parseRawOption.call(\n            this, rawOption, optionPreprocessorFuncs, !oldOptionBackup\n        );\n        this._newBaseOption = newParsedOption.baseOption;\n\n        // For setOption at second time (using merge mode);\n        if (oldOptionBackup) {\n            // Only baseOption can be merged.\n            mergeOption(oldOptionBackup.baseOption, newParsedOption.baseOption);\n\n            // For simplicity, timeline options and media options do not support merge,\n            // that is, if you `setOption` twice and both has timeline options, the latter\n            // timeline opitons will not be merged to the formers, but just substitude them.\n            if (newParsedOption.timelineOptions.length) {\n                oldOptionBackup.timelineOptions = newParsedOption.timelineOptions;\n            }\n            if (newParsedOption.mediaList.length) {\n                oldOptionBackup.mediaList = newParsedOption.mediaList;\n            }\n            if (newParsedOption.mediaDefault) {\n                oldOptionBackup.mediaDefault = newParsedOption.mediaDefault;\n            }\n        }\n        else {\n            this._optionBackup = newParsedOption;\n        }\n    },\n\n    /**\n     * @param {boolean} isRecreate\n     * @return {Object}\n     */\n    mountOption: function (isRecreate) {\n        var optionBackup = this._optionBackup;\n\n        // TODO\n        // 如果没有reset功能则不clone。\n\n        this._timelineOptions = map$1(optionBackup.timelineOptions, clone$3);\n        this._mediaList = map$1(optionBackup.mediaList, clone$3);\n        this._mediaDefault = clone$3(optionBackup.mediaDefault);\n        this._currentMediaIndices = [];\n\n        return clone$3(isRecreate\n            // this._optionBackup.baseOption, which is created at the first `setOption`\n            // called, and is merged into every new option by inner method `mergeOption`\n            // each time `setOption` called, can be only used in `isRecreate`, because\n            // its reliability is under suspicion. In other cases option merge is\n            // performed by `model.mergeOption`.\n            ? optionBackup.baseOption : this._newBaseOption\n        );\n    },\n\n    /**\n     * @param {module:echarts/model/Global} ecModel\n     * @return {Object}\n     */\n    getTimelineOption: function (ecModel) {\n        var option;\n        var timelineOptions = this._timelineOptions;\n\n        if (timelineOptions.length) {\n            // getTimelineOption can only be called after ecModel inited,\n            // so we can get currentIndex from timelineModel.\n            var timelineModel = ecModel.getComponent('timeline');\n            if (timelineModel) {\n                option = clone$3(\n                    timelineOptions[timelineModel.getCurrentIndex()],\n                    true\n                );\n            }\n        }\n\n        return option;\n    },\n\n    /**\n     * @param {module:echarts/model/Global} ecModel\n     * @return {Array.<Object>}\n     */\n    getMediaOption: function (ecModel) {\n        var ecWidth = this._api.getWidth();\n        var ecHeight = this._api.getHeight();\n        var mediaList = this._mediaList;\n        var mediaDefault = this._mediaDefault;\n        var indices = [];\n        var result = [];\n\n        // No media defined.\n        if (!mediaList.length && !mediaDefault) {\n            return result;\n        }\n\n        // Multi media may be applied, the latter defined media has higher priority.\n        for (var i = 0, len = mediaList.length; i < len; i++) {\n            if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) {\n                indices.push(i);\n            }\n        }\n\n        // FIXME\n        // 是否mediaDefault应该强制用户设置，否则可能修改不能回归。\n        if (!indices.length && mediaDefault) {\n            indices = [-1];\n        }\n\n        if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) {\n            result = map$1(indices, function (index) {\n                return clone$3(\n                    index === -1 ? mediaDefault.option : mediaList[index].option\n                );\n            });\n        }\n        // Otherwise return nothing.\n\n        this._currentMediaIndices = indices;\n\n        return result;\n    }\n};\n\nfunction parseRawOption(rawOption, optionPreprocessorFuncs, isNew) {\n    var timelineOptions = [];\n    var mediaList = [];\n    var mediaDefault;\n    var baseOption;\n\n    // Compatible with ec2.\n    var timelineOpt = rawOption.timeline;\n\n    if (rawOption.baseOption) {\n        baseOption = rawOption.baseOption;\n    }\n\n    // For timeline\n    if (timelineOpt || rawOption.options) {\n        baseOption = baseOption || {};\n        timelineOptions = (rawOption.options || []).slice();\n    }\n\n    // For media query\n    if (rawOption.media) {\n        baseOption = baseOption || {};\n        var media = rawOption.media;\n        each$4(media, function (singleMedia) {\n            if (singleMedia && singleMedia.option) {\n                if (singleMedia.query) {\n                    mediaList.push(singleMedia);\n                }\n                else if (!mediaDefault) {\n                    // Use the first media default.\n                    mediaDefault = singleMedia;\n                }\n            }\n        });\n    }\n\n    // For normal option\n    if (!baseOption) {\n        baseOption = rawOption;\n    }\n\n    // Set timelineOpt to baseOption in ec3,\n    // which is convenient for merge option.\n    if (!baseOption.timeline) {\n        baseOption.timeline = timelineOpt;\n    }\n\n    // Preprocess.\n    each$4([baseOption].concat(timelineOptions)\n        .concat(map(mediaList, function (media) {\n            return media.option;\n        })),\n        function (option) {\n            each$4(optionPreprocessorFuncs, function (preProcess) {\n                preProcess(option, isNew);\n            });\n        }\n    );\n\n    return {\n        baseOption: baseOption,\n        timelineOptions: timelineOptions,\n        mediaDefault: mediaDefault,\n        mediaList: mediaList\n    };\n}\n\n/**\n * @see <http://www.w3.org/TR/css3-mediaqueries/#media1>\n * Support: width, height, aspectRatio\n * Can use max or min as prefix.\n */\nfunction applyMediaQuery(query, ecWidth, ecHeight) {\n    var realMap = {\n        width: ecWidth,\n        height: ecHeight,\n        aspectratio: ecWidth / ecHeight // lowser case for convenientce.\n    };\n\n    var applicatable = true;\n\n    each$1(query, function (value, attr) {\n        var matched = attr.match(QUERY_REG);\n\n        if (!matched || !matched[1] || !matched[2]) {\n            return;\n        }\n\n        var operator = matched[1];\n        var realAttr = matched[2].toLowerCase();\n\n        if (!compare(realMap[realAttr], value, operator)) {\n            applicatable = false;\n        }\n    });\n\n    return applicatable;\n}\n\nfunction compare(real, expect, operator) {\n    if (operator === 'min') {\n        return real >= expect;\n    }\n    else if (operator === 'max') {\n        return real <= expect;\n    }\n    else { // Equals\n        return real === expect;\n    }\n}\n\nfunction indicesEquals(indices1, indices2) {\n    // indices is always order by asc and has only finite number.\n    return indices1.join(',') === indices2.join(',');\n}\n\n/**\n * Consider case:\n * `chart.setOption(opt1);`\n * Then user do some interaction like dataZoom, dataView changing.\n * `chart.setOption(opt2);`\n * Then user press 'reset button' in toolbox.\n *\n * After doing that all of the interaction effects should be reset, the\n * chart should be the same as the result of invoke\n * `chart.setOption(opt1); chart.setOption(opt2);`.\n *\n * Although it is not able ensure that\n * `chart.setOption(opt1); chart.setOption(opt2);` is equivalents to\n * `chart.setOption(merge(opt1, opt2));` exactly,\n * this might be the only simple way to implement that feature.\n *\n * MEMO: We've considered some other approaches:\n * 1. Each model handle its self restoration but not uniform treatment.\n *     (Too complex in logic and error-prone)\n * 2. Use a shadow ecModel. (Performace expensive)\n */\nfunction mergeOption(oldOption, newOption) {\n    newOption = newOption || {};\n\n    each$4(newOption, function (newCptOpt, mainType) {\n        if (newCptOpt == null) {\n            return;\n        }\n\n        var oldCptOpt = oldOption[mainType];\n\n        if (!ComponentModel.hasClass(mainType)) {\n            oldOption[mainType] = merge$1(oldCptOpt, newCptOpt, true);\n        }\n        else {\n            newCptOpt = normalizeToArray(newCptOpt);\n            oldCptOpt = normalizeToArray(oldCptOpt);\n\n            var mapResult = mappingToExists(oldCptOpt, newCptOpt);\n\n            oldOption[mainType] = map$1(mapResult, function (item) {\n                return (item.option && item.exist)\n                    ? merge$1(item.exist, item.option, true)\n                    : (item.exist || item.option);\n            });\n        }\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar each$5 = each$1;\nvar isObject$3 = isObject$1;\n\nvar POSSIBLE_STYLES = [\n    'areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle',\n    'chordStyle', 'label', 'labelLine'\n];\n\nfunction compatEC2ItemStyle(opt) {\n    var itemStyleOpt = opt && opt.itemStyle;\n    if (!itemStyleOpt) {\n        return;\n    }\n    for (var i = 0, len = POSSIBLE_STYLES.length; i < len; i++) {\n        var styleName = POSSIBLE_STYLES[i];\n        var normalItemStyleOpt = itemStyleOpt.normal;\n        var emphasisItemStyleOpt = itemStyleOpt.emphasis;\n        if (normalItemStyleOpt && normalItemStyleOpt[styleName]) {\n            opt[styleName] = opt[styleName] || {};\n            if (!opt[styleName].normal) {\n                opt[styleName].normal = normalItemStyleOpt[styleName];\n            }\n            else {\n                merge(opt[styleName].normal, normalItemStyleOpt[styleName]);\n            }\n            normalItemStyleOpt[styleName] = null;\n        }\n        if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) {\n            opt[styleName] = opt[styleName] || {};\n            if (!opt[styleName].emphasis) {\n                opt[styleName].emphasis = emphasisItemStyleOpt[styleName];\n            }\n            else {\n                merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]);\n            }\n            emphasisItemStyleOpt[styleName] = null;\n        }\n    }\n}\n\nfunction convertNormalEmphasis(opt, optType, useExtend) {\n    if (opt && opt[optType] && (opt[optType].normal || opt[optType].emphasis)) {\n        var normalOpt = opt[optType].normal;\n        var emphasisOpt = opt[optType].emphasis;\n\n        if (normalOpt) {\n            // Timeline controlStyle has other properties besides normal and emphasis\n            if (useExtend) {\n                opt[optType].normal = opt[optType].emphasis = null;\n                defaults(opt[optType], normalOpt);\n            }\n            else {\n                opt[optType] = normalOpt;\n            }\n        }\n        if (emphasisOpt) {\n            opt.emphasis = opt.emphasis || {};\n            opt.emphasis[optType] = emphasisOpt;\n        }\n    }\n}\nfunction removeEC3NormalStatus(opt) {\n    convertNormalEmphasis(opt, 'itemStyle');\n    convertNormalEmphasis(opt, 'lineStyle');\n    convertNormalEmphasis(opt, 'areaStyle');\n    convertNormalEmphasis(opt, 'label');\n    convertNormalEmphasis(opt, 'labelLine');\n    // treemap\n    convertNormalEmphasis(opt, 'upperLabel');\n    // graph\n    convertNormalEmphasis(opt, 'edgeLabel');\n}\n\nfunction compatTextStyle(opt, propName) {\n    // Check whether is not object (string\\null\\undefined ...)\n    var labelOptSingle = isObject$3(opt) && opt[propName];\n    var textStyle = isObject$3(labelOptSingle) && labelOptSingle.textStyle;\n    if (textStyle) {\n        for (var i = 0, len = TEXT_STYLE_OPTIONS.length; i < len; i++) {\n            var propName = TEXT_STYLE_OPTIONS[i];\n            if (textStyle.hasOwnProperty(propName)) {\n                labelOptSingle[propName] = textStyle[propName];\n            }\n        }\n    }\n}\n\nfunction compatEC3CommonStyles(opt) {\n    if (opt) {\n        removeEC3NormalStatus(opt);\n        compatTextStyle(opt, 'label');\n        opt.emphasis && compatTextStyle(opt.emphasis, 'label');\n    }\n}\n\nfunction processSeries(seriesOpt) {\n    if (!isObject$3(seriesOpt)) {\n        return;\n    }\n\n    compatEC2ItemStyle(seriesOpt);\n    removeEC3NormalStatus(seriesOpt);\n\n    compatTextStyle(seriesOpt, 'label');\n    // treemap\n    compatTextStyle(seriesOpt, 'upperLabel');\n    // graph\n    compatTextStyle(seriesOpt, 'edgeLabel');\n    if (seriesOpt.emphasis) {\n        compatTextStyle(seriesOpt.emphasis, 'label');\n        // treemap\n        compatTextStyle(seriesOpt.emphasis, 'upperLabel');\n        // graph\n        compatTextStyle(seriesOpt.emphasis, 'edgeLabel');\n    }\n\n    var markPoint = seriesOpt.markPoint;\n    if (markPoint) {\n        compatEC2ItemStyle(markPoint);\n        compatEC3CommonStyles(markPoint);\n    }\n\n    var markLine = seriesOpt.markLine;\n    if (markLine) {\n        compatEC2ItemStyle(markLine);\n        compatEC3CommonStyles(markLine);\n    }\n\n    var markArea = seriesOpt.markArea;\n    if (markArea) {\n        compatEC3CommonStyles(markArea);\n    }\n\n    var data = seriesOpt.data;\n\n    // Break with ec3: if `setOption` again, there may be no `type` in option,\n    // then the backward compat based on option type will not be performed.\n\n    if (seriesOpt.type === 'graph') {\n        data = data || seriesOpt.nodes;\n        var edgeData = seriesOpt.links || seriesOpt.edges;\n        if (edgeData && !isTypedArray(edgeData)) {\n            for (var i = 0; i < edgeData.length; i++) {\n                compatEC3CommonStyles(edgeData[i]);\n            }\n        }\n        each$1(seriesOpt.categories, function (opt) {\n            removeEC3NormalStatus(opt);\n        });\n    }\n\n    if (data && !isTypedArray(data)) {\n        for (var i = 0; i < data.length; i++) {\n            compatEC3CommonStyles(data[i]);\n        }\n    }\n\n    // mark point data\n    var markPoint = seriesOpt.markPoint;\n    if (markPoint && markPoint.data) {\n        var mpData = markPoint.data;\n        for (var i = 0; i < mpData.length; i++) {\n            compatEC3CommonStyles(mpData[i]);\n        }\n    }\n    // mark line data\n    var markLine = seriesOpt.markLine;\n    if (markLine && markLine.data) {\n        var mlData = markLine.data;\n        for (var i = 0; i < mlData.length; i++) {\n            if (isArray(mlData[i])) {\n                compatEC3CommonStyles(mlData[i][0]);\n                compatEC3CommonStyles(mlData[i][1]);\n            }\n            else {\n                compatEC3CommonStyles(mlData[i]);\n            }\n        }\n    }\n\n    // Series\n    if (seriesOpt.type === 'gauge') {\n        compatTextStyle(seriesOpt, 'axisLabel');\n        compatTextStyle(seriesOpt, 'title');\n        compatTextStyle(seriesOpt, 'detail');\n    }\n    else if (seriesOpt.type === 'treemap') {\n        convertNormalEmphasis(seriesOpt.breadcrumb, 'itemStyle');\n        each$1(seriesOpt.levels, function (opt) {\n            removeEC3NormalStatus(opt);\n        });\n    }\n    else if (seriesOpt.type === 'tree') {\n        removeEC3NormalStatus(seriesOpt.leaves);\n    }\n    // sunburst starts from ec4, so it does not need to compat levels.\n}\n\nfunction toArr(o) {\n    return isArray(o) ? o : o ? [o] : [];\n}\n\nfunction toObj(o) {\n    return (isArray(o) ? o[0] : o) || {};\n}\n\nvar compatStyle = function (option, isTheme) {\n    each$5(toArr(option.series), function (seriesOpt) {\n        isObject$3(seriesOpt) && processSeries(seriesOpt);\n    });\n\n    var axes = ['xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'parallelAxis', 'radar'];\n    isTheme && axes.push('valueAxis', 'categoryAxis', 'logAxis', 'timeAxis');\n\n    each$5(\n        axes,\n        function (axisName) {\n            each$5(toArr(option[axisName]), function (axisOpt) {\n                if (axisOpt) {\n                    compatTextStyle(axisOpt, 'axisLabel');\n                    compatTextStyle(axisOpt.axisPointer, 'label');\n                }\n            });\n        }\n    );\n\n    each$5(toArr(option.parallel), function (parallelOpt) {\n        var parallelAxisDefault = parallelOpt && parallelOpt.parallelAxisDefault;\n        compatTextStyle(parallelAxisDefault, 'axisLabel');\n        compatTextStyle(parallelAxisDefault && parallelAxisDefault.axisPointer, 'label');\n    });\n\n    each$5(toArr(option.calendar), function (calendarOpt) {\n        convertNormalEmphasis(calendarOpt, 'itemStyle');\n        compatTextStyle(calendarOpt, 'dayLabel');\n        compatTextStyle(calendarOpt, 'monthLabel');\n        compatTextStyle(calendarOpt, 'yearLabel');\n    });\n\n    // radar.name.textStyle\n    each$5(toArr(option.radar), function (radarOpt) {\n        compatTextStyle(radarOpt, 'name');\n    });\n\n    each$5(toArr(option.geo), function (geoOpt) {\n        if (isObject$3(geoOpt)) {\n            compatEC3CommonStyles(geoOpt);\n            each$5(toArr(geoOpt.regions), function (regionObj) {\n                compatEC3CommonStyles(regionObj);\n            });\n        }\n    });\n\n    each$5(toArr(option.timeline), function (timelineOpt) {\n        compatEC3CommonStyles(timelineOpt);\n        convertNormalEmphasis(timelineOpt, 'label');\n        convertNormalEmphasis(timelineOpt, 'itemStyle');\n        convertNormalEmphasis(timelineOpt, 'controlStyle', true);\n\n        var data = timelineOpt.data;\n        isArray(data) && each$1(data, function (item) {\n            if (isObject$1(item)) {\n                convertNormalEmphasis(item, 'label');\n                convertNormalEmphasis(item, 'itemStyle');\n            }\n        });\n    });\n\n    each$5(toArr(option.toolbox), function (toolboxOpt) {\n        convertNormalEmphasis(toolboxOpt, 'iconStyle');\n        each$5(toolboxOpt.feature, function (featureOpt) {\n            convertNormalEmphasis(featureOpt, 'iconStyle');\n        });\n    });\n\n    compatTextStyle(toObj(option.axisPointer), 'label');\n    compatTextStyle(toObj(option.tooltip).axisPointer, 'label');\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Compatitable with 2.0\n\nfunction get(opt, path) {\n    path = path.split(',');\n    var obj = opt;\n    for (var i = 0; i < path.length; i++) {\n        obj = obj && obj[path[i]];\n        if (obj == null) {\n            break;\n        }\n    }\n    return obj;\n}\n\nfunction set$1(opt, path, val, overwrite) {\n    path = path.split(',');\n    var obj = opt;\n    var key;\n    for (var i = 0; i < path.length - 1; i++) {\n        key = path[i];\n        if (obj[key] == null) {\n            obj[key] = {};\n        }\n        obj = obj[key];\n    }\n    if (overwrite || obj[path[i]] == null) {\n        obj[path[i]] = val;\n    }\n}\n\nfunction compatLayoutProperties(option) {\n    each$1(LAYOUT_PROPERTIES, function (prop) {\n        if (prop[0] in option && !(prop[1] in option)) {\n            option[prop[1]] = option[prop[0]];\n        }\n    });\n}\n\nvar LAYOUT_PROPERTIES = [\n    ['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom']\n];\n\nvar COMPATITABLE_COMPONENTS = [\n    'grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline'\n];\n\nvar backwardCompat = function (option, isTheme) {\n    compatStyle(option, isTheme);\n\n    // Make sure series array for model initialization.\n    option.series = normalizeToArray(option.series);\n\n    each$1(option.series, function (seriesOpt) {\n        if (!isObject$1(seriesOpt)) {\n            return;\n        }\n\n        var seriesType = seriesOpt.type;\n\n        if (seriesType === 'pie' || seriesType === 'gauge') {\n            if (seriesOpt.clockWise != null) {\n                seriesOpt.clockwise = seriesOpt.clockWise;\n            }\n        }\n        if (seriesType === 'gauge') {\n            var pointerColor = get(seriesOpt, 'pointer.color');\n            pointerColor != null\n                && set$1(seriesOpt, 'itemStyle.normal.color', pointerColor);\n        }\n\n        compatLayoutProperties(seriesOpt);\n    });\n\n    // dataRange has changed to visualMap\n    if (option.dataRange) {\n        option.visualMap = option.dataRange;\n    }\n\n    each$1(COMPATITABLE_COMPONENTS, function (componentName) {\n        var options = option[componentName];\n        if (options) {\n            if (!isArray(options)) {\n                options = [options];\n            }\n            each$1(options, function (option) {\n                compatLayoutProperties(option);\n            });\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// (1) [Caution]: the logic is correct based on the premises:\n//     data processing stage is blocked in stream.\n//     See <module:echarts/stream/Scheduler#performDataProcessorTasks>\n// (2) Only register once when import repeatly.\n//     Should be executed before after series filtered and before stack calculation.\nvar dataStack = function (ecModel) {\n    var stackInfoMap = createHashMap();\n    ecModel.eachSeries(function (seriesModel) {\n        var stack = seriesModel.get('stack');\n        // Compatibal: when `stack` is set as '', do not stack.\n        if (stack) {\n            var stackInfoList = stackInfoMap.get(stack) || stackInfoMap.set(stack, []);\n            var data = seriesModel.getData();\n\n            var stackInfo = {\n                // Used for calculate axis extent automatically.\n                stackResultDimension: data.getCalculationInfo('stackResultDimension'),\n                stackedOverDimension: data.getCalculationInfo('stackedOverDimension'),\n                stackedDimension: data.getCalculationInfo('stackedDimension'),\n                stackedByDimension: data.getCalculationInfo('stackedByDimension'),\n                isStackedByIndex: data.getCalculationInfo('isStackedByIndex'),\n                data: data,\n                seriesModel: seriesModel\n            };\n\n            // If stacked on axis that do not support data stack.\n            if (!stackInfo.stackedDimension\n                || !(stackInfo.isStackedByIndex || stackInfo.stackedByDimension)\n            ) {\n                return;\n            }\n\n            stackInfoList.length && data.setCalculationInfo(\n                'stackedOnSeries', stackInfoList[stackInfoList.length - 1].seriesModel\n            );\n\n            stackInfoList.push(stackInfo);\n        }\n    });\n\n    stackInfoMap.each(calculateStack);\n};\n\nfunction calculateStack(stackInfoList) {\n    each$1(stackInfoList, function (targetStackInfo, idxInStack) {\n        var resultVal = [];\n        var resultNaN = [NaN, NaN];\n        var dims = [targetStackInfo.stackResultDimension, targetStackInfo.stackedOverDimension];\n        var targetData = targetStackInfo.data;\n        var isStackedByIndex = targetStackInfo.isStackedByIndex;\n\n        // Should not write on raw data, because stack series model list changes\n        // depending on legend selection.\n        var newData = targetData.map(dims, function (v0, v1, dataIndex) {\n            var sum = targetData.get(targetStackInfo.stackedDimension, dataIndex);\n\n            // Consider `connectNulls` of line area, if value is NaN, stackedOver\n            // should also be NaN, to draw a appropriate belt area.\n            if (isNaN(sum)) {\n                return resultNaN;\n            }\n\n            var byValue;\n            var stackedDataRawIndex;\n\n            if (isStackedByIndex) {\n                stackedDataRawIndex = targetData.getRawIndex(dataIndex);\n            }\n            else {\n                byValue = targetData.get(targetStackInfo.stackedByDimension, dataIndex);\n            }\n\n            // If stackOver is NaN, chart view will render point on value start.\n            var stackedOver = NaN;\n\n            for (var j = idxInStack - 1; j >= 0; j--) {\n                var stackInfo = stackInfoList[j];\n\n                // Has been optimized by inverted indices on `stackedByDimension`.\n                if (!isStackedByIndex) {\n                    stackedDataRawIndex = stackInfo.data.rawIndexOf(stackInfo.stackedByDimension, byValue);\n                }\n\n                if (stackedDataRawIndex >= 0) {\n                    var val = stackInfo.data.getByRawIndex(stackInfo.stackResultDimension, stackedDataRawIndex);\n\n                    // Considering positive stack, negative stack and empty data\n                    if ((sum >= 0 && val > 0) // Positive stack\n                        || (sum <= 0 && val < 0) // Negative stack\n                    ) {\n                        sum += val;\n                        stackedOver = val;\n                        break;\n                    }\n                }\n            }\n\n            resultVal[0] = sum;\n            resultVal[1] = stackedOver;\n\n            return resultVal;\n        });\n\n        targetData.hostModel.setData(newData);\n        // Update for consequent calculation\n        targetStackInfo.data = newData;\n    });\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// TODO\n// ??? refactor? check the outer usage of data provider.\n// merge with defaultDimValueGetter?\n\n/**\n * If normal array used, mutable chunk size is supported.\n * If typed array used, chunk size must be fixed.\n */\nfunction DefaultDataProvider(source, dimSize) {\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n    this._source = source;\n\n    var data = this._data = source.data;\n    var sourceFormat = source.sourceFormat;\n\n    // Typed array. TODO IE10+?\n    if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {\n        if (__DEV__) {\n            if (dimSize == null) {\n                throw new Error('Typed array data must specify dimension size');\n            }\n        }\n        this._offset = 0;\n        this._dimSize = dimSize;\n        this._data = data;\n    }\n\n    var methods = providerMethods[\n        sourceFormat === SOURCE_FORMAT_ARRAY_ROWS\n        ? sourceFormat + '_' + source.seriesLayoutBy\n        : sourceFormat\n    ];\n\n    if (__DEV__) {\n        assert$1(methods, 'Invalide sourceFormat: ' + sourceFormat);\n    }\n\n    extend(this, methods);\n}\n\nvar providerProto = DefaultDataProvider.prototype;\n// If data is pure without style configuration\nproviderProto.pure = false;\n// If data is persistent and will not be released after use.\nproviderProto.persistent = true;\n\n// ???! FIXME legacy data provider do not has method getSource\nproviderProto.getSource = function () {\n    return this._source;\n};\n\nvar providerMethods = {\n\n    'arrayRows_column': {\n        pure: true,\n        count: function () {\n            return Math.max(0, this._data.length - this._source.startIndex);\n        },\n        getItem: function (idx) {\n            return this._data[idx + this._source.startIndex];\n        },\n        appendData: appendDataSimply\n    },\n\n    'arrayRows_row': {\n        pure: true,\n        count: function () {\n            var row = this._data[0];\n            return row ? Math.max(0, row.length - this._source.startIndex) : 0;\n        },\n        getItem: function (idx) {\n            idx += this._source.startIndex;\n            var item = [];\n            var data = this._data;\n            for (var i = 0; i < data.length; i++) {\n                var row = data[i];\n                item.push(row ? row[idx] : null);\n            }\n            return item;\n        },\n        appendData: function () {\n            throw new Error('Do not support appendData when set seriesLayoutBy: \"row\".');\n        }\n    },\n\n    'objectRows': {\n        pure: true,\n        count: countSimply,\n        getItem: getItemSimply,\n        appendData: appendDataSimply\n    },\n\n    'keyedColumns': {\n        pure: true,\n        count: function () {\n            var dimName = this._source.dimensionsDefine[0].name;\n            var col = this._data[dimName];\n            return col ? col.length : 0;\n        },\n        getItem: function (idx) {\n            var item = [];\n            var dims = this._source.dimensionsDefine;\n            for (var i = 0; i < dims.length; i++) {\n                var col = this._data[dims[i].name];\n                item.push(col ? col[idx] : null);\n            }\n            return item;\n        },\n        appendData: function (newData) {\n            var data = this._data;\n            each$1(newData, function (newCol, key) {\n                var oldCol = data[key] || (data[key] = []);\n                for (var i = 0; i < (newCol || []).length; i++) {\n                    oldCol.push(newCol[i]);\n                }\n            });\n        }\n    },\n\n    'original': {\n        count: countSimply,\n        getItem: getItemSimply,\n        appendData: appendDataSimply\n    },\n\n    'typedArray': {\n        persistent: false,\n        pure: true,\n        count: function () {\n            return this._data ? (this._data.length / this._dimSize) : 0;\n        },\n        getItem: function (idx, out) {\n            idx = idx - this._offset;\n            out = out || [];\n            var offset = this._dimSize * idx;\n            for (var i = 0; i < this._dimSize; i++) {\n                out[i] = this._data[offset + i];\n            }\n            return out;\n        },\n        appendData: function (newData) {\n            if (__DEV__) {\n                assert$1(\n                    isTypedArray(newData),\n                    'Added data must be TypedArray if data in initialization is TypedArray'\n                );\n            }\n\n            this._data = newData;\n        },\n\n        // Clean self if data is already used.\n        clean: function () {\n            // PENDING\n            this._offset += this.count();\n            this._data = null;\n        }\n    }\n};\n\nfunction countSimply() {\n    return this._data.length;\n}\nfunction getItemSimply(idx) {\n    return this._data[idx];\n}\nfunction appendDataSimply(newData) {\n    for (var i = 0; i < newData.length; i++) {\n        this._data.push(newData[i]);\n    }\n}\n\n\n\nvar rawValueGetters = {\n\n    arrayRows: getRawValueSimply,\n\n    objectRows: function (dataItem, dataIndex, dimIndex, dimName) {\n        return dimIndex != null ? dataItem[dimName] : dataItem;\n    },\n\n    keyedColumns: getRawValueSimply,\n\n    original: function (dataItem, dataIndex, dimIndex, dimName) {\n        // FIXME\n        // In some case (markpoint in geo (geo-map.html)), dataItem\n        // is {coord: [...]}\n        var value = getDataItemValue(dataItem);\n        return (dimIndex == null || !(value instanceof Array))\n            ? value\n            : value[dimIndex];\n    },\n\n    typedArray: getRawValueSimply\n};\n\nfunction getRawValueSimply(dataItem, dataIndex, dimIndex, dimName) {\n    return dimIndex != null ? dataItem[dimIndex] : dataItem;\n}\n\n\nvar defaultDimValueGetters = {\n\n    arrayRows: getDimValueSimply,\n\n    objectRows: function (dataItem, dimName, dataIndex, dimIndex) {\n        return converDataValue(dataItem[dimName], this._dimensionInfos[dimName]);\n    },\n\n    keyedColumns: getDimValueSimply,\n\n    original: function (dataItem, dimName, dataIndex, dimIndex) {\n        // Performance sensitive, do not use modelUtil.getDataItemValue.\n        // If dataItem is an plain object with no value field, the var `value`\n        // will be assigned with the object, but it will be tread correctly\n        // in the `convertDataValue`.\n        var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value);\n\n        // If any dataItem is like { value: 10 }\n        if (!this._rawData.pure && isDataItemOption(dataItem)) {\n            this.hasItemOption = true;\n        }\n        return converDataValue(\n            (value instanceof Array)\n                ? value[dimIndex]\n                // If value is a single number or something else not array.\n                : value,\n            this._dimensionInfos[dimName]\n        );\n    },\n\n    typedArray: function (dataItem, dimName, dataIndex, dimIndex) {\n        return dataItem[dimIndex];\n    }\n\n};\n\nfunction getDimValueSimply(dataItem, dimName, dataIndex, dimIndex) {\n    return converDataValue(dataItem[dimIndex], this._dimensionInfos[dimName]);\n}\n\n/**\n * This helper method convert value in data.\n * @param {string|number|Date} value\n * @param {Object|string} [dimInfo] If string (like 'x'), dimType defaults 'number'.\n *        If \"dimInfo.ordinalParseAndSave\", ordinal value can be parsed.\n */\nfunction converDataValue(value, dimInfo) {\n    // Performance sensitive.\n    var dimType = dimInfo && dimInfo.type;\n    if (dimType === 'ordinal') {\n        // If given value is a category string\n        var ordinalMeta = dimInfo && dimInfo.ordinalMeta;\n        return ordinalMeta\n            ? ordinalMeta.parseAndCollect(value)\n            : value;\n    }\n\n    if (dimType === 'time'\n        // spead up when using timestamp\n        && typeof value !== 'number'\n        && value != null\n        && value !== '-'\n    ) {\n        value = +parseDate(value);\n    }\n\n    // dimType defaults 'number'.\n    // If dimType is not ordinal and value is null or undefined or NaN or '-',\n    // parse to NaN.\n    return (value == null || value === '')\n        ? NaN\n        // If string (like '-'), using '+' parse to NaN\n        // If object, also parse to NaN\n        : +value;\n}\n\n// ??? FIXME can these logic be more neat: getRawValue, getRawDataItem,\n// Consider persistent.\n// Caution: why use raw value to display on label or tooltip?\n// A reason is to avoid format. For example time value we do not know\n// how to format is expected. More over, if stack is used, calculated\n// value may be 0.91000000001, which have brings trouble to display.\n// TODO: consider how to treat null/undefined/NaN when display?\n/**\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @param {string|number} [dim] dimName or dimIndex\n * @return {Array.<number>|string|number} can be null/undefined.\n */\nfunction retrieveRawValue(data, dataIndex, dim) {\n    if (!data) {\n        return;\n    }\n\n    // Consider data may be not persistent.\n    var dataItem = data.getRawDataItem(dataIndex);\n\n    if (dataItem == null) {\n        return;\n    }\n\n    var sourceFormat = data.getProvider().getSource().sourceFormat;\n    var dimName;\n    var dimIndex;\n\n    var dimInfo = data.getDimensionInfo(dim);\n    if (dimInfo) {\n        dimName = dimInfo.name;\n        dimIndex = dimInfo.index;\n    }\n\n    return rawValueGetters[sourceFormat](dataItem, dataIndex, dimIndex, dimName);\n}\n\n/**\n * Compatible with some cases (in pie, map) like:\n * data: [{name: 'xx', value: 5, selected: true}, ...]\n * where only sourceFormat is 'original' and 'objectRows' supported.\n *\n * ??? TODO\n * Supported detail options in data item when using 'arrayRows'.\n *\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @param {string} attr like 'selected'\n */\nfunction retrieveRawAttr(data, dataIndex, attr) {\n    if (!data) {\n        return;\n    }\n\n    var sourceFormat = data.getProvider().getSource().sourceFormat;\n\n    if (sourceFormat !== SOURCE_FORMAT_ORIGINAL\n        && sourceFormat !== SOURCE_FORMAT_OBJECT_ROWS\n    ) {\n        return;\n    }\n\n    var dataItem = data.getRawDataItem(dataIndex);\n    if (sourceFormat === SOURCE_FORMAT_ORIGINAL && !isObject$1(dataItem)) {\n        dataItem = null;\n    }\n    if (dataItem) {\n        return dataItem[attr];\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar DIMENSION_LABEL_REG = /\\{@(.+?)\\}/g;\n\n// PENDING A little ugly\nvar dataFormatMixin = {\n    /**\n     * Get params for formatter\n     * @param {number} dataIndex\n     * @param {string} [dataType]\n     * @return {Object}\n     */\n    getDataParams: function (dataIndex, dataType) {\n        var data = this.getData(dataType);\n        var rawValue = this.getRawValue(dataIndex, dataType);\n        var rawDataIndex = data.getRawIndex(dataIndex);\n        var name = data.getName(dataIndex);\n        var itemOpt = data.getRawDataItem(dataIndex);\n        var color = data.getItemVisual(dataIndex, 'color');\n        var tooltipModel = this.ecModel.getComponent('tooltip');\n        var renderModeOption = tooltipModel && tooltipModel.get('renderMode');\n        var renderMode = getTooltipRenderMode(renderModeOption);\n        var mainType = this.mainType;\n        var isSeries = mainType === 'series';\n\n        return {\n            componentType: mainType,\n            componentSubType: this.subType,\n            componentIndex: this.componentIndex,\n            seriesType: isSeries ? this.subType : null,\n            seriesIndex: this.seriesIndex,\n            seriesId: isSeries ? this.id : null,\n            seriesName: isSeries ? this.name : null,\n            name: name,\n            dataIndex: rawDataIndex,\n            data: itemOpt,\n            dataType: dataType,\n            value: rawValue,\n            color: color,\n            marker: getTooltipMarker({\n                color: color,\n                renderMode: renderMode\n            }),\n\n            // Param name list for mapping `a`, `b`, `c`, `d`, `e`\n            $vars: ['seriesName', 'name', 'value']\n        };\n    },\n\n    /**\n     * Format label\n     * @param {number} dataIndex\n     * @param {string} [status='normal'] 'normal' or 'emphasis'\n     * @param {string} [dataType]\n     * @param {number} [dimIndex]\n     * @param {string} [labelProp='label']\n     * @return {string} If not formatter, return null/undefined\n     */\n    getFormattedLabel: function (dataIndex, status, dataType, dimIndex, labelProp) {\n        status = status || 'normal';\n        var data = this.getData(dataType);\n        var itemModel = data.getItemModel(dataIndex);\n\n        var params = this.getDataParams(dataIndex, dataType);\n        if (dimIndex != null && (params.value instanceof Array)) {\n            params.value = params.value[dimIndex];\n        }\n\n        var formatter = itemModel.get(\n            status === 'normal'\n            ? [labelProp || 'label', 'formatter']\n            : [status, labelProp || 'label', 'formatter']\n        );\n\n        if (typeof formatter === 'function') {\n            params.status = status;\n            return formatter(params);\n        }\n        else if (typeof formatter === 'string') {\n            var str = formatTpl(formatter, params);\n\n            // Support 'aaa{@[3]}bbb{@product}ccc'.\n            // Do not support '}' in dim name util have to.\n            return str.replace(DIMENSION_LABEL_REG, function (origin, dim) {\n                var len = dim.length;\n                if (dim.charAt(0) === '[' && dim.charAt(len - 1) === ']') {\n                    dim = +dim.slice(1, len - 1); // Also: '[]' => 0\n                }\n                return retrieveRawValue(data, dataIndex, dim);\n            });\n        }\n    },\n\n    /**\n     * Get raw value in option\n     * @param {number} idx\n     * @param {string} [dataType]\n     * @return {Array|number|string}\n     */\n    getRawValue: function (idx, dataType) {\n        return retrieveRawValue(this.getData(dataType), idx);\n    },\n\n    /**\n     * Should be implemented.\n     * @param {number} dataIndex\n     * @param {boolean} [multipleSeries=false]\n     * @param {number} [dataType]\n     * @return {string} tooltip string\n     */\n    formatTooltip: function () {\n        // Empty function\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} define\n * @return See the return of `createTask`.\n */\nfunction createTask(define) {\n    return new Task(define);\n}\n\n/**\n * @constructor\n * @param {Object} define\n * @param {Function} define.reset Custom reset\n * @param {Function} [define.plan] Returns 'reset' indicate reset immediately.\n * @param {Function} [define.count] count is used to determin data task.\n * @param {Function} [define.onDirty] count is used to determin data task.\n */\nfunction Task(define) {\n    define = define || {};\n\n    this._reset = define.reset;\n    this._plan = define.plan;\n    this._count = define.count;\n    this._onDirty = define.onDirty;\n\n    this._dirty = true;\n\n    // Context must be specified implicitly, to\n    // avoid miss update context when model changed.\n    this.context;\n}\n\nvar taskProto = Task.prototype;\n\n/**\n * @param {Object} performArgs\n * @param {number} [performArgs.step] Specified step.\n * @param {number} [performArgs.skip] Skip customer perform call.\n * @param {number} [performArgs.modBy] Sampling window size.\n * @param {number} [performArgs.modDataCount] Sampling count.\n */\ntaskProto.perform = function (performArgs) {\n    var upTask = this._upstream;\n    var skip = performArgs && performArgs.skip;\n\n    // TODO some refactor.\n    // Pull data. Must pull data each time, because context.data\n    // may be updated by Series.setData.\n    if (this._dirty && upTask) {\n        var context = this.context;\n        context.data = context.outputData = upTask.context.outputData;\n    }\n\n    if (this.__pipeline) {\n        this.__pipeline.currentTask = this;\n    }\n\n    var planResult;\n    if (this._plan && !skip) {\n        planResult = this._plan(this.context);\n    }\n\n    // Support sharding by mod, which changes the render sequence and makes the rendered graphic\n    // elements uniformed distributed when progress, especially when moving or zooming.\n    var lastModBy = normalizeModBy(this._modBy);\n    var lastModDataCount = this._modDataCount || 0;\n    var modBy = normalizeModBy(performArgs && performArgs.modBy);\n    var modDataCount = performArgs && performArgs.modDataCount || 0;\n    if (lastModBy !== modBy || lastModDataCount !== modDataCount) {\n        planResult = 'reset';\n    }\n\n    function normalizeModBy(val) {\n        !(val >= 1) && (val = 1); // jshint ignore:line\n        return val;\n    }\n\n    var forceFirstProgress;\n    if (this._dirty || planResult === 'reset') {\n        this._dirty = false;\n        forceFirstProgress = reset(this, skip);\n    }\n\n    this._modBy = modBy;\n    this._modDataCount = modDataCount;\n\n    var step = performArgs && performArgs.step;\n\n    if (upTask) {\n\n        if (__DEV__) {\n            assert$1(upTask._outputDueEnd != null);\n        }\n        this._dueEnd = upTask._outputDueEnd;\n    }\n    // DataTask or overallTask\n    else {\n        if (__DEV__) {\n            assert$1(!this._progress || this._count);\n        }\n        this._dueEnd = this._count ? this._count(this.context) : Infinity;\n    }\n\n    // Note: Stubs, that its host overall task let it has progress, has progress.\n    // If no progress, pass index from upstream to downstream each time plan called.\n    if (this._progress) {\n        var start = this._dueIndex;\n        var end = Math.min(\n            step != null ? this._dueIndex + step : Infinity,\n            this._dueEnd\n        );\n\n        if (!skip && (forceFirstProgress || start < end)) {\n            var progress = this._progress;\n            if (isArray(progress)) {\n                for (var i = 0; i < progress.length; i++) {\n                    doProgress(this, progress[i], start, end, modBy, modDataCount);\n                }\n            }\n            else {\n                doProgress(this, progress, start, end, modBy, modDataCount);\n            }\n        }\n\n        this._dueIndex = end;\n        // If no `outputDueEnd`, assume that output data and\n        // input data is the same, so use `dueIndex` as `outputDueEnd`.\n        var outputDueEnd = this._settedOutputEnd != null\n            ? this._settedOutputEnd : end;\n\n        if (__DEV__) {\n            // ??? Can not rollback.\n            assert$1(outputDueEnd >= this._outputDueEnd);\n        }\n\n        this._outputDueEnd = outputDueEnd;\n    }\n    else {\n        // (1) Some overall task has no progress.\n        // (2) Stubs, that its host overall task do not let it has progress, has no progress.\n        // This should always be performed so it can be passed to downstream.\n        this._dueIndex = this._outputDueEnd = this._settedOutputEnd != null\n            ? this._settedOutputEnd : this._dueEnd;\n    }\n\n    return this.unfinished();\n};\n\nvar iterator = (function () {\n\n    var end;\n    var current;\n    var modBy;\n    var modDataCount;\n    var winCount;\n\n    var it = {\n        reset: function (s, e, sStep, sCount) {\n            current = s;\n            end = e;\n\n            modBy = sStep;\n            modDataCount = sCount;\n            winCount = Math.ceil(modDataCount / modBy);\n\n            it.next = (modBy > 1 && modDataCount > 0) ? modNext : sequentialNext;\n        }\n    };\n\n    return it;\n\n    function sequentialNext() {\n        return current < end ? current++ : null;\n    }\n\n    function modNext() {\n        var dataIndex = (current % winCount) * modBy + Math.ceil(current / winCount);\n        var result = current >= end\n            ? null\n            : dataIndex < modDataCount\n            ? dataIndex\n            // If modDataCount is smaller than data.count() (consider `appendData` case),\n            // Use normal linear rendering mode.\n            : current;\n        current++;\n        return result;\n    }\n})();\n\ntaskProto.dirty = function () {\n    this._dirty = true;\n    this._onDirty && this._onDirty(this.context);\n};\n\nfunction doProgress(taskIns, progress, start, end, modBy, modDataCount) {\n    iterator.reset(start, end, modBy, modDataCount);\n    taskIns._callingProgress = progress;\n    taskIns._callingProgress({\n        start: start, end: end, count: end - start, next: iterator.next\n    }, taskIns.context);\n}\n\nfunction reset(taskIns, skip) {\n    taskIns._dueIndex = taskIns._outputDueEnd = taskIns._dueEnd = 0;\n    taskIns._settedOutputEnd = null;\n\n    var progress;\n    var forceFirstProgress;\n\n    if (!skip && taskIns._reset) {\n        progress = taskIns._reset(taskIns.context);\n        if (progress && progress.progress) {\n            forceFirstProgress = progress.forceFirstProgress;\n            progress = progress.progress;\n        }\n        // To simplify no progress checking, array must has item.\n        if (isArray(progress) && !progress.length) {\n            progress = null;\n        }\n    }\n\n    taskIns._progress = progress;\n    taskIns._modBy = taskIns._modDataCount = null;\n\n    var downstream = taskIns._downstream;\n    downstream && downstream.dirty();\n\n    return forceFirstProgress;\n}\n\n/**\n * @return {boolean}\n */\ntaskProto.unfinished = function () {\n    return this._progress && this._dueIndex < this._dueEnd;\n};\n\n/**\n * @param {Object} downTask The downstream task.\n * @return {Object} The downstream task.\n */\ntaskProto.pipe = function (downTask) {\n    if (__DEV__) {\n        assert$1(downTask && !downTask._disposed && downTask !== this);\n    }\n\n    // If already downstream, do not dirty downTask.\n    if (this._downstream !== downTask || this._dirty) {\n        this._downstream = downTask;\n        downTask._upstream = this;\n        downTask.dirty();\n    }\n};\n\ntaskProto.dispose = function () {\n    if (this._disposed) {\n        return;\n    }\n\n    this._upstream && (this._upstream._downstream = null);\n    this._downstream && (this._downstream._upstream = null);\n\n    this._dirty = false;\n    this._disposed = true;\n};\n\ntaskProto.getUpstream = function () {\n    return this._upstream;\n};\n\ntaskProto.getDownstream = function () {\n    return this._downstream;\n};\n\ntaskProto.setOutputEnd = function (end) {\n    // This only happend in dataTask, dataZoom, map, currently.\n    // where dataZoom do not set end each time, but only set\n    // when reset. So we should record the setted end, in case\n    // that the stub of dataZoom perform again and earse the\n    // setted end by upstream.\n    this._outputDueEnd = this._settedOutputEnd = end;\n};\n\n\n///////////////////////////////////////////////////////////\n// For stream debug (Should be commented out after used!)\n// Usage: printTask(this, 'begin');\n// Usage: printTask(this, null, {someExtraProp});\n// function printTask(task, prefix, extra) {\n//     window.ecTaskUID == null && (window.ecTaskUID = 0);\n//     task.uidDebug == null && (task.uidDebug = `task_${window.ecTaskUID++}`);\n//     task.agent && task.agent.uidDebug == null && (task.agent.uidDebug = `task_${window.ecTaskUID++}`);\n//     var props = [];\n//     if (task.__pipeline) {\n//         var val = `${task.__idxInPipeline}/${task.__pipeline.tail.__idxInPipeline} ${task.agent ? '(stub)' : ''}`;\n//         props.push({text: 'idx', value: val});\n//     } else {\n//         var stubCount = 0;\n//         task.agentStubMap.each(() => stubCount++);\n//         props.push({text: 'idx', value: `overall (stubs: ${stubCount})`});\n//     }\n//     props.push({text: 'uid', value: task.uidDebug});\n//     if (task.__pipeline) {\n//         props.push({text: 'pid', value: task.__pipeline.id});\n//         task.agent && props.push(\n//             {text: 'stubFor', value: task.agent.uidDebug}\n//         );\n//     }\n//     props.push(\n//         {text: 'dirty', value: task._dirty},\n//         {text: 'dueIndex', value: task._dueIndex},\n//         {text: 'dueEnd', value: task._dueEnd},\n//         {text: 'outputDueEnd', value: task._outputDueEnd}\n//     );\n//     if (extra) {\n//         Object.keys(extra).forEach(key => {\n//             props.push({text: key, value: extra[key]});\n//         });\n//     }\n//     var args = ['color: blue'];\n//     var msg = `%c[${prefix || 'T'}] %c` + props.map(item => (\n//         args.push('color: black', 'color: red'),\n//         `${item.text}: %c${item.value}`\n//     )).join('%c, ');\n//     console.log.apply(console, [msg].concat(args));\n//     // console.log(this);\n// }\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$4 = makeInner();\n\nvar SeriesModel = ComponentModel.extend({\n\n    type: 'series.__base__',\n\n    /**\n     * @readOnly\n     */\n    seriesIndex: 0,\n\n    // coodinateSystem will be injected in the echarts/CoordinateSystem\n    coordinateSystem: null,\n\n    /**\n     * @type {Object}\n     * @protected\n     */\n    defaultOption: null,\n\n    /**\n     * Data provided for legend\n     * @type {Function}\n     */\n    // PENDING\n    legendDataProvider: null,\n\n    /**\n     * Access path of color for visual\n     */\n    visualColorAccessPath: 'itemStyle.color',\n\n    /**\n     * Support merge layout params.\n     * Only support 'box' now (left/right/top/bottom/width/height).\n     * @type {string|Object} Object can be {ignoreSize: true}\n     * @readOnly\n     */\n    layoutMode: null,\n\n    init: function (option, parentModel, ecModel, extraOpt) {\n\n        /**\n         * @type {number}\n         * @readOnly\n         */\n        this.seriesIndex = this.componentIndex;\n\n        this.dataTask = createTask({\n            count: dataTaskCount,\n            reset: dataTaskReset\n        });\n        this.dataTask.context = {model: this};\n\n        this.mergeDefaultAndTheme(option, ecModel);\n\n        prepareSource(this);\n\n\n        var data = this.getInitialData(option, ecModel);\n        wrapData(data, this);\n        this.dataTask.context.data = data;\n\n        if (__DEV__) {\n            assert$1(data, 'getInitialData returned invalid data.');\n        }\n\n        /**\n         * @type {module:echarts/data/List|module:echarts/data/Tree|module:echarts/data/Graph}\n         * @private\n         */\n        inner$4(this).dataBeforeProcessed = data;\n\n        // If we reverse the order (make data firstly, and then make\n        // dataBeforeProcessed by cloneShallow), cloneShallow will\n        // cause data.graph.data !== data when using\n        // module:echarts/data/Graph or module:echarts/data/Tree.\n        // See module:echarts/data/helper/linkList\n\n        // Theoretically, it is unreasonable to call `seriesModel.getData()` in the model\n        // init or merge stage, because the data can be restored. So we do not `restoreData`\n        // and `setData` here, which forbids calling `seriesModel.getData()` in this stage.\n        // Call `seriesModel.getRawData()` instead.\n        // this.restoreData();\n\n        autoSeriesName(this);\n    },\n\n    /**\n     * Util for merge default and theme to option\n     * @param  {Object} option\n     * @param  {module:echarts/model/Global} ecModel\n     */\n    mergeDefaultAndTheme: function (option, ecModel) {\n        var layoutMode = this.layoutMode;\n        var inputPositionParams = layoutMode\n            ? getLayoutParams(option) : {};\n\n        // Backward compat: using subType on theme.\n        // But if name duplicate between series subType\n        // (for example: parallel) add component mainType,\n        // add suffix 'Series'.\n        var themeSubType = this.subType;\n        if (ComponentModel.hasClass(themeSubType)) {\n            themeSubType += 'Series';\n        }\n        merge(\n            option,\n            ecModel.getTheme().get(this.subType)\n        );\n        merge(option, this.getDefaultOption());\n\n        // Default label emphasis `show`\n        defaultEmphasis(option, 'label', ['show']);\n\n        this.fillDataTextStyle(option.data);\n\n        if (layoutMode) {\n            mergeLayoutParam(option, inputPositionParams, layoutMode);\n        }\n    },\n\n    mergeOption: function (newSeriesOption, ecModel) {\n        // this.settingTask.dirty();\n\n        newSeriesOption = merge(this.option, newSeriesOption, true);\n        this.fillDataTextStyle(newSeriesOption.data);\n\n        var layoutMode = this.layoutMode;\n        if (layoutMode) {\n            mergeLayoutParam(this.option, newSeriesOption, layoutMode);\n        }\n\n        prepareSource(this);\n\n        var data = this.getInitialData(newSeriesOption, ecModel);\n        wrapData(data, this);\n        this.dataTask.dirty();\n        this.dataTask.context.data = data;\n\n        inner$4(this).dataBeforeProcessed = data;\n\n        autoSeriesName(this);\n    },\n\n    fillDataTextStyle: function (data) {\n        // Default data label emphasis `show`\n        // FIXME Tree structure data ?\n        // FIXME Performance ?\n        if (data && !isTypedArray(data)) {\n            var props = ['show'];\n            for (var i = 0; i < data.length; i++) {\n                if (data[i] && data[i].label) {\n                    defaultEmphasis(data[i], 'label', props);\n                }\n            }\n        }\n    },\n\n    /**\n     * Init a data structure from data related option in series\n     * Must be overwritten\n     */\n    getInitialData: function () {},\n\n    /**\n     * Append data to list\n     * @param {Object} params\n     * @param {Array|TypedArray} params.data\n     */\n    appendData: function (params) {\n        // FIXME ???\n        // (1) If data from dataset, forbidden append.\n        // (2) support append data of dataset.\n        var data = this.getRawData();\n        data.appendData(params.data);\n    },\n\n    /**\n     * Consider some method like `filter`, `map` need make new data,\n     * We should make sure that `seriesModel.getData()` get correct\n     * data in the stream procedure. So we fetch data from upstream\n     * each time `task.perform` called.\n     * @param {string} [dataType]\n     * @return {module:echarts/data/List}\n     */\n    getData: function (dataType) {\n        var task = getCurrentTask(this);\n        if (task) {\n            var data = task.context.data;\n            return dataType == null ? data : data.getLinkedData(dataType);\n        }\n        else {\n            // When series is not alive (that may happen when click toolbox\n            // restore or setOption with not merge mode), series data may\n            // be still need to judge animation or something when graphic\n            // elements want to know whether fade out.\n            return inner$4(this).data;\n        }\n    },\n\n    /**\n     * @param {module:echarts/data/List} data\n     */\n    setData: function (data) {\n        var task = getCurrentTask(this);\n        if (task) {\n            var context = task.context;\n            // Consider case: filter, data sample.\n            if (context.data !== data && task.modifyOutputEnd) {\n                task.setOutputEnd(data.count());\n            }\n            context.outputData = data;\n            // Caution: setData should update context.data,\n            // Because getData may be called multiply in a\n            // single stage and expect to get the data just\n            // set. (For example, AxisProxy, x y both call\n            // getData and setDate sequentially).\n            // So the context.data should be fetched from\n            // upstream each time when a stage starts to be\n            // performed.\n            if (task !== this.dataTask) {\n                context.data = data;\n            }\n        }\n        inner$4(this).data = data;\n    },\n\n    /**\n     * @see {module:echarts/data/helper/sourceHelper#getSource}\n     * @return {module:echarts/data/Source} source\n     */\n    getSource: function () {\n        return getSource(this);\n    },\n\n    /**\n     * Get data before processed\n     * @return {module:echarts/data/List}\n     */\n    getRawData: function () {\n        return inner$4(this).dataBeforeProcessed;\n    },\n\n    /**\n     * Get base axis if has coordinate system and has axis.\n     * By default use coordSys.getBaseAxis();\n     * Can be overrided for some chart.\n     * @return {type} description\n     */\n    getBaseAxis: function () {\n        var coordSys = this.coordinateSystem;\n        return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis();\n    },\n\n    // FIXME\n    /**\n     * Default tooltip formatter\n     *\n     * @param {number} dataIndex\n     * @param {boolean} [multipleSeries=false]\n     * @param {number} [dataType]\n     * @param {string} [renderMode='html'] valid values: 'html' and 'richText'.\n     *                                     'html' is used for rendering tooltip in extra DOM form, and the result\n     *                                     string is used as DOM HTML content.\n     *                                     'richText' is used for rendering tooltip in rich text form, for those where\n     *                                     DOM operation is not supported.\n     * @return {Object} formatted tooltip with `html` and `markers`\n     */\n    formatTooltip: function (dataIndex, multipleSeries, dataType, renderMode) {\n\n        var series = this;\n        renderMode = renderMode || 'html';\n        var newLine = renderMode === 'html' ? '<br/>' : '\\n';\n        var isRichText = renderMode === 'richText';\n        var markers = {};\n        var markerId = 0;\n\n        function formatArrayValue(value) {\n            // ??? TODO refactor these logic.\n            // check: category-no-encode-has-axis-data in dataset.html\n            var vertially = reduce(value, function (vertially, val, idx) {\n                var dimItem = data.getDimensionInfo(idx);\n                return vertially |= dimItem && dimItem.tooltip !== false && dimItem.displayName != null;\n            }, 0);\n\n            var result = [];\n\n            tooltipDims.length\n                ? each$1(tooltipDims, function (dim) {\n                    setEachItem(retrieveRawValue(data, dataIndex, dim), dim);\n                })\n                // By default, all dims is used on tooltip.\n                : each$1(value, setEachItem);\n\n            function setEachItem(val, dim) {\n                var dimInfo = data.getDimensionInfo(dim);\n                // If `dimInfo.tooltip` is not set, show tooltip.\n                if (!dimInfo || dimInfo.otherDims.tooltip === false) {\n                    return;\n                }\n                var dimType = dimInfo.type;\n                var markName = 'sub' + series.seriesIndex + 'at' + markerId;\n                var dimHead = getTooltipMarker({\n                    color: color,\n                    type: 'subItem',\n                    renderMode: renderMode,\n                    markerId: markName\n                });\n\n                var dimHeadStr = typeof dimHead === 'string' ? dimHead : dimHead.content;\n                var valStr = (vertially\n                        ? dimHeadStr + encodeHTML(dimInfo.displayName || '-') + ': '\n                        : ''\n                    )\n                    // FIXME should not format time for raw data?\n                    + encodeHTML(dimType === 'ordinal'\n                        ? val + ''\n                        : dimType === 'time'\n                        ? (multipleSeries ? '' : formatTime('yyyy/MM/dd hh:mm:ss', val))\n                        : addCommas(val)\n                    );\n                valStr && result.push(valStr);\n\n                if (isRichText) {\n                    markers[markName] = color;\n                    ++markerId;\n                }\n            }\n\n            var newLine = vertially ? (isRichText ? '\\n' : '<br/>') : '';\n            var content = newLine + result.join(newLine || ', ');\n            return {\n                renderMode: renderMode,\n                content: content,\n                style: markers\n            };\n        }\n\n        function formatSingleValue(val) {\n            // return encodeHTML(addCommas(val));\n            return {\n                renderMode: renderMode,\n                content: encodeHTML(addCommas(val)),\n                style: markers\n            };\n        }\n\n        var data = this.getData();\n        var tooltipDims = data.mapDimension('defaultedTooltip', true);\n        var tooltipDimLen = tooltipDims.length;\n        var value = this.getRawValue(dataIndex);\n        var isValueArr = isArray(value);\n\n        var color = data.getItemVisual(dataIndex, 'color');\n        if (isObject$1(color) && color.colorStops) {\n            color = (color.colorStops[0] || {}).color;\n        }\n        color = color || 'transparent';\n\n        // Complicated rule for pretty tooltip.\n        var formattedValue = (tooltipDimLen > 1 || (isValueArr && !tooltipDimLen))\n            ? formatArrayValue(value)\n            : tooltipDimLen\n            ? formatSingleValue(retrieveRawValue(data, dataIndex, tooltipDims[0]))\n            : formatSingleValue(isValueArr ? value[0] : value);\n        var content = formattedValue.content;\n\n        var markName = series.seriesIndex + 'at' + markerId;\n        var colorEl = getTooltipMarker({\n            color: color,\n            type: 'item',\n            renderMode: renderMode,\n            markerId: markName\n        });\n        markers[markName] = color;\n        ++markerId;\n\n        var name = data.getName(dataIndex);\n\n        var seriesName = this.name;\n        if (!isNameSpecified(this)) {\n            seriesName = '';\n        }\n        seriesName = seriesName\n            ? encodeHTML(seriesName) + (!multipleSeries ? newLine : ': ')\n            : '';\n\n        var colorStr = typeof colorEl === 'string' ? colorEl : colorEl.content;\n        var html = !multipleSeries\n            ? seriesName + colorStr\n                + (name\n                    ? encodeHTML(name) + ': ' + content\n                    : content\n                )\n            : colorStr + seriesName + content;\n\n        return {\n            html: html,\n            markers: markers\n        };\n    },\n\n    /**\n     * @return {boolean}\n     */\n    isAnimationEnabled: function () {\n        if (env$1.node) {\n            return false;\n        }\n\n        var animationEnabled = this.getShallow('animation');\n        if (animationEnabled) {\n            if (this.getData().count() > this.getShallow('animationThreshold')) {\n                animationEnabled = false;\n            }\n        }\n        return animationEnabled;\n    },\n\n    restoreData: function () {\n        this.dataTask.dirty();\n    },\n\n    getColorFromPalette: function (name, scope, requestColorNum) {\n        var ecModel = this.ecModel;\n        // PENDING\n        var color = colorPaletteMixin.getColorFromPalette.call(this, name, scope, requestColorNum);\n        if (!color) {\n            color = ecModel.getColorFromPalette(name, scope, requestColorNum);\n        }\n        return color;\n    },\n\n    /**\n     * Use `data.mapDimension(coordDim, true)` instead.\n     * @deprecated\n     */\n    coordDimToDataDim: function (coordDim) {\n        return this.getRawData().mapDimension(coordDim, true);\n    },\n\n    /**\n     * Get progressive rendering count each step\n     * @return {number}\n     */\n    getProgressive: function () {\n        return this.get('progressive');\n    },\n\n    /**\n     * Get progressive rendering count each step\n     * @return {number}\n     */\n    getProgressiveThreshold: function () {\n        return this.get('progressiveThreshold');\n    },\n\n    /**\n     * Get data indices for show tooltip content. See tooltip.\n     * @abstract\n     * @param {Array.<string>|string} dim\n     * @param {Array.<number>} value\n     * @param {module:echarts/coord/single/SingleAxis} baseAxis\n     * @return {Object} {dataIndices, nestestValue}.\n     */\n    getAxisTooltipData: null,\n\n    /**\n     * See tooltip.\n     * @abstract\n     * @param {number} dataIndex\n     * @return {Array.<number>} Point of tooltip. null/undefined can be returned.\n     */\n    getTooltipPosition: null,\n\n    /**\n     * @see {module:echarts/stream/Scheduler}\n     */\n    pipeTask: null,\n\n    /**\n     * Convinient for override in extended class.\n     * @protected\n     * @type {Function}\n     */\n    preventIncremental: null,\n\n    /**\n     * @public\n     * @readOnly\n     * @type {Object}\n     */\n    pipelineContext: null\n\n});\n\n\nmixin(SeriesModel, dataFormatMixin);\nmixin(SeriesModel, colorPaletteMixin);\n\n/**\n * MUST be called after `prepareSource` called\n * Here we need to make auto series, especially for auto legend. But we\n * do not modify series.name in option to avoid side effects.\n */\nfunction autoSeriesName(seriesModel) {\n    // User specified name has higher priority, otherwise it may cause\n    // series can not be queried unexpectedly.\n    var name = seriesModel.name;\n    if (!isNameSpecified(seriesModel)) {\n        seriesModel.name = getSeriesAutoName(seriesModel) || name;\n    }\n}\n\nfunction getSeriesAutoName(seriesModel) {\n    var data = seriesModel.getRawData();\n    var dataDims = data.mapDimension('seriesName', true);\n    var nameArr = [];\n    each$1(dataDims, function (dataDim) {\n        var dimInfo = data.getDimensionInfo(dataDim);\n        dimInfo.displayName && nameArr.push(dimInfo.displayName);\n    });\n    return nameArr.join(' ');\n}\n\nfunction dataTaskCount(context) {\n    return context.model.getRawData().count();\n}\n\nfunction dataTaskReset(context) {\n    var seriesModel = context.model;\n    seriesModel.setData(seriesModel.getRawData().cloneShallow());\n    return dataTaskProgress;\n}\n\nfunction dataTaskProgress(param, context) {\n    // Avoid repead cloneShallow when data just created in reset.\n    if (param.end > context.outputData.count()) {\n        context.model.getRawData().cloneShallow(context.outputData);\n    }\n}\n\n// TODO refactor\nfunction wrapData(data, seriesModel) {\n    each$1(data.CHANGABLE_METHODS, function (methodName) {\n        data.wrapMethod(methodName, curry(onDataSelfChange, seriesModel));\n    });\n}\n\nfunction onDataSelfChange(seriesModel) {\n    var task = getCurrentTask(seriesModel);\n    if (task) {\n        // Consider case: filter, selectRange\n        task.setOutputEnd(this.count());\n    }\n}\n\nfunction getCurrentTask(seriesModel) {\n    var scheduler = (seriesModel.ecModel || {}).scheduler;\n    var pipeline = scheduler && scheduler.getPipeline(seriesModel.uid);\n\n    if (pipeline) {\n        // When pipline finished, the currrentTask keep the last\n        // task (renderTask).\n        var task = pipeline.currentTask;\n        if (task) {\n            var agentStubMap = task.agentStubMap;\n            if (agentStubMap) {\n                task = agentStubMap.get(seriesModel.uid);\n            }\n        }\n        return task;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar Component = function () {\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.uid = getUID('viewComponent');\n};\n\nComponent.prototype = {\n\n    constructor: Component,\n\n    init: function (ecModel, api) {},\n\n    render: function (componentModel, ecModel, api, payload) {},\n\n    dispose: function () {},\n\n    /**\n     * @param {string} eventType\n     * @param {Object} query\n     * @param {module:zrender/Element} targetEl\n     * @param {Object} packedEvent\n     * @return {boolen} Pass only when return `true`.\n     */\n    filterForExposedEvent: null\n\n};\n\nvar componentProto = Component.prototype;\ncomponentProto.updateView\n    = componentProto.updateLayout\n    = componentProto.updateVisual\n    = function (seriesModel, ecModel, api, payload) {\n        // Do nothing;\n    };\n// Enable Component.extend.\nenableClassExtend(Component);\n\n// Enable capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(Component, {registerWhenExtend: true});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @return {string} If large mode changed, return string 'reset';\n */\nvar createRenderPlanner = function () {\n    var inner = makeInner();\n\n    return function (seriesModel) {\n        var fields = inner(seriesModel);\n        var pipelineContext = seriesModel.pipelineContext;\n\n        var originalLarge = fields.large;\n        var originalProgressive = fields.progressiveRender;\n\n        var large = fields.large = pipelineContext.large;\n        var progressive = fields.progressiveRender = pipelineContext.progressiveRender;\n\n        return !!((originalLarge ^ large) || (originalProgressive ^ progressive)) && 'reset';\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$5 = makeInner();\nvar renderPlanner = createRenderPlanner();\n\nfunction Chart() {\n\n    /**\n     * @type {module:zrender/container/Group}\n     * @readOnly\n     */\n    this.group = new Group();\n\n    /**\n     * @type {string}\n     * @readOnly\n     */\n    this.uid = getUID('viewChart');\n\n    this.renderTask = createTask({\n        plan: renderTaskPlan,\n        reset: renderTaskReset\n    });\n    this.renderTask.context = {view: this};\n}\n\nChart.prototype = {\n\n    type: 'chart',\n\n    /**\n     * Init the chart.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    init: function (ecModel, api) {},\n\n    /**\n     * Render the chart.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    render: function (seriesModel, ecModel, api, payload) {},\n\n    /**\n     * Highlight series or specified data item.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    highlight: function (seriesModel, ecModel, api, payload) {\n        toggleHighlight(seriesModel.getData(), payload, 'emphasis');\n    },\n\n    /**\n     * Downplay series or specified data item.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    downplay: function (seriesModel, ecModel, api, payload) {\n        toggleHighlight(seriesModel.getData(), payload, 'normal');\n    },\n\n    /**\n     * Remove self.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    remove: function (ecModel, api) {\n        this.group.removeAll();\n    },\n\n    /**\n     * Dispose self.\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     */\n    dispose: function () {},\n\n    /**\n     * Rendering preparation in progressive mode.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    incrementalPrepareRender: null,\n\n    /**\n     * Render in progressive mode.\n     * @param  {Object} params See taskParams in `stream/task.js`\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     */\n    incrementalRender: null,\n\n    /**\n     * Update transform directly.\n     * @param  {module:echarts/model/Series} seriesModel\n     * @param  {module:echarts/model/Global} ecModel\n     * @param  {module:echarts/ExtensionAPI} api\n     * @param  {Object} payload\n     * @return {Object} {update: true}\n     */\n    updateTransform: null,\n\n    /**\n     * The view contains the given point.\n     * @interface\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    // containPoint: function () {}\n\n    /**\n     * @param {string} eventType\n     * @param {Object} query\n     * @param {module:zrender/Element} targetEl\n     * @param {Object} packedEvent\n     * @return {boolen} Pass only when return `true`.\n     */\n    filterForExposedEvent: null\n\n};\n\nvar chartProto = Chart.prototype;\nchartProto.updateView\n    = chartProto.updateLayout\n    = chartProto.updateVisual\n    = function (seriesModel, ecModel, api, payload) {\n        this.render(seriesModel, ecModel, api, payload);\n    };\n\n/**\n * Set state of single element\n * @param  {module:zrender/Element} el\n * @param  {string} state\n */\nfunction elSetState(el, state) {\n    if (el) {\n        el.trigger(state);\n        if (el.type === 'group') {\n            for (var i = 0; i < el.childCount(); i++) {\n                elSetState(el.childAt(i), state);\n            }\n        }\n    }\n}\n/**\n * @param  {module:echarts/data/List} data\n * @param  {Object} payload\n * @param  {string} state 'normal'|'emphasis'\n */\nfunction toggleHighlight(data, payload, state) {\n    var dataIndex = queryDataIndex(data, payload);\n\n    if (dataIndex != null) {\n        each$1(normalizeToArray(dataIndex), function (dataIdx) {\n            elSetState(data.getItemGraphicEl(dataIdx), state);\n        });\n    }\n    else {\n        data.eachItemGraphicEl(function (el) {\n            elSetState(el, state);\n        });\n    }\n}\n\n// Enable Chart.extend.\nenableClassExtend(Chart, ['dispose']);\n\n// Add capability of registerClass, getClass, hasClass, registerSubTypeDefaulter and so on.\nenableClassManagement(Chart, {registerWhenExtend: true});\n\nChart.markUpdateMethod = function (payload, methodName) {\n    inner$5(payload).updateMethod = methodName;\n};\n\nfunction renderTaskPlan(context) {\n    return renderPlanner(context.model);\n}\n\nfunction renderTaskReset(context) {\n    var seriesModel = context.model;\n    var ecModel = context.ecModel;\n    var api = context.api;\n    var payload = context.payload;\n    // ???! remove updateView updateVisual\n    var progressiveRender = seriesModel.pipelineContext.progressiveRender;\n    var view = context.view;\n\n    var updateMethod = payload && inner$5(payload).updateMethod;\n    var methodName = progressiveRender\n        ? 'incrementalPrepareRender'\n        : (updateMethod && view[updateMethod])\n        ? updateMethod\n        // `appendData` is also supported when data amount\n        // is less than progressive threshold.\n        : 'render';\n\n    if (methodName !== 'render') {\n        view[methodName](seriesModel, ecModel, api, payload);\n    }\n\n    return progressMethodMap[methodName];\n}\n\nvar progressMethodMap = {\n    incrementalPrepareRender: {\n        progress: function (params, context) {\n            context.view.incrementalRender(\n                params, context.model, context.ecModel, context.api, context.payload\n            );\n        }\n    },\n    render: {\n        // Put view.render in `progress` to support appendData. But in this case\n        // view.render should not be called in reset, otherwise it will be called\n        // twise. Use `forceFirstProgress` to make sure that view.render is called\n        // in any cases.\n        forceFirstProgress: true,\n        progress: function (params, context) {\n            context.view.render(\n                context.model, context.ecModel, context.api, context.payload\n            );\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * @public\n * @param {(Function)} fn\n * @param {number} [delay=0] Unit: ms.\n * @param {boolean} [debounce=false]\n *        true: If call interval less than `delay`, only the last call works.\n *        false: If call interval less than `delay, call works on fixed rate.\n * @return {(Function)} throttled fn.\n */\nfunction throttle(fn, delay, debounce) {\n\n    var currCall;\n    var lastCall = 0;\n    var lastExec = 0;\n    var timer = null;\n    var diff;\n    var scope;\n    var args;\n    var debounceNextCall;\n\n    delay = delay || 0;\n\n    function exec() {\n        lastExec = (new Date()).getTime();\n        timer = null;\n        fn.apply(scope, args || []);\n    }\n\n    var cb = function () {\n        currCall = (new Date()).getTime();\n        scope = this;\n        args = arguments;\n        var thisDelay = debounceNextCall || delay;\n        var thisDebounce = debounceNextCall || debounce;\n        debounceNextCall = null;\n        diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay;\n\n        clearTimeout(timer);\n\n        // Here we should make sure that: the `exec` SHOULD NOT be called later\n        // than a new call of `cb`, that is, preserving the command order. Consider\n        // calculating \"scale rate\" when roaming as an example. When a call of `cb`\n        // happens, either the `exec` is called dierectly, or the call is delayed.\n        // But the delayed call should never be later than next call of `cb`. Under\n        // this assurance, we can simply update view state each time `dispatchAction`\n        // triggered by user roaming, but not need to add extra code to avoid the\n        // state being \"rolled-back\".\n        if (thisDebounce) {\n            timer = setTimeout(exec, thisDelay);\n        }\n        else {\n            if (diff >= 0) {\n                exec();\n            }\n            else {\n                timer = setTimeout(exec, -diff);\n            }\n        }\n\n        lastCall = currCall;\n    };\n\n    /**\n     * Clear throttle.\n     * @public\n     */\n    cb.clear = function () {\n        if (timer) {\n            clearTimeout(timer);\n            timer = null;\n        }\n    };\n\n    /**\n     * Enable debounce once.\n     */\n    cb.debounceNextCall = function (debounceDelay) {\n        debounceNextCall = debounceDelay;\n    };\n\n    return cb;\n}\n\n/**\n * Create throttle method or update throttle rate.\n *\n * @example\n * ComponentView.prototype.render = function () {\n *     ...\n *     throttle.createOrUpdate(\n *         this,\n *         '_dispatchAction',\n *         this.model.get('throttle'),\n *         'fixRate'\n *     );\n * };\n * ComponentView.prototype.remove = function () {\n *     throttle.clear(this, '_dispatchAction');\n * };\n * ComponentView.prototype.dispose = function () {\n *     throttle.clear(this, '_dispatchAction');\n * };\n *\n * @public\n * @param {Object} obj\n * @param {string} fnAttr\n * @param {number} [rate]\n * @param {string} [throttleType='fixRate'] 'fixRate' or 'debounce'\n * @return {Function} throttled function.\n */\n\n\n/**\n * Clear throttle. Example see throttle.createOrUpdate.\n *\n * @public\n * @param {Object} obj\n * @param {string} fnAttr\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar seriesColor = {\n    createOnAllSeries: true,\n    performRawSeries: true,\n    reset: function (seriesModel, ecModel) {\n        var data = seriesModel.getData();\n        var colorAccessPath = (seriesModel.visualColorAccessPath || 'itemStyle.color').split('.');\n        var color = seriesModel.get(colorAccessPath) // Set in itemStyle\n            || seriesModel.getColorFromPalette(\n                // TODO series count changed.\n                seriesModel.name, null, ecModel.getSeriesCount()\n            );  // Default color\n\n        // FIXME Set color function or use the platte color\n        data.setVisual('color', color);\n\n        // Only visible series has each data be visual encoded\n        if (!ecModel.isSeriesFiltered(seriesModel)) {\n            if (typeof color === 'function' && !(color instanceof Gradient)) {\n                data.each(function (idx) {\n                    data.setItemVisual(\n                        idx, 'color', color(seriesModel.getDataParams(idx))\n                    );\n                });\n            }\n\n            // itemStyle in each data item\n            var dataEach = function (data, idx) {\n                var itemModel = data.getItemModel(idx);\n                var color = itemModel.get(colorAccessPath, true);\n                if (color != null) {\n                    data.setItemVisual(idx, 'color', color);\n                }\n            };\n\n            return { dataEach: data.hasItemOption ? dataEach : null };\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar lang = {\n    toolbox: {\n        brush: {\n            title: {\n                rect: '矩形选择',\n                polygon: '圈选',\n                lineX: '横向选择',\n                lineY: '纵向选择',\n                keep: '保持选择',\n                clear: '清除选择'\n            }\n        },\n        dataView: {\n            title: '数据视图',\n            lang: ['数据视图', '关闭', '刷新']\n        },\n        dataZoom: {\n            title: {\n                zoom: '区域缩放',\n                back: '区域缩放还原'\n            }\n        },\n        magicType: {\n            title: {\n                line: '切换为折线图',\n                bar: '切换为柱状图',\n                stack: '切换为堆叠',\n                tiled: '切换为平铺'\n            }\n        },\n        restore: {\n            title: '还原'\n        },\n        saveAsImage: {\n            title: '保存为图片',\n            lang: ['右键另存为图片']\n        }\n    },\n    series: {\n        typeNames: {\n            pie: '饼图',\n            bar: '柱状图',\n            line: '折线图',\n            scatter: '散点图',\n            effectScatter: '涟漪散点图',\n            radar: '雷达图',\n            tree: '树图',\n            treemap: '矩形树图',\n            boxplot: '箱型图',\n            candlestick: 'K线图',\n            k: 'K线图',\n            heatmap: '热力图',\n            map: '地图',\n            parallel: '平行坐标图',\n            lines: '线图',\n            graph: '关系图',\n            sankey: '桑基图',\n            funnel: '漏斗图',\n            gauge: '仪表盘图',\n            pictorialBar: '象形柱图',\n            themeRiver: '主题河流图',\n            sunburst: '旭日图'\n        }\n    },\n    aria: {\n        general: {\n            withTitle: '这是一个关于“{title}”的图表。',\n            withoutTitle: '这是一个图表，'\n        },\n        series: {\n            single: {\n                prefix: '',\n                withName: '图表类型是{seriesType}，表示{seriesName}。',\n                withoutName: '图表类型是{seriesType}。'\n            },\n            multiple: {\n                prefix: '它由{seriesCount}个图表系列组成。',\n                withName: '第{seriesId}个系列是一个表示{seriesName}的{seriesType}，',\n                withoutName: '第{seriesId}个系列是一个{seriesType}，',\n                separator: {\n                    middle: '；',\n                    end: '。'\n                }\n            }\n        },\n        data: {\n            allData: '其数据是——',\n            partialData: '其中，前{displayCnt}项是——',\n            withName: '{name}的数据是{value}',\n            withoutName: '{value}',\n            separator: {\n                middle: '，',\n                end: ''\n            }\n        }\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar aria = function (dom, ecModel) {\n    var ariaModel = ecModel.getModel('aria');\n    if (!ariaModel.get('show')) {\n        return;\n    }\n    else if (ariaModel.get('description')) {\n        dom.setAttribute('aria-label', ariaModel.get('description'));\n        return;\n    }\n\n    var seriesCnt = 0;\n    ecModel.eachSeries(function (seriesModel, idx) {\n        ++seriesCnt;\n    }, this);\n\n    var maxDataCnt = ariaModel.get('data.maxCount') || 10;\n    var maxSeriesCnt = ariaModel.get('series.maxCount') || 10;\n    var displaySeriesCnt = Math.min(seriesCnt, maxSeriesCnt);\n\n    var ariaLabel;\n    if (seriesCnt < 1) {\n        // No series, no aria label\n        return;\n    }\n    else {\n        var title = getTitle();\n        if (title) {\n            ariaLabel = replace(getConfig('general.withTitle'), {\n                title: title\n            });\n        }\n        else {\n            ariaLabel = getConfig('general.withoutTitle');\n        }\n\n        var seriesLabels = [];\n        var prefix = seriesCnt > 1\n            ? 'series.multiple.prefix'\n            : 'series.single.prefix';\n        ariaLabel += replace(getConfig(prefix), { seriesCount: seriesCnt });\n\n        ecModel.eachSeries(function (seriesModel, idx) {\n            if (idx < displaySeriesCnt) {\n                var seriesLabel;\n\n                var seriesName = seriesModel.get('name');\n                var seriesTpl = 'series.'\n                    + (seriesCnt > 1 ? 'multiple' : 'single') + '.';\n                seriesLabel = getConfig(seriesName\n                    ? seriesTpl + 'withName'\n                    : seriesTpl + 'withoutName');\n\n                seriesLabel = replace(seriesLabel, {\n                    seriesId: seriesModel.seriesIndex,\n                    seriesName: seriesModel.get('name'),\n                    seriesType: getSeriesTypeName(seriesModel.subType)\n                });\n\n                var data = seriesModel.getData();\n                window.data = data;\n                if (data.count() > maxDataCnt) {\n                    // Show part of data\n                    seriesLabel += replace(getConfig('data.partialData'), {\n                        displayCnt: maxDataCnt\n                    });\n                }\n                else {\n                    seriesLabel += getConfig('data.allData');\n                }\n\n                var dataLabels = [];\n                for (var i = 0; i < data.count(); i++) {\n                    if (i < maxDataCnt) {\n                        var name = data.getName(i);\n                        var value = retrieveRawValue(data, i);\n                        dataLabels.push(\n                            replace(\n                                name\n                                    ? getConfig('data.withName')\n                                    : getConfig('data.withoutName'),\n                                {\n                                    name: name,\n                                    value: value\n                                }\n                            )\n                        );\n                    }\n                }\n                seriesLabel += dataLabels\n                    .join(getConfig('data.separator.middle'))\n                    + getConfig('data.separator.end');\n\n                seriesLabels.push(seriesLabel);\n            }\n        });\n\n        ariaLabel += seriesLabels\n            .join(getConfig('series.multiple.separator.middle'))\n            + getConfig('series.multiple.separator.end');\n\n        dom.setAttribute('aria-label', ariaLabel);\n    }\n\n    function replace(str, keyValues) {\n        if (typeof str !== 'string') {\n            return str;\n        }\n\n        var result = str;\n        each$1(keyValues, function (value, key) {\n            result = result.replace(\n                new RegExp('\\\\{\\\\s*' + key + '\\\\s*\\\\}', 'g'),\n                value\n            );\n        });\n        return result;\n    }\n\n    function getConfig(path) {\n        var userConfig = ariaModel.get(path);\n        if (userConfig == null) {\n            var pathArr = path.split('.');\n            var result = lang.aria;\n            for (var i = 0; i < pathArr.length; ++i) {\n                result = result[pathArr[i]];\n            }\n            return result;\n        }\n        else {\n            return userConfig;\n        }\n    }\n\n    function getTitle() {\n        var title = ecModel.getModel('title').option;\n        if (title && title.length) {\n            title = title[0];\n        }\n        return title && title.text;\n    }\n\n    function getSeriesTypeName(type) {\n        return lang.series.typeNames[type] || '自定义图';\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PI$1 = Math.PI;\n\n/**\n * @param {module:echarts/ExtensionAPI} api\n * @param {Object} [opts]\n * @param {string} [opts.text]\n * @param {string} [opts.color]\n * @param {string} [opts.textColor]\n * @return {module:zrender/Element}\n */\nvar loadingDefault = function (api, opts) {\n    opts = opts || {};\n    defaults(opts, {\n        text: 'loading',\n        color: '#c23531',\n        textColor: '#000',\n        maskColor: 'rgba(255, 255, 255, 0.8)',\n        zlevel: 0\n    });\n    var mask = new Rect({\n        style: {\n            fill: opts.maskColor\n        },\n        zlevel: opts.zlevel,\n        z: 10000\n    });\n    var arc = new Arc({\n        shape: {\n            startAngle: -PI$1 / 2,\n            endAngle: -PI$1 / 2 + 0.1,\n            r: 10\n        },\n        style: {\n            stroke: opts.color,\n            lineCap: 'round',\n            lineWidth: 5\n        },\n        zlevel: opts.zlevel,\n        z: 10001\n    });\n    var labelRect = new Rect({\n        style: {\n            fill: 'none',\n            text: opts.text,\n            textPosition: 'right',\n            textDistance: 10,\n            textFill: opts.textColor\n        },\n        zlevel: opts.zlevel,\n        z: 10001\n    });\n\n    arc.animateShape(true)\n        .when(1000, {\n            endAngle: PI$1 * 3 / 2\n        })\n        .start('circularInOut');\n    arc.animateShape(true)\n        .when(1000, {\n            startAngle: PI$1 * 3 / 2\n        })\n        .delay(300)\n        .start('circularInOut');\n\n    var group = new Group();\n    group.add(arc);\n    group.add(labelRect);\n    group.add(mask);\n    // Inject resize\n    group.resize = function () {\n        var cx = api.getWidth() / 2;\n        var cy = api.getHeight() / 2;\n        arc.setShape({\n            cx: cx,\n            cy: cy\n        });\n        var r = arc.shape.r;\n        labelRect.setShape({\n            x: cx - r,\n            y: cy - r,\n            width: r * 2,\n            height: r * 2\n        });\n\n        mask.setShape({\n            x: 0,\n            y: 0,\n            width: api.getWidth(),\n            height: api.getHeight()\n        });\n    };\n    group.resize();\n    return group;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/stream/Scheduler\n */\n\n/**\n * @constructor\n */\nfunction Scheduler(ecInstance, api, dataProcessorHandlers, visualHandlers) {\n    this.ecInstance = ecInstance;\n    this.api = api;\n    this.unfinished;\n\n    // Fix current processors in case that in some rear cases that\n    // processors might be registered after echarts instance created.\n    // Register processors incrementally for a echarts instance is\n    // not supported by this stream architecture.\n    var dataProcessorHandlers = this._dataProcessorHandlers = dataProcessorHandlers.slice();\n    var visualHandlers = this._visualHandlers = visualHandlers.slice();\n    this._allHandlers = dataProcessorHandlers.concat(visualHandlers);\n\n    /**\n     * @private\n     * @type {\n     *     [handlerUID: string]: {\n     *         seriesTaskMap?: {\n     *             [seriesUID: string]: Task\n     *         },\n     *         overallTask?: Task\n     *     }\n     * }\n     */\n    this._stageTaskMap = createHashMap();\n}\n\nvar proto = Scheduler.prototype;\n\n/**\n * @param {module:echarts/model/Global} ecModel\n * @param {Object} payload\n */\nproto.restoreData = function (ecModel, payload) {\n    // TODO: Only restroe needed series and components, but not all components.\n    // Currently `restoreData` of all of the series and component will be called.\n    // But some independent components like `title`, `legend`, `graphic`, `toolbox`,\n    // `tooltip`, `axisPointer`, etc, do not need series refresh when `setOption`,\n    // and some components like coordinate system, axes, dataZoom, visualMap only\n    // need their target series refresh.\n    // (1) If we are implementing this feature some day, we should consider these cases:\n    // if a data processor depends on a component (e.g., dataZoomProcessor depends\n    // on the settings of `dataZoom`), it should be re-performed if the component\n    // is modified by `setOption`.\n    // (2) If a processor depends on sevral series, speicified by its `getTargetSeries`,\n    // it should be re-performed when the result array of `getTargetSeries` changed.\n    // We use `dependencies` to cover these issues.\n    // (3) How to update target series when coordinate system related components modified.\n\n    // TODO: simply the dirty mechanism? Check whether only the case here can set tasks dirty,\n    // and this case all of the tasks will be set as dirty.\n\n    ecModel.restoreData(payload);\n\n    // Theoretically an overall task not only depends on each of its target series, but also\n    // depends on all of the series.\n    // The overall task is not in pipeline, and `ecModel.restoreData` only set pipeline tasks\n    // dirty. If `getTargetSeries` of an overall task returns nothing, we should also ensure\n    // that the overall task is set as dirty and to be performed, otherwise it probably cause\n    // state chaos. So we have to set dirty of all of the overall tasks manually, otherwise it\n    // probably cause state chaos (consider `dataZoomProcessor`).\n    this._stageTaskMap.each(function (taskRecord) {\n        var overallTask = taskRecord.overallTask;\n        overallTask && overallTask.dirty();\n    });\n};\n\n// If seriesModel provided, incremental threshold is check by series data.\nproto.getPerformArgs = function (task, isBlock) {\n    // For overall task\n    if (!task.__pipeline) {\n        return;\n    }\n\n    var pipeline = this._pipelineMap.get(task.__pipeline.id);\n    var pCtx = pipeline.context;\n    var incremental = !isBlock\n        && pipeline.progressiveEnabled\n        && (!pCtx || pCtx.progressiveRender)\n        && task.__idxInPipeline > pipeline.blockIndex;\n\n    var step = incremental ? pipeline.step : null;\n    var modDataCount = pCtx && pCtx.modDataCount;\n    var modBy = modDataCount != null ? Math.ceil(modDataCount / step) : null;\n\n    return {step: step, modBy: modBy, modDataCount: modDataCount};\n};\n\nproto.getPipeline = function (pipelineId) {\n    return this._pipelineMap.get(pipelineId);\n};\n\n/**\n * Current, progressive rendering starts from visual and layout.\n * Always detect render mode in the same stage, avoiding that incorrect\n * detection caused by data filtering.\n * Caution:\n * `updateStreamModes` use `seriesModel.getData()`.\n */\nproto.updateStreamModes = function (seriesModel, view) {\n    var pipeline = this._pipelineMap.get(seriesModel.uid);\n    var data = seriesModel.getData();\n    var dataLen = data.count();\n\n    // `progressiveRender` means that can render progressively in each\n    // animation frame. Note that some types of series do not provide\n    // `view.incrementalPrepareRender` but support `chart.appendData`. We\n    // use the term `incremental` but not `progressive` to describe the\n    // case that `chart.appendData`.\n    var progressiveRender = pipeline.progressiveEnabled\n        && view.incrementalPrepareRender\n        && dataLen >= pipeline.threshold;\n\n    var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold');\n\n    // TODO: modDataCount should not updated if `appendData`, otherwise cause whole repaint.\n    // see `test/candlestick-large3.html`\n    var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null;\n\n    seriesModel.pipelineContext = pipeline.context = {\n        progressiveRender: progressiveRender,\n        modDataCount: modDataCount,\n        large: large\n    };\n};\n\nproto.restorePipelines = function (ecModel) {\n    var scheduler = this;\n    var pipelineMap = scheduler._pipelineMap = createHashMap();\n\n    ecModel.eachSeries(function (seriesModel) {\n        var progressive = seriesModel.getProgressive();\n        var pipelineId = seriesModel.uid;\n\n        pipelineMap.set(pipelineId, {\n            id: pipelineId,\n            head: null,\n            tail: null,\n            threshold: seriesModel.getProgressiveThreshold(),\n            progressiveEnabled: progressive\n                && !(seriesModel.preventIncremental && seriesModel.preventIncremental()),\n            blockIndex: -1,\n            step: Math.round(progressive || 700),\n            count: 0\n        });\n\n        pipe(scheduler, seriesModel, seriesModel.dataTask);\n    });\n};\n\nproto.prepareStageTasks = function () {\n    var stageTaskMap = this._stageTaskMap;\n    var ecModel = this.ecInstance.getModel();\n    var api = this.api;\n\n    each$1(this._allHandlers, function (handler) {\n        var record = stageTaskMap.get(handler.uid) || stageTaskMap.set(handler.uid, []);\n\n        handler.reset && createSeriesStageTask(this, handler, record, ecModel, api);\n        handler.overallReset && createOverallStageTask(this, handler, record, ecModel, api);\n    }, this);\n};\n\nproto.prepareView = function (view, model, ecModel, api) {\n    var renderTask = view.renderTask;\n    var context = renderTask.context;\n\n    context.model = model;\n    context.ecModel = ecModel;\n    context.api = api;\n\n    renderTask.__block = !view.incrementalPrepareRender;\n\n    pipe(this, model, renderTask);\n};\n\n\nproto.performDataProcessorTasks = function (ecModel, payload) {\n    // If we do not use `block` here, it should be considered when to update modes.\n    performStageTasks(this, this._dataProcessorHandlers, ecModel, payload, {block: true});\n};\n\n// opt\n// opt.visualType: 'visual' or 'layout'\n// opt.setDirty\nproto.performVisualTasks = function (ecModel, payload, opt) {\n    performStageTasks(this, this._visualHandlers, ecModel, payload, opt);\n};\n\nfunction performStageTasks(scheduler, stageHandlers, ecModel, payload, opt) {\n    opt = opt || {};\n    var unfinished;\n\n    each$1(stageHandlers, function (stageHandler, idx) {\n        if (opt.visualType && opt.visualType !== stageHandler.visualType) {\n            return;\n        }\n\n        var stageHandlerRecord = scheduler._stageTaskMap.get(stageHandler.uid);\n        var seriesTaskMap = stageHandlerRecord.seriesTaskMap;\n        var overallTask = stageHandlerRecord.overallTask;\n\n        if (overallTask) {\n            var overallNeedDirty;\n            var agentStubMap = overallTask.agentStubMap;\n            agentStubMap.each(function (stub) {\n                if (needSetDirty(opt, stub)) {\n                    stub.dirty();\n                    overallNeedDirty = true;\n                }\n            });\n            overallNeedDirty && overallTask.dirty();\n            updatePayload(overallTask, payload);\n            var performArgs = scheduler.getPerformArgs(overallTask, opt.block);\n            // Execute stubs firstly, which may set the overall task dirty,\n            // then execute the overall task. And stub will call seriesModel.setData,\n            // which ensures that in the overallTask seriesModel.getData() will not\n            // return incorrect data.\n            agentStubMap.each(function (stub) {\n                stub.perform(performArgs);\n            });\n            unfinished |= overallTask.perform(performArgs);\n        }\n        else if (seriesTaskMap) {\n            seriesTaskMap.each(function (task, pipelineId) {\n                if (needSetDirty(opt, task)) {\n                    task.dirty();\n                }\n                var performArgs = scheduler.getPerformArgs(task, opt.block);\n                performArgs.skip = !stageHandler.performRawSeries\n                    && ecModel.isSeriesFiltered(task.context.model);\n                updatePayload(task, payload);\n                unfinished |= task.perform(performArgs);\n            });\n        }\n    });\n\n    function needSetDirty(opt, task) {\n        return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id));\n    }\n\n    scheduler.unfinished |= unfinished;\n}\n\nproto.performSeriesTasks = function (ecModel) {\n    var unfinished;\n\n    ecModel.eachSeries(function (seriesModel) {\n        // Progress to the end for dataInit and dataRestore.\n        unfinished |= seriesModel.dataTask.perform();\n    });\n\n    this.unfinished |= unfinished;\n};\n\nproto.plan = function () {\n    // Travel pipelines, check block.\n    this._pipelineMap.each(function (pipeline) {\n        var task = pipeline.tail;\n        do {\n            if (task.__block) {\n                pipeline.blockIndex = task.__idxInPipeline;\n                break;\n            }\n            task = task.getUpstream();\n        }\n        while (task);\n    });\n};\n\nvar updatePayload = proto.updatePayload = function (task, payload) {\n    payload !== 'remain' && (task.context.payload = payload);\n};\n\nfunction createSeriesStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) {\n    var seriesTaskMap = stageHandlerRecord.seriesTaskMap\n        || (stageHandlerRecord.seriesTaskMap = createHashMap());\n    var seriesType = stageHandler.seriesType;\n    var getTargetSeries = stageHandler.getTargetSeries;\n\n    // If a stageHandler should cover all series, `createOnAllSeries` should be declared mandatorily,\n    // to avoid some typo or abuse. Otherwise if an extension do not specify a `seriesType`,\n    // it works but it may cause other irrelevant charts blocked.\n    if (stageHandler.createOnAllSeries) {\n        ecModel.eachRawSeries(create);\n    }\n    else if (seriesType) {\n        ecModel.eachRawSeriesByType(seriesType, create);\n    }\n    else if (getTargetSeries) {\n        getTargetSeries(ecModel, api).each(create);\n    }\n\n    function create(seriesModel) {\n        var pipelineId = seriesModel.uid;\n\n        // Init tasks for each seriesModel only once.\n        // Reuse original task instance.\n        var task = seriesTaskMap.get(pipelineId)\n            || seriesTaskMap.set(pipelineId, createTask({\n                plan: seriesTaskPlan,\n                reset: seriesTaskReset,\n                count: seriesTaskCount\n            }));\n        task.context = {\n            model: seriesModel,\n            ecModel: ecModel,\n            api: api,\n            useClearVisual: stageHandler.isVisual && !stageHandler.isLayout,\n            plan: stageHandler.plan,\n            reset: stageHandler.reset,\n            scheduler: scheduler\n        };\n        pipe(scheduler, seriesModel, task);\n    }\n\n    // Clear unused series tasks.\n    var pipelineMap = scheduler._pipelineMap;\n    seriesTaskMap.each(function (task, pipelineId) {\n        if (!pipelineMap.get(pipelineId)) {\n            task.dispose();\n            seriesTaskMap.removeKey(pipelineId);\n        }\n    });\n}\n\nfunction createOverallStageTask(scheduler, stageHandler, stageHandlerRecord, ecModel, api) {\n    var overallTask = stageHandlerRecord.overallTask = stageHandlerRecord.overallTask\n        // For overall task, the function only be called on reset stage.\n        || createTask({reset: overallTaskReset});\n\n    overallTask.context = {\n        ecModel: ecModel,\n        api: api,\n        overallReset: stageHandler.overallReset,\n        scheduler: scheduler\n    };\n\n    // Reuse orignal stubs.\n    var agentStubMap = overallTask.agentStubMap = overallTask.agentStubMap || createHashMap();\n\n    var seriesType = stageHandler.seriesType;\n    var getTargetSeries = stageHandler.getTargetSeries;\n    var overallProgress = true;\n    var modifyOutputEnd = stageHandler.modifyOutputEnd;\n\n    // An overall task with seriesType detected or has `getTargetSeries`, we add\n    // stub in each pipelines, it will set the overall task dirty when the pipeline\n    // progress. Moreover, to avoid call the overall task each frame (too frequent),\n    // we set the pipeline block.\n    if (seriesType) {\n        ecModel.eachRawSeriesByType(seriesType, createStub);\n    }\n    else if (getTargetSeries) {\n        getTargetSeries(ecModel, api).each(createStub);\n    }\n    // Otherwise, (usually it is legancy case), the overall task will only be\n    // executed when upstream dirty. Otherwise the progressive rendering of all\n    // pipelines will be disabled unexpectedly. But it still needs stubs to receive\n    // dirty info from upsteam.\n    else {\n        overallProgress = false;\n        each$1(ecModel.getSeries(), createStub);\n    }\n\n    function createStub(seriesModel) {\n        var pipelineId = seriesModel.uid;\n        var stub = agentStubMap.get(pipelineId);\n        if (!stub) {\n            stub = agentStubMap.set(pipelineId, createTask(\n                {reset: stubReset, onDirty: stubOnDirty}\n            ));\n            // When the result of `getTargetSeries` changed, the overallTask\n            // should be set as dirty and re-performed.\n            overallTask.dirty();\n        }\n        stub.context = {\n            model: seriesModel,\n            overallProgress: overallProgress,\n            modifyOutputEnd: modifyOutputEnd\n        };\n        stub.agent = overallTask;\n        stub.__block = overallProgress;\n\n        pipe(scheduler, seriesModel, stub);\n    }\n\n    // Clear unused stubs.\n    var pipelineMap = scheduler._pipelineMap;\n    agentStubMap.each(function (stub, pipelineId) {\n        if (!pipelineMap.get(pipelineId)) {\n            stub.dispose();\n            // When the result of `getTargetSeries` changed, the overallTask\n            // should be set as dirty and re-performed.\n            overallTask.dirty();\n            agentStubMap.removeKey(pipelineId);\n        }\n    });\n}\n\nfunction overallTaskReset(context) {\n    context.overallReset(\n        context.ecModel, context.api, context.payload\n    );\n}\n\nfunction stubReset(context, upstreamContext) {\n    return context.overallProgress && stubProgress;\n}\n\nfunction stubProgress() {\n    this.agent.dirty();\n    this.getDownstream().dirty();\n}\n\nfunction stubOnDirty() {\n    this.agent && this.agent.dirty();\n}\n\nfunction seriesTaskPlan(context) {\n    return context.plan && context.plan(\n        context.model, context.ecModel, context.api, context.payload\n    );\n}\n\nfunction seriesTaskReset(context) {\n    if (context.useClearVisual) {\n        context.data.clearAllVisual();\n    }\n    var resetDefines = context.resetDefines = normalizeToArray(context.reset(\n        context.model, context.ecModel, context.api, context.payload\n    ));\n    return resetDefines.length > 1\n        ? map(resetDefines, function (v, idx) {\n            return makeSeriesTaskProgress(idx);\n        })\n        : singleSeriesTaskProgress;\n}\n\nvar singleSeriesTaskProgress = makeSeriesTaskProgress(0);\n\nfunction makeSeriesTaskProgress(resetDefineIdx) {\n    return function (params, context) {\n        var data = context.data;\n        var resetDefine = context.resetDefines[resetDefineIdx];\n\n        if (resetDefine && resetDefine.dataEach) {\n            for (var i = params.start; i < params.end; i++) {\n                resetDefine.dataEach(data, i);\n            }\n        }\n        else if (resetDefine && resetDefine.progress) {\n            resetDefine.progress(params, data);\n        }\n    };\n}\n\nfunction seriesTaskCount(context) {\n    return context.data.count();\n}\n\nfunction pipe(scheduler, seriesModel, task) {\n    var pipelineId = seriesModel.uid;\n    var pipeline = scheduler._pipelineMap.get(pipelineId);\n    !pipeline.head && (pipeline.head = task);\n    pipeline.tail && pipeline.tail.pipe(task);\n    pipeline.tail = task;\n    task.__idxInPipeline = pipeline.count++;\n    task.__pipeline = pipeline;\n}\n\nScheduler.wrapStageHandler = function (stageHandler, visualType) {\n    if (isFunction$1(stageHandler)) {\n        stageHandler = {\n            overallReset: stageHandler,\n            seriesType: detectSeriseType(stageHandler)\n        };\n    }\n\n    stageHandler.uid = getUID('stageHandler');\n    visualType && (stageHandler.visualType = visualType);\n\n    return stageHandler;\n};\n\n\n\n/**\n * Only some legacy stage handlers (usually in echarts extensions) are pure function.\n * To ensure that they can work normally, they should work in block mode, that is,\n * they should not be started util the previous tasks finished. So they cause the\n * progressive rendering disabled. We try to detect the series type, to narrow down\n * the block range to only the series type they concern, but not all series.\n */\nfunction detectSeriseType(legacyFunc) {\n    seriesType = null;\n    try {\n        // Assume there is no async when calling `eachSeriesByType`.\n        legacyFunc(ecModelMock, apiMock);\n    }\n    catch (e) {\n    }\n    return seriesType;\n}\n\nvar ecModelMock = {};\nvar apiMock = {};\nvar seriesType;\n\nmockMethods(ecModelMock, GlobalModel);\nmockMethods(apiMock, ExtensionAPI);\necModelMock.eachSeriesByType = ecModelMock.eachRawSeriesByType = function (type) {\n    seriesType = type;\n};\necModelMock.eachComponent = function (cond) {\n    if (cond.mainType === 'series' && cond.subType) {\n        seriesType = cond.subType;\n    }\n};\n\nfunction mockMethods(target, Clz) {\n    /* eslint-disable */\n    for (var name in Clz.prototype) {\n        // Do not use hasOwnProperty\n        target[name] = noop;\n    }\n    /* eslint-enable */\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar colorAll = [\n    '#37A2DA', '#32C5E9', '#67E0E3', '#9FE6B8', '#FFDB5C', '#ff9f7f',\n    '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF'\n];\n\nvar lightTheme = {\n\n    color: colorAll,\n\n    colorLayer: [\n        ['#37A2DA', '#ffd85c', '#fd7b5f'],\n        ['#37A2DA', '#67E0E3', '#FFDB5C', '#ff9f7f', '#E062AE', '#9d96f5'],\n        ['#37A2DA', '#32C5E9', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#e7bcf3', '#8378EA', '#96BFFF'],\n        colorAll\n    ]\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar contrastColor = '#eee';\nvar axisCommon = function () {\n    return {\n        axisLine: {\n            lineStyle: {\n                color: contrastColor\n            }\n        },\n        axisTick: {\n            lineStyle: {\n                color: contrastColor\n            }\n        },\n        axisLabel: {\n            textStyle: {\n                color: contrastColor\n            }\n        },\n        splitLine: {\n            lineStyle: {\n                type: 'dashed',\n                color: '#aaa'\n            }\n        },\n        splitArea: {\n            areaStyle: {\n                color: contrastColor\n            }\n        }\n    };\n};\n\nvar colorPalette = [\n    '#dd6b66', '#759aa0', '#e69d87', '#8dc1a9', '#ea7e53',\n    '#eedd78', '#73a373', '#73b9bc', '#7289ab', '#91ca8c', '#f49f42'\n];\nvar theme = {\n    color: colorPalette,\n    backgroundColor: '#333',\n    tooltip: {\n        axisPointer: {\n            lineStyle: {\n                color: contrastColor\n            },\n            crossStyle: {\n                color: contrastColor\n            }\n        }\n    },\n    legend: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    textStyle: {\n        color: contrastColor\n    },\n    title: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    toolbox: {\n        iconStyle: {\n            normal: {\n                borderColor: contrastColor\n            }\n        }\n    },\n    dataZoom: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    visualMap: {\n        textStyle: {\n            color: contrastColor\n        }\n    },\n    timeline: {\n        lineStyle: {\n            color: contrastColor\n        },\n        itemStyle: {\n            normal: {\n                color: colorPalette[1]\n            }\n        },\n        label: {\n            normal: {\n                textStyle: {\n                    color: contrastColor\n                }\n            }\n        },\n        controlStyle: {\n            normal: {\n                color: contrastColor,\n                borderColor: contrastColor\n            }\n        }\n    },\n    timeAxis: axisCommon(),\n    logAxis: axisCommon(),\n    valueAxis: axisCommon(),\n    categoryAxis: axisCommon(),\n\n    line: {\n        symbol: 'circle'\n    },\n    graph: {\n        color: colorPalette\n    },\n    gauge: {\n        title: {\n            textStyle: {\n                color: contrastColor\n            }\n        }\n    },\n    candlestick: {\n        itemStyle: {\n            normal: {\n                color: '#FD1050',\n                color0: '#0CF49B',\n                borderColor: '#FD1050',\n                borderColor0: '#0CF49B'\n            }\n        }\n    }\n};\ntheme.categoryAxis.splitLine.show = false;\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * This module is imported by echarts directly.\n *\n * Notice:\n * Always keep this file exists for backward compatibility.\n * Because before 4.1.0, dataset is an optional component,\n * some users may import this module manually.\n */\n\nComponentModel.extend({\n\n    type: 'dataset',\n\n    /**\n     * @protected\n     */\n    defaultOption: {\n\n        // 'row', 'column'\n        seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN,\n\n        // null/'auto': auto detect header, see \"module:echarts/data/helper/sourceHelper\"\n        sourceHeader: null,\n\n        dimensions: null,\n\n        source: null\n    },\n\n    optionUpdated: function () {\n        detectSourceFormat(this);\n    }\n\n});\n\nComponent.extend({\n\n    type: 'dataset'\n\n});\n\n/**\n * 椭圆形状\n * @module zrender/graphic/shape/Ellipse\n */\n\nvar Ellipse = Path.extend({\n\n    type: 'ellipse',\n\n    shape: {\n        cx: 0, cy: 0,\n        rx: 0, ry: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var k = 0.5522848;\n        var x = shape.cx;\n        var y = shape.cy;\n        var a = shape.rx;\n        var b = shape.ry;\n        var ox = a * k; // 水平控制点偏移量\n        var oy = b * k; // 垂直控制点偏移量\n        // 从椭圆的左端点开始顺时针绘制四条三次贝塞尔曲线\n        ctx.moveTo(x - a, y);\n        ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b);\n        ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y);\n        ctx.bezierCurveTo(x + a, y + oy, x + ox, y + b, x, y + b);\n        ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y);\n        ctx.closePath();\n    }\n});\n\n// import RadialGradient from '../graphic/RadialGradient';\n// import Pattern from '../graphic/Pattern';\n// import * as vector from '../core/vector';\n// Most of the values can be separated by comma and/or white space.\nvar DILIMITER_REG = /[\\s,]+/;\n\n/**\n * For big svg string, this method might be time consuming.\n *\n * @param {string} svg xml string\n * @return {Object} xml root.\n */\nfunction parseXML(svg) {\n    if (isString(svg)) {\n        var parser = new DOMParser();\n        svg = parser.parseFromString(svg, 'text/xml');\n    }\n\n    // Document node. If using $.get, doc node may be input.\n    if (svg.nodeType === 9) {\n        svg = svg.firstChild;\n    }\n    // nodeName of <!DOCTYPE svg> is also 'svg'.\n    while (svg.nodeName.toLowerCase() !== 'svg' || svg.nodeType !== 1) {\n        svg = svg.nextSibling;\n    }\n\n    return svg;\n}\n\nfunction SVGParser() {\n    this._defs = {};\n    this._root = null;\n\n    this._isDefine = false;\n    this._isText = false;\n}\n\nSVGParser.prototype.parse = function (xml, opt) {\n    opt = opt || {};\n\n    var svg = parseXML(xml);\n\n    if (!svg) {\n        throw new Error('Illegal svg');\n    }\n\n    var root = new Group();\n    this._root = root;\n    // parse view port\n    var viewBox = svg.getAttribute('viewBox') || '';\n\n    // If width/height not specified, means \"100%\" of `opt.width/height`.\n    // TODO: Other percent value not supported yet.\n    var width = parseFloat(svg.getAttribute('width') || opt.width);\n    var height = parseFloat(svg.getAttribute('height') || opt.height);\n    // If width/height not specified, set as null for output.\n    isNaN(width) && (width = null);\n    isNaN(height) && (height = null);\n\n    // Apply inline style on svg element.\n    parseAttributes(svg, root, null, true);\n\n    var child = svg.firstChild;\n    while (child) {\n        this._parseNode(child, root);\n        child = child.nextSibling;\n    }\n\n    var viewBoxRect;\n    var viewBoxTransform;\n\n    if (viewBox) {\n        var viewBoxArr = trim(viewBox).split(DILIMITER_REG);\n        // Some invalid case like viewBox: 'none'.\n        if (viewBoxArr.length >= 4) {\n            viewBoxRect = {\n                x: parseFloat(viewBoxArr[0] || 0),\n                y: parseFloat(viewBoxArr[1] || 0),\n                width: parseFloat(viewBoxArr[2]),\n                height: parseFloat(viewBoxArr[3])\n            };\n        }\n    }\n\n    if (viewBoxRect && width != null && height != null) {\n        viewBoxTransform = makeViewBoxTransform(viewBoxRect, width, height);\n\n        if (!opt.ignoreViewBox) {\n            // If set transform on the output group, it probably bring trouble when\n            // some users only intend to show the clipped content inside the viewBox,\n            // but not intend to transform the output group. So we keep the output\n            // group no transform. If the user intend to use the viewBox as a\n            // camera, just set `opt.ignoreViewBox` as `true` and set transfrom\n            // manually according to the viewBox info in the output of this method.\n            var elRoot = root;\n            root = new Group();\n            root.add(elRoot);\n            elRoot.scale = viewBoxTransform.scale.slice();\n            elRoot.position = viewBoxTransform.position.slice();\n        }\n    }\n\n    // Some shapes might be overflow the viewport, which should be\n    // clipped despite whether the viewBox is used, as the SVG does.\n    if (!opt.ignoreRootClip && width != null && height != null) {\n        root.setClipPath(new Rect({\n            shape: {x: 0, y: 0, width: width, height: height}\n        }));\n    }\n\n    // Set width/height on group just for output the viewport size.\n    return {\n        root: root,\n        width: width,\n        height: height,\n        viewBoxRect: viewBoxRect,\n        viewBoxTransform: viewBoxTransform\n    };\n};\n\nSVGParser.prototype._parseNode = function (xmlNode, parentGroup) {\n\n    var nodeName = xmlNode.nodeName.toLowerCase();\n\n    // TODO\n    // support <style>...</style> in svg, where nodeName is 'style',\n    // CSS classes is defined globally wherever the style tags are declared.\n\n    if (nodeName === 'defs') {\n        // define flag\n        this._isDefine = true;\n    }\n    else if (nodeName === 'text') {\n        this._isText = true;\n    }\n\n    var el;\n    if (this._isDefine) {\n        var parser = defineParsers[nodeName];\n        if (parser) {\n            var def = parser.call(this, xmlNode);\n            var id = xmlNode.getAttribute('id');\n            if (id) {\n                this._defs[id] = def;\n            }\n        }\n    }\n    else {\n        var parser = nodeParsers[nodeName];\n        if (parser) {\n            el = parser.call(this, xmlNode, parentGroup);\n            parentGroup.add(el);\n        }\n    }\n\n    var child = xmlNode.firstChild;\n    while (child) {\n        if (child.nodeType === 1) {\n            this._parseNode(child, el);\n        }\n        // Is text\n        if (child.nodeType === 3 && this._isText) {\n            this._parseText(child, el);\n        }\n        child = child.nextSibling;\n    }\n\n    // Quit define\n    if (nodeName === 'defs') {\n        this._isDefine = false;\n    }\n    else if (nodeName === 'text') {\n        this._isText = false;\n    }\n};\n\nSVGParser.prototype._parseText = function (xmlNode, parentGroup) {\n    if (xmlNode.nodeType === 1) {\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n        this._textX += parseFloat(dx);\n        this._textY += parseFloat(dy);\n    }\n\n    var text = new Text({\n        style: {\n            text: xmlNode.textContent,\n            transformText: true\n        },\n        position: [this._textX || 0, this._textY || 0]\n    });\n\n    inheritStyle(parentGroup, text);\n    parseAttributes(xmlNode, text, this._defs);\n\n    var fontSize = text.style.fontSize;\n    if (fontSize && fontSize < 9) {\n        // PENDING\n        text.style.fontSize = 9;\n        text.scale = text.scale || [1, 1];\n        text.scale[0] *= fontSize / 9;\n        text.scale[1] *= fontSize / 9;\n    }\n\n    var rect = text.getBoundingRect();\n    this._textX += rect.width;\n\n    parentGroup.add(text);\n\n    return text;\n};\n\nvar nodeParsers = {\n    'g': function (xmlNode, parentGroup) {\n        var g = new Group();\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n        return g;\n    },\n    'rect': function (xmlNode, parentGroup) {\n        var rect = new Rect();\n        inheritStyle(parentGroup, rect);\n        parseAttributes(xmlNode, rect, this._defs);\n\n        rect.setShape({\n            x: parseFloat(xmlNode.getAttribute('x') || 0),\n            y: parseFloat(xmlNode.getAttribute('y') || 0),\n            width: parseFloat(xmlNode.getAttribute('width') || 0),\n            height: parseFloat(xmlNode.getAttribute('height') || 0)\n        });\n\n        // console.log(xmlNode.getAttribute('transform'));\n        // console.log(rect.transform);\n\n        return rect;\n    },\n    'circle': function (xmlNode, parentGroup) {\n        var circle = new Circle();\n        inheritStyle(parentGroup, circle);\n        parseAttributes(xmlNode, circle, this._defs);\n\n        circle.setShape({\n            cx: parseFloat(xmlNode.getAttribute('cx') || 0),\n            cy: parseFloat(xmlNode.getAttribute('cy') || 0),\n            r: parseFloat(xmlNode.getAttribute('r') || 0)\n        });\n\n        return circle;\n    },\n    'line': function (xmlNode, parentGroup) {\n        var line = new Line();\n        inheritStyle(parentGroup, line);\n        parseAttributes(xmlNode, line, this._defs);\n\n        line.setShape({\n            x1: parseFloat(xmlNode.getAttribute('x1') || 0),\n            y1: parseFloat(xmlNode.getAttribute('y1') || 0),\n            x2: parseFloat(xmlNode.getAttribute('x2') || 0),\n            y2: parseFloat(xmlNode.getAttribute('y2') || 0)\n        });\n\n        return line;\n    },\n    'ellipse': function (xmlNode, parentGroup) {\n        var ellipse = new Ellipse();\n        inheritStyle(parentGroup, ellipse);\n        parseAttributes(xmlNode, ellipse, this._defs);\n\n        ellipse.setShape({\n            cx: parseFloat(xmlNode.getAttribute('cx') || 0),\n            cy: parseFloat(xmlNode.getAttribute('cy') || 0),\n            rx: parseFloat(xmlNode.getAttribute('rx') || 0),\n            ry: parseFloat(xmlNode.getAttribute('ry') || 0)\n        });\n        return ellipse;\n    },\n    'polygon': function (xmlNode, parentGroup) {\n        var points = xmlNode.getAttribute('points');\n        if (points) {\n            points = parsePoints(points);\n        }\n        var polygon = new Polygon({\n            shape: {\n                points: points || []\n            }\n        });\n\n        inheritStyle(parentGroup, polygon);\n        parseAttributes(xmlNode, polygon, this._defs);\n\n        return polygon;\n    },\n    'polyline': function (xmlNode, parentGroup) {\n        var path = new Path();\n        inheritStyle(parentGroup, path);\n        parseAttributes(xmlNode, path, this._defs);\n\n        var points = xmlNode.getAttribute('points');\n        if (points) {\n            points = parsePoints(points);\n        }\n        var polyline = new Polyline({\n            shape: {\n                points: points || []\n            }\n        });\n\n        return polyline;\n    },\n    'image': function (xmlNode, parentGroup) {\n        var img = new ZImage();\n        inheritStyle(parentGroup, img);\n        parseAttributes(xmlNode, img, this._defs);\n\n        img.setStyle({\n            image: xmlNode.getAttribute('xlink:href'),\n            x: xmlNode.getAttribute('x'),\n            y: xmlNode.getAttribute('y'),\n            width: xmlNode.getAttribute('width'),\n            height: xmlNode.getAttribute('height')\n        });\n\n        return img;\n    },\n    'text': function (xmlNode, parentGroup) {\n        var x = xmlNode.getAttribute('x') || 0;\n        var y = xmlNode.getAttribute('y') || 0;\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n\n        this._textX = parseFloat(x) + parseFloat(dx);\n        this._textY = parseFloat(y) + parseFloat(dy);\n\n        var g = new Group();\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n        return g;\n    },\n    'tspan': function (xmlNode, parentGroup) {\n        var x = xmlNode.getAttribute('x');\n        var y = xmlNode.getAttribute('y');\n        if (x != null) {\n            // new offset x\n            this._textX = parseFloat(x);\n        }\n        if (y != null) {\n            // new offset y\n            this._textY = parseFloat(y);\n        }\n        var dx = xmlNode.getAttribute('dx') || 0;\n        var dy = xmlNode.getAttribute('dy') || 0;\n\n        var g = new Group();\n\n        inheritStyle(parentGroup, g);\n        parseAttributes(xmlNode, g, this._defs);\n\n\n        this._textX += dx;\n        this._textY += dy;\n\n        return g;\n    },\n    'path': function (xmlNode, parentGroup) {\n        // TODO svg fill rule\n        // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule\n        // path.style.globalCompositeOperation = 'xor';\n        var d = xmlNode.getAttribute('d') || '';\n\n        // Performance sensitive.\n\n        var path = createFromString(d);\n\n        inheritStyle(parentGroup, path);\n        parseAttributes(xmlNode, path, this._defs);\n\n        return path;\n    }\n};\n\nvar defineParsers = {\n\n    'lineargradient': function (xmlNode) {\n        var x1 = parseInt(xmlNode.getAttribute('x1') || 0, 10);\n        var y1 = parseInt(xmlNode.getAttribute('y1') || 0, 10);\n        var x2 = parseInt(xmlNode.getAttribute('x2') || 10, 10);\n        var y2 = parseInt(xmlNode.getAttribute('y2') || 0, 10);\n\n        var gradient = new LinearGradient(x1, y1, x2, y2);\n\n        _parseGradientColorStops(xmlNode, gradient);\n\n        return gradient;\n    },\n\n    'radialgradient': function (xmlNode) {\n\n    }\n};\n\nfunction _parseGradientColorStops(xmlNode, gradient) {\n\n    var stop = xmlNode.firstChild;\n\n    while (stop) {\n        if (stop.nodeType === 1) {\n            var offset = stop.getAttribute('offset');\n            if (offset.indexOf('%') > 0) {  // percentage\n                offset = parseInt(offset, 10) / 100;\n            }\n            else if (offset) {    // number from 0 to 1\n                offset = parseFloat(offset);\n            }\n            else {\n                offset = 0;\n            }\n\n            var stopColor = stop.getAttribute('stop-color') || '#000000';\n\n            gradient.addColorStop(offset, stopColor);\n        }\n        stop = stop.nextSibling;\n    }\n}\n\nfunction inheritStyle(parent, child) {\n    if (parent && parent.__inheritedStyle) {\n        if (!child.__inheritedStyle) {\n            child.__inheritedStyle = {};\n        }\n        defaults(child.__inheritedStyle, parent.__inheritedStyle);\n    }\n}\n\nfunction parsePoints(pointsString) {\n    var list = trim(pointsString).split(DILIMITER_REG);\n    var points = [];\n\n    for (var i = 0; i < list.length; i += 2) {\n        var x = parseFloat(list[i]);\n        var y = parseFloat(list[i + 1]);\n        points.push([x, y]);\n    }\n    return points;\n}\n\nvar attributesMap = {\n    'fill': 'fill',\n    'stroke': 'stroke',\n    'stroke-width': 'lineWidth',\n    'opacity': 'opacity',\n    'fill-opacity': 'fillOpacity',\n    'stroke-opacity': 'strokeOpacity',\n    'stroke-dasharray': 'lineDash',\n    'stroke-dashoffset': 'lineDashOffset',\n    'stroke-linecap': 'lineCap',\n    'stroke-linejoin': 'lineJoin',\n    'stroke-miterlimit': 'miterLimit',\n    'font-family': 'fontFamily',\n    'font-size': 'fontSize',\n    'font-style': 'fontStyle',\n    'font-weight': 'fontWeight',\n\n    'text-align': 'textAlign',\n    'alignment-baseline': 'textBaseline'\n};\n\nfunction parseAttributes(xmlNode, el, defs, onlyInlineStyle) {\n    var zrStyle = el.__inheritedStyle || {};\n    var isTextEl = el.type === 'text';\n\n    // TODO Shadow\n    if (xmlNode.nodeType === 1) {\n        parseTransformAttribute(xmlNode, el);\n\n        extend(zrStyle, parseStyleAttribute(xmlNode));\n\n        if (!onlyInlineStyle) {\n            for (var svgAttrName in attributesMap) {\n                if (attributesMap.hasOwnProperty(svgAttrName)) {\n                    var attrValue = xmlNode.getAttribute(svgAttrName);\n                    if (attrValue != null) {\n                        zrStyle[attributesMap[svgAttrName]] = attrValue;\n                    }\n                }\n            }\n        }\n    }\n\n    var elFillProp = isTextEl ? 'textFill' : 'fill';\n    var elStrokeProp = isTextEl ? 'textStroke' : 'stroke';\n\n    el.style = el.style || new Style();\n    var elStyle = el.style;\n\n    zrStyle.fill != null && elStyle.set(elFillProp, getPaint(zrStyle.fill, defs));\n    zrStyle.stroke != null && elStyle.set(elStrokeProp, getPaint(zrStyle.stroke, defs));\n\n    each$1([\n        'lineWidth', 'opacity', 'fillOpacity', 'strokeOpacity', 'miterLimit', 'fontSize'\n    ], function (propName) {\n        var elPropName = (propName === 'lineWidth' && isTextEl) ? 'textStrokeWidth' : propName;\n        zrStyle[propName] != null && elStyle.set(elPropName, parseFloat(zrStyle[propName]));\n    });\n\n    if (!zrStyle.textBaseline || zrStyle.textBaseline === 'auto') {\n        zrStyle.textBaseline = 'alphabetic';\n    }\n    if (zrStyle.textBaseline === 'alphabetic') {\n        zrStyle.textBaseline = 'bottom';\n    }\n    if (zrStyle.textAlign === 'start') {\n        zrStyle.textAlign = 'left';\n    }\n    if (zrStyle.textAlign === 'end') {\n        zrStyle.textAlign = 'right';\n    }\n\n    each$1(['lineDashOffset', 'lineCap', 'lineJoin',\n        'fontWeight', 'fontFamily', 'fontStyle', 'textAlign', 'textBaseline'\n    ], function (propName) {\n        zrStyle[propName] != null && elStyle.set(propName, zrStyle[propName]);\n    });\n\n    if (zrStyle.lineDash) {\n        el.style.lineDash = trim(zrStyle.lineDash).split(DILIMITER_REG);\n    }\n\n    if (elStyle[elStrokeProp] && elStyle[elStrokeProp] !== 'none') {\n        // enable stroke\n        el[elStrokeProp] = true;\n    }\n\n    el.__inheritedStyle = zrStyle;\n}\n\n\nvar urlRegex = /url\\(\\s*#(.*?)\\)/;\nfunction getPaint(str, defs) {\n    // if (str === 'none') {\n    //     return;\n    // }\n    var urlMatch = defs && str && str.match(urlRegex);\n    if (urlMatch) {\n        var url = trim(urlMatch[1]);\n        var def = defs[url];\n        return def;\n    }\n    return str;\n}\n\nvar transformRegex = /(translate|scale|rotate|skewX|skewY|matrix)\\(([\\-\\s0-9\\.e,]*)\\)/g;\n\nfunction parseTransformAttribute(xmlNode, node) {\n    var transform = xmlNode.getAttribute('transform');\n    if (transform) {\n        transform = transform.replace(/,/g, ' ');\n        var m = null;\n        var transformOps = [];\n        transform.replace(transformRegex, function (str, type, value) {\n            transformOps.push(type, value);\n        });\n        for (var i = transformOps.length - 1; i > 0; i -= 2) {\n            var value = transformOps[i];\n            var type = transformOps[i - 1];\n            m = m || create$1();\n            switch (type) {\n                case 'translate':\n                    value = trim(value).split(DILIMITER_REG);\n                    translate(m, m, [parseFloat(value[0]), parseFloat(value[1] || 0)]);\n                    break;\n                case 'scale':\n                    value = trim(value).split(DILIMITER_REG);\n                    scale$1(m, m, [parseFloat(value[0]), parseFloat(value[1] || value[0])]);\n                    break;\n                case 'rotate':\n                    value = trim(value).split(DILIMITER_REG);\n                    rotate(m, m, parseFloat(value[0]));\n                    break;\n                case 'skew':\n                    value = trim(value).split(DILIMITER_REG);\n                    console.warn('Skew transform is not supported yet');\n                    break;\n                case 'matrix':\n                    var value = trim(value).split(DILIMITER_REG);\n                    m[0] = parseFloat(value[0]);\n                    m[1] = parseFloat(value[1]);\n                    m[2] = parseFloat(value[2]);\n                    m[3] = parseFloat(value[3]);\n                    m[4] = parseFloat(value[4]);\n                    m[5] = parseFloat(value[5]);\n                    break;\n            }\n        }\n        node.setLocalTransform(m);\n    }\n}\n\n// Value may contain space.\nvar styleRegex = /([^\\s:;]+)\\s*:\\s*([^:;]+)/g;\nfunction parseStyleAttribute(xmlNode) {\n    var style = xmlNode.getAttribute('style');\n    var result = {};\n\n    if (!style) {\n        return result;\n    }\n\n    var styleList = {};\n    styleRegex.lastIndex = 0;\n    var styleRegResult;\n    while ((styleRegResult = styleRegex.exec(style)) != null) {\n        styleList[styleRegResult[1]] = styleRegResult[2];\n    }\n\n    for (var svgAttrName in attributesMap) {\n        if (attributesMap.hasOwnProperty(svgAttrName) && styleList[svgAttrName] != null) {\n            result[attributesMap[svgAttrName]] = styleList[svgAttrName];\n        }\n    }\n\n    return result;\n}\n\n/**\n * @param {Array.<number>} viewBoxRect\n * @param {number} width\n * @param {number} height\n * @return {Object} {scale, position}\n */\nfunction makeViewBoxTransform(viewBoxRect, width, height) {\n    var scaleX = width / viewBoxRect.width;\n    var scaleY = height / viewBoxRect.height;\n    var scale = Math.min(scaleX, scaleY);\n    // preserveAspectRatio 'xMidYMid'\n    var viewBoxScale = [scale, scale];\n    var viewBoxPosition = [\n        -(viewBoxRect.x + viewBoxRect.width / 2) * scale + width / 2,\n        -(viewBoxRect.y + viewBoxRect.height / 2) * scale + height / 2\n    ];\n\n    return {\n        scale: viewBoxScale,\n        position: viewBoxPosition\n    };\n}\n\n/**\n * @param {string|XMLElement} xml\n * @param {Object} [opt]\n * @param {number} [opt.width] Default width if svg width not specified or is a percent value.\n * @param {number} [opt.height] Default height if svg height not specified or is a percent value.\n * @param {boolean} [opt.ignoreViewBox]\n * @param {boolean} [opt.ignoreRootClip]\n * @return {Object} result:\n * {\n *     root: Group, The root of the the result tree of zrender shapes,\n *     width: number, the viewport width of the SVG,\n *     height: number, the viewport height of the SVG,\n *     viewBoxRect: {x, y, width, height}, the declared viewBox rect of the SVG, if exists,\n *     viewBoxTransform: the {scale, position} calculated by viewBox and viewport, is exists.\n * }\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar storage = createHashMap();\n\n// For minimize the code size of common echarts package,\n// do not put too much logic in this module.\n\nvar mapDataStorage = {\n\n    // The format of record: see `echarts.registerMap`.\n    // Compatible with previous `echarts.registerMap`.\n    registerMap: function (mapName, rawGeoJson, rawSpecialAreas) {\n\n        var records;\n\n        if (isArray(rawGeoJson)) {\n            records = rawGeoJson;\n        }\n        else if (rawGeoJson.svg) {\n            records = [{\n                type: 'svg',\n                source: rawGeoJson.svg,\n                specialAreas: rawGeoJson.specialAreas\n            }];\n        }\n        else {\n            // Backward compatibility.\n            if (rawGeoJson.geoJson && !rawGeoJson.features) {\n                rawSpecialAreas = rawGeoJson.specialAreas;\n                rawGeoJson = rawGeoJson.geoJson;\n            }\n            records = [{\n                type: 'geoJSON',\n                source: rawGeoJson,\n                specialAreas: rawSpecialAreas\n            }];\n        }\n\n        each$1(records, function (record) {\n            var type = record.type;\n            type === 'geoJson' && (type = record.type = 'geoJSON');\n\n            var parse = parsers[type];\n\n            if (__DEV__) {\n                assert$1(parse, 'Illegal map type: ' + type);\n            }\n\n            parse(record);\n        });\n\n        return storage.set(mapName, records);\n    },\n\n    retrieveMap: function (mapName) {\n        return storage.get(mapName);\n    }\n\n};\n\nvar parsers = {\n\n    geoJSON: function (record) {\n        var source = record.source;\n        record.geoJSON = !isString(source)\n            ? source\n            : (typeof JSON !== 'undefined' && JSON.parse)\n            ? JSON.parse(source)\n            : (new Function('return (' + source + ');'))();\n    },\n\n    // Only perform parse to XML object here, which might be time\n    // consiming for large SVG.\n    // Although convert XML to zrender element is also time consiming,\n    // if we do it here, the clone of zrender elements has to be\n    // required. So we do it once for each geo instance, util real\n    // performance issues call for optimizing it.\n    svg: function (record) {\n        record.svgXML = parseXML(record.source);\n    }\n\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\nvar assert = assert$1;\nvar each = each$1;\nvar isFunction = isFunction$1;\nvar isObject = isObject$1;\nvar parseClassType = ComponentModel.parseClassType;\n\nvar version = '4.2.1';\n\nvar dependencies = {\n    zrender: '4.0.6'\n};\n\nvar TEST_FRAME_REMAIN_TIME = 1;\n\nvar PRIORITY_PROCESSOR_FILTER = 1000;\nvar PRIORITY_PROCESSOR_STATISTIC = 5000;\n\nvar PRIORITY_VISUAL_LAYOUT = 1000;\nvar PRIORITY_VISUAL_GLOBAL = 2000;\nvar PRIORITY_VISUAL_CHART = 3000;\nvar PRIORITY_VISUAL_COMPONENT = 4000;\n// FIXME\n// necessary?\nvar PRIORITY_VISUAL_BRUSH = 5000;\n\nvar PRIORITY = {\n    PROCESSOR: {\n        FILTER: PRIORITY_PROCESSOR_FILTER,\n        STATISTIC: PRIORITY_PROCESSOR_STATISTIC\n    },\n    VISUAL: {\n        LAYOUT: PRIORITY_VISUAL_LAYOUT,\n        GLOBAL: PRIORITY_VISUAL_GLOBAL,\n        CHART: PRIORITY_VISUAL_CHART,\n        COMPONENT: PRIORITY_VISUAL_COMPONENT,\n        BRUSH: PRIORITY_VISUAL_BRUSH\n    }\n};\n\n// Main process have three entries: `setOption`, `dispatchAction` and `resize`,\n// where they must not be invoked nestedly, except the only case: invoke\n// dispatchAction with updateMethod \"none\" in main process.\n// This flag is used to carry out this rule.\n// All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]).\nvar IN_MAIN_PROCESS = '__flagInMainProcess';\nvar OPTION_UPDATED = '__optionUpdated';\nvar ACTION_REG = /^[a-zA-Z0-9_]+$/;\n\n\nfunction createRegisterEventWithLowercaseName(method) {\n    return function (eventName, handler, context) {\n        // Event name is all lowercase\n        eventName = eventName && eventName.toLowerCase();\n        Eventful.prototype[method].call(this, eventName, handler, context);\n    };\n}\n\n/**\n * @module echarts~MessageCenter\n */\nfunction MessageCenter() {\n    Eventful.call(this);\n}\nMessageCenter.prototype.on = createRegisterEventWithLowercaseName('on');\nMessageCenter.prototype.off = createRegisterEventWithLowercaseName('off');\nMessageCenter.prototype.one = createRegisterEventWithLowercaseName('one');\nmixin(MessageCenter, Eventful);\n\n/**\n * @module echarts~ECharts\n */\nfunction ECharts(dom, theme$$1, opts) {\n    opts = opts || {};\n\n    // Get theme by name\n    if (typeof theme$$1 === 'string') {\n        theme$$1 = themeStorage[theme$$1];\n    }\n\n    /**\n     * @type {string}\n     */\n    this.id;\n\n    /**\n     * Group id\n     * @type {string}\n     */\n    this.group;\n\n    /**\n     * @type {HTMLElement}\n     * @private\n     */\n    this._dom = dom;\n\n    var defaultRenderer = 'canvas';\n    if (__DEV__) {\n        defaultRenderer = (\n            typeof window === 'undefined' ? global : window\n        ).__ECHARTS__DEFAULT__RENDERER__ || defaultRenderer;\n    }\n\n    /**\n     * @type {module:zrender/ZRender}\n     * @private\n     */\n    var zr = this._zr = init$1(dom, {\n        renderer: opts.renderer || defaultRenderer,\n        devicePixelRatio: opts.devicePixelRatio,\n        width: opts.width,\n        height: opts.height\n    });\n\n    /**\n     * Expect 60 pfs.\n     * @type {Function}\n     * @private\n     */\n    this._throttledZrFlush = throttle(bind(zr.flush, zr), 17);\n\n    var theme$$1 = clone(theme$$1);\n    theme$$1 && backwardCompat(theme$$1, true);\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._theme = theme$$1;\n\n    /**\n     * @type {Array.<module:echarts/view/Chart>}\n     * @private\n     */\n    this._chartsViews = [];\n\n    /**\n     * @type {Object.<string, module:echarts/view/Chart>}\n     * @private\n     */\n    this._chartsMap = {};\n\n    /**\n     * @type {Array.<module:echarts/view/Component>}\n     * @private\n     */\n    this._componentsViews = [];\n\n    /**\n     * @type {Object.<string, module:echarts/view/Component>}\n     * @private\n     */\n    this._componentsMap = {};\n\n    /**\n     * @type {module:echarts/CoordinateSystem}\n     * @private\n     */\n    this._coordSysMgr = new CoordinateSystemManager();\n\n    /**\n     * @type {module:echarts/ExtensionAPI}\n     * @private\n     */\n    var api = this._api = createExtensionAPI(this);\n\n    // Sort on demand\n    function prioritySortFunc(a, b) {\n        return a.__prio - b.__prio;\n    }\n    sort(visualFuncs, prioritySortFunc);\n    sort(dataProcessorFuncs, prioritySortFunc);\n\n    /**\n     * @type {module:echarts/stream/Scheduler}\n     */\n    this._scheduler = new Scheduler(this, api, dataProcessorFuncs, visualFuncs);\n\n    Eventful.call(this, this._ecEventProcessor = new EventProcessor());\n\n    /**\n     * @type {module:echarts~MessageCenter}\n     * @private\n     */\n    this._messageCenter = new MessageCenter();\n\n    // Init mouse events\n    this._initEvents();\n\n    // In case some people write `window.onresize = chart.resize`\n    this.resize = bind(this.resize, this);\n\n    // Can't dispatch action during rendering procedure\n    this._pendingActions = [];\n\n    zr.animation.on('frame', this._onframe, this);\n\n    bindRenderedEvent(zr, this);\n\n    // ECharts instance can be used as value.\n    setAsPrimitive(this);\n}\n\nvar echartsProto = ECharts.prototype;\n\nechartsProto._onframe = function () {\n    if (this._disposed) {\n        return;\n    }\n\n    var scheduler = this._scheduler;\n\n    // Lazy update\n    if (this[OPTION_UPDATED]) {\n        var silent = this[OPTION_UPDATED].silent;\n\n        this[IN_MAIN_PROCESS] = true;\n\n        prepare(this);\n        updateMethods.update.call(this);\n\n        this[IN_MAIN_PROCESS] = false;\n\n        this[OPTION_UPDATED] = false;\n\n        flushPendingActions.call(this, silent);\n\n        triggerUpdatedEvent.call(this, silent);\n    }\n    // Avoid do both lazy update and progress in one frame.\n    else if (scheduler.unfinished) {\n        // Stream progress.\n        var remainTime = TEST_FRAME_REMAIN_TIME;\n        var ecModel = this._model;\n        var api = this._api;\n        scheduler.unfinished = false;\n        do {\n            var startTime = +new Date();\n\n            scheduler.performSeriesTasks(ecModel);\n\n            // Currently dataProcessorFuncs do not check threshold.\n            scheduler.performDataProcessorTasks(ecModel);\n\n            updateStreamModes(this, ecModel);\n\n            // Do not update coordinate system here. Because that coord system update in\n            // each frame is not a good user experience. So we follow the rule that\n            // the extent of the coordinate system is determin in the first frame (the\n            // frame is executed immedietely after task reset.\n            // this._coordSysMgr.update(ecModel, api);\n\n            // console.log('--- ec frame visual ---', remainTime);\n            scheduler.performVisualTasks(ecModel);\n\n            renderSeries(this, this._model, api, 'remain');\n\n            remainTime -= (+new Date() - startTime);\n        }\n        while (remainTime > 0 && scheduler.unfinished);\n\n        // Call flush explicitly for trigger finished event.\n        if (!scheduler.unfinished) {\n            this._zr.flush();\n        }\n        // Else, zr flushing be ensue within the same frame,\n        // because zr flushing is after onframe event.\n    }\n};\n\n/**\n * @return {HTMLElement}\n */\nechartsProto.getDom = function () {\n    return this._dom;\n};\n\n/**\n * @return {module:zrender~ZRender}\n */\nechartsProto.getZr = function () {\n    return this._zr;\n};\n\n/**\n * Usage:\n * chart.setOption(option, notMerge, lazyUpdate);\n * chart.setOption(option, {\n *     notMerge: ...,\n *     lazyUpdate: ...,\n *     silent: ...\n * });\n *\n * @param {Object} option\n * @param {Object|boolean} [opts] opts or notMerge.\n * @param {boolean} [opts.notMerge=false]\n * @param {boolean} [opts.lazyUpdate=false] Useful when setOption frequently.\n */\nechartsProto.setOption = function (option, notMerge, lazyUpdate) {\n    if (__DEV__) {\n        assert(!this[IN_MAIN_PROCESS], '`setOption` should not be called during main process.');\n    }\n\n    var silent;\n    if (isObject(notMerge)) {\n        lazyUpdate = notMerge.lazyUpdate;\n        silent = notMerge.silent;\n        notMerge = notMerge.notMerge;\n    }\n\n    this[IN_MAIN_PROCESS] = true;\n\n    if (!this._model || notMerge) {\n        var optionManager = new OptionManager(this._api);\n        var theme$$1 = this._theme;\n        var ecModel = this._model = new GlobalModel(null, null, theme$$1, optionManager);\n        ecModel.scheduler = this._scheduler;\n        ecModel.init(null, null, theme$$1, optionManager);\n    }\n\n    this._model.setOption(option, optionPreprocessorFuncs);\n\n    if (lazyUpdate) {\n        this[OPTION_UPDATED] = {silent: silent};\n        this[IN_MAIN_PROCESS] = false;\n    }\n    else {\n        prepare(this);\n\n        updateMethods.update.call(this);\n\n        // Ensure zr refresh sychronously, and then pixel in canvas can be\n        // fetched after `setOption`.\n        this._zr.flush();\n\n        this[OPTION_UPDATED] = false;\n        this[IN_MAIN_PROCESS] = false;\n\n        flushPendingActions.call(this, silent);\n        triggerUpdatedEvent.call(this, silent);\n    }\n};\n\n/**\n * @DEPRECATED\n */\nechartsProto.setTheme = function () {\n    console.error('ECharts#setTheme() is DEPRECATED in ECharts 3.0');\n};\n\n/**\n * @return {module:echarts/model/Global}\n */\nechartsProto.getModel = function () {\n    return this._model;\n};\n\n/**\n * @return {Object}\n */\nechartsProto.getOption = function () {\n    return this._model && this._model.getOption();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getWidth = function () {\n    return this._zr.getWidth();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getHeight = function () {\n    return this._zr.getHeight();\n};\n\n/**\n * @return {number}\n */\nechartsProto.getDevicePixelRatio = function () {\n    return this._zr.painter.dpr || window.devicePixelRatio || 1;\n};\n\n/**\n * Get canvas which has all thing rendered\n * @param {Object} opts\n * @param {string} [opts.backgroundColor]\n * @return {string}\n */\nechartsProto.getRenderedCanvas = function (opts) {\n    if (!env$1.canvasSupported) {\n        return;\n    }\n    opts = opts || {};\n    opts.pixelRatio = opts.pixelRatio || 1;\n    opts.backgroundColor = opts.backgroundColor\n        || this._model.get('backgroundColor');\n    var zr = this._zr;\n    // var list = zr.storage.getDisplayList();\n    // Stop animations\n    // Never works before in init animation, so remove it.\n    // zrUtil.each(list, function (el) {\n    //     el.stopAnimation(true);\n    // });\n    return zr.painter.getRenderedCanvas(opts);\n};\n\n/**\n * Get svg data url\n * @return {string}\n */\nechartsProto.getSvgDataUrl = function () {\n    if (!env$1.svgSupported) {\n        return;\n    }\n\n    var zr = this._zr;\n    var list = zr.storage.getDisplayList();\n    // Stop animations\n    each$1(list, function (el) {\n        el.stopAnimation(true);\n    });\n\n    return zr.painter.pathToDataUrl();\n};\n\n/**\n * @return {string}\n * @param {Object} opts\n * @param {string} [opts.type='png']\n * @param {string} [opts.pixelRatio=1]\n * @param {string} [opts.backgroundColor]\n * @param {string} [opts.excludeComponents]\n */\nechartsProto.getDataURL = function (opts) {\n    opts = opts || {};\n    var excludeComponents = opts.excludeComponents;\n    var ecModel = this._model;\n    var excludesComponentViews = [];\n    var self = this;\n\n    each(excludeComponents, function (componentType) {\n        ecModel.eachComponent({\n            mainType: componentType\n        }, function (component) {\n            var view = self._componentsMap[component.__viewId];\n            if (!view.group.ignore) {\n                excludesComponentViews.push(view);\n                view.group.ignore = true;\n            }\n        });\n    });\n\n    var url = this._zr.painter.getType() === 'svg'\n        ? this.getSvgDataUrl()\n        : this.getRenderedCanvas(opts).toDataURL(\n            'image/' + (opts && opts.type || 'png')\n        );\n\n    each(excludesComponentViews, function (view) {\n        view.group.ignore = false;\n    });\n\n    return url;\n};\n\n\n/**\n * @return {string}\n * @param {Object} opts\n * @param {string} [opts.type='png']\n * @param {string} [opts.pixelRatio=1]\n * @param {string} [opts.backgroundColor]\n */\nechartsProto.getConnectedDataURL = function (opts) {\n    if (!env$1.canvasSupported) {\n        return;\n    }\n    var groupId = this.group;\n    var mathMin = Math.min;\n    var mathMax = Math.max;\n    var MAX_NUMBER = Infinity;\n    if (connectedGroups[groupId]) {\n        var left = MAX_NUMBER;\n        var top = MAX_NUMBER;\n        var right = -MAX_NUMBER;\n        var bottom = -MAX_NUMBER;\n        var canvasList = [];\n        var dpr = (opts && opts.pixelRatio) || 1;\n\n        each$1(instances, function (chart, id) {\n            if (chart.group === groupId) {\n                var canvas = chart.getRenderedCanvas(\n                    clone(opts)\n                );\n                var boundingRect = chart.getDom().getBoundingClientRect();\n                left = mathMin(boundingRect.left, left);\n                top = mathMin(boundingRect.top, top);\n                right = mathMax(boundingRect.right, right);\n                bottom = mathMax(boundingRect.bottom, bottom);\n                canvasList.push({\n                    dom: canvas,\n                    left: boundingRect.left,\n                    top: boundingRect.top\n                });\n            }\n        });\n\n        left *= dpr;\n        top *= dpr;\n        right *= dpr;\n        bottom *= dpr;\n        var width = right - left;\n        var height = bottom - top;\n        var targetCanvas = createCanvas();\n        targetCanvas.width = width;\n        targetCanvas.height = height;\n        var zr = init$1(targetCanvas);\n\n        each(canvasList, function (item) {\n            var img = new ZImage({\n                style: {\n                    x: item.left * dpr - left,\n                    y: item.top * dpr - top,\n                    image: item.dom\n                }\n            });\n            zr.add(img);\n        });\n        zr.refreshImmediately();\n\n        return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png'));\n    }\n    else {\n        return this.getDataURL(opts);\n    }\n};\n\n/**\n * Convert from logical coordinate system to pixel coordinate system.\n * See CoordinateSystem#convertToPixel.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId, geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName,\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {Array|number} result\n */\nechartsProto.convertToPixel = curry(doConvertPixel, 'convertToPixel');\n\n/**\n * Convert from pixel coordinate system to logical coordinate system.\n * See CoordinateSystem#convertFromPixel.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId / geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {Array|number} result\n */\nechartsProto.convertFromPixel = curry(doConvertPixel, 'convertFromPixel');\n\nfunction doConvertPixel(methodName, finder, value) {\n    var ecModel = this._model;\n    var coordSysList = this._coordSysMgr.getCoordinateSystems();\n    var result;\n\n    finder = parseFinder(ecModel, finder);\n\n    for (var i = 0; i < coordSysList.length; i++) {\n        var coordSys = coordSysList[i];\n        if (coordSys[methodName]\n            && (result = coordSys[methodName](ecModel, finder, value)) != null\n        ) {\n            return result;\n        }\n    }\n\n    if (__DEV__) {\n        console.warn(\n            'No coordinate system that supports ' + methodName + ' found by the given finder.'\n        );\n    }\n}\n\n/**\n * Is the specified coordinate systems or components contain the given pixel point.\n * @param {string|Object} finder\n *        If string, e.g., 'geo', means {geoIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            geoIndex / geoId / geoName,\n *            bmapIndex / bmapId / bmapName,\n *            xAxisIndex / xAxisId / xAxisName,\n *            yAxisIndex / yAxisId / yAxisName,\n *            gridIndex / gridId / gridName,\n *            ... (can be extended)\n *        }\n * @param {Array|number} value\n * @return {boolean} result\n */\nechartsProto.containPixel = function (finder, value) {\n    var ecModel = this._model;\n    var result;\n\n    finder = parseFinder(ecModel, finder);\n\n    each$1(finder, function (models, key) {\n        key.indexOf('Models') >= 0 && each$1(models, function (model) {\n            var coordSys = model.coordinateSystem;\n            if (coordSys && coordSys.containPoint) {\n                result |= !!coordSys.containPoint(value);\n            }\n            else if (key === 'seriesModels') {\n                var view = this._chartsMap[model.__viewId];\n                if (view && view.containPoint) {\n                    result |= view.containPoint(value, model);\n                }\n                else {\n                    if (__DEV__) {\n                        console.warn(key + ': ' + (view\n                            ? 'The found component do not support containPoint.'\n                            : 'No view mapping to the found component.'\n                        ));\n                    }\n                }\n            }\n            else {\n                if (__DEV__) {\n                    console.warn(key + ': containPoint is not supported');\n                }\n            }\n        }, this);\n    }, this);\n\n    return !!result;\n};\n\n/**\n * Get visual from series or data.\n * @param {string|Object} finder\n *        If string, e.g., 'series', means {seriesIndex: 0}.\n *        If Object, could contain some of these properties below:\n *        {\n *            seriesIndex / seriesId / seriesName,\n *            dataIndex / dataIndexInside\n *        }\n *        If dataIndex is not specified, series visual will be fetched,\n *        but not data item visual.\n *        If all of seriesIndex, seriesId, seriesName are not specified,\n *        visual will be fetched from first series.\n * @param {string} visualType 'color', 'symbol', 'symbolSize'\n */\nechartsProto.getVisual = function (finder, visualType) {\n    var ecModel = this._model;\n\n    finder = parseFinder(ecModel, finder, {defaultMainType: 'series'});\n\n    var seriesModel = finder.seriesModel;\n\n    if (__DEV__) {\n        if (!seriesModel) {\n            console.warn('There is no specified seires model');\n        }\n    }\n\n    var data = seriesModel.getData();\n\n    var dataIndexInside = finder.hasOwnProperty('dataIndexInside')\n        ? finder.dataIndexInside\n        : finder.hasOwnProperty('dataIndex')\n        ? data.indexOfRawIndex(finder.dataIndex)\n        : null;\n\n    return dataIndexInside != null\n        ? data.getItemVisual(dataIndexInside, visualType)\n        : data.getVisual(visualType);\n};\n\n/**\n * Get view of corresponding component model\n * @param  {module:echarts/model/Component} componentModel\n * @return {module:echarts/view/Component}\n */\nechartsProto.getViewOfComponentModel = function (componentModel) {\n    return this._componentsMap[componentModel.__viewId];\n};\n\n/**\n * Get view of corresponding series model\n * @param  {module:echarts/model/Series} seriesModel\n * @return {module:echarts/view/Chart}\n */\nechartsProto.getViewOfSeriesModel = function (seriesModel) {\n    return this._chartsMap[seriesModel.__viewId];\n};\n\nvar updateMethods = {\n\n    prepareAndUpdate: function (payload) {\n        prepare(this);\n        updateMethods.update.call(this, payload);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    update: function (payload) {\n        // console.profile && console.profile('update');\n\n        var ecModel = this._model;\n        var api = this._api;\n        var zr = this._zr;\n        var coordSysMgr = this._coordSysMgr;\n        var scheduler = this._scheduler;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        scheduler.restoreData(ecModel, payload);\n\n        scheduler.performSeriesTasks(ecModel);\n\n        // TODO\n        // Save total ecModel here for undo/redo (after restoring data and before processing data).\n        // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call.\n\n        // Create new coordinate system each update\n        // In LineView may save the old coordinate system and use it to get the orignal point\n        coordSysMgr.create(ecModel, api);\n\n        scheduler.performDataProcessorTasks(ecModel, payload);\n\n        // Current stream render is not supported in data process. So we can update\n        // stream modes after data processing, where the filtered data is used to\n        // deteming whether use progressive rendering.\n        updateStreamModes(this, ecModel);\n\n        // We update stream modes before coordinate system updated, then the modes info\n        // can be fetched when coord sys updating (consider the barGrid extent fix). But\n        // the drawback is the full coord info can not be fetched. Fortunately this full\n        // coord is not requied in stream mode updater currently.\n        coordSysMgr.update(ecModel, api);\n\n        clearColorPalette(ecModel);\n        scheduler.performVisualTasks(ecModel, payload);\n\n        render(this, ecModel, api, payload);\n\n        // Set background\n        var backgroundColor = ecModel.get('backgroundColor') || 'transparent';\n\n        // In IE8\n        if (!env$1.canvasSupported) {\n            var colorArr = parse(backgroundColor);\n            backgroundColor = stringify(colorArr, 'rgb');\n            if (colorArr[3] === 0) {\n                backgroundColor = 'transparent';\n            }\n        }\n        else {\n            zr.setBackgroundColor(backgroundColor);\n        }\n\n        performPostUpdateFuncs(ecModel, api);\n\n        // console.profile && console.profileEnd('update');\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateTransform: function (payload) {\n        var ecModel = this._model;\n        var ecIns = this;\n        var api = this._api;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        // ChartView.markUpdateMethod(payload, 'updateTransform');\n\n        var componentDirtyList = [];\n        ecModel.eachComponent(function (componentType, componentModel) {\n            var componentView = ecIns.getViewOfComponentModel(componentModel);\n            if (componentView && componentView.__alive) {\n                if (componentView.updateTransform) {\n                    var result = componentView.updateTransform(componentModel, ecModel, api, payload);\n                    result && result.update && componentDirtyList.push(componentView);\n                }\n                else {\n                    componentDirtyList.push(componentView);\n                }\n            }\n        });\n\n        var seriesDirtyMap = createHashMap();\n        ecModel.eachSeries(function (seriesModel) {\n            var chartView = ecIns._chartsMap[seriesModel.__viewId];\n            if (chartView.updateTransform) {\n                var result = chartView.updateTransform(seriesModel, ecModel, api, payload);\n                result && result.update && seriesDirtyMap.set(seriesModel.uid, 1);\n            }\n            else {\n                seriesDirtyMap.set(seriesModel.uid, 1);\n            }\n        });\n\n        clearColorPalette(ecModel);\n        // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);\n        this._scheduler.performVisualTasks(\n            ecModel, payload, {setDirty: true, dirtyMap: seriesDirtyMap}\n        );\n\n        // Currently, not call render of components. Geo render cost a lot.\n        // renderComponents(ecIns, ecModel, api, payload, componentDirtyList);\n        renderSeries(ecIns, ecModel, api, payload, seriesDirtyMap);\n\n        performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateView: function (payload) {\n        var ecModel = this._model;\n\n        // update before setOption\n        if (!ecModel) {\n            return;\n        }\n\n        Chart.markUpdateMethod(payload, 'updateView');\n\n        clearColorPalette(ecModel);\n\n        // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});\n\n        render(this, this._model, this._api, payload);\n\n        performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateVisual: function (payload) {\n        updateMethods.update.call(this, payload);\n\n        // var ecModel = this._model;\n\n        // // update before setOption\n        // if (!ecModel) {\n        //     return;\n        // }\n\n        // ChartView.markUpdateMethod(payload, 'updateVisual');\n\n        // clearColorPalette(ecModel);\n\n        // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // this._scheduler.performVisualTasks(ecModel, payload, {visualType: 'visual', setDirty: true});\n\n        // render(this, this._model, this._api, payload);\n\n        // performPostUpdateFuncs(ecModel, this._api);\n    },\n\n    /**\n     * @param {Object} payload\n     * @private\n     */\n    updateLayout: function (payload) {\n        updateMethods.update.call(this, payload);\n\n        // var ecModel = this._model;\n\n        // // update before setOption\n        // if (!ecModel) {\n        //     return;\n        // }\n\n        // ChartView.markUpdateMethod(payload, 'updateLayout');\n\n        // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.\n        // // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);\n        // this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});\n\n        // render(this, this._model, this._api, payload);\n\n        // performPostUpdateFuncs(ecModel, this._api);\n    }\n};\n\nfunction prepare(ecIns) {\n    var ecModel = ecIns._model;\n    var scheduler = ecIns._scheduler;\n\n    scheduler.restorePipelines(ecModel);\n\n    scheduler.prepareStageTasks();\n\n    prepareView(ecIns, 'component', ecModel, scheduler);\n\n    prepareView(ecIns, 'chart', ecModel, scheduler);\n\n    scheduler.plan();\n}\n\n/**\n * @private\n */\nfunction updateDirectly(ecIns, method, payload, mainType, subType) {\n    var ecModel = ecIns._model;\n\n    // broadcast\n    if (!mainType) {\n        // FIXME\n        // Chart will not be update directly here, except set dirty.\n        // But there is no such scenario now.\n        each(ecIns._componentsViews.concat(ecIns._chartsViews), callView);\n        return;\n    }\n\n    var query = {};\n    query[mainType + 'Id'] = payload[mainType + 'Id'];\n    query[mainType + 'Index'] = payload[mainType + 'Index'];\n    query[mainType + 'Name'] = payload[mainType + 'Name'];\n\n    var condition = {mainType: mainType, query: query};\n    subType && (condition.subType = subType); // subType may be '' by parseClassType;\n\n    var excludeSeriesId = payload.excludeSeriesId;\n    if (excludeSeriesId != null) {\n        excludeSeriesId = createHashMap(normalizeToArray(excludeSeriesId));\n    }\n\n    // If dispatchAction before setOption, do nothing.\n    ecModel && ecModel.eachComponent(condition, function (model) {\n        if (!excludeSeriesId || excludeSeriesId.get(model.id) == null) {\n            callView(ecIns[\n                mainType === 'series' ? '_chartsMap' : '_componentsMap'\n            ][model.__viewId]);\n        }\n    }, ecIns);\n\n    function callView(view) {\n        view && view.__alive && view[method] && view[method](\n            view.__model, ecModel, ecIns._api, payload\n        );\n    }\n}\n\n/**\n * Resize the chart\n * @param {Object} opts\n * @param {number} [opts.width] Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Can be 'auto' (the same as null/undefined)\n * @param {boolean} [opts.silent=false]\n */\nechartsProto.resize = function (opts) {\n    if (__DEV__) {\n        assert(!this[IN_MAIN_PROCESS], '`resize` should not be called during main process.');\n    }\n\n    this._zr.resize(opts);\n\n    var ecModel = this._model;\n\n    // Resize loading effect\n    this._loadingFX && this._loadingFX.resize();\n\n    if (!ecModel) {\n        return;\n    }\n\n    var optionChanged = ecModel.resetOption('media');\n\n    var silent = opts && opts.silent;\n\n    this[IN_MAIN_PROCESS] = true;\n\n    optionChanged && prepare(this);\n    updateMethods.update.call(this);\n\n    this[IN_MAIN_PROCESS] = false;\n\n    flushPendingActions.call(this, silent);\n\n    triggerUpdatedEvent.call(this, silent);\n};\n\nfunction updateStreamModes(ecIns, ecModel) {\n    var chartsMap = ecIns._chartsMap;\n    var scheduler = ecIns._scheduler;\n    ecModel.eachSeries(function (seriesModel) {\n        scheduler.updateStreamModes(seriesModel, chartsMap[seriesModel.__viewId]);\n    });\n}\n\n/**\n * Show loading effect\n * @param  {string} [name='default']\n * @param  {Object} [cfg]\n */\nechartsProto.showLoading = function (name, cfg) {\n    if (isObject(name)) {\n        cfg = name;\n        name = '';\n    }\n    name = name || 'default';\n\n    this.hideLoading();\n    if (!loadingEffects[name]) {\n        if (__DEV__) {\n            console.warn('Loading effects ' + name + ' not exists.');\n        }\n        return;\n    }\n    var el = loadingEffects[name](this._api, cfg);\n    var zr = this._zr;\n    this._loadingFX = el;\n\n    zr.add(el);\n};\n\n/**\n * Hide loading effect\n */\nechartsProto.hideLoading = function () {\n    this._loadingFX && this._zr.remove(this._loadingFX);\n    this._loadingFX = null;\n};\n\n/**\n * @param {Object} eventObj\n * @return {Object}\n */\nechartsProto.makeActionFromEvent = function (eventObj) {\n    var payload = extend({}, eventObj);\n    payload.type = eventActionMap[eventObj.type];\n    return payload;\n};\n\n/**\n * @pubilc\n * @param {Object} payload\n * @param {string} [payload.type] Action type\n * @param {Object|boolean} [opt] If pass boolean, means opt.silent\n * @param {boolean} [opt.silent=false] Whether trigger events.\n * @param {boolean} [opt.flush=undefined]\n *                  true: Flush immediately, and then pixel in canvas can be fetched\n *                      immediately. Caution: it might affect performance.\n *                  false: Not not flush.\n *                  undefined: Auto decide whether perform flush.\n */\nechartsProto.dispatchAction = function (payload, opt) {\n    if (!isObject(opt)) {\n        opt = {silent: !!opt};\n    }\n\n    if (!actions[payload.type]) {\n        return;\n    }\n\n    // Avoid dispatch action before setOption. Especially in `connect`.\n    if (!this._model) {\n        return;\n    }\n\n    // May dispatchAction in rendering procedure\n    if (this[IN_MAIN_PROCESS]) {\n        this._pendingActions.push(payload);\n        return;\n    }\n\n    doDispatchAction.call(this, payload, opt.silent);\n\n    if (opt.flush) {\n        this._zr.flush(true);\n    }\n    else if (opt.flush !== false && env$1.browser.weChat) {\n        // In WeChat embeded browser, `requestAnimationFrame` and `setInterval`\n        // hang when sliding page (on touch event), which cause that zr does not\n        // refresh util user interaction finished, which is not expected.\n        // But `dispatchAction` may be called too frequently when pan on touch\n        // screen, which impacts performance if do not throttle them.\n        this._throttledZrFlush();\n    }\n\n    flushPendingActions.call(this, opt.silent);\n\n    triggerUpdatedEvent.call(this, opt.silent);\n};\n\nfunction doDispatchAction(payload, silent) {\n    var payloadType = payload.type;\n    var escapeConnect = payload.escapeConnect;\n    var actionWrap = actions[payloadType];\n    var actionInfo = actionWrap.actionInfo;\n\n    var cptType = (actionInfo.update || 'update').split(':');\n    var updateMethod = cptType.pop();\n    cptType = cptType[0] != null && parseClassType(cptType[0]);\n\n    this[IN_MAIN_PROCESS] = true;\n\n    var payloads = [payload];\n    var batched = false;\n    // Batch action\n    if (payload.batch) {\n        batched = true;\n        payloads = map(payload.batch, function (item) {\n            item = defaults(extend({}, item), payload);\n            item.batch = null;\n            return item;\n        });\n    }\n\n    var eventObjBatch = [];\n    var eventObj;\n    var isHighDown = payloadType === 'highlight' || payloadType === 'downplay';\n\n    each(payloads, function (batchItem) {\n        // Action can specify the event by return it.\n        eventObj = actionWrap.action(batchItem, this._model, this._api);\n        // Emit event outside\n        eventObj = eventObj || extend({}, batchItem);\n        // Convert type to eventType\n        eventObj.type = actionInfo.event || eventObj.type;\n        eventObjBatch.push(eventObj);\n\n        // light update does not perform data process, layout and visual.\n        if (isHighDown) {\n            // method, payload, mainType, subType\n            updateDirectly(this, updateMethod, batchItem, 'series');\n        }\n        else if (cptType) {\n            updateDirectly(this, updateMethod, batchItem, cptType.main, cptType.sub);\n        }\n    }, this);\n\n    if (updateMethod !== 'none' && !isHighDown && !cptType) {\n        // Still dirty\n        if (this[OPTION_UPDATED]) {\n            // FIXME Pass payload ?\n            prepare(this);\n            updateMethods.update.call(this, payload);\n            this[OPTION_UPDATED] = false;\n        }\n        else {\n            updateMethods[updateMethod].call(this, payload);\n        }\n    }\n\n    // Follow the rule of action batch\n    if (batched) {\n        eventObj = {\n            type: actionInfo.event || payloadType,\n            escapeConnect: escapeConnect,\n            batch: eventObjBatch\n        };\n    }\n    else {\n        eventObj = eventObjBatch[0];\n    }\n\n    this[IN_MAIN_PROCESS] = false;\n\n    !silent && this._messageCenter.trigger(eventObj.type, eventObj);\n}\n\nfunction flushPendingActions(silent) {\n    var pendingActions = this._pendingActions;\n    while (pendingActions.length) {\n        var payload = pendingActions.shift();\n        doDispatchAction.call(this, payload, silent);\n    }\n}\n\nfunction triggerUpdatedEvent(silent) {\n    !silent && this.trigger('updated');\n}\n\n/**\n * Event `rendered` is triggered when zr\n * rendered. It is useful for realtime\n * snapshot (reflect animation).\n *\n * Event `finished` is triggered when:\n * (1) zrender rendering finished.\n * (2) initial animation finished.\n * (3) progressive rendering finished.\n * (4) no pending action.\n * (5) no delayed setOption needs to be processed.\n */\nfunction bindRenderedEvent(zr, ecIns) {\n    zr.on('rendered', function () {\n\n        ecIns.trigger('rendered');\n\n        // The `finished` event should not be triggered repeatly,\n        // so it should only be triggered when rendering indeed happend\n        // in zrender. (Consider the case that dipatchAction is keep\n        // triggering when mouse move).\n        if (\n            // Although zr is dirty if initial animation is not finished\n            // and this checking is called on frame, we also check\n            // animation finished for robustness.\n            zr.animation.isFinished()\n            && !ecIns[OPTION_UPDATED]\n            && !ecIns._scheduler.unfinished\n            && !ecIns._pendingActions.length\n        ) {\n            ecIns.trigger('finished');\n        }\n    });\n}\n\n/**\n * @param {Object} params\n * @param {number} params.seriesIndex\n * @param {Array|TypedArray} params.data\n */\nechartsProto.appendData = function (params) {\n    var seriesIndex = params.seriesIndex;\n    var ecModel = this.getModel();\n    var seriesModel = ecModel.getSeriesByIndex(seriesIndex);\n\n    if (__DEV__) {\n        assert(params.data && seriesModel);\n    }\n\n    seriesModel.appendData(params);\n\n    // Note: `appendData` does not support that update extent of coordinate\n    // system, util some scenario require that. In the expected usage of\n    // `appendData`, the initial extent of coordinate system should better\n    // be fixed by axis `min`/`max` setting or initial data, otherwise if\n    // the extent changed while `appendData`, the location of the painted\n    // graphic elements have to be changed, which make the usage of\n    // `appendData` meaningless.\n\n    this._scheduler.unfinished = true;\n};\n\n/**\n * Register event\n * @method\n */\nechartsProto.on = createRegisterEventWithLowercaseName('on');\nechartsProto.off = createRegisterEventWithLowercaseName('off');\nechartsProto.one = createRegisterEventWithLowercaseName('one');\n\n/**\n * Prepare view instances of charts and components\n * @param  {module:echarts/model/Global} ecModel\n * @private\n */\nfunction prepareView(ecIns, type, ecModel, scheduler) {\n    var isComponent = type === 'component';\n    var viewList = isComponent ? ecIns._componentsViews : ecIns._chartsViews;\n    var viewMap = isComponent ? ecIns._componentsMap : ecIns._chartsMap;\n    var zr = ecIns._zr;\n    var api = ecIns._api;\n\n    for (var i = 0; i < viewList.length; i++) {\n        viewList[i].__alive = false;\n    }\n\n    isComponent\n        ? ecModel.eachComponent(function (componentType, model) {\n            componentType !== 'series' && doPrepare(model);\n        })\n        : ecModel.eachSeries(doPrepare);\n\n    function doPrepare(model) {\n        // Consider: id same and type changed.\n        var viewId = '_ec_' + model.id + '_' + model.type;\n        var view = viewMap[viewId];\n        if (!view) {\n            var classType = parseClassType(model.type);\n            var Clazz = isComponent\n                ? Component.getClass(classType.main, classType.sub)\n                : Chart.getClass(classType.sub);\n\n            if (__DEV__) {\n                assert(Clazz, classType.sub + ' does not exist.');\n            }\n\n            view = new Clazz();\n            view.init(ecModel, api);\n            viewMap[viewId] = view;\n            viewList.push(view);\n            zr.add(view.group);\n        }\n\n        model.__viewId = view.__id = viewId;\n        view.__alive = true;\n        view.__model = model;\n        view.group.__ecComponentInfo = {\n            mainType: model.mainType,\n            index: model.componentIndex\n        };\n        !isComponent && scheduler.prepareView(view, model, ecModel, api);\n    }\n\n    for (var i = 0; i < viewList.length;) {\n        var view = viewList[i];\n        if (!view.__alive) {\n            !isComponent && view.renderTask.dispose();\n            zr.remove(view.group);\n            view.dispose(ecModel, api);\n            viewList.splice(i, 1);\n            delete viewMap[view.__id];\n            view.__id = view.group.__ecComponentInfo = null;\n        }\n        else {\n            i++;\n        }\n    }\n}\n\n// /**\n//  * Encode visual infomation from data after data processing\n//  *\n//  * @param {module:echarts/model/Global} ecModel\n//  * @param {object} layout\n//  * @param {boolean} [layoutFilter] `true`: only layout,\n//  *                                 `false`: only not layout,\n//  *                                 `null`/`undefined`: all.\n//  * @param {string} taskBaseTag\n//  * @private\n//  */\n// function startVisualEncoding(ecIns, ecModel, api, payload, layoutFilter) {\n//     each(visualFuncs, function (visual, index) {\n//         var isLayout = visual.isLayout;\n//         if (layoutFilter == null\n//             || (layoutFilter === false && !isLayout)\n//             || (layoutFilter === true && isLayout)\n//         ) {\n//             visual.func(ecModel, api, payload);\n//         }\n//     });\n// }\n\nfunction clearColorPalette(ecModel) {\n    ecModel.clearColorPalette();\n    ecModel.eachSeries(function (seriesModel) {\n        seriesModel.clearColorPalette();\n    });\n}\n\nfunction render(ecIns, ecModel, api, payload) {\n\n    renderComponents(ecIns, ecModel, api, payload);\n\n    each(ecIns._chartsViews, function (chart) {\n        chart.__alive = false;\n    });\n\n    renderSeries(ecIns, ecModel, api, payload);\n\n    // Remove groups of unrendered charts\n    each(ecIns._chartsViews, function (chart) {\n        if (!chart.__alive) {\n            chart.remove(ecModel, api);\n        }\n    });\n}\n\nfunction renderComponents(ecIns, ecModel, api, payload, dirtyList) {\n    each(dirtyList || ecIns._componentsViews, function (componentView) {\n        var componentModel = componentView.__model;\n        componentView.render(componentModel, ecModel, api, payload);\n\n        updateZ(componentModel, componentView);\n    });\n}\n\n/**\n * Render each chart and component\n * @private\n */\nfunction renderSeries(ecIns, ecModel, api, payload, dirtyMap) {\n    // Render all charts\n    var scheduler = ecIns._scheduler;\n    var unfinished;\n    ecModel.eachSeries(function (seriesModel) {\n        var chartView = ecIns._chartsMap[seriesModel.__viewId];\n        chartView.__alive = true;\n\n        var renderTask = chartView.renderTask;\n        scheduler.updatePayload(renderTask, payload);\n\n        if (dirtyMap && dirtyMap.get(seriesModel.uid)) {\n            renderTask.dirty();\n        }\n\n        unfinished |= renderTask.perform(scheduler.getPerformArgs(renderTask));\n\n        chartView.group.silent = !!seriesModel.get('silent');\n\n        updateZ(seriesModel, chartView);\n\n        updateBlend(seriesModel, chartView);\n    });\n    scheduler.unfinished |= unfinished;\n\n    // If use hover layer\n    updateHoverLayerStatus(ecIns._zr, ecModel);\n\n    // Add aria\n    aria(ecIns._zr.dom, ecModel);\n}\n\nfunction performPostUpdateFuncs(ecModel, api) {\n    each(postUpdateFuncs, function (func) {\n        func(ecModel, api);\n    });\n}\n\n\nvar MOUSE_EVENT_NAMES = [\n    'click', 'dblclick', 'mouseover', 'mouseout', 'mousemove',\n    'mousedown', 'mouseup', 'globalout', 'contextmenu'\n];\n\n/**\n * @private\n */\nechartsProto._initEvents = function () {\n    each(MOUSE_EVENT_NAMES, function (eveName) {\n        var handler = function (e) {\n            var ecModel = this.getModel();\n            var el = e.target;\n            var params;\n            var isGlobalOut = eveName === 'globalout';\n\n            // no e.target when 'globalout'.\n            if (isGlobalOut) {\n                params = {};\n            }\n            else if (el && el.dataIndex != null) {\n                var dataModel = el.dataModel || ecModel.getSeriesByIndex(el.seriesIndex);\n                params = dataModel && dataModel.getDataParams(el.dataIndex, el.dataType, el) || {};\n            }\n            // If element has custom eventData of components\n            else if (el && el.eventData) {\n                params = extend({}, el.eventData);\n            }\n\n            // Contract: if params prepared in mouse event,\n            // these properties must be specified:\n            // {\n            //    componentType: string (component main type)\n            //    componentIndex: number\n            // }\n            // Otherwise event query can not work.\n\n            if (params) {\n                var componentType = params.componentType;\n                var componentIndex = params.componentIndex;\n                // Special handling for historic reason: when trigger by\n                // markLine/markPoint/markArea, the componentType is\n                // 'markLine'/'markPoint'/'markArea', but we should better\n                // enable them to be queried by seriesIndex, since their\n                // option is set in each series.\n                if (componentType === 'markLine'\n                    || componentType === 'markPoint'\n                    || componentType === 'markArea'\n                ) {\n                    componentType = 'series';\n                    componentIndex = params.seriesIndex;\n                }\n                var model = componentType && componentIndex != null\n                    && ecModel.getComponent(componentType, componentIndex);\n                var view = model && this[\n                    model.mainType === 'series' ? '_chartsMap' : '_componentsMap'\n                ][model.__viewId];\n\n                if (__DEV__) {\n                    // `event.componentType` and `event[componentTpype + 'Index']` must not\n                    // be missed, otherwise there is no way to distinguish source component.\n                    // See `dataFormat.getDataParams`.\n                    if (!isGlobalOut && !(model && view)) {\n                        console.warn('model or view can not be found by params');\n                    }\n                }\n\n                params.event = e;\n                params.type = eveName;\n\n                this._ecEventProcessor.eventInfo = {\n                    targetEl: el,\n                    packedEvent: params,\n                    model: model,\n                    view: view\n                };\n\n                this.trigger(eveName, params);\n            }\n        };\n        // Consider that some component (like tooltip, brush, ...)\n        // register zr event handler, but user event handler might\n        // do anything, such as call `setOption` or `dispatchAction`,\n        // which probably update any of the content and probably\n        // cause problem if it is called previous other inner handlers.\n        handler.zrEventfulCallAtLast = true;\n        this._zr.on(eveName, handler, this);\n    }, this);\n\n    each(eventActionMap, function (actionType, eventType) {\n        this._messageCenter.on(eventType, function (event) {\n            this.trigger(eventType, event);\n        }, this);\n    }, this);\n};\n\n/**\n * @return {boolean}\n */\nechartsProto.isDisposed = function () {\n    return this._disposed;\n};\n\n/**\n * Clear\n */\nechartsProto.clear = function () {\n    this.setOption({ series: [] }, true);\n};\n\n/**\n * Dispose instance\n */\nechartsProto.dispose = function () {\n    if (this._disposed) {\n        if (__DEV__) {\n            console.warn('Instance ' + this.id + ' has been disposed');\n        }\n        return;\n    }\n    this._disposed = true;\n\n    setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, '');\n\n    var api = this._api;\n    var ecModel = this._model;\n\n    each(this._componentsViews, function (component) {\n        component.dispose(ecModel, api);\n    });\n    each(this._chartsViews, function (chart) {\n        chart.dispose(ecModel, api);\n    });\n\n    // Dispose after all views disposed\n    this._zr.dispose();\n\n    delete instances[this.id];\n};\n\nmixin(ECharts, Eventful);\n\nfunction updateHoverLayerStatus(zr, ecModel) {\n    var storage = zr.storage;\n    var elCount = 0;\n    storage.traverse(function (el) {\n        if (!el.isGroup) {\n            elCount++;\n        }\n    });\n    if (elCount > ecModel.get('hoverLayerThreshold') && !env$1.node) {\n        storage.traverse(function (el) {\n            if (!el.isGroup) {\n                // Don't switch back.\n                el.useHoverLayer = true;\n            }\n        });\n    }\n}\n\n/**\n * Update chart progressive and blend.\n * @param {module:echarts/model/Series|module:echarts/model/Component} model\n * @param {module:echarts/view/Component|module:echarts/view/Chart} view\n */\nfunction updateBlend(seriesModel, chartView) {\n    var blendMode = seriesModel.get('blendMode') || null;\n    if (__DEV__) {\n        if (!env$1.canvasSupported && blendMode && blendMode !== 'source-over') {\n            console.warn('Only canvas support blendMode');\n        }\n    }\n    chartView.group.traverse(function (el) {\n        // FIXME marker and other components\n        if (!el.isGroup) {\n            // Only set if blendMode is changed. In case element is incremental and don't wan't to rerender.\n            if (el.style.blend !== blendMode) {\n                el.setStyle('blend', blendMode);\n            }\n        }\n        if (el.eachPendingDisplayable) {\n            el.eachPendingDisplayable(function (displayable) {\n                displayable.setStyle('blend', blendMode);\n            });\n        }\n    });\n}\n\n/**\n * @param {module:echarts/model/Series|module:echarts/model/Component} model\n * @param {module:echarts/view/Component|module:echarts/view/Chart} view\n */\nfunction updateZ(model, view) {\n    var z = model.get('z');\n    var zlevel = model.get('zlevel');\n    // Set z and zlevel\n    view.group.traverse(function (el) {\n        if (el.type !== 'group') {\n            z != null && (el.z = z);\n            zlevel != null && (el.zlevel = zlevel);\n        }\n    });\n}\n\nfunction createExtensionAPI(ecInstance) {\n    var coordSysMgr = ecInstance._coordSysMgr;\n    return extend(new ExtensionAPI(ecInstance), {\n        // Inject methods\n        getCoordinateSystems: bind(\n            coordSysMgr.getCoordinateSystems, coordSysMgr\n        ),\n        getComponentByElement: function (el) {\n            while (el) {\n                var modelInfo = el.__ecComponentInfo;\n                if (modelInfo != null) {\n                    return ecInstance._model.getComponent(modelInfo.mainType, modelInfo.index);\n                }\n                el = el.parent;\n            }\n        }\n    });\n}\n\n\n/**\n * @class\n * Usage of query:\n * `chart.on('click', query, handler);`\n * The `query` can be:\n * + The component type query string, only `mainType` or `mainType.subType`,\n *   like: 'xAxis', 'series', 'xAxis.category' or 'series.line'.\n * + The component query object, like:\n *   `{seriesIndex: 2}`, `{seriesName: 'xx'}`, `{seriesId: 'some'}`,\n *   `{xAxisIndex: 2}`, `{xAxisName: 'xx'}`, `{xAxisId: 'some'}`.\n * + The data query object, like:\n *   `{dataIndex: 123}`, `{dataType: 'link'}`, `{name: 'some'}`.\n * + The other query object (cmponent customized query), like:\n *   `{element: 'some'}` (only available in custom series).\n *\n * Caveat: If a prop in the `query` object is `null/undefined`, it is the\n * same as there is no such prop in the `query` object.\n */\nfunction EventProcessor() {\n    // These info required: targetEl, packedEvent, model, view\n    this.eventInfo;\n}\nEventProcessor.prototype = {\n    constructor: EventProcessor,\n\n    normalizeQuery: function (query) {\n        var cptQuery = {};\n        var dataQuery = {};\n        var otherQuery = {};\n\n        // `query` is `mainType` or `mainType.subType` of component.\n        if (isString(query)) {\n            var condCptType = parseClassType(query);\n            // `.main` and `.sub` may be ''.\n            cptQuery.mainType = condCptType.main || null;\n            cptQuery.subType = condCptType.sub || null;\n        }\n        // `query` is an object, convert to {mainType, index, name, id}.\n        else {\n            // `xxxIndex`, `xxxName`, `xxxId`, `name`, `dataIndex`, `dataType` is reserved,\n            // can not be used in `compomentModel.filterForExposedEvent`.\n            var suffixes = ['Index', 'Name', 'Id'];\n            var dataKeys = {name: 1, dataIndex: 1, dataType: 1};\n            each$1(query, function (val, key) {\n                var reserved = false;\n                for (var i = 0; i < suffixes.length; i++) {\n                    var propSuffix = suffixes[i];\n                    var suffixPos = key.lastIndexOf(propSuffix);\n                    if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) {\n                        var mainType = key.slice(0, suffixPos);\n                        // Consider `dataIndex`.\n                        if (mainType !== 'data') {\n                            cptQuery.mainType = mainType;\n                            cptQuery[propSuffix.toLowerCase()] = val;\n                            reserved = true;\n                        }\n                    }\n                }\n                if (dataKeys.hasOwnProperty(key)) {\n                    dataQuery[key] = val;\n                    reserved = true;\n                }\n                if (!reserved) {\n                    otherQuery[key] = val;\n                }\n            });\n        }\n\n        return {\n            cptQuery: cptQuery,\n            dataQuery: dataQuery,\n            otherQuery: otherQuery\n        };\n    },\n\n    filter: function (eventType, query, args) {\n        // They should be assigned before each trigger call.\n        var eventInfo = this.eventInfo;\n\n        if (!eventInfo) {\n            return true;\n        }\n\n        var targetEl = eventInfo.targetEl;\n        var packedEvent = eventInfo.packedEvent;\n        var model = eventInfo.model;\n        var view = eventInfo.view;\n\n        // For event like 'globalout'.\n        if (!model || !view) {\n            return true;\n        }\n\n        var cptQuery = query.cptQuery;\n        var dataQuery = query.dataQuery;\n\n        return check(cptQuery, model, 'mainType')\n            && check(cptQuery, model, 'subType')\n            && check(cptQuery, model, 'index', 'componentIndex')\n            && check(cptQuery, model, 'name')\n            && check(cptQuery, model, 'id')\n            && check(dataQuery, packedEvent, 'name')\n            && check(dataQuery, packedEvent, 'dataIndex')\n            && check(dataQuery, packedEvent, 'dataType')\n            && (!view.filterForExposedEvent || view.filterForExposedEvent(\n                eventType, query.otherQuery, targetEl, packedEvent\n            ));\n\n        function check(query, host, prop, propOnHost) {\n            return query[prop] == null || host[propOnHost || prop] === query[prop];\n        }\n    },\n\n    afterTrigger: function () {\n        // Make sure the eventInfo wont be used in next trigger.\n        this.eventInfo = null;\n    }\n};\n\n\n/**\n * @type {Object} key: actionType.\n * @inner\n */\nvar actions = {};\n\n/**\n * Map eventType to actionType\n * @type {Object}\n */\nvar eventActionMap = {};\n\n/**\n * Data processor functions of each stage\n * @type {Array.<Object.<string, Function>>}\n * @inner\n */\nvar dataProcessorFuncs = [];\n\n/**\n * @type {Array.<Function>}\n * @inner\n */\nvar optionPreprocessorFuncs = [];\n\n/**\n * @type {Array.<Function>}\n * @inner\n */\nvar postUpdateFuncs = [];\n\n/**\n * Visual encoding functions of each stage\n * @type {Array.<Object.<string, Function>>}\n */\nvar visualFuncs = [];\n\n/**\n * Theme storage\n * @type {Object.<key, Object>}\n */\nvar themeStorage = {};\n/**\n * Loading effects\n */\nvar loadingEffects = {};\n\nvar instances = {};\nvar connectedGroups = {};\n\nvar idBase = new Date() - 0;\nvar groupIdBase = new Date() - 0;\nvar DOM_ATTRIBUTE_KEY = '_echarts_instance_';\n\nfunction enableConnect(chart) {\n    var STATUS_PENDING = 0;\n    var STATUS_UPDATING = 1;\n    var STATUS_UPDATED = 2;\n    var STATUS_KEY = '__connectUpdateStatus';\n\n    function updateConnectedChartsStatus(charts, status) {\n        for (var i = 0; i < charts.length; i++) {\n            var otherChart = charts[i];\n            otherChart[STATUS_KEY] = status;\n        }\n    }\n\n    each(eventActionMap, function (actionType, eventType) {\n        chart._messageCenter.on(eventType, function (event) {\n            if (connectedGroups[chart.group] && chart[STATUS_KEY] !== STATUS_PENDING) {\n                if (event && event.escapeConnect) {\n                    return;\n                }\n\n                var action = chart.makeActionFromEvent(event);\n                var otherCharts = [];\n\n                each(instances, function (otherChart) {\n                    if (otherChart !== chart && otherChart.group === chart.group) {\n                        otherCharts.push(otherChart);\n                    }\n                });\n\n                updateConnectedChartsStatus(otherCharts, STATUS_PENDING);\n                each(otherCharts, function (otherChart) {\n                    if (otherChart[STATUS_KEY] !== STATUS_UPDATING) {\n                        otherChart.dispatchAction(action);\n                    }\n                });\n                updateConnectedChartsStatus(otherCharts, STATUS_UPDATED);\n            }\n        });\n    });\n}\n\n/**\n * @param {HTMLElement} dom\n * @param {Object} [theme]\n * @param {Object} opts\n * @param {number} [opts.devicePixelRatio] Use window.devicePixelRatio by default\n * @param {string} [opts.renderer] Currently only 'canvas' is supported.\n * @param {number} [opts.width] Use clientWidth of the input `dom` by default.\n *                              Can be 'auto' (the same as null/undefined)\n * @param {number} [opts.height] Use clientHeight of the input `dom` by default.\n *                               Can be 'auto' (the same as null/undefined)\n */\nfunction init(dom, theme$$1, opts) {\n    if (__DEV__) {\n        // Check version\n        if ((version$1.replace('.', '') - 0) < (dependencies.zrender.replace('.', '') - 0)) {\n            throw new Error(\n                'zrender/src ' + version$1\n                + ' is too old for ECharts ' + version\n                + '. Current version need ZRender '\n                + dependencies.zrender + '+'\n            );\n        }\n\n        if (!dom) {\n            throw new Error('Initialize failed: invalid dom.');\n        }\n    }\n\n    var existInstance = getInstanceByDom(dom);\n    if (existInstance) {\n        if (__DEV__) {\n            console.warn('There is a chart instance already initialized on the dom.');\n        }\n        return existInstance;\n    }\n\n    if (__DEV__) {\n        if (isDom(dom)\n            && dom.nodeName.toUpperCase() !== 'CANVAS'\n            && (\n                (!dom.clientWidth && (!opts || opts.width == null))\n                || (!dom.clientHeight && (!opts || opts.height == null))\n            )\n        ) {\n            console.warn('Can\\'t get dom width or height');\n        }\n    }\n\n    var chart = new ECharts(dom, theme$$1, opts);\n    chart.id = 'ec_' + idBase++;\n    instances[chart.id] = chart;\n\n    setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id);\n\n    enableConnect(chart);\n\n    return chart;\n}\n\n/**\n * @return {string|Array.<module:echarts~ECharts>} groupId\n */\nfunction connect(groupId) {\n    // Is array of charts\n    if (isArray(groupId)) {\n        var charts = groupId;\n        groupId = null;\n        // If any chart has group\n        each(charts, function (chart) {\n            if (chart.group != null) {\n                groupId = chart.group;\n            }\n        });\n        groupId = groupId || ('g_' + groupIdBase++);\n        each(charts, function (chart) {\n            chart.group = groupId;\n        });\n    }\n    connectedGroups[groupId] = true;\n    return groupId;\n}\n\n/**\n * @DEPRECATED\n * @return {string} groupId\n */\nfunction disConnect(groupId) {\n    connectedGroups[groupId] = false;\n}\n\n/**\n * @return {string} groupId\n */\nvar disconnect = disConnect;\n\n/**\n * Dispose a chart instance\n * @param  {module:echarts~ECharts|HTMLDomElement|string} chart\n */\nfunction dispose(chart) {\n    if (typeof chart === 'string') {\n        chart = instances[chart];\n    }\n    else if (!(chart instanceof ECharts)) {\n        // Try to treat as dom\n        chart = getInstanceByDom(chart);\n    }\n    if ((chart instanceof ECharts) && !chart.isDisposed()) {\n        chart.dispose();\n    }\n}\n\n/**\n * @param  {HTMLElement} dom\n * @return {echarts~ECharts}\n */\nfunction getInstanceByDom(dom) {\n    return instances[getAttribute(dom, DOM_ATTRIBUTE_KEY)];\n}\n\n/**\n * @param {string} key\n * @return {echarts~ECharts}\n */\nfunction getInstanceById(key) {\n    return instances[key];\n}\n\n/**\n * Register theme\n */\nfunction registerTheme(name, theme$$1) {\n    themeStorage[name] = theme$$1;\n}\n\n/**\n * Register option preprocessor\n * @param {Function} preprocessorFunc\n */\nfunction registerPreprocessor(preprocessorFunc) {\n    optionPreprocessorFuncs.push(preprocessorFunc);\n}\n\n/**\n * @param {number} [priority=1000]\n * @param {Object|Function} processor\n */\nfunction registerProcessor(priority, processor) {\n    normalizeRegister(dataProcessorFuncs, priority, processor, PRIORITY_PROCESSOR_FILTER);\n}\n\n/**\n * Register postUpdater\n * @param {Function} postUpdateFunc\n */\nfunction registerPostUpdate(postUpdateFunc) {\n    postUpdateFuncs.push(postUpdateFunc);\n}\n\n/**\n * Usage:\n * registerAction('someAction', 'someEvent', function () { ... });\n * registerAction('someAction', function () { ... });\n * registerAction(\n *     {type: 'someAction', event: 'someEvent', update: 'updateView'},\n *     function () { ... }\n * );\n *\n * @param {(string|Object)} actionInfo\n * @param {string} actionInfo.type\n * @param {string} [actionInfo.event]\n * @param {string} [actionInfo.update]\n * @param {string} [eventName]\n * @param {Function} action\n */\nfunction registerAction(actionInfo, eventName, action) {\n    if (typeof eventName === 'function') {\n        action = eventName;\n        eventName = '';\n    }\n    var actionType = isObject(actionInfo)\n        ? actionInfo.type\n        : ([actionInfo, actionInfo = {\n            event: eventName\n        }][0]);\n\n    // Event name is all lowercase\n    actionInfo.event = (actionInfo.event || actionType).toLowerCase();\n    eventName = actionInfo.event;\n\n    // Validate action type and event name.\n    assert(ACTION_REG.test(actionType) && ACTION_REG.test(eventName));\n\n    if (!actions[actionType]) {\n        actions[actionType] = {action: action, actionInfo: actionInfo};\n    }\n    eventActionMap[eventName] = actionType;\n}\n\n/**\n * @param {string} type\n * @param {*} CoordinateSystem\n */\nfunction registerCoordinateSystem(type, CoordinateSystem$$1) {\n    CoordinateSystemManager.register(type, CoordinateSystem$$1);\n}\n\n/**\n * Get dimensions of specified coordinate system.\n * @param {string} type\n * @return {Array.<string|Object>}\n */\nfunction getCoordinateSystemDimensions(type) {\n    var coordSysCreator = CoordinateSystemManager.get(type);\n    if (coordSysCreator) {\n        return coordSysCreator.getDimensionsInfo\n                ? coordSysCreator.getDimensionsInfo()\n                : coordSysCreator.dimensions.slice();\n    }\n}\n\n/**\n * Layout is a special stage of visual encoding\n * Most visual encoding like color are common for different chart\n * But each chart has it's own layout algorithm\n *\n * @param {number} [priority=1000]\n * @param {Function} layoutTask\n */\nfunction registerLayout(priority, layoutTask) {\n    normalizeRegister(visualFuncs, priority, layoutTask, PRIORITY_VISUAL_LAYOUT, 'layout');\n}\n\n/**\n * @param {number} [priority=3000]\n * @param {module:echarts/stream/Task} visualTask\n */\nfunction registerVisual(priority, visualTask) {\n    normalizeRegister(visualFuncs, priority, visualTask, PRIORITY_VISUAL_CHART, 'visual');\n}\n\n/**\n * @param {Object|Function} fn: {seriesType, createOnAllSeries, performRawSeries, reset}\n */\nfunction normalizeRegister(targetList, priority, fn, defaultPriority, visualType) {\n    if (isFunction(priority) || isObject(priority)) {\n        fn = priority;\n        priority = defaultPriority;\n    }\n\n    if (__DEV__) {\n        if (isNaN(priority) || priority == null) {\n            throw new Error('Illegal priority');\n        }\n        // Check duplicate\n        each(targetList, function (wrap) {\n            assert(wrap.__raw !== fn);\n        });\n    }\n\n    var stageHandler = Scheduler.wrapStageHandler(fn, visualType);\n\n    stageHandler.__prio = priority;\n    stageHandler.__raw = fn;\n    targetList.push(stageHandler);\n\n    return stageHandler;\n}\n\n/**\n * @param {string} name\n */\nfunction registerLoading(name, loadingFx) {\n    loadingEffects[name] = loadingFx;\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendComponentModel(opts/*, superClass*/) {\n    // var Clazz = ComponentModel;\n    // if (superClass) {\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentModel.getClass(classType.main, classType.sub, true);\n    // }\n    return ComponentModel.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendComponentView(opts/*, superClass*/) {\n    // var Clazz = ComponentView;\n    // if (superClass) {\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentView.getClass(classType.main, classType.sub, true);\n    // }\n    return Component.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendSeriesModel(opts/*, superClass*/) {\n    // var Clazz = SeriesModel;\n    // if (superClass) {\n    //     superClass = 'series.' + superClass.replace('series.', '');\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ComponentModel.getClass(classType.main, classType.sub, true);\n    // }\n    return SeriesModel.extend(opts);\n}\n\n/**\n * @param {Object} opts\n * @param {string} [superClass]\n */\nfunction extendChartView(opts/*, superClass*/) {\n    // var Clazz = ChartView;\n    // if (superClass) {\n    //     superClass = superClass.replace('series.', '');\n    //     var classType = parseClassType(superClass);\n    //     Clazz = ChartView.getClass(classType.main, true);\n    // }\n    return Chart.extend(opts);\n}\n\n/**\n * ZRender need a canvas context to do measureText.\n * But in node environment canvas may be created by node-canvas.\n * So we need to specify how to create a canvas instead of using document.createElement('canvas')\n *\n * Be careful of using it in the browser.\n *\n * @param {Function} creator\n * @example\n *     var Canvas = require('canvas');\n *     var echarts = require('echarts');\n *     echarts.setCanvasCreator(function () {\n *         // Small size is enough.\n *         return new Canvas(32, 32);\n *     });\n */\nfunction setCanvasCreator(creator) {\n    $override('createCanvas', creator);\n}\n\n/**\n * @param {string} mapName\n * @param {Array.<Object>|Object|string} geoJson\n * @param {Object} [specialAreas]\n *\n * @example GeoJSON\n *     $.get('USA.json', function (geoJson) {\n *         echarts.registerMap('USA', geoJson);\n *         // Or\n *         echarts.registerMap('USA', {\n *             geoJson: geoJson,\n *             specialAreas: {}\n *         })\n *     });\n *\n *     $.get('airport.svg', function (svg) {\n *         echarts.registerMap('airport', {\n *             svg: svg\n *         }\n *     });\n *\n *     echarts.registerMap('eu', [\n *         {svg: eu-topographic.svg},\n *         {geoJSON: eu.json}\n *     ])\n */\nfunction registerMap(mapName, geoJson, specialAreas) {\n    mapDataStorage.registerMap(mapName, geoJson, specialAreas);\n}\n\n/**\n * @param {string} mapName\n * @return {Object}\n */\nfunction getMap(mapName) {\n    // For backward compatibility, only return the first one.\n    var records = mapDataStorage.retrieveMap(mapName);\n    return records && records[0] && {\n        geoJson: records[0].geoJSON,\n        specialAreas: records[0].specialAreas\n    };\n}\n\nregisterVisual(PRIORITY_VISUAL_GLOBAL, seriesColor);\nregisterPreprocessor(backwardCompat);\nregisterProcessor(PRIORITY_PROCESSOR_STATISTIC, dataStack);\nregisterLoading('default', loadingDefault);\n\n// Default actions\n\nregisterAction({\n    type: 'highlight',\n    event: 'highlight',\n    update: 'highlight'\n}, noop);\n\nregisterAction({\n    type: 'downplay',\n    event: 'downplay',\n    update: 'downplay'\n}, noop);\n\n// Default theme\nregisterTheme('light', lightTheme);\nregisterTheme('dark', theme);\n\n// For backward compatibility, where the namespace `dataTool` will\n// be mounted on `echarts` is the extension `dataTool` is imported.\nvar dataTool = {};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction defaultKeyGetter(item) {\n    return item;\n}\n\n/**\n * @param {Array} oldArr\n * @param {Array} newArr\n * @param {Function} oldKeyGetter\n * @param {Function} newKeyGetter\n * @param {Object} [context] Can be visited by this.context in callback.\n */\nfunction DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter, context) {\n    this._old = oldArr;\n    this._new = newArr;\n\n    this._oldKeyGetter = oldKeyGetter || defaultKeyGetter;\n    this._newKeyGetter = newKeyGetter || defaultKeyGetter;\n\n    this.context = context;\n}\n\nDataDiffer.prototype = {\n\n    constructor: DataDiffer,\n\n    /**\n     * Callback function when add a data\n     */\n    add: function (func) {\n        this._add = func;\n        return this;\n    },\n\n    /**\n     * Callback function when update a data\n     */\n    update: function (func) {\n        this._update = func;\n        return this;\n    },\n\n    /**\n     * Callback function when remove a data\n     */\n    remove: function (func) {\n        this._remove = func;\n        return this;\n    },\n\n    execute: function () {\n        var oldArr = this._old;\n        var newArr = this._new;\n\n        var oldDataIndexMap = {};\n        var newDataIndexMap = {};\n        var oldDataKeyArr = [];\n        var newDataKeyArr = [];\n        var i;\n\n        initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, '_oldKeyGetter', this);\n        initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter', this);\n\n        // Travel by inverted order to make sure order consistency\n        // when duplicate keys exists (consider newDataIndex.pop() below).\n        // For performance consideration, these code below do not look neat.\n        for (i = 0; i < oldArr.length; i++) {\n            var key = oldDataKeyArr[i];\n            var idx = newDataIndexMap[key];\n\n            // idx can never be empty array here. see 'set null' logic below.\n            if (idx != null) {\n                // Consider there is duplicate key (for example, use dataItem.name as key).\n                // We should make sure every item in newArr and oldArr can be visited.\n                var len = idx.length;\n                if (len) {\n                    len === 1 && (newDataIndexMap[key] = null);\n                    idx = idx.unshift();\n                }\n                else {\n                    newDataIndexMap[key] = null;\n                }\n                this._update && this._update(idx, i);\n            }\n            else {\n                this._remove && this._remove(i);\n            }\n        }\n\n        for (var i = 0; i < newDataKeyArr.length; i++) {\n            var key = newDataKeyArr[i];\n            if (newDataIndexMap.hasOwnProperty(key)) {\n                var idx = newDataIndexMap[key];\n                if (idx == null) {\n                    continue;\n                }\n                // idx can never be empty array here. see 'set null' logic above.\n                if (!idx.length) {\n                    this._add && this._add(idx);\n                }\n                else {\n                    for (var j = 0, len = idx.length; j < len; j++) {\n                        this._add && this._add(idx[j]);\n                    }\n                }\n            }\n        }\n    }\n};\n\nfunction initIndexMap(arr, map, keyArr, keyGetterName, dataDiffer) {\n    for (var i = 0; i < arr.length; i++) {\n        // Add prefix to avoid conflict with Object.prototype.\n        var key = '_ec_' + dataDiffer[keyGetterName](arr[i], i);\n        var existence = map[key];\n        if (existence == null) {\n            keyArr.push(key);\n            map[key] = i;\n        }\n        else {\n            if (!existence.length) {\n                map[key] = existence = [existence];\n            }\n            existence.push(i);\n        }\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar OTHER_DIMENSIONS = createHashMap([\n    'tooltip', 'label', 'itemName', 'itemId', 'seriesName'\n]);\n\nfunction summarizeDimensions(data) {\n    var summary = {};\n    var encode = summary.encode = {};\n    var notExtraCoordDimMap = createHashMap();\n    var defaultedLabel = [];\n    var defaultedTooltip = [];\n\n    each$1(data.dimensions, function (dimName) {\n        var dimItem = data.getDimensionInfo(dimName);\n\n        var coordDim = dimItem.coordDim;\n        if (coordDim) {\n            if (__DEV__) {\n                assert$1(OTHER_DIMENSIONS.get(coordDim) == null);\n            }\n            var coordDimArr = encode[coordDim];\n            if (!encode.hasOwnProperty(coordDim)) {\n                coordDimArr = encode[coordDim] = [];\n            }\n            coordDimArr[dimItem.coordDimIndex] = dimName;\n\n            if (!dimItem.isExtraCoord) {\n                notExtraCoordDimMap.set(coordDim, 1);\n\n                // Use the last coord dim (and label friendly) as default label,\n                // because when dataset is used, it is hard to guess which dimension\n                // can be value dimension. If both show x, y on label is not look good,\n                // and conventionally y axis is focused more.\n                if (mayLabelDimType(dimItem.type)) {\n                    defaultedLabel[0] = dimName;\n                }\n            }\n            if (dimItem.defaultTooltip) {\n                defaultedTooltip.push(dimName);\n            }\n        }\n\n        OTHER_DIMENSIONS.each(function (v, otherDim) {\n            var otherDimArr = encode[otherDim];\n            if (!encode.hasOwnProperty(otherDim)) {\n                otherDimArr = encode[otherDim] = [];\n            }\n\n            var dimIndex = dimItem.otherDims[otherDim];\n            if (dimIndex != null && dimIndex !== false) {\n                otherDimArr[dimIndex] = dimItem.name;\n            }\n        });\n    });\n\n    var dataDimsOnCoord = [];\n    var encodeFirstDimNotExtra = {};\n\n    notExtraCoordDimMap.each(function (v, coordDim) {\n        var dimArr = encode[coordDim];\n        // ??? FIXME extra coord should not be set in dataDimsOnCoord.\n        // But should fix the case that radar axes: simplify the logic\n        // of `completeDimension`, remove `extraPrefix`.\n        encodeFirstDimNotExtra[coordDim] = dimArr[0];\n        // Not necessary to remove duplicate, because a data\n        // dim canot on more than one coordDim.\n        dataDimsOnCoord = dataDimsOnCoord.concat(dimArr);\n    });\n\n    summary.dataDimsOnCoord = dataDimsOnCoord;\n    summary.encodeFirstDimNotExtra = encodeFirstDimNotExtra;\n\n    var encodeLabel = encode.label;\n    // FIXME `encode.label` is not recommanded, because formatter can not be set\n    // in this way. Use label.formatter instead. May be remove this approach someday.\n    if (encodeLabel && encodeLabel.length) {\n        defaultedLabel = encodeLabel.slice();\n    }\n\n    var encodeTooltip = encode.tooltip;\n    if (encodeTooltip && encodeTooltip.length) {\n        defaultedTooltip = encodeTooltip.slice();\n    }\n    else if (!defaultedTooltip.length) {\n        defaultedTooltip = defaultedLabel.slice();\n    }\n\n    encode.defaultedLabel = defaultedLabel;\n    encode.defaultedTooltip = defaultedTooltip;\n\n    return summary;\n}\n\nfunction getDimensionTypeByAxis(axisType) {\n    return axisType === 'category'\n        ? 'ordinal'\n        : axisType === 'time'\n        ? 'time'\n        : 'float';\n}\n\nfunction mayLabelDimType(dimType) {\n    // In most cases, ordinal and time do not suitable for label.\n    // Ordinal info can be displayed on axis. Time is too long.\n    return !(dimType === 'ordinal' || dimType === 'time');\n}\n\n// function findTheLastDimMayLabel(data) {\n//     // Get last value dim\n//     var dimensions = data.dimensions.slice();\n//     var valueType;\n//     var valueDim;\n//     while (dimensions.length && (\n//         valueDim = dimensions.pop(),\n//         valueType = data.getDimensionInfo(valueDim).type,\n//         valueType === 'ordinal' || valueType === 'time'\n//     )) {} // jshint ignore:line\n//     return valueDim;\n// }\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float64Array, Int32Array, Uint32Array, Uint16Array */\n\n/**\n * List for data storage\n * @module echarts/data/List\n */\n\nvar isObject$4 = isObject$1;\n\nvar UNDEFINED = 'undefined';\nvar INDEX_NOT_FOUND = -1;\n\n// Use prefix to avoid index to be the same as otherIdList[idx],\n// which will cause weird udpate animation.\nvar ID_PREFIX = 'e\\0\\0';\n\nvar dataCtors = {\n    'float': typeof Float64Array === UNDEFINED\n        ? Array : Float64Array,\n    'int': typeof Int32Array === UNDEFINED\n        ? Array : Int32Array,\n    // Ordinal data type can be string or int\n    'ordinal': Array,\n    'number': Array,\n    'time': Array\n};\n\n// Caution: MUST not use `new CtorUint32Array(arr, 0, len)`, because the Ctor of array is\n// different from the Ctor of typed array.\nvar CtorUint32Array = typeof Uint32Array === UNDEFINED ? Array : Uint32Array;\nvar CtorInt32Array = typeof Int32Array === UNDEFINED ? Array : Int32Array;\nvar CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array;\n\nfunction getIndicesCtor(list) {\n    // The possible max value in this._indicies is always this._rawCount despite of filtering.\n    return list._rawCount > 65535 ? CtorUint32Array : CtorUint16Array;\n}\n\nfunction cloneChunk(originalChunk) {\n    var Ctor = originalChunk.constructor;\n    // Only shallow clone is enough when Array.\n    return Ctor === Array ? originalChunk.slice() : new Ctor(originalChunk);\n}\n\nvar TRANSFERABLE_PROPERTIES = [\n    'hasItemOption', '_nameList', '_idList', '_invertedIndicesMap',\n    '_rawData', '_chunkSize', '_chunkCount', '_dimValueGetter',\n    '_count', '_rawCount', '_nameDimIdx', '_idDimIdx'\n];\nvar CLONE_PROPERTIES = [\n    '_extent', '_approximateExtent', '_rawExtent'\n];\n\nfunction transferProperties(target, source) {\n    each$1(TRANSFERABLE_PROPERTIES.concat(source.__wrappedMethods || []), function (propName) {\n        if (source.hasOwnProperty(propName)) {\n            target[propName] = source[propName];\n        }\n    });\n\n    target.__wrappedMethods = source.__wrappedMethods;\n\n    each$1(CLONE_PROPERTIES, function (propName) {\n        target[propName] = clone(source[propName]);\n    });\n\n    target._calculationInfo = extend(source._calculationInfo);\n}\n\n\n\n\n\n/**\n * @constructor\n * @alias module:echarts/data/List\n *\n * @param {Array.<string|Object>} dimensions\n *      For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...].\n *      Dimensions should be concrete names like x, y, z, lng, lat, angle, radius\n *      Spetial fields: {\n *          ordinalMeta: <module:echarts/data/OrdinalMeta>\n *          createInvertedIndices: <boolean>\n *      }\n * @param {module:echarts/model/Model} hostModel\n */\nvar List = function (dimensions, hostModel) {\n\n    dimensions = dimensions || ['x', 'y'];\n\n    var dimensionInfos = {};\n    var dimensionNames = [];\n    var invertedIndicesMap = {};\n\n    for (var i = 0; i < dimensions.length; i++) {\n        // Use the original dimensions[i], where other flag props may exists.\n        var dimensionInfo = dimensions[i];\n\n        if (isString(dimensionInfo)) {\n            dimensionInfo = {name: dimensionInfo};\n        }\n\n        var dimensionName = dimensionInfo.name;\n        dimensionInfo.type = dimensionInfo.type || 'float';\n        if (!dimensionInfo.coordDim) {\n            dimensionInfo.coordDim = dimensionName;\n            dimensionInfo.coordDimIndex = 0;\n        }\n\n        dimensionInfo.otherDims = dimensionInfo.otherDims || {};\n        dimensionNames.push(dimensionName);\n        dimensionInfos[dimensionName] = dimensionInfo;\n\n        dimensionInfo.index = i;\n\n        if (dimensionInfo.createInvertedIndices) {\n            invertedIndicesMap[dimensionName] = [];\n        }\n    }\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    this.dimensions = dimensionNames;\n\n    /**\n     * Infomation of each data dimension, like data type.\n     * @type {Object}\n     */\n    this._dimensionInfos = dimensionInfos;\n\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.hostModel = hostModel;\n\n    /**\n     * @type {module:echarts/model/Model}\n     */\n    this.dataType;\n\n    /**\n     * Indices stores the indices of data subset after filtered.\n     * This data subset will be used in chart.\n     * @type {Array.<number>}\n     * @readOnly\n     */\n    this._indices = null;\n\n    this._count = 0;\n    this._rawCount = 0;\n\n    /**\n     * Data storage\n     * @type {Object.<key, Array.<TypedArray|Array>>}\n     * @private\n     */\n    this._storage = {};\n\n    /**\n     * @type {Array.<string>}\n     */\n    this._nameList = [];\n    /**\n     * @type {Array.<string>}\n     */\n    this._idList = [];\n\n    /**\n     * Models of data option is stored sparse for optimizing memory cost\n     * @type {Array.<module:echarts/model/Model>}\n     * @private\n     */\n    this._optionModels = [];\n\n    /**\n     * Global visual properties after visual coding\n     * @type {Object}\n     * @private\n     */\n    this._visual = {};\n\n    /**\n     * Globel layout properties.\n     * @type {Object}\n     * @private\n     */\n    this._layout = {};\n\n    /**\n     * Item visual properties after visual coding\n     * @type {Array.<Object>}\n     * @private\n     */\n    this._itemVisuals = [];\n\n    /**\n     * Key: visual type, Value: boolean\n     * @type {Object}\n     * @readOnly\n     */\n    this.hasItemVisual = {};\n\n    /**\n     * Item layout properties after layout\n     * @type {Array.<Object>}\n     * @private\n     */\n    this._itemLayouts = [];\n\n    /**\n     * Graphic elemnents\n     * @type {Array.<module:zrender/Element>}\n     * @private\n     */\n    this._graphicEls = [];\n\n    /**\n     * Max size of each chunk.\n     * @type {number}\n     * @private\n     */\n    this._chunkSize = 1e5;\n\n    /**\n     * @type {number}\n     * @private\n     */\n    this._chunkCount = 0;\n\n    /**\n     * @type {Array.<Array|Object>}\n     * @private\n     */\n    this._rawData;\n\n    /**\n     * Raw extent will not be cloned, but only transfered.\n     * It will not be calculated util needed.\n     * key: dim,\n     * value: {end: number, extent: Array.<number>}\n     * @type {Object}\n     * @private\n     */\n    this._rawExtent = {};\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._extent = {};\n\n    /**\n     * key: dim\n     * value: extent\n     * @type {Object}\n     * @private\n     */\n    this._approximateExtent = {};\n\n    /**\n     * Cache summary info for fast visit. See \"dimensionHelper\".\n     * @type {Object}\n     * @private\n     */\n    this._dimensionsSummary = summarizeDimensions(this);\n\n    /**\n     * @type {Object.<Array|TypedArray>}\n     * @private\n     */\n    this._invertedIndicesMap = invertedIndicesMap;\n\n    /**\n     * @type {Object}\n     * @private\n     */\n    this._calculationInfo = {};\n};\n\nvar listProto = List.prototype;\n\nlistProto.type = 'list';\n\n/**\n * If each data item has it's own option\n * @type {boolean}\n */\nlistProto.hasItemOption = true;\n\n/**\n * Get dimension name\n * @param {string|number} dim\n *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius\n *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'\n * @return {string} Concrete dim name.\n */\nlistProto.getDimension = function (dim) {\n    if (!isNaN(dim)) {\n        dim = this.dimensions[dim] || dim;\n    }\n    return dim;\n};\n\n/**\n * Get type and calculation info of particular dimension\n * @param {string|number} dim\n *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius\n *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'\n */\nlistProto.getDimensionInfo = function (dim) {\n    // Do not clone, because there may be categories in dimInfo.\n    return this._dimensionInfos[this.getDimension(dim)];\n};\n\n/**\n * @return {Array.<string>} concrete dimension name list on coord.\n */\nlistProto.getDimensionsOnCoord = function () {\n    return this._dimensionsSummary.dataDimsOnCoord.slice();\n};\n\n/**\n * @param {string} coordDim\n * @param {number} [idx] A coordDim may map to more than one data dim.\n *        If idx is `true`, return a array of all mapped dims.\n *        If idx is not specified, return the first dim not extra.\n * @return {string|Array.<string>} concrete data dim.\n *        If idx is number, and not found, return null/undefined.\n *        If idx is `true`, and not found, return empty array (always return array).\n */\nlistProto.mapDimension = function (coordDim, idx) {\n    var dimensionsSummary = this._dimensionsSummary;\n\n    if (idx == null) {\n        return dimensionsSummary.encodeFirstDimNotExtra[coordDim];\n    }\n\n    var dims = dimensionsSummary.encode[coordDim];\n    return idx === true\n        // always return array if idx is `true`\n        ? (dims || []).slice()\n        : (dims && dims[idx]);\n};\n\n/**\n * Initialize from data\n * @param {Array.<Object|number|Array>} data source or data or data provider.\n * @param {Array.<string>} [nameLIst] The name of a datum is used on data diff and\n *        defualt label/tooltip.\n *        A name can be specified in encode.itemName,\n *        or dataItem.name (only for series option data),\n *        or provided in nameList from outside.\n * @param {Function} [dimValueGetter] (dataItem, dimName, dataIndex, dimIndex) => number\n */\nlistProto.initData = function (data, nameList, dimValueGetter) {\n\n    var notProvider = Source.isInstance(data) || isArrayLike(data);\n    if (notProvider) {\n        data = new DefaultDataProvider(data, this.dimensions.length);\n    }\n\n    if (__DEV__) {\n        if (!notProvider && (typeof data.getItem !== 'function' || typeof data.count !== 'function')) {\n            throw new Error('Inavlid data provider.');\n        }\n    }\n\n    this._rawData = data;\n\n    // Clear\n    this._storage = {};\n    this._indices = null;\n\n    this._nameList = nameList || [];\n\n    this._idList = [];\n\n    this._nameRepeatCount = {};\n\n    if (!dimValueGetter) {\n        this.hasItemOption = false;\n    }\n\n    /**\n     * @readOnly\n     */\n    this.defaultDimValueGetter = defaultDimValueGetters[\n        this._rawData.getSource().sourceFormat\n    ];\n    // Default dim value getter\n    this._dimValueGetter = dimValueGetter = dimValueGetter\n        || this.defaultDimValueGetter;\n    this._dimValueGetterArrayRows = defaultDimValueGetters.arrayRows;\n\n    // Reset raw extent.\n    this._rawExtent = {};\n\n    this._initDataFromProvider(0, data.count());\n\n    // If data has no item option.\n    if (data.pure) {\n        this.hasItemOption = false;\n    }\n};\n\nlistProto.getProvider = function () {\n    return this._rawData;\n};\n\n/**\n * Caution: Can be only called on raw data (before `this._indices` created).\n */\nlistProto.appendData = function (data) {\n    if (__DEV__) {\n        assert$1(!this._indices, 'appendData can only be called on raw data.');\n    }\n\n    var rawData = this._rawData;\n    var start = this.count();\n    rawData.appendData(data);\n    var end = rawData.count();\n    if (!rawData.persistent) {\n        end += start;\n    }\n    this._initDataFromProvider(start, end);\n};\n\n/**\n * Caution: Can be only called on raw data (before `this._indices` created).\n * This method does not modify `rawData` (`dataProvider`), but only\n * add values to storage.\n *\n * The final count will be increased by `Math.max(values.length, names.length)`.\n *\n * @param {Array.<Array.<*>>} values That is the SourceType: 'arrayRows', like\n *        [\n *            [12, 33, 44],\n *            [NaN, 43, 1],\n *            ['-', 'asdf', 0]\n *        ]\n *        Each item is exaclty cooresponding to a dimension.\n * @param {Array.<string>} [names]\n */\nlistProto.appendValues = function (values, names) {\n    var chunkSize = this._chunkSize;\n    var storage = this._storage;\n    var dimensions = this.dimensions;\n    var dimLen = dimensions.length;\n    var rawExtent = this._rawExtent;\n\n    var start = this.count();\n    var end = start + Math.max(values.length, names ? names.length : 0);\n    var originalChunkCount = this._chunkCount;\n\n    for (var i = 0; i < dimLen; i++) {\n        var dim = dimensions[i];\n        if (!rawExtent[dim]) {\n            rawExtent[dim] = getInitialExtent();\n        }\n        if (!storage[dim]) {\n            storage[dim] = [];\n        }\n        prepareChunks(storage, this._dimensionInfos[dim], chunkSize, originalChunkCount, end);\n        this._chunkCount = storage[dim].length;\n    }\n\n    var emptyDataItem = new Array(dimLen);\n    for (var idx = start; idx < end; idx++) {\n        var sourceIdx = idx - start;\n        var chunkIndex = Math.floor(idx / chunkSize);\n        var chunkOffset = idx % chunkSize;\n\n        // Store the data by dimensions\n        for (var k = 0; k < dimLen; k++) {\n            var dim = dimensions[k];\n            var val = this._dimValueGetterArrayRows(\n                values[sourceIdx] || emptyDataItem, dim, sourceIdx, k\n            );\n            storage[dim][chunkIndex][chunkOffset] = val;\n\n            var dimRawExtent = rawExtent[dim];\n            val < dimRawExtent[0] && (dimRawExtent[0] = val);\n            val > dimRawExtent[1] && (dimRawExtent[1] = val);\n        }\n\n        if (names) {\n            this._nameList[idx] = names[sourceIdx];\n        }\n    }\n\n    this._rawCount = this._count = end;\n\n    // Reset data extent\n    this._extent = {};\n\n    prepareInvertedIndex(this);\n};\n\nlistProto._initDataFromProvider = function (start, end) {\n    // Optimize.\n    if (start >= end) {\n        return;\n    }\n\n    var chunkSize = this._chunkSize;\n    var rawData = this._rawData;\n    var storage = this._storage;\n    var dimensions = this.dimensions;\n    var dimLen = dimensions.length;\n    var dimensionInfoMap = this._dimensionInfos;\n    var nameList = this._nameList;\n    var idList = this._idList;\n    var rawExtent = this._rawExtent;\n    var nameRepeatCount = this._nameRepeatCount = {};\n    var nameDimIdx;\n\n    var originalChunkCount = this._chunkCount;\n    for (var i = 0; i < dimLen; i++) {\n        var dim = dimensions[i];\n        if (!rawExtent[dim]) {\n            rawExtent[dim] = getInitialExtent();\n        }\n\n        var dimInfo = dimensionInfoMap[dim];\n        if (dimInfo.otherDims.itemName === 0) {\n            nameDimIdx = this._nameDimIdx = i;\n        }\n        if (dimInfo.otherDims.itemId === 0) {\n            this._idDimIdx = i;\n        }\n\n        if (!storage[dim]) {\n            storage[dim] = [];\n        }\n\n        prepareChunks(storage, dimInfo, chunkSize, originalChunkCount, end);\n\n        this._chunkCount = storage[dim].length;\n    }\n\n    var dataItem = new Array(dimLen);\n    for (var idx = start; idx < end; idx++) {\n        // NOTICE: Try not to write things into dataItem\n        dataItem = rawData.getItem(idx, dataItem);\n        // Each data item is value\n        // [1, 2]\n        // 2\n        // Bar chart, line chart which uses category axis\n        // only gives the 'y' value. 'x' value is the indices of category\n        // Use a tempValue to normalize the value to be a (x, y) value\n        var chunkIndex = Math.floor(idx / chunkSize);\n        var chunkOffset = idx % chunkSize;\n\n        // Store the data by dimensions\n        for (var k = 0; k < dimLen; k++) {\n            var dim = dimensions[k];\n            var dimStorage = storage[dim][chunkIndex];\n            // PENDING NULL is empty or zero\n            var val = this._dimValueGetter(dataItem, dim, idx, k);\n            dimStorage[chunkOffset] = val;\n\n            var dimRawExtent = rawExtent[dim];\n            val < dimRawExtent[0] && (dimRawExtent[0] = val);\n            val > dimRawExtent[1] && (dimRawExtent[1] = val);\n        }\n\n        // ??? FIXME not check by pure but sourceFormat?\n        // TODO refactor these logic.\n        if (!rawData.pure) {\n            var name = nameList[idx];\n\n            if (dataItem && name == null) {\n                // If dataItem is {name: ...}, it has highest priority.\n                // That is appropriate for many common cases.\n                if (dataItem.name != null) {\n                    // There is no other place to persistent dataItem.name,\n                    // so save it to nameList.\n                    nameList[idx] = name = dataItem.name;\n                }\n                else if (nameDimIdx != null) {\n                    var nameDim = dimensions[nameDimIdx];\n                    var nameDimChunk = storage[nameDim][chunkIndex];\n                    if (nameDimChunk) {\n                        name = nameDimChunk[chunkOffset];\n                        var ordinalMeta = dimensionInfoMap[nameDim].ordinalMeta;\n                        if (ordinalMeta && ordinalMeta.categories.length) {\n                            name = ordinalMeta.categories[name];\n                        }\n                    }\n                }\n            }\n\n            // Try using the id in option\n            // id or name is used on dynamical data, mapping old and new items.\n            var id = dataItem == null ? null : dataItem.id;\n\n            if (id == null && name != null) {\n                // Use name as id and add counter to avoid same name\n                nameRepeatCount[name] = nameRepeatCount[name] || 0;\n                id = name;\n                if (nameRepeatCount[name] > 0) {\n                    id += '__ec__' + nameRepeatCount[name];\n                }\n                nameRepeatCount[name]++;\n            }\n            id != null && (idList[idx] = id);\n        }\n    }\n\n    if (!rawData.persistent && rawData.clean) {\n        // Clean unused data if data source is typed array.\n        rawData.clean();\n    }\n\n    this._rawCount = this._count = end;\n\n    // Reset data extent\n    this._extent = {};\n\n    prepareInvertedIndex(this);\n};\n\nfunction prepareChunks(storage, dimInfo, chunkSize, chunkCount, end) {\n    var DataCtor = dataCtors[dimInfo.type];\n    var lastChunkIndex = chunkCount - 1;\n    var dim = dimInfo.name;\n    var resizeChunkArray = storage[dim][lastChunkIndex];\n    if (resizeChunkArray && resizeChunkArray.length < chunkSize) {\n        var newStore = new DataCtor(Math.min(end - lastChunkIndex * chunkSize, chunkSize));\n        // The cost of the copy is probably inconsiderable\n        // within the initial chunkSize.\n        for (var j = 0; j < resizeChunkArray.length; j++) {\n            newStore[j] = resizeChunkArray[j];\n        }\n        storage[dim][lastChunkIndex] = newStore;\n    }\n\n    // Create new chunks.\n    for (var k = chunkCount * chunkSize; k < end; k += chunkSize) {\n        storage[dim].push(new DataCtor(Math.min(end - k, chunkSize)));\n    }\n}\n\nfunction prepareInvertedIndex(list) {\n    var invertedIndicesMap = list._invertedIndicesMap;\n    each$1(invertedIndicesMap, function (invertedIndices, dim) {\n        var dimInfo = list._dimensionInfos[dim];\n\n        // Currently, only dimensions that has ordinalMeta can create inverted indices.\n        var ordinalMeta = dimInfo.ordinalMeta;\n        if (ordinalMeta) {\n            invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array(\n                ordinalMeta.categories.length\n            );\n            // The default value of TypedArray is 0. To avoid miss\n            // mapping to 0, we should set it as INDEX_NOT_FOUND.\n            for (var i = 0; i < invertedIndices.length; i++) {\n                invertedIndices[i] = INDEX_NOT_FOUND;\n            }\n            for (var i = 0; i < list._count; i++) {\n                // Only support the case that all values are distinct.\n                invertedIndices[list.get(dim, i)] = i;\n            }\n        }\n    });\n}\n\nfunction getRawValueFromStore(list, dimIndex, rawIndex) {\n    var val;\n    if (dimIndex != null) {\n        var chunkSize = list._chunkSize;\n        var chunkIndex = Math.floor(rawIndex / chunkSize);\n        var chunkOffset = rawIndex % chunkSize;\n        var dim = list.dimensions[dimIndex];\n        var chunk = list._storage[dim][chunkIndex];\n        if (chunk) {\n            val = chunk[chunkOffset];\n            var ordinalMeta = list._dimensionInfos[dim].ordinalMeta;\n            if (ordinalMeta && ordinalMeta.categories.length) {\n                val = ordinalMeta.categories[val];\n            }\n        }\n    }\n    return val;\n}\n\n/**\n * @return {number}\n */\nlistProto.count = function () {\n    return this._count;\n};\n\nlistProto.getIndices = function () {\n    var newIndices;\n\n    var indices = this._indices;\n    if (indices) {\n        var Ctor = indices.constructor;\n        var thisCount = this._count;\n        // `new Array(a, b, c)` is different from `new Uint32Array(a, b, c)`.\n        if (Ctor === Array) {\n            newIndices = new Ctor(thisCount);\n            for (var i = 0; i < thisCount; i++) {\n                newIndices[i] = indices[i];\n            }\n        }\n        else {\n            newIndices = new Ctor(indices.buffer, 0, thisCount);\n        }\n    }\n    else {\n        var Ctor = getIndicesCtor(this);\n        var newIndices = new Ctor(this.count());\n        for (var i = 0; i < newIndices.length; i++) {\n            newIndices[i] = i;\n        }\n    }\n\n    return newIndices;\n};\n\n/**\n * Get value. Return NaN if idx is out of range.\n * @param {string} dim Dim must be concrete name.\n * @param {number} idx\n * @param {boolean} stack\n * @return {number}\n */\nlistProto.get = function (dim, idx /*, stack */) {\n    if (!(idx >= 0 && idx < this._count)) {\n        return NaN;\n    }\n    var storage = this._storage;\n    if (!storage[dim]) {\n        // TODO Warn ?\n        return NaN;\n    }\n\n    idx = this.getRawIndex(idx);\n\n    var chunkIndex = Math.floor(idx / this._chunkSize);\n    var chunkOffset = idx % this._chunkSize;\n\n    var chunkStore = storage[dim][chunkIndex];\n    var value = chunkStore[chunkOffset];\n    // FIXME ordinal data type is not stackable\n    // if (stack) {\n    //     var dimensionInfo = this._dimensionInfos[dim];\n    //     if (dimensionInfo && dimensionInfo.stackable) {\n    //         var stackedOn = this.stackedOn;\n    //         while (stackedOn) {\n    //             // Get no stacked data of stacked on\n    //             var stackedValue = stackedOn.get(dim, idx);\n    //             // Considering positive stack, negative stack and empty data\n    //             if ((value >= 0 && stackedValue > 0)  // Positive stack\n    //                 || (value <= 0 && stackedValue < 0) // Negative stack\n    //             ) {\n    //                 value += stackedValue;\n    //             }\n    //             stackedOn = stackedOn.stackedOn;\n    //         }\n    //     }\n    // }\n\n    return value;\n};\n\n/**\n * @param {string} dim concrete dim\n * @param {number} rawIndex\n * @return {number|string}\n */\nlistProto.getByRawIndex = function (dim, rawIdx) {\n    if (!(rawIdx >= 0 && rawIdx < this._rawCount)) {\n        return NaN;\n    }\n    var dimStore = this._storage[dim];\n    if (!dimStore) {\n        // TODO Warn ?\n        return NaN;\n    }\n\n    var chunkIndex = Math.floor(rawIdx / this._chunkSize);\n    var chunkOffset = rawIdx % this._chunkSize;\n    var chunkStore = dimStore[chunkIndex];\n    return chunkStore[chunkOffset];\n};\n\n/**\n * FIXME Use `get` on chrome maybe slow(in filterSelf and selectRange).\n * Hack a much simpler _getFast\n * @private\n */\nlistProto._getFast = function (dim, rawIdx) {\n    var chunkIndex = Math.floor(rawIdx / this._chunkSize);\n    var chunkOffset = rawIdx % this._chunkSize;\n    var chunkStore = this._storage[dim][chunkIndex];\n    return chunkStore[chunkOffset];\n};\n\n/**\n * Get value for multi dimensions.\n * @param {Array.<string>} [dimensions] If ignored, using all dimensions.\n * @param {number} idx\n * @return {number}\n */\nlistProto.getValues = function (dimensions, idx /*, stack */) {\n    var values = [];\n\n    if (!isArray(dimensions)) {\n        // stack = idx;\n        idx = dimensions;\n        dimensions = this.dimensions;\n    }\n\n    for (var i = 0, len = dimensions.length; i < len; i++) {\n        values.push(this.get(dimensions[i], idx /*, stack */));\n    }\n\n    return values;\n};\n\n/**\n * If value is NaN. Inlcuding '-'\n * Only check the coord dimensions.\n * @param {string} dim\n * @param {number} idx\n * @return {number}\n */\nlistProto.hasValue = function (idx) {\n    var dataDimsOnCoord = this._dimensionsSummary.dataDimsOnCoord;\n    var dimensionInfos = this._dimensionInfos;\n    for (var i = 0, len = dataDimsOnCoord.length; i < len; i++) {\n        if (\n            // Ordinal type can be string or number\n            dimensionInfos[dataDimsOnCoord[i]].type !== 'ordinal'\n            // FIXME check ordinal when using index?\n            && isNaN(this.get(dataDimsOnCoord[i], idx))\n        ) {\n            return false;\n        }\n    }\n    return true;\n};\n\n/**\n * Get extent of data in one dimension\n * @param {string} dim\n * @param {boolean} stack\n */\nlistProto.getDataExtent = function (dim /*, stack */) {\n    // Make sure use concrete dim as cache name.\n    dim = this.getDimension(dim);\n    var dimData = this._storage[dim];\n    var initialExtent = getInitialExtent();\n\n    // stack = !!((stack || false) && this.getCalculationInfo(dim));\n\n    if (!dimData) {\n        return initialExtent;\n    }\n\n    // Make more strict checkings to ensure hitting cache.\n    var currEnd = this.count();\n    // var cacheName = [dim, !!stack].join('_');\n    // var cacheName = dim;\n\n    // Consider the most cases when using data zoom, `getDataExtent`\n    // happened before filtering. We cache raw extent, which is not\n    // necessary to be cleared and recalculated when restore data.\n    var useRaw = !this._indices; // && !stack;\n    var dimExtent;\n\n    if (useRaw) {\n        return this._rawExtent[dim].slice();\n    }\n    dimExtent = this._extent[dim];\n    if (dimExtent) {\n        return dimExtent.slice();\n    }\n    dimExtent = initialExtent;\n\n    var min = dimExtent[0];\n    var max = dimExtent[1];\n\n    for (var i = 0; i < currEnd; i++) {\n        // var value = stack ? this.get(dim, i, true) : this._getFast(dim, this.getRawIndex(i));\n        var value = this._getFast(dim, this.getRawIndex(i));\n        value < min && (min = value);\n        value > max && (max = value);\n    }\n\n    dimExtent = [min, max];\n\n    this._extent[dim] = dimExtent;\n\n    return dimExtent;\n};\n\n/**\n * Optimize for the scenario that data is filtered by a given extent.\n * Consider that if data amount is more than hundreds of thousand,\n * extent calculation will cost more than 10ms and the cache will\n * be erased because of the filtering.\n */\nlistProto.getApproximateExtent = function (dim /*, stack */) {\n    dim = this.getDimension(dim);\n    return this._approximateExtent[dim] || this.getDataExtent(dim /*, stack */);\n};\n\nlistProto.setApproximateExtent = function (extent, dim /*, stack */) {\n    dim = this.getDimension(dim);\n    this._approximateExtent[dim] = extent.slice();\n};\n\n/**\n * @param {string} key\n * @return {*}\n */\nlistProto.getCalculationInfo = function (key) {\n    return this._calculationInfo[key];\n};\n\n/**\n * @param {string|Object} key or k-v object\n * @param {*} [value]\n */\nlistProto.setCalculationInfo = function (key, value) {\n    isObject$4(key)\n        ? extend(this._calculationInfo, key)\n        : (this._calculationInfo[key] = value);\n};\n\n/**\n * Get sum of data in one dimension\n * @param {string} dim\n */\nlistProto.getSum = function (dim /*, stack */) {\n    var dimData = this._storage[dim];\n    var sum = 0;\n    if (dimData) {\n        for (var i = 0, len = this.count(); i < len; i++) {\n            var value = this.get(dim, i /*, stack */);\n            if (!isNaN(value)) {\n                sum += value;\n            }\n        }\n    }\n    return sum;\n};\n\n/**\n * Get median of data in one dimension\n * @param {string} dim\n */\nlistProto.getMedian = function (dim /*, stack */) {\n    var dimDataArray = [];\n    // map all data of one dimension\n    this.each(dim, function (val, idx) {\n        if (!isNaN(val)) {\n            dimDataArray.push(val);\n        }\n    });\n\n    // TODO\n    // Use quick select?\n\n    // immutability & sort\n    var sortedDimDataArray = [].concat(dimDataArray).sort(function (a, b) {\n        return a - b;\n    });\n    var len = this.count();\n    // calculate median\n    return len === 0\n        ? 0\n        : len % 2 === 1\n        ? sortedDimDataArray[(len - 1) / 2]\n        : (sortedDimDataArray[len / 2] + sortedDimDataArray[len / 2 - 1]) / 2;\n};\n\n// /**\n//  * Retreive the index with given value\n//  * @param {string} dim Concrete dimension.\n//  * @param {number} value\n//  * @return {number}\n//  */\n// Currently incorrect: should return dataIndex but not rawIndex.\n// Do not fix it until this method is to be used somewhere.\n// FIXME Precision of float value\n// listProto.indexOf = function (dim, value) {\n//     var storage = this._storage;\n//     var dimData = storage[dim];\n//     var chunkSize = this._chunkSize;\n//     if (dimData) {\n//         for (var i = 0, len = this.count(); i < len; i++) {\n//             var chunkIndex = Math.floor(i / chunkSize);\n//             var chunkOffset = i % chunkSize;\n//             if (dimData[chunkIndex][chunkOffset] === value) {\n//                 return i;\n//             }\n//         }\n//     }\n//     return -1;\n// };\n\n/**\n * Only support the dimension which inverted index created.\n * Do not support other cases until required.\n * @param {string} concrete dim\n * @param {number|string} value\n * @return {number} rawIndex\n */\nlistProto.rawIndexOf = function (dim, value) {\n    var invertedIndices = dim && this._invertedIndicesMap[dim];\n    if (__DEV__) {\n        if (!invertedIndices) {\n            throw new Error('Do not supported yet');\n        }\n    }\n    var rawIndex = invertedIndices[value];\n    if (rawIndex == null || isNaN(rawIndex)) {\n        return INDEX_NOT_FOUND;\n    }\n    return rawIndex;\n};\n\n/**\n * Retreive the index with given name\n * @param {number} idx\n * @param {number} name\n * @return {number}\n */\nlistProto.indexOfName = function (name) {\n    for (var i = 0, len = this.count(); i < len; i++) {\n        if (this.getName(i) === name) {\n            return i;\n        }\n    }\n\n    return -1;\n};\n\n/**\n * Retreive the index with given raw data index\n * @param {number} idx\n * @param {number} name\n * @return {number}\n */\nlistProto.indexOfRawIndex = function (rawIndex) {\n    if (!this._indices) {\n        return rawIndex;\n    }\n\n    if (rawIndex >= this._rawCount || rawIndex < 0) {\n        return -1;\n    }\n\n    // Indices are ascending\n    var indices = this._indices;\n\n    // If rawIndex === dataIndex\n    var rawDataIndex = indices[rawIndex];\n    if (rawDataIndex != null && rawDataIndex < this._count && rawDataIndex === rawIndex) {\n        return rawIndex;\n    }\n\n    var left = 0;\n    var right = this._count - 1;\n    while (left <= right) {\n        var mid = (left + right) / 2 | 0;\n        if (indices[mid] < rawIndex) {\n            left = mid + 1;\n        }\n        else if (indices[mid] > rawIndex) {\n            right = mid - 1;\n        }\n        else {\n            return mid;\n        }\n    }\n    return -1;\n};\n\n/**\n * Retreive the index of nearest value\n * @param {string} dim\n * @param {number} value\n * @param {number} [maxDistance=Infinity]\n * @return {Array.<number>} Considere multiple points has the same value.\n */\nlistProto.indicesOfNearest = function (dim, value, maxDistance) {\n    var storage = this._storage;\n    var dimData = storage[dim];\n    var nearestIndices = [];\n\n    if (!dimData) {\n        return nearestIndices;\n    }\n\n    if (maxDistance == null) {\n        maxDistance = Infinity;\n    }\n\n    var minDist = Number.MAX_VALUE;\n    var minDiff = -1;\n    for (var i = 0, len = this.count(); i < len; i++) {\n        var diff = value - this.get(dim, i /*, stack */);\n        var dist = Math.abs(diff);\n        if (diff <= maxDistance && dist <= minDist) {\n            // For the case of two data are same on xAxis, which has sequence data.\n            // Show the nearest index\n            // https://github.com/ecomfe/echarts/issues/2869\n            if (dist < minDist || (diff >= 0 && minDiff < 0)) {\n                minDist = dist;\n                minDiff = diff;\n                nearestIndices.length = 0;\n            }\n            nearestIndices.push(i);\n        }\n    }\n    return nearestIndices;\n};\n\n/**\n * Get raw data index\n * @param {number} idx\n * @return {number}\n */\nlistProto.getRawIndex = getRawIndexWithoutIndices;\n\nfunction getRawIndexWithoutIndices(idx) {\n    return idx;\n}\n\nfunction getRawIndexWithIndices(idx) {\n    if (idx < this._count && idx >= 0) {\n        return this._indices[idx];\n    }\n    return -1;\n}\n\n/**\n * Get raw data item\n * @param {number} idx\n * @return {number}\n */\nlistProto.getRawDataItem = function (idx) {\n    if (!this._rawData.persistent) {\n        var val = [];\n        for (var i = 0; i < this.dimensions.length; i++) {\n            var dim = this.dimensions[i];\n            val.push(this.get(dim, idx));\n        }\n        return val;\n    }\n    else {\n        return this._rawData.getItem(this.getRawIndex(idx));\n    }\n};\n\n/**\n * @param {number} idx\n * @param {boolean} [notDefaultIdx=false]\n * @return {string}\n */\nlistProto.getName = function (idx) {\n    var rawIndex = this.getRawIndex(idx);\n    return this._nameList[rawIndex]\n        || getRawValueFromStore(this, this._nameDimIdx, rawIndex)\n        || '';\n};\n\n/**\n * @param {number} idx\n * @param {boolean} [notDefaultIdx=false]\n * @return {string}\n */\nlistProto.getId = function (idx) {\n    return getId(this, this.getRawIndex(idx));\n};\n\nfunction getId(list, rawIndex) {\n    var id = list._idList[rawIndex];\n    if (id == null) {\n        id = getRawValueFromStore(list, list._idDimIdx, rawIndex);\n    }\n    if (id == null) {\n        // FIXME Check the usage in graph, should not use prefix.\n        id = ID_PREFIX + rawIndex;\n    }\n    return id;\n}\n\nfunction normalizeDimensions(dimensions) {\n    if (!isArray(dimensions)) {\n        dimensions = [dimensions];\n    }\n    return dimensions;\n}\n\nfunction validateDimensions(list, dims) {\n    for (var i = 0; i < dims.length; i++) {\n        // stroage may be empty when no data, so use\n        // dimensionInfos to check.\n        if (!list._dimensionInfos[dims[i]]) {\n            console.error('Unkown dimension ' + dims[i]);\n        }\n    }\n}\n\n/**\n * Data iteration\n * @param {string|Array.<string>}\n * @param {Function} cb\n * @param {*} [context=this]\n *\n * @example\n *  list.each('x', function (x, idx) {});\n *  list.each(['x', 'y'], function (x, y, idx) {});\n *  list.each(function (idx) {})\n */\nlistProto.each = function (dims, cb, context, contextCompat) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    if (typeof dims === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dims;\n        dims = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dims = map(normalizeDimensions(dims), this.getDimension, this);\n\n    if (__DEV__) {\n        validateDimensions(this, dims);\n    }\n\n    var dimSize = dims.length;\n\n    for (var i = 0; i < this.count(); i++) {\n        // Simple optimization\n        switch (dimSize) {\n            case 0:\n                cb.call(context, i);\n                break;\n            case 1:\n                cb.call(context, this.get(dims[0], i), i);\n                break;\n            case 2:\n                cb.call(context, this.get(dims[0], i), this.get(dims[1], i), i);\n                break;\n            default:\n                var k = 0;\n                var value = [];\n                for (; k < dimSize; k++) {\n                    value[k] = this.get(dims[k], i);\n                }\n                // Index\n                value[k] = i;\n                cb.apply(context, value);\n        }\n    }\n};\n\n/**\n * Data filter\n * @param {string|Array.<string>}\n * @param {Function} cb\n * @param {*} [context=this]\n */\nlistProto.filterSelf = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    if (typeof dimensions === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dimensions;\n        dimensions = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dimensions = map(\n        normalizeDimensions(dimensions), this.getDimension, this\n    );\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n\n    var count = this.count();\n    var Ctor = getIndicesCtor(this);\n    var newIndices = new Ctor(count);\n    var value = [];\n    var dimSize = dimensions.length;\n\n    var offset = 0;\n    var dim0 = dimensions[0];\n\n    for (var i = 0; i < count; i++) {\n        var keep;\n        var rawIdx = this.getRawIndex(i);\n        // Simple optimization\n        if (dimSize === 0) {\n            keep = cb.call(context, i);\n        }\n        else if (dimSize === 1) {\n            var val = this._getFast(dim0, rawIdx);\n            keep = cb.call(context, val, i);\n        }\n        else {\n            for (var k = 0; k < dimSize; k++) {\n                value[k] = this._getFast(dim0, rawIdx);\n            }\n            value[k] = i;\n            keep = cb.apply(context, value);\n        }\n        if (keep) {\n            newIndices[offset++] = rawIdx;\n        }\n    }\n\n    // Set indices after filtered.\n    if (offset < count) {\n        this._indices = newIndices;\n    }\n    this._count = offset;\n    // Reset data extent\n    this._extent = {};\n\n    this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return this;\n};\n\n/**\n * Select data in range. (For optimization of filter)\n * (Manually inline code, support 5 million data filtering in data zoom.)\n */\nlistProto.selectRange = function (range) {\n    'use strict';\n\n    if (!this._count) {\n        return;\n    }\n\n    var dimensions = [];\n    for (var dim in range) {\n        if (range.hasOwnProperty(dim)) {\n            dimensions.push(dim);\n        }\n    }\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n    var dimSize = dimensions.length;\n    if (!dimSize) {\n        return;\n    }\n\n    var originalCount = this.count();\n    var Ctor = getIndicesCtor(this);\n    var newIndices = new Ctor(originalCount);\n\n    var offset = 0;\n    var dim0 = dimensions[0];\n\n    var min = range[dim0][0];\n    var max = range[dim0][1];\n\n    var quickFinished = false;\n    if (!this._indices) {\n        // Extreme optimization for common case. About 2x faster in chrome.\n        var idx = 0;\n        if (dimSize === 1) {\n            var dimStorage = this._storage[dimensions[0]];\n            for (var k = 0; k < this._chunkCount; k++) {\n                var chunkStorage = dimStorage[k];\n                var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);\n                for (var i = 0; i < len; i++) {\n                    var val = chunkStorage[i];\n                    // NaN will not be filtered. Consider the case, in line chart, empty\n                    // value indicates the line should be broken. But for the case like\n                    // scatter plot, a data item with empty value will not be rendered,\n                    // but the axis extent may be effected if some other dim of the data\n                    // item has value. Fortunately it is not a significant negative effect.\n                    if (\n                        (val >= min && val <= max) || isNaN(val)\n                    ) {\n                        newIndices[offset++] = idx;\n                    }\n                    idx++;\n                }\n            }\n            quickFinished = true;\n        }\n        else if (dimSize === 2) {\n            var dimStorage = this._storage[dim0];\n            var dimStorage2 = this._storage[dimensions[1]];\n            var min2 = range[dimensions[1]][0];\n            var max2 = range[dimensions[1]][1];\n            for (var k = 0; k < this._chunkCount; k++) {\n                var chunkStorage = dimStorage[k];\n                var chunkStorage2 = dimStorage2[k];\n                var len = Math.min(this._count - k * this._chunkSize, this._chunkSize);\n                for (var i = 0; i < len; i++) {\n                    var val = chunkStorage[i];\n                    var val2 = chunkStorage2[i];\n                    // Do not filter NaN, see comment above.\n                    if ((\n                            (val >= min && val <= max) || isNaN(val)\n                        )\n                        && (\n                            (val2 >= min2 && val2 <= max2) || isNaN(val2)\n                        )\n                    ) {\n                        newIndices[offset++] = idx;\n                    }\n                    idx++;\n                }\n            }\n            quickFinished = true;\n        }\n    }\n    if (!quickFinished) {\n        if (dimSize === 1) {\n            for (var i = 0; i < originalCount; i++) {\n                var rawIndex = this.getRawIndex(i);\n                var val = this._getFast(dim0, rawIndex);\n                // Do not filter NaN, see comment above.\n                if (\n                    (val >= min && val <= max) || isNaN(val)\n                ) {\n                    newIndices[offset++] = rawIndex;\n                }\n            }\n        }\n        else {\n            for (var i = 0; i < originalCount; i++) {\n                var keep = true;\n                var rawIndex = this.getRawIndex(i);\n                for (var k = 0; k < dimSize; k++) {\n                    var dimk = dimensions[k];\n                    var val = this._getFast(dim, rawIndex);\n                    // Do not filter NaN, see comment above.\n                    if (val < range[dimk][0] || val > range[dimk][1]) {\n                        keep = false;\n                    }\n                }\n                if (keep) {\n                    newIndices[offset++] = this.getRawIndex(i);\n                }\n            }\n        }\n    }\n\n    // Set indices after filtered.\n    if (offset < originalCount) {\n        this._indices = newIndices;\n    }\n    this._count = offset;\n    // Reset data extent\n    this._extent = {};\n\n    this.getRawIndex = this._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return this;\n};\n\n/**\n * Data mapping to a plain array\n * @param {string|Array.<string>} [dimensions]\n * @param {Function} cb\n * @param {*} [context=this]\n * @return {Array}\n */\nlistProto.mapArray = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    if (typeof dimensions === 'function') {\n        contextCompat = context;\n        context = cb;\n        cb = dimensions;\n        dimensions = [];\n    }\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    var result = [];\n    this.each(dimensions, function () {\n        result.push(cb && cb.apply(this, arguments));\n    }, context);\n    return result;\n};\n\n// Data in excludeDimensions is copied, otherwise transfered.\nfunction cloneListForMapAndSample(original, excludeDimensions) {\n    var allDimensions = original.dimensions;\n    var list = new List(\n        map(allDimensions, original.getDimensionInfo, original),\n        original.hostModel\n    );\n    // FIXME If needs stackedOn, value may already been stacked\n    transferProperties(list, original);\n\n    var storage = list._storage = {};\n    var originalStorage = original._storage;\n\n    // Init storage\n    for (var i = 0; i < allDimensions.length; i++) {\n        var dim = allDimensions[i];\n        if (originalStorage[dim]) {\n            // Notice that we do not reset invertedIndicesMap here, becuase\n            // there is no scenario of mapping or sampling ordinal dimension.\n            if (indexOf(excludeDimensions, dim) >= 0) {\n                storage[dim] = cloneDimStore(originalStorage[dim]);\n                list._rawExtent[dim] = getInitialExtent();\n                list._extent[dim] = null;\n            }\n            else {\n                // Direct reference for other dimensions\n                storage[dim] = originalStorage[dim];\n            }\n        }\n    }\n    return list;\n}\n\nfunction cloneDimStore(originalDimStore) {\n    var newDimStore = new Array(originalDimStore.length);\n    for (var j = 0; j < originalDimStore.length; j++) {\n        newDimStore[j] = cloneChunk(originalDimStore[j]);\n    }\n    return newDimStore;\n}\n\nfunction getInitialExtent() {\n    return [Infinity, -Infinity];\n}\n\n/**\n * Data mapping to a new List with given dimensions\n * @param {string|Array.<string>} dimensions\n * @param {Function} cb\n * @param {*} [context=this]\n * @return {Array}\n */\nlistProto.map = function (dimensions, cb, context, contextCompat) {\n    'use strict';\n\n    // contextCompat just for compat echarts3\n    context = context || contextCompat || this;\n\n    dimensions = map(\n        normalizeDimensions(dimensions), this.getDimension, this\n    );\n\n    if (__DEV__) {\n        validateDimensions(this, dimensions);\n    }\n\n    var list = cloneListForMapAndSample(this, dimensions);\n\n    // Following properties are all immutable.\n    // So we can reference to the same value\n    list._indices = this._indices;\n    list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    var storage = list._storage;\n\n    var tmpRetValue = [];\n    var chunkSize = this._chunkSize;\n    var dimSize = dimensions.length;\n    var dataCount = this.count();\n    var values = [];\n    var rawExtent = list._rawExtent;\n\n    for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) {\n        for (var dimIndex = 0; dimIndex < dimSize; dimIndex++) {\n            values[dimIndex] = this.get(dimensions[dimIndex], dataIndex /*, stack */);\n        }\n        values[dimSize] = dataIndex;\n\n        var retValue = cb && cb.apply(context, values);\n        if (retValue != null) {\n            // a number or string (in oridinal dimension)?\n            if (typeof retValue !== 'object') {\n                tmpRetValue[0] = retValue;\n                retValue = tmpRetValue;\n            }\n\n            var rawIndex = this.getRawIndex(dataIndex);\n            var chunkIndex = Math.floor(rawIndex / chunkSize);\n            var chunkOffset = rawIndex % chunkSize;\n\n            for (var i = 0; i < retValue.length; i++) {\n                var dim = dimensions[i];\n                var val = retValue[i];\n                var rawExtentOnDim = rawExtent[dim];\n\n                var dimStore = storage[dim];\n                if (dimStore) {\n                    dimStore[chunkIndex][chunkOffset] = val;\n                }\n\n                if (val < rawExtentOnDim[0]) {\n                    rawExtentOnDim[0] = val;\n                }\n                if (val > rawExtentOnDim[1]) {\n                    rawExtentOnDim[1] = val;\n                }\n            }\n        }\n    }\n\n    return list;\n};\n\n/**\n * Large data down sampling on given dimension\n * @param {string} dimension\n * @param {number} rate\n * @param {Function} sampleValue\n * @param {Function} sampleIndex Sample index for name and id\n */\nlistProto.downSample = function (dimension, rate, sampleValue, sampleIndex) {\n    var list = cloneListForMapAndSample(this, [dimension]);\n    var targetStorage = list._storage;\n\n    var frameValues = [];\n    var frameSize = Math.floor(1 / rate);\n\n    var dimStore = targetStorage[dimension];\n    var len = this.count();\n    var chunkSize = this._chunkSize;\n    var rawExtentOnDim = list._rawExtent[dimension];\n\n    var newIndices = new (getIndicesCtor(this))(len);\n\n    var offset = 0;\n    for (var i = 0; i < len; i += frameSize) {\n        // Last frame\n        if (frameSize > len - i) {\n            frameSize = len - i;\n            frameValues.length = frameSize;\n        }\n        for (var k = 0; k < frameSize; k++) {\n            var dataIdx = this.getRawIndex(i + k);\n            var originalChunkIndex = Math.floor(dataIdx / chunkSize);\n            var originalChunkOffset = dataIdx % chunkSize;\n            frameValues[k] = dimStore[originalChunkIndex][originalChunkOffset];\n        }\n        var value = sampleValue(frameValues);\n        var sampleFrameIdx = this.getRawIndex(\n            Math.min(i + sampleIndex(frameValues, value) || 0, len - 1)\n        );\n        var sampleChunkIndex = Math.floor(sampleFrameIdx / chunkSize);\n        var sampleChunkOffset = sampleFrameIdx % chunkSize;\n        // Only write value on the filtered data\n        dimStore[sampleChunkIndex][sampleChunkOffset] = value;\n\n        if (value < rawExtentOnDim[0]) {\n            rawExtentOnDim[0] = value;\n        }\n        if (value > rawExtentOnDim[1]) {\n            rawExtentOnDim[1] = value;\n        }\n\n        newIndices[offset++] = sampleFrameIdx;\n    }\n\n    list._count = offset;\n    list._indices = newIndices;\n\n    list.getRawIndex = getRawIndexWithIndices;\n\n    return list;\n};\n\n/**\n * Get model of one data item.\n *\n * @param {number} idx\n */\n// FIXME Model proxy ?\nlistProto.getItemModel = function (idx) {\n    var hostModel = this.hostModel;\n    return new Model(this.getRawDataItem(idx), hostModel, hostModel && hostModel.ecModel);\n};\n\n/**\n * Create a data differ\n * @param {module:echarts/data/List} otherList\n * @return {module:echarts/data/DataDiffer}\n */\nlistProto.diff = function (otherList) {\n    var thisList = this;\n\n    return new DataDiffer(\n        otherList ? otherList.getIndices() : [],\n        this.getIndices(),\n        function (idx) {\n            return getId(otherList, idx);\n        },\n        function (idx) {\n            return getId(thisList, idx);\n        }\n    );\n};\n/**\n * Get visual property.\n * @param {string} key\n */\nlistProto.getVisual = function (key) {\n    var visual = this._visual;\n    return visual && visual[key];\n};\n\n/**\n * Set visual property\n * @param {string|Object} key\n * @param {*} [value]\n *\n * @example\n *  setVisual('color', color);\n *  setVisual({\n *      'color': color\n *  });\n */\nlistProto.setVisual = function (key, val) {\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                this.setVisual(name, key[name]);\n            }\n        }\n        return;\n    }\n    this._visual = this._visual || {};\n    this._visual[key] = val;\n};\n\n/**\n * Set layout property.\n * @param {string|Object} key\n * @param {*} [val]\n */\nlistProto.setLayout = function (key, val) {\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                this.setLayout(name, key[name]);\n            }\n        }\n        return;\n    }\n    this._layout[key] = val;\n};\n\n/**\n * Get layout property.\n * @param  {string} key.\n * @return {*}\n */\nlistProto.getLayout = function (key) {\n    return this._layout[key];\n};\n\n/**\n * Get layout of single data item\n * @param {number} idx\n */\nlistProto.getItemLayout = function (idx) {\n    return this._itemLayouts[idx];\n};\n\n/**\n * Set layout of single data item\n * @param {number} idx\n * @param {Object} layout\n * @param {boolean=} [merge=false]\n */\nlistProto.setItemLayout = function (idx, layout, merge$$1) {\n    this._itemLayouts[idx] = merge$$1\n        ? extend(this._itemLayouts[idx] || {}, layout)\n        : layout;\n};\n\n/**\n * Clear all layout of single data item\n */\nlistProto.clearItemLayouts = function () {\n    this._itemLayouts.length = 0;\n};\n\n/**\n * Get visual property of single data item\n * @param {number} idx\n * @param {string} key\n * @param {boolean} [ignoreParent=false]\n */\nlistProto.getItemVisual = function (idx, key, ignoreParent) {\n    var itemVisual = this._itemVisuals[idx];\n    var val = itemVisual && itemVisual[key];\n    if (val == null && !ignoreParent) {\n        // Use global visual property\n        return this.getVisual(key);\n    }\n    return val;\n};\n\n/**\n * Set visual property of single data item\n *\n * @param {number} idx\n * @param {string|Object} key\n * @param {*} [value]\n *\n * @example\n *  setItemVisual(0, 'color', color);\n *  setItemVisual(0, {\n *      'color': color\n *  });\n */\nlistProto.setItemVisual = function (idx, key, value) {\n    var itemVisual = this._itemVisuals[idx] || {};\n    var hasItemVisual = this.hasItemVisual;\n    this._itemVisuals[idx] = itemVisual;\n\n    if (isObject$4(key)) {\n        for (var name in key) {\n            if (key.hasOwnProperty(name)) {\n                itemVisual[name] = key[name];\n                hasItemVisual[name] = true;\n            }\n        }\n        return;\n    }\n    itemVisual[key] = value;\n    hasItemVisual[key] = true;\n};\n\n/**\n * Clear itemVisuals and list visual.\n */\nlistProto.clearAllVisual = function () {\n    this._visual = {};\n    this._itemVisuals = [];\n    this.hasItemVisual = {};\n};\n\nvar setItemDataAndSeriesIndex = function (child) {\n    child.seriesIndex = this.seriesIndex;\n    child.dataIndex = this.dataIndex;\n    child.dataType = this.dataType;\n};\n/**\n * Set graphic element relative to data. It can be set as null\n * @param {number} idx\n * @param {module:zrender/Element} [el]\n */\nlistProto.setItemGraphicEl = function (idx, el) {\n    var hostModel = this.hostModel;\n\n    if (el) {\n        // Add data index and series index for indexing the data by element\n        // Useful in tooltip\n        el.dataIndex = idx;\n        el.dataType = this.dataType;\n        el.seriesIndex = hostModel && hostModel.seriesIndex;\n        if (el.type === 'group') {\n            el.traverse(setItemDataAndSeriesIndex, el);\n        }\n    }\n\n    this._graphicEls[idx] = el;\n};\n\n/**\n * @param {number} idx\n * @return {module:zrender/Element}\n */\nlistProto.getItemGraphicEl = function (idx) {\n    return this._graphicEls[idx];\n};\n\n/**\n * @param {Function} cb\n * @param {*} context\n */\nlistProto.eachItemGraphicEl = function (cb, context) {\n    each$1(this._graphicEls, function (el, idx) {\n        if (el) {\n            cb && cb.call(context, el, idx);\n        }\n    });\n};\n\n/**\n * Shallow clone a new list except visual and layout properties, and graph elements.\n * New list only change the indices.\n */\nlistProto.cloneShallow = function (list) {\n    if (!list) {\n        var dimensionInfoList = map(this.dimensions, this.getDimensionInfo, this);\n        list = new List(dimensionInfoList, this.hostModel);\n    }\n\n    // FIXME\n    list._storage = this._storage;\n\n    transferProperties(list, this);\n\n    // Clone will not change the data extent and indices\n    if (this._indices) {\n        var Ctor = this._indices.constructor;\n        list._indices = new Ctor(this._indices);\n    }\n    else {\n        list._indices = null;\n    }\n    list.getRawIndex = list._indices ? getRawIndexWithIndices : getRawIndexWithoutIndices;\n\n    return list;\n};\n\n/**\n * Wrap some method to add more feature\n * @param {string} methodName\n * @param {Function} injectFunction\n */\nlistProto.wrapMethod = function (methodName, injectFunction) {\n    var originalMethod = this[methodName];\n    if (typeof originalMethod !== 'function') {\n        return;\n    }\n    this.__wrappedMethods = this.__wrappedMethods || [];\n    this.__wrappedMethods.push(methodName);\n    this[methodName] = function () {\n        var res = originalMethod.apply(this, arguments);\n        return injectFunction.apply(this, [res].concat(slice(arguments)));\n    };\n};\n\n// Methods that create a new list based on this list should be listed here.\n// Notice that those method should `RETURN` the new list.\nlistProto.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'map'];\n// Methods that change indices of this list should be listed here.\nlistProto.CHANGABLE_METHODS = ['filterSelf', 'selectRange'];\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @deprecated\n * Use `echarts/data/helper/createDimensions` instead.\n */\n\n/**\n * @see {module:echarts/test/ut/spec/data/completeDimensions}\n *\n * Complete the dimensions array, by user defined `dimension` and `encode`,\n * and guessing from the data structure.\n * If no 'value' dimension specified, the first no-named dimension will be\n * named as 'value'.\n *\n * @param {Array.<string>} sysDims Necessary dimensions, like ['x', 'y'], which\n *      provides not only dim template, but also default order.\n *      properties: 'name', 'type', 'displayName'.\n *      `name` of each item provides default coord name.\n *      [{dimsDef: [string|Object, ...]}, ...] dimsDef of sysDim item provides default dim name, and\n *                                    provide dims count that the sysDim required.\n *      [{ordinalMeta}] can be specified.\n * @param {module:echarts/data/Source|Array|Object} source or data (for compatibal with pervious)\n * @param {Object} [opt]\n * @param {Array.<Object|string>} [opt.dimsDef] option.series.dimensions User defined dimensions\n *      For example: ['asdf', {name, type}, ...].\n * @param {Object|HashMap} [opt.encodeDef] option.series.encode {x: 2, y: [3, 1], tooltip: [1, 2], label: 3}\n * @param {string} [opt.generateCoord] Generate coord dim with the given name.\n *                 If not specified, extra dim names will be:\n *                 'value', 'value0', 'value1', ...\n * @param {number} [opt.generateCoordCount] By default, the generated dim name is `generateCoord`.\n *                 If `generateCoordCount` specified, the generated dim names will be:\n *                 `generateCoord` + 0, `generateCoord` + 1, ...\n *                 can be Infinity, indicate that use all of the remain columns.\n * @param {number} [opt.dimCount] If not specified, guess by the first data item.\n * @param {number} [opt.encodeDefaulter] If not specified, auto find the next available data dim.\n * @return {Array.<Object>} [{\n *      name: string mandatory,\n *      displayName: string, the origin name in dimsDef, see source helper.\n *                 If displayName given, the tooltip will displayed vertically.\n *      coordDim: string mandatory,\n *      coordDimIndex: number mandatory,\n *      type: string optional,\n *      otherDims: { never null/undefined\n *          tooltip: number optional,\n *          label: number optional,\n *          itemName: number optional,\n *          seriesName: number optional,\n *      },\n *      isExtraCoord: boolean true if coord is generated\n *          (not specified in encode and not series specified)\n *      other props ...\n * }]\n */\nfunction completeDimensions(sysDims, source, opt) {\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n\n    opt = opt || {};\n    sysDims = (sysDims || []).slice();\n    var dimsDef = (opt.dimsDef || []).slice();\n    var encodeDef = createHashMap(opt.encodeDef);\n    var dataDimNameMap = createHashMap();\n    var coordDimNameMap = createHashMap();\n    // var valueCandidate;\n    var result = [];\n\n    var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimCount);\n\n    // Apply user defined dims (`name` and `type`) and init result.\n    for (var i = 0; i < dimCount; i++) {\n        var dimDefItem = dimsDef[i] = extend(\n            {}, isObject$1(dimsDef[i]) ? dimsDef[i] : {name: dimsDef[i]}\n        );\n        var userDimName = dimDefItem.name;\n        var resultItem = result[i] = {otherDims: {}};\n        // Name will be applied later for avoiding duplication.\n        if (userDimName != null && dataDimNameMap.get(userDimName) == null) {\n            // Only if `series.dimensions` is defined in option\n            // displayName, will be set, and dimension will be diplayed vertically in\n            // tooltip by default.\n            resultItem.name = resultItem.displayName = userDimName;\n            dataDimNameMap.set(userDimName, i);\n        }\n        dimDefItem.type != null && (resultItem.type = dimDefItem.type);\n        dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);\n    }\n\n    // Set `coordDim` and `coordDimIndex` by `encodeDef` and normalize `encodeDef`.\n    encodeDef.each(function (dataDims, coordDim) {\n        dataDims = normalizeToArray(dataDims).slice();\n\n        // Note: It is allowed that `dataDims.length` is `0`, e.g., options is\n        // `{encode: {x: -1, y: 1}}`. Should not filter anything in\n        // this case.\n        if (dataDims.length === 1 && dataDims[0] < 0) {\n            encodeDef.set(coordDim, false);\n            return;\n        }\n\n        var validDataDims = encodeDef.set(coordDim, []);\n        each$1(dataDims, function (resultDimIdx, idx) {\n            // The input resultDimIdx can be dim name or index.\n            isString(resultDimIdx) && (resultDimIdx = dataDimNameMap.get(resultDimIdx));\n            if (resultDimIdx != null && resultDimIdx < dimCount) {\n                validDataDims[idx] = resultDimIdx;\n                applyDim(result[resultDimIdx], coordDim, idx);\n            }\n        });\n    });\n\n    // Apply templetes and default order from `sysDims`.\n    var availDimIdx = 0;\n    each$1(sysDims, function (sysDimItem, sysDimIndex) {\n        var coordDim;\n        var sysDimItem;\n        var sysDimItemDimsDef;\n        var sysDimItemOtherDims;\n        if (isString(sysDimItem)) {\n            coordDim = sysDimItem;\n            sysDimItem = {};\n        }\n        else {\n            coordDim = sysDimItem.name;\n            var ordinalMeta = sysDimItem.ordinalMeta;\n            sysDimItem.ordinalMeta = null;\n            sysDimItem = clone(sysDimItem);\n            sysDimItem.ordinalMeta = ordinalMeta;\n            // `coordDimIndex` should not be set directly.\n            sysDimItemDimsDef = sysDimItem.dimsDef;\n            sysDimItemOtherDims = sysDimItem.otherDims;\n            sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex\n                = sysDimItem.dimsDef = sysDimItem.otherDims = null;\n        }\n\n        var dataDims = encodeDef.get(coordDim);\n\n        // negative resultDimIdx means no need to mapping.\n        if (dataDims === false) {\n            return;\n        }\n\n        var dataDims = normalizeToArray(dataDims);\n\n        // dimensions provides default dim sequences.\n        if (!dataDims.length) {\n            for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {\n                while (availDimIdx < result.length && result[availDimIdx].coordDim != null) {\n                    availDimIdx++;\n                }\n                availDimIdx < result.length && dataDims.push(availDimIdx++);\n            }\n        }\n\n        // Apply templates.\n        each$1(dataDims, function (resultDimIdx, coordDimIndex) {\n            var resultItem = result[resultDimIdx];\n            applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);\n            if (resultItem.name == null && sysDimItemDimsDef) {\n                var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];\n                !isObject$1(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {name: sysDimItemDimsDefItem});\n                resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;\n                resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;\n            }\n            // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}\n            sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);\n        });\n    });\n\n    function applyDim(resultItem, coordDim, coordDimIndex) {\n        if (OTHER_DIMENSIONS.get(coordDim) != null) {\n            resultItem.otherDims[coordDim] = coordDimIndex;\n        }\n        else {\n            resultItem.coordDim = coordDim;\n            resultItem.coordDimIndex = coordDimIndex;\n            coordDimNameMap.set(coordDim, true);\n        }\n    }\n\n    // Make sure the first extra dim is 'value'.\n    var generateCoord = opt.generateCoord;\n    var generateCoordCount = opt.generateCoordCount;\n    var fromZero = generateCoordCount != null;\n    generateCoordCount = generateCoord ? (generateCoordCount || 1) : 0;\n    var extra = generateCoord || 'value';\n\n    // Set dim `name` and other `coordDim` and other props.\n    for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {\n        var resultItem = result[resultDimIdx] = result[resultDimIdx] || {};\n        var coordDim = resultItem.coordDim;\n\n        if (coordDim == null) {\n            resultItem.coordDim = genName(\n                extra, coordDimNameMap, fromZero\n            );\n            resultItem.coordDimIndex = 0;\n            if (!generateCoord || generateCoordCount <= 0) {\n                resultItem.isExtraCoord = true;\n            }\n            generateCoordCount--;\n        }\n\n        resultItem.name == null && (resultItem.name = genName(\n            resultItem.coordDim,\n            dataDimNameMap\n        ));\n\n        if (resultItem.type == null && guessOrdinal(source, resultDimIdx, resultItem.name)) {\n            resultItem.type = 'ordinal';\n        }\n    }\n\n    return result;\n}\n\n// ??? TODO\n// Originally detect dimCount by data[0]. Should we\n// optimize it to only by sysDims and dimensions and encode.\n// So only necessary dims will be initialized.\n// But\n// (1) custom series should be considered. where other dims\n// may be visited.\n// (2) sometimes user need to calcualte bubble size or use visualMap\n// on other dimensions besides coordSys needed.\n// So, dims that is not used by system, should be shared in storage?\nfunction getDimCount(source, sysDims, dimsDef, optDimCount) {\n    // Note that the result dimCount should not small than columns count\n    // of data, otherwise `dataDimNameMap` checking will be incorrect.\n    var dimCount = Math.max(\n        source.dimensionsDetectCount || 1,\n        sysDims.length,\n        dimsDef.length,\n        optDimCount || 0\n    );\n    each$1(sysDims, function (sysDimItem) {\n        var sysDimItemDimsDef = sysDimItem.dimsDef;\n        sysDimItemDimsDef && (dimCount = Math.max(dimCount, sysDimItemDimsDef.length));\n    });\n    return dimCount;\n}\n\nfunction genName(name, map$$1, fromZero) {\n    if (fromZero || map$$1.get(name) != null) {\n        var i = 0;\n        while (map$$1.get(name + i) != null) {\n            i++;\n        }\n        name += i;\n    }\n    map$$1.set(name, true);\n    return name;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Substitute `completeDimensions`.\n * `completeDimensions` is to be deprecated.\n */\n/**\n * @param {module:echarts/data/Source|module:echarts/data/List} source or data.\n * @param {Object|Array} [opt]\n * @param {Array.<string|Object>} [opt.coordDimensions=[]]\n * @param {number} [opt.dimensionsCount]\n * @param {string} [opt.generateCoord]\n * @param {string} [opt.generateCoordCount]\n * @param {Array.<string|Object>} [opt.dimensionsDefine=source.dimensionsDefine] Overwrite source define.\n * @param {Object|HashMap} [opt.encodeDefine=source.encodeDefine] Overwrite source define.\n * @return {Array.<Object>} dimensionsInfo\n */\nvar createDimensions = function (source, opt) {\n    opt = opt || {};\n    return completeDimensions(opt.coordDimensions || [], source, {\n        dimsDef: opt.dimensionsDefine || source.dimensionsDefine,\n        encodeDef: opt.encodeDefine || source.encodeDefine,\n        dimCount: opt.dimensionsCount,\n        generateCoord: opt.generateCoord,\n        generateCoordCount: opt.generateCoordCount\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Note that it is too complicated to support 3d stack by value\n * (have to create two-dimension inverted index), so in 3d case\n * we just support that stacked by index.\n *\n * @param {module:echarts/model/Series} seriesModel\n * @param {Array.<string|Object>} dimensionInfoList The same as the input of <module:echarts/data/List>.\n *        The input dimensionInfoList will be modified.\n * @param {Object} [opt]\n * @param {boolean} [opt.stackedCoordDimension=''] Specify a coord dimension if needed.\n * @param {boolean} [opt.byIndex=false]\n * @return {Object} calculationInfo\n * {\n *     stackedDimension: string\n *     stackedByDimension: string\n *     isStackedByIndex: boolean\n *     stackedOverDimension: string\n *     stackResultDimension: string\n * }\n */\nfunction enableDataStack(seriesModel, dimensionInfoList, opt) {\n    opt = opt || {};\n    var byIndex = opt.byIndex;\n    var stackedCoordDimension = opt.stackedCoordDimension;\n\n    // Compatibal: when `stack` is set as '', do not stack.\n    var mayStack = !!(seriesModel && seriesModel.get('stack'));\n    var stackedByDimInfo;\n    var stackedDimInfo;\n    var stackResultDimension;\n    var stackedOverDimension;\n\n    each$1(dimensionInfoList, function (dimensionInfo, index) {\n        if (isString(dimensionInfo)) {\n            dimensionInfoList[index] = dimensionInfo = {name: dimensionInfo};\n        }\n\n        if (mayStack && !dimensionInfo.isExtraCoord) {\n            // Find the first ordinal dimension as the stackedByDimInfo.\n            if (!byIndex && !stackedByDimInfo && dimensionInfo.ordinalMeta) {\n                stackedByDimInfo = dimensionInfo;\n            }\n            // Find the first stackable dimension as the stackedDimInfo.\n            if (!stackedDimInfo\n                && dimensionInfo.type !== 'ordinal'\n                && dimensionInfo.type !== 'time'\n                && (!stackedCoordDimension || stackedCoordDimension === dimensionInfo.coordDim)\n            ) {\n                stackedDimInfo = dimensionInfo;\n            }\n        }\n    });\n\n    if (stackedDimInfo && !byIndex && !stackedByDimInfo) {\n        // Compatible with previous design, value axis (time axis) only stack by index.\n        // It may make sense if the user provides elaborately constructed data.\n        byIndex = true;\n    }\n\n    // Add stack dimension, they can be both calculated by coordinate system in `unionExtent`.\n    // That put stack logic in List is for using conveniently in echarts extensions, but it\n    // might not be a good way.\n    if (stackedDimInfo) {\n        // Use a weird name that not duplicated with other names.\n        stackResultDimension = '__\\0ecstackresult';\n        stackedOverDimension = '__\\0ecstackedover';\n\n        // Create inverted index to fast query index by value.\n        if (stackedByDimInfo) {\n            stackedByDimInfo.createInvertedIndices = true;\n        }\n\n        var stackedDimCoordDim = stackedDimInfo.coordDim;\n        var stackedDimType = stackedDimInfo.type;\n        var stackedDimCoordIndex = 0;\n\n        each$1(dimensionInfoList, function (dimensionInfo) {\n            if (dimensionInfo.coordDim === stackedDimCoordDim) {\n                stackedDimCoordIndex++;\n            }\n        });\n\n        dimensionInfoList.push({\n            name: stackResultDimension,\n            coordDim: stackedDimCoordDim,\n            coordDimIndex: stackedDimCoordIndex,\n            type: stackedDimType,\n            isExtraCoord: true,\n            isCalculationCoord: true\n        });\n\n        stackedDimCoordIndex++;\n\n        dimensionInfoList.push({\n            name: stackedOverDimension,\n            // This dimension contains stack base (generally, 0), so do not set it as\n            // `stackedDimCoordDim` to avoid extent calculation, consider log scale.\n            coordDim: stackedOverDimension,\n            coordDimIndex: stackedDimCoordIndex,\n            type: stackedDimType,\n            isExtraCoord: true,\n            isCalculationCoord: true\n        });\n    }\n\n    return {\n        stackedDimension: stackedDimInfo && stackedDimInfo.name,\n        stackedByDimension: stackedByDimInfo && stackedByDimInfo.name,\n        isStackedByIndex: byIndex,\n        stackedOverDimension: stackedOverDimension,\n        stackResultDimension: stackResultDimension\n    };\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {string} stackedDim\n */\nfunction isDimensionStacked(data, stackedDim /*, stackedByDim*/) {\n    // Each single series only maps to one pair of axis. So we do not need to\n    // check stackByDim, whatever stacked by a dimension or stacked by index.\n    return !!stackedDim && stackedDim === data.getCalculationInfo('stackedDimension');\n        // && (\n        //     stackedByDim != null\n        //         ? stackedByDim === data.getCalculationInfo('stackedByDimension')\n        //         : data.getCalculationInfo('isStackedByIndex')\n        // );\n}\n\n/**\n * @param {module:echarts/data/List} data\n * @param {string} targetDim\n * @param {string} [stackedByDim] If not input this parameter, check whether\n *                                stacked by index.\n * @return {string} dimension\n */\nfunction getStackedDimension(data, targetDim) {\n    return isDimensionStacked(data, targetDim)\n        ? data.getCalculationInfo('stackResultDimension')\n        : targetDim;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/data/Source|Array} source Or raw data.\n * @param {module:echarts/model/Series} seriesModel\n * @param {Object} [opt]\n * @param {string} [opt.generateCoord]\n */\nfunction createListFromArray(source, seriesModel, opt) {\n    opt = opt || {};\n\n    if (!Source.isInstance(source)) {\n        source = Source.seriesDataToSource(source);\n    }\n\n    var coordSysName = seriesModel.get('coordinateSystem');\n    var registeredCoordSys = CoordinateSystemManager.get(coordSysName);\n\n    var coordSysDefine = getCoordSysDefineBySeries(seriesModel);\n\n    var coordSysDimDefs;\n\n    if (coordSysDefine) {\n        coordSysDimDefs = map(coordSysDefine.coordSysDims, function (dim) {\n            var dimInfo = {name: dim};\n            var axisModel = coordSysDefine.axisMap.get(dim);\n            if (axisModel) {\n                var axisType = axisModel.get('type');\n                dimInfo.type = getDimensionTypeByAxis(axisType);\n                // dimInfo.stackable = isStackable(axisType);\n            }\n            return dimInfo;\n        });\n    }\n\n    if (!coordSysDimDefs) {\n        // Get dimensions from registered coordinate system\n        coordSysDimDefs = (registeredCoordSys && (\n            registeredCoordSys.getDimensionsInfo\n                ? registeredCoordSys.getDimensionsInfo()\n                : registeredCoordSys.dimensions.slice()\n        )) || ['x', 'y'];\n    }\n\n    var dimInfoList = createDimensions(source, {\n        coordDimensions: coordSysDimDefs,\n        generateCoord: opt.generateCoord\n    });\n\n    var firstCategoryDimIndex;\n    var hasNameEncode;\n    coordSysDefine && each$1(dimInfoList, function (dimInfo, dimIndex) {\n        var coordDim = dimInfo.coordDim;\n        var categoryAxisModel = coordSysDefine.categoryAxisMap.get(coordDim);\n        if (categoryAxisModel) {\n            if (firstCategoryDimIndex == null) {\n                firstCategoryDimIndex = dimIndex;\n            }\n            dimInfo.ordinalMeta = categoryAxisModel.getOrdinalMeta();\n        }\n        if (dimInfo.otherDims.itemName != null) {\n            hasNameEncode = true;\n        }\n    });\n    if (!hasNameEncode && firstCategoryDimIndex != null) {\n        dimInfoList[firstCategoryDimIndex].otherDims.itemName = 0;\n    }\n\n    var stackCalculationInfo = enableDataStack(seriesModel, dimInfoList);\n\n    var list = new List(dimInfoList, seriesModel);\n\n    list.setCalculationInfo(stackCalculationInfo);\n\n    var dimValueGetter = (firstCategoryDimIndex != null && isNeedCompleteOrdinalData(source))\n        ? function (itemOpt, dimName, dataIndex, dimIndex) {\n            // Use dataIndex as ordinal value in categoryAxis\n            return dimIndex === firstCategoryDimIndex\n                ? dataIndex\n                : this.defaultDimValueGetter(itemOpt, dimName, dataIndex, dimIndex);\n        }\n        : null;\n\n    list.hasItemOption = false;\n    list.initData(source, null, dimValueGetter);\n\n    return list;\n}\n\nfunction isNeedCompleteOrdinalData(source) {\n    if (source.sourceFormat === SOURCE_FORMAT_ORIGINAL) {\n        var sampleItem = firstDataNotNull(source.data || []);\n        return sampleItem != null\n            && !isArray(getDataItemValue(sampleItem));\n    }\n}\n\nfunction firstDataNotNull(data) {\n    var i = 0;\n    while (i < data.length && data[i] == null) {\n        i++;\n    }\n    return data[i];\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nSeriesModel.extend({\n\n    type: 'series.line',\n\n    dependencies: ['grid', 'polar'],\n\n    getInitialData: function (option, ecModel) {\n        if (__DEV__) {\n            var coordSys = option.coordinateSystem;\n            if (coordSys !== 'polar' && coordSys !== 'cartesian2d') {\n                throw new Error('Line not support coordinateSystem besides cartesian and polar');\n            }\n        }\n        return createListFromArray(this.getSource(), this);\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // stack: null\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // polarIndex: 0,\n\n        // If clip the overflow value\n        clipOverflow: true,\n        // cursor: null,\n\n        label: {\n            position: 'top'\n        },\n        // itemStyle: {\n        // },\n\n        lineStyle: {\n            width: 2,\n            type: 'solid'\n        },\n        // areaStyle: {\n            // origin of areaStyle. Valid values:\n            // `'auto'/null/undefined`: from axisLine to data\n            // `'start'`: from min to data\n            // `'end'`: from data to max\n            // origin: 'auto'\n        // },\n        // false, 'start', 'end', 'middle'\n        step: false,\n\n        // Disabled if step is true\n        smooth: false,\n        smoothMonotone: null,\n        symbol: 'emptyCircle',\n        symbolSize: 4,\n        symbolRotate: null,\n\n        showSymbol: true,\n        // `false`: follow the label interval strategy.\n        // `true`: show all symbols.\n        // `'auto'`: If possible, show all symbols, otherwise\n        //           follow the label interval strategy.\n        showAllSymbol: 'auto',\n\n        // Whether to connect break point.\n        connectNulls: false,\n\n        // Sampling for large data. Can be: 'average', 'max', 'min', 'sum'.\n        sampling: 'none',\n\n        animationEasing: 'linear',\n\n        // Disable progressive\n        progressive: 0,\n        hoverLayerThreshold: Infinity\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Symbol factory\n\n/**\n * Triangle shape\n * @inner\n */\nvar Triangle = extendShape({\n    type: 'triangle',\n    shape: {\n        cx: 0,\n        cy: 0,\n        width: 0,\n        height: 0\n    },\n    buildPath: function (path, shape) {\n        var cx = shape.cx;\n        var cy = shape.cy;\n        var width = shape.width / 2;\n        var height = shape.height / 2;\n        path.moveTo(cx, cy - height);\n        path.lineTo(cx + width, cy + height);\n        path.lineTo(cx - width, cy + height);\n        path.closePath();\n    }\n});\n\n/**\n * Diamond shape\n * @inner\n */\nvar Diamond = extendShape({\n    type: 'diamond',\n    shape: {\n        cx: 0,\n        cy: 0,\n        width: 0,\n        height: 0\n    },\n    buildPath: function (path, shape) {\n        var cx = shape.cx;\n        var cy = shape.cy;\n        var width = shape.width / 2;\n        var height = shape.height / 2;\n        path.moveTo(cx, cy - height);\n        path.lineTo(cx + width, cy);\n        path.lineTo(cx, cy + height);\n        path.lineTo(cx - width, cy);\n        path.closePath();\n    }\n});\n\n/**\n * Pin shape\n * @inner\n */\nvar Pin = extendShape({\n    type: 'pin',\n    shape: {\n        // x, y on the cusp\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (path, shape) {\n        var x = shape.x;\n        var y = shape.y;\n        var w = shape.width / 5 * 3;\n        // Height must be larger than width\n        var h = Math.max(w, shape.height);\n        var r = w / 2;\n\n        // Dist on y with tangent point and circle center\n        var dy = r * r / (h - r);\n        var cy = y - h + r + dy;\n        var angle = Math.asin(dy / r);\n        // Dist on x with tangent point and circle center\n        var dx = Math.cos(angle) * r;\n\n        var tanX = Math.sin(angle);\n        var tanY = Math.cos(angle);\n\n        var cpLen = r * 0.6;\n        var cpLen2 = r * 0.7;\n\n        path.moveTo(x - dx, cy + dy);\n\n        path.arc(\n            x, cy, r,\n            Math.PI - angle,\n            Math.PI * 2 + angle\n        );\n        path.bezierCurveTo(\n            x + dx - tanX * cpLen, cy + dy + tanY * cpLen,\n            x, y - cpLen2,\n            x, y\n        );\n        path.bezierCurveTo(\n            x, y - cpLen2,\n            x - dx + tanX * cpLen, cy + dy + tanY * cpLen,\n            x - dx, cy + dy\n        );\n        path.closePath();\n    }\n});\n\n/**\n * Arrow shape\n * @inner\n */\nvar Arrow = extendShape({\n\n    type: 'arrow',\n\n    shape: {\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    buildPath: function (ctx, shape) {\n        var height = shape.height;\n        var width = shape.width;\n        var x = shape.x;\n        var y = shape.y;\n        var dx = width / 3 * 2;\n        ctx.moveTo(x, y);\n        ctx.lineTo(x + dx, y + height);\n        ctx.lineTo(x, y + height / 4 * 3);\n        ctx.lineTo(x - dx, y + height);\n        ctx.lineTo(x, y);\n        ctx.closePath();\n    }\n});\n\n/**\n * Map of path contructors\n * @type {Object.<string, module:zrender/graphic/Path>}\n */\nvar symbolCtors = {\n\n    line: Line,\n\n    rect: Rect,\n\n    roundRect: Rect,\n\n    square: Rect,\n\n    circle: Circle,\n\n    diamond: Diamond,\n\n    pin: Pin,\n\n    arrow: Arrow,\n\n    triangle: Triangle\n};\n\nvar symbolShapeMakers = {\n\n    line: function (x, y, w, h, shape) {\n        // FIXME\n        shape.x1 = x;\n        shape.y1 = y + h / 2;\n        shape.x2 = x + w;\n        shape.y2 = y + h / 2;\n    },\n\n    rect: function (x, y, w, h, shape) {\n        shape.x = x;\n        shape.y = y;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    roundRect: function (x, y, w, h, shape) {\n        shape.x = x;\n        shape.y = y;\n        shape.width = w;\n        shape.height = h;\n        shape.r = Math.min(w, h) / 4;\n    },\n\n    square: function (x, y, w, h, shape) {\n        var size = Math.min(w, h);\n        shape.x = x;\n        shape.y = y;\n        shape.width = size;\n        shape.height = size;\n    },\n\n    circle: function (x, y, w, h, shape) {\n        // Put circle in the center of square\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.r = Math.min(w, h) / 2;\n    },\n\n    diamond: function (x, y, w, h, shape) {\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    pin: function (x, y, w, h, shape) {\n        shape.x = x + w / 2;\n        shape.y = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    arrow: function (x, y, w, h, shape) {\n        shape.x = x + w / 2;\n        shape.y = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    },\n\n    triangle: function (x, y, w, h, shape) {\n        shape.cx = x + w / 2;\n        shape.cy = y + h / 2;\n        shape.width = w;\n        shape.height = h;\n    }\n};\n\nvar symbolBuildProxies = {};\neach$1(symbolCtors, function (Ctor, name) {\n    symbolBuildProxies[name] = new Ctor();\n});\n\nvar SymbolClz$2 = extendShape({\n\n    type: 'symbol',\n\n    shape: {\n        symbolType: '',\n        x: 0,\n        y: 0,\n        width: 0,\n        height: 0\n    },\n\n    beforeBrush: function () {\n        var style = this.style;\n        var shape = this.shape;\n        // FIXME\n        if (shape.symbolType === 'pin' && style.textPosition === 'inside') {\n            style.textPosition = ['50%', '40%'];\n            style.textAlign = 'center';\n            style.textVerticalAlign = 'middle';\n        }\n    },\n\n    buildPath: function (ctx, shape, inBundle) {\n        var symbolType = shape.symbolType;\n        var proxySymbol = symbolBuildProxies[symbolType];\n        if (shape.symbolType !== 'none') {\n            if (!proxySymbol) {\n                // Default rect\n                symbolType = 'rect';\n                proxySymbol = symbolBuildProxies[symbolType];\n            }\n            symbolShapeMakers[symbolType](\n                shape.x, shape.y, shape.width, shape.height, proxySymbol.shape\n            );\n            proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle);\n        }\n    }\n});\n\n// Provide setColor helper method to avoid determine if set the fill or stroke outside\nfunction symbolPathSetColor(color, innerColor) {\n    if (this.type !== 'image') {\n        var symbolStyle = this.style;\n        var symbolShape = this.shape;\n        if (symbolShape && symbolShape.symbolType === 'line') {\n            symbolStyle.stroke = color;\n        }\n        else if (this.__isEmptyBrush) {\n            symbolStyle.stroke = color;\n            symbolStyle.fill = innerColor || '#fff';\n        }\n        else {\n            // FIXME 判断图形默认是填充还是描边，使用 onlyStroke ?\n            symbolStyle.fill && (symbolStyle.fill = color);\n            symbolStyle.stroke && (symbolStyle.stroke = color);\n        }\n        this.dirty(false);\n    }\n}\n\n/**\n * Create a symbol element with given symbol configuration: shape, x, y, width, height, color\n * @param {string} symbolType\n * @param {number} x\n * @param {number} y\n * @param {number} w\n * @param {number} h\n * @param {string} color\n * @param {boolean} [keepAspect=false] whether to keep the ratio of w/h,\n *                            for path and image only.\n */\nfunction createSymbol(symbolType, x, y, w, h, color, keepAspect) {\n    // TODO Support image object, DynamicImage.\n\n    var isEmpty = symbolType.indexOf('empty') === 0;\n    if (isEmpty) {\n        symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6);\n    }\n    var symbolPath;\n\n    if (symbolType.indexOf('image://') === 0) {\n        symbolPath = makeImage(\n            symbolType.slice(8),\n            new BoundingRect(x, y, w, h),\n            keepAspect ? 'center' : 'cover'\n        );\n    }\n    else if (symbolType.indexOf('path://') === 0) {\n        symbolPath = makePath(\n            symbolType.slice(7),\n            {},\n            new BoundingRect(x, y, w, h),\n            keepAspect ? 'center' : 'cover'\n        );\n    }\n    else {\n        symbolPath = new SymbolClz$2({\n            shape: {\n                symbolType: symbolType,\n                x: x,\n                y: y,\n                width: w,\n                height: h\n            }\n        });\n    }\n\n    symbolPath.__isEmptyBrush = isEmpty;\n\n    symbolPath.setColor = symbolPathSetColor;\n\n    symbolPath.setColor(color);\n\n    return symbolPath;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @return {string} label string. Not null/undefined\n */\nfunction getDefaultLabel(data, dataIndex) {\n    var labelDims = data.mapDimension('defaultedLabel', true);\n    var len = labelDims.length;\n\n    // Simple optimization (in lots of cases, label dims length is 1)\n    if (len === 1) {\n        return retrieveRawValue(data, dataIndex, labelDims[0]);\n    }\n    else if (len) {\n        var vals = [];\n        for (var i = 0; i < labelDims.length; i++) {\n            var val = retrieveRawValue(data, dataIndex, labelDims[i]);\n            vals.push(val);\n        }\n        return vals.join(' ');\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/Symbol\n */\n\n/**\n * @constructor\n * @alias {module:echarts/chart/helper/Symbol}\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @extends {module:zrender/graphic/Group}\n */\nfunction SymbolClz(data, idx, seriesScope) {\n    Group.call(this);\n    this.updateData(data, idx, seriesScope);\n}\n\nvar symbolProto = SymbolClz.prototype;\n\n/**\n * @public\n * @static\n * @param {module:echarts/data/List} data\n * @param {number} dataIndex\n * @return {Array.<number>} [width, height]\n */\nvar getSymbolSize = SymbolClz.getSymbolSize = function (data, idx) {\n    var symbolSize = data.getItemVisual(idx, 'symbolSize');\n    return symbolSize instanceof Array\n        ? symbolSize.slice()\n        : [+symbolSize, +symbolSize];\n};\n\nfunction getScale(symbolSize) {\n    return [symbolSize[0] / 2, symbolSize[1] / 2];\n}\n\nfunction driftSymbol(dx, dy) {\n    this.parent.drift(dx, dy);\n}\n\nsymbolProto._createSymbol = function (\n    symbolType,\n    data,\n    idx,\n    symbolSize,\n    keepAspect\n) {\n    // Remove paths created before\n    this.removeAll();\n\n    var color = data.getItemVisual(idx, 'color');\n\n    // var symbolPath = createSymbol(\n    //     symbolType, -0.5, -0.5, 1, 1, color\n    // );\n    // If width/height are set too small (e.g., set to 1) on ios10\n    // and macOS Sierra, a circle stroke become a rect, no matter what\n    // the scale is set. So we set width/height as 2. See #4150.\n    var symbolPath = createSymbol(\n        symbolType, -1, -1, 2, 2, color, keepAspect\n    );\n\n    symbolPath.attr({\n        z2: 100,\n        culling: true,\n        scale: getScale(symbolSize)\n    });\n    // Rewrite drift method\n    symbolPath.drift = driftSymbol;\n\n    this._symbolType = symbolType;\n\n    this.add(symbolPath);\n};\n\n/**\n * Stop animation\n * @param {boolean} toLastFrame\n */\nsymbolProto.stopSymbolAnimation = function (toLastFrame) {\n    this.childAt(0).stopAnimation(toLastFrame);\n};\n\n/**\n * FIXME:\n * Caution: This method breaks the encapsulation of this module,\n * but it indeed brings convenience. So do not use the method\n * unless you detailedly know all the implements of `Symbol`,\n * especially animation.\n *\n * Get symbol path element.\n */\nsymbolProto.getSymbolPath = function () {\n    return this.childAt(0);\n};\n\n/**\n * Get scale(aka, current symbol size).\n * Including the change caused by animation\n */\nsymbolProto.getScale = function () {\n    return this.childAt(0).scale;\n};\n\n/**\n * Highlight symbol\n */\nsymbolProto.highlight = function () {\n    this.childAt(0).trigger('emphasis');\n};\n\n/**\n * Downplay symbol\n */\nsymbolProto.downplay = function () {\n    this.childAt(0).trigger('normal');\n};\n\n/**\n * @param {number} zlevel\n * @param {number} z\n */\nsymbolProto.setZ = function (zlevel, z) {\n    var symbolPath = this.childAt(0);\n    symbolPath.zlevel = zlevel;\n    symbolPath.z = z;\n};\n\nsymbolProto.setDraggable = function (draggable) {\n    var symbolPath = this.childAt(0);\n    symbolPath.draggable = draggable;\n    symbolPath.cursor = draggable ? 'move' : 'pointer';\n};\n\n/**\n * Update symbol properties\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @param {Object} [seriesScope]\n * @param {Object} [seriesScope.itemStyle]\n * @param {Object} [seriesScope.hoverItemStyle]\n * @param {Object} [seriesScope.symbolRotate]\n * @param {Object} [seriesScope.symbolOffset]\n * @param {module:echarts/model/Model} [seriesScope.labelModel]\n * @param {module:echarts/model/Model} [seriesScope.hoverLabelModel]\n * @param {boolean} [seriesScope.hoverAnimation]\n * @param {Object} [seriesScope.cursorStyle]\n * @param {module:echarts/model/Model} [seriesScope.itemModel]\n * @param {string} [seriesScope.symbolInnerColor]\n * @param {Object} [seriesScope.fadeIn=false]\n */\nsymbolProto.updateData = function (data, idx, seriesScope) {\n    this.silent = false;\n\n    var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';\n    var seriesModel = data.hostModel;\n    var symbolSize = getSymbolSize(data, idx);\n    var isInit = symbolType !== this._symbolType;\n\n    if (isInit) {\n        var keepAspect = data.getItemVisual(idx, 'symbolKeepAspect');\n        this._createSymbol(symbolType, data, idx, symbolSize, keepAspect);\n    }\n    else {\n        var symbolPath = this.childAt(0);\n        symbolPath.silent = false;\n        updateProps(symbolPath, {\n            scale: getScale(symbolSize)\n        }, seriesModel, idx);\n    }\n\n    this._updateCommon(data, idx, symbolSize, seriesScope);\n\n    if (isInit) {\n        var symbolPath = this.childAt(0);\n        var fadeIn = seriesScope && seriesScope.fadeIn;\n\n        var target = {scale: symbolPath.scale.slice()};\n        fadeIn && (target.style = {opacity: symbolPath.style.opacity});\n\n        symbolPath.scale = [0, 0];\n        fadeIn && (symbolPath.style.opacity = 0);\n\n        initProps(symbolPath, target, seriesModel, idx);\n    }\n\n    this._seriesModel = seriesModel;\n};\n\n// Update common properties\nvar normalStyleAccessPath = ['itemStyle'];\nvar emphasisStyleAccessPath = ['emphasis', 'itemStyle'];\nvar normalLabelAccessPath = ['label'];\nvar emphasisLabelAccessPath = ['emphasis', 'label'];\n\n/**\n * @param {module:echarts/data/List} data\n * @param {number} idx\n * @param {Array.<number>} symbolSize\n * @param {Object} [seriesScope]\n */\nsymbolProto._updateCommon = function (data, idx, symbolSize, seriesScope) {\n    var symbolPath = this.childAt(0);\n    var seriesModel = data.hostModel;\n    var color = data.getItemVisual(idx, 'color');\n\n    // Reset style\n    if (symbolPath.type !== 'image') {\n        symbolPath.useStyle({\n            strokeNoScale: true\n        });\n    }\n\n    var itemStyle = seriesScope && seriesScope.itemStyle;\n    var hoverItemStyle = seriesScope && seriesScope.hoverItemStyle;\n    var symbolRotate = seriesScope && seriesScope.symbolRotate;\n    var symbolOffset = seriesScope && seriesScope.symbolOffset;\n    var labelModel = seriesScope && seriesScope.labelModel;\n    var hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;\n    var hoverAnimation = seriesScope && seriesScope.hoverAnimation;\n    var cursorStyle = seriesScope && seriesScope.cursorStyle;\n\n    if (!seriesScope || data.hasItemOption) {\n        var itemModel = (seriesScope && seriesScope.itemModel)\n            ? seriesScope.itemModel : data.getItemModel(idx);\n\n        // Color must be excluded.\n        // Because symbol provide setColor individually to set fill and stroke\n        itemStyle = itemModel.getModel(normalStyleAccessPath).getItemStyle(['color']);\n        hoverItemStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();\n\n        symbolRotate = itemModel.getShallow('symbolRotate');\n        symbolOffset = itemModel.getShallow('symbolOffset');\n\n        labelModel = itemModel.getModel(normalLabelAccessPath);\n        hoverLabelModel = itemModel.getModel(emphasisLabelAccessPath);\n        hoverAnimation = itemModel.getShallow('hoverAnimation');\n        cursorStyle = itemModel.getShallow('cursor');\n    }\n    else {\n        hoverItemStyle = extend({}, hoverItemStyle);\n    }\n\n    var elStyle = symbolPath.style;\n\n    symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0);\n\n    if (symbolOffset) {\n        symbolPath.attr('position', [\n            parsePercent$1(symbolOffset[0], symbolSize[0]),\n            parsePercent$1(symbolOffset[1], symbolSize[1])\n        ]);\n    }\n\n    cursorStyle && symbolPath.attr('cursor', cursorStyle);\n\n    // PENDING setColor before setStyle!!!\n    symbolPath.setColor(color, seriesScope && seriesScope.symbolInnerColor);\n\n    symbolPath.setStyle(itemStyle);\n\n    var opacity = data.getItemVisual(idx, 'opacity');\n    if (opacity != null) {\n        elStyle.opacity = opacity;\n    }\n\n    var liftZ = data.getItemVisual(idx, 'liftZ');\n    var z2Origin = symbolPath.__z2Origin;\n    if (liftZ != null) {\n        if (z2Origin == null) {\n            symbolPath.__z2Origin = symbolPath.z2;\n            symbolPath.z2 += liftZ;\n        }\n    }\n    else if (z2Origin != null) {\n        symbolPath.z2 = z2Origin;\n        symbolPath.__z2Origin = null;\n    }\n\n    var useNameLabel = seriesScope && seriesScope.useNameLabel;\n\n    setLabelStyle(\n        elStyle, hoverItemStyle, labelModel, hoverLabelModel,\n        {\n            labelFetcher: seriesModel,\n            labelDataIndex: idx,\n            defaultText: getLabelDefaultText,\n            isRectText: true,\n            autoColor: color\n        }\n    );\n\n    // Do not execute util needed.\n    function getLabelDefaultText(idx, opt) {\n        return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx);\n    }\n\n    symbolPath.off('mouseover')\n        .off('mouseout')\n        .off('emphasis')\n        .off('normal');\n\n    symbolPath.hoverStyle = hoverItemStyle;\n\n    // FIXME\n    // Do not use symbol.trigger('emphasis'), but use symbol.highlight() instead.\n    setHoverStyle(symbolPath);\n\n    symbolPath.__symbolOriginalScale = getScale(symbolSize);\n\n    if (hoverAnimation && seriesModel.isAnimationEnabled()) {\n        // Note: consider `off`, should use static function here.\n        symbolPath.on('mouseover', onMouseOver)\n            .on('mouseout', onMouseOut)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal);\n    }\n};\n\nfunction onMouseOver() {\n    // see comment in `graphic.isInEmphasis`\n    !isInEmphasis(this) && onEmphasis.call(this);\n}\n\nfunction onMouseOut() {\n    // see comment in `graphic.isInEmphasis`\n    !isInEmphasis(this) && onNormal.call(this);\n}\n\nfunction onEmphasis() {\n    // Do not support this hover animation util some scenario required.\n    // Animation can only be supported in hover layer when using `el.incremetal`.\n    if (this.incremental || this.useHoverLayer) {\n        return;\n    }\n    var scale = this.__symbolOriginalScale;\n    var ratio = scale[1] / scale[0];\n    this.animateTo({\n        scale: [\n            Math.max(scale[0] * 1.1, scale[0] + 3),\n            Math.max(scale[1] * 1.1, scale[1] + 3 * ratio)\n        ]\n    }, 400, 'elasticOut');\n}\n\nfunction onNormal() {\n    if (this.incremental || this.useHoverLayer) {\n        return;\n    }\n    this.animateTo({\n        scale: this.__symbolOriginalScale\n    }, 400, 'elasticOut');\n}\n\n\n/**\n * @param {Function} cb\n * @param {Object} [opt]\n * @param {Object} [opt.keepLabel=true]\n */\nsymbolProto.fadeOut = function (cb, opt) {\n    var symbolPath = this.childAt(0);\n    // Avoid mistaken hover when fading out\n    this.silent = symbolPath.silent = true;\n    // Not show text when animating\n    !(opt && opt.keepLabel) && (symbolPath.style.text = null);\n\n    updateProps(\n        symbolPath,\n        {\n            style: {opacity: 0},\n            scale: [0, 0]\n        },\n        this._seriesModel,\n        this.dataIndex,\n        cb\n    );\n};\n\ninherits(SymbolClz, Group);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @module echarts/chart/helper/SymbolDraw\n */\n\n/**\n * @constructor\n * @alias module:echarts/chart/helper/SymbolDraw\n * @param {module:zrender/graphic/Group} [symbolCtor]\n */\nfunction SymbolDraw(symbolCtor) {\n    this.group = new Group();\n\n    this._symbolCtor = symbolCtor || SymbolClz;\n}\n\nvar symbolDrawProto = SymbolDraw.prototype;\n\nfunction symbolNeedsDraw(data, point, idx, opt) {\n    return point && !isNaN(point[0]) && !isNaN(point[1])\n        && !(opt.isIgnore && opt.isIgnore(idx))\n        // We do not set clipShape on group, because it will cut part of\n        // the symbol element shape. We use the same clip shape here as\n        // the line clip.\n        && !(opt.clipShape && !opt.clipShape.contain(point[0], point[1]))\n        && data.getItemVisual(idx, 'symbol') !== 'none';\n}\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n * @param {Object} [opt] Or isIgnore\n * @param {Function} [opt.isIgnore]\n * @param {Object} [opt.clipShape]\n */\nsymbolDrawProto.updateData = function (data, opt) {\n    opt = normalizeUpdateOpt(opt);\n\n    var group = this.group;\n    var seriesModel = data.hostModel;\n    var oldData = this._data;\n    var SymbolCtor = this._symbolCtor;\n\n    var seriesScope = makeSeriesScope(data);\n\n    // There is no oldLineData only when first rendering or switching from\n    // stream mode to normal mode, where previous elements should be removed.\n    if (!oldData) {\n        group.removeAll();\n    }\n\n    data.diff(oldData)\n        .add(function (newIdx) {\n            var point = data.getItemLayout(newIdx);\n            if (symbolNeedsDraw(data, point, newIdx, opt)) {\n                var symbolEl = new SymbolCtor(data, newIdx, seriesScope);\n                symbolEl.attr('position', point);\n                data.setItemGraphicEl(newIdx, symbolEl);\n                group.add(symbolEl);\n            }\n        })\n        .update(function (newIdx, oldIdx) {\n            var symbolEl = oldData.getItemGraphicEl(oldIdx);\n            var point = data.getItemLayout(newIdx);\n            if (!symbolNeedsDraw(data, point, newIdx, opt)) {\n                group.remove(symbolEl);\n                return;\n            }\n            if (!symbolEl) {\n                symbolEl = new SymbolCtor(data, newIdx);\n                symbolEl.attr('position', point);\n            }\n            else {\n                symbolEl.updateData(data, newIdx, seriesScope);\n                updateProps(symbolEl, {\n                    position: point\n                }, seriesModel);\n            }\n\n            // Add back\n            group.add(symbolEl);\n\n            data.setItemGraphicEl(newIdx, symbolEl);\n        })\n        .remove(function (oldIdx) {\n            var el = oldData.getItemGraphicEl(oldIdx);\n            el && el.fadeOut(function () {\n                group.remove(el);\n            });\n        })\n        .execute();\n\n    this._data = data;\n};\n\nsymbolDrawProto.isPersistent = function () {\n    return true;\n};\n\nsymbolDrawProto.updateLayout = function () {\n    var data = this._data;\n    if (data) {\n        // Not use animation\n        data.eachItemGraphicEl(function (el, idx) {\n            var point = data.getItemLayout(idx);\n            el.attr('position', point);\n        });\n    }\n};\n\nsymbolDrawProto.incrementalPrepareUpdate = function (data) {\n    this._seriesScope = makeSeriesScope(data);\n    this._data = null;\n    this.group.removeAll();\n};\n\n/**\n * Update symbols draw by new data\n * @param {module:echarts/data/List} data\n * @param {Object} [opt] Or isIgnore\n * @param {Function} [opt.isIgnore]\n * @param {Object} [opt.clipShape]\n */\nsymbolDrawProto.incrementalUpdate = function (taskParams, data, opt) {\n    opt = normalizeUpdateOpt(opt);\n\n    function updateIncrementalAndHover(el) {\n        if (!el.isGroup) {\n            el.incremental = el.useHoverLayer = true;\n        }\n    }\n    for (var idx = taskParams.start; idx < taskParams.end; idx++) {\n        var point = data.getItemLayout(idx);\n        if (symbolNeedsDraw(data, point, idx, opt)) {\n            var el = new this._symbolCtor(data, idx, this._seriesScope);\n            el.traverse(updateIncrementalAndHover);\n            el.attr('position', point);\n            this.group.add(el);\n            data.setItemGraphicEl(idx, el);\n        }\n    }\n};\n\nfunction normalizeUpdateOpt(opt) {\n    if (opt != null && !isObject$1(opt)) {\n        opt = {isIgnore: opt};\n    }\n    return opt || {};\n}\n\nsymbolDrawProto.remove = function (enableAnimation) {\n    var group = this.group;\n    var data = this._data;\n    // Incremental model do not have this._data.\n    if (data && enableAnimation) {\n        data.eachItemGraphicEl(function (el) {\n            el.fadeOut(function () {\n                group.remove(el);\n            });\n        });\n    }\n    else {\n        group.removeAll();\n    }\n};\n\nfunction makeSeriesScope(data) {\n    var seriesModel = data.hostModel;\n    return {\n        itemStyle: seriesModel.getModel('itemStyle').getItemStyle(['color']),\n        hoverItemStyle: seriesModel.getModel('emphasis.itemStyle').getItemStyle(),\n        symbolRotate: seriesModel.get('symbolRotate'),\n        symbolOffset: seriesModel.get('symbolOffset'),\n        hoverAnimation: seriesModel.get('hoverAnimation'),\n        labelModel: seriesModel.getModel('label'),\n        hoverLabelModel: seriesModel.getModel('emphasis.label'),\n        cursorStyle: seriesModel.get('cursor')\n    };\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {Object} coordSys\n * @param {module:echarts/data/List} data\n * @param {string} valueOrigin lineSeries.option.areaStyle.origin\n */\nfunction prepareDataCoordInfo(coordSys, data, valueOrigin) {\n    var baseAxis = coordSys.getBaseAxis();\n    var valueAxis = coordSys.getOtherAxis(baseAxis);\n    var valueStart = getValueStart(valueAxis, valueOrigin);\n\n    var baseAxisDim = baseAxis.dim;\n    var valueAxisDim = valueAxis.dim;\n    var valueDim = data.mapDimension(valueAxisDim);\n    var baseDim = data.mapDimension(baseAxisDim);\n    var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0;\n\n    var dims = map(coordSys.dimensions, function (coordDim) {\n        return data.mapDimension(coordDim);\n    });\n\n    var stacked;\n    var stackResultDim = data.getCalculationInfo('stackResultDimension');\n    if (stacked |= isDimensionStacked(data, dims[0] /*, dims[1]*/)) { // jshint ignore:line\n        dims[0] = stackResultDim;\n    }\n    if (stacked |= isDimensionStacked(data, dims[1] /*, dims[0]*/)) { // jshint ignore:line\n        dims[1] = stackResultDim;\n    }\n\n    return {\n        dataDimsForPoint: dims,\n        valueStart: valueStart,\n        valueAxisDim: valueAxisDim,\n        baseAxisDim: baseAxisDim,\n        stacked: !!stacked,\n        valueDim: valueDim,\n        baseDim: baseDim,\n        baseDataOffset: baseDataOffset,\n        stackedOverDimension: data.getCalculationInfo('stackedOverDimension')\n    };\n}\n\nfunction getValueStart(valueAxis, valueOrigin) {\n    var valueStart = 0;\n    var extent = valueAxis.scale.getExtent();\n\n    if (valueOrigin === 'start') {\n        valueStart = extent[0];\n    }\n    else if (valueOrigin === 'end') {\n        valueStart = extent[1];\n    }\n    // auto\n    else {\n        // Both positive\n        if (extent[0] > 0) {\n            valueStart = extent[0];\n        }\n        // Both negative\n        else if (extent[1] < 0) {\n            valueStart = extent[1];\n        }\n        // If is one positive, and one negative, onZero shall be true\n    }\n\n    return valueStart;\n}\n\nfunction getStackedOnPoint(dataCoordInfo, coordSys, data, idx) {\n    var value = NaN;\n    if (dataCoordInfo.stacked) {\n        value = data.get(data.getCalculationInfo('stackedOverDimension'), idx);\n    }\n    if (isNaN(value)) {\n        value = dataCoordInfo.valueStart;\n    }\n\n    var baseDataOffset = dataCoordInfo.baseDataOffset;\n    var stackedData = [];\n    stackedData[baseDataOffset] = data.get(dataCoordInfo.baseDim, idx);\n    stackedData[1 - baseDataOffset] = value;\n\n    return coordSys.dataToPoint(stackedData);\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// var arrayDiff = require('zrender/src/core/arrayDiff');\n// 'zrender/src/core/arrayDiff' has been used before, but it did\n// not do well in performance when roam with fixed dataZoom window.\n\n// function convertToIntId(newIdList, oldIdList) {\n//     // Generate int id instead of string id.\n//     // Compare string maybe slow in score function of arrDiff\n\n//     // Assume id in idList are all unique\n//     var idIndicesMap = {};\n//     var idx = 0;\n//     for (var i = 0; i < newIdList.length; i++) {\n//         idIndicesMap[newIdList[i]] = idx;\n//         newIdList[i] = idx++;\n//     }\n//     for (var i = 0; i < oldIdList.length; i++) {\n//         var oldId = oldIdList[i];\n//         // Same with newIdList\n//         if (idIndicesMap[oldId]) {\n//             oldIdList[i] = idIndicesMap[oldId];\n//         }\n//         else {\n//             oldIdList[i] = idx++;\n//         }\n//     }\n// }\n\nfunction diffData(oldData, newData) {\n    var diffResult = [];\n\n    newData.diff(oldData)\n        .add(function (idx) {\n            diffResult.push({cmd: '+', idx: idx});\n        })\n        .update(function (newIdx, oldIdx) {\n            diffResult.push({cmd: '=', idx: oldIdx, idx1: newIdx});\n        })\n        .remove(function (idx) {\n            diffResult.push({cmd: '-', idx: idx});\n        })\n        .execute();\n\n    return diffResult;\n}\n\nvar lineAnimationDiff = function (\n    oldData, newData,\n    oldStackedOnPoints, newStackedOnPoints,\n    oldCoordSys, newCoordSys,\n    oldValueOrigin, newValueOrigin\n) {\n    var diff = diffData(oldData, newData);\n\n    // var newIdList = newData.mapArray(newData.getId);\n    // var oldIdList = oldData.mapArray(oldData.getId);\n\n    // convertToIntId(newIdList, oldIdList);\n\n    // // FIXME One data ?\n    // diff = arrayDiff(oldIdList, newIdList);\n\n    var currPoints = [];\n    var nextPoints = [];\n    // Points for stacking base line\n    var currStackedPoints = [];\n    var nextStackedPoints = [];\n\n    var status = [];\n    var sortedIndices = [];\n    var rawIndices = [];\n\n    var newDataOldCoordInfo = prepareDataCoordInfo(oldCoordSys, newData, oldValueOrigin);\n    var oldDataNewCoordInfo = prepareDataCoordInfo(newCoordSys, oldData, newValueOrigin);\n\n    for (var i = 0; i < diff.length; i++) {\n        var diffItem = diff[i];\n        var pointAdded = true;\n\n        // FIXME, animation is not so perfect when dataZoom window moves fast\n        // Which is in case remvoing or add more than one data in the tail or head\n        switch (diffItem.cmd) {\n            case '=':\n                var currentPt = oldData.getItemLayout(diffItem.idx);\n                var nextPt = newData.getItemLayout(diffItem.idx1);\n                // If previous data is NaN, use next point directly\n                if (isNaN(currentPt[0]) || isNaN(currentPt[1])) {\n                    currentPt = nextPt.slice();\n                }\n                currPoints.push(currentPt);\n                nextPoints.push(nextPt);\n\n                currStackedPoints.push(oldStackedOnPoints[diffItem.idx]);\n                nextStackedPoints.push(newStackedOnPoints[diffItem.idx1]);\n\n                rawIndices.push(newData.getRawIndex(diffItem.idx1));\n                break;\n            case '+':\n                var idx = diffItem.idx;\n                currPoints.push(\n                    oldCoordSys.dataToPoint([\n                        newData.get(newDataOldCoordInfo.dataDimsForPoint[0], idx),\n                        newData.get(newDataOldCoordInfo.dataDimsForPoint[1], idx)\n                    ])\n                );\n\n                nextPoints.push(newData.getItemLayout(idx).slice());\n\n                currStackedPoints.push(\n                    getStackedOnPoint(newDataOldCoordInfo, oldCoordSys, newData, idx)\n                );\n                nextStackedPoints.push(newStackedOnPoints[idx]);\n\n                rawIndices.push(newData.getRawIndex(idx));\n                break;\n            case '-':\n                var idx = diffItem.idx;\n                var rawIndex = oldData.getRawIndex(idx);\n                // Data is replaced. In the case of dynamic data queue\n                // FIXME FIXME FIXME\n                if (rawIndex !== idx) {\n                    currPoints.push(oldData.getItemLayout(idx));\n                    nextPoints.push(newCoordSys.dataToPoint([\n                        oldData.get(oldDataNewCoordInfo.dataDimsForPoint[0], idx),\n                        oldData.get(oldDataNewCoordInfo.dataDimsForPoint[1], idx)\n                    ]));\n\n                    currStackedPoints.push(oldStackedOnPoints[idx]);\n                    nextStackedPoints.push(\n                        getStackedOnPoint(oldDataNewCoordInfo, newCoordSys, oldData, idx)\n                    );\n\n                    rawIndices.push(rawIndex);\n                }\n                else {\n                    pointAdded = false;\n                }\n        }\n\n        // Original indices\n        if (pointAdded) {\n            status.push(diffItem);\n            sortedIndices.push(sortedIndices.length);\n        }\n    }\n\n    // Diff result may be crossed if all items are changed\n    // Sort by data index\n    sortedIndices.sort(function (a, b) {\n        return rawIndices[a] - rawIndices[b];\n    });\n\n    var sortedCurrPoints = [];\n    var sortedNextPoints = [];\n\n    var sortedCurrStackedPoints = [];\n    var sortedNextStackedPoints = [];\n\n    var sortedStatus = [];\n    for (var i = 0; i < sortedIndices.length; i++) {\n        var idx = sortedIndices[i];\n        sortedCurrPoints[i] = currPoints[idx];\n        sortedNextPoints[i] = nextPoints[idx];\n\n        sortedCurrStackedPoints[i] = currStackedPoints[idx];\n        sortedNextStackedPoints[i] = nextStackedPoints[idx];\n\n        sortedStatus[i] = status[idx];\n    }\n\n    return {\n        current: sortedCurrPoints,\n        next: sortedNextPoints,\n\n        stackedOnCurrent: sortedCurrStackedPoints,\n        stackedOnNext: sortedNextStackedPoints,\n\n        status: sortedStatus\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Poly path support NaN point\n\nvar vec2Min = min;\nvar vec2Max = max;\n\nvar scaleAndAdd$1 = scaleAndAdd;\nvar v2Copy = copy;\n\n// Temporary variable\nvar v = [];\nvar cp0 = [];\nvar cp1 = [];\n\nfunction isPointNull(p) {\n    return isNaN(p[0]) || isNaN(p[1]);\n}\n\nfunction drawSegment(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    // if (smoothMonotone == null) {\n    //     if (isMono(points, 'x')) {\n    //         return drawMono(ctx, points, start, segLen, allLen,\n    //             dir, smoothMin, smoothMax, smooth, 'x', connectNulls);\n    //     }\n    //     else if (isMono(points, 'y')) {\n    //         return drawMono(ctx, points, start, segLen, allLen,\n    //             dir, smoothMin, smoothMax, smooth, 'y', connectNulls);\n    //     }\n    //     else {\n    //         return drawNonMono.apply(this, arguments);\n    //     }\n    // }\n    // else if (smoothMonotone !== 'none' && isMono(points, smoothMonotone)) {\n    //     return drawMono.apply(this, arguments);\n    // }\n    // else {\n    //     return drawNonMono.apply(this, arguments);\n    // }\n    if (smoothMonotone === 'none' || !smoothMonotone) {\n        return drawNonMono.apply(this, arguments);\n    }\n    else {\n        return drawMono.apply(this, arguments);\n    }\n}\n\n/**\n * Check if points is in monotone.\n *\n * @param {number[][]} points         Array of points which is in [x, y] form\n * @param {string}     smoothMonotone 'x', 'y', or 'none', stating for which\n *                                    dimension that is checking.\n *                                    If is 'none', `drawNonMono` should be\n *                                    called.\n *                                    If is undefined, either being monotone\n *                                    in 'x' or 'y' will call `drawMono`.\n */\n// function isMono(points, smoothMonotone) {\n//     if (points.length <= 1) {\n//         return true;\n//     }\n\n//     var dim = smoothMonotone === 'x' ? 0 : 1;\n//     var last = points[0][dim];\n//     var lastDiff = 0;\n//     for (var i = 1; i < points.length; ++i) {\n//         var diff = points[i][dim] - last;\n//         if (!isNaN(diff) && !isNaN(lastDiff)\n//             && diff !== 0 && lastDiff !== 0\n//             && ((diff >= 0) !== (lastDiff >= 0))\n//         ) {\n//             return false;\n//         }\n//         if (!isNaN(diff) && diff !== 0) {\n//             lastDiff = diff;\n//             last = points[i][dim];\n//         }\n//     }\n//     return true;\n// }\n\n/**\n * Draw smoothed line in monotone, in which only vertical or horizontal bezier\n * control points will be used. This should be used when points are monotone\n * either in x or y dimension.\n */\nfunction drawMono(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    var prevIdx = 0;\n    var idx = start;\n    for (var k = 0; k < segLen; k++) {\n        var p = points[idx];\n        if (idx >= allLen || idx < 0) {\n            break;\n        }\n        if (isPointNull(p)) {\n            if (connectNulls) {\n                idx += dir;\n                continue;\n            }\n            break;\n        }\n\n        if (idx === start) {\n            ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);\n        }\n        else {\n            if (smooth > 0) {\n                var prevP = points[prevIdx];\n                var dim = smoothMonotone === 'y' ? 1 : 0;\n\n                // Length of control point to p, either in x or y, but not both\n                var ctrlLen = (p[dim] - prevP[dim]) * smooth;\n\n                v2Copy(cp0, prevP);\n                cp0[dim] = prevP[dim] + ctrlLen;\n\n                v2Copy(cp1, p);\n                cp1[dim] = p[dim] - ctrlLen;\n\n                ctx.bezierCurveTo(\n                    cp0[0], cp0[1],\n                    cp1[0], cp1[1],\n                    p[0], p[1]\n                );\n            }\n            else {\n                ctx.lineTo(p[0], p[1]);\n            }\n        }\n\n        prevIdx = idx;\n        idx += dir;\n    }\n\n    return k;\n}\n\n/**\n * Draw smoothed line in non-monotone, in may cause undesired curve in extreme\n * situations. This should be used when points are non-monotone neither in x or\n * y dimension.\n */\nfunction drawNonMono(\n    ctx, points, start, segLen, allLen,\n    dir, smoothMin, smoothMax, smooth, smoothMonotone, connectNulls\n) {\n    var prevIdx = 0;\n    var idx = start;\n    for (var k = 0; k < segLen; k++) {\n        var p = points[idx];\n        if (idx >= allLen || idx < 0) {\n            break;\n        }\n        if (isPointNull(p)) {\n            if (connectNulls) {\n                idx += dir;\n                continue;\n            }\n            break;\n        }\n\n        if (idx === start) {\n            ctx[dir > 0 ? 'moveTo' : 'lineTo'](p[0], p[1]);\n            v2Copy(cp0, p);\n        }\n        else {\n            if (smooth > 0) {\n                var nextIdx = idx + dir;\n                var nextP = points[nextIdx];\n                if (connectNulls) {\n                    // Find next point not null\n                    while (nextP && isPointNull(points[nextIdx])) {\n                        nextIdx += dir;\n                        nextP = points[nextIdx];\n                    }\n                }\n\n                var ratioNextSeg = 0.5;\n                var prevP = points[prevIdx];\n                var nextP = points[nextIdx];\n                // Last point\n                if (!nextP || isPointNull(nextP)) {\n                    v2Copy(cp1, p);\n                }\n                else {\n                    // If next data is null in not connect case\n                    if (isPointNull(nextP) && !connectNulls) {\n                        nextP = p;\n                    }\n\n                    sub(v, nextP, prevP);\n\n                    var lenPrevSeg;\n                    var lenNextSeg;\n                    if (smoothMonotone === 'x' || smoothMonotone === 'y') {\n                        var dim = smoothMonotone === 'x' ? 0 : 1;\n                        lenPrevSeg = Math.abs(p[dim] - prevP[dim]);\n                        lenNextSeg = Math.abs(p[dim] - nextP[dim]);\n                    }\n                    else {\n                        lenPrevSeg = dist(p, prevP);\n                        lenNextSeg = dist(p, nextP);\n                    }\n\n                    // Use ratio of seg length\n                    ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg);\n\n                    scaleAndAdd$1(cp1, p, v, -smooth * (1 - ratioNextSeg));\n                }\n                // Smooth constraint\n                vec2Min(cp0, cp0, smoothMax);\n                vec2Max(cp0, cp0, smoothMin);\n                vec2Min(cp1, cp1, smoothMax);\n                vec2Max(cp1, cp1, smoothMin);\n\n                ctx.bezierCurveTo(\n                    cp0[0], cp0[1],\n                    cp1[0], cp1[1],\n                    p[0], p[1]\n                );\n                // cp0 of next segment\n                scaleAndAdd$1(cp0, p, v, smooth * ratioNextSeg);\n            }\n            else {\n                ctx.lineTo(p[0], p[1]);\n            }\n        }\n\n        prevIdx = idx;\n        idx += dir;\n    }\n\n    return k;\n}\n\nfunction getBoundingBox(points, smoothConstraint) {\n    var ptMin = [Infinity, Infinity];\n    var ptMax = [-Infinity, -Infinity];\n    if (smoothConstraint) {\n        for (var i = 0; i < points.length; i++) {\n            var pt = points[i];\n            if (pt[0] < ptMin[0]) {\n                ptMin[0] = pt[0];\n            }\n            if (pt[1] < ptMin[1]) {\n                ptMin[1] = pt[1];\n            }\n            if (pt[0] > ptMax[0]) {\n                ptMax[0] = pt[0];\n            }\n            if (pt[1] > ptMax[1]) {\n                ptMax[1] = pt[1];\n            }\n        }\n    }\n    return {\n        min: smoothConstraint ? ptMin : ptMax,\n        max: smoothConstraint ? ptMax : ptMin\n    };\n}\n\nvar Polyline$1 = Path.extend({\n\n    type: 'ec-polyline',\n\n    shape: {\n        points: [],\n\n        smooth: 0,\n\n        smoothConstraint: true,\n\n        smoothMonotone: null,\n\n        connectNulls: false\n    },\n\n    style: {\n        fill: null,\n\n        stroke: '#000'\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n        var points = shape.points;\n\n        var i = 0;\n        var len$$1 = points.length;\n\n        var result = getBoundingBox(points, shape.smoothConstraint);\n\n        if (shape.connectNulls) {\n            // Must remove first and last null values avoid draw error in polygon\n            for (; len$$1 > 0; len$$1--) {\n                if (!isPointNull(points[len$$1 - 1])) {\n                    break;\n                }\n            }\n            for (; i < len$$1; i++) {\n                if (!isPointNull(points[i])) {\n                    break;\n                }\n            }\n        }\n        while (i < len$$1) {\n            i += drawSegment(\n                ctx, points, i, len$$1, len$$1,\n                1, result.min, result.max, shape.smooth,\n                shape.smoothMonotone, shape.connectNulls\n            ) + 1;\n        }\n    }\n});\n\nvar Polygon$1 = Path.extend({\n\n    type: 'ec-polygon',\n\n    shape: {\n        points: [],\n\n        // Offset between stacked base points and points\n        stackedOnPoints: [],\n\n        smooth: 0,\n\n        stackedOnSmooth: 0,\n\n        smoothConstraint: true,\n\n        smoothMonotone: null,\n\n        connectNulls: false\n    },\n\n    brush: fixClipWithShadow(Path.prototype.brush),\n\n    buildPath: function (ctx, shape) {\n        var points = shape.points;\n        var stackedOnPoints = shape.stackedOnPoints;\n\n        var i = 0;\n        var len$$1 = points.length;\n        var smoothMonotone = shape.smoothMonotone;\n        var bbox = getBoundingBox(points, shape.smoothConstraint);\n        var stackedOnBBox = getBoundingBox(stackedOnPoints, shape.smoothConstraint);\n\n        if (shape.connectNulls) {\n            // Must remove first and last null values avoid draw error in polygon\n            for (; len$$1 > 0; len$$1--) {\n                if (!isPointNull(points[len$$1 - 1])) {\n                    break;\n                }\n            }\n            for (; i < len$$1; i++) {\n                if (!isPointNull(points[i])) {\n                    break;\n                }\n            }\n        }\n        while (i < len$$1) {\n            var k = drawSegment(\n                ctx, points, i, len$$1, len$$1,\n                1, bbox.min, bbox.max, shape.smooth,\n                smoothMonotone, shape.connectNulls\n            );\n            drawSegment(\n                ctx, stackedOnPoints, i + k - 1, k, len$$1,\n                -1, stackedOnBBox.min, stackedOnBBox.max, shape.stackedOnSmooth,\n                smoothMonotone, shape.connectNulls\n            );\n            i += k + 1;\n\n            ctx.closePath();\n        }\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME step not support polar\n\nfunction isPointsSame(points1, points2) {\n    if (points1.length !== points2.length) {\n        return;\n    }\n    for (var i = 0; i < points1.length; i++) {\n        var p1 = points1[i];\n        var p2 = points2[i];\n        if (p1[0] !== p2[0] || p1[1] !== p2[1]) {\n            return;\n        }\n    }\n    return true;\n}\n\nfunction getSmooth(smooth) {\n    return typeof (smooth) === 'number' ? smooth : (smooth ? 0.5 : 0);\n}\n\nfunction getAxisExtentWithGap(axis) {\n    var extent = axis.getGlobalExtent();\n    if (axis.onBand) {\n        // Remove extra 1px to avoid line miter in clipped edge\n        var halfBandWidth = axis.getBandWidth() / 2 - 1;\n        var dir = extent[1] > extent[0] ? 1 : -1;\n        extent[0] += dir * halfBandWidth;\n        extent[1] -= dir * halfBandWidth;\n    }\n    return extent;\n}\n\n/**\n * @param {module:echarts/coord/cartesian/Cartesian2D|module:echarts/coord/polar/Polar} coordSys\n * @param {module:echarts/data/List} data\n * @param {Object} dataCoordInfo\n * @param {Array.<Array.<number>>} points\n */\nfunction getStackedOnPoints(coordSys, data, dataCoordInfo) {\n    if (!dataCoordInfo.valueDim) {\n        return [];\n    }\n\n    var points = [];\n    for (var idx = 0, len = data.count(); idx < len; idx++) {\n        points.push(getStackedOnPoint(dataCoordInfo, coordSys, data, idx));\n    }\n\n    return points;\n}\n\nfunction createGridClipShape(cartesian, hasAnimation, forSymbol, seriesModel) {\n    var xExtent = getAxisExtentWithGap(cartesian.getAxis('x'));\n    var yExtent = getAxisExtentWithGap(cartesian.getAxis('y'));\n    var isHorizontal = cartesian.getBaseAxis().isHorizontal();\n\n    var x = Math.min(xExtent[0], xExtent[1]);\n    var y = Math.min(yExtent[0], yExtent[1]);\n    var width = Math.max(xExtent[0], xExtent[1]) - x;\n    var height = Math.max(yExtent[0], yExtent[1]) - y;\n\n    // Avoid float number rounding error for symbol on the edge of axis extent.\n    // See #7913 and `test/dataZoom-clip.html`.\n    if (forSymbol) {\n        x -= 0.5;\n        width += 0.5;\n        y -= 0.5;\n        height += 0.5;\n    }\n    else {\n        var lineWidth = seriesModel.get('lineStyle.width') || 2;\n        // Expand clip shape to avoid clipping when line value exceeds axis\n        var expandSize = seriesModel.get('clipOverflow') ? lineWidth / 2 : Math.max(width, height);\n        if (isHorizontal) {\n            y -= expandSize;\n            height += expandSize * 2;\n        }\n        else {\n            x -= expandSize;\n            width += expandSize * 2;\n        }\n    }\n\n    var clipPath = new Rect({\n        shape: {\n            x: x,\n            y: y,\n            width: width,\n            height: height\n        }\n    });\n\n    if (hasAnimation) {\n        clipPath.shape[isHorizontal ? 'width' : 'height'] = 0;\n        initProps(clipPath, {\n            shape: {\n                width: width,\n                height: height\n            }\n        }, seriesModel);\n    }\n\n    return clipPath;\n}\n\nfunction createPolarClipShape(polar, hasAnimation, forSymbol, seriesModel) {\n    var angleAxis = polar.getAngleAxis();\n    var radiusAxis = polar.getRadiusAxis();\n\n    var radiusExtent = radiusAxis.getExtent().slice();\n    radiusExtent[0] > radiusExtent[1] && radiusExtent.reverse();\n    var angleExtent = angleAxis.getExtent();\n\n    var RADIAN = Math.PI / 180;\n\n    // Avoid float number rounding error for symbol on the edge of axis extent.\n    if (forSymbol) {\n        radiusExtent[0] -= 0.5;\n        radiusExtent[1] += 0.5;\n    }\n\n    var clipPath = new Sector({\n        shape: {\n            cx: round$2(polar.cx, 1),\n            cy: round$2(polar.cy, 1),\n            r0: round$2(radiusExtent[0], 1),\n            r: round$2(radiusExtent[1], 1),\n            startAngle: -angleExtent[0] * RADIAN,\n            endAngle: -angleExtent[1] * RADIAN,\n            clockwise: angleAxis.inverse\n        }\n    });\n\n    if (hasAnimation) {\n        clipPath.shape.endAngle = -angleExtent[0] * RADIAN;\n        initProps(clipPath, {\n            shape: {\n                endAngle: -angleExtent[1] * RADIAN\n            }\n        }, seriesModel);\n    }\n\n    return clipPath;\n}\n\nfunction createClipShape(coordSys, hasAnimation, forSymbol, seriesModel) {\n    return coordSys.type === 'polar'\n        ? createPolarClipShape(coordSys, hasAnimation, forSymbol, seriesModel)\n        : createGridClipShape(coordSys, hasAnimation, forSymbol, seriesModel);\n}\n\nfunction turnPointsIntoStep(points, coordSys, stepTurnAt) {\n    var baseAxis = coordSys.getBaseAxis();\n    var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1;\n\n    var stepPoints = [];\n    for (var i = 0; i < points.length - 1; i++) {\n        var nextPt = points[i + 1];\n        var pt = points[i];\n        stepPoints.push(pt);\n\n        var stepPt = [];\n        switch (stepTurnAt) {\n            case 'end':\n                stepPt[baseIndex] = nextPt[baseIndex];\n                stepPt[1 - baseIndex] = pt[1 - baseIndex];\n                // default is start\n                stepPoints.push(stepPt);\n                break;\n            case 'middle':\n                // default is start\n                var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2;\n                var stepPt2 = [];\n                stepPt[baseIndex] = stepPt2[baseIndex] = middle;\n                stepPt[1 - baseIndex] = pt[1 - baseIndex];\n                stepPt2[1 - baseIndex] = nextPt[1 - baseIndex];\n                stepPoints.push(stepPt);\n                stepPoints.push(stepPt2);\n                break;\n            default:\n                stepPt[baseIndex] = pt[baseIndex];\n                stepPt[1 - baseIndex] = nextPt[1 - baseIndex];\n                // default is start\n                stepPoints.push(stepPt);\n        }\n    }\n    // Last points\n    points[i] && stepPoints.push(points[i]);\n    return stepPoints;\n}\n\nfunction getVisualGradient(data, coordSys) {\n    var visualMetaList = data.getVisual('visualMeta');\n    if (!visualMetaList || !visualMetaList.length || !data.count()) {\n        // When data.count() is 0, gradient range can not be calculated.\n        return;\n    }\n\n    if (coordSys.type !== 'cartesian2d') {\n        if (__DEV__) {\n            console.warn('Visual map on line style is only supported on cartesian2d.');\n        }\n        return;\n    }\n\n    var coordDim;\n    var visualMeta;\n\n    for (var i = visualMetaList.length - 1; i >= 0; i--) {\n        var dimIndex = visualMetaList[i].dimension;\n        var dimName = data.dimensions[dimIndex];\n        var dimInfo = data.getDimensionInfo(dimName);\n        coordDim = dimInfo && dimInfo.coordDim;\n        // Can only be x or y\n        if (coordDim === 'x' || coordDim === 'y') {\n            visualMeta = visualMetaList[i];\n            break;\n        }\n    }\n\n    if (!visualMeta) {\n        if (__DEV__) {\n            console.warn('Visual map on line style only support x or y dimension.');\n        }\n        return;\n    }\n\n    // If the area to be rendered is bigger than area defined by LinearGradient,\n    // the canvas spec prescribes that the color of the first stop and the last\n    // stop should be used. But if two stops are added at offset 0, in effect\n    // browsers use the color of the second stop to render area outside\n    // LinearGradient. So we can only infinitesimally extend area defined in\n    // LinearGradient to render `outerColors`.\n\n    var axis = coordSys.getAxis(coordDim);\n\n    // dataToCoor mapping may not be linear, but must be monotonic.\n    var colorStops = map(visualMeta.stops, function (stop) {\n        return {\n            coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)),\n            color: stop.color\n        };\n    });\n    var stopLen = colorStops.length;\n    var outerColors = visualMeta.outerColors.slice();\n\n    if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) {\n        colorStops.reverse();\n        outerColors.reverse();\n    }\n\n    var tinyExtent = 10; // Arbitrary value: 10px\n    var minCoord = colorStops[0].coord - tinyExtent;\n    var maxCoord = colorStops[stopLen - 1].coord + tinyExtent;\n    var coordSpan = maxCoord - minCoord;\n\n    if (coordSpan < 1e-3) {\n        return 'transparent';\n    }\n\n    each$1(colorStops, function (stop) {\n        stop.offset = (stop.coord - minCoord) / coordSpan;\n    });\n    colorStops.push({\n        offset: stopLen ? colorStops[stopLen - 1].offset : 0.5,\n        color: outerColors[1] || 'transparent'\n    });\n    colorStops.unshift({ // notice colorStops.length have been changed.\n        offset: stopLen ? colorStops[0].offset : 0.5,\n        color: outerColors[0] || 'transparent'\n    });\n\n    // zrUtil.each(colorStops, function (colorStop) {\n    //     // Make sure each offset has rounded px to avoid not sharp edge\n    //     colorStop.offset = (Math.round(colorStop.offset * (end - start) + start) - start) / (end - start);\n    // });\n\n    var gradient = new LinearGradient(0, 0, 0, 0, colorStops, true);\n    gradient[coordDim] = minCoord;\n    gradient[coordDim + '2'] = maxCoord;\n\n    return gradient;\n}\n\nfunction getIsIgnoreFunc(seriesModel, data, coordSys) {\n    var showAllSymbol = seriesModel.get('showAllSymbol');\n    var isAuto = showAllSymbol === 'auto';\n\n    if (showAllSymbol && !isAuto) {\n        return;\n    }\n\n    var categoryAxis = coordSys.getAxesByScale('ordinal')[0];\n    if (!categoryAxis) {\n        return;\n    }\n\n    // Note that category label interval strategy might bring some weird effect\n    // in some scenario: users may wonder why some of the symbols are not\n    // displayed. So we show all symbols as possible as we can.\n    if (isAuto\n        // Simplify the logic, do not determine label overlap here.\n        && canShowAllSymbolForCategory(categoryAxis, data)\n    ) {\n        return;\n    }\n\n    // Otherwise follow the label interval strategy on category axis.\n    var categoryDataDim = data.mapDimension(categoryAxis.dim);\n    var labelMap = {};\n\n    each$1(categoryAxis.getViewLabels(), function (labelItem) {\n        labelMap[labelItem.tickValue] = 1;\n    });\n\n    return function (dataIndex) {\n        return !labelMap.hasOwnProperty(data.get(categoryDataDim, dataIndex));\n    };\n}\n\nfunction canShowAllSymbolForCategory(categoryAxis, data) {\n    // In mose cases, line is monotonous on category axis, and the label size\n    // is close with each other. So we check the symbol size and some of the\n    // label size alone with the category axis to estimate whether all symbol\n    // can be shown without overlap.\n    var axisExtent = categoryAxis.getExtent();\n    var availSize = Math.abs(axisExtent[1] - axisExtent[0]) / categoryAxis.scale.count();\n    isNaN(availSize) && (availSize = 0); // 0/0 is NaN.\n\n    // Sampling some points, max 5.\n    var dataLen = data.count();\n    var step = Math.max(1, Math.round(dataLen / 5));\n    for (var dataIndex = 0; dataIndex < dataLen; dataIndex += step) {\n        if (SymbolClz.getSymbolSize(\n                data, dataIndex\n            // Only for cartesian, where `isHorizontal` exists.\n            )[categoryAxis.isHorizontal() ? 1 : 0]\n            // Empirical number\n            * 1.5 > availSize\n        ) {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nChart.extend({\n\n    type: 'line',\n\n    init: function () {\n        var lineGroup = new Group();\n\n        var symbolDraw = new SymbolDraw();\n        this.group.add(symbolDraw.group);\n\n        this._symbolDraw = symbolDraw;\n        this._lineGroup = lineGroup;\n    },\n\n    render: function (seriesModel, ecModel, api) {\n        var coordSys = seriesModel.coordinateSystem;\n        var group = this.group;\n        var data = seriesModel.getData();\n        var lineStyleModel = seriesModel.getModel('lineStyle');\n        var areaStyleModel = seriesModel.getModel('areaStyle');\n\n        var points = data.mapArray(data.getItemLayout);\n\n        var isCoordSysPolar = coordSys.type === 'polar';\n        var prevCoordSys = this._coordSys;\n\n        var symbolDraw = this._symbolDraw;\n        var polyline = this._polyline;\n        var polygon = this._polygon;\n\n        var lineGroup = this._lineGroup;\n\n        var hasAnimation = seriesModel.get('animation');\n\n        var isAreaChart = !areaStyleModel.isEmpty();\n\n        var valueOrigin = areaStyleModel.get('origin');\n        var dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin);\n\n        var stackedOnPoints = getStackedOnPoints(coordSys, data, dataCoordInfo);\n\n        var showSymbol = seriesModel.get('showSymbol');\n\n        var isIgnoreFunc = showSymbol && !isCoordSysPolar\n            && getIsIgnoreFunc(seriesModel, data, coordSys);\n\n        // Remove temporary symbols\n        var oldData = this._data;\n        oldData && oldData.eachItemGraphicEl(function (el, idx) {\n            if (el.__temp) {\n                group.remove(el);\n                oldData.setItemGraphicEl(idx, null);\n            }\n        });\n\n        // Remove previous created symbols if showSymbol changed to false\n        if (!showSymbol) {\n            symbolDraw.remove();\n        }\n\n        group.add(lineGroup);\n\n        // FIXME step not support polar\n        var step = !isCoordSysPolar && seriesModel.get('step');\n        // Initialization animation or coordinate system changed\n        if (\n            !(polyline && prevCoordSys.type === coordSys.type && step === this._step)\n        ) {\n            showSymbol && symbolDraw.updateData(data, {\n                isIgnore: isIgnoreFunc,\n                clipShape: createClipShape(coordSys, false, true, seriesModel)\n            });\n\n            if (step) {\n                // TODO If stacked series is not step\n                points = turnPointsIntoStep(points, coordSys, step);\n                stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);\n            }\n\n            polyline = this._newPolyline(points, coordSys, hasAnimation);\n            if (isAreaChart) {\n                polygon = this._newPolygon(\n                    points, stackedOnPoints,\n                    coordSys, hasAnimation\n                );\n            }\n            lineGroup.setClipPath(createClipShape(coordSys, true, false, seriesModel));\n        }\n        else {\n            if (isAreaChart && !polygon) {\n                // If areaStyle is added\n                polygon = this._newPolygon(\n                    points, stackedOnPoints,\n                    coordSys, hasAnimation\n                );\n            }\n            else if (polygon && !isAreaChart) {\n                // If areaStyle is removed\n                lineGroup.remove(polygon);\n                polygon = this._polygon = null;\n            }\n\n            // Update clipPath\n            lineGroup.setClipPath(createClipShape(coordSys, false, false, seriesModel));\n\n            // Always update, or it is wrong in the case turning on legend\n            // because points are not changed\n            showSymbol && symbolDraw.updateData(data, {\n                isIgnore: isIgnoreFunc,\n                clipShape: createClipShape(coordSys, false, true, seriesModel)\n            });\n\n            // Stop symbol animation and sync with line points\n            // FIXME performance?\n            data.eachItemGraphicEl(function (el) {\n                el.stopAnimation(true);\n            });\n\n            // In the case data zoom triggerred refreshing frequently\n            // Data may not change if line has a category axis. So it should animate nothing\n            if (!isPointsSame(this._stackedOnPoints, stackedOnPoints)\n                || !isPointsSame(this._points, points)\n            ) {\n                if (hasAnimation) {\n                    this._updateAnimation(\n                        data, stackedOnPoints, coordSys, api, step, valueOrigin\n                    );\n                }\n                else {\n                    // Not do it in update with animation\n                    if (step) {\n                        // TODO If stacked series is not step\n                        points = turnPointsIntoStep(points, coordSys, step);\n                        stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step);\n                    }\n\n                    polyline.setShape({\n                        points: points\n                    });\n                    polygon && polygon.setShape({\n                        points: points,\n                        stackedOnPoints: stackedOnPoints\n                    });\n                }\n            }\n        }\n\n        var visualColor = getVisualGradient(data, coordSys) || data.getVisual('color');\n\n        polyline.useStyle(defaults(\n            // Use color in lineStyle first\n            lineStyleModel.getLineStyle(),\n            {\n                fill: 'none',\n                stroke: visualColor,\n                lineJoin: 'bevel'\n            }\n        ));\n\n        var smooth = seriesModel.get('smooth');\n        smooth = getSmooth(seriesModel.get('smooth'));\n        polyline.setShape({\n            smooth: smooth,\n            smoothMonotone: seriesModel.get('smoothMonotone'),\n            connectNulls: seriesModel.get('connectNulls')\n        });\n\n        if (polygon) {\n            var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');\n            var stackedOnSmooth = 0;\n\n            polygon.useStyle(defaults(\n                areaStyleModel.getAreaStyle(),\n                {\n                    fill: visualColor,\n                    opacity: 0.7,\n                    lineJoin: 'bevel'\n                }\n            ));\n\n            if (stackedOnSeries) {\n                stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth'));\n            }\n\n            polygon.setShape({\n                smooth: smooth,\n                stackedOnSmooth: stackedOnSmooth,\n                smoothMonotone: seriesModel.get('smoothMonotone'),\n                connectNulls: seriesModel.get('connectNulls')\n            });\n        }\n\n        this._data = data;\n        // Save the coordinate system for transition animation when data changed\n        this._coordSys = coordSys;\n        this._stackedOnPoints = stackedOnPoints;\n        this._points = points;\n        this._step = step;\n        this._valueOrigin = valueOrigin;\n    },\n\n    dispose: function () {},\n\n    highlight: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n        var dataIndex = queryDataIndex(data, payload);\n\n        if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) {\n            var symbol = data.getItemGraphicEl(dataIndex);\n            if (!symbol) {\n                // Create a temporary symbol if it is not exists\n                var pt = data.getItemLayout(dataIndex);\n                if (!pt) {\n                    // Null data\n                    return;\n                }\n                symbol = new SymbolClz(data, dataIndex);\n                symbol.position = pt;\n                symbol.setZ(\n                    seriesModel.get('zlevel'),\n                    seriesModel.get('z')\n                );\n                symbol.ignore = isNaN(pt[0]) || isNaN(pt[1]);\n                symbol.__temp = true;\n                data.setItemGraphicEl(dataIndex, symbol);\n\n                // Stop scale animation\n                symbol.stopSymbolAnimation(true);\n\n                this.group.add(symbol);\n            }\n            symbol.highlight();\n        }\n        else {\n            // Highlight whole series\n            Chart.prototype.highlight.call(\n                this, seriesModel, ecModel, api, payload\n            );\n        }\n    },\n\n    downplay: function (seriesModel, ecModel, api, payload) {\n        var data = seriesModel.getData();\n        var dataIndex = queryDataIndex(data, payload);\n        if (dataIndex != null && dataIndex >= 0) {\n            var symbol = data.getItemGraphicEl(dataIndex);\n            if (symbol) {\n                if (symbol.__temp) {\n                    data.setItemGraphicEl(dataIndex, null);\n                    this.group.remove(symbol);\n                }\n                else {\n                    symbol.downplay();\n                }\n            }\n        }\n        else {\n            // FIXME\n            // can not downplay completely.\n            // Downplay whole series\n            Chart.prototype.downplay.call(\n                this, seriesModel, ecModel, api, payload\n            );\n        }\n    },\n\n    /**\n     * @param {module:zrender/container/Group} group\n     * @param {Array.<Array.<number>>} points\n     * @private\n     */\n    _newPolyline: function (points) {\n        var polyline = this._polyline;\n        // Remove previous created polyline\n        if (polyline) {\n            this._lineGroup.remove(polyline);\n        }\n\n        polyline = new Polyline$1({\n            shape: {\n                points: points\n            },\n            silent: true,\n            z2: 10\n        });\n\n        this._lineGroup.add(polyline);\n\n        this._polyline = polyline;\n\n        return polyline;\n    },\n\n    /**\n     * @param {module:zrender/container/Group} group\n     * @param {Array.<Array.<number>>} stackedOnPoints\n     * @param {Array.<Array.<number>>} points\n     * @private\n     */\n    _newPolygon: function (points, stackedOnPoints) {\n        var polygon = this._polygon;\n        // Remove previous created polygon\n        if (polygon) {\n            this._lineGroup.remove(polygon);\n        }\n\n        polygon = new Polygon$1({\n            shape: {\n                points: points,\n                stackedOnPoints: stackedOnPoints\n            },\n            silent: true\n        });\n\n        this._lineGroup.add(polygon);\n\n        this._polygon = polygon;\n        return polygon;\n    },\n\n    /**\n     * @private\n     */\n    // FIXME Two value axis\n    _updateAnimation: function (data, stackedOnPoints, coordSys, api, step, valueOrigin) {\n        var polyline = this._polyline;\n        var polygon = this._polygon;\n        var seriesModel = data.hostModel;\n\n        var diff = lineAnimationDiff(\n            this._data, data,\n            this._stackedOnPoints, stackedOnPoints,\n            this._coordSys, coordSys,\n            this._valueOrigin, valueOrigin\n        );\n\n        var current = diff.current;\n        var stackedOnCurrent = diff.stackedOnCurrent;\n        var next = diff.next;\n        var stackedOnNext = diff.stackedOnNext;\n        if (step) {\n            // TODO If stacked series is not step\n            current = turnPointsIntoStep(diff.current, coordSys, step);\n            stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step);\n            next = turnPointsIntoStep(diff.next, coordSys, step);\n            stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step);\n        }\n        // `diff.current` is subset of `current` (which should be ensured by\n        // turnPointsIntoStep), so points in `__points` can be updated when\n        // points in `current` are update during animation.\n        polyline.shape.__points = diff.current;\n        polyline.shape.points = current;\n\n        updateProps(polyline, {\n            shape: {\n                points: next\n            }\n        }, seriesModel);\n\n        if (polygon) {\n            polygon.setShape({\n                points: current,\n                stackedOnPoints: stackedOnCurrent\n            });\n            updateProps(polygon, {\n                shape: {\n                    points: next,\n                    stackedOnPoints: stackedOnNext\n                }\n            }, seriesModel);\n        }\n\n        var updatedDataInfo = [];\n        var diffStatus = diff.status;\n\n        for (var i = 0; i < diffStatus.length; i++) {\n            var cmd = diffStatus[i].cmd;\n            if (cmd === '=') {\n                var el = data.getItemGraphicEl(diffStatus[i].idx1);\n                if (el) {\n                    updatedDataInfo.push({\n                        el: el,\n                        ptIdx: i    // Index of points\n                    });\n                }\n            }\n        }\n\n        if (polyline.animators && polyline.animators.length) {\n            polyline.animators[0].during(function () {\n                for (var i = 0; i < updatedDataInfo.length; i++) {\n                    var el = updatedDataInfo[i].el;\n                    el.attr('position', polyline.shape.__points[updatedDataInfo[i].ptIdx]);\n                }\n            });\n        }\n    },\n\n    remove: function (ecModel) {\n        var group = this.group;\n        var oldData = this._data;\n        this._lineGroup.removeAll();\n        this._symbolDraw.remove(true);\n        // Remove temporary created elements when highlighting\n        oldData && oldData.eachItemGraphicEl(function (el, idx) {\n            if (el.__temp) {\n                group.remove(el);\n                oldData.setItemGraphicEl(idx, null);\n            }\n        });\n\n        this._polyline\n            = this._polygon\n            = this._coordSys\n            = this._points\n            = this._stackedOnPoints\n            = this._data = null;\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar visualSymbol = function (seriesType, defaultSymbolType, legendSymbol) {\n    // Encoding visual for all series include which is filtered for legend drawing\n    return {\n        seriesType: seriesType,\n\n        // For legend.\n        performRawSeries: true,\n\n        reset: function (seriesModel, ecModel, api) {\n            var data = seriesModel.getData();\n\n            var symbolType = seriesModel.get('symbol') || defaultSymbolType;\n            var symbolSize = seriesModel.get('symbolSize');\n            var keepAspect = seriesModel.get('symbolKeepAspect');\n\n            data.setVisual({\n                legendSymbol: legendSymbol || symbolType,\n                symbol: symbolType,\n                symbolSize: symbolSize,\n                symbolKeepAspect: keepAspect\n            });\n\n            // Only visible series has each data be visual encoded\n            if (ecModel.isSeriesFiltered(seriesModel)) {\n                return;\n            }\n\n            var hasCallback = typeof symbolSize === 'function';\n\n            function dataEach(data, idx) {\n                if (typeof symbolSize === 'function') {\n                    var rawValue = seriesModel.getRawValue(idx);\n                    // FIXME\n                    var params = seriesModel.getDataParams(idx);\n                    data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params));\n                }\n\n                if (data.hasItemOption) {\n                    var itemModel = data.getItemModel(idx);\n                    var itemSymbolType = itemModel.getShallow('symbol', true);\n                    var itemSymbolSize = itemModel.getShallow('symbolSize',\n                        true);\n                    var itemSymbolKeepAspect\n                        = itemModel.getShallow('symbolKeepAspect', true);\n\n                    // If has item symbol\n                    if (itemSymbolType != null) {\n                        data.setItemVisual(idx, 'symbol', itemSymbolType);\n                    }\n                    if (itemSymbolSize != null) {\n                        // PENDING Transform symbolSize ?\n                        data.setItemVisual(idx, 'symbolSize', itemSymbolSize);\n                    }\n                    if (itemSymbolKeepAspect != null) {\n                        data.setItemVisual(idx, 'symbolKeepAspect',\n                            itemSymbolKeepAspect);\n                    }\n                }\n            }\n\n            return { dataEach: (data.hasItemOption || hasCallback) ? dataEach : null };\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar layoutPoints = function (seriesType) {\n    return {\n        seriesType: seriesType,\n\n        plan: createRenderPlanner(),\n\n        reset: function (seriesModel) {\n            var data = seriesModel.getData();\n            var coordSys = seriesModel.coordinateSystem;\n            var pipelineContext = seriesModel.pipelineContext;\n            var isLargeRender = pipelineContext.large;\n\n            if (!coordSys) {\n                return;\n            }\n\n            var dims = map(coordSys.dimensions, function (dim) {\n                return data.mapDimension(dim);\n            }).slice(0, 2);\n            var dimLen = dims.length;\n\n            var stackResultDim = data.getCalculationInfo('stackResultDimension');\n            if (isDimensionStacked(data, dims[0] /*, dims[1]*/)) {\n                dims[0] = stackResultDim;\n            }\n            if (isDimensionStacked(data, dims[1] /*, dims[0]*/)) {\n                dims[1] = stackResultDim;\n            }\n\n            function progress(params, data) {\n                var segCount = params.end - params.start;\n                var points = isLargeRender && new Float32Array(segCount * dimLen);\n\n                for (var i = params.start, offset = 0, tmpIn = [], tmpOut = []; i < params.end; i++) {\n                    var point;\n\n                    if (dimLen === 1) {\n                        var x = data.get(dims[0], i);\n                        point = !isNaN(x) && coordSys.dataToPoint(x, null, tmpOut);\n                    }\n                    else {\n                        var x = tmpIn[0] = data.get(dims[0], i);\n                        var y = tmpIn[1] = data.get(dims[1], i);\n                        // Also {Array.<number>}, not undefined to avoid if...else... statement\n                        point = !isNaN(x) && !isNaN(y) && coordSys.dataToPoint(tmpIn, null, tmpOut);\n                    }\n\n                    if (isLargeRender) {\n                        points[offset++] = point ? point[0] : NaN;\n                        points[offset++] = point ? point[1] : NaN;\n                    }\n                    else {\n                        data.setItemLayout(i, (point && point.slice()) || [NaN, NaN]);\n                    }\n                }\n\n                isLargeRender && data.setLayout('symbolPoints', points);\n            }\n\n            return dimLen && {progress: progress};\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar samplers = {\n    average: function (frame) {\n        var sum = 0;\n        var count = 0;\n        for (var i = 0; i < frame.length; i++) {\n            if (!isNaN(frame[i])) {\n                sum += frame[i];\n                count++;\n            }\n        }\n        // Return NaN if count is 0\n        return count === 0 ? NaN : sum / count;\n    },\n    sum: function (frame) {\n        var sum = 0;\n        for (var i = 0; i < frame.length; i++) {\n            // Ignore NaN\n            sum += frame[i] || 0;\n        }\n        return sum;\n    },\n    max: function (frame) {\n        var max = -Infinity;\n        for (var i = 0; i < frame.length; i++) {\n            frame[i] > max && (max = frame[i]);\n        }\n        // NaN will cause illegal axis extent.\n        return isFinite(max) ? max : NaN;\n    },\n    min: function (frame) {\n        var min = Infinity;\n        for (var i = 0; i < frame.length; i++) {\n            frame[i] < min && (min = frame[i]);\n        }\n        // NaN will cause illegal axis extent.\n        return isFinite(min) ? min : NaN;\n    },\n    // TODO\n    // Median\n    nearest: function (frame) {\n        return frame[0];\n    }\n};\n\nvar indexSampler = function (frame, value) {\n    return Math.round(frame.length / 2);\n};\n\nvar dataSample = function (seriesType) {\n    return {\n\n        seriesType: seriesType,\n\n        modifyOutputEnd: true,\n\n        reset: function (seriesModel, ecModel, api) {\n            var data = seriesModel.getData();\n            var sampling = seriesModel.get('sampling');\n            var coordSys = seriesModel.coordinateSystem;\n            // Only cartesian2d support down sampling\n            if (coordSys.type === 'cartesian2d' && sampling) {\n                var baseAxis = coordSys.getBaseAxis();\n                var valueAxis = coordSys.getOtherAxis(baseAxis);\n                var extent = baseAxis.getExtent();\n                // Coordinste system has been resized\n                var size = extent[1] - extent[0];\n                var rate = Math.round(data.count() / size);\n                if (rate > 1) {\n                    var sampler;\n                    if (typeof sampling === 'string') {\n                        sampler = samplers[sampling];\n                    }\n                    else if (typeof sampling === 'function') {\n                        sampler = sampling;\n                    }\n                    if (sampler) {\n                        // Only support sample the first dim mapped from value axis.\n                        seriesModel.setData(data.downSample(\n                            data.mapDimension(valueAxis.dim), 1 / rate, sampler, indexSampler\n                        ));\n                    }\n                }\n            }\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * // Scale class management\n * @module echarts/scale/Scale\n */\n\n/**\n * @param {Object} [setting]\n */\nfunction Scale(setting) {\n    this._setting = setting || {};\n\n    /**\n     * Extent\n     * @type {Array.<number>}\n     * @protected\n     */\n    this._extent = [Infinity, -Infinity];\n\n    /**\n     * Step is calculated in adjustExtent\n     * @type {Array.<number>}\n     * @protected\n     */\n    this._interval = 0;\n\n    this.init && this.init.apply(this, arguments);\n}\n\n/**\n * Parse input val to valid inner number.\n * @param {*} val\n * @return {number}\n */\nScale.prototype.parse = function (val) {\n    // Notice: This would be a trap here, If the implementation\n    // of this method depends on extent, and this method is used\n    // before extent set (like in dataZoom), it would be wrong.\n    // Nevertheless, parse does not depend on extent generally.\n    return val;\n};\n\nScale.prototype.getSetting = function (name) {\n    return this._setting[name];\n};\n\nScale.prototype.contain = function (val) {\n    var extent = this._extent;\n    return val >= extent[0] && val <= extent[1];\n};\n\n/**\n * Normalize value to linear [0, 1], return 0.5 if extent span is 0\n * @param {number} val\n * @return {number}\n */\nScale.prototype.normalize = function (val) {\n    var extent = this._extent;\n    if (extent[1] === extent[0]) {\n        return 0.5;\n    }\n    return (val - extent[0]) / (extent[1] - extent[0]);\n};\n\n/**\n * Scale normalized value\n * @param {number} val\n * @return {number}\n */\nScale.prototype.scale = function (val) {\n    var extent = this._extent;\n    return val * (extent[1] - extent[0]) + extent[0];\n};\n\n/**\n * Set extent from data\n * @param {Array.<number>} other\n */\nScale.prototype.unionExtent = function (other) {\n    var extent = this._extent;\n    other[0] < extent[0] && (extent[0] = other[0]);\n    other[1] > extent[1] && (extent[1] = other[1]);\n    // not setExtent because in log axis it may transformed to power\n    // this.setExtent(extent[0], extent[1]);\n};\n\n/**\n * Set extent from data\n * @param {module:echarts/data/List} data\n * @param {string} dim\n */\nScale.prototype.unionExtentFromData = function (data, dim) {\n    this.unionExtent(data.getApproximateExtent(dim));\n};\n\n/**\n * Get extent\n * @return {Array.<number>}\n */\nScale.prototype.getExtent = function () {\n    return this._extent.slice();\n};\n\n/**\n * Set extent\n * @param {number} start\n * @param {number} end\n */\nScale.prototype.setExtent = function (start, end) {\n    var thisExtent = this._extent;\n    if (!isNaN(start)) {\n        thisExtent[0] = start;\n    }\n    if (!isNaN(end)) {\n        thisExtent[1] = end;\n    }\n};\n\n/**\n * When axis extent depends on data and no data exists,\n * axis ticks should not be drawn, which is named 'blank'.\n */\nScale.prototype.isBlank = function () {\n    return this._isBlank;\n},\n\n/**\n * When axis extent depends on data and no data exists,\n * axis ticks should not be drawn, which is named 'blank'.\n */\nScale.prototype.setBlank = function (isBlank) {\n    this._isBlank = isBlank;\n};\n\n/**\n * @abstract\n * @param {*} tick\n * @return {string} label of the tick.\n */\nScale.prototype.getLabel = null;\n\n\nenableClassExtend(Scale);\nenableClassManagement(Scale, {\n    registerWhenExtend: true\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @constructor\n * @param {Object} [opt]\n * @param {Object} [opt.categories=[]]\n * @param {Object} [opt.needCollect=false]\n * @param {Object} [opt.deduplication=false]\n */\nfunction OrdinalMeta(opt) {\n\n    /**\n     * @readOnly\n     * @type {Array.<string>}\n     */\n    this.categories = opt.categories || [];\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._needCollect = opt.needCollect;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._deduplication = opt.deduplication;\n\n    /**\n     * @private\n     * @type {boolean}\n     */\n    this._map;\n}\n\n/**\n * @param {module:echarts/model/Model} axisModel\n * @return {module:echarts/data/OrdinalMeta}\n */\nOrdinalMeta.createByAxisModel = function (axisModel) {\n    var option = axisModel.option;\n    var data = option.data;\n    var categories = data && map(data, getName);\n\n    return new OrdinalMeta({\n        categories: categories,\n        needCollect: !categories,\n        // deduplication is default in axis.\n        deduplication: option.dedplication !== false\n    });\n};\n\nvar proto$1 = OrdinalMeta.prototype;\n\n/**\n * @param {string} category\n * @return {number} ordinal\n */\nproto$1.getOrdinal = function (category) {\n    return getOrCreateMap(this).get(category);\n};\n\n/**\n * @param {*} category\n * @return {number} The ordinal. If not found, return NaN.\n */\nproto$1.parseAndCollect = function (category) {\n    var index;\n    var needCollect = this._needCollect;\n\n    // The value of category dim can be the index of the given category set.\n    // This feature is only supported when !needCollect, because we should\n    // consider a common case: a value is 2017, which is a number but is\n    // expected to be tread as a category. This case usually happen in dataset,\n    // where it happent to be no need of the index feature.\n    if (typeof category !== 'string' && !needCollect) {\n        return category;\n    }\n\n    // Optimize for the scenario:\n    // category is ['2012-01-01', '2012-01-02', ...], where the input\n    // data has been ensured not duplicate and is large data.\n    // Notice, if a dataset dimension provide categroies, usually echarts\n    // should remove duplication except user tell echarts dont do that\n    // (set axis.deduplication = false), because echarts do not know whether\n    // the values in the category dimension has duplication (consider the\n    // parallel-aqi example)\n    if (needCollect && !this._deduplication) {\n        index = this.categories.length;\n        this.categories[index] = category;\n        return index;\n    }\n\n    var map$$1 = getOrCreateMap(this);\n    index = map$$1.get(category);\n\n    if (index == null) {\n        if (needCollect) {\n            index = this.categories.length;\n            this.categories[index] = category;\n            map$$1.set(category, index);\n        }\n        else {\n            index = NaN;\n        }\n    }\n\n    return index;\n};\n\n// Consider big data, do not create map until needed.\nfunction getOrCreateMap(ordinalMeta) {\n    return ordinalMeta._map || (\n        ordinalMeta._map = createHashMap(ordinalMeta.categories)\n    );\n}\n\nfunction getName(obj) {\n    if (isObject$1(obj) && obj.value != null) {\n        return obj.value;\n    }\n    else {\n        return obj + '';\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Linear continuous scale\n * @module echarts/coord/scale/Ordinal\n *\n * http://en.wikipedia.org/wiki/Level_of_measurement\n */\n\n// FIXME only one data\n\nvar scaleProto = Scale.prototype;\n\nvar OrdinalScale = Scale.extend({\n\n    type: 'ordinal',\n\n    /**\n     * @param {module:echarts/data/OrdianlMeta|Array.<string>} ordinalMeta\n     */\n    init: function (ordinalMeta, extent) {\n        // Caution: Should not use instanceof, consider ec-extensions using\n        // import approach to get OrdinalMeta class.\n        if (!ordinalMeta || isArray(ordinalMeta)) {\n            ordinalMeta = new OrdinalMeta({categories: ordinalMeta});\n        }\n        this._ordinalMeta = ordinalMeta;\n        this._extent = extent || [0, ordinalMeta.categories.length - 1];\n    },\n\n    parse: function (val) {\n        return typeof val === 'string'\n            ? this._ordinalMeta.getOrdinal(val)\n            // val might be float.\n            : Math.round(val);\n    },\n\n    contain: function (rank) {\n        rank = this.parse(rank);\n        return scaleProto.contain.call(this, rank)\n            && this._ordinalMeta.categories[rank] != null;\n    },\n\n    /**\n     * Normalize given rank or name to linear [0, 1]\n     * @param {number|string} [val]\n     * @return {number}\n     */\n    normalize: function (val) {\n        return scaleProto.normalize.call(this, this.parse(val));\n    },\n\n    scale: function (val) {\n        return Math.round(scaleProto.scale.call(this, val));\n    },\n\n    /**\n     * @return {Array}\n     */\n    getTicks: function () {\n        var ticks = [];\n        var extent = this._extent;\n        var rank = extent[0];\n\n        while (rank <= extent[1]) {\n            ticks.push(rank);\n            rank++;\n        }\n\n        return ticks;\n    },\n\n    /**\n     * Get item on rank n\n     * @param {number} n\n     * @return {string}\n     */\n    getLabel: function (n) {\n        if (!this.isBlank()) {\n            // Note that if no data, ordinalMeta.categories is an empty array.\n            return this._ordinalMeta.categories[n];\n        }\n    },\n\n    /**\n     * @return {number}\n     */\n    count: function () {\n        return this._extent[1] - this._extent[0] + 1;\n    },\n\n    /**\n     * @override\n     */\n    unionExtentFromData: function (data, dim) {\n        this.unionExtent(data.getApproximateExtent(dim));\n    },\n\n    getOrdinalMeta: function () {\n        return this._ordinalMeta;\n    },\n\n    niceTicks: noop,\n    niceExtent: noop\n});\n\n/**\n * @return {module:echarts/scale/Time}\n */\nOrdinalScale.create = function () {\n    return new OrdinalScale();\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * For testable.\n */\n\nvar roundNumber$1 = round$2;\n\n/**\n * @param {Array.<number>} extent Both extent[0] and extent[1] should be valid number.\n *                                Should be extent[0] < extent[1].\n * @param {number} splitNumber splitNumber should be >= 1.\n * @param {number} [minInterval]\n * @param {number} [maxInterval]\n * @return {Object} {interval, intervalPrecision, niceTickExtent}\n */\nfunction intervalScaleNiceTicks(extent, splitNumber, minInterval, maxInterval) {\n    var result = {};\n    var span = extent[1] - extent[0];\n\n    var interval = result.interval = nice(span / splitNumber, true);\n    if (minInterval != null && interval < minInterval) {\n        interval = result.interval = minInterval;\n    }\n    if (maxInterval != null && interval > maxInterval) {\n        interval = result.interval = maxInterval;\n    }\n    // Tow more digital for tick.\n    var precision = result.intervalPrecision = getIntervalPrecision(interval);\n    // Niced extent inside original extent\n    var niceTickExtent = result.niceTickExtent = [\n        roundNumber$1(Math.ceil(extent[0] / interval) * interval, precision),\n        roundNumber$1(Math.floor(extent[1] / interval) * interval, precision)\n    ];\n\n    fixExtent(niceTickExtent, extent);\n\n    return result;\n}\n\n/**\n * @param {number} interval\n * @return {number} interval precision\n */\nfunction getIntervalPrecision(interval) {\n    // Tow more digital for tick.\n    return getPrecisionSafe(interval) + 2;\n}\n\nfunction clamp(niceTickExtent, idx, extent) {\n    niceTickExtent[idx] = Math.max(Math.min(niceTickExtent[idx], extent[1]), extent[0]);\n}\n\n// In some cases (e.g., splitNumber is 1), niceTickExtent may be out of extent.\nfunction fixExtent(niceTickExtent, extent) {\n    !isFinite(niceTickExtent[0]) && (niceTickExtent[0] = extent[0]);\n    !isFinite(niceTickExtent[1]) && (niceTickExtent[1] = extent[1]);\n    clamp(niceTickExtent, 0, extent);\n    clamp(niceTickExtent, 1, extent);\n    if (niceTickExtent[0] > niceTickExtent[1]) {\n        niceTickExtent[0] = niceTickExtent[1];\n    }\n}\n\nfunction intervalScaleGetTicks(interval, extent, niceTickExtent, intervalPrecision) {\n    var ticks = [];\n\n    // If interval is 0, return [];\n    if (!interval) {\n        return ticks;\n    }\n\n    // Consider this case: using dataZoom toolbox, zoom and zoom.\n    var safeLimit = 10000;\n\n    if (extent[0] < niceTickExtent[0]) {\n        ticks.push(extent[0]);\n    }\n    var tick = niceTickExtent[0];\n\n    while (tick <= niceTickExtent[1]) {\n        ticks.push(tick);\n        // Avoid rounding error\n        tick = roundNumber$1(tick + interval, intervalPrecision);\n        if (tick === ticks[ticks.length - 1]) {\n            // Consider out of safe float point, e.g.,\n            // -3711126.9907707 + 2e-10 === -3711126.9907707\n            break;\n        }\n        if (ticks.length > safeLimit) {\n            return [];\n        }\n    }\n    // Consider this case: the last item of ticks is smaller\n    // than niceTickExtent[1] and niceTickExtent[1] === extent[1].\n    if (extent[1] > (ticks.length ? ticks[ticks.length - 1] : niceTickExtent[1])) {\n        ticks.push(extent[1]);\n    }\n\n    return ticks;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Interval scale\n * @module echarts/scale/Interval\n */\n\n\nvar roundNumber = round$2;\n\n/**\n * @alias module:echarts/coord/scale/Interval\n * @constructor\n */\nvar IntervalScale = Scale.extend({\n\n    type: 'interval',\n\n    _interval: 0,\n\n    _intervalPrecision: 2,\n\n    setExtent: function (start, end) {\n        var thisExtent = this._extent;\n        //start,end may be a Number like '25',so...\n        if (!isNaN(start)) {\n            thisExtent[0] = parseFloat(start);\n        }\n        if (!isNaN(end)) {\n            thisExtent[1] = parseFloat(end);\n        }\n    },\n\n    unionExtent: function (other) {\n        var extent = this._extent;\n        other[0] < extent[0] && (extent[0] = other[0]);\n        other[1] > extent[1] && (extent[1] = other[1]);\n\n        // unionExtent may called by it's sub classes\n        IntervalScale.prototype.setExtent.call(this, extent[0], extent[1]);\n    },\n    /**\n     * Get interval\n     */\n    getInterval: function () {\n        return this._interval;\n    },\n\n    /**\n     * Set interval\n     */\n    setInterval: function (interval) {\n        this._interval = interval;\n        // Dropped auto calculated niceExtent and use user setted extent\n        // We assume user wan't to set both interval, min, max to get a better result\n        this._niceExtent = this._extent.slice();\n\n        this._intervalPrecision = getIntervalPrecision(interval);\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getTicks: function () {\n        return intervalScaleGetTicks(\n            this._interval, this._extent, this._niceExtent, this._intervalPrecision\n        );\n    },\n\n    /**\n     * @param {number} data\n     * @param {Object} [opt]\n     * @param {number|string} [opt.precision] If 'auto', use nice presision.\n     * @param {boolean} [opt.pad] returns 1.50 but not 1.5 if precision is 2.\n     * @return {string}\n     */\n    getLabel: function (data, opt) {\n        if (data == null) {\n            return '';\n        }\n\n        var precision = opt && opt.precision;\n\n        if (precision == null) {\n            precision = getPrecisionSafe(data) || 0;\n        }\n        else if (precision === 'auto') {\n            // Should be more precise then tick.\n            precision = this._intervalPrecision;\n        }\n\n        // (1) If `precision` is set, 12.005 should be display as '12.00500'.\n        // (2) Use roundNumber (toFixed) to avoid scientific notation like '3.5e-7'.\n        data = roundNumber(data, precision, true);\n\n        return addCommas(data);\n    },\n\n    /**\n     * Update interval and extent of intervals for nice ticks\n     *\n     * @param {number} [splitNumber = 5] Desired number of ticks\n     * @param {number} [minInterval]\n     * @param {number} [maxInterval]\n     */\n    niceTicks: function (splitNumber, minInterval, maxInterval) {\n        splitNumber = splitNumber || 5;\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        if (!isFinite(span)) {\n            return;\n        }\n        // User may set axis min 0 and data are all negative\n        // FIXME If it needs to reverse ?\n        if (span < 0) {\n            span = -span;\n            extent.reverse();\n        }\n\n        var result = intervalScaleNiceTicks(\n            extent, splitNumber, minInterval, maxInterval\n        );\n\n        this._intervalPrecision = result.intervalPrecision;\n        this._interval = result.interval;\n        this._niceExtent = result.niceTickExtent;\n    },\n\n    /**\n     * Nice extent.\n     * @param {Object} opt\n     * @param {number} [opt.splitNumber = 5] Given approx tick number\n     * @param {boolean} [opt.fixMin=false]\n     * @param {boolean} [opt.fixMax=false]\n     * @param {boolean} [opt.minInterval]\n     * @param {boolean} [opt.maxInterval]\n     */\n    niceExtent: function (opt) {\n        var extent = this._extent;\n        // If extent start and end are same, expand them\n        if (extent[0] === extent[1]) {\n            if (extent[0] !== 0) {\n                // Expand extent\n                var expandSize = extent[0];\n                // In the fowllowing case\n                //      Axis has been fixed max 100\n                //      Plus data are all 100 and axis extent are [100, 100].\n                // Extend to the both side will cause expanded max is larger than fixed max.\n                // So only expand to the smaller side.\n                if (!opt.fixMax) {\n                    extent[1] += expandSize / 2;\n                    extent[0] -= expandSize / 2;\n                }\n                else {\n                    extent[0] -= expandSize / 2;\n                }\n            }\n            else {\n                extent[1] = 1;\n            }\n        }\n        var span = extent[1] - extent[0];\n        // If there are no data and extent are [Infinity, -Infinity]\n        if (!isFinite(span)) {\n            extent[0] = 0;\n            extent[1] = 1;\n        }\n\n        this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);\n\n        // var extent = this._extent;\n        var interval = this._interval;\n\n        if (!opt.fixMin) {\n            extent[0] = roundNumber(Math.floor(extent[0] / interval) * interval);\n        }\n        if (!opt.fixMax) {\n            extent[1] = roundNumber(Math.ceil(extent[1] / interval) * interval);\n        }\n    }\n});\n\n/**\n * @return {module:echarts/scale/Time}\n */\nIntervalScale.create = function () {\n    return new IntervalScale();\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global Float32Array */\n\nvar STACK_PREFIX = '__ec_stack_';\nvar LARGE_BAR_MIN_WIDTH = 0.5;\n\nvar LargeArr = typeof Float32Array !== 'undefined' ? Float32Array : Array;\n\nfunction getSeriesStackId(seriesModel) {\n    return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex;\n}\n\nfunction getAxisKey(axis) {\n    return axis.dim + axis.index;\n}\n\n/**\n * @param {Object} opt\n * @param {module:echarts/coord/Axis} opt.axis Only support category axis currently.\n * @param {number} opt.count Positive interger.\n * @param {number} [opt.barWidth]\n * @param {number} [opt.barMaxWidth]\n * @param {number} [opt.barGap]\n * @param {number} [opt.barCategoryGap]\n * @return {Object} {width, offset, offsetCenter} If axis.type is not 'category', return undefined.\n */\n\n\nfunction prepareLayoutBarSeries(seriesType, ecModel) {\n    var seriesModels = [];\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        // Check series coordinate, do layout for cartesian2d only\n        if (isOnCartesian(seriesModel) && !isInLargeMode(seriesModel)) {\n            seriesModels.push(seriesModel);\n        }\n    });\n    return seriesModels;\n}\n\nfunction makeColumnLayout(barSeries) {\n    var seriesInfoList = [];\n    each$1(barSeries, function (seriesModel) {\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var axisExtent = baseAxis.getExtent();\n        var bandWidth = baseAxis.type === 'category'\n            ? baseAxis.getBandWidth()\n            : (Math.abs(axisExtent[1] - axisExtent[0]) / data.count());\n\n        var barWidth = parsePercent$1(\n            seriesModel.get('barWidth'), bandWidth\n        );\n        var barMaxWidth = parsePercent$1(\n            seriesModel.get('barMaxWidth'), bandWidth\n        );\n        var barGap = seriesModel.get('barGap');\n        var barCategoryGap = seriesModel.get('barCategoryGap');\n\n        seriesInfoList.push({\n            bandWidth: bandWidth,\n            barWidth: barWidth,\n            barMaxWidth: barMaxWidth,\n            barGap: barGap,\n            barCategoryGap: barCategoryGap,\n            axisKey: getAxisKey(baseAxis),\n            stackId: getSeriesStackId(seriesModel)\n        });\n    });\n\n    return doCalBarWidthAndOffset(seriesInfoList);\n}\n\nfunction doCalBarWidthAndOffset(seriesInfoList) {\n    // Columns info on each category axis. Key is cartesian name\n    var columnsMap = {};\n\n    each$1(seriesInfoList, function (seriesInfo, idx) {\n        var axisKey = seriesInfo.axisKey;\n        var bandWidth = seriesInfo.bandWidth;\n        var columnsOnAxis = columnsMap[axisKey] || {\n            bandWidth: bandWidth,\n            remainedWidth: bandWidth,\n            autoWidthCount: 0,\n            categoryGap: '20%',\n            gap: '30%',\n            stacks: {}\n        };\n        var stacks = columnsOnAxis.stacks;\n        columnsMap[axisKey] = columnsOnAxis;\n\n        var stackId = seriesInfo.stackId;\n\n        if (!stacks[stackId]) {\n            columnsOnAxis.autoWidthCount++;\n        }\n        stacks[stackId] = stacks[stackId] || {\n            width: 0,\n            maxWidth: 0\n        };\n\n        // Caution: In a single coordinate system, these barGrid attributes\n        // will be shared by series. Consider that they have default values,\n        // only the attributes set on the last series will work.\n        // Do not change this fact unless there will be a break change.\n\n        // TODO\n        var barWidth = seriesInfo.barWidth;\n        if (barWidth && !stacks[stackId].width) {\n            // See #6312, do not restrict width.\n            stacks[stackId].width = barWidth;\n            barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);\n            columnsOnAxis.remainedWidth -= barWidth;\n        }\n\n        var barMaxWidth = seriesInfo.barMaxWidth;\n        barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);\n        var barGap = seriesInfo.barGap;\n        (barGap != null) && (columnsOnAxis.gap = barGap);\n        var barCategoryGap = seriesInfo.barCategoryGap;\n        (barCategoryGap != null) && (columnsOnAxis.categoryGap = barCategoryGap);\n    });\n\n    var result = {};\n\n    each$1(columnsMap, function (columnsOnAxis, coordSysName) {\n\n        result[coordSysName] = {};\n\n        var stacks = columnsOnAxis.stacks;\n        var bandWidth = columnsOnAxis.bandWidth;\n        var categoryGap = parsePercent$1(columnsOnAxis.categoryGap, bandWidth);\n        var barGapPercent = parsePercent$1(columnsOnAxis.gap, 1);\n\n        var remainedWidth = columnsOnAxis.remainedWidth;\n        var autoWidthCount = columnsOnAxis.autoWidthCount;\n        var autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        // Find if any auto calculated bar exceeded maxBarWidth\n        each$1(stacks, function (column, stack) {\n            var maxWidth = column.maxWidth;\n            if (maxWidth && maxWidth < autoWidth) {\n                maxWidth = Math.min(maxWidth, remainedWidth);\n                if (column.width) {\n                    maxWidth = Math.min(maxWidth, column.width);\n                }\n                remainedWidth -= maxWidth;\n                column.width = maxWidth;\n                autoWidthCount--;\n            }\n        });\n\n        // Recalculate width again\n        autoWidth = (remainedWidth - categoryGap)\n            / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);\n        autoWidth = Math.max(autoWidth, 0);\n\n        var widthSum = 0;\n        var lastColumn;\n        each$1(stacks, function (column, idx) {\n            if (!column.width) {\n                column.width = autoWidth;\n            }\n            lastColumn = column;\n            widthSum += column.width * (1 + barGapPercent);\n        });\n        if (lastColumn) {\n            widthSum -= lastColumn.width * barGapPercent;\n        }\n\n        var offset = -widthSum / 2;\n        each$1(stacks, function (column, stackId) {\n            result[coordSysName][stackId] = result[coordSysName][stackId] || {\n                offset: offset,\n                width: column.width\n            };\n\n            offset += column.width * (1 + barGapPercent);\n        });\n    });\n\n    return result;\n}\n\n/**\n * @param {Object} barWidthAndOffset The result of makeColumnLayout\n * @param {module:echarts/coord/Axis} axis\n * @param {module:echarts/model/Series} [seriesModel] If not provided, return all.\n * @return {Object} {stackId: {offset, width}} or {offset, width} if seriesModel provided.\n */\nfunction retrieveColumnLayout(barWidthAndOffset, axis, seriesModel) {\n    if (barWidthAndOffset && axis) {\n        var result = barWidthAndOffset[getAxisKey(axis)];\n        if (result != null && seriesModel != null) {\n            result = result[getSeriesStackId(seriesModel)];\n        }\n        return result;\n    }\n}\n\n/**\n * @param {string} seriesType\n * @param {module:echarts/model/Global} ecModel\n */\nfunction layout(seriesType, ecModel) {\n\n    var seriesModels = prepareLayoutBarSeries(seriesType, ecModel);\n    var barWidthAndOffset = makeColumnLayout(seriesModels);\n\n    var lastStackCoords = {};\n    each$1(seriesModels, function (seriesModel) {\n\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n\n        var stackId = getSeriesStackId(seriesModel);\n        var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId];\n        var columnOffset = columnLayoutInfo.offset;\n        var columnWidth = columnLayoutInfo.width;\n        var valueAxis = cartesian.getOtherAxis(baseAxis);\n\n        var barMinHeight = seriesModel.get('barMinHeight') || 0;\n\n        lastStackCoords[stackId] = lastStackCoords[stackId] || [];\n        data.setLayout({\n            offset: columnOffset,\n            size: columnWidth\n        });\n\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var stacked = isDimensionStacked(data, valueDim /*, baseDim*/);\n        var isValueAxisH = valueAxis.isHorizontal();\n\n        var valueAxisStart = getValueAxisStart(baseAxis, valueAxis, stacked);\n\n        for (var idx = 0, len = data.count(); idx < len; idx++) {\n            var value = data.get(valueDim, idx);\n            var baseValue = data.get(baseDim, idx);\n\n            if (isNaN(value)) {\n                continue;\n            }\n\n            var sign = value >= 0 ? 'p' : 'n';\n            var baseCoord = valueAxisStart;\n\n            // Because of the barMinHeight, we can not use the value in\n            // stackResultDimension directly.\n            if (stacked) {\n                // Only ordinal axis can be stacked.\n                if (!lastStackCoords[stackId][baseValue]) {\n                    lastStackCoords[stackId][baseValue] = {\n                        p: valueAxisStart, // Positive stack\n                        n: valueAxisStart  // Negative stack\n                    };\n                }\n                // Should also consider #4243\n                baseCoord = lastStackCoords[stackId][baseValue][sign];\n            }\n\n            var x;\n            var y;\n            var width;\n            var height;\n\n            if (isValueAxisH) {\n                var coord = cartesian.dataToPoint([value, baseValue]);\n                x = baseCoord;\n                y = coord[1] + columnOffset;\n                width = coord[0] - valueAxisStart;\n                height = columnWidth;\n\n                if (Math.abs(width) < barMinHeight) {\n                    width = (width < 0 ? -1 : 1) * barMinHeight;\n                }\n                stacked && (lastStackCoords[stackId][baseValue][sign] += width);\n            }\n            else {\n                var coord = cartesian.dataToPoint([baseValue, value]);\n                x = coord[0] + columnOffset;\n                y = baseCoord;\n                width = columnWidth;\n                height = coord[1] - valueAxisStart;\n\n                if (Math.abs(height) < barMinHeight) {\n                    // Include zero to has a positive bar\n                    height = (height <= 0 ? -1 : 1) * barMinHeight;\n                }\n                stacked && (lastStackCoords[stackId][baseValue][sign] += height);\n            }\n\n            data.setItemLayout(idx, {\n                x: x,\n                y: y,\n                width: width,\n                height: height\n            });\n        }\n\n    }, this);\n}\n\n// TODO: Do not support stack in large mode yet.\nvar largeLayout = {\n\n    seriesType: 'bar',\n\n    plan: createRenderPlanner(),\n\n    reset: function (seriesModel) {\n        if (!isOnCartesian(seriesModel) || !isInLargeMode(seriesModel)) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var cartesian = seriesModel.coordinateSystem;\n        var baseAxis = cartesian.getBaseAxis();\n        var valueAxis = cartesian.getOtherAxis(baseAxis);\n        var valueDim = data.mapDimension(valueAxis.dim);\n        var baseDim = data.mapDimension(baseAxis.dim);\n        var valueAxisHorizontal = valueAxis.isHorizontal();\n        var valueDimIdx = valueAxisHorizontal ? 0 : 1;\n\n        var barWidth = retrieveColumnLayout(\n            makeColumnLayout([seriesModel]), baseAxis, seriesModel\n        ).width;\n        if (!(barWidth > LARGE_BAR_MIN_WIDTH)) { // jshint ignore:line\n            barWidth = LARGE_BAR_MIN_WIDTH;\n        }\n\n        return {progress: progress};\n\n        function progress(params, data) {\n            var largePoints = new LargeArr(params.count * 2);\n            var dataIndex;\n            var coord = [];\n            var valuePair = [];\n            var offset = 0;\n\n            while ((dataIndex = params.next()) != null) {\n                valuePair[valueDimIdx] = data.get(valueDim, dataIndex);\n                valuePair[1 - valueDimIdx] = data.get(baseDim, dataIndex);\n\n                coord = cartesian.dataToPoint(valuePair, null, coord);\n                largePoints[offset++] = coord[0];\n                largePoints[offset++] = coord[1];\n            }\n\n            data.setLayout({\n                largePoints: largePoints,\n                barWidth: barWidth,\n                valueAxisStart: getValueAxisStart(baseAxis, valueAxis, false),\n                valueAxisHorizontal: valueAxisHorizontal\n            });\n        }\n    }\n};\n\nfunction isOnCartesian(seriesModel) {\n    return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d';\n}\n\nfunction isInLargeMode(seriesModel) {\n    return seriesModel.pipelineContext && seriesModel.pipelineContext.large;\n}\n\n// See cases in `test/bar-start.html` and `#7412`, `#8747`.\nfunction getValueAxisStart(baseAxis, valueAxis, stacked) {\n    var extent = valueAxis.getGlobalExtent();\n    var min;\n    var max;\n    if (extent[0] > extent[1]) {\n        min = extent[1];\n        max = extent[0];\n    }\n    else {\n        min = extent[0];\n        max = extent[1];\n    }\n\n    var valueStart = valueAxis.toGlobalCoord(valueAxis.dataToCoord(0));\n    valueStart < min && (valueStart = min);\n    valueStart > max && (valueStart = max);\n\n    return valueStart;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The \"scaleLevels\" was originally copied from \"d3.js\" with some\n* modifications made for this project.\n* (See more details in the comment on the definition of \"scaleLevels\" below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\n\n// [About UTC and local time zone]:\n// In most cases, `number.parseDate` will treat input data string as local time\n// (except time zone is specified in time string). And `format.formateTime` returns\n// local time by default. option.useUTC is false by default. This design have\n// concidered these common case:\n// (1) Time that is persistent in server is in UTC, but it is needed to be diplayed\n// in local time by default.\n// (2) By default, the input data string (e.g., '2011-01-02') should be displayed\n// as its original time, without any time difference.\n\nvar intervalScaleProto = IntervalScale.prototype;\n\nvar mathCeil = Math.ceil;\nvar mathFloor = Math.floor;\nvar ONE_SECOND = 1000;\nvar ONE_MINUTE = ONE_SECOND * 60;\nvar ONE_HOUR = ONE_MINUTE * 60;\nvar ONE_DAY = ONE_HOUR * 24;\n\n// FIXME 公用？\nvar bisect = function (a, x, lo, hi) {\n    while (lo < hi) {\n        var mid = lo + hi >>> 1;\n        if (a[mid][1] < x) {\n            lo = mid + 1;\n        }\n        else {\n            hi = mid;\n        }\n    }\n    return lo;\n};\n\n/**\n * @alias module:echarts/coord/scale/Time\n * @constructor\n */\nvar TimeScale = IntervalScale.extend({\n    type: 'time',\n\n    /**\n     * @override\n     */\n    getLabel: function (val) {\n        var stepLvl = this._stepLvl;\n\n        var date = new Date(val);\n\n        return formatTime(stepLvl[0], date, this.getSetting('useUTC'));\n    },\n\n    /**\n     * @override\n     */\n    niceExtent: function (opt) {\n        var extent = this._extent;\n        // If extent start and end are same, expand them\n        if (extent[0] === extent[1]) {\n            // Expand extent\n            extent[0] -= ONE_DAY;\n            extent[1] += ONE_DAY;\n        }\n        // If there are no data and extent are [Infinity, -Infinity]\n        if (extent[1] === -Infinity && extent[0] === Infinity) {\n            var d = new Date();\n            extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate());\n            extent[0] = extent[1] - ONE_DAY;\n        }\n\n        this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);\n\n        // var extent = this._extent;\n        var interval = this._interval;\n\n        if (!opt.fixMin) {\n            extent[0] = round$2(mathFloor(extent[0] / interval) * interval);\n        }\n        if (!opt.fixMax) {\n            extent[1] = round$2(mathCeil(extent[1] / interval) * interval);\n        }\n    },\n\n    /**\n     * @override\n     */\n    niceTicks: function (approxTickNum, minInterval, maxInterval) {\n        approxTickNum = approxTickNum || 10;\n\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        var approxInterval = span / approxTickNum;\n\n        if (minInterval != null && approxInterval < minInterval) {\n            approxInterval = minInterval;\n        }\n        if (maxInterval != null && approxInterval > maxInterval) {\n            approxInterval = maxInterval;\n        }\n\n        var scaleLevelsLen = scaleLevels.length;\n        var idx = bisect(scaleLevels, approxInterval, 0, scaleLevelsLen);\n\n        var level = scaleLevels[Math.min(idx, scaleLevelsLen - 1)];\n        var interval = level[1];\n        // Same with interval scale if span is much larger than 1 year\n        if (level[0] === 'year') {\n            var yearSpan = span / interval;\n\n            // From \"Nice Numbers for Graph Labels\" of Graphic Gems\n            // var niceYearSpan = numberUtil.nice(yearSpan, false);\n            var yearStep = nice(yearSpan / approxTickNum, true);\n\n            interval *= yearStep;\n        }\n\n        var timezoneOffset = this.getSetting('useUTC')\n            ? 0 : (new Date(+extent[0] || +extent[1])).getTimezoneOffset() * 60 * 1000;\n        var niceExtent = [\n            Math.round(mathCeil((extent[0] - timezoneOffset) / interval) * interval + timezoneOffset),\n            Math.round(mathFloor((extent[1] - timezoneOffset) / interval) * interval + timezoneOffset)\n        ];\n\n        fixExtent(niceExtent, extent);\n\n        this._stepLvl = level;\n        // Interval will be used in getTicks\n        this._interval = interval;\n        this._niceExtent = niceExtent;\n    },\n\n    parse: function (val) {\n        // val might be float.\n        return +parseDate(val);\n    }\n});\n\neach$1(['contain', 'normalize'], function (methodName) {\n    TimeScale.prototype[methodName] = function (val) {\n        return intervalScaleProto[methodName].call(this, this.parse(val));\n    };\n});\n\n/**\n * This implementation was originally copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/b516d77fb8566b576088e73410437494717ada26/src/time/scale.js>\n * with some modifications made for this program.\n * See the license statement at the head of this file.\n */\nvar scaleLevels = [\n    // Format              interval\n    ['hh:mm:ss', ONE_SECOND],          // 1s\n    ['hh:mm:ss', ONE_SECOND * 5],      // 5s\n    ['hh:mm:ss', ONE_SECOND * 10],     // 10s\n    ['hh:mm:ss', ONE_SECOND * 15],     // 15s\n    ['hh:mm:ss', ONE_SECOND * 30],     // 30s\n    ['hh:mm\\nMM-dd', ONE_MINUTE],      // 1m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 5],  // 5m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 10], // 10m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 15], // 15m\n    ['hh:mm\\nMM-dd', ONE_MINUTE * 30], // 30m\n    ['hh:mm\\nMM-dd', ONE_HOUR],        // 1h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 2],    // 2h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 6],    // 6h\n    ['hh:mm\\nMM-dd', ONE_HOUR * 12],   // 12h\n    ['MM-dd\\nyyyy', ONE_DAY],          // 1d\n    ['MM-dd\\nyyyy', ONE_DAY * 2],      // 2d\n    ['MM-dd\\nyyyy', ONE_DAY * 3],      // 3d\n    ['MM-dd\\nyyyy', ONE_DAY * 4],      // 4d\n    ['MM-dd\\nyyyy', ONE_DAY * 5],      // 5d\n    ['MM-dd\\nyyyy', ONE_DAY * 6],      // 6d\n    ['week', ONE_DAY * 7],             // 7d\n    ['MM-dd\\nyyyy', ONE_DAY * 10],     // 10d\n    ['week', ONE_DAY * 14],            // 2w\n    ['week', ONE_DAY * 21],            // 3w\n    ['month', ONE_DAY * 31],           // 1M\n    ['week', ONE_DAY * 42],            // 6w\n    ['month', ONE_DAY * 62],           // 2M\n    ['week', ONE_DAY * 70],            // 10w\n    ['quarter', ONE_DAY * 95],         // 3M\n    ['month', ONE_DAY * 31 * 4],       // 4M\n    ['month', ONE_DAY * 31 * 5],       // 5M\n    ['half-year', ONE_DAY * 380 / 2],  // 6M\n    ['month', ONE_DAY * 31 * 8],       // 8M\n    ['month', ONE_DAY * 31 * 10],      // 10M\n    ['year', ONE_DAY * 380]            // 1Y\n];\n\n/**\n * @param {module:echarts/model/Model}\n * @return {module:echarts/scale/Time}\n */\nTimeScale.create = function (model) {\n    return new TimeScale({useUTC: model.ecModel.get('useUTC')});\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Log scale\n * @module echarts/scale/Log\n */\n\n// Use some method of IntervalScale\nvar scaleProto$1 = Scale.prototype;\nvar intervalScaleProto$1 = IntervalScale.prototype;\n\nvar getPrecisionSafe$1 = getPrecisionSafe;\nvar roundingErrorFix = round$2;\n\nvar mathFloor$1 = Math.floor;\nvar mathCeil$1 = Math.ceil;\nvar mathPow$1 = Math.pow;\n\nvar mathLog = Math.log;\n\nvar LogScale = Scale.extend({\n\n    type: 'log',\n\n    base: 10,\n\n    $constructor: function () {\n        Scale.apply(this, arguments);\n        this._originalScale = new IntervalScale();\n    },\n\n    /**\n     * @return {Array.<number>}\n     */\n    getTicks: function () {\n        var originalScale = this._originalScale;\n        var extent = this._extent;\n        var originalExtent = originalScale.getExtent();\n\n        return map(intervalScaleProto$1.getTicks.call(this), function (val) {\n            var powVal = round$2(mathPow$1(this.base, val));\n\n            // Fix #4158\n            powVal = (val === extent[0] && originalScale.__fixMin)\n                ? fixRoundingError(powVal, originalExtent[0])\n                : powVal;\n            powVal = (val === extent[1] && originalScale.__fixMax)\n                ? fixRoundingError(powVal, originalExtent[1])\n                : powVal;\n\n            return powVal;\n        }, this);\n    },\n\n    /**\n     * @param {number} val\n     * @return {string}\n     */\n    getLabel: intervalScaleProto$1.getLabel,\n\n    /**\n     * @param  {number} val\n     * @return {number}\n     */\n    scale: function (val) {\n        val = scaleProto$1.scale.call(this, val);\n        return mathPow$1(this.base, val);\n    },\n\n    /**\n     * @param {number} start\n     * @param {number} end\n     */\n    setExtent: function (start, end) {\n        var base = this.base;\n        start = mathLog(start) / mathLog(base);\n        end = mathLog(end) / mathLog(base);\n        intervalScaleProto$1.setExtent.call(this, start, end);\n    },\n\n    /**\n     * @return {number} end\n     */\n    getExtent: function () {\n        var base = this.base;\n        var extent = scaleProto$1.getExtent.call(this);\n        extent[0] = mathPow$1(base, extent[0]);\n        extent[1] = mathPow$1(base, extent[1]);\n\n        // Fix #4158\n        var originalScale = this._originalScale;\n        var originalExtent = originalScale.getExtent();\n        originalScale.__fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0]));\n        originalScale.__fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1]));\n\n        return extent;\n    },\n\n    /**\n     * @param  {Array.<number>} extent\n     */\n    unionExtent: function (extent) {\n        this._originalScale.unionExtent(extent);\n\n        var base = this.base;\n        extent[0] = mathLog(extent[0]) / mathLog(base);\n        extent[1] = mathLog(extent[1]) / mathLog(base);\n        scaleProto$1.unionExtent.call(this, extent);\n    },\n\n    /**\n     * @override\n     */\n    unionExtentFromData: function (data, dim) {\n        // TODO\n        // filter value that <= 0\n        this.unionExtent(data.getApproximateExtent(dim));\n    },\n\n    /**\n     * Update interval and extent of intervals for nice ticks\n     * @param  {number} [approxTickNum = 10] Given approx tick number\n     */\n    niceTicks: function (approxTickNum) {\n        approxTickNum = approxTickNum || 10;\n        var extent = this._extent;\n        var span = extent[1] - extent[0];\n        if (span === Infinity || span <= 0) {\n            return;\n        }\n\n        var interval = quantity(span);\n        var err = approxTickNum / span * interval;\n\n        // Filter ticks to get closer to the desired count.\n        if (err <= 0.5) {\n            interval *= 10;\n        }\n\n        // Interval should be integer\n        while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) {\n            interval *= 10;\n        }\n\n        var niceExtent = [\n            round$2(mathCeil$1(extent[0] / interval) * interval),\n            round$2(mathFloor$1(extent[1] / interval) * interval)\n        ];\n\n        this._interval = interval;\n        this._niceExtent = niceExtent;\n    },\n\n    /**\n     * Nice extent.\n     * @override\n     */\n    niceExtent: function (opt) {\n        intervalScaleProto$1.niceExtent.call(this, opt);\n\n        var originalScale = this._originalScale;\n        originalScale.__fixMin = opt.fixMin;\n        originalScale.__fixMax = opt.fixMax;\n    }\n\n});\n\neach$1(['contain', 'normalize'], function (methodName) {\n    LogScale.prototype[methodName] = function (val) {\n        val = mathLog(val) / mathLog(this.base);\n        return scaleProto$1[methodName].call(this, val);\n    };\n});\n\nLogScale.create = function () {\n    return new LogScale();\n};\n\nfunction fixRoundingError(val, originalVal) {\n    return roundingErrorFix(val, getPrecisionSafe$1(originalVal));\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Get axis scale extent before niced.\n * Item of returned array can only be number (including Infinity and NaN).\n */\nfunction getScaleExtent(scale, model) {\n    var scaleType = scale.type;\n\n    var min = model.getMin();\n    var max = model.getMax();\n    var fixMin = min != null;\n    var fixMax = max != null;\n    var originalExtent = scale.getExtent();\n\n    var axisDataLen;\n    var boundaryGap;\n    var span;\n    if (scaleType === 'ordinal') {\n        axisDataLen = model.getCategories().length;\n    }\n    else {\n        boundaryGap = model.get('boundaryGap');\n        if (!isArray(boundaryGap)) {\n            boundaryGap = [boundaryGap || 0, boundaryGap || 0];\n        }\n        if (typeof boundaryGap[0] === 'boolean') {\n            if (__DEV__) {\n                console.warn('Boolean type for boundaryGap is only '\n                    + 'allowed for ordinal axis. Please use string in '\n                    + 'percentage instead, e.g., \"20%\". Currently, '\n                    + 'boundaryGap is set to be 0.');\n            }\n            boundaryGap = [0, 0];\n        }\n        boundaryGap[0] = parsePercent$1(boundaryGap[0], 1);\n        boundaryGap[1] = parsePercent$1(boundaryGap[1], 1);\n        span = (originalExtent[1] - originalExtent[0])\n            || Math.abs(originalExtent[0]);\n    }\n\n    // Notice: When min/max is not set (that is, when there are null/undefined,\n    // which is the most common case), these cases should be ensured:\n    // (1) For 'ordinal', show all axis.data.\n    // (2) For others:\n    //      + `boundaryGap` is applied (if min/max set, boundaryGap is\n    //      disabled).\n    //      + If `needCrossZero`, min/max should be zero, otherwise, min/max should\n    //      be the result that originalExtent enlarged by boundaryGap.\n    // (3) If no data, it should be ensured that `scale.setBlank` is set.\n\n    // FIXME\n    // (1) When min/max is 'dataMin' or 'dataMax', should boundaryGap be able to used?\n    // (2) When `needCrossZero` and all data is positive/negative, should it be ensured\n    // that the results processed by boundaryGap are positive/negative?\n\n    if (min == null) {\n        min = scaleType === 'ordinal'\n            ? (axisDataLen ? 0 : NaN)\n            : originalExtent[0] - boundaryGap[0] * span;\n    }\n    if (max == null) {\n        max = scaleType === 'ordinal'\n            ? (axisDataLen ? axisDataLen - 1 : NaN)\n            : originalExtent[1] + boundaryGap[1] * span;\n    }\n\n    if (min === 'dataMin') {\n        min = originalExtent[0];\n    }\n    else if (typeof min === 'function') {\n        min = min({\n            min: originalExtent[0],\n            max: originalExtent[1]\n        });\n    }\n\n    if (max === 'dataMax') {\n        max = originalExtent[1];\n    }\n    else if (typeof max === 'function') {\n        max = max({\n            min: originalExtent[0],\n            max: originalExtent[1]\n        });\n    }\n\n    (min == null || !isFinite(min)) && (min = NaN);\n    (max == null || !isFinite(max)) && (max = NaN);\n\n    scale.setBlank(\n        eqNaN(min)\n        || eqNaN(max)\n        || (scaleType === 'ordinal' && !scale.getOrdinalMeta().categories.length)\n    );\n\n    // Evaluate if axis needs cross zero\n    if (model.getNeedCrossZero()) {\n        // Axis is over zero and min is not set\n        if (min > 0 && max > 0 && !fixMin) {\n            min = 0;\n        }\n        // Axis is under zero and max is not set\n        if (min < 0 && max < 0 && !fixMax) {\n            max = 0;\n        }\n    }\n\n    // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis\n    // is base axis\n    // FIXME\n    // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly.\n    // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent?\n    //     Should not depend on series type `bar`?\n    // (3) Fix that might overlap when using dataZoom.\n    // (4) Consider other chart types using `barGrid`?\n    // See #6728, #4862, `test/bar-overflow-time-plot.html`\n    var ecModel = model.ecModel;\n    if (ecModel && (scaleType === 'time' /*|| scaleType === 'interval' */)) {\n        var barSeriesModels = prepareLayoutBarSeries('bar', ecModel);\n        var isBaseAxisAndHasBarSeries;\n\n        each$1(barSeriesModels, function (seriesModel) {\n            isBaseAxisAndHasBarSeries |= seriesModel.getBaseAxis() === model.axis;\n        });\n\n        if (isBaseAxisAndHasBarSeries) {\n            // Calculate placement of bars on axis\n            var barWidthAndOffset = makeColumnLayout(barSeriesModels);\n\n            // Adjust axis min and max to account for overflow\n            var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset);\n            min = adjustedScale.min;\n            max = adjustedScale.max;\n        }\n    }\n\n    return [min, max];\n}\n\nfunction adjustScaleForOverflow(min, max, model, barWidthAndOffset) {\n\n    // Get Axis Length\n    var axisExtent = model.axis.getExtent();\n    var axisLength = axisExtent[1] - axisExtent[0];\n\n    // Get bars on current base axis and calculate min and max overflow\n    var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis);\n    if (barsOnCurrentAxis === undefined) {\n        return {min: min, max: max};\n    }\n\n    var minOverflow = Infinity;\n    each$1(barsOnCurrentAxis, function (item) {\n        minOverflow = Math.min(item.offset, minOverflow);\n    });\n    var maxOverflow = -Infinity;\n    each$1(barsOnCurrentAxis, function (item) {\n        maxOverflow = Math.max(item.offset + item.width, maxOverflow);\n    });\n    minOverflow = Math.abs(minOverflow);\n    maxOverflow = Math.abs(maxOverflow);\n    var totalOverFlow = minOverflow + maxOverflow;\n\n    // Calulate required buffer based on old range and overflow\n    var oldRange = max - min;\n    var oldRangePercentOfNew = (1 - (minOverflow + maxOverflow) / axisLength);\n    var overflowBuffer = ((oldRange / oldRangePercentOfNew) - oldRange);\n\n    max += overflowBuffer * (maxOverflow / totalOverFlow);\n    min -= overflowBuffer * (minOverflow / totalOverFlow);\n\n    return {min: min, max: max};\n}\n\nfunction niceScaleExtent(scale, model) {\n    var extent = getScaleExtent(scale, model);\n    var fixMin = model.getMin() != null;\n    var fixMax = model.getMax() != null;\n    var splitNumber = model.get('splitNumber');\n\n    if (scale.type === 'log') {\n        scale.base = model.get('logBase');\n    }\n\n    var scaleType = scale.type;\n    scale.setExtent(extent[0], extent[1]);\n    scale.niceExtent({\n        splitNumber: splitNumber,\n        fixMin: fixMin,\n        fixMax: fixMax,\n        minInterval: (scaleType === 'interval' || scaleType === 'time')\n            ? model.get('minInterval') : null,\n        maxInterval: (scaleType === 'interval' || scaleType === 'time')\n            ? model.get('maxInterval') : null\n    });\n\n    // If some one specified the min, max. And the default calculated interval\n    // is not good enough. He can specify the interval. It is often appeared\n    // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard\n    // to be 60.\n    // FIXME\n    var interval = model.get('interval');\n    if (interval != null) {\n        scale.setInterval && scale.setInterval(interval);\n    }\n}\n\n/**\n * @param {module:echarts/model/Model} model\n * @param {string} [axisType] Default retrieve from model.type\n * @return {module:echarts/scale/*}\n */\nfunction createScaleByModel(model, axisType) {\n    axisType = axisType || model.get('type');\n    if (axisType) {\n        switch (axisType) {\n            // Buildin scale\n            case 'category':\n                return new OrdinalScale(\n                    model.getOrdinalMeta\n                        ? model.getOrdinalMeta()\n                        : model.getCategories(),\n                    [Infinity, -Infinity]\n                );\n            case 'value':\n                return new IntervalScale();\n            // Extended scale, like time and log\n            default:\n                return (Scale.getClass(axisType) || IntervalScale).create(model);\n        }\n    }\n}\n\n/**\n * Check if the axis corss 0\n */\nfunction ifAxisCrossZero(axis) {\n    var dataExtent = axis.scale.getExtent();\n    var min = dataExtent[0];\n    var max = dataExtent[1];\n    return !((min > 0 && max > 0) || (min < 0 && max < 0));\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @return {Function} Label formatter function.\n *         param: {number} tickValue,\n *         param: {number} idx, the index in all ticks.\n *                         If category axis, this param is not requied.\n *         return: {string} label string.\n */\nfunction makeLabelFormatter(axis) {\n    var labelFormatter = axis.getLabelModel().get('formatter');\n    var categoryTickStart = axis.type === 'category' ? axis.scale.getExtent()[0] : null;\n\n    if (typeof labelFormatter === 'string') {\n        labelFormatter = (function (tpl) {\n            return function (val) {\n                // For category axis, get raw value; for numeric axis,\n                // get foramtted label like '1,333,444'.\n                val = axis.scale.getLabel(val);\n                return tpl.replace('{value}', val != null ? val : '');\n            };\n        })(labelFormatter);\n        // Consider empty array\n        return labelFormatter;\n    }\n    else if (typeof labelFormatter === 'function') {\n        return function (tickValue, idx) {\n            // The original intention of `idx` is \"the index of the tick in all ticks\".\n            // But the previous implementation of category axis do not consider the\n            // `axisLabel.interval`, which cause that, for example, the `interval` is\n            // `1`, then the ticks \"name5\", \"name7\", \"name9\" are displayed, where the\n            // corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep\n            // the definition here for back compatibility.\n            if (categoryTickStart != null) {\n                idx = tickValue - categoryTickStart;\n            }\n            return labelFormatter(getAxisRawValue(axis, tickValue), idx);\n        };\n    }\n    else {\n        return function (tick) {\n            return axis.scale.getLabel(tick);\n        };\n    }\n}\n\nfunction getAxisRawValue(axis, value) {\n    // In category axis with data zoom, tick is not the original\n    // index of axis.data. So tick should not be exposed to user\n    // in category axis.\n    return axis.type === 'category' ? axis.scale.getLabel(value) : value;\n}\n\n/**\n * @param {module:echarts/coord/Axis} axis\n * @return {module:zrender/core/BoundingRect} Be null/undefined if no labels.\n */\nfunction estimateLabelUnionRect(axis) {\n    var axisModel = axis.model;\n    var scale = axis.scale;\n\n    if (!axisModel.get('axisLabel.show') || scale.isBlank()) {\n        return;\n    }\n\n    var isCategory = axis.type === 'category';\n\n    var realNumberScaleTicks;\n    var tickCount;\n    var categoryScaleExtent = scale.getExtent();\n\n    // Optimize for large category data, avoid call `getTicks()`.\n    if (isCategory) {\n        tickCount = scale.count();\n    }\n    else {\n        realNumberScaleTicks = scale.getTicks();\n        tickCount = realNumberScaleTicks.length;\n    }\n\n    var axisLabelModel = axis.getLabelModel();\n    var labelFormatter = makeLabelFormatter(axis);\n\n    var rect;\n    var step = 1;\n    // Simple optimization for large amount of labels\n    if (tickCount > 40) {\n        step = Math.ceil(tickCount / 40);\n    }\n    for (var i = 0; i < tickCount; i += step) {\n        var tickValue = realNumberScaleTicks ? realNumberScaleTicks[i] : categoryScaleExtent[0] + i;\n        var label = labelFormatter(tickValue);\n        var unrotatedSingleRect = axisLabelModel.getTextRect(label);\n        var singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0);\n\n        rect ? rect.union(singleRect) : (rect = singleRect);\n    }\n\n    return rect;\n}\n\nfunction rotateTextRect(textRect, rotate) {\n    var rotateRadians = rotate * Math.PI / 180;\n    var boundingBox = textRect.plain();\n    var beforeWidth = boundingBox.width;\n    var beforeHeight = boundingBox.height;\n    var afterWidth = beforeWidth * Math.cos(rotateRadians) + beforeHeight * Math.sin(rotateRadians);\n    var afterHeight = beforeWidth * Math.sin(rotateRadians) + beforeHeight * Math.cos(rotateRadians);\n    var rotatedRect = new BoundingRect(boundingBox.x, boundingBox.y, afterWidth, afterHeight);\n\n    return rotatedRect;\n}\n\n/**\n * @param {module:echarts/src/model/Model} model axisLabelModel or axisTickModel\n * @return {number|String} Can be null|'auto'|number|function\n */\nfunction getOptionCategoryInterval(model) {\n    var interval = model.get('interval');\n    return interval == null ? 'auto' : interval;\n}\n\n/**\n * Set `categoryInterval` as 0 implicitly indicates that\n * show all labels reguardless of overlap.\n * @param {Object} axis axisModel.axis\n * @return {boolean}\n */\nfunction shouldShowAllLabels(axis) {\n    return axis.type === 'category'\n        && getOptionCategoryInterval(axis.getLabelModel()) === 0;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Cartesian coordinate system\n * @module  echarts/coord/Cartesian\n *\n */\n\nfunction dimAxisMapper(dim) {\n    return this._axes[dim];\n}\n\n/**\n * @alias module:echarts/coord/Cartesian\n * @constructor\n */\nvar Cartesian = function (name) {\n    this._axes = {};\n\n    this._dimList = [];\n\n    /**\n     * @type {string}\n     */\n    this.name = name || '';\n};\n\nCartesian.prototype = {\n\n    constructor: Cartesian,\n\n    type: 'cartesian',\n\n    /**\n     * Get axis\n     * @param  {number|string} dim\n     * @return {module:echarts/coord/Cartesian~Axis}\n     */\n    getAxis: function (dim) {\n        return this._axes[dim];\n    },\n\n    /**\n     * Get axes list\n     * @return {Array.<module:echarts/coord/Cartesian~Axis>}\n     */\n    getAxes: function () {\n        return map(this._dimList, dimAxisMapper, this);\n    },\n\n    /**\n     * Get axes list by given scale type\n     */\n    getAxesByScale: function (scaleType) {\n        scaleType = scaleType.toLowerCase();\n        return filter(\n            this.getAxes(),\n            function (axis) {\n                return axis.scale.type === scaleType;\n            }\n        );\n    },\n\n    /**\n     * Add axis\n     * @param {module:echarts/coord/Cartesian.Axis}\n     */\n    addAxis: function (axis) {\n        var dim = axis.dim;\n\n        this._axes[dim] = axis;\n\n        this._dimList.push(dim);\n    },\n\n    /**\n     * Convert data to coord in nd space\n     * @param {Array.<number>|Object.<string, number>} val\n     * @return {Array.<number>|Object.<string, number>}\n     */\n    dataToCoord: function (val) {\n        return this._dataCoordConvert(val, 'dataToCoord');\n    },\n\n    /**\n     * Convert coord in nd space to data\n     * @param  {Array.<number>|Object.<string, number>} val\n     * @return {Array.<number>|Object.<string, number>}\n     */\n    coordToData: function (val) {\n        return this._dataCoordConvert(val, 'coordToData');\n    },\n\n    _dataCoordConvert: function (input, method) {\n        var dimList = this._dimList;\n\n        var output = input instanceof Array ? [] : {};\n\n        for (var i = 0; i < dimList.length; i++) {\n            var dim = dimList[i];\n            var axis = this._axes[dim];\n\n            output[dim] = axis[method](input[dim]);\n        }\n\n        return output;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nfunction Cartesian2D(name) {\n\n    Cartesian.call(this, name);\n}\n\nCartesian2D.prototype = {\n\n    constructor: Cartesian2D,\n\n    type: 'cartesian2d',\n\n    /**\n     * @type {Array.<string>}\n     * @readOnly\n     */\n    dimensions: ['x', 'y'],\n\n    /**\n     * Base axis will be used on stacking.\n     *\n     * @return {module:echarts/coord/cartesian/Axis2D}\n     */\n    getBaseAxis: function () {\n        return this.getAxesByScale('ordinal')[0]\n            || this.getAxesByScale('time')[0]\n            || this.getAxis('x');\n    },\n\n    /**\n     * If contain point\n     * @param {Array.<number>} point\n     * @return {boolean}\n     */\n    containPoint: function (point) {\n        var axisX = this.getAxis('x');\n        var axisY = this.getAxis('y');\n        return axisX.contain(axisX.toLocalCoord(point[0]))\n            && axisY.contain(axisY.toLocalCoord(point[1]));\n    },\n\n    /**\n     * If contain data\n     * @param {Array.<number>} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this.getAxis('x').containData(data[0])\n            && this.getAxis('y').containData(data[1]);\n    },\n\n    /**\n     * @param {Array.<number>} data\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    dataToPoint: function (data, reserved, out) {\n        var xAxis = this.getAxis('x');\n        var yAxis = this.getAxis('y');\n        out = out || [];\n        out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(data[0]));\n        out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(data[1]));\n        return out;\n    },\n\n    /**\n     * @param {Array.<number>} data\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    clampData: function (data, out) {\n        var xScale = this.getAxis('x').scale;\n        var yScale = this.getAxis('y').scale;\n        var xAxisExtent = xScale.getExtent();\n        var yAxisExtent = yScale.getExtent();\n        var x = xScale.parse(data[0]);\n        var y = yScale.parse(data[1]);\n        out = out || [];\n        out[0] = Math.min(\n            Math.max(Math.min(xAxisExtent[0], xAxisExtent[1]), x),\n            Math.max(xAxisExtent[0], xAxisExtent[1])\n        );\n        out[1] = Math.min(\n            Math.max(Math.min(yAxisExtent[0], yAxisExtent[1]), y),\n            Math.max(yAxisExtent[0], yAxisExtent[1])\n        );\n\n        return out;\n    },\n\n    /**\n     * @param {Array.<number>} point\n     * @param {Array.<number>} out\n     * @return {Array.<number>}\n     */\n    pointToData: function (point, out) {\n        var xAxis = this.getAxis('x');\n        var yAxis = this.getAxis('y');\n        out = out || [];\n        out[0] = xAxis.coordToData(xAxis.toLocalCoord(point[0]));\n        out[1] = yAxis.coordToData(yAxis.toLocalCoord(point[1]));\n        return out;\n    },\n\n    /**\n     * Get other axis\n     * @param {module:echarts/coord/cartesian/Axis2D} axis\n     */\n    getOtherAxis: function (axis) {\n        return this.getAxis(axis.dim === 'x' ? 'y' : 'x');\n    }\n\n};\n\ninherits(Cartesian2D, Cartesian);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar inner$6 = makeInner();\n\n/**\n * @param {module:echats/coord/Axis} axis\n * @return {Object} {\n *     labels: [{\n *         formattedLabel: string,\n *         rawLabel: string,\n *         tickValue: number\n *     }, ...],\n *     labelCategoryInterval: number\n * }\n */\nfunction createAxisLabels(axis) {\n    // Only ordinal scale support tick interval\n    return axis.type === 'category'\n        ? makeCategoryLabels(axis)\n        : makeRealNumberLabels(axis);\n}\n\n/**\n * @param {module:echats/coord/Axis} axis\n * @param {module:echarts/model/Model} tickModel For example, can be axisTick, splitLine, splitArea.\n * @return {Object} {\n *     ticks: Array.<number>\n *     tickCategoryInterval: number\n * }\n */\nfunction createAxisTicks(axis, tickModel) {\n    // Only ordinal scale support tick interval\n    return axis.type === 'category'\n        ? makeCategoryTicks(axis, tickModel)\n        : {ticks: axis.scale.getTicks()};\n}\n\nfunction makeCategoryLabels(axis) {\n    var labelModel = axis.getLabelModel();\n    var result = makeCategoryLabelsActually(axis, labelModel);\n\n    return (!labelModel.get('show') || axis.scale.isBlank())\n        ? {labels: [], labelCategoryInterval: result.labelCategoryInterval}\n        : result;\n}\n\nfunction makeCategoryLabelsActually(axis, labelModel) {\n    var labelsCache = getListCache(axis, 'labels');\n    var optionLabelInterval = getOptionCategoryInterval(labelModel);\n    var result = listCacheGet(labelsCache, optionLabelInterval);\n\n    if (result) {\n        return result;\n    }\n\n    var labels;\n    var numericLabelInterval;\n\n    if (isFunction$1(optionLabelInterval)) {\n        labels = makeLabelsByCustomizedCategoryInterval(axis, optionLabelInterval);\n    }\n    else {\n        numericLabelInterval = optionLabelInterval === 'auto'\n            ? makeAutoCategoryInterval(axis) : optionLabelInterval;\n        labels = makeLabelsByNumericCategoryInterval(axis, numericLabelInterval);\n    }\n\n    // Cache to avoid calling interval function repeatly.\n    return listCacheSet(labelsCache, optionLabelInterval, {\n        labels: labels, labelCategoryInterval: numericLabelInterval\n    });\n}\n\nfunction makeCategoryTicks(axis, tickModel) {\n    var ticksCache = getListCache(axis, 'ticks');\n    var optionTickInterval = getOptionCategoryInterval(tickModel);\n    var result = listCacheGet(ticksCache, optionTickInterval);\n\n    if (result) {\n        return result;\n    }\n\n    var ticks;\n    var tickCategoryInterval;\n\n    // Optimize for the case that large category data and no label displayed,\n    // we should not return all ticks.\n    if (!tickModel.get('show') || axis.scale.isBlank()) {\n        ticks = [];\n    }\n\n    if (isFunction$1(optionTickInterval)) {\n        ticks = makeLabelsByCustomizedCategoryInterval(axis, optionTickInterval, true);\n    }\n    // Always use label interval by default despite label show. Consider this\n    // scenario, Use multiple grid with the xAxis sync, and only one xAxis shows\n    // labels. `splitLine` and `axisTick` should be consistent in this case.\n    else if (optionTickInterval === 'auto') {\n        var labelsResult = makeCategoryLabelsActually(axis, axis.getLabelModel());\n        tickCategoryInterval = labelsResult.labelCategoryInterval;\n        ticks = map(labelsResult.labels, function (labelItem) {\n            return labelItem.tickValue;\n        });\n    }\n    else {\n        tickCategoryInterval = optionTickInterval;\n        ticks = makeLabelsByNumericCategoryInterval(axis, tickCategoryInterval, true);\n    }\n\n    // Cache to avoid calling interval function repeatly.\n    return listCacheSet(ticksCache, optionTickInterval, {\n        ticks: ticks, tickCategoryInterval: tickCategoryInterval\n    });\n}\n\nfunction makeRealNumberLabels(axis) {\n    var ticks = axis.scale.getTicks();\n    var labelFormatter = makeLabelFormatter(axis);\n    return {\n        labels: map(ticks, function (tickValue, idx) {\n            return {\n                formattedLabel: labelFormatter(tickValue, idx),\n                rawLabel: axis.scale.getLabel(tickValue),\n                tickValue: tickValue\n            };\n        })\n    };\n}\n\n// Large category data calculation is performence sensitive, and ticks and label\n// probably be fetched by multiple times. So we cache the result.\n// axis is created each time during a ec process, so we do not need to clear cache.\nfunction getListCache(axis, prop) {\n    // Because key can be funciton, and cache size always be small, we use array cache.\n    return inner$6(axis)[prop] || (inner$6(axis)[prop] = []);\n}\n\nfunction listCacheGet(cache, key) {\n    for (var i = 0; i < cache.length; i++) {\n        if (cache[i].key === key) {\n            return cache[i].value;\n        }\n    }\n}\n\nfunction listCacheSet(cache, key, value) {\n    cache.push({key: key, value: value});\n    return value;\n}\n\nfunction makeAutoCategoryInterval(axis) {\n    var result = inner$6(axis).autoInterval;\n    return result != null\n        ? result\n        : (inner$6(axis).autoInterval = axis.calculateCategoryInterval());\n}\n\n/**\n * Calculate interval for category axis ticks and labels.\n * To get precise result, at least one of `getRotate` and `isHorizontal`\n * should be implemented in axis.\n */\nfunction calculateCategoryInterval(axis) {\n    var params = fetchAutoCategoryIntervalCalculationParams(axis);\n    var labelFormatter = makeLabelFormatter(axis);\n    var rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI;\n\n    var ordinalScale = axis.scale;\n    var ordinalExtent = ordinalScale.getExtent();\n    // Providing this method is for optimization:\n    // avoid generating a long array by `getTicks`\n    // in large category data case.\n    var tickCount = ordinalScale.count();\n\n    if (ordinalExtent[1] - ordinalExtent[0] < 1) {\n        return 0;\n    }\n\n    var step = 1;\n    // Simple optimization. Empirical value: tick count should less than 40.\n    if (tickCount > 40) {\n        step = Math.max(1, Math.floor(tickCount / 40));\n    }\n    var tickValue = ordinalExtent[0];\n    var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue);\n    var unitW = Math.abs(unitSpan * Math.cos(rotation));\n    var unitH = Math.abs(unitSpan * Math.sin(rotation));\n\n    var maxW = 0;\n    var maxH = 0;\n\n    // Caution: Performance sensitive for large category data.\n    // Consider dataZoom, we should make appropriate step to avoid O(n) loop.\n    for (; tickValue <= ordinalExtent[1]; tickValue += step) {\n        var width = 0;\n        var height = 0;\n\n        // Not precise, do not consider align and vertical align\n        // and each distance from axis line yet.\n        var rect = getBoundingRect(\n            labelFormatter(tickValue), params.font, 'center', 'top'\n        );\n        // Magic number\n        width = rect.width * 1.3;\n        height = rect.height * 1.3;\n\n        // Min size, void long loop.\n        maxW = Math.max(maxW, width, 7);\n        maxH = Math.max(maxH, height, 7);\n    }\n\n    var dw = maxW / unitW;\n    var dh = maxH / unitH;\n    // 0/0 is NaN, 1/0 is Infinity.\n    isNaN(dw) && (dw = Infinity);\n    isNaN(dh) && (dh = Infinity);\n    var interval = Math.max(0, Math.floor(Math.min(dw, dh)));\n\n    var cache = inner$6(axis.model);\n    var lastAutoInterval = cache.lastAutoInterval;\n    var lastTickCount = cache.lastTickCount;\n\n    // Use cache to keep interval stable while moving zoom window,\n    // otherwise the calculated interval might jitter when the zoom\n    // window size is close to the interval-changing size.\n    if (lastAutoInterval != null\n        && lastTickCount != null\n        && Math.abs(lastAutoInterval - interval) <= 1\n        && Math.abs(lastTickCount - tickCount) <= 1\n        // Always choose the bigger one, otherwise the critical\n        // point is not the same when zooming in or zooming out.\n        && lastAutoInterval > interval\n    ) {\n        interval = lastAutoInterval;\n    }\n    // Only update cache if cache not used, otherwise the\n    // changing of interval is too insensitive.\n    else {\n        cache.lastTickCount = tickCount;\n        cache.lastAutoInterval = interval;\n    }\n\n    return interval;\n}\n\nfunction fetchAutoCategoryIntervalCalculationParams(axis) {\n    var labelModel = axis.getLabelModel();\n    return {\n        axisRotate: axis.getRotate\n            ? axis.getRotate()\n            : (axis.isHorizontal && !axis.isHorizontal())\n            ? 90\n            : 0,\n        labelRotate: labelModel.get('rotate') || 0,\n        font: labelModel.getFont()\n    };\n}\n\nfunction makeLabelsByNumericCategoryInterval(axis, categoryInterval, onlyTick) {\n    var labelFormatter = makeLabelFormatter(axis);\n    var ordinalScale = axis.scale;\n    var ordinalExtent = ordinalScale.getExtent();\n    var labelModel = axis.getLabelModel();\n    var result = [];\n\n    // TODO: axisType: ordinalTime, pick the tick from each month/day/year/...\n\n    var step = Math.max((categoryInterval || 0) + 1, 1);\n    var startTick = ordinalExtent[0];\n    var tickCount = ordinalScale.count();\n\n    // Calculate start tick based on zero if possible to keep label consistent\n    // while zooming and moving while interval > 0. Otherwise the selection\n    // of displayable ticks and symbols probably keep changing.\n    // 3 is empirical value.\n    if (startTick !== 0 && step > 1 && tickCount / step > 2) {\n        startTick = Math.round(Math.ceil(startTick / step) * step);\n    }\n\n    // (1) Only add min max label here but leave overlap checking\n    // to render stage, which also ensure the returned list\n    // suitable for splitLine and splitArea rendering.\n    // (2) Scales except category always contain min max label so\n    // do not need to perform this process.\n    var showAllLabel = shouldShowAllLabels(axis);\n    var includeMinLabel = labelModel.get('showMinLabel') || showAllLabel;\n    var includeMaxLabel = labelModel.get('showMaxLabel') || showAllLabel;\n\n    if (includeMinLabel && startTick !== ordinalExtent[0]) {\n        addItem(ordinalExtent[0]);\n    }\n\n    // Optimize: avoid generating large array by `ordinalScale.getTicks()`.\n    var tickValue = startTick;\n    for (; tickValue <= ordinalExtent[1]; tickValue += step) {\n        addItem(tickValue);\n    }\n\n    if (includeMaxLabel && tickValue !== ordinalExtent[1]) {\n        addItem(ordinalExtent[1]);\n    }\n\n    function addItem(tVal) {\n        result.push(onlyTick\n            ? tVal\n            : {\n                formattedLabel: labelFormatter(tVal),\n                rawLabel: ordinalScale.getLabel(tVal),\n                tickValue: tVal\n            }\n        );\n    }\n\n    return result;\n}\n\n// When interval is function, the result `false` means ignore the tick.\n// It is time consuming for large category data.\nfunction makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) {\n    var ordinalScale = axis.scale;\n    var labelFormatter = makeLabelFormatter(axis);\n    var result = [];\n\n    each$1(ordinalScale.getTicks(), function (tickValue) {\n        var rawLabel = ordinalScale.getLabel(tickValue);\n        if (categoryInterval(tickValue, rawLabel)) {\n            result.push(onlyTick\n                ? tickValue\n                : {\n                    formattedLabel: labelFormatter(tickValue),\n                    rawLabel: rawLabel,\n                    tickValue: tickValue\n                }\n            );\n        }\n    });\n\n    return result;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar NORMALIZED_EXTENT = [0, 1];\n\n/**\n * Base class of Axis.\n * @constructor\n */\nvar Axis = function (dim, scale, extent) {\n\n    /**\n     * Axis dimension. Such as 'x', 'y', 'z', 'angle', 'radius'.\n     * @type {string}\n     */\n    this.dim = dim;\n\n    /**\n     * Axis scale\n     * @type {module:echarts/coord/scale/*}\n     */\n    this.scale = scale;\n\n    /**\n     * @type {Array.<number>}\n     * @private\n     */\n    this._extent = extent || [0, 0];\n\n    /**\n     * @type {boolean}\n     */\n    this.inverse = false;\n\n    /**\n     * Usually true when axis has a ordinal scale\n     * @type {boolean}\n     */\n    this.onBand = false;\n};\n\nAxis.prototype = {\n\n    constructor: Axis,\n\n    /**\n     * If axis extent contain given coord\n     * @param {number} coord\n     * @return {boolean}\n     */\n    contain: function (coord) {\n        var extent = this._extent;\n        var min = Math.min(extent[0], extent[1]);\n        var max = Math.max(extent[0], extent[1]);\n        return coord >= min && coord <= max;\n    },\n\n    /**\n     * If axis extent contain given data\n     * @param {number} data\n     * @return {boolean}\n     */\n    containData: function (data) {\n        return this.contain(this.dataToCoord(data));\n    },\n\n    /**\n     * Get coord extent.\n     * @return {Array.<number>}\n     */\n    getExtent: function () {\n        return this._extent.slice();\n    },\n\n    /**\n     * Get precision used for formatting\n     * @param {Array.<number>} [dataExtent]\n     * @return {number}\n     */\n    getPixelPrecision: function (dataExtent) {\n        return getPixelPrecision(\n            dataExtent || this.scale.getExtent(),\n            this._extent\n        );\n    },\n\n    /**\n     * Set coord extent\n     * @param {number} start\n     * @param {number} end\n     */\n    setExtent: function (start, end) {\n        var extent = this._extent;\n        extent[0] = start;\n        extent[1] = end;\n    },\n\n    /**\n     * Convert data to coord. Data is the rank if it has an ordinal scale\n     * @param {number} data\n     * @param  {boolean} clamp\n     * @return {number}\n     */\n    dataToCoord: function (data, clamp) {\n        var extent = this._extent;\n        var scale = this.scale;\n        data = scale.normalize(data);\n\n        if (this.onBand && scale.type === 'ordinal') {\n            extent = extent.slice();\n            fixExtentWithBands(extent, scale.count());\n        }\n\n        return linearMap(data, NORMALIZED_EXTENT, extent, clamp);\n    },\n\n    /**\n     * Convert coord to data. Data is the rank if it has an ordinal scale\n     * @param {number} coord\n     * @param  {boolean} clamp\n     * @return {number}\n     */\n    coordToData: function (coord, clamp) {\n        var extent = this._extent;\n        var scale = this.scale;\n\n        if (this.onBand && scale.type === 'ordinal') {\n            extent = extent.slice();\n            fixExtentWithBands(extent, scale.count());\n        }\n\n        var t = linearMap(coord, extent, NORMALIZED_EXTENT, clamp);\n\n        return this.scale.scale(t);\n    },\n\n    /**\n     * Convert pixel point to data in axis\n     * @param {Array.<number>} point\n     * @param  {boolean} clamp\n     * @return {number} data\n     */\n    pointToData: function (point, clamp) {\n        // Should be implemented in derived class if necessary.\n    },\n\n    /**\n     * Different from `zrUtil.map(axis.getTicks(), axis.dataToCoord, axis)`,\n     * `axis.getTicksCoords` considers `onBand`, which is used by\n     * `boundaryGap:true` of category axis and splitLine and splitArea.\n     * @param {Object} [opt]\n     * @param {number} [opt.tickModel=axis.model.getModel('axisTick')]\n     * @param {boolean} [opt.clamp] If `true`, the first and the last\n     *        tick must be at the axis end points. Otherwise, clip ticks\n     *        that outside the axis extent.\n     * @return {Array.<Object>} [{\n     *     coord: ...,\n     *     tickValue: ...\n     * }, ...]\n     */\n    getTicksCoords: function (opt) {\n        opt = opt || {};\n\n        var tickModel = opt.tickModel || this.getTickModel();\n\n        var result = createAxisTicks(this, tickModel);\n        var ticks = result.ticks;\n\n        var ticksCoords = map(ticks, function (tickValue) {\n            return {\n                coord: this.dataToCoord(tickValue),\n                tickValue: tickValue\n            };\n        }, this);\n\n        var alignWithLabel = tickModel.get('alignWithLabel');\n        fixOnBandTicksCoords(\n            this, ticksCoords, result.tickCategoryInterval, alignWithLabel, opt.clamp\n        );\n\n        return ticksCoords;\n    },\n\n    /**\n     * @return {Array.<Object>} [{\n     *     formattedLabel: string,\n     *     rawLabel: axis.scale.getLabel(tickValue)\n     *     tickValue: number\n     * }, ...]\n     */\n    getViewLabels: function () {\n        return createAxisLabels(this).labels;\n    },\n\n    /**\n     * @return {module:echarts/coord/model/Model}\n     */\n    getLabelModel: function () {\n        return this.model.getModel('axisLabel');\n    },\n\n    /**\n     * Notice here we only get the default tick model. For splitLine\n     * or splitArea, we should pass the splitLineModel or splitAreaModel\n     * manually when calling `getTicksCoords`.\n     * In GL, this method may be overrided to:\n     * `axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));`\n     * @return {module:echarts/coord/model/Model}\n     */\n    getTickModel: function () {\n        return this.model.getModel('axisTick');\n    },\n\n    /**\n     * Get width of band\n     * @return {number}\n     */\n    getBandWidth: function () {\n        var axisExtent = this._extent;\n        var dataExtent = this.scale.getExtent();\n\n        var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0);\n        // Fix #2728, avoid NaN when only one data.\n        len === 0 && (len = 1);\n\n        var size = Math.abs(axisExtent[1] - axisExtent[0]);\n\n        return Math.abs(size) / len;\n    },\n\n    /**\n     * @abstract\n     * @return {boolean} Is horizontal\n     */\n    isHorizontal: null,\n\n    /**\n     * @abstract\n     * @return {number} Get axis rotate, by degree.\n     */\n    getRotate: null,\n\n    /**\n     * Only be called in category axis.\n     * Can be overrided, consider other axes like in 3D.\n     * @return {number} Auto interval for cateogry axis tick and label\n     */\n    calculateCategoryInterval: function () {\n        return calculateCategoryInterval(this);\n    }\n\n};\n\nfunction fixExtentWithBands(extent, nTick) {\n    var size = extent[1] - extent[0];\n    var len = nTick;\n    var margin = size / len / 2;\n    extent[0] += margin;\n    extent[1] -= margin;\n}\n\n// If axis has labels [1, 2, 3, 4]. Bands on the axis are\n// |---1---|---2---|---3---|---4---|.\n// So the displayed ticks and splitLine/splitArea should between\n// each data item, otherwise cause misleading (e.g., split tow bars\n// of a single data item when there are two bar series).\n// Also consider if tickCategoryInterval > 0 and onBand, ticks and\n// splitLine/spliteArea should layout appropriately corresponding\n// to displayed labels. (So we should not use `getBandWidth` in this\n// case).\nfunction fixOnBandTicksCoords(axis, ticksCoords, tickCategoryInterval, alignWithLabel, clamp) {\n    var ticksLen = ticksCoords.length;\n\n    if (!axis.onBand || alignWithLabel || !ticksLen) {\n        return;\n    }\n\n    var axisExtent = axis.getExtent();\n    var last;\n    if (ticksLen === 1) {\n        ticksCoords[0].coord = axisExtent[0];\n        last = ticksCoords[1] = {coord: axisExtent[0]};\n    }\n    else {\n        var shift = (ticksCoords[1].coord - ticksCoords[0].coord);\n        each$1(ticksCoords, function (ticksItem) {\n            ticksItem.coord -= shift / 2;\n            var tickCategoryInterval = tickCategoryInterval || 0;\n            // Avoid split a single data item when odd interval.\n            if (tickCategoryInterval % 2 > 0) {\n                ticksItem.coord -= shift / ((tickCategoryInterval + 1) * 2);\n            }\n        });\n        last = {coord: ticksCoords[ticksLen - 1].coord + shift};\n        ticksCoords.push(last);\n    }\n\n    var inverse = axisExtent[0] > axisExtent[1];\n\n    if (littleThan(ticksCoords[0].coord, axisExtent[0])) {\n        clamp ? (ticksCoords[0].coord = axisExtent[0]) : ticksCoords.shift();\n    }\n    if (clamp && littleThan(axisExtent[0], ticksCoords[0].coord)) {\n        ticksCoords.unshift({coord: axisExtent[0]});\n    }\n    if (littleThan(axisExtent[1], last.coord)) {\n        clamp ? (last.coord = axisExtent[1]) : ticksCoords.pop();\n    }\n    if (clamp && littleThan(last.coord, axisExtent[1])) {\n        ticksCoords.push({coord: axisExtent[1]});\n    }\n\n    function littleThan(a, b) {\n        return inverse ? a > b : a < b;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Extend axis 2d\n * @constructor module:echarts/coord/cartesian/Axis2D\n * @extends {module:echarts/coord/cartesian/Axis}\n * @param {string} dim\n * @param {*} scale\n * @param {Array.<number>} coordExtent\n * @param {string} axisType\n * @param {string} position\n */\nvar Axis2D = function (dim, scale, coordExtent, axisType, position) {\n    Axis.call(this, dim, scale, coordExtent);\n    /**\n     * Axis type\n     *  - 'category'\n     *  - 'value'\n     *  - 'time'\n     *  - 'log'\n     * @type {string}\n     */\n    this.type = axisType || 'value';\n\n    /**\n     * Axis position\n     *  - 'top'\n     *  - 'bottom'\n     *  - 'left'\n     *  - 'right'\n     */\n    this.position = position || 'bottom';\n};\n\nAxis2D.prototype = {\n\n    constructor: Axis2D,\n\n    /**\n     * Index of axis, can be used as key\n     */\n    index: 0,\n\n    /**\n     * Implemented in <module:echarts/coord/cartesian/Grid>.\n     * @return {Array.<module:echarts/coord/cartesian/Axis2D>}\n     *         If not on zero of other axis, return null/undefined.\n     *         If no axes, return an empty array.\n     */\n    getAxesOnZeroOf: null,\n\n    /**\n     * Axis model\n     * @param {module:echarts/coord/cartesian/AxisModel}\n     */\n    model: null,\n\n    isHorizontal: function () {\n        var position = this.position;\n        return position === 'top' || position === 'bottom';\n    },\n\n    /**\n     * Each item cooresponds to this.getExtent(), which\n     * means globalExtent[0] may greater than globalExtent[1],\n     * unless `asc` is input.\n     *\n     * @param {boolean} [asc]\n     * @return {Array.<number>}\n     */\n    getGlobalExtent: function (asc) {\n        var ret = this.getExtent();\n        ret[0] = this.toGlobalCoord(ret[0]);\n        ret[1] = this.toGlobalCoord(ret[1]);\n        asc && ret[0] > ret[1] && ret.reverse();\n        return ret;\n    },\n\n    getOtherAxis: function () {\n        this.grid.getOtherAxis();\n    },\n\n    /**\n     * @override\n     */\n    pointToData: function (point, clamp) {\n        return this.coordToData(this.toLocalCoord(point[this.dim === 'x' ? 0 : 1]), clamp);\n    },\n\n    /**\n     * Transform global coord to local coord,\n     * i.e. var localCoord = axis.toLocalCoord(80);\n     * designate by module:echarts/coord/cartesian/Grid.\n     * @type {Function}\n     */\n    toLocalCoord: null,\n\n    /**\n     * Transform global coord to local coord,\n     * i.e. var globalCoord = axis.toLocalCoord(40);\n     * designate by module:echarts/coord/cartesian/Grid.\n     * @type {Function}\n     */\n    toGlobalCoord: null\n\n};\n\ninherits(Axis2D, Axis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar defaultOption = {\n    show: true,\n    zlevel: 0,\n    z: 0,\n    // Inverse the axis.\n    inverse: false,\n\n    // Axis name displayed.\n    name: '',\n    // 'start' | 'middle' | 'end'\n    nameLocation: 'end',\n    // By degree. By defualt auto rotate by nameLocation.\n    nameRotate: null,\n    nameTruncate: {\n        maxWidth: null,\n        ellipsis: '...',\n        placeholder: '.'\n    },\n    // Use global text style by default.\n    nameTextStyle: {},\n    // The gap between axisName and axisLine.\n    nameGap: 15,\n\n    // Default `false` to support tooltip.\n    silent: false,\n    // Default `false` to avoid legacy user event listener fail.\n    triggerEvent: false,\n\n    tooltip: {\n        show: false\n    },\n\n    axisPointer: {},\n\n    axisLine: {\n        show: true,\n        onZero: true,\n        onZeroAxisIndex: null,\n        lineStyle: {\n            color: '#333',\n            width: 1,\n            type: 'solid'\n        },\n        // The arrow at both ends the the axis.\n        symbol: ['none', 'none'],\n        symbolSize: [10, 15]\n    },\n    axisTick: {\n        show: true,\n        // Whether axisTick is inside the grid or outside the grid.\n        inside: false,\n        // The length of axisTick.\n        length: 5,\n        lineStyle: {\n            width: 1\n        }\n    },\n    axisLabel: {\n        show: true,\n        // Whether axisLabel is inside the grid or outside the grid.\n        inside: false,\n        rotate: 0,\n        // true | false | null/undefined (auto)\n        showMinLabel: null,\n        // true | false | null/undefined (auto)\n        showMaxLabel: null,\n        margin: 8,\n        // formatter: null,\n        fontSize: 12\n    },\n    splitLine: {\n        show: true,\n        lineStyle: {\n            color: ['#ccc'],\n            width: 1,\n            type: 'solid'\n        }\n    },\n    splitArea: {\n        show: false,\n        areaStyle: {\n            color: ['rgba(250,250,250,0.3)', 'rgba(200,200,200,0.3)']\n        }\n    }\n};\n\nvar axisDefault = {};\n\naxisDefault.categoryAxis = merge({\n    // The gap at both ends of the axis. For categoryAxis, boolean.\n    boundaryGap: true,\n    // Set false to faster category collection.\n    // Only usefull in the case like: category is\n    // ['2012-01-01', '2012-01-02', ...], where the input\n    // data has been ensured not duplicate and is large data.\n    // null means \"auto\":\n    // if axis.data provided, do not deduplication,\n    // else do deduplication.\n    deduplication: null,\n    // splitArea: {\n        // show: false\n    // },\n    splitLine: {\n        show: false\n    },\n    axisTick: {\n        // If tick is align with label when boundaryGap is true\n        alignWithLabel: false,\n        interval: 'auto'\n    },\n    axisLabel: {\n        interval: 'auto'\n    }\n}, defaultOption);\n\naxisDefault.valueAxis = merge({\n    // The gap at both ends of the axis. For value axis, [GAP, GAP], where\n    // `GAP` can be an absolute pixel number (like `35`), or percent (like `'30%'`)\n    boundaryGap: [0, 0],\n\n    // TODO\n    // min/max: [30, datamin, 60] or [20, datamin] or [datamin, 60]\n\n    // Min value of the axis. can be:\n    // + a number\n    // + 'dataMin': use the min value in data.\n    // + null/undefined: auto decide min value (consider pretty look and boundaryGap).\n    // min: null,\n\n    // Max value of the axis. can be:\n    // + a number\n    // + 'dataMax': use the max value in data.\n    // + null/undefined: auto decide max value (consider pretty look and boundaryGap).\n    // max: null,\n\n    // Readonly prop, specifies start value of the range when using data zoom.\n    // rangeStart: null\n\n    // Readonly prop, specifies end value of the range when using data zoom.\n    // rangeEnd: null\n\n    // Optional value can be:\n    // + `false`: always include value 0.\n    // + `true`: the extent do not consider value 0.\n    // scale: false,\n\n    // AxisTick and axisLabel and splitLine are caculated based on splitNumber.\n    splitNumber: 5\n\n    // Interval specifies the span of the ticks is mandatorily.\n    // interval: null\n\n    // Specify min interval when auto calculate tick interval.\n    // minInterval: null\n\n    // Specify max interval when auto calculate tick interval.\n    // maxInterval: null\n\n}, defaultOption);\n\naxisDefault.timeAxis = defaults({\n    scale: true,\n    min: 'dataMin',\n    max: 'dataMax'\n}, axisDefault.valueAxis);\n\naxisDefault.logAxis = defaults({\n    scale: true,\n    logBase: 10\n}, axisDefault.valueAxis);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME axisType is fixed ?\nvar AXIS_TYPES = ['value', 'category', 'time', 'log'];\n\n/**\n * Generate sub axis model class\n * @param {string} axisName 'x' 'y' 'radius' 'angle' 'parallel'\n * @param {module:echarts/model/Component} BaseAxisModelClass\n * @param {Function} axisTypeDefaulter\n * @param {Object} [extraDefaultOption]\n */\nvar axisModelCreator = function (axisName, BaseAxisModelClass, axisTypeDefaulter, extraDefaultOption) {\n\n    each$1(AXIS_TYPES, function (axisType) {\n\n        BaseAxisModelClass.extend({\n\n            /**\n             * @readOnly\n             */\n            type: axisName + 'Axis.' + axisType,\n\n            mergeDefaultAndTheme: function (option, ecModel) {\n                var layoutMode = this.layoutMode;\n                var inputPositionParams = layoutMode\n                    ? getLayoutParams(option) : {};\n\n                var themeModel = ecModel.getTheme();\n                merge(option, themeModel.get(axisType + 'Axis'));\n                merge(option, this.getDefaultOption());\n\n                option.type = axisTypeDefaulter(axisName, option);\n\n                if (layoutMode) {\n                    mergeLayoutParam(option, inputPositionParams, layoutMode);\n                }\n            },\n\n            /**\n             * @override\n             */\n            optionUpdated: function () {\n                var thisOption = this.option;\n                if (thisOption.type === 'category') {\n                    this.__ordinalMeta = OrdinalMeta.createByAxisModel(this);\n                }\n            },\n\n            /**\n             * Should not be called before all of 'getInitailData' finished.\n             * Because categories are collected during initializing data.\n             */\n            getCategories: function (rawData) {\n                var option = this.option;\n                // FIXME\n                // warning if called before all of 'getInitailData' finished.\n                if (option.type === 'category') {\n                    if (rawData) {\n                        return option.data;\n                    }\n                    return this.__ordinalMeta.categories;\n                }\n            },\n\n            getOrdinalMeta: function () {\n                return this.__ordinalMeta;\n            },\n\n            defaultOption: mergeAll(\n                [\n                    {},\n                    axisDefault[axisType + 'Axis'],\n                    extraDefaultOption\n                ],\n                true\n            )\n        });\n    });\n\n    ComponentModel.registerSubTypeDefaulter(\n        axisName + 'Axis',\n        curry(axisTypeDefaulter, axisName)\n    );\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// import * as axisHelper from './axisHelper';\n\nvar axisModelCommonMixin = {\n\n    /**\n     * @param {boolean} origin\n     * @return {number|string} min value or 'dataMin' or null/undefined (means auto) or NaN\n     */\n    getMin: function (origin) {\n        var option = this.option;\n        var min = (!origin && option.rangeStart != null)\n            ? option.rangeStart : option.min;\n\n        if (this.axis\n            && min != null\n            && min !== 'dataMin'\n            && typeof min !== 'function'\n            && !eqNaN(min)\n        ) {\n            min = this.axis.scale.parse(min);\n        }\n        return min;\n    },\n\n    /**\n     * @param {boolean} origin\n     * @return {number|string} max value or 'dataMax' or null/undefined (means auto) or NaN\n     */\n    getMax: function (origin) {\n        var option = this.option;\n        var max = (!origin && option.rangeEnd != null)\n            ? option.rangeEnd : option.max;\n\n        if (this.axis\n            && max != null\n            && max !== 'dataMax'\n            && typeof max !== 'function'\n            && !eqNaN(max)\n        ) {\n            max = this.axis.scale.parse(max);\n        }\n        return max;\n    },\n\n    /**\n     * @return {boolean}\n     */\n    getNeedCrossZero: function () {\n        var option = this.option;\n        return (option.rangeStart != null || option.rangeEnd != null)\n            ? false : !option.scale;\n    },\n\n    /**\n     * Should be implemented by each axis model if necessary.\n     * @return {module:echarts/model/Component} coordinate system model\n     */\n    getCoordSysModel: noop,\n\n    /**\n     * @param {number} rangeStart Can only be finite number or null/undefined or NaN.\n     * @param {number} rangeEnd Can only be finite number or null/undefined or NaN.\n     */\n    setRange: function (rangeStart, rangeEnd) {\n        this.option.rangeStart = rangeStart;\n        this.option.rangeEnd = rangeEnd;\n    },\n\n    /**\n     * Reset range\n     */\n    resetRange: function () {\n        // rangeStart and rangeEnd is readonly.\n        this.option.rangeStart = this.option.rangeEnd = null;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar AxisModel = ComponentModel.extend({\n\n    type: 'cartesian2dAxis',\n\n    /**\n     * @type {module:echarts/coord/cartesian/Axis2D}\n     */\n    axis: null,\n\n    /**\n     * @override\n     */\n    init: function () {\n        AxisModel.superApply(this, 'init', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     */\n    mergeOption: function () {\n        AxisModel.superApply(this, 'mergeOption', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     */\n    restoreData: function () {\n        AxisModel.superApply(this, 'restoreData', arguments);\n        this.resetRange();\n    },\n\n    /**\n     * @override\n     * @return {module:echarts/model/Component}\n     */\n    getCoordSysModel: function () {\n        return this.ecModel.queryComponents({\n            mainType: 'grid',\n            index: this.option.gridIndex,\n            id: this.option.gridId\n        })[0];\n    }\n\n});\n\nfunction getAxisType(axisDim, option) {\n    // Default axis with data is category axis\n    return option.type || (option.data ? 'category' : 'value');\n}\n\nmerge(AxisModel.prototype, axisModelCommonMixin);\n\nvar extraOption = {\n    // gridIndex: 0,\n    // gridId: '',\n\n    // Offset is for multiple axis on the same position\n    offset: 0\n};\n\naxisModelCreator('x', AxisModel, getAxisType, extraOption);\naxisModelCreator('y', AxisModel, getAxisType, extraOption);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Grid 是在有直角坐标系的时候必须要存在的\n// 所以这里也要被 Cartesian2D 依赖\n\nComponentModel.extend({\n\n    type: 'grid',\n\n    dependencies: ['xAxis', 'yAxis'],\n\n    layoutMode: 'box',\n\n    /**\n     * @type {module:echarts/coord/cartesian/Grid}\n     */\n    coordinateSystem: null,\n\n    defaultOption: {\n        show: false,\n        zlevel: 0,\n        z: 0,\n        left: '10%',\n        top: 60,\n        right: '10%',\n        bottom: 60,\n        // If grid size contain label\n        containLabel: false,\n        // width: {totalWidth} - left - right,\n        // height: {totalHeight} - top - bottom,\n        backgroundColor: 'rgba(0,0,0,0)',\n        borderWidth: 1,\n        borderColor: '#ccc'\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Grid is a region which contains at most 4 cartesian systems\n *\n * TODO Default cartesian\n */\n\n// Depends on GridModel, AxisModel, which performs preprocess.\n/**\n * Check if the axis is used in the specified grid\n * @inner\n */\nfunction isAxisUsedInTheGrid(axisModel, gridModel, ecModel) {\n    return axisModel.getCoordSysModel() === gridModel;\n}\n\nfunction Grid(gridModel, ecModel, api) {\n    /**\n     * @type {Object.<string, module:echarts/coord/cartesian/Cartesian2D>}\n     * @private\n     */\n    this._coordsMap = {};\n\n    /**\n     * @type {Array.<module:echarts/coord/cartesian/Cartesian>}\n     * @private\n     */\n    this._coordsList = [];\n\n    /**\n     * @type {Object.<string, module:echarts/coord/cartesian/Axis2D>}\n     * @private\n     */\n    this._axesMap = {};\n\n    /**\n     * @type {Array.<module:echarts/coord/cartesian/Axis2D>}\n     * @private\n     */\n    this._axesList = [];\n\n    this._initCartesian(gridModel, ecModel, api);\n\n    this.model = gridModel;\n}\n\nvar gridProto = Grid.prototype;\n\ngridProto.type = 'grid';\n\ngridProto.axisPointerEnabled = true;\n\ngridProto.getRect = function () {\n    return this._rect;\n};\n\ngridProto.update = function (ecModel, api) {\n\n    var axesMap = this._axesMap;\n\n    this._updateScale(ecModel, this.model);\n\n    each$1(axesMap.x, function (xAxis) {\n        niceScaleExtent(xAxis.scale, xAxis.model);\n    });\n    each$1(axesMap.y, function (yAxis) {\n        niceScaleExtent(yAxis.scale, yAxis.model);\n    });\n\n    // Key: axisDim_axisIndex, value: boolean, whether onZero target.\n    var onZeroRecords = {};\n\n    each$1(axesMap.x, function (xAxis) {\n        fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords);\n    });\n    each$1(axesMap.y, function (yAxis) {\n        fixAxisOnZero(axesMap, 'x', yAxis, onZeroRecords);\n    });\n\n    // Resize again if containLabel is enabled\n    // FIXME It may cause getting wrong grid size in data processing stage\n    this.resize(this.model, api);\n};\n\nfunction fixAxisOnZero(axesMap, otherAxisDim, axis, onZeroRecords) {\n\n    axis.getAxesOnZeroOf = function () {\n        // TODO: onZero of multiple axes.\n        return otherAxisOnZeroOf ? [otherAxisOnZeroOf] : [];\n    };\n\n    // onZero can not be enabled in these two situations:\n    // 1. When any other axis is a category axis.\n    // 2. When no axis is cross 0 point.\n    var otherAxes = axesMap[otherAxisDim];\n\n    var otherAxisOnZeroOf;\n    var axisModel = axis.model;\n    var onZero = axisModel.get('axisLine.onZero');\n    var onZeroAxisIndex = axisModel.get('axisLine.onZeroAxisIndex');\n\n    if (!onZero) {\n        return;\n    }\n\n    // If target axis is specified.\n    if (onZeroAxisIndex != null) {\n        if (canOnZeroToAxis(otherAxes[onZeroAxisIndex])) {\n            otherAxisOnZeroOf = otherAxes[onZeroAxisIndex];\n        }\n    }\n    else {\n        // Find the first available other axis.\n        for (var idx in otherAxes) {\n            if (otherAxes.hasOwnProperty(idx)\n                && canOnZeroToAxis(otherAxes[idx])\n                // Consider that two Y axes on one value axis,\n                // if both onZero, the two Y axes overlap.\n                && !onZeroRecords[getOnZeroRecordKey(otherAxes[idx])]\n            ) {\n                otherAxisOnZeroOf = otherAxes[idx];\n                break;\n            }\n        }\n    }\n\n    if (otherAxisOnZeroOf) {\n        onZeroRecords[getOnZeroRecordKey(otherAxisOnZeroOf)] = true;\n    }\n\n    function getOnZeroRecordKey(axis) {\n        return axis.dim + '_' + axis.index;\n    }\n}\n\nfunction canOnZeroToAxis(axis) {\n    return axis && axis.type !== 'category' && axis.type !== 'time' && ifAxisCrossZero(axis);\n}\n\n/**\n * Resize the grid\n * @param {module:echarts/coord/cartesian/GridModel} gridModel\n * @param {module:echarts/ExtensionAPI} api\n */\ngridProto.resize = function (gridModel, api, ignoreContainLabel) {\n\n    var gridRect = getLayoutRect(\n        gridModel.getBoxLayoutParams(), {\n            width: api.getWidth(),\n            height: api.getHeight()\n        });\n\n    this._rect = gridRect;\n\n    var axesList = this._axesList;\n\n    adjustAxes();\n\n    // Minus label size\n    if (!ignoreContainLabel && gridModel.get('containLabel')) {\n        each$1(axesList, function (axis) {\n            if (!axis.model.get('axisLabel.inside')) {\n                var labelUnionRect = estimateLabelUnionRect(axis);\n                if (labelUnionRect) {\n                    var dim = axis.isHorizontal() ? 'height' : 'width';\n                    var margin = axis.model.get('axisLabel.margin');\n                    gridRect[dim] -= labelUnionRect[dim] + margin;\n                    if (axis.position === 'top') {\n                        gridRect.y += labelUnionRect.height + margin;\n                    }\n                    else if (axis.position === 'left') {\n                        gridRect.x += labelUnionRect.width + margin;\n                    }\n                }\n            }\n        });\n\n        adjustAxes();\n    }\n\n    function adjustAxes() {\n        each$1(axesList, function (axis) {\n            var isHorizontal = axis.isHorizontal();\n            var extent = isHorizontal ? [0, gridRect.width] : [0, gridRect.height];\n            var idx = axis.inverse ? 1 : 0;\n            axis.setExtent(extent[idx], extent[1 - idx]);\n            updateAxisTransform(axis, isHorizontal ? gridRect.x : gridRect.y);\n        });\n    }\n};\n\n/**\n * @param {string} axisType\n * @param {number} [axisIndex]\n */\ngridProto.getAxis = function (axisType, axisIndex) {\n    var axesMapOnDim = this._axesMap[axisType];\n    if (axesMapOnDim != null) {\n        if (axisIndex == null) {\n            // Find first axis\n            for (var name in axesMapOnDim) {\n                if (axesMapOnDim.hasOwnProperty(name)) {\n                    return axesMapOnDim[name];\n                }\n            }\n        }\n        return axesMapOnDim[axisIndex];\n    }\n};\n\n/**\n * @return {Array.<module:echarts/coord/Axis>}\n */\ngridProto.getAxes = function () {\n    return this._axesList.slice();\n};\n\n/**\n * Usage:\n *      grid.getCartesian(xAxisIndex, yAxisIndex);\n *      grid.getCartesian(xAxisIndex);\n *      grid.getCartesian(null, yAxisIndex);\n *      grid.getCartesian({xAxisIndex: ..., yAxisIndex: ...});\n *\n * @param {number|Object} [xAxisIndex]\n * @param {number} [yAxisIndex]\n */\ngridProto.getCartesian = function (xAxisIndex, yAxisIndex) {\n    if (xAxisIndex != null && yAxisIndex != null) {\n        var key = 'x' + xAxisIndex + 'y' + yAxisIndex;\n        return this._coordsMap[key];\n    }\n\n    if (isObject$1(xAxisIndex)) {\n        yAxisIndex = xAxisIndex.yAxisIndex;\n        xAxisIndex = xAxisIndex.xAxisIndex;\n    }\n    // When only xAxisIndex or yAxisIndex given, find its first cartesian.\n    for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) {\n        if (coordList[i].getAxis('x').index === xAxisIndex\n            || coordList[i].getAxis('y').index === yAxisIndex\n        ) {\n            return coordList[i];\n        }\n    }\n};\n\ngridProto.getCartesians = function () {\n    return this._coordsList.slice();\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.convertToPixel = function (ecModel, finder, value) {\n    var target = this._findConvertTarget(ecModel, finder);\n\n    return target.cartesian\n        ? target.cartesian.dataToPoint(value)\n        : target.axis\n        ? target.axis.toGlobalCoord(target.axis.dataToCoord(value))\n        : null;\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.convertFromPixel = function (ecModel, finder, value) {\n    var target = this._findConvertTarget(ecModel, finder);\n\n    return target.cartesian\n        ? target.cartesian.pointToData(value)\n        : target.axis\n        ? target.axis.coordToData(target.axis.toLocalCoord(value))\n        : null;\n};\n\n/**\n * @inner\n */\ngridProto._findConvertTarget = function (ecModel, finder) {\n    var seriesModel = finder.seriesModel;\n    var xAxisModel = finder.xAxisModel\n        || (seriesModel && seriesModel.getReferringComponents('xAxis')[0]);\n    var yAxisModel = finder.yAxisModel\n        || (seriesModel && seriesModel.getReferringComponents('yAxis')[0]);\n    var gridModel = finder.gridModel;\n    var coordsList = this._coordsList;\n    var cartesian;\n    var axis;\n\n    if (seriesModel) {\n        cartesian = seriesModel.coordinateSystem;\n        indexOf(coordsList, cartesian) < 0 && (cartesian = null);\n    }\n    else if (xAxisModel && yAxisModel) {\n        cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);\n    }\n    else if (xAxisModel) {\n        axis = this.getAxis('x', xAxisModel.componentIndex);\n    }\n    else if (yAxisModel) {\n        axis = this.getAxis('y', yAxisModel.componentIndex);\n    }\n    // Lowest priority.\n    else if (gridModel) {\n        var grid = gridModel.coordinateSystem;\n        if (grid === this) {\n            cartesian = this._coordsList[0];\n        }\n    }\n\n    return {cartesian: cartesian, axis: axis};\n};\n\n/**\n * @implements\n * see {module:echarts/CoodinateSystem}\n */\ngridProto.containPoint = function (point) {\n    var coord = this._coordsList[0];\n    if (coord) {\n        return coord.containPoint(point);\n    }\n};\n\n/**\n * Initialize cartesian coordinate systems\n * @private\n */\ngridProto._initCartesian = function (gridModel, ecModel, api) {\n    var axisPositionUsed = {\n        left: false,\n        right: false,\n        top: false,\n        bottom: false\n    };\n\n    var axesMap = {\n        x: {},\n        y: {}\n    };\n    var axesCount = {\n        x: 0,\n        y: 0\n    };\n\n    /// Create axis\n    ecModel.eachComponent('xAxis', createAxisCreator('x'), this);\n    ecModel.eachComponent('yAxis', createAxisCreator('y'), this);\n\n    if (!axesCount.x || !axesCount.y) {\n        // Roll back when there no either x or y axis\n        this._axesMap = {};\n        this._axesList = [];\n        return;\n    }\n\n    this._axesMap = axesMap;\n\n    /// Create cartesian2d\n    each$1(axesMap.x, function (xAxis, xAxisIndex) {\n        each$1(axesMap.y, function (yAxis, yAxisIndex) {\n            var key = 'x' + xAxisIndex + 'y' + yAxisIndex;\n            var cartesian = new Cartesian2D(key);\n\n            cartesian.grid = this;\n            cartesian.model = gridModel;\n\n            this._coordsMap[key] = cartesian;\n            this._coordsList.push(cartesian);\n\n            cartesian.addAxis(xAxis);\n            cartesian.addAxis(yAxis);\n        }, this);\n    }, this);\n\n    function createAxisCreator(axisType) {\n        return function (axisModel, idx) {\n            if (!isAxisUsedInTheGrid(axisModel, gridModel, ecModel)) {\n                return;\n            }\n\n            var axisPosition = axisModel.get('position');\n            if (axisType === 'x') {\n                // Fix position\n                if (axisPosition !== 'top' && axisPosition !== 'bottom') {\n                    // Default bottom of X\n                    axisPosition = 'bottom';\n                    if (axisPositionUsed[axisPosition]) {\n                        axisPosition = axisPosition === 'top' ? 'bottom' : 'top';\n                    }\n                }\n            }\n            else {\n                // Fix position\n                if (axisPosition !== 'left' && axisPosition !== 'right') {\n                    // Default left of Y\n                    axisPosition = 'left';\n                    if (axisPositionUsed[axisPosition]) {\n                        axisPosition = axisPosition === 'left' ? 'right' : 'left';\n                    }\n                }\n            }\n            axisPositionUsed[axisPosition] = true;\n\n            var axis = new Axis2D(\n                axisType, createScaleByModel(axisModel),\n                [0, 0],\n                axisModel.get('type'),\n                axisPosition\n            );\n\n            var isCategory = axis.type === 'category';\n            axis.onBand = isCategory && axisModel.get('boundaryGap');\n            axis.inverse = axisModel.get('inverse');\n\n            // Inject axis into axisModel\n            axisModel.axis = axis;\n\n            // Inject axisModel into axis\n            axis.model = axisModel;\n\n            // Inject grid info axis\n            axis.grid = this;\n\n            // Index of axis, can be used as key\n            axis.index = idx;\n\n            this._axesList.push(axis);\n\n            axesMap[axisType][idx] = axis;\n            axesCount[axisType]++;\n        };\n    }\n};\n\n/**\n * Update cartesian properties from series\n * @param  {module:echarts/model/Option} option\n * @private\n */\ngridProto._updateScale = function (ecModel, gridModel) {\n    // Reset scale\n    each$1(this._axesList, function (axis) {\n        axis.scale.setExtent(Infinity, -Infinity);\n    });\n    ecModel.eachSeries(function (seriesModel) {\n        if (isCartesian2D(seriesModel)) {\n            var axesModels = findAxesModels(seriesModel, ecModel);\n            var xAxisModel = axesModels[0];\n            var yAxisModel = axesModels[1];\n\n            if (!isAxisUsedInTheGrid(xAxisModel, gridModel, ecModel)\n                || !isAxisUsedInTheGrid(yAxisModel, gridModel, ecModel)\n            ) {\n                return;\n            }\n\n            var cartesian = this.getCartesian(\n                xAxisModel.componentIndex, yAxisModel.componentIndex\n            );\n            var data = seriesModel.getData();\n            var xAxis = cartesian.getAxis('x');\n            var yAxis = cartesian.getAxis('y');\n\n            if (data.type === 'list') {\n                unionExtent(data, xAxis, seriesModel);\n                unionExtent(data, yAxis, seriesModel);\n            }\n        }\n    }, this);\n\n    function unionExtent(data, axis, seriesModel) {\n        each$1(data.mapDimension(axis.dim, true), function (dim) {\n            axis.scale.unionExtentFromData(\n                // For example, the extent of the orginal dimension\n                // is [0.1, 0.5], the extent of the `stackResultDimension`\n                // is [7, 9], the final extent should not include [0.1, 0.5].\n                data, getStackedDimension(data, dim)\n            );\n        });\n    }\n};\n\n/**\n * @param {string} [dim] 'x' or 'y' or 'auto' or null/undefined\n * @return {Object} {baseAxes: [], otherAxes: []}\n */\ngridProto.getTooltipAxes = function (dim) {\n    var baseAxes = [];\n    var otherAxes = [];\n\n    each$1(this.getCartesians(), function (cartesian) {\n        var baseAxis = (dim != null && dim !== 'auto')\n            ? cartesian.getAxis(dim) : cartesian.getBaseAxis();\n        var otherAxis = cartesian.getOtherAxis(baseAxis);\n        indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis);\n        indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis);\n    });\n\n    return {baseAxes: baseAxes, otherAxes: otherAxes};\n};\n\n/**\n * @inner\n */\nfunction updateAxisTransform(axis, coordBase) {\n    var axisExtent = axis.getExtent();\n    var axisExtentSum = axisExtent[0] + axisExtent[1];\n\n    // Fast transform\n    axis.toGlobalCoord = axis.dim === 'x'\n        ? function (coord) {\n            return coord + coordBase;\n        }\n        : function (coord) {\n            return axisExtentSum - coord + coordBase;\n        };\n    axis.toLocalCoord = axis.dim === 'x'\n        ? function (coord) {\n            return coord - coordBase;\n        }\n        : function (coord) {\n            return axisExtentSum - coord + coordBase;\n        };\n}\n\nvar axesTypes = ['xAxis', 'yAxis'];\n/**\n * @inner\n */\nfunction findAxesModels(seriesModel, ecModel) {\n    return map(axesTypes, function (axisType) {\n        var axisModel = seriesModel.getReferringComponents(axisType)[0];\n\n        if (__DEV__) {\n            if (!axisModel) {\n                throw new Error(axisType + ' \"' + retrieve(\n                    seriesModel.get(axisType + 'Index'),\n                    seriesModel.get(axisType + 'Id'),\n                    0\n                ) + '\" not found');\n            }\n        }\n        return axisModel;\n    });\n}\n\n/**\n * @inner\n */\nfunction isCartesian2D(seriesModel) {\n    return seriesModel.get('coordinateSystem') === 'cartesian2d';\n}\n\nGrid.create = function (ecModel, api) {\n    var grids = [];\n    ecModel.eachComponent('grid', function (gridModel, idx) {\n        var grid = new Grid(gridModel, ecModel, api);\n        grid.name = 'grid_' + idx;\n        // dataSampling requires axis extent, so resize\n        // should be performed in create stage.\n        grid.resize(gridModel, api, true);\n\n        gridModel.coordinateSystem = grid;\n\n        grids.push(grid);\n    });\n\n    // Inject the coordinateSystems into seriesModel\n    ecModel.eachSeries(function (seriesModel) {\n        if (!isCartesian2D(seriesModel)) {\n            return;\n        }\n\n        var axesModels = findAxesModels(seriesModel, ecModel);\n        var xAxisModel = axesModels[0];\n        var yAxisModel = axesModels[1];\n\n        var gridModel = xAxisModel.getCoordSysModel();\n\n        if (__DEV__) {\n            if (!gridModel) {\n                throw new Error(\n                    'Grid \"' + retrieve(\n                        xAxisModel.get('gridIndex'),\n                        xAxisModel.get('gridId'),\n                        0\n                    ) + '\" not found'\n                );\n            }\n            if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) {\n                throw new Error('xAxis and yAxis must use the same grid');\n            }\n        }\n\n        var grid = gridModel.coordinateSystem;\n\n        seriesModel.coordinateSystem = grid.getCartesian(\n            xAxisModel.componentIndex, yAxisModel.componentIndex\n        );\n    });\n\n    return grids;\n};\n\n// For deciding which dimensions to use when creating list data\nGrid.dimensions = Grid.prototype.dimensions = Cartesian2D.prototype.dimensions;\n\nCoordinateSystemManager.register('cartesian2d', Grid);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PI$2 = Math.PI;\n\nfunction makeAxisEventDataBase(axisModel) {\n    var eventData = {\n        componentType: axisModel.mainType,\n        componentIndex: axisModel.componentIndex\n    };\n    eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex;\n    return eventData;\n}\n\n/**\n * A final axis is translated and rotated from a \"standard axis\".\n * So opt.position and opt.rotation is required.\n *\n * A standard axis is and axis from [0, 0] to [0, axisExtent[1]],\n * for example: (0, 0) ------------> (0, 50)\n *\n * nameDirection or tickDirection or labelDirection is 1 means tick\n * or label is below the standard axis, whereas is -1 means above\n * the standard axis. labelOffset means offset between label and axis,\n * which is useful when 'onZero', where axisLabel is in the grid and\n * label in outside grid.\n *\n * Tips: like always,\n * positive rotation represents anticlockwise, and negative rotation\n * represents clockwise.\n * The direction of position coordinate is the same as the direction\n * of screen coordinate.\n *\n * Do not need to consider axis 'inverse', which is auto processed by\n * axis extent.\n *\n * @param {module:zrender/container/Group} group\n * @param {Object} axisModel\n * @param {Object} opt Standard axis parameters.\n * @param {Array.<number>} opt.position [x, y]\n * @param {number} opt.rotation by radian\n * @param {number} [opt.nameDirection=1] 1 or -1 Used when nameLocation is 'middle' or 'center'.\n * @param {number} [opt.tickDirection=1] 1 or -1\n * @param {number} [opt.labelDirection=1] 1 or -1\n * @param {number} [opt.labelOffset=0] Usefull when onZero.\n * @param {string} [opt.axisLabelShow] default get from axisModel.\n * @param {string} [opt.axisName] default get from axisModel.\n * @param {number} [opt.axisNameAvailableWidth]\n * @param {number} [opt.labelRotate] by degree, default get from axisModel.\n * @param {number} [opt.strokeContainThreshold] Default label interval when label\n * @param {number} [opt.nameTruncateMaxWidth]\n */\nvar AxisBuilder = function (axisModel, opt) {\n\n    /**\n     * @readOnly\n     */\n    this.opt = opt;\n\n    /**\n     * @readOnly\n     */\n    this.axisModel = axisModel;\n\n    // Default value\n    defaults(\n        opt,\n        {\n            labelOffset: 0,\n            nameDirection: 1,\n            tickDirection: 1,\n            labelDirection: 1,\n            silent: true\n        }\n    );\n\n    /**\n     * @readOnly\n     */\n    this.group = new Group();\n\n    // FIXME Not use a seperate text group?\n    var dumbGroup = new Group({\n        position: opt.position.slice(),\n        rotation: opt.rotation\n    });\n\n    // this.group.add(dumbGroup);\n    // this._dumbGroup = dumbGroup;\n\n    dumbGroup.updateTransform();\n    this._transform = dumbGroup.transform;\n\n    this._dumbGroup = dumbGroup;\n};\n\nAxisBuilder.prototype = {\n\n    constructor: AxisBuilder,\n\n    hasBuilder: function (name) {\n        return !!builders[name];\n    },\n\n    add: function (name) {\n        builders[name].call(this);\n    },\n\n    getGroup: function () {\n        return this.group;\n    }\n\n};\n\nvar builders = {\n\n    /**\n     * @private\n     */\n    axisLine: function () {\n        var opt = this.opt;\n        var axisModel = this.axisModel;\n\n        if (!axisModel.get('axisLine.show')) {\n            return;\n        }\n\n        var extent = this.axisModel.axis.getExtent();\n\n        var matrix = this._transform;\n        var pt1 = [extent[0], 0];\n        var pt2 = [extent[1], 0];\n        if (matrix) {\n            applyTransform(pt1, pt1, matrix);\n            applyTransform(pt2, pt2, matrix);\n        }\n\n        var lineStyle = extend(\n            {\n                lineCap: 'round'\n            },\n            axisModel.getModel('axisLine.lineStyle').getLineStyle()\n        );\n\n        this.group.add(new Line(subPixelOptimizeLine({\n            // Id for animation\n            anid: 'line',\n\n            shape: {\n                x1: pt1[0],\n                y1: pt1[1],\n                x2: pt2[0],\n                y2: pt2[1]\n            },\n            style: lineStyle,\n            strokeContainThreshold: opt.strokeContainThreshold || 5,\n            silent: true,\n            z2: 1\n        })));\n\n        var arrows = axisModel.get('axisLine.symbol');\n        var arrowSize = axisModel.get('axisLine.symbolSize');\n\n        var arrowOffset = axisModel.get('axisLine.symbolOffset') || 0;\n        if (typeof arrowOffset === 'number') {\n            arrowOffset = [arrowOffset, arrowOffset];\n        }\n\n        if (arrows != null) {\n            if (typeof arrows === 'string') {\n                // Use the same arrow for start and end point\n                arrows = [arrows, arrows];\n            }\n            if (typeof arrowSize === 'string'\n                || typeof arrowSize === 'number'\n            ) {\n                // Use the same size for width and height\n                arrowSize = [arrowSize, arrowSize];\n            }\n\n            var symbolWidth = arrowSize[0];\n            var symbolHeight = arrowSize[1];\n\n            each$1([{\n                rotate: opt.rotation + Math.PI / 2,\n                offset: arrowOffset[0],\n                r: 0\n            }, {\n                rotate: opt.rotation - Math.PI / 2,\n                offset: arrowOffset[1],\n                r: Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0])\n                    + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1]))\n            }], function (point, index) {\n                if (arrows[index] !== 'none' && arrows[index] != null) {\n                    var symbol = createSymbol(\n                        arrows[index],\n                        -symbolWidth / 2,\n                        -symbolHeight / 2,\n                        symbolWidth,\n                        symbolHeight,\n                        lineStyle.stroke,\n                        true\n                    );\n\n                    // Calculate arrow position with offset\n                    var r = point.r + point.offset;\n                    var pos = [\n                        pt1[0] + r * Math.cos(opt.rotation),\n                        pt1[1] - r * Math.sin(opt.rotation)\n                    ];\n\n                    symbol.attr({\n                        rotation: point.rotate,\n                        position: pos,\n                        silent: true,\n                        z2: 11\n                    });\n                    this.group.add(symbol);\n                }\n            }, this);\n        }\n    },\n\n    /**\n     * @private\n     */\n    axisTickLabel: function () {\n        var axisModel = this.axisModel;\n        var opt = this.opt;\n\n        var tickEls = buildAxisTick(this, axisModel, opt);\n        var labelEls = buildAxisLabel(this, axisModel, opt);\n\n        fixMinMaxLabelShow(axisModel, labelEls, tickEls);\n    },\n\n    /**\n     * @private\n     */\n    axisName: function () {\n        var opt = this.opt;\n        var axisModel = this.axisModel;\n        var name = retrieve(opt.axisName, axisModel.get('name'));\n\n        if (!name) {\n            return;\n        }\n\n        var nameLocation = axisModel.get('nameLocation');\n        var nameDirection = opt.nameDirection;\n        var textStyleModel = axisModel.getModel('nameTextStyle');\n        var gap = axisModel.get('nameGap') || 0;\n\n        var extent = this.axisModel.axis.getExtent();\n        var gapSignal = extent[0] > extent[1] ? -1 : 1;\n        var pos = [\n            nameLocation === 'start'\n                ? extent[0] - gapSignal * gap\n                : nameLocation === 'end'\n                ? extent[1] + gapSignal * gap\n                : (extent[0] + extent[1]) / 2, // 'middle'\n            // Reuse labelOffset.\n            isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * gap : 0\n        ];\n\n        var labelLayout;\n\n        var nameRotation = axisModel.get('nameRotate');\n        if (nameRotation != null) {\n            nameRotation = nameRotation * PI$2 / 180; // To radian.\n        }\n\n        var axisNameAvailableWidth;\n\n        if (isNameLocationCenter(nameLocation)) {\n            labelLayout = innerTextLayout(\n                opt.rotation,\n                nameRotation != null ? nameRotation : opt.rotation, // Adapt to axis.\n                nameDirection\n            );\n        }\n        else {\n            labelLayout = endTextLayout(\n                opt, nameLocation, nameRotation || 0, extent\n            );\n\n            axisNameAvailableWidth = opt.axisNameAvailableWidth;\n            if (axisNameAvailableWidth != null) {\n                axisNameAvailableWidth = Math.abs(\n                    axisNameAvailableWidth / Math.sin(labelLayout.rotation)\n                );\n                !isFinite(axisNameAvailableWidth) && (axisNameAvailableWidth = null);\n            }\n        }\n\n        var textFont = textStyleModel.getFont();\n\n        var truncateOpt = axisModel.get('nameTruncate', true) || {};\n        var ellipsis = truncateOpt.ellipsis;\n        var maxWidth = retrieve(\n            opt.nameTruncateMaxWidth, truncateOpt.maxWidth, axisNameAvailableWidth\n        );\n        // FIXME\n        // truncate rich text? (consider performance)\n        var truncatedText = (ellipsis != null && maxWidth != null)\n            ? truncateText$1(\n                name, maxWidth, textFont, ellipsis,\n                {minChar: 2, placeholder: truncateOpt.placeholder}\n            )\n            : name;\n\n        var tooltipOpt = axisModel.get('tooltip', true);\n\n        var mainType = axisModel.mainType;\n        var formatterParams = {\n            componentType: mainType,\n            name: name,\n            $vars: ['name']\n        };\n        formatterParams[mainType + 'Index'] = axisModel.componentIndex;\n\n        var textEl = new Text({\n            // Id for animation\n            anid: 'name',\n\n            __fullText: name,\n            __truncatedText: truncatedText,\n\n            position: pos,\n            rotation: labelLayout.rotation,\n            silent: isSilent(axisModel),\n            z2: 1,\n            tooltip: (tooltipOpt && tooltipOpt.show)\n                ? extend({\n                    content: name,\n                    formatter: function () {\n                        return name;\n                    },\n                    formatterParams: formatterParams\n                }, tooltipOpt)\n                : null\n        });\n\n        setTextStyle(textEl.style, textStyleModel, {\n            text: truncatedText,\n            textFont: textFont,\n            textFill: textStyleModel.getTextColor()\n                || axisModel.get('axisLine.lineStyle.color'),\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.textVerticalAlign\n        });\n\n        if (axisModel.get('triggerEvent')) {\n            textEl.eventData = makeAxisEventDataBase(axisModel);\n            textEl.eventData.targetType = 'axisName';\n            textEl.eventData.name = name;\n        }\n\n        // FIXME\n        this._dumbGroup.add(textEl);\n        textEl.updateTransform();\n\n        this.group.add(textEl);\n\n        textEl.decomposeTransform();\n    }\n\n};\n\n/**\n * @public\n * @static\n * @param {Object} opt\n * @param {number} axisRotation in radian\n * @param {number} textRotation in radian\n * @param {number} direction\n * @return {Object} {\n *  rotation, // according to axis\n *  textAlign,\n *  textVerticalAlign\n * }\n */\nvar innerTextLayout = AxisBuilder.innerTextLayout = function (axisRotation, textRotation, direction) {\n    var rotationDiff = remRadian(textRotation - axisRotation);\n    var textAlign;\n    var textVerticalAlign;\n\n    if (isRadianAroundZero(rotationDiff)) { // Label is parallel with axis line.\n        textVerticalAlign = direction > 0 ? 'top' : 'bottom';\n        textAlign = 'center';\n    }\n    else if (isRadianAroundZero(rotationDiff - PI$2)) { // Label is inverse parallel with axis line.\n        textVerticalAlign = direction > 0 ? 'bottom' : 'top';\n        textAlign = 'center';\n    }\n    else {\n        textVerticalAlign = 'middle';\n\n        if (rotationDiff > 0 && rotationDiff < PI$2) {\n            textAlign = direction > 0 ? 'right' : 'left';\n        }\n        else {\n            textAlign = direction > 0 ? 'left' : 'right';\n        }\n    }\n\n    return {\n        rotation: rotationDiff,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n};\n\nfunction endTextLayout(opt, textPosition, textRotate, extent) {\n    var rotationDiff = remRadian(textRotate - opt.rotation);\n    var textAlign;\n    var textVerticalAlign;\n    var inverse = extent[0] > extent[1];\n    var onLeft = (textPosition === 'start' && !inverse)\n        || (textPosition !== 'start' && inverse);\n\n    if (isRadianAroundZero(rotationDiff - PI$2 / 2)) {\n        textVerticalAlign = onLeft ? 'bottom' : 'top';\n        textAlign = 'center';\n    }\n    else if (isRadianAroundZero(rotationDiff - PI$2 * 1.5)) {\n        textVerticalAlign = onLeft ? 'top' : 'bottom';\n        textAlign = 'center';\n    }\n    else {\n        textVerticalAlign = 'middle';\n        if (rotationDiff < PI$2 * 1.5 && rotationDiff > PI$2 / 2) {\n            textAlign = onLeft ? 'left' : 'right';\n        }\n        else {\n            textAlign = onLeft ? 'right' : 'left';\n        }\n    }\n\n    return {\n        rotation: rotationDiff,\n        textAlign: textAlign,\n        textVerticalAlign: textVerticalAlign\n    };\n}\n\nfunction isSilent(axisModel) {\n    var tooltipOpt = axisModel.get('tooltip');\n    return axisModel.get('silent')\n        // Consider mouse cursor, add these restrictions.\n        || !(\n            axisModel.get('triggerEvent') || (tooltipOpt && tooltipOpt.show)\n        );\n}\n\nfunction fixMinMaxLabelShow(axisModel, labelEls, tickEls) {\n    if (shouldShowAllLabels(axisModel.axis)) {\n        return;\n    }\n\n    // If min or max are user set, we need to check\n    // If the tick on min(max) are overlap on their neighbour tick\n    // If they are overlapped, we need to hide the min(max) tick label\n    var showMinLabel = axisModel.get('axisLabel.showMinLabel');\n    var showMaxLabel = axisModel.get('axisLabel.showMaxLabel');\n\n    // FIXME\n    // Have not consider onBand yet, where tick els is more than label els.\n\n    labelEls = labelEls || [];\n    tickEls = tickEls || [];\n\n    var firstLabel = labelEls[0];\n    var nextLabel = labelEls[1];\n    var lastLabel = labelEls[labelEls.length - 1];\n    var prevLabel = labelEls[labelEls.length - 2];\n\n    var firstTick = tickEls[0];\n    var nextTick = tickEls[1];\n    var lastTick = tickEls[tickEls.length - 1];\n    var prevTick = tickEls[tickEls.length - 2];\n\n    if (showMinLabel === false) {\n        ignoreEl(firstLabel);\n        ignoreEl(firstTick);\n    }\n    else if (isTwoLabelOverlapped(firstLabel, nextLabel)) {\n        if (showMinLabel) {\n            ignoreEl(nextLabel);\n            ignoreEl(nextTick);\n        }\n        else {\n            ignoreEl(firstLabel);\n            ignoreEl(firstTick);\n        }\n    }\n\n    if (showMaxLabel === false) {\n        ignoreEl(lastLabel);\n        ignoreEl(lastTick);\n    }\n    else if (isTwoLabelOverlapped(prevLabel, lastLabel)) {\n        if (showMaxLabel) {\n            ignoreEl(prevLabel);\n            ignoreEl(prevTick);\n        }\n        else {\n            ignoreEl(lastLabel);\n            ignoreEl(lastTick);\n        }\n    }\n}\n\nfunction ignoreEl(el) {\n    el && (el.ignore = true);\n}\n\nfunction isTwoLabelOverlapped(current, next, labelLayout) {\n    // current and next has the same rotation.\n    var firstRect = current && current.getBoundingRect().clone();\n    var nextRect = next && next.getBoundingRect().clone();\n\n    if (!firstRect || !nextRect) {\n        return;\n    }\n\n    // When checking intersect of two rotated labels, we use mRotationBack\n    // to avoid that boundingRect is enlarge when using `boundingRect.applyTransform`.\n    var mRotationBack = identity([]);\n    rotate(mRotationBack, mRotationBack, -current.rotation);\n\n    firstRect.applyTransform(mul$1([], mRotationBack, current.getLocalTransform()));\n    nextRect.applyTransform(mul$1([], mRotationBack, next.getLocalTransform()));\n\n    return firstRect.intersect(nextRect);\n}\n\nfunction isNameLocationCenter(nameLocation) {\n    return nameLocation === 'middle' || nameLocation === 'center';\n}\n\nfunction buildAxisTick(axisBuilder, axisModel, opt) {\n    var axis = axisModel.axis;\n\n    if (!axisModel.get('axisTick.show') || axis.scale.isBlank()) {\n        return;\n    }\n\n    var tickModel = axisModel.getModel('axisTick');\n\n    var lineStyleModel = tickModel.getModel('lineStyle');\n    var tickLen = tickModel.get('length');\n\n    var ticksCoords = axis.getTicksCoords();\n\n    var pt1 = [];\n    var pt2 = [];\n    var matrix = axisBuilder._transform;\n\n    var tickEls = [];\n\n    for (var i = 0; i < ticksCoords.length; i++) {\n        var tickCoord = ticksCoords[i].coord;\n\n        pt1[0] = tickCoord;\n        pt1[1] = 0;\n        pt2[0] = tickCoord;\n        pt2[1] = opt.tickDirection * tickLen;\n\n        if (matrix) {\n            applyTransform(pt1, pt1, matrix);\n            applyTransform(pt2, pt2, matrix);\n        }\n        // Tick line, Not use group transform to have better line draw\n        var tickEl = new Line(subPixelOptimizeLine({\n            // Id for animation\n            anid: 'tick_' + ticksCoords[i].tickValue,\n\n            shape: {\n                x1: pt1[0],\n                y1: pt1[1],\n                x2: pt2[0],\n                y2: pt2[1]\n            },\n            style: defaults(\n                lineStyleModel.getLineStyle(),\n                {\n                    stroke: axisModel.get('axisLine.lineStyle.color')\n                }\n            ),\n            z2: 2,\n            silent: true\n        }));\n        axisBuilder.group.add(tickEl);\n        tickEls.push(tickEl);\n    }\n\n    return tickEls;\n}\n\nfunction buildAxisLabel(axisBuilder, axisModel, opt) {\n    var axis = axisModel.axis;\n    var show = retrieve(opt.axisLabelShow, axisModel.get('axisLabel.show'));\n\n    if (!show || axis.scale.isBlank()) {\n        return;\n    }\n\n    var labelModel = axisModel.getModel('axisLabel');\n    var labelMargin = labelModel.get('margin');\n    var labels = axis.getViewLabels();\n\n    // Special label rotate.\n    var labelRotation = (\n        retrieve(opt.labelRotate, labelModel.get('rotate')) || 0\n    ) * PI$2 / 180;\n\n    var labelLayout = innerTextLayout(opt.rotation, labelRotation, opt.labelDirection);\n    var rawCategoryData = axisModel.getCategories(true);\n\n    var labelEls = [];\n    var silent = isSilent(axisModel);\n    var triggerEvent = axisModel.get('triggerEvent');\n\n    each$1(labels, function (labelItem, index) {\n        var tickValue = labelItem.tickValue;\n        var formattedLabel = labelItem.formattedLabel;\n        var rawLabel = labelItem.rawLabel;\n\n        var itemLabelModel = labelModel;\n        if (rawCategoryData && rawCategoryData[tickValue] && rawCategoryData[tickValue].textStyle) {\n            itemLabelModel = new Model(\n                rawCategoryData[tickValue].textStyle, labelModel, axisModel.ecModel\n            );\n        }\n\n        var textColor = itemLabelModel.getTextColor()\n            || axisModel.get('axisLine.lineStyle.color');\n\n        var tickCoord = axis.dataToCoord(tickValue);\n        var pos = [\n            tickCoord,\n            opt.labelOffset + opt.labelDirection * labelMargin\n        ];\n\n        var textEl = new Text({\n            // Id for animation\n            anid: 'label_' + tickValue,\n            position: pos,\n            rotation: labelLayout.rotation,\n            silent: silent,\n            z2: 10\n        });\n\n        setTextStyle(textEl.style, itemLabelModel, {\n            text: formattedLabel,\n            textAlign: itemLabelModel.getShallow('align', true)\n                || labelLayout.textAlign,\n            textVerticalAlign: itemLabelModel.getShallow('verticalAlign', true)\n                || itemLabelModel.getShallow('baseline', true)\n                || labelLayout.textVerticalAlign,\n            textFill: typeof textColor === 'function'\n                ? textColor(\n                    // (1) In category axis with data zoom, tick is not the original\n                    // index of axis.data. So tick should not be exposed to user\n                    // in category axis.\n                    // (2) Compatible with previous version, which always use formatted label as\n                    // input. But in interval scale the formatted label is like '223,445', which\n                    // maked user repalce ','. So we modify it to return original val but remain\n                    // it as 'string' to avoid error in replacing.\n                    axis.type === 'category'\n                        ? rawLabel\n                        : axis.type === 'value'\n                        ? tickValue + ''\n                        : tickValue,\n                    index\n                )\n                : textColor\n        });\n\n        // Pack data for mouse event\n        if (triggerEvent) {\n            textEl.eventData = makeAxisEventDataBase(axisModel);\n            textEl.eventData.targetType = 'axisLabel';\n            textEl.eventData.value = rawLabel;\n        }\n\n        // FIXME\n        axisBuilder._dumbGroup.add(textEl);\n        textEl.updateTransform();\n\n        labelEls.push(textEl);\n        axisBuilder.group.add(textEl);\n\n        textEl.decomposeTransform();\n\n    });\n\n    return labelEls;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Build axisPointerModel, mergin tooltip.axisPointer model for each axis.\n// allAxesInfo should be updated when setOption performed.\n\n\nfunction fixValue(axisModel) {\n    var axisInfo = getAxisInfo(axisModel);\n    if (!axisInfo) {\n        return;\n    }\n\n    var axisPointerModel = axisInfo.axisPointerModel;\n    var scale = axisInfo.axis.scale;\n    var option = axisPointerModel.option;\n    var status = axisPointerModel.get('status');\n    var value = axisPointerModel.get('value');\n\n    // Parse init value for category and time axis.\n    if (value != null) {\n        value = scale.parse(value);\n    }\n\n    var useHandle = isHandleTrigger(axisPointerModel);\n    // If `handle` used, `axisPointer` will always be displayed, so value\n    // and status should be initialized.\n    if (status == null) {\n        option.status = useHandle ? 'show' : 'hide';\n    }\n\n    var extent = scale.getExtent().slice();\n    extent[0] > extent[1] && extent.reverse();\n\n    if (// Pick a value on axis when initializing.\n        value == null\n        // If both `handle` and `dataZoom` are used, value may be out of axis extent,\n        // where we should re-pick a value to keep `handle` displaying normally.\n        || value > extent[1]\n    ) {\n        // Make handle displayed on the end of the axis when init, which looks better.\n        value = extent[1];\n    }\n    if (value < extent[0]) {\n        value = extent[0];\n    }\n\n    option.value = value;\n\n    if (useHandle) {\n        option.status = axisInfo.axis.scale.isBlank() ? 'hide' : 'show';\n    }\n}\n\nfunction getAxisInfo(axisModel) {\n    var coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') || {}).coordSysAxesInfo;\n    return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)];\n}\n\nfunction getAxisPointerModel(axisModel) {\n    var axisInfo = getAxisInfo(axisModel);\n    return axisInfo && axisInfo.axisPointerModel;\n}\n\nfunction isHandleTrigger(axisPointerModel) {\n    return !!axisPointerModel.get('handle.show');\n}\n\n/**\n * @param {module:echarts/model/Model} model\n * @return {string} unique key\n */\nfunction makeKey(model) {\n    return model.type + '||' + model.id;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Base class of AxisView.\n */\nvar AxisView = extendComponentView({\n\n    type: 'axis',\n\n    /**\n     * @private\n     */\n    _axisPointer: null,\n\n    /**\n     * @protected\n     * @type {string}\n     */\n    axisPointerClass: null,\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n        // FIXME\n        // This process should proformed after coordinate systems updated\n        // (axis scale updated), and should be performed each time update.\n        // So put it here temporarily, although it is not appropriate to\n        // put a model-writing procedure in `view`.\n        this.axisPointerClass && fixValue(axisModel);\n\n        AxisView.superApply(this, 'render', arguments);\n\n        updateAxisPointer(this, axisModel, ecModel, api, payload, true);\n    },\n\n    /**\n     * Action handler.\n     * @public\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/model/Global} ecModel\n     * @param {module:echarts/ExtensionAPI} api\n     * @param {Object} payload\n     */\n    updateAxisPointer: function (axisModel, ecModel, api, payload, force) {\n        updateAxisPointer(this, axisModel, ecModel, api, payload, false);\n    },\n\n    /**\n     * @override\n     */\n    remove: function (ecModel, api) {\n        var axisPointer = this._axisPointer;\n        axisPointer && axisPointer.remove(api);\n        AxisView.superApply(this, 'remove', arguments);\n    },\n\n    /**\n     * @override\n     */\n    dispose: function (ecModel, api) {\n        disposeAxisPointer(this, api);\n        AxisView.superApply(this, 'dispose', arguments);\n    }\n\n});\n\nfunction updateAxisPointer(axisView, axisModel, ecModel, api, payload, forceRender) {\n    var Clazz = AxisView.getAxisPointerClass(axisView.axisPointerClass);\n    if (!Clazz) {\n        return;\n    }\n    var axisPointerModel = getAxisPointerModel(axisModel);\n    axisPointerModel\n        ? (axisView._axisPointer || (axisView._axisPointer = new Clazz()))\n            .render(axisModel, axisPointerModel, api, forceRender)\n        : disposeAxisPointer(axisView, api);\n}\n\nfunction disposeAxisPointer(axisView, ecModel, api) {\n    var axisPointer = axisView._axisPointer;\n    axisPointer && axisPointer.dispose(ecModel, api);\n    axisView._axisPointer = null;\n}\n\nvar axisPointerClazz = [];\n\nAxisView.registerAxisPointerClass = function (type, clazz) {\n    if (__DEV__) {\n        if (axisPointerClazz[type]) {\n            throw new Error('axisPointer ' + type + ' exists');\n        }\n    }\n    axisPointerClazz[type] = clazz;\n};\n\nAxisView.getAxisPointerClass = function (type) {\n    return type && axisPointerClazz[type];\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Can only be called after coordinate system creation stage.\n * (Can be called before coordinate system update stage).\n *\n * @param {Object} opt {labelInside}\n * @return {Object} {\n *  position, rotation, labelDirection, labelOffset,\n *  tickDirection, labelRotate, z2\n * }\n */\nfunction layout$1(gridModel, axisModel, opt) {\n    opt = opt || {};\n    var grid = gridModel.coordinateSystem;\n    var axis = axisModel.axis;\n    var layout = {};\n    var otherAxisOnZeroOf = axis.getAxesOnZeroOf()[0];\n\n    var rawAxisPosition = axis.position;\n    var axisPosition = otherAxisOnZeroOf ? 'onZero' : rawAxisPosition;\n    var axisDim = axis.dim;\n\n    var rect = grid.getRect();\n    var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];\n    var idx = {left: 0, right: 1, top: 0, bottom: 1, onZero: 2};\n    var axisOffset = axisModel.get('offset') || 0;\n\n    var posBound = axisDim === 'x'\n        ? [rectBound[2] - axisOffset, rectBound[3] + axisOffset]\n        : [rectBound[0] - axisOffset, rectBound[1] + axisOffset];\n\n    if (otherAxisOnZeroOf) {\n        var onZeroCoord = otherAxisOnZeroOf.toGlobalCoord(otherAxisOnZeroOf.dataToCoord(0));\n        posBound[idx.onZero] = Math.max(Math.min(onZeroCoord, posBound[1]), posBound[0]);\n    }\n\n    // Axis position\n    layout.position = [\n        axisDim === 'y' ? posBound[idx[axisPosition]] : rectBound[0],\n        axisDim === 'x' ? posBound[idx[axisPosition]] : rectBound[3]\n    ];\n\n    // Axis rotation\n    layout.rotation = Math.PI / 2 * (axisDim === 'x' ? 0 : 1);\n\n    // Tick and label direction, x y is axisDim\n    var dirMap = {top: -1, bottom: 1, left: -1, right: 1};\n\n    layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition];\n    layout.labelOffset = otherAxisOnZeroOf ? posBound[idx[rawAxisPosition]] - posBound[idx.onZero] : 0;\n\n    if (axisModel.get('axisTick.inside')) {\n        layout.tickDirection = -layout.tickDirection;\n    }\n    if (retrieve(opt.labelInside, axisModel.get('axisLabel.inside'))) {\n        layout.labelDirection = -layout.labelDirection;\n    }\n\n    // Special label rotation\n    var labelRotate = axisModel.get('axisLabel.rotate');\n    layout.labelRotate = axisPosition === 'top' ? -labelRotate : labelRotate;\n\n    // Over splitLine and splitArea\n    layout.z2 = 1;\n\n    return layout;\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar axisBuilderAttrs = [\n    'axisLine', 'axisTickLabel', 'axisName'\n];\nvar selfBuilderAttrs = [\n    'splitArea', 'splitLine'\n];\n\n// function getAlignWithLabel(model, axisModel) {\n//     var alignWithLabel = model.get('alignWithLabel');\n//     if (alignWithLabel === 'auto') {\n//         alignWithLabel = axisModel.get('axisTick.alignWithLabel');\n//     }\n//     return alignWithLabel;\n// }\n\nvar CartesianAxisView = AxisView.extend({\n\n    type: 'cartesianAxis',\n\n    axisPointerClass: 'CartesianAxisPointer',\n\n    /**\n     * @override\n     */\n    render: function (axisModel, ecModel, api, payload) {\n\n        this.group.removeAll();\n\n        var oldAxisGroup = this._axisGroup;\n        this._axisGroup = new Group();\n\n        this.group.add(this._axisGroup);\n\n        if (!axisModel.get('show')) {\n            return;\n        }\n\n        var gridModel = axisModel.getCoordSysModel();\n\n        var layout = layout$1(gridModel, axisModel);\n\n        var axisBuilder = new AxisBuilder(axisModel, layout);\n\n        each$1(axisBuilderAttrs, axisBuilder.add, axisBuilder);\n\n        this._axisGroup.add(axisBuilder.getGroup());\n\n        each$1(selfBuilderAttrs, function (name) {\n            if (axisModel.get(name + '.show')) {\n                this['_' + name](axisModel, gridModel);\n            }\n        }, this);\n\n        groupTransition(oldAxisGroup, this._axisGroup, axisModel);\n\n        CartesianAxisView.superCall(this, 'render', axisModel, ecModel, api, payload);\n    },\n\n    remove: function () {\n        this._splitAreaColors = null;\n    },\n\n    /**\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/coord/cartesian/GridModel} gridModel\n     * @private\n     */\n    _splitLine: function (axisModel, gridModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitLineModel = axisModel.getModel('splitLine');\n        var lineStyleModel = splitLineModel.getModel('lineStyle');\n        var lineColors = lineStyleModel.get('color');\n\n        lineColors = isArray(lineColors) ? lineColors : [lineColors];\n\n        var gridRect = gridModel.coordinateSystem.getRect();\n        var isHorizontal = axis.isHorizontal();\n\n        var lineCount = 0;\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitLineModel\n        });\n\n        var p1 = [];\n        var p2 = [];\n\n        // Simple optimization\n        // Batching the lines if color are the same\n        var lineStyle = lineStyleModel.getLineStyle();\n        for (var i = 0; i < ticksCoords.length; i++) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n\n            if (isHorizontal) {\n                p1[0] = tickCoord;\n                p1[1] = gridRect.y;\n                p2[0] = tickCoord;\n                p2[1] = gridRect.y + gridRect.height;\n            }\n            else {\n                p1[0] = gridRect.x;\n                p1[1] = tickCoord;\n                p2[0] = gridRect.x + gridRect.width;\n                p2[1] = tickCoord;\n            }\n\n            var colorIndex = (lineCount++) % lineColors.length;\n            var tickValue = ticksCoords[i].tickValue;\n            this._axisGroup.add(new Line(subPixelOptimizeLine({\n                anid: tickValue != null ? 'line_' + ticksCoords[i].tickValue : null,\n                shape: {\n                    x1: p1[0],\n                    y1: p1[1],\n                    x2: p2[0],\n                    y2: p2[1]\n                },\n                style: defaults({\n                    stroke: lineColors[colorIndex]\n                }, lineStyle),\n                silent: true\n            })));\n        }\n    },\n\n    /**\n     * @param {module:echarts/coord/cartesian/AxisModel} axisModel\n     * @param {module:echarts/coord/cartesian/GridModel} gridModel\n     * @private\n     */\n    _splitArea: function (axisModel, gridModel) {\n        var axis = axisModel.axis;\n\n        if (axis.scale.isBlank()) {\n            return;\n        }\n\n        var splitAreaModel = axisModel.getModel('splitArea');\n        var areaStyleModel = splitAreaModel.getModel('areaStyle');\n        var areaColors = areaStyleModel.get('color');\n\n        var gridRect = gridModel.coordinateSystem.getRect();\n\n        var ticksCoords = axis.getTicksCoords({\n            tickModel: splitAreaModel,\n            clamp: true\n        });\n\n        if (!ticksCoords.length) {\n            return;\n        }\n\n        // For Making appropriate splitArea animation, the color and anid\n        // should be corresponding to previous one if possible.\n        var areaColorsLen = areaColors.length;\n        var lastSplitAreaColors = this._splitAreaColors;\n        var newSplitAreaColors = createHashMap();\n        var colorIndex = 0;\n        if (lastSplitAreaColors) {\n            for (var i = 0; i < ticksCoords.length; i++) {\n                var cIndex = lastSplitAreaColors.get(ticksCoords[i].tickValue);\n                if (cIndex != null) {\n                    colorIndex = (cIndex + (areaColorsLen - 1) * i) % areaColorsLen;\n                    break;\n                }\n            }\n        }\n\n        var prev = axis.toGlobalCoord(ticksCoords[0].coord);\n\n        var areaStyle = areaStyleModel.getAreaStyle();\n        areaColors = isArray(areaColors) ? areaColors : [areaColors];\n\n        for (var i = 1; i < ticksCoords.length; i++) {\n            var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);\n\n            var x;\n            var y;\n            var width;\n            var height;\n            if (axis.isHorizontal()) {\n                x = prev;\n                y = gridRect.y;\n                width = tickCoord - x;\n                height = gridRect.height;\n                prev = x + width;\n            }\n            else {\n                x = gridRect.x;\n                y = prev;\n                width = gridRect.width;\n                height = tickCoord - y;\n                prev = y + height;\n            }\n\n            var tickValue = ticksCoords[i - 1].tickValue;\n            tickValue != null && newSplitAreaColors.set(tickValue, colorIndex);\n\n            this._axisGroup.add(new Rect({\n                anid: tickValue != null ? 'area_' + tickValue : null,\n                shape: {\n                    x: x,\n                    y: y,\n                    width: width,\n                    height: height\n                },\n                style: defaults({\n                    fill: areaColors[colorIndex]\n                }, areaStyle),\n                silent: true\n            }));\n\n            colorIndex = (colorIndex + 1) % areaColorsLen;\n        }\n\n        this._splitAreaColors = newSplitAreaColors;\n    }\n});\n\nCartesianAxisView.extend({\n    type: 'xAxis'\n});\nCartesianAxisView.extend({\n    type: 'yAxis'\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Grid view\nextendComponentView({\n\n    type: 'grid',\n\n    render: function (gridModel, ecModel) {\n        this.group.removeAll();\n        if (gridModel.get('show')) {\n            this.group.add(new Rect({\n                shape: gridModel.coordinateSystem.getRect(),\n                style: defaults({\n                    fill: gridModel.get('backgroundColor')\n                }, gridModel.getItemStyle()),\n                silent: true,\n                z2: -1\n            }));\n        }\n    }\n\n});\n\nregisterPreprocessor(function (option) {\n    // Only create grid when need\n    if (option.xAxis && option.yAxis && !option.grid) {\n        option.grid = {};\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterVisual(visualSymbol('line', 'circle', 'line'));\nregisterLayout(layoutPoints('line'));\n\n// Down sample after filter\nregisterProcessor(\n    PRIORITY.PROCESSOR.STATISTIC,\n    dataSample('line')\n);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BaseBarSeries = SeriesModel.extend({\n\n    type: 'series.__base_bar__',\n\n    getInitialData: function (option, ecModel) {\n        return createListFromArray(this.getSource(), this);\n    },\n\n    getMarkerPosition: function (value) {\n        var coordSys = this.coordinateSystem;\n        if (coordSys) {\n            // PENDING if clamp ?\n            var pt = coordSys.dataToPoint(coordSys.clampData(value));\n            var data = this.getData();\n            var offset = data.getLayout('offset');\n            var size = data.getLayout('size');\n            var offsetIndex = coordSys.getBaseAxis().isHorizontal() ? 0 : 1;\n            pt[offsetIndex] += offset + size / 2;\n            return pt;\n        }\n        return [NaN, NaN];\n    },\n\n    defaultOption: {\n        zlevel: 0,                  // 一级层叠\n        z: 2,                       // 二级层叠\n        coordinateSystem: 'cartesian2d',\n        legendHoverLink: true,\n        // stack: null\n\n        // Cartesian coordinate system\n        // xAxisIndex: 0,\n        // yAxisIndex: 0,\n\n        // 最小高度改为0\n        barMinHeight: 0,\n        // 最小角度为0，仅对极坐标系下的柱状图有效\n        barMinAngle: 0,\n        // cursor: null,\n\n        large: false,\n        largeThreshold: 400,\n        progressive: 3e3,\n        progressiveChunkMode: 'mod',\n\n        // barMaxWidth: null,\n        // 默认自适应\n        // barWidth: null,\n        // 柱间距离，默认为柱形宽度的30%，可设固定值\n        // barGap: '30%',\n        // 类目间柱形距离，默认为类目间距的20%，可设固定值\n        // barCategoryGap: '20%',\n        // label: {\n        //      show: false\n        // },\n        itemStyle: {},\n        emphasis: {}\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nBaseBarSeries.extend({\n\n    type: 'series.bar',\n\n    dependencies: ['grid', 'polar'],\n\n    brushSelector: 'rect',\n\n    /**\n     * @override\n     */\n    getProgressive: function () {\n        // Do not support progressive in normal mode.\n        return this.get('large')\n            ? this.get('progressive')\n            : false;\n    },\n\n    /**\n     * @override\n     */\n    getProgressiveThreshold: function () {\n        // Do not support progressive in normal mode.\n        var progressiveThreshold = this.get('progressiveThreshold');\n        var largeThreshold = this.get('largeThreshold');\n        if (largeThreshold > progressiveThreshold) {\n            progressiveThreshold = largeThreshold;\n        }\n        return progressiveThreshold;\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction setLabel(\n    normalStyle, hoverStyle, itemModel, color, seriesModel, dataIndex, labelPositionOutside\n) {\n    var labelModel = itemModel.getModel('label');\n    var hoverLabelModel = itemModel.getModel('emphasis.label');\n\n    setLabelStyle(\n        normalStyle, hoverStyle, labelModel, hoverLabelModel,\n        {\n            labelFetcher: seriesModel,\n            labelDataIndex: dataIndex,\n            defaultText: getDefaultLabel(seriesModel.getData(), dataIndex),\n            isRectText: true,\n            autoColor: color\n        }\n    );\n\n    fixPosition(normalStyle);\n    fixPosition(hoverStyle);\n}\n\nfunction fixPosition(style, labelPositionOutside) {\n    if (style.textPosition === 'outside') {\n        style.textPosition = labelPositionOutside;\n    }\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar getBarItemStyle = makeStyleMapper(\n    [\n        ['fill', 'color'],\n        ['stroke', 'borderColor'],\n        ['lineWidth', 'borderWidth'],\n        // Compatitable with 2\n        ['stroke', 'barBorderColor'],\n        ['lineWidth', 'barBorderWidth'],\n        ['opacity'],\n        ['shadowBlur'],\n        ['shadowOffsetX'],\n        ['shadowOffsetY'],\n        ['shadowColor']\n    ]\n);\n\nvar barItemStyle = {\n    getBarItemStyle: function (excludes) {\n        var style = getBarItemStyle(this, excludes);\n        if (this.getBorderLineDash) {\n            var lineDash = this.getBorderLineDash();\n            lineDash && (style.lineDash = lineDash);\n        }\n        return style;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'barBorderWidth'];\n\n// FIXME\n// Just for compatible with ec2.\nextend(Model.prototype, barItemStyle);\n\nextendChartView({\n\n    type: 'bar',\n\n    render: function (seriesModel, ecModel, api) {\n        this._updateDrawMode(seriesModel);\n\n        var coordinateSystemType = seriesModel.get('coordinateSystem');\n\n        if (coordinateSystemType === 'cartesian2d'\n            || coordinateSystemType === 'polar'\n        ) {\n            this._isLargeDraw\n                ? this._renderLarge(seriesModel, ecModel, api)\n                : this._renderNormal(seriesModel, ecModel, api);\n        }\n        else if (__DEV__) {\n            console.warn('Only cartesian2d and polar supported for bar.');\n        }\n\n        return this.group;\n    },\n\n    incrementalPrepareRender: function (seriesModel, ecModel, api) {\n        this._clear();\n        this._updateDrawMode(seriesModel);\n    },\n\n    incrementalRender: function (params, seriesModel, ecModel, api) {\n        // Do not support progressive in normal mode.\n        this._incrementalRenderLarge(params, seriesModel);\n    },\n\n    _updateDrawMode: function (seriesModel) {\n        var isLargeDraw = seriesModel.pipelineContext.large;\n        if (this._isLargeDraw == null || isLargeDraw ^ this._isLargeDraw) {\n            this._isLargeDraw = isLargeDraw;\n            this._clear();\n        }\n    },\n\n    _renderNormal: function (seriesModel, ecModel, api) {\n        var group = this.group;\n        var data = seriesModel.getData();\n        var oldData = this._data;\n\n        var coord = seriesModel.coordinateSystem;\n        var baseAxis = coord.getBaseAxis();\n        var isHorizontalOrRadial;\n\n        if (coord.type === 'cartesian2d') {\n            isHorizontalOrRadial = baseAxis.isHorizontal();\n        }\n        else if (coord.type === 'polar') {\n            isHorizontalOrRadial = baseAxis.dim === 'angle';\n        }\n\n        var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null;\n\n        data.diff(oldData)\n            .add(function (dataIndex) {\n                if (!data.hasValue(dataIndex)) {\n                    return;\n                }\n\n                var itemModel = data.getItemModel(dataIndex);\n                var layout = getLayout[coord.type](data, dataIndex, itemModel);\n                var el = elementCreator[coord.type](\n                    data, dataIndex, itemModel, layout, isHorizontalOrRadial, animationModel\n                );\n                data.setItemGraphicEl(dataIndex, el);\n                group.add(el);\n\n                updateStyle(\n                    el, data, dataIndex, itemModel, layout,\n                    seriesModel, isHorizontalOrRadial, coord.type === 'polar'\n                );\n            })\n            .update(function (newIndex, oldIndex) {\n                var el = oldData.getItemGraphicEl(oldIndex);\n\n                if (!data.hasValue(newIndex)) {\n                    group.remove(el);\n                    return;\n                }\n\n                var itemModel = data.getItemModel(newIndex);\n                var layout = getLayout[coord.type](data, newIndex, itemModel);\n\n                if (el) {\n                    updateProps(el, {shape: layout}, animationModel, newIndex);\n                }\n                else {\n                    el = elementCreator[coord.type](\n                        data, newIndex, itemModel, layout, isHorizontalOrRadial, animationModel, true\n                    );\n                }\n\n                data.setItemGraphicEl(newIndex, el);\n                // Add back\n                group.add(el);\n\n                updateStyle(\n                    el, data, newIndex, itemModel, layout,\n                    seriesModel, isHorizontalOrRadial, coord.type === 'polar'\n                );\n            })\n            .remove(function (dataIndex) {\n                var el = oldData.getItemGraphicEl(dataIndex);\n                if (coord.type === 'cartesian2d') {\n                    el && removeRect(dataIndex, animationModel, el);\n                }\n                else {\n                    el && removeSector(dataIndex, animationModel, el);\n                }\n            })\n            .execute();\n\n        this._data = data;\n    },\n\n    _renderLarge: function (seriesModel, ecModel, api) {\n        this._clear();\n        createLarge(seriesModel, this.group);\n    },\n\n    _incrementalRenderLarge: function (params, seriesModel) {\n        createLarge(seriesModel, this.group, true);\n    },\n\n    dispose: noop,\n\n    remove: function (ecModel) {\n        this._clear(ecModel);\n    },\n\n    _clear: function (ecModel) {\n        var group = this.group;\n        var data = this._data;\n        if (ecModel && ecModel.get('animation') && data && !this._isLargeDraw) {\n            data.eachItemGraphicEl(function (el) {\n                if (el.type === 'sector') {\n                    removeSector(el.dataIndex, ecModel, el);\n                }\n                else {\n                    removeRect(el.dataIndex, ecModel, el);\n                }\n            });\n        }\n        else {\n            group.removeAll();\n        }\n        this._data = null;\n    }\n\n});\n\nvar elementCreator = {\n\n    cartesian2d: function (\n        data, dataIndex, itemModel, layout, isHorizontal,\n        animationModel, isUpdate\n    ) {\n        var rect = new Rect({shape: extend({}, layout)});\n\n        // Animation\n        if (animationModel) {\n            var rectShape = rect.shape;\n            var animateProperty = isHorizontal ? 'height' : 'width';\n            var animateTarget = {};\n            rectShape[animateProperty] = 0;\n            animateTarget[animateProperty] = layout[animateProperty];\n            graphic[isUpdate ? 'updateProps' : 'initProps'](rect, {\n                shape: animateTarget\n            }, animationModel, dataIndex);\n        }\n\n        return rect;\n    },\n\n    polar: function (\n        data, dataIndex, itemModel, layout, isRadial,\n        animationModel, isUpdate\n    ) {\n        // Keep the same logic with bar in catesion: use end value to control\n        // direction. Notice that if clockwise is true (by default), the sector\n        // will always draw clockwisely, no matter whether endAngle is greater\n        // or less than startAngle.\n        var clockwise = layout.startAngle < layout.endAngle;\n        var sector = new Sector({\n            shape: defaults({clockwise: clockwise}, layout)\n        });\n\n        // Animation\n        if (animationModel) {\n            var sectorShape = sector.shape;\n            var animateProperty = isRadial ? 'r' : 'endAngle';\n            var animateTarget = {};\n            sectorShape[animateProperty] = isRadial ? 0 : layout.startAngle;\n            animateTarget[animateProperty] = layout[animateProperty];\n            graphic[isUpdate ? 'updateProps' : 'initProps'](sector, {\n                shape: animateTarget\n            }, animationModel, dataIndex);\n        }\n\n        return sector;\n    }\n};\n\nfunction removeRect(dataIndex, animationModel, el) {\n    // Not show text when animating\n    el.style.text = null;\n    updateProps(el, {\n        shape: {\n            width: 0\n        }\n    }, animationModel, dataIndex, function () {\n        el.parent && el.parent.remove(el);\n    });\n}\n\nfunction removeSector(dataIndex, animationModel, el) {\n    // Not show text when animating\n    el.style.text = null;\n    updateProps(el, {\n        shape: {\n            r: el.shape.r0\n        }\n    }, animationModel, dataIndex, function () {\n        el.parent && el.parent.remove(el);\n    });\n}\n\nvar getLayout = {\n    cartesian2d: function (data, dataIndex, itemModel) {\n        var layout = data.getItemLayout(dataIndex);\n        var fixedLineWidth = getLineWidth(itemModel, layout);\n\n        // fix layout with lineWidth\n        var signX = layout.width > 0 ? 1 : -1;\n        var signY = layout.height > 0 ? 1 : -1;\n        return {\n            x: layout.x + signX * fixedLineWidth / 2,\n            y: layout.y + signY * fixedLineWidth / 2,\n            width: layout.width - signX * fixedLineWidth,\n            height: layout.height - signY * fixedLineWidth\n        };\n    },\n\n    polar: function (data, dataIndex, itemModel) {\n        var layout = data.getItemLayout(dataIndex);\n        return {\n            cx: layout.cx,\n            cy: layout.cy,\n            r0: layout.r0,\n            r: layout.r,\n            startAngle: layout.startAngle,\n            endAngle: layout.endAngle\n        };\n    }\n};\n\nfunction updateStyle(\n    el, data, dataIndex, itemModel, layout, seriesModel, isHorizontal, isPolar\n) {\n    var color = data.getItemVisual(dataIndex, 'color');\n    var opacity = data.getItemVisual(dataIndex, 'opacity');\n    var itemStyleModel = itemModel.getModel('itemStyle');\n    var hoverStyle = itemModel.getModel('emphasis.itemStyle').getBarItemStyle();\n\n    if (!isPolar) {\n        el.setShape('r', itemStyleModel.get('barBorderRadius') || 0);\n    }\n\n    el.useStyle(defaults(\n        {\n            fill: color,\n            opacity: opacity\n        },\n        itemStyleModel.getBarItemStyle()\n    ));\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && el.attr('cursor', cursorStyle);\n\n    var labelPositionOutside = isHorizontal\n        ? (layout.height > 0 ? 'bottom' : 'top')\n        : (layout.width > 0 ? 'left' : 'right');\n\n    if (!isPolar) {\n        setLabel(\n            el.style, hoverStyle, itemModel, color,\n            seriesModel, dataIndex, labelPositionOutside\n        );\n    }\n\n    setHoverStyle(el, hoverStyle);\n}\n\n// In case width or height are too small.\nfunction getLineWidth(itemModel, rawLayout) {\n    var lineWidth = itemModel.get(BAR_BORDER_WIDTH_QUERY) || 0;\n    return Math.min(lineWidth, Math.abs(rawLayout.width), Math.abs(rawLayout.height));\n}\n\n\nvar LargePath = Path.extend({\n\n    type: 'largeBar',\n\n    shape: {points: []},\n\n    buildPath: function (ctx, shape) {\n        // Drawing lines is more efficient than drawing\n        // a whole line or drawing rects.\n        var points = shape.points;\n        var startPoint = this.__startPoint;\n        var valueIdx = this.__valueIdx;\n\n        for (var i = 0; i < points.length; i += 2) {\n            startPoint[this.__valueIdx] = points[i + valueIdx];\n            ctx.moveTo(startPoint[0], startPoint[1]);\n            ctx.lineTo(points[i], points[i + 1]);\n        }\n    }\n});\n\nfunction createLarge(seriesModel, group, incremental) {\n    // TODO support polar\n    var data = seriesModel.getData();\n    var startPoint = [];\n    var valueIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0;\n    startPoint[1 - valueIdx] = data.getLayout('valueAxisStart');\n\n    var el = new LargePath({\n        shape: {points: data.getLayout('largePoints')},\n        incremental: !!incremental,\n        __startPoint: startPoint,\n        __valueIdx: valueIdx\n    });\n    group.add(el);\n    setLargeStyle(el, seriesModel, data);\n}\n\nfunction setLargeStyle(el, seriesModel, data) {\n    var borderColor = data.getVisual('borderColor') || data.getVisual('color');\n    var itemStyle = seriesModel.getModel('itemStyle').getItemStyle(['color', 'borderColor']);\n\n    el.useStyle(itemStyle);\n    el.style.fill = null;\n    el.style.stroke = borderColor;\n    el.style.lineWidth = data.getLayout('barWidth');\n}\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// In case developer forget to include grid component\nregisterLayout(curry(layout, 'bar'));\n// Should after normal bar layout, otherwise it is blocked by normal bar layout.\nregisterLayout(largeLayout);\n\nregisterVisual({\n    seriesType: 'bar',\n    reset: function (seriesModel) {\n        // Visual coding for legend\n        seriesModel.getData().setVisual('legendSymbol', 'roundRect');\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\n/**\n * [Usage]:\n * (1)\n * createListSimply(seriesModel, ['value']);\n * (2)\n * createListSimply(seriesModel, {\n *     coordDimensions: ['value'],\n *     dimensionsCount: 5\n * });\n *\n * @param {module:echarts/model/Series} seriesModel\n * @param {Object|Array.<string|Object>} opt opt or coordDimensions\n *        The options in opt, see `echarts/data/helper/createDimensions`\n * @param {Array.<string>} [nameList]\n * @return {module:echarts/data/List}\n */\nvar createListSimply = function (seriesModel, opt, nameList) {\n    opt = isArray(opt) && {coordDimensions: opt} || extend({}, opt);\n\n    var source = seriesModel.getSource();\n\n    var dimensionsInfo = createDimensions(source, opt);\n\n    var list = new List(dimensionsInfo, seriesModel);\n    list.initData(source, nameList);\n\n    return list;\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * Data selectable mixin for chart series.\n * To eanble data select, option of series must have `selectedMode`.\n * And each data item will use `selected` to toggle itself selected status\n */\n\nvar dataSelectableMixin = {\n\n    /**\n     * @param {Array.<Object>} targetList [{name, value, selected}, ...]\n     *        If targetList is an array, it should like [{name: ..., value: ...}, ...].\n     *        If targetList is a \"List\", it must have coordDim: 'value' dimension and name.\n     */\n    updateSelectedMap: function (targetList) {\n        this._targetList = isArray(targetList) ? targetList.slice() : [];\n\n        this._selectTargetMap = reduce(targetList || [], function (targetMap, target) {\n            targetMap.set(target.name, target);\n            return targetMap;\n        }, createHashMap());\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    // PENGING If selectedMode is null ?\n    select: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        var selectedMode = this.get('selectedMode');\n        if (selectedMode === 'single') {\n            this._selectTargetMap.each(function (target) {\n                target.selected = false;\n            });\n        }\n        target && (target.selected = true);\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    unSelect: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        // var selectedMode = this.get('selectedMode');\n        // selectedMode !== 'single' && target && (target.selected = false);\n        target && (target.selected = false);\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    toggleSelected: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        if (target != null) {\n            this[target.selected ? 'unSelect' : 'select'](name, id);\n            return target.selected;\n        }\n    },\n\n    /**\n     * Either name or id should be passed as input here.\n     * If both of them are defined, id is used.\n     *\n     * @param {string|undefined} name name of data\n     * @param {number|undefined} id dataIndex of data\n     */\n    isSelected: function (name, id) {\n        var target = id != null\n            ? this._targetList[id]\n            : this._selectTargetMap.get(name);\n        return target && target.selected;\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar PieSeries = extendSeriesModel({\n\n    type: 'series.pie',\n\n    // Overwrite\n    init: function (option) {\n        PieSeries.superApply(this, 'init', arguments);\n\n        // Enable legend selection for each data item\n        // Use a function instead of direct access because data reference may changed\n        this.legendDataProvider = function () {\n            return this.getRawData();\n        };\n\n        this.updateSelectedMap(this._createSelectableList());\n\n        this._defaultLabelLine(option);\n    },\n\n    // Overwrite\n    mergeOption: function (newOption) {\n        PieSeries.superCall(this, 'mergeOption', newOption);\n\n        this.updateSelectedMap(this._createSelectableList());\n    },\n\n    getInitialData: function (option, ecModel) {\n        return createListSimply(this, ['value']);\n    },\n\n    _createSelectableList: function () {\n        var data = this.getRawData();\n        var valueDim = data.mapDimension('value');\n        var targetList = [];\n        for (var i = 0, len = data.count(); i < len; i++) {\n            targetList.push({\n                name: data.getName(i),\n                value: data.get(valueDim, i),\n                selected: retrieveRawAttr(data, i, 'selected')\n            });\n        }\n        return targetList;\n    },\n\n    // Overwrite\n    getDataParams: function (dataIndex) {\n        var data = this.getData();\n        var params = PieSeries.superCall(this, 'getDataParams', dataIndex);\n        // FIXME toFixed?\n\n        var valueList = [];\n        data.each(data.mapDimension('value'), function (value) {\n            valueList.push(value);\n        });\n\n        params.percent = getPercentWithPrecision(\n            valueList,\n            dataIndex,\n            data.hostModel.get('percentPrecision')\n        );\n\n        params.$vars.push('percent');\n        return params;\n    },\n\n    _defaultLabelLine: function (option) {\n        // Extend labelLine emphasis\n        defaultEmphasis(option, 'labelLine', ['show']);\n\n        var labelLineNormalOpt = option.labelLine;\n        var labelLineEmphasisOpt = option.emphasis.labelLine;\n        // Not show label line if `label.normal.show = false`\n        labelLineNormalOpt.show = labelLineNormalOpt.show\n            && option.label.show;\n        labelLineEmphasisOpt.show = labelLineEmphasisOpt.show\n            && option.emphasis.label.show;\n    },\n\n    defaultOption: {\n        zlevel: 0,\n        z: 2,\n        legendHoverLink: true,\n\n        hoverAnimation: true,\n        // 默认全局居中\n        center: ['50%', '50%'],\n        radius: [0, '75%'],\n        // 默认顺时针\n        clockwise: true,\n        startAngle: 90,\n        // 最小角度改为0\n        minAngle: 0,\n        // 选中时扇区偏移量\n        selectedOffset: 10,\n        // 高亮扇区偏移量\n        hoverOffset: 10,\n\n        // If use strategy to avoid label overlapping\n        avoidLabelOverlap: true,\n        // 选择模式，默认关闭，可选single，multiple\n        // selectedMode: false,\n        // 南丁格尔玫瑰图模式，'radius'（半径） | 'area'（面积）\n        // roseType: null,\n\n        percentPrecision: 2,\n\n        // If still show when all data zero.\n        stillShowZeroSum: true,\n\n        // cursor: null,\n\n        label: {\n            // If rotate around circle\n            rotate: false,\n            show: true,\n            // 'outer', 'inside', 'center'\n            position: 'outer'\n            // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调\n            // 默认使用全局文本样式，详见TEXTSTYLE\n            // distance: 当position为inner时有效，为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数\n        },\n        // Enabled when label.normal.position is 'outer'\n        labelLine: {\n            show: true,\n            // 引导线两段中的第一段长度\n            length: 15,\n            // 引导线两段中的第二段长度\n            length2: 15,\n            smooth: false,\n            lineStyle: {\n                // color: 各异,\n                width: 1,\n                type: 'solid'\n            }\n        },\n        itemStyle: {\n            borderWidth: 1\n        },\n\n        // Animation type canbe expansion, scale\n        animationType: 'expansion',\n\n        animationEasing: 'cubicOut'\n    }\n});\n\nmixin(PieSeries, dataSelectableMixin);\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * @param {module:echarts/model/Series} seriesModel\n * @param {boolean} hasAnimation\n * @inner\n */\nfunction updateDataSelected(uid, seriesModel, hasAnimation, api) {\n    var data = seriesModel.getData();\n    var dataIndex = this.dataIndex;\n    var name = data.getName(dataIndex);\n    var selectedOffset = seriesModel.get('selectedOffset');\n\n    api.dispatchAction({\n        type: 'pieToggleSelect',\n        from: uid,\n        name: name,\n        seriesId: seriesModel.id\n    });\n\n    data.each(function (idx) {\n        toggleItemSelected(\n            data.getItemGraphicEl(idx),\n            data.getItemLayout(idx),\n            seriesModel.isSelected(data.getName(idx)),\n            selectedOffset,\n            hasAnimation\n        );\n    });\n}\n\n/**\n * @param {module:zrender/graphic/Sector} el\n * @param {Object} layout\n * @param {boolean} isSelected\n * @param {number} selectedOffset\n * @param {boolean} hasAnimation\n * @inner\n */\nfunction toggleItemSelected(el, layout, isSelected, selectedOffset, hasAnimation) {\n    var midAngle = (layout.startAngle + layout.endAngle) / 2;\n\n    var dx = Math.cos(midAngle);\n    var dy = Math.sin(midAngle);\n\n    var offset = isSelected ? selectedOffset : 0;\n    var position = [dx * offset, dy * offset];\n\n    hasAnimation\n        // animateTo will stop revious animation like update transition\n        ? el.animate()\n            .when(200, {\n                position: position\n            })\n            .start('bounceOut')\n        : el.attr('position', position);\n}\n\n/**\n * Piece of pie including Sector, Label, LabelLine\n * @constructor\n * @extends {module:zrender/graphic/Group}\n */\nfunction PiePiece(data, idx) {\n\n    Group.call(this);\n\n    var sector = new Sector({\n        z2: 2\n    });\n    var polyline = new Polyline();\n    var text = new Text();\n    this.add(sector);\n    this.add(polyline);\n    this.add(text);\n\n    this.updateData(data, idx, true);\n\n    // Hover to change label and labelLine\n    function onEmphasis() {\n        polyline.ignore = polyline.hoverIgnore;\n        text.ignore = text.hoverIgnore;\n    }\n    function onNormal() {\n        polyline.ignore = polyline.normalIgnore;\n        text.ignore = text.normalIgnore;\n    }\n    this.on('emphasis', onEmphasis)\n        .on('normal', onNormal)\n        .on('mouseover', onEmphasis)\n        .on('mouseout', onNormal);\n}\n\nvar piePieceProto = PiePiece.prototype;\n\npiePieceProto.updateData = function (data, idx, firstCreate) {\n\n    var sector = this.childAt(0);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var sectorShape = extend({}, layout);\n    sectorShape.label = null;\n\n    if (firstCreate) {\n        sector.setShape(sectorShape);\n\n        var animationType = seriesModel.getShallow('animationType');\n        if (animationType === 'scale') {\n            sector.shape.r = layout.r0;\n            initProps(sector, {\n                shape: {\n                    r: layout.r\n                }\n            }, seriesModel, idx);\n        }\n        // Expansion\n        else {\n            sector.shape.endAngle = layout.startAngle;\n            updateProps(sector, {\n                shape: {\n                    endAngle: layout.endAngle\n                }\n            }, seriesModel, idx);\n        }\n\n    }\n    else {\n        updateProps(sector, {\n            shape: sectorShape\n        }, seriesModel, idx);\n    }\n\n    // Update common style\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    sector.useStyle(\n        defaults(\n            {\n                lineJoin: 'bevel',\n                fill: visualColor\n            },\n            itemModel.getModel('itemStyle').getItemStyle()\n        )\n    );\n    sector.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();\n\n    var cursorStyle = itemModel.getShallow('cursor');\n    cursorStyle && sector.attr('cursor', cursorStyle);\n\n    // Toggle selected\n    toggleItemSelected(\n        this,\n        data.getItemLayout(idx),\n        seriesModel.isSelected(null, idx),\n        seriesModel.get('selectedOffset'),\n        seriesModel.get('animation')\n    );\n\n    function onEmphasis() {\n        // Sector may has animation of updating data. Force to move to the last frame\n        // Or it may stopped on the wrong shape\n        sector.stopAnimation(true);\n        sector.animateTo({\n            shape: {\n                r: layout.r + seriesModel.get('hoverOffset')\n            }\n        }, 300, 'elasticOut');\n    }\n    function onNormal() {\n        sector.stopAnimation(true);\n        sector.animateTo({\n            shape: {\n                r: layout.r\n            }\n        }, 300, 'elasticOut');\n    }\n    sector.off('mouseover').off('mouseout').off('emphasis').off('normal');\n    if (itemModel.get('hoverAnimation') && seriesModel.isAnimationEnabled()) {\n        sector\n            .on('mouseover', onEmphasis)\n            .on('mouseout', onNormal)\n            .on('emphasis', onEmphasis)\n            .on('normal', onNormal);\n    }\n\n    this._updateLabel(data, idx);\n\n    setHoverStyle(this);\n};\n\npiePieceProto._updateLabel = function (data, idx) {\n\n    var labelLine = this.childAt(1);\n    var labelText = this.childAt(2);\n\n    var seriesModel = data.hostModel;\n    var itemModel = data.getItemModel(idx);\n    var layout = data.getItemLayout(idx);\n    var labelLayout = layout.label;\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    updateProps(labelLine, {\n        shape: {\n            points: labelLayout.linePoints || [\n                [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y]\n            ]\n        }\n    }, seriesModel, idx);\n\n    updateProps(labelText, {\n        style: {\n            x: labelLayout.x,\n            y: labelLayout.y\n        }\n    }, seriesModel, idx);\n    labelText.attr({\n        rotation: labelLayout.rotation,\n        origin: [labelLayout.x, labelLayout.y],\n        z2: 10\n    });\n\n    var labelModel = itemModel.getModel('label');\n    var labelHoverModel = itemModel.getModel('emphasis.label');\n    var labelLineModel = itemModel.getModel('labelLine');\n    var labelLineHoverModel = itemModel.getModel('emphasis.labelLine');\n    var visualColor = data.getItemVisual(idx, 'color');\n\n    setLabelStyle(\n        labelText.style, labelText.hoverStyle = {}, labelModel, labelHoverModel,\n        {\n            labelFetcher: data.hostModel,\n            labelDataIndex: idx,\n            defaultText: data.getName(idx),\n            autoColor: visualColor,\n            useInsideStyle: !!labelLayout.inside\n        },\n        {\n            textAlign: labelLayout.textAlign,\n            textVerticalAlign: labelLayout.verticalAlign,\n            opacity: data.getItemVisual(idx, 'opacity')\n        }\n    );\n\n    labelText.ignore = labelText.normalIgnore = !labelModel.get('show');\n    labelText.hoverIgnore = !labelHoverModel.get('show');\n\n    labelLine.ignore = labelLine.normalIgnore = !labelLineModel.get('show');\n    labelLine.hoverIgnore = !labelLineHoverModel.get('show');\n\n    // Default use item visual color\n    labelLine.setStyle({\n        stroke: visualColor,\n        opacity: data.getItemVisual(idx, 'opacity')\n    });\n    labelLine.setStyle(labelLineModel.getModel('lineStyle').getLineStyle());\n\n    labelLine.hoverStyle = labelLineHoverModel.getModel('lineStyle').getLineStyle();\n\n    var smooth = labelLineModel.get('smooth');\n    if (smooth && smooth === true) {\n        smooth = 0.4;\n    }\n    labelLine.setShape({\n        smooth: smooth\n    });\n};\n\ninherits(PiePiece, Group);\n\n\n// Pie view\nvar PieView = Chart.extend({\n\n    type: 'pie',\n\n    init: function () {\n        var sectorGroup = new Group();\n        this._sectorGroup = sectorGroup;\n    },\n\n    render: function (seriesModel, ecModel, api, payload) {\n        if (payload && (payload.from === this.uid)) {\n            return;\n        }\n\n        var data = seriesModel.getData();\n        var oldData = this._data;\n        var group = this.group;\n\n        var hasAnimation = ecModel.get('animation');\n        var isFirstRender = !oldData;\n        var animationType = seriesModel.get('animationType');\n\n        var onSectorClick = curry(\n            updateDataSelected, this.uid, seriesModel, hasAnimation, api\n        );\n\n        var selectedMode = seriesModel.get('selectedMode');\n\n        data.diff(oldData)\n            .add(function (idx) {\n                var piePiece = new PiePiece(data, idx);\n                // Default expansion animation\n                if (isFirstRender && animationType !== 'scale') {\n                    piePiece.eachChild(function (child) {\n                        child.stopAnimation(true);\n                    });\n                }\n\n                selectedMode && piePiece.on('click', onSectorClick);\n\n                data.setItemGraphicEl(idx, piePiece);\n\n                group.add(piePiece);\n            })\n            .update(function (newIdx, oldIdx) {\n                var piePiece = oldData.getItemGraphicEl(oldIdx);\n\n                piePiece.updateData(data, newIdx);\n\n                piePiece.off('click');\n                selectedMode && piePiece.on('click', onSectorClick);\n                group.add(piePiece);\n                data.setItemGraphicEl(newIdx, piePiece);\n            })\n            .remove(function (idx) {\n                var piePiece = oldData.getItemGraphicEl(idx);\n                group.remove(piePiece);\n            })\n            .execute();\n\n        if (\n            hasAnimation && isFirstRender && data.count() > 0\n            // Default expansion animation\n            && animationType !== 'scale'\n        ) {\n            var shape = data.getItemLayout(0);\n            var r = Math.max(api.getWidth(), api.getHeight()) / 2;\n\n            var removeClipPath = bind(group.removeClipPath, group);\n            group.setClipPath(this._createClipPath(\n                shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel\n            ));\n        }\n        else {\n            // clipPath is used in first-time animation, so remove it when otherwise. See: #8994\n            group.removeClipPath();\n        }\n\n        this._data = data;\n    },\n\n    dispose: function () {},\n\n    _createClipPath: function (\n        cx, cy, r, startAngle, clockwise, cb, seriesModel\n    ) {\n        var clipPath = new Sector({\n            shape: {\n                cx: cx,\n                cy: cy,\n                r0: 0,\n                r: r,\n                startAngle: startAngle,\n                endAngle: startAngle,\n                clockwise: clockwise\n            }\n        });\n\n        initProps(clipPath, {\n            shape: {\n                endAngle: startAngle + (clockwise ? 1 : -1) * Math.PI * 2\n            }\n        }, seriesModel, cb);\n\n        return clipPath;\n    },\n\n    /**\n     * @implement\n     */\n    containPoint: function (point, seriesModel) {\n        var data = seriesModel.getData();\n        var itemLayout = data.getItemLayout(0);\n        if (itemLayout) {\n            var dx = point[0] - itemLayout.cx;\n            var dy = point[1] - itemLayout.cy;\n            var radius = Math.sqrt(dx * dx + dy * dy);\n            return radius <= itemLayout.r && radius >= itemLayout.r0;\n        }\n    }\n\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar createDataSelectAction = function (seriesType, actionInfos) {\n    each$1(actionInfos, function (actionInfo) {\n        actionInfo.update = 'updateView';\n        /**\n         * @payload\n         * @property {string} seriesName\n         * @property {string} name\n         */\n        registerAction(actionInfo, function (payload, ecModel) {\n            var selected = {};\n            ecModel.eachComponent(\n                {mainType: 'series', subType: seriesType, query: payload},\n                function (seriesModel) {\n                    if (seriesModel[actionInfo.method]) {\n                        seriesModel[actionInfo.method](\n                            payload.name,\n                            payload.dataIndex\n                        );\n                    }\n                    var data = seriesModel.getData();\n                    // Create selected map\n                    data.each(function (idx) {\n                        var name = data.getName(idx);\n                        selected[name] = seriesModel.isSelected(name)\n                            || false;\n                    });\n                }\n            );\n            return {\n                name: payload.name,\n                selected: selected\n            };\n        });\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// Pick color from palette for each data item.\n// Applicable for charts that require applying color palette\n// in data level (like pie, funnel, chord).\nvar dataColor = function (seriesType) {\n    return {\n        getTargetSeries: function (ecModel) {\n            // Pie and funnel may use diferrent scope\n            var paletteScope = {};\n            var seiresModelMap = createHashMap();\n\n            ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n                seriesModel.__paletteScope = paletteScope;\n                seiresModelMap.set(seriesModel.uid, seriesModel);\n            });\n\n            return seiresModelMap;\n        },\n        reset: function (seriesModel, ecModel) {\n            var dataAll = seriesModel.getRawData();\n            var idxMap = {};\n            var data = seriesModel.getData();\n\n            data.each(function (idx) {\n                var rawIdx = data.getRawIndex(idx);\n                idxMap[rawIdx] = idx;\n            });\n\n            dataAll.each(function (rawIdx) {\n                var filteredIdx = idxMap[rawIdx];\n\n                // If series.itemStyle.normal.color is a function. itemVisual may be encoded\n                var singleDataColor = filteredIdx != null\n                    && data.getItemVisual(filteredIdx, 'color', true);\n\n                if (!singleDataColor) {\n                    // FIXME Performance\n                    var itemModel = dataAll.getItemModel(rawIdx);\n\n                    var color = itemModel.get('itemStyle.color')\n                        || seriesModel.getColorFromPalette(\n                            dataAll.getName(rawIdx) || (rawIdx + ''), seriesModel.__paletteScope,\n                            dataAll.count()\n                        );\n                    // Legend may use the visual info in data before processed\n                    dataAll.setItemVisual(rawIdx, 'color', color);\n\n                    // Data is not filtered\n                    if (filteredIdx != null) {\n                        data.setItemVisual(filteredIdx, 'color', color);\n                    }\n                }\n                else {\n                    // Set data all color for legend\n                    dataAll.setItemVisual(rawIdx, 'color', singleDataColor);\n                }\n            });\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// FIXME emphasis label position is not same with normal label position\n\nfunction adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight) {\n    list.sort(function (a, b) {\n        return a.y - b.y;\n    });\n\n    function shiftDown(start, end, delta, dir) {\n        for (var j = start; j < end; j++) {\n            list[j].y += delta;\n            if (j > start\n                && j + 1 < end\n                && list[j + 1].y > list[j].y + list[j].height\n            ) {\n                shiftUp(j, delta / 2);\n                return;\n            }\n        }\n\n        shiftUp(end - 1, delta / 2);\n    }\n\n    function shiftUp(end, delta) {\n        for (var j = end; j >= 0; j--) {\n            list[j].y -= delta;\n            if (j > 0\n                && list[j].y > list[j - 1].y + list[j - 1].height\n            ) {\n                break;\n            }\n        }\n    }\n\n    function changeX(list, isDownList, cx, cy, r, dir) {\n        var lastDeltaX = dir > 0\n            ? isDownList                // right-side\n                ? Number.MAX_VALUE      // down\n                : 0                     // up\n            : isDownList                // left-side\n                ? Number.MAX_VALUE      // down\n                : 0;                    // up\n\n        for (var i = 0, l = list.length; i < l; i++) {\n            var deltaY = Math.abs(list[i].y - cy);\n            var length = list[i].len;\n            var length2 = list[i].len2;\n            var deltaX = (deltaY < r + length)\n                ? Math.sqrt(\n                        (r + length + length2) * (r + length + length2)\n                        - deltaY * deltaY\n                    )\n                : Math.abs(list[i].x - cx);\n            if (isDownList && deltaX >= lastDeltaX) {\n                // right-down, left-down\n                deltaX = lastDeltaX - 10;\n            }\n            if (!isDownList && deltaX <= lastDeltaX) {\n                // right-up, left-up\n                deltaX = lastDeltaX + 10;\n            }\n\n            list[i].x = cx + deltaX * dir;\n            lastDeltaX = deltaX;\n        }\n    }\n\n    var lastY = 0;\n    var delta;\n    var len = list.length;\n    var upList = [];\n    var downList = [];\n    for (var i = 0; i < len; i++) {\n        delta = list[i].y - lastY;\n        if (delta < 0) {\n            shiftDown(i, len, -delta, dir);\n        }\n        lastY = list[i].y + list[i].height;\n    }\n    if (viewHeight - lastY < 0) {\n        shiftUp(len - 1, lastY - viewHeight);\n    }\n    for (var i = 0; i < len; i++) {\n        if (list[i].y >= cy) {\n            downList.push(list[i]);\n        }\n        else {\n            upList.push(list[i]);\n        }\n    }\n    changeX(upList, false, cx, cy, r, dir);\n    changeX(downList, true, cx, cy, r, dir);\n}\n\nfunction avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight) {\n    var leftList = [];\n    var rightList = [];\n    for (var i = 0; i < labelLayoutList.length; i++) {\n        if (isPositionCenter(labelLayoutList[i])) {\n            continue;\n        }\n        if (labelLayoutList[i].x < cx) {\n            leftList.push(labelLayoutList[i]);\n        }\n        else {\n            rightList.push(labelLayoutList[i]);\n        }\n    }\n\n    adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight);\n    adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight);\n\n    for (var i = 0; i < labelLayoutList.length; i++) {\n        if (isPositionCenter(labelLayoutList[i])) {\n            continue;\n        }\n        var linePoints = labelLayoutList[i].linePoints;\n        if (linePoints) {\n            var dist = linePoints[1][0] - linePoints[2][0];\n            if (labelLayoutList[i].x < cx) {\n                linePoints[2][0] = labelLayoutList[i].x + 3;\n            }\n            else {\n                linePoints[2][0] = labelLayoutList[i].x - 3;\n            }\n            linePoints[1][1] = linePoints[2][1] = labelLayoutList[i].y;\n            linePoints[1][0] = linePoints[2][0] + dist;\n        }\n    }\n}\n\nfunction isPositionCenter(layout) {\n    // Not change x for center label\n    return layout.position === 'center';\n}\n\nvar labelLayout = function (seriesModel, r, viewWidth, viewHeight) {\n    var data = seriesModel.getData();\n    var labelLayoutList = [];\n    var cx;\n    var cy;\n    var hasLabelRotate = false;\n\n    data.each(function (idx) {\n        var layout = data.getItemLayout(idx);\n\n        var itemModel = data.getItemModel(idx);\n        var labelModel = itemModel.getModel('label');\n        // Use position in normal or emphasis\n        var labelPosition = labelModel.get('position') || itemModel.get('emphasis.label.position');\n\n        var labelLineModel = itemModel.getModel('labelLine');\n        var labelLineLen = labelLineModel.get('length');\n        var labelLineLen2 = labelLineModel.get('length2');\n\n        var midAngle = (layout.startAngle + layout.endAngle) / 2;\n        var dx = Math.cos(midAngle);\n        var dy = Math.sin(midAngle);\n\n        var textX;\n        var textY;\n        var linePoints;\n        var textAlign;\n\n        cx = layout.cx;\n        cy = layout.cy;\n\n        var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';\n        if (labelPosition === 'center') {\n            textX = layout.cx;\n            textY = layout.cy;\n            textAlign = 'center';\n        }\n        else {\n            var x1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dx : layout.r * dx) + cx;\n            var y1 = (isLabelInside ? (layout.r + layout.r0) / 2 * dy : layout.r * dy) + cy;\n\n            textX = x1 + dx * 3;\n            textY = y1 + dy * 3;\n\n            if (!isLabelInside) {\n                // For roseType\n                var x2 = x1 + dx * (labelLineLen + r - layout.r);\n                var y2 = y1 + dy * (labelLineLen + r - layout.r);\n                var x3 = x2 + ((dx < 0 ? -1 : 1) * labelLineLen2);\n                var y3 = y2;\n\n                textX = x3 + (dx < 0 ? -5 : 5);\n                textY = y3;\n                linePoints = [[x1, y1], [x2, y2], [x3, y3]];\n            }\n\n            textAlign = isLabelInside ? 'center' : (dx > 0 ? 'left' : 'right');\n        }\n        var font = labelModel.getFont();\n\n        var labelRotate = labelModel.get('rotate')\n            ? (dx < 0 ? -midAngle + Math.PI : -midAngle) : 0;\n        var text = seriesModel.getFormattedLabel(idx, 'normal')\n                    || data.getName(idx);\n        var textRect = getBoundingRect(\n            text, font, textAlign, 'top'\n        );\n        hasLabelRotate = !!labelRotate;\n        layout.label = {\n            x: textX,\n            y: textY,\n            position: labelPosition,\n            height: textRect.height,\n            len: labelLineLen,\n            len2: labelLineLen2,\n            linePoints: linePoints,\n            textAlign: textAlign,\n            verticalAlign: 'middle',\n            rotation: labelRotate,\n            inside: isLabelInside\n        };\n\n        // Not layout the inside label\n        if (!isLabelInside) {\n            labelLayoutList.push(layout.label);\n        }\n    });\n    if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {\n        avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight);\n    }\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n\nvar PI2$4 = Math.PI * 2;\nvar RADIAN = Math.PI / 180;\n\nvar pieLayout = function (seriesType, ecModel, api, payload) {\n    ecModel.eachSeriesByType(seriesType, function (seriesModel) {\n        var data = seriesModel.getData();\n        var valueDim = data.mapDimension('value');\n\n        var center = seriesModel.get('center');\n        var radius = seriesModel.get('radius');\n\n        if (!isArray(radius)) {\n            radius = [0, radius];\n        }\n        if (!isArray(center)) {\n            center = [center, center];\n        }\n\n        var width = api.getWidth();\n        var height = api.getHeight();\n        var size = Math.min(width, height);\n        var cx = parsePercent$1(center[0], width);\n        var cy = parsePercent$1(center[1], height);\n        var r0 = parsePercent$1(radius[0], size / 2);\n        var r = parsePercent$1(radius[1], size / 2);\n\n        var startAngle = -seriesModel.get('startAngle') * RADIAN;\n\n        var minAngle = seriesModel.get('minAngle') * RADIAN;\n\n        var validDataCount = 0;\n        data.each(valueDim, function (value) {\n            !isNaN(value) && validDataCount++;\n        });\n\n        var sum = data.getSum(valueDim);\n        // Sum may be 0\n        var unitRadian = Math.PI / (sum || validDataCount) * 2;\n\n        var clockwise = seriesModel.get('clockwise');\n\n        var roseType = seriesModel.get('roseType');\n        var stillShowZeroSum = seriesModel.get('stillShowZeroSum');\n\n        // [0...max]\n        var extent = data.getDataExtent(valueDim);\n        extent[0] = 0;\n\n        // In the case some sector angle is smaller than minAngle\n        var restAngle = PI2$4;\n        var valueSumLargerThanMinAngle = 0;\n\n        var currentAngle = startAngle;\n        var dir = clockwise ? 1 : -1;\n\n        data.each(valueDim, function (value, idx) {\n            var angle;\n            if (isNaN(value)) {\n                data.setItemLayout(idx, {\n                    angle: NaN,\n                    startAngle: NaN,\n                    endAngle: NaN,\n                    clockwise: clockwise,\n                    cx: cx,\n                    cy: cy,\n                    r0: r0,\n                    r: roseType\n                        ? NaN\n                        : r\n                });\n                return;\n            }\n\n            // FIXME 兼容 2.0 但是 roseType 是 area 的时候才是这样？\n            if (roseType !== 'area') {\n                angle = (sum === 0 && stillShowZeroSum)\n                    ? unitRadian : (value * unitRadian);\n            }\n            else {\n                angle = PI2$4 / validDataCount;\n            }\n\n            if (angle < minAngle) {\n                angle = minAngle;\n                restAngle -= minAngle;\n            }\n            else {\n                valueSumLargerThanMinAngle += value;\n            }\n\n            var endAngle = currentAngle + dir * angle;\n            data.setItemLayout(idx, {\n                angle: angle,\n                startAngle: currentAngle,\n                endAngle: endAngle,\n                clockwise: clockwise,\n                cx: cx,\n                cy: cy,\n                r0: r0,\n                r: roseType\n                    ? linearMap(value, extent, [r0, r])\n                    : r\n            });\n\n            currentAngle = endAngle;\n        });\n\n        // Some sector is constrained by minAngle\n        // Rest sectors needs recalculate angle\n        if (restAngle < PI2$4 && validDataCount) {\n            // Average the angle if rest angle is not enough after all angles is\n            // Constrained by minAngle\n            if (restAngle <= 1e-3) {\n                var angle = PI2$4 / validDataCount;\n                data.each(valueDim, function (value, idx) {\n                    if (!isNaN(value)) {\n                        var layout = data.getItemLayout(idx);\n                        layout.angle = angle;\n                        layout.startAngle = startAngle + dir * idx * angle;\n                        layout.endAngle = startAngle + dir * (idx + 1) * angle;\n                    }\n                });\n            }\n            else {\n                unitRadian = restAngle / valueSumLargerThanMinAngle;\n                currentAngle = startAngle;\n                data.each(valueDim, function (value, idx) {\n                    if (!isNaN(value)) {\n                        var layout = data.getItemLayout(idx);\n                        var angle = layout.angle === minAngle\n                            ? minAngle : value * unitRadian;\n                        layout.startAngle = currentAngle;\n                        layout.endAngle = currentAngle + dir * angle;\n                        currentAngle += dir * angle;\n                    }\n                });\n            }\n        }\n\n        labelLayout(seriesModel, r, width, height);\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar dataFilter = function (seriesType) {\n    return {\n        seriesType: seriesType,\n        reset: function (seriesModel, ecModel) {\n            var legendModels = ecModel.findComponents({\n                mainType: 'legend'\n            });\n            if (!legendModels || !legendModels.length) {\n                return;\n            }\n            var data = seriesModel.getData();\n            data.filterSelf(function (idx) {\n                var name = data.getName(idx);\n                // If in any legend component the status is not selected.\n                for (var i = 0; i < legendModels.length; i++) {\n                    if (!legendModels[i].isSelected(name)) {\n                        return false;\n                    }\n                }\n                return true;\n            });\n        }\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\ncreateDataSelectAction('pie', [{\n    type: 'pieToggleSelect',\n    event: 'pieselectchanged',\n    method: 'toggleSelected'\n}, {\n    type: 'pieSelect',\n    event: 'pieselected',\n    method: 'select'\n}, {\n    type: 'pieUnSelect',\n    event: 'pieunselected',\n    method: 'unSelect'\n}]);\n\nregisterVisual(dataColor('pie'));\nregisterLayout(curry(pieLayout, 'pie'));\nregisterProcessor(dataFilter('pie'));\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nexports.version = version;\nexports.dependencies = dependencies;\nexports.PRIORITY = PRIORITY;\nexports.init = init;\nexports.connect = connect;\nexports.disConnect = disConnect;\nexports.disconnect = disconnect;\nexports.dispose = dispose;\nexports.getInstanceByDom = getInstanceByDom;\nexports.getInstanceById = getInstanceById;\nexports.registerTheme = registerTheme;\nexports.registerPreprocessor = registerPreprocessor;\nexports.registerProcessor = registerProcessor;\nexports.registerPostUpdate = registerPostUpdate;\nexports.registerAction = registerAction;\nexports.registerCoordinateSystem = registerCoordinateSystem;\nexports.getCoordinateSystemDimensions = getCoordinateSystemDimensions;\nexports.registerLayout = registerLayout;\nexports.registerVisual = registerVisual;\nexports.registerLoading = registerLoading;\nexports.extendComponentModel = extendComponentModel;\nexports.extendComponentView = extendComponentView;\nexports.extendSeriesModel = extendSeriesModel;\nexports.extendChartView = extendChartView;\nexports.setCanvasCreator = setCanvasCreator;\nexports.registerMap = registerMap;\nexports.getMap = getMap;\nexports.dataTool = dataTool;\n\n})));\n"
  },
  {
    "path": "static/js/Echarts/extension/bmap.js",
    "content": "(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('echarts')) :\n\ttypeof define === 'function' && define.amd ? define(['exports', 'echarts'], factory) :\n\t(factory((global.bmap = {}),global.echarts));\n}(this, (function (exports,echarts) { 'use strict';\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/* global BMap */\n\nfunction BMapCoordSys(bmap, api) {\n    this._bmap = bmap;\n    this.dimensions = ['lng', 'lat'];\n    this._mapOffset = [0, 0];\n\n    this._api = api;\n\n    this._projection = new BMap.MercatorProjection();\n}\n\nBMapCoordSys.prototype.dimensions = ['lng', 'lat'];\n\nBMapCoordSys.prototype.setZoom = function (zoom) {\n    this._zoom = zoom;\n};\n\nBMapCoordSys.prototype.setCenter = function (center) {\n    this._center = this._projection.lngLatToPoint(new BMap.Point(center[0], center[1]));\n};\n\nBMapCoordSys.prototype.setMapOffset = function (mapOffset) {\n    this._mapOffset = mapOffset;\n};\n\nBMapCoordSys.prototype.getBMap = function () {\n    return this._bmap;\n};\n\nBMapCoordSys.prototype.dataToPoint = function (data) {\n    var point = new BMap.Point(data[0], data[1]);\n    // TODO mercator projection is toooooooo slow\n    // var mercatorPoint = this._projection.lngLatToPoint(point);\n\n    // var width = this._api.getZr().getWidth();\n    // var height = this._api.getZr().getHeight();\n    // var divider = Math.pow(2, 18 - 10);\n    // return [\n    //     Math.round((mercatorPoint.x - this._center.x) / divider + width / 2),\n    //     Math.round((this._center.y - mercatorPoint.y) / divider + height / 2)\n    // ];\n    var px = this._bmap.pointToOverlayPixel(point);\n    var mapOffset = this._mapOffset;\n    return [px.x - mapOffset[0], px.y - mapOffset[1]];\n};\n\nBMapCoordSys.prototype.pointToData = function (pt) {\n    var mapOffset = this._mapOffset;\n    var pt = this._bmap.overlayPixelToPoint({\n        x: pt[0] + mapOffset[0],\n        y: pt[1] + mapOffset[1]\n    });\n    return [pt.lng, pt.lat];\n};\n\nBMapCoordSys.prototype.getViewRect = function () {\n    var api = this._api;\n    return new echarts.graphic.BoundingRect(0, 0, api.getWidth(), api.getHeight());\n};\n\nBMapCoordSys.prototype.getRoamTransform = function () {\n    return echarts.matrix.create();\n};\n\nBMapCoordSys.prototype.prepareCustoms = function (data) {\n    var rect = this.getViewRect();\n    return {\n        coordSys: {\n            // The name exposed to user is always 'cartesian2d' but not 'grid'.\n            type: 'bmap',\n            x: rect.x,\n            y: rect.y,\n            width: rect.width,\n            height: rect.height\n        },\n        api: {\n            coord: echarts.util.bind(this.dataToPoint, this),\n            size: echarts.util.bind(dataToCoordSize, this)\n        }\n    };\n};\n\nfunction dataToCoordSize(dataSize, dataItem) {\n    dataItem = dataItem || [0, 0];\n    return echarts.util.map([0, 1], function (dimIdx) {\n        var val = dataItem[dimIdx];\n        var halfSize = dataSize[dimIdx] / 2;\n        var p1 = [];\n        var p2 = [];\n        p1[dimIdx] = val - halfSize;\n        p2[dimIdx] = val + halfSize;\n        p1[1 - dimIdx] = p2[1 - dimIdx] = dataItem[1 - dimIdx];\n        return Math.abs(this.dataToPoint(p1)[dimIdx] - this.dataToPoint(p2)[dimIdx]);\n    }, this);\n}\n\nvar Overlay;\n\n// For deciding which dimensions to use when creating list data\nBMapCoordSys.dimensions = BMapCoordSys.prototype.dimensions;\n\nfunction createOverlayCtor() {\n    function Overlay(root) {\n        this._root = root;\n    }\n\n    Overlay.prototype = new BMap.Overlay();\n    /**\n     * 初始化\n     *\n     * @param {BMap.Map} map\n     * @override\n     */\n    Overlay.prototype.initialize = function (map) {\n        map.getPanes().labelPane.appendChild(this._root);\n        return this._root;\n    };\n    /**\n     * @override\n     */\n    Overlay.prototype.draw = function () {};\n\n    return Overlay;\n}\n\nBMapCoordSys.create = function (ecModel, api) {\n    var bmapCoordSys;\n    var root = api.getDom();\n\n    // TODO Dispose\n    ecModel.eachComponent('bmap', function (bmapModel) {\n        var painter = api.getZr().painter;\n        var viewportRoot = painter.getViewportRoot();\n        if (typeof BMap === 'undefined') {\n            throw new Error('BMap api is not loaded');\n        }\n        Overlay = Overlay || createOverlayCtor();\n        if (bmapCoordSys) {\n            throw new Error('Only one bmap component can exist');\n        }\n        if (!bmapModel.__bmap) {\n            // Not support IE8\n            var bmapRoot = root.querySelector('.ec-extension-bmap');\n            if (bmapRoot) {\n                // Reset viewport left and top, which will be changed\n                // in moving handler in BMapView\n                viewportRoot.style.left = '0px';\n                viewportRoot.style.top = '0px';\n                root.removeChild(bmapRoot);\n            }\n            bmapRoot = document.createElement('div');\n            bmapRoot.style.cssText = 'width:100%;height:100%';\n            // Not support IE8\n            bmapRoot.classList.add('ec-extension-bmap');\n            root.appendChild(bmapRoot);\n            var bmap = bmapModel.__bmap = new BMap.Map(bmapRoot);\n\n            var overlay = new Overlay(viewportRoot);\n            bmap.addOverlay(overlay);\n\n            // Override\n            painter.getViewportRootOffset = function () {\n                return {offsetLeft: 0, offsetTop: 0};\n            };\n        }\n        var bmap = bmapModel.__bmap;\n\n        // Set bmap options\n        // centerAndZoom before layout and render\n        var center = bmapModel.get('center');\n        var zoom = bmapModel.get('zoom');\n        if (center && zoom) {\n            var pt = new BMap.Point(center[0], center[1]);\n            bmap.centerAndZoom(pt, zoom);\n        }\n\n        bmapCoordSys = new BMapCoordSys(bmap, api);\n        bmapCoordSys.setMapOffset(bmapModel.__mapOffset || [0, 0]);\n        bmapCoordSys.setZoom(zoom);\n        bmapCoordSys.setCenter(center);\n\n        bmapModel.coordinateSystem = bmapCoordSys;\n    });\n\n    ecModel.eachSeries(function (seriesModel) {\n        if (seriesModel.get('coordinateSystem') === 'bmap') {\n            seriesModel.coordinateSystem = bmapCoordSys;\n        }\n    });\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nfunction v2Equal(a, b) {\n    return a && b && a[0] === b[0] && a[1] === b[1];\n}\n\necharts.extendComponentModel({\n    type: 'bmap',\n\n    getBMap: function () {\n        // __bmap is injected when creating BMapCoordSys\n        return this.__bmap;\n    },\n\n    setCenterAndZoom: function (center, zoom) {\n        this.option.center = center;\n        this.option.zoom = zoom;\n    },\n\n    centerOrZoomChanged: function (center, zoom) {\n        var option = this.option;\n        return !(v2Equal(center, option.center) && zoom === option.zoom);\n    },\n\n    defaultOption: {\n\n        center: [104.114129, 37.550339],\n\n        zoom: 5,\n\n        mapStyle: {},\n\n        roam: false\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\necharts.extendComponentView({\n    type: 'bmap',\n\n    render: function (bMapModel, ecModel, api) {\n        var rendering = true;\n\n        var bmap = bMapModel.getBMap();\n        var viewportRoot = api.getZr().painter.getViewportRoot();\n        var coordSys = bMapModel.coordinateSystem;\n        var moveHandler = function (type, target) {\n            if (rendering) {\n                return;\n            }\n            var offsetEl = viewportRoot.parentNode.parentNode.parentNode;\n            var mapOffset = [\n                -parseInt(offsetEl.style.left, 10) || 0,\n                -parseInt(offsetEl.style.top, 10) || 0\n            ];\n            viewportRoot.style.left = mapOffset[0] + 'px';\n            viewportRoot.style.top = mapOffset[1] + 'px';\n\n            coordSys.setMapOffset(mapOffset);\n            bMapModel.__mapOffset = mapOffset;\n\n            api.dispatchAction({\n                type: 'bmapRoam'\n            });\n        };\n\n        function zoomEndHandler() {\n            if (rendering) {\n                return;\n            }\n            api.dispatchAction({\n                type: 'bmapRoam'\n            });\n        }\n\n        bmap.removeEventListener('moving', this._oldMoveHandler);\n        // FIXME\n        // Moveend may be triggered by centerAndZoom method when creating coordSys next time\n        // bmap.removeEventListener('moveend', this._oldMoveHandler);\n        bmap.removeEventListener('zoomend', this._oldZoomEndHandler);\n        bmap.addEventListener('moving', moveHandler);\n        // bmap.addEventListener('moveend', moveHandler);\n        bmap.addEventListener('zoomend', zoomEndHandler);\n\n        this._oldMoveHandler = moveHandler;\n        this._oldZoomEndHandler = zoomEndHandler;\n\n        var roam = bMapModel.get('roam');\n        if (roam && roam !== 'scale') {\n            bmap.enableDragging();\n        }\n        else {\n            bmap.disableDragging();\n        }\n        if (roam && roam !== 'move') {\n            bmap.enableScrollWheelZoom();\n            bmap.enableDoubleClickZoom();\n            bmap.enablePinchToZoom();\n        }\n        else {\n            bmap.disableScrollWheelZoom();\n            bmap.disableDoubleClickZoom();\n            bmap.disablePinchToZoom();\n        }\n\n        var originalStyle = bMapModel.__mapStyle;\n\n        var newMapStyle = bMapModel.get('mapStyle') || {};\n        // FIXME, Not use JSON methods\n        var mapStyleStr = JSON.stringify(newMapStyle);\n        if (JSON.stringify(originalStyle) !== mapStyleStr) {\n            // FIXME May have blank tile when dragging if setMapStyle\n            if (Object.keys(newMapStyle).length) {\n                bmap.setMapStyle(newMapStyle);\n            }\n            bMapModel.__mapStyle = JSON.parse(mapStyleStr);\n        }\n\n        rendering = false;\n    }\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * BMap component extension\n */\n\necharts.registerCoordinateSystem('bmap', BMapCoordSys);\n\n// Action\necharts.registerAction({\n    type: 'bmapRoam',\n    event: 'bmapRoam',\n    update: 'updateLayout'\n}, function (payload, ecModel) {\n    ecModel.eachComponent('bmap', function (bMapModel) {\n        var bmap = bMapModel.getBMap();\n        var center = bmap.getCenter();\n        bMapModel.setCenterAndZoom([center.lng, center.lat], bmap.getZoom());\n    });\n});\n\nvar version = '1.0.0';\n\nexports.version = version;\n\n})));\n//# sourceMappingURL=bmap.js.map\n"
  },
  {
    "path": "static/js/Echarts/extension/dataTool.js",
    "content": "\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('echarts')) :\n\ttypeof define === 'function' && define.amd ? define(['exports', 'echarts'], factory) :\n\t(factory((global.dataTool = {}),global.echarts));\n}(this, (function (exports,echarts) { 'use strict';\n\n/**\n * @module zrender/core/util\n */\n\n// 用于处理merge时无法遍历Date等对象的问题\nvar arrayProto = Array.prototype;\nvar nativeMap = arrayProto.map;\n\n\n/**\n * Those data types can be cloned:\n *     Plain object, Array, TypedArray, number, string, null, undefined.\n * Those data types will be assgined using the orginal data:\n *     BUILTIN_OBJECT\n * Instance of user defined class will be cloned to a plain object, without\n * properties in prototype.\n * Other data types is not supported (not sure what will happen).\n *\n * Caution: do not support clone Date, for performance consideration.\n * (There might be a large number of date in `series.data`).\n * So date should not be modified in and out of echarts.\n *\n * @param {*} source\n * @return {*} new\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overwrite=false]\n */\n\n\n/**\n * @param {Array} targetAndSources The first item is target, and the rests are source.\n * @param {boolean} [overwrite=false]\n * @return {*} target\n */\n\n\n/**\n * @param {*} target\n * @param {*} source\n * @memberOf module:zrender/core/util\n */\n\n\n/**\n * @param {*} target\n * @param {*} source\n * @param {boolean} [overlay=false]\n * @memberOf module:zrender/core/util\n */\n\n\n\n\n\n\n/**\n * 查询数组中元素的index\n * @memberOf module:zrender/core/util\n */\n\n\n/**\n * 构造类继承关系\n *\n * @memberOf module:zrender/core/util\n * @param {Function} clazz 源类\n * @param {Function} baseClazz 基类\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Object|Function} target\n * @param {Object|Function} sorce\n * @param {boolean} overlay\n */\n\n\n/**\n * Consider typed array.\n * @param {Array|TypedArray} data\n */\n\n\n/**\n * 数组或对象遍历\n * @memberOf module:zrender/core/util\n * @param {Object|Array} obj\n * @param {Function} cb\n * @param {*} [context]\n */\n\n\n/**\n * 数组映射\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\nfunction map(obj, cb, context) {\n    if (!(obj && cb)) {\n        return;\n    }\n    if (obj.map && obj.map === nativeMap) {\n        return obj.map(cb, context);\n    }\n    else {\n        var result = [];\n        for (var i = 0, len = obj.length; i < len; i++) {\n            result.push(cb.call(context, obj[i], i, obj));\n        }\n        return result;\n    }\n}\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {Object} [memo]\n * @param {*} [context]\n * @return {Array}\n */\n\n\n/**\n * 数组过滤\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {Array}\n */\n\n\n/**\n * 数组项查找\n * @memberOf module:zrender/core/util\n * @param {Array} obj\n * @param {Function} cb\n * @param {*} [context]\n * @return {*}\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @param {*} context\n * @return {Function}\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Function} func\n * @return {Function}\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {*} value\n * @return {boolean}\n */\n\n\n/**\n * Whether is exactly NaN. Notice isNaN('a') returns true.\n * @param {*} value\n * @return {boolean}\n */\n\n\n/**\n * If value1 is not null, then return value1, otherwise judget rest of values.\n * Low performance.\n * @memberOf module:zrender/core/util\n * @return {*} Final value\n */\n\n\n\n\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {Array} arr\n * @param {number} startIndex\n * @param {number} endIndex\n * @return {Array}\n */\n\n\n/**\n * Normalize css liked array configuration\n * e.g.\n *  3 => [3, 3, 3, 3]\n *  [4, 2] => [4, 2, 4, 2]\n *  [4, 3, 2] => [4, 3, 2, 3]\n * @param {number|Array.<number>} val\n * @return {Array.<number>}\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {boolean} condition\n * @param {string} message\n */\n\n\n/**\n * @memberOf module:zrender/core/util\n * @param {string} str string to be trimed\n * @return {string} trimed string\n */\n\n\n/**\n * Set an object as primitive to be ignored traversing children in clone or merge\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n// GEXF File Parser\n// http://gexf.net/1.2draft/gexf-12draft-primer.pdf\n\nfunction parse(xml) {\n    var doc;\n    if (typeof xml === 'string') {\n        var parser = new DOMParser();\n        doc = parser.parseFromString(xml, 'text/xml');\n    }\n    else {\n        doc = xml;\n    }\n    if (!doc || doc.getElementsByTagName('parsererror').length) {\n        return null;\n    }\n\n    var gexfRoot = getChildByTagName(doc, 'gexf');\n\n    if (!gexfRoot) {\n        return null;\n    }\n\n    var graphRoot = getChildByTagName(gexfRoot, 'graph');\n\n    var attributes = parseAttributes(getChildByTagName(graphRoot, 'attributes'));\n    var attributesMap = {};\n    for (var i = 0; i < attributes.length; i++) {\n        attributesMap[attributes[i].id] = attributes[i];\n    }\n\n    return {\n        nodes: parseNodes(getChildByTagName(graphRoot, 'nodes'), attributesMap),\n        links: parseEdges(getChildByTagName(graphRoot, 'edges'))\n    };\n}\n\nfunction parseAttributes(parent) {\n    return parent ? map(getChildrenByTagName(parent, 'attribute'), function (attribDom) {\n        return {\n            id: getAttr(attribDom, 'id'),\n            title: getAttr(attribDom, 'title'),\n            type: getAttr(attribDom, 'type')\n        };\n    }) : [];\n}\n\nfunction parseNodes(parent, attributesMap) {\n    return parent ? map(getChildrenByTagName(parent, 'node'), function (nodeDom) {\n\n        var id = getAttr(nodeDom, 'id');\n        var label = getAttr(nodeDom, 'label');\n\n        var node = {\n            id: id,\n            name: label,\n            itemStyle: {\n                normal: {}\n            }\n        };\n\n        var vizSizeDom = getChildByTagName(nodeDom, 'viz:size');\n        var vizPosDom = getChildByTagName(nodeDom, 'viz:position');\n        var vizColorDom = getChildByTagName(nodeDom, 'viz:color');\n        // var vizShapeDom = getChildByTagName(nodeDom, 'viz:shape');\n\n        var attvaluesDom = getChildByTagName(nodeDom, 'attvalues');\n\n        if (vizSizeDom) {\n            node.symbolSize = parseFloat(getAttr(vizSizeDom, 'value'));\n        }\n        if (vizPosDom) {\n            node.x = parseFloat(getAttr(vizPosDom, 'x'));\n            node.y = parseFloat(getAttr(vizPosDom, 'y'));\n            // z\n        }\n        if (vizColorDom) {\n            node.itemStyle.normal.color = 'rgb(' +[\n                getAttr(vizColorDom, 'r') | 0,\n                getAttr(vizColorDom, 'g') | 0,\n                getAttr(vizColorDom, 'b') | 0\n            ].join(',') + ')';\n        }\n        // if (vizShapeDom) {\n            // node.shape = getAttr(vizShapeDom, 'shape');\n        // }\n        if (attvaluesDom) {\n            var attvalueDomList = getChildrenByTagName(attvaluesDom, 'attvalue');\n\n            node.attributes = {};\n\n            for (var j = 0; j < attvalueDomList.length; j++) {\n                var attvalueDom = attvalueDomList[j];\n                var attId = getAttr(attvalueDom, 'for');\n                var attValue = getAttr(attvalueDom, 'value');\n                var attribute = attributesMap[attId];\n\n                if (attribute) {\n                    switch (attribute.type) {\n                        case 'integer':\n                        case 'long':\n                            attValue = parseInt(attValue, 10);\n                            break;\n                        case 'float':\n                        case 'double':\n                            attValue = parseFloat(attValue);\n                            break;\n                        case 'boolean':\n                            attValue = attValue.toLowerCase() == 'true';\n                            break;\n                        default:\n                    }\n                    node.attributes[attId] = attValue;\n                }\n            }\n        }\n\n        return node;\n    }) : [];\n}\n\nfunction parseEdges(parent) {\n    return parent ? map(getChildrenByTagName(parent, 'edge'), function (edgeDom) {\n        var id = getAttr(edgeDom, 'id');\n        var label = getAttr(edgeDom, 'label');\n\n        var sourceId = getAttr(edgeDom, 'source');\n        var targetId = getAttr(edgeDom, 'target');\n\n        var edge = {\n            id: id,\n            name: label,\n            source: sourceId,\n            target: targetId,\n            lineStyle: {\n                normal: {}\n            }\n        };\n\n        var lineStyle = edge.lineStyle.normal;\n\n        var vizThicknessDom = getChildByTagName(edgeDom, 'viz:thickness');\n        var vizColorDom = getChildByTagName(edgeDom, 'viz:color');\n        // var vizShapeDom = getChildByTagName(edgeDom, 'viz:shape');\n\n        if (vizThicknessDom) {\n            lineStyle.width = parseFloat(vizThicknessDom.getAttribute('value'));\n        }\n        if (vizColorDom) {\n            lineStyle.color = 'rgb(' + [\n                getAttr(vizColorDom, 'r') | 0,\n                getAttr(vizColorDom, 'g') | 0,\n                getAttr(vizColorDom, 'b') | 0\n            ].join(',') + ')';\n        }\n        // if (vizShapeDom) {\n        //     edge.shape = vizShapeDom.getAttribute('shape');\n        // }\n\n        return edge;\n    }) : [];\n}\n\nfunction getAttr(el, attrName) {\n    return el.getAttribute(attrName);\n}\n\nfunction getChildByTagName (parent, tagName) {\n    var node = parent.firstChild;\n\n    while (node) {\n        if (\n            node.nodeType != 1 ||\n            node.nodeName.toLowerCase() != tagName.toLowerCase()\n        ) {\n            node = node.nextSibling;\n        } else {\n            return node;\n        }\n    }\n\n    return null;\n}\n\nfunction getChildrenByTagName (parent, tagName) {\n    var node = parent.firstChild;\n    var children = [];\n    while (node) {\n        if (node.nodeName.toLowerCase() == tagName.toLowerCase()) {\n            children.push(node);\n        }\n        node = node.nextSibling;\n    }\n\n    return children;\n}\n\n\nvar gexf = (Object.freeze || Object)({\n\tparse: parse\n});\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/*\n* A third-party license is embeded for some of the code in this file:\n* The method \"quantile\" was copied from \"d3.js\".\n* (See more details in the comment of the method below.)\n* The use of the source code of this file is also subject to the terms\n* and consitions of the license of \"d3.js\" (BSD-3Clause, see\n* </licenses/LICENSE-d3>).\n*/\n\n/**\n * Linear mapping a value from domain to range\n * @memberOf module:echarts/util/number\n * @param  {(number|Array.<number>)} val\n * @param  {Array.<number>} domain Domain extent domain[0] can be bigger than domain[1]\n * @param  {Array.<number>} range  Range extent range[0] can be bigger than range[1]\n * @param  {boolean} clamp\n * @return {(number|Array.<number>}\n */\n\n\n/**\n * Convert a percent string to absolute number.\n * Returns NaN if percent is not a valid string or number\n * @memberOf module:echarts/util/number\n * @param {string|number} percent\n * @param {number} all\n * @return {number}\n */\n\n\n/**\n * (1) Fix rounding error of float numbers.\n * (2) Support return string to avoid scientific notation like '3.5e-7'.\n *\n * @param {number} x\n * @param {number} [precision]\n * @param {boolean} [returnStr]\n * @return {number|string}\n */\n\n\nfunction asc(arr) {\n    arr.sort(function (a, b) {\n        return a - b;\n    });\n    return arr;\n}\n\n/**\n * Get precision\n * @param {number} val\n */\n\n\n/**\n * @param {string|number} val\n * @return {number}\n */\n\n\n/**\n * Minimal dicernible data precisioin according to a single pixel.\n *\n * @param {Array.<number>} dataExtent\n * @param {Array.<number>} pixelExtent\n * @return {number} precision\n */\n\n\n/**\n * Get a data of given precision, assuring the sum of percentages\n * in valueList is 1.\n * The largest remainer method is used.\n * https://en.wikipedia.org/wiki/Largest_remainder_method\n *\n * @param {Array.<number>} valueList a list of all data\n * @param {number} idx index of the data to be processed in valueList\n * @param {number} precision integer number showing digits of precision\n * @return {number} percent ranging from 0 to 100\n */\n\n\n// Number.MAX_SAFE_INTEGER, ie do not support.\n\n\n/**\n * To 0 - 2 * PI, considering negative radian.\n * @param {number} radian\n * @return {number}\n */\n\n\n/**\n * @param {type} radian\n * @return {boolean}\n */\n\n\n/* eslint-enable */\n\n/**\n * @param {string|Date|number} value These values can be accepted:\n *   + An instance of Date, represent a time in its own time zone.\n *   + Or string in a subset of ISO 8601, only including:\n *     + only year, month, date: '2012-03', '2012-03-01', '2012-03-01 05', '2012-03-01 05:06',\n *     + separated with T or space: '2012-03-01T12:22:33.123', '2012-03-01 12:22:33.123',\n *     + time zone: '2012-03-01T12:22:33Z', '2012-03-01T12:22:33+8000', '2012-03-01T12:22:33-05:00',\n *     all of which will be treated as local time if time zone is not specified\n *     (see <https://momentjs.com/>).\n *   + Or other string format, including (all of which will be treated as loacal time):\n *     '2012', '2012-3-1', '2012/3/1', '2012/03/01',\n *     '2009/6/12 2:00', '2009/6/12 2:05:08', '2009/6/12 2:05:08.123'\n *   + a timestamp, which represent a time in UTC.\n * @return {Date} date\n */\n\n\n/**\n * Quantity of a number. e.g. 0.1, 1, 10, 100\n *\n * @param  {number} val\n * @return {number}\n */\n\n\n/**\n * find a “nice” number approximately equal to x. Round the number if round = true,\n * take ceiling if round = false. The primary observation is that the “nicest”\n * numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers.\n *\n * See \"Nice Numbers for Graph Labels\" of Graphic Gems.\n *\n * @param  {number} val Non-negative value.\n * @param  {boolean} round\n * @return {number}\n */\n\n\n/**\n * This code was copied from \"d3.js\"\n * <https://github.com/d3/d3/blob/9cc9a875e636a1dcf36cc1e07bdf77e1ad6e2c74/src/arrays/quantile.js>.\n * See the license statement at the head of this file.\n * @param {Array.<number>} ascArr\n */\nfunction quantile(ascArr, p) {\n    var H = (ascArr.length - 1) * p + 1;\n    var h = Math.floor(H);\n    var v = +ascArr[h - 1];\n    var e = H - h;\n    return e ? v + e * (ascArr[h] - v) : v;\n}\n\n/**\n * Order intervals asc, and split them when overlap.\n * expect(numberUtil.reformIntervals([\n *     {interval: [18, 62], close: [1, 1]},\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [1, 1]},\n *     {interval: [62, 150], close: [1, 1]},\n *     {interval: [106, 150], close: [1, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ])).toEqual([\n *     {interval: [-Infinity, -70], close: [0, 0]},\n *     {interval: [-70, -26], close: [1, 1]},\n *     {interval: [-26, 18], close: [0, 1]},\n *     {interval: [18, 62], close: [0, 1]},\n *     {interval: [62, 150], close: [0, 1]},\n *     {interval: [150, Infinity], close: [0, 0]}\n * ]);\n * @param {Array.<Object>} list, where `close` mean open or close\n *        of the interval, and Infinity can be used.\n * @return {Array.<Object>} The origin list, which has been reformed.\n */\n\n\n/**\n * parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n * ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n * subtraction forces infinities to NaN\n *\n * @param {*} v\n * @return {boolean}\n */\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\n/**\n * See:\n *  <https://en.wikipedia.org/wiki/Box_plot#cite_note-frigge_hoaglin_iglewicz-2>\n *  <http://stat.ethz.ch/R-manual/R-devel/library/grDevices/html/boxplot.stats.html>\n *\n * Helper method for preparing data.\n *\n * @param {Array.<number>} rawData like\n *        [\n *            [12,232,443], (raw data set for the first box)\n *            [3843,5545,1232], (raw datat set for the second box)\n *            ...\n *        ]\n * @param {Object} [opt]\n *\n * @param {(number|string)} [opt.boundIQR=1.5] Data less than min bound is outlier.\n *      default 1.5, means Q1 - 1.5 * (Q3 - Q1).\n *      If 'none'/0 passed, min bound will not be used.\n * @param {(number|string)} [opt.layout='horizontal']\n *      Box plot layout, can be 'horizontal' or 'vertical'\n * @return {Object} {\n *      boxData: Array.<Array.<number>>\n *      outliers: Array.<Array.<number>>\n *      axisData: Array.<string>\n * }\n */\nvar prepareBoxplotData = function (rawData, opt) {\n    opt = opt || [];\n    var boxData = [];\n    var outliers = [];\n    var axisData = [];\n    var boundIQR = opt.boundIQR;\n    var useExtreme = boundIQR === 'none' || boundIQR === 0;\n\n    for (var i = 0; i < rawData.length; i++) {\n        axisData.push(i + '');\n        var ascList = asc(rawData[i].slice());\n\n        var Q1 = quantile(ascList, 0.25);\n        var Q2 = quantile(ascList, 0.5);\n        var Q3 = quantile(ascList, 0.75);\n        var min = ascList[0];\n        var max = ascList[ascList.length - 1];\n\n        var bound = (boundIQR == null ? 1.5 : boundIQR) * (Q3 - Q1);\n\n        var low = useExtreme\n            ? min\n            : Math.max(min, Q1 - bound);\n        var high = useExtreme\n            ? max\n            : Math.min(max, Q3 + bound);\n\n        boxData.push([low, Q1, Q2, Q3, high]);\n\n        for (var j = 0; j < ascList.length; j++) {\n            var dataItem = ascList[j];\n            if (dataItem < low || dataItem > high) {\n                var outlier = [i, dataItem];\n                opt.layout === 'vertical' && outlier.reverse();\n                outliers.push(outlier);\n            }\n        }\n    }\n    return {\n        boxData: boxData,\n        outliers: outliers,\n        axisData: axisData\n    };\n};\n\n/*\n* Licensed to the Apache Software Foundation (ASF) under one\n* or more contributor license agreements.  See the NOTICE file\n* distributed with this work for additional information\n* regarding copyright ownership.  The ASF licenses this file\n* to you under the Apache License, Version 2.0 (the\n* \"License\"); you may not use this file except in compliance\n* with the License.  You may obtain a copy of the License at\n*\n*   http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing,\n* software distributed under the License is distributed on an\n* \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n* KIND, either express or implied.  See the License for the\n* specific language governing permissions and limitations\n* under the License.\n*/\n\nvar version = '1.0.0';\n\n// For backward compatibility, where the namespace `dataTool` will\n// be mounted on `echarts` is the extension `dataTool` is imported.\n// But the old version of echarts do not have `dataTool` namespace,\n// so check it before mounting.\nif (echarts.dataTool) {\n    echarts.dataTool.version = version;\n    echarts.dataTool.gexf = gexf;\n    echarts.dataTool.prepareBoxplotData = prepareBoxplotData;\n}\n\nexports.version = version;\nexports.gexf = gexf;\nexports.prepareBoxplotData = prepareBoxplotData;\n\n})));\n//# sourceMappingURL=dataTool.js.map\n"
  },
  {
    "path": "static/js/FileSaver.js",
    "content": "/*! FileSaver.js\n *  A saveAs() FileSaver implementation.\n *  2014-01-24\n *\n *  By Eli Grey, http://eligrey.com\n *  License: X11/MIT\n *    See LICENSE.md\n */\n\n/*global self */\n/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */\n\n/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */\n\nvar saveAs = saveAs\n  // IE 10+ (native saveAs)\n  || (typeof navigator !== \"undefined\" &&\n      navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator))\n  // Everyone else\n  || (function(view) {\n\t\"use strict\";\n\t// IE <10 is explicitly unsupported\n\tif (typeof navigator !== \"undefined\" &&\n\t    /MSIE [1-9]\\./.test(navigator.userAgent)) {\n\t\treturn;\n\t}\n\tvar\n\t\t  doc = view.document\n\t\t  // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet\n\t\t, get_URL = function() {\n\t\t\treturn view.URL || view.webkitURL || view;\n\t\t}\n\t\t, URL = view.URL || view.webkitURL || view\n\t\t, save_link = doc.createElementNS(\"http://www.w3.org/1999/xhtml\", \"a\")\n\t\t, can_use_save_link = !view.externalHost && \"download\" in save_link\n\t\t, click = function(node) {\n\t\t\tvar event = doc.createEvent(\"MouseEvents\");\n\t\t\tevent.initMouseEvent(\n\t\t\t\t\"click\", true, false, view, 0, 0, 0, 0, 0\n\t\t\t\t, false, false, false, false, 0, null\n\t\t\t);\n\t\t\tnode.dispatchEvent(event);\n\t\t}\n\t\t, webkit_req_fs = view.webkitRequestFileSystem\n\t\t, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem\n\t\t, throw_outside = function(ex) {\n\t\t\t(view.setImmediate || view.setTimeout)(function() {\n\t\t\t\tthrow ex;\n\t\t\t}, 0);\n\t\t}\n\t\t, force_saveable_type = \"application/octet-stream\"\n\t\t, fs_min_size = 0\n\t\t, deletion_queue = []\n\t\t, process_deletion_queue = function() {\n\t\t\tvar i = deletion_queue.length;\n\t\t\twhile (i--) {\n\t\t\t\tvar file = deletion_queue[i];\n\t\t\t\tif (typeof file === \"string\") { // file is an object URL\n\t\t\t\t\tURL.revokeObjectURL(file);\n\t\t\t\t} else { // file is a File\n\t\t\t\t\tfile.remove();\n\t\t\t\t}\n\t\t\t}\n\t\t\tdeletion_queue.length = 0; // clear queue\n\t\t}\n\t\t, dispatch = function(filesaver, event_types, event) {\n\t\t\tevent_types = [].concat(event_types);\n\t\t\tvar i = event_types.length;\n\t\t\twhile (i--) {\n\t\t\t\tvar listener = filesaver[\"on\" + event_types[i]];\n\t\t\t\tif (typeof listener === \"function\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tlistener.call(filesaver, event || filesaver);\n\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\tthrow_outside(ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t, FileSaver = function(blob, name) {\n\t\t\t// First try a.download, then web filesystem, then object URLs\n\t\t\tvar\n\t\t\t\t  filesaver = this\n\t\t\t\t, type = blob.type\n\t\t\t\t, blob_changed = false\n\t\t\t\t, object_url\n\t\t\t\t, target_view\n\t\t\t\t, get_object_url = function() {\n\t\t\t\t\tvar object_url = get_URL().createObjectURL(blob);\n\t\t\t\t\tdeletion_queue.push(object_url);\n\t\t\t\t\treturn object_url;\n\t\t\t\t}\n\t\t\t\t, dispatch_all = function() {\n\t\t\t\t\tdispatch(filesaver, \"writestart progress write writeend\".split(\" \"));\n\t\t\t\t}\n\t\t\t\t// on any filesys errors revert to saving with object URLs\n\t\t\t\t, fs_error = function() {\n\t\t\t\t\t// don't create more object URLs than needed\n\t\t\t\t\tif (blob_changed || !object_url) {\n\t\t\t\t\t\tobject_url = get_object_url(blob);\n\t\t\t\t\t}\n\t\t\t\t\tif (target_view) {\n\t\t\t\t\t\ttarget_view.location.href = object_url;\n\t\t\t\t\t} else {\n\t\t\t\t\t\twindow.open(object_url, \"_blank\");\n\t\t\t\t\t}\n\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t\tdispatch_all();\n\t\t\t\t}\n\t\t\t\t, abortable = function(func) {\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\tif (filesaver.readyState !== filesaver.DONE) {\n\t\t\t\t\t\t\treturn func.apply(this, arguments);\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\t, create_if_not_found = {create: true, exclusive: false}\n\t\t\t\t, slice\n\t\t\t;\n\t\t\tfilesaver.readyState = filesaver.INIT;\n\t\t\tif (!name) {\n\t\t\t\tname = \"download\";\n\t\t\t}\n\t\t\tif (can_use_save_link) {\n\t\t\t\tobject_url = get_object_url(blob);\n\t\t\t\t// FF for Android has a nasty garbage collection mechanism\n\t\t\t\t// that turns all objects that are not pure javascript into 'deadObject'\n\t\t\t\t// this means `doc` and `save_link` are unusable and need to be recreated\n\t\t\t\t// `view` is usable though:\n\t\t\t\tdoc = view.document;\n\t\t\t\tsave_link = doc.createElementNS(\"http://www.w3.org/1999/xhtml\", \"a\");\n\t\t\t\tsave_link.href = object_url;\n\t\t\t\tsave_link.download = name;\n\t\t\t\tvar event = doc.createEvent(\"MouseEvents\");\n\t\t\t\tevent.initMouseEvent(\n\t\t\t\t\t\"click\", true, false, view, 0, 0, 0, 0, 0\n\t\t\t\t\t, false, false, false, false, 0, null\n\t\t\t\t);\n\t\t\t\tsave_link.dispatchEvent(event);\n\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\tdispatch_all();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Object and web filesystem URLs have a problem saving in Google Chrome when\n\t\t\t// viewed in a tab, so I force save with application/octet-stream\n\t\t\t// http://code.google.com/p/chromium/issues/detail?id=91158\n\t\t\tif (view.chrome && type && type !== force_saveable_type) {\n\t\t\t\tslice = blob.slice || blob.webkitSlice;\n\t\t\t\tblob = slice.call(blob, 0, blob.size, force_saveable_type);\n\t\t\t\tblob_changed = true;\n\t\t\t}\n\t\t\t// Since I can't be sure that the guessed media type will trigger a download\n\t\t\t// in WebKit, I append .download to the filename.\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=65440\n\t\t\tif (webkit_req_fs && name !== \"download\") {\n\t\t\t\tname += \".download\";\n\t\t\t}\n\t\t\tif (type === force_saveable_type || webkit_req_fs) {\n\t\t\t\ttarget_view = view;\n\t\t\t}\n\t\t\tif (!req_fs) {\n\t\t\t\tfs_error();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfs_min_size += blob.size;\n\t\t\treq_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {\n\t\t\t\tfs.root.getDirectory(\"saved\", create_if_not_found, abortable(function(dir) {\n\t\t\t\t\tvar save = function() {\n\t\t\t\t\t\tdir.getFile(name, create_if_not_found, abortable(function(file) {\n\t\t\t\t\t\t\tfile.createWriter(abortable(function(writer) {\n\t\t\t\t\t\t\t\twriter.onwriteend = function(event) {\n\t\t\t\t\t\t\t\t\ttarget_view.location.href = file.toURL();\n\t\t\t\t\t\t\t\t\tdeletion_queue.push(file);\n\t\t\t\t\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t\t\t\t\t\tdispatch(filesaver, \"writeend\", event);\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\twriter.onerror = function() {\n\t\t\t\t\t\t\t\t\tvar error = writer.error;\n\t\t\t\t\t\t\t\t\tif (error.code !== error.ABORT_ERR) {\n\t\t\t\t\t\t\t\t\t\tfs_error();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\"writestart progress write abort\".split(\" \").forEach(function(event) {\n\t\t\t\t\t\t\t\t\twriter[\"on\" + event] = filesaver[\"on\" + event];\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\twriter.write(blob);\n\t\t\t\t\t\t\t\tfilesaver.abort = function() {\n\t\t\t\t\t\t\t\t\twriter.abort();\n\t\t\t\t\t\t\t\t\tfilesaver.readyState = filesaver.DONE;\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tfilesaver.readyState = filesaver.WRITING;\n\t\t\t\t\t\t\t}), fs_error);\n\t\t\t\t\t\t}), fs_error);\n\t\t\t\t\t};\n\t\t\t\t\tdir.getFile(name, {create: false}, abortable(function(file) {\n\t\t\t\t\t\t// delete file if it already exists\n\t\t\t\t\t\tfile.remove();\n\t\t\t\t\t\tsave();\n\t\t\t\t\t}), abortable(function(ex) {\n\t\t\t\t\t\tif (ex.code === ex.NOT_FOUND_ERR) {\n\t\t\t\t\t\t\tsave();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfs_error();\n\t\t\t\t\t\t}\n\t\t\t\t\t}));\n\t\t\t\t}), fs_error);\n\t\t\t}), fs_error);\n\t\t}\n\t\t, FS_proto = FileSaver.prototype\n\t\t, saveAs = function(blob, name) {\n\t\t\treturn new FileSaver(blob, name);\n\t\t}\n\t;\n\tFS_proto.abort = function() {\n\t\tvar filesaver = this;\n\t\tfilesaver.readyState = filesaver.DONE;\n\t\tdispatch(filesaver, \"abort\");\n\t};\n\tFS_proto.readyState = FS_proto.INIT = 0;\n\tFS_proto.WRITING = 1;\n\tFS_proto.DONE = 2;\n\n\tFS_proto.error =\n\tFS_proto.onwritestart =\n\tFS_proto.onprogress =\n\tFS_proto.onwrite =\n\tFS_proto.onabort =\n\tFS_proto.onerror =\n\tFS_proto.onwriteend =\n\t\tnull;\n\n\tview.addEventListener(\"unload\", process_deletion_queue, false);\n\tsaveAs.unload = function() {\n\t\tprocess_deletion_queue();\n\t\tview.removeEventListener(\"unload\", process_deletion_queue, false);\n\t};\n\treturn saveAs;\n}(\n\t   typeof self !== \"undefined\" && self\n\t|| typeof window !== \"undefined\" && window\n\t|| this.content\n));\n// `self` is undefined in Firefox for Android content script context\n// while `this` is nsIContentFrameMessageManager\n// with an attribute `content` that corresponds to the window\n\nif (typeof module !== \"undefined\" && module !== null) {\n  module.exports = saveAs;\n} else if ((typeof define !== \"undefined\" && define !== null) && (define.amd != null)) {\n  define([], function() {\n    return saveAs;\n  });\n}"
  },
  {
    "path": "static/js/bootstrap.js",
    "content": "/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under the MIT license\n */\n\nif (typeof jQuery === 'undefined') {\n    throw new Error('Bootstrap\\'s JavaScript requires jQuery')\n  }\n  \n  +function ($) {\n    'use strict';\n    var version = $.fn.jquery.split(' ')[0].split('.')\n    if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) {\n      throw new Error('Bootstrap\\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4')\n    }\n  }(jQuery);\n  \n  /* ========================================================================\n   * Bootstrap: transition.js v3.3.7\n   * http://getbootstrap.com/javascript/#transitions\n   * ========================================================================\n   * Copyright 2011-2016 Twitter, Inc.\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * ======================================================================== */\n  \n  \n  +function ($) {\n    'use strict';\n  \n    // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)\n    // ============================================================\n  \n    function transitionEnd() {\n      var el = document.createElement('bootstrap')\n  \n      var transEndEventNames = {\n        WebkitTransition : 'webkitTransitionEnd',\n        MozTransition    : 'transitionend',\n        OTransition      : 'oTransitionEnd otransitionend',\n        transition       : 'transitionend'\n      }\n  \n      for (var name in transEndEventNames) {\n        if (el.style[name] !== undefined) {\n          return { end: transEndEventNames[name] }\n        }\n      }\n  \n      return false // explicit for ie8 (  ._.)\n    }\n  \n    // http://blog.alexmaccaw.com/css-transitions\n    $.fn.emulateTransitionEnd = function (duration) {\n      var called = false\n      var $el = this\n      $(this).one('bsTransitionEnd', function () { called = true })\n      var callback = function () { if (!called) $($el).trigger($.support.transition.end) }\n      setTimeout(callback, duration)\n      return this\n    }\n  \n    $(function () {\n      $.support.transition = transitionEnd()\n  \n      if (!$.support.transition) return\n  \n      $.event.special.bsTransitionEnd = {\n        bindType: $.support.transition.end,\n        delegateType: $.support.transition.end,\n        handle: function (e) {\n          if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)\n        }\n      }\n    })\n  \n  }(jQuery);\n  \n  /* ========================================================================\n   * Bootstrap: alert.js v3.3.7\n   * http://getbootstrap.com/javascript/#alerts\n   * ========================================================================\n   * Copyright 2011-2016 Twitter, Inc.\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * ======================================================================== */\n  \n  \n  +function ($) {\n    'use strict';\n  \n    // ALERT CLASS DEFINITION\n    // ======================\n  \n    var dismiss = '[data-dismiss=\"alert\"]'\n    var Alert   = function (el) {\n      $(el).on('click', dismiss, this.close)\n    }\n  \n    Alert.VERSION = '3.3.7'\n  \n    Alert.TRANSITION_DURATION = 150\n  \n    Alert.prototype.close = function (e) {\n      var $this    = $(this)\n      var selector = $this.attr('data-target')\n  \n      if (!selector) {\n        selector = $this.attr('href')\n        selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n      }\n  \n      var $parent = $(selector === '#' ? [] : selector)\n  \n      if (e) e.preventDefault()\n  \n      if (!$parent.length) {\n        $parent = $this.closest('.alert')\n      }\n  \n      $parent.trigger(e = $.Event('close.bs.alert'))\n  \n      if (e.isDefaultPrevented()) return\n  \n      $parent.removeClass('in')\n  \n      function removeElement() {\n        // detach from parent, fire event then clean up data\n        $parent.detach().trigger('closed.bs.alert').remove()\n      }\n  \n      $.support.transition && $parent.hasClass('fade') ?\n        $parent\n          .one('bsTransitionEnd', removeElement)\n          .emulateTransitionEnd(Alert.TRANSITION_DURATION) :\n        removeElement()\n    }\n  \n  \n    // ALERT PLUGIN DEFINITION\n    // =======================\n  \n    function Plugin(option) {\n      return this.each(function () {\n        var $this = $(this)\n        var data  = $this.data('bs.alert')\n  \n        if (!data) $this.data('bs.alert', (data = new Alert(this)))\n        if (typeof option == 'string') data[option].call($this)\n      })\n    }\n  \n    var old = $.fn.alert\n  \n    $.fn.alert             = Plugin\n    $.fn.alert.Constructor = Alert\n  \n  \n    // ALERT NO CONFLICT\n    // =================\n  \n    $.fn.alert.noConflict = function () {\n      $.fn.alert = old\n      return this\n    }\n  \n  \n    // ALERT DATA-API\n    // ==============\n  \n    $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)\n  \n  }(jQuery);\n  \n  /* ========================================================================\n   * Bootstrap: button.js v3.3.7\n   * http://getbootstrap.com/javascript/#buttons\n   * ========================================================================\n   * Copyright 2011-2016 Twitter, Inc.\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * ======================================================================== */\n  \n  \n  +function ($) {\n    'use strict';\n  \n    // BUTTON PUBLIC CLASS DEFINITION\n    // ==============================\n  \n    var Button = function (element, options) {\n      this.$element  = $(element)\n      this.options   = $.extend({}, Button.DEFAULTS, options)\n      this.isLoading = false\n    }\n  \n    Button.VERSION  = '3.3.7'\n  \n    Button.DEFAULTS = {\n      loadingText: 'loading...'\n    }\n  \n    Button.prototype.setState = function (state) {\n      var d    = 'disabled'\n      var $el  = this.$element\n      var val  = $el.is('input') ? 'val' : 'html'\n      var data = $el.data()\n  \n      state += 'Text'\n  \n      if (data.resetText == null) $el.data('resetText', $el[val]())\n  \n      // push to event loop to allow forms to submit\n      setTimeout($.proxy(function () {\n        $el[val](data[state] == null ? this.options[state] : data[state])\n  \n        if (state == 'loadingText') {\n          this.isLoading = true\n          $el.addClass(d).attr(d, d).prop(d, true)\n        } else if (this.isLoading) {\n          this.isLoading = false\n          $el.removeClass(d).removeAttr(d).prop(d, false)\n        }\n      }, this), 0)\n    }\n  \n    Button.prototype.toggle = function () {\n      var changed = true\n      var $parent = this.$element.closest('[data-toggle=\"buttons\"]')\n  \n      if ($parent.length) {\n        var $input = this.$element.find('input')\n        if ($input.prop('type') == 'radio') {\n          if ($input.prop('checked')) changed = false\n          $parent.find('.active').removeClass('active')\n          this.$element.addClass('active')\n        } else if ($input.prop('type') == 'checkbox') {\n          if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false\n          this.$element.toggleClass('active')\n        }\n        $input.prop('checked', this.$element.hasClass('active'))\n        if (changed) $input.trigger('change')\n      } else {\n        this.$element.attr('aria-pressed', !this.$element.hasClass('active'))\n        this.$element.toggleClass('active')\n      }\n    }\n  \n  \n    // BUTTON PLUGIN DEFINITION\n    // ========================\n  \n    function Plugin(option) {\n      return this.each(function () {\n        var $this   = $(this)\n        var data    = $this.data('bs.button')\n        var options = typeof option == 'object' && option\n  \n        if (!data) $this.data('bs.button', (data = new Button(this, options)))\n  \n        if (option == 'toggle') data.toggle()\n        else if (option) data.setState(option)\n      })\n    }\n  \n    var old = $.fn.button\n  \n    $.fn.button             = Plugin\n    $.fn.button.Constructor = Button\n  \n  \n    // BUTTON NO CONFLICT\n    // ==================\n  \n    $.fn.button.noConflict = function () {\n      $.fn.button = old\n      return this\n    }\n  \n  \n    // BUTTON DATA-API\n    // ===============\n  \n    $(document)\n      .on('click.bs.button.data-api', '[data-toggle^=\"button\"]', function (e) {\n        var $btn = $(e.target).closest('.btn')\n        Plugin.call($btn, 'toggle')\n        if (!($(e.target).is('input[type=\"radio\"], input[type=\"checkbox\"]'))) {\n          // Prevent double click on radios, and the double selections (so cancellation) on checkboxes\n          e.preventDefault()\n          // The target component still receive the focus\n          if ($btn.is('input,button')) $btn.trigger('focus')\n          else $btn.find('input:visible,button:visible').first().trigger('focus')\n        }\n      })\n      .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^=\"button\"]', function (e) {\n        $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))\n      })\n  \n  }(jQuery);\n  \n  /* ========================================================================\n   * Bootstrap: carousel.js v3.3.7\n   * http://getbootstrap.com/javascript/#carousel\n   * ========================================================================\n   * Copyright 2011-2016 Twitter, Inc.\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * ======================================================================== */\n  \n  \n  +function ($) {\n    'use strict';\n  \n    // CAROUSEL CLASS DEFINITION\n    // =========================\n  \n    var Carousel = function (element, options) {\n      this.$element    = $(element)\n      this.$indicators = this.$element.find('.carousel-indicators')\n      this.options     = options\n      this.paused      = null\n      this.sliding     = null\n      this.interval    = null\n      this.$active     = null\n      this.$items      = null\n  \n      this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))\n  \n      this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element\n        .on('mouseenter.bs.carousel', $.proxy(this.pause, this))\n        .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))\n    }\n  \n    Carousel.VERSION  = '3.3.7'\n  \n    Carousel.TRANSITION_DURATION = 600\n  \n    Carousel.DEFAULTS = {\n      interval: 5000,\n      pause: 'hover',\n      wrap: true,\n      keyboard: true\n    }\n  \n    Carousel.prototype.keydown = function (e) {\n      if (/input|textarea/i.test(e.target.tagName)) return\n      switch (e.which) {\n        case 37: this.prev(); break\n        case 39: this.next(); break\n        default: return\n      }\n  \n      e.preventDefault()\n    }\n  \n    Carousel.prototype.cycle = function (e) {\n      e || (this.paused = false)\n  \n      this.interval && clearInterval(this.interval)\n  \n      this.options.interval\n        && !this.paused\n        && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))\n  \n      return this\n    }\n  \n    Carousel.prototype.getItemIndex = function (item) {\n      this.$items = item.parent().children('.item')\n      return this.$items.index(item || this.$active)\n    }\n  \n    Carousel.prototype.getItemForDirection = function (direction, active) {\n      var activeIndex = this.getItemIndex(active)\n      var willWrap = (direction == 'prev' && activeIndex === 0)\n                  || (direction == 'next' && activeIndex == (this.$items.length - 1))\n      if (willWrap && !this.options.wrap) return active\n      var delta = direction == 'prev' ? -1 : 1\n      var itemIndex = (activeIndex + delta) % this.$items.length\n      return this.$items.eq(itemIndex)\n    }\n  \n    Carousel.prototype.to = function (pos) {\n      var that        = this\n      var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))\n  \n      if (pos > (this.$items.length - 1) || pos < 0) return\n  \n      if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, \"slid\"\n      if (activeIndex == pos) return this.pause().cycle()\n  \n      return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))\n    }\n  \n    Carousel.prototype.pause = function (e) {\n      e || (this.paused = true)\n  \n      if (this.$element.find('.next, .prev').length && $.support.transition) {\n        this.$element.trigger($.support.transition.end)\n        this.cycle(true)\n      }\n  \n      this.interval = clearInterval(this.interval)\n  \n      return this\n    }\n  \n    Carousel.prototype.next = function () {\n      if (this.sliding) return\n      return this.slide('next')\n    }\n  \n    Carousel.prototype.prev = function () {\n      if (this.sliding) return\n      return this.slide('prev')\n    }\n  \n    Carousel.prototype.slide = function (type, next) {\n      var $active   = this.$element.find('.item.active')\n      var $next     = next || this.getItemForDirection(type, $active)\n      var isCycling = this.interval\n      var direction = type == 'next' ? 'left' : 'right'\n      var that      = this\n  \n      if ($next.hasClass('active')) return (this.sliding = false)\n  \n      var relatedTarget = $next[0]\n      var slideEvent = $.Event('slide.bs.carousel', {\n        relatedTarget: relatedTarget,\n        direction: direction\n      })\n      this.$element.trigger(slideEvent)\n      if (slideEvent.isDefaultPrevented()) return\n  \n      this.sliding = true\n  \n      isCycling && this.pause()\n  \n      if (this.$indicators.length) {\n        this.$indicators.find('.active').removeClass('active')\n        var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])\n        $nextIndicator && $nextIndicator.addClass('active')\n      }\n  \n      var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, \"slid\"\n      if ($.support.transition && this.$element.hasClass('slide')) {\n        $next.addClass(type)\n        $next[0].offsetWidth // force reflow\n        $active.addClass(direction)\n        $next.addClass(direction)\n        $active\n          .one('bsTransitionEnd', function () {\n            $next.removeClass([type, direction].join(' ')).addClass('active')\n            $active.removeClass(['active', direction].join(' '))\n            that.sliding = false\n            setTimeout(function () {\n              that.$element.trigger(slidEvent)\n            }, 0)\n          })\n          .emulateTransitionEnd(Carousel.TRANSITION_DURATION)\n      } else {\n        $active.removeClass('active')\n        $next.addClass('active')\n        this.sliding = false\n        this.$element.trigger(slidEvent)\n      }\n  \n      isCycling && this.cycle()\n  \n      return this\n    }\n  \n  \n    // CAROUSEL PLUGIN DEFINITION\n    // ==========================\n  \n    function Plugin(option) {\n      return this.each(function () {\n        var $this   = $(this)\n        var data    = $this.data('bs.carousel')\n        var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)\n        var action  = typeof option == 'string' ? option : options.slide\n  \n        if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))\n        if (typeof option == 'number') data.to(option)\n        else if (action) data[action]()\n        else if (options.interval) data.pause().cycle()\n      })\n    }\n  \n    var old = $.fn.carousel\n  \n    $.fn.carousel             = Plugin\n    $.fn.carousel.Constructor = Carousel\n  \n  \n    // CAROUSEL NO CONFLICT\n    // ====================\n  \n    $.fn.carousel.noConflict = function () {\n      $.fn.carousel = old\n      return this\n    }\n  \n  \n    // CAROUSEL DATA-API\n    // =================\n  \n    var clickHandler = function (e) {\n      var href\n      var $this   = $(this)\n      var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '')) // strip for ie7\n      if (!$target.hasClass('carousel')) return\n      var options = $.extend({}, $target.data(), $this.data())\n      var slideIndex = $this.attr('data-slide-to')\n      if (slideIndex) options.interval = false\n  \n      Plugin.call($target, options)\n  \n      if (slideIndex) {\n        $target.data('bs.carousel').to(slideIndex)\n      }\n  \n      e.preventDefault()\n    }\n  \n    $(document)\n      .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)\n      .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)\n  \n    $(window).on('load', function () {\n      $('[data-ride=\"carousel\"]').each(function () {\n        var $carousel = $(this)\n        Plugin.call($carousel, $carousel.data())\n      })\n    })\n  \n  }(jQuery);\n  \n  /* ========================================================================\n   * Bootstrap: collapse.js v3.3.7\n   * http://getbootstrap.com/javascript/#collapse\n   * ========================================================================\n   * Copyright 2011-2016 Twitter, Inc.\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * ======================================================================== */\n  \n  /* jshint latedef: false */\n  \n  +function ($) {\n    'use strict';\n  \n    // COLLAPSE PUBLIC CLASS DEFINITION\n    // ================================\n  \n    var Collapse = function (element, options) {\n      this.$element      = $(element)\n      this.options       = $.extend({}, Collapse.DEFAULTS, options)\n      this.$trigger      = $('[data-toggle=\"collapse\"][href=\"#' + element.id + '\"],' +\n                             '[data-toggle=\"collapse\"][data-target=\"#' + element.id + '\"]')\n      this.transitioning = null\n  \n      if (this.options.parent) {\n        this.$parent = this.getParent()\n      } else {\n        this.addAriaAndCollapsedClass(this.$element, this.$trigger)\n      }\n  \n      if (this.options.toggle) this.toggle()\n    }\n  \n    Collapse.VERSION  = '3.3.7'\n  \n    Collapse.TRANSITION_DURATION = 350\n  \n    Collapse.DEFAULTS = {\n      toggle: true\n    }\n  \n    Collapse.prototype.dimension = function () {\n      var hasWidth = this.$element.hasClass('width')\n      return hasWidth ? 'width' : 'height'\n    }\n  \n    Collapse.prototype.show = function () {\n      if (this.transitioning || this.$element.hasClass('in')) return\n  \n      var activesData\n      var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')\n  \n      if (actives && actives.length) {\n        activesData = actives.data('bs.collapse')\n        if (activesData && activesData.transitioning) return\n      }\n  \n      var startEvent = $.Event('show.bs.collapse')\n      this.$element.trigger(startEvent)\n      if (startEvent.isDefaultPrevented()) return\n  \n      if (actives && actives.length) {\n        Plugin.call(actives, 'hide')\n        activesData || actives.data('bs.collapse', null)\n      }\n  \n      var dimension = this.dimension()\n  \n      this.$element\n        .removeClass('collapse')\n        .addClass('collapsing')[dimension](0)\n        .attr('aria-expanded', true)\n  \n      this.$trigger\n        .removeClass('collapsed')\n        .attr('aria-expanded', true)\n  \n      this.transitioning = 1\n  \n      var complete = function () {\n        this.$element\n          .removeClass('collapsing')\n          .addClass('collapse in')[dimension]('')\n        this.transitioning = 0\n        this.$element\n          .trigger('shown.bs.collapse')\n      }\n  \n      if (!$.support.transition) return complete.call(this)\n  \n      var scrollSize = $.camelCase(['scroll', dimension].join('-'))\n  \n      this.$element\n        .one('bsTransitionEnd', $.proxy(complete, this))\n        .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])\n    }\n  \n    Collapse.prototype.hide = function () {\n      if (this.transitioning || !this.$element.hasClass('in')) return\n  \n      var startEvent = $.Event('hide.bs.collapse')\n      this.$element.trigger(startEvent)\n      if (startEvent.isDefaultPrevented()) return\n  \n      var dimension = this.dimension()\n  \n      this.$element[dimension](this.$element[dimension]())[0].offsetHeight\n  \n      this.$element\n        .addClass('collapsing')\n        .removeClass('collapse in')\n        .attr('aria-expanded', false)\n  \n      this.$trigger\n        .addClass('collapsed')\n        .attr('aria-expanded', false)\n  \n      this.transitioning = 1\n  \n      var complete = function () {\n        this.transitioning = 0\n        this.$element\n          .removeClass('collapsing')\n          .addClass('collapse')\n          .trigger('hidden.bs.collapse')\n      }\n  \n      if (!$.support.transition) return complete.call(this)\n  \n      this.$element\n        [dimension](0)\n        .one('bsTransitionEnd', $.proxy(complete, this))\n        .emulateTransitionEnd(Collapse.TRANSITION_DURATION)\n    }\n  \n    Collapse.prototype.toggle = function () {\n      this[this.$element.hasClass('in') ? 'hide' : 'show']()\n    }\n  \n    Collapse.prototype.getParent = function () {\n      return $(this.options.parent)\n        .find('[data-toggle=\"collapse\"][data-parent=\"' + this.options.parent + '\"]')\n        .each($.proxy(function (i, element) {\n          var $element = $(element)\n          this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)\n        }, this))\n        .end()\n    }\n  \n    Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {\n      var isOpen = $element.hasClass('in')\n  \n      $element.attr('aria-expanded', isOpen)\n      $trigger\n        .toggleClass('collapsed', !isOpen)\n        .attr('aria-expanded', isOpen)\n    }\n  \n    function getTargetFromTrigger($trigger) {\n      var href\n      var target = $trigger.attr('data-target')\n        || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '') // strip for ie7\n  \n      return $(target)\n    }\n  \n  \n    // COLLAPSE PLUGIN DEFINITION\n    // ==========================\n  \n    function Plugin(option) {\n      return this.each(function () {\n        var $this   = $(this)\n        var data    = $this.data('bs.collapse')\n        var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)\n  \n        if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false\n        if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))\n        if (typeof option == 'string') data[option]()\n      })\n    }\n  \n    var old = $.fn.collapse\n  \n    $.fn.collapse             = Plugin\n    $.fn.collapse.Constructor = Collapse\n  \n  \n    // COLLAPSE NO CONFLICT\n    // ====================\n  \n    $.fn.collapse.noConflict = function () {\n      $.fn.collapse = old\n      return this\n    }\n  \n  \n    // COLLAPSE DATA-API\n    // =================\n  \n    $(document).on('click.bs.collapse.data-api', '[data-toggle=\"collapse\"]', function (e) {\n      var $this   = $(this)\n  \n      if (!$this.attr('data-target')) e.preventDefault()\n  \n      var $target = getTargetFromTrigger($this)\n      var data    = $target.data('bs.collapse')\n      var option  = data ? 'toggle' : $this.data()\n  \n      Plugin.call($target, option)\n    })\n  \n  }(jQuery);\n  \n  /* ========================================================================\n   * Bootstrap: dropdown.js v3.3.7\n   * http://getbootstrap.com/javascript/#dropdowns\n   * ========================================================================\n   * Copyright 2011-2016 Twitter, Inc.\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * ======================================================================== */\n  \n  \n  +function ($) {\n    'use strict';\n  \n    // DROPDOWN CLASS DEFINITION\n    // =========================\n  \n    var backdrop = '.dropdown-backdrop'\n    var toggle   = '[data-toggle=\"dropdown\"]'\n    var Dropdown = function (element) {\n      $(element).on('click.bs.dropdown', this.toggle)\n    }\n  \n    Dropdown.VERSION = '3.3.7'\n  \n    function getParent($this) {\n      var selector = $this.attr('data-target')\n  \n      if (!selector) {\n        selector = $this.attr('href')\n        selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n      }\n  \n      var $parent = selector && $(selector)\n  \n      return $parent && $parent.length ? $parent : $this.parent()\n    }\n  \n    function clearMenus(e) {\n      if (e && e.which === 3) return\n      $(backdrop).remove()\n      $(toggle).each(function () {\n        var $this         = $(this)\n        var $parent       = getParent($this)\n        var relatedTarget = { relatedTarget: this }\n  \n        if (!$parent.hasClass('open')) return\n  \n        if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return\n  \n        $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))\n  \n        if (e.isDefaultPrevented()) return\n  \n        $this.attr('aria-expanded', 'false')\n        $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))\n      })\n    }\n  \n    Dropdown.prototype.toggle = function (e) {\n      var $this = $(this)\n  \n      if ($this.is('.disabled, :disabled')) return\n  \n      var $parent  = getParent($this)\n      var isActive = $parent.hasClass('open')\n  \n      clearMenus()\n  \n      if (!isActive) {\n        if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {\n          // if mobile we use a backdrop because click events don't delegate\n          $(document.createElement('div'))\n            .addClass('dropdown-backdrop')\n            .insertAfter($(this))\n            .on('click', clearMenus)\n        }\n  \n        var relatedTarget = { relatedTarget: this }\n        $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))\n  \n        if (e.isDefaultPrevented()) return\n  \n        $this\n          .trigger('focus')\n          .attr('aria-expanded', 'true')\n  \n        $parent\n          .toggleClass('open')\n          .trigger($.Event('shown.bs.dropdown', relatedTarget))\n      }\n  \n      return false\n    }\n  \n    Dropdown.prototype.keydown = function (e) {\n      if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return\n  \n      var $this = $(this)\n  \n      e.preventDefault()\n      e.stopPropagation()\n  \n      if ($this.is('.disabled, :disabled')) return\n  \n      var $parent  = getParent($this)\n      var isActive = $parent.hasClass('open')\n  \n      if (!isActive && e.which != 27 || isActive && e.which == 27) {\n        if (e.which == 27) $parent.find(toggle).trigger('focus')\n        return $this.trigger('click')\n      }\n  \n      var desc = ' li:not(.disabled):visible a'\n      var $items = $parent.find('.dropdown-menu' + desc)\n  \n      if (!$items.length) return\n  \n      var index = $items.index(e.target)\n  \n      if (e.which == 38 && index > 0)                 index--         // up\n      if (e.which == 40 && index < $items.length - 1) index++         // down\n      if (!~index)                                    index = 0\n  \n      $items.eq(index).trigger('focus')\n    }\n  \n  \n    // DROPDOWN PLUGIN DEFINITION\n    // ==========================\n  \n    function Plugin(option) {\n      return this.each(function () {\n        var $this = $(this)\n        var data  = $this.data('bs.dropdown')\n  \n        if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))\n        if (typeof option == 'string') data[option].call($this)\n      })\n    }\n  \n    var old = $.fn.dropdown\n  \n    $.fn.dropdown             = Plugin\n    $.fn.dropdown.Constructor = Dropdown\n  \n  \n    // DROPDOWN NO CONFLICT\n    // ====================\n  \n    $.fn.dropdown.noConflict = function () {\n      $.fn.dropdown = old\n      return this\n    }\n  \n  \n    // APPLY TO STANDARD DROPDOWN ELEMENTS\n    // ===================================\n  \n    $(document)\n      .on('click.bs.dropdown.data-api', clearMenus)\n      .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })\n      .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)\n      .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)\n      .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)\n  \n  }(jQuery);\n  \n  /* ========================================================================\n   * Bootstrap: modal.js v3.3.7\n   * http://getbootstrap.com/javascript/#modals\n   * ========================================================================\n   * Copyright 2011-2016 Twitter, Inc.\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * ======================================================================== */\n  \n  \n  +function ($) {\n    'use strict';\n  \n    // MODAL CLASS DEFINITION\n    // ======================\n  \n    var Modal = function (element, options) {\n      this.options             = options\n      this.$body               = $(document.body)\n      this.$element            = $(element)\n      this.$dialog             = this.$element.find('.modal-dialog')\n      this.$backdrop           = null\n      this.isShown             = null\n      this.originalBodyPad     = null\n      this.scrollbarWidth      = 0\n      this.ignoreBackdropClick = false\n  \n      if (this.options.remote) {\n        this.$element\n          .find('.modal-content')\n          .load(this.options.remote, $.proxy(function () {\n            this.$element.trigger('loaded.bs.modal')\n          }, this))\n      }\n    }\n  \n    Modal.VERSION  = '3.3.7'\n  \n    Modal.TRANSITION_DURATION = 300\n    Modal.BACKDROP_TRANSITION_DURATION = 150\n  \n    Modal.DEFAULTS = {\n      backdrop: true,\n      keyboard: true,\n      show: true\n    }\n  \n    Modal.prototype.toggle = function (_relatedTarget) {\n      return this.isShown ? this.hide() : this.show(_relatedTarget)\n    }\n  \n    Modal.prototype.show = function (_relatedTarget) {\n      var that = this\n      var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })\n  \n      this.$element.trigger(e)\n  \n      if (this.isShown || e.isDefaultPrevented()) return\n  \n      this.isShown = true\n  \n      this.checkScrollbar()\n      this.setScrollbar()\n      this.$body.addClass('modal-open')\n  \n      this.escape()\n      this.resize()\n  \n      this.$element.on('click.dismiss.bs.modal', '[data-dismiss=\"modal\"]', $.proxy(this.hide, this))\n  \n      this.$dialog.on('mousedown.dismiss.bs.modal', function () {\n        that.$element.one('mouseup.dismiss.bs.modal', function (e) {\n          if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true\n        })\n      })\n  \n      this.backdrop(function () {\n        var transition = $.support.transition && that.$element.hasClass('fade')\n  \n        if (!that.$element.parent().length) {\n          that.$element.appendTo(that.$body) // don't move modals dom position\n        }\n  \n        that.$element\n          .show()\n          .scrollTop(0)\n  \n        that.adjustDialog()\n  \n        if (transition) {\n          that.$element[0].offsetWidth // force reflow\n        }\n  \n        that.$element.addClass('in')\n  \n        that.enforceFocus()\n  \n        var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })\n  \n        transition ?\n          that.$dialog // wait for modal to slide in\n            .one('bsTransitionEnd', function () {\n              that.$element.trigger('focus').trigger(e)\n            })\n            .emulateTransitionEnd(Modal.TRANSITION_DURATION) :\n          that.$element.trigger('focus').trigger(e)\n      })\n    }\n  \n    Modal.prototype.hide = function (e) {\n      if (e) e.preventDefault()\n  \n      e = $.Event('hide.bs.modal')\n  \n      this.$element.trigger(e)\n  \n      if (!this.isShown || e.isDefaultPrevented()) return\n  \n      this.isShown = false\n  \n      this.escape()\n      this.resize()\n  \n      $(document).off('focusin.bs.modal')\n  \n      this.$element\n        .removeClass('in')\n        .off('click.dismiss.bs.modal')\n        .off('mouseup.dismiss.bs.modal')\n  \n      this.$dialog.off('mousedown.dismiss.bs.modal')\n  \n      $.support.transition && this.$element.hasClass('fade') ?\n        this.$element\n          .one('bsTransitionEnd', $.proxy(this.hideModal, this))\n          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :\n        this.hideModal()\n    }\n  \n    Modal.prototype.enforceFocus = function () {\n      $(document)\n        .off('focusin.bs.modal') // guard against infinite focus loop\n        .on('focusin.bs.modal', $.proxy(function (e) {\n          if (document !== e.target &&\n              this.$element[0] !== e.target &&\n              !this.$element.has(e.target).length) {\n            this.$element.trigger('focus')\n          }\n        }, this))\n    }\n  \n    Modal.prototype.escape = function () {\n      if (this.isShown && this.options.keyboard) {\n        this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {\n          e.which == 27 && this.hide()\n        }, this))\n      } else if (!this.isShown) {\n        this.$element.off('keydown.dismiss.bs.modal')\n      }\n    }\n  \n    Modal.prototype.resize = function () {\n      if (this.isShown) {\n        $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))\n      } else {\n        $(window).off('resize.bs.modal')\n      }\n    }\n  \n    Modal.prototype.hideModal = function () {\n      var that = this\n      this.$element.hide()\n      this.backdrop(function () {\n        that.$body.removeClass('modal-open')\n        that.resetAdjustments()\n        that.resetScrollbar()\n        that.$element.trigger('hidden.bs.modal')\n      })\n    }\n  \n    Modal.prototype.removeBackdrop = function () {\n      this.$backdrop && this.$backdrop.remove()\n      this.$backdrop = null\n    }\n  \n    Modal.prototype.backdrop = function (callback) {\n      var that = this\n      var animate = this.$element.hasClass('fade') ? 'fade' : ''\n  \n      if (this.isShown && this.options.backdrop) {\n        var doAnimate = $.support.transition && animate\n  \n        this.$backdrop = $(document.createElement('div'))\n          .addClass('modal-backdrop ' + animate)\n          .appendTo(this.$body)\n  \n        this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {\n          if (this.ignoreBackdropClick) {\n            this.ignoreBackdropClick = false\n            return\n          }\n          if (e.target !== e.currentTarget) return\n          this.options.backdrop == 'static'\n            ? this.$element[0].focus()\n            : this.hide()\n        }, this))\n  \n        if (doAnimate) this.$backdrop[0].offsetWidth // force reflow\n  \n        this.$backdrop.addClass('in')\n  \n        if (!callback) return\n  \n        doAnimate ?\n          this.$backdrop\n            .one('bsTransitionEnd', callback)\n            .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :\n          callback()\n  \n      } else if (!this.isShown && this.$backdrop) {\n        this.$backdrop.removeClass('in')\n  \n        var callbackRemove = function () {\n          that.removeBackdrop()\n          callback && callback()\n        }\n        $.support.transition && this.$element.hasClass('fade') ?\n          this.$backdrop\n            .one('bsTransitionEnd', callbackRemove)\n            .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :\n          callbackRemove()\n  \n      } else if (callback) {\n        callback()\n      }\n    }\n  \n    // these following methods are used to handle overflowing modals\n  \n    Modal.prototype.handleUpdate = function () {\n      this.adjustDialog()\n    }\n  \n    Modal.prototype.adjustDialog = function () {\n      var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight\n  \n      this.$element.css({\n        paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',\n        paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''\n      })\n    }\n  \n    Modal.prototype.resetAdjustments = function () {\n      this.$element.css({\n        paddingLeft: '',\n        paddingRight: ''\n      })\n    }\n  \n    Modal.prototype.checkScrollbar = function () {\n      var fullWindowWidth = window.innerWidth\n      if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8\n        var documentElementRect = document.documentElement.getBoundingClientRect()\n        fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)\n      }\n      this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth\n      this.scrollbarWidth = this.measureScrollbar()\n    }\n  \n    Modal.prototype.setScrollbar = function () {\n      var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)\n      this.originalBodyPad = document.body.style.paddingRight || ''\n      if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)\n    }\n  \n    Modal.prototype.resetScrollbar = function () {\n      this.$body.css('padding-right', this.originalBodyPad)\n    }\n  \n    Modal.prototype.measureScrollbar = function () { // thx walsh\n      var scrollDiv = document.createElement('div')\n      scrollDiv.className = 'modal-scrollbar-measure'\n      this.$body.append(scrollDiv)\n      var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth\n      this.$body[0].removeChild(scrollDiv)\n      return scrollbarWidth\n    }\n  \n  \n    // MODAL PLUGIN DEFINITION\n    // =======================\n  \n    function Plugin(option, _relatedTarget) {\n      return this.each(function () {\n        var $this   = $(this)\n        var data    = $this.data('bs.modal')\n        var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)\n  \n        if (!data) $this.data('bs.modal', (data = new Modal(this, options)))\n        if (typeof option == 'string') data[option](_relatedTarget)\n        else if (options.show) data.show(_relatedTarget)\n      })\n    }\n  \n    var old = $.fn.modal\n  \n    $.fn.modal             = Plugin\n    $.fn.modal.Constructor = Modal\n  \n  \n    // MODAL NO CONFLICT\n    // =================\n  \n    $.fn.modal.noConflict = function () {\n      $.fn.modal = old\n      return this\n    }\n  \n  \n    // MODAL DATA-API\n    // ==============\n  \n    $(document).on('click.bs.modal.data-api', '[data-toggle=\"modal\"]', function (e) {\n      var $this   = $(this)\n      var href    = $this.attr('href')\n      var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\\s]+$)/, ''))) // strip for ie7\n      var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())\n  \n      if ($this.is('a')) e.preventDefault()\n  \n      $target.one('show.bs.modal', function (showEvent) {\n        if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown\n        $target.one('hidden.bs.modal', function () {\n          $this.is(':visible') && $this.trigger('focus')\n        })\n      })\n      Plugin.call($target, option, this)\n    })\n  \n  }(jQuery);\n  \n  /* ========================================================================\n   * Bootstrap: tooltip.js v3.3.7\n   * http://getbootstrap.com/javascript/#tooltip\n   * Inspired by the original jQuery.tipsy by Jason Frame\n   * ========================================================================\n   * Copyright 2011-2016 Twitter, Inc.\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * ======================================================================== */\n  \n  \n  +function ($) {\n    'use strict';\n  \n    // TOOLTIP PUBLIC CLASS DEFINITION\n    // ===============================\n  \n    var Tooltip = function (element, options) {\n      this.type       = null\n      this.options    = null\n      this.enabled    = null\n      this.timeout    = null\n      this.hoverState = null\n      this.$element   = null\n      this.inState    = null\n  \n      this.init('tooltip', element, options)\n    }\n  \n    Tooltip.VERSION  = '3.3.7'\n  \n    Tooltip.TRANSITION_DURATION = 150\n  \n    Tooltip.DEFAULTS = {\n      animation: true,\n      placement: 'top',\n      selector: false,\n      template: '<div class=\"tooltip\" role=\"tooltip\"><div class=\"tooltip-arrow\"></div><div class=\"tooltip-inner\"></div></div>',\n      trigger: 'hover focus',\n      title: '',\n      delay: 0,\n      html: false,\n      container: false,\n      viewport: {\n        selector: 'body',\n        padding: 0\n      }\n    }\n  \n    Tooltip.prototype.init = function (type, element, options) {\n      this.enabled   = true\n      this.type      = type\n      this.$element  = $(element)\n      this.options   = this.getOptions(options)\n      this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))\n      this.inState   = { click: false, hover: false, focus: false }\n  \n      if (this.$element[0] instanceof document.constructor && !this.options.selector) {\n        throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')\n      }\n  \n      var triggers = this.options.trigger.split(' ')\n  \n      for (var i = triggers.length; i--;) {\n        var trigger = triggers[i]\n  \n        if (trigger == 'click') {\n          this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))\n        } else if (trigger != 'manual') {\n          var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'\n          var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'\n  \n          this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))\n          this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))\n        }\n      }\n  \n      this.options.selector ?\n        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :\n        this.fixTitle()\n    }\n  \n    Tooltip.prototype.getDefaults = function () {\n      return Tooltip.DEFAULTS\n    }\n  \n    Tooltip.prototype.getOptions = function (options) {\n      options = $.extend({}, this.getDefaults(), this.$element.data(), options)\n  \n      if (options.delay && typeof options.delay == 'number') {\n        options.delay = {\n          show: options.delay,\n          hide: options.delay\n        }\n      }\n  \n      return options\n    }\n  \n    Tooltip.prototype.getDelegateOptions = function () {\n      var options  = {}\n      var defaults = this.getDefaults()\n  \n      this._options && $.each(this._options, function (key, value) {\n        if (defaults[key] != value) options[key] = value\n      })\n  \n      return options\n    }\n  \n    Tooltip.prototype.enter = function (obj) {\n      var self = obj instanceof this.constructor ?\n        obj : $(obj.currentTarget).data('bs.' + this.type)\n  \n      if (!self) {\n        self = new this.constructor(obj.currentTarget, this.getDelegateOptions())\n        $(obj.currentTarget).data('bs.' + this.type, self)\n      }\n  \n      if (obj instanceof $.Event) {\n        self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true\n      }\n  \n      if (self.tip().hasClass('in') || self.hoverState == 'in') {\n        self.hoverState = 'in'\n        return\n      }\n  \n      clearTimeout(self.timeout)\n  \n      self.hoverState = 'in'\n  \n      if (!self.options.delay || !self.options.delay.show) return self.show()\n  \n      self.timeout = setTimeout(function () {\n        if (self.hoverState == 'in') self.show()\n      }, self.options.delay.show)\n    }\n  \n    Tooltip.prototype.isInStateTrue = function () {\n      for (var key in this.inState) {\n        if (this.inState[key]) return true\n      }\n  \n      return false\n    }\n  \n    Tooltip.prototype.leave = function (obj) {\n      var self = obj instanceof this.constructor ?\n        obj : $(obj.currentTarget).data('bs.' + this.type)\n  \n      if (!self) {\n        self = new this.constructor(obj.currentTarget, this.getDelegateOptions())\n        $(obj.currentTarget).data('bs.' + this.type, self)\n      }\n  \n      if (obj instanceof $.Event) {\n        self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false\n      }\n  \n      if (self.isInStateTrue()) return\n  \n      clearTimeout(self.timeout)\n  \n      self.hoverState = 'out'\n  \n      if (!self.options.delay || !self.options.delay.hide) return self.hide()\n  \n      self.timeout = setTimeout(function () {\n        if (self.hoverState == 'out') self.hide()\n      }, self.options.delay.hide)\n    }\n  \n    Tooltip.prototype.show = function () {\n      var e = $.Event('show.bs.' + this.type)\n  \n      if (this.hasContent() && this.enabled) {\n        this.$element.trigger(e)\n  \n        var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])\n        if (e.isDefaultPrevented() || !inDom) return\n        var that = this\n  \n        var $tip = this.tip()\n  \n        var tipId = this.getUID(this.type)\n  \n        this.setContent()\n        $tip.attr('id', tipId)\n        this.$element.attr('aria-describedby', tipId)\n  \n        if (this.options.animation) $tip.addClass('fade')\n  \n        var placement = typeof this.options.placement == 'function' ?\n          this.options.placement.call(this, $tip[0], this.$element[0]) :\n          this.options.placement\n  \n        var autoToken = /\\s?auto?\\s?/i\n        var autoPlace = autoToken.test(placement)\n        if (autoPlace) placement = placement.replace(autoToken, '') || 'top'\n  \n        $tip\n          .detach()\n          .css({ top: 0, left: 0, display: 'block' })\n          .addClass(placement)\n          .data('bs.' + this.type, this)\n  \n        this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)\n        this.$element.trigger('inserted.bs.' + this.type)\n  \n        var pos          = this.getPosition()\n        var actualWidth  = $tip[0].offsetWidth\n        var actualHeight = $tip[0].offsetHeight\n  \n        if (autoPlace) {\n          var orgPlacement = placement\n          var viewportDim = this.getPosition(this.$viewport)\n  \n          placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    :\n                      placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' :\n                      placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   :\n                      placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  :\n                      placement\n  \n          $tip\n            .removeClass(orgPlacement)\n            .addClass(placement)\n        }\n  \n        var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)\n  \n        this.applyPlacement(calculatedOffset, placement)\n  \n        var complete = function () {\n          var prevHoverState = that.hoverState\n          that.$element.trigger('shown.bs.' + that.type)\n          that.hoverState = null\n  \n          if (prevHoverState == 'out') that.leave(that)\n        }\n  \n        $.support.transition && this.$tip.hasClass('fade') ?\n          $tip\n            .one('bsTransitionEnd', complete)\n            .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :\n          complete()\n      }\n    }\n  \n    Tooltip.prototype.applyPlacement = function (offset, placement) {\n      var $tip   = this.tip()\n      var width  = $tip[0].offsetWidth\n      var height = $tip[0].offsetHeight\n  \n      // manually read margins because getBoundingClientRect includes difference\n      var marginTop = parseInt($tip.css('margin-top'), 10)\n      var marginLeft = parseInt($tip.css('margin-left'), 10)\n  \n      // we must check for NaN for ie 8/9\n      if (isNaN(marginTop))  marginTop  = 0\n      if (isNaN(marginLeft)) marginLeft = 0\n  \n      offset.top  += marginTop\n      offset.left += marginLeft\n  \n      // $.fn.offset doesn't round pixel values\n      // so we use setOffset directly with our own function B-0\n      $.offset.setOffset($tip[0], $.extend({\n        using: function (props) {\n          $tip.css({\n            top: Math.round(props.top),\n            left: Math.round(props.left)\n          })\n        }\n      }, offset), 0)\n  \n      $tip.addClass('in')\n  \n      // check to see if placing tip in new offset caused the tip to resize itself\n      var actualWidth  = $tip[0].offsetWidth\n      var actualHeight = $tip[0].offsetHeight\n  \n      if (placement == 'top' && actualHeight != height) {\n        offset.top = offset.top + height - actualHeight\n      }\n  \n      var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)\n  \n      if (delta.left) offset.left += delta.left\n      else offset.top += delta.top\n  \n      var isVertical          = /top|bottom/.test(placement)\n      var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight\n      var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'\n  \n      $tip.offset(offset)\n      this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)\n    }\n  \n    Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {\n      this.arrow()\n        .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')\n        .css(isVertical ? 'top' : 'left', '')\n    }\n  \n    Tooltip.prototype.setContent = function () {\n      var $tip  = this.tip()\n      var title = this.getTitle()\n  \n      $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)\n      $tip.removeClass('fade in top bottom left right')\n    }\n  \n    Tooltip.prototype.hide = function (callback) {\n      var that = this\n      var $tip = $(this.$tip)\n      var e    = $.Event('hide.bs.' + this.type)\n  \n      function complete() {\n        if (that.hoverState != 'in') $tip.detach()\n        if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.\n          that.$element\n            .removeAttr('aria-describedby')\n            .trigger('hidden.bs.' + that.type)\n        }\n        callback && callback()\n      }\n  \n      this.$element.trigger(e)\n  \n      if (e.isDefaultPrevented()) return\n  \n      $tip.removeClass('in')\n  \n      $.support.transition && $tip.hasClass('fade') ?\n        $tip\n          .one('bsTransitionEnd', complete)\n          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :\n        complete()\n  \n      this.hoverState = null\n  \n      return this\n    }\n  \n    Tooltip.prototype.fixTitle = function () {\n      var $e = this.$element\n      if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {\n        $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')\n      }\n    }\n  \n    Tooltip.prototype.hasContent = function () {\n      return this.getTitle()\n    }\n  \n    Tooltip.prototype.getPosition = function ($element) {\n      $element   = $element || this.$element\n  \n      var el     = $element[0]\n      var isBody = el.tagName == 'BODY'\n  \n      var elRect    = el.getBoundingClientRect()\n      if (elRect.width == null) {\n        // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n        elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })\n      }\n      var isSvg = window.SVGElement && el instanceof window.SVGElement\n      // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3.\n      // See https://github.com/twbs/bootstrap/issues/20280\n      var elOffset  = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset())\n      var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }\n      var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null\n  \n      return $.extend({}, elRect, scroll, outerDims, elOffset)\n    }\n  \n    Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {\n      return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :\n             placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :\n             placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :\n          /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }\n  \n    }\n  \n    Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {\n      var delta = { top: 0, left: 0 }\n      if (!this.$viewport) return delta\n  \n      var viewportPadding = this.options.viewport && this.options.viewport.padding || 0\n      var viewportDimensions = this.getPosition(this.$viewport)\n  \n      if (/right|left/.test(placement)) {\n        var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll\n        var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight\n        if (topEdgeOffset < viewportDimensions.top) { // top overflow\n          delta.top = viewportDimensions.top - topEdgeOffset\n        } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow\n          delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset\n        }\n      } else {\n        var leftEdgeOffset  = pos.left - viewportPadding\n        var rightEdgeOffset = pos.left + viewportPadding + actualWidth\n        if (leftEdgeOffset < viewportDimensions.left) { // left overflow\n          delta.left = viewportDimensions.left - leftEdgeOffset\n        } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow\n          delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset\n        }\n      }\n  \n      return delta\n    }\n  \n    Tooltip.prototype.getTitle = function () {\n      var title\n      var $e = this.$element\n      var o  = this.options\n  \n      title = $e.attr('data-original-title')\n        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)\n  \n      return title\n    }\n  \n    Tooltip.prototype.getUID = function (prefix) {\n      do prefix += ~~(Math.random() * 1000000)\n      while (document.getElementById(prefix))\n      return prefix\n    }\n  \n    Tooltip.prototype.tip = function () {\n      if (!this.$tip) {\n        this.$tip = $(this.options.template)\n        if (this.$tip.length != 1) {\n          throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')\n        }\n      }\n      return this.$tip\n    }\n  \n    Tooltip.prototype.arrow = function () {\n      return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))\n    }\n  \n    Tooltip.prototype.enable = function () {\n      this.enabled = true\n    }\n  \n    Tooltip.prototype.disable = function () {\n      this.enabled = false\n    }\n  \n    Tooltip.prototype.toggleEnabled = function () {\n      this.enabled = !this.enabled\n    }\n  \n    Tooltip.prototype.toggle = function (e) {\n      var self = this\n      if (e) {\n        self = $(e.currentTarget).data('bs.' + this.type)\n        if (!self) {\n          self = new this.constructor(e.currentTarget, this.getDelegateOptions())\n          $(e.currentTarget).data('bs.' + this.type, self)\n        }\n      }\n  \n      if (e) {\n        self.inState.click = !self.inState.click\n        if (self.isInStateTrue()) self.enter(self)\n        else self.leave(self)\n      } else {\n        self.tip().hasClass('in') ? self.leave(self) : self.enter(self)\n      }\n    }\n  \n    Tooltip.prototype.destroy = function () {\n      var that = this\n      clearTimeout(this.timeout)\n      this.hide(function () {\n        that.$element.off('.' + that.type).removeData('bs.' + that.type)\n        if (that.$tip) {\n          that.$tip.detach()\n        }\n        that.$tip = null\n        that.$arrow = null\n        that.$viewport = null\n        that.$element = null\n      })\n    }\n  \n  \n    // TOOLTIP PLUGIN DEFINITION\n    // =========================\n  \n    function Plugin(option) {\n      return this.each(function () {\n        var $this   = $(this)\n        var data    = $this.data('bs.tooltip')\n        var options = typeof option == 'object' && option\n  \n        if (!data && /destroy|hide/.test(option)) return\n        if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))\n        if (typeof option == 'string') data[option]()\n      })\n    }\n  \n    var old = $.fn.tooltip\n  \n    $.fn.tooltip             = Plugin\n    $.fn.tooltip.Constructor = Tooltip\n  \n  \n    // TOOLTIP NO CONFLICT\n    // ===================\n  \n    $.fn.tooltip.noConflict = function () {\n      $.fn.tooltip = old\n      return this\n    }\n  \n  }(jQuery);\n  \n  /* ========================================================================\n   * Bootstrap: popover.js v3.3.7\n   * http://getbootstrap.com/javascript/#popovers\n   * ========================================================================\n   * Copyright 2011-2016 Twitter, Inc.\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * ======================================================================== */\n  \n  \n  +function ($) {\n    'use strict';\n  \n    // POPOVER PUBLIC CLASS DEFINITION\n    // ===============================\n  \n    var Popover = function (element, options) {\n      this.init('popover', element, options)\n    }\n  \n    if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')\n  \n    Popover.VERSION  = '3.3.7'\n  \n    Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {\n      placement: 'right',\n      trigger: 'click',\n      content: '',\n      template: '<div class=\"popover\" role=\"tooltip\"><div class=\"arrow\"></div><h3 class=\"popover-title\"></h3><div class=\"popover-content\"></div></div>'\n    })\n  \n  \n    // NOTE: POPOVER EXTENDS tooltip.js\n    // ================================\n  \n    Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)\n  \n    Popover.prototype.constructor = Popover\n  \n    Popover.prototype.getDefaults = function () {\n      return Popover.DEFAULTS\n    }\n  \n    Popover.prototype.setContent = function () {\n      var $tip    = this.tip()\n      var title   = this.getTitle()\n      var content = this.getContent()\n  \n      $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)\n      $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events\n        this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'\n      ](content)\n  \n      $tip.removeClass('fade top bottom left right in')\n  \n      // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do\n      // this manually by checking the contents.\n      if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()\n    }\n  \n    Popover.prototype.hasContent = function () {\n      return this.getTitle() || this.getContent()\n    }\n  \n    Popover.prototype.getContent = function () {\n      var $e = this.$element\n      var o  = this.options\n  \n      return $e.attr('data-content')\n        || (typeof o.content == 'function' ?\n              o.content.call($e[0]) :\n              o.content)\n    }\n  \n    Popover.prototype.arrow = function () {\n      return (this.$arrow = this.$arrow || this.tip().find('.arrow'))\n    }\n  \n  \n    // POPOVER PLUGIN DEFINITION\n    // =========================\n  \n    function Plugin(option) {\n      return this.each(function () {\n        var $this   = $(this)\n        var data    = $this.data('bs.popover')\n        var options = typeof option == 'object' && option\n  \n        if (!data && /destroy|hide/.test(option)) return\n        if (!data) $this.data('bs.popover', (data = new Popover(this, options)))\n        if (typeof option == 'string') data[option]()\n      })\n    }\n  \n    var old = $.fn.popover\n  \n    $.fn.popover             = Plugin\n    $.fn.popover.Constructor = Popover\n  \n  \n    // POPOVER NO CONFLICT\n    // ===================\n  \n    $.fn.popover.noConflict = function () {\n      $.fn.popover = old\n      return this\n    }\n  \n  }(jQuery);\n  \n  /* ========================================================================\n   * Bootstrap: scrollspy.js v3.3.7\n   * http://getbootstrap.com/javascript/#scrollspy\n   * ========================================================================\n   * Copyright 2011-2016 Twitter, Inc.\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * ======================================================================== */\n  \n  \n  +function ($) {\n    'use strict';\n  \n    // SCROLLSPY CLASS DEFINITION\n    // ==========================\n  \n    function ScrollSpy(element, options) {\n      this.$body          = $(document.body)\n      this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)\n      this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)\n      this.selector       = (this.options.target || '') + ' .nav li > a'\n      this.offsets        = []\n      this.targets        = []\n      this.activeTarget   = null\n      this.scrollHeight   = 0\n  \n      this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))\n      this.refresh()\n      this.process()\n    }\n  \n    ScrollSpy.VERSION  = '3.3.7'\n  \n    ScrollSpy.DEFAULTS = {\n      offset: 10\n    }\n  \n    ScrollSpy.prototype.getScrollHeight = function () {\n      return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)\n    }\n  \n    ScrollSpy.prototype.refresh = function () {\n      var that          = this\n      var offsetMethod  = 'offset'\n      var offsetBase    = 0\n  \n      this.offsets      = []\n      this.targets      = []\n      this.scrollHeight = this.getScrollHeight()\n  \n      if (!$.isWindow(this.$scrollElement[0])) {\n        offsetMethod = 'position'\n        offsetBase   = this.$scrollElement.scrollTop()\n      }\n  \n      this.$body\n        .find(this.selector)\n        .map(function () {\n          var $el   = $(this)\n          var href  = $el.data('target') || $el.attr('href')\n          var $href = /^#./.test(href) && $(href)\n  \n          return ($href\n            && $href.length\n            && $href.is(':visible')\n            && [[$href[offsetMethod]().top + offsetBase, href]]) || null\n        })\n        .sort(function (a, b) { return a[0] - b[0] })\n        .each(function () {\n          that.offsets.push(this[0])\n          that.targets.push(this[1])\n        })\n    }\n  \n    ScrollSpy.prototype.process = function () {\n      var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset\n      var scrollHeight = this.getScrollHeight()\n      var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()\n      var offsets      = this.offsets\n      var targets      = this.targets\n      var activeTarget = this.activeTarget\n      var i\n  \n      if (this.scrollHeight != scrollHeight) {\n        this.refresh()\n      }\n  \n      if (scrollTop >= maxScroll) {\n        return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)\n      }\n  \n      if (activeTarget && scrollTop < offsets[0]) {\n        this.activeTarget = null\n        return this.clear()\n      }\n  \n      for (i = offsets.length; i--;) {\n        activeTarget != targets[i]\n          && scrollTop >= offsets[i]\n          && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])\n          && this.activate(targets[i])\n      }\n    }\n  \n    ScrollSpy.prototype.activate = function (target) {\n      this.activeTarget = target\n  \n      this.clear()\n  \n      var selector = this.selector +\n        '[data-target=\"' + target + '\"],' +\n        this.selector + '[href=\"' + target + '\"]'\n  \n      var active = $(selector)\n        .parents('li')\n        .addClass('active')\n  \n      if (active.parent('.dropdown-menu').length) {\n        active = active\n          .closest('li.dropdown')\n          .addClass('active')\n      }\n  \n      active.trigger('activate.bs.scrollspy')\n    }\n  \n    ScrollSpy.prototype.clear = function () {\n      $(this.selector)\n        .parentsUntil(this.options.target, '.active')\n        .removeClass('active')\n    }\n  \n  \n    // SCROLLSPY PLUGIN DEFINITION\n    // ===========================\n  \n    function Plugin(option) {\n      return this.each(function () {\n        var $this   = $(this)\n        var data    = $this.data('bs.scrollspy')\n        var options = typeof option == 'object' && option\n  \n        if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))\n        if (typeof option == 'string') data[option]()\n      })\n    }\n  \n    var old = $.fn.scrollspy\n  \n    $.fn.scrollspy             = Plugin\n    $.fn.scrollspy.Constructor = ScrollSpy\n  \n  \n    // SCROLLSPY NO CONFLICT\n    // =====================\n  \n    $.fn.scrollspy.noConflict = function () {\n      $.fn.scrollspy = old\n      return this\n    }\n  \n  \n    // SCROLLSPY DATA-API\n    // ==================\n  \n    $(window).on('load.bs.scrollspy.data-api', function () {\n      $('[data-spy=\"scroll\"]').each(function () {\n        var $spy = $(this)\n        Plugin.call($spy, $spy.data())\n      })\n    })\n  \n  }(jQuery);\n  \n  /* ========================================================================\n   * Bootstrap: tab.js v3.3.7\n   * http://getbootstrap.com/javascript/#tabs\n   * ========================================================================\n   * Copyright 2011-2016 Twitter, Inc.\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * ======================================================================== */\n  \n  \n  +function ($) {\n    'use strict';\n  \n    // TAB CLASS DEFINITION\n    // ====================\n  \n    var Tab = function (element) {\n      // jscs:disable requireDollarBeforejQueryAssignment\n      this.element = $(element)\n      // jscs:enable requireDollarBeforejQueryAssignment\n    }\n  \n    Tab.VERSION = '3.3.7'\n  \n    Tab.TRANSITION_DURATION = 150\n  \n    Tab.prototype.show = function () {\n      var $this    = this.element\n      var $ul      = $this.closest('ul:not(.dropdown-menu)')\n      var selector = $this.data('target')\n  \n      if (!selector) {\n        selector = $this.attr('href')\n        selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n      }\n  \n      if ($this.parent('li').hasClass('active')) return\n  \n      var $previous = $ul.find('.active:last a')\n      var hideEvent = $.Event('hide.bs.tab', {\n        relatedTarget: $this[0]\n      })\n      var showEvent = $.Event('show.bs.tab', {\n        relatedTarget: $previous[0]\n      })\n  \n      $previous.trigger(hideEvent)\n      $this.trigger(showEvent)\n  \n      if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return\n  \n      var $target = $(selector)\n  \n      this.activate($this.closest('li'), $ul)\n      this.activate($target, $target.parent(), function () {\n        $previous.trigger({\n          type: 'hidden.bs.tab',\n          relatedTarget: $this[0]\n        })\n        $this.trigger({\n          type: 'shown.bs.tab',\n          relatedTarget: $previous[0]\n        })\n      })\n    }\n  \n    Tab.prototype.activate = function (element, container, callback) {\n      var $active    = container.find('> .active')\n      var transition = callback\n        && $.support.transition\n        && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)\n  \n      function next() {\n        $active\n          .removeClass('active')\n          .find('> .dropdown-menu > .active')\n            .removeClass('active')\n          .end()\n          .find('[data-toggle=\"tab\"]')\n            .attr('aria-expanded', false)\n  \n        element\n          .addClass('active')\n          .find('[data-toggle=\"tab\"]')\n            .attr('aria-expanded', true)\n  \n        if (transition) {\n          element[0].offsetWidth // reflow for transition\n          element.addClass('in')\n        } else {\n          element.removeClass('fade')\n        }\n  \n        if (element.parent('.dropdown-menu').length) {\n          element\n            .closest('li.dropdown')\n              .addClass('active')\n            .end()\n            .find('[data-toggle=\"tab\"]')\n              .attr('aria-expanded', true)\n        }\n  \n        callback && callback()\n      }\n  \n      $active.length && transition ?\n        $active\n          .one('bsTransitionEnd', next)\n          .emulateTransitionEnd(Tab.TRANSITION_DURATION) :\n        next()\n  \n      $active.removeClass('in')\n    }\n  \n  \n    // TAB PLUGIN DEFINITION\n    // =====================\n  \n    function Plugin(option) {\n      return this.each(function () {\n        var $this = $(this)\n        var data  = $this.data('bs.tab')\n  \n        if (!data) $this.data('bs.tab', (data = new Tab(this)))\n        if (typeof option == 'string') data[option]()\n      })\n    }\n  \n    var old = $.fn.tab\n  \n    $.fn.tab             = Plugin\n    $.fn.tab.Constructor = Tab\n  \n  \n    // TAB NO CONFLICT\n    // ===============\n  \n    $.fn.tab.noConflict = function () {\n      $.fn.tab = old\n      return this\n    }\n  \n  \n    // TAB DATA-API\n    // ============\n  \n    var clickHandler = function (e) {\n      e.preventDefault()\n      Plugin.call($(this), 'show')\n    }\n  \n    $(document)\n      .on('click.bs.tab.data-api', '[data-toggle=\"tab\"]', clickHandler)\n      .on('click.bs.tab.data-api', '[data-toggle=\"pill\"]', clickHandler)\n  \n  }(jQuery);\n  \n  /* ========================================================================\n   * Bootstrap: affix.js v3.3.7\n   * http://getbootstrap.com/javascript/#affix\n   * ========================================================================\n   * Copyright 2011-2016 Twitter, Inc.\n   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n   * ======================================================================== */\n  \n  \n  +function ($) {\n    'use strict';\n  \n    // AFFIX CLASS DEFINITION\n    // ======================\n  \n    var Affix = function (element, options) {\n      this.options = $.extend({}, Affix.DEFAULTS, options)\n  \n      this.$target = $(this.options.target)\n        .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))\n        .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))\n  \n      this.$element     = $(element)\n      this.affixed      = null\n      this.unpin        = null\n      this.pinnedOffset = null\n  \n      this.checkPosition()\n    }\n  \n    Affix.VERSION  = '3.3.7'\n  \n    Affix.RESET    = 'affix affix-top affix-bottom'\n  \n    Affix.DEFAULTS = {\n      offset: 0,\n      target: window\n    }\n  \n    Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {\n      var scrollTop    = this.$target.scrollTop()\n      var position     = this.$element.offset()\n      var targetHeight = this.$target.height()\n  \n      if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false\n  \n      if (this.affixed == 'bottom') {\n        if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'\n        return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'\n      }\n  \n      var initializing   = this.affixed == null\n      var colliderTop    = initializing ? scrollTop : position.top\n      var colliderHeight = initializing ? targetHeight : height\n  \n      if (offsetTop != null && scrollTop <= offsetTop) return 'top'\n      if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'\n  \n      return false\n    }\n  \n    Affix.prototype.getPinnedOffset = function () {\n      if (this.pinnedOffset) return this.pinnedOffset\n      this.$element.removeClass(Affix.RESET).addClass('affix')\n      var scrollTop = this.$target.scrollTop()\n      var position  = this.$element.offset()\n      return (this.pinnedOffset = position.top - scrollTop)\n    }\n  \n    Affix.prototype.checkPositionWithEventLoop = function () {\n      setTimeout($.proxy(this.checkPosition, this), 1)\n    }\n  \n    Affix.prototype.checkPosition = function () {\n      if (!this.$element.is(':visible')) return\n  \n      var height       = this.$element.height()\n      var offset       = this.options.offset\n      var offsetTop    = offset.top\n      var offsetBottom = offset.bottom\n      var scrollHeight = Math.max($(document).height(), $(document.body).height())\n  \n      if (typeof offset != 'object')         offsetBottom = offsetTop = offset\n      if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)\n      if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)\n  \n      var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)\n  \n      if (this.affixed != affix) {\n        if (this.unpin != null) this.$element.css('top', '')\n  \n        var affixType = 'affix' + (affix ? '-' + affix : '')\n        var e         = $.Event(affixType + '.bs.affix')\n  \n        this.$element.trigger(e)\n  \n        if (e.isDefaultPrevented()) return\n  \n        this.affixed = affix\n        this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null\n  \n        this.$element\n          .removeClass(Affix.RESET)\n          .addClass(affixType)\n          .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')\n      }\n  \n      if (affix == 'bottom') {\n        this.$element.offset({\n          top: scrollHeight - height - offsetBottom\n        })\n      }\n    }\n  \n  \n    // AFFIX PLUGIN DEFINITION\n    // =======================\n  \n    function Plugin(option) {\n      return this.each(function () {\n        var $this   = $(this)\n        var data    = $this.data('bs.affix')\n        var options = typeof option == 'object' && option\n  \n        if (!data) $this.data('bs.affix', (data = new Affix(this, options)))\n        if (typeof option == 'string') data[option]()\n      })\n    }\n  \n    var old = $.fn.affix\n  \n    $.fn.affix             = Plugin\n    $.fn.affix.Constructor = Affix\n  \n  \n    // AFFIX NO CONFLICT\n    // =================\n  \n    $.fn.affix.noConflict = function () {\n      $.fn.affix = old\n      return this\n    }\n  \n  \n    // AFFIX DATA-API\n    // ==============\n  \n    $(window).on('load', function () {\n      $('[data-spy=\"affix\"]').each(function () {\n        var $spy = $(this)\n        var data = $spy.data()\n  \n        data.offset = data.offset || {}\n  \n        if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom\n        if (data.offsetTop    != null) data.offset.top    = data.offsetTop\n  \n        Plugin.call($spy, data)\n      })\n    })\n  \n  }(jQuery);"
  },
  {
    "path": "static/js/canvas-nest.js",
    "content": "!function(){\"use strict\";function e(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,\"default\")?e.default:e}function t(e,t){return e(t={exports:{}},t.exports),t.exports}var n=t(function(e,t){Object.defineProperty(t,\"__esModule\",{value:!0});var n=1;t.default=function(){return\"\"+n++},e.exports=t.default});e(n);var o=t(function(e,t){Object.defineProperty(t,\"__esModule\",{value:!0}),t.default=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:30,n=null;return function(){for(var o=this,i=arguments.length,r=Array(i),a=0;a<i;a++)r[a]=arguments[a];clearTimeout(n),n=setTimeout(function(){e.apply(o,r)},t)}},e.exports=t.default});e(o);var i=t(function(e,t){Object.defineProperty(t,\"__esModule\",{value:!0});t.SizeSensorId=\"size-sensor-id\",t.SensorStyle=\"display:block;position:absolute;top:0;left:0;height:100%;width:100%;overflow:hidden;pointer-events:none;z-index:-1;opacity:0\",t.SensorClassName=\"size-sensor-object\"});e(i);i.SizeSensorId,i.SensorStyle,i.SensorClassName;var r=t(function(e,t){Object.defineProperty(t,\"__esModule\",{value:!0}),t.createSensor=void 0;var n,r=(n=o)&&n.__esModule?n:{default:n};t.createSensor=function(e){var t=void 0,n=[],o=(0,r.default)(function(){n.forEach(function(t){t(e)})}),a=function(){t&&t.parentNode&&(t.contentDocument.defaultView.removeEventListener(\"resize\",o),t.parentNode.removeChild(t),t=void 0,n=[])};return{element:e,bind:function(r){t||(t=function(){\"static\"===getComputedStyle(e).position&&(e.style.position=\"relative\");var t=document.createElement(\"object\");return t.onload=function(){t.contentDocument.defaultView.addEventListener(\"resize\",o),o()},t.setAttribute(\"style\",i.SensorStyle),t.setAttribute(\"class\",i.SensorClassName),t.type=\"text/html\",e.appendChild(t),t.data=\"about:blank\",t}()),-1===n.indexOf(r)&&n.push(r)},destroy:a,unbind:function(e){var o=n.indexOf(e);-1!==o&&n.splice(o,1),0===n.length&&t&&a()}}}});e(r);r.createSensor;var a=t(function(e,t){Object.defineProperty(t,\"__esModule\",{value:!0}),t.createSensor=void 0;var n,i=(n=o)&&n.__esModule?n:{default:n};t.createSensor=function(e){var t=void 0,n=[],o=(0,i.default)(function(){n.forEach(function(t){t(e)})}),r=function(){t.disconnect(),n=[],t=void 0};return{element:e,bind:function(i){t||(t=function(){var t=new ResizeObserver(o);return t.observe(e),o(),t}()),-1===n.indexOf(i)&&n.push(i)},destroy:r,unbind:function(e){var o=n.indexOf(e);-1!==o&&n.splice(o,1),0===n.length&&t&&r()}}}});e(a);a.createSensor;var s=t(function(e,t){Object.defineProperty(t,\"__esModule\",{value:!0}),t.createSensor=void 0;t.createSensor=\"undefined\"!=typeof ResizeObserver?a.createSensor:r.createSensor});e(s);s.createSensor;var u=t(function(e,t){Object.defineProperty(t,\"__esModule\",{value:!0}),t.removeSensor=t.getSensor=void 0;var o,r=(o=n)&&o.__esModule?o:{default:o};var a={};t.getSensor=function(e){var t=e.getAttribute(i.SizeSensorId);if(t&&a[t])return a[t];var n=(0,r.default)();e.setAttribute(i.SizeSensorId,n);var o=(0,s.createSensor)(e);return a[n]=o,o},t.removeSensor=function(e){var t=e.element.getAttribute(i.SizeSensorId);e.element.removeAttribute(i.SizeSensorId),e.destroy(),t&&a[t]&&delete a[t]}});e(u);u.removeSensor,u.getSensor;var c=t(function(e,t){Object.defineProperty(t,\"__esModule\",{value:!0}),t.clear=t.bind=void 0;t.bind=function(e,t){var n=(0,u.getSensor)(e);return n.bind(t),function(){n.unbind(t)}},t.clear=function(e){var t=(0,u.getSensor)(e);(0,u.removeSensor)(t)}});e(c);var l=c.clear,d=c.bind,v=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame||function(e){return window.setTimeout(e,1e3/60)},f=window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.msCancelAnimationFrame||window.oCancelAnimationFrame||window.clearTimeout,m=function(e){return new Array(e).fill(0).map(function(e,t){return t})},h=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},p=function(){function e(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,\"value\"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(t,n,o){return n&&e(t.prototype,n),o&&e(t,o),t}}();var y=function(){function e(t,n){var o=this;!function(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}(this,e),this.randomPoints=function(){return m(o.c.count).map(function(){return{x:Math.random()*o.canvas.width,y:Math.random()*o.canvas.height,xa:2*Math.random()-1,ya:2*Math.random()-1,max:6e3}})},this.el=t,this.c=h({zIndex:-1,opacity:.5,color:\"0,0,0\",pointColor:\"0,0,0\",count:99},n),this.canvas=this.newCanvas(),this.context=this.canvas.getContext(\"2d\"),this.points=this.randomPoints(),this.current={x:null,y:null,max:2e4},this.all=this.points.concat([this.current]),this.bindEvent(),this.requestFrame(this.drawCanvas)}return p(e,[{key:\"bindEvent\",value:function(){var e=this;d(this.el,function(){e.canvas.width=e.el.clientWidth,e.canvas.height=e.el.clientHeight}),this.onmousemove=window.onmousemove,window.onmousemove=function(t){e.current.x=t.clientX-e.el.offsetLeft+document.scrollingElement.scrollLeft,e.current.y=t.clientY-e.el.offsetTop+document.scrollingElement.scrollTop,e.onmousemove&&e.onmousemove(t)},this.onmouseout=window.onmouseout,window.onmouseout=function(){e.current.x=null,e.current.y=null,e.onmouseout&&e.onmouseout()}}},{key:\"newCanvas\",value:function(){\"static\"===getComputedStyle(this.el).position&&(this.el.style.position=\"relative\");var e,t=document.createElement(\"canvas\");return t.style.cssText=\"display:block;position:absolute;top:0;left:0;height:100%;width:100%;overflow:hidden;pointer-events:none;z-index:\"+(e=this.c).zIndex+\";opacity:\"+e.opacity,t.width=this.el.clientWidth,t.height=this.el.clientHeight,this.el.appendChild(t),t}},{key:\"requestFrame\",value:function(e){var t=this;this.tid=v(function(){return e.call(t)})}},{key:\"drawCanvas\",value:function(){var e=this,t=this.context,n=this.canvas.width,o=this.canvas.height,i=this.current,r=this.points,a=this.all;t.clearRect(0,0,n,o);var s=void 0,u=void 0,c=void 0,l=void 0,d=void 0,v=void 0;r.forEach(function(r,f){for(r.x+=r.xa,r.y+=r.ya,r.xa*=r.x>n||r.x<0?-1:1,r.ya*=r.y>o||r.y<0?-1:1,t.fillStyle=\"rgba(\"+e.c.pointColor+\")\",t.fillRect(r.x-.5,r.y-.5,1,1),u=f+1;u<a.length;u++)null!==(s=a[u]).x&&null!==s.y&&(l=r.x-s.x,d=r.y-s.y,(v=l*l+d*d)<s.max&&(s===i&&v>=s.max/2&&(r.x-=.03*l,r.y-=.03*d),c=(s.max-v)/s.max,t.beginPath(),t.lineWidth=c/2,t.strokeStyle=\"rgba(\"+e.c.color+\",\"+(c+.2)+\")\",t.moveTo(r.x,r.y),t.lineTo(s.x,s.y),t.stroke()))}),this.requestFrame(this.drawCanvas)}},{key:\"destroy\",value:function(){l(this.el),window.onmousemove=this.onmousemove,window.onmouseout=this.onmouseout,f(this.tid),this.canvas.parentNode.removeChild(this.canvas)}}]),e}();y.version=\"2.0.4\";var w,b;new y(document.body,(w=document.getElementsByTagName(\"script\"),{zIndex:(b=w[w.length-1]).getAttribute(\"zIndex\"),opacity:b.getAttribute(\"opacity\"),color:b.getAttribute(\"color\"),pointColor:b.getAttribute(\"pointColor\"),count:Number(b.getAttribute(\"count\"))||99}))}();\n"
  },
  {
    "path": "static/js/dashboard_echarts.js",
    "content": "var year = localStorage.getItem(\"selected_year\");\nvar quarter = localStorage.getItem(\"selected_quarter\");\nvar month = localStorage.getItem(\"selected_month\");\nvar day = localStorage.getItem(\"selected_day\");\n\n\n//数据质量总览\n$.ajax({\n    type : \"GET\",\n    async : false,\n    url : \"../../api/dashboard/data_overview_total\",    \n    data: {\n        'year': year,\n        'quarter': quarter,\n        'month': month,\n        'day': day\n    },\n    dataType : \"json\",\n    success : function(result) {\n        all_cnt = document.getElementById(\"all_cnt\");\n        all_cnt.innerHTML = result.all_cnt;\n        problem_cnt = document.getElementById(\"problem_cnt\");\n        problem_cnt.innerHTML = result.problem_cnt;\n        problem_per = document.getElementById(\"problem_per\");\n        problem_per.innerHTML = result.problem_per + '%';\n    },\n})\n\n\n// 数据质量问题概况\nfunction InsertTable(company, data){\n    // 填充各公司数据概况<table>\n    let table = document.getElementById(\"overview_\"+company);\n    let html = \"\";\n    html += \"<td>检核数据量</td>\";\n    html += \"<td>\" + data[1] + \"</td>\";\n    html += '<td rowspan=\"3\" id=\"overview_chart_' + company + '\", style=\"weight:auto; height: auto;\"></td>';\n    html += \"</tr>\"\n    html += \"<tr>\";\n    html += \"<td>问题数据量</td>\";\n    html += '<td style=\"color:red;\">' + data[2] + \"</td>\";\n    html += \"</tr>\"\n    html += \"<tr>\";\n    html += \"<td>问题占比</td>\";\n    html += '<td>' + data[3] + '%' + \"</td>\";\n    html += \"</tr>\"\n    table.innerHTML = html;\n}\n\nfunction GetCompanyTrend(company, year, month, day, chart_obj){\n    $.ajax({\n        type : \"GET\",\n        async : true,\n        url : \"../../api/dashboard/data_overview_company_trend\",\n        data: {\n            'company': company,\n            'year': year,\n            'month': month,\n            'day': day\n        },\n        dataType : \"json\",\n        success : function(result) {\n            chart_obj.setOption({\n                series:[{data: result}]\n            });\n        },\n    })\n}\n\n$.ajax({\n    type : \"GET\",\n    async : false,\n    url : \"../../api/dashboard/data_overview_company\",    \n    data: {\n        'year': year,\n        'quarter': quarter,\n        'month': month,\n        'day': day\n    },\n    dataType : \"json\",\n    success : function(result) {\n        let company = [\"xt\", \"zc\", \"db\", \"jk\", \"jj1\", \"jj2\", \"jz\"]\n        for(let i in company){\n            InsertTable(company[i], result[i]);\n        }\n\n        var option = {\n            grid: {\n                left: '4%',\n                right: '4%',\n                bottom: '6%',\n                top: '6%',\n                containLabel: true\n            },\n            xAxis: {\n                data: [],\n            },\n            yAxis: {},\n            series: [{\n                name: '问题占比',\n                type: 'line',\n                data: []\n            }]\n        };\n        var CompanyChart1 = echarts.init(document.getElementById('overview_chart_xt'));\n        var CompanyChart2 = echarts.init(document.getElementById('overview_chart_zc'));\n        var CompanyChart3 = echarts.init(document.getElementById('overview_chart_db'));\n        var CompanyChart4 = echarts.init(document.getElementById('overview_chart_jk'));\n        var CompanyChart5 = echarts.init(document.getElementById('overview_chart_jj1'));\n        var CompanyChart6 = echarts.init(document.getElementById('overview_chart_jj2'));\n        var CompanyChart7 = echarts.init(document.getElementById('overview_chart_jz'));\n        CompanyChart1.setOption(option);\n        CompanyChart2.setOption(option);\n        CompanyChart3.setOption(option);\n        CompanyChart4.setOption(option);\n        CompanyChart5.setOption(option);\n        CompanyChart6.setOption(option);\n        CompanyChart7.setOption(option);\n        \n        let objs = [CompanyChart1, CompanyChart2, CompanyChart3, CompanyChart4, CompanyChart5, CompanyChart6, CompanyChart7]\n        for(let i in objs){\n            GetCompanyTrend(company[i], year, month, day, objs[i]);\n        }\n    },\n})\n\n\n// echarts部分\nvar color = [\n\"#60acfc\",\n\"#32d3eb\",\n\"#5bc49f\",\n\"#feb64d\",\n\"#ff7c7c\",\n\"#9287e7\",\n\"#009688\"] ;\n\nvar myChart1 = echarts.init(document.getElementById('echarts1'));\nvar option = {\n    color : '#ff7c7c',\n    title : {\n        text: '各公司平均问题占比（%）',\n        subtext: '风险集市相关',\n        x:'left'\n    },\n    tooltip : {\n        trigger: 'axis',\n        axisPointer : {\n            type : 'shadow'\n        }\n    },\n    toolbox: {\n        show : true,\n        feature : {\n            mark : {show: true},\n            magicType: {show: true, type: ['line', 'bar']},\n            restore : {show: true},\n            saveAsImage : {show: true}\n        }\n    },\n    legend: {\n        x: 'left',\n        top: '15%',\n    },\n    dataset: {\n        source: []\n    },\n    xAxis: [\n        {type: 'category', gridIndex: 0},\n    ],\n    yAxis: [\n        {gridIndex: 0},\n    ],\n    series: [\n        {type: 'bar', seriesLayoutBy: 'row'},\n        {type: 'bar', seriesLayoutBy: 'row'},\n        {type: 'bar', seriesLayoutBy: 'row'},\n        {type: 'bar', seriesLayoutBy: 'row'},\n        {type: 'bar', seriesLayoutBy: 'row'},\n        {type: 'bar', seriesLayoutBy: 'row'},\n        {type: 'bar', seriesLayoutBy: 'row'},\n    ],\n    grid:{\n        top: 100,\n    },\n    dataZoom: [{\n        show: true,\n        bottom: 0,\n        start: 15,\n        end: 75,\n    },{\n        type: 'inside',\n        start: 94,\n        end: 100\n    }],\n};\nmyChart1.setOption(option);\nmyChart1.showLoading();\n\n$.ajax({\n    type : \"GET\",\n    async : false,\n    url : \"../../api/dashboard/avg_problem_percentage\",    \n    data: {},\n    dataType : \"json\",\n    success : function(result) {\n        myChart1.hideLoading();              //隐藏加载动画\n        myChart1.setOption({                 //加载数据图表\n        //渲染echarts\n            dataset: {\n                source: result\n            },\n        });\n    },\n})\n\nvar myChart2 = echarts.init(document.getElementById('echarts2'));\nvar option = {\n    color: color,\n    title : {\n        text: '各公司同类问题Top 5统计',\n        subtext: year + '-' + month + '-' + day +'（风险集市相关）',\n        x:'center'\n    },\n    tooltip : {\n        trigger: 'item',\n    },\n    series : [{\n        type: 'pie',\n        radius : '55%',\n        center: ['50%', '55%'],\n        data: [],\n        itemStyle: {\n            emphasis: {\n                shadowBlur: 10,\n                shadowOffsetX: 0,\n                shadowColor: 'rgba(0, 0, 0, 0.5)'\n            }\n        }\n    }]\n};\nmyChart2.setOption(option);\nmyChart2.showLoading();\n\n$.ajax({\n    type : \"GET\",\n    async : false,\n    url : \"../../api/dashboard/same_problem_top5\",    \n    data: {\n        'year': year,\n        'quarter': quarter,\n        'month': month,\n        'day': day\n    },\n    dataType : \"json\",\n    success : function(result) {\n        var names = result.name || []\n        var values = result.value || []\n        var data = []\n        for(var i=0;i<names.length;i++){\n            data.push({ name: names[i], value: values[i] })\n        }\n        myChart2.hideLoading();\n        myChart2.setOption({\n            series : [{\n                data: data,\n            }]\n        });\n    },\n})\n\n\nvar myChart3 = echarts.init(document.getElementById('echarts3'));\nvar option = {\n    color: color,\n    title : {\n        text: '各公司数据量占比',\n        subtext: year + '-' + month + '-' + day +'（风险集市相关）',\n        x:'left'\n    },\n    tooltip: {\n        trigger: 'item',\n        formatter: \"{a} <br/>{b}: {c} ({d}%)\"\n    },\n    legend: {\n        orient: 'vertical',\n        x: 'left',\n        y: 'bottom',\n        data:['信托','资产','担保','金科','基金1','基金2','金租']\n    },\n    series: [\n        {\n            name:'数据库来源',\n            type:'pie',\n            selectedMode: 'single',\n            radius: [0, '30%'],\n            center: ['55%', '55%'],\n            label: {\n                normal: {\n                    position: 'inner'\n                }\n            },\n            labelLine: {\n                normal: {\n                    show: false\n                }\n            },\n            data: []\n        },\n        {\n            name:'数据量占比',\n            type:'pie',\n            radius: ['40%', '55%'],\n            center: ['55%', '55%'],\n            label: {\n                normal: {\n                    formatter: '{a|{a}}{abg|}\\n{hr|}\\n  {b|{b}：}{c}  {per|{d}%}  ',\n                    backgroundColor: '#eee',\n                    borderColor: '#aaa',\n                    borderWidth: 1,\n                    borderRadius: 4,\n                    rich: {\n                        a: {\n                            color: '#999',\n                            lineHeight: 22,\n                            align: 'center'\n                        },\n                        hr: {\n                            borderColor: '#aaa',\n                            width: '100%',\n                            borderWidth: 0.5,\n                            height: 0\n                        },\n                        b: {\n                            fontSize: 16,\n                            lineHeight: 33\n                        },\n                        per: {\n                            color: '#eee',\n                            backgroundColor: '#334455',\n                            padding: [2, 4],\n                            borderRadius: 2\n                        }\n                    }\n                }\n            },\n            data:[]\n        }\n    ]\n};\nmyChart3.setOption(option);\nmyChart3.showLoading();\n\n$.ajax({\n    type : \"GET\",\n    async : false,\n    url : \"../../api/dashboard/subcompany_data_percentage\",    \n    data: {\n        'year': year,\n        'quarter': quarter,\n        'month': month,\n        'day': day\n    },\n    dataType : \"json\",\n    success : function(result) {\n        myChart3.setOption({\n            series: [{},\n            {\n                data: result\n            }]\n        });\n    },\n})\n\n$.ajax({\n    type : \"GET\",\n    async : false,\n    url : \"../../api/dashboard/count_db_rows\",    \n    data: {\n        'year': year,\n        'quarter': quarter,\n        'month': month,\n        'day': day\n    },\n    dataType : \"json\",\n    success : function(result) {\n        myChart3.hideLoading();\n        myChart3.setOption({\n            series: [{\n                data: result\n            }]\n        });\n    },\n})\n\n\n\nvar myChart4 = echarts.init(document.getElementById('echarts4'));\nvar option = {\n    color : ['#FFC000','#70AD47','#5B9BD5'],\n    title : {\n        text: '需求改造进度',\n        subtext: year + 'Q' + quarter +'风险集市相关',\n        x:'left'\n    },\n    tooltip : {\n        trigger: 'axis',\n        axisPointer : {            // 坐标轴指示器，坐标轴触发有效\n            type : 'shadow'        // 默认为直线，可选为：'line' | 'shadow'\n        }\n    },\n    legend: {\n        data: ['未完成','已完成','无需改造']\n    },\n    grid: {\n        left: '3%',\n        right: '4%',\n        bottom: '3%',\n        containLabel: true\n    },\n    xAxis:  {\n        type: 'value'\n    },\n    yAxis: {\n        type: 'category',\n        data: []\n    },\n    series: [\n        {\n            name: '未完成',\n            type: 'bar',\n            stack: '总量',\n            data: []\n        },\n        {\n            name: '已完成',\n            type: 'bar',\n            stack: '总量',\n            data: []\n        },\n        {\n            name: '无需改造',\n            type: 'bar',\n            stack: '总量',\n            data: []\n        },\n    ]\n};\n\nmyChart4.setOption(option);\nmyChart4.showLoading();\n\n// 请求接口数据-填充[问题数据统计]\n$.ajax({\n    type : \"get\",\n    async : false,\n    url : \"../../static/resource/demand.json\",    \n    data: {},\n    dataType : \"json\",\n    success : function(result) {\n        if (result) {\n            //去重获取公司名\n            var company = [];\n            for(var i=1;i<result.length;i++){\n                if (company.indexOf(result[i][1])==-1){\n                    company.push(result[i][1]);\n                }\n            }\n\n            //获取当前季度的列号\n            var unfinished_list  = [];\n            var finished_list    = [];\n            var noneed_list      = [];\n            for(var i=5;i<result[0].length;i++){\n                if (result[0][i].substr(0,6) == '{{ quarter }}'){\n                    var quarter = i;\n                    break;\n                }\n            }\n            //改造进度计数\n            for(var i=0;i<company.length;i++){\n                var unfinished_count = 0;\n                var finished_count   = 0;\n                var noneed_count     = 0;\n                for (var t=1;t<result.length;t++){\n                    if (result[t][1] != company[i]){\n                        continue;\n                    }\n                    else{\n                        if (result[t][quarter] == '进行中' || result[t][quarter] == '未完成' || result[t][quarter] == '未开展'){\n                            unfinished_count++;\n                        }\n                        else if (result[t][quarter] == '完成'){\n                            finished_count++;\n                        }\n                        else {\n                            noneed_count++;\n                        }\n                    }\n                }\n                unfinished_list.push(unfinished_count);\n                finished_list.push(finished_count);\n                noneed_list.push(noneed_count);\n            }\n\n            myChart4.hideLoading();              //隐藏加载动画\n            myChart4.setOption({                 //加载数据图表\n            //渲染echarts\n                yAxis: {\n                    type: 'category',\n                    data: company\n                },\n                series: [\n                    {\n                        data: unfinished_list\n                    },\n                    {\n                        data: finished_list\n                    },\n                    {\n                        data: noneed_list\n                    },\n                ]\n            });\n\n            //渲染table\n            var html = \"<thead><th>公司</th><th>未完成需求数</th><th>已完成需求数</th><th>完成率</th></thead><tbody>\";\n            var total_unfinished = 0;\n            var total_finished   = 0;\n            var total_noneed     = 0;\n            for(var i=0;i<company.length;i++){\n                var unfinished = unfinished_list[i]\n                var finished   = finished_list[i]\n                var noneed     = noneed_list[i]\n                var finished_per = (finished+noneed)/(finished+noneed+unfinished)*100\n                total_unfinished += unfinished;\n                total_finished   += finished;\n                total_noneed     += noneed;\n                total_finished_per = (total_finished+total_noneed)/(total_finished+total_noneed+total_unfinished)*100\n                html += \"<tr>\";\n                html += \"<td>\" + company[i] + \"</td>\";\n                html += \"<td style=\\\"color:red;\\\">\" + unfinished + \"</td>\";\n                html += \"<td style=\\\"color:green;\\\">\" + (finished+noneed) + \"</td>\";\n                html += \"<td>\" + finished_per.toFixed(2) + \"%</td>\";\n                html += \"</tr>\";\n            }\n            html += \"<tr style=\\\"font-weight: 600;\\\"><td>集团合计</td>\"\n            html += \"<td style=\\\"color:red;\\\">\" + total_unfinished + \"</td>\";\n            html += \"<td style=\\\"color:green;\\\">\" + (total_finished+total_noneed) + \"</td>\";\n            html += \"<td>\" + total_finished_per.toFixed(2) + \"%</td></tr>\";\n            html += \"</tbody>\";\n            document.getElementById(\"demand_table\").innerHTML = html;\n        }\n    },\n    error : function(errorMsg) {\n        console.log(errorMsg);\n    }\n})\n\n//集团总问题占比\nvar myChart5 = echarts.init(document.getElementById('echarts5'));\nvar option = {\n    color: \"#4CAF50\",\n    title : {\n        text: '集团总问题占比（%）',\n        subtext: '风险集市相关',\n        x:'left'\n    },\n    xAxis: {\n        type: 'category',\n        data: []\n    },\n    yAxis: {\n        type: 'value'\n    },\n    series: [{\n        data: [],\n        type: 'line',\n        markPoint: {\n            data: [\n                {type: 'max', name: '最大值'},\n                {type: 'min', name: '最小值'}\n            ]\n        },\n    }],\n    toolbox: {\n        show : true,\n        feature : {\n            mark : {show: true},\n            magicType: {show: true, type: ['line', 'bar']},\n            restore : {show: true},\n            saveAsImage : {show: true}\n        }\n    },\n    dataZoom: [{\n        show: true,\n        bottom: 0,\n        start: 0,\n        end: 100,\n        width: '70%',\n        x: '15%'\n    },\n    {\n        type: 'inside',\n        start: 94,\n        end: 100\n    },\n    ],\n};\nmyChart5.setOption(option);\nmyChart5.showLoading();\n\n$.ajax({\n    type : \"GET\",\n    async : false,\n    url : \"../../api/dashboard/total_trend\",    \n    data: {},\n    dataType : \"json\",\n    success : function(result) {\n        myChart5.hideLoading();\n        myChart5.setOption({\n            xAxis: {\n                data: result.datatime\n            },\n            series: [{\n                data: result.value,\n            }]\n        });\n    },\n})\n\n//根据窗口缩放动态调整echarts大小\n$('.chart').resize(function(){\n    myChart1.resize();\n    myChart2.resize();\n    myChart3.resize();\n    myChart4.resize();\n});"
  },
  {
    "path": "static/js/get_quality_detail.js",
    "content": "var year = localStorage.getItem(\"selected_year\");\nvar quarter = localStorage.getItem(\"selected_quarter\");\nvar month = localStorage.getItem(\"selected_month\");\nvar day = localStorage.getItem(\"selected_day\");\n\n//报告标题\nvar obj = document.getElementById(\"report_title\");\nobj.innerHTML = \"粤财控股\"+ year + 'Q' + quarter +\"数据质量报告(\" + year + '-' + month + '-' + day + \")\";\n\n//总结概述\n$.ajax({\n    type : \"GET\",\n    async : false,\n    url : \"../../api/dashboard/data_overview_total\",    \n    data: {\n        'year': year,\n        'quarter': quarter,\n        'month': month,\n        'day': day\n    },\n    dataType : \"json\",\n    success : function(result) {\n        let text = document.getElementById(\"summary_1\");\n        let html = \"&nbsp;&nbsp;本季度对对信托、资产、再担保、金科、基金创投、中银粤财、金租七个公司风险集市相关共\" + result.all_cnt + \"条数据进行检查，合计问题数\" + result.problem_cnt + \"，问题占比\"+ result.problem_per +\"%。\";\n        html += '<font style=\"font-style:italic;size:21.3px;font-family:SimSun;color:rgb(91, 155, 213);text-decoration:underline;\">补充环比统计和需求完成情况统计</font>';\n        text.innerHTML = html;\n    },\n})\n\n//各公司风险集市相关数据质量概况\n$.ajax({\n    type : \"GET\",\n    async : false,\n    url : \"../../api/dashboard/data_overview_company\",    \n    data: {\n        'year': year,\n        'quarter': quarter,\n        'month': month,\n        'day': day\n    },\n    dataType : \"json\",\n    success : function(result) {\n        let text = document.getElementById(\"summary_2\");\n        var html = \"\";\n        for (i of result){\n            html += \"<tr>\";\n            html += \"<td>\"+ year + 'Q' + quarter +\"</td>\";\n            html += \"<td>\"+ i[0] +\"</td>\";\n            html += \"<td>\"+ i[1] +\"</td>\";\n            html += \"<td>\"+ i[2] +\"</td>\";\n            html += \"<td>\"+ i[3] +\"%</td>\";\n            html += \"</tr>\";\n        }\n        text.innerHTML = html;\n    },\n})\n\n//填充各公司检核结果明细\nfor (i of [\"ycxt\", \"yczc\", \"gdzdb\", \"ycjk\", \"fdct\", \"zyyc\", \"jz\"]){\n    $.ajax({\n        type : \"GET\",\n        async : false,\n        url : \"../../api/quality/report\",\n        data: {\n            'year': year,\n            'quarter': quarter,\n            'month': month,\n            'day': day,\n            'company': i\n        },\n        dataType : \"json\",\n        success : function(result) {\n            let text = document.getElementById(\"table_\"+i);\n            var html = \"\";\n            for (let t of result.data){\n               html += \"<tr>\";\n               html += \"<td>\"+ t.check_item +\"</td>\";\n               html += \"<td>\"+ t.problem_type +\"</td>\";\n               html += \"<td>\"+ t.problem_count +\"</td>\";\n               html += \"<td>\"+ t.item_count +\"</td>\";\n               html += \"<td>\"+ t.problem_per +\"</td>\";\n               html += \"<td></td>\"\n               html += \"</tr>\";\n            }\n            text.innerHTML = html;\n        },\n    })\n}"
  },
  {
    "path": "static/js/gojs/Buttons.js",
    "content": "'use strict';\n/*\n*  Copyright (C) 1998-2020 by Northwoods Software Corporation. All Rights Reserved.\n*/\n\n// These are the definitions for all of the predefined buttons.\n// You do not need to load this file in order to use buttons.\n\n// A 'Button' is a Panel that has a Shape surrounding some content\n// and that has mouseEnter/mouseLeave behavior to highlight the button.\n// The content of the button, whether a TextBlock or a Picture or a complicated Panel,\n// must be supplied by the caller.\n// The caller must also provide a click event handler.\n\n// Typical usage:\n//    $('Button',\n//      $(go.TextBlock, 'Click me!'),  // the content is just the text label\n//      { click: function(e, obj) { alert('I was clicked'); } }\n//    )\n\n// Note that a button click event handler is not invoked upon a click if isEnabledObject() returns false.\n\ngo.GraphObject.defineBuilder('Button', function (args) {\n  // default colors for 'Button' shape\n  var buttonFillNormal = '#F5F5F5';\n  var buttonStrokeNormal = '#BDBDBD';\n  var buttonFillOver = '#E0E0E0';\n  var buttonStrokeOver = '#9E9E9E';\n  var buttonFillPressed = '#BDBDBD'; // set to null for no button pressed effects\n  var buttonStrokePressed = '#9E9E9E';\n  var buttonFillDisabled = '#E5E5E5';\n\n  // padding inside the ButtonBorder to match sizing from previous versions\n  var paddingHorizontal = 2.76142374915397;\n  var paddingVertical = 2.761423749153969;\n\n  var button = /** @type {Panel} */ (\n    go.GraphObject.make(go.Panel, 'Auto',\n      {\n        isActionable: true,  // needed so that the ActionTool intercepts mouse events\n        enabledChanged: function (btn, enabled) {\n          var shape = btn.findObject('ButtonBorder');\n          if (shape !== null) {\n            shape.fill = enabled ? btn['_buttonFillNormal'] : btn['_buttonFillDisabled'];\n          }\n        },\n        cursor: 'pointer',\n        // save these values for the mouseEnter and mouseLeave event handlers\n        '_buttonFillNormal': buttonFillNormal,\n        '_buttonStrokeNormal': buttonStrokeNormal,\n        '_buttonFillOver': buttonFillOver,\n        '_buttonStrokeOver': buttonStrokeOver,\n        '_buttonFillPressed': buttonFillPressed,\n        '_buttonStrokePressed': buttonStrokePressed,\n        '_buttonFillDisabled': buttonFillDisabled\n      },\n      go.GraphObject.make(go.Shape,  // the border\n        {\n          name: 'ButtonBorder',\n          figure: 'RoundedRectangle',\n          spot1: new go.Spot(0, 0, paddingHorizontal, paddingVertical),\n          spot2: new go.Spot(1, 1, -paddingHorizontal, -paddingVertical),\n          parameter1: 2,\n          parameter2: 2,\n          fill: buttonFillNormal,\n          stroke: buttonStrokeNormal\n        }\n      )\n    )\n  );\n\n  // There's no GraphObject inside the button shape -- it must be added as part of the button definition.\n  // This way the object could be a TextBlock or a Shape or a Picture or arbitrarily complex Panel.\n\n  // mouse-over behavior\n  button.mouseEnter = function (e, btn, prev) {\n    if (!btn.isEnabledObject()) return;\n    var shape = btn.findObject('ButtonBorder');  // the border Shape\n    if (shape instanceof go.Shape) {\n      var brush = btn['_buttonFillOver'];\n      btn['_buttonFillNormal'] = shape.fill;\n      shape.fill = brush;\n      brush = btn['_buttonStrokeOver'];\n      btn['_buttonStrokeNormal'] = shape.stroke;\n      shape.stroke = brush;\n    }\n  };\n\n  button.mouseLeave = function (e, btn, prev) {\n    if (!btn.isEnabledObject()) return;\n    var shape = btn.findObject('ButtonBorder');  // the border Shape\n    if (shape instanceof go.Shape) {\n      shape.fill = btn['_buttonFillNormal'];\n      shape.stroke = btn['_buttonStrokeNormal'];\n    }\n  };\n\n  // mousedown/mouseup behavior\n  button.actionDown = function (e, btn) {\n    if (!btn.isEnabledObject()) return;\n    if (btn['_buttonFillPressed'] === null) return;\n    if (e.button !== 0) return;\n    var shape = btn.findObject('ButtonBorder');  // the border Shape\n    if (shape instanceof go.Shape) {\n      var diagram = e.diagram;\n      var oldskip = diagram.skipsUndoManager;\n      diagram.skipsUndoManager = true;\n      var brush = btn['_buttonFillPressed'];\n      btn['_buttonFillOver'] = shape.fill;\n      shape.fill = brush;\n      brush = btn['_buttonStrokePressed'];\n      btn['_buttonStrokeOver'] = shape.stroke;\n      shape.stroke = brush;\n      diagram.skipsUndoManager = oldskip;\n    }\n  };\n\n  button.actionUp = function (e, btn) {\n    if (!btn.isEnabledObject()) return;\n    if (btn['_buttonFillPressed'] === null) return;\n    if (e.button !== 0) return;\n    var shape = btn.findObject('ButtonBorder');  // the border Shape\n    if (shape instanceof go.Shape) {\n      var diagram = e.diagram;\n      var oldskip = diagram.skipsUndoManager;\n      diagram.skipsUndoManager = true;\n      if (overButton(e, btn)) {\n        shape.fill = btn['_buttonFillOver'];\n        shape.stroke = btn['_buttonStrokeOver'];\n      } else {\n        shape.fill = btn['_buttonFillNormal'];\n        shape.stroke = btn['_buttonStrokeNormal'];\n      }\n      diagram.skipsUndoManager = oldskip;\n    }\n  };\n\n  button.actionCancel = function (e, btn) {\n    if (!btn.isEnabledObject()) return;\n    if (btn['_buttonFillPressed'] === null) return;\n    var shape = btn.findObject('ButtonBorder');  // the border Shape\n    if (shape instanceof go.Shape) {\n      var diagram = e.diagram;\n      var oldskip = diagram.skipsUndoManager;\n      diagram.skipsUndoManager = true;\n      if (overButton(e, btn)) {\n        shape.fill = btn['_buttonFillOver'];\n        shape.stroke = btn['_buttonStrokeOver'];\n      } else {\n        shape.fill = btn['_buttonFillNormal'];\n        shape.stroke = btn['_buttonStrokeNormal'];\n      }\n      diagram.skipsUndoManager = oldskip;\n    }\n  };\n\n  button.actionMove = function (e, btn) {\n    if (!btn.isEnabledObject()) return;\n    if (btn['_buttonFillPressed'] === null) return;\n    var diagram = e.diagram;\n    if (diagram.firstInput.button !== 0) return;\n    diagram.currentTool.standardMouseOver();\n    if (overButton(e, btn)) {\n      var shape = btn.findObject('ButtonBorder');\n      if (shape instanceof go.Shape) {\n        var oldskip = diagram.skipsUndoManager;\n        diagram.skipsUndoManager = true;\n        let brush = btn['_buttonFillPressed'];\n        if (shape.fill !== brush) shape.fill = brush;\n        brush = btn['_buttonStrokePressed'];\n        if (shape.stroke !== brush) shape.stroke = brush;\n        diagram.skipsUndoManager = oldskip;\n      }\n    }\n  };\n\n  function overButton(e, btn) {\n    var over = e.diagram.findObjectAt(\n      e.documentPoint,\n      function (x) {\n        while (x.panel !== null) {\n          if (x.isActionable) return x;\n          x = x.panel;\n        }\n        return x;\n      },\n      function (x) { return x === btn; }\n    );\n    return over !== null;\n  }\n\n  return button;\n});\n\n\n// This is a complete Button that you can have in a Node template\n// to allow the user to collapse/expand the subtree beginning at that Node.\n\n// Typical usage within a Node template:\n//    $('TreeExpanderButton')\n\ngo.GraphObject.defineBuilder('TreeExpanderButton', function (args) {\n  var button = /** @type {Panel} */ (\n    go.GraphObject.make('Button',\n      { // set these values for the isTreeExpanded binding conversion\n        '_treeExpandedFigure': 'MinusLine',\n        '_treeCollapsedFigure': 'PlusLine'\n      },\n      go.GraphObject.make(go.Shape,  // the icon\n        {\n          name: 'ButtonIcon',\n          figure: 'MinusLine',  // default value for isTreeExpanded is true\n          stroke: '#424242',\n          strokeWidth: 2,\n          desiredSize: new go.Size(8, 8)\n        },\n        // bind the Shape.figure to the Node.isTreeExpanded value using this converter:\n        new go.Binding('figure', 'isTreeExpanded',\n          function (exp, shape) {\n            var but = shape.panel;\n            return exp ? but['_treeExpandedFigure'] : but['_treeCollapsedFigure'];\n          }\n        ).ofObject()\n      ),\n      // assume initially not visible because there are no links coming out\n      { visible: false },\n      // bind the button visibility to whether it's not a leaf node\n      new go.Binding('visible', 'isTreeLeaf',\n        function (leaf) { return !leaf; }\n      ).ofObject()\n    )\n  );\n\n  // tree expand/collapse behavior\n  button.click = function (e, btn) {\n    var node = btn.part;\n    if (node instanceof go.Adornment) node = node.adornedPart;\n    if (!(node instanceof go.Node)) return;\n    var diagram = node.diagram;\n    if (diagram === null) return;\n    var cmd = diagram.commandHandler;\n    if (node.isTreeExpanded) {\n      if (!cmd.canCollapseTree(node)) return;\n    } else {\n      if (!cmd.canExpandTree(node)) return;\n    }\n    e.handled = true;\n    if (node.isTreeExpanded) {\n      cmd.collapseTree(node);\n    } else {\n      cmd.expandTree(node);\n    }\n  };\n\n  return button;\n});\n\n\n// This is a complete Button that you can have in a Group template\n// to allow the user to collapse/expand the subgraph that the Group holds.\n\n// Typical usage within a Group template:\n//    $('SubGraphExpanderButton')\n\ngo.GraphObject.defineBuilder('SubGraphExpanderButton', function (args) {\n  var button = /** @type {Panel} */ (\n    go.GraphObject.make('Button',\n      { // set these values for the isSubGraphExpanded binding conversion\n        '_subGraphExpandedFigure': 'MinusLine',\n        '_subGraphCollapsedFigure': 'PlusLine'\n      },\n      go.GraphObject.make(go.Shape,  // the icon\n        {\n          name: 'ButtonIcon',\n          figure: 'MinusLine',  // default value for isSubGraphExpanded is true\n          stroke: '#424242',\n          strokeWidth: 2,\n          desiredSize: new go.Size(8, 8)\n        },\n        // bind the Shape.figure to the Group.isSubGraphExpanded value using this converter:\n        new go.Binding('figure', 'isSubGraphExpanded',\n          function (exp, shape) {\n            var but = shape.panel;\n            return exp ? but['_subGraphExpandedFigure'] : but['_subGraphCollapsedFigure'];\n          }\n        ).ofObject()\n      )\n    )\n  );\n\n  // subgraph expand/collapse behavior\n  button.click = function (e, btn) {\n    var group = btn.part;\n    if (group instanceof go.Adornment) group = group.adornedPart;\n    if (!(group instanceof go.Group)) return;\n    var diagram = group.diagram;\n    if (diagram === null) return;\n    var cmd = diagram.commandHandler;\n    if (group.isSubGraphExpanded) {\n      if (!cmd.canCollapseSubGraph(group)) return;\n    } else {\n      if (!cmd.canExpandSubGraph(group)) return;\n    }\n    e.handled = true;\n    if (group.isSubGraphExpanded) {\n      cmd.collapseSubGraph(group);\n    } else {\n      cmd.expandSubGraph(group);\n    }\n  };\n\n  return button;\n});\n\n\n// This is just an \"Auto\" Adornment that can hold some contents within a light gray, shadowed box.\n\n// Typical usage:\n//   toolTip:\n//     $(\"ToolTip\",\n//       $(go.TextBlock, . . .)\n//     )\ngo.GraphObject.defineBuilder('ToolTip', function (args) {\n  var ad = go.GraphObject.make(go.Adornment, 'Auto',\n    {\n      isShadowed: true,\n      shadowColor: 'rgba(0, 0, 0, .4)',\n      shadowOffset: new go.Point(0, 3),\n      shadowBlur: 5\n    },\n    go.GraphObject.make(go.Shape,\n      {\n        name: 'Border',\n        figure: 'RoundedRectangle',\n        parameter1: 1,\n        parameter2: 1,\n        fill: '#F5F5F5',\n        stroke: '#F0F0F0',\n        spot1: new go.Spot(0, 0, 4, 6),\n        spot2: new go.Spot(1, 1, -4, -4)\n      }\n    )\n  );\n  return ad;\n});\n\n\n// This is just a \"Vertical\" Adornment that can hold some \"ContextMenuButton\"s.\n\n// Typical usage:\n//   contextMenu:\n//     $(\"ContextMenu\",\n//       $(\"ContextMenuButton\",\n//         $(go.TextBlock, . . .),\n//         { click: . . .}\n//       ),\n//       $(\"ContextMenuButton\", . . .)\n//     )\ngo.GraphObject.defineBuilder('ContextMenu', function (args) {\n  var ad = go.GraphObject.make(go.Adornment, 'Vertical',\n    {\n      background: '#F5F5F5',\n      isShadowed: true,\n      shadowColor: 'rgba(0, 0, 0, .4)',\n      shadowOffset: new go.Point(0, 3),\n      shadowBlur: 5\n    },\n    // don't set the background if the ContextMenu is adorning something and there's a Placeholder\n    new go.Binding('background', '', function (obj) {\n      var part = obj.adornedPart;\n      if (part !== null && obj.placeholder !== null) return null;\n      return '#F5F5F5';\n    })\n  );\n  return ad;\n});\n\n\n// This just holds the 'ButtonBorder' Shape that acts as the border\n// around the button contents, which must be supplied by the caller.\n// The button contents are usually a TextBlock or Panel consisting of a Shape and a TextBlock.\n\n// Typical usage within an Adornment that is either a GraphObject.contextMenu or a Diagram.contextMenu:\n// $('ContextMenuButton',\n//   $(go.TextBlock, text),\n//   { click: function(e, obj) { alert('Command for ' + obj.part.adornedPart); } },\n//   new go.Binding('visible', '', function(data) { return ...OK to perform Command...; })\n// )\n\ngo.GraphObject.defineBuilder('ContextMenuButton', function (args) {\n  var button = /** @type {Panel} */ (go.GraphObject.make('Button'));\n  button.stretch = go.GraphObject.Horizontal;\n  var border = button.findObject('ButtonBorder');\n  if (border instanceof go.Shape) {\n    border.figure = 'Rectangle';\n    border.spot1 = new go.Spot(0, 0, 2, 3);\n    border.spot2 = new go.Spot(1, 1, -2, -2);\n  }\n  return button;\n});\n\n\n// This button is used to toggle the visibility of a GraphObject named\n// by the second argument to GraphObject.make.  If the second argument is not present\n// or if it is not a string, this assumes that the element name is 'COLLAPSIBLE'.\n// You can only control the visibility of one element in a Part at a time,\n// although that element might be an arbitrarily complex Panel.\n\n// Typical usage:\n//   $(go.Panel, . . .,\n//     $('PanelExpanderButton', 'COLLAPSIBLE'),\n//     . . .,\n//       $(go.Panel, . . .,\n//         { name: 'COLLAPSIBLE' },\n//         . . . stuff to be hidden or shown as the PanelExpanderButton is clicked . . .\n//       ),\n//     . . .\n//   )\n\ngo.GraphObject.defineBuilder('PanelExpanderButton', function (args) {\n  var eltname = /** @type {string} */ (go.GraphObject.takeBuilderArgument(args, 'COLLAPSIBLE'));\n\n  var button = /** @type {Panel} */ (\n    go.GraphObject.make('Button',\n      { // set these values for the button's look\n        '_buttonExpandedFigure': 'M0 0 M0 6 L4 2 8 6 M8 8',\n        '_buttonCollapsedFigure': 'M0 0 M0 2 L4 6 8 2 M8 8',\n        '_buttonFillNormal': 'rgba(0, 0, 0, 0)',\n        '_buttonStrokeNormal': null,\n        '_buttonFillOver': 'rgba(0, 0, 0, .2)',\n        '_buttonStrokeOver': null,\n        '_buttonFillPressed': 'rgba(0, 0, 0, .4)',\n        '_buttonStrokePressed': null\n      },\n      go.GraphObject.make(go.Shape,\n        { name: 'ButtonIcon', strokeWidth: 2 },\n        new go.Binding('geometryString', 'visible',\n          function (vis) { return vis ? button['_buttonExpandedFigure'] : button['_buttonCollapsedFigure']; }\n        ).ofObject(eltname)\n      )\n    )\n  );\n\n  var border = button.findObject('ButtonBorder');\n  if (border instanceof go.Shape) {\n    border.stroke = null;\n    border.fill = 'rgba(0, 0, 0, 0)';\n  }\n\n  button.click = function (e, btn) {\n    var diagram = btn.diagram;\n    if (diagram === null) return;\n    if (diagram.isReadOnly) return;\n    var elt = btn.findTemplateBinder();\n    if (elt === null) elt = btn.part;\n    if (elt !== null) {\n      var pan = elt.findObject(eltname);\n      if (pan !== null) {\n        e.handled = true;\n        diagram.startTransaction('Collapse/Expand Panel');\n        pan.visible = !pan.visible;\n        diagram.commitTransaction('Collapse/Expand Panel');\n      }\n    }\n  };\n\n  return button;\n});\n\n\n// Define a common checkbox button; the first argument is the name of the data property\n// to which the state of this checkbox is data bound.  If the first argument is not a string,\n// it raises an error.  If no data binding of the checked state is desired,\n// pass an empty string as the first argument.\n\n// Examples:\n// $('CheckBoxButton', 'dataPropertyName', ...)\n// or:\n// $('CheckBoxButton', '', { '_doClick': function(e, obj) { alert('clicked!'); } })\n\ngo.GraphObject.defineBuilder('CheckBoxButton', function (args) {\n  // process the one required string argument for this kind of button\n  var propname = /** @type {string} */ (go.GraphObject.takeBuilderArgument(args));\n\n  var button = /** @type {Panel} */ (\n    go.GraphObject.make('Button',\n      { desiredSize: new go.Size(14, 14) },\n      go.GraphObject.make(go.Shape,\n        {\n          name: 'ButtonIcon',\n          geometryString: 'M0 0 M0 8.85 L4.9 13.75 16.2 2.45 M16.2 16.2',  // a 'check' mark\n          strokeWidth: 2,\n          stretch: go.GraphObject.Fill,  // this Shape expands to fill the Button\n          geometryStretch: go.GraphObject.Uniform,  // the check mark fills the Shape without distortion\n          visible: false  // visible set to false: not checked, unless data.PROPNAME is true\n        },\n        // create a data Binding only if PROPNAME is supplied and not the empty string\n        (propname !== '' ? new go.Binding('visible', propname).makeTwoWay() : []))\n    )\n  );\n\n  button.click = function (e, btn) {\n    var diagram = e.diagram;\n    if (diagram === null || diagram.isReadOnly) return;\n    if (propname !== '' && diagram.model.isReadOnly) return;\n    e.handled = true;\n    var shape = btn.findObject('ButtonIcon');\n    diagram.startTransaction('checkbox');\n    shape.visible = !shape.visible;  // this toggles data.checked due to TwoWay Binding\n    // support extra side-effects without clobbering the click event handler:\n    if (typeof btn['_doClick'] === 'function') btn['_doClick'](e, btn);\n    diagram.commitTransaction('checkbox');\n  };\n\n  return button;\n});\n\n\n// This defines a whole check-box -- including both a 'CheckBoxButton' and whatever you want as the check box label.\n// Note that mouseEnter/mouseLeave/click events apply to everything in the panel, not just in the 'CheckBoxButton'.\n\n// Examples:\n// $('CheckBox', 'aBooleanDataProperty', $(go.TextBlock, 'the checkbox label'))\n// or\n// $('CheckBox', 'someProperty', $(go.TextBlock, 'A choice'),\n//   { '_doClick': function(e, obj) { ... perform extra side-effects ... } })\n\ngo.GraphObject.defineBuilder('CheckBox', function (args) {\n  // process the one required string argument for this kind of button\n  var propname = /** @type {string} */ (go.GraphObject.takeBuilderArgument(args));\n\n  var button = /** @type {Panel} */ (\n    go.GraphObject.make('CheckBoxButton', propname,  // bound to this data property\n      {\n        name: 'Button',\n        isActionable: false, // actionable is set on the whole horizontal panel\n        margin: new go.Margin(0, 1, 0, 0)\n      })\n  );\n\n  var box = /** @type {Panel} */ (\n    go.GraphObject.make(go.Panel, 'Horizontal',\n      button,\n      {\n        isActionable: true,\n        cursor: button.cursor,\n        margin: 1,\n        // transfer CheckBoxButton properties over to this new CheckBox panel\n        '_buttonFillNormal': button['_buttonFillNormal'],\n        '_buttonStrokeNormal': button['_buttonStrokeNormal'],\n        '_buttonFillOver': button['_buttonFillOver'],\n        '_buttonStrokeOver': button['_buttonStrokeOver'],\n        '_buttonFillPressed': button['_buttonFillPressed'],\n        '_buttonStrokePressed': button['_buttonStrokePressed'],\n        '_buttonFillDisabled': button['_buttonFillDisabled'],\n        mouseEnter: button.mouseEnter,\n        mouseLeave: button.mouseLeave,\n        actionDown: button.actionDown,\n        actionUp: button.actionUp,\n        actionCancel: button.actionCancel,\n        actionMove: button.actionMove,\n        click: button.click,\n        // also save original Button behavior, for potential use in a Panel.click event handler\n        '_buttonClick': button.click\n      }\n    )\n  );\n  // avoid potentially conflicting event handlers on the 'CheckBoxButton'\n  button.mouseEnter = null;\n  button.mouseLeave = null;\n  button.actionDown = null;\n  button.actionUp = null;\n  button.actionCancel = null;\n  button.actionMove = null;\n  button.click = null;\n  return box;\n});"
  },
  {
    "path": "static/js/gojs/go.js",
    "content": "/*\n * GoJS v2.1.11 JavaScript Library for HTML Diagrams, https://gojs.net\n * GoJS and Northwoods Software are registered trademarks of Northwoods Software Corporation, https://www.nwoods.com.\n * Copyright (C) 1998-2020 by Northwoods Software Corporation.  All Rights Reserved.\n * THIS SOFTWARE IS LICENSED.  THE LICENSE AGREEMENT IS AT: https://gojs.net/2.1.11/license.html.\n * DO NOT MODIFY THIS FILE.  DO NOT DISTRIBUTE A MODIFIED COPY OF THE CONTENTS OF THIS FILE.\n */\n(function () {\n    var t;\n\n    function aa(a) {\n        var b = 0;\n        return function () {\n            return b < a.length ? {\n                done: !1,\n                value: a[b++]\n            } : {\n                done: !0\n            }\n        }\n    }\n\n    function ba(a) {\n        var b = \"undefined\" != typeof Symbol && Symbol.iterator && a[Symbol.iterator];\n        return b ? b.call(a) : {\n            next: aa(a)\n        }\n    }\n\n    function da(a) {\n        for (var b, c = []; !(b = a.next()).done;) c.push(b.value);\n        return c\n    }\n    var ea = \"function\" == typeof Object.create ? Object.create : function (a) {\n            function b() {}\n            b.prototype = a;\n            return new b\n        },\n        fa;\n    if (\"function\" == typeof Object.setPrototypeOf) fa = Object.setPrototypeOf;\n    else {\n        var ha;\n        a: {\n            var ia = {\n                    a: !0\n                },\n                ja = {};\n            try {\n                ja.__proto__ = ia;\n                ha = ja.a;\n                break a\n            } catch (a) {}\n            ha = !1\n        }\n        fa = ha ? function (a, b) {\n            a.__proto__ = b;\n            if (a.__proto__ !== b) throw new TypeError(a + \" is not extensible\");\n            return a\n        } : null\n    }\n    var ka = fa;\n\n    function la(a, b) {\n        a.prototype = ea(b.prototype);\n        a.prototype.constructor = a;\n        if (ka) ka(a, b);\n        else\n            for (var c in b)\n                if (\"prototype\" != c)\n                    if (Object.defineProperties) {\n                        var d = Object.getOwnPropertyDescriptor(b, c);\n                        d && Object.defineProperty(a, c, d)\n                    } else a[c] = b[c];\n        a.LA = b.prototype\n    }\n    var ma = \"undefined\" != typeof window && window === self ? self : \"undefined\" != typeof global && null != global ? global : self,\n        na = \"function\" == typeof Object.defineProperties ? Object.defineProperty : function (a, b, c) {\n            a != Array.prototype && a != Object.prototype && (a[b] = c.value)\n        };\n\n    function oa(a) {\n        if (a) {\n            for (var b = ma, c = [\"Array\", \"prototype\", \"fill\"], d = 0; d < c.length - 1; d++) {\n                var e = c[d];\n                e in b || (b[e] = {});\n                b = b[e]\n            }\n            c = c[c.length - 1];\n            d = b[c];\n            a = a(d);\n            a != d && null != a && na(b, c, {\n                writable: !0,\n                value: a\n            })\n        }\n    }\n    oa(function (a) {\n        return a ? a : function (a, c, d) {\n            var b = this.length || 0;\n            0 > c && (c = Math.max(0, b + c));\n            if (null == d || d > b) d = b;\n            d = Number(d);\n            0 > d && (d = Math.max(0, b + d));\n            for (c = Number(c || 0); c < d; c++) this[c] = a;\n            return this\n        }\n    });\n    var x = \"object\" === typeof self && self.self === self && self || \"object\" === typeof global && global.global === global && global || \"object\" === typeof window && window.window === window && window || {};\n    void 0 === x.requestAnimationFrame && (x.requestAnimationFrame = x.setImmediate);\n\n    function qa() {}\n\n    function ra(a, b) {\n        var c = -1;\n        return function () {\n            var d = this,\n                e = arguments; - 1 !== c && x.clearTimeout(c);\n            c = sa(function () {\n                c = -1;\n                a.apply(d, e)\n            }, b)\n        }\n    }\n\n    function sa(a, b) {\n        return x.setTimeout(a, b)\n    }\n\n    function ta(a) {\n        return x.document.createElement(a)\n    }\n\n    function B(a) {\n        throw Error(a);\n    }\n\n    function ua(a, b) {\n        a = \"The object is frozen, so its properties cannot be set: \" + a.toString();\n        void 0 !== b && (a += \"  to value: \" + b);\n        B(a)\n    }\n\n    function va(a, b, c, d) {\n        c = null === c ? \"*\" : \"string\" === typeof c ? c : \"function\" === typeof c && \"string\" === typeof c.className ? c.className : \"\";\n        void 0 !== d && (c += \".\" + d);\n        B(c + \" is not in the range \" + b + \": \" + a)\n    }\n\n    function wa(a) {\n        x.console && x.console.log(a)\n    }\n\n    function ya() {\n        x.console && x.console.log(\"Warning: List/Map/Set constructors no longer take an argument that enforces type.Instead they take an optional collection of Values to add to the collection. See 2.0 changelog for details.\")\n    }\n\n    function za(a) {\n        return \"object\" === typeof a && null !== a\n    }\n\n    function Aa(a) {\n        return Array.isArray(a) || x.NodeList && a instanceof x.NodeList || x.HTMLCollection && a instanceof x.HTMLCollection\n    }\n\n    function Ba(a) {\n        return Array.prototype.slice.call(a)\n    }\n\n    function Ca(a, b, c) {\n        Array.isArray(a) ? b >= a.length ? a.push(c) : a.splice(b, 0, c) : B(\"Cannot insert an object into an HTMLCollection or NodeList: \" + c + \" at \" + b)\n    }\n\n    function Da(a, b) {\n        Array.isArray(a) ? b >= a.length ? a.pop() : a.splice(b, 1) : B(\"Cannot remove an object from an HTMLCollection or NodeList at \" + b)\n    }\n\n    function Fa() {\n        var a = Ga.pop();\n        return void 0 === a ? [] : a\n    }\n\n    function Ha(a) {\n        a.length = 0;\n        Ga.push(a)\n    }\n\n    function Ia(a) {\n        if (\"function\" === typeof a) {\n            if (a.className) return a.className;\n            if (a.name) return a.name;\n            var b = a.toString();\n            b = b.substring(9, b.indexOf(\"(\")).trim();\n            if (\"\" !== b) return a._className = b\n        } else if (za(a) && a.constructor) return Ia(a.constructor);\n        return typeof a\n    }\n\n    function Ja(a) {\n        var b = a;\n        za(a) && (a.text ? b = a.text : a.name ? b = a.name : void 0 !== a.key ? b = a.key : void 0 !== a.id ? b = a.id : a.constructor === Object && (a.Text ? b = a.Text : a.Name ? b = a.Name : void 0 !== a.Key ? b = a.Key : void 0 !== a.Id ? b = a.Id : void 0 !== a.ID && (b = a.ID)));\n        return void 0 === b ? \"undefined\" : null === b ? \"null\" : b.toString()\n    }\n\n    function Ka(a, b) {\n        if (a.hasOwnProperty(b)) return !0;\n        for (a = Object.getPrototypeOf(a); a && a !== Function;) {\n            if (a.hasOwnProperty(b)) return !0;\n            var c = a.FA;\n            if (c && c[b]) return !0;\n            a = Object.getPrototypeOf(a)\n        }\n        return !1\n    }\n\n    function La(a, b, c) {\n        Object.defineProperty(Oa.prototype, a, {\n            get: b,\n            set: c\n        })\n    }\n\n    function Pa() {\n        var a = Qa;\n        if (0 === a.length)\n            for (var b = x.document.getElementsByTagName(\"canvas\"), c = b.length, d = 0; d < c; d++) {\n                var e = b[d];\n                e.parentElement && e.parentElement.B && a.push(e.parentElement.B)\n            }\n        return a\n    }\n\n    function Ra(a) {\n        for (var b = [], c = 0; 256 > c; c++) b[\"0123456789abcdef\".charAt(c >> 4) + \"0123456789abcdef\".charAt(c & 15)] = String.fromCharCode(c);\n        a.length % 2 && (a = \"0\" + a);\n        c = [];\n        for (var d = 0, e = 0; e < a.length; e += 2) c[d++] = b[a.substr(e, 2)];\n        a = c.join(\"\");\n        a = \"\" === a ? \"0\" : a;\n        b = [];\n        for (c = 0; 256 > c; c++) b[c] = c;\n        for (c = d = 0; 256 > c; c++) d = (d + b[c] + 119) % 256, e = b[c], b[c] = b[d], b[d] = e;\n        d = c = 0;\n        for (var f = \"\", g = 0; g < a.length; g++) c = (c + 1) % 256, d = (d + b[c]) % 256, e = b[c], b[c] = b[d], b[d] = e, f += String.fromCharCode(a.charCodeAt(g) ^ b[(b[c] + b[d]) % 256]);\n        return f\n    }\n    var Sa = void 0 !== x.navigator && 0 < x.navigator.userAgent.indexOf(\"MSIE 9.0\"),\n        Ta = void 0 !== x.navigator && 0 < x.navigator.userAgent.indexOf(\"MSIE 10.0\"),\n        Ua = void 0 !== x.navigator && 0 < x.navigator.userAgent.indexOf(\"Trident/7\"),\n        Va = void 0 !== x.navigator && 0 < x.navigator.userAgent.indexOf(\"Edge/\"),\n        Wa = void 0 !== x.navigator && void 0 !== x.navigator.platform && 0 <= x.navigator.platform.toUpperCase().indexOf(\"MAC\"),\n        Xa = void 0 !== x.navigator && void 0 !== x.navigator.platform && null !== x.navigator.platform.match(/(iPhone|iPod|iPad)/i),\n        Ga = [];\n    Object.freeze([]);\n    var Qa = [];\n    qa.className = \"Util\";\n    qa.Dx = \"32ab5ff3b26f42dc0ed90f21442913b5\";\n    qa.adym = \"gojs.net\";\n    qa.vfo = \"28e647fdb267\";\n    qa.className = \"Util\";\n\n    function D(a, b, c) {\n        Ya(this);\n        this.l = a;\n        this.Ra = b;\n        this.u = c\n    }\n    D.prototype.toString = function () {\n        return \"EnumValue.\" + this.Ra\n    };\n\n    function Za(a, b) {\n        return void 0 === b || null === b || \"\" === b ? null : a[b]\n    }\n    ma.Object.defineProperties(D.prototype, {\n        classType: {\n            get: function () {\n                return this.l\n            }\n        },\n        name: {\n            get: function () {\n                return this.Ra\n            }\n        },\n        value: {\n            get: function () {\n                return this.u\n            }\n        }\n    });\n    D.className = \"EnumValue\";\n\n    function cb() {\n        this.Ow = []\n    }\n    cb.prototype.toString = function () {\n        return this.Ow.join(\"\")\n    };\n    cb.prototype.add = function (a) {\n        \"\" !== a && this.Ow.push(a)\n    };\n    cb.className = \"StringBuilder\";\n\n    function db() {}\n    db.className = \"PropertyCollection\";\n\n    function eb() {}\n    eb.prototype.reset = function () {};\n    eb.prototype.next = function () {\n        return !1\n    };\n    eb.prototype.ed = function () {\n        return !1\n    };\n    eb.prototype.first = function () {\n        return null\n    };\n    eb.prototype.any = function () {\n        return !1\n    };\n    eb.prototype.all = function () {\n        return !0\n    };\n    eb.prototype.each = function () {\n        return this\n    };\n    eb.prototype.map = function () {\n        return this\n    };\n    eb.prototype.filter = function () {\n        return this\n    };\n    eb.prototype.Bd = function () {};\n    eb.prototype.toString = function () {\n        return \"EmptyIterator\"\n    };\n    ma.Object.defineProperties(eb.prototype, {\n        iterator: {\n            get: function () {\n                return this\n            }\n        },\n        count: {\n            get: function () {\n                return 0\n            }\n        }\n    });\n    eb.prototype.first = eb.prototype.first;\n    eb.prototype.hasNext = eb.prototype.ed;\n    eb.prototype.next = eb.prototype.next;\n    eb.prototype.reset = eb.prototype.reset;\n    var fb = null;\n    eb.className = \"EmptyIterator\";\n    fb = new eb;\n\n    function gb(a) {\n        this.key = -1;\n        this.value = a\n    }\n    gb.prototype.reset = function () {\n        this.key = -1\n    };\n    gb.prototype.next = function () {\n        return -1 === this.key ? (this.key = 0, !0) : !1\n    };\n    gb.prototype.ed = function () {\n        return this.next()\n    };\n    gb.prototype.first = function () {\n        this.key = 0;\n        return this.value\n    };\n    gb.prototype.any = function (a) {\n        this.key = -1;\n        return a(this.value)\n    };\n    gb.prototype.all = function (a) {\n        this.key = -1;\n        return a(this.value)\n    };\n    gb.prototype.each = function (a) {\n        this.key = -1;\n        a(this.value);\n        return this\n    };\n    gb.prototype.map = function (a) {\n        return new gb(a(this.value))\n    };\n    gb.prototype.filter = function (a) {\n        return a(this.value) ? new gb(this.value) : fb\n    };\n    gb.prototype.Bd = function () {\n        this.value = null\n    };\n    gb.prototype.toString = function () {\n        return \"SingletonIterator(\" + this.value + \")\"\n    };\n    ma.Object.defineProperties(gb.prototype, {\n        iterator: {\n            get: function () {\n                return this\n            }\n        },\n        count: {\n            get: function () {\n                return 1\n            }\n        }\n    });\n    gb.prototype.first = gb.prototype.first;\n    gb.prototype.hasNext = gb.prototype.ed;\n    gb.prototype.next = gb.prototype.next;\n    gb.prototype.reset = gb.prototype.reset;\n    gb.className = \"SingletonIterator\";\n\n    function jb(a) {\n        this.nb = a;\n        this.$e = null;\n        a.Fa = null;\n        this.ia = a.Aa;\n        this.Pa = -1\n    }\n    jb.prototype.reset = function () {\n        var a = this.nb;\n        a.Fa = null;\n        this.ia = a.Aa;\n        this.Pa = -1\n    };\n    jb.prototype.next = function () {\n        var a = this.nb;\n        if (a.Aa !== this.ia && 0 > this.key) return !1;\n        a = a.j;\n        var b = a.length,\n            c = ++this.Pa,\n            d = this.$e;\n        if (null !== d)\n            for (; c < b;) {\n                var e = a[c];\n                if (d(e)) return this.key = this.Pa = c, this.value = e, !0;\n                c++\n            } else {\n                if (c < b) return this.key = c, this.value = a[c], !0;\n                this.Bd()\n            }\n        return !1\n    };\n    jb.prototype.ed = function () {\n        return this.next()\n    };\n    jb.prototype.first = function () {\n        var a = this.nb;\n        this.ia = a.Aa;\n        this.Pa = 0;\n        a = a.j;\n        var b = a.length,\n            c = this.$e;\n        if (null !== c) {\n            for (var d = 0; d < b;) {\n                var e = a[d];\n                if (c(e)) return this.key = this.Pa = d, this.value = e;\n                d++\n            }\n            return null\n        }\n        return 0 < b ? (a = a[0], this.key = 0, this.value = a) : null\n    };\n    jb.prototype.any = function (a) {\n        var b = this.nb;\n        b.Fa = null;\n        this.Pa = -1;\n        b = b.j;\n        for (var c = b.length, d = this.$e, e = 0; e < c; e++) {\n            var f = b[e];\n            if ((null === d || d(f)) && a(f)) return !0\n        }\n        return !1\n    };\n    jb.prototype.all = function (a) {\n        var b = this.nb;\n        b.Fa = null;\n        this.Pa = -1;\n        b = b.j;\n        for (var c = b.length, d = this.$e, e = 0; e < c; e++) {\n            var f = b[e];\n            if ((null === d || d(f)) && !a(f)) return !1\n        }\n        return !0\n    };\n    jb.prototype.each = function (a) {\n        var b = this.nb;\n        b.Fa = null;\n        this.Pa = -1;\n        b = b.j;\n        for (var c = b.length, d = this.$e, e = 0; e < c; e++) {\n            var f = b[e];\n            (null === d || d(f)) && a(f)\n        }\n        return this\n    };\n    jb.prototype.map = function (a) {\n        var b = this.nb;\n        b.Fa = null;\n        this.Pa = -1;\n        var c = [];\n        b = b.j;\n        for (var d = b.length, e = this.$e, f = 0; f < d; f++) {\n            var g = b[f];\n            (null === e || e(g)) && c.push(a(g))\n        }\n        a = new E;\n        a.j = c;\n        a.ib();\n        return a.iterator\n    };\n    jb.prototype.filter = function (a) {\n        var b = this.nb;\n        b.Fa = null;\n        this.Pa = -1;\n        var c = [];\n        b = b.j;\n        for (var d = b.length, e = this.$e, f = 0; f < d; f++) {\n            var g = b[f];\n            (null === e || e(g)) && a(g) && c.push(g)\n        }\n        a = new E;\n        a.j = c;\n        a.ib();\n        return a.iterator\n    };\n    jb.prototype.Bd = function () {\n        this.key = -1;\n        this.value = null;\n        this.ia = -1;\n        this.$e = null;\n        this.nb.Fa = this\n    };\n    jb.prototype.toString = function () {\n        return \"ListIterator@\" + this.Pa + \"/\" + this.nb.count\n    };\n    ma.Object.defineProperties(jb.prototype, {\n        iterator: {\n            get: function () {\n                return this\n            }\n        },\n        predicate: {\n            get: function () {\n                return this.$e\n            },\n            set: function (a) {\n                this.$e = a\n            }\n        },\n        count: {\n            get: function () {\n                var a = this.$e;\n                if (null !== a) {\n                    for (var b = 0, c = this.nb.j, d = c.length, e = 0; e < d; e++) a(c[e]) && b++;\n                    return b\n                }\n                return this.nb.j.length\n            }\n        }\n    });\n    jb.prototype.first = jb.prototype.first;\n    jb.prototype.hasNext = jb.prototype.ed;\n    jb.prototype.next = jb.prototype.next;\n    jb.prototype.reset = jb.prototype.reset;\n    jb.className = \"ListIterator\";\n\n    function kb(a) {\n        this.nb = a;\n        a.bh = null;\n        this.ia = a.Aa;\n        this.Pa = a.j.length\n    }\n    kb.prototype.reset = function () {\n        var a = this.nb;\n        a.bh = null;\n        this.ia = a.Aa;\n        this.Pa = a.j.length\n    };\n    kb.prototype.next = function () {\n        var a = this.nb;\n        if (a.Aa !== this.ia && 0 > this.key) return !1;\n        var b = --this.Pa;\n        if (0 <= b) return this.key = b, this.value = a.j[b], !0;\n        this.Bd();\n        return !1\n    };\n    kb.prototype.ed = function () {\n        return this.next()\n    };\n    kb.prototype.first = function () {\n        var a = this.nb;\n        this.ia = a.Aa;\n        var b = a.j;\n        this.Pa = a = b.length - 1;\n        return 0 <= a ? (b = b[a], this.key = a, this.value = b) : null\n    };\n    kb.prototype.any = function (a) {\n        var b = this.nb;\n        b.bh = null;\n        b = b.j;\n        var c = b.length;\n        this.Pa = c;\n        for (--c; 0 <= c; c--)\n            if (a(b[c])) return !0;\n        return !1\n    };\n    kb.prototype.all = function (a) {\n        var b = this.nb;\n        b.bh = null;\n        b = b.j;\n        var c = b.length;\n        this.Pa = c;\n        for (--c; 0 <= c; c--)\n            if (!a(b[c])) return !1;\n        return !0\n    };\n    kb.prototype.each = function (a) {\n        var b = this.nb;\n        b.bh = null;\n        b = b.j;\n        var c = b.length;\n        this.Pa = c;\n        for (--c; 0 <= c; c--) a(b[c]);\n        return this\n    };\n    kb.prototype.map = function (a) {\n        var b = this.nb;\n        b.bh = null;\n        var c = [];\n        b = b.j;\n        var d = b.length;\n        this.Pa = d;\n        for (--d; 0 <= d; d--) c.push(a(b[d]));\n        a = new E;\n        a.j = c;\n        a.ib();\n        return a.iterator\n    };\n    kb.prototype.filter = function (a) {\n        var b = this.nb;\n        b.bh = null;\n        var c = [];\n        b = b.j;\n        var d = b.length;\n        this.Pa = d;\n        for (--d; 0 <= d; d--) {\n            var e = b[d];\n            a(e) && c.push(e)\n        }\n        a = new E;\n        a.j = c;\n        a.ib();\n        return a.iterator\n    };\n    kb.prototype.Bd = function () {\n        this.key = -1;\n        this.value = null;\n        this.ia = -1;\n        this.nb.bh = this\n    };\n    kb.prototype.toString = function () {\n        return \"ListIteratorBackwards(\" + this.Pa + \"/\" + this.nb.count + \")\"\n    };\n    ma.Object.defineProperties(kb.prototype, {\n        iterator: {\n            get: function () {\n                return this\n            }\n        },\n        count: {\n            get: function () {\n                return this.nb.j.length\n            }\n        }\n    });\n    kb.prototype.first = kb.prototype.first;\n    kb.prototype.hasNext = kb.prototype.ed;\n    kb.prototype.next = kb.prototype.next;\n    kb.prototype.reset = kb.prototype.reset;\n    kb.className = \"ListIteratorBackwards\";\n\n    function E(a) {\n        Ya(this);\n        this.s = !1;\n        this.j = [];\n        this.Aa = 0;\n        this.bh = this.Fa = null;\n        void 0 !== a && (\"function\" === typeof a || \"string\" === typeof a ? ya() : this.addAll(a))\n    }\n    t = E.prototype;\n    t.ib = function () {\n        var a = this.Aa;\n        a++;\n        999999999 < a && (a = 0);\n        this.Aa = a\n    };\n    t.freeze = function () {\n        this.s = !0;\n        return this\n    };\n    t.ea = function () {\n        this.s = !1;\n        return this\n    };\n    t.toString = function () {\n        return \"List()#\" + lb(this)\n    };\n    t.add = function (a) {\n        if (null === a) return this;\n        this.s && ua(this, a);\n        this.j.push(a);\n        this.ib();\n        return this\n    };\n    t.push = function (a) {\n        this.add(a)\n    };\n    t.addAll = function (a) {\n        if (null === a) return this;\n        this.s && ua(this);\n        var b = this.j;\n        if (Aa(a))\n            for (var c = a.length, d = 0; d < c; d++) b.push(a[d]);\n        else\n            for (a = a.iterator; a.next();) b.push(a.value);\n        this.ib();\n        return this\n    };\n    t.clear = function () {\n        this.s && ua(this);\n        this.j.length = 0;\n        this.ib()\n    };\n    t.contains = function (a) {\n        return null === a ? !1 : -1 !== this.j.indexOf(a)\n    };\n    t.has = function (a) {\n        return this.contains(a)\n    };\n    t.indexOf = function (a) {\n        return null === a ? -1 : this.j.indexOf(a)\n    };\n    t.L = function (a) {\n        var b = this.j;\n        (0 > a || a >= b.length) && va(a, \"0 <= i < length\", E, \"elt:i\");\n        return b[a]\n    };\n    t.get = function (a) {\n        return this.L(a)\n    };\n    t.gd = function (a, b) {\n        var c = this.j;\n        (0 > a || a >= c.length) && va(a, \"0 <= i < length\", E, \"setElt:i\");\n        this.s && ua(this, a);\n        c[a] = b\n    };\n    t.set = function (a, b) {\n        this.gd(a, b)\n    };\n    t.first = function () {\n        var a = this.j;\n        return 0 === a.length ? null : a[0]\n    };\n    t.Xb = function () {\n        var a = this.j,\n            b = a.length;\n        return 0 < b ? a[b - 1] : null\n    };\n    t.pop = function () {\n        this.s && ua(this);\n        var a = this.j;\n        return 0 < a.length ? a.pop() : null\n    };\n    E.prototype.any = function (a) {\n        for (var b = this.j, c = b.length, d = 0; d < c; d++)\n            if (a(b[d])) return !0;\n        return !1\n    };\n    E.prototype.all = function (a) {\n        for (var b = this.j, c = b.length, d = 0; d < c; d++)\n            if (!a(b[d])) return !1;\n        return !0\n    };\n    E.prototype.each = function (a) {\n        for (var b = this.j, c = b.length, d = 0; d < c; d++) a(b[d]);\n        return this\n    };\n    E.prototype.map = function (a) {\n        for (var b = new E, c = [], d = this.j, e = d.length, f = 0; f < e; f++) c.push(a(d[f]));\n        b.j = c;\n        b.ib();\n        return b\n    };\n    E.prototype.filter = function (a) {\n        for (var b = new E, c = [], d = this.j, e = d.length, f = 0; f < e; f++) {\n            var g = d[f];\n            a(g) && c.push(g)\n        }\n        b.j = c;\n        b.ib();\n        return b\n    };\n    t = E.prototype;\n    t.Kb = function (a, b) {\n        0 > a && va(a, \">= 0\", E, \"insertAt:i\");\n        this.s && ua(this, a);\n        var c = this.j;\n        a >= c.length ? c.push(b) : c.splice(a, 0, b);\n        this.ib()\n    };\n    t.remove = function (a) {\n        if (null === a) return !1;\n        this.s && ua(this, a);\n        var b = this.j;\n        a = b.indexOf(a);\n        if (-1 === a) return !1;\n        a === b.length - 1 ? b.pop() : b.splice(a, 1);\n        this.ib();\n        return !0\n    };\n    t.delete = function (a) {\n        return this.remove(a)\n    };\n    t.lb = function (a) {\n        var b = this.j;\n        (0 > a || a >= b.length) && va(a, \"0 <= i < length\", E, \"removeAt:i\");\n        this.s && ua(this, a);\n        a === b.length - 1 ? b.pop() : b.splice(a, 1);\n        this.ib()\n    };\n    t.removeRange = function (a, b) {\n        var c = this.j,\n            d = c.length;\n        if (0 > a) a = 0;\n        else if (a >= d) return this;\n        if (0 > b) return this;\n        b >= d && (b = d - 1);\n        if (a > b) return this;\n        this.s && ua(this);\n        for (var e = a, f = b + 1; f < d;) c[e++] = c[f++];\n        c.length = d - (b - a + 1);\n        this.ib();\n        return this\n    };\n    E.prototype.copy = function () {\n        var a = new E,\n            b = this.j;\n        0 < b.length && (a.j = Array.prototype.slice.call(b));\n        return a\n    };\n    t = E.prototype;\n    t.na = function () {\n        for (var a = this.j, b = this.count, c = Array(b), d = 0; d < b; d++) c[d] = a[d];\n        return c\n    };\n    t.mw = function () {\n        for (var a = new F, b = this.j, c = this.count, d = 0; d < c; d++) a.add(b[d]);\n        return a\n    };\n    t.sort = function (a) {\n        this.s && ua(this);\n        this.j.sort(a);\n        this.ib();\n        return this\n    };\n    t.ej = function (a, b, c) {\n        var d = this.j,\n            e = d.length;\n        void 0 === b && (b = 0);\n        void 0 === c && (c = e);\n        this.s && ua(this);\n        var f = c - b;\n        if (1 >= f) return this;\n        (0 > b || b >= e - 1) && va(b, \"0 <= from < length\", E, \"sortRange:from\");\n        if (2 === f) return c = d[b], e = d[b + 1], 0 < a(c, e) && (d[b] = e, d[b + 1] = c, this.ib()), this;\n        if (0 === b)\n            if (c >= e) d.sort(a);\n            else\n                for (b = d.slice(0, c), b.sort(a), a = 0; a < c; a++) d[a] = b[a];\n        else if (c >= e)\n            for (c = d.slice(b), c.sort(a), a = b; a < e; a++) d[a] = c[a - b];\n        else\n            for (e = d.slice(b, c), e.sort(a), a = b; a < c; a++) d[a] = e[a - b];\n        this.ib();\n        return this\n    };\n    t.reverse = function () {\n        this.s && ua(this);\n        this.j.reverse();\n        this.ib();\n        return this\n    };\n    ma.Object.defineProperties(E.prototype, {\n        _dataArray: {\n            get: function () {\n                return this.j\n            }\n        },\n        count: {\n            get: function () {\n                return this.j.length\n            }\n        },\n        size: {\n            get: function () {\n                return this.j.length\n            }\n        },\n        length: {\n            get: function () {\n                return this.j.length\n            }\n        },\n        iterator: {\n            get: function () {\n                if (0 >= this.j.length) return fb;\n                var a = this.Fa;\n                return null !== a ? (a.reset(), a) : new jb(this)\n            }\n        },\n        iteratorBackwards: {\n            get: function () {\n                if (0 >= this.j.length) return fb;\n                var a = this.bh;\n                return null !== a ? (a.reset(), a) : new kb(this)\n            }\n        }\n    });\n    E.prototype.reverse = E.prototype.reverse;\n    E.prototype.sortRange = E.prototype.ej;\n    E.prototype.sort = E.prototype.sort;\n    E.prototype.toSet = E.prototype.mw;\n    E.prototype.toArray = E.prototype.na;\n    E.prototype.removeRange = E.prototype.removeRange;\n    E.prototype.removeAt = E.prototype.lb;\n    E.prototype[\"delete\"] = E.prototype.delete;\n    E.prototype.remove = E.prototype.remove;\n    E.prototype.insertAt = E.prototype.Kb;\n    E.prototype.pop = E.prototype.pop;\n    E.prototype.last = E.prototype.Xb;\n    E.prototype.first = E.prototype.first;\n    E.prototype.set = E.prototype.set;\n    E.prototype.setElt = E.prototype.gd;\n    E.prototype.get = E.prototype.get;\n    E.prototype.elt = E.prototype.L;\n    E.prototype.indexOf = E.prototype.indexOf;\n    E.prototype.has = E.prototype.has;\n    E.prototype.contains = E.prototype.contains;\n    E.prototype.clear = E.prototype.clear;\n    E.prototype.addAll = E.prototype.addAll;\n    E.prototype.push = E.prototype.push;\n    E.prototype.add = E.prototype.add;\n    E.prototype.thaw = E.prototype.ea;\n    E.prototype.freeze = E.prototype.freeze;\n    E.className = \"List\";\n\n    function mb(a) {\n        this.rg = a;\n        a.Fa = null;\n        this.ia = a.Aa;\n        this.la = null\n    }\n    mb.prototype.reset = function () {\n        var a = this.rg;\n        a.Fa = null;\n        this.ia = a.Aa;\n        this.la = null\n    };\n    mb.prototype.next = function () {\n        var a = this.rg;\n        if (a.Aa !== this.ia && null === this.key) return !1;\n        var b = this.la;\n        b = null === b ? a.ba : b.oa;\n        if (null !== b) return this.la = b, this.value = b.value, this.key = b.key, !0;\n        this.Bd();\n        return !1\n    };\n    mb.prototype.ed = function () {\n        return this.next()\n    };\n    mb.prototype.first = function () {\n        var a = this.rg;\n        this.ia = a.Aa;\n        a = a.ba;\n        if (null !== a) {\n            this.la = a;\n            var b = a.value;\n            this.key = a.key;\n            return this.value = b\n        }\n        return null\n    };\n    mb.prototype.any = function (a) {\n        var b = this.rg;\n        this.la = b.Fa = null;\n        for (b = b.ba; null !== b;) {\n            if (a(b.value)) return !0;\n            b = b.oa\n        }\n        return !1\n    };\n    mb.prototype.all = function (a) {\n        var b = this.rg;\n        this.la = b.Fa = null;\n        for (b = b.ba; null !== b;) {\n            if (!a(b.value)) return !1;\n            b = b.oa\n        }\n        return !0\n    };\n    mb.prototype.each = function (a) {\n        var b = this.rg;\n        this.la = b.Fa = null;\n        for (b = b.ba; null !== b;) a(b.value), b = b.oa;\n        return this\n    };\n    mb.prototype.map = function (a) {\n        var b = this.rg;\n        b.Fa = null;\n        var c = new E;\n        for (b = b.ba; null !== b;) c.add(a(b.value)), b = b.oa;\n        return c.iterator\n    };\n    mb.prototype.filter = function (a) {\n        var b = this.rg;\n        b.Fa = null;\n        var c = new E;\n        for (b = b.ba; null !== b;) {\n            var d = b.value;\n            a(d) && c.add(d);\n            b = b.oa\n        }\n        return c.iterator\n    };\n    mb.prototype.Bd = function () {\n        this.value = this.key = null;\n        this.ia = -1;\n        this.rg.Fa = this\n    };\n    mb.prototype.toString = function () {\n        return null !== this.la ? \"SetIterator@\" + this.la.value : \"SetIterator\"\n    };\n    ma.Object.defineProperties(mb.prototype, {\n        iterator: {\n            get: function () {\n                return this\n            }\n        },\n        count: {\n            get: function () {\n                return this.rg.Cb\n            }\n        }\n    });\n    mb.prototype.first = mb.prototype.first;\n    mb.prototype.hasNext = mb.prototype.ed;\n    mb.prototype.next = mb.prototype.next;\n    mb.prototype.reset = mb.prototype.reset;\n    mb.className = \"SetIterator\";\n\n    function F(a) {\n        Ya(this);\n        this.s = !1;\n        this.Eb = {};\n        this.Cb = 0;\n        this.Fa = null;\n        this.Aa = 0;\n        this.Ue = this.ba = null;\n        void 0 !== a && (\"function\" === typeof a || \"string\" === typeof a ? ya() : this.addAll(a))\n    }\n    t = F.prototype;\n    t.ib = function () {\n        var a = this.Aa;\n        a++;\n        999999999 < a && (a = 0);\n        this.Aa = a\n    };\n    t.freeze = function () {\n        this.s = !0;\n        return this\n    };\n    t.ea = function () {\n        this.s = !1;\n        return this\n    };\n    t.toString = function () {\n        return \"Set()#\" + lb(this)\n    };\n    t.add = function (a) {\n        if (null === a) return this;\n        this.s && ua(this, a);\n        var b = a;\n        za(a) && (b = nb(a));\n        void 0 === this.Eb[b] && (this.Cb++, a = new ob(a, a), this.Eb[b] = a, b = this.Ue, null === b ? this.ba = a : (a.Dl = b, b.oa = a), this.Ue = a, this.ib());\n        return this\n    };\n    t.addAll = function (a) {\n        if (null === a) return this;\n        this.s && ua(this);\n        if (Aa(a))\n            for (var b = a.length, c = 0; c < b; c++) this.add(a[c]);\n        else\n            for (a = a.iterator; a.next();) this.add(a.value);\n        return this\n    };\n    t.contains = function (a) {\n        if (null === a) return !1;\n        var b = a;\n        return za(a) && (b = lb(a), void 0 === b) ? !1 : void 0 !== this.Eb[b]\n    };\n    t.has = function (a) {\n        return this.contains(a)\n    };\n    t.Uy = function (a) {\n        if (null === a) return !0;\n        for (a = a.iterator; a.next();)\n            if (!this.contains(a.value)) return !1;\n        return !0\n    };\n    t.Vy = function (a) {\n        if (null === a) return !0;\n        for (a = a.iterator; a.next();)\n            if (this.contains(a.value)) return !0;\n        return !1\n    };\n    t.first = function () {\n        var a = this.ba;\n        return null === a ? null : a.value\n    };\n    F.prototype.any = function (a) {\n        for (var b = this.ba; null !== b;) {\n            if (a(b.value)) return !0;\n            b = b.oa\n        }\n        return !1\n    };\n    F.prototype.all = function (a) {\n        for (var b = this.ba; null !== b;) {\n            if (!a(b.value)) return !1;\n            b = b.oa\n        }\n        return !0\n    };\n    F.prototype.each = function (a) {\n        for (var b = this.ba; null !== b;) a(b.value), b = b.oa;\n        return this\n    };\n    F.prototype.map = function (a) {\n        for (var b = new F, c = this.ba; null !== c;) b.add(a(c.value)), c = c.oa;\n        return b\n    };\n    F.prototype.filter = function (a) {\n        for (var b = new F, c = this.ba; null !== c;) {\n            var d = c.value;\n            a(d) && b.add(d);\n            c = c.oa\n        }\n        return b\n    };\n    t = F.prototype;\n    t.remove = function (a) {\n        if (null === a) return !1;\n        this.s && ua(this, a);\n        var b = a;\n        if (za(a) && (b = lb(a), void 0 === b)) return !1;\n        a = this.Eb[b];\n        if (void 0 === a) return !1;\n        var c = a.oa,\n            d = a.Dl;\n        null !== c && (c.Dl = d);\n        null !== d && (d.oa = c);\n        this.ba === a && (this.ba = c);\n        this.Ue === a && (this.Ue = d);\n        delete this.Eb[b];\n        this.Cb--;\n        this.ib();\n        return !0\n    };\n    t.delete = function (a) {\n        return this.remove(a)\n    };\n    t.Fq = function (a) {\n        if (null === a) return this;\n        this.s && ua(this);\n        if (Aa(a))\n            for (var b = a.length, c = 0; c < b; c++) this.remove(a[c]);\n        else\n            for (a = a.iterator; a.next();) this.remove(a.value);\n        return this\n    };\n    t.qA = function (a) {\n        if (null === a || 0 === this.count) return this;\n        this.s && ua(this);\n        var b = new F;\n        b.addAll(a);\n        a = [];\n        for (var c = this.iterator; c.next();) {\n            var d = c.value;\n            b.contains(d) || a.push(d)\n        }\n        this.Fq(a);\n        return this\n    };\n    t.clear = function () {\n        this.s && ua(this);\n        this.Eb = {};\n        this.Cb = 0;\n        null !== this.Fa && this.Fa.reset();\n        this.Ue = this.ba = null;\n        this.ib()\n    };\n    F.prototype.copy = function () {\n        var a = new F,\n            b = this.Eb,\n            c;\n        for (c in b) a.add(b[c].value);\n        return a\n    };\n    F.prototype.na = function () {\n        var a = Array(this.Cb),\n            b = this.Eb,\n            c = 0,\n            d;\n        for (d in b) a[c] = b[d].value, c++;\n        return a\n    };\n    F.prototype.lw = function () {\n        var a = new E,\n            b = this.Eb,\n            c;\n        for (c in b) a.add(b[c].value);\n        return a\n    };\n\n    function Ya(a) {\n        a.__gohashid = pb++\n    }\n\n    function nb(a) {\n        var b = a.__gohashid;\n        void 0 === b && (b = pb++, a.__gohashid = b);\n        return b\n    }\n\n    function lb(a) {\n        return a.__gohashid\n    }\n    ma.Object.defineProperties(F.prototype, {\n        count: {\n            get: function () {\n                return this.Cb\n            }\n        },\n        size: {\n            get: function () {\n                return this.Cb\n            }\n        },\n        iterator: {\n            get: function () {\n                if (0 >= this.Cb) return fb;\n                var a = this.Fa;\n                return null !== a ? (a.reset(), a) : new mb(this)\n            }\n        }\n    });\n    F.prototype.toList = F.prototype.lw;\n    F.prototype.toArray = F.prototype.na;\n    F.prototype.clear = F.prototype.clear;\n    F.prototype.retainAll = F.prototype.qA;\n    F.prototype.removeAll = F.prototype.Fq;\n    F.prototype[\"delete\"] = F.prototype.delete;\n    F.prototype.remove = F.prototype.remove;\n    F.prototype.first = F.prototype.first;\n    F.prototype.containsAny = F.prototype.Vy;\n    F.prototype.containsAll = F.prototype.Uy;\n    F.prototype.has = F.prototype.has;\n    F.prototype.contains = F.prototype.contains;\n    F.prototype.addAll = F.prototype.addAll;\n    F.prototype.add = F.prototype.add;\n    F.prototype.thaw = F.prototype.ea;\n    F.prototype.freeze = F.prototype.freeze;\n    var pb = 1;\n    F.className = \"Set\";\n    F.uniqueHash = Ya;\n    F.hashIdUnique = nb;\n    F.hashId = lb;\n\n    function rb(a) {\n        this.fa = a;\n        this.ia = a.Aa;\n        this.la = null\n    }\n    rb.prototype.reset = function () {\n        this.ia = this.fa.Aa;\n        this.la = null\n    };\n    rb.prototype.next = function () {\n        var a = this.fa;\n        if (a.Aa !== this.ia && null === this.key) return !1;\n        var b = this.la;\n        b = null === b ? a.ba : b.oa;\n        if (null !== b) return this.la = b, this.value = this.key = a = b.key, !0;\n        this.Bd();\n        return !1\n    };\n    rb.prototype.ed = function () {\n        return this.next()\n    };\n    rb.prototype.first = function () {\n        var a = this.fa;\n        this.ia = a.Aa;\n        a = a.ba;\n        return null !== a ? (this.la = a, this.value = this.key = a = a.key) : null\n    };\n    rb.prototype.any = function (a) {\n        var b = this.fa;\n        this.la = null;\n        for (b = b.ba; null !== b;) {\n            if (a(b.key)) return !0;\n            b = b.oa\n        }\n        return !1\n    };\n    rb.prototype.all = function (a) {\n        var b = this.fa;\n        this.la = null;\n        for (b = b.ba; null !== b;) {\n            if (!a(b.key)) return !1;\n            b = b.oa\n        }\n        return !0\n    };\n    rb.prototype.each = function (a) {\n        var b = this.fa;\n        this.la = null;\n        for (b = b.ba; null !== b;) a(b.key), b = b.oa;\n        return this\n    };\n    rb.prototype.map = function (a) {\n        var b = this.fa;\n        this.la = null;\n        var c = new E;\n        for (b = b.ba; null !== b;) c.add(a(b.key)), b = b.oa;\n        return c.iterator\n    };\n    rb.prototype.filter = function (a) {\n        var b = this.fa;\n        this.la = null;\n        var c = new E;\n        for (b = b.ba; null !== b;) {\n            var d = b.key;\n            a(d) && c.add(d);\n            b = b.oa\n        }\n        return c.iterator\n    };\n    rb.prototype.Bd = function () {\n        this.value = this.key = null;\n        this.ia = -1\n    };\n    rb.prototype.toString = function () {\n        return null !== this.la ? \"MapKeySetIterator@\" + this.la.value : \"MapKeySetIterator\"\n    };\n    ma.Object.defineProperties(rb.prototype, {\n        iterator: {\n            get: function () {\n                return this\n            }\n        },\n        count: {\n            get: function () {\n                return this.fa.Cb\n            }\n        }\n    });\n    rb.prototype.first = rb.prototype.first;\n    rb.prototype.hasNext = rb.prototype.ed;\n    rb.prototype.next = rb.prototype.next;\n    rb.prototype.reset = rb.prototype.reset;\n    rb.className = \"MapKeySetIterator\";\n\n    function sb(a) {\n        F.call(this);\n        Ya(this);\n        this.s = !0;\n        this.fa = a\n    }\n    la(sb, F);\n    t = sb.prototype;\n    t.freeze = function () {\n        return this\n    };\n    t.ea = function () {\n        return this\n    };\n    t.toString = function () {\n        return \"MapKeySet(\" + this.fa.toString() + \")\"\n    };\n    t.add = function () {\n        B(\"This Set is read-only: \" + this.toString());\n        return this\n    };\n    t.contains = function (a) {\n        return this.fa.contains(a)\n    };\n    t.has = function (a) {\n        return this.contains(a)\n    };\n    t.remove = function () {\n        B(\"This Set is read-only: \" + this.toString());\n        return !1\n    };\n    t.delete = function (a) {\n        return this.remove(a)\n    };\n    t.clear = function () {\n        B(\"This Set is read-only: \" + this.toString())\n    };\n    t.first = function () {\n        var a = this.fa.ba;\n        return null !== a ? a.key : null\n    };\n    sb.prototype.any = function (a) {\n        for (var b = this.fa.ba; null !== b;) {\n            if (a(b.key)) return !0;\n            b = b.oa\n        }\n        return !1\n    };\n    sb.prototype.all = function (a) {\n        for (var b = this.fa.ba; null !== b;) {\n            if (!a(b.key)) return !1;\n            b = b.oa\n        }\n        return !0\n    };\n    sb.prototype.each = function (a) {\n        for (var b = this.fa.ba; null !== b;) a(b.key), b = b.oa;\n        return this\n    };\n    sb.prototype.map = function (a) {\n        for (var b = new F, c = this.fa.ba; null !== c;) b.add(a(c.key)), c = c.oa;\n        return b\n    };\n    sb.prototype.filter = function (a) {\n        for (var b = new F, c = this.fa.ba; null !== c;) {\n            var d = c.key;\n            a(d) && b.add(d);\n            c = c.oa\n        }\n        return b\n    };\n    sb.prototype.copy = function () {\n        return new sb(this.fa)\n    };\n    sb.prototype.mw = function () {\n        var a = new F,\n            b = this.fa.Eb,\n            c;\n        for (c in b) a.add(b[c].key);\n        return a\n    };\n    sb.prototype.na = function () {\n        var a = this.fa.Eb,\n            b = Array(this.fa.Cb),\n            c = 0,\n            d;\n        for (d in a) b[c] = a[d].key, c++;\n        return b\n    };\n    sb.prototype.lw = function () {\n        var a = new E,\n            b = this.fa.Eb,\n            c;\n        for (c in b) a.add(b[c].key);\n        return a\n    };\n    ma.Object.defineProperties(sb.prototype, {\n        count: {\n            get: function () {\n                return this.fa.Cb\n            }\n        },\n        size: {\n            get: function () {\n                return this.fa.Cb\n            }\n        },\n        iterator: {\n            get: function () {\n                return 0 >= this.fa.Cb ? fb : new rb(this.fa)\n            }\n        }\n    });\n    sb.prototype.toList = sb.prototype.lw;\n    sb.prototype.toArray = sb.prototype.na;\n    sb.prototype.toSet = sb.prototype.mw;\n    sb.prototype.first = sb.prototype.first;\n    sb.prototype.clear = sb.prototype.clear;\n    sb.prototype[\"delete\"] = sb.prototype.delete;\n    sb.prototype.remove = sb.prototype.remove;\n    sb.prototype.has = sb.prototype.has;\n    sb.prototype.contains = sb.prototype.contains;\n    sb.prototype.add = sb.prototype.add;\n    sb.prototype.thaw = sb.prototype.ea;\n    sb.prototype.freeze = sb.prototype.freeze;\n    sb.className = \"MapKeySet\";\n\n    function tb(a) {\n        this.fa = a;\n        a.Te = null;\n        this.ia = a.Aa;\n        this.la = null\n    }\n    tb.prototype.reset = function () {\n        var a = this.fa;\n        a.Te = null;\n        this.ia = a.Aa;\n        this.la = null\n    };\n    tb.prototype.next = function () {\n        var a = this.fa;\n        if (a.Aa !== this.ia && null === this.key) return !1;\n        var b = this.la;\n        b = null === b ? a.ba : b.oa;\n        if (null !== b) return this.la = b, this.value = b.value, this.key = b.key, !0;\n        this.Bd();\n        return !1\n    };\n    tb.prototype.ed = function () {\n        return this.next()\n    };\n    tb.prototype.first = function () {\n        var a = this.fa;\n        this.ia = a.Aa;\n        a = a.ba;\n        if (null !== a) {\n            this.la = a;\n            var b = a.value;\n            this.key = a.key;\n            return this.value = b\n        }\n        return null\n    };\n    tb.prototype.any = function (a) {\n        var b = this.fa;\n        this.la = b.Te = null;\n        for (b = b.ba; null !== b;) {\n            if (a(b.value)) return !0;\n            b = b.oa\n        }\n        return !1\n    };\n    tb.prototype.all = function (a) {\n        var b = this.fa;\n        this.la = b.Te = null;\n        for (b = b.ba; null !== b;) {\n            if (!a(b.value)) return !1;\n            b = b.oa\n        }\n        return !0\n    };\n    tb.prototype.each = function (a) {\n        var b = this.fa;\n        this.la = b.Te = null;\n        for (b = b.ba; null !== b;) a(b.value), b = b.oa;\n        return this\n    };\n    tb.prototype.map = function (a) {\n        var b = this.fa;\n        this.la = b.Te = null;\n        var c = new E;\n        for (b = b.ba; null !== b;) c.add(a(b.value)), b = b.oa;\n        return c.iterator\n    };\n    tb.prototype.filter = function (a) {\n        var b = this.fa;\n        this.la = b.Te = null;\n        var c = new E;\n        for (b = b.ba; null !== b;) {\n            var d = b.value;\n            a(d) && c.add(d);\n            b = b.oa\n        }\n        return c.iterator\n    };\n    tb.prototype.Bd = function () {\n        this.value = this.key = null;\n        this.ia = -1;\n        this.fa.Te = this\n    };\n    tb.prototype.toString = function () {\n        return null !== this.la ? \"MapValueSetIterator@\" + this.la.value : \"MapValueSetIterator\"\n    };\n    ma.Object.defineProperties(tb.prototype, {\n        iterator: {\n            get: function () {\n                return this\n            }\n        },\n        count: {\n            get: function () {\n                return this.fa.Cb\n            }\n        }\n    });\n    tb.prototype.first = tb.prototype.first;\n    tb.prototype.hasNext = tb.prototype.ed;\n    tb.prototype.next = tb.prototype.next;\n    tb.prototype.reset = tb.prototype.reset;\n    tb.className = \"MapValueSetIterator\";\n\n    function ob(a, b) {\n        this.key = a;\n        this.value = b;\n        this.Dl = this.oa = null\n    }\n    ob.prototype.toString = function () {\n        return \"{\" + this.key + \":\" + this.value + \"}\"\n    };\n    ob.className = \"KeyValuePair\";\n\n    function ub(a) {\n        this.fa = a;\n        a.Fa = null;\n        this.ia = a.Aa;\n        this.la = null\n    }\n    ub.prototype.reset = function () {\n        var a = this.fa;\n        a.Fa = null;\n        this.ia = a.Aa;\n        this.la = null\n    };\n    ub.prototype.next = function () {\n        var a = this.fa;\n        if (a.Aa !== this.ia && null === this.key) return !1;\n        var b = this.la;\n        b = null === b ? a.ba : b.oa;\n        if (null !== b) return this.la = b, this.key = b.key, this.value = b.value, !0;\n        this.Bd();\n        return !1\n    };\n    ub.prototype.ed = function () {\n        return this.next()\n    };\n    ub.prototype.first = function () {\n        var a = this.fa;\n        this.ia = a.Aa;\n        a = a.ba;\n        return null !== a ? (this.la = a, this.key = a.key, this.value = a.value, a) : null\n    };\n    ub.prototype.any = function (a) {\n        var b = this.fa;\n        this.la = b.Fa = null;\n        for (b = b.ba; null !== b;) {\n            if (a(b)) return !0;\n            b = b.oa\n        }\n        return !1\n    };\n    ub.prototype.all = function (a) {\n        var b = this.fa;\n        this.la = b.Fa = null;\n        for (b = b.ba; null !== b;) {\n            if (!a(b)) return !1;\n            b = b.oa\n        }\n        return !0\n    };\n    ub.prototype.each = function (a) {\n        var b = this.fa;\n        this.la = b.Fa = null;\n        for (b = b.ba; null !== b;) a(b), b = b.oa;\n        return this\n    };\n    ub.prototype.map = function (a) {\n        var b = this.fa;\n        this.la = b.Fa = null;\n        var c = new E;\n        for (b = b.ba; null !== b;) c.add(a(b)), b = b.oa;\n        return c.iterator\n    };\n    ub.prototype.filter = function (a) {\n        var b = this.fa;\n        this.la = b.Fa = null;\n        var c = new E;\n        for (b = b.ba; null !== b;) a(b) && c.add(b), b = b.oa;\n        return c.iterator\n    };\n    ub.prototype.Bd = function () {\n        this.value = this.key = null;\n        this.ia = -1;\n        this.fa.Fa = this\n    };\n    ub.prototype.toString = function () {\n        return null !== this.la ? \"MapIterator@\" + this.la : \"MapIterator\"\n    };\n    ma.Object.defineProperties(ub.prototype, {\n        iterator: {\n            get: function () {\n                return this\n            }\n        },\n        count: {\n            get: function () {\n                return this.fa.Cb\n            }\n        }\n    });\n    ub.prototype.first = ub.prototype.first;\n    ub.prototype.hasNext = ub.prototype.ed;\n    ub.prototype.next = ub.prototype.next;\n    ub.prototype.reset = ub.prototype.reset;\n    ub.className = \"MapIterator\";\n\n    function H(a) {\n        Ya(this);\n        this.s = !1;\n        this.Eb = {};\n        this.Cb = 0;\n        this.Te = this.Fa = null;\n        this.Aa = 0;\n        this.Ue = this.ba = null;\n        void 0 !== a && (\"function\" === typeof a || \"string\" === typeof a ? ya() : this.addAll(a))\n    }\n    t = H.prototype;\n    t.ib = function () {\n        var a = this.Aa;\n        a++;\n        999999999 < a && (a = 0);\n        this.Aa = a\n    };\n    t.freeze = function () {\n        this.s = !0;\n        return this\n    };\n    t.ea = function () {\n        this.s = !1;\n        return this\n    };\n    t.toString = function () {\n        return \"Map()#\" + lb(this)\n    };\n    t.add = function (a, b) {\n        this.s && ua(this, a);\n        var c = a;\n        za(a) && (c = nb(a));\n        var d = this.Eb[c];\n        void 0 === d ? (this.Cb++, a = new ob(a, b), this.Eb[c] = a, c = this.Ue, null === c ? this.ba = a : (a.Dl = c, c.oa = a), this.Ue = a, this.ib()) : d.value = b;\n        return this\n    };\n    t.set = function (a, b) {\n        return this.add(a, b)\n    };\n    t.addAll = function (a) {\n        if (null === a) return this;\n        if (Aa(a))\n            for (var b = a.length, c = 0; c < b; c++) {\n                var d = a[c];\n                this.add(d.key, d.value)\n            } else if (a instanceof H)\n                for (a = a.iterator; a.next();) this.add(a.key, a.value);\n            else\n                for (a = a.iterator; a.next();) b = a.value, this.add(b.key, b.value);\n        return this\n    };\n    t.first = function () {\n        return this.ba\n    };\n    H.prototype.any = function (a) {\n        for (var b = this.ba; null !== b;) {\n            if (a(b)) return !0;\n            b = b.oa\n        }\n        return !1\n    };\n    H.prototype.all = function (a) {\n        for (var b = this.ba; null !== b;) {\n            if (!a(b)) return !1;\n            b = b.oa\n        }\n        return !0\n    };\n    H.prototype.each = function (a) {\n        for (var b = this.ba; null !== b;) a(b), b = b.oa;\n        return this\n    };\n    H.prototype.map = function (a) {\n        for (var b = new H, c = this.ba; null !== c;) b.add(c.key, a(c)), c = c.oa;\n        return b\n    };\n    H.prototype.filter = function (a) {\n        for (var b = new H, c = this.ba; null !== c;) a(c) && b.add(c.key, c.value), c = c.oa;\n        return b\n    };\n    t = H.prototype;\n    t.contains = function (a) {\n        var b = a;\n        return za(a) && (b = lb(a), void 0 === b) ? !1 : void 0 !== this.Eb[b]\n    };\n    t.has = function (a) {\n        return this.contains(a)\n    };\n    t.H = function (a) {\n        var b = a;\n        if (za(a) && (b = lb(a), void 0 === b)) return null;\n        a = this.Eb[b];\n        return void 0 === a ? null : a.value\n    };\n    t.get = function (a) {\n        return this.H(a)\n    };\n    t.remove = function (a) {\n        if (null === a) return !1;\n        this.s && ua(this, a);\n        var b = a;\n        if (za(a) && (b = lb(a), void 0 === b)) return !1;\n        a = this.Eb[b];\n        if (void 0 === a) return !1;\n        var c = a.oa,\n            d = a.Dl;\n        null !== c && (c.Dl = d);\n        null !== d && (d.oa = c);\n        this.ba === a && (this.ba = c);\n        this.Ue === a && (this.Ue = d);\n        delete this.Eb[b];\n        this.Cb--;\n        this.ib();\n        return !0\n    };\n    t.delete = function (a) {\n        return this.remove(a)\n    };\n    t.clear = function () {\n        this.s && ua(this);\n        this.Eb = {};\n        this.Cb = 0;\n        null !== this.Fa && this.Fa.reset();\n        null !== this.Te && this.Te.reset();\n        this.Ue = this.ba = null;\n        this.ib()\n    };\n    H.prototype.copy = function () {\n        var a = new H,\n            b = this.Eb,\n            c;\n        for (c in b) {\n            var d = b[c];\n            a.add(d.key, d.value)\n        }\n        return a\n    };\n    H.prototype.na = function () {\n        var a = this.Eb,\n            b = Array(this.Cb),\n            c = 0,\n            d;\n        for (d in a) {\n            var e = a[d];\n            b[c] = new ob(e.key, e.value);\n            c++\n        }\n        return b\n    };\n    H.prototype.Df = function () {\n        return new sb(this)\n    };\n    ma.Object.defineProperties(H.prototype, {\n        count: {\n            get: function () {\n                return this.Cb\n            }\n        },\n        size: {\n            get: function () {\n                return this.Cb\n            }\n        },\n        iterator: {\n            get: function () {\n                if (0 >= this.count) return fb;\n                var a = this.Fa;\n                return null !== a ? (a.reset(), a) : new ub(this)\n            }\n        },\n        iteratorKeys: {\n            get: function () {\n                return 0 >= this.count ? fb : new rb(this)\n            }\n        },\n        iteratorValues: {\n            get: function () {\n                if (0 >= this.count) return fb;\n                var a = this.Te;\n                return null !== a ? (a.reset(), a) : new tb(this)\n            }\n        }\n    });\n    H.prototype.toKeySet = H.prototype.Df;\n    H.prototype.toArray = H.prototype.na;\n    H.prototype.clear = H.prototype.clear;\n    H.prototype[\"delete\"] = H.prototype.delete;\n    H.prototype.remove = H.prototype.remove;\n    H.prototype.get = H.prototype.get;\n    H.prototype.getValue = H.prototype.H;\n    H.prototype.has = H.prototype.has;\n    H.prototype.contains = H.prototype.contains;\n    H.prototype.first = H.prototype.first;\n    H.prototype.addAll = H.prototype.addAll;\n    H.prototype.set = H.prototype.set;\n    H.prototype.add = H.prototype.add;\n    H.prototype.thaw = H.prototype.ea;\n    H.prototype.freeze = H.prototype.freeze;\n    H.className = \"Map\";\n\n    function I(a, b) {\n        void 0 === a ? this.y = this.x = 0 : \"number\" === typeof a && \"number\" === typeof b ? (this.x = a, this.y = b) : B(\"Invalid arguments to Point constructor: \" + a + \", \" + b);\n        this.s = !1\n    }\n    I.prototype.assign = function (a) {\n        this.x = a.x;\n        this.y = a.y;\n        return this\n    };\n    I.prototype.h = function (a, b) {\n        this.x = a;\n        this.y = b;\n        return this\n    };\n    I.prototype.Fg = function (a, b) {\n        this.x = a;\n        this.y = b;\n        return this\n    };\n    I.prototype.set = function (a) {\n        this.x = a.x;\n        this.y = a.y;\n        return this\n    };\n    I.prototype.copy = function () {\n        var a = new I;\n        a.x = this.x;\n        a.y = this.y;\n        return a\n    };\n    t = I.prototype;\n    t.ca = function () {\n        this.s = !0;\n        Object.freeze(this);\n        return this\n    };\n    t.G = function () {\n        return this.s || Object.isFrozen(this) ? this : this.copy().freeze()\n    };\n    t.freeze = function () {\n        this.s = !0;\n        return this\n    };\n    t.ea = function () {\n        Object.isFrozen(this) && B(\"cannot thaw constant: \" + this);\n        this.s = !1;\n        return this\n    };\n\n    function vb(a) {\n        if (\"string\" === typeof a) {\n            a = a.split(\" \");\n            for (var b = 0, c = 0;\n                \"\" === a[b];) b++;\n            var d = a[b++];\n            d && (c = parseFloat(d));\n            for (var e = 0;\n                \"\" === a[b];) b++;\n            (d = a[b++]) && (e = parseFloat(d));\n            return new I(c, e)\n        }\n        return new I\n    }\n\n    function wb(a) {\n        return a.x.toString() + \" \" + a.y.toString()\n    }\n    t.toString = function () {\n        return \"Point(\" + this.x + \",\" + this.y + \")\"\n    };\n    t.w = function (a) {\n        return a instanceof I ? this.x === a.x && this.y === a.y : !1\n    };\n    t.Ri = function (a, b) {\n        return this.x === a && this.y === b\n    };\n    t.Ma = function (a) {\n        return J.A(this.x, a.x) && J.A(this.y, a.y)\n    };\n    t.add = function (a) {\n        this.x += a.x;\n        this.y += a.y;\n        return this\n    };\n    t.Zd = function (a) {\n        this.x -= a.x;\n        this.y -= a.y;\n        return this\n    };\n    t.offset = function (a, b) {\n        this.x += a;\n        this.y += b;\n        return this\n    };\n    I.prototype.rotate = function (a) {\n        if (0 === a) return this;\n        var b = this.x,\n            c = this.y;\n        if (0 === b && 0 === c) return this;\n        360 <= a ? a -= 360 : 0 > a && (a += 360);\n        if (90 === a) {\n            a = 0;\n            var d = 1\n        } else 180 === a ? (a = -1, d = 0) : 270 === a ? (a = 0, d = -1) : (d = a * Math.PI / 180, a = Math.cos(d), d = Math.sin(d));\n        this.x = a * b - d * c;\n        this.y = d * b + a * c;\n        return this\n    };\n    t = I.prototype;\n    t.scale = function (a, b) {\n        this.x *= a;\n        this.y *= b;\n        return this\n    };\n    t.Ae = function (a) {\n        var b = a.x - this.x;\n        a = a.y - this.y;\n        return b * b + a * a\n    };\n    t.dd = function (a, b) {\n        a -= this.x;\n        b -= this.y;\n        return a * a + b * b\n    };\n    t.normalize = function () {\n        var a = this.x,\n            b = this.y,\n            c = Math.sqrt(a * a + b * b);\n        0 < c && (this.x = a / c, this.y = b / c);\n        return this\n    };\n    t.Ta = function (a) {\n        return yb(a.x - this.x, a.y - this.y)\n    };\n    t.direction = function (a, b) {\n        return yb(a - this.x, b - this.y)\n    };\n\n    function yb(a, b) {\n        if (0 === a) return 0 < b ? 90 : 0 > b ? 270 : 0;\n        if (0 === b) return 0 < a ? 0 : 180;\n        if (isNaN(a) || isNaN(b)) return 0;\n        var c = 180 * Math.atan(Math.abs(b / a)) / Math.PI;\n        0 > a ? c = 0 > b ? c + 180 : 180 - c : 0 > b && (c = 360 - c);\n        return c\n    }\n    t.kA = function (a, b, c, d) {\n        J.Lh(a, b, c, d, this.x, this.y, this);\n        return this\n    };\n    t.lA = function (a, b) {\n        J.Lh(a.x, a.y, b.x, b.y, this.x, this.y, this);\n        return this\n    };\n    t.wA = function (a, b, c, d) {\n        J.mq(this.x, this.y, a, b, c, d, this);\n        return this\n    };\n    t.xA = function (a, b) {\n        J.mq(this.x, this.y, a.x, a.y, b.width, b.height, this);\n        return this\n    };\n    t.dj = function (a, b) {\n        this.x = a.x + b.x * a.width + b.offsetX;\n        this.y = a.y + b.y * a.height + b.offsetY;\n        return this\n    };\n    t.xk = function (a, b, c, d, e) {\n        this.x = a + e.x * c + e.offsetX;\n        this.y = b + e.y * d + e.offsetY;\n        return this\n    };\n    t.transform = function (a) {\n        a.ra(this);\n        return this\n    };\n\n    function zb(a, b) {\n        b.Vd(a);\n        return a\n    }\n\n    function Ab(a, b, c, d, e, f) {\n        var g = e - c,\n            h = f - d,\n            k = g * g + h * h;\n        c -= a;\n        d -= b;\n        var l = -c * g - d * h;\n        if (0 >= l || l >= k) return g = e - a, h = f - b, Math.min(c * c + d * d, g * g + h * h);\n        a = g * d - h * c;\n        return a * a / k\n    }\n\n    function Bb(a, b, c, d) {\n        a = c - a;\n        b = d - b;\n        return a * a + b * b\n    }\n\n    function Cb(a, b, c, d) {\n        a = c - a;\n        b = d - b;\n        if (0 === a) return 0 < b ? 90 : 0 > b ? 270 : 0;\n        if (0 === b) return 0 < a ? 0 : 180;\n        if (isNaN(a) || isNaN(b)) return 0;\n        d = 180 * Math.atan(Math.abs(b / a)) / Math.PI;\n        0 > a ? d = 0 > b ? d + 180 : 180 - d : 0 > b && (d = 360 - d);\n        return d\n    }\n    t.v = function () {\n        return isFinite(this.x) && isFinite(this.y)\n    };\n    I.alloc = function () {\n        var a = Db.pop();\n        return void 0 === a ? new I : a\n    };\n    I.allocAt = function (a, b) {\n        var c = Db.pop();\n        if (void 0 === c) return new I(a, b);\n        c.x = a;\n        c.y = b;\n        return c\n    };\n    I.free = function (a) {\n        Db.push(a)\n    };\n    I.prototype.isReal = I.prototype.v;\n    I.prototype.setSpot = I.prototype.xk;\n    I.prototype.setRectSpot = I.prototype.dj;\n    I.prototype.snapToGridPoint = I.prototype.xA;\n    I.prototype.snapToGrid = I.prototype.wA;\n    I.prototype.projectOntoLineSegmentPoint = I.prototype.lA;\n    I.prototype.projectOntoLineSegment = I.prototype.kA;\n    I.intersectingLineSegments = function (a, b, c, d, e, f, g, h) {\n        return J.sq(a, b, c, d, e, f, g, h)\n    };\n    I.prototype.direction = I.prototype.direction;\n    I.prototype.directionPoint = I.prototype.Ta;\n    I.prototype.normalize = I.prototype.normalize;\n    I.prototype.distanceSquared = I.prototype.dd;\n    I.prototype.distanceSquaredPoint = I.prototype.Ae;\n    I.prototype.scale = I.prototype.scale;\n    I.prototype.rotate = I.prototype.rotate;\n    I.prototype.offset = I.prototype.offset;\n    I.prototype.subtract = I.prototype.Zd;\n    I.prototype.add = I.prototype.add;\n    I.prototype.equalsApprox = I.prototype.Ma;\n    I.prototype.equalTo = I.prototype.Ri;\n    I.prototype.equals = I.prototype.w;\n    I.prototype.set = I.prototype.set;\n    I.prototype.setTo = I.prototype.Fg;\n    var Fb = null,\n        Gb = null,\n        Hb = null,\n        Ib = null,\n        Jb = null,\n        Db = [];\n    I.className = \"Point\";\n    I.parse = vb;\n    I.stringify = wb;\n    I.distanceLineSegmentSquared = Ab;\n    I.distanceSquared = Bb;\n    I.direction = Cb;\n    I.Origin = Fb = (new I(0, 0)).ca();\n    I.InfiniteTopLeft = Gb = (new I(-Infinity, -Infinity)).ca();\n    I.InfiniteBottomRight = Hb = (new I(Infinity, Infinity)).ca();\n    I.SixPoint = Ib = (new I(6, 6)).ca();\n    I.NoPoint = Jb = (new I(NaN, NaN)).ca();\n    I.parse = vb;\n    I.stringify = wb;\n    I.distanceLineSegmentSquared = Ab;\n    I.distanceSquared = Bb;\n    I.direction = Cb;\n\n    function M(a, b) {\n        void 0 === a ? this.height = this.width = 0 : \"number\" === typeof a && (0 <= a || isNaN(a)) && \"number\" === typeof b && (0 <= b || isNaN(b)) ? (this.width = a, this.height = b) : B(\"Invalid arguments to Size constructor: \" + a + \", \" + b);\n        this.s = !1\n    }\n    var Kb, Lb, Mb, Nb, Ob, Pb, Rb;\n    M.prototype.assign = function (a) {\n        this.width = a.width;\n        this.height = a.height;\n        return this\n    };\n    M.prototype.h = function (a, b) {\n        this.width = a;\n        this.height = b;\n        return this\n    };\n    M.prototype.Fg = function (a, b) {\n        this.width = a;\n        this.height = b;\n        return this\n    };\n    M.prototype.set = function (a) {\n        this.width = a.width;\n        this.height = a.height;\n        return this\n    };\n    M.prototype.copy = function () {\n        var a = new M;\n        a.width = this.width;\n        a.height = this.height;\n        return a\n    };\n    t = M.prototype;\n    t.ca = function () {\n        this.s = !0;\n        Object.freeze(this);\n        return this\n    };\n    t.G = function () {\n        return this.s || Object.isFrozen(this) ? this : this.copy().freeze()\n    };\n    t.freeze = function () {\n        this.s = !0;\n        return this\n    };\n    t.ea = function () {\n        Object.isFrozen(this) && B(\"cannot thaw constant: \" + this);\n        this.s = !1;\n        return this\n    };\n\n    function Sb(a) {\n        if (\"string\" === typeof a) {\n            a = a.split(\" \");\n            for (var b = 0, c = 0;\n                \"\" === a[b];) b++;\n            var d = a[b++];\n            d && (c = parseFloat(d));\n            for (var e = 0;\n                \"\" === a[b];) b++;\n            (d = a[b++]) && (e = parseFloat(d));\n            return new M(c, e)\n        }\n        return new M\n    }\n\n    function Tb(a) {\n        return a.width.toString() + \" \" + a.height.toString()\n    }\n    t.toString = function () {\n        return \"Size(\" + this.width + \",\" + this.height + \")\"\n    };\n    t.w = function (a) {\n        return a instanceof M ? this.width === a.width && this.height === a.height : !1\n    };\n    t.Ri = function (a, b) {\n        return this.width === a && this.height === b\n    };\n    t.Ma = function (a) {\n        return J.A(this.width, a.width) && J.A(this.height, a.height)\n    };\n    t.v = function () {\n        return isFinite(this.width) && isFinite(this.height)\n    };\n    M.alloc = function () {\n        var a = Ub.pop();\n        return void 0 === a ? new M : a\n    };\n    M.free = function (a) {\n        Ub.push(a)\n    };\n    M.prototype.isReal = M.prototype.v;\n    M.prototype.equalsApprox = M.prototype.Ma;\n    M.prototype.equalTo = M.prototype.Ri;\n    M.prototype.equals = M.prototype.w;\n    M.prototype.set = M.prototype.set;\n    M.prototype.setTo = M.prototype.Fg;\n    var Ub = [];\n    M.className = \"Size\";\n    M.parse = Sb;\n    M.stringify = Tb;\n    M.ZeroSize = Kb = (new M(0, 0)).ca();\n    M.OneSize = Lb = (new M(1, 1)).ca();\n    M.SixSize = Mb = (new M(6, 6)).ca();\n    M.EightSize = Nb = (new M(8, 8)).ca();\n    M.TenSize = Ob = (new M(10, 10)).ca();\n    M.InfiniteSize = Pb = (new M(Infinity, Infinity)).ca();\n    M.NoSize = Rb = (new M(NaN, NaN)).ca();\n    M.parse = Sb;\n    M.stringify = Tb;\n\n    function N(a, b, c, d) {\n        void 0 === a ? this.height = this.width = this.y = this.x = 0 : a instanceof I ? (c = a.x, a = a.y, b instanceof I ? (d = b.x, b = b.y, this.x = Math.min(c, d), this.y = Math.min(a, b), this.width = Math.abs(c - d), this.height = Math.abs(a - b)) : b instanceof M ? (this.x = c, this.y = a, this.width = b.width, this.height = b.height) : B(\"Incorrect arguments supplied to Rect constructor\")) : \"number\" === typeof a && \"number\" === typeof b && \"number\" === typeof c && (0 <= c || isNaN(c)) && \"number\" === typeof d && (0 <= d || isNaN(d)) ? (this.x = a, this.y = b, this.width = c,\n            this.height = d) : B(\"Invalid arguments to Rect constructor: \" + a + \", \" + b + \", \" + c + \", \" + d);\n        this.s = !1\n    }\n    t = N.prototype;\n    t.assign = function (a) {\n        this.x = a.x;\n        this.y = a.y;\n        this.width = a.width;\n        this.height = a.height;\n        return this\n    };\n    t.h = function (a, b, c, d) {\n        this.x = a;\n        this.y = b;\n        this.width = c;\n        this.height = d;\n        return this\n    };\n\n    function Vb(a, b, c) {\n        a.width = b;\n        a.height = c\n    }\n    t.Fg = function (a, b, c, d) {\n        this.x = a;\n        this.y = b;\n        this.width = c;\n        this.height = d;\n        return this\n    };\n    t.set = function (a) {\n        this.x = a.x;\n        this.y = a.y;\n        this.width = a.width;\n        this.height = a.height;\n        return this\n    };\n    t.hd = function (a) {\n        this.x = a.x;\n        this.y = a.y;\n        return this\n    };\n    t.uA = function (a) {\n        this.width = a.width;\n        this.height = a.height;\n        return this\n    };\n    N.prototype.copy = function () {\n        var a = new N;\n        a.x = this.x;\n        a.y = this.y;\n        a.width = this.width;\n        a.height = this.height;\n        return a\n    };\n    t = N.prototype;\n    t.ca = function () {\n        this.s = !0;\n        Object.freeze(this);\n        return this\n    };\n    t.G = function () {\n        return this.s || Object.isFrozen(this) ? this : this.copy().freeze()\n    };\n    t.freeze = function () {\n        this.s = !0;\n        return this\n    };\n    t.ea = function () {\n        Object.isFrozen(this) && B(\"cannot thaw constant: \" + this);\n        this.s = !1;\n        return this\n    };\n\n    function Wb(a) {\n        if (\"string\" === typeof a) {\n            a = a.split(\" \");\n            for (var b = 0, c = 0;\n                \"\" === a[b];) b++;\n            var d = a[b++];\n            d && (c = parseFloat(d));\n            for (var e = 0;\n                \"\" === a[b];) b++;\n            (d = a[b++]) && (e = parseFloat(d));\n            for (var f = 0;\n                \"\" === a[b];) b++;\n            (d = a[b++]) && (f = parseFloat(d));\n            for (var g = 0;\n                \"\" === a[b];) b++;\n            (d = a[b++]) && (g = parseFloat(d));\n            return new N(c, e, f, g)\n        }\n        return new N\n    }\n\n    function Zb(a) {\n        return a.x.toString() + \" \" + a.y.toString() + \" \" + a.width.toString() + \" \" + a.height.toString()\n    }\n    t.toString = function () {\n        return \"Rect(\" + this.x + \",\" + this.y + \",\" + this.width + \",\" + this.height + \")\"\n    };\n    t.w = function (a) {\n        return a instanceof N ? this.x === a.x && this.y === a.y && this.width === a.width && this.height === a.height : !1\n    };\n    t.Ri = function (a, b, c, d) {\n        return this.x === a && this.y === b && this.width === c && this.height === d\n    };\n    t.Ma = function (a) {\n        return J.A(this.x, a.x) && J.A(this.y, a.y) && J.A(this.width, a.width) && J.A(this.height, a.height)\n    };\n\n    function $b(a, b) {\n        return J.$(a.x, b.x) && J.$(a.y, b.y) && J.$(a.width, b.width) && J.$(a.height, b.height)\n    }\n    t.aa = function (a) {\n        return this.x <= a.x && this.x + this.width >= a.x && this.y <= a.y && this.y + this.height >= a.y\n    };\n    t.ze = function (a) {\n        return this.x <= a.x && a.x + a.width <= this.x + this.width && this.y <= a.y && a.y + a.height <= this.y + this.height\n    };\n    t.contains = function (a, b, c, d) {\n        void 0 === c && (c = 0);\n        void 0 === d && (d = 0);\n        return this.x <= a && a + c <= this.x + this.width && this.y <= b && b + d <= this.y + this.height\n    };\n    t.offset = function (a, b) {\n        this.x += a;\n        this.y += b;\n        return this\n    };\n    t.Vc = function (a, b) {\n        return ac(this, b, a, b, a)\n    };\n    t.cq = function (a) {\n        return ac(this, a.top, a.right, a.bottom, a.left)\n    };\n    t.kw = function (a) {\n        return ac(this, -a.top, -a.right, -a.bottom, -a.left)\n    };\n    t.Oz = function (a, b, c, d) {\n        return ac(this, a, b, c, d)\n    };\n\n    function ac(a, b, c, d, e) {\n        var f = a.width;\n        c + e <= -f ? (a.x += f / 2, a.width = 0) : (a.x -= e, a.width += c + e);\n        c = a.height;\n        b + d <= -c ? (a.y += c / 2, a.height = 0) : (a.y -= b, a.height += b + d);\n        return a\n    }\n    t.Sz = function (a) {\n        return bc(this, a.x, a.y, a.width, a.height)\n    };\n    t.Dv = function (a, b, c, d) {\n        return bc(this, a, b, c, d)\n    };\n\n    function bc(a, b, c, d, e) {\n        var f = Math.max(a.x, b),\n            g = Math.max(a.y, c);\n        b = Math.min(a.x + a.width, b + d);\n        c = Math.min(a.y + a.height, c + e);\n        a.x = f;\n        a.y = g;\n        a.width = Math.max(0, b - f);\n        a.height = Math.max(0, c - g);\n        return a\n    }\n    t.Gc = function (a) {\n        return this.Ev(a.x, a.y, a.width, a.height)\n    };\n    t.Ev = function (a, b, c, d) {\n        var e = this.width,\n            f = this.x;\n        if (Infinity !== e && Infinity !== c && (e += f, c += a, isNaN(c) || isNaN(e) || f > c || a > e)) return !1;\n        a = this.height;\n        c = this.y;\n        return Infinity !== a && Infinity !== d && (a += c, d += b, isNaN(d) || isNaN(a) || c > d || b > a) ? !1 : !0\n    };\n\n    function dc(a, b) {\n        var c = a.width,\n            d = a.x,\n            e = b.x - 10;\n        if (d > b.width + 10 + 10 + e || e > c + d) return !1;\n        c = a.height;\n        a = a.y;\n        d = b.y - 10;\n        return a > b.height + 10 + 10 + d || d > c + a ? !1 : !0\n    }\n    t.He = function (a) {\n        return ec(this, a.x, a.y, 0, 0)\n    };\n    t.Hc = function (a) {\n        return ec(this, a.x, a.y, a.width, a.height)\n    };\n    t.rw = function (a, b, c, d) {\n        void 0 === c && (c = 0);\n        void 0 === d && (d = 0);\n        return ec(this, a, b, c, d)\n    };\n\n    function ec(a, b, c, d, e) {\n        var f = Math.min(a.x, b),\n            g = Math.min(a.y, c);\n        b = Math.max(a.x + a.width, b + d);\n        c = Math.max(a.y + a.height, c + e);\n        a.x = f;\n        a.y = g;\n        a.width = b - f;\n        a.height = c - g;\n        return a\n    }\n    t.xk = function (a, b, c) {\n        this.x = a - c.offsetX - c.x * this.width;\n        this.y = b - c.offsetY - c.y * this.height;\n        return this\n    };\n\n    function fc(a, b, c, d, e, f, g, h) {\n        void 0 === g && (g = 0);\n        void 0 === h && (h = 0);\n        return a <= e && e + g <= a + c && b <= f && f + h <= b + d\n    }\n\n    function gc(a, b, c, d, e, f, g, h) {\n        return a > g + e || e > c + a ? !1 : b > h + f || f > d + b ? !1 : !0\n    }\n    t.v = function () {\n        return isFinite(this.x) && isFinite(this.y) && isFinite(this.width) && isFinite(this.height)\n    };\n    t.Uz = function () {\n        return 0 === this.width && 0 === this.height\n    };\n    N.alloc = function () {\n        var a = hc.pop();\n        return void 0 === a ? new N : a\n    };\n    N.allocAt = function (a, b, c, d) {\n        var e = hc.pop();\n        return void 0 === e ? new N(a, b, c, d) : e.h(a, b, c, d)\n    };\n    N.free = function (a) {\n        hc.push(a)\n    };\n    ma.Object.defineProperties(N.prototype, {\n        left: {\n            get: function () {\n                return this.x\n            },\n            set: function (a) {\n                this.x = a\n            }\n        },\n        top: {\n            get: function () {\n                return this.y\n            },\n            set: function (a) {\n                this.y = a\n            }\n        },\n        right: {\n            get: function () {\n                return this.x + this.width\n            },\n            set: function (a) {\n                this.x += a - (this.x + this.width)\n            }\n        },\n        bottom: {\n            get: function () {\n                return this.y + this.height\n            },\n            set: function (a) {\n                this.y += a - (this.y + this.height)\n            }\n        },\n        position: {\n            get: function () {\n                return new I(this.x, this.y)\n            },\n            set: function (a) {\n                this.x = a.x;\n                this.y = a.y\n            }\n        },\n        size: {\n            get: function () {\n                return new M(this.width, this.height)\n            },\n            set: function (a) {\n                this.width = a.width;\n                this.height = a.height\n            }\n        },\n        center: {\n            get: function () {\n                return new I(this.x + this.width / 2, this.y + this.height / 2)\n            },\n            set: function (a) {\n                this.x = a.x - this.width / 2;\n                this.y = a.y - this.height / 2\n            }\n        },\n        centerX: {\n            get: function () {\n                return this.x + this.width / 2\n            },\n            set: function (a) {\n                this.x = a - this.width / 2\n            }\n        },\n        centerY: {\n            get: function () {\n                return this.y + this.height / 2\n            },\n            set: function (a) {\n                this.y = a - this.height / 2\n            }\n        }\n    });\n    N.prototype.isEmpty = N.prototype.Uz;\n    N.prototype.isReal = N.prototype.v;\n    N.intersectsLineSegment = function (a, b, c, d, e, f, g, h) {\n        return J.Rx(a, b, c, d, e, f, g, h)\n    };\n    N.prototype.setSpot = N.prototype.xk;\n    N.prototype.union = N.prototype.rw;\n    N.prototype.unionRect = N.prototype.Hc;\n    N.prototype.unionPoint = N.prototype.He;\n    N.prototype.intersects = N.prototype.Ev;\n    N.prototype.intersectsRect = N.prototype.Gc;\n    N.prototype.intersect = N.prototype.Dv;\n    N.prototype.intersectRect = N.prototype.Sz;\n    N.prototype.grow = N.prototype.Oz;\n    N.prototype.subtractMargin = N.prototype.kw;\n    N.prototype.addMargin = N.prototype.cq;\n    N.prototype.inflate = N.prototype.Vc;\n    N.prototype.offset = N.prototype.offset;\n    N.prototype.contains = N.prototype.contains;\n    N.prototype.containsRect = N.prototype.ze;\n    N.prototype.containsPoint = N.prototype.aa;\n    N.prototype.equalsApprox = N.prototype.Ma;\n    N.prototype.equalTo = N.prototype.Ri;\n    N.prototype.equals = N.prototype.w;\n    N.prototype.setSize = N.prototype.uA;\n    N.prototype.setPoint = N.prototype.hd;\n    N.prototype.set = N.prototype.set;\n    N.prototype.setTo = N.prototype.Fg;\n    var ic = null,\n        nc = null,\n        hc = [];\n    N.className = \"Rect\";\n    N.parse = Wb;\n    N.stringify = Zb;\n    N.contains = fc;\n    N.intersects = gc;\n    N.ZeroRect = ic = (new N(0, 0, 0, 0)).ca();\n    N.NoRect = nc = (new N(NaN, NaN, NaN, NaN)).ca();\n    N.parse = Wb;\n    N.stringify = Zb;\n    N.contains = fc;\n    N.intersects = gc;\n\n    function oc(a, b, c, d) {\n        void 0 === a ? this.left = this.bottom = this.right = this.top = 0 : void 0 === b ? this.left = this.bottom = this.right = this.top = a : void 0 === c ? (this.top = a, this.right = b, this.bottom = a, this.left = b) : void 0 !== d ? (this.top = a, this.right = b, this.bottom = c, this.left = d) : B(\"Invalid arguments to Margin constructor: \" + a + \", \" + b + \", \" + c + \", \" + d);\n        this.s = !1\n    }\n    oc.prototype.assign = function (a) {\n        this.top = a.top;\n        this.right = a.right;\n        this.bottom = a.bottom;\n        this.left = a.left;\n        return this\n    };\n    oc.prototype.Fg = function (a, b, c, d) {\n        this.top = a;\n        this.right = b;\n        this.bottom = c;\n        this.left = d;\n        return this\n    };\n    oc.prototype.set = function (a) {\n        this.top = a.top;\n        this.right = a.right;\n        this.bottom = a.bottom;\n        this.left = a.left;\n        return this\n    };\n    oc.prototype.copy = function () {\n        var a = new oc;\n        a.top = this.top;\n        a.right = this.right;\n        a.bottom = this.bottom;\n        a.left = this.left;\n        return a\n    };\n    t = oc.prototype;\n    t.ca = function () {\n        this.s = !0;\n        Object.freeze(this);\n        return this\n    };\n    t.G = function () {\n        return this.s || Object.isFrozen(this) ? this : this.copy().freeze()\n    };\n    t.freeze = function () {\n        this.s = !0;\n        return this\n    };\n    t.ea = function () {\n        Object.isFrozen(this) && B(\"cannot thaw constant: \" + this);\n        this.s = !1;\n        return this\n    };\n\n    function pc(a) {\n        if (\"string\" === typeof a) {\n            a = a.split(\" \");\n            for (var b = 0, c = NaN;\n                \"\" === a[b];) b++;\n            var d = a[b++];\n            d && (c = parseFloat(d));\n            if (isNaN(c)) return new oc;\n            for (var e = NaN;\n                \"\" === a[b];) b++;\n            (d = a[b++]) && (e = parseFloat(d));\n            if (isNaN(e)) return new oc(c);\n            for (var f = NaN;\n                \"\" === a[b];) b++;\n            (d = a[b++]) && (f = parseFloat(d));\n            if (isNaN(f)) return new oc(c, e);\n            for (var g = NaN;\n                \"\" === a[b];) b++;\n            (d = a[b++]) && (g = parseFloat(d));\n            return isNaN(g) ? new oc(c, e) : new oc(c, e, f, g)\n        }\n        return new oc\n    }\n\n    function qc(a) {\n        return a.top.toString() + \" \" + a.right.toString() + \" \" + a.bottom.toString() + \" \" + a.left.toString()\n    }\n    t.toString = function () {\n        return \"Margin(\" + this.top + \",\" + this.right + \",\" + this.bottom + \",\" + this.left + \")\"\n    };\n    t.w = function (a) {\n        return a instanceof oc ? this.top === a.top && this.right === a.right && this.bottom === a.bottom && this.left === a.left : !1\n    };\n    t.Ri = function (a, b, c, d) {\n        return this.top === a && this.right === b && this.bottom === c && this.left === d\n    };\n    t.Ma = function (a) {\n        return J.A(this.top, a.top) && J.A(this.right, a.right) && J.A(this.bottom, a.bottom) && J.A(this.left, a.left)\n    };\n    t.v = function () {\n        return isFinite(this.top) && isFinite(this.right) && isFinite(this.bottom) && isFinite(this.left)\n    };\n    oc.alloc = function () {\n        var a = rc.pop();\n        return void 0 === a ? new oc : a\n    };\n    oc.free = function (a) {\n        rc.push(a)\n    };\n    oc.prototype.isReal = oc.prototype.v;\n    oc.prototype.equalsApprox = oc.prototype.Ma;\n    oc.prototype.equalTo = oc.prototype.Ri;\n    oc.prototype.equals = oc.prototype.w;\n    oc.prototype.set = oc.prototype.set;\n    oc.prototype.setTo = oc.prototype.Fg;\n    var sc = null,\n        tc = null,\n        rc = [];\n    oc.className = \"Margin\";\n    oc.parse = pc;\n    oc.stringify = qc;\n    oc.ZeroMargin = sc = (new oc(0, 0, 0, 0)).ca();\n    oc.TwoMargin = tc = (new oc(2, 2, 2, 2)).ca();\n    oc.parse = pc;\n    oc.stringify = qc;\n\n    function P(a, b, c, d) {\n        void 0 === a ? this.offsetY = this.offsetX = this.y = this.x = 0 : (void 0 === b && (b = 0), void 0 === c && (c = 0), void 0 === d && (d = 0), this.x = a, this.y = b, this.offsetX = c, this.offsetY = d);\n        this.s = !1\n    }\n    var uc, vc, xc, yc, zc, Ac, Bc, Cc, Fc, Gc, Hc, Ic, Jc, Kc, Lc, Mc, Nc, Pc, Qc, Rc, Sc, Tc, Uc, Vc, Yc, Zc, $c, ad, bd, cd, dd, ed, fd, gd, hd, id;\n    P.prototype.assign = function (a) {\n        this.x = a.x;\n        this.y = a.y;\n        this.offsetX = a.offsetX;\n        this.offsetY = a.offsetY;\n        return this\n    };\n    P.prototype.Fg = function (a, b, c, d) {\n        this.x = a;\n        this.y = b;\n        this.offsetX = c;\n        this.offsetY = d;\n        return this\n    };\n    P.prototype.set = function (a) {\n        this.x = a.x;\n        this.y = a.y;\n        this.offsetX = a.offsetX;\n        this.offsetY = a.offsetY;\n        return this\n    };\n    P.prototype.copy = function () {\n        var a = new P;\n        a.x = this.x;\n        a.y = this.y;\n        a.offsetX = this.offsetX;\n        a.offsetY = this.offsetY;\n        return a\n    };\n    t = P.prototype;\n    t.ca = function () {\n        this.s = !0;\n        Object.freeze(this);\n        return this\n    };\n    t.G = function () {\n        return this.s || Object.isFrozen(this) ? this : this.copy().freeze()\n    };\n    t.freeze = function () {\n        this.s = !0;\n        return this\n    };\n    t.ea = function () {\n        Object.isFrozen(this) && B(\"cannot thaw constant: \" + this);\n        this.s = !1;\n        return this\n    };\n\n    function jd(a, b) {\n        a.x = NaN;\n        a.y = NaN;\n        a.offsetX = b;\n        return a\n    }\n\n    function kd(a) {\n        if (\"string\" === typeof a) {\n            a = a.trim();\n            if (\"None\" === a) return uc;\n            if (\"TopLeft\" === a) return vc;\n            if (\"Top\" === a || \"TopCenter\" === a || \"MiddleTop\" === a) return xc;\n            if (\"TopRight\" === a) return yc;\n            if (\"Left\" === a || \"LeftCenter\" === a || \"MiddleLeft\" === a) return zc;\n            if (\"Center\" === a) return Ac;\n            if (\"Right\" === a || \"RightCenter\" === a || \"MiddleRight\" === a) return Bc;\n            if (\"BottomLeft\" === a) return Cc;\n            if (\"Bottom\" === a || \"BottomCenter\" === a || \"MiddleBottom\" === a) return Fc;\n            if (\"BottomRight\" === a) return Gc;\n            if (\"TopSide\" === a) return Hc;\n            if (\"LeftSide\" ===\n                a) return Ic;\n            if (\"RightSide\" === a) return Jc;\n            if (\"BottomSide\" === a) return Kc;\n            if (\"TopBottomSides\" === a) return Lc;\n            if (\"LeftRightSides\" === a) return Mc;\n            if (\"TopLeftSides\" === a) return Nc;\n            if (\"TopRightSides\" === a) return Pc;\n            if (\"BottomLeftSides\" === a) return Qc;\n            if (\"BottomRightSides\" === a) return Rc;\n            if (\"NotTopSide\" === a) return Sc;\n            if (\"NotLeftSide\" === a) return Tc;\n            if (\"NotRightSide\" === a) return Uc;\n            if (\"NotBottomSide\" === a) return Vc;\n            if (\"AllSides\" === a) return Yc;\n            if (\"Default\" === a) return Zc;\n            a = a.split(\" \");\n            for (var b = 0, c = 0;\n                \"\" === a[b];) b++;\n            var d = a[b++];\n            void 0 !== d && 0 < d.length && (c = parseFloat(d));\n            for (var e = 0;\n                \"\" === a[b];) b++;\n            d = a[b++];\n            void 0 !== d && 0 < d.length && (e = parseFloat(d));\n            for (var f = 0;\n                \"\" === a[b];) b++;\n            d = a[b++];\n            void 0 !== d && 0 < d.length && (f = parseFloat(d));\n            for (var g = 0;\n                \"\" === a[b];) b++;\n            d = a[b++];\n            void 0 !== d && 0 < d.length && (g = parseFloat(d));\n            return new P(c, e, f, g)\n        }\n        return new P\n    }\n\n    function ld(a) {\n        return a.eb() ? a.x.toString() + \" \" + a.y.toString() + \" \" + a.offsetX.toString() + \" \" + a.offsetY.toString() : a.toString()\n    }\n    t.toString = function () {\n        return this.eb() ? 0 === this.offsetX && 0 === this.offsetY ? \"Spot(\" + this.x + \",\" + this.y + \")\" : \"Spot(\" + this.x + \",\" + this.y + \",\" + this.offsetX + \",\" + this.offsetY + \")\" : this.w(uc) ? \"None\" : this.w(vc) ? \"TopLeft\" : this.w(xc) ? \"Top\" : this.w(yc) ? \"TopRight\" : this.w(zc) ? \"Left\" : this.w(Ac) ? \"Center\" : this.w(Bc) ? \"Right\" : this.w(Cc) ? \"BottomLeft\" : this.w(Fc) ? \"Bottom\" : this.w(Gc) ? \"BottomRight\" : this.w(Hc) ? \"TopSide\" : this.w(Ic) ? \"LeftSide\" : this.w(Jc) ? \"RightSide\" : this.w(Kc) ? \"BottomSide\" : this.w(Lc) ? \"TopBottomSides\" : this.w(Mc) ?\n            \"LeftRightSides\" : this.w(Nc) ? \"TopLeftSides\" : this.w(Pc) ? \"TopRightSides\" : this.w(Qc) ? \"BottomLeftSides\" : this.w(Rc) ? \"BottomRightSides\" : this.w(Sc) ? \"NotTopSide\" : this.w(Tc) ? \"NotLeftSide\" : this.w(Uc) ? \"NotRightSide\" : this.w(Vc) ? \"NotBottomSide\" : this.w(Yc) ? \"AllSides\" : this.w(Zc) ? \"Default\" : \"None\"\n    };\n    t.w = function (a) {\n        return a instanceof P ? (this.x === a.x || isNaN(this.x) && isNaN(a.x)) && (this.y === a.y || isNaN(this.y) && isNaN(a.y)) && this.offsetX === a.offsetX && this.offsetY === a.offsetY : !1\n    };\n    t.Pv = function () {\n        return new P(.5 - (this.x - .5), .5 - (this.y - .5), -this.offsetX, -this.offsetY)\n    };\n    t.wf = function (a) {\n        if (!this.yf()) return !1;\n        if (!a.yf())\n            if (a.w($c)) a = Ic;\n            else if (a.w(ad)) a = Jc;\n        else if (a.w(bd)) a = Hc;\n        else if (a.w(cd)) a = Kc;\n        else return !1;\n        a = a.offsetY;\n        return (this.offsetY & a) === a\n    };\n    t.eb = function () {\n        return !isNaN(this.x) && !isNaN(this.y)\n    };\n    t.jc = function () {\n        return isNaN(this.x) || isNaN(this.y)\n    };\n    t.yf = function () {\n        return isNaN(this.x) && isNaN(this.y) && 1 === this.offsetX && 0 !== this.offsetY\n    };\n    t.wt = function () {\n        return isNaN(this.x) && isNaN(this.y) && 0 === this.offsetX && 0 === this.offsetY\n    };\n    t.Mb = function () {\n        return isNaN(this.x) && isNaN(this.y) && -1 === this.offsetX && 0 === this.offsetY\n    };\n    P.alloc = function () {\n        var a = qd.pop();\n        return void 0 === a ? new P : a\n    };\n    P.free = function (a) {\n        qd.push(a)\n    };\n    P.prototype.isDefault = P.prototype.Mb;\n    P.prototype.isNone = P.prototype.wt;\n    P.prototype.isSide = P.prototype.yf;\n    P.prototype.isNoSpot = P.prototype.jc;\n    P.prototype.isSpot = P.prototype.eb;\n    P.prototype.includesSide = P.prototype.wf;\n    P.prototype.opposite = P.prototype.Pv;\n    P.prototype.equals = P.prototype.w;\n    P.prototype.set = P.prototype.set;\n    P.prototype.setTo = P.prototype.Fg;\n    var qd = [];\n    P.className = \"Spot\";\n    P.parse = kd;\n    P.stringify = ld;\n    P.None = uc = jd(new P(0, 0, 0, 0), 0).ca();\n    P.Default = Zc = jd(new P(0, 0, -1, 0), -1).ca();\n    P.TopLeft = vc = (new P(0, 0, 0, 0)).ca();\n    P.TopCenter = xc = (new P(.5, 0, 0, 0)).ca();\n    P.TopRight = yc = (new P(1, 0, 0, 0)).ca();\n    P.LeftCenter = zc = (new P(0, .5, 0, 0)).ca();\n    P.Center = Ac = (new P(.5, .5, 0, 0)).ca();\n    P.RightCenter = Bc = (new P(1, .5, 0, 0)).ca();\n    P.BottomLeft = Cc = (new P(0, 1, 0, 0)).ca();\n    P.BottomCenter = Fc = (new P(.5, 1, 0, 0)).ca();\n    P.BottomRight = Gc = (new P(1, 1, 0, 0)).ca();\n    P.MiddleTop = dd = xc;\n    P.MiddleLeft = ed = zc;\n    P.MiddleRight = fd = Bc;\n    P.MiddleBottom = gd = Fc;\n    P.Top = bd = xc;\n    P.Left = $c = zc;\n    P.Right = ad = Bc;\n    P.Bottom = cd = Fc;\n    P.TopSide = Hc = jd(new P(0, 0, 1, 1), 1).ca();\n    P.LeftSide = Ic = jd(new P(0, 0, 1, 2), 1).ca();\n    P.RightSide = Jc = jd(new P(0, 0, 1, 4), 1).ca();\n    P.BottomSide = Kc = jd(new P(0, 0, 1, 8), 1).ca();\n    P.TopBottomSides = Lc = jd(new P(0, 0, 1, 9), 1).ca();\n    P.LeftRightSides = Mc = jd(new P(0, 0, 1, 6), 1).ca();\n    P.TopLeftSides = Nc = jd(new P(0, 0, 1, 3), 1).ca();\n    P.TopRightSides = Pc = jd(new P(0, 0, 1, 5), 1).ca();\n    P.BottomLeftSides = Qc = jd(new P(0, 0, 1, 10), 1).ca();\n    P.BottomRightSides = Rc = jd(new P(0, 0, 1, 12), 1).ca();\n    P.NotTopSide = Sc = jd(new P(0, 0, 1, 14), 1).ca();\n    P.NotLeftSide = Tc = jd(new P(0, 0, 1, 13), 1).ca();\n    P.NotRightSide = Uc = jd(new P(0, 0, 1, 11), 1).ca();\n    P.NotBottomSide = Vc = jd(new P(0, 0, 1, 7), 1).ca();\n    P.AllSides = Yc = jd(new P(0, 0, 1, 15), 1).ca();\n    hd = (new P(.156, .156)).ca();\n    id = (new P(.844, .844)).ca();\n    P.parse = kd;\n    P.stringify = ld;\n\n    function rd() {\n        this.m11 = 1;\n        this.m21 = this.m12 = 0;\n        this.m22 = 1;\n        this.dy = this.dx = 0\n    }\n    rd.prototype.set = function (a) {\n        this.m11 = a.m11;\n        this.m12 = a.m12;\n        this.m21 = a.m21;\n        this.m22 = a.m22;\n        this.dx = a.dx;\n        this.dy = a.dy;\n        return this\n    };\n    rd.prototype.copy = function () {\n        var a = new rd;\n        a.m11 = this.m11;\n        a.m12 = this.m12;\n        a.m21 = this.m21;\n        a.m22 = this.m22;\n        a.dx = this.dx;\n        a.dy = this.dy;\n        return a\n    };\n    t = rd.prototype;\n    t.toString = function () {\n        return \"Transform(\" + this.m11 + \",\" + this.m12 + \",\" + this.m21 + \",\" + this.m22 + \",\" + this.dx + \",\" + this.dy + \")\"\n    };\n    t.w = function (a) {\n        return this.m11 === a.m11 && this.m12 === a.m12 && this.m21 === a.m21 && this.m22 === a.m22 && this.dx === a.dx && this.dy === a.dy\n    };\n    t.ut = function () {\n        return 0 === this.dx && 0 === this.dy && 1 === this.m11 && 0 === this.m12 && 0 === this.m21 && 1 === this.m22\n    };\n    t.reset = function () {\n        this.m11 = 1;\n        this.m21 = this.m12 = 0;\n        this.m22 = 1;\n        this.dy = this.dx = 0;\n        return this\n    };\n    t.multiply = function (a) {\n        var b = this.m11 * a.m11 + this.m21 * a.m12,\n            c = this.m12 * a.m11 + this.m22 * a.m12,\n            d = this.m11 * a.m21 + this.m21 * a.m22,\n            e = this.m12 * a.m21 + this.m22 * a.m22;\n        this.dx = this.m11 * a.dx + this.m21 * a.dy + this.dx;\n        this.dy = this.m12 * a.dx + this.m22 * a.dy + this.dy;\n        this.m11 = b;\n        this.m12 = c;\n        this.m21 = d;\n        this.m22 = e;\n        return this\n    };\n    t.Lv = function (a) {\n        var b = 1 / (a.m11 * a.m22 - a.m12 * a.m21),\n            c = a.m22 * b,\n            d = -a.m12 * b,\n            e = -a.m21 * b,\n            f = a.m11 * b,\n            g = b * (a.m21 * a.dy - a.m22 * a.dx);\n        a = b * (a.m12 * a.dx - a.m11 * a.dy);\n        b = this.m11 * c + this.m21 * d;\n        c = this.m12 * c + this.m22 * d;\n        d = this.m11 * e + this.m21 * f;\n        e = this.m12 * e + this.m22 * f;\n        this.dx = this.m11 * g + this.m21 * a + this.dx;\n        this.dy = this.m12 * g + this.m22 * a + this.dy;\n        this.m11 = b;\n        this.m12 = c;\n        this.m21 = d;\n        this.m22 = e;\n        return this\n    };\n    t.tt = function () {\n        var a = 1 / (this.m11 * this.m22 - this.m12 * this.m21),\n            b = -this.m12 * a,\n            c = -this.m21 * a,\n            d = this.m11 * a,\n            e = a * (this.m21 * this.dy - this.m22 * this.dx),\n            f = a * (this.m12 * this.dx - this.m11 * this.dy);\n        this.m11 = this.m22 * a;\n        this.m12 = b;\n        this.m21 = c;\n        this.m22 = d;\n        this.dx = e;\n        this.dy = f;\n        return this\n    };\n    rd.prototype.rotate = function (a, b, c) {\n        360 <= a ? a -= 360 : 0 > a && (a += 360);\n        if (0 === a) return this;\n        this.translate(b, c);\n        if (90 === a) {\n            a = 0;\n            var d = 1\n        } else 180 === a ? (a = -1, d = 0) : 270 === a ? (a = 0, d = -1) : (d = a * Math.PI / 180, a = Math.cos(d), d = Math.sin(d));\n        var e = this.m12 * a + this.m22 * d,\n            f = this.m11 * -d + this.m21 * a,\n            g = this.m12 * -d + this.m22 * a;\n        this.m11 = this.m11 * a + this.m21 * d;\n        this.m12 = e;\n        this.m21 = f;\n        this.m22 = g;\n        this.translate(-b, -c);\n        return this\n    };\n    t = rd.prototype;\n    t.translate = function (a, b) {\n        this.dx += this.m11 * a + this.m21 * b;\n        this.dy += this.m12 * a + this.m22 * b;\n        return this\n    };\n    t.scale = function (a, b) {\n        void 0 === b && (b = a);\n        this.m11 *= a;\n        this.m12 *= a;\n        this.m21 *= b;\n        this.m22 *= b;\n        return this\n    };\n    t.ra = function (a) {\n        var b = a.x,\n            c = a.y;\n        return a.h(b * this.m11 + c * this.m21 + this.dx, b * this.m12 + c * this.m22 + this.dy)\n    };\n    t.Vd = function (a) {\n        var b = 1 / (this.m11 * this.m22 - this.m12 * this.m21),\n            c = a.x,\n            d = a.y;\n        return a.h(c * this.m22 * b + d * -this.m21 * b + b * (this.m21 * this.dy - this.m22 * this.dx), c * -this.m12 * b + d * this.m11 * b + b * (this.m12 * this.dx - this.m11 * this.dy))\n    };\n    t.qw = function (a) {\n        var b = a.x,\n            c = a.y,\n            d = b + a.width,\n            e = c + a.height,\n            f = this.m11,\n            g = this.m12,\n            h = this.m21,\n            k = this.m22,\n            l = this.dx,\n            m = this.dy,\n            n = b * f + c * h + l,\n            p = b * g + c * k + m,\n            r = d * f + c * h + l,\n            q = d * g + c * k + m;\n        c = b * f + e * h + l;\n        b = b * g + e * k + m;\n        f = d * f + e * h + l;\n        d = d * g + e * k + m;\n        e = Math.min(n, r);\n        n = Math.max(n, r);\n        r = Math.min(p, q);\n        p = Math.max(p, q);\n        e = Math.min(e, c);\n        n = Math.max(n, c);\n        r = Math.min(r, b);\n        p = Math.max(p, b);\n        e = Math.min(e, f);\n        n = Math.max(n, f);\n        r = Math.min(r, d);\n        p = Math.max(p, d);\n        a.h(e, r, n - e, p - r);\n        return a\n    };\n    rd.alloc = function () {\n        var a = sd.pop();\n        return void 0 === a ? new rd : a\n    };\n    rd.free = function (a) {\n        sd.push(a)\n    };\n    rd.prototype.transformRect = rd.prototype.qw;\n    rd.prototype.invertedTransformPoint = rd.prototype.Vd;\n    rd.prototype.transformPoint = rd.prototype.ra;\n    rd.prototype.scale = rd.prototype.scale;\n    rd.prototype.translate = rd.prototype.translate;\n    rd.prototype.rotate = rd.prototype.rotate;\n    rd.prototype.invert = rd.prototype.tt;\n    rd.prototype.multiplyInverted = rd.prototype.Lv;\n    rd.prototype.multiply = rd.prototype.multiply;\n    rd.prototype.reset = rd.prototype.reset;\n    rd.prototype.isIdentity = rd.prototype.ut;\n    rd.prototype.equals = rd.prototype.w;\n    rd.prototype.set = rd.prototype.set;\n    var sd = [];\n    rd.className = \"Transform\";\n    rd.xF = \"54a702f3e53909c447824c6706603faf4c\";\n    var J = {\n        DA: \"7da71ca0ad381e90\",\n        Ig: (Math.sqrt(2) - 1) / 3 * 4,\n        Hw: null,\n        sqrt: function (a) {\n            if (0 >= a) return 0;\n            var b = J.Hw;\n            if (null === b) {\n                b = [];\n                for (var c = 0; 2E3 >= c; c++) b[c] = Math.sqrt(c);\n                J.Hw = b\n            }\n            return 1 > a ? (c = 1 / a, 2E3 >= c ? 1 / b[c | 0] : Math.sqrt(a)) : 2E3 >= a ? b[a | 0] : Math.sqrt(a)\n        },\n        A: function (a, b) {\n            a -= b;\n            return .5 > a && -.5 < a\n        },\n        $: function (a, b) {\n            a -= b;\n            return 5E-8 > a && -5E-8 < a\n        },\n        Nb: function (a, b, c, d, e, f, g) {\n            0 >= e && (e = 1E-6);\n            if (a < c) {\n                var h = a;\n                var k = c\n            } else h = c, k = a;\n            if (b < d) {\n                var l = b;\n                var m = d\n            } else l = d, m = b;\n            if (a === c) return l <= g && g <= m && a - e <= f && f <= a + e;\n            if (b === d) return h <=\n                f && f <= k && b - e <= g && g <= b + e;\n            k += e;\n            h -= e;\n            if (h <= f && f <= k && (m += e, l -= e, l <= g && g <= m))\n                if (k - h > m - l)\n                    if (a - c > e || c - a > e) {\n                        if (f = (d - b) / (c - a) * (f - a) + b, f - e <= g && g <= f + e) return !0\n                    } else return !0;\n            else if (b - d > e || d - b > e) {\n                if (g = (c - a) / (d - b) * (g - b) + a, g - e <= f && f <= g + e) return !0\n            } else return !0;\n            return !1\n        },\n        at: function (a, b, c, d, e, f, g, h, k, l, m, n) {\n            if (J.Nb(a, b, g, h, n, c, d) && J.Nb(a, b, g, h, n, e, f)) return J.Nb(a, b, g, h, n, l, m);\n            var p = (a + c) / 2,\n                r = (b + d) / 2,\n                q = (c + e) / 2,\n                u = (d + f) / 2;\n            e = (e + g) / 2;\n            f = (f + h) / 2;\n            d = (p + q) / 2;\n            c = (r + u) / 2;\n            q = (q + e) / 2;\n            u = (u + f) / 2;\n            var v = (d + q) / 2,\n                w = (c + u) / 2;\n            return J.at(a,\n                b, p, r, d, c, v, w, k, l, m, n) || J.at(v, w, q, u, e, f, g, h, k, l, m, n)\n        },\n        Qy: function (a, b, c, d, e, f, g, h, k) {\n            var l = (c + e) / 2,\n                m = (d + f) / 2;\n            k.h((((a + c) / 2 + l) / 2 + (l + (e + g) / 2) / 2) / 2, (((b + d) / 2 + m) / 2 + (m + (f + h) / 2) / 2) / 2);\n            return k\n        },\n        Py: function (a, b, c, d, e, f, g, h) {\n            var k = (c + e) / 2,\n                l = (d + f) / 2;\n            return Cb(((a + c) / 2 + k) / 2, ((b + d) / 2 + l) / 2, (k + (e + g) / 2) / 2, (l + (f + h) / 2) / 2)\n        },\n        bm: function (a, b, c, d, e, f, g, h, k, l) {\n            if (J.Nb(a, b, g, h, k, c, d) && J.Nb(a, b, g, h, k, e, f)) ec(l, a, b, 0, 0), ec(l, g, h, 0, 0);\n            else {\n                var m = (a + c) / 2,\n                    n = (b + d) / 2,\n                    p = (c + e) / 2,\n                    r = (d + f) / 2;\n                e = (e + g) / 2;\n                f = (f + h) / 2;\n                d = (m + p) / 2;\n                c = (n + r) /\n                    2;\n                p = (p + e) / 2;\n                r = (r + f) / 2;\n                var q = (d + p) / 2,\n                    u = (c + r) / 2;\n                J.bm(a, b, m, n, d, c, q, u, k, l);\n                J.bm(q, u, p, r, e, f, g, h, k, l)\n            }\n            return l\n        },\n        ye: function (a, b, c, d, e, f, g, h, k, l) {\n            if (J.Nb(a, b, g, h, k, c, d) && J.Nb(a, b, g, h, k, e, f)) 0 === l.length && (l.push(a), l.push(b)), l.push(g), l.push(h);\n            else {\n                var m = (a + c) / 2,\n                    n = (b + d) / 2,\n                    p = (c + e) / 2,\n                    r = (d + f) / 2;\n                e = (e + g) / 2;\n                f = (f + h) / 2;\n                d = (m + p) / 2;\n                c = (n + r) / 2;\n                p = (p + e) / 2;\n                r = (r + f) / 2;\n                var q = (d + p) / 2,\n                    u = (c + r) / 2;\n                J.ye(a, b, m, n, d, c, q, u, k, l);\n                J.ye(q, u, p, r, e, f, g, h, k, l)\n            }\n            return l\n        },\n        Sv: function (a, b, c, d, e, f, g, h, k, l) {\n            if (J.Nb(a, b, e, f, l, c, d)) return J.Nb(a,\n                b, e, f, l, h, k);\n            var m = (a + c) / 2,\n                n = (b + d) / 2;\n            c = (c + e) / 2;\n            d = (d + f) / 2;\n            var p = (m + c) / 2,\n                r = (n + d) / 2;\n            return J.Sv(a, b, m, n, p, r, g, h, k, l) || J.Sv(p, r, c, d, e, f, g, h, k, l)\n        },\n        JA: function (a, b, c, d, e, f, g) {\n            g.h(((a + c) / 2 + (c + e) / 2) / 2, ((b + d) / 2 + (d + f) / 2) / 2);\n            return g\n        },\n        Rv: function (a, b, c, d, e, f, g, h) {\n            if (J.Nb(a, b, e, f, g, c, d)) ec(h, a, b, 0, 0), ec(h, e, f, 0, 0);\n            else {\n                var k = (a + c) / 2,\n                    l = (b + d) / 2;\n                c = (c + e) / 2;\n                d = (d + f) / 2;\n                var m = (k + c) / 2,\n                    n = (l + d) / 2;\n                J.Rv(a, b, k, l, m, n, g, h);\n                J.Rv(m, n, c, d, e, f, g, h)\n            }\n            return h\n        },\n        Cq: function (a, b, c, d, e, f, g, h) {\n            if (J.Nb(a, b, e, f, g, c, d)) 0 === h.length && (h.push(a),\n                h.push(b)), h.push(e), h.push(f);\n            else {\n                var k = (a + c) / 2,\n                    l = (b + d) / 2;\n                c = (c + e) / 2;\n                d = (d + f) / 2;\n                var m = (k + c) / 2,\n                    n = (l + d) / 2;\n                J.Cq(a, b, k, l, m, n, g, h);\n                J.Cq(m, n, c, d, e, f, g, h)\n            }\n            return h\n        },\n        eq: function (a, b, c, d, e, f, g, h, k, l, m, n, p, r) {\n            if (J.Nb(a, b, g, h, p, c, d) && J.Nb(a, b, g, h, p, e, f)) {\n                var q = (a - g) * (l - n) - (b - h) * (k - m);\n                if (0 === q) return !1;\n                p = ((a * h - b * g) * (k - m) - (a - g) * (k * n - l * m)) / q;\n                q = ((a * h - b * g) * (l - n) - (b - h) * (k * n - l * m)) / q;\n                if ((k > m ? k - m : m - k) < (l > n ? l - n : n - l)) {\n                    if (b < h ? g = b : (g = h, h = b), q < g || q > h) return !1\n                } else if (a < g ? h = a : (h = g, g = a), p < h || p > g) return !1;\n                r.h(p, q);\n                return !0\n            }\n            q =\n                (a + c) / 2;\n            var u = (b + d) / 2;\n            c = (c + e) / 2;\n            d = (d + f) / 2;\n            e = (e + g) / 2;\n            f = (f + h) / 2;\n            var v = (q + c) / 2,\n                w = (u + d) / 2;\n            c = (c + e) / 2;\n            d = (d + f) / 2;\n            var y = (v + c) / 2,\n                z = (w + d) / 2,\n                A = (m - k) * (m - k) + (n - l) * (n - l),\n                C = !1;\n            J.eq(a, b, q, u, v, w, y, z, k, l, m, n, p, r) && (a = (r.x - k) * (r.x - k) + (r.y - l) * (r.y - l), a < A && (A = a, C = !0));\n            a = r.x;\n            b = r.y;\n            J.eq(y, z, c, d, e, f, g, h, k, l, m, n, p, r) && ((r.x - k) * (r.x - k) + (r.y - l) * (r.y - l) < A ? C = !0 : r.h(a, b));\n            return C\n        },\n        fq: function (a, b, c, d, e, f, g, h, k, l, m, n, p) {\n            var r = 0;\n            if (J.Nb(a, b, g, h, p, c, d) && J.Nb(a, b, g, h, p, e, f)) {\n                p = (a - g) * (l - n) - (b - h) * (k - m);\n                if (0 === p) return r;\n                var q = ((a *\n                        h - b * g) * (k - m) - (a - g) * (k * n - l * m)) / p,\n                    u = ((a * h - b * g) * (l - n) - (b - h) * (k * n - l * m)) / p;\n                if (q >= m) return r;\n                if ((k > m ? k - m : m - k) < (l > n ? l - n : n - l)) {\n                    if (b < h ? (a = b, b = h) : a = h, u < a || u > b) return r\n                } else if (a < g ? (b = a, a = g) : b = g, q < b || q > a) return r;\n                0 < p ? r++ : 0 > p && r--\n            } else {\n                q = (a + c) / 2;\n                u = (b + d) / 2;\n                var v = (c + e) / 2,\n                    w = (d + f) / 2;\n                e = (e + g) / 2;\n                f = (f + h) / 2;\n                d = (q + v) / 2;\n                c = (u + w) / 2;\n                v = (v + e) / 2;\n                w = (w + f) / 2;\n                var y = (d + v) / 2,\n                    z = (c + w) / 2;\n                r += J.fq(a, b, q, u, d, c, y, z, k, l, m, n, p);\n                r += J.fq(y, z, v, w, e, f, g, h, k, l, m, n, p)\n            }\n            return r\n        },\n        Lh: function (a, b, c, d, e, f, g) {\n            if (J.$(a, c)) {\n                b < d ? (c = b, b = d) : c = d;\n                if (f < c) return g.h(a,\n                    c), !1;\n                if (f > b) return g.h(a, b), !1;\n                g.h(a, f);\n                return !0\n            }\n            if (J.$(b, d)) {\n                a < c ? (d = a, a = c) : d = c;\n                if (e < d) return g.h(d, b), !1;\n                if (e > a) return g.h(a, b), !1;\n                g.h(e, b);\n                return !0\n            }\n            e = ((a - e) * (a - c) + (b - f) * (b - d)) / ((c - a) * (c - a) + (d - b) * (d - b));\n            if (-5E-6 > e) return g.h(a, b), !1;\n            if (1.000005 < e) return g.h(c, d), !1;\n            g.h(a + e * (c - a), b + e * (d - b));\n            return !0\n        },\n        De: function (a, b, c, d, e, f, g, h, k) {\n            if (J.A(a, c) && J.A(b, d)) return k.h(a, b), !1;\n            if (J.$(e, g)) return J.$(a, c) ? (J.Lh(a, b, c, d, e, f, k), !1) : J.Lh(a, b, c, d, e, (d - b) / (c - a) * (e - a) + b, k);\n            h = (h - f) / (g - e);\n            if (J.$(a, c)) {\n                c = h * (a - e) +\n                    f;\n                b < d ? (e = b, b = d) : e = d;\n                if (c < e) return k.h(a, e), !1;\n                if (c > b) return k.h(a, b), !1;\n                k.h(a, c);\n                return !0\n            }\n            g = (d - b) / (c - a);\n            if (J.$(h, g)) return J.Lh(a, b, c, d, e, f, k), !1;\n            e = (g * a - h * e + f - b) / (g - h);\n            if (J.$(g, 0)) {\n                a < c ? (d = a, a = c) : d = c;\n                if (e < d) return k.h(d, b), !1;\n                if (e > a) return k.h(a, b), !1;\n                k.h(e, b);\n                return !0\n            }\n            return J.Lh(a, b, c, d, e, g * (e - a) + b, k)\n        },\n        IA: function (a, b, c, d, e) {\n            return J.De(c.x, c.y, d.x, d.y, a.x, a.y, b.x, b.y, e)\n        },\n        HA: function (a, b, c, d, e, f, g, h, k, l) {\n            function m(c, d) {\n                var e = (c - a) * (c - a) + (d - b) * (d - b);\n                e < n && (n = e, k.h(c, d))\n            }\n            var n = Infinity;\n            m(k.x, k.y);\n            var p = 0,\n                r = 0,\n                q = 0,\n                u = 0;\n            e < g ? (p = e, r = g) : (p = g, r = e);\n            f < h ? (q = e, u = g) : (q = g, u = e);\n            p = (r - p) / 2 + l;\n            l = (u - q) / 2 + l;\n            e = (e + g) / 2;\n            f = (f + h) / 2;\n            if (0 === p || 0 === l) return k;\n            if (.5 > (c > a ? c - a : a - c)) {\n                p = 1 - (c - e) * (c - e) / (p * p);\n                if (0 > p) return k;\n                p = Math.sqrt(p);\n                d = -l * p + f;\n                m(c, l * p + f);\n                m(c, d)\n            } else {\n                c = (d - b) / (c - a);\n                d = 1 / (p * p) + c * c / (l * l);\n                h = 2 * c * (b - c * a) / (l * l) - 2 * c * f / (l * l) - 2 * e / (p * p);\n                p = h * h - 4 * d * (2 * c * a * f / (l * l) - 2 * b * f / (l * l) + f * f / (l * l) + e * e / (p * p) - 1 + (b - c * a) * (b - c * a) / (l * l));\n                if (0 > p) return k;\n                p = Math.sqrt(p);\n                l = (-h + p) / (2 * d);\n                m(l, c * l - c * a + b);\n                p = (-h - p) / (2 * d);\n                m(p, c * p - c * a + b)\n            }\n            return k\n        },\n        Uc: function (a, b, c, d, e, f, g, h, k) {\n            var l = 1E21,\n                m = a,\n                n = b;\n            if (J.De(a, b, a, d, e, f, g, h, k)) {\n                var p = (k.x - e) * (k.x - e) + (k.y - f) * (k.y - f);\n                p < l && (l = p, m = k.x, n = k.y)\n            }\n            J.De(c, b, c, d, e, f, g, h, k) && (p = (k.x - e) * (k.x - e) + (k.y - f) * (k.y - f), p < l && (l = p, m = k.x, n = k.y));\n            J.De(a, b, c, b, e, f, g, h, k) && (b = (k.x - e) * (k.x - e) + (k.y - f) * (k.y - f), b < l && (l = b, m = k.x, n = k.y));\n            J.De(a, d, c, d, e, f, g, h, k) && (a = (k.x - e) * (k.x - e) + (k.y - f) * (k.y - f), a < l && (l = a, m = k.x, n = k.y));\n            k.h(m, n);\n            return 1E21 > l\n        },\n        GA: function (a, b, c, d, e, f, g, h, k) {\n            c = a - c;\n            g = e - g;\n            0 === c || 0 === g ? 0 === c ? (b = (f - h) / g, h = a, e = b * h + (f -\n                b * e)) : (f = (b - d) / c, h = e, e = f * h + (b - f * a)) : (d = (b - d) / c, h = (f - h) / g, a = b - d * a, h = (f - h * e - a) / (d - h), e = d * h + a);\n            k.h(h, e);\n            return k\n        },\n        rt: function (a, b, c) {\n            return J.Rx(a.x, a.y, a.width, a.height, b.x, b.y, c.x, c.y)\n        },\n        Rx: function (a, b, c, d, e, f, g, h) {\n            var k = a + c,\n                l = b + d;\n            return e === g ? (f < h ? (g = f, f = h) : g = h, a <= e && e <= k && g <= l && f >= b) : f === h ? (e < g ? (h = e, e = g) : h = g, b <= f && f <= l && h <= k && e >= a) : fc(a, b, c, d, e, f) || fc(a, b, c, d, g, h) || J.sq(a, b, k, b, e, f, g, h) || J.sq(k, b, k, l, e, f, g, h) || J.sq(k, l, a, l, e, f, g, h) || J.sq(a, l, a, b, e, f, g, h) ? !0 : !1\n        },\n        sq: function (a, b, c, d, e, f, g, h) {\n            return 0 >=\n                J.dt(a, b, c, d, e, f) * J.dt(a, b, c, d, g, h) && 0 >= J.dt(e, f, g, h, a, b) * J.dt(e, f, g, h, c, d)\n        },\n        dt: function (a, b, c, d, e, f) {\n            c -= a;\n            d -= b;\n            a = e - a;\n            b = f - b;\n            f = a * d - b * c;\n            0 === f && (f = a * c + b * d, 0 < f && (f = (a - c) * c + (b - d) * d, 0 > f && (f = 0)));\n            return 0 > f ? -1 : 0 < f ? 1 : 0\n        },\n        zq: function (a) {\n            0 > a && (a += 360);\n            360 <= a && (a -= 360);\n            return a\n        },\n        Cx: function (a, b, c, d, e, f) {\n            var g = Math.PI;\n            f || (d *= g / 180, e *= g / 180);\n            var h = d > e ? -1 : 1;\n            f = [];\n            var k = g / 2,\n                l = d;\n            d = Math.min(2 * g, Math.abs(e - d));\n            if (1E-5 > d) return k = l + h * Math.min(d, k), h = a + c * Math.cos(l), l = b + c * Math.sin(l), a += c * Math.cos(k), b += c * Math.sin(k),\n                c = (h + a) / 2, k = (l + b) / 2, f.push([h, l, c, k, c, k, a, b]), f;\n            for (; 1E-5 < d;) e = l + h * Math.min(d, k), f.push(J.Xy(c, l, e, a, b)), d -= Math.abs(e - l), l = e;\n            return f\n        },\n        Xy: function (a, b, c, d, e) {\n            var f = (c - b) / 2,\n                g = a * Math.cos(f),\n                h = a * Math.sin(f),\n                k = -h,\n                l = g * g + k * k,\n                m = l + g * g + k * h;\n            l = 4 / 3 * (Math.sqrt(2 * l * m) - m) / (g * h - k * g);\n            h = g - l * k;\n            g = k + l * g;\n            k = -g;\n            l = f + b;\n            f = Math.cos(l);\n            l = Math.sin(l);\n            return [d + a * Math.cos(b), e + a * Math.sin(b), d + h * f - g * l, e + h * l + g * f, d + h * f - k * l, e + h * l + k * f, d + a * Math.cos(c), e + a * Math.sin(c)]\n        },\n        mq: function (a, b, c, d, e, f, g) {\n            c = Math.floor((a - c) / e) * e + c;\n            d = Math.floor((b -\n                d) / f) * f + d;\n            var h = c;\n            c + e - a < e / 2 && (h = c + e);\n            a = d;\n            d + f - b < f / 2 && (a = d + f);\n            g.h(h, a);\n            return g\n        },\n        Nx: function (a, b) {\n            var c = Math.max(a, b);\n            a = Math.min(a, b);\n            var d;\n            do b = c % a, c = d = a, a = b; while (0 < b);\n            return d\n        },\n        bz: function (a, b, c, d) {\n            var e = 0 > c,\n                f = 0 > d;\n            if (a < b) {\n                var g = 1;\n                var h = 0\n            } else g = 0, h = 1;\n            var k = 0 === g ? a : b;\n            var l = 0 === g ? c : d;\n            if (0 === g ? e : f) l = -l;\n            g = h;\n            c = 0 === g ? c : d;\n            if (0 === g ? e : f) c = -c;\n            return J.cz(k, 0 === g ? a : b, l, c, 0, 0)\n        },\n        cz: function (a, b, c, d, e, f) {\n            if (0 < d)\n                if (0 < c) {\n                    e = a * a;\n                    f = b * b;\n                    a *= c;\n                    var g = b * d,\n                        h = -f + g,\n                        k = -f + Math.sqrt(a * a + g * g);\n                    b = h;\n                    for (var l = 0; 9999999999 > l; ++l) {\n                        b =\n                            .5 * (h + k);\n                        if (b === h || b === k) break;\n                        var m = a / (b + e),\n                            n = g / (b + f);\n                        m = m * m + n * n - 1;\n                        if (0 < m) h = b;\n                        else if (0 > m) k = b;\n                        else break\n                    }\n                    c = e * c / (b + e) - c;\n                    d = f * d / (b + f) - d;\n                    c = Math.sqrt(c * c + d * d)\n                } else c = Math.abs(d - b);\n            else d = a * a - b * b, f = a * c, f < d ? (d = f / d, f = b * Math.sqrt(Math.abs(1 - d * d)), c = a * d - c, c = Math.sqrt(c * c + f * f)) : c = Math.abs(c - a);\n            return c\n        },\n        Je: new db,\n        Nm: new db,\n        Ff: new db,\n        Gf: 0\n    };\n    J.za = J.DA;\n\n    function td(a) {\n        Ya(this);\n        this.s = !1;\n        void 0 === a && (a = ud);\n        this.pa = a;\n        this.mc = this.ec = this.Sc = this.Rc = 0;\n        this.rj = new E;\n        this.Dr = this.rj.Aa;\n        this.kr = (new N).freeze();\n        this.qa = !0;\n        this.Tm = this.Gk = null;\n        this.Um = NaN;\n        this.hf = vc;\n        this.jf = Gc;\n        this.jl = this.kl = NaN;\n        this.Qf = vd\n    }\n    td.prototype.copy = function () {\n        var a = new td;\n        a.pa = this.pa;\n        a.Rc = this.Rc;\n        a.Sc = this.Sc;\n        a.ec = this.ec;\n        a.mc = this.mc;\n        for (var b = this.rj.j, c = b.length, d = a.rj, e = 0; e < c; e++) {\n            var f = b[e].copy();\n            d.add(f)\n        }\n        a.Dr = this.Dr;\n        a.kr.assign(this.kr);\n        a.qa = this.qa;\n        a.Gk = this.Gk;\n        a.Tm = this.Tm;\n        a.Um = this.Um;\n        a.hf = this.hf.G();\n        a.jf = this.jf.G();\n        a.kl = this.kl;\n        a.jl = this.jl;\n        a.Qf = this.Qf;\n        return a\n    };\n    t = td.prototype;\n    t.ca = function () {\n        this.freeze();\n        Object.freeze(this);\n        return this\n    };\n    t.freeze = function () {\n        this.s = !0;\n        var a = this.figures;\n        a.freeze();\n        a = a.j;\n        for (var b = a.length, c = 0; c < b; c++) a[c].freeze();\n        return this\n    };\n    t.ea = function () {\n        Object.isFrozen(this) && B(\"cannot thaw constant: \" + this);\n        this.s = !1;\n        var a = this.figures;\n        a.ea();\n        a = a.j;\n        for (var b = a.length, c = 0; c < b; c++) a[c].ea();\n        return this\n    };\n    t.Ma = function (a) {\n        if (!(a instanceof td)) return !1;\n        if (this.type !== a.type) return this.type === wd && a.type === ud ? xd(this, a) : a.type === wd && this.type === ud ? xd(a, this) : !1;\n        if (this.type === ud) {\n            var b = this.figures.j;\n            a = a.figures.j;\n            var c = b.length;\n            if (c !== a.length) return !1;\n            for (var d = 0; d < c; d++)\n                if (!b[d].Ma(a[d])) return !1;\n            return !0\n        }\n        return J.A(this.startX, a.startX) && J.A(this.startY, a.startY) && J.A(this.endX, a.endX) && J.A(this.endY, a.endY)\n    };\n\n    function xd(a, b) {\n        return a.type !== wd || b.type !== ud ? !1 : 1 === b.figures.count && (b = b.figures.L(0), 1 === b.segments.count && J.A(a.startX, b.startX) && J.A(a.startY, b.startY) && (b = b.segments.L(0), b.type === yd && J.A(a.endX, b.endX) && J.A(a.endY, b.endY))) ? !0 : !1\n    }\n\n    function zd(a) {\n        return a.toString()\n    }\n    t.cb = function (a) {\n        a.classType === td && (this.type = a)\n    };\n    t.toString = function (a) {\n        void 0 === a && (a = -1);\n        switch (this.type) {\n            case wd:\n                return 0 > a ? \"M\" + this.startX.toString() + \" \" + this.startY.toString() + \"L\" + this.endX.toString() + \" \" + this.endY.toString() : \"M\" + this.startX.toFixed(a) + \" \" + this.startY.toFixed(a) + \"L\" + this.endX.toFixed(a) + \" \" + this.endY.toFixed(a);\n            case Gd:\n                var b = new N(this.startX, this.startY, 0, 0);\n                b.rw(this.endX, this.endY, 0, 0);\n                return 0 > a ? \"M\" + b.x.toString() + \" \" + b.y.toString() + \"H\" + b.right.toString() + \"V\" + b.bottom.toString() + \"H\" + b.left.toString() + \"z\" : \"M\" + b.x.toFixed(a) +\n                    \" \" + b.y.toFixed(a) + \"H\" + b.right.toFixed(a) + \"V\" + b.bottom.toFixed(a) + \"H\" + b.left.toFixed(a) + \"z\";\n            case Hd:\n                b = new N(this.startX, this.startY, 0, 0);\n                b.rw(this.endX, this.endY, 0, 0);\n                if (0 > a) return a = b.left.toString() + \" \" + (b.y + b.height / 2).toString(), \"M\" + a + \"A\" + (b.width / 2).toString() + \" \" + (b.height / 2).toString() + \" 0 0 1 \" + (b.right.toString() + \" \" + (b.y + b.height / 2).toString()) + \"A\" + (b.width / 2).toString() + \" \" + (b.height / 2).toString() + \" 0 0 1 \" + a;\n                var c = b.left.toFixed(a) + \" \" + (b.y + b.height / 2).toFixed(a);\n                return \"M\" + c + \"A\" + (b.width /\n                    2).toFixed(a) + \" \" + (b.height / 2).toFixed(a) + \" 0 0 1 \" + (b.right.toFixed(a) + \" \" + (b.y + b.height / 2).toFixed(a)) + \"A\" + (b.width / 2).toFixed(a) + \" \" + (b.height / 2).toFixed(a) + \" 0 0 1 \" + c;\n            case ud:\n                b = \"\";\n                c = this.figures.j;\n                for (var d = c.length, e = 0; e < d; e++) {\n                    var f = c[e];\n                    0 < e && (b += \" x \");\n                    f.isFilled && (b += \"F \");\n                    b += f.toString(a)\n                }\n                return b;\n            default:\n                return this.type.toString()\n        }\n    };\n\n    function Id(a, b) {\n        function c() {\n            return u >= A - 1 ? !0 : null !== k[u + 1].match(/[UuBbMmZzLlHhVvCcSsQqTtAaFfXx]/)\n        }\n\n        function d() {\n            u++;\n            return k[u]\n        }\n\n        function e() {\n            var a = new I(parseFloat(d()), parseFloat(d()));\n            v === v.toLowerCase() && (a.x = z.x + a.x, a.y = z.y + a.y);\n            return a\n        }\n\n        function f() {\n            return z = e()\n        }\n\n        function g() {\n            return y = e()\n        }\n\n        function h() {\n            var a = w.toLowerCase();\n            return \"c\" !== a && \"s\" !== a && \"q\" !== a && \"t\" !== a ? z : new I(2 * z.x - y.x, 2 * z.y - y.y)\n        }\n        void 0 === b && (b = !1);\n        a = a.replace(/,/gm, \" \");\n        a = a.replace(/([UuBbMmZzLlHhVvCcSsQqTtAaFfXx])([UuBbMmZzLlHhVvCcSsQqTtAaFfXx])/gm,\n            \"$1 $2\");\n        a = a.replace(/([UuBbMmZzLlHhVvCcSsQqTtAaFfXx])([UuBbMmZzLlHhVvCcSsQqTtAaFfXx])/gm, \"$1 $2\");\n        a = a.replace(/([UuBbMmZzLlHhVvCcSsQqTtAaFfXx])([^\\s])/gm, \"$1 $2\");\n        a = a.replace(/([^\\s])([UuBbMmZzLlHhVvCcSsQqTtAaFfXx])/gm, \"$1 $2\");\n        a = a.replace(/([0-9])([+\\-])/gm, \"$1 $2\");\n        a = a.replace(/([Aa](\\s+[0-9]+){3})\\s+([01])\\s*([01])/gm, \"$1 $3 $4 \");\n        a = a.replace(/[\\s\\r\\t\\n]+/gm, \" \");\n        a = a.replace(/^\\s+|\\s+$/g, \"\");\n        var k = a.split(\" \");\n        for (a = 0; a < k.length; a++) {\n            var l = k[a];\n            if (null !== l.match(/(\\.[0-9]*)(\\.)/gm)) {\n                for (var m =\n                        Fa(), n = \"\", p = !1, r = 0; r < l.length; r++) {\n                    var q = l[r];\n                    \".\" !== q || p ? \".\" === q ? (m.push(n), n = \".\") : n += q : (p = !0, n += q)\n                }\n                m.push(n);\n                k.splice(a, 1);\n                for (l = 0; l < m.length; l++) k.splice(a + l, 0, m[l]);\n                a += m.length - 1;\n                Ha(m)\n            }\n        }\n        var u = -1,\n            v = \"\",\n            w = \"\";\n        m = new I(0, 0);\n        var y = new I(0, 0),\n            z = new I(0, 0),\n            A = k.length;\n        a = Jd(null);\n        n = l = !1;\n        p = !0;\n        for (r = null; !(u >= A - 1);)\n            if (w = v, v = d(), \"\" !== v) switch (v.toUpperCase()) {\n                case \"X\":\n                    p = !0;\n                    n = l = !1;\n                    break;\n                case \"M\":\n                    r = f();\n                    null === a.fc || !0 === p ? (Kd(a, r.x, r.y, l, !n), p = !1) : a.moveTo(r.x, r.y);\n                    for (m = z; !c();) r = f(), a.lineTo(r.x, r.y);\n                    break;\n                case \"L\":\n                    for (; !c();) r = f(), a.lineTo(r.x, r.y);\n                    break;\n                case \"H\":\n                    for (; !c();) z = new I((v === v.toLowerCase() ? z.x : 0) + parseFloat(d()), z.y), a.lineTo(z.x, z.y);\n                    break;\n                case \"V\":\n                    for (; !c();) z = new I(z.x, (v === v.toLowerCase() ? z.y : 0) + parseFloat(d())), a.lineTo(z.x, z.y);\n                    break;\n                case \"C\":\n                    for (; !c();) {\n                        r = e();\n                        q = g();\n                        var C = f();\n                        Ld(a, r.x, r.y, q.x, q.y, C.x, C.y)\n                    }\n                    break;\n                case \"S\":\n                    for (; !c();) r = h(), q = g(), C = f(), Ld(a, r.x, r.y, q.x, q.y, C.x, C.y);\n                    break;\n                case \"Q\":\n                    for (; !c();) r = g(), q = f(), Qd(a, r.x, r.y, q.x, q.y);\n                    break;\n                case \"T\":\n                    for (; !c();) y = r = h(), q = f(), Qd(a,\n                        r.x, r.y, q.x, q.y);\n                    break;\n                case \"B\":\n                    for (; !c();) {\n                        r = parseFloat(d());\n                        q = parseFloat(d());\n                        C = parseFloat(d());\n                        var G = parseFloat(d()),\n                            L = parseFloat(d()),\n                            K = L,\n                            V = !1;\n                        c() || (K = parseFloat(d()), c() || (V = 0 !== parseFloat(d())));\n                        v === v.toLowerCase() && (C += z.x, G += z.y);\n                        a.arcTo(r, q, C, G, L, K, V)\n                    }\n                    break;\n                case \"A\":\n                    for (; !c();) r = Math.abs(parseFloat(d())), q = Math.abs(parseFloat(d())), C = parseFloat(d()), G = !!parseFloat(d()), L = !!parseFloat(d()), K = f(), Rd(a, r, q, C, G, L, K.x, K.y);\n                    break;\n                case \"Z\":\n                    Sd(a);\n                    z = m;\n                    break;\n                case \"F\":\n                    r = \"\";\n                    for (q = 1; k[u + q];)\n                        if (null !==\n                            k[u + q].match(/[Uu]/)) q++;\n                        else if (null === k[u + q].match(/[UuBbMmZzLlHhVvCcSsQqTtAaFfXx]/)) q++;\n                    else {\n                        r = k[u + q];\n                        break\n                    }\n                    r.match(/[Mm]/) ? l = !0 : 0 < a.fc.segments.length && (a.fc.isFilled = !0);\n                    break;\n                case \"U\":\n                    r = \"\";\n                    for (q = 1; k[u + q];)\n                        if (null !== k[u + q].match(/[Ff]/)) q++;\n                        else if (null === k[u + q].match(/[UuBbMmZzLlHhVvCcSsQqTtAaFfXx]/)) q++;\n                    else {\n                        r = k[u + q];\n                        break\n                    }\n                    r.match(/[Mm]/) ? n = !0 : a.Lq(!1)\n            }\n        m = a.mt;\n        Td = a;\n        if (b)\n            for (b = m.figures.iterator; b.next();) b.value.isFilled = !0;\n        return m\n    }\n\n    function Ud(a, b) {\n        for (var c = a.length, d = I.alloc(), e = 0; e < c; e++) {\n            var f = a[e];\n            d.x = f[0];\n            d.y = f[1];\n            b.ra(d);\n            f[0] = d.x;\n            f[1] = d.y;\n            d.x = f[2];\n            d.y = f[3];\n            b.ra(d);\n            f[2] = d.x;\n            f[3] = d.y;\n            d.x = f[4];\n            d.y = f[5];\n            b.ra(d);\n            f[4] = d.x;\n            f[5] = d.y;\n            d.x = f[6];\n            d.y = f[7];\n            b.ra(d);\n            f[6] = d.x;\n            f[7] = d.y\n        }\n        I.free(d)\n    }\n    t.Iv = function () {\n        if (this.qa || this.Dr !== this.figures.Aa) return !0;\n        for (var a = this.figures.j, b = a.length, c = 0; c < b; c++)\n            if (a[c].Iv()) return !0;\n        return !1\n    };\n    td.prototype.computeBounds = function () {\n        this.qa = !1;\n        this.Tm = this.Gk = null;\n        this.Um = NaN;\n        this.Dr = this.figures.Aa;\n        for (var a = this.figures.j, b = a.length, c = 0; c < b; c++) {\n            var d = a[c];\n            d.qa = !1;\n            var e = d.segments;\n            d.Is = e.Aa;\n            d = e.j;\n            e = d.length;\n            for (var f = 0; f < e; f++) {\n                var g = d[f];\n                g.qa = !1;\n                g.Le = null\n            }\n        }\n        a = this.kr;\n        a.ea();\n        isNaN(this.kl) || isNaN(this.jl) ? a.h(0, 0, 0, 0) : a.h(0, 0, this.kl, this.jl);\n        Vd(this, a, !1);\n        ec(a, 0, 0, 0, 0);\n        a.freeze()\n    };\n    td.prototype.Bx = function () {\n        var a = new N;\n        Vd(this, a, !0);\n        return a\n    };\n\n    function Vd(a, b, c) {\n        switch (a.type) {\n            case wd:\n            case Gd:\n            case Hd:\n                c ? b.h(a.Rc, a.Sc, 0, 0) : ec(b, a.Rc, a.Sc, 0, 0);\n                ec(b, a.ec, a.mc, 0, 0);\n                break;\n            case ud:\n                var d = a.figures;\n                a = d.j;\n                d = d.length;\n                for (var e = 0; e < d; e++) {\n                    var f = a[e];\n                    c && 0 === e ? b.h(f.startX, f.startY, 0, 0) : ec(b, f.startX, f.startY, 0, 0);\n                    for (var g = f.segments.j, h = g.length, k = f.startX, l = f.startY, m = 0; m < h; m++) {\n                        var n = g[m];\n                        switch (n.type) {\n                            case yd:\n                            case Wd:\n                                k = n.endX;\n                                l = n.endY;\n                                ec(b, k, l, 0, 0);\n                                break;\n                            case Xd:\n                                J.bm(k, l, n.point1X, n.point1Y, n.point2X, n.point2Y, n.endX, n.endY, .5, b);\n                                k = n.endX;\n                                l = n.endY;\n                                break;\n                            case Yd:\n                                J.Rv(k, l, n.point1X, n.point1Y, n.endX, n.endY, .5, b);\n                                k = n.endX;\n                                l = n.endY;\n                                break;\n                            case Zd:\n                            case $d:\n                                var p = n.type === Zd ? ae(n, f) : be(n, f, k, l),\n                                    r = p.length;\n                                if (0 === r) {\n                                    k = n.centerX;\n                                    l = n.centerY;\n                                    ec(b, k, l, 0, 0);\n                                    break\n                                }\n                                n = null;\n                                for (var q = 0; q < r; q++) n = p[q], J.bm(n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7], .5, b);\n                                null !== n && (k = n[6], l = n[7]);\n                                break;\n                            default:\n                                B(\"Unknown Segment type: \" + n.type)\n                        }\n                    }\n                }\n                break;\n            default:\n                B(\"Unknown Geometry type: \" + a.type)\n        }\n    }\n    td.prototype.normalize = function () {\n        this.s && ua(this);\n        var a = this.Bx();\n        this.offset(-a.x, -a.y);\n        return new I(-a.x, -a.y)\n    };\n    td.prototype.offset = function (a, b) {\n        this.s && ua(this);\n        this.transform(1, 0, 0, 1, a, b);\n        return this\n    };\n    td.prototype.scale = function (a, b) {\n        this.s && ua(this);\n        this.transform(a, 0, 0, b, 0, 0);\n        return this\n    };\n    td.prototype.rotate = function (a, b, c) {\n        this.s && ua(this);\n        void 0 === b && (b = 0);\n        void 0 === c && (c = 0);\n        var d = rd.alloc();\n        d.reset();\n        d.rotate(a, b, c);\n        this.transform(d.m11, d.m12, d.m21, d.m22, d.dx, d.dy);\n        rd.free(d);\n        return this\n    };\n    t = td.prototype;\n    t.transform = function (a, b, c, d, e, f) {\n        switch (this.type) {\n            case wd:\n            case Gd:\n            case Hd:\n                var g = this.Rc;\n                var h = this.Sc;\n                this.Rc = g * a + h * c + e;\n                this.Sc = g * b + h * d + f;\n                g = this.ec;\n                h = this.mc;\n                this.ec = g * a + h * c + e;\n                this.mc = g * b + h * d + f;\n                break;\n            case ud:\n                for (var k = this.figures.j, l = k.length, m = 0; m < l; m++) {\n                    var n = k[m];\n                    g = n.startX;\n                    h = n.startY;\n                    n.startX = g * a + h * c + e;\n                    n.startY = g * b + h * d + f;\n                    n = n.segments.j;\n                    for (var p = n.length, r = 0; r < p; r++) {\n                        var q = n[r];\n                        switch (q.type) {\n                            case yd:\n                            case Wd:\n                                g = q.endX;\n                                h = q.endY;\n                                q.endX = g * a + h * c + e;\n                                q.endY = g * b + h * d + f;\n                                break;\n                            case Xd:\n                                g = q.point1X;\n                                h = q.point1Y;\n                                q.point1X = g * a + h * c + e;\n                                q.point1Y = g * b + h * d + f;\n                                g = q.point2X;\n                                h = q.point2Y;\n                                q.point2X = g * a + h * c + e;\n                                q.point2Y = g * b + h * d + f;\n                                g = q.endX;\n                                h = q.endY;\n                                q.endX = g * a + h * c + e;\n                                q.endY = g * b + h * d + f;\n                                break;\n                            case Yd:\n                                g = q.point1X;\n                                h = q.point1Y;\n                                q.point1X = g * a + h * c + e;\n                                q.point1Y = g * b + h * d + f;\n                                g = q.endX;\n                                h = q.endY;\n                                q.endX = g * a + h * c + e;\n                                q.endY = g * b + h * d + f;\n                                break;\n                            case Zd:\n                                g = q.centerX;\n                                h = q.centerY;\n                                q.centerX = g * a + h * c + e;\n                                q.centerY = g * b + h * d + f;\n                                0 !== b && (g = 180 * Math.atan2(b, a) / Math.PI, 0 > g && (g += 360), q.startAngle += g);\n                                0 > a && (q.startAngle = 180 - q.startAngle, q.sweepAngle = -q.sweepAngle);\n                                0 > d &&\n                                    (q.startAngle = -q.startAngle, q.sweepAngle = -q.sweepAngle);\n                                q.radiusX *= Math.sqrt(a * a + c * c);\n                                void 0 !== q.radiusY && (q.radiusY *= Math.sqrt(b * b + d * d));\n                                break;\n                            case $d:\n                                g = q.endX;\n                                h = q.endY;\n                                q.endX = g * a + h * c + e;\n                                q.endY = g * b + h * d + f;\n                                0 !== b && (g = 180 * Math.atan2(b, a) / Math.PI, 0 > g && (g += 360), q.xAxisRotation += g);\n                                0 > a && (q.xAxisRotation = 180 - q.xAxisRotation, q.isClockwiseArc = !q.isClockwiseArc);\n                                0 > d && (q.xAxisRotation = -q.xAxisRotation, q.isClockwiseArc = !q.isClockwiseArc);\n                                q.radiusX *= Math.sqrt(a * a + c * c);\n                                q.radiusY *= Math.sqrt(b * b + d * d);\n                                break;\n                            default:\n                                B(\"Unknown Segment type: \" +\n                                    q.type)\n                        }\n                    }\n                }\n        }\n        this.qa = !0;\n        return this\n    };\n    t.aa = function (a, b) {\n        void 0 === b && (b = 0);\n        var c = this.Rc,\n            d = this.Sc,\n            e = this.ec,\n            f = this.mc;\n        switch (this.type) {\n            case wd:\n                return J.Nb(c, d, e, f, b, a.x, a.y);\n            case Gd:\n                var g = N.allocAt(Math.min(c, e) - b, Math.min(d, f) - b, Math.abs(e - c) + 2 * b, Math.abs(f - d) + 2 * b);\n                a = g.aa(a);\n                N.free(g);\n                return a;\n            case Hd:\n                g = Math.min(c, e) - b;\n                var h = Math.min(d, f) - b;\n                c = (Math.abs(e - c) + 2 * b) / 2;\n                b = (Math.abs(f - d) + 2 * b) / 2;\n                if (0 >= c || 0 >= b) return !1;\n                g = a.x - (g + c);\n                h = a.y - (h + b);\n                return 1 >= g * g / (c * c) + h * h / (b * b);\n            case ud:\n                return ce(this, a, b, !0, !1);\n            default:\n                return !1\n        }\n    };\n\n    function ce(a, b, c, d, e) {\n        var f = b.x;\n        b = b.y;\n        for (var g = a.bounds.x - 20, h = 0, k, l, m, n, p = a.figures.j, r = p.length, q = 0; q < r; q++) {\n            var u = p[q];\n            if (u.isFilled) {\n                if (d && u.aa(f, b, c)) return !0;\n                var v = u.segments;\n                k = u.startX;\n                l = u.startY;\n                for (var w = k, y = l, z = v.j, A = 0; A <= v.length; A++) {\n                    var C = void 0;\n                    if (A !== v.length) {\n                        C = z[A];\n                        var G = C.type;\n                        a = C.endX;\n                        n = C.endY\n                    } else G = yd, a = w, n = y;\n                    switch (G) {\n                        case Wd:\n                            w = de(f, b, g, b, k, l, w, y);\n                            if (isNaN(w)) return !0;\n                            h += w;\n                            w = a;\n                            y = n;\n                            break;\n                        case yd:\n                            k = de(f, b, g, b, k, l, a, n);\n                            if (isNaN(k)) return !0;\n                            h += k;\n                            break;\n                        case Xd:\n                            m = J.fq(k, l, C.point1X,\n                                C.point1Y, C.point2X, C.point2Y, a, n, g, b, f, b, .5);\n                            h += m;\n                            break;\n                        case Yd:\n                            m = J.fq(k, l, (k + 2 * C.point1X) / 3, (l + 2 * C.point1Y) / 3, (2 * C.point1X + a) / 3, (2 * C.point1Y + n) / 3, a, n, g, b, f, b, .5);\n                            h += m;\n                            break;\n                        case Zd:\n                        case $d:\n                            G = C.type === Zd ? ae(C, u) : be(C, u, k, l);\n                            var L = G.length;\n                            if (0 === L) {\n                                k = de(f, b, g, b, k, l, C.centerX, C.centerY);\n                                if (isNaN(k)) return !0;\n                                h += k;\n                                break\n                            }\n                            C = null;\n                            for (var K = 0; K < L; K++) {\n                                C = G[K];\n                                if (0 === K) {\n                                    m = de(f, b, g, b, k, l, C[0], C[1]);\n                                    if (isNaN(m)) return !0;\n                                    h += m\n                                }\n                                m = J.fq(C[0], C[1], C[2], C[3], C[4], C[5], C[6], C[7], g, b, f, b, .5);\n                                h += m\n                            }\n                            null !== C && (a = C[6],\n                                n = C[7]);\n                            break;\n                        default:\n                            B(\"Unknown Segment type: \" + C.type)\n                    }\n                    k = a;\n                    l = n\n                }\n                if (0 !== h) return !0;\n                h = 0\n            } else if (u.aa(f, b, e ? c : c + 2)) return !0\n        }\n        return 0 !== h\n    }\n\n    function de(a, b, c, d, e, f, g, h) {\n        if (J.Nb(e, f, g, h, .05, a, b)) return NaN;\n        var k = (a - c) * (f - h);\n        if (0 === k) return 0;\n        var l = ((a * d - b * c) * (e - g) - (a - c) * (e * h - f * g)) / k;\n        b = (a * d - b * c) * (f - h) / k;\n        if (l >= a) return 0;\n        if ((e > g ? e - g : g - e) < (f > h ? f - h : h - f))\n            if (f < h) {\n                if (b < f || b > h) return 0\n            } else {\n                if (b < h || b > f) return 0\n            }\n        else if (e < g) {\n            if (l < e || l > g) return 0\n        } else if (l < g || l > e) return 0;\n        return 0 < k ? 1 : -1\n    }\n\n    function ee(a, b, c, d) {\n        a = a.figures.j;\n        for (var e = a.length, f = 0; f < e; f++)\n            if (a[f].aa(b, c, d)) return !0;\n        return !1\n    }\n    t.yv = function (a, b) {\n        0 > a ? a = 0 : 1 < a && (a = 1);\n        void 0 === b && (b = new I);\n        if (this.type === wd) return b.h(this.startX + a * (this.endX - this.startX), this.startY + a * (this.endY - this.startY)), b;\n        for (var c = this.flattenedSegments, d = this.flattenedLengths, e = c.length, f = this.flattenedTotalLength * a, g = 0, h = 0; h < e; h++) {\n            var k = d[h],\n                l = k.length;\n            for (a = 0; a < l; a++) {\n                var m = k[a];\n                if (g + m >= f) return d = f - g, d = 0 === m ? 0 : d / m, c = c[h], h = c[2 * a], e = c[2 * a + 1], b.h(h + (c[2 * a + 2] - h) * d, e + (c[2 * a + 3] - e) * d), b;\n                g += m\n            }\n        }\n        return b\n    };\n    t.Ox = function (a) {\n        0 > a ? a = 0 : 1 < a && (a = 1);\n        if (this.type === wd) return 180 * Math.atan2(this.endY - this.startY, this.endX - this.startX) / Math.PI;\n        for (var b = this.flattenedSegments, c = this.flattenedLengths, d = b.length, e = this.flattenedTotalLength * a, f = 0, g = 0; g < d; g++) {\n            var h = c[g],\n                k = h.length;\n            for (a = 0; a < k; a++) {\n                var l = h[a];\n                if (f + l >= e) return e = b[g], b = e[2 * a], c = e[2 * a + 1], d = e[2 * a + 2], a = e[2 * a + 3], 1 > Math.abs(d - b) && 1 > Math.abs(a - c) ? 0 : 1 > Math.abs(d - b) ? 0 <= a - c ? 90 : 270 : 1 > Math.abs(a - c) ? 0 <= d - b ? 0 : 180 : 180 * Math.atan2(a - c, d - b) / Math.PI;\n                f += l\n            }\n        }\n        return NaN\n    };\n    t.zv = function (a, b) {\n        0 > a ? a = 0 : 1 < a && (a = 1);\n        void 0 === b && (b = []);\n        b.length = 3;\n        if (this.type === wd) return b[0] = this.startX + a * (this.endX - this.startX), b[1] = this.startY + a * (this.endY - this.startY), b[2] = 180 * Math.atan2(this.endY - this.startY, this.endX - this.startX) / Math.PI, b;\n        for (var c = this.flattenedSegments, d = this.flattenedLengths, e = c.length, f = this.flattenedTotalLength * a, g = 0, h = 0; h < e; h++) {\n            var k = d[h],\n                l = k.length;\n            for (a = 0; a < l; a++) {\n                var m = k[a];\n                if (g + m >= f) return d = f - g, d = 0 === m ? 0 : d / m, m = c[h], c = m[2 * a], h = m[2 * a + 1], e = m[2 * a + 2], a = m[2 * a +\n                    3], b[0] = c + (e - c) * d, b[1] = h + (a - h) * d, b[2] = 1 > Math.abs(e - c) && 1 > Math.abs(a - h) ? 0 : 1 > Math.abs(e - c) ? 0 <= a - h ? 90 : 270 : 1 > Math.abs(a - h) ? 0 <= e - c ? 0 : 180 : 180 * Math.atan2(a - h, e - c) / Math.PI, b;\n                g += m\n            }\n        }\n        return b\n    };\n    t.Px = function (a) {\n        if (this.type === wd) {\n            var b = this.startX,\n                c = this.startY,\n                d = this.endX,\n                e = this.endY;\n            if (b !== d || c !== e) {\n                var f = a.x;\n                a = a.y;\n                if (b === d) {\n                    if (c < e) {\n                        var g = c;\n                        d = e\n                    } else g = e, d = c;\n                    return a <= g ? g === c ? 0 : 1 : a >= d ? d === c ? 0 : 1 : Math.abs(a - c) / (d - g)\n                }\n                if (c === e) return b < d ? g = b : (g = d, d = b), f <= g ? g === b ? 0 : 1 : f >= d ? d === b ? 0 : 1 : Math.abs(f - b) / (d - g);\n                g = (d - b) * (d - b) + (e - c) * (e - c);\n                var h = I.alloc();\n                J.Lh(b, c, d, e, f, a, h);\n                a = h.x;\n                f = h.y;\n                I.free(h);\n                return Math.sqrt(((a - b) * (a - b) + (f - c) * (f - c)) / g)\n            }\n        } else if (this.type === Gd) {\n            g = this.startX;\n            h = this.startY;\n            var k = this.endX;\n            e = this.endY;\n            if (g !== k || h !== e) {\n                b = k - g;\n                c = e - h;\n                f = 2 * b + 2 * c;\n                d = a.x;\n                a = a.y;\n                d = Math.min(Math.max(d, g), k);\n                a = Math.min(Math.max(a, h), e);\n                g = Math.abs(d - g);\n                k = Math.abs(d - k);\n                h = Math.abs(a - h);\n                e = Math.abs(a - e);\n                var l = Math.min(g, k, h, e);\n                if (l === h) return d / f;\n                if (l === k) return (b + a) / f;\n                if (l === e) return (2 * b + c - d) / f;\n                if (l === g) return (2 * b + 2 * c - a) / f\n            }\n        } else {\n            b = this.flattenedSegments;\n            c = this.flattenedLengths;\n            f = this.flattenedTotalLength;\n            d = I.alloc();\n            e = Infinity;\n            h = g = 0;\n            k = b.length;\n            for (var m = l = 0, n = 0; n < k; n++)\n                for (var p = b[n], r = c[n], q = p.length, u = 0; u < q; u += 2) {\n                    var v =\n                        p[u],\n                        w = p[u + 1];\n                    if (0 !== u) {\n                        J.Lh(l, m, v, w, a.x, a.y, d);\n                        var y = (d.x - a.x) * (d.x - a.x) + (d.y - a.y) * (d.y - a.y);\n                        y < e && (e = y, g = h, g += Math.sqrt((d.x - l) * (d.x - l) + (d.y - m) * (d.y - m)));\n                        h += r[(u - 2) / 2]\n                    }\n                    l = v;\n                    m = w\n                }\n            I.free(d);\n            a = g / f;\n            return 0 > a ? 0 : 1 < a ? 1 : a\n        }\n        return 0\n    };\n\n    function fe(a) {\n        if (null === a.Gk) {\n            var b = a.Gk = [],\n                c = a.Tm = [],\n                d = [],\n                e = [];\n            if (a.type === wd) d.push(a.startX), d.push(a.startY), d.push(a.endX), d.push(a.endY), b.push(d), e.push(Math.sqrt((a.startX - a.endX) * (a.startX - a.endX) + (a.startY - a.endY) * (a.startY - a.endY))), c.push(e);\n            else if (a.type === Gd) d.push(a.startX), d.push(a.startY), d.push(a.endX), d.push(a.startY), d.push(a.endX), d.push(a.endY), d.push(a.startX), d.push(a.endY), d.push(a.startX), d.push(a.startY), b.push(d), e.push(Math.abs(a.startX - a.endX)), e.push(Math.abs(a.startY -\n                a.endY)), e.push(Math.abs(a.startX - a.endX)), e.push(Math.abs(a.startY - a.endY)), c.push(e);\n            else if (a.type === Hd) {\n                var f = new ke;\n                f.startX = a.endX;\n                f.startY = (a.startY + a.endY) / 2;\n                var g = new le(Zd);\n                g.startAngle = 0;\n                g.sweepAngle = 360;\n                g.centerX = (a.startX + a.endX) / 2;\n                g.centerY = (a.startY + a.endY) / 2;\n                g.radiusX = Math.abs(a.startX - a.endX) / 2;\n                g.radiusY = Math.abs(a.startY - a.endY) / 2;\n                f.add(g);\n                a = ae(g, f);\n                e = a.length;\n                if (0 === e) d.push(g.centerX), d.push(g.centerY);\n                else {\n                    g = f.startX;\n                    f = f.startY;\n                    for (var h = 0; h < e; h++) {\n                        var k = a[h];\n                        J.ye(g, f, k[2], k[3],\n                            k[4], k[5], k[6], k[7], .5, d);\n                        g = k[6];\n                        f = k[7]\n                    }\n                }\n                b.push(d);\n                c.push(me(d))\n            } else\n                for (a = a.figures.iterator; a.next();) {\n                    e = a.value;\n                    d = [];\n                    d.push(e.startX);\n                    d.push(e.startY);\n                    g = e.startX;\n                    f = e.startY;\n                    h = g;\n                    k = f;\n                    for (var l = e.segments.j, m = l.length, n = 0; n < m; n++) {\n                        var p = l[n];\n                        switch (p.type) {\n                            case Wd:\n                                4 <= d.length && (b.push(d), c.push(me(d)));\n                                d = [];\n                                d.push(p.endX);\n                                d.push(p.endY);\n                                g = p.endX;\n                                f = p.endY;\n                                h = g;\n                                k = f;\n                                break;\n                            case yd:\n                                d.push(p.endX);\n                                d.push(p.endY);\n                                g = p.endX;\n                                f = p.endY;\n                                break;\n                            case Xd:\n                                J.ye(g, f, p.point1X, p.point1Y, p.point2X, p.point2Y, p.endX, p.endY,\n                                    .5, d);\n                                g = p.endX;\n                                f = p.endY;\n                                break;\n                            case Yd:\n                                J.Cq(g, f, p.point1X, p.point1Y, p.endX, p.endY, .5, d);\n                                g = p.endX;\n                                f = p.endY;\n                                break;\n                            case Zd:\n                                var r = ae(p, e),\n                                    q = r.length;\n                                if (0 === q) {\n                                    d.push(p.centerX);\n                                    d.push(p.centerY);\n                                    g = p.centerX;\n                                    f = p.centerY;\n                                    break\n                                }\n                                for (var u = 0; u < q; u++) {\n                                    var v = r[u];\n                                    J.ye(g, f, v[2], v[3], v[4], v[5], v[6], v[7], .5, d);\n                                    g = v[6];\n                                    f = v[7]\n                                }\n                                break;\n                            case $d:\n                                r = be(p, e, g, f);\n                                q = r.length;\n                                if (0 === q) {\n                                    d.push(p.centerX);\n                                    d.push(p.centerY);\n                                    g = p.centerX;\n                                    f = p.centerY;\n                                    break\n                                }\n                                for (u = 0; u < q; u++) v = r[u], J.ye(g, f, v[2], v[3], v[4], v[5], v[6], v[7], .5, d), g = v[6],\n                                    f = v[7];\n                                break;\n                            default:\n                                B(\"Segment not of valid type: \" + p.type)\n                        }\n                        p.isClosed && (d.push(h), d.push(k))\n                    }\n                    4 <= d.length && (b.push(d), c.push(me(d)))\n                }\n        }\n    }\n\n    function me(a) {\n        for (var b = [], c = 0, d = 0, e = a.length, f = 0; f < e; f += 2) {\n            var g = a[f],\n                h = a[f + 1];\n            0 !== f && b.push(Math.sqrt(Bb(c, d, g, h)));\n            c = g;\n            d = h\n        }\n        return b\n    }\n    t.add = function (a) {\n        this.rj.add(a);\n        return this\n    };\n    t.Jm = function (a, b, c, d, e, f, g, h) {\n        this.s && ua(this);\n        this.hf = (new P(a, b, e, f)).freeze();\n        this.jf = (new P(c, d, g, h)).freeze();\n        return this\n    };\n    ma.Object.defineProperties(td.prototype, {\n        flattenedSegments: {\n            get: function () {\n                fe(this);\n                return this.Gk\n            }\n        },\n        flattenedLengths: {\n            get: function () {\n                fe(this);\n                return this.Tm\n            }\n        },\n        flattenedTotalLength: {\n            get: function () {\n                var a = this.Um;\n                if (isNaN(a)) {\n                    if (this.type === wd) {\n                        a = Math.abs(this.endX - this.startX);\n                        var b = Math.abs(this.endY - this.startY);\n                        a = Math.sqrt(a * a + b * b)\n                    } else if (this.type === Gd) a = 2 * Math.abs(this.endX - this.startX) + 2 * Math.abs(this.endY -\n                        this.startY);\n                    else {\n                        b = this.flattenedLengths;\n                        for (var c = b.length, d = a = 0; d < c; d++)\n                            for (var e = b[d], f = e.length, g = 0; g < f; g++) a += e[g]\n                    }\n                    this.Um = a\n                }\n                return a\n            }\n        },\n        type: {\n            get: function () {\n                return this.pa\n            },\n            set: function (a) {\n                this.pa !== a && (this.s && ua(this, a), this.pa = a, this.qa = !0)\n            }\n        },\n        startX: {\n            get: function () {\n                return this.Rc\n            },\n            set: function (a) {\n                this.Rc !== a && (this.s && ua(this, a), this.Rc = a, this.qa = !0)\n            }\n        },\n        startY: {\n            get: function () {\n                return this.Sc\n            },\n            set: function (a) {\n                this.Sc !==\n                    a && (this.s && ua(this, a), this.Sc = a, this.qa = !0)\n            }\n        },\n        endX: {\n            get: function () {\n                return this.ec\n            },\n            set: function (a) {\n                this.ec !== a && (this.s && ua(this, a), this.ec = a, this.qa = !0)\n            }\n        },\n        endY: {\n            get: function () {\n                return this.mc\n            },\n            set: function (a) {\n                this.mc !== a && (this.s && ua(this, a), this.mc = a, this.qa = !0)\n            }\n        },\n        figures: {\n            get: function () {\n                return this.rj\n            },\n            set: function (a) {\n                this.rj !== a && (this.s && ua(this, a), this.rj = a, this.qa = !0)\n            }\n        },\n        spot1: {\n            get: function () {\n                return this.hf\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.hf = a.G()\n            }\n        },\n        spot2: {\n            get: function () {\n                return this.jf\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.jf = a.G()\n            }\n        },\n        defaultStretch: {\n            get: function () {\n                return this.Qf\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.Qf = a\n            }\n        },\n        bounds: {\n            get: function () {\n                this.Iv() && this.computeBounds();\n                return this.kr\n            }\n        }\n    });\n    td.prototype.setSpots = td.prototype.Jm;\n    td.prototype.add = td.prototype.add;\n    td.prototype.getFractionForPoint = td.prototype.Px;\n    td.prototype.getPointAndAngleAlongPath = td.prototype.zv;\n    td.prototype.getAngleAlongPath = td.prototype.Ox;\n    td.prototype.getPointAlongPath = td.prototype.yv;\n    td.prototype.containsPoint = td.prototype.aa;\n    td.prototype.transform = td.prototype.transform;\n    td.prototype.rotate = td.prototype.rotate;\n    td.prototype.scale = td.prototype.scale;\n    td.prototype.offset = td.prototype.offset;\n    td.prototype.normalize = td.prototype.normalize;\n    td.prototype.computeBoundsWithoutOrigin = td.prototype.Bx;\n    td.prototype.equalsApprox = td.prototype.Ma;\n    var wd = new D(td, \"Line\", 0),\n        Gd = new D(td, \"Rectangle\", 1),\n        Hd = new D(td, \"Ellipse\", 2),\n        ud = new D(td, \"Path\", 3);\n    td.className = \"Geometry\";\n    td.stringify = zd;\n    td.fillPath = function (a) {\n        a = a.split(/[Xx]/);\n        for (var b = a.length, c = \"\", d = 0; d < b; d++) {\n            var e = a[d];\n            c = null !== e.match(/[Ff]/) ? 0 === d ? c + e : c + (\"X\" + (\" \" === e[0] ? \"\" : \" \") + e) : c + ((0 === d ? \"\" : \"X \") + \"F\" + (\" \" === e[0] ? \"\" : \" \") + e)\n        }\n        return c\n    };\n    td.parse = Id;\n    td.Line = wd;\n    td.Rectangle = Gd;\n    td.Ellipse = Hd;\n    td.Path = ud;\n\n    function ke(a, b, c, d) {\n        Ya(this);\n        this.s = !1;\n        void 0 === c && (c = !0);\n        this.Or = c;\n        void 0 === d && (d = !0);\n        this.Sr = d;\n        void 0 !== a ? this.Rc = a : this.Rc = 0;\n        void 0 !== b ? this.Sc = b : this.Sc = 0;\n        this.Kl = new E;\n        this.Is = this.Kl.Aa;\n        this.qa = !0\n    }\n    ke.prototype.copy = function () {\n        var a = new ke;\n        a.Or = this.Or;\n        a.Sr = this.Sr;\n        a.Rc = this.Rc;\n        a.Sc = this.Sc;\n        for (var b = this.Kl.j, c = b.length, d = a.Kl, e = 0; e < c; e++) {\n            var f = b[e].copy();\n            d.add(f)\n        }\n        a.Is = this.Is;\n        a.qa = this.qa;\n        return a\n    };\n    t = ke.prototype;\n    t.Ma = function (a) {\n        if (!(a instanceof ke && J.A(this.startX, a.startX) && J.A(this.startY, a.startY))) return !1;\n        var b = this.segments.j;\n        a = a.segments.j;\n        var c = b.length;\n        if (c !== a.length) return !1;\n        for (var d = 0; d < c; d++)\n            if (!b[d].Ma(a[d])) return !1;\n        return !0\n    };\n    t.toString = function (a) {\n        void 0 === a && (a = -1);\n        var b = 0 > a ? \"M\" + this.startX.toString() + \" \" + this.startY.toString() : \"M\" + this.startX.toFixed(a) + \" \" + this.startY.toFixed(a);\n        for (var c = this.segments.j, d = c.length, e = 0; e < d; e++) b += \" \" + c[e].toString(a);\n        return b\n    };\n    t.freeze = function () {\n        this.s = !0;\n        var a = this.segments;\n        a.freeze();\n        var b = a.j;\n        a = a.length;\n        for (var c = 0; c < a; c++) b[c].freeze();\n        return this\n    };\n    t.ea = function () {\n        this.s = !1;\n        var a = this.segments;\n        a.ea();\n        a = a.j;\n        for (var b = a.length, c = 0; c < b; c++) a[c].ea();\n        return this\n    };\n    t.Iv = function () {\n        if (this.qa) return !0;\n        var a = this.segments;\n        if (this.Is !== a.Aa) return !0;\n        a = a.j;\n        for (var b = a.length, c = 0; c < b; c++)\n            if (a[c].qa) return !0;\n        return !1\n    };\n    t.add = function (a) {\n        this.Kl.add(a);\n        return this\n    };\n    t.aa = function (a, b, c) {\n        for (var d = this.startX, e = this.startY, f = d, g = e, h = this.segments.j, k = h.length, l = 0; l < k; l++) {\n            var m = h[l];\n            switch (m.type) {\n                case Wd:\n                    f = m.endX;\n                    g = m.endY;\n                    d = m.endX;\n                    e = m.endY;\n                    break;\n                case yd:\n                    if (J.Nb(d, e, m.endX, m.endY, c, a, b)) return !0;\n                    d = m.endX;\n                    e = m.endY;\n                    break;\n                case Xd:\n                    if (J.at(d, e, m.point1X, m.point1Y, m.point2X, m.point2Y, m.endX, m.endY, .5, a, b, c)) return !0;\n                    d = m.endX;\n                    e = m.endY;\n                    break;\n                case Yd:\n                    if (J.Sv(d, e, m.point1X, m.point1Y, m.endX, m.endY, .5, a, b, c)) return !0;\n                    d = m.endX;\n                    e = m.endY;\n                    break;\n                case Zd:\n                case $d:\n                    var n = m.type ===\n                        Zd ? ae(m, this) : be(m, this, d, e),\n                        p = n.length;\n                    if (0 === p) {\n                        if (J.Nb(d, e, m.centerX, m.centerY, c, a, b)) return !0;\n                        d = m.centerX;\n                        e = m.centerY;\n                        break\n                    }\n                    for (var r = null, q = 0; q < p; q++)\n                        if (r = n[q], 0 === q && J.Nb(d, e, r[0], r[1], c, a, b) || J.at(r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], .5, a, b, c)) return !0;\n                    null !== r && (d = r[6], e = r[7]);\n                    break;\n                default:\n                    B(\"Unknown Segment type: \" + m.type)\n            }\n            if (m.isClosed && (d !== f || e !== g) && J.Nb(d, e, f, g, c, a, b)) return !0\n        }\n        return !1\n    };\n    ma.Object.defineProperties(ke.prototype, {\n        isFilled: {\n            get: function () {\n                return this.Or\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.Or = a\n            }\n        },\n        isShadowed: {\n            get: function () {\n                return this.Sr\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.Sr = a\n            }\n        },\n        startX: {\n            get: function () {\n                return this.Rc\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.Rc = a;\n                this.qa = !0\n            }\n        },\n        startY: {\n            get: function () {\n                return this.Sc\n            },\n            set: function (a) {\n                this.s && ua(this,\n                    a);\n                this.Sc = a;\n                this.qa = !0\n            }\n        },\n        segments: {\n            get: function () {\n                return this.Kl\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.Kl = a;\n                this.qa = !0\n            }\n        }\n    });\n    ke.prototype.add = ke.prototype.add;\n    ke.prototype.equalsApprox = ke.prototype.Ma;\n    ke.className = \"PathFigure\";\n\n    function le(a, b, c, d, e, f, g, h) {\n        Ya(this);\n        this.s = !1;\n        void 0 === a && (a = yd);\n        this.pa = a;\n        void 0 !== b ? this.ec = b : this.ec = 0;\n        void 0 !== c ? this.mc = c : this.mc = 0;\n        void 0 === d && (d = 0);\n        void 0 === e && (e = 0);\n        void 0 === f && (f = 0);\n        void 0 === g && (g = 0);\n        a === $d ? (a = f % 360, 0 > a && (a += 360), this.ue = a, this.Di = 0, this.Ei = Math.max(d, 0), this.kh = Math.max(e, 0), this.sl = \"boolean\" === typeof g ? !!g : !1, this.Kk = !!h) : (this.ue = d, this.Di = e, a === Zd && (f = Math.max(f, 0)), this.Ei = f, \"number\" === typeof g ? (a === Zd && (g = Math.max(g, 0)), this.kh = g) : this.kh = 0, this.Kk = this.sl = !1);\n        this.wj = !1;\n        this.qa = !0;\n        this.Le = null\n    }\n    le.prototype.copy = function () {\n        var a = new le;\n        a.pa = this.pa;\n        a.ec = this.ec;\n        a.mc = this.mc;\n        a.ue = this.ue;\n        a.Di = this.Di;\n        a.Ei = this.Ei;\n        a.kh = this.kh;\n        a.sl = this.sl;\n        a.Kk = this.Kk;\n        a.wj = this.wj;\n        a.qa = this.qa;\n        return a\n    };\n    t = le.prototype;\n    t.Ma = function (a) {\n        if (!(a instanceof le) || this.type !== a.type || this.isClosed !== a.isClosed) return !1;\n        switch (this.type) {\n            case Wd:\n            case yd:\n                return J.A(this.endX, a.endX) && J.A(this.endY, a.endY);\n            case Xd:\n                return J.A(this.endX, a.endX) && J.A(this.endY, a.endY) && J.A(this.point1X, a.point1X) && J.A(this.point1Y, a.point1Y) && J.A(this.point2X, a.point2X) && J.A(this.point2Y, a.point2Y);\n            case Yd:\n                return J.A(this.endX, a.endX) && J.A(this.endY, a.endY) && J.A(this.point1X, a.point1X) && J.A(this.point1Y, a.point1Y);\n            case Zd:\n                return J.A(this.startAngle,\n                    a.startAngle) && J.A(this.sweepAngle, a.sweepAngle) && J.A(this.centerX, a.centerX) && J.A(this.centerY, a.centerY) && J.A(this.radiusX, a.radiusX) && J.A(this.radiusY, a.radiusY);\n            case $d:\n                return this.isClockwiseArc === a.isClockwiseArc && this.isLargeArc === a.isLargeArc && J.A(this.xAxisRotation, a.xAxisRotation) && J.A(this.endX, a.endX) && J.A(this.endY, a.endY) && J.A(this.radiusX, a.radiusX) && J.A(this.radiusY, a.radiusY);\n            default:\n                return !1\n        }\n    };\n    t.cb = function (a) {\n        a.classType === le && (this.type = a)\n    };\n    t.toString = function (a) {\n        void 0 === a && (a = -1);\n        switch (this.type) {\n            case Wd:\n                a = 0 > a ? \"M\" + this.endX.toString() + \" \" + this.endY.toString() : \"M\" + this.endX.toFixed(a) + \" \" + this.endY.toFixed(a);\n                break;\n            case yd:\n                a = 0 > a ? \"L\" + this.endX.toString() + \" \" + this.endY.toString() : \"L\" + this.endX.toFixed(a) + \" \" + this.endY.toFixed(a);\n                break;\n            case Xd:\n                a = 0 > a ? \"C\" + this.point1X.toString() + \" \" + this.point1Y.toString() + \" \" + this.point2X.toString() + \" \" + this.point2Y.toString() + \" \" + this.endX.toString() + \" \" + this.endY.toString() : \"C\" + this.point1X.toFixed(a) +\n                    \" \" + this.point1Y.toFixed(a) + \" \" + this.point2X.toFixed(a) + \" \" + this.point2Y.toFixed(a) + \" \" + this.endX.toFixed(a) + \" \" + this.endY.toFixed(a);\n                break;\n            case Yd:\n                a = 0 > a ? \"Q\" + this.point1X.toString() + \" \" + this.point1Y.toString() + \" \" + this.endX.toString() + \" \" + this.endY.toString() : \"Q\" + this.point1X.toFixed(a) + \" \" + this.point1Y.toFixed(a) + \" \" + this.endX.toFixed(a) + \" \" + this.endY.toFixed(a);\n                break;\n            case Zd:\n                a = 0 > a ? \"B\" + this.startAngle.toString() + \" \" + this.sweepAngle.toString() + \" \" + this.centerX.toString() + \" \" + this.centerY.toString() +\n                    \" \" + this.radiusX.toString() + \" \" + this.radiusY.toString() : \"B\" + this.startAngle.toFixed(a) + \" \" + this.sweepAngle.toFixed(a) + \" \" + this.centerX.toFixed(a) + \" \" + this.centerY.toFixed(a) + \" \" + this.radiusX.toFixed(a) + \" \" + this.radiusY.toFixed(a);\n                break;\n            case $d:\n                a = 0 > a ? \"A\" + this.radiusX.toString() + \" \" + this.radiusY.toString() + \" \" + this.xAxisRotation.toString() + \" \" + (this.isLargeArc ? 1 : 0) + \" \" + (this.isClockwiseArc ? 1 : 0) + \" \" + this.endX.toString() + \" \" + this.endY.toString() : \"A\" + this.radiusX.toFixed(a) + \" \" + this.radiusY.toFixed(a) +\n                    \" \" + this.xAxisRotation.toFixed(a) + \" \" + (this.isLargeArc ? 1 : 0) + \" \" + (this.isClockwiseArc ? 1 : 0) + \" \" + this.endX.toFixed(a) + \" \" + this.endY.toFixed(a);\n                break;\n            default:\n                a = this.type.toString()\n        }\n        return a + (this.wj ? \"z\" : \"\")\n    };\n    t.freeze = function () {\n        this.s = !0;\n        return this\n    };\n    t.ea = function () {\n        this.s = !1;\n        return this\n    };\n    t.close = function () {\n        this.wj = !0;\n        return this\n    };\n\n    function ae(a, b) {\n        if (null !== a.Le && !1 === b.qa) return a.Le;\n        var c = a.radiusX,\n            d = a.radiusY;\n        void 0 === d && (d = c);\n        if (0 === c || 0 === d) return a.Le = [], a.Le;\n        b = a.ue;\n        var e = a.Di,\n            f = J.Cx(0, 0, c < d ? c : d, a.startAngle, a.startAngle + a.sweepAngle, !1);\n        if (c !== d) {\n            var g = rd.alloc();\n            g.reset();\n            c < d ? g.scale(1, d / c) : g.scale(c / d, 1);\n            Ud(f, g);\n            rd.free(g)\n        }\n        c = f.length;\n        for (d = 0; d < c; d++) g = f[d], g[0] += b, g[1] += e, g[2] += b, g[3] += e, g[4] += b, g[5] += e, g[6] += b, g[7] += e;\n        a.Le = f;\n        return a.Le\n    }\n\n    function be(a, b, c, d) {\n        function e(a, b, c, d) {\n            return (a * d < b * c ? -1 : 1) * Math.acos((a * c + b * d) / (Math.sqrt(a * a + b * b) * Math.sqrt(c * c + d * d)))\n        }\n        if (null !== a.Le && !1 === b.qa) return a.Le;\n        b = a.Ei;\n        var f = a.kh;\n        0 === b && (b = 1E-4);\n        0 === f && (f = 1E-4);\n        var g = Math.PI / 180 * a.ue,\n            h = a.sl,\n            k = a.Kk,\n            l = a.ec,\n            m = a.mc,\n            n = Math.cos(g),\n            p = Math.sin(g),\n            r = n * (c - l) / 2 + p * (d - m) / 2;\n        g = -p * (c - l) / 2 + n * (d - m) / 2;\n        var q = r * r / (b * b) + g * g / (f * f);\n        1 < q && (b *= Math.sqrt(q), f *= Math.sqrt(q));\n        q = (h === k ? -1 : 1) * Math.sqrt((b * b * f * f - b * b * g * g - f * f * r * r) / (b * b * g * g + f * f * r * r));\n        isNaN(q) && (q = 0);\n        h = q * b * g / f;\n        q = q * -f *\n            r / b;\n        isNaN(h) && (h = 0);\n        isNaN(q) && (q = 0);\n        c = (c + l) / 2 + n * h - p * q;\n        d = (d + m) / 2 + p * h + n * q;\n        m = e(1, 0, (r - h) / b, (g - q) / f);\n        n = (r - h) / b;\n        l = (g - q) / f;\n        r = (-r - h) / b;\n        h = (-g - q) / f;\n        g = e(n, l, r, h);\n        r = (n * r + l * h) / (Math.sqrt(n * n + l * l) * Math.sqrt(r * r + h * h)); - 1 >= r ? g = Math.PI : 1 <= r && (g = 0);\n        !k && 0 < g && (g -= 2 * Math.PI);\n        k && 0 > g && (g += 2 * Math.PI);\n        k = b > f ? 1 : b / f;\n        r = b > f ? f / b : 1;\n        b = J.Cx(0, 0, b > f ? b : f, m, m + g, !0);\n        f = rd.alloc();\n        f.reset();\n        f.translate(c, d);\n        f.rotate(a.ue, 0, 0);\n        f.scale(k, r);\n        Ud(b, f);\n        rd.free(f);\n        a.Le = b;\n        return a.Le\n    }\n    ma.Object.defineProperties(le.prototype, {\n        isClosed: {\n            get: function () {\n                return this.wj\n            },\n            set: function (a) {\n                this.wj !== a && (this.wj = a, this.qa = !0)\n            }\n        },\n        type: {\n            get: function () {\n                return this.pa\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.pa = a;\n                this.qa = !0\n            }\n        },\n        endX: {\n            get: function () {\n                return this.ec\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.ec = a;\n                this.qa = !0\n            }\n        },\n        endY: {\n            get: function () {\n                return this.mc\n            },\n            set: function (a) {\n                this.s &&\n                    ua(this, a);\n                this.mc = a;\n                this.qa = !0\n            }\n        },\n        point1X: {\n            get: function () {\n                return this.ue\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.ue = a;\n                this.qa = !0\n            }\n        },\n        point1Y: {\n            get: function () {\n                return this.Di\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.Di = a;\n                this.qa = !0\n            }\n        },\n        point2X: {\n            get: function () {\n                return this.Ei\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.Ei = a;\n                this.qa = !0\n            }\n        },\n        point2Y: {\n            get: function () {\n                return this.kh\n            },\n            set: function (a) {\n                this.s &&\n                    ua(this, a);\n                this.kh = a;\n                this.qa = !0\n            }\n        },\n        centerX: {\n            get: function () {\n                return this.ue\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.ue = a;\n                this.qa = !0\n            }\n        },\n        centerY: {\n            get: function () {\n                return this.Di\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.Di = a;\n                this.qa = !0\n            }\n        },\n        radiusX: {\n            get: function () {\n                return this.Ei\n            },\n            set: function (a) {\n                0 > a && va(a, \">= zero\", le, \"radiusX\");\n                this.s && ua(this, a);\n                this.Ei = a;\n                this.qa = !0\n            }\n        },\n        radiusY: {\n            get: function () {\n                return this.kh\n            },\n            set: function (a) {\n                0 > a && va(a, \">= zero\", le, \"radiusY\");\n                this.s && ua(this, a);\n                this.kh = a;\n                this.qa = !0\n            }\n        },\n        startAngle: {\n            get: function () {\n                return this.ec\n            },\n            set: function (a) {\n                this.ec !== a && (this.s && ua(this, a), a %= 360, 0 > a && (a += 360), this.ec = a, this.qa = !0)\n            }\n        },\n        sweepAngle: {\n            get: function () {\n                return this.mc\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                360 < a && (a = 360); - 360 > a && (a = -360);\n                this.mc = a;\n                this.qa = !0\n            }\n        },\n        isClockwiseArc: {\n            get: function () {\n                return this.Kk\n            },\n            set: function (a) {\n                this.s &&\n                    ua(this, a);\n                this.Kk = a;\n                this.qa = !0\n            }\n        },\n        isLargeArc: {\n            get: function () {\n                return this.sl\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.sl = a;\n                this.qa = !0\n            }\n        },\n        xAxisRotation: {\n            get: function () {\n                return this.ue\n            },\n            set: function (a) {\n                a %= 360;\n                0 > a && (a += 360);\n                this.s && ua(this, a);\n                this.ue = a;\n                this.qa = !0\n            }\n        }\n    });\n    le.prototype.equalsApprox = le.prototype.Ma;\n    var Wd = new D(le, \"Move\", 0),\n        yd = new D(le, \"Line\", 1),\n        Xd = new D(le, \"Bezier\", 2),\n        Yd = new D(le, \"QuadraticBezier\", 3),\n        Zd = new D(le, \"Arc\", 4),\n        $d = new D(le, \"SvgArc\", 4);\n    le.className = \"PathSegment\";\n    le.Move = Wd;\n    le.Line = yd;\n    le.Bezier = Xd;\n    le.QuadraticBezier = Yd;\n    le.Arc = Zd;\n    le.SvgArc = $d;\n\n    function ne() {\n        this.B = null;\n        this.Yu = (new I(0, 0)).freeze();\n        this.iu = (new I(0, 0)).freeze();\n        this.cr = this.fs = 0;\n        this.dr = 1;\n        this.Wr = \"\";\n        this.Ws = this.xr = !1;\n        this.ur = this.fr = 0;\n        this.Mg = this.Hr = this.Qr = !1;\n        this.Cr = null;\n        this.Rs = 0;\n        this.bd = this.Qs = null\n    }\n    ne.prototype.copy = function () {\n        var a = new ne;\n        return this.clone(a)\n    };\n    ne.prototype.clone = function (a) {\n        a.B = this.B;\n        a.Yu.assign(this.viewPoint);\n        a.iu.assign(this.documentPoint);\n        a.fs = this.fs;\n        a.cr = this.cr;\n        a.dr = this.dr;\n        a.Wr = this.Wr;\n        a.xr = this.xr;\n        a.Ws = this.Ws;\n        a.fr = this.fr;\n        a.ur = this.ur;\n        a.Qr = this.Qr;\n        a.Hr = this.Hr;\n        a.Mg = this.Mg;\n        a.Cr = this.Cr;\n        a.Rs = this.Rs;\n        a.Qs = this.Qs;\n        a.bd = this.bd;\n        return a\n    };\n    ne.prototype.toString = function () {\n        var a = \"^\";\n        0 !== this.modifiers && (a += \"M:\" + this.modifiers);\n        0 !== this.button && (a += \"B:\" + this.button);\n        \"\" !== this.key && (a += \"K:\" + this.key);\n        0 !== this.clickCount && (a += \"C:\" + this.clickCount);\n        0 !== this.delta && (a += \"D:\" + this.delta);\n        this.handled && (a += \"h\");\n        this.bubbles && (a += \"b\");\n        null !== this.documentPoint && (a += \"@\" + this.documentPoint.toString());\n        return a\n    };\n    ne.prototype.oq = function (a, b) {\n        var c = this.diagram;\n        if (null === c) return b;\n        oe(c, this.event, a, b);\n        return b\n    };\n    ne.prototype.Ez = function (a, b) {\n        var c = this.diagram;\n        if (null === c) return b;\n        oe(c, this.event, a, b);\n        b.assign(c.Pt(b));\n        return b\n    };\n    ma.Object.defineProperties(ne.prototype, {\n        diagram: {\n            get: function () {\n                return this.B\n            },\n            set: function (a) {\n                this.B = a\n            }\n        },\n        viewPoint: {\n            get: function () {\n                return this.Yu\n            },\n            set: function (a) {\n                this.Yu.assign(a)\n            }\n        },\n        documentPoint: {\n            get: function () {\n                return this.iu\n            },\n            set: function (a) {\n                this.iu.assign(a)\n            }\n        },\n        modifiers: {\n            get: function () {\n                return this.fs\n            },\n            set: function (a) {\n                this.fs = a\n            }\n        },\n        button: {\n            get: function () {\n                return this.cr\n            },\n            set: function (a) {\n                this.cr = a;\n                if (null === this.event) switch (a) {\n                    case 0:\n                        this.buttons = 1;\n                        break;\n                    case 1:\n                        this.buttons = 4;\n                        break;\n                    case 2:\n                        this.buttons = 2\n                }\n            }\n        },\n        buttons: {\n            get: function () {\n                return this.dr\n            },\n            set: function (a) {\n                this.dr = a\n            }\n        },\n        key: {\n            get: function () {\n                return this.Wr\n            },\n            set: function (a) {\n                this.Wr = a\n            }\n        },\n        down: {\n            get: function () {\n                return this.xr\n            },\n            set: function (a) {\n                this.xr = a\n            }\n        },\n        up: {\n            get: function () {\n                return this.Ws\n            },\n            set: function (a) {\n                this.Ws =\n                    a\n            }\n        },\n        clickCount: {\n            get: function () {\n                return this.fr\n            },\n            set: function (a) {\n                this.fr = a\n            }\n        },\n        delta: {\n            get: function () {\n                return this.ur\n            },\n            set: function (a) {\n                this.ur = a\n            }\n        },\n        isMultiTouch: {\n            get: function () {\n                return this.Qr\n            },\n            set: function (a) {\n                this.Qr = a\n            }\n        },\n        handled: {\n            get: function () {\n                return this.Hr\n            },\n            set: function (a) {\n                this.Hr = a\n            }\n        },\n        bubbles: {\n            get: function () {\n                return this.Mg\n            },\n            set: function (a) {\n                this.Mg = a\n            }\n        },\n        event: {\n            get: function () {\n                return this.Cr\n            },\n            set: function (a) {\n                this.Cr = a\n            }\n        },\n        isTouchEvent: {\n            get: function () {\n                var a = x.TouchEvent,\n                    b = this.event;\n                return a && b instanceof a ? !0 : (a = x.PointerEvent) && b instanceof a && (\"touch\" === b.pointerType || \"pen\" === b.pointerType)\n            }\n        },\n        timestamp: {\n            get: function () {\n                return this.Rs\n            },\n            set: function (a) {\n                this.Rs = a\n            }\n        },\n        targetDiagram: {\n            get: function () {\n                return this.Qs\n            },\n            set: function (a) {\n                this.Qs = a\n            }\n        },\n        targetObject: {\n            get: function () {\n                return this.bd\n            },\n            set: function (a) {\n                this.bd = a\n            }\n        },\n        control: {\n            get: function () {\n                return 0 !== (this.modifiers & 1)\n            },\n            set: function (a) {\n                this.modifiers = a ? this.modifiers | 1 : this.modifiers & -2\n            }\n        },\n        shift: {\n            get: function () {\n                return 0 !== (this.modifiers & 4)\n            },\n            set: function (a) {\n                this.modifiers = a ? this.modifiers | 4 : this.modifiers & -5\n            }\n        },\n        alt: {\n            get: function () {\n                return 0 !== (this.modifiers & 2)\n            },\n            set: function (a) {\n                this.modifiers = a ? this.modifiers |\n                    2 : this.modifiers & -3\n            }\n        },\n        meta: {\n            get: function () {\n                return 0 !== (this.modifiers & 8)\n            },\n            set: function (a) {\n                this.modifiers = a ? this.modifiers | 8 : this.modifiers & -9\n            }\n        },\n        left: {\n            get: function () {\n                var a = this.event;\n                return null === a || \"mousedown\" !== a.type && \"mouseup\" !== a.type && \"pointerdown\" !== a.type && \"pointerup\" !== a.type ? 0 !== (this.buttons & 1) : 0 === this.button\n            },\n            set: function (a) {\n                this.buttons = a ? this.buttons | 1 : this.buttons & -2\n            }\n        },\n        right: {\n            get: function () {\n                var a =\n                    this.event;\n                return null === a || \"mousedown\" !== a.type && \"mouseup\" !== a.type && \"pointerdown\" !== a.type && \"pointerup\" !== a.type ? 0 !== (this.buttons & 2) : 2 === this.button\n            },\n            set: function (a) {\n                this.buttons = a ? this.buttons | 2 : this.buttons & -3\n            }\n        },\n        middle: {\n            get: function () {\n                var a = this.event;\n                return null === a || \"mousedown\" !== a.type && \"mouseup\" !== a.type && \"pointerdown\" !== a.type && \"pointerup\" !== a.type ? 0 !== (this.buttons & 4) : 1 === this.button\n            },\n            set: function (a) {\n                this.buttons = a ? this.buttons | 4 : this.buttons & -5\n            }\n        }\n    });\n    ne.prototype.getMultiTouchDocumentPoint = ne.prototype.Ez;\n    ne.prototype.getMultiTouchViewPoint = ne.prototype.oq;\n    ne.className = \"InputEvent\";\n\n    function pe() {\n        this.B = null;\n        this.Ra = \"\";\n        this.qs = this.Ps = null\n    }\n    pe.prototype.copy = function () {\n        var a = new pe;\n        a.B = this.B;\n        a.Ra = this.Ra;\n        a.Ps = this.Ps;\n        a.qs = this.qs;\n        return a\n    };\n    pe.prototype.toString = function () {\n        var a = \"*\" + this.name;\n        null !== this.subject && (a += \":\" + this.subject.toString());\n        null !== this.parameter && (a += \"(\" + this.parameter.toString() + \")\");\n        return a\n    };\n    ma.Object.defineProperties(pe.prototype, {\n        diagram: {\n            get: function () {\n                return this.B\n            },\n            set: function (a) {\n                this.B = a\n            }\n        },\n        name: {\n            get: function () {\n                return this.Ra\n            },\n            set: function (a) {\n                this.Ra = a\n            }\n        },\n        subject: {\n            get: function () {\n                return this.Ps\n            },\n            set: function (a) {\n                this.Ps = a\n            }\n        },\n        parameter: {\n            get: function () {\n                return this.qs\n            },\n            set: function (a) {\n                this.qs = a\n            }\n        }\n    });\n    pe.className = \"DiagramEvent\";\n\n    function qe() {\n        this.dn = re;\n        this.af = this.es = \"\";\n        this.Oo = this.Po = this.Vo = this.Wo = this.Uo = this.B = this.ac = null\n    }\n    qe.prototype.clear = function () {\n        this.Oo = this.Po = this.Vo = this.Wo = this.Uo = this.B = this.ac = null\n    };\n    qe.prototype.copy = function () {\n        var a = new qe;\n        a.dn = this.dn;\n        a.es = this.es;\n        a.af = this.af;\n        a.ac = this.ac;\n        a.B = this.B;\n        a.Uo = this.Uo;\n        var b = this.Wo;\n        a.Wo = za(b) && \"function\" === typeof b.G ? b.G() : b;\n        b = this.Vo;\n        a.Vo = za(b) && \"function\" === typeof b.G ? b.G() : b;\n        b = this.Po;\n        a.Po = za(b) && \"function\" === typeof b.G ? b.G() : b;\n        b = this.Oo;\n        a.Oo = za(b) && \"function\" === typeof b.G ? b.G() : b;\n        return a\n    };\n    qe.prototype.cb = function (a) {\n        a.classType === qe && (this.change = a)\n    };\n    qe.prototype.toString = function () {\n        var a = \"\";\n        a = this.change === se ? a + \"* \" : this.change === re ? a + (null !== this.model ? \"!m\" : \"!d\") : a + ((null !== this.model ? \"!m\" : \"!d\") + this.change);\n        this.propertyName && \"string\" === typeof this.propertyName && (a += \" \" + this.propertyName);\n        this.modelChange && this.modelChange !== this.propertyName && (a += \" \" + this.modelChange);\n        a += \": \";\n        this.change === se ? null !== this.oldValue && (a += \" \" + this.oldValue) : (null !== this.object && (a += Ja(this.object)), null !== this.oldValue && (a += \"  old: \" + Ja(this.oldValue)), null !==\n            this.oldParam && (a += \" \" + this.oldParam), null !== this.newValue && (a += \"  new: \" + Ja(this.newValue)), null !== this.newParam && (a += \" \" + this.newParam));\n        return a\n    };\n    qe.prototype.H = function (a) {\n        return a ? this.oldValue : this.newValue\n    };\n    qe.prototype.Gz = function (a) {\n        return a ? this.oldParam : this.newParam\n    };\n    qe.prototype.canUndo = function () {\n        return null !== this.model || null !== this.diagram ? !0 : !1\n    };\n    qe.prototype.undo = function () {\n        this.canUndo() && (null !== this.model ? this.model.changeState(this, !0) : null !== this.diagram && this.diagram.changeState(this, !0))\n    };\n    qe.prototype.canRedo = function () {\n        return null !== this.model || null !== this.diagram ? !0 : !1\n    };\n    qe.prototype.redo = function () {\n        this.canRedo() && (null !== this.model ? this.model.changeState(this, !1) : null !== this.diagram && this.diagram.changeState(this, !1))\n    };\n    ma.Object.defineProperties(qe.prototype, {\n        model: {\n            get: function () {\n                return this.ac\n            },\n            set: function (a) {\n                this.ac = a\n            }\n        },\n        diagram: {\n            get: function () {\n                return this.B\n            },\n            set: function (a) {\n                this.B = a\n            }\n        },\n        change: {\n            get: function () {\n                return this.dn\n            },\n            set: function (a) {\n                this.dn = a\n            }\n        },\n        modelChange: {\n            get: function () {\n                return this.es\n            },\n            set: function (a) {\n                this.es = a\n            }\n        },\n        propertyName: {\n            get: function () {\n                return this.af\n            },\n            set: function (a) {\n                this.af = a\n            }\n        },\n        isTransactionFinished: {\n            get: function () {\n                return this.dn === se && (\"CommittedTransaction\" === this.af || \"FinishedUndo\" === this.af || \"FinishedRedo\" === this.af)\n            }\n        },\n        object: {\n            get: function () {\n                return this.Uo\n            },\n            set: function (a) {\n                this.Uo = a\n            }\n        },\n        oldValue: {\n            get: function () {\n                return this.Wo\n            },\n            set: function (a) {\n                this.Wo = a\n            }\n        },\n        oldParam: {\n            get: function () {\n                return this.Vo\n            },\n            set: function (a) {\n                this.Vo = a\n            }\n        },\n        newValue: {\n            get: function () {\n                return this.Po\n            },\n            set: function (a) {\n                this.Po = a\n            }\n        },\n        newParam: {\n            get: function () {\n                return this.Oo\n            },\n            set: function (a) {\n                this.Oo = a\n            }\n        }\n    });\n    qe.prototype.redo = qe.prototype.redo;\n    qe.prototype.canRedo = qe.prototype.canRedo;\n    qe.prototype.undo = qe.prototype.undo;\n    qe.prototype.canUndo = qe.prototype.canUndo;\n    qe.prototype.getParam = qe.prototype.Gz;\n    qe.prototype.getValue = qe.prototype.H;\n    qe.prototype.clear = qe.prototype.clear;\n    var se = new D(qe, \"Transaction\", -1),\n        re = new D(qe, \"Property\", 0),\n        te = new D(qe, \"Insert\", 1),\n        ue = new D(qe, \"Remove\", 2);\n    qe.className = \"ChangedEvent\";\n    qe.Transaction = se;\n    qe.Property = re;\n    qe.Insert = te;\n    qe.Remove = ue;\n\n    function ve() {\n        this.u = (new E).freeze();\n        this.Ra = \"\";\n        this.l = !1\n    }\n    ve.prototype.toString = function (a) {\n        var b = \"Transaction: \" + this.name + \" \" + this.changes.count.toString() + (this.isComplete ? \"\" : \", incomplete\");\n        if (void 0 !== a && 0 < a) {\n            a = this.changes.count;\n            for (var c = 0; c < a; c++) {\n                var d = this.changes.L(c);\n                null !== d && (b += \"\\n  \" + d.toString())\n            }\n        }\n        return b\n    };\n    ve.prototype.clear = function () {\n        var a = this.changes;\n        a.ea();\n        for (var b = a.count - 1; 0 <= b; b--) {\n            var c = a.L(b);\n            null !== c && c.clear()\n        }\n        a.clear();\n        a.freeze()\n    };\n    ve.prototype.canUndo = function () {\n        return this.isComplete\n    };\n    ve.prototype.undo = function () {\n        if (this.canUndo())\n            for (var a = this.changes.count - 1; 0 <= a; a--) {\n                var b = this.changes.L(a);\n                null !== b && b.undo()\n            }\n    };\n    ve.prototype.canRedo = function () {\n        return this.isComplete\n    };\n    ve.prototype.redo = function () {\n        if (this.canRedo())\n            for (var a = this.changes.count, b = 0; b < a; b++) {\n                var c = this.changes.L(b);\n                null !== c && c.redo()\n            }\n    };\n    ma.Object.defineProperties(ve.prototype, {\n        changes: {\n            get: function () {\n                return this.u\n            }\n        },\n        name: {\n            get: function () {\n                return this.Ra\n            },\n            set: function (a) {\n                this.Ra = a\n            }\n        },\n        isComplete: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l = a\n            }\n        }\n    });\n    ve.prototype.redo = ve.prototype.redo;\n    ve.prototype.canRedo = ve.prototype.canRedo;\n    ve.prototype.undo = ve.prototype.undo;\n    ve.prototype.canUndo = ve.prototype.canUndo;\n    ve.prototype.clear = ve.prototype.clear;\n    ve.className = \"Transaction\";\n\n    function we() {\n        this.Fu = new F;\n        this.Mc = !1;\n        this.I = (new E).freeze();\n        this.Gd = -1;\n        this.u = 999;\n        this.ke = !1;\n        this.rr = null;\n        this.Li = 0;\n        this.l = !1;\n        this.qe = (new E).freeze();\n        this.Al = new E;\n        this.pu = !0;\n        this.zu = !1\n    }\n    we.prototype.toString = function (a) {\n        var b = \"UndoManager \" + this.historyIndex + \"<\" + this.history.count + \"<=\" + this.maxHistoryLength;\n        b += \"[\";\n        for (var c = this.nestedTransactionNames.count, d = 0; d < c; d++) 0 < d && (b += \" \"), b += this.nestedTransactionNames.L(d);\n        b += \"]\";\n        if (void 0 !== a && 0 < a)\n            for (c = this.history.count, d = 0; d < c; d++) b += \"\\n \" + this.history.L(d).toString(a - 1);\n        return b\n    };\n    we.prototype.clear = function () {\n        var a = this.history;\n        a.ea();\n        for (var b = a.count - 1; 0 <= b; b--) {\n            var c = a.L(b);\n            null !== c && c.clear()\n        }\n        a.clear();\n        this.Gd = -1;\n        a.freeze();\n        this.ke = !1;\n        this.rr = null;\n        this.Li = 0;\n        this.qe.ea();\n        this.qe.clear();\n        this.qe.freeze();\n        this.Al.clear()\n    };\n    we.prototype.copyProperties = function (a) {\n        this.isEnabled = a.isEnabled;\n        this.maxHistoryLength = a.maxHistoryLength;\n        this.checksTransactionLevel = a.checksTransactionLevel\n    };\n    t = we.prototype;\n    t.ux = function (a) {\n        this.Fu.add(a)\n    };\n    t.by = function (a) {\n        this.Fu.remove(a)\n    };\n    t.ua = function (a) {\n        void 0 === a && (a = \"\");\n        null === a && (a = \"\");\n        if (this.isUndoingRedoing) return !1;\n        !0 === this.pu && (this.pu = !1, this.Li++, this.xb(\"StartingFirstTransaction\", a, this.currentTransaction), 0 < this.Li && this.Li--);\n        this.isEnabled && (this.qe.ea(), this.qe.add(a), this.qe.freeze(), null === this.currentTransaction ? this.Al.add(0) : this.Al.add(this.currentTransaction.changes.count));\n        this.Li++;\n        var b = 1 === this.transactionLevel;\n        b && this.xb(\"StartedTransaction\", a, this.currentTransaction);\n        return b\n    };\n    t.Ua = function (a) {\n        void 0 === a && (a = \"\");\n        return xe(this, !0, a)\n    };\n    t.Bf = function () {\n        return xe(this, !1, \"\")\n    };\n\n    function xe(a, b, c) {\n        if (a.isUndoingRedoing) return !1;\n        a.checksTransactionLevel && 1 > a.transactionLevel && wa(\"Ending transaction without having started a transaction: \" + c);\n        var d = 1 === a.transactionLevel;\n        d && b && a.xb(\"CommittingTransaction\", c, a.currentTransaction);\n        var e = 0;\n        if (0 < a.transactionLevel && (a.Li--, a.isEnabled)) {\n            var f = a.qe.count;\n            0 < f && (\"\" === c && (c = a.qe.L(0)), a.qe.ea(), a.qe.lb(f - 1), a.qe.freeze());\n            f = a.Al.count;\n            0 < f && (e = a.Al.L(f - 1), a.Al.lb(f - 1))\n        }\n        f = a.currentTransaction;\n        if (d) {\n            if (b) {\n                a.zu = !1;\n                if (a.isEnabled && null !==\n                    f) {\n                    b = f;\n                    b.isComplete = !0;\n                    b.name = c;\n                    d = a.history;\n                    d.ea();\n                    for (e = d.count - 1; e > a.historyIndex; e--) f = d.L(e), null !== f && f.clear(), d.lb(e), a.zu = !0;\n                    e = a.maxHistoryLength;\n                    0 <= e && (0 === e ? d.clear() : d.count >= e && (f = d.L(0), null !== f && f.clear(), d.lb(0), a.Gd--));\n                    0 !== e && (d.add(b), a.Gd++);\n                    d.freeze();\n                    f = b\n                }\n                a.xb(\"CommittedTransaction\", c, f)\n            } else {\n                a.ke = !0;\n                try {\n                    a.isEnabled && null !== f && (f.isComplete = !0, f.undo())\n                } finally {\n                    a.xb(\"RolledBackTransaction\", c, f), a.ke = !1\n                }\n                null !== f && f.clear()\n            }\n            a.rr = null;\n            return !0\n        }\n        if (a.isEnabled && !b && null !== f) {\n            a = e;\n            c =\n                f.changes;\n            for (b = c.count - 1; b >= a; b--) d = c.L(b), null !== d && d.undo(), c.ea(), c.lb(b);\n            c.freeze()\n        }\n        return !1\n    }\n    we.prototype.canUndo = function () {\n        if (!this.isEnabled || 0 < this.transactionLevel) return !1;\n        var a = this.transactionToUndo;\n        return null !== a && a.canUndo() ? !0 : !1\n    };\n    we.prototype.undo = function () {\n        if (this.canUndo()) {\n            var a = this.transactionToUndo;\n            try {\n                this.ke = !0, this.xb(\"StartingUndo\", \"Undo\", a), this.Gd--, a.undo()\n            } catch (b) {\n                wa(\"undo error: \" + b.toString())\n            } finally {\n                this.xb(\"FinishedUndo\", \"Undo\", a), this.ke = !1\n            }\n        }\n    };\n    we.prototype.canRedo = function () {\n        if (!this.isEnabled || 0 < this.transactionLevel) return !1;\n        var a = this.transactionToRedo;\n        return null !== a && a.canRedo() ? !0 : !1\n    };\n    we.prototype.redo = function () {\n        if (this.canRedo()) {\n            var a = this.transactionToRedo;\n            try {\n                this.ke = !0, this.xb(\"StartingRedo\", \"Redo\", a), this.Gd++, a.redo()\n            } catch (b) {\n                wa(\"redo error: \" + b.toString())\n            } finally {\n                this.xb(\"FinishedRedo\", \"Redo\", a), this.ke = !1\n            }\n        }\n    };\n    we.prototype.xb = function (a, b, c) {\n        void 0 === c && (c = null);\n        var d = new qe;\n        d.change = se;\n        d.propertyName = a;\n        d.object = c;\n        d.oldValue = b;\n        for (a = this.models; a.next();) b = a.value, d.model = b, b.bt(d)\n    };\n    we.prototype.Cv = function (a) {\n        if (this.isEnabled && !this.isUndoingRedoing && !this.skipsEvent(a)) {\n            var b = this.currentTransaction;\n            null === b && (this.rr = b = new ve);\n            var c = a.copy();\n            b = b.changes;\n            b.ea();\n            b.add(c);\n            b.freeze();\n            this.checksTransactionLevel && 0 >= this.transactionLevel && !this.pu && (a = a.diagram, null !== a && !1 === a.kk || wa(\"Change not within a transaction: \" + c.toString()))\n        }\n    };\n    we.prototype.skipsEvent = function (a) {\n        if (null === a || 0 > a.change.value) return !0;\n        a = a.object;\n        if (null === a) return !1;\n        if (void 0 !== a.layer) {\n            if (a = a.layer, null !== a && a.isTemporary) return !0\n        } else if (a.isTemporary) return !0;\n        return !1\n    };\n    ma.Object.defineProperties(we.prototype, {\n        models: {\n            get: function () {\n                return this.Fu.iterator\n            }\n        },\n        isEnabled: {\n            get: function () {\n                return this.Mc\n            },\n            set: function (a) {\n                this.Mc = a\n            }\n        },\n        transactionToUndo: {\n            get: function () {\n                return 0 <= this.historyIndex && this.historyIndex <= this.history.count - 1 ? this.history.L(this.historyIndex) : null\n            }\n        },\n        transactionToRedo: {\n            get: function () {\n                return this.historyIndex < this.history.count -\n                    1 ? this.history.L(this.historyIndex + 1) : null\n            }\n        },\n        isUndoingRedoing: {\n            get: function () {\n                return this.ke\n            }\n        },\n        history: {\n            get: function () {\n                return this.I\n            }\n        },\n        maxHistoryLength: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a\n            }\n        },\n        historyIndex: {\n            get: function () {\n                return this.Gd\n            }\n        },\n        currentTransaction: {\n            get: function () {\n                return this.rr\n            }\n        },\n        transactionLevel: {\n            get: function () {\n                return this.Li\n            }\n        },\n        isInTransaction: {\n            get: function () {\n                return 0 < this.Li\n            }\n        },\n        checksTransactionLevel: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l = a\n            }\n        },\n        nestedTransactionNames: {\n            get: function () {\n                return this.qe\n            }\n        }\n    });\n    we.prototype.handleChanged = we.prototype.Cv;\n    we.prototype.redo = we.prototype.redo;\n    we.prototype.undo = we.prototype.undo;\n    we.prototype.canUndo = we.prototype.canUndo;\n    we.prototype.rollbackTransaction = we.prototype.Bf;\n    we.prototype.commitTransaction = we.prototype.Ua;\n    we.prototype.startTransaction = we.prototype.ua;\n    we.prototype.removeModel = we.prototype.by;\n    we.prototype.addModel = we.prototype.ux;\n    we.prototype.clear = we.prototype.clear;\n    we.className = \"UndoManager\";\n\n    function ye() {\n        Ya(this);\n        this.B = ze;\n        this.Ra = \"\";\n        this.Mc = !0;\n        this.jd = !1;\n        this.Gw = null;\n        this.Ey = new ne;\n        this.Zs = -1\n    }\n    ye.prototype.toString = function () {\n        return \"\" !== this.name ? this.name + \" Tool\" : Ia(this.constructor)\n    };\n    ye.prototype.updateAdornments = function () {};\n    ye.prototype.canStart = function () {\n        return this.isEnabled\n    };\n    ye.prototype.doStart = function () {};\n    ye.prototype.doActivate = function () {\n        this.isActive = !0\n    };\n    ye.prototype.doDeactivate = function () {\n        this.isActive = !1\n    };\n    ye.prototype.doStop = function () {};\n    ye.prototype.doCancel = function () {\n        this.transactionResult = null;\n        this.stopTool()\n    };\n    ye.prototype.stopTool = function () {\n        var a = this.diagram;\n        a.currentTool === this && (a.currentTool = null, a.currentCursor = \"\")\n    };\n    ye.prototype.doMouseDown = function () {\n        !this.isActive && this.canStart() && this.doActivate()\n    };\n    ye.prototype.doMouseMove = function () {};\n    ye.prototype.doMouseUp = function () {\n        this.stopTool()\n    };\n    ye.prototype.doMouseWheel = function () {};\n    ye.prototype.canStartMultiTouch = function () {\n        return !0\n    };\n    ye.prototype.standardPinchZoomStart = function () {\n        var a = this.diagram,\n            b = a.lastInput,\n            c = b.oq(0, I.allocAt(NaN, NaN)),\n            d = b.oq(1, I.allocAt(NaN, NaN));\n        if (c.v() && d.v() && (this.doCancel(), a.mm(\"hasGestureZoom\"))) {\n            a.Cl = a.scale;\n            var e = d.x - c.x,\n                f = d.y - c.y;\n            a.Su = Math.sqrt(e * e + f * f);\n            b.bubbles = !1\n        }\n        I.free(c);\n        I.free(d)\n    };\n    ye.prototype.standardPinchZoomMove = function () {\n        var a = this.diagram,\n            b = a.lastInput,\n            c = b.oq(0, I.allocAt(NaN, NaN)),\n            d = b.oq(1, I.allocAt(NaN, NaN));\n        if (c.v() && d.v() && (this.doCancel(), a.mm(\"hasGestureZoom\"))) {\n            var e = d.x - c.x,\n                f = d.y - c.y;\n            f = Math.sqrt(e * e + f * f) / a.Su;\n            e = new I((Math.min(d.x, c.x) + Math.max(d.x, c.x)) / 2, (Math.min(d.y, c.y) + Math.max(d.y, c.y)) / 2);\n            f *= a.Cl;\n            var g = a.commandHandler;\n            if (f !== a.scale && g.canResetZoom(f)) {\n                var h = a.zoomPoint;\n                a.zoomPoint = e;\n                g.resetZoom(f);\n                a.zoomPoint = h\n            }\n            b.bubbles = !1\n        }\n        I.free(c);\n        I.free(d)\n    };\n    ye.prototype.doKeyDown = function () {\n        \"Esc\" === this.diagram.lastInput.key && this.doCancel()\n    };\n    ye.prototype.doKeyUp = function () {};\n    ye.prototype.ua = function (a) {\n        void 0 === a && (a = this.name);\n        this.transactionResult = null;\n        return this.diagram.ua(a)\n    };\n    ye.prototype.Hg = function () {\n        var a = this.diagram;\n        return null === this.transactionResult ? a.Bf() : a.Ua(this.transactionResult)\n    };\n    ye.prototype.standardMouseSelect = function () {\n        var a = this.diagram;\n        if (a.allowSelect) {\n            var b = a.lastInput,\n                c = a.jm(b.documentPoint, !1);\n            if (null !== c)\n                if (Wa ? b.meta : b.control) {\n                    a.R(\"ChangingSelection\", a.selection);\n                    for (b = c; null !== b && !b.canSelect();) b = b.containingGroup;\n                    null !== b && (b.isSelected = !b.isSelected);\n                    a.R(\"ChangedSelection\", a.selection)\n                } else if (b.shift) {\n                if (!c.isSelected) {\n                    a.R(\"ChangingSelection\", a.selection);\n                    for (b = c; null !== b && !b.canSelect();) b = b.containingGroup;\n                    null !== b && (b.isSelected = !0);\n                    a.R(\"ChangedSelection\",\n                        a.selection)\n                }\n            } else {\n                if (!c.isSelected) {\n                    for (b = c; null !== b && !b.canSelect();) b = b.containingGroup;\n                    null !== b && a.select(b)\n                }\n            } else !b.left || (Wa ? b.meta : b.control) || b.shift || a.clearSelection()\n        }\n    };\n    ye.prototype.standardMouseClick = function (a, b) {\n        void 0 === a && (a = null);\n        void 0 === b && (b = function (a) {\n            return !a.layer.isTemporary\n        });\n        var c = this.diagram,\n            d = c.lastInput;\n        a = c.Ub(d.documentPoint, a, b);\n        d.targetObject = a;\n        Ae(a, d, c);\n        return d.handled\n    };\n\n    function Ae(a, b, c) {\n        b.handled = !1;\n        if (null === a || a.Eg()) {\n            var d = 0;\n            b.left ? d = 1 === b.clickCount ? 1 : 2 === b.clickCount ? 2 : 1 : b.right && 1 === b.clickCount && (d = 3);\n            var e = \"ObjectSingleClicked\";\n            if (null !== a) {\n                switch (d) {\n                    case 1:\n                        e = \"ObjectSingleClicked\";\n                        break;\n                    case 2:\n                        e = \"ObjectDoubleClicked\";\n                        break;\n                    case 3:\n                        e = \"ObjectContextClicked\"\n                }\n                0 !== d && c.R(e, a)\n            } else {\n                switch (d) {\n                    case 1:\n                        e = \"BackgroundSingleClicked\";\n                        break;\n                    case 2:\n                        e = \"BackgroundDoubleClicked\";\n                        break;\n                    case 3:\n                        e = \"BackgroundContextClicked\"\n                }\n                0 !== d && c.R(e)\n            }\n            if (null !== a)\n                for (; null !== a;) {\n                    c = null;\n                    switch (d) {\n                        case 1:\n                            c =\n                                a.click;\n                            break;\n                        case 2:\n                            c = a.doubleClick ? a.doubleClick : a.click;\n                            break;\n                        case 3:\n                            c = a.contextClick\n                    }\n                    if (null !== c && (c(b, a), b.handled)) break;\n                    a = a.panel\n                } else {\n                    a = null;\n                    switch (d) {\n                        case 1:\n                            a = c.click;\n                            break;\n                        case 2:\n                            a = c.doubleClick ? c.doubleClick : c.click;\n                            break;\n                        case 3:\n                            a = c.contextClick\n                    }\n                    null !== a && a(b)\n                }\n        }\n    }\n    ye.prototype.standardMouseOver = function () {\n        var a = this.diagram,\n            b = a.lastInput;\n        if (!0 !== a.animationManager.qc) {\n            var c = a.skipsUndoManager;\n            a.skipsUndoManager = !0;\n            var d = a.viewportBounds.aa(b.documentPoint) ? a.Ub(b.documentPoint, null, null) : null;\n            b.targetObject = d;\n            var e = !1;\n            if (d !== a.mj) {\n                var f = a.mj,\n                    g = f;\n                a.mj = d;\n                this.doCurrentObjectChanged(f, d);\n                for (b.handled = !1; null !== f;) {\n                    var h = f.mouseLeave;\n                    if (null !== h) {\n                        if (d === f) break;\n                        if (null !== d && d.Dg(f)) break;\n                        h(b, f, d);\n                        e = !0;\n                        if (b.handled) break\n                    }\n                    f = f.panel\n                }\n                f = g;\n                for (b.handled = !1; null !== d;) {\n                    g =\n                        d.mouseEnter;\n                    if (null !== g) {\n                        if (f === d) break;\n                        if (null !== f && f.Dg(d)) break;\n                        g(b, d, f);\n                        e = !0;\n                        if (b.handled) break\n                    }\n                    d = d.panel\n                }\n                d = a.mj\n            }\n            if (null !== d) {\n                f = d;\n                for (g = \"\"; null !== f;) {\n                    g = f.cursor;\n                    if (\"\" !== g) break;\n                    f = f.panel\n                }\n                a.currentCursor = g;\n                b.handled = !1;\n                for (f = d; null !== f;) {\n                    d = f.mouseOver;\n                    if (null !== d && (d(b, f), e = !0, b.handled)) break;\n                    f = f.panel\n                }\n            } else a.currentCursor = \"\", d = a.mouseOver, null !== d && (d(b), e = !0);\n            e && a.Pb();\n            a.skipsUndoManager = c\n        }\n    };\n    ye.prototype.doCurrentObjectChanged = function () {};\n    ye.prototype.standardMouseWheel = function () {\n        var a = this.diagram,\n            b = a.lastInput,\n            c = b.delta;\n        if (0 !== c && a.documentBounds.v()) {\n            var d = a.commandHandler,\n                e = a.toolManager.mouseWheelBehavior;\n            if (null !== d && (e === Be && !b.shift || e === Ce && b.control)) {\n                if (0 < c ? d.canIncreaseZoom() : d.canDecreaseZoom()) e = a.zoomPoint, a.zoomPoint = b.viewPoint, 0 < c ? d.increaseZoom() : d.decreaseZoom(), a.zoomPoint = e;\n                b.bubbles = !1\n            } else if (e === Be && b.shift || e === Ce && !b.control) {\n                d = a.position.copy();\n                var f = 0 < c ? c : -c,\n                    g = b.event,\n                    h = g.deltaMode;\n                e = g.deltaX;\n                g = g.deltaY;\n                if (Ta || Ua || Va) h = 1, 0 < e && (e = 3), 0 > e && (e = -3), 0 < g && (g = 3), 0 > g && (g = -3);\n                if (void 0 === h || void 0 === e || void 0 === g || 0 === e && 0 === g || b.shift) !b.shift && a.allowVerticalScroll ? (f = 3 * f * a.scrollVerticalLineChange, 0 < c ? a.scroll(\"pixel\", \"up\", f) : a.scroll(\"pixel\", \"down\", f)) : b.shift && a.allowHorizontalScroll && (f = 3 * f * a.scrollHorizontalLineChange, 0 < c ? a.scroll(\"pixel\", \"left\", f) : a.scroll(\"pixel\", \"right\", f));\n                else {\n                    switch (h) {\n                        case 0:\n                            c = \"pixel\";\n                            break;\n                        case 1:\n                            c = \"line\";\n                            break;\n                        case 2:\n                            c = \"page\";\n                            break;\n                        default:\n                            c = \"pixel\"\n                    }\n                    0 !== e && a.allowHorizontalScroll &&\n                        (e *= a.scrollHorizontalLineChange / 16, 0 < e ? a.scroll(c, \"left\", -e) : a.scroll(c, \"right\", e));\n                    0 !== g && a.allowVerticalScroll && (g *= a.scrollVerticalLineChange / 16, 0 < g ? a.scroll(c, \"up\", -g) : a.scroll(c, \"down\", g))\n                }\n                a.position.w(d) || (b.bubbles = !1)\n            }\n        }\n    };\n    ye.prototype.standardWaitAfter = function (a, b) {\n        void 0 === b && (b = this.diagram.lastInput);\n        this.cancelWaitAfter();\n        var c = this,\n            d = b.clone(this.Ey);\n        this.Zs = sa(function () {\n            c.doWaitAfter(d)\n        }, a)\n    };\n    ye.prototype.cancelWaitAfter = function () {\n        -1 !== this.Zs && x.clearTimeout(this.Zs);\n        this.Zs = -1\n    };\n    ye.prototype.doWaitAfter = function () {};\n    ye.prototype.findToolHandleAt = function (a, b) {\n        a = this.diagram.Ub(a, function (a) {\n            for (; null !== a && !(a.panel instanceof Je);) a = a.panel;\n            return a\n        });\n        return null === a ? null : a.part.category === b ? a : null\n    };\n    ye.prototype.isBeyondDragSize = function (a, b) {\n        var c = this.diagram;\n        void 0 === a && (a = c.firstInput.viewPoint);\n        void 0 === b && (b = c.lastInput.viewPoint);\n        var d = c.toolManager.dragSize,\n            e = d.width;\n        d = d.height;\n        c.firstInput.isTouchEvent && (e += 6, d += 6);\n        return Math.abs(b.x - a.x) > e || Math.abs(b.y - a.y) > d\n    };\n    ma.Object.defineProperties(ye.prototype, {\n        diagram: {\n            get: function () {\n                return this.B\n            },\n            set: function (a) {\n                a instanceof R && (this.B = a)\n            }\n        },\n        name: {\n            get: function () {\n                return this.Ra\n            },\n            set: function (a) {\n                this.Ra = a\n            }\n        },\n        isEnabled: {\n            get: function () {\n                return this.Mc\n            },\n            set: function (a) {\n                this.Mc = a\n            }\n        },\n        isActive: {\n            get: function () {\n                return this.jd\n            },\n            set: function (a) {\n                this.jd = a\n            }\n        },\n        transactionResult: {\n            get: function () {\n                return this.Gw\n            },\n            set: function (a) {\n                this.Gw = a\n            }\n        }\n    });\n    ye.prototype.stopTransaction = ye.prototype.Hg;\n    ye.prototype.startTransaction = ye.prototype.ua;\n    ye.className = \"Tool\";\n\n    function Oa() {\n        ye.call(this);\n        this.name = \"ToolManager\";\n        this.Ic = new E;\n        this.Yc = new E;\n        this.Ef = new E;\n        this.Y = this.Ha = 850;\n        this.u = (new M(2, 2)).ca();\n        this.Za = 5E3;\n        this.Ia = Ce;\n        this.I = Ke;\n        this.qr = this.l = null;\n        this.Qj = -1\n    }\n    la(Oa, ye);\n    Oa.prototype.initializeStandardTools = function () {};\n    Oa.prototype.updateAdornments = function (a) {\n        var b = this.currentToolTip;\n        if (b instanceof Je && this.qr === a) {\n            var c = b.adornedObject;\n            (null !== a ? c.part === a : null === c) ? this.showToolTip(b, c): this.hideToolTip()\n        }\n    };\n    Oa.prototype.doMouseDown = function () {\n        var a = this.diagram,\n            b = a.lastInput;\n        b.isTouchEvent && this.gestureBehavior === Le && (b.bubbles = !1);\n        if (b.isMultiTouch) {\n            this.cancelWaitAfter();\n            if (this.gestureBehavior === Me) {\n                b.bubbles = !0;\n                return\n            }\n            if (this.gestureBehavior === Le) return;\n            if (a.currentTool.canStartMultiTouch()) {\n                a.currentTool.standardPinchZoomStart();\n                return\n            }\n        }\n        for (var c = this.mouseDownTools.length, d = 0; d < c; d++) {\n            var e = this.mouseDownTools.L(d);\n            e.diagram = this.diagram;\n            if (e.canStart()) {\n                a.doFocus();\n                a.currentTool = e;\n                a.currentTool ===\n                    e && (e.isActive || e.doActivate(), e.doMouseDown());\n                return\n            }\n        }\n        1 === a.lastInput.button && (this.mouseWheelBehavior === Ce ? this.mouseWheelBehavior = Be : this.mouseWheelBehavior === Be && (this.mouseWheelBehavior = Ce));\n        this.doActivate();\n        this.standardWaitAfter(this.holdDelay, b)\n    };\n    Oa.prototype.doMouseMove = function () {\n        var a = this.diagram,\n            b = a.lastInput;\n        if (b.isMultiTouch) {\n            if (this.gestureBehavior === Me) {\n                b.bubbles = !0;\n                return\n            }\n            if (this.gestureBehavior === Le) return;\n            if (a.currentTool.canStartMultiTouch()) {\n                a.currentTool.standardPinchZoomMove();\n                return\n            }\n        }\n        if (this.isActive)\n            for (var c = this.mouseMoveTools.length, d = 0; d < c; d++) {\n                var e = this.mouseMoveTools.L(d);\n                e.diagram = this.diagram;\n                if (e.canStart()) {\n                    a.doFocus();\n                    a.currentTool = e;\n                    a.currentTool === e && (e.isActive || e.doActivate(), e.doMouseMove());\n                    return\n                }\n            }\n        Ne(this,\n            a);\n        a = b.event;\n        null === a || \"mousemove\" !== a.type && \"pointermove\" !== a.type && a.cancelable || (b.bubbles = !0)\n    };\n\n    function Ne(a, b) {\n        a.standardMouseOver();\n        a.isBeyondDragSize() && a.standardWaitAfter(a.isActive ? a.holdDelay : a.hoverDelay, b.lastInput)\n    }\n    Oa.prototype.doCurrentObjectChanged = function (a, b) {\n        a = this.currentToolTip;\n        null === a || null !== b && a instanceof Je && (b === a || b.Dg(a)) || this.hideToolTip()\n    };\n    Oa.prototype.doWaitAfter = function (a) {\n        var b = this.diagram;\n        b.sa && (this.doMouseHover(), this.isActive || this.doToolTip(), a.isTouchEvent && !b.lastInput.handled && (a = a.copy(), a.button = 2, a.buttons = 2, b.lastInput = a, b.Pj = !0, b.doMouseUp()))\n    };\n    Oa.prototype.doMouseHover = function () {\n        var a = this.diagram,\n            b = a.lastInput;\n        null === b.targetObject && (b.targetObject = a.Ub(b.documentPoint, null, null));\n        var c = b.targetObject;\n        if (null !== c)\n            for (b.handled = !1; null !== c;) {\n                a = this.isActive ? c.mouseHold : c.mouseHover;\n                if (null !== a && (a(b, c), b.handled)) break;\n                c = c.panel\n            } else c = this.isActive ? a.mouseHold : a.mouseHover, null !== c && c(b)\n    };\n    Oa.prototype.doToolTip = function () {\n        var a = this.diagram,\n            b = a.lastInput;\n        null === b.targetObject && (b.targetObject = a.Ub(b.documentPoint, null, null));\n        b = b.targetObject;\n        if (null !== b) {\n            if (a = this.currentToolTip, !(a instanceof Je) || b !== a && !b.Dg(a)) {\n                for (; null !== b;) {\n                    a = b.toolTip;\n                    if (null !== a) {\n                        this.showToolTip(a, b);\n                        return\n                    }\n                    b = b.panel\n                }\n                this.hideToolTip()\n            }\n        } else b = a.toolTip, null !== b ? this.showToolTip(b, null) : this.hideToolTip()\n    };\n    Oa.prototype.showToolTip = function (a, b) {\n        var c = this.diagram;\n        a !== this.currentToolTip && this.hideToolTip();\n        if (a instanceof Je) {\n            a.layerName = \"Tool\";\n            a.selectable = !1;\n            a.scale = 1 / c.scale;\n            a.category = \"ToolTip\";\n            null !== a.placeholder && (a.placeholder.scale = c.scale);\n            var d = a.diagram;\n            null !== d && d !== c && d.remove(a);\n            c.add(a);\n            null !== b ? a.adornedObject = b : a.data = c.model;\n            a.yb();\n            this.positionToolTip(a, b)\n        } else a instanceof Oe && a !== this.currentToolTip && a.show(b, c, this);\n        this.currentToolTip = a; - 1 !== this.Qj && (x.clearTimeout(this.Qj),\n            this.Qj = -1);\n        a = this.toolTipDuration;\n        if (0 < a && Infinity !== a) {\n            var e = this;\n            this.Qj = sa(function () {\n                e.hideToolTip()\n            }, a)\n        }\n    };\n    Oa.prototype.positionToolTip = function (a) {\n        if (null === a.placeholder) {\n            var b = this.diagram,\n                c = b.lastInput.documentPoint.copy(),\n                d = a.measuredBounds,\n                e = b.viewportBounds;\n            b.lastInput.isTouchEvent && (c.x -= d.width);\n            c.x + d.width > e.right && (c.x -= d.width + 5 / b.scale);\n            c.x < e.x && (c.x = e.x);\n            c.y = c.y + 20 / b.scale + d.height > e.bottom ? c.y - (d.height + 5 / b.scale) : c.y + 20 / b.scale;\n            c.y < e.y && (c.y = e.y);\n            a.position = c\n        }\n    };\n    Oa.prototype.hideToolTip = function () {\n        -1 !== this.Qj && (x.clearTimeout(this.Qj), this.Qj = -1);\n        var a = this.diagram,\n            b = this.currentToolTip;\n        null !== b && (b instanceof Je ? (a.remove(b), null !== this.qr && this.qr.Af(b.category), b.data = null, b.adornedObject = null) : b instanceof Oe && null !== b.hide && b.hide(a, this), this.currentToolTip = null)\n    };\n    Oa.prototype.doMouseUp = function () {\n        this.cancelWaitAfter();\n        var a = this.diagram;\n        if (this.isActive)\n            for (var b = this.mouseUpTools.length, c = 0; c < b; c++) {\n                var d = this.mouseUpTools.L(c);\n                d.diagram = this.diagram;\n                if (d.canStart()) {\n                    a.doFocus();\n                    a.currentTool = d;\n                    a.currentTool === d && (d.isActive || d.doActivate(), d.doMouseUp());\n                    return\n                }\n            }\n        a.doFocus();\n        this.doDeactivate()\n    };\n    Oa.prototype.doMouseWheel = function () {\n        this.standardMouseWheel()\n    };\n    Oa.prototype.doKeyDown = function () {\n        var a = this.diagram;\n        null !== a.commandHandler && a.commandHandler.doKeyDown()\n    };\n    Oa.prototype.doKeyUp = function () {\n        var a = this.diagram;\n        null !== a.commandHandler && a.commandHandler.doKeyUp()\n    };\n    Oa.prototype.findTool = function (a) {\n        for (var b = this.mouseDownTools.length, c = 0; c < b; c++) {\n            var d = this.mouseDownTools.L(c);\n            if (d.name === a) return d\n        }\n        b = this.mouseMoveTools.length;\n        for (c = 0; c < b; c++)\n            if (d = this.mouseMoveTools.L(c), d.name === a) return d;\n        b = this.mouseUpTools.length;\n        for (c = 0; c < b; c++)\n            if (d = this.mouseUpTools.L(c), d.name === a) return d;\n        return null\n    };\n    Oa.prototype.replaceTool = function (a, b) {\n        null !== b && (b.diagram = this.diagram);\n        for (var c = this.mouseDownTools.length, d = 0; d < c; d++) {\n            var e = this.mouseDownTools.L(d);\n            if (e.name === a) return null !== b ? this.mouseDownTools.gd(d, b) : this.mouseDownTools.lb(d), e\n        }\n        c = this.mouseMoveTools.length;\n        for (d = 0; d < c; d++)\n            if (e = this.mouseMoveTools.L(d), e.name === a) return null !== b ? this.mouseMoveTools.gd(d, b) : this.mouseMoveTools.lb(d), e;\n        c = this.mouseUpTools.length;\n        for (d = 0; d < c; d++)\n            if (e = this.mouseUpTools.L(d), e.name === a) return null !== b ? this.mouseUpTools.gd(d,\n                b) : this.mouseUpTools.lb(d), e;\n        return null\n    };\n    Oa.prototype.Va = function (a, b, c) {\n        null !== b && (b.name = a, b.diagram = this.diagram);\n        this.findTool(a) ? this.replaceTool(a, b) : null !== b && c.add(b)\n    };\n    ma.Object.defineProperties(Oa.prototype, {\n        mouseWheelBehavior: {\n            get: function () {\n                return this.Ia\n            },\n            set: function (a) {\n                this.Ia = a\n            }\n        },\n        gestureBehavior: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I = a\n            }\n        },\n        currentToolTip: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l = a;\n                this.qr = null !== a && a instanceof Je ? a.adornedPart : null\n            }\n        },\n        mouseDownTools: {\n            get: function () {\n                return this.Ic\n            }\n        },\n        mouseMoveTools: {\n            get: function () {\n                return this.Yc\n            }\n        },\n        mouseUpTools: {\n            get: function () {\n                return this.Ef\n            }\n        },\n        hoverDelay: {\n            get: function () {\n                return this.Ha\n            },\n            set: function (a) {\n                this.Ha = a\n            }\n        },\n        holdDelay: {\n            get: function () {\n                return this.Y\n            },\n            set: function (a) {\n                this.Y = a\n            }\n        },\n        dragSize: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a.G()\n            }\n        },\n        toolTipDuration: {\n            get: function () {\n                return this.Za\n            },\n            set: function (a) {\n                this.Za =\n                    a\n            }\n        }\n    });\n    Oa.prototype.replaceStandardTool = Oa.prototype.Va;\n    var Ce = new D(Oa, \"WheelScroll\", 0),\n        Be = new D(Oa, \"WheelZoom\", 1),\n        Pe = new D(Oa, \"WheelNone\", 2),\n        Ke = new D(Oa, \"GestureZoom\", 3),\n        Le = new D(Oa, \"GestureCancel\", 4),\n        Me = new D(Oa, \"GestureNone\", 5);\n    Oa.className = \"ToolManager\";\n    Oa.WheelScroll = Ce;\n    Oa.WheelZoom = Be;\n    Oa.WheelNone = Pe;\n    Oa.GestureZoom = Ke;\n    Oa.GestureCancel = Le;\n    Oa.GestureNone = Me;\n\n    function Qe() {\n        ye.call(this);\n        this.name = \"Dragging\";\n        this.I = this.Yc = !0;\n        this.u = this.Za = this.Ha = this.og = null;\n        this.Bn = this.Ef = !1;\n        this.Ql = new I(NaN, NaN);\n        this.Ns = new I;\n        this.Ic = !0;\n        this.Vk = 100;\n        this.Tg = [];\n        this.Sq = (new F).freeze();\n        this.Ia = new Re;\n        this.ko = null;\n        this.Y = \"copy\";\n        this.Oh = \"\";\n        this.Ie = \"no-drop\"\n    }\n    la(Qe, ye);\n    Qe.prototype.canStart = function () {\n        if (!this.isEnabled) return !1;\n        var a = this.diagram;\n        if (a.isReadOnly && !a.allowDragOut || !a.allowMove && !a.allowCopy && !a.allowDragOut || !a.allowSelect) return !1;\n        var b = a.lastInput;\n        return !b.left || a.currentTool !== this && (!this.isBeyondDragSize() || b.isTouchEvent && b.timestamp - a.firstInput.timestamp < this.Vk) ? !1 : null !== this.findDraggablePart()\n    };\n    Qe.prototype.findDraggablePart = function () {\n        var a = this.diagram;\n        a = a.jm(a.firstInput.documentPoint, !1);\n        if (null === a) return null;\n        for (; null !== a && !a.canSelect();) a = a.containingGroup;\n        return null !== a && (a.canMove() || a.canCopy()) ? a : null\n    };\n    Qe.prototype.standardMouseSelect = function () {\n        var a = this.diagram;\n        if (a.allowSelect) {\n            var b = a.jm(a.firstInput.documentPoint, !1);\n            if (null !== b) {\n                for (; null !== b && !b.canSelect();) b = b.containingGroup;\n                this.currentPart = b;\n                null === this.currentPart || this.currentPart.isSelected || (a.R(\"ChangingSelection\", a.selection), b = a.lastInput, (Wa ? b.meta : b.control) || b.shift || a.clearSelection(!0), this.currentPart.isSelected = !0, a.R(\"ChangedSelection\", a.selection))\n            }\n        }\n    };\n    Qe.prototype.doActivate = function () {\n        var a = this.diagram;\n        this.ko = null;\n        null === this.currentPart && this.standardMouseSelect();\n        var b = this.currentPart;\n        null !== b && (b.canMove() || b.canCopy()) && (Se = null, this.isActive = !0, this.Ql.set(a.position), Te(this, a.selection), this.Tg.length = 0, this.draggedParts = this.computeEffectiveCollection(a.selection, this.dragOptions), a.Ot = !0, !0 === a.Be(\"temporaryPixelRatio\") && 30 < a.xx && Ue(a), Ve(a, this.draggedParts), this.ua(\"Drag\"), this.startPoint = a.firstInput.documentPoint, a.isMouseCaptured = !0, a.allowDragOut && (this.isDragOutStarted = !0, this.Bn = !1, Se = this, We = this.diagram, this.doSimulatedDragOut()))\n    };\n\n    function Te(a, b) {\n        if (a.dragsLink) {\n            var c = a.diagram;\n            c.allowRelink && (c.model.ik() && 1 === b.count && b.first() instanceof S ? (a.draggedLink = b.first(), a.draggedLink.canRelinkFrom() && a.draggedLink.canRelinkTo() && a.draggedLink.Yj(), a.og = c.toolManager.findTool(\"Relinking\"), null === a.og && (a.og = new Xe, a.og.diagram = c)) : (a.draggedLink = null, a.og = null))\n        }\n    }\n    Qe.prototype.computeEffectiveCollection = function (a, b) {\n        return this.diagram.commandHandler.computeEffectiveCollection(a, b)\n    };\n    Qe.prototype.sd = function (a) {\n        return void 0 === a ? new df(Fb) : this.isGridSnapEnabled ? new df(new I(Math.round(a.x), Math.round(a.y))) : new df(a.copy())\n    };\n    Qe.prototype.doDeactivate = function () {\n        this.isActive = !1;\n        var a = this.diagram;\n        a.Cf();\n        ef(this);\n        ff(a, this.draggedParts);\n        this.draggedParts = this.currentPart = this.ko = null;\n        this.Bn = this.isDragOutStarted = !1;\n        if (0 < gf.count) {\n            for (var b = gf, c = b.length, d = 0; d < c; d++) {\n                var e = b.L(d);\n                hf(e);\n                jf(e);\n                ef(e);\n                e.diagram.Cf()\n            }\n            b.clear()\n        }\n        hf(this);\n        this.Ql.h(NaN, NaN);\n        Se = We = null;\n        jf(this);\n        a.isMouseCaptured = !1;\n        a.currentCursor = \"\";\n        a.Ot = !1;\n        this.Hg();\n        kf(a, !0)\n    };\n\n    function ef(a) {\n        var b = a.diagram,\n            c = b.skipsUndoManager;\n        b.skipsUndoManager = !0;\n        lf(a, b.lastInput, null);\n        b.skipsUndoManager = c;\n        a.Tg.length = 0\n    }\n\n    function mf() {\n        var a = Se;\n        jf(a);\n        nf(a);\n        var b = a.diagram;\n        a.Ql.v() && (b.position = a.Ql);\n        b.Cf()\n    }\n    Qe.prototype.doCancel = function () {\n        jf(this);\n        nf(this);\n        var a = this.diagram;\n        this.Ql.v() && (a.position = this.Ql);\n        this.stopTool()\n    };\n    Qe.prototype.doKeyDown = function () {\n        this.isActive && (\"Esc\" === this.diagram.lastInput.key ? this.doCancel() : this.doMouseMove())\n    };\n    Qe.prototype.doKeyUp = function () {\n        this.isActive && this.doMouseMove()\n    };\n\n    function of (a, b) {\n        var c = Infinity,\n            d = Infinity,\n            e = -Infinity,\n            f = -Infinity;\n        for (a = a.iterator; a.next();) {\n            var g = a.value;\n            if (g.Wb() && g.isVisible()) {\n                var h = g.location;\n                g = h.x;\n                h = h.y;\n                isNaN(g) || isNaN(h) || (g < c && (c = g), h < d && (d = h), g > e && (e = g), h > f && (f = h))\n            }\n        }\n        Infinity === c ? b.h(0, 0, 0, 0) : b.h(c, d, e - c, f - d)\n    }\n\n    function pf(a, b) {\n        if (null === a.copiedParts) {\n            var c = a.diagram;\n            if ((!b || !c.isReadOnly && !c.isModelReadOnly) && null !== a.draggedParts) {\n                var d = c.undoManager;\n                d.isEnabled && d.isInTransaction ? null !== d.currentTransaction && 0 < d.currentTransaction.changes.count && (c.undoManager.Bf(), c.ua(\"Drag\")) : nf(a);\n                c.skipsUndoManager = !b;\n                c.partManager.addsToTemporaryLayer = !b;\n                a.startPoint = c.firstInput.documentPoint;\n                b = a.copiesEffectiveCollection ? a.draggedParts.Df() : c.selection;\n                c = c.ck(b, c, !0);\n                for (b = c.iterator; b.next();) b.value.location =\n                    b.key.location;\n                b = N.alloc(); of (c, b);\n                N.free(b);\n                b = new H;\n                for (d = a.draggedParts.iterator; d.next();) {\n                    var e = d.key;\n                    e.Wb() && e.canCopy() && (e = c.H(e), null !== e && (e.yb(), b.add(e, a.sd(e.location))))\n                }\n                for (c = c.iterator; c.next();) d = c.value, d instanceof S && d.canCopy() && b.add(d, a.sd());\n                a.copiedParts = b;\n                Te(a, b.Df());\n                null !== a.draggedLink && (c = a.draggedLink, b = c.routeBounds, qf(c, a.startPoint.x - (b.x + b.width / 2), a.startPoint.y - (b.y + b.height / 2)))\n            }\n        }\n    }\n\n    function jf(a) {\n        var b = a.diagram;\n        if (null !== a.copiedParts && (b.Jt(a.copiedParts.Df(), !1), a.copiedParts = null, null !== a.draggedParts))\n            for (var c = a.draggedParts.iterator; c.next();) c.key instanceof S && (c.value.point = new I(0, 0));\n        b.skipsUndoManager = !1;\n        b.partManager.addsToTemporaryLayer = !1;\n        a.startPoint = b.firstInput.documentPoint\n    }\n\n    function hf(a) {\n        if (null !== a.draggedLink) {\n            if (a.dragsLink && null !== a.og) {\n                var b = a.og;\n                b.diagram.remove(b.temporaryFromNode);\n                b.diagram.remove(b.temporaryToNode)\n            }\n            a.draggedLink = null;\n            a.og = null\n        }\n    }\n\n    function rf(a, b, c) {\n        var d = a.diagram,\n            e = a.startPoint,\n            f = I.alloc();\n        f.assign(d.lastInput.documentPoint);\n        a.moveParts(b, f.Zd(e), c);\n        I.free(f);\n        !0 === d.Be(\"temporaryPixelRatio\") && null === d.uh && 30 < d.xx && (Ue(d), d.Ht())\n    }\n    Qe.prototype.moveParts = function (a, b, c) {\n        var d = this.diagram;\n        null !== d && sf(d, a, b, this.dragOptions, c)\n    };\n\n    function nf(a) {\n        if (null !== a.draggedParts) {\n            for (var b = a.diagram, c = a.draggedParts.iterator; c.next();) {\n                var d = c.key;\n                d.Wb() && (d.location = c.value.point)\n            }\n            for (c = a.draggedParts.iterator; c.next();)\n                if (d = c.key, d instanceof S && d.suspendsRouting) {\n                    var e = c.value.point;\n                    a.draggedParts.add(d, a.sd());\n                    qf(d, -e.x, -e.y)\n                } b.Wc()\n        }\n    }\n\n    function tf(a, b) {\n        var c = a.diagram;\n        a.dragsLink && (null !== a.draggedLink && (a.draggedLink.fromNode = null, a.draggedLink.toNode = null), uf(a, !1));\n        var d = a.findDragOverObject(b),\n            e = c.lastInput;\n        e.targetObject = d;\n        a.doUpdateCursor(d);\n        var f = c.skipsUndoManager,\n            g = !1;\n        try {\n            c.skipsUndoManager = !0;\n            g = lf(a, e, d);\n            if (!a.isActive && null === Se) return;\n            var h = null !== d ? d.part : null;\n            if (null === h || c.handlesDragDropForTopLevelParts && h.isTopLevel && !(h instanceof T)) {\n                var k = c.mouseDragOver;\n                null !== k && (k(e), g = !0)\n            }\n            if (!a.isActive && null === Se) return;\n            a.doDragOver(b, d);\n            if (!a.isActive && null === Se) return\n        } finally {\n            c.skipsUndoManager = f, g && c.Wc()\n        }\n        a.ko = d;\n        c.isReadOnly || !c.allowMove && !c.allowCopy || !c.allowHorizontalScroll && !c.allowVerticalScroll || c.gt(e.viewPoint)\n    }\n    Qe.prototype.findDragOverObject = function (a) {\n        var b = this;\n        return vf(this.diagram, a, null, function (a) {\n            null === a ? a = !0 : (a = a.part, a = null === a || a instanceof Je || a.layer.isTemporary || b.draggedParts && b.draggedParts.contains(a) || b.copiedParts && b.copiedParts.contains(a) ? !0 : !1);\n            return !a\n        })\n    };\n    Qe.prototype.doUpdateCursor = function (a) {\n        var b = this.diagram;\n        this.ko !== a && (!this.diagram.currentTool.isActive || this.mayCopy() ? b.currentCursor = this.copyCursor : this.mayMove() ? b.currentCursor = this.moveCursor : this.mayDragOut() && (b.currentCursor = this.nodropCursor))\n    };\n\n    function lf(a, b, c) {\n        var d = !1,\n            e = a.Tg.length,\n            f = 0 < e ? a.Tg[0] : null;\n        if (c === f) return !1;\n        b.handled = !1;\n        for (var g = 0; g < e; g++) {\n            var h = a.Tg[g],\n                k = h.mouseDragLeave;\n            if (null !== k && (k(b, h, c), d = !0, b.handled)) break\n        }\n        a.Tg.length = 0;\n        if (!a.isActive && null === Se || null === c) return d;\n        b.handled = !1;\n        for (e = c; null !== e;) a.Tg.push(e), e = wf(e);\n        e = a.Tg.length;\n        for (c = 0; c < e && (g = a.Tg[c], h = g.mouseDragEnter, null === h || (h(b, g, f), d = !0, !b.handled)); c++);\n        return d\n    }\n\n    function wf(a) {\n        var b = a.panel;\n        return null !== b ? b : a instanceof U && !(a instanceof T) && (a = a.containingGroup, null !== a && a.handlesDragDropForMembers) ? a : null\n    }\n\n    function xf(a, b, c) {\n        var d = a.og;\n        if (null === d) return null;\n        var e = a.diagram.Ag(b, d.portGravity, function (a) {\n            return d.findValidLinkablePort(a, c)\n        });\n        a = I.alloc();\n        var f = Infinity,\n            g = null;\n        for (e = e.iterator; e.next();) {\n            var h = e.value;\n            if (null !== h.part) {\n                var k = h.ga(Ac, a);\n                k = b.Ae(k);\n                k < f && (g = h, f = k)\n            }\n        }\n        I.free(a);\n        return g\n    }\n\n    function uf(a, b) {\n        var c = a.draggedLink;\n        if (null !== c && !(2 > c.pointsCount)) {\n            var d = a.diagram;\n            if (!d.isReadOnly) {\n                var e = a.og;\n                if (null !== e) {\n                    var f = null,\n                        g = null;\n                    null === c.fromNode && (f = xf(a, c.i(0), !1), null !== f && (g = f.part));\n                    var h = null,\n                        k = null;\n                    null === c.toNode && (h = xf(a, c.i(c.pointsCount - 1), !0), null !== h && (k = h.part));\n                    e.isValidLink(g, f, k, h) ? b ? (c.defaultFromPoint = c.i(0), c.defaultToPoint = c.i(c.pointsCount - 1), c.suspendsRouting = !1, c.fromNode = g, null !== f && (c.fromPortId = f.portId), c.toNode = k, null !== h && (c.toPortId = h.portId), c.fromPort !==\n                        d.Xx && d.R(\"LinkRelinked\", c, d.Xx), c.toPort !== d.Yx && d.R(\"LinkRelinked\", c, d.Yx)) : yf(e, g, f, k, h) : yf(e, null, null, null, null)\n                }\n            }\n        }\n    }\n    Qe.prototype.doDragOver = function () {};\n\n    function Ef(a, b) {\n        var c = a.diagram;\n        a.dragsLink && uf(a, !0);\n        ef(a);\n        var d = a.findDragOverObject(b),\n            e = c.lastInput;\n        e.targetObject = d;\n        if (null !== d) {\n            e.handled = !1;\n            for (var f = d; null !== f;) {\n                var g = f.mouseDrop;\n                if (null !== g && (g(e, f), e.handled)) break;\n                Ff(a, e, f);\n                f = wf(f)\n            }\n        } else f = c.mouseDrop, null !== f && f(e);\n        if (a.isActive || null !== Se) {\n            for (e = (a.copiedParts || a.draggedParts).iterator; e.next();) f = e.key, f instanceof W && f.linksConnected.each(function (a) {\n                a.suspendsRouting = !1\n            });\n            a.doDropOnto(b, d);\n            if (a.isActive || null !== Se) {\n                a = N.alloc();\n                for (b =\n                    c.selection.iterator; b.next();) d = b.value, d instanceof W && Gf(c, d, a);\n                N.free(a)\n            }\n        }\n    }\n\n    function Ff(a, b, c) {\n        a = a.diagram;\n        c = c.part;\n        !a.handlesDragDropForTopLevelParts || !c.isTopLevel || c instanceof T || (c = a.mouseDrop, null !== c && c(b))\n    }\n\n    function Gf(a, b, c) {\n        var d = !1;\n        b.getAvoidableRect(c);\n        a.viewportBounds.ze(c) && (d = !0);\n        a = a.uv(c, function (a) {\n            return a.part\n        }, function (a) {\n            return a instanceof S\n        }, !0, function (a) {\n            return a instanceof S\n        }, d);\n        if (0 !== a.count)\n            for (a = a.iterator; a.next();) c = a.value, !c.Wd(b) && c.isAvoiding && c.Oa()\n    }\n    Qe.prototype.doDropOnto = function () {};\n    Qe.prototype.doMouseMove = function () {\n        if (this.isActive) {\n            var a = this.diagram,\n                b = a.lastInput;\n            this.simulatedMouseMove(b.event, b.documentPoint, b.targetDiagram) || null === this.currentPart || null === this.draggedParts || (this.mayCopy() ? (pf(this, !1), Ve(a, this.copiedParts), rf(this, this.copiedParts, !1), ff(a, this.copiedParts)) : this.mayMove() ? (jf(this), rf(this, this.draggedParts, !0)) : this.mayDragOut() ? (pf(this, !1), rf(this, this.copiedParts, !1)) : jf(this), tf(this, a.lastInput.documentPoint))\n        }\n    };\n    Qe.prototype.doMouseUp = function () {\n        if (this.isActive) {\n            var a = this.diagram,\n                b = a.lastInput;\n            if (!this.simulatedMouseUp(b.event, b.documentPoint, b.targetDiagram)) {\n                b = !1;\n                var c = this.mayCopy();\n                c && null !== this.copiedParts ? (jf(this), pf(this, !0), Ve(a, this.copiedParts), rf(this, this.copiedParts, !1), ff(a, this.copiedParts), null !== this.copiedParts && (a.R(\"ChangingSelection\", a.selection), a.clearSelection(!0), this.copiedParts.iteratorKeys.each(function (a) {\n                    a.isSelected = !0\n                }))) : (b = !0, jf(this), this.mayMove() && (rf(this, this.draggedParts,\n                    !0), tf(this, a.lastInput.documentPoint)));\n                this.Bn = !0;\n                Ef(this, a.lastInput.documentPoint);\n                if (this.isActive) {\n                    var d = c ? this.copiedParts.Df() : this.draggedParts.Df();\n                    this.copiedParts = null;\n                    b && Hf(this);\n                    a.Na();\n                    ff(a, this.draggedParts);\n                    this.transactionResult = c ? \"Copy\" : \"Move\";\n                    a.R(c ? \"SelectionCopied\" : \"SelectionMoved\", d)\n                }\n                this.stopTool();\n                c && a.R(\"ChangedSelection\", a.selection)\n            }\n        }\n    };\n    Qe.prototype.simulatedMouseMove = function (a, b, c) {\n        if (null === Se) return !1;\n        var d = Se.diagram;\n        c instanceof R || (c = null);\n        var e = We;\n        c !== e && (null !== e && e !== d && (e.Cf(), Se.isDragOutStarted = !1, e = e.toolManager.findTool(\"Dragging\"), null !== e && e.doSimulatedDragLeave()), We = c, null !== c && c !== d && (mf(), e = c.toolManager.findTool(\"Dragging\"), null !== e && (gf.contains(e) || gf.add(e), e.doSimulatedDragEnter())));\n        if (null === c || c === d || !c.allowDrop || c.isReadOnly || !c.allowInsert) return !1;\n        d = c.toolManager.findTool(\"Dragging\");\n        null !== d && (null !==\n            a && (void 0 !== a.targetTouches && (0 < a.targetTouches.length ? a = a.targetTouches[0] : 0 < a.changedTouches.length && (a = a.changedTouches[0])), b = c.getMouse(a)), c.lastInput.documentPoint = b, c.lastInput.viewPoint = c.Nq(b), c.lastInput.down = !1, c.lastInput.up = !1, d.doSimulatedDragOver());\n        return !0\n    };\n    Qe.prototype.simulatedMouseUp = function (a, b, c) {\n        if (null === Se) return !1;\n        var d = We,\n            e = Se.diagram;\n        if (null === c) return Se.doCancel(), !0;\n        if (c !== d) {\n            var f = d.toolManager.findTool(\"Dragging\");\n            if (null !== d && d !== e && null !== f) return d.Cf(), Se.isDragOutStarted = !1, f.doSimulatedDragLeave(), !1;\n            We = c;\n            d = c.toolManager.findTool(\"Dragging\");\n            null !== d && (mf(), gf.contains(d) || gf.add(d), d.doSimulatedDragEnter())\n        }\n        return c !== this.diagram ? (null !== a ? (void 0 !== a.targetTouches && (0 < a.targetTouches.length ? a = a.targetTouches[0] : 0 < a.changedTouches.length &&\n            (a = a.changedTouches[0])), b = c.getMouse(a)) : null === b && (b = new I), c.lastInput.documentPoint = b, c.lastInput.viewPoint = c.Nq(b), c.lastInput.down = !1, c.lastInput.up = !0, a = c.toolManager.findTool(\"Dragging\"), null !== a && a.doSimulatedDrop(), a = Se, null !== a && (c = a.mayCopy(), a.transactionResult = c ? \"Copy\" : \"Move\", a.stopTool()), !0) : !1\n    };\n\n    function Hf(a) {\n        if (null !== a.draggedParts)\n            for (var b = a.draggedParts.iterator; b.next();) {\n                var c = b.key;\n                c instanceof W && (c = c.containingGroup, null === c || null === c.placeholder || a.draggedParts.contains(c) || c.placeholder.o())\n            }\n    }\n    Qe.prototype.mayCopy = function () {\n        if (!this.isCopyEnabled) return !1;\n        var a = this.diagram;\n        if (a.isReadOnly || a.isModelReadOnly || !a.allowInsert || !a.allowCopy || (Wa ? !a.lastInput.alt : !a.lastInput.control)) return !1;\n        for (a = a.selection.iterator; a.next();) {\n            var b = a.value;\n            if (b.Wb() && b.canCopy()) return !0\n        }\n        return null !== this.draggedLink && this.dragsLink && this.draggedLink.canCopy() ? !0 : !1\n    };\n    Qe.prototype.mayDragOut = function () {\n        if (!this.isCopyEnabled) return !1;\n        var a = this.diagram;\n        if (!a.allowDragOut || !a.allowCopy || a.allowMove) return !1;\n        for (a = a.selection.iterator; a.next();) {\n            var b = a.value;\n            if (b.Wb() && b.canCopy()) return !0\n        }\n        return null !== this.draggedLink && this.dragsLink && this.draggedLink.canCopy() ? !0 : !1\n    };\n    Qe.prototype.mayMove = function () {\n        var a = this.diagram;\n        if (a.isReadOnly || !a.allowMove) return !1;\n        for (a = a.selection.iterator; a.next();) {\n            var b = a.value;\n            if (b.Wb() && b.canMove()) return !0\n        }\n        return null !== this.draggedLink && this.dragsLink && this.draggedLink.canMove() ? !0 : !1\n    };\n    Qe.prototype.computeBorder = function (a, b, c) {\n        return this.Bn || null === this.draggedParts || this.draggedParts.contains(a) ? null : c.assign(b)\n    };\n    Qe.prototype.Bz = function () {\n        return Se\n    };\n    Qe.prototype.mayDragIn = function () {\n        var a = this.diagram;\n        if (!a.allowDrop || a.isReadOnly || a.isModelReadOnly || !a.allowInsert) return !1;\n        var b = Se;\n        return null === b || b.diagram.model.dataFormat !== a.model.dataFormat ? !1 : !0\n    };\n    Qe.prototype.doSimulatedDragEnter = function () {\n        if (this.mayDragIn()) {\n            var a = this.diagram;\n            a.animationManager.Xc();\n            If(a);\n            a.animationManager.Xc();\n            var b = Se;\n            null !== b && (b.diagram.Ot = !1);\n            this.doUpdateCursor(a.grid)\n        }\n    };\n    Qe.prototype.doSimulatedDragLeave = function () {\n        var a = Se;\n        null !== a && a.doSimulatedDragOut();\n        this.doCancel()\n    };\n    Qe.prototype.doSimulatedDragOver = function () {\n        var a = this.diagram;\n        a.animationManager.bn = !0;\n        var b = Se;\n        if (null !== b && null !== b.draggedParts) {\n            if (!this.mayDragIn()) return;\n            Jf(this, b.draggedParts.Df(), !1, a.firstInput);\n            rf(this, this.copiedParts, !1);\n            tf(this, a.lastInput.documentPoint)\n        }\n        a.animationManager.bn = !1\n    };\n    Qe.prototype.doSimulatedDrop = function () {\n        var a = this.diagram,\n            b = Se;\n        if (null !== b) {\n            var c = b.diagram;\n            b.Bn = !0;\n            jf(this);\n            if (!this.mayDragIn()) return;\n            a.animationManager.bn = !0;\n            a.R(\"ChangingSelection\", a.selection);\n            this.ua(\"Drop\");\n            Jf(this, b.draggedParts.Df(), !0, a.lastInput);\n            rf(this, this.copiedParts, !1);\n            null !== this.copiedParts && (a.clearSelection(!0), this.copiedParts.iteratorKeys.each(function (a) {\n                a.isSelected = !0\n            }));\n            Ef(this, a.lastInput.documentPoint);\n            a.Na();\n            b = a.selection;\n            null !== this.copiedParts ? this.transactionResult =\n                \"ExternalCopy\" : b = new F;\n            this.copiedParts = null;\n            a.doFocus();\n            a.R(\"ExternalObjectsDropped\", b, c);\n            this.Hg();\n            a.R(\"ChangedSelection\", a.selection)\n        }\n        a.animationManager.bn = !1\n    };\n\n    function Jf(a, b, c, d) {\n        if (null === a.copiedParts) {\n            var e = a.diagram;\n            if (!e.isReadOnly && !e.isModelReadOnly) {\n                e.skipsUndoManager = !c;\n                e.partManager.addsToTemporaryLayer = !c;\n                a.startPoint = d.documentPoint;\n                c = e.ck(b, e, !0);\n                var f = N.alloc(); of (b, f);\n                d = f.x + f.width / 2;\n                e = f.y + f.height / 2;\n                N.free(f);\n                f = a.Ns;\n                var g = new H,\n                    h = I.alloc();\n                for (b = b.iterator; b.next();) {\n                    var k = b.value,\n                        l = c.H(k);\n                    k.Wb() && k.canCopy() ? (k = k.location, h.h(f.x - (d - k.x), f.y - (e - k.y)), l.location = h, l.yb(), g.add(l, a.sd(h))) : l instanceof S && k.canCopy() && (qf(l, f.x - d, f.y - e),\n                        g.add(l, a.sd()))\n                }\n                I.free(h);\n                a.copiedParts = g;\n                Te(a, g.Df());\n                null !== a.draggedLink && (c = a.draggedLink, d = c.routeBounds, qf(c, a.startPoint.x - (d.x + d.width / 2), a.startPoint.y - (d.y + d.height / 2)))\n            }\n        }\n    }\n    Qe.prototype.doSimulatedDragOut = function () {\n        var a = this.diagram;\n        a.Ot = !1;\n        this.mayCopy() || this.mayMove() ? a.currentCursor = \"\" : a.currentCursor = this.nodropCursor;\n        this.ko = null\n    };\n    Qe.prototype.computeMove = function (a, b, c, d) {\n        c = this.diagram;\n        return null !== c ? c.computeMove(a, b, this.dragOptions, d) : new I\n    };\n    ma.Object.defineProperties(Qe.prototype, {\n        isCopyEnabled: {\n            get: function () {\n                return this.Yc\n            },\n            set: function (a) {\n                this.Yc = a\n            }\n        },\n        copiesEffectiveCollection: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I = a\n            }\n        },\n        dragOptions: {\n            get: function () {\n                return this.Ia\n            },\n            set: function (a) {\n                this.Ia = a\n            }\n        },\n        isGridSnapEnabled: {\n            get: function () {\n                return this.dragOptions.isGridSnapEnabled\n            },\n            set: function (a) {\n                this.dragOptions.isGridSnapEnabled =\n                    a\n            }\n        },\n        isComplexRoutingRealtime: {\n            get: function () {\n                return this.Ic\n            },\n            set: function (a) {\n                this.Ic = a\n            }\n        },\n        isGridSnapRealtime: {\n            get: function () {\n                return this.dragOptions.isGridSnapRealtime\n            },\n            set: function (a) {\n                this.dragOptions.isGridSnapRealtime = a\n            }\n        },\n        gridSnapCellSize: {\n            get: function () {\n                return this.dragOptions.gridSnapCellSize\n            },\n            set: function (a) {\n                this.dragOptions.gridSnapCellSize.w(a) || (a = a.G(), this.dragOptions.gridSnapCellSize = a)\n            }\n        },\n        gridSnapCellSpot: {\n            get: function () {\n                return this.dragOptions.gridSnapCellSpot\n            },\n            set: function (a) {\n                this.dragOptions.gridSnapCellSpot.w(a) || (a = a.G(), this.dragOptions.gridSnapCellSpot = a)\n            }\n        },\n        gridSnapOrigin: {\n            get: function () {\n                return this.dragOptions.gridSnapOrigin\n            },\n            set: function (a) {\n                this.dragOptions.gridSnapOrigin.w(a) || (a = a.G(), this.dragOptions.gridSnapOrigin = a)\n            }\n        },\n        dragsLink: {\n            get: function () {\n                return this.dragOptions.dragsLink\n            },\n            set: function (a) {\n                this.dragOptions.dragsLink =\n                    a\n            }\n        },\n        dragsTree: {\n            get: function () {\n                return this.dragOptions.dragsTree\n            },\n            set: function (a) {\n                this.dragOptions.dragsTree = a\n            }\n        },\n        copyCursor: {\n            get: function () {\n                return this.Y\n            },\n            set: function (a) {\n                this.Y = a\n            }\n        },\n        moveCursor: {\n            get: function () {\n                return this.Oh\n            },\n            set: function (a) {\n                this.Oh = a\n            }\n        },\n        nodropCursor: {\n            get: function () {\n                return this.Ie\n            },\n            set: function (a) {\n                this.Ie = a\n            }\n        },\n        currentPart: {\n            get: function () {\n                return this.Ha\n            },\n            set: function (a) {\n                this.Ha = a\n            }\n        },\n        copiedParts: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a\n            }\n        },\n        draggedParts: {\n            get: function () {\n                return this.Za\n            },\n            set: function (a) {\n                this.Za = a\n            }\n        },\n        draggingParts: {\n            get: function () {\n                return null !== this.copiedParts ? this.copiedParts.Df() : null !== this.draggedParts ? this.draggedParts.Df() : this.Sq\n            }\n        },\n        draggedLink: {\n            get: function () {\n                return this.diagram.draggedLink\n            },\n            set: function (a) {\n                this.diagram.draggedLink =\n                    a\n            }\n        },\n        isDragOutStarted: {\n            get: function () {\n                return this.Ef\n            },\n            set: function (a) {\n                this.Ef = a\n            }\n        },\n        startPoint: {\n            get: function () {\n                return this.Ns\n            },\n            set: function (a) {\n                this.Ns.w(a) || this.Ns.assign(a)\n            }\n        },\n        delay: {\n            get: function () {\n                return this.Vk\n            },\n            set: function (a) {\n                this.Vk = a\n            }\n        }\n    });\n    Qe.prototype.getDraggingSource = Qe.prototype.Bz;\n    var gf = null,\n        Se = null,\n        We = null;\n    Qe.className = \"DraggingTool\";\n    gf = new E;\n    La(\"draggingTool\", function () {\n        return this.findTool(\"Dragging\")\n    }, function (a) {\n        this.Va(\"Dragging\", a, this.mouseMoveTools)\n    });\n    Oa.prototype.doCancel = function () {\n        null !== Se && Se.doCancel();\n        ye.prototype.doCancel.call(this)\n    };\n\n    function Kf() {\n        ye.call(this);\n        this.Ef = 100;\n        this.Y = !1;\n        this.fi = \"pointer\";\n        var a = new S,\n            b = new Lf;\n        b.isPanelMain = !0;\n        b.stroke = \"blue\";\n        a.add(b);\n        b = new Lf;\n        b.toArrow = \"Standard\";\n        b.fill = \"blue\";\n        b.stroke = \"blue\";\n        a.add(b);\n        a.layerName = \"Tool\";\n        this.Dw = a;\n        a = new W;\n        b = new Lf;\n        b.portId = \"\";\n        b.figure = \"Rectangle\";\n        b.fill = null;\n        b.stroke = \"magenta\";\n        b.strokeWidth = 2;\n        b.desiredSize = Lb;\n        a.add(b);\n        a.selectable = !1;\n        a.layerName = \"Tool\";\n        this.Bw = a;\n        this.Cw = b;\n        a = new W;\n        b = new Lf;\n        b.portId = \"\";\n        b.figure = \"Rectangle\";\n        b.fill = null;\n        b.stroke = \"magenta\";\n        b.strokeWidth =\n            2;\n        b.desiredSize = Lb;\n        a.add(b);\n        a.selectable = !1;\n        a.layerName = \"Tool\";\n        this.Ew = a;\n        this.Fw = b;\n        this.Yc = this.Ic = this.Ia = this.Ha = this.Za = null;\n        this.I = !0;\n        this.vy = new H;\n        this.Oh = this.xi = this.Sq = null\n    }\n    la(Kf, ye);\n    Kf.prototype.doStop = function () {\n        this.diagram.Cf();\n        this.originalToPort = this.originalToNode = this.originalFromPort = this.originalFromNode = this.originalLink = null;\n        this.validPortsCache.clear();\n        this.targetPort = null\n    };\n    Kf.prototype.copyPortProperties = function (a, b, c, d, e) {\n        if (null !== a && null !== b && null !== c && null !== d) {\n            var f = b.uf(),\n                g = M.alloc();\n            g.width = b.naturalBounds.width * f;\n            g.height = b.naturalBounds.height * f;\n            d.desiredSize = g;\n            M.free(g);\n            e ? (d.toSpot = b.toSpot, d.toEndSegmentLength = b.toEndSegmentLength) : (d.fromSpot = b.fromSpot, d.fromEndSegmentLength = b.fromEndSegmentLength);\n            c.locationSpot = Ac;\n            f = I.alloc();\n            c.location = b.ga(Ac, f);\n            I.free(f);\n            d.angle = b.Xi();\n            null !== this.portTargeted && this.portTargeted(a, b, c, d, e)\n        }\n    };\n    Kf.prototype.setNoTargetPortProperties = function (a, b, c) {\n        null !== b && (b.desiredSize = Lb, b.fromSpot = uc, b.toSpot = uc);\n        null !== a && (a.location = this.diagram.lastInput.documentPoint);\n        null !== this.portTargeted && this.portTargeted(null, null, a, b, c)\n    };\n    Kf.prototype.doMouseDown = function () {\n        this.isActive && this.doMouseMove()\n    };\n    Kf.prototype.doMouseMove = function () {\n        if (this.isActive) {\n            var a = this.diagram;\n            this.targetPort = this.findTargetPort(this.isForwards);\n            if (null !== this.targetPort && this.targetPort.part instanceof W) {\n                var b = this.targetPort.part;\n                this.isForwards ? this.copyPortProperties(b, this.targetPort, this.temporaryToNode, this.temporaryToPort, !0) : this.copyPortProperties(b, this.targetPort, this.temporaryFromNode, this.temporaryFromPort, !1)\n            } else this.isForwards ? this.setNoTargetPortProperties(this.temporaryToNode, this.temporaryToPort,\n                !0) : this.setNoTargetPortProperties(this.temporaryFromNode, this.temporaryFromPort, !1);\n            (a.allowHorizontalScroll || a.allowVerticalScroll) && a.gt(a.lastInput.viewPoint)\n        }\n    };\n    Kf.prototype.findValidLinkablePort = function (a, b) {\n        if (null === a) return null;\n        var c = a.part;\n        if (!(c instanceof W)) return null;\n        for (; null !== a;) {\n            var d = b ? a.toLinkable : a.fromLinkable;\n            if (!0 === d && (null !== a.portId || a instanceof W) && (b ? this.isValidTo(c, a) : this.isValidFrom(c, a))) return a;\n            if (!1 === d) break;\n            a = a.panel\n        }\n        return null\n    };\n    Kf.prototype.findTargetPort = function (a) {\n        var b = this.diagram,\n            c = b.lastInput.documentPoint,\n            d = this.portGravity;\n        0 >= d && (d = .1);\n        var e = this,\n            f = b.Ag(c, d, function (b) {\n                return e.findValidLinkablePort(b, a)\n            }, null, !0);\n        d = Infinity;\n        b = null;\n        for (f = f.iterator; f.next();) {\n            var g = f.value,\n                h = g.part;\n            if (h instanceof W) {\n                var k = g.ga(Ac, I.alloc()),\n                    l = c.x - k.x,\n                    m = c.y - k.y;\n                I.free(k);\n                k = l * l + m * m;\n                k < d && (l = this.validPortsCache.H(g), null !== l ? l && (b = g, d = k) : a && this.isValidLink(this.originalFromNode, this.originalFromPort, h, g) || !a && this.isValidLink(h,\n                    g, this.originalToNode, this.originalToPort) ? (this.validPortsCache.add(g, !0), b = g, d = k) : this.validPortsCache.add(g, !1))\n            }\n        }\n        return null !== b && (c = b.part, c instanceof W && (null === c.layer || c.layer.allowLink)) ? b : null\n    };\n    Kf.prototype.isValidFrom = function (a, b) {\n        if (null === a || null === b) return this.isUnconnectedLinkValid;\n        if (this.diagram.currentTool === this && (null !== a.layer && !a.layer.allowLink || !0 !== b.fromLinkable)) return !1;\n        var c = b.fromMaxLinks;\n        if (Infinity > c) {\n            if (null !== this.originalLink && a === this.originalFromNode && b === this.originalFromPort) return !0;\n            b = b.portId;\n            null === b && (b = \"\");\n            if (a.lq(b).count >= c) return !1\n        }\n        return !0\n    };\n    Kf.prototype.isValidTo = function (a, b) {\n        if (null === a || null === b) return this.isUnconnectedLinkValid;\n        if (this.diagram.currentTool === this && (null !== a.layer && !a.layer.allowLink || !0 !== b.toLinkable)) return !1;\n        var c = b.toMaxLinks;\n        if (Infinity > c) {\n            if (null !== this.originalLink && a === this.originalToNode && b === this.originalToPort) return !0;\n            b = b.portId;\n            null === b && (b = \"\");\n            if (a.vd(b).count >= c) return !1\n        }\n        return !0\n    };\n    Kf.prototype.isInSameNode = function (a, b) {\n        if (null === a || null === b) return !1;\n        if (a === b) return !0;\n        a = a.part;\n        b = b.part;\n        return null !== a && a === b\n    };\n    Kf.prototype.isLinked = function (a, b) {\n        if (null === a || null === b) return !1;\n        var c = a.part;\n        if (!(c instanceof W)) return !1;\n        a = a.portId;\n        null === a && (a = \"\");\n        var d = b.part;\n        if (!(d instanceof W)) return !1;\n        b = b.portId;\n        null === b && (b = \"\");\n        for (b = d.vd(b); b.next();)\n            if (d = b.value, d.fromNode === c && d.fromPortId === a) return !0;\n        return !1\n    };\n    Kf.prototype.isValidLink = function (a, b, c, d) {\n        if (!this.isValidFrom(a, b) || !this.isValidTo(c, d) || !(null === b || null === d || (b.fromLinkableSelfNode && d.toLinkableSelfNode || !this.isInSameNode(b, d)) && (b.fromLinkableDuplicates && d.toLinkableDuplicates || !this.isLinked(b, d))) || null !== this.originalLink && (null !== a && this.isLabelDependentOnLink(a, this.originalLink) || null !== c && this.isLabelDependentOnLink(c, this.originalLink)) || null !== a && null !== c && (null === a.data && null !== c.data || null !== a.data && null === c.data) || !this.isValidCycle(a,\n                c, this.originalLink)) return !1;\n        if (null !== a) {\n            var e = a.linkValidation;\n            if (null !== e && !e(a, b, c, d, this.originalLink)) return !1\n        }\n        if (null !== c && (e = c.linkValidation, null !== e && !e(a, b, c, d, this.originalLink))) return !1;\n        e = this.linkValidation;\n        return null !== e ? e(a, b, c, d, this.originalLink) : !0\n    };\n    Kf.prototype.isLabelDependentOnLink = function (a, b) {\n        if (null === a) return !1;\n        var c = a.labeledLink;\n        if (null === c) return !1;\n        if (c === b) return !0;\n        var d = new F;\n        d.add(a);\n        return Mf(this, c, b, d)\n    };\n\n    function Mf(a, b, c, d) {\n        if (b === c) return !0;\n        var e = b.fromNode;\n        if (null !== e && e.isLinkLabel && (d.add(e), Mf(a, e.labeledLink, c, d))) return !0;\n        b = b.toNode;\n        return null !== b && b.isLinkLabel && (d.add(b), Mf(a, b.labeledLink, c, d)) ? !0 : !1\n    }\n    Kf.prototype.isValidCycle = function (a, b, c) {\n        void 0 === c && (c = null);\n        if (null === a || null === b) return this.isUnconnectedLinkValid;\n        var d = this.diagram.validCycle;\n        if (d !== Nf) {\n            if (d === Of) {\n                d = c || this.temporaryLink;\n                if (null !== d && !d.isTreeLink) return !0;\n                for (d = b.linksConnected; d.next();) {\n                    var e = d.value;\n                    if (e !== c && e.isTreeLink && e.toNode === b) return !1\n                }\n                return !Pf(this, a, b, c, !0)\n            }\n            if (d === Qf) {\n                d = c || this.temporaryLink;\n                if (null !== d && !d.isTreeLink) return !0;\n                for (d = a.linksConnected; d.next();)\n                    if (e = d.value, e !== c && e.isTreeLink && e.fromNode ===\n                        a) return !1;\n                return !Pf(this, a, b, c, !0)\n            }\n            if (d === Rf) return a === b ? a = !0 : (d = new F, d.add(b), a = Sf(this, d, a, b, c)), !a;\n            if (d === Tf) return !Pf(this, a, b, c, !1);\n            if (d === Uf) return a === b ? a = !0 : (d = new F, d.add(b), a = Vf(this, d, a, b, c)), !a\n        }\n        return !0\n    };\n\n    function Pf(a, b, c, d, e) {\n        if (b === c) return !0;\n        if (null === b || null === c) return !1;\n        for (var f = b.linksConnected; f.next();) {\n            var g = f.value;\n            if (g !== d && (!e || g.isTreeLink) && g.toNode === b && (g = g.fromNode, g !== b && Pf(a, g, c, d, e))) return !0\n        }\n        return !1\n    }\n\n    function Sf(a, b, c, d, e) {\n        if (c === d) return !0;\n        if (null === c || null === d || b.contains(c)) return !1;\n        b.add(c);\n        for (var f = c.linksConnected; f.next();) {\n            var g = f.value;\n            if (g !== e && g.toNode === c && (g = g.fromNode, g !== c && Sf(a, b, g, d, e))) return !0\n        }\n        return !1\n    }\n\n    function Vf(a, b, c, d, e) {\n        if (c === d) return !0;\n        if (null === c || null === d || b.contains(c)) return !1;\n        b.add(c);\n        for (var f = c.linksConnected; f.next();) {\n            var g = f.value;\n            if (g !== e) {\n                var h = g.fromNode;\n                g = g.toNode;\n                h = h === c ? g : h;\n                if (h !== c && Vf(a, b, h, d, e)) return !0\n            }\n        }\n        return !1\n    }\n    ma.Object.defineProperties(Kf.prototype, {\n        portGravity: {\n            get: function () {\n                return this.Ef\n            },\n            set: function (a) {\n                0 <= a && (this.Ef = a)\n            }\n        },\n        isUnconnectedLinkValid: {\n            get: function () {\n                return this.Y\n            },\n            set: function (a) {\n                this.Y = a\n            }\n        },\n        linkingCursor: {\n            get: function () {\n                return this.fi\n            },\n            set: function (a) {\n                this.fi = a\n            }\n        },\n        temporaryLink: {\n            get: function () {\n                return this.Dw\n            },\n            set: function (a) {\n                this.Dw = a\n            }\n        },\n        temporaryFromNode: {\n            get: function () {\n                return this.Bw\n            },\n            set: function (a) {\n                this.Bw = a\n            }\n        },\n        temporaryFromPort: {\n            get: function () {\n                return this.Cw\n            },\n            set: function (a) {\n                this.Cw = a\n            }\n        },\n        temporaryToNode: {\n            get: function () {\n                return this.Ew\n            },\n            set: function (a) {\n                this.Ew = a\n            }\n        },\n        temporaryToPort: {\n            get: function () {\n                return this.Fw\n            },\n            set: function (a) {\n                this.Fw = a\n            }\n        },\n        originalLink: {\n            get: function () {\n                return this.Za\n            },\n            set: function (a) {\n                this.Za = a\n            }\n        },\n        originalFromNode: {\n            get: function () {\n                return this.Ha\n            },\n            set: function (a) {\n                this.Ha = a\n            }\n        },\n        originalFromPort: {\n            get: function () {\n                return this.Ia\n            },\n            set: function (a) {\n                this.Ia = a\n            }\n        },\n        originalToNode: {\n            get: function () {\n                return this.Ic\n            },\n            set: function (a) {\n                this.Ic = a\n            }\n        },\n        originalToPort: {\n            get: function () {\n                return this.Yc\n            },\n            set: function (a) {\n                this.Yc = a\n            }\n        },\n        isForwards: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I = a\n            }\n        },\n        validPortsCache: {\n            get: function () {\n                return this.vy\n            }\n        },\n        targetPort: {\n            get: function () {\n                return this.Sq\n            },\n            set: function (a) {\n                this.Sq = a\n            }\n        },\n        linkValidation: {\n            get: function () {\n                return this.xi\n            },\n            set: function (a) {\n                this.xi = a\n            }\n        },\n        portTargeted: {\n            get: function () {\n                return this.Oh\n            },\n            set: function (a) {\n                this.Oh = a\n            }\n        }\n    });\n    Kf.className = \"LinkingBaseTool\";\n\n    function Wf() {\n        Kf.call(this);\n        this.name = \"Linking\";\n        this.u = {};\n        this.l = null;\n        this.J = Xf;\n        this.Ie = null\n    }\n    la(Wf, Kf);\n    Wf.prototype.canStart = function () {\n        if (!this.isEnabled) return !1;\n        var a = this.diagram;\n        return a.isReadOnly || a.isModelReadOnly || !a.allowLink || !a.model.vt() || !a.lastInput.left || a.currentTool !== this && !this.isBeyondDragSize() ? !1 : null !== this.findLinkablePort()\n    };\n    Wf.prototype.findLinkablePort = function () {\n        var a = this.diagram,\n            b = this.startObject;\n        null === b && (b = a.Ub(a.firstInput.documentPoint, null, null));\n        if (null === b || !(b.part instanceof W)) return null;\n        a = this.direction;\n        if (a === Xf || a === Yf) {\n            var c = this.findValidLinkablePort(b, !1);\n            if (null !== c) return this.isForwards = !0, c\n        }\n        if (a === Xf || a === Zf)\n            if (b = this.findValidLinkablePort(b, !0), null !== b) return this.isForwards = !1, b;\n        return null\n    };\n    Wf.prototype.doActivate = function () {\n        var a = this.diagram,\n            b = this.findLinkablePort();\n        null !== b && (this.ua(this.name), a.isMouseCaptured = !0, a.currentCursor = this.linkingCursor, this.isForwards ? (null === this.temporaryToNode || this.temporaryToNode.location.v() || (this.temporaryToNode.location = a.lastInput.documentPoint), this.originalFromPort = b, b = this.originalFromPort.part, b instanceof W && (this.originalFromNode = b), this.copyPortProperties(this.originalFromNode, this.originalFromPort, this.temporaryFromNode, this.temporaryFromPort,\n            !1)) : (null === this.temporaryFromNode || this.temporaryFromNode.location.v() || (this.temporaryFromNode.location = a.lastInput.documentPoint), this.originalToPort = b, b = this.originalToPort.part, b instanceof W && (this.originalToNode = b), this.copyPortProperties(this.originalToNode, this.originalToPort, this.temporaryToNode, this.temporaryToPort, !0)), a.add(this.temporaryFromNode), a.add(this.temporaryToNode), null !== this.temporaryLink && (null !== this.temporaryFromNode && (this.temporaryLink.fromNode = this.temporaryFromNode),\n            null !== this.temporaryToNode && (this.temporaryLink.toNode = this.temporaryToNode), this.temporaryLink.isTreeLink = this.isNewTreeLink(), this.temporaryLink.Oa(), a.add(this.temporaryLink)), this.isActive = !0)\n    };\n    Wf.prototype.doDeactivate = function () {\n        this.isActive = !1;\n        var a = this.diagram;\n        a.remove(this.temporaryLink);\n        a.remove(this.temporaryFromNode);\n        a.remove(this.temporaryToNode);\n        a.isMouseCaptured = !1;\n        a.currentCursor = \"\";\n        this.Hg()\n    };\n    Wf.prototype.doStop = function () {\n        Kf.prototype.doStop.call(this);\n        this.startObject = null\n    };\n    Wf.prototype.doMouseUp = function () {\n        var a = this.diagram;\n        if (this.isActive) {\n            var b = this.transactionResult = null,\n                c = null,\n                d = null,\n                e = null,\n                f = null;\n            try {\n                var g = this.targetPort = this.findTargetPort(this.isForwards);\n                if (null !== g) {\n                    var h = g.part;\n                    h instanceof W && (this.isForwards ? (null !== this.originalFromNode && (b = this.originalFromNode, c = this.originalFromPort), d = h, e = g) : (b = h, c = g, null !== this.originalToNode && (d = this.originalToNode, e = this.originalToPort)))\n                } else this.isForwards ? null !== this.originalFromNode && this.isUnconnectedLinkValid &&\n                    (b = this.originalFromNode, c = this.originalFromPort) : null !== this.originalToNode && this.isUnconnectedLinkValid && (d = this.originalToNode, e = this.originalToPort);\n                null !== b || null !== d ? (f = this.insertLink(b, c, d, e), null !== f ? (null === g && (this.isForwards ? f.defaultToPoint = a.lastInput.documentPoint : f.defaultFromPoint = a.lastInput.documentPoint), a.allowSelect && (a.R(\"ChangingSelection\", a.selection), a.clearSelection(!0), f.isSelected = !0), this.transactionResult = this.name, a.R(\"LinkDrawn\", f)) : (a.model.gq(), this.doNoLink(b, c,\n                    d, e))) : this.isForwards ? this.doNoLink(this.originalFromNode, this.originalFromPort, null, null) : this.doNoLink(null, null, this.originalToNode, this.originalToPort)\n            } finally {\n                this.stopTool(), f && a.allowSelect && a.R(\"ChangedSelection\", a.selection)\n            }\n        }\n    };\n    Wf.prototype.isNewTreeLink = function () {\n        var a = this.archetypeLinkData;\n        if (null === a) return !0;\n        if (a instanceof S) return a.isTreeLink;\n        var b = this.diagram;\n        if (null === b) return !0;\n        a = b.partManager.getLinkCategoryForData(a);\n        b = b.partManager.findLinkTemplateForCategory(a);\n        return null !== b ? b.isTreeLink : !0\n    };\n    Wf.prototype.insertLink = function (a, b, c, d) {\n        return this.diagram.partManager.insertLink(a, b, c, d)\n    };\n    Wf.prototype.doNoLink = function () {};\n    ma.Object.defineProperties(Wf.prototype, {\n        archetypeLinkData: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a\n            }\n        },\n        archetypeLabelNodeData: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l = a\n            }\n        },\n        direction: {\n            get: function () {\n                return this.J\n            },\n            set: function (a) {\n                this.J = a\n            }\n        },\n        startObject: {\n            get: function () {\n                return this.Ie\n            },\n            set: function (a) {\n                this.Ie = a\n            }\n        }\n    });\n    var Xf = new D(Wf, \"Either\", 0),\n        Yf = new D(Wf, \"ForwardsOnly\", 0),\n        Zf = new D(Wf, \"BackwardsOnly\", 0);\n    Wf.className = \"LinkingTool\";\n    Wf.Either = Xf;\n    Wf.ForwardsOnly = Yf;\n    Wf.BackwardsOnly = Zf;\n\n    function Xe() {\n        Kf.call(this);\n        this.name = \"Relinking\";\n        var a = new Lf;\n        a.figure = \"Diamond\";\n        a.desiredSize = Nb;\n        a.fill = \"lightblue\";\n        a.stroke = \"dodgerblue\";\n        a.cursor = this.linkingCursor;\n        a.segmentIndex = 0;\n        this.u = a;\n        a = new Lf;\n        a.figure = \"Diamond\";\n        a.desiredSize = Nb;\n        a.fill = \"lightblue\";\n        a.stroke = \"dodgerblue\";\n        a.cursor = this.linkingCursor;\n        a.segmentIndex = -1;\n        this.Ie = a;\n        this.l = null;\n        this.gx = new N\n    }\n    la(Xe, Kf);\n    Xe.prototype.updateAdornments = function (a) {\n        if (null !== a && a instanceof S) {\n            var b = \"RelinkFrom\",\n                c = null;\n            if (a.isSelected && !this.diagram.isReadOnly) {\n                var d = a.selectionObject;\n                null !== d && a.canRelinkFrom() && a.actualBounds.v() && a.isVisible() && d.actualBounds.v() && d.zf() && (c = a.fk(b), null === c && (c = this.makeAdornment(d, !1), a.Ch(b, c)))\n            }\n            null === c && a.Af(b);\n            b = \"RelinkTo\";\n            c = null;\n            a.isSelected && !this.diagram.isReadOnly && (d = a.selectionObject, null !== d && a.canRelinkTo() && a.actualBounds.v() && a.isVisible() && d.actualBounds.v() && d.zf() &&\n                (c = a.fk(b), null === c ? (c = this.makeAdornment(d, !0), a.Ch(b, c)) : c.o()));\n            null === c && a.Af(b)\n        }\n    };\n    Xe.prototype.makeAdornment = function (a, b) {\n        var c = new Je;\n        c.type = X.Link;\n        b = b ? this.toHandleArchetype : this.fromHandleArchetype;\n        null !== b && c.add(b.copy());\n        c.adornedObject = a;\n        return c\n    };\n    Xe.prototype.canStart = function () {\n        if (!this.isEnabled) return !1;\n        var a = this.diagram;\n        if (a.isReadOnly || a.isModelReadOnly || !a.allowRelink || !a.model.vt() || !a.lastInput.left) return !1;\n        var b = this.findToolHandleAt(a.firstInput.documentPoint, \"RelinkFrom\");\n        null === b && (b = this.findToolHandleAt(a.firstInput.documentPoint, \"RelinkTo\"));\n        return null !== b\n    };\n    Xe.prototype.doActivate = function () {\n        var a = this.diagram;\n        if (null === this.originalLink) {\n            var b = this.handle;\n            null === b && (b = this.findToolHandleAt(a.firstInput.documentPoint, \"RelinkFrom\"), null === b && (b = this.findToolHandleAt(a.firstInput.documentPoint, \"RelinkTo\")));\n            if (null === b) return;\n            var c = b.part;\n            if (!(c instanceof Je && c.adornedPart instanceof S)) return;\n            this.handle = b;\n            this.isForwards = null === c || \"RelinkTo\" === c.category;\n            this.originalLink = c.adornedPart\n        }\n        this.ua(this.name);\n        a.isMouseCaptured = !0;\n        a.currentCursor = this.linkingCursor;\n        this.originalFromPort = this.originalLink.fromPort;\n        this.originalFromNode = this.originalLink.fromNode;\n        this.originalToPort = this.originalLink.toPort;\n        this.originalToNode = this.originalLink.toNode;\n        this.gx.set(this.originalLink.actualBounds);\n        null !== this.originalLink && 0 < this.originalLink.pointsCount && (null === this.originalLink.fromNode && (null !== this.temporaryFromPort && (this.temporaryFromPort.desiredSize = Kb), null !== this.temporaryFromNode && (this.temporaryFromNode.location = this.originalLink.i(0))), null === this.originalLink.toNode &&\n            (null !== this.temporaryToPort && (this.temporaryToPort.desiredSize = Kb), null !== this.temporaryToNode && (this.temporaryToNode.location = this.originalLink.i(this.originalLink.pointsCount - 1))));\n        this.copyPortProperties(this.originalFromNode, this.originalFromPort, this.temporaryFromNode, this.temporaryFromPort, !1);\n        this.copyPortProperties(this.originalToNode, this.originalToPort, this.temporaryToNode, this.temporaryToPort, !0);\n        a.add(this.temporaryFromNode);\n        a.add(this.temporaryToNode);\n        null !== this.temporaryLink && (null !==\n            this.temporaryFromNode && (this.temporaryLink.fromNode = this.temporaryFromNode), null !== this.temporaryToNode && (this.temporaryLink.toNode = this.temporaryToNode), this.copyLinkProperties(this.originalLink, this.temporaryLink), this.temporaryLink.Oa(), a.add(this.temporaryLink));\n        this.isActive = !0\n    };\n    Xe.prototype.copyLinkProperties = function (a, b) {\n        if (null !== a && null !== b) {\n            b.adjusting = a.adjusting;\n            b.corner = a.corner;\n            var c = a.curve;\n            if (c === $f || c === ag) c = bg;\n            b.curve = c;\n            b.curviness = a.curviness;\n            b.isTreeLink = a.isTreeLink;\n            b.points = a.points;\n            b.routing = a.routing;\n            b.smoothness = a.smoothness;\n            b.fromSpot = a.fromSpot;\n            b.fromEndSegmentLength = a.fromEndSegmentLength;\n            b.fromShortLength = a.fromShortLength;\n            b.toSpot = a.toSpot;\n            b.toEndSegmentLength = a.toEndSegmentLength;\n            b.toShortLength = a.toShortLength\n        }\n    };\n    Xe.prototype.doDeactivate = function () {\n        this.isActive = !1;\n        var a = this.diagram;\n        a.remove(this.temporaryLink);\n        a.remove(this.temporaryFromNode);\n        a.remove(this.temporaryToNode);\n        a.isMouseCaptured = !1;\n        a.currentCursor = \"\";\n        this.Hg()\n    };\n    Xe.prototype.doStop = function () {\n        Kf.prototype.doStop.call(this);\n        this.handle = null\n    };\n    Xe.prototype.doMouseUp = function () {\n        if (this.isActive) {\n            var a = this.diagram;\n            this.transactionResult = null;\n            var b = this.originalFromNode,\n                c = this.originalFromPort,\n                d = this.originalToNode,\n                e = this.originalToPort,\n                f = this.originalLink;\n            this.targetPort = this.findTargetPort(this.isForwards);\n            if (null !== this.targetPort) {\n                var g = this.targetPort.part;\n                g instanceof W && (this.isForwards ? (d = g, e = this.targetPort) : (b = g, c = this.targetPort))\n            } else this.isUnconnectedLinkValid ? this.isForwards ? e = d = null : c = b = null : f = null;\n            null !== f ? (this.reconnectLink(f,\n                this.isForwards ? d : b, this.isForwards ? e : c, this.isForwards), null === this.targetPort && (this.isForwards ? f.defaultToPoint = a.lastInput.documentPoint : f.defaultFromPoint = a.lastInput.documentPoint, f.Oa()), a.allowSelect && (f.isSelected = !0), this.transactionResult = this.name, a.R(\"LinkRelinked\", f, this.isForwards ? this.originalToPort : this.originalFromPort)) : this.doNoRelink(this.originalLink, this.isForwards);\n            this.originalLink.tq(this.gx)\n        }\n        this.stopTool()\n    };\n    Xe.prototype.reconnectLink = function (a, b, c, d) {\n        c = null !== c && null !== c.portId ? c.portId : \"\";\n        d ? (a.toNode = b, a.toPortId = c) : (a.fromNode = b, a.fromPortId = c);\n        return !0\n    };\n    Xe.prototype.doNoRelink = function () {};\n\n    function yf(a, b, c, d, e) {\n        null !== b ? (a.copyPortProperties(b, c, a.temporaryFromNode, a.temporaryFromPort, !1), a.diagram.add(a.temporaryFromNode)) : a.diagram.remove(a.temporaryFromNode);\n        null !== d ? (a.copyPortProperties(d, e, a.temporaryToNode, a.temporaryToPort, !0), a.diagram.add(a.temporaryToNode)) : a.diagram.remove(a.temporaryToNode)\n    }\n    ma.Object.defineProperties(Xe.prototype, {\n        fromHandleArchetype: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a\n            }\n        },\n        toHandleArchetype: {\n            get: function () {\n                return this.Ie\n            },\n            set: function (a) {\n                this.Ie = a\n            }\n        },\n        handle: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                if (null !== a && !(a.part instanceof Je)) throw Error(\"new handle is not in an Adornment: \" + a);\n                this.l = a\n            }\n        }\n    });\n    Xe.className = \"RelinkingTool\";\n    La(\"linkingTool\", function () {\n        return this.findTool(\"Linking\")\n    }, function (a) {\n        this.Va(\"Linking\", a, this.mouseMoveTools)\n    });\n    La(\"relinkingTool\", function () {\n        return this.findTool(\"Relinking\")\n    }, function (a) {\n        this.Va(\"Relinking\", a, this.mouseDownTools)\n    });\n\n    function cg() {\n        ye.call(this);\n        this.name = \"LinkReshaping\";\n        var a = new Lf;\n        a.figure = \"Rectangle\";\n        a.desiredSize = Mb;\n        a.fill = \"lightblue\";\n        a.stroke = \"dodgerblue\";\n        this.u = a;\n        a = new Lf;\n        a.figure = \"Diamond\";\n        a.desiredSize = Nb;\n        a.fill = \"lightblue\";\n        a.stroke = \"dodgerblue\";\n        a.cursor = \"move\";\n        this.I = a;\n        this.Y = 3;\n        this.Xt = this.l = null;\n        this.hx = new I;\n        this.ps = new E\n    }\n    la(cg, ye);\n    cg.prototype.Av = function (a) {\n        return a && a.ws && 0 !== a.ws.value ? a.ws : pg\n    };\n    cg.prototype.Im = function (a, b) {\n        a.ws = b\n    };\n    cg.prototype.updateAdornments = function (a) {\n        if (null !== a && a instanceof S) {\n            var b = null;\n            if (a.isSelected && !this.diagram.isReadOnly) {\n                var c = a.path;\n                null !== c && a.canReshape() && a.actualBounds.v() && a.isVisible() && c.actualBounds.v() && c.zf() && (b = a.fk(this.name), null === b || b.ax !== a.pointsCount || b.qx !== a.resegmentable) && (b = this.makeAdornment(c), null !== b && (b.ax = a.pointsCount, b.qx = a.resegmentable, a.Ch(this.name, b)))\n            }\n            null === b && a.Af(this.name)\n        }\n    };\n    cg.prototype.makeAdornment = function (a) {\n        var b = a.part,\n            c = b.pointsCount,\n            d = b.isOrthogonal,\n            e = null;\n        if (null !== b.points && 1 < c) {\n            e = new Je;\n            e.type = X.Link;\n            c = b.firstPickIndex;\n            var f = b.lastPickIndex,\n                g = d ? 1 : 0;\n            if (b.resegmentable && b.computeCurve() !== qg)\n                for (var h = c + g; h < f - g; h++) {\n                    var k = this.makeResegmentHandle(a, h);\n                    null !== k && (k.segmentIndex = h, k.segmentFraction = .5, k.fromMaxLinks = 999, e.add(k))\n                }\n            for (g = c + 1; g < f; g++)\n                if (h = this.makeHandle(a, g), null !== h) {\n                    h.segmentIndex = g;\n                    if (g !== c)\n                        if (g === c + 1 && d) {\n                            k = b.i(c);\n                            var l = b.i(c + 1);\n                            J.A(k.x, l.x) &&\n                                J.A(k.y, l.y) && (l = b.i(c - 1));\n                            J.A(k.x, l.x) ? (this.Im(h, rg), h.cursor = \"n-resize\") : J.A(k.y, l.y) && (this.Im(h, sg), h.cursor = \"w-resize\")\n                        } else g === f - 1 && d ? (k = b.i(f - 1), l = b.i(f), J.A(k.x, l.x) && J.A(k.y, l.y) && (k = b.i(f + 1)), J.A(k.x, l.x) ? (this.Im(h, rg), h.cursor = \"n-resize\") : J.A(k.y, l.y) && (this.Im(h, sg), h.cursor = \"w-resize\")) : g !== f && (this.Im(h, tg), h.cursor = \"move\");\n                    e.add(h)\n                } e.adornedObject = a\n        }\n        return e\n    };\n    cg.prototype.makeHandle = function () {\n        var a = this.handleArchetype;\n        return null === a ? null : a.copy()\n    };\n    cg.prototype.makeResegmentHandle = function () {\n        var a = this.midHandleArchetype;\n        return null === a ? null : a.copy()\n    };\n    cg.prototype.canStart = function () {\n        if (!this.isEnabled) return !1;\n        var a = this.diagram;\n        return !a.isReadOnly && a.allowReshape && a.lastInput.left ? null !== this.findToolHandleAt(a.firstInput.documentPoint, this.name) : !1\n    };\n    cg.prototype.doActivate = function () {\n        var a = this.diagram;\n        null === this.handle && (this.handle = this.findToolHandleAt(a.firstInput.documentPoint, this.name));\n        if (null !== this.handle) {\n            var b = this.handle.part.adornedPart;\n            if (b instanceof S) {\n                this.Xt = b;\n                a.isMouseCaptured = !0;\n                this.ua(this.name);\n                if (b.resegmentable && 999 === this.handle.fromMaxLinks) {\n                    var c = b.points.copy(),\n                        d = this.getResegmentingPoint();\n                    c.Kb(this.handle.segmentIndex + 1, d);\n                    b.isOrthogonal && c.Kb(this.handle.segmentIndex + 1, d);\n                    b.points = c;\n                    b.Lb();\n                    b.updateAdornments();\n                    this.handle = this.findToolHandleAt(a.firstInput.documentPoint, this.name);\n                    if (null === this.handle) {\n                        this.doDeactivate();\n                        return\n                    }\n                }\n                this.hx = b.i(this.handle.segmentIndex);\n                this.ps = b.points.copy();\n                this.isActive = !0\n            }\n        }\n    };\n    cg.prototype.doDeactivate = function () {\n        this.Hg();\n        this.Xt = this.handle = null;\n        this.isActive = this.diagram.isMouseCaptured = !1\n    };\n    cg.prototype.doCancel = function () {\n        var a = this.adornedLink;\n        null !== a && (a.points = this.ps);\n        this.stopTool()\n    };\n    cg.prototype.getResegmentingPoint = function () {\n        return this.handle.ga(Ac)\n    };\n    cg.prototype.doMouseMove = function () {\n        var a = this.diagram;\n        this.isActive && (a = this.computeReshape(a.lastInput.documentPoint), this.reshape(a))\n    };\n    cg.prototype.doMouseUp = function () {\n        var a = this.diagram;\n        if (this.isActive) {\n            var b = this.computeReshape(a.lastInput.documentPoint);\n            this.reshape(b);\n            b = this.adornedLink;\n            if (null !== b && b.resegmentable) {\n                var c = this.handle.segmentIndex,\n                    d = b.i(c - 1),\n                    e = b.i(c),\n                    f = b.i(c + 1);\n                if (b.isOrthogonal) {\n                    if (c > b.firstPickIndex + 1 && c < b.lastPickIndex - 1) {\n                        var g = b.i(c - 2);\n                        if (Math.abs(d.x - e.x) < this.resegmentingDistance && Math.abs(d.y - e.y) < this.resegmentingDistance && (ug(this, g, d, e, f, !0) || ug(this, g, d, e, f, !1))) {\n                            var h = b.points.copy();\n                            ug(this, g, d,\n                                e, f, !0) ? (h.gd(c - 2, new I(g.x, (f.y + g.y) / 2)), h.gd(c + 1, new I(f.x, (f.y + g.y) / 2))) : (h.gd(c - 2, new I((f.x + g.x) / 2, g.y)), h.gd(c + 1, new I((f.x + g.x) / 2, f.y)));\n                            h.lb(c);\n                            h.lb(c - 1);\n                            b.points = h;\n                            b.Lb()\n                        } else g = b.i(c + 2), Math.abs(e.x - f.x) < this.resegmentingDistance && Math.abs(e.y - f.y) < this.resegmentingDistance && (ug(this, d, e, f, g, !0) || ug(this, d, e, f, g, !1)) && (h = b.points.copy(), ug(this, d, e, f, g, !0) ? (h.gd(c - 1, new I(d.x, (d.y + g.y) / 2)), h.gd(c + 2, new I(g.x, (d.y + g.y) / 2))) : (h.gd(c - 1, new I((d.x + g.x) / 2, d.y)), h.gd(c + 2, new I((d.x + g.x) / 2, g.y))),\n                            h.lb(c + 1), h.lb(c), b.points = h, b.Lb())\n                    }\n                } else g = I.alloc(), J.Lh(d.x, d.y, f.x, f.y, e.x, e.y, g) && g.Ae(e) < this.resegmentingDistance * this.resegmentingDistance && (d = b.points.copy(), d.lb(c), b.points = d, b.Lb()), I.free(g)\n            }\n            a.Na();\n            this.transactionResult = this.name;\n            a.R(\"LinkReshaped\", this.adornedLink, this.ps)\n        }\n        this.stopTool()\n    };\n\n    function ug(a, b, c, d, e, f) {\n        return f ? Math.abs(b.y - c.y) < a.resegmentingDistance && Math.abs(c.y - d.y) < a.resegmentingDistance && Math.abs(d.y - e.y) < a.resegmentingDistance : Math.abs(b.x - c.x) < a.resegmentingDistance && Math.abs(c.x - d.x) < a.resegmentingDistance && Math.abs(d.x - e.x) < a.resegmentingDistance\n    }\n    cg.prototype.reshape = function (a) {\n        var b = this.adornedLink;\n        b.Nh();\n        var c = this.handle.segmentIndex,\n            d = this.Av(this.handle);\n        if (b.isOrthogonal)\n            if (c === b.firstPickIndex + 1) c = b.firstPickIndex + 1, d === rg ? (b.K(c, b.i(c - 1).x, a.y), b.K(c + 1, b.i(c + 2).x, a.y)) : d === sg && (b.K(c, a.x, b.i(c - 1).y), b.K(c + 1, a.x, b.i(c + 2).y));\n            else if (c === b.lastPickIndex - 1) c = b.lastPickIndex - 1, d === rg ? (b.K(c - 1, b.i(c - 2).x, a.y), b.K(c, b.i(c + 1).x, a.y)) : d === sg && (b.K(c - 1, a.x, b.i(c - 2).y), b.K(c, a.x, b.i(c + 1).y));\n        else {\n            d = c;\n            var e = b.i(d),\n                f = b.i(d - 1),\n                g = b.i(d + 1);\n            J.A(f.x,\n                e.x) && J.A(e.y, g.y) ? (J.A(f.x, b.i(d - 2).x) && !J.A(f.y, b.i(d - 2).y) ? (b.m(d, a.x, f.y), c++, d++) : b.K(d - 1, a.x, f.y), J.A(g.y, b.i(d + 2).y) && !J.A(g.x, b.i(d + 2).x) ? b.m(d + 1, g.x, a.y) : b.K(d + 1, g.x, a.y)) : J.A(f.y, e.y) && J.A(e.x, g.x) ? (J.A(f.y, b.i(d - 2).y) && !J.A(f.x, b.i(d - 2).x) ? (b.m(d, f.x, a.y), c++, d++) : b.K(d - 1, f.x, a.y), J.A(g.x, b.i(d + 2).x) && !J.A(g.y, b.i(d + 2).y) ? b.m(d + 1, a.x, g.y) : b.K(d + 1, a.x, g.y)) : J.A(f.x, e.x) && J.A(e.x, g.x) ? (J.A(f.x, b.i(d - 2).x) && !J.A(f.y, b.i(d - 2).y) ? (b.m(d, a.x, f.y), c++, d++) : b.K(d - 1, a.x, f.y), J.A(g.x, b.i(d + 2).x) &&\n                !J.A(g.y, b.i(d + 2).y) ? b.m(d + 1, a.x, g.y) : b.K(d + 1, a.x, g.y)) : J.A(f.y, e.y) && J.A(e.y, g.y) && (J.A(f.y, b.i(d - 2).y) && !J.A(f.x, b.i(d - 2).x) ? (b.m(d, f.x, a.y), c++, d++) : b.K(d - 1, f.x, a.y), J.A(g.y, b.i(d + 2).y) && !J.A(g.x, b.i(d + 2).x) ? b.m(d + 1, g.x, a.y) : b.K(d + 1, g.x, a.y));\n            b.K(c, a.x, a.y)\n        } else b.K(c, a.x, a.y), d = b.fromNode, e = b.fromPort, null !== d && (f = d.findVisibleNode(), null !== f && f !== d && (d = f, e = d.port)), 1 === c && b.computeSpot(!0, e).jc() && (f = e.ga(Ac, I.alloc()), d = b.getLinkPointFromPoint(d, e, f, a, !0, I.alloc()), b.K(0, d.x, d.y), I.free(f),\n            I.free(d)), d = b.toNode, e = b.toPort, null !== d && (f = d.findVisibleNode(), null !== f && f !== d && (d = f, e = d.port)), c === b.pointsCount - 2 && b.computeSpot(!1, e).jc() && (c = e.ga(Ac, I.alloc()), a = b.getLinkPointFromPoint(d, e, c, a, !1, I.alloc()), b.K(b.pointsCount - 1, a.x, a.y), I.free(c), I.free(a));\n        b.rf()\n    };\n    cg.prototype.computeReshape = function (a) {\n        var b = this.adornedLink,\n            c = this.handle.segmentIndex;\n        switch (this.Av(this.handle)) {\n            case tg:\n                return a;\n            case rg:\n                return new I(b.i(c).x, a.y);\n            case sg:\n                return new I(a.x, b.i(c).y);\n            default:\n            case pg:\n                return b.i(c)\n        }\n    };\n    ma.Object.defineProperties(cg.prototype, {\n        handleArchetype: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a\n            }\n        },\n        midHandleArchetype: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I = a\n            }\n        },\n        handle: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                if (null !== a && !(a.part instanceof Je)) throw Error(\"new handle is not in an Adornment: \" + a);\n                this.l = a\n            }\n        },\n        adornedLink: {\n            get: function () {\n                return this.Xt\n            }\n        },\n        resegmentingDistance: {\n            get: function () {\n                return this.Y\n            },\n            set: function (a) {\n                this.Y = a\n            }\n        },\n        originalPoint: {\n            get: function () {\n                return this.hx\n            }\n        },\n        originalPoints: {\n            get: function () {\n                return this.ps\n            }\n        }\n    });\n    cg.prototype.setReshapingBehavior = cg.prototype.Im;\n    cg.prototype.getReshapingBehavior = cg.prototype.Av;\n    var pg = new D(cg, \"None\", 0),\n        sg = new D(cg, \"Horizontal\", 1),\n        rg = new D(cg, \"Vertical\", 2),\n        tg = new D(cg, \"All\", 3);\n    cg.className = \"LinkReshapingTool\";\n    cg.None = pg;\n    cg.Horizontal = sg;\n    cg.Vertical = rg;\n    cg.All = tg;\n    La(\"linkReshapingTool\", function () {\n        return this.findTool(\"LinkReshaping\")\n    }, function (a) {\n        this.Va(\"LinkReshaping\", a, this.mouseDownTools)\n    });\n\n    function vg() {\n        ye.call(this);\n        this.name = \"Resizing\";\n        this.eg = (new M(1, 1)).freeze();\n        this.dg = (new M(9999, 9999)).freeze();\n        this.Ng = (new M(NaN, NaN)).freeze();\n        this.I = !1;\n        this.ae = null;\n        var a = new Lf;\n        a.alignmentFocus = Ac;\n        a.figure = \"Rectangle\";\n        a.desiredSize = Mb;\n        a.fill = \"lightblue\";\n        a.stroke = \"dodgerblue\";\n        a.strokeWidth = 1;\n        a.cursor = \"pointer\";\n        this.u = a;\n        this.l = null;\n        this.os = new I;\n        this.ex = new M;\n        this.Xo = new I;\n        this.nu = new M(0, 0);\n        this.mu = new M(Infinity, Infinity);\n        this.lu = new M(1, 1);\n        this.$w = !0\n    }\n    la(vg, ye);\n    vg.prototype.updateAdornments = function (a) {\n        if (!(null === a || a instanceof S)) {\n            if (a.isSelected && !this.diagram.isReadOnly) {\n                var b = a.resizeObject,\n                    c = a.fk(this.name);\n                if (null !== b && a.canResize() && a.actualBounds.v() && a.isVisible() && b.actualBounds.v() && b.zf()) {\n                    if (null === c || c.adornedObject !== b) c = this.makeAdornment(b);\n                    if (null !== c) {\n                        b = b.Xi();\n                        wg(a) && this.updateResizeHandles(c, b);\n                        a.Ch(this.name, c);\n                        return\n                    }\n                }\n            }\n            a.Af(this.name)\n        }\n    };\n    vg.prototype.makeAdornment = function (a) {\n        var b = a.part.resizeAdornmentTemplate;\n        if (null === b) {\n            b = new Je;\n            b.type = X.Spot;\n            b.locationSpot = Ac;\n            var c = new xg;\n            c.isPanelMain = !0;\n            b.add(c);\n            b.add(this.makeHandle(a, vc));\n            b.add(this.makeHandle(a, yc));\n            b.add(this.makeHandle(a, Gc));\n            b.add(this.makeHandle(a, Cc));\n            b.add(this.makeHandle(a, dd));\n            b.add(this.makeHandle(a, fd));\n            b.add(this.makeHandle(a, gd));\n            b.add(this.makeHandle(a, ed))\n        } else if (yg(b), b = b.copy(), null === b) return null;\n        b.adornedObject = a;\n        return b\n    };\n    vg.prototype.makeHandle = function (a, b) {\n        a = this.handleArchetype;\n        if (null === a) return null;\n        a = a.copy();\n        a.alignment = b;\n        return a\n    };\n    vg.prototype.updateResizeHandles = function (a, b) {\n        if (null !== a)\n            if (!a.alignment.Mb() && (\"pointer\" === a.cursor || 0 < a.cursor.indexOf(\"resize\"))) a: {\n                var c = a.alignment;c.jc() && (c = Ac);\n                if (0 >= c.x) b = 0 >= c.y ? b + 225 : 1 <= c.y ? b + 135 : b + 180;\n                else if (1 <= c.x) 0 >= c.y ? b += 315 : 1 <= c.y && (b += 45);\n                else if (0 >= c.y) b += 270;\n                else if (1 <= c.y) b += 90;\n                else break a;0 > b ? b += 360 : 360 <= b && (b -= 360);a.cursor = 22.5 > b ? \"e-resize\" : 67.5 > b ? \"se-resize\" : 112.5 > b ? \"s-resize\" : 157.5 > b ? \"sw-resize\" : 202.5 > b ? \"w-resize\" : 247.5 > b ? \"nw-resize\" : 292.5 > b ? \"n-resize\" : 337.5 > b ? \"ne-resize\" : \"e-resize\"\n            }\n        else if (a instanceof X)\n            for (a = a.elements; a.next();) this.updateResizeHandles(a.value, b)\n    };\n    vg.prototype.canStart = function () {\n        if (!this.isEnabled) return !1;\n        var a = this.diagram;\n        return !a.isReadOnly && a.allowResize && a.lastInput.left ? null !== this.findToolHandleAt(a.firstInput.documentPoint, this.name) : !1\n    };\n    vg.prototype.doActivate = function () {\n        var a = this.diagram;\n        null === this.handle && (this.handle = this.findToolHandleAt(a.firstInput.documentPoint, this.name));\n        null !== this.handle && (this.adornedObject = this.handle.part.adornedObject, null !== this.adornedObject && (this.os.set(this.adornedObject.ga(this.handle.alignment.Pv())), this.Xo.set(this.adornedObject.part.location), this.ex.set(this.adornedObject.desiredSize), this.lu = this.computeCellSize(), this.nu = this.computeMinSize(), this.mu = this.computeMaxSize(), a.isMouseCaptured = !0, this.$w = a.animationManager.isEnabled, a.animationManager.isEnabled = !1, this.ua(this.name), this.isActive = !0))\n    };\n    vg.prototype.doDeactivate = function () {\n        var a = this.diagram;\n        this.Hg();\n        this.ae = this.handle = null;\n        this.isActive = a.isMouseCaptured = !1;\n        a.animationManager.isEnabled = this.$w\n    };\n    vg.prototype.doCancel = function () {\n        null !== this.adornedObject && (this.adornedObject.desiredSize = this.originalDesiredSize, this.adornedObject.part.location = this.originalLocation);\n        this.stopTool()\n    };\n    vg.prototype.doMouseMove = function () {\n        var a = this.diagram;\n        if (this.isActive) {\n            var b = this.nu,\n                c = this.mu,\n                d = this.lu,\n                e = this.adornedObject.ot(a.lastInput.documentPoint, I.alloc()),\n                f = this.computeReshape();\n            b = this.computeResize(e, this.handle.alignment, b, c, d, f);\n            this.resize(b);\n            a.Wc();\n            I.free(e)\n        }\n    };\n    vg.prototype.doMouseUp = function () {\n        var a = this.diagram;\n        if (this.isActive) {\n            var b = this.nu,\n                c = this.mu,\n                d = this.lu,\n                e = this.adornedObject.ot(a.lastInput.documentPoint, I.alloc()),\n                f = this.computeReshape();\n            b = this.computeResize(e, this.handle.alignment, b, c, d, f);\n            this.resize(b);\n            I.free(e);\n            a.Na();\n            this.transactionResult = this.name;\n            a.R(\"PartResized\", this.adornedObject, this.originalDesiredSize)\n        }\n        this.stopTool()\n    };\n    vg.prototype.resize = function (a) {\n        var b = this.diagram,\n            c = this.adornedObject;\n        if (null !== c) {\n            c.desiredSize = a.size;\n            a = c.part;\n            a.yb();\n            c = c.ga(this.handle.alignment.Pv());\n            if (a instanceof T) {\n                var d = new E;\n                d.add(a);\n                b.moveParts(d, this.oppositePoint.copy().Zd(c), !0)\n            } else a.location = a.location.copy().Zd(c).add(this.oppositePoint);\n            b.Wc()\n        }\n    };\n    vg.prototype.computeResize = function (a, b, c, d, e, f) {\n        b.jc() && (b = Ac);\n        var g = this.adornedObject.naturalBounds,\n            h = g.x,\n            k = g.y,\n            l = g.x + g.width,\n            m = g.y + g.height,\n            n = 1;\n        if (!f) {\n            n = g.width;\n            var p = g.height;\n            0 >= n && (n = 1);\n            0 >= p && (p = 1);\n            n = p / n\n        }\n        p = I.alloc();\n        J.mq(a.x, a.y, h, k, e.width, e.height, p);\n        a = g.copy();\n        0 >= b.x ? 0 >= b.y ? (a.x = Math.max(p.x, l - d.width), a.x = Math.min(a.x, l - c.width), a.width = Math.max(l - a.x, c.width), a.y = Math.max(p.y, m - d.height), a.y = Math.min(a.y, m - c.height), a.height = Math.max(m - a.y, c.height), f || (1 <= a.height / a.width ? (a.height = Math.max(Math.min(n *\n            a.width, d.height), c.height), a.width = a.height / n) : (a.width = Math.max(Math.min(a.height / n, d.width), c.width), a.height = n * a.width), a.x = l - a.width, a.y = m - a.height)) : 1 <= b.y ? (a.x = Math.max(p.x, l - d.width), a.x = Math.min(a.x, l - c.width), a.width = Math.max(l - a.x, c.width), a.height = Math.max(Math.min(p.y - k, d.height), c.height), f || (1 <= a.height / a.width ? (a.height = Math.max(Math.min(n * a.width, d.height), c.height), a.width = a.height / n) : (a.width = Math.max(Math.min(a.height / n, d.width), c.width), a.height = n * a.width), a.x = l - a.width)) : (a.x =\n            Math.max(p.x, l - d.width), a.x = Math.min(a.x, l - c.width), a.width = l - a.x, f || (a.height = Math.max(Math.min(n * a.width, d.height), c.height), a.width = a.height / n, a.y = k + .5 * (m - k - a.height))) : 1 <= b.x ? 0 >= b.y ? (a.width = Math.max(Math.min(p.x - h, d.width), c.width), a.y = Math.max(p.y, m - d.height), a.y = Math.min(a.y, m - c.height), a.height = Math.max(m - a.y, c.height), f || (1 <= a.height / a.width ? (a.height = Math.max(Math.min(n * a.width, d.height), c.height), a.width = a.height / n) : (a.width = Math.max(Math.min(a.height / n, d.width), c.width), a.height = n * a.width),\n            a.y = m - a.height)) : 1 <= b.y ? (a.width = Math.max(Math.min(p.x - h, d.width), c.width), a.height = Math.max(Math.min(p.y - k, d.height), c.height), f || (1 <= a.height / a.width ? (a.height = Math.max(Math.min(n * a.width, d.height), c.height), a.width = a.height / n) : (a.width = Math.max(Math.min(a.height / n, d.width), c.width), a.height = n * a.width))) : (a.width = Math.max(Math.min(p.x - h, d.width), c.width), f || (a.height = Math.max(Math.min(n * a.width, d.height), c.height), a.width = a.height / n, a.y = k + .5 * (m - k - a.height))) : 0 >= b.y ? (a.y = Math.max(p.y, m - d.height),\n            a.y = Math.min(a.y, m - c.height), a.height = m - a.y, f || (a.width = Math.max(Math.min(a.height / n, d.width), c.width), a.height = n * a.width, a.x = h + .5 * (l - h - a.width))) : 1 <= b.y && (a.height = Math.max(Math.min(p.y - k, d.height), c.height), f || (a.width = Math.max(Math.min(a.height / n, d.width), c.width), a.height = n * a.width, a.x = h + .5 * (l - h - a.width)));\n        I.free(p);\n        return a\n    };\n    vg.prototype.computeReshape = function () {\n        var a = zg;\n        this.adornedObject instanceof Lf && (a = Ag(this.adornedObject));\n        return !(a === Bg || this.diagram.lastInput.shift)\n    };\n    vg.prototype.computeMinSize = function () {\n        var a = this.adornedObject.minSize.copy(),\n            b = this.minSize;\n        !isNaN(b.width) && b.width > a.width && (a.width = b.width);\n        !isNaN(b.height) && b.height > a.height && (a.height = b.height);\n        return a\n    };\n    vg.prototype.computeMaxSize = function () {\n        var a = this.adornedObject.maxSize.copy(),\n            b = this.maxSize;\n        !isNaN(b.width) && b.width < a.width && (a.width = b.width);\n        !isNaN(b.height) && b.height < a.height && (a.height = b.height);\n        return a\n    };\n    vg.prototype.computeCellSize = function () {\n        var a = new M(NaN, NaN),\n            b = this.adornedObject.part;\n        null !== b && (b = b.resizeCellSize, !isNaN(b.width) && 0 < b.width && (a.width = b.width), !isNaN(b.height) && 0 < b.height && (a.height = b.height));\n        b = this.cellSize;\n        isNaN(a.width) && !isNaN(b.width) && 0 < b.width && (a.width = b.width);\n        isNaN(a.height) && !isNaN(b.height) && 0 < b.height && (a.height = b.height);\n        b = this.diagram;\n        (isNaN(a.width) || isNaN(a.height)) && b && (b = b.grid, null !== b && b.visible && this.isGridSnapEnabled && (b = b.gridCellSize, isNaN(a.width) &&\n            !isNaN(b.width) && 0 < b.width && (a.width = b.width), isNaN(a.height) && !isNaN(b.height) && 0 < b.height && (a.height = b.height)));\n        if (isNaN(a.width) || 0 === a.width || Infinity === a.width) a.width = 1;\n        if (isNaN(a.height) || 0 === a.height || Infinity === a.height) a.height = 1;\n        return a\n    };\n    ma.Object.defineProperties(vg.prototype, {\n        handleArchetype: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a\n            }\n        },\n        handle: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                if (null !== a && !(a.part instanceof Je)) throw Error(\"new handle is not in an Adornment: \" + a);\n                this.l = a\n            }\n        },\n        adornedObject: {\n            get: function () {\n                return this.ae\n            },\n            set: function (a) {\n                if (null !== a && a.part instanceof Je) throw Error(\"new handle must not be in an Adornment: \" +\n                    a);\n                this.ae = a\n            }\n        },\n        minSize: {\n            get: function () {\n                return this.eg\n            },\n            set: function (a) {\n                if (!this.eg.w(a)) {\n                    var b = a.width;\n                    isNaN(b) && (b = 0);\n                    a = a.height;\n                    isNaN(a) && (a = 0);\n                    this.eg.h(b, a)\n                }\n            }\n        },\n        maxSize: {\n            get: function () {\n                return this.dg\n            },\n            set: function (a) {\n                if (!this.dg.w(a)) {\n                    var b = a.width;\n                    isNaN(b) && (b = Infinity);\n                    a = a.height;\n                    isNaN(a) && (a = Infinity);\n                    this.dg.h(b, a)\n                }\n            }\n        },\n        cellSize: {\n            get: function () {\n                return this.Ng\n            },\n            set: function (a) {\n                this.Ng.w(a) || this.Ng.assign(a)\n            }\n        },\n        isGridSnapEnabled: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I = a\n            }\n        },\n        oppositePoint: {\n            get: function () {\n                return this.os\n            },\n            set: function (a) {\n                this.os.w(a) || this.os.assign(a)\n            }\n        },\n        originalDesiredSize: {\n            get: function () {\n                return this.ex\n            }\n        },\n        originalLocation: {\n            get: function () {\n                return this.Xo\n            }\n        }\n    });\n    vg.className = \"ResizingTool\";\n    La(\"resizingTool\", function () {\n        return this.findTool(\"Resizing\")\n    }, function (a) {\n        this.Va(\"Resizing\", a, this.mouseDownTools)\n    });\n\n    function Cg() {\n        ye.call(this);\n        this.name = \"Rotating\";\n        this.Ia = 45;\n        this.Ha = 2;\n        this.Xo = new I;\n        this.ae = null;\n        var a = new Lf;\n        a.figure = \"Ellipse\";\n        a.desiredSize = Nb;\n        a.fill = \"lightblue\";\n        a.stroke = \"dodgerblue\";\n        a.strokeWidth = 1;\n        a.cursor = \"pointer\";\n        this.u = a;\n        this.l = null;\n        this.bx = 0;\n        this.Lu = new I(NaN, NaN);\n        this.I = 0;\n        this.Y = 50\n    }\n    la(Cg, ye);\n    Cg.prototype.updateAdornments = function (a) {\n        if (null !== a) {\n            if (a.Kh()) {\n                var b = a.rotateObject;\n                if (b === a || b === a.path || b.isPanelMain) return\n            }\n            if (a.isSelected && !this.diagram.isReadOnly && (b = a.rotateObject, null !== b && a.canRotate() && a.actualBounds.v() && a.isVisible() && b.actualBounds.v() && b.zf())) {\n                var c = a.fk(this.name);\n                if (null === c || c.adornedObject !== b) c = this.makeAdornment(b);\n                if (null !== c) {\n                    c.angle = b.Xi();\n                    null === c.placeholder && (c.location = this.computeAdornmentLocation(b));\n                    a.Ch(this.name, c);\n                    return\n                }\n            }\n            a.Af(this.name)\n        }\n    };\n    Cg.prototype.makeAdornment = function (a) {\n        var b = a.part.rotateAdornmentTemplate;\n        if (null === b) {\n            b = new Je;\n            b.type = X.Position;\n            b.locationSpot = Ac;\n            var c = this.handleArchetype;\n            null !== c && b.add(c.copy())\n        } else if (yg(b), b = b.copy(), null === b) return null;\n        b.adornedObject = a;\n        return b\n    };\n    Cg.prototype.canStart = function () {\n        if (!this.isEnabled) return !1;\n        var a = this.diagram;\n        return !a.isReadOnly && a.allowRotate && a.lastInput.left ? null !== this.findToolHandleAt(a.firstInput.documentPoint, this.name) : !1\n    };\n    Cg.prototype.doActivate = function () {\n        var a = this.diagram;\n        if (null === this.adornedObject) {\n            null === this.handle && (this.handle = this.findToolHandleAt(a.firstInput.documentPoint, this.name));\n            if (null === this.handle) return;\n            this.adornedObject = this.handle.part.adornedObject\n        }\n        null !== this.adornedObject && (this.bx = this.adornedObject.angle, this.Lu = this.computeRotationPoint(this.adornedObject), this.Xo = this.adornedObject.part.location.copy(), a.isMouseCaptured = !0, a.delaysLayout = !0, this.ua(this.name), this.isActive = !0)\n    };\n    Cg.prototype.computeRotationPoint = function (a) {\n        var b = a.part,\n            c = b.locationObject;\n        return b.rotationSpot.eb() ? a.ga(b.rotationSpot) : a === b || a === c ? c.ga(b.locationSpot) : a.ga(Ac)\n    };\n    Cg.prototype.computeAdornmentLocation = function (a) {\n        var b = this.rotationPoint;\n        b.v() || (b = this.computeRotationPoint(a));\n        b = a.ot(b);\n        var c = this.handleAngle;\n        0 > c ? c += 360 : 360 <= c && (c -= 360);\n        c = Math.round(45 * Math.round(c / 45));\n        var d = this.handleDistance;\n        0 === c ? b.x = a.naturalBounds.width + d : 45 === c ? (b.x = a.naturalBounds.width + d, b.y = a.naturalBounds.height + d) : 90 === c ? b.y = a.naturalBounds.height + d : 135 === c ? (b.x = -d, b.y = a.naturalBounds.height + d) : 180 === c ? b.x = -d : 225 === c ? (b.x = -d, b.y = -d) : 270 === c ? b.y = -d : 315 === c && (b.x = a.naturalBounds.width +\n            d, b.y = -d);\n        return a.ga(b)\n    };\n    Cg.prototype.doDeactivate = function () {\n        var a = this.diagram;\n        this.Hg();\n        this.ae = this.handle = null;\n        this.Lu = new I(NaN, NaN);\n        this.isActive = a.isMouseCaptured = !1\n    };\n    Cg.prototype.doCancel = function () {\n        this.diagram.delaysLayout = !1;\n        this.rotate(this.originalAngle);\n        this.stopTool()\n    };\n    Cg.prototype.doMouseMove = function () {\n        var a = this.diagram;\n        this.isActive && (a = this.computeRotate(a.lastInput.documentPoint), this.rotate(a))\n    };\n    Cg.prototype.doMouseUp = function () {\n        var a = this.diagram;\n        if (this.isActive) {\n            a.delaysLayout = !1;\n            var b = this.computeRotate(a.lastInput.documentPoint);\n            this.rotate(b);\n            a.Na();\n            this.transactionResult = this.name;\n            a.R(\"PartRotated\", this.adornedObject, this.originalAngle)\n        }\n        this.stopTool()\n    };\n    Cg.prototype.rotate = function (a) {\n        var b = this.adornedObject;\n        if (null !== b) {\n            b.angle = a;\n            b = b.part;\n            b.yb();\n            var c = b.locationObject,\n                d = b.rotateObject;\n            if (c === d || c.Dg(d)) c = this.Xo.copy(), b.location = c.Zd(this.rotationPoint).rotate(a - this.originalAngle).add(this.rotationPoint);\n            this.diagram.Wc()\n        }\n    };\n    Cg.prototype.computeRotate = function (a) {\n        a = this.rotationPoint.Ta(a) - this.handleAngle;\n        var b = this.adornedObject.panel;\n        null !== b && (a -= b.Xi());\n        360 <= a ? a -= 360 : 0 > a && (a += 360);\n        b = Math.min(Math.abs(this.snapAngleMultiple), 180);\n        var c = Math.min(Math.abs(this.snapAngleEpsilon), b / 2);\n        !this.diagram.lastInput.shift && 0 < b && 0 < c && (a % b < c ? a = Math.floor(a / b) * b : a % b > b - c && (a = (Math.floor(a / b) + 1) * b));\n        360 <= a ? a -= 360 : 0 > a && (a += 360);\n        return a\n    };\n    ma.Object.defineProperties(Cg.prototype, {\n        handleArchetype: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a\n            }\n        },\n        handle: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                if (null !== a && !(a.part instanceof Je)) throw Error(\"new handle is not in an Adornment: \" + a);\n                this.l = a\n            }\n        },\n        adornedObject: {\n            get: function () {\n                return this.ae\n            },\n            set: function (a) {\n                if (null !== a && a.part instanceof Je) throw Error(\"new handle must not be in an Adornment: \" +\n                    a);\n                this.ae = a\n            }\n        },\n        snapAngleMultiple: {\n            get: function () {\n                return this.Ia\n            },\n            set: function (a) {\n                this.Ia = a\n            }\n        },\n        snapAngleEpsilon: {\n            get: function () {\n                return this.Ha\n            },\n            set: function (a) {\n                this.Ha = a\n            }\n        },\n        originalAngle: {\n            get: function () {\n                return this.bx\n            }\n        },\n        rotationPoint: {\n            get: function () {\n                return this.Lu\n            }\n        },\n        handleAngle: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I = a\n            }\n        },\n        handleDistance: {\n            get: function () {\n                return this.Y\n            },\n            set: function (a) {\n                this.Y = a\n            }\n        }\n    });\n    Cg.className = \"RotatingTool\";\n    La(\"rotatingTool\", function () {\n        return this.findTool(\"Rotating\")\n    }, function (a) {\n        this.Va(\"Rotating\", a, this.mouseDownTools)\n    });\n\n    function Dg() {\n        ye.call(this);\n        this.name = \"ClickSelecting\"\n    }\n    la(Dg, ye);\n    Dg.prototype.canStart = function () {\n        return !this.isEnabled || this.isBeyondDragSize() ? !1 : !0\n    };\n    Dg.prototype.doMouseUp = function () {\n        this.isActive && (this.standardMouseSelect(), !this.standardMouseClick() && this.diagram.lastInput.isTouchEvent && this.diagram.toolManager.doToolTip());\n        this.stopTool()\n    };\n    Dg.className = \"ClickSelectingTool\";\n\n    function Eg() {\n        ye.call(this);\n        this.name = \"Action\";\n        this.Bk = null\n    }\n    la(Eg, ye);\n    Eg.prototype.canStart = function () {\n        if (!this.isEnabled) return !1;\n        var a = this.diagram,\n            b = a.lastInput,\n            c = a.Ub(b.documentPoint, function (a) {\n                for (; null !== a.panel && !a.isActionable;) a = a.panel;\n                return a\n            });\n        if (null !== c) {\n            if (!c.isActionable) return !1;\n            this.Bk = c;\n            a.mj = a.Ub(b.documentPoint, null, null);\n            return !0\n        }\n        return !1\n    };\n    Eg.prototype.doMouseDown = function () {\n        if (this.isActive) {\n            var a = this.diagram.lastInput,\n                b = this.Bk;\n            null !== b && (a.targetObject = b, null !== b.actionDown && b.actionDown(a, b))\n        } else this.canStart() && this.doActivate()\n    };\n    Eg.prototype.doMouseMove = function () {\n        if (this.isActive) {\n            var a = this.diagram.lastInput,\n                b = this.Bk;\n            null !== b && (a.targetObject = b, null !== b.actionMove && b.actionMove(a, b))\n        }\n    };\n    Eg.prototype.doMouseUp = function () {\n        if (this.isActive) {\n            var a = this.diagram.lastInput,\n                b = this.Bk;\n            if (null === b) return;\n            a.targetObject = b;\n            null !== b.actionUp && b.actionUp(a, b);\n            this.standardMouseClick(function (a) {\n                for (; null !== a.panel && (!a.isActionable || a !== b);) a = a.panel;\n                return a\n            }, function (a) {\n                return a === b\n            })\n        }\n        this.stopTool()\n    };\n    Eg.prototype.doCancel = function () {\n        var a = this.diagram.lastInput,\n            b = this.Bk;\n        null !== b && (a.targetObject = b, null !== b.actionCancel && b.actionCancel(a, b), this.stopTool())\n    };\n    Eg.prototype.doStop = function () {\n        this.Bk = null\n    };\n    Eg.className = \"ActionTool\";\n\n    function Fg() {\n        ye.call(this);\n        this.name = \"ClickCreating\";\n        this.ij = null;\n        this.u = !0;\n        this.l = !1;\n        this.Uw = new I(0, 0)\n    }\n    la(Fg, ye);\n    Fg.prototype.canStart = function () {\n        if (!this.isEnabled || null === this.archetypeNodeData) return !1;\n        var a = this.diagram;\n        if (a.isReadOnly || a.isModelReadOnly || !a.allowInsert || !a.lastInput.left || this.isBeyondDragSize()) return !1;\n        if (this.isDoubleClick) {\n            if (1 === a.lastInput.clickCount && (this.Uw = a.lastInput.viewPoint.copy()), 2 !== a.lastInput.clickCount || this.isBeyondDragSize(this.Uw)) return !1\n        } else if (1 !== a.lastInput.clickCount) return !1;\n        return a.currentTool !== this && null !== a.jm(a.lastInput.documentPoint, !0) ? !1 : !0\n    };\n    Fg.prototype.doMouseUp = function () {\n        var a = this.diagram;\n        this.isActive && this.insertPart(a.lastInput.documentPoint);\n        this.stopTool()\n    };\n    Fg.prototype.insertPart = function (a) {\n        var b = this.diagram,\n            c = this.archetypeNodeData;\n        if (null === c) return null;\n        var d = null;\n        try {\n            b.R(\"ChangingSelection\", b.selection);\n            this.ua(this.name);\n            if (c instanceof U) c.Wb() && (yg(c), d = c.copy(), null !== d && b.add(d));\n            else if (null !== c) {\n                var e = b.model.copyNodeData(c);\n                za(e) && (b.model.pf(e), d = b.wc(e))\n            }\n            if (null !== d) {\n                var f = I.allocAt(a.x, a.y);\n                this.isGridSnapEnabled && Gg(this.diagram, d, a, f);\n                d.location = f;\n                b.allowSelect && (b.clearSelection(!0), d.isSelected = !0);\n                I.free(f)\n            }\n            b.Na();\n            this.transactionResult =\n                this.name;\n            b.R(\"PartCreated\", d)\n        } finally {\n            this.Hg(), b.R(\"ChangedSelection\", b.selection)\n        }\n        return d\n    };\n    ma.Object.defineProperties(Fg.prototype, {\n        archetypeNodeData: {\n            get: function () {\n                return this.ij\n            },\n            set: function (a) {\n                this.ij = a\n            }\n        },\n        isDoubleClick: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a\n            }\n        },\n        isGridSnapEnabled: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l = a\n            }\n        }\n    });\n    Fg.className = \"ClickCreatingTool\";\n\n    function Hg() {\n        ye.call(this);\n        this.name = \"DragSelecting\";\n        this.Vk = 175;\n        this.u = !1;\n        var a = new U;\n        a.layerName = \"Tool\";\n        a.selectable = !1;\n        var b = new Lf;\n        b.name = \"SHAPE\";\n        b.figure = \"Rectangle\";\n        b.fill = null;\n        b.stroke = \"magenta\";\n        a.add(b);\n        this.l = a\n    }\n    la(Hg, ye);\n    Hg.prototype.canStart = function () {\n        if (!this.isEnabled) return !1;\n        var a = this.diagram;\n        if (!a.allowSelect) return !1;\n        var b = a.lastInput;\n        return !b.left || a.currentTool !== this && (!this.isBeyondDragSize() || b.timestamp - a.firstInput.timestamp < this.delay || null !== a.jm(b.documentPoint, !0)) ? !1 : !0\n    };\n    Hg.prototype.doActivate = function () {\n        var a = this.diagram;\n        this.isActive = !0;\n        a.isMouseCaptured = !0;\n        a.skipsUndoManager = !0;\n        a.add(this.box);\n        this.doMouseMove()\n    };\n    Hg.prototype.doDeactivate = function () {\n        var a = this.diagram;\n        a.Cf();\n        a.remove(this.box);\n        a.skipsUndoManager = !1;\n        this.isActive = a.isMouseCaptured = !1\n    };\n    Hg.prototype.doMouseMove = function () {\n        var a = this.diagram;\n        if (this.isActive && null !== this.box) {\n            var b = this.computeBoxBounds(),\n                c = this.box.Xa(\"SHAPE\");\n            null === c && (c = this.box.zb());\n            var d = M.alloc().h(b.width, b.height);\n            b = I.allocAt(b.x, b.y);\n            c.desiredSize = d;\n            this.box.position = b;\n            M.free(d);\n            I.free(b);\n            (a.allowHorizontalScroll || a.allowVerticalScroll) && a.gt(a.lastInput.viewPoint)\n        }\n    };\n    Hg.prototype.doMouseUp = function () {\n        if (this.isActive) {\n            var a = this.diagram;\n            a.remove(this.box);\n            try {\n                a.currentCursor = \"wait\", a.R(\"ChangingSelection\", a.selection), this.selectInRect(this.computeBoxBounds()), a.R(\"ChangedSelection\", a.selection)\n            } finally {\n                a.currentCursor = \"\"\n            }\n        }\n        this.stopTool()\n    };\n    Hg.prototype.computeBoxBounds = function () {\n        var a = this.diagram;\n        return new N(a.firstInput.documentPoint, a.lastInput.documentPoint)\n    };\n    Hg.prototype.selectInRect = function (a) {\n        var b = this.diagram,\n            c = b.lastInput;\n        a = b.Mx(a, this.isPartialInclusion);\n        if (Wa ? c.meta : c.control)\n            if (c.shift)\n                for (a = a.iterator; a.next();) b = a.value, b.isSelected && (b.isSelected = !1);\n            else\n                for (a = a.iterator; a.next();) b = a.value, b.isSelected = !b.isSelected;\n        else if (c.shift)\n            for (a = a.iterator; a.next();) b = a.value, b.isSelected || (b.isSelected = !0);\n        else {\n            c = new E;\n            for (b = b.selection.iterator; b.next();) {\n                var d = b.value;\n                a.contains(d) || c.add(d)\n            }\n            for (b = c.iterator; b.next();) b.value.isSelected = !1;\n            for (a =\n                a.iterator; a.next();) b = a.value, b.isSelected || (b.isSelected = !0)\n        }\n    };\n    ma.Object.defineProperties(Hg.prototype, {\n        delay: {\n            get: function () {\n                return this.Vk\n            },\n            set: function (a) {\n                this.Vk = a\n            }\n        },\n        isPartialInclusion: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a\n            }\n        },\n        box: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l = a\n            }\n        }\n    });\n    Hg.className = \"DragSelectingTool\";\n\n    function Ig() {\n        ye.call(this);\n        this.name = \"Panning\";\n        this.Iu = new I;\n        this.Dy = new I;\n        this.Mg = !1;\n        var a = this;\n        this.kx = function () {\n            var b = a.diagram;\n            null !== b && b.removeEventListener(x.document, \"scroll\", a.kx, !1);\n            a.stopTool()\n        }\n    }\n    la(Ig, ye);\n    Ig.prototype.canStart = function () {\n        if (!this.isEnabled) return !1;\n        var a = this.diagram;\n        return !a.allowHorizontalScroll && !a.allowVerticalScroll || !a.lastInput.left || a.currentTool !== this && !this.isBeyondDragSize() ? !1 : !0\n    };\n    Ig.prototype.doActivate = function () {\n        var a = this.diagram;\n        this.Mg ? (a.lastInput.bubbles = !0, a.addEventListener(x.document, \"scroll\", this.kx, !1)) : (a.currentCursor = \"move\", a.isMouseCaptured = !0, this.Iu.assign(a.position));\n        this.isActive = !0\n    };\n    Ig.prototype.doDeactivate = function () {\n        var a = this.diagram;\n        a.currentCursor = \"\";\n        this.isActive = a.isMouseCaptured = !1\n    };\n    Ig.prototype.doCancel = function () {\n        var a = this.diagram;\n        a.position = this.Iu;\n        a.isMouseCaptured = !1;\n        this.stopTool()\n    };\n    Ig.prototype.doMouseMove = function () {\n        this.move()\n    };\n    Ig.prototype.doMouseUp = function () {\n        this.move();\n        this.stopTool()\n    };\n    Ig.prototype.move = function () {\n        var a = this.diagram;\n        if (this.isActive && a)\n            if (this.Mg) a.lastInput.bubbles = !0;\n            else {\n                var b = a.position,\n                    c = a.firstInput.documentPoint,\n                    d = a.lastInput.documentPoint,\n                    e = b.x + c.x - d.x;\n                c = b.y + c.y - d.y;\n                a.allowHorizontalScroll || (e = b.x);\n                a.allowVerticalScroll || (c = b.y);\n                a.position = this.Dy.h(e, c)\n            }\n    };\n    ma.Object.defineProperties(Ig.prototype, {\n        bubbles: {\n            get: function () {\n                return this.Mg\n            },\n            set: function (a) {\n                this.Mg = a\n            }\n        },\n        originalPosition: {\n            get: function () {\n                return this.Iu\n            }\n        }\n    });\n    Ig.className = \"PanningTool\";\n    La(\"clickCreatingTool\", function () {\n        return this.findTool(\"ClickCreating\")\n    }, function (a) {\n        this.Va(\"ClickCreating\", a, this.mouseUpTools)\n    });\n    La(\"clickSelectingTool\", function () {\n        return this.findTool(\"ClickSelecting\")\n    }, function (a) {\n        this.Va(\"ClickSelecting\", a, this.mouseUpTools)\n    });\n    La(\"panningTool\", function () {\n        return this.findTool(\"Panning\")\n    }, function (a) {\n        this.Va(\"Panning\", a, this.mouseMoveTools)\n    });\n    La(\"dragSelectingTool\", function () {\n        return this.findTool(\"DragSelecting\")\n    }, function (a) {\n        this.Va(\"DragSelecting\", a, this.mouseMoveTools)\n    });\n    La(\"actionTool\", function () {\n        return this.findTool(\"Action\")\n    }, function (a) {\n        this.Va(\"Action\", a, this.mouseDownTools)\n    });\n\n    function Oe() {\n        this.Y = this.I = this.l = this.u = null\n    }\n    ma.Object.defineProperties(Oe.prototype, {\n        mainElement: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I = a\n            }\n        },\n        show: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u !== a && (this.u = a)\n            }\n        },\n        hide: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l !== a && (this.l = a)\n            }\n        },\n        valueFunction: {\n            get: function () {\n                return this.Y\n            },\n            set: function (a) {\n                this.Y = a\n            }\n        }\n    });\n    Oe.className = \"HTMLInfo\";\n\n    function Jg(a, b, c) {\n        this.text = a;\n        this.Ax = b;\n        this.visible = c\n    }\n    Jg.className = \"ContextMenuButtonInfo\";\n\n    function Kg() {\n        ye.call(this);\n        this.name = \"ContextMenu\";\n        this.u = this.cu = this.l = null;\n        this.Zw = new I;\n        this.du = null;\n        this.xu = !1;\n        var a = this;\n        this.Wu = function () {\n            a.stopTool()\n        }\n    }\n    la(Kg, ye);\n\n    function Lg(a) {\n        var b = new Oe;\n        b.show = function (a, b, c) {\n            c.showDefaultContextMenu()\n        };\n        b.hide = function (a, b) {\n            b.hideDefaultContextMenu()\n        };\n        Mg = b;\n        a.Wu = function () {\n            a.stopTool()\n        };\n        b = ta(\"div\");\n        var c = ta(\"div\");\n        b.style.cssText = \"top: 0px;z-index:10002;position: fixed;display: none;text-align: center;left: 25%;width: 50%;background-color: #F5F5F5;padding: 16px;border: 16px solid #444;border-radius: 10px;margin-top: 10px\";\n        c.style.cssText = \"z-index:10001;position: fixed;display: none;top: 0;left: 0;width: 100%;height: 100%;background-color: black;opacity: 0.8;\";\n        var d = ta(\"style\");\n        x.document.getElementsByTagName(\"head\")[0].appendChild(d);\n        d.sheet.insertRule(\".goCXul { list-style: none; }\", 0);\n        d.sheet.insertRule(\".goCXli {font:700 1.5em Helvetica, Arial, sans-serif;position: relative;min-width: 60px; }\", 0);\n        d.sheet.insertRule(\".goCXa {color: #444;display: inline-block;padding: 4px;text-decoration: none;margin: 2px;border: 1px solid gray;border-radius: 10px; }\", 0);\n        d = a.diagram;\n        null !== d && (d.addEventListener(b, \"contextmenu\", Ng, !1), d.addEventListener(b, \"selectstart\",\n            Ng, !1), d.addEventListener(c, \"contextmenu\", Ng, !1));\n        b.className = \"goCXforeground\";\n        c.className = \"goCXbackground\";\n        x.document.body && (x.document.body.appendChild(b), x.document.body.appendChild(c));\n        Og = b;\n        Pg = c;\n        Qg = !0\n    }\n\n    function Ng(a) {\n        a.preventDefault();\n        return !1\n    }\n    Kg.prototype.canStart = function () {\n        if (!this.isEnabled) return !1;\n        var a = this.diagram;\n        return this.isBeyondDragSize() || !a.lastInput.right ? !1 : a.lastInput.isTouchEvent && null !== this.defaultTouchContextMenu || null !== this.findObjectWithContextMenu() ? !0 : !1\n    };\n    Kg.prototype.doStart = function () {\n        this.Zw.set(this.diagram.firstInput.documentPoint)\n    };\n    Kg.prototype.doStop = function () {\n        this.hideContextMenu();\n        this.currentObject = null\n    };\n    Kg.prototype.findObjectWithContextMenu = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram,\n            c = b.lastInput,\n            d = null;\n        a instanceof R || (a instanceof Y ? d = a : d = b.Ub(c.documentPoint, null, function (a) {\n            return !a.layer.isTemporary\n        }));\n        if (null !== d) {\n            for (a = d; null !== a;) {\n                if (null !== a.contextMenu) return a;\n                a = a.panel\n            }\n            if (b.lastInput.isTouchEvent && this.defaultTouchContextMenu) return d.part\n        } else if (null !== b.contextMenu) return b;\n        return null\n    };\n    Kg.prototype.doActivate = function () {};\n    Kg.prototype.doMouseDown = function () {\n        ye.prototype.doMouseDown.call(this);\n        if (this.isActive && this.currentContextMenu instanceof Je) {\n            var a = this.diagram.toolManager.findTool(\"Action\");\n            null !== a && a.canStart() && (a.doActivate(), a.doMouseDown(), a.doDeactivate())\n        }\n        this.diagram.toolManager.mouseDownTools.contains(this) && Rg(this)\n    };\n    Kg.prototype.doMouseUp = function () {\n        if (this.isActive && this.currentContextMenu instanceof Je) {\n            var a = this.diagram.toolManager.findTool(\"Action\");\n            null !== a && a.canStart() && (a.doActivate(), a.doCancel(), a.doDeactivate())\n        }\n        Rg(this)\n    };\n\n    function Rg(a) {\n        var b = a.diagram;\n        if (a.isActive) {\n            var c = a.currentContextMenu;\n            if (null !== c) {\n                if (!(c instanceof Oe)) {\n                    var d = b.Ub(b.lastInput.documentPoint, null, null);\n                    null !== d && d.Dg(c) && a.standardMouseClick(null, null)\n                }\n                a.stopTool();\n                a.canStart() && (b.currentTool = a, a.doMouseUp())\n            }\n        } else a.canStart() && (Sg(a, !0), a.isActive || a.stopTool())\n    }\n\n    function Sg(a, b, c) {\n        void 0 === c && (c = null);\n        if (!a.xu && (a.xu = !0, b && a.standardMouseSelect(), b = a.standardMouseClick(), a.xu = !1, !b))\n            if (a.isActive = !0, b = Mg, null === c && (c = a.findObjectWithContextMenu()), null !== c) {\n                var d = c.contextMenu;\n                null !== d ? (a.currentObject = c instanceof Y ? c : null, a.showContextMenu(d, a.currentObject)) : null !== b && a.showContextMenu(b, a.currentObject)\n            } else null !== b && a.showContextMenu(b, null)\n    }\n    Kg.prototype.doMouseMove = function () {\n        var a = this.diagram.toolManager.findTool(\"Action\");\n        null !== a && a.doMouseMove();\n        this.isActive && this.diagram.toolManager.doMouseMove()\n    };\n    Kg.prototype.showContextMenu = function (a, b) {\n        var c = this.diagram;\n        a !== this.currentContextMenu && this.hideContextMenu();\n        if (a instanceof Je) {\n            a.layerName = \"Tool\";\n            a.selectable = !1;\n            a.scale = 1 / c.scale;\n            a.category = this.name;\n            null !== a.placeholder && (a.placeholder.scale = c.scale);\n            var d = a.diagram;\n            null !== d && d !== c && d.remove(a);\n            c.add(a);\n            null !== b ? a.adornedObject = b : a.data = c.model;\n            a.yb();\n            this.positionContextMenu(a, b)\n        } else a instanceof Oe && a.show(b, c, this);\n        this.currentContextMenu = a\n    };\n    Kg.prototype.positionContextMenu = function (a) {\n        if (null === a.placeholder) {\n            var b = this.diagram,\n                c = b.lastInput.documentPoint.copy(),\n                d = a.measuredBounds,\n                e = b.viewportBounds;\n            b.lastInput.isTouchEvent && (c.x -= d.width);\n            c.x + d.width > e.right && (c.x -= d.width + 5 / b.scale);\n            c.x < e.x && (c.x = e.x);\n            c.y + d.height > e.bottom && (c.y -= d.height + 5 / b.scale);\n            c.y < e.y && (c.y = e.y);\n            a.position = c\n        }\n    };\n    Kg.prototype.hideContextMenu = function () {\n        var a = this.diagram,\n            b = this.currentContextMenu;\n        null !== b && (b instanceof Je ? (a.remove(b), null !== this.cu && this.cu.Af(b.category), b.data = null, b.adornedObject = null) : b instanceof Oe && (null !== b.hide ? b.hide(a, this) : null !== b.mainElement && (b.mainElement.style.display = \"none\")), this.currentContextMenu = null, this.standardMouseOver())\n    };\n\n    function Tg(a) {\n        var b = new E;\n        b.add(new Jg(\"Copy\", function (a) {\n            a.commandHandler.copySelection()\n        }, function (a) {\n            return a.commandHandler.canCopySelection()\n        }));\n        b.add(new Jg(\"Cut\", function (a) {\n            a.commandHandler.cutSelection()\n        }, function (a) {\n            return a.commandHandler.canCutSelection()\n        }));\n        b.add(new Jg(\"Delete\", function (a) {\n            a.commandHandler.deleteSelection()\n        }, function (a) {\n            return a.commandHandler.canDeleteSelection()\n        }));\n        b.add(new Jg(\"Paste\", function (b) {\n            b.commandHandler.pasteSelection(a.mouseDownPoint)\n        }, function (b) {\n            return b.commandHandler.canPasteSelection(a.mouseDownPoint)\n        }));\n        b.add(new Jg(\"Select All\", function (a) {\n            a.commandHandler.selectAll()\n        }, function (a) {\n            return a.commandHandler.canSelectAll()\n        }));\n        b.add(new Jg(\"Undo\", function (a) {\n            a.commandHandler.undo()\n        }, function (a) {\n            return a.commandHandler.canUndo()\n        }));\n        b.add(new Jg(\"Redo\", function (a) {\n            a.commandHandler.redo()\n        }, function (a) {\n            return a.commandHandler.canRedo()\n        }));\n        b.add(new Jg(\"Scroll To Part\", function (a) {\n            a.commandHandler.scrollToPart()\n        }, function (a) {\n            return a.commandHandler.canScrollToPart()\n        }));\n        b.add(new Jg(\"Zoom To Fit\", function (a) {\n                a.commandHandler.zoomToFit()\n            },\n            function (a) {\n                return a.commandHandler.canZoomToFit()\n            }));\n        b.add(new Jg(\"Reset Zoom\", function (a) {\n            a.commandHandler.resetZoom()\n        }, function (a) {\n            return a.commandHandler.canResetZoom()\n        }));\n        b.add(new Jg(\"Group Selection\", function (a) {\n            a.commandHandler.groupSelection()\n        }, function (a) {\n            return a.commandHandler.canGroupSelection()\n        }));\n        b.add(new Jg(\"Ungroup Selection\", function (a) {\n            a.commandHandler.ungroupSelection()\n        }, function (a) {\n            return a.commandHandler.canUngroupSelection()\n        }));\n        b.add(new Jg(\"Edit Text\", function (a) {\n                a.commandHandler.editTextBlock()\n            },\n            function (a) {\n                return a.commandHandler.canEditTextBlock()\n            }));\n        return b\n    }\n    Kg.prototype.showDefaultContextMenu = function () {\n        var a = this.diagram;\n        null === this.du && (this.du = Tg(this));\n        Og.innerHTML = \"\";\n        Pg.addEventListener(\"click\", this.Wu, !1);\n        var b = this,\n            c = ta(\"ul\");\n        c.className = \"goCXul\";\n        Og.appendChild(c);\n        c.innerHTML = \"\";\n        for (var d = this.du.iterator; d.next();) {\n            var e = d.value,\n                f = e.visible;\n            if (\"function\" === typeof e.Ax && (\"function\" !== typeof f || f(a))) {\n                f = ta(\"li\");\n                f.className = \"goCXli\";\n                var g = ta(\"a\");\n                g.className = \"goCXa\";\n                g.href = \"#\";\n                g.xy = e.Ax;\n                g.addEventListener(\"click\", function (c) {\n                    this.xy(a);\n                    b.stopTool();\n                    c.preventDefault();\n                    return !1\n                }, !1);\n                g.textContent = e.text;\n                f.appendChild(g);\n                c.appendChild(f)\n            }\n        }\n        Og.style.display = \"block\";\n        Pg.style.display = \"block\"\n    };\n    Kg.prototype.hideDefaultContextMenu = function () {\n        if (null !== this.currentContextMenu && this.currentContextMenu === Mg) {\n            Og.style.display = \"none\";\n            Pg.style.display = \"none\";\n            var a = this.diagram;\n            null !== a && a.removeEventListener(Pg, \"click\", this.Wu, !1);\n            this.currentContextMenu = null\n        }\n    };\n    ma.Object.defineProperties(Kg.prototype, {\n        currentContextMenu: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l = a;\n                this.cu = a instanceof Je ? a.adornedPart : null\n            }\n        },\n        defaultTouchContextMenu: {\n            get: function () {\n                !1 === Qg && null === Mg && Ug && Lg(this);\n                return Mg\n            },\n            set: function (a) {\n                null === a && (Qg = !0);\n                Mg = a\n            }\n        },\n        currentObject: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a\n            }\n        },\n        mouseDownPoint: {\n            get: function () {\n                return this.Zw\n            }\n        }\n    });\n    var Mg = null,\n        Qg = !1,\n        Pg = null,\n        Og = null;\n    Kg.className = \"ContextMenuTool\";\n    La(\"contextMenuTool\", function () {\n        return this.findTool(\"ContextMenu\")\n    }, function (a) {\n        this.Va(\"ContextMenu\", a, this.mouseUpTools)\n    });\n\n    function Vg() {\n        ye.call(this);\n        this.name = \"TextEditing\";\n        this.vh = new Wg;\n        this.Ia = null;\n        this.Ha = Xg;\n        this.Ji = null;\n        this.ia = Yg;\n        this.I = 1;\n        this.Y = !0;\n        this.u = null;\n        this.l = new Oe;\n        this.hu = null;\n        Zg(this, this.l)\n    }\n    la(Vg, ye);\n\n    function Zg(a, b) {\n        if (Ug) {\n            var c = ta(\"textarea\");\n            a.hu = c;\n            c.addEventListener(\"input\", function () {\n                if (null !== a.textBlock) {\n                    var b = a.Wx(this.value);\n                    this.style.width = 20 + b.measuredBounds.width * this.yA + \"px\";\n                    this.rows = b.lineCount\n                }\n            }, !1);\n            c.addEventListener(\"keydown\", function (b) {\n                if (null !== a.textBlock) {\n                    var c = b.which;\n                    13 === c ? (!1 === a.textBlock.isMultiline && b.preventDefault(), a.acceptText($g)) : 9 === c ? (a.acceptText(ah), b.preventDefault()) : 27 === c && (a.doCancel(), null !== a.diagram && a.diagram.doFocus())\n                }\n            }, !1);\n            c.addEventListener(\"focus\",\n                function () {\n                    if (null !== a.currentTextEditor && a.state !== Yg) {\n                        var b = a.hu;\n                        a.ia === bh && (a.ia = ch);\n                        \"function\" === typeof b.select && a.selectsTextOnActivate && (b.select(), b.setSelectionRange(0, 9999))\n                    }\n                }, !1);\n            c.addEventListener(\"blur\", function () {\n                if (null !== a.currentTextEditor && a.state !== Yg) {\n                    var b = a.hu;\n                    \"function\" === typeof b.focus && b.focus();\n                    \"function\" === typeof b.select && a.selectsTextOnActivate && (b.select(), b.setSelectionRange(0, 9999))\n                }\n            }, !1);\n            b.valueFunction = function () {\n                return c.value\n            };\n            b.mainElement = c;\n            b.show = function (a,\n                b, f) {\n                if (a instanceof Wg && f instanceof Vg)\n                    if (f.state === dh) c.style.border = \"3px solid red\", c.focus();\n                    else {\n                        var d = a.ga(Ac),\n                            e = b.position,\n                            k = b.scale,\n                            l = a.uf() * k;\n                        l < f.minimumEditorScale && (l = f.minimumEditorScale);\n                        var m = a.naturalBounds.width * l + 6,\n                            n = a.naturalBounds.height * l + 2,\n                            p = (d.x - e.x) * k;\n                        d = (d.y - e.y) * k;\n                        c.value = a.text;\n                        b.div.style.font = a.font;\n                        c.style.position = \"absolute\";\n                        c.style.zIndex = \"100\";\n                        c.style.font = \"inherit\";\n                        c.style.fontSize = 100 * l + \"%\";\n                        c.style.lineHeight = \"normal\";\n                        c.style.width = m + \"px\";\n                        c.style.left = (p - m / 2 | 0) - 1 +\n                            \"px\";\n                        c.style.top = (d - n / 2 | 0) - 1 + \"px\";\n                        c.style.textAlign = a.textAlign;\n                        c.style.margin = \"0\";\n                        c.style.padding = \"1px\";\n                        c.style.border = \"0\";\n                        c.style.outline = \"none\";\n                        c.style.whiteSpace = \"pre-wrap\";\n                        c.style.overflow = \"hidden\";\n                        c.rows = a.lineCount;\n                        c.yA = l;\n                        c.className = \"goTXarea\";\n                        b.div.appendChild(c);\n                        c.focus();\n                        f.selectsTextOnActivate && (c.select(), c.setSelectionRange(0, 9999))\n                    }\n            };\n            b.hide = function (a) {\n                a.div.removeChild(c)\n            }\n        }\n    }\n    Vg.prototype.canStart = function () {\n        if (!this.isEnabled) return !1;\n        var a = this.diagram;\n        if (null === a || a.isReadOnly || eh && eh !== this && (eh.acceptText(fh), eh && eh !== this) || !a.lastInput.left || this.isBeyondDragSize()) return !1;\n        var b = a.Ub(a.lastInput.documentPoint);\n        if (!(null !== b && b instanceof Wg && b.editable && b.part.canEdit())) return !1;\n        b = b.part;\n        return null === b || this.starting === Xg && !b.isSelected || this.starting === gh && 2 > a.lastInput.clickCount ? !1 : !0\n    };\n    Vg.prototype.doStart = function () {\n        eh = this;\n        null !== this.textBlock && this.doActivate()\n    };\n    Vg.prototype.doActivate = function () {\n        if (!this.isActive) {\n            var a = this.diagram;\n            if (null !== a) {\n                var b = this.textBlock;\n                null === b && (b = a.Ub(a.lastInput.documentPoint));\n                if (null !== b && b instanceof Wg && (this.textBlock = b, null !== b.part)) {\n                    this.isActive = !0;\n                    this.ia = bh;\n                    var c = this.defaultTextEditor;\n                    null !== b.textEditor && (c = b.textEditor);\n                    this.vh = this.textBlock.copy();\n                    var d = new N(this.textBlock.ga(vc), this.textBlock.ga(Gc));\n                    a.cw(d);\n                    c.show(b, a, this);\n                    this.currentTextEditor = c\n                }\n            }\n        }\n    };\n    Vg.prototype.doCancel = function () {\n        this.stopTool()\n    };\n    Vg.prototype.doMouseUp = function () {\n        this.canStart() && this.doActivate()\n    };\n    Vg.prototype.doMouseDown = function () {\n        this.isActive && this.acceptText(fh)\n    };\n    Vg.prototype.acceptText = function (a) {\n        switch (a) {\n            case fh:\n                if (this.ia === hh) this.currentTextEditor instanceof HTMLElement && this.currentTextEditor.focus();\n                else if (this.ia === bh || this.ia === dh || this.ia === ch) this.ia = ih, jh(this);\n                break;\n            case kh:\n            case $g:\n            case ah:\n                if ($g !== a || !0 !== this.textBlock.isMultiline)\n                    if (this.ia === bh || this.ia === dh || this.ia === ch) this.ia = ih, jh(this)\n        }\n    };\n\n    function jh(a) {\n        var b = a.textBlock,\n            c = a.diagram,\n            d = a.currentTextEditor;\n        if (null !== b && null !== d) {\n            var e = b.text,\n                f = \"\";\n            null !== d.valueFunction && (f = d.valueFunction());\n            if (a.isValidText(b, e, f)) a.ua(a.name), a.ia = hh, a.transactionResult = a.name, b.text = f, d = a.textBlock, null !== d.textEdited && d.textEdited(d, e, f), null !== c && c.R(\"TextEdited\", b, e), a.Hg(), a.stopTool(), null !== c && c.doFocus();\n            else {\n                a.ia = dh;\n                var g = a.textBlock;\n                null !== g.errorFunction && g.errorFunction(a, e, f);\n                d.show(b, c, a)\n            }\n        }\n    }\n    Vg.prototype.doDeactivate = function () {\n        var a = this.diagram;\n        null !== a && (this.ia = Yg, this.textBlock = null, null !== this.currentTextEditor && this.currentTextEditor.hide(a, this), this.isActive = !1)\n    };\n    Vg.prototype.doStop = function () {\n        eh = null\n    };\n    Vg.prototype.isValidText = function (a, b, c) {\n        var d = this.textValidation;\n        if (null !== d && !d(a, b, c)) return !1;\n        d = a.textValidation;\n        return null === d || d(a, b, c) ? !0 : !1\n    };\n    Vg.prototype.Wx = function (a) {\n        var b = this.vh;\n        b.text = a;\n        b.measure(this.textBlock.ti, Infinity);\n        return b\n    };\n    ma.Object.defineProperties(Vg.prototype, {\n        textBlock: {\n            get: function () {\n                return this.Ia\n            },\n            set: function (a) {\n                this.Ia = a\n            }\n        },\n        currentTextEditor: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a\n            }\n        },\n        defaultTextEditor: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l = a\n            }\n        },\n        starting: {\n            get: function () {\n                return this.Ha\n            },\n            set: function (a) {\n                this.Ha = a\n            }\n        },\n        textValidation: {\n            get: function () {\n                return this.Ji\n            },\n            set: function (a) {\n                this.Ji = a\n            }\n        },\n        minimumEditorScale: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I = a\n            }\n        },\n        selectsTextOnActivate: {\n            get: function () {\n                return this.Y\n            },\n            set: function (a) {\n                this.Y = a\n            }\n        },\n        state: {\n            get: function () {\n                return this.ia\n            },\n            set: function (a) {\n                this.ia !== a && (this.ia = a)\n            }\n        }\n    });\n    Vg.prototype.measureTemporaryTextBlock = Vg.prototype.Wx;\n    var kh = new D(Vg, \"LostFocus\", 0),\n        fh = new D(Vg, \"MouseDown\", 1),\n        ah = new D(Vg, \"Tab\", 2),\n        $g = new D(Vg, \"Enter\", 3),\n        th = new D(Vg, \"SingleClick\", 0),\n        Xg = new D(Vg, \"SingleClickSelected\", 1),\n        gh = new D(Vg, \"DoubleClick\", 2),\n        Yg = new D(Vg, \"StateNone\", 0),\n        bh = new D(Vg, \"StateActive\", 1),\n        ch = new D(Vg, \"StateEditing\", 2),\n        ih = new D(Vg, \"StateValidating\", 3),\n        dh = new D(Vg, \"StateInvalid\", 4),\n        hh = new D(Vg, \"StateValidated\", 5),\n        eh = null;\n    Vg.className = \"TextEditingTool\";\n    Vg.LostFocus = kh;\n    Vg.MouseDown = fh;\n    Vg.Tab = ah;\n    Vg.Enter = $g;\n    Vg.SingleClick = th;\n    Vg.SingleClickSelected = Xg;\n    Vg.DoubleClick = gh;\n    Vg.StateNone = Yg;\n    Vg.StateActive = bh;\n    Vg.StateEditing = ch;\n    Vg.StateValidating = ih;\n    Vg.StateInvalid = dh;\n    Vg.StateValidated = hh;\n    La(\"textEditingTool\", function () {\n        return this.findTool(\"TextEditing\")\n    }, function (a) {\n        this.Va(\"TextEditing\", a, this.mouseUpTools)\n    });\n\n    function uh() {\n        vh || (wh(), vh = !0);\n        this.B = ze;\n        this.gl = this.Ze = this.qc = this.Tr = this.hc = !1;\n        this.px = !0;\n        this.hl = xh;\n        this.bn = !1;\n        this.oi = this.Mc = !0;\n        this.Ug = 600;\n        this.Mw = this.ox = !1;\n        this.Ke = new F;\n        this.Ad = new yh;\n        this.Ad.Jc = this;\n        this.Ck = new F;\n        this.Tu = new F;\n        this.Ss = new F\n    }\n    uh.prototype.Yd = function (a) {\n        this.B = a\n    };\n    uh.prototype.canStart = function () {\n        return !0\n    };\n\n    function zh(a, b) {\n        Ah(a, b) && (a.Ze = !0)\n    }\n\n    function Ah(a, b) {\n        if (!a.Mc || !a.canStart(b)) return !1;\n        a.Ke.add(b);\n        a.defaultAnimation.isAnimating && a.Xc();\n        return a.qc = !0\n    }\n\n    function Bh(a) {\n        if (a.Mc && a.qc) {\n            var b = a.Ad,\n                c = a.B,\n                d = a.Ke.contains(\"Model\");\n            d && (a.gl = !0, a.hl === xh ? (b.isViewportUnconstrained = !0, b.pc.clear(), b.add(c, \"position\", c.position.copy().offset(0, -200), c.position), b.add(c, \"opacity\", 0, 1)) : a.hl === Ch && b.pc.clear(), c.R(\"InitialAnimationStarting\", a));\n            d && !a.oi || 0 === b.pc.count ? (a.Ke.clear(), a.qc = !1, a.Ze = !1, b.pc.clear(), Dh(b), a.gl = !1, c.M()) : (a.Ke.clear(), c.we = !1, x.requestAnimationFrame(function () {\n                !1 === a.qc || b.hc || (c.Be(\"temporaryPixelRatio\") && Ue(c), Eh(c), a.qc = !1, a.Ze = !1, a.px = d && a.hl === Fh && c.Nu.w(c.ma) ? !0 : !1, b.start(), Gh(a), c.Na(), Hh(b, 0), If(c, !0), Ih(a), c.R(\"AnimationStarting\", a))\n            }))\n        }\n    }\n\n    function Jh(a, b, c, d) {\n        b instanceof S && (null !== b.fromNode || null !== b.toNode) || a.Ad.add(b, \"position\", c, d, !1)\n    }\n    t = uh.prototype;\n    t.Dt = function (a) {\n        return this.Ad.Dt(a)\n    };\n    t.Gv = function (a) {\n        return this.Ad.Gv(a)\n    };\n\n    function Kh(a, b) {\n        function c() {\n            0 < e.Ss.count && (d.addAll(e.Ss), e.Ss.clear(), e.hc = !0);\n            if (!1 !== e.hc && 0 !== d.count) {\n                e.Tu.addAll(d);\n                for (var a = e.Tu.iterator; a.next();) {\n                    var b = a.value;\n                    if (!1 !== b.hc) {\n                        a: if (0 < b.Xl.count) var h = !0;\n                            else {\n                                for (h = b.pc.iterator; h.next();) {\n                                    var k = h.key;\n                                    if (k instanceof Y && null !== k.diagram || k instanceof R) {\n                                        h = !0;\n                                        break a\n                                    }\n                                }\n                                h = !1\n                            }h ? Lh(b, !1) : b.pl = !0\n                    }\n                }\n                e.Tu.clear();\n                Gh(e);\n                If(e.B);\n                Ih(e);\n                x.requestAnimationFrame(c)\n            }\n        }\n        var d = a.Ck,\n            e = a;\n        a.hc ? a.Ss.add(b) : (a.hc = !0, d.add(b), x.requestAnimationFrame(function () {\n            c()\n        }))\n    }\n\n    function Mh(a) {\n        for (a = a.Ck.iterator; a.next();) a.value.pl = !1\n    }\n\n    function Gh(a) {\n        if (!a.Tr) {\n            var b = a.B;\n            a.ox = b.skipsUndoManager;\n            a.Mw = b.skipsModelSourceBindings;\n            b.skipsUndoManager = !0;\n            b.skipsModelSourceBindings = !0;\n            a.Tr = !0\n        }\n    }\n\n    function Ih(a) {\n        var b = a.B;\n        b.skipsUndoManager = a.ox;\n        b.skipsModelSourceBindings = a.Mw;\n        a.Tr = !1\n    }\n    t.Xc = function (a) {\n        var b = this.Ad;\n        !0 === this.qc && (this.gl = this.Ze = this.qc = !1, this.Ke.clear(), 0 < b.pc.count && this.B.Pb());\n        if (this.hc && this.Mc) {\n            if (b.gm(!0), b.pc.clear(), Dh(b), !0 === a)\n                for (a = this.Ck.na(), b = 0; b < a.length; b++) a[b].gm(!0)\n        } else b.pc.clear(), Dh(b)\n    };\n    t.gm = function (a) {\n        a === this.defaultAnimation && this.defaultAnimation.pc.clear();\n        this.Ck.remove(a);\n        0 === this.Ck.count && (this.hc = !1, this.B.Pb());\n        a === this.defaultAnimation && (this.defaultAnimation.pc.clear(), this.B.R(\"AnimationFinished\", this))\n    };\n    t.Vj = function (a, b) {\n        this.Ze && (this.Ke.contains(\"Expand Tree\") || this.Ke.contains(\"Expand SubGraph\")) && this.Ad.Vj(a, b)\n    };\n    t.Tj = function (a, b) {\n        this.Ze && (this.Ke.contains(\"Collapse Tree\") || this.Ke.contains(\"Collapse SubGraph\")) && (this.Ad.Tj(a, b), Nh(this.Ad, b, \"position\", b.position, b.position))\n    };\n\n    function Oh(a, b, c) {\n        a.Ze && !b.w(c) && (a.B.kk || (b = c.copy()), Nh(a.Ad, a.B, \"position\", b, c))\n    }\n\n    function Ph(a, b, c, d, e) {\n        null === a && (a = \"rgba(0,0,0,0)\");\n        null === b && (b = \"rgba(0,0,0,0)\");\n        Qh(a);\n        Rh();\n        var f = Sh.l,\n            g = Sh.I,\n            h = Sh.u;\n        a = Sh.Y;\n        Qh(b);\n        Rh();\n        var k = Sh.I,\n            l = Sh.u;\n        b = Sh.Y;\n        f = e(c, f, Sh.l - f, d);\n        g = e(c, g, k - g, d);\n        h = e(c, h, l - h, d);\n        c = e(c, a, b - a, d);\n        return \"hsla(\" + f + \", \" + g + \"%, \" + h + \"%, \" + c + \")\"\n    }\n\n    function wh() {\n        var a = new H;\n        a.add(\"position:diagram\", function (a, c, d, e, f, g) {\n            a.position = new I(e(f, c.x, d.x - c.x, g), e(f, c.y, d.y - c.y, g))\n        });\n        a.add(\"position\", function (a, c, d, e, f, g) {\n            f < g ? a.Kq(e(f, c.x, d.x - c.x, g), e(f, c.y, d.y - c.y, g), !1) : a.position = new I(e(f, c.x, d.x - c.x, g), e(f, c.y, d.y - c.y, g))\n        });\n        a.add(\"location\", function (a, c, d, e, f, g) {\n            f < g ? a.Kq(e(f, c.x, d.x - c.x, g), e(f, c.y, d.y - c.y, g), !0) : a.location = new I(e(f, c.x, d.x - c.x, g), e(f, c.y, d.y - c.y, g))\n        });\n        a.add(\"position:placeholder\", function (a, c, d, e, f, g) {\n            f < g ? a.Kq(e(f, c.x, d.x - c.x,\n                g), e(f, c.y, d.y - c.y, g), !1) : a.position = new I(e(f, c.x, d.x - c.x, g), e(f, c.y, d.y - c.y, g))\n        });\n        a.add(\"position:node\", function (a, c, d, e, f, g) {\n            var b = a.actualBounds,\n                k = d.actualBounds;\n            d = k.x + k.width / 2 - b.width / 2;\n            b = k.y + k.height / 2 - b.height / 2;\n            f < g ? a.Kq(e(f, c.x, d - c.x, g), e(f, c.y, b - c.y, g), !1) : a.position = new I(e(f, c.x, d - c.x, g), e(f, c.y, b - c.y, g))\n        });\n        a.add(\"desiredSize\", function (a, c, d, e, f, g) {\n            a.desiredSize = new N(e(f, c.width, d.width - c.width, g), e(f, c.height, d.height - c.height, g))\n        });\n        a.add(\"width\", function (a, c, d, e, f, g) {\n            a.width = e(f, c,\n                d - c, g)\n        });\n        a.add(\"height\", function (a, c, d, e, f, g) {\n            a.height = e(f, c, d - c, g)\n        });\n        a.add(\"fill\", function (a, c, d, e, f, g) {\n            a.fill = Ph(c, d, f, g, e)\n        });\n        a.add(\"stroke\", function (a, c, d, e, f, g) {\n            a.stroke = Ph(c, d, f, g, e)\n        });\n        a.add(\"strokeWidth\", function (a, c, d, e, f, g) {\n            a.strokeWidth = e(f, c, d - c, g)\n        });\n        a.add(\"strokeDashOffset\", function (a, c, d, e, f, g) {\n            a.strokeDashOffset = e(f, c, d - c, g)\n        });\n        a.add(\"background\", function (a, c, d, e, f, g) {\n            a.background = Ph(c, d, f, g, e)\n        });\n        a.add(\"areaBackground\", function (a, c, d, e, f, g) {\n            a.areaBackground = Ph(c, d, f, g, e)\n        });\n        a.add(\"opacity\",\n            function (a, c, d, e, f, g) {\n                a.opacity = e(f, c, d - c, g)\n            });\n        a.add(\"scale\", function (a, c, d, e, f, g) {\n            a.scale = e(f, c, d - c, g)\n        });\n        a.add(\"angle\", function (a, c, d, e, f, g) {\n            a.angle = e(f, c, d - c, g)\n        });\n        Th = a\n    }\n    ma.Object.defineProperties(uh.prototype, {\n        animationReasons: {\n            get: function () {\n                return this.Ke\n            }\n        },\n        isEnabled: {\n            get: function () {\n                return this.Mc\n            },\n            set: function (a) {\n                this.Mc = a\n            }\n        },\n        duration: {\n            get: function () {\n                return this.Ug\n            },\n            set: function (a) {\n                1 > a && va(a, \">= 1\", uh, \"duration\");\n                this.Ug = a\n            }\n        },\n        isAnimating: {\n            get: function () {\n                return this.hc\n            }\n        },\n        isTicking: {\n            get: function () {\n                return this.Tr\n            }\n        },\n        isInitial: {\n            get: function () {\n                return this.oi\n            },\n            set: function (a) {\n                this.oi = a\n            }\n        },\n        defaultAnimation: {\n            get: function () {\n                return this.Ad\n            }\n        },\n        activeAnimations: {\n            get: function () {\n                return this.Ck\n            }\n        },\n        initialAnimationStyle: {\n            get: function () {\n                return this.hl\n            },\n            set: function (a) {\n                this.hl = a\n            }\n        }\n    });\n    uh.prototype.stopAnimation = uh.prototype.Xc;\n    var Th = null,\n        vh = !1,\n        xh = new D(uh, \"Default\", 1),\n        Fh = new D(uh, \"AnimateLocations\", 2),\n        Ch = new D(uh, \"None\", 3);\n    uh.className = \"AnimationManager\";\n    uh.defineAnimationEffect = function (a, b) {\n        vh || (wh(), vh = !0);\n        Th.add(a, b)\n    };\n    uh.Default = xh;\n    uh.AnimateLocations = Fh;\n    uh.None = Ch;\n\n    function yh() {\n        this.Xu = this.nx = this.Jc = this.B = null;\n        this.pl = this.hc = this.l = !1;\n        this.Gn = this.td = 0;\n        this.nr = this.ku = Uh;\n        this.ol = this.lp = !1;\n        this.Mu = 1;\n        this.Ku = 0;\n        this.md = this.Ug = NaN;\n        this.Pw = 0;\n        this.Hn = null;\n        this.u = Fb;\n        this.pc = new H;\n        this.Gu = new H;\n        this.Xl = new F;\n        this.Hu = new F;\n        this.Nw = Vh\n    }\n    yh.prototype.suspend = function () {\n        this.pl = !0\n    };\n    yh.prototype.advanceTo = function (a, b) {\n        b && (this.pl = !1);\n        this.lp && a >= this.md && (this.ol = !0, a -= this.md);\n        this.Pw = a;\n        Lh(this, !0);\n        Gh(this.Jc);\n        If(this.B);\n        Ih(this.Jc);\n        this.B.Ee()\n    };\n\n    function Dh(a) {\n        a.Gu.clear();\n        a.ol = !1;\n        a.Ku = 0;\n        a.md = NaN;\n        0 < a.Xl.count && a.Xl.clear();\n        0 < a.Hu.count && a.Hu.clear()\n    }\n    t = yh.prototype;\n    t.start = function () {\n        if (0 !== this.pc.count && !this.hc) {\n            for (var a = this.B, b = this.pc.iterator; b.next();) {\n                var c = b.value.end,\n                    d = b.key;\n                if (c[\"position:placeholder\"]) {\n                    var e = d.findVisibleNode();\n                    if (e instanceof T && null !== e.placeholder) {\n                        var f = e.placeholder;\n                        e = f.ga(vc);\n                        f = f.padding;\n                        e.x += f.left;\n                        e.y += f.top;\n                        c[\"position:placeholder\"] = e\n                    }\n                }\n                null === a && (d instanceof R ? a = d : d instanceof Y && (a = d.diagram))\n            }\n            null !== a && (this.B = a, b = this.Jc = a.animationManager, this.md = isNaN(this.Ug) ? b.duration : this.Ug, this.nr = this.ku, b.gl && b.hl === xh &&\n                this === b.defaultAnimation && (this.nr = Wh, this.md = isNaN(this.Ug) ? 600 === b.duration ? 900 : b.duration : this.Ug), this.Nw = a.scrollMode, this.isViewportUnconstrained && (a.Gi = Xh), Gh(b), this.Xl.each(function (b) {\n                    b.data = null;\n                    a.add(b)\n                }), Ih(b), this.hc = !0, this.td = +new Date, this.Gn = this.td + this.md, Kh(b, this))\n        }\n    };\n    t.Ly = function (a, b) {\n        a.Wb() && (this.Xl.add(a), this.B = b)\n    };\n    t.add = function (a, b, c, d, e) {\n        \"position\" === b && c.w(d) || (null === this.B && (a instanceof R ? this.B = a : a instanceof Y && null !== a.diagram && (this.B = a.diagram)), a instanceof U && !a.isAnimated || Nh(this, a, b, c, d, e))\n    };\n\n    function Nh(a, b, c, d, e, f) {\n        var g = a.pc;\n        b instanceof R && \"position\" === c && (c = \"position:diagram\");\n        if (g.contains(b)) {\n            var h = g.H(b);\n            var k = h.start;\n            var l = h.end;\n            void 0 === k[c] && (k[c] = Yh(d));\n            l[c] = Yh(e)\n        } else k = {}, l = {}, k[c] = Yh(d), l[c] = Yh(e), h = k.position, b instanceof Y && h instanceof I && !h.v() && b.diagram.animationManager.Ke.contains(\"Expand SubGraph\") && h.assign(l.position), h = new Zh(k, l, f), g.add(b, h);\n        g = k[c];\n        g instanceof I && !g.v() && g.assign(a.u);\n        f && 0 === c.indexOf(\"position:\") && b instanceof U ? h.pv.location = Yh(b.location) :\n            f && (h.pv[c] = Yh(d))\n    }\n\n    function Yh(a) {\n        return a instanceof I ? a.copy() : a instanceof M ? a.copy() : a\n    }\n    t.Dt = function (a) {\n        if (!this.hc) return !1;\n        a = this.pc.H(a);\n        return null !== a && a.Uv\n    };\n    t.Gv = function (a) {\n        if (!this.hc) return !1;\n        a = this.pc.H(a);\n        return null !== a && (a.start.position || a.start.location)\n    };\n\n    function Lh(a, b) {\n        if (!a.pl || b) {\n            var c = a.Jc;\n            if (!1 !== a.hc) {\n                var d = +new Date,\n                    e = d > a.Gn ? a.md : d - a.td;\n                b && (e = a.Pw, e < a.md ? (a.td = +new Date - e, a.Gn = a.td + a.md) : e = a.md);\n                Gh(c);\n                Hh(a, e);\n                If(a.B, !0);\n                Ih(c);\n                d > a.Gn && (a.lp && !a.ol ? (a.td = +new Date, a.Gn = a.td + a.md, a.ol = !0) : a.gm(!1))\n            }\n        }\n    }\n\n    function Hh(a, b) {\n        for (var c = a.md, d = a.pc.iterator, e = a.ol; d.next();) {\n            var f = d.key;\n            if (!(f instanceof Y && null === f.diagram)) {\n                var g = d.value,\n                    h = e ? g.end : g.start;\n                g = e ? g.start : g.end;\n                var k = Th,\n                    l;\n                for (l in g) \"position\" === l && (g[\"position:placeholder\"] || g[\"position:node\"]) || null === k.get(l) || k.get(l)(f, h[l], g[l], a.nr, b, c, a)\n            }\n        }\n    }\n    t.stop = function () {\n        this.hc && this.gm(!0)\n    };\n    t.gm = function (a) {\n        null !== this.Xu && this.Xu.sp.remove(this.nx);\n        if (this.hc) {\n            var b = this.B,\n                c = this.Jc;\n            this.pl = this.hc = c.gl = !1;\n            Gh(c);\n            for (var d = this.pc, e = this.Xl.iterator; e.next();) b.remove(e.value);\n            for (e = this.Hu.iterator; e.next();) e.value.o();\n            e = this.lp;\n            d = d.iterator;\n            for (var f = Th; d.next();) {\n                var g = d.key,\n                    h = d.value,\n                    k = e ? h.end : h.start,\n                    l = e ? h.start : h.end,\n                    m = h.pv,\n                    n;\n                for (n in l)\n                    if (null !== f.get(n)) {\n                        var p = n;\n                        !h.kv || \"position:node\" !== p && \"position:placeholder\" !== p || (p = \"position\");\n                        f.get(p)(g, k[n], void 0 !== m[n] ? m[n] : h.kv ? k[n] :\n                            l[n], this.nr, this.md, this.md, this)\n                    } h.kv && void 0 !== m.location && g instanceof U && (g.location = m.location);\n                h.Uv && g instanceof U && g.Ob(!1)\n            }\n            if (c.defaultAnimation === this)\n                for (n = this.B.links; n.next();) e = n.value, null === e.oh ? (d = e.path, null !== d && (e.kd = !1, e.o(), d.o())) : (e.points = e.oh, e.oh = null);\n            b.yt.clear();\n            kf(b, !1);\n            b.Na();\n            b.M();\n            If(b, !0);\n            this.isViewportUnconstrained && (b.scrollMode = this.Nw);\n            Ih(c);\n            this.Ku++;\n            !a && this.Mu > this.Ku ? (this.ol = !1, this.start()) : (this.Hn && this.Hn(this), Dh(this), c.gm(this), b.Pb())\n        }\n    };\n    t.Vj = function (a, b) {\n        var c = b.actualBounds,\n            d = null;\n        b instanceof T && (d = b.placeholder);\n        null !== d ? (c = d.ga(vc), d = d.padding, c.x += d.left, c.y += d.top, this.add(a, \"position\", c, a.position, !1)) : this.add(a, \"position\", new I(c.x + c.width / 2, c.y + c.height / 2), a.position, !1);\n        this.add(a, \"scale\", .01, a.scale, !1);\n        if (a instanceof T)\n            for (a = a.memberParts; a.next();) d = a.value, d instanceof W && this.Vj(d, b)\n    };\n    t.Tj = function (a, b) {\n        if (a.isVisible()) {\n            var c = null;\n            b instanceof T && (c = b.placeholder);\n            null !== c ? this.add(a, \"position:placeholder\", a.position, c, !0) : this.add(a, \"position:node\", a.position, b, !0);\n            this.add(a, \"scale\", a.scale, .01, !0);\n            c = this.pc;\n            c.contains(a) && (c.H(a).Uv = !0);\n            if (a instanceof T)\n                for (a = a.memberParts; a.next();) c = a.value, c instanceof W && this.Tj(c, b)\n        }\n    };\n    t.Hz = function (a) {\n        var b = this.Gu.get(a);\n        null === b && (b = {}, this.Gu.add(a, b));\n        return b\n    };\n    ma.Object.defineProperties(yh.prototype, {\n        duration: {\n            get: function () {\n                return this.Ug\n            },\n            set: function (a) {\n                1 > a && va(a, \">= 1\", yh, \"duration\");\n                this.Ug = a\n            }\n        },\n        reversible: {\n            get: function () {\n                return this.lp\n            },\n            set: function (a) {\n                this.lp = a\n            }\n        },\n        runCount: {\n            get: function () {\n                return this.Mu\n            },\n            set: function (a) {\n                0 < a ? this.Mu = a : B(\"Animation.runCount value must be a positive integer.\")\n            }\n        },\n        finished: {\n            get: function () {\n                return this.Hn\n            },\n            set: function (a) {\n                this.Hn !== a && (this.Hn = a)\n            }\n        },\n        easing: {\n            get: function () {\n                return this.ku\n            },\n            set: function (a) {\n                this.ku = a\n            }\n        },\n        isViewportUnconstrained: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l = a\n            }\n        },\n        isAnimating: {\n            get: function () {\n                return this.hc\n            }\n        }\n    });\n    yh.prototype.getTemporaryState = yh.prototype.Hz;\n    yh.prototype.stop = yh.prototype.stop;\n    yh.prototype.add = yh.prototype.add;\n    yh.prototype.addTemporaryPart = yh.prototype.Ly;\n\n    function Uh(a, b, c, d) {\n        a /= d / 2;\n        return 1 > a ? c / 2 * a * a + b : -c / 2 * (--a * (a - 2) - 1) + b\n    }\n\n    function Wh(a, b, c, d) {\n        return a === d ? b + c : c * (-Math.pow(2, -10 * a / d) + 1) + b\n    }\n    yh.className = \"Animation\";\n    yh.EaseLinear = function (a, b, c, d) {\n        return c * a / d + b\n    };\n    yh.EaseInOutQuad = Uh;\n    yh.EaseInQuad = function (a, b, c, d) {\n        return c * (a /= d) * a + b\n    };\n    yh.EaseOutQuad = function (a, b, c, d) {\n        return -c * (a /= d) * (a - 2) + b\n    };\n    yh.EaseInExpo = function (a, b, c, d) {\n        return 0 === a ? b : c * Math.pow(2, 10 * (a / d - 1)) + b\n    };\n    yh.EaseOutExpo = Wh;\n\n    function Zh(a, b, c) {\n        this.start = a;\n        this.end = b;\n        this.pv = {};\n        this.kv = c;\n        this.Uv = !1\n    }\n    Zh.className = \"AnimationState\";\n\n    function $h(a, b, c) {\n        this.bd = null;\n        this.af = a;\n        this.Mp = c || ai;\n        this.Hk = null;\n        void 0 !== b && (this.Hk = b, void 0 === c && (this.Mp = bi))\n    }\n    $h.prototype.copy = function () {\n        var a = new $h(this.af);\n        a.Mp = this.Mp;\n        var b = this.Hk;\n        if (null !== b) {\n            var c = {};\n            void 0 !== b.duration && (c.Hx = b.duration);\n            void 0 !== b.finished && (c.Hx = b.finished);\n            void 0 !== b.easing && (c.Hx = b.easing);\n            a.Hk = c\n        }\n        return a\n    };\n\n    function ci(a, b) {\n        a = a.Hk;\n        null !== a && (a.duration && (b.duration = a.duration), a.finished && (b.finished = a.finished), a.easing && (b.easing = a.easing))\n    }\n    ma.Object.defineProperties($h.prototype, {\n        propertyName: {\n            get: function () {\n                return this.af\n            },\n            set: function (a) {\n                this.af = a\n            }\n        },\n        animationSettings: {\n            get: function () {\n                return this.Hk\n            },\n            set: function (a) {\n                this.Hk = a\n            }\n        },\n        startCondition: {\n            get: function () {\n                return this.Mp\n            },\n            set: function (a) {\n                this.Mp = a\n            }\n        }\n    });\n    var ai = new D($h, \"Default\", 1),\n        bi = new D($h, \"Immediate\", 2),\n        di = new D($h, \"Bundled\", 3);\n    $h.className = \"AnimationTrigger\";\n    $h.Default = ai;\n    $h.Immediate = bi;\n    $h.Bundled = di;\n\n    function ei() {\n        Ya(this);\n        this.B = null;\n        this.Ca = new E;\n        this.Ra = \"\";\n        this.qb = 1;\n        this.u = !1;\n        this.Bi = this.I = this.$h = this.Zh = this.Yh = this.Xh = this.Vh = this.Wh = this.Uh = this.bi = this.Th = this.ai = this.Sh = this.Rh = !0;\n        this.l = !1;\n        this.Yo = []\n    }\n    t = ei.prototype;\n    t.clear = function () {\n        this.Ca.clear();\n        this.Yo.length = 0\n    };\n    t.Yd = function (a) {\n        this.B = a\n    };\n    t.toString = function (a) {\n        void 0 === a && (a = 0);\n        var b = 'Layer \"' + this.name + '\"';\n        if (0 >= a) return b;\n        for (var c = 0, d = 0, e = 0, f = 0, g = 0, h = this.Ca.iterator; h.next();) {\n            var k = h.value;\n            k instanceof T ? e++ : k instanceof W ? d++ : k instanceof S ? f++ : k instanceof Je ? g++ : c++\n        }\n        h = \"\";\n        0 < c && (h += c + \" Parts \");\n        0 < d && (h += d + \" Nodes \");\n        0 < e && (h += e + \" Groups \");\n        0 < f && (h += f + \" Links \");\n        0 < g && (h += g + \" Adornments \");\n        if (1 < a)\n            for (a = this.Ca.iterator; a.next();) c = a.value, h += \"\\n    \" + c.toString(), d = c.data, null !== d && lb(d) && (h += \" #\" + lb(d)), c instanceof W ? h += \" \" +\n                Ja(d) : c instanceof S && (h += \" \" + Ja(c.fromNode) + \" \" + Ja(c.toNode));\n        return b + \" \" + this.Ca.count + \": \" + h\n    };\n    t.Ub = function (a, b, c) {\n        void 0 === b && (b = null);\n        void 0 === c && (c = null);\n        if (!1 === this.Bi) return null;\n        var d = !1;\n        null !== this.diagram && this.diagram.viewportBounds.aa(a) && (d = !0);\n        for (var e = I.alloc(), f = this.Ca.j, g = f.length; g--;) {\n            var h = f[g];\n            if ((!0 !== d || !1 !== wg(h)) && h.isVisible() && (e.assign(a), zb(e, h.ud), h = h.Ub(e, b, c), null !== h && (null !== b && (h = b(h)), null !== h && (null === c || c(h))))) return I.free(e), h\n        }\n        I.free(e);\n        return null\n    };\n    t.Ti = function (a, b, c, d) {\n        void 0 === b && (b = null);\n        void 0 === c && (c = null);\n        d instanceof E || d instanceof F || (d = new F);\n        if (!1 === this.Bi) return d;\n        var e = !1;\n        null !== this.diagram && this.diagram.viewportBounds.aa(a) && (e = !0);\n        for (var f = I.alloc(), g = this.Ca.j, h = g.length; h--;) {\n            var k = g[h];\n            if ((!0 !== e || !1 !== wg(k)) && k.isVisible()) {\n                f.assign(a);\n                zb(f, k.ud);\n                var l = k;\n                k.Ti(f, b, c, d) && (null !== b && (l = b(l)), null === l || null !== c && !c(l) || d.add(l))\n            }\n        }\n        I.free(f);\n        return d\n    };\n    t.tf = function (a, b, c, d, e) {\n        void 0 === b && (b = null);\n        void 0 === c && (c = null);\n        void 0 === d && (d = !1);\n        e instanceof E || e instanceof F || (e = new F);\n        if (!1 === this.Bi) return e;\n        var f = !1;\n        null !== this.diagram && this.diagram.viewportBounds.ze(a) && (f = !0);\n        for (var g = this.Ca.j, h = g.length; h--;) {\n            var k = g[h];\n            if ((!0 !== f || !1 !== wg(k)) && k.isVisible()) {\n                var l = k;\n                k.tf(a, b, c, d, e) && (null !== b && (l = b(l)), null === l || null !== c && !c(l) || e.add(l))\n            }\n        }\n        return e\n    };\n    t.uv = function (a, b, c, d, e, f, g) {\n        if (!1 === this.Bi) return e;\n        for (var h = this.Ca.j, k = h.length; k--;) {\n            var l = h[k];\n            if ((!0 !== g || !1 !== wg(l)) && f(l) && l.isVisible()) {\n                var m = l;\n                l.tf(a, b, c, d, e) && (null !== b && (m = b(m)), null === m || null !== c && !c(m) || e.add(m))\n            }\n        }\n        return e\n    };\n    t.Ag = function (a, b, c, d, e, f) {\n        void 0 === c && (c = null);\n        void 0 === d && (d = null);\n        void 0 === e && (e = !0);\n        if (!1 !== e && !0 !== e) {\n            if (e instanceof E || e instanceof F) f = e;\n            e = !0\n        }\n        f instanceof E || f instanceof F || (f = new F);\n        if (!1 === this.Bi) return f;\n        var g = !1;\n        null !== this.diagram && this.diagram.viewportBounds.aa(a) && (g = !0);\n        for (var h = I.alloc(), k = I.alloc(), l = this.Ca.j, m = l.length; m--;) {\n            var n = l[m];\n            if ((!0 !== g || !1 !== wg(n)) && n.isVisible()) {\n                h.assign(a);\n                zb(h, n.ud);\n                k.h(a.x + b, a.y);\n                zb(k, n.ud);\n                var p = n;\n                n.Ag(h, k, c, d, e, f) && (null !== c && (p = c(p)), null ===\n                    p || null !== d && !d(p) || f.add(p))\n            }\n        }\n        I.free(h);\n        I.free(k);\n        return f\n    };\n    t.yd = function (a, b) {\n        if (this.visible) {\n            var c = void 0 === b ? a.viewportBounds : b;\n            var d = this.Ca.j,\n                e = d.length;\n            a = Fa();\n            b = Fa();\n            for (var f = 0; f < e; f++) {\n                var g = d[f];\n                g.Xw = f;\n                g instanceof S && !1 === g.kd || g instanceof Je && null !== g.adornedPart || (dc(g.actualBounds, c) ? (g.yd(!0), a.push(g)) : (g.yd(!1), null !== g.adornments && 0 < g.adornments.count && b.push(g)))\n            }\n            for (c = 0; c < a.length; c++)\n                for (d = a[c], fi(d), d = d.adornments; d.next();) e = d.value, e.measure(Infinity, Infinity), e.arrange(), e.yd(!0);\n            for (c = 0; c < b.length; c++) d = b[c], d.updateAdornments(),\n                gi(d, !0);\n            Ha(a);\n            Ha(b)\n        }\n    };\n\n    function hi(a, b) {\n        var c = 1;\n        1 !== a.qb && (c = b.globalAlpha, b.globalAlpha = c * a.qb);\n        return c\n    }\n    t.bc = function (a, b, c) {\n        if (this.visible && 0 !== this.qb && (void 0 === c && (c = !0), c || !this.isTemporary)) {\n            c = this.Ca.j;\n            var d = c.length;\n            if (0 !== d) {\n                var e = hi(this, a),\n                    f = this.Yo;\n                f.length = 0;\n                for (var g = b.scale, h = N.alloc(), k = 0; k < d; k++) this.Pi(a, c[k], b, f, g, h);\n                N.free(h);\n                a.globalAlpha = e\n            }\n        }\n    };\n    t.Pi = function (a, b, c, d, e, f) {\n        if (null !== d && b instanceof S && (b.isOrthogonal && d.push(b), !1 === b.kd)) return;\n        var g = b.actualBounds;\n        d = !1;\n        var h = b.containingGroup;\n        if (null !== h && h.isClipping && h.type !== X.Spot) {\n            h.locationObject.lm(f);\n            if (!f.Gc(g)) return;\n            d = !f.ze(g)\n        }\n        d && (a.save(), a.beginPath(), a.rect(f.x, f.y, f.width, f.height), a.clip());\n        g.width * e > c.Bo || g.height * e > c.Bo ? b.bc(a, c) : (e = b.actualBounds, f = b.naturalBounds, 0 === e.width || 0 === e.height || isNaN(e.x) || isNaN(e.y) || !b.isVisible() || (c = b.transform, null !== b.areaBackground &&\n            (ii(b, a, b.areaBackground, !0, !0, f, e), a.fillRect(e.x, e.y, e.width, e.height)), null === b.areaBackground && null === b.background && (ii(b, a, \"rgba(0,0,0,0.3)\", !0, !1, f, e), a.fillRect(e.x, e.y, e.width, e.height)), null !== b.background && (a.transform(c.m11, c.m12, c.m21, c.m22, c.dx, c.dy), ii(b, a, b.background, !0, !1, f, e), a.fillRect(0, 0, f.width / 2, f.height / 2), c.ut() || (b = 1 / (c.m11 * c.m22 - c.m12 * c.m21), a.transform(c.m22 * b, -c.m12 * b, -c.m21 * b, c.m11 * b, b * (c.m21 * c.dy - c.m22 * c.dx), b * (c.m12 * c.dx - c.m11 * c.dy))))));\n        d && (a.restore(), a.sc(!0))\n    };\n    t.g = function (a, b, c, d, e) {\n        var f = this.diagram;\n        null !== f && f.Ya(re, a, this, b, c, d, e)\n    };\n    t.aj = function (a, b, c) {\n        var d = this.Ca;\n        b.ui = this;\n        if (a >= d.count) a = d.count;\n        else if (d.L(a) === b) return -1;\n        d.Kb(a, b);\n        b.qq(c);\n        d = this.diagram;\n        null !== d && (c ? d.M() : d.aj(b));\n        ji(this, a, b);\n        return a\n    };\n    t.Fc = function (a, b, c) {\n        if (!c && b.layer !== this && null !== b.layer) return b.layer.Fc(a, b, c);\n        var d = this.Ca;\n        if (0 > a || a >= d.length) {\n            if (a = d.indexOf(b), 0 > a) return -1\n        } else if (d.L(a) !== b && (a = d.indexOf(b), 0 > a)) return -1;\n        b.rq(c);\n        d.lb(a);\n        d = this.diagram;\n        null !== d && (c ? d.M() : d.Fc(b));\n        b.ui = null;\n        return a\n    };\n\n    function ji(a, b, c) {\n        b = ki(a, b, c);\n        if (c instanceof T && null !== c && isNaN(c.zOrder)) {\n            if (0 !== c.memberParts.count) {\n                for (var d = -1, e = a.Ca.j, f = e.length, g = 0; g < f; g++) {\n                    var h = e[g];\n                    if (h === c && (b = g, 0 <= d)) break;\n                    if (0 > d && h.containingGroup === c && (d = g, 0 <= b)) break\n                }!(0 > d) && d < b && (e = a.Ca, e.lb(b), e.Kb(d, c))\n            }\n            c = c.containingGroup;\n            null !== c && ji(a, -1, c)\n        }\n    }\n\n    function ki(a, b, c) {\n        var d = c.zOrder;\n        if (isNaN(d)) return b;\n        a = a.Ca;\n        var e = a.count;\n        if (1 >= e) return b;\n        0 > b && (b = a.indexOf(c));\n        if (0 > b) return -1;\n        for (var f = b - 1, g = NaN; 0 <= f;) {\n            g = a.L(f).zOrder;\n            if (!isNaN(g)) break;\n            f--\n        }\n        for (var h = b + 1, k = NaN; h < e;) {\n            k = a.L(h).zOrder;\n            if (!isNaN(k)) break;\n            h++\n        }\n        if (!isNaN(g) && g > d)\n            for (;;) {\n                if (-1 === f || g <= d) {\n                    f++;\n                    if (f === b) break;\n                    a.lb(b);\n                    a.Kb(f, c);\n                    return f\n                }\n                for (g = NaN; 0 <= --f && (g = a.L(f).zOrder, isNaN(g)););\n            } else if (!isNaN(k) && k < d)\n                for (;;) {\n                    if (h === e || k >= d) {\n                        h--;\n                        if (h === b) break;\n                        a.lb(b);\n                        a.Kb(h, c);\n                        return h\n                    }\n                    for (k = NaN; ++h <\n                        e && (k = a.L(h).zOrder, isNaN(k)););\n                }\n        return b\n    }\n    ma.Object.defineProperties(ei.prototype, {\n        parts: {\n            get: function () {\n                return this.Ca.iterator\n            }\n        },\n        partsBackwards: {\n            get: function () {\n                return this.Ca.iteratorBackwards\n            }\n        },\n        diagram: {\n            get: function () {\n                return this.B\n            }\n        },\n        name: {\n            get: function () {\n                return this.Ra\n            },\n            set: function (a) {\n                var b = this.Ra;\n                if (b !== a) {\n                    var c = this.diagram;\n                    if (null !== c)\n                        for (\"\" === b && B(\"Cannot rename default Layer to: \" + a), c = c.layers; c.next();) c.value.name ===\n                            a && B(\"Layer.name is already present in this diagram: \" + a);\n                    this.Ra = a;\n                    this.g(\"name\", b, a);\n                    for (a = this.Ca.iterator; a.next();) a.value.layerName = this.Ra\n                }\n            }\n        },\n        opacity: {\n            get: function () {\n                return this.qb\n            },\n            set: function (a) {\n                var b = this.qb;\n                b !== a && ((0 > a || 1 < a) && va(a, \"0 <= value <= 1\", ei, \"opacity\"), this.qb = a, this.g(\"opacity\", b, a), a = this.diagram, null !== a && a.M())\n            }\n        },\n        isTemporary: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                var b = this.u;\n                b !== a && (this.u = a, this.g(\"isTemporary\",\n                    b, a))\n            }\n        },\n        visible: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                var b = this.I;\n                if (b !== a) {\n                    this.I = a;\n                    this.g(\"visible\", b, a);\n                    for (b = this.Ca.iterator; b.next();) b.value.Ob(a);\n                    a = this.diagram;\n                    null !== a && a.M()\n                }\n            }\n        },\n        pickable: {\n            get: function () {\n                return this.Bi\n            },\n            set: function (a) {\n                var b = this.Bi;\n                b !== a && (this.Bi = a, this.g(\"pickable\", b, a))\n            }\n        },\n        isBoundsIncluded: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l !== a && (this.l = a, null !== this.diagram &&\n                    this.diagram.Na())\n            }\n        },\n        allowCopy: {\n            get: function () {\n                return this.Rh\n            },\n            set: function (a) {\n                var b = this.Rh;\n                b !== a && (this.Rh = a, this.g(\"allowCopy\", b, a))\n            }\n        },\n        allowDelete: {\n            get: function () {\n                return this.Sh\n            },\n            set: function (a) {\n                var b = this.Sh;\n                b !== a && (this.Sh = a, this.g(\"allowDelete\", b, a))\n            }\n        },\n        allowTextEdit: {\n            get: function () {\n                return this.ai\n            },\n            set: function (a) {\n                var b = this.ai;\n                b !== a && (this.ai = a, this.g(\"allowTextEdit\", b, a))\n            }\n        },\n        allowGroup: {\n            get: function () {\n                return this.Th\n            },\n            set: function (a) {\n                var b = this.Th;\n                b !== a && (this.Th = a, this.g(\"allowGroup\", b, a))\n            }\n        },\n        allowUngroup: {\n            get: function () {\n                return this.bi\n            },\n            set: function (a) {\n                var b = this.bi;\n                b !== a && (this.bi = a, this.g(\"allowUngroup\", b, a))\n            }\n        },\n        allowLink: {\n            get: function () {\n                return this.Uh\n            },\n            set: function (a) {\n                var b = this.Uh;\n                b !== a && (this.Uh = a, this.g(\"allowLink\", b, a))\n            }\n        },\n        allowRelink: {\n            get: function () {\n                return this.Wh\n            },\n            set: function (a) {\n                var b =\n                    this.Wh;\n                b !== a && (this.Wh = a, this.g(\"allowRelink\", b, a))\n            }\n        },\n        allowMove: {\n            get: function () {\n                return this.Vh\n            },\n            set: function (a) {\n                var b = this.Vh;\n                b !== a && (this.Vh = a, this.g(\"allowMove\", b, a))\n            }\n        },\n        allowReshape: {\n            get: function () {\n                return this.Xh\n            },\n            set: function (a) {\n                var b = this.Xh;\n                b !== a && (this.Xh = a, this.g(\"allowReshape\", b, a))\n            }\n        },\n        allowResize: {\n            get: function () {\n                return this.Yh\n            },\n            set: function (a) {\n                var b = this.Yh;\n                b !== a && (this.Yh = a, this.g(\"allowResize\", b, a))\n            }\n        },\n        allowRotate: {\n            get: function () {\n                return this.Zh\n            },\n            set: function (a) {\n                var b = this.Zh;\n                b !== a && (this.Zh = a, this.g(\"allowRotate\", b, a))\n            }\n        },\n        allowSelect: {\n            get: function () {\n                return this.$h\n            },\n            set: function (a) {\n                var b = this.$h;\n                b !== a && (this.$h = a, this.g(\"allowSelect\", b, a))\n            }\n        }\n    });\n    ei.prototype.findObjectsNear = ei.prototype.Ag;\n    ei.prototype.findObjectsIn = ei.prototype.tf;\n    ei.prototype.findObjectsAt = ei.prototype.Ti;\n    ei.prototype.findObjectAt = ei.prototype.Ub;\n    ei.className = \"Layer\";\n\n    function R(a) {\n        function b() {\n            c.removeEventListener(x.document, \"DOMContentLoaded\", b, !1);\n            c.setRTL()\n        }\n        1 < arguments.length && B(\"Diagram constructor can only take one optional argument, the DIV HTML element or its id.\");\n        li || (mi(), li = !0);\n        Ya(this);\n        ze = this;\n        Qa = [];\n        this.Rb = !0;\n        this.Jc = new uh;\n        this.Jc.Yd(this);\n        this.jb = 17;\n        this.nl = this.Pu = !1;\n        this.zs = \"default\";\n        this.La = null;\n        var c = this;\n        Ug && (null !== x.document.body ? this.setRTL() : c.addEventListener(x.document, \"DOMContentLoaded\", b, !1));\n        this.Ja = new E;\n        this.va = this.wa = 0;\n        this.sa =\n            null;\n        this.jx = new H;\n        this.bf = this.Db = null;\n        this.aw();\n        this.vj = null;\n        this.$v();\n        this.qb = 1;\n        this.ma = (new I(NaN, NaN)).freeze();\n        this.Nu = new I(NaN, NaN);\n        this.yn = this.ya = 1;\n        this.Kr = (new I(NaN, NaN)).freeze();\n        this.Lr = NaN;\n        this.ds = 1E-4;\n        this.bs = 100;\n        this.kb = new rd;\n        this.$s = (new I(NaN, NaN)).freeze();\n        this.Fr = (new N(NaN, NaN, NaN, NaN)).freeze();\n        this.Fi = (new oc(0, 0, 0, 0)).freeze();\n        this.Gi = Vh;\n        this.Hs = !1;\n        this.As = this.vs = null;\n        this.Lg = ni;\n        this.lj = Zc;\n        this.Xf = ni;\n        this.Xn = Zc;\n        this.Mr = this.Jr = vc;\n        this.Ac = !0;\n        this.ll = !1;\n        this.nd = new F;\n        this.Sg =\n            new H;\n        this.Xk = !0;\n        this.Zm = 250;\n        this.jj = -1;\n        this.an = (new oc(16, 16, 16, 16)).freeze();\n        this.pj = this.we = !1;\n        this.sj = !0;\n        this.Uf = new ne;\n        this.Uf.diagram = this;\n        this.Pd = new ne;\n        this.Pd.diagram = this;\n        this.dh = new ne;\n        this.dh.diagram = this;\n        this.oe = this.Mf = null;\n        this.Pj = !1;\n        this.vr = this.wr = null;\n        this.Vm = x.PointerEvent && (Ta || Ua || Va) && x.navigator && !1 !== x.navigator.msPointerEnabled;\n        oi(this);\n        this.zh = new F;\n        this.Ur = !0;\n        this.Vs = pi;\n        this.uu = !1;\n        this.Xs = Nf;\n        this.Ia = null;\n        qi.add(\"Model\", ri);\n        this.pr = this.sr = this.Ts = null;\n        this.xn = this.mr = \"auto\";\n        this.fg = this.gs = this.hg = this.ig = this.kg = this.Of = this.Sf = this.Nf = null;\n        this.Ir = !1;\n        this.Pf = this.ug = this.jg = this.gg = null;\n        this.hs = !1;\n        this.ts = {};\n        this.Kj = [null, null];\n        this.gr = null;\n        this.tr = this.Ls = this.Ru = this.sg = !1;\n        this.yu = !0;\n        this.ni = this.Bc = !1;\n        this.ac = null;\n        var d = this;\n        this.jd = function (a) {\n            var b = d.partManager;\n            if (a.model === b.diagram.model && b.diagram.Z) {\n                b.diagram.Z = !1;\n                try {\n                    var c = a.change;\n                    \"\" === a.modelChange && c === re && b.updateDataBindings(a.object, a.propertyName)\n                } finally {\n                    b.diagram.Z = !0\n                }\n            }\n        };\n        this.Ic = function (a) {\n            d.partManager.doModelChanged(a)\n        };\n        this.$u = !0;\n        this.Gd = -2;\n        this.Ci = new H;\n        this.ss = new E;\n        this.Zf = !1;\n        this.Sh = this.Rh = this.Uq = this.Mc = !0;\n        this.Vq = !1;\n        this.ar = this.Zq = this.$h = this.Zh = this.Yh = this.Xh = this.Vh = this.Wh = this.Uh = this.Yq = this.bi = this.Th = this.ai = this.Wq = !0;\n        this.Yf = this.wu = !1;\n        this.$q = this.Xq = this.dl = this.cl = !0;\n        this.Gs = this.Cs = 16;\n        this.Bs = this.vp = !1;\n        this.wp = this.Es = null;\n        this.Ds = this.Fs = 0;\n        this.bb = (new oc(5)).freeze();\n        this.Qu = (new F).freeze();\n        this.cs = 999999999;\n        this.ru = (new F).freeze();\n        this.mi = this.li = this.ki = !0;\n        this.Se = this.he = !1;\n        this.ic =\n            null;\n        this.If = !0;\n        this.ie = !1;\n        this.Yw = new F;\n        this.su = new F;\n        this.Gb = null;\n        this.Cl = 1;\n        this.Su = 0;\n        this.Rd = {\n            scale: 1,\n            position: new I,\n            bounds: new N,\n            Jv: !1\n        };\n        this.Zu = (new N(NaN, NaN, NaN, NaN)).freeze();\n        this.Zl = (new M(NaN, NaN)).freeze();\n        this.zn = (new N(NaN, NaN, NaN, NaN)).freeze();\n        this.Vr = !1;\n        this.qo = this.Vn = this.Ro = this.fu = this.eu = this.gu = this.ag = this.ah = this.Ye = this.zr = null;\n        si(this);\n        this.Fb = null;\n        this.Un = !1;\n        this.mj = null;\n        this.partManager = new ri;\n        this.toolManager = new Oa;\n        this.toolManager.initializeStandardTools();\n        this.currentTool =\n            this.defaultTool = this.toolManager;\n        this.yr = null;\n        this.Qk = new Re;\n        this.ns = this.ms = null;\n        this.Op = !1;\n        this.commandHandler = zi();\n        this.model = Ai();\n        this.sg = !0;\n        Bi(this);\n        this.layout = new Ci;\n        this.sg = !1;\n        this.Rw = this.ju = null;\n        this.Sb = 1;\n        this.uh = null;\n        this.Bo = 1;\n        this.Io = 0;\n        this.Jo = [0, 0, 0, 0, 0];\n        this.Ko = 0;\n        this.od = 1;\n        this.Aj = 0;\n        this.lo = new I;\n        this.Us = 500;\n        this.$m = new I;\n        this.je = !1;\n        this.preventDefault = this.Ht = this.vm = this.wm = this.um = this.tm = this.rk = this.tk = this.sk = this.pk = this.qk = this.vw = this.nw = this.ow = this.pw = this.nh = this.Gl = this.mh =\n            this.Fl = null;\n        this.$n = !1;\n        this.ji = new Di;\n        this.Pp = !1;\n        void 0 !== a && Ei(this, a);\n        this.In = null;\n        this.Jn = Jb;\n        this.Rb = !1\n    }\n    R.prototype.clear = function () {\n        this.animationManager.Xc();\n        this.model.clear();\n        Fi = null;\n        Gi = \"\";\n        Hi(this, !1);\n        this.Na();\n        Ii(this);\n        this.M()\n    };\n\n    function Hi(a, b) {\n        a.animationManager.Xc(!0);\n        a.Qu = (new F).freeze();\n        a.ru = (new F).freeze();\n        var c = a.skipsUndoManager;\n        null !== a.model && (a.skipsUndoManager = !0);\n        var d = null;\n        null !== a.Fb && (d = a.Fb.part, null !== d && a.remove(d));\n        var e = [],\n            f = a.Ja.length;\n        if (b) {\n            for (b = 0; b < f; b++)\n                for (var g = a.Ja.j[b].parts; g.next();) {\n                    var h = g.value;\n                    h !== d && null === h.data && e.push(h)\n                }\n            for (b = 0; b < e.length; b++) a.remove(e[b])\n        }\n        for (b = 0; b < f; b++) a.Ja.j[b].clear();\n        a.partManager.clear();\n        a.nd.clear();\n        a.Sg.clear();\n        a.zh.clear();\n        a.mj = null;\n        Ga = [];\n        null !== d && (a.add(d),\n            a.partManager.parts.remove(d));\n        null !== a.model && (a.skipsUndoManager = c);\n        return e\n    }\n\n    function zi() {\n        return null\n    }\n    R.prototype.reset = function () {\n        this.clear();\n        this.Rb = !0;\n        this.Jc = new uh;\n        this.Jc.Yd(this);\n        this.jb = 17;\n        this.nl = this.Pu = !1;\n        this.zs = \"default\";\n        this.Ja = new E;\n        this.jx = new H;\n        this.bf = null;\n        this.aw();\n        this.vj = null;\n        this.$v();\n        this.qb = 1;\n        this.ma = (new I(NaN, NaN)).freeze();\n        this.Nu = new I(NaN, NaN);\n        this.yn = this.ya = 1;\n        this.Kr = (new I(NaN, NaN)).freeze();\n        this.Lr = NaN;\n        this.ds = 1E-4;\n        this.bs = 100;\n        this.kb = new rd;\n        this.$s = (new I(NaN, NaN)).freeze();\n        this.Fr = (new N(NaN, NaN, NaN, NaN)).freeze();\n        this.Fi = (new oc(0, 0, 0, 0)).freeze();\n        this.Gi = Vh;\n        this.Hs = !1;\n        this.As = this.vs = null;\n        this.Lg = ni;\n        this.lj = Zc;\n        this.Xf = ni;\n        this.Xn = Zc;\n        this.Mr = this.Jr = vc;\n        this.Ac = !0;\n        this.ll = !1;\n        this.nd = new F;\n        this.Sg = new H;\n        this.Xk = !0;\n        this.Zm = 250;\n        this.jj = -1;\n        this.an = (new oc(16, 16, 16, 16)).freeze();\n        this.pj = this.we = !1;\n        this.sj = !0;\n        this.Uf = new ne;\n        this.Uf.diagram = this;\n        this.Pd = new ne;\n        this.Pd.diagram = this;\n        this.dh = new ne;\n        this.dh.diagram = this;\n        this.oe = this.Mf = null;\n        this.Pj = !1;\n        this.vr = this.wr = null;\n        this.Vm = x.PointerEvent && (Ta || Ua || Va) && x.navigator && !1 !== x.navigator.msPointerEnabled;\n        oi(this);\n        this.zh =\n            new F;\n        this.Ur = !0;\n        this.Vs = pi;\n        this.uu = !1;\n        this.Xs = Nf;\n        this.pr = this.sr = this.Ts = null;\n        this.xn = this.mr = \"auto\";\n        this.fg = this.gs = this.hg = this.ig = this.kg = this.Of = this.Sf = this.Nf = null;\n        this.Ir = !1;\n        this.Pf = this.ug = this.jg = this.gg = null;\n        this.hs = !1;\n        this.ts = {};\n        this.Kj = [null, null];\n        this.gr = null;\n        this.tr = this.Ls = this.Ru = this.sg = !1;\n        this.yu = !0;\n        this.ni = this.Bc = !1;\n        this.$u = !0;\n        this.Gd = -2;\n        this.Ci = new H;\n        this.ss = new E;\n        this.Zf = !1;\n        this.Sh = this.Rh = this.Uq = this.Mc = !0;\n        this.Vq = !1;\n        this.ar = this.Zq = this.$h = this.Zh = this.Yh = this.Xh = this.Vh =\n            this.Wh = this.Uh = this.Yq = this.bi = this.Th = this.ai = this.Wq = !0;\n        this.Yf = this.wu = !1;\n        this.$q = this.Xq = this.dl = this.cl = !0;\n        this.Gs = this.Cs = 16;\n        this.Bs = this.vp = !1;\n        this.Ds = this.Fs = 0;\n        this.bb = (new oc(5)).freeze();\n        this.Qu = (new F).freeze();\n        this.cs = 999999999;\n        this.ru = (new F).freeze();\n        this.mi = this.li = this.ki = !0;\n        this.Se = this.he = !1;\n        this.ic = null;\n        this.If = !0;\n        this.ie = !1;\n        this.Yw = new F;\n        this.su = new F;\n        this.Gb = null;\n        this.Cl = 1;\n        this.Su = 0;\n        this.Rd = {\n            scale: 1,\n            position: new I,\n            bounds: new N,\n            Jv: !1\n        };\n        this.Zu = (new N(NaN, NaN, NaN, NaN)).freeze();\n        this.Zl = (new M(NaN, NaN)).freeze();\n        this.zn = (new N(NaN, NaN, NaN, NaN)).freeze();\n        this.Vr = !1;\n        this.qo = this.Vn = this.Ro = this.fu = this.eu = this.gu = this.ag = this.ah = this.Ye = null;\n        si(this);\n        this.Fb = null;\n        this.Un = !1;\n        this.mj = null;\n        this.partManager = new ri;\n        this.toolManager = new Oa;\n        this.toolManager.initializeStandardTools();\n        this.currentTool = this.defaultTool = this.toolManager;\n        this.yr = null;\n        this.Qk = new Re;\n        this.ns = this.ms = null;\n        this.Op = !1;\n        this.commandHandler = zi();\n        this.sg = !0;\n        Bi(this);\n        this.layout = new Ci;\n        this.sg = !1;\n        this.model = Ai();\n        this.model.undoManager = new we;\n        this.ie = !1;\n        this.sj = !0;\n        this.we = !1;\n        this.Sb = 1;\n        this.uh = null;\n        this.Bo = 1;\n        this.Io = 0;\n        this.Jo = [0, 0, 0, 0, 0];\n        this.Ko = 0;\n        this.od = 1;\n        this.Aj = 0;\n        this.lo = new I;\n        this.Us = 500;\n        this.$m = new I;\n        this.je = !1;\n        this.nh = this.Gl = this.mh = this.Fl = null;\n        this.Pp = this.$n = !1;\n        this.In = null;\n        this.Jn = Jb;\n        this.Rb = !1;\n        this.M()\n    };\n\n    function si(a) {\n        a.Ye = new H;\n        var b = new W,\n            c = new Wg;\n        c.bind(new Ji(\"text\", \"\", Ja));\n        b.add(c);\n        a.gu = b;\n        a.Ye.add(\"\", b);\n        b = new W;\n        c = new Wg;\n        c.stroke = \"brown\";\n        c.bind(new Ji(\"text\", \"\", Ja));\n        b.add(c);\n        a.Ye.add(\"Comment\", b);\n        b = new W;\n        b.selectable = !1;\n        b.avoidable = !1;\n        c = new Lf;\n        c.figure = \"Ellipse\";\n        c.fill = \"black\";\n        c.stroke = null;\n        c.desiredSize = (new M(3, 3)).ca();\n        b.add(c);\n        a.Ye.add(\"LinkLabel\", b);\n        a.ah = new H;\n        b = new T;\n        b.selectionObjectName = \"GROUPPANEL\";\n        b.type = X.Vertical;\n        c = new Wg;\n        c.font = \"bold 12pt sans-serif\";\n        c.bind(new Ji(\"text\", \"\", Ja));\n        b.add(c);\n        c = new X(X.Auto);\n        c.name = \"GROUPPANEL\";\n        var d = new Lf;\n        d.figure = \"Rectangle\";\n        d.fill = \"rgba(128,128,128,0.2)\";\n        d.stroke = \"black\";\n        c.add(d);\n        d = new xg;\n        d.padding = (new oc(5, 5, 5, 5)).ca();\n        c.add(d);\n        b.add(c);\n        a.eu = b;\n        a.ah.add(\"\", b);\n        a.ag = new H;\n        b = new S;\n        c = new Lf;\n        c.isPanelMain = !0;\n        b.add(c);\n        c = new Lf;\n        c.toArrow = \"Standard\";\n        c.fill = \"black\";\n        c.stroke = null;\n        c.strokeWidth = 0;\n        b.add(c);\n        a.fu = b;\n        a.ag.add(\"\", b);\n        b = new S;\n        c = new Lf;\n        c.isPanelMain = !0;\n        c.stroke = \"brown\";\n        b.add(c);\n        a.ag.add(\"Comment\", b);\n        b = new Je;\n        b.type = X.Auto;\n        c = new Lf;\n        c.fill = null;\n        c.stroke = \"dodgerblue\";\n        c.strokeWidth = 3;\n        b.add(c);\n        c = new xg;\n        c.margin = (new oc(1.5, 1.5, 1.5, 1.5)).ca();\n        b.add(c);\n        a.Ro = b;\n        a.Vn = b;\n        b = new Je;\n        b.type = X.Link;\n        c = new Lf;\n        c.isPanelMain = !0;\n        c.fill = null;\n        c.stroke = \"dodgerblue\";\n        c.strokeWidth = 3;\n        b.add(c);\n        a.qo = b\n    }\n    R.prototype.setRTL = function (a) {\n        a = void 0 === a ? this.div : a;\n        null === a && (a = x.document.body);\n        var b = ta(\"div\");\n        b.dir = \"rtl\";\n        b.style.cssText = \"font-size: 14px; width: 1px; height: 1px; position: absolute; top: -1000px; overflow: scroll;\";\n        b.textContent = \"A\";\n        a.appendChild(b);\n        var c = \"reverse\";\n        0 < b.scrollLeft ? c = \"default\" : (b.scrollLeft = 1, 0 === b.scrollLeft && (c = \"negative\"));\n        a.removeChild(b);\n        this.zs = c\n    };\n    R.prototype.setScrollWidth = function (a) {\n        a = void 0 === a ? this.div : a;\n        null === a && (a = x.document.body);\n        var b = 0;\n        if (Ug) {\n            var c = Ki;\n            b = Li;\n            null === c && (c = Ki = ta(\"p\"), c.style.width = \"100%\", c.style.height = \"200px\", c.style.boxSizing = \"content-box\", b = Li = ta(\"div\"), b.style.position = \"absolute\", b.style.visibility = \"hidden\", b.style.width = \"200px\", b.style.height = \"150px\", b.style.boxSizing = \"content-box\", b.appendChild(c));\n            b.style.overflow = \"hidden\";\n            a.appendChild(b);\n            var d = c.offsetWidth;\n            b.style.overflow = \"scroll\";\n            c = c.offsetWidth;\n            d === c && (c =\n                b.clientWidth);\n            a.removeChild(b);\n            b = d - c;\n            0 !== b || Xa || (b = 11)\n        }\n        this.jb = b;\n        this.Pu = !0\n    };\n    R.prototype.cb = function (a) {\n        a.classType === R && (this.autoScale = a)\n    };\n    R.prototype.toString = function (a) {\n        void 0 === a && (a = 0);\n        var b = \"\";\n        this.div && this.div.id && (b = this.div.id);\n        b = 'Diagram \"' + b + '\"';\n        if (0 >= a) return b;\n        for (var c = this.Ja.iterator; c.next();) b += \"\\n  \" + c.value.toString(a - 1);\n        return b\n    };\n    R.prototype.addEventListener = function (a, b, c, d) {\n        a.addEventListener(b, c, d)\n    };\n    R.prototype.removeEventListener = function (a, b, c, d) {\n        a.removeEventListener(b, c, d)\n    };\n\n    function Mi(a) {\n        var b = a.sa.Ea;\n        b instanceof HTMLCanvasElement && (a.Vm ? (a.addEventListener(b, \"pointerdown\", a.tm, !1), a.addEventListener(b, \"pointermove\", a.um, !1), a.addEventListener(b, \"pointerup\", a.wm, !1), a.addEventListener(b, \"pointerout\", a.vm, !1)) : (a.addEventListener(b, \"touchstart\", a.pw, !1), a.addEventListener(b, \"touchmove\", a.ow, !1), a.addEventListener(b, \"touchend\", a.nw, !1), a.addEventListener(b, \"mousemove\", a.qk, !1), a.addEventListener(b, \"mousedown\", a.pk, !1), a.addEventListener(b, \"mouseup\", a.sk, !1), a.addEventListener(b,\n            \"mouseout\", a.rk, !1)), a.addEventListener(b, \"mouseenter\", a.dz, !1), a.addEventListener(b, \"mouseleave\", a.ez, !1), a.addEventListener(b, \"wheel\", a.tk, !1), a.addEventListener(b, \"keydown\", a.Xz, !1), a.addEventListener(b, \"keyup\", a.Yz, !1), a.addEventListener(b, \"blur\", a.Ry, !1), a.addEventListener(b, \"focus\", a.Sy, !1), a.addEventListener(b, \"selectstart\", function (a) {\n            a.preventDefault();\n            return !1\n        }, !1), a.addEventListener(b, \"contextmenu\", function (a) {\n            a.preventDefault();\n            return !1\n        }, !1), a.addEventListener(b, \"gesturestart\", function (b) {\n            a.toolManager.gestureBehavior !==\n                Me && (a.toolManager.gestureBehavior === Le ? b.preventDefault() : a.je && a.lastInput.handled || (b.preventDefault(), a.Cl = a.scale, a.currentTool.doCancel()))\n        }, !1), a.addEventListener(b, \"gesturechange\", function (b) {\n            if (a.toolManager.gestureBehavior !== Me)\n                if (a.toolManager.gestureBehavior === Le) b.preventDefault();\n                else if (!a.je || !a.lastInput.handled) {\n                b.preventDefault();\n                var c = b.scale;\n                if (null !== a.Cl) {\n                    var e = a.sa.getBoundingClientRect();\n                    b = new I(b.pageX - window.scrollX - a.wa / e.width * e.left, b.pageY - window.scrollY - a.va / e.height *\n                        e.top);\n                    c = a.Cl * c;\n                    e = a.commandHandler;\n                    if (c !== a.scale && e.canResetZoom(c)) {\n                        var f = a.zoomPoint;\n                        a.zoomPoint = b;\n                        e.resetZoom(c);\n                        a.zoomPoint = f\n                    }\n                }\n            }\n        }, !1), a.addEventListener(x, \"resize\", a.vw, !1))\n    }\n\n    function Ue(a) {\n        30 < a.Io && (a.uh = 1)\n    }\n\n    function kf(a, b) {\n        null !== a.uh && (a.uh = null, b && a.Ht(), a.Io = 0, a.Jo = [0, 0, 0, 0, 0], a.Ko = 0)\n    }\n    R.prototype.computePixelRatio = function () {\n        return null !== this.uh ? this.uh : x.devicePixelRatio || 1\n    };\n    R.prototype.doMouseMove = function () {\n        this.currentTool.doMouseMove()\n    };\n    R.prototype.doMouseDown = function () {\n        this.currentTool.doMouseDown()\n    };\n    R.prototype.doMouseUp = function () {\n        this.currentTool.doMouseUp()\n    };\n    R.prototype.doMouseWheel = function () {\n        this.currentTool.doMouseWheel()\n    };\n    R.prototype.doKeyDown = function () {\n        this.currentTool.doKeyDown()\n    };\n    R.prototype.doKeyUp = function () {\n        this.currentTool.doKeyUp()\n    };\n    R.prototype.doFocus = function () {\n        this.focus()\n    };\n    R.prototype.focus = function () {\n        if (this.sa)\n            if (this.scrollsPageOnFocus) this.sa.focus();\n            else {\n                var a = x.scrollX || x.pageXOffset,\n                    b = x.scrollY || x.pageYOffset;\n                this.sa.focus();\n                x.scrollTo(a, b)\n            }\n    };\n    R.prototype.Sy = function () {\n        this.B.R(\"GainedFocus\")\n    };\n    R.prototype.Ry = function () {\n        this.B.R(\"LostFocus\")\n    };\n\n    function Eh(a) {\n        if (null !== a.sa) {\n            var b = a.La;\n            if (0 !== b.clientWidth && 0 !== b.clientHeight) {\n                a.Pu || a.setScrollWidth();\n                var c = a.Se ? a.jb : 0,\n                    d = a.he ? a.jb : 0,\n                    e = a.Sb;\n                a.Sb = a.computePixelRatio();\n                a.Sb !== e && (a.ll = !0, a.Pb());\n                if (b.clientWidth !== a.wa + c || b.clientHeight !== a.va + d) a.li = !0, a.Ac = !0, b = a.layout, null !== b && b.isViewportSized && a.autoScale === ni && (a.pj = !0, b.C()), a.Bc || a.Pb()\n            }\n        }\n    }\n\n    function Bi(a) {\n        var b = new ei;\n        b.name = \"Background\";\n        a.$l(b);\n        b = new ei;\n        b.name = \"\";\n        a.$l(b);\n        b = new ei;\n        b.name = \"Foreground\";\n        a.$l(b);\n        b = new ei;\n        b.name = \"Adornment\";\n        b.isTemporary = !0;\n        a.$l(b);\n        b = new ei;\n        b.name = \"Tool\";\n        b.isTemporary = !0;\n        b.isBoundsIncluded = !0;\n        a.$l(b);\n        b = new ei;\n        b.name = \"Grid\";\n        b.allowSelect = !1;\n        b.pickable = !1;\n        b.isTemporary = !0;\n        a.tx(b, a.im(\"Background\"))\n    }\n\n    function Ni(a) {\n        a.Fb = new X(X.Grid);\n        a.Fb.name = \"GRID\";\n        var b = new Lf;\n        b.figure = \"LineH\";\n        b.stroke = \"lightgray\";\n        b.strokeWidth = .5;\n        b.interval = 1;\n        a.Fb.add(b);\n        b = new Lf;\n        b.figure = \"LineH\";\n        b.stroke = \"gray\";\n        b.strokeWidth = .5;\n        b.interval = 5;\n        a.Fb.add(b);\n        b = new Lf;\n        b.figure = \"LineH\";\n        b.stroke = \"gray\";\n        b.strokeWidth = 1;\n        b.interval = 10;\n        a.Fb.add(b);\n        b = new Lf;\n        b.figure = \"LineV\";\n        b.stroke = \"lightgray\";\n        b.strokeWidth = .5;\n        b.interval = 1;\n        a.Fb.add(b);\n        b = new Lf;\n        b.figure = \"LineV\";\n        b.stroke = \"gray\";\n        b.strokeWidth = .5;\n        b.interval = 5;\n        a.Fb.add(b);\n        b = new Lf;\n        b.figure =\n            \"LineV\";\n        b.stroke = \"gray\";\n        b.strokeWidth = 1;\n        b.interval = 10;\n        a.Fb.add(b);\n        b = new U;\n        b.add(a.Fb);\n        b.layerName = \"Grid\";\n        b.zOrder = 0;\n        b.isInDocumentBounds = !1;\n        b.isAnimated = !1;\n        b.pickable = !1;\n        b.locationObjectName = \"GRID\";\n        a.add(b);\n        a.partManager.parts.remove(b);\n        a.Fb.visible = !1\n    }\n\n    function Oi() {\n        this.B.Bs ? this.B.Bs = !1 : this.B.isEnabled ? this.B.Ex(this) : Pi(this.B)\n    }\n\n    function Qi(a) {\n        this.B.isEnabled ? (this.B.Fs = a.target.scrollTop, this.B.Ds = a.target.scrollLeft) : Pi(this.B)\n    }\n    R.prototype.Ex = function (a) {\n        if (null !== this.sa) {\n            this.vp = !0;\n            var b = this.documentBounds,\n                c = this.viewportBounds,\n                d = this.Fi,\n                e = b.x - d.left,\n                f = b.y - d.top,\n                g = b.width + d.left + d.right,\n                h = b.height + d.top + d.bottom,\n                k = b.right + d.right;\n            d = b.bottom + d.bottom;\n            var l = c.x;\n            b = c.y;\n            var m = c.width,\n                n = c.height,\n                p = c.right,\n                r = c.bottom;\n            c = this.scale;\n            var q = a.scrollLeft;\n            if (this.nl) switch (this.zs) {\n                case \"negative\":\n                    q = q + a.scrollWidth - a.clientWidth;\n                    break;\n                case \"reverse\":\n                    q = a.scrollWidth - q - a.clientWidth\n            }\n            var u = q;\n            m < g || n < h ? (q = I.allocAt(this.position.x, this.position.y),\n                this.allowHorizontalScroll && this.Ds !== u && (q.x = u / c + e, this.Ds = u), this.allowVerticalScroll && this.Fs !== a.scrollTop && (q.y = a.scrollTop / c + f, this.Fs = a.scrollTop), this.position = q, I.free(q), this.li = this.vp = !1) : (q = I.alloc(), a.Ay && this.allowHorizontalScroll && (e < l && (this.position = q.h(u + e, this.position.y)), k > p && (this.position = q.h(-(this.Es.scrollWidth - this.wa) + u - this.wa / c + k, this.position.y))), a.By && this.allowVerticalScroll && (f < b && (this.position = q.h(this.position.x, a.scrollTop + f)), d > r && (this.position = q.h(this.position.x,\n                -(this.Es.scrollHeight - this.va) + a.scrollTop - this.va / c + d))), I.free(q), Ri(this), this.li = this.vp = !1, b = this.documentBounds, c = this.viewportBounds, k = b.right, p = c.right, d = b.bottom, r = c.bottom, e = b.x, l = c.x, f = b.y, b = c.y, m >= g && e >= l && k <= p && (this.wp.style.width = \"1px\"), n >= h && f >= b && d <= r && (this.wp.style.height = \"1px\"))\n        }\n    };\n    R.prototype.computeBounds = function () {\n        0 < this.nd.count && Si(this);\n        return Ti(this)\n    };\n\n    function Ti(a) {\n        if (a.fixedBounds.v()) {\n            var b = a.fixedBounds.copy();\n            b.cq(a.bb);\n            return b\n        }\n        for (var c = !0, d = a.Ja.j, e = d.length, f = 0; f < e; f++) {\n            var g = d[f];\n            if (g.visible && (!g.isTemporary || g.isBoundsIncluded)) {\n                g = g.Ca.j;\n                for (var h = g.length, k = 0; k < h; k++) {\n                    var l = g[k];\n                    l.isInDocumentBounds && l.isVisible() && (l = l.actualBounds, l.v() && (c ? (c = !1, b = l.copy()) : b.Hc(l)))\n                }\n            }\n        }\n        c && (b = new N(0, 0, 0, 0));\n        b.cq(a.bb);\n        return b\n    }\n    R.prototype.computePartsBounds = function (a, b) {\n        void 0 === b && (b = !1);\n        var c = null;\n        if (Aa(a))\n            for (var d = 0; d < a.length; d++) {\n                var e = a[d];\n                !b && e instanceof S || (e.yb(), null === c ? c = e.actualBounds.copy() : c.Hc(e.actualBounds))\n            } else\n                for (a = a.iterator; a.next();) d = a.value, !b && d instanceof S || (d.yb(), null === c ? c = d.actualBounds.copy() : c.Hc(d.actualBounds));\n        return null === c ? new N(NaN, NaN, 0, 0) : c\n    };\n\n    function Ui(a, b) {\n        if ((b || a.ie) && !a.Rb && null !== a.sa && a.documentBounds.v()) {\n            if (b) {\n                var c = a.initialPosition;\n                if (c.v()) {\n                    a.position = c;\n                    return\n                }\n                c = I.alloc();\n                c.dj(a.documentBounds, a.initialDocumentSpot);\n                var d = a.viewportBounds;\n                d = N.allocAt(0, 0, d.width, d.height);\n                var e = I.alloc();\n                e.dj(d, a.initialViewportSpot);\n                e.h(c.x - e.x, c.y - e.y);\n                a.position = e;\n                N.free(d);\n                I.free(e);\n                I.free(c)\n            }\n            a.Rb = !0;\n            c = a.Lg;\n            b && a.Xf !== ni && (c = a.Xf);\n            d = c !== ni ? Vi(a, c) : a.scale;\n            c = a.viewportBounds.copy();\n            e = a.wa / d;\n            var f = a.va / d,\n                g = a.lj,\n                h = a.Xn;\n            b && !g.eb() && (h.eb() ||\n                h.Mb()) && (g = h.Mb() ? Ac : h);\n            Wi(a, a.documentBounds, e, f, g, b);\n            b = a.scale;\n            a.scale = d;\n            a.Rb = !1;\n            d = a.viewportBounds;\n            d.Ma(c) || a.Bq(c, d, b, !1);\n            Xi(a);\n            Yi(a, !0, !1)\n        }\n    }\n\n    function Vi(a, b) {\n        var c = a.yn;\n        if (null === a.sa) return c;\n        Ii(a);\n        var d = a.documentBounds;\n        if (!d.v()) return c;\n        var e = d.width;\n        d = d.height;\n        var f = a.wa + (a.Se ? a.jb : 0),\n            g = a.va + (a.he ? a.jb : 0),\n            h = f / e,\n            k = g / d;\n        return b === Zi ? (b = Math.min(k, h), b > c && (b = c), b < a.minScale && (b = a.minScale), b > a.maxScale && (b = a.maxScale), b) : b === $i ? (b = k > h ? (g - a.jb) / d : (f - a.jb) / e, b > c && (b = c), b < a.minScale && (b = a.minScale), b > a.maxScale && (b = a.maxScale), b) : a.scale\n    }\n    R.prototype.zoomToFit = function () {\n        var a = this.Gi;\n        this.Gi = Vh;\n        this.scale = Vi(this, Zi);\n        a !== Vh && (Ui(this, !1), Wi(this, this.documentBounds, this.wa / this.ya, this.va / this.ya, this.lj, !1));\n        this.Gi = a\n    };\n    t = R.prototype;\n    t.EA = function (a, b) {\n        void 0 === b && (b = Zi);\n        var c = a.width,\n            d = a.height;\n        if (!(0 === c || 0 === d || isNaN(c) && isNaN(d))) {\n            var e = 1;\n            if (b === Zi || b === $i)\n                if (isNaN(c)) e = this.viewportBounds.height * this.scale / d;\n                else if (isNaN(d)) e = this.viewportBounds.width * this.scale / c;\n            else {\n                e = this.wa;\n                var f = this.va;\n                e = b === $i ? f / d > e / c ? (f - (this.he ? this.jb : 0)) / d : (e - (this.Se ? this.jb : 0)) / c : Math.min(f / d, e / c)\n            }\n            this.scale = e;\n            this.position = new I(a.x, a.y)\n        }\n    };\n    t.My = function (a, b) {\n        Ii(this);\n        var c = this.documentBounds,\n            d = this.viewportBounds;\n        this.position = new I(c.x + (a.x * c.width + a.offsetX) - (b.x * d.width - b.offsetX), c.y + (a.y * c.height + a.offsetY) - (b.y * d.height - b.offsetY))\n    };\n    t.Az = function (a) {\n        if (a instanceof Y) {\n            this.In = a;\n            var b = I.alloc();\n            this.Jn = this.Nq(a.ga(vc, b));\n            I.free(b)\n        } else this.In = null, this.Jn = Jb\n    };\n\n    function Wi(a, b, c, d, e, f) {\n        var g = I.allocAt(a.ma.x, a.ma.y),\n            h = g.x,\n            k = g.y;\n        if (null !== a.In) {\n            var l = I.alloc();\n            l = a.In.ga(vc, l);\n            h = l.x - a.Jn.x / a.scale;\n            k = l.y - a.Jn.y / a.scale;\n            e = uc;\n            I.free(l)\n        }\n        if (f || a.scrollMode === Vh) e.eb() && (c > b.width && (h = b.x + (e.x * b.width + e.offsetX) - (e.x * c - e.offsetX)), d > b.height && (k = b.y + (e.y * b.height + e.offsetY) - (e.y * d - e.offsetY))), e = a.Fi, f = c - b.width, c < b.width + e.left + e.right ? (h = Math.min(h + c / 2, b.right + Math.max(f, e.right) - c / 2), h = Math.max(h, b.left - Math.max(f, e.left) + c / 2), h -= c / 2) : h > b.left ? h = b.left : h < b.right -\n            c && (h = b.right - c), c = d - b.height, d < b.height + e.top + e.bottom ? (k = Math.min(k + d / 2, b.bottom + Math.max(c, e.bottom) - d / 2), k = Math.max(k, b.top - Math.max(c, e.top) + d / 2), k -= d / 2) : k > b.top ? k = b.top : k < b.bottom - d && (k = b.bottom - d);\n        g.x = isFinite(h) ? h : -a.bb.left;\n        g.y = isFinite(k) ? k : -a.bb.top;\n        null !== a.positionComputation && (b = a.positionComputation(a, g), g.x = b.x, g.y = b.y);\n        a.Jc.qc && Oh(a.Jc, a.ma, g);\n        a.ma.h(g.x, g.y);\n        I.free(g)\n    }\n    t.jm = function (a, b) {\n        void 0 === b && (b = !0);\n        if (b) {\n            if (a = vf(this, a, function (a) {\n                    return a.part\n                }, function (a) {\n                    return a.canSelect()\n                }), a instanceof U) return a\n        } else if (a = vf(this, a, function (a) {\n                return a.part\n            }), a instanceof U) return a;\n        return null\n    };\n    t.Ub = function (a, b, c) {\n        void 0 === b && (b = null);\n        void 0 === c && (c = null);\n        Si(this);\n        for (var d = this.Ja.iteratorBackwards; d.next();) {\n            var e = d.value;\n            if (e.visible && (e = e.Ub(a, b, c), null !== e)) return e\n        }\n        return null\n    };\n\n    function vf(a, b, c, d) {\n        void 0 === c && (c = null);\n        void 0 === d && (d = null);\n        Si(a);\n        for (a = a.Ja.iteratorBackwards; a.next();) {\n            var e = a.value;\n            if (e.visible && !e.isTemporary && (e = e.Ub(b, c, d), null !== e)) return e\n        }\n        return null\n    }\n    t.nz = function (a, b, c) {\n        void 0 === b && (b = !0);\n        return aj(this, a, function (a) {\n            return a.part\n        }, b ? function (a) {\n            return a instanceof U && a.canSelect()\n        } : null, c)\n    };\n\n    function aj(a, b, c, d, e) {\n        void 0 === c && (c = null);\n        void 0 === d && (d = null);\n        e instanceof E || e instanceof F || (e = new F);\n        Si(a);\n        for (a = a.Ja.iteratorBackwards; a.next();) {\n            var f = a.value;\n            f.visible && !f.isTemporary && f.Ti(b, c, d, e)\n        }\n        return e\n    }\n    t.Ti = function (a, b, c, d) {\n        void 0 === b && (b = null);\n        void 0 === c && (c = null);\n        d instanceof E || d instanceof F || (d = new F);\n        Si(this);\n        for (var e = this.Ja.iteratorBackwards; e.next();) {\n            var f = e.value;\n            f.visible && f.Ti(a, b, c, d)\n        }\n        return d\n    };\n    t.Mx = function (a, b, c, d) {\n        void 0 === b && (b = !1);\n        void 0 === c && (c = !0);\n        return bj(this, a, function (a) {\n            return a instanceof U && (!c || a.canSelect())\n        }, b, d)\n    };\n    t.tf = function (a, b, c, d, e) {\n        void 0 === b && (b = null);\n        void 0 === c && (c = null);\n        void 0 === d && (d = !1);\n        e instanceof E || e instanceof F || (e = new F);\n        Si(this);\n        for (var f = this.Ja.iteratorBackwards; f.next();) {\n            var g = f.value;\n            g.visible && g.tf(a, b, c, d, e)\n        }\n        return e\n    };\n    t.uv = function (a, b, c, d, e, f) {\n        var g = new F;\n        Si(this);\n        for (var h = this.Ja.iteratorBackwards; h.next();) {\n            var k = h.value;\n            k.visible && k.uv(a, b, c, d, g, e, f)\n        }\n        return g\n    };\n\n    function bj(a, b, c, d, e) {\n        var f = null;\n        void 0 === f && (f = null);\n        void 0 === c && (c = null);\n        void 0 === d && (d = !1);\n        e instanceof E || e instanceof F || (e = new F);\n        Si(a);\n        for (a = a.Ja.iteratorBackwards; a.next();) {\n            var g = a.value;\n            g.visible && !g.isTemporary && g.tf(b, f, c, d, e)\n        }\n        return e\n    }\n    t.oz = function (a, b, c, d, e) {\n        void 0 === c && (c = !0);\n        void 0 === d && (d = !0);\n        return cj(this, a, b, function (a) {\n            return a instanceof U && (!d || a.canSelect())\n        }, c, e)\n    };\n    t.Ag = function (a, b, c, d, e, f) {\n        void 0 === c && (c = null);\n        void 0 === d && (d = null);\n        void 0 === e && (e = !0);\n        if (!1 !== e && !0 !== e) {\n            if (e instanceof E || e instanceof F) f = e;\n            e = !0\n        }\n        f instanceof E || f instanceof F || (f = new F);\n        Si(this);\n        for (var g = this.Ja.iteratorBackwards; g.next();) {\n            var h = g.value;\n            h.visible && h.Ag(a, b, c, d, e, f)\n        }\n        return f\n    };\n\n    function cj(a, b, c, d, e, f) {\n        var g = null;\n        void 0 === g && (g = null);\n        void 0 === d && (d = null);\n        void 0 === e && (e = !0);\n        if (!1 !== e && !0 !== e) {\n            if (e instanceof E || e instanceof F) f = e;\n            e = !0\n        }\n        f instanceof E || f instanceof F || (f = new F);\n        Si(a);\n        for (a = a.Ja.iteratorBackwards; a.next();) {\n            var h = a.value;\n            h.visible && !h.isTemporary && h.Ag(b, c, g, d, e, f)\n        }\n        return f\n    }\n    R.prototype.acceptEvent = function (a) {\n        return dj(this, a, a instanceof MouseEvent)\n    };\n\n    function dj(a, b, c) {\n        var d = a.Pd;\n        a.Pd = a.dh;\n        a.dh = d;\n        d.diagram = a;\n        d.event = b;\n        c ? ej(a, b, d) : (d.viewPoint = a.Pd.viewPoint, d.documentPoint = a.Pd.documentPoint);\n        a = 0;\n        b.ctrlKey && (a += 1);\n        b.altKey && (a += 2);\n        b.shiftKey && (a += 4);\n        b.metaKey && (a += 8);\n        d.modifiers = a;\n        d.button = b.button;\n        void 0 === b.buttons || Sa || (d.buttons = b.buttons);\n        Wa && 0 === b.button && b.ctrlKey && (d.button = 2);\n        d.down = !1;\n        d.up = !1;\n        d.clickCount = 1;\n        d.delta = 0;\n        d.handled = !1;\n        d.bubbles = !1;\n        d.timestamp = b.timeStamp;\n        d.isMultiTouch = !1;\n        d.targetDiagram = fj(b);\n        d.targetObject = null;\n        return d\n    }\n\n    function fj(a) {\n        var b = a.target.B;\n        if (!b) {\n            var c = a.path;\n            c || \"function\" !== typeof a.composedPath || (c = a.composedPath());\n            c && c[0] && (b = c[0].B)\n        }\n        return b ? b : null\n    }\n\n    function gj(a, b, c, d) {\n        var e = hj(a, b, !0, !1, !0, d);\n        ej(a, c, e);\n        e.targetDiagram = fj(b);\n        e.targetObject = null;\n        d || e.clone(a.Uf);\n        return e\n    }\n\n    function ij(a, b, c, d) {\n        var e;\n        d = hj(a, b, !1, !1, !1, d);\n        null !== c ? ((e = x.document.elementFromPoint(c.clientX, c.clientY)) && e.B ? (b = c, c = e.B) : (b = void 0 !== b.targetTouches ? b.targetTouches[0] : b, c = a), d.targetDiagram = c, ej(a, b, d)) : null !== a.Pd ? (d.documentPoint = a.Pd.documentPoint, d.viewPoint = a.Pd.viewPoint, d.targetDiagram = a.Pd.targetDiagram) : null !== a.Uf && (d.documentPoint = a.Uf.documentPoint, d.viewPoint = a.Uf.viewPoint, d.targetDiagram = a.Uf.targetDiagram);\n        d.targetObject = null;\n        return d\n    }\n\n    function hj(a, b, c, d, e, f) {\n        var g = a.Pd;\n        a.Pd = a.dh;\n        a.dh = g;\n        g.diagram = a;\n        g.clickCount = 1;\n        var h = g.delta = 0;\n        b.ctrlKey && (h += 1);\n        b.altKey && (h += 2);\n        b.shiftKey && (h += 4);\n        b.metaKey && (h += 8);\n        g.modifiers = h;\n        g.button = 0;\n        g.buttons = 1;\n        g.event = b;\n        g.timestamp = b.timeStamp;\n        a.Vm && b instanceof x.PointerEvent && \"touch\" !== b.pointerType && (g.button = b.button, void 0 === b.buttons || Sa || (g.buttons = b.buttons), Wa && 0 === b.button && b.ctrlKey && (g.button = 2));\n        g.down = c;\n        g.up = d;\n        g.handled = !1;\n        g.bubbles = e;\n        g.isMultiTouch = f;\n        return g\n    }\n\n    function jj(a, b) {\n        if (a.bubbles) return !0;\n        void 0 !== b.stopPropagation && b.stopPropagation();\n        !1 !== b.cancelable && b.preventDefault();\n        b.cancelBubble = !0;\n        return !1\n    }\n    R.prototype.Xz = function (a) {\n        var b = this.B;\n        if (!this.B.isEnabled) return !1;\n        var c = dj(b, a, !1);\n        c.key = String.fromCharCode(a.which);\n        c.down = !0;\n        switch (a.which) {\n            case 8:\n                c.key = \"Backspace\";\n                break;\n            case 33:\n                c.key = \"PageUp\";\n                break;\n            case 34:\n                c.key = \"PageDown\";\n                break;\n            case 35:\n                c.key = \"End\";\n                break;\n            case 36:\n                c.key = \"Home\";\n                break;\n            case 37:\n                c.key = \"Left\";\n                break;\n            case 38:\n                c.key = \"Up\";\n                break;\n            case 39:\n                c.key = \"Right\";\n                break;\n            case 40:\n                c.key = \"Down\";\n                break;\n            case 45:\n                c.key = \"Insert\";\n                break;\n            case 46:\n                c.key = \"Del\";\n                break;\n            case 48:\n                c.key = \"0\";\n                break;\n            case 187:\n            case 61:\n            case 107:\n                c.key =\n                    \"Add\";\n                break;\n            case 189:\n            case 173:\n            case 109:\n                c.key = \"Subtract\";\n                break;\n            case 27:\n                c.key = \"Esc\"\n        }\n        b.doKeyDown();\n        return jj(c, a)\n    };\n    R.prototype.Yz = function (a) {\n        var b = this.B;\n        if (!b.isEnabled) return !1;\n        var c = dj(b, a, !1);\n        c.key = String.fromCharCode(a.which);\n        c.up = !0;\n        switch (a.which) {\n            case 8:\n                c.key = \"Backspace\";\n                break;\n            case 33:\n                c.key = \"PageUp\";\n                break;\n            case 34:\n                c.key = \"PageDown\";\n                break;\n            case 35:\n                c.key = \"End\";\n                break;\n            case 36:\n                c.key = \"Home\";\n                break;\n            case 37:\n                c.key = \"Left\";\n                break;\n            case 38:\n                c.key = \"Up\";\n                break;\n            case 39:\n                c.key = \"Right\";\n                break;\n            case 40:\n                c.key = \"Down\";\n                break;\n            case 45:\n                c.key = \"Insert\";\n                break;\n            case 46:\n                c.key = \"Del\"\n        }\n        b.doKeyUp();\n        return jj(c, a)\n    };\n    R.prototype.dz = function (a) {\n        var b = this.B;\n        if (!b.isEnabled) return !1;\n        var c = dj(b, a, !0);\n        null !== b.mouseEnter && b.mouseEnter(c);\n        return jj(c, a)\n    };\n    R.prototype.ez = function (a) {\n        var b = this.B;\n        if (!b.isEnabled) return !1;\n        var c = dj(b, a, !0);\n        null !== b.mouseLeave && b.mouseLeave(c);\n        return jj(c, a)\n    };\n    R.prototype.getMouse = function (a) {\n        var b = this.sa;\n        if (null === b) return new I(0, 0);\n        var c = b.getBoundingClientRect();\n        b = a.clientX - this.wa / c.width * c.left;\n        a = a.clientY - this.va / c.height * c.top;\n        return null !== this.kb ? zb(new I(b, a), this.kb) : new I(b, a)\n    };\n\n    function ej(a, b, c) {\n        var d = a.sa,\n            e = a.wa,\n            f = a.va,\n            g = 0,\n            h = 0;\n        null !== d && (d = d.getBoundingClientRect(), g = b.clientX - e / d.width * d.left, h = b.clientY - f / d.height * d.top);\n        c.viewPoint.h(g, h);\n        null !== a.kb ? (b = I.allocAt(g, h), a.kb.Vd(b), c.documentPoint.assign(b), I.free(b)) : c.documentPoint.h(g, h)\n    }\n\n    function oe(a, b, c, d) {\n        if (void 0 !== b.targetTouches) {\n            if (2 > b.targetTouches.length) return;\n            b = b.targetTouches[c]\n        } else if (null !== a.Kj[0]) b = a.Kj[c];\n        else return;\n        c = a.sa;\n        null !== c && (c = c.getBoundingClientRect(), d.h(b.clientX - a.wa / c.width * c.left, b.clientY - a.va / c.height * c.top))\n    }\n    t = R.prototype;\n    t.Na = function () {\n        this.ki || (this.ki = !0, this.Pb(!0))\n    };\n\n    function kj(a) {\n        a.Bc || Si(a);\n        Ii(a)\n    }\n    t.Ee = function () {\n        this.Rb || this.Bc || (this.M(), Xi(this), Ri(this), this.Na(), this.Wc())\n    };\n    t.Wz = function () {\n        return this.we\n    };\n    t.Zy = function (a) {\n        void 0 === a && (a = null);\n        var b = this.animationManager,\n            c = b.isEnabled;\n        b.Xc();\n        b.isEnabled = !1;\n        If(this);\n        this.ie = !1;\n        b.isEnabled = c;\n        null !== a && sa(function () {\n            zh(b, \"Model\");\n            a()\n        }, 1)\n    };\n    t.Pb = function (a) {\n        void 0 === a && (a = !1);\n        if (!0 !== this.we && !(this.Rb || !1 === a && this.Bc)) {\n            this.we = !0;\n            var b = this;\n            x.requestAnimationFrame(function () {\n                b.we && b.Wc()\n            })\n        }\n    };\n    t.Wc = function () {\n        if (!this.sj || this.we) this.sj && (this.sj = !1), If(this)\n    };\n\n    function Yi(a, b, c) {\n        a.animationManager.defaultAnimation.isAnimating || a.Rb || !a.li || Pi(a) || (b && Si(a), c && Ui(a, !1))\n    }\n\n    function If(a, b) {\n        if (!a.Bc && (a.we = !1, null !== a.La || a.Zl.v())) {\n            a.Bc = !0;\n            var c = a.animationManager,\n                d = a.ss;\n            if (!c.isAnimating && 0 !== d.length) {\n                for (var e = d.j, f = e.length, g = 0; g < f; g++) {\n                    var h = e[g];\n                    lj(h, !1);\n                    h.o()\n                }\n                d.clear()\n            }\n            d = a.su;\n            0 < d.count && (d.each(function (a) {\n                a.uw()\n            }), d.clear());\n            e = d = !1;\n            c.isAnimating && (e = !0, d = a.skipsUndoManager, a.skipsUndoManager = !0);\n            c.qc || Eh(a);\n            Yi(a, !1, !1);\n            null !== a.Fb && (a.Fb.visible && !a.Un && (mj(a), a.Un = !0), !a.Fb.visible && a.Un && (a.Un = !1));\n            Si(a);\n            f = !1;\n            if (!a.ie || a.If) a.ie ? nj(a, !a.pj) : (a.ua(\"Initial Layout\"),\n                !1 === c.isEnabled && c.Xc(), nj(a, !1)), f = !0;\n            a.pj = !1;\n            Si(a);\n            a.Ls || kj(a);\n            Yi(a, !0, !1);\n            g = !1;\n            f ? (a.ie || (g = a.ie = !0, oj(a)), a.R(\"LayoutCompleted\")) : c.gl && c.px && (a.Xf !== ni ? a.scale = Vi(a, a.Xf) : a.Lg !== ni ? a.scale = Vi(a, a.Lg) : (c = a.initialScale, isFinite(c) && 0 < c && (a.scale = c)), Ui(a, !0));\n            Si(a);\n            f && g && (a.Ua(\"Initial Layout\"), a.skipsUndoManager || a.undoManager.clear(), sa(function () {\n                a.isModified = !1\n            }, 1));\n            a.gv();\n            b || a.bc(a.Db);\n            e && (a.skipsUndoManager = d);\n            a.Bc = !1\n        }\n    }\n\n    function oj(a) {\n        var b = a.ya;\n        if (a.Xf !== ni) a.scale = Vi(a, a.Xf);\n        else if (a.Lg !== ni) a.scale = Vi(a, a.Lg);\n        else {\n            var c = a.initialScale;\n            isFinite(c) && 0 < c && (a.scale = c)\n        }\n        a.ya !== b && (Xi(a), Yi(a, !0, !1));\n        Ui(a, !0);\n        a.Nu.assign(a.ma);\n        b = a.Ja.j;\n        a.yd(b, b.length, a);\n        a.R(\"InitialLayoutCompleted\");\n        mj(a)\n    }\n\n    function Si(a) {\n        if ((a.Bc || !a.animationManager.isTicking) && 0 !== a.nd.count) {\n            for (var b = 0; 23 > b; b++) {\n                var c = a.nd.iterator;\n                if (null === c || 0 === a.nd.count) break;\n                a.nd = new F;\n                a.uw(c, a.nd)\n            }\n            a.nodes.each(function (a) {\n                a instanceof T && 0 !== (a.P & 65536) !== !1 && (a.P = a.P ^ 65536)\n            })\n        }\n    }\n    t.uw = function (a, b) {\n        for (a.reset(); a.next();) {\n            var c = a.value;\n            !c.Wb() || c instanceof T || (c.bj() ? (c.measure(Infinity, Infinity), c.arrange()) : b.add(c))\n        }\n        for (a.reset(); a.next();) c = a.value, c instanceof T && c.isVisible() && pj(this, c);\n        for (a.reset(); a.next();) c = a.value, c instanceof S && c.isVisible() && (c.bj() ? (c.measure(Infinity, Infinity), c.arrange()) : b.add(c));\n        for (a.reset(); a.next();) c = a.value, c instanceof Je && c.isVisible() && (c.bj() ? (c.measure(Infinity, Infinity), c.arrange()) : b.add(c))\n    };\n\n    function pj(a, b) {\n        for (var c = Fa(), d = Fa(), e = b.memberParts; e.next();) {\n            var f = e.value;\n            f.isVisible() && (f instanceof T ? (qj(f) || rj(f) || sj(f)) && pj(a, f) : f instanceof S ? f.fromNode === b || f.toNode === b ? d.push(f) : c.push(f) : (f.measure(Infinity, Infinity), f.arrange()))\n        }\n        a = c.length;\n        for (e = 0; e < a; e++) f = c[e], f.measure(Infinity, Infinity), f.arrange();\n        Ha(c);\n        b.measure(Infinity, Infinity);\n        b.arrange();\n        a = d.length;\n        for (b = 0; b < a; b++) c = d[b], c.measure(Infinity, Infinity), c.arrange();\n        Ha(d)\n    }\n    t.yd = function (a, b, c, d) {\n        if (this.mi || this.animationManager.isAnimating)\n            for (var e = 0; e < b; e++) a[e].yd(c, d)\n    };\n    t.bc = function (a, b) {\n        void 0 === b && (b = null);\n        if (null !== this.La) {\n            null === this.sa && B(\"No canvas specified\");\n            var c = this.animationManager;\n            if (!c.qc && (!c.isAnimating || c.isTicking)) {\n                var d = new Date;\n                tj(this);\n                if (\"0\" !== this.La.style.opacity) {\n                    var e = a !== this.Db,\n                        f = this.Ja.j,\n                        g = f.length,\n                        h = this;\n                    this.yd(f, g, h);\n                    if (e) a.sc(!0), Ri(this);\n                    else if (!this.Ac && null === b && !c.isAnimating) return;\n                    g = this.ma;\n                    var k = this.ya,\n                        l = Math.round(g.x * k) / k,\n                        m = Math.round(g.y * k) / k;\n                    c = this.kb;\n                    c.reset();\n                    1 !== k && c.scale(k);\n                    0 === g.x && 0 === g.y || c.translate(-l, -m);\n                    k = this.Sb;\n                    a.setTransform(1, 0, 0, 1, 0, 0);\n                    a.scale(k, k);\n                    a.clearRect(0, 0, this.wa, this.va);\n                    a.setTransform(1, 0, 0, 1, 0, 0);\n                    a.scale(k, k);\n                    a.transform(c.m11, c.m12, c.m21, c.m22, c.dx, c.dy);\n                    uj(this, a);\n                    a.globalAlpha = this.qb;\n                    l = null !== b ? function (c) {\n                        var d = b;\n                        if (c.visible && 0 !== c.qb) {\n                            var e = c.Ca.j,\n                                f = e.length;\n                            if (0 !== f) {\n                                var g = hi(c, a),\n                                    k = c.Yo;\n                                k.length = 0;\n                                for (var l = h.scale, m = N.alloc(), n = 0; n < f; n++) {\n                                    var A = e[n];\n                                    d.contains(A) || c.Pi(a, A, h, k, l, m)\n                                }\n                                N.free(m);\n                                a.globalAlpha = g\n                            }\n                        }\n                    } : function (b) {\n                        b.bc(a, h)\n                    };\n                    g = f.length;\n                    for (m = 0; m < g; m++) a.setTransform(1,\n                        0, 0, 1, 0, 0), a.scale(k, k), a.transform(c.m11, c.m12, c.m21, c.m22, c.dx, c.dy), l(f[m]);\n                    this.ji && vj(this.ji, this) && this.zr();\n                    e ? (this.Db.sc(!0), Ri(this)) : this.Ac = this.mi = !1;\n                    e = +new Date - +d;\n                    if (null === this.uh) {\n                        d = this.Jo;\n                        d[this.Ko] = e;\n                        this.Ko = (this.Ko + 1) % d.length;\n                        for (f = e = 0; f < this.Jo.length; f++) e += this.Jo[f];\n                        this.Io = e / d.length\n                    }\n                }\n            }\n        }\n    };\n\n    function wj(a, b, c, d, e, f, g, h, k, l) {\n        if (null !== a.La) {\n            null === a.sa && B(\"No canvas specified\");\n            void 0 === g && (g = null);\n            void 0 === h && (h = null);\n            void 0 === k && (k = !1);\n            void 0 === l && (l = !1);\n            tj(a);\n            a.Db.sc(!0);\n            Ri(a);\n            a.ni = !0;\n            var m = a.ya;\n            a.ya = e;\n            var n = a.Ja.j,\n                p = n.length;\n            try {\n                var r = new N(f.x, f.y, d.width / e, d.height / e),\n                    q = r.copy();\n                q.cq(c);\n                mj(a, q);\n                Si(a);\n                a.yd(n, p, a, r);\n                var u = a.Sb;\n                b.setTransform(1, 0, 0, 1, 0, 0);\n                b.scale(u, u);\n                b.clearRect(0, 0, d.width, d.height);\n                null !== h && \"\" !== h && (b.fillStyle = h, b.fillRect(0, 0, d.width, d.height));\n                var v = rd.alloc();\n                v.reset();\n                v.translate(c.left, c.top);\n                v.scale(e);\n                0 === f.x && 0 === f.y || v.translate(-f.x, -f.y);\n                b.setTransform(v.m11, v.m12, v.m21, v.m22, v.dx, v.dy);\n                rd.free(v);\n                uj(a, b);\n                b.globalAlpha = a.qb;\n                if (null !== g) {\n                    var w = new F,\n                        y = g.iterator;\n                    for (y.reset(); y.next();) {\n                        var z = y.value;\n                        !1 === l && \"Grid\" === z.layer.name || null === z || w.add(z)\n                    }\n                    var A = function (c) {\n                        if (c.visible && 0 !== c.qb && (k || !c.isTemporary)) {\n                            var d = c.Ca.j,\n                                e = d.length;\n                            if (0 !== e) {\n                                var f = hi(c, b),\n                                    g = c.Yo;\n                                g.length = 0;\n                                for (var h = a.scale, l = N.alloc(), m = 0; m < e; m++) {\n                                    var n = d[m];\n                                    w.contains(n) &&\n                                        c.Pi(b, n, a, g, h, l)\n                                }\n                                N.free(l);\n                                b.globalAlpha = f\n                            }\n                        }\n                    }\n                } else if (!k && l) {\n                    var C = a.grid.part,\n                        G = C.layer;\n                    A = function (c) {\n                        c === G ? C.bc(b, a) : c.bc(b, a, k)\n                    }\n                } else A = function (c) {\n                    c.bc(b, a, k)\n                };\n                for (c = 0; c < p; c++) A(n[c]);\n                a.ni = !1;\n                a.ji && vj(a.ji, a) && a.zr()\n            } finally {\n                a.ya = m, a.Db.sc(!0), Ri(a), a.yd(n, p, a), mj(a)\n            }\n        }\n    }\n    t.Be = function (a) {\n        return this.bf[a]\n    };\n    t.ly = function (a, b) {\n        \"minDrawingLength\" === a && (this.Bo = b);\n        this.bf[a] = b;\n        this.Ee()\n    };\n    t.aw = function () {\n        this.bf = new db;\n        this.bf.drawShadows = !0;\n        this.bf.textGreeking = !0;\n        this.bf.viewportOptimizations = Xa || Ta || Ua ? !1 : !0;\n        this.bf.temporaryPixelRatio = !0;\n        this.bf.pictureRatioOptimization = !0;\n        this.Bo = this.bf.minDrawingLength = 1\n    };\n\n    function uj(a, b) {\n        a = a.bf;\n        null !== a && (void 0 !== a.imageSmoothingEnabled && b.ky(!!a.imageSmoothingEnabled), a = a.defaultFont, void 0 !== a && null !== a && (b.font = a))\n    }\n    t.mm = function (a) {\n        return this.vj[a]\n    };\n    t.tA = function (a, b) {\n        this.vj[a] = b\n    };\n    t.$v = function () {\n        this.vj = new db;\n        this.vj.extraTouchArea = 10;\n        this.vj.extraTouchThreshold = 10;\n        this.vj.hasGestureZoom = !0\n    };\n    t.iw = function (a) {\n        xj(this, a)\n    };\n\n    function xj(a, b) {\n        var c = a instanceof X,\n            d = a instanceof R,\n            e;\n        for (e in b) {\n            \"\" === e && B(\"Setting properties requires non-empty property names\");\n            var f = a,\n                g = e;\n            if (c || d) {\n                var h = e.indexOf(\".\");\n                if (0 < h) {\n                    var k = e.substring(0, h);\n                    if (c) f = a.Xa(k);\n                    else if (f = a[k], void 0 === f || null === f) f = a.toolManager[k];\n                    za(f) ? g = e.substr(h + 1) : B(\"Unable to find object named: \" + k + \" in \" + a.toString() + \" when trying to set property: \" + e)\n                }\n            }\n            if (\"_\" !== g[0] && !Ka(f, g))\n                if (d && \"ModelChanged\" === g) {\n                    a.vx(b[g]);\n                    continue\n                } else if (d && \"Changed\" === g) {\n                a.Dh(b[g]);\n                continue\n            } else if (d &&\n                Ka(a.toolManager, g)) f = a.toolManager;\n            else if (d && yj(a, g)) {\n                a.Uj(g, b[g]);\n                continue\n            } else if (a instanceof Z && \"Changed\" === g) {\n                a.Dh(b[g]);\n                continue\n            } else B('Trying to set undefined property \"' + g + '\" on object: ' + f.toString());\n            f[g] = b[e];\n            \"_\" === g[0] && f instanceof Y && f.sx(g)\n        }\n    }\n    t.gv = function () {\n        if (0 === this.undoManager.transactionLevel && 0 !== this.Sg.count) {\n            for (; 0 < this.Sg.count;) {\n                var a = this.Sg;\n                this.Sg = new H;\n                for (a = a.iterator; a.next();) {\n                    var b = a.key;\n                    b.tq(a.value);\n                    b.cc()\n                }\n            }\n            this.M()\n        }\n    };\n    t.M = function (a) {\n        void 0 === a && (a = null);\n        if (null === a) this.Ac = !0, this.Pb();\n        else {\n            var b = this.viewportBounds;\n            null !== a && a.v() && b.Gc(a) && (this.Ac = !0, this.Pb())\n        }\n        this.R(\"InvalidateDraw\")\n    };\n    t.Sx = function (a, b) {\n        if (!0 !== this.Ac) {\n            this.Ac = !0;\n            var c = !0 === this.Be(\"temporaryPixelRatio\");\n            if (!0 === this.Be(\"viewportOptimizations\") && this.scrollMode !== Xh && this.Fi.Ri(0, 0, 0, 0) && b.width === a.width && b.height === a.height) {\n                var d = this.scale,\n                    e = Math.max(a.x, b.x),\n                    f = Math.max(a.y, b.y);\n                d = N.allocAt(e, f, Math.max(0, Math.min(a.x + a.width, b.x + b.width) - e) * d, Math.max(0, Math.min(a.y + a.height, b.y + b.height) - f) * d);\n                if (!this.Pp && 0 < d.width && 0 < d.height) {\n                    if (!(this.Bc || (this.we = !1, null === this.La || (this.Bc = !0, this.gv(), this.documentBounds.v() ||\n                            zj(this, this.computeBounds()), e = this.sa, null === e || e instanceof Aj)))) {\n                        var g = this.Sb;\n                        f = this.wa * g;\n                        var h = this.va * g,\n                            k = this.scale * g,\n                            l = Math.round(Math.round(b.x * k) - Math.round(a.x * k));\n                        b = Math.round(Math.round(b.y * k) - Math.round(a.y * k));\n                        k = this.ju;\n                        a = this.Rw;\n                        k.width !== f && (k.width = f);\n                        k.height !== h && (k.height = h);\n                        a.clearRect(0, 0, f, h);\n                        k = 190 * g;\n                        var m = 70 * g,\n                            n = Math.max(l, 0),\n                            p = Math.max(b, 0),\n                            r = Math.floor(f - n),\n                            q = Math.floor(h - p);\n                        a.drawImage(e.Ea, n, p, r, q, 0, 0, r, q);\n                        vj(this.ji, this) && a.clearRect(0, 0, k, m);\n                        e = Fa();\n                        a = Fa();\n                        q = Math.abs(l);\n                        r = Math.abs(b);\n                        var u = 0 === n ? 0 : f - q;\n                        n = I.allocAt(u, 0);\n                        q = I.allocAt(q + u, h);\n                        a.push(new N(Math.min(n.x, q.x), Math.min(n.y, q.y), Math.abs(n.x - q.x), Math.abs(n.y - q.y)));\n                        var v = this.kb;\n                        v.reset();\n                        v.scale(g, g);\n                        1 !== this.ya && v.scale(this.ya);\n                        g = this.ma;\n                        (0 !== g.x || 0 !== g.y) && isFinite(g.x) && isFinite(g.y) && v.translate(-g.x, -g.y);\n                        zb(n, v);\n                        zb(q, v);\n                        e.push(new N(Math.min(n.x, q.x), Math.min(n.y, q.y), Math.abs(n.x - q.x), Math.abs(n.y - q.y)));\n                        u = 0 === p ? 0 : h - r;\n                        n.h(0, u);\n                        q.h(f, r + u);\n                        a.push(new N(Math.min(n.x, q.x), Math.min(n.y, q.y), Math.abs(n.x -\n                            q.x), Math.abs(n.y - q.y)));\n                        zb(n, v);\n                        zb(q, v);\n                        e.push(new N(Math.min(n.x, q.x), Math.min(n.y, q.y), Math.abs(n.x - q.x), Math.abs(n.y - q.y)));\n                        vj(this.ji, this) && (f = 0 < l ? 0 : -l, h = 0 < b ? 0 : -b, n.h(f, h), q.h(k + f, m + h), a.push(new N(Math.min(n.x, q.x), Math.min(n.y, q.y), Math.abs(n.x - q.x), Math.abs(n.y - q.y))), zb(n, v), zb(q, v), e.push(new N(Math.min(n.x, q.x), Math.min(n.y, q.y), Math.abs(n.x - q.x), Math.abs(n.y - q.y))));\n                        I.free(n);\n                        I.free(q);\n                        Yi(this, !1, !0);\n                        null === this.La && B(\"No div specified\");\n                        null === this.sa && B(\"No canvas specified\");\n                        if (!this.animationManager.qc &&\n                            (f = this.Db, this.Ac)) {\n                            tj(this);\n                            h = this.Sb;\n                            f.setTransform(1, 0, 0, 1, 0, 0);\n                            f.clearRect(0, 0, this.wa * h, this.va * h);\n                            f.drawImage(this.ju.Ea, 0 < l ? 0 : Math.round(-l), 0 < b ? 0 : Math.round(-b));\n                            l = this.ma;\n                            g = this.ya;\n                            k = Math.round(l.x * g) / g;\n                            m = Math.round(l.y * g) / g;\n                            b = this.kb;\n                            b.reset();\n                            1 !== g && b.scale(g);\n                            0 === l.x && 0 === l.y || b.translate(-k, -m);\n                            f.save();\n                            f.beginPath();\n                            l = a.length;\n                            for (g = 0; g < l; g++) k = a[g], 0 !== k.width && 0 !== k.height && f.rect(Math.floor(k.x), Math.floor(k.y), Math.ceil(k.width), Math.ceil(k.height));\n                            f.clip();\n                            f.setTransform(1, 0,\n                                0, 1, 0, 0);\n                            f.scale(h, h);\n                            f.transform(b.m11, b.m12, b.m21, b.m22, b.dx, b.dy);\n                            b = this.Ja.j;\n                            l = b.length;\n                            this.yd(b, l, this);\n                            uj(this, f);\n                            f.globalAlpha = this.qb;\n                            for (h = 0; h < l; h++)\n                                if (g = b[h], k = e, g.visible && 0 !== g.qb) {\n                                    m = hi(g, f);\n                                    p = g.Yo;\n                                    p.length = 0;\n                                    n = this.scale;\n                                    r = N.alloc();\n                                    q = g.Ca.j;\n                                    v = q.length;\n                                    u = k.length;\n                                    for (var w = 0; w < v; w++) {\n                                        var y = q[w],\n                                            z = Bj(y, y.actualBounds);\n                                        a: {\n                                            for (var A = 2 / n, C = 4 / n, G = 0; G < u; G++) {\n                                                var L = k[G];\n                                                if (0 !== L.width && 0 !== L.height && z.Ev(L.x - A, L.y - A, L.width + C, L.height + C)) {\n                                                    z = !0;\n                                                    break a\n                                                }\n                                            }\n                                            z = !1\n                                        }\n                                        z && g.Pi(f, y, this, p, n, r)\n                                    }\n                                    N.free(r);\n                                    f.globalAlpha = m\n                                } f.restore();\n                            f.sc(!0);\n                            this.ji && vj(this.ji, this) && this.zr();\n                            this.Ac = this.mi = !1;\n                            this.Ht()\n                        }\n                        Ha(e);\n                        Ha(a);\n                        this.Bc = !1\n                    }\n                } else this.Wc();\n                N.free(d);\n                c && (Ue(this), this.Wc(), kf(this, !0))\n            } else c ? (Ue(this), this.Wc(), kf(this, !0)) : this.Wc()\n        }\n    };\n\n    function Xi(a) {\n        !1 === a.li && (a.li = !0)\n    }\n\n    function Ri(a) {\n        !1 === a.mi && (a.mi = !0)\n    }\n\n    function tj(a) {\n        !1 !== a.ll && (a.ll = !1, Cj(a, a.wa, a.va))\n    }\n\n    function Cj(a, b, c) {\n        var d = a.Sb;\n        a.sa.resize(b * d, c * d, b, c) && (a.Ac = !0, a.Db.sc(!0))\n    }\n\n    function Pi(a) {\n        var b = a.sa;\n        if (null === b) return !0;\n        var c = a.La,\n            d = a.wa,\n            e = a.va,\n            f = a.Zu.copy();\n        if (isNaN(f.width) || isNaN(f.height)) return !0;\n        var g = !1,\n            h = a.Se ? a.jb : 0,\n            k = a.he ? a.jb : 0,\n            l = c.clientWidth || d + h,\n            m = c.clientHeight || e + k;\n        if (l !== d + h || m !== e + k) a.Se = !1, a.he = !1, k = h = 0, a.wa = l, a.va = m, g = a.ll = !0;\n        if (!(g || a.Se || a.he || a.cl || a.dl)) return !0;\n        a.li = !1;\n        var n = a.viewportBounds,\n            p = a.documentBounds,\n            r = 0,\n            q = 0,\n            u = 0,\n            v = 0;\n        c = n.width;\n        var w = n.height,\n            y = a.Fi;\n        a.contentAlignment.eb() ? (p.width > c && (r = y.left, q = y.right), p.height > w && (u = y.top, v = y.bottom)) :\n            (r = y.left, q = y.right, u = y.top, v = y.bottom);\n        y = p.width + r + q;\n        var z = p.height + u + v;\n        r = p.x - r;\n        var A = n.x;\n        q = p.right + q;\n        var C = n.right + h;\n        u = p.y - u;\n        var G = n.y;\n        p = p.bottom + v;\n        n = n.bottom + k;\n        var L = \"1px\",\n            K = \"1px\";\n        v = a.scale;\n        l = y > l / v;\n        m = z > m / v;\n        a.scrollMode === Vh && (l || m) && (l && a.hasHorizontalScrollbar && a.allowHorizontalScroll && (l = 1, r + 1 < A && (l = Math.max((A - r) * v + a.wa, l)), q > C + 1 && (l = Math.max((q - C) * v + a.wa, l)), c + h + 1 < y && (l = Math.max((y - c) * v + a.wa, l)), L = l.toString() + \"px\"), m && a.hasVerticalScrollbar && a.allowVerticalScroll && (l = 1, u + 1 < G && (l = Math.max((G -\n            u) * v + a.va, l)), p > n + 1 && (l = Math.max((p - n) * v + a.va, l)), w + k + 1 < z && (l = Math.max((z - w) * v + a.va, l)), K = l.toString() + \"px\"));\n        l = \"1px\" !== L;\n        m = \"1px\" !== K;\n        l && m || !l && !m || (m && (C -= a.jb), l && (n -= a.jb), y < c + h || !a.hasHorizontalScrollbar || !a.allowHorizontalScroll || (h = 1, r + 1 < A && (h = Math.max((A - r) * v + a.wa, h)), q > C + 1 && (h = Math.max((q - C) * v + a.wa, h)), c + 1 < y && (h = Math.max((y - c) * v + a.wa, h)), L = h.toString() + \"px\"), l = \"1px\" !== L, h = a.va, l !== a.he && (h = l ? a.va - a.jb : a.va + a.jb), z < w + k || !a.hasVerticalScrollbar || !a.allowVerticalScroll || (k = 1, u + 1 < G && (k = Math.max((G -\n            u) * v + h, k)), p > n + 1 && (k = Math.max((p - n) * v + h, k)), w + 1 < z && (k = Math.max((z - w) * v + h, k)), K = k.toString() + \"px\"), m = \"1px\" !== K);\n        if (a.vp && l === a.he && m === a.Se) return d === a.wa && e === a.va || a.Wc(), !1;\n        l !== a.he && (\"1px\" === L ? a.va = a.va + a.jb : a.va = Math.max(a.va - a.jb, 1), g = !0);\n        a.he = l;\n        a.wp.style.width = L;\n        m !== a.Se && (\"1px\" === K ? a.wa = a.wa + a.jb : a.wa = Math.max(a.wa - a.jb, 1), g = !0, a.nl && (k = I.alloc(), m ? (b.style.left = a.jb + \"px\", a.position = k.h(a.ma.x + a.jb / a.scale, a.ma.y)) : (b.style.left = \"0px\", a.position = k.h(a.ma.x - a.jb / a.scale, a.ma.y)), I.free(k)));\n        a.Se = m;\n        a.wp.style.height = K;\n        a.Bs = !0;\n        g && (a.ll = !0);\n        b = a.Es;\n        k = b.scrollLeft;\n        a.hasHorizontalScrollbar && a.allowHorizontalScroll && (c + 1 < y ? k = (a.position.x - r) * v : r + 1 < A ? k = b.scrollWidth - b.clientWidth : q > C + 1 && (k = a.position.x * v));\n        if (a.nl) switch (a.zs) {\n            case \"negative\":\n                k = -(b.scrollWidth - k - b.clientWidth);\n                break;\n            case \"reverse\":\n                k = b.scrollWidth - k - b.clientWidth\n        }\n        b.scrollLeft = k;\n        a.hasVerticalScrollbar && a.allowVerticalScroll && (w + 1 < z ? b.scrollTop = (a.position.y - u) * v : u + 1 < G ? b.scrollTop = b.scrollHeight - b.clientHeight : p > n + 1 && (b.scrollTop =\n            a.position.y * v));\n        l = a.wa;\n        m = a.va;\n        b.style.width = l + (a.Se ? a.jb : 0) + \"px\";\n        b.style.height = m + (a.he ? a.jb : 0) + \"px\";\n        return d !== l || e !== m || a.animationManager.qc ? (a.Bq(f, a.viewportBounds, v, g), !1) : !0\n    }\n    t.add = function (a) {\n        var b = a.diagram;\n        if (b !== this && (null !== b && B(\"Cannot add part \" + a.toString() + \" to \" + this.toString() + \". It is already a part of \" + b.toString()), b = this.im(a.layerName), null === b && (b = this.im(\"\")), null === b && B('Cannot add a Part when unable find a Layer named \"' + a.layerName + '\" and there is no default Layer'), a.layer !== b)) {\n            var c = b.aj(99999999, a, a.diagram === this);\n            0 <= c && this.Ya(te, \"parts\", b, null, a, null, c);\n            b.isTemporary || this.Na();\n            a.C(1);\n            c = a.layerChanged;\n            null !== c && c(a, null, b)\n        }\n    };\n    t.aj = function (a) {\n        this.partManager.aj(a);\n        var b = this;\n        Dj(a, function (a) {\n            Ej(b, a)\n        });\n        (a instanceof Je || a instanceof T && null !== a.placeholder) && a.o();\n        null !== a.data && Dj(a, function (a) {\n            Fj(b.partManager, a)\n        });\n        !0 !== rj(a) && !0 !== sj(a) || this.nd.add(a);\n        Gj(a, !0, this);\n        Hj(a) ? (a.actualBounds.v() && this.M(Bj(a, a.actualBounds)), this.Na()) : a.isVisible() && a.actualBounds.v() && this.M(Bj(a, a.actualBounds));\n        this.Pb()\n    };\n    t.Fc = function (a) {\n        a.Yj();\n        this.partManager.Fc(a);\n        var b = this;\n        null !== a.data && Dj(a, function (a) {\n            Ij(b.partManager, a, b)\n        });\n        this.nd.remove(a);\n        Hj(a) ? (a.actualBounds.v() && this.M(Bj(a, a.actualBounds)), this.Na()) : a.isVisible() && a.actualBounds.v() && this.M(Bj(a, a.actualBounds));\n        this.Pb()\n    };\n    t.remove = function (a) {\n        Jj(this, a, !0)\n    };\n\n    function Jj(a, b, c) {\n        var d = b.layer;\n        null !== d && d.diagram === a && (b.isSelected = !1, b.isHighlighted = !1, b.C(2), c && b.dk(), c = d.Fc(-1, b, !1), 0 <= c && a.Ya(ue, \"parts\", d, b, null, c, null), a = b.layerChanged, null !== a && a(b, d, null))\n    }\n    t.Jt = function (a, b) {\n        if (Aa(a))\n            for (var c = a.length, d = 0; d < c; d++) {\n                var e = a[d];\n                b && !e.canDelete() || this.remove(e)\n            } else\n                for (c = new F, c.addAll(a), a = c.iterator; a.next();) c = a.value, b && !c.canDelete() || this.remove(c)\n    };\n    t.ck = function (a, b, c) {\n        return this.partManager.ck(a, b, c)\n    };\n    R.prototype.moveParts = function (a, b, c, d) {\n        void 0 === d && (d = Kj(this));\n        if (null !== this.toolManager) {\n            var e = new H;\n            if (null !== a)\n                if (Aa(a))\n                    for (var f = 0; f < a.length; f++) Lj(this, e, a[f], c, d);\n                else\n                    for (a = a.iterator; a.next();) Lj(this, e, a.value, c, d);\n            else {\n                for (a = this.parts; a.next();) Lj(this, e, a.value, c, d);\n                for (a = this.nodes; a.next();) Lj(this, e, a.value, c, d);\n                for (a = this.links; a.next();) Lj(this, e, a.value, c, d)\n            }\n            sf(this, e, b, d, c)\n        }\n    };\n\n    function Lj(a, b, c, d, e, f) {\n        if (!b.contains(c) && (void 0 === f && (f = !1), !d || f || c.canMove() || c.canCopy()))\n            if (void 0 === e && (e = Kj(a)), c instanceof W) {\n                b.add(c, a.sd(e, c, c.location));\n                if (c instanceof T)\n                    for (f = c.memberParts; f.next();) Lj(a, b, f.value, d, e, e.Mz);\n                for (f = c.linksConnected; f.next();) {\n                    var g = f.value;\n                    if (!b.contains(g)) {\n                        var h = g.fromNode,\n                            k = g.toNode;\n                        null !== h && b.contains(h) && null !== k && b.contains(k) && Lj(a, b, g, d, e)\n                    }\n                }\n                if (e.dragsTree)\n                    for (c = c.vv(); c.next();) Lj(a, b, c.value, d, e)\n            } else if (c instanceof S)\n            for (b.add(c, a.sd(e,\n                    c)), c = c.labelNodes; c.next();) Lj(a, b, c.value, d, e);\n        else c instanceof Je || b.add(c, a.sd(e, c, c.location))\n    }\n\n    function sf(a, b, c, d, e) {\n        if (null !== b && 0 !== b.count) {\n            var f = I.alloc(),\n                g = I.alloc();\n            g.assign(c);\n            isNaN(g.x) && (g.x = 0);\n            isNaN(g.y) && (g.y = 0);\n            (c = a.Op) || Ve(a, b);\n            for (var h = Fa(), k = Fa(), l = b.iterator, m = I.alloc(); l.next();) {\n                var n = l.key,\n                    p = l.value;\n                if (n.Wb()) {\n                    var r = Mj(a, n, b);\n                    if (null !== r) h.push(new Nj(n, p, r));\n                    else if (!e || n.canMove()) r = p.point, f.assign(r), a.computeMove(n, f.add(g), d, m), n.location = m, void 0 === p.shifted && (p.shifted = new I), p.shifted.assign(m.Zd(r))\n                } else l.key instanceof S && k.push(l.la)\n            }\n            I.free(m);\n            e = h.length;\n            for (l =\n                0; l < e; l++) n = h[l], f.assign(n.info.point), void 0 === n.Bv.shifted && (n.Bv.shifted = new I), n.node.location = f.add(n.Bv.shifted);\n            e = I.alloc();\n            l = I.alloc();\n            n = k.length;\n            for (p = 0; p < n; p++) {\n                var q = k[p];\n                r = q.key;\n                if (r instanceof S)\n                    if (r.suspendsRouting) {\n                        r.oh = null;\n                        m = r.fromNode;\n                        var u = r.toNode;\n                        if (null !== a.draggedLink && d.dragsLink)\n                            if (u = q.value.point, null === r.dragComputation) b.add(r, a.sd(d, r, g)), qf(r, g.x - u.x, g.y - u.y);\n                            else {\n                                q = I.allocAt(0, 0);\n                                (m = r.i(0)) && m.v() && q.assign(m);\n                                var v = m = I.alloc().assign(q).add(g);\n                                d.isGridSnapEnabled &&\n                                    (d.isGridSnapRealtime || a.lastInput.up) && (v = I.alloc(), Gg(a, r, m, v, d));\n                                m.assign(r.dragComputation(r, m, v)).Zd(q);\n                                b.add(r, a.sd(d, r, m));\n                                qf(r, m.x - u.x, m.y - u.y);\n                                I.free(q);\n                                I.free(m);\n                                v !== m && I.free(v)\n                            }\n                        else null !== m && (e.assign(m.location), v = b.H(m), null !== v && e.Zd(v.point)), null !== u && (l.assign(u.location), v = b.H(u), null !== v && l.Zd(v.point)), null !== m && null !== u ? e.Ma(l) ? (m = q.value.point, u = f, u.assign(e), u.Zd(m), b.add(r, a.sd(d, r, e)), qf(r, u.x, u.y)) : (r.suspendsRouting = !1, r.Oa()) : (q = q.value.point, m = null !== m ? e : null !== u ? l :\n                            g, b.add(r, a.sd(d, r, m)), qf(r, m.x - q.x, m.y - q.y))\n                    } else if (null === r.fromNode || null === r.toNode) m = q.value.point, b.add(r, a.sd(d, r, g)), qf(r, g.x - m.x, g.y - m.y)\n            }\n            I.free(f);\n            I.free(g);\n            I.free(e);\n            I.free(l);\n            Ha(h);\n            Ha(k);\n            c || (Si(a), ff(a, b))\n        }\n    }\n    R.prototype.computeMove = function (a, b, c, d) {\n        void 0 === d && (d = new I);\n        d.assign(b);\n        if (null === a) return d;\n        var e = b,\n            f = c.isGridSnapEnabled;\n        f && (c.isGridSnapRealtime || this.lastInput.up) && (e = I.alloc(), Gg(this, a, b, e, c));\n        c = null !== a.dragComputation ? a.dragComputation(a, b, e) : e;\n        var g = a.minLocation,\n            h = g.x;\n        isNaN(h) && (h = f ? Math.round(a.location.x) : a.location.x);\n        g = g.y;\n        isNaN(g) && (g = f ? Math.round(a.location.y) : a.location.y);\n        var k = a.maxLocation,\n            l = k.x;\n        isNaN(l) && (l = f ? Math.round(a.location.x) : a.location.x);\n        k = k.y;\n        isNaN(k) && (k = f ? Math.round(a.location.y) :\n            a.location.y);\n        d.h(Math.max(h, Math.min(c.x, l)), Math.max(g, Math.min(c.y, k)));\n        e !== b && I.free(e);\n        return d\n    };\n\n    function Kj(a) {\n        var b = a.toolManager.findTool(\"Dragging\");\n        return null !== b ? b.dragOptions : a.Qk\n    }\n\n    function Gg(a, b, c, d, e) {\n        void 0 === e && (e = Kj(a));\n        d.assign(c);\n        if (null !== b) {\n            var f = a.grid;\n            b = e.gridSnapCellSize;\n            a = b.width;\n            b = b.height;\n            var g = e.gridSnapOrigin,\n                h = g.x;\n            g = g.y;\n            e = e.gridSnapCellSpot;\n            if (null !== f) {\n                var k = f.gridCellSize;\n                isNaN(a) && (a = k.width);\n                isNaN(b) && (b = k.height);\n                f = f.gridOrigin;\n                isNaN(h) && (h = f.x);\n                isNaN(g) && (g = f.y)\n            }\n            f = I.allocAt(0, 0);\n            f.xk(0, 0, a, b, e);\n            J.mq(c.x, c.y, h + f.x, g + f.y, a, b, d);\n            I.free(f)\n        }\n    }\n\n    function Ve(a, b) {\n        if (null !== b)\n            for (a.Op = !0, a = b.iterator; a.next();) b = a.key, b instanceof S && (b.suspendsRouting = !0)\n    }\n\n    function ff(a, b) {\n        if (null !== b) {\n            for (b = b.iterator; b.next();) {\n                var c = b.key;\n                c instanceof S && (c.suspendsRouting = !1, Oj(c) && c.Oa())\n            }\n            a.Op = !1\n        }\n    }\n\n    function Mj(a, b, c) {\n        b = b.containingGroup;\n        if (null !== b) {\n            a = Mj(a, b, c);\n            if (null !== a) return a;\n            a = c.H(b);\n            if (null !== a) return a\n        }\n        return null\n    }\n    t = R.prototype;\n    t.sd = function (a, b, c) {\n        if (void 0 === c) return new df(Fb);\n        var d = a.isGridSnapEnabled;\n        a.Nz || null === b.containingGroup || (d = !1);\n        return d ? new df(new I(Math.round(c.x), Math.round(c.y))) : new df(c.copy())\n    };\n\n    function Pj(a, b, c) {\n        null !== b.diagram && b.diagram !== a && B(\"Cannot share a Layer with another Diagram: \" + b + \" of \" + b.diagram);\n        null === c ? null !== b.diagram && B(\"Cannot add an existing Layer to this Diagram again: \" + b) : (c.diagram !== a && B(\"Existing Layer must be in this Diagram: \" + c + \" not in \" + c.diagram), b === c && B(\"Cannot move a Layer before or after itself: \" + b));\n        if (b.diagram !== a) {\n            b = b.name;\n            a = a.Ja;\n            c = a.count;\n            for (var d = 0; d < c; d++) a.L(d).name === b && B(\"Cannot add Layer with the name '\" + b + \"'; a Layer with the same name is already present in this Diagram.\")\n        }\n    }\n    t.$l = function (a) {\n        Pj(this, a, null);\n        a.Yd(this);\n        var b = this.Ja,\n            c = b.count - 1;\n        if (!a.isTemporary)\n            for (; 0 <= c && b.L(c).isTemporary;) c--;\n        b.Kb(c + 1, a);\n        null !== this.ac && this.Ya(te, \"layers\", this, null, a, null, c + 1);\n        this.M();\n        this.Na()\n    };\n    t.tx = function (a, b) {\n        Pj(this, a, b);\n        a.Yd(this);\n        var c = this.Ja,\n            d = c.indexOf(a);\n        0 <= d && (c.remove(a), null !== this.ac && this.Ya(ue, \"layers\", this, a, null, d, null));\n        var e = c.count,\n            f;\n        for (f = 0; f < e; f++)\n            if (c.L(f) === b) {\n                c.Kb(f, a);\n                break\n            } null !== this.ac && this.Ya(te, \"layers\", this, null, a, null, f);\n        this.M();\n        0 > d && this.Na()\n    };\n    t.Gy = function (a, b) {\n        Pj(this, a, b);\n        a.Yd(this);\n        var c = this.Ja,\n            d = c.indexOf(a);\n        0 <= d && (c.remove(a), null !== this.ac && this.Ya(ue, \"layers\", this, a, null, d, null));\n        var e = c.count,\n            f;\n        for (f = 0; f < e; f++)\n            if (c.L(f) === b) {\n                c.Kb(f + 1, a);\n                break\n            } null !== this.ac && this.Ya(te, \"layers\", this, null, a, null, f + 1);\n        this.M();\n        0 > d && this.Na()\n    };\n    t.mA = function (a) {\n        a.diagram !== this && B(\"Cannot remove a Layer from another Diagram: \" + a + \" of \" + a.diagram);\n        if (\"\" !== a.name) {\n            var b = this.Ja,\n                c = b.indexOf(a);\n            if (b.remove(a)) {\n                for (b = a.Ca.copy().iterator; b.next();) {\n                    var d = b.value,\n                        e = d.layerName;\n                    e !== a.name ? d.layerName = e : d.layerName = \"\"\n                }\n                null !== this.ac && this.Ya(ue, \"layers\", this, a, null, c, null);\n                this.M();\n                this.Na()\n            }\n        }\n    };\n    t.im = function (a) {\n        for (var b = this.layers; b.next();) {\n            var c = b.value;\n            if (c.name === a) return c\n        }\n        return null\n    };\n    t.vx = function (a) {\n        null === this.oe && (this.oe = new E);\n        this.oe.add(a);\n        this.model.Dh(a)\n    };\n    t.oA = function (a) {\n        null !== this.oe && (this.oe.remove(a), 0 === this.oe.count && (this.oe = null));\n        this.model.wk(a)\n    };\n    t.Dh = function (a) {\n        null === this.Mf && (this.Mf = new E);\n        this.Mf.add(a)\n    };\n    t.wk = function (a) {\n        null !== this.Mf && (this.Mf.remove(a), 0 === this.Mf.count && (this.Mf = null))\n    };\n    t.bt = function (a) {\n        this.skipsUndoManager || this.model.skipsUndoManager || this.model.undoManager.Cv(a);\n        a.change !== se && (this.isModified = !0);\n        if (null !== this.Mf)\n            for (var b = this.Mf, c = b.length, d = 0; d < c; d++) b.L(d)(a)\n    };\n    t.Ya = function (a, b, c, d, e, f, g) {\n        void 0 === f && (f = null);\n        void 0 === g && (g = null);\n        var h = new qe;\n        h.diagram = this;\n        h.change = a;\n        h.propertyName = b;\n        h.object = c;\n        h.oldValue = d;\n        h.oldParam = f;\n        h.newValue = e;\n        h.newParam = g;\n        this.bt(h)\n    };\n    t.g = function (a, b, c, d, e) {\n        this.Ya(re, a, this, b, c, d, e)\n    };\n    R.prototype.changeState = function (a, b) {\n        if (null !== a && a.diagram === this) {\n            var c = this.skipsModelSourceBindings;\n            try {\n                this.skipsModelSourceBindings = !0;\n                var d = a.change;\n                if (d === re) {\n                    var e = a.object;\n                    Qj(e, a.propertyName, a.H(b));\n                    if (e instanceof Y) {\n                        var f = e.part;\n                        null !== f && f.Lb()\n                    }\n                    this.isModified = !0\n                } else if (d === te) {\n                    var g = a.object,\n                        h = a.newParam,\n                        k = a.newValue;\n                    if (g instanceof X)\n                        if (\"number\" === typeof h && k instanceof Y) {\n                            b ? g.Fc(h) : g.Kb(h, k);\n                            var l = g.part;\n                            null !== l && l.Lb()\n                        } else {\n                            if (\"number\" === typeof h && k instanceof Rj)\n                                if (b) k.isRow ?\n                                    g.Yv(h) : g.Wv(h);\n                                else {\n                                    var m = k.isRow ? g.getRowDefinition(k.index) : g.getColumnDefinition(k.index);\n                                    m.et(k)\n                                }\n                        }\n                    else if (g instanceof ei) {\n                        var n = !0 === a.oldParam;\n                        \"number\" === typeof h && k instanceof U && (b ? (k.isSelected = !1, k.isHighlighted = !1, k.Lb(), g.Fc(n ? h : -1, k, n)) : g.aj(h, k, n))\n                    } else g instanceof R ? \"number\" === typeof h && k instanceof ei && (b ? this.Ja.lb(h) : (k.Yd(this), this.Ja.Kb(h, k))) : B(\"unknown ChangedEvent.Insert object: \" + a.toString());\n                    this.isModified = !0\n                } else if (d === ue) {\n                    var p = a.object,\n                        r = a.oldParam,\n                        q = a.oldValue;\n                    if (p instanceof X) \"number\" === typeof r && q instanceof Y ? b ? p.Kb(r, q) : p.Fc(r) : \"number\" === typeof r && q instanceof Rj && (b ? (m = q.isRow ? p.getRowDefinition(q.index) : p.getColumnDefinition(q.index), m.et(q)) : q.isRow ? p.Yv(r) : p.Wv(r));\n                    else if (p instanceof ei) {\n                        var u = !0 === a.newParam;\n                        \"number\" === typeof r && q instanceof U && (b ? 0 > p.Ca.indexOf(q) && p.aj(r, q, u) : (q.isSelected = !1, q.isHighlighted = !1, q.Lb(), p.Fc(u ? r : -1, q, u)))\n                    } else p instanceof R ? \"number\" === typeof r && q instanceof ei && (b ? (q.Yd(this), this.Ja.Kb(r, q)) : this.Ja.lb(r)) : B(\"unknown ChangedEvent.Remove object: \" +\n                        a.toString());\n                    this.isModified = !0\n                } else d !== se && B(\"unknown ChangedEvent: \" + a.toString())\n            } finally {\n                this.skipsModelSourceBindings = c\n            }\n        }\n    };\n    R.prototype.ua = function (a) {\n        return this.undoManager.ua(a)\n    };\n    R.prototype.Ua = function (a) {\n        return this.undoManager.Ua(a)\n    };\n    R.prototype.Bf = function () {\n        return this.undoManager.Bf()\n    };\n    R.prototype.commit = function (a, b) {\n        void 0 === b && (b = \"\");\n        var c = this.skipsUndoManager;\n        null === b && (this.skipsUndoManager = !0, b = \"\");\n        this.undoManager.ua(b);\n        var d = !1;\n        try {\n            a(this), d = !0\n        } finally {\n            d ? this.undoManager.Ua(b) : this.undoManager.Bf(), this.skipsUndoManager = c\n        }\n    };\n    R.prototype.updateAllTargetBindings = function (a) {\n        this.partManager.updateAllTargetBindings(a)\n    };\n    R.prototype.Pq = function () {\n        this.partManager.Pq()\n    };\n\n    function Sj(a, b, c) {\n        var d = a.animationManager;\n        if (a.Rb || a.Bc) a.ya = c, d.Ze && d.Ad.add(d.B, \"scale\", b, a.ya);\n        else if (a.Rb = !0, null === a.sa) a.ya = c;\n        else {\n            var e = a.viewportBounds.copy(),\n                f = a.wa,\n                g = a.va;\n            e.width = a.wa / b;\n            e.height = a.va / b;\n            var h = a.zoomPoint.x,\n                k = a.zoomPoint.y,\n                l = a.contentAlignment;\n            isNaN(h) && (l.yf() ? l.wf(Ic) ? h = 0 : l.wf(Jc) && (h = f - 1) : h = l.eb() ? l.x * (f - 1) : f / 2);\n            isNaN(k) && (l.yf() ? l.wf(Hc) ? k = 0 : l.wf(Kc) && (k = g - 1) : k = l.eb() ? l.y * (g - 1) : g / 2);\n            null === a.scaleComputation || a.animationManager.isAnimating || (c = a.scaleComputation(a,\n                c));\n            c < a.minScale && (c = a.minScale);\n            c > a.maxScale && (c = a.maxScale);\n            f = I.allocAt(a.ma.x + h / b - h / c, a.ma.y + k / b - k / c);\n            a.position = f;\n            I.free(f);\n            a.ya = c;\n            a.Bq(e, a.viewportBounds, b, !1);\n            a.Rb = !1;\n            Ui(a, !1);\n            d.Ze && d.Ad.add(d.B, \"scale\", b, a.ya);\n            a.M();\n            Xi(a)\n        }\n    }\n    R.prototype.Bq = function (a, b, c, d) {\n        if (!a.w(b)) {\n            void 0 === d && (d = !1);\n            d || Xi(this);\n            Ri(this);\n            var e = this.layout;\n            null === e || !e.isViewportSized || this.autoScale !== ni || d || a.width === b.width && a.height === b.height || e.C();\n            e = this.currentTool;\n            !0 === this.Yf && e instanceof Oa && (this.lastInput.documentPoint = this.Pt(this.lastInput.viewPoint), Ne(e, this));\n            this.Rb || this.Sx(a, b);\n            mj(this);\n            this.Rd.scale = c;\n            this.Rd.position.x = a.x;\n            this.Rd.position.y = a.y;\n            this.Rd.bounds.assign(a);\n            this.Rd.Jv = d;\n            this.R(\"ViewportBoundsChanged\", this.Rd, a);\n            this.isVirtualized && this.links.each(function (a) {\n                a.isAvoiding && a.actualBounds.Gc(b) && a.Oa()\n            })\n        }\n    };\n\n    function mj(a, b) {\n        void 0 === b && (b = null);\n        var c = a.Fb;\n        if (null !== c && c.visible) {\n            for (var d = M.alloc(), e = 1, f = 1, g = c.W.j, h = g.length, k = 0; k < h; k++) {\n                var l = g[k],\n                    m = l.interval;\n                2 > m || (dk(l.figure) ? f = f * m / J.Nx(f, m) : e = e * m / J.Nx(e, m))\n            }\n            g = c.gridCellSize;\n            d.h(f * g.width, e * g.height);\n            if (null !== b) e = b.width, f = b.height, a = b.x, g = b.y;\n            else {\n                b = N.alloc();\n                a = a.viewportBounds;\n                b.h(a.x, a.y, a.width, a.height);\n                if (!b.v()) {\n                    N.free(b);\n                    return\n                }\n                e = b.width;\n                f = b.height;\n                a = b.x;\n                g = b.y;\n                N.free(b)\n            }\n            c.width = e + 2 * d.width;\n            c.height = f + 2 * d.height;\n            b = I.alloc();\n            J.mq(a, g, 0, 0,\n                d.width, d.height, b);\n            b.offset(-d.width, -d.height);\n            M.free(d);\n            c.part.location = b;\n            I.free(b)\n        }\n    }\n    R.prototype.clearSelection = function (a) {\n        void 0 === a && (a = !1);\n        var b = this.selection;\n        if (0 !== b.count) {\n            a || this.R(\"ChangingSelection\", b);\n            for (var c = b.na(), d = c.length, e = 0; e < d; e++) c[e].isSelected = !1;\n            b.ea();\n            b.clear();\n            b.freeze();\n            a || this.R(\"ChangedSelection\", b)\n        }\n    };\n    R.prototype.select = function (a) {\n        null !== a && a.layer.diagram === this && (!a.isSelected || 1 < this.selection.count) && (this.R(\"ChangingSelection\", this.selection), this.clearSelection(!0), a.isSelected = !0, this.R(\"ChangedSelection\", this.selection))\n    };\n    R.prototype.sA = function (a) {\n        this.R(\"ChangingSelection\", this.selection);\n        this.clearSelection(!0);\n        if (Aa(a))\n            for (var b = a.length, c = 0; c < b; c++) {\n                var d = a[c];\n                d instanceof U || B(\"Diagram.selectCollection given something that is not a Part: \" + d);\n                d.isSelected = !0\n            } else\n                for (a = a.iterator; a.next();) b = a.value, b instanceof U || B(\"Diagram.selectCollection given something that is not a Part: \" + b), b.isSelected = !0;\n        this.R(\"ChangedSelection\", this.selection)\n    };\n    R.prototype.clearHighlighteds = function () {\n        var a = this.highlighteds;\n        if (0 < a.count) {\n            for (var b = a.na(), c = b.length, d = 0; d < c; d++) b[d].isHighlighted = !1;\n            a.ea();\n            a.clear();\n            a.freeze()\n        }\n    };\n    t = R.prototype;\n    t.Pz = function (a) {\n        null !== a && a.layer.diagram === this && (!a.isHighlighted || 1 < this.highlighteds.count) && (this.clearHighlighteds(), a.isHighlighted = !0)\n    };\n    t.Qz = function (a) {\n        a = (new F).addAll(a);\n        for (var b = this.highlighteds.copy().Fq(a).iterator; b.next();) b.value.isHighlighted = !1;\n        for (a = a.iterator; a.next();) b = a.value, b instanceof U || B(\"Diagram.highlightCollection given something that is not a Part: \" + b), b.isHighlighted = !0\n    };\n    t.scroll = function (a, b, c) {\n        void 0 === c && (c = 1);\n        var d = \"up\" === b || \"down\" === b,\n            e = 0;\n        if (\"pixel\" === a) e = c;\n        else if (\"line\" === a) e = c * (d ? this.scrollVerticalLineChange : this.scrollHorizontalLineChange);\n        else if (\"page\" === a) a = d ? this.viewportBounds.height : this.viewportBounds.width, a *= this.scale, 0 !== a && (e = c * Math.max(a - (d ? this.scrollVerticalLineChange : this.scrollHorizontalLineChange), 0));\n        else {\n            if (\"document\" === a) {\n                e = this.documentBounds;\n                c = this.viewportBounds;\n                d = I.alloc();\n                \"up\" === b ? this.position = d.h(c.x, e.y) : \"left\" === b ? this.position =\n                    d.h(e.x, c.y) : \"down\" === b ? this.position = d.h(c.x, e.bottom - c.height) : \"right\" === b && (this.position = d.h(e.right - c.width, c.y));\n                I.free(d);\n                return\n            }\n            B(\"scrolling unit must be 'pixel', 'line', 'page', or 'document', not: \" + a)\n        }\n        e /= this.scale;\n        c = this.position.copy();\n        \"up\" === b ? c.y = this.position.y - e : \"down\" === b ? c.y = this.position.y + e : \"left\" === b ? c.x = this.position.x - e : \"right\" === b ? c.x = this.position.x + e : B(\"scrolling direction must be 'up', 'down', 'left', or 'right', not: \" + b);\n        this.position = c\n    };\n    t.cw = function (a) {\n        var b = this.viewportBounds;\n        b.ze(a) || (a = a.center, a.x -= b.width / 2, a.y -= b.height / 2, this.position = a)\n    };\n    t.ct = function (a) {\n        var b = this.viewportBounds;\n        a = a.center;\n        a.x -= b.width / 2;\n        a.y -= b.height / 2;\n        this.position = a\n    };\n    t.Nq = function (a) {\n        var b = this.kb;\n        b.reset();\n        1 !== this.ya && b.scale(this.ya);\n        var c = this.ma;\n        (0 !== c.x || 0 !== c.y) && isFinite(c.x) && isFinite(c.y) && b.translate(-c.x, -c.y);\n        return a.copy().transform(this.kb)\n    };\n    t.BA = function (a) {\n        var b = this.kb,\n            c = a.x,\n            d = a.y,\n            e = c + a.width,\n            f = d + a.height,\n            g = b.m11,\n            h = b.m12,\n            k = b.m21,\n            l = b.m22,\n            m = b.dx,\n            n = b.dy,\n            p = c * g + d * k + m;\n        b = c * h + d * l + n;\n        var r = e * g + d * k + m;\n        a = e * h + d * l + n;\n        d = c * g + f * k + m;\n        c = c * h + f * l + n;\n        g = e * g + f * k + m;\n        e = e * h + f * l + n;\n        f = Math.min(p, r);\n        p = Math.max(p, r);\n        r = Math.min(b, a);\n        b = Math.max(b, a);\n        f = Math.min(f, d);\n        p = Math.max(p, d);\n        r = Math.min(r, c);\n        b = Math.max(b, c);\n        f = Math.min(f, g);\n        p = Math.max(p, g);\n        r = Math.min(r, e);\n        b = Math.max(b, e);\n        return new N(f, r, p - f, b - r)\n    };\n    t.Pt = function (a) {\n        var b = this.kb;\n        b.reset();\n        1 !== this.ya && b.scale(this.ya);\n        var c = this.ma;\n        (0 !== c.x || 0 !== c.y) && isFinite(c.x) && isFinite(c.y) && b.translate(-c.x, -c.y);\n        return zb(a.copy(), this.kb)\n    };\n\n    function hk(a) {\n        var b = a.isModified;\n        a.$u !== b && (a.$u = b, a.R(\"Modified\"))\n    }\n\n    function ik(a) {\n        a = qi.get(a);\n        return null !== a ? new a : new ri\n    }\n    R.prototype.doModelChanged = function (a) {\n        if (a.model === this.model) {\n            var b = a.change,\n                c = a.propertyName;\n            if (b === se && \"S\" === c[0])\n                if (\"StartingFirstTransaction\" === c) {\n                    var d = this;\n                    a = this.toolManager;\n                    a.mouseDownTools.each(function (a) {\n                        a.diagram = d\n                    });\n                    a.mouseMoveTools.each(function (a) {\n                        a.diagram = d\n                    });\n                    a.mouseUpTools.each(function (a) {\n                        a.diagram = d\n                    });\n                    this.Bc || this.ie || (this.pj = !0, this.sj && (this.we = !0))\n                } else \"StartingUndo\" === c || \"StartingRedo\" === c ? (a = this.animationManager, a.defaultAnimation.isAnimating && !this.skipsUndoManager &&\n                    a.Xc(), this.R(\"ChangingSelection\", this.selection)) : \"StartedTransaction\" === c && (a = this.animationManager, a.defaultAnimation.isAnimating && !this.skipsUndoManager && a.Xc());\n            else if (this.Z) {\n                this.Z = !1;\n                try {\n                    if (\"\" === a.modelChange && b === se) {\n                        if (\"FinishedUndo\" === c || \"FinishedRedo\" === c) this.R(\"ChangedSelection\", this.selection), Si(this);\n                        var e = this.animationManager;\n                        \"RolledBackTransaction\" === c && e.Xc();\n                        this.pj = !0;\n                        this.Wc();\n                        0 !== this.undoManager.transactionLevel && 1 !== this.undoManager.transactionLevel || Bh(e);\n                        \"CommittedTransaction\" ===\n                        c && this.undoManager.zu && (this.Gd = Math.min(this.Gd, this.undoManager.historyIndex - 1));\n                        var f = a.isTransactionFinished;\n                        f && (hk(this), this.yt.clear(), Mh(this.animationManager));\n                        if (!this.hs && f) {\n                            this.hs = !0;\n                            var g = this;\n                            sa(function () {\n                                g.currentTool.standardMouseOver();\n                                g.hs = !1\n                            }, 10)\n                        }\n                    }\n                } finally {\n                    this.Z = !0\n                }\n            }\n        }\n    };\n\n    function Ej(a, b) {\n        b = b.W.j;\n        for (var c = b.length, d = 0; d < c; d++) jk(a, b[d])\n    }\n\n    function jk(a, b) {\n        if (b instanceof kk) {\n            var c = b.element;\n            if (null !== c && c instanceof HTMLImageElement) {\n                var d = b.Vg;\n                null !== d && (d.bl instanceof Event && null !== b.zc && b.zc(b, d.bl), !0 === d.Pr && (null !== b.kf && b.kf(b, d.Ou), null !== b.diagram && b.diagram.ss.add(b)));\n                c = c.getAttribute(\"src\");\n                d = a.Ci.H(c);\n                if (null === d) d = [], d.push(b), a.Ci.add(c, d);\n                else {\n                    for (a = 0; a < d.length; a++)\n                        if (d[a] === b) return;\n                    d.push(b)\n                }\n            }\n        }\n    }\n\n    function lk(a, b) {\n        if (b instanceof kk) {\n            var c = b.element;\n            if (null !== c && c instanceof HTMLImageElement) {\n                c = c.getAttribute(\"src\");\n                var d = a.Ci.H(c);\n                if (null !== d)\n                    for (var e = 0; e < d.length; e++)\n                        if (d[e] === b) {\n                            d.splice(e, 1);\n                            0 === d.length && (a.Ci.remove(c), mk(c));\n                            break\n                        }\n            }\n        }\n    }\n    R.prototype.xd = function () {\n        this.partManager.xd()\n    };\n    R.prototype.Tj = function (a, b) {\n        this.Jc.Tj(a, b)\n    };\n    R.prototype.Vj = function (a, b) {\n        this.Jc.Vj(a, b)\n    };\n    R.prototype.findPartForKey = function (a) {\n        return this.partManager.findPartForKey(a)\n    };\n    R.prototype.Jb = function (a) {\n        return this.partManager.Jb(a)\n    };\n    R.prototype.findLinkForKey = function (a) {\n        return this.partManager.findLinkForKey(a)\n    };\n    t = R.prototype;\n    t.wc = function (a) {\n        return this.partManager.wc(a)\n    };\n    t.Si = function (a) {\n        return this.partManager.Si(a)\n    };\n    t.vc = function (a) {\n        return this.partManager.vc(a)\n    };\n    t.kt = function (a) {\n        for (var b = [], c = 0; c < arguments.length; ++c) b[c] = arguments[c];\n        return this.partManager.kt.apply(this.partManager, b instanceof Array ? b : da(ba(b)))\n    };\n    t.jt = function (a) {\n        for (var b = [], c = 0; c < arguments.length; ++c) b[c] = arguments[c];\n        return this.partManager.jt.apply(this.partManager, b instanceof Array ? b : da(ba(b)))\n    };\n\n    function zj(a, b) {\n        a.ki = !1;\n        var c = a.zn;\n        c.w(b) || (b = b.G(), a.zn = b, Ui(a, !1), a.R(\"DocumentBoundsChanged\", null, c.copy()), Xi(a))\n    }\n\n    function Ii(a) {\n        a.ki && zj(a, a.computeBounds())\n    }\n    t.sz = function () {\n        for (var a = new F, b = this.nodes; b.next();) {\n            var c = b.value;\n            c.isTopLevel && a.add(c)\n        }\n        for (b = this.links; b.next();) c = b.value, c.isTopLevel && a.add(c);\n        return a.iterator\n    };\n    t.rz = function () {\n        return this.zh.iterator\n    };\n    t.aA = function (a) {\n        Si(this);\n        a && nk(this, !0);\n        this.pj = !0;\n        If(this)\n    };\n\n    function nk(a, b) {\n        for (var c = a.zh.iterator; c.next();) ok(a, c.value, b);\n        null !== a.layout && (b ? a.layout.isValidLayout = !1 : a.layout.C())\n    }\n\n    function ok(a, b, c) {\n        if (null !== b) {\n            for (var d = b.zl.iterator; d.next();) ok(a, d.value, c);\n            null !== b.layout && (c ? b.layout.isValidLayout = !1 : b.layout.C())\n        }\n    }\n\n    function nj(a, b) {\n        if (a.If && !a.tr) {\n            var c = a.Z;\n            a.Z = !0;\n            var d = a.undoManager.transactionLevel,\n                e = a.layout;\n            try {\n                0 === d && a.ua(\"Layout\");\n                var f = a.animationManager;\n                1 >= d && !f.isAnimating && !f.qc && (b || zh(f, \"Layout\"));\n                a.If = !1;\n                for (var g = a.zh.iterator; g.next();) pk(a, g.value, b, d);\n                e.isValidLayout || (!b || e.isRealtime || null === e.isRealtime || 0 === d ? (e.doLayout(a), Si(a), e.isValidLayout = !0) : a.If = !0)\n            } finally {\n                0 === d && a.Ua(\"Layout\"), a.If = !e.isValidLayout, a.Z = c\n            }\n        }\n    }\n\n    function pk(a, b, c, d) {\n        if (null !== b) {\n            for (var e = b.zl.iterator; e.next();) pk(a, e.value, c, d);\n            e = b.layout;\n            null === e || e.isValidLayout || (!c || e.isRealtime || 0 === d ? (b.uk = !b.location.v(), e.doLayout(b), b.C(32), pj(a, b), e.isValidLayout = !0) : a.If = !0)\n        }\n    }\n    t.zz = function () {\n        for (var a = new E, b = this.nodes; b.next();) {\n            var c = b.value;\n            c.isTopLevel && null === c.Vi() && a.add(c)\n        }\n        return a.iterator\n    };\n\n    function oi(a) {\n        function b(a) {\n            var b = a.toLowerCase(),\n                e = new E;\n            c.add(a, e);\n            c.add(b, e);\n            d.add(a, a);\n            d.add(b, a)\n        }\n        var c = new H,\n            d = new H;\n        b(\"InitialAnimationStarting\");\n        b(\"AnimationStarting\");\n        b(\"AnimationFinished\");\n        b(\"BackgroundSingleClicked\");\n        b(\"BackgroundDoubleClicked\");\n        b(\"BackgroundContextClicked\");\n        b(\"ClipboardChanged\");\n        b(\"ClipboardPasted\");\n        b(\"DocumentBoundsChanged\");\n        b(\"ExternalObjectsDropped\");\n        b(\"GainedFocus\");\n        b(\"InitialLayoutCompleted\");\n        b(\"LayoutCompleted\");\n        b(\"LinkDrawn\");\n        b(\"LinkRelinked\");\n        b(\"LinkReshaped\");\n        b(\"LostFocus\");\n        b(\"Modified\");\n        b(\"ObjectSingleClicked\");\n        b(\"ObjectDoubleClicked\");\n        b(\"ObjectContextClicked\");\n        b(\"PartCreated\");\n        b(\"PartResized\");\n        b(\"PartRotated\");\n        b(\"SelectionMoved\");\n        b(\"SelectionCopied\");\n        b(\"SelectionDeleting\");\n        b(\"SelectionDeleted\");\n        b(\"SelectionGrouped\");\n        b(\"SelectionUngrouped\");\n        b(\"ChangingSelection\");\n        b(\"ChangedSelection\");\n        b(\"SubGraphCollapsed\");\n        b(\"SubGraphExpanded\");\n        b(\"TextEdited\");\n        b(\"TreeCollapsed\");\n        b(\"TreeExpanded\");\n        b(\"ViewportBoundsChanged\");\n        b(\"InvalidateDraw\");\n        a.wr = c;\n        a.vr = d\n    }\n\n    function yj(a, b) {\n        var c = a.vr.H(b);\n        return null !== c ? c : a.vr.H(b.toLowerCase())\n    }\n\n    function qk(a, b) {\n        var c = a.wr.H(b);\n        if (null !== c) return c;\n        c = a.wr.H(b.toLowerCase());\n        if (null !== c) return c;\n        B(\"Unknown DiagramEvent name: \" + b);\n        return null\n    }\n    t.Uj = function (a, b) {\n        a = qk(this, a);\n        null !== a && a.add(b)\n    };\n    t.ym = function (a, b) {\n        a = qk(this, a);\n        null !== a && a.remove(b)\n    };\n    t.R = function (a, b, c) {\n        var d = qk(this, a),\n            e = new pe;\n        e.diagram = this;\n        a = yj(this, a);\n        null !== a && (e.name = a);\n        void 0 !== b && (e.subject = b);\n        void 0 !== c && (e.parameter = c);\n        b = d.length;\n        if (1 === b) d.L(0)(e);\n        else if (0 !== b)\n            for (d = d.na(), c = 0; c < b; c++)(0, d[c])(e)\n    };\n\n    function rk(a) {\n        if (a.animationManager.isAnimating) return !1;\n        var b = a.currentTool;\n        return b === a.toolManager.findTool(\"Dragging\") ? !a.Op || b.isComplexRoutingRealtime : !0\n    }\n    t.lk = function (a, b) {\n        void 0 === b && (b = null);\n        return sk(this, !1, null, b).lk(a.x, a.y, a.width, a.height)\n    };\n    R.prototype.computeOccupiedArea = function () {\n        return this.isVirtualized ? this.viewportBounds.copy() : this.ki ? Ti(this) : this.documentBounds.copy()\n    };\n\n    function sk(a, b, c, d) {\n        null === a.Gb && (a.Gb = new tk);\n        if (a.Gb.st || a.Gb.group !== c || a.Gb.oy !== d) {\n            if (null === c) {\n                b = a.computeOccupiedArea();\n                b.Vc(100, 100);\n                a.Gb.initialize(b);\n                b = N.alloc();\n                for (var e = a.nodes; e.next();) {\n                    var f = e.value,\n                        g = f.layer;\n                    null !== g && g.visible && !g.isTemporary && uk(a, f, d, b)\n                }\n                N.free(b)\n            } else {\n                0 < c.memberParts.count && (b = a.computePartsBounds(c.memberParts, !1), b.Vc(20, 20), a.Gb.initialize(b));\n                b = N.alloc();\n                for (e = c.memberParts; e.next();) f = e.value, f instanceof W && uk(a, f, d, b);\n                N.free(b)\n            }\n            a.Gb.group = c;\n            a.Gb.oy = d;\n            a.Gb.st = !1\n        } else b && vk(a.Gb);\n        return a.Gb\n    }\n\n    function uk(a, b, c, d) {\n        if (b !== c)\n            if (b.isVisible() && b.avoidable && !b.isLinkLabel) {\n                var e = b.getAvoidableRect(d),\n                    f = a.Gb.dm;\n                c = a.Gb.cm;\n                d = e.x + e.width;\n                b = e.y + e.height;\n                for (var g = e.x; g < d; g += f) {\n                    for (var h = e.y; h < b; h += c) wk(a.Gb, g, h);\n                    wk(a.Gb, g, b)\n                }\n                for (e = e.y; e < b; e += c) wk(a.Gb, d, e);\n                wk(a.Gb, d, b)\n            } else if (b instanceof T)\n            for (b = b.memberParts; b.next();) e = b.value, e instanceof W && uk(a, e, c, d)\n    }\n\n    function xk(a, b) {\n        null !== a.Gb && !a.Gb.st && (void 0 === b && (b = null), null === b || b.avoidable && !b.isLinkLabel) && (a.Gb.st = !0)\n    }\n    t = R.prototype;\n    t.gt = function (a) {\n        this.$m.assign(a);\n        yk(this, this.$m).Ma(this.position) ? this.Cf() : zk(this)\n    };\n\n    function zk(a) {\n        -1 === a.jj && (a.jj = sa(function () {\n            if (-1 !== a.jj && (a.Cf(), null !== a.lastInput.event)) {\n                var b = yk(a, a.$m);\n                b.Ma(a.position) || (a.position = b, a.lastInput.documentPoint = a.Pt(a.$m), a.doMouseMove(), a.ki = !0, zj(a, a.documentBounds.copy().Hc(a.computeBounds())), a.Ac = !0, a.Wc(), zk(a))\n            }\n        }, a.Zm))\n    }\n    t.Cf = function () {\n        -1 !== this.jj && (x.clearTimeout(this.jj), this.jj = -1)\n    };\n\n    function yk(a, b) {\n        var c = a.position,\n            d = a.an;\n        if (0 >= d.top && 0 >= d.left && 0 >= d.right && 0 >= d.bottom) return c;\n        var e = a.viewportBounds,\n            f = a.scale;\n        e = N.allocAt(0, 0, e.width * f, e.height * f);\n        var g = I.allocAt(0, 0);\n        if (b.x >= e.x && b.x < e.x + d.left) {\n            var h = Math.max(a.scrollHorizontalLineChange, 1);\n            h |= 0;\n            g.x -= h;\n            b.x < e.x + d.left / 2 && (g.x -= h);\n            b.x < e.x + d.left / 4 && (g.x -= 4 * h)\n        } else b.x <= e.x + e.width && b.x > e.x + e.width - d.right && (h = Math.max(a.scrollHorizontalLineChange, 1), h |= 0, g.x += h, b.x > e.x + e.width - d.right / 2 && (g.x += h), b.x > e.x + e.width - d.right / 4 &&\n            (g.x += 4 * h));\n        b.y >= e.y && b.y < e.y + d.top ? (a = Math.max(a.scrollVerticalLineChange, 1), a |= 0, g.y -= a, b.y < e.y + d.top / 2 && (g.y -= a), b.y < e.y + d.top / 4 && (g.y -= 4 * a)) : b.y <= e.y + e.height && b.y > e.y + e.height - d.bottom && (a = Math.max(a.scrollVerticalLineChange, 1), a |= 0, g.y += a, b.y > e.y + e.height - d.bottom / 2 && (g.y += a), b.y > e.y + e.height - d.bottom / 4 && (g.y += 4 * a));\n        g.Ma(Fb) || (c = new I(c.x + g.x / f, c.y + g.y / f));\n        N.free(e);\n        I.free(g);\n        return c\n    }\n    t.At = function () {\n        return null\n    };\n    t.Kv = function () {\n        return null\n    };\n    t.Ky = function (a, b) {\n        this.jx.add(a, b)\n    };\n\n    function Ak(a, b, c) {\n        function d() {\n            var a = +new Date;\n            f = !0;\n            for (g.reset(); g.next();)\n                if (!g.value[0].vl) {\n                    f = !1;\n                    break\n                } f || a - l > k ? b(c, e, h) : x.requestAnimationFrame(d)\n        }\n        for (var e = c.callback, f = !0, g = a.Ci.iterator; g.next();)\n            if (!g.value[0].vl) {\n                f = !1;\n                break\n            } if (\"function\" !== typeof e || f) return b(c, e, a);\n        var h = a,\n            k = c.callbackTimeout || 300,\n            l = +new Date;\n        x.requestAnimationFrame(function () {\n            d()\n        });\n        return null\n    }\n    t.cA = function (a) {\n        if (!Ug) return null;\n        void 0 === a && (a = new db);\n        a.returnType = \"Image\";\n        return this.Ux(a)\n    };\n    t.Ux = function (a) {\n        void 0 === a && (a = new db);\n        return Ak(this, this.dA, a)\n    };\n    t.dA = function (a, b, c) {\n        var d = Bk(c, a, \"canvas\", null);\n        if (null === d) return null;\n        c = d.V.canvas;\n        var e = null;\n        if (null !== c) switch (e = a.returnType, void 0 === e ? e = \"string\" : e = e.toLowerCase(), e) {\n            case \"imagedata\":\n                e = d.getImageData(0, 0, c.width, c.height);\n                break;\n            case \"image\":\n                d = (a.document || document).createElement(\"img\");\n                d.src = c.toDataURL(a.type, a.details);\n                e = d;\n                break;\n            case \"blob\":\n                \"function\" !== typeof b && B('Error: Diagram.makeImageData called with \"returnType: toBlob\", but no required \"callback\" function property defined.');\n                if (\"function\" ===\n                    typeof c.toBlob) return c.toBlob(b, a.type, a.details), \"toBlob\";\n                if (\"function\" === typeof c.msToBlob) return b(c.msToBlob()), \"msToBlob\";\n                b(null);\n                return null;\n            default:\n                e = c.toDataURL(a.type, a.details)\n        }\n        return \"function\" === typeof b ? (b(e), null) : e\n    };\n\n    function Bk(a, b, c, d) {\n        a.animationManager.Xc();\n        a.Wc();\n        if (null === a.sa) return null;\n        \"object\" !== typeof b && B(\"properties argument must be an Object.\");\n        var e = b.size || null,\n            f = b.scale || null;\n        void 0 !== b.scale && isNaN(b.scale) && (f = \"NaN\");\n        var g = b.maxSize;\n        void 0 === b.maxSize && (g = \"SVG\" === c ? new M(Infinity, Infinity) : new M(2E3, 2E3));\n        var h = b.position || null,\n            k = b.parts || null,\n            l = void 0 === b.padding ? 1 : b.padding,\n            m = b.background || null,\n            n = b.omitTemporary;\n        void 0 === n && (n = !0);\n        var p = b.document || document,\n            r = b.elementFinished || null,\n            q = b.showTemporary;\n        void 0 === q && (q = !n);\n        b = b.showGrid;\n        void 0 === b && (b = q);\n        null !== e && isNaN(e.width) && isNaN(e.height) && (e = null);\n        \"number\" === typeof l ? l = new oc(l) : l instanceof oc || B(\"MakeImage padding must be a Margin or a number.\");\n        l.left = Math.max(l.left, 0);\n        l.right = Math.max(l.right, 0);\n        l.top = Math.max(l.top, 0);\n        l.bottom = Math.max(l.bottom, 0);\n        a.Db.sc(!0);\n        n = new Ck(null, p);\n        var u = n.context;\n        if (!(e || f || k || h)) {\n            n.width = a.wa + Math.ceil(l.left + l.right);\n            n.height = a.va + Math.ceil(l.top + l.bottom);\n            if (\"SVG\" === c) {\n                if (null === d) return null;\n                d.resize(n.width,\n                    n.height, n.width, n.height);\n                d.ownerDocument = p;\n                d.jq = r;\n                wj(a, d.context, l, new M(n.width, n.height), a.ya, a.ma, k, m, q, b);\n                return d.context\n            }\n            a.Xk = !1;\n            wj(a, u, l, new M(n.width, n.height), a.ya, a.ma, k, m, q, b);\n            a.Xk = !0;\n            return n.context\n        }\n        var v = a.yn,\n            w = a.documentBounds.copy();\n        w.kw(a.bb);\n        if (q)\n            for (var y = a.Ja.j, z = y.length, A = 0; A < z; A++) {\n                var C = y[A];\n                if (C.visible && C.isTemporary) {\n                    C = C.Ca.j;\n                    for (var G = C.length, L = 0; L < G; L++) {\n                        var K = C[L];\n                        K.isInDocumentBounds && K.isVisible() && (K = K.actualBounds, K.v() && w.Hc(K))\n                    }\n                }\n            }\n        y = new I(w.x, w.y);\n        if (null !== k) {\n            z = !0;\n            A = k.iterator;\n            for (A.reset(); A.next();)\n                if (C = A.value, C instanceof U && (G = C.layer, (null === G || G.visible) && (null === G || q || !G.isTemporary) && C.isVisible() && (C = C.actualBounds, C.v())))\n                    if (z) {\n                        z = !1;\n                        var V = C.copy()\n                    } else V.Hc(C);\n            z && (V = new N(0, 0, 0, 0));\n            w.width = V.width;\n            w.height = V.height;\n            y.x = V.x;\n            y.y = V.y\n        }\n        null !== h && h.v() && (y = h, f || (f = v));\n        V = h = 0;\n        null !== l && (h = l.left + l.right, V = l.top + l.bottom);\n        z = A = 0;\n        null !== e && (A = e.width, z = e.height, isFinite(A) && (A = Math.max(0, A - h)), isFinite(z) && (z = Math.max(0, z - V)));\n        null !== e && null !== f ? (\"NaN\" ===\n            f && (f = v), e.v() ? (e = A, w = z) : isNaN(z) ? (e = A, w = w.height * f) : (e = w.width * f, w = z)) : null !== e ? e.v() ? (f = Math.min(A / w.width, z / w.height), e = A, w = z) : isNaN(z) ? (f = A / w.width, e = A, w = w.height * f) : (f = z / w.height, e = w.width * f, w = z) : null !== f ? \"NaN\" === f && g.v() ? (f = Math.min((g.width - h) / w.width, (g.height - V) / w.height), f > v ? (f = v, e = w.width, w = w.height) : (e = g.width, w = g.height)) : (e = w.width * f, w = w.height * f) : (f = v, e = w.width, w = w.height);\n        null !== l ? (e += h, w += V) : l = new oc(0);\n        null !== g && (v = g.width, g = g.height, isNaN(v) && (v = 2E3), isNaN(g) && (g = 2E3), isFinite(v) &&\n            (e = Math.min(e, v)), isFinite(g) && (w = Math.min(w, g)));\n        n.width = Math.ceil(e);\n        n.height = Math.ceil(w);\n        if (\"SVG\" === c) {\n            if (null === d) return null;\n            d.resize(n.width, n.height, n.width, n.height);\n            d.ownerDocument = p;\n            d.jq = r;\n            wj(a, d.context, l, new M(Math.ceil(e), Math.ceil(w)), f, y, k, m, q, b);\n            return d.context\n        }\n        a.Xk = !1;\n        wj(a, u, l, new M(Math.ceil(e), Math.ceil(w)), f, y, k, m, q, b);\n        a.Xk = !0;\n        return n.context\n    }\n    ma.Object.defineProperties(R.prototype, {\n        div: {\n            get: function () {\n                return this.La\n            },\n            set: function (a) {\n                if (this.La !== a) {\n                    Qa = [];\n                    var b = this.La;\n                    null !== b ? (b.B = void 0, b.innerHTML = \"\", null !== this.sa && (b = this.sa.Ea, this.removeEventListener(b, \"touchstart\", this.pw, !1), this.removeEventListener(b, \"touchmove\", this.ow, !1), this.removeEventListener(b, \"touchend\", this.nw, !1), this.sa.Fx()), b = this.toolManager, null !== b && (b.mouseDownTools.each(function (a) {\n                            a.cancelWaitAfter()\n                        }), b.mouseMoveTools.each(function (a) {\n                            a.cancelWaitAfter()\n                        }),\n                        b.mouseUpTools.each(function (a) {\n                            a.cancelWaitAfter()\n                        })), b.cancelWaitAfter(), this.currentTool.doCancel(), this.Db = this.sa = null, this.removeEventListener(x, \"resize\", this.vw, !1), this.removeEventListener(x, \"mousemove\", this.qk, !0), this.removeEventListener(x, \"mousedown\", this.pk, !0), this.removeEventListener(x, \"mouseup\", this.sk, !0), this.removeEventListener(x, \"wheel\", this.tk, !0), this.removeEventListener(x, \"mouseout\", this.rk, !0), ze === this && (ze = null)) : this.ie = !1;\n                    this.La = null;\n                    if (null !== a) {\n                        if (b = a.B) b.div = null;\n                        Ei(this,\n                            a);\n                        this.Ee()\n                    }\n                }\n            }\n        },\n        xx: {\n            get: function () {\n                return this.Io\n            }\n        },\n        kk: {\n            get: function () {\n                return this.ie\n            }\n        },\n        draggedLink: {\n            get: function () {\n                return this.yr\n            },\n            set: function (a) {\n                this.yr !== a && (this.yr = a, null !== a && (this.ms = a.fromPort, this.ns = a.toPort))\n            }\n        },\n        Xx: {\n            get: function () {\n                return this.ms\n            },\n            set: function (a) {\n                this.ms = a\n            }\n        },\n        Yx: {\n            get: function () {\n                return this.ns\n            },\n            set: function (a) {\n                this.ns = a\n            }\n        },\n        animationManager: {\n            get: function () {\n                return this.Jc\n            }\n        },\n        undoManager: {\n            get: function () {\n                return this.ac.undoManager\n            }\n        },\n        skipsUndoManager: {\n            get: function () {\n                return this.sg\n            },\n            set: function (a) {\n                this.sg = a;\n                this.ac.skipsUndoManager = a\n            }\n        },\n        delaysLayout: {\n            get: function () {\n                return this.tr\n            },\n            set: function (a) {\n                this.tr = a\n            }\n        },\n        opacity: {\n            get: function () {\n                return this.qb\n            },\n            set: function (a) {\n                var b = this.qb;\n                b !== a && ((0 > a || 1 < a) && va(a, \"0 <= value <= 1\",\n                    R, \"opacity\"), this.qb = a, this.g(\"opacity\", b, a), this.M())\n            }\n        },\n        validCycle: {\n            get: function () {\n                return this.Xs\n            },\n            set: function (a) {\n                var b = this.Xs;\n                b !== a && (this.Xs = a, this.g(\"validCycle\", b, a))\n            }\n        },\n        layers: {\n            get: function () {\n                return this.Ja.iterator\n            }\n        },\n        isModelReadOnly: {\n            get: function () {\n                var a = this.ac;\n                return null === a ? !1 : a.isReadOnly\n            },\n            set: function (a) {\n                var b = this.ac;\n                null !== b && (b.isReadOnly = a)\n            }\n        },\n        isReadOnly: {\n            get: function () {\n                return this.Zf\n            },\n            set: function (a) {\n                var b = this.Zf;\n                b !== a && (this.Zf = a, this.g(\"isReadOnly\", b, a))\n            }\n        },\n        isEnabled: {\n            get: function () {\n                return this.Mc\n            },\n            set: function (a) {\n                var b = this.Mc;\n                b !== a && (this.Mc = a, this.g(\"isEnabled\", b, a))\n            }\n        },\n        allowClipboard: {\n            get: function () {\n                return this.Uq\n            },\n            set: function (a) {\n                var b = this.Uq;\n                b !== a && (this.Uq = a, this.g(\"allowClipboard\", b, a))\n            }\n        },\n        allowCopy: {\n            get: function () {\n                return this.Rh\n            },\n            set: function (a) {\n                var b = this.Rh;\n                b !== a && (this.Rh = a, this.g(\"allowCopy\",\n                    b, a))\n            }\n        },\n        allowDelete: {\n            get: function () {\n                return this.Sh\n            },\n            set: function (a) {\n                var b = this.Sh;\n                b !== a && (this.Sh = a, this.g(\"allowDelete\", b, a))\n            }\n        },\n        allowDragOut: {\n            get: function () {\n                return this.Vq\n            },\n            set: function (a) {\n                var b = this.Vq;\n                b !== a && (this.Vq = a, this.g(\"allowDragOut\", b, a))\n            }\n        },\n        allowDrop: {\n            get: function () {\n                return this.Wq\n            },\n            set: function (a) {\n                var b = this.Wq;\n                b !== a && (this.Wq = a, this.g(\"allowDrop\", b, a))\n            }\n        },\n        allowTextEdit: {\n            get: function () {\n                return this.ai\n            },\n            set: function (a) {\n                var b = this.ai;\n                b !== a && (this.ai = a, this.g(\"allowTextEdit\", b, a))\n            }\n        },\n        allowGroup: {\n            get: function () {\n                return this.Th\n            },\n            set: function (a) {\n                var b = this.Th;\n                b !== a && (this.Th = a, this.g(\"allowGroup\", b, a))\n            }\n        },\n        allowUngroup: {\n            get: function () {\n                return this.bi\n            },\n            set: function (a) {\n                var b = this.bi;\n                b !== a && (this.bi = a, this.g(\"allowUngroup\", b, a))\n            }\n        },\n        allowInsert: {\n            get: function () {\n                return this.Yq\n            },\n            set: function (a) {\n                var b =\n                    this.Yq;\n                b !== a && (this.Yq = a, this.g(\"allowInsert\", b, a))\n            }\n        },\n        allowLink: {\n            get: function () {\n                return this.Uh\n            },\n            set: function (a) {\n                var b = this.Uh;\n                b !== a && (this.Uh = a, this.g(\"allowLink\", b, a))\n            }\n        },\n        allowRelink: {\n            get: function () {\n                return this.Wh\n            },\n            set: function (a) {\n                var b = this.Wh;\n                b !== a && (this.Wh = a, this.g(\"allowRelink\", b, a))\n            }\n        },\n        allowMove: {\n            get: function () {\n                return this.Vh\n            },\n            set: function (a) {\n                var b = this.Vh;\n                b !== a && (this.Vh = a, this.g(\"allowMove\", b, a))\n            }\n        },\n        allowReshape: {\n            get: function () {\n                return this.Xh\n            },\n            set: function (a) {\n                var b = this.Xh;\n                b !== a && (this.Xh = a, this.g(\"allowReshape\", b, a))\n            }\n        },\n        allowResize: {\n            get: function () {\n                return this.Yh\n            },\n            set: function (a) {\n                var b = this.Yh;\n                b !== a && (this.Yh = a, this.g(\"allowResize\", b, a))\n            }\n        },\n        allowRotate: {\n            get: function () {\n                return this.Zh\n            },\n            set: function (a) {\n                var b = this.Zh;\n                b !== a && (this.Zh = a, this.g(\"allowRotate\", b, a))\n            }\n        },\n        allowSelect: {\n            get: function () {\n                return this.$h\n            },\n            set: function (a) {\n                var b =\n                    this.$h;\n                b !== a && (this.$h = a, this.g(\"allowSelect\", b, a))\n            }\n        },\n        allowUndo: {\n            get: function () {\n                return this.Zq\n            },\n            set: function (a) {\n                var b = this.Zq;\n                b !== a && (this.Zq = a, this.g(\"allowUndo\", b, a))\n            }\n        },\n        allowZoom: {\n            get: function () {\n                return this.ar\n            },\n            set: function (a) {\n                var b = this.ar;\n                b !== a && (this.ar = a, this.g(\"allowZoom\", b, a))\n            }\n        },\n        hasVerticalScrollbar: {\n            get: function () {\n                return this.dl\n            },\n            set: function (a) {\n                var b = this.dl;\n                b !== a && (this.dl = a, Xi(this), this.M(), this.g(\"hasVerticalScrollbar\",\n                    b, a), Ui(this, !1))\n            }\n        },\n        hasHorizontalScrollbar: {\n            get: function () {\n                return this.cl\n            },\n            set: function (a) {\n                var b = this.cl;\n                b !== a && (this.cl = a, Xi(this), this.M(), this.g(\"hasHorizontalScrollbar\", b, a), Ui(this, !1))\n            }\n        },\n        allowHorizontalScroll: {\n            get: function () {\n                return this.Xq\n            },\n            set: function (a) {\n                var b = this.Xq;\n                b !== a && (this.Xq = a, this.g(\"allowHorizontalScroll\", b, a), Ui(this, !1))\n            }\n        },\n        allowVerticalScroll: {\n            get: function () {\n                return this.$q\n            },\n            set: function (a) {\n                var b =\n                    this.$q;\n                b !== a && (this.$q = a, this.g(\"allowVerticalScroll\", b, a), Ui(this, !1))\n            }\n        },\n        scrollHorizontalLineChange: {\n            get: function () {\n                return this.Cs\n            },\n            set: function (a) {\n                var b = this.Cs;\n                b !== a && (0 > a && va(a, \">= 0\", R, \"scrollHorizontalLineChange\"), this.Cs = a, this.g(\"scrollHorizontalLineChange\", b, a))\n            }\n        },\n        scrollVerticalLineChange: {\n            get: function () {\n                return this.Gs\n            },\n            set: function (a) {\n                var b = this.Gs;\n                b !== a && (0 > a && va(a, \">= 0\", R, \"scrollVerticalLineChange\"), this.Gs = a, this.g(\"scrollVerticalLineChange\",\n                    b, a))\n            }\n        },\n        lastInput: {\n            get: function () {\n                return this.dh\n            },\n            set: function (a) {\n                this.dh = a\n            }\n        },\n        firstInput: {\n            get: function () {\n                return this.Uf\n            },\n            set: function (a) {\n                this.Uf = a\n            }\n        },\n        currentCursor: {\n            get: function () {\n                return this.mr\n            },\n            set: function (a) {\n                \"\" === a && (a = this.xn);\n                if (this.mr !== a) {\n                    var b = this.sa,\n                        c = this.La;\n                    if (null !== b) {\n                        this.mr = a;\n                        var d = b.style.cursor;\n                        b.style.cursor = a;\n                        c.style.cursor = a;\n                        b.style.cursor === d && (b.style.cursor = \"-webkit-\" + a, c.style.cursor =\n                            \"-webkit-\" + a, b.style.cursor === d && (b.style.cursor = \"-moz-\" + a, c.style.cursor = \"-moz-\" + a, b.style.cursor === d && (b.style.cursor = a, c.style.cursor = a)))\n                    }\n                }\n            }\n        },\n        defaultCursor: {\n            get: function () {\n                return this.xn\n            },\n            set: function (a) {\n                \"\" === a && (a = \"auto\");\n                var b = this.xn;\n                b !== a && (this.xn = a, this.g(\"defaultCursor\", b, a))\n            }\n        },\n        click: {\n            get: function () {\n                return this.Nf\n            },\n            set: function (a) {\n                var b = this.Nf;\n                b !== a && (this.Nf = a, this.g(\"click\", b, a))\n            }\n        },\n        doubleClick: {\n            get: function () {\n                return this.Sf\n            },\n            set: function (a) {\n                var b = this.Sf;\n                b !== a && (this.Sf = a, this.g(\"doubleClick\", b, a))\n            }\n        },\n        contextClick: {\n            get: function () {\n                return this.Of\n            },\n            set: function (a) {\n                var b = this.Of;\n                b !== a && (this.Of = a, this.g(\"contextClick\", b, a))\n            }\n        },\n        mouseOver: {\n            get: function () {\n                return this.kg\n            },\n            set: function (a) {\n                var b = this.kg;\n                b !== a && (this.kg = a, this.g(\"mouseOver\", b, a))\n            }\n        },\n        mouseHover: {\n            get: function () {\n                return this.ig\n            },\n            set: function (a) {\n                var b =\n                    this.ig;\n                b !== a && (this.ig = a, this.g(\"mouseHover\", b, a))\n            }\n        },\n        mouseHold: {\n            get: function () {\n                return this.hg\n            },\n            set: function (a) {\n                var b = this.hg;\n                b !== a && (this.hg = a, this.g(\"mouseHold\", b, a))\n            }\n        },\n        mouseDragOver: {\n            get: function () {\n                return this.gs\n            },\n            set: function (a) {\n                var b = this.gs;\n                b !== a && (this.gs = a, this.g(\"mouseDragOver\", b, a))\n            }\n        },\n        mouseDrop: {\n            get: function () {\n                return this.fg\n            },\n            set: function (a) {\n                var b = this.fg;\n                b !== a && (this.fg = a, this.g(\"mouseDrop\", b, a))\n            }\n        },\n        handlesDragDropForTopLevelParts: {\n            get: function () {\n                return this.Ir\n            },\n            set: function (a) {\n                var b = this.Ir;\n                b !== a && (this.Ir = a, this.g(\"handlesDragDropForTopLevelParts\", b, a))\n            }\n        },\n        mouseEnter: {\n            get: function () {\n                return this.gg\n            },\n            set: function (a) {\n                var b = this.gg;\n                b !== a && (this.gg = a, this.g(\"mouseEnter\", b, a))\n            }\n        },\n        mouseLeave: {\n            get: function () {\n                return this.jg\n            },\n            set: function (a) {\n                var b = this.jg;\n                b !== a && (this.jg = a, this.g(\"mouseLeave\", b, a))\n            }\n        },\n        toolTip: {\n            get: function () {\n                return this.ug\n            },\n            set: function (a) {\n                var b = this.ug;\n                b !== a && (this.ug = a, this.g(\"toolTip\", b, a))\n            }\n        },\n        contextMenu: {\n            get: function () {\n                return this.Pf\n            },\n            set: function (a) {\n                var b = this.Pf;\n                b !== a && (this.Pf = a, this.g(\"contextMenu\", b, a))\n            }\n        },\n        commandHandler: {\n            get: function () {\n                return this.gr\n            },\n            set: function (a) {\n                this.gr !== a && (this.gr = a, a.Yd(this))\n            }\n        },\n        toolManager: {\n            get: function () {\n                return this.Ts\n            },\n            set: function (a) {\n                this.Ts !== a &&\n                    (this.Ts = a, a.diagram = this)\n            }\n        },\n        defaultTool: {\n            get: function () {\n                return this.sr\n            },\n            set: function (a) {\n                var b = this.sr;\n                b !== a && (this.sr = a, a.diagram = this, this.currentTool === b && (this.currentTool = a))\n            }\n        },\n        currentTool: {\n            get: function () {\n                return this.pr\n            },\n            set: function (a) {\n                var b = this.pr;\n                null !== b && (b.isActive && b.doDeactivate(), b.cancelWaitAfter(), b.doStop());\n                null === a && (a = this.defaultTool);\n                null !== a && (this.pr = a, a.diagram = this, a.doStart())\n            }\n        },\n        selection: {\n            get: function () {\n                return this.Qu\n            }\n        },\n        maxSelectionCount: {\n            get: function () {\n                return this.cs\n            },\n            set: function (a) {\n                var b = this.cs;\n                if (b !== a)\n                    if (0 <= a && !isNaN(a)) {\n                        if (this.cs = a, this.g(\"maxSelectionCount\", b, a), !this.undoManager.isUndoingRedoing && (a = this.selection.count - a, 0 < a)) {\n                            this.R(\"ChangingSelection\", this.selection);\n                            b = this.selection.na();\n                            for (var c = 0; c < a; c++) b[c].isSelected = !1;\n                            this.R(\"ChangedSelection\", this.selection)\n                        }\n                    } else va(a, \">= 0\", R, \"maxSelectionCount\")\n            }\n        },\n        nodeSelectionAdornmentTemplate: {\n            get: function () {\n                return this.Ro\n            },\n            set: function (a) {\n                var b = this.Ro;\n                b !== a && (this.Ro = a, this.g(\"nodeSelectionAdornmentTemplate\", b, a))\n            }\n        },\n        groupSelectionAdornmentTemplate: {\n            get: function () {\n                return this.Vn\n            },\n            set: function (a) {\n                var b = this.Vn;\n                b !== a && (this.Vn = a, this.g(\"groupSelectionAdornmentTemplate\", b, a))\n            }\n        },\n        linkSelectionAdornmentTemplate: {\n            get: function () {\n                return this.qo\n            },\n            set: function (a) {\n                var b = this.qo;\n                b !== a && (this.qo = a, this.g(\"linkSelectionAdornmentTemplate\",\n                    b, a))\n            }\n        },\n        highlighteds: {\n            get: function () {\n                return this.ru\n            }\n        },\n        isModified: {\n            get: function () {\n                var a = this.undoManager;\n                return a.isEnabled ? null !== a.currentTransaction ? !0 : this.$n && this.Gd !== a.historyIndex : this.$n\n            },\n            set: function (a) {\n                if (this.$n !== a) {\n                    this.$n = a;\n                    var b = this.undoManager;\n                    !a && b.isEnabled && (this.Gd = b.historyIndex);\n                    a || hk(this)\n                }\n            }\n        },\n        model: {\n            get: function () {\n                return this.ac\n            },\n            set: function (a) {\n                var b = this.ac;\n                if (b !== a) {\n                    this.currentTool.doCancel();\n                    null !== b && b.undoManager !== a.undoManager && b.undoManager.isInTransaction && B(\"Do not replace a Diagram.model while a transaction is in progress.\");\n                    this.animationManager.Xc(!0);\n                    var c = Hi(this, !0);\n                    this.ie = !1;\n                    this.sj = !0;\n                    this.Gd = -2;\n                    this.we = !1;\n                    var d = this.Bc;\n                    this.Bc = !0;\n                    zh(this.animationManager, \"Model\");\n                    null !== b && (null !== this.oe && this.oe.each(function (a) {\n                        b.wk(a)\n                    }), b.wk(this.Ic));\n                    this.ac = a;\n                    this.partManager = ik(this.ac.constructor.type);\n                    for (var e = 0; e < c.length; e++) this.add(c[e]);\n                    a.Dh(this.jd);\n                    this.partManager.addAllModeledParts();\n                    a.wk(this.jd);\n                    a.Dh(this.Ic);\n                    null !== this.oe && this.oe.each(function (b) {\n                        a.Dh(b)\n                    });\n                    this.Bc = d;\n                    this.Rb || this.M();\n                    null !== b && a.undoManager.copyProperties(b.undoManager)\n                }\n            }\n        },\n        Z: {\n            get: function () {\n                return this.yu\n            },\n            set: function (a) {\n                this.yu = a\n            }\n        },\n        yt: {\n            get: function () {\n                return this.Yw\n            }\n        },\n        skipsModelSourceBindings: {\n            get: function () {\n                return this.Ru\n            },\n            set: function (a) {\n                this.Ru = a\n            }\n        },\n        Ot: {\n            get: function () {\n                return this.Ls\n            },\n            set: function (a) {\n                this.Ls = a\n            }\n        },\n        nodeTemplate: {\n            get: function () {\n                return this.Ye.H(\"\")\n            },\n            set: function (a) {\n                var b = this.Ye.H(\"\");\n                b !== a && (this.Ye.add(\"\", a), this.g(\"nodeTemplate\", b, a), this.undoManager.isUndoingRedoing || this.xd())\n            }\n        },\n        nodeTemplateMap: {\n            get: function () {\n                return this.Ye\n            },\n            set: function (a) {\n                var b = this.Ye;\n                b !== a && (this.Ye = a, this.g(\"nodeTemplateMap\", b, a), this.undoManager.isUndoingRedoing || this.xd())\n            }\n        },\n        groupTemplate: {\n            get: function () {\n                return this.ah.H(\"\")\n            },\n            set: function (a) {\n                var b = this.ah.H(\"\");\n                b !== a && (this.ah.add(\"\", a), this.g(\"groupTemplate\", b, a), this.undoManager.isUndoingRedoing || this.xd())\n            }\n        },\n        groupTemplateMap: {\n            get: function () {\n                return this.ah\n            },\n            set: function (a) {\n                var b = this.ah;\n                b !== a && (this.ah = a, this.g(\"groupTemplateMap\", b, a), this.undoManager.isUndoingRedoing || this.xd())\n            }\n        },\n        linkTemplate: {\n            get: function () {\n                return this.ag.H(\"\")\n            },\n            set: function (a) {\n                var b = this.ag.H(\"\");\n                b !== a && (this.ag.add(\"\", a), this.g(\"linkTemplate\",\n                    b, a), this.undoManager.isUndoingRedoing || this.xd())\n            }\n        },\n        linkTemplateMap: {\n            get: function () {\n                return this.ag\n            },\n            set: function (a) {\n                var b = this.ag;\n                b !== a && (this.ag = a, this.g(\"linkTemplateMap\", b, a), this.undoManager.isUndoingRedoing || this.xd())\n            }\n        },\n        isMouseCaptured: {\n            get: function () {\n                return this.wu\n            },\n            set: function (a) {\n                var b = this.sa;\n                null !== b && (b = b.Ea, b instanceof SVGElement || (a ? (this.lastInput.bubbles = !1, this.Vm ? (this.removeEventListener(b, \"pointermove\", this.um, !1), this.removeEventListener(b,\n                    \"pointerdown\", this.tm, !1), this.removeEventListener(b, \"pointerup\", this.wm, !1), this.removeEventListener(b, \"pointerout\", this.vm, !1), this.addEventListener(x, \"pointermove\", this.um, !0), this.addEventListener(x, \"pointerdown\", this.tm, !0), this.addEventListener(x, \"pointerup\", this.wm, !0), this.addEventListener(x, \"pointerout\", this.vm, !0)) : (this.removeEventListener(b, \"mousemove\", this.qk, !1), this.removeEventListener(b, \"mousedown\", this.pk, !1), this.removeEventListener(b, \"mouseup\", this.sk, !1), this.removeEventListener(b,\n                    \"mouseout\", this.rk, !1), this.addEventListener(x, \"mousemove\", this.qk, !0), this.addEventListener(x, \"mousedown\", this.pk, !0), this.addEventListener(x, \"mouseup\", this.sk, !0), this.addEventListener(x, \"mouseout\", this.rk, !0)), this.removeEventListener(b, \"wheel\", this.tk, !1), this.addEventListener(x, \"wheel\", this.tk, !0), this.addEventListener(x, \"selectstart\", this.preventDefault, !1)) : (this.Vm ? (this.removeEventListener(x, \"pointermove\", this.um, !0), this.removeEventListener(x, \"pointerdown\", this.tm, !0), this.removeEventListener(x,\n                    \"pointerup\", this.wm, !0), this.removeEventListener(x, \"pointerout\", this.vm, !0), this.addEventListener(b, \"pointermove\", this.um, !1), this.addEventListener(b, \"pointerdown\", this.tm, !1), this.addEventListener(b, \"pointerup\", this.wm, !1), this.addEventListener(b, \"pointerout\", this.vm, !1)) : (this.removeEventListener(x, \"mousemove\", this.qk, !0), this.removeEventListener(x, \"mousedown\", this.pk, !0), this.removeEventListener(x, \"mouseup\", this.sk, !0), this.removeEventListener(x, \"mouseout\", this.rk, !0), this.addEventListener(b, \"mousemove\",\n                    this.qk, !1), this.addEventListener(b, \"mousedown\", this.pk, !1), this.addEventListener(b, \"mouseup\", this.sk, !1), this.addEventListener(b, \"mouseout\", this.rk, !1)), this.removeEventListener(x, \"wheel\", this.tk, !0), this.removeEventListener(x, \"selectstart\", this.preventDefault, !1), this.addEventListener(b, \"wheel\", this.tk, !1)), this.wu = a))\n            }\n        },\n        position: {\n            get: function () {\n                return this.ma\n            },\n            set: function (a) {\n                var b = I.alloc().assign(this.ma);\n                if (!b.w(a)) {\n                    var c = this.viewportBounds.copy();\n                    this.ma.assign(a);\n                    Oh(this.animationManager, b, this.ma);\n                    this.Rb || null === this.sa && !this.Zl.v() || (this.Rb = !0, a = this.scale, Wi(this, this.zn, this.wa / a, this.va / a, this.lj, !1), this.Rb = !1);\n                    this.Rb || this.Bq(c, this.viewportBounds, this.ya, !1)\n                }\n                I.free(b)\n            }\n        },\n        initialPosition: {\n            get: function () {\n                return this.Kr\n            },\n            set: function (a) {\n                this.Kr.w(a) || (this.Kr = a.G())\n            }\n        },\n        initialScale: {\n            get: function () {\n                return this.Lr\n            },\n            set: function (a) {\n                this.Lr !== a && (this.Lr = a)\n            }\n        },\n        grid: {\n            get: function () {\n                null === this.Fb && Ni(this);\n                return this.Fb\n            },\n            set: function (a) {\n                var b = this.Fb;\n                if (b !== a) {\n                    null === b && (Ni(this), b = this.Fb);\n                    a.type !== X.Grid && B(\"Diagram.grid must be a Panel of type Panel.Grid\");\n                    var c = b.panel;\n                    null !== c && c.remove(b);\n                    this.Fb = a;\n                    a.name = \"GRID\";\n                    null !== c && c.add(a);\n                    mj(this);\n                    this.M();\n                    this.g(\"grid\", b, a)\n                }\n            }\n        },\n        viewportBounds: {\n            get: function () {\n                var a = this.Zu,\n                    b = this.ma,\n                    c = this.ya;\n                if (null === this.sa) return this.Zl.v() && a.h(b.x, b.y, this.wa / c, this.va / c), a;\n                a.h(b.x, b.y, Math.max(this.wa,\n                    0) / c, Math.max(this.va, 0) / c);\n                return a\n            }\n        },\n        viewSize: {\n            get: function () {\n                return this.Zl\n            },\n            set: function (a) {\n                var b = this.viewSize;\n                b.w(a) || (this.Zl = a = a.G(), this.wa = a.width, this.va = a.height, this.Na(), this.g(\"viewSize\", b, a))\n            }\n        },\n        fixedBounds: {\n            get: function () {\n                return this.Fr\n            },\n            set: function (a) {\n                var b = this.Fr;\n                b.w(a) || (-Infinity !== a.width && Infinity !== a.height && -Infinity !== a.height || B(\"fixedBounds width/height must not be Infinity\"), this.Fr = a = a.G(), this.Na(), this.g(\"fixedBounds\",\n                    b, a))\n            }\n        },\n        scrollMargin: {\n            get: function () {\n                return this.Fi\n            },\n            set: function (a) {\n                \"number\" === typeof a && (a = new oc(a));\n                var b = this.Fi;\n                b.w(a) || (this.Fi = a = a.G(), this.g(\"scrollMargin\", b, a), this.Ee())\n            }\n        },\n        scrollMode: {\n            get: function () {\n                return this.Gi\n            },\n            set: function (a) {\n                var b = this.Gi;\n                b !== a && (this.Gi = a, a === Vh && Ui(this, !1), this.g(\"scrollMode\", b, a), this.M())\n            }\n        },\n        scrollsPageOnFocus: {\n            get: function () {\n                return this.Hs\n            },\n            set: function (a) {\n                var b = this.Hs;\n                b !== a && (this.Hs = a, this.g(\"scrollsPageOnFocus\", b, a))\n            }\n        },\n        positionComputation: {\n            get: function () {\n                return this.vs\n            },\n            set: function (a) {\n                var b = this.vs;\n                b !== a && (this.vs = a, Ui(this, !1), this.g(\"positionComputation\", b, a))\n            }\n        },\n        scaleComputation: {\n            get: function () {\n                return this.As\n            },\n            set: function (a) {\n                var b = this.As;\n                b !== a && (this.As = a, Sj(this, this.scale, this.scale), this.g(\"scaleComputation\", b, a))\n            }\n        },\n        documentBounds: {\n            get: function () {\n                return this.zn\n            }\n        },\n        isVirtualized: {\n            get: function () {\n                return this.Vr\n            },\n            set: function (a) {\n                var b = this.Vr;\n                b !== a && (this.Vr = a, this.g(\"isVirtualized\", b, a))\n            }\n        },\n        scale: {\n            get: function () {\n                return this.ya\n            },\n            set: function (a) {\n                var b = this.ya;\n                b !== a && Sj(this, b, a)\n            }\n        },\n        defaultScale: {\n            get: function () {\n                return this.yn\n            },\n            set: function (a) {\n                this.yn = a\n            }\n        },\n        autoScale: {\n            get: function () {\n                return this.Lg\n            },\n            set: function (a) {\n                var b = this.Lg;\n                b !== a && (this.Lg = a, this.g(\"autoScale\",\n                    b, a), a !== ni && Ui(this, !1))\n            }\n        },\n        initialAutoScale: {\n            get: function () {\n                return this.Xf\n            },\n            set: function (a) {\n                var b = this.Xf;\n                b !== a && (this.Xf = a, this.g(\"initialAutoScale\", b, a))\n            }\n        },\n        initialViewportSpot: {\n            get: function () {\n                return this.Mr\n            },\n            set: function (a) {\n                var b = this.Mr;\n                b !== a && (a.eb() || B(\"initialViewportSpot must be a specific Spot: \" + a), this.Mr = a, this.g(\"initialViewportSpot\", b, a))\n            }\n        },\n        initialDocumentSpot: {\n            get: function () {\n                return this.Jr\n            },\n            set: function (a) {\n                var b =\n                    this.Jr;\n                b !== a && (a.eb() || B(\"initialViewportSpot must be a specific Spot: \" + a), this.Jr = a, this.g(\"initialDocumentSpot\", b, a))\n            }\n        },\n        minScale: {\n            get: function () {\n                return this.ds\n            },\n            set: function (a) {\n                var b = this.ds;\n                b !== a && (0 < a ? (this.ds = a, this.g(\"minScale\", b, a), a > this.scale && (this.scale = a)) : va(a, \"> 0\", R, \"minScale\"))\n            }\n        },\n        maxScale: {\n            get: function () {\n                return this.bs\n            },\n            set: function (a) {\n                var b = this.bs;\n                b !== a && (0 < a ? (this.bs = a, this.g(\"maxScale\", b, a), a < this.scale && (this.scale =\n                    a)) : va(a, \"> 0\", R, \"maxScale\"))\n            }\n        },\n        zoomPoint: {\n            get: function () {\n                return this.$s\n            },\n            set: function (a) {\n                this.$s.w(a) || (this.$s = a = a.G())\n            }\n        },\n        contentAlignment: {\n            get: function () {\n                return this.lj\n            },\n            set: function (a) {\n                var b = this.lj;\n                b.w(a) || (this.lj = a = a.G(), this.g(\"contentAlignment\", b, a), Ui(this, !1))\n            }\n        },\n        initialContentAlignment: {\n            get: function () {\n                return this.Xn\n            },\n            set: function (a) {\n                var b = this.Xn;\n                b.w(a) || (this.Xn = a = a.G(), this.g(\"initialContentAlignment\",\n                    b, a))\n            }\n        },\n        padding: {\n            get: function () {\n                return this.bb\n            },\n            set: function (a) {\n                \"number\" === typeof a && (a = new oc(a));\n                var b = this.bb;\n                b.w(a) || (this.bb = a = a.G(), this.Na(), this.g(\"padding\", b, a))\n            }\n        },\n        partManager: {\n            get: function () {\n                return this.Ia\n            },\n            set: function (a) {\n                var b = this.Ia;\n                b !== a && (null !== a.diagram && B(\"Cannot share PartManagers between Diagrams: \" + a.toString()), null !== b && b.Yd(null), this.Ia = a, a.Yd(this))\n            }\n        },\n        nodes: {\n            get: function () {\n                return this.partManager.nodes.iterator\n            }\n        },\n        links: {\n            get: function () {\n                return this.partManager.links.iterator\n            }\n        },\n        parts: {\n            get: function () {\n                return this.partManager.parts.iterator\n            }\n        },\n        layout: {\n            get: function () {\n                return this.ic\n            },\n            set: function (a) {\n                var b = this.ic;\n                b !== a && (this.ic = a, a.diagram = this, a.group = null, this.If = !0, this.g(\"layout\", b, a), this.Pb())\n            }\n        },\n        isTreePathToChildren: {\n            get: function () {\n                return this.Ur\n            },\n            set: function (a) {\n                var b = this.Ur;\n                if (b !== a && (this.Ur =\n                        a, this.g(\"isTreePathToChildren\", b, a), !this.undoManager.isUndoingRedoing))\n                    for (a = this.nodes; a.next();) Dk(a.value)\n            }\n        },\n        treeCollapsePolicy: {\n            get: function () {\n                return this.Vs\n            },\n            set: function (a) {\n                var b = this.Vs;\n                b !== a && (a !== pi && a !== Ek && a !== Fk && B(\"Unknown Diagram.treeCollapsePolicy: \" + a), this.Vs = a, this.g(\"treeCollapsePolicy\", b, a))\n            }\n        },\n        Ce: {\n            get: function () {\n                return this.uu\n            },\n            set: function (a) {\n                this.uu = a\n            }\n        },\n        autoScrollInterval: {\n            get: function () {\n                return this.Zm\n            },\n            set: function (a) {\n                var b = this.Zm;\n                b !== a && (this.Zm = a, this.g(\"autoScrollInterval\", b, a))\n            }\n        },\n        autoScrollRegion: {\n            get: function () {\n                return this.an\n            },\n            set: function (a) {\n                \"number\" === typeof a && (a = new oc(a));\n                var b = this.an;\n                b.w(a) || (this.an = a = a.G(), this.Na(), this.g(\"autoScrollRegion\", b, a))\n            }\n        }\n    });\n    ma.Object.defineProperties(R, {\n        licenseKey: {\n            get: function () {\n                return Gk.Xb()\n            },\n            set: function (a) {\n                Gk.add(a)\n            }\n        },\n        version: {\n            get: function () {\n                return Hk\n            }\n        }\n    });\n    R.prototype.makeImageData = R.prototype.Ux;\n    R.prototype.makeImage = R.prototype.cA;\n    R.prototype.addRenderer = R.prototype.Ky;\n    R.prototype.makeSVG = R.prototype.Kv;\n    R.prototype.makeSvg = R.prototype.At;\n    R.prototype.stopAutoScroll = R.prototype.Cf;\n    R.prototype.doAutoScroll = R.prototype.gt;\n    R.prototype.isUnoccupied = R.prototype.lk;\n    R.prototype.raiseDiagramEvent = R.prototype.R;\n    R.prototype.removeDiagramListener = R.prototype.ym;\n    R.prototype.addDiagramListener = R.prototype.Uj;\n    R.prototype.findTreeRoots = R.prototype.zz;\n    R.prototype.layoutDiagram = R.prototype.aA;\n    R.prototype.findTopLevelGroups = R.prototype.rz;\n    R.prototype.findTopLevelNodesAndLinks = R.prototype.sz;\n    R.prototype.findLinksByExample = R.prototype.jt;\n    R.prototype.findNodesByExample = R.prototype.kt;\n    R.prototype.findLinkForData = R.prototype.vc;\n    R.prototype.findNodeForData = R.prototype.Si;\n    R.prototype.findPartForData = R.prototype.wc;\n    R.prototype.findLinkForKey = R.prototype.findLinkForKey;\n    R.prototype.findNodeForKey = R.prototype.Jb;\n    R.prototype.findPartForKey = R.prototype.findPartForKey;\n    R.prototype.rebuildParts = R.prototype.xd;\n    R.prototype.transformViewToDoc = R.prototype.Pt;\n    R.prototype.transformRectDocToView = R.prototype.BA;\n    R.prototype.transformDocToView = R.prototype.Nq;\n    R.prototype.centerRect = R.prototype.ct;\n    R.prototype.scrollToRect = R.prototype.cw;\n    R.prototype.scroll = R.prototype.scroll;\n    R.prototype.highlightCollection = R.prototype.Qz;\n    R.prototype.highlight = R.prototype.Pz;\n    R.prototype.selectCollection = R.prototype.sA;\n    R.prototype.select = R.prototype.select;\n    R.prototype.updateAllRelationshipsFromData = R.prototype.Pq;\n    R.prototype.updateAllTargetBindings = R.prototype.updateAllTargetBindings;\n    R.prototype.commit = R.prototype.commit;\n    R.prototype.rollbackTransaction = R.prototype.Bf;\n    R.prototype.commitTransaction = R.prototype.Ua;\n    R.prototype.startTransaction = R.prototype.ua;\n    R.prototype.raiseChanged = R.prototype.g;\n    R.prototype.raiseChangedEvent = R.prototype.Ya;\n    R.prototype.removeChangedListener = R.prototype.wk;\n    R.prototype.addChangedListener = R.prototype.Dh;\n    R.prototype.removeModelChangedListener = R.prototype.oA;\n    R.prototype.addModelChangedListener = R.prototype.vx;\n    R.prototype.findLayer = R.prototype.im;\n    R.prototype.removeLayer = R.prototype.mA;\n    R.prototype.addLayerAfter = R.prototype.Gy;\n    R.prototype.addLayerBefore = R.prototype.tx;\n    R.prototype.addLayer = R.prototype.$l;\n    R.prototype.moveParts = R.prototype.moveParts;\n    R.prototype.copyParts = R.prototype.ck;\n    R.prototype.removeParts = R.prototype.Jt;\n    R.prototype.remove = R.prototype.remove;\n    R.prototype.add = R.prototype.add;\n    R.prototype.clearDelayedGeometries = R.prototype.gv;\n    R.prototype.setProperties = R.prototype.iw;\n    R.prototype.resetInputOptions = R.prototype.$v;\n    R.prototype.setInputOption = R.prototype.tA;\n    R.prototype.getInputOption = R.prototype.mm;\n    R.prototype.resetRenderingHints = R.prototype.aw;\n    R.prototype.setRenderingHint = R.prototype.ly;\n    R.prototype.getRenderingHint = R.prototype.Be;\n    R.prototype.maybeUpdate = R.prototype.Wc;\n    R.prototype.requestUpdate = R.prototype.Pb;\n    R.prototype.delayInitialization = R.prototype.Zy;\n    R.prototype.isUpdateRequested = R.prototype.Wz;\n    R.prototype.redraw = R.prototype.Ee;\n    R.prototype.invalidateDocumentBounds = R.prototype.Na;\n    R.prototype.findObjectsNear = R.prototype.Ag;\n    R.prototype.findPartsNear = R.prototype.oz;\n    R.prototype.findObjectsIn = R.prototype.tf;\n    R.prototype.findPartsIn = R.prototype.Mx;\n    R.prototype.findObjectsAt = R.prototype.Ti;\n    R.prototype.findPartsAt = R.prototype.nz;\n    R.prototype.findObjectAt = R.prototype.Ub;\n    R.prototype.findPartAt = R.prototype.jm;\n    R.prototype.focusObject = R.prototype.Az;\n    R.prototype.alignDocument = R.prototype.My;\n    R.prototype.zoomToRect = R.prototype.EA;\n    R.prototype.zoomToFit = R.prototype.zoomToFit;\n    R.prototype.diagramScroll = R.prototype.Ex;\n    R.prototype.focus = R.prototype.focus;\n    R.prototype.reset = R.prototype.reset;\n    R.useDOM = function (a) {\n        Ug = a ? void 0 !== x.document : !1\n    };\n    R.isUsingDOM = function () {\n        return Ug\n    };\n    var ze = null,\n        qi = new H,\n        Li = null,\n        Ki = null,\n        Ug = void 0 !== x.document,\n        Fi = null,\n        Gi = \"\",\n        ni = new D(R, \"None\", 0),\n        Zi = new D(R, \"Uniform\", 1),\n        $i = new D(R, \"UniformToFill\", 2),\n        Nf = new D(R, \"CycleAll\", 10),\n        Rf = new D(R, \"CycleNotDirected\", 11),\n        Tf = new D(R, \"CycleNotDirectedFast\", 12),\n        Uf = new D(R, \"CycleNotUndirected\", 13),\n        Of = new D(R, \"CycleDestinationTree\", 14),\n        Qf = new D(R, \"CycleSourceTree\", 15),\n        Vh = new D(R, \"DocumentScroll\", 1),\n        Xh = new D(R, \"InfiniteScroll\", 2),\n        pi = new D(R, \"TreeParentCollapsed\", 21),\n        Ek = new D(R, \"AllParentsCollapsed\", 22),\n        Fk = new D(R,\n            \"AnyParentsCollapsed\", 23),\n        Gk = new E,\n        Hk = \"2.1.11\",\n        Ik = null,\n        li = !1;\n\n    function mi() {\n        if (Ug) {\n            var a = x.document.createElement(\"canvas\"),\n                b = a.getContext(\"2d\"),\n                c = Ra(\"7ca11abfd022028846\");\n            b[c] = Ra(\"398c3597c01238\");\n            for (var d = [\"5da73c80a36455d5038e4972187c3cae51fd22\", qa.Dx + \"4ae6247590da4bb21c324ba3a84e385776\", rd.xF + \"fb236cdfda5de14c134ba1a95a2d4c7cc6f93c1387\", J.za], e = 1; 5 > e; e++) b[Ra(\"7ca11abfd7330390\")](Ra(d[e - 1]), 10, 15 * e);\n            b[c] = Ra(\"39f046ebb36e4b\");\n            for (c = 1; 5 > c; c++) b[Ra(\"7ca11abfd7330390\")](Ra(d[c - 1]), 10, 15 * c);\n            Ik = a\n        }\n    }\n    R.className = \"Diagram\";\n    R.fromDiv = function (a) {\n        var b = a;\n        \"string\" === typeof a && (b = x.document.getElementById(a));\n        return b instanceof HTMLDivElement && b.B instanceof R ? b.B : null\n    };\n    R.inherit = function (a, b) {\n        function c() {}\n        if (Object.getPrototypeOf(a).prototype) throw Error(\"Used go.Diagram.inherit defining already defined class \\n\" + a);\n        c.prototype = b.prototype;\n        a.prototype = new c;\n        a.prototype.constructor = a\n    };\n    R.None = ni;\n    R.Uniform = Zi;\n    R.UniformToFill = $i;\n    R.CycleAll = Nf;\n    R.CycleNotDirected = Rf;\n    R.CycleNotDirectedFast = Tf;\n    R.CycleNotUndirected = Uf;\n    R.CycleDestinationTree = Of;\n    R.CycleSourceTree = Qf;\n    R.DocumentScroll = Vh;\n    R.InfiniteScroll = Xh;\n    R.TreeParentCollapsed = pi;\n    R.AllParentsCollapsed = Ek;\n    R.AnyParentsCollapsed = Fk;\n\n    function Di() {\n        this.Cy = null;\n        this.l = \"zz@orderNum\";\n        \"63ad05bbe23a1786468a4c741b6d2\" === this._tk ? this.Pe = this.l = !0 : this.Pe = null\n    }\n\n    function vj(a, b) {\n        b.Db.setTransform(b.Sb, 0, 0, b.Sb, 0, 0);\n        if (null === a.Pe) {\n            b = \"f\";\n            var c = x[Ra(\"76a715b2f73f148a\")][Ra(\"72ba13b5\")];\n            a.Pe = !0;\n            if (Ug) {\n                var d = R[Ra(\"76a115b6ed251eaf4692\")];\n                if (d)\n                    for (var e = Gk.iterator; e.next();) {\n                        d = e.value;\n                        d = Ra(d).split(Ra(\"39e9\"));\n                        if (6 > d.length) break;\n                        var f = Ra(d[1]).split(\".\");\n                        if (\"7da71ca0\" !== d[4]) break;\n                        var g = Ra(qa[Ra(\"6cae19\")]).split(\".\");\n                        if (f[0] > g[0] || f[0] === g[0] && f[1] >= g[1]) {\n                            f = c[Ra(\"76ad18b4f73e\")];\n                            for (g = c[Ra(\"73a612b6fb191d\")](Ra(\"35e7\")) + 2; g < f; g++) b += c[g];\n                            f = b[Ra(\"73a612b6fb191d\")](Ra(d[2]));\n                            0 > f && Ra(d[2]) !== Ra(\"7da71ca0ad381e90\") && (f = b[Ra(\"73a612b6fb191d\")](Ra(\"76a715b2ef3e149757\")));\n                            0 > f && (f = b[Ra(\"73a612b6fb191d\")](Ra(\"76a715b2ef3e149757\")));\n                            0 > f && (f = c[Ra(\"73a612b6fb191d\")](Ra(\"7baa19a6f76c1988428554\")));\n                            a.Pe = !(0 <= f && f < b[Ra(\"73a612b6fb191d\")](Ra(\"35\")) || -1 === b[Ra(\"73a612b6fb191d\")](Ra(\"35\")));\n                            if (!a.Pe) break;\n                            f = Ra(d[2]);\n                            if (\"#\" !== f[0]) break;\n                            g = x.document.createElement(\"div\");\n                            for (var h = d[0].replace(/[A-Za-z]/g, \"\"); 4 > h.length;) h += \"9\";\n                            h = h.substr(h.length - 4);\n                            d = \"\";\n                            d += [\"gsh\", \"gsf\"][parseInt(h.substr(0,\n                                1), 10) % 2];\n                            d += [\"Header\", \"Background\", \"Display\", \"Feedback\"][parseInt(h.substr(0, 1), 10) % 4];\n                            g[Ra(\"79a417a0f0181a8946\")] = d;\n                            if (x.document[Ra(\"78a712aa\")]) {\n                                x.document[Ra(\"78a712aa\")][Ra(\"7bb806b6ed32388c4a875b\")](g);\n                                h = x.getComputedStyle(g).getPropertyValue(Ra(\"78a704b7e62456904c9b12701b6532a8\"));\n                                x.document[Ra(\"78a712aa\")][Ra(\"68ad1bbcf533388c4a875b\")](g);\n                                if (!h) break;\n                                if (-1 !== h.indexOf(parseInt(f[1] + f[2], 16)) && -1 !== h.indexOf(parseInt(f[3] + f[4], 16))) {\n                                    a.Pe = !1;\n                                    break\n                                } else if (Sa || Ta || Ua || Va)\n                                    for (d = \".\" + d, f = 0; f < document.styleSheets.length; f++) {\n                                        g =\n                                            document.styleSheets[f].rules || document.styleSheets[f].cssRules;\n                                        for (var k in g)\n                                            if (d === g[k].selectorText) {\n                                                a.Pe = !1;\n                                                break\n                                            }\n                                    }\n                            } else a.Pe = null, a.Pe = !1\n                        }\n                    } else {\n                        k = c[Ra(\"76ad18b4f73e\")];\n                        for (e = c[Ra(\"73a612b6fb191d\")](Ra(\"35e7\")) + 2; e < k; e++) b += c[e];\n                        c = b[Ra(\"73a612b6fb191d\")](Ra(\"7da71ca0ad381e90\"));\n                        a.Pe = !(0 <= c && c < b[Ra(\"73a612b6fb191d\")](Ra(\"35\")))\n                    }\n            }\n        }\n        return 0 < a.Pe && a !== a.Cy ? !0 : !1\n    }\n\n    function Ei(a, b) {\n        if (Ug) {\n            void 0 !== b && null !== b || B(\"Diagram setup requires an argument DIV.\");\n            null !== a.La && B(\"Diagram has already completed setup.\");\n            \"string\" === typeof b ? a.La = x.document.getElementById(b) : b instanceof HTMLDivElement ? a.La = b : B(\"No DIV or DIV id supplied: \" + b);\n            null === a.La && B(\"Invalid DIV id; could not get element with id: \" + b);\n            void 0 !== a.La.B && B(\"Invalid div id; div already has a Diagram associated with it.\");\n            \"static\" === x.getComputedStyle(a.La, null).position && (a.La.style.position = \"relative\");\n            a.La.style[\"-webkit-tap-highlight-color\"] = \"rgba(255, 255, 255, 0)\";\n            a.La.style[\"-ms-touch-action\"] = \"none\";\n            a.La.innerHTML = \"\";\n            a.La.B = a;\n            var c = a.Pp ? new Aj(a) : new Ck(a);\n            void 0 !== c.style && (c.style.position = \"absolute\", c.style.top = \"0px\", c.style.left = \"0px\", \"rtl\" === x.getComputedStyle(a.La, null).getPropertyValue(\"direction\") && (a.nl = !0), c.style.zIndex = \"2\", c.style.userSelect = \"none\", c.style.webkitUserSelect = \"none\", c.style.MozUserSelect = \"none\");\n            a.sa = c;\n            a.Db = c.context;\n            b = a.Db;\n            a.Sb = a.computePixelRatio();\n            a.wa = a.La.clientWidth ||\n                1;\n            a.va = a.La.clientHeight || 1;\n            Cj(a, a.wa, a.va);\n            // a.zr = b.V[Ra(\"7eba17a4ca3b1a8346\")][Ra(\"78a118b7\")](b.V, Ik, 4, 4);\n            a.zr = function(){return true;};\n            a.La.insertBefore(c.Ea, a.La.firstChild);\n            c = new Ck(null);\n            c.width = 1;\n            c.height = 1;\n            a.ju = c;\n            a.Rw = c.context;\n            if (Ug) {\n                c = ta(\"div\");\n                var d = ta(\"div\");\n                c.style.position = \"absolute\";\n                c.style.overflow = \"auto\";\n                c.style.width = a.wa + \"px\";\n                c.style.height = a.va + \"px\";\n                c.style.zIndex = \"1\";\n                d.style.position = \"absolute\";\n                d.style.width = \"1px\";\n                d.style.height = \"1px\";\n                a.La.appendChild(c);\n                c.appendChild(d);\n                c.onscroll = Oi;\n                c.onmousedown = Qi;\n                c.ontouchstart =\n                    Qi;\n                c.B = a;\n                c.Ay = !0;\n                c.By = !0;\n                a.Es = c;\n                a.wp = d\n            }\n            a.Ht = ra(function () {\n                a.uh = null;\n                a.M()\n            }, 300);\n            a.vw = ra(function () {\n                Eh(a)\n            }, 250);\n            a.preventDefault = function (a) {\n                a.preventDefault();\n                return !1\n            };\n            a.qk = function (b) {\n                if (a.isEnabled) {\n                    a.Yf = !0;\n                    var c = dj(a, b, !0);\n                    a.doMouseMove();\n                    a.currentTool.isBeyondDragSize() && (a.od = 0);\n                    jj(c, b)\n                }\n            };\n            a.pk = function (b) {\n                if (a.isEnabled)\n                    if (a.Yf = !0, a.je) b.preventDefault();\n                    else {\n                        var c = dj(a, b, !0);\n                        c.down = !0;\n                        c.clickCount = b.detail;\n                        if (Ta || Ua) b.timeStamp - a.Aj < a.Us && !a.currentTool.isBeyondDragSize() ? a.od++ : a.od = 1, a.Aj =\n                            b.timeStamp, c.clickCount = a.od;\n                        c.clone(a.firstInput);\n                        a.doMouseDown();\n                        1 === b.button ? b.preventDefault() : jj(c, b)\n                    }\n            };\n            a.sk = function (b) {\n                if (a.isEnabled)\n                    if (a.je && 2 === b.button) b.preventDefault();\n                    else if (a.je && 0 === b.button && (a.je = !1), a.Pj) b.preventDefault();\n                else {\n                    a.Yf = !0;\n                    var c = dj(a, b, !0);\n                    c.up = !0;\n                    c.clickCount = b.detail;\n                    if (Ta || Ua) c.clickCount = a.od;\n                    c.bubbles = b.bubbles;\n                    c.targetDiagram = fj(b);\n                    a.doMouseUp();\n                    a.Cf();\n                    jj(c, b)\n                }\n            };\n            a.tk = function (b) {\n                if (a.isEnabled) {\n                    var c = dj(a, b, !0);\n                    c.bubbles = !0;\n                    var d = 0,\n                        e = 0;\n                    c.delta = 0;\n                    void 0 !== b.deltaX ?\n                        (0 !== b.deltaX && (d = 0 < b.deltaX ? 1 : -1), 0 !== b.deltaY && (e = 0 < b.deltaY ? 1 : -1), c.delta = Math.abs(b.deltaX) > Math.abs(b.deltaY) ? -d : -e) : void 0 !== b.wheelDeltaX ? (0 !== b.wheelDeltaX && (d = 0 < b.wheelDeltaX ? -1 : 1), 0 !== b.wheelDeltaY && (e = 0 < b.wheelDeltaY ? -1 : 1), c.delta = Math.abs(b.wheelDeltaX) > Math.abs(b.wheelDeltaY) ? -d : -e) : void 0 !== b.wheelDelta && 0 !== b.wheelDelta && (c.delta = 0 < b.wheelDelta ? 1 : -1);\n                    a.doMouseWheel();\n                    jj(c, b)\n                }\n            };\n            a.rk = function (b) {\n                a.isEnabled && (a.Yf = !1, dj(a, b, !0), b = a.currentTool, b.cancelWaitAfter(), b.standardMouseOver())\n            };\n            a.pw = function (b) {\n                if (a.isEnabled) {\n                    a.Pj = !1;\n                    a.je = !0;\n                    var c = gj(a, b, b.targetTouches[0], 1 < b.touches.length),\n                        d = null;\n                    0 < b.targetTouches.length ? d = b.targetTouches[0] : 0 < b.changedTouches.length && (d = b.changedTouches[0]);\n                    if (null !== d) {\n                        var e = d.screenX;\n                        d = d.screenY;\n                        var k = a.lo;\n                        b.timeStamp - a.Aj < a.Us && !(25 < Math.abs(k.x - e) || 25 < Math.abs(k.y - d)) ? a.od++ : a.od = 1;\n                        c.clickCount = a.od;\n                        a.Aj = b.timeStamp;\n                        a.lo.h(e, d)\n                    }\n                    a.doMouseDown();\n                    jj(c, b)\n                }\n            };\n            a.ow = function (b) {\n                if (a.isEnabled) {\n                    var c = null;\n                    0 < b.targetTouches.length ? c = b.targetTouches[0] : 0 <\n                        b.changedTouches.length && (c = b.changedTouches[0]);\n                    c = ij(a, b, c, 1 < b.touches.length);\n                    a.doMouseMove();\n                    jj(c, b)\n                }\n            };\n            a.nw = function (b) {\n                if (a.isEnabled)\n                    if (a.Pj) b.preventDefault();\n                    else if (!(1 < b.touches.length)) {\n                    var c = null,\n                        d = null;\n                    0 < b.targetTouches.length ? d = b.targetTouches[0] : 0 < b.changedTouches.length && (d = b.changedTouches[0]);\n                    var e = hj(a, b, !1, !0, !1, !1);\n                    null !== d && (c = x.document.elementFromPoint(d.clientX, d.clientY), null !== c && c.B instanceof R && c.B !== a && ej(c.B, d, e), ej(a, d, e), e.clickCount = a.od);\n                    null === c ? e.targetDiagram =\n                        fj(b) : c.B ? e.targetDiagram = c.B : e.targetDiagram = null;\n                    e.targetObject = null;\n                    a.doMouseUp();\n                    jj(e, b);\n                    a.je = !1\n                }\n            };\n            a.tm = function (b) {\n                if (a.isEnabled) {\n                    a.Yf = !0;\n                    var c = a.ts;\n                    void 0 === c[b.pointerId] && (c[b.pointerId] = b);\n                    c = a.Kj;\n                    var d = !1;\n                    if (null !== c[0] && c[0].pointerId === b.pointerId) c[0] = b;\n                    else if (null !== c[1] && c[1].pointerId === b.pointerId) c[1] = b, d = !0;\n                    else if (null === c[0]) c[0] = b;\n                    else if (null === c[1]) c[1] = b, d = !0;\n                    else {\n                        b.preventDefault();\n                        return\n                    }\n                    if (\"touch\" === b.pointerType || \"pen\" === b.pointerType) a.Pj = !1, a.je = !0;\n                    c = gj(a, b, b, d);\n                    d =\n                        a.lo;\n                    var e = \"touch\" === b.pointerType || \"pen\" === b.pointerType ? 25 : 10;\n                    b.timeStamp - a.Aj < a.Us && !(Math.abs(d.x - b.screenX) > e || Math.abs(d.y - b.screenY) > e) ? a.od++ : a.od = 1;\n                    c.clickCount = a.od;\n                    a.Aj = b.timeStamp;\n                    a.lo.Fg(b.screenX, b.screenY);\n                    a.doMouseDown();\n                    1 === b.button ? b.preventDefault() : jj(c, b)\n                }\n            };\n            a.um = function (b) {\n                if (a.isEnabled) {\n                    a.Yf = !0;\n                    var c = a.Kj;\n                    if (null !== c[0] && c[0].pointerId === b.pointerId) c[0] = b;\n                    else {\n                        if (null !== c[1] && c[1].pointerId === b.pointerId) {\n                            c[1] = b;\n                            return\n                        }\n                        if (null === c[0]) c[0] = b;\n                        else return\n                    }\n                    c[0].pointerId === b.pointerId &&\n                        (c = ij(a, b, b, null !== c[1]), c.targetDiagram = fj(b), a.doMouseMove(), jj(c, b))\n                }\n            };\n            a.wm = function (b) {\n                if (a.isEnabled) {\n                    a.Yf = !0;\n                    var c = \"touch\" === b.pointerType || \"pen\" === b.pointerType,\n                        d = a.ts;\n                    if (c && a.Pj) delete d[b.pointerId], b.preventDefault();\n                    else if (d = a.Kj, null !== d[0] && d[0].pointerId === b.pointerId) {\n                        d[0] = null;\n                        d = hj(a, b, !1, !0, !0, !1);\n                        var e = x.document.elementFromPoint(b.clientX, b.clientY);\n                        null !== e && e.B instanceof R && e.B !== a && ej(e.B, b, d);\n                        ej(a, b, d);\n                        d.clickCount = a.od;\n                        null === e ? d.targetDiagram = fj(b) : e.B ? d.targetDiagram = e.B :\n                            d.targetDiagram = null;\n                        d.targetObject = null;\n                        a.doMouseUp();\n                        jj(d, b);\n                        c && (a.je = !1)\n                    } else null !== d[1] && d[1].pointerId === b.pointerId && (d[1] = null)\n                }\n            };\n            a.vm = function (b) {\n                if (a.isEnabled) {\n                    a.Yf = !1;\n                    var c = a.ts;\n                    c[b.pointerId] && delete c[b.pointerId];\n                    c = a.Kj;\n                    null !== c[0] && c[0].pointerId === b.pointerId && (c[0] = null);\n                    null !== c[1] && c[1].pointerId === b.pointerId && (c[1] = null);\n                    \"touch\" !== b.pointerType && \"pen\" !== b.pointerType && (b = a.currentTool, b.cancelWaitAfter(), b.standardMouseOver())\n                }\n            };\n            b.sc(!0);\n            Mi(a)\n        }\n    }\n    Di.className = \"DiagramHelper\";\n\n    function df(a) {\n        this.l = void 0 === a ? new I : a;\n        this.u = new I\n    }\n    ma.Object.defineProperties(df.prototype, {\n        point: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l = a\n            }\n        },\n        shifted: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a\n            }\n        }\n    });\n    df.className = \"DraggingInfo\";\n\n    function Nj(a, b, c) {\n        this.node = a;\n        this.info = b;\n        this.Bv = c\n    }\n    Nj.className = \"DraggingNodeInfoPair\";\n\n    function Re() {\n        this.reset()\n    }\n    Re.prototype.reset = function () {\n        this.isGridSnapEnabled = !1;\n        this.isGridSnapRealtime = !0;\n        this.gridSnapCellSize = (new M(NaN, NaN)).freeze();\n        this.gridSnapCellSpot = vc;\n        this.gridSnapOrigin = (new I(NaN, NaN)).freeze();\n        this.Nz = this.dragsTree = this.dragsLink = !1;\n        this.Mz = !0\n    };\n\n    function Jk(a) {\n        1 < arguments.length && B(\"Palette constructor can only take one optional argument, the DIV HTML element or its id.\");\n        R.call(this, a);\n        Kk(this)\n    }\n    la(Jk, R);\n\n    function Kk(a) {\n        a.allowDragOut = !0;\n        a.allowMove = !1;\n        a.isReadOnly = !0;\n        a.contentAlignment = xc;\n        a.layout = new Lk\n    }\n    Jk.prototype.reset = function () {\n        R.prototype.reset.call(this);\n        Kk(this)\n    };\n    Jk.className = \"Palette\";\n\n    function Mk(a) {\n        1 < arguments.length && B(\"Overview constructor can only take one optional argument, the DIV HTML element or its id.\");\n        R.call(this, a);\n        var b = this;\n        this.animationManager.isEnabled = !1;\n        this.Rb = !0;\n        this.Ha = null;\n        this.dl = this.cl = !1;\n        this.u = this.I = !0;\n        this.Za = 0;\n        this.Y = !1;\n        this.Ml = null;\n        this.ly(\"drawShadows\", !1);\n        var c = new U,\n            d = new Lf;\n        d.stroke = \"magenta\";\n        d.strokeWidth = 2;\n        d.fill = \"transparent\";\n        d.name = \"BOXSHAPE\";\n        c.selectable = !0;\n        c.selectionAdorned = !1;\n        c.selectionObjectName = \"BOXSHAPE\";\n        c.locationObjectName = \"BOXSHAPE\";\n        c.resizeObjectName = \"BOXSHAPE\";\n        c.cursor = \"move\";\n        c.add(d);\n        this.l = c;\n        this.allowDelete = this.allowCopy = !1;\n        this.allowSelect = !0;\n        this.autoScrollRegion = new oc(0, 0, 0, 0);\n        this.ma.h(0, 0);\n        this.toolManager.Va(\"Dragging\", new Nk, this.toolManager.mouseMoveTools);\n        this.click = function () {\n            var a = b.observed;\n            if (null !== a) {\n                var c = a.viewportBounds,\n                    d = b.lastInput.documentPoint;\n                a.position = new I(d.x - c.width / 2, d.y - c.height / 2)\n            }\n        };\n        this.Ie = function () {\n            b.Na();\n            Ok(b)\n        };\n        this.Ef = function () {\n            null !== b.observed && (b.Na(), b.M())\n        };\n        this.Oh = function () {\n            1 >\n                b.updateDelay ? b.M() : b.Y || (b.Y = !0, setTimeout(function () {\n                    b.Y = !1;\n                    Pk(b);\n                    b.M()\n                }, b.updateDelay))\n        };\n        this.Yc = function () {\n            null !== b.observed && Ok(b)\n        };\n        this.autoScale = Zi;\n        this.Rb = !1\n    }\n    la(Mk, R);\n    Mk.prototype.computePixelRatio = function () {\n        return 1\n    };\n    Mk.prototype.bc = function () {\n        null === this.La && B(\"No div specified\");\n        null === this.sa && B(\"No canvas specified\");\n        if (!(this.sa instanceof Aj) && (fi(this.box), this.Ac)) {\n            var a = this.observed;\n            if (null !== a && !a.animationManager.isAnimating) {\n                tj(this);\n                var b = this.sa;\n                a = this.Db;\n                a.sc(!0);\n                a.setTransform(1, 0, 0, 1, 0, 0);\n                a.clearRect(0, 0, b.width, b.height);\n                1 > this.updateDelay ? Qk(this) : null !== this.Ml && (a.drawImage(this.Ml.Ea, 0, 0), b = this.kb, b.reset(), 1 !== this.scale && b.scale(this.scale), 0 === this.position.x && 0 === this.position.y || b.translate(-this.position.x,\n                    -this.position.y), a.scale(this.Sb, this.Sb), a.transform(b.m11, b.m12, b.m21, b.m22, b.dx, b.dy));\n                b = this.Ja.j;\n                for (var c = b.length, d = 0; d < c; d++) b[d].bc(a, this);\n                this.Ac = this.mi = !1\n            }\n        }\n    };\n\n    function Pk(a) {\n        var b = a.sa,\n            c = a.Db;\n        if (null !== b && null !== c) {\n            tj(a);\n            if (null === a.Ml) {\n                var d = new Ck(null);\n                d.width = b.width;\n                d.height = b.height;\n                a.Ml = d\n            }\n            try {\n                a.sa = a.Ml, a.Db = a.sa.context, a.Db.sc(!0), a.Db.setTransform(1, 0, 0, 1, 0, 0), a.Db.clearRect(0, 0, a.sa.width, a.sa.height), Qk(a)\n            } finally {\n                a.sa = b, a.Db = c\n            }\n        }\n    }\n\n    function Qk(a) {\n        var b = a.observed;\n        if (null !== b) {\n            var c = a.drawsTemporaryLayers,\n                d = a.drawsGrid && c,\n                e = b.grid;\n            d && null !== e && e.visible && !isNaN(e.width) && !isNaN(e.height) && (e = N.alloc().assign(a.viewportBounds).Hc(b.viewportBounds), mj(b, e), N.free(e), Si(b));\n            var f = a.kb;\n            f.reset();\n            1 !== a.scale && f.scale(a.scale);\n            0 === a.position.x && 0 === a.position.y || f.translate(-a.position.x, -a.position.y);\n            e = a.Db;\n            e.scale(a.Sb, a.Sb);\n            e.transform(f.m11, f.m12, f.m21, f.m22, f.dx, f.dy);\n            b = b.Ja.j;\n            f = b.length;\n            for (var g = 0; g < f; g++) {\n                var h = b[g],\n                    k = a;\n                if (h.visible &&\n                    0 !== h.opacity) {\n                    var l = h.diagram.grid.part;\n                    if (!c && h.isTemporary) d && l.layer === h && (h = hi(h, e), l.bc(e, k), e.globalAlpha = h);\n                    else {\n                        for (var m = hi(h, e), n = k.scale, p = N.alloc(), r = h.Ca.j, q = r.length, u = 0; u < q; u++) {\n                            var v = r[u];\n                            (d || v !== l) && h.Pi(e, v, k, null, n, p)\n                        }\n                        N.free(p);\n                        e.globalAlpha = m\n                    }\n                }\n            }\n        }\n    }\n\n    function Ok(a) {\n        var b = a.box;\n        if (null !== b) {\n            var c = a.observed;\n            if (null !== c) {\n                a.Ac = !0;\n                c = c.viewportBounds;\n                var d = b.selectionObject,\n                    e = M.alloc();\n                e.h(c.width, c.height);\n                d.desiredSize = e;\n                M.free(e);\n                a = 2 / a.scale;\n                d instanceof Lf && (d.strokeWidth = a);\n                b.location = new I(c.x - a / 2, c.y - a / 2);\n                b.isSelected = !0\n            }\n        }\n    }\n    Mk.prototype.computeBounds = function () {\n        var a = this.observed;\n        if (null === a) return ic;\n        var b = a.documentBounds.copy();\n        b.Hc(a.viewportBounds);\n        return b\n    };\n    Mk.prototype.Sx = function () {\n        !0 !== this.Ac && (this.Ac = !0, this.Pb())\n    };\n    Mk.prototype.Bq = function (a, b, c, d) {\n        this.Rb || (Ri(this), this.M(), Xi(this), this.Na(), Ok(this), this.Rd.scale = c, this.Rd.position.x = a.x, this.Rd.position.y = a.y, this.Rd.bounds.assign(a), this.Rd.Jv = d, this.R(\"ViewportBoundsChanged\", this.Rd, a))\n    };\n    ma.Object.defineProperties(Mk.prototype, {\n        observed: {\n            get: function () {\n                return this.Ha\n            },\n            set: function (a) {\n                var b = this.Ha;\n                a instanceof Mk && B(\"Overview.observed Diagram may not be an Overview itself: \" + a);\n                if (b !== a) {\n                    null !== b && (this.remove(this.box), b.ym(\"ViewportBoundsChanged\", this.Ie), b.ym(\"DocumentBoundsChanged\", this.Ef), b.ym(\"InvalidateDraw\", this.Oh), b.ym(\"AnimationFinished\", this.Yc));\n                    this.Ha = a;\n                    null !== a && (a.Uj(\"ViewportBoundsChanged\", this.Ie), a.Uj(\"DocumentBoundsChanged\", this.Ef),\n                        a.Uj(\"InvalidateDraw\", this.Oh), a.Uj(\"AnimationFinished\", this.Yc), this.add(this.box), Ok(this));\n                    this.Na();\n                    if (null === a) {\n                        this.Ml = null;\n                        var c = this.sa,\n                            d = this.Db;\n                        c && d && (d.setTransform(1, 0, 0, 1, 0, 0), d.clearRect(0, 0, c.width, c.height))\n                    } else Pk(this), Ok(this), this.M();\n                    this.g(\"observed\", b, a)\n                }\n            }\n        },\n        box: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                var b = this.l;\n                b !== a && (this.l = a, this.remove(b), this.add(this.l), Ok(this), this.g(\"box\", b, a))\n            }\n        },\n        drawsTemporaryLayers: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I !== a && (this.I = a, this.Ee())\n            }\n        },\n        drawsGrid: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u !== a && (this.u = a, this.Ee())\n            }\n        },\n        updateDelay: {\n            get: function () {\n                return this.Za\n            },\n            set: function (a) {\n                0 > a && (a = 0);\n                this.Za !== a && (this.Za = a)\n            }\n        }\n    });\n    Mk.className = \"Overview\";\n\n    function Nk() {\n        Qe.call(this);\n        this.l = null\n    }\n    la(Nk, Qe);\n    Nk.prototype.canStart = function () {\n        if (!this.isEnabled) return !1;\n        var a = this.diagram;\n        if (null === a || !a.allowMove || !a.allowSelect) return !1;\n        var b = a.observed;\n        if (null === b) return !1;\n        var c = a.lastInput;\n        if (!c.left || a.currentTool !== this && (!this.isBeyondDragSize() || c.isTouchEvent && c.timestamp - a.firstInput.timestamp < this.delay)) return !1;\n        null === this.findDraggablePart() && (c = b.viewportBounds, this.l = new I(c.width / 2, c.height / 2), a = a.firstInput.documentPoint, b.position = new I(a.x - this.l.x, a.y - this.l.y));\n        return !0\n    };\n    Nk.prototype.doActivate = function () {\n        this.l = null;\n        Qe.prototype.doActivate.call(this)\n    };\n    Nk.prototype.moveParts = function () {\n        var a = this.diagram,\n            b = a.observed;\n        if (null !== b) {\n            var c = a.box;\n            if (null !== c) {\n                if (null === this.l) {\n                    var d = a.firstInput.documentPoint;\n                    c = c.location;\n                    this.l = new I(d.x - c.x, d.y - c.y)\n                }\n                a = a.lastInput.documentPoint;\n                b.position = new I(a.x - this.l.x, a.y - this.l.y)\n            }\n        }\n    };\n    Nk.className = \"OverviewDraggingTool\";\n\n    function Rk() {\n        Ya(this);\n        this.B = ze;\n        this.Za = this.I = this.u = !0;\n        this.Y = this.Ha = this.jd = this.Ia = !1;\n        this.yi = this.l = null;\n        this.Yc = 1.05;\n        this.Au = NaN;\n        this.Ww = null;\n        this.bv = NaN;\n        this.av = ic;\n        this.pg = null;\n        this.Ic = 200\n    }\n    Rk.prototype.toString = function () {\n        return \"CommandHandler\"\n    };\n    Rk.prototype.Yd = function (a) {\n        this.B = a\n    };\n    Rk.prototype.doKeyDown = function () {\n        var a = this.diagram,\n            b = a.lastInput,\n            c = Wa ? b.meta : b.control,\n            d = b.shift,\n            e = b.alt,\n            f = b.key;\n        !c || \"C\" !== f && \"Insert\" !== f ? c && \"X\" === f || d && \"Del\" === f ? this.canCutSelection() && this.cutSelection() : c && \"V\" === f || d && \"Insert\" === f ? this.canPasteSelection() && this.pasteSelection() : c && \"Y\" === f || e && d && \"Backspace\" === f ? this.canRedo() && this.redo() : c && \"Z\" === f || e && \"Backspace\" === f ? this.canUndo() && this.undo() : \"Del\" === f || \"Backspace\" === f ? this.canDeleteSelection() && this.deleteSelection() : c && \"A\" === f ? this.canSelectAll() &&\n            this.selectAll() : \"Esc\" === f ? this.canStopCommand() && this.stopCommand() : \"Up\" === f ? a.allowVerticalScroll && (c ? a.scroll(\"pixel\", \"up\") : a.scroll(\"line\", \"up\")) : \"Down\" === f ? a.allowVerticalScroll && (c ? a.scroll(\"pixel\", \"down\") : a.scroll(\"line\", \"down\")) : \"Left\" === f ? a.allowHorizontalScroll && (c ? a.scroll(\"pixel\", \"left\") : a.scroll(\"line\", \"left\")) : \"Right\" === f ? a.allowHorizontalScroll && (c ? a.scroll(\"pixel\", \"right\") : a.scroll(\"line\", \"right\")) : \"PageUp\" === f ? d && a.allowHorizontalScroll ? a.scroll(\"page\", \"left\") : a.allowVerticalScroll &&\n            a.scroll(\"page\", \"up\") : \"PageDown\" === f ? d && a.allowHorizontalScroll ? a.scroll(\"page\", \"right\") : a.allowVerticalScroll && a.scroll(\"page\", \"down\") : \"Home\" === f ? c && a.allowVerticalScroll ? a.scroll(\"document\", \"up\") : !c && a.allowHorizontalScroll && a.scroll(\"document\", \"left\") : \"End\" === f ? c && a.allowVerticalScroll ? a.scroll(\"document\", \"down\") : !c && a.allowHorizontalScroll && a.scroll(\"document\", \"right\") : \" \" === f ? this.canScrollToPart() && this.scrollToPart() : \"Subtract\" === f ? this.canDecreaseZoom() && this.decreaseZoom() : \"Add\" === f ? this.canIncreaseZoom() &&\n            this.increaseZoom() : c && \"0\" === f ? this.canResetZoom() && this.resetZoom() : d && \"Z\" === f ? this.canZoomToFit() && this.zoomToFit() : c && !d && \"G\" === f ? this.canGroupSelection() && this.groupSelection() : c && d && \"G\" === f ? this.canUngroupSelection() && this.ungroupSelection() : b.event && 113 === b.event.which ? this.canEditTextBlock() && this.editTextBlock() : b.event && 93 === b.event.which ? this.canShowContextMenu() && this.showContextMenu() : b.bubbles = !0 : this.canCopySelection() && this.copySelection()\n    };\n    Rk.prototype.doKeyUp = function () {\n        this.diagram.lastInput.bubbles = !0\n    };\n    Rk.prototype.stopCommand = function () {\n        var a = this.diagram,\n            b = a.currentTool;\n        b instanceof Oa && a.allowSelect && a.clearSelection();\n        null !== b && b.doCancel()\n    };\n    Rk.prototype.canStopCommand = function () {\n        return !0\n    };\n    Rk.prototype.selectAll = function () {\n        var a = this.diagram;\n        a.M();\n        try {\n            a.currentCursor = \"wait\";\n            a.R(\"ChangingSelection\", a.selection);\n            for (var b = a.parts; b.next();) b.value.isSelected = !0;\n            for (var c = a.nodes; c.next();) c.value.isSelected = !0;\n            for (var d = a.links; d.next();) d.value.isSelected = !0\n        } finally {\n            a.R(\"ChangedSelection\", a.selection), a.currentCursor = \"\"\n        }\n    };\n    Rk.prototype.canSelectAll = function () {\n        return this.diagram.allowSelect\n    };\n    Rk.prototype.deleteSelection = function () {\n        var a = this.diagram;\n        try {\n            a.currentCursor = \"wait\";\n            a.R(\"ChangingSelection\", a.selection);\n            a.ua(\"Delete\");\n            a.R(\"SelectionDeleting\", a.selection);\n            for (var b = new F, c = a.selection.iterator; c.next();) Sk(b, c.value, !0, this.deletesTree ? Infinity : 0, this.deletesConnectedLinks ? null : !1, function (a) {\n                return a.canDelete()\n            });\n            a.Jt(b, !0);\n            a.R(\"SelectionDeleted\", b)\n        } finally {\n            a.Ua(\"Delete\"), a.R(\"ChangedSelection\", a.selection), a.currentCursor = \"\"\n        }\n    };\n    Rk.prototype.canDeleteSelection = function () {\n        var a = this.diagram;\n        return a.isReadOnly || a.isModelReadOnly || !a.allowDelete || 0 === a.selection.count ? !1 : !0\n    };\n    Rk.prototype.copySelection = function () {\n        var a = this.diagram,\n            b = new F;\n        for (a = a.selection.iterator; a.next();) Sk(b, a.value, !0, this.copiesTree ? Infinity : 0, this.copiesConnectedLinks, function (a) {\n            return a.canCopy()\n        });\n        this.copyToClipboard(b)\n    };\n    Rk.prototype.canCopySelection = function () {\n        var a = this.diagram;\n        return a.allowCopy && a.allowClipboard && 0 !== a.selection.count ? !0 : !1\n    };\n    Rk.prototype.cutSelection = function () {\n        this.copySelection();\n        this.deleteSelection()\n    };\n    Rk.prototype.canCutSelection = function () {\n        var a = this.diagram;\n        return !a.isReadOnly && !a.isModelReadOnly && a.allowCopy && a.allowDelete && a.allowClipboard && 0 !== a.selection.count ? !0 : !1\n    };\n    Rk.prototype.copyToClipboard = function (a) {\n        var b = this.diagram,\n            c = null;\n        if (null === a) Fi = null, Gi = \"\";\n        else {\n            c = b.model;\n            var d = !1,\n                e = !1,\n                f = null;\n            try {\n                c.qm() && (d = c.bk, c.bk = this.copiesParentKey), c.ik() && (e = c.ak, c.ak = this.copiesGroupKey), f = b.ck(a, null, !0)\n            } finally {\n                c.qm() && (c.bk = d), c.ik() && (c.ak = e), c = new E, c.addAll(f), Fi = c, Gi = b.model.dataFormat\n            }\n        }\n        b.R(\"ClipboardChanged\", c)\n    };\n    Rk.prototype.pasteFromClipboard = function () {\n        var a = new F,\n            b = Fi;\n        if (null === b) return a;\n        var c = this.diagram;\n        if (Gi !== c.model.dataFormat) return a;\n        var d = c.model,\n            e = !1,\n            f = !1,\n            g = null;\n        try {\n            d.qm() && (e = d.bk, d.bk = this.copiesParentKey), d.ik() && (f = d.ak, d.ak = this.copiesGroupKey), g = c.ck(b, c, !1)\n        } finally {\n            for (d.qm() && (d.bk = e), d.ik() && (d.ak = f), b = g.iterator; b.next();) c = b.value, d = b.key, c.location.v() || (d.location.v() ? c.location = d.location : !c.position.v() && d.position.v() && (c.position = d.position)), a.add(c)\n        }\n        return a\n    };\n    Rk.prototype.pasteSelection = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram;\n        try {\n            b.currentCursor = \"wait\";\n            b.R(\"ChangingSelection\", b.selection);\n            b.ua(\"Paste\");\n            var c = this.pasteFromClipboard();\n            0 < c.count && b.clearSelection(!0);\n            for (var d = c.iterator; d.next();) d.value.isSelected = !0;\n            if (null !== a) {\n                var e = b.computePartsBounds(b.selection);\n                if (e.v()) {\n                    var f = this.computeEffectiveCollection(b.selection, b.Qk);\n                    sf(b, f, new I(a.x - e.centerX, a.y - e.centerY), b.Qk, !1)\n                }\n            }\n            b.R(\"ClipboardPasted\", c)\n        } finally {\n            b.Ua(\"Paste\"), b.R(\"ChangedSelection\",\n                b.selection), b.currentCursor = \"\"\n        }\n    };\n    Rk.prototype.canPasteSelection = function () {\n        var a = this.diagram;\n        return a.isReadOnly || a.isModelReadOnly || !a.allowInsert || !a.allowClipboard || null === Fi || 0 === Fi.count || Gi !== a.model.dataFormat ? !1 : !0\n    };\n    Rk.prototype.undo = function () {\n        this.diagram.undoManager.undo()\n    };\n    Rk.prototype.canUndo = function () {\n        var a = this.diagram;\n        return a.isReadOnly || a.isModelReadOnly ? !1 : a.allowUndo && a.undoManager.canUndo()\n    };\n    Rk.prototype.redo = function () {\n        this.diagram.undoManager.redo()\n    };\n    Rk.prototype.canRedo = function () {\n        var a = this.diagram;\n        return a.isReadOnly || a.isModelReadOnly ? !1 : a.allowUndo && a.undoManager.canRedo()\n    };\n    Rk.prototype.decreaseZoom = function (a) {\n        void 0 === a && (a = 1 / this.zoomFactor);\n        var b = this.diagram;\n        b.autoScale === ni && (a = b.scale * a, a < b.minScale || a > b.maxScale || (b.scale = a))\n    };\n    Rk.prototype.canDecreaseZoom = function (a) {\n        void 0 === a && (a = 1 / this.zoomFactor);\n        var b = this.diagram;\n        if (b.autoScale !== ni) return !1;\n        a = b.scale * a;\n        return a < b.minScale || a > b.maxScale ? !1 : b.allowZoom\n    };\n    Rk.prototype.increaseZoom = function (a) {\n        void 0 === a && (a = this.zoomFactor);\n        var b = this.diagram;\n        b.autoScale === ni && (a = b.scale * a, a < b.minScale || a > b.maxScale || (b.scale = a))\n    };\n    Rk.prototype.canIncreaseZoom = function (a) {\n        void 0 === a && (a = this.zoomFactor);\n        var b = this.diagram;\n        if (b.autoScale !== ni) return !1;\n        a = b.scale * a;\n        return a < b.minScale || a > b.maxScale ? !1 : b.allowZoom\n    };\n    Rk.prototype.resetZoom = function (a) {\n        void 0 === a && (a = this.defaultScale);\n        var b = this.diagram;\n        a < b.minScale || a > b.maxScale || (b.scale = a)\n    };\n    Rk.prototype.canResetZoom = function (a) {\n        void 0 === a && (a = this.defaultScale);\n        var b = this.diagram;\n        return a < b.minScale || a > b.maxScale ? !1 : b.allowZoom\n    };\n    Rk.prototype.zoomToFit = function () {\n        var a = this.diagram,\n            b = a.animationManager;\n        b.Xc();\n        a.Ee();\n        var c = a.position,\n            d = a.scale;\n        zh(b, \"Zoom To Fit\");\n        d === this.bv && !isNaN(this.Au) && a.documentBounds.w(this.av) ? (a.scale = this.Au, a.position = this.Ww, this.bv = NaN, this.av = ic) : (this.Au = d, this.Ww = c.copy(), a.zoomToFit(), this.bv = a.scale, this.av = a.documentBounds.copy());\n        Bh(b)\n    };\n    Rk.prototype.canZoomToFit = function () {\n        return this.diagram.allowZoom\n    };\n    Rk.prototype.scrollToPart = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram;\n        Ii(b);\n        if (null === a) {\n            try {\n                null !== this.pg && (this.pg.next() ? a = this.pg.value : this.pg = null)\n            } catch (k) {\n                this.pg = null\n            }\n            null === a && (0 < b.highlighteds.count ? this.pg = b.highlighteds.iterator : 0 < b.selection.count && (this.pg = b.selection.iterator), null !== this.pg && this.pg.next() && (a = this.pg.value))\n        }\n        if (null !== a) {\n            var c = b.animationManager;\n            zh(c, \"Scroll To Part\");\n            var d = this.scrollToPartPause;\n            if (0 < d) {\n                var e = Tk(this, a, [a]);\n                if (1 === e.length) b.ua(), b.ct(a.actualBounds),\n                    b.Ua(\"Scroll To Part\");\n                else {\n                    var f = function () {\n                            b.ua();\n                            for (var a = e.pop(); 0 < e.length && a instanceof W && a.isTreeExpanded && (!(a instanceof T) || a.isSubGraphExpanded);) a = e.pop();\n                            0 < e.length ? (a instanceof U && b.cw(a.actualBounds), a instanceof W && !a.isTreeExpanded && (a.isTreeExpanded = !0), a instanceof T && !a.isSubGraphExpanded && (a.isSubGraphExpanded = !0)) : (a instanceof U && b.ct(a.actualBounds), b.ym(\"LayoutCompleted\", g));\n                            b.Ua(\"Scroll To Part\")\n                        },\n                        g = function () {\n                            sa(f, (c.isEnabled ? c.duration : 0) + d)\n                        };\n                    b.Uj(\"LayoutCompleted\",\n                        g);\n                    f()\n                }\n            } else {\n                var h = b.position.copy();\n                b.ct(a.actualBounds);\n                h.Ma(b.position) && c.Xc()\n            }\n        }\n    };\n\n    function Tk(a, b, c) {\n        if (b.isVisible()) return c;\n        if (b instanceof Je) Tk(a, b.adornedPart, c);\n        else if (b instanceof S) {\n            var d = b.fromNode;\n            null !== d && Tk(a, d, c);\n            b = b.toNode;\n            null !== b && Tk(a, b, c)\n        } else b instanceof W && (d = b.labeledLink, null !== d && Tk(a, d, c), d = b.Bg(), null !== d && (d.isTreeExpanded || d.wasTreeExpanded || c.push(d), Tk(a, d, c))), b = b.containingGroup, null !== b && (b.isSubGraphExpanded || b.wasSubGraphExpanded || c.push(b), Tk(a, b, c));\n        return c\n    }\n    Rk.prototype.canScrollToPart = function (a) {\n        void 0 === a && (a = null);\n        if (null !== a && !(a instanceof U)) return !1;\n        a = this.diagram;\n        return 0 === a.selection.count && 0 === a.highlighteds.count ? !1 : a.allowHorizontalScroll && a.allowVerticalScroll\n    };\n    Rk.prototype.collapseTree = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram;\n        try {\n            b.ua(\"Collapse Tree\");\n            zh(b.animationManager, \"Collapse Tree\");\n            var c = new E;\n            if (null !== a && a.isTreeExpanded) a.collapseTree(), c.add(a);\n            else if (null === a)\n                for (var d = b.selection.iterator; d.next();) {\n                    var e = d.value;\n                    e instanceof W && e.isTreeExpanded && (e.collapseTree(), c.add(e))\n                }\n            b.R(\"TreeCollapsed\", c)\n        } finally {\n            b.Ua(\"Collapse Tree\")\n        }\n    };\n    Rk.prototype.canCollapseTree = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram;\n        if (b.isReadOnly) return !1;\n        if (null !== a) {\n            if (!(a instanceof W && a.isTreeExpanded)) return !1;\n            if (0 < a.nq().count) return !0\n        } else\n            for (a = b.selection.iterator; a.next();)\n                if (b = a.value, b instanceof W && b.isTreeExpanded && 0 < b.nq().count) return !0;\n        return !1\n    };\n    Rk.prototype.expandTree = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram;\n        try {\n            b.ua(\"Expand Tree\");\n            zh(b.animationManager, \"Expand Tree\");\n            var c = new E;\n            if (null !== a && !a.isTreeExpanded) a.expandTree(), c.add(a);\n            else if (null === a)\n                for (var d = b.selection.iterator; d.next();) {\n                    var e = d.value;\n                    e instanceof W && !e.isTreeExpanded && (e.expandTree(), c.add(e))\n                }\n            b.R(\"TreeExpanded\", c)\n        } finally {\n            b.Ua(\"Expand Tree\")\n        }\n    };\n    Rk.prototype.canExpandTree = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram;\n        if (b.isReadOnly) return !1;\n        if (null !== a) {\n            if (!(a instanceof W) || a.isTreeExpanded) return !1;\n            if (0 < a.nq().count) return !0\n        } else\n            for (a = b.selection.iterator; a.next();)\n                if (b = a.value, b instanceof W && !b.isTreeExpanded && 0 < b.nq().count) return !0;\n        return !1\n    };\n    Rk.prototype.groupSelection = function () {\n        var a = this.diagram,\n            b = a.model;\n        if (b.jk()) {\n            var c = this.archetypeGroupData;\n            if (null !== c) {\n                var d = null;\n                try {\n                    a.currentCursor = \"wait\";\n                    a.R(\"ChangingSelection\", a.selection);\n                    a.ua(\"Group\");\n                    for (var e = new E, f = a.selection.iterator; f.next();) {\n                        var g = f.value;\n                        g.Wb() && g.canGroup() && e.add(g)\n                    }\n                    for (var h = new E, k = e.iterator; k.next();) {\n                        var l = k.value;\n                        f = !1;\n                        for (var m = e.iterator; m.next();)\n                            if (l.Wd(m.value)) {\n                                f = !0;\n                                break\n                            } f || h.add(l)\n                    }\n                    if (0 < h.count) {\n                        var n = h.first().containingGroup;\n                        if (null !== n)\n                            for (; null !==\n                                n;) {\n                                e = !1;\n                                for (var p = h.iterator; p.next();)\n                                    if (!p.value.Wd(n)) {\n                                        e = !0;\n                                        break\n                                    } if (e) n = n.containingGroup;\n                                else break\n                            }\n                        if (c instanceof T) yg(c), d = c.copy(), null !== d && a.add(d);\n                        else if (b.Hv(c)) {\n                            var r = b.copyNodeData(c);\n                            za(r) && (b.pf(r), d = a.Si(r))\n                        }\n                        if (null !== d) {\n                            null !== n && this.isValidMember(n, d) && (d.containingGroup = n);\n                            for (var q = h.iterator; q.next();) {\n                                var u = q.value;\n                                this.isValidMember(d, u) && (u.containingGroup = d)\n                            }\n                            a.clearSelection(!0);\n                            d.isSelected = !0\n                        }\n                    }\n                    a.R(\"SelectionGrouped\", d)\n                } finally {\n                    a.Ua(\"Group\"), a.R(\"ChangedSelection\", a.selection),\n                        a.currentCursor = \"\"\n                }\n            }\n        }\n    };\n    Rk.prototype.canGroupSelection = function () {\n        var a = this.diagram;\n        if (a.isReadOnly || a.isModelReadOnly || !a.allowInsert || !a.allowGroup || !a.model.jk() || null === this.archetypeGroupData) return !1;\n        for (a = a.selection.iterator; a.next();) {\n            var b = a.value;\n            if (b.Wb() && b.canGroup()) return !0\n        }\n        return !1\n    };\n\n    function Uk(a) {\n        var b = Fa();\n        for (a = a.iterator; a.next();) {\n            var c = a.value;\n            c instanceof S || b.push(c)\n        }\n        a = new F;\n        c = b.length;\n        for (var d = 0; d < c; d++) {\n            for (var e = b[d], f = !0, g = 0; g < c; g++)\n                if (e.Wd(b[g])) {\n                    f = !1;\n                    break\n                } f && a.add(e)\n        }\n        Ha(b);\n        return a\n    }\n    Rk.prototype.isValidMember = function (a, b) {\n        if (null === b || a === b || b instanceof S) return !1;\n        if (null !== a) {\n            if (a === b || a.Wd(b)) return !1;\n            var c = a.memberValidation;\n            if (null !== c && !c(a, b) || null === a.data && null !== b.data || null !== a.data && null === b.data) return !1\n        }\n        c = this.memberValidation;\n        return null !== c ? c(a, b) : !0\n    };\n    Rk.prototype.ungroupSelection = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram,\n            c = b.model;\n        if (c.jk()) try {\n            b.currentCursor = \"wait\";\n            b.R(\"ChangingSelection\", b.selection);\n            b.ua(\"Ungroup\");\n            var d = new E;\n            if (null !== a) d.add(a);\n            else\n                for (var e = b.selection.iterator; e.next();) {\n                    var f = e.value;\n                    f instanceof T && f.canUngroup() && d.add(f)\n                }\n            var g = new E;\n            if (0 < d.count) {\n                b.clearSelection(!0);\n                for (var h = d.iterator; h.next();) {\n                    var k = h.value;\n                    k.expandSubGraph();\n                    var l = k.containingGroup,\n                        m = null !== l && null !== l.data ? c.ja(l.data) : void 0;\n                    g.addAll(k.memberParts);\n                    for (var n = g.iterator; n.next();) {\n                        var p = n.value;\n                        p.isSelected = !0;\n                        if (!(p instanceof S)) {\n                            var r = p.data;\n                            null !== r ? c.Mt(r, m) : p.containingGroup = l\n                        }\n                    }\n                    b.remove(k)\n                }\n            }\n            b.R(\"SelectionUngrouped\", d, g)\n        } finally {\n            b.Ua(\"Ungroup\"), b.R(\"ChangedSelection\", b.selection), b.currentCursor = \"\"\n        }\n    };\n    Rk.prototype.canUngroupSelection = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram;\n        if (b.isReadOnly || b.isModelReadOnly || !b.allowDelete || !b.allowUngroup || !b.model.jk()) return !1;\n        if (null !== a) {\n            if (!(a instanceof T)) return !1;\n            if (a.canUngroup()) return !0\n        } else\n            for (a = b.selection.iterator; a.next();)\n                if (b = a.value, b instanceof T && b.canUngroup()) return !0;\n        return !1\n    };\n    Rk.prototype.addTopLevelParts = function (a, b) {\n        var c = !0;\n        for (a = Uk(a).iterator; a.next();) {\n            var d = a.value;\n            null !== d.containingGroup && (!b || this.isValidMember(null, d) ? d.containingGroup = null : c = !1)\n        }\n        return c\n    };\n    Rk.prototype.collapseSubGraph = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram;\n        try {\n            b.ua(\"Collapse SubGraph\");\n            zh(b.animationManager, \"Collapse SubGraph\");\n            var c = new E;\n            if (null !== a && a.isSubGraphExpanded) a.collapseSubGraph(), c.add(a);\n            else if (null === a)\n                for (var d = b.selection.iterator; d.next();) {\n                    var e = d.value;\n                    e instanceof T && e.isSubGraphExpanded && (e.collapseSubGraph(), c.add(e))\n                }\n            b.R(\"SubGraphCollapsed\", c)\n        } finally {\n            b.Ua(\"Collapse SubGraph\")\n        }\n    };\n    Rk.prototype.canCollapseSubGraph = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram;\n        if (b.isReadOnly) return !1;\n        if (null !== a) return a instanceof T && a.isSubGraphExpanded ? !0 : !1;\n        for (a = b.selection.iterator; a.next();)\n            if (b = a.value, b instanceof T && b.isSubGraphExpanded) return !0;\n        return !1\n    };\n    Rk.prototype.expandSubGraph = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram;\n        try {\n            b.ua(\"Expand SubGraph\");\n            zh(b.animationManager, \"Expand SubGraph\");\n            var c = new E;\n            if (null !== a && !a.isSubGraphExpanded) a.expandSubGraph(), c.add(a);\n            else if (null === a)\n                for (var d = b.selection.iterator; d.next();) {\n                    var e = d.value;\n                    e instanceof T && !e.isSubGraphExpanded && (e.expandSubGraph(), c.add(e))\n                }\n            b.R(\"SubGraphExpanded\", c)\n        } finally {\n            b.Ua(\"Expand SubGraph\")\n        }\n    };\n    Rk.prototype.canExpandSubGraph = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram;\n        if (b.isReadOnly) return !1;\n        if (null !== a) return a instanceof T && !a.isSubGraphExpanded ? !0 : !1;\n        for (a = b.selection.iterator; a.next();)\n            if (b = a.value, b instanceof T && !b.isSubGraphExpanded) return !0;\n        return !1\n    };\n    Rk.prototype.editTextBlock = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram,\n            c = b.toolManager.findTool(\"TextEditing\");\n        if (null !== c) {\n            if (null === a) {\n                a = null;\n                for (var d = b.selection.iterator; d.next();) {\n                    var e = d.value;\n                    if (e.canEdit()) {\n                        a = e;\n                        break\n                    }\n                }\n                if (null === a) return;\n                a = a.hm(function (a) {\n                    return a instanceof Wg && a.editable\n                })\n            }\n            null !== a && (b.currentTool = null, c.textBlock = a, b.currentTool = c)\n        }\n    };\n    Rk.prototype.canEditTextBlock = function (a) {\n        void 0 === a && (a = null);\n        var b = this.diagram;\n        if (b.isReadOnly || b.isModelReadOnly || !b.allowTextEdit || null === b.toolManager.findTool(\"TextEditing\")) return !1;\n        if (null !== a) {\n            if (!(a instanceof Wg)) return !1;\n            a = a.part;\n            if (null !== a && a.canEdit()) return !0\n        } else\n            for (b = b.selection.iterator; b.next();)\n                if (a = b.value, a.canEdit() && (a = a.hm(function (a) {\n                        return a instanceof Wg && a.editable\n                    }), null !== a)) return !0;\n        return !1\n    };\n    Rk.prototype.showContextMenu = function (a) {\n        var b = this.diagram,\n            c = b.toolManager.findTool(\"ContextMenu\");\n        if (null !== c && (void 0 === a && (a = 0 < b.selection.count ? b.selection.first() : b), a = c.findObjectWithContextMenu(a), null !== a)) {\n            var d = b.lastInput,\n                e = null;\n            a instanceof Y ? e = a.ga(Ac) : b.viewportBounds.aa(d.documentPoint) || (e = b.viewportBounds, e = new I(e.x + e.width / 2, e.y + e.height / 2));\n            null !== e && (d.viewPoint = b.Nq(e), d.documentPoint = e, d.left = !1, d.right = !0, d.up = !0);\n            b.currentTool = c;\n            Sg(c, !1, a)\n        }\n    };\n    Rk.prototype.canShowContextMenu = function (a) {\n        var b = this.diagram,\n            c = b.toolManager.findTool(\"ContextMenu\");\n        if (null === c) return !1;\n        void 0 === a && (a = 0 < b.selection.count ? b.selection.first() : b);\n        return null === c.findObjectWithContextMenu(a) ? !1 : !0\n    };\n    Rk.prototype.computeEffectiveCollection = function (a, b) {\n        var c = this.diagram,\n            d = c.toolManager.findTool(\"Dragging\"),\n            e = c.currentTool === d;\n        void 0 === b && (b = e ? d.dragOptions : c.Qk);\n        d = new H;\n        if (null === a) return d;\n        for (var f = a.iterator; f.next();) Lj(c, d, f.value, e, b);\n        if (null !== c.draggedLink && b.dragsLink) return d;\n        for (f = a.iterator; f.next();) a = f.value, a instanceof S && (b = a.fromNode, null === b || d.contains(b) ? (b = a.toNode, null === b || d.contains(b) || d.remove(a)) : d.remove(a));\n        return d\n    };\n    ma.Object.defineProperties(Rk.prototype, {\n        diagram: {\n            get: function () {\n                return this.B\n            }\n        },\n        copiesClipboardData: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a\n            }\n        },\n        copiesConnectedLinks: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I = a\n            }\n        },\n        deletesConnectedLinks: {\n            get: function () {\n                return this.Za\n            },\n            set: function (a) {\n                this.Za = a\n            }\n        },\n        copiesTree: {\n            get: function () {\n                return this.Ia\n            },\n            set: function (a) {\n                this.Ia = a\n            }\n        },\n        deletesTree: {\n            get: function () {\n                return this.jd\n            },\n            set: function (a) {\n                this.jd = a\n            }\n        },\n        copiesParentKey: {\n            get: function () {\n                return this.Ha\n            },\n            set: function (a) {\n                this.Ha = a\n            }\n        },\n        copiesGroupKey: {\n            get: function () {\n                return this.Y\n            },\n            set: function (a) {\n                this.Y = a\n            }\n        },\n        archetypeGroupData: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l = a\n            }\n        },\n        memberValidation: {\n            get: function () {\n                return this.yi\n            },\n            set: function (a) {\n                this.yi = a\n            }\n        },\n        defaultScale: {\n            get: function () {\n                return this.diagram.defaultScale\n            },\n            set: function (a) {\n                this.diagram.defaultScale = a\n            }\n        },\n        zoomFactor: {\n            get: function () {\n                return this.Yc\n            },\n            set: function (a) {\n                1 < a || B(\"zoomFactor must be larger than 1.0, not: \" + a);\n                this.Yc = a\n            }\n        },\n        scrollToPartPause: {\n            get: function () {\n                return this.Ic\n            },\n            set: function (a) {\n                this.Ic = a\n            }\n        }\n    });\n    Rk.className = \"CommandHandler\";\n    zi = function () {\n        return new Rk\n    };\n\n    function Y() {\n        Ya(this);\n        this.F = 4225027;\n        this.qb = 1;\n        this.ng = null;\n        this.Ra = \"\";\n        this.dc = this.gb = null;\n        this.ma = (new I(NaN, NaN)).freeze();\n        this.Lc = Rb;\n        this.eg = Kb;\n        this.dg = Pb;\n        this.kb = new rd;\n        this.Qh = new rd;\n        this.bg = new rd;\n        this.ya = this.Wk = 1;\n        this.Yb = 0;\n        this.ve = Vk;\n        this.fh = sc;\n        this.nc = (new N(NaN, NaN, NaN, NaN)).freeze();\n        this.ub = (new N(NaN, NaN, NaN, NaN)).freeze();\n        this.oc = (new N(0, 0, NaN, NaN)).freeze();\n        this.O = this.cp = this.ep = null;\n        this.Fk = this.vb = Zc;\n        this.pp = 0;\n        this.qp = 1;\n        this.Og = 0;\n        this.gn = 1;\n        this.Kp = null;\n        this.xp = -Infinity;\n        this.Hl =\n            0;\n        this.Il = Fb;\n        this.Jl = bg;\n        this.fi = \"\";\n        this.$a = this.N = null;\n        this.Jk = -1;\n        this.Ll = this.ld = this.ei = this.Pl = null;\n        this.ws = zg;\n        this.sp = this.Kg = this.Jj = null\n    }\n    var vd, zg, Bg, Vk, Wk, Xk, Yk, Zk, $k, al;\n    Y.prototype.cloneProtected = function (a) {\n        a.F = this.F | 6144;\n        a.qb = this.qb;\n        a.Ra = this.Ra;\n        a.gb = this.gb;\n        a.dc = this.dc;\n        a.Kg = this.Kg;\n        a.ma.assign(this.ma);\n        a.Lc = this.Lc.G();\n        a.eg = this.eg.G();\n        a.dg = this.dg.G();\n        a.bg = this.bg.copy();\n        a.ya = this.ya;\n        a.Yb = this.Yb;\n        a.ve = this.ve;\n        a.fh = this.fh.G();\n        a.nc.assign(this.nc);\n        a.ub.assign(this.ub);\n        a.oc.assign(this.oc);\n        a.cp = this.cp;\n        null !== this.O && (a.O = this.O.copy());\n        a.vb = this.vb.G();\n        a.Fk = this.Fk.G();\n        a.pp = this.pp;\n        a.qp = this.qp;\n        a.Og = this.Og;\n        a.gn = this.gn;\n        a.Kp = this.Kp;\n        a.xp = this.xp;\n        a.Hl = this.Hl;\n        a.Il = this.Il.G();\n        a.Jl = this.Jl;\n        a.fi = this.fi;\n        null !== this.N && (a.N = this.N.copy());\n        a.$a = this.$a;\n        a.Jk = this.Jk;\n        null !== this.ei && (a.ei = Ba(this.ei));\n        null !== this.ld && (a.ld = this.ld.copy());\n        a.Ll = this.Ll\n    };\n    Y.prototype.sx = function (a) {\n        var b = this.ei;\n        if (Aa(b))\n            for (var c = 0; c < b.length; c++) {\n                if (b[c] === a) return\n            } else this.ei = b = [];\n        b.push(a)\n    };\n    Y.prototype.sf = function (a) {\n        a.ep = null;\n        a.Jj = null;\n        a.o()\n    };\n    Y.prototype.clone = function () {\n        var a = new this.constructor;\n        this.cloneProtected(a);\n        if (null !== this.ei)\n            for (var b = 0; b < this.ei.length; b++) {\n                var c = this.ei[b];\n                a[c] = this[c]\n            }\n        return a\n    };\n    Y.prototype.copy = function () {\n        return this.clone()\n    };\n    t = Y.prototype;\n    t.cb = function (a) {\n        a.classType === S ? 0 === a.name.indexOf(\"Orient\") ? this.segmentOrientation = a : B(\"Unknown Link enum value for GraphObject.segmentOrientation property: \" + a) : a.classType === Y && (this.stretch = a)\n    };\n    t.toString = function () {\n        return Ia(this.constructor) + \"#\" + lb(this)\n    };\n\n    function bl(a) {\n        null === a.N && (a.N = new cl)\n    }\n    t.Ec = function () {\n        if (null === this.O) {\n            var a = new dl;\n            a.Yg = uc;\n            a.yh = uc;\n            a.Wg = 10;\n            a.wh = 10;\n            a.Xg = 0;\n            a.xh = 0;\n            this.O = a\n        }\n    };\n    t.Ya = function (a, b, c, d, e, f, g) {\n        var h = this.part;\n        if (null !== h && (h.vk(a, b, c, d, e, f, g), c === this && a === re && el(this) && fl(this, h, b), f = this.diagram, null === this.Kg || null === f || !f.kk || f.undoManager.isUndoingRedoing || f.currentTool !== f.toolManager || f.animationManager.bn || (a = this.Kg.get(b), null === a || f.animationManager.isTicking || (null === this.sp && (this.sp = new H), g = 0 === f.undoManager.transactionLevel, a.startCondition === bi ? g = !0 : a.startCondition === di && (g = !1), g ? (f = new yh, ci(a, f), g = this.sp.get(a), null !== g && g.stop(), this.sp.add(a,\n                f), f.Xu = this, f.nx = a, f.add(this, b, d, e), f.start()) : (Ah(f.animationManager, \"Trigger\"), f.animationManager.defaultAnimation.add(this, b, d, e)))), this instanceof X && c === h && 0 !== (h.F & 16777216) && null !== h.data))\n            for (c = this.W.j, d = c.length, e = 0; e < d; e++) h = c[e], h instanceof X && Dj(h, function (a) {\n                null !== a.data && 0 !== (a.F & 16777216) && a.Ba(b)\n            })\n    };\n\n    function fl(a, b, c) {\n        var d = a.Ui();\n        if (null !== d)\n            for (var e = a.$a.iterator; e.next();) {\n                var f = e.value,\n                    g = null;\n                if (null !== f.sourceName) {\n                    g = gl(f, d, a);\n                    if (null === g) continue;\n                    f.Qq(a, g, c, null)\n                } else if (f.isToModel) {\n                    var h = b.diagram;\n                    null === h || h.skipsModelSourceBindings || f.Qq(a, h.model.modelData, c, d)\n                } else {\n                    h = d.data;\n                    if (null === h) continue;\n                    var k = b.diagram;\n                    null === k || k.skipsModelSourceBindings || f.Qq(a, h, c, d)\n                }\n                g === a && (h = d.it(f.gj), null !== h && f.tw(h, g, c))\n            }\n    }\n    t.it = function (a) {\n        return this.Jk === a ? this : null\n    };\n    t.g = function (a, b, c) {\n        this.Ya(re, a, this, b, c)\n    };\n\n    function hl(a, b, c, d, e) {\n        var f = a.nc,\n            g = a.bg;\n        g.reset();\n        il(a, g, b, c, d, e);\n        a.bg = g;\n        f.h(b, c, d, e);\n        g.ut() || g.qw(f)\n    }\n\n    function jl(a, b, c, d) {\n        if (!1 === a.pickable) return !1;\n        d.multiply(a.transform);\n        return c ? a.Gc(b, d) : a.Gh(b, d)\n    }\n    t.Lx = function (a, b, c) {\n        if (!1 === this.pickable) return !1;\n        var d = this.naturalBounds;\n        b = a.Ae(b);\n        return c ? Ab(a.x, a.y, 0, 0, 0, d.height) <= b || Ab(a.x, a.y, 0, d.height, d.width, d.height) <= b || Ab(a.x, a.y, d.width, d.height, d.width, 0) <= b || Ab(a.x, a.y, d.width, 0, 0, 0) <= b : a.dd(0, 0) <= b && a.dd(0, d.height) <= b && a.dd(d.width, 0) <= b && a.dd(d.width, d.height) <= b\n    };\n    t.$d = function () {\n        return !0\n    };\n    t.aa = function (a) {\n        var b = I.alloc();\n        b.assign(a);\n        this.transform.ra(b);\n        var c = this.actualBounds;\n        if (!c.v()) return I.free(b), !1;\n        var d = this.diagram;\n        if (null !== d && d.je) {\n            var e = d.mm(\"extraTouchThreshold\"),\n                f = d.mm(\"extraTouchArea\"),\n                g = f / 2,\n                h = this.naturalBounds;\n            d = this.uf() * d.scale;\n            var k = 1 / d;\n            if (h.width * d < e && h.height * d < e) return a = fc(c.x - g * k, c.y - g * k, c.width + f * k, c.height + f * k, b.x, b.y), I.free(b), a\n        }\n        e = !1;\n        if (this instanceof Je || this instanceof Lf ? fc(c.x - 5, c.y - 5, c.width + 10, c.height + 10, b.x, b.y) : c.aa(b)) this.ld && !this.ld.aa(b) ?\n            e = !1 : null !== this.dc && c.aa(b) ? e = !0 : null !== this.gb && this.oc.aa(a) ? e = !0 : e = this.Hh(a);\n        I.free(b);\n        return e\n    };\n    t.Hh = function (a) {\n        var b = this.naturalBounds;\n        return fc(0, 0, b.width, b.height, a.x, a.y)\n    };\n    t.ze = function (a) {\n        if (0 === this.angle) return this.actualBounds.ze(a);\n        var b = this.naturalBounds;\n        b = N.allocAt(0, 0, b.width, b.height);\n        var c = this.transform,\n            d = !1,\n            e = I.allocAt(a.x, a.y);\n        b.aa(c.Vd(e)) && (e.h(a.x, a.bottom), b.aa(c.Vd(e)) && (e.h(a.right, a.bottom), b.aa(c.Vd(e)) && (e.h(a.right, a.y), b.aa(c.Vd(e)) && (d = !0))));\n        I.free(e);\n        N.free(b);\n        return d\n    };\n    t.Gh = function (a, b) {\n        if (void 0 === b) return a.ze(this.actualBounds);\n        var c = this.naturalBounds,\n            d = !1,\n            e = I.allocAt(0, 0);\n        a.aa(b.ra(e)) && (e.h(0, c.height), a.aa(b.ra(e)) && (e.h(c.width, c.height), a.aa(b.ra(e)) && (e.h(c.width, 0), a.aa(b.ra(e)) && (d = !0))));\n        I.free(e);\n        return d\n    };\n    t.Gc = function (a, b) {\n        if (void 0 === b && (b = this.transform, 0 === this.angle)) return a.Gc(this.actualBounds);\n        var c = this.naturalBounds,\n            d = I.allocAt(0, 0),\n            e = I.allocAt(0, c.height),\n            f = I.allocAt(c.width, c.height),\n            g = I.allocAt(c.width, 0),\n            h = !1;\n        if (a.aa(b.ra(d)) || a.aa(b.ra(e)) || a.aa(b.ra(f)) || a.aa(b.ra(g))) h = !0;\n        else {\n            c = N.allocAt(0, 0, c.width, c.height);\n            var k = I.allocAt(a.x, a.y);\n            c.aa(b.Vd(k)) ? h = !0 : (k.h(a.x, a.bottom), c.aa(b.Vd(k)) ? h = !0 : (k.h(a.right, a.bottom), c.aa(b.Vd(k)) ? h = !0 : (k.h(a.right, a.y), c.aa(b.Vd(k)) && (h = !0))));\n            I.free(k);\n            N.free(c);\n            !h && (J.rt(a, d, e) || J.rt(a, e, f) || J.rt(a, f, g) || J.rt(a, g, d)) && (h = !0)\n        }\n        I.free(d);\n        I.free(e);\n        I.free(f);\n        I.free(g);\n        return h\n    };\n    t.ga = function (a, b) {\n        void 0 === b && (b = new I);\n        if (a instanceof P) {\n            var c = this.naturalBounds;\n            b.h(a.x * c.width + a.offsetX, a.y * c.height + a.offsetY)\n        } else b.set(a);\n        this.ud.ra(b);\n        return b\n    };\n    t.lm = function (a) {\n        void 0 === a && (a = new N);\n        var b = this.naturalBounds,\n            c = this.ud,\n            d = I.allocAt(0, 0).transform(c);\n        a.h(d.x, d.y, 0, 0);\n        d.h(b.width, 0).transform(c);\n        ec(a, d.x, d.y, 0, 0);\n        d.h(b.width, b.height).transform(c);\n        ec(a, d.x, d.y, 0, 0);\n        d.h(0, b.height).transform(c);\n        ec(a, d.x, d.y, 0, 0);\n        I.free(d);\n        return a\n    };\n    t.Xi = function () {\n        var a = this.ud;\n        1 === a.m11 && 0 === a.m12 ? a = 0 : (a = 180 * Math.atan2(a.m12, a.m11) / Math.PI, 0 > a && (a += 360));\n        return a\n    };\n    t.uf = function () {\n        if (0 !== (this.F & 4096) === !1) return this.Wk;\n        var a = this.ya;\n        return null !== this.panel ? a * this.panel.uf() : a\n    };\n    t.ot = function (a, b) {\n        void 0 === b && (b = new I);\n        b.assign(a);\n        this.ud.Vd(b);\n        return b\n    };\n    t.Uc = function (a, b, c) {\n        return this.hk(a.x, a.y, b.x, b.y, c)\n    };\n    t.hk = function (a, b, c, d, e) {\n        var f = this.transform,\n            g = 1 / (f.m11 * f.m22 - f.m12 * f.m21),\n            h = f.m22 * g,\n            k = -f.m12 * g,\n            l = -f.m21 * g,\n            m = f.m11 * g,\n            n = g * (f.m21 * f.dy - f.m22 * f.dx),\n            p = g * (f.m12 * f.dx - f.m11 * f.dy);\n        if (null !== this.areaBackground) return f = this.actualBounds, J.Uc(f.left, f.top, f.right, f.bottom, a, b, c, d, e);\n        g = a * h + b * l + n;\n        a = a * k + b * m + p;\n        b = c * h + d * l + n;\n        c = c * k + d * m + p;\n        e.h(0, 0);\n        d = this.naturalBounds;\n        c = J.Uc(0, 0, d.width, d.height, g, a, b, c, e);\n        e.transform(f);\n        return c\n    };\n    Y.prototype.measure = function (a, b, c, d) {\n        if (!1 !== qj(this)) {\n            var e = this.fh,\n                f = e.right + e.left;\n            e = e.top + e.bottom;\n            a = Math.max(a - f, 0);\n            b = Math.max(b - e, 0);\n            c = Math.max((c || 0) - f, 0);\n            d = Math.max((d || 0) - e, 0);\n            f = this.angle;\n            e = this.desiredSize;\n            var g = 0;\n            this instanceof Lf && (g = this.strokeWidth);\n            90 === f || 270 === f ? (a = isFinite(e.height) ? e.height + g : a, b = isFinite(e.width) ? e.width + g : b) : (a = isFinite(e.width) ? e.width + g : a, b = isFinite(e.height) ? e.height + g : b);\n            e = c || 0;\n            g = d || 0;\n            var h = this instanceof X;\n            switch (kl(this, !0)) {\n                case zg:\n                    g = e = 0;\n                    h && (b = a = Infinity);\n                    break;\n                case vd:\n                    isFinite(a) && a > c && (e = a);\n                    isFinite(b) && b > d && (g = b);\n                    break;\n                case Wk:\n                    isFinite(a) && a > c && (e = a);\n                    g = 0;\n                    h && (b = Infinity);\n                    break;\n                case Xk:\n                    isFinite(b) && b > d && (g = b), e = 0, h && (a = Infinity)\n            }\n            h = this.maxSize;\n            var k = this.minSize;\n            e > h.width && k.width < h.width && (e = h.width);\n            g > h.height && k.height < h.height && (g = h.height);\n            c = Math.max(e / this.scale, k.width);\n            d = Math.max(g / this.scale, k.height);\n            h.width < c && (c = Math.min(k.width, c));\n            h.height < d && (d = Math.min(k.height, d));\n            a = Math.min(h.width, a);\n            b = Math.min(h.height, b);\n            a = Math.max(c, a);\n            b = Math.max(d,\n                b);\n            if (90 === f || 270 === f) f = a, a = b, b = f, f = c, c = d, d = f;\n            this.nc.ea();\n            this.sm(a, b, c, d);\n            this.nc.freeze();\n            this.nc.v() || B(\"Non-real measuredBounds has been set. Object \" + this + \", measuredBounds: \" + this.nc.toString());\n            lj(this, !1)\n        }\n    };\n    Y.prototype.sm = function () {};\n    Y.prototype.xf = function () {\n        return !1\n    };\n    Y.prototype.arrange = function (a, b, c, d, e) {\n        this.ml();\n        var f = N.alloc();\n        f.assign(this.ub);\n        this.ub.ea();\n        !1 === rj(this) ? this.ub.h(a, b, c, d) : this.Fh(a, b, c, d);\n        this.ub.freeze();\n        void 0 === e ? this.ld = null : this.ld = e;\n        c = !1;\n        if (void 0 !== e) c = !0;\n        else if (e = this.panel, null === e || e.type !== X.TableRow && e.type !== X.TableColumn || (e = e.panel), null !== e && (e = e.oc, d = this.measuredBounds, null !== this.areaBackground && (d = this.ub), c = b + d.height, d = a + d.width, c = !(0 <= a + .05 && d <= e.width + .05 && 0 <= b + .05 && c <= e.height + .05), this instanceof Wg && (a = this.naturalBounds,\n                this.$r > a.height || this.pb > a.width))) c = !0;\n        this.F = c ? this.F | 256 : this.F & -257;\n        this.ub.v() || B(\"Non-real actualBounds has been set. Object \" + this + \", actualBounds: \" + this.ub.toString());\n        this.Et(f, this.ub);\n        ll(this, !1);\n        N.free(f)\n    };\n    t = Y.prototype;\n    t.Fh = function () {};\n\n    function ml(a, b, c, d, e) {\n        a.ub.h(b, c, d, e);\n        if (!a.desiredSize.v()) {\n            var f = a.nc;\n            c = a.fh;\n            b = c.right + c.left;\n            var g = c.top + c.bottom;\n            c = f.width + b;\n            f = f.height + g;\n            d += b;\n            e += g;\n            b = kl(a, !0);\n            c === d && f === e && (b = zg);\n            switch (b) {\n                case zg:\n                    if (c > d || f > e) lj(a, !0), a.measure(c > d ? d : c, f > e ? e : f, 0, 0);\n                    break;\n                case vd:\n                    lj(a, !0);\n                    a.measure(d, e, 0, 0);\n                    break;\n                case Wk:\n                    lj(a, !0);\n                    a.measure(d, f, 0, 0);\n                    break;\n                case Xk:\n                    lj(a, !0), a.measure(c, e, 0, 0)\n            }\n        }\n    }\n    t.Et = function (a, b) {\n        var c = this.part;\n        null !== c && null !== c.diagram && (c.selectionObject !== this && c.resizeObject !== this && c.rotateObject !== this || nl(c, !0), this.M(), $b(a, b) || (c.Jh(), this.To(c)))\n    };\n    t.To = function (a) {\n        null !== this.portId && (nl(a, !0), a instanceof W && ol(a, this))\n    };\n    t.bc = function (a, b) {\n        if (this.visible) {\n            var c = this instanceof X && (this.type === X.TableRow || this.type === X.TableColumn),\n                d = this.ub;\n            if (c || 0 !== d.width && 0 !== d.height && !isNaN(d.x) && !isNaN(d.y)) {\n                var e = this.opacity;\n                if (0 !== e) {\n                    var f = 1;\n                    1 !== e && (f = a.globalAlpha, a.globalAlpha = f * e);\n                    if (!this.Gx(a, b))\n                        if (c) pl(this, a, b);\n                        else {\n                            this instanceof S && this.nk(!1);\n                            c = this.transform;\n                            var g = this.panel;\n                            0 !== (this.F & 4096) === !0 && ql(this);\n                            var h = this.part,\n                                k = !1,\n                                l = 0;\n                            if (h && b.Be(\"drawShadows\") && (k = h.isShadowed)) {\n                                var m = h.shadowOffset;\n                                l = Math.max(m.y,\n                                    m.x) * b.scale * b.Sb\n                            }\n                            if (!(m = b.ni || !this.xf())) {\n                                var n = this.naturalBounds;\n                                m = this.Qh;\n                                var p = m.m11,\n                                    r = m.m21,\n                                    q = m.dx,\n                                    u = m.m12,\n                                    v = m.m22,\n                                    w = m.dy,\n                                    y, z = y = 0;\n                                m = y * p + z * r + q;\n                                var A = y * u + z * v + w;\n                                y = n.width + l;\n                                z = 0;\n                                var C = y * p + z * r + q;\n                                y = y * u + z * v + w;\n                                z = Math.min(m, C);\n                                var G = Math.min(A, y);\n                                var L = Math.max(m + 0, C) - z;\n                                var K = Math.max(A + 0, y) - G;\n                                m = z;\n                                A = G;\n                                y = n.width + l;\n                                z = n.height + l;\n                                C = y * p + z * r + q;\n                                y = y * u + z * v + w;\n                                z = Math.min(m, C);\n                                G = Math.min(A, y);\n                                L = Math.max(m + L, C) - z;\n                                K = Math.max(A + K, y) - G;\n                                m = z;\n                                A = G;\n                                y = 0;\n                                z = n.height + l;\n                                C = y * p + z * r + q;\n                                y = y * u + z * v + w;\n                                z = Math.min(m, C);\n                                G = Math.min(A, y);\n                                L = Math.max(m + L, C) - z;\n                                K = Math.max(A + K, y) - G;\n                                m = z;\n                                A = G;\n                                l = b.viewportBounds;\n                                n = l.x;\n                                p = l.y;\n                                m = !(m > l.width + n || n > L + m || A > l.height + p || p > K + A)\n                            }\n                            if (m) {\n                                m = 0 !== (this.F & 256);\n                                a.clipInsteadOfFill && (m = !1);\n                                this instanceof Wg && (a.font = this.font);\n                                if (m) {\n                                    A = g.$d() ? g.naturalBounds : g.actualBounds;\n                                    null !== this.ld ? (n = this.ld, L = n.x, K = n.y, l = n.width, n = n.height) : (L = Math.max(d.x, A.x), K = Math.max(d.y, A.y), l = Math.min(d.right, A.right) - L, n = Math.min(d.bottom, A.bottom) - K);\n                                    if (L > d.width + d.x || d.x > A.width + A.x) {\n                                        1 !== e && (a.globalAlpha = f);\n                                        return\n                                    }\n                                    a.save();\n                                    a.beginPath();\n                                    a.rect(L, K, l, n);\n                                    a.clip()\n                                }\n                                if (this.xf()) {\n                                    if (!h.isVisible()) {\n                                        1 !== e && (a.globalAlpha = f);\n                                        return\n                                    }\n                                    k && (A = h.shadowOffset, a.jw(A.x * b.scale * b.Sb, A.y * b.scale * b.Sb, h.shadowBlur), rl(a), a.shadowColor = h.shadowColor)\n                                }!0 === this.shadowVisible ? rl(a) : !1 === this.shadowVisible && sl(a);\n                                h = this.naturalBounds;\n                                null !== this.dc && (ii(this, a, this.dc, !0, !0, h, d), this.dc instanceof tl && this.dc.type === ul ? (a.beginPath(), a.rect(d.x, d.y, d.width, d.height), a.Ud(this.dc)) : a.fillRect(d.x, d.y, d.width, d.height));\n                                a.transform(c.m11,\n                                    c.m12, c.m21, c.m22, c.dx, c.dy);\n                                k && (null !== g && 0 !== (g.F & 512) || null !== g && (g.type === X.Auto || g.type === X.Spot) && g.zb() !== this) && null === this.shadowVisible && sl(a);\n                                null !== this.gb && (l = this.naturalBounds, L = A = 0, K = l.width, l = l.height, n = 0, this instanceof Lf && (l = this.ka.bounds, A = l.x, L = l.y, K = l.width, l = l.height, n = this.strokeWidth), ii(this, a, this.gb, !0, !1, h, d), this.gb instanceof tl && this.gb.type === ul ? (a.beginPath(), a.rect(A - n / 2, L - n / 2, K + n, l + n), a.Ud(this.gb)) : a.fillRect(A - n / 2, L - n / 2, K + n, l + n));\n                                k && (null !== this.gb || null !==\n                                    this.dc || null !== g && 0 !== (g.F & 512) || null !== g && (g.type === X.Auto || g.type === X.Spot) && g.zb() !== this) ? (vl(this, !0), null === this.shadowVisible && sl(a)) : vl(this, !1);\n                                this.Qi(a, b);\n                                k && 0 !== (this.F & 512) === !0 && rl(a);\n                                this.xf() && k && sl(a);\n                                m ? (a.restore(), this instanceof X ? a.sc(!0) : a.sc(!1)) : c.ut() || (b = 1 / (c.m11 * c.m22 - c.m12 * c.m21), a.transform(c.m22 * b, -c.m12 * b, -c.m21 * b, c.m11 * b, b * (c.m21 * c.dy - c.m22 * c.dx), b * (c.m12 * c.dx - c.m11 * c.dy)))\n                            }\n                        } 1 !== e && (a.globalAlpha = f)\n                }\n            }\n        }\n    };\n    t.Gx = function () {\n        return !1\n    };\n\n    function pl(a, b, c) {\n        var d = a.ub,\n            e = a.oc;\n        null !== a.dc && (ii(a, b, a.dc, !0, !0, e, d), a.dc instanceof tl && a.dc.type === ul ? (b.beginPath(), b.rect(d.x, d.y, d.width, d.height), b.Ud(a.dc)) : b.fillRect(d.x, d.y, d.width, d.height));\n        null !== a.gb && (ii(a, b, a.gb, !0, !1, e, d), a.gb instanceof tl && a.gb.type === ul ? (b.beginPath(), b.rect(d.x, d.y, d.width, d.height), b.Ud(a.gb)) : b.fillRect(d.x, d.y, d.width, d.height));\n        a.Qi(b, c)\n    }\n    t.Qi = function () {};\n\n    function ii(a, b, c, d, e, f, g) {\n        if (null !== c) {\n            var h = 1,\n                k = 1;\n            if (\"string\" === typeof c) d ? b.fillStyle = c : b.strokeStyle = c;\n            else if (c.type === wl) d ? b.fillStyle = c.color : b.strokeStyle = c.color;\n            else {\n                h = f.width;\n                k = f.height;\n                e && (h = g.width, k = g.height);\n                if ((f = b instanceof xl) && c.ce && (c.type === yl || c.Mk === h && c.au === k)) var l = c.ce;\n                else {\n                    var m = 0,\n                        n = 0,\n                        p = 0,\n                        r = 0,\n                        q = 0,\n                        u = 0;\n                    u = q = 0;\n                    e && (q = g.x, u = g.y);\n                    m = c.start.x * h + c.start.offsetX;\n                    n = c.start.y * k + c.start.offsetY;\n                    p = c.end.x * h + c.end.offsetX;\n                    r = c.end.y * k + c.end.offsetY;\n                    m += q;\n                    p += q;\n                    n += u;\n                    r += u;\n                    if (c.type === zl) l =\n                        b.createLinearGradient(m, n, p, r);\n                    else if (c.type === ul) u = isNaN(c.endRadius) ? Math.max(h, k) / 2 : c.endRadius, isNaN(c.startRadius) ? (q = 0, u = Math.max(h, k) / 2) : q = c.startRadius, l = b.createRadialGradient(m, n, q, p, r, u);\n                    else if (c.type === yl) try {\n                        l = b.createPattern(c.pattern, \"repeat\")\n                    } catch (w) {\n                        l = null\n                    }\n                    if (c.type !== yl && (e = c.colorStops, null !== e))\n                        for (e = e.iterator; e.next();) l.addColorStop(e.key, e.value);\n                    if (f && (c.ce = l, null !== l && (c.Mk = h, c.au = k), null === l && c.type === yl && -1 !== c.Mk)) {\n                        c.Mk = -1;\n                        var v = a.diagram;\n                        null !== v && -1 === c.Mk && sa(function () {\n                                v.Ee()\n                            },\n                            600)\n                    }\n                }\n                d ? b.fillStyle = l : b.strokeStyle = l\n            }\n        }\n    }\n    t.Dg = function (a) {\n        if (a instanceof X) a: {\n            if (this !== a && null !== a)\n                for (var b = this.panel; null !== b;) {\n                    if (b === a) {\n                        a = !0;\n                        break a\n                    }\n                    b = b.panel\n                }\n            a = !1\n        }\n        else a = !1;\n        return a\n    };\n    t.zf = function () {\n        if (!this.visible) return !1;\n        var a = this.panel;\n        return null !== a ? a.zf() : !0\n    };\n    t.Eg = function () {\n        for (var a = this instanceof X ? this : this.panel; null !== a && a.isEnabled;) a = a.panel;\n        return null === a\n    };\n\n    function ql(a) {\n        if (0 !== (a.F & 2048) === !0) {\n            var b = a.kb;\n            b.reset();\n            if (!a.ub.v() || !a.nc.v()) {\n                Al(a, !1);\n                return\n            }\n            b.translate(a.ub.x - a.nc.x, a.ub.y - a.nc.y);\n            if (1 !== a.scale || 0 !== a.angle) {\n                var c = a.naturalBounds;\n                il(a, b, c.x, c.y, c.width, c.height)\n            }\n            Al(a, !1);\n            Bl(a, !0)\n        }\n        0 !== (a.F & 4096) === !0 && (b = a.panel, null === b ? (a.Qh.set(a.kb), a.Wk = a.scale, Bl(a, !1)) : null !== b.ud && (c = a.Qh, c.reset(), b.$d() ? c.multiply(b.Qh) : null !== b.panel && c.multiply(b.panel.Qh), c.multiply(a.kb), a.Wk = a.scale * b.Wk, Bl(a, !1)))\n    }\n\n    function il(a, b, c, d, e, f) {\n        1 !== a.scale && b.scale(a.scale);\n        if (0 !== a.Yb) {\n            var g = Ac;\n            a.xf() && a.locationSpot.eb() && (g = a.locationSpot);\n            var h = I.alloc();\n            if (a instanceof U && a.locationObject !== a)\n                for (c = a.locationObject, d = c.naturalBounds, h.xk(d.x, d.y, d.width, d.height, g), c.bg.ra(h), h.offset(-c.measuredBounds.x, -c.measuredBounds.y), g = c.panel; null !== g && g !== a;) g.bg.ra(h), h.offset(-g.measuredBounds.x, -g.measuredBounds.y), g = g.panel;\n            else h.xk(c, d, e, f, g);\n            b.rotate(a.Yb, h.x, h.y);\n            I.free(h)\n        }\n    }\n    t.o = function (a) {\n        void 0 === a && (a = !1);\n        if (!0 !== qj(this)) {\n            lj(this, !0);\n            ll(this, !0);\n            var b = this.panel;\n            null === b || a || b.o()\n        }\n    };\n    t.om = function () {\n        !0 !== qj(this) && (lj(this, !0), ll(this, !0))\n    };\n\n    function Cl(a) {\n        if (!1 === rj(a)) {\n            var b = a.panel;\n            null !== b ? b.o() : a.xf() && (b = a.diagram, null !== b && (b.nd.add(a), a instanceof W && a.fd(), b.Pb()));\n            ll(a, !0)\n        }\n    }\n    t.ml = function () {\n        0 !== (this.F & 2048) === !1 && (Al(this, !0), Bl(this, !0))\n    };\n    t.Fv = function () {\n        Bl(this, !0)\n    };\n    t.M = function () {\n        var a = this.part;\n        null !== a && a.M()\n    };\n\n    function kl(a, b) {\n        var c = a.stretch,\n            d = a.panel;\n        if (null !== d && d.type === X.Table) return Dl(a, d.getRowDefinition(a.row), d.getColumnDefinition(a.column), b);\n        if (null !== d && d.type === X.Auto && d.zb() === a) return El(a, vd, b);\n        if (c === Vk) {\n            if (null !== d) {\n                if (d.type === X.Spot && d.zb() === a) return El(a, vd, b);\n                c = d.defaultStretch;\n                return c === Vk ? El(a, zg, b) : El(a, c, b)\n            }\n            return El(a, zg, b)\n        }\n        return El(a, c, b)\n    }\n\n    function Dl(a, b, c, d) {\n        var e = a.stretch;\n        if (e !== Vk) return El(a, e, d);\n        var f = e = null;\n        switch (b.stretch) {\n            case Xk:\n                f = !0;\n                break;\n            case vd:\n                f = !0\n        }\n        switch (c.stretch) {\n            case Wk:\n                e = !0;\n                break;\n            case vd:\n                e = !0\n        }\n        b = a.panel.defaultStretch;\n        null === e && (e = b === Wk || b === vd);\n        null === f && (f = b === Xk || b === vd);\n        return !0 === e && !0 === f ? El(a, vd, d) : !0 === e ? El(a, Wk, d) : !0 === f ? El(a, Xk, d) : El(a, zg, d)\n    }\n\n    function El(a, b, c) {\n        if (c) return b;\n        if (b === zg) return zg;\n        c = a.desiredSize;\n        if (c.v()) return zg;\n        a = a.angle;\n        if (!isNaN(c.width))\n            if (90 !== a && 270 !== a) {\n                if (b === Wk) return zg;\n                if (b === vd) return Xk\n            } else {\n                if (b === Xk) return zg;\n                if (b === vd) return Wk\n            } if (!isNaN(c.height))\n            if (90 !== a && 270 !== a) {\n                if (b === Xk) return zg;\n                if (b === vd) return Wk\n            } else {\n                if (b === Wk) return zg;\n                if (b === vd) return Xk\n            } return b\n    }\n\n    function vl(a, b) {\n        a.F = b ? a.F | 512 : a.F & -513\n    }\n\n    function el(a) {\n        return 0 !== (a.F & 1024)\n    }\n\n    function Fl(a, b) {\n        a.F = b ? a.F | 1024 : a.F & -1025\n    }\n\n    function Al(a, b) {\n        a.F = b ? a.F | 2048 : a.F & -2049\n    }\n\n    function Bl(a, b) {\n        a.F = b ? a.F | 4096 : a.F & -4097\n    }\n\n    function qj(a) {\n        return 0 !== (a.F & 8192)\n    }\n\n    function lj(a, b) {\n        a.F = b ? a.F | 8192 : a.F & -8193\n    }\n\n    function rj(a) {\n        return 0 !== (a.F & 16384)\n    }\n\n    function ll(a, b) {\n        a.F = b ? a.F | 16384 : a.F & -16385\n    }\n    t.cj = function (a) {\n        this.ng = a\n    };\n    t.hw = function () {};\n    t.gw = function (a) {\n        this.ma.assign(a);\n        Cl(this);\n        return !0\n    };\n    t.Kq = function (a, b) {\n        if (this.ma.x !== a || this.ma.y !== b) this.ma.h(a, b), this.ml()\n    };\n\n    function Gl(a) {\n        var b = a.part;\n        if (b instanceof W && (null !== a.portId || a === b.port)) {\n            var c = b.diagram;\n            null === c || c.undoManager.isUndoingRedoing || ol(b, a)\n        }\n    }\n\n    function Hl(a) {\n        var b = a.diagram;\n        null === b || b.undoManager.isUndoingRedoing || (a instanceof X ? a instanceof W ? a.fd() : a.Km(a, function (a) {\n            Gl(a)\n        }) : Gl(a))\n    }\n    t.bind = function (a) {\n        a.bd = this;\n        var b = this.Ui();\n        null !== b && Il(b) && B(\"Cannot add a Binding to a template that has already been copied: \" + a);\n        null === this.$a && (this.$a = new E);\n        this.$a.add(a)\n    };\n    t.Ui = function () {\n        for (var a = this instanceof X ? this : this.panel; null !== a;) {\n            if (null !== a.ci) return a;\n            a = a.panel\n        }\n        return null\n    };\n    t.iw = function (a) {\n        xj(this, a)\n    };\n\n    function Jl(a, b) {\n        b.bd = a;\n        null === a.Kg && (a.Kg = new H);\n        a.Kg.add(b.propertyName, b)\n    }\n\n    function Kl(a, b) {\n        for (var c = 1; c < arguments.length; ++c);\n        c = arguments;\n        var d = null,\n            e = null;\n        if (\"function\" === typeof a) e = a;\n        else if (\"string\" === typeof a) {\n            var f = Ll.H(a);\n            \"function\" === typeof f ? (c = Ba(arguments), d = f(c), za(d) || B('GraphObject.make invoked object builder \"' + a + '\", but it did not return an Object')) : e = x.go[a]\n        }\n        null === d && (void 0 !== e && null !== e && e.constructor || B(\"GraphObject.make requires a class function or GoJS class name or name of an object builder, not: \" + a), d = new e);\n        e = 1;\n        if (d instanceof R && 1 < c.length) {\n            f =\n                d;\n            var g = c[1];\n            if (\"string\" === typeof g || g instanceof HTMLDivElement) Ei(f, g), e++\n        }\n        for (; e < c.length; e++) f = c[e], void 0 === f ? B(\"Undefined value at argument \" + e + \" for object being constructed by GraphObject.make: \" + d) : Ml(d, f);\n        return d\n    }\n\n    function Ml(a, b) {\n        if (\"string\" === typeof b)\n            if (a instanceof Wg) a.text = b;\n            else if (a instanceof Lf) a.figure = b;\n        else if (a instanceof kk) a.source = b;\n        else if (a instanceof X) b = Nl.H(b), null !== b && (a.type = b);\n        else if (a instanceof tl) {\n            var c = Za(tl, b);\n            null !== c ? a.type = c : B(\"Unknown Brush type as an argument to GraphObject.make: \" + b)\n        } else a instanceof td ? (b = Za(td, b), null !== b && (a.type = b)) : a instanceof le && (b = Za(le, b), null !== b && (a.type = b));\n        else if (b instanceof Y) a instanceof X || B(\"A GraphObject can only be added to a Panel, not to: \" +\n            a), a.add(b);\n        else if (b instanceof Rj) {\n            var d;\n            b.isRow && \"function\" === typeof a.getRowDefinition ? d = a.getRowDefinition(b.index) : b.isRow || \"function\" !== typeof a.getColumnDefinition || (d = a.getColumnDefinition(b.index));\n            d instanceof Rj ? d.et(b) : B(\"A RowColumnDefinition can only be added to an object that implements getRowDefinition/getColumnDefinition, not to: \" + a)\n        } else if (b instanceof D) \"function\" === typeof a.cb && a.cb(b);\n        else if (b instanceof Ol) a.type = b;\n        else if (b instanceof Ji) a instanceof Y ? a.bind(b) : a instanceof\n        Rj ? a.bind(b) : B(\"A Binding can only be applied to a GraphObject or RowColumnDefinition, not to: \" + a);\n        else if (b instanceof $h) a instanceof Y ? Jl(a, b) : B(\"An AnimationTrigger can only be applied to a GraphObject, not to: \" + a);\n        else if (b instanceof ke) a instanceof td ? a.figures.add(b) : B(\"A PathFigure can only be added to a Geometry, not to: \" + a);\n        else if (b instanceof le) a instanceof ke ? a.segments.add(b) : B(\"A PathSegment can only be added to a PathFigure, not to: \" + a);\n        else if (b instanceof Ci) a instanceof R ?\n            a.layout = b : a instanceof T ? a.layout = b : B(\"A Layout can only be assigned to a Diagram or a Group, not to: \" + a);\n        else if (Array.isArray(b))\n            for (c = 0; c < b.length; c++) Ml(a, b[c]);\n        else if (\"object\" === typeof b && null !== b)\n            if (a instanceof tl) {\n                c = new db;\n                for (var e in b) d = parseFloat(e), isNaN(d) ? c[e] = b[e] : a.addColorStop(d, b[e]);\n                xj(a, c)\n            } else if (a instanceof Rj) {\n            void 0 !== b.row ? (e = b.row, (void 0 === e || null === e || Infinity === e || isNaN(e) || 0 > e) && B(\"Must specify non-negative integer row for RowColumnDefinition \" + b + \", not: \" + e), a.isRow = !0, a.index = e) : void 0 !== b.column && (e = b.column, (void 0 === e || null === e || Infinity === e || isNaN(e) || 0 > e) && B(\"Must specify non-negative integer column for RowColumnDefinition \" + b + \", not: \" + e), a.isRow = !1, a.index = e);\n            e = new db;\n            for (c in b) \"row\" !== c && \"column\" !== c && (e[c] = b[c]);\n            xj(a, e)\n        } else xj(a, b);\n        else B('Unknown initializer \"' + b + '\" for object being constructed by GraphObject.make: ' + a)\n    }\n\n    function Pl(a, b) {\n        Ll.add(a, b)\n    }\n\n    function Ql(a, b, c) {\n        void 0 === c && (c = null);\n        var d = a[1];\n        if (\"function\" === typeof c ? c(d) : \"string\" === typeof d) return a.splice(1, 1), d;\n        if (void 0 === b) throw Error(\"no \" + (\"function\" === typeof c ? \"satisfactory\" : \"string\") + \" argument for GraphObject builder \" + a[0]);\n        return b\n    }\n    ma.Object.defineProperties(Y.prototype, {\n        shadowVisible: {\n            get: function () {\n                return this.Ll\n            },\n            set: function (a) {\n                var b = this.Ll;\n                b !== a && (this.Ll = a, this.M(), this.g(\"shadowVisible\", b, a))\n            }\n        },\n        enabledChanged: {\n            get: function () {\n                return null !== this.N ? this.N.En : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.En;\n                b !== a && (this.N.En = a, this.g(\"enabledChanged\", b, a))\n            }\n        },\n        segmentOrientation: {\n            get: function () {\n                return this.Jl\n            },\n            set: function (a) {\n                var b = this.Jl;\n                b !== a && (this.Jl = a, this.o(), this.g(\"segmentOrientation\", b, a), a === bg && (this.angle = 0))\n            }\n        },\n        segmentIndex: {\n            get: function () {\n                return this.xp\n            },\n            set: function (a) {\n                a = Math.round(a);\n                var b = this.xp;\n                b !== a && (this.xp = a, this.o(), this.g(\"segmentIndex\", b, a))\n            }\n        },\n        segmentFraction: {\n            get: function () {\n                return this.Hl\n            },\n            set: function (a) {\n                isNaN(a) ? a = 0 : 0 > a ? a = 0 : 1 < a && (a = 1);\n                var b = this.Hl;\n                b !== a && (this.Hl = a, this.o(), this.g(\"segmentFraction\", b, a))\n            }\n        },\n        segmentOffset: {\n            get: function () {\n                return this.Il\n            },\n            set: function (a) {\n                var b = this.Il;\n                b.w(a) || (this.Il = a = a.G(), this.o(), this.g(\"segmentOffset\", b, a))\n            }\n        },\n        stretch: {\n            get: function () {\n                return this.ve\n            },\n            set: function (a) {\n                var b = this.ve;\n                b !== a && (this.ve = a, this.o(), this.g(\"stretch\", b, a))\n            }\n        },\n        name: {\n            get: function () {\n                return this.Ra\n            },\n            set: function (a) {\n                var b = this.Ra;\n                b !== a && (this.Ra = a, null !== this.part && (this.part.Fj = null), this.g(\"name\", b, a))\n            }\n        },\n        opacity: {\n            get: function () {\n                return this.qb\n            },\n            set: function (a) {\n                var b = this.qb;\n                b !== a && ((0 > a || 1 < a) && va(a, \"0 <= value <= 1\", Y, \"opacity\"), this.qb = a, this.g(\"opacity\", b, a), a = this.diagram, b = this.part, null !== a && null !== b && a.M(Bj(b, b.actualBounds)))\n            }\n        },\n        visible: {\n            get: function () {\n                return 0 !== (this.F & 1)\n            },\n            set: function (a) {\n                var b = 0 !== (this.F & 1);\n                b !== a && (this.F ^= 1, this.g(\"visible\", b, a), b = this.panel, null !== b ? b.o() : this.xf() && this.Ob(a), this.M(), Hl(this))\n            }\n        },\n        pickable: {\n            get: function () {\n                return 0 !== (this.F & 2)\n            },\n            set: function (a) {\n                var b =\n                    0 !== (this.F & 2);\n                b !== a && (this.F ^= 2, this.g(\"pickable\", b, a))\n            }\n        },\n        fromLinkableDuplicates: {\n            get: function () {\n                return 0 !== (this.F & 4)\n            },\n            set: function (a) {\n                var b = 0 !== (this.F & 4);\n                b !== a && (this.F ^= 4, this.g(\"fromLinkableDuplicates\", b, a))\n            }\n        },\n        fromLinkableSelfNode: {\n            get: function () {\n                return 0 !== (this.F & 8)\n            },\n            set: function (a) {\n                var b = 0 !== (this.F & 8);\n                b !== a && (this.F ^= 8, this.g(\"fromLinkableSelfNode\", b, a))\n            }\n        },\n        toLinkableDuplicates: {\n            get: function () {\n                return 0 !==\n                    (this.F & 16)\n            },\n            set: function (a) {\n                var b = 0 !== (this.F & 16);\n                b !== a && (this.F ^= 16, this.g(\"toLinkableDuplicates\", b, a))\n            }\n        },\n        toLinkableSelfNode: {\n            get: function () {\n                return 0 !== (this.F & 32)\n            },\n            set: function (a) {\n                var b = 0 !== (this.F & 32);\n                b !== a && (this.F ^= 32, this.g(\"toLinkableSelfNode\", b, a))\n            }\n        },\n        isPanelMain: {\n            get: function () {\n                return 0 !== (this.F & 64)\n            },\n            set: function (a) {\n                var b = 0 !== (this.F & 64);\n                b !== a && (this.F ^= 64, this.o(), this.g(\"isPanelMain\", b, a))\n            }\n        },\n        isActionable: {\n            get: function () {\n                return 0 !== (this.F & 128)\n            },\n            set: function (a) {\n                var b = 0 !== (this.F & 128);\n                b !== a && (this.F ^= 128, this.g(\"isActionable\", b, a))\n            }\n        },\n        areaBackground: {\n            get: function () {\n                return this.dc\n            },\n            set: function (a) {\n                var b = this.dc;\n                b !== a && (null !== a && Rl(a, \"GraphObject.areaBackground\"), a instanceof tl && a.freeze(), this.dc = a, this.M(), this.g(\"areaBackground\", b, a))\n            }\n        },\n        background: {\n            get: function () {\n                return this.gb\n            },\n            set: function (a) {\n                var b = this.gb;\n                b !== a && (null !== a && Rl(a, \"GraphObject.background\"),\n                    a instanceof tl && a.freeze(), this.gb = a, this.M(), this.g(\"background\", b, a))\n            }\n        },\n        part: {\n            get: function () {\n                if (this.xf()) return this;\n                if (null !== this.Jj) return this.Jj;\n                var a;\n                for (a = this.panel; a;) {\n                    if (a instanceof U) return this.Jj = a;\n                    a = a.panel\n                }\n                return null\n            }\n        },\n        svg: {\n            get: function () {\n                return this.Pp\n            },\n            set: function (a) {\n                this.Pp = a\n            }\n        },\n        panel: {\n            get: function () {\n                return this.ng\n            }\n        },\n        layer: {\n            get: function () {\n                var a = this.part;\n                return null !== a ? a.layer : null\n            }\n        },\n        diagram: {\n            get: function () {\n                var a = this.part;\n                return null !== a ? a.diagram : null\n            }\n        },\n        position: {\n            get: function () {\n                return this.ma\n            },\n            set: function (a) {\n                var b = a.x,\n                    c = a.y,\n                    d = this.ma,\n                    e = d.x,\n                    f = d.y;\n                (e === b || isNaN(e) && isNaN(b)) && (f === c || isNaN(f) && isNaN(c)) ? this.hw(): (a = a.copy(), this.gw(a, d) && this.g(\"position\", d.copy(), a))\n            }\n        },\n        actualBounds: {\n            get: function () {\n                return this.ub\n            }\n        },\n        scale: {\n            get: function () {\n                return this.ya\n            },\n            set: function (a) {\n                var b = this.ya;\n                b !== a && (0 >= a && B(\"GraphObject.scale for \" + this + \" must be greater than zero, not: \" + a), this.ya = a, this.o(), this.g(\"scale\", b, a))\n            }\n        },\n        angle: {\n            get: function () {\n                return this.Yb\n            },\n            set: function (a) {\n                var b = this.Yb;\n                b !== a && (a %= 360, 0 > a && (a += 360), b !== a && (this.Yb = a, Hl(this), this.o(), this.g(\"angle\", b, a)))\n            }\n        },\n        desiredSize: {\n            get: function () {\n                return this.Lc\n            },\n            set: function (a) {\n                var b = a.width,\n                    c = a.height,\n                    d = this.Lc,\n                    e = d.width,\n                    f = d.height;\n                (e === b || isNaN(e) &&\n                    isNaN(b)) && (f === c || isNaN(f) && isNaN(c)) || (this.Lc = a = a.G(), this.o(), this instanceof Lf && this.cc(), this.g(\"desiredSize\", d, a), el(this) && (a = this.part, null !== a && (fl(this, a, \"width\"), fl(this, a, \"height\"))))\n            }\n        },\n        width: {\n            get: function () {\n                return this.Lc.width\n            },\n            set: function (a) {\n                var b = this.Lc.width;\n                b === a || isNaN(b) && isNaN(a) || (b = this.Lc, this.Lc = a = (new M(a, this.Lc.height)).freeze(), this.o(), this instanceof Lf && this.cc(), this.g(\"desiredSize\", b, a), el(this) && (a = this.part, null !== a && fl(this, a,\n                    \"width\")))\n            }\n        },\n        height: {\n            get: function () {\n                return this.Lc.height\n            },\n            set: function (a) {\n                var b = this.Lc.height;\n                b === a || isNaN(b) && isNaN(a) || (b = this.Lc, this.Lc = a = (new M(this.Lc.width, a)).freeze(), this.o(), this instanceof Lf && this.cc(), this.g(\"desiredSize\", b, a), el(this) && (a = this.part, null !== a && fl(this, a, \"height\")))\n            }\n        },\n        minSize: {\n            get: function () {\n                return this.eg\n            },\n            set: function (a) {\n                var b = this.eg;\n                b.w(a) || (a = a.copy(), isNaN(a.width) && (a.width = 0), isNaN(a.height) && (a.height =\n                    0), a.freeze(), this.eg = a, this.o(), this.g(\"minSize\", b, a))\n            }\n        },\n        maxSize: {\n            get: function () {\n                return this.dg\n            },\n            set: function (a) {\n                var b = this.dg;\n                b.w(a) || (a = a.copy(), isNaN(a.width) && (a.width = Infinity), isNaN(a.height) && (a.height = Infinity), a.freeze(), this.dg = a, this.o(), this.g(\"maxSize\", b, a))\n            }\n        },\n        measuredBounds: {\n            get: function () {\n                return this.nc\n            }\n        },\n        naturalBounds: {\n            get: function () {\n                return this.oc\n            }\n        },\n        margin: {\n            get: function () {\n                return this.fh\n            },\n            set: function (a) {\n                \"number\" === typeof a && (a = new oc(a));\n                var b = this.fh;\n                b.w(a) || (this.fh = a = a.G(), this.o(), this.g(\"margin\", b, a))\n            }\n        },\n        transform: {\n            get: function () {\n                0 !== (this.F & 2048) === !0 && ql(this);\n                return this.kb\n            }\n        },\n        ud: {\n            get: function () {\n                0 !== (this.F & 4096) === !0 && ql(this);\n                return this.Qh\n            }\n        },\n        alignment: {\n            get: function () {\n                return this.vb\n            },\n            set: function (a) {\n                var b = this.vb;\n                b.w(a) || (a.jc() && !a.Mb() && B(\"GraphObject.alignment for \" + this + \" must be a real Spot or Spot.Default, not: \" +\n                    a), this.vb = a = a.G(), Cl(this), this.g(\"alignment\", b, a))\n            }\n        },\n        column: {\n            get: function () {\n                return this.Og\n            },\n            set: function (a) {\n                a = Math.round(a);\n                var b = this.Og;\n                b !== a && (0 > a && va(a, \">= 0\", Y, \"column\"), this.Og = a, this.o(), this.g(\"column\", b, a))\n            }\n        },\n        columnSpan: {\n            get: function () {\n                return this.gn\n            },\n            set: function (a) {\n                a = Math.round(a);\n                var b = this.gn;\n                b !== a && (1 > a && va(a, \">= 1\", Y, \"columnSpan\"), this.gn = a, this.o(), this.g(\"columnSpan\", b, a))\n            }\n        },\n        row: {\n            get: function () {\n                return this.pp\n            },\n            set: function (a) {\n                a = Math.round(a);\n                var b = this.pp;\n                b !== a && (0 > a && va(a, \">= 0\", Y, \"row\"), this.pp = a, this.o(), this.g(\"row\", b, a))\n            }\n        },\n        rowSpan: {\n            get: function () {\n                return this.qp\n            },\n            set: function (a) {\n                a = Math.round(a);\n                var b = this.qp;\n                b !== a && (1 > a && va(a, \">= 1\", Y, \"rowSpan\"), this.qp = a, this.o(), this.g(\"rowSpan\", b, a))\n            }\n        },\n        spanAllocation: {\n            get: function () {\n                return this.Kp\n            },\n            set: function (a) {\n                var b = this.Kp;\n                b !== a && (this.Kp = a, this.o(), this.g(\"spanAllocation\", b, a))\n            }\n        },\n        alignmentFocus: {\n            get: function () {\n                return this.Fk\n            },\n            set: function (a) {\n                var b = this.Fk;\n                b.w(a) || (this.Fk = a = a.G(), this.o(), this.g(\"alignmentFocus\", b, a))\n            }\n        },\n        portId: {\n            get: function () {\n                return this.cp\n            },\n            set: function (a) {\n                var b = this.cp;\n                if (b !== a) {\n                    var c = this.part;\n                    null === c || c instanceof W || (B(\"Cannot set portID on a Link: \" + a), c = null);\n                    null !== b && null !== c && Sl(c, this);\n                    this.cp = a;\n                    null !== a && null !== c && (c.Ih = !0, Tl(c, this));\n                    this.g(\"portId\", b, a)\n                }\n            }\n        },\n        toSpot: {\n            get: function () {\n                return null !==\n                    this.O ? this.O.yh : uc\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.yh;\n                b.w(a) || (a = a.G(), this.O.yh = a, this.g(\"toSpot\", b, a), Gl(this))\n            }\n        },\n        toEndSegmentLength: {\n            get: function () {\n                return null !== this.O ? this.O.wh : 10\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.wh;\n                b !== a && (0 > a && va(a, \">= 0\", Y, \"toEndSegmentLength\"), this.O.wh = a, this.g(\"toEndSegmentLength\", b, a), Gl(this))\n            }\n        },\n        toShortLength: {\n            get: function () {\n                return null !== this.O ? this.O.xh : 0\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.xh;\n                b !== a && (this.O.xh = a, this.g(\"toShortLength\", b, a), Gl(this))\n            }\n        },\n        toLinkable: {\n            get: function () {\n                return null !== this.O ? this.O.Tp : null\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.Tp;\n                b !== a && (this.O.Tp = a, this.g(\"toLinkable\", b, a))\n            }\n        },\n        toMaxLinks: {\n            get: function () {\n                return null !== this.O ? this.O.Up : Infinity\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.Up;\n                b !== a && (0 > a && va(a, \">= 0\", Y, \"toMaxLinks\"), this.O.Up = a, this.g(\"toMaxLinks\", b, a))\n            }\n        },\n        fromSpot: {\n            get: function () {\n                return null !== this.O ? this.O.Yg : uc\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.Yg;\n                b.w(a) || (a = a.G(), this.O.Yg = a, this.g(\"fromSpot\", b, a), Gl(this))\n            }\n        },\n        fromEndSegmentLength: {\n            get: function () {\n                return null !== this.O ? this.O.Wg : 10\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.Wg;\n                b !== a && (0 > a && va(a, \">= 0\", Y, \"fromEndSegmentLength\"), this.O.Wg = a, this.g(\"fromEndSegmentLength\", b, a), Gl(this))\n            }\n        },\n        fromShortLength: {\n            get: function () {\n                return null !== this.O ? this.O.Xg :\n                    0\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.Xg;\n                b !== a && (this.O.Xg = a, this.g(\"fromShortLength\", b, a), Gl(this))\n            }\n        },\n        fromLinkable: {\n            get: function () {\n                return null !== this.O ? this.O.Kn : null\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.Kn;\n                b !== a && (this.O.Kn = a, this.g(\"fromLinkable\", b, a))\n            }\n        },\n        fromMaxLinks: {\n            get: function () {\n                return null !== this.O ? this.O.Ln : Infinity\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.Ln;\n                b !== a && (0 > a && va(a, \">= 0\", Y, \"fromMaxLinks\"), this.O.Ln = a, this.g(\"fromMaxLinks\",\n                    b, a))\n            }\n        },\n        cursor: {\n            get: function () {\n                return this.fi\n            },\n            set: function (a) {\n                var b = this.fi;\n                b !== a && (this.fi = a, this.g(\"cursor\", b, a))\n            }\n        },\n        click: {\n            get: function () {\n                return null !== this.N ? this.N.Nf : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.Nf;\n                b !== a && (this.N.Nf = a, this.g(\"click\", b, a))\n            }\n        },\n        doubleClick: {\n            get: function () {\n                return null !== this.N ? this.N.Sf : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.Sf;\n                b !== a && (this.N.Sf = a, this.g(\"doubleClick\", b,\n                    a))\n            }\n        },\n        contextClick: {\n            get: function () {\n                return null !== this.N ? this.N.Of : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.Of;\n                b !== a && (this.N.Of = a, this.g(\"contextClick\", b, a))\n            }\n        },\n        mouseEnter: {\n            get: function () {\n                return null !== this.N ? this.N.gg : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.gg;\n                b !== a && (this.N.gg = a, this.g(\"mouseEnter\", b, a))\n            }\n        },\n        mouseLeave: {\n            get: function () {\n                return null !== this.N ? this.N.jg : null\n            },\n            set: function (a) {\n                bl(this);\n                var b =\n                    this.N.jg;\n                b !== a && (this.N.jg = a, this.g(\"mouseLeave\", b, a))\n            }\n        },\n        mouseOver: {\n            get: function () {\n                return null !== this.N ? this.N.kg : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.kg;\n                b !== a && (this.N.kg = a, this.g(\"mouseOver\", b, a))\n            }\n        },\n        mouseHover: {\n            get: function () {\n                return null !== this.N ? this.N.ig : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.ig;\n                b !== a && (this.N.ig = a, this.g(\"mouseHover\", b, a))\n            }\n        },\n        mouseHold: {\n            get: function () {\n                return null !== this.N ? this.N.hg :\n                    null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.hg;\n                b !== a && (this.N.hg = a, this.g(\"mouseHold\", b, a))\n            }\n        },\n        mouseDragEnter: {\n            get: function () {\n                return null !== this.N ? this.N.Fo : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.Fo;\n                b !== a && (this.N.Fo = a, this.g(\"mouseDragEnter\", b, a))\n            }\n        },\n        mouseDragLeave: {\n            get: function () {\n                return null !== this.N ? this.N.Go : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.Go;\n                b !== a && (this.N.Go = a, this.g(\"mouseDragLeave\", b, a))\n            }\n        },\n        mouseDrop: {\n            get: function () {\n                return null !== this.N ? this.N.fg : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.fg;\n                b !== a && (this.N.fg = a, this.g(\"mouseDrop\", b, a))\n            }\n        },\n        actionDown: {\n            get: function () {\n                return null !== this.N ? this.N.Pm : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.Pm;\n                b !== a && (this.N.Pm = a, this.g(\"actionDown\", b, a))\n            }\n        },\n        actionMove: {\n            get: function () {\n                return null !== this.N ? this.N.Qm : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.Qm;\n                b !== a && (this.N.Qm = a, this.g(\"actionMove\",\n                    b, a))\n            }\n        },\n        actionUp: {\n            get: function () {\n                return null !== this.N ? this.N.Rm : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.Rm;\n                b !== a && (this.N.Rm = a, this.g(\"actionUp\", b, a))\n            }\n        },\n        actionCancel: {\n            get: function () {\n                return null !== this.N ? this.N.Om : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.Om;\n                b !== a && (this.N.Om = a, this.g(\"actionCancel\", b, a))\n            }\n        },\n        toolTip: {\n            get: function () {\n                return null !== this.N ? this.N.ug : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.ug;\n                b !== a && (this.N.ug = a, this.g(\"toolTip\", b, a))\n            }\n        },\n        contextMenu: {\n            get: function () {\n                return null !== this.N ? this.N.Pf : null\n            },\n            set: function (a) {\n                bl(this);\n                var b = this.N.Pf;\n                b !== a && (this.N.Pf = a, this.g(\"contextMenu\", b, a))\n            }\n        }\n    });\n    Y.prototype.setProperties = Y.prototype.iw;\n    Y.prototype.findTemplateBinder = Y.prototype.Ui;\n    Y.prototype.bind = Y.prototype.bind;\n    Y.prototype.isEnabledObject = Y.prototype.Eg;\n    Y.prototype.isVisibleObject = Y.prototype.zf;\n    Y.prototype.isContainedBy = Y.prototype.Dg;\n    Y.prototype.getNearestIntersectionPoint = Y.prototype.Uc;\n    Y.prototype.getLocalPoint = Y.prototype.ot;\n    Y.prototype.getDocumentScale = Y.prototype.uf;\n    Y.prototype.getDocumentAngle = Y.prototype.Xi;\n    Y.prototype.getDocumentBounds = Y.prototype.lm;\n    Y.prototype.getDocumentPoint = Y.prototype.ga;\n    Y.prototype.intersectsRect = Y.prototype.Gc;\n    Y.prototype.containedInRect = Y.prototype.Gh;\n    Y.prototype.containsRect = Y.prototype.ze;\n    Y.prototype.containsPoint = Y.prototype.aa;\n    Y.prototype.raiseChanged = Y.prototype.g;\n    Y.prototype.raiseChangedEvent = Y.prototype.Ya;\n    Y.prototype.addCopyProperty = Y.prototype.sx;\n    var Ll = null;\n    Y.className = \"GraphObject\";\n    Ll = new H;\n    Pl(\"Button\", function () {\n        function a(a, b) {\n            return null !== a.diagram.Ub(a.documentPoint, function (a) {\n                for (; null !== a.panel && !a.isActionable;) a = a.panel;\n                return a\n            }, function (a) {\n                return a === b\n            })\n        }\n        var b = Kl(X, X.Auto, {\n            isActionable: !0,\n            enabledChanged: function (a, b) {\n                if (a instanceof X) {\n                    var c = a.Xa(\"ButtonBorder\");\n                    null !== c && (c.fill = b ? a._buttonFillNormal : a._buttonFillDisabled)\n                }\n            },\n            cursor: \"pointer\",\n            _buttonFillNormal: \"#F5F5F5\",\n            _buttonStrokeNormal: \"#BDBDBD\",\n            _buttonFillOver: \"#E0E0E0\",\n            _buttonStrokeOver: \"#9E9E9E\",\n            _buttonFillPressed: \"#BDBDBD\",\n            _buttonStrokePressed: \"#9E9E9E\",\n            _buttonFillDisabled: \"#E5E5E5\"\n        }, Kl(Lf, {\n            name: \"ButtonBorder\",\n            figure: \"RoundedRectangle\",\n            spot1: new P(0, 0, 2.76142374915397, 2.761423749153969),\n            spot2: new P(1, 1, -2.76142374915397, -2.761423749153969),\n            parameter1: 2,\n            parameter2: 2,\n            fill: \"#F5F5F5\",\n            stroke: \"#BDBDBD\"\n        }));\n        b.mouseEnter = function (a, b) {\n            if (b.Eg() && b instanceof X && (a = b.Xa(\"ButtonBorder\"), a instanceof Lf)) {\n                var c = b._buttonFillOver;\n                b._buttonFillNormal = a.fill;\n                a.fill = c;\n                c = b._buttonStrokeOver;\n                b._buttonStrokeNormal = a.stroke;\n                a.stroke = c\n            }\n        };\n        b.mouseLeave = function (a, b) {\n            b.Eg() && b instanceof X && (a = b.Xa(\"ButtonBorder\"), a instanceof Lf && (a.fill = b._buttonFillNormal, a.stroke = b._buttonStrokeNormal))\n        };\n        b.actionDown = function (a, b) {\n            if (b.Eg() && b instanceof X && null !== b._buttonFillPressed && 0 === a.button) {\n                var c = b.Xa(\"ButtonBorder\");\n                if (c instanceof Lf) {\n                    a = a.diagram;\n                    var d = a.skipsUndoManager;\n                    a.skipsUndoManager = !0;\n                    var g = b._buttonFillPressed;\n                    b._buttonFillOver = c.fill;\n                    c.fill = g;\n                    g = b._buttonStrokePressed;\n                    b._buttonStrokeOver = c.stroke;\n                    c.stroke = g;\n                    a.skipsUndoManager =\n                        d\n                }\n            }\n        };\n        b.actionUp = function (b, d) {\n            if (d.Eg() && d instanceof X && null !== d._buttonFillPressed && 0 === b.button) {\n                var c = d.Xa(\"ButtonBorder\");\n                if (c instanceof Lf) {\n                    var f = b.diagram,\n                        g = f.skipsUndoManager;\n                    f.skipsUndoManager = !0;\n                    a(b, d) ? (c.fill = d._buttonFillOver, c.stroke = d._buttonStrokeOver) : (c.fill = d._buttonFillNormal, c.stroke = d._buttonStrokeNormal);\n                    f.skipsUndoManager = g\n                }\n            }\n        };\n        b.actionCancel = function (b, d) {\n            if (d.Eg() && d instanceof X && null !== d._buttonFillPressed) {\n                var c = d.Xa(\"ButtonBorder\");\n                if (c instanceof Lf) {\n                    var f = b.diagram,\n                        g = f.skipsUndoManager;\n                    f.skipsUndoManager = !0;\n                    a(b, d) ? (c.fill = d._buttonFillOver, c.stroke = d._buttonStrokeOver) : (c.fill = d._buttonFillNormal, c.stroke = d._buttonStrokeNormal);\n                    f.skipsUndoManager = g\n                }\n            }\n        };\n        b.actionMove = function (b, d) {\n            if (d.Eg() && d instanceof X && null !== d._buttonFillPressed) {\n                var c = b.diagram;\n                if (0 === c.firstInput.button && (c.currentTool.standardMouseOver(), a(b, d) && (b = d.Xa(\"ButtonBorder\"), b instanceof Lf))) {\n                    var f = c.skipsUndoManager;\n                    c.skipsUndoManager = !0;\n                    var g = d._buttonFillPressed;\n                    b.fill !== g && (b.fill = g);\n                    g =\n                        d._buttonStrokePressed;\n                    b.stroke !== g && (b.stroke = g);\n                    c.skipsUndoManager = f\n                }\n            }\n        };\n        return b\n    });\n    Pl(\"TreeExpanderButton\", function () {\n        var a = Kl(\"Button\", {\n            _treeExpandedFigure: \"MinusLine\",\n            _treeCollapsedFigure: \"PlusLine\"\n        }, Kl(Lf, {\n            name: \"ButtonIcon\",\n            figure: \"MinusLine\",\n            stroke: \"#424242\",\n            strokeWidth: 2,\n            desiredSize: Nb\n        }, (new Ji(\"figure\", \"isTreeExpanded\", function (a, c) {\n            c = c.panel;\n            return a ? c._treeExpandedFigure : c._treeCollapsedFigure\n        })).Aq()), {\n            visible: !1\n        }, (new Ji(\"visible\", \"isTreeLeaf\", function (a) {\n            return !a\n        })).Aq());\n        a.click = function (a, c) {\n            c = c.part;\n            c instanceof Je && (c = c.adornedPart);\n            if (c instanceof W) {\n                var b = c.diagram;\n                if (null !== b) {\n                    b = b.commandHandler;\n                    if (c.isTreeExpanded) {\n                        if (!b.canCollapseTree(c)) return\n                    } else if (!b.canExpandTree(c)) return;\n                    a.handled = !0;\n                    c.isTreeExpanded ? b.collapseTree(c) : b.expandTree(c)\n                }\n            }\n        };\n        return a\n    });\n    Pl(\"SubGraphExpanderButton\", function () {\n        var a = Kl(\"Button\", {\n            _subGraphExpandedFigure: \"MinusLine\",\n            _subGraphCollapsedFigure: \"PlusLine\"\n        }, Kl(Lf, {\n            name: \"ButtonIcon\",\n            figure: \"MinusLine\",\n            stroke: \"#424242\",\n            strokeWidth: 2,\n            desiredSize: Nb\n        }, (new Ji(\"figure\", \"isSubGraphExpanded\", function (a, c) {\n            c = c.panel;\n            return a ? c._subGraphExpandedFigure : c._subGraphCollapsedFigure\n        })).Aq()));\n        a.click = function (a, c) {\n            c = c.part;\n            c instanceof Je && (c = c.adornedPart);\n            if (c instanceof T) {\n                var b = c.diagram;\n                if (null !== b) {\n                    b = b.commandHandler;\n                    if (c.isSubGraphExpanded) {\n                        if (!b.canCollapseSubGraph(c)) return\n                    } else if (!b.canExpandSubGraph(c)) return;\n                    a.handled = !0;\n                    c.isSubGraphExpanded ? b.collapseSubGraph(c) : b.expandSubGraph(c)\n                }\n            }\n        };\n        return a\n    });\n    Pl(\"ToolTip\", function () {\n        return Kl(Je, X.Auto, {\n            isShadowed: !0,\n            shadowColor: \"rgba(0, 0, 0, .4)\",\n            shadowOffset: new I(0, 3),\n            shadowBlur: 5\n        }, Kl(Lf, {\n            name: \"Border\",\n            figure: \"RoundedRectangle\",\n            parameter1: 1,\n            parameter2: 1,\n            fill: \"#F5F5F5\",\n            stroke: \"#F0F0F0\",\n            spot1: new P(0, 0, 4, 6),\n            spot2: new P(1, 1, -4, -4)\n        }))\n    });\n    Pl(\"ContextMenu\", function () {\n        return Kl(Je, X.Vertical, {\n            background: \"#F5F5F5\",\n            isShadowed: !0,\n            shadowColor: \"rgba(0, 0, 0, .4)\",\n            shadowOffset: new I(0, 3),\n            shadowBlur: 5\n        }, new Ji(\"background\", \"\", function (a) {\n            return null !== a.adornedPart && null !== a.placeholder ? null : \"#F5F5F5\"\n        }))\n    });\n    Pl(\"ContextMenuButton\", function () {\n        var a = Kl(\"Button\");\n        a.stretch = Wk;\n        var b = a.Xa(\"ButtonBorder\");\n        b instanceof Lf && (b.figure = \"Rectangle\", b.strokeWidth = 0, b.spot1 = new P(0, 0, 2, 3), b.spot2 = new P(1, 1, -2, -2));\n        return a\n    });\n    Pl(\"PanelExpanderButton\", function (a) {\n        var b = Ql(a, \"COLLAPSIBLE\"),\n            c = Kl(\"Button\", {\n                _buttonExpandedFigure: \"M0 0 M0 6 L4 2 8 6 M8 8\",\n                _buttonCollapsedFigure: \"M0 0 M0 2 L4 6 8 2 M8 8\",\n                _buttonFillNormal: \"rgba(0, 0, 0, 0)\",\n                _buttonStrokeNormal: null,\n                _buttonFillOver: \"rgba(0, 0, 0, .2)\",\n                _buttonStrokeOver: null,\n                _buttonFillPressed: \"rgba(0, 0, 0, .4)\",\n                _buttonStrokePressed: null\n            }, Kl(Lf, {\n                name: \"ButtonIcon\",\n                strokeWidth: 2\n            }, (new Ji(\"geometryString\", \"visible\", function (a) {\n                return a ? c._buttonExpandedFigure : c._buttonCollapsedFigure\n            })).Aq(b)));\n        a = c.Xa(\"ButtonBorder\");\n        a instanceof Lf && (a.stroke = null, a.fill = \"rgba(0, 0, 0, 0)\");\n        c.click = function (a, c) {\n            var d = c.diagram;\n            if (null !== d && !d.isReadOnly) {\n                var e = c.Ui();\n                null === e && (e = c.part);\n                null !== e && (c = e.Xa(b), null !== c && (a.handled = !0, d.ua(\"Collapse/Expand Panel\"), c.visible = !c.visible, d.Ua(\"Collapse/Expand Panel\")))\n            }\n        };\n        return c\n    });\n    Pl(\"CheckBoxButton\", function (a) {\n        var b = Ql(a);\n        a = Kl(\"Button\", {\n            desiredSize: new M(14, 14)\n        }, Kl(Lf, {\n            name: \"ButtonIcon\",\n            geometryString: \"M0 0 M0 8.85 L4.9 13.75 16.2 2.45 M16.2 16.2\",\n            strokeWidth: 2,\n            stretch: vd,\n            geometryStretch: Bg,\n            visible: !1\n        }, \"\" !== b ? (new Ji(\"visible\", b)).Vx() : []));\n        a.click = function (a, d) {\n            if (d instanceof X) {\n                var c = a.diagram;\n                if (!(null === c || c.isReadOnly || \"\" !== b && c.model.isReadOnly)) {\n                    a.handled = !0;\n                    var f = d.Xa(\"ButtonIcon\");\n                    c.ua(\"checkbox\");\n                    f.visible = !f.visible;\n                    \"function\" === typeof d._doClick && d._doClick(a,\n                        d);\n                    c.Ua(\"checkbox\")\n                }\n            }\n        };\n        return a\n    });\n    Pl(\"CheckBox\", function (a) {\n        a = Ql(a);\n        a = Kl(\"CheckBoxButton\", a, {\n            name: \"Button\",\n            isActionable: !1,\n            margin: new oc(0, 1, 0, 0)\n        });\n        var b = Kl(X, \"Horizontal\", a, {\n            isActionable: !0,\n            cursor: a.cursor,\n            margin: 1,\n            _buttonFillNormal: a._buttonFillNormal,\n            _buttonStrokeNormal: a._buttonStrokeNormal,\n            _buttonFillOver: a._buttonFillOver,\n            _buttonStrokeOver: a._buttonStrokeOver,\n            _buttonFillPressed: a._buttonFillPressed,\n            _buttonStrokePressed: a._buttonStrokePressed,\n            _buttonFillDisabled: a._buttonFillDisabled,\n            mouseEnter: a.mouseEnter,\n            mouseLeave: a.mouseLeave,\n            actionDown: a.actionDown,\n            actionUp: a.actionUp,\n            actionCancel: a.actionCancel,\n            actionMove: a.actionMove,\n            click: a.click,\n            _buttonClick: a.click\n        });\n        a.mouseEnter = null;\n        a.mouseLeave = null;\n        a.actionDown = null;\n        a.actionUp = null;\n        a.actionCancel = null;\n        a.actionMove = null;\n        a.click = null;\n        return b\n    });\n    Y.None = zg = new D(Y, \"None\", 0);\n    Y.Default = Vk = new D(Y, \"Default\", 0);\n    Y.Vertical = Xk = new D(Y, \"Vertical\", 4);\n    Y.Horizontal = Wk = new D(Y, \"Horizontal\", 5);\n    Y.Fill = vd = new D(Y, \"Fill\", 3);\n    Y.Uniform = Bg = new D(Y, \"Uniform\", 1);\n    Y.UniformToFill = Yk = new D(Y, \"UniformToFill\", 2);\n    Y.FlipVertical = Zk = new D(Y, \"FlipVertical\", 1);\n    Y.FlipHorizontal = $k = new D(Y, \"FlipHorizontal\", 2);\n    Y.FlipBoth = al = new D(Y, \"FlipBoth\", 3);\n    Y.make = Kl;\n    Y.getBuilders = function () {\n        var a = new H,\n            b;\n        for (b in Ll)\n            if (b !== b.toLowerCase()) {\n                var c = Ll.H(b);\n                \"function\" === typeof c && a.add(b, c)\n            } a.freeze();\n        return a\n    };\n    Y.defineBuilder = Pl;\n    Y.takeBuilderArgument = Ql;\n\n    function cl() {\n        this.En = this.Pf = this.ug = this.Om = this.Rm = this.Qm = this.Pm = this.fg = this.Go = this.Fo = this.hg = this.ig = this.kg = this.jg = this.gg = this.Of = this.Sf = this.Nf = null\n    }\n    cl.prototype.copy = function () {\n        var a = new cl;\n        a.Nf = this.Nf;\n        a.Sf = this.Sf;\n        a.Of = this.Of;\n        a.gg = this.gg;\n        a.jg = this.jg;\n        a.kg = this.kg;\n        a.ig = this.ig;\n        a.hg = this.hg;\n        a.Fo = this.Fo;\n        a.Go = this.Go;\n        a.fg = this.fg;\n        a.Pm = this.Pm;\n        a.Qm = this.Qm;\n        a.Rm = this.Rm;\n        a.Om = this.Om;\n        a.ug = this.ug;\n        a.Pf = this.Pf;\n        a.En = this.En;\n        return a\n    };\n    cl.className = \"GraphObjectEventHandlers\";\n\n    function Ul() {\n        this.Ka = [1, 0, 0, 1, 0, 0]\n    }\n    Ul.prototype.copy = function () {\n        var a = new Ul;\n        a.Ka[0] = this.Ka[0];\n        a.Ka[1] = this.Ka[1];\n        a.Ka[2] = this.Ka[2];\n        a.Ka[3] = this.Ka[3];\n        a.Ka[4] = this.Ka[4];\n        a.Ka[5] = this.Ka[5];\n        return a\n    };\n    Ul.prototype.translate = function (a, b) {\n        this.Ka[4] += this.Ka[0] * a + this.Ka[2] * b;\n        this.Ka[5] += this.Ka[1] * a + this.Ka[3] * b\n    };\n    Ul.prototype.scale = function (a, b) {\n        this.Ka[0] *= a;\n        this.Ka[1] *= a;\n        this.Ka[2] *= b;\n        this.Ka[3] *= b\n    };\n    Ul.className = \"STransform\";\n\n    function Vl(a) {\n        this.type = a;\n        this.r2 = this.y2 = this.x2 = this.r1 = this.y1 = this.x1 = 0;\n        this.zx = [];\n        this.pattern = null\n    }\n    Vl.prototype.addColorStop = function (a, b) {\n        this.zx.push({\n            offset: a,\n            color: b\n        })\n    };\n    Vl.className = \"SGradient\";\n\n    function Aj(a, b) {\n        this.ownerDocument = a = void 0 === b ? x.document : b;\n        this.hA = \"http://www.w3.org/2000/svg\";\n        void 0 !== a && (this.Ea = this.tb(\"svg\", {\n            width: \"1px\",\n            height: \"1px\",\n            viewBox: \"0 0 1 1\"\n        }), this.Ea.setAttributeNS(\"http://www.w3.org/2000/xmlns/\", \"xmlns\", \"http://www.w3.org/2000/svg\"), this.Ea.setAttributeNS(\"http://www.w3.org/2000/xmlns/\", \"xmlns:xlink\", \"http://www.w3.org/1999/xlink\"));\n        this.jq = null;\n        this.context = new Wl(this)\n    }\n    Aj.prototype.resize = function (a, b, c, d) {\n        return this.width !== a || this.height !== b ? (this.style.width = c + \"px\", this.style.height = d + \"px\", this.Ea.setAttributeNS(null, \"width\", c + \"px\"), this.Ea.setAttributeNS(null, \"height\", d + \"px\"), this.Ea.setAttributeNS(null, \"viewBox\", \"0 0 \" + c + \" \" + d), this.context.Cu.firstElementChild.setAttributeNS(null, \"width\", c + \"px\"), this.context.Cu.firstElementChild.setAttributeNS(null, \"height\", d + \"px\"), !0) : !1\n    };\n    Aj.prototype.tb = function (a, b, c) {\n        a = this.ownerDocument.createElementNS(this.hA, a);\n        if (za(b))\n            for (var d in b) a.setAttributeNS(\"href\" === d ? \"http://www.w3.org/1999/xlink\" : \"\", d, b[d]);\n        void 0 !== c && (a.textContent = c);\n        return a\n    };\n    Aj.prototype.getBoundingClientRect = function () {\n        return this.Ea.getBoundingClientRect()\n    };\n    Aj.prototype.focus = function () {\n        this.Ea.focus()\n    };\n    Aj.prototype.Fx = function () {\n        this.ownerDocument = null\n    };\n    ma.Object.defineProperties(Aj.prototype, {\n        width: {\n            get: function () {\n                return this.Ea.width.baseVal.value\n            },\n            set: function (a) {\n                this.Ea.width = a\n            }\n        },\n        height: {\n            get: function () {\n                return this.Ea.height.baseVal.value\n            },\n            set: function (a) {\n                this.Ea.height = a\n            }\n        },\n        style: {\n            get: function () {\n                return this.Ea.style\n            }\n        }\n    });\n    Aj.className = \"SVGSurface\";\n\n    function Wl(a) {\n        this.yk = a;\n        this.svg = a.Ea;\n        this.stack = [];\n        this.xc = [];\n        this.fillStyle = \"#000000\";\n        this.font = \"10px sans-serif\";\n        this.globalAlpha = 1;\n        this.lineCap = \"butt\";\n        this.lineDashOffset = 0;\n        this.lineJoin = \"miter\";\n        this.lineWidth = 1;\n        this.miterLimit = 10;\n        this.shadowBlur = 0;\n        this.shadowColor = \"rgba(0, 0, 0, 0)\";\n        this.shadowOffsetY = this.shadowOffsetX = 0;\n        this.strokeStyle = \"#000000\";\n        this.textAlign = \"start\";\n        this.clipInsteadOfFill = !1;\n        this.df = this.Gp = this.Fp = 0;\n        this.uq = null;\n        this.path = [];\n        this.vu = !1;\n        this.rh = null;\n        this.sh = 0;\n        this.Td = new Ul;\n        Xl(this, 1, 0, 0, 1, 0, 0);\n        var b = pb++,\n            c = this.tb(\"clipPath\", {\n                id: \"mainClip\" + b\n            });\n        c.appendChild(this.tb(\"rect\", {\n            x: 0,\n            y: 0,\n            width: a.width,\n            height: a.height\n        }));\n        this.Cu = c;\n        this.yk.Ea.appendChild(c);\n        this.xc[0].setAttributeNS(null, \"clip-path\", \"url(#mainClip\" + b + \")\");\n        this.jA = {}\n    }\n    t = Wl.prototype;\n    t.reset = function () {\n        this.stack = [];\n        this.xc = [];\n        this.fillStyle = \"#000000\";\n        this.font = \"10px sans-serif\";\n        this.globalAlpha = 1;\n        this.lineCap = \"butt\";\n        this.lineDashOffset = 0;\n        this.lineJoin = \"miter\";\n        this.lineWidth = 1;\n        this.miterLimit = 10;\n        this.shadowBlur = 0;\n        this.shadowColor = \"rgba(0, 0, 0, 0)\";\n        this.shadowOffsetY = this.shadowOffsetX = 0;\n        this.strokeStyle = \"#000000\";\n        this.textAlign = \"start\";\n        this.clipInsteadOfFill = !1;\n        this.df = this.Gp = this.Fp = 0;\n        this.uq = null;\n        this.path = [];\n        this.Td = new Ul;\n        Xl(this, 1, 0, 0, 1, 0, 0);\n        var a = pb++,\n            b = this.tb(\"clipPath\", {\n                id: \"mainClip\" + a\n            });\n        b.appendChild(this.tb(\"rect\", {\n            x: 0,\n            y: 0,\n            width: this.yk.width,\n            height: this.yk.height\n        }));\n        this.Cu = b;\n        this.yk.Ea.appendChild(b);\n        this.xc[0].setAttributeNS(null, \"clip-path\", \"url(#mainClip\" + a + \")\")\n    };\n    t.arc = function (a, b, c, d, e, f, g, h) {\n        var k = 2 * Math.PI,\n            l = k - 1E-6,\n            m = c * Math.cos(d),\n            n = c * Math.sin(d),\n            p = a + m,\n            r = b + n,\n            q = f ? 0 : 1;\n        d = f ? d - e : e - d;\n        (1E-6 < Math.abs(g - p) || 1E-6 < Math.abs(h - r)) && this.path.push([\"L\", p, +r]);\n        0 > d && (d = d % k + k);\n        d > l ? (this.path.push([\"A\", c, c, 0, 1, q, a - m, b - n]), this.path.push([\"A\", c, c, 0, 1, q, p, r])) : 1E-6 < d && this.path.push([\"A\", c, c, 0, +(d >= Math.PI), q, a + c * Math.cos(e), b + c * Math.sin(e)])\n    };\n    t.beginPath = function () {\n        this.path = []\n    };\n    t.bezierCurveTo = function (a, b, c, d, e, f) {\n        this.path.push([\"C\", a, b, c, d, e, f])\n    };\n    t.clearRect = function () {};\n    t.clip = function () {\n        this.addPath(\"clipPath\", this.path, this.Td);\n        this.addPath(\"clipPath\", this.path, new Ul)\n    };\n    t.closePath = function () {\n        this.path.push([\"z\"])\n    };\n    t.createLinearGradient = function (a, b, c, d) {\n        var e = new Vl(\"linear\");\n        e.x1 = a;\n        e.y1 = b;\n        e.x2 = c;\n        e.y2 = d;\n        return e\n    };\n    t.createPattern = function (a) {\n        var b = \"\";\n        a instanceof HTMLCanvasElement && (b = a.toDataURL());\n        a instanceof HTMLImageElement && (b = a.getAttribute(\"src\"));\n        var c = this.jA;\n        if (c[b]) return \"url(#\" + c[b] + \")\";\n        var d = \"PATTERN\" + pb++,\n            e = {\n                x: 0,\n                y: 0,\n                width: a.width,\n                height: a.height,\n                href: b\n            };\n        a = this.tb(\"pattern\", {\n            width: a.width,\n            height: a.height,\n            id: d,\n            patternUnits: \"userSpaceOnUse\"\n        });\n        a.appendChild(this.tb(\"image\", e));\n        this.svg.appendChild(a);\n        c[b] = d;\n        return \"url(#\" + d + \")\"\n    };\n    t.createRadialGradient = function (a, b, c, d, e, f) {\n        var g = new Vl(\"radial\");\n        g.x1 = a;\n        g.y1 = b;\n        g.r1 = c;\n        g.x2 = d;\n        g.y2 = e;\n        g.r2 = f;\n        return g\n    };\n    t.drawImage = function (a, b, c, d, e, f, g, h, k) {\n        var l = \"\";\n        a instanceof HTMLCanvasElement && (l = a.toDataURL());\n        a instanceof HTMLImageElement && (l = a.getAttribute(\"src\"));\n        var m = a instanceof HTMLImageElement ? a.naturalWidth : a.width,\n            n = a instanceof HTMLImageElement ? a.naturalHeight : a.height;\n        void 0 === d && (f = b, g = c, h = d = m, k = e = n);\n        d = d || 0;\n        e = e || 0;\n        f = f || 0;\n        g = g || 0;\n        h = h || 0;\n        k = k || 0;\n        l = {\n            x: 0,\n            y: 0,\n            width: m || d,\n            height: n || e,\n            href: l,\n            preserveAspectRatio: \"xMidYMid slice\"\n        };\n        J.$(d, h) && J.$(e, k) || (l.preserveAspectRatio = \"none\");\n        a = \"\";\n        h /= d;\n        k /= e;\n        if (0 !== f ||\n            0 !== g) a += \" translate(\" + f + \", \" + g + \")\";\n        if (1 !== h || 1 !== k) a += \" scale(\" + h + \", \" + k + \")\";\n        if (0 !== b || 0 !== c) a += \" translate(\" + -b + \", \" + -c + \")\";\n        if (0 !== b || 0 !== c || d !== m || e !== n) f = \"CLIP\" + pb++, g = this.tb(\"clipPath\", {\n            id: f\n        }), g.appendChild(this.tb(\"rect\", {\n            x: b,\n            y: c,\n            width: d,\n            height: e\n        })), this.svg.appendChild(g), l[\"clip-path\"] = \"url(#\" + f + \")\";\n        Yl(this, \"image\", l, this.Td, a);\n        this.addElement(\"image\", l)\n    };\n    t.fill = function () {\n        this.addPath(\"fill\", this.path, this.Td)\n    };\n    t.Ud = function () {\n        this.clipInsteadOfFill ? this.clip() : this.fill()\n    };\n    t.fillRect = function (a, b, c, d) {\n        a = [a, b, c, d];\n        a = {\n            x: a[0],\n            y: a[1],\n            width: a[2],\n            height: a[3]\n        };\n        Yl(this, \"fill\", a, this.Td);\n        this.addElement(\"rect\", a)\n    };\n    t.fillText = function (a, b, c) {\n        a = [a, b, c];\n        b = this.textAlign;\n        \"left\" === b ? b = \"start\" : \"right\" === b ? b = \"end\" : \"center\" === b && (b = \"middle\");\n        b = {\n            x: a[1],\n            y: a[2],\n            style: \"font: \" + this.font,\n            \"text-anchor\": b\n        };\n        Yl(this, \"fill\", b, this.Td);\n        this.addElement(\"text\", b, a[0])\n    };\n    t.lineTo = function (a, b) {\n        this.path.push([\"L\", a, b])\n    };\n    t.moveTo = function (a, b) {\n        this.path.push([\"M\", a, b])\n    };\n    t.quadraticCurveTo = function (a, b, c, d) {\n        this.path.push([\"Q\", a, b, c, d])\n    };\n    t.rect = function (a, b, c, d) {\n        this.path.push([\"M\", a, b], [\"L\", a + c, b], [\"L\", a + c, b + d], [\"L\", a, b + d], [\"z\"])\n    };\n    t.restore = function () {\n        this.Td = this.stack.pop();\n        this.path = this.stack.pop();\n        var a = this.stack.pop();\n        this.fillStyle = a.fillStyle;\n        this.font = a.font;\n        this.globalAlpha = a.globalAlpha;\n        this.lineCap = a.lineCap;\n        this.lineDashOffset = a.lineDashOffset;\n        this.lineJoin = a.lineJoin;\n        this.lineWidth = a.lineWidth;\n        this.miterLimit = a.miterLimit;\n        this.shadowBlur = a.shadowBlur;\n        this.shadowColor = a.shadowColor;\n        this.shadowOffsetX = a.shadowOffsetX;\n        this.shadowOffsetY = a.shadowOffsetY;\n        this.strokeStyle = a.strokeStyle;\n        this.textAlign = a.textAlign\n    };\n    t.save = function () {\n        this.stack.push({\n            fillStyle: this.fillStyle,\n            font: this.font,\n            globalAlpha: this.globalAlpha,\n            lineCap: this.lineCap,\n            lineDashOffset: this.lineDashOffset,\n            lineJoin: this.lineJoin,\n            lineWidth: this.lineWidth,\n            miterLimit: this.miterLimit,\n            shadowBlur: this.shadowBlur,\n            shadowColor: this.shadowColor,\n            shadowOffsetX: this.shadowOffsetX,\n            shadowOffsetY: this.shadowOffsetY,\n            strokeStyle: this.strokeStyle,\n            textAlign: this.textAlign\n        });\n        for (var a = [], b = 0; b < this.path.length; b++) a.push(this.path[b]);\n        this.stack.push(a);\n        this.stack.push(this.Td.copy())\n    };\n    t.setTransform = function (a, b, c, d, e, f) {\n        1 === a && 0 === b && 0 === c && 1 === d && 0 === e && 0 === f || Xl(this, a, b, c, d, e, f)\n    };\n    t.scale = function (a, b) {\n        this.Td.scale(a, b)\n    };\n    t.translate = function (a, b) {\n        this.Td.translate(a, b)\n    };\n    t.transform = function () {};\n    t.stroke = function () {\n        this.addPath(\"stroke\", this.path, this.Td)\n    };\n    t.fj = function () {\n        this.clipInsteadOfFill || this.stroke()\n    };\n    t.tb = function (a, b, c) {\n        return this.yk.tb(a, b, c)\n    };\n    t.addElement = function (a, b, c) {\n        a = this.tb(a, b, c);\n        0 < this.xc.length ? this.xc[this.xc.length - 1].appendChild(a) : this.svg.appendChild(a);\n        return this.uq = a\n    };\n\n    function Yl(a, b, c, d, e) {\n        1 !== a.globalAlpha && (c.opacity = a.globalAlpha);\n        \"fill\" === b ? (a.fillStyle instanceof Vl ? c.fill = Zl(a, a.fillStyle) : (/^rgba\\(/.test(a.fillStyle) && (b = /^\\s*rgba\\s*\\(([^,\\s]+)\\s*,\\s*([^,\\s]+)\\s*,\\s*([^,\\s]+)\\s*,\\s*([^,\\s]+)\\)\\s*$/i.exec(a.fillStyle), c.fill = \"rgb(\" + b[1] + \",\" + b[2] + \",\" + b[3] + \")\", c[\"fill-opacity\"] = b[4]), c.fill = a.fillStyle), c.stroke = \"none\") : \"stroke\" === b && (c.fill = \"none\", a.strokeStyle instanceof Vl ? c.stroke = Zl(a, a.strokeStyle) : (/^rgba\\(/.test(a.strokeStyle) && (b = /^\\s*rgba\\s*\\(([^,\\s]+)\\s*,\\s*([^,\\s]+)\\s*,\\s*([^,\\s]+)\\s*,\\s*([^,\\s]+)\\)\\s*$/i.exec(a.strokeStyle),\n            c.stroke = \"rgb(\" + b[1] + \",\" + b[2] + \",\" + b[3] + \")\", c[\"stroke-opacity\"] = b[4]), c.stroke = a.strokeStyle), c[\"stroke-width\"] = a.lineWidth, c[\"stroke-linecap\"] = a.lineCap, c[\"stroke-linejoin\"] = a.lineJoin, c[\"stroke-miterlimit\"] = a.miterLimit);\n        a = d.Ka;\n        a = \"matrix(\" + a[0] + \", \" + a[1] + \", \" + a[2] + \", \" + a[3] + \", \" + a[4] + \", \" + a[5] + \")\";\n        void 0 !== e && (a += e);\n        c.transform = a\n    }\n\n    function Zl(a, b) {\n        var c = \"GRAD\" + pb++;\n        if (\"linear\" === b.type) var d = a.tb(\"linearGradient\", {\n            x1: b.x1,\n            x2: b.x2,\n            y1: b.y1,\n            y2: b.y2,\n            id: c,\n            gradientUnits: \"userSpaceOnUse\"\n        });\n        else if (\"radial\" === b.type) d = a.tb(\"radialGradient\", {\n            x1: b.x1,\n            x2: b.x2,\n            y1: b.y1,\n            y2: b.y2,\n            r1: b.r1,\n            r2: b.r2,\n            id: c\n        });\n        else throw Error(\"invalid gradient\");\n        var e = b.zx;\n        b = e.length;\n        for (var f = [], g = 0; g < b; g++) {\n            var h = e[g],\n                k = h.color;\n            h = {\n                offset: h.offset,\n                \"stop-color\": k\n            };\n            /^rgba\\(/.test(k) && (k = /^\\s*rgba\\s*\\(([^,\\s]+)\\s*,\\s*([^,\\s]+)\\s*,\\s*([^,\\s]+)\\s*,\\s*([^,\\s]+)\\)\\s*$/i.exec(k),\n                h[\"stop-color\"] = \"rgb(\" + k[1] + \",\" + k[2] + \",\" + k[3] + \")\", h[\"stop-opacity\"] = k[4]);\n            f.push(h)\n        }\n        f.sort(function (a, b) {\n            return a.offset > b.offset ? 1 : -1\n        });\n        for (e = 0; e < b; e++) d.appendChild(a.tb(\"stop\", f[e]));\n        a.svg.appendChild(d);\n        return \"url(#\" + c + \")\"\n    }\n    t.addPath = function (a, b, c) {\n        for (var d = [], e = 0; e < b.length; e++) {\n            var f = Ba(b[e]),\n                g = [f.shift()];\n            if (\"A\" === g[0]) g.push(f.shift() + \",\" + f.shift(), f.shift(), f.shift() + \",\" + f.shift(), f.shift() + \",\" + f.shift());\n            else\n                for (; f.length;) g.push(f.shift() + \",\" + f.shift());\n            d.push(g.join(\" \"))\n        }\n        b = {\n            d: d.join(\" \")\n        };\n        \"stroke\" === a && this.vu && (b[\"stroke-dasharray\"] = this.rh.toString(), b[\"stroke-dashoffset\"] = this.sh);\n        Yl(this, a, b, c);\n        \"clipPath\" === a ? (a = \"CLIP\" + pb++, c = this.tb(\"clipPath\", {\n                id: a\n            }), c.appendChild(this.tb(\"path\", b)), this.svg.appendChild(c),\n            0 < this.xc.length && this.xc[this.xc.length - 1].setAttributeNS(null, \"clip-path\", \"url(#\" + a + \")\")) : this.addElement(\"path\", b)\n    };\n\n    function Xl(a, b, c, d, e, f, g) {\n        var h = new Ul;\n        h.Ka = [b, c, d, e, f, g];\n        b = {};\n        Yl(a, \"g\", b, h);\n        h = a.addElement(\"g\", b);\n        a.xc.push(h)\n    }\n    t.Lq = function () {\n        if (0 !== this.shadowOffsetX || 0 !== this.shadowOffsetY || 0 !== this.shadowBlur) {\n            var a = \"SHADOW\" + pb++,\n                b = this.addElement(\"filter\", {\n                    id: a,\n                    x: \"-100%\",\n                    y: \"-100%\",\n                    width: \"300%\",\n                    height: \"300%\"\n                }, null);\n            var c = this.tb(\"feGaussianBlur\", {\n                \"in\": \"SourceAlpha\",\n                result: \"blur\",\n                KA: this.shadowBlur / 2\n            });\n            var d = this.tb(\"feFlood\", {\n                \"in\": \"blur\",\n                result: \"flood\",\n                \"flood-color\": this.shadowColor\n            });\n            var e = this.tb(\"feComposite\", {\n                \"in\": \"flood\",\n                in2: \"blur\",\n                operator: \"in\",\n                result: \"comp\"\n            });\n            var f = this.tb(\"feOffset\", {\n                \"in\": \"comp\",\n                result: \"offsetBlur\",\n                dx: this.shadowOffsetX,\n                dy: this.shadowOffsetY\n            });\n            var g = this.tb(\"feMerge\", {});\n            g.appendChild(this.tb(\"feMergeNode\", {\n                \"in\": \"offsetBlur\"\n            }));\n            g.appendChild(this.tb(\"feMergeNode\", {\n                \"in\": \"SourceGraphic\"\n            }));\n            b.appendChild(c);\n            b.appendChild(d);\n            b.appendChild(e);\n            b.appendChild(f);\n            b.appendChild(g);\n            0 < this.xc.length && this.xc[this.xc.length - 1].setAttributeNS(null, \"filter\", \"url(#\" + a + \")\")\n        }\n    };\n    t.jw = function (a, b, c) {\n        this.Fp = a;\n        this.Gp = b;\n        this.df = c\n    };\n\n    function sl(a) {\n        a.shadowOffsetX = 0;\n        a.shadowOffsetY = 0;\n        a.shadowBlur = 0\n    }\n\n    function rl(a) {\n        a.shadowOffsetX = a.Fp;\n        a.shadowOffsetY = a.Gp;\n        a.shadowBlur = a.df\n    }\n    t.ht = function (a, b) {\n        this.vu = !0;\n        this.rh = a;\n        this.sh = b\n    };\n    t.ft = function () {\n        this.vu = !1\n    };\n    t.sc = function () {};\n    t.ky = function () {};\n    Wl.prototype.rotate = function () {};\n    Wl.prototype.getImageData = function () {\n        return null\n    };\n    Wl.prototype.measureText = function () {\n        return null\n    };\n    Wl.className = \"SVGContext\";\n    R.prototype.At = function (a) {\n        var b = new Aj(this, x.document);\n        void 0 === a && (a = new db);\n        var c = this;\n        return Ak(this, function (a, e) {\n            a = Bk(c, a, \"SVG\", b);\n            a = null !== a ? a.svg : null;\n            return \"function\" === typeof e ? (e(a), null) : a\n        }, a)\n    };\n    R.prototype.makeSvg = R.prototype.At;\n    R.prototype.Kv = function (a) {\n        return this.At(a)\n    };\n    R.prototype.makeSVG = R.prototype.Kv;\n    Y.prototype.Gx = function (a, b) {\n        if (!(a instanceof Wl)) return !1;\n        if (!this.visible) return !0;\n        var c = null,\n            d = a.uq;\n        if (this instanceof X && (this.type === X.TableRow || this.type === X.TableColumn)) return pl(this, a, b), !0;\n        var e = this.ub;\n        if (0 === e.width || 0 === e.height || isNaN(e.x) || isNaN(e.y)) return !0;\n        var f = this.transform,\n            g = this.panel;\n        0 !== (this.F & 4096) === !0 && ql(this);\n        var h = 0 !== (this.F & 256),\n            k = !1;\n        this instanceof Wg && (a.font = this.font);\n        if (h) {\n            k = g.$d() ? g.naturalBounds : g.actualBounds;\n            if (null !== this.ld) {\n                var l = this.ld;\n                var m = l.x;\n                var n =\n                    l.y;\n                var p = l.width;\n                l = l.height\n            } else m = Math.max(e.x, k.x), n = Math.max(e.y, k.y), p = Math.min(e.right, k.right) - m, l = Math.min(e.bottom, k.bottom) - n;\n            if (m > e.width + e.x || e.x > k.width + k.x || n > e.height + e.y || e.y > k.height + k.y) return !0;\n            k = !0;\n            Xl(a, 1, 0, 0, 1, 0, 0);\n            a.save();\n            a.beginPath();\n            a.rect(m, n, p, l);\n            a.clip()\n        }\n        if (this.xf() && !this.isVisible()) return !0;\n        a.Td.Ka = [1, 0, 0, 1, 0, 0];\n        (this instanceof Wg && 1 < this.lineCount || this instanceof Lf && 1 < this.geometry.figures.length) && Xl(a, 1, 0, 0, 1, 0, 0);\n        m = !1;\n        this.xf() && this.isShadowed && b.Be(\"drawShadows\") &&\n            (n = this.shadowOffset, a.jw(n.x * b.scale * b.Sb, n.y * b.scale * b.Sb, this.shadowBlur), rl(a), a.shadowColor = this.shadowColor);\n        n = !1;\n        this.part && b.Be(\"drawShadows\") && (n = this.part.isShadowed);\n        !0 === this.shadowVisible ? (rl(a), !1 === m && n && (Xl(a, 1, 0, 0, 1, 0, 0), a.Lq(), m = !0)) : !1 === this.shadowVisible && sl(a);\n        p = this.naturalBounds;\n        null !== this.areaBackground && (ii(this, a, this.areaBackground, !0, !0, p, e), !1 === m && n && (Xl(a, 1, 0, 0, 1, 0, 0), a.Lq(), m = !0), this.areaBackground instanceof tl && this.areaBackground.type === ul ? (a.beginPath(), a.rect(e.x,\n            e.y, e.width, e.height), a.Ud(this.areaBackground)) : a.fillRect(e.x, e.y, e.width, e.height));\n        this instanceof X ? Xl(a, f.m11, f.m12, f.m21, f.m22, f.dx, f.dy) : a.Td.Ka = [f.m11, f.m12, f.m21, f.m22, f.dx, f.dy];\n        if (null !== this.background) {\n            !1 === m && n && (Xl(a, 1, 0, 0, 1, 0, 0), a.Lq(), m = !0);\n            var r = this.naturalBounds;\n            l = f = 0;\n            var q = r.width;\n            r = r.height;\n            var u = 0;\n            this instanceof Lf && (r = this.geometry.bounds, f = r.x, l = r.y, q = r.width, r = r.height, u = this.strokeWidth);\n            ii(this, a, this.background, !0, !1, p, e);\n            this.background instanceof tl && this.background.type ===\n                ul ? (a.beginPath(), a.rect(f - u / 2, l - u / 2, q + u, r + u), a.Ud(this.background)) : a.fillRect(f - u / 2, l - u / 2, q + u, r + u)\n        }\n        n && (null !== this.background || null !== this.areaBackground || null !== g && 0 !== (g.F & 512) || null !== g && (g.type === X.Auto || g.type === X.Spot) && g.zb() !== this) ? (vl(this, !0), null === this.shadowVisible && sl(a)) : vl(this, !1);\n        this.Qi(a, b);\n        n && 0 !== (this.F & 512) === !0 && rl(a);\n        this.xf() && n && sl(a);\n        h && (a.restore(), k && a.xc.pop());\n        this instanceof X && (c = a.xc.pop());\n        !0 === m && a.xc.pop();\n        if (this instanceof Wg && 1 < this.lineCount || this instanceof Lf && 1 < this.geometry.figures.length) c = a.xc.pop();\n        null !== a.yk.jq && (null === c && (d === a.uq ? (Xl(a, 1, 0, 0, 1, 0, 0), c = a.xc.pop()) : c = a.uq), a.yk.jq(this, c));\n        this.svg = c;\n        return !0\n    };\n\n    function Ck(a, b) {\n        this.ownerDocument = b = void 0 === b ? x.document : b;\n        this.jq = null;\n        b = b.createElement(\"canvas\");\n        b.tabIndex = 0;\n        this.Ea = b;\n        this.Ea.innerHTML = \"This text is displayed if your browser does not support the Canvas HTML element.\";\n        this.context = new xl(b);\n        b.B = a\n    }\n    Ck.prototype.resize = function (a, b, c, d) {\n        return this.width !== a || this.height !== b ? (this.width = a, this.height = b, this.style.width = c + \"px\", this.style.height = d + \"px\", !0) : !1\n    };\n    Ck.prototype.toDataURL = function (a, b) {\n        return this.Ea.toDataURL(a, b)\n    };\n    Ck.prototype.getBoundingClientRect = function () {\n        return this.Ea.getBoundingClientRect()\n    };\n    Ck.prototype.focus = function () {\n        this.Ea.focus()\n    };\n    Ck.prototype.Fx = function () {\n        this.ownerDocument = this.Ea.B = null\n    };\n    ma.Object.defineProperties(Ck.prototype, {\n        width: {\n            get: function () {\n                return this.Ea.width\n            },\n            set: function (a) {\n                this.Ea.width = a\n            }\n        },\n        height: {\n            get: function () {\n                return this.Ea.height\n            },\n            set: function (a) {\n                this.Ea.height = a\n            }\n        },\n        style: {\n            get: function () {\n                return this.Ea.style\n            }\n        }\n    });\n    Ck.className = \"CanvasSurface\";\n\n    function xl(a) {\n        a.getContext && a.getContext(\"2d\") || B(\"Browser does not support HTML Canvas Element\");\n        this.V = a.getContext(\"2d\");\n        this.Yt = this.$t = this.Zt = \"\";\n        this.fn = !1;\n        this.df = this.Gp = this.Fp = 0\n    }\n    t = xl.prototype;\n    t.ky = function (a) {\n        this.V.imageSmoothingEnabled = a\n    };\n    t.arc = function (a, b, c, d, e, f) {\n        this.V.arc(a, b, c, d, e, f)\n    };\n    t.beginPath = function () {\n        this.V.beginPath()\n    };\n    t.bezierCurveTo = function (a, b, c, d, e, f) {\n        this.V.bezierCurveTo(a, b, c, d, e, f)\n    };\n    t.clearRect = function (a, b, c, d) {\n        this.V.clearRect(a, b, c, d)\n    };\n    t.clip = function () {\n        this.V.clip()\n    };\n    t.closePath = function () {\n        this.V.closePath()\n    };\n    t.createLinearGradient = function (a, b, c, d) {\n        return this.V.createLinearGradient(a, b, c, d)\n    };\n    t.createPattern = function (a, b) {\n        return this.V.createPattern(a, b)\n    };\n    t.createRadialGradient = function (a, b, c, d, e, f) {\n        return this.V.createRadialGradient(a, b, c, d, e, f)\n    };\n    t.drawImage = function (a, b, c, d, e, f, g, h, k) {\n        void 0 === d ? this.V.drawImage(a, b, c) : this.V.drawImage(a, b, c, d, e, f, g, h, k)\n    };\n    t.fill = function () {\n        this.V.fill()\n    };\n    t.fillRect = function (a, b, c, d) {\n        this.V.fillRect(a, b, c, d)\n    };\n    t.fillText = function (a, b, c) {\n        this.V.fillText(a, b, c)\n    };\n    t.getImageData = function (a, b, c, d) {\n        return this.V.getImageData(a, b, c, d)\n    };\n    t.lineTo = function (a, b) {\n        this.V.lineTo(a, b)\n    };\n    t.measureText = function (a) {\n        return this.V.measureText(a)\n    };\n    t.moveTo = function (a, b) {\n        this.V.moveTo(a, b)\n    };\n    t.quadraticCurveTo = function (a, b, c, d) {\n        this.V.quadraticCurveTo(a, b, c, d)\n    };\n    t.rect = function (a, b, c, d) {\n        this.V.rect(a, b, c, d)\n    };\n    t.restore = function () {\n        this.V.restore()\n    };\n    xl.prototype.rotate = function (a) {\n        this.V.rotate(a)\n    };\n    t = xl.prototype;\n    t.save = function () {\n        this.V.save()\n    };\n    t.setTransform = function (a, b, c, d, e, f) {\n        this.V.setTransform(a, b, c, d, e, f)\n    };\n    t.scale = function (a, b) {\n        this.V.scale(a, b)\n    };\n    t.stroke = function () {\n        this.V.stroke()\n    };\n    t.transform = function (a, b, c, d, e, f) {\n        1 === a && 0 === b && 0 === c && 1 === d && 0 === e && 0 === f || this.V.transform(a, b, c, d, e, f)\n    };\n    t.translate = function (a, b) {\n        this.V.translate(a, b)\n    };\n    t.Ud = function (a) {\n        if (a instanceof tl && a.type === ul) {\n            var b = a.Mk;\n            a = a.au;\n            a > b ? (this.scale(b / a, 1), this.translate((a - b) / 2, 0)) : b > a && (this.scale(1, a / b), this.translate(0, (b - a) / 2));\n            this.fn ? this.clip() : this.fill();\n            a > b ? (this.translate(-(a - b) / 2, 0), this.scale(1 / (b / a), 1)) : b > a && (this.translate(0, -(b - a) / 2), this.scale(1, 1 / (a / b)))\n        } else this.fn ? this.clip() : this.fill()\n    };\n    t.fj = function () {\n        this.fn || this.stroke()\n    };\n    t.jw = function (a, b, c) {\n        this.Fp = a;\n        this.Gp = b;\n        this.df = c\n    };\n    t.ht = function (a, b) {\n        var c = this.V;\n        void 0 !== c.setLineDash && (c.setLineDash(a), c.lineDashOffset = b)\n    };\n    t.ft = function () {\n        var a = this.V;\n        void 0 !== a.setLineDash && (a.setLineDash($l), a.lineDashOffset = 0)\n    };\n    t.sc = function (a) {\n        a && (this.Zt = \"\");\n        this.Yt = this.$t = \"\"\n    };\n    ma.Object.defineProperties(xl.prototype, {\n        fillStyle: {\n            get: function () {\n                return this.V.fillStyle\n            },\n            set: function (a) {\n                this.Yt !== a && (this.Yt = this.V.fillStyle = a)\n            }\n        },\n        font: {\n            get: function () {\n                return this.V.font\n            },\n            set: function (a) {\n                this.Zt !== a && (this.Zt = this.V.font = a)\n            }\n        },\n        globalAlpha: {\n            get: function () {\n                return this.V.globalAlpha\n            },\n            set: function (a) {\n                this.V.globalAlpha = a\n            }\n        },\n        lineCap: {\n            get: function () {\n                return this.V.lineCap\n            },\n            set: function (a) {\n                this.V.lineCap = a\n            }\n        },\n        lineDashOffset: {\n            get: function () {\n                return this.V.lineDashOffset\n            },\n            set: function (a) {\n                this.V.lineDashOffset = a\n            }\n        },\n        lineJoin: {\n            get: function () {\n                return this.V.lineJoin\n            },\n            set: function (a) {\n                this.V.lineJoin = a\n            }\n        },\n        lineWidth: {\n            get: function () {\n                return this.V.lineWidth\n            },\n            set: function (a) {\n                this.V.lineWidth = a\n            }\n        },\n        miterLimit: {\n            get: function () {\n                return this.V.miterLimit\n            },\n            set: function (a) {\n                this.V.miterLimit =\n                    a\n            }\n        },\n        shadowBlur: {\n            get: function () {\n                return this.V.shadowBlur\n            },\n            set: function (a) {\n                this.V.shadowBlur = a\n            }\n        },\n        shadowColor: {\n            get: function () {\n                return this.V.shadowColor\n            },\n            set: function (a) {\n                this.V.shadowColor = a\n            }\n        },\n        shadowOffsetX: {\n            get: function () {\n                return this.V.shadowOffsetX\n            },\n            set: function (a) {\n                this.V.shadowOffsetX = a\n            }\n        },\n        shadowOffsetY: {\n            get: function () {\n                return this.V.shadowOffsetY\n            },\n            set: function (a) {\n                this.V.shadowOffsetY =\n                    a\n            }\n        },\n        strokeStyle: {\n            get: function () {\n                return this.V.strokeStyle\n            },\n            set: function (a) {\n                this.$t !== a && (this.$t = this.V.strokeStyle = a)\n            }\n        },\n        textAlign: {\n            get: function () {\n                return this.V.textAlign\n            },\n            set: function (a) {\n                this.V.textAlign = a\n            }\n        },\n        imageSmoothingEnabled: {\n            get: function () {\n                return this.V.imageSmoothingEnabled\n            },\n            set: function (a) {\n                this.V.imageSmoothingEnabled = a\n            }\n        },\n        clipInsteadOfFill: {\n            get: function () {\n                return this.fn\n            },\n            set: function (a) {\n                this.fn = a\n            }\n        }\n    });\n    var $l = Object.freeze([]);\n    xl.className = \"CanvasSurfaceContext\";\n\n    function am() {\n        this.Y = this.u = this.I = this.l = 0\n    }\n    am.className = \"ColorNumbers\";\n\n    function tl(a) {\n        bm || (cm(), bm = !0);\n        Ya(this);\n        this.s = !1;\n        void 0 === a ? (this.pa = wl, this.Lk = \"black\") : \"string\" === typeof a ? (this.pa = wl, this.Lk = a) : (this.pa = a, this.Lk = \"black\");\n        a = this.pa;\n        a === zl ? (this.td = xc, this.Yk = Fc) : this.Yk = a === ul ? this.td = Ac : this.td = uc;\n        this.Os = 0;\n        this.Br = NaN;\n        this.ce = this.rs = this.be = null;\n        this.au = this.Mk = 0\n    }\n    tl.prototype.copy = function () {\n        var a = new tl;\n        a.pa = this.pa;\n        a.Lk = this.Lk;\n        a.td = this.td.G();\n        a.Yk = this.Yk.G();\n        a.Os = this.Os;\n        a.Br = this.Br;\n        null !== this.be && (a.be = this.be.copy());\n        a.rs = this.rs;\n        return a\n    };\n    t = tl.prototype;\n    t.freeze = function () {\n        this.s = !0;\n        null !== this.be && this.be.freeze();\n        return this\n    };\n    t.ea = function () {\n        Object.isFrozen(this) && B(\"cannot thaw constant: \" + this);\n        this.s = !1;\n        null !== this.be && this.be.ea();\n        return this\n    };\n    t.cb = function (a) {\n        a.classType === tl && (this.type = a)\n    };\n    t.toString = function () {\n        var a = \"Brush(\";\n        if (this.type === wl) a += this.color;\n        else if (a = this.type === zl ? a + \"Linear \" : this.type === ul ? a + \"Radial \" : this.type === yl ? a + \"Pattern \" : a + \"(unknown) \", a += this.start + \" \" + this.end, null !== this.colorStops)\n            for (var b = this.colorStops.iterator; b.next();) a += \" \" + b.key + \":\" + b.value;\n        return a + \")\"\n    };\n    t.addColorStop = function (a, b) {\n        this.s && ua(this);\n        (\"number\" !== typeof a || !isFinite(a) || 1 < a || 0 > a) && va(a, \"0 <= loc <= 1\", tl, \"addColorStop:loc\");\n        null === this.be && (this.be = new H);\n        this.be.add(a, b);\n        this.pa === wl && (this.type = zl);\n        this.ce = null;\n        return this\n    };\n    t.bA = function (a, b) {\n        this.s && ua(this);\n        a = void 0 === a || \"number\" !== typeof a ? .2 : a;\n        b = void 0 === b ? dm : b;\n        if (this.type === wl) Qh(this.color), this.color = em(a, b);\n        else if ((this.type === zl || this.type === ul) && null !== this.colorStops)\n            for (var c = this.colorStops.iterator; c.next();) Qh(c.value), this.addColorStop(c.key, em(a, b));\n        return this\n    };\n\n    function fm(a, b, c) {\n        b = void 0 === b || \"number\" !== typeof b ? .2 : b;\n        c = void 0 === c ? dm : c;\n        Qh(a);\n        return em(b, c)\n    }\n    t.Yy = function (a, b) {\n        this.s && ua(this);\n        a = void 0 === a || \"number\" !== typeof a ? .2 : a;\n        b = void 0 === b ? dm : b;\n        if (this.type === wl) Qh(this.color), this.color = em(-a, b);\n        else if ((this.type === zl || this.type === ul) && null !== this.colorStops)\n            for (var c = this.colorStops.iterator; c.next();) Qh(c.value), this.addColorStop(c.key, em(-a, b));\n        return this\n    };\n\n    function gm(a, b, c) {\n        b = void 0 === b || \"number\" !== typeof b ? .2 : b;\n        c = void 0 === c ? dm : c;\n        Qh(a);\n        return em(-b, c)\n    }\n\n    function hm(a, b, c) {\n        Qh(a);\n        a = im.l;\n        var d = im.I,\n            e = im.u,\n            f = im.Y;\n        Qh(b);\n        void 0 === c && (c = .5);\n        return \"rgba(\" + Math.round((im.l - a) * c + a) + \", \" + Math.round((im.I - d) * c + d) + \", \" + Math.round((im.u - e) * c + e) + \", \" + Math.round((im.Y - f) * c + f) + \")\"\n    }\n    t.Tx = function () {\n        if (this.type === wl) return jm(this.color);\n        if ((this.type === zl || this.type === ul) && null !== this.colorStops) {\n            var a = this.colorStops;\n            if (this.type === ul) return jm(a.first().value);\n            if (null !== a.get(.5)) return jm(a.get(.5));\n            if (2 === a.count) return a = a.na(), jm(hm(a[0].value, a[1].value));\n            for (var b = a.iterator, c = -1, d = -1, e = 1, f = 1; b.next();) {\n                var g = b.key,\n                    h = Math.abs(.5 - b.key);\n                e > f && h < e ? (c = g, e = h) : f >= e && h < f && (d = g, f = h)\n            }\n            c > d && (f = c, c = d, d = f, f = e);\n            e = d - c;\n            return jm(hm(a.get(c), a.get(d), 1 - f / e))\n        }\n        return !1\n    };\n\n    function jm(a) {\n        if (null === a) return null;\n        if (a instanceof tl) return a.Tx();\n        Qh(a);\n        return 128 > (299 * im.l + 587 * im.I + 114 * im.u) / 1E3\n    }\n\n    function em(a, b) {\n        switch (b) {\n            case dm:\n                b = 100 * km(im.l);\n                var c = 100 * km(im.I),\n                    d = 100 * km(im.u);\n                lm.l = .4124564 * b + .3575761 * c + .1804375 * d;\n                lm.I = .2126729 * b + .7151522 * c + .072175 * d;\n                lm.u = .0193339 * b + .119192 * c + .9503041 * d;\n                lm.Y = im.Y;\n                b = mm(lm.l / nm[0]);\n                c = mm(lm.I / nm[1]);\n                d = mm(lm.u / nm[2]);\n                om.l = 116 * c - 16;\n                om.I = 500 * (b - c);\n                om.u = 200 * (c - d);\n                om.Y = lm.Y;\n                om.l = Math.min(100, Math.max(0, om.l + 100 * a));\n                a = (om.l + 16) / 116;\n                b = a - om.u / 200;\n                lm.l = nm[0] * pm(om.I / 500 + a);\n                lm.I = nm[1] * (om.l > qm * rm ? Math.pow(a, 3) : om.l / qm);\n                lm.u = nm[2] * pm(b);\n                lm.Y = om.Y;\n                a = -.969266 * lm.l + 1.8760108 *\n                    lm.I + .041556 * lm.u;\n                b = .0556434 * lm.l + -.2040259 * lm.I + 1.0572252 * lm.u;\n                im.l = 255 * sm((3.2404542 * lm.l + -1.5371385 * lm.I + -.4985314 * lm.u) / 100);\n                im.I = 255 * sm(a / 100);\n                im.u = 255 * sm(b / 100);\n                im.Y = lm.Y;\n                im.l = Math.round(im.l);\n                255 < im.l ? im.l = 255 : 0 > im.l && (im.l = 0);\n                im.I = Math.round(im.I);\n                255 < im.I ? im.I = 255 : 0 > im.I && (im.I = 0);\n                im.u = Math.round(im.u);\n                255 < im.u ? im.u = 255 : 0 > im.u && (im.u = 0);\n                return \"rgba(\" + im.l + \", \" + im.I + \", \" + im.u + \", \" + im.Y + \")\";\n            case tm:\n                return Rh(), Sh.u = Math.min(100, Math.max(0, Sh.u + 100 * a)), \"hsla(\" + Sh.l + \", \" + Sh.I + \"%, \" + Sh.u + \"%, \" +\n                    Sh.Y + \")\";\n            default:\n                return B(\"Unknown color space: \" + b), \"rgba(0, 0, 0, 1)\"\n        }\n    }\n\n    function Qh(a) {\n        bm || (cm(), bm = !0);\n        var b = um;\n        if (null !== b) {\n            b.clearRect(0, 0, 1, 1);\n            b.fillStyle = \"#000000\";\n            var c = b.fillStyle;\n            b.fillStyle = a;\n            b.fillStyle !== c ? (b.fillRect(0, 0, 1, 1), a = b.getImageData(0, 0, 1, 1).data, im.l = a[0], im.I = a[1], im.u = a[2], im.Y = a[3] / 255) : (b.fillStyle = \"#FFFFFF\", b.fillStyle = a, im.l = 0, im.I = 0, im.u = 0, im.Y = 1)\n        }\n    }\n\n    function Rh() {\n        var a = im.l / 255,\n            b = im.I / 255,\n            c = im.u / 255,\n            d = Math.max(a, b, c),\n            e = Math.min(a, b, c),\n            f = d - e;\n        e = (d + e) / 2;\n        if (0 === f) var g = a = 0;\n        else {\n            switch (d) {\n                case a:\n                    g = (b - c) / f % 6;\n                    break;\n                case b:\n                    g = (c - a) / f + 2;\n                    break;\n                case c:\n                    g = (a - b) / f + 4\n            }\n            g *= 60;\n            0 > g && (g += 360);\n            a = f / (1 - Math.abs(2 * e - 1))\n        }\n        Sh.l = Math.round(g);\n        Sh.I = Math.round(100 * a);\n        Sh.u = Math.round(100 * e);\n        Sh.Y = im.Y\n    }\n\n    function km(a) {\n        a /= 255;\n        return .04045 >= a ? a / 12.92 : Math.pow((a + .055) / 1.055, 2.4)\n    }\n\n    function sm(a) {\n        return .0031308 >= a ? 12.92 * a : 1.055 * Math.pow(a, 1 / 2.4) - .055\n    }\n\n    function mm(a) {\n        return a > rm ? Math.pow(a, 1 / 3) : (qm * a + 16) / 116\n    }\n\n    function pm(a) {\n        var b = a * a * a;\n        return b > rm ? b : (116 * a - 16) / qm\n    }\n\n    function Rl(a, b) {\n        \"string\" !== typeof a && (a instanceof tl || B(\"Value for \" + b + \" must be a color string or a Brush, not \" + a))\n    }\n\n    function cm() {\n        um = Ug ? (new Ck(null)).context : null\n    }\n    ma.Object.defineProperties(tl.prototype, {\n        type: {\n            get: function () {\n                return this.pa\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.pa = a;\n                this.start.jc() && (a === zl ? this.start = xc : a === ul && (this.start = Ac));\n                this.end.jc() && (a === zl ? this.end = Fc : a === ul && (this.end = Ac));\n                this.ce = null\n            }\n        },\n        color: {\n            get: function () {\n                return this.Lk\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.Lk = a;\n                this.ce = null\n            }\n        },\n        start: {\n            get: function () {\n                return this.td\n            },\n            set: function (a) {\n                this.s &&\n                    ua(this, a);\n                this.td = a.G();\n                this.ce = null\n            }\n        },\n        end: {\n            get: function () {\n                return this.Yk\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.Yk = a.G();\n                this.ce = null\n            }\n        },\n        startRadius: {\n            get: function () {\n                return this.Os\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                0 > a && va(a, \">= zero\", tl, \"startRadius\");\n                this.Os = a;\n                this.ce = null\n            }\n        },\n        endRadius: {\n            get: function () {\n                return this.Br\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                0 > a && va(a, \">= zero\", tl, \"endRadius\");\n                this.Br = a;\n                this.ce =\n                    null\n            }\n        },\n        colorStops: {\n            get: function () {\n                return this.be\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.be = a;\n                this.ce = null\n            }\n        },\n        pattern: {\n            get: function () {\n                return this.rs\n            },\n            set: function (a) {\n                this.s && ua(this, a);\n                this.rs = a;\n                this.ce = null\n            }\n        }\n    });\n    tl.prototype.isDark = tl.prototype.Tx;\n    tl.prototype.darkenBy = tl.prototype.Yy;\n    tl.prototype.lightenBy = tl.prototype.bA;\n    tl.prototype.addColorStop = tl.prototype.addColorStop;\n    var rm = 216 / 24389,\n        qm = 24389 / 27,\n        nm = [95.047, 100, 108.883],\n        um = null,\n        im = new am,\n        Sh = new am,\n        lm = new am,\n        om = new am,\n        bm = !1;\n    tl.className = \"Brush\";\n    var wl;\n    tl.Solid = wl = new D(tl, \"Solid\", 0);\n    var zl;\n    tl.Linear = zl = new D(tl, \"Linear\", 1);\n    var ul;\n    tl.Radial = ul = new D(tl, \"Radial\", 2);\n    var yl;\n    tl.Pattern = yl = new D(tl, \"Pattern\", 4);\n    var dm;\n    tl.Lab = dm = new D(tl, \"Lab\", 5);\n    var tm;\n    tl.HSL = tm = new D(tl, \"HSL\", 6);\n    tl.randomColor = function (a, b) {\n        void 0 === a && (a = 128);\n        void 0 === b && (b = Math.max(a, 255));\n        var c = Math.abs(b - a);\n        b = Math.floor(a + Math.random() * c).toString(16);\n        var d = Math.floor(a + Math.random() * c).toString(16);\n        a = Math.floor(a + Math.random() * c).toString(16);\n        2 > b.length && (b = \"0\" + b);\n        2 > d.length && (d = \"0\" + d);\n        2 > a.length && (a = \"0\" + a);\n        return \"#\" + b + d + a\n    };\n    tl.isValidColor = function (a) {\n        if (\"black\" === a) return !0;\n        if (\"\" === a) return !1;\n        bm || (cm(), bm = !0);\n        var b = um;\n        if (null === b) return !0;\n        b.fillStyle = \"#000000\";\n        var c = b.fillStyle;\n        b.fillStyle = a;\n        if (b.fillStyle !== c) return !0;\n        b.fillStyle = \"#FFFFFF\";\n        c = b.fillStyle;\n        b.fillStyle = a;\n        return b.fillStyle !== c\n    };\n    tl.lighten = function (a) {\n        return fm(a)\n    };\n    tl.lightenBy = fm;\n    tl.darken = function (a) {\n        return gm(a)\n    };\n    tl.darkenBy = gm;\n    tl.mix = hm;\n    tl.isDark = jm;\n\n    function Ol() {\n        this.name = \"Base\"\n    }\n    Ol.prototype.measure = function () {};\n    Ol.prototype.eA = function (a, b, c, d, e) {\n        a.measure(b, c, d, e)\n    };\n    Ol.prototype.arrange = function () {};\n    Ol.prototype.Oy = function (a, b, c, d, e, f) {\n        a.arrange(b, c, d, e, f)\n    };\n    Ol.prototype.bc = function () {};\n    ma.Object.defineProperties(Ol.prototype, {\n        classType: {\n            get: function () {\n                return X\n            }\n        }\n    });\n    Ol.prototype.arrangeElement = Ol.prototype.Oy;\n    Ol.prototype.measureElement = Ol.prototype.eA;\n    Ol.className = \"PanelLayout\";\n\n    function vm() {\n        this.name = \"Base\";\n        this.name = \"Position\"\n    }\n    la(vm, Ol);\n    vm.prototype.measure = function (a, b, c, d, e, f, g) {\n        var h = d.length;\n        a = wm(a);\n        for (var k = 0; k < h; k++) {\n            var l = d[k];\n            if (l.visible || l === a) {\n                var m = l.margin,\n                    n = m.right + m.left;\n                m = m.top + m.bottom;\n                l.measure(b, c, f, g);\n                var p = l.measuredBounds;\n                n = Math.max(p.width + n, 0);\n                m = Math.max(p.height + m, 0);\n                p = l.position.x;\n                var r = l.position.y;\n                isFinite(p) || (p = 0);\n                isFinite(r) || (r = 0);\n                l instanceof Lf && l.isGeometryPositioned && (l = l.strokeWidth / 2, p -= l, r -= l);\n                ec(e, p, r, n, m)\n            }\n        }\n    };\n    vm.prototype.arrange = function (a, b, c) {\n        var d = b.length,\n            e = a.padding;\n        a = c.x - e.left;\n        c = c.y - e.top;\n        for (e = 0; e < d; e++) {\n            var f = b[e],\n                g = f.measuredBounds,\n                h = f.margin,\n                k = f.position.x,\n                l = f.position.y;\n            k = isNaN(k) ? -a : k - a;\n            l = isNaN(l) ? -c : l - c;\n            if (f instanceof Lf && f.isGeometryPositioned) {\n                var m = f.strokeWidth / 2;\n                k -= m;\n                l -= m\n            }\n            f.visible && f.arrange(k + h.left, l + h.top, g.width, g.height)\n        }\n    };\n\n    function xm() {\n        this.name = \"Base\";\n        this.name = \"Horizontal\"\n    }\n    la(xm, Ol);\n    xm.prototype.measure = function (a, b, c, d, e, f, g) {\n        var h = d.length;\n        b = Fa();\n        f = wm(a);\n        for (var k = 0; k < h; k++) {\n            var l = d[k];\n            if (l.visible || l === f) {\n                var m = kl(l, !1);\n                if (m !== zg && m !== Wk) b.push(l);\n                else {\n                    l.measure(Infinity, c, 0, g);\n                    m = l.margin;\n                    l = l.measuredBounds;\n                    var n = Math.max(l.height + m.top + m.bottom, 0);\n                    e.width += Math.max(l.width + m.right + m.left, 0);\n                    e.height = Math.max(e.height, n)\n                }\n            }\n        }\n        d = b.length;\n        a.desiredSize.height ? c = Math.min(a.desiredSize.height, a.maxSize.height) : 0 !== e.height && (c = Math.min(e.height, a.maxSize.height));\n        for (a = 0; a < d; a++)\n            if (k =\n                b[a], k.visible || k === f) m = k.margin, h = m.right + m.left, m = m.top + m.bottom, k.measure(Infinity, c, 0, g), k = k.measuredBounds, m = Math.max(k.height + m, 0), e.width += Math.max(k.width + h, 0), e.height = Math.max(e.height, m);\n        Ha(b)\n    };\n    xm.prototype.arrange = function (a, b, c) {\n        for (var d = b.length, e = a.padding, f = e.top, g = a.isOpposite, h = g ? c.width : e.left, k = 0; k < d; k++) {\n            var l = f,\n                m = b[k];\n            if (m.visible) {\n                var n = m.measuredBounds,\n                    p = m.margin,\n                    r = p.top + p.bottom,\n                    q = f + e.bottom,\n                    u = n.height,\n                    v = kl(m, !1);\n                if (isNaN(m.desiredSize.height) && v === vd || v === Xk) u = Math.max(c.height - r - q, 0);\n                r = u + r + q;\n                q = m.alignment;\n                q.Mb() && (q = a.defaultAlignment);\n                q.eb() || (q = Ac);\n                g && (h -= n.width + p.left + p.right);\n                m.arrange(h + q.offsetX + p.left, l + q.offsetY + p.top + (c.height * q.y - r * q.y), n.width, u);\n                g || (h += n.width +\n                    p.left + p.right)\n            }\n        }\n    };\n\n    function ym() {\n        this.name = \"Base\";\n        this.name = \"Vertical\"\n    }\n    la(ym, Ol);\n    ym.prototype.measure = function (a, b, c, d, e, f) {\n        var g = d.length;\n        c = Fa();\n        for (var h = wm(a), k = 0; k < g; k++) {\n            var l = d[k];\n            if (l.visible || l === h) {\n                var m = kl(l, !1);\n                if (m !== zg && m !== Xk) c.push(l);\n                else {\n                    var n = l.margin;\n                    m = n.right + n.left;\n                    n = n.top + n.bottom;\n                    l.measure(b, Infinity, f, 0);\n                    l = l.measuredBounds;\n                    Vb(e, Math.max(e.width, Math.max(l.width + m, 0)), e.height + Math.max(l.height + n, 0))\n                }\n            }\n        }\n        d = c.length;\n        if (0 !== d) {\n            a.desiredSize.width ? b = Math.min(a.desiredSize.width, a.maxSize.width) : 0 !== e.width && (b = Math.min(e.width, a.maxSize.width));\n            for (a = 0; a < d; a++)\n                if (k =\n                    c[a], k.visible || k === h) l = k.margin, g = l.right + l.left, l = l.top + l.bottom, k.measure(b, Infinity, f, 0), k = k.measuredBounds, l = Math.max(k.height + l, 0), e.width = Math.max(e.width, Math.max(k.width + g, 0)), e.height += l;\n            Ha(c)\n        }\n    };\n    ym.prototype.arrange = function (a, b, c) {\n        for (var d = b.length, e = a.padding, f = e.left, g = a.isOpposite, h = g ? c.height : e.top, k = 0; k < d; k++) {\n            var l = f,\n                m = b[k];\n            if (m.visible) {\n                var n = m.measuredBounds,\n                    p = m.margin,\n                    r = p.left + p.right,\n                    q = f + e.right,\n                    u = n.width,\n                    v = kl(m, !1);\n                if (isNaN(m.desiredSize.width) && v === vd || v === Wk) u = Math.max(c.width - r - q, 0);\n                r = u + r + q;\n                q = m.alignment;\n                q.Mb() && (q = a.defaultAlignment);\n                q.eb() || (q = Ac);\n                g && (h -= n.height + p.bottom + p.top);\n                m.arrange(l + q.offsetX + p.left + (c.width * q.x - r * q.x), h + q.offsetY + p.top, u, n.height);\n                g || (h += n.height +\n                    p.bottom + p.top)\n            }\n        }\n    };\n\n    function zm() {\n        this.name = \"Base\";\n        this.name = \"Spot\"\n    }\n    la(zm, Ol);\n    zm.prototype.measure = function (a, b, c, d, e, f, g) {\n        var h = d.length,\n            k = a.zb(),\n            l = k.margin,\n            m = l.right + l.left,\n            n = l.top + l.bottom;\n        k.measure(b, c, f, g);\n        var p = k.measuredBounds;\n        f = p.width;\n        g = p.height;\n        var r = Math.max(f + m, 0);\n        var q = Math.max(g + n, 0);\n        for (var u = a.isClipping, v = N.allocAt(-l.left, -l.top, r, q), w = !0, y = wm(a), z = 0; z < h; z++) {\n            var A = d[z];\n            if (A !== k && (A.visible || A === y)) {\n                l = A.margin;\n                r = l.right + l.left;\n                q = l.top + l.bottom;\n                p = kl(A, !1);\n                switch (p) {\n                    case vd:\n                        b = f;\n                        c = g;\n                        break;\n                    case Wk:\n                        b = f;\n                        break;\n                    case Xk:\n                        c = g\n                }\n                A.measure(b, c, 0, 0);\n                p = A.measuredBounds;\n                r =\n                    Math.max(p.width + r, 0);\n                q = Math.max(p.height + q, 0);\n                var C = A.alignment;\n                C.Mb() && (C = a.defaultAlignment);\n                C.eb() || (C = Ac);\n                var G = A.alignmentFocus;\n                G.Mb() && (G = Ac);\n                var L = null;\n                A instanceof X && \"\" !== A.Jg && (A.arrange(0, 0, p.width, p.height), L = A.Xa(A.Jg), L === A && (L = null));\n                if (null !== L) {\n                    l = L.naturalBounds;\n                    p = L.margin;\n                    for (l = I.allocAt(G.x * l.width - G.offsetX - p.left, G.y * l.height - G.offsetY - p.top); L !== A;) L.transform.ra(l), L = L.panel;\n                    A = C.x * f + C.offsetX - l.x;\n                    p = C.y * g + C.offsetY - l.y;\n                    I.free(l)\n                } else A = C.x * f + C.offsetX - (G.x * p.width + G.offsetX) -\n                    l.left, p = C.y * g + C.offsetY - (G.y * p.height + G.offsetY) - l.top;\n                w ? (w = !1, e.h(A, p, r, q)) : ec(e, A, p, r, q)\n            }\n        }\n        w ? e.assign(v) : u ? e.Dv(v.x, v.y, v.width, v.height) : ec(e, v.x, v.y, v.width, v.height);\n        N.free(v);\n        p = k.stretch;\n        p === Vk && (p = kl(k, !1));\n        switch (p) {\n            case zg:\n                return;\n            case vd:\n                if (!isFinite(b) && !isFinite(c)) return;\n                break;\n            case Wk:\n                if (!isFinite(b)) return;\n                break;\n            case Xk:\n                if (!isFinite(c)) return\n        }\n        p = k.measuredBounds;\n        f = p.width;\n        g = p.height;\n        r = Math.max(f + m, 0);\n        q = Math.max(g + n, 0);\n        l = k.margin;\n        v = N.allocAt(-l.left, -l.top, r, q);\n        for (b = 0; b < h; b++) c = d[b], c ===\n            k || !c.visible && c !== y || (l = c.margin, r = l.right + l.left, q = l.top + l.bottom, p = c.measuredBounds, r = Math.max(p.width + r, 0), q = Math.max(p.height + q, 0), m = c.alignment, m.Mb() && (m = a.defaultAlignment), m.eb() || (m = Ac), c = c.alignmentFocus, c.Mb() && (c = Ac), w ? (w = !1, e.h(m.x * f + m.offsetX - (c.x * p.width + c.offsetX) - l.left, m.y * g + m.offsetY - (c.y * p.height + c.offsetY) - l.top, r, q)) : ec(e, m.x * f + m.offsetX - (c.x * p.width + c.offsetX) - l.left, m.y * g + m.offsetY - (c.y * p.height + c.offsetY) - l.top, r, q));\n        w ? e.assign(v) : u ? e.Dv(v.x, v.y, v.width, v.height) : ec(e, v.x,\n            v.y, v.width, v.height);\n        N.free(v)\n    };\n    zm.prototype.arrange = function (a, b, c) {\n        var d = b.length,\n            e = a.zb(),\n            f = e.measuredBounds,\n            g = f.width;\n        f = f.height;\n        var h = a.padding,\n            k = h.left;\n        h = h.top;\n        var l = k - c.x,\n            m = h - c.y;\n        e.arrange(l, m, g, f);\n        for (var n = 0; n < d; n++) {\n            var p = b[n];\n            if (p !== e) {\n                var r = p.measuredBounds,\n                    q = r.width;\n                r = r.height;\n                m = p.alignment;\n                m.Mb() && (m = a.defaultAlignment);\n                m.eb() || (m = Ac);\n                var u = p.alignmentFocus;\n                u.Mb() && (u = Ac);\n                l = null;\n                p instanceof X && \"\" !== p.Jg && (l = p.Xa(p.Jg), l === p && (l = null));\n                if (null !== l) {\n                    var v = l.naturalBounds;\n                    for (u = I.allocAt(u.x * v.width - u.offsetX, u.y * v.height -\n                            u.offsetY); l !== p;) l.transform.ra(u), l = l.panel;\n                    l = m.x * g + m.offsetX - u.x;\n                    m = m.y * f + m.offsetY - u.y;\n                    I.free(u)\n                } else l = m.x * g + m.offsetX - (u.x * q + u.offsetX), m = m.y * f + m.offsetY - (u.y * r + u.offsetY);\n                l -= c.x;\n                m -= c.y;\n                p.visible && p.arrange(k + l, h + m, q, r)\n            }\n        }\n    };\n\n    function Am() {\n        this.name = \"Base\";\n        this.name = \"Auto\"\n    }\n    la(Am, Ol);\n    Am.prototype.measure = function (a, b, c, d, e, f, g) {\n        var h = d.length,\n            k = a.zb(),\n            l = k.margin,\n            m = b,\n            n = c,\n            p = l.right + l.left,\n            r = l.top + l.bottom;\n        k.measure(b, c, f, g);\n        l = k.measuredBounds;\n        var q = 0,\n            u = null;\n        k instanceof Lf && (u = k, q = u.strokeWidth * u.scale);\n        var v = Math.max(l.width + p, 0);\n        l = Math.max(l.height + r, 0);\n        var w = Bm(k),\n            y = w.x * v + w.offsetX;\n        w = w.y * l + w.offsetY;\n        var z = Cm(k),\n            A = z.x * v + z.offsetX;\n        z = z.y * l + z.offsetY;\n        isFinite(b) && (m = Math.max(Math.abs(y - A) - q, 0));\n        isFinite(c) && (n = Math.max(Math.abs(w - z) - q, 0));\n        q = M.alloc();\n        q.h(0, 0);\n        a = wm(a);\n        for (z = 0; z < h; z++) w =\n            d[z], w === k || !w.visible && w !== a || (l = w.margin, v = l.right + l.left, y = l.top + l.bottom, w.measure(m, n, 0, 0), l = w.measuredBounds, v = Math.max(l.width + v, 0), l = Math.max(l.height + y, 0), q.h(Math.max(v, q.width), Math.max(l, q.height)));\n        if (1 === h) e.width = v, e.height = l, M.free(q);\n        else {\n            w = Bm(k);\n            z = Cm(k);\n            h = d = 0;\n            z.x !== w.x && z.y !== w.y && (d = q.width / Math.abs(z.x - w.x), h = q.height / Math.abs(z.y - w.y));\n            M.free(q);\n            q = 0;\n            null !== u && (q = u.strokeWidth * u.scale, Ag(u) === Bg && (d = h = Math.max(d, h)));\n            d += Math.abs(w.offsetX) + Math.abs(z.offsetX) + q;\n            h += Math.abs(w.offsetY) +\n                Math.abs(z.offsetY) + q;\n            u = k.stretch;\n            u === Vk && (u = kl(k, !1));\n            switch (u) {\n                case zg:\n                    g = f = 0;\n                    break;\n                case vd:\n                    isFinite(b) && (d = b);\n                    isFinite(c) && (h = c);\n                    break;\n                case Wk:\n                    isFinite(b) && (d = b);\n                    g = 0;\n                    break;\n                case Xk:\n                    f = 0, isFinite(c) && (h = c)\n            }\n            k.om();\n            k.measure(d, h, f, g);\n            e.width = k.measuredBounds.width + p;\n            e.height = k.measuredBounds.height + r\n        }\n    };\n    Am.prototype.arrange = function (a, b) {\n        var c = b.length,\n            d = a.zb(),\n            e = d.measuredBounds,\n            f = N.alloc();\n        f.h(0, 0, 1, 1);\n        var g = d.margin,\n            h = g.left;\n        g = g.top;\n        var k = a.padding,\n            l = k.left;\n        k = k.top;\n        d.arrange(l + h, k + g, e.width, e.height);\n        var m = Bm(d),\n            n = Cm(d),\n            p = m.y * e.height + m.offsetY,\n            r = n.x * e.width + n.offsetX;\n        n = n.y * e.height + n.offsetY;\n        f.x = m.x * e.width + m.offsetX;\n        f.y = p;\n        ec(f, r, n, 0, 0);\n        f.x += h + l;\n        f.y += g + k;\n        for (e = 0; e < c; e++) h = b[e], h !== d && (l = h.measuredBounds, g = h.margin, k = Math.max(l.width + g.right + g.left, 0), m = Math.max(l.height + g.top + g.bottom, 0), p = h.alignment,\n            p.Mb() && (p = a.defaultAlignment), p.eb() || (p = Ac), k = f.width * p.x + p.offsetX - k * p.x + g.left + f.x, g = f.height * p.y + p.offsetY - m * p.y + g.top + f.y, h.visible && (fc(f.x, f.y, f.width, f.height, k, g, l.width, l.height) ? h.arrange(k, g, l.width, l.height) : h.arrange(k, g, l.width, l.height, new N(f.x, f.y, f.width, f.height))));\n        N.free(f)\n    };\n\n    function Dm() {\n        this.name = \"Base\";\n        this.name = \"Table\"\n    }\n    la(Dm, Ol);\n    Dm.prototype.measure = function (a, b, c, d, e, f, g) {\n        for (var h = d.length, k = Fa(), l = Fa(), m = 0; m < h; m++) {\n            var n = d[m],\n                p = n instanceof X ? n : null;\n            if (null === p || p.type !== X.TableRow && p.type !== X.TableColumn || !n.visible) k.push(n);\n            else {\n                l.push(p);\n                for (var r = p.W.j, q = r.length, u = 0; u < q; u++) {\n                    var v = r[u];\n                    p.type === X.TableRow ? v.row = n.row : p.type === X.TableColumn && (v.column = n.column);\n                    k.push(v)\n                }\n            }\n        }\n        h = k.length;\n        0 === h && (a.getRowDefinition(0), a.getColumnDefinition(0));\n        for (var w = [], y = 0; y < h; y++) {\n            var z = k[y];\n            lj(z, !0);\n            ll(z, !0);\n            w[z.row] || (w[z.row] = []);\n            w[z.row][z.column] || (w[z.row][z.column] = []);\n            w[z.row][z.column].push(z)\n        }\n        Ha(k);\n        var A = Fa(),\n            C = Fa(),\n            G = Fa(),\n            L = {\n                count: 0\n            },\n            K = {\n                count: 0\n            },\n            V = b,\n            Q = c,\n            ca = a.rb;\n        h = ca.length;\n        for (var pa = 0; pa < h; pa++) {\n            var O = ca[pa];\n            void 0 !== O && (O.actual = 0)\n        }\n        ca = a.mb;\n        h = ca.length;\n        for (var xa = 0; xa < h; xa++) O = ca[xa], void 0 !== O && (O.actual = 0);\n        for (var Ma = w.length, hb = 0, Ea = 0; Ea < Ma; Ea++) w[Ea] && (hb = Math.max(hb, w[Ea].length));\n        var xb = Math.min(a.topIndex, Ma - 1),\n            Ad = Math.min(a.leftIndex, hb - 1),\n            ib = 0;\n        Ma = w.length;\n        for (var Xb = wm(a), $a = 0; $a < Ma; $a++)\n            if (w[$a]) {\n                hb =\n                    w[$a].length;\n                for (var Md = a.getRowDefinition($a), wc = Md.actual = 0; wc < hb; wc++)\n                    if (w[$a][wc]) {\n                        var zf = a.getColumnDefinition(wc);\n                        void 0 === A[wc] && (zf.actual = 0, A[wc] = !0);\n                        for (var Ye = w[$a][wc], De = Ye.length, lh = 0; lh < De; lh++) {\n                            var Dc = Ye[lh];\n                            if (Dc.visible || Dc === Xb) {\n                                var Af = 1 < Dc.rowSpan || 1 < Dc.columnSpan;\n                                Af && ($a < xb || wc < Ad || C.push(Dc));\n                                var Ze = Dc.margin,\n                                    Nd = Ze.right + Ze.left,\n                                    Tj = Ze.top + Ze.bottom;\n                                var Eb = Dl(Dc, Md, zf, !1);\n                                var Bf = Dc.desiredSize,\n                                    Bd = !isNaN(Bf.height),\n                                    jc = !isNaN(Bf.width) && Bd;\n                                Af || Eb === zg || jc || $a < xb || wc < Ad || (void 0 !==\n                                    L[wc] || Eb !== vd && Eb !== Wk || (L[wc] = -1, L.count++), void 0 !== K[$a] || Eb !== vd && Eb !== Xk || (K[$a] = -1, K.count++), G.push(Dc));\n                                Dc.measure(Infinity, Infinity, 0, 0);\n                                if (!($a < xb || wc < Ad)) {\n                                    var $e = Dc.measuredBounds,\n                                        Wc = Math.max($e.width + Nd, 0),\n                                        dg = Math.max($e.height + Tj, 0);\n                                    if (1 === Dc.rowSpan && (Eb === zg || Eb === Wk)) {\n                                        O = a.getRowDefinition($a);\n                                        var mh = O.uc();\n                                        ib = Math.max(dg - O.actual, 0);\n                                        ib + mh > Q && (ib = Math.max(Q - mh, 0));\n                                        var nn = 0 === O.actual;\n                                        O.actual = O.actual + ib;\n                                        Q = Math.max(Q - (ib + (nn ? mh : 0)), 0)\n                                    }\n                                    if (1 === Dc.columnSpan && (Eb === zg || Eb === Xk)) {\n                                        O = a.getColumnDefinition(wc);\n                                        var eg = O.uc();\n                                        ib = Math.max(Wc - O.actual, 0);\n                                        ib + eg > V && (ib = Math.max(V - eg, 0));\n                                        var Uj = 0 === O.actual;\n                                        O.actual = O.actual + ib;\n                                        V = Math.max(V - (ib + (Uj ? eg : 0)), 0)\n                                    }\n                                    Af && Dc.om()\n                                }\n                            }\n                        }\n                    }\n            } Ha(A);\n        var Yb = 0,\n            Oc = 0;\n        h = a.columnCount;\n        for (var cc = 0; cc < h; cc++) {\n            var fg = a.mb[cc];\n            void 0 !== fg && (Yb += fg.ha, 0 !== fg.ha && (Yb += fg.uc()))\n        }\n        h = a.rowCount;\n        for (var nh = 0; nh < h; nh++) {\n            var af = a.rb[nh];\n            void 0 !== af && (Oc += af.ha, 0 !== af.ha && (Oc += af.uc()))\n        }\n        V = Math.max(b - Yb, 0);\n        var ti = Q = Math.max(c - Oc, 0),\n            ge = V;\n        h = G.length;\n        for (var Ee = 0; Ee < h; Ee++) {\n            var kc = G[Ee],\n                Vj = a.getRowDefinition(kc.row),\n                on = a.getColumnDefinition(kc.column),\n                gg = kc.measuredBounds,\n                Qb = kc.margin,\n                hg = Qb.right + Qb.left,\n                Wj = Qb.top + Qb.bottom;\n            L[kc.column] = 0 === on.actual && void 0 !== L[kc.column] ? Math.max(gg.width + hg, L[kc.column]) : null;\n            K[kc.row] = 0 === Vj.actual && void 0 !== K[kc.row] ? Math.max(gg.height + Wj, K[kc.row]) : null\n        }\n        var ui = 0,\n            ig = 0,\n            Cf;\n        for (Cf in K) \"count\" !== Cf && (ui += K[Cf]);\n        for (Cf in L) \"count\" !== Cf && (ig += L[Cf]);\n        for (var ab = M.alloc(), jg = 0; jg < h; jg++) {\n            var lc = G[jg];\n            if (lc.visible || lc === Xb) {\n                var Ec = a.getRowDefinition(lc.row),\n                    bb = a.getColumnDefinition(lc.column),\n                    Cd = 0;\n                isFinite(bb.width) ? Cd = bb.width : (isFinite(V) && null !== L[lc.column] ? 0 === ig ? Cd = bb.actual + V : Cd = L[lc.column] / ig * ge : null !== L[lc.column] ? Cd = V : Cd = bb.actual || V, Cd = Math.max(0, Cd - bb.uc()));\n                var Dd = 0;\n                isFinite(Ec.height) ? Dd = Ec.height : (isFinite(Q) && null !== K[lc.row] ? 0 === ui ? Dd = Ec.actual + Q : Dd = K[lc.row] / ui * ti : null !== K[lc.row] ? Dd = Q : Dd = Ec.actual || Q, Dd = Math.max(0, Dd - Ec.uc()));\n                ab.h(Math.max(bb.minimum, Math.min(Cd, bb.maximum)), Math.max(Ec.minimum, Math.min(Dd, Ec.maximum)));\n                Eb = Dl(lc, Ec, bb, !1);\n                switch (Eb) {\n                    case Wk:\n                        ab.height =\n                            Math.max(ab.height, Ec.actual + Q);\n                        break;\n                    case Xk:\n                        ab.width = Math.max(ab.width, bb.actual + V)\n                }\n                var Od = lc.margin,\n                    pn = Od.right + Od.left,\n                    oh = Od.top + Od.bottom;\n                lc.om();\n                lc.measure(ab.width, ab.height, bb.minimum, Ec.minimum);\n                var ph = lc.measuredBounds,\n                    qh = Math.max(ph.width + pn, 0),\n                    rh = Math.max(ph.height + oh, 0);\n                isFinite(V) && (qh = Math.min(qh, ab.width));\n                isFinite(Q) && (rh = Math.min(rh, ab.height));\n                var kg = 0;\n                kg = Ec.actual;\n                Ec.actual = Math.max(Ec.actual, rh);\n                ib = Ec.actual - kg;\n                Q = Math.max(Q - ib, 0);\n                kg = bb.actual;\n                bb.actual = Math.max(bb.actual, qh);\n                ib = bb.actual - kg;\n                V = Math.max(V - ib, 0)\n            }\n        }\n        Ha(G);\n        var Ed = M.alloc(),\n            Xc = Fa(),\n            he = Fa();\n        h = C.length;\n        if (0 !== h)\n            for (var qb = 0; qb < Ma; qb++)\n                if (w[qb]) {\n                    hb = w[qb].length;\n                    var vi = a.getRowDefinition(qb);\n                    Xc[qb] = vi.actual;\n                    for (var md = 0; md < hb; md++)\n                        if (w[qb][md]) {\n                            var qn = a.getColumnDefinition(md);\n                            he[md] = qn.actual\n                        }\n                } for (var ie = 0; ie < h; ie++) {\n            var Na = C[ie];\n            if (Na.visible || Na === Xb) {\n                var Fd = a.getRowDefinition(Na.row),\n                    mc = a.getColumnDefinition(Na.column);\n                ab.h(Math.max(mc.minimum, Math.min(b, mc.maximum)), Math.max(Fd.minimum, Math.min(c, Fd.maximum)));\n                Eb = Dl(Na, Fd, mc, !1);\n                switch (Eb) {\n                    case vd:\n                        0 !== he[mc.index] && (ab.width = Math.min(ab.width, he[mc.index]));\n                        0 !== Xc[Fd.index] && (ab.height = Math.min(ab.height, Xc[Fd.index]));\n                        break;\n                    case Wk:\n                        0 !== he[mc.index] && (ab.width = Math.min(ab.width, he[mc.index]));\n                        break;\n                    case Xk:\n                        0 !== Xc[Fd.index] && (ab.height = Math.min(ab.height, Xc[Fd.index]))\n                }\n                isFinite(mc.width) && (ab.width = mc.width);\n                isFinite(Fd.height) && (ab.height = Fd.height);\n                Ed.h(0, 0);\n                for (var Fe = 1; Fe < Na.rowSpan && !(Na.row + Fe >= a.rowCount); Fe++) O = a.getRowDefinition(Na.row + Fe), ib = 0,\n                    ib = Eb === vd || Eb === Xk ? Math.max(O.minimum, 0 === Xc[Na.row + Fe] ? O.maximum : Math.min(Xc[Na.row + Fe], O.maximum)) : Math.max(O.minimum, isNaN(O.Pc) ? O.maximum : Math.min(O.Pc, O.maximum)), Ed.height += ib;\n                for (var Df = 1; Df < Na.columnSpan && !(Na.column + Df >= a.columnCount); Df++) O = a.getColumnDefinition(Na.column + Df), ib = 0, ib = Eb === vd || Eb === Wk ? Math.max(O.minimum, 0 === he[Na.column + Df] ? O.maximum : Math.min(he[Na.column + Df], O.maximum)) : Math.max(O.minimum, isNaN(O.Pc) ? O.maximum : Math.min(O.Pc, O.maximum)), Ed.width += ib;\n                ab.width += Ed.width;\n                ab.height +=\n                    Ed.height;\n                var bf = Na.margin,\n                    Pd = bf.right + bf.left,\n                    Ge = bf.top + bf.bottom;\n                Na.measure(ab.width, ab.height, f, g);\n                for (var cf = Na.measuredBounds, He = Math.max(cf.width + Pd, 0), Ie = Math.max(cf.height + Ge, 0), nd = 0, lg = 0; lg < Na.rowSpan && !(Na.row + lg >= a.rowCount); lg++) O = a.getRowDefinition(Na.row + lg), nd += O.total || 0;\n                if (nd < Ie) {\n                    var je = Ie - nd,\n                        rn = Ie - nd;\n                    if (null !== Na.spanAllocation)\n                        for (var sn = Na.spanAllocation, od = 0; od < Na.rowSpan && !(0 >= je) && !(Na.row + od >= a.rowCount); od++) {\n                            O = a.getRowDefinition(Na.row + od);\n                            var mg = O.ha || 0,\n                                tn = sn(Na, O, rn);\n                            O.actual =\n                                Math.min(O.maximum, mg + tn);\n                            O.ha !== mg && (je -= O.ha - mg)\n                        }\n                    for (; 0 < je;) {\n                        var sh = O.ha || 0;\n                        isNaN(O.height) && O.maximum > sh && (O.actual = Math.min(O.maximum, sh + je), O.ha !== sh && (je -= O.ha - sh));\n                        if (0 === O.index) break;\n                        O = a.getRowDefinition(O.index - 1)\n                    }\n                }\n                for (var Xj = 0, Yj = 0; Yj < Na.columnSpan && !(Na.column + Yj >= a.columnCount); Yj++) O = a.getColumnDefinition(Na.column + Yj), Xj += O.total || 0;\n                if (Xj < He) {\n                    var wi = He - Xj,\n                        Lt = He - Xj;\n                    if (null !== Na.spanAllocation)\n                        for (var Mt = Na.spanAllocation, Zj = 0; Zj < Na.columnSpan && !(0 >= wi) && !(Na.column + Zj >= a.columnCount); Zj++) {\n                            O =\n                                a.getColumnDefinition(Na.column + Zj);\n                            var un = O.ha || 0,\n                                Nt = Mt(Na, O, Lt);\n                            O.actual = Math.min(O.maximum, un + Nt);\n                            O.ha !== un && (wi -= O.ha - un)\n                        }\n                    for (; 0 < wi;) {\n                        var ak = O.ha || 0;\n                        isNaN(O.width) && O.maximum > ak && (O.actual = Math.min(O.maximum, ak + wi), O.ha !== ak && (wi -= O.ha - ak));\n                        if (0 === O.index) break;\n                        O = a.getColumnDefinition(O.index - 1)\n                    }\n                }\n            }\n        }\n        Ha(C);\n        M.free(Ed);\n        M.free(ab);\n        void 0 !== Xc && Ha(Xc);\n        void 0 !== he && Ha(he);\n        var ng = 0,\n            og = 0,\n            bk = a.desiredSize,\n            jr = a.maxSize;\n        Eb = kl(a, !0);\n        var xi = Oc = Yb = 0,\n            yi = 0;\n        h = a.columnCount;\n        for (var ck = 0; ck < h; ck++) void 0 !== a.mb[ck] &&\n            (O = a.getColumnDefinition(ck), isFinite(O.width) ? (xi += O.width, xi += O.uc()) : Em(O) === Fm ? (xi += O.ha, xi += O.uc()) : 0 !== O.ha && (Yb += O.ha, Yb += O.uc()));\n        isFinite(bk.width) ? ng = Math.min(bk.width, jr.width) : ng = Eb !== zg && isFinite(b) ? b : Yb;\n        ng = Math.max(ng, a.minSize.width);\n        ng = Math.max(ng - xi, 0);\n        for (var Ot = 0 === Yb ? 1 : Math.max(ng / Yb, 1), ek = 0; ek < h; ek++) void 0 !== a.mb[ek] && (O = a.getColumnDefinition(ek), isFinite(O.width) || Em(O) === Fm || (O.actual = O.ha * Ot), O.position = e.width, 0 !== O.ha && (e.width += O.ha, e.width += O.uc()));\n        h = a.rowCount;\n        for (var fk =\n                0; fk < h; fk++) void 0 !== a.rb[fk] && (O = a.getRowDefinition(fk), isFinite(O.height) ? (yi += O.height, yi += O.uc()) : Em(O) === Fm ? (yi += O.ha, yi += O.uc()) : 0 !== O.ha && (Oc += O.ha, 0 !== O.ha && (Oc += O.uc())));\n        isFinite(bk.height) ? og = Math.min(bk.height, jr.height) : og = Eb !== zg && isFinite(c) ? c : Oc;\n        og = Math.max(og, a.minSize.height);\n        og = Math.max(og - yi, 0);\n        for (var Pt = 0 === Oc ? 1 : Math.max(og / Oc, 1), gk = 0; gk < h; gk++) void 0 !== a.rb[gk] && (O = a.getRowDefinition(gk), isFinite(O.height) || Em(O) === Fm || (O.actual = O.ha * Pt), O.position = e.height, 0 !== O.ha && (e.height +=\n            O.ha, 0 !== O.ha && (e.height += O.uc())));\n        h = l.length;\n        for (var vn = 0; vn < h; vn++) {\n            var pd = l[vn],\n                wn = 0,\n                xn = 0;\n            pd.type === X.TableRow ? (wn = e.width, O = a.getRowDefinition(pd.row), xn = O.actual) : (O = a.getColumnDefinition(pd.column), wn = O.actual, xn = e.height);\n            pd.measuredBounds.h(0, 0, wn, xn);\n            lj(pd, !1);\n            w[pd.row] || (w[pd.row] = []);\n            w[pd.row][pd.column] || (w[pd.row][pd.column] = []);\n            w[pd.row][pd.column].push(pd)\n        }\n        Ha(l);\n        a.rp = w\n    };\n    Dm.prototype.arrange = function (a, b, c) {\n        var d = b.length,\n            e = a.padding,\n            f = e.left;\n        e = e.top;\n        for (var g = a.rp, h, k, l = g.length, m = 0, n = 0; n < l; n++) g[n] && (m = Math.max(m, g[n].length));\n        for (n = Math.min(a.topIndex, l - 1); n !== l && (void 0 === a.rb[n] || 0 === a.rb[n].ha);) n++;\n        n = Math.min(n, l - 1);\n        n = -a.rb[n].position;\n        for (h = Math.min(a.leftIndex, m - 1); h !== m && (void 0 === a.mb[h] || 0 === a.mb[h].ha);) h++;\n        h = Math.min(h, m - 1);\n        for (var p = -a.mb[h].position, r = M.alloc(), q = 0; q < l; q++)\n            if (g[q]) {\n                m = g[q].length;\n                var u = a.getRowDefinition(q);\n                k = u.position + n + e;\n                0 !== u.ha &&\n                    (k += u.iv());\n                for (var v = 0; v < m; v++)\n                    if (g[q][v]) {\n                        var w = a.getColumnDefinition(v);\n                        h = w.position + p + f;\n                        0 !== w.ha && (h += w.iv());\n                        for (var y = g[q][v], z = y.length, A = 0; A < z; A++) {\n                            var C = y[A],\n                                G = C.measuredBounds,\n                                L = C instanceof X ? C : null;\n                            if (null === L || L.type !== X.TableRow && L.type !== X.TableColumn) {\n                                r.h(0, 0);\n                                for (var K = 1; K < C.rowSpan && !(q + K >= a.rowCount); K++) L = a.getRowDefinition(q + K), r.height += L.total;\n                                for (K = 1; K < C.columnSpan && !(v + K >= a.columnCount); K++) L = a.getColumnDefinition(v + K), r.width += L.total;\n                                var V = w.ha + r.width,\n                                    Q = u.ha + r.height;\n                                K =\n                                    h;\n                                L = k;\n                                var ca = V,\n                                    pa = Q,\n                                    O = h,\n                                    xa = k,\n                                    Ma = V,\n                                    hb = Q;\n                                h + V > c.width && (Ma = Math.max(c.width - h, 0));\n                                k + Q > c.height && (hb = Math.max(c.height - k, 0));\n                                var Ea = C.alignment;\n                                if (Ea.Mb()) {\n                                    Ea = a.defaultAlignment;\n                                    Ea.eb() || (Ea = Ac);\n                                    var xb = Ea.x;\n                                    var Ad = Ea.y;\n                                    var ib = Ea.offsetX;\n                                    Ea = Ea.offsetY;\n                                    var Xb = w.alignment,\n                                        $a = u.alignment;\n                                    Xb.eb() && (xb = Xb.x, ib = Xb.offsetX);\n                                    $a.eb() && (Ad = $a.y, Ea = $a.offsetY)\n                                } else xb = Ea.x, Ad = Ea.y, ib = Ea.offsetX, Ea = Ea.offsetY;\n                                if (isNaN(xb) || isNaN(Ad)) Ad = xb = .5, Ea = ib = 0;\n                                Xb = G.width;\n                                $a = G.height;\n                                var Md = C.margin,\n                                    wc = Md.left + Md.right,\n                                    zf = Md.top +\n                                    Md.bottom,\n                                    Ye = Dl(C, u, w, !1);\n                                !isNaN(C.desiredSize.width) || Ye !== vd && Ye !== Wk || (Xb = Math.max(V - wc, 0));\n                                !isNaN(C.desiredSize.height) || Ye !== vd && Ye !== Xk || ($a = Math.max(Q - zf, 0));\n                                V = C.maxSize;\n                                Q = C.minSize;\n                                Xb = Math.min(V.width, Xb);\n                                $a = Math.min(V.height, $a);\n                                Xb = Math.max(Q.width, Xb);\n                                $a = Math.max(Q.height, $a);\n                                V = $a + zf;\n                                K += ca * xb - (Xb + wc) * xb + ib + Md.left;\n                                L += pa * Ad - V * Ad + Ea + Md.top;\n                                C.visible && (fc(O, xa, Ma, hb, K, L, G.width, G.height) ? C.arrange(K, L, Xb, $a) : C.arrange(K, L, Xb, $a, new N(O, xa, Ma, hb)))\n                            } else C.ml(), C.actualBounds.ea(), ca = C.actualBounds,\n                                K = N.allocAt(ca.x, ca.y, ca.width, ca.height), ca.x = L.type === X.TableRow ? f : h, ca.y = L.type === X.TableColumn ? e : k, ca.width = G.width, ca.height = G.height, C.actualBounds.freeze(), ll(C, !1), $b(K, ca) || (G = C.part, null !== G && (G.Jh(), C.To(G))), N.free(K)\n                        }\n                    }\n            } M.free(r);\n        for (a = 0; a < d; a++) c = b[a], f = c instanceof X ? c : null, null === f || f.type !== X.TableRow && f.type !== X.TableColumn || (f = c.actualBounds, c.naturalBounds.ea(), c.naturalBounds.h(0, 0, f.width, f.height), c.naturalBounds.freeze())\n    };\n\n    function Gm() {\n        this.name = \"Base\";\n        this.name = \"TableRow\"\n    }\n    la(Gm, Ol);\n    Gm.prototype.measure = function () {};\n    Gm.prototype.arrange = function () {};\n\n    function Hm() {\n        this.name = \"Base\";\n        this.name = \"TableColumn\"\n    }\n    la(Hm, Ol);\n    Hm.prototype.measure = function () {};\n    Hm.prototype.arrange = function () {};\n\n    function Im() {\n        this.name = \"Base\";\n        this.name = \"Viewbox\"\n    }\n    la(Im, Ol);\n    Im.prototype.measure = function (a, b, c, d, e, f, g) {\n        1 < d.length && B(\"Viewbox Panel cannot contain more than one GraphObject.\");\n        d = d[0];\n        d.ya = 1;\n        d.om();\n        d.measure(Infinity, Infinity, f, g);\n        var h = d.measuredBounds,\n            k = d.margin,\n            l = k.right + k.left;\n        k = k.top + k.bottom;\n        if (isFinite(b) || isFinite(c)) {\n            var m = d.scale,\n                n = h.width;\n            h = h.height;\n            var p = Math.max(b - l, 0),\n                r = Math.max(c - k, 0),\n                q = 1;\n            a.viewboxStretch === Bg ? 0 !== n && 0 !== h && (q = Math.min(p / n, r / h)) : 0 !== n && 0 !== h && (q = Math.max(p / n, r / h));\n            0 === q && (q = 1E-4);\n            d.ya *= q;\n            m !== d.scale && (lj(d, !0), d.measure(Infinity,\n                Infinity, f, g))\n        }\n        h = d.measuredBounds;\n        e.width = isFinite(b) ? b : Math.max(h.width + l, 0);\n        e.height = isFinite(c) ? c : Math.max(h.height + k, 0)\n    };\n    Im.prototype.arrange = function (a, b, c) {\n        b = b[0];\n        var d = b.measuredBounds,\n            e = b.margin,\n            f = Math.max(d.width + (e.right + e.left), 0);\n        e = Math.max(d.height + (e.top + e.bottom), 0);\n        var g = b.alignment;\n        g.Mb() && (g = a.defaultAlignment);\n        g.eb() || (g = Ac);\n        b.arrange(c.width * g.x - f * g.x + g.offsetX, c.height * g.y - e * g.y + g.offsetY, d.width, d.height)\n    };\n\n    function Jm() {\n        this.name = \"Base\";\n        this.name = \"Grid\"\n    }\n    la(Jm, Ol);\n    Jm.prototype.measure = function () {};\n    Jm.prototype.arrange = function () {};\n    Jm.prototype.bc = function (a, b, c) {\n        c = a.uf() * c.scale;\n        0 >= c && (c = 1);\n        var d = a.gridCellSize,\n            e = d.width;\n        d = d.height;\n        var f = a.naturalBounds,\n            g = a.actualBounds,\n            h = f.width,\n            k = f.height,\n            l = Math.ceil(h / e),\n            m = Math.ceil(k / d),\n            n = a.gridOrigin;\n        b.save();\n        b.beginPath();\n        b.rect(0, 0, h, k);\n        b.clip();\n        for (var p = [], r = a.W.j, q = r.length, u = 0; u < q; u++) {\n            var v = r[u],\n                w = [];\n            p.push(w);\n            if (v.visible) {\n                var y = v.interval;\n                if (!(0 > y)) {\n                    v = dk(v.figure);\n                    for (var z = 0; z < q; z++)\n                        if (z !== u) {\n                            var A = r[z];\n                            A.visible && dk(A.figure) === v && (A = A.interval, A > y && w.push(A))\n                        }\n                }\n            }\n        }\n        r = a.W.j;\n        q =\n            r.length;\n        for (u = 0; u < q; u++) {\n            var C = r[u];\n            if (C.visible && (w = C.interval, !(2 > e * Math.abs(w) * c))) {\n                y = C.opacity;\n                v = 1;\n                if (1 !== y) {\n                    if (0 === y) continue;\n                    v = b.globalAlpha;\n                    b.globalAlpha = v * y\n                }\n                z = p[u];\n                A = !1;\n                var G = C.strokeDashArray;\n                null !== G && (A = !0, b.ht(G, C.strokeDashOffset));\n                if (\"LineV\" === C.figure && null !== C.stroke && 0 < C.strokeWidth) {\n                    b.lineWidth = C.strokeWidth;\n                    ii(a, b, C.stroke, !1, !1, f, g);\n                    b.beginPath();\n                    for (G = C = Math.floor(-n.x / e); G <= C + l; G++) {\n                        var L = G * e + n.x;\n                        0 <= L && L <= h && Km(G, w, z) && (b.moveTo(L, 0), b.lineTo(L, k))\n                    }\n                    b.stroke()\n                } else if (\"LineH\" ===\n                    C.figure && null !== C.stroke && 0 < C.strokeWidth) {\n                    b.lineWidth = C.strokeWidth;\n                    ii(a, b, C.stroke, !1, !1, f, g);\n                    b.beginPath();\n                    for (G = C = Math.floor(-n.y / d); G <= C + m; G++) L = G * d + n.y, 0 <= L && L <= k && Km(G, w, z) && (b.moveTo(0, L), b.lineTo(h, L));\n                    b.stroke()\n                } else if (\"BarV\" === C.figure && null !== C.fill)\n                    for (ii(a, b, C.fill, !0, !1, f, g), C = C.width, isNaN(C) && (C = e), L = G = Math.floor(-n.x / e); L <= G + l; L++) {\n                        var K = L * e + n.x;\n                        0 <= K && K <= h && Km(L, w, z) && b.fillRect(K, 0, C, k)\n                    } else if (\"BarH\" === C.figure && null !== C.fill)\n                        for (ii(a, b, C.fill, !0, !1, f, g), C = C.height, isNaN(C) &&\n                            (C = d), L = G = Math.floor(-n.y / d); L <= G + m; L++) K = L * d + n.y, 0 <= K && K <= k && Km(L, w, z) && b.fillRect(0, K, h, C);\n                A && b.ft();\n                1 !== y && (b.globalAlpha = v)\n            }\n        }\n        b.restore();\n        b.sc(!1)\n    };\n\n    function Km(a, b, c) {\n        if (0 > b) return 0 === a % b;\n        if (0 !== a % b) return !1;\n        b = c.length;\n        for (var d = 0; d < b; d++)\n            if (0 === a % c[d]) return !1;\n        return !0\n    }\n\n    function Lm() {\n        this.name = \"Base\";\n        this.name = \"Link\"\n    }\n    la(Lm, Ol);\n    Lm.prototype.measure = function (a, b, c, d, e) {\n        c = d.length;\n        if (a instanceof Je || a instanceof S) {\n            var f = null,\n                g = null,\n                h = null;\n            a instanceof S && (g = f = a);\n            a instanceof Je && (h = a, f = h.adornedPart);\n            if (f instanceof S) {\n                var k = f;\n                if (0 === c) Vb(a.naturalBounds, 0, 0), a.measuredBounds.h(0, 0, 0, 0);\n                else {\n                    var l = a instanceof Je ? null : f.path,\n                        m = f.routeBounds;\n                    b = a.vg;\n                    b.h(0, 0, m.width, m.height);\n                    var n = k.points;\n                    f = f.pointsCount;\n                    null !== h ? h.nk(!1) : null !== g && g.nk(!1);\n                    var p = m.width,\n                        r = m.height;\n                    a.location.h(m.x, m.y);\n                    a.l.length = 0;\n                    null !== l && (Mm(a, p, r, l),\n                        h = l.measuredBounds, b.Hc(h), a.l.push(h));\n                    h = rd.alloc();\n                    for (var q = I.alloc(), u = I.alloc(), v = 0; v < c; v++) {\n                        var w = d[v];\n                        if (w !== l)\n                            if (w.isPanelMain && w instanceof Lf) {\n                                Mm(a, p, r, w);\n                                var y = w.measuredBounds;\n                                b.Hc(y);\n                                a.l.push(y)\n                            } else if (2 > f) w.measure(Infinity, Infinity, 0, 0), y = w.measuredBounds, b.Hc(y), a.l.push(y);\n                        else {\n                            var z = w.segmentIndex,\n                                A = w.segmentFraction,\n                                C = w.alignmentFocus;\n                            C.jc() && (C = Ac);\n                            var G = w.segmentOrientation,\n                                L = w.segmentOffset;\n                            if (isNaN(z)) {\n                                var K = k.ka;\n                                y = Fa();\n                                K.zv(A, y);\n                                var V = I.allocAt(y[0], y[1]);\n                                V.add(k.i(0));\n                                K.type ===\n                                    wd ? V.offset(-K.startX, -K.startY) : (K = K.figures.first(), V.offset(-K.startX, -K.startY));\n                                K = y[2];\n                                if (G !== bg) {\n                                    var Q = k.computeAngle(w, G, K);\n                                    w.Yb = Q\n                                }\n                                Q = V.x - m.x;\n                                var ca = V.y - m.y;\n                                I.free(V);\n                                Ha(y)\n                            } else if (z < -f || z >= f) ca = k.midPoint, K = k.midAngle, G !== bg && (Q = k.computeAngle(w, G, K), w.Yb = Q), Q = ca.x - m.x, ca = ca.y - m.y;\n                            else {\n                                Q = 0;\n                                0 <= z ? (ca = n.L(z), y = z < f - 1 ? n.L(z + 1) : ca) : (Q = f + z, ca = n.L(Q), y = 0 < Q ? n.L(Q - 1) : ca);\n                                if (ca.Ma(y)) {\n                                    0 <= z ? (K = 0 < z ? n.L(z - 1) : ca, Q = z < f - 2 ? n.L(z + 2) : y) : (K = Q < f - 1 ? n.L(Q + 1) : ca, Q = 1 < Q ? n.L(Q - 2) : y);\n                                    V = K.Ae(ca);\n                                    var pa = y.Ae(Q);\n                                    K = V > pa + 10 ?\n                                        0 <= z ? K.Ta(ca) : ca.Ta(K) : pa > V + 10 ? 0 <= z ? y.Ta(Q) : Q.Ta(y) : 0 <= z ? K.Ta(Q) : Q.Ta(K)\n                                } else K = 0 <= z ? ca.Ta(y) : y.Ta(ca);\n                                G !== bg && (Q = k.computeAngle(w, G, K), w.Yb = Q);\n                                Q = ca.x + (y.x - ca.x) * A - m.x;\n                                ca = ca.y + (y.y - ca.y) * A - m.y\n                            }\n                            w.measure(Infinity, Infinity, 0, 0);\n                            y = w.measuredBounds;\n                            V = w.naturalBounds;\n                            var O = 0;\n                            w instanceof Lf && (O = w.strokeWidth);\n                            pa = V.width + O;\n                            var xa = V.height + O;\n                            h.reset();\n                            h.translate(-y.x, -y.y);\n                            h.scale(w.scale, w.scale);\n                            h.rotate(G === bg ? w.angle : K, pa / 2, xa / 2);\n                            G !== Nm && G !== Om || h.rotate(90, pa / 2, xa / 2);\n                            G !== Pm && G !== Qm || h.rotate(-90, pa /\n                                2, xa / 2);\n                            G === Rm && (45 < K && 135 > K || 225 < K && 315 > K) && h.rotate(-K, pa / 2, xa / 2);\n                            V = new N(0, 0, pa, xa);\n                            q.dj(V, C);\n                            h.ra(q);\n                            C = -q.x + O / 2 * w.scale;\n                            w = -q.y + O / 2 * w.scale;\n                            u.assign(L);\n                            O = isNaN(L.x);\n                            var Ma = isNaN(L.y);\n                            if (O || Ma) {\n                                pa = pa / 2 + 3;\n                                xa = xa / 2 + 3;\n                                var hb = 45 <= K && 135 >= K,\n                                    Ea = 225 <= K && 315 >= K;\n                                G === bg && (hb || Ea) ? (u.x = Ma ? pa : L.y, u.y = O ? xa : L.x, hb ? 0 <= z || isNaN(z) && .5 > A || !O || (u.y = -xa) : Ea && ((0 <= z || isNaN(z) && .5 > A) && O && (u.y = -xa), Ma && (u.x = -pa))) : (O && (u.x = 0 <= z || isNaN(z) && .5 > A ? pa : -pa), Ma && (u.y = -xa), u.rotate(K))\n                            } else u.rotate(K);\n                            Q += u.x;\n                            ca += u.y;\n                            V.set(y);\n                            V.h(Q + C, ca + w, y.width, y.height);\n                            a.l.push(V);\n                            b.Hc(V)\n                        }\n                    }\n                    if (null !== g)\n                        for (d = g.labelNodes; d.next();) d.value.measure(Infinity, Infinity);\n                    a.vg = b;\n                    a = a.location;\n                    a.h(a.x + b.x, a.y + b.y);\n                    Vb(e, b.width || 0, b.height || 0);\n                    rd.free(h);\n                    I.free(q);\n                    I.free(u)\n                }\n            }\n        }\n    };\n    Lm.prototype.arrange = function (a, b) {\n        var c = b.length;\n        if (a instanceof Je || a instanceof S) {\n            var d = null,\n                e = null,\n                f = null;\n            a instanceof S && (e = d = a);\n            a instanceof Je && (f = a, d = f.adornedPart);\n            var g = a instanceof Je ? null : d.path;\n            if (0 !== a.l.length) {\n                var h = a.l,\n                    k = 0;\n                if (null !== g && k < a.l.length) {\n                    var l = h[k];\n                    k++;\n                    g.arrange(l.x - a.vg.x, l.y - a.vg.y, l.width, l.height)\n                }\n                for (l = 0; l < c; l++) {\n                    var m = b[l];\n                    if (m !== g && k < a.l.length) {\n                        var n = h[k];\n                        k++;\n                        m.arrange(n.x - a.vg.x, n.y - a.vg.y, n.width, n.height)\n                    }\n                }\n            }\n            b = d.points;\n            c = b.count;\n            if (2 <= c && a instanceof S)\n                for (d =\n                    a.labelNodes; d.next();) {\n                    var p = a;\n                    g = d.value;\n                    h = g.segmentIndex;\n                    k = g.segmentFraction;\n                    var r = g.alignmentFocus;\n                    l = g.segmentOrientation;\n                    m = g.segmentOffset;\n                    if (isNaN(h)) {\n                        n = p.ka;\n                        var q = Fa();\n                        n.zv(k, q);\n                        var u = I.allocAt(q[0], q[1]);\n                        u.add(p.i(0));\n                        n.type === wd ? u.offset(-n.startX, -n.startY) : (n = n.figures.first(), u.offset(-n.startX, -n.startY));\n                        n = q[2];\n                        l !== bg && (p = p.computeAngle(g, l, n), g.angle = p);\n                        p = u.x;\n                        var v = u.y;\n                        I.free(u);\n                        Ha(q)\n                    } else if (h < -c || h >= c) v = p.midPoint, n = p.midAngle, l !== bg && (p = p.computeAngle(g, l, n), g.angle = p), p = v.x, v = v.y;\n                    else {\n                        u = 0;\n                        0 <= h ? (q = b.j[h], v = h < c - 1 ? b.j[h + 1] : q) : (u = c + h, q = b.j[u], v = 0 < u ? b.j[u - 1] : q);\n                        if (q.Ma(v)) {\n                            0 <= h ? (n = 0 < h ? b.j[h - 1] : q, u = h < c - 2 ? b.j[h + 2] : v) : (n = u < c - 1 ? b.j[u + 1] : q, u = 1 < u ? b.j[u - 2] : v);\n                            var w = n.Ae(q),\n                                y = v.Ae(u);\n                            n = w > y + 10 ? 0 <= h ? n.Ta(q) : q.Ta(n) : y > w + 10 ? 0 <= h ? v.Ta(u) : u.Ta(v) : 0 <= h ? n.Ta(u) : u.Ta(n)\n                        } else n = 0 <= h ? q.Ta(v) : v.Ta(q);\n                        l !== bg && (p = p.computeAngle(g, l, n), g.angle = p);\n                        p = q.x + (v.x - q.x) * k;\n                        v = q.y + (v.y - q.y) * k\n                    }\n                    if (r.wt()) g.location = new I(p, v);\n                    else {\n                        r.jc() && (r = Ac);\n                        q = rd.alloc();\n                        q.reset();\n                        q.scale(g.scale, g.scale);\n                        q.rotate(g.angle, 0,\n                            0);\n                        var z = g.naturalBounds;\n                        u = N.allocAt(0, 0, z.width, z.height);\n                        w = I.alloc();\n                        w.dj(u, r);\n                        q.ra(w);\n                        r = -w.x;\n                        y = -w.y;\n                        var A = z.width,\n                            C = z.height;\n                        z = I.alloc();\n                        z.assign(m);\n                        var G = isNaN(m.x),\n                            L = isNaN(m.y);\n                        if (G || L) {\n                            A = A / 2 + 3;\n                            C = C / 2 + 3;\n                            var K = 45 <= n && 135 >= n,\n                                V = 225 <= n && 315 >= n;\n                            l === bg && (K || V) ? (z.x = L ? A : m.y, z.y = G ? C : m.x, K ? 0 <= h || isNaN(h) && .5 > k || !G || (z.y = -C) : V && ((0 <= h || isNaN(h) && .5 > k) && G && (z.y = -C), L && (z.x = -A))) : (G && (z.x = 0 <= h || isNaN(h) && .5 > k ? A : -A), L && (z.y = -C), z.rotate(n))\n                        } else z.rotate(n);\n                        p += z.x;\n                        v += z.y;\n                        q.qw(u);\n                        r += u.x;\n                        y += u.y;\n                        h = I.allocAt(p +\n                            r, v + y);\n                        g.move(h);\n                        I.free(h);\n                        I.free(z);\n                        I.free(w);\n                        N.free(u);\n                        rd.free(q)\n                    }\n                }\n            null !== f ? f.nk(!1) : null !== e && e.nk(!1)\n        }\n    };\n\n    function Mm(a, b, c, d) {\n        if (!1 !== qj(d)) {\n            var e = d.strokeWidth;\n            0 === e && a instanceof Je && a.type === X.Link && a.adornedObject instanceof Lf && (e = a.adornedObject.strokeWidth);\n            e *= d.ya;\n            a instanceof S && null !== a.ka ? (a = a.ka.bounds, hl(d, a.x - e / 2, a.y - e / 2, a.width + e, a.height + e)) : a instanceof Je && null !== a.adornedPart.ka ? (a = a.adornedPart.ka.bounds, hl(d, a.x - e / 2, a.y - e / 2, a.width + e, a.height + e)) : hl(d, -(e / 2), -(e / 2), b + e, c + e);\n            lj(d, !1)\n        }\n    }\n\n    function Sm() {\n        this.name = \"Base\";\n        this.name = \"Graduated\"\n    }\n    la(Sm, Ol);\n    Sm.prototype.measure = function (a, b, c, d, e, f, g) {\n        var h = a.zb();\n        a.Zg = [];\n        var k = h.margin,\n            l = k.right + k.left,\n            m = k.top + k.bottom;\n        h.measure(b, c, f, g);\n        var n = h.measuredBounds,\n            p = new N(-k.left, -k.top, Math.max(n.width + l, 0), Math.max(n.height + m, 0));\n        a.Zg.push(p);\n        e.assign(p);\n        for (var r = h.geometry, q = h.strokeWidth, u = r.flattenedSegments, v = r.flattenedLengths, w = r.flattenedTotalLength, y = u.length, z = 0, A = 0, C = Fa(), G = 0; G < y; G++) {\n            var L = u[G],\n                K = [];\n            A = z = 0;\n            for (var V = L.length, Q = 0; Q < V; Q += 2) {\n                var ca = L[Q],\n                    pa = L[Q + 1];\n                if (0 !== Q) {\n                    var O = 180 * Math.atan2(pa -\n                        A, ca - z) / Math.PI;\n                    0 > O && (O += 360);\n                    K.push(O)\n                }\n                z = ca;\n                A = pa\n            }\n            C.push(K)\n        }\n        if (null === a.$g) {\n            for (var xa = [], Ma = a.W.j, hb = Ma.length, Ea = 0; Ea < hb; Ea++) {\n                var xb = Ma[Ea],\n                    Ad = [];\n                xa.push(Ad);\n                if (xb.visible) {\n                    var ib = xb.interval;\n                    if (!(0 > ib))\n                        for (var Xb = 0; Xb < hb; Xb++)\n                            if (Xb !== Ea) {\n                                var $a = Ma[Xb];\n                                if ($a.visible && xb.constructor === $a.constructor) {\n                                    var Md = $a.interval;\n                                    Md > ib && Ad.push(Md)\n                                }\n                            }\n                }\n            }\n            a.$g = xa\n        }\n        var wc = a.$g;\n        var zf = a.W.j,\n            Ye = zf.length,\n            De = 0,\n            lh = 0,\n            Dc = w;\n        a.uj = [];\n        for (var Af, Ze = 0; Ze < Ye; Ze++) {\n            var Nd = zf[Ze];\n            Af = [];\n            if (Nd.visible && Nd !== h) {\n                var Tj = Math.abs(Nd.interval),\n                    Eb = a.graduatedTickUnit;\n                if (!(2 > Eb * Tj * w / a.graduatedRange)) {\n                    var Bf = v[0][0],\n                        Bd = 0,\n                        jc = 0;\n                    lh = w * Nd.graduatedStart - 1E-4;\n                    Dc = w * Nd.graduatedEnd + 1E-4;\n                    var $e = Eb * Tj,\n                        Wc = a.graduatedTickBase;\n                    if (Wc < a.graduatedMin) {\n                        var dg = (a.graduatedMin - Wc) / $e;\n                        dg = 0 === dg % 1 ? dg : Math.floor(dg + 1);\n                        Wc += dg * $e\n                    } else Wc > a.graduatedMin + $e && (Wc -= Math.floor((Wc - a.graduatedMin) / $e) * $e);\n                    for (var mh = wc[Ze]; Wc <= a.graduatedMax;) {\n                        a: {\n                            for (var nn = mh.length, eg = 0; eg < nn; eg++)\n                                if (J.$((Wc - a.graduatedTickBase) % (mh[eg] * a.graduatedTickUnit), 0)) {\n                                    var Uj = !1;\n                                    break a\n                                } Uj = !0\n                        }\n                        if (Uj && (null === Nd.graduatedSkip || !Nd.graduatedSkip(Wc)) && (De = (Wc - a.graduatedMin) * w / a.graduatedRange, De > w && (De = w), lh <= De && De <= Dc)) {\n                            for (var Yb = C[Bd][jc], Oc = v[Bd][jc]; Bd < v.length;) {\n                                for (; De > Bf && jc < v[Bd].length - 1;) jc++, Yb = C[Bd][jc], Oc = v[Bd][jc], Bf += Oc;\n                                if (De <= Bf) break;\n                                Bd++;\n                                jc = 0;\n                                Yb = C[Bd][jc];\n                                Oc = v[Bd][jc];\n                                Bf += Oc\n                            }\n                            var cc = u[Bd],\n                                fg = cc[2 * jc],\n                                nh = cc[2 * jc + 1],\n                                af = (De - (Bf - Oc)) / Oc,\n                                ti = new I(fg + (cc[2 * jc + 2] - fg) * af + q / 2 - r.bounds.x, nh + (cc[2 * jc + 3] - nh) * af + q / 2 - r.bounds.y);\n                            ti.scale(h.scale, h.scale);\n                            var ge = Yb,\n                                Ee = C[Bd];\n                            1E-4 >\n                                af ? 0 < jc ? ge = Ee[jc - 1] : J.$(cc[0], cc[cc.length - 2]) && J.$(cc[1], cc[cc.length - 1]) && (ge = Ee[Ee.length - 1]) : .9999 < af && (jc + 1 < Ee.length ? ge = Ee[jc + 1] : J.$(cc[0], cc[cc.length - 2]) && J.$(cc[1], cc[cc.length - 1]) && (ge = Ee[0]));\n                            Yb !== ge && (180 < Math.abs(Yb - ge) && (Yb < ge ? Yb += 360 : ge += 360), Yb = (Yb + ge) / 2 % 360);\n                            if (Nd instanceof Wg) {\n                                var kc = \"\";\n                                null !== Nd.graduatedFunction ? (kc = Nd.graduatedFunction(Wc), kc = null !== kc && void 0 !== kc ? kc.toString() : \"\") : kc = (+Wc.toFixed(2)).toString();\n                                \"\" !== kc && Af.push({\n                                    xm: ti,\n                                    angle: Yb,\n                                    text: kc\n                                })\n                            } else Af.push({\n                                xm: ti,\n                                angle: Yb\n                            })\n                        }\n                        Wc += $e\n                    }\n                }\n            }\n            a.uj.push(Af)\n        }\n        Ha(C);\n        var Vj = a.uj;\n        if (null !== Vj)\n            for (var on = d.length, gg = 0; gg < on; gg++) {\n                var Qb = d[gg],\n                    hg = Vj[gg];\n                if (Qb.visible && Qb !== h && 0 !== hg.length) {\n                    if (Qb instanceof Lf) {\n                        var Wj = a,\n                            ui = e,\n                            ig = Qb.alignmentFocus;\n                        ig.jc() && (ig = xc);\n                        var Cf = Qb.angle;\n                        Qb.Yb = 0;\n                        Qb.measure(Infinity, Infinity, 0, 0);\n                        Qb.Yb = Cf;\n                        var ab = Qb.measuredBounds,\n                            jg = ab.width,\n                            lc = ab.height,\n                            Ec = N.allocAt(0, 0, jg, lc),\n                            bb = I.alloc();\n                        bb.dj(Ec, ig);\n                        N.free(Ec);\n                        for (var Cd = -bb.x, Dd = -bb.y, Od = new N, pn = hg.length, oh = 0; oh < pn; oh++)\n                            for (var ph = hg[oh], qh = ph.xm.x,\n                                    rh = ph.xm.y, kg = ph.angle, Ed = 0; 4 > Ed; Ed++) {\n                                switch (Ed) {\n                                    case 0:\n                                        bb.h(Cd, Dd);\n                                        break;\n                                    case 1:\n                                        bb.h(Cd + jg, Dd);\n                                        break;\n                                    case 2:\n                                        bb.h(Cd, Dd + lc);\n                                        break;\n                                    case 3:\n                                        bb.h(Cd + jg, Dd + lc)\n                                }\n                                bb.rotate(kg + Qb.angle);\n                                bb.offset(qh, rh);\n                                0 === oh && 0 === Ed ? Od.h(bb.x, bb.y, 0, 0) : Od.He(bb);\n                                bb.offset(-qh, -rh);\n                                bb.rotate(-kg - Qb.angle)\n                            }\n                        I.free(bb);\n                        null !== Wj.Zg && Wj.Zg.push(Od);\n                        ec(ui, Od.x, Od.y, Od.width, Od.height)\n                    } else if (Qb instanceof Wg) {\n                        var Xc = a,\n                            he = e;\n                        null === Xc.vh && (Xc.vh = new Wg);\n                        var qb = Xc.vh;\n                        Tm(qb, Qb);\n                        var vi = Qb.alignmentFocus;\n                        vi.jc() && (vi = xc);\n                        for (var md =\n                                Qb.segmentOrientation, qn = Qb.segmentOffset, ie = new N, Na = 0, Fd = 0, mc = 0, Fe = 0, Df = hg.length, bf = 0; bf < Df; bf++) {\n                            var Pd = hg[bf];\n                            Na = Pd.xm.x;\n                            Fd = Pd.xm.y;\n                            mc = Pd.angle;\n                            md !== bg && (Fe = S.computeAngle(md, mc), qb.Yb = Fe);\n                            qb.text = Pd.text || \"\";\n                            qb.measure(Infinity, Infinity, 0, 0);\n                            var Ge = qb.measuredBounds,\n                                cf = qb.naturalBounds,\n                                He = cf.width,\n                                Ie = cf.height,\n                                nd = rd.alloc();\n                            nd.reset();\n                            nd.translate(-Ge.x, -Ge.y);\n                            nd.scale(qb.scale, qb.scale);\n                            nd.rotate(md === bg ? qb.angle : mc, He / 2, Ie / 2);\n                            md !== Nm && md !== Om || nd.rotate(90, He / 2, Ie / 2);\n                            md !== Pm && md !== Qm || nd.rotate(-90,\n                                He / 2, Ie / 2);\n                            md === Rm && (45 < mc && 135 > mc || 225 < mc && 315 > mc) && nd.rotate(-mc, He / 2, Ie / 2);\n                            var lg = N.allocAt(0, 0, He, Ie),\n                                je = I.alloc();\n                            je.dj(lg, vi);\n                            nd.ra(je);\n                            var rn = -je.x,\n                                sn = -je.y,\n                                od = I.alloc();\n                            od.assign(qn);\n                            isNaN(od.x) && (od.x = He / 2 + 3);\n                            isNaN(od.y) && (od.y = -(Ie / 2 + 3));\n                            od.rotate(mc);\n                            Na += od.x + rn;\n                            Fd += od.y + sn;\n                            var mg = new N(Na, Fd, Ge.width, Ge.height),\n                                tn = new N(Ge.x, Ge.y, Ge.width, Ge.height),\n                                sh = new N(cf.x, cf.y, cf.width, cf.height);\n                            Pd.Zz = Fe;\n                            Pd.lineCount = qb.lineCount;\n                            Pd.lines = [qb.pb, qb.ti, qb.ge, qb.te, qb.Qb, qb.fb, qb.ee];\n                            Pd.actualBounds =\n                                mg;\n                            Pd.measuredBounds = tn;\n                            Pd.naturalBounds = sh;\n                            0 === bf ? ie.assign(mg) : ie.Hc(mg);\n                            I.free(od);\n                            I.free(je);\n                            N.free(lg);\n                            rd.free(nd)\n                        }\n                        null !== Xc.Zg && Xc.Zg.push(ie);\n                        ec(he, ie.x, ie.y, ie.width, ie.height)\n                    }\n                    lj(Qb, !1)\n                }\n            }\n    };\n    Sm.prototype.arrange = function (a, b, c) {\n        if (null !== a.Zg) {\n            var d = a.zb(),\n                e = a.uj;\n            if (null !== e) {\n                var f = a.Zg,\n                    g = 0,\n                    h = f[g];\n                g++;\n                null !== d && d.arrange(h.x - c.x, h.y - c.y, h.width, h.height);\n                for (var k = b.length, l = 0; l < k; l++) {\n                    var m = b[l];\n                    h = e[l];\n                    m.visible && m !== d && 0 !== h.length && (h = f[g], g++, m.arrange(h.x - c.x, h.y - c.y, h.width, h.height))\n                }\n                a.Zg = null\n            }\n        }\n    };\n    Sm.prototype.bc = function (a, b, c) {\n        var d = c.ni;\n        c.ni = !0;\n        var e = a.naturalBounds,\n            f = e.width;\n        e = e.height;\n        b.save();\n        b.beginPath();\n        b.rect(-1, -1, f + 1, e + 1);\n        b.clip();\n        f = a.zb();\n        f.bc(b, c);\n        e = a.uf() * c.scale;\n        0 >= e && (e = 1);\n        for (var g = f.actualBounds, h = a.W.j, k = a.uj, l = h.length, m = 0; m < l; m++) {\n            var n = h[m],\n                p = k[m],\n                r = p.length;\n            if (n.visible && n !== f && 0 !== p.length)\n                if (n instanceof Lf) {\n                    if (!(2 > a.graduatedTickUnit * n.interval * f.geometry.flattenedTotalLength / a.graduatedRange * e)) {\n                        var q = n.measuredBounds,\n                            u = n.strokeWidth * n.scale,\n                            v = n.alignmentFocus;\n                        v.jc() &&\n                            (v = xc);\n                        for (var w = 0; w < r; w++) {\n                            var y = p[w].xm,\n                                z = p[w].angle,\n                                A = v,\n                                C = n.kb;\n                            C.reset();\n                            C.translate(y.x + g.x, y.y + g.y);\n                            C.rotate(z + n.angle, 0, 0);\n                            C.translate(-q.width * A.x + A.offsetX + u / 2, -q.height * A.y + A.offsetY + u / 2);\n                            C.scale(n.scale, n.scale);\n                            Al(n, !1);\n                            n.Qh.set(n.kb);\n                            n.Wk = n.scale;\n                            Bl(n, !1);\n                            n.bc(b, c);\n                            n.kb.reset()\n                        }\n                    }\n                } else if (n instanceof Wg)\n                for (null === a.vh && (a.vh = new Wg), q = a.vh, Tm(q, n), n = 0; n < r; n++) u = p[n], u.actualBounds && u.measuredBounds && u.naturalBounds && (q.Tb = u.text || \"\", q.Yb = u.Zz || 0, q.Nc = u.lineCount || 0, v = u.lines, void 0 !==\n                    v && (q.pb = v[0], q.ti = v[1], q.ge = v[2], q.te = v[3], q.Qb = v[4], q.fb = v[5], q.ee = v[6]), u.naturalBounds && (q.oc = u.naturalBounds), u.actualBounds && (v = u.actualBounds, q.arrange(v.x, v.y, v.width, v.height)), v = u.actualBounds, q.arrange(v.x, v.y, v.width, v.height), w = u.measuredBounds, u = u.naturalBounds, y = q.kb, y.reset(), y.translate(v.x + g.x, v.y + g.y), y.translate(-w.x, -w.y), il(q, y, u.x, u.y, u.width, u.height), Al(q, !1), q.Qh.set(q.kb), q.Wk = q.scale, Bl(q, !1), q.bc(b, c))\n        }\n        c.ni = d;\n        b.restore();\n        b.sc(!0)\n    };\n\n    function X(a) {\n        Y.call(this);\n        this.pa = void 0 === a ? X.Position : a;\n        null === this.pa && B(\"Panel type not specified or PanelLayout not loaded: \" + a);\n        this.W = new E;\n        this.bb = sc;\n        this.pa === X.Grid && (this.isAtomic = !0);\n        this.un = Zc;\n        this.Qf = Vk;\n        this.pa === X.Table && Um(this);\n        this.Yp = Bg;\n        this.Sn = Ob;\n        this.Tn = Fb;\n        this.Pn = 0;\n        this.On = 100;\n        this.Rn = 10;\n        this.Qn = 0;\n        this.ci = this.hb = this.$g = this.Zg = this.uj = null;\n        this.io = NaN;\n        this.le = this.si = null;\n        this.ql = \"category\";\n        this.Jd = null;\n        this.vg = new N(NaN, NaN, NaN, NaN);\n        this.vh = this.rp = this.Hi = null;\n        this.Jg = \"\"\n    }\n    la(X, Y);\n\n    function Um(a) {\n        a.nj = sc;\n        a.Rg = 1;\n        a.ii = null;\n        a.hi = null;\n        a.Qg = 1;\n        a.Pg = null;\n        a.gi = null;\n        a.rb = [];\n        a.mb = [];\n        a.Mj = Vm;\n        a.kj = Vm;\n        a.Ki = 0;\n        a.vi = 0\n    }\n    X.prototype.cloneProtected = function (a) {\n        Y.prototype.cloneProtected.call(this, a);\n        a.pa = this.pa;\n        a.bb = this.bb.G();\n        a.un = this.un.G();\n        a.Qf = this.Qf;\n        if (a.pa === X.Table) {\n            a.nj = this.nj.G();\n            a.Rg = this.Rg;\n            a.ii = this.ii;\n            a.hi = this.hi;\n            a.Qg = this.Qg;\n            a.Pg = this.Pg;\n            a.gi = this.gi;\n            var b = [];\n            if (0 < this.rb.length)\n                for (var c = this.rb, d = c.length, e = 0; e < d; e++)\n                    if (void 0 !== c[e]) {\n                        var f = c[e].copy();\n                        f.cj(a);\n                        b[e] = f\n                    } a.rb = b;\n            b = [];\n            if (0 < this.mb.length)\n                for (c = this.mb, d = c.length, e = 0; e < d; e++) void 0 !== c[e] && (f = c[e].copy(), f.cj(a), b[e] = f);\n            a.mb = b;\n            a.Mj =\n                this.Mj;\n            a.kj = this.kj;\n            a.Ki = this.Ki;\n            a.vi = this.vi\n        }\n        a.Yp = this.Yp;\n        a.Sn = this.Sn.G();\n        a.Tn = this.Tn.G();\n        a.Pn = this.Pn;\n        a.On = this.On;\n        a.Rn = this.Rn;\n        a.Qn = this.Qn;\n        a.uj = this.uj;\n        a.$g = this.$g;\n        a.hb = this.hb;\n        a.ci = this.ci;\n        a.io = this.io;\n        a.si = this.si;\n        a.le = this.le;\n        a.ql = this.ql;\n        a.vg.assign(this.vg);\n        a.Jg = this.Jg;\n        null !== this.rp && (a.rp = this.rp)\n    };\n    X.prototype.sf = function (a) {\n        Y.prototype.sf.call(this, a);\n        a.W = this.W;\n        for (var b = a.W.j, c = b.length, d = 0; d < c; d++) b[d].ng = a;\n        a.Hi = null\n    };\n    X.prototype.copy = function () {\n        var a = Y.prototype.copy.call(this);\n        if (null !== a) {\n            for (var b = this.W.j, c = b.length, d = 0; d < c; d++) {\n                var e = b[d].copy();\n                e.cj(a);\n                e.Jj = null;\n                var f = a.W,\n                    g = f.count;\n                f.Kb(g, e);\n                f = a.part;\n                if (null !== f) {\n                    f.Fj = null;\n                    null !== e.portId && f instanceof W && (f.Ih = !0);\n                    var h = a.diagram;\n                    null !== h && h.undoManager.isUndoingRedoing || f.Ya(te, \"elements\", a, null, e, null, g)\n                }\n            }\n            return a\n        }\n        return null\n    };\n    t = X.prototype;\n    t.toString = function () {\n        return \"Panel(\" + this.type + \")#\" + lb(this)\n    };\n    t.To = function (a) {\n        Y.prototype.To.call(this, a);\n        for (var b = this.W.j, c = b.length, d = 0; d < c; d++) b[d].To(a)\n    };\n    t.Qi = function (a, b) {\n        if (this.pa === X.Grid) this.pa.bc(this, a, b);\n        else if (this.pa === X.Graduated) this.pa.bc(this, a, b);\n        else {\n            this.pa === X.Table && (a.lineCap = \"butt\", Wm(this, a, !0, this.rb, !0), Wm(this, a, !1, this.mb, !0), Xm(this, a, !0, this.rb), Xm(this, a, !1, this.mb), Wm(this, a, !0, this.rb, !1), Wm(this, a, !1, this.mb, !1));\n            var c = this.isClipping && this.pa === X.Spot;\n            c && a.save();\n            for (var d = this.zb(), e = this.W.j, f = e.length, g = 0; g < f; g++) {\n                var h = e[g];\n                c && h === d && (a.clipInsteadOfFill = !0);\n                h.bc(a, b);\n                c && h === d && (a.clipInsteadOfFill = !1)\n            }\n            c && (a.restore(),\n                a.sc(!0))\n        }\n    };\n\n    function Xm(a, b, c, d) {\n        for (var e = d.length, f = a.actualBounds, g = a.naturalBounds, h = !0, k = 0; k < e; k++) {\n            var l = d[k];\n            if (void 0 !== l)\n                if (h) h = !1;\n                else if (0 !== l.actual) {\n                if (c) {\n                    if (l.position > f.height) continue\n                } else if (l.position > f.width) continue;\n                var m = l.separatorStrokeWidth;\n                isNaN(m) && (m = c ? a.Rg : a.Qg);\n                var n = l.separatorStroke;\n                null === n && (n = c ? a.ii : a.Pg);\n                if (0 !== m && null !== n) {\n                    ii(a, b, n, !1, !1, g, f);\n                    n = !1;\n                    var p = l.separatorDashArray;\n                    null === p && (p = c ? a.hi : a.gi);\n                    null !== p && (n = !0, b.ht(p, 0));\n                    b.beginPath();\n                    p = l.position + m;\n                    c ? p > f.height && (m -=\n                        p - f.height) : p > f.width && (m -= p - f.width);\n                    l = l.position + m / 2;\n                    b.lineWidth = m;\n                    m = a.bb;\n                    c ? (l += m.top, p = f.width - m.right, b.moveTo(m.left, l), b.lineTo(p, l)) : (l += m.left, p = f.height - m.bottom, b.moveTo(l, m.top), b.lineTo(l, p));\n                    b.stroke();\n                    n && b.ft()\n                }\n            }\n        }\n    }\n\n    function Wm(a, b, c, d, e) {\n        for (var f = d.length, g = a.actualBounds, h = a.naturalBounds, k = 0; k < f; k++) {\n            var l = d[k];\n            if (void 0 !== l && null !== l.background && l.coversSeparators !== e && 0 !== l.actual) {\n                var m = c ? g.height : g.width;\n                if (!(l.position > m)) {\n                    var n = l.uc(),\n                        p = l.separatorStrokeWidth;\n                    isNaN(p) && (p = c ? a.Rg : a.Qg);\n                    var r = l.separatorStroke;\n                    null === r && (r = c ? a.ii : a.Pg);\n                    null === r && (p = 0);\n                    n -= p;\n                    p = l.position + p;\n                    n += l.actual;\n                    p + n > m && (n = m - p);\n                    0 >= n || (m = a.bb, ii(a, b, l.background, !0, !1, h, g), c ? b.fillRect(m.left, p + m.top, g.width - (m.left + m.right), n) : b.fillRect(p +\n                        m.left, m.top, n, g.height - (m.top + m.bottom)))\n                }\n            }\n        }\n    }\n\n    function dk(a) {\n        return \"LineV\" === a || \"BarV\" === a\n    }\n    t.hk = function (a, b, c, d, e) {\n        var f = this.$d(),\n            g = this.transform,\n            h = 1 / (g.m11 * g.m22 - g.m12 * g.m21),\n            k = g.m22 * h,\n            l = -g.m12 * h,\n            m = -g.m21 * h,\n            n = g.m11 * h,\n            p = h * (g.m21 * g.dy - g.m22 * g.dx),\n            r = h * (g.m12 * g.dx - g.m11 * g.dy);\n        if (null !== this.areaBackground) return g = this.actualBounds, J.Uc(g.left, g.top, g.right, g.bottom, a, b, c, d, e);\n        if (null !== this.background) return f = a * k + b * m + p, h = a * l + b * n + r, a = c * k + d * m + p, k = c * l + d * n + r, e.h(0, 0), c = this.naturalBounds, f = J.Uc(0, 0, c.width, c.height, f, h, a, k, e), e.transform(g), f;\n        f || (k = 1, m = l = 0, n = 1, r = p = 0);\n        h = a * k + b * m + p;\n        a = a * l + b *\n            n + r;\n        k = c * k + d * m + p;\n        c = c * l + d * n + r;\n        e.h(k, c);\n        d = (k - h) * (k - h) + (c - a) * (c - a);\n        l = !1;\n        n = this.W.j;\n        r = n.length;\n        m = I.alloc();\n        p = null;\n        b = Infinity;\n        var q = null,\n            u = this.isClipping && this.pa === X.Spot;\n        u && (q = I.alloc(), p = this.zb(), (l = p.hk(h, a, k, c, q)) && (b = (h - q.x) * (h - q.x) + (a - q.y) * (a - q.y)));\n        for (var v = 0; v < r; v++) {\n            var w = n[v];\n            w.visible && w !== p && w.hk(h, a, k, c, m) && (l = !0, w = (h - m.x) * (h - m.x) + (a - m.y) * (a - m.y), w < d && (d = w, e.set(m)))\n        }\n        u && (b > d && e.set(q), I.free(q));\n        I.free(m);\n        f && e.transform(g);\n        return l\n    };\n    t.o = function (a) {\n        if (!0 !== qj(this)) {\n            Y.prototype.o.call(this, a);\n            a = null;\n            if (this.pa === X.Auto || this.pa === X.Link) a = this.zb();\n            for (var b = this.W.j, c = b.length, d = 0; d < c; d++) {\n                var e = b[d];\n                (e === a || e.isPanelMain) && e.o(!0);\n                if (!e.desiredSize.v()) {\n                    var f = kl(e, !1);\n                    (e instanceof xg || e instanceof X || e instanceof Wg || f !== zg) && e.o(!0)\n                }\n            }\n        }\n    };\n    t.om = function () {\n        if (!1 === qj(this)) {\n            lj(this, !0);\n            ll(this, !0);\n            for (var a = this.W.j, b = a.length, c = 0; c < b; c++) a[c].om()\n        }\n    };\n    t.ml = function () {\n        if (0 !== (this.F & 2048) === !1) {\n            Al(this, !0);\n            Bl(this, !0);\n            for (var a = this.W.j, b = a.length, c = 0; c < b; c++) a[c].Fv()\n        }\n    };\n    t.Fv = function () {\n        Bl(this, !0);\n        for (var a = this.W.j, b = a.length, c = 0; c < b; c++) a[c].Fv()\n    };\n    t.sm = function (a, b, c, d) {\n        var e = this.vg;\n        e.h(0, 0, 0, 0);\n        var f = this.desiredSize,\n            g = this.minSize;\n        void 0 === c && (c = g.width, d = g.height);\n        c = Math.max(c, g.width);\n        d = Math.max(d, g.height);\n        var h = this.maxSize;\n        isNaN(f.width) || (a = Math.min(f.width, h.width));\n        isNaN(f.height) || (b = Math.min(f.height, h.height));\n        a = Math.max(c, a);\n        b = Math.max(d, b);\n        var k = this.bb;\n        a = Math.max(a - k.left - k.right, 0);\n        b = Math.max(b - k.top - k.bottom, 0);\n        var l = this.W.j;\n        0 !== l.length && this.pa.measure(this, a, b, l, e, c, d);\n        a = e.width + k.left + k.right;\n        k = e.height + k.top + k.bottom;\n        isFinite(f.width) && (a = f.width);\n        isFinite(f.height) && (k = f.height);\n        a = Math.min(h.width, a);\n        k = Math.min(h.height, k);\n        a = Math.max(g.width, a);\n        k = Math.max(g.height, k);\n        a = Math.max(c, a);\n        k = Math.max(d, k);\n        Vb(e, a, k);\n        Vb(this.naturalBounds, a, k);\n        hl(this, 0, 0, a, k)\n    };\n    t.zb = function () {\n        if (null === this.Hi) {\n            var a = this.W.j,\n                b = a.length;\n            if (0 === b) return null;\n            for (var c = 0; c < b; c++) {\n                var d = a[c];\n                if (!0 === d.isPanelMain) return this.Hi = d\n            }\n            this.Hi = a[0]\n        }\n        return this.Hi\n    };\n\n    function wm(a) {\n        return null !== a.part ? a.part.locationObject : null\n    }\n    t.Fh = function (a, b, c, d) {\n        var e = this.W.j;\n        this.actualBounds.h(a, b, c, d);\n        if (0 !== e.length) {\n            if (!this.desiredSize.v()) {\n                a = kl(this, !0);\n                var f = this.measuredBounds;\n                b = f.width;\n                f = f.height;\n                var g = this.fh,\n                    h = g.left + g.right;\n                g = g.top + g.bottom;\n                b === c && f === d && (a = zg);\n                switch (a) {\n                    case zg:\n                        if (b > c || f > d) this.o(), this.measure(b > c ? c : b, f > d ? d : f, 0, 0);\n                        break;\n                    case vd:\n                        this.o(!0);\n                        this.measure(c + h, d + g, 0, 0);\n                        break;\n                    case Wk:\n                        this.o(!0);\n                        this.measure(c + h, f + g, 0, 0);\n                        break;\n                    case Xk:\n                        this.o(!0), this.measure(b + h, d + g, 0, 0)\n                }\n            }\n            this.pa.arrange(this, e, this.vg)\n        }\n    };\n    t.Hh = function (a) {\n        var b = this.naturalBounds,\n            c = wm(this);\n        if (fc(0, 0, b.width, b.height, a.x, a.y)) {\n            b = this.W.j;\n            for (var d = b.length, e = I.allocAt(0, 0); d--;) {\n                var f = b[d];\n                if (f.visible || f === c)\n                    if (zb(e.set(a), f.transform), f.aa(e)) return I.free(e), !0\n            }\n            I.free(e);\n            return null === this.gb && null === this.dc ? !1 : !0\n        }\n        return !1\n    };\n    t.it = function (a) {\n        if (this.Jk === a) return this;\n        for (var b = this.W.j, c = b.length, d = 0; d < c; d++) {\n            var e = b[d].it(a);\n            if (null !== e) return e\n        }\n        return null\n    };\n    t.Km = function (a, b) {\n        b(this, a);\n        if (a instanceof X) {\n            a = a.W.j;\n            for (var c = a.length, d = 0; d < c; d++) this.Km(a[d], b)\n        }\n    };\n\n    function Dj(a, b) {\n        Ym(a, a, b)\n    }\n\n    function Ym(a, b, c) {\n        c(b);\n        b = b.W.j;\n        for (var d = b.length, e = 0; e < d; e++) {\n            var f = b[e];\n            f instanceof X && Ym(a, f, c)\n        }\n    }\n\n    function Zm(a, b) {\n        $m(a, a, b)\n    }\n\n    function $m(a, b, c) {\n        c(b);\n        if (b instanceof X) {\n            b = b.W.j;\n            for (var d = b.length, e = 0; e < d; e++) $m(a, b[e], c)\n        }\n    }\n    t.hm = function (a) {\n        return an(this, this, a)\n    };\n\n    function an(a, b, c) {\n        if (c(b)) return b;\n        if (b instanceof X) {\n            b = b.W.j;\n            for (var d = b.length, e = 0; e < d; e++) {\n                var f = an(a, b[e], c);\n                if (null !== f) return f\n            }\n        }\n        return null\n    }\n    t.Xa = function (a) {\n        if (this.name === a) return this;\n        var b = this.W.j,\n            c = b.length;\n        null === this.si && null === this.le || (c = bn(this));\n        for (var d = 0; d < c; d++) {\n            var e = b[d];\n            if (e instanceof X) {\n                var f = e.Xa(a);\n                if (null !== f) return f\n            }\n            if (e.name === a) return e\n        }\n        return null\n    };\n\n    function cn(a) {\n        a = a.W.j;\n        for (var b = a.length, c = 0, d = 0; d < b; d++) {\n            var e = a[d];\n            if (e instanceof X) c = Math.max(c, cn(e));\n            else if (e instanceof Lf) {\n                a: {\n                    switch (e.Zk) {\n                        case \"None\":\n                        case \"Square\":\n                        case \"Ellipse\":\n                        case \"Circle\":\n                        case \"LineH\":\n                        case \"LineV\":\n                        case \"FramedRectangle\":\n                        case \"RoundedRectangle\":\n                        case \"Line1\":\n                        case \"Line2\":\n                        case \"Border\":\n                        case \"Cube1\":\n                        case \"Cube2\":\n                        case \"Junction\":\n                        case \"Cylinder1\":\n                        case \"Cylinder2\":\n                        case \"Cylinder3\":\n                        case \"Cylinder4\":\n                        case \"PlusLine\":\n                        case \"XLine\":\n                        case \"ThinCross\":\n                        case \"ThickCross\":\n                            e = 0;\n                            break a\n                    }\n                    e =\n                    e.th / 2 * e.Oj * e.uf()\n                }\n                c = Math.max(c, e)\n            }\n        }\n        return c\n    }\n    t.$d = function () {\n        return !(this.type === X.TableRow || this.type === X.TableColumn)\n    };\n    t.Ub = function (a, b, c) {\n        if (!1 === this.pickable) return null;\n        void 0 === b && (b = null);\n        void 0 === c && (c = null);\n        if (rj(this)) return null;\n        var d = this.naturalBounds,\n            e = 1 / this.uf(),\n            f = this.$d(),\n            g = f ? a : zb(I.allocAt(a.x, a.y), this.transform),\n            h = this.diagram,\n            k = 10,\n            l = 5;\n        null !== h && (k = h.mm(\"extraTouchArea\"), l = k / 2);\n        if (fc(-(l * e), -(l * e), d.width + k * e, d.height + k * e, g.x, g.y)) {\n            if (!this.isAtomic) {\n                e = this.W.j;\n                var m = e.length;\n                h = I.alloc();\n                l = (k = this.isClipping && this.pa === X.Spot) ? this.zb() : null;\n                if (k && (l.$d() ? zb(h.set(a), l.transform) : h.set(a), !l.aa(h))) return I.free(h),\n                    f || I.free(g), null;\n                for (var n = wm(this); m--;) {\n                    var p = e[m];\n                    if (p.visible || p === n)\n                        if (p.$d() ? zb(h.set(a), p.transform) : h.set(a), !k || p !== l) {\n                            var r = null;\n                            p instanceof X ? r = p.Ub(h, b, c) : !0 === p.pickable && p.aa(h) && (r = p);\n                            if (null !== r && (null !== b && (r = b(r)), null !== r && (null === c || c(r)))) return I.free(h), f || I.free(g), r\n                        }\n                }\n                I.free(h)\n            }\n            if (null === this.background && null === this.areaBackground) return f || I.free(g), null;\n            a = fc(0, 0, d.width, d.height, g.x, g.y) ? this : null;\n            f || I.free(g);\n            return a\n        }\n        f || I.free(g);\n        return null\n    };\n    t.Ti = function (a, b, c, d) {\n        if (!1 === this.pickable) return !1;\n        void 0 === b && (b = null);\n        void 0 === c && (c = null);\n        var e = this.naturalBounds,\n            f = this.$d(),\n            g = f ? a : zb(I.allocAt(a.x, a.y), this.transform);\n        e = fc(0, 0, e.width, e.height, g.x, g.y);\n        if (this.type === X.TableRow || this.type === X.TableColumn || e) {\n            if (!this.isAtomic) {\n                for (var h = this.W.j, k = h.length, l = I.alloc(), m = wm(this); k--;) {\n                    var n = h[k];\n                    if (n.visible || n === m) {\n                        n.$d() ? zb(l.set(a), n.transform) : l.set(a);\n                        var p = n;\n                        n = n instanceof X ? n : null;\n                        (null !== n ? n.Ti(l, b, c, d) : p.aa(l)) && !1 !== p.pickable &&\n                            (null !== b && (p = b(p)), null === p || null !== c && !c(p) || d.add(p))\n                    }\n                }\n                I.free(l)\n            }\n            f || I.free(g);\n            return e && (null !== this.background || null !== this.areaBackground)\n        }\n        f || I.free(g);\n        return !1\n    };\n    t.tf = function (a, b, c, d, e, f) {\n        if (!1 === this.pickable) return !1;\n        void 0 === b && (b = null);\n        void 0 === c && (c = null);\n        var g = f;\n        void 0 === f && (g = rd.alloc(), g.reset());\n        g.multiply(this.transform);\n        if (this.Gh(a, g)) return dn(this, b, c, e), void 0 === f && rd.free(g), !0;\n        if (this.Gc(a, g)) {\n            if (!this.isAtomic)\n                for (var h = wm(this), k = this.W.j, l = k.length; l--;) {\n                    var m = k[l];\n                    if (m.visible || m === h) {\n                        var n = m.actualBounds,\n                            p = this.naturalBounds;\n                        if (!(n.x > p.width || n.y > p.height || 0 > n.x + n.width || 0 > n.y + n.height)) {\n                            n = m;\n                            m = m instanceof X ? m : null;\n                            p = rd.alloc();\n                            p.set(g);\n                            if (null !== m ? m.tf(a, b, c, d, e, p) : jl(n, a, d, p)) null !== b && (n = b(n)), null === n || null !== c && !c(n) || e.add(n);\n                            rd.free(p)\n                        }\n                    }\n                }\n            void 0 === f && rd.free(g);\n            return d\n        }\n        void 0 === f && rd.free(g);\n        return !1\n    };\n\n    function dn(a, b, c, d) {\n        for (var e = a.W.j, f = e.length; f--;) {\n            var g = e[f];\n            if (g.visible) {\n                var h = g.actualBounds,\n                    k = a.naturalBounds;\n                h.x > k.width || h.y > k.height || 0 > h.x + h.width || 0 > h.y + h.height || (g instanceof X && dn(g, b, c, d), null !== b && (g = b(g)), null === g || null !== c && !c(g) || d.add(g))\n            }\n        }\n    }\n    t.Ag = function (a, b, c, d, e, f) {\n        if (!1 === this.pickable) return !1;\n        void 0 === c && (c = null);\n        void 0 === d && (d = null);\n        var g = this.naturalBounds,\n            h = this.$d(),\n            k = h ? a : zb(I.allocAt(a.x, a.y), this.transform),\n            l = h ? b : zb(I.allocAt(b.x, b.y), this.transform),\n            m = k.Ae(l),\n            n = 0 < k.x && k.x < g.width && 0 < k.y && k.y < g.height || Ab(k.x, k.y, 0, 0, 0, g.height) <= m || Ab(k.x, k.y, 0, g.height, g.width, g.height) <= m || Ab(k.x, k.y, g.width, g.height, g.width, 0) <= m || Ab(k.x, k.y, g.width, 0, 0, 0) <= m;\n        g = k.dd(0, 0) <= m && k.dd(0, g.height) <= m && k.dd(g.width, 0) <= m && k.dd(g.width, g.height) <=\n            m;\n        h || (I.free(k), I.free(l));\n        if (n) {\n            if (!this.isAtomic) {\n                k = I.alloc();\n                l = I.alloc();\n                m = wm(this);\n                for (var p = this.W.j, r = p.length; r--;) {\n                    var q = p[r];\n                    if (q.visible || q === m) {\n                        var u = q.actualBounds,\n                            v = this.naturalBounds;\n                        if (!h || !(u.x > v.width || u.y > v.height || 0 > u.x + u.width || 0 > u.y + u.height))\n                            if (q.$d() ? (u = q.transform, zb(k.set(a), u), zb(l.set(b), u)) : (k.set(a), l.set(b)), u = q, q = q instanceof X ? q : null, null !== q ? q.Ag(k, l, c, d, e, f) : u.Lx(k, l, e)) null !== c && (u = c(u)), null === u || null !== d && !d(u) || f.add(u)\n                    }\n                }\n                I.free(k);\n                I.free(l)\n            }\n            return e ? n : g\n        }\n        return !1\n    };\n\n    function Bm(a) {\n        var b = null;\n        a instanceof Lf && (b = a.spot1, b === Zc && (b = null), a = a.geometry, null !== a && null === b && (b = a.spot1));\n        null === b && (b = vc);\n        return b\n    }\n\n    function Cm(a) {\n        var b = null;\n        a instanceof Lf && (b = a.spot2, b === Zc && (b = null), a = a.geometry, null !== a && null === b && (b = a.spot2));\n        null === b && (b = Gc);\n        return b\n    }\n    t.add = function (a) {\n        this.Kb(this.W.count, a)\n    };\n    t.L = function (a) {\n        return this.W.L(a)\n    };\n    t.Kb = function (a, b) {\n        b instanceof U && B(\"Cannot add a Part to a Panel: \" + b + \"; use a Panel instead\");\n        if (this === b || this.Dg(b)) this === b && B(\"Cannot make a Panel contain itself: \" + this.toString()), B(\"Cannot make a Panel indirectly contain itself: \" + this.toString() + \" already contains \" + b.toString());\n        var c = b.panel;\n        null !== c && c !== this && B(\"Cannot add a GraphObject that already belongs to another Panel to this Panel: \" + b.toString() + \", already contained by \" + c.toString() + \", cannot be shared by this Panel: \" + this.toString());\n        this.pa !== X.Grid || b instanceof Lf || B(\"Can only add Shapes to a Grid Panel, not: \" + b);\n        this.pa !== X.Graduated || b instanceof Lf || b instanceof Wg || B(\"Can only add Shapes or TextBlocks to a Graduated Panel, not: \" + b);\n        b.cj(this);\n        b.Jj = null;\n        if (null !== this.itemArray) {\n            var d = b.data;\n            null !== d && \"object\" === typeof d && (null === this.Jd && (this.Jd = new H), this.Jd.add(d, b))\n        }\n        var e = this.W;\n        d = -1;\n        if (c === this) {\n            for (var f = -1, g = this.W.j, h = g.length, k = 0; k < h; k++)\n                if (g[k] === b) {\n                    f = k;\n                    break\n                } if (-1 !== f) {\n                if (f === a || f + 1 >= e.count && a >= e.count) return;\n                e.lb(f);\n                d = f\n            } else B(\"element \" + b.toString() + \" has panel \" + c.toString() + \" but is not contained by it.\")\n        }\n        if (0 > a || a > e.count) a = e.count;\n        e.Kb(a, b);\n        if (0 === a || b.isPanelMain) this.Hi = null;\n        qj(this) || this.o();\n        b.o(!1);\n        null !== b.portId ? this.Ih = !0 : b instanceof X && !0 === b.Ih && (this.Ih = !0);\n        this.$g = null;\n        c = this.part;\n        null !== c && (c.Fj = null, c.gh = NaN, this.Ih && c instanceof W && (c.Ih = !0), c.Ih && c instanceof W && (c.rc = null), e = this.diagram, null !== e && e.undoManager.isUndoingRedoing || (-1 !== d && c.Ya(ue, \"elements\", this, b, null, d, null), c.Ya(te,\n            \"elements\", this, null, b, null, a), this.Eg() || en(this, b, !1)))\n    };\n\n    function fn(a, b) {\n        a.F = b ? a.F | 16777216 : a.F & -16777217\n    }\n    t.remove = function (a) {\n        for (var b = this.W.j, c = b.length, d = -1, e = 0; e < c; e++)\n            if (b[e] === a) {\n                d = e;\n                break\n            } - 1 !== d && this.Fc(d, !0)\n    };\n    t.lb = function (a) {\n        0 <= a && this.Fc(a, !0)\n    };\n    t.Fc = function (a, b) {\n        var c = this.W,\n            d = c.L(a);\n        d.Jj = null;\n        d.cj(null);\n        if (null !== this.Jd) {\n            var e = d.data;\n            \"object\" === typeof e && this.Jd.remove(e)\n        }\n        c.lb(a);\n        lj(this, !1);\n        this.o();\n        this.Hi === d && (this.Hi = null);\n        this.$g = null;\n        var f = this.part;\n        null !== f && (f.Fj = null, f.gh = NaN, f.Lb(), f instanceof W && (d instanceof X ? d.Km(d, function (a, c) {\n            Sl(f, c, b)\n        }) : Sl(f, d, b)), c = this.diagram, null !== c && c.undoManager.isUndoingRedoing || f.Ya(ue, \"elements\", this, d, null, a, null))\n    };\n    X.prototype.getRowDefinition = function (a) {\n        0 > a && va(a, \">= 0\", X, \"getRowDefinition:idx\");\n        a = Math.round(a);\n        var b = this.rb;\n        if (void 0 === b) return null;\n        if (void 0 === b[a]) {\n            var c = new Rj;\n            c.cj(this);\n            c.isRow = !0;\n            c.index = a;\n            b[a] = c\n        }\n        return b[a]\n    };\n    X.prototype.Yv = function (a) {\n        0 > a && va(a, \">= 0\", X, \"removeRowDefinition:idx\");\n        a = Math.round(a);\n        var b = this.rb;\n        void 0 !== b && (this.Ya(ue, \"coldefs\", this, b[a], null, a, null), b[a] && delete b[a], this.o())\n    };\n    X.prototype.getColumnDefinition = function (a) {\n        0 > a && va(a, \">= 0\", X, \"getColumnDefinition:idx\");\n        a = Math.round(a);\n        var b = this.mb;\n        if (void 0 === b) return null;\n        if (void 0 === b[a]) {\n            var c = new Rj;\n            c.cj(this);\n            c.isRow = !1;\n            c.index = a;\n            b[a] = c\n        }\n        return b[a]\n    };\n    t = X.prototype;\n    t.Wv = function (a) {\n        0 > a && va(a, \">= 0\", X, \"removeColumnDefinition:idx\");\n        a = Math.round(a);\n        var b = this.mb;\n        void 0 !== b && (this.Ya(ue, \"coldefs\", this, b[a], null, a, null), b[a] && delete b[a], this.o())\n    };\n    t.pz = function (a) {\n        if (0 > a || this.type !== X.Table) return -1;\n        for (var b = 0, c = this.rb, d = c.length, e = this.Ki; e < d; e++) {\n            var f = c[e];\n            if (void 0 !== f && (b += f.total, a < b)) break\n        }\n        return e\n    };\n    t.hz = function (a) {\n        if (0 > a || this.type !== X.Table) return -1;\n        for (var b = 0, c = this.mb, d = c.length, e = this.vi; e < d; e++) {\n            var f = c[e];\n            if (void 0 !== f && (b += f.total, a < b)) break\n        }\n        return e\n    };\n    t.Kz = function (a, b) {\n        void 0 === b && (b = new I(NaN, NaN));\n        if (this.type !== X.Graduated) return b.h(NaN, NaN), b;\n        a = Math.min(Math.max(a, this.graduatedMin), this.graduatedMax);\n        var c = this.zb();\n        c.geometry.yv((a - this.graduatedMin) / this.graduatedRange, b);\n        return c.transform.ra(b)\n    };\n    t.Lz = function (a) {\n        if (this.type !== X.Graduated) return NaN;\n        var b = this.zb();\n        b.transform.Vd(a);\n        return b.geometry.Px(a) * this.graduatedRange + this.graduatedMin\n    };\n\n    function Il(a) {\n        a = a.ci;\n        return null !== a && a.s\n    }\n\n    function yg(a) {\n        var b = a.ci;\n        if (null === b) null !== a.data && B(\"Template cannot have .data be non-null: \" + a), a.ci = b = new E;\n        else if (b.s) return;\n        var c = new E;\n        fn(a, !1);\n        a.Km(a, function (a, d) {\n            var e = d.$a;\n            if (null !== e)\n                for (Fl(d, !1), e = e.iterator; e.next();) {\n                    var f = e.value;\n                    f.mode === gn && Fl(d, !0);\n                    var g = f.sourceName;\n                    null !== g && (\"/\" === g && fn(a, !0), g = gl(f, a, d), null !== g && (c.add(g), null === g.Pl && (g.Pl = new E), g.Pl.add(f)));\n                    b.add(f)\n                }\n            if (d instanceof X && d.type === X.Table) {\n                if (0 < d.rb.length)\n                    for (a = d.rb, e = a.length, f = 0; f < e; f++)\n                        if (g = a[f], void 0 !==\n                            g && null !== g.$a)\n                            for (var h = g.$a.iterator; h.next();) {\n                                var k = h.value;\n                                k.bd = g;\n                                k.Qp = 2;\n                                k.Vl = g.index;\n                                b.add(k)\n                            }\n                if (0 < d.mb.length)\n                    for (d = d.mb, a = d.length, e = 0; e < a; e++)\n                        if (f = d[e], void 0 !== f && null !== f.$a)\n                            for (g = f.$a.iterator; g.next();) h = g.value, h.bd = f, h.Qp = 1, h.Vl = f.index, b.add(h)\n            }\n        });\n        for (var d = c.iterator; d.next();) {\n            var e = d.value;\n            if (null !== e.Pl) {\n                Fl(e, !0);\n                for (var f = e.Pl.iterator; f.next();) {\n                    var g = f.value;\n                    null === e.$a && (e.$a = new E);\n                    e.$a.add(g)\n                }\n            }\n            e.Pl = null\n        }\n        for (d = b.iterator; d.next();)\n            if (e = d.value, f = e.bd, null !== f) {\n                e.bd = null;\n                var h =\n                    e.targetProperty,\n                    k = h.indexOf(\".\");\n                0 < k && f instanceof X && (g = h.substring(0, k), h = h.substr(k + 1), k = f.Xa(g), null !== k ? (f = k, e.targetProperty = h) : wa('Warning: unable to find GraphObject named \"' + g + '\" for Binding: ' + e.toString()));\n                f instanceof Rj ? (g = lb(f.panel), e.gj = void 0 === g ? -1 : g, f.panel.Jk = e.gj) : f instanceof Y ? (g = lb(f), e.gj = void 0 === g ? -1 : g, f.Jk = e.gj) : B(\"Unknown type of binding target: \" + f)\n            } b.freeze();\n        a instanceof U && a.Wb() && a.yb()\n    }\n    t.Wy = function () {\n        var a = this.copy();\n        Zm(a, function (a) {\n            a instanceof X && (a.ci = null, a.hb = null);\n            var b = a.$a;\n            null !== b && (a.$a = null, b.each(function (b) {\n                a.bind(b.copy())\n            }));\n            b = a.Kg;\n            null !== b && (a.Kg = null, b.each(function (b) {\n                Jl(a, b.value.copy())\n            }))\n        });\n        return a\n    };\n    t.Ba = function (a) {\n        var b = this.ci;\n        if (null !== b)\n            for (void 0 === a && (a = \"\"), b = b.iterator; b.next();) {\n                var c = b.value,\n                    d = c.sourceProperty;\n                if (\"\" === a || \"\" === d || d === a)\n                    if (d = c.targetProperty, null !== c.converter || \"\" !== d) {\n                        d = this.data;\n                        var e = c.sourceName;\n                        if (null !== e) d = \"\" === e ? this : \"/\" === e ? this : \".\" === e ? this : \"..\" === e ? this : this.Xa(e);\n                        else {\n                            var f = this.diagram;\n                            null !== f && c.isToModel && (d = f.model.modelData)\n                        }\n                        if (null !== d) {\n                            f = this;\n                            var g = c.gj;\n                            if (-1 !== g) {\n                                if (f = this.it(g), null === f) continue\n                            } else null !== c.bd && (f = c.bd);\n                            \"/\" === e ? d = f.part : \".\" ===\n                                e ? d = f : \"..\" === e && (d = f.panel);\n                            e = c.Qp;\n                            if (0 !== e) {\n                                if (!(f instanceof X)) continue;\n                                1 === e ? f = f.getColumnDefinition(c.Vl) : 2 === e && (f = f.getRowDefinition(c.Vl))\n                            }\n                            void 0 !== f && c.tw(f, d)\n                        }\n                    }\n            }\n    };\n\n    function hn(a, b) {\n        a = a.W.j;\n        for (var c = a.length, d = b.length, e = 0, f = null; e < c && !(f = a[e], f instanceof X && null !== f.data);) e++, f = a[e];\n        if (c - e !== d) return !0;\n        if (null === f) return 0 < d;\n        for (var g = 0; e < c && g < d;) {\n            f = a[e];\n            if (!(f instanceof X) || f.data !== b[g]) return !0;\n            e++;\n            g++\n        }\n        return !1\n    }\n\n    function bn(a) {\n        if (a.type === X.Spot || a.type === X.Auto) return Math.min(a.W.length, 1);\n        if (a.type === X.Link) {\n            a = a.W;\n            for (var b = a.length, c = 0; c < b; c++) {\n                var d = a.L(c);\n                if (!(d instanceof Lf && d.isPanelMain)) break\n            }\n            return c\n        }\n        return a.type === X.Table && 0 < a.W.length && (a = a.W.L(0), a.isPanelMain && a instanceof X && (a.type === X.TableRow || a.type === X.TableColumn)) ? 1 : 0\n    }\n    t.Gt = function () {\n        for (var a = bn(this); this.W.length > a;) this.Fc(this.W.length - 1, !1);\n        a = this.itemArray;\n        if (null !== a)\n            for (var b = a.length, c = 0; c < b; c++) jn(this, a[c], c)\n    };\n    t.Kx = function (a) {\n        return void 0 === a || null === a || null === this.Jd ? null : this.Jd.H(a)\n    };\n\n    function jn(a, b, c) {\n        if (!(void 0 === b || null === b || 0 > c)) {\n            var d = kn(a, b),\n                e = a.itemTemplateMap,\n                f = null;\n            null !== e && (f = e.H(d));\n            null === f && (ln || (ln = !0, wa('No item template Panel found for category \"' + d + '\" on ' + a), wa(\"  Using default item template.\"), d = new X, e = new Wg, e.bind(new Ji(\"text\", \"\", Ja)), d.add(e), mn = d), f = mn);\n            d = f;\n            null !== d && (yg(d), d = d.copy(), 0 !== (d.F & 16777216) && (e = a.Ui(), null !== e && fn(e, !0)), \"object\" === typeof b && (null === a.Jd && (a.Jd = new H), a.Jd.add(b, d)), e = c + bn(a), a.Kb(e, d), d.hb = b, yn(a, e, c), d.hb = null, d.data =\n                b)\n        }\n    }\n\n    function yn(a, b, c) {\n        for (a = a.W; b < a.length;) {\n            var d = a.L(b);\n            if (d instanceof X) {\n                var e = b,\n                    f = c;\n                d.type === X.TableRow ? d.row = e : d.type === X.TableColumn && (d.column = e);\n                d.itemIndex = f\n            }\n            b++;\n            c++\n        }\n    }\n\n    function kn(a, b) {\n        if (null === b) return \"\";\n        a = a.ql;\n        if (\"function\" === typeof a) a = a(b);\n        else if (\"string\" === typeof a && \"object\" === typeof b) {\n            if (\"\" === a) return \"\";\n            a = zn(b, a)\n        } else return \"\";\n        if (void 0 === a) return \"\";\n        if (\"string\" === typeof a) return a;\n        B(\"Panel.getCategoryForItemData found a non-string category for \" + b + \": \" + a);\n        return \"\"\n    }\n\n    function en(a, b, c) {\n        var d = b.enabledChanged;\n        null !== d && d(b, c);\n        if (b instanceof X) {\n            b = b.W.j;\n            d = b.length;\n            for (var e = 0; e < d; e++) {\n                var f = b[e];\n                c && f instanceof X && !f.isEnabled || en(a, f, c)\n            }\n        }\n    }\n\n    function An(a, b) {\n        Nl.add(a, b)\n    }\n    ma.Object.defineProperties(X.prototype, {\n        type: {\n            get: function () {\n                return this.pa\n            },\n            set: function (a) {\n                var b = this.pa;\n                b !== a && (this.pa = a, this.pa === X.Grid ? this.isAtomic = !0 : this.pa === X.Table && Um(this), this.o(), this.g(\"type\", b, a))\n            }\n        },\n        elements: {\n            get: function () {\n                return this.W.iterator\n            }\n        },\n        naturalBounds: {\n            get: function () {\n                return this.oc\n            }\n        },\n        padding: {\n            get: function () {\n                return this.bb\n            },\n            set: function (a) {\n                \"number\" ===\n                typeof a ? (0 > a && va(a, \">= 0\", X, \"padding\"), a = new oc(a)) : (0 > a.left && va(a.left, \">= 0\", X, \"padding:value.left\"), 0 > a.right && va(a.right, \">= 0\", X, \"padding:value.right\"), 0 > a.top && va(a.top, \">= 0\", X, \"padding:value.top\"), 0 > a.bottom && va(a.bottom, \">= 0\", X, \"padding:value.bottom\"));\n                var b = this.bb;\n                b.w(a) || (this.bb = a = a.G(), this.o(), this.g(\"padding\", b, a))\n            }\n        },\n        defaultAlignment: {\n            get: function () {\n                return this.un\n            },\n            set: function (a) {\n                var b = this.un;\n                b.w(a) || (this.un = a = a.G(), this.o(), this.g(\"defaultAlignment\",\n                    b, a))\n            }\n        },\n        defaultStretch: {\n            get: function () {\n                return this.Qf\n            },\n            set: function (a) {\n                var b = this.Qf;\n                b !== a && (this.Qf = a, this.o(), this.g(\"defaultStretch\", b, a))\n            }\n        },\n        defaultSeparatorPadding: {\n            get: function () {\n                return void 0 === this.nj ? sc : this.nj\n            },\n            set: function (a) {\n                if (void 0 !== this.nj) {\n                    \"number\" === typeof a && (a = new oc(a));\n                    var b = this.nj;\n                    b.w(a) || (this.nj = a = a.G(), this.o(), this.g(\"defaultSeparatorPadding\", b, a))\n                }\n            }\n        },\n        defaultRowSeparatorStroke: {\n            get: function () {\n                return void 0 ===\n                    this.ii ? null : this.ii\n            },\n            set: function (a) {\n                var b = this.ii;\n                b !== a && (null === a || \"string\" === typeof a || a instanceof tl) && (a instanceof tl && a.freeze(), this.ii = a, this.M(), this.g(\"defaultRowSeparatorStroke\", b, a))\n            }\n        },\n        defaultRowSeparatorStrokeWidth: {\n            get: function () {\n                return void 0 === this.Rg ? 1 : this.Rg\n            },\n            set: function (a) {\n                if (void 0 !== this.Rg) {\n                    var b = this.Rg;\n                    b !== a && isFinite(a) && 0 <= a && (this.Rg = a, this.o(), this.g(\"defaultRowSeparatorStrokeWidth\", b, a))\n                }\n            }\n        },\n        defaultRowSeparatorDashArray: {\n            get: function () {\n                return void 0 === this.hi ? null : this.hi\n            },\n            set: function (a) {\n                if (void 0 !== this.hi) {\n                    var b = this.hi;\n                    if (b !== a) {\n                        if (null !== a) {\n                            for (var c = a.length, d = 0, e = 0; e < c; e++) {\n                                var f = a[e];\n                                \"number\" === typeof f && 0 <= f && isFinite(f) || B(\"defaultRowSeparatorDashArray value \" + f + \" at index \" + e + \" must be a positive number or zero.\");\n                                d += f\n                            }\n                            if (0 === d) {\n                                if (null === b) return;\n                                a = null\n                            }\n                        }\n                        this.hi = a;\n                        this.M();\n                        this.g(\"defaultRowSeparatorDashArray\", b, a)\n                    }\n                }\n            }\n        },\n        defaultColumnSeparatorStroke: {\n            get: function () {\n                return void 0 ===\n                    this.Pg ? null : this.Pg\n            },\n            set: function (a) {\n                if (void 0 !== this.Pg) {\n                    var b = this.Pg;\n                    b !== a && (null === a || \"string\" === typeof a || a instanceof tl) && (a instanceof tl && a.freeze(), this.Pg = a, this.M(), this.g(\"defaultColumnSeparatorStroke\", b, a))\n                }\n            }\n        },\n        defaultColumnSeparatorStrokeWidth: {\n            get: function () {\n                return void 0 === this.Qg ? 1 : this.Qg\n            },\n            set: function (a) {\n                if (void 0 !== this.Qg) {\n                    var b = this.Qg;\n                    b !== a && isFinite(a) && 0 <= a && (this.Qg = a, this.o(), this.g(\"defaultColumnSeparatorStrokeWidth\", b, a))\n                }\n            }\n        },\n        defaultColumnSeparatorDashArray: {\n            get: function () {\n                return void 0 === this.gi ? null : this.gi\n            },\n            set: function (a) {\n                if (void 0 !== this.gi) {\n                    var b = this.gi;\n                    if (b !== a) {\n                        if (null !== a) {\n                            for (var c = a.length, d = 0, e = 0; e < c; e++) {\n                                var f = a[e];\n                                \"number\" === typeof f && 0 <= f && isFinite(f) || B(\"defaultColumnSeparatorDashArray value \" + f + \" at index \" + e + \" must be a positive number or zero.\");\n                                d += f\n                            }\n                            if (0 === d) {\n                                if (null === b) return;\n                                a = null\n                            }\n                        }\n                        this.gi = a;\n                        this.M();\n                        this.g(\"defaultColumnSeparatorDashArray\", b, a)\n                    }\n                }\n            }\n        },\n        viewboxStretch: {\n            get: function () {\n                return this.Yp\n            },\n            set: function (a) {\n                var b = this.Yp;\n                b !== a && (this.Yp = a, this.o(), this.g(\"viewboxStretch\", b, a))\n            }\n        },\n        gridCellSize: {\n            get: function () {\n                return this.Sn\n            },\n            set: function (a) {\n                var b = this.Sn;\n                if (!b.w(a)) {\n                    a.v() && 0 !== a.width && 0 !== a.height || B(\"Invalid Panel.gridCellSize: \" + a);\n                    this.Sn = a.G();\n                    var c = this.diagram;\n                    null !== c && this === c.grid && mj(c);\n                    this.M();\n                    this.g(\"gridCellSize\", b, a)\n                }\n            }\n        },\n        gridOrigin: {\n            get: function () {\n                return this.Tn\n            },\n            set: function (a) {\n                var b = this.Tn;\n                if (!b.w(a)) {\n                    a.v() ||\n                        B(\"Invalid Panel.gridOrigin: \" + a);\n                    this.Tn = a.G();\n                    var c = this.diagram;\n                    null !== c && this === c.grid && mj(c);\n                    this.M();\n                    this.g(\"gridOrigin\", b, a)\n                }\n            }\n        },\n        graduatedMin: {\n            get: function () {\n                return this.Pn\n            },\n            set: function (a) {\n                var b = this.Pn;\n                b !== a && (this.Pn = a, this.o(), this.g(\"graduatedMin\", b, a), el(this) && (a = this.part, null !== a && fl(this, a, \"graduatedRange\")))\n            }\n        },\n        graduatedMax: {\n            get: function () {\n                return this.On\n            },\n            set: function (a) {\n                var b = this.On;\n                b !== a && (this.On = a, this.o(), this.g(\"graduatedMax\",\n                    b, a), el(this) && (a = this.part, null !== a && fl(this, a, \"graduatedRange\")))\n            }\n        },\n        graduatedRange: {\n            get: function () {\n                return this.graduatedMax - this.graduatedMin\n            }\n        },\n        graduatedTickUnit: {\n            get: function () {\n                return this.Rn\n            },\n            set: function (a) {\n                var b = this.Rn;\n                b !== a && 0 < a && (this.Rn = a, this.o(), this.g(\"graduatedTickUnit\", b, a))\n            }\n        },\n        graduatedTickBase: {\n            get: function () {\n                return this.Qn\n            },\n            set: function (a) {\n                var b = this.Qn;\n                b !== a && (this.Qn = a, this.o(), this.g(\"graduatedTickBase\",\n                    b, a))\n            }\n        },\n        Ih: {\n            get: function () {\n                return 0 !== (this.F & 8388608)\n            },\n            set: function (a) {\n                0 !== (this.F & 8388608) !== a && (this.F ^= 8388608)\n            }\n        },\n        rowCount: {\n            get: function () {\n                return void 0 === this.rb ? 0 : this.rb.length\n            }\n        },\n        columnCount: {\n            get: function () {\n                return void 0 === this.mb ? 0 : this.mb.length\n            }\n        },\n        rowSizing: {\n            get: function () {\n                return void 0 === this.Mj ? Vm : this.Mj\n            },\n            set: function (a) {\n                if (void 0 !== this.Mj) {\n                    var b = this.Mj;\n                    b !== a && (this.Mj =\n                        a, this.o(), this.g(\"rowSizing\", b, a))\n                }\n            }\n        },\n        columnSizing: {\n            get: function () {\n                return void 0 === this.kj ? Vm : this.kj\n            },\n            set: function (a) {\n                if (void 0 !== this.kj) {\n                    var b = this.kj;\n                    b !== a && (this.kj = a, this.o(), this.g(\"columnSizing\", b, a))\n                }\n            }\n        },\n        topIndex: {\n            get: function () {\n                return void 0 === this.Ki ? 0 : this.Ki\n            },\n            set: function (a) {\n                if (void 0 !== this.Ki) {\n                    var b = this.Ki;\n                    b !== a && ((!isFinite(a) || 0 > a) && B(\"Panel.topIndex must be greater than zero and a real number, not: \" + a), this.Ki = a, this.o(),\n                        this.g(\"topIndex\", b, a))\n                }\n            }\n        },\n        leftIndex: {\n            get: function () {\n                return void 0 === this.vi ? 0 : this.vi\n            },\n            set: function (a) {\n                if (void 0 !== this.vi) {\n                    var b = this.vi;\n                    b !== a && ((!isFinite(a) || 0 > a) && B(\"Panel.leftIndex must be greater than zero and a real number, not: \" + a), this.vi = a, this.o(), this.g(\"leftIndex\", b, a))\n                }\n            }\n        },\n        data: {\n            get: function () {\n                return this.hb\n            },\n            set: function (a) {\n                var b = this.hb;\n                if (b !== a) {\n                    var c = this instanceof U && !(this instanceof Je);\n                    yg(this);\n                    this.hb = a;\n                    var d = this.diagram;\n                    null !== d && (c ? (c = d.partManager, this instanceof S ? (null !== b && c.Ne.remove(b), null !== a && c.Ne.add(a, this)) : this instanceof U && (null !== b && c.Oe.remove(b), null !== a && c.Oe.add(a, this))) : (c = this.panel, null !== c && null !== c.Jd && (null !== b && c.Jd.remove(b), null !== a && c.Jd.add(a, this))));\n                    this.g(\"data\", b, a);\n                    null !== d && d.undoManager.isUndoingRedoing || null !== a && this.Ba()\n                }\n            }\n        },\n        itemIndex: {\n            get: function () {\n                return this.io\n            },\n            set: function (a) {\n                var b = this.io;\n                b !== a && (this.io = a, this.g(\"itemIndex\", b, a))\n            }\n        },\n        itemArray: {\n            get: function () {\n                return this.si\n            },\n            set: function (a) {\n                var b = this.si;\n                if (b !== a || null !== a && hn(this, a)) {\n                    var c = this.diagram;\n                    b !== a && (null !== c && null !== b && Ij(c.partManager, this, c), this.si = a, null !== c && null !== a && Fj(c.partManager, this));\n                    this.g(\"itemArray\", b, a);\n                    null !== c && c.undoManager.isUndoingRedoing || this.Gt()\n                }\n            }\n        },\n        itemTemplate: {\n            get: function () {\n                return null === this.le ? null : this.le.H(\"\")\n            },\n            set: function (a) {\n                if (null === this.le) {\n                    if (null === a) return;\n                    this.le = new H\n                }\n                var b = this.le.H(\"\");\n                b !== a && ((a instanceof U || a.isPanelMain) && B(\"Panel.itemTemplate must not be a Part or be Panel.isPanelMain: \" + a), this.le.add(\"\", a), this.g(\"itemTemplate\", b, a), a = this.diagram, null !== a && a.undoManager.isUndoingRedoing || this.Gt())\n            }\n        },\n        itemTemplateMap: {\n            get: function () {\n                return this.le\n            },\n            set: function (a) {\n                var b = this.le;\n                if (b !== a) {\n                    for (var c = a.iterator; c.next(););\n                    this.le = a;\n                    this.g(\"itemTemplateMap\", b, a);\n                    a = this.diagram;\n                    null !== a && a.undoManager.isUndoingRedoing || this.Gt()\n                }\n            }\n        },\n        itemCategoryProperty: {\n            get: function () {\n                return this.ql\n            },\n            set: function (a) {\n                var b = this.ql;\n                b !== a && (this.ql = a, this.g(\"itemCategoryProperty\", b, a))\n            }\n        },\n        isAtomic: {\n            get: function () {\n                return 0 !== (this.F & 1048576)\n            },\n            set: function (a) {\n                var b = 0 !== (this.F & 1048576);\n                b !== a && (this.F ^= 1048576, this.g(\"isAtomic\", b, a))\n            }\n        },\n        isClipping: {\n            get: function () {\n                return 0 !== (this.F & 2097152)\n            },\n            set: function (a) {\n                var b = 0 !== (this.F & 2097152);\n                b !== a && (a && this.type !== X.Spot && wa(\"Warning: Panel.isClipping set on non-Spot Panel: \" +\n                    this.toString()), this.F ^= 2097152, this.o(), this.g(\"isClipping\", b, a))\n            }\n        },\n        isOpposite: {\n            get: function () {\n                return 0 !== (this.F & 33554432)\n            },\n            set: function (a) {\n                var b = 0 !== (this.F & 33554432);\n                b !== a && (this.F ^= 33554432, this.o(), this.g(\"isOpposite\", b, a))\n            }\n        },\n        isEnabled: {\n            get: function () {\n                return 0 !== (this.F & 4194304)\n            },\n            set: function (a) {\n                var b = 0 !== (this.F & 4194304);\n                if (b !== a) {\n                    var c = null === this.panel || this.panel.Eg();\n                    this.F ^= 4194304;\n                    this.g(\"isEnabled\", b, a);\n                    b = this.diagram;\n                    null !==\n                        b && b.undoManager.isUndoingRedoing || c && en(this, this, a)\n                }\n            }\n        },\n        alignmentFocusName: {\n            get: function () {\n                return this.Jg\n            },\n            set: function (a) {\n                var b = this.Jg;\n                b !== a && (this.Jg = a, this.o(), this.g(\"alignmentFocusName\", b, a))\n            }\n        }\n    });\n    ma.Object.defineProperties(X, {\n        Position: {\n            get: function () {\n                return Nl.H(\"Position\")\n            }\n        },\n        Horizontal: {\n            get: function () {\n                return Nl.H(\"Horizontal\")\n            }\n        },\n        Vertical: {\n            get: function () {\n                return Nl.H(\"Vertical\")\n            }\n        },\n        Spot: {\n            get: function () {\n                return Nl.H(\"Spot\")\n            }\n        },\n        Auto: {\n            get: function () {\n                return Nl.H(\"Auto\")\n            }\n        },\n        Table: {\n            get: function () {\n                return Nl.H(\"Table\")\n            }\n        },\n        Viewbox: {\n            get: function () {\n                return Nl.H(\"Viewbox\")\n            }\n        },\n        TableRow: {\n            get: function () {\n                return Nl.H(\"TableRow\")\n            }\n        },\n        TableColumn: {\n            get: function () {\n                return Nl.H(\"TableColumn\")\n            }\n        },\n        Link: {\n            get: function () {\n                return Nl.H(\"Link\")\n            }\n        },\n        Grid: {\n            get: function () {\n                return Nl.H(\"Grid\")\n            }\n        },\n        Graduated: {\n            get: function () {\n                return Nl.H(\"Graduated\")\n            }\n        }\n    });\n    X.prototype.findItemPanelForData = X.prototype.Kx;\n    X.prototype.rebuildItemElements = X.prototype.Gt;\n    X.prototype.updateTargetBindings = X.prototype.Ba;\n    X.prototype.copyTemplate = X.prototype.Wy;\n    X.prototype.graduatedValueForPoint = X.prototype.Lz;\n    X.prototype.graduatedPointForValue = X.prototype.Kz;\n    X.prototype.findColumnForLocalX = X.prototype.hz;\n    X.prototype.findRowForLocalY = X.prototype.pz;\n    X.prototype.removeColumnDefinition = X.prototype.Wv;\n    X.prototype.removeRowDefinition = X.prototype.Yv;\n    X.prototype.removeAt = X.prototype.lb;\n    X.prototype.remove = X.prototype.remove;\n    X.prototype.insertAt = X.prototype.Kb;\n    X.prototype.elt = X.prototype.L;\n    X.prototype.add = X.prototype.add;\n    X.prototype.findObject = X.prototype.Xa;\n    X.prototype.findInVisualTree = X.prototype.hm;\n    X.prototype.walkVisualTreeFrom = X.prototype.Km;\n    X.prototype.findMainElement = X.prototype.zb;\n    var ln = !1,\n        mn = null,\n        Nl = new H;\n    X.className = \"Panel\";\n    X.definePanelLayout = An;\n    An(\"Position\", new vm);\n    An(\"Vertical\", new ym);\n    An(\"Auto\", new Am);\n    An(\"Link\", new Lm);\n\n    function Rj() {\n        Ya(this);\n        this.ng = null;\n        this.Rr = !0;\n        this.Pa = 0;\n        this.Pc = NaN;\n        this.ih = 0;\n        this.hh = Infinity;\n        this.vb = Zc;\n        this.ma = this.ha = 0;\n        this.$a = null;\n        this.Hp = Bn;\n        this.ve = Vk;\n        this.Bp = this.qg = null;\n        this.Cp = NaN;\n        this.gb = this.Nj = null;\n        this.qn = !1\n    }\n    Rj.prototype.copy = function () {\n        var a = new Rj;\n        a.Rr = this.Rr;\n        a.Pa = this.Pa;\n        a.Pc = this.Pc;\n        a.ih = this.ih;\n        a.hh = this.hh;\n        a.vb = this.vb;\n        a.ha = this.ha;\n        a.ma = this.ma;\n        a.ve = this.ve;\n        a.Hp = this.Hp;\n        null === this.qg ? a.qg = null : a.qg = this.qg.G();\n        a.Bp = this.Bp;\n        a.Cp = this.Cp;\n        a.Nj = null;\n        null !== this.Nj && (a.separatorDashArray = Ba(this.separatorDashArray));\n        a.gb = this.gb;\n        a.qn = this.qn;\n        a.$a = this.$a;\n        return a\n    };\n    t = Rj.prototype;\n    t.et = function (a) {\n        a.isRow ? this.height = a.height : this.width = a.width;\n        this.minimum = a.minimum;\n        this.maximum = a.maximum;\n        this.alignment = a.alignment;\n        this.stretch = a.stretch;\n        this.sizing = a.sizing;\n        this.qg = null === a.separatorPadding ? null : a.separatorPadding.G();\n        this.separatorStroke = a.separatorStroke;\n        this.separatorStrokeWidth = a.separatorStrokeWidth;\n        this.Nj = null;\n        a.separatorDashArray && (this.Nj = Ba(a.separatorDashArray));\n        this.background = a.background;\n        this.coversSeparators = a.coversSeparators;\n        this.$a = a.$a\n    };\n    t.cb = function (a) {\n        a.classType === Rj && (this.sizing = a)\n    };\n    t.toString = function () {\n        return \"RowColumnDefinition \" + (this.isRow ? \"(Row \" : \"(Column \") + this.index + \") #\" + lb(this)\n    };\n    t.cj = function (a) {\n        this.ng = a\n    };\n    t.iv = function () {\n        var a = 0,\n            b = 0,\n            c = this.ng,\n            d = this.isRow;\n        if (null !== c && c.type === X.Table)\n            for (var e = d ? c.rb.length : c.mb.length, f = 0; f < e; f++) {\n                var g = d ? c.rb[f] : c.mb[f];\n                if (void 0 !== g) {\n                    b = g.index;\n                    break\n                }\n            }\n        this.index !== b && (b = this.separatorStroke, null === b && null !== c && (b = this.isRow ? c.defaultRowSeparatorStroke : c.defaultColumnSeparatorStroke), null !== b && (a = this.separatorStrokeWidth, isNaN(a) && (null !== c ? a = this.isRow ? c.defaultRowSeparatorStrokeWidth : c.defaultColumnSeparatorStrokeWidth : a = 0)));\n        b = this.qg;\n        if (null === b)\n            if (null !== c) b =\n                c.defaultSeparatorPadding;\n            else return a;\n        return a + (this.isRow ? b.top : b.left)\n    };\n    t.uc = function () {\n        var a = 0,\n            b = this.ng,\n            c = 0,\n            d = this.isRow;\n        if (null !== b && b.type === X.Table)\n            for (var e = d ? b.rb.length : b.mb.length, f = 0; f < e; f++) {\n                var g = d ? b.rb[f] : b.mb[f];\n                if (void 0 !== g) {\n                    c = g.index;\n                    break\n                }\n            }\n        this.index !== c && (c = this.separatorStroke, null === c && null !== b && (c = d ? b.defaultRowSeparatorStroke : b.defaultColumnSeparatorStroke), null !== c && (a = this.separatorStrokeWidth, isNaN(a) && (null !== b ? a = d ? b.defaultRowSeparatorStrokeWidth : b.defaultColumnSeparatorStrokeWidth : a = 0)));\n        d = this.qg;\n        if (null === d)\n            if (null !== b) d = b.defaultSeparatorPadding;\n            else return a;\n        return a + (this.isRow ? d.top + d.bottom : d.left + d.right)\n    };\n    t.xb = function (a, b, c) {\n        var d = this.ng;\n        if (null !== d && (d.Ya(re, a, this, b, c, void 0, void 0), null !== this.$a && (b = d.diagram, null !== b && !b.skipsModelSourceBindings && (d = d.Ui(), null !== d && (b = d.data, null !== b)))))\n            for (c = this.$a.iterator; c.next();) c.value.Qq(this, b, a, d)\n    };\n\n    function Em(a) {\n        if (a.sizing === Bn) {\n            var b = a.ng;\n            return a.isRow ? b.rowSizing : b.columnSizing\n        }\n        return a.sizing\n    }\n    t.bind = function (a) {\n        a.bd = this;\n        var b = this.panel;\n        if (null !== b) {\n            var c = b.Ui();\n            null !== c && Il(c) && B(\"Cannot add a Binding to a RowColumnDefinition that is already frozen: \" + a + \" on \" + b)\n        }\n        null === this.$a && (this.$a = new E);\n        this.$a.add(a)\n    };\n    ma.Object.defineProperties(Rj.prototype, {\n        panel: {\n            get: function () {\n                return this.ng\n            }\n        },\n        isRow: {\n            get: function () {\n                return this.Rr\n            },\n            set: function (a) {\n                this.Rr = a\n            }\n        },\n        index: {\n            get: function () {\n                return this.Pa\n            },\n            set: function (a) {\n                this.Pa = a\n            }\n        },\n        height: {\n            get: function () {\n                return this.Pc\n            },\n            set: function (a) {\n                var b = this.Pc;\n                b !== a && (0 > a && va(a, \">= 0\", Rj, \"height\"), this.Pc = a, this.actual = this.ha, null !== this.panel && this.panel.o(),\n                    this.xb(\"height\", b, a))\n            }\n        },\n        width: {\n            get: function () {\n                return this.Pc\n            },\n            set: function (a) {\n                var b = this.Pc;\n                b !== a && (0 > a && va(a, \">= 0\", Rj, \"width\"), this.Pc = a, this.actual = this.ha, null !== this.panel && this.panel.o(), this.xb(\"width\", b, a))\n            }\n        },\n        minimum: {\n            get: function () {\n                return this.ih\n            },\n            set: function (a) {\n                var b = this.ih;\n                b !== a && ((0 > a || !isFinite(a)) && va(a, \">= 0\", Rj, \"minimum\"), this.ih = a, this.actual = this.ha, null !== this.panel && this.panel.o(), this.xb(\"minimum\", b, a))\n            }\n        },\n        maximum: {\n            get: function () {\n                return this.hh\n            },\n            set: function (a) {\n                var b = this.hh;\n                b !== a && (0 > a && va(a, \">= 0\", Rj, \"maximum\"), this.hh = a, this.actual = this.ha, null !== this.panel && this.panel.o(), this.xb(\"maximum\", b, a))\n            }\n        },\n        alignment: {\n            get: function () {\n                return this.vb\n            },\n            set: function (a) {\n                var b = this.vb;\n                b.w(a) || (this.vb = a.G(), null !== this.panel && this.panel.o(), this.xb(\"alignment\", b, a))\n            }\n        },\n        stretch: {\n            get: function () {\n                return this.ve\n            },\n            set: function (a) {\n                var b = this.ve;\n                b !== a && (this.ve =\n                    a, null !== this.panel && this.panel.o(), this.xb(\"stretch\", b, a))\n            }\n        },\n        separatorPadding: {\n            get: function () {\n                return this.qg\n            },\n            set: function (a) {\n                \"number\" === typeof a && (a = new oc(a));\n                var b = this.qg;\n                null !== a && null !== b && b.w(a) || (null !== a && (a = a.G()), this.qg = a, null !== this.panel && this.panel.o(), this.xb(\"separatorPadding\", b, a))\n            }\n        },\n        separatorStroke: {\n            get: function () {\n                return this.Bp\n            },\n            set: function (a) {\n                var b = this.Bp;\n                b !== a && (null !== a && Rl(a, \"RowColumnDefinition.separatorStroke\"),\n                    a instanceof tl && a.freeze(), this.Bp = a, null !== this.panel && this.panel.o(), this.xb(\"separatorStroke\", b, a))\n            }\n        },\n        separatorStrokeWidth: {\n            get: function () {\n                return this.Cp\n            },\n            set: function (a) {\n                var b = this.Cp;\n                b !== a && (this.Cp = a, null !== this.panel && this.panel.o(), this.xb(\"separatorStrokeWidth\", b, a))\n            }\n        },\n        separatorDashArray: {\n            get: function () {\n                return this.Nj\n            },\n            set: function (a) {\n                var b = this.Nj;\n                if (b !== a) {\n                    if (null !== a) {\n                        for (var c = a.length, d = 0, e = 0; e < c; e++) {\n                            var f = a[e];\n                            \"number\" ===\n                            typeof f && 0 <= f && isFinite(f) || B(\"separatorDashArray value \" + f + \" at index \" + e + \" must be a positive number or zero.\");\n                            d += f\n                        }\n                        if (0 === d) {\n                            if (null === b) return;\n                            a = null\n                        }\n                    }\n                    this.Nj = a;\n                    null !== this.panel && this.panel.M();\n                    this.xb(\"separatorDashArray\", b, a)\n                }\n            }\n        },\n        background: {\n            get: function () {\n                return this.gb\n            },\n            set: function (a) {\n                var b = this.gb;\n                b !== a && (null !== a && Rl(a, \"RowColumnDefinition.background\"), a instanceof tl && a.freeze(), this.gb = a, null !== this.panel && this.panel.M(), this.xb(\"background\", b, a))\n            }\n        },\n        coversSeparators: {\n            get: function () {\n                return this.qn\n            },\n            set: function (a) {\n                var b = this.qn;\n                b !== a && (this.qn = a, null !== this.panel && this.panel.M(), this.xb(\"coversSeparators\", b, a))\n            }\n        },\n        sizing: {\n            get: function () {\n                return this.Hp\n            },\n            set: function (a) {\n                var b = this.Hp;\n                b !== a && (this.Hp = a, null !== this.panel && this.panel.o(), this.xb(\"sizing\", b, a))\n            }\n        },\n        actual: {\n            get: function () {\n                return this.ha\n            },\n            set: function (a) {\n                this.ha = isNaN(this.Pc) ? Math.max(Math.min(this.hh, a), this.ih) : Math.max(Math.min(this.hh,\n                    this.Pc), this.ih)\n            }\n        },\n        total: {\n            get: function () {\n                return this.ha + this.uc()\n            },\n            set: function (a) {\n                this.ha = isNaN(this.Pc) ? Math.max(Math.min(this.hh, a), this.ih) : Math.max(Math.min(this.hh, this.Pc), this.ih);\n                this.ha = Math.max(0, this.ha - this.uc())\n            }\n        },\n        position: {\n            get: function () {\n                return this.ma\n            },\n            set: function (a) {\n                this.ma = a\n            }\n        }\n    });\n    Rj.prototype.bind = Rj.prototype.bind;\n    Rj.prototype.computeEffectiveSpacing = Rj.prototype.uc;\n    Rj.prototype.computeEffectiveSpacingTop = Rj.prototype.iv;\n    var Bn = new D(Rj, \"Default\", 0),\n        Fm = new D(Rj, \"None\", 1),\n        Vm = new D(Rj, \"ProportionalExtra\", 2);\n    Rj.className = \"RowColumnDefinition\";\n    Rj.Default = Bn;\n    Rj.None = Fm;\n    Rj.ProportionalExtra = Vm;\n\n    function Lf() {\n        Y.call(this);\n        this.Qd = this.ka = null;\n        this.Zk = \"None\";\n        this.Nn = Vk;\n        this.Dc = this.$k = \"black\";\n        this.th = 1;\n        this.Rl = \"butt\";\n        this.Sl = \"miter\";\n        this.Oj = 10;\n        this.rh = null;\n        this.sh = 0;\n        this.jf = this.hf = Zc;\n        this.$o = this.Zo = NaN;\n        this.Zn = !1;\n        this.bp = null;\n        this.al = this.Yl = \"None\";\n        this.Hd = 1;\n        this.Fd = 0;\n        this.Dd = 1;\n        this.Ed = null\n    }\n    la(Lf, Y);\n    Lf.prototype.cloneProtected = function (a) {\n        Y.prototype.cloneProtected.call(this, a);\n        a.ka = this.ka;\n        a.Zk = this.Zk;\n        a.Nn = this.Nn;\n        a.Qd = this.Qd;\n        a.$k = this.$k;\n        a.Dc = this.Dc;\n        a.th = this.th;\n        a.Rl = this.Rl;\n        a.Sl = this.Sl;\n        a.Oj = this.Oj;\n        null !== this.rh && (a.rh = Ba(this.rh));\n        a.sh = this.sh;\n        a.hf = this.hf.G();\n        a.jf = this.jf.G();\n        a.Zo = this.Zo;\n        a.$o = this.$o;\n        a.Zn = this.Zn;\n        a.bp = this.bp;\n        a.Yl = this.Yl;\n        a.al = this.al;\n        a.Hd = this.Hd;\n        a.Fd = this.Fd;\n        a.Dd = this.Dd;\n        a.Ed = this.Ed\n    };\n    t = Lf.prototype;\n    t.cb = function (a) {\n        a === zg || a === Bg || a === Yk || a === Vk ? this.geometryStretch = a : Y.prototype.cb.call(this, a)\n    };\n    t.toString = function () {\n        return \"Shape(\" + (\"None\" !== this.figure ? this.figure : \"None\" !== this.toArrow ? this.toArrow : this.fromArrow) + \")#\" + lb(this)\n    };\n\n    function Cn(a, b, c, d) {\n        var e = c.length;\n        if (!(4 > e)) {\n            var f = d.measuredBounds,\n                g = Math.max(1, f.width);\n            f = f.height;\n            for (var h = c[0], k = c[1], l, m, n, p, r, q, u = 0, v = Fa(), w = 2; w < e; w += 2) l = c[w], m = c[w + 1], n = l - h, h = m - k, 0 === n && (n = .001), p = h / n, r = Math.atan2(h, n), q = Math.sqrt(n * n + h * h), v.push([n, r, p, q]), u += q, h = l, k = m;\n            h = c[0];\n            k = c[1];\n            n = d.measuredBounds.width;\n            d instanceof Lf && (n -= d.strokeWidth);\n            1 > n && (n = 1);\n            e = c = n;\n            l = g / 2;\n            m = 0 === l ? !1 : !0;\n            w = 0;\n            q = v[w];\n            n = q[0];\n            r = q[1];\n            p = q[2];\n            q = q[3];\n            for (var y = 0; .1 <= u;) {\n                0 === y && (m ? (e = c, e -= l, u -= l, m = !1) : e = c, 0 === e && (e = 1));\n                if (e > u) {\n                    Ha(v);\n                    return\n                }\n                e > q ? (y = e - q, e = q) : y = 0;\n                var z = Math.sqrt(e * e / (1 + p * p));\n                0 > n && (z = -z);\n                h += z;\n                k += p * z;\n                a.translate(h, k);\n                a.rotate(r);\n                a.translate(-(g / 2), -(f / 2));\n                0 === y && d.Qi(a, b);\n                a.translate(g / 2, f / 2);\n                a.rotate(-r);\n                a.translate(-h, -k);\n                u -= e;\n                q -= e;\n                if (0 !== y) {\n                    w++;\n                    if (w === v.length) {\n                        Ha(v);\n                        return\n                    }\n                    q = v[w];\n                    n = q[0];\n                    r = q[1];\n                    p = q[2];\n                    q = q[3];\n                    e = y\n                }\n            }\n            Ha(v)\n        }\n    }\n    t.Qi = function (a, b) {\n        var c = this.Dc,\n            d = this.$k;\n        if (null !== c || null !== d) {\n            var e = this.actualBounds,\n                f = this.naturalBounds;\n            null !== d && ii(this, a, d, !0, !1, f, e);\n            var g = this.part,\n                h = this.th;\n            null !== c && 0 === h && null !== g && (h = g.type === X.Link && g instanceof Je && \"Selection\" === g.category && g.adornedObject instanceof Lf && g.adornedPart.zb() === g.adornedObject ? g.adornedObject.strokeWidth : 0);\n            null !== c && 0 !== h && (ii(this, a, c, !1, !1, f, e), a.lineWidth = h, a.lineJoin = this.Sl, a.lineCap = this.Rl, a.miterLimit = this.Oj);\n            e = !1;\n            g && b.Be(\"drawShadows\") &&\n                (e = g.isShadowed);\n            g = !0;\n            null === c || null !== d && \"transparent\" !== d || (g = !1);\n            f = !1;\n            var k = this.strokeDashArray;\n            null !== k && (f = !0, a.ht(k, this.sh));\n            var l = this.ka;\n            if (null !== l) {\n                if (l.type === wd) a.beginPath(), a.moveTo(l.startX, l.startY), a.lineTo(l.endX, l.endY), null !== d && a.Ud(d), 0 !== h && null !== c && a.fj();\n                else if (l.type === Gd) {\n                    var m = l.startX;\n                    k = l.startY;\n                    var n = l.endX,\n                        p = l.endY;\n                    l = Math.min(m, n);\n                    var r = Math.min(k, p);\n                    m = Math.abs(n - m);\n                    k = Math.abs(p - k);\n                    a.beginPath();\n                    a.rect(l, r, m, k);\n                    null !== d && a.Ud(d);\n                    if (null !== c) {\n                        g && e && sl(a);\n                        if (0 !== h) {\n                            if (0 ===\n                                m || 0 === k) a.beginPath(), a.rect(l, r, Math.max(m, .1), Math.max(k, .1));\n                            a.fj()\n                        }\n                        g && e && rl(a)\n                    }\n                } else if (l.type === Hd) m = l.startX, k = l.startY, n = l.endX, p = l.endY, l = Math.abs(n - m) / 2, r = Math.abs(p - k) / 2, m = Math.min(m, n) + l, k = Math.min(k, p) + r, a.beginPath(), a.moveTo(m, k - r), a.bezierCurveTo(m + J.Ig * l, k - r, m + l, k - J.Ig * r, m + l, k), a.bezierCurveTo(m + l, k + J.Ig * r, m + J.Ig * l, k + r, m, k + r), a.bezierCurveTo(m - J.Ig * l, k + r, m - l, k + J.Ig * r, m - l, k), a.bezierCurveTo(m - l, k - J.Ig * r, m - J.Ig * l, k - r, m, k - r), a.closePath(), null !== d && a.Ud(d), 0 !== h && null !== c && (g && e ? (sl(a),\n                    a.fj(), rl(a)) : a.fj());\n                else if (l.type === ud)\n                    for (k = l.figures, l = k.length, r = 0; r < l; r++) {\n                        m = k.j[r];\n                        a.beginPath();\n                        a.moveTo(m.startX, m.startY);\n                        n = m.segments.j;\n                        p = n.length;\n                        for (var q = null, u = 0; u < p; u++) {\n                            var v = n[u];\n                            switch (v.type) {\n                                case Wd:\n                                    a.moveTo(v.endX, v.endY);\n                                    break;\n                                case yd:\n                                    a.lineTo(v.endX, v.endY);\n                                    break;\n                                case Xd:\n                                    a.bezierCurveTo(v.point1X, v.point1Y, v.point2X, v.point2Y, v.endX, v.endY);\n                                    break;\n                                case Yd:\n                                    a.quadraticCurveTo(v.point1X, v.point1Y, v.endX, v.endY);\n                                    break;\n                                case Zd:\n                                    if (v.radiusX === v.radiusY) {\n                                        var w = Math.PI / 180;\n                                        a.arc(v.point1X,\n                                            v.point1Y, v.radiusX, v.startAngle * w, (v.startAngle + v.sweepAngle) * w, 0 > v.sweepAngle, null !== q ? q.endX : m.startX, null !== q ? q.endY : m.startY)\n                                    } else if (q = ae(v, m), w = q.length, 0 === w) a.lineTo(v.centerX, v.centerY);\n                                    else\n                                        for (var y = 0; y < w; y++) {\n                                            var z = q[y];\n                                            0 === y && a.lineTo(z[0], z[1]);\n                                            a.bezierCurveTo(z[2], z[3], z[4], z[5], z[6], z[7])\n                                        }\n                                    break;\n                                case $d:\n                                    y = w = 0;\n                                    if (null !== q && q.type === Zd) {\n                                        q = ae(q, m);\n                                        z = q.length;\n                                        if (0 === z) {\n                                            a.lineTo(v.centerX, v.centerY);\n                                            break\n                                        }\n                                        q = q[z - 1] || null;\n                                        null !== q && (w = q[6], y = q[7])\n                                    } else w = null !== q ? q.endX : m.startX, y = null !==\n                                        q ? q.endY : m.startY;\n                                    q = be(v, m, w, y);\n                                    w = q.length;\n                                    if (0 === w) {\n                                        a.lineTo(v.centerX, v.centerY);\n                                        break\n                                    }\n                                    for (y = 0; y < w; y++) z = q[y], a.bezierCurveTo(z[2], z[3], z[4], z[5], z[6], z[7]);\n                                    break;\n                                default:\n                                    B(\"Segment not of valid type: \" + v.type)\n                            }\n                            v.isClosed && a.closePath();\n                            q = v\n                        }\n                        e ? m.isShadowed ? (!0 === m.isFilled && \"transparent\" !== d && null !== d && a.Ud(d), 0 !== h && null !== c && (g && sl(a), a.fj(), g && rl(a))) : (g && sl(a), !0 === m.isFilled && \"transparent\" !== d && null !== d && a.Ud(d), 0 !== h && null !== c && a.fj(), g && rl(a)) : (!0 === m.isFilled && null !== d && a.Ud(d), 0 !== h && null !==\n                            c && a.fj())\n                    }\n                f && a.ft();\n                if (null !== this.pathPattern) {\n                    c = this.pathPattern;\n                    c.measure(Infinity, Infinity);\n                    d = c.measuredBounds;\n                    c.arrange(0, 0, d.width, d.height);\n                    h = this.geometry;\n                    a.save();\n                    a.beginPath();\n                    d = Fa();\n                    if (h.type === wd) d.push(h.startX), d.push(h.startY), d.push(h.endX), d.push(h.endY), Cn(a, b, d, c);\n                    else if (h.type === ud)\n                        for (h = h.figures.iterator; h.next();) {\n                            e = h.value;\n                            d.length = 0;\n                            d.push(e.startX);\n                            d.push(e.startY);\n                            g = e.startX;\n                            f = e.startY;\n                            k = g;\n                            l = f;\n                            r = e.segments.j;\n                            m = r.length;\n                            for (n = 0; n < m; n++) {\n                                p = r[n];\n                                switch (p.type) {\n                                    case Wd:\n                                        Cn(a,\n                                            b, d, c);\n                                        d.length = 0;\n                                        d.push(p.endX);\n                                        d.push(p.endY);\n                                        g = p.endX;\n                                        f = p.endY;\n                                        k = g;\n                                        l = f;\n                                        break;\n                                    case yd:\n                                        d.push(p.endX);\n                                        d.push(p.endY);\n                                        g = p.endX;\n                                        f = p.endY;\n                                        break;\n                                    case Xd:\n                                        J.ye(g, f, p.point1X, p.point1Y, p.point2X, p.point2Y, p.endX, p.endY, .5, d);\n                                        g = p.endX;\n                                        f = p.endY;\n                                        break;\n                                    case Yd:\n                                        J.Cq(g, f, p.point1X, p.point1Y, p.endX, p.endY, .5, d);\n                                        g = p.endX;\n                                        f = p.endY;\n                                        break;\n                                    case Zd:\n                                        u = ae(p, e);\n                                        v = u.length;\n                                        if (0 === v) {\n                                            d.push(p.centerX);\n                                            d.push(p.centerY);\n                                            g = p.centerX;\n                                            f = p.centerY;\n                                            break\n                                        }\n                                        for (q = 0; q < v; q++) w = u[q], J.ye(g, f, w[2], w[3], w[4], w[5], w[6], w[7], .5, d), g = w[6],\n                                            f = w[7];\n                                        break;\n                                    case $d:\n                                        u = be(p, e, g, f);\n                                        v = u.length;\n                                        if (0 === v) {\n                                            d.push(p.centerX);\n                                            d.push(p.centerY);\n                                            g = p.centerX;\n                                            f = p.centerY;\n                                            break\n                                        }\n                                        for (q = 0; q < v; q++) w = u[q], J.ye(g, f, w[2], w[3], w[4], w[5], w[6], w[7], .5, d), g = w[6], f = w[7];\n                                        break;\n                                    default:\n                                        B(\"Segment not of valid type: \" + p.type)\n                                }\n                                p.isClosed && (d.push(k), d.push(l), Cn(a, b, d, c))\n                            }\n                            Cn(a, b, d, c)\n                        } else if (h.type === Gd) d.push(h.startX), d.push(h.startY), d.push(h.endX), d.push(h.startY), d.push(h.endX), d.push(h.endY), d.push(h.startX), d.push(h.endY), d.push(h.startX), d.push(h.startY), Cn(a,\n                            b, d, c);\n                        else if (h.type === Hd) {\n                        f = new ke;\n                        f.startX = h.endX;\n                        f.startY = (h.startY + h.endY) / 2;\n                        g = new le(Zd);\n                        g.startAngle = 0;\n                        g.sweepAngle = 360;\n                        g.centerX = (h.startX + h.endX) / 2;\n                        g.centerY = (h.startY + h.endY) / 2;\n                        g.radiusX = Math.abs(h.startX - h.endX) / 2;\n                        g.radiusY = Math.abs(h.startY - h.endY) / 2;\n                        f.add(g);\n                        h = ae(g, f);\n                        e = h.length;\n                        if (0 === e) d.push(g.centerX), d.push(g.centerY);\n                        else\n                            for (g = f.startX, f = f.startY, k = 0; k < e; k++) l = h[k], J.ye(g, f, l[2], l[3], l[4], l[5], l[6], l[7], .5, d), g = l[6], f = l[7];\n                        Cn(a, b, d, c)\n                    }\n                    Ha(d);\n                    a.restore();\n                    a.sc(!1)\n                }\n            }\n        }\n    };\n    t.ga = function (a, b) {\n        void 0 === b && (b = new I);\n        if (a instanceof P) {\n            a.jc() && B(\"getDocumentPoint Spot must be a real, specific Spot, not: \" + a.toString());\n            var c = this.naturalBounds,\n                d = this.strokeWidth;\n            b.h(a.x * (c.width + d) - d / 2 + c.x + a.offsetX, a.y * (c.height + d) - d / 2 + c.y + a.offsetY)\n        } else b.set(a);\n        this.ud.ra(b);\n        return b\n    };\n    t.lm = function (a) {\n        void 0 === a && (a = new N);\n        var b = this.naturalBounds,\n            c = this.ud;\n        b = N.allocAt(b.x, b.y, b.width, b.height);\n        var d = this.strokeWidth;\n        b.Vc(d / 2, d / 2);\n        d = I.allocAt(b.x, b.y).transform(c);\n        a.h(d.x, d.y, 0, 0);\n        d.h(b.right, b.y).transform(c);\n        ec(a, d.x, d.y, 0, 0);\n        d.h(b.right, b.bottom).transform(c);\n        ec(a, d.x, d.y, 0, 0);\n        d.h(b.x, b.bottom).transform(c);\n        ec(a, d.x, d.y, 0, 0);\n        N.free(b);\n        I.free(d);\n        return a\n    };\n    t.Hh = function (a, b) {\n        var c = this.geometry;\n        if (null === c || null === this.fill && null === this.stroke) return !1;\n        var d = c.bounds,\n            e = this.strokeWidth / 2;\n        c.type !== wd || b || (e += 2);\n        var f = N.alloc();\n        f.assign(d);\n        f.Vc(e + 2, e + 2);\n        if (!f.aa(a)) return N.free(f), !1;\n        d = e + 1E-4;\n        if (c.type === wd) {\n            if (null === this.stroke) return !1;\n            d = (c.endX - c.startX) * (a.x - c.startX) + (c.endY - c.startY) * (a.y - c.startY);\n            if (0 > (c.startX - c.endX) * (a.x - c.endX) + (c.startY - c.endY) * (a.y - c.endY) || 0 > d) return !1;\n            N.free(f);\n            return J.Nb(c.startX, c.startY, c.endX, c.endY, e, a.x, a.y)\n        }\n        if (c.type ===\n            Gd) {\n            b = c.startX;\n            var g = c.startY,\n                h = c.endX;\n            c = c.endY;\n            f.x = Math.min(b, h);\n            f.y = Math.min(g, c);\n            f.width = Math.abs(h - b);\n            f.height = Math.abs(c - g);\n            if (null === this.fill) {\n                f.Vc(-d, -d);\n                if (f.aa(a)) return N.free(f), !1;\n                f.Vc(d, d)\n            }\n            null !== this.stroke && f.Vc(e, e);\n            a = f.aa(a);\n            N.free(f);\n            return a\n        }\n        if (c.type === Hd) {\n            g = c.startX;\n            e = c.startY;\n            h = c.endX;\n            var k = c.endY;\n            c = Math.min(g, h);\n            b = Math.min(e, k);\n            g = Math.abs(h - g) / 2;\n            e = Math.abs(k - e) / 2;\n            c = a.x - (c + g);\n            b = a.y - (b + e);\n            if (null === this.fill) {\n                g -= d;\n                e -= d;\n                if (0 >= g || 0 >= e || 1 >= c * c / (g * g) + b * b / (e * e)) return N.free(f), !1;\n                g += d;\n                e += d\n            }\n            null !== this.stroke && (g += d, e += d);\n            N.free(f);\n            return 0 >= g || 0 >= e ? !1 : 1 >= c * c / (g * g) + b * b / (e * e)\n        }\n        if (c.type === ud) return N.free(f), null === this.fill ? ee(c, a.x, a.y, e) : ce(c, a, e, 1 < this.strokeWidth, b);\n        B(\"Unknown Geometry type: \" + c.type);\n        return !1\n    };\n    t.sm = function (a, b, c, d) {\n        var e = this.desiredSize,\n            f = this.th;\n        a = Math.max(a, 0);\n        b = Math.max(b, 0);\n        if (null !== this.Qd) var g = this.geometry.bounds;\n        else {\n            var h = this.figure,\n                k = Dn[h];\n            if (void 0 === k) {\n                var l = J.Je[h];\n                \"string\" === typeof l && (l = J.Je[l]);\n                \"function\" === typeof l ? (k = l(null, 100, 100), Dn[h] = k) : B(\"Unsupported Figure: \" + h)\n            }\n            g = k.bounds\n        }\n        h = g.width;\n        k = g.height;\n        l = g.width;\n        var m = g.height;\n        switch (kl(this, !0)) {\n            case zg:\n                d = c = 0;\n                break;\n            case vd:\n                l = Math.max(a - f, 0);\n                m = Math.max(b - f, 0);\n                break;\n            case Wk:\n                l = Math.max(a - f, 0);\n                d = 0;\n                break;\n            case Xk:\n                c = 0, m =\n                    Math.max(b - f, 0)\n        }\n        isFinite(e.width) && (l = e.width);\n        isFinite(e.height) && (m = e.height);\n        e = this.maxSize;\n        g = this.minSize;\n        c = Math.max(c - f, g.width);\n        d = Math.max(d - f, g.height);\n        l = Math.min(e.width, l);\n        m = Math.min(e.height, m);\n        l = isFinite(l) ? Math.max(c, l) : Math.max(h, c);\n        m = isFinite(m) ? Math.max(d, m) : Math.max(k, d);\n        c = Ag(this);\n        switch (c) {\n            case zg:\n                break;\n            case vd:\n                h = l;\n                k = m;\n                break;\n            case Bg:\n                c = Math.min(l / h, m / k);\n                isFinite(c) || (c = 1);\n                h *= c;\n                k *= c;\n                break;\n            default:\n                B(c + \" is not a valid geometryStretch.\")\n        }\n        null !== this.Qd ? (h = Math.max(h, .01), k = Math.max(k,\n            .01), g = null !== this.Qd ? this.Qd : this.ka, e = h, d = k, c = g.copy(), g = g.bounds, e /= g.width, d /= g.height, isFinite(e) || (e = 1), isFinite(d) || (d = 1), 1 === e && 1 === d || c.scale(e, d), this.ka = c) : null !== this.ka && J.$(this.ka.kl, a - f) && J.$(this.ka.jl, b - f) || (this.ka = Lf.makeGeometry(this, h, k));\n        g = this.ka.bounds;\n        Infinity === a || Infinity === b ? hl(this, g.x - f / 2, g.y - f / 2, 0 === a && 0 === h ? 0 : g.width + f, 0 === b && 0 === k ? 0 : g.height + f) : hl(this, -(f / 2), -(f / 2), l + f, m + f)\n    };\n\n    function Ag(a) {\n        var b = a.geometryStretch;\n        return null !== a.Qd ? b === Vk ? vd : b : b === Vk ? Dn[a.figure].defaultStretch : b\n    }\n    t.Fh = function (a, b, c, d) {\n        ml(this, a, b, c, d)\n    };\n    t.Uc = function (a, b, c) {\n        return this.hk(a.x, a.y, b.x, b.y, c)\n    };\n    t.hk = function (a, b, c, d, e) {\n        var f = this.transform,\n            g = 1 / (f.m11 * f.m22 - f.m12 * f.m21),\n            h = f.m22 * g,\n            k = -f.m12 * g,\n            l = -f.m21 * g,\n            m = f.m11 * g,\n            n = g * (f.m21 * f.dy - f.m22 * f.dx),\n            p = g * (f.m12 * f.dx - f.m11 * f.dy);\n        f = a * h + b * l + n;\n        g = a * k + b * m + p;\n        h = c * h + d * l + n;\n        k = c * k + d * m + p;\n        n = this.th / 2;\n        l = this.ka;\n        null === l && (this.measure(Infinity, Infinity), l = this.ka);\n        p = l.bounds;\n        m = !1;\n        if (l.type === wd)\n            if (1.5 >= this.strokeWidth) m = J.De(l.startX, l.startY, l.endX, l.endY, f, g, h, k, e);\n            else {\n                l.startX === l.endX ? (d = n, m = 0) : (b = (l.endY - l.startY) / (l.endX - l.startX), m = n / Math.sqrt(1 + b * b), d = m *\n                    b);\n                b = Fa();\n                a = new I;\n                J.De(l.startX + d, l.startY + m, l.endX + d, l.endY + m, f, g, h, k, a) && b.push(a);\n                a = new I;\n                J.De(l.startX - d, l.startY - m, l.endX - d, l.endY - m, f, g, h, k, a) && b.push(a);\n                a = new I;\n                J.De(l.startX + d, l.startY + m, l.startX - d, l.startY - m, f, g, h, k, a) && b.push(a);\n                a = new I;\n                J.De(l.endX + d, l.endY + m, l.endX - d, l.endY - m, f, g, h, k, a) && b.push(a);\n                h = b.length;\n                if (0 === h) return Ha(b), !1;\n                m = !0;\n                k = Infinity;\n                for (d = 0; d < h; d++) a = b[d], c = (a.x - f) * (a.x - f) + (a.y - g) * (a.y - g), c < k && (k = c, e.x = a.x, e.y = a.y);\n                Ha(b)\n            }\n        else if (l.type === Gd) m = J.Uc(p.x - n, p.y - n, p.x + p.width +\n            n, p.y + p.height + n, f, g, h, k, e);\n        else if (l.type === Hd) {\n            b = N.allocAt(p.x, p.y, p.width, p.height).Vc(n, n);\n            a: if (0 === b.width) m = J.De(b.x, b.y, b.x, b.y + b.height, f, g, h, k, e);\n                else if (0 === b.height) m = J.De(b.x, b.y, b.x + b.width, b.y, f, g, h, k, e);\n            else {\n                a = b.width / 2;\n                l = b.height / 2;\n                d = b.x + a;\n                m = b.y + l;\n                c = 9999;\n                f !== h && (c = (g - k) / (f - h));\n                if (9999 > Math.abs(c)) {\n                    k = g - m - c * (f - d);\n                    if (0 > a * a * c * c + l * l - k * k) {\n                        e.x = NaN;\n                        e.y = NaN;\n                        m = !1;\n                        break a\n                    }\n                    n = Math.sqrt(a * a * c * c + l * l - k * k);\n                    h = (-(a * a * c * k) + a * l * n) / (l * l + a * a * c * c) + d;\n                    a = (-(a * a * c * k) - a * l * n) / (l * l + a * a * c * c) + d;\n                    l = c * (h - d) + k + m;\n                    k = c *\n                        (a - d) + k + m;\n                    Math.abs((f - h) * (f - h)) + Math.abs((g - l) * (g - l)) < Math.abs((f - a) * (f - a)) + Math.abs((g - k) * (g - k)) ? (e.x = h, e.y = l) : (e.x = a, e.y = k)\n                } else {\n                    h = l * l;\n                    k = f - d;\n                    h -= h / (a * a) * k * k;\n                    if (0 > h) {\n                        e.x = NaN;\n                        e.y = NaN;\n                        m = !1;\n                        break a\n                    }\n                    k = Math.sqrt(h);\n                    h = m + k;\n                    k = m - k;\n                    Math.abs(h - g) < Math.abs(k - g) ? (e.x = f, e.y = h) : (e.x = f, e.y = k)\n                }\n                m = !0\n            }\n            N.free(b)\n        } else if (l.type === ud) {\n            p = I.alloc();\n            var r = h - f;\n            var q = k - g;\n            var u = r * r + q * q;\n            e.x = h;\n            e.y = k;\n            for (var v = 0; v < l.figures.count; v++) {\n                var w = l.figures.j[v],\n                    y = w.segments;\n                r = w.startX;\n                q = w.startY;\n                for (var z = r, A = q, C = 0; C < y.count; C++) {\n                    var G =\n                        y.j[C],\n                        L = G.type;\n                    var K = G.endX;\n                    var V = G.endY;\n                    var Q = !1;\n                    switch (L) {\n                        case Wd:\n                            z = K;\n                            A = V;\n                            break;\n                        case yd:\n                            Q = En(r, q, K, V, f, g, h, k, p);\n                            break;\n                        case Xd:\n                            Q = J.eq(r, q, G.point1X, G.point1Y, G.point2X, G.point2Y, K, V, f, g, h, k, .6, p);\n                            break;\n                        case Yd:\n                            Q = J.eq(r, q, (r + 2 * G.point1X) / 3, (q + 2 * G.point1Y) / 3, (2 * G.point1X + K) / 3, (2 * G.point1X + K) / 3, K, V, f, g, h, k, .6, p);\n                            break;\n                        case Zd:\n                        case $d:\n                            L = G.type === Zd ? ae(G, w) : be(G, w, r, q);\n                            var ca = L.length;\n                            if (0 === ca) {\n                                Q = En(r, q, G.centerX, G.centerY, f, g, h, k, p);\n                                break\n                            }\n                            V = null;\n                            for (K = 0; K < ca; K++) {\n                                V = L[K];\n                                if (0 === K && En(r, q, V[0], V[1],\n                                        f, g, h, k, p)) {\n                                    var pa = Fn(f, g, p, u, e);\n                                    pa < u && (u = pa, m = !0)\n                                }\n                                J.eq(V[0], V[1], V[2], V[3], V[4], V[5], V[6], V[7], f, g, h, k, .6, p) && (pa = Fn(f, g, p, u, e), pa < u && (u = pa, m = !0))\n                            }\n                            K = V[6];\n                            V = V[7];\n                            break;\n                        default:\n                            B(\"Unknown Segment type: \" + L)\n                    }\n                    r = K;\n                    q = V;\n                    Q && (Q = Fn(f, g, p, u, e), Q < u && (u = Q, m = !0));\n                    G.isClosed && (K = z, V = A, En(r, q, K, V, f, g, h, k, p) && (G = Fn(f, g, p, u, e), G < u && (u = G, m = !0)))\n                }\n            }\n            f = c - a;\n            g = d - b;\n            h = Math.sqrt(f * f + g * g);\n            0 !== h && (f /= h, g /= h);\n            e.x -= f * n;\n            e.y -= g * n;\n            I.free(p)\n        } else B(\"Unknown Geometry type: \" + l.type);\n        if (!m) return !1;\n        this.transform.ra(e);\n        return !0\n    };\n\n    function Fn(a, b, c, d, e) {\n        a = c.x - a;\n        b = c.y - b;\n        b = a * a + b * b;\n        return b < d ? (e.x = c.x, e.y = c.y, b) : d\n    }\n\n    function En(a, b, c, d, e, f, g, h, k) {\n        var l = !1,\n            m = (e - g) * (b - d) - (f - h) * (a - c);\n        if (0 === m) return !1;\n        k.x = ((e * h - f * g) * (a - c) - (e - g) * (a * d - b * c)) / m;\n        k.y = ((e * h - f * g) * (b - d) - (f - h) * (a * d - b * c)) / m;\n        (a > c ? a - c : c - a) < (b > d ? b - d : d - b) ? (a = b < d ? b : d, b = b < d ? d : b, (k.y > a || J.$(k.y, a)) && (k.y < b || J.$(k.y, b)) && (l = !0)) : (b = a < c ? a : c, a = a < c ? c : a, (k.x > b || J.$(k.x, b)) && (k.x < a || J.$(k.x, a)) && (l = !0));\n        return l\n    }\n    t.Gh = function (a, b) {\n        if (void 0 === b) return a.ze(this.actualBounds);\n        var c = this.ka;\n        null === c && (this.measure(Infinity, Infinity), c = this.ka);\n        c = c.bounds;\n        var d = this.strokeWidth / 2,\n            e = !1,\n            f = I.alloc();\n        f.h(c.x - d, c.y - d);\n        a.aa(b.ra(f)) && (f.h(c.x - d, c.bottom + d), a.aa(b.ra(f)) && (f.h(c.right + d, c.bottom + d), a.aa(b.ra(f)) && (f.h(c.right + d, c.y - d), a.aa(b.ra(f)) && (e = !0))));\n        I.free(f);\n        return e\n    };\n    t.Gc = function (a, b) {\n        if (this.Gh(a, b) || void 0 === b && (b = this.transform, a.ze(this.actualBounds))) return !0;\n        var c = rd.alloc();\n        c.set(b);\n        c.tt();\n        var d = a.left,\n            e = a.right,\n            f = a.top;\n        a = a.bottom;\n        var g = I.alloc();\n        g.h(d, f);\n        c.ra(g);\n        if (this.Hh(g, !0)) return I.free(g), !0;\n        g.h(e, f);\n        c.ra(g);\n        if (this.Hh(g, !0)) return I.free(g), !0;\n        g.h(d, a);\n        c.ra(g);\n        if (this.Hh(g, !0)) return I.free(g), !0;\n        g.h(e, a);\n        c.ra(g);\n        if (this.Hh(g, !0)) return I.free(g), !0;\n        var h = I.alloc(),\n            k = I.alloc();\n        c.set(b);\n        c.Lv(this.transform);\n        c.tt();\n        h.x = e;\n        h.y = f;\n        h.transform(c);\n        g.x =\n            d;\n        g.y = f;\n        g.transform(c);\n        b = !1;\n        Gn(this, g, h, k) ? b = !0 : (g.x = e, g.y = a, g.transform(c), Gn(this, g, h, k) ? b = !0 : (h.x = d, h.y = a, h.transform(c), Gn(this, g, h, k) ? b = !0 : (g.x = d, g.y = f, g.transform(c), Gn(this, g, h, k) && (b = !0))));\n        I.free(g);\n        rd.free(c);\n        I.free(h);\n        I.free(k);\n        return b\n    };\n\n    function Gn(a, b, c, d) {\n        if (!a.Uc(b, c, d)) return !1;\n        a = b.x;\n        b = b.y;\n        var e = c.x,\n            f = c.y;\n        c = d.x;\n        d = d.y;\n        if (a === e) return b < f ? (a = b, b = f) : a = f, d >= a && d <= b;\n        a < e ? (d = a, a = e) : d = e;\n        return c >= d && c <= a\n    }\n    t.Lx = function (a, b, c) {\n        function d(a, b) {\n            for (var c = a.length, d = 0; d < c; d += 2)\n                if (b.dd(a[d], a[d + 1]) > e) return !0;\n            return !1\n        }\n        if (c && null !== this.fill && this.Hh(a, !0)) return !0;\n        var e = a.Ae(b),\n            f = e;\n        1.5 < this.strokeWidth && (e = this.strokeWidth / 2 + Math.sqrt(e), e *= e);\n        b = this.ka;\n        if (null === b && (this.measure(Infinity, Infinity), b = this.ka, null === b)) return !1;\n        if (!c) {\n            var g = b.bounds,\n                h = g.x,\n                k = g.y,\n                l = g.x + g.width;\n            g = g.y + g.height;\n            if (Bb(a.x, a.y, h, k) <= e && Bb(a.x, a.y, l, k) <= e && Bb(a.x, a.y, h, g) <= e && Bb(a.x, a.y, l, g) <= e) return !0\n        }\n        h = b.startX;\n        k = b.startY;\n        l =\n            b.endX;\n        g = b.endY;\n        if (b.type === wd) {\n            if (c = (h - l) * (a.x - l) + (k - g) * (a.y - g), Ab(a.x, a.y, h, k, l, g) <= (0 <= (l - h) * (a.x - h) + (g - k) * (a.y - k) && 0 <= c ? e : f)) return !0\n        } else {\n            if (b.type === Gd) return b = !1, c && (b = Ab(a.x, a.y, h, k, h, g) <= e || Ab(a.x, a.y, h, k, l, k) <= e || Ab(a.x, a.y, l, k, l, g) <= e || Ab(a.x, a.y, h, g, l, g) <= e), b;\n            if (b.type === Hd) {\n                b = a.x - (h + l) / 2;\n                f = a.y - (k + g) / 2;\n                var m = Math.abs(l - h) / 2,\n                    n = Math.abs(g - k) / 2;\n                if (0 === m || 0 === n) return Ab(a.x, a.y, h, k, l, g) <= e ? !0 : !1;\n                if (c) {\n                    if (a = J.bz(m, n, b, f), a * a <= e) return !0\n                } else return Bb(b, f, -m, 0) >= e || Bb(b, f, 0, -n) >= e || Bb(b,\n                    f, 0, n) >= e || Bb(b, f, m, 0) >= e ? !1 : !0\n            } else if (b.type === ud) {\n                l = b.bounds;\n                f = l.x;\n                h = l.y;\n                k = l.x + l.width;\n                l = l.y + l.height;\n                if (a.x > k && a.x < f && a.y > l && a.y < h && Ab(a.x, a.y, f, h, f, l) > e && Ab(a.x, a.y, f, h, k, h) > e && Ab(a.x, a.y, k, l, f, l) > e && Ab(a.x, a.y, k, l, k, h) > e) return !1;\n                f = Math.sqrt(e);\n                if (c) {\n                    if (null === this.fill ? ee(b, a.x, a.y, f) : ce(b, a, f, !0, !1)) return !0\n                } else {\n                    c = b.figures;\n                    for (b = 0; b < c.count; b++) {\n                        f = c.j[b];\n                        g = f.startX;\n                        m = f.startY;\n                        if (a.dd(g, m) > e) return !1;\n                        h = f.segments.j;\n                        k = h.length;\n                        for (l = 0; l < k; l++) switch (n = h[l], n.type) {\n                            case Wd:\n                            case yd:\n                                g = n.endX;\n                                m = n.endY;\n                                if (a.dd(g, m) > e) return !1;\n                                break;\n                            case Xd:\n                                var p = Fa();\n                                J.ye(g, m, n.point1X, n.point1Y, n.point2X, n.point2Y, n.endX, n.endY, .8, p);\n                                g = d(p, a);\n                                Ha(p);\n                                if (g) return !1;\n                                g = n.endX;\n                                m = n.endY;\n                                if (a.dd(g, m) > e) return !1;\n                                break;\n                            case Yd:\n                                p = Fa();\n                                J.Cq(g, m, n.point1X, n.point1Y, n.endX, n.endY, .8, p);\n                                g = d(p, a);\n                                Ha(p);\n                                if (g) return !1;\n                                g = n.endX;\n                                m = n.endY;\n                                if (a.dd(g, m) > e) return !1;\n                                break;\n                            case Zd:\n                            case $d:\n                                p = n.type === Zd ? ae(n, f) : be(n, f, g, m);\n                                var r = p.length;\n                                if (0 === r) {\n                                    g = n.centerX;\n                                    m = n.centerY;\n                                    if (a.dd(g, m) > e) return !1;\n                                    break\n                                }\n                                n = null;\n                                for (var q = Fa(), u = 0; u <\n                                    r; u++)\n                                    if (n = p[u], q.length = 0, J.ye(n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7], .8, q), d(q, a)) return Ha(q), !1;\n                                Ha(q);\n                                null !== n && (g = n[6], m = n[7]);\n                                break;\n                            default:\n                                B(\"Unknown Segment type: \" + n.type)\n                        }\n                    }\n                    return !0\n                }\n            }\n        }\n        return !1\n    };\n    t.cc = function () {\n        this.ka = null\n    };\n\n    function Hn(a) {\n        var b = a.diagram;\n        null !== b && b.undoManager.isUndoingRedoing || (a.segmentOrientation = In, \"None\" !== a.Yl ? (a.segmentIndex = -1, a.alignmentFocus = fd) : \"None\" !== a.al && (a.segmentIndex = 0, a.alignmentFocus = new P(1 - fd.x, fd.y)))\n    }\n    Lf.makeGeometry = function (a, b, c) {\n        if (\"None\" !== a.toArrow) var d = Jn[a.toArrow];\n        else \"None\" !== a.fromArrow ? d = Jn[a.fromArrow] : (d = J.Je[a.figure], \"string\" === typeof d && (d = J.Je[d]), void 0 === d && B(\"Unknown Shape.figure: \" + a.figure), d = d(a, b, c), d.kl = b, d.jl = c);\n        if (null === d) {\n            var e = J.Je.Rectangle;\n            \"function\" === typeof e && (d = e(a, b, c))\n        }\n        return d\n    };\n\n    function Kn(a) {\n        var b = Jn[a];\n        if (void 0 === b) {\n            var c = a.toLowerCase();\n            if (\"none\" === c) return \"None\";\n            b = Jn[c];\n            if (void 0 === b) {\n                var d = null,\n                    e;\n                for (e in J.Nm)\n                    if (e.toLowerCase() === c) {\n                        d = e;\n                        break\n                    } if (null !== d) return a = Id(J.Nm[d], !1), Jn[d] = a, c !== d && (Jn[c] = d), d\n            }\n        }\n        return \"string\" === typeof b ? b : b instanceof td ? a : null\n    }\n    ma.Object.defineProperties(Lf.prototype, {\n        geometry: {\n            get: function () {\n                return null !== this.ka ? this.ka : this.Qd\n            },\n            set: function (a) {\n                var b = this.ka;\n                if (b !== a) {\n                    null !== a ? this.Qd = this.ka = a.freeze() : this.Qd = this.ka = null;\n                    var c = this.part;\n                    null !== c && (c.gh = NaN);\n                    this.o();\n                    this.g(\"geometry\", b, a);\n                    el(this) && (a = this.part, null !== a && fl(this, a, \"geometryString\"))\n                }\n            }\n        },\n        geometryString: {\n            get: function () {\n                return null === this.geometry ? \"\" : this.geometry.toString()\n            },\n            set: function (a) {\n                a =\n                    Id(a);\n                var b = a.normalize();\n                this.geometry = a;\n                this.position = a = I.allocAt(-b.x, -b.y);\n                I.free(a)\n            }\n        },\n        isGeometryPositioned: {\n            get: function () {\n                return this.Zn\n            },\n            set: function (a) {\n                var b = this.Zn;\n                b !== a && (this.Zn = a, this.o(), this.g(\"isGeometryPositioned\", b, a))\n            }\n        },\n        fill: {\n            get: function () {\n                return this.$k\n            },\n            set: function (a) {\n                var b = this.$k;\n                b !== a && (null !== a && Rl(a, \"Shape.fill\"), a instanceof tl && a.freeze(), this.$k = a, this.M(), this.g(\"fill\", b, a))\n            }\n        },\n        stroke: {\n            get: function () {\n                return this.Dc\n            },\n            set: function (a) {\n                var b = this.Dc;\n                b !== a && (null !== a && Rl(a, \"Shape.stroke\"), a instanceof tl && a.freeze(), this.Dc = a, this.M(), this.g(\"stroke\", b, a))\n            }\n        },\n        strokeWidth: {\n            get: function () {\n                return this.th\n            },\n            set: function (a) {\n                var b = this.th;\n                if (b !== a)\n                    if (0 <= a) {\n                        this.th = a;\n                        this.o();\n                        var c = this.part;\n                        null !== c && (c.gh = NaN);\n                        this.g(\"strokeWidth\", b, a)\n                    } else va(a, \"value >= 0\", Lf, \"strokeWidth:value\")\n            }\n        },\n        strokeCap: {\n            get: function () {\n                return this.Rl\n            },\n            set: function (a) {\n                var b =\n                    this.Rl;\n                b !== a && (\"string\" !== typeof a || \"butt\" !== a && \"round\" !== a && \"square\" !== a ? va(a, '\"butt\", \"round\", or \"square\"', Lf, \"strokeCap\") : (this.Rl = a, this.M(), this.g(\"strokeCap\", b, a)))\n            }\n        },\n        strokeJoin: {\n            get: function () {\n                return this.Sl\n            },\n            set: function (a) {\n                var b = this.Sl;\n                b !== a && (\"string\" !== typeof a || \"miter\" !== a && \"bevel\" !== a && \"round\" !== a ? va(a, '\"miter\", \"bevel\", or \"round\"', Lf, \"strokeJoin\") : (this.Sl = a, this.M(), this.g(\"strokeJoin\", b, a)))\n            }\n        },\n        strokeMiterLimit: {\n            get: function () {\n                return this.Oj\n            },\n            set: function (a) {\n                var b = this.Oj;\n                if (b !== a && 1 <= a) {\n                    this.Oj = a;\n                    this.M();\n                    var c = this.part;\n                    null !== c && (c.gh = NaN);\n                    this.g(\"strokeMiterLimit\", b, a)\n                }\n            }\n        },\n        strokeDashArray: {\n            get: function () {\n                return this.rh\n            },\n            set: function (a) {\n                var b = this.rh;\n                if (b !== a) {\n                    if (null !== a) {\n                        for (var c = a.length, d = 0, e = 0; e < c; e++) {\n                            var f = a[e];\n                            0 <= f && isFinite(f) || B(\"strokeDashArray:value \" + f + \" at index \" + e + \" must be a positive number or zero.\");\n                            d += f\n                        }\n                        if (0 === d) {\n                            if (null === b) return;\n                            a = null\n                        }\n                    }\n                    this.rh = a;\n                    this.M();\n                    this.g(\"strokeDashArray\",\n                        b, a)\n                }\n            }\n        },\n        strokeDashOffset: {\n            get: function () {\n                return this.sh\n            },\n            set: function (a) {\n                var b = this.sh;\n                b !== a && 0 <= a && (this.sh = a, this.M(), this.g(\"strokeDashOffset\", b, a))\n            }\n        },\n        figure: {\n            get: function () {\n                return this.Zk\n            },\n            set: function (a) {\n                var b = this.Zk;\n                if (b !== a) {\n                    var c = J.Je[a];\n                    \"function\" === typeof c ? c = a : (c = J.Je[a.toLowerCase()]) || B(\"Unknown Shape.figure: \" + a);\n                    b !== c && (a = this.part, null !== a && (a.gh = NaN), this.Zk = c, this.Qd = null, this.cc(), this.o(), this.g(\"figure\", b, c))\n                }\n            }\n        },\n        toArrow: {\n            get: function () {\n                return this.Yl\n            },\n            set: function (a) {\n                var b = this.Yl;\n                !0 === a ? a = \"Standard\" : !1 === a && (a = \"\");\n                if (b !== a) {\n                    var c = Kn(a);\n                    null === c ? B(\"Unknown Shape.toArrow: \" + a) : b !== c && (this.Yl = c, this.Qd = null, this.cc(), this.o(), Hn(this), this.g(\"toArrow\", b, c))\n                }\n            }\n        },\n        fromArrow: {\n            get: function () {\n                return this.al\n            },\n            set: function (a) {\n                var b = this.al;\n                !0 === a ? a = \"Standard\" : !1 === a && (a = \"\");\n                if (b !== a) {\n                    var c = Kn(a);\n                    null === c ? B(\"Unknown Shape.fromArrow: \" + a) : b !== c && (this.al = c, this.Qd = null, this.cc(), this.o(),\n                        Hn(this), this.g(\"fromArrow\", b, c))\n                }\n            }\n        },\n        spot1: {\n            get: function () {\n                return this.hf\n            },\n            set: function (a) {\n                var b = this.hf;\n                b.w(a) || (this.hf = a = a.G(), this.o(), this.g(\"spot1\", b, a))\n            }\n        },\n        spot2: {\n            get: function () {\n                return this.jf\n            },\n            set: function (a) {\n                var b = this.jf;\n                b.w(a) || (this.jf = a = a.G(), this.o(), this.g(\"spot2\", b, a))\n            }\n        },\n        parameter1: {\n            get: function () {\n                return this.Zo\n            },\n            set: function (a) {\n                var b = this.Zo;\n                b !== a && (this.Zo = a, this.cc(), this.o(), this.g(\"parameter1\",\n                    b, a))\n            }\n        },\n        parameter2: {\n            get: function () {\n                return this.$o\n            },\n            set: function (a) {\n                var b = this.$o;\n                b !== a && (this.$o = a, this.cc(), this.o(), this.g(\"parameter2\", b, a))\n            }\n        },\n        naturalBounds: {\n            get: function () {\n                if (null !== this.ka) return this.oc.assign(this.ka.bounds), this.oc;\n                var a = this.desiredSize;\n                return new N(0, 0, a.width, a.height)\n            }\n        },\n        pathPattern: {\n            get: function () {\n                return this.bp\n            },\n            set: function (a) {\n                var b = this.bp;\n                b !== a && (this.bp = a, this.M(), this.g(\"pathPattern\",\n                    b, a))\n            }\n        },\n        geometryStretch: {\n            get: function () {\n                return this.Nn\n            },\n            set: function (a) {\n                var b = this.Nn;\n                b !== a && (this.Nn = a, this.g(\"geometryStretch\", b, a))\n            }\n        },\n        interval: {\n            get: function () {\n                return this.Hd\n            },\n            set: function (a) {\n                var b = this.Hd;\n                a = Math.round(a);\n                if (b !== a && 0 !== a && isFinite(a)) {\n                    this.Hd = a;\n                    var c = this.diagram;\n                    null !== c && this.panel === c.grid && mj(c);\n                    this.o();\n                    c = this.panel;\n                    null !== c && (c.$g = null);\n                    this.g(\"interval\", b, a)\n                }\n            }\n        },\n        graduatedStart: {\n            get: function () {\n                return this.Fd\n            },\n            set: function (a) {\n                var b = this.Fd;\n                b !== a && (0 > a ? a = 0 : 1 < a && (a = 1), this.Fd = a, this.o(), this.g(\"graduatedStart\", b, a))\n            }\n        },\n        graduatedEnd: {\n            get: function () {\n                return this.Dd\n            },\n            set: function (a) {\n                var b = this.Dd;\n                b !== a && (0 > a ? a = 0 : 1 < a && (a = 1), this.Dd = a, this.o(), this.g(\"graduatedEnd\", b, a))\n            }\n        },\n        graduatedSkip: {\n            get: function () {\n                return this.Ed\n            },\n            set: function (a) {\n                var b = this.Ed;\n                b !== a && (this.Ed = a, this.o(), this.g(\"graduatedSkip\", b, a))\n            }\n        }\n    });\n    Lf.prototype.intersectsRect = Lf.prototype.Gc;\n    Lf.prototype.containedInRect = Lf.prototype.Gh;\n    Lf.prototype.getNearestIntersectionPoint = Lf.prototype.Uc;\n    Lf.prototype.getDocumentBounds = Lf.prototype.lm;\n    Lf.prototype.getDocumentPoint = Lf.prototype.ga;\n    var Jn = new db,\n        Dn = new db;\n    Lf.className = \"Shape\";\n    Lf.getFigureGenerators = function () {\n        var a = new H,\n            b;\n        for (b in J.Je) b !== b.toLowerCase() && a.add(b, J.Je[b]);\n        a.freeze();\n        return a\n    };\n    Lf.defineFigureGenerator = function (a, b) {\n        var c = a.toLowerCase(),\n            d = J.Je;\n        d[a] = b;\n        d[c] = a\n    };\n    Lf.getArrowheadGeometries = function () {\n        var a = new H;\n        for (d in J.Nm)\n            if (void 0 === Jn[d]) {\n                var b = Id(J.Nm[d], !1);\n                Jn[d] = b;\n                b = d.toLowerCase();\n                b !== d && (Jn[b] = d)\n            } for (var c in Jn)\n            if (c !== c.toLowerCase()) {\n                var d = Jn[c];\n                d instanceof td && a.add(c, d)\n            } a.freeze();\n        return a\n    };\n    Lf.defineArrowheadGeometry = function (a, b) {\n        var c = null;\n        \"string\" === typeof b ? c = Id(b, !1) : c = b;\n        b = a.toLowerCase();\n        \"none\" !== b && a !== b || B(\"Shape.defineArrowheadGeometry name must not be empty or None or all-lower-case: \" + a);\n        var d = Jn;\n        d[a] = c;\n        d[b] = a\n    };\n\n    function Wg() {\n        Y.call(this);\n        Ln || (Mn = Ug ? (new Ck(null)).context : null, Ln = !0);\n        this.ix = this.Tb = \"\";\n        this.Dc = \"black\";\n        this.fe = \"13px sans-serif\";\n        this.Ii = \"start\";\n        this.Cd = zg;\n        this.Mi = bd;\n        this.xj = !0;\n        this.pi = this.ri = !1;\n        this.lg = Nn;\n        this.wg = On;\n        this.$r = this.pb = this.Nc = 0;\n        this.Du = this.Eu = null;\n        this.Dn = !1;\n        this.zc = this.en = this.Rp = this.Ji = this.Sp = null;\n        this.gf = this.ff = 0;\n        this.ne = Infinity;\n        this.ti = 0;\n        this.ge = null;\n        this.te = 0;\n        this.ee = this.fb = this.Qb = null;\n        this.Hd = 1;\n        this.Fd = 0;\n        this.Dd = 1;\n        this.Ed = this.tj = null\n    }\n    la(Wg, Y);\n    Wg.prototype.cloneProtected = function (a) {\n        Y.prototype.cloneProtected.call(this, a);\n        a.Tb = this.Tb;\n        a.ix = this.ix;\n        a.Dc = this.Dc;\n        a.fe = this.fe;\n        a.Ii = this.Ii;\n        a.Cd = this.Cd;\n        a.Mi = this.Mi;\n        a.xj = this.xj;\n        a.ri = this.ri;\n        a.pi = this.pi;\n        a.lg = this.lg;\n        a.wg = this.wg;\n        a.Nc = this.Nc;\n        a.$r = this.$r;\n        a.pb = this.pb;\n        a.Eu = this.Eu;\n        a.Du = this.Du;\n        a.Dn = this.Dn;\n        a.Sp = this.Sp;\n        a.Ji = this.Ji;\n        a.Rp = this.Rp;\n        a.en = this.en;\n        a.zc = this.zc;\n        a.ff = this.ff;\n        a.gf = this.gf;\n        a.ne = this.ne;\n        a.ge = this.ge;\n        a.te = this.te;\n        a.Qb = this.Qb;\n        a.fb = this.fb;\n        a.ee = this.ee;\n        a.ti = this.ti;\n        a.Hd =\n            this.Hd;\n        a.Fd = this.Fd;\n        a.Dd = this.Dd;\n        a.tj = this.tj;\n        a.Ed = this.Ed\n    };\n\n    function Tm(a, b) {\n        a.F = b.F | 6144;\n        a.qb = b.opacity;\n        a.gb = b.background;\n        a.dc = b.areaBackground;\n        a.Lc = b.desiredSize.G();\n        a.eg = b.minSize.G();\n        a.dg = b.maxSize.G();\n        a.bg = b.bg.copy();\n        a.ya = b.scale;\n        a.Yb = b.angle;\n        a.ve = b.stretch;\n        a.fh = b.margin.G();\n        a.vb = b.alignment.G();\n        a.Fk = b.alignmentFocus.G();\n        a.Hl = b.segmentFraction;\n        a.Il = b.segmentOffset.G();\n        a.Jl = b.segmentOrientation;\n        null !== b.ld && (a.ld = b.ld.copy());\n        a.Ll = b.shadowVisible;\n        b instanceof Wg && (a.Tb = b.Tb, a.Dc = b.Dc, a.fe = b.fe, a.Ii = b.Ii, a.Cd = b.Cd, a.Mi = b.Mi, a.xj = b.xj, a.ri = b.ri, a.pi = b.pi,\n            a.lg = b.lg, a.wg = b.wg, a.ge = null, a.ff = b.ff, a.gf = b.gf, a.ne = b.ne, a.ti = b.ti, a.Hd = b.Hd, a.Fd = b.Fd, a.Dd = b.Dd, a.tj = b.tj, a.Ed = b.Ed)\n    }\n    t = Wg.prototype;\n    t.cb = function (a) {\n        a.classType === Wg ? this.wrap = a : Y.prototype.cb.call(this, a)\n    };\n    t.toString = function () {\n        return 22 < this.Tb.length ? 'TextBlock(\"' + this.Tb.substring(0, 20) + '\"...)' : 'TextBlock(\"' + this.Tb + '\")'\n    };\n    t.o = function () {\n        Y.prototype.o.call(this);\n        this.Du = this.Eu = null\n    };\n    t.Qi = function (a, b) {\n        if (null !== this.Dc && 0 !== this.Tb.length && null !== this.fe) {\n            var c = this.naturalBounds,\n                d = this.actualBounds,\n                e = c.width,\n                f = c.height,\n                g = Pn(this),\n                h = a.textAlign = this.Ii,\n                k = b.nl;\n            \"start\" === h ? h = k ? \"right\" : \"left\" : \"end\" === h && (h = k ? \"left\" : \"right\");\n            k = this.ri;\n            var l = this.pi;\n            ii(this, a, this.Dc, !0, !1, c, d);\n            (k || l) && ii(this, a, this.Dc, !1, !1, c, d);\n            d = 0;\n            c = !1;\n            var m = I.allocAt(0, 0);\n            this.ud.ra(m);\n            var n = I.allocAt(0, g);\n            this.ud.ra(n);\n            var p = m.Ae(n);\n            I.free(m);\n            I.free(n);\n            m = b.scale;\n            8 > p * m * m && (c = !0);\n            b.Db !== a && (c = !1);\n            !1 === b.Be(\"textGreeking\") &&\n                (c = !1);\n            b = this.ff;\n            p = this.gf;\n            switch (this.flip) {\n                case $k:\n                    a.translate(e, 0);\n                    a.scale(-1, 1);\n                    break;\n                case Zk:\n                    a.translate(0, f);\n                    a.scale(1, -1);\n                    break;\n                case al:\n                    a.translate(e, f), a.scale(-1, -1)\n            }\n            m = this.Nc;\n            n = (b + g + p) * m;\n            f > n && (d = this.Mi, d = d.y * f - d.y * n + d.offsetY);\n            if (1 === m && null !== this.ee) p = this.pb, p > e && (p = e), this.Pi(this.ee, a, 0, d + b, e, g, p, c, h, k, l);\n            else if (null !== this.Qb && null !== this.fb)\n                for (n = 0; n < m; n++) {\n                    var r = this.Qb[n];\n                    r > e && (r = e);\n                    d += b;\n                    this.Pi(this.fb[n], a, 0, d, e, g, r, c, h, k, l);\n                    d += g + p\n                }\n            switch (this.flip) {\n                case $k:\n                    a.scale(-1, 1);\n                    a.translate(-e,\n                        0);\n                    break;\n                case Zk:\n                    a.scale(1, -1);\n                    a.translate(0, -f);\n                    break;\n                case al:\n                    a.scale(-1, -1), a.translate(-e, -f)\n            }\n        }\n    };\n    t.Pi = function (a, b, c, d, e, f, g, h, k, l, m) {\n        var n = 0;\n        h ? (\"left\" === k ? n = 0 : \"right\" === k ? n = e - g : \"center\" === k && (n = (e - g) / 2), b.fillRect(c + n, d + .25 * f, g, 1)) : (\"left\" === k ? n = 0 : \"right\" === k ? n = e : \"center\" === k && (n = e / 2), e = null !== Qn ? Qn(this, f) : .75 * f, b.fillText(a, c + n, d + e), a = f / 20 | 0, 0 === a && (a = 1), \"right\" === k ? n -= g : \"center\" === k && (n -= g / 2), l && (k = null !== Rn ? Rn(this, f) : .8 * f, b.beginPath(), b.lineWidth = a, b.moveTo(c + n, d + k), b.lineTo(c + n + g, d + k), b.stroke()), m && (b.beginPath(), b.lineWidth = a, d = d + f - f / 2.2 | 0, 0 !== a % 2 && (d += .5), b.moveTo(c + n, d), b.lineTo(c +\n            n + g, d), b.stroke()))\n    };\n    t.sm = function (a, b, c, d) {\n        this.ti = a;\n        var e = this.fe;\n        null !== Mn && Sn !== e && (Sn = Mn.font = e);\n        this.pb = this.te = 0;\n        this.ee = this.fb = this.Qb = this.ge = null;\n        var f;\n        if (isNaN(this.desiredSize.width)) {\n            e = this.Tb.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n            if (0 === e.length) e = 0;\n            else if (this.isMultiline) {\n                for (var g = f = 0, h = !1; !h;) {\n                    var k = e.indexOf(\"\\n\", g); - 1 === k && (k = e.length, h = !0);\n                    f = Math.max(f, Tn(e.substr(g, k - g).trim()));\n                    g = k + 1\n                }\n                e = f\n            } else f = e.indexOf(\"\\n\", 0), 0 <= f && (e = e.substr(0, f)), e = Tn(e);\n            e = Math.min(e, a / this.scale);\n            e = Math.max(8, e)\n        } else e =\n            this.desiredSize.width;\n        null !== this.panel && (e = Math.min(e, this.panel.maxSize.width));\n        f = Un(this, e);\n        isNaN(this.desiredSize.height) ? f = Math.min(f, b / this.scale) : f = this.desiredSize.height;\n        g = f;\n        if (0 !== this.pb && null !== this.Qb && null !== this.fb && this.lg === Vn && (b = this.fe, b = this.lg === Vn ? Wn(b) : 0, h = this.ff + this.gf, h = Math.max(0, Pn(this) + h), g = Math.min(this.maxLines - 1, Math.max(Math.floor(g / h + .01) - 1, 0)), !(g + 1 >= this.fb.length))) {\n            h = this.fb[g];\n            for (b = Math.max(1, a - b); Tn(h) > b && 1 < h.length;) h = h.substr(0, h.length - 1);\n            h += Xn;\n            b = Tn(h);\n            this.fb[g] = h;\n            this.fb = this.fb.slice(0, g + 1);\n            this.Qb[g] = b;\n            this.Qb = this.Qb.slice(0, g + 1);\n            this.te = this.fb.length;\n            this.pb = Math.max(this.pb, b);\n            this.Nc = this.te;\n            1 === this.Nc && (this.ee = this.fb[0])\n        }\n        if (this.wrap === Yn || isNaN(this.desiredSize.width)) e = isNaN(a) ? this.pb : Math.min(a, this.pb), isNaN(this.desiredSize.width) && (e = Math.max(8, e));\n        e = Math.max(c, e);\n        f = Math.max(d, f);\n        Vb(this.oc, e, f);\n        hl(this, 0, 0, e, f)\n    };\n    t.Fh = function (a, b, c, d) {\n        ml(this, a, b, c, d)\n    };\n\n    function Zn(a, b, c) {\n        if (null === a.ee) a.ee = b, a.pb = c;\n        else {\n            if (null === a.fb || null === a.Qb) a.fb = [], a.Qb = [], a.fb.push(a.ee), a.Qb.push(a.pb);\n            a.fb.push(b);\n            a.Qb.push(c)\n        }\n    }\n\n    function $n(a, b, c, d) {\n        b = b.trim();\n        var e = 0;\n        var f = a.fe;\n        var g = a.ff + a.gf;\n        g = Math.max(0, Pn(a) + g);\n        var h = a.lg === Vn ? Wn(f) : 0;\n        if (a.Nc >= a.ne) null !== d && d.h(0, g);\n        else {\n            var k = b;\n            if (a.wg === ao)\n                if (a.te = 1, f = Tn(b), 0 === h || f <= c) a.pb = Math.max(a.pb, f), Zn(a, b, a.pb), null !== d && d.h(f, g);\n                else {\n                    e = bo(a, k);\n                    k = k.substr(e.length);\n                    b = bo(a, k);\n                    for (f = Tn(e + b); 0 < b.length && f <= c;) e += b, k = k.substr(b.length), b = bo(a, k), f = Tn((e + b).trim());\n                    e += b.trim();\n                    for (c = Math.max(1, c - h); Tn(e) > c && 1 < e.length;) e = e.substr(0, e.length - 1);\n                    e += Xn;\n                    b = Tn(e);\n                    a.pb = b;\n                    Zn(a, e, b);\n                    null !==\n                        d && d.h(b, g)\n                }\n            else {\n                h = 0;\n                0 === k.length && (h = 1, Zn(a, k, 0));\n                for (; 0 < k.length;) {\n                    var l = bo(a, k);\n                    for (k = k.substr(l.length); Tn(l) > c;) {\n                        var m = 1;\n                        f = Tn(l.substr(0, m));\n                        for (b = 0; f <= c;) m++, b = f, f = Tn(l.substr(0, m));\n                        if (1 === m) {\n                            var n = f;\n                            e = Math.max(e, f)\n                        } else n = b, e = Math.max(e, b);\n                        m--;\n                        1 > m && (m = 1);\n                        Zn(a, l.substr(0, m), n);\n                        h++;\n                        l = l.substr(m);\n                        if (a.Nc + h > a.ne) break\n                    }\n                    b = bo(a, k);\n                    for (f = Tn(l + b); 0 < b.length && f <= c;) l += b, k = k.substr(b.length), b = bo(a, k), f = Tn((l + b).trim());\n                    l = l.trim();\n                    if (\"\" !== l && (\"\\u00ad\" === l[l.length - 1] && (l = l.substring(0, l.length - 1) + \"\\u2010\"),\n                            0 === b.length ? (m = f, e = Math.max(e, f)) : (m = b = Tn(l), e = Math.max(e, b)), Zn(a, l, m), h++, a.Nc + h > a.ne)) break\n                }\n                a.te = Math.min(a.ne, h);\n                a.pb = Math.max(a.pb, e);\n                null !== d && d.h(a.pb, g * a.te)\n            }\n        }\n    }\n\n    function bo(a, b) {\n        if (a.wg === co) return b.substr(0, 1);\n        a = b.length;\n        for (var c = 0, d = eo; c < a && !d.test(b.charAt(c));) c++;\n        for (; c < a && d.test(b.charAt(c));) c++;\n        return c >= a ? b : b.substr(0, c)\n    }\n\n    function Tn(a) {\n        return null === Mn ? 8 * a.length : Mn.measureText(a).width\n    }\n\n    function Pn(a) {\n        if (null !== a.ge) return a.ge;\n        var b = a.fe;\n        if (null === Mn) {\n            var c = 16;\n            return a.ge = c\n        }\n        void 0 !== fo[b] && 5E3 > go ? c = fo[b] : (c = 1.3 * Mn.measureText(\"M\").width, fo[b] = c, go++);\n        return a.ge = c\n    }\n\n    function Wn(a) {\n        if (null === Mn) return 6;\n        if (void 0 !== ho[a] && 5E3 > io) var b = ho[a];\n        else b = Mn.measureText(Xn).width, ho[a] = b, io++;\n        return b\n    }\n\n    function Un(a, b) {\n        var c = a.Tb.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\"),\n            d = a.ff + a.gf;\n        d = Math.max(0, Pn(a) + d);\n        if (0 === c.length) return a.pb = 0, a.Nc = 1, d;\n        if (!a.isMultiline) {\n            var e = c.indexOf(\"\\n\", 0);\n            0 <= e && (c = c.substr(0, e))\n        }\n        e = 0;\n        for (var f = a.Nc = 0, g, h = !1; !h;) {\n            g = c.indexOf(\"\\n\", f); - 1 === g && (g = c.length, h = !0);\n            if (f <= g) {\n                f = c.substr(f, g - f);\n                if (a.wg !== ao) {\n                    a.te = 0;\n                    var k = M.alloc();\n                    $n(a, f, b, k);\n                    e += k.height;\n                    M.free(k);\n                    a.Nc += a.te\n                } else $n(a, f, b, null), e += d, a.Nc++;\n                a.Nc === a.ne && (h = !0)\n            }\n            f = g + 1\n        }\n        return a.$r = e\n    }\n    ma.Object.defineProperties(Wg.prototype, {\n        font: {\n            get: function () {\n                return this.fe\n            },\n            set: function (a) {\n                var b = this.fe;\n                b !== a && (this.fe = a, this.ge = null, this.o(), this.g(\"font\", b, a))\n            }\n        },\n        text: {\n            get: function () {\n                return this.Tb\n            },\n            set: function (a) {\n                var b = this.Tb;\n                null !== a && void 0 !== a ? a = a.toString() : a = \"\";\n                b !== a && (this.Tb = a, this.o(), this.g(\"text\", b, a))\n            }\n        },\n        textAlign: {\n            get: function () {\n                return this.Ii\n            },\n            set: function (a) {\n                var b = this.Ii;\n                b === a || \"start\" !==\n                    a && \"end\" !== a && \"left\" !== a && \"right\" !== a && \"center\" !== a || (this.Ii = a, this.M(), this.g(\"textAlign\", b, a))\n            }\n        },\n        flip: {\n            get: function () {\n                return this.Cd\n            },\n            set: function (a) {\n                var b = this.Cd;\n                b !== a && (this.Cd = a, this.M(), this.g(\"flip\", b, a))\n            }\n        },\n        verticalAlignment: {\n            get: function () {\n                return this.Mi\n            },\n            set: function (a) {\n                var b = this.Mi;\n                b.w(a) || (this.Mi = a = a.G(), Cl(this), this.g(\"verticalAlignment\", b, a))\n            }\n        },\n        naturalBounds: {\n            get: function () {\n                if (!this.oc.v()) {\n                    var a =\n                        M.alloc();\n                    $n(this, this.Tb, 999999, a);\n                    var b = a.width;\n                    M.free(a);\n                    a = Un(this, b);\n                    var c = this.desiredSize;\n                    isNaN(c.width) || (b = c.width);\n                    isNaN(c.height) || (a = c.height);\n                    Vb(this.oc, b, a)\n                }\n                return this.oc\n            }\n        },\n        isMultiline: {\n            get: function () {\n                return this.xj\n            },\n            set: function (a) {\n                var b = this.xj;\n                b !== a && (this.xj = a, this.o(), this.g(\"isMultiline\", b, a))\n            }\n        },\n        isUnderline: {\n            get: function () {\n                return this.ri\n            },\n            set: function (a) {\n                var b = this.ri;\n                b !== a && (this.ri = a, this.M(), this.g(\"isUnderline\", b,\n                    a))\n            }\n        },\n        isStrikethrough: {\n            get: function () {\n                return this.pi\n            },\n            set: function (a) {\n                var b = this.pi;\n                b !== a && (this.pi = a, this.M(), this.g(\"isStrikethrough\", b, a))\n            }\n        },\n        wrap: {\n            get: function () {\n                return this.wg\n            },\n            set: function (a) {\n                var b = this.wg;\n                b !== a && (this.wg = a, this.o(), this.g(\"wrap\", b, a))\n            }\n        },\n        overflow: {\n            get: function () {\n                return this.lg\n            },\n            set: function (a) {\n                var b = this.lg;\n                b !== a && (this.lg = a, this.o(), this.g(\"overflow\", b, a))\n            }\n        },\n        stroke: {\n            get: function () {\n                return this.Dc\n            },\n            set: function (a) {\n                var b = this.Dc;\n                b !== a && (null !== a && Rl(a, \"TextBlock.stroke\"), a instanceof tl && a.freeze(), this.Dc = a, this.M(), this.g(\"stroke\", b, a))\n            }\n        },\n        lineCount: {\n            get: function () {\n                return this.Nc\n            }\n        },\n        editable: {\n            get: function () {\n                return this.Dn\n            },\n            set: function (a) {\n                var b = this.Dn;\n                b !== a && (this.Dn = a, this.g(\"editable\", b, a))\n            }\n        },\n        textEditor: {\n            get: function () {\n                return this.Sp\n            },\n            set: function (a) {\n                var b = this.Sp;\n                b !== a &&\n                    (this.Sp = a, this.g(\"textEditor\", b, a))\n            }\n        },\n        errorFunction: {\n            get: function () {\n                return this.zc\n            },\n            set: function (a) {\n                var b = this.zc;\n                b !== a && (this.zc = a, this.g(\"errorFunction\", b, a))\n            }\n        },\n        interval: {\n            get: function () {\n                return this.Hd\n            },\n            set: function (a) {\n                var b = this.Hd;\n                a = Math.round(a);\n                if (b !== a && 0 !== a && isFinite(a)) {\n                    this.Hd = a;\n                    this.o();\n                    var c = this.panel;\n                    null !== c && (c.$g = null);\n                    this.g(\"interval\", b, a)\n                }\n            }\n        },\n        graduatedStart: {\n            get: function () {\n                return this.Fd\n            },\n            set: function (a) {\n                var b = this.Fd;\n                b !== a && (0 > a ? a = 0 : 1 < a && (a = 1), this.Fd = a, this.o(), this.g(\"graduatedStart\", b, a))\n            }\n        },\n        graduatedEnd: {\n            get: function () {\n                return this.Dd\n            },\n            set: function (a) {\n                var b = this.Dd;\n                b !== a && (0 > a ? a = 0 : 1 < a && (a = 1), this.Dd = a, this.o(), this.g(\"graduatedEnd\", b, a))\n            }\n        },\n        graduatedFunction: {\n            get: function () {\n                return this.tj\n            },\n            set: function (a) {\n                var b = this.tj;\n                b !== a && (this.tj = a, this.o(), this.g(\"graduatedFunction\", b, a))\n            }\n        },\n        graduatedSkip: {\n            get: function () {\n                return this.Ed\n            },\n            set: function (a) {\n                var b = this.Ed;\n                b !== a && (this.Ed = a, this.o(), this.g(\"graduatedSkip\", b, a))\n            }\n        },\n        textValidation: {\n            get: function () {\n                return this.Ji\n            },\n            set: function (a) {\n                var b = this.Ji;\n                b !== a && (this.Ji = a, this.g(\"textValidation\", b, a))\n            }\n        },\n        textEdited: {\n            get: function () {\n                return this.Rp\n            },\n            set: function (a) {\n                var b = this.Rp;\n                b !== a && (this.Rp = a, this.g(\"textEdited\", b, a))\n            }\n        },\n        spacingAbove: {\n            get: function () {\n                return this.ff\n            },\n            set: function (a) {\n                var b =\n                    this.ff;\n                b !== a && (this.ff = a, this.g(\"spacingAbove\", b, a))\n            }\n        },\n        spacingBelow: {\n            get: function () {\n                return this.gf\n            },\n            set: function (a) {\n                var b = this.gf;\n                b !== a && (this.gf = a, this.g(\"spacingBelow\", b, a))\n            }\n        },\n        maxLines: {\n            get: function () {\n                return this.ne\n            },\n            set: function (a) {\n                var b = this.ne;\n                b !== a && (a = Math.floor(a), 0 >= a && va(a, \"> 0\", Wg, \"maxLines\"), this.ne = a, this.g(\"maxLines\", b, a), this.o())\n            }\n        },\n        metrics: {\n            get: function () {\n                return {\n                    arrSize: null !== this.Qb ? this.Qb : [this.pb],\n                    arrText: null !== this.fb ? this.fb : [this.ee],\n                    maxLineWidth: this.pb,\n                    fontHeight: this.ge\n                }\n            }\n        },\n        choices: {\n            get: function () {\n                return this.en\n            },\n            set: function (a) {\n                var b = this.en;\n                b !== a && (this.en = a, this.g(\"choices\", b, a))\n            }\n        }\n    });\n    var Qn = null,\n        Rn = null,\n        ao = new D(Wg, \"None\", 0),\n        Yn = new D(Wg, \"WrapFit\", 1),\n        On = new D(Wg, \"WrapDesiredSize\", 2),\n        co = new D(Wg, \"WrapBreakAll\", 3),\n        Nn = new D(Wg, \"OverflowClip\", 0),\n        Vn = new D(Wg, \"OverflowEllipsis\", 1),\n        eo = /[ \\u200b\\u00ad]/,\n        fo = new db,\n        go = 0,\n        ho = new db,\n        io = 0,\n        Xn = \"...\",\n        Sn = \"\",\n        Mn = null,\n        Ln = !1;\n    Wg.className = \"TextBlock\";\n    Wg.getEllipsis = function () {\n        return Xn\n    };\n    Wg.setEllipsis = function (a) {\n        Xn = a;\n        ho = new db;\n        io = 0\n    };\n    Wg.getBaseline = function () {\n        return Qn\n    };\n    Wg.setBaseline = function (a) {\n        Qn = a;\n        a = Pa();\n        for (var b = a.length, c = 0; c < b; c++) a[c].Ee()\n    };\n    Wg.getUnderline = function () {\n        return Rn\n    };\n    Wg.setUnderline = function (a) {\n        Rn = a;\n        a = Pa();\n        for (var b = a.length, c = 0; c < b; c++) a[c].Ee()\n    };\n    Wg.isValidFont = function (a) {\n        Ln || (Mn = Ug ? (new Ck(null)).context : null, Ln = !0);\n        if (null === Mn) return !0;\n        var b = Mn.font;\n        if (a === b || \"10px sans-serif\" === a) return !0;\n        Mn.font = \"10px sans-serif\";\n        Mn.font = a;\n        var c = Mn.font;\n        if (\"10px sans-serif\" !== c) return Mn.font = b, !0;\n        Mn.font = \"19px serif\";\n        var d = Mn.font;\n        Mn.font = a;\n        c = Mn.font;\n        Mn.font = b;\n        return c !== d\n    };\n    Wg.None = ao;\n    Wg.WrapFit = Yn;\n    Wg.WrapDesiredSize = On;\n    Wg.WrapBreakAll = co;\n    Wg.OverflowClip = Nn;\n    Wg.OverflowEllipsis = Vn;\n\n    function jo() {\n        this.Qb = [];\n        this.fb = []\n    }\n    jo.prototype.reset = function () {\n        this.Qb = [];\n        this.fb = []\n    };\n    jo.prototype.et = function (a) {\n        this.Qb = Ba(a.Qb);\n        this.fb = Ba(a.fb)\n    };\n    jo.className = \"TextBlockMetrics\";\n\n    function kk() {\n        Y.call(this);\n        this.Vg = null;\n        this.Jp = \"\";\n        this.qh = nc;\n        this.fl = vd;\n        this.kf = this.zc = null;\n        this.el = Ac;\n        this.Cd = zg;\n        this.Ul = null;\n        this.tu = !1;\n        this.Er = !0;\n        this.vl = !1;\n        this.Nl = null\n    }\n    la(kk, Y);\n    kk.prototype.cloneProtected = function (a) {\n        Y.prototype.cloneProtected.call(this, a);\n        a.element = this.Vg;\n        a.Jp = this.Jp;\n        a.qh = this.qh.G();\n        a.fl = this.fl;\n        a.Cd = this.Cd;\n        a.zc = this.zc;\n        a.kf = this.kf;\n        a.el = this.el.G();\n        a.Er = this.Er;\n        a.Nl = this.Nl\n    };\n    t = kk.prototype;\n    t.cb = function (a) {\n        a === zg || a === Bg || a === Yk ? this.imageStretch = a : Y.prototype.cb.call(this, a)\n    };\n    t.toString = function () {\n        return \"Picture(\" + this.source + \")#\" + lb(this)\n    };\n\n    function mk(a) {\n        void 0 === a && (a = \"\");\n        \"\" !== a ? ko[a] && (delete ko[a], lo--) : (ko = new db, lo = 0)\n    }\n\n    function mo(a, b) {\n        a.Pr = !0;\n        a.bl = !1;\n        for (var c, d = Pa(), e = d.length, f = 0; f < e; f++) {\n            var g = d[f];\n            c = a.getAttribute(\"src\");\n            var h = g.Ci.H(c);\n            if (null !== h)\n                for (var k = h.length, l = 0; l < k; l++) c = h[l], g.ss.add(c), g.Pb(), void 0 === a.Ou && (a.Ou = b, null !== c.kf && c.kf(c, b))\n        }\n    }\n\n    function no(a, b) {\n        a.bl = b;\n        for (var c, d = Pa(), e = d.length, f = 0; f < e; f++) {\n            var g = d[f],\n                h = a.getAttribute(\"src\");\n            c = g.Ci.H(h);\n            if (null !== c) {\n                g = c.length;\n                h = Fa();\n                for (var k = 0; k < g; k++) h.push(c[k]);\n                for (k = 0; k < g; k++) c = h[k], null !== c.zc && c.zc(c, b);\n                Ha(h)\n            }\n        }\n    }\n    t.Ee = function () {\n        this.M()\n    };\n    t.Qi = function (a, b) {\n        var c = this.Vg;\n        if (null !== c) {\n            var d = c.getAttribute(\"src\");\n            c instanceof HTMLImageElement && (null === d || \"\" === d) && B('Element has no source (\"src\") attribute: ' + c);\n            if (!(c.bl instanceof Event)) {\n                d = this.naturalBounds;\n                var e = 0,\n                    f = 0,\n                    g = this.tu,\n                    h = g ? +c.width : c.naturalWidth;\n                g = g ? +c.height : c.naturalHeight;\n                void 0 === h && c.videoWidth && (h = c.videoWidth);\n                void 0 === g && c.videoHeight && (g = c.videoHeight);\n                h = h || d.width;\n                g = g || d.height;\n                if (0 !== h && 0 !== g) {\n                    var k = h,\n                        l = g;\n                    this.sourceRect.v() && (e = this.qh.x, f = this.qh.y, h = this.qh.width,\n                        g = this.qh.height);\n                    var m = h,\n                        n = g,\n                        p = this.fl,\n                        r = this.el;\n                    switch (p) {\n                        case zg:\n                            if (this.sourceRect.v()) break;\n                            m >= d.width && (e = e + r.offsetX + (m * r.x - d.width * r.x));\n                            n >= d.height && (f = f + r.offsetY + (n * r.y - d.height * r.y));\n                            h = Math.min(d.width, m);\n                            g = Math.min(d.height, n);\n                            break;\n                        case vd:\n                            m = d.width;\n                            n = d.height;\n                            break;\n                        case Bg:\n                        case Yk:\n                            p === Bg ? (p = Math.min(d.height / n, d.width / m), m *= p, n *= p) : p === Yk && (p = Math.max(d.height / n, d.width / m), m *= p, n *= p, m >= d.width && (e = (e + r.offsetX + (m * r.x - d.width * r.x) / m) * h), n >= d.height && (f = (f + r.offsetY + (n * r.y - d.height * r.y) /\n                                n) * g), h *= 1 / (m / d.width), g *= 1 / (n / d.height), m = d.width, n = d.height)\n                    }\n                    p = this.uf() * b.scale;\n                    var q = m * p * n * p,\n                        u = h * g / q,\n                        v = c.__goCache;\n                    p = null;\n                    var w = oo;\n                    if (c.Pr && void 0 !== v && 4 < q && u > w * w)\n                        for (null === v.Oi && (po(v, 4, k, l, c), po(v, 16, k, l, c)), k = v.Oi, l = k.length, q = 0; q < l; q++)\n                            if (k[q].ratio * k[q].ratio < u) p = k[q];\n                            else break;\n                    if (!b.Xk) {\n                        if (null === this.Ul)\n                            if (null === this.Vg) this.Ul = !1;\n                            else {\n                                k = (new Ck(null)).context;\n                                k.drawImage(this.Vg, 0, 0);\n                                try {\n                                    k.getImageData(0, 0, 1, 1).data[3] && (this.Ul = !1), this.Ul = !1\n                                } catch (y) {\n                                    this.Ul = !0\n                                }\n                            } if (this.Ul) return\n                    }\n                    k =\n                        0;\n                    m < d.width && (k = r.offsetX + (d.width * r.x - m * r.x));\n                    l = 0;\n                    n < d.height && (l = r.offsetY + (d.height * r.y - n * r.y));\n                    switch (this.flip) {\n                        case $k:\n                            a.translate(Math.min(d.width, m), 0);\n                            a.scale(-1, 1);\n                            break;\n                        case Zk:\n                            a.translate(0, Math.min(d.height, n));\n                            a.scale(1, -1);\n                            break;\n                        case al:\n                            a.translate(Math.min(d.width, m), Math.min(d.height, n)), a.scale(-1, -1)\n                    }\n                    if (b.Be(\"pictureRatioOptimization\") && !b.ni && void 0 !== v && null !== p && 1 !== p.ratio) {\n                        a.save();\n                        b = p.ratio;\n                        try {\n                            a.drawImage(p.source, e / b, f / b, Math.min(p.source.width, h / b), Math.min(p.source.height,\n                                g / b), k, l, Math.min(d.width, m), Math.min(d.height, n))\n                        } catch (y) {\n                            this.Er = !1\n                        }\n                        a.restore()\n                    } else try {\n                        a.drawImage(c, e, f, h, g, k, l, Math.min(d.width, m), Math.min(d.height, n))\n                    } catch (y) {\n                        this.Er = !1\n                    }\n                    switch (this.flip) {\n                        case $k:\n                            a.scale(-1, 1);\n                            a.translate(-Math.min(d.width, m), 0);\n                            break;\n                        case Zk:\n                            a.scale(1, -1);\n                            a.translate(0, -Math.min(d.height, n));\n                            break;\n                        case al:\n                            a.scale(-1, -1), a.translate(-Math.min(d.width, m), -Math.min(d.height, n))\n                    }\n                }\n            }\n        }\n    };\n    t.sm = function (a, b, c, d) {\n        var e = this.desiredSize,\n            f = kl(this, !0),\n            g = this.Vg,\n            h = this.tu;\n        if (h || !this.vl && g && g.complete) this.vl = !0;\n        null === g && (isFinite(e.width) || (a = 0), isFinite(e.height) || (b = 0));\n        isFinite(e.width) || f === vd || f === Wk ? (isFinite(a) || (a = this.sourceRect.v() ? this.sourceRect.width : h ? +g.width : g.naturalWidth), c = 0) : null !== g && !1 !== this.vl && (a = this.sourceRect.v() ? this.sourceRect.width : h ? +g.width : g.naturalWidth);\n        isFinite(e.height) || f === vd || f === Xk ? (isFinite(b) || (b = this.sourceRect.v() ? this.sourceRect.height : h ?\n            +g.height : g.naturalHeight), d = 0) : null !== g && !1 !== this.vl && (b = this.sourceRect.v() ? this.sourceRect.height : h ? +g.height : g.naturalHeight);\n        isFinite(e.width) && (a = e.width);\n        isFinite(e.height) && (b = e.height);\n        e = this.maxSize;\n        f = this.minSize;\n        c = Math.max(c, f.width);\n        d = Math.max(d, f.height);\n        a = Math.min(e.width, a);\n        b = Math.min(e.height, b);\n        a = Math.max(c, a);\n        b = Math.max(d, b);\n        null === g || g.complete || (isFinite(a) || (a = 0), isFinite(b) || (b = 0));\n        Vb(this.oc, a, b);\n        hl(this, 0, 0, a, b)\n    };\n    t.Fh = function (a, b, c, d) {\n        ml(this, a, b, c, d)\n    };\n    ma.Object.defineProperties(kk.prototype, {\n        element: {\n            get: function () {\n                return this.Vg\n            },\n            set: function (a) {\n                var b = this.Vg;\n                if (b !== a) {\n                    null === a || a instanceof HTMLImageElement || a instanceof HTMLVideoElement || a instanceof HTMLCanvasElement || B(\"Picture.element must be an instance of Image, Canvas, or Video, not: \" + a);\n                    this.tu = a instanceof HTMLCanvasElement;\n                    this.Vg = a;\n                    if (null !== a)\n                        if (a instanceof HTMLCanvasElement || !0 === a.complete) a.bl instanceof Event && null !== this.zc && this.zc(this, a.bl),\n                            !0 === a.Pr && null !== this.kf && this.kf(this, a.Ou), a.Pr = !0, this.desiredSize.v() || (lj(this, !1), this.o());\n                        else {\n                            var c = this;\n                            a.Vw || (a.addEventListener(\"load\", function (b) {\n                                mo(a, b);\n                                c.desiredSize.v() || (lj(c, !1), c.o())\n                            }), a.addEventListener(\"error\", function (b) {\n                                no(a, b)\n                            }), a.Vw = !0)\n                        } this.g(\"element\", b, a);\n                    this.M()\n                }\n            }\n        },\n        source: {\n            get: function () {\n                return this.Jp\n            },\n            set: function (a) {\n                var b = this.Jp;\n                if (b !== a) {\n                    this.Jp = a;\n                    var c = ko,\n                        d = this.diagram,\n                        e = null;\n                    if (void 0 !== c[a]) e = c[a];\n                    else {\n                        30 < lo && (mk(), c = ko);\n                        e = ta(\"img\");\n                        var f = this;\n                        e.addEventListener(\"load\", function (a) {\n                            mo(e, a);\n                            f.desiredSize.v() || (lj(f, !1), f.o())\n                        });\n                        e.addEventListener(\"error\", function (a) {\n                            no(e, a)\n                        });\n                        e.Vw = !0;\n                        var g = this.Nl;\n                        null !== g && (e.crossOrigin = g(this));\n                        e.src = a;\n                        c[a] = e;\n                        lo++\n                    }\n                    null !== d && lk(d, this);\n                    this.element = e;\n                    null !== d && jk(d, this);\n                    void 0 === e.__goCache && (e.__goCache = new qo);\n                    this.o();\n                    this.M();\n                    this.g(\"source\", b, a)\n                }\n            }\n        },\n        sourceCrossOrigin: {\n            get: function () {\n                return this.Nl\n            },\n            set: function (a) {\n                if (this.Nl !== a && (this.Nl = a, null !== this.element)) {\n                    var b =\n                        this.element.getAttribute(\"src\");\n                    null === a && \"string\" === typeof b ? this.element.crossOrigin = null : null !== a && (this.element.crossOrigin = a(this));\n                    this.element.src = b\n                }\n            }\n        },\n        sourceRect: {\n            get: function () {\n                return this.qh\n            },\n            set: function (a) {\n                var b = this.qh;\n                b.w(a) || (this.qh = a = a.G(), this.M(), this.g(\"sourceRect\", b, a))\n            }\n        },\n        imageStretch: {\n            get: function () {\n                return this.fl\n            },\n            set: function (a) {\n                var b = this.fl;\n                b !== a && (this.fl = a, this.M(), this.g(\"imageStretch\", b, a))\n            }\n        },\n        flip: {\n            get: function () {\n                return this.Cd\n            },\n            set: function (a) {\n                var b = this.Cd;\n                b !== a && (this.Cd = a, this.M(), this.g(\"flip\", b, a))\n            }\n        },\n        imageAlignment: {\n            get: function () {\n                return this.el\n            },\n            set: function (a) {\n                var b = this.el;\n                b.w(a) || (this.el = a = a.G(), this.o(), this.g(\"imageAlignment\", b, a))\n            }\n        },\n        errorFunction: {\n            get: function () {\n                return this.zc\n            },\n            set: function (a) {\n                var b = this.zc;\n                b !== a && (this.zc = a, this.g(\"errorFunction\", b, a))\n            }\n        },\n        successFunction: {\n            get: function () {\n                return this.kf\n            },\n            set: function (a) {\n                var b = this.kf;\n                b !== a && (this.kf = a, this.g(\"successFunction\", b, a))\n            }\n        },\n        naturalBounds: {\n            get: function () {\n                return this.oc\n            }\n        }\n    });\n    var ko = null,\n        lo = 0,\n        oo = 4;\n    kk.className = \"Picture\";\n    ko = new db;\n    kk.clearCache = mk;\n\n    function qo() {\n        this.Oi = null\n    }\n\n    function po(a, b, c, d, e) {\n        null === a.Oi && (a.Oi = []);\n        var f = new Ck(null),\n            g = f.context,\n            h = 1 / b;\n        f.width = c / b;\n        f.height = d / b;\n        0 !== f.width && 0 !== f.height && (b = new ro(f.Ea, b), c = 1, 0 < a.Oi.length && (c = a.Oi[a.Oi.length - 1], e = c.source, c = c.ratio), g.setTransform(h * c, 0, 0, h * c, 0, 0), g.drawImage(e, 0, 0), a.Oi.push(b))\n    }\n    qo.className = \"PictureCacheArray\";\n\n    function ro(a, b) {\n        this.source = a;\n        this.ratio = b\n    }\n    ro.className = \"PictureCacheInstance\";\n\n    function so() {\n        this.mt = new td;\n        this.fc = null\n    }\n    t = so.prototype;\n    t.reset = function (a) {\n        null !== a ? (a.ea(), this.mt = a, a.figures.clear()) : this.mt = new td;\n        this.fc = null\n    };\n\n    function Kd(a, b, c, d, e) {\n        a.fc = new ke;\n        a.fc.startX = b;\n        a.fc.startY = c;\n        a.fc.isFilled = d;\n        a.mt.figures.add(a.fc);\n        void 0 !== e && (a.fc.isShadowed = e)\n    }\n\n    function Sd(a) {\n        var b = a.fc.segments.length;\n        0 < b && a.fc.segments.L(b - 1).close()\n    }\n    t.Lq = function (a) {\n        this.fc.isShadowed = a\n    };\n    t.moveTo = function (a, b, c) {\n        void 0 === c && (c = !1);\n        var d = new le(Wd);\n        d.endX = a;\n        d.endY = b;\n        c && d.close();\n        this.fc.segments.add(d)\n    };\n    t.lineTo = function (a, b, c) {\n        void 0 === c && (c = !1);\n        var d = new le(yd);\n        d.endX = a;\n        d.endY = b;\n        c && d.close();\n        this.fc.segments.add(d)\n    };\n\n    function Ld(a, b, c, d, e, f, g) {\n        var h;\n        void 0 === h && (h = !1);\n        var k = new le(Xd);\n        k.point1X = b;\n        k.point1Y = c;\n        k.point2X = d;\n        k.point2Y = e;\n        k.endX = f;\n        k.endY = g;\n        h && k.close();\n        a.fc.segments.add(k)\n    }\n\n    function Qd(a, b, c, d, e) {\n        var f;\n        void 0 === f && (f = !1);\n        var g = new le(Yd);\n        g.point1X = b;\n        g.point1Y = c;\n        g.endX = d;\n        g.endY = e;\n        f && g.close();\n        a.fc.segments.add(g)\n    }\n    t.arcTo = function (a, b, c, d, e, f, g) {\n        void 0 === f && (f = 0);\n        void 0 === g && (g = !1);\n        var h = new le(Zd);\n        h.startAngle = a;\n        h.sweepAngle = b;\n        h.centerX = c;\n        h.centerY = d;\n        h.radiusX = e;\n        h.radiusY = 0 !== f ? f : e;\n        g && h.close();\n        this.fc.segments.add(h)\n    };\n\n    function Rd(a, b, c, d, e, f, g, h) {\n        var k;\n        void 0 === k && (k = !1);\n        b = new le($d, g, h, b, c, d, e, f);\n        k && b.close();\n        a.fc.segments.add(b)\n    }\n\n    function Jd(a) {\n        var b = Td;\n        if (null !== b) return Td = null, b.reset(a), b;\n        b = new so;\n        b.reset(a);\n        return b\n    }\n    var Td = null;\n    so.className = \"StreamGeometryContext\";\n\n    function to(a, b) {\n        var c = a.toLowerCase(),\n            d = J.Je;\n        d[a] = b;\n        d[c] = a\n    }\n    to(\"Rectangle\", function (a, b, c) {\n        a = 50 > J.Gf;\n        var d = \"r\" + b + \",\" + c,\n            e = J.Ff[d];\n        if (void 0 !== e) return e;\n        e = new td(Gd);\n        e.endX = b;\n        e.endY = c;\n        a && (J.Ff[d] = e, J.Gf++);\n        return e\n    });\n    to(\"Square\", function (a, b, c) {\n        a = 50 > J.Gf;\n        var d = \"s\" + b + \",\" + c,\n            e = J.Ff[d];\n        if (void 0 !== e) return e;\n        e = new td(Gd);\n        e.endX = b;\n        e.endY = c;\n        e.defaultStretch = Bg;\n        a && (J.Ff[d] = e, J.Gf++);\n        return e\n    });\n    to(\"RoundedRectangle\", function (a, b, c) {\n        var d = 50 > J.Gf,\n            e = \"rr\" + b + \",\" + c,\n            f = J.Ff[e];\n        if (void 0 === f) {\n            f = a ? a.parameter1 : NaN;\n            if (isNaN(f) || 0 >= f) f = 5;\n            f = Math.min(f, b / 3);\n            f = Math.min(f, c / 3);\n            a = f * J.Ig;\n            f = (new td).add((new ke(f, 0, !0)).add(new le(yd, b - f, 0)).add(new le(Xd, b, f, b - a, 0, b, a)).add(new le(yd, b, c - f)).add(new le(Xd, b - f, c, b, c - a, b - a, c)).add(new le(yd, f, c)).add(new le(Xd, 0, c - f, a, c, 0, c - a)).add(new le(yd, 0, f)).add((new le(Xd, f, 0, 0, a, a, 0)).close()));\n            1 < a && (f.spot1 = new P(0, 0, a, a), f.spot2 = new P(1, 1, -a, -a));\n            d && (J.Ff[e] = f, J.Gf++)\n        }\n        return f\n    });\n    to(\"Border\", \"RoundedRectangle\");\n    to(\"Ellipse\", function (a, b, c) {\n        a = 50 > J.Gf;\n        var d = \"e\" + b + \",\" + c,\n            e = J.Ff[d];\n        if (void 0 !== e) return e;\n        e = new td(Hd);\n        e.endX = b;\n        e.endY = c;\n        e.spot1 = hd;\n        e.spot2 = id;\n        a && (J.Ff[d] = e, J.Gf++);\n        return e\n    });\n    to(\"Circle\", function (a, b, c) {\n        a = 50 > J.Gf;\n        var d = \"c\" + b + \",\" + c,\n            e = J.Ff[d];\n        if (void 0 !== e) return e;\n        e = new td(Hd);\n        e.endX = b;\n        e.endY = c;\n        e.spot1 = hd;\n        e.spot2 = id;\n        e.defaultStretch = Bg;\n        a && (J.Ff[d] = e, J.Gf++);\n        return e\n    });\n    to(\"TriangleRight\", function (a, b, c) {\n        return (new td).add((new ke(0, 0)).add(new le(yd, b, .5 * c)).add((new le(yd, 0, c)).close())).Jm(0, .25, .5, .75)\n    });\n    to(\"TriangleDown\", function (a, b, c) {\n        return (new td).add((new ke(0, 0)).add(new le(yd, b, 0)).add((new le(yd, .5 * b, c)).close())).Jm(.25, 0, .75, .5)\n    });\n    to(\"TriangleLeft\", function (a, b, c) {\n        return (new td).add((new ke(b, c)).add(new le(yd, 0, .5 * c)).add((new le(yd, b, 0)).close())).Jm(.5, .25, 1, .75)\n    });\n    to(\"TriangleUp\", function (a, b, c) {\n        return (new td).add((new ke(b, c)).add(new le(yd, 0, c)).add((new le(yd, .5 * b, 0)).close())).Jm(.25, .5, .75, 1)\n    });\n    to(\"Triangle\", \"TriangleUp\");\n    to(\"Diamond\", function (a, b, c) {\n        return (new td).add((new ke(.5 * b, 0)).add(new le(yd, 0, .5 * c)).add(new le(yd, .5 * b, c)).add((new le(yd, b, .5 * c)).close())).Jm(.25, .25, .75, .75)\n    });\n    to(\"LineH\", function (a, b, c) {\n        a = new td(wd);\n        a.startX = 0;\n        a.startY = c / 2;\n        a.endX = b;\n        a.endY = c / 2;\n        return a\n    });\n    to(\"LineV\", function (a, b, c) {\n        a = new td(wd);\n        a.startX = b / 2;\n        a.startY = 0;\n        a.endX = b / 2;\n        a.endY = c;\n        return a\n    });\n    to(\"None\", \"Rectangle\");\n    to(\"BarH\", \"Rectangle\");\n    to(\"BarV\", \"Rectangle\");\n    to(\"MinusLine\", \"LineH\");\n    to(\"PlusLine\", function (a, b, c) {\n        return (new td).add((new ke(0, c / 2, !1)).add(new le(yd, b, c / 2)).add(new le(Wd, b / 2, 0)).add(new le(yd, b / 2, c)))\n    });\n    to(\"XLine\", function (a, b, c) {\n        return (new td).add((new ke(0, c, !1)).add(new le(yd, b, 0)).add(new le(Wd, 0, 0)).add(new le(yd, b, c)))\n    });\n    J.Nm = {\n        \"\": \"\",\n        Standard: \"F1 m 0,0 l 8,4 -8,4 2,-4 z\",\n        Backward: \"F1 m 8,0 l -2,4 2,4 -8,-4 z\",\n        Triangle: \"F1 m 0,0 l 8,4.62 -8,4.62 z\",\n        BackwardTriangle: \"F1 m 8,4 l 0,4 -8,-4 8,-4 0,4 z\",\n        Boomerang: \"F1 m 0,0 l 8,4 -8,4 4,-4 -4,-4 z\",\n        BackwardBoomerang: \"F1 m 8,0 l -8,4 8,4 -4,-4 4,-4 z\",\n        SidewaysV: \"m 0,0 l 8,4 -8,4 0,-1 6,-3 -6,-3 0,-1 z\",\n        BackwardV: \"m 8,0 l -8,4 8,4 0,-1 -6,-3 6,-3 0,-1 z\",\n        OpenTriangle: \"m 0,0 l 8,4 -8,4\",\n        BackwardOpenTriangle: \"m 8,0 l -8,4 8,4\",\n        OpenTriangleLine: \"m 0,0 l 8,4 -8,4 m 8.5,0 l 0,-8\",\n        BackwardOpenTriangleLine: \"m 8,0 l  -8,4 8,4 m -8.5,0 l 0,-8\",\n        OpenTriangleTop: \"m 0,0 l 8,4 m 0,4\",\n        BackwardOpenTriangleTop: \"m 8,0 l -8,4 m 0,4\",\n        OpenTriangleBottom: \"m 0,8 l 8,-4\",\n        BackwardOpenTriangleBottom: \"m 0,4 l 8,4\",\n        HalfTriangleTop: \"F1 m 0,0 l 0,4 8,0 z m 0,8\",\n        BackwardHalfTriangleTop: \"F1 m 8,0 l 0,4 -8,0 z m 0,8\",\n        HalfTriangleBottom: \"F1 m 0,4 l 0,4 8,-4 z\",\n        BackwardHalfTriangleBottom: \"F1 m 8,4 l 0,4 -8,-4 z\",\n        ForwardSemiCircle: \"m 4,0 b 270 180 0 4 4\",\n        BackwardSemiCircle: \"m 4,8 b 90 180 0 -4 4\",\n        Feather: \"m 0,0 l 3,4 -3,4\",\n        BackwardFeather: \"m 3,0 l -3,4 3,4\",\n        DoubleFeathers: \"m 0,0 l 3,4 -3,4 m 3,-8 l 3,4 -3,4\",\n        BackwardDoubleFeathers: \"m 3,0 l -3,4 3,4 m 3,-8 l -3,4 3,4\",\n        TripleFeathers: \"m 0,0 l 3,4 -3,4 m 3,-8 l 3,4 -3,4 m 3,-8 l 3,4 -3,4\",\n        BackwardTripleFeathers: \"m 3,0 l -3,4 3,4 m 3,-8 l -3,4 3,4 m 3,-8 l -3,4 3,4\",\n        ForwardSlash: \"m 0,8 l 5,-8\",\n        BackSlash: \"m 0,0 l 5,8\",\n        DoubleForwardSlash: \"m 0,8 l 4,-8 m -2,8 l 4,-8\",\n        DoubleBackSlash: \"m 0,0 l 4,8 m -2,-8 l 4,8\",\n        TripleForwardSlash: \"m 0,8 l 4,-8 m -2,8 l 4,-8 m -2,8 l 4,-8\",\n        TripleBackSlash: \"m 0,0 l 4,8 m -2,-8 l 4,8 m -2,-8 l 4,8\",\n        Fork: \"m 0,4 l 8,0 m -8,0 l 8,-4 m -8,4 l 8,4\",\n        BackwardFork: \"m 8,4 l -8,0 m 8,0 l -8,-4 m 8,4 l -8,4\",\n        LineFork: \"m 0,0 l 0,8 m 0,-4 l 8,0 m -8,0 l 8,-4 m -8,4 l 8,4\",\n        BackwardLineFork: \"m 8,4 l -8,0 m 8,0 l -8,-4 m 8,4 l -8,4 m 8,-8 l 0,8\",\n        CircleFork: \"F1 m 6,4 b 0 360 -3 0 3 z m 0,0 l 6,0 m -6,0 l 6,-4 m -6,4 l 6,4\",\n        BackwardCircleFork: \"F1 m 0,4 l 6,0 m -6,-4 l 6,4 m -6,4 l 6,-4 m 6,0 b 0 360 -3 0 3\",\n        CircleLineFork: \"F1 m 6,4 b 0 360 -3 0 3 z m 1,-4 l 0,8 m 0,-4 l 6,0 m -6,0 l 6,-4 m -6,4 l 6,4\",\n        BackwardCircleLineFork: \"F1 m 0,4 l 6,0 m -6,-4 l 6,4 m -6,4 l 6,-4 m 0,-4 l 0,8 m 7,-4 b 0 360 -3 0 3\",\n        Circle: \"F1 m 8,4 b 0 360 -4 0 4 z\",\n        Block: \"F1 m 0,0 l 0,8 8,0 0,-8 z\",\n        StretchedDiamond: \"F1 m 0,3 l 5,-3 5,3 -5,3 -5,-3 z\",\n        Diamond: \"F1 m 0,4 l 4,-4 4,4 -4,4 -4,-4 z\",\n        Chevron: \"F1 m 0,0 l 5,0 3,4 -3,4 -5,0 3,-4 -3,-4 z\",\n        StretchedChevron: \"F1 m 0,0 l 8,0 3,4 -3,4 -8,0 3,-4 -3,-4 z\",\n        NormalArrow: \"F1 m 0,2 l 4,0 0,-2 4,4 -4,4 0,-2 -4,0 z\",\n        X: \"m 0,0 l 8,8 m 0,-8 l -8,8\",\n        TailedNormalArrow: \"F1 m 0,0 l 2,0 1,2 3,0 0,-2 2,4 -2,4 0,-2 -3,0 -1,2 -2,0 1,-4 -1,-4 z\",\n        DoubleTriangle: \"F1 m 0,0 l 4,4 -4,4 0,-8 z  m 4,0 l 4,4 -4,4 0,-8 z\",\n        BigEndArrow: \"F1 m 0,0 l 5,2 0,-2 3,4 -3,4 0,-2 -5,2 0,-8 z\",\n        ConcaveTailArrow: \"F1 m 0,2 h 4 v -2 l 4,4 -4,4 v -2 h -4 l 2,-2 -2,-2 z\",\n        RoundedTriangle: \"F1 m 0,1 a 1,1 0 0 1 1,-1 l 7,3 a 0.5,1 0 0 1 0,2 l -7,3 a 1,1 0 0 1 -1,-1 l 0,-6 z\",\n        SimpleArrow: \"F1 m 1,2 l -1,-2 2,0 1,2 -1,2 -2,0 1,-2 5,0 0,-2 2,2 -2,2 0,-2 z\",\n        AccelerationArrow: \"F1 m 0,0 l 0,8 0.2,0 0,-8 -0.2,0 z m 2,0 l 0,8 1,0 0,-8 -1,0 z m 3,0 l 2,0 2,4 -2,4 -2,0 0,-8 z\",\n        BoxArrow: \"F1 m 0,0 l 4,0 0,2 2,0 0,-2 2,4 -2,4 0,-2 -2,0 0,2 -4,0 0,-8 z\",\n        TriangleLine: \"F1 m 8,4 l -8,-4 0,8 8,-4 z m 0.5,4 l 0,-8\",\n        CircleEndedArrow: \"F1 m 10,4 l -2,-3 0,2 -2,0 0,2 2,0 0,2 2,-3 z m -4,0 b 0 360 -3 0 3 z\",\n        DynamicWidthArrow: \"F1 m 0,3 l 2,0 2,-1 2,-2 2,4 -2,4 -2,-2 -2,-1 -2,0 0,-2 z\",\n        EquilibriumArrow: \"m 0,3 l 8,0 -3,-3 m 3,5 l -8,0 3,3\",\n        FastForward: \"F1 m 0,0 l 3.5,4 0,-4 3.5,4 0,-4 1,0 0,8 -1,0 0,-4 -3.5,4 0,-4 -3.5,4 0,-8 z\",\n        Kite: \"F1 m 0,4 l 2,-4 6,4 -6,4 -2,-4 z\",\n        HalfArrowTop: \"F1 m 0,0 l 4,4 4,0 -8,-4 z m 0,8\",\n        HalfArrowBottom: \"F1 m 0,8 l 4,-4 4,0 -8,4 z\",\n        OpposingDirectionDoubleArrow: \"F1 m 0,4 l 2,-4 0,2 4,0 0,-2 2,4 -2,4 0,-2 -4,0 0,2 -2,-4 z\",\n        PartialDoubleTriangle: \"F1 m 0,0 4,3 0,-3 4,4 -4,4 0,-3 -4,3 0,-8 z\",\n        LineCircle: \"F1 m 0,0 l 0,8 m 7 -4 b 0 360 -3 0 3 z\",\n        DoubleLineCircle: \"F1 m 0,0 l 0,8 m 2,-8 l 0,8 m 7 -4 b 0 360 -3 0 3 z\",\n        TripleLineCircle: \"F1 m 0,0 l 0,8 m 2,-8 l 0,8 m 2,-8 l 0,8 m 7 -4 b 0 360 -3 0 3 z\",\n        CircleLine: \"F1 m 6 4 b 0 360 -3 0 3 z m 1,-4 l 0,8\",\n        DiamondCircle: \"F1 m 8,4 l -4,4 -4,-4 4,-4 4,4 m 8,0 b 0 360 -4 0 4 z\",\n        PlusCircle: \"F1 m 8,4 b 0 360 -4 0 4 l -8 0 z m -4 -4 l 0 8\",\n        OpenRightTriangleTop: \"m 8,0 l 0,4 -8,0 m 0,4\",\n        OpenRightTriangleBottom: \"m 8,8 l 0,-4 -8,0\",\n        Line: \"m 0,0 l 0,8\",\n        DoubleLine: \"m 0,0 l 0,8 m 2,0 l 0,-8\",\n        TripleLine: \"m 0,0 l 0,8 m 2,0 l 0,-8 m 2,0 l 0,8\",\n        PentagonArrow: \"F1 m 8,4 l -4,-4 -4,0 0,8 4,0 4,-4 z\"\n    };\n\n    function U(a) {\n        X.call(this, a);\n        this.D = 2408959;\n        this.eh = this.Lf = \"\";\n        this.mp = this.ip = this.yp = this.mo = null;\n        this.Ap = \"\";\n        this.Hf = this.Wn = this.zp = this.ph = null;\n        this.kp = \"\";\n        this.jp = Rb;\n        this.Tb = this.np = \"\";\n        this.ui = this.hn = this.di = null;\n        this.cg = (new I(NaN, NaN)).freeze();\n        this.to = \"\";\n        this.Xe = null;\n        this.uo = vc;\n        this.op = Zc;\n        this.Do = Gb;\n        this.vo = Hb;\n        this.An = null;\n        this.no = 127;\n        this.Ep = Ib;\n        this.Dp = \"gray\";\n        this.df = 4;\n        this.Xw = -1;\n        this.aq = NaN;\n        this.yy = new N;\n        this.Fj = null;\n        this.gh = NaN\n    }\n    la(U, X);\n    U.prototype.cloneProtected = function (a) {\n        X.prototype.cloneProtected.call(this, a);\n        a.D = this.D & -4097 | 49152;\n        a.Lf = this.Lf;\n        a.eh = this.eh;\n        a.mo = this.mo;\n        a.yp = this.yp;\n        a.ip = this.ip;\n        a.mp = this.mp;\n        a.Ap = this.Ap;\n        a.zp = this.zp;\n        a.Wn = this.Wn;\n        a.Hf = null;\n        a.kp = this.kp;\n        a.jp = this.jp.G();\n        a.np = this.np;\n        a.op = this.op.G();\n        a.Tb = this.Tb;\n        a.hn = this.hn;\n        a.cg.assign(this.cg);\n        a.to = this.to;\n        a.uo = this.uo.G();\n        a.Do = this.Do.G();\n        a.vo = this.vo.G();\n        a.An = this.An;\n        a.no = this.no;\n        a.Ep = this.Ep.G();\n        a.Dp = this.Dp;\n        a.df = this.df;\n        a.aq = this.aq\n    };\n    U.prototype.sf = function (a) {\n        X.prototype.sf.call(this, a);\n        a.Jh();\n        a.ph = null;\n        a.Xe = null;\n        a.Fj = null\n    };\n    U.prototype.toString = function () {\n        var a = Ia(this.constructor) + \"#\" + lb(this);\n        null !== this.data && (a += \"(\" + Ja(this.data) + \")\");\n        return a\n    };\n    U.prototype.vk = function (a, b, c, d, e, f, g) {\n        var h = this.diagram;\n        null !== h && (a === te && \"elements\" === b ? e instanceof X ? Dj(e, function (a) {\n            Fj(h.partManager, a);\n            Ej(h, a)\n        }) : jk(h, e) : a === ue && \"elements\" === b && (e instanceof X ? Dj(e, function (a) {\n            Ij(h.partManager, a, h)\n        }) : lk(h, e)), h.Ya(a, b, c, d, e, f, g))\n    };\n    U.prototype.Ba = function (a) {\n        X.prototype.Ba.call(this, a);\n        if (null !== this.data) {\n            for (var b = this.W.j, c = b.length, d = 0; d < c; d++) {\n                var e = b[d];\n                e instanceof X && Dj(e, function (a) {\n                    null !== a.data && a.Ba()\n                })\n            }\n            for (b = this.adornments; b.next();) b.value.Ba(a)\n        }\n    };\n    U.prototype.updateRelationshipsFromData = function () {\n        null !== this.data && this.diagram.partManager.updateRelationshipsFromData(this)\n    };\n    U.prototype.fk = function (a) {\n        var b = this.Hf;\n        return null === b ? null : b.H(a)\n    };\n    U.prototype.Ch = function (a, b) {\n        if (null !== b) {\n            var c = null,\n                d = this.Hf;\n            null !== d && (c = d.H(a));\n            if (c !== b) {\n                if (null !== c) {\n                    var e = c.diagram;\n                    null !== e && e.remove(c)\n                }\n                null === d && (this.Hf = d = new H);\n                b.Lf !== a && (b.category = a);\n                d.add(a, b);\n                a = this.diagram;\n                null !== a && (a.add(b), a = b.adornedObject, null !== a && (a = a.Ui(), null !== a && (b.data = a.data)))\n            }\n        }\n    };\n    U.prototype.Af = function (a) {\n        var b = this.Hf;\n        if (null !== b) {\n            var c = b.H(a);\n            if (null !== c) {\n                var d = c.diagram;\n                null !== d && d.remove(c)\n            }\n            b.remove(a);\n            0 === b.count && (this.Hf = null)\n        }\n    };\n    U.prototype.Yj = function () {\n        var a = this.Hf;\n        if (null !== a) {\n            var b = Fa();\n            for (a = a.iterator; a.next();) b.push(a.key);\n            a = b.length;\n            for (var c = 0; c < a; c++) this.Af(b[c]);\n            Ha(b)\n        }\n    };\n    U.prototype.updateAdornments = function () {\n        var a = this.diagram;\n        if (null !== a) {\n            for (var b = this.adornments; b.next();) {\n                var c = b.value;\n                c.o();\n                c.placeholder && c.placeholder.o()\n            }\n            a: {\n                if (this.isSelected && this.selectionAdorned && (b = this.selectionObject, null !== b && this.actualBounds.v() && this.isVisible() && b.zf() && b.actualBounds.v())) {\n                    c = this.fk(\"Selection\");\n                    if (null === c) {\n                        c = this.selectionAdornmentTemplate;\n                        null === c && (c = this.Kh() ? a.linkSelectionAdornmentTemplate : this instanceof T ? a.groupSelectionAdornmentTemplate : a.nodeSelectionAdornmentTemplate);\n                        if (!(c instanceof Je)) break a;\n                        yg(c);\n                        c = c.copy();\n                        null !== c && (this.Kh() && this.selectionObject === this.path && (c.type = X.Link), c.adornedObject = b)\n                    }\n                    if (null !== c) {\n                        c.type === X.Link && c.o();\n                        this.Ch(\"Selection\", c);\n                        break a\n                    }\n                }\n                this.Af(\"Selection\")\n            }\n            uo(this, a);\n            for (b = this.adornments; b.next();) b.value.Ba()\n        }\n    };\n    U.prototype.Lb = function () {\n        var a = this.diagram;\n        null !== a && (Ri(a), 0 !== (this.D & 16384) !== !0 && (gi(this, !0), a.Pb()))\n    };\n\n    function fi(a) {\n        0 !== (a.D & 16384) !== !1 && (a.updateAdornments(), gi(a, !1))\n    }\n\n    function uo(a, b) {\n        b.toolManager.mouseDownTools.each(function (b) {\n            b.isEnabled && b.updateAdornments(a)\n        });\n        b.toolManager.updateAdornments(a)\n    }\n\n    function vo(a) {\n        if (!1 === sj(a)) {\n            wo(a, !0);\n            a.ml();\n            var b = a.diagram;\n            null !== b && (b.nd.add(a), b.Pb())\n        }\n    }\n\n    function xo(a) {\n        a.D |= 2097152;\n        if (!1 !== sj(a)) {\n            var b = a.position,\n                c = a.location;\n            c.v() && b.v() || yo(a, b, c);\n            c = a.ub;\n            var d = N.alloc().assign(c);\n            c.ea();\n            c.x = b.x;\n            c.y = b.y;\n            c.freeze();\n            a.Et(d, c);\n            N.free(d);\n            wo(a, !1)\n        }\n    }\n    U.prototype.move = function (a, b) {\n        !0 === b ? this.location = a : this.position = a\n    };\n    U.prototype.moveTo = function (a, b, c) {\n        a = I.allocAt(a, b);\n        this.move(a, c);\n        I.free(a)\n    };\n    U.prototype.isVisible = function () {\n        if (!this.visible) return !1;\n        var a = this.layer;\n        if (null !== a) {\n            if (!a.visible) return !1;\n            a = a.diagram;\n            if (null !== a && a.animationManager.Dt(this)) return !0\n        }\n        a = this.containingGroup;\n        return null === a || a.isSubGraphExpanded && a.isVisible() ? !0 : !1\n    };\n    t = U.prototype;\n    t.Ob = function (a) {\n        var b = this.diagram;\n        a ? (this.C(4), this.Lb(), null !== b && b.nd.add(this)) : (this.C(8), this.Yj());\n        this.Jh();\n        null !== b && (b.Na(), b.M())\n    };\n    t.Xa = function (a) {\n        if (this.name === a) return this;\n        var b = this.Fj;\n        null === b && (this.Fj = b = new H);\n        if (null !== b.H(a)) return b.H(a);\n        var c = X.prototype.Xa.call(this, a);\n        if (null !== c) return b.set(a, c), c;\n        b.set(a, null);\n        return null\n    };\n    t.vf = function (a, b, c) {\n        void 0 === c && (c = new I);\n        b = b.jc() ? Ac : b;\n        var d = a.naturalBounds;\n        c.h(d.width * b.x + b.offsetX, d.height * b.y + b.offsetY);\n        if (null === a || a === this) return c;\n        a.transform.ra(c);\n        for (a = a.panel; null !== a && a !== this;) a.transform.ra(c), a = a.panel;\n        this.bg.ra(c);\n        c.offset(-this.nc.x, -this.nc.y);\n        return c\n    };\n    t.lm = function (a) {\n        void 0 === a && (a = new N);\n        return a.assign(this.actualBounds)\n    };\n    t.yb = function () {\n        !0 === qj(this) && this.measure(Infinity, Infinity);\n        this.arrange()\n    };\n\n    function Bj(a, b) {\n        var c = a.yy;\n        isNaN(a.gh) && (a.gh = cn(a));\n        var d = a.gh;\n        var e = 2 * d;\n        if (!a.isShadowed) return c.h(b.x - 1 - d, b.y - 1 - d, b.width + 2 + e, b.height + 2 + e), c;\n        d = b.x;\n        e = b.y;\n        var f = b.width;\n        b = b.height;\n        var g = a.shadowBlur;\n        a = a.shadowOffset;\n        f += g;\n        b += g;\n        d -= g / 2;\n        e -= g / 2;\n        0 < a.x ? f += a.x : (d += a.x, f -= a.x);\n        0 < a.y ? b += a.y : (e += a.y, b -= a.y);\n        c.h(d - 1, e - 1, f + 2, b + 2);\n        return c\n    }\n    U.prototype.arrange = function () {\n        if (!1 === rj(this)) xo(this);\n        else {\n            var a = this.ub,\n                b = N.alloc();\n            b.assign(a);\n            a.ea();\n            var c = wg(this);\n            this.Fh(0, 0, this.nc.width, this.nc.height);\n            var d = this.position;\n            yo(this, d, this.location);\n            a.x = d.x;\n            a.y = d.y;\n            a.freeze();\n            this.Et(b, a);\n            ll(this, !1);\n            b.w(a) ? this.yd(c) : !this.Wb() || J.A(b.width, a.width) && J.A(b.height, a.height) || 0 <= this.Xw && this.C(16);\n            N.free(b);\n            wo(this, !1)\n        }\n    };\n    t = U.prototype;\n    t.Et = function (a, b) {\n        var c = this.diagram;\n        if (null !== c) {\n            var d = !1;\n            if (!1 === c.ki && a.v()) {\n                var e = N.alloc();\n                e.assign(c.documentBounds);\n                e.kw(c.padding);\n                a.x > e.x && a.y > e.y && a.right < e.right && a.bottom < e.bottom && b.x > e.x && b.y > e.y && b.right < e.right && b.bottom < e.bottom && (d = !0);\n                N.free(e)\n            }\n            0 !== (this.D & 65536) !== !0 && a.w(b) || Gj(this, d, c);\n            c.M();\n            $b(a, b) || (this instanceof W && !c.undoManager.isUndoingRedoing && this.fd(), this.Jh())\n        }\n    };\n    t.gw = function (a, b) {\n        if (this.Kh() || !a.v()) return !1;\n        var c = this.diagram;\n        if (null !== c && (zo(this, c, a, b), !0 === c.undoManager.isUndoingRedoing)) return !0;\n        this.ma = a;\n        this.D &= -2097153;\n        c = this.cg;\n        if (c.v()) {\n            var d = c.copy();\n            c.h(c.x + (a.x - b.x), c.y + (a.y - b.y));\n            this.g(\"location\", d, c.copy())\n        }!1 === sj(this) && !1 === rj(this) && (vo(this), xo(this));\n        return !0\n    };\n\n    function zo(a, b, c, d) {\n        null === b || a instanceof Je || (b = b.animationManager, b.Ze && Jh(b, a, d.copy(), c.copy()))\n    }\n    t.Kq = function (a, b, c) {\n        var d = this.cg,\n            e = this.ma;\n        if (c) {\n            if (d.x === a && d.y === b) return;\n            sj(this) || rj(this) ? e.h(NaN, NaN) : e.h(e.x + a - d.x, e.y + b - d.y);\n            d.h(a, b)\n        } else {\n            if (e.x === a && e.y === b) return;\n            sj(this) || rj(this) ? d.h(NaN, NaN) : d.h(d.x + a - e.x, d.y + b - e.y);\n            e.h(a, b)\n        }\n        vo(this)\n    };\n    t.hw = function () {\n        this.D &= -2097153;\n        vo(this)\n    };\n\n    function yo(a, b, c) {\n        var d = I.alloc(),\n            e = a.locationSpot,\n            f = a.locationObject;\n        e.jc() && B(\"determineOffset: Part's locationSpot must be real: \" + e.toString());\n        var g = f.naturalBounds,\n            h = f instanceof Lf ? f.strokeWidth : 0;\n        d.xk(0, 0, g.width + h, g.height + h, e);\n        if (f !== a)\n            for (d.offset(-h / 2, -h / 2), f.transform.ra(d), e = f.panel; null !== e && e !== a;) e.transform.ra(d), e = e.panel;\n        a.bg.ra(d);\n        d.offset(-a.nc.x, -a.nc.y);\n        e = a.diagram;\n        f = c.v();\n        g = b.v();\n        f && g ? 0 !== (a.D & 2097152) ? Ao(a, b, c, e, d) : Bo(a, b, c, e, d) : f ? Ao(a, b, c, e, d) : g && Bo(a, b, c, e, d);\n        a.D |= 2097152;\n        I.free(d);\n        a.ml()\n    }\n\n    function Ao(a, b, c, d, e) {\n        var f = b.x,\n            g = b.y;\n        b.h(c.x - e.x, c.y - e.y);\n        null !== d && (c = d.animationManager, (e = c.isAnimating) || !c.Ze || a instanceof Je || Jh(c, a, new I(f, g), b), e || b.x === f && b.y === g || (c = d.skipsUndoManager, d.skipsUndoManager = !0, a.g(\"position\", new I(f, g), b), d.skipsUndoManager = c))\n    }\n\n    function Bo(a, b, c, d, e) {\n        var f = c.copy();\n        c.h(b.x + e.x, b.y + e.y);\n        c.w(f) || null === d || (b = d.skipsUndoManager, d.skipsUndoManager = !0, a.g(\"location\", f, c.copy()), d.skipsUndoManager = b)\n    }\n\n    function Gj(a, b, c) {\n        nl(a, !1);\n        a instanceof W && xk(c, a);\n        a.layer.isTemporary || b || c.Na();\n        b = a.ub;\n        var d = c.viewportBounds;\n        d.v() ? wg(a) ? (dc(b, d) || a.yd(!1), a.updateAdornments()) : b.Gc(d) ? (a.yd(!0), a.updateAdornments()) : a.Lb() : c.mi = !0\n    }\n    t.bj = function () {\n        return !0\n    };\n    t.Wb = function () {\n        return !0\n    };\n    t.Kh = function () {\n        return !1\n    };\n    t.xf = function () {\n        return !0\n    };\n\n    function Co(a, b, c, d) {\n        b.constructor === a.constructor || Do || (Do = !0, wa('Should not change the class of the Part when changing category from \"' + c + '\" to \"' + d + '\"'), wa(\"  Old class: \" + Ia(a.constructor) + \", new class: \" + Ia(b.constructor) + \", part: \" + a.toString()));\n        a.Yj();\n        var e = a.data;\n        c = a.layerName;\n        var f = a.isSelected,\n            g = a.isHighlighted,\n            h = !0,\n            k = !0,\n            l = !1;\n        a instanceof W && (h = a.isTreeLeaf, k = a.isTreeExpanded, l = a.wasTreeExpanded);\n        b.sf(a);\n        b.cloneProtected(a);\n        a.Lf = d;\n        a.o();\n        a.M();\n        b = a.diagram;\n        d = !0;\n        null !== b && (d = b.skipsUndoManager,\n            b.skipsUndoManager = !0);\n        a.hb = e;\n        a.D = f ? a.D | 4096 : a.D & -4097;\n        a.D = g ? a.D | 524288 : a.D & -524289;\n        a instanceof W && (a.P = h ? a.P | 4 : a.P & -5, a.P = k ? a.P | 1 : a.P & -2, a.P = l ? a.P | 2 : a.P & -3);\n        null !== e && a.Ba();\n        e = a.layerName;\n        e !== c && (a.eh = c, a.layerName = e);\n        null !== b && (b.skipsUndoManager = d);\n        a.Wb() && a.C(64)\n    }\n    U.prototype.canCopy = function () {\n        if (!this.copyable) return !1;\n        var a = this.layer;\n        if (null === a) return !0;\n        if (!a.allowCopy) return !1;\n        a = a.diagram;\n        return null === a ? !0 : a.allowCopy ? !0 : !1\n    };\n    U.prototype.canDelete = function () {\n        if (!this.deletable) return !1;\n        var a = this.layer;\n        if (null === a) return !0;\n        if (!a.allowDelete) return !1;\n        a = a.diagram;\n        return null === a ? !0 : a.allowDelete ? !0 : !1\n    };\n    U.prototype.canEdit = function () {\n        if (!this.textEditable) return !1;\n        var a = this.layer;\n        if (null === a) return !0;\n        if (!a.allowTextEdit) return !1;\n        a = a.diagram;\n        return null === a ? !0 : a.allowTextEdit ? !0 : !1\n    };\n    U.prototype.canGroup = function () {\n        if (!this.groupable) return !1;\n        var a = this.layer;\n        if (null === a) return !0;\n        if (!a.allowGroup) return !1;\n        a = a.diagram;\n        return null === a ? !0 : a.allowGroup ? !0 : !1\n    };\n    U.prototype.canMove = function () {\n        if (!this.movable) return !1;\n        var a = this.layer;\n        if (null === a) return !0;\n        if (!a.allowMove) return !1;\n        a = a.diagram;\n        return null === a ? !0 : a.allowMove ? !0 : !1\n    };\n    U.prototype.canReshape = function () {\n        if (!this.reshapable) return !1;\n        var a = this.layer;\n        if (null === a) return !0;\n        if (!a.allowReshape) return !1;\n        a = a.diagram;\n        return null === a ? !0 : a.allowReshape ? !0 : !1\n    };\n    U.prototype.canResize = function () {\n        if (!this.resizable) return !1;\n        var a = this.layer;\n        if (null === a) return !0;\n        if (!a.allowResize) return !1;\n        a = a.diagram;\n        return null === a ? !0 : a.allowResize ? !0 : !1\n    };\n    U.prototype.canRotate = function () {\n        if (!this.rotatable) return !1;\n        var a = this.layer;\n        if (null === a) return !0;\n        if (!a.allowRotate) return !1;\n        a = a.diagram;\n        return null === a ? !0 : a.allowRotate ? !0 : !1\n    };\n    U.prototype.canSelect = function () {\n        if (!this.selectable) return !1;\n        var a = this.layer;\n        if (null === a) return !0;\n        if (!a.allowSelect) return !1;\n        a = a.diagram;\n        return null === a ? !0 : a.allowSelect ? !0 : !1\n    };\n\n    function gi(a, b) {\n        a.D = b ? a.D | 16384 : a.D & -16385\n    }\n\n    function sj(a) {\n        return 0 !== (a.D & 32768)\n    }\n\n    function wo(a, b) {\n        a.D = b ? a.D | 32768 : a.D & -32769\n    }\n\n    function nl(a, b) {\n        a.D = b ? a.D | 65536 : a.D & -65537\n    }\n\n    function wg(a) {\n        return 0 !== (a.D & 131072)\n    }\n    t = U.prototype;\n    t.yd = function (a) {\n        this.D = a ? this.D | 131072 : this.D & -131073\n    };\n\n    function Eo(a, b) {\n        a.D = b ? a.D | 1048576 : a.D & -1048577\n    }\n    t.Jh = function () {\n        var a = this.containingGroup;\n        null !== a && (a.o(), null !== a.placeholder && a.placeholder.o(), a.fd())\n    };\n    t.M = function () {\n        var a = this.diagram;\n        null !== a && !rj(this) && !sj(this) && this.isVisible() && this.ub.v() && a.M(Bj(this, this.ub))\n    };\n    t.o = function () {\n        X.prototype.o.call(this);\n        var a = this.diagram;\n        null !== a && (a.nd.add(this), this instanceof W && null !== this.labeledLink && Cl(this.labeledLink), a.Pb(!0))\n    };\n    t.qq = function (a) {\n        a || (a = this.di, null !== a && Fo(a, this))\n    };\n    t.rq = function (a) {\n        a || (a = this.di, null !== a && Go(a, this))\n    };\n    t.dk = function () {\n        var a = this.data;\n        if (null !== a) {\n            var b = this.diagram;\n            null !== b && (b = b.model, null !== b && b.Am(a))\n        }\n    };\n    t.qz = function () {\n        return Ho(this, this)\n    };\n\n    function Ho(a, b) {\n        var c = b.containingGroup;\n        return null !== c ? 1 + Ho(a, c) : b instanceof W && (b = b.labeledLink, null !== b) ? Ho(a, b) : 0\n    }\n    t.uz = function () {\n        return Io(this, this)\n    };\n\n    function Io(a, b) {\n        var c = b.containingGroup;\n        return null !== c || b instanceof W && (c = b.labeledLink, null !== c) ? Io(a, c) : b\n    }\n    t.Wd = function (a) {\n        return a instanceof T ? Jo(this, this, a) : !1\n    };\n\n    function Jo(a, b, c) {\n        if (b === c || null === c) return !1;\n        var d = b.containingGroup;\n        return null === d || d !== c && !Jo(a, d, c) ? b instanceof W && (b = b.labeledLink, null !== b) ? Jo(a, b, c) : !1 : !0\n    }\n    t.Ix = function (a) {\n        if (null === a) return null;\n        if (this === a) return this.containingGroup;\n        for (var b = this; null !== b;) {\n            b instanceof T && Eo(b, !0);\n            if (b instanceof W) {\n                var c = b.labeledLink;\n                null !== c && (b = c)\n            }\n            b = b.containingGroup\n        }\n        c = null;\n        for (b = a; null !== b;) {\n            if (0 !== (b.D & 1048576)) {\n                c = b;\n                break\n            }\n            b instanceof W && (a = b.labeledLink, null !== a && (b = a));\n            b = b.containingGroup\n        }\n        for (b = this; null !== b;) b instanceof T && Eo(b, !1), b instanceof W && (a = b.labeledLink, null !== a && (b = a)), b = b.containingGroup;\n        return c\n    };\n    U.prototype.canLayout = function () {\n        if (!this.isLayoutPositioned || !this.isVisible()) return !1;\n        var a = this.layer;\n        return null !== a && a.isTemporary || this instanceof W && this.isLinkLabel ? !1 : !0\n    };\n    U.prototype.C = function (a) {\n        void 0 === a && (a = 16777215);\n        if (this.isLayoutPositioned && 0 !== (a & this.layoutConditions)) {\n            var b = this.layer;\n            null !== b && b.isTemporary || this instanceof W && this.isLinkLabel ? b = !1 : (b = this.diagram, b = null !== b && b.undoManager.isUndoingRedoing ? !1 : !0)\n        } else b = !1;\n        if (b)\n            if (b = this.di, null !== b) {\n                var c = b.layout;\n                null !== c ? c.C() : b.C(a)\n            } else a = this.diagram, null !== a && (a = a.layout, null !== a && a.C())\n    };\n\n    function Hj(a) {\n        if (!a.isVisible()) return !1;\n        a = a.layer;\n        return null !== a && a.isTemporary ? !1 : !0\n    }\n\n    function Sk(a, b, c, d, e, f) {\n        void 0 === f && (f = null);\n        if (!(a.contains(b) || null !== f && !f(b) || b instanceof Je))\n            if (a.add(b), b instanceof W) {\n                if (c && b instanceof T)\n                    for (var g = b.memberParts; g.next();) Sk(a, g.value, c, d, e, f);\n                if (!1 !== e)\n                    for (g = b.linksConnected; g.next();) {\n                        var h = g.value;\n                        if (!a.contains(h)) {\n                            var k = h.fromNode,\n                                l = h.toNode;\n                            k = null === k || a.contains(k);\n                            l = null === l || a.contains(l);\n                            (e ? k && l : k || l) && Sk(a, h, c, d, e, f)\n                        }\n                    }\n                if (1 < d)\n                    for (b = b.vv(); b.next();) Sk(a, b.value, c, d - 1, e, f)\n            } else if (b instanceof S)\n            for (b = b.labelNodes; b.next();) Sk(a,\n                b.value, c, d, e, f)\n    }\n    ma.Object.defineProperties(U.prototype, {\n        key: {\n            get: function () {\n                var a = this.diagram;\n                if (null !== a) return a.model.ja(this.data)\n            }\n        },\n        adornments: {\n            get: function () {\n                return null === this.Hf ? fb : this.Hf.iteratorValues\n            }\n        },\n        layer: {\n            get: function () {\n                return this.ui\n            }\n        },\n        diagram: {\n            get: function () {\n                var a = this.ui;\n                return null !== a ? a.diagram : null\n            }\n        },\n        layerName: {\n            get: function () {\n                return this.eh\n            },\n            set: function (a) {\n                var b =\n                    this.eh;\n                if (b !== a) {\n                    var c = this.diagram;\n                    if (null === c || null !== c.im(a) && !c.partManager.addsToTemporaryLayer)\n                        if (this.eh = a, null !== c && c.Na(), this.g(\"layerName\", b, a), b = this.layer, null !== b && b.name !== a && (c = b.diagram, null !== c && (a = c.im(a), null !== a && a !== b))) {\n                            var d = b.Fc(-1, this, !0);\n                            0 <= d && c.Ya(ue, \"parts\", b, this, null, d, !0);\n                            d = a.aj(99999999, this, !0);\n                            b.visible !== a.visible && this.Ob(a.visible);\n                            0 <= d && c.Ya(te, \"parts\", a, null, this, !0, d);\n                            d = this.layerChanged;\n                            if (null !== d) {\n                                var e = c.Z;\n                                c.Z = !0;\n                                d(this, b, a);\n                                c.Z = e\n                            }\n                        }\n                }\n            }\n        },\n        layerChanged: {\n            get: function () {\n                return this.mo\n            },\n            set: function (a) {\n                var b = this.mo;\n                b !== a && (this.mo = a, this.g(\"layerChanged\", b, a))\n            }\n        },\n        zOrder: {\n            get: function () {\n                return this.aq\n            },\n            set: function (a) {\n                var b = this.aq;\n                if (b !== a) {\n                    this.aq = a;\n                    var c = this.layer;\n                    null !== c && ji(c, -1, this);\n                    this.g(\"zOrder\", b, a);\n                    a = this.diagram;\n                    null !== a && a.M()\n                }\n            }\n        },\n        locationObject: {\n            get: function () {\n                if (null === this.Xe) {\n                    var a = this.locationObjectName;\n                    \"\" !== a ? (a = this.Xa(a), null !== a ? this.Xe = a : this.Xe = this) :\n                        this instanceof Je ? this.type !== X.Link && null !== this.placeholder ? this.Xe = this.placeholder : this.Xe = this : this.Xe = this\n                }\n                return this.Xe.visible ? this.Xe : this\n            }\n        },\n        minLocation: {\n            get: function () {\n                return this.Do\n            },\n            set: function (a) {\n                var b = this.Do;\n                b.w(a) || (this.Do = a = a.G(), this.g(\"minLocation\", b, a))\n            }\n        },\n        maxLocation: {\n            get: function () {\n                return this.vo\n            },\n            set: function (a) {\n                var b = this.vo;\n                b.w(a) || (this.vo = a = a.G(), this.g(\"maxLocation\", b, a))\n            }\n        },\n        locationObjectName: {\n            get: function () {\n                return this.to\n            },\n            set: function (a) {\n                var b = this.to;\n                b !== a && (this.to = a, this.Xe = null, this.o(), this.g(\"locationObjectName\", b, a))\n            }\n        },\n        locationSpot: {\n            get: function () {\n                return this.uo\n            },\n            set: function (a) {\n                var b = this.uo;\n                b.w(a) || (this.uo = a = a.G(), this.o(), this.g(\"locationSpot\", b, a))\n            }\n        },\n        location: {\n            get: function () {\n                return this.cg\n            },\n            set: function (a) {\n                var b = a.x,\n                    c = a.y,\n                    d = this.cg,\n                    e = d.x,\n                    f = d.y;\n                (e === b || isNaN(e) && isNaN(b)) && (f === c || isNaN(f) && isNaN(c)) ||\n                (a = a.copy(), b = a, this.Kh() ? b = !1 : (this.cg = b, this.D |= 2097152, !1 === rj(this) && (vo(this), c = this.ma, c.v() && (e = c.copy(), c.h(c.x + (b.x - d.x), c.y + (b.y - d.y)), zo(this, this.diagram, c, e), this.g(\"position\", e, c))), b = !0), b && this.g(\"location\", d.copy(), a.copy()))\n            }\n        },\n        category: {\n            get: function () {\n                return this.Lf\n            },\n            set: function (a) {\n                var b = this.Lf;\n                if (b !== a) {\n                    var c = this.diagram,\n                        d = this.data,\n                        e = null;\n                    if (null !== c && null !== d && !(this instanceof Je)) {\n                        var f = c.model.undoManager;\n                        f.isEnabled && !f.isUndoingRedoing && (e =\n                            this.clone(), e.W.addAll(this.W))\n                    }\n                    this.Lf = a;\n                    this.g(\"category\", b, a);\n                    null === c || null === d || this instanceof Je ? this instanceof Je && (e = this.adornedPart, null !== e && (a = e.Hf, null !== a && a.remove(b), e.Ch(this.category, this))) : (f = c.model, f.undoManager.isUndoingRedoing || (this.Kh() ? (c.partManager.setLinkCategoryForData(d, a), c = c.partManager.findLinkTemplateForCategory(a), null !== c && (yg(c), c = c.copy(), null !== c && Co(this, c, b, a))) : (null !== f && f.Jq(d, a), c = Ko(c.partManager, d, a), null !== c && (yg(c), c = c.copy(), null === c || c instanceof S || (d = this.location.copy(), Co(this, c, b, a), this.location.v() || (this.location = d)))), null !== e && (b = this.clone(), b.W.addAll(this.W), this.g(\"self\", e, b))))\n                }\n            }\n        },\n        self: {\n            get: function () {\n                return this\n            },\n            set: function (a) {\n                Co(this, a, this.category, a.category)\n            }\n        },\n        copyable: {\n            get: function () {\n                return 0 !== (this.D & 1)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 1);\n                b !== a && (this.D ^= 1, this.g(\"copyable\", b, a))\n            }\n        },\n        deletable: {\n            get: function () {\n                return 0 !== (this.D &\n                    2)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 2);\n                b !== a && (this.D ^= 2, this.g(\"deletable\", b, a))\n            }\n        },\n        textEditable: {\n            get: function () {\n                return 0 !== (this.D & 4)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 4);\n                b !== a && (this.D ^= 4, this.g(\"textEditable\", b, a), this.Lb())\n            }\n        },\n        groupable: {\n            get: function () {\n                return 0 !== (this.D & 8)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 8);\n                b !== a && (this.D ^= 8, this.g(\"groupable\", b, a))\n            }\n        },\n        movable: {\n            get: function () {\n                return 0 !== (this.D & 16)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 16);\n                b !== a && (this.D ^= 16, this.g(\"movable\", b, a))\n            }\n        },\n        selectionAdorned: {\n            get: function () {\n                return 0 !== (this.D & 32)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 32);\n                b !== a && (this.D ^= 32, this.g(\"selectionAdorned\", b, a), this.Lb())\n            }\n        },\n        isInDocumentBounds: {\n            get: function () {\n                return 0 !== (this.D & 64)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 64);\n                if (b !== a) {\n                    this.D ^= 64;\n                    var c = this.diagram;\n                    null !== c && c.Na();\n                    this.g(\"isInDocumentBounds\", b, a)\n                }\n            }\n        },\n        isLayoutPositioned: {\n            get: function () {\n                return 0 !== (this.D & 128)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 128);\n                b !== a && (this.D ^= 128, this.g(\"isLayoutPositioned\", b, a), this.C(a ? 4 : 8))\n            }\n        },\n        selectable: {\n            get: function () {\n                return 0 !== (this.D & 256)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 256);\n                b !== a && (this.D ^= 256, this.g(\"selectable\", b, a), this.Lb())\n            }\n        },\n        reshapable: {\n            get: function () {\n                return 0 !== (this.D & 512)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 512);\n                b !== a && (this.D ^= 512, this.g(\"reshapable\",\n                    b, a), this.Lb())\n            }\n        },\n        resizable: {\n            get: function () {\n                return 0 !== (this.D & 1024)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 1024);\n                b !== a && (this.D ^= 1024, this.g(\"resizable\", b, a), this.Lb())\n            }\n        },\n        rotatable: {\n            get: function () {\n                return 0 !== (this.D & 2048)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 2048);\n                b !== a && (this.D ^= 2048, this.g(\"rotatable\", b, a), this.Lb())\n            }\n        },\n        isSelected: {\n            get: function () {\n                return 0 !== (this.D & 4096)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 4096);\n                if (b !== a) {\n                    var c = this.diagram;\n                    if (!a || this.canSelect() && !(null !== c && c.selection.count >= c.maxSelectionCount)) {\n                        this.D ^= 4096;\n                        var d = !1;\n                        if (null !== c) {\n                            d = c.skipsUndoManager;\n                            c.skipsUndoManager = !0;\n                            var e = c.selection;\n                            e.ea();\n                            a ? e.add(this) : e.remove(this);\n                            e.freeze()\n                        }\n                        this.g(\"isSelected\", b, a);\n                        this.Lb();\n                        a = this.selectionChanged;\n                        null !== a && a(this);\n                        null !== c && (c.Pb(), c.skipsUndoManager = d)\n                    }\n                }\n            }\n        },\n        isHighlighted: {\n            get: function () {\n                return 0 !== (this.D & 524288)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 524288);\n                if (b !== a) {\n                    this.D ^= 524288;\n                    var c = this.diagram;\n                    null !== c && (c = c.highlighteds, c.ea(), a ? c.add(this) : c.remove(this), c.freeze());\n                    this.g(\"isHighlighted\", b, a);\n                    this.M();\n                    a = this.highlightedChanged;\n                    null !== a && a(this)\n                }\n            }\n        },\n        isShadowed: {\n            get: function () {\n                return 0 !== (this.D & 8192)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D & 8192);\n                b !== a && (this.D ^= 8192, this.g(\"isShadowed\", b, a), this.M())\n            }\n        },\n        isAnimated: {\n            get: function () {\n                return 0 !== (this.D & 262144)\n            },\n            set: function (a) {\n                var b = 0 !== (this.D &\n                    262144);\n                b !== a && (this.D ^= 262144, this.g(\"isAnimated\", b, a))\n            }\n        },\n        highlightedChanged: {\n            get: function () {\n                return this.Wn\n            },\n            set: function (a) {\n                var b = this.Wn;\n                b !== a && (this.Wn = a, this.g(\"highlightedChanged\", b, a))\n            }\n        },\n        selectionObjectName: {\n            get: function () {\n                return this.Ap\n            },\n            set: function (a) {\n                var b = this.Ap;\n                b !== a && (this.Ap = a, this.ph = null, this.g(\"selectionObjectName\", b, a))\n            }\n        },\n        selectionAdornmentTemplate: {\n            get: function () {\n                return this.yp\n            },\n            set: function (a) {\n                var b =\n                    this.yp;\n                b !== a && (this.yp = a, this.g(\"selectionAdornmentTemplate\", b, a))\n            }\n        },\n        selectionObject: {\n            get: function () {\n                if (null === this.ph) {\n                    var a = this.selectionObjectName;\n                    null !== a && \"\" !== a ? (a = this.Xa(a), null !== a ? this.ph = a : this.ph = this) : this instanceof S ? (a = this.path, null !== a ? this.ph = a : this.ph = this) : this.ph = this\n                }\n                return this.ph\n            }\n        },\n        selectionChanged: {\n            get: function () {\n                return this.zp\n            },\n            set: function (a) {\n                var b = this.zp;\n                b !== a && (this.zp = a, this.g(\"selectionChanged\", b, a))\n            }\n        },\n        resizeAdornmentTemplate: {\n            get: function () {\n                return this.ip\n            },\n            set: function (a) {\n                var b = this.ip;\n                b !== a && (this.ip = a, this.g(\"resizeAdornmentTemplate\", b, a))\n            }\n        },\n        resizeObjectName: {\n            get: function () {\n                return this.kp\n            },\n            set: function (a) {\n                var b = this.kp;\n                b !== a && (this.kp = a, this.g(\"resizeObjectName\", b, a))\n            }\n        },\n        resizeObject: {\n            get: function () {\n                var a = this.resizeObjectName;\n                return \"\" !== a && (a = this.Xa(a), null !== a) ? a : this\n            }\n        },\n        resizeCellSize: {\n            get: function () {\n                return this.jp\n            },\n            set: function (a) {\n                var b = this.jp;\n                b.w(a) || (this.jp = a = a.G(), this.g(\"resizeCellSize\", b, a))\n            }\n        },\n        rotateAdornmentTemplate: {\n            get: function () {\n                return this.mp\n            },\n            set: function (a) {\n                var b = this.mp;\n                b !== a && (this.mp = a, this.g(\"rotateAdornmentTemplate\", b, a))\n            }\n        },\n        rotateObjectName: {\n            get: function () {\n                return this.np\n            },\n            set: function (a) {\n                var b = this.np;\n                b !== a && (this.np = a, this.g(\"rotateObjectName\", b, a))\n            }\n        },\n        rotateObject: {\n            get: function () {\n                var a = this.rotateObjectName;\n                return \"\" !== a && (a = this.Xa(a), null !== a) ? a : this\n            }\n        },\n        rotationSpot: {\n            get: function () {\n                return this.op\n            },\n            set: function (a) {\n                var b = this.op;\n                b.w(a) || (this.op = a = a.G(), this.g(\"rotationSpot\", b, a))\n            }\n        },\n        text: {\n            get: function () {\n                return this.Tb\n            },\n            set: function (a) {\n                var b = this.Tb;\n                b !== a && (this.Tb = a, this.g(\"text\", b, a))\n            }\n        },\n        containingGroup: {\n            get: function () {\n                return this.di\n            },\n            set: function (a) {\n                if (this.Wb()) {\n                    var b =\n                        this.di;\n                    if (b !== a) {\n                        null === a || this !== a && !a.Wd(this) || (this === a && B(\"Cannot make a Group a member of itself: \" + this.toString()), B(\"Cannot make a Group indirectly contain itself: \" + this.toString() + \" already contains \" + a.toString()));\n                        this.C(2);\n                        var c = this.diagram;\n                        null !== b ? Go(b, this) : this instanceof T && null !== c && c.zh.remove(this);\n                        this.di = a;\n                        null !== a ? Fo(a, this) : this instanceof T && null !== c && c.zh.add(this);\n                        this.C(1);\n                        if (null !== c && c.Z) {\n                            var d = this.data,\n                                e = c.model;\n                            if (null !== d && e.jk()) {\n                                var f = e.ja(null !== a ? a.data : null);\n                                e.Mt(d, f)\n                            }\n                        }\n                        d = this.containingGroupChanged;\n                        null !== d && (e = !0, null !== c && (e = c.Z, c.Z = !0), d(this, b, a), null !== c && (c.Z = e));\n                        if (this instanceof T)\n                            for (c = new F, Sk(c, this, !0, 0, !0), c = c.iterator; c.next();)\n                                if (d = c.value, d instanceof W)\n                                    for (d = d.linksConnected; d.next();) Lo(d.value);\n                        if (this instanceof W) {\n                            for (c = this.linksConnected; c.next();) Lo(c.value);\n                            c = this.labeledLink;\n                            null !== c && Lo(c)\n                        }\n                        this.g(\"containingGroup\", b, a);\n                        null !== a && (b = a.layer, null !== b && ji(b, -1, a))\n                    }\n                } else B(\"cannot set the Part.containingGroup of a Link or Adornment\")\n            }\n        },\n        containingGroupChanged: {\n            get: function () {\n                return this.hn\n            },\n            set: function (a) {\n                var b = this.hn;\n                b !== a && (this.hn = a, this.g(\"containingGroupChanged\", b, a))\n            }\n        },\n        isTopLevel: {\n            get: function () {\n                return null !== this.containingGroup || this instanceof W && null !== this.labeledLink ? !1 : !0\n            }\n        },\n        layoutConditions: {\n            get: function () {\n                return this.no\n            },\n            set: function (a) {\n                var b = this.no;\n                b !== a && (this.no = a, this.g(\"layoutConditions\", b, a))\n            }\n        },\n        dragComputation: {\n            get: function () {\n                return this.An\n            },\n            set: function (a) {\n                var b = this.An;\n                b !== a && (this.An = a, this.g(\"dragComputation\", b, a))\n            }\n        },\n        shadowOffset: {\n            get: function () {\n                return this.Ep\n            },\n            set: function (a) {\n                var b = this.Ep;\n                b.w(a) || (this.Ep = a = a.G(), this.M(), this.g(\"shadowOffset\", b, a))\n            }\n        },\n        shadowColor: {\n            get: function () {\n                return this.Dp\n            },\n            set: function (a) {\n                var b = this.Dp;\n                b !== a && (this.Dp = a, this.M(), this.g(\"shadowColor\", b, a))\n            }\n        },\n        shadowBlur: {\n            get: function () {\n                return this.df\n            },\n            set: function (a) {\n                var b = this.df;\n                b !== a && (this.df = a, this.M(), this.g(\"shadowBlur\", b, a))\n            }\n        }\n    });\n    U.prototype.invalidateLayout = U.prototype.C;\n    U.prototype.findCommonContainingGroup = U.prototype.Ix;\n    U.prototype.isMemberOf = U.prototype.Wd;\n    U.prototype.findTopLevelPart = U.prototype.uz;\n    U.prototype.findSubGraphLevel = U.prototype.qz;\n    U.prototype.ensureBounds = U.prototype.yb;\n    U.prototype.getDocumentBounds = U.prototype.lm;\n    U.prototype.getRelativePoint = U.prototype.vf;\n    U.prototype.findObject = U.prototype.Xa;\n    U.prototype.moveTo = U.prototype.moveTo;\n    U.prototype.invalidateAdornments = U.prototype.Lb;\n    U.prototype.clearAdornments = U.prototype.Yj;\n    U.prototype.removeAdornment = U.prototype.Af;\n    U.prototype.addAdornment = U.prototype.Ch;\n    U.prototype.findAdornment = U.prototype.fk;\n    U.prototype.updateTargetBindings = U.prototype.Ba;\n    var Do = !1;\n    U.className = \"Part\";\n    U.LayoutNone = 0;\n    U.LayoutAdded = 1;\n    U.LayoutRemoved = 2;\n    U.LayoutShown = 4;\n    U.LayoutHidden = 8;\n    U.LayoutNodeSized = 16;\n    U.LayoutGroupLayout = 32;\n    U.LayoutNodeReplaced = 64;\n    U.LayoutStandard = 127;\n    U.LayoutAll = 16777215;\n\n    function Je(a) {\n        U.call(this, a);\n        this.D &= -257;\n        this.eh = \"Adornment\";\n        this.ae = null;\n        this.ax = 0;\n        this.qx = !1;\n        this.l = [];\n        this.Sa = null\n    }\n    la(Je, U);\n    Je.prototype.toString = function () {\n        var a = this.adornedPart;\n        return \"Adornment(\" + this.category + \")\" + (null !== a ? a.toString() : \"\")\n    };\n    Je.prototype.updateRelationshipsFromData = function () {};\n    Je.prototype.nk = function (a) {\n        var b = this.adornedObject.part;\n        if (b instanceof S && this.adornedObject instanceof Lf) {\n            var c = b.path;\n            b.nk(a);\n            a = c.geometry;\n            b = this.W.j;\n            c = b.length;\n            for (var d = 0; d < c; d++) {\n                var e = b[d];\n                e.isPanelMain && e instanceof Lf && (e.ka = a)\n            }\n        }\n    };\n    Je.prototype.bj = function () {\n        var a = this.ae;\n        if (null === a) return !0;\n        a = a.part;\n        return null === a || !rj(a)\n    };\n    Je.prototype.Wb = function () {\n        return !1\n    };\n    Je.prototype.vk = function (a, b, c, d, e, f, g) {\n        if (a === te && \"elements\" === b)\n            if (e instanceof xg) null === this.Sa && (this.Sa = e);\n            else {\n                if (e instanceof X) {\n                    var h = e.hm(function (a) {\n                        return a instanceof xg\n                    });\n                    h instanceof xg && null === this.Sa && (this.Sa = h)\n                }\n            }\n        else a === ue && \"elements\" === b && null !== this.Sa && (d === this.Sa ? this.Sa = null : d instanceof X && this.Sa.Dg(d) && (this.Sa = null));\n        U.prototype.vk.call(this, a, b, c, d, e, f, g)\n    };\n    Je.prototype.updateAdornments = function () {};\n    Je.prototype.dk = function () {};\n    ma.Object.defineProperties(Je.prototype, {\n        placeholder: {\n            get: function () {\n                return this.Sa\n            }\n        },\n        adornedObject: {\n            get: function () {\n                return this.ae\n            },\n            set: function (a) {\n                var b = this.adornedPart,\n                    c = null;\n                null !== a && (c = a.part);\n                null === b || null !== a && b === c || b.Af(this.category);\n                this.ae = a;\n                null !== c && c.Ch(this.category, this)\n            }\n        },\n        adornedPart: {\n            get: function () {\n                var a = this.ae;\n                return null !== a ? a.part : null\n            }\n        },\n        containingGroup: {\n            get: function () {\n                return null\n            }\n        }\n    });\n    Je.className = \"Adornment\";\n\n    function W(a) {\n        U.call(this, a);\n        this.P = 13;\n        this.Wa = new E;\n        this.Wp = this.rl = this.xi = this.po = this.oo = null;\n        this.Ik = tc;\n        this.rc = this.Me = null;\n        this.fp = Mo;\n        this.Ah = !1\n    }\n    la(W, U);\n    W.prototype.cloneProtected = function (a) {\n        U.prototype.cloneProtected.call(this, a);\n        a.P = this.P;\n        a.P = this.P & -17;\n        a.oo = this.oo;\n        a.po = this.po;\n        a.xi = this.xi;\n        a.Wp = this.Wp;\n        a.Ik = this.Ik.G();\n        a.fp = this.fp\n    };\n    t = W.prototype;\n    t.sf = function (a) {\n        U.prototype.sf.call(this, a);\n        a.fd();\n        a.Me = this.Me;\n        a.rc = null\n    };\n\n    function No(a, b) {\n        null !== b && (null === a.Me && (a.Me = new F), a.Me.add(b))\n    }\n\n    function Oo(a, b, c, d) {\n        if (null === b || null === a.Me) return null;\n        for (var e = a.Me.iterator; e.next();) {\n            var f = e.value;\n            if (f.Bt === a && f.Mv === b && f.Zx === c && f.$x === d || f.Bt === b && f.Mv === a && f.Zx === d && f.$x === c) return f\n        }\n        return null\n    }\n    t.Tz = function (a, b, c) {\n        if (void 0 === b || null === b) b = \"\";\n        if (void 0 === c || null === c) c = \"\";\n        a = Oo(this, a, b, c);\n        null !== a && a.nm()\n    };\n    t.vk = function (a, b, c, d, e, f, g) {\n        a === te && \"elements\" === b ? this.rc = null : a === ue && \"elements\" === b && (this.rc = null);\n        U.prototype.vk.call(this, a, b, c, d, e, f, g)\n    };\n    t.fd = function (a) {\n        void 0 === a && (a = null);\n        for (var b = this.linksConnected; b.next();) {\n            var c = b.value;\n            null !== a && a.contains(c) || (Po(this, c.fromPort), Po(this, c.toPort), c.Oa())\n        }\n    };\n\n    function ol(a, b) {\n        for (var c = a.linksConnected; c.next();) {\n            var d = c.value;\n            if (d.fromPort === b || d.toPort === b) Po(a, d.fromPort), Po(a, d.toPort), d.Oa()\n        }\n    }\n\n    function Po(a, b) {\n        null !== b && (b = b.ep, null !== b && b.nm(), a = a.containingGroup, null === a || a.isSubGraphExpanded || Po(a, a.port))\n    }\n    t.bj = function () {\n        return !0\n    };\n    W.prototype.getAvoidableRect = function (a) {\n        a.set(this.actualBounds);\n        a.cq(this.Ik);\n        return a\n    };\n    W.prototype.findVisibleNode = function () {\n        for (var a = this; null !== a && !a.isVisible();) a = a.containingGroup;\n        return a\n    };\n    W.prototype.isVisible = function () {\n        if (!U.prototype.isVisible.call(this)) return !1;\n        var a = !0,\n            b = pi,\n            c = this.diagram;\n        if (null !== c) {\n            if (c.animationManager.Dt(this)) return !0;\n            a = c.isTreePathToChildren;\n            b = c.treeCollapsePolicy\n        }\n        if (b === pi) {\n            if (a = this.Bg(), null !== a && !a.isTreeExpanded) return !1\n        } else if (b === Ek) {\n            if (a = a ? this.sv() : this.tv(), 0 < a.count && a.all(function (a) {\n                    return !a.isTreeExpanded\n                })) return !1\n        } else if (b === Fk && (a = a ? this.sv() : this.tv(), 0 < a.count && a.any(function (a) {\n                return !a.isTreeExpanded\n            }))) return !1;\n        a = this.labeledLink;\n        return null !== a ? a.isVisible() : !0\n    };\n    W.prototype.Ob = function (a) {\n        U.prototype.Ob.call(this, a);\n        for (var b = this.linksConnected; b.next();) b.value.Ob(a)\n    };\n    W.prototype.Jx = function () {\n        var a = new F,\n            b = new F;\n        Qo(this, this, a, b);\n        return b.iterator\n    };\n\n    function Qo(a, b, c, d) {\n        if (!c.has(b)) {\n            c.add(b);\n            var e = !0,\n                f = a.diagram;\n            null !== f && (e = f.isTreePathToChildren);\n            b.linksConnected.each(function (f) {\n                f.isTreeLink ? (e ? f.fromNode === b : f.toNode === b) && Qo(a, e ? f.toNode : f.fromNode, c, d) : d.add(f)\n            })\n        }\n    }\n    W.prototype.findLinksConnected = function (a) {\n        void 0 === a && (a = null);\n        if (null === a) return this.Wa.iterator;\n        var b = new jb(this.Wa),\n            c = this;\n        b.predicate = function (b) {\n            return b.fromNode === c && b.fromPortId === a || b.toNode === c && b.toPortId === a\n        };\n        return b\n    };\n    t = W.prototype;\n    t.lq = function (a) {\n        void 0 === a && (a = null);\n        var b = new jb(this.Wa),\n            c = this;\n        b.predicate = function (b) {\n            return b.fromNode !== c ? !1 : null === a ? !0 : b.fromPortId === a\n        };\n        return b\n    };\n    t.vd = function (a) {\n        void 0 === a && (a = null);\n        var b = new jb(this.Wa),\n            c = this;\n        b.predicate = function (b) {\n            return b.toNode !== c ? !1 : null === a ? !0 : b.toPortId === a\n        };\n        return b\n    };\n    t.rv = function (a) {\n        void 0 === a && (a = null);\n        for (var b = null, c = null, d = this.Wa.iterator; d.next();) {\n            var e = d.value;\n            if (e.fromNode === this) {\n                if (null === a || e.fromPortId === a) e = e.toNode, null !== b ? b.add(e) : null !== c && c !== e ? (b = new F, b.add(c), b.add(e)) : c = e\n            } else e.toNode !== this || null !== a && e.toPortId !== a || (e = e.fromNode, null !== b ? b.add(e) : null !== c && c !== e ? (b = new F, b.add(c), b.add(e)) : c = e)\n        }\n        return null !== b ? b.iterator : null !== c ? new gb(c) : fb\n    };\n    t.tv = function (a) {\n        void 0 === a && (a = null);\n        for (var b = null, c = null, d = this.Wa.iterator; d.next();) {\n            var e = d.value;\n            e.fromNode !== this || null !== a && e.fromPortId !== a || (e = e.toNode, null !== b ? b.add(e) : null !== c && c !== e ? (b = new F, b.add(c), b.add(e)) : c = e)\n        }\n        return null !== b ? b.iterator : null !== c ? new gb(c) : fb\n    };\n    t.sv = function (a) {\n        void 0 === a && (a = null);\n        for (var b = null, c = null, d = this.Wa.iterator; d.next();) {\n            var e = d.value;\n            e.toNode !== this || null !== a && e.toPortId !== a || (e = e.fromNode, null !== b ? b.add(e) : null !== c && c !== e ? (b = new F, b.add(c), b.add(e)) : c = e)\n        }\n        return null !== b ? b.iterator : null !== c ? new gb(c) : fb\n    };\n    t.lz = function (a, b, c) {\n        void 0 === b && (b = null);\n        void 0 === c && (c = null);\n        var d = new jb(this.Wa),\n            e = this;\n        d.predicate = function (d) {\n            return (d.fromNode !== e || d.toNode !== a || null !== b && d.fromPortId !== b || null !== c && d.toPortId !== c) && (d.fromNode !== a || d.toNode !== e || null !== c && d.fromPortId !== c || null !== b && d.toPortId !== b) ? !1 : !0\n        };\n        return d\n    };\n    t.mz = function (a, b, c) {\n        void 0 === b && (b = null);\n        void 0 === c && (c = null);\n        var d = new jb(this.Wa),\n            e = this;\n        d.predicate = function (d) {\n            return d.fromNode !== e || d.toNode !== a || null !== b && d.fromPortId !== b || null !== c && d.toPortId !== c ? !1 : !0\n        };\n        return d\n    };\n\n    function Ro(a, b, c) {\n        Po(a, c);\n        var d = a.Wa.contains(b);\n        d || a.Wa.add(b);\n        if (!d || b.fromNode === b.toNode) {\n            var e = a.linkConnected;\n            if (null !== e) {\n                var f = !0,\n                    g = a.diagram;\n                null !== g && (f = g.Z, g.Z = !0);\n                e(a, b, c);\n                null !== g && (g.Z = f)\n            }\n        }!d && b.isTreeLink && (c = b.fromNode, b = b.toNode, null !== c && null !== b && c !== b && (d = !0, a = a.diagram, null !== a && (d = a.isTreePathToChildren), e = d ? b : c, f = d ? c : b, e.Ah || (e.Ah = f), !f.isTreeLeaf || null !== a && a.undoManager.isUndoingRedoing || (d ? c === f && (f.isTreeLeaf = !1) : b === f && (f.isTreeLeaf = !1))))\n    }\n\n    function So(a, b, c) {\n        Po(a, c);\n        var d = a.Wa.remove(b),\n            e = null;\n        if (d || b.toNode === b.fromNode) {\n            var f = a.linkDisconnected;\n            e = a.diagram;\n            if (null !== f) {\n                var g = !0;\n                null !== e && (g = e.Z, e.Z = !0);\n                f(a, b, c);\n                null !== e && (e.Z = g)\n            }\n        }\n        d && b.isTreeLink && (c = !0, null !== e && (c = e.isTreePathToChildren), a = c ? b.toNode : b.fromNode, b = c ? b.fromNode : b.toNode, null !== a && (a.Ah = !1), null === b || b.isTreeLeaf || (0 === b.Wa.count ? (b.Ah = null, null !== e && e.undoManager.isUndoingRedoing || (b.isTreeLeaf = !0)) : Dk(b)))\n    }\n\n    function Dk(a) {\n        a.Ah = !1;\n        if (0 !== a.Wa.count) {\n            var b = !0,\n                c = a.diagram;\n            if (null === c || !c.undoManager.isUndoingRedoing) {\n                null !== c && (b = c.isTreePathToChildren);\n                for (c = a.Wa.iterator; c.next();) {\n                    var d = c.value;\n                    if (d.isTreeLink)\n                        if (b) {\n                            if (d.fromNode === a) {\n                                a.isTreeLeaf = !1;\n                                return\n                            }\n                        } else if (d.toNode === a) {\n                        a.isTreeLeaf = !1;\n                        return\n                    }\n                }\n                a.isTreeLeaf = !0\n            }\n        }\n    }\n    W.prototype.updateRelationshipsFromData = function () {\n        var a = this.diagram;\n        null !== a && a.partManager.updateRelationshipsFromData(this)\n    };\n    t = W.prototype;\n    t.qq = function (a) {\n        U.prototype.qq.call(this, a);\n        a || (Dk(this), a = this.rl, null !== a && To(a, this))\n    };\n    t.rq = function (a) {\n        U.prototype.rq.call(this, a);\n        a || (a = this.rl, null !== a && null !== a.ad && (a.ad.remove(this), a.o()))\n    };\n    t.dk = function () {\n        if (0 < this.Wa.count) {\n            var a = this.diagram;\n            if (null !== a)\n                for (var b = null !== a.commandHandler ? a.commandHandler.deletesConnectedLinks : !0, c = this.Wa.copy().iterator; c.next();) {\n                    var d = c.value;\n                    b ? a.remove(d) : (d.fromNode === this && (d.fromNode = null), d.toNode === this && (d.toNode = null))\n                }\n        }\n        this.labeledLink = null;\n        U.prototype.dk.call(this)\n    };\n    t.lt = function (a) {\n        if (null === this.rc) {\n            if (\"\" === a && !1 === this.Ih) return this;\n            Uo(this)\n        }\n        var b = this.rc.H(a);\n        return null !== b || \"\" !== a && (b = this.rc.H(\"\"), null !== b) ? b : this\n    };\n\n    function Uo(a) {\n        null === a.rc ? a.rc = new H : a.rc.clear();\n        a.Km(a, function (a, c) {\n            Tl(a, c)\n        });\n        0 === a.rc.count && a.rc.add(\"\", a)\n    }\n\n    function Tl(a, b) {\n        var c = b.portId;\n        null !== c && null !== a.rc && a.rc.add(c, b)\n    }\n\n    function Sl(a, b, c) {\n        var d = b.portId;\n        if (null !== d && (null !== a.rc && a.rc.remove(d), b = a.diagram, null !== b && c)) {\n            c = null;\n            for (a = a.findLinksConnected(d); a.next();) d = a.value, null === c && (c = Fa()), c.push(d);\n            if (null !== c) {\n                for (a = 0; a < c.length; a++) b.remove(c[a]);\n                Ha(c)\n            }\n        }\n    }\n    t.Vz = function (a) {\n        if (null === a || a === this) return !1;\n        var b = !0,\n            c = this.diagram;\n        null !== c && (b = c.isTreePathToChildren);\n        c = this;\n        if (b)\n            for (; c !== a;) {\n                b = null;\n                for (var d = c.Wa.iterator; d.next();) {\n                    var e = d.value;\n                    if (e.isTreeLink && (b = e.fromNode, b !== c && b !== this)) break\n                }\n                if (b === this || null === b || b === c) return !1;\n                c = b\n            } else\n                for (; c !== a;) {\n                    b = null;\n                    for (d = c.Wa.iterator; d.next() && (e = d.value, !e.isTreeLink || (b = e.toNode, b === c || b === this)););\n                    if (b === this || null === b || b === c) return !1;\n                    c = b\n                }\n        return !0\n    };\n    t.yz = function () {\n        var a = !0,\n            b = this.diagram;\n        null !== b && (a = b.isTreePathToChildren);\n        b = this;\n        if (a)\n            for (;;) {\n                a = null;\n                for (var c = b.Wa.iterator; c.next();) {\n                    var d = c.value;\n                    if (d.isTreeLink && (a = d.fromNode, a !== b && a !== this)) break\n                }\n                if (a === this) return this;\n                if (null === a || a === b) return b;\n                b = a\n            } else\n                for (;;) {\n                    a = null;\n                    for (c = b.Wa.iterator; c.next() && (d = c.value, !d.isTreeLink || (a = d.toNode, a === b || a === this)););\n                    if (a === this) return this;\n                    if (null === a || a === b) return b;\n                    b = a\n                }\n    };\n    t.iz = function (a) {\n        if (null === a) return null;\n        if (this === a) return this;\n        for (var b = this; null !== b;) Eo(b, !0), b = b.Bg();\n        var c = null;\n        for (b = a; null !== b;) {\n            if (0 !== (b.D & 1048576)) {\n                c = b;\n                break\n            }\n            b = b.Bg()\n        }\n        for (b = this; null !== b;) Eo(b, !1), b = b.Bg();\n        return c\n    };\n    t.Vi = function () {\n        var a = !0,\n            b = this.diagram;\n        null !== b && (a = b.isTreePathToChildren);\n        b = this.Wa.iterator;\n        if (a)\n            for (; b.next();) {\n                if (a = b.value, a.isTreeLink && a.fromNode !== this) return a\n            } else\n                for (; b.next();)\n                    if (a = b.value, a.isTreeLink && a.toNode !== this) return a;\n        return null\n    };\n    t.Bg = function () {\n        var a = this.Ah;\n        if (null === a) return null;\n        if (a instanceof W) return a;\n        var b = !0;\n        a = this.diagram;\n        null !== a && (b = a.isTreePathToChildren);\n        a = this.Wa.iterator;\n        if (b)\n            for (; a.next();) {\n                if (b = a.value, b.isTreeLink && (b = b.fromNode, b !== this)) return this.Ah = b\n            } else\n                for (; a.next();)\n                    if (b = a.value, b.isTreeLink && (b = b.toNode, b !== this)) return this.Ah = b;\n        return this.Ah = null\n    };\n    t.wz = function () {\n        function a(b, d) {\n            if (null !== b) {\n                d.add(b);\n                var c = b.Vi();\n                null !== c && (d.add(c), a(b.Bg(), d))\n            }\n        }\n        var b = new F;\n        a(this, b);\n        return b\n    };\n    t.vz = function () {\n        return Vo(this, this)\n    };\n\n    function Vo(a, b) {\n        b = b.Bg();\n        return null === b ? 0 : 1 + Vo(a, b)\n    }\n    t.nq = function () {\n        var a = !0,\n            b = this.diagram;\n        null !== b && (a = b.isTreePathToChildren);\n        b = new jb(this.Wa);\n        var c = this;\n        b.predicate = a ? function (a) {\n            return a.isTreeLink && a.fromNode === c ? !0 : !1\n        } : function (a) {\n            return a.isTreeLink && a.toNode === c ? !0 : !1\n        };\n        return b\n    };\n    t.vv = function () {\n        var a = !0,\n            b = this.diagram;\n        null !== b && (a = b.isTreePathToChildren);\n        var c = b = null,\n            d = this.Wa.iterator;\n        if (a)\n            for (; d.next();) a = d.value, a.isTreeLink && a.fromNode === this && (a = a.toNode, null !== b ? b.add(a) : null !== c && c !== a ? (b = new E, b.add(c), b.add(a)) : c = a);\n        else\n            for (; d.next();) a = d.value, a.isTreeLink && a.toNode === this && (a = a.fromNode, null !== b ? b.add(a) : null !== c && c !== a ? (b = new E, b.add(c), b.add(a)) : c = a);\n        return null !== b ? b.iterator : null !== c ? new gb(c) : fb\n    };\n    t.xz = function (a) {\n        void 0 === a && (a = Infinity);\n        var b = new F;\n        Sk(b, this, !1, a, !0);\n        return b\n    };\n    W.prototype.collapseTree = function (a) {\n        void 0 === a && (a = 1);\n        1 > a && (a = 1);\n        var b = this.diagram;\n        if (null !== b && !b.Ce) {\n            b.Ce = !0;\n            var c = new F;\n            c.add(this);\n            Wo(this, c, b.isTreePathToChildren, a, b, this, b.treeCollapsePolicy === pi);\n            b.Ce = !1\n        }\n    };\n\n    function Wo(a, b, c, d, e, f, g) {\n        if (1 < d)\n            for (var h = c ? a.lq() : a.vd(); h.next();) {\n                var k = h.value;\n                k.isTreeLink && (k = k.pt(a), null === k || k === a || b.contains(k) || (b.add(k), Wo(k, b, c, d - 1, e, f, g)))\n            } else Xo(a, b, c, e, f, g)\n    }\n\n    function Xo(a, b, c, d, e, f) {\n        for (var g = e === a ? !0 : a.isTreeExpanded, h = c ? a.lq() : a.vd(); h.next();) {\n            var k = h.value;\n            if (k.isTreeLink && (k = k.pt(a), null !== k && k !== a)) {\n                var l = b.contains(k);\n                l || b.add(k);\n                g && (f && d.Tj(k, e), k.Jh(), k.Ob(!1));\n                k.isTreeExpanded && (k.wasTreeExpanded = k.isTreeExpanded, l || Xo(k, b, c, d, e, f))\n            }\n        }\n        a.isTreeExpanded = !1\n    }\n    W.prototype.expandTree = function (a) {\n        void 0 === a && (a = 2);\n        2 > a && (a = 2);\n        var b = this.diagram;\n        if (null !== b && !b.Ce) {\n            b.Ce = !0;\n            var c = new F;\n            c.add(this);\n            Yo(this, c, b.isTreePathToChildren, a, b, this, b.treeCollapsePolicy === pi);\n            b.Ce = !1\n        }\n    };\n\n    function Yo(a, b, c, d, e, f, g) {\n        for (var h = f === a ? !1 : a.isTreeExpanded, k = c ? a.lq() : a.vd(); k.next();) {\n            var l = k.value;\n            l.isTreeLink && (h || l.kd || l.Oa(), l = l.pt(a), null !== l && l !== a && !b.contains(l) && (b.add(l), h || (l.Ob(!0), l.Jh(), g && e.Vj(l, f)), 2 < d || l.wasTreeExpanded)) && (l.wasTreeExpanded = !1, Yo(l, b, c, d - 1, e, f, g))\n        }\n        a.isTreeExpanded = !0\n    }\n    ma.Object.defineProperties(W.prototype, {\n        portSpreading: {\n            get: function () {\n                return this.fp\n            },\n            set: function (a) {\n                var b = this.fp;\n                b !== a && (this.fp = a, this.g(\"portSpreading\", b, a), a = this.diagram, null !== a && a.undoManager.isUndoingRedoing || this.fd())\n            }\n        },\n        avoidable: {\n            get: function () {\n                return 0 !== (this.P & 8)\n            },\n            set: function (a) {\n                var b = 0 !== (this.P & 8);\n                if (b !== a) {\n                    this.P ^= 8;\n                    var c = this.diagram;\n                    null !== c && xk(c, this);\n                    this.g(\"avoidable\", b, a)\n                }\n            }\n        },\n        avoidableMargin: {\n            get: function () {\n                return this.Ik\n            },\n            set: function (a) {\n                \"number\" === typeof a && (a = new oc(a));\n                var b = this.Ik;\n                if (!b.w(a)) {\n                    this.Ik = a = a.G();\n                    var c = this.diagram;\n                    null !== c && xk(c, this);\n                    this.g(\"avoidableMargin\", b, a)\n                }\n            }\n        },\n        linksConnected: {\n            get: function () {\n                return this.Wa.iterator\n            }\n        },\n        linkConnected: {\n            get: function () {\n                return this.oo\n            },\n            set: function (a) {\n                var b = this.oo;\n                b !== a && (this.oo = a, this.g(\"linkConnected\", b, a))\n            }\n        },\n        linkDisconnected: {\n            get: function () {\n                return this.po\n            },\n            set: function (a) {\n                var b = this.po;\n                b !== a && (this.po = a, this.g(\"linkDisconnected\", b, a))\n            }\n        },\n        linkValidation: {\n            get: function () {\n                return this.xi\n            },\n            set: function (a) {\n                var b = this.xi;\n                b !== a && (this.xi = a, this.g(\"linkValidation\", b, a))\n            }\n        },\n        isLinkLabel: {\n            get: function () {\n                return null !== this.rl\n            }\n        },\n        labeledLink: {\n            get: function () {\n                return this.rl\n            },\n            set: function (a) {\n                var b = this.rl;\n                if (b !== a) {\n                    var c = this.diagram,\n                        d = this.data;\n                    if (null !== b) {\n                        null !== b.ad && (b.ad.remove(this),\n                            b.o());\n                        if (null !== c && null !== d && !c.undoManager.isUndoingRedoing) {\n                            var e = b.data,\n                                f = c.model;\n                            if (null !== e && f.pm()) {\n                                var g = f.ja(d);\n                                void 0 !== g && f.ay(e, g)\n                            }\n                        }\n                        this.containingGroup = null\n                    }\n                    this.rl = a;\n                    null !== a && (To(a, this), null === c || null === d || c.undoManager.isUndoingRedoing || (e = a.data, c = c.model, null !== e && c.pm() && (d = c.ja(d), void 0 !== d && c.dv(e, d))), this.containingGroup = a.containingGroup);\n                    Cl(this);\n                    this.g(\"labeledLink\", b, a)\n                }\n            }\n        },\n        port: {\n            get: function () {\n                return this.lt(\"\")\n            }\n        },\n        ports: {\n            get: function () {\n                null === this.rc && Uo(this);\n                return this.rc.iteratorValues\n            }\n        },\n        isTreeExpanded: {\n            get: function () {\n                return 0 !== (this.P & 1)\n            },\n            set: function (a) {\n                var b = 0 !== (this.P & 1);\n                if (b !== a) {\n                    this.P ^= 1;\n                    var c = this.diagram;\n                    this.g(\"isTreeExpanded\", b, a);\n                    b = this.treeExpandedChanged;\n                    if (null !== b) {\n                        var d = !0;\n                        null !== c && (d = c.Z, c.Z = !0);\n                        b(this);\n                        null !== c && (c.Z = d)\n                    }\n                    null !== c && c.undoManager.isUndoingRedoing ? this.Ob(a) : a ? this.expandTree() : this.collapseTree()\n                }\n            }\n        },\n        wasTreeExpanded: {\n            get: function () {\n                return 0 !== (this.P & 2)\n            },\n            set: function (a) {\n                var b = 0 !== (this.P & 2);\n                b !== a && (this.P ^= 2, this.g(\"wasTreeExpanded\", b, a))\n            }\n        },\n        treeExpandedChanged: {\n            get: function () {\n                return this.Wp\n            },\n            set: function (a) {\n                var b = this.Wp;\n                b !== a && (this.Wp = a, this.g(\"treeExpandedChanged\", b, a))\n            }\n        },\n        isTreeLeaf: {\n            get: function () {\n                return 0 !== (this.P & 4)\n            },\n            set: function (a) {\n                var b = 0 !== (this.P & 4);\n                b !== a && (this.P ^= 4, this.g(\"isTreeLeaf\", b, a))\n            }\n        }\n    });\n    W.prototype.expandTree = W.prototype.expandTree;\n    W.prototype.collapseTree = W.prototype.collapseTree;\n    W.prototype.findTreeParts = W.prototype.xz;\n    W.prototype.findTreeChildrenNodes = W.prototype.vv;\n    W.prototype.findTreeChildrenLinks = W.prototype.nq;\n    W.prototype.findTreeLevel = W.prototype.vz;\n    W.prototype.findTreeParentChain = W.prototype.wz;\n    W.prototype.findTreeParentNode = W.prototype.Bg;\n    W.prototype.findTreeParentLink = W.prototype.Vi;\n    W.prototype.findCommonTreeParent = W.prototype.iz;\n    W.prototype.findTreeRoot = W.prototype.yz;\n    W.prototype.isInTreeOf = W.prototype.Vz;\n    W.prototype.findPort = W.prototype.lt;\n    W.prototype.findLinksTo = W.prototype.mz;\n    W.prototype.findLinksBetween = W.prototype.lz;\n    W.prototype.findNodesInto = W.prototype.sv;\n    W.prototype.findNodesOutOf = W.prototype.tv;\n    W.prototype.findNodesConnected = W.prototype.rv;\n    W.prototype.findLinksInto = W.prototype.vd;\n    W.prototype.findLinksOutOf = W.prototype.lq;\n    W.prototype.findExternalTreeLinksConnected = W.prototype.Jx;\n    W.prototype.invalidateConnectedLinks = W.prototype.fd;\n    W.prototype.invalidateLinkBundle = W.prototype.Tz;\n    var Zo = new D(W, \"SpreadingNone\", 10),\n        Mo = new D(W, \"SpreadingEvenly\", 11),\n        $o = new D(W, \"SpreadingPacked\", 12);\n    W.className = \"Node\";\n    W.SpreadingNone = Zo;\n    W.SpreadingEvenly = Mo;\n    W.SpreadingPacked = $o;\n\n    function T(a) {\n        W.call(this, a);\n        this.P |= 4608;\n        this.zo = new F;\n        this.zl = new F;\n        this.Sa = this.Np = this.yi = this.Ao = this.yo = null;\n        this.ic = new Ci;\n        this.ic.group = this\n    }\n    la(T, W);\n    T.prototype.cloneProtected = function (a) {\n        W.prototype.cloneProtected.call(this, a);\n        this.P = this.P & -32769;\n        a.yo = this.yo;\n        a.Ao = this.Ao;\n        a.yi = this.yi;\n        a.Np = this.Np;\n        var b = a.hm(function (a) {\n            return a instanceof xg\n        });\n        b instanceof xg ? a.Sa = b : a.Sa = null;\n        null !== this.ic ? (a.ic = this.ic.copy(), a.ic.group = a) : (null !== a.ic && (a.ic.group = null), a.ic = null)\n    };\n    t = T.prototype;\n    t.sf = function (a) {\n        W.prototype.sf.call(this, a);\n        var b = a.gk();\n        for (a = a.memberParts; a.next();) {\n            var c = a.value;\n            c.o();\n            c.C(8);\n            c.Yj();\n            if (c instanceof W) c.fd(b);\n            else if (c instanceof S)\n                for (c = c.labelNodes; c.next();) c.value.fd(b)\n        }\n    };\n    t.vk = function (a, b, c, d, e, f, g) {\n        if (a === te && \"elements\" === b)\n            if (e instanceof xg) null === this.Sa ? this.Sa = e : this.Sa !== e && B(\"Cannot insert a second Placeholder into the visual tree of a Group.\");\n            else {\n                if (e instanceof X) {\n                    var h = e.hm(function (a) {\n                        return a instanceof xg\n                    });\n                    h instanceof xg && (null === this.Sa ? this.Sa = h : this.Sa !== h && B(\"Cannot insert a second Placeholder into the visual tree of a Group.\"))\n                }\n            }\n        else a === ue && \"elements\" === b && null !== this.Sa && (d === this.Sa ? this.Sa = null : d instanceof X && this.Sa.Dg(d) && (this.Sa = null));\n        W.prototype.vk.call(this, a, b, c, d, e, f, g)\n    };\n    t.Fh = function (a, b, c, d) {\n        this.Xe = this.Sa;\n        W.prototype.Fh.call(this, a, b, c, d)\n    };\n    t.yb = function () {\n        this.memberParts.each(function (a) {\n            a.yb()\n        });\n        W.prototype.yb.call(this)\n    };\n    t.bj = function () {\n        if (!W.prototype.bj.call(this)) return !1;\n        for (var a = this.memberParts; a.next();) {\n            var b = a.value;\n            if (b instanceof W) {\n                if (b.isVisible() && rj(b)) return !1\n            } else if (b instanceof S && b.isVisible() && rj(b) && b.fromNode !== this && b.toNode !== this) return !1\n        }\n        return !0\n    };\n\n    function Fo(a, b) {\n        if (a.zo.add(b)) {\n            b instanceof T && a.zl.add(b);\n            var c = a.memberAdded;\n            if (null !== c) {\n                var d = !0,\n                    e = a.diagram;\n                null !== e && (d = e.Z, e.Z = !0);\n                c(a, b);\n                null !== e && (e.Z = d)\n            }\n            a.isVisible() && a.isSubGraphExpanded || b.Ob(!1)\n        }\n        b instanceof S && !a.computesBoundsIncludingLinks || (b = a.Sa, null === b && (b = a), b.o())\n    }\n\n    function Go(a, b) {\n        if (a.zo.remove(b)) {\n            b instanceof T && a.zl.remove(b);\n            var c = a.memberRemoved;\n            if (null !== c) {\n                var d = !0,\n                    e = a.diagram;\n                null !== e && (d = e.Z, e.Z = !0);\n                c(a, b);\n                null !== e && (e.Z = d)\n            }\n            a.isVisible() && a.isSubGraphExpanded || b.Ob(!0)\n        }\n        b instanceof S && !a.computesBoundsIncludingLinks || (b = a.Sa, null === b && (b = a), b.o())\n    }\n    t.dk = function () {\n        if (0 < this.zo.count) {\n            var a = this.diagram;\n            if (null !== a)\n                for (var b = this.zo.copy().iterator; b.next();) a.remove(b.value)\n        }\n        W.prototype.dk.call(this)\n    };\n    T.prototype.canAddMembers = function (a) {\n        var b = this.diagram;\n        if (null === b) return !1;\n        b = b.commandHandler;\n        for (a = Uk(a).iterator; a.next();)\n            if (!b.isValidMember(this, a.value)) return !1;\n        return !0\n    };\n    T.prototype.addMembers = function (a, b) {\n        var c = this.diagram;\n        if (null === c) return !1;\n        c = c.commandHandler;\n        var d = !0;\n        for (a = Uk(a).iterator; a.next();) {\n            var e = a.value;\n            !b || c.isValidMember(this, e) ? e.containingGroup = this : d = !1\n        }\n        return d\n    };\n    T.prototype.canUngroup = function () {\n        if (!this.ungroupable) return !1;\n        var a = this.layer;\n        if (null !== a && !a.allowUngroup) return !1;\n        a = a.diagram;\n        return null === a || a.allowUngroup ? !0 : !1\n    };\n    t = T.prototype;\n    t.fd = function (a) {\n        void 0 === a && (a = null);\n        var b = 0 !== (this.P & 65536);\n        W.prototype.fd.call(this, a);\n        if (!b)\n            for (0 !== (this.P & 65536) !== !0 && (this.P = this.P ^ 65536), b = this.qv(); b.next();) {\n                var c = b.value;\n                if (null === a || !a.contains(c)) {\n                    var d = c.fromNode;\n                    null !== d && d !== this && d.Wd(this) && !d.isVisible() ? (Po(d, c.fromPort), Po(d, c.toPort), c.Oa()) : (d = c.toNode, null !== d && d !== this && d.Wd(this) && !d.isVisible() && (Po(d, c.fromPort), Po(d, c.toPort), c.Oa()))\n                }\n            }\n    };\n    t.qv = function () {\n        var a = this.gk();\n        a.add(this);\n        for (var b = new F, c = a.iterator; c.next();) {\n            var d = c.value;\n            if (d instanceof W)\n                for (d = d.linksConnected; d.next();) {\n                    var e = d.value;\n                    a.contains(e) || b.add(e)\n                }\n        }\n        return b.iterator\n    };\n    t.kz = function () {\n        var a = this.gk();\n        a.add(this);\n        for (var b = new F, c = a.iterator; c.next();) {\n            var d = c.value;\n            if (d instanceof W)\n                for (d = d.linksConnected; d.next();) {\n                    var e = d.value,\n                        f = e.fromNode;\n                    a.contains(f) && f !== this || b.add(f);\n                    e = e.toNode;\n                    a.contains(e) && e !== this || b.add(e)\n                }\n        }\n        return b.iterator\n    };\n    t.jz = function () {\n        function a(b, d) {\n            null !== b && (d.add(b), a(b.containingGroup, d))\n        }\n        var b = new F;\n        a(this, b);\n        return b\n    };\n    t.gk = function () {\n        var a = new F;\n        Sk(a, this, !0, 0, !0);\n        a.remove(this);\n        return a\n    };\n    t.Ob = function (a) {\n        W.prototype.Ob.call(this, a);\n        for (var b = this.memberParts; b.next();) b.value.Ob(a)\n    };\n    T.prototype.collapseSubGraph = function () {\n        var a = this.diagram;\n        if (null !== a && !a.Ce) {\n            a.Ce = !0;\n            var b = this.gk();\n            ap(this, b, a, this);\n            a.Ce = !1\n        }\n    };\n\n    function ap(a, b, c, d) {\n        for (var e = a.memberParts; e.next();) {\n            var f = e.value;\n            f.Ob(!1);\n            f instanceof T && f.isSubGraphExpanded && (f.wasSubGraphExpanded = f.isSubGraphExpanded, ap(f, b, c, d));\n            if (f instanceof W) f.fd(b), c.Tj(f, d);\n            else if (f instanceof S)\n                for (f = f.labelNodes; f.next();) f.value.fd(b)\n        }\n        a.isSubGraphExpanded = !1\n    }\n    T.prototype.expandSubGraph = function () {\n        var a = this.diagram;\n        if (null !== a && !a.Ce) {\n            a.Ce = !0;\n            var b = this.gk();\n            bp(this, b, a, this);\n            a.Ce = !1\n        }\n    };\n\n    function bp(a, b, c, d) {\n        for (var e = a.memberParts; e.next();) {\n            var f = e.value;\n            f.Ob(!0);\n            f instanceof T && f.wasSubGraphExpanded && (f.wasSubGraphExpanded = !1, bp(f, b, c, d));\n            if (f instanceof W) f.fd(b), c.Vj(f, d);\n            else if (f instanceof S)\n                for (f = f.labelNodes; f.next();) f.value.fd(b)\n        }\n        a.isSubGraphExpanded = !0\n    }\n    T.prototype.move = function (a, b) {\n        void 0 === b && (b = !1);\n        var c = b ? this.location : this.position,\n            d = c.x;\n        c = c.y;\n        var e = a.x,\n            f = a.y;\n        if (!(d === e || isNaN(d) && isNaN(e)) || !(c === f || isNaN(c) && isNaN(f))) {\n            d = e - (isNaN(d) ? 0 : d);\n            c = f - (isNaN(c) ? 0 : c);\n            f = I.alloc();\n            W.prototype.move.call(this, a, b);\n            a = new F;\n            for (b = this.gk().iterator; b.next();)\n                if (e = b.value, e instanceof S && (e.suspendsRouting && a.add(e), e.kd || e.fromNode !== this && e.toNode !== this)) e.suspendsRouting = !0;\n            for (b.reset(); b.next();)\n                if (e = b.value, !(e.Kh() || e instanceof W && e.isLinkLabel)) {\n                    var g =\n                        e.position,\n                        h = e.location;\n                    g.v() ? (f.x = g.x + d, f.y = g.y + c, e.position = f) : h.v() && (f.x = h.x + d, f.y = h.y + c, e.location = f)\n                } for (b.reset(); b.next();)\n                if (e = b.value, e instanceof S && (e.suspendsRouting = a.contains(e), e.kd || e.fromNode !== this && e.toNode !== this)) g = e.position, f.x = g.x + d, f.y = g.y + c, f.v() ? e.move(f) : e.Oa(), Oj(e) && e.Oa();\n            I.free(f)\n        }\n    };\n    ma.Object.defineProperties(T.prototype, {\n        placeholder: {\n            get: function () {\n                return this.Sa\n            }\n        },\n        computesBoundsAfterDrag: {\n            get: function () {\n                return 0 !== (this.P & 2048)\n            },\n            set: function (a) {\n                var b = 0 !== (this.P & 2048);\n                b !== a && (this.P ^= 2048, this.g(\"computesBoundsAfterDrag\", b, a))\n            }\n        },\n        computesBoundsIncludingLinks: {\n            get: function () {\n                return 0 !== (this.P & 4096)\n            },\n            set: function (a) {\n                var b = 0 !== (this.P & 4096);\n                b !== a && (this.P ^= 4096, this.g(\"computesBoundsIncludingLinks\",\n                    b, a))\n            }\n        },\n        computesBoundsIncludingLocation: {\n            get: function () {\n                return 0 !== (this.P & 8192)\n            },\n            set: function (a) {\n                var b = 0 !== (this.P & 8192);\n                b !== a && (this.P ^= 8192, this.g(\"computesBoundsIncludingLocation\", b, a))\n            }\n        },\n        handlesDragDropForMembers: {\n            get: function () {\n                return 0 !== (this.P & 16384)\n            },\n            set: function (a) {\n                var b = 0 !== (this.P & 16384);\n                b !== a && (this.P ^= 16384, this.g(\"handlesDragDropForMembers\", b, a))\n            }\n        },\n        memberParts: {\n            get: function () {\n                return this.zo.iterator\n            }\n        },\n        layout: {\n            get: function () {\n                return this.ic\n            },\n            set: function (a) {\n                var b = this.ic;\n                if (b !== a) {\n                    null !== b && (b.diagram = null, b.group = null);\n                    this.ic = a;\n                    var c = this.diagram;\n                    null !== a && (a.diagram = c, a.group = this);\n                    null !== c && (c.If = !0);\n                    this.g(\"layout\", b, a);\n                    null !== c && c.Pb()\n                }\n            }\n        },\n        memberAdded: {\n            get: function () {\n                return this.yo\n            },\n            set: function (a) {\n                var b = this.yo;\n                b !== a && (this.yo = a, this.g(\"memberAdded\", b, a))\n            }\n        },\n        memberRemoved: {\n            get: function () {\n                return this.Ao\n            },\n            set: function (a) {\n                var b = this.Ao;\n                b !== a && (this.Ao = a, this.g(\"memberRemoved\", b, a))\n            }\n        },\n        memberValidation: {\n            get: function () {\n                return this.yi\n            },\n            set: function (a) {\n                var b = this.yi;\n                b !== a && (this.yi = a, this.g(\"memberValidation\", b, a))\n            }\n        },\n        ungroupable: {\n            get: function () {\n                return 0 !== (this.P & 256)\n            },\n            set: function (a) {\n                var b = 0 !== (this.P & 256);\n                b !== a && (this.P ^= 256, this.g(\"ungroupable\", b, a))\n            }\n        },\n        isSubGraphExpanded: {\n            get: function () {\n                return 0 !== (this.P & 512)\n            },\n            set: function (a) {\n                var b = 0 !== (this.P & 512);\n                if (b !== a) {\n                    this.P ^= 512;\n                    var c = this.diagram;\n                    this.g(\"isSubGraphExpanded\", b, a);\n                    b = this.subGraphExpandedChanged;\n                    if (null !== b) {\n                        var d = !0;\n                        null !== c && (d = c.Z, c.Z = !0);\n                        b(this);\n                        null !== c && (c.Z = d)\n                    }\n                    null !== c && c.undoManager.isUndoingRedoing ? (null !== this.Sa && this.Sa.o(), this.memberParts.each(function (a) {\n                        a.updateAdornments()\n                    })) : a ? this.expandSubGraph() : this.collapseSubGraph()\n                }\n            }\n        },\n        wasSubGraphExpanded: {\n            get: function () {\n                return 0 !== (this.P & 1024)\n            },\n            set: function (a) {\n                var b =\n                    0 !== (this.P & 1024);\n                b !== a && (this.P ^= 1024, this.g(\"wasSubGraphExpanded\", b, a))\n            }\n        },\n        subGraphExpandedChanged: {\n            get: function () {\n                return this.Np\n            },\n            set: function (a) {\n                var b = this.Np;\n                b !== a && (this.Np = a, this.g(\"subGraphExpandedChanged\", b, a))\n            }\n        },\n        uk: {\n            get: function () {\n                return 0 !== (this.P & 32768)\n            },\n            set: function (a) {\n                0 !== (this.P & 32768) !== a && (this.P ^= 32768)\n            }\n        }\n    });\n    T.prototype.expandSubGraph = T.prototype.expandSubGraph;\n    T.prototype.collapseSubGraph = T.prototype.collapseSubGraph;\n    T.prototype.findSubGraphParts = T.prototype.gk;\n    T.prototype.findContainingGroupChain = T.prototype.jz;\n    T.prototype.findExternalNodesConnected = T.prototype.kz;\n    T.prototype.findExternalLinksConnected = T.prototype.qv;\n    T.prototype.ensureBounds = T.prototype.yb;\n    T.className = \"Group\";\n\n    function xg() {\n        Y.call(this);\n        this.bb = sc;\n        this.tp = new N(NaN, NaN, NaN, NaN)\n    }\n    la(xg, Y);\n    xg.prototype.cloneProtected = function (a) {\n        Y.prototype.cloneProtected.call(this, a);\n        a.bb = this.bb.G();\n        a.tp = this.tp.copy()\n    };\n    xg.prototype.Hh = function (a) {\n        if (null === this.background && null === this.areaBackground) return !1;\n        var b = this.naturalBounds;\n        return fc(0, 0, b.width, b.height, a.x, a.y)\n    };\n    xg.prototype.sm = function () {\n        var a = this.part;\n        null !== a && (a instanceof T || a instanceof Je) || B(\"Placeholder is not inside a Group or Adornment.\");\n        if (a instanceof T) {\n            var b = this.computeBorder(this.tp),\n                c = this.minSize,\n                d = this.oc;\n            Vb(d, (isFinite(c.width) ? Math.max(c.width, b.width) : b.width) || 0, (isFinite(c.height) ? Math.max(c.height, b.height) : b.height) || 0);\n            hl(this, 0, 0, d.width, d.height);\n            d = a.memberParts;\n            for (c = !1; d.next();)\n                if (d.value.isVisible()) {\n                    c = !0;\n                    break\n                } d = a.diagram;\n            !c || null === d || d.animationManager.Gv(a) || isNaN(b.x) ||\n                isNaN(b.y) || (c = I.alloc(), c.dj(b, a.locationSpot), c.w(a.location) || (a.location = new I(c.x, c.y)), I.free(c))\n        } else {\n            b = this.oc;\n            c = this.bb;\n            d = c.left + c.right;\n            var e = c.top + c.bottom,\n                f = a.adornedObject;\n            a.angle = f.Xi();\n            var g = 0;\n            f instanceof Lf && (g = f.strokeWidth);\n            var h = f.uf(),\n                k = f.naturalBounds,\n                l = (k.width + g) * h;\n            g = (k.height + g) * h;\n            a.type !== X.Link && (f = f.ga(\"Selection\" === a.category ? vc : a.locationSpot, I.alloc()), a.location = f, I.free(f));\n            isNaN(l) || isNaN(g) ? (a = a.adornedObject, l = a.ga(vc, I.alloc()), f = N.allocAt(l.x, l.y, 0, 0), f.He(a.ga(Gc,\n                l)), f.He(a.ga(yc, l)), f.He(a.ga(Cc, l)), Vb(b, f.width + d || 0, f.height + e || 0), hl(this, -c.left, -c.top, b.width, b.height), I.free(l), N.free(f)) : (Vb(b, l + d || 0, g + e || 0), hl(this, -c.left, -c.top, b.width, b.height))\n        }\n    };\n    xg.prototype.Fh = function (a, b, c, d) {\n        this.actualBounds.h(a, b, c, d)\n    };\n    xg.prototype.computeBorder = function (a) {\n        var b = this.part,\n            c = b.diagram;\n        if (null !== c && b instanceof T && !b.layer.isTemporary && b.computesBoundsAfterDrag && this.tp.v()) {\n            var d = c.toolManager.findTool(\"Dragging\");\n            if (d === c.currentTool && (c = d.computeBorder(b, this.tp, a), null !== c)) return c\n        }\n        c = N.alloc();\n        d = this.computeMemberBounds(c);\n        var e = this.bb;\n        b instanceof T && !b.isSubGraphExpanded ? a.h(d.x - e.left, d.y - e.top, 0, 0) : a.h(d.x - e.left, d.y - e.top, Math.max(d.width + e.left + e.right, 0), Math.max(d.height + e.top + e.bottom, 0));\n        N.free(c);\n        b instanceof T && b.computesBoundsIncludingLocation && b.location.v() && a.He(b.location);\n        return a\n    };\n    xg.prototype.computeMemberBounds = function (a) {\n        if (!(this.part instanceof T)) return a.h(0, 0, 0, 0), a;\n        for (var b = this.part, c = Infinity, d = Infinity, e = -Infinity, f = -Infinity, g = b.memberParts; g.next();) {\n            var h = g.value;\n            if (h.isVisible()) {\n                if (h instanceof S) {\n                    if (!b.computesBoundsIncludingLinks) continue;\n                    if (qj(h)) continue;\n                    if (h.fromNode === b || h.toNode === b) continue\n                }\n                h = h.actualBounds;\n                h.left < c && (c = h.left);\n                h.top < d && (d = h.top);\n                h.right > e && (e = h.right);\n                h.bottom > f && (f = h.bottom)\n            }\n        }\n        isFinite(c) && isFinite(d) ? a.h(c, d, e - c, f - d) : (b = b.location,\n            a.h(b.x, b.y, 0, 0));\n        return a\n    };\n    ma.Object.defineProperties(xg.prototype, {\n        padding: {\n            get: function () {\n                return this.bb\n            },\n            set: function (a) {\n                \"number\" === typeof a && (a = new oc(a));\n                var b = this.bb;\n                b.w(a) || (this.bb = a = a.G(), this.g(\"padding\", b, a))\n            }\n        }\n    });\n    xg.className = \"Placeholder\";\n\n    function S() {\n        U.call(this, X.Link);\n        this.Qa = 8;\n        this.Qe = null;\n        this.Re = \"\";\n        this.lf = this.Mn = null;\n        this.mf = \"\";\n        this.Vp = null;\n        this.Dk = bg;\n        this.pn = 0;\n        this.rn = bg;\n        this.sn = NaN;\n        this.Lj = cp;\n        this.Ip = .5;\n        this.ad = null;\n        this.wb = (new E).freeze();\n        this.oh = this.jh = null;\n        this.El = new N;\n        this.ka = new td;\n        this.Yn = !0;\n        this.I = this.u = this.Kf = this.Tf = null;\n        this.l = [];\n        this.Vu = new I;\n        this.Gr = this.mx = this.lx = null;\n        this.qu = NaN;\n        this.O = null\n    }\n    la(S, U);\n    S.prototype.cloneProtected = function (a) {\n        U.prototype.cloneProtected.call(this, a);\n        a.Qa = this.Qa & -113;\n        a.Re = this.Re;\n        a.Mn = this.Mn;\n        a.mf = this.mf;\n        a.Vp = this.Vp;\n        a.Dk = this.Dk;\n        a.pn = this.pn;\n        a.rn = this.rn;\n        a.sn = this.sn;\n        a.Lj = this.Lj;\n        a.Ip = this.Ip;\n        null !== this.O && (a.O = this.O.copy())\n    };\n    t = S.prototype;\n    t.sf = function (a) {\n        U.prototype.sf.call(this, a);\n        this.Re = a.Re;\n        this.mf = a.mf;\n        a.jh = null;\n        a.Oa();\n        a.Kf = this.Kf;\n        var b = a.fromPort;\n        null !== b && Po(a.fromNode, b);\n        b = a.toPort;\n        null !== b && Po(a.toNode, b)\n    };\n    t.cb = function (a) {\n        a.classType === S ? 2 === (a.value & 2) ? this.routing = a : a === qg || a === ag || a === $f ? this.curve = a : a === dp || a === ep || a === fp ? this.adjusting = a : a !== cp && a !== bg && B(\"Unknown Link enum value for a Link property: \" + a) : U.prototype.cb.call(this, a)\n    };\n    t.Ec = function () {\n        null === this.O && (this.O = new dl)\n    };\n    t.bj = function () {\n        var a = this.fromNode;\n        if (null !== a) {\n            var b = a.findVisibleNode();\n            null !== b && (a = b);\n            if (rj(a) || sj(a)) return !1\n        }\n        a = this.toNode;\n        return null !== a && (b = a.findVisibleNode(), null !== b && (a = b), rj(a) || sj(a)) ? !1 : !0\n    };\n    t.gw = function () {\n        return !1\n    };\n    t.hw = function () {};\n    t.Wb = function () {\n        return !1\n    };\n    S.prototype.computeAngle = function (a, b, c) {\n        return S.computeAngle(b, c)\n    };\n    S.computeAngle = function (a, b) {\n        switch (a) {\n            default:\n            case bg:\n                a = 0;\n                break;\n            case In:\n                a = b;\n                break;\n            case Nm:\n                a = b + 90;\n                break;\n            case Pm:\n                a = b - 90;\n                break;\n            case gp:\n                a = b + 180;\n                break;\n            case hp:\n                a = J.zq(b);\n                90 < a && 270 > a && (a -= 180);\n                break;\n            case Om:\n                a = J.zq(b + 90);\n                90 < a && 270 > a && (a -= 180);\n                break;\n            case Qm:\n                a = J.zq(b - 90);\n                90 < a && 270 > a && (a -= 180);\n                break;\n            case Rm:\n                a = J.zq(b);\n                if (45 < a && 135 > a || 225 < a && 315 > a) return 0;\n                90 < a && 270 > a && (a -= 180)\n        }\n        return J.zq(a)\n    };\n\n    function Lo(a) {\n        var b = a.fromNode,\n            c = a.toNode,\n            d = null;\n        null !== b ? d = null !== c ? b.Ix(c) : b.containingGroup : null !== c ? d = c.containingGroup : d = null;\n        b = d;\n        c = a.di;\n        if (c !== b) {\n            null !== c && Go(c, a);\n            a.di = b;\n            null !== b && Fo(b, a);\n            var e = a.containingGroupChanged;\n            if (null !== e) {\n                var f = !0,\n                    g = a.diagram;\n                null !== g && (f = g.Z, g.Z = !0);\n                e(a, c, b);\n                null !== g && (g.Z = f)\n            }!a.kd || a.lx !== c && a.mx !== c || a.Oa()\n        }\n        if (a.isLabeledLink)\n            for (a = a.labelNodes; a.next();) a.value.containingGroup = d\n    }\n    t = S.prototype;\n    t.Jh = function () {\n        var a = this.containingGroup;\n        null !== a && this.fromNode !== a && this.toNode !== a && a.computesBoundsIncludingLinks && U.prototype.Jh.call(this)\n    };\n    t.pt = function (a) {\n        var b = this.fromNode;\n        return a === b ? this.toNode : b\n    };\n    t.Fz = function (a) {\n        var b = this.fromPort;\n        return a === b ? this.toPort : b\n    };\n\n    function To(a, b) {\n        null === a.ad && (a.ad = new F);\n        a.ad.add(b);\n        a.o()\n    }\n    t.qq = function (a) {\n        U.prototype.qq.call(this, a);\n        ip(this) && this.tq(this.actualBounds);\n        if (!a) {\n            a = this.Qe;\n            var b = null;\n            null !== a && (b = this.fromPort, Ro(a, this, b));\n            var c = this.lf;\n            if (null !== c) {\n                var d = this.toPort;\n                c === a && d === b || Ro(c, this, d)\n            }\n            jp(this)\n        }\n    };\n    t.rq = function (a) {\n        U.prototype.rq.call(this, a);\n        ip(this) && this.tq(this.actualBounds);\n        if (!a) {\n            a = this.Qe;\n            var b = null;\n            null !== a && (b = this.fromPort, So(a, this, b));\n            var c = this.lf;\n            if (null !== c) {\n                var d = this.toPort;\n                c === a && d === b || So(c, this, d)\n            }\n            kp(this)\n        }\n    };\n    t.dk = function () {\n        this.kd = !0;\n        if (null !== this.ad) {\n            var a = this.diagram;\n            if (null !== a)\n                for (var b = this.ad.copy().iterator; b.next();) a.remove(b.value)\n        }\n        null !== this.data && (a = this.diagram, null !== a && a.partManager.removeDataForLink(this))\n    };\n    S.prototype.updateRelationshipsFromData = function () {\n        if (null !== this.data) {\n            var a = this.diagram;\n            null !== a && a.partManager.updateRelationshipsFromData(this)\n        }\n    };\n    S.prototype.move = function (a, b) {\n        var c = b ? this.location : this.position,\n            d = c.x;\n        isNaN(d) && (d = 0);\n        var e = c.y;\n        isNaN(e) && (e = 0);\n        d = a.x - d;\n        e = a.y - e;\n        !0 === b ? U.prototype.move.call(this, a, !1) : (a = I.allocAt(c.x + d, c.y + e), U.prototype.move.call(this, a, !1), I.free(a));\n        qf(this, d, e);\n        for (a = this.labelNodes; a.next();) b = a.value, c = b.position, b.moveTo(c.x + d, c.y + e)\n    };\n    S.prototype.canRelinkFrom = function () {\n        if (!this.relinkableFrom) return !1;\n        var a = this.layer;\n        if (null === a) return !0;\n        if (!a.allowRelink) return !1;\n        a = a.diagram;\n        return null === a || a.allowRelink ? !0 : !1\n    };\n    S.prototype.canRelinkTo = function () {\n        if (!this.relinkableTo) return !1;\n        var a = this.layer;\n        if (null === a) return !0;\n        if (!a.allowRelink) return !1;\n        a = a.diagram;\n        return null === a || a.allowRelink ? !0 : !1\n    };\n    S.prototype.computeMidPoint = function (a) {\n        var b = this.pointsCount;\n        if (0 === b) return a.assign(Jb), a;\n        if (1 === b) return a.assign(this.i(0)), a;\n        if (2 === b) {\n            var c = this.i(0),\n                d = this.i(1);\n            a.h((c.x + d.x) / 2, (c.y + d.y) / 2);\n            return a\n        }\n        if (this.isOrthogonal && (15 <= this.computeCorner() || this.computeCurve() === qg)) return this.ka.yv(.5, a), a.add(this.i(0)), c = this.ka.figures.first(), a.offset(-c.startX, -c.startY), a;\n        if (this.computeCurve() === qg) {\n            if (3 === b) return this.i(1);\n            d = (b - 1) / 3 | 0;\n            c = 3 * (d / 2 | 0);\n            if (1 === d % 2) {\n                d = this.i(c);\n                var e = this.i(c + 1),\n                    f = this.i(c + 2);\n                c = this.i(c + 3);\n                J.Qy(d.x, d.y, e.x, e.y, f.x, f.y, c.x, c.y, a)\n            } else a.assign(this.i(c));\n            return a\n        }\n        var g = this.flattenedLengths;\n        c = this.flattenedTotalLength;\n        for (e = f = d = 0; d < c / 2 && f < b;) {\n            e = g[f];\n            if (d + e > c / 2) break;\n            d += e;\n            f++\n        }\n        b = this.i(f);\n        f = this.i(f + 1);\n        1 > Math.abs(b.x - f.x) ? b.y > f.y ? a.h(b.x, b.y - (c / 2 - d)) : a.h(b.x, b.y + (c / 2 - d)) : 1 > Math.abs(b.y - f.y) ? b.x > f.x ? a.h(b.x - (c / 2 - d), b.y) : a.h(b.x + (c / 2 - d), b.y) : (c = (c / 2 - d) / e, a.h(b.x + c * (f.x - b.x), b.y + c * (f.y - b.y)));\n        return a\n    };\n    S.prototype.computeMidAngle = function () {\n        var a = this.pointsCount;\n        if (2 > a) return NaN;\n        if (2 === a) return this.i(0).Ta(this.i(1));\n        if (this.isOrthogonal && (15 <= this.computeCorner() || this.computeCurve() === qg)) return this.ka.Ox(.5);\n        if (this.computeCurve() === qg && 4 <= a) {\n            var b = (a - 1) / 3 | 0,\n                c = 3 * (b / 2 | 0);\n            if (1 === b % 2) {\n                c = Math.floor(c);\n                a = this.i(c);\n                b = this.i(c + 1);\n                var d = this.i(c + 2);\n                c = this.i(c + 3);\n                return J.Py(a.x, a.y, b.x, b.y, d.x, d.y, c.x, c.y)\n            }\n            if (0 < c && c + 1 < a) return this.i(c - 1).Ta(this.i(c + 1))\n        }\n        b = this.flattenedLengths;\n        d = this.flattenedTotalLength;\n        var e = 0;\n        c = 0;\n        for (var f; e < d / 2 && c < a;) {\n            f = b[c];\n            if (e + f > d / 2) break;\n            e += f;\n            c++\n        }\n        b = this.i(c);\n        d = this.i(c + 1);\n        if (1 > Math.abs(b.x - d.x) && 1 > Math.abs(b.y - d.y)) {\n            if (0 < c && c + 2 < a) return this.i(c - 1).Ta(this.i(c + 2))\n        } else {\n            if (1 > Math.abs(b.x - d.x)) return b.y > d.y ? 270 : 90;\n            if (1 > Math.abs(b.y - d.y)) return b.x > d.x ? 180 : 0\n        }\n        return b.Ta(d)\n    };\n    t = S.prototype;\n    t.i = function (a) {\n        return this.wb.j[a]\n    };\n    t.hd = function (a, b) {\n        this.wb.gd(a, b)\n    };\n    t.K = function (a, b, c) {\n        this.wb.gd(a, new I(b, c))\n    };\n    t.Rz = function (a, b) {\n        this.wb.Kb(a, b)\n    };\n    t.m = function (a, b, c) {\n        this.wb.Kb(a, new I(b, c))\n    };\n    t.xe = function (a) {\n        this.wb.add(a)\n    };\n    t.qf = function (a, b) {\n        this.wb.add(new I(a, b))\n    };\n    t.Xv = function (a) {\n        this.wb.lb(a)\n    };\n    t.Zj = function () {\n        this.wb.clear()\n    };\n\n    function qf(a, b, c) {\n        if (0 !== b || 0 !== c) {\n            for (var d = a.kd, e = new E, f = a.wb.iterator; f.next();) {\n                var g = f.value;\n                e.add((new I(g.x + b, g.y + c)).freeze())\n            }\n            e.freeze();\n            f = a.wb;\n            a.wb = e;\n            g = a.diagram;\n            isNaN(b) || isNaN(c) || null !== g && g.animationManager.qc ? a.o() : (a.cg.h(a.cg.x + b, a.cg.y + c), a.ma.h(a.ma.x + b, a.ma.y + c), Cl(a));\n            d && lp(a);\n            null !== g && g.animationManager.qc && (a.oh = e);\n            a.g(\"points\", f, e)\n        }\n    }\n    t.Nh = function () {\n        null === this.jh && (this.jh = this.wb, this.wb = this.wb.copy())\n    };\n    t.rf = function () {\n        if (null !== this.jh) {\n            for (var a = this.jh, b = this.wb, c = Infinity, d = Infinity, e = a.j, f = e.length, g = 0; g < f; g++) {\n                var h = e[g];\n                c = Math.min(h.x, c);\n                d = Math.min(h.y, d)\n            }\n            h = g = Infinity;\n            for (var k = b.j, l = k.length, m = 0; m < l; m++) {\n                var n = k[m];\n                g = Math.min(n.x, g);\n                h = Math.min(n.y, h);\n                n.freeze()\n            }\n            b.freeze();\n            if (l === f)\n                for (f = 0; f < l; f++) {\n                    if (m = e[f], n = k[f], m.x - c !== n.x - g || m.y - d !== n.y - h) {\n                        this.o();\n                        this.cc();\n                        break\n                    }\n                } else this.o(), this.cc();\n            this.jh = null;\n            c = this.diagram;\n            null !== c && c.animationManager.qc && (this.oh = b);\n            lp(this);\n            this.g(\"points\",\n                a, b)\n        }\n    };\n    t.ey = function () {\n        null !== this.jh && (this.wb = this.jh, this.jh = null)\n    };\n\n    function lp(a) {\n        0 === a.wb.count ? a.kd = !1 : (a.kd = !0, a.Gr = null, a.qu = NaN, a.defaultFromPoint = a.i(0), a.defaultToPoint = a.i(a.pointsCount - 1), mp(a, !1))\n    }\n    t.Oa = function () {\n        if (!this.suspendsRouting) {\n            var a = this.diagram;\n            if (a) {\n                if (a.yt.contains(this) || a.undoManager.isUndoingRedoing) return;\n                a = a.animationManager;\n                if (a.isTicking && !a.isAnimating) return;\n                null !== this.oh && !a.isTicking && a.isAnimating && (this.oh = null)\n            }\n            a = this.path;\n            null !== a && (this.kd = !1, this.o(), a.o())\n        }\n    };\n    t.hj = function () {\n        if (!this.kd && !this.jv) {\n            var a = !0;\n            try {\n                this.jv = !0, this.Nh(), a = this.computePoints()\n            } finally {\n                this.jv = !1, a ? this.rf() : this.ey()\n            }\n        }\n    };\n    S.prototype.computePoints = function () {\n        var a = this.diagram;\n        if (null === a) return !1;\n        var b = this.fromNode,\n            c = null;\n        null === b ? (a.mh || (a.Fl = new Lf, a.Fl.desiredSize = Kb, a.Fl.strokeWidth = 0, a.mh = new W, a.mh.add(a.Fl), a.mh.yb()), this.defaultFromPoint && (a.mh.position = a.mh.location = this.defaultFromPoint, a.mh.yb(), b = a.mh, c = a.Fl)) : c = this.fromPort;\n        if (null !== c && !b.isVisible()) {\n            var d = b.findVisibleNode();\n            null !== d && d !== b ? (b = d, c = d.port) : b = d\n        }\n        this.lx = b;\n        if (null === b || !b.location.v()) return !1;\n        for (; !(null === c || c.actualBounds.v() && c.zf());) c =\n            c.panel;\n        if (null === c) return !1;\n        var e = this.toNode,\n            f = null;\n        null === e ? (a.nh || (a.Gl = new Lf, a.Gl.desiredSize = Kb, a.Gl.strokeWidth = 0, a.nh = new W, a.nh.add(a.Gl), a.nh.yb()), this.defaultToPoint && (a.nh.position = a.nh.location = this.defaultToPoint, a.nh.yb(), e = a.nh, f = a.Gl)) : f = this.toPort;\n        null === f || e.isVisible() || (a = e.findVisibleNode(), null !== a && a !== e ? (e = a, f = a.port) : e = a);\n        this.mx = e;\n        if (null === e || !e.location.v()) return !1;\n        for (; !(null === f || f.actualBounds.v() && f.zf());) f = f.panel;\n        if (null === f) return !1;\n        var g = this.pointsCount;\n        d = this.computeSpot(!0, c);\n        a = this.computeSpot(!1, f);\n        var h = np(d),\n            k = np(a),\n            l = c === f && null !== c,\n            m = this.isOrthogonal,\n            n = this.curve === qg;\n        this.Tf = l && !m ? n = !0 : !1;\n        var p = this.computeAdjusting() === bg || l;\n        if (!m && !l && h && k) {\n            if (h = !1, !p && 3 <= g && (p = this.getLinkPoint(b, c, d, !0, !1, e, f), k = this.getLinkPoint(e, f, a, !1, !1, b, c), h = this.adjustPoints(0, p, g - 1, k)) && (p = this.getLinkPoint(b, c, d, !0, !1, e, f), k = this.getLinkPoint(e, f, a, !1, !1, b, c), this.adjustPoints(0, p, g - 1, k)), !h)\n                if (this.Zj(), n) {\n                    g = this.getLinkPoint(b, c, d, !0, !1, e, f);\n                    p = this.getLinkPoint(e,\n                        f, a, !1, !1, b, c);\n                    h = p.x - g.x;\n                    k = p.y - g.y;\n                    l = this.computeCurviness();\n                    n = m = 0;\n                    var r = g.x + h / 3,\n                        q = g.y + k / 3,\n                        u = r,\n                        v = q;\n                    J.A(k, 0) ? v = 0 < h ? v - l : v + l : (m = -h / k, n = Math.sqrt(l * l / (m * m + 1)), 0 > l && (n = -n), u = (0 > k ? -1 : 1) * n + r, v = m * (u - r) + q);\n                    r = g.x + 2 * h / 3;\n                    q = g.y + 2 * k / 3;\n                    var w = r,\n                        y = q;\n                    J.A(k, 0) ? y = 0 < h ? y - l : y + l : (w = (0 > k ? -1 : 1) * n + r, y = m * (w - r) + q);\n                    this.Zj();\n                    this.xe(g);\n                    this.qf(u, v);\n                    this.qf(w, y);\n                    this.xe(p);\n                    this.hd(0, this.getLinkPoint(b, c, d, !0, !1, e, f));\n                    this.hd(3, this.getLinkPoint(e, f, a, !1, !1, b, c))\n                } else d = this.getLinkPoint(b, c, d, !0, !1, e, f), a = this.getLinkPoint(e,\n                    f, a, !1, !1, b, c), this.hasCurviness() ? (p = a.x - d.x, e = a.y - d.y, f = this.computeCurviness(), b = d.x + p / 2, c = d.y + e / 2, g = b, h = c, J.A(e, 0) ? h = 0 < p ? h - f : h + f : (p = -p / e, g = Math.sqrt(f * f / (p * p + 1)), 0 > f && (g = -g), g = (0 > e ? -1 : 1) * g + b, h = p * (g - b) + c), this.xe(d), this.qf(g, h)) : this.xe(d), this.xe(a)\n        } else {\n            n = this.isAvoiding;\n            p && (m && n || l) && this.Zj();\n            var z = l ? this.computeCurviness() : 0;\n            n = this.getLinkPoint(b, c, d, !0, m, e, f);\n            r = u = q = 0;\n            if (m || !h || l) v = this.computeEndSegmentLength(b, c, d, !0), r = this.getLinkDirection(b, c, n, d, !0, m, e, f), l && (h || d.w(a) || !m && 1 === d.x +\n                a.x && 1 === d.y + a.y) && (r -= m ? 90 : 30, 0 > z && (r -= 180)), 0 > r ? r += 360 : 360 <= r && (r -= 360), l && (v += Math.abs(z) * (m ? 1 : 2)), 0 === r ? q = v : 90 === r ? u = v : 180 === r ? q = -v : 270 === r ? u = -v : (q = v * Math.cos(r * Math.PI / 180), u = v * Math.sin(r * Math.PI / 180)), d.jc() && l && (v = c.ga(Ac, I.alloc()), w = I.allocAt(v.x + 1E3 * q, v.y + 1E3 * u), this.getLinkPointFromPoint(b, c, v, w, !0, n), I.free(v), I.free(w));\n            v = this.getLinkPoint(e, f, a, !1, m, b, c);\n            var A = y = w = 0;\n            if (m || !k || l) {\n                var C = this.computeEndSegmentLength(e, f, a, !1);\n                A = this.getLinkDirection(e, f, v, a, !1, m, b, c);\n                l && (k || d.w(a) || !m &&\n                    1 === d.x + a.x && 1 === d.y + a.y) && (A += m ? 0 : 30, 0 > z && (A += 180));\n                0 > A ? A += 360 : 360 <= A && (A -= 360);\n                l && (C += Math.abs(z) * (m ? 1 : 2));\n                0 === A ? w = C : 90 === A ? y = C : 180 === A ? w = -C : 270 === A ? y = -C : (w = C * Math.cos(A * Math.PI / 180), y = C * Math.sin(A * Math.PI / 180));\n                a.jc() && l && (a = f.ga(Ac, I.alloc()), d = I.allocAt(a.x + 1E3 * w, a.y + 1E3 * y), this.getLinkPointFromPoint(e, f, a, d, !1, v), I.free(a), I.free(d))\n            }\n            a = n;\n            if (m || !h || l) a = new I(n.x + q, n.y + u);\n            d = v;\n            if (m || !k || l) d = new I(v.x + w, v.y + y);\n            !p && !m && h && 3 < g && this.adjustPoints(0, n, g - 2, d) ? this.hd(g - 1, v) : !p && !m && k && 3 < g && this.adjustPoints(1,\n                a, g - 1, v) ? this.hd(0, n) : !p && (m ? 6 <= g : 4 < g) && this.adjustPoints(1, a, g - 2, d) ? (this.hd(0, n), this.hd(g - 1, v)) : (this.Zj(), this.xe(n), (m || !h || l) && this.xe(a), m && this.addOrthoPoints(a, r, d, A, b, e), (m || !k || l) && this.xe(d), this.xe(v))\n        }\n        return !0\n    };\n\n    function op(a, b) {\n        Math.abs(b.x - a.x) > Math.abs(b.y - a.y) ? (b.x >= a.x ? b.x = a.x + 9E9 : b.x = a.x - 9E9, b.y = a.y) : (b.y >= a.y ? b.y = a.y + 9E9 : b.y = a.y - 9E9, b.x = a.x);\n        return b\n    }\n    S.prototype.getLinkPointFromPoint = function (a, b, c, d, e, f) {\n        void 0 === f && (f = new I);\n        if (null === a || null === b) return f.assign(c), f;\n        a.isVisible() || (e = a.findVisibleNode(), null !== e && e !== a && (b = e.port));\n        a = null;\n        e = b.panel;\n        null === e || e.$d() || (e = e.panel);\n        if (null === e) {\n            e = d.x;\n            d = d.y;\n            var g = c.x;\n            c = c.y\n        } else {\n            a = e.ud;\n            e = 1 / (a.m11 * a.m22 - a.m12 * a.m21);\n            g = a.m22 * e;\n            var h = -a.m12 * e,\n                k = -a.m21 * e,\n                l = a.m11 * e,\n                m = e * (a.m21 * a.dy - a.m22 * a.dx),\n                n = e * (a.m12 * a.dx - a.m11 * a.dy);\n            e = d.x * g + d.y * k + m;\n            d = d.x * h + d.y * l + n;\n            g = c.x * g + c.y * k + m;\n            c = c.x * h + c.y * l + n\n        }\n        b.hk(e, d, g, c, f);\n        null !==\n            a && f.transform(a);\n        return f\n    };\n\n    function pp(a, b) {\n        var c = b.ep;\n        null === c && (c = new qp, c.port = b, c.node = b.part, b.ep = c);\n        return rp(c, a)\n    }\n    S.prototype.getLinkPoint = function (a, b, c, d, e, f, g, h) {\n        void 0 === h && (h = new I);\n        if (c.eb() && !np(c)) return b.ga(c, h), h;\n        if (c.yf()) {\n            var k = pp(this, b);\n            if (null !== k) {\n                h.assign(k.wq);\n                if (e && this.routing === sp) {\n                    var l = pp(this, g);\n                    if (null !== l && k.em < l.em) {\n                        k = I.alloc();\n                        l = I.alloc();\n                        var m = new N(b.ga(vc, k), b.ga(Gc, l)),\n                            n = this.computeSpot(!d, g);\n                        a = this.getLinkPoint(f, g, n, !d, e, a, b, l);\n                        (c.wf(Ic) || c.wf(Jc)) && a.y >= m.y && a.y <= m.y + m.height ? h.y = a.y : (c.wf(Hc) || c.wf(Kc)) && a.x >= m.x && a.x <= m.x + m.width && (h.x = a.x);\n                        I.free(k);\n                        I.free(l)\n                    }\n                }\n                return h\n            }\n        }\n        c =\n            b.ga(.5 === c.x && .5 === c.y ? c : Ac, I.alloc());\n        this.pointsCount > (e ? 6 : 2) ? (g = d ? this.i(1) : this.i(this.pointsCount - 2), e && (g = op(c, g.copy()))) : (k = this.computeSpot(!d, g), f = I.alloc(), g = g.ga(.5 === k.x && .5 === k.y ? k : Ac, f), e && (g = op(c, g)), I.free(f));\n        this.getLinkPointFromPoint(a, b, c, g, d, h);\n        I.free(c);\n        return h\n    };\n    S.prototype.getLinkDirection = function (a, b, c, d, e, f, g, h) {\n        a: if (d.eb()) var k = d.x > d.y ? d.x > 1 - d.y ? 0 : d.x < 1 - d.y ? 270 : 315 : d.x < d.y ? d.x > 1 - d.y ? 90 : d.x < 1 - d.y ? 180 : 135 : .5 > d.x ? 225 : .5 < d.x ? 45 : 0;\n            else {\n                if (d.yf() && (k = pp(this, b), null !== k)) switch (k.yc) {\n                    case 1:\n                        k = 270;\n                        break a;\n                    case 2:\n                        k = 180;\n                        break a;\n                    default:\n                    case 4:\n                        k = 0;\n                        break a;\n                    case 8:\n                        k = 90;\n                        break a\n                }\n                k = b.ga(Ac, I.alloc());\n                this.pointsCount > (f ? 6 : 2) ? (h = e ? this.i(1) : this.i(this.pointsCount - 2), h = f ? op(k, h.copy()) : c) : (c = I.alloc(), h = h.ga(Ac, c), I.free(c));\n                c = Math.abs(h.x - k.x) > Math.abs(h.y - k.y) ? h.x >=\n                    k.x ? 0 : 180 : h.y >= k.y ? 90 : 270;\n                I.free(k);\n                k = c\n            }d.jc() && g.Wd(a) && (k += 180, 360 <= k && (k -= 360));\n        if (np(d)) return k;a = b.Xi();\n        if (0 === a) return k;45 <= a && 135 > a ? k += 90 : 135 <= a && 225 > a ? k += 180 : 225 <= a && 315 > a && (k += 270);360 <= k && (k -= 360);\n        return k\n    };\n    S.prototype.computeEndSegmentLength = function (a, b, c, d) {\n        if (null !== b && c.yf() && (a = pp(this, b), null !== a)) return a.ov;\n        a = d ? this.fromEndSegmentLength : this.toEndSegmentLength;\n        null !== b && isNaN(a) && (a = d ? b.fromEndSegmentLength : b.toEndSegmentLength);\n        isNaN(a) && (a = 10);\n        return a\n    };\n    S.prototype.computeSpot = function (a, b) {\n        void 0 === b && (b = null);\n        a ? (a = b ? b : this.fromPort, null === a ? a = Ac : (b = this.fromSpot, b.Mb() && (b = a.fromSpot), a = b === Zc ? uc : b)) : (a = b ? b : this.toPort, null === a ? a = Ac : (b = this.toSpot, b.Mb() && (b = a.toSpot), a = b === Zc ? uc : b));\n        return a\n    };\n\n    function np(a) {\n        return a === uc || .5 === a.x && .5 === a.y\n    }\n    S.prototype.computeOtherPoint = function (a, b) {\n        if (this.computeAdjusting() !== bg && 4 < this.pointsCount) return this.computeMidPoint(new I);\n        a = b.ga(Ac);\n        b = b.ep;\n        b = null !== b ? rp(b, this) : null;\n        null !== b && (a = b.wq);\n        return a\n    };\n    S.prototype.computeShortLength = function (a) {\n        if (a) {\n            a = this.fromShortLength;\n            if (isNaN(a)) {\n                var b = this.fromPort;\n                null !== b && (a = b.fromShortLength)\n            }\n            return isNaN(a) ? 0 : a\n        }\n        a = this.toShortLength;\n        isNaN(a) && (b = this.toPort, null !== b && (a = b.toShortLength));\n        return isNaN(a) ? 0 : a\n    };\n    S.prototype.tf = function (a, b, c, d, e, f) {\n        if (!1 === this.pickable) return !1;\n        void 0 === b && (b = null);\n        void 0 === c && (c = null);\n        var g = f;\n        void 0 === f && (g = rd.alloc(), g.reset());\n        g.multiply(this.transform);\n        if (this.Gh(a, g)) return dn(this, b, c, e), void 0 === f && rd.free(g), !0;\n        if (this.Gc(a, g)) {\n            var h = !1;\n            if (!this.isAtomic)\n                for (var k = this.W.j, l = k.length; l--;) {\n                    var m = k[l];\n                    if (m.visible || m === this.locationObject) {\n                        var n = m.actualBounds,\n                            p = this.naturalBounds;\n                        if (!(n.x > p.width || n.y > p.height || 0 > n.x + n.width || 0 > n.y + n.height)) {\n                            n = rd.alloc();\n                            n.set(g);\n                            if (m instanceof X) h = m.tf(a, b, c, d, e, n);\n                            else if (this.path === m) {\n                                if (m instanceof Lf)\n                                    if (h = a, p = d, !1 === m.pickable) h = !1;\n                                    else if (n.multiply(m.transform), p) b: {\n                                    var r = h,\n                                        q = n;\n                                    if (m.Gh(r, q)) h = !0;\n                                    else {\n                                        if (void 0 === q && (q = m.transform, r.ze(m.actualBounds))) {\n                                            h = !0;\n                                            break b\n                                        }\n                                        h = r.left;\n                                        p = r.right;\n                                        var u = r.top;\n                                        r = r.bottom;\n                                        var v = I.alloc(),\n                                            w = I.alloc(),\n                                            y = I.alloc(),\n                                            z = rd.alloc();\n                                        z.set(q);\n                                        z.Lv(m.transform);\n                                        z.tt();\n                                        w.x = p;\n                                        w.y = u;\n                                        w.transform(z);\n                                        v.x = h;\n                                        v.y = u;\n                                        v.transform(z);\n                                        q = !1;\n                                        Gn(m, v, w, y) ? q = !0 : (v.x = p, v.y = r, v.transform(z), Gn(m, v, w, y) ? q = !0 : (w.x =\n                                            h, w.y = r, w.transform(z), Gn(m, v, w, y) ? q = !0 : (v.x = h, v.y = u, v.transform(z), Gn(m, v, w, y) && (q = !0))));\n                                        rd.free(z);\n                                        I.free(v);\n                                        I.free(w);\n                                        I.free(y);\n                                        h = q\n                                    }\n                                }\n                                else h = m.Gh(h, n)\n                            } else h = jl(m, a, d, n);\n                            h && (p = m, null !== b && (p = b(m)), p && (null === c || c(p)) && e.add(p));\n                            rd.free(n)\n                        }\n                    }\n                }\n            void 0 === f && rd.free(g);\n            return h || null !== this.background || null !== this.areaBackground\n        }\n        void 0 === f && rd.free(g);\n        return !1\n    };\n    S.prototype.computeCurve = function () {\n        if (null === this.Tf) {\n            var a = this.fromPort,\n                b = this.isOrthogonal;\n            this.Tf = null !== a && a === this.toPort && !b\n        }\n        return this.Tf ? qg : this.curve\n    };\n    S.prototype.computeCorner = function () {\n        if (this.curve === qg) return 0;\n        var a = this.corner;\n        if (isNaN(a) || 0 > a) a = 10;\n        return a\n    };\n    S.prototype.findMidLabel = function () {\n        for (var a = this.path, b = this.W.j, c = b.length, d = 0; d < c; d++) {\n            var e = b[d];\n            if (e !== a && !e.isPanelMain && (-Infinity === e.segmentIndex || isNaN(e.segmentIndex))) return e\n        }\n        for (a = this.labelNodes; a.next();)\n            if (b = a.value, -Infinity === b.segmentIndex || isNaN(b.segmentIndex)) return b;\n        return null\n    };\n    S.prototype.computeSpacing = function () {\n        if (!this.isVisible()) return 0;\n        var a = Math.max(14, this.computeThickness());\n        var b = this.fromPort,\n            c = this.toPort;\n        if (null !== b && null !== c) {\n            var d = this.findMidLabel();\n            if (null !== d) {\n                var e = d.naturalBounds,\n                    f = d.margin,\n                    g = isNaN(e.width) ? 30 : e.width * d.scale + f.left + f.right;\n                e = isNaN(e.height) ? 14 : e.height * d.scale + f.top + f.bottom;\n                d = d.segmentOrientation;\n                d === In || d === hp || d === gp ? a = Math.max(a, e) : d === Pm || d === Qm || d === Nm || d === Om ? a = Math.max(a, g) : (b = b.ga(Ac).Ta(c.ga(Ac)) / 180 * Math.PI, a = Math.max(a,\n                    Math.abs(Math.sin(b) * g) + Math.abs(Math.cos(b) * e) + 1));\n                this.curve === qg && (a *= 1.333)\n            }\n        }\n        return a\n    };\n    S.prototype.arrangeBundledLinks = function (a, b) {\n        if (b)\n            for (b = 0; b < a.length; b++) {\n                var c = a[b];\n                c.computeAdjusting() === bg && c.Oa()\n            }\n    };\n    S.prototype.computeCurviness = function () {\n        var a = this.curviness;\n        if (isNaN(a)) {\n            a = 16;\n            var b = this.Kf;\n            if (null !== b) {\n                for (var c = Fa(), d = 0, e = b.links, f = 0; f < e.length; f++) {\n                    var g = e[f].computeSpacing();\n                    c.push(g);\n                    d += g\n                }\n                d = -d / 2;\n                for (f = 0; f < e.length; f++) {\n                    if (e[f] === this) {\n                        a = d + c[f] / 2;\n                        break\n                    }\n                    d += c[f]\n                }\n                b.Bt === this.fromNode && (a = -a);\n                Ha(c)\n            }\n        }\n        return a\n    };\n    S.prototype.computeThickness = function () {\n        if (!this.isVisible()) return 0;\n        var a = this.path;\n        return null !== a ? Math.max(a.strokeWidth, 1) : 1\n    };\n    S.prototype.hasCurviness = function () {\n        return !isNaN(this.curviness) || null !== this.Kf\n    };\n    S.prototype.adjustPoints = function (a, b, c, d) {\n        var e = this.computeAdjusting();\n        if (this.isOrthogonal) {\n            if (e === ep) return !1;\n            e === fp && (e = dp)\n        }\n        switch (e) {\n            case ep:\n                var f = this.i(a),\n                    g = this.i(c);\n                if (!f.Ma(b) || !g.Ma(d)) {\n                    e = f.x;\n                    f = f.y;\n                    var h = g.x - e,\n                        k = g.y - f,\n                        l = Math.sqrt(h * h + k * k);\n                    if (!J.$(l, 0)) {\n                        if (J.$(h, 0)) var m = 0 > k ? -Math.PI / 2 : Math.PI / 2;\n                        else m = Math.atan(k / Math.abs(h)), 0 > h && (m = Math.PI - m);\n                        g = b.x;\n                        var n = b.y;\n                        h = d.x - g;\n                        var p = d.y - n;\n                        k = Math.sqrt(h * h + p * p);\n                        J.$(h, 0) ? p = 0 > p ? -Math.PI / 2 : Math.PI / 2 : (p = Math.atan(p / Math.abs(h)), 0 > h && (p = Math.PI - p));\n                        l =\n                            k / l;\n                        m = p - m;\n                        this.hd(a, b);\n                        for (a += 1; a < c; a++) b = this.i(a), h = b.x - e, k = b.y - f, b = Math.sqrt(h * h + k * k), J.$(b, 0) || (J.$(h, 0) ? k = 0 > k ? -Math.PI / 2 : Math.PI / 2 : (k = Math.atan(k / Math.abs(h)), 0 > h && (k = Math.PI - k)), h = k + m, b *= l, this.K(a, g + b * Math.cos(h), n + b * Math.sin(h)));\n                        this.hd(c, d)\n                    }\n                }\n                return !0;\n            case fp:\n                f = this.i(a);\n                n = this.i(c);\n                if (!f.Ma(b) || !n.Ma(d)) {\n                    e = f.x;\n                    f = f.y;\n                    g = n.x;\n                    n = n.y;\n                    l = (g - e) * (g - e) + (n - f) * (n - f);\n                    h = b.x;\n                    m = b.y;\n                    k = d.x;\n                    p = d.y;\n                    var r = 1;\n                    if (0 !== k - h) {\n                        var q = (p - m) / (k - h);\n                        r = Math.sqrt(1 + 1 / (q * q))\n                    } else q = 9E9;\n                    this.hd(a, b);\n                    for (a += 1; a < c; a++) {\n                        b = this.i(a);\n                        var u = b.x,\n                            v = b.y,\n                            w = .5;\n                        0 !== l && (w = ((e - u) * (e - g) + (f - v) * (f - n)) / l);\n                        var y = e + w * (g - e),\n                            z = f + w * (n - f);\n                        b = Math.sqrt((u - y) * (u - y) + (v - z) * (v - z));\n                        v < q * (u - y) + z && (b = -b);\n                        0 < q && (b = -b);\n                        u = h + w * (k - h);\n                        w = m + w * (p - m);\n                        0 !== q ? (b = u + b / r, this.K(a, b, w - (b - u) / q)) : this.K(a, u, w + b)\n                    }\n                    this.hd(c, d)\n                }\n                return !0;\n            case dp:\n                a: {\n                    if (this.isOrthogonal && (e = this.i(a), f = this.i(a + 1), g = this.i(a + 2), h = f.x, m = f.y, n = h, l = m, J.A(e.y, f.y) ? J.A(f.x, g.x) ? m = b.y : J.A(f.y, g.y) && (h = b.x) : J.A(e.x, f.x) && (J.A(f.y, g.y) ? h = b.x : J.A(f.x, g.x) && (m = b.y)), this.K(a + 1, h, m), e = this.i(c), f = this.i(c -\n                            1), g = this.i(c - 2), h = f.x, m = f.y, k = h, p = m, J.A(e.y, f.y) ? J.A(f.x, g.x) ? m = d.y : J.A(f.y, g.y) && (h = d.x) : J.A(e.x, f.x) && (J.A(f.y, g.y) ? h = d.x : J.A(f.x, g.x) && (m = d.y)), this.K(c - 1, h, m), Oj(this))) {\n                        this.K(a + 1, n, l);\n                        this.K(c - 1, k, p);\n                        c = !1;\n                        break a\n                    }\n                    this.hd(a, b);this.hd(c, d);c = !0\n                }\n                return c;\n            default:\n                return !1\n        }\n    };\n    S.prototype.addOrthoPoints = function (a, b, c, d, e, f) {\n        b = -45 <= b && 45 > b ? 0 : 45 <= b && 135 > b ? 90 : 135 <= b && 225 > b ? 180 : 270;\n        d = -45 <= d && 45 > d ? 0 : 45 <= d && 135 > d ? 90 : 135 <= d && 225 > d ? 180 : 270;\n        var g = e.actualBounds.copy(),\n            h = f.actualBounds.copy();\n        if (g.v() && h.v()) {\n            g.Vc(8, 8);\n            h.Vc(8, 8);\n            g.He(a);\n            h.He(c);\n            if (0 === b)\n                if (c.x > a.x || 270 === d && c.y < a.y && h.right > a.x || 90 === d && c.y > a.y && h.right > a.x) {\n                    var k = new I(c.x, a.y);\n                    var l = new I(c.x, (a.y + c.y) / 2);\n                    180 === d ? (k.x = this.computeMidOrthoPosition(a.x, a.y, c.x, c.y, !1), l.x = k.x, l.y = c.y) : 270 === d && c.y < a.y || 90 === d &&\n                        c.y > a.y ? (k.x = a.x < h.left ? this.computeMidOrthoPosition(a.x, a.y, h.left, c.y, !1) : a.x < h.right && (270 === d && a.y < h.top || 90 === d && a.y > h.bottom) ? this.computeMidOrthoPosition(a.x, a.y, c.x, c.y, !1) : h.right, l.x = k.x, l.y = c.y) : 0 === d && a.x < h.left && a.y > h.top && a.y < h.bottom && (k.x = a.x, k.y = a.y < c.y ? Math.min(c.y, h.top) : Math.max(c.y, h.bottom), l.y = k.y)\n                } else {\n                    k = new I(a.x, c.y);\n                    l = new I((a.x + c.x) / 2, c.y);\n                    if (180 === d || 90 === d && c.y < g.top || 270 === d && c.y > g.bottom) 180 === d && (h.aa(a) || g.aa(c)) ? k.y = this.computeMidOrthoPosition(a.x, a.y, c.x, c.y, !0) :\n                        c.y < a.y && (180 === d || 90 === d) ? k.y = this.computeMidOrthoPosition(a.x, g.top, c.x, Math.max(c.y, h.bottom), !0) : c.y > a.y && (180 === d || 270 === d) && (k.y = this.computeMidOrthoPosition(a.x, g.bottom, c.x, Math.min(c.y, h.top), !0)), l.x = c.x, l.y = k.y;\n                    if (k.y > g.top && k.y < g.bottom)\n                        if (c.x >= g.left && c.x <= a.x || a.x <= h.right && a.x >= c.x) {\n                            if (90 === d || 270 === d) k = new I(Math.max((a.x + c.x) / 2, a.x), a.y), l = new I(k.x, c.y)\n                        } else k.y = 270 === d || (0 === d || 180 === d) && c.y < a.y ? Math.min(c.y, 0 === d ? g.top : Math.min(g.top, h.top)) : Math.max(c.y, 0 === d ? g.bottom : Math.max(g.bottom,\n                            h.bottom)), l.x = c.x, l.y = k.y\n                }\n            else if (180 === b)\n                if (c.x < a.x || 270 === d && c.y < a.y && h.left < a.x || 90 === d && c.y > a.y && h.left < a.x) k = new I(c.x, a.y), l = new I(c.x, (a.y + c.y) / 2), 0 === d ? (k.x = this.computeMidOrthoPosition(a.x, a.y, c.x, c.y, !1), l.x = k.x, l.y = c.y) : 270 === d && c.y < a.y || 90 === d && c.y > a.y ? (k.x = a.x > h.right ? this.computeMidOrthoPosition(a.x, a.y, h.right, c.y, !1) : a.x > h.left && (270 === d && a.y < h.top || 90 === d && a.y > h.bottom) ? this.computeMidOrthoPosition(a.x, a.y, c.x, c.y, !1) : h.left, l.x = k.x, l.y = c.y) : 180 === d && a.x > h.right && a.y > h.top && a.y <\n                    h.bottom && (k.x = a.x, k.y = a.y < c.y ? Math.min(c.y, h.top) : Math.max(c.y, h.bottom), l.y = k.y);\n                else {\n                    k = new I(a.x, c.y);\n                    l = new I((a.x + c.x) / 2, c.y);\n                    if (0 === d || 90 === d && c.y < g.top || 270 === d && c.y > g.bottom) 0 === d && (h.aa(a) || g.aa(c)) ? k.y = this.computeMidOrthoPosition(a.x, a.y, c.x, c.y, !0) : c.y < a.y && (0 === d || 90 === d) ? k.y = this.computeMidOrthoPosition(a.x, g.top, c.x, Math.max(c.y, h.bottom), !0) : c.y > a.y && (0 === d || 270 === d) && (k.y = this.computeMidOrthoPosition(a.x, g.bottom, c.x, Math.min(c.y, h.top), !0)), l.x = c.x, l.y = k.y;\n                    if (k.y > g.top && k.y < g.bottom)\n                        if (c.x <=\n                            g.right && c.x >= a.x || a.x >= h.left && a.x <= c.x) {\n                            if (90 === d || 270 === d) k = new I(Math.min((a.x + c.x) / 2, a.x), a.y), l = new I(k.x, c.y)\n                        } else k.y = 270 === d || (0 === d || 180 === d) && c.y < a.y ? Math.min(c.y, 180 === d ? g.top : Math.min(g.top, h.top)) : Math.max(c.y, 180 === d ? g.bottom : Math.max(g.bottom, h.bottom)), l.x = c.x, l.y = k.y\n                }\n            else if (90 === b)\n                if (c.y > a.y || 180 === d && c.x < a.x && h.bottom > a.y || 0 === d && c.x > a.x && h.bottom > a.y) k = new I(a.x, c.y), l = new I((a.x + c.x) / 2, c.y), 270 === d ? (k.y = this.computeMidOrthoPosition(a.x, a.y, c.x, c.y, !0), l.x = c.x, l.y = k.y) : 180 ===\n                    d && c.x < a.x || 0 === d && c.x > a.x ? (k.y = a.y < h.top ? this.computeMidOrthoPosition(a.x, a.y, c.x, h.top, !0) : a.y < h.bottom && (180 === d && a.x < h.left || 0 === d && a.x > h.right) ? this.computeMidOrthoPosition(a.x, a.y, c.x, c.y, !0) : h.bottom, l.x = c.x, l.y = k.y) : 90 === d && a.y < h.top && a.x > h.left && a.x < h.right && (k.x = a.x < c.x ? Math.min(c.x, h.left) : Math.max(c.x, h.right), k.y = a.y, l.x = k.x);\n                else {\n                    k = new I(c.x, a.y);\n                    l = new I(c.x, (a.y + c.y) / 2);\n                    if (270 === d || 0 === d && c.x < g.left || 180 === d && c.x > g.right) 270 === d && (h.aa(a) || g.aa(c)) ? k.x = this.computeMidOrthoPosition(a.x,\n                        a.y, c.x, c.y, !1) : c.x < a.x && (270 === d || 0 === d) ? k.x = this.computeMidOrthoPosition(g.left, a.y, Math.max(c.x, h.right), c.y, !1) : c.x > a.x && (270 === d || 180 === d) && (k.x = this.computeMidOrthoPosition(g.right, a.y, Math.min(c.x, h.left), c.y, !1)), l.x = k.x, l.y = c.y;\n                    if (k.x > g.left && k.x < g.right)\n                        if (c.y >= g.top && c.y <= a.y || a.y <= h.bottom && a.y >= c.y) {\n                            if (0 === d || 180 === d) k = new I(a.x, Math.max((a.y + c.y) / 2, a.y)), l = new I(c.x, k.y)\n                        } else k.x = 180 === d || (90 === d || 270 === d) && c.x < a.x ? Math.min(c.x, 90 === d ? g.left : Math.min(g.left, h.left)) : Math.max(c.x, 90 ===\n                            d ? g.right : Math.max(g.right, h.right)), l.x = k.x, l.y = c.y\n                }\n            else if (c.y < a.y || 180 === d && c.x < a.x && h.top < a.y || 0 === d && c.x > a.x && h.top < a.y) k = new I(a.x, c.y), l = new I((a.x + c.x) / 2, c.y), 90 === d ? (k.y = this.computeMidOrthoPosition(a.x, a.y, c.x, c.y, !0), l.x = c.x, l.y = k.y) : 180 === d && c.x < a.x || 0 === d && c.x >= a.x ? (k.y = a.y > h.bottom ? this.computeMidOrthoPosition(a.x, a.y, c.x, h.bottom, !0) : a.y > h.top && (180 === d && a.x < h.left || 0 === d && a.x > h.right) ? this.computeMidOrthoPosition(a.x, a.y, c.x, c.y, !0) : h.top, l.x = c.x, l.y = k.y) : 270 === d && a.y > h.bottom && a.x >\n                h.left && a.x < h.right && (k.x = a.x < c.x ? Math.min(c.x, h.left) : Math.max(c.x, h.right), k.y = a.y, l.x = k.x);\n            else {\n                k = new I(c.x, a.y);\n                l = new I(c.x, (a.y + c.y) / 2);\n                if (90 === d || 0 === d && c.x < g.left || 180 === d && c.x > g.right) 90 === d && (h.aa(a) || g.aa(c)) ? k.x = this.computeMidOrthoPosition(a.x, a.y, c.x, c.y, !1) : c.x < a.x && (90 === d || 0 === d) ? k.x = this.computeMidOrthoPosition(g.left, a.y, Math.max(c.x, h.right), c.y, !1) : c.x > a.x && (90 === d || 180 === d) && (k.x = this.computeMidOrthoPosition(g.right, a.y, Math.min(c.x, h.left), c.y, !1)), l.x = k.x, l.y = c.y;\n                if (k.x > g.left &&\n                    k.x < g.right)\n                    if (c.y <= g.bottom && c.y >= a.y || a.y >= h.top && a.y <= c.y) {\n                        if (0 === d || 180 === d) k = new I(a.x, Math.min((a.y + c.y) / 2, a.y)), l = new I(c.x, k.y)\n                    } else k.x = 180 === d || (90 === d || 270 === d) && c.x < a.x ? Math.min(c.x, 270 === d ? g.left : Math.min(g.left, h.left)) : Math.max(c.x, 270 === d ? g.right : Math.max(g.right, h.right)), l.x = k.x, l.y = c.y\n            }\n            var m = k,\n                n = l,\n                p = c;\n            if (this.isAvoiding) {\n                var r = this.diagram;\n                if (null === r || !rk(r) || g.aa(p) && !f.Wd(e) || h.aa(a) && !e.Wd(f) || e === f || this.layer.isTemporary) b = !1;\n                else {\n                    var q = sk(r, !0, this.containingGroup, null);\n                    if (q.lk(Math.min(a.x, m.x), Math.min(a.y, m.y), Math.abs(a.x - m.x), Math.abs(a.y - m.y)) && q.lk(Math.min(m.x, n.x), Math.min(m.y, n.y), Math.abs(m.x - n.x), Math.abs(m.y - n.y)) && q.lk(Math.min(n.x, p.x), Math.min(n.y, p.y), Math.abs(n.x - p.x), Math.abs(n.y - p.y))) b = !1;\n                    else {\n                        e = a;\n                        f = p;\n                        var u = c = null;\n                        if (r.isVirtualized) {\n                            r = q.bounds.copy();\n                            r.Vc(-q.dm, -q.cm);\n                            var v = I.alloc();\n                            tp(q, a.x, a.y) || (J.Uc(r.x, r.y, r.x + r.width, r.y + r.height, a.x, a.y, m.x, m.y, v) ? (c = a = v.copy(), b = v.Ta(m)) : J.Uc(r.x, r.y, r.x + r.width, r.y + r.height, m.x, m.y, n.x, n.y, v) ? (c = a =\n                                v.copy(), b = v.Ta(n)) : J.Uc(r.x, r.y, r.x + r.width, r.y + r.height, n.x, n.y, p.x, p.y, v) && (c = a = v.copy(), b = v.Ta(p)));\n                            tp(q, p.x, p.y) || (J.Uc(r.x, r.y, r.x + r.width, r.y + r.height, p.x, p.y, n.x, n.y, v) ? (u = p = v.copy(), d = n.Ta(v)) : J.Uc(r.x, r.y, r.x + r.width, r.y + r.height, n.x, n.y, m.x, m.y, v) ? (u = p = v.copy(), d = m.Ta(v)) : J.Uc(r.x, r.y, r.x + r.width, r.y + r.height, m.x, m.y, a.x, a.y, v) && (u = p = v.copy(), d = a.Ta(v)));\n                            I.free(v)\n                        }\n                        g = g.copy().Hc(h);\n                        h = q.vA;\n                        g.Vc(q.dm * h, q.cm * h);\n                        up(q, a, b, p, d, g);\n                        h = vp(q, p.x, p.y);\n                        !q.abort && h >= wp && (vk(q), h = q.$z, g.Vc(q.dm * h, q.cm *\n                            h), up(q, a, b, p, d, g), h = vp(q, p.x, p.y));\n                        !q.abort && h >= wp && q.CA && (vk(q), up(q, a, b, p, d, q.bounds), h = vp(q, p.x, p.y));\n                        if (!q.abort && h < wp && vp(q, p.x, p.y) !== xp) {\n                            yp(this, q, p.x, p.y, d, !0);\n                            g = this.i(2);\n                            if (4 > this.pointsCount) 0 === b || 180 === b ? (g.x = a.x, g.y = p.y) : (g.x = p.x, g.y = a.y), this.K(2, g.x, g.y), this.m(3, g.x, g.y);\n                            else if (p = this.i(3), 0 === b || 180 === b) J.A(g.x, p.x) ? (g = 0 === b ? Math.max(g.x, a.x) : Math.min(g.x, a.x), this.K(2, g, a.y), this.K(3, g, p.y)) : J.A(g.y, p.y) ? (Math.abs(a.y - g.y) <= q.cm / 2 && (this.K(2, g.x, a.y), this.K(3, p.x, a.y)), this.m(2,\n                                g.x, a.y)) : this.K(2, a.x, g.y);\n                            else if (90 === b || 270 === b) J.A(g.y, p.y) ? (g = 90 === b ? Math.max(g.y, a.y) : Math.min(g.y, a.y), this.K(2, a.x, g), this.K(3, p.x, g)) : J.A(g.x, p.x) ? (Math.abs(a.x - g.x) <= q.dm / 2 && (this.K(2, a.x, g.y), this.K(3, a.x, p.y)), this.m(2, a.x, g.y)) : this.K(2, g.x, a.y);\n                            null !== c && (a = this.i(1), p = this.i(2), a.x !== p.x && a.y !== p.y ? 0 === b || 180 === b ? this.m(2, a.x, p.y) : this.m(2, p.x, a.y) : 0 === b || 180 === b ? this.m(2, e.x, c.y) : this.m(2, c.x, e.y));\n                            null !== u && (0 === d || 180 === d ? this.qf(f.x, u.y) : this.qf(u.x, f.y));\n                            b = !0\n                        } else b = !1\n                    }\n                }\n            } else b = !1;\n            b || (this.xe(k), this.xe(l))\n        }\n    };\n    S.prototype.computeMidOrthoPosition = function (a, b, c, d, e) {\n        var f = 0;\n        this.hasCurviness() && (f = this.computeCurviness());\n        return e ? (b + d) / 2 + f : (a + c) / 2 + f\n    };\n\n    function Oj(a) {\n        if (null === a.diagram || !a.isAvoiding || !rk(a.diagram)) return !1;\n        var b = a.points.j,\n            c = b.length;\n        if (4 > c) return !1;\n        a = sk(a.diagram, !0, a.containingGroup, null);\n        for (var d = 1; d < c - 2; d++) {\n            var e = b[d],\n                f = b[d + 1];\n            if (!a.lk(Math.min(e.x, f.x), Math.min(e.y, f.y), Math.abs(e.x - f.x), Math.abs(e.y - f.y))) return !0\n        }\n        return !1\n    }\n\n    function yp(a, b, c, d, e, f) {\n        var g = b.dm,\n            h = b.cm,\n            k = vp(b, c, d),\n            l = c,\n            m = d;\n        for (0 === e ? l += g : 90 === e ? m += h : 180 === e ? l -= g : m -= h; k > zp && vp(b, l, m) === k - 1;) c = l, d = m, 0 === e ? l += g : 90 === e ? m += h : 180 === e ? l -= g : m -= h, --k;\n        if (f) {\n            if (k > zp)\n                if (180 === e || 0 === e) c = Math.floor(c / g) * g + g / 2;\n                else if (90 === e || 270 === e) d = Math.floor(d / h) * h + h / 2\n        } else c = Math.floor(c / g) * g + g / 2, d = Math.floor(d / h) * h + h / 2;\n        k > zp && (f = e, l = c, m = d, 0 === e ? (f = 90, m += h) : 90 === e ? (f = 180, l -= g) : 180 === e ? (f = 270, m -= h) : 270 === e && (f = 0, l += g), vp(b, l, m) === k - 1 ? yp(a, b, l, m, f, !1) : (l = c, m = d, 0 === e ? (f = 270, m -= h) : 90 ===\n            e ? (f = 0, l += g) : 180 === e ? (f = 90, m += h) : 270 === e && (f = 180, l -= g), vp(b, l, m) === k - 1 && yp(a, b, l, m, f, !1)));\n        a.qf(c, d)\n    }\n    S.prototype.gz = function (a) {\n        var b = a.x;\n        a = a.y;\n        for (var c = this.i(0), d = this.i(1), e = Ab(b, a, c.x, c.y, d.x, d.y), f = 0, g = 1; g < this.pointsCount - 1; g++) {\n            c = this.i(g + 1);\n            var h = Ab(b, a, d.x, d.y, c.x, c.y);\n            d = c;\n            h < e && (f = g, e = h)\n        }\n        return f\n    };\n    S.prototype.cc = function () {\n        this.Yn = !0\n    };\n    S.prototype.nk = function (a) {\n        if (!a) {\n            if (!1 === this.kd) return;\n            a = this.zb();\n            if (!this.Yn && (null === a || null !== a.geometry)) return\n        }\n        this.ka = this.makeGeometry();\n        a = this.path;\n        if (null !== a) {\n            a.ka = this.ka;\n            for (var b = this.W.j, c = b.length, d = 0; d < c; d++) {\n                var e = b[d];\n                e !== a && e.isPanelMain && e instanceof Lf && (e.ka = this.ka)\n            }\n        }\n    };\n    S.prototype.makeGeometry = function () {\n        var a = this.ka,\n            b = this.pointsCount;\n        if (2 > b) return a.type = wd, this.Yn = !1, a;\n        var c = !1,\n            d = this.diagram;\n        null !== d && ip(this) && d.Sg.contains(this) && (0 !== this.El.width || 0 !== this.El.height) && (c = !0);\n        var e = this.i(0).copy(),\n            f = e.copy();\n        d = this.wb.j;\n        var g = this.computeCurve();\n        if (g === qg && 3 <= b && !J.$(this.smoothness, 0))\n            if (3 === b) {\n                var h = this.i(1);\n                d = Math.min(e.x, h.x);\n                var k = Math.min(e.y, h.y);\n                h = this.i(2);\n                d = Math.min(d, h.x);\n                k = Math.min(k, h.y)\n            } else {\n                if (this.isOrthogonal)\n                    for (k = 0; k < b; k++) h = d[k], f.x =\n                        Math.min(h.x, f.x), f.y = Math.min(h.y, f.y);\n                else\n                    for (d = 3; d < b; d += 3) d + 3 >= b && (d = b - 1), k = this.i(d), f.x = Math.min(k.x, f.x), f.y = Math.min(k.y, f.y);\n                d = f.x;\n                k = f.y\n            }\n        else {\n            for (k = 0; k < b; k++) h = d[k], f.x = Math.min(h.x, f.x), f.y = Math.min(h.y, f.y);\n            d = f.x;\n            k = f.y\n        }\n        d -= this.Vu.x;\n        k -= this.Vu.y;\n        e.x -= d;\n        e.y -= k;\n        if (2 !== b || ip(this)) {\n            a.type = ud;\n            h = Jd(a);\n            0 !== this.computeShortLength(!0) && (e = Ap(this, e, !0, f));\n            Kd(h, e.x, e.y, !1);\n            if (g === qg && 3 <= b && !J.$(this.smoothness, 0))\n                if (3 === b) c = this.i(1), b = c.x - d, c = c.y - k, e = this.i(2).copy(), e.x -= d, e.y -= k, 0 !== this.computeShortLength(!1) &&\n                    (e = Ap(this, e, !1, f)), Ld(h, b, c, b, c, e.x, e.y);\n                else if (this.isOrthogonal) {\n                f = new I(d, k);\n                e = this.i(1).copy();\n                g = new I(d, k);\n                b = new I(d, k);\n                c = this.i(0);\n                for (var l, m = this.smoothness / 3, n = 1; n < this.pointsCount - 1; n++) {\n                    l = this.i(n);\n                    var p = c,\n                        r = l,\n                        q = this.i(Bp(this, l, n, !1));\n                    if (!J.$(p.x, r.x) || !J.$(r.x, q.x))\n                        if (!J.$(p.y, r.y) || !J.$(r.y, q.y)) {\n                            var u = m;\n                            isNaN(u) && (u = this.smoothness / 3);\n                            var v = p.x;\n                            p = p.y;\n                            var w = r.x;\n                            r = r.y;\n                            var y = q.x;\n                            q = q.y;\n                            var z = u * Cp(v, p, w, r);\n                            u *= Cp(w, r, y, q);\n                            J.$(p, r) && J.$(w, y) && (w > v ? q > r ? (g.x = w - z, g.y = r - z, b.x = w + u, b.y = r + u) : (g.x =\n                                w - z, g.y = r + z, b.x = w + u, b.y = r - u) : q > r ? (g.x = w + z, g.y = r - z, b.x = w - u, b.y = r + u) : (g.x = w + z, g.y = r + z, b.x = w - u, b.y = r - u));\n                            J.$(v, w) && J.$(r, q) && (r > p ? (y > w ? (g.x = w - z, g.y = r - z, b.x = w + u) : (g.x = w + z, g.y = r - z, b.x = w - u), b.y = r + u) : (y > w ? (g.x = w - z, g.y = r + z, b.x = w + u) : (g.x = w + z, g.y = r + z, b.x = w - u), b.y = r - u));\n                            if (J.$(v, w) && J.$(w, y) || J.$(p, r) && J.$(r, q)) v = .5 * (v + y), p = .5 * (p + q), g.x = v, g.y = p, b.x = v, b.y = p;\n                            1 === n ? (e.x = .5 * (c.x + l.x), e.y = .5 * (c.y + l.y)) : 2 === n && J.$(c.x, this.i(0).x) && J.$(c.y, this.i(0).y) && (e.x = .5 * (c.x + l.x), e.y = .5 * (c.y + l.y));\n                            Ld(h, e.x - d, e.y - k, g.x - d, g.y -\n                                k, l.x - d, l.y - k);\n                            f.set(g);\n                            e.set(b);\n                            c = l\n                        }\n                }\n                f = c.x;\n                c = c.y;\n                e = this.i(this.pointsCount - 1);\n                0 !== this.computeShortLength(!1) && (e = Ap(this, e.copy(), !1, Fb));\n                f = .5 * (f + e.x);\n                c = .5 * (c + e.y);\n                Ld(h, b.x - d, b.y - k, f - d, c - k, e.x - d, e.y - k)\n            } else\n                for (c = 3; c < b; c += 3) f = this.i(c - 2), c + 3 >= b && (c = b - 1), e = this.i(c - 1), g = this.i(c), c === b - 1 && 0 !== this.computeShortLength(!1) && (g = Ap(this, g.copy(), !1, Fb)), Ld(h, f.x - d, f.y - k, e.x - d, e.y - k, g.x - d, g.y - k);\n            else {\n                f = I.alloc();\n                f.assign(this.i(0));\n                g = 1;\n                for (e = 0; g < b;) {\n                    g = Bp(this, f, g, 1 < g);\n                    m = this.i(g);\n                    if (g >= b - 1) {\n                        if (!f.w(m)) 0 !==\n                            this.computeShortLength(!1) && (m = Ap(this, m.copy(), !1, Fb)), Dp(this, h, -d, -k, f, m, c);\n                        else if (0 === e)\n                            for (g = 1; g < b;) m = this.i(g++), Dp(this, h, -d, -k, f, m, c), f.assign(m);\n                        break\n                    }\n                    e = Bp(this, m, g + 1, g < b - 3);\n                    g = -d;\n                    l = -k;\n                    n = this.i(e);\n                    v = c;\n                    J.A(f.y, m.y) && J.A(m.x, n.x) ? (p = this.computeCorner(), p = Math.min(p, Math.abs(m.x - f.x) / 2), p = u = Math.min(p, Math.abs(n.y - m.y) / 2), J.A(p, 0) ? (Dp(this, h, g, l, f, m, v), f.assign(m)) : (w = m.x, r = m.y, y = w, q = r, m.x > f.x ? w = m.x - p : w = m.x + p, n.y > m.y ? q = m.y + u : q = m.y - u, Dp(this, h, g, l, f, new I(w, r), v), Qd(h, m.x + g, m.y + l, y + g, q + l),\n                        f.h(y, q))) : J.A(f.x, m.x) && J.A(m.y, n.y) ? (p = this.computeCorner(), p = Math.min(p, Math.abs(m.y - f.y) / 2), p = u = Math.min(p, Math.abs(n.x - m.x) / 2), J.A(u, 0) ? (Dp(this, h, g, l, f, m, v), f.assign(m)) : (w = m.x, r = m.y, y = w, q = r, m.y > f.y ? r = m.y - p : r = m.y + p, n.x > m.x ? y = m.x + u : y = m.x - u, Dp(this, h, g, l, f, new I(w, r), v), Qd(h, m.x + g, m.y + l, y + g, q + l), f.h(y, q))) : (Dp(this, h, g, l, f, m, v), f.assign(m));\n                    g = e\n                }\n                I.free(f)\n            }\n            Td = h\n        } else h = this.i(1).copy(), h.x -= d, h.y -= k, 0 !== this.computeShortLength(!0) && (e = Ap(this, e, !0, f)), 0 !== this.computeShortLength(!1) && (h = Ap(this,\n            h, !1, f)), a.type = wd, a.startX = e.x, a.startY = e.y, a.endX = h.x, a.endY = h.y;\n        this.Yn = !1;\n        return a\n    };\n\n    function Cp(a, b, c, d) {\n        a = c - a;\n        if (isNaN(a) || Infinity === a || -Infinity === a) return NaN;\n        0 > a && (a = -a);\n        b = d - b;\n        if (isNaN(b) || Infinity === b || -Infinity === b) return NaN;\n        0 > b && (b = -b);\n        return J.$(a, 0) ? b : J.$(b, 0) ? a : Math.sqrt(a * a + b * b)\n    }\n\n    function Ap(a, b, c, d) {\n        var e = a.pointsCount;\n        if (2 > e) return b;\n        if (c) {\n            var f = a.i(1);\n            c = f.x - d.x;\n            f = f.y - d.y;\n            d = Cp(b.x, b.y, c, f);\n            if (0 === d) return b;\n            e = 2 === e ? .5 * d : d;\n            a = a.computeShortLength(!0);\n            a > e && (a = e);\n            e = a * (f - b.y) / d;\n            b.x += a * (c - b.x) / d;\n            b.y += e\n        } else {\n            f = a.i(e - 2);\n            c = f.x - d.x;\n            f = f.y - d.y;\n            d = Cp(b.x, b.y, c, f);\n            if (0 === d) return b;\n            e = 2 === e ? .5 * d : d;\n            a = a.computeShortLength(!1);\n            a > e && (a = e);\n            e = a * (b.y - f) / d;\n            b.x -= a * (b.x - c) / d;\n            b.y -= e\n        }\n        return b\n    }\n\n    function Bp(a, b, c, d) {\n        for (var e = a.pointsCount, f = b; J.$(b.x, f.x) && J.$(b.y, f.y);) {\n            if (c >= e) return e - 1;\n            f = a.i(c++)\n        }\n        if (!J.$(b.x, f.x) && !J.$(b.y, f.y)) return c - 1;\n        for (var g = f; J.$(b.x, f.x) && J.$(f.x, g.x) && (!d || (b.y >= f.y ? f.y >= g.y : f.y <= g.y)) || J.$(b.y, f.y) && J.$(f.y, g.y) && (!d || (b.x >= f.x ? f.x >= g.x : f.x <= g.x));) {\n            if (c >= e) return e - 1;\n            g = a.i(c++)\n        }\n        return c - 2\n    }\n\n    function Dp(a, b, c, d, e, f, g) {\n        if (!g && ip(a)) {\n            g = [];\n            var h = 0;\n            a.isVisible() && (h = Ep(a, e, f, g));\n            if (0 < h)\n                if (J.A(e.y, f.y))\n                    if (e.x < f.x)\n                        for (var k = 0; k < h;) {\n                            var l = Math.max(e.x, Math.min(g[k++] - 5, f.x - 10));\n                            b.lineTo(l + c, f.y + d);\n                            var m = l + c;\n                            for (var n = Math.min(l + 10, f.x); k < h;)\n                                if (l = g[k], l < n + 10) k++, n = Math.min(l + 5, f.x);\n                                else break;\n                            l = f.y - 10 + d;\n                            n += c;\n                            var p = f.y + d;\n                            a.curve === ag ? Kd(b, n, p, !1) : Ld(b, m, l, n, l, n, p)\n                        } else\n                            for (--h; 0 <= h;) {\n                                k = Math.min(e.x, Math.max(g[h--] + 5, f.x + 10));\n                                b.lineTo(k + c, f.y + d);\n                                m = k + c;\n                                for (l = Math.max(k - 10, f.x); 0 <= h;)\n                                    if (k = g[h], k >\n                                        l - 10) h--, l = Math.max(k - 5, f.x);\n                                    else break;\n                                k = f.y - 10 + d;\n                                l += c;\n                                n = f.y + d;\n                                a.curve === ag ? Kd(b, l, n, !1) : Ld(b, m, k, l, k, l, n)\n                            } else if (J.A(e.x, f.x))\n                                if (e.y < f.y)\n                                    for (k = 0; k < h;) {\n                                        l = Math.max(e.y, Math.min(g[k++] - 5, f.y - 10));\n                                        b.lineTo(f.x + c, l + d);\n                                        m = l + d;\n                                        for (l = Math.min(l + 10, f.y); k < h;)\n                                            if (n = g[k], n < l + 10) k++, l = Math.min(n + 5, f.y);\n                                            else break;\n                                        n = f.x - 10 + c;\n                                        p = f.x + c;\n                                        l += d;\n                                        a.curve === ag ? Kd(b, p, l, !1) : Ld(b, n, m, n, l, p, l)\n                                    } else\n                                        for (--h; 0 <= h;) {\n                                            k = Math.min(e.y, Math.max(g[h--] + 5, f.y + 10));\n                                            b.lineTo(f.x + c, k + d);\n                                            m = k + d;\n                                            for (k = Math.max(k - 10, f.y); 0 <= h;)\n                                                if (l = g[h],\n                                                    l > k - 10) h--, k = Math.max(l - 5, f.y);\n                                                else break;\n                                            l = f.x - 10 + c;\n                                            n = f.x + c;\n                                            k += d;\n                                            a.curve === ag ? Kd(b, n, k, !1) : Ld(b, l, m, l, k, n, k)\n                                        }\n        }\n        b.lineTo(f.x + c, f.y + d)\n    }\n\n    function Ep(a, b, c, d) {\n        var e = a.diagram;\n        if (null === e || b.w(c)) return 0;\n        for (e = e.layers; e.next();) {\n            var f = e.value;\n            if (null !== f && f.visible) {\n                f = f.Ca.j;\n                for (var g = f.length, h = 0; h < g; h++) {\n                    var k = f[h];\n                    if (k instanceof S) {\n                        if (k === a) return 0 < d.length && d.sort(function (a, b) {\n                            return a - b\n                        }), d.length;\n                        if (k.isVisible() && ip(k)) {\n                            var l = k.routeBounds;\n                            l.v() && a.routeBounds.Gc(l) && !a.usesSamePort(k) && (l = k.path, null !== l && l.zf() && Fp(b, c, d, k))\n                        }\n                    }\n                }\n            }\n        }\n        0 < d.length && d.sort(function (a, b) {\n            return a - b\n        });\n        return d.length\n    }\n\n    function Fp(a, b, c, d) {\n        for (var e = J.A(a.y, b.y), f = d.pointsCount, g = d.i(0), h = I.alloc(), k = 1; k < f; k++) {\n            var l = d.i(k);\n            if (k < f - 1) {\n                var m = d.i(k + 1);\n                if (g.y === l.y && l.y === m.y) {\n                    if (l.x > g.x && m.x >= l.x || l.x < g.x && m.x <= l.x) continue\n                } else if (g.x === l.x && l.x === m.x && (l.y > g.y && m.y >= l.y || l.y < g.y && m.y <= l.y)) continue\n            }\n            a: {\n                m = a.x;\n                var n = a.y,\n                    p = b.x,\n                    r = b.y,\n                    q = g.x;g = g.y;\n                var u = l.x,\n                    v = l.y;\n                if (!J.A(m, p)) {\n                    if (J.A(n, r) && J.A(q, u) && Math.min(m, p) < q && Math.max(m, p) > q && Math.min(g, v) < n && Math.max(g, v) > n && !J.A(g, v)) {\n                        h.x = q;\n                        h.y = n;\n                        m = !0;\n                        break a\n                    }\n                } else if (!J.A(n, r) &&\n                    J.A(g, v) && Math.min(n, r) < g && Math.max(n, r) > g && Math.min(q, u) < m && Math.max(q, u) > m && !J.A(q, u)) {\n                    h.x = m;\n                    h.y = g;\n                    m = !0;\n                    break a\n                }\n                h.x = 0;h.y = 0;m = !1\n            }\n            m && (e ? c.push(h.x) : c.push(h.y));\n            g = l\n        }\n        I.free(h)\n    }\n\n    function ip(a) {\n        a = a.curve;\n        return a === $f || a === ag\n    }\n\n    function mp(a, b) {\n        if (b || ip(a)) b = a.diagram, null === b || b.animationManager.isTicking || b.Sg.contains(a) || 0 === a.El.width && 0 === a.El.height || b.Sg.add(a, a.El.copy())\n    }\n    S.prototype.tq = function (a) {\n        var b = this.layer;\n        if (null !== b && b.visible && !b.isTemporary) {\n            var c = b.diagram;\n            if (null !== c && !c.animationManager.isAnimating) {\n                var d = !1;\n                for (c = c.layers; c.next();) {\n                    var e = c.value;\n                    if (e.visible)\n                        if (e === b) {\n                            d = !0;\n                            var f = !1;\n                            e = e.Ca.j;\n                            for (var g = e.length, h = 0; h < g; h++) {\n                                var k = e[h];\n                                k instanceof S && (k === this ? f = !0 : f && Gp(this, k, a))\n                            }\n                        } else if (d)\n                        for (f = e.Ca.j, e = f.length, g = 0; g < e; g++) h = f[g], h instanceof S && Gp(this, h, a)\n                }\n            }\n        }\n    };\n\n    function Gp(a, b, c) {\n        if (null !== b && null !== b.ka && ip(b)) {\n            var d = b.routeBounds;\n            d.v() && (a.routeBounds.Gc(d) || c.Gc(d)) && (a.usesSamePort(b) || b.cc())\n        }\n    }\n    S.prototype.usesSamePort = function (a) {\n        var b = this.pointsCount,\n            c = a.pointsCount;\n        if (0 < b && 0 < c) {\n            var d = this.i(0),\n                e = a.i(0);\n            if (d.Ma(e)) return !0;\n            b = this.i(b - 1);\n            a = a.i(c - 1);\n            if (b.Ma(a) || d.Ma(a) || b.Ma(e)) return !0\n        } else if (this.fromNode === a.fromNode || this.toNode === a.toNode || this.fromNode === a.toNode || this.toNode === a.fromNode) return !0;\n        return !1\n    };\n    S.prototype.isVisible = function () {\n        if (!U.prototype.isVisible.call(this)) return !1;\n        var a = this.containingGroup,\n            b = !0,\n            c = this.diagram;\n        null !== c && (b = c.isTreePathToChildren);\n        c = this.fromNode;\n        if (null !== c) {\n            if (this.isTreeLink && b && !c.isTreeExpanded) return !1;\n            if (c === a) return !0;\n            for (var d = c; null !== d;) {\n                if (d.labeledLink === this) return !0;\n                d = d.containingGroup\n            }\n            c = c.findVisibleNode();\n            if (null === c || c === a) return !1\n        }\n        c = this.toNode;\n        if (null !== c) {\n            if (this.isTreeLink && !b && !c.isTreeExpanded) return !1;\n            if (c === a) return !0;\n            for (b = c; null !== b;) {\n                if (b.labeledLink ===\n                    this) return !0;\n                b = b.containingGroup\n            }\n            b = c.findVisibleNode();\n            if (null === b || b === a) return !1\n        }\n        return !0\n    };\n    S.prototype.Ob = function (a) {\n        U.prototype.Ob.call(this, a);\n        null !== this.Kf && this.Kf.nm();\n        if (null !== this.ad)\n            for (var b = this.ad.iterator; b.next();) b.value.Ob(a)\n    };\n    S.prototype.computeAdjusting = function () {\n        return null !== this.diagram && this.diagram.animationManager.isAnimating ? dp : this.Dk\n    };\n\n    function jp(a) {\n        var b = a.Qe;\n        if (null !== b) {\n            var c = a.lf;\n            if (null !== c) {\n                for (var d = a.Re, e = a.mf, f = a = null, g = b.Wa.j, h = g.length, k = 0; k < h; k++) {\n                    var l = g[k];\n                    if (l.Qe === b && l.Re === d && l.lf === c && l.mf === e || l.Qe === c && l.Re === e && l.lf === b && l.mf === d) null === f ? f = l : (null === a && (a = [], a.push(f)), a.push(l))\n                }\n                if (null !== a) {\n                    f = Oo(b, c, d, e);\n                    null === f && (f = new Hp(b, d, c, e), No(b, f), No(c, f));\n                    f.links = a;\n                    for (b = 0; b < a.length; b++) a[b].Kf = f;\n                    f.nm()\n                }\n            }\n        }\n    }\n\n    function kp(a) {\n        var b = a.Kf;\n        null !== b && (a.Kf = null, a = b.links.indexOf(a), 0 <= a && (Da(b.links, a), b.nm()))\n    }\n    S.prototype.Kh = function () {\n        return !0\n    };\n    ma.Object.defineProperties(S.prototype, {\n        fromNode: {\n            get: function () {\n                return this.Qe\n            },\n            set: function (a) {\n                var b = this.Qe;\n                if (b !== a) {\n                    var c = this.fromPort;\n                    null !== b && (this.lf !== b && So(b, this, c), kp(this), this.C(2));\n                    this.Qe = a;\n                    null !== a && this.Ob(a.isVisible());\n                    this.Tf = null;\n                    this.Oa();\n                    var d = this.diagram;\n                    null !== d && d.Z && d.partManager.setFromNodeForLink(this, a, b);\n                    var e = this.fromPort,\n                        f = this.fromPortChanged;\n                    if (null !== f) {\n                        var g = !0;\n                        null !== d && (g = d.Z, d.Z = !0);\n                        f(this, c, e);\n                        null !== d && (d.Z = g)\n                    }\n                    null !== a &&\n                        (this.lf !== a && Ro(a, this, e), jp(this), this.C(1));\n                    this.g(\"fromNode\", b, a);\n                    Lo(this)\n                }\n            }\n        },\n        fromPortId: {\n            get: function () {\n                return this.Re\n            },\n            set: function (a) {\n                var b = this.Re;\n                if (b !== a) {\n                    var c = this.fromPort;\n                    null !== c && Po(this.fromNode, c);\n                    kp(this);\n                    this.Re = a;\n                    var d = this.fromPort;\n                    null !== d && Po(this.fromNode, d);\n                    var e = this.diagram;\n                    if (null !== e) {\n                        var f = this.data,\n                            g = e.model;\n                        null !== f && g.pm() && g.jy(f, a)\n                    }\n                    c !== d && (this.Tf = null, this.Oa(), f = this.fromPortChanged, null !== f && (g = !0, null !== e && (g = e.Z, e.Z = !0), f(this,\n                        c, d), null !== e && (e.Z = g)));\n                    jp(this);\n                    this.g(\"fromPortId\", b, a)\n                }\n            }\n        },\n        fromPort: {\n            get: function () {\n                var a = this.Qe;\n                return null === a ? null : a.lt(this.Re)\n            }\n        },\n        fromPortChanged: {\n            get: function () {\n                return this.Mn\n            },\n            set: function (a) {\n                var b = this.Mn;\n                b !== a && (this.Mn = a, this.g(\"fromPortChanged\", b, a))\n            }\n        },\n        toNode: {\n            get: function () {\n                return this.lf\n            },\n            set: function (a) {\n                var b = this.lf;\n                if (b !== a) {\n                    var c = this.toPort;\n                    null !== b && (this.Qe !== b && So(b, this, c), kp(this), this.C(2));\n                    this.lf = a;\n                    null !== a && this.Ob(a.isVisible());\n                    this.Tf = null;\n                    this.Oa();\n                    var d = this.diagram;\n                    null !== d && d.Z && d.partManager.setToNodeForLink(this, a, b);\n                    var e = this.toPort,\n                        f = this.toPortChanged;\n                    if (null !== f) {\n                        var g = !0;\n                        null !== d && (g = d.Z, d.Z = !0);\n                        f(this, c, e);\n                        null !== d && (d.Z = g)\n                    }\n                    null !== a && (this.Qe !== a && Ro(a, this, e), jp(this), this.C(1));\n                    this.g(\"toNode\", b, a);\n                    Lo(this)\n                }\n            }\n        },\n        toPortId: {\n            get: function () {\n                return this.mf\n            },\n            set: function (a) {\n                var b = this.mf;\n                if (b !== a) {\n                    var c = this.toPort;\n                    null !== c && Po(this.toNode,\n                        c);\n                    kp(this);\n                    this.mf = a;\n                    var d = this.toPort;\n                    null !== d && Po(this.toNode, d);\n                    var e = this.diagram;\n                    if (null !== e) {\n                        var f = this.data,\n                            g = e.model;\n                        null !== f && g.pm() && g.ny(f, a)\n                    }\n                    c !== d && (this.Tf = null, this.Oa(), f = this.toPortChanged, null !== f && (g = !0, null !== e && (g = e.Z, e.Z = !0), f(this, c, d), null !== e && (e.Z = g)));\n                    jp(this);\n                    this.g(\"toPortId\", b, a)\n                }\n            }\n        },\n        toPort: {\n            get: function () {\n                var a = this.lf;\n                return null === a ? null : a.lt(this.mf)\n            }\n        },\n        toPortChanged: {\n            get: function () {\n                return this.Vp\n            },\n            set: function (a) {\n                var b =\n                    this.Vp;\n                b !== a && (this.Vp = a, this.g(\"toPortChanged\", b, a))\n            }\n        },\n        fromSpot: {\n            get: function () {\n                return null !== this.O ? this.O.Yg : Zc\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.Yg;\n                b.w(a) || (a = a.G(), this.O.Yg = a, this.g(\"fromSpot\", b, a), this.Oa())\n            }\n        },\n        fromEndSegmentLength: {\n            get: function () {\n                return null !== this.O ? this.O.Wg : NaN\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.Wg;\n                b !== a && (0 > a && va(a, \">= 0\", S, \"fromEndSegmentLength\"), this.O.Wg = a, this.g(\"fromEndSegmentLength\", b, a), this.Oa())\n            }\n        },\n        fromShortLength: {\n            get: function () {\n                return null !== this.O ? this.O.Xg : NaN\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.Xg;\n                b !== a && (this.O.Xg = a, this.g(\"fromShortLength\", b, a), this.Oa(), this.cc())\n            }\n        },\n        toSpot: {\n            get: function () {\n                return null !== this.O ? this.O.yh : Zc\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.yh;\n                b.w(a) || (a = a.G(), this.O.yh = a, this.g(\"toSpot\", b, a), this.Oa())\n            }\n        },\n        toEndSegmentLength: {\n            get: function () {\n                return null !== this.O ? this.O.wh :\n                    NaN\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.wh;\n                b !== a && (0 > a && va(a, \">= 0\", S, \"toEndSegmentLength\"), this.O.wh = a, this.g(\"toEndSegmentLength\", b, a), this.Oa())\n            }\n        },\n        toShortLength: {\n            get: function () {\n                return null !== this.O ? this.O.xh : NaN\n            },\n            set: function (a) {\n                this.Ec();\n                var b = this.O.xh;\n                b !== a && (this.O.xh = a, this.g(\"toShortLength\", b, a), this.Oa(), this.cc())\n            }\n        },\n        isLabeledLink: {\n            get: function () {\n                return null === this.ad ? !1 : 0 < this.ad.count\n            }\n        },\n        labelNodes: {\n            get: function () {\n                return null === this.ad ? fb : this.ad.iterator\n            }\n        },\n        relinkableFrom: {\n            get: function () {\n                return 0 !== (this.Qa & 1)\n            },\n            set: function (a) {\n                var b = 0 !== (this.Qa & 1);\n                b !== a && (this.Qa ^= 1, this.g(\"relinkableFrom\", b, a), this.Lb())\n            }\n        },\n        relinkableTo: {\n            get: function () {\n                return 0 !== (this.Qa & 2)\n            },\n            set: function (a) {\n                var b = 0 !== (this.Qa & 2);\n                b !== a && (this.Qa ^= 2, this.g(\"relinkableTo\", b, a), this.Lb())\n            }\n        },\n        resegmentable: {\n            get: function () {\n                return 0 !== (this.Qa &\n                    4)\n            },\n            set: function (a) {\n                var b = 0 !== (this.Qa & 4);\n                b !== a && (this.Qa ^= 4, this.g(\"resegmentable\", b, a), this.Lb())\n            }\n        },\n        isTreeLink: {\n            get: function () {\n                return 0 !== (this.Qa & 8)\n            },\n            set: function (a) {\n                var b = 0 !== (this.Qa & 8);\n                b !== a && (this.Qa ^= 8, this.g(\"isTreeLink\", b, a), null !== this.fromNode && Dk(this.fromNode), null !== this.toNode && Dk(this.toNode))\n            }\n        },\n        path: {\n            get: function () {\n                var a = this.zb();\n                return a instanceof Lf ? a : null\n            }\n        },\n        routeBounds: {\n            get: function () {\n                this.hj();\n                var a = this.El,\n                    b = Infinity,\n                    c = Infinity,\n                    d = this.pointsCount;\n                if (0 === d) a.h(NaN, NaN, 0, 0);\n                else {\n                    if (1 === d) d = this.i(0), b = Math.min(d.x, b), c = Math.min(d.y, c), a.h(d.x, d.y, 0, 0);\n                    else if (2 === d) {\n                        d = this.i(0);\n                        var e = this.i(1);\n                        b = Math.min(d.x, e.x);\n                        c = Math.min(d.y, e.y);\n                        a.h(d.x, d.y, 0, 0);\n                        a.He(e)\n                    } else if (this.computeCurve() === qg && 3 <= d && !this.isOrthogonal)\n                        if (e = this.i(0), b = e.x, c = e.y, a.h(b, c, 0, 0), 3 === d) {\n                            d = this.i(1);\n                            b = Math.min(d.x, b);\n                            c = Math.min(d.y, c);\n                            var f = this.i(2);\n                            b = Math.min(f.x, b);\n                            c = Math.min(f.y, c);\n                            J.bm(e.x, e.y, d.x, d.y, d.x, d.y,\n                                f.x, f.y, .5, a)\n                        } else\n                            for (f = 3; f < d; f += 3) {\n                                var g = this.i(f - 2);\n                                f + 3 >= d && (f = d - 1);\n                                var h = this.i(f - 1),\n                                    k = this.i(f);\n                                J.bm(e.x, e.y, g.x, g.y, h.x, h.y, k.x, k.y, .5, a);\n                                b = Math.min(k.x, b);\n                                c = Math.min(k.y, c);\n                                e = k\n                            } else\n                                for (e = this.i(0), f = this.i(1), b = Math.min(e.x, f.x), c = Math.min(e.y, f.y), a.h(e.x, e.y, 0, 0), a.He(f), e = 2; e < d; e++) f = this.i(e), b = Math.min(f.x, b), c = Math.min(f.y, c), a.He(f);\n                    this.Vu.h(b - a.x, c - a.y)\n                }\n                return a\n            }\n        },\n        midPoint: {\n            get: function () {\n                this.hj();\n                return this.computeMidPoint(new I)\n            }\n        },\n        midAngle: {\n            get: function () {\n                this.hj();\n                return this.computeMidAngle()\n            }\n        },\n        flattenedLengths: {\n            get: function () {\n                if (null === this.Gr) {\n                    this.kd || lp(this);\n                    for (var a = this.Gr = [], b = this.pointsCount, c = 0; c < b - 1; c++) {\n                        var d = this.i(c);\n                        var e = this.i(c + 1);\n                        J.$(d.x, e.x) ? (d = e.y - d.y, 0 > d && (d = -d)) : J.$(d.y, e.y) ? (d = e.x - d.x, 0 > d && (d = -d)) : d = Math.sqrt(d.Ae(e));\n                        a.push(d)\n                    }\n                }\n                return this.Gr\n            }\n        },\n        flattenedTotalLength: {\n            get: function () {\n                var a = this.qu;\n                if (isNaN(a)) {\n                    for (var b = this.flattenedLengths,\n                            c = b.length, d = a = 0; d < c; d++) a += b[d];\n                    this.qu = a\n                }\n                return a\n            }\n        },\n        points: {\n            get: function () {\n                return this.wb\n            },\n            set: function (a) {\n                var b = this.wb;\n                if (b !== a) {\n                    var c = null;\n                    if (Array.isArray(a)) {\n                        var d = 0 === a.length % 2;\n                        if (d)\n                            for (var e = 0; e < a.length; e++)\n                                if (\"number\" !== typeof a[e] || isNaN(a[e])) {\n                                    d = !1;\n                                    break\n                                } if (d)\n                            for (c = new E, d = 0; d < a.length / 2; d++) e = (new I(a[2 * d], a[2 * d + 1])).freeze(), c.add(e);\n                        else {\n                            d = !0;\n                            for (e = 0; e < a.length; e++) {\n                                var f = a[e];\n                                if (!za(f) || \"number\" !== typeof f.x || isNaN(f.x) || \"number\" !== typeof f.y || isNaN(f.y)) {\n                                    d = !1;\n                                    break\n                                }\n                            }\n                            if (d)\n                                for (c = new E, d = 0; d < a.length; d++) e = a[d], c.add((new I(e.x, e.y)).freeze())\n                        }\n                    } else if (a instanceof E)\n                        for (c = a.copy(), a = c.iterator; a.next();) a.value.freeze();\n                    else B(\"Link.points value is not an instance of List or Array: \" + a);\n                    c.freeze();\n                    this.wb = c;\n                    this.cc();\n                    this.o();\n                    lp(this);\n                    a = this.diagram;\n                    null !== a && (a.kk || a.undoManager.isUndoingRedoing || a.yt.add(this), a.animationManager.qc && (this.oh = c));\n                    this.g(\"points\", b, c)\n                }\n            }\n        },\n        pointsCount: {\n            get: function () {\n                return this.wb.count\n            }\n        },\n        kd: {\n            get: function () {\n                return 0 !== (this.Qa & 16)\n            },\n            set: function (a) {\n                0 !== (this.Qa & 16) !== a && (this.Qa ^= 16)\n            }\n        },\n        suspendsRouting: {\n            get: function () {\n                return 0 !== (this.Qa & 32)\n            },\n            set: function (a) {\n                0 !== (this.Qa & 32) !== a && (this.Qa ^= 32)\n            }\n        },\n        jv: {\n            get: function () {\n                return 0 !== (this.Qa & 64)\n            },\n            set: function (a) {\n                0 !== (this.Qa & 64) !== a && (this.Qa ^= 64)\n            }\n        },\n        defaultFromPoint: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u = a.copy()\n            }\n        },\n        defaultToPoint: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I = a.copy()\n            }\n        },\n        isOrthogonal: {\n            get: function () {\n                return 2 === (this.Lj.value & 2)\n            }\n        },\n        isAvoiding: {\n            get: function () {\n                return 4 === (this.Lj.value & 4)\n            }\n        },\n        geometry: {\n            get: function () {\n                this.Yn && (this.hj(), this.ka = this.makeGeometry());\n                return this.ka\n            }\n        },\n        firstPickIndex: {\n            get: function () {\n                return 2 >= this.pointsCount ? 0 : this.isOrthogonal ||\n                    !np(this.computeSpot(!0)) ? 1 : 0\n            }\n        },\n        lastPickIndex: {\n            get: function () {\n                var a = this.pointsCount;\n                return 0 === a ? 0 : 2 >= a ? a - 1 : this.isOrthogonal || !np(this.computeSpot(!1)) ? a - 2 : a - 1\n            }\n        },\n        adjusting: {\n            get: function () {\n                return this.Dk\n            },\n            set: function (a) {\n                var b = this.Dk;\n                b !== a && (this.Dk = a, this.g(\"adjusting\", b, a))\n            }\n        },\n        corner: {\n            get: function () {\n                return this.pn\n            },\n            set: function (a) {\n                var b = this.pn;\n                b !== a && (this.pn = a, this.cc(), this.g(\"corner\", b, a))\n            }\n        },\n        curve: {\n            get: function () {\n                return this.rn\n            },\n            set: function (a) {\n                var b = this.rn;\n                b !== a && (this.rn = a, this.Oa(), this.cc(), mp(this, b === ag || b === $f || a === ag || a === $f), this.g(\"curve\", b, a))\n            }\n        },\n        curviness: {\n            get: function () {\n                return this.sn\n            },\n            set: function (a) {\n                var b = this.sn;\n                b !== a && (this.sn = a, this.Oa(), this.cc(), this.g(\"curviness\", b, a))\n            }\n        },\n        routing: {\n            get: function () {\n                return this.Lj\n            },\n            set: function (a) {\n                var b = this.Lj;\n                b !== a && (this.Lj = a, this.Tf = null, this.Oa(), mp(this, 2 === (b.value &\n                    2) || 2 === (a.value & 2)), this.g(\"routing\", b, a))\n            }\n        },\n        smoothness: {\n            get: function () {\n                return this.Ip\n            },\n            set: function (a) {\n                var b = this.Ip;\n                b !== a && (this.Ip = a, this.cc(), this.g(\"smoothness\", b, a))\n            }\n        },\n        key: {\n            get: function () {\n                var a = this.diagram;\n                if (null !== a && a.model.pm()) return a.model.Vb(this.data)\n            }\n        }\n    });\n    S.prototype.invalidateOtherJumpOvers = S.prototype.tq;\n    S.prototype.findClosestSegment = S.prototype.gz;\n    S.prototype.updateRoute = S.prototype.hj;\n    S.prototype.invalidateRoute = S.prototype.Oa;\n    S.prototype.rollbackRoute = S.prototype.ey;\n    S.prototype.commitRoute = S.prototype.rf;\n    S.prototype.startRoute = S.prototype.Nh;\n    S.prototype.clearPoints = S.prototype.Zj;\n    S.prototype.removePoint = S.prototype.Xv;\n    S.prototype.addPointAt = S.prototype.qf;\n    S.prototype.addPoint = S.prototype.xe;\n    S.prototype.insertPointAt = S.prototype.m;\n    S.prototype.insertPoint = S.prototype.Rz;\n    S.prototype.setPointAt = S.prototype.K;\n    S.prototype.setPoint = S.prototype.hd;\n    S.prototype.getPoint = S.prototype.i;\n    S.prototype.getOtherPort = S.prototype.Fz;\n    S.prototype.getOtherNode = S.prototype.pt;\n    var cp = new D(S, \"Normal\", 1),\n        Ip = new D(S, \"Orthogonal\", 2),\n        Jp = new D(S, \"AvoidsNodes\", 6),\n        sp = new D(S, \"AvoidsNodesStraight\", 7),\n        bg = new D(S, \"None\", 0),\n        qg = new D(S, \"Bezier\", 9),\n        ag = new D(S, \"JumpGap\", 10),\n        $f = new D(S, \"JumpOver\", 11),\n        dp = new D(S, \"End\", 17),\n        ep = new D(S, \"Scale\", 18),\n        fp = new D(S, \"Stretch\", 19),\n        In = new D(S, \"OrientAlong\", 21),\n        Nm = new D(S, \"OrientPlus90\", 22),\n        Pm = new D(S, \"OrientMinus90\", 23),\n        gp = new D(S, \"OrientOpposite\", 24),\n        hp = new D(S, \"OrientUpright\", 25),\n        Om = new D(S, \"OrientPlus90Upright\", 26),\n        Qm = new D(S, \"OrientMinus90Upright\",\n            27),\n        Rm = new D(S, \"OrientUpright45\", 28);\n    S.className = \"Link\";\n    S.Normal = cp;\n    S.Orthogonal = Ip;\n    S.AvoidsNodes = Jp;\n    S.AvoidsNodesStraight = sp;\n    S.None = bg;\n    S.Bezier = qg;\n    S.JumpGap = ag;\n    S.JumpOver = $f;\n    S.End = dp;\n    S.Scale = ep;\n    S.Stretch = fp;\n    S.OrientAlong = In;\n    S.OrientPlus90 = Nm;\n    S.OrientMinus90 = Pm;\n    S.OrientOpposite = gp;\n    S.OrientUpright = hp;\n    S.OrientPlus90Upright = Om;\n    S.OrientMinus90Upright = Qm;\n    S.OrientUpright45 = Rm;\n\n    function Hp(a, b, c, d) {\n        Ya(this);\n        this.ke = this.Nr = !1;\n        this.Bt = a;\n        this.Zx = b;\n        this.Mv = c;\n        this.$x = d;\n        this.links = []\n    }\n    Hp.prototype.nm = function () {\n        if (!this.Nr) {\n            var a = this.links;\n            0 < a.length && (a = a[0].diagram, null !== a && (a.su.add(this), this.ke = a.undoManager.isUndoingRedoing))\n        }\n        this.Nr = !0\n    };\n    Hp.prototype.uw = function () {\n        if (this.Nr) {\n            this.Nr = !1;\n            var a = this.links;\n            if (0 < a.length) {\n                var b = a[0],\n                    c = b.diagram;\n                c = null === c || c.kk && !this.ke;\n                this.ke = !1;\n                b.arrangeBundledLinks(a, c);\n                1 === a.length && (b.Kf = null, a.length = 0)\n            }\n            0 === a.length && (a = this.Bt, null !== this && null !== a.Me && a.Me.remove(this), a = this.Mv, null !== this && null !== a.Me && a.Me.remove(this))\n        }\n    };\n    Hp.className = \"LinkBundle\";\n\n    function tk() {\n        Ya(this);\n        this.oy = this.group = null;\n        this.st = !0;\n        this.abort = !1;\n        this.Nd = this.Md = 1;\n        this.xo = this.wo = -1;\n        this.lc = this.kc = 8;\n        this.Bb = [\n            []\n        ];\n        this.Sj = this.Rj = 0;\n        this.CA = !1;\n        this.vA = 22;\n        this.$z = 111\n    }\n    tk.prototype.initialize = function (a) {\n        if (!(0 >= a.width || 0 >= a.height)) {\n            var b = a.y,\n                c = a.x + a.width,\n                d = a.y + a.height;\n            this.Md = Math.floor((a.x - this.kc) / this.kc) * this.kc;\n            this.Nd = Math.floor((b - this.lc) / this.lc) * this.lc;\n            this.wo = Math.ceil((c + 2 * this.kc) / this.kc) * this.kc;\n            this.xo = Math.ceil((d + 2 * this.lc) / this.lc) * this.lc;\n            a = 1 + (Math.ceil((this.wo - this.Md) / this.kc) | 0);\n            b = 1 + (Math.ceil((this.xo - this.Nd) / this.lc) | 0);\n            if (null === this.Bb || this.Rj < a - 1 || this.Sj < b - 1) {\n                c = [];\n                for (d = 0; d <= a; d++) c[d] = [];\n                this.Bb = c;\n                this.Rj = a - 1;\n                this.Sj = b - 1\n            }\n            a =\n                Kp;\n            if (null !== this.Bb)\n                for (b = 0; b <= this.Rj; b++)\n                    for (c = 0; c <= this.Sj; c++) this.Bb[b][c] = a\n        }\n    };\n\n    function tp(a, b, c) {\n        return a.Md <= b && b <= a.wo && a.Nd <= c && c <= a.xo\n    }\n\n    function vp(a, b, c) {\n        if (!tp(a, b, c)) return Kp;\n        b -= a.Md;\n        b /= a.kc;\n        c -= a.Nd;\n        c /= a.lc;\n        return a.Bb[b | 0][c | 0]\n    }\n\n    function wk(a, b, c) {\n        tp(a, b, c) && (b -= a.Md, b /= a.kc, c -= a.Nd, c /= a.lc, a.Bb[b | 0][c | 0] = xp)\n    }\n\n    function vk(a) {\n        if (null !== a.Bb)\n            for (var b = 0; b <= a.Rj; b++)\n                for (var c = 0; c <= a.Sj; c++) a.Bb[b][c] >= zp && (a.Bb[b][c] = Kp)\n    }\n    tk.prototype.lk = function (a, b, c, d) {\n        if (a > this.wo || a + c < this.Md || b > this.xo || b + d < this.Nd) return !0;\n        a = (a - this.Md) / this.kc | 0;\n        b = (b - this.Nd) / this.lc | 0;\n        c = Math.max(0, c) / this.kc + 1 | 0;\n        var e = Math.max(0, d) / this.lc + 1 | 0;\n        0 > a && (c += a, a = 0);\n        0 > b && (e += b, b = 0);\n        if (0 > c || 0 > e) return !0;\n        d = Math.min(a + c - 1, this.Rj) | 0;\n        for (c = Math.min(b + e - 1, this.Sj) | 0; a <= d; a++)\n            for (e = b; e <= c; e++)\n                if (this.Bb[a][e] === xp) return !1;\n        return !0\n    };\n\n    function Lp(a, b, c, d, e, f, g, h, k) {\n        if (!(b < f || b > g || c < h || c > k)) {\n            var l = b | 0;\n            var m = c | 0;\n            var n = a.Bb[l][m];\n            if (n >= zp && n < wp)\n                for (e ? m += d : l += d, n += 1; f <= l && l <= g && h <= m && m <= k && !(n >= a.Bb[l][m]);) a.Bb[l][m] = n, n += 1, e ? m += d : l += d;\n            l = e ? m : l;\n            if (e)\n                if (0 < d)\n                    for (c += d; c < l; c += d) Lp(a, b, c, 1, !e, f, g, h, k), Lp(a, b, c, -1, !e, f, g, h, k);\n                else\n                    for (c += d; c > l; c += d) Lp(a, b, c, 1, !e, f, g, h, k), Lp(a, b, c, -1, !e, f, g, h, k);\n            else if (0 < d)\n                for (b += d; b < l; b += d) Lp(a, b, c, 1, !e, f, g, h, k), Lp(a, b, c, -1, !e, f, g, h, k);\n            else\n                for (b += d; b > l; b += d) Lp(a, b, c, 1, !e, f, g, h, k), Lp(a, b, c, -1, !e, f, g, h,\n                    k)\n        }\n    }\n\n    function Mp(a, b, c, d, e, f, g, h, k) {\n        b |= 0;\n        c |= 0;\n        var l = xp,\n            m = zp;\n        for (a.Bb[b][c] = m; l === xp && b > f && b < g && c > h && c < k;) m += 1, a.Bb[b][c] = m, e ? c += d : b += d, l = a.Bb[b][c]\n    }\n\n    function Np(a, b, c, d, e, f, g, h, k) {\n        b |= 0;\n        c |= 0;\n        var l = xp,\n            m = wp;\n        for (a.Bb[b][c] = m; l === xp && b > f && b < g && c > h && c < k;) a.Bb[b][c] = m, e ? c += d : b += d, l = a.Bb[b][c]\n    }\n\n    function up(a, b, c, d, e, f) {\n        if (null !== a.Bb) {\n            a.abort = !1;\n            var g = b.x,\n                h = b.y;\n            if (tp(a, g, h) && (g -= a.Md, g /= a.kc, h -= a.Nd, h /= a.lc, b = d.x, d = d.y, tp(a, b, d)))\n                if (b -= a.Md, b /= a.kc, d -= a.Nd, d /= a.lc, 1 >= Math.abs(g - b) && 1 >= Math.abs(h - d)) a.abort = !0;\n                else {\n                    var k = f.x,\n                        l = f.y,\n                        m = f.x + f.width,\n                        n = f.y + f.height;\n                    k -= a.Md;\n                    k /= a.kc;\n                    l -= a.Nd;\n                    l /= a.lc;\n                    m -= a.Md;\n                    m /= a.kc;\n                    n -= a.Nd;\n                    n /= a.lc;\n                    f = Math.max(0, Math.min(a.Rj, k | 0));\n                    m = Math.min(a.Rj, Math.max(0, m | 0));\n                    l = Math.max(0, Math.min(a.Sj, l | 0));\n                    n = Math.min(a.Sj, Math.max(0, n | 0));\n                    g |= 0;\n                    h |= 0;\n                    b |= 0;\n                    d |= 0;\n                    k = 0 === c || 90 === c ?\n                        1 : -1;\n                    c = 90 === c || 270 === c;\n                    a.Bb[g][h] === xp ? (Mp(a, g, h, k, c, f, m, l, n), Mp(a, g, h, 1, !c, f, m, l, n), Mp(a, g, h, -1, !c, f, m, l, n)) : Mp(a, g, h, k, c, g, h, g, h);\n                    a.Bb[b][d] === xp ? (Np(a, b, d, 0 === e || 90 === e ? 1 : -1, 90 === e || 270 === e, f, m, l, n), Np(a, b, d, 1, !(90 === e || 270 === e), f, m, l, n), Np(a, b, d, -1, !(90 === e || 270 === e), f, m, l, n)) : Np(a, b, d, k, c, b, d, b, d);\n                    a.abort || (Lp(a, g, h, 1, !1, f, m, l, n), Lp(a, g, h, -1, !1, f, m, l, n), Lp(a, g, h, 1, !0, f, m, l, n), Lp(a, g, h, -1, !0, f, m, l, n))\n                }\n        }\n    }\n    ma.Object.defineProperties(tk.prototype, {\n        bounds: {\n            get: function () {\n                return new N(this.Md, this.Nd, this.wo - this.Md, this.xo - this.Nd)\n            }\n        },\n        dm: {\n            get: function () {\n                return this.kc\n            },\n            set: function (a) {\n                0 < a && a !== this.kc && (this.kc = a, this.initialize(this.bounds))\n            }\n        },\n        cm: {\n            get: function () {\n                return this.lc\n            },\n            set: function (a) {\n                0 < a && a !== this.lc && (this.lc = a, this.initialize(this.bounds))\n            }\n        }\n    });\n    var xp = 0,\n        zp = 1,\n        wp = 999999,\n        Kp = wp + 1;\n    tk.className = \"PositionArray\";\n\n    function qp() {\n        Ya(this);\n        this.port = this.node = null;\n        this.Xd = [];\n        this.yq = !1\n    }\n    qp.prototype.toString = function () {\n        for (var a = this.Xd, b = this.node.toString() + \" \" + a.length.toString() + \":\", c = 0; c < a.length; c++) {\n            var d = a[c];\n            null !== d && (b += \"\\n  \" + d.toString())\n        }\n        return b\n    };\n\n    function Op(a, b, c, d) {\n        b = b.offsetY;\n        switch (b) {\n            case 8:\n                return 90;\n            case 2:\n                return 180;\n            case 1:\n                return 270;\n            case 4:\n                return 0\n        }\n        switch (b) {\n            case 9:\n                return 180 < c ? 270 : 90;\n            case 6:\n                return 90 < c && 270 >= c ? 180 : 0\n        }\n        a = 180 * Math.atan2(a.height, a.width) / Math.PI;\n        switch (b) {\n            case 3:\n                return c > a && c <= 180 + a ? 180 : 270;\n            case 5:\n                return c > 180 - a && c <= 360 - a ? 270 : 0;\n            case 12:\n                return c > a && c <= 180 + a ? 90 : 0;\n            case 10:\n                return c > 180 - a && c <= 360 - a ? 180 : 90;\n            case 7:\n                return 90 < c && c <= 180 + a ? 180 : c > 180 + a && c <= 360 - a ? 270 : 0;\n            case 13:\n                return 180 < c && c <= 360 - a ? 270 : c > a && 180 >= c ? 90 : 0;\n            case 14:\n                return c >\n                    a && c <= 180 - a ? 90 : c > 180 - a && 270 >= c ? 180 : 0;\n            case 11:\n                return c > 180 - a && c <= 180 + a ? 180 : c > 180 + a ? 270 : 90\n        }\n        d && 15 !== b && (c -= 15, 0 > c && (c += 360));\n        return c > a && c < 180 - a ? 90 : c >= 180 - a && c <= 180 + a ? 180 : c > 180 + a && c < 360 - a ? 270 : 0\n    }\n    qp.prototype.nm = function () {\n        this.Xd.length = 0\n    };\n\n    function rp(a, b) {\n        var c = a.Xd;\n        if (0 === c.length) {\n            a: if (!a.yq) {\n                c = a.yq;\n                a.yq = !0;\n                var d = null,\n                    e = a.node,\n                    f = e instanceof T ? e : null;\n                if (null === f || f.isSubGraphExpanded) var g = e.isTreeExpanded ? e.findLinksConnected(a.port.portId) : e.Jx();\n                else {\n                    if (!f.actualBounds.v()) {\n                        a.yq = c;\n                        break a\n                    }\n                    d = f;\n                    g = d.qv()\n                }\n                f = a.Xd.length = 0;\n                var h = a.port.ga(vc, I.alloc()),\n                    k = a.port.ga(Gc, I.alloc());\n                e = N.allocAt(h.x, h.y, 0, 0);\n                e.He(k);\n                I.free(h);\n                I.free(k);\n                h = I.allocAt(e.x + e.width / 2, e.y + e.height / 2);\n                k = a.port.Xi();\n                for (g = g.iterator; g.next();) {\n                    var l = g.value;\n                    if (l.isVisible() &&\n                        l.fromPort !== l.toPort) {\n                        var m = l.fromPort === a.port || null !== l.fromNode && l.fromNode.Wd(d),\n                            n = l.computeSpot(m, a.port);\n                        if (n.yf() && (m = m ? l.toPort : l.fromPort, null !== m)) {\n                            var p = m.part;\n                            if (null !== p) {\n                                var r = p.findVisibleNode();\n                                null !== r && r !== p && (p = r, m = p.port);\n                                m = l.computeOtherPoint(p, m);\n                                p = h.Ta(m);\n                                p -= k;\n                                0 > p && (p += 360);\n                                n = Op(e, n, p, l.isOrthogonal);\n                                0 === n ? (n = 4, 180 < p && (p -= 360)) : n = 90 === n ? 8 : 180 === n ? 2 : 1;\n                                r = a.Xd[f];\n                                void 0 === r ? (r = new Pp(l, p, n), a.Xd[f] = r) : (r.link = l, r.angle = p, r.yc = n);\n                                r.Qv.set(m);\n                                f++\n                            }\n                        }\n                    }\n                }\n                I.free(h);\n                a.Xd.sort(qp.prototype.l);\n                k = a.Xd.length;\n                d = -1;\n                for (f = h = 0; f < k; f++) g = a.Xd[f], void 0 !== g && (g.yc !== d && (d = g.yc, h = 0), g.pq = h, h++);\n                d = -1;\n                h = 0;\n                for (f = k - 1; 0 <= f; f--) k = a.Xd[f], void 0 !== k && (k.yc !== d && (d = k.yc, h = k.pq + 1), k.em = h);\n                f = a.Xd;\n                n = a.port;\n                d = a.node.portSpreading;\n                h = I.alloc();\n                k = I.alloc();\n                g = I.alloc();\n                l = I.alloc();\n                n.ga(vc, h);\n                n.ga(yc, k);\n                n.ga(Gc, g);\n                n.ga(Cc, l);\n                r = p = m = n = 0;\n                if (d === $o)\n                    for (var q = 0; q < f.length; q++) {\n                        var u = f[q];\n                        if (null !== u) {\n                            var v = u.link.computeThickness();\n                            switch (u.yc) {\n                                case 8:\n                                    p += v;\n                                    break;\n                                case 2:\n                                    r += v;\n                                    break;\n                                case 1:\n                                    n += v;\n                                    break;\n                                default:\n                                case 4:\n                                    m +=\n                                        v\n                            }\n                        }\n                    }\n                var w = q = 0,\n                    y = 1,\n                    z = u = 0;\n                for (v = 0; v < f.length; v++) {\n                    var A = f[v];\n                    if (null !== A) {\n                        if (q !== A.yc) {\n                            q = A.yc;\n                            switch (q) {\n                                case 8:\n                                    var C = g;\n                                    w = l;\n                                    break;\n                                case 2:\n                                    C = l;\n                                    w = h;\n                                    break;\n                                case 1:\n                                    C = h;\n                                    w = k;\n                                    break;\n                                default:\n                                case 4:\n                                    C = k, w = g\n                            }\n                            u = w.x - C.x;\n                            z = w.y - C.y;\n                            switch (q) {\n                                case 8:\n                                    p > Math.abs(u) ? (y = Math.abs(u) / p, p = Math.abs(u)) : y = 1;\n                                    break;\n                                case 2:\n                                    r > Math.abs(z) ? (y = Math.abs(z) / r, r = Math.abs(z)) : y = 1;\n                                    break;\n                                case 1:\n                                    n > Math.abs(u) ? (y = Math.abs(u) / n, n = Math.abs(u)) : y = 1;\n                                    break;\n                                default:\n                                case 4:\n                                    m > Math.abs(z) ? (y = Math.abs(z) / m, m = Math.abs(z)) : y = 1\n                            }\n                            w = 0\n                        }\n                        var G = A.wq;\n                        if (d === $o) {\n                            A =\n                                A.link.computeThickness();\n                            A *= y;\n                            G.set(C);\n                            switch (q) {\n                                case 8:\n                                    G.x = C.x + u / 2 + p / 2 - w - A / 2;\n                                    break;\n                                case 2:\n                                    G.y = C.y + z / 2 + r / 2 - w - A / 2;\n                                    break;\n                                case 1:\n                                    G.x = C.x + u / 2 - n / 2 + w + A / 2;\n                                    break;\n                                default:\n                                case 4:\n                                    G.y = C.y + z / 2 - m / 2 + w + A / 2\n                            }\n                            w += A\n                        } else {\n                            var L = .5;\n                            d === Mo && (L = (A.pq + 1) / (A.em + 1));\n                            G.x = C.x + u * L;\n                            G.y = C.y + z * L\n                        }\n                    }\n                }\n                I.free(h);\n                I.free(k);\n                I.free(g);\n                I.free(l);\n                C = a.Xd;\n                for (f = 0; f < C.length; f++) d = C[f], null !== d && (d.ov = a.computeEndSegmentLength(d));\n                a.yq = c;\n                N.free(e)\n            }c = a.Xd\n        }\n        for (a = 0; a < c.length; a++)\n            if (e = c[a], null !== e && e.link === b) return e;\n        return null\n    }\n    qp.prototype.l = function (a, b) {\n        return a === b ? 0 : null === a ? -1 : null === b ? 1 : a.yc < b.yc ? -1 : a.yc > b.yc ? 1 : a.angle < b.angle ? -1 : a.angle > b.angle ? 1 : 0\n    };\n    qp.prototype.computeEndSegmentLength = function (a) {\n        var b = a.link,\n            c = b.computeEndSegmentLength(this.node, this.port, uc, b.fromPort === this.port),\n            d = a.pq;\n        if (0 > d) return c;\n        var e = a.em;\n        if (1 >= e || !b.isOrthogonal) return c;\n        b = a.Qv;\n        var f = a.wq;\n        if (2 === a.yc || 8 === a.yc) d = e - 1 - d;\n        return ((a = 2 === a.yc || 4 === a.yc) ? b.y < f.y : b.x < f.x) ? c + 8 * d : (a ? b.y === f.y : b.x === f.x) ? c : c + 8 * (e - 1 - d)\n    };\n    qp.className = \"Knot\";\n\n    function Pp(a, b, c) {\n        this.link = a;\n        this.angle = b;\n        this.yc = c;\n        this.Qv = new I;\n        this.em = this.pq = 0;\n        this.wq = new I;\n        this.ov = 0\n    }\n    Pp.prototype.toString = function () {\n        return this.link.toString() + \" \" + this.angle.toString() + \" \" + this.yc.toString() + \":\" + this.pq.toString() + \"/\" + this.em.toString() + \" \" + this.wq.toString() + \" \" + this.ov.toString() + \" \" + this.Qv.toString()\n    };\n    Pp.className = \"LinkInfo\";\n\n    function dl() {\n        this.yh = this.Yg = Zc;\n        this.xh = this.Xg = this.wh = this.Wg = NaN;\n        this.Tp = this.Kn = null;\n        this.Up = this.Ln = Infinity\n    }\n    dl.prototype.copy = function () {\n        var a = new dl;\n        a.Yg = this.Yg.G();\n        a.yh = this.yh.G();\n        a.Wg = this.Wg;\n        a.wh = this.wh;\n        a.Xg = this.Xg;\n        a.xh = this.xh;\n        a.Kn = this.Kn;\n        a.Tp = this.Tp;\n        a.Ln = this.Ln;\n        a.Up = this.Up;\n        return a\n    };\n    dl.className = \"LinkSettings\";\n\n    function Ci() {\n        Ya(this);\n        this.I = this.B = null;\n        this.oi = this.ao = !0;\n        this.ho = !1;\n        this.Wm = (new I(0, 0)).freeze();\n        this.co = !0;\n        this.bo = null;\n        this.Qw = \"\";\n        this.u = null;\n        this.fo = !1;\n        this.l = null\n    }\n    Ci.prototype.cloneProtected = function (a) {\n        a.ao = this.ao;\n        a.oi = this.oi;\n        a.ho = this.ho;\n        a.Wm.assign(this.Wm);\n        a.co = this.co;\n        a.bo = this.bo;\n        a.Qw = this.Qw;\n        a.fo = !0\n    };\n    Ci.prototype.copy = function () {\n        var a = new this.constructor;\n        this.cloneProtected(a);\n        return a\n    };\n    Ci.prototype.cb = function () {};\n    Ci.prototype.toString = function () {\n        var a = Ia(this.constructor);\n        a += \"(\";\n        null !== this.group && (a += \" in \" + this.group);\n        null !== this.diagram && (a += \" for \" + this.diagram);\n        return a + \")\"\n    };\n    Ci.prototype.C = function () {\n        if (this.isValidLayout) {\n            var a = this.diagram;\n            if (null !== a && !a.undoManager.isUndoingRedoing) {\n                var b = a.animationManager;\n                !b.isTicking && (b.defaultAnimation.isAnimating && b.Xc(), this.isOngoing && a.kk || this.isInitial && !a.kk) && (this.isValidLayout = !1, a.Pb())\n            }\n        }\n    };\n    Ci.prototype.createNetwork = function () {\n        return new Qp(this)\n    };\n    Ci.prototype.makeNetwork = function (a) {\n        var b = this.createNetwork();\n        a instanceof R ? (b.xg(a.nodes, !0), b.xg(a.links, !0)) : a instanceof T ? b.xg(a.memberParts) : b.xg(a.iterator);\n        return b\n    };\n    Ci.prototype.updateParts = function () {\n        var a = this.diagram;\n        if (null === a && null !== this.network)\n            for (var b = this.network.vertexes.iterator; b.next();) {\n                var c = b.value.node;\n                if (null !== c && (a = c.diagram, null !== a)) break\n            }\n        this.isValidLayout = !0;\n        try {\n            null !== a && a.ua(\"Layout\"), this.commitLayout()\n        } finally {\n            null !== a && a.Ua(\"Layout\")\n        }\n    };\n    Ci.prototype.commitLayout = function () {\n        if (null !== this.network) {\n            for (var a = this.network.vertexes.iterator; a.next();) a.value.commit();\n            if (this.isRouting)\n                for (a = this.network.edges.iterator; a.next();) a.value.commit()\n        }\n    };\n    Ci.prototype.doLayout = function (a) {\n        var b = new F;\n        a instanceof R ? (Rp(this, b, a.nodes, !0, this.uk, !0, !1, !0), Rp(this, b, a.parts, !0, this.uk, !0, !1, !0)) : a instanceof T ? Rp(this, b, a.memberParts, !1, this.uk, !0, !1, !0) : b.addAll(a.iterator);\n        var c = b.count;\n        if (0 < c) {\n            a = this.diagram;\n            null !== a && a.ua(\"Layout\");\n            c = Math.ceil(Math.sqrt(c));\n            this.arrangementOrigin = this.initialOrigin(this.arrangementOrigin);\n            var d = this.arrangementOrigin.x,\n                e = d,\n                f = this.arrangementOrigin.y,\n                g = 0,\n                h = 0;\n            for (b = b.iterator; b.next();) {\n                var k = b.value;\n                Sp(k);\n                var l = k.measuredBounds,\n                    m = l.width;\n                l = l.height;\n                k.moveTo(e, f);\n                k instanceof T && (k.uk = !1);\n                e += Math.max(m, 50) + 20;\n                h = Math.max(h, Math.max(l, 50));\n                g >= c - 1 ? (g = 0, e = d, f += h + 20, h = 0) : g++\n            }\n            null !== a && a.Ua(\"Layout\")\n        }\n        this.isValidLayout = !0\n    };\n    Ci.prototype.uk = function (a) {\n        return !a.location.v() || a instanceof T && a.uk ? !0 : !1\n    };\n\n    function Rp(a, b, c, d, e, f, g, h) {\n        for (c = c.iterator; c.next();) {\n            var k = c.value;\n            d && !k.isTopLevel || null !== e && !e(k) || !k.canLayout() || (f && k instanceof W ? k.isLinkLabel || (k instanceof T ? null === k.layout ? Rp(a, b, k.memberParts, !1, e, f, g, h) : (Sp(k), b.add(k)) : (Sp(k), b.add(k))) : g && k instanceof S ? b.add(k) : !h || !k.Wb() || k instanceof W || (Sp(k), b.add(k)))\n        }\n    }\n\n    function Sp(a) {\n        var b = a.actualBounds;\n        (0 === b.width || 0 === b.height || isNaN(b.width) || isNaN(b.height)) && a.yb()\n    }\n    Ci.prototype.Zi = function (a, b) {\n        var c = this.boundsComputation;\n        if (null !== c) return b || (b = new N), c(a, this, b);\n        if (!b) return a.actualBounds;\n        b.set(a.actualBounds);\n        return b\n    };\n    Ci.prototype.yx = function (a) {\n        var b = new F;\n        a instanceof R ? (Rp(this, b, a.nodes, !0, null, !0, !0, !0), Rp(this, b, a.links, !0, null, !0, !0, !0), Rp(this, b, a.parts, !0, null, !0, !0, !0)) : a instanceof T ? Rp(this, b, a.memberParts, !1, null, !0, !0, !0) : Rp(this, b, a.iterator, !1, null, !0, !0, !0);\n        return b\n    };\n    Ci.prototype.initialOrigin = function (a) {\n        var b = this.group;\n        if (null !== b) {\n            var c = b.position.copy();\n            (isNaN(c.x) || isNaN(c.y)) && c.set(a);\n            b = b.placeholder;\n            null !== b && (c = b.ga(vc), (isNaN(c.x) || isNaN(c.y)) && c.set(a), a = b.padding, c.x += a.left, c.y += a.top);\n            return c\n        }\n        return a\n    };\n    ma.Object.defineProperties(Ci.prototype, {\n        diagram: {\n            get: function () {\n                return this.B\n            },\n            set: function (a) {\n                this.B = a\n            }\n        },\n        group: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I !== a && (this.I = a, null !== a && (this.B = a.diagram))\n            }\n        },\n        isOngoing: {\n            get: function () {\n                return this.ao\n            },\n            set: function (a) {\n                this.ao !== a && (this.ao = a)\n            }\n        },\n        isInitial: {\n            get: function () {\n                return this.oi\n            },\n            set: function (a) {\n                this.oi = a;\n                a || (this.fo = !0)\n            }\n        },\n        isViewportSized: {\n            get: function () {\n                return this.ho\n            },\n            set: function (a) {\n                this.ho !== a && (this.ho = a) && this.C()\n            }\n        },\n        isRouting: {\n            get: function () {\n                return this.co\n            },\n            set: function (a) {\n                this.co !== a && (this.co = a)\n            }\n        },\n        isRealtime: {\n            get: function () {\n                return this.bo\n            },\n            set: function (a) {\n                this.bo !== a && (this.bo = a)\n            }\n        },\n        isValidLayout: {\n            get: function () {\n                return this.fo\n            },\n            set: function (a) {\n                this.fo !== a && (this.fo = a, a || (a = this.diagram, null !==\n                    a && (a.If = !0)))\n            }\n        },\n        network: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l !== a && (this.l = a, null !== a && (a.layout = this))\n            }\n        },\n        boundsComputation: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u !== a && (this.u = a, this.C())\n            }\n        },\n        arrangementOrigin: {\n            get: function () {\n                return this.Wm\n            },\n            set: function (a) {\n                this.Wm.w(a) || (this.Wm.assign(a), this.C())\n            }\n        }\n    });\n    Ci.prototype.collectParts = Ci.prototype.yx;\n    Ci.prototype.getLayoutBounds = Ci.prototype.Zi;\n    Ci.prototype.invalidateLayout = Ci.prototype.C;\n    Ci.className = \"Layout\";\n\n    function Qp(a) {\n        Ya(this);\n        this.ic = a;\n        this.nf = new F;\n        this.de = new F;\n        this.Ct = new H;\n        this.xt = new H\n    }\n    Qp.prototype.clear = function () {\n        if (this.nf)\n            for (var a = this.nf.iterator; a.next();) a.value.clear();\n        if (this.de)\n            for (a = this.de.iterator; a.next();) a.value.clear();\n        this.nf = new F;\n        this.de = new F;\n        this.Ct = new H;\n        this.xt = new H\n    };\n    Qp.prototype.toString = function (a) {\n        void 0 === a && (a = 0);\n        var b = \"LayoutNetwork\" + (null !== this.layout ? \"(\" + this.layout.toString() + \")\" : \"\");\n        if (0 >= a) return b;\n        b += \" vertexes: \" + this.nf.count + \" edges: \" + this.de.count;\n        if (1 < a) {\n            for (var c = this.nf.iterator; c.next();) b += \"\\n    \" + c.value.toString(a - 1);\n            for (c = this.de.iterator; c.next();) b += \"\\n    \" + c.value.toString(a - 1)\n        }\n        return b\n    };\n    Qp.prototype.createVertex = function () {\n        return new Tp(this)\n    };\n    Qp.prototype.createEdge = function () {\n        return new Up(this)\n    };\n    Qp.prototype.xg = function (a, b, c) {\n        if (null !== a) {\n            void 0 === b && (b = !1);\n            void 0 === c && (c = null);\n            null === c && (c = function (a) {\n                if (a instanceof W) return !a.isLinkLabel;\n                if (a instanceof S) {\n                    var b = a.fromNode;\n                    if (null === b || b.isLinkLabel) return !1;\n                    a = a.toNode;\n                    return null === a || a.isLinkLabel ? !1 : !0\n                }\n                return !1\n            });\n            for (a = a.iterator; a.next();) {\n                var d = a.value;\n                if (d instanceof W && (!b || d.isTopLevel) && d.canLayout() && c(d))\n                    if (d instanceof T && null === d.layout) this.xg(d.memberParts, !1);\n                    else if (null === this.Wi(d)) {\n                    var e = this.createVertex();\n                    e.node =\n                        d;\n                    this.Eh(e)\n                }\n            }\n            for (a.reset(); a.next();)\n                if (d = a.value, d instanceof S && (!b || d.isTopLevel) && d.canLayout() && c(d) && null === this.kq(d)) {\n                    var f = d.fromNode;\n                    e = d.toNode;\n                    null !== f && null !== e && f !== e && (f = this.findGroupVertex(f), e = this.findGroupVertex(e), null !== f && null !== e && this.mk(f, e, d))\n                }\n        }\n    };\n    Qp.prototype.findGroupVertex = function (a) {\n        if (null === a) return null;\n        var b = a.findVisibleNode();\n        if (null === b) return null;\n        a = this.Wi(b);\n        if (null !== a) return a;\n        for (b = b.containingGroup; null !== b;) {\n            a = this.Wi(b);\n            if (null !== a) return a;\n            b = b.containingGroup\n        }\n        return null\n    };\n    t = Qp.prototype;\n    t.Eh = function (a) {\n        if (null !== a) {\n            this.nf.add(a);\n            var b = a.node;\n            null !== b && this.Ct.add(b, a);\n            a.network = this\n        }\n    };\n    t.am = function (a) {\n        if (null === a) return null;\n        var b = this.Wi(a);\n        null === b && (b = this.createVertex(), b.node = a, this.Eh(b));\n        return b\n    };\n    t.nv = function (a) {\n        if (null !== a && Vp(this, a)) {\n            for (var b = a.Gg, c = b.count - 1; 0 <= c; c--) {\n                var d = b.L(c);\n                this.ek(d)\n            }\n            b = a.yg;\n            for (a = b.count - 1; 0 <= a; a--) c = b.L(a), this.ek(c)\n        }\n    };\n\n    function Vp(a, b) {\n        if (null === b) return !1;\n        var c = a.nf.remove(b);\n        c && (b = b.node, null !== b && a.Ct.remove(b));\n        return c\n    }\n    t.az = function (a) {\n        null !== a && (a = this.Wi(a), null !== a && this.nv(a))\n    };\n    t.Wi = function (a) {\n        return null === a ? null : this.Ct.H(a)\n    };\n    t.bq = function (a) {\n        if (null !== a) {\n            Wp(this, a);\n            var b = a.toVertex;\n            null !== b && b.ev(a);\n            b = a.fromVertex;\n            null !== b && b.cv(a)\n        }\n    };\n\n    function Wp(a, b) {\n        if (null !== b) {\n            a.de.add(b);\n            var c = b.link;\n            null !== c && null === a.kq(c) && a.xt.add(c, b);\n            b.network = a\n        }\n    }\n    t.Hy = function (a) {\n        if (null === a) return null;\n        var b = a.fromNode,\n            c = a.toNode,\n            d = this.kq(a);\n        null === d ? (d = this.createEdge(), d.link = a, null !== b && (d.fromVertex = this.am(b)), null !== c && (d.toVertex = this.am(c)), this.bq(d)) : (null !== b ? d.fromVertex = this.am(b) : d.fromVertex = null, null !== c ? d.toVertex = this.am(c) : d.toVertex = null);\n        return d\n    };\n    t.ek = function (a) {\n        if (null !== a) {\n            var b = a.toVertex;\n            null !== b && b.mv(a);\n            b = a.fromVertex;\n            null !== b && b.lv(a);\n            Xp(this, a)\n        }\n    };\n\n    function Xp(a, b) {\n        null !== b && a.de.remove(b) && (b = b.link, null !== b && a.xt.remove(b))\n    }\n    t.$y = function (a) {\n        null !== a && (a = this.kq(a), null !== a && this.ek(a))\n    };\n    t.kq = function (a) {\n        return null === a ? null : this.xt.H(a)\n    };\n    t.mk = function (a, b, c) {\n        if (null === a || null === b) return null;\n        if (a.network === this && b.network === this) {\n            var d = this.createEdge();\n            d.link = c;\n            d.fromVertex = a;\n            d.toVertex = b;\n            this.bq(d);\n            return d\n        }\n        return null\n    };\n    t.Em = function (a) {\n        if (null !== a) {\n            var b = a.fromVertex,\n                c = a.toVertex;\n            null !== b && null !== c && (b.lv(a), c.mv(a), a.Em(), b.ev(a), c.cv(a))\n        }\n    };\n    t.iq = function () {\n        for (var a = Fa(), b = this.de.iterator; b.next();) {\n            var c = b.value;\n            c.fromVertex === c.toVertex && a.push(c)\n        }\n        b = a.length;\n        for (c = 0; c < b; c++) this.ek(a[c]);\n        Ha(a)\n    };\n    Qp.prototype.deleteArtificialVertexes = function () {\n        for (var a = Fa(), b = this.nf.iterator; b.next();) {\n            var c = b.value;\n            null === c.node && a.push(c)\n        }\n        c = a.length;\n        for (b = 0; b < c; b++) this.nv(a[b]);\n        b = Fa();\n        for (c = this.de.iterator; c.next();) {\n            var d = c.value;\n            null === d.link && b.push(d)\n        }\n        c = b.length;\n        for (d = 0; d < c; d++) this.ek(b[d]);\n        Ha(a);\n        Ha(b)\n    };\n\n    function Yp(a) {\n        for (var b = Fa(), c = a.de.iterator; c.next();) {\n            var d = c.value;\n            null !== d.fromVertex && null !== d.toVertex || b.push(d)\n        }\n        c = b.length;\n        for (d = 0; d < c; d++) a.ek(b[d]);\n        Ha(b)\n    }\n    Qp.prototype.py = function (a) {\n        void 0 === a && (a = !0);\n        a && (this.deleteArtificialVertexes(), Yp(this), this.iq());\n        a = new E;\n        for (var b = !0; b;) {\n            b = !1;\n            for (var c = this.nf.iterator; c.next();) {\n                var d = c.value;\n                if (0 < d.Gg.count || 0 < d.yg.count) {\n                    b = this.layout.createNetwork();\n                    a.add(b);\n                    Zp(this, b, d);\n                    b = !0;\n                    break\n                }\n            }\n        }\n        a.sort(function (a, b) {\n            return null === a || null === b || a === b ? 0 : b.vertexes.count - a.vertexes.count\n        });\n        return a\n    };\n\n    function Zp(a, b, c) {\n        if (null !== c && c.network !== b) {\n            Vp(a, c);\n            b.Eh(c);\n            for (var d = c.sourceEdges; d.next();) {\n                var e = d.value;\n                e.network !== b && (Xp(a, e), Wp(b, e), Zp(a, b, e.fromVertex))\n            }\n            for (d = c.destinationEdges; d.next();) c = d.value, c.network !== b && (Xp(a, c), Wp(b, c), Zp(a, b, c.toVertex))\n        }\n    }\n    Qp.prototype.fz = function () {\n        for (var a = new F, b = this.nf.iterator; b.next();) a.add(b.value.node);\n        for (b = this.de.iterator; b.next();) a.add(b.value.link);\n        return a\n    };\n    ma.Object.defineProperties(Qp.prototype, {\n        layout: {\n            get: function () {\n                return this.ic\n            },\n            set: function (a) {\n                null !== a && (this.ic = a)\n            }\n        },\n        vertexes: {\n            get: function () {\n                return this.nf\n            }\n        },\n        edges: {\n            get: function () {\n                return this.de\n            }\n        }\n    });\n    Qp.prototype.findAllParts = Qp.prototype.fz;\n    Qp.prototype.splitIntoSubNetworks = Qp.prototype.py;\n    Qp.prototype.deleteSelfEdges = Qp.prototype.iq;\n    Qp.prototype.reverseEdge = Qp.prototype.Em;\n    Qp.prototype.linkVertexes = Qp.prototype.mk;\n    Qp.prototype.findEdge = Qp.prototype.kq;\n    Qp.prototype.deleteLink = Qp.prototype.$y;\n    Qp.prototype.deleteEdge = Qp.prototype.ek;\n    Qp.prototype.addLink = Qp.prototype.Hy;\n    Qp.prototype.addEdge = Qp.prototype.bq;\n    Qp.prototype.findVertex = Qp.prototype.Wi;\n    Qp.prototype.deleteNode = Qp.prototype.az;\n    Qp.prototype.deleteVertex = Qp.prototype.nv;\n    Qp.prototype.addNode = Qp.prototype.am;\n    Qp.prototype.addVertex = Qp.prototype.Eh;\n    Qp.prototype.addParts = Qp.prototype.xg;\n    Qp.className = \"LayoutNetwork\";\n\n    function Tp(a) {\n        Ya(this);\n        this.Yc = a;\n        this.l = (new N(0, 0, 10, 10)).freeze();\n        this.u = (new I(5, 5)).freeze();\n        this.zi = this.hb = null;\n        this.Gg = new E;\n        this.yg = new E\n    }\n    Tp.prototype.clear = function () {\n        this.zi = this.hb = null;\n        this.Gg = new E;\n        this.yg = new E\n    };\n    Tp.prototype.toString = function (a) {\n        void 0 === a && (a = 0);\n        var b = \"LayoutVertex#\" + lb(this);\n        if (0 < a && (b += null !== this.node ? \"(\" + this.node.toString() + \")\" : \"\", 1 < a)) {\n            a = \"\";\n            for (var c = !0, d = this.Gg.iterator; d.next();) {\n                var e = d.value;\n                c ? c = !1 : a += \",\";\n                a += e.toString(0)\n            }\n            e = \"\";\n            c = !0;\n            for (d = this.yg.iterator; d.next();) {\n                var f = d.value;\n                c ? c = !1 : e += \",\";\n                e += f.toString(0)\n            }\n            b += \" sources: \" + a + \" destinations: \" + e\n        }\n        return b\n    };\n    Tp.prototype.commit = function () {\n        var a = this.hb;\n        if (null !== a) {\n            var b = this.bounds,\n                c = a.bounds;\n            za(c) ? (c.x = b.x, c.y = b.y, c.width = b.width, c.height = b.height) : a.bounds = b.copy()\n        } else if (a = this.node, null !== a) {\n            b = this.bounds;\n            if (!(a instanceof T)) {\n                c = N.alloc();\n                var d = this.network.layout.Zi(a, c),\n                    e = a.locationObject.ga(Ac);\n                if (d.v() && e.v()) {\n                    a.moveTo(b.x + this.focusX - (e.x - d.x), b.y + this.focusY - (e.y - d.y));\n                    N.free(c);\n                    return\n                }\n                N.free(c)\n            }\n            a.moveTo(b.x, b.y)\n        }\n    };\n    Tp.prototype.ev = function (a) {\n        null !== a && (this.Gg.contains(a) || this.Gg.add(a))\n    };\n    Tp.prototype.mv = function (a) {\n        null !== a && this.Gg.remove(a)\n    };\n    Tp.prototype.cv = function (a) {\n        null !== a && (this.yg.contains(a) || this.yg.add(a))\n    };\n    Tp.prototype.lv = function (a) {\n        null !== a && this.yg.remove(a)\n    };\n\n    function $p(a, b) {\n        a = a.zi;\n        b = b.zi;\n        return a ? b ? (a = a.text, b = b.text, a < b ? -1 : a > b ? 1 : 0) : 1 : null !== b ? -1 : 0\n    }\n    ma.Object.defineProperties(Tp.prototype, {\n        sourceEdgesArrayAccess: {\n            get: function () {\n                return this.Gg._dataArray\n            }\n        },\n        destinationEdgesArrayAccess: {\n            get: function () {\n                return this.yg._dataArray\n            }\n        },\n        data: {\n            get: function () {\n                return this.hb\n            },\n            set: function (a) {\n                this.hb = a;\n                if (null !== a) {\n                    var b = a.bounds;\n                    a = b.x;\n                    var c = b.y,\n                        d = b.width;\n                    b = b.height;\n                    this.u.h(d / 2, b / 2);\n                    this.l.h(a, c, d, b)\n                }\n            }\n        },\n        node: {\n            get: function () {\n                return this.zi\n            },\n            set: function (a) {\n                if (this.zi !== a) {\n                    this.zi = a;\n                    a.yb();\n                    var b = this.network.layout,\n                        c = N.alloc(),\n                        d = b.Zi(a, c);\n                    b = d.x;\n                    var e = d.y,\n                        f = d.width;\n                    d = d.height;\n                    isNaN(b) && (b = 0);\n                    isNaN(e) && (e = 0);\n                    this.l.h(b, e, f, d);\n                    N.free(c);\n                    if (!(a instanceof T) && (a = a.locationObject.ga(Ac), a.v())) {\n                        this.u.h(a.x - b, a.y - e);\n                        return\n                    }\n                    this.u.h(f / 2, d / 2)\n                }\n            }\n        },\n        bounds: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l.w(a) || this.l.assign(a)\n            }\n        },\n        focus: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u.w(a) ||\n                    this.u.assign(a)\n            }\n        },\n        centerX: {\n            get: function () {\n                return this.l.x + this.u.x\n            },\n            set: function (a) {\n                var b = this.l;\n                b.x + this.u.x !== a && (b.ea(), b.x = a - this.u.x, b.freeze())\n            }\n        },\n        centerY: {\n            get: function () {\n                return this.l.y + this.u.y\n            },\n            set: function (a) {\n                var b = this.l;\n                b.y + this.u.y !== a && (b.ea(), b.y = a - this.u.y, b.freeze())\n            }\n        },\n        focusX: {\n            get: function () {\n                return this.u.x\n            },\n            set: function (a) {\n                var b = this.u;\n                b.x !== a && (b.ea(), b.x = a, b.freeze())\n            }\n        },\n        focusY: {\n            get: function () {\n                return this.u.y\n            },\n            set: function (a) {\n                var b = this.u;\n                b.y !== a && (b.ea(), b.y = a, b.freeze())\n            }\n        },\n        x: {\n            get: function () {\n                return this.l.x\n            },\n            set: function (a) {\n                var b = this.l;\n                b.x !== a && (b.ea(), b.x = a, b.freeze())\n            }\n        },\n        y: {\n            get: function () {\n                return this.l.y\n            },\n            set: function (a) {\n                var b = this.l;\n                b.y !== a && (b.ea(), b.y = a, b.freeze())\n            }\n        },\n        width: {\n            get: function () {\n                return this.l.width\n            },\n            set: function (a) {\n                var b = this.l;\n                b.width !== a && (b.ea(), b.width =\n                    a, b.freeze())\n            }\n        },\n        height: {\n            get: function () {\n                return this.l.height\n            },\n            set: function (a) {\n                var b = this.l;\n                b.height !== a && (b.ea(), b.height = a, b.freeze())\n            }\n        },\n        network: {\n            get: function () {\n                return this.Yc\n            },\n            set: function (a) {\n                this.Yc = a\n            }\n        },\n        sourceVertexes: {\n            get: function () {\n                for (var a = new F, b = this.sourceEdges; b.next();) a.add(b.value.fromVertex);\n                return a.iterator\n            }\n        },\n        destinationVertexes: {\n            get: function () {\n                for (var a = new F, b =\n                        this.destinationEdges; b.next();) a.add(b.value.toVertex);\n                return a.iterator\n            }\n        },\n        vertexes: {\n            get: function () {\n                for (var a = new F, b = this.sourceEdges; b.next();) a.add(b.value.fromVertex);\n                for (b = this.destinationEdges; b.next();) a.add(b.value.toVertex);\n                return a.iterator\n            }\n        },\n        sourceEdges: {\n            get: function () {\n                return this.Gg.iterator\n            }\n        },\n        destinationEdges: {\n            get: function () {\n                return this.yg.iterator\n            }\n        },\n        edges: {\n            get: function () {\n                for (var a =\n                        new E, b = this.sourceEdges; b.next();) a.add(b.value);\n                for (b = this.destinationEdges; b.next();) a.add(b.value);\n                return a.iterator\n            }\n        },\n        edgesCount: {\n            get: function () {\n                return this.Gg.count + this.yg.count\n            }\n        }\n    });\n    Tp.prototype.deleteDestinationEdge = Tp.prototype.lv;\n    Tp.prototype.addDestinationEdge = Tp.prototype.cv;\n    Tp.prototype.deleteSourceEdge = Tp.prototype.mv;\n    Tp.prototype.addSourceEdge = Tp.prototype.ev;\n    Tp.className = \"LayoutVertex\";\n    Tp.standardComparer = $p;\n    Tp.smartComparer = function (a, b) {\n        if (null !== a) {\n            if (null !== b) {\n                a = a.zi;\n                var c = b.zi;\n                if (null !== a) {\n                    if (null !== c) {\n                        b = a.text.toLocaleLowerCase().split(/([+\\-]?[\\.]?\\d+(?:\\.\\d*)?(?:e[+\\-]?\\d+)?)/);\n                        a = c.text.toLocaleLowerCase().split(/([+\\-]?[\\.]?\\d+(?:\\.\\d*)?(?:e[+\\-]?\\d+)?)/);\n                        for (c = 0; c < b.length; c++)\n                            if (\"\" !== a[c] && void 0 !== a[c]) {\n                                var d = parseFloat(b[c]),\n                                    e = parseFloat(a[c]);\n                                if (isNaN(d))\n                                    if (isNaN(e)) {\n                                        if (0 !== b[c].localeCompare(a[c])) return b[c].localeCompare(a[c])\n                                    } else return 1;\n                                else {\n                                    if (isNaN(e)) return -1;\n                                    if (0 !== d - e) return d -\n                                        e\n                                }\n                            } else if (\"\" !== b[c]) return 1;\n                        return \"\" !== a[c] && void 0 !== a[c] ? -1 : 0\n                    }\n                    return 1\n                }\n                return null !== c ? -1 : 0\n            }\n            return 1\n        }\n        return null !== b ? -1 : 0\n    };\n\n    function Up(a) {\n        Ya(this);\n        this.jd = a;\n        this.tg = this.Vf = this.ul = this.hb = null\n    }\n    Up.prototype.clear = function () {\n        this.tg = this.Vf = this.ul = this.hb = null\n    };\n    Up.prototype.toString = function (a) {\n        void 0 === a && (a = 0);\n        var b = \"LayoutEdge#\" + lb(this);\n        0 < a && (b += null !== this.ul ? \"(\" + this.ul.toString() + \")\" : \"\", 1 < a && (b += \" \" + (this.Vf ? this.Vf.toString() : \"null\") + \" --\\x3e \" + (this.tg ? this.tg.toString() : \"null\")));\n        return b\n    };\n    Up.prototype.Em = function () {\n        var a = this.Vf;\n        this.Vf = this.tg;\n        this.tg = a\n    };\n    Up.prototype.commit = function () {};\n    Up.prototype.Qx = function (a) {\n        return this.tg === a ? this.Vf : this.Vf === a ? this.tg : null\n    };\n    ma.Object.defineProperties(Up.prototype, {\n        network: {\n            get: function () {\n                return this.jd\n            },\n            set: function (a) {\n                this.jd = a\n            }\n        },\n        data: {\n            get: function () {\n                return this.hb\n            },\n            set: function (a) {\n                this.hb !== a && (this.hb = a)\n            }\n        },\n        link: {\n            get: function () {\n                return this.ul\n            },\n            set: function (a) {\n                this.ul !== a && (this.ul = a)\n            }\n        },\n        fromVertex: {\n            get: function () {\n                return this.Vf\n            },\n            set: function (a) {\n                this.Vf !== a && (this.Vf = a)\n            }\n        },\n        toVertex: {\n            get: function () {\n                return this.tg\n            },\n            set: function (a) {\n                this.tg !== a && (this.tg = a)\n            }\n        }\n    });\n    Up.prototype.getOtherVertex = Up.prototype.Qx;\n    Up.className = \"LayoutEdge\";\n\n    function Lk() {\n        Ci.call(this);\n        this.isViewportSized = !0;\n        this.Zp = this.$p = NaN;\n        this.Ng = (new M(NaN, NaN)).freeze();\n        this.ef = (new M(10, 10)).freeze();\n        this.vb = aq;\n        this.Ab = bq;\n        this.Qc = cq;\n        this.Kc = dq\n    }\n    la(Lk, Ci);\n    Lk.prototype.cloneProtected = function (a) {\n        Ci.prototype.cloneProtected.call(this, a);\n        a.$p = this.$p;\n        a.Zp = this.Zp;\n        a.Ng.assign(this.Ng);\n        a.ef.assign(this.ef);\n        a.vb = this.vb;\n        a.Ab = this.Ab;\n        a.Qc = this.Qc;\n        a.Kc = this.Kc\n    };\n    Lk.prototype.cb = function (a) {\n        a.classType === Lk ? a === cq || a === eq || a === fq || a === gq ? this.sorting = a : a === bq || a === hq ? this.arrangement = a : a === aq || a === iq ? this.alignment = a : B(\"Unknown enum value: \" + a) : Ci.prototype.cb.call(this, a)\n    };\n    Lk.prototype.doLayout = function (a) {\n        this.arrangementOrigin = this.initialOrigin(this.arrangementOrigin);\n        var b = this.yx(a);\n        a = this.diagram;\n        for (var c = b.copy().iterator; c.next();) {\n            var d = c.value;\n            if (!d.Kh() || null === d.fromNode && null === d.toNode) {\n                if (d.yb(), d instanceof T)\n                    for (d = d.memberParts; d.next();) b.remove(d.value)\n            } else b.remove(d)\n        }\n        var e = b.na();\n        if (0 !== e.length) {\n            switch (this.sorting) {\n                case gq:\n                    e.reverse();\n                    break;\n                case cq:\n                    e.sort(this.comparer);\n                    break;\n                case eq:\n                    e.sort(this.comparer), e.reverse()\n            }\n            var f = this.wrappingColumn;\n            isNaN(f) && (f = 0);\n            var g = this.wrappingWidth;\n            isNaN(g) && null !== a ? (b = a.padding, g = Math.max(a.viewportBounds.width - b.left - b.right, 0)) : g = Math.max(this.wrappingWidth, 0);\n            0 >= f && 0 >= g && (f = 1);\n            b = this.spacing.width;\n            isFinite(b) || (b = 0);\n            c = this.spacing.height;\n            isFinite(c) || (c = 0);\n            null !== a && a.ua(\"Layout\");\n            d = [];\n            switch (this.alignment) {\n                case iq:\n                    var h = b,\n                        k = c,\n                        l = N.alloc(),\n                        m = Math.max(this.cellSize.width, 1);\n                    if (!isFinite(m))\n                        for (var n = m = 0; n < e.length; n++) {\n                            var p = this.Zi(e[n], l);\n                            m = Math.max(m, p.width)\n                        }\n                    m = Math.max(m + h, 1);\n                    n = Math.max(this.cellSize.height,\n                        1);\n                    if (!isFinite(n))\n                        for (p = n = 0; p < e.length; p++) {\n                            var r = this.Zi(e[p], l);\n                            n = Math.max(n, r.height)\n                        }\n                    n = Math.max(n + k, 1);\n                    p = this.arrangement;\n                    for (var q = r = this.arrangementOrigin.x, u = this.arrangementOrigin.y, v = 0, w = 0, y = 0; y < e.length; y++) {\n                        var z = e[y],\n                            A = this.Zi(z, l),\n                            C = Math.ceil((A.width + h) / m) * m,\n                            G = Math.ceil((A.height + k) / n) * n;\n                        switch (p) {\n                            case hq:\n                                var L = Math.abs(q - A.width);\n                                break;\n                            default:\n                                L = q + A.width\n                        }\n                        if (0 < f && v > f - 1 || 0 < g && 0 < v && L - r > g) d.push(new N(0, u, g + h, w)), v = 0, q = r, u += w, w = 0;\n                        w = Math.max(w, G);\n                        switch (p) {\n                            case hq:\n                                A = -A.width;\n                                break;\n                            default:\n                                A =\n                                    0\n                        }\n                        z.moveTo(q + A, u);\n                        switch (p) {\n                            case hq:\n                                q -= C;\n                                break;\n                            default:\n                                q += C\n                        }\n                        v++\n                    }\n                    d.push(new N(0, u, g + h, w));\n                    N.free(l);\n                    break;\n                case aq:\n                    k = g;\n                    m = f;\n                    n = b;\n                    p = c;\n                    g = N.alloc();\n                    r = Math.max(this.cellSize.width, 1);\n                    f = u = l = 0;\n                    h = I.alloc();\n                    for (q = 0; q < e.length; q++) w = e[q], v = this.Zi(w, g), w = w.vf(w.locationObject, w.locationSpot, h), l = Math.max(l, w.x), u = Math.max(u, v.width - w.x), f = Math.max(f, w.y);\n                    q = this.arrangement;\n                    switch (q) {\n                        case hq:\n                            l += n;\n                            break;\n                        default:\n                            u += n\n                    }\n                    r = isFinite(r) ? Math.max(r + n, 1) : Math.max(l + u, 1);\n                    var K = w = this.arrangementOrigin.x;\n                    y = this.arrangementOrigin.y;\n                    u = 0;\n                    k >= l && (k -= l);\n                    l = z = 0;\n                    C = Math.max(this.cellSize.height, 1);\n                    A = f = 0;\n                    G = !0;\n                    v = I.alloc();\n                    for (L = 0; L < e.length; L++) {\n                        var V = e[L],\n                            Q = this.Zi(V, g),\n                            ca = V.vf(V.locationObject, V.locationSpot, h);\n                        if (0 < u) switch (q) {\n                            case hq:\n                                K = (K - w - (Q.width - ca.x)) / r;\n                                K = J.$(Math.round(K), K) ? Math.round(K) : Math.floor(K);\n                                K = K * r + w;\n                                break;\n                            default:\n                                K = (K - w + ca.x) / r, K = J.$(Math.round(K), K) ? Math.round(K) : Math.ceil(K), K = K * r + w\n                        } else switch (q) {\n                            case hq:\n                                z = K + ca.x + Q.width;\n                                break;\n                            default:\n                                z = K - ca.x\n                        }\n                        switch (q) {\n                            case hq:\n                                var pa = -(K + ca.x) + z;\n                                break;\n                            default:\n                                pa = K + Q.width - ca.x -\n                                    z\n                        }\n                        if (0 < m && u > m - 1 || 0 < k && 0 < u && pa > k) {\n                            d.push(new N(0, G ? y - f : y, k + n, A + f + p));\n                            for (K = 0; K < u && L !== u; K++) {\n                                pa = e[L - u + K];\n                                var O = pa.vf(pa.locationObject, pa.locationSpot, v);\n                                pa.moveTo(pa.position.x, pa.position.y + f - O.y)\n                            }\n                            A += p;\n                            y = G ? y + A : y + (A + f);\n                            u = A = f = 0;\n                            K = w;\n                            G = !1\n                        }\n                        K === w && (l = q === hq ? Math.max(l, Q.width - ca.x) : Math.min(l, -ca.x));\n                        f = Math.max(f, ca.y);\n                        A = Math.max(A, Q.height - ca.y);\n                        isFinite(C) && (A = Math.max(A, Math.max(Q.height, C) - ca.y));\n                        G ? V.moveTo(K - ca.x, y - ca.y) : V.moveTo(K - ca.x, y);\n                        switch (q) {\n                            case hq:\n                                K -= ca.x + n;\n                                break;\n                            default:\n                                K += Q.width - ca.x +\n                                    n\n                        }\n                        u++\n                    }\n                    d.push(new N(0, y, k + n, (G ? A : A + f) + p));\n                    if (e.length !== u)\n                        for (k = 0; k < u; k++) m = e[e.length - u + k], n = m.vf(m.locationObject, m.locationSpot, h), m.moveTo(m.position.x, m.position.y + f - n.y);\n                    I.free(h);\n                    I.free(v);\n                    if (q === hq)\n                        for (e = 0; e < d.length; e++) f = d[e], f.width += l, f.x -= l;\n                    else\n                        for (e = 0; e < d.length; e++) f = d[e], f.x > l && (f.width += f.x - l, f.x = l);\n                    N.free(g)\n            }\n            for (h = f = g = e = 0; h < d.length; h++) k = d[h], e = Math.min(e, k.x), g = Math.min(g, k.y), f = Math.max(f, k.x + k.width);\n            this.arrangement === hq ? this.commitLayers(d, new I(e + b / 2 - (f + e), g - c / 2)) : this.commitLayers(d,\n                new I(e - b / 2, g - c / 2));\n            null !== a && a.Ua(\"Layout\");\n            this.isValidLayout = !0\n        }\n    };\n    Lk.prototype.commitLayers = function () {};\n\n    function dq(a, b) {\n        a = a.text;\n        b = b.text;\n        return a < b ? -1 : a > b ? 1 : 0\n    }\n    ma.Object.defineProperties(Lk.prototype, {\n        wrappingWidth: {\n            get: function () {\n                return this.$p\n            },\n            set: function (a) {\n                this.$p !== a && (0 < a || isNaN(a)) && (this.$p = a, this.isViewportSized = isNaN(a), this.C())\n            }\n        },\n        wrappingColumn: {\n            get: function () {\n                return this.Zp\n            },\n            set: function (a) {\n                this.Zp !== a && (0 < a || isNaN(a)) && (this.Zp = a, this.C())\n            }\n        },\n        cellSize: {\n            get: function () {\n                return this.Ng\n            },\n            set: function (a) {\n                this.Ng.w(a) || (this.Ng.assign(a), this.C())\n            }\n        },\n        spacing: {\n            get: function () {\n                return this.ef\n            },\n            set: function (a) {\n                this.ef.w(a) || (this.ef.assign(a), this.C())\n            }\n        },\n        alignment: {\n            get: function () {\n                return this.vb\n            },\n            set: function (a) {\n                this.vb === a || a !== aq && a !== iq || (this.vb = a, this.C())\n            }\n        },\n        arrangement: {\n            get: function () {\n                return this.Ab\n            },\n            set: function (a) {\n                this.Ab === a || a !== bq && a !== hq || (this.Ab = a, this.C())\n            }\n        },\n        sorting: {\n            get: function () {\n                return this.Qc\n            },\n            set: function (a) {\n                this.Qc === a || a !== fq && a !== gq &&\n                    a !== cq && a !== eq || (this.Qc = a, this.C())\n            }\n        },\n        comparer: {\n            get: function () {\n                return this.Kc\n            },\n            set: function (a) {\n                this.Kc !== a && (this.Kc = a, this.C())\n            }\n        }\n    });\n    var iq = new D(Lk, \"Position\", 0),\n        aq = new D(Lk, \"Location\", 1),\n        bq = new D(Lk, \"LeftToRight\", 2),\n        hq = new D(Lk, \"RightToLeft\", 3),\n        fq = new D(Lk, \"Forward\", 4),\n        gq = new D(Lk, \"Reverse\", 5),\n        cq = new D(Lk, \"Ascending\", 6),\n        eq = new D(Lk, \"Descending\", 7);\n    Lk.className = \"GridLayout\";\n    Lk.standardComparer = dq;\n    Lk.smartComparer = function (a, b) {\n        if (null !== a) {\n            if (null !== b) {\n                a = a.text.toLocaleLowerCase().split(/([+\\-]?[\\.]?\\d+(?:\\.\\d*)?(?:e[+\\-]?\\d+)?)/);\n                b = b.text.toLocaleLowerCase().split(/([+\\-]?[\\.]?\\d+(?:\\.\\d*)?(?:e[+\\-]?\\d+)?)/);\n                for (var c = 0; c < a.length; c++)\n                    if (\"\" !== b[c] && void 0 !== b[c]) {\n                        var d = parseFloat(a[c]),\n                            e = parseFloat(b[c]);\n                        if (isNaN(d))\n                            if (isNaN(e)) {\n                                if (0 !== a[c].localeCompare(b[c])) return a[c].localeCompare(b[c])\n                            } else return 1;\n                        else {\n                            if (isNaN(e)) return -1;\n                            if (0 !== d - e) return d - e\n                        }\n                    } else if (\"\" !== a[c]) return 1;\n                return \"\" !==\n                    b[c] && void 0 !== b[c] ? -1 : 0\n            }\n            return 1\n        }\n        return null !== b ? -1 : 0\n    };\n    Lk.Position = iq;\n    Lk.Location = aq;\n    Lk.LeftToRight = bq;\n    Lk.RightToLeft = hq;\n    Lk.Forward = fq;\n    Lk.Reverse = gq;\n    Lk.Ascending = cq;\n    Lk.Descending = eq;\n\n    function ri() {\n        this.So = new F;\n        this.so = new F;\n        this.Ca = new F;\n        this.Oe = new H;\n        this.Ne = new H;\n        this.yj = new H;\n        this.B = null;\n        this.Tq = !1\n    }\n    t = ri.prototype;\n    t.clear = function () {\n        this.So.clear();\n        this.so.clear();\n        this.Ca.clear();\n        this.Oe.clear();\n        this.Ne.clear();\n        this.yj.clear()\n    };\n    t.Yd = function (a) {\n        this.B = a\n    };\n    t.aj = function (a) {\n        if (a instanceof W) {\n            if (this.So.add(a), a instanceof T) {\n                var b = a.containingGroup;\n                null === b ? this.B.zh.add(a) : b.zl.add(a);\n                b = a.layout;\n                null !== b && (b.diagram = this.B)\n            }\n        } else a instanceof S ? this.so.add(a) : a instanceof Je || this.Ca.add(a);\n        b = a.data;\n        null === b || a instanceof Je || (a instanceof S ? this.Ne.add(b, a) : this.Oe.add(b, a))\n    };\n    t.Fc = function (a) {\n        a.Yj();\n        if (a instanceof W) {\n            if (this.So.remove(a), a instanceof T) {\n                var b = a.containingGroup;\n                null === b ? this.B.zh.remove(a) : b.zl.remove(a);\n                b = a.layout;\n                null !== b && (b.diagram = null)\n            }\n        } else a instanceof S ? this.so.remove(a) : a instanceof Je || this.Ca.remove(a);\n        b = a.data;\n        null === b || a instanceof Je || (a instanceof S ? this.Ne.remove(b) : this.Oe.remove(b))\n    };\n    t.xd = function () {\n        for (var a = this.B.nodeTemplateMap.iterator; a.next();) {\n            var b = a.value,\n                c = a.key;\n            (!b.Wb() || b instanceof T) && B('Invalid node template in Diagram.nodeTemplateMap: template for \"' + c + '\" must be a Node or a simple Part, not a Group or Link: ' + b)\n        }\n        for (a = this.B.groupTemplateMap.iterator; a.next();) b = a.value, c = a.key, b instanceof T || B('Invalid group template in Diagram.groupTemplateMap: template for \"' + c + '\" must be a Group, not a normal Node or Link: ' + b);\n        for (a = this.B.linkTemplateMap.iterator; a.next();) b =\n            a.value, c = a.key, b instanceof S || B('Invalid link template in Diagram.linkTemplateMap: template for \"' + c + '\" must be a Link, not a normal Node or simple Part: ' + b);\n        a = Fa();\n        for (b = this.B.selection.iterator; b.next();)(c = b.value.data) && a.push(c);\n        b = Fa();\n        for (c = this.B.highlighteds.iterator; c.next();) {\n            var d = c.value.data;\n            d && b.push(d)\n        }\n        c = Fa();\n        for (d = this.nodes.iterator; d.next();) {\n            var e = d.value;\n            null !== e.data && (c.push(e.data), c.push(e.location))\n        }\n        for (d = this.links.iterator; d.next();) e = d.value, null !== e.data && (c.push(e.data),\n            c.push(e.location));\n        for (d = this.parts.iterator; d.next();) e = d.value, null !== e.data && (c.push(e.data), c.push(e.location));\n        this.removeAllModeledParts();\n        this.addAllModeledParts();\n        for (d = 0; d < a.length; d++) e = this.wc(a[d]), null !== e && (e.isSelected = !0);\n        for (d = 0; d < b.length; d++) e = this.wc(b[d]), null !== e && (e.isHighlighted = !0);\n        for (d = 0; d < c.length; d += 2) e = this.wc(c[d]), null !== e && (e.location = c[d + 1]);\n        Ha(a);\n        Ha(b);\n        Ha(c)\n    };\n    ri.prototype.addAllModeledParts = function () {\n        this.addModeledParts(this.diagram.model.nodeDataArray)\n    };\n    ri.prototype.addModeledParts = function (a, b) {\n        var c = this,\n            d = this.diagram.model;\n        a.forEach(function (a) {\n            d.sb(a) && jq(c, a, !1)\n        });\n        a.forEach(function (a) {\n            d.sb(a) && c.resolveReferencesForData(a)\n        });\n        !1 !== b && nk(this.diagram, !1)\n    };\n\n    function jq(a, b, c) {\n        if (void 0 !== b && null !== b && !a.diagram.undoManager.isUndoingRedoing && !a.Oe.contains(b)) {\n            void 0 === c && (c = !0);\n            a: {\n                if (void 0 !== b && null !== b && !a.B.undoManager.isUndoingRedoing && !a.Oe.contains(b)) {\n                    var d = a.nt(b);\n                    var e = Ko(a, b, d);\n                    if (null !== e && (yg(e), e = e.copy(), null !== e)) {\n                        var f = a.diagram.skipsModelSourceBindings;\n                        a.diagram.skipsModelSourceBindings = !0;\n                        e.Lf = d;\n                        e.hb = b;\n                        a.Tq && (e.eh = \"Tool\");\n                        a.diagram.add(e);\n                        e.hb = null;\n                        e.data = b;\n                        a.diagram.skipsModelSourceBindings = f;\n                        d = e;\n                        break a\n                    }\n                }\n                d = null\n            }\n            null !== d && c && a.resolveReferencesForData(b)\n        }\n    }\n    ri.prototype.insertLink = function () {\n        return null\n    };\n    ri.prototype.resolveReferencesForData = function () {};\n    ri.prototype.nt = function (a) {\n        return this.B.model.nt(a)\n    };\n\n    function Ko(a, b, c) {\n        a = a.B;\n        var d = a.model;\n        d.jk() && d.Hv(b) ? (b = a.groupTemplateMap.H(c), null === b && (b = a.groupTemplateMap.H(\"\"), null === b && (kq || (kq = !0, wa('No Group template found for category \"' + c + '\"'), wa(\"  Using default group template\")), b = a.eu))) : (b = a.nodeTemplateMap.H(c), null === b && (b = a.nodeTemplateMap.H(\"\"), null === b && (lq || (lq = !0, wa('No Node template found for category \"' + c + '\"'), wa(\"  Using default node template\")), b = a.gu)));\n        return b\n    }\n    ri.prototype.getLinkCategoryForData = function () {\n        return \"\"\n    };\n    ri.prototype.setLinkCategoryForData = function () {};\n    ri.prototype.setFromNodeForLink = function () {};\n    ri.prototype.setToNodeForLink = function () {};\n    ri.prototype.findLinkTemplateForCategory = function (a) {\n        var b = this.B.linkTemplateMap.H(a);\n        null === b && (b = this.B.linkTemplateMap.H(\"\"), null === b && (mq || (mq = !0, wa('No Link template found for category \"' + a + '\"'), wa(\"  Using default link template\")), b = this.B.fu));\n        return b\n    };\n    ri.prototype.removeAllModeledParts = function () {\n        this.It(this.diagram.model.nodeDataArray)\n    };\n    ri.prototype.It = function (a) {\n        var b = this;\n        a.forEach(function (a) {\n            b.Gq(a)\n        })\n    };\n    ri.prototype.Gq = function (a) {\n        a = this.wc(a);\n        null !== a && (Jj(this.diagram, a, !1), this.unresolveReferencesForPart(a))\n    };\n    ri.prototype.unresolveReferencesForPart = function () {};\n    ri.prototype.removeDataForLink = function () {};\n    ri.prototype.findPartForKey = function (a) {\n        if (null === a || void 0 === a) return null;\n        a = this.B.model.Ib(a);\n        return null !== a ? this.Oe.H(a) : null\n    };\n    ri.prototype.Jb = function (a) {\n        if (null === a || void 0 === a) return null;\n        a = this.B.model.Ib(a);\n        if (null === a) return null;\n        a = this.Oe.H(a);\n        return a instanceof W ? a : null\n    };\n    ri.prototype.findLinkForKey = function () {\n        return null\n    };\n    t = ri.prototype;\n    t.wc = function (a) {\n        if (null === a) return null;\n        var b = this.Oe.H(a);\n        return null !== b ? b : b = this.Ne.H(a)\n    };\n    t.Si = function (a) {\n        if (null === a) return null;\n        a = this.Oe.H(a);\n        return a instanceof W ? a : null\n    };\n    t.vc = function (a) {\n        return null === a ? null : this.Ne.H(a)\n    };\n    t.kt = function (a) {\n        for (var b = 0; b < arguments.length; ++b);\n        b = new F;\n        for (var c = this.So.iterator; c.next();) {\n            var d = c.value,\n                e = d.data;\n            if (null !== e)\n                for (var f = 0; f < arguments.length; f++) {\n                    var g = arguments[f];\n                    if (za(g) && nq(this, e, g)) {\n                        b.add(d);\n                        break\n                    }\n                }\n        }\n        return b.iterator\n    };\n    t.jt = function (a) {\n        for (var b = 0; b < arguments.length; ++b);\n        b = new F;\n        for (var c = this.so.iterator; c.next();) {\n            var d = c.value,\n                e = d.data;\n            if (null !== e)\n                for (var f = 0; f < arguments.length; f++) {\n                    var g = arguments[f];\n                    if (za(g) && nq(this, e, g)) {\n                        b.add(d);\n                        break\n                    }\n                }\n        }\n        return b.iterator\n    };\n\n    function nq(a, b, c) {\n        for (var d in c) {\n            var e = b[d],\n                f = c[d];\n            if (Aa(f)) {\n                if (!Aa(e) || e.length < f.length) return !1;\n                for (var g = 0; g < e.length; g++) {\n                    var h = f[g];\n                    if (void 0 !== h && !oq(a, e[g], h)) return !1\n                }\n            } else if (!oq(a, e, f)) return !1\n        }\n        return !0\n    }\n\n    function oq(a, b, c) {\n        if (\"function\" === typeof c) {\n            if (!c(b)) return !1\n        } else if (c instanceof RegExp) {\n            if (!b || !c.test(b.toString())) return !1\n        } else if (za(b) && za(c)) {\n            if (!nq(a, b, c)) return !1\n        } else if (b !== c) return !1;\n        return !0\n    }\n    ri.prototype.doModelChanged = function (a) {\n        if (this.B) {\n            var b = this.B;\n            if (a.model === b.model) {\n                var c = a.change;\n                b.doModelChanged(a);\n                if (b.Z) {\n                    b.Z = !1;\n                    try {\n                        var d = a.modelChange;\n                        if (\"\" !== d)\n                            if (c === re) {\n                                if (\"nodeCategory\" === d) {\n                                    var e = this.wc(a.object),\n                                        f = a.newValue;\n                                    null !== e && \"string\" === typeof f && (e.category = f)\n                                } else \"nodeDataArray\" === d && (this.It(a.oldValue), this.addModeledParts(a.newValue));\n                                b.isModified = !0\n                            } else if (c === te) {\n                            var g = a.newValue;\n                            \"nodeDataArray\" === d && za(g) && jq(this, g);\n                            b.isModified = !0\n                        } else if (c === ue) {\n                            var h = a.oldValue;\n                            \"nodeDataArray\" === d && za(h) && this.Gq(h);\n                            b.isModified = !0\n                        } else c === se && (\"SourceChanged\" === d ? null !== a.object ? this.updateDataBindings(a.object, a.propertyName) : (this.Pq(), this.updateAllTargetBindings()) : \"ModelDisplaced\" === d && this.xd());\n                        else if (c === re) {\n                            var k = a.propertyName,\n                                l = a.object;\n                            if (l === b.model) {\n                                if (\"nodeKeyProperty\" === k || \"nodeCategoryProperty\" === k) b.undoManager.isUndoingRedoing || this.xd()\n                            } else this.updateDataBindings(l, k);\n                            b.isModified = !0\n                        } else if (c === te || c === ue) {\n                            var m = a.change === te,\n                                n = m ? a.newParam : a.oldParam,\n                                p = m ? a.newValue : a.oldValue,\n                                r = this.yj.H(a.object);\n                            if (Array.isArray(r))\n                                for (a = 0; a < r.length; a++) {\n                                    var q = r[a];\n                                    if (m) jn(q, p, n);\n                                    else if (!(0 > n)) {\n                                        var u = n + bn(q);\n                                        q.Fc(u, !0);\n                                        yn(q, u, n)\n                                    }\n                                }\n                            b.isModified = !0\n                        }\n                    } finally {\n                        b.Z = !0\n                    }\n                }\n            }\n        }\n    };\n    ri.prototype.updateAllTargetBindings = function (a) {\n        void 0 === a && (a = \"\");\n        for (var b = this.parts.iterator; b.next();) b.value.Ba(a);\n        for (b = this.nodes.iterator; b.next();) b.value.Ba(a);\n        for (b = this.links.iterator; b.next();) b.value.Ba(a)\n    };\n    ri.prototype.Pq = function () {\n        for (var a = this.B.model, b = new F, c = a.nodeDataArray, d = 0; d < c.length; d++) b.add(c[d]);\n        var e = [];\n        this.nodes.each(function (a) {\n            null === a.data || b.contains(a.data) || e.push(a.data)\n        });\n        this.parts.each(function (a) {\n            null === a.data || b.contains(a.data) || e.push(a.data)\n        });\n        e.forEach(function (b) {\n            pq(a, b, !1)\n        });\n        for (d = 0; d < c.length; d++) {\n            var f = c[d];\n            null === this.wc(f) && qq(a, f, !1)\n        }\n        this.refreshDataBoundLinks();\n        for (c = this.parts.iterator; c.next();) c.value.updateRelationshipsFromData();\n        for (c = this.nodes.iterator; c.next();) c.value.updateRelationshipsFromData();\n        for (c = this.links.iterator; c.next();) c.value.updateRelationshipsFromData()\n    };\n    ri.prototype.refreshDataBoundLinks = function () {};\n    ri.prototype.updateRelationshipsFromData = function () {};\n    ri.prototype.updateDataBindings = function (a, b) {\n        if (\"string\" === typeof b) {\n            var c = this.wc(a);\n            if (null !== c) c.Ba(b);\n            else {\n                c = null;\n                for (var d = this.yj.iterator; d.next();) {\n                    for (var e = d.value, f = 0; f < e.length; f++) {\n                        var g = e[f].Kx(a);\n                        null !== g && (null === c && (c = Fa()), c.push(g))\n                    }\n                    if (null !== c) break\n                }\n                if (null !== c) {\n                    for (d = 0; d < c.length; d++) c[d].Ba(b);\n                    Ha(c)\n                }\n            }\n            a === this.diagram.model.modelData && this.updateAllTargetBindings(b)\n        }\n    };\n\n    function Fj(a, b) {\n        var c = b.si;\n        if (Aa(c)) {\n            var d = a.yj.H(c);\n            if (null === d) d = [], d.push(b), a.yj.add(c, d);\n            else {\n                for (a = 0; a < d.length; a++)\n                    if (d[a] === b) return;\n                d.push(b)\n            }\n        }\n    }\n\n    function Ij(a, b, c) {\n        Dj(b, function (a) {\n            a = a.W.j;\n            for (var b = a.length, d = 0; d < b; d++) lk(c, a[d])\n        });\n        var d = b.si;\n        if (Aa(d)) {\n            var e = a.yj.H(d);\n            if (null !== e)\n                for (var f = 0; f < e.length; f++)\n                    if (e[f] === b) {\n                        e.splice(f, 1);\n                        0 === e.length && a.yj.remove(d);\n                        break\n                    }\n        }\n    }\n    ri.prototype.ck = function (a, b, c) {\n        var d = new H;\n        if (Aa(a))\n            for (var e = 0; e < a.length; e++) rq(this, a[e], b, d, c);\n        else\n            for (a = a.iterator; a.next();) rq(this, a.value, b, d, c);\n        if (null !== b) {\n            c = b.model;\n            a = b.toolManager.findTool(\"Dragging\");\n            a = null !== a ? a.dragOptions.dragsLink : b.Qk.dragsLink;\n            e = new F;\n            for (var f = new H, g = d.iterator; g.next();) {\n                var h = g.value;\n                if (h instanceof S) a || null !== h.fromNode && null !== h.toNode || e.add(h);\n                else if (h instanceof W && null !== h.data && c.qm()) {\n                    var k = h;\n                    h = g.key;\n                    var l = h.Bg();\n                    null !== l && (l = d.H(l), null !== l ? (c.Ge(k.data,\n                        c.ja(l.data)), k = b.vc(k.data), h = h.Vi(), null !== h && null !== k && f.add(h, k)) : c.Ge(k.data, void 0))\n                }\n            }\n            0 < e.count && b.Jt(e, !1);\n            if (0 < f.count)\n                for (c = f.iterator; c.next();) d.add(c.key, c.value)\n        }\n        if (null !== b && null !== this.B && (b = b.model, c = b.afterCopyFunction, null !== c)) {\n            var m = new H;\n            d.each(function (a) {\n                null !== a.key.data && m.add(a.key.data, a.value.data)\n            });\n            c(m, b, this.B.model)\n        }\n        for (b = d.iterator; b.next();) b.value.Ba();\n        return d\n    };\n\n    function rq(a, b, c, d, e) {\n        if (null === b || e && !b.canCopy()) return null;\n        if (d.contains(b)) return d.H(b);\n        var f = a.copyPartData(b, c);\n        if (!(f instanceof U)) return null;\n        f.isSelected = !1;\n        f.isHighlighted = !1;\n        d.add(b, f);\n        if (b instanceof W) {\n            for (var g = b.linksConnected; g.next();) {\n                var h = g.value;\n                if (h.fromNode === b) {\n                    var k = d.H(h);\n                    null !== k && (k.fromNode = f)\n                }\n                h.toNode === b && (h = d.H(h), null !== h && (h.toNode = f))\n            }\n            if (b instanceof T && f instanceof T)\n                for (b = b.memberParts; b.next();) g = rq(a, b.value, c, d, e), g instanceof S || null === g || (g.containingGroup =\n                    f)\n        } else if (b instanceof S && f instanceof S)\n            for (g = b.fromNode, null !== g && (g = d.H(g), null !== g && (f.fromNode = g)), g = b.toNode, null !== g && (g = d.H(g), null !== g && (f.toNode = g)), b = b.labelNodes; b.next();) g = rq(a, b.value, c, d, e), null !== g && g instanceof W && (g.labeledLink = f);\n        return f\n    }\n    ri.prototype.copyPartData = function (a, b) {\n        var c = null,\n            d = a.data;\n        if (null !== d && null !== b) {\n            var e = b.model;\n            a instanceof S || (d = e.copyNodeData(d), za(d) && (e.pf(d), c = b.wc(d)))\n        } else yg(a), c = a.copy(), null !== c && (e = this.B, null !== b ? b.add(c) : null !== d && null !== e && null !== e.commandHandler && e.commandHandler.copiesClipboardData && (b = e.model, e = null, c instanceof S || (e = b.copyNodeData(d)), za(e) && (c.data = e)));\n        return c\n    };\n    ma.Object.defineProperties(ri.prototype, {\n        nodes: {\n            get: function () {\n                return this.So\n            }\n        },\n        links: {\n            get: function () {\n                return this.so\n            }\n        },\n        parts: {\n            get: function () {\n                return this.Ca\n            }\n        },\n        diagram: {\n            get: function () {\n                return this.B\n            }\n        },\n        addsToTemporaryLayer: {\n            get: function () {\n                return this.Tq\n            },\n            set: function (a) {\n                this.Tq = a\n            }\n        }\n    });\n    ri.prototype.updateAllRelationshipsFromData = ri.prototype.Pq;\n    ri.prototype.findLinksByExample = ri.prototype.jt;\n    ri.prototype.findNodesByExample = ri.prototype.kt;\n    ri.prototype.findLinkForData = ri.prototype.vc;\n    ri.prototype.findNodeForData = ri.prototype.Si;\n    ri.prototype.findPartForData = ri.prototype.wc;\n    ri.prototype.findNodeForKey = ri.prototype.Jb;\n    ri.prototype.removeModeledPart = ri.prototype.Gq;\n    ri.prototype.removeModeledParts = ri.prototype.It;\n    ri.prototype.rebuildParts = ri.prototype.xd;\n    var lq = !1,\n        kq = !1,\n        mq = !1;\n    ri.className = \"PartManager\";\n\n    function sq(a) {\n        ri.apply(this, arguments)\n    }\n    la(sq, ri);\n    sq.prototype.addAllModeledParts = function () {\n        var a = this.diagram.model;\n        this.addModeledParts(a.nodeDataArray);\n        tq(this, a.linkDataArray)\n    };\n    sq.prototype.addModeledParts = function (a) {\n        ri.prototype.addModeledParts.call(this, a, !1);\n        for (a = this.links.iterator; a.next();) Lo(a.value);\n        nk(this.diagram, !1)\n    };\n\n    function tq(a, b) {\n        b.forEach(function (b) {\n            uq(a, b)\n        });\n        nk(a.diagram, !1)\n    }\n\n    function uq(a, b) {\n        if (void 0 !== b && null !== b && !a.diagram.undoManager.isUndoingRedoing && !a.Ne.contains(b)) {\n            var c = a.getLinkCategoryForData(b),\n                d = a.findLinkTemplateForCategory(c);\n            if (null !== d) {\n                yg(d);\n                var e = d.copy();\n                if (null !== e) {\n                    d = a.diagram.skipsModelSourceBindings;\n                    a.diagram.skipsModelSourceBindings = !0;\n                    e.Lf = c;\n                    e.hb = b;\n                    c = a.diagram.model;\n                    var f = vq(c, b, !0);\n                    \"\" !== f && (e.fromPortId = f);\n                    f = wq(c, b, !0);\n                    void 0 !== f && (f = a.Jb(f), f instanceof W && (e.fromNode = f));\n                    f = vq(c, b, !1);\n                    \"\" !== f && (e.toPortId = f);\n                    f = wq(c, b, !1);\n                    void 0 !== f && (f = a.Jb(f),\n                        f instanceof W && (e.toNode = f));\n                    c = c.Cg(b);\n                    Array.isArray(c) && c.forEach(function (b) {\n                        b = a.Jb(b);\n                        null !== b && (b.labeledLink = e)\n                    });\n                    a.Tq && (e.eh = \"Tool\");\n                    a.diagram.add(e);\n                    e.hb = null;\n                    e.data = b;\n                    a.diagram.skipsModelSourceBindings = d\n                }\n            }\n        }\n    }\n    sq.prototype.removeAllModeledParts = function () {\n        var a = this.diagram.model;\n        xq(this, a.linkDataArray);\n        this.It(a.nodeDataArray)\n    };\n\n    function xq(a, b) {\n        b.forEach(function (b) {\n            a.Gq(b)\n        })\n    }\n    sq.prototype.getLinkCategoryForData = function (a) {\n        return this.diagram.model.wv(a)\n    };\n    sq.prototype.setLinkCategoryForData = function (a, b) {\n        return this.diagram.model.Lt(a, b)\n    };\n    sq.prototype.setFromNodeForLink = function (a, b) {\n        var c = this.diagram.model;\n        c.iy(a.data, c.ja(null !== b ? b.data : null))\n    };\n    sq.prototype.setToNodeForLink = function (a, b) {\n        var c = this.diagram.model;\n        c.my(a.data, c.ja(null !== b ? b.data : null))\n    };\n    sq.prototype.removeDataForLink = function (a) {\n        this.diagram.model.zm(a.data)\n    };\n    sq.prototype.findPartForKey = function (a) {\n        var b = ri.prototype.findPartForKey.call(this, a);\n        return null === b && (a = this.diagram.model.zg(a), null !== a) ? this.Ne.H(a) : b\n    };\n    sq.prototype.findLinkForKey = function (a) {\n        if (null === a || void 0 === a) return null;\n        a = this.diagram.model.zg(a);\n        return null !== a ? this.Ne.H(a) : null\n    };\n    sq.prototype.doModelChanged = function (a) {\n        var b = this;\n        ri.prototype.doModelChanged.call(this, a);\n        if (this.diagram) {\n            var c = this.diagram;\n            if (a.model === c.model) {\n                var d = a.change;\n                if (c.Z) {\n                    c.Z = !1;\n                    try {\n                        var e = a.modelChange;\n                        if (\"\" !== e)\n                            if (d === re) {\n                                if (\"linkFromKey\" === e) {\n                                    var f = this.vc(a.object);\n                                    if (null !== f) {\n                                        var g = this.Jb(a.newValue);\n                                        f.fromNode = g\n                                    }\n                                } else if (\"linkToKey\" === e) {\n                                    var h = this.vc(a.object);\n                                    if (null !== h) {\n                                        var k = this.Jb(a.newValue);\n                                        h.toNode = k\n                                    }\n                                } else if (\"linkFromPortId\" === e) {\n                                    var l = this.vc(a.object);\n                                    if (null !== l) {\n                                        var m = a.newValue;\n                                        \"string\" === typeof m && (l.fromPortId = m)\n                                    }\n                                } else if (\"linkToPortId\" === e) {\n                                    var n = this.vc(a.object);\n                                    if (null !== n) {\n                                        var p = a.newValue;\n                                        \"string\" === typeof p && (n.toPortId = p)\n                                    }\n                                } else if (\"nodeGroupKey\" === e) {\n                                    var r = this.wc(a.object);\n                                    if (null !== r) {\n                                        var q = a.newValue;\n                                        if (void 0 !== q) {\n                                            var u = this.Jb(q);\n                                            u instanceof T ? r.containingGroup = u : r.containingGroup = null\n                                        } else r.containingGroup = null\n                                    }\n                                } else if (\"linkLabelKeys\" === e) {\n                                    var v = this.vc(a.object);\n                                    if (null !== v) {\n                                        var w = a.oldValue,\n                                            y = a.newValue;\n                                        Array.isArray(w) && w.forEach(function (a) {\n                                            a = b.Jb(a);\n                                            null !== a && (a.labeledLink = null)\n                                        });\n                                        Array.isArray(y) && y.forEach(function (a) {\n                                            a = b.Jb(a);\n                                            null !== a && (a.labeledLink = v)\n                                        })\n                                    }\n                                } else if (\"linkCategory\" === e) {\n                                    var z = this.vc(a.object),\n                                        A = a.newValue;\n                                    null !== z && \"string\" === typeof A && (z.category = A)\n                                } else \"linkDataArray\" === e && (xq(this, a.oldValue), tq(this, a.newValue));\n                                c.isModified = !0\n                            } else if (d === te) {\n                            var C = a.newValue;\n                            if (\"linkDataArray\" === e && \"object\" === typeof C && null !== C) uq(this, C);\n                            else if (\"linkLabelKeys\" === e && yq(C)) {\n                                var G = this.vc(a.object),\n                                    L = this.Jb(C);\n                                null !== G && null !== L && (L.labeledLink =\n                                    G)\n                            }\n                            c.isModified = !0\n                        } else {\n                            if (d === ue) {\n                                var K = a.oldValue;\n                                if (\"linkDataArray\" === e && \"object\" === typeof K && null !== K) this.Gq(K);\n                                else if (\"linkLabelKeys\" === e && yq(K)) {\n                                    var V = this.Jb(K);\n                                    null !== V && (V.labeledLink = null)\n                                }\n                                c.isModified = !0\n                            }\n                        } else if (d === re) {\n                            var Q = a.propertyName;\n                            a.object !== c.model || \"linkFromKeyProperty\" !== Q && \"linkToKeyProperty\" !== Q && \"linkFromPortIdProperty\" !== Q && \"linkToPortIdProperty\" !== Q && \"linkLabelKeysProperty\" !== Q && \"nodeIsGroupProperty\" !== Q && \"nodeGroupKeyProperty\" !== Q && \"linkCategoryProperty\" !== Q || c.undoManager.isUndoingRedoing ||\n                                this.xd();\n                            c.isModified = !0\n                        }\n                    } finally {\n                        c.Z = !0\n                    }\n                }\n            }\n        }\n    };\n    sq.prototype.refreshDataBoundLinks = function () {\n        var a = this,\n            b = this.diagram.model,\n            c = new F,\n            d = b.linkDataArray;\n        d.forEach(function (a) {\n            c.add(a)\n        });\n        var e = [];\n        this.links.each(function (a) {\n            null === a.data || c.contains(a.data) || e.push(a.data)\n        });\n        e.forEach(function (a) {\n            zq(b, a, !1)\n        });\n        d.forEach(function (c) {\n            null === a.vc(c) && Aq(b, c, !1)\n        })\n    };\n    sq.prototype.updateRelationshipsFromData = function (a) {\n        var b = a.data;\n        if (null !== b) {\n            var c = a.diagram;\n            if (null !== c) {\n                var d = c.model;\n                if (a instanceof S) {\n                    var e = wq(d, b, !0);\n                    e = c.Jb(e);\n                    a.fromNode = e;\n                    e = wq(d, b, !1);\n                    e = c.Jb(e);\n                    a.toNode = e;\n                    b = d.Cg(b);\n                    if (0 < b.length || 0 < a.labelNodes.count) {\n                        if (1 === b.length && 1 === a.labelNodes.count) {\n                            e = b[0];\n                            var f = a.labelNodes.first();\n                            if (d.ja(f.data) === e) return\n                        }\n                        e = (new F).addAll(b);\n                        var g = new F;\n                        a.labelNodes.each(function (a) {\n                            null !== a.data && (a = d.ja(a.data), void 0 !== a && g.add(a))\n                        });\n                        b = g.copy();\n                        b.Fq(e);\n                        e =\n                            e.copy();\n                        e.Fq(g);\n                        if (0 < b.count || 0 < e.count) b.each(function (b) {\n                            b = c.Jb(b);\n                            null !== b && b.labeledLink === a && (b.labeledLink = null)\n                        }), e.each(function (b) {\n                            b = c.Jb(b);\n                            null !== b && b.labeledLink !== a && (b.labeledLink = a)\n                        })\n                    }\n                } else !(a instanceof Je) && (b = d.Yi(b), b = c.findPartForKey(b), null === b || b instanceof T) && (a.containingGroup = b)\n            }\n        }\n    };\n    sq.prototype.resolveReferencesForData = function (a) {\n        var b = this.diagram.model,\n            c = b.ja(a);\n        if (void 0 !== c) {\n            var d = Bq(b, c),\n                e = this.wc(a);\n            if (null !== d && null !== e) {\n                d = d.iterator;\n                for (var f = {}; d.next();) {\n                    var g = d.value;\n                    b.sb(g) ? e instanceof T && b.Yi(g) === c && (g = this.wc(g), null !== g && (g.containingGroup = e)) : (f.link = this.vc(g), null !== f.link && e instanceof W && (wq(b, g, !0) === c && (f.link.fromNode = e), wq(b, g, !1) === c && (f.link.toNode = e), g = b.Cg(g), Array.isArray(g) && g.some(function (a) {\n                        return function (b) {\n                            return b === c ? (e.labeledLink = a.link,\n                                !0) : !1\n                        }\n                    }(f))));\n                    f = {\n                        link: f.link\n                    }\n                }\n                Cq(b, c)\n            }\n            a = b.Yi(a);\n            void 0 !== a && (a = this.Jb(a), a instanceof T && (e.containingGroup = a))\n        }\n    };\n    sq.prototype.unresolveReferencesForPart = function (a) {\n        var b = this.diagram.model;\n        if (a instanceof W) {\n            var c = b.ja(a.data);\n            if (void 0 !== c) {\n                for (var d = a.linksConnected; d.next();) Dq(b, c, d.value.data);\n                a.isLinkLabel && (d = a.labeledLink, null !== d && Dq(b, c, d.data));\n                if (a instanceof T)\n                    for (a = a.memberParts; a.next();) d = a.value.data, b.sb(d) && Dq(b, c, d)\n            }\n        }\n    };\n    sq.prototype.copyPartData = function (a, b) {\n        var c = ri.prototype.copyPartData.call(this, a, b);\n        if (a instanceof S)\n            if (a = a.data, null !== a && null !== b) {\n                var d = b.model;\n                a = d.hq(a);\n                \"object\" === typeof a && null !== a && (d.Ni(a), c = b.vc(a))\n            } else null !== c && (b = this.diagram, null !== a && null !== b && null !== b.commandHandler && b.commandHandler.copiesClipboardData && (b = b.model.hq(a), \"object\" === typeof b && null !== b && (c.data = b)));\n        return c\n    };\n    sq.prototype.insertLink = function (a, b, c, d) {\n        var e = this.diagram,\n            f = e.model,\n            g = e.toolManager.findTool(\"Linking\"),\n            h = \"\";\n        null !== a && (null === b && (b = a), h = b.portId, null === h && (h = \"\"));\n        b = \"\";\n        null !== c && (null === d && (d = c), b = d.portId, null === b && (b = \"\"));\n        d = g.archetypeLinkData;\n        if (d instanceof S) {\n            if (yg(d), f = d.copy(), null !== f) return f.fromNode = a, f.fromPortId = h, f.toNode = c, f.toPortId = b, e.add(f), a = g.archetypeLabelNodeData, a instanceof W && (yg(a), a = a.copy(), null !== a && (a.labeledLink = f, e.add(a))), f\n        } else if (null !== d && (d = f.hq(d), \"object\" ===\n                typeof d && null !== d)) return null !== a && Eq(f, d, f.ja(a.data), !0), Fq(f, d, h, !0), null !== c && Eq(f, d, f.ja(c.data), !1), Fq(f, d, b, !1), f.Ni(d), a = g.archetypeLabelNodeData, null === a || a instanceof W || (a = f.copyNodeData(a), \"object\" === typeof a && null !== a && (f.pf(a), a = f.ja(a), void 0 !== a && f.dv(d, a))), e.vc(d);\n        return null\n    };\n    sq.prototype.findLinkForKey = sq.prototype.findLinkForKey;\n    sq.prototype.findPartForKey = sq.prototype.findPartForKey;\n    sq.prototype.removeAllModeledParts = sq.prototype.removeAllModeledParts;\n    sq.prototype.addModeledParts = sq.prototype.addModeledParts;\n    sq.prototype.addAllModeledParts = sq.prototype.addAllModeledParts;\n    sq.className = \"GraphLinksPartManager\";\n\n    function Gq() {\n        ri.apply(this, arguments);\n        this.lh = null\n    }\n    la(Gq, ri);\n\n    function Hq(a, b, c) {\n        if (null !== b && null !== c) {\n            var d = a.diagram.toolManager.findTool(\"Linking\"),\n                e = b,\n                f = c;\n            if (a.diagram.isTreePathToChildren)\n                for (b = f.linksConnected; b.next();) {\n                    if (b.value.toNode === f) return\n                } else\n                    for (e = c, f = b, b = e.linksConnected; b.next();)\n                        if (b.value.fromNode === e) return;\n            if (null === d || !Pf(d, e, f, null, !0))\n                if (d = a.getLinkCategoryForData(c.data), b = a.findLinkTemplateForCategory(d), null !== b && (yg(b), b = b.copy(), null !== b)) {\n                    var g = a.diagram.skipsModelSourceBindings;\n                    a.diagram.skipsModelSourceBindings = !0;\n                    b.Lf = d;\n                    b.hb = c.data;\n                    b.fromNode = e;\n                    b.toNode = f;\n                    a.diagram.add(b);\n                    b.hb = null;\n                    b.data = c.data;\n                    a.diagram.skipsModelSourceBindings = g\n                }\n        }\n    }\n    Gq.prototype.getLinkCategoryForData = function (a) {\n        return this.diagram.model.xv(a)\n    };\n    Gq.prototype.setLinkCategoryForData = function (a, b) {\n        this.diagram.model.ew(a, b)\n    };\n    Gq.prototype.setFromNodeForLink = function (a, b, c) {\n        var d = this.diagram.model;\n        void 0 === c && (c = null);\n        b = null !== b ? b.data : null;\n        if (this.diagram.isTreePathToChildren) d.Ge(a.data, d.ja(b));\n        else {\n            var e = this.lh;\n            this.lh = a;\n            null !== c && d.Ge(c.data, void 0);\n            d.Ge(b, d.ja(null !== a.toNode ? a.toNode.data : null));\n            this.lh = e\n        }\n    };\n    Gq.prototype.setToNodeForLink = function (a, b, c) {\n        var d = this.diagram.model;\n        void 0 === c && (c = null);\n        b = null !== b ? b.data : null;\n        if (this.diagram.isTreePathToChildren) {\n            var e = this.lh;\n            this.lh = a;\n            null !== c && d.Ge(c.data, void 0);\n            d.Ge(b, d.ja(null !== a.fromNode ? a.fromNode.data : null));\n            this.lh = e\n        } else d.Ge(a.data, d.ja(b))\n    };\n    Gq.prototype.removeDataForLink = function (a) {\n        this.diagram.model.Ge(a.data, void 0)\n    };\n    Gq.prototype.findLinkForKey = function (a) {\n        if (null === a || void 0 === a) return null;\n        a = this.diagram.model.Ib(a);\n        return null !== a ? this.Ne.H(a) : null\n    };\n    Gq.prototype.doModelChanged = function (a) {\n        ri.prototype.doModelChanged.call(this, a);\n        if (this.diagram) {\n            var b = this.diagram;\n            if (a.model === b.model) {\n                var c = a.change;\n                if (b.Z) {\n                    b.Z = !1;\n                    try {\n                        var d = a.modelChange;\n                        if (\"\" !== d) {\n                            if (c === re) {\n                                if (\"nodeParentKey\" === d) {\n                                    var e = a.object,\n                                        f = this.Jb(a.newValue),\n                                        g = this.Si(e);\n                                    if (null !== this.lh) null !== f && (this.lh.data = e, this.lh.category = this.getLinkCategoryForData(e));\n                                    else if (null !== g) {\n                                        var h = g.Vi();\n                                        null !== h ? null === f ? b.remove(h) : b.isTreePathToChildren ? h.fromNode = f : h.toNode = f : Hq(this, f, g)\n                                    }\n                                } else if (\"parentLinkCategory\" ===\n                                    d) {\n                                    var k = this.Si(a.object),\n                                        l = a.newValue;\n                                    if (null !== k && \"string\" === typeof l) {\n                                        var m = k.Vi();\n                                        null !== m && (m.category = l)\n                                    }\n                                }\n                                b.isModified = !0\n                            }\n                        } else if (c === re) {\n                            var n = a.propertyName;\n                            a.object === b.model && \"nodeParentKeyProperty\" === n && (b.undoManager.isUndoingRedoing || this.xd());\n                            b.isModified = !0\n                        }\n                    } finally {\n                        b.Z = !0\n                    }\n                }\n            }\n        }\n    };\n    Gq.prototype.updateRelationshipsFromData = function (a) {\n        var b = a.data;\n        if (null !== b) {\n            var c = a.diagram;\n            if (null !== c) {\n                var d = c.model;\n                a instanceof W && (b = d.$i(b), b = c.Jb(b), d = a.Bg(), b !== d && (d = a.Vi(), null !== b ? null !== d ? c.isTreePathToChildren ? d.fromNode = b : d.toNode = b : Hq(this, b, a) : null !== d && Jj(c, d, !1)))\n            }\n        }\n    };\n    Gq.prototype.updateDataBindings = function (a, b) {\n        ri.prototype.updateDataBindings.call(this, a, b);\n        \"string\" === typeof b && null !== this.wc(a) && (a = this.vc(a), null !== a && a.Ba(b))\n    };\n    Gq.prototype.resolveReferencesForData = function (a) {\n        var b = this.diagram.model,\n            c = b.ja(a);\n        if (void 0 !== c) {\n            var d = Bq(b, c),\n                e = this.wc(a);\n            if (null !== d && null !== e) {\n                for (d = d.iterator; d.next();) {\n                    var f = d.value;\n                    b.sb(f) && e instanceof W && b.$i(f) === c && Hq(this, e, this.Si(f))\n                }\n                Cq(b, c)\n            }\n            a = b.$i(a);\n            void 0 !== a && e instanceof W && (a = this.Jb(a), Hq(this, a, e))\n        }\n    };\n    Gq.prototype.unresolveReferencesForPart = function (a) {\n        var b = this.diagram.model;\n        if (a instanceof W) {\n            var c = b.ja(a.data),\n                d = this.vc(a.data);\n            if (null !== d) {\n                d.isSelected = !1;\n                d.isHighlighted = !1;\n                var e = d.layer;\n                if (null !== e) {\n                    var f = e.Fc(-1, d, !1);\n                    0 <= f && this.diagram.Ya(ue, \"parts\", e, d, null, f, null);\n                    f = d.layerChanged;\n                    null !== f && f(d, e, null)\n                }\n            }\n            d = this.diagram.isTreePathToChildren;\n            for (a = a.linksConnected; a.next();) e = a.value, e = (d ? e.toNode : e.fromNode).data, b.sb(e) && Dq(b, c, e)\n        }\n    };\n    Gq.prototype.insertLink = function (a, b, c) {\n        b = this.diagram.model;\n        var d = a,\n            e = c;\n        this.diagram.isTreePathToChildren || (d = c, e = a);\n        return null !== d && null !== e ? (b.Ge(e.data, b.ja(d.data)), e.Vi()) : null\n    };\n    Gq.prototype.findLinkForKey = Gq.prototype.findLinkForKey;\n    Gq.className = \"TreePartManager\";\n\n    function Z(a) {\n        this.Ut = ',\\n  \"insertedNodeKeys\": ';\n        this.Jw = ',\\n  \"modifiedNodeData\": ';\n        this.Wt = ',\\n  \"removedNodeKeys\": ';\n        this.Ph = null;\n        Ya(this);\n        this.tn = this.Ra = \"\";\n        this.Zf = !1;\n        this.l = {};\n        this.Cc = [];\n        this.ab = new H;\n        this.Ai = \"key\";\n        this.Ok = this.wl = null;\n        this.kn = this.ln = !1;\n        this.nn = !0;\n        this.Sm = null;\n        this.Gj = \"category\";\n        this.Rf = new H;\n        this.Bu = new E;\n        this.sg = !1;\n        this.u = null;\n        this.undoManager = new we;\n        void 0 !== a && (this.nodeDataArray = a)\n    }\n    Z.prototype.cloneProtected = function (a) {\n        a.Ra = this.Ra;\n        a.tn = this.tn;\n        a.Zf = this.Zf;\n        a.Ai = this.Ai;\n        a.wl = this.wl;\n        a.Ok = this.Ok;\n        a.ln = this.ln;\n        a.kn = this.kn;\n        a.nn = this.nn;\n        a.Sm = this.Sm;\n        a.Gj = this.Gj\n    };\n    Z.prototype.copy = function () {\n        var a = new this.constructor;\n        this.cloneProtected(a);\n        return a\n    };\n    Z.prototype.clear = function () {\n        this.Cc = [];\n        this.ab.clear();\n        this.Rf.clear();\n        this.undoManager.clear()\n    };\n    Z.prototype.toString = function (a) {\n        void 0 === a && (a = 0);\n        if (1 < a) return this.Mq();\n        var b = (\"\" !== this.name ? this.name : \"\") + \" Model\";\n        if (0 < a) {\n            b += \"\\n node data:\";\n            a = this.nodeDataArray;\n            for (var c = a.length, d = 0; d < c; d++) {\n                var e = a[d];\n                b += \" \" + this.ja(e) + \":\" + Ja(e)\n            }\n        }\n        return b\n    };\n    Z.prototype.zA = function (a) {\n        a.change !== se && B(\"Model.toIncrementalData argument is not a Transaction ChangedEvent:\" + a.toString());\n        var b = a.object;\n        if (!(a.isTransactionFinished && b instanceof ve)) return null;\n        Iq(this, b);\n        a = this.xw(b, \"FinishedUndo\" === a.propertyName);\n        this.Ph = null;\n        return a\n    };\n    Z.prototype.xw = function (a, b) {\n        var c = this,\n            d = !1,\n            e = new F,\n            f = new F,\n            g = new F,\n            h = this.Ph;\n        a.changes.each(function (a) {\n            a.model === c && (\"nodeDataArray\" === a.modelChange ? a.change === te ? e.add(a.newValue) : a.change === ue && g.add(a.oldValue) : c.sb(a.object) ? f.add(a.object) : a.change !== re || c.modelData !== a.object && \"modelData\" !== a.propertyName ? null !== a.object && (h && h.contains(a.object) ? h.get(a.object).each(function (a) {\n                c.sb(a) && f.add(a)\n            }) : Jq(c, a.object).each(function (a) {\n                f.add(a)\n            })) : d = !0)\n        });\n        var k = new F;\n        e.each(function (a) {\n            k.add(c.ja(a));\n            b || f.add(a)\n        });\n        var l = new F;\n        g.each(function (a) {\n            l.add(c.ja(a));\n            b && f.add(a)\n        });\n        a = c.cloneDeep(f.na());\n        var m = null;\n        d && (null === m && (m = {}), m.modelData = this.cloneDeep(this.modelData));\n        0 < k.count && (null === m && (m = {}), b ? m.removedNodeKeys = k.na() : m.insertedNodeKeys = k.na());\n        0 < a.length && (null === m && (m = {}), m.modifiedNodeData = a);\n        0 < l.count && (null === m && (m = {}), b ? m.insertedNodeKeys = l.na() : m.removedNodeKeys = l.na());\n        return m\n    };\n    Z.prototype.cloneDeep = function (a) {\n        return Kq(this, a, !0)\n    };\n\n    function Kq(a, b, c, d, e, f) {\n        function g(a, c) {\n            h ? (void 0 === a.__gohashid && f.push(a), d.set(a, c)) : (a = pb++, d.set(a, c), e.set(a, b))\n        }\n        if (!za(b)) return b;\n        f || (f = []);\n        var h = Object.isExtensible(b);\n        d || (d = new H);\n        if (h) {\n            var k = d.get(b);\n            if (k) return k\n        } else\n            for (e || (e = new H), k = e.iterator; k.next();) {\n                var l = k.key;\n                if (k.value === b && (l = d.get(l))) return l\n            }\n        if (Array.isArray(b)) {\n            k = [];\n            g(b, k);\n            for (var m = 0; m < b.length; m++) k.push(Kq(a, b[m], !1, d, e, f))\n        } else if (b instanceof I || b instanceof M || b instanceof N || b instanceof oc || b instanceof P) k = b.copy(),\n            g(b, k);\n        else {\n            if (b instanceof tl || b instanceof td || b instanceof D) return b;\n            if (b instanceof E) k = (new E).addAll(Kq(a, b.na(), !1, d, e, f)), g(b, k);\n            else if (b instanceof F) k = (new F).addAll(Kq(a, b.na(), !1, d, e, f)), g(b, k);\n            else if (b instanceof H) k = (new H).addAll(Kq(a, b.na(), !1, d, e, f)), g(b, k);\n            else if (b instanceof Date) k = new Date(b.getTime()), g(b, k);\n            else if (b instanceof RegExp) k = new RegExp(b), g(b, k), k.lastIndex = b.lastIndex;\n            else if (\"function\" === typeof b.copy) k = b.copy(), g(b, k);\n            else\n                for (m in k = {}, g(b, k), b) \"__gohashid\" !==\n                    m && (k[m] = Kq(a, b[m], !1, d, e, f))\n        }\n        c && f.forEach(function (a) {\n            delete a.__gohashid\n        });\n        return k\n    }\n    t = Z.prototype;\n    t.zk = function () {\n        var a = \"\";\n        \"\" !== this.name && (a += ',\\n  \"name\": ' + this.quote(this.name));\n        \"\" !== this.dataFormat && (a += ',\\n  \"dataFormat\": ' + this.quote(this.dataFormat));\n        this.isReadOnly && (a += ',\\n  \"isReadOnly\": ' + this.isReadOnly);\n        \"key\" !== this.nodeKeyProperty && \"string\" === typeof this.nodeKeyProperty && (a += ',\\n  \"nodeKeyProperty\": ' + this.quote(this.nodeKeyProperty));\n        this.copiesArrays && (a += ',\\n  \"copiesArrays\": true');\n        this.copiesArrayObjects && (a += ',\\n  \"copiesArrayObjects\": true');\n        this.copiesKey || (a += ',\\n  \"copiesKey\": false');\n        \"category\" !== this.nodeCategoryProperty && \"string\" === typeof this.nodeCategoryProperty && (a += ',\\n  \"nodeCategoryProperty\": ' + this.quote(this.nodeCategoryProperty));\n        return a\n    };\n    t.Eq = function (a) {\n        a.name && (this.name = a.name);\n        a.dataFormat && (this.dataFormat = a.dataFormat);\n        a.isReadOnly && (this.isReadOnly = !0);\n        a.nodeKeyProperty && (this.nodeKeyProperty = a.nodeKeyProperty);\n        a.copiesArrays && (this.copiesArrays = !0);\n        a.copiesArrayObjects && (this.copiesArrayObjects = !0);\n        !1 === a.copiesKey && (this.copiesKey = !1);\n        a.nodeCategoryProperty && (this.nodeCategoryProperty = a.nodeCategoryProperty)\n    };\n\n    function Lq(a) {\n        return ',\\n  \"modelData\": ' + Mq(a, a.modelData)\n    }\n\n    function Nq(a, b) {\n        b = b.modelData;\n        za(b) && (a.Bm(b), a.modelData = b)\n    }\n    t.yw = function () {\n        var a = this.modelData,\n            b = !1,\n            c;\n        for (c in a)\n            if (!Oq(c, a[c])) {\n                b = !0;\n                break\n            } a = \"\";\n        b && (a = Lq(this));\n        return a + ',\\n  \"nodeDataArray\": ' + Pq(this, this.nodeDataArray, !0)\n    };\n    t.Tv = function (a) {\n        Nq(this, a);\n        a = a.nodeDataArray;\n        Aa(a) && (this.Bm(a), this.nodeDataArray = a)\n    };\n\n    function Qq(a, b, c, d) {\n        if (b === c) return !0;\n        if (typeof b !== typeof c || \"function\" === typeof b || \"function\" === typeof c) return !1;\n        if (Array.isArray(b) && Array.isArray(c)) {\n            if (d.H(b) === c) return !0;\n            d.add(b, c);\n            if (b.length !== c.length) return !1;\n            for (var e = 0; e < b.length; e++)\n                if (!Qq(a, b[e], c[e], d)) return !1;\n            return !0\n        }\n        if (za(b) && za(c)) {\n            if (d.H(b) === c) return !0;\n            d.add(b, c);\n            for (var f in b) {\n                var g = b[f];\n                if (!Oq(f, g)) {\n                    var h = c[f];\n                    if (void 0 === h || !Qq(a, g, h, d)) return !1\n                }\n            }\n            for (e in c)\n                if (f = c[e], !Oq(e, f) && (g = b[e], void 0 === g || !Qq(a, g, f, d))) return !1;\n            return !0\n        }\n        return !1\n    }\n\n    function Rq(a, b, c) {\n        a[c] !== b[c] && B(\"Model.computeJsonDifference: Model.\" + c + ' is not the same in both models: \"' + a[c] + '\" and \"' + b[c] + '\"')\n    }\n    t.Rq = function (a) {\n        Rq(this, a, \"nodeKeyProperty\");\n        for (var b = new F, c = new F, d = (new F).addAll(this.ab.iteratorKeys), e = new H, f = a.nodeDataArray, g = f.length, h = 0; h < g; h++) {\n            var k = f[h],\n                l = a.ja(k);\n            if (void 0 !== l) {\n                d.remove(l);\n                var m = this.Ib(l);\n                null === m ? (b.add(l), c.add(k)) : Qq(this, m, k, e) || c.add(k)\n            } else this.zt(k), l = this.ja(k), b.add(l), c.add(k)\n        }\n        f = \"\";\n        Qq(this, this.modelData, a.modelData, e) || (f += Lq(this));\n        0 < b.count && (f += this.Ut + Pq(this, b.na(), !0));\n        0 < c.count && (f += this.Jw + Pq(this, c.na(), !0));\n        0 < d.count && (f += this.Wt + Pq(this, d.na(),\n            !0));\n        return f\n    };\n    t.Ty = function (a, b) {\n        void 0 === b && (b = Sq(this, this));\n        return '{ \"class\": ' + this.quote(b) + ', \"incremental\": 1' + this.zk() + this.Rq(a) + \"}\"\n    };\n\n    function Iq(a, b) {\n        function c(a, b) {\n            b = b.part.data;\n            if (a !== b) {\n                var c = d.get(a);\n                null === c ? (c = new F, c.add(b), d.add(a, c)) : c.add(b)\n            }\n        }\n        var d = a.Ph;\n        null === d && (d = new H, b.changes.each(function (a) {\n            if (null !== a.diagram) {\n                var b = a.change;\n                if (b === re)(a = a.object.panel) && (b = a.data) && c(b, a);\n                else if (b === te || b === ue) a = a.object, (b = a.itemArray) && c(b, a)\n            }\n        }), a.Ph = d)\n    }\n\n    function Jq(a, b) {\n        for (var c = new F, d = 0; d < a.nodeDataArray.length; d++) {\n            var e = a.nodeDataArray[d];\n            Tq(a, b, e, e, c)\n        }\n        return c\n    }\n\n    function Tq(a, b, c, d, e) {\n        if (Array.isArray(c))\n            for (var f = 0; f < c.length; f++) {\n                var g = c[f];\n                if (g === b) return e.add(d), !0;\n                if (Tq(a, b, g, d, e)) return !0\n            } else if (za(c) && Object.getPrototypeOf(c) === Object.prototype)\n                for (f in c) {\n                    g = c[f];\n                    if (g === b) return e.add(d), !0;\n                    if (Tq(a, b, g, d, e)) return !0\n                }\n        return !1\n    }\n    t.ww = function (a, b) {\n        var c = this,\n            d = !1,\n            e = new F,\n            f = new F,\n            g = new F,\n            h = this.Ph;\n        a.changes.each(function (a) {\n            a.model === c && (\"nodeDataArray\" === a.modelChange ? a.change === te ? e.add(a.newValue) : a.change === ue && g.add(a.oldValue) : c.sb(a.object) ? f.add(a.object) : a.change !== re || c.modelData !== a.object && \"modelData\" !== a.propertyName ? null !== a.object && (h && h.contains(a.object) ? h.get(a.object).each(function (a) {\n                c.sb(a) && f.add(a)\n            }) : Jq(c, a.object).each(function (a) {\n                f.add(a)\n            })) : d = !0)\n        });\n        var k = new F;\n        e.each(function (a) {\n            k.add(c.ja(a));\n            b ||\n                f.add(a)\n        });\n        var l = new F;\n        g.each(function (a) {\n            l.add(c.ja(a));\n            b && f.add(a)\n        });\n        a = \"\";\n        d && (a += Lq(this));\n        0 < k.count && (a += (b ? this.Wt : this.Ut) + Pq(this, k.na(), !0));\n        0 < f.count && (a += this.Jw + Pq(this, f.na(), !0));\n        0 < l.count && (a += (b ? this.Ut : this.Wt) + Pq(this, l.na(), !0));\n        return a\n    };\n    t.Dq = function (a) {\n        (void 0 !== a.name && a.name !== this.name || void 0 !== a.dataFormat && a.dataFormat !== this.dataFormat || void 0 !== a.isReadOnly && a.isReadOnly !== this.isReadOnly || void 0 !== a.nodeKeyProperty && a.nodeKeyProperty !== this.nodeKeyProperty || void 0 !== a.copiesArrays && a.copiesArrays !== this.copiesArrays || void 0 !== a.copiesArrayObjects && a.copiesArrayObjects !== this.copiesArrayObjects || void 0 !== a.copiesKey && a.copiesKey !== this.copiesKey || void 0 !== a.nodeCategoryProperty && a.nodeCategoryProperty !== this.nodeCategoryProperty) &&\n        B(\"applyIncrementalJson cannot change Model properties\");\n        Nq(this, a);\n        var b = a.insertedNodeKeys,\n            c = a.modifiedNodeData,\n            d = new H;\n        if (Array.isArray(c))\n            for (var e = 0; e < c.length; e++) {\n                var f = c[e],\n                    g = this.ja(f);\n                void 0 !== g && null !== g && d.set(g, f)\n            }\n        if (Array.isArray(b))\n            for (e = b.length, f = 0; f < e; f++) {\n                g = b[f];\n                var h = this.Ib(g);\n                null === h && (h = (h = d.get(g)) ? h : this.copyNodeData({}), this.Hm(h, g), this.pf(h))\n            }\n        if (Array.isArray(c))\n            for (b = c.length, d = 0; d < b; d++)\n                if (e = c[d], f = this.ja(e), f = this.Ib(f), null !== f)\n                    for (var k in e) \"__gohashid\" === k || k ===\n                        this.nodeKeyProperty || this.ik() && k === this.nodeIsGroupProperty || this.setDataProperty(f, k, e[k]);\n        a = a.removedNodeKeys;\n        if (Array.isArray(a))\n            for (c = a.length, k = 0; k < c; k++) b = this.Ib(a[k]), null !== b && this.Am(b)\n    };\n    t.qy = function (a, b) {\n        a.change !== se && B(\"Model.toIncrementalJson argument is not a Transaction ChangedEvent:\" + a.toString());\n        var c = a.object;\n        if (!(a.isTransactionFinished && c instanceof ve)) return '{ \"incremental\": 0 }';\n        void 0 === b && (b = Sq(this, this));\n        Iq(this, c);\n        a = this.ww(c, \"FinishedUndo\" === a.propertyName);\n        this.Ph = null;\n        return \"2\" === b ? '{ \"incremental\": 2' + a + \"}\" : '{ \"class\": ' + this.quote(b) + ', \"incremental\": 1' + this.zk() + a + \"}\"\n    };\n    t.AA = function (a, b) {\n        return this.qy(a, b)\n    };\n    t.Mq = function (a) {\n        void 0 === a && (a = Sq(this, this));\n        return '{ \"class\": ' + this.quote(a) + this.zk() + this.yw() + \"}\"\n    };\n    t.toJSON = function (a) {\n        return this.Mq(a)\n    };\n    t.wx = function (a) {\n        var b = null;\n        if (\"string\" === typeof a) try {\n            b = x.JSON.parse(a)\n        } catch (d) {} else \"object\" === typeof a ? b = a : B(\"Unable to modify a Model from: \" + a);\n        var c = b.incremental;\n        \"number\" !== typeof c && B(\"Unable to apply non-incremental changes to Model: \" + a);\n        0 !== c && (this.ua(\"applyIncrementalJson\"), this.Dq(b), this.Ua(\"applyIncrementalJson\"))\n    };\n    t.Ny = function (a) {\n        return this.wx(a)\n    };\n    Z.constructGraphLinksModel = function () {\n        return new Z\n    };\n    t = Z.prototype;\n    t.Bm = function (a) {\n        if (Aa(a))\n            for (var b = a.length, c = 0; c < b; c++) {\n                var d = a[c];\n                if (za(d)) {\n                    var e = c;\n                    d = this.Bm(d);\n                    Array.isArray(a) ? a[e] = d : B(\"Cannot replace an object in an HTMLCollection or NodeList at \" + e)\n                }\n            } else if (za(a)) {\n                for (c in a)\n                    if (e = a[c], za(e) && (e = this.Bm(e), a[c] = e, \"points\" === c && Array.isArray(e))) {\n                        d = 0 === e.length % 2;\n                        for (var f = 0; f < e.length; f++)\n                            if (\"number\" !== typeof e[f]) {\n                                d = !1;\n                                break\n                            } if (d) {\n                            d = new E;\n                            for (f = 0; f < e.length / 2; f++) d.add(new I(e[2 * f], e[2 * f + 1]));\n                            d.freeze();\n                            a[c] = d\n                        }\n                    } if (\"object\" === typeof a) {\n                    c = a;\n                    e = a[\"class\"] ||\n                        \"\";\n                    0 === e.indexOf(\"go.\") && (e = e.substr(3));\n                    if (\"NaN\" === e) c = NaN;\n                    else if (\"Date\" === e) c = new Date(a.value);\n                    else if (\"Point\" === e) c = new I(Uq(a.x), Uq(a.y));\n                    else if (\"Size\" === e) c = new M(Uq(a.width), Uq(a.height));\n                    else if (\"Rect\" === e) c = new N(Uq(a.x), Uq(a.y), Uq(a.width), Uq(a.height));\n                    else if (\"Margin\" === e) c = new oc(Uq(a.top), Uq(a.right), Uq(a.bottom), Uq(a.left));\n                    else if (\"Spot\" === e) \"string\" === typeof a[\"enum\"] ? c = kd(a[\"enum\"]) : c = new P(Uq(a.x), Uq(a.y), Uq(a.offsetX), Uq(a.offsetY));\n                    else if (\"Brush\" === e) {\n                        if (c = new tl, c.type = Za(tl,\n                                a.type), \"string\" === typeof a.color && (c.color = a.color), a.start instanceof P && (c.start = a.start), a.end instanceof P && (c.end = a.end), \"number\" === typeof a.startRadius && (c.startRadius = Uq(a.startRadius)), \"number\" === typeof a.endRadius && (c.endRadius = Uq(a.endRadius)), a = a.colorStops, za(a))\n                            for (b in a) c.addColorStop(parseFloat(b), a[b])\n                    } else \"Geometry\" === e ? (b = null, \"string\" === typeof a.path ? b = Id(a.path) : b = new td, b.type = Za(td, a.type), \"number\" === typeof a.startX && (b.startX = Uq(a.startX)), \"number\" === typeof a.startY && (b.startY =\n                        Uq(a.startY)), \"number\" === typeof a.endX && (b.endX = Uq(a.endX)), \"number\" === typeof a.endY && (b.endY = Uq(a.endY)), a.spot1 instanceof P && (b.spot1 = a.spot1), a.spot2 instanceof P && (b.spot2 = a.spot2), c = b) : \"EnumValue\" === e && (b = a.classType, 0 === b.indexOf(\"go.\") && (b = b.substr(3)), b = Vq(b), \"function\" === typeof b && (c = Za(b, a.name)));\n                    a = c\n                }\n            } return a\n    };\n    t.quote = function (a) {\n        for (var b = \"\", c = a.length, d = 0; d < c; d++) {\n            var e = a[d];\n            if ('\"' === e || \"\\\\\" === e) b += \"\\\\\" + e;\n            else if (\"\\b\" === e) b += \"\\\\b\";\n            else if (\"\\f\" === e) b += \"\\\\f\";\n            else if (\"\\n\" === e) b += \"\\\\n\";\n            else if (\"\\r\" === e) b += \"\\\\r\";\n            else if (\"\\t\" === e) b += \"\\\\t\";\n            else {\n                var f = a.charCodeAt(d);\n                b = 16 > f ? b + (\"\\\\u000\" + a.charCodeAt(d).toString(16)) : 32 > f ? b + (\"\\\\u00\" + a.charCodeAt(d).toString(16)) : 8232 === f ? b + \"\\\\u2028\" : 8233 === f ? b + \"\\\\u2029\" : b + e\n            }\n        }\n        return '\"' + b + '\"'\n    };\n    t.Lm = function (a) {\n        return void 0 === a ? \"undefined\" : null === a ? \"null\" : !0 === a ? \"true\" : !1 === a ? \"false\" : \"string\" === typeof a ? this.quote(a) : \"number\" === typeof a ? Infinity === a ? \"9e9999\" : -Infinity === a ? \"-9e9999\" : isNaN(a) ? '{\"class\":\"NaN\"}' : a.toString() : a instanceof Date ? '{\"class\":\"Date\", \"value\":\"' + a.toJSON() + '\"}' : a instanceof Number ? this.Lm(a.valueOf()) : Aa(a) ? Pq(this, a) : za(a) ? Mq(this, a) : \"function\" === typeof a ? \"null\" : a.toString()\n    };\n\n    function Pq(a, b, c) {\n        void 0 === c && (c = !1);\n        var d = b.length;\n        if (0 >= d) return \"[]\";\n        var e = new cb;\n        e.add(\"[ \");\n        c && 1 < d && e.add(\"\\n\");\n        for (var f = 0; f < d; f++) {\n            var g = b[f];\n            void 0 !== g && (0 < f && (e.add(\",\"), c && e.add(\"\\n\")), e.add(a.Lm(g)))\n        }\n        c && 1 < d && e.add(\"\\n\");\n        e.add(\" ]\");\n        return e.toString()\n    }\n\n    function Oq(a, b) {\n        return void 0 === b || \"__gohashid\" === a || \"_\" === a[0] || \"function\" === typeof b ? !0 : !1\n    }\n\n    function Wq(a) {\n        return isNaN(a) ? \"NaN\" : Infinity === a ? \"9e9999\" : -Infinity === a ? \"-9e9999\" : a\n    }\n\n    function Mq(a, b) {\n        var c = b;\n        if (c instanceof I) b = {\n            \"class\": \"go.Point\",\n            x: Wq(c.x),\n            y: Wq(c.y)\n        };\n        else if (c instanceof M) b = {\n            \"class\": \"go.Size\",\n            width: Wq(c.width),\n            height: Wq(c.height)\n        };\n        else if (c instanceof N) b = {\n            \"class\": \"go.Rect\",\n            x: Wq(c.x),\n            y: Wq(c.y),\n            width: Wq(c.width),\n            height: Wq(c.height)\n        };\n        else if (c instanceof oc) b = {\n            \"class\": \"go.Margin\",\n            top: Wq(c.top),\n            right: Wq(c.right),\n            bottom: Wq(c.bottom),\n            left: Wq(c.left)\n        };\n        else if (c instanceof P) c.eb() ? b = {\n                \"class\": \"go.Spot\",\n                x: Wq(c.x),\n                y: Wq(c.y),\n                offsetX: Wq(c.offsetX),\n                offsetY: Wq(c.offsetY)\n            } :\n            b = {\n                \"class\": \"go.Spot\",\n                \"enum\": c.toString()\n            };\n        else if (c instanceof tl) {\n            b = {\n                \"class\": \"go.Brush\",\n                type: c.type.name\n            };\n            if (c.type === wl) b.color = c.color;\n            else if (c.type === zl || c.type === ul) b.start = c.start, b.end = c.end, c.type === ul && (0 !== c.startRadius && (b.startRadius = Wq(c.startRadius)), isNaN(c.endRadius) || (b.endRadius = Wq(c.endRadius)));\n            if (null !== c.colorStops) {\n                var d = {};\n                for (c = c.colorStops.iterator; c.next();) d[c.key] = c.value;\n                b.colorStops = d\n            }\n        } else c instanceof td ? (b = {\n            \"class\": \"go.Geometry\",\n            type: c.type.name\n        }, 0 !== c.startX && (b.startX =\n            Wq(c.startX)), 0 !== c.startY && (b.startY = Wq(c.startY)), 0 !== c.endX && (b.endX = Wq(c.endX)), 0 !== c.endY && (b.endY = Wq(c.endY)), c.spot1.w(vc) || (b.spot1 = c.spot1), c.spot2.w(Gc) || (b.spot2 = c.spot2), c.type === ud && (b.path = zd(c))) : c instanceof D && (b = {\n            \"class\": \"go.EnumValue\",\n            classType: Sq(a, c.classType),\n            name: c.name\n        });\n        d = \"{\";\n        c = !0;\n        for (var e in b) {\n            var f = zn(b, e);\n            if (!Oq(e, f))\n                if (c ? c = !1 : d += \", \", d += '\"' + e + '\":', \"points\" === e && f instanceof E) {\n                    var g = \"[\";\n                    for (f = f.iterator; f.next();) {\n                        var h = f.value;\n                        1 < g.length && (g += \",\");\n                        g += a.Lm(h.x);\n                        g += \",\";\n                        g += a.Lm(h.y)\n                    }\n                    g += \"]\";\n                    d += g\n                } else d += a.Lm(f)\n        }\n        return d + \"}\"\n    }\n\n    function Uq(a) {\n        return \"number\" === typeof a ? a : \"NaN\" === a ? NaN : \"9e9999\" === a ? Infinity : \"-9e9999\" === a ? -Infinity : parseFloat(a)\n    }\n    t.Dh = function (a) {\n        this.Bu.add(a)\n    };\n    t.wk = function (a) {\n        this.Bu.remove(a)\n    };\n    t.bt = function (a) {\n        this.skipsUndoManager || this.undoManager.Cv(a);\n        for (var b = this.Bu, c = b.length, d = 0; d < c; d++) b.L(d)(a)\n    };\n    t.Ya = function (a, b, c, d, e, f, g) {\n        Xq(this, \"\", a, b, c, d, e, f, g)\n    };\n    t.g = function (a, b, c, d, e) {\n        Xq(this, \"\", re, a, this, b, c, d, e)\n    };\n    t.Ft = function (a, b, c, d, e, f) {\n        Xq(this, \"\", re, b, a, c, d, e, f)\n    };\n\n    function Xq(a, b, c, d, e, f, g, h, k) {\n        void 0 === h && (h = null);\n        void 0 === k && (k = null);\n        var l = new qe;\n        l.model = a;\n        l.change = c;\n        l.modelChange = b;\n        l.propertyName = d;\n        l.object = e;\n        l.oldValue = f;\n        l.oldParam = h;\n        l.newValue = g;\n        l.newParam = k;\n        a.bt(l)\n    }\n    Z.prototype.changeState = function (a, b) {\n        if (null !== a && a.model === this)\n            if (a.change === re) Qj(a.object, a.propertyName, a.H(b));\n            else if (a.change === te) {\n            var c = a.newParam;\n            if (\"nodeDataArray\" === a.modelChange) {\n                if (a = a.newValue, za(a) && \"number\" === typeof c) {\n                    var d = this.ja(a);\n                    b ? (this.Cc[c] === a && Da(this.Cc, c), void 0 !== d && this.ab.remove(d)) : (this.Cc[c] !== a && Ca(this.Cc, c, a), void 0 !== d && this.ab.add(d, a))\n                }\n            } else \"\" === a.modelChange ? ((d = a.object) && !Aa(d) && a.propertyName && (d = zn(a.object, a.propertyName)), Aa(d) && \"number\" === typeof c &&\n                (a = a.newValue, b ? Da(d, c) : Ca(d, c, a))) : B(\"unknown ChangedEvent.Insert modelChange: \" + a.toString())\n        } else a.change === ue ? (c = a.oldParam, \"nodeDataArray\" === a.modelChange ? (a = a.oldValue, za(a) && \"number\" === typeof c && (d = this.ja(a), b ? (this.Cc[c] !== a && Ca(this.Cc, c, a), void 0 !== d && this.ab.add(d, a)) : (this.Cc[c] === a && Da(this.Cc, c), void 0 !== d && this.ab.remove(d)))) : \"\" === a.modelChange ? ((d = a.object) && !Aa(d) && a.propertyName && (d = zn(a.object, a.propertyName)), Aa(d) && \"number\" === typeof c && (a = a.oldValue, b ? Ca(d, c, a) : Da(d, c))) : B(\"unknown ChangedEvent.Remove modelChange: \" +\n            a.toString())) : a.change !== se && B(\"unknown ChangedEvent: \" + a.toString())\n    };\n    Z.prototype.ua = function (a) {\n        return this.undoManager.ua(a)\n    };\n    Z.prototype.Ua = function (a) {\n        return this.undoManager.Ua(a)\n    };\n    Z.prototype.Bf = function () {\n        return this.undoManager.Bf()\n    };\n    Z.prototype.commit = function (a, b) {\n        void 0 === b && (b = \"\");\n        var c = this.skipsUndoManager;\n        null === b && (this.skipsUndoManager = !0, b = \"\");\n        this.undoManager.ua(b);\n        var d = !1;\n        try {\n            a(this), d = !0\n        } finally {\n            d ? this.undoManager.Ua(b) : this.undoManager.Bf(), this.skipsUndoManager = c\n        }\n    };\n    t = Z.prototype;\n    t.Ba = function (a, b) {\n        void 0 === b && (b = \"\");\n        Xq(this, \"SourceChanged\", se, b, a, null, null)\n    };\n    t.ja = function (a) {\n        if (null !== a) {\n            var b = this.Ai;\n            if (\"\" !== b && (b = zn(a, b), void 0 !== b)) {\n                if (yq(b)) return b;\n                B(\"Key value for node data \" + a + \" is not a number or a string: \" + b)\n            }\n        }\n    };\n    t.Hm = function (a, b) {\n        if (null !== a) {\n            var c = this.Ai;\n            if (\"\" !== c)\n                if (this.sb(a)) {\n                    var d = zn(a, c);\n                    d !== b && null === this.Ib(b) && (Qj(a, c, b), void 0 !== d && this.ab.remove(d), this.ab.add(b, a), Xq(this, \"nodeKey\", re, c, a, d, b), \"string\" === typeof c && this.Ba(a, c), this.Hq(d, b))\n                } else Qj(a, c, b)\n        }\n    };\n\n    function yq(a) {\n        return \"number\" === typeof a || \"string\" === typeof a\n    }\n    t.sb = function (a) {\n        var b = this.ja(a);\n        return void 0 === b ? !1 : this.ab.H(b) === a\n    };\n    t.Ib = function (a) {\n        null === a && B(\"Model.findNodeDataForKey:key must not be null\");\n        return void 0 !== a && yq(a) ? this.ab.H(a) : null\n    };\n    t.zt = function (a) {\n        if (null !== a) {\n            var b = this.Ai;\n            if (\"\" !== b) {\n                var c = this.ja(a);\n                if (void 0 === c || this.ab.contains(c)) {\n                    var d = this.wl;\n                    if (null !== d && (c = d(this, a), void 0 !== c && null !== c && !this.ab.contains(c))) {\n                        Qj(a, b, c);\n                        return\n                    }\n                    if (\"string\" === typeof c) {\n                        for (d = 2; this.ab.contains(c + d);) d++;\n                        Qj(a, b, c + d)\n                    } else if (void 0 === c || \"number\" === typeof c) {\n                        for (c = -this.ab.count - 1; this.ab.contains(c);) c--;\n                        Qj(a, b, c)\n                    }\n                }\n            }\n        }\n    };\n    t.pf = function (a) {\n        null !== a && (nb(a), this.sb(a) || qq(this, a, !0))\n    };\n\n    function qq(a, b, c) {\n        var d = a.ja(b);\n        if (void 0 === d || a.ab.H(d) !== b) a.zt(b), d = a.ja(b), void 0 === d ? B(\"Model.makeNodeDataKeyUnique failed on \" + b + \".  Data not added to Model.\") : (a.ab.add(d, b), d = null, c && (d = a.Cc.length, Ca(a.Cc, d, b)), Xq(a, \"nodeDataArray\", te, \"nodeDataArray\", a, null, b, null, d), a.Dm(b), a.Cm(b))\n    }\n    t.Jy = function (a) {\n        if (Aa(a))\n            for (var b = a.length, c = 0; c < b; c++) this.pf(a[c]);\n        else\n            for (a = a.iterator; a.next();) this.pf(a.value)\n    };\n    t.Am = function (a) {\n        null !== a && pq(this, a, !0)\n    };\n\n    function pq(a, b, c) {\n        var d = a.ja(b);\n        void 0 !== d && a.ab.remove(d);\n        d = null;\n        if (c) {\n            a: if (c = a.Cc, Array.isArray(c)) d = c.indexOf(b);\n                else {\n                    d = c.length;\n                    for (var e = 0; e < d; e++)\n                        if (c[e] === b) {\n                            d = e;\n                            break a\n                        } d = -1\n                }if (0 > d) return;Da(a.Cc, d)\n        }\n        Xq(a, \"nodeDataArray\", ue, \"nodeDataArray\", a, b, null, d, null);\n        a.Oq(b)\n    }\n    t.pA = function (a) {\n        if (Aa(a))\n            for (var b = a.length, c = 0; c < b; c++) this.Am(a[c]);\n        else\n            for (a = a.iterator; a.next();) this.Am(a.value)\n    };\n    t.gA = function (a) {\n        if (Aa(a)) {\n            for (var b = new F(this.ab.iteratorKeys), c = new F, d = a.length, e = 0; e < d; e++) {\n                var f = a[e],\n                    g = this.ja(f);\n                if (void 0 !== g) {\n                    c.add(g);\n                    var h = this.Ib(g);\n                    null !== h ? this.Xj(h, f) : (h = {}, this.Hm(h, g), this.Xj(h, f), this.pf(h))\n                } else this.pf(f), c.add(this.ja(f))\n            }\n            for (a = b.iterator; a.next();) b = a.value, c.contains(b) || (b = this.Ib(b)) && this.Am(b);\n            this.gq()\n        }\n    };\n    t.Hq = function (a, b) {\n        void 0 !== b && (a = Bq(this, a), a instanceof F && this.Rf.add(b, a))\n    };\n    t.sw = function () {};\n    t.Dm = function () {};\n    t.Cm = function () {};\n    t.Oq = function () {};\n\n    function Dq(a, b, c) {\n        if (void 0 !== b) {\n            var d = a.Rf.H(b);\n            null === d && (d = new F, a.Rf.add(b, d));\n            d.add(c)\n        }\n    }\n\n    function Cq(a, b, c) {\n        if (void 0 !== b) {\n            var d = a.Rf.H(b);\n            d instanceof F && (void 0 === c || null === c ? a.Rf.remove(b) : (d.remove(c), 0 === d.count && a.Rf.remove(b)))\n        }\n    }\n\n    function Bq(a, b) {\n        if (void 0 === b) return null;\n        a = a.Rf.H(b);\n        return a instanceof F ? a : null\n    }\n    t.gq = function (a) {\n        void 0 === a ? this.Rf.clear() : this.Rf.remove(a)\n    };\n    Z.prototype.copyNodeData = function (a) {\n        if (null === a) return null;\n        var b = this.Ok;\n        a = null !== b ? b(a, this) : Yq(this, a, !0);\n        za(a) && Ya(a);\n        return a\n    };\n\n    function Yq(a, b, c) {\n        if (a.copiesArrays && Array.isArray(b)) {\n            var d = [];\n            for (c = 0; c < b.length; c++) {\n                var e = Yq(a, b[c], a.copiesArrayObjects);\n                d.push(e)\n            }\n            Ya(d);\n            return d\n        }\n        if (c && za(b)) {\n            c = (c = b.constructor) ? new c : {};\n            e = a.copiesKey || \"string\" !== typeof a.nodeKeyProperty ? null : a.nodeKeyProperty;\n            for (d in b)\n                if (\"__gohashid\" === d) c.__gohashid = void 0;\n                else if (d === e) c[e] = void 0;\n            else {\n                var f = zn(b, d),\n                    g = Sq(a, f);\n                \"GraphObject\" === g || \"Diagram\" === g || \"Layer\" === g || \"RowColumnDefinition\" === g || \"AnimationManager\" === g || \"Tool\" === g || \"CommandHandler\" ===\n                    g || \"Layout\" === g || \"InputEvent\" === g || \"DiagramEvent\" === g || f instanceof Z || f instanceof we || f instanceof ve || f instanceof qe ? Qj(c, d, f) : (f = Yq(a, f, !1), Qj(c, d, f))\n            }\n            Ya(c);\n            return c\n        }\n        return b instanceof I ? b.copy() : b instanceof M ? b.copy() : b instanceof N ? b.copy() : b instanceof P ? b.copy() : b instanceof oc ? b.copy() : b\n    }\n    Z.prototype.setDataProperty = function (a, b, c) {\n        if (this.sb(a))\n            if (b === this.nodeKeyProperty) this.Hm(a, c);\n            else {\n                if (b === this.nodeCategoryProperty) {\n                    this.Jq(a, c);\n                    return\n                }\n            }\n        else !Zq && a instanceof Y && (Zq = !0, wa('Model.setDataProperty is modifying a GraphObject, \"' + a.toString() + '\"'), wa(\"  Is that really your intent?\"));\n        var d = zn(a, b);\n        d !== c && (Qj(a, b, c), this.Ft(a, b, d, c))\n    };\n    t = Z.prototype;\n    t.set = function (a, b, c) {\n        this.setDataProperty(a, b, c)\n    };\n    t.Xj = function (a, b) {\n        if (b) {\n            var c = this.sb(a),\n                d;\n            for (d in b) \"__gohashid\" === d || c && d === this.nodeKeyProperty || this.setDataProperty(a, d, b[d])\n        }\n    };\n    t.Fy = function (a, b) {\n        this.qt(a, -1, b)\n    };\n    t.qt = function (a, b, c) {\n        0 > b && (b = a.length);\n        Ca(a, b, c);\n        Xq(this, \"\", te, \"\", a, null, c, null, b)\n    };\n    t.Vv = function (a, b) {\n        void 0 === b && (b = -1);\n        a === this.Cc && B(\"Model.removeArrayItem should not be called on the Model.nodeDataArray\"); - 1 === b && (b = a.length - 1);\n        var c = a[b];\n        Da(a, b);\n        Xq(this, \"\", ue, \"\", a, c, null, b, null)\n    };\n    t.nt = function (a) {\n        if (null === a) return \"\";\n        var b = this.Gj;\n        if (\"\" === b) return \"\";\n        b = zn(a, b);\n        if (void 0 === b) return \"\";\n        if (\"string\" === typeof b) return b;\n        B(\"getCategoryForNodeData found a non-string category for \" + a + \": \" + b);\n        return \"\"\n    };\n    t.Jq = function (a, b) {\n        if (null !== a) {\n            var c = this.Gj;\n            if (\"\" !== c)\n                if (this.sb(a)) {\n                    var d = zn(a, c);\n                    void 0 === d && (d = \"\");\n                    d !== b && (Qj(a, c, b), Xq(this, \"nodeCategory\", re, c, a, d, b))\n                } else Qj(a, c, b)\n        }\n    };\n    t.qm = function () {\n        return !1\n    };\n    t.ik = function () {\n        return !1\n    };\n    t.pm = function () {\n        return !1\n    };\n    t.vt = function () {\n        return !1\n    };\n    t.jk = function () {\n        return !1\n    };\n\n    function Ai() {\n        return new Z\n    }\n\n    function Sq(a, b) {\n        if (\"function\" === typeof b) {\n            if (b.className) return b.className;\n            if (b.name) return b.name\n        } else if (\"object\" === typeof b && null !== b && b.constructor) return Sq(a, b.constructor);\n        return typeof b\n    }\n\n    function Vq(a) {\n        return $q[a] ? $q[a] : void 0 !== x.go && x.go[a] ? x.go[a] : null\n    }\n\n    function zn(a, b) {\n        if (!a || !b) return null;\n        try {\n            if (\"function\" === typeof b) var c = b(a);\n            else \"function\" === typeof a.getAttribute ? (c = a.getAttribute(b), null === c && (c = void 0)) : c = a[b]\n        } catch (d) {}\n        return c\n    }\n\n    function Qj(a, b, c) {\n        if (a && b) try {\n            \"function\" === typeof b ? b(a, c) : \"function\" === typeof a.setAttribute ? a.setAttribute(b, c) : a[b] = c\n        } catch (d) {}\n    }\n    ma.Object.defineProperties(Z.prototype, {\n        name: {\n            get: function () {\n                return this.Ra\n            },\n            set: function (a) {\n                var b = this.Ra;\n                b !== a && (this.Ra = a, this.g(\"name\", b, a))\n            }\n        },\n        dataFormat: {\n            get: function () {\n                return this.tn\n            },\n            set: function (a) {\n                var b = this.tn;\n                b !== a && (this.tn = a, this.g(\"dataFormat\", b, a))\n            }\n        },\n        isReadOnly: {\n            get: function () {\n                return this.Zf\n            },\n            set: function (a) {\n                var b = this.Zf;\n                b !== a && (this.Zf = a, this.g(\"isReadOnly\", b, a))\n            }\n        },\n        modelData: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                var b = this.l;\n                b !== a && (this.l = a, this.g(\"modelData\", b, a), this.Ba(a))\n            }\n        },\n        undoManager: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                var b = this.u;\n                b !== a && (null !== b && b.by(this), this.u = a, null !== a && a.ux(this))\n            }\n        },\n        skipsUndoManager: {\n            get: function () {\n                return this.sg\n            },\n            set: function (a) {\n                this.sg = a\n            }\n        },\n        nodeKeyProperty: {\n            get: function () {\n                return this.Ai\n            },\n            set: function (a) {\n                var b = this.Ai;\n                b !== a && (\"\" === a && B(\"Model.nodeKeyProperty may not be the empty string\"), 0 < this.ab.count && B(\"Cannot set Model.nodeKeyProperty when there is existing node data\"), this.Ai = a, this.g(\"nodeKeyProperty\", b, a))\n            }\n        },\n        makeUniqueKeyFunction: {\n            get: function () {\n                return this.wl\n            },\n            set: function (a) {\n                var b = this.wl;\n                b !== a && (this.wl = a, this.g(\"makeUniqueKeyFunction\", b, a))\n            }\n        },\n        nodeDataArray: {\n            get: function () {\n                return this.Cc\n            },\n            set: function (a) {\n                var b = this.Cc;\n                if (b !== a) {\n                    this.ab.clear();\n                    this.sw();\n                    for (var c = a.length, d = 0; d < c; d++) {\n                        var e = a[d];\n                        if (!za(e)) {\n                            B(\"Model.nodeDataArray must only contain Objects, not: \" + e);\n                            return\n                        }\n                        nb(e)\n                    }\n                    this.Cc = a;\n                    d = new E;\n                    for (e = 0; e < c; e++) {\n                        var f = a[e],\n                            g = this.ja(f);\n                        void 0 === g ? d.add(f) : null !== this.ab.H(g) ? d.add(f) : this.ab.add(g, f)\n                    }\n                    for (d = d.iterator; d.next();) e = d.value, this.zt(e), f = this.ja(e), void 0 !== f && this.ab.add(f, e);\n                    Xq(this, \"nodeDataArray\", re, \"nodeDataArray\", this, b, a);\n                    for (b = 0; b < c; b++) d = a[b], this.Dm(d), this.Cm(d);\n                    this.gq();\n                    Array.isArray(a) || (this.isReadOnly = !0)\n                }\n            }\n        },\n        copyNodeDataFunction: {\n            get: function () {\n                return this.Ok\n            },\n            set: function (a) {\n                var b = this.Ok;\n                b !== a && (this.Ok = a, this.g(\"copyNodeDataFunction\", b, a))\n            }\n        },\n        copiesArrays: {\n            get: function () {\n                return this.ln\n            },\n            set: function (a) {\n                var b = this.ln;\n                b !== a && (this.ln = a, this.g(\"copiesArrays\", b, a))\n            }\n        },\n        copiesArrayObjects: {\n            get: function () {\n                return this.kn\n            },\n            set: function (a) {\n                var b = this.kn;\n                b !== a && (this.kn = a, this.g(\"copiesArrayObjects\", b, a))\n            }\n        },\n        copiesKey: {\n            get: function () {\n                return this.nn\n            },\n            set: function (a) {\n                var b = this.nn;\n                b !== a && (this.nn = a, this.g(\"copiesKey\", b, a))\n            }\n        },\n        afterCopyFunction: {\n            get: function () {\n                return this.Sm\n            },\n            set: function (a) {\n                var b = this.Sm;\n                b !== a && (this.Sm = a, this.g(\"afterCopyFunction\", b, a))\n            }\n        },\n        nodeCategoryProperty: {\n            get: function () {\n                return this.Gj\n            },\n            set: function (a) {\n                var b = this.Gj;\n                b !== a && (this.Gj = a, this.g(\"nodeCategoryProperty\", b, a))\n            }\n        }\n    });\n    ma.Object.defineProperties(Z, {\n        type: {\n            get: function () {\n                return \"Model\"\n            }\n        }\n    });\n    Z.prototype.setCategoryForNodeData = Z.prototype.Jq;\n    Z.prototype.getCategoryForNodeData = Z.prototype.nt;\n    Z.prototype.removeArrayItem = Z.prototype.Vv;\n    Z.prototype.insertArrayItem = Z.prototype.qt;\n    Z.prototype.addArrayItem = Z.prototype.Fy;\n    Z.prototype.assignAllDataProperties = Z.prototype.Xj;\n    Z.prototype.set = Z.prototype.set;\n    Z.prototype.clearUnresolvedReferences = Z.prototype.gq;\n    Z.prototype.mergeNodeDataArray = Z.prototype.gA;\n    Z.prototype.removeNodeDataCollection = Z.prototype.pA;\n    Z.prototype.removeNodeData = Z.prototype.Am;\n    Z.prototype.addNodeDataCollection = Z.prototype.Jy;\n    Z.prototype.addNodeData = Z.prototype.pf;\n    Z.prototype.makeNodeDataKeyUnique = Z.prototype.zt;\n    Z.prototype.findNodeDataForKey = Z.prototype.Ib;\n    Z.prototype.containsNodeData = Z.prototype.sb;\n    Z.prototype.setKeyForNodeData = Z.prototype.Hm;\n    Z.prototype.getKeyForNodeData = Z.prototype.ja;\n    Z.prototype.updateTargetBindings = Z.prototype.Ba;\n    Z.prototype.commit = Z.prototype.commit;\n    Z.prototype.rollbackTransaction = Z.prototype.Bf;\n    Z.prototype.commitTransaction = Z.prototype.Ua;\n    Z.prototype.startTransaction = Z.prototype.ua;\n    Z.prototype.raiseDataChanged = Z.prototype.Ft;\n    Z.prototype.raiseChanged = Z.prototype.g;\n    Z.prototype.raiseChangedEvent = Z.prototype.Ya;\n    Z.prototype.removeChangedListener = Z.prototype.wk;\n    Z.prototype.addChangedListener = Z.prototype.Dh;\n    Z.prototype.writeJsonValue = Z.prototype.Lm;\n    Z.prototype.replaceJsonObjects = Z.prototype.Bm;\n    Z.prototype.applyIncrementalJSON = Z.prototype.Ny;\n    Z.prototype.applyIncrementalJson = Z.prototype.wx;\n    Z.prototype.toJSON = Z.prototype.toJSON;\n    Z.prototype.toJson = Z.prototype.Mq;\n    Z.prototype.toIncrementalJSON = Z.prototype.AA;\n    Z.prototype.toIncrementalJson = Z.prototype.qy;\n    Z.prototype.computeJsonDifference = Z.prototype.Ty;\n    Z.prototype.toIncrementalData = Z.prototype.zA;\n    Z.prototype.clear = Z.prototype.clear;\n    var Zq = !1,\n        $q = {};\n    Z.className = \"Model\";\n    Z.fromJSON = Z.fromJson = function (a, b) {\n        void 0 === b && (b = null);\n        var c = null;\n        if (\"string\" === typeof a) try {\n            c = x.JSON.parse(a)\n        } catch (f) {} else \"object\" === typeof a ? c = a : B(\"Unable to construct a Model from: \" + a);\n        if (null === b) {\n            a = null;\n            var d = c[\"class\"];\n            if (\"string\" === typeof d) try {\n                var e = null;\n                0 === d.indexOf(\"go.\") ? (d = d.substr(3), e = Vq(d)) : (e = Vq(d), null === e && (e = x[d]));\n                \"function\" === typeof e && (a = new e)\n            } catch (f) {}\n            null === a || a instanceof Z ? b = a : B(\"Unable to construct a Model of declared class: \" + c[\"class\"])\n        }\n        null === b && (b = Z.constructGraphLinksModel());\n        b.Eq(c);\n        b.Tv(c);\n        return b\n    };\n    Z.safePropertyValue = zn;\n    Z.safePropertySet = Qj;\n    $q.Brush = tl;\n    $q.ChangedEvent = qe;\n    $q.Geometry = td;\n    $q.Margin = oc;\n    $q.Panel = X;\n    $q.Point = I;\n    $q.Rect = N;\n    $q.Size = M;\n    $q.Spot = P;\n    $q.Transaction = ve;\n    $q.UndoManager = we;\n\n    function Ji(a, b, c) {\n        Ya(this);\n        this.s = !1;\n        void 0 === a && (a = \"\");\n        void 0 === b && (b = a);\n        void 0 === c && (c = null);\n        this.l = -1;\n        this.bd = null;\n        this.Wl = a;\n        this.Vl = this.Qp = 0;\n        this.Ms = null;\n        this.eo = !1;\n        this.Ol = b;\n        this.jn = c;\n        this.Eo = ar;\n        this.cn = null;\n        this.ou = new F\n    }\n    Ji.prototype.copy = function () {\n        var a = new Ji;\n        a.Wl = this.Wl;\n        a.Qp = this.Qp;\n        a.Vl = this.Vl;\n        a.Ms = this.Ms;\n        a.eo = this.eo;\n        a.Ol = this.Ol;\n        a.jn = this.jn;\n        a.Eo = this.Eo;\n        a.cn = this.cn;\n        return a\n    };\n    t = Ji.prototype;\n    t.cb = function (a) {\n        a.classType === Ji && (this.mode = a)\n    };\n    t.toString = function () {\n        return \"Binding(\" + this.targetProperty + \":\" + this.sourceProperty + (-1 !== this.gj ? \" \" + this.gj : \"\") + \" \" + this.mode.name + \")\"\n    };\n    t.freeze = function () {\n        this.s = !0;\n        return this\n    };\n    t.ea = function () {\n        this.s = !1;\n        return this\n    };\n    t.Vx = function (a) {\n        void 0 === a && (a = null);\n        this.mode = gn;\n        this.backConverter = a;\n        return this\n    };\n    t.Aq = function (a) {\n        void 0 === a && (a = \"\");\n        this.sourceName = a;\n        this.isToModel = !1;\n        return this\n    };\n    t.iA = function () {\n        this.sourceName = null;\n        this.isToModel = !0;\n        return this\n    };\n\n    function gl(a, b, c) {\n        a = a.sourceName;\n        return null === a || \"\" === a ? b : \"/\" === a ? c.part : \".\" === a ? c : \"..\" === a ? c.panel : b.Xa(a)\n    }\n    t.tw = function (a, b, c) {\n        var d = this.Ol;\n        if (void 0 === c || \"\" === d || d === c) {\n            c = this.Wl;\n            var e = this.jn;\n            if (null === e && \"\" === c) wa(\"Binding error: target property is the empty string: \" + this.toString());\n            else {\n                var f = b;\n                \"\" !== d && (f = zn(b, d));\n                if (void 0 !== f)\n                    if (null === e) \"\" !== c && Qj(a, c, f);\n                    else try {\n                        if (\"\" !== c) {\n                            var g = e(f, a);\n                            Qj(a, c, g)\n                        } else e(f, a)\n                    } catch (h) {}\n            }\n        }\n    };\n    t.Qq = function (a, b, c, d) {\n        if (this.Eo === gn) {\n            var e = this.Wl;\n            if (void 0 === c || e === c) {\n                c = this.Ol;\n                var f = this.cn,\n                    g = a;\n                \"\" !== e && (g = zn(a, e));\n                if (void 0 !== g && !this.ou.contains(a)) try {\n                    this.ou.add(a);\n                    var h = null !== d ? d.diagram : null,\n                        k = null !== h ? h.model : null;\n                    if (null === f)\n                        if (\"\" !== c) null !== k ? k.setDataProperty(b, c, g) : Qj(b, c, g);\n                        else {\n                            if (null !== k && null !== d && 0 <= d.itemIndex && null !== d.panel && Array.isArray(d.panel.itemArray)) {\n                                var l = d.itemIndex,\n                                    m = d.panel.itemArray;\n                                k.Vv(m, l);\n                                k.qt(m, l, g)\n                            }\n                        }\n                    else try {\n                        if (\"\" !== c) {\n                            var n = f(g, b, k);\n                            null !== k ? k.setDataProperty(b,\n                                c, n) : Qj(b, c, n)\n                        } else {\n                            var p = f(g, b, k);\n                            if (void 0 !== p && null !== k && null !== d && 0 <= d.itemIndex && null !== d.panel && Array.isArray(d.panel.itemArray)) {\n                                var r = d.itemIndex,\n                                    q = d.panel.itemArray;\n                                k.Vv(q, r);\n                                k.qt(q, r, p)\n                            }\n                        }\n                    } catch (u) {}\n                } finally {\n                    this.ou.remove(a)\n                }\n            }\n        }\n    };\n    ma.Object.defineProperties(Ji.prototype, {\n        gj: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.s && ua(this);\n                this.l = a\n            }\n        },\n        targetProperty: {\n            get: function () {\n                return this.Wl\n            },\n            set: function (a) {\n                this.s && ua(this);\n                this.Wl = a\n            }\n        },\n        sourceName: {\n            get: function () {\n                return this.Ms\n            },\n            set: function (a) {\n                this.s && ua(this);\n                this.Ms = a;\n                null !== a && (this.eo = !1)\n            }\n        },\n        isToModel: {\n            get: function () {\n                return this.eo\n            },\n            set: function (a) {\n                this.s &&\n                    ua(this);\n                this.eo = a\n            }\n        },\n        sourceProperty: {\n            get: function () {\n                return this.Ol\n            },\n            set: function (a) {\n                this.s && ua(this);\n                this.Ol = a\n            }\n        },\n        converter: {\n            get: function () {\n                return this.jn\n            },\n            set: function (a) {\n                this.s && ua(this);\n                this.jn = a\n            }\n        },\n        backConverter: {\n            get: function () {\n                return this.cn\n            },\n            set: function (a) {\n                this.s && ua(this);\n                this.cn = a\n            }\n        },\n        mode: {\n            get: function () {\n                return this.Eo\n            },\n            set: function (a) {\n                this.s && ua(this);\n                this.Eo = a\n            }\n        }\n    });\n    Ji.prototype.updateSource = Ji.prototype.Qq;\n    Ji.prototype.updateTarget = Ji.prototype.tw;\n    Ji.prototype.ofModel = Ji.prototype.iA;\n    Ji.prototype.ofObject = Ji.prototype.Aq;\n    Ji.prototype.makeTwoWay = Ji.prototype.Vx;\n    var ar = new D(Ji, \"OneWay\", 1),\n        gn = new D(Ji, \"TwoWay\", 2);\n    Ji.className = \"Binding\";\n    Ji.parseEnum = function (a, b) {\n        return function (c) {\n            c = Za(a, c);\n            return null === c ? b : c\n        }\n    };\n    Ji.toString = Ja;\n    Ji.OneWay = ar;\n    Ji.TwoWay = gn;\n\n    function br(a, b) {\n        Z.call(this);\n        this.Tt = ',\\n  \"insertedLinkKeys\": ';\n        this.Iw = ',\\n  \"modifiedLinkData\": ';\n        this.Vt = ',\\n  \"removedLinkKeys\": ';\n        this.Oc = [];\n        this.$f = new F;\n        this.ob = new H;\n        this.wi = \"\";\n        this.ij = this.Nk = this.xl = null;\n        this.Ve = \"from\";\n        this.We = \"to\";\n        this.Dj = this.Cj = \"\";\n        this.Bj = \"category\";\n        this.Ld = \"\";\n        this.Bl = \"isGroup\";\n        this.re = \"group\";\n        this.mn = !1;\n        void 0 !== a && (this.nodeDataArray = a);\n        void 0 !== b && (this.linkDataArray = b)\n    }\n    la(br, Z);\n    br.constructGraphLinksModel = Z.constructGraphLinksModel;\n    br.prototype.cloneProtected = function (a) {\n        Z.prototype.cloneProtected.call(this, a);\n        a.wi = this.wi;\n        a.xl = this.xl;\n        a.Nk = this.Nk;\n        a.Ve = this.Ve;\n        a.We = this.We;\n        a.Cj = this.Cj;\n        a.Dj = this.Dj;\n        a.Bj = this.Bj;\n        a.Ld = this.Ld;\n        a.Bl = this.Bl;\n        a.re = this.re;\n        a.mn = this.mn\n    };\n    t = br.prototype;\n    t.clear = function () {\n        Z.prototype.clear.call(this);\n        this.Oc = [];\n        this.ob.clear();\n        this.$f.clear()\n    };\n    t.toString = function (a) {\n        void 0 === a && (a = 0);\n        if (2 <= a) return this.Mq();\n        var b = (\"\" !== this.name ? this.name : \"\") + \" GraphLinksModel\";\n        if (0 < a) {\n            b += \"\\n node data:\";\n            a = this.nodeDataArray;\n            var c = a.length,\n                d;\n            for (d = 0; d < c; d++) {\n                var e = a[d];\n                b += \" \" + this.ja(e) + \":\" + Ja(e)\n            }\n            b += \"\\n link data:\";\n            a = this.linkDataArray;\n            c = a.length;\n            for (d = 0; d < c; d++) e = a[d], b += \" \" + wq(this, e, !0) + \"--\\x3e\" + wq(this, e, !1)\n        }\n        return b\n    };\n    t.xw = function (a, b) {\n        var c = Z.prototype.xw.call(this, a, b),\n            d = this,\n            e = new F,\n            f = new F,\n            g = new F,\n            h = this.Ph;\n        a.changes.each(function (a) {\n            a.model === d && (\"linkDataArray\" === a.modelChange ? a.change === te ? e.add(a.newValue) : a.change === ue && g.add(a.oldValue) : d.cd(a.object) ? f.add(a.object) : null !== a.object && (null !== a.object && h && h.contains(a.object) ? h.get(a.object).each(function (a) {\n                d.cd(a) && f.add(a)\n            }) : cr(d, a.object).each(function (a) {\n                f.add(a)\n            })))\n        });\n        var k = new F;\n        e.each(function (a) {\n            k.add(d.Vb(a));\n            b || f.add(a)\n        });\n        var l = new F;\n        g.each(function (a) {\n            l.add(d.Vb(a));\n            b && f.add(a)\n        });\n        a = d.cloneDeep(f.na());\n        0 < k.count && (null === c && (c = {}), b ? c.removedLinkKeys = k.na() : c.insertedLinkKeys = k.na());\n        0 < a.length && (null === c && (c = {}), c.modifiedLinkData = a);\n        0 < l.count && (null === c && (c = {}), b ? c.insertedLinkKeys = l.na() : c.removedLinkKeys = l.na());\n        return c\n    };\n    t.zk = function () {\n        var a = Z.prototype.zk.call(this),\n            b = \"\";\n        \"category\" !== this.linkCategoryProperty && \"string\" === typeof this.linkCategoryProperty && (b += ',\\n  \"linkCategoryProperty\": ' + this.quote(this.linkCategoryProperty));\n        \"\" !== this.linkKeyProperty && \"string\" === typeof this.linkKeyProperty && (b += ',\\n  \"linkKeyProperty\": ' + this.quote(this.linkKeyProperty));\n        \"from\" !== this.linkFromKeyProperty && \"string\" === typeof this.linkFromKeyProperty && (b += ',\\n  \"linkFromKeyProperty\": ' + this.quote(this.linkFromKeyProperty));\n        \"to\" !==\n        this.linkToKeyProperty && \"string\" === typeof this.linkToKeyProperty && (b += ',\\n  \"linkToKeyProperty\": ' + this.quote(this.linkToKeyProperty));\n        \"\" !== this.linkFromPortIdProperty && \"string\" === typeof this.linkFromPortIdProperty && (b += ',\\n  \"linkFromPortIdProperty\": ' + this.quote(this.linkFromPortIdProperty));\n        \"\" !== this.linkToPortIdProperty && \"string\" === typeof this.linkToPortIdProperty && (b += ',\\n  \"linkToPortIdProperty\": ' + this.quote(this.linkToPortIdProperty));\n        \"\" !== this.linkLabelKeysProperty && \"string\" === typeof this.linkLabelKeysProperty &&\n            (b += ',\\n  \"linkLabelKeysProperty\": ' + this.quote(this.linkLabelKeysProperty));\n        \"isGroup\" !== this.nodeIsGroupProperty && \"string\" === typeof this.nodeIsGroupProperty && (b += ',\\n  \"nodeIsGroupProperty\": ' + this.quote(this.nodeIsGroupProperty));\n        \"group\" !== this.nodeGroupKeyProperty && \"string\" === typeof this.nodeGroupKeyProperty && (b += ',\\n  \"nodeGroupKeyProperty\": ' + this.quote(this.nodeGroupKeyProperty));\n        return a + b\n    };\n    t.Eq = function (a) {\n        Z.prototype.Eq.call(this, a);\n        a.linkKeyProperty && (this.linkKeyProperty = a.linkKeyProperty);\n        a.linkFromKeyProperty && (this.linkFromKeyProperty = a.linkFromKeyProperty);\n        a.linkToKeyProperty && (this.linkToKeyProperty = a.linkToKeyProperty);\n        a.linkFromPortIdProperty && (this.linkFromPortIdProperty = a.linkFromPortIdProperty);\n        a.linkToPortIdProperty && (this.linkToPortIdProperty = a.linkToPortIdProperty);\n        a.linkCategoryProperty && (this.linkCategoryProperty = a.linkCategoryProperty);\n        a.linkLabelKeysProperty && (this.linkLabelKeysProperty =\n            a.linkLabelKeysProperty);\n        a.nodeIsGroupProperty && (this.nodeIsGroupProperty = a.nodeIsGroupProperty);\n        a.nodeGroupKeyProperty && (this.nodeGroupKeyProperty = a.nodeGroupKeyProperty)\n    };\n    t.yw = function () {\n        var a = Z.prototype.yw.call(this),\n            b = ',\\n  \"linkDataArray\": ' + Pq(this, this.linkDataArray, !0);\n        return a + b\n    };\n    t.Tv = function (a) {\n        Z.prototype.Tv.call(this, a);\n        a = a.linkDataArray;\n        Array.isArray(a) && (this.Bm(a), this.linkDataArray = a)\n    };\n    t.Rq = function (a) {\n        if (!(a instanceof br)) return B(\"Model.computeJsonDifference: newmodel must be a GraphLinksModel\"), \"\";\n        var b = Z.prototype.Rq.call(this, a);\n        Rq(this, a, \"linkKeyProperty\");\n        Rq(this, a, \"linkFromKeyProperty\");\n        Rq(this, a, \"linkToKeyProperty\");\n        Rq(this, a, \"linkLabelKeysProperty\");\n        Rq(this, a, \"nodeIsGroupProperty\");\n        Rq(this, a, \"nodeGroupKeyProperty\");\n        for (var c = new F, d = new F, e = (new F).addAll(this.ob.iteratorKeys), f = new H, g = a.linkDataArray, h = g.length, k = 0; k < h; k++) {\n            var l = g[k],\n                m = a.Vb(l);\n            if (void 0 !== m) {\n                e.remove(m);\n                var n = this.zg(m);\n                null === n ? (c.add(m), d.add(l)) : Qq(this, n, l, f) || d.add(l)\n            } else this.xq(l), m = this.Vb(l), c.add(m), d.add(l)\n        }\n        a = b;\n        0 < c.count && (a += this.Tt + Pq(this, c.na(), !0));\n        0 < d.count && (a += this.Iw + Pq(this, d.na(), !0));\n        0 < e.count && (a += this.Vt + Pq(this, e.na(), !0));\n        return a\n    };\n\n    function cr(a, b) {\n        for (var c = new F, d = 0; d < a.linkDataArray.length; d++) {\n            var e = a.linkDataArray[d];\n            Tq(a, b, e, e, c)\n        }\n        return c\n    }\n    t.ww = function (a, b) {\n        var c = Z.prototype.ww.call(this, a, b),\n            d = this,\n            e = new F,\n            f = new F,\n            g = new F,\n            h = this.Ph;\n        a.changes.each(function (a) {\n            a.model === d && (\"linkDataArray\" === a.modelChange ? a.change === te ? e.add(a.newValue) : a.change === ue && g.add(a.oldValue) : d.cd(a.object) ? f.add(a.object) : null !== a.object && (null !== a.object && h && h.contains(a.object) ? h.get(a.object).each(function (a) {\n                d.cd(a) && f.add(a)\n            }) : cr(d, a.object).each(function (a) {\n                f.add(a)\n            })))\n        });\n        var k = new F;\n        e.each(function (a) {\n            k.add(d.Vb(a));\n            b || f.add(a)\n        });\n        var l = new F;\n        g.each(function (a) {\n            l.add(d.Vb(a));\n            b && f.add(a)\n        });\n        a = c;\n        0 < k.count && (a += (b ? this.Vt : this.Tt) + Pq(this, k.na(), !0));\n        0 < f.count && (a += this.Iw + Pq(this, f.na(), !0));\n        0 < l.count && (a += (b ? this.Tt : this.Vt) + Pq(this, l.na(), !0));\n        return a\n    };\n    t.Dq = function (a) {\n        (void 0 !== a.linkCategoryProperty && a.linkCategoryProperty !== this.linkCategoryProperty || void 0 !== a.linkKeyProperty && a.linkKeyProperty !== this.linkKeyProperty || void 0 !== a.linkFromKeyProperty && a.linkFromKeyProperty !== this.linkFromKeyProperty || void 0 !== a.linkToKeyProperty && a.linkToKeyProperty !== this.linkToKeyProperty || void 0 !== a.linkFromPortIdProperty && a.linkFromPortIdProperty !== this.linkFromPortIdProperty || void 0 !== a.linkToPortIdProperty && a.linkToPortIdProperty !== this.linkToPortIdProperty ||\n            void 0 !== a.linkLabelKeysProperty && a.linkLabelKeysProperty !== this.linkLabelKeysProperty || void 0 !== a.nodeIsGroupProperty && a.nodeIsGroupProperty !== this.nodeIsGroupProperty || void 0 !== a.nodeGroupKeyProperty && a.nodeGroupKeyProperty !== this.nodeGroupKeyProperty) && B(\"applyIncrementalJson cannot change Model properties\");\n        Z.prototype.Dq.call(this, a);\n        var b = a.insertedLinkKeys;\n        if (Array.isArray(b))\n            for (var c = b.length, d = 0; d < c; d++) {\n                var e = b[d],\n                    f = this.zg(e);\n                null === f && (f = this.hq({}), this.Nt(f, e), this.Ni(f))\n            }\n        b = a.modifiedLinkData;\n        if (Array.isArray(b))\n            for (c = b.length, d = 0; d < c; d++)\n                if (e = b[d], f = this.Vb(e), f = this.zg(f), null !== f)\n                    for (var g in e) \"__gohashid\" !== g && g !== this.linkKeyProperty && this.setDataProperty(f, g, e[g]);\n        a = a.removedLinkKeys;\n        if (Array.isArray(a))\n            for (g = a.length, b = 0; b < g; b++) c = this.zg(a[b]), null !== c && this.zm(c)\n    };\n    br.prototype.changeState = function (a, b) {\n        if (a.change === te) {\n            var c = a.newParam;\n            if (\"linkDataArray\" === a.modelChange) {\n                a = a.newValue;\n                if (za(a) && \"number\" === typeof c) {\n                    var d = this.Vb(a);\n                    b ? (this.$f.remove(a), this.Oc[c] === a && this.Oc.splice(c, 1), void 0 !== d && this.ob.remove(d)) : (this.$f.add(a), this.Oc[c] !== a && this.Oc.splice(c, 0, a), void 0 !== d && this.ob.add(d, a))\n                }\n                return\n            }\n            if (\"linkLabelKeys\" === a.modelChange) {\n                d = this.Cg(a.object);\n                Array.isArray(d) && \"number\" === typeof c && (b ? (c = d.indexOf(a.newValue), 0 <= c && d.splice(c, 1)) : 0 > d.indexOf(a.newValue) &&\n                    d.splice(c, 0, a.newValue));\n                return\n            }\n        } else if (a.change === ue) {\n            c = a.oldParam;\n            if (\"linkDataArray\" === a.modelChange) {\n                a = a.oldValue;\n                za(a) && \"number\" === typeof c && (d = this.Vb(a), b ? (this.$f.add(a), this.Oc[c] !== a && this.Oc.splice(c, 0, a), void 0 !== d && this.ob.add(d, a)) : (this.$f.remove(a), this.Oc[c] === a && this.Oc.splice(c, 1), void 0 !== d && this.ob.remove(d)));\n                return\n            }\n            if (\"linkLabelKeys\" === a.modelChange) {\n                d = this.Cg(a.object);\n                Array.isArray(d) && \"number\" === typeof c && (b ? 0 > d.indexOf(a.newValue) && d.splice(c, 0, a.newValue) : (c = d.indexOf(a.newValue),\n                    0 <= c && d.splice(c, 1)));\n                return\n            }\n        }\n        Z.prototype.changeState.call(this, a, b)\n    };\n    t = br.prototype;\n    t.rm = function (a) {\n        if (void 0 !== a) {\n            var b = this.ij;\n            if (null !== b) {\n                var c = this.Ib(a);\n                null === c && (c = this.copyNodeData(b), Qj(c, this.nodeKeyProperty, a), this.pf(c))\n            }\n            return a\n        }\n    };\n    t.Cz = function (a) {\n        return wq(this, a, !0)\n    };\n    t.iy = function (a, b) {\n        Eq(this, a, b, !0)\n    };\n    t.Iz = function (a) {\n        return wq(this, a, !1)\n    };\n    t.my = function (a, b) {\n        Eq(this, a, b, !1)\n    };\n\n    function wq(a, b, c) {\n        if (null !== b && (a = c ? a.Ve : a.We, \"\" !== a && (a = zn(b, a), void 0 !== a))) {\n            if (yq(a)) return a;\n            B((c ? \"FromKey\" : \"ToKey\") + \" value for link data \" + b + \" is not a number or a string: \" + a)\n        }\n    }\n\n    function Eq(a, b, c, d) {\n        null === c && (c = void 0);\n        if (null !== b) {\n            var e = d ? a.Ve : a.We;\n            if (\"\" !== e)\n                if (c = a.rm(c), a.cd(b)) {\n                    var f = zn(b, e);\n                    f !== c && (Cq(a, f, b), Qj(b, e, c), null === a.Ib(c) && Dq(a, c, b), Xq(a, d ? \"linkFromKey\" : \"linkToKey\", re, e, b, f, c), \"string\" === typeof e && a.Ba(b, e))\n                } else Qj(b, e, c)\n        }\n    }\n    t.Dz = function (a) {\n        return vq(this, a, !0)\n    };\n    t.jy = function (a, b) {\n        Fq(this, a, b, !0)\n    };\n    t.Jz = function (a) {\n        return vq(this, a, !1)\n    };\n    t.ny = function (a, b) {\n        Fq(this, a, b, !1)\n    };\n\n    function vq(a, b, c) {\n        if (null === b) return \"\";\n        a = c ? a.Cj : a.Dj;\n        if (\"\" === a) return \"\";\n        b = zn(b, a);\n        return void 0 === b ? \"\" : b\n    }\n\n    function Fq(a, b, c, d) {\n        if (null !== b) {\n            var e = d ? a.Cj : a.Dj;\n            if (\"\" !== e)\n                if (a.cd(b)) {\n                    var f = zn(b, e);\n                    void 0 === f && (f = \"\");\n                    f !== c && (Qj(b, e, c), Xq(a, d ? \"linkFromPortId\" : \"linkToPortId\", re, e, b, f, c), \"string\" === typeof e && a.Ba(b, e))\n                } else Qj(b, e, c)\n        }\n    }\n    t.Cg = function (a) {\n        if (null === a) return dr;\n        var b = this.Ld;\n        if (\"\" === b) return dr;\n        a = zn(a, b);\n        return void 0 === a ? dr : a\n    };\n    t.dw = function (a, b) {\n        if (null !== a) {\n            var c = this.Ld;\n            if (\"\" !== c)\n                if (this.cd(a)) {\n                    var d = zn(a, c);\n                    void 0 === d && (d = dr);\n                    if (d !== b) {\n                        if (Array.isArray(d))\n                            for (var e = d.length, f = 0; f < e; f++) Cq(this, d[f], a);\n                        Qj(a, c, b);\n                        e = b.length;\n                        for (f = 0; f < e; f++) {\n                            var g = b[f];\n                            null === this.Ib(g) && Dq(this, g, a)\n                        }\n                        Xq(this, \"linkLabelKeys\", re, c, a, d, b);\n                        \"string\" === typeof c && this.Ba(a, c)\n                    }\n                } else Qj(a, c, b)\n        }\n    };\n    t.dv = function (a, b) {\n        if (null !== b && void 0 !== b && null !== a) {\n            var c = this.Ld;\n            if (\"\" !== c) {\n                var d = zn(a, c);\n                if (void 0 === d) c = [], c.push(b), this.dw(a, c);\n                else if (Array.isArray(d)) {\n                    var e = d.indexOf(b);\n                    0 <= e || (e = d.length, d.push(b), this.cd(a) && (null === this.Ib(b) && Dq(this, b, a), Xq(this, \"linkLabelKeys\", te, c, a, null, b, null, e)))\n                } else B(c + \" property is not an Array; cannot addLabelKeyForLinkData: \" + a)\n            }\n        }\n    };\n    t.ay = function (a, b) {\n        if (null !== b && void 0 !== b && null !== a) {\n            var c = this.Ld;\n            if (\"\" !== c) {\n                var d = zn(a, c);\n                if (Array.isArray(d)) {\n                    var e = d.indexOf(b);\n                    0 > e || (d.splice(e, 1), this.cd(a) && (Cq(this, b, a), Xq(this, \"linkLabelKeys\", ue, c, a, b, null, e, null)))\n                } else void 0 !== d && B(c + \" property is not an Array; cannot removeLabelKeyforLinkData: \" + a)\n            }\n        }\n    };\n    t.Vb = function (a) {\n        if (null !== a) {\n            var b = this.wi;\n            if (\"\" !== b && (b = zn(a, b), void 0 !== b)) {\n                if (yq(b)) return b;\n                B(\"Key value for link data \" + a + \" is not a number or a string: \" + b)\n            }\n        }\n    };\n    t.Nt = function (a, b) {\n        if (null !== a) {\n            var c = this.wi;\n            if (\"\" !== c)\n                if (this.cd(a)) {\n                    var d = zn(a, c);\n                    d !== b && null === this.zg(b) && (Qj(a, c, b), void 0 !== d && this.ob.remove(d), this.ob.add(b, a), Xq(this, \"linkKey\", re, c, a, d, b), \"string\" === typeof c && this.Ba(a, c))\n                } else Qj(a, c, b)\n        }\n    };\n    t.zg = function (a) {\n        null === a && B(\"GraphLinksModel.findLinkDataForKey:key must not be null\");\n        return void 0 !== a && yq(a) ? this.ob.H(a) : null\n    };\n    t.xq = function (a) {\n        if (null !== a) {\n            var b = this.wi;\n            if (\"\" !== b) {\n                var c = this.Vb(a);\n                if (void 0 === c || this.ob.contains(c)) {\n                    var d = this.xl;\n                    if (null !== d && (c = d(this, a), void 0 !== c && null !== c && !this.ob.contains(c))) {\n                        Qj(a, b, c);\n                        return\n                    }\n                    if (\"string\" === typeof c) {\n                        for (d = 2; this.ob.contains(c + d);) d++;\n                        Qj(a, b, c + d)\n                    } else if (void 0 === c || \"number\" === typeof c) {\n                        for (c = -this.ob.count - 1; this.ob.contains(c);) c--;\n                        Qj(a, b, c)\n                    }\n                }\n            }\n        }\n    };\n    t.cd = function (a) {\n        return null === a ? !1 : this.$f.contains(a)\n    };\n    t.Ni = function (a) {\n        null !== a && (nb(a), this.cd(a) || Aq(this, a, !0))\n    };\n\n    function Aq(a, b, c) {\n        if (\"\" !== a.linkKeyProperty) {\n            var d = a.Vb(b);\n            if (void 0 !== d && a.ob.H(d) === b) return;\n            a.xq(b);\n            d = a.Vb(b);\n            if (void 0 === d) {\n                B(\"GraphLinksModel.makeLinkDataKeyUnique failed on \" + b + \". Data not added to model.\");\n                return\n            }\n            a.ob.add(d, b)\n        }\n        a.$f.add(b);\n        d = null;\n        c && (d = a.Oc.length, a.Oc.splice(d, 0, b));\n        Xq(a, \"linkDataArray\", te, \"linkDataArray\", a, null, b, null, d);\n        er(a, b)\n    }\n    t.Iy = function (a) {\n        if (Array.isArray(a))\n            for (var b = a.length, c = 0; c < b; c++) this.Ni(a[c]);\n        else\n            for (a = a.iterator; a.next();) this.Ni(a.value)\n    };\n    t.zm = function (a) {\n        null !== a && zq(this, a, !0)\n    };\n\n    function zq(a, b, c) {\n        a.$f.remove(b);\n        var d = a.Vb(b);\n        void 0 !== d && a.ob.remove(d);\n        d = null;\n        if (c) {\n            d = a.Oc.indexOf(b);\n            if (0 > d) return;\n            a.Oc.splice(d, 1)\n        }\n        Xq(a, \"linkDataArray\", ue, \"linkDataArray\", a, b, null, d, null);\n        c = wq(a, b, !0);\n        Cq(a, c, b);\n        c = wq(a, b, !1);\n        Cq(a, c, b);\n        d = a.Cg(b);\n        if (Array.isArray(d))\n            for (var e = d.length, f = 0; f < e; f++) c = d[f], Cq(a, c, b)\n    }\n    t.nA = function (a) {\n        if (Array.isArray(a))\n            for (var b = a.length, c = 0; c < b; c++) this.zm(a[c]);\n        else\n            for (a = a.iterator; a.next();) this.zm(a.value)\n    };\n    t.fA = function (a) {\n        if (Aa(a)) {\n            for (var b = new F(this.ob.iteratorKeys), c = new F, d = a.length, e = 0; e < d; e++) {\n                var f = a[e],\n                    g = this.Vb(f);\n                if (void 0 !== g) {\n                    c.add(g);\n                    var h = this.zg(g);\n                    null !== h ? this.Xj(h, f) : (h = {}, this.Nt(h, g), this.Xj(h, f), this.Ni(h))\n                } else this.Ni(f), c.add(this.Vb(f))\n            }\n            for (a = b.iterator; a.next();) b = a.value, c.contains(b) || (b = this.zg(b)) && this.zm(b);\n            this.gq()\n        }\n    };\n\n    function er(a, b) {\n        var c = wq(a, b, !0);\n        c = a.rm(c);\n        null === a.Ib(c) && Dq(a, c, b);\n        c = wq(a, b, !1);\n        c = a.rm(c);\n        null === a.Ib(c) && Dq(a, c, b);\n        var d = a.Cg(b);\n        if (Array.isArray(d))\n            for (var e = d.length, f = 0; f < e; f++) c = d[f], null === a.Ib(c) && Dq(a, c, b)\n    }\n    t.hq = function (a) {\n        if (null === a) return null;\n        var b = this.Nk;\n        a = null !== b ? b(a, this) : Yq(this, a, !0);\n        za(a) && (Ya(a), \"\" !== this.Ve && Qj(a, this.Ve, void 0), \"\" !== this.We && Qj(a, this.We, void 0), \"\" !== this.Ld && Qj(a, this.Ld, []));\n        return a\n    };\n    t.Hv = function (a) {\n        if (null === a) return !1;\n        var b = this.Bl;\n        return \"\" === b ? !1 : zn(a, b) ? !0 : !1\n    };\n    t.Yi = function (a) {\n        if (null !== a) {\n            var b = this.re;\n            if (\"\" !== b && (b = zn(a, b), void 0 !== b)) {\n                if (yq(b)) return b;\n                B(\"GroupKey value for node data \" + a + \" is not a number or a string: \" + b)\n            }\n        }\n    };\n    t.Mt = function (a, b) {\n        null === b && (b = void 0);\n        if (null !== a) {\n            var c = this.re;\n            if (\"\" !== c)\n                if (this.sb(a)) {\n                    var d = zn(a, c);\n                    d !== b && (Cq(this, d, a), Qj(a, c, b), null === this.Ib(b) && Dq(this, b, a), Xq(this, \"nodeGroupKey\", re, c, a, d, b), \"string\" === typeof c && this.Ba(a, c))\n                } else Qj(a, c, b)\n        }\n    };\n    br.prototype.copyNodeData = function (a) {\n        if (null === a) return null;\n        a = Z.prototype.copyNodeData.call(this, a);\n        this.ak || \"\" === this.re || void 0 === zn(a, this.re) || Qj(a, this.re, void 0);\n        return a\n    };\n    br.prototype.setDataProperty = function (a, b, c) {\n        if (this.sb(a))\n            if (b === this.nodeKeyProperty) this.Hm(a, c);\n            else {\n                if (b === this.nodeCategoryProperty) {\n                    this.Jq(a, c);\n                    return\n                }\n                if (b === this.nodeGroupKeyProperty) {\n                    this.Mt(a, c);\n                    return\n                }\n            }\n        else if (this.cd(a)) {\n            if (b === this.linkFromKeyProperty) {\n                Eq(this, a, c, !0);\n                return\n            }\n            if (b === this.linkToKeyProperty) {\n                Eq(this, a, c, !1);\n                return\n            }\n            if (b === this.linkFromPortIdProperty) {\n                Fq(this, a, c, !0);\n                return\n            }\n            if (b === this.linkToPortIdProperty) {\n                Fq(this, a, c, !1);\n                return\n            }\n            if (b === this.linkKeyProperty) {\n                this.Nt(a, c);\n                return\n            }\n            if (b === this.linkCategoryProperty) {\n                this.Lt(a, c);\n                return\n            }\n            if (b === this.linkLabelKeysProperty) {\n                this.dw(a, c);\n                return\n            }\n        }\n        var d = zn(a, b);\n        d !== c && (Qj(a, b, c), this.Ft(a, b, d, c))\n    };\n    t = br.prototype;\n    t.Xj = function (a, b) {\n        if (b) {\n            var c = this.sb(a),\n                d = this.cd(a),\n                e;\n            for (e in b) \"__gohashid\" === e || c && e === this.nodeKeyProperty || c && e === this.nodeIsGroupProperty && zn(a, e) === b[e] || d && e === this.linkKeyProperty || this.setDataProperty(a, e, b[e])\n        }\n    };\n    t.Hq = function (a, b) {\n        Z.prototype.Hq.call(this, a, b);\n        for (var c = this.ab.iterator; c.next();) this.Zv(c.value, a, b);\n        for (c = this.$f.iterator; c.next();) {\n            var d = c.value,\n                e = a,\n                f = b;\n            if (wq(this, d, !0) === e) {\n                var g = this.Ve;\n                Qj(d, g, f);\n                Xq(this, \"linkFromKey\", re, g, d, e, f);\n                \"string\" === typeof g && this.Ba(d, g)\n            }\n            wq(this, d, !1) === e && (g = this.We, Qj(d, g, f), Xq(this, \"linkToKey\", re, g, d, e, f), \"string\" === typeof g && this.Ba(d, g));\n            g = this.Cg(d);\n            if (Array.isArray(g))\n                for (var h = g.length, k = this.Ld, l = 0; l < h; l++) g[l] === e && (g[l] = f, Xq(this, \"linkLabelKeys\", te,\n                    k, d, e, f, l, l))\n        }\n    };\n    t.Zv = function (a, b, c) {\n        if (this.Yi(a) === b) {\n            var d = this.re;\n            Qj(a, d, c);\n            Xq(this, \"nodeGroupKey\", re, d, a, b, c);\n            \"string\" === typeof d && this.Ba(a, d)\n        }\n    };\n    t.sw = function () {\n        Z.prototype.sw.call(this);\n        for (var a = this.linkDataArray, b = a.length, c = 0; c < b; c++) er(this, a[c])\n    };\n    t.Dm = function (a) {\n        Z.prototype.Dm.call(this, a);\n        a = this.ja(a);\n        var b = Bq(this, a);\n        if (null !== b) {\n            var c = Fa();\n            for (b = b.iterator; b.next();) {\n                var d = b.value;\n                if (this.sb(d)) {\n                    if (this.Yi(d) === a) {\n                        var e = this.re;\n                        Xq(this, \"nodeGroupKey\", re, e, d, a, a);\n                        \"string\" === typeof e && this.Ba(d, e);\n                        c.push(d)\n                    }\n                } else if (wq(this, d, !0) === a && (e = this.Ve, Xq(this, \"linkFromKey\", re, e, d, a, a), \"string\" === typeof e && this.Ba(d, e), c.push(d)), wq(this, d, !1) === a && (e = this.We, Xq(this, \"linkToKey\", re, e, d, a, a), \"string\" === typeof e && this.Ba(d, e), c.push(d)), e = this.Cg(d),\n                    Array.isArray(e))\n                    for (var f = e.length, g = this.Ld, h = 0; h < f; h++) e[h] === a && (Xq(this, \"linkLabelKeys\", te, g, d, a, a, h, h), c.push(d))\n            }\n            for (b = 0; b < c.length; b++) Cq(this, a, c[b]);\n            Ha(c)\n        }\n    };\n    t.Cm = function (a) {\n        Z.prototype.Cm.call(this, a);\n        var b = this.Yi(a);\n        null === this.Ib(b) && Dq(this, b, a)\n    };\n    t.Oq = function (a) {\n        Z.prototype.Oq.call(this, a);\n        var b = this.Yi(a);\n        Cq(this, b, a)\n    };\n    t.wv = function (a) {\n        if (null === a) return \"\";\n        var b = this.Bj;\n        if (\"\" === b) return \"\";\n        b = zn(a, b);\n        if (void 0 === b) return \"\";\n        if (\"string\" === typeof b) return b;\n        B(\"getCategoryForLinkData found a non-string category for \" + a + \": \" + b);\n        return \"\"\n    };\n    br.prototype.getLinkCategoryForData = function (a) {\n        return this.wv(a)\n    };\n    br.prototype.Lt = function (a, b) {\n        if (null !== a) {\n            var c = this.Bj;\n            if (\"\" !== c)\n                if (this.cd(a)) {\n                    var d = zn(a, c);\n                    void 0 === d && (d = \"\");\n                    d !== b && (Qj(a, c, b), Xq(this, \"linkCategory\", re, c, a, d, b), \"string\" === typeof c && this.Ba(a, c))\n                } else Qj(a, c, b)\n        }\n    };\n    br.prototype.setLinkCategoryForData = function (a, b) {\n        this.Lt(a, b)\n    };\n    br.prototype.ik = function () {\n        return !0\n    };\n    br.prototype.pm = function () {\n        return !0\n    };\n    br.prototype.vt = function () {\n        return !0\n    };\n    br.prototype.jk = function () {\n        return !0\n    };\n    ma.Object.defineProperties(br.prototype, {\n        archetypeNodeData: {\n            get: function () {\n                return this.ij\n            },\n            set: function (a) {\n                var b = this.ij;\n                b !== a && (this.ij = a, this.g(\"archetypeNodeData\", b, a))\n            }\n        },\n        linkFromKeyProperty: {\n            get: function () {\n                return this.Ve\n            },\n            set: function (a) {\n                var b = this.Ve;\n                b !== a && (this.Ve = a, this.g(\"linkFromKeyProperty\", b, a))\n            }\n        },\n        linkToKeyProperty: {\n            get: function () {\n                return this.We\n            },\n            set: function (a) {\n                var b = this.We;\n                b !== a && (this.We = a, this.g(\"linkToKeyProperty\",\n                    b, a))\n            }\n        },\n        linkFromPortIdProperty: {\n            get: function () {\n                return this.Cj\n            },\n            set: function (a) {\n                var b = this.Cj;\n                b !== a && (this.Cj = a, this.g(\"linkFromPortIdProperty\", b, a))\n            }\n        },\n        linkToPortIdProperty: {\n            get: function () {\n                return this.Dj\n            },\n            set: function (a) {\n                var b = this.Dj;\n                b !== a && (this.Dj = a, this.g(\"linkToPortIdProperty\", b, a))\n            }\n        },\n        linkLabelKeysProperty: {\n            get: function () {\n                return this.Ld\n            },\n            set: function (a) {\n                var b = this.Ld;\n                b !== a && (this.Ld = a, this.g(\"linkLabelKeysProperty\",\n                    b, a))\n            }\n        },\n        linkDataArray: {\n            get: function () {\n                return this.Oc\n            },\n            set: function (a) {\n                var b = this.Oc;\n                if (b !== a) {\n                    this.ob.clear();\n                    for (var c = a.length, d = 0; d < c; d++) {\n                        var e = a[d];\n                        if (!za(e)) {\n                            B(\"GraphLinksModel.linkDataArray must only contain Objects, not: \" + e);\n                            return\n                        }\n                        nb(e)\n                    }\n                    this.Oc = a;\n                    if (\"\" !== this.linkKeyProperty) {\n                        d = new E;\n                        for (e = 0; e < c; e++) {\n                            var f = a[e],\n                                g = this.Vb(f);\n                            void 0 === g ? d.add(f) : null !== this.ob.H(g) ? d.add(f) : this.ob.add(g, f)\n                        }\n                        for (d = d.iterator; d.next();) e = d.value, this.xq(e), f = this.Vb(e), void 0 !==\n                            f && this.ob.add(f, e)\n                    }\n                    d = new F;\n                    for (e = 0; e < c; e++) d.add(a[e]);\n                    this.$f = d;\n                    Xq(this, \"linkDataArray\", re, \"linkDataArray\", this, b, a);\n                    for (b = 0; b < c; b++) er(this, a[b])\n                }\n            }\n        },\n        linkKeyProperty: {\n            get: function () {\n                return this.wi\n            },\n            set: function (a) {\n                var b = this.wi;\n                if (b !== a) {\n                    this.wi = a;\n                    this.ob.clear();\n                    for (var c = this.linkDataArray.length, d = 0; d < c; d++) {\n                        var e = this.linkDataArray[d],\n                            f = this.Vb(e);\n                        void 0 === f && (this.xq(e), f = this.Vb(e));\n                        void 0 !== f && this.ob.add(f, e)\n                    }\n                    this.g(\"linkKeyProperty\", b, a)\n                }\n            }\n        },\n        makeUniqueLinkKeyFunction: {\n            get: function () {\n                return this.xl\n            },\n            set: function (a) {\n                var b = this.xl;\n                b !== a && (this.xl = a, this.g(\"makeUniqueLinkKeyFunction\", b, a))\n            }\n        },\n        copyLinkDataFunction: {\n            get: function () {\n                return this.Nk\n            },\n            set: function (a) {\n                var b = this.Nk;\n                b !== a && (this.Nk = a, this.g(\"copyLinkDataFunction\", b, a))\n            }\n        },\n        nodeIsGroupProperty: {\n            get: function () {\n                return this.Bl\n            },\n            set: function (a) {\n                var b = this.Bl;\n                b !== a && (this.Bl = a, this.g(\"nodeIsGroupProperty\", b, a))\n            }\n        },\n        nodeGroupKeyProperty: {\n            get: function () {\n                return this.re\n            },\n            set: function (a) {\n                var b = this.re;\n                b !== a && (this.re = a, this.g(\"nodeGroupKeyProperty\", b, a))\n            }\n        },\n        ak: {\n            get: function () {\n                return this.mn\n            },\n            set: function (a) {\n                this.mn !== a && (this.mn = a)\n            }\n        },\n        linkCategoryProperty: {\n            get: function () {\n                return this.Bj\n            },\n            set: function (a) {\n                var b = this.Bj;\n                b !== a && (this.Bj = a, this.g(\"linkCategoryProperty\", b, a))\n            }\n        }\n    });\n    ma.Object.defineProperties(br, {\n        type: {\n            get: function () {\n                return \"GraphLinksModel\"\n            }\n        }\n    });\n    br.prototype.setCategoryForLinkData = br.prototype.Lt;\n    br.prototype.getCategoryForLinkData = br.prototype.wv;\n    br.prototype.assignAllDataProperties = br.prototype.Xj;\n    br.prototype.setGroupKeyForNodeData = br.prototype.Mt;\n    br.prototype.getGroupKeyForNodeData = br.prototype.Yi;\n    br.prototype.isGroupForNodeData = br.prototype.Hv;\n    br.prototype.copyLinkData = br.prototype.hq;\n    br.prototype.mergeLinkDataArray = br.prototype.fA;\n    br.prototype.removeLinkDataCollection = br.prototype.nA;\n    br.prototype.removeLinkData = br.prototype.zm;\n    br.prototype.addLinkDataCollection = br.prototype.Iy;\n    br.prototype.addLinkData = br.prototype.Ni;\n    br.prototype.containsLinkData = br.prototype.cd;\n    br.prototype.makeLinkDataKeyUnique = br.prototype.xq;\n    br.prototype.findLinkDataForKey = br.prototype.zg;\n    br.prototype.setKeyForLinkData = br.prototype.Nt;\n    br.prototype.getKeyForLinkData = br.prototype.Vb;\n    br.prototype.removeLabelKeyForLinkData = br.prototype.ay;\n    br.prototype.addLabelKeyForLinkData = br.prototype.dv;\n    br.prototype.setLabelKeysForLinkData = br.prototype.dw;\n    br.prototype.getLabelKeysForLinkData = br.prototype.Cg;\n    br.prototype.setToPortIdForLinkData = br.prototype.ny;\n    br.prototype.getToPortIdForLinkData = br.prototype.Jz;\n    br.prototype.setFromPortIdForLinkData = br.prototype.jy;\n    br.prototype.getFromPortIdForLinkData = br.prototype.Dz;\n    br.prototype.setToKeyForLinkData = br.prototype.my;\n    br.prototype.getToKeyForLinkData = br.prototype.Iz;\n    br.prototype.setFromKeyForLinkData = br.prototype.iy;\n    br.prototype.getFromKeyForLinkData = br.prototype.Cz;\n    br.prototype.clear = br.prototype.clear;\n    var dr = Object.freeze([]);\n    br.className = \"GraphLinksModel\";\n    $q.GraphLinksModel = br;\n    Z.constructGraphLinksModel = Z.constructGraphLinksModel = function () {\n        return new br\n    };\n    Z.initDiagramModel = Ai = function () {\n        return new br\n    };\n\n    function fr(a) {\n        Z.call(this);\n        this.se = \"parent\";\n        this.on = !1;\n        this.Ij = \"parentLinkCategory\";\n        void 0 !== a && (this.nodeDataArray = a)\n    }\n    la(fr, Z);\n    fr.constructGraphLinksModel = Z.constructGraphLinksModel;\n    fr.prototype.cloneProtected = function (a) {\n        Z.prototype.cloneProtected.call(this, a);\n        a.se = this.se;\n        a.on = this.on;\n        a.Ij = this.Ij\n    };\n    t = fr.prototype;\n    t.toString = function (a) {\n        void 0 === a && (a = 0);\n        if (2 <= a) return this.Mq();\n        var b = (\"\" !== this.name ? this.name : \"\") + \" TreeModel\";\n        if (0 < a) {\n            b += \"\\n node data:\";\n            a = this.nodeDataArray;\n            for (var c = a.length, d = 0; d < c; d++) {\n                var e = a[d];\n                b += \" \" + this.ja(e) + \":\" + Ja(e)\n            }\n        }\n        return b\n    };\n    t.zk = function () {\n        var a = Z.prototype.zk.call(this),\n            b = \"\";\n        \"parent\" !== this.nodeParentKeyProperty && \"string\" === typeof this.nodeParentKeyProperty && (b += ',\\n  \"nodeParentKeyProperty\": ' + this.quote(this.nodeParentKeyProperty));\n        return a + b\n    };\n    t.Eq = function (a) {\n        Z.prototype.Eq.call(this, a);\n        a.nodeParentKeyProperty && (this.nodeParentKeyProperty = a.nodeParentKeyProperty)\n    };\n    t.Rq = function (a) {\n        Rq(this, a, \"nodeParentKeyProperty\");\n        return Z.prototype.Rq.call(this, a)\n    };\n    t.Dq = function (a) {\n        void 0 !== a.nodeParentKeyProperty && a.nodeParentKeyProperty !== this.nodeParentKeyProperty && B(\"applyIncrementalJson cannot change Model properties\");\n        Z.prototype.Dq.call(this, a)\n    };\n    t.rm = function (a) {\n        return a\n    };\n    t.$i = function (a) {\n        if (null !== a) {\n            var b = this.se;\n            if (\"\" !== b && (b = zn(a, b), void 0 !== b)) {\n                if (yq(b)) return b;\n                B(\"ParentKey value for node data \" + a + \" is not a number or a string: \" + b)\n            }\n        }\n    };\n    t.Ge = function (a, b) {\n        null === b && (b = void 0);\n        if (null !== a) {\n            var c = this.se;\n            if (\"\" !== c)\n                if (b = this.rm(b), this.sb(a)) {\n                    var d = zn(a, c);\n                    d !== b && (Cq(this, d, a), Qj(a, c, b), null === this.Ib(b) && Dq(this, b, a), Xq(this, \"nodeParentKey\", re, c, a, d, b), \"string\" === typeof c && this.Ba(a, c))\n                } else Qj(a, c, b)\n        }\n    };\n    t.xv = function (a) {\n        if (null === a) return \"\";\n        var b = this.Ij;\n        if (\"\" === b) return \"\";\n        b = zn(a, b);\n        if (void 0 === b) return \"\";\n        if (\"string\" === typeof b) return b;\n        B(\"getParentLinkCategoryForNodeData found a non-string category for \" + a + \": \" + b);\n        return \"\"\n    };\n    fr.prototype.getLinkCategoryForData = function (a) {\n        return this.xv(a)\n    };\n    fr.prototype.ew = function (a, b) {\n        if (null !== a) {\n            var c = this.Ij;\n            if (\"\" !== c)\n                if (this.sb(a)) {\n                    var d = zn(a, c);\n                    void 0 === d && (d = \"\");\n                    d !== b && (Qj(a, c, b), Xq(this, \"parentLinkCategory\", re, c, a, d, b), \"string\" === typeof c && this.Ba(a, c))\n                } else Qj(a, c, b)\n        }\n    };\n    fr.prototype.setLinkCategoryForData = function (a, b) {\n        this.ew(a, b)\n    };\n    fr.prototype.copyNodeData = function (a) {\n        if (null === a) return null;\n        a = Z.prototype.copyNodeData.call(this, a);\n        this.bk || \"\" === this.se || void 0 === zn(a, this.se) || Qj(a, this.se, void 0);\n        return a\n    };\n    fr.prototype.setDataProperty = function (a, b, c) {\n        if (this.sb(a))\n            if (b === this.nodeKeyProperty) this.Hm(a, c);\n            else {\n                if (b === this.nodeCategoryProperty) {\n                    this.Jq(a, c);\n                    return\n                }\n                if (b === this.nodeParentKeyProperty) {\n                    this.Ge(a, c);\n                    return\n                }\n            } var d = zn(a, b);\n        d !== c && (Qj(a, b, c), this.Ft(a, b, d, c))\n    };\n    t = fr.prototype;\n    t.Hq = function (a, b) {\n        Z.prototype.Hq.call(this, a, b);\n        for (var c = this.ab.iterator; c.next();) this.Zv(c.value, a, b)\n    };\n    t.Zv = function (a, b, c) {\n        if (this.$i(a) === b) {\n            var d = this.se;\n            Qj(a, d, c);\n            Xq(this, \"nodeParentKey\", re, d, a, b, c);\n            \"string\" === typeof d && this.Ba(a, d)\n        }\n    };\n    t.Dm = function (a) {\n        Z.prototype.Dm.call(this, a);\n        a = this.ja(a);\n        var b = Bq(this, a);\n        if (null !== b) {\n            var c = Fa();\n            for (b = b.iterator; b.next();) {\n                var d = b.value;\n                if (this.sb(d) && this.$i(d) === a) {\n                    var e = this.se;\n                    Xq(this, \"nodeParentKey\", re, e, d, a, a);\n                    \"string\" === typeof e && this.Ba(d, e);\n                    c.push(d)\n                }\n            }\n            for (b = 0; b < c.length; b++) Cq(this, a, c[b]);\n            Ha(c)\n        }\n    };\n    t.Cm = function (a) {\n        Z.prototype.Cm.call(this, a);\n        var b = this.$i(a);\n        b = this.rm(b);\n        null === this.Ib(b) && Dq(this, b, a)\n    };\n    t.Oq = function (a) {\n        Z.prototype.Oq.call(this, a);\n        var b = this.$i(a);\n        Cq(this, b, a)\n    };\n    t.qm = function () {\n        return !0\n    };\n    t.vt = function () {\n        return !0\n    };\n    ma.Object.defineProperties(fr.prototype, {\n        nodeParentKeyProperty: {\n            get: function () {\n                return this.se\n            },\n            set: function (a) {\n                var b = this.se;\n                b !== a && (this.se = a, this.g(\"nodeParentKeyProperty\", b, a))\n            }\n        },\n        bk: {\n            get: function () {\n                return this.on\n            },\n            set: function (a) {\n                this.on !== a && (this.on = a)\n            }\n        },\n        parentLinkCategoryProperty: {\n            get: function () {\n                return this.Ij\n            },\n            set: function (a) {\n                var b = this.Ij;\n                b !== a && (this.Ij = a, this.g(\"parentLinkCategoryProperty\", b, a))\n            }\n        },\n        linkCategoryProperty: {\n            get: function () {\n                return this.parentLinkCategoryProperty\n            },\n            set: function (a) {\n                this.parentLinkCategoryProperty = a\n            }\n        }\n    });\n    ma.Object.defineProperties(fr, {\n        type: {\n            get: function () {\n                return \"TreeModel\"\n            }\n        }\n    });\n    fr.prototype.setParentLinkCategoryForNodeData = fr.prototype.ew;\n    fr.prototype.getParentLinkCategoryForNodeData = fr.prototype.xv;\n    fr.prototype.setParentKeyForNodeData = fr.prototype.Ge;\n    fr.prototype.getParentKeyForNodeData = fr.prototype.$i;\n    fr.className = \"TreeModel\";\n    $q.TreeModel = fr;\n\n    function gr() {\n        Ci.call(this);\n        this.Tw = this.Cn = this.$b = 0;\n        this.Ar = 360;\n        this.Sw = hr;\n        this.qj = 0;\n        this.Kw = new I;\n        this.lr = this.Sd = 0;\n        this.Ys = new ir;\n        this.bu = this.Hj = 0;\n        this.zy = 600;\n        this.gp = NaN;\n        this.Ym = 1;\n        this.Lp = 0;\n        this.Tl = 360;\n        this.Ab = hr;\n        this.J = kr;\n        this.Qc = lr;\n        this.Kc = $p;\n        this.ef = 6;\n        this.Qo = mr\n    }\n    la(gr, Ci);\n    gr.prototype.cloneProtected = function (a) {\n        Ci.prototype.cloneProtected.call(this, a);\n        a.gp = this.gp;\n        a.Ym = this.Ym;\n        a.Lp = this.Lp;\n        a.Tl = this.Tl;\n        a.Ab = this.Ab;\n        a.J = this.J;\n        a.Qc = this.Qc;\n        a.Kc = this.Kc;\n        a.ef = this.ef;\n        a.Qo = this.Qo\n    };\n    gr.prototype.cb = function (a) {\n        if (a.classType === gr)\n            if (a === nr || a === or || a === pr || a === qr || a === lr) this.sorting = a;\n            else if (a === rr || a === sr || a === kr || a === tr) this.direction = a;\n        else if (a === ur || a === vr || a === hr || a === wr) this.arrangement = a;\n        else {\n            if (a === xr || a === mr) this.nodeDiameterFormula = a\n        } else Ci.prototype.cb.call(this, a)\n    };\n    gr.prototype.createNetwork = function () {\n        return new yr(this)\n    };\n    gr.prototype.doLayout = function (a) {\n        null === this.network && (this.network = this.makeNetwork(a));\n        this.arrangementOrigin = this.initialOrigin(this.arrangementOrigin);\n        a = this.network.vertexes;\n        if (1 >= a.count) 1 === a.count && (a = a.first(), a.centerX = 0, a.centerY = 0);\n        else {\n            var b = new E;\n            b.addAll(a.iterator);\n            a = new E;\n            var c = new E;\n            var d = this.sort(b);\n            var e, f, g = this.lr;\n            var h = this.arrangement;\n            var k = this.nodeDiameterFormula;\n            var l = this.radius;\n            if (!isFinite(l) || 0 >= l) l = NaN;\n            var m = this.aspectRatio;\n            if (!isFinite(m) || 0 >= m) m = 1;\n            var n = this.startAngle;\n            isFinite(n) || (n = 0);\n            var p = this.sweepAngle;\n            if (!isFinite(p) || 360 < p || 1 > p) p = 360;\n            b = this.spacing;\n            isFinite(b) || (b = NaN);\n            h === wr && k === xr ? h = hr : h === wr && k !== xr && (h = this.arrangement);\n            if ((this.direction === rr || this.direction === sr) && this.sorting !== lr) {\n                for (k = 0; !(k >= d.length); k += 2) {\n                    a.add(d.L(k));\n                    if (k + 1 >= d.length) break;\n                    c.add(d.L(k + 1))\n                }\n                this.direction === rr ? (this.arrangement === wr && a.reverse(), d = new E, d.addAll(a), d.addAll(c)) : (this.arrangement === wr && c.reverse(), d = new E, d.addAll(c), d.addAll(a))\n            }\n            k = d.length;\n            for (var r = f = e = 0; r <\n                d.length; r++) {\n                var q = n + p * f * (this.direction === kr ? 1 : -1) / k,\n                    u = d.L(r).diameter;\n                isNaN(u) && (u = zr(d.L(r), q));\n                360 > p && (0 === r || r === d.length - 1) && (u /= 2);\n                e += u;\n                f++\n            }\n            if (isNaN(l) || h === wr) {\n                isNaN(b) && (b = 6);\n                if (h !== hr && h !== wr) {\n                    f = -Infinity;\n                    for (g = 0; g < k; g++) r = d.L(g), e = d.L(g === k - 1 ? 0 : g + 1), isNaN(r.diameter) && zr(r, 0), isNaN(e.diameter) && zr(e, 0), f = Math.max(f, (r.diameter + e.diameter) / 2);\n                    g = f + b;\n                    h === ur ? l = (f + b) / (2 * Math.PI / k) : l = Ar(this, g * (360 <= p ? k : k - 1), m, n * Math.PI / 180, p * Math.PI / 180)\n                } else l = Ar(this, e + (360 <= p ? k : k - 1) * (h !== wr ? b : 1.6 * b), m, n *\n                    Math.PI / 180, p * Math.PI / 180);\n                f = l * m\n            } else if (f = l * m, r = Br(this, l, f, n * Math.PI / 180, p * Math.PI / 180), isNaN(b)) {\n                if (h === hr || h === wr) b = (r - e) / (360 <= p ? k : k - 1)\n            } else if (h === hr || h === wr) r = (r - e) / (360 <= p ? k : k - 1), r < b ? (l = Ar(this, e + b * (360 <= p ? k : k - 1), m, n * Math.PI / 180, p * Math.PI / 180), f = l * m) : b = r;\n            else {\n                g = -Infinity;\n                for (e = 0; e < k; e++) q = d.L(e), u = d.L(e === k - 1 ? 0 : e + 1), isNaN(q.diameter) && zr(q, 0), isNaN(u.diameter) && zr(u, 0), g = Math.max(g, (q.diameter + u.diameter) / 2);\n                g += b;\n                e = Ar(this, g * (360 <= p ? k : k - 1), m, n * Math.PI / 180, p * Math.PI / 180);\n                e > l ? (l = e, f = l * m) : g =\n                    r / (360 <= p ? k : k - 1)\n            }\n            this.Sw = h;\n            this.$b = l;\n            this.Cn = m;\n            this.Tw = n;\n            this.Ar = p;\n            this.qj = b;\n            this.Sd = f;\n            this.lr = g;\n            b = d;\n            d = this.Sw;\n            h = this.$b;\n            l = this.Tw;\n            m = this.Ar;\n            n = this.qj;\n            p = this.Sd;\n            k = this.lr;\n            if (this.direction !== rr && this.direction !== sr || d !== wr)\n                if (this.direction === rr || this.direction === sr) {\n                    g = 0;\n                    switch (d) {\n                        case vr:\n                            g = 180 * Cr(this, h, p, l, k) / Math.PI;\n                            break;\n                        case hr:\n                            k = b = 0;\n                            g = a.first();\n                            null !== g && (b = zr(g, Math.PI / 2));\n                            g = c.first();\n                            null !== g && (k = zr(g, Math.PI / 2));\n                            g = 180 * Cr(this, h, p, l, n + (b + k) / 2) / Math.PI;\n                            break;\n                        case ur:\n                            g = m / b.length\n                    }\n                    if (this.direction ===\n                        rr) {\n                        switch (d) {\n                            case vr:\n                                Dr(this, a, l, tr);\n                                break;\n                            case hr:\n                                Er(this, a, l, tr);\n                                break;\n                            case ur:\n                                Fr(this, a, m / 2, l, tr)\n                        }\n                        switch (d) {\n                            case vr:\n                                Dr(this, c, l + g, kr);\n                                break;\n                            case hr:\n                                Er(this, c, l + g, kr);\n                                break;\n                            case ur:\n                                Fr(this, c, m / 2, l + g, kr)\n                        }\n                    } else {\n                        switch (d) {\n                            case vr:\n                                Dr(this, c, l, tr);\n                                break;\n                            case hr:\n                                Er(this, c, l, tr);\n                                break;\n                            case ur:\n                                Fr(this, c, m / 2, l, tr)\n                        }\n                        switch (d) {\n                            case vr:\n                                Dr(this, a, l + g, kr);\n                                break;\n                            case hr:\n                                Er(this, a, l + g, kr);\n                                break;\n                            case ur:\n                                Fr(this, a, m / 2, l + g, kr)\n                        }\n                    }\n                } else switch (d) {\n                    case vr:\n                        Dr(this, b, l, this.direction);\n                        break;\n                    case hr:\n                        Er(this, b, l, this.direction);\n                        break;\n                    case ur:\n                        Fr(this, b, m, l, this.direction);\n                        break;\n                    case wr:\n                        Gr(this, b, m, l, this.direction)\n                } else Gr(this, b, m, l - m / 2, kr)\n        }\n        this.updateParts();\n        this.network = null;\n        this.isValidLayout = !0\n    };\n\n    function Fr(a, b, c, d, e) {\n        var f = a.Ar,\n            g = a.$b;\n        a = a.Sd;\n        d = d * Math.PI / 180;\n        c = c * Math.PI / 180;\n        for (var h = b.length, k = 0; k < h; k++) {\n            var l = d + (e === kr ? k * c / (360 <= f ? h : h - 1) : -(k * c) / h),\n                m = b.L(k),\n                n = g * Math.tan(l) / a;\n            n = Math.sqrt((g * g + a * a * n * n) / (1 + n * n));\n            m.centerX = n * Math.cos(l);\n            m.centerY = n * Math.sin(l);\n            m.actualAngle = 180 * l / Math.PI\n        }\n    }\n\n    function Er(a, b, c, d) {\n        var e = a.$b,\n            f = a.Sd,\n            g = a.qj;\n        c = c * Math.PI / 180;\n        for (var h = b.length, k = 0; k < h; k++) {\n            var l = b.L(k),\n                m = b.L(k === h - 1 ? 0 : k + 1),\n                n = f * Math.sin(c);\n            l.centerX = e * Math.cos(c);\n            l.centerY = n;\n            l.actualAngle = 180 * c / Math.PI;\n            isNaN(l.diameter) && zr(l, 0);\n            isNaN(m.diameter) && zr(m, 0);\n            l = Cr(a, e, f, d === kr ? c : -c, (l.diameter + m.diameter) / 2 + g);\n            c += d === kr ? l : -l\n        }\n    }\n\n    function Dr(a, b, c, d) {\n        var e = a.$b,\n            f = a.Sd,\n            g = a.lr;\n        c = c * Math.PI / 180;\n        for (var h = b.length, k = 0; k < h; k++) {\n            var l = b.L(k);\n            l.centerX = e * Math.cos(c);\n            l.centerY = f * Math.sin(c);\n            l.actualAngle = 180 * c / Math.PI;\n            l = Cr(a, e, f, d === kr ? c : -c, g);\n            c += d === kr ? l : -l\n        }\n    }\n\n    function Gr(a, b, c, d, e) {\n        var f = a.Ar;\n        a.Hj = 0;\n        a.Ys = new ir;\n        if (360 > c) {\n            for (f = d + (e === kr ? f : -f); 0 > f;) f += 360;\n            f %= 360;\n            180 < f && (f -= 360);\n            f *= Math.PI / 180;\n            a.bu = f;\n            Hr(a, b, c, d, e)\n        } else Ir(a, b, c, d, e);\n        a.Ys.commit(b)\n    }\n\n    function Ir(a, b, c, d, e) {\n        var f = a.$b,\n            g = a.qj,\n            h = a.Cn,\n            k = f * Math.cos(d * Math.PI / 180),\n            l = a.Sd * Math.sin(d * Math.PI / 180),\n            m = b.na();\n        if (3 === m.length) m[0].centerX = f, m[0].centerY = 0, m[1].centerX = m[0].centerX - m[0].width / 2 - m[1].width / 2 - g, m[1].y = m[0].y, m[2].centerX = (m[0].centerX + m[1].centerX) / 2, m[2].y = m[0].y - m[2].height - g;\n        else if (4 === m.length) m[0].centerX = f, m[0].centerY = 0, m[2].centerX = -m[0].centerX, m[2].centerY = m[0].centerY, m[1].centerX = 0, m[1].y = Math.min(m[0].y, m[2].y) - m[1].height - g, m[3].centerX = 0, m[3].y = Math.max(m[0].y +\n            m[0].height + g, m[2].y + m[2].height + g);\n        else {\n            f = I.alloc();\n            for (var n = 0; n < m.length; n++) {\n                m[n].centerX = k;\n                m[n].centerY = l;\n                if (n >= m.length - 1) break;\n                Jr(a, k, l, m, n, e, f) || Kr(a, k, l, m, n, e, f);\n                k = f.x;\n                l = f.y\n            }\n            I.free(f);\n            a.Hj++;\n            if (!(23 < a.Hj)) {\n                k = m[0].centerX;\n                l = m[0].centerY;\n                f = m[m.length - 1].centerX;\n                n = m[m.length - 1].centerY;\n                var p = Math.abs(k - f) - ((m[0].width + m[m.length - 1].width) / 2 + g),\n                    r = Math.abs(l - n) - ((m[0].height + m[m.length - 1].height) / 2 + g);\n                g = 0;\n                1 > Math.abs(r) ? Math.abs(k - f) < (m[0].width + m[m.length - 1].width) / 2 && (g = 0) : g = 0 < r ? r : 1 > Math.abs(p) ?\n                    0 : p;\n                k = Math.abs(f) > Math.abs(n) ? 0 < f !== l > n : 0 < n !== k < f;\n                if (k = e === kr ? k : !k) g = -Math.abs(g), g = Math.min(g, -m[m.length - 1].width), g = Math.min(g, -m[m.length - 1].height);\n                a.Ys.compare(g, m);\n                1 < Math.abs(g) && (a.$b = 8 > a.Hj ? a.$b - g / (2 * Math.PI) : 5 > m.length && 10 < g ? a.$b / 2 : a.$b - (0 < g ? 1.7 : -2.3), a.Sd = a.$b * h, Ir(a, b, c, d, e))\n            }\n        }\n    }\n\n    function Hr(a, b, c, d, e) {\n        for (var f = a.$b, g = a.Sd, h = a.Cn, k = f * Math.cos(d * Math.PI / 180), l = g * Math.sin(d * Math.PI / 180), m = I.alloc(), n = b.na(), p = 0; p < n.length; p++) {\n            n[p].centerX = k;\n            n[p].centerY = l;\n            if (p >= n.length - 1) break;\n            Jr(a, k, l, n, p, e, m) || Kr(a, k, l, n, p, e, m);\n            k = m.x;\n            l = m.y\n        }\n        I.free(m);\n        a.Hj++;\n        if (!(23 < a.Hj)) {\n            k = Math.atan2(l, k);\n            k = e === kr ? a.bu - k : k - a.bu;\n            k = Math.abs(k) < Math.abs(k - 2 * Math.PI) ? k : k - 2 * Math.PI;\n            f = k * (f + g) / 2;\n            g = a.Ys;\n            if (Math.abs(f) < Math.abs(g.km))\n                for (g.km = f, g.Ak = [], g.Mm = [], k = 0; k < n.length; k++) g.Ak[k] = n[k].bounds.x, g.Mm[k] = n[k].bounds.y;\n            1 < Math.abs(f) && (a.$b = 8 > a.Hj ? a.$b - f / (2 * Math.PI) : a.$b - (0 < f ? 1.7 : -2.3), a.Sd = a.$b * h, Hr(a, b, c, d, e))\n        }\n    }\n\n    function Jr(a, b, c, d, e, f, g) {\n        var h = a.$b,\n            k = a.Sd,\n            l = 0;\n        a = (d[e].width + d[e + 1].width) / 2 + a.qj;\n        var m = !1;\n        if (0 <= c !== (f === kr)) {\n            if (f = b + a, f > h) {\n                f = b - a;\n                if (f < -h) return g.x = f, g.y = l, !1;\n                m = !0\n            }\n        } else if (f = b - a, f < -h) {\n            f = b + a;\n            if (f > h) return g.x = f, g.y = l, !1;\n            m = !0\n        }\n        l = Math.sqrt(1 - Math.min(1, f * f / (h * h))) * k;\n        0 > c !== m && (l = -l);\n        if (Math.abs(c - l) > (d[e].height + d[e + 1].height) / 2) return g.x = f, g.y = l, !1;\n        g.x = f;\n        g.y = l;\n        return !0\n    }\n\n    function Kr(a, b, c, d, e, f, g) {\n        var h = a.$b,\n            k = a.Sd,\n            l = 0;\n        a = (d[e].height + d[e + 1].height) / 2 + a.qj;\n        d = !1;\n        if (0 <= b !== (f === kr)) {\n            if (f = c - a, f < -k) {\n                f = c + a;\n                if (f > k) {\n                    g.x = l;\n                    g.y = f;\n                    return\n                }\n                d = !0\n            }\n        } else if (f = c + a, f > k) {\n            f = c - a;\n            if (f < -k) {\n                g.x = l;\n                g.y = f;\n                return\n            }\n            d = !0\n        }\n        l = Math.sqrt(1 - Math.min(1, f * f / (k * k))) * h;\n        0 > b !== d && (l = -l);\n        g.x = l;\n        g.y = f\n    }\n    gr.prototype.commitLayout = function () {\n        this.commitNodes();\n        this.isRouting && this.commitLinks()\n    };\n    gr.prototype.commitNodes = function () {\n        var a = null !== this.group && null !== this.group.placeholder && this.group.isSubGraphExpanded,\n            b = a ? this.group.location.copy() : null,\n            c = this.actualCenter;\n        a ? c = new I(0, 0) : (c.x = this.arrangementOrigin.x + this.$b, c.y = this.arrangementOrigin.y + this.Sd);\n        for (var d = this.network.vertexes.iterator; d.next();) {\n            var e = d.value;\n            e.x += c.x;\n            e.y += c.y;\n            e.commit()\n        }\n        a && (this.group.yb(), a = this.group.position.copy(), c = this.group.location.copy(), b = b.Zd(c.Zd(a)), this.group.move(b), this.Kw = b.Zd(a))\n    };\n    gr.prototype.commitLinks = function () {\n        for (var a = this.network.edges.iterator; a.next();) a.value.commit()\n    };\n\n    function Br(a, b, c, d, e) {\n        var f = a.zy;\n        if (.001 > Math.abs(a.Cn - 1)) return void 0 !== d && void 0 !== e ? e * b : 2 * Math.PI * b;\n        a = b > c ? Math.sqrt(b * b - c * c) / b : Math.sqrt(c * c - b * b) / c;\n        var g = 0;\n        var h = void 0 !== d && void 0 !== e ? e / (f + 1) : Math.PI / (2 * (f + 1));\n        for (var k = 0, l = 0; l <= f; l++) {\n            void 0 !== d && void 0 !== e ? k = d + l * e / f : k = l * Math.PI / (2 * f);\n            var m = Math.sin(k);\n            g += Math.sqrt(1 - a * a * m * m) * h\n        }\n        return void 0 !== d && void 0 !== e ? (b > c ? b : c) * g : 4 * (b > c ? b : c) * g\n    }\n\n    function Ar(a, b, c, d, e) {\n        return b / (void 0 !== d && void 0 !== e ? Br(a, 1, c, d, e) : Br(a, 1, c))\n    }\n\n    function Cr(a, b, c, d, e) {\n        if (.001 > Math.abs(a.Cn - 1)) return e / b;\n        var f = b > c ? Math.sqrt(b * b - c * c) / b : Math.sqrt(c * c - b * b) / c,\n            g = 0;\n        a = 2 * Math.PI / (700 * a.network.vertexes.count);\n        b > c && (d += Math.PI / 2);\n        for (var h = 0;; h++) {\n            var k = Math.sin(d + h * a);\n            g += (b > c ? b : c) * Math.sqrt(1 - f * f * k * k) * a;\n            if (g >= e) return h * a\n        }\n    }\n    gr.prototype.sort = function (a) {\n        switch (this.sorting) {\n            case pr:\n                break;\n            case qr:\n                a.reverse();\n                break;\n            case nr:\n                a.sort(this.comparer);\n                break;\n            case or:\n                a.sort(this.comparer);\n                a.reverse();\n                break;\n            case lr:\n                for (var b = [], c = 0; c < a.length; c++) b.push(0);\n                c = new E;\n                for (var d = 0; d < a.length; d++) {\n                    var e = -1,\n                        f = -1;\n                    if (0 === d)\n                        for (var g = 0; g < a.length; g++) {\n                            var h = a.L(g).edgesCount;\n                            h > e && (e = h, f = g)\n                        } else\n                            for (g = 0; g < a.length; g++) h = b[g], h > e && (e = h, f = g);\n                    c.add(a.L(f));\n                    b[f] = -1;\n                    f = a.L(f);\n                    for (g = f.sourceEdges; g.next();) e = a.indexOf(g.value.fromVertex), 0 > e || 0 <=\n                        b[e] && b[e]++;\n                    for (f = f.destinationEdges; f.next();) e = a.indexOf(f.value.toVertex), 0 > e || 0 <= b[e] && b[e]++\n                }\n                a = [];\n                for (b = 0; b < c.length; b++) {\n                    e = c.L(b);\n                    a[b] = [];\n                    for (f = e.destinationEdges; f.next();) d = c.indexOf(f.value.toVertex), d !== b && 0 > a[b].indexOf(d) && a[b].push(d);\n                    for (e = e.sourceEdges; e.next();) d = c.indexOf(e.value.fromVertex), d !== b && 0 > a[b].indexOf(d) && a[b].push(d)\n                }\n                f = [];\n                for (b = 0; b < a.length; b++) f[b] = 0;\n                b = [];\n                g = [];\n                h = [];\n                e = [];\n                d = new E;\n                for (var k = 0, l = 0; l < a.length; l++) {\n                    var m = a[l].length;\n                    if (1 === m) e.push(l);\n                    else if (0 === m) d.add(c.L(l));\n                    else {\n                        if (0 === k) b.push(l);\n                        else {\n                            for (var n = m = Infinity, p = -1, r = [], q = 0; q < b.length; q++) 0 > a[b[q]].indexOf(b[q === b.length - 1 ? 0 : q + 1]) && r.push(q === b.length - 1 ? 0 : q + 1);\n                            if (0 === r.length)\n                                for (q = 0; q < b.length; q++) r.push(q);\n                            for (q = 0; q < r.length; q++) {\n                                for (var u = r[q], v = a[l], w = 0, y = 0; y < g.length; y++) {\n                                    var z = f[g[y]],\n                                        A = f[h[y]];\n                                    if (z < A) {\n                                        var C = z;\n                                        z = A\n                                    } else C = A;\n                                    if (C < u && u <= z)\n                                        for (A = 0; A < v.length; A++) {\n                                            var G = v[A];\n                                            0 > b.indexOf(G) || C < f[G] && f[G] < z || C === f[G] || z === f[G] || w++\n                                        } else\n                                            for (A = 0; A < v.length; A++) G = v[A], 0 > b.indexOf(G) || C < f[G] && f[G] < z && C !== f[G] &&\n                                                z !== f[G] && w++\n                                }\n                                v = w;\n                                for (y = w = 0; y < a[l].length; y++) C = b.indexOf(a[l][y]), 0 <= C && (C = Math.abs(u - (C >= u ? C + 1 : C)), w += C < b.length + 1 - C ? C : b.length + 1 - C);\n                                for (y = 0; y < g.length; y++) C = f[g[y]], z = f[h[y]], C >= u && C++, z >= u && z++, C > z && (A = z, z = C, C = A), z - C < (b.length + 2) / 2 === (C < u && u <= z) && w++;\n                                if (v < m || v === m && w < n) m = v, n = w, p = u\n                            }\n                            b.splice(p, 0, l);\n                            for (m = 0; m < b.length; m++) f[b[m]] = m;\n                            for (m = 0; m < a[l].length; m++) n = a[l][m], 0 <= b.indexOf(n) && (g.push(l), h.push(n))\n                        }\n                        k++\n                    }\n                }\n                for (g = b.length;;) {\n                    f = !0;\n                    for (h = 0; h < e.length; h++)\n                        if (k = e[h], l = a[k][0], m = b.indexOf(l), 0 <= m) {\n                            for (p =\n                                n = 0; p < a[l].length; p++) r = b.indexOf(a[l][p]), 0 > r || r === m || (q = r > m ? r - m : m - r, n += r < m !== q > g - q ? 1 : -1);\n                            b.splice(0 > n ? m : m + 1, 0, k);\n                            e.splice(h, 1);\n                            h--\n                        } else f = !1;\n                    if (f) break;\n                    else b.push(e[0]), e.splice(0, 1)\n                }\n                for (a = 0; a < b.length; a++) d.add(c.L(b[a]));\n                return d;\n            default:\n                B(\"Invalid sorting type.\")\n        }\n        return a\n    };\n    ma.Object.defineProperties(gr.prototype, {\n        radius: {\n            get: function () {\n                return this.gp\n            },\n            set: function (a) {\n                this.gp !== a && (0 < a || isNaN(a)) && (this.gp = a, this.C())\n            }\n        },\n        aspectRatio: {\n            get: function () {\n                return this.Ym\n            },\n            set: function (a) {\n                this.Ym !== a && 0 < a && (this.Ym = a, this.C())\n            }\n        },\n        startAngle: {\n            get: function () {\n                return this.Lp\n            },\n            set: function (a) {\n                this.Lp !== a && (this.Lp = a, this.C())\n            }\n        },\n        sweepAngle: {\n            get: function () {\n                return this.Tl\n            },\n            set: function (a) {\n                this.Tl !== a && (0 < a && 360 >= a ? this.Tl = a : this.Tl = 360, this.C())\n            }\n        },\n        arrangement: {\n            get: function () {\n                return this.Ab\n            },\n            set: function (a) {\n                this.Ab === a || a !== wr && a !== hr && a !== vr && a !== ur || (this.Ab = a, this.C())\n            }\n        },\n        direction: {\n            get: function () {\n                return this.J\n            },\n            set: function (a) {\n                this.J === a || a !== kr && a !== tr && a !== rr && a !== sr || (this.J = a, this.C())\n            }\n        },\n        sorting: {\n            get: function () {\n                return this.Qc\n            },\n            set: function (a) {\n                this.Qc === a || a !== pr && a !== qr &&\n                    a !== nr && !or && a !== lr || (this.Qc = a, this.C())\n            }\n        },\n        comparer: {\n            get: function () {\n                return this.Kc\n            },\n            set: function (a) {\n                this.Kc !== a && (this.Kc = a, this.C())\n            }\n        },\n        spacing: {\n            get: function () {\n                return this.ef\n            },\n            set: function (a) {\n                this.ef !== a && (this.ef = a, this.C())\n            }\n        },\n        nodeDiameterFormula: {\n            get: function () {\n                return this.Qo\n            },\n            set: function (a) {\n                this.Qo === a || a !== mr && a !== xr || (this.Qo = a, this.C())\n            }\n        },\n        actualXRadius: {\n            get: function () {\n                return this.$b\n            }\n        },\n        actualYRadius: {\n            get: function () {\n                return this.Sd\n            }\n        },\n        actualSpacing: {\n            get: function () {\n                return this.qj\n            }\n        },\n        actualCenter: {\n            get: function () {\n                return this.Kw\n            }\n        }\n    });\n    var hr = new D(gr, \"ConstantSpacing\", 0),\n        vr = new D(gr, \"ConstantDistance\", 1),\n        ur = new D(gr, \"ConstantAngle\", 2),\n        wr = new D(gr, \"Packed\", 3),\n        kr = new D(gr, \"Clockwise\", 4),\n        tr = new D(gr, \"Counterclockwise\", 5),\n        rr = new D(gr, \"BidirectionalLeft\", 6),\n        sr = new D(gr, \"BidirectionalRight\", 7),\n        pr = new D(gr, \"Forwards\", 8),\n        qr = new D(gr, \"Reverse\", 9),\n        nr = new D(gr, \"Ascending\", 10),\n        or = new D(gr, \"Descending\", 11),\n        lr = new D(gr, \"Optimized\", 12),\n        mr = new D(gr, \"Pythagorean\", 13),\n        xr = new D(gr, \"Circular\", 14);\n    gr.className = \"CircularLayout\";\n    gr.ConstantSpacing = hr;\n    gr.ConstantDistance = vr;\n    gr.ConstantAngle = ur;\n    gr.Packed = wr;\n    gr.Clockwise = kr;\n    gr.Counterclockwise = tr;\n    gr.BidirectionalLeft = rr;\n    gr.BidirectionalRight = sr;\n    gr.Forwards = pr;\n    gr.Reverse = qr;\n    gr.Ascending = nr;\n    gr.Descending = or;\n    gr.Optimized = lr;\n    gr.Pythagorean = mr;\n    gr.Circular = xr;\n\n    function ir() {\n        this.km = -Infinity;\n        this.Mm = this.Ak = null\n    }\n    ir.prototype.compare = function (a, b) {\n        if (0 < a && 0 > this.km || Math.abs(a) < Math.abs(this.km) && !(0 > a && 0 < this.km))\n            for (this.km = a, this.Ak = [], this.Mm = [], a = 0; a < b.length; a++) this.Ak[a] = b[a].bounds.x, this.Mm[a] = b[a].bounds.y\n    };\n    ir.prototype.commit = function (a) {\n        if (null !== this.Ak && null !== this.Mm)\n            for (var b = 0; b < this.Ak.length; b++) {\n                var c = a.L(b);\n                c.x = this.Ak[b];\n                c.y = this.Mm[b]\n            }\n    };\n    ir.className = \"VertexArrangement\";\n\n    function yr(a) {\n        Qp.call(this, a)\n    }\n    la(yr, Qp);\n    yr.prototype.createVertex = function () {\n        return new Lr(this)\n    };\n    yr.prototype.createEdge = function () {\n        return new Mr(this)\n    };\n    yr.className = \"CircularNetwork\";\n\n    function Lr(a) {\n        Tp.call(this, a);\n        this.I = this.oj = NaN\n    }\n    la(Lr, Tp);\n\n    function zr(a, b) {\n        var c = a.network;\n        if (null === c) return NaN;\n        c = c.layout;\n        if (null === c) return NaN;\n        if (c.arrangement === wr)\n            if (c.nodeDiameterFormula === xr) a.oj = Math.max(a.width, a.height);\n            else {\n                c = Math.abs(Math.sin(b));\n                b = Math.abs(Math.cos(b));\n                if (0 === c) return a.width;\n                if (0 === b) return a.height;\n                a.oj = Math.min(a.height / c, a.width / b)\n            }\n        else a.oj = c.nodeDiameterFormula === xr ? Math.max(a.width, a.height) : Math.sqrt(a.width * a.width + a.height * a.height);\n        return a.oj\n    }\n    ma.Object.defineProperties(Lr.prototype, {\n        diameter: {\n            get: function () {\n                return this.oj\n            },\n            set: function (a) {\n                this.oj !== a && (this.oj = a)\n            }\n        },\n        actualAngle: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I !== a && (this.I = a)\n            }\n        }\n    });\n    Lr.className = \"CircularVertex\";\n\n    function Mr(a) {\n        Up.call(this, a)\n    }\n    la(Mr, Up);\n    Mr.className = \"CircularEdge\";\n\n    function Nr() {\n        Ci.call(this);\n        this.Bh = null;\n        this.jo = 0;\n        this.zd = (new M(100, 100)).freeze();\n        this.Xm = !1;\n        this.cf = !0;\n        this.Zc = !1;\n        this.yl = 100;\n        this.Fn = 1;\n        this.Wf = 1E3;\n        this.Ho = 10;\n        this.hp = Math;\n        this.Uk = .05;\n        this.Tk = 50;\n        this.Rk = 150;\n        this.Sk = 0;\n        this.wn = 10;\n        this.vn = 5\n    }\n    la(Nr, Ci);\n    Nr.prototype.cloneProtected = function (a) {\n        Ci.prototype.cloneProtected.call(this, a);\n        a.zd.assign(this.zd);\n        a.Xm = this.Xm;\n        a.cf = this.cf;\n        a.Zc = this.Zc;\n        a.yl = this.yl;\n        a.Fn = this.Fn;\n        a.Wf = this.Wf;\n        a.Ho = this.Ho;\n        a.hp = this.hp;\n        a.Uk = this.Uk;\n        a.Tk = this.Tk;\n        a.Rk = this.Rk;\n        a.Sk = this.Sk;\n        a.wn = this.wn;\n        a.vn = this.vn\n    };\n    Nr.prototype.createNetwork = function () {\n        return new Or(this)\n    };\n    Nr.prototype.doLayout = function (a) {\n        null === this.network && (this.network = this.makeNetwork(a));\n        a = this.maxIterations;\n        if (0 < this.network.vertexes.count) {\n            this.network.iq();\n            for (var b = this.network.vertexes.iterator; b.next();) {\n                var c = b.value;\n                c.charge = this.electricalCharge(c);\n                c.mass = this.gravitationalMass(c)\n            }\n            for (b = this.network.edges.iterator; b.next();) c = b.value, c.stiffness = this.springStiffness(c), c.length = this.springLength(c);\n            this.fv();\n            this.jo = 0;\n            if (this.needsClusterLayout()) {\n                b = this.network;\n                for (c = b.py().iterator; c.next();) {\n                    this.network =\n                        c.value;\n                    for (var d = this.network.vertexes.iterator; d.next();) {\n                        var e = d.value;\n                        e.wd = e.vertexes.count;\n                        e.Mh = 1;\n                        e.$j = null;\n                        e.Fe = null\n                    }\n                    Pr(this, 0, a)\n                }\n                this.network = b;\n                c.reset();\n                d = this.arrangementSpacing;\n                for (var f = c.count, g = !0, h = e = 0, k = Fa(), l = 0; l < f + b.vertexes.count + 2; l++) k[l] = null;\n                f = 0;\n                c.reset();\n                for (var m = N.alloc(); c.next();)\n                    if (l = c.value, this.computeBounds(l, m), g) g = !1, e = m.x + m.width / 2, h = m.y + m.height / 2, k[0] = new I(m.x + m.width + d.width, m.y), k[1] = new I(m.x, m.y + m.height + d.height), f = 2;\n                    else {\n                        var n = Qr(k, f, e, h, m.width, m.height,\n                                d),\n                            p = k[n],\n                            r = new I(p.x + m.width + d.width, p.y),\n                            q = new I(p.x, p.y + m.height + d.height);\n                        n + 1 < f && k.splice(n + 1, 0, null);\n                        k[n] = r;\n                        k[n + 1] = q;\n                        f++;\n                        n = p.x - m.x;\n                        p = p.y - m.y;\n                        for (l = l.vertexes.iterator; l.next();) r = l.value, r.centerX += n, r.centerY += p\n                    } N.free(m);\n                for (l = b.vertexes.iterator; l.next();) g = l.value, r = g.bounds, 2 > f ? (e = r.x + r.width / 2, h = r.y + r.height / 2, k[0] = new I(r.x + r.width + d.width, r.y), k[1] = new I(r.x, r.y + r.height + d.height), f = 2) : (m = Qr(k, f, e, h, r.width, r.height, d), p = k[m], n = new I(p.x + r.width + d.width, p.y), r = new I(p.x, p.y + r.height +\n                    d.height), m + 1 < f && k.splice(m + 1, 0, null), k[m] = n, k[m + 1] = r, f++, g.centerX = p.x + g.width / 2, g.centerY = p.y + g.height / 2);\n                Ha(k);\n                for (c.reset(); c.next();) {\n                    d = c.value;\n                    for (e = d.vertexes.iterator; e.next();) b.Eh(e.value);\n                    for (d = d.edges.iterator; d.next();) b.bq(d.value)\n                }\n            }\n            Rr(this, a);\n            this.updateParts()\n        }\n        this.yl = a;\n        this.network = null;\n        this.isValidLayout = !0\n    };\n    Nr.prototype.needsClusterLayout = function () {\n        if (3 > this.network.vertexes.count) return !1;\n        for (var a = 0, b = 0, c = this.network.vertexes.first().bounds, d = this.network.vertexes.iterator; d.next();) {\n            if (d.value.bounds.Gc(c) && (a++, 2 < a)) return !0;\n            if (10 < b) break;\n            b++\n        }\n        return !1\n    };\n    Nr.prototype.computeBounds = function (a, b) {\n        var c = !0;\n        for (a = a.vertexes.iterator; a.next();) {\n            var d = a.value;\n            c ? (c = !1, b.set(d.bounds)) : b.Hc(d.bounds)\n        }\n        return b\n    };\n\n    function Pr(a, b, c) {\n        if (Sr(a, b)) {\n            var d = a.Wf;\n            a.Wf *= 1 + 1 / (b + 1);\n            var e = Tr(a, b),\n                f = Math.max(0, Math.max(Math.min(a.network.vertexes.count, c * (b + 1) / 11), 10));\n            a.maxIterations += f;\n            Pr(a, b + 1, c);\n            Rr(a, f);\n            Ur(a, e);\n            b = e.vertexes.na();\n            b.sort(function (a, b) {\n                return null === a || null === b || a === b ? 0 : b.wd - a.wd\n            });\n            for (c = 0; c < b.length; c++) Vr(a, b[c]);\n            a.Wf = d\n        }\n    }\n\n    function Sr(a, b) {\n        if (10 < b || 3 > a.network.vertexes.count) return !1;\n        a.Bh = a.network.vertexes.na();\n        a = a.Bh;\n        a.sort(function (a, b) {\n            return null === a || null === b || a === b ? 0 : b.wd - a.wd\n        });\n        for (b = a.length - 1; 0 <= b && 1 >= a[b].wd;) b--;\n        return 1 < a.length - b\n    }\n\n    function Tr(a, b) {\n        for (var c = a.network, d = new Or(a), e = 0; e < a.Bh.length; e++) {\n            var f = a.Bh[e];\n            if (1 < f.wd) {\n                d.Eh(f);\n                var g = new Wr;\n                g.Rt = f.wd;\n                g.St = f.width;\n                g.Qt = f.height;\n                g.zw = f.focus.x;\n                g.Aw = f.focus.y;\n                null === f.Fe && (f.Fe = new E);\n                f.Fe.add(g);\n                f.bw = f.Fe.count - 1\n            } else break\n        }\n        for (f = c.edges.iterator; f.next();) {\n            var h = f.value;\n            e = h.fromVertex;\n            g = h.toVertex;\n            e.network === d && g.network === d ? d.bq(h) : e.network === d ? (h = e.$j, null === h && (h = new E, e.$j = h), h.add(g), e.wd--, e.Mh += g.Mh) : g.network === d && (h = g.$j, null === h && (h = new E, g.$j = h), h.add(e),\n                g.wd--, g.Mh += e.Mh)\n        }\n        for (e = d.edges.iterator; e.next();) f = e.value, f.length *= Math.max(1, J.sqrt((f.fromVertex.Mh + f.toVertex.Mh) / (4 * b + 1)));\n        for (b = d.vertexes.iterator; b.next();) {\n            e = b.value;\n            var k = e.$j;\n            if (null !== k && 0 < k.count && (g = e.Fe.L(e.Fe.count - 1).Rt - e.wd, !(0 >= g))) {\n                for (var l = h = 0, m = k.count - g; m < k.count; m++) {\n                    var n = k.L(m),\n                        p = null;\n                    for (f = n.edges.iterator; f.next();) {\n                        var r = f.value;\n                        if (r.Qx(n) === e) {\n                            p = r;\n                            break\n                        }\n                    }\n                    null !== p && (l += p.length, h += n.width * n.height)\n                }\n                f = e.centerX;\n                k = e.centerY;\n                m = e.width;\n                n = e.height;\n                p = e.focus;\n                r = m * n;\n                1 > r &&\n                    (r = 1);\n                h = J.sqrt((h + r + l * l * 4 / (g * g)) / r);\n                g = (h - 1) * m / 2;\n                h = (h - 1) * n / 2;\n                e.bounds = new N(f - p.x - g, k - p.y - h, m + 2 * g, n + 2 * h);\n                e.focus = new I(p.x + g, p.y + h)\n            }\n        }\n        a.network = d;\n        return c\n    }\n\n    function Ur(a, b) {\n        for (var c = a.network.vertexes.iterator; c.next();) {\n            var d = c.value;\n            d.network = b;\n            if (null !== d.Fe) {\n                var e = d.Fe.L(d.bw);\n                d.wd = e.Rt;\n                var f = e.zw,\n                    g = e.Aw;\n                d.bounds = new N(d.centerX - f, d.centerY - g, e.St, e.Qt);\n                d.focus = new I(f, g);\n                d.bw--\n            }\n        }\n        for (c = a.network.edges.iterator; c.next();) c.value.network = b;\n        a.network = b\n    }\n\n    function Vr(a, b) {\n        var c = b.$j;\n        if (null !== c && 0 !== c.count) {\n            var d = b.centerX,\n                e = b.centerY,\n                f = b.width,\n                g = b.height;\n            null !== b.Fe && 0 < b.Fe.count && (g = b.Fe.L(0), f = g.St, g = g.Qt);\n            f = J.sqrt(f * f + g * g) / 2;\n            for (var h = !1, k = g = 0, l = 0, m = b.vertexes.iterator; m.next();) {\n                var n = m.value;\n                1 >= n.wd ? k++ : (h = !0, l++, g += Math.atan2(b.centerY - n.centerY, b.centerX - n.centerX))\n            }\n            if (0 !== k)\n                for (0 < l && (g /= l), l = b = 0, b = h ? 2 * Math.PI / (k + 1) : 2 * Math.PI / k, 0 === k % 2 && (l = b / 2), 1 < c.count && c.sort(function (a, b) {\n                        return null === a || null === b || a === b ? 0 : b.width * b.height - a.width * a.height\n                    }),\n                    h = 0 === k % 2 ? 0 : 1, c = c.iterator; c.next();)\n                    if (k = c.value, !(1 < k.wd || a.isFixed(k))) {\n                        m = null;\n                        for (n = k.edges.iterator; n.next();) {\n                            m = n.value;\n                            break\n                        }\n                        n = k.width;\n                        var p = k.height;\n                        n = J.sqrt(n * n + p * p) / 2;\n                        m = f + m.length + n;\n                        n = g + (b * (h / 2 >> 1) + l) * (0 === h % 2 ? 1 : -1);\n                        k.centerX = d + m * Math.cos(n);\n                        k.centerY = e + m * Math.sin(n);\n                        h++\n                    }\n        }\n    }\n\n    function Qr(a, b, c, d, e, f, g) {\n        var h = 9E19,\n            k = -1,\n            l = 0;\n        a: for (; l < b; l++) {\n            var m = a[l],\n                n = m.x - c,\n                p = m.y - d;\n            n = n * n + p * p;\n            if (n < h) {\n                for (p = l - 1; 0 <= p; p--)\n                    if (a[p].y > m.y && a[p].x - m.x < e + g.width) continue a;\n                for (p = l + 1; p < b; p++)\n                    if (a[p].x > m.x && a[p].y - m.y < f + g.height) continue a;\n                k = l;\n                h = n\n            }\n        }\n        return k\n    }\n    Nr.prototype.fv = function () {\n        if (this.comments)\n            for (var a = this.network.vertexes.iterator; a.next();) this.addComments(a.value)\n    };\n    Nr.prototype.addComments = function (a) {\n        var b = a.node;\n        if (null !== b)\n            for (b = b.rv(); b.next();) {\n                var c = b.value;\n                if (\"Comment\" === c.category && c.isVisible()) {\n                    var d = this.network.Wi(c);\n                    null === d && (d = this.network.am(c));\n                    d.charge = this.defaultCommentElectricalCharge;\n                    c = null;\n                    for (var e = d.destinationEdges; e.next();) {\n                        var f = e.value;\n                        if (f.toVertex === a) {\n                            c = f;\n                            break\n                        }\n                    }\n                    if (null === c)\n                        for (e = d.sourceEdges; e.next();)\n                            if (f = e.value, f.fromVertex === a) {\n                                c = f;\n                                break\n                            } null === c && (c = this.network.mk(a, d, null));\n                    c.length = this.defaultCommentSpringLength\n                }\n            }\n    };\n\n    function Xr(a, b) {\n        var c = a.bounds,\n            d = c.x;\n        a = c.y;\n        var e = c.width;\n        c = c.height;\n        var f = b.bounds,\n            g = f.x;\n        b = f.y;\n        var h = f.width;\n        f = f.height;\n        return d + e < g ? a > b + f ? (c = d + e - g, a = a - b - f, J.sqrt(c * c + a * a)) : a + c < b ? (d = d + e - g, a = a + c - b, J.sqrt(d * d + a * a)) : g - (d + e) : d > g + h ? a > b + f ? (c = d - g - h, a = a - b - f, J.sqrt(c * c + a * a)) : a + c < b ? (d = d - g - h, a = a + c - b, J.sqrt(d * d + a * a)) : d - (g + h) : a > b + f ? a - (b + f) : a + c < b ? b - (a + c) : .1\n    }\n\n    function Rr(a, b) {\n        a.Bh = null;\n        for (b = a.jo + b; a.jo < b && (a.jo++, Yr(a)););\n        a.Bh = null\n    }\n\n    function Yr(a) {\n        null === a.Bh && (a.Bh = a.network.vertexes.na());\n        var b = a.Bh;\n        if (0 >= b.length) return !1;\n        var c = b[0];\n        c.forceX = 0;\n        c.forceY = 0;\n        for (var d = c.centerX, e = d, f = c = c.centerY, g = 1; g < b.length; g++) {\n            var h = b[g];\n            h.forceX = 0;\n            h.forceY = 0;\n            var k = h.centerX;\n            h = h.centerY;\n            d = Math.min(d, k);\n            e = Math.max(e, k);\n            c = Math.min(c, h);\n            f = Math.max(f, h)\n        }(e = e - d > f - c) ? b.sort(function (a, b) {\n            return null === a || null === b || a === b ? 0 : a.centerX - b.centerX\n        }): b.sort(function (a, b) {\n            return null === a || null === b || a === b ? 0 : a.centerY - b.centerY\n        });\n        c = a.Wf;\n        var l = d = h = 0;\n        for (f =\n            0; f < b.length; f++) {\n            g = b[f];\n            d = g.bounds;\n            h = g.focus;\n            k = d.x + h.x;\n            var m = d.y + h.y;\n            d = g.charge * a.electricalFieldX(k, m);\n            l = g.charge * a.electricalFieldY(k, m);\n            d += g.mass * a.gravitationalFieldX(k, m);\n            l += g.mass * a.gravitationalFieldY(k, m);\n            g.forceX += d;\n            g.forceY += l;\n            for (var n = f + 1; n < b.length; n++) {\n                var p = b[n];\n                if (p !== g) {\n                    d = p.bounds;\n                    h = p.focus;\n                    l = d.x + h.x;\n                    var r = d.y + h.y;\n                    if (k - l > c || l - k > c) {\n                        if (e) break\n                    } else if (m - r > c || r - m > c) {\n                        if (!e) break\n                    } else {\n                        var q = Xr(g, p);\n                        1 > q ? (d = a.randomNumberGenerator, null === d && (a.randomNumberGenerator = d = new Zr), q = d.random(),\n                            h = d.random(), k > l ? (d = Math.abs(p.bounds.right - g.bounds.x), d = (1 + d) * q) : k < l ? (d = Math.abs(p.bounds.x - g.bounds.right), d = -(1 + d) * q) : (d = Math.max(p.width, g.width), d = (1 + d) * q - d / 2), m > r ? (l = Math.abs(p.bounds.bottom - g.bounds.y), l = (1 + l) * h) : k < l ? (l = Math.abs(p.bounds.y - g.bounds.bottom), l = -(1 + l) * h) : (l = Math.max(p.height, g.height), l = (1 + l) * h - l / 2)) : (h = -(g.charge * p.charge) / (q * q), d = (l - k) / q * h, l = (r - m) / q * h);\n                        g.forceX += d;\n                        g.forceY += l;\n                        p.forceX -= d;\n                        p.forceY -= l\n                    }\n                }\n            }\n        }\n        for (e = a.network.edges.iterator; e.next();) h = e.value, c = h.fromVertex, f = h.toVertex,\n            g = c.bounds, k = c.focus, d = g.x + k.x, g = g.y + k.y, m = f.bounds, n = f.focus, k = m.x + n.x, m = m.y + n.y, n = Xr(c, f), 1 > n ? (n = a.randomNumberGenerator, null === n && (a.randomNumberGenerator = n = new Zr), h = n.random(), n = n.random(), d = (d > k ? 1 : -1) * (1 + (f.width > c.width ? f.width : c.width)) * h, l = (g > m ? 1 : -1) * (1 + (f.height > c.height ? f.height : c.height)) * n) : (h = h.stiffness * (n - h.length), d = (k - d) / n * h, l = (m - g) / n * h), c.forceX += d, c.forceY += l, f.forceX -= d, f.forceY -= l;\n        d = 0;\n        e = a.moveLimit;\n        for (c = 0; c < b.length; c++) f = b[c], a.isFixed(f) ? a.moveFixedVertex(f) : (g = f.forceX, k =\n            f.forceY, g < -e ? g = -e : g > e && (g = e), k < -e ? k = -e : k > e && (k = e), f.centerX += g, f.centerY += k, d = Math.max(d, g * g + k * k));\n        return d > a.epsilonDistance * a.epsilonDistance\n    }\n    Nr.prototype.moveFixedVertex = function () {};\n    Nr.prototype.commitLayout = function () {\n        this.fw();\n        this.commitNodes();\n        this.isRouting && this.commitLinks()\n    };\n    Nr.prototype.fw = function () {\n        if (this.setsPortSpots)\n            for (var a = this.network.edges.iterator; a.next();) {\n                var b = a.value.link;\n                null !== b && (b.fromSpot = Zc, b.toSpot = Zc)\n            }\n    };\n    Nr.prototype.commitNodes = function () {\n        var a = 0,\n            b = 0;\n        if (this.arrangesToOrigin) {\n            var c = N.alloc();\n            this.computeBounds(this.network, c);\n            b = this.arrangementOrigin;\n            a = b.x - c.x;\n            b = b.y - c.y;\n            N.free(c)\n        }\n        c = N.alloc();\n        for (var d = this.network.vertexes.iterator; d.next();) {\n            var e = d.value;\n            if (0 !== a || 0 !== b) c.assign(e.bounds), c.x += a, c.y += b, e.bounds = c;\n            e.commit()\n        }\n        N.free(c)\n    };\n    Nr.prototype.commitLinks = function () {\n        for (var a = this.network.edges.iterator; a.next();) a.value.commit()\n    };\n    Nr.prototype.springStiffness = function (a) {\n        a = a.stiffness;\n        return isNaN(a) ? this.Uk : a\n    };\n    Nr.prototype.springLength = function (a) {\n        a = a.length;\n        return isNaN(a) ? this.Tk : a\n    };\n    Nr.prototype.electricalCharge = function (a) {\n        a = a.charge;\n        return isNaN(a) ? this.Rk : a\n    };\n    Nr.prototype.electricalFieldX = function () {\n        return 0\n    };\n    Nr.prototype.electricalFieldY = function () {\n        return 0\n    };\n    Nr.prototype.gravitationalMass = function (a) {\n        a = a.mass;\n        return isNaN(a) ? this.Sk : a\n    };\n    Nr.prototype.gravitationalFieldX = function () {\n        return 0\n    };\n    Nr.prototype.gravitationalFieldY = function () {\n        return 0\n    };\n    Nr.prototype.isFixed = function (a) {\n        return a.isFixed\n    };\n    ma.Object.defineProperties(Nr.prototype, {\n        currentIteration: {\n            get: function () {\n                return this.jo\n            }\n        },\n        arrangementSpacing: {\n            get: function () {\n                return this.zd\n            },\n            set: function (a) {\n                this.zd.w(a) || (this.zd.assign(a), this.C())\n            }\n        },\n        arrangesToOrigin: {\n            get: function () {\n                return this.Xm\n            },\n            set: function (a) {\n                this.Xm !== a && (this.Xm = a, this.C())\n            }\n        },\n        setsPortSpots: {\n            get: function () {\n                return this.cf\n            },\n            set: function (a) {\n                this.cf !== a && (this.cf =\n                    a, this.C())\n            }\n        },\n        comments: {\n            get: function () {\n                return this.Zc\n            },\n            set: function (a) {\n                this.Zc !== a && (this.Zc = a, this.C())\n            }\n        },\n        maxIterations: {\n            get: function () {\n                return this.yl\n            },\n            set: function (a) {\n                this.yl !== a && 0 <= a && (this.yl = a, this.C())\n            }\n        },\n        epsilonDistance: {\n            get: function () {\n                return this.Fn\n            },\n            set: function (a) {\n                this.Fn !== a && 0 < a && (this.Fn = a, this.C())\n            }\n        },\n        infinityDistance: {\n            get: function () {\n                return this.Wf\n            },\n            set: function (a) {\n                this.Wf !==\n                    a && 1 < a && (this.Wf = a, this.C())\n            }\n        },\n        moveLimit: {\n            get: function () {\n                return this.Ho\n            },\n            set: function (a) {\n                this.Ho !== a && 1 < a && (this.Ho = a, this.C())\n            }\n        },\n        randomNumberGenerator: {\n            get: function () {\n                return this.hp\n            },\n            set: function (a) {\n                this.hp !== a && (null !== a && \"function\" !== typeof a.random && B('ForceDirectedLayout.randomNumberGenerator must have a \"random()\" function on it: ' + a), this.hp = a)\n            }\n        },\n        defaultSpringStiffness: {\n            get: function () {\n                return this.Uk\n            },\n            set: function (a) {\n                this.Uk !== a && (this.Uk = a, this.C())\n            }\n        },\n        defaultSpringLength: {\n            get: function () {\n                return this.Tk\n            },\n            set: function (a) {\n                this.Tk !== a && (this.Tk = a, this.C())\n            }\n        },\n        defaultElectricalCharge: {\n            get: function () {\n                return this.Rk\n            },\n            set: function (a) {\n                this.Rk !== a && (this.Rk = a, this.C())\n            }\n        },\n        defaultGravitationalMass: {\n            get: function () {\n                return this.Sk\n            },\n            set: function (a) {\n                this.Sk !== a && (this.Sk = a, this.C())\n            }\n        },\n        defaultCommentSpringLength: {\n            get: function () {\n                return this.wn\n            },\n            set: function (a) {\n                this.wn !== a && (this.wn = a, this.C())\n            }\n        },\n        defaultCommentElectricalCharge: {\n            get: function () {\n                return this.vn\n            },\n            set: function (a) {\n                this.vn !== a && (this.vn = a, this.C())\n            }\n        }\n    });\n    Nr.className = \"ForceDirectedLayout\";\n\n    function Wr() {\n        this.Aw = this.zw = this.Qt = this.St = this.Rt = 0\n    }\n    Wr.className = \"ForceDirectedSubnet\";\n\n    function Or(a) {\n        Qp.call(this, a)\n    }\n    la(Or, Qp);\n    Or.prototype.createVertex = function () {\n        return new $r(this)\n    };\n    Or.prototype.createEdge = function () {\n        return new as(this)\n    };\n    Or.className = \"ForceDirectedNetwork\";\n\n    function $r(a) {\n        Tp.call(this, a);\n        this.Ia = !1;\n        this.Za = this.I = NaN;\n        this.Mh = this.wd = this.Ha = this.Y = 0;\n        this.Fe = this.$j = null;\n        this.bw = 0\n    }\n    la($r, Tp);\n    ma.Object.defineProperties($r.prototype, {\n        isFixed: {\n            get: function () {\n                return this.Ia\n            },\n            set: function (a) {\n                this.Ia !== a && (this.Ia = a)\n            }\n        },\n        charge: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I !== a && (this.I = a)\n            }\n        },\n        mass: {\n            get: function () {\n                return this.Za\n            },\n            set: function (a) {\n                this.Za !== a && (this.Za = a)\n            }\n        },\n        forceX: {\n            get: function () {\n                return this.Y\n            },\n            set: function (a) {\n                this.Y !== a && (this.Y = a)\n            }\n        },\n        forceY: {\n            get: function () {\n                return this.Ha\n            },\n            set: function (a) {\n                this.Ha !== a && (this.Ha = a)\n            }\n        }\n    });\n    $r.className = \"ForceDirectedVertex\";\n\n    function as(a) {\n        Up.call(this, a);\n        this.l = this.u = NaN\n    }\n    la(as, Up);\n    ma.Object.defineProperties(as.prototype, {\n        stiffness: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u !== a && (this.u = a)\n            }\n        },\n        length: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l !== a && (this.l = a)\n            }\n        }\n    });\n    as.className = \"ForceDirectedEdge\";\n\n    function Zr() {\n        var a = 0;\n        void 0 === a && (a = 42);\n        this.seed = a;\n        this.sy = 48271;\n        this.uy = 2147483647;\n        this.Q = 44488.07041494893;\n        this.wy = 3399;\n        this.ty = 1 / 2147483647;\n        this.random()\n    }\n    Zr.prototype.random = function () {\n        var a = this.seed % this.Q * this.sy - this.seed / this.Q * this.wy;\n        0 < a ? this.seed = a : this.seed = a + this.uy;\n        return this.seed * this.ty\n    };\n    Zr.className = \"RandomNumberGenerator\";\n\n    function bs() {\n        Ci.call(this);\n        this.Zb = this.me = 25;\n        this.J = 0;\n        this.Pk = cs;\n        this.tl = ds;\n        this.il = es;\n        this.zj = 4;\n        this.Ek = fs;\n        this.mg = 7;\n        this.cf = !0;\n        this.ro = 4;\n        this.Da = this.Zr = this.xa = -1;\n        this.rd = this.Co = 0;\n        this.Ga = this.pd = this.qd = this.Kd = this.gc = null;\n        this.Mo = 0;\n        this.Lo = this.Ej = null;\n        this.Od = 0;\n        this.No = null;\n        this.Jf = new I;\n        this.pe = [];\n        this.pe.length = 100\n    }\n    la(bs, Ci);\n    bs.prototype.cloneProtected = function (a) {\n        Ci.prototype.cloneProtected.call(this, a);\n        a.me = this.me;\n        a.Zb = this.Zb;\n        a.J = this.J;\n        a.Pk = this.Pk;\n        a.tl = this.tl;\n        a.il = this.il;\n        a.zj = this.zj;\n        a.Ek = this.Ek;\n        a.mg = this.mg;\n        a.cf = this.cf;\n        a.ro = this.ro\n    };\n    bs.prototype.cb = function (a) {\n        a.classType === bs ? 0 === a.name.indexOf(\"Aggressive\") ? this.aggressiveOption = a : 0 === a.name.indexOf(\"Cycle\") ? this.cycleRemoveOption = a : 0 === a.name.indexOf(\"Init\") ? this.initializeOption = a : 0 === a.name.indexOf(\"Layer\") ? this.layeringOption = a : B(\"Unknown enum value: \" + a) : Ci.prototype.cb.call(this, a)\n    };\n    bs.prototype.createNetwork = function () {\n        return new gs(this)\n    };\n    bs.prototype.doLayout = function (a) {\n        null === this.network && (this.network = this.makeNetwork(a));\n        this.arrangementOrigin = this.initialOrigin(this.arrangementOrigin);\n        this.Zr = -1;\n        this.rd = this.Co = 0;\n        this.No = this.Lo = this.Ej = null;\n        for (a = 0; a < this.pe.length; a++) this.pe[a] = null;\n        if (0 < this.network.vertexes.count) {\n            this.network.iq();\n            this.cycleRemoveOption !== hs && this.removeCycles();\n            for (a = this.network.vertexes.iterator; a.next();) a.value.layer = -1;\n            this.xa = -1;\n            this.assignLayers();\n            for (a.reset(); a.next();) this.xa = Math.max(this.xa,\n                a.value.layer);\n            this.cycleRemoveOption === hs && this.removeCycles();\n            a = this.network;\n            for (var b = [], c = a.edges.iterator; c.next();) {\n                var d = c.value;\n                d.valid = !1;\n                b.push(d)\n            }\n            for (c = 0; c < b.length; c++) {\n                d = b[c];\n                var e = d.fromVertex,\n                    f = d.toVertex;\n                if (!d.valid && (null !== e.node && null !== f.node || e.layer !== f.layer)) {\n                    var g = 0,\n                        h = 0,\n                        k = 0,\n                        l = 0;\n                    if (null !== d.link) {\n                        h = d.link;\n                        if (null === h) continue;\n                        var m = e.node;\n                        g = f.node;\n                        if (null === m || null === g) continue;\n                        var n = h.fromNode;\n                        k = h.toNode;\n                        var p = h.fromPort;\n                        h = h.toPort;\n                        if (d.rev) {\n                            l = n;\n                            var r = p;\n                            n = k;\n                            p = h;\n                            k = l;\n                            h = r\n                        }\n                        var q =\n                            e.focus;\n                        l = f.focus;\n                        var u = d.rev ? f.bounds : e.bounds;\n                        r = I.alloc();\n                        m !== n ? u.v() && n.isVisible() ? n.actualBounds.v() ? (n.vf(p, Ac, r), r.x += n.actualBounds.x - u.x, r.y += n.actualBounds.y - u.y) : (n.vf(p, Ac, r), r.v() || r.assign(q)) : r.assign(q) : u.v() ? (n.vf(p, Ac, r), r.v() || r.assign(q)) : r.assign(q);\n                        n = d.rev ? e.bounds : f.bounds;\n                        m = I.alloc();\n                        g !== k ? n.v() && k.isVisible() ? k.actualBounds.v() ? (k.vf(h, Ac, m), m.x += k.actualBounds.x - n.x, m.y += k.actualBounds.y - n.y) : (k.vf(h, Ac, m), m.v() || m.assign(l)) : m.assign(l) : n.v() ? (k.vf(h, Ac, m), m.v() || m.assign(l)) :\n                            m.assign(l);\n                        90 === this.J || 270 === this.J ? (g = Math.round((r.x - q.x) / this.Zb), k = r.x, h = Math.round((m.x - l.x) / this.Zb), l = m.x) : (g = Math.round((r.y - q.y) / this.Zb), k = r.y, h = Math.round((m.y - l.y) / this.Zb), l = m.y);\n                        I.free(r);\n                        I.free(m);\n                        d.portFromColOffset = g;\n                        d.portFromPos = k;\n                        d.portToColOffset = h;\n                        d.portToPos = l\n                    } else d.portFromColOffset = 0, d.portFromPos = 0, d.portToColOffset = 0, d.portToPos = 0;\n                    r = e.layer;\n                    m = f.layer;\n                    n = 0;\n                    u = d.link;\n                    if (null !== u) {\n                        var v = u.fromPort,\n                            w = u.toPort;\n                        if (null !== v && null !== w) {\n                            var y = u.fromNode;\n                            p = u.toNode;\n                            if (null !== y &&\n                                null !== p) {\n                                var z = is(this, !0),\n                                    A = is(this, !1),\n                                    C = this.setsPortSpots ? z : u.computeSpot(!0, v);\n                                q = this.setsPortSpots ? A : u.computeSpot(!1, w);\n                                var G = u.isOrthogonal;\n                                C.yf() && C.wf(A) && q.yf() && q.wf(z) ? n = 0 : (z = u.getLinkPoint(y, v, C, !0, G, p, w, I.alloc()), A = u.getLinkDirection(y, v, z, C, !0, G, p, w), I.free(z), C.wt() || A !== js(this, d, !0) ? this.setsPortSpots && null !== y && 1 === y.ports.count && d.rev && (n += 1) : n += 1, C = u.getLinkPoint(p, w, q, !1, G, y, v, I.alloc()), u = u.getLinkDirection(p, w, C, q, !1, G, y, v), I.free(C), q.wt() || u !== js(this, d, !1) ? this.setsPortSpots &&\n                                    null !== p && 1 === p.ports.count && d.rev && (n += 2) : n += 2)\n                            }\n                        }\n                    }\n                    p = n;\n                    n = 1 === p || 3 === p ? !0 : !1;\n                    if (p = 2 === p || 3 === p ? !0 : !1) q = a.createVertex(), q.node = null, q.Wj = 1, q.layer = r, q.near = e, a.Eh(q), e = a.mk(e, q, d.link), e.valid = !1, e.rev = d.rev, e.portFromColOffset = g, e.portToColOffset = 0, e.portFromPos = k, e.portToPos = 0, e = q;\n                    u = 1;\n                    n && u--;\n                    if (r - m > u && 0 < r) {\n                        d.valid = !1;\n                        q = a.createVertex();\n                        q.node = null;\n                        q.Wj = 2;\n                        q.layer = r - 1;\n                        a.Eh(q);\n                        e = a.mk(e, q, d.link);\n                        e.valid = !0;\n                        e.rev = d.rev;\n                        e.portFromColOffset = p ? 0 : g;\n                        e.portToColOffset = 0;\n                        e.portFromPos = p ? 0 : k;\n                        e.portToPos = 0;\n                        e =\n                            q;\n                        for (r--; r - m > u && 0 < r;) q = a.createVertex(), q.node = null, q.Wj = 3, q.layer = r - 1, a.Eh(q), e = a.mk(e, q, d.link), e.valid = !0, e.rev = d.rev, e.portFromColOffset = 0, e.portToColOffset = 0, e.portFromPos = 0, e.portToPos = 0, e = q, r--;\n                        e = a.mk(q, f, d.link);\n                        e.valid = !n;\n                        n && (q.near = f);\n                        e.rev = d.rev;\n                        e.portFromColOffset = 0;\n                        e.portToColOffset = h;\n                        e.portFromPos = 0;\n                        e.portToPos = l\n                    } else d.valid = !0\n                }\n            }\n            a = this.gc = [];\n            for (b = 0; b <= this.xa; b++) a[b] = 0;\n            for (b = this.network.vertexes.iterator; b.next();) b.value.index = -1;\n            this.initializeIndices();\n            this.Zr = -1;\n            for (c = this.rd =\n                this.Co = 0; c <= this.xa; c++) a[c] > a[this.rd] && (this.Zr = a[c] - 1, this.rd = c), a[c] < a[this.Co] && (this.Co = c);\n            this.No = [];\n            for (c = 0; c < a.length; c++) this.No[c] = [];\n            for (b.reset(); b.next();) a = b.value, this.No[a.layer][a.index] = a;\n            this.Da = -1;\n            for (a = 0; a <= this.xa; a++) {\n                b = ks(this, a);\n                c = 0;\n                d = this.gc[a];\n                for (f = 0; f < d; f++) e = b[f], c += this.nodeMinColumnSpace(e, !0), e.column = c, c += 1, c += this.nodeMinColumnSpace(e, !1);\n                this.Da = Math.max(this.Da, c - 1);\n                ls(this, a, b)\n            }\n            this.reduceCrossings();\n            this.straightenAndPack();\n            this.updateParts()\n        }\n        this.network =\n            null;\n        this.isValidLayout = !0\n    };\n    bs.prototype.linkMinLength = function () {\n        return 1\n    };\n\n    function ms(a) {\n        var b = a.fromVertex.node;\n        a = a.toVertex.node;\n        return null === b && null === a ? 8 : null === b || null === a ? 4 : 1\n    }\n    bs.prototype.nodeMinLayerSpace = function (a, b) {\n        return null === a.node ? 0 : 90 === this.J || 270 === this.J ? b ? a.focus.y + 10 : a.bounds.height - a.focus.y + 10 : b ? a.focus.x + 10 : a.bounds.width - a.focus.x + 10\n    };\n    bs.prototype.nodeMinColumnSpace = function (a, b) {\n        if (null === a.node) return 0;\n        var c = b ? a.Ov : a.Nv;\n        if (null !== c) return c;\n        c = this.J;\n        return 90 === c || 270 === c ? b ? a.Ov = a.focus.x / this.Zb + 1 | 0 : a.Nv = (a.bounds.width - a.focus.x) / this.Zb + 1 | 0 : b ? a.Ov = a.focus.y / this.Zb + 1 | 0 : a.Nv = (a.bounds.height - a.focus.y) / this.Zb + 1 | 0\n    };\n\n    function ns(a) {\n        null === a.Ej && (a.Ej = []);\n        for (var b = 0, c = a.network.vertexes.iterator; c.next();) {\n            var d = c.value;\n            a.Ej[b] = d.layer;\n            b++;\n            a.Ej[b] = d.column;\n            b++;\n            a.Ej[b] = d.index;\n            b++\n        }\n        return a.Ej\n    }\n\n    function os(a, b) {\n        var c = 0;\n        for (a = a.network.vertexes.iterator; a.next();) {\n            var d = a.value;\n            d.layer = b[c];\n            c++;\n            d.column = b[c];\n            c++;\n            d.index = b[c];\n            c++\n        }\n    }\n\n    function ps(a, b, c) {\n        var d = ks(a, b),\n            e = a.gc[b];\n        if (null === a.Lo || a.Lo.length < e * e) a.Lo = [];\n        for (var f = a.Lo, g = 0; g < e; g++) {\n            var h = 0,\n                k = d[g],\n                l = k.near;\n            if (null !== l && l.layer === k.layer)\n                if (k = l.index, k > g)\n                    for (var m = g + 1; m < k; m++) {\n                        var n = d[m];\n                        n.near === l && n.Wj === l.Wj || h++\n                    } else\n                        for (m = g - 1; m > k; m--) n = d[m], n.near === l && n.Wj === l.Wj || h++;\n            var p;\n            if (0 <= c)\n                for (k = d[g].sourceEdgesArrayAccess, l = 0; l < k.length; l++) {\n                    var r = k[l];\n                    if (r.valid && r.fromVertex.layer !== b)\n                        for (n = r.fromVertex.index, m = r.portToPos, r = r.portFromPos, p = l + 1; p < k.length; p++) {\n                            var q =\n                                k[p];\n                            if (q.valid && q.fromVertex.layer !== b) {\n                                var u = q.fromVertex.index;\n                                var v = q.portToPos;\n                                q = q.portFromPos;\n                                m < v && (n > u || n === u && r > q) && h++;\n                                v < m && (u > n || u === n && q > r) && h++\n                            }\n                        }\n                }\n            if (0 >= c)\n                for (k = d[g].destinationEdgesArrayAccess, l = 0; l < k.length; l++)\n                    if (r = k[l], r.valid && r.toVertex.layer !== b)\n                        for (n = r.toVertex.index, m = r.portToPos, r = r.portFromPos, p = l + 1; p < k.length; p++) q = k[p], q.valid && q.toVertex.layer !== b && (u = q.toVertex.index, v = q.portToPos, q = q.portFromPos, r < q && (n > u || n === u && m > v) && h++, q < r && (u > n || u === n && v > m) && h++);\n            f[g * e + g] = h;\n            for (k = g +\n                1; k < e; k++) {\n                var w = 0,\n                    y = 0;\n                if (0 <= c) {\n                    h = d[g].sourceEdgesArrayAccess;\n                    var z = d[k].sourceEdgesArrayAccess;\n                    for (l = 0; l < h.length; l++)\n                        if (r = h[l], r.valid && r.fromVertex.layer !== b)\n                            for (n = r.fromVertex.index, r = r.portFromPos, p = 0; p < z.length; p++) q = z[p], q.valid && q.fromVertex.layer !== b && (u = q.fromVertex.index, q = q.portFromPos, (n < u || n === u && r < q) && y++, (u < n || u === n && q < r) && w++)\n                }\n                if (0 >= c)\n                    for (h = d[g].destinationEdgesArrayAccess, z = d[k].destinationEdgesArrayAccess, l = 0; l < h.length; l++)\n                        if (r = h[l], r.valid && r.toVertex.layer !== b)\n                            for (n = r.toVertex.index,\n                                m = r.portToPos, p = 0; p < z.length; p++) q = z[p], q.valid && q.toVertex.layer !== b && (u = q.toVertex.index, v = q.portToPos, (n < u || n === u && m < v) && y++, (u < n || u === n && v < m) && w++);\n                f[g * e + k] = w;\n                f[k * e + g] = y\n            }\n        }\n        ls(a, b, d);\n        return f\n    }\n    bs.prototype.countCrossings = function () {\n        for (var a = 0, b = 0; b <= this.xa; b++)\n            for (var c = ps(this, b, 1), d = this.gc[b], e = 0; e < d; e++)\n                for (var f = e; f < d; f++) a += c[e * d + f];\n        return a\n    };\n\n    function qs(a) {\n        for (var b = 0, c = 0; c <= a.xa; c++) {\n            for (var d = a, e = c, f = ks(d, e), g = d.gc[e], h = 0, k = 0; k < g; k++) {\n                var l = f[k].destinationEdgesArrayAccess;\n                if (null !== l)\n                    for (var m = 0; m < l.length; m++) {\n                        var n = l[m];\n                        if (n.valid && n.toVertex.layer !== e) {\n                            var p = n.fromVertex.column + n.portFromColOffset;\n                            var r = n.toVertex.column + n.portToColOffset;\n                            h += (Math.abs(p - r) + 1) * ms(n)\n                        }\n                    }\n            }\n            ls(d, e, f);\n            b += h\n        }\n        return b\n    }\n    bs.prototype.normalize = function () {\n        var a = Infinity;\n        this.Da = -1;\n        for (var b = this.network.vertexes.iterator; b.next();) {\n            var c = b.value;\n            a = Math.min(a, c.column - this.nodeMinColumnSpace(c, !0));\n            this.Da = Math.max(this.Da, c.column + this.nodeMinColumnSpace(c, !1))\n        }\n        for (b.reset(); b.next();) b.value.column -= a;\n        this.Da -= a\n    };\n\n    function rs(a, b, c) {\n        for (var d = ks(a, b), e = a.gc[b], f = [], g = 0; g < e; g++) {\n            var h = d[g],\n                k = null;\n            0 >= c && (k = h.sourceEdgesArrayAccess);\n            var l = null;\n            0 <= c && (l = h.destinationEdgesArrayAccess);\n            var m = 0,\n                n = 0,\n                p = h.near;\n            null !== p && p.layer === h.layer && (m += p.column - 1, n++);\n            if (null !== k)\n                for (p = 0; p < k.length; p++) {\n                    h = k[p];\n                    var r = h.fromVertex;\n                    h.valid && !h.rev && r.layer !== b && (m += r.column, n++)\n                }\n            if (null !== l)\n                for (k = 0; k < l.length; k++) h = l[k], p = h.toVertex, h.valid && !h.rev && p.layer !== b && (m += p.column, n++);\n            f[g] = 0 === n ? -1 : m / n\n        }\n        ls(a, b, d);\n        return f\n    }\n\n    function ss(a, b, c) {\n        for (var d = ks(a, b), e = a.gc[b], f = [], g = 0; g < e; g++) {\n            var h = d[g],\n                k = null;\n            0 >= c && (k = h.sourceEdgesArrayAccess);\n            var l = null;\n            0 <= c && (l = h.destinationEdgesArrayAccess);\n            var m = 0,\n                n = [],\n                p = h.near;\n            null !== p && p.layer === h.layer && (n[m] = p.column - 1, m++);\n            h = void 0;\n            if (null !== k)\n                for (p = 0; p < k.length; p++) {\n                    h = k[p];\n                    var r = h.fromVertex;\n                    h.valid && !h.rev && r.layer !== b && (n[m] = r.column + h.portFromColOffset, m++)\n                }\n            if (null !== l)\n                for (k = 0; k < l.length; k++) h = l[k], p = h.toVertex, h.valid && !h.rev && p.layer !== b && (n[m] = p.column + h.portToColOffset,\n                    m++);\n            0 === m ? f[g] = -1 : (n.sort(function (a, b) {\n                return a - b\n            }), l = m >> 1, f[g] = 0 !== (m & 1) ? n[l] : n[l - 1] + n[l] >> 1)\n        }\n        ls(a, b, d);\n        return f\n    }\n\n    function ts(a, b, c, d, e, f) {\n        if (b.component === d) {\n            b.component = c;\n            if (e)\n                for (var g = b.destinationEdges; g.next();) {\n                    var h = g.value;\n                    var k = h.toVertex;\n                    var l = b.layer - k.layer;\n                    h = a.linkMinLength(h);\n                    l === h && ts(a, k, c, d, e, f)\n                }\n            if (f)\n                for (g = b.sourceEdges; g.next();) h = g.value, k = h.fromVertex, l = k.layer - b.layer, h = a.linkMinLength(h), l === h && ts(a, k, c, d, e, f)\n        }\n    }\n\n    function us(a, b, c, d, e, f) {\n        if (b.component === d) {\n            b.component = c;\n            if (e)\n                for (var g = b.destinationEdges; g.next();) us(a, g.value.toVertex, c, d, e, f);\n            if (f)\n                for (b = b.sourceEdges; b.next();) us(a, b.value.fromVertex, c, d, e, f)\n        }\n    }\n    bs.prototype.removeCycles = function () {\n        for (var a = this.network.edges.iterator; a.next();) a.value.rev = !1;\n        switch (this.Pk) {\n            default:\n            case vs:\n                a = this.network;\n                var b = 0,\n                    c = a.vertexes.count - 1,\n                    d = [];\n                d.length = c + 1;\n                for (var e = a.vertexes.iterator; e.next();) e.value.valid = !0;\n                for (; null !== ws(a);) {\n                    for (e = xs(a); null !== e;) d[c] = e, c--, e.valid = !1, e = xs(a);\n                    for (e = ys(a); null !== e;) d[b] = e, b++, e.valid = !1, e = ys(a);\n                    e = null;\n                    for (var f = 0, g = this.network.vertexes.iterator; g.next();) {\n                        var h = g.value;\n                        if (h.valid) {\n                            for (var k = 0, l = h.destinationEdges; l.next();) l.value.toVertex.valid &&\n                                k++;\n                            l = 0;\n                            for (var m = h.sourceEdges; m.next();) m.value.fromVertex.valid && l++;\n                            if (null === e || f < k - l) e = h, f = k - l\n                        }\n                    }\n                    null !== e && (d[b] = e, b++, e.valid = !1)\n                }\n                for (b = 0; b < a.vertexes.count; b++) d[b].index = b;\n                for (d = a.edges.iterator; d.next();) b = d.value, b.fromVertex.index > b.toVertex.index && (a.Em(b), b.rev = !0);\n                break;\n            case cs:\n                for (d = this.network.vertexes.iterator; d.next();) a = d.value, a.fm = -1, a.finish = -1;\n                for (a = this.network.edges.iterator; a.next();) a.value.forest = !1;\n                this.Mo = 0;\n                for (d.reset(); d.next();) b = d.value, 0 === b.sourceEdges.count &&\n                    zs(this, b);\n                for (d.reset(); d.next();) b = d.value, -1 === b.fm && zs(this, b);\n                for (a.reset(); a.next();) d = a.value, d.forest || (b = d.fromVertex, c = b.finish, e = d.toVertex, f = e.finish, e.fm < b.fm && c < f && (this.network.Em(d), d.rev = !0));\n                break;\n            case hs:\n                a = this.network;\n                b = a.vertexes.iterator;\n                for (d = Infinity; b.next();) d = Math.min(d, b.value.layer);\n                if (Infinity > d) {\n                    if (0 > d)\n                        for (b.reset(); b.next();) b.value.layer -= d;\n                    d = [];\n                    for (b.reset(); b.next();) c = b.value, e = d[c.layer], void 0 === e ? d[c.layer] = [c] : e.push(c);\n                    for (c = b = 0; c < d.length; c++)\n                        if (e = d[c], !e ||\n                            0 === e.length) b++;\n                        else if (0 < c)\n                        for (f = 0; f < e.length; f++) e[f].layer -= b;\n                    for (d = a.edges.iterator; d.next();) b = d.value, b.fromVertex.layer < b.toVertex.layer && (a.Em(b), b.rev = !0)\n                }\n        }\n    };\n\n    function ws(a) {\n        for (a = a.vertexes.iterator; a.next();) {\n            var b = a.value;\n            if (b.valid) return b\n        }\n        return null\n    }\n\n    function xs(a) {\n        for (a = a.vertexes.iterator; a.next();) {\n            var b = a.value;\n            if (b.valid) {\n                for (var c = !0, d = b.destinationEdges; d.next();)\n                    if (d.value.toVertex.valid) {\n                        c = !1;\n                        break\n                    } if (c) return b\n            }\n        }\n        return null\n    }\n\n    function ys(a) {\n        for (a = a.vertexes.iterator; a.next();) {\n            var b = a.value;\n            if (b.valid) {\n                for (var c = !0, d = b.sourceEdges; d.next();)\n                    if (d.value.fromVertex.valid) {\n                        c = !1;\n                        break\n                    } if (c) return b\n            }\n        }\n        return null\n    }\n\n    function zs(a, b) {\n        b.fm = a.Mo;\n        a.Mo++;\n        for (var c = b.destinationEdges; c.next();) {\n            var d = c.value,\n                e = d.toVertex; - 1 === e.fm && (d.forest = !0, zs(a, e))\n        }\n        b.finish = a.Mo;\n        a.Mo++\n    }\n    bs.prototype.assignLayers = function () {\n        switch (this.tl) {\n            case As:\n                Bs(this);\n                break;\n            case Cs:\n                for (var a, b = this.network.vertexes.iterator; b.next();) a = Ds(this, b.value), this.xa = Math.max(a, this.xa);\n                for (b.reset(); b.next();) a = b.value, a.layer = this.xa - a.layer;\n                break;\n            default:\n            case ds:\n                Bs(this);\n                for (b = this.network.vertexes.iterator; b.next();) b.value.valid = !1;\n                for (b.reset(); b.next();) a = b.value, 0 === a.sourceEdges.count && Es(this, a);\n                a = Infinity;\n                for (b.reset(); b.next();) a = Math.min(a, b.value.layer);\n                this.xa = -1;\n                for (b.reset(); b.next();) {\n                    var c =\n                        b.value;\n                    c.layer -= a;\n                    this.xa = Math.max(this.xa, c.layer)\n                }\n        }\n    };\n\n    function Bs(a) {\n        for (var b = a.network.vertexes.iterator; b.next();) {\n            var c = Fs(a, b.value);\n            a.xa = Math.max(c, a.xa)\n        }\n    }\n\n    function Fs(a, b) {\n        var c = 0;\n        if (-1 === b.layer) {\n            for (var d = b.destinationEdges; d.next();) {\n                var e = d.value,\n                    f = e.toVertex;\n                e = a.linkMinLength(e);\n                c = Math.max(c, Fs(a, f) + e)\n            }\n            b.layer = c\n        } else c = b.layer;\n        return c\n    }\n\n    function Ds(a, b) {\n        var c = 0;\n        if (-1 === b.layer) {\n            for (var d = b.sourceEdges; d.next();) {\n                var e = d.value,\n                    f = e.fromVertex;\n                e = a.linkMinLength(e);\n                c = Math.max(c, Ds(a, f) + e)\n            }\n            b.layer = c\n        } else c = b.layer;\n        return c\n    }\n\n    function Es(a, b) {\n        if (!b.valid) {\n            b.valid = !0;\n            for (var c = b.destinationEdges; c.next();) Es(a, c.value.toVertex);\n            for (c = a.network.vertexes.iterator; c.next();) c.value.component = -1;\n            for (var d = b.sourceEdgesArrayAccess, e = d.length, f = 0; f < e; f++) {\n                var g = d[f],\n                    h = g.fromVertex,\n                    k = g.toVertex;\n                g = a.linkMinLength(g);\n                h.layer - k.layer > g && ts(a, h, 0, -1, !0, !1)\n            }\n            for (ts(a, b, 1, -1, !0, !0); 0 !== b.component;) {\n                f = 0;\n                d = Infinity;\n                h = 0;\n                k = null;\n                for (g = a.network.vertexes.iterator; g.next();) {\n                    var l = g.value;\n                    if (1 === l.component) {\n                        var m = 0,\n                            n = !1,\n                            p = l.sourceEdgesArrayAccess;\n                        e = p.length;\n                        for (var r = 0; r < e; r++) {\n                            var q = p[r],\n                                u = q.fromVertex;\n                            m += 1;\n                            1 !== u.component && (f += 1, u = u.layer - l.layer, q = a.linkMinLength(q), d = Math.min(d, u - q))\n                        }\n                        p = l.destinationEdgesArrayAccess;\n                        e = p.length;\n                        for (r = 0; r < e; r++) q = p[r].toVertex, --m, 1 !== q.component ? --f : n = !0;\n                        (null === k || m < h) && !n && (k = l, h = m)\n                    }\n                }\n                if (0 < f) {\n                    for (c.reset(); c.next();) e = c.value, 1 === e.component && (e.layer += d);\n                    b.component = 0\n                } else k.component = 0\n            }\n            for (c = a.network.vertexes.iterator; c.next();) c.value.component = -1;\n            for (ts(a, b, 1, -1, !0, !1); 0 !== b.component;) {\n                d = 0;\n                e = Infinity;\n                f = 0;\n                h = null;\n                for (k = a.network.vertexes.iterator; k.next();)\n                    if (g = k.value, 1 === g.component) {\n                        l = 0;\n                        m = !1;\n                        p = g.sourceEdgesArrayAccess;\n                        n = p.length;\n                        for (r = 0; r < n; r++) q = p[r].fromVertex, l += 1, 1 !== q.component ? d += 1 : m = !0;\n                        p = g.destinationEdgesArrayAccess;\n                        n = p.length;\n                        for (r = 0; r < n; r++) q = p[r], u = q.toVertex, --l, 1 !== u.component && (--d, u = g.layer - u.layer, q = a.linkMinLength(q), e = Math.min(e, u - q));\n                        (null === h || l > f) && !m && (h = g, f = l)\n                    } if (0 > d) {\n                    for (c.reset(); c.next();) d = c.value, 1 === d.component && (d.layer -= e);\n                    b.component = 0\n                } else h.component = 0\n            }\n        }\n    }\n\n    function js(a, b, c) {\n        return 90 === a.J ? c && !b.rev || !c && b.rev ? 270 : 90 : 180 === a.J ? c && !b.rev || !c && b.rev ? 0 : 180 : 270 === a.J ? c && !b.rev || !c && b.rev ? 90 : 270 : c && !b.rev || !c && b.rev ? 180 : 0\n    }\n    bs.prototype.initializeIndices = function () {\n        switch (this.il) {\n            default:\n            case Gs:\n                for (var a = this.network.vertexes.iterator; a.next();) {\n                    var b = a.value,\n                        c = b.layer;\n                    b.index = this.gc[c];\n                    this.gc[c]++\n                }\n                break;\n            case es:\n                a = this.network.vertexes.iterator;\n                for (b = this.xa; 0 <= b; b--)\n                    for (a.reset(); a.next();) c = a.value, c.layer === b && -1 === c.index && Hs(this, c);\n                break;\n            case Is:\n                for (a = this.network.vertexes.iterator, b = 0; b <= this.xa; b++)\n                    for (a.reset(); a.next();) c = a.value, c.layer === b && -1 === c.index && Js(this, c)\n        }\n    };\n\n    function Hs(a, b) {\n        var c = b.layer;\n        b.index = a.gc[c];\n        a.gc[c]++;\n        b = b.destinationEdgesArrayAccess;\n        for (c = !0; c;) {\n            c = !1;\n            for (var d = 0; d < b.length - 1; d++) {\n                var e = b[d],\n                    f = b[d + 1];\n                e.portFromColOffset > f.portFromColOffset && (c = !0, b[d] = f, b[d + 1] = e)\n            }\n        }\n        for (c = 0; c < b.length; c++) d = b[c], d.valid && (d = d.toVertex, -1 === d.index && Hs(a, d))\n    }\n\n    function Js(a, b) {\n        var c = b.layer;\n        b.index = a.gc[c];\n        a.gc[c]++;\n        b = b.sourceEdgesArrayAccess;\n        for (var d = !0; d;)\n            for (d = !1, c = 0; c < b.length - 1; c++) {\n                var e = b[c],\n                    f = b[c + 1];\n                e.portToColOffset > f.portToColOffset && (d = !0, b[c] = f, b[c + 1] = e)\n            }\n        for (c = 0; c < b.length; c++) d = b[c], d.valid && (d = d.fromVertex, -1 === d.index && Js(a, d))\n    }\n    bs.prototype.reduceCrossings = function () {\n        var a = this.countCrossings(),\n            b = ns(this),\n            c, d;\n        for (c = 0; c < this.zj; c++) {\n            for (d = 0; d <= this.xa; d++) Ks(this, d, 1), Ls(this, d, 1);\n            var e = this.countCrossings();\n            e < a && (a = e, b = ns(this));\n            for (d = this.xa; 0 <= d; d--) Ks(this, d, -1), Ls(this, d, -1);\n            e = this.countCrossings();\n            e < a && (a = e, b = ns(this))\n        }\n        os(this, b);\n        for (c = 0; c < this.zj; c++) {\n            for (d = 0; d <= this.xa; d++) Ks(this, d, 0), Ls(this, d, 0);\n            e = this.countCrossings();\n            e < a && (a = e, b = ns(this));\n            for (d = this.xa; 0 <= d; d--) Ks(this, d, 0), Ls(this, d, 0);\n            e = this.countCrossings();\n            e < a && (a = e, b = ns(this))\n        }\n        os(this, b);\n        var f, g, h;\n        switch (this.Ek) {\n            case Ms:\n                break;\n            case Ns:\n                for (h = a + 1;\n                    (d = this.countCrossings()) < h;)\n                    for (h = d, c = this.xa; 0 <= c; c--)\n                        for (g = 0; g <= c; g++) {\n                            for (f = !0; f;)\n                                for (f = !1, d = c; d >= g; d--) f = Ls(this, d, -1) || f;\n                            e = this.countCrossings();\n                            e >= a ? os(this, b) : (a = e, b = ns(this));\n                            for (f = !0; f;)\n                                for (f = !1, d = c; d >= g; d--) f = Ls(this, d, 1) || f;\n                            e = this.countCrossings();\n                            e >= a ? os(this, b) : (a = e, b = ns(this));\n                            for (f = !0; f;)\n                                for (f = !1, d = g; d <= c; d++) f = Ls(this, d, 1) || f;\n                            e >= a ? os(this, b) : (a = e, b = ns(this));\n                            for (f = !0; f;)\n                                for (f = !1, d = g; d <= c; d++) f =\n                                    Ls(this, d, -1) || f;\n                            e >= a ? os(this, b) : (a = e, b = ns(this));\n                            for (f = !0; f;)\n                                for (f = !1, d = c; d >= g; d--) f = Ls(this, d, 0) || f;\n                            e >= a ? os(this, b) : (a = e, b = ns(this));\n                            for (f = !0; f;)\n                                for (f = !1, d = g; d <= c; d++) f = Ls(this, d, 0) || f;\n                            e >= a ? os(this, b) : (a = e, b = ns(this))\n                        }\n                break;\n            default:\n            case fs:\n                for (c = this.xa, g = 0, h = a + 1;\n                    (d = this.countCrossings()) < h;) {\n                    h = d;\n                    for (f = !0; f;)\n                        for (f = !1, d = c; d >= g; d--) f = Ls(this, d, -1) || f;\n                    e = this.countCrossings();\n                    e >= a ? os(this, b) : (a = e, b = ns(this));\n                    for (f = !0; f;)\n                        for (f = !1, d = c; d >= g; d--) f = Ls(this, d, 1) || f;\n                    e = this.countCrossings();\n                    e >= a ? os(this, b) :\n                        (a = e, b = ns(this));\n                    for (f = !0; f;)\n                        for (f = !1, d = g; d <= c; d++) f = Ls(this, d, 1) || f;\n                    e >= a ? os(this, b) : (a = e, b = ns(this));\n                    for (f = !0; f;)\n                        for (f = !1, d = g; d <= c; d++) f = Ls(this, d, -1) || f;\n                    e >= a ? os(this, b) : (a = e, b = ns(this));\n                    for (f = !0; f;)\n                        for (f = !1, d = c; d >= g; d--) f = Ls(this, d, 0) || f;\n                    e >= a ? os(this, b) : (a = e, b = ns(this));\n                    for (f = !0; f;)\n                        for (f = !1, d = g; d <= c; d++) f = Ls(this, d, 0) || f;\n                    e >= a ? os(this, b) : (a = e, b = ns(this))\n                }\n        }\n        os(this, b)\n    };\n\n    function Ks(a, b, c) {\n        var d = ks(a, b),\n            e = a.gc[b],\n            f = ss(a, b, c),\n            g = rs(a, b, c);\n        for (c = 0; c < e; c++) - 1 === g[c] && (g[c] = d[c].column), -1 === f[c] && (f[c] = d[c].column);\n        for (var h = !0, k; h;)\n            for (h = !1, c = 0; c < e - 1; c++)\n                if (f[c + 1] < f[c] || f[c + 1] === f[c] && g[c + 1] < g[c]) h = !0, k = f[c], f[c] = f[c + 1], f[c + 1] = k, k = g[c], g[c] = g[c + 1], g[c + 1] = k, k = d[c], d[c] = d[c + 1], d[c + 1] = k;\n        for (c = f = 0; c < e; c++) k = d[c], k.index = c, f += a.nodeMinColumnSpace(k, !0), k.column = f, f += 1, f += a.nodeMinColumnSpace(k, !1);\n        ls(a, b, d)\n    }\n\n    function Ls(a, b, c) {\n        var d = ks(a, b),\n            e = a.gc[b];\n        c = ps(a, b, c);\n        var f;\n        var g = [];\n        for (f = 0; f < e; f++) g[f] = -1;\n        var h = [];\n        for (f = 0; f < e; f++) h[f] = -1;\n        for (var k = !1, l = !0; l;)\n            for (l = !1, f = 0; f < e - 1; f++) {\n                var m = c[d[f].index * e + d[f + 1].index],\n                    n = c[d[f + 1].index * e + d[f].index],\n                    p = 0,\n                    r = 0,\n                    q = d[f].column,\n                    u = d[f + 1].column,\n                    v = a.nodeMinColumnSpace(d[f], !0),\n                    w = a.nodeMinColumnSpace(d[f], !1),\n                    y = a.nodeMinColumnSpace(d[f + 1], !0),\n                    z = a.nodeMinColumnSpace(d[f + 1], !1);\n                v = q - v + y;\n                w = u - w + z;\n                var A = d[f].sourceEdges.iterator;\n                for (A.reset(); A.next();)\n                    if (y = A.value, z = y.fromVertex,\n                        y.valid && z.layer === b) {\n                        for (y = 0; d[y] !== z;) y++;\n                        y < f && (p += 2 * (f - y), r += 2 * (f + 1 - y));\n                        y === f + 1 && (p += 1);\n                        y > f + 1 && (p += 4 * (y - f), r += 4 * (y - (f + 1)))\n                    } A = d[f].destinationEdges.iterator;\n                for (A.reset(); A.next();)\n                    if (y = A.value, z = y.toVertex, y.valid && z.layer === b) {\n                        for (y = 0; d[y] !== z;) y++;\n                        y === f + 1 && (r += 1)\n                    } A = d[f + 1].sourceEdges.iterator;\n                for (A.reset(); A.next();)\n                    if (y = A.value, z = y.fromVertex, y.valid && z.layer === b) {\n                        for (y = 0; d[y] !== z;) y++;\n                        y < f && (p += 2 * (f + 1 - y), r += 2 * (f - y));\n                        y === f && (r += 1);\n                        y > f + 1 && (p += 4 * (y - (f + 1)), r += 4 * (y - f))\n                    } A = d[f + 1].destinationEdges.iterator;\n                for (A.reset(); A.next();)\n                    if (y = A.value, z = y.toVertex, y.valid && z.layer === b) {\n                        for (y = 0; d[y] !== z;) y++;\n                        y === f && (p += 1)\n                    } y = z = 0;\n                A = g[d[f].index];\n                var C = h[d[f].index],\n                    G = g[d[f + 1].index],\n                    L = h[d[f + 1].index]; - 1 !== A && (z += Math.abs(A - q), y += Math.abs(A - w)); - 1 !== C && (z += Math.abs(C - q), y += Math.abs(C - w)); - 1 !== G && (z += Math.abs(G - u), y += Math.abs(G - v)); - 1 !== L && (z += Math.abs(L - u), y += Math.abs(L - v));\n                if (r < p - .5 || r === p && n < m - .5 || r === p && n === m && y < z - .5) l = k = !0, d[f].column = w, d[f + 1].column = v, m = d[f], d[f] = d[f + 1], d[f + 1] = m\n            }\n        for (f = 0; f < e; f++) d[f].index =\n            f;\n        ls(a, b, d);\n        return k\n    }\n    bs.prototype.straightenAndPack = function () {\n        var a = 0 !== (this.mg & 1);\n        var b = 7 === this.mg;\n        1E3 < this.network.edges.count && !b && (a = !1);\n        if (a) {\n            var c = [];\n            for (b = 0; b <= this.xa; b++) c[b] = 0;\n            for (var d, e = this.network.vertexes.iterator; e.next();) {\n                var f = e.value;\n                b = f.layer;\n                d = f.column;\n                f = this.nodeMinColumnSpace(f, !1);\n                c[b] = Math.max(c[b], d + f)\n            }\n            for (e.reset(); e.next();) f = e.value, b = f.layer, d = f.column, f.column = (8 * (this.Da - c[b]) >> 1) + 8 * d;\n            this.Da *= 8\n        }\n        if (0 !== (this.mg & 2))\n            for (c = !0; c;) {\n                c = !1;\n                for (b = this.rd + 1; b <= this.xa; b++) c = Os(this, b, 1) || c;\n                for (b =\n                    this.rd - 1; 0 <= b; b--) c = Os(this, b, -1) || c;\n                c = Os(this, this.rd, 0) || c\n            }\n        if (0 !== (this.mg & 4)) {\n            for (b = this.rd + 1; b <= this.xa; b++) Ps(this, b, 1);\n            for (b = this.rd - 1; 0 <= b; b--) Ps(this, b, -1);\n            Ps(this, this.rd, 0)\n        }\n        a && (Qs(this, -1), Qs(this, 1));\n        if (0 !== (this.mg & 2))\n            for (c = !0; c;) {\n                c = !1;\n                c = Os(this, this.rd, 0) || c;\n                for (b = this.rd + 1; b <= this.xa; b++) c = Os(this, b, 0) || c;\n                for (b = this.rd - 1; 0 <= b; b--) c = Os(this, b, 0) || c\n            }\n    };\n\n    function Os(a, b, c) {\n        for (var d = !1; Rs(a, b, c);) d = !0;\n        return d\n    }\n\n    function Rs(a, b, c) {\n        var d, e = ks(a, b),\n            f = a.gc[b],\n            g = rs(a, b, -1);\n        if (0 < c)\n            for (d = 0; d < f; d++) g[d] = -1;\n        var h = rs(a, b, 1);\n        if (0 > c)\n            for (d = 0; d < f; d++) h[d] = -1;\n        for (var k = !1, l = !0; l;)\n            for (l = !1, d = 0; d < f; d++) {\n                var m = e[d].column,\n                    n = a.nodeMinColumnSpace(e[d], !0),\n                    p = a.nodeMinColumnSpace(e[d], !1),\n                    r = 0;\n                0 > d - 1 || m - e[d - 1].column - 1 > n + a.nodeMinColumnSpace(e[d - 1], !1) ? r = m - 1 : r = m;\n                n = d + 1 >= f || e[d + 1].column - m - 1 > p + a.nodeMinColumnSpace(e[d + 1], !0) ? m + 1 : m;\n                var q = p = 0,\n                    u = 0;\n                if (0 >= c)\n                    for (var v = e[d].sourceEdges.iterator; v.next();) {\n                        var w = v.value;\n                        var y = w.fromVertex;\n                        if (w.valid && y.layer !== b) {\n                            var z = ms(w);\n                            var A = w.portFromColOffset;\n                            w = w.portToColOffset;\n                            y = y.column;\n                            p += (Math.abs(m + w - (y + A)) + 1) * z;\n                            q += (Math.abs(r + w - (y + A)) + 1) * z;\n                            u += (Math.abs(n + w - (y + A)) + 1) * z\n                        }\n                    }\n                if (0 <= c)\n                    for (v = e[d].destinationEdges.iterator; v.next();) w = v.value, y = w.toVertex, w.valid && y.layer !== b && (z = ms(w), A = w.portFromColOffset, w = w.portToColOffset, y = y.column, p += (Math.abs(m + A - (y + w)) + 1) * z, q += (Math.abs(r + A - (y + w)) + 1) * z, u += (Math.abs(n + A - (y + w)) + 1) * z);\n                w = A = z = 0;\n                v = g[e[d].index];\n                y = h[e[d].index]; - 1 !== v && (z += Math.abs(v - m), A +=\n                    Math.abs(v - r), w += Math.abs(v - n)); - 1 !== y && (z += Math.abs(y - m), A += Math.abs(y - r), w += Math.abs(y - n));\n                if (q < p || q === p && A < z) l = k = !0, e[d].column = r;\n                else if (u < p || u === p && w < z) l = k = !0, e[d].column = n\n            }\n        ls(a, b, e);\n        a.normalize();\n        return k\n    }\n\n    function Ps(a, b, c) {\n        var d = ks(a, b),\n            e = a.gc[b],\n            f = ss(a, b, c),\n            g = [];\n        for (c = 0; c < e; c++) g[c] = f[c];\n        for (f = !0; f;)\n            for (f = !1, c = 0; c < e; c++) {\n                var h = d[c].column,\n                    k = a.nodeMinColumnSpace(d[c], !0),\n                    l = a.nodeMinColumnSpace(d[c], !1),\n                    m = 0;\n                if (-1 === g[c])\n                    if (0 === c && c === e - 1) m = h;\n                    else if (0 === c) {\n                    var n = d[c + 1].column;\n                    n - h === l + a.nodeMinColumnSpace(d[c + 1], !0) ? m = h - 1 : m = h\n                } else c === e - 1 ? (n = d[c - 1].column, m = h - n === k + a.nodeMinColumnSpace(d[c - 1], !1) ? h + 1 : h) : (n = d[c - 1].column, k = n + a.nodeMinColumnSpace(d[c - 1], !1) + k + 1, n = d[c + 1].column, l = n - a.nodeMinColumnSpace(d[c +\n                    1], !0) - l - 1, m = (k + l) / 2 | 0);\n                else 0 === c && c === e - 1 ? m = g[c] : 0 === c ? (n = d[c + 1].column, l = n - a.nodeMinColumnSpace(d[c + 1], !0) - l - 1, m = Math.min(g[c], l)) : c === e - 1 ? (n = d[c - 1].column, k = n + a.nodeMinColumnSpace(d[c - 1], !1) + k + 1, m = Math.max(g[c], k)) : (n = d[c - 1].column, k = n + a.nodeMinColumnSpace(d[c - 1], !1) + k + 1, n = d[c + 1].column, l = n - a.nodeMinColumnSpace(d[c + 1], !0) - l - 1, k < g[c] && g[c] < l ? m = g[c] : k >= g[c] ? m = k : l <= g[c] && (m = l));\n                m !== h && (f = !0, d[c].column = m)\n            }\n        ls(a, b, d);\n        a.normalize()\n    }\n\n    function Ss(a, b) {\n        for (var c = !0, d = a.network.vertexes.iterator; d.next();) {\n            var e = d.value,\n                f = a.nodeMinColumnSpace(e, !0),\n                g = a.nodeMinColumnSpace(e, !1);\n            if (e.column - f <= b && e.column + g >= b) {\n                c = !1;\n                break\n            }\n        }\n        a = !1;\n        if (c)\n            for (d.reset(); d.next();) c = d.value, c.column > b && (--c.column, a = !0);\n        return a\n    }\n\n    function Ts(a, b) {\n        var c = b + 1;\n        var d, e = [],\n            f = [];\n        for (d = 0; d <= a.xa; d++) e[d] = !1, f[d] = !1;\n        for (var g = a.network.vertexes.iterator; g.next();) {\n            d = g.value;\n            var h = d.column - a.nodeMinColumnSpace(d, !0),\n                k = d.column + a.nodeMinColumnSpace(d, !1);\n            h <= b && k >= b && (e[d.layer] = !0);\n            h <= c && k >= c && (f[d.layer] = !0)\n        }\n        h = !0;\n        c = !1;\n        for (d = 0; d <= a.xa; d++) h = h && !(e[d] && f[d]);\n        if (h)\n            for (g.reset(); g.next();) a = g.value, a.column > b && (--a.column, c = !0);\n        return c\n    }\n\n    function Qs(a, b) {\n        for (var c = 0; c <= a.Da; c++)\n            for (; Ss(a, c););\n        a.normalize();\n        for (c = 0; c < a.Da; c++)\n            for (; Ts(a, c););\n        a.normalize();\n        var d;\n        if (0 < b)\n            for (c = 0; c <= a.Da; c++) {\n                var e = ns(a);\n                var f = qs(a);\n                for (d = f + 1; f < d;) {\n                    d = f;\n                    Us(a, c, 1);\n                    var g = qs(a);\n                    g > f ? os(a, e) : g < f && (f = g, e = ns(a))\n                }\n            }\n        if (0 > b)\n            for (c = a.Da; 0 <= c; c--)\n                for (e = ns(a), f = qs(a), d = f + 1; f < d;) d = f, Us(a, c, -1), g = qs(a), g > f ? os(a, e) : g < f && (f = g, e = ns(a));\n        a.normalize()\n    }\n\n    function Us(a, b, c) {\n        a.Od = 0;\n        for (var d = a.network.vertexes.iterator; d.next();) d.value.component = -1;\n        if (0 < c)\n            for (d.reset(); d.next();) {\n                var e = d.value;\n                e.column - a.nodeMinColumnSpace(e, !0) <= b && (e.component = a.Od)\n            }\n        if (0 > c)\n            for (d.reset(); d.next();) e = d.value, e.column + a.nodeMinColumnSpace(e, !1) >= b && (e.component = a.Od);\n        a.Od++;\n        for (d.reset(); d.next();) b = d.value, -1 === b.component && (us(a, b, a.Od, -1, !0, !0), a.Od++);\n        var f;\n        b = [];\n        for (f = 0; f < a.Od * a.Od; f++) b[f] = !1;\n        e = [];\n        for (f = 0; f < (a.xa + 1) * (a.Da + 1); f++) e[f] = -1;\n        for (d.reset(); d.next();) {\n            f =\n                d.value;\n            for (var g = f.layer, h = Math.max(0, f.column - a.nodeMinColumnSpace(f, !0)), k = Math.min(a.Da, f.column + a.nodeMinColumnSpace(f, !1)); h <= k; h++) e[g * (a.Da + 1) + h] = f.component\n        }\n        for (f = 0; f <= a.xa; f++) {\n            if (0 < c)\n                for (g = 0; g < a.Da; g++) - 1 !== e[f * (a.Da + 1) + g] && -1 !== e[f * (a.Da + 1) + g + 1] && e[f * (a.Da + 1) + g] !== e[f * (a.Da + 1) + g + 1] && (b[e[f * (a.Da + 1) + g] * a.Od + e[f * (a.Da + 1) + g + 1]] = !0);\n            if (0 > c)\n                for (g = a.Da; 0 < g; g--) - 1 !== e[f * (a.Da + 1) + g] && -1 !== e[f * (a.Da + 1) + g - 1] && e[f * (a.Da + 1) + g] !== e[f * (a.Da + 1) + g - 1] && (b[e[f * (a.Da + 1) + g] * a.Od + e[f * (a.Da + 1) + g - 1]] = !0)\n        }\n        e = [];\n        for (f = 0; f < a.Od; f++) e[f] = !0;\n        g = [];\n        for (g.push(0); 0 !== g.length;)\n            if (k = g[g.length - 1], g.pop(), e[k])\n                for (e[k] = !1, f = 0; f < a.Od; f++) b[k * a.Od + f] && g.splice(0, 0, f);\n        if (0 < c)\n            for (d.reset(); d.next();) a = d.value, e[a.component] && --a.column;\n        if (0 > c)\n            for (d.reset(); d.next();) c = d.value, e[c.component] && (c.column += 1)\n    }\n    bs.prototype.commitLayout = function () {\n        if (this.setsPortSpots)\n            for (var a = is(this, !0), b = is(this, !1), c = this.network.edges.iterator; c.next();) {\n                var d = c.value.link;\n                null !== d && (d.fromSpot = a, d.toSpot = b)\n            }\n        this.commitNodes();\n        this.hv();\n        this.isRouting && this.commitLinks()\n    };\n\n    function is(a, b) {\n        return 270 === a.J ? b ? dd : gd : 90 === a.J ? b ? gd : dd : 180 === a.J ? b ? ed : fd : b ? fd : ed\n    }\n    bs.prototype.commitNodes = function () {\n        this.Kd = [];\n        this.qd = [];\n        this.pd = [];\n        this.Ga = [];\n        for (var a = 0; a <= this.xa; a++) this.Kd[a] = 0, this.qd[a] = 0, this.pd[a] = 0, this.Ga[a] = 0;\n        for (a = this.network.vertexes.iterator; a.next();) {\n            var b = a.value,\n                c = b.layer;\n            this.Kd[c] = Math.max(this.Kd[c], this.nodeMinLayerSpace(b, !0));\n            this.qd[c] = Math.max(this.qd[c], this.nodeMinLayerSpace(b, !1))\n        }\n        b = 0;\n        c = this.me;\n        for (var d = 0; d <= this.xa; d++) {\n            var e = c;\n            0 >= this.Kd[d] + this.qd[d] && (e = 0);\n            0 < d && (b += e / 2);\n            90 === this.J || 0 === this.J ? (b += this.qd[d], this.pd[d] = b,\n                b += this.Kd[d]) : (b += this.Kd[d], this.pd[d] = b, b += this.qd[d]);\n            d < this.xa && (b += e / 2);\n            this.Ga[d] = b\n        }\n        c = b;\n        b = this.arrangementOrigin;\n        for (d = 0; d <= this.xa; d++) 270 === this.J ? this.pd[d] = b.y + this.pd[d] : 90 === this.J ? (this.pd[d] = b.y + c - this.pd[d], this.Ga[d] = c - this.Ga[d]) : 180 === this.J ? this.pd[d] = b.x + this.pd[d] : (this.pd[d] = b.x + c - this.pd[d], this.Ga[d] = c - this.Ga[d]);\n        a.reset();\n        for (c = d = Infinity; a.next();) {\n            e = a.value;\n            var f = e.layer,\n                g = e.column | 0;\n            if (270 === this.J || 90 === this.J) {\n                var h = b.x + this.Zb * g;\n                f = this.pd[f]\n            } else h = this.pd[f], f = b.y +\n                this.Zb * g;\n            e.centerX = h;\n            e.centerY = f;\n            d = Math.min(e.x, d);\n            c = Math.min(e.y, c)\n        }\n        d = b.x - d;\n        b = b.y - c;\n        this.Jf = new I(d, b);\n        for (a.reset(); a.next();) c = a.value, c.x += d, c.y += b, c.commit()\n    };\n    bs.prototype.hv = function () {\n        for (var a = 0, b = this.me, c = 0; c <= this.xa; c++) a += this.Kd[c], a += this.qd[c];\n        a += this.xa * b;\n        b = [];\n        c = this.Zb * this.Da;\n        for (var d = this.maxLayer; 0 <= d; d--) 270 === this.J ? 0 === d ? b.push(new N(0, 0, c, Math.abs(this.Ga[0]))) : b.push(new N(0, this.Ga[d - 1], c, Math.abs(this.Ga[d - 1] - this.Ga[d]))) : 90 === this.J ? 0 === d ? b.push(new N(0, this.Ga[0], c, Math.abs(this.Ga[0] - a))) : b.push(new N(0, this.Ga[d], c, Math.abs(this.Ga[d - 1] - this.Ga[d]))) : 180 === this.J ? 0 === d ? b.push(new N(0, 0, Math.abs(this.Ga[0]), c)) : b.push(new N(this.Ga[d -\n            1], 0, Math.abs(this.Ga[d - 1] - this.Ga[d]), c)) : 0 === d ? b.push(new N(this.Ga[0], 0, Math.abs(this.Ga[0] - a), c)) : b.push(new N(this.Ga[d], 0, Math.abs(this.Ga[d - 1] - this.Ga[d]), c));\n        this.commitLayers(b, this.Jf)\n    };\n    bs.prototype.commitLayers = function () {};\n    bs.prototype.commitLinks = function () {\n        for (var a = this.network.edges.iterator, b; a.next();) b = a.value.link, null !== b && (b.Nh(), b.Zj(), b.rf());\n        for (a.reset(); a.next();) b = a.value.link, null !== b && b.hj();\n        for (a.reset(); a.next();) {\n            var c = a.value;\n            b = c.link;\n            if (null !== b) {\n                b.Nh();\n                var d = b,\n                    e = d.fromNode,\n                    f = d.toNode,\n                    g = d.fromPort,\n                    h = d.toPort;\n                if (null !== e) {\n                    var k = e.findVisibleNode();\n                    null !== k && k !== e && (e = k, g = k.port)\n                }\n                null !== f && (k = f.findVisibleNode(), null !== k && k !== f && (f = k, h = k.port));\n                var l = b.computeSpot(!0, g);\n                k = b.computeSpot(!1, h);\n                var m =\n                    c.fromVertex,\n                    n = c.toVertex;\n                if (c.valid) {\n                    if (b.curve === qg && 4 === b.pointsCount)\n                        if (m.column === n.column) c = b.getLinkPoint(e, g, l, !0, !1, f, h), g = b.getLinkPoint(f, h, k, !1, !1, e, g), c.v() || c.set(e.actualBounds.center), g.v() || g.set(f.actualBounds.center), b.Zj(), b.qf(c.x, c.y), b.qf((2 * c.x + g.x) / 3, (2 * c.y + g.y) / 3), b.qf((c.x + 2 * g.x) / 3, (c.y + 2 * g.y) / 3), b.qf(g.x, g.y);\n                        else {\n                            var p = !1,\n                                r = !1;\n                            null !== g && l === uc && (p = !0);\n                            null !== h && k === uc && (r = !0);\n                            if (p || r) {\n                                var q = b.i(0).x;\n                                c = b.i(0).y;\n                                m = b.i(3).x;\n                                d = b.i(3).y;\n                                p && (90 === this.J || 270 === this.J ? (p = q, n =\n                                    (c + d) / 2) : (p = (q + m) / 2, n = c), b.K(1, p, n), l = b.getLinkPoint(e, g, l, !0, !1, f, h), l.v() || l.set(e.actualBounds.center), b.K(0, l.x, l.y));\n                                r && (90 === this.J || 270 === this.J ? (l = m, c = (c + d) / 2) : (l = (q + m) / 2, c = d), b.K(2, l, c), e = b.getLinkPoint(f, h, k, !1, !1, e, g), e.v() || e.set(f.actualBounds.center), b.K(3, e.x, e.y))\n                            }\n                        } b.rf()\n                } else if (m.layer === n.layer) b.rf();\n                else {\n                    p = r = !1;\n                    q = b.firstPickIndex + 1;\n                    if (b.isOrthogonal) {\n                        p = !0;\n                        var u = b.pointsCount;\n                        4 < u && b.points.removeRange(2, u - 3)\n                    } else if (b.curve === qg) r = !0, u = b.pointsCount, 4 < u && b.points.removeRange(2,\n                        u - 3), 4 === u && (q = 2);\n                    else {\n                        u = b.pointsCount;\n                        var v = l === uc,\n                            w = k === uc;\n                        2 < u && v && w ? b.points.removeRange(1, u - 2) : 3 < u && v && !w ? b.points.removeRange(1, u - 3) : 3 < u && !v && w ? b.points.removeRange(2, u - 2) : 4 < u && !v && !w && b.points.removeRange(2, u - 3)\n                    }\n                    if (c.rev) {\n                        for (; null !== n && m !== n;) {\n                            var y = u = null;\n                            for (v = n.sourceEdges.iterator; v.next() && (w = v.value, w.link !== c.link || (u = w.fromVertex, y = w.toVertex, null !== u.node)););\n                            if (u !== m) {\n                                v = b.i(q - 1).x;\n                                w = b.i(q - 1).y;\n                                var z = u.centerX;\n                                var A = u.centerY;\n                                if (p) 180 === this.J || 0 === this.J ? q === b.firstPickIndex + 1 ? (b.m(q++,\n                                    v, w), b.m(q++, v, A)) : (null !== y ? y.centerY : w) !== A && (y = this.Ga[u.layer - 1] + this.Jf.x, b.m(q++, y, w), b.m(q++, y, A)) : q === b.firstPickIndex + 1 ? (b.m(q++, v, w), b.m(q++, z, w)) : (null !== y ? y.centerX : v) !== z && (y = this.Ga[u.layer - 1] + this.Jf.y, b.m(q++, v, y), b.m(q++, z, y));\n                                else if (q === b.firstPickIndex + 1) {\n                                    y = Math.max(10, this.Kd[n.layer]);\n                                    var C = Math.max(10, this.qd[n.layer]);\n                                    if (r) 180 === this.J ? z <= n.bounds.x ? (n = n.bounds.x, b.m(q++, n - y, A), b.m(q++, n, A), b.m(q++, n + C, A)) : (b.m(q++, z - y, A), b.m(q++, z, A), b.m(q++, z + C, A)) : 90 === this.J ? A >= n.bounds.bottom ?\n                                        (n = n.bounds.y + n.bounds.height, b.m(q++, z, n + C), b.m(q++, z, n), b.m(q++, z, n - y)) : (b.m(q++, z, A + C), b.m(q++, z, A), b.m(q++, z, A - y)) : 270 === this.J ? A <= n.bounds.y ? (n = n.bounds.y, b.m(q++, z, n - y), b.m(q++, z, n), b.m(q++, z, n + C)) : (b.m(q++, z, A - y), b.m(q++, z, A), b.m(q++, z, A + C)) : 0 === this.J && (z >= n.bounds.right ? (n = n.bounds.x + n.bounds.width, b.m(q++, n + C, A), b.m(q++, n, A), b.m(q++, n - y, A)) : (b.m(q++, z + C, A), b.m(q++, z, A), b.m(q++, z - y, A)));\n                                    else {\n                                        b.m(q++, v, w);\n                                        var G = 0;\n                                        if (180 === this.J || 0 === this.J) {\n                                            if (180 === this.J ? z >= n.bounds.right : z <= n.bounds.x) G =\n                                                (0 === this.J ? -y : C) / 2;\n                                            b.m(q++, v + G, A)\n                                        } else {\n                                            if (270 === this.J ? A >= n.bounds.bottom : A <= n.bounds.y) G = (90 === this.J ? -y : C) / 2;\n                                            b.m(q++, z, w + G)\n                                        }\n                                        b.m(q++, z, A)\n                                    }\n                                } else y = Math.max(10, this.Kd[u.layer]), C = Math.max(10, this.qd[u.layer]), 180 === this.J ? (r && b.m(q++, z - y, A), b.m(q++, z, A), r && b.m(q++, z + C, A)) : 90 === this.J ? (r && b.m(q++, z, A + C), b.m(q++, z, A), r && b.m(q++, z, A - y)) : 270 === this.J ? (r && b.m(q++, z, A - y), b.m(q++, z, A), r && b.m(q++, z, A + C)) : (r && b.m(q++, z + C, A), b.m(q++, z, A), r && b.m(q++, z - y, A))\n                            }\n                            n = u\n                        }\n                        if (null === h || l !== uc || p)\n                            if (v = b.i(q - 1).x, w = b.i(q -\n                                    1).y, z = b.i(q).x, A = b.i(q).y, p) n = this.qd[m.layer], 180 === this.J || 0 === this.J ? (p = w, p >= m.bounds.y && p <= m.bounds.bottom && (180 === this.J ? z >= m.bounds.x : z <= m.bounds.right) && (n = m.centerX + (180 === this.J ? -n : n), p < m.bounds.y + m.bounds.height / 2 ? p = m.bounds.y - this.Zb / 2 : p = m.bounds.bottom + this.Zb / 2, b.m(q++, n, w), b.m(q++, n, p)), b.m(q++, z, p)) : (p = v, p >= m.bounds.x && p <= m.bounds.right && (270 === this.J ? A >= m.bounds.y : A <= m.bounds.bottom) && (n = m.centerY + (270 === this.J ? -n : n), p < m.bounds.x + m.bounds.width / 2 ? p = m.bounds.x - this.Zb / 2 : p = m.bounds.right +\n                                this.Zb / 2, b.m(q++, v, n), b.m(q++, p, n)), b.m(q++, p, A)), b.m(q++, z, A);\n                            else if (r) y = Math.max(10, this.Kd[m.layer]), C = Math.max(10, this.qd[m.layer]), 180 === this.J && z >= m.bounds.x ? (n = m.bounds.x + m.bounds.width, b.K(q - 2, n, w), b.K(q - 1, n + C, w)) : 90 === this.J && A <= m.bounds.bottom ? (n = m.bounds.y, b.K(q - 2, v, n), b.K(q - 1, v, n - y)) : 270 === this.J && A >= m.bounds.y ? (n = m.bounds.y + m.bounds.height, b.K(q - 2, v, n), b.K(q - 1, v, n + C)) : 0 === this.J && z <= m.bounds.right && (n = m.bounds.x, b.K(q - 2, n, w), b.K(q - 1, n - y, w));\n                        else {\n                            y = Math.max(10, this.Kd[m.layer]);\n                            C = Math.max(10,\n                                this.qd[m.layer]);\n                            p = 0;\n                            if (180 === this.J || 0 === this.J) {\n                                if (180 === this.J ? z <= m.bounds.x : z >= m.bounds.right) p = (0 === this.J ? C : -y) / 2;\n                                b.m(q++, z + p, w)\n                            } else {\n                                if (270 === this.J ? A <= m.bounds.y : A >= m.bounds.bottom) p = (90 === this.J ? C : -y) / 2;\n                                b.m(q++, v, A + p)\n                            }\n                            b.m(q++, z, A)\n                        }\n                    } else {\n                        for (; null !== m && m !== n;) {\n                            y = u = null;\n                            for (m = m.destinationEdges.iterator; m.next() && (v = m.value, v.link !== c.link || (u = v.toVertex, y = v.fromVertex, null !== y.node && (y = null), null !== u.node)););\n                            u !== n && (v = b.i(q - 1).x, w = b.i(q - 1).y, z = u.centerX, A = u.centerY, p ? 180 === this.J || 0 === this.J ?\n                                (null !== y ? y.centerY : w) !== A && (y = this.Ga[u.layer] + this.Jf.x, q === b.firstPickIndex + 1 && (y = 0 === this.J ? Math.max(y, v) : Math.min(y, v)), b.m(q++, y, w), b.m(q++, y, A)) : (null !== y ? y.centerX : v) !== z && (y = this.Ga[u.layer] + this.Jf.y, q === b.firstPickIndex + 1 && (y = 90 === this.J ? Math.max(y, w) : Math.min(y, w)), b.m(q++, v, y), b.m(q++, z, y)) : (y = Math.max(10, this.Kd[u.layer]), C = Math.max(10, this.qd[u.layer]), 180 === this.J ? (b.m(q++, z + C, A), r && b.m(q++, z, A), b.m(q++, z - y, A)) : 90 === this.J ? (b.m(q++, z, A - y), r && b.m(q++, z, A), b.m(q++, z, A + C)) : 270 === this.J ?\n                                    (b.m(q++, z, A + C), r && b.m(q++, z, A), b.m(q++, z, A - y)) : (b.m(q++, z - y, A), r && b.m(q++, z, A), b.m(q++, z + C, A))));\n                            m = u\n                        }\n                        p && (v = b.i(q - 1).x, w = b.i(q - 1).y, z = b.i(q).x, A = b.i(q).y, 180 === this.J || 0 === this.J ? w !== A && (y = 0 === this.J ? Math.min(Math.max((z + v) / 2, this.Ga[n.layer] + this.Jf.x), z) : Math.max(Math.min((z + v) / 2, this.Ga[n.layer] + this.Jf.x), z), b.m(q++, y, w), b.m(q++, y, A)) : v !== z && (y = 90 === this.J ? Math.min(Math.max((A + w) / 2, this.Ga[n.layer] + this.Jf.y), A) : Math.max(Math.min((A + w) / 2, this.Ga[n.layer] + this.Jf.y), A), b.m(q++, v, y), b.m(q++, z, y)))\n                    }\n                    null !==\n                        d && r && (null !== g && (l === uc && (l = b.i(0), d = b.i(2), l.w(d) || b.K(1, (l.x + d.x) / 2, (l.y + d.y) / 2)), l = b.getLinkPoint(e, g, uc, !0, !1, f, h), l.v() || l.set(e.actualBounds.center), b.K(0, l.x, l.y)), null !== h && (k === uc && (k = b.i(b.pointsCount - 1), l = b.i(b.pointsCount - 3), k.w(l) || b.K(b.pointsCount - 2, (k.x + l.x) / 2, (k.y + l.y) / 2)), e = b.getLinkPoint(f, h, uc, !1, !1, e, g), e.v() || e.set(f.actualBounds.center), b.K(b.pointsCount - 1, e.x, e.y)));\n                    b.rf();\n                    c.commit()\n                }\n            }\n        }\n        this.avoidOrthogonalOverlaps()\n    };\n    bs.prototype.avoidOrthogonalOverlaps = function () {\n        for (var a = new E, b = this.network.edges.iterator; b.next();) {\n            var c = b.value.link;\n            null !== c && c.isOrthogonal && !a.contains(c) && a.add(c)\n        }\n        if (0 < a.count)\n            if (90 === this.J || 270 === this.J) {\n                b = 0;\n                c = [];\n                for (a = a.iterator; a.next();) {\n                    var d = a.value;\n                    if (null !== d && d.isOrthogonal)\n                        for (var e = 2; e < d.pointsCount - 3; e++) {\n                            var f = d.i(e);\n                            var g = d.i(e + 1);\n                            if (this.A(f.y, g.y) && !this.A(f.x, g.x)) {\n                                var h = new Vs;\n                                h.layer = Math.floor(f.y / 2);\n                                var k = d.i(0),\n                                    l = d.i(d.pointsCount - 1);\n                                h.first = k.x * k.x + k.y;\n                                h.Xb = l.x *\n                                    l.x + l.y;\n                                h.Tc = Math.min(f.x, g.x);\n                                h.tc = Math.max(f.x, g.x);\n                                h.index = e;\n                                h.link = d;\n                                if (e + 2 < d.pointsCount) {\n                                    k = d.i(e - 1);\n                                    l = d.i(e + 2);\n                                    var m = 0;\n                                    k.y < f.y ? m = l.y < f.y ? 3 : f.x < g.x ? 2 : 1 : k.y > f.y && (m = l.y > f.y ? 0 : g.x < f.x ? 2 : 1);\n                                    h.l = m\n                                }\n                                c.push(h)\n                            }\n                        }\n                }\n                if (1 < c.length)\n                    for (c.sort(this.hy), a = 0; a < c.length;) {\n                        f = c[a].layer;\n                        for (d = a + 1; d < c.length && c[d].layer === f;) d++;\n                        if (1 < d - a)\n                            for (f = a; f < d;) {\n                                g = c[f].tc;\n                                for (e = a + 1; e < d && c[e].Tc < g;) g = Math.max(g, c[e].tc), e++;\n                                g = e - f;\n                                if (1 < g) {\n                                    this.ej(c, this.Kt, f, f + g);\n                                    m = 1;\n                                    h = c[f].Xb;\n                                    for (k = f; k < e; k++) l = c[k], l.Xb !== h && (m++, h = l.Xb);\n                                    this.ej(c,\n                                        this.gy, f, f + g);\n                                    var n = 1;\n                                    h = c[f].first;\n                                    for (k = f; k < e; k++) l = c[k], l.first !== h && (n++, h = l.first);\n                                    k = !0;\n                                    l = n;\n                                    m < n ? (k = !1, l = m, h = c[f].Xb, this.ej(c, this.Kt, f, f + g)) : h = c[f].first;\n                                    m = 0;\n                                    for (n = f; n < e; n++) {\n                                        var p = c[n];\n                                        (k ? p.first : p.Xb) !== h && (m++, h = k ? p.first : p.Xb);\n                                        var r = p.link;\n                                        f = r.i(p.index);\n                                        g = r.i(p.index + 1);\n                                        var q = this.linkSpacing * (m - (l - 1) / 2);\n                                        b++;\n                                        r.Nh();\n                                        r.K(p.index, f.x, f.y + q);\n                                        r.K(p.index + 1, g.x, g.y + q);\n                                        r.rf()\n                                    }\n                                }\n                                f = e\n                            }\n                        a = d\n                    }\n            } else {\n                b = 0;\n                c = [];\n                for (a = a.iterator; a.next();)\n                    if (d = a.value, null !== d && d.isOrthogonal)\n                        for (e = 2; e < d.pointsCount - 3; e++) f =\n                            d.i(e), g = d.i(e + 1), this.A(f.x, g.x) && !this.A(f.y, g.y) && (h = new Vs, h.layer = Math.floor(f.x / 2), k = d.i(0), l = d.i(d.pointsCount - 1), h.first = k.x + k.y * k.y, h.Xb = l.x + l.y * l.y, h.Tc = Math.min(f.y, g.y), h.tc = Math.max(f.y, g.y), h.index = e, h.link = d, e + 2 < d.pointsCount && (k = d.i(e - 1), l = d.i(e + 2), m = 0, k.x < f.x ? m = l.x < f.x ? 3 : f.y < g.y ? 2 : 1 : k.x > f.x && (m = l.x > f.x ? 0 : g.y < f.y ? 2 : 1), h.l = m), c.push(h));\n                if (1 < c.length)\n                    for (c.sort(this.hy), a = 0; a < c.length;) {\n                        f = c[a].layer;\n                        for (d = a + 1; d < c.length && c[d].layer === f;) d++;\n                        if (1 < d - a)\n                            for (f = a; f < d;) {\n                                g = c[f].tc;\n                                for (e = a +\n                                    1; e < d && c[e].Tc < g;) g = Math.max(g, c[e].tc), e++;\n                                g = e - f;\n                                if (1 < g) {\n                                    this.ej(c, this.Kt, f, f + g);\n                                    m = 1;\n                                    h = c[f].Xb;\n                                    for (k = f; k < e; k++) l = c[k], l.Xb !== h && (m++, h = l.Xb);\n                                    this.ej(c, this.gy, f, f + g);\n                                    n = 1;\n                                    h = c[f].first;\n                                    for (k = f; k < e; k++) l = c[k], l.first !== h && (n++, h = l.first);\n                                    k = !0;\n                                    l = n;\n                                    m < n ? (k = !1, l = m, h = c[f].Xb, this.ej(c, this.Kt, f, f + g)) : h = c[f].first;\n                                    m = 0;\n                                    for (n = f; n < e; n++) p = c[n], (k ? p.first : p.Xb) !== h && (m++, h = k ? p.first : p.Xb), r = p.link, f = r.i(p.index), g = r.i(p.index + 1), q = this.linkSpacing * (m - (l - 1) / 2), b++, r.Nh(), r.K(p.index, f.x + q, f.y), r.K(p.index + 1,\n                                        g.x + q, g.y), r.rf()\n                                }\n                                f = e\n                            }\n                        a = d\n                    }\n            }\n    };\n    t = bs.prototype;\n    t.hy = function (a, b) {\n        return a instanceof Vs && b instanceof Vs && a !== b ? a.layer < b.layer ? -1 : a.layer > b.layer ? 1 : a.Tc < b.Tc ? -1 : a.Tc > b.Tc ? 1 : a.tc < b.tc ? -1 : a.tc > b.tc ? 1 : 0 : 0\n    };\n    t.gy = function (a, b) {\n        return a instanceof Vs && b instanceof Vs && a !== b ? a.first < b.first ? -1 : a.first > b.first || a.l < b.l ? 1 : a.l > b.l || a.Tc < b.Tc ? -1 : a.Tc > b.Tc ? 1 : a.tc < b.tc ? -1 : a.tc > b.tc ? 1 : 0 : 0\n    };\n    t.Kt = function (a, b) {\n        return a instanceof Vs && b instanceof Vs && a !== b ? a.Xb < b.Xb ? -1 : a.Xb > b.Xb || a.l < b.l ? 1 : a.l > b.l || a.Tc < b.Tc ? -1 : a.Tc > b.Tc ? 1 : a.tc < b.tc ? -1 : a.tc > b.tc ? 1 : 0 : 0\n    };\n    t.A = function (a, b) {\n        a -= b;\n        return -1 < a && 1 > a\n    };\n    t.ej = function (a, b, c, d) {\n        var e = a.length,\n            f = d - c;\n        if (!(1 >= f))\n            if ((0 > c || c >= e - 1) && B(\"not in range 0 <= from < length: \" + c), 2 === f) d = a[c], e = a[c + 1], 0 < b(d, e) && (a[c] = e, a[c + 1] = d);\n            else if (0 === c)\n            if (d >= e) a.sort(b);\n            else\n                for (c = a.slice(0, d), c.sort(b), b = 0; b < d; b++) a[b] = c[b];\n        else if (d >= e)\n            for (d = a.slice(c), d.sort(b), b = c; b < e; b++) a[b] = d[b - c];\n        else\n            for (e = a.slice(c, d), e.sort(b), b = c; b < d; b++) a[b] = e[b - c]\n    };\n\n    function ks(a, b) {\n        var c = a.gc[b];\n        if (c >= a.pe.length) {\n            var d = [];\n            for (var e = 0; e < a.pe.length; e++) d[e] = a.pe[e];\n            a.pe = d\n        }\n        void 0 === a.pe[c] || null === a.pe[c] ? d = [] : (d = a.pe[c], a.pe[c] = null);\n        a = a.No[b];\n        for (b = 0; b < a.length; b++) c = a[b], d[c.index] = c;\n        return d\n    }\n\n    function ls(a, b, c) {\n        a.pe[a.gc[b]] = c\n    }\n    ma.Object.defineProperties(bs.prototype, {\n        layerSpacing: {\n            get: function () {\n                return this.me\n            },\n            set: function (a) {\n                this.me !== a && 0 <= a && (this.me = a, this.C())\n            }\n        },\n        columnSpacing: {\n            get: function () {\n                return this.Zb\n            },\n            set: function (a) {\n                this.Zb !== a && 0 < a && (this.Zb = a, this.C())\n            }\n        },\n        direction: {\n            get: function () {\n                return this.J\n            },\n            set: function (a) {\n                this.J !== a && (0 === a || 90 === a || 180 === a || 270 === a ? (this.J = a, this.C()) : B(\"LayeredDigraphLayout.direction must be 0, 90, 180, or 270\"))\n            }\n        },\n        cycleRemoveOption: {\n            get: function () {\n                return this.Pk\n            },\n            set: function (a) {\n                this.Pk === a || a !== vs && a !== cs && a !== hs || (this.Pk = a, this.C())\n            }\n        },\n        layeringOption: {\n            get: function () {\n                return this.tl\n            },\n            set: function (a) {\n                this.tl === a || a !== ds && a !== As && a !== Cs || (this.tl = a, this.C())\n            }\n        },\n        initializeOption: {\n            get: function () {\n                return this.il\n            },\n            set: function (a) {\n                this.il === a || a !== es && a !== Is && a !== Gs || (this.il = a, this.C())\n            }\n        },\n        iterations: {\n            get: function () {\n                return this.zj\n            },\n            set: function (a) {\n                this.zj !== a && 0 <= a && (this.zj = a, this.C())\n            }\n        },\n        aggressiveOption: {\n            get: function () {\n                return this.Ek\n            },\n            set: function (a) {\n                this.Ek === a || a !== Ms && a !== fs && a !== Ns || (this.Ek = a, this.C())\n            }\n        },\n        packOption: {\n            get: function () {\n                return this.mg\n            },\n            set: function (a) {\n                this.mg !== a && 0 <= a && 8 > a && (this.mg = a, this.C())\n            }\n        },\n        setsPortSpots: {\n            get: function () {\n                return this.cf\n            },\n            set: function (a) {\n                this.cf !== a && (this.cf = a, this.C())\n            }\n        },\n        linkSpacing: {\n            get: function () {\n                return this.ro\n            },\n            set: function (a) {\n                this.ro !== a && 0 <= a && (this.ro = a, this.C())\n            }\n        },\n        maxLayer: {\n            get: function () {\n                return this.xa\n            }\n        },\n        maxIndex: {\n            get: function () {\n                return this.Zr\n            }\n        },\n        maxColumn: {\n            get: function () {\n                return this.Da\n            }\n        },\n        minIndexLayer: {\n            get: function () {\n                return this.Co\n            }\n        },\n        maxIndexLayer: {\n            get: function () {\n                return this.rd\n            }\n        }\n    });\n    var cs = new D(bs, \"CycleDepthFirst\", 0),\n        vs = new D(bs, \"CycleGreedy\", 1),\n        hs = new D(bs, \"CycleFromLayers\", 2),\n        ds = new D(bs, \"LayerOptimalLinkLength\", 0),\n        As = new D(bs, \"LayerLongestPathSink\", 1),\n        Cs = new D(bs, \"LayerLongestPathSource\", 2),\n        es = new D(bs, \"InitDepthFirstOut\", 0),\n        Is = new D(bs, \"InitDepthFirstIn\", 1),\n        Gs = new D(bs, \"InitNaive\", 2),\n        Ms = new D(bs, \"AggressiveNone\", 0),\n        fs = new D(bs, \"AggressiveLess\", 1),\n        Ns = new D(bs, \"AggressiveMore\", 2);\n    bs.className = \"LayeredDigraphLayout\";\n    bs.CycleDepthFirst = cs;\n    bs.CycleGreedy = vs;\n    bs.CycleFromLayers = hs;\n    bs.LayerOptimalLinkLength = ds;\n    bs.LayerLongestPathSink = As;\n    bs.LayerLongestPathSource = Cs;\n    bs.InitDepthFirstOut = es;\n    bs.InitDepthFirstIn = Is;\n    bs.InitNaive = Gs;\n    bs.AggressiveNone = Ms;\n    bs.AggressiveLess = fs;\n    bs.AggressiveMore = Ns;\n    bs.PackNone = 0;\n    bs.PackExpand = 1;\n    bs.PackStraighten = 2;\n    bs.PackMedian = 4;\n    bs.PackAll = 7;\n\n    function Vs() {\n        this.index = this.tc = this.Tc = this.Xb = this.first = this.layer = 0;\n        this.link = null;\n        this.l = 0\n    }\n    Vs.className = \"SegInfo\";\n\n    function gs(a) {\n        Qp.call(this, a)\n    }\n    la(gs, Qp);\n    gs.prototype.createVertex = function () {\n        return new Ws(this)\n    };\n    gs.prototype.createEdge = function () {\n        return new Xs(this)\n    };\n    gs.className = \"LayeredDigraphNetwork\";\n\n    function Ws(a) {\n        Tp.call(this, a);\n        this.Pa = this.Og = this.ui = -1;\n        this.I = NaN;\n        this.Y = null;\n        this.valid = !1;\n        this.finish = this.fm = NaN;\n        this.Wj = 0;\n        this.Nv = this.Ov = null\n    }\n    la(Ws, Tp);\n    ma.Object.defineProperties(Ws.prototype, {\n        layer: {\n            get: function () {\n                return this.ui\n            },\n            set: function (a) {\n                this.ui !== a && (this.ui = a)\n            }\n        },\n        column: {\n            get: function () {\n                return this.Og\n            },\n            set: function (a) {\n                this.Og !== a && (this.Og = a)\n            }\n        },\n        index: {\n            get: function () {\n                return this.Pa\n            },\n            set: function (a) {\n                this.Pa !== a && (this.Pa = a)\n            }\n        },\n        component: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I !== a && (this.I = a)\n            }\n        },\n        near: {\n            get: function () {\n                return this.Y\n            },\n            set: function (a) {\n                this.Y !== a && (this.Y = a)\n            }\n        }\n    });\n    Ws.className = \"LayeredDigraphVertex\";\n\n    function Xs(a) {\n        Up.call(this, a);\n        this.l = this.Ia = this.Za = !1;\n        this.Ha = this.I = NaN;\n        this.Y = this.u = 0\n    }\n    la(Xs, Up);\n    ma.Object.defineProperties(Xs.prototype, {\n        valid: {\n            get: function () {\n                return this.Za\n            },\n            set: function (a) {\n                this.Za !== a && (this.Za = a)\n            }\n        },\n        rev: {\n            get: function () {\n                return this.Ia\n            },\n            set: function (a) {\n                this.Ia !== a && (this.Ia = a)\n            }\n        },\n        forest: {\n            get: function () {\n                return this.l\n            },\n            set: function (a) {\n                this.l !== a && (this.l = a)\n            }\n        },\n        portFromPos: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                this.I !== a && (this.I = a)\n            }\n        },\n        portToPos: {\n            get: function () {\n                return this.Ha\n            },\n            set: function (a) {\n                this.Ha !== a && (this.Ha = a)\n            }\n        },\n        portFromColOffset: {\n            get: function () {\n                return this.u\n            },\n            set: function (a) {\n                this.u !== a && (this.u = a)\n            }\n        },\n        portToColOffset: {\n            get: function () {\n                return this.Y\n            },\n            set: function (a) {\n                this.Y !== a && (this.Y = a)\n            }\n        }\n    });\n    Xs.className = \"LayeredDigraphEdge\";\n\n    function Ys() {\n        Ci.call(this);\n        this.Hb = new F;\n        this.ap = Zs;\n        this.$c = $s;\n        this.Xp = at;\n        this.Yr = bt;\n        this.Lw = [];\n        this.Zc = !0;\n        this.Ab = ct;\n        this.zd = (new M(10, 10)).freeze();\n        var a = new dt(this);\n        this.T = new et(a);\n        this.U = new et(a);\n        this.Uu = []\n    }\n    la(Ys, Ci);\n    Ys.prototype.cloneProtected = function (a) {\n        Ci.prototype.cloneProtected.call(this, a);\n        a.ap = this.ap;\n        a.Xp = this.Xp;\n        a.Yr = this.Yr;\n        a.Zc = this.Zc;\n        a.Ab = this.Ab;\n        a.zd.assign(this.zd);\n        a.T.copyInheritedPropertiesFrom(this.T);\n        a.U.copyInheritedPropertiesFrom(this.U)\n    };\n    Ys.prototype.cb = function (a) {\n        a.classType === Ys ? 0 === a.name.indexOf(\"Alignment\") ? this.alignment = a : 0 === a.name.indexOf(\"Arrangement\") ? this.arrangement = a : 0 === a.name.indexOf(\"Compaction\") ? this.compaction = a : 0 === a.name.indexOf(\"Path\") ? this.path = a : 0 === a.name.indexOf(\"Sorting\") ? this.sorting = a : 0 === a.name.indexOf(\"Style\") ? this.treeStyle = a : B(\"Unknown enum value: \" + a) : Ci.prototype.cb.call(this, a)\n    };\n    Ys.prototype.createNetwork = function () {\n        return new dt(this)\n    };\n    Ys.prototype.makeNetwork = function (a) {\n        function b(a) {\n            if (a instanceof W) return !a.isLinkLabel && \"Comment\" !== a.category;\n            if (a instanceof S) {\n                var b = a.fromNode;\n                if (null === b || b.isLinkLabel || \"Comment\" === b.category) return !1;\n                a = a.toNode;\n                return null === a || a.isLinkLabel || \"Comment\" === a.category ? !1 : !0\n            }\n            return !1\n        }\n        var c = this.createNetwork();\n        a instanceof R ? (c.xg(a.nodes, !0, b), c.xg(a.links, !0, b)) : a instanceof T ? c.xg(a.memberParts, !1, b) : c.xg(a.iterator, !1, b);\n        return c\n    };\n    Ys.prototype.doLayout = function (a) {\n        null === this.network && (this.network = this.makeNetwork(a));\n        this.arrangement !== ft && (this.arrangementOrigin = this.initialOrigin(this.arrangementOrigin));\n        var b = this.diagram;\n        null === b && a instanceof R && (b = a);\n        this.path === Zs && null !== b ? this.$c = b.isTreePathToChildren ? $s : gt : this.$c = this.path === Zs ? $s : this.path;\n        if (0 < this.network.vertexes.count) {\n            this.network.iq();\n            for (a = this.network.vertexes.iterator; a.next();) b = a.value, b.initialized = !1, b.level = 0, b.parent = null, b.children = [];\n            if (0 < this.Hb.count) {\n                a =\n                    new F;\n                for (b = this.Hb.iterator; b.next();) {\n                    var c = b.value;\n                    c instanceof W ? (c = this.network.Wi(c), null !== c && a.add(c)) : c instanceof et && a.add(c)\n                }\n                this.Hb = a\n            }\n            0 === this.Hb.count && this.findRoots();\n            for (a = this.Hb.copy().iterator; a.next();) b = a.value, b.initialized || (b.initialized = !0, ht(this, b));\n            b = this.network.vertexes;\n            for (a = null; a = it(b), 0 < a.count;) b = jt(this, a), null !== b && this.Hb.add(b), b.initialized = !0, ht(this, b), b = a;\n            for (a = this.Hb.iterator; a.next();) b = a.value, b instanceof et && kt(this, b);\n            for (a = this.Hb.iterator; a.next();) b =\n                a.value, b instanceof et && lt(this, b);\n            for (a = this.Hb.iterator; a.next();) b = a.value, b instanceof et && mt(this, b);\n            this.fv();\n            if (this.layerStyle === nt) {\n                a = [];\n                for (b = this.network.vertexes.iterator; b.next();) {\n                    c = b.value;\n                    var d = c.parent;\n                    null === d && (d = c);\n                    d = 0 === d.angle || 180 === d.angle;\n                    var e = a[c.level];\n                    void 0 === e && (e = 0);\n                    a[c.level] = Math.max(e, d ? c.width : c.height)\n                }\n                for (b = 0; b < a.length; b++) void 0 === a[b] && (a[b] = 0);\n                this.Lw = a;\n                for (b = this.network.vertexes.iterator; b.next();) c = b.value, d = c.parent, null === d && (d = c), 0 === d.angle || 180 ===\n                    d.angle ? (180 === d.angle && (c.focusX += a[c.level] - c.width), c.width = a[c.level]) : (270 === d.angle && (c.focusY += a[c.level] - c.height), c.height = a[c.level])\n            } else if (this.layerStyle === ot)\n                for (a = this.network.vertexes.iterator; a.next();) {\n                    b = a.value;\n                    c = 0 === b.angle || 180 === b.angle;\n                    d = -1;\n                    for (e = 0; e < b.children.length; e++) {\n                        var f = b.children[e];\n                        d = Math.max(d, c ? f.width : f.height)\n                    }\n                    if (0 <= d)\n                        for (e = 0; e < b.children.length; e++) f = b.children[e], c ? (180 === b.angle && (f.focusX += d - f.width), f.width = d) : (270 === b.angle && (f.focusY += d - f.height), f.height =\n                            d)\n                }\n            for (a = this.Hb.iterator; a.next();) b = a.value, b instanceof et && this.layoutTree(b);\n            this.arrangeTrees();\n            this.updateParts()\n        }\n        this.network = null;\n        this.Hb = new F;\n        this.isValidLayout = !0\n    };\n\n    function it(a) {\n        var b = new F;\n        for (a = a.iterator; a.next();) {\n            var c = a.value;\n            c.initialized || b.add(c)\n        }\n        return b\n    }\n    Ys.prototype.findRoots = function () {\n        for (var a = this.network.vertexes, b = a.iterator; b.next();) {\n            var c = b.value;\n            switch (this.$c) {\n                case $s:\n                    0 === c.sourceEdges.count && this.Hb.add(c);\n                    break;\n                case gt:\n                    0 === c.destinationEdges.count && this.Hb.add(c);\n                    break;\n                default:\n                    B(\"Unhandled path value \" + this.$c.toString())\n            }\n        }\n        0 === this.Hb.count && (a = jt(this, a), null !== a && this.Hb.add(a))\n    };\n\n    function jt(a, b) {\n        var c = 999999,\n            d = null;\n        for (b = b.iterator; b.next();) {\n            var e = b.value;\n            switch (a.$c) {\n                case $s:\n                    e.sourceEdges.count < c && (c = e.sourceEdges.count, d = e);\n                    break;\n                case gt:\n                    e.destinationEdges.count < c && (c = e.destinationEdges.count, d = e);\n                    break;\n                default:\n                    B(\"Unhandled path value \" + a.$c.toString())\n            }\n        }\n        return d\n    }\n\n    function ht(a, b) {\n        if (null !== b) {\n            switch (a.$c) {\n                case $s:\n                    if (0 < b.destinationEdges.count) {\n                        for (var c = new E, d = b.destinationVertexes; d.next();) {\n                            var e = d.value;\n                            pt(a, b, e) && c.add(e)\n                        }\n                        0 < c.count && (b.children = c.na())\n                    }\n                    break;\n                case gt:\n                    if (0 < b.sourceEdges.count) {\n                        c = new E;\n                        for (d = b.sourceVertexes; d.next();) e = d.value, pt(a, b, e) && c.add(e);\n                        0 < c.count && (b.children = c.na())\n                    }\n                    break;\n                default:\n                    B(\"Unhandled path value\" + a.$c.toString())\n            }\n            c = b.children;\n            d = c.length;\n            for (e = 0; e < d; e++) {\n                var f = c[e];\n                f.initialized = !0;\n                f.level = b.level + 1;\n                f.parent = b;\n                a.Hb.remove(f)\n            }\n            for (b =\n                0; b < d; b++) ht(a, c[b])\n        }\n    }\n\n    function pt(a, b, c) {\n        if (c.initialized) {\n            if (null === b) var d = !1;\n            else {\n                for (d = b.parent; null !== d && d !== c;) d = d.parent;\n                d = d === c\n            }\n            if (d || c.level > b.level) return !1;\n            a.removeChild(c.parent, c)\n        }\n        return !0\n    }\n    Ys.prototype.removeChild = function (a, b) {\n        if (null !== a && null !== b) {\n            for (var c = a.children, d = 0, e = 0; e < c.length; e++) c[e] === b && d++;\n            if (0 < d) {\n                d = Array(c.length - d);\n                for (var f = e = 0; f < c.length; f++) c[f] !== b && (d[e++] = c[f]);\n                a.children = d\n            }\n        }\n    };\n\n    function kt(a, b) {\n        if (null !== b) {\n            a.initializeTreeVertexValues(b);\n            b.alignment === qt && a.sortTreeVertexChildren(b);\n            for (var c = 0, d = b.childrenCount, e = 0, f = b.children, g = f.length, h = 0; h < g; h++) {\n                var k = f[h];\n                kt(a, k);\n                c += k.descendantCount + 1;\n                d = Math.max(d, k.maxChildrenCount);\n                e = Math.max(e, k.maxGenerationCount)\n            }\n            b.descendantCount = c;\n            b.maxChildrenCount = d;\n            b.maxGenerationCount = 0 < d ? e + 1 : 0\n        }\n    }\n\n    function rt(a, b) {\n        switch (a.Xp) {\n            default:\n            case at:\n                return null !== b.parent ? b.parent : a.T;\n            case st:\n                return null === b.parent ? a.T : null === b.parent.parent ? a.U : b.parent;\n            case tt:\n                return null !== b.parent ? null !== b.parent.parent ? b.parent.parent : a.U : a.T;\n            case ut:\n                var c = !0;\n                if (0 === b.childrenCount) c = !1;\n                else\n                    for (var d = b.children, e = d.length, f = 0; f < e; f++)\n                        if (0 < d[f].childrenCount) {\n                            c = !1;\n                            break\n                        } return c && null !== b.parent ? a.U : null !== b.parent ? b.parent : a.T\n        }\n    }\n    Ys.prototype.initializeTreeVertexValues = function (a) {\n        a.copyInheritedPropertiesFrom(rt(this, a));\n        if (null !== a.parent && a.parent.alignment === qt) {\n            for (var b = a.angle, c = a.parent.children, d = 0; d < c.length && a !== c[d];) d++;\n            0 === d % 2 ? d !== c.length - 1 && (b = 90 === b ? 180 : 180 === b ? 270 : 270 === b ? 180 : 270) : b = 90 === b ? 0 : 180 === b ? 90 : 270 === b ? 0 : 90;\n            a.angle = b\n        }\n        a.initialized = !0\n    };\n\n    function lt(a, b) {\n        if (null !== b) {\n            a.assignTreeVertexValues(b);\n            b = b.children;\n            for (var c = b.length, d = 0; d < c; d++) lt(a, b[d])\n        }\n    }\n    Ys.prototype.assignTreeVertexValues = function () {};\n\n    function mt(a, b) {\n        if (null !== b) {\n            b.alignment !== qt && a.sortTreeVertexChildren(b);\n            b = b.children;\n            for (var c = b.length, d = 0; d < c; d++) mt(a, b[d])\n        }\n    }\n    Ys.prototype.sortTreeVertexChildren = function (a) {\n        switch (a.sorting) {\n            case vt:\n                break;\n            case wt:\n                a.children.reverse();\n                break;\n            case xt:\n                a.children.sort(a.comparer);\n                break;\n            case yt:\n                a.children.sort(a.comparer);\n                a.children.reverse();\n                break;\n            default:\n                B(\"Unhandled sorting value \" + a.sorting.toString())\n        }\n    };\n    Ys.prototype.fv = function () {\n        if (this.comments)\n            for (var a = this.network.vertexes.iterator; a.next();) this.addComments(a.value)\n    };\n    Ys.prototype.addComments = function (a) {\n        var b = a.angle,\n            c = a.parent,\n            d = 0;\n        var e = !1;\n        null !== c && (d = c.angle, e = c.alignment, e = zt(e));\n        b = 90 === b || 270 === b;\n        d = 90 === d || 270 === d;\n        c = 0 === a.childrenCount;\n        var f = 0,\n            g = 0,\n            h = 0,\n            k = a.commentSpacing;\n        if (null !== a.node)\n            for (var l = a.node.rv(); l.next();) {\n                var m = l.value;\n                \"Comment\" === m.category && m.canLayout() && (null === a.comments && (a.comments = []), a.comments.push(m), m.yb(), m = m.measuredBounds, b && !c || !e && !d && c || e && d && c ? (f = Math.max(f, m.width), g += m.height + Math.abs(h)) : (f += m.width + Math.abs(h), g = Math.max(g,\n                    m.height)), h = k)\n            }\n        null !== a.comments && (b && !c || !e && !d && c || e && d && c ? (f += Math.abs(a.commentMargin), g = Math.max(0, g - a.height)) : (g += Math.abs(a.commentMargin), f = Math.max(0, f - a.width)), e = N.allocAt(0, 0, a.bounds.width + f, a.bounds.height + g), a.bounds = e, N.free(e))\n    };\n\n    function zt(a) {\n        return a === At || a === qt || a === Bt || a === Ct\n    }\n\n    function Dt(a) {\n        return a === At || a === qt\n    }\n\n    function Et(a) {\n        var b = a.parent;\n        if (null !== b) {\n            var c = b.alignment;\n            if (zt(c)) {\n                if (Dt(c)) {\n                    b = b.children;\n                    for (c = 0; c < b.length && a !== b[c];) c++;\n                    return 0 === c % 2\n                }\n                if (c === Bt) return !0\n            }\n        }\n        return !1\n    }\n    Ys.prototype.layoutComments = function (a) {\n        if (null !== a.comments) {\n            var b = a.node.measuredBounds,\n                c = a.parent,\n                d = a.angle,\n                e = 0;\n            var f = !1;\n            null !== c && (e = c.angle, f = c.alignment, f = zt(f));\n            d = 90 === d || 270 === d;\n            c = 90 === e || 270 === e;\n            for (var g = 0 === a.childrenCount, h = Et(a), k = 0, l = a.comments, m = l.length, n = I.alloc(), p = 0; p < m; p++) {\n                var r = l[p],\n                    q = r.measuredBounds;\n                if (d && !g || !f && !c && g || f && c && g) {\n                    if (135 < e && !f || c && h)\n                        if (0 <= a.commentMargin)\n                            for (n.h(a.bounds.x - a.commentMargin - q.width, a.bounds.y + k), r.move(n), r = r.vd(); r.next();) {\n                                var u = r.value;\n                                u.fromSpot =\n                                    ed;\n                                u.toSpot = fd\n                            } else\n                                for (n.h(a.bounds.x + 2 * a.focus.x - a.commentMargin, a.bounds.y + k), r.move(n), r = r.vd(); r.next();) u = r.value, u.fromSpot = fd, u.toSpot = ed;\n                        else if (0 <= a.commentMargin)\n                        for (n.h(a.bounds.x + 2 * a.focus.x + a.commentMargin, a.bounds.y + k), r.move(n), r = r.vd(); r.next();) u = r.value, u.fromSpot = fd, u.toSpot = ed;\n                    else\n                        for (n.h(a.bounds.x + a.commentMargin - q.width, a.bounds.y + k), r.move(n), r = r.vd(); r.next();) u = r.value, u.fromSpot = ed, u.toSpot = fd;\n                    k = 0 <= a.commentSpacing ? k + (q.height + a.commentSpacing) : k + (a.commentSpacing - q.height)\n                } else {\n                    if (135 <\n                        e && !f || !c && h)\n                        if (0 <= a.commentMargin)\n                            for (n.h(a.bounds.x + k, a.bounds.y - a.commentMargin - q.height), r.move(n), r = r.vd(); r.next();) u = r.value, u.fromSpot = dd, u.toSpot = gd;\n                        else\n                            for (n.h(a.bounds.x + k, a.bounds.y + 2 * a.focus.y - a.commentMargin), r.move(n), r = r.vd(); r.next();) u = r.value, u.fromSpot = gd, u.toSpot = dd;\n                    else if (0 <= a.commentMargin)\n                        for (n.h(a.bounds.x + k, a.bounds.y + 2 * a.focus.y + a.commentMargin), r.move(n), r = r.vd(); r.next();) u = r.value, u.fromSpot = gd, u.toSpot = dd;\n                    else\n                        for (n.h(a.bounds.x + k, a.bounds.y + a.commentMargin - q.height),\n                            r.move(n), r = r.vd(); r.next();) u = r.value, u.fromSpot = dd, u.toSpot = gd;\n                    k = 0 <= a.commentSpacing ? k + (q.width + a.commentSpacing) : k + (a.commentSpacing - q.width)\n                }\n            }\n            I.free(n);\n            b = k - a.commentSpacing - (d ? b.height : b.width);\n            if (this.$c === $s)\n                for (a = a.destinationEdges; a.next();) e = a.value.link, null === e || e.isAvoiding || (e.fromEndSegmentLength = 0 < b ? b : NaN);\n            else\n                for (a = a.sourceEdges; a.next();) e = a.value.link, null === e || e.isAvoiding || (e.toEndSegmentLength = 0 < b ? b : NaN)\n        }\n    };\n    Ys.prototype.layoutTree = function (a) {\n        if (null !== a) {\n            for (var b = a.children, c = b.length, d = 0; d < c; d++) this.layoutTree(b[d]);\n            switch (a.compaction) {\n                case Ft:\n                    Gt(this, a);\n                    break;\n                case Ht:\n                    if (a.alignment === qt) Gt(this, a);\n                    else if (0 === a.childrenCount) d = a.parent, c = !1, b = 0, null !== d && (b = d.angle, c = d.alignment, c = zt(c)), d = Et(a), a.S.h(0, 0), a.ta.h(a.width, a.height), null === a.parent || null === a.comments || (180 !== b && 270 !== b || c) && !d ? a.da.h(0, 0) : 180 === b && !c || (90 === b || 270 === b) && d ? a.da.h(a.width - 2 * a.focus.x, 0) : a.da.h(0, a.height - 2 * a.focus.y),\n                        a.vq = null, a.Iq = null;\n                    else {\n                        var e = It(a);\n                        b = 90 === e || 270 === e;\n                        var f = 0,\n                            g = a.children,\n                            h = g.length;\n                        for (c = 0; c < h; c++) d = g[c], f = Math.max(f, b ? d.ta.width : d.ta.height);\n                        var k = a.alignment,\n                            l = k === Jt,\n                            m = zt(k),\n                            n = Math.max(0, a.breadthLimit);\n                        c = Kt(a);\n                        var p = a.nodeSpacing,\n                            r = Qt(a),\n                            q = a.rowSpacing,\n                            u = 0;\n                        if (k === Rt || l || a.Fm || a.Gm && 1 === a.maxGenerationCount) u = Math.max(0, a.rowIndent);\n                        d = a.width;\n                        var v = a.height,\n                            w = 0,\n                            y = 0,\n                            z = 0,\n                            A = null,\n                            C = null,\n                            G = 0,\n                            L = 0,\n                            K = 0,\n                            V = 0,\n                            Q = 0,\n                            ca = 0,\n                            pa = 0,\n                            O = 0;\n                        m && !Dt(k) && 135 < e && g.reverse();\n                        if (Dt(k))\n                            if (1 < h)\n                                for (var xa = 0; xa < h; xa++) 0 ===\n                                    xa % 2 && xa !== h - 1 && (O = Math.max(O, b ? g[xa].ta.width : g[xa].ta.height));\n                            else 1 === h && (O = b ? g[0].ta.width : g[0].ta.height);\n                        if (m) {\n                            switch (k) {\n                                case At:\n                                    y = 135 > e ? St(a, g, O, w, y) : Tt(a, g, O, w, y);\n                                    O = y.x;\n                                    w = y.width;\n                                    y = y.height;\n                                    break;\n                                case Bt:\n                                    for (A = 0; A < h; A++) C = g[A], n = C.ta, z = 0 === ca ? 0 : q, b ? (C.S.h(f - n.width, V + z), w = Math.max(w, n.width), y = Math.max(y, V + z + n.height), V += z + n.height) : (C.S.h(K + z, f - n.height), w = Math.max(w, K + z + n.width), y = Math.max(y, n.height), K += z + n.width), ca++;\n                                    break;\n                                case Ct:\n                                    for (A = 0; A < h; A++) C = g[A], f = C.ta, n = 0 === ca ? 0 : q, b ? (C.S.h(p /\n                                        2 + a.focus.x, V + n), w = Math.max(w, f.width), y = Math.max(y, V + n + f.height), V += n + f.height) : (C.S.h(K + n, p / 2 + a.focus.y), w = Math.max(w, K + n + f.width), y = Math.max(y, f.height), K += n + f.width), ca++\n                            }\n                            A = Ut(this, 2);\n                            C = Ut(this, 2);\n                            b ? (A[0].h(0, 0), A[1].h(0, y), C[0].h(w, 0)) : (A[0].h(0, 0), A[1].h(w, 0), C[0].h(0, y));\n                            C[1].h(w, y)\n                        } else\n                            for (xa = 0; xa < h; xa++) {\n                                var Ma = g[xa],\n                                    hb = Ma.ta;\n                                if (b) {\n                                    0 < n && 0 < ca && K + p + hb.width > n && (K < f && Vt(a, k, f - K, 0, pa, xa - 1), Q++, ca = 0, pa = xa, z = y, K = 0, V = 135 < e ? -y - q : y + q);\n                                    Wt(this, Ma, 0, V);\n                                    var Ea = 0;\n                                    if (0 === ca) {\n                                        if (A = Ma.vq, C = Ma.Iq, G = hb.width,\n                                            L = hb.height, null === A || null === C || e !== It(Ma)) A = Ut(this, 2), C = Ut(this, 2), A[0].h(0, 0), A[1].h(0, L), C[0].h(G, 0), C[1].h(G, L)\n                                    } else {\n                                        var xb = Fa();\n                                        L = Xt(this, a, Ma, A, C, G, L, xb);\n                                        Ea = L.x;\n                                        A = xb[0];\n                                        C = xb[1];\n                                        G = L.width;\n                                        L = L.height;\n                                        Ha(xb);\n                                        K < hb.width && 0 > Ea && (Yt(a, -Ea, 0, pa, xa - 1), Zt(A, -Ea, 0), Zt(C, -Ea, 0), Ea = 0)\n                                    }\n                                    Ma.S.h(Ea, V);\n                                    w = Math.max(w, G);\n                                    y = Math.max(y, z + (0 === Q ? 0 : q) + hb.height);\n                                    K = G\n                                } else {\n                                    0 < n && 0 < ca && V + p + hb.height > n && (V < f && Vt(a, k, 0, f - V, pa, xa - 1), Q++, ca = 0, pa = xa, z = w, V = 0, K = 135 < e ? -w - q : w + q);\n                                    Wt(this, Ma, K, 0);\n                                    Ea = 0;\n                                    if (0 === ca) {\n                                        if (A = Ma.vq, C = Ma.Iq,\n                                            G = hb.width, L = hb.height, null === A || null === C || e !== It(Ma)) A = Ut(this, 2), C = Ut(this, 2), A[0].h(0, 0), A[1].h(G, 0), C[0].h(0, L), C[1].h(G, L)\n                                    } else xb = Fa(), L = Xt(this, a, Ma, A, C, G, L, xb), Ea = L.x, A = xb[0], C = xb[1], G = L.width, L = L.height, Ha(xb), V < hb.height && 0 > Ea && (Yt(a, 0, -Ea, pa, xa - 1), Zt(A, 0, -Ea), Zt(C, 0, -Ea), Ea = 0);\n                                    Ma.S.h(K, Ea);\n                                    y = Math.max(y, L);\n                                    w = Math.max(w, z + (0 === Q ? 0 : q) + hb.width);\n                                    V = L\n                                }\n                                ca++\n                            }\n                        0 < Q && (b ? (y += Math.max(0, c), K < w && Vt(a, k, w - K, 0, pa, h - 1), 0 < u && (l || Yt(a, u, 0, 0, h - 1), w += u)) : (w += Math.max(0, c), V < y && Vt(a, k, 0, y - V, pa, h - 1), 0 < u && (l ||\n                            Yt(a, 0, u, 0, h - 1), y += u)));\n                        u = l = 0;\n                        switch (k) {\n                            case $t:\n                                b ? l += w / 2 - a.focus.x - r / 2 : u += y / 2 - a.focus.y - r / 2;\n                                break;\n                            case au:\n                                0 < Q ? b ? l += w / 2 - a.focus.x - r / 2 : u += y / 2 - a.focus.y - r / 2 : b ? (O = g[0].S.x + g[0].da.x, l += O + (g[h - 1].S.x + g[h - 1].da.x + 2 * g[h - 1].focus.x - O) / 2 - a.focus.x - r / 2) : (O = g[0].S.y + g[0].da.y, u += O + (g[h - 1].S.y + g[h - 1].da.y + 2 * g[h - 1].focus.y - O) / 2 - a.focus.y - r / 2);\n                                break;\n                            case Rt:\n                                b ? (l -= r, w += r) : (u -= r, y += r);\n                                break;\n                            case Jt:\n                                b ? (l += w - a.width + r, w += r) : (u += y - a.height + r, y += r);\n                                break;\n                            case At:\n                                b ? 1 < h ? l += O + p / 2 - a.focus.x : l += g[0].focus.x - a.focus.x + g[0].da.x :\n                                    1 < h ? u += O + p / 2 - a.focus.y : u += g[0].focus.y - a.focus.y + g[0].da.y;\n                                break;\n                            case Bt:\n                                b ? l += w + p / 2 - a.focus.x : u += y + p / 2 - a.focus.y;\n                                break;\n                            case Ct:\n                                break;\n                            default:\n                                B(\"Unhandled alignment value \" + k.toString())\n                        }\n                        for (r = 0; r < h; r++) O = g[r], b ? O.S.h(O.S.x + O.da.x - l, O.S.y + (135 < e ? (m ? -y : -O.ta.height) + O.da.y - c : v + c + O.da.y)) : O.S.h(O.S.x + (135 < e ? (m ? -w : -O.ta.width) + O.da.x - c : d + c + O.da.x), O.S.y + O.da.y - u);\n                        h = g = 0;\n                        m ? b ? (w = bu(a, w, l), 0 > l && (l = 0), 135 < e && (u += y + c), y += v + c, k === Ct && (g += p / 2 + a.focus.x), h += v + c) : (135 < e && (l += w + c), w += d + c, y = cu(a, y, u), 0 > u && (u = 0),\n                            k === Ct && (h += p / 2 + a.focus.y), g += d + c) : b ? (null === a.comments ? d > w && (w = du(k, d - w, 0), g = w.x, h = w.y, w = d, l = 0) : w = bu(a, w, l), 0 > l && (g -= l, l = 0), 135 < e && (u += y + c), y = Math.max(Math.max(y, v), y + v + c), h += v + c) : (135 < e && (l += w + c), w = Math.max(Math.max(w, d), w + d + c), null === a.comments ? v > y && (y = du(k, 0, v - y), g = y.x, h = y.y, y = v, u = 0) : y = cu(a, y, u), 0 > u && (h -= u, u = 0), g += d + c);\n                        if (0 < Q) e = Ut(this, 4), Q = Ut(this, 4), b ? (e[2].h(0, v + c), e[3].h(e[2].x, y), Q[2].h(w, e[2].y), Q[3].h(Q[2].x, e[3].y)) : (e[2].h(d + c, 0), e[3].h(w, e[2].y), Q[2].h(e[2].x, y), Q[3].h(e[3].x, Q[2].y));\n                        else {\n                            e = Ut(this, A.length + 2);\n                            Q = Ut(this, C.length + 2);\n                            for (k = 0; k < A.length; k++) m = A[k], e[k + 2].h(m.x + g, m.y + h);\n                            for (k = 0; k < C.length; k++) m = C[k], Q[k + 2].h(m.x + g, m.y + h)\n                        }\n                        b ? (e[0].h(l, 0), e[1].h(e[0].x, v), e[2].y < e[1].y && (e[2].x > e[0].x ? e[2].assign(e[1]) : e[1].assign(e[2])), e[3].y < e[2].y && (e[3].x > e[0].x ? e[3].assign(e[2]) : e[2].assign(e[3])), Q[0].h(l + d, 0), Q[1].h(Q[0].x, v), Q[2].y < Q[1].y && (Q[2].x < Q[0].x ? Q[2].assign(Q[1]) : Q[1].assign(Q[2])), Q[3].y < Q[2].y && (Q[3].x < Q[0].x ? Q[3].assign(Q[2]) : Q[2].assign(Q[3])), e[2].y -= c / 2, Q[2].y -=\n                            c / 2) : (e[0].h(0, u), e[1].h(d, e[0].y), e[2].x < e[1].x && (e[2].y > e[0].y ? e[2].assign(e[1]) : e[1].assign(e[2])), e[3].x < e[2].x && (e[3].y > e[0].y ? e[3].assign(e[2]) : e[2].assign(e[3])), Q[0].h(0, u + v), Q[1].h(d, Q[0].y), Q[2].x < Q[1].x && (Q[2].y < Q[0].y ? Q[2].assign(Q[1]) : Q[1].assign(Q[2])), Q[3].x < Q[2].x && (Q[3].y < Q[0].y ? Q[3].assign(Q[2]) : Q[2].assign(Q[3])), e[2].x -= c / 2, Q[2].x -= c / 2);\n                        eu(this, A);\n                        eu(this, C);\n                        a.vq = e;\n                        a.Iq = Q;\n                        a.da.h(l, u);\n                        a.ta.h(w, y)\n                    }\n                    break;\n                default:\n                    B(\"Unhandled compaction value \" + a.compaction.toString())\n            }\n        }\n    };\n\n    function Gt(a, b) {\n        if (0 === b.childrenCount) {\n            var c = !1,\n                d = 0;\n            null !== b.parent && (d = b.parent.angle, c = b.parent.alignment, c = zt(c));\n            var e = Et(b);\n            b.S.h(0, 0);\n            b.ta.h(b.width, b.height);\n            null === b.parent || null === b.comments || (180 !== d && 270 !== d || c) && !e ? b.da.h(0, 0) : 180 === d && !c || (90 === d || 270 === d) && e ? b.da.h(b.width - 2 * b.focus.x, 0) : b.da.h(0, b.height - 2 * b.focus.y)\n        } else {\n            d = It(b);\n            c = 90 === d || 270 === d;\n            var f = 0;\n            e = b.children;\n            for (var g = e.length, h = 0; h < g; h++) {\n                var k = e[h];\n                f = Math.max(f, c ? k.ta.width : k.ta.height)\n            }\n            var l = b.alignment,\n                m = l === Rt,\n                n = l ===\n                Jt;\n            h = zt(l);\n            var p = Math.max(0, b.breadthLimit);\n            k = Kt(b);\n            var r = b.nodeSpacing,\n                q = Qt(b),\n                u = m || n ? 0 : q / 2,\n                v = b.rowSpacing,\n                w = 0;\n            if (m || n || b.Fm || b.Gm && 1 === b.maxGenerationCount) w = Math.max(0, b.rowIndent);\n            m = b.width;\n            var y = b.height,\n                z = 0,\n                A = 0,\n                C = 0,\n                G = 0,\n                L = 0,\n                K = 0,\n                V = 0,\n                Q = 0,\n                ca = 0;\n            h && !Dt(l) && 135 < d && e.reverse();\n            if (Dt(l))\n                if (1 < g)\n                    for (var pa = 0; pa < g; pa++) {\n                        var O = e[pa],\n                            xa = O.ta;\n                        0 === pa % 2 && pa !== g - 1 && (ca = Math.max(ca, (c ? xa.width : xa.height) + fu(O) - r))\n                    } else 1 === g && (ca = c ? e[0].ta.width : e[0].ta.height);\n            if (h) switch (l) {\n                case At:\n                case qt:\n                    A = 135 > d ? St(b, e, ca,\n                        z, A) : Tt(b, e, ca, z, A);\n                    ca = A.x;\n                    z = A.width;\n                    A = A.height;\n                    break;\n                case Bt:\n                    for (a = 0; a < g; a++) p = e[a], u = p.ta, C = 0 === V ? 0 : v, c ? (p.S.h(f - u.width, L + C), z = Math.max(z, u.width), A = Math.max(A, L + C + u.height), L += C + u.height) : (p.S.h(G + C, f - u.height), z = Math.max(z, G + C + u.width), A = Math.max(A, u.height), G += C + u.width), V++;\n                    break;\n                case Ct:\n                    for (f = 0; f < g; f++) a = e[f], p = a.ta, u = 0 === V ? 0 : v, c ? (a.S.h(r / 2 + b.focus.x, L + u), z = Math.max(z, p.width), A = Math.max(A, L + u + p.height), L += u + p.height) : (a.S.h(G + u, r / 2 + b.focus.y), z = Math.max(z, G + u + p.width), A = Math.max(A, p.height),\n                        G += u + p.width), V++\n            } else\n                for (pa = 0; pa < g; pa++) {\n                    O = e[pa];\n                    xa = O.ta;\n                    if (c) {\n                        0 < p && 0 < V && G + r + xa.width > p && (G < f && Vt(b, l, f - G, 0, Q, pa - 1), K++, V = 0, Q = pa, C = A, G = 0, L = 135 < d ? -A - v : A + v);\n                        var Ma = 0 === V ? u : r;\n                        Wt(a, O, 0, L);\n                        O.S.h(G + Ma, L);\n                        z = Math.max(z, G + Ma + xa.width);\n                        A = Math.max(A, C + (0 === K ? 0 : v) + xa.height);\n                        G += Ma + xa.width\n                    } else 0 < p && 0 < V && L + r + xa.height > p && (L < f && Vt(b, l, 0, f - L, Q, pa - 1), K++, V = 0, Q = pa, C = z, L = 0, G = 135 < d ? -z - v : z + v), Ma = 0 === V ? u : r, Wt(a, O, G, 0), O.S.h(G, L + Ma), A = Math.max(A, L + Ma + xa.height), z = Math.max(z, C + (0 === K ? 0 : v) + xa.width), L += Ma + xa.height;\n                    V++\n                }\n            0 <\n                K && (c ? (A += Math.max(0, k), G < z && Vt(b, l, z - G, 0, Q, g - 1), 0 < w && (n || Yt(b, w, 0, 0, g - 1), z += w)) : (z += Math.max(0, k), L < A && Vt(b, l, 0, A - L, Q, g - 1), 0 < w && (n || Yt(b, 0, w, 0, g - 1), A += w)));\n            w = n = 0;\n            switch (l) {\n                case $t:\n                    c ? n += z / 2 - b.focus.x - q / 2 : w += A / 2 - b.focus.y - q / 2;\n                    break;\n                case au:\n                    0 < K ? c ? n += z / 2 - b.focus.x - q / 2 : w += A / 2 - b.focus.y - q / 2 : c ? (l = e[0].S.x + e[0].da.x, n += l + (e[g - 1].S.x + e[g - 1].da.x + 2 * e[g - 1].focus.x - l) / 2 - b.focus.x - q / 2) : (l = e[0].S.y + e[0].da.y, w += l + (e[g - 1].S.y + e[g - 1].da.y + 2 * e[g - 1].focus.y - l) / 2 - b.focus.y - q / 2);\n                    break;\n                case Rt:\n                    c ? (n -= q, z += q) : (w -= q, A +=\n                        q);\n                    break;\n                case Jt:\n                    c ? (n += z - b.width + q, z += q) : (w += A - b.height + q, A += q);\n                    break;\n                case At:\n                case qt:\n                    c ? 1 < g ? n += ca + r / 2 - b.focus.x : n += e[0].focus.x - b.focus.x + e[0].da.x : 1 < g ? w += ca + r / 2 - b.focus.y : w += e[0].focus.y - b.focus.y + e[0].da.y;\n                    break;\n                case Bt:\n                    c ? n += z + r / 2 - b.focus.x : w += A + r / 2 - b.focus.y;\n                    break;\n                case Ct:\n                    break;\n                default:\n                    B(\"Unhandled alignment value \" + l.toString())\n            }\n            for (q = 0; q < g; q++) l = e[q], c ? l.S.h(l.S.x + l.da.x - n, l.S.y + (135 < d ? (h ? -A : -l.ta.height) + l.da.y - k : y + k + l.da.y)) : l.S.h(l.S.x + (135 < d ? (h ? -z : -l.ta.width) + l.da.x - k : m + k + l.da.x), l.S.y +\n                l.da.y - w);\n            c ? (z = bu(b, z, n), 0 > n && (n = 0), 135 < d && (w += A + k), A = Math.max(Math.max(A, y), A + y + k)) : (135 < d && (n += z + k), z = Math.max(Math.max(z, m), z + m + k), A = cu(b, A, w), 0 > w && (w = 0));\n            b.da.h(n, w);\n            b.ta.h(z, A)\n        }\n    }\n\n    function St(a, b, c, d, e) {\n        var f = b.length;\n        if (0 === f) return new N(c, 0, d, e);\n        if (1 === f) return a = b[0], d = a.ta.width, e = a.ta.height, new N(c, 0, d, e);\n        for (var g = a.nodeSpacing, h = a.rowSpacing, k = 90 === It(a), l = 0, m = 0, n = 0, p = 0; p < f; p++)\n            if (!(0 !== p % 2 || 1 < f && p === f - 1)) {\n                var r = b[p],\n                    q = r.ta,\n                    u = 0 === l ? 0 : h;\n                if (k) {\n                    var v = fu(r) - g;\n                    r.S.h(c - (q.width + v), n + u);\n                    d = Math.max(d, q.width + v);\n                    e = Math.max(e, n + u + q.height);\n                    n += u + q.height\n                } else v = fu(r) - g, r.S.h(m + u, c - (q.height + v)), e = Math.max(e, q.height + v), d = Math.max(d, m + u + q.width), m += u + q.width;\n                l++\n            } l = 0;\n        r = m;\n        p = n;\n        k ?\n            (m = c + g, n = 0) : (m = 0, n = c + g);\n        for (q = 0; q < f; q++)\n            if (0 !== q % 2) {\n                u = b[q];\n                v = u.ta;\n                var w = 0 === l ? 0 : h;\n                if (k) {\n                    var y = fu(u) - g;\n                    u.S.h(m + y, n + w);\n                    d = Math.max(d, m + v.width + y);\n                    e = Math.max(e, n + w + v.height);\n                    n += w + v.height\n                } else y = fu(u) - g, u.S.h(m + w, n + y), d = Math.max(d, m + w + v.width), e = Math.max(e, n + v.height + y), m += w + v.width;\n                l++\n            } 1 < f && 1 === f % 2 && (b = b[f - 1], f = b.ta, h = null === b.parent ? 0 : b.parent.rowSpacing, k ? (b.S.h(c + g / 2 - b.focus.x - b.da.x, e + h), k = c + g / 2 - b.focus.x - b.da.x, d = Math.max(d, k + f.width), 0 > k && (d -= k), e = Math.max(e, Math.max(p, n) + h + f.height), 0 > b.S.x &&\n            (c = gu(a, b.S.x, !1, c, g))) : (b.S.h(d + h, c + g / 2 - b.focus.y - b.da.y), d = Math.max(d, Math.max(r, m) + h + f.width), n = c + g / 2 - b.focus.y - b.da.y, e = Math.max(e, n + f.height), 0 > n && (e -= n), 0 > b.S.y && (c = gu(a, b.S.y, !0, c, g))));\n        return new N(c, 0, d, e)\n    }\n\n    function Tt(a, b, c, d, e) {\n        var f = b.length;\n        if (0 === f) return new N(c, 0, d, e);\n        if (1 === f) return b = b[0], d = b.ta.width, e = b.ta.height, new N(c, 0, d, e);\n        for (var g = a.nodeSpacing, h = a.rowSpacing, k = 270 === It(a), l = 0, m = 0, n = 0, p = 0; p < f; p++)\n            if (!(0 !== p % 2 || 1 < f && p === f - 1)) {\n                var r = b[p],\n                    q = r.ta,\n                    u = 0 === l ? 0 : h;\n                if (k) {\n                    var v = fu(r) - g;\n                    n -= u + q.height;\n                    r.S.h(c - (q.width + v), n);\n                    d = Math.max(d, q.width + v);\n                    e = Math.max(e, Math.abs(n))\n                } else v = fu(r) - g, m -= u + q.width, r.S.h(m, c - (q.height + v)), e = Math.max(e, q.height + v), d = Math.max(d, Math.abs(m));\n                l++\n            } l = 0;\n        r = m;\n        p = n;\n        k ? (m =\n            c + g, n = 0) : (m = 0, n = c + g);\n        for (q = 0; q < f; q++)\n            if (0 !== q % 2) {\n                u = b[q];\n                v = u.ta;\n                var w = 0 === l ? 0 : h;\n                if (k) {\n                    var y = fu(u) - g;\n                    n -= w + v.height;\n                    u.S.h(m + y, n);\n                    d = Math.max(d, m + v.width + y);\n                    e = Math.max(e, Math.abs(n))\n                } else y = fu(u) - g, m -= w + v.width, u.S.h(m, n + y), e = Math.max(e, n + v.height + y), d = Math.max(d, Math.abs(m));\n                l++\n            } 1 < f && 1 === f % 2 && (h = b[f - 1], l = h.ta, q = null === h.parent ? 0 : h.parent.rowSpacing, k ? (h.S.h(c + g / 2 - h.focus.x - h.da.x, -e - l.height - q), m = c + g / 2 - h.focus.x - h.da.x, d = Math.max(d, m + l.width), 0 > m && (d -= m), e = Math.max(e, Math.abs(Math.min(p, n)) + q + l.height),\n            0 > h.S.x && (c = gu(a, h.S.x, !1, c, g))) : (h.S.h(-d - l.width - q, c + g / 2 - h.focus.y - h.da.y), d = Math.max(d, Math.abs(Math.min(r, m)) + q + l.width), n = c + g / 2 - h.focus.y - h.da.y, e = Math.max(e, n + l.height), 0 > n && (e -= n), 0 > h.S.y && (c = gu(a, h.S.y, !0, c, g))));\n        for (a = 0; a < f; a++) g = b[a], k ? g.S.h(g.S.x, g.S.y + e) : g.S.h(g.S.x + d, g.S.y);\n        return new N(c, 0, d, e)\n    }\n\n    function fu(a) {\n        return null === a.parent ? 0 : a.parent.nodeSpacing\n    }\n\n    function gu(a, b, c, d, e) {\n        a = a.children;\n        for (var f = a.length, g = 0; g < f; g++) c ? a[g].S.h(a[g].S.x, a[g].S.y - b) : a[g].S.h(a[g].S.x - b, a[g].S.y);\n        b = a[f - 1];\n        return Math.max(d, c ? b.da.y + b.focus.y - e / 2 : b.da.x + b.focus.x - e / 2)\n    }\n\n    function bu(a, b, c) {\n        switch (a.alignment) {\n            case au:\n            case $t:\n                return c + a.width > b && (b = c + a.width), 0 > c && (b -= c), b;\n            case Rt:\n                return a.width > b ? a.width : b;\n            case Jt:\n                return 2 * a.focus.x > b ? a.width : b + a.width - 2 * a.focus.x;\n            case At:\n            case qt:\n                return Math.max(a.width, Math.max(b, c + a.width) - Math.min(0, c));\n            case Bt:\n                return a.width - a.focus.x + a.nodeSpacing / 2 + b;\n            case Ct:\n                return Math.max(a.width, a.focus.x + a.nodeSpacing / 2 + b);\n            default:\n                return b\n        }\n    }\n\n    function cu(a, b, c) {\n        switch (a.alignment) {\n            case au:\n            case $t:\n                return c + a.height > b && (b = c + a.height), 0 > c && (b -= c), b;\n            case Rt:\n                return a.height > b ? a.height : b;\n            case Jt:\n                return 2 * a.focus.y > b ? a.height : b + a.height - 2 * a.focus.y;\n            case At:\n            case qt:\n                return Math.max(a.height, Math.max(b, c + a.height) - Math.min(0, c));\n            case Bt:\n                return a.height - a.focus.y + a.nodeSpacing / 2 + b;\n            case Ct:\n                return Math.max(a.height, a.focus.y + a.nodeSpacing / 2 + b);\n            default:\n                return b\n        }\n    }\n\n    function du(a, b, c) {\n        switch (a) {\n            case $t:\n                b /= 2;\n                c /= 2;\n                break;\n            case au:\n                b /= 2;\n                c /= 2;\n                break;\n            case Rt:\n                c = b = 0;\n                break;\n            case Jt:\n                break;\n            default:\n                B(\"Unhandled alignment value \" + a.toString())\n        }\n        return new I(b, c)\n    }\n\n    function Vt(a, b, c, d, e, f) {\n        b = du(b, c, d);\n        Yt(a, b.x, b.y, e, f)\n    }\n\n    function Yt(a, b, c, d, e) {\n        if (0 !== b || 0 !== c)\n            for (a = a.children; d <= e; d++) {\n                var f = a[d].S;\n                f.x += b;\n                f.y += c\n            }\n    }\n\n    function Wt(a, b, c, d) {\n        var e = b.parent;\n        switch (a.$c) {\n            case $s:\n                for (a = b.sourceEdges; a.next();) b = a.value, b.fromVertex === e && b.relativePoint.h(c, d);\n                break;\n            case gt:\n                for (a = b.destinationEdges; a.next();) b = a.value, b.toVertex === e && b.relativePoint.h(c, d);\n                break;\n            default:\n                B(\"Unhandled path value \" + a.$c.toString())\n        }\n    }\n\n    function Zt(a, b, c) {\n        for (var d = 0; d < a.length; d++) {\n            var e = a[d];\n            e.x += b;\n            e.y += c\n        }\n    }\n\n    function Xt(a, b, c, d, e, f, g, h) {\n        var k = It(b),\n            l = 90 === k || 270 === k,\n            m = b.nodeSpacing;\n        b = d;\n        var n = e;\n        d = f;\n        var p = g,\n            r = c.vq,\n            q = c.Iq;\n        g = c.ta;\n        var u = l ? Math.max(p, g.height) : Math.max(d, g.width);\n        if (null === r || k !== It(c)) r = Ut(a, 2), q = Ut(a, 2), l ? (r[0].h(0, 0), r[1].h(0, g.height), q[0].h(g.width, 0), q[1].h(q[0].x, r[1].y)) : (r[0].h(0, 0), r[1].h(g.width, 0), q[0].h(0, g.height), q[1].h(r[1].x, q[0].y));\n        if (l) {\n            p = 9999999;\n            if (!(null === n || 2 > n.length || null === r || 2 > r.length))\n                for (e = c = 0; c < n.length && e < r.length;) {\n                    f = n[c];\n                    var v = r[e];\n                    k = v.x;\n                    l = v.y;\n                    k += d;\n                    var w =\n                        f;\n                    c + 1 < n.length && (w = n[c + 1]);\n                    var y = v;\n                    v = y.x;\n                    y = y.y;\n                    e + 1 < r.length && (y = r[e + 1], v = y.x, y = y.y, v += d);\n                    var z = p;\n                    f.y === l ? z = k - f.x : f.y > l && f.y < y ? z = k + (f.y - l) / (y - l) * (v - k) - f.x : l > f.y && l < w.y && (z = k - (f.x + (l - f.y) / (w.y - f.y) * (w.x - f.x)));\n                    z < p && (p = z);\n                    w.y <= f.y ? c++ : y <= l ? e++ : (w.y <= y && c++, y <= w.y && e++)\n                }\n            p = d - p;\n            p += m;\n            c = r;\n            e = p;\n            if (null === b || 2 > b.length || null === c || 2 > c.length) d = null;\n            else {\n                m = Ut(a, b.length + c.length);\n                for (d = f = k = 0; f < c.length && c[f].y < b[0].y;) l = c[f++], m[d++].h(l.x + e, l.y);\n                for (; k < b.length;) l = b[k++], m[d++].h(l.x, l.y);\n                for (k = b[b.length - 1].y; f <\n                    c.length && c[f].y <= k;) f++;\n                for (; f < c.length && c[f].y > k;) l = c[f++], m[d++].h(l.x + e, l.y);\n                c = Ut(a, d);\n                for (k = 0; k < d; k++) c[k].assign(m[k]);\n                eu(a, m);\n                d = c\n            }\n            f = q;\n            k = p;\n            if (null === n || 2 > n.length || null === f || 2 > f.length) e = null;\n            else {\n                m = Ut(a, n.length + f.length);\n                for (e = l = c = 0; c < n.length && n[c].y < f[0].y;) w = n[c++], m[e++].h(w.x, w.y);\n                for (; l < f.length;) w = f[l++], m[e++].h(w.x + k, w.y);\n                for (f = f[f.length - 1].y; c < n.length && n[c].y <= f;) c++;\n                for (; c < n.length && n[c].y > f;) k = n[c++], m[e++].h(k.x, k.y);\n                f = Ut(a, e);\n                for (c = 0; c < e; c++) f[c].assign(m[c]);\n                eu(a, m);\n                e = f\n            }\n            f =\n                Math.max(0, p) + g.width;\n            g = u;\n            eu(a, b);\n            eu(a, r);\n            eu(a, n);\n            eu(a, q);\n            h[0] = d;\n            h[1] = e;\n            return new N(p, 0, f, g)\n        }\n        d = 9999999;\n        if (!(null === n || 2 > n.length || null === r || 2 > r.length))\n            for (e = c = 0; c < n.length && e < r.length;) f = n[c], v = r[e], k = v.x, l = v.y, l += p, w = f, c + 1 < n.length && (w = n[c + 1]), y = v, v = y.x, y = y.y, e + 1 < r.length && (y = r[e + 1], v = y.x, y = y.y, y += p), z = d, f.x === k ? z = l - f.y : f.x > k && f.x < v ? z = l + (f.x - k) / (v - k) * (y - l) - f.y : k > f.x && k < w.x && (z = l - (f.y + (k - f.x) / (w.x - f.x) * (w.y - f.y))), z < d && (d = z), w.x <= f.x ? c++ : v <= k ? e++ : (w.x <= v && c++, v <= w.x && e++);\n        p -= d;\n        p += m;\n        c = r;\n        e = p;\n        if (null ===\n            b || 2 > b.length || null === c || 2 > c.length) d = null;\n        else {\n            m = Ut(a, b.length + c.length);\n            for (d = f = k = 0; f < c.length && c[f].x < b[0].x;) l = c[f++], m[d++].h(l.x, l.y + e);\n            for (; k < b.length;) l = b[k++], m[d++].h(l.x, l.y);\n            for (k = b[b.length - 1].x; f < c.length && c[f].x <= k;) f++;\n            for (; f < c.length && c[f].x > k;) l = c[f++], m[d++].h(l.x, l.y + e);\n            c = Ut(a, d);\n            for (k = 0; k < d; k++) c[k].assign(m[k]);\n            eu(a, m);\n            d = c\n        }\n        f = q;\n        k = p;\n        if (null === n || 2 > n.length || null === f || 2 > f.length) e = null;\n        else {\n            m = Ut(a, n.length + f.length);\n            for (e = l = c = 0; c < n.length && n[c].x < f[0].x;) w = n[c++], m[e++].h(w.x, w.y);\n            for (; l < f.length;) w = f[l++], m[e++].h(w.x, w.y + k);\n            for (f = f[f.length - 1].x; c < n.length && n[c].x <= f;) c++;\n            for (; c < n.length && n[c].x > f;) k = n[c++], m[e++].h(k.x, k.y);\n            f = Ut(a, e);\n            for (c = 0; c < e; c++) f[c].assign(m[c]);\n            eu(a, m);\n            e = f\n        }\n        f = u;\n        g = Math.max(0, p) + g.height;\n        eu(a, b);\n        eu(a, r);\n        eu(a, n);\n        eu(a, q);\n        h[0] = d;\n        h[1] = e;\n        return new N(p, 0, f, g)\n    }\n\n    function Ut(a, b) {\n        a = a.Uu[b];\n        if (void 0 !== a && (a = a.pop(), void 0 !== a)) return a;\n        a = [];\n        for (var c = 0; c < b; c++) a[c] = new I;\n        return a\n    }\n\n    function eu(a, b) {\n        var c = b.length,\n            d = a.Uu[c];\n        void 0 === d && (d = [], a.Uu[c] = d);\n        d.push(b)\n    }\n    Ys.prototype.arrangeTrees = function () {\n        if (this.Ab === ft)\n            for (var a = this.Hb.iterator; a.next();) {\n                var b = a.value;\n                if (b instanceof et) {\n                    var c = b.node;\n                    if (null !== c) {\n                        var d = c.position;\n                        c = d.x;\n                        d = d.y;\n                        isFinite(c) || (c = 0);\n                        isFinite(d) || (d = 0);\n                        hu(this, b, c, d)\n                    }\n                }\n            } else {\n                a = [];\n                for (b = this.Hb.iterator; b.next();) c = b.value, c instanceof et && a.push(c);\n                switch (this.sorting) {\n                    case vt:\n                        break;\n                    case wt:\n                        a.reverse();\n                        break;\n                    case xt:\n                        a.sort(this.comparer);\n                        break;\n                    case yt:\n                        a.sort(this.comparer);\n                        a.reverse();\n                        break;\n                    default:\n                        B(\"Unhandled sorting value \" + this.sorting.toString())\n                }\n                c =\n                    this.arrangementOrigin;\n                b = c.x;\n                c = c.y;\n                for (d = 0; d < a.length; d++) {\n                    var e = a[d];\n                    hu(this, e, b + e.da.x, c + e.da.y);\n                    switch (this.Ab) {\n                        case ct:\n                            c += e.ta.height + this.zd.height;\n                            break;\n                        case iu:\n                            b += e.ta.width + this.zd.width;\n                            break;\n                        default:\n                            B(\"Unhandled arrangement value \" + this.Ab.toString())\n                    }\n                }\n            }\n    };\n\n    function hu(a, b, c, d) {\n        if (null !== b) {\n            b.x = c;\n            b.y = d;\n            b = b.children;\n            for (var e = b.length, f = 0; f < e; f++) {\n                var g = b[f];\n                hu(a, g, c + g.S.x, d + g.S.y)\n            }\n        }\n    }\n    Ys.prototype.commitLayout = function () {\n        this.fw();\n        this.commitNodes();\n        this.hv();\n        this.isRouting && this.commitLinks()\n    };\n    Ys.prototype.commitNodes = function () {\n        for (var a = this.network.vertexes.iterator; a.next();) a.value.commit();\n        for (a.reset(); a.next();) this.layoutComments(a.value)\n    };\n    Ys.prototype.hv = function () {\n        if (this.layerStyle === nt) {\n            for (var a = this.Lw, b = [], c = null, d = this.network.vertexes.iterator; d.next();) {\n                var e = d.value;\n                null === c ? c = e.bounds.copy() : c.Hc(e.bounds);\n                var f = b[e.level];\n                void 0 === f ? f = Kt(e) : f = Math.max(f, Kt(e));\n                b[e.level] = f\n            }\n            for (d = 0; d < b.length; d++) void 0 === b[d] && (b[d] = 0);\n            90 === this.angle || 270 === this.angle ? (c.Vc(this.nodeSpacing / 2, this.layerSpacing), d = new I(-this.nodeSpacing / 2, -this.layerSpacing / 2)) : (c.Vc(this.layerSpacing, this.nodeSpacing / 2), d = new I(-this.layerSpacing / 2, -this.nodeSpacing /\n                2));\n            e = [];\n            c = 90 === this.angle || 270 === this.angle ? c.width : c.height;\n            f = 0;\n            if (180 === this.angle || 270 === this.angle)\n                for (var g = 0; g < a.length; g++) f += a[g] + b[g];\n            for (g = 0; g < a.length; g++) {\n                var h = a[g] + b[g];\n                270 === this.angle ? (f -= h, e.push(new N(0, f, c, h))) : 90 === this.angle ? (e.push(new N(0, f, c, h)), f += h) : 180 === this.angle ? (f -= h, e.push(new N(f, 0, h, c))) : (e.push(new N(f, 0, h, c)), f += h)\n            }\n            this.commitLayers(e, d)\n        }\n    };\n    Ys.prototype.commitLayers = function () {};\n    Ys.prototype.commitLinks = function () {\n        for (var a = this.network.edges.iterator; a.next();) a.value.commit()\n    };\n    Ys.prototype.fw = function () {\n        for (var a = this.Hb.iterator; a.next();) {\n            var b = a.value;\n            b instanceof et && ju(this, b)\n        }\n    };\n\n    function ju(a, b) {\n        if (null !== b) {\n            a.setPortSpots(b);\n            b = b.children;\n            for (var c = b.length, d = 0; d < c; d++) ju(a, b[d])\n        }\n    }\n    Ys.prototype.setPortSpots = function (a) {\n        var b = a.alignment;\n        if (zt(b)) {\n            var c = this.$c === $s,\n                d = It(a);\n            switch (d) {\n                case 0:\n                    var e = fd;\n                    break;\n                case 90:\n                    e = gd;\n                    break;\n                case 180:\n                    e = ed;\n                    break;\n                default:\n                    e = dd\n            }\n            var f = a.children,\n                g = f.length;\n            switch (b) {\n                case At:\n                case qt:\n                    for (b = 0; b < g; b++) {\n                        var h = f[b];\n                        h = (c ? h.sourceEdges : h.destinationEdges).first();\n                        if (null !== h && (h = h.link, null !== h)) {\n                            var k = 90 === d || 270 === d ? ed : dd;\n                            if (1 === g || b === g - 1 && 1 === g % 2) switch (d) {\n                                case 0:\n                                    k = ed;\n                                    break;\n                                case 90:\n                                    k = dd;\n                                    break;\n                                case 180:\n                                    k = fd;\n                                    break;\n                                default:\n                                    k = gd\n                            } else 0 === b % 2 && (k = 90 === d || 270 ===\n                                d ? fd : gd);\n                            c ? (a.setsPortSpot && (h.fromSpot = e), a.setsChildPortSpot && (h.toSpot = k)) : (a.setsPortSpot && (h.fromSpot = k), a.setsChildPortSpot && (h.toSpot = e))\n                        }\n                    }\n                    break;\n                case Bt:\n                    d = 90 === d || 270 === d ? fd : gd;\n                    for (f = c ? a.destinationEdges : a.sourceEdges; f.next();) g = f.value.link, null !== g && (c ? (a.setsPortSpot && (g.fromSpot = e), a.setsChildPortSpot && (g.toSpot = d)) : (a.setsPortSpot && (g.fromSpot = d), a.setsChildPortSpot && (g.toSpot = e)));\n                    break;\n                case Ct:\n                    for (d = 90 === d || 270 === d ? ed : dd, f = c ? a.destinationEdges : a.sourceEdges; f.next();) g = f.value.link,\n                        null !== g && (c ? (a.setsPortSpot && (g.fromSpot = e), a.setsChildPortSpot && (g.toSpot = d)) : (a.setsPortSpot && (g.fromSpot = d), a.setsChildPortSpot && (g.toSpot = e)))\n            }\n        } else if (c = It(a), this.$c === $s)\n            for (e = a.destinationEdges; e.next();) {\n                if (d = e.value.link, null !== d) {\n                    if (a.setsPortSpot)\n                        if (a.portSpot.Mb()) switch (c) {\n                            case 0:\n                                d.fromSpot = fd;\n                                break;\n                            case 90:\n                                d.fromSpot = gd;\n                                break;\n                            case 180:\n                                d.fromSpot = ed;\n                                break;\n                            default:\n                                d.fromSpot = dd\n                        } else d.fromSpot = a.portSpot;\n                    if (a.setsChildPortSpot)\n                        if (a.childPortSpot.Mb()) switch (c) {\n                            case 0:\n                                d.toSpot = ed;\n                                break;\n                            case 90:\n                                d.toSpot = dd;\n                                break;\n                            case 180:\n                                d.toSpot = fd;\n                                break;\n                            default:\n                                d.toSpot = gd\n                        } else d.toSpot = a.childPortSpot\n                }\n            } else\n                for (e = a.sourceEdges; e.next();)\n                    if (d = e.value.link, null !== d) {\n                        if (a.setsPortSpot)\n                            if (a.portSpot.Mb()) switch (c) {\n                                case 0:\n                                    d.toSpot = fd;\n                                    break;\n                                case 90:\n                                    d.toSpot = gd;\n                                    break;\n                                case 180:\n                                    d.toSpot = ed;\n                                    break;\n                                default:\n                                    d.toSpot = dd\n                            } else d.toSpot = a.portSpot;\n                        if (a.setsChildPortSpot)\n                            if (a.childPortSpot.Mb()) switch (c) {\n                                case 0:\n                                    d.fromSpot = ed;\n                                    break;\n                                case 90:\n                                    d.fromSpot = dd;\n                                    break;\n                                case 180:\n                                    d.fromSpot = fd;\n                                    break;\n                                default:\n                                    d.fromSpot = gd\n                            } else d.fromSpot =\n                                a.childPortSpot\n                    }\n    };\n\n    function It(a) {\n        a = a.angle;\n        return 45 >= a ? 0 : 135 >= a ? 90 : 225 >= a ? 180 : 315 >= a ? 270 : 0\n    }\n\n    function Kt(a) {\n        var b = It(a);\n        b = 90 === b || 270 === b;\n        var c = a.layerSpacing;\n        if (0 < a.layerSpacingParentOverlap) {\n            var d = Math.min(1, a.layerSpacingParentOverlap);\n            c -= b ? a.height * d : a.width * d\n        }\n        c < (b ? -a.height : -a.width) && (c = b ? -a.height : -a.width);\n        return c\n    }\n\n    function Qt(a) {\n        var b = It(a),\n            c = a.nodeIndent;\n        if (0 < a.nodeIndentPastParent) {\n            var d = Math.min(1, a.nodeIndentPastParent);\n            c += 90 === b || 270 === b ? a.width * d : a.height * d\n        }\n        return c = Math.max(0, c)\n    }\n    ma.Object.defineProperties(Ys.prototype, {\n        roots: {\n            get: function () {\n                return this.Hb\n            },\n            set: function (a) {\n                this.Hb !== a && (this.Hb = a, this.C())\n            }\n        },\n        path: {\n            get: function () {\n                return this.ap\n            },\n            set: function (a) {\n                this.ap !== a && (this.ap = a, this.C())\n            }\n        },\n        treeStyle: {\n            get: function () {\n                return this.Xp\n            },\n            set: function (a) {\n                this.Ab === a || a !== at && a !== tt && a !== ut && a !== st || (this.Xp = a, this.C())\n            }\n        },\n        layerStyle: {\n            get: function () {\n                return this.Yr\n            },\n            set: function (a) {\n                this.Ab === a || a !== bt && a !== ot && a !== nt || (this.Yr = a, this.C())\n            }\n        },\n        comments: {\n            get: function () {\n                return this.Zc\n            },\n            set: function (a) {\n                this.Zc !== a && (this.Zc = a, this.C())\n            }\n        },\n        arrangement: {\n            get: function () {\n                return this.Ab\n            },\n            set: function (a) {\n                this.Ab === a || a !== ct && a !== iu && a !== ft || (this.Ab = a, this.C())\n            }\n        },\n        arrangementSpacing: {\n            get: function () {\n                return this.zd\n            },\n            set: function (a) {\n                this.zd.w(a) || (this.zd.assign(a), this.C())\n            }\n        },\n        rootDefaults: {\n            get: function () {\n                return this.T\n            },\n            set: function (a) {\n                this.T !== a && (this.T = a, this.C())\n            }\n        },\n        alternateDefaults: {\n            get: function () {\n                return this.U\n            },\n            set: function (a) {\n                this.U !== a && (this.U = a, this.C())\n            }\n        },\n        sorting: {\n            get: function () {\n                return this.T.sorting\n            },\n            set: function (a) {\n                this.T.sorting === a || a !== vt && a !== wt && a !== xt && !yt || (this.T.sorting = a, this.C())\n            }\n        },\n        comparer: {\n            get: function () {\n                return this.T.comparer\n            },\n            set: function (a) {\n                this.T.comparer !==\n                    a && (this.T.comparer = a, this.C())\n            }\n        },\n        angle: {\n            get: function () {\n                return this.T.angle\n            },\n            set: function (a) {\n                this.T.angle !== a && (0 === a || 90 === a || 180 === a || 270 === a ? (this.T.angle = a, this.C()) : B(\"TreeLayout.angle must be 0, 90, 180, or 270\"))\n            }\n        },\n        alignment: {\n            get: function () {\n                return this.T.alignment\n            },\n            set: function (a) {\n                this.T.alignment !== a && (this.T.alignment = a, this.C())\n            }\n        },\n        nodeIndent: {\n            get: function () {\n                return this.T.nodeIndent\n            },\n            set: function (a) {\n                this.T.nodeIndent !==\n                    a && 0 <= a && (this.T.nodeIndent = a, this.C())\n            }\n        },\n        nodeIndentPastParent: {\n            get: function () {\n                return this.T.nodeIndentPastParent\n            },\n            set: function (a) {\n                this.T.nodeIndentPastParent !== a && 0 <= a && 1 >= a && (this.T.nodeIndentPastParent = a, this.C())\n            }\n        },\n        nodeSpacing: {\n            get: function () {\n                return this.T.nodeSpacing\n            },\n            set: function (a) {\n                this.T.nodeSpacing !== a && (this.T.nodeSpacing = a, this.C())\n            }\n        },\n        layerSpacing: {\n            get: function () {\n                return this.T.layerSpacing\n            },\n            set: function (a) {\n                this.T.layerSpacing !==\n                    a && (this.T.layerSpacing = a, this.C())\n            }\n        },\n        layerSpacingParentOverlap: {\n            get: function () {\n                return this.T.layerSpacingParentOverlap\n            },\n            set: function (a) {\n                this.T.layerSpacingParentOverlap !== a && 0 <= a && 1 >= a && (this.T.layerSpacingParentOverlap = a, this.C())\n            }\n        },\n        compaction: {\n            get: function () {\n                return this.T.compaction\n            },\n            set: function (a) {\n                this.T.compaction === a || a !== Ft && a !== Ht || (this.T.compaction = a, this.C())\n            }\n        },\n        breadthLimit: {\n            get: function () {\n                return this.T.breadthLimit\n            },\n            set: function (a) {\n                this.T.breadthLimit !== a && 0 <= a && (this.T.breadthLimit = a, this.C())\n            }\n        },\n        rowSpacing: {\n            get: function () {\n                return this.T.rowSpacing\n            },\n            set: function (a) {\n                this.T.rowSpacing !== a && (this.T.rowSpacing = a, this.C())\n            }\n        },\n        rowIndent: {\n            get: function () {\n                return this.T.rowIndent\n            },\n            set: function (a) {\n                this.T.rowIndent !== a && 0 <= a && (this.T.rowIndent = a, this.C())\n            }\n        },\n        commentSpacing: {\n            get: function () {\n                return this.T.commentSpacing\n            },\n            set: function (a) {\n                this.T.commentSpacing !==\n                    a && (this.T.commentSpacing = a, this.C())\n            }\n        },\n        commentMargin: {\n            get: function () {\n                return this.T.commentMargin\n            },\n            set: function (a) {\n                this.T.commentMargin !== a && (this.T.commentMargin = a, this.C())\n            }\n        },\n        setsPortSpot: {\n            get: function () {\n                return this.T.setsPortSpot\n            },\n            set: function (a) {\n                this.T.setsPortSpot !== a && (this.T.setsPortSpot = a, this.C())\n            }\n        },\n        portSpot: {\n            get: function () {\n                return this.T.portSpot\n            },\n            set: function (a) {\n                this.T.portSpot.w(a) || (this.T.portSpot =\n                    a, this.C())\n            }\n        },\n        setsChildPortSpot: {\n            get: function () {\n                return this.T.setsChildPortSpot\n            },\n            set: function (a) {\n                this.T.setsChildPortSpot !== a && (this.T.setsChildPortSpot = a, this.C())\n            }\n        },\n        childPortSpot: {\n            get: function () {\n                return this.T.childPortSpot\n            },\n            set: function (a) {\n                this.T.childPortSpot.w(a) || (this.T.childPortSpot = a, this.C())\n            }\n        },\n        alternateSorting: {\n            get: function () {\n                return this.U.sorting\n            },\n            set: function (a) {\n                this.U.sorting === a || a !== vt && a !== wt &&\n                    a !== xt && !yt || (this.U.sorting = a, this.C())\n            }\n        },\n        alternateComparer: {\n            get: function () {\n                return this.U.comparer\n            },\n            set: function (a) {\n                this.U.comparer !== a && (this.U.comparer = a, this.C())\n            }\n        },\n        alternateAngle: {\n            get: function () {\n                return this.U.angle\n            },\n            set: function (a) {\n                this.U.angle === a || 0 !== a && 90 !== a && 180 !== a && 270 !== a || (this.U.angle = a, this.C())\n            }\n        },\n        alternateAlignment: {\n            get: function () {\n                return this.U.alignment\n            },\n            set: function (a) {\n                this.U.alignment !==\n                    a && (this.U.alignment = a, this.C())\n            }\n        },\n        alternateNodeIndent: {\n            get: function () {\n                return this.U.nodeIndent\n            },\n            set: function (a) {\n                this.U.nodeIndent !== a && 0 <= a && (this.U.nodeIndent = a, this.C())\n            }\n        },\n        alternateNodeIndentPastParent: {\n            get: function () {\n                return this.U.nodeIndentPastParent\n            },\n            set: function (a) {\n                this.U.nodeIndentPastParent !== a && 0 <= a && 1 >= a && (this.U.nodeIndentPastParent = a, this.C())\n            }\n        },\n        alternateNodeSpacing: {\n            get: function () {\n                return this.U.nodeSpacing\n            },\n            set: function (a) {\n                this.U.nodeSpacing !== a && (this.U.nodeSpacing = a, this.C())\n            }\n        },\n        alternateLayerSpacing: {\n            get: function () {\n                return this.U.layerSpacing\n            },\n            set: function (a) {\n                this.U.layerSpacing !== a && (this.U.layerSpacing = a, this.C())\n            }\n        },\n        alternateLayerSpacingParentOverlap: {\n            get: function () {\n                return this.U.layerSpacingParentOverlap\n            },\n            set: function (a) {\n                this.U.layerSpacingParentOverlap !== a && 0 <= a && 1 >= a && (this.U.layerSpacingParentOverlap = a, this.C())\n            }\n        },\n        alternateCompaction: {\n            get: function () {\n                return this.U.compaction\n            },\n            set: function (a) {\n                this.U.compaction === a || a !== Ft && a !== Ht || (this.U.compaction = a, this.C())\n            }\n        },\n        alternateBreadthLimit: {\n            get: function () {\n                return this.U.breadthLimit\n            },\n            set: function (a) {\n                this.U.breadthLimit !== a && 0 <= a && (this.U.breadthLimit = a, this.C())\n            }\n        },\n        alternateRowSpacing: {\n            get: function () {\n                return this.U.rowSpacing\n            },\n            set: function (a) {\n                this.U.rowSpacing !== a && (this.U.rowSpacing = a, this.C())\n            }\n        },\n        alternateRowIndent: {\n            get: function () {\n                return this.U.rowIndent\n            },\n            set: function (a) {\n                this.U.rowIndent !== a && 0 <= a && (this.U.rowIndent = a, this.C())\n            }\n        },\n        alternateCommentSpacing: {\n            get: function () {\n                return this.U.commentSpacing\n            },\n            set: function (a) {\n                this.U.commentSpacing !== a && (this.U.commentSpacing = a, this.C())\n            }\n        },\n        alternateCommentMargin: {\n            get: function () {\n                return this.U.commentMargin\n            },\n            set: function (a) {\n                this.U.commentMargin !== a && (this.U.commentMargin = a, this.C())\n            }\n        },\n        alternateSetsPortSpot: {\n            get: function () {\n                return this.U.setsPortSpot\n            },\n            set: function (a) {\n                this.U.setsPortSpot !== a && (this.U.setsPortSpot = a, this.C())\n            }\n        },\n        alternatePortSpot: {\n            get: function () {\n                return this.U.portSpot\n            },\n            set: function (a) {\n                this.U.portSpot.w(a) || (this.U.portSpot = a, this.C())\n            }\n        },\n        alternateSetsChildPortSpot: {\n            get: function () {\n                return this.U.setsChildPortSpot\n            },\n            set: function (a) {\n                this.U.setsChildPortSpot !== a && (this.U.setsChildPortSpot = a, this.C())\n            }\n        },\n        alternateChildPortSpot: {\n            get: function () {\n                return this.U.childPortSpot\n            },\n            set: function (a) {\n                this.U.childPortSpot.w(a) || (this.U.childPortSpot = a, this.C())\n            }\n        }\n    });\n    var Zs = new D(Ys, \"PathDefault\", -1),\n        $s = new D(Ys, \"PathDestination\", 0),\n        gt = new D(Ys, \"PathSource\", 1),\n        vt = new D(Ys, \"SortingForwards\", 10),\n        wt = new D(Ys, \"SortingReverse\", 11),\n        xt = new D(Ys, \"SortingAscending\", 12),\n        yt = new D(Ys, \"SortingDescending\", 13),\n        $t = new D(Ys, \"AlignmentCenterSubtrees\", 20),\n        au = new D(Ys, \"AlignmentCenterChildren\", 21),\n        Rt = new D(Ys, \"AlignmentStart\", 22),\n        Jt = new D(Ys, \"AlignmentEnd\", 23),\n        At = new D(Ys, \"AlignmentBus\", 24),\n        qt = new D(Ys, \"AlignmentBusBranching\", 25),\n        Bt = new D(Ys, \"AlignmentTopLeftBus\", 26),\n        Ct = new D(Ys,\n            \"AlignmentBottomRightBus\", 27),\n        Ft = new D(Ys, \"CompactionNone\", 30),\n        Ht = new D(Ys, \"CompactionBlock\", 31),\n        at = new D(Ys, \"StyleLayered\", 40),\n        ut = new D(Ys, \"StyleLastParents\", 41),\n        tt = new D(Ys, \"StyleAlternating\", 42),\n        st = new D(Ys, \"StyleRootOnly\", 43),\n        ct = new D(Ys, \"ArrangementVertical\", 50),\n        iu = new D(Ys, \"ArrangementHorizontal\", 51),\n        ft = new D(Ys, \"ArrangementFixedRoots\", 52),\n        bt = new D(Ys, \"LayerIndividual\", 60),\n        ot = new D(Ys, \"LayerSiblings\", 61),\n        nt = new D(Ys, \"LayerUniform\", 62);\n    Ys.className = \"TreeLayout\";\n    Ys.PathDefault = Zs;\n    Ys.PathDestination = $s;\n    Ys.PathSource = gt;\n    Ys.SortingForwards = vt;\n    Ys.SortingReverse = wt;\n    Ys.SortingAscending = xt;\n    Ys.SortingDescending = yt;\n    Ys.AlignmentCenterSubtrees = $t;\n    Ys.AlignmentCenterChildren = au;\n    Ys.AlignmentStart = Rt;\n    Ys.AlignmentEnd = Jt;\n    Ys.AlignmentBus = At;\n    Ys.AlignmentBusBranching = qt;\n    Ys.AlignmentTopLeftBus = Bt;\n    Ys.AlignmentBottomRightBus = Ct;\n    Ys.CompactionNone = Ft;\n    Ys.CompactionBlock = Ht;\n    Ys.StyleLayered = at;\n    Ys.StyleLastParents = ut;\n    Ys.StyleAlternating = tt;\n    Ys.StyleRootOnly = st;\n    Ys.ArrangementVertical = ct;\n    Ys.ArrangementHorizontal = iu;\n    Ys.ArrangementFixedRoots = ft;\n    Ys.LayerIndividual = bt;\n    Ys.LayerSiblings = ot;\n    Ys.LayerUniform = nt;\n\n    function dt(a) {\n        Qp.call(this, a)\n    }\n    la(dt, Qp);\n    dt.prototype.createVertex = function () {\n        return new et(this)\n    };\n    dt.prototype.createEdge = function () {\n        return new ku(this)\n    };\n    dt.className = \"TreeNetwork\";\n\n    function et(a) {\n        Tp.call(this, a);\n        this.Ha = !1;\n        this.Ic = null;\n        this.I = [];\n        this.jd = this.Za = this.Y = this.Ia = 0;\n        this.Zc = null;\n        this.S = new I(0, 0);\n        this.ta = new M(0, 0);\n        this.da = new I(0, 0);\n        this.Gm = this.Fm = this.rA = !1;\n        this.Iq = this.vq = null;\n        this.Qc = vt;\n        this.Kc = $p;\n        this.Yb = 0;\n        this.vb = au;\n        this.ks = this.js = 0;\n        this.ls = 20;\n        this.me = 50;\n        this.Xr = 0;\n        this.jr = Ht;\n        this.br = 0;\n        this.ys = 25;\n        this.ir = this.xs = 10;\n        this.hr = 20;\n        this.Ks = !0;\n        this.us = Zc;\n        this.Js = !0;\n        this.er = Zc\n    }\n    la(et, Tp);\n    et.prototype.copyInheritedPropertiesFrom = function (a) {\n        null !== a && (this.Qc = a.sorting, this.Kc = a.comparer, this.Yb = a.angle, this.vb = a.alignment, this.js = a.nodeIndent, this.ks = a.nodeIndentPastParent, this.ls = a.nodeSpacing, this.me = a.layerSpacing, this.Xr = a.layerSpacingParentOverlap, this.jr = a.compaction, this.br = a.breadthLimit, this.ys = a.rowSpacing, this.xs = a.rowIndent, this.ir = a.commentSpacing, this.hr = a.commentMargin, this.Ks = a.setsPortSpot, this.us = a.portSpot, this.Js = a.setsChildPortSpot, this.er = a.childPortSpot)\n    };\n    ma.Object.defineProperties(et.prototype, {\n        initialized: {\n            get: function () {\n                return this.Ha\n            },\n            set: function (a) {\n                this.Ha !== a && (this.Ha = a)\n            }\n        },\n        parent: {\n            get: function () {\n                return this.Ic\n            },\n            set: function (a) {\n                this.Ic !== a && (this.Ic = a)\n            }\n        },\n        children: {\n            get: function () {\n                return this.I\n            },\n            set: function (a) {\n                if (this.I !== a) {\n                    if (null !== a)\n                        for (var b = a.length, c = 0; c < b; c++);\n                    this.I = a\n                }\n            }\n        },\n        level: {\n            get: function () {\n                return this.Ia\n            },\n            set: function (a) {\n                this.Ia !==\n                    a && (this.Ia = a)\n            }\n        },\n        descendantCount: {\n            get: function () {\n                return this.Y\n            },\n            set: function (a) {\n                this.Y !== a && (this.Y = a)\n            }\n        },\n        maxChildrenCount: {\n            get: function () {\n                return this.Za\n            },\n            set: function (a) {\n                this.Za !== a && (this.Za = a)\n            }\n        },\n        maxGenerationCount: {\n            get: function () {\n                return this.jd\n            },\n            set: function (a) {\n                this.jd !== a && (this.jd = a)\n            }\n        },\n        comments: {\n            get: function () {\n                return this.Zc\n            },\n            set: function (a) {\n                if (this.Zc !== a) {\n                    if (null !== a)\n                        for (var b =\n                                a.length, c = 0; c < b; c++);\n                    this.Zc = a\n                }\n            }\n        },\n        sorting: {\n            get: function () {\n                return this.Qc\n            },\n            set: function (a) {\n                this.Qc !== a && (this.Qc = a)\n            }\n        },\n        comparer: {\n            get: function () {\n                return this.Kc\n            },\n            set: function (a) {\n                this.Kc !== a && (this.Kc = a)\n            }\n        },\n        angle: {\n            get: function () {\n                return this.Yb\n            },\n            set: function (a) {\n                this.Yb !== a && (this.Yb = a)\n            }\n        },\n        alignment: {\n            get: function () {\n                return this.vb\n            },\n            set: function (a) {\n                this.vb !== a && (this.vb = a)\n            }\n        },\n        nodeIndent: {\n            get: function () {\n                return this.js\n            },\n            set: function (a) {\n                this.js !== a && (this.js = a)\n            }\n        },\n        nodeIndentPastParent: {\n            get: function () {\n                return this.ks\n            },\n            set: function (a) {\n                this.ks !== a && (this.ks = a)\n            }\n        },\n        nodeSpacing: {\n            get: function () {\n                return this.ls\n            },\n            set: function (a) {\n                this.ls !== a && (this.ls = a)\n            }\n        },\n        layerSpacing: {\n            get: function () {\n                return this.me\n            },\n            set: function (a) {\n                this.me !== a && (this.me = a)\n            }\n        },\n        layerSpacingParentOverlap: {\n            get: function () {\n                return this.Xr\n            },\n            set: function (a) {\n                this.Xr !== a && (this.Xr = a)\n            }\n        },\n        compaction: {\n            get: function () {\n                return this.jr\n            },\n            set: function (a) {\n                this.jr !== a && (this.jr = a)\n            }\n        },\n        breadthLimit: {\n            get: function () {\n                return this.br\n            },\n            set: function (a) {\n                this.br !== a && (this.br = a)\n            }\n        },\n        rowSpacing: {\n            get: function () {\n                return this.ys\n            },\n            set: function (a) {\n                this.ys !== a && (this.ys = a)\n            }\n        },\n        rowIndent: {\n            get: function () {\n                return this.xs\n            },\n            set: function (a) {\n                this.xs !==\n                    a && (this.xs = a)\n            }\n        },\n        commentSpacing: {\n            get: function () {\n                return this.ir\n            },\n            set: function (a) {\n                this.ir !== a && (this.ir = a)\n            }\n        },\n        commentMargin: {\n            get: function () {\n                return this.hr\n            },\n            set: function (a) {\n                this.hr !== a && (this.hr = a)\n            }\n        },\n        setsPortSpot: {\n            get: function () {\n                return this.Ks\n            },\n            set: function (a) {\n                this.Ks !== a && (this.Ks = a)\n            }\n        },\n        portSpot: {\n            get: function () {\n                return this.us\n            },\n            set: function (a) {\n                this.us.w(a) || (this.us = a)\n            }\n        },\n        setsChildPortSpot: {\n            get: function () {\n                return this.Js\n            },\n            set: function (a) {\n                this.Js !== a && (this.Js = a)\n            }\n        },\n        childPortSpot: {\n            get: function () {\n                return this.er\n            },\n            set: function (a) {\n                this.er.w(a) || (this.er = a)\n            }\n        },\n        childrenCount: {\n            get: function () {\n                return this.children.length\n            }\n        },\n        relativePosition: {\n            get: function () {\n                return this.S\n            },\n            set: function (a) {\n                this.S.set(a)\n            }\n        },\n        subtreeSize: {\n            get: function () {\n                return this.ta\n            },\n            set: function (a) {\n                this.ta.set(a)\n            }\n        },\n        subtreeOffset: {\n            get: function () {\n                return this.da\n            },\n            set: function (a) {\n                this.da.set(a)\n            }\n        }\n    });\n    et.className = \"TreeVertex\";\n\n    function ku(a) {\n        Up.call(this, a);\n        this.Ju = new I(0, 0)\n    }\n    la(ku, Up);\n    ku.prototype.commit = function () {\n        var a = this.link;\n        if (null !== a && !a.isAvoiding) {\n            var b = this.network.layout,\n                c = null,\n                d = null;\n            switch (b.$c) {\n                case $s:\n                    c = this.fromVertex;\n                    d = this.toVertex;\n                    break;\n                case gt:\n                    c = this.toVertex;\n                    d = this.fromVertex;\n                    break;\n                default:\n                    B(\"Unhandled path value \" + b.$c.toString())\n            }\n            if (null !== c && null !== d)\n                if (b = this.Ju, 0 !== b.x || 0 !== b.y || c.rA) {\n                    d = c.bounds;\n                    var e = It(c),\n                        f = Kt(c),\n                        g = c.rowSpacing;\n                    a.hj();\n                    var h = a.curve === qg,\n                        k = a.isOrthogonal,\n                        l;\n                    a.Nh();\n                    if (k || h) {\n                        for (l = 2; 4 < a.pointsCount;) a.Xv(2);\n                        var m = a.i(1);\n                        var n = a.i(2)\n                    } else {\n                        for (l =\n                            1; 3 < a.pointsCount;) a.Xv(1);\n                        m = a.i(0);\n                        n = a.i(a.pointsCount - 1)\n                    }\n                    var p = a.i(a.pointsCount - 1);\n                    0 === e ? (c.alignment === Jt ? (e = d.bottom + b.y, 0 === b.y && m.y > p.y + c.rowIndent && (e = Math.min(e, Math.max(m.y, e - Qt(c))))) : c.alignment === Rt ? (e = d.top + b.y, 0 === b.y && m.y < p.y - c.rowIndent && (e = Math.max(e, Math.min(m.y, e + Qt(c))))) : e = c.Fm || c.Gm && 1 === c.maxGenerationCount ? d.top - c.da.y + b.y : d.y + d.height / 2 + b.y, h ? (a.m(l, m.x, e), l++, a.m(l, d.right + f, e), l++, a.m(l, d.right + f + (b.x - g) / 3, e), l++, a.m(l, d.right + f + 2 * (b.x - g) / 3, e), l++, a.m(l, d.right + f + (b.x -\n                        g), e), l++, a.m(l, n.x, e)) : (k && (a.m(l, d.right + f / 2, m.y), l++), a.m(l, d.right + f / 2, e), l++, a.m(l, d.right + f + b.x - (k ? g / 2 : g), e), l++, k && a.m(l, a.i(l - 1).x, n.y))) : 90 === e ? (c.alignment === Jt ? (e = d.right + b.x, 0 === b.x && m.x > p.x + c.rowIndent && (e = Math.min(e, Math.max(m.x, e - Qt(c))))) : c.alignment === Rt ? (e = d.left + b.x, 0 === b.x && m.x < p.x - c.rowIndent && (e = Math.max(e, Math.min(m.x, e + Qt(c))))) : e = c.Fm || c.Gm && 1 === c.maxGenerationCount ? d.left - c.da.x + b.x : d.x + d.width / 2 + b.x, h ? (a.m(l, e, m.y), l++, a.m(l, e, d.bottom + f), l++, a.m(l, e, d.bottom + f + (b.y - g) /\n                        3), l++, a.m(l, e, d.bottom + f + 2 * (b.y - g) / 3), l++, a.m(l, e, d.bottom + f + (b.y - g)), l++, a.m(l, e, n.y)) : (k && (a.m(l, m.x, d.bottom + f / 2), l++), a.m(l, e, d.bottom + f / 2), l++, a.m(l, e, d.bottom + f + b.y - (k ? g / 2 : g)), l++, k && a.m(l, n.x, a.i(l - 1).y))) : 180 === e ? (c.alignment === Jt ? (e = d.bottom + b.y, 0 === b.y && m.y > p.y + c.rowIndent && (e = Math.min(e, Math.max(m.y, e - Qt(c))))) : c.alignment === Rt ? (e = d.top + b.y, 0 === b.y && m.y < p.y - c.rowIndent && (e = Math.max(e, Math.min(m.y, e + Qt(c))))) : e = c.Fm || c.Gm && 1 === c.maxGenerationCount ? d.top - c.da.y + b.y : d.y + d.height / 2 + b.y, h ?\n                        (a.m(l, m.x, e), l++, a.m(l, d.left - f, e), l++, a.m(l, d.left - f + (b.x + g) / 3, e), l++, a.m(l, d.left - f + 2 * (b.x + g) / 3, e), l++, a.m(l, d.left - f + (b.x + g), e), l++, a.m(l, n.x, e)) : (k && (a.m(l, d.left - f / 2, m.y), l++), a.m(l, d.left - f / 2, e), l++, a.m(l, d.left - f + b.x + (k ? g / 2 : g), e), l++, k && a.m(l, a.i(l - 1).x, n.y))) : 270 === e ? (c.alignment === Jt ? (e = d.right + b.x, 0 === b.x && m.x > p.x + c.rowIndent && (e = Math.min(e, Math.max(m.x, e - Qt(c))))) : c.alignment === Rt ? (e = d.left + b.x, 0 === b.x && m.x < p.x - c.rowIndent && (e = Math.max(e, Math.min(m.x, e + Qt(c))))) : e = c.Fm || c.Gm && 1 === c.maxGenerationCount ?\n                        d.left - c.da.x + b.x : d.x + d.width / 2 + b.x, h ? (a.m(l, e, m.y), l++, a.m(l, e, d.top - f), l++, a.m(l, e, d.top - f + (b.y + g) / 3), l++, a.m(l, e, d.top - f + 2 * (b.y + g) / 3), l++, a.m(l, e, d.top - f + (b.y + g)), l++, a.m(l, e, n.y)) : (k && (a.m(l, m.x, d.top - f / 2), l++), a.m(l, e, d.top - f / 2), l++, a.m(l, e, d.top - f + b.y + (k ? g / 2 : g)), l++, k && a.m(l, n.x, a.i(l - 1).y))) : B(\"Invalid angle \" + e);\n                    a.rf()\n                } else a = this.link, f = It(c), f !== It(d) && (g = Kt(c), h = c.bounds, c = d.bounds, 0 === f && c.left - h.right < g + 1 || 90 === f && c.top - h.bottom < g + 1 || 180 === f && h.left - c.right < g + 1 || 270 === f && h.top - c.bottom <\n                    g + 1 || (a.hj(), c = a.curve === qg, b = a.isOrthogonal, d = zt(this.fromVertex.alignment), a.Nh(), 0 === f ? (f = h.right + g / 2, c ? 4 === a.pointsCount && (c = a.i(3).y, a.K(1, f - 20, a.i(1).y), a.m(2, f - 20, c), a.m(3, f, c), a.m(4, f + 20, c), a.K(5, a.i(5).x, c)) : b ? d ? a.K(3, a.i(2).x, a.i(4).y) : 6 === a.pointsCount && (a.K(2, f, a.i(2).y), a.K(3, f, a.i(3).y)) : 4 === a.pointsCount ? a.m(2, f, a.i(2).y) : 3 === a.pointsCount ? a.K(1, f, a.i(2).y) : 2 === a.pointsCount && a.m(1, f, a.i(1).y)) : 90 === f ? (f = h.bottom + g / 2, c ? 4 === a.pointsCount && (c = a.i(3).x, a.K(1, a.i(1).x, f - 20), a.m(2, c, f - 20),\n                        a.m(3, c, f), a.m(4, c, f + 20), a.K(5, c, a.i(5).y)) : b ? d ? a.K(3, a.i(2).x, a.i(4).y) : 6 === a.pointsCount && (a.K(2, a.i(2).x, f), a.K(3, a.i(3).x, f)) : 4 === a.pointsCount ? a.m(2, a.i(2).x, f) : 3 === a.pointsCount ? a.K(1, a.i(2).x, f) : 2 === a.pointsCount && a.m(1, a.i(1).x, f)) : 180 === f ? (f = h.left - g / 2, c ? 4 === a.pointsCount && (c = a.i(3).y, a.K(1, f + 20, a.i(1).y), a.m(2, f + 20, c), a.m(3, f, c), a.m(4, f - 20, c), a.K(5, a.i(5).x, c)) : b ? d ? a.K(3, a.i(2).x, a.i(4).y) : 6 === a.pointsCount && (a.K(2, f, a.i(2).y), a.K(3, f, a.i(3).y)) : 4 === a.pointsCount ? a.m(2, f, a.i(2).y) : 3 === a.pointsCount ?\n                        a.K(1, f, a.i(2).y) : 2 === a.pointsCount && a.m(1, f, a.i(1).y)) : 270 === f && (f = h.top - g / 2, c ? 4 === a.pointsCount && (c = a.i(3).x, a.K(1, a.i(1).x, f + 20), a.m(2, c, f + 20), a.m(3, c, f), a.m(4, c, f - 20), a.K(5, c, a.i(5).y)) : b ? d ? a.K(3, a.i(2).x, a.i(4).y) : 6 === a.pointsCount && (a.K(2, a.i(2).x, f), a.K(3, a.i(3).x, f)) : 4 === a.pointsCount ? a.m(2, a.i(2).x, f) : 3 === a.pointsCount ? a.K(1, a.i(2).x, f) : 2 === a.pointsCount && a.m(1, a.i(1).x, f)), a.rf()))\n        }\n    };\n    ma.Object.defineProperties(ku.prototype, {\n        relativePoint: {\n            get: function () {\n                return this.Ju\n            },\n            set: function (a) {\n                this.Ju.set(a)\n            }\n        }\n    });\n    ku.className = \"TreeEdge\";\n    Oa.prototype.initializeStandardTools = function () {\n        this.Va(\"Action\", new Eg, this.mouseDownTools);\n        this.Va(\"Relinking\", new Xe, this.mouseDownTools);\n        this.Va(\"LinkReshaping\", new cg, this.mouseDownTools);\n        this.Va(\"Rotating\", new Cg, this.mouseDownTools);\n        this.Va(\"Resizing\", new vg, this.mouseDownTools);\n        this.Va(\"Linking\", new Wf, this.mouseMoveTools);\n        this.Va(\"Dragging\", new Qe, this.mouseMoveTools);\n        this.Va(\"DragSelecting\", new Hg, this.mouseMoveTools);\n        this.Va(\"Panning\", new Ig, this.mouseMoveTools);\n        this.Va(\"ContextMenu\", new Kg,\n            this.mouseUpTools);\n        this.Va(\"TextEditing\", new Vg, this.mouseUpTools);\n        this.Va(\"ClickCreating\", new Fg, this.mouseUpTools);\n        this.Va(\"ClickSelecting\", new Dg, this.mouseUpTools)\n    };\n    An(\"Horizontal\", new xm);\n    An(\"Spot\", new zm);\n    An(\"Table\", new Dm);\n    An(\"Viewbox\", new Im);\n    An(\"TableRow\", new Gm);\n    An(\"TableColumn\", new Hm);\n    An(\"Graduated\", new Sm);\n    An(\"Grid\", new Jm);\n    qi.add(br.type, sq);\n    qi.add(fr.type, Gq);\n    var lu = x.go,\n        mu = {\n            get licenseKey() {\n                return R.licenseKey\n            },\n            set licenseKey(a) {\n                R.licenseKey = a\n            },\n            get version() {\n                return R.version\n            },\n            Group: T,\n            EnumValue: D,\n            List: E,\n            Set: F,\n            Map: H,\n            Point: I,\n            Size: M,\n            Rect: N,\n            Margin: oc,\n            Spot: P,\n            Geometry: td,\n            PathFigure: ke,\n            PathSegment: le,\n            InputEvent: ne,\n            DiagramEvent: pe,\n            ChangedEvent: qe,\n            Model: Z,\n            GraphLinksModel: br,\n            TreeModel: fr,\n            Binding: Ji,\n            Transaction: ve,\n            UndoManager: we,\n            CommandHandler: Rk,\n            Tool: ye,\n            DraggingTool: Qe,\n            DraggingInfo: df,\n            LinkingBaseTool: Kf,\n            LinkingTool: Wf,\n            RelinkingTool: Xe,\n            LinkReshapingTool: cg,\n            ResizingTool: vg,\n            RotatingTool: Cg,\n            ClickSelectingTool: Dg,\n            ActionTool: Eg,\n            ClickCreatingTool: Fg,\n            HTMLInfo: Oe,\n            ContextMenuTool: Kg,\n            DragSelectingTool: Hg,\n            PanningTool: Ig,\n            TextEditingTool: Vg,\n            ToolManager: Oa,\n            Animation: yh,\n            AnimationManager: uh,\n            AnimationTrigger: $h,\n            Layer: ei,\n            Diagram: R,\n            Palette: Jk,\n            Overview: Mk,\n            Brush: tl,\n            GraphObject: Y,\n            Panel: X,\n            RowColumnDefinition: Rj,\n            Shape: Lf,\n            TextBlock: Wg,\n            TextBlockMetrics: jo,\n            Picture: kk,\n            Part: U,\n            Adornment: Je,\n            Node: W,\n            Link: S,\n            Placeholder: xg,\n            Layout: Ci,\n            LayoutNetwork: Qp,\n            LayoutVertex: Tp,\n            LayoutEdge: Up,\n            GridLayout: Lk,\n            PanelLayout: Ol,\n            CircularLayout: gr,\n            CircularNetwork: yr,\n            CircularVertex: Lr,\n            CircularEdge: Mr,\n            ForceDirectedLayout: Nr,\n            ForceDirectedNetwork: Or,\n            ForceDirectedVertex: $r,\n            ForceDirectedEdge: as,\n            LayeredDigraphLayout: bs,\n            LayeredDigraphNetwork: gs,\n            LayeredDigraphVertex: Ws,\n            LayeredDigraphEdge: Xs,\n            TreeLayout: Ys,\n            TreeNetwork: dt,\n            TreeVertex: et,\n            TreeEdge: ku\n        };\n    lu && lu.version !== mu.version && B(\"WARNING: a `go` object on the root object is already defined with a version mismatch.\" + lu.version + \". Replaced with version: \" + mu.version);\n    x.go = mu;\n    (\"undefined\" === typeof x || \"undefined\" === typeof x.module || \"object\" !== typeof x.module.exports) && x.define && \"function\" === typeof x.define && x.define.amd && x.define(mu);\n    'undefined' !== typeof module && 'object' === typeof module.exports && (module.exports = 'undefined' !== typeof global ? global.go : self.go);\n})();"
  },
  {
    "path": "static/js/init.js",
    "content": "// 设置头像\nfunction SetAvatar() {\n    // 头像背景色\n    let bgColor = [ //from  https://www.google.com/design/spec/style/color.html\n        '#F44336', // red 500\n        '#E91E63', // pink 500\n        '#9C27B0', // purple 500,\n        '#673AB7', // deep purple 500\n        '#3F51B5', // indigo 500\n        '#2196F3', // blue 500\n        '#03A9F4', // light blue 500\n        '#00BCD4', // cyan 500\n        '#009688', // teal 500\n        '#4CAF50', // green 500\n        '#8BC34A', // light green 500\n        '#CDDC39', // lime 500\n        '#FFEB3B', // yellow 500\n        '#FFC107', // amber 500\n        '#FF9800', // orange 500\n        '#FF5722', // deep orange 500\n        '#795548', // brown 500\n        '#9E9E9E', // grey 500\n        '#607D8B', // blue grey 500\n    ];\n\n    username = localStorage.getItem(\"username\");\n    let myAvatar = document.getElementById('avatar');\n    let index = Math.floor(Math.random() * bgColor.length);\n    myAvatar.style.backgroundColor = bgColor[index];\n    myAvatar.innerHTML = username.substr(0,1).toLocaleUpperCase();\n}\n\n\n// 获取年份\nfunction GetYear(){\n    let obj = document.getElementById('data_year');\n\n    $.ajax({\n        type : \"GET\",\n        async : false,\n        url : \"../../api/date/year\",\n        data: {},\n        dataType : \"json\",\n        success : function(result) {\n            if(localStorage.getItem('selected_year') == null){\n                localStorage.setItem('selected_year', result.data[0]);\n            }\n\n            // 设置下拉框内容\n            for(let i in result.data) {\n                obj.options.add(new Option(result.data[i], result.data[i]));\n            };\n        },\n    })\n}\n\n\n// 获取季度\nfunction GetQuarter(){\n    let opt = document.getElementById('data_year');\n    let year = opt.options[opt.selectedIndex].value;\n    $.ajax({\n        type : \"GET\",\n        async : false,\n        url : \"../../api/date/quarter\",\n        data: {\n            'year': year\n        },\n        dataType : \"json\",\n        success : function(result) {\n            if(localStorage.getItem('selected_quarter') == null){\n                localStorage.setItem('selected_quarter', result.data[0]);\n            }\n\n            // 设置下拉框内容\n            var obj = document.getElementById('data_quarter');\n            obj.options.length=0;\n            for(let i in result.data) {\n                obj.options.add(new Option(result.data[i], result.data[i]));\n            };\n\n            if (result.data.length == 1){\n                GetMonth();\n            }\n        },\n    })\n}\n\n\n// 获取月份\nfunction GetMonth(){\n    let opt = document.getElementById('data_year');\n    let year = opt.options[opt.selectedIndex].value;\n\n    opt = document.getElementById('data_quarter');\n    let quarter = opt.options[opt.selectedIndex].value;\n\n    $.ajax({\n        type : \"GET\",\n        async : false,\n        url : \"../../api/date/month\",\n        data: {\n            'year': year,\n            'quarter': quarter\n        },\n        dataType : \"json\",\n        success : function(result) {\n            if(localStorage.getItem('selected_month') == null){\n                localStorage.setItem('selected_month', result.data[0]);\n            }\n\n            var obj = document.getElementById('data_month');\n            obj.options.length=0;\n            for(let i in result.data) {\n                obj.options.add(new Option(result.data[i], result.data[i]));\n            };\n\n            if (result.data.length == 1){\n                GetDay();\n            }\n        },\n    })\n}\n\n\n// 获取天\nfunction GetDay(){\n    let opt = document.getElementById('data_year');\n    let year = opt.options[opt.selectedIndex].value;\n\n    opt = document.getElementById('data_quarter');\n    let quarter = opt.options[opt.selectedIndex].value;\n\n    opt = document.getElementById('data_month');\n    let month = opt.options[opt.selectedIndex].value;\n\n    $.ajax({\n        type : \"GET\",\n        async : false,\n        url : \"../../api/date/day\",\n        data: {\n            'year': year,\n            'quarter': quarter,\n            'month': month\n        },\n        dataType : \"json\",\n        success : function(result) {\n            // 若未选择过数据日期，则显示最新日期数据\n            if(localStorage.getItem('selected_day') == null){\n                localStorage.setItem('selected_day', result.data[0]);\n                // 刷新页面\n                history.go(0);\n            }\n\n            var obj = document.getElementById('data_day');\n            obj.options.length=0;\n            for(let i in result.data) {\n                obj.options.add(new Option(result.data[i], result.data[i]));\n            };\n        },\n    })\n}\n\n\n// 监听日期选择事件，根据所选的年/季/月更改下拉框中显示的日期\nfunction ChangeDataDate(){\n    let opt = document.getElementById('data_year');\n    let year = opt.options[opt.selectedIndex].value;\n\n    opt = document.getElementById('data_quarter');\n    let quarter = opt.options[opt.selectedIndex].value;\n\n    opt = document.getElementById('data_month');\n    let month = opt.options[opt.selectedIndex].value;\n\n    opt = document.getElementById('data_day');\n    let day = opt.options[opt.selectedIndex].value;\n\n    localStorage.setItem(\"selected_year\", year);\n    localStorage.setItem(\"selected_quarter\", quarter);\n    localStorage.setItem(\"selected_month\", month);\n    localStorage.setItem(\"selected_day\", day);\n\n    //url = './?year=' + year + '&quarter=' + quarter + '&month=' + month + '&day=' + day;\n    //修改localstorge存放的日期后，刷新页面\n    window.location.reload();\n}\n\n\n// 设置默认显示的日期\nfunction InitSelectedDate(){\n    // 根据用户上一次选择的日期，设置下拉框的默认显示日期\n    var year = localStorage.getItem(\"selected_year\");\n    var quarter = localStorage.getItem(\"selected_quarter\");\n    var month = localStorage.getItem(\"selected_month\");\n    var day = localStorage.getItem(\"selected_day\");\n\n    // 若未有选择过日期，默认显示最新日期\n    if(year||quarter||month||day == null){\n        GetYear();\n        GetQuarter();\n        GetMonth();\n        GetDay();\n    }\n    else{\n        GetYear();\n        let opt = document.getElementById('data_year');\n        for(let i=0;i<opt.length;i++){\n            if(opt[i].value == year){\n                opt[i].selected = true;\n            }\n        }\n    \n        GetQuarter();\n        opt = document.getElementById('data_quarter');\n        for(i=0;i<opt.length;i++){\n            if(opt[i].value == quarter){\n                opt[i].selected = true;\n            }\n        }\n    \n        GetMonth();\n        opt = document.getElementById('data_month');\n        for(i=0;i<opt.length;i++){\n            if(opt[i].value == month){\n                opt[i].selected = true;\n            }\n        }\n    \n        GetDay();\n        opt = document.getElementById('data_day');\n        for(i=0;i<opt.length;i++){\n            if(opt[i].value == day){\n                opt[i].selected = true;\n            }\n        }\n    }\n}\n\nfunction init(){\n    // 设置头像\n    SetAvatar();\n\n    // 设置日期\n    if (document.getElementById('data_year') != null){\n        InitSelectedDate();\n    }\n}\n\n"
  },
  {
    "path": "static/js/jquery/jquery.ba-resize.js",
    "content": "/*!\n * jQuery resize event - v1.1 - 3/14/2010\n * http://benalman.com/projects/jquery-resize-plugin/\n * \n * Copyright (c) 2010 \"Cowboy\" Ben Alman\n * Dual licensed under the MIT and GPL licenses.\n * http://benalman.com/about/license/\n */\n\n// Script: jQuery resize event\n//\n// *Version: 1.1, Last updated: 3/14/2010*\n// \n// Project Home - http://benalman.com/projects/jquery-resize-plugin/\n// GitHub       - http://github.com/cowboy/jquery-resize/\n// Source       - http://github.com/cowboy/jquery-resize/raw/master/jquery.ba-resize.js\n// (Minified)   - http://github.com/cowboy/jquery-resize/raw/master/jquery.ba-resize.min.js (1.0kb)\n// \n// About: License\n// \n// Copyright (c) 2010 \"Cowboy\" Ben Alman,\n// Dual licensed under the MIT and GPL licenses.\n// http://benalman.com/about/license/\n// \n// About: Examples\n// \n// This working example, complete with fully commented code, illustrates a few\n// ways in which this plugin can be used.\n// \n// resize event - http://benalman.com/code/projects/jquery-resize/examples/resize/\n// \n// About: Support and Testing\n// \n// Information about what version or versions of jQuery this plugin has been\n// tested with, what browsers it has been tested in, and where the unit tests\n// reside (so you can test it yourself).\n// \n// jQuery Versions - 1.3.2, 1.4.1, 1.4.2\n// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.6, Safari 3-4, Chrome, Opera 9.6-10.1.\n// Unit Tests      - http://benalman.com/code/projects/jquery-resize/unit/\n// \n// About: Release History\n// \n// 1.1 - (3/14/2010) Fixed a minor bug that was causing the event to trigger\n//       immediately after bind in some circumstances. Also changed $.fn.data\n//       to $.data to improve performance.\n// 1.0 - (2/10/2010) Initial release\n\n(function($,window,undefined){\n  '$:nomunge'; // Used by YUI compressor.\n  \n  // A jQuery object containing all non-window elements to which the resize\n  // event is bound.\n  var elems = $([]),\n    \n    // Extend $.resize if it already exists, otherwise create it.\n    jq_resize = $.resize = $.extend( $.resize, {} ),\n    \n    timeout_id,\n    \n    // Reused strings.\n    str_setTimeout = 'setTimeout',\n    str_resize = 'resize',\n    str_data = str_resize + '-special-event',\n    str_delay = 'delay',\n    str_throttle = 'throttleWindow';\n  \n  // Property: jQuery.resize.delay\n  // \n  // The numeric interval (in milliseconds) at which the resize event polling\n  // loop executes. Defaults to 250.\n  \n  jq_resize[ str_delay ] = 250;\n  \n  // Property: jQuery.resize.throttleWindow\n  // \n  // Throttle the native window object resize event to fire no more than once\n  // every <jQuery.resize.delay> milliseconds. Defaults to true.\n  // \n  // Because the window object has its own resize event, it doesn't need to be\n  // provided by this plugin, and its execution can be left entirely up to the\n  // browser. However, since certain browsers fire the resize event continuously\n  // while others do not, enabling this will throttle the window resize event,\n  // making event behavior consistent across all elements in all browsers.\n  // \n  // While setting this property to false will disable window object resize\n  // event throttling, please note that this property must be changed before any\n  // window object resize event callbacks are bound.\n  \n  jq_resize[ str_throttle ] = true;\n  \n  // Event: resize event\n  // \n  // Fired when an element's width or height changes. Because browsers only\n  // provide this event for the window element, for other elements a polling\n  // loop is initialized, running every <jQuery.resize.delay> milliseconds\n  // to see if elements' dimensions have changed. You may bind with either\n  // .resize( fn ) or .bind( \"resize\", fn ), and unbind with .unbind( \"resize\" ).\n  // \n  // Usage:\n  // \n  // > jQuery('selector').bind( 'resize', function(e) {\n  // >   // element's width or height has changed!\n  // >   ...\n  // > });\n  // \n  // Additional Notes:\n  // \n  // * The polling loop is not created until at least one callback is actually\n  //   bound to the 'resize' event, and this single polling loop is shared\n  //   across all elements.\n  // \n  // Double firing issue in jQuery 1.3.2:\n  // \n  // While this plugin works in jQuery 1.3.2, if an element's event callbacks\n  // are manually triggered via .trigger( 'resize' ) or .resize() those\n  // callbacks may double-fire, due to limitations in the jQuery 1.3.2 special\n  // events system. This is not an issue when using jQuery 1.4+.\n  // \n  // > // While this works in jQuery 1.4+\n  // > $(elem).css({ width: new_w, height: new_h }).resize();\n  // > \n  // > // In jQuery 1.3.2, you need to do this:\n  // > var elem = $(elem);\n  // > elem.css({ width: new_w, height: new_h });\n  // > elem.data( 'resize-special-event', { width: elem.width(), height: elem.height() } );\n  // > elem.resize();\n      \n  $.event.special[ str_resize ] = {\n    \n    // Called only when the first 'resize' event callback is bound per element.\n    setup: function() {\n      // Since window has its own native 'resize' event, return false so that\n      // jQuery will bind the event using DOM methods. Since only 'window'\n      // objects have a .setTimeout method, this should be a sufficient test.\n      // Unless, of course, we're throttling the 'resize' event for window.\n      if ( !jq_resize[ str_throttle ] && this[ str_setTimeout ] ) { return false; }\n      \n      var elem = $(this);\n      \n      // Add this element to the list of internal elements to monitor.\n      elems = elems.add( elem );\n      \n      // Initialize data store on the element.\n      $.data( this, str_data, { w: elem.width(), h: elem.height() } );\n      \n      // If this is the first element added, start the polling loop.\n      if ( elems.length === 1 ) {\n        loopy();\n      }\n    },\n    \n    // Called only when the last 'resize' event callback is unbound per element.\n    teardown: function() {\n      // Since window has its own native 'resize' event, return false so that\n      // jQuery will unbind the event using DOM methods. Since only 'window'\n      // objects have a .setTimeout method, this should be a sufficient test.\n      // Unless, of course, we're throttling the 'resize' event for window.\n      if ( !jq_resize[ str_throttle ] && this[ str_setTimeout ] ) { return false; }\n      \n      var elem = $(this);\n      \n      // Remove this element from the list of internal elements to monitor.\n      elems = elems.not( elem );\n      \n      // Remove any data stored on the element.\n      elem.removeData( str_data );\n      \n      // If this is the last element removed, stop the polling loop.\n      if ( !elems.length ) {\n        clearTimeout( timeout_id );\n      }\n    },\n    \n    // Called every time a 'resize' event callback is bound per element (new in\n    // jQuery 1.4).\n    add: function( handleObj ) {\n      // Since window has its own native 'resize' event, return false so that\n      // jQuery doesn't modify the event object. Unless, of course, we're\n      // throttling the 'resize' event for window.\n      if ( !jq_resize[ str_throttle ] && this[ str_setTimeout ] ) { return false; }\n      \n      var old_handler;\n      \n      // The new_handler function is executed every time the event is triggered.\n      // This is used to update the internal element data store with the width\n      // and height when the event is triggered manually, to avoid double-firing\n      // of the event callback. See the \"Double firing issue in jQuery 1.3.2\"\n      // comments above for more information.\n      \n      function new_handler( e, w, h ) {\n        var elem = $(this),\n          data = $.data( this, str_data );\n        \n        // If called from the polling loop, w and h will be passed in as\n        // arguments. If called manually, via .trigger( 'resize' ) or .resize(),\n        // those values will need to be computed.\n        data.w = w !== undefined ? w : elem.width();\n        data.h = h !== undefined ? h : elem.height();\n        \n        old_handler.apply( this, arguments );\n      };\n      \n      // This may seem a little complicated, but it normalizes the special event\n      // .add method between jQuery 1.4/1.4.1 and 1.4.2+\n      if ( $.isFunction( handleObj ) ) {\n        // 1.4, 1.4.1\n        old_handler = handleObj;\n        return new_handler;\n      } else {\n        // 1.4.2+\n        old_handler = handleObj.handler;\n        handleObj.handler = new_handler;\n      }\n    }\n    \n  };\n  \n  function loopy() {\n    \n    // Start the polling loop, asynchronously.\n    timeout_id = window[ str_setTimeout ](function(){\n      \n      // Iterate over all elements to which the 'resize' event is bound.\n      elems.each(function(){\n        var elem = $(this),\n          width = elem.width(),\n          height = elem.height(),\n          data = $.data( this, str_data );\n        \n        // If element size has changed since the last time, update the element\n        // data store and trigger the 'resize' event.\n        if ( width !== data.w || height !== data.h ) {\n          elem.trigger( str_resize, [ data.w = width, data.h = height ] );\n        }\n        \n      });\n      \n      // Loop.\n      loopy();\n      \n    }, jq_resize[ str_delay ] );\n    \n  };\n  \n})(jQuery,this);"
  },
  {
    "path": "static/js/jquery/jquery.slimscroll.js",
    "content": "!function(e){e.fn.extend({slimScroll:function(i){var o={width:\"auto\",height:\"250px\",size:\"7px\",color:\"#000\",position:\"right\",distance:\"1px\",start:\"top\",opacity:.4,alwaysVisible:!1,disableFadeOut:!1,railVisible:!1,railColor:\"#333\",railOpacity:.2,railDraggable:!0,railClass:\"slimScrollRail\",barClass:\"slimScrollBar\",wrapperClass:\"slimScrollDiv\",allowPageScroll:!1,wheelStep:20,touchScrollStep:200,borderRadius:\"7px\",railBorderRadius:\"7px\"},s=e.extend(o,i);return this.each(function(){function o(t){if(h){var t=t||window.event,i=0;t.wheelDelta&&(i=-t.wheelDelta/120),t.detail&&(i=t.detail/3);var o=t.target||t.srcTarget||t.srcElement;e(o).closest(\".\"+s.wrapperClass).is(x.parent())&&r(i,!0),t.preventDefault&&!y&&t.preventDefault(),y||(t.returnValue=!1)}}function r(e,t,i){y=!1;var o=e,r=x.outerHeight()-R.outerHeight();if(t&&(o=parseInt(R.css(\"top\"))+e*parseInt(s.wheelStep)/100*R.outerHeight(),o=Math.min(Math.max(o,0),r),o=e>0?Math.ceil(o):Math.floor(o),R.css({top:o+\"px\"})),v=parseInt(R.css(\"top\"))/(x.outerHeight()-R.outerHeight()),o=v*(x[0].scrollHeight-x.outerHeight()),i){o=e;var a=o/x[0].scrollHeight*x.outerHeight();a=Math.min(Math.max(a,0),r),R.css({top:a+\"px\"})}x.scrollTop(o),x.trigger(\"slimscrolling\",~~o),n(),c()}function a(e){window.addEventListener?(e.addEventListener(\"DOMMouseScroll\",o,!1),e.addEventListener(\"mousewheel\",o,!1)):document.attachEvent(\"onmousewheel\",o)}function l(){f=Math.max(x.outerHeight()/x[0].scrollHeight*x.outerHeight(),m),R.css({height:f+\"px\"});var e=f==x.outerHeight()?\"none\":\"block\";R.css({display:e})}function n(){if(l(),clearTimeout(p),v==~~v){if(y=s.allowPageScroll,b!=v){var e=0==~~v?\"top\":\"bottom\";x.trigger(\"slimscroll\",e)}}else y=!1;return b=v,f>=x.outerHeight()?void(y=!0):(R.stop(!0,!0).fadeIn(\"fast\"),void(s.railVisible&&E.stop(!0,!0).fadeIn(\"fast\")))}function c(){s.alwaysVisible||(p=setTimeout(function(){s.disableFadeOut&&h||u||d||(R.fadeOut(\"slow\"),E.fadeOut(\"slow\"))},1e3))}var h,u,d,p,g,f,v,b,w=\"<div></div>\",m=30,y=!1,x=e(this);if(x.parent().hasClass(s.wrapperClass)){var C=x.scrollTop();if(R=x.closest(\".\"+s.barClass),E=x.closest(\".\"+s.railClass),l(),e.isPlainObject(i)){if(\"height\"in i&&\"auto\"==i.height){x.parent().css(\"height\",\"auto\"),x.css(\"height\",\"auto\");var H=x.parent().parent().height();x.parent().css(\"height\",H),x.css(\"height\",H)}if(\"scrollTo\"in i)C=parseInt(s.scrollTo);else if(\"scrollBy\"in i)C+=parseInt(s.scrollBy);else if(\"destroy\"in i)return R.remove(),E.remove(),void x.unwrap();r(C,!1,!0)}}else if(!(e.isPlainObject(i)&&\"destroy\"in i)){s.height=\"auto\"==s.height?x.parent().height():s.height;var S=e(w).addClass(s.wrapperClass).css({position:\"relative\",overflow:\"hidden\",width:s.width,height:s.height});x.css({overflow:\"hidden\",width:s.width,height:s.height});var E=e(w).addClass(s.railClass).css({width:s.size,height:\"100%\",position:\"absolute\",top:0,display:s.alwaysVisible&&s.railVisible?\"block\":\"none\",\"border-radius\":s.railBorderRadius,background:s.railColor,opacity:s.railOpacity,zIndex:90}),R=e(w).addClass(s.barClass).css({background:s.color,width:s.size,position:\"absolute\",top:0,opacity:s.opacity,display:s.alwaysVisible?\"block\":\"none\",\"border-radius\":s.borderRadius,BorderRadius:s.borderRadius,MozBorderRadius:s.borderRadius,WebkitBorderRadius:s.borderRadius,zIndex:99}),D=\"right\"==s.position?{right:s.distance}:{left:s.distance};E.css(D),R.css(D),x.wrap(S),x.parent().append(R),x.parent().append(E),s.railDraggable&&R.bind(\"mousedown\",function(i){var o=e(document);return d=!0,t=parseFloat(R.css(\"top\")),pageY=i.pageY,o.bind(\"mousemove.slimscroll\",function(e){currTop=t+e.pageY-pageY,R.css(\"top\",currTop),r(0,R.position().top,!1)}),o.bind(\"mouseup.slimscroll\",function(e){d=!1,c(),o.unbind(\".slimscroll\")}),!1}).bind(\"selectstart.slimscroll\",function(e){return e.stopPropagation(),e.preventDefault(),!1}),E.hover(function(){n()},function(){c()}),R.hover(function(){u=!0},function(){u=!1}),x.hover(function(){h=!0,n(),c()},function(){h=!1,c()}),x.bind(\"touchstart\",function(e,t){e.originalEvent.touches.length&&(g=e.originalEvent.touches[0].pageY)}),x.bind(\"touchmove\",function(e){if(y||e.originalEvent.preventDefault(),e.originalEvent.touches.length){var t=(g-e.originalEvent.touches[0].pageY)/s.touchScrollStep;r(t,!0),g=e.originalEvent.touches[0].pageY}}),l(),\"bottom\"===s.start?(R.css({top:x.outerHeight()-R.outerHeight()}),r(0,!0)):\"top\"!==s.start&&(r(e(s.start).position().top,null,!0),s.alwaysVisible||R.hide()),a(this)}}),this}}),e.fn.extend({slimscroll:e.fn.slimScroll})}(jQuery);"
  },
  {
    "path": "static/js/jquery/jquery.wordexport.js",
    "content": "if (typeof jQuery !== \"undefined\" && typeof saveAs !== \"undefined\") {\n    (function($) {\n        $.fn.wordExport = function(fileName) {\n            fileName = typeof fileName !== 'undefined' ? fileName : \"数据质量报告\";\n            var static = {\n                mhtml: {\n                    top: \"Mime-Version: 1.0\\nContent-Base: \" + location.href + \"\\nContent-Type: Multipart/related; boundary=\\\"NEXT.ITEM-BOUNDARY\\\";type=\\\"text/html\\\"\\n\\n--NEXT.ITEM-BOUNDARY\\nContent-Type: text/html; charset=\\\"utf-8\\\"\\nContent-Location: \" + location.href + \"\\n\\n<!DOCTYPE html>\\n<html>\\n_html_</html>\",\n                    head: \"<head>\\n<meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html; charset=utf-8\\\">\\n<style>\\n_styles_\\n</style>\\n</head>\\n\",\n                    body: \"<body>_body_</body>\"\n                }\n            };\n            var options = {\n                maxWidth: 624\n            };\n            // Clone selected element before manipulating it\n            var markup = $(this).clone();\n\n            // Remove hidden elements from the output\n            markup.each(function() {\n                var self = $(this);\n                if (self.is(':hidden'))\n                    self.remove();\n            });\n\n            // Embed all images using Data URLs\n            var images = Array();\n            var img = markup.find('img');\n            for (var i = 0; i < img.length; i++) {\n                // Calculate dimensions of output image\n                var w = Math.min(img[i].width, options.maxWidth);\n                var h = img[i].height * (w / img[i].width);\n                // Create canvas for converting image to data URL\n                var canvas = document.createElement(\"CANVAS\");\n                canvas.width = w;\n                canvas.height = h;\n                // Draw image to canvas\n                var context = canvas.getContext('2d');\n                context.drawImage(img[i], 0, 0, w, h);\n                // Get data URL encoding of image\n                var uri = canvas.toDataURL(\"image/png\");\n                $(img[i]).attr(\"src\", img[i].src);\n                img[i].width = w;\n                img[i].height = h;\n                // Save encoded image to array\n                images[i] = {\n                    type: uri.substring(uri.indexOf(\":\") + 1, uri.indexOf(\";\")),\n                    encoding: uri.substring(uri.indexOf(\";\") + 1, uri.indexOf(\",\")),\n                    location: $(img[i]).attr(\"src\"),\n                    data: uri.substring(uri.indexOf(\",\") + 1)\n                };\n            }\n\n            // Prepare bottom of mhtml file with image data\n            var mhtmlBottom = \"\\n\";\n            for (var i = 0; i < images.length; i++) {\n                mhtmlBottom += \"--NEXT.ITEM-BOUNDARY\\n\";\n                mhtmlBottom += \"Content-Location: \" + images[i].location + \"\\n\";\n                mhtmlBottom += \"Content-Type: \" + images[i].type + \"\\n\";\n                mhtmlBottom += \"Content-Transfer-Encoding: \" + images[i].encoding + \"\\n\\n\";\n                mhtmlBottom += images[i].data + \"\\n\\n\";\n            }\n            mhtmlBottom += \"--NEXT.ITEM-BOUNDARY--\";\n\n            //TODO: load css from included stylesheet\n            var styles = \"\";\n\n            // Aggregate parts of the file together\n            var fileContent = static.mhtml.top.replace(\"_html_\", static.mhtml.head.replace(\"_styles_\", styles) + static.mhtml.body.replace(\"_body_\", markup.html())) + mhtmlBottom;\n\n            // Create a Blob with the file contents\n            var blob = new Blob([fileContent], {\n                type: \"application/msword;charset=utf-8\"\n            });\n            saveAs(blob, fileName + \".doc\");\n        };\n    })(jQuery);\n} else {\n    if (typeof jQuery === \"undefined\") {\n        console.error(\"jQuery Word Export: missing dependency (jQuery)\");\n    }\n    if (typeof saveAs === \"undefined\") {\n        console.error(\"jQuery Word Export: missing dependency (FileSaver.js)\");\n    }\n}\n"
  },
  {
    "path": "static/js/login.js",
    "content": "// 设置随机背景图\nfunction Onload(){\n    var imgList = [\n        \"/static/img/bg_0.jpg\",\n        \"/static/img/bg_1.jpg\",\n        \"/static/img/bg_2.jpg\",\n    ]\n    var imgRandom = Math.floor(Math.random() * (imgList.length));\n    html = \"<div id=\\\"bg-pict\\\" style=\\\"background-image:url(/static/img/bg_\" + imgRandom + \".jpg);\\\"></div>\"\n    imgRandom = Math.floor(Math.random() * imgList.length);\n    html += \"<div id=\\\"bg-pict\\\" style=\\\"background-image:url(/static/img/bg_\" + imgRandom + \".jpg);\\\"></div>\"\n    imgRandom = Math.floor(Math.random() * imgList.length);\n    html += \"<div id=\\\"bg-pict\\\" style=\\\"background-image:url(/static/img/bg_\" + imgRandom + \".jpg);\\\"></div>\"\n    document.getElementById(\"bg\").innerHTML = html;\n}\n\n\n// 登录验证\nfunction Login() {\n    document.getElementById(\"login\").disabled = true;\n    $.ajax({\n        url: \"../../authorize/login_auth\",\n        type: \"POST\",\n        dataType: \"json\",\n        data: {\n            username: $(\"#username\").val(),\n            password: $(\"#password\").val(),\n        },\n        success: function (data) {\n            if (data.status == 'success') {\n                swal({\n                    title: \"欢迎回来!\",\n                    text: \"正在跳转...\",\n                    icon: \"success\",\n                    buttons: false,\n                    timer: 1000,\n                }).then(function(){\n                    window.location.href = '../../data/dashboard/';\n                });\n            }\n            else {\n                document.getElementById(\"login\").disabled = false;\n                swal(\"登录失败!\", data.status, 'error');\n            }\n        },\n        error: function () {\n            document.getElementById(\"login\").disabled = false;\n        }\n    });\n}\n\nfunction NextElement(id){\n    if ( id == 'username' && event.keyCode == 13 ){\n        document.getElementById(\"password\").focus();\n    }\n    else if ( id == 'password' && event.keyCode == 13 ){\n        document.getElementById(\"login\").click();\n    }\n    else if ( id == 'send-sms' && event.keyCode == 13 ){\n        document.getElementById(\"new-password\").focus();\n    }\n    else if ( id == 'new-password' && event.keyCode == 13 ){\n        document.getElementById(\"reset\").click();\n    }\n}\n\n\n// 发送短信\nfunction SendSMSCode(){\n    if ( $(\"#mobile\").val() == '' || $(\"#mobile\").val() == null ){\n        swal({\n            text: '请先输入手机号',\n            icon: 'warning',\n            buttons: false,\n            timer: 1000,\n        })\n        return;\n    }\n    $.ajax({\n        url: \"\",\n        type: \"GET\",\n        dataType: \"json\",\n        contentType:'application/x-www-form-urlencoded',\n        data: {\n            mobile: $(\"#mobile\").val(),\n        },\n        success: function (data) {\n            if ( data.status == '短信发送成功' ){\n                swal({\n                    'text': '短信发送成功',\n                    'icon': 'success',\n                    'buttons': false,\n                    'timer': 1000\n                });\n                var obj = $(\"#send-sms\");\n                $(\"#sms-code\").focus();\n                settime(obj);\n            }\n            else if ( data.status == '验证失败' ) {\n                swal({\n                    title: data.status,\n                    text: data.msg,\n                    icon: 'error'\n                });\n            }\n            else {\n                swal({\n                    title: data.status,\n                    text: data.msg,\n                    icon: 'error'\n                });\n            }\n        },\n        error: function () {\n            swal({\n                text: '服务器正在开小差，请稍候重试...',\n                icon: 'warning'\n            });\n        }\n    });\n    \n}\n\n\n// 验证码有效期\nvar countdown=60; \nfunction settime(obj) { //发送验证码倒计时\n    if (countdown == 0) { \n        obj.attr('disabled',false); \n        obj.html(\"获取验证码\");\n        countdown = 60; \n        return;\n    } else { \n        obj.attr('disabled',true);\n        obj.html(\"重新发送(\" + countdown + \")...\");\n        countdown--; \n    } \nsetTimeout(function() { \n    settime(obj) }\n    ,1000) \n}\n\n\n// 登录框键入回车换行\nfunction SwitchTab(id){\n    if ( id == 'InputForm' ){\n        document.getElementById(\"InputForm\").style.display='block';\n        document.getElementById(\"ResetForm\").style.display='none';\n        document.getElementById(\"reset-pwd\").className='';\n        document.getElementById(\"login-page\").className='active';\n        document.getElementById(\"login\").style.display='';\n        document.getElementById(\"reset\").style.display='none';\n    }\n    else if ( id == 'ResetForm' ){\n        document.getElementById(\"ResetForm\").style.display='block';\n        document.getElementById(\"InputForm\").style.display='none';\n        document.getElementById(\"reset-pwd\").className='active';\n        document.getElementById(\"login-page\").className='';\n        document.getElementById(\"login\").style.display='none';\n        document.getElementById(\"reset\").style.display='';\n    }\n}\n\n\n// 修改密码\nfunction ModifyPassword() {\n    document.getElementById(\"login\").disabled = true;\n    $.ajax({\n        url: \"\",\n        type: \"POST\",\n        xhrFields: {\n            withCredentials: true\n        },\n        crossDomain: true,\n        dataType: \"json\",\n        contentType:'application/x-www-form-urlencoded',\n        data: {\n            mobile: $(\"#mobile\").val(),\n            code: $(\"#sms-code\").val(),\n            password: $(\"#new-password\").val(),\n        },\n        success: function (data) {\n            var user = data.username;\n            if (data.status == '修改成功') {\n                swal({\n                    title: \"重置密码成功!\",\n                    text: \"正在跳转...\",\n                    icon: \"success\",\n                    buttons: false,\n                    timer: 1000,\n                }).then(function(){\n                    window.location.href = 'portal.html#token=' + data.token;\n                });\n            }\n            else if ( data.status == '验证码错误' ){\n                swal({\n                    title: \"验证码错误\",\n                    icon: \"error\",\n                }).then(function(){\n                    document.getElementById(\"login\").disabled = false;\n                });\n            }\n            else {\n                document.getElementById(\"login\").disabled = false;\n                swal(\"登录失败!\", data.reason, 'error');\n            }\n        },\n        error: function () {\n            document.getElementById(\"login\").disabled = false;\n        }\n    });\n}"
  },
  {
    "path": "static/js/scripts.js",
    "content": "$(function() {\n    \"use strict\";\n    $(function() {\n            $(\".preloader\").fadeOut();\n        }),\n\n        jQuery(document).on(\"click\", \".mega-dropdown\", function(i) {\n            i.stopPropagation();\n        });\n\n\n    var i = function() {\n        (window.innerWidth > 0 ? window.innerWidth : this.screen.width) < 1170 ? ($(\"body\").addClass(\"mini-sidebar\"),\n            $(\".navbar-brand span\").hide(), $(\".scroll-sidebar, .slimScrollDiv\").css(\"overflow-x\", \"visible\").parent().css(\"overflow\", \"visible\"),\n            $(\".sidebartoggler i\").addClass(\"ti-menu\")) : ($(\"body\").removeClass(\"mini-sidebar\"),\n            $(\".navbar-brand span\").show());\n        var i = (window.innerHeight > 0 ? window.innerHeight : this.screen.height) - 1;\n        (i -= 70) < 1 && (i = 1), i > 70 && $(\".page-wrapper\").css(\"min-height\", i + \"px\");\n    };\n\n\n    $(window).ready(i), $(window).on(\"resize\", i), $(\".sidebartoggler\").on(\"click\", function() {\n            $(\"body\").hasClass(\"mini-sidebar\") ? ($(\"body\").trigger(\"resize\"), $(\".scroll-sidebar, .slimScrollDiv\").css(\"overflow\", \"hidden\").parent().css(\"overflow\", \"visible\"),\n                $(\"body\").removeClass(\"mini-sidebar\"), $(\".navbar-brand span\").show()) : ($(\"body\").trigger(\"resize\"),\n                $(\".scroll-sidebar, .slimScrollDiv\").css(\"overflow-x\", \"visible\").parent().css(\"overflow\", \"visible\"),\n                $(\"body\").addClass(\"mini-sidebar\"), $(\".navbar-brand span\").hide());\n        }),\n\n\n\n        $(\".fix-header .header\").stick_in_parent({}), $(\".nav-toggler\").click(function() {\n            $(\"body\").toggleClass(\"show-sidebar\"), $(\".nav-toggler i\").toggleClass(\"mdi mdi-menu\"),\n                $(\".nav-toggler i\").addClass(\"mdi mdi-close\");\n        }),\n\n\n\n        $(\".search-box a, .search-box .app-search .srh-btn\").on(\"click\", function() {\n            $(\".app-search\").slideToggle(200);\n        }),\n\n\n\n        $(\".floating-labels .form-control\").on(\"focus blur\", function(i) {\n            $(this).parents(\".form-group\").toggleClass(\"focused\", \"focus\" === i.type || this.value.length > 0);\n        }).trigger(\"blur\"), $(function() {\n            for (var i = window.location, o = $(\"ul#sidebarnav a\").filter(function() {\n                    return this.href == i;\n                }).addClass(\"active\").parent().addClass(\"active\");;) {\n                if (!o.is(\"li\")) break;\n                o = o.parent().addClass(\"in\").parent().addClass(\"active\");\n            }\n        }),\n\n        $(function() {\n            $(\"#sidebarnav\").metisMenu();\n        }),\n\n        $(\".scroll-sidebar\").slimScroll({\n            position: \"left\",\n            size: \"5px\",\n            height: \"100%\",\n            color: \"#dcdcdc\"\n        }),\n\n        $(\".message-center\").slimScroll({\n            position: \"right\",\n            size: \"5px\",\n            color: \"#dcdcdc\"\n        }),\n\n        $(\".aboutscroll\").slimScroll({\n            position: \"right\",\n            size: \"5px\",\n            height: \"80\",\n            color: \"#dcdcdc\"\n        }),\n\n        $(\".message-scroll\").slimScroll({\n            position: \"right\",\n            size: \"5px\",\n            height: \"570\",\n            color: \"#dcdcdc\"\n        }),\n\n        $(\".chat-box\").slimScroll({\n            position: \"right\",\n            size: \"5px\",\n            height: \"470\",\n            color: \"#dcdcdc\"\n        }),\n\n        $(\".slimscrollright\").slimScroll({\n            height: \"100%\",\n            position: \"right\",\n            size: \"5px\",\n            color: \"#dcdcdc\"\n        }),\n\n\n\n        $(\"body\").trigger(\"resize\"), $(\".list-task li label\").click(function() {\n            $(this).toggleClass(\"task-done\");\n        }),\n\n\n\n        $(\"#to-recover\").on(\"click\", function() {\n            $(\"#loginform\").slideUp(), $(\"#recoverform\").fadeIn();\n        }),\n\n\n\n        $('a[data-action=\"collapse\"]').on(\"click\", function(i) {\n            i.preventDefault(), $(this).closest(\".card\").find('[data-action=\"collapse\"] i').toggleClass(\"ti-minus ti-plus\"),\n                $(this).closest(\".card\").children(\".card-body\").collapse(\"toggle\");\n        }),\n\n\n\n        $('a[data-action=\"expand\"]').on(\"click\", function(i) {\n            i.preventDefault(), $(this).closest(\".card\").find('[data-action=\"expand\"] i').toggleClass(\"mdi-arrow-expand mdi-arrow-compress\"),\n                $(this).closest(\".card\").toggleClass(\"card-fullscreen\");\n        }),\n\n\n\n        $('a[data-action=\"close\"]').on(\"click\", function() {\n            $(this).closest(\".card\").removeClass().slideUp(\"fast\");\n        });\n});\n"
  },
  {
    "path": "static/js/sidebarmenu.js",
    "content": "/*\nTemplate Name: Admin Press Admin\nAuthor: Themedesigner\nEmail: niravjoshi87@gmail.com\nFile: js\n*/\n(function (global, factory) {\n  if (typeof define === \"function\" && define.amd) {\n    define(['jquery'], factory);\n  } else if (typeof exports !== \"undefined\") {\n    factory(require('jquery'));\n  } else {\n    var mod = {\n      exports: {}\n    };\n    factory(global.jquery);\n    global.metisMenu = mod.exports;\n  }\n})(this, function (_jquery) {\n  'use strict';\n\n  var _jquery2 = _interopRequireDefault(_jquery);\n\n  function _interopRequireDefault(obj) {\n    return obj && obj.__esModule ? obj : {\n      default: obj\n    };\n  }\n\n  var _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) {\n    return typeof obj;\n  } : function (obj) {\n    return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n  };\n\n  function _classCallCheck(instance, Constructor) {\n    if (!(instance instanceof Constructor)) {\n      throw new TypeError(\"Cannot call a class as a function\");\n    }\n  }\n\n  var Util = function ($) {\n    var transition = false;\n\n    var TransitionEndEvent = {\n      WebkitTransition: 'webkitTransitionEnd',\n      MozTransition: 'transitionend',\n      OTransition: 'oTransitionEnd otransitionend',\n      transition: 'transitionend'\n    };\n\n    function getSpecialTransitionEndEvent() {\n      return {\n        bindType: transition.end,\n        delegateType: transition.end,\n        handle: function handle(event) {\n          if ($(event.target).is(this)) {\n            return event.handleObj.handler.apply(this, arguments);\n          }\n          return undefined;\n        }\n      };\n    }\n\n    function transitionEndTest() {\n      if (window.QUnit) {\n        return false;\n      }\n\n      var el = document.createElement('mm');\n\n      for (var name in TransitionEndEvent) {\n        if (el.style[name] !== undefined) {\n          return {\n            end: TransitionEndEvent[name]\n          };\n        }\n      }\n\n      return false;\n    }\n\n    function transitionEndEmulator(duration) {\n      var _this2 = this;\n\n      var called = false;\n\n      $(this).one(Util.TRANSITION_END, function () {\n        called = true;\n      });\n\n      setTimeout(function () {\n        if (!called) {\n          Util.triggerTransitionEnd(_this2);\n        }\n      }, duration);\n\n      return this;\n    }\n\n    function setTransitionEndSupport() {\n      transition = transitionEndTest();\n      $.fn.emulateTransitionEnd = transitionEndEmulator;\n\n      if (Util.supportsTransitionEnd()) {\n        $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent();\n      }\n    }\n\n    var Util = {\n      TRANSITION_END: 'mmTransitionEnd',\n\n      triggerTransitionEnd: function triggerTransitionEnd(element) {\n        $(element).trigger(transition.end);\n      },\n      supportsTransitionEnd: function supportsTransitionEnd() {\n        return Boolean(transition);\n      }\n    };\n\n    setTransitionEndSupport();\n\n    return Util;\n  }(jQuery);\n\n  var MetisMenu = function ($) {\n\n    var NAME = 'metisMenu';\n    var DATA_KEY = 'metisMenu';\n    var EVENT_KEY = '.' + DATA_KEY;\n    var DATA_API_KEY = '.data-api';\n    var JQUERY_NO_CONFLICT = $.fn[NAME];\n    var TRANSITION_DURATION = 350;\n\n    var Default = {\n      toggle: true,\n      preventDefault: true,\n      activeClass: 'active',\n      collapseClass: 'collapse',\n      collapseInClass: 'in',\n      collapsingClass: 'collapsing',\n      triggerElement: 'a',\n      parentTrigger: 'li',\n      subMenu: 'ul'\n    };\n\n    var Event = {\n      SHOW: 'show' + EVENT_KEY,\n      SHOWN: 'shown' + EVENT_KEY,\n      HIDE: 'hide' + EVENT_KEY,\n      HIDDEN: 'hidden' + EVENT_KEY,\n      CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY\n    };\n\n    var MetisMenu = function () {\n      function MetisMenu(element, config) {\n        _classCallCheck(this, MetisMenu);\n\n        this._element = element;\n        this._config = this._getConfig(config);\n        this._transitioning = null;\n\n        this.init();\n      }\n\n      MetisMenu.prototype.init = function init() {\n        var self = this;\n        $(this._element).find(this._config.parentTrigger + '.' + this._config.activeClass).has(this._config.subMenu).children(this._config.subMenu).attr('aria-expanded', true).addClass(this._config.collapseClass + ' ' + this._config.collapseInClass);\n\n        $(this._element).find(this._config.parentTrigger).not('.' + this._config.activeClass).has(this._config.subMenu).children(this._config.subMenu).attr('aria-expanded', false).addClass(this._config.collapseClass);\n\n        $(this._element).find(this._config.parentTrigger).has(this._config.subMenu).children(this._config.triggerElement).on(Event.CLICK_DATA_API, function (e) {\n          var _this = $(this);\n          var _parent = _this.parent(self._config.parentTrigger);\n          var _siblings = _parent.siblings(self._config.parentTrigger).children(self._config.triggerElement);\n          var _list = _parent.children(self._config.subMenu);\n          if (self._config.preventDefault) {\n            e.preventDefault();\n          }\n          if (_this.attr('aria-disabled') === 'true') {\n            return;\n          }\n          if (_parent.hasClass(self._config.activeClass)) {\n            _this.attr('aria-expanded', false);\n            self._hide(_list);\n          } else {\n            self._show(_list);\n            _this.attr('aria-expanded', true);\n            if (self._config.toggle) {\n              _siblings.attr('aria-expanded', false);\n            }\n          }\n\n          if (self._config.onTransitionStart) {\n            self._config.onTransitionStart(e);\n          }\n        });\n      };\n\n      MetisMenu.prototype._show = function _show(element) {\n        if (this._transitioning || $(element).hasClass(this._config.collapsingClass)) {\n          return;\n        }\n        var _this = this;\n        var _el = $(element);\n\n        var startEvent = $.Event(Event.SHOW);\n        _el.trigger(startEvent);\n\n        if (startEvent.isDefaultPrevented()) {\n          return;\n        }\n\n        _el.parent(this._config.parentTrigger).addClass(this._config.activeClass);\n\n        if (this._config.toggle) {\n          this._hide(_el.parent(this._config.parentTrigger).siblings().children(this._config.subMenu + '.' + this._config.collapseInClass).attr('aria-expanded', false));\n        }\n\n        _el.removeClass(this._config.collapseClass).addClass(this._config.collapsingClass).height(0);\n\n        this.setTransitioning(true);\n\n        var complete = function complete() {\n\n          _el.removeClass(_this._config.collapsingClass).addClass(_this._config.collapseClass + ' ' + _this._config.collapseInClass).height('').attr('aria-expanded', true);\n\n          _this.setTransitioning(false);\n\n          _el.trigger(Event.SHOWN);\n        };\n\n        if (!Util.supportsTransitionEnd()) {\n          complete();\n          return;\n        }\n\n        _el.height(_el[0].scrollHeight).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);\n      };\n\n      MetisMenu.prototype._hide = function _hide(element) {\n\n        if (this._transitioning || !$(element).hasClass(this._config.collapseInClass)) {\n          return;\n        }\n        var _this = this;\n        var _el = $(element);\n\n        var startEvent = $.Event(Event.HIDE);\n        _el.trigger(startEvent);\n\n        if (startEvent.isDefaultPrevented()) {\n          return;\n        }\n\n        _el.parent(this._config.parentTrigger).removeClass(this._config.activeClass);\n        _el.height(_el.height())[0].offsetHeight;\n\n        _el.addClass(this._config.collapsingClass).removeClass(this._config.collapseClass).removeClass(this._config.collapseInClass);\n\n        this.setTransitioning(true);\n\n        var complete = function complete() {\n          if (_this._transitioning && _this._config.onTransitionEnd) {\n            _this._config.onTransitionEnd();\n          }\n\n          _this.setTransitioning(false);\n          _el.trigger(Event.HIDDEN);\n\n          _el.removeClass(_this._config.collapsingClass).addClass(_this._config.collapseClass).attr('aria-expanded', false);\n        };\n\n        if (!Util.supportsTransitionEnd()) {\n          complete();\n          return;\n        }\n\n        _el.height() == 0 || _el.css('display') == 'none' ? complete() : _el.height(0).one(Util.TRANSITION_END, complete).emulateTransitionEnd(TRANSITION_DURATION);\n      };\n\n      MetisMenu.prototype.setTransitioning = function setTransitioning(isTransitioning) {\n        this._transitioning = isTransitioning;\n      };\n\n      MetisMenu.prototype.dispose = function dispose() {\n        $.removeData(this._element, DATA_KEY);\n\n        $(this._element).find(this._config.parentTrigger).has(this._config.subMenu).children(this._config.triggerElement).off('click');\n\n        this._transitioning = null;\n        this._config = null;\n        this._element = null;\n      };\n\n      MetisMenu.prototype._getConfig = function _getConfig(config) {\n        config = $.extend({}, Default, config);\n        return config;\n      };\n\n      MetisMenu._jQueryInterface = function _jQueryInterface(config) {\n        return this.each(function () {\n          var $this = $(this);\n          var data = $this.data(DATA_KEY);\n          var _config = $.extend({}, Default, $this.data(), (typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object' && config);\n\n          if (!data && /dispose/.test(config)) {\n            this.dispose();\n          }\n\n          if (!data) {\n            data = new MetisMenu(this, _config);\n            $this.data(DATA_KEY, data);\n          }\n\n          if (typeof config === 'string') {\n            if (data[config] === undefined) {\n              throw new Error('No method named \"' + config + '\"');\n            }\n            data[config]();\n          }\n        });\n      };\n\n      return MetisMenu;\n    }();\n\n    /**\n     * ------------------------------------------------------------------------\n     * jQuery\n     * ------------------------------------------------------------------------\n     */\n\n    $.fn[NAME] = MetisMenu._jQueryInterface;\n    $.fn[NAME].Constructor = MetisMenu;\n    $.fn[NAME].noConflict = function () {\n      $.fn[NAME] = JQUERY_NO_CONFLICT;\n      return MetisMenu._jQueryInterface;\n    };\n    return MetisMenu;\n  }(jQuery);\n});"
  },
  {
    "path": "static/resource/chinese.lang",
    "content": "{\n\t\"sProcessing\":   \"处理中...\",\n\t\"sLengthMenu\":   \"显示 _MENU_ 项结果\",\n\t\"sZeroRecords\":  \"没有匹配结果\",\n\t\"sInfo\":         \"显示第 _START_ 至 _END_ 项结果，共 _TOTAL_ 项\",\n\t\"sInfoEmpty\":    \"显示第 0 至 0 项结果，共 0 项\",\n\t\"sInfoFiltered\": \"(由 _MAX_ 项结果过滤)\",\n\t\"sInfoPostFix\":  \"\",\n\t\"sSearch\":       \"搜索:\",\n\t\"sUrl\":          \"\",\n\t\"sEmptyTable\":     \"表中数据为空\",\n\t\"sLoadingRecords\": \"载入中...\",\n\t\"sInfoThousands\":  \",\",\n\t\"oPaginate\": {\n\t\t\"sFirst\":    \"首页\",\n\t\t\"sPrevious\": \"上页\",\n\t\t\"sNext\":     \"下页\",\n\t\t\"sLast\":     \"末页\"\n\t},\n\t\"oAria\": {\n\t\t\"sSortAscending\":  \": 以升序排列此列\",\n\t\t\"sSortDescending\": \": 以降序排列此列\"\n\t}\n}"
  },
  {
    "path": "static/resource/demand.json",
    "content": "[\n    [\"序号\", \"公司\", \"数据项\", \"改造需求\", \"需求提出日期\", \"2019Q1状态\", \"2019Q2状态\"],\n    [1, \"信托\", \"风险等级\", \"补创建数据项\", 201905, \"进行中\", \"未开展\"],\n    [2, \"信托\", \"净资本类别\", \"补创建数据项\", 201905, \"进行中\", \"未开展\"],\n    [3, \"信托\", \"风险资本类别\", \"补创建数据项\", 201905, \"进行中\", \"未开展\"],\n    [4, \"信托\", \"参与人角色\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [5, \"信托\", \"所有制类型\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [6, \"信托\", \"参与人规模\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [7, \"信托\", \"参与人角色标识\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [8, \"信托\", \"产品收益率\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [9, \"信托\", \"参与人上市标识\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [10, \"信托\", \"项目投向行业\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [11, \"信托\", \"项目名称\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [12, \"信托\", \"项目来源\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [13, \"信托\", \"存续标识\", \"设为必填\", 201905, \"进行中\", \"业务系统自动填写，不是业务人员填写\"],\n    [1, \"资产\", \"逾期天数\", \"补创建数据项\", 201905, \"进行中\", \"进行中\"],\n    [2, \"资产\", \"续封续冻资产所在市\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [3, \"资产\", \"担保方式\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [4, \"资产\", \"收购方式\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [5, \"资产\", \"续封续冻资产所在县\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [6, \"资产\", \"项目五级分类\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [7, \"资产\", \"续封续冻资产所在省\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [8, \"资产\", \"资产金额\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [9, \"资产\", \"参与人行业\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [10, \"资产\", \"交易本金金额\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [11, \"资产\", \"到期日期\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [12, \"资产\", \"账面金额\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [13, \"资产\", \"资产处置合同金额\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [14, \"资产\", \"项目余额\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [15, \"资产\", \"项目金额\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [16, \"资产\", \"参与人市\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [17, \"资产\", \"收益率\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [18, \"资产\", \"项目收益\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [19, \"资产\", \"项目类别\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [20, \"资产\", \"开始日期\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [1, \"担保\", \"五级分类\", \"设为必填\", 201905, \"进行中\", \"业务上季后审查回填，不是实时必填项\"],\n    [2, \"担保\", \"参与人五级分类\", \"设为必填\", 201905, \"进行中\", \"业务上季后审查回填，不是实时必填项\"],\n    [3, \"担保\", \"参与人县\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [4, \"担保\", \"参与人行业\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [5, \"担保\", \"收益率\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [6, \"担保\", \"所有制类型\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [7, \"担保\", \"机构证件号码\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [8, \"担保\", \"机构证件类别\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [9, \"担保\", \"项目收益\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [10, \"担保\", \"参与人抵质押物估值\", \"设为必填\", 201905, \"进行中\", \"在有抵押物的业务场景中才要求必填\"],\n    [11, \"担保\", \"参与人市\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [12, \"担保\", \"参与人省份\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [13, \"担保\", \"担保责任比例\", \"设为必填\", 201905, \"进行中\", \"在有合作渠道的业务场景中才要求必填\"],\n    [14, \"担保\", \"到期日期\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [15, \"担保\", \"开始日期\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [16, \"担保\", \"参与人规模\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [17, \"担保\", \"项目名称\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [18, \"担保\", \"项目余额\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [19, \"担保\", \"项目金额\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [20, \"担保\", \"项目编号\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [1, \"基金2\", \"参与人省份\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [2, \"基金2\", \"参与人市\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [3, \"基金2\", \"项目余额\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [4, \"基金2\", \"收益率\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [5, \"基金2\", \"项目资金用途\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [6, \"基金2\", \"项目金额\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [7, \"基金2\", \"项目名称\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [8, \"基金2\", \"管理费率\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [9, \"基金2\", \"交易本金金额\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [10, \"基金2\", \"项目类别\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [11, \"基金2\", \"约定退出方式\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [12, \"基金2\", \"项目投向行业（展业指引）\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [13, \"基金2\", \"到期日期\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [14, \"基金2\", \"约定退出日期\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [15, \"基金2\", \"项目管理方式\", \"补创建数据项\", 201905, \"进行中\", \"未完成\"],\n    [16, \"基金2\", \"我方管理角色\", \"补创建数据项\", 201905, \"进行中\", \"未完成\"],\n    [17, \"基金2\", \"基金资金来源\", \"补创建数据项\", 201905, \"进行中\", \"未完成\"],\n    [18, \"基金2\", \"投资轮次\", \"补创建数据项\", 201905, \"进行中\", \"未完成\"],\n    [19, \"基金2\", \"参与人角色标识\", \"补创建数据项\", 201905, \"进行中\", \"未完成\"],\n    [1, \"基金1\", \"项目金额\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [2, \"基金1\", \"约定退出日期\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [3, \"基金1\", \"约定退出方式\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [4, \"基金1\", \"管理费率\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [5, \"基金1\", \"参与人市\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [6, \"基金1\", \"参与人省份\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [7, \"基金1\", \"交易分红金额\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [8, \"基金1\", \"交易本金金额\", \"设为必填\", 201905, \"进行中\", \"完成\"],\n    [9, \"基金1\", \"项目类别\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [10, \"基金1\", \"我方管理角色\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [11, \"基金1\", \"项目余额\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [12, \"基金1\", \"到期日期\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [13, \"基金1\", \"项目管理方式\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [14, \"基金1\", \"风险等级\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [15, \"基金1\", \"项目投向行业（展业指引）\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [16, \"基金1\", \"风险项目简述\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [17, \"基金1\", \"项目资金用途\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [18, \"基金1\", \"基金1业务类型\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [19, \"基金1\", \"收益率\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [20, \"基金1\", \"投资轮次\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [21, \"基金1\", \"参与人角色标识\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [22, \"基金1\", \"交易类型\", \"补创建数据项\", 201905, \"进行中\", \"完成\"],\n    [1, \"金租\", \"项目五级分类\", \"设为必填\", 201905, \"进行中\", \"未完成\"],\n    [2, \"金租\", \"收益率\", \"设为必填\", 201905, \"进行中\", \"未完成\"]\n]"
  },
  {
    "path": "static/resource/stdNodes.json",
    "content": "[\n    { \"id\":1 ,\"pId\":0,   \"name\":\"概述\", \"t\":\"概述\", \"open\":\"true\"},\n    { \"id\":2 ,\"pId\":0,   \"name\":\"参考文献\", \"t\":\"参考文献\", \"open\":\"true\"},\n    { \"id\":3 ,\"pId\":0,   \"name\":\"术语和定义\", \"t\":\"术语和定义\", \"open\":\"true\"},\n    { \"id\":4 ,\"pId\":0,   \"name\":\"主题域分类\", \"t\":\"主题域分类\", \"open\":\"true\"},\n    { \"id\":41 ,\"pId\":4,   \"name\":\"项目（协议）\", \"t\":\"项目（协议）\"},\n    { \"id\":42 ,\"pId\":4,   \"name\":\"交易\", \"t\":\"交易\"},\n    { \"id\":43 ,\"pId\":4,   \"name\":\"参与人（对公）\", \"t\":\"参与人（对公）\"},\n    { \"id\":44 ,\"pId\":4,  \"name\":\"参与人（个人）\", \"t\":\"参与人（个人）\"},\n    { \"id\":45 ,\"pId\":4,  \"name\":\"机构\", \"t\":\"机构\"},\n    { \"id\":46 ,\"pId\":4,  \"name\":\"产品\", \"t\":\"产品\"},\n    { \"id\":47 ,\"pId\":4,  \"name\":\"财务\", \"t\":\"财务\"},\n    { \"id\":5 ,\"pId\":0,   \"name\":\"数据项标准\", \"t\":\"数据项标准\", \"open\":\"true\"},\n    { \"id\":51 ,\"pId\":5,  \"name\":\"项目（协议）\", \"t\":\"项目（协议）\"},\n    { \"id\":5101 ,\"pId\":51,  \"name\":\"项目编号\", \"t\":\"项目编号\"},\n    { \"id\":5102 ,\"pId\":51,  \"name\":\"项目名称\", \"t\":\"项目名称\"},\n    { \"id\":5103 ,\"pId\":51,  \"name\":\"项目类别\", \"t\":\"项目类别\"},\n    { \"id\":5104 ,\"pId\":51,  \"name\":\"项目投向行业\", \"t\":\"项目投向行业\"},\n    { \"id\":5105 ,\"pId\":51,  \"name\":\"项目投向行业（展业指引）\", \"t\":\"项目投向行业（展业指引）\"},\n    { \"id\":5106 ,\"pId\":51,  \"name\":\"项目投向（按功能）\", \"t\":\"项目投向（按功能）\"},\n    { \"id\":5107 ,\"pId\":51,  \"name\":\"项目资金用途\", \"t\":\"项目资金用途\"},\n    { \"id\":5108 ,\"pId\":51,  \"name\":\"项目交易对手（投向）\", \"t\":\"项目交易对手（投向）\"},\n    { \"id\":5109 ,\"pId\":51,  \"name\":\"项目来源\", \"t\":\"项目来源\"},\n    { \"id\":5110 ,\"pId\":51,  \"name\":\"项目所在省\", \"t\":\"项目所在省\"},\n    { \"id\":5111 ,\"pId\":51,  \"name\":\"项目所在市\", \"t\":\"项目所在市\"},\n    { \"id\":5112 ,\"pId\":51,  \"name\":\"项目所在县\", \"t\":\"项目所在县\"},\n    { \"id\":5113 ,\"pId\":51,  \"name\":\"开始日期\", \"t\":\"开始日期\"},\n    { \"id\":5114 ,\"pId\":51,  \"name\":\"到期日期\", \"t\":\"到期日期\"},\n    { \"id\":5115 ,\"pId\":51,  \"name\":\"约定退出日期\", \"t\":\"约定退出日期\"},\n    { \"id\":5116 ,\"pId\":51,  \"name\":\"约定退出方式\", \"t\":\"约定退出方式\"},\n    { \"id\":5117 ,\"pId\":51,  \"name\":\"项目管理方式\", \"t\":\"项目管理方式\"},\n    { \"id\":5118 ,\"pId\":51,  \"name\":\"项目管理方式（监管）\", \"t\":\"项目管理方式（监管）\"},\n    { \"id\":5119 ,\"pId\":51,  \"name\":\"我方管理角色\", \"t\":\"我方管理角色\"},\n    { \"id\":5120 ,\"pId\":51,  \"name\":\"项目金额\", \"t\":\"项目金额\"},\n    { \"id\":5121 ,\"pId\":51,  \"name\":\"项目余额\", \"t\":\"项目余额\"},\n    { \"id\":5122 ,\"pId\":51,  \"name\":\"账面金额\", \"t\":\"账面金额\"},\n    { \"id\":5123 ,\"pId\":51,  \"name\":\"账面余额\", \"t\":\"账面余额\"},\n    { \"id\":5124 ,\"pId\":51,  \"name\":\"资产金额\", \"t\":\"资产金额\"},\n    { \"id\":5125 ,\"pId\":51,  \"name\":\"资产余额\", \"t\":\"资产余额\"},\n    { \"id\":5126 ,\"pId\":51,  \"name\":\"收益率\", \"t\":\"收益率\"},\n    { \"id\":5127 ,\"pId\":51,  \"name\":\"项目收益\", \"t\":\"项目收益\"},\n    { \"id\":5128 ,\"pId\":51,  \"name\":\"审批结论\", \"t\":\"审批结论\"},\n    { \"id\":5129 ,\"pId\":51,  \"name\":\"审批金额\", \"t\":\"审批金额\"},\n    { \"id\":5130 ,\"pId\":51,  \"name\":\"撤销原因\", \"t\":\"撤销原因\"},\n    { \"id\":5131 ,\"pId\":51,  \"name\":\"拒绝原因\", \"t\":\"拒绝原因\"},\n    { \"id\":5132 ,\"pId\":51,  \"name\":\"风险等级\", \"t\":\"风险等级\"},\n    { \"id\":5133 ,\"pId\":51,  \"name\":\"项目五级分类\", \"t\":\"项目五级分类\"},\n    { \"id\":5134 ,\"pId\":51,  \"name\":\"担保责任比例\", \"t\":\"担保责任比例\"},\n    { \"id\":5135 ,\"pId\":51,  \"name\":\"风险项目简述\", \"t\":\"风险项目简述\"},\n    { \"id\":5136 ,\"pId\":51,  \"name\":\"担保方式\", \"t\":\"担保方式\"},\n    { \"id\":5137 ,\"pId\":51,  \"name\":\"收购方式\", \"t\":\"收购方式\"},\n    { \"id\":5138 ,\"pId\":51,  \"name\":\"资产包类别\", \"t\":\"资产包类别\"},\n    { \"id\":5139 ,\"pId\":51,  \"name\":\"资产编号\", \"t\":\"资产编号\"},\n    { \"id\":5140 ,\"pId\":51,  \"name\":\"资产名称\", \"t\":\"资产名称\"},\n    { \"id\":5141 ,\"pId\":51,  \"name\":\"资产类别\", \"t\":\"资产类别\"},\n    { \"id\":5142 ,\"pId\":51,  \"name\":\"续封续冻资产类型\", \"t\":\"续封续冻资产类型\"},\n    { \"id\":5143 ,\"pId\":51,  \"name\":\"是否续封续冻预警\", \"t\":\"是否续封续冻预警\"},\n    { \"id\":5144 ,\"pId\":51,  \"name\":\"资产处置合同金额\", \"t\":\"资产处置合同金额\"},\n    { \"id\":5145 ,\"pId\":51,  \"name\":\"资金或资产来源\", \"t\":\"资金或资产来源\"},\n    { \"id\":5146 ,\"pId\":51,  \"name\":\"基金创投业务类型\", \"t\":\"基金创投业务类型\"},\n    { \"id\":5147 ,\"pId\":51,  \"name\":\"净资本类别\", \"t\":\"净资本类别\"},\n    { \"id\":5148 ,\"pId\":51,  \"name\":\"风险资本类别\", \"t\":\"风险资本类别\"},\n    { \"id\":5149 ,\"pId\":51,  \"name\":\"保证金\", \"t\":\"保证金\"},\n    { \"id\":5150 ,\"pId\":51,  \"name\":\"线上/线下\", \"t\":\"线上/线下\"},\n    { \"id\":52 ,\"pId\":5,  \"name\":\"交易\", \"t\":\"交易\"},\n    { \"id\":5201 ,\"pId\":52,  \"name\":\"交易编号\", \"t\":\"交易编号\"},\n    { \"id\":5202 ,\"pId\":52,  \"name\":\"交易类型\", \"t\":\"交易类型\"},\n    { \"id\":5203 ,\"pId\":52,  \"name\":\"交易日期\", \"t\":\"交易日期\"},\n    { \"id\":5204 ,\"pId\":52,  \"name\":\"交易本金金额\", \"t\":\"交易本金金额\"},\n    { \"id\":5205 ,\"pId\":52,  \"name\":\"交易利息金额\", \"t\":\"交易利息金额\"},\n    { \"id\":5206 ,\"pId\":52,  \"name\":\"交易分红金额\", \"t\":\"交易分红金额\"},\n    { \"id\":5207 ,\"pId\":52,  \"name\":\"逾期天数\", \"t\":\"逾期天数\"},\n    { \"id\":5208 ,\"pId\":52,  \"name\":\"基金资金来源\", \"t\":\"基金资金来源\"},\n    { \"id\":5209 ,\"pId\":52,  \"name\":\"预计还款金额\", \"t\":\"预计还款金额\"},\n    { \"id\":53 ,\"pId\":5,  \"name\":\"参与人（对公）\", \"t\":\"参与人（对公）\"},\n    { \"id\":5301 ,\"pId\":53,  \"name\":\"参与人类别\", \"t\":\"参与人类别\"},\n    { \"id\":5302 ,\"pId\":53,  \"name\":\"参与人编号\", \"t\":\"参与人编号\"},\n    { \"id\":5303 ,\"pId\":53,  \"name\":\"参与人名称\", \"t\":\"参与人名称\"},\n    { \"id\":5304 ,\"pId\":53,  \"name\":\"机构证件类别\", \"t\":\"机构证件类别\"},\n    { \"id\":5305 ,\"pId\":53,  \"name\":\"机构证件号码\", \"t\":\"机构证件号码\"},\n    { \"id\":5306 ,\"pId\":53,  \"name\":\"机构证件有效期\", \"t\":\"机构证件有效期\"},\n    { \"id\":5307 ,\"pId\":53,  \"name\":\"参与人角色标识\", \"t\":\"参与人角色标识\"},\n    { \"id\":5308 ,\"pId\":53,  \"name\":\"参与人行业\", \"t\":\"参与人行业\"},\n    { \"id\":5309 ,\"pId\":53,  \"name\":\"参与人省份\", \"t\":\"参与人省份\"},\n    { \"id\":5310 ,\"pId\":53,  \"name\":\"参与人市\", \"t\":\"参与人市\"},\n    { \"id\":5311 ,\"pId\":53,  \"name\":\"参与人县\", \"t\":\"参与人县\"},\n    { \"id\":5312 ,\"pId\":53,  \"name\":\"参与人规模\", \"t\":\"参与人规模\"},\n    { \"id\":5313 ,\"pId\":53,  \"name\":\"从业人数\", \"t\":\"从业人数\"},\n    { \"id\":5314 ,\"pId\":53,  \"name\":\"营业收入\", \"t\":\"营业收入\"},\n    { \"id\":5315 ,\"pId\":53,  \"name\":\"营业状态\", \"t\":\"营业状态\"},\n    { \"id\":5316 ,\"pId\":53,  \"name\":\"所有制类型\", \"t\":\"所有制类型\"},\n    { \"id\":5317 ,\"pId\":53,  \"name\":\"国企标识\", \"t\":\"国企标识\"},\n    { \"id\":5318 ,\"pId\":53,  \"name\":\"参与人上市标识\", \"t\":\"参与人上市标识\"},\n    { \"id\":5319 ,\"pId\":53,  \"name\":\"股票代码\", \"t\":\"股票代码\"},\n    { \"id\":5320 ,\"pId\":53,  \"name\":\"股票类型\", \"t\":\"股票类型\"},\n    { \"id\":5321 ,\"pId\":53,  \"name\":\"股票名称\", \"t\":\"股票名称\"},\n    { \"id\":5322 ,\"pId\":53,  \"name\":\"参与人担保类型\", \"t\":\"参与人担保类型\"},\n    { \"id\":5323 ,\"pId\":53,  \"name\":\"参与人抵质押物估值\", \"t\":\"参与人抵质押物估值\"},\n    { \"id\":5324 ,\"pId\":53,  \"name\":\"地方政府融资平台标识\", \"t\":\"地方政府融资平台标识\"},\n    { \"id\":5325 ,\"pId\":53,  \"name\":\"参与人实际控制人类别\", \"t\":\"参与人实际控制人类别\"},\n    { \"id\":5326 ,\"pId\":53,  \"name\":\"参与人实际控制人名称\", \"t\":\"参与人实际控制人名称\"},\n    { \"id\":5327 ,\"pId\":53,  \"name\":\"上级股东类别\", \"t\":\"上级股东类别\"},\n    { \"id\":5328 ,\"pId\":53,  \"name\":\"上级股东名称\", \"t\":\"上级股东名称\"},\n    { \"id\":5329 ,\"pId\":53,  \"name\":\"参与人内部信用等级\", \"t\":\"参与人内部信用等级\"},\n    { \"id\":5330 ,\"pId\":53,  \"name\":\"参与人外部信用等级\", \"t\":\"参与人外部信用等级\"},\n    { \"id\":5331 ,\"pId\":53,  \"name\":\"参与人历史违约标识\", \"t\":\"参与人历史违约标识\"},\n    { \"id\":5332 ,\"pId\":53,  \"name\":\"历史违约事件类型\", \"t\":\"历史违约事件类型\"},\n    { \"id\":5333 ,\"pId\":53,  \"name\":\"违约日期\", \"t\":\"违约日期\"},\n    { \"id\":5334 ,\"pId\":53,  \"name\":\"参与人五级分类\", \"t\":\"参与人五级分类\"},\n    { \"id\":5335 ,\"pId\":53,  \"name\":\"首次业务签约日期\", \"t\":\"首次业务签约日期\"},\n    { \"id\":5336 ,\"pId\":53,  \"name\":\"法人代表姓名\", \"t\":\"法人代表姓名\"},\n    { \"id\":5337 ,\"pId\":53,  \"name\":\"法人代表证件类型\", \"t\":\"法人代表证件类型\"},\n    { \"id\":5338 ,\"pId\":53,  \"name\":\"法人代表证件号码\", \"t\":\"法人代表证件号码\"},\n    { \"id\":5339 ,\"pId\":53,  \"name\":\"集团客户标志\", \"t\":\"集团客户标志\"},\n    { \"id\":5340 ,\"pId\":53,  \"name\":\"企业成长阶段\", \"t\":\"企业成长阶段\"},\n    { \"id\":5341 ,\"pId\":53,  \"name\":\"投资轮次\", \"t\":\"投资轮次\"},\n    { \"id\":5342 ,\"pId\":53,  \"name\":\"注册日期\", \"t\":\"注册日期\"},\n    { \"id\":54 ,\"pId\":5,  \"name\":\"参与人（个人）\", \"t\":\"参与人（个人）\"},\n    { \"id\":5401 ,\"pId\":54,  \"name\":\"参与人编号\", \"t\":\"参与人编号\"},\n    { \"id\":5402 ,\"pId\":54,  \"name\":\"参与人名称\", \"t\":\"参与人名称\"},\n    { \"id\":5403 ,\"pId\":54,  \"name\":\"个人证件类别\", \"t\":\"个人证件类别\"},\n    { \"id\":5404 ,\"pId\":54,  \"name\":\"个人证件号码\", \"t\":\"个人证件号码\"},\n    { \"id\":5405 ,\"pId\":54,  \"name\":\"个人证件有效期\", \"t\":\"个人证件有效期\"},\n    { \"id\":5406 ,\"pId\":54,  \"name\":\"参与人角色\", \"t\":\"参与人角色\"},\n    { \"id\":5407 ,\"pId\":54,  \"name\":\"参与人年龄\", \"t\":\"参与人年龄\"},\n    { \"id\":5408 ,\"pId\":54,  \"name\":\"参与人性别\", \"t\":\"参与人性别\"},\n    { \"id\":5409 ,\"pId\":54,  \"name\":\"参与人岗位\", \"t\":\"参与人岗位\"},\n    { \"id\":5410 ,\"pId\":54,  \"name\":\"参与人所属单位\", \"t\":\"参与人所属单位\"},\n    { \"id\":5411 ,\"pId\":54,  \"name\":\"参与人所属部门\", \"t\":\"参与人所属部门\"},\n    { \"id\":5412 ,\"pId\":54,  \"name\":\"参与人职务\", \"t\":\"参与人职务\"},\n    { \"id\":5413 ,\"pId\":54,  \"name\":\"参与人职级\", \"t\":\"参与人职级\"},\n    { \"id\":5414 ,\"pId\":54,  \"name\":\"从业状况\", \"t\":\"从业状况\"},\n    { \"id\":5415 ,\"pId\":54,  \"name\":\"婚姻状况\", \"t\":\"婚姻状况\"},\n    { \"id\":5416 ,\"pId\":54,  \"name\":\"健康状况\", \"t\":\"健康状况\"},\n    { \"id\":5417 ,\"pId\":54,  \"name\":\"年收入\", \"t\":\"年收入\"},\n    { \"id\":5418 ,\"pId\":54,  \"name\":\"国籍\", \"t\":\"国籍\"},\n    { \"id\":5419 ,\"pId\":54,  \"name\":\"家庭地址\", \"t\":\"家庭地址\"},\n    { \"id\":5420 ,\"pId\":54,  \"name\":\"通讯地址\", \"t\":\"通讯地址\"},\n    { \"id\":5421 ,\"pId\":54,  \"name\":\"联系电话\", \"t\":\"联系电话\"},\n    { \"id\":5422 ,\"pId\":54,  \"name\":\"民族\", \"t\":\"民族\"},\n    { \"id\":5423 ,\"pId\":54,  \"name\":\"户口性质\", \"t\":\"户口性质\"},\n    { \"id\":5424 ,\"pId\":54,  \"name\":\"内部员工标志\", \"t\":\"内部员工标志\"},\n    { \"id\":55 ,\"pId\":5,  \"name\":\"机构\", \"t\":\"机构\"},\n    { \"id\":5501 ,\"pId\":55,  \"name\":\"机构编号\", \"t\":\"机构编号\"},\n    { \"id\":5502 ,\"pId\":55,  \"name\":\"机构名称\", \"t\":\"机构名称\"},\n    { \"id\":5503 ,\"pId\":55,  \"name\":\"机构简称\", \"t\":\"机构简称\"},\n    { \"id\":5504 ,\"pId\":55,  \"name\":\"上级机构名称\", \"t\":\"上级机构名称\"},\n    { \"id\":5505 ,\"pId\":55,  \"name\":\"机构类型\", \"t\":\"机构类型\"},\n    { \"id\":5506 ,\"pId\":55,  \"name\":\"投资类型\", \"t\":\"投资类型\"},\n    { \"id\":56 ,\"pId\":5,  \"name\":\"产品\", \"t\":\"产品\"},\n    { \"id\":5601 ,\"pId\":56,  \"name\":\"产品编号\", \"t\":\"产品编号\"},\n    { \"id\":5602 ,\"pId\":56,  \"name\":\"产品名称\", \"t\":\"产品名称\"},\n    { \"id\":5603 ,\"pId\":56,  \"name\":\"上级产品单元\", \"t\":\"上级产品单元\"},\n    { \"id\":5604 ,\"pId\":56,  \"name\":\"产品级次\", \"t\":\"产品级次\"},\n    { \"id\":5605 ,\"pId\":56,  \"name\":\"产品开始日期\", \"t\":\"产品开始日期\"},\n    { \"id\":5606 ,\"pId\":56,  \"name\":\"产品结束日期\", \"t\":\"产品结束日期\"},\n    { \"id\":5607 ,\"pId\":56,  \"name\":\"产品收益率\", \"t\":\"产品收益率\"},\n    { \"id\":5608 ,\"pId\":56,  \"name\":\"产品收益\", \"t\":\"产品收益\"},\n    { \"id\":5609 ,\"pId\":56,  \"name\":\"管理费率\", \"t\":\"管理费率\"},\n    { \"id\":5610 ,\"pId\":56,  \"name\":\"存续标识\", \"t\":\"存续标识\"},\n    { \"id\":57 ,\"pId\":5,  \"name\":\"财务\", \"t\":\"财务\"},\n    { \"id\":5701 ,\"pId\":57,  \"name\":\"期初借方余额\", \"t\":\"期初借方余额\"},\n    { \"id\":5702 ,\"pId\":57,  \"name\":\"期初贷方余额\", \"t\":\"期初贷方余额\"},\n    { \"id\":5703 ,\"pId\":57,  \"name\":\"本期借方发生额\", \"t\":\"本期借方发生额\"},\n    { \"id\":5704 ,\"pId\":57,  \"name\":\"本期贷方发生额\", \"t\":\"本期贷方发生额\"},\n    { \"id\":5705 ,\"pId\":57,  \"name\":\"期末借方余额\", \"t\":\"期末借方余额\"},\n    { \"id\":5706 ,\"pId\":57,  \"name\":\"期末贷方余额\", \"t\":\"期末贷方余额\"},\n    { \"id\":5707 ,\"pId\":57,  \"name\":\"总账会计科目编号\", \"t\":\"总账会计科目编号\"},\n    { \"id\":5708 ,\"pId\":57,  \"name\":\"总账会计科目名称\", \"t\":\"总账会计科目名称\"},\n    { \"id\":5709 ,\"pId\":57,  \"name\":\"总账会计科目级次\", \"t\":\"总账会计科目级次\"},\n    { \"id\":5710 ,\"pId\":57,  \"name\":\"会计日期\", \"t\":\"会计日期\"},\n    { \"id\":6 ,\"pId\":0,  \"name\":\"附录\", \"t\":\"附录\", \"open\":\"true\"}\n]"
  },
  {
    "path": "static/zTree/css/zTreeStyle.css",
    "content": "/*-------------------------------------\nzTree Style\n\nversion:\t3.5.19\nauthor:\t\tHunter.z\nemail:\t\thunter.z@263.net\nwebsite:\thttp://code.google.com/p/jquerytree/\n\n-------------------------------------*/\n\n.ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif}\n.ztree {margin:0; padding:5px; color:#333}\n.ztree li{padding:0; margin:0; list-style:none; line-height:14px; text-align:left; white-space:nowrap; outline:0}\n.ztree li ul{ margin:0; padding:0 0 0 18px}\n.ztree li ul.line{ background:url(./img/line_conn.gif) 0 0 repeat-y;}\n\n.ztree li a {padding:1px 3px 0 0; margin:0; cursor:pointer; height:17px; color:#333; background-color: transparent;\n\ttext-decoration:none; vertical-align:top; display: inline-block}\n.ztree li a:hover {text-decoration:underline}\n.ztree li a.curSelectedNode {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;}\n.ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;}\n.ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#316AC5; color:white; height:16px; border:1px #316AC5 solid;\n\topacity:0.8; filter:alpha(opacity=80)}\n.ztree li a.tmpTargetNode_prev {}\n.ztree li a.tmpTargetNode_next {}\n.ztree li a input.rename {height:14px; width:80px; padding:0; margin:0;\n\tfont-size:12px; border:1px #7EC4CC solid; *border:0px}\n.ztree li span {line-height:16px; margin-right:2px}\n.ztree li span.button {line-height:0; margin:0; width:16px; height:16px; display: inline-block; vertical-align:middle;\n\tborder:0 none; cursor: pointer;outline:none;\n\tbackground-color:transparent; background-repeat:no-repeat; background-attachment: scroll;\n\tbackground-image:url(\"./img/zTreeStandard.png\"); *background-image:url(\"./img/zTreeStandard.gif\")}\n\n.ztree li span.button.chk {width:13px; height:13px; margin:0 3px 0 0; cursor: auto}\n.ztree li span.button.chk.checkbox_false_full {background-position:0 0}\n.ztree li span.button.chk.checkbox_false_full_focus {background-position:0 -14px}\n.ztree li span.button.chk.checkbox_false_part {background-position:0 -28px}\n.ztree li span.button.chk.checkbox_false_part_focus {background-position:0 -42px}\n.ztree li span.button.chk.checkbox_false_disable {background-position:0 -56px}\n.ztree li span.button.chk.checkbox_true_full {background-position:-14px 0}\n.ztree li span.button.chk.checkbox_true_full_focus {background-position:-14px -14px}\n.ztree li span.button.chk.checkbox_true_part {background-position:-14px -28px}\n.ztree li span.button.chk.checkbox_true_part_focus {background-position:-14px -42px}\n.ztree li span.button.chk.checkbox_true_disable {background-position:-14px -56px}\n.ztree li span.button.chk.radio_false_full {background-position:-28px 0}\n.ztree li span.button.chk.radio_false_full_focus {background-position:-28px -14px}\n.ztree li span.button.chk.radio_false_part {background-position:-28px -28px}\n.ztree li span.button.chk.radio_false_part_focus {background-position:-28px -42px}\n.ztree li span.button.chk.radio_false_disable {background-position:-28px -56px}\n.ztree li span.button.chk.radio_true_full {background-position:-42px 0}\n.ztree li span.button.chk.radio_true_full_focus {background-position:-42px -14px}\n.ztree li span.button.chk.radio_true_part {background-position:-42px -28px}\n.ztree li span.button.chk.radio_true_part_focus {background-position:-42px -42px}\n.ztree li span.button.chk.radio_true_disable {background-position:-42px -56px}\n\n.ztree li span.button.switch {width:18px; height:18px}\n.ztree li span.button.root_open{background-position:-92px -54px}\n.ztree li span.button.root_close{background-position:-74px -54px}\n.ztree li span.button.roots_open{background-position:-92px 0}\n.ztree li span.button.roots_close{background-position:-74px 0}\n.ztree li span.button.center_open{background-position:-92px -18px}\n.ztree li span.button.center_close{background-position:-74px -18px}\n.ztree li span.button.bottom_open{background-position:-92px -36px}\n.ztree li span.button.bottom_close{background-position:-74px -36px}\n.ztree li span.button.noline_open{background-position:-92px -72px}\n.ztree li span.button.noline_close{background-position:-74px -72px}\n.ztree li span.button.root_docu{ background:none;}\n.ztree li span.button.roots_docu{background-position:-56px 0}\n.ztree li span.button.center_docu{background-position:-56px -18px}\n.ztree li span.button.bottom_docu{background-position:-56px -36px}\n.ztree li span.button.noline_docu{ background:none;}\n\n.ztree li span.button.ico_open{margin-right:2px; background-position:-110px -16px; vertical-align:top; *vertical-align:middle}\n.ztree li span.button.ico_close{margin-right:2px; background-position:-110px 0; vertical-align:top; *vertical-align:middle}\n.ztree li span.button.ico_docu{margin-right:2px; background-position:-110px -32px; vertical-align:top; *vertical-align:middle}\n.ztree li span.button.edit {margin-right:2px; background-position:-110px -48px; vertical-align:top; *vertical-align:middle}\n.ztree li span.button.remove {margin-right:2px; background-position:-110px -64px; vertical-align:top; *vertical-align:middle}\n\n.ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle}\n\nul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)}\n\nspan.tmpzTreeMove_arrow {width:16px; height:16px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute;\n\tbackground-color:transparent; background-repeat:no-repeat; background-attachment: scroll;\n\tbackground-position:-110px -80px; background-image:url(\"./img/zTreeStandard.png\"); *background-image:url(\"./img/zTreeStandard.gif\")}\n\nul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)}\n.zTreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute}\n\n/* level style*/\n/*.ztree li span.button.level0 {\n\tdisplay:none;\n}\n.ztree li ul.level0 {\n\tpadding:0;\n\tbackground:none;\n}*/"
  },
  {
    "path": "static/zTree/js/fuzzysearch.js",
    "content": "/*\n * email: bigablecat@hotmail.com\n * Date: 2018-04-14\n */\n\n/**\n * @param zTreeId the ztree id used to get the ztree object\n * @param searchField selector of your input for fuzzy search\n * @param isHighLight whether highlight the match words, default true\n * @param isExpand whether to expand the node, default false\n * \n * @returns\n */\t\n function fuzzySearch(zTreeId, searchField, isHighLight, isExpand){\n\tvar zTreeObj = $.fn.zTree.getZTreeObj(zTreeId);//get the ztree object by ztree id\n\tif(!zTreeObj){\n\t\talert(\"fail to get ztree object\");\n\t}\n\tvar nameKey = zTreeObj.setting.data.key.name; //get the key of the node name\n\tisHighLight = isHighLight===false?false:true;//default true, only use false to disable highlight\n\tisExpand = isExpand?true:false; // not to expand in default\n\tzTreeObj.setting.view.nameIsHTML = isHighLight; //allow use html in node name for highlight use\n\t\n\tvar metaChar = '[\\\\[\\\\]\\\\\\\\\\^\\\\$\\\\.\\\\|\\\\?\\\\*\\\\+\\\\(\\\\)]'; //js meta characters\n\tvar rexMeta = new RegExp(metaChar, 'gi');//regular expression to match meta characters\n\t\n\t// keywords filter function \n\tfunction ztreeFilter(zTreeObj,_keywords,callBackFunc) {\n\t\tif(!_keywords){\n\t\t\t_keywords =''; //default blank for _keywords \n\t\t}\n\t\t\n\t\t// function to find the matching node\n\t\tfunction filterFunc(node) {\n\t\t\tif(node && node.oldname && node.oldname.length>0){\n\t\t\t\tnode[nameKey] = node.oldname; //recover oldname of the node if exist\n\t\t\t}\n\t\t\tzTreeObj.updateNode(node); //update node to for modifications take effect\n\t\t\tif (_keywords.length == 0) {\n\t\t\t\t//return true to show all nodes if the keyword is blank\n\t\t\t\tzTreeObj.showNode(node);\n\t\t\t\tzTreeObj.expandNode(node,isExpand);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t//transform node name and keywords to lowercase\n\t\t\tif (node[nameKey] && node[nameKey].toLowerCase().indexOf(_keywords.toLowerCase())!=-1) {\n\t\t\t\tif(isHighLight){ //highlight process\n\t\t\t\t\t//a new variable 'newKeywords' created to store the keywords information \n\t\t\t\t\t//keep the parameter '_keywords' as initial and it will be used in next node\n\t\t\t\t\t//process the meta characters in _keywords thus the RegExp can be correctly used in str.replace\n\t\t\t\t\tvar newKeywords = _keywords.replace(rexMeta,function(matchStr){\n\t\t\t\t\t\t//add escape character before meta characters\n\t\t\t\t\t\treturn '\\\\' + matchStr;\n\t\t\t\t\t});\n\t\t\t\t\tnode.oldname = node[nameKey]; //store the old name  \n\t\t\t\t\tvar rexGlobal = new RegExp(newKeywords, 'gi');//'g' for global,'i' for ignore case\n\t\t\t\t\t//use replace(RegExp,replacement) since replace(/substr/g,replacement) cannot be used here\n\t\t\t\t\tnode[nameKey] = node.oldname.replace(rexGlobal, function(originalText){\n\t\t\t\t\t\t//highlight the matching words in node name\n\t\t\t\t\t\tvar highLightText =\n\t\t\t\t\t\t\t'<span style=\"color: whitesmoke;background-color: darkred;\">'\n\t\t\t\t\t\t\t+ originalText\n\t\t\t\t\t\t\t+'</span>';\n\t\t\t\t\t\treturn \thighLightText;\t\t\t\t\t\n\t\t\t\t\t});\n\t\t\t\t\tzTreeObj.updateNode(node); //update node for modifications take effect\n\t\t\t\t}\n\t\t\t\tzTreeObj.showNode(node);//show node with matching keywords\n\t\t\t\treturn true; //return true and show this node\n\t\t\t}\n\t\t\t\n\t\t\tzTreeObj.hideNode(node); // hide node that not matched\n\t\t\treturn false; //return false for node not matched\n\t\t}\n\t\t\n\t\tvar nodesShow = zTreeObj.getNodesByFilter(filterFunc); //get all nodes that would be shown\n\t\tprocessShowNodes(nodesShow, _keywords);//nodes should be reprocessed to show correctly\n\t}\n\t\n\t/**\n\t * reprocess of nodes before showing\n\t */\n\tfunction processShowNodes(nodesShow,_keywords){\n\t\tif(nodesShow && nodesShow.length>0){\n\t\t\t//process the ancient nodes if _keywords is not blank\n\t\t\tif(_keywords.length>0){ \n\t\t\t\t$.each(nodesShow, function(n,obj){\n\t\t\t\t\tvar pathOfOne = obj.getPath();//get all the ancient nodes including current node\n\t\t\t\t\tif(pathOfOne && pathOfOne.length>0){ \n\t\t\t\t\t\t//i < pathOfOne.length-1 process every node in path except self\n\t\t\t\t\t\tfor(var i=0;i<pathOfOne.length-1;i++){\n\t\t\t\t\t\t\tzTreeObj.showNode(pathOfOne[i]); //show node \n\t\t\t\t\t\t\tzTreeObj.expandNode(pathOfOne[i],true); //expand node\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\t\n\t\t\t}else{ //show all nodes when _keywords is blank and expand the root nodes\n\t\t\t\tvar rootNodes = zTreeObj.getNodesByParam('level','0');//get all root nodes\n\t\t\t\t$.each(rootNodes,function(n,obj){\n\t\t\t\t\tzTreeObj.expandNode(obj,true); //expand all root nodes\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\t\n\t//listen to change in input element\n\t$(searchField).bind('input propertychange', function() {\n\t\tvar _keywords = $(this).val();\n\t\tsearchNodeLazy(_keywords); //call lazy load\n\t});\n\n\tvar timeoutId = null;\n  var lastKeyword = '';\n\t// excute lazy load once after input change, the last pending task will be cancled  \n\tfunction searchNodeLazy(_keywords) {\n\t\tif (timeoutId) { \n\t\t\t//clear pending task\n\t\t\tclearTimeout(timeoutId);\n\t\t}\n\t\ttimeoutId = setTimeout(function() {\n      if (lastKeyword === _keywords) {\n        return;\n      }\n\t\t\tztreeFilter(zTreeObj,_keywords); //lazy load ztreeFilter function \n\t\t\t// $(searchField).focus();//focus input field again after filtering\n      lastKeyword = _keywords;\n\t\t}, 500);\n\t}\n}"
  },
  {
    "path": "utils/functions.py",
    "content": "import datetime\nimport math\nfrom functools import wraps\n\nimport numpy as np\nfrom django.shortcuts import redirect\n\nfrom mysite import db_config\n\n\n# from itertools import chain\n\nclass is_login():\n    \"\"\"从session判断发起请求的账号是否已经登录，session中未有登录信息则跳转到登录界面\n    \"\"\"\n\n    def __new__(self, func):\n        @wraps(func)\n        def _wrap(request):\n            if request.session.get('is_login') is None or request is None:\n                return redirect(\"../../authorize/login\")\n            else:\n                f = func(request)\n                return f\n\n        return _wrap\n\n\ndef get_quarter_list():\n    \"\"\"获取检核结果库中所有季度的列表\n    \"\"\"\n    \"\"\"\n# DDL:/data/pyweb/mysite/mysite/ddl.sql\n    conn = db_config.mysql_connect()\n    curs = conn.cursor()\n    # 当一个季度的7家公司全部检核完，才会在下拉框中显示新季度出来\n    sql  = \"select distinct quarter from (select quarter,count(distinct company) as cnt from check_execute_log group by quarter) a where cnt>=7 order by quarter asc\"\n    curs.execute (sql)\n    db_quarter_list = curs.fetchall()                            #此时的数据格式为二维元组(('2019Q1',), ('2019Q2',))\n    quarter_list = list(chain.from_iterable(db_quarter_list))    #将二维元组转为一维元组，方便后续进行数据查询\n    curs.close()\n    conn.close()\n    return quarter_list\n    \"\"\"\n    return '2019Q1', '2019Q2', '2019Q3', '2019Q4'\n\n\n# 检核结果Excel明细\ndef get_result_detail(company, quarter):\n    data = [\n        [1, company, '项目编号', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [2, company, '项目名称', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [3, company, '项目类别', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [4, company, '项目投向行业', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [5, company, '项目投向（按功能）', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [6, company, '项目资金用途', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [7, company, '项目交易对手（投向）', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [8, company, '项目来源', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [9, company, '项目所在省', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [10, company, '项目所在市', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [11, company, '项目管理方式', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [12, company, '项目管理方式（监管）', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [13, company, '项目金额', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [14, company, '项目余额', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [15, company, '项目余额', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [16, company, '收益率', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [17, company, '风险等级', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n        [18, company, '资金或资产来源', '项目基本信息', '是', '控制检验', 'select col from tab', np.random.randint(5555, 99999),\n         np.random.randint(5555, 99999), str(round(np.random.rand() * 100, 2)) + '%', None],\n    ]\n    return data\n\n\ndef query_check_progressbar(company, quarter):\n    \"\"\"查询当前检核进度\n    \"\"\"\n    conn = db_config.mysql_connect()\n    curs = conn.cursor()\n    try:\n        sql = f\"select count(*) from check_result_{company}_{quarter} where check_sql is not null and check_sql != '' \"\n        curs.execute(sql)\n        to_be_check_cnt = curs.fetchone()[0]\n\n        sql = f\"select count(*) from check_result_{company}_{quarter} where check_sql is not null and check_sql != '' and update_flag='Y'\"\n        curs.execute(sql)\n        checked_cnt = curs.fetchone()[0]\n        return round(checked_cnt / to_be_check_cnt * 100, 2)\n    except Exception:\n        return 0\n    finally:\n        curs.close()\n        conn.close()\n\n\ndef get_user_quarter(request):\n    \"\"\"初始化仪表盘季度\n    传入参数：request\n         如果GET请求没有传入quarter参数，则先判断用户session是否有上一次选定的季度\n              - 如果上一次有选定季度，则显示上次选定的季度\n              - 没有选定季度，则默认显示上一季度数据\n\n    返回参数：quarter\n    \"\"\"\n    if request.GET.get('quarter') is None:\n        if request.session.get('selected_quarter') is None:\n            if math.ceil(datetime.datetime.now().month / 3.) - 1 == 0:  # 如果季度=0，则显示去年Q4季度\n                quarter = str(datetime.datetime.now().year - 1) + \"Q4\"\n            else:\n                quarter = str(datetime.datetime.now().year) + \"Q\" + str(\n                    math.ceil(datetime.datetime.now().month / 3.) - 1)\n        else:\n            quarter = request.session['selected_quarter']\n    else:\n        quarter = request.GET.get('quarter')\n        request.session['selected_quarter'] = request.GET.get('quarter')\n    return quarter\n\n\n\ndef query_data_year():\n    try:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        sql = \"\"\"select date_format(execute_date,'%Y'),count(distinct company) as cnt from check_execute_log\n                where status='success'\n                group by date_format(execute_date,'%Y')\n                having count(distinct company)>=7\n                order by 1 desc\"\"\"\n        curs.execute(sql)\n        year = curs.fetchall()\n        year = [y[0] for y in year]\n        return year\n    except Exception as e:\n        print('获取年份错误:', e)\n        return False\n    finally:\n        curs.close()\n        conn.close()\n        \n\ndef query_data_quarter(year):\n    try:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        sql = f\"\"\"select distinct quarter from (\n                    select b.quarter,count(distinct company),b.year from check_execute_log a,dim_date b\n                                    where DATE_FORMAT(execute_date,'%Y%m%d') = b.day_id\n                                    and a.status='success'\n                                    and b.year={year}\n                                    group by b.year,b.quarter\n                                    having count(distinct company)>=7\n                    ) a\n                    order by 1 desc\"\"\"\n        curs.execute(sql)\n        quarter = curs.fetchall()\n        quarter = [q[0] for q in quarter]\n        return quarter\n    except Exception as e:\n        print('获取季度错误:', e)\n        return False\n    finally:\n        curs.close()\n        conn.close()\n\n\ndef query_data_month(year, quarter):\n    try:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        sql = f\"\"\"select distinct month from (\n                    select b.month,count(distinct company),b.year,b.day from check_execute_log a,dim_date b\n                                    where DATE_FORMAT(execute_date,'%Y%m%d') = b.day_id\n                                    and a.status='success'\n                                    and b.year={year}\n                                    and b.quarter={quarter}\n                                    group by b.year,b.month,b.day\n                                    having count(distinct company)>=7\n                    ) a\n                    order by month desc\"\"\"\n        curs.execute(sql)\n        month = curs.fetchall()\n        month = [m[0] for m in month]\n        return month\n    except Exception as e:\n        print('获取月份错误:', e)\n        return False\n    finally:\n        curs.close()\n        conn.close()\n\n\ndef query_data_day(year, quarter, month):\n    try:\n        conn = db_config.mysql_connect()\n        curs = conn.cursor()\n        sql = f\"\"\"select distinct date_format(d,'%d') from (\n                    select date_format(a.execute_date,'%Y%m%d') d,count(distinct company) from check_execute_log a,dim_date b\n                                    where DATE_FORMAT(execute_date,'%Y%m%d') = b.day_id\n                                    and a.status='success'\n                                    and b.year={year}\n                                    and b.quarter={quarter}\n                                    and b.month={month}\n                                    group by date_format(a.execute_date,'%Y%m%d')\n                                    having count(distinct company)>=7\n                    ) a\n                    order by 1 desc\"\"\"\n        curs.execute(sql)\n        day = curs.fetchall()\n        day = [d[0] for d in day]\n        return day\n    except Exception as e:\n        print('获取天错误:', e)\n        return False\n    finally:\n        curs.close()\n        conn.close()\n"
  },
  {
    "path": "utils/generate_dim_date.py",
    "content": "import pandas as pd\nfrom sqlalchemy import create_engine\n\ndef db():\n    host     = 'localhost'\n    user     = 'system'\n    passwd   = 'H5cT7yHB8_'\n    port     = 3306\n    charset  = 'utf8mb4'\n    database = 'data_quality'\n    \n    engine = create_engine(\n        f'mysql+mysqldb://{user}:{passwd}@{host}:{port}/{database}?charset={charset}',\n        echo=False,\t\t\t\t# 打印sql语句\n        max_overflow=0,  \t\t# 超过连接池大小外最多创建的连接\n        pool_size=5,  \t\t\t# 连接池大小\n        pool_timeout=30,  \t\t# 池中没有线程最多等待的时间，否则报错\n        pool_recycle=-1, \t\t# 多久之后对线程池中的线程进行一次连接的回收（重置）\n    )\n    return engine\n\n\ndef generateData(startDate=None, endDate=None):\n    d = {'date':pd.date_range(start=startDate, end=endDate)}\n    data = pd.DataFrame(d)\n    data['day_id'] = data['date'].astype(str).str.replace('-', '').astype('int32')\n    data['year'] = data['date'].apply(lambda x:x.year).astype('int32')\n    data['month'] = data['date'].apply(lambda x:x.month).astype('int32')\n    data['day'] = data['date'].apply(lambda x:x.day).astype('int32')\n    data['quarter'] = data['date'].apply(lambda x:x.quarter).astype('int32')\n    data['day_name'] = data['date'].apply(lambda x:x.day_name())\n    data['weekofyear'] = data['date'].apply(lambda x:x.weekofyear)\n    data['dayofyear'] = data['date'].apply(lambda x:x.dayofyear).astype('int32')\n    data['daysinmonth'] = data['date'].apply(lambda x:x.daysinmonth).astype('int32')\n    data['dayofweek'] = data['date'].apply(lambda x:x.dayofweek).astype('int32')\n    data['is_leap_year'] = data['date'].apply(lambda x:x.is_leap_year)\n    data['is_month_end'] = data['date'].apply(lambda x:x.is_month_end)\n    data['is_month_start'] = data['date'].apply(lambda x:x.is_month_start)\n    data['is_quarter_end'] = data['date'].apply(lambda x:x.is_quarter_end)\n    data['is_quarter_start'] = data['date'].apply(lambda x:x.is_quarter_start)\n    data['is_year_end'] = data['date'].apply(lambda x:x.is_year_end)\n    data['is_year_start'] = data['date'].apply(lambda x:x.is_year_start)\n    return data\n\ndata = generateData(startDate='2019-1-01', endDate='2029-12-31')\n\n# data.to_csv('/tmp/dim_date.csv', index = False,index_label = False)\n\nconn = db()\n# 插入到mysql中，pandas的bool类型会转换为tinyint(1)类型，0表示False，1表示True\ndata.to_sql('dim_date', con=conn, if_exists='replace', index=False)"
  },
  {
    "path": "utils/report_data.py",
    "content": "#数据库连接配置，配置文件/data/pyweb/mysite/mysite/db_config.py\nimport sys,MySQLdb\nsys.path.insert(0, '..')\nfrom mysite import db_config\nimport numpy as np\n\ndef risk_market_total_count(quarter):\n    return np.random.randint(5555, 99999)\n    \ndef risk_market_problem_count(quarter):\n    return np.random.randint(5555, 99999)\n    \ndef risk_market_problem_detail(company, quarter):\n    data = ['项目编号', '空值检验', np.random.randint(5555, 99999), np.random.randint(5555, 99999), str(round(np.random.rand()*100, 2))+'%', None]\n    return data"
  }
]